[
  {
    "path": ".codecov.yml",
    "content": "codecov:\n  require_ci_to_pass: false\n\ncoverage:\n  status:\n    project:\n      default:\n        target: 15%\n        threshold: 0.5%\n        base: auto\n        if_ci_failed: success\n    patch: off\n\ncomment: false\n"
  },
  {
    "path": ".conform.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2025-12-25T11:36:39Z by kres 26be706.\n\npolicies:\n  - type: commit\n    spec:\n      dco: true\n      gpg:\n        required: true\n        identity:\n          gitHubOrganization: siderolabs\n      spellcheck:\n        locale: US\n      maximumOfOneCommit: false\n      header:\n        length: 89\n        imperative: true\n        case: lower\n        invalidLastCharacters: .\n      body:\n        required: true\n      conventional:\n        types:\n          - chore\n          - docs\n          - perf\n          - refactor\n          - style\n          - test\n          - release\n        scopes:\n          - apid\n          - machined\n          - networkd\n          - talosctl\n          - trustd\n          - talosctl\n          - kernel\n          - security\n          - ci\n          - ^v1.13\n  - type: license\n    spec:\n      skipPaths:\n        - .git/\n        - testdata/\n      includeSuffixes:\n        - .go\n      excludeSuffixes:\n        - .pb.go\n        - .pb.gw.go\n        - _string.go\n        - _enumer.go\n        - _string_linux.go\n        - zz_generated.deepcopy.go\n      header: |\n        // This Source Code Form is subject to the terms of the Mozilla Public\n        // License, v. 2.0. If a copy of the MPL was not distributed with this\n        // file, You can obtain one at http://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": ".dockerignore",
    "content": "**\n!api\n!selinux\n!cmd\n!docs\n!hack\n!internal\n!pkg\n!website\n!tools\n!.golangci.yml\n!.markdownlint.json\n!.textlintrc.json\n!go.mod\n!go.sum\n!go.work\n!README.md\n!CONTRIBUTING.md\n!_out/uki-certs\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [siderolabs]\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG_REPORT.md",
    "content": "---\nname: Bug Report\nabout: Report a bug.\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n## Bug Report\n\n### Description\n\n### Logs\n\n### Environment\n\n- Talos version: [`talosctl version --nodes <problematic nodes>`]\n- Kubernetes version: [`kubectl version`]\n- Platform:\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE_REQUEST.md",
    "content": "---\nname: Feature Requests\nabout: Create a feature request.\ntitle: \"\"\nlabels: \"\"\nassignees: \"\"\n---\n\n## Feature Request\n\n### Description\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Question\n    url: https://github.com/siderolabs/talos/discussions\n    about: Ask a question about Talos Linux.\n  - name: Community\n    url: https://taloscommunity.slack.com\n    about: Join the community. (Not an official support channel.) Get your invite by visiting https://inviter.co/sidero-labs-community.\n  - name: Get Enterprise Support\n    url: https://www.siderolabs.com/support/\n    about: Get commercial support from the Sidero Labs team, with SLAs for every issue.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Pull Request\n\n<!--\n## Note to the Contributor\n\nWe encourage contributors to go through a proposal process to discuss major changes.\nBefore your PR is allowed to run through CI, the maintainers of Talos will first have to approve the PR.\n-->\n\n## What? (description)\n\n## Why? (reasoning)\n\n## Acceptance\n\nPlease use the following checklist:\n\n- [ ] you linked an issue (if applicable)\n- [ ] you included tests (if applicable)\n- [ ] you ran conformance (`make conformance`)\n- [ ] you formatted your code (`make fmt`)\n- [ ] you linted your code (`make lint`)\n- [ ] you generated documentation (`make docs`)\n- [ ] you ran unit-tests (`make unit-tests`)\n\n> See `make help` for a description of the available targets.\n"
  },
  {
    "path": ".github/renovate.json",
    "content": "{\n    \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n    \"description\": \"THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\",\n    \"prHeader\": \"Update Request | Renovate Bot\",\n    \"extends\": [\n        \":dependencyDashboard\",\n        \":gitSignOff\",\n        \":semanticCommitScopeDisabled\",\n        \"schedule:earlyMondays\"\n    ],\n    \"customManagers\": [\n        {\n            \"customType\": \"regex\",\n            \"versioningTemplate\": \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\",\n            \"managerFilePatterns\": [\n                \"/Makefile/\"\n            ],\n            \"matchStrings\": [\n                \"# renovate: datasource=(?<datasource>.*?)(?:\\\\s+extractVersion=(?<extractVersion>.+?))?\\\\s+depName=(?<depName>.+?)\\\\s.*_VERSION\\\\s+\\\\?=\\\\s+(?<currentValue>.+)\"\n            ]\n        },\n        {\n            \"customType\": \"regex\",\n            \"versioningTemplate\": \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\",\n            \"managerFilePatterns\": [\n                \"/pkg/machinery/constants/constants.go/\"\n            ],\n            \"matchStrings\": [\n                \"\\\\/\\\\/\\\\s+renovate: datasource=(?<datasource>.*?)(?:\\\\s+extractVersion=(?<extractVersion>.+?))?(?:\\\\s+versioning=(?<versioning>.+?))?\\\\s+depName=(?<depName>.+?)?\\\\s.*Version\\\\s+=\\\\s+\\\\\\\"(?<currentValue>.+?)\\\\\\\"\"\n            ]\n        },\n        {\n            \"customType\": \"regex\",\n            \"versioningTemplate\": \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\",\n            \"managerFilePatterns\": [\n                \"/internal/integration/k8s/constants.go/\",\n                \"/internal/integration/api/constants.go/\"\n            ],\n            \"matchStrings\": [\n                \"\\\\/\\\\/\\\\s+renovate: datasource=(?<datasource>.*?)(?:\\\\s+extractVersion=(?<extractVersion>.+?))?(?:\\\\s+versioning=(?<versioning>.+?))?\\\\s+depName=(?<depName>.+?)?(?:\\\\s+registryUrl=(?<registryUrl>.+?))?\\\\s.*Version\\\\s+=\\\\s+\\\\\\\"(?<currentValue>.+?)\\\\\\\"\"\n            ]\n        },\n        {\n            \"customType\": \"regex\",\n            \"datasourceTemplate\": \"docker\",\n            \"depNameTemplate\": \"docker/dockerfile-upstream\",\n            \"versioningTemplate\": \"docker\",\n            \"managerFilePatterns\": [\n                \"/Dockerfile/\"\n            ],\n            \"matchStrings\": [\n                \"# syntax = docker\\\\/dockerfile-upstream:(?<currentValue>.*)\"\n            ]\n        }\n    ],\n    \"packageRules\": [\n        {\n            \"groupName\": \"dependencies\",\n            \"matchUpdateTypes\": [\n                \"major\",\n                \"minor\",\n                \"patch\",\n                \"pin\",\n                \"digest\"\n            ]\n        },\n        {\n            \"enabled\": false,\n            \"matchFileNames\": [\n                \"website/**\"\n            ]\n        },\n        {\n            \"versioning\": \"regex:^(?<major>\\\\d+)\\\\.(?<minor>\\\\d+)\",\n            \"matchPackageNames\": [\n                \"golang/go\"\n            ]\n        }\n    ],\n    \"separateMajorMinor\": false\n}\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-16T15:20:50Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  push:\n    branches:\n      - main\n      - release-*\n    tags:\n      - v*\n  pull_request:\n    branches:\n      - main\n      - release-*\nname: default\njobs:\n  base-lint:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: lint\n        run: |\n          make lint\n  base-unit-tests:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: unit-tests\n        run: |\n          make unit-tests\n      - name: unit-tests-fips\n        run: |\n          make unit-tests-fips\n      - name: unit-tests-race\n        run: |\n          make unit-tests-race\n      - name: coverage\n        uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # version: v5.5.2\n        with:\n          files: _out/coverage.txt\n          token: ${{ secrets.CODECOV_TOKEN }}\n        timeout-minutes: 3\n  default:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) && github.event_name == 'pull_request'\n    outputs:\n      labels: ${{ steps.retrieve-pr-labels.outputs.result }}\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: external-artifacts\n        run: |\n          make external-artifacts\n      - name: generate\n        run: |\n          make generate docs\n      - name: uki-certs\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: check-dirty\n        run: |\n          make check-dirty\n      - name: build\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        run: |\n          make talosctl-cni-bundle\n      - name: sbom\n        run: |\n          make sbom\n      - name: iso\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n        run: |\n          make iso secureboot-iso\n      - name: images-essential\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: Generate executable list\n        run: |\n          find _out -type f -executable > _out/executable-artifacts\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-artifacts\n          path: |\n            _out\n          retention-days: \"5\"\n      - name: Retrieve PR labels\n        id: retrieve-pr-labels\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # version: v8.0.0\n        with:\n          retries: \"3\"\n          script: |\n            if (context.eventName != \"pull_request\") { return \"[]\" }\n\n            const resp = await github.rest.issues.get({\n                issue_number: context.issue.number,\n                owner: context.repo.owner,\n                repo: context.repo.repo,\n            })\n\n            return resp.data.labels.map(label => label.name)\n  e2e-docker-short:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Download artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: e2e-docker\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n        run: |\n          make e2e-docker\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-e2e-docker-short\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  e2e-iso:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Download artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: e2e-iso\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make e2e-iso\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-e2e-iso\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  e2e-qemu-short:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Download artifacts\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        run: |\n          make ci-temp-release-tag\n      - name: e2e-qemu\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-short\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-e2e-qemu-short\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  grype-scan:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: login-to-registry\n        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # version: v4.0.0\n        with:\n          password: ${{ secrets.GITHUB_TOKEN }}\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n      - name: local-grype-scan-result\n        env:\n          DEST: _out\n        run: |\n          make local-grype-scan-result\n      - name: target-grype-validate\n        run: |\n          make target-grype-validate\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-grype-scan-result\n          path: |\n            _out/grype-scan.log\n          retention-days: \"5\"\n  integration-airgapped:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/airgapped') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: integration-images-list\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make integration-images-list\n      - name: e2e-airgapped-no-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: no-proxy\n          WITH_CLUSTER_DISCOVERY: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-http-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-http-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: http-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-secure-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-secure-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: secure-http-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-reverse-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-reverse-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: https-reverse-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-airgapped\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n            /tmp/airgapped*.log\n          retention-days: \"5\"\n  integration-aws:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/aws') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: default\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-aws-nvidia-nonfree-lts:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-nonfree-lts') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-nonfree') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-lts nonfree-kmod-nvidia-lts extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-nonfree-lts\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-nonfree-lts\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-aws-nvidia-nonfree-production:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-nonfree-production') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-nonfree') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-production nonfree-kmod-nvidia-production extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-nonfree-production\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-nonfree-production\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-aws-nvidia-oss-lts:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-oss-lts') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-oss') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-lts nvidia-open-gpu-kernel-modules-lts extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-oss-lts\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-oss-lts\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia -talos.verifyukibooted=false\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-aws-nvidia-oss-production:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-oss-production') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia-oss') || contains(fromJSON(needs.default.outputs.labels), 'integration/aws-nvidia')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-production nvidia-open-gpu-kernel-modules-production extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-oss-production\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-oss-production\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia -talos.verifyukibooted=false\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-cilium:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/cilium') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-cilium\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-no-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-cilium-strict\n        env:\n          CILIUM_INSTALL_TYPE: strict\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-cilium-strict-kubespan\n        env:\n          CILIUM_INSTALL_TYPE: strict\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-cilium\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-cloud-images:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/cloud-images')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: images\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images\n      - name: cloud-images\n        run: |\n          make cloud-images\n  integration-conformance:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/conformance') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: conformance-qemu\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TEST_MODE: fast-conformance\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-conformance\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-conformance-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/conformance-enforcing')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: conformance-qemu\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TAG_SUFFIX_IN: -enforcing\n          TEST_MODE: fast-conformance\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-conformance-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-embedded:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/embedded') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-embedded\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make e2e-embedded\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-embedded\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-extensions:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/extensions') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: unshallow-extensions\n        run: |\n          git -C _out/extensions fetch --prune --unshallow\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make all extensions-metadata -C _out/extensions\n      - name: installer extensions\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make installer-with-extensions\n      - name: e2e-extensions\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.qemu\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-extensions\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"3\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          QEMU_WORKERS: \"1\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_WORKER: '@_out/installer-extensions-patch.yaml:@hack/test/patches/extensions.yaml:@hack/test/patches/dm-raid-module.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-extensions\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-gcp:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/gcp') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: image-gcp\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-gcp\n      - name: e2e-gcp-prepare\n        run: |\n          make e2e-gcp-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: gcp\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-gcp\n        run: |\n          make e2e-gcp\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: gcp\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n  integration-image-cache:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/image-cache') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-cache\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make cache-create\n      - name: e2e-image-cache\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          REGISTRY_MIRROR_FLAGS: \"no\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-verification.yaml'\n          WITH_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-image-cache-encrypted\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache-encrypted\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          REGISTRY_MIRROR_FLAGS: \"no\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-cache-encrypted.yaml:@hack/test/patches/image-verification.yaml'\n          WITH_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-image-cache\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-image-factory:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/image-factory')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: factory-1.11-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-iso\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-image\n        env:\n          FACTORY_BOOT_METHOD: disk-image\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-image\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-pxe\n        env:\n          FACTORY_BOOT_METHOD: ipxe\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_VERSION: v1.11.6\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-pxe\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-secureboot\n        env:\n          FACTORY_BOOT_METHOD: secureboot-iso\n          FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-secureboot\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.10-secureboot\n        env:\n          FACTORY_BOOT_METHOD: secureboot-iso\n          FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE_VERSION: v1.10.9\n          FACTORY_VERSION: v1.10.8\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-secureboot\n          KUBERNETES_VERSION: 1.33.7\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.10-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.10.9\n          FACTORY_VERSION: v1.10.8\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-iso\n          KUBERNETES_VERSION: 1.33.7\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.9-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.9.6\n          FACTORY_VERSION: v1.9.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.9-iso\n          KUBERNETES_VERSION: 1.32.11\n        run: |\n          sudo -E make e2e-image-factory\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-image-factory\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-images:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/images') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images\n  integration-misc-0:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-0') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-metal-uki\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-metal-uki\n      - name: e2e-firewall\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-firewall\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_FIREWALL: block\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-canal-reset\n        env:\n          CUSTOM_CNI_URL: https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/canal.yaml\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-canal-reset\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          INTEGRATION_TEST_RUN: TestIntegration/api.ResetSuite/TestResetWithSpec\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-controlplane-port\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-controlplane-port\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/ephemeral-min-max.yaml'\n          WITH_CONTROL_PLANE_PORT: \"443\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-uki-4k\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-uki-4k\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_4K_DISK: \"true\"\n          WITH_UKI_BOOT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-flannel-netpol\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-flannel-netpol\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TEST_MODE: network-policy\n          WITH_CONFIG_PATCH: '@hack/test/patches/flannel-netpol.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-0\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-1:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-1') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-no-cluster-discovery\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CLUSTER_DISCOVERY: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-kubespan\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CLUSTER_DISCOVERY: \"true\"\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-default-hostname\n        env:\n          DISABLE_DHCP_HOSTNAME: \"true\"\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-min-requirements\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_MEMORY_CONTROLPLANES: \"2048\"\n          QEMU_MEMORY_WORKERS: \"1024\"\n          QEMU_SYSTEM_DISK_SIZE: \"10240\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-1\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-1-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-1-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-no-cluster-discovery\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CLUSTER_DISCOVERY: \"false\"\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-kubespan\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CLUSTER_DISCOVERY: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-default-hostname\n        env:\n          DISABLE_DHCP_HOSTNAME: \"true\"\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-min-requirements\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_MEMORY_CONTROLPLANES: \"2048\"\n          QEMU_MEMORY_WORKERS: \"1024\"\n          QEMU_SYSTEM_DISK_SIZE: \"10240\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-1-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-2:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-2') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n        run: |\n          make iso\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: e2e-bios\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-bios-iso\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ISO: \"true\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-disk-image\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          USE_DISK_IMAGE: \"true\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_JSON_LOGS: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-disk-image-bios\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image-bios\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          USE_DISK_IMAGE: \"true\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-node-address-v2\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/node-address-v2.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-tpm1_2\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-tpm1_2\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_TPM1_2: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-2\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-3:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-3') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-network-chaos\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_NETWORK_CHAOS: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-metal-iso\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_INJECTION_METHOD: metal-iso\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-iommu-pcidriverrebind\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_IOMMU: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-3\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-3-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-3-enforcing')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-network-chaos\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n          WITH_NETWORK_CHAOS: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-metal-iso\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CONFIG_INJECTION_METHOD: metal-iso\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-iommu-pcidriverrebind\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n          WITH_IOMMU: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-3-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-4:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-4') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-siderolink\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tunnel\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: tunnel\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tls\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: wireguard+tls\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-apparmor\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_APPARMOR_LSM_ENABLED: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-k8s-user-namespace\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/usernamespace.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-4\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-misc-4-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/misc-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/misc-4-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-siderolink\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tunnel\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: tunnel\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tls\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: wireguard+tls\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-apparmor\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_APPARMOR_LSM_ENABLED: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-k8s-user-namespace\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CONFIG_PATCH: '@hack/test/patches/usernamespace.yaml'\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-4-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-provision-0:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/provision') || contains(fromJSON(needs.default.outputs.labels), 'integration/provision-0') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-0\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-0\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-0\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-provision-1:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/provision') || contains(fromJSON(needs.default.outputs.labels), 'integration/provision-1') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-1\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-1\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-1\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-provision-2:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/provision') || contains(fromJSON(needs.default.outputs.labels), 'integration/provision-2') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: installer\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=talos.extra_cmdline=extra-super-cmdline\n          PLATFORM: linux/amd64,linux/arm64\n          TAG_SUFFIX_OUT: -extra-cmdline\n        run: |\n          make installer\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-2\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-2\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-2\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-provision-3:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/provision') || contains(fromJSON(needs.default.outputs.labels), 'integration/provision-3') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-3\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-3\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-3\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          USER_DISKS_MOUNTS: /var/mnt/extra,/var/mnt/p1,/var/mnt/p2\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_USER_DISK: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-csi-longhorn:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi') || contains(fromJSON(needs.default.outputs.labels), 'integration/extensions') || contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi-longhorn') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make iscsi-tools util-linux-tools extensions-metadata -C _out/extensions\n      - name: installer extensions\n        env:\n          EXTENSIONS_FILTER_COMMAND: grep -E '/iscsi-tools|util-linux-tools'\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make installer-with-extensions\n      - name: kubelet-fat-patch\n        run: |\n          make kubelet-fat-patch\n      - name: e2e-qemu-csi-longhorn\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=longhorn\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-longhorn\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_DRIVERS: nvme\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_SYSTEM_DISK_SIZE: \"20480\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/longhorn-cp.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@_out/installer-extensions-patch.yaml:@_out/kubelet-fat-patch.yaml:@hack/test/patches/longhorn.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-longhorn\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-longhorn\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-csi-openebs:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi') || contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi-openebs') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu-csi-openebs\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=openebs\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-openebs\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"4\"\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/openebs-cp.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/openebs.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-openebs\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-openebs\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-csi-rook-ceph:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi') || contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-csi-rook-ceph') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu-csi-rook-ceph\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=rook-ceph\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-rook-ceph\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/rook-ceph.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-rook-ceph\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-rook-ceph\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-encrypted-vip:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-encrypted-vip') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_KUBESPAN: \"true\"\n          WITH_VIRTUAL_IP: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-encrypted-vip\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-enforcing') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-qemu\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"3\"\n          QEMU_EXTRA_DISKS_DRIVERS: ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          TAG_SUFFIX_IN: -enforcing\n          USER_DISKS_MOUNTS: /var/mnt/extra,/var/mnt/p1,/var/mnt/p2\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_ENFORCING: \"true\"\n          WITH_USER_DISK: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-qemu-race:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/qemu-race') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: build-race\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          TAG_SUFFIX: -race\n          WITH_RACE: \"1\"\n        run: |\n          make initramfs installer-base imager installer\n      - name: e2e-qemu-race\n        env:\n          EXTRA_TEST_ARGS: -talos.race\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-race\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          QEMU_MEMORY_CONTROLPLANES: \"4096\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TAG_SUFFIX: -race\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-race\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-reproducibility-test:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/reproducibility-test') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: reproducibility-test\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make reproducibility-test\n  integration-trusted-boot:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/trusted-boot') || contains(fromJSON(needs.default.outputs.labels), 'integration/release-gate')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: secureboot-iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make secureboot-iso\n      - name: integration-trusted-boot\n        env:\n          EXTRA_TEST_ARGS: -talos.trustedboot\n          GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_TRUSTED_BOOT_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-trusted-boot\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  integration-trusted-boot-enforcing:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: contains(fromJSON(needs.default.outputs.labels), 'integration/trusted-boot-enforcing')\n    needs:\n      - default\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: secureboot-iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make secureboot-iso\n      - name: integration-trusted-boot-enforcing\n        env:\n          EXTRA_TEST_ARGS: -talos.trustedboot -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot-enforcing\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_TRUSTED_BOOT_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-trusted-boot-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n  push:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) && github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/tags/')\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: build\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make talosctl-all kernel sd-boot sd-stub initramfs installer-base imager talos\n      - name: release-notes\n        run: |\n          make release-notes\n      - name: login-to-registry\n        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # version: v4.0.0\n        with:\n          password: ${{ secrets.GITHUB_TOKEN }}\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n      - name: push\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make push\n      - name: push-latest\n        if: github.ref == 'refs/heads/main'\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make push-latest\n  tag:\n    permissions:\n      actions: read\n      contents: write\n      id-token: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: large\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/')) && startsWith(github.ref, 'refs/tags/')\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: build\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make talosctl-all kernel sd-boot sd-stub initramfs installer-base imager talos talosctl-cni-bundle\n      - name: release-notes\n        run: |\n          make release-notes\n      - name: sbom\n        run: |\n          make sbom\n      - name: login-to-registry\n        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # version: v4.0.0\n        with:\n          password: ${{ secrets.GITHUB_TOKEN }}\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n      - name: push\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make push\n      - name: images\n        env:\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images\n      - name: Install Cosign\n        uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # version: v4.1.0\n      - name: Sign artifacts\n        run: |\n          cosign sign-blob --bundle _out/initramfs-amd64.xz.bundle --yes _out/initramfs-amd64.xz\n          cosign sign-blob --bundle _out/initramfs-arm64.xz.bundle --yes _out/initramfs-arm64.xz\n          cosign sign-blob --bundle _out/metal-amd64.iso.bundle --yes _out/metal-amd64.iso\n          cosign sign-blob --bundle _out/metal-arm64.iso.bundle --yes _out/metal-arm64.iso\n          cosign sign-blob --bundle _out/metal-amd64-uki.efi.bundle --yes _out/metal-amd64-uki.efi\n          cosign sign-blob --bundle _out/metal-arm64-uki.efi.bundle --yes _out/metal-arm64-uki.efi\n          cosign sign-blob --bundle _out/metal-amd64.raw.zst.bundle --yes _out/metal-amd64.raw.zst\n          cosign sign-blob --bundle _out/metal-arm64.raw.zst.bundle --yes _out/metal-arm64.raw.zst\n          cosign sign-blob --bundle _out/talos-arm64.spdx.json.bundle --yes _out/talos-arm64.spdx.json\n          cosign sign-blob --bundle _out/talos-amd64.spdx.json.bundle --yes _out/talos-amd64.spdx.json\n          cosign sign-blob --bundle _out/talos-container-arm64.spdx.json.bundle --yes _out/talos-container-arm64.spdx.json\n          cosign sign-blob --bundle _out/talos-container-amd64.spdx.json.bundle --yes _out/talos-container-amd64.spdx.json\n          cosign sign-blob --bundle _out/talosctl-cni-bundle-amd64.tar.gz.bundle --yes _out/talosctl-cni-bundle-amd64.tar.gz\n          cosign sign-blob --bundle _out/talosctl-cni-bundle-arm64.tar.gz.bundle --yes _out/talosctl-cni-bundle-arm64.tar.gz\n          cosign sign-blob --bundle _out/talosctl-darwin-amd64.bundle --yes _out/talosctl-darwin-amd64\n          cosign sign-blob --bundle _out/talosctl-darwin-arm64.bundle --yes _out/talosctl-darwin-arm64\n          cosign sign-blob --bundle _out/talosctl-freebsd-amd64.bundle --yes _out/talosctl-freebsd-amd64\n          cosign sign-blob --bundle _out/talosctl-freebsd-arm64.bundle --yes _out/talosctl-freebsd-arm64\n          cosign sign-blob --bundle _out/talosctl-linux-amd64.bundle --yes _out/talosctl-linux-amd64\n          cosign sign-blob --bundle _out/talosctl-linux-arm64.bundle --yes _out/talosctl-linux-arm64\n          cosign sign-blob --bundle _out/talosctl-linux-armv7.bundle --yes _out/talosctl-linux-armv7\n          cosign sign-blob --bundle _out/talosctl-linux-riscv64.bundle --yes _out/talosctl-linux-riscv64\n          cosign sign-blob --bundle _out/talosctl-windows-amd64.exe.bundle --yes _out/talosctl-windows-amd64.exe\n          cosign sign-blob --bundle _out/talosctl-windows-arm64.exe.bundle --yes _out/talosctl-windows-arm64.exe\n          cosign sign-blob --bundle _out/vmlinuz-amd64.bundle --yes _out/vmlinuz-amd64\n          cosign sign-blob --bundle _out/vmlinuz-arm64.bundle --yes _out/vmlinuz-arm64\n      - name: Generate Checksums\n        run: |\n          cd _out\n          sha256sum initramfs-amd64.xz initramfs-arm64.xz metal-amd64.iso metal-arm64.iso metal-amd64-uki.efi metal-arm64-uki.efi metal-amd64.raw.zst metal-arm64.raw.zst talos-arm64.spdx.json talos-amd64.spdx.json talos-container-arm64.spdx.json talos-container-amd64.spdx.json talosctl-cni-bundle-amd64.tar.gz talosctl-cni-bundle-arm64.tar.gz talosctl-darwin-amd64 talosctl-darwin-arm64 talosctl-freebsd-amd64 talosctl-freebsd-arm64 talosctl-linux-amd64 talosctl-linux-arm64 talosctl-linux-armv7 talosctl-linux-riscv64 talosctl-windows-amd64.exe talosctl-windows-arm64.exe vmlinuz-amd64 vmlinuz-arm64 > sha256sum.txt\n          sha512sum initramfs-amd64.xz initramfs-arm64.xz metal-amd64.iso metal-arm64.iso metal-amd64-uki.efi metal-arm64-uki.efi metal-amd64.raw.zst metal-arm64.raw.zst talos-arm64.spdx.json talos-amd64.spdx.json talos-container-arm64.spdx.json talos-container-amd64.spdx.json talosctl-cni-bundle-amd64.tar.gz talosctl-cni-bundle-arm64.tar.gz talosctl-darwin-amd64 talosctl-darwin-arm64 talosctl-freebsd-amd64 talosctl-freebsd-arm64 talosctl-linux-amd64 talosctl-linux-arm64 talosctl-linux-armv7 talosctl-linux-riscv64 talosctl-windows-amd64.exe talosctl-windows-arm64.exe vmlinuz-amd64 vmlinuz-arm64 > sha512sum.txt\n      - name: Sign checksums\n        run: |\n          cd _out\n          cosign sign-blob --bundle sha256sum.txt.bundle --yes sha256sum.txt\n          cosign sign-blob --bundle sha512sum.txt.bundle --yes sha512sum.txt\n      - name: release\n        uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # version: v2.5.0\n        with:\n          body_path: _out/RELEASE_NOTES.md\n          draft: \"true\"\n          files: |-\n            _out/initramfs-amd64.xz\n            _out/initramfs-arm64.xz\n            _out/metal-amd64.iso\n            _out/metal-arm64.iso\n            _out/metal-amd64-uki.efi\n            _out/metal-arm64-uki.efi\n            _out/metal-amd64.raw.zst\n            _out/metal-arm64.raw.zst\n            _out/talos-arm64.spdx.json\n            _out/talos-amd64.spdx.json\n            _out/talos-container-arm64.spdx.json\n            _out/talos-container-amd64.spdx.json\n            _out/talosctl-cni-bundle-amd64.tar.gz\n            _out/talosctl-cni-bundle-arm64.tar.gz\n            _out/talosctl-darwin-amd64\n            _out/talosctl-darwin-arm64\n            _out/talosctl-freebsd-amd64\n            _out/talosctl-freebsd-arm64\n            _out/talosctl-linux-amd64\n            _out/talosctl-linux-arm64\n            _out/talosctl-linux-armv7\n            _out/talosctl-linux-riscv64\n            _out/talosctl-windows-amd64.exe\n            _out/talosctl-windows-arm64.exe\n            _out/vmlinuz-amd64\n            _out/vmlinuz-arm64\n            _out/sha*.txt\n            _out/*.bundle\n"
  },
  {
    "path": ".github/workflows/dispatch.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-02-17T20:54:45Z by kres 6458cfd.\n\n\"on\":\n  workflow_dispatch:\n    inputs:\n      release:\n        description: \"\"\n        type: string\n        required: false\n      tag:\n        description: \"\"\n        type: string\n        required: false\nname: dispatch\njobs:\n  cloud-images:\n    permissions:\n      actions: read\n      contents: write\n      issues: read\n      packages: write\n      pull-requests: read\n    runs-on:\n      group: generic\n    if: (!startsWith(github.head_ref, 'renovate/') && !startsWith(github.head_ref, 'dependabot/'))\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: cloud-images\n        env:\n          CLOUD_IMAGES_EXTRA_ARGS: --use-factory\n          PLATFORM: linux/amd64,linux/arm64\n          TAG: ${{ github.event.inputs.tag }}\n        run: |\n          make cloud-images\n      - name: attach-images\n        env:\n          GH_TOKEN: ${{ github.token }}\n          RELEASE: ${{ github.event.inputs.release }}\n        run: |\n          gh release upload \"${RELEASE}\" --clobber \\\n            _out/cloud-images.json\n"
  },
  {
    "path": ".github/workflows/grype-scan-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: grype-scan-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: login-to-registry\n        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # version: v4.0.0\n        with:\n          password: ${{ secrets.GITHUB_TOKEN }}\n          registry: ghcr.io\n          username: ${{ github.repository_owner }}\n      - name: local-grype-scan-result\n        env:\n          DEST: _out\n        run: |\n          make local-grype-scan-result\n      - name: target-grype-validate\n        run: |\n          make target-grype-validate\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-grype-scan-result\n          path: |\n            _out/grype-scan.log\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-airgapped-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-airgapped-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: integration-images-list\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make integration-images-list\n      - name: e2e-airgapped-no-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: no-proxy\n          WITH_CLUSTER_DISCOVERY: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-http-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-http-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: http-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-secure-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-secure-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: secure-http-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-airgapped-reverse-proxy\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-reverse-proxy\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_AIRGAPPED: https-reverse-proxy\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-airgapped\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n            /tmp/airgapped*.log\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-aws-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-aws-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: default\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-aws-nvidia-nonfree-lts-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-aws-nvidia-nonfree-lts-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-lts nonfree-kmod-nvidia-lts extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-nonfree-lts\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-nonfree-lts\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-aws-nvidia-nonfree-production-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-aws-nvidia-nonfree-production-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-production nonfree-kmod-nvidia-production extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-nonfree-production\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-nonfree-production\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-aws-nvidia-oss-lts-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-aws-nvidia-oss-lts-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-lts nvidia-open-gpu-kernel-modules-lts extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-oss-lts\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-oss-lts\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia -talos.verifyukibooted=false\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-aws-nvidia-oss-production-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-aws-nvidia-oss-production-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-aws\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-aws\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make nvidia-container-toolkit-production nvidia-open-gpu-kernel-modules-production extensions-metadata -C _out/extensions\n      - name: e2e-aws-prepare\n        env:\n          E2E_AWS_TARGET: nvidia-oss-production\n          EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make e2e-aws-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-aws-nvidia-oss-production\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.nvidia -talos.verifyukibooted=false\n          INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        run: |\n          make e2e-aws\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: aws\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-cilium-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-cilium-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-cilium\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-no-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-cilium-strict\n        env:\n          CILIUM_INSTALL_TYPE: strict\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-cilium-strict-kubespan\n        env:\n          CILIUM_INSTALL_TYPE: strict\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/cilium-kubeproxy.yaml'\n          WITH_CUSTOM_CNI: cilium\n          WITH_FIREWALL: accept\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-cilium\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-conformance-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-conformance-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: conformance-qemu\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TEST_MODE: fast-conformance\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-conformance\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-conformance-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-conformance-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: conformance-qemu\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TAG_SUFFIX_IN: -enforcing\n          TEST_MODE: fast-conformance\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-conformance-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-embedded-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-embedded-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-embedded\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make e2e-embedded\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-embedded\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-extensions-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 6 * * *\nname: integration-extensions-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: unshallow-extensions\n        run: |\n          git -C _out/extensions fetch --prune --unshallow\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make all extensions-metadata -C _out/extensions\n      - name: installer extensions\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make installer-with-extensions\n      - name: e2e-extensions\n        env:\n          EXTRA_TEST_ARGS: -talos.extensions.qemu\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-extensions\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"3\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          QEMU_WORKERS: \"1\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_WORKER: '@_out/installer-extensions-patch.yaml:@hack/test/patches/extensions.yaml:@hack/test/patches/dm-raid-module.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-extensions\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-gcp-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 7 * * *\nname: integration-gcp-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Mask secrets\n        run: |\n          echo \"$(sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | \"::add-mask::\" + .value')\"\n      - name: Set secrets for job\n        run: |\n          sops -d .secrets.yaml | yq -e '.secrets | to_entries[] | .key + \"=\" + .value' >> \"$GITHUB_ENV\"\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: image-gcp\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-gcp\n      - name: e2e-gcp-prepare\n        run: |\n          make e2e-gcp-prepare\n      - name: checkout contrib\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/contrib\n          ref: main\n          repository: siderolabs/contrib\n      - name: setup tf\n        uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # version: v4.0.0\n        with:\n          terraform_wrapper: \"false\"\n      - name: tf apply\n        env:\n          TF_E2E_ACTION: apply\n          TF_E2E_TEST_TYPE: gcp\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n      - name: e2e-gcp\n        run: |\n          make e2e-gcp\n      - name: tf destroy\n        if: always()\n        env:\n          TF_E2E_ACTION: destroy\n          TF_E2E_REFRESH_ON_DESTROY: \"false\"\n          TF_E2E_TEST_TYPE: gcp\n          TF_SCRIPT_DIR: _out/contrib\n        run: |\n          make e2e-cloud-tf\n"
  },
  {
    "path": ".github/workflows/integration-image-cache-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-16T10:48:51Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 2 * * *\nname: integration-image-cache-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-cache\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make cache-create\n      - name: e2e-image-cache\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          REGISTRY_MIRROR_FLAGS: \"no\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-verification.yaml'\n          WITH_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-image-cache-encrypted\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache-encrypted\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          REGISTRY_MIRROR_FLAGS: \"no\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-cache-encrypted.yaml:@hack/test/patches/image-verification.yaml'\n          WITH_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-image-cache\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-image-factory-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 6 * * *\nname: integration-image-factory-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: factory-1.11-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-iso\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-image\n        env:\n          FACTORY_BOOT_METHOD: disk-image\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-image\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-pxe\n        env:\n          FACTORY_BOOT_METHOD: ipxe\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_VERSION: v1.11.6\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-pxe\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.11-secureboot\n        env:\n          FACTORY_BOOT_METHOD: secureboot-iso\n          FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE_VERSION: v1.11.6\n          FACTORY_VERSION: v1.11.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-secureboot\n          KUBERNETES_VERSION: 1.34.3\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.10-secureboot\n        env:\n          FACTORY_BOOT_METHOD: secureboot-iso\n          FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE_VERSION: v1.10.9\n          FACTORY_VERSION: v1.10.8\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-secureboot\n          KUBERNETES_VERSION: 1.33.7\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.10-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.10.9\n          FACTORY_VERSION: v1.10.8\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-iso\n          KUBERNETES_VERSION: 1.33.7\n        run: |\n          sudo -E make e2e-image-factory\n      - name: factory-1.9-iso\n        env:\n          FACTORY_BOOT_METHOD: iso\n          FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n          FACTORY_UPGRADE: \"true\"\n          FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n          FACTORY_UPGRADE_VERSION: v1.9.6\n          FACTORY_VERSION: v1.9.5\n          GITHUB_STEP_NAME: ${{ github.job}}-factory-1.9-iso\n          KUBERNETES_VERSION: 1.32.11\n        run: |\n          sudo -E make e2e-image-factory\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-image-factory\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-images-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 2 * * *\nname: integration-images-cron\njobs:\n  default:\n    runs-on:\n      group: generic\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images\n"
  },
  {
    "path": ".github/workflows/integration-misc-0-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-0-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: image-metal-uki\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make image-metal-uki\n      - name: e2e-firewall\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-firewall\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_FIREWALL: block\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-canal-reset\n        env:\n          CUSTOM_CNI_URL: https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/canal.yaml\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-canal-reset\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          INTEGRATION_TEST_RUN: TestIntegration/api.ResetSuite/TestResetWithSpec\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-controlplane-port\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-controlplane-port\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/ephemeral-min-max.yaml'\n          WITH_CONTROL_PLANE_PORT: \"443\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-uki-4k\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-uki-4k\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_4K_DISK: \"true\"\n          WITH_UKI_BOOT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-flannel-netpol\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-flannel-netpol\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TEST_MODE: network-policy\n          WITH_CONFIG_PATCH: '@hack/test/patches/flannel-netpol.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-0\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-1-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-1-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-no-cluster-discovery\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CLUSTER_DISCOVERY: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-kubespan\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CLUSTER_DISCOVERY: \"true\"\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-default-hostname\n        env:\n          DISABLE_DHCP_HOSTNAME: \"true\"\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-min-requirements\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_MEMORY_CONTROLPLANES: \"2048\"\n          QEMU_MEMORY_WORKERS: \"1024\"\n          QEMU_SYSTEM_DISK_SIZE: \"10240\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-1\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-1-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-1-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-no-cluster-discovery\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CLUSTER_DISCOVERY: \"false\"\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-kubespan\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CLUSTER_DISCOVERY: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_KUBESPAN: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-default-hostname\n        env:\n          DISABLE_DHCP_HOSTNAME: \"true\"\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-min-requirements\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_MEMORY_CONTROLPLANES: \"2048\"\n          QEMU_MEMORY_WORKERS: \"1024\"\n          QEMU_SYSTEM_DISK_SIZE: \"10240\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-1-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-2-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-2-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n        run: |\n          make iso\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: e2e-bios\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-bios-iso\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ISO: \"true\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-disk-image\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          USE_DISK_IMAGE: \"true\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_JSON_LOGS: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-disk-image-bios\n        env:\n          EXTRA_TEST_ARGS: -talos.verifyukibooted=false\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image-bios\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          USE_DISK_IMAGE: \"true\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_UEFI: \"false\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-node-address-v2\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/node-address-v2.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-tpm1_2\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-tpm1_2\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_TPM1_2: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-2\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-3-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-3-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-network-chaos\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_NETWORK_CHAOS: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-metal-iso\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_INJECTION_METHOD: metal-iso\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-iommu-pcidriverrebind\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_IOMMU: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-3\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-3-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-3-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-network-chaos\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n          WITH_NETWORK_CHAOS: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-metal-iso\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CONFIG_INJECTION_METHOD: metal-iso\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-iommu-pcidriverrebind\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_ENFORCING: \"true\"\n          WITH_IOMMU: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-3-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-4-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-4-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-siderolink\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tunnel\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: tunnel\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tls\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_SIDEROLINK_AGENT: wireguard+tls\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-apparmor\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_APPARMOR_LSM_ENABLED: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-k8s-user-namespace\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/usernamespace.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-4\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-misc-4-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 5 * * *\nname: integration-misc-4-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-siderolink\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tunnel\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: tunnel\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-siderolink-tls\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_SIDEROLINK_AGENT: wireguard+tls\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-apparmor\n        env:\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_APPARMOR_LSM_ENABLED: \"yes\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: e2e-k8s-user-namespace\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          SHORT_INTEGRATION_TEST: \"yes\"\n          TAG_SUFFIX_IN: -enforcing\n          WITH_CONFIG_PATCH: '@hack/test/patches/usernamespace.yaml'\n          WITH_ENFORCING: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-misc-4-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-provision-0-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-provision-0-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-0\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-0\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-0\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-provision-1-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-provision-1-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-1\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-1\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-1\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-provision-2-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-provision-2-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: installer\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=talos.extra_cmdline=extra-super-cmdline\n          PLATFORM: linux/amd64,linux/arm64\n          TAG_SUFFIX_OUT: -extra-cmdline\n        run: |\n          make installer\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-2\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-2\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-2\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-provision-3-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-16T15:20:50Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 4 * * *\nname: integration-provision-3-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: provision-tests-prepare\n        run: |\n          make provision-tests-prepare\n      - name: provision-tests-track-3\n        env:\n          GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          sudo -E make provision-tests-track-3\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-provision-3\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          USER_DISKS_MOUNTS: /var/mnt/extra,/var/mnt/p1,/var/mnt/p2\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_USER_DISK: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-csi-longhorn-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-csi-longhorn-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: generate\n        if: github.event_name == 'schedule'\n        run: |\n          make generate\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: checkout extensions\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n        with:\n          path: _out/extensions\n          ref: main\n          repository: siderolabs/extensions\n      - name: set variables\n        run: |\n          cat _out/talos-metadata >> \"$GITHUB_ENV\"\n      - name: build extensions\n        env:\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make iscsi-tools util-linux-tools extensions-metadata -C _out/extensions\n      - name: installer extensions\n        env:\n          EXTENSIONS_FILTER_COMMAND: grep -E '/iscsi-tools|util-linux-tools'\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make installer-with-extensions\n      - name: kubelet-fat-patch\n        run: |\n          make kubelet-fat-patch\n      - name: e2e-qemu-csi-longhorn\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=longhorn\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-longhorn\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_DRIVERS: nvme\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_SYSTEM_DISK_SIZE: \"20480\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/longhorn-cp.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@_out/installer-extensions-patch.yaml:@_out/kubelet-fat-patch.yaml:@hack/test/patches/longhorn.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-longhorn\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-longhorn\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-csi-openebs-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-csi-openebs-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu-csi-openebs\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=openebs\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-openebs\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"4\"\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/openebs-cp.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/openebs.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-openebs\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-openebs\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-csi-rook-ceph-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-csi-rook-ceph-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu-csi-rook-ceph\n        env:\n          EXTRA_TEST_ARGS: -talos.csi=rook-ceph\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-rook-ceph\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_CPUS_WORKERS: \"6\"\n          QEMU_EXTRA_DISKS: \"1\"\n          QEMU_EXTRA_DISKS_SIZE: \"12288\"\n          QEMU_MEMORY_WORKERS: \"8192\"\n          QEMU_WORKERS: \"3\"\n          SHORT_INTEGRATION_TEST: \"yes\"\n          WITH_CONFIG_PATCH_CONTROLPLANE: '@hack/test/patches/rook-ceph.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: fio-integration-qemu-csi-rook-ceph\n          path: |\n            /tmp/fio-*.json\n          retention-days: \"180\"\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-csi-rook-ceph\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-encrypted-vip-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-encrypted-vip-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: e2e-qemu\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_DISK_ENCRYPTION: \"true\"\n          WITH_KUBESPAN: \"true\"\n          WITH_VIRTUAL_IP: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-encrypted-vip\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: e2e-qemu\n        env:\n          EXTRA_TEST_ARGS: -talos.enforcing\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"3\"\n          QEMU_EXTRA_DISKS_DRIVERS: ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          TAG_SUFFIX_IN: -enforcing\n          USER_DISKS_MOUNTS: /var/mnt/extra,/var/mnt/p1,/var/mnt/p2\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n          WITH_ENFORCING: \"true\"\n          WITH_USER_DISK: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-qemu-race-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-qemu-race-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: build-race\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64\n          PUSH: \"true\"\n          TAG_SUFFIX: -race\n          WITH_RACE: \"1\"\n        run: |\n          make initramfs installer-base imager installer\n      - name: e2e-qemu-race\n        env:\n          EXTRA_TEST_ARGS: -talos.race\n          GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-race\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          QEMU_EXTRA_DISKS: \"4\"\n          QEMU_EXTRA_DISKS_DRIVERS: virtiofs,ide,nvme\n          QEMU_EXTRA_DISKS_SIZE: \"10240\"\n          QEMU_EXTRA_DISKS_TAGS: disk0\n          QEMU_MEMORY_CONTROLPLANES: \"4096\"\n          QEMU_MEMORY_WORKERS: \"4096\"\n          TAG_SUFFIX: -race\n          WITH_CONFIG_PATCH_WORKER: '@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml'\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-qemu-race\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-reproducibility-test-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 2 * * *\nname: integration-reproducibility-test-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: reproducibility-test\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n        run: |\n          make reproducibility-test\n"
  },
  {
    "path": ".github/workflows/integration-trusted-boot-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-trusted-boot-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make images-essential\n      - name: secureboot-iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make secureboot-iso\n      - name: integration-trusted-boot\n        env:\n          EXTRA_TEST_ARGS: -talos.trustedboot\n          GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_CONFIG_PATCH: '@hack/test/patches/image-verification.yaml'\n          WITH_TRUSTED_BOOT_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-trusted-boot\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/integration-trusted-boot-enforcing-cron.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-15T13:42:44Z by kres e68c408.\n\nconcurrency:\n  group: ${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\"on\":\n  schedule:\n    - cron: 30 3 * * *\nname: integration-trusted-boot-enforcing-cron\njobs:\n  default:\n    runs-on:\n      group: large\n    steps:\n      - name: gather-system-info\n        id: system-info\n        uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0\n        continue-on-error: true\n      - name: print-system-info\n        run: |\n          MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))\n\n          OUTPUTS=(\n            \"CPU Core: ${{ steps.system-info.outputs.cpu-core }}\"\n            \"CPU Model: ${{ steps.system-info.outputs.cpu-model }}\"\n            \"Hostname: ${{ steps.system-info.outputs.hostname }}\"\n            \"NodeName: ${NODE_NAME}\"\n            \"Kernel release: ${{ steps.system-info.outputs.kernel-release }}\"\n            \"Kernel version: ${{ steps.system-info.outputs.kernel-version }}\"\n            \"Name: ${{ steps.system-info.outputs.name }}\"\n            \"Platform: ${{ steps.system-info.outputs.platform }}\"\n            \"Release: ${{ steps.system-info.outputs.release }}\"\n            \"Total memory: ${MEMORY_GB} GB\"\n          )\n\n          for OUTPUT in \"${OUTPUTS[@]}\";do\n            echo \"${OUTPUT}\"\n          done\n        continue-on-error: true\n      - name: checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # version: v6.0.2\n      - name: Unshallow\n        run: |\n          git fetch --prune --unshallow\n      - name: Set up Docker Buildx\n        id: setup-buildx\n        uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # version: v4.0.0\n        with:\n          driver: remote\n          endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234\n        timeout-minutes: 10\n      - name: Download artifacts\n        if: github.event_name != 'schedule'\n        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # version: v8.0.0\n        with:\n          name: talos-artifacts\n          path: _out\n      - name: Fix artifact permissions\n        if: github.event_name != 'schedule'\n        run: |\n          xargs -a _out/executable-artifacts -I {} chmod +x {}\n      - name: ci-temp-release-tag\n        if: github.event_name != 'schedule'\n        run: |\n          make ci-temp-release-tag\n      - name: uki-certs\n        if: github.event_name == 'schedule'\n        env:\n          PLATFORM: linux/amd64\n        run: |\n          make uki-certs\n      - name: build\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n        run: |\n          make talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n      - name: talosctl-cni-bundle\n        if: github.event_name == 'schedule'\n        run: |\n          make talosctl-cni-bundle\n      - name: images-essential-enforcing\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n          PUSH: \"true\"\n          TAG_SUFFIX_OUT: -enforcing\n        run: |\n          make images-essential\n      - name: secureboot-iso\n        if: github.event_name == 'schedule'\n        env:\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          IMAGER_ARGS: --extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\n          PLATFORM: linux/amd64,linux/arm64\n        run: |\n          make secureboot-iso\n      - name: integration-trusted-boot-enforcing\n        env:\n          EXTRA_TEST_ARGS: -talos.trustedboot -talos.enforcing\n          GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot-enforcing\n          IMAGE_REGISTRY: registry.dev.siderolabs.io\n          TAG_SUFFIX_IN: -enforcing\n          VIA_MAINTENANCE_MODE: \"true\"\n          WITH_ENFORCING: \"true\"\n          WITH_TRUSTED_BOOT_ISO: \"true\"\n        run: |\n          sudo -E make e2e-qemu\n      - name: save artifacts\n        if: always()\n        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # version: v7.0.0\n        with:\n          name: talos-logs-integration-trusted-boot-enforcing\n          path: |-\n            /tmp/logs-*.tar.gz\n            /tmp/support-*.zip\n          retention-days: \"5\"\n"
  },
  {
    "path": ".github/workflows/lock.yaml",
    "content": "name: 'Lock old issues'\n\non:\n  schedule:\n    - cron: '0 2 * * *'\n  workflow_dispatch:\n\npermissions:\n  issues: write\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: dessant/lock-threads@v5\n        with:\n          issue-inactive-days: '60'\n          process-only: 'issues'\n          log-output: true\n"
  },
  {
    "path": ".github/workflows/lock.yml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2025-12-18T09:21:29Z by kres 26be706.\n\n\"on\":\n  schedule:\n    - cron: 0 2 * * *\nname: Lock old issues\npermissions:\n  issues: write\njobs:\n  action:\n    runs-on:\n      - ubuntu-latest\n    steps:\n      - name: Lock old issues\n        uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # version: v6.0.0\n        with:\n          issue-inactive-days: \"60\"\n          log-output: \"true\"\n          process-only: issues\n"
  },
  {
    "path": ".github/workflows/slack-notify-ci-failure.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-16T15:20:50Z by kres e68c408.\n\n\"on\":\n  workflow_run:\n    workflows:\n      - default\n      - grype-scan-cron\n      - integration-qemu-cron\n      - integration-qemu-enforcing-cron\n      - integration-embedded-cron\n      - integration-conformance-cron\n      - integration-conformance-enforcing-cron\n      - integration-trusted-boot-cron\n      - integration-trusted-boot-enforcing-cron\n      - integration-provision-0-cron\n      - integration-provision-1-cron\n      - integration-provision-2-cron\n      - integration-provision-3-cron\n      - integration-airgapped-cron\n      - integration-misc-0-cron\n      - integration-misc-1-cron\n      - integration-misc-1-enforcing-cron\n      - integration-misc-2-cron\n      - integration-misc-3-cron\n      - integration-misc-3-enforcing-cron\n      - integration-misc-4-cron\n      - integration-misc-4-enforcing-cron\n      - integration-extensions-cron\n      - integration-cilium-cron\n      - integration-qemu-encrypted-vip-cron\n      - integration-qemu-race-cron\n      - integration-qemu-csi-rook-ceph-cron\n      - integration-qemu-csi-longhorn-cron\n      - integration-qemu-csi-openebs-cron\n      - integration-images-cron\n      - integration-reproducibility-test-cron\n      - integration-image-cache-cron\n      - integration-image-factory-cron\n      - integration-aws-cron\n      - integration-aws-nvidia-oss-lts-cron\n      - integration-aws-nvidia-oss-production-cron\n      - integration-aws-nvidia-nonfree-lts-cron\n      - integration-aws-nvidia-nonfree-production-cron\n      - integration-gcp-cron\n    types:\n      - completed\n    branches:\n      - main\nname: slack-notify-failure\njobs:\n  slack-notify:\n    runs-on:\n      group: generic\n    if: github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event != 'pull_request'\n    steps:\n      - name: Slack Notify\n        uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # version: v2.1.1\n        with:\n          method: chat.postMessage\n          payload: |\n            {\n                \"channel\": \"ci-failure\",\n                \"text\": \"${{ github.event.workflow_run.conclusion }} - ${{ github.repository }}\",\n                \"icon_emoji\": \"${{ github.event.workflow_run.conclusion == 'success' && ':white_check_mark:' || github.event.workflow_run.conclusion == 'failure' && ':x:' || ':warning:' }}\",\n                \"username\": \"GitHub Actions\",\n                \"attachments\": [\n                    {\n                        \"blocks\": [\n                            {\n                                \"fields\": [\n                                    {\n                                        \"text\": \"${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}\",\n                                        \"type\": \"mrkdwn\"\n                                    },\n                                    {\n                                        \"text\": \"*Status:*\\n`${{ github.event.workflow_run.conclusion }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    }\n                                ],\n                                \"type\": \"section\"\n                            },\n                            {\n                                \"fields\": [\n                                    {\n                                        \"text\": \"*Author:*\\n`${{ github.actor }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    },\n                                    {\n                                        \"text\": \"*Event:*\\n`${{ github.event.workflow_run.event }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    }\n                                ],\n                                \"type\": \"section\"\n                            },\n                            {\n                                \"type\": \"divider\"\n                            },\n                            {\n                                \"elements\": [\n                                    {\n                                        \"text\": {\n                                            \"text\": \"Logs\",\n                                            \"type\": \"plain_text\"\n                                        },\n                                        \"type\": \"button\",\n                                        \"url\": \"${{ github.event.workflow_run.html_url }}\"\n                                    },\n                                    {\n                                        \"text\": {\n                                            \"text\": \"Commit\",\n                                            \"type\": \"plain_text\"\n                                        },\n                                        \"type\": \"button\",\n                                        \"url\": \"${{ github.event.repository.html_url }}/commit/${{ github.sha }}\"\n                                    }\n                                ],\n                                \"type\": \"actions\"\n                            }\n                        ],\n                        \"color\": \"${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}\"\n                    }\n                ]\n            }\n          token: ${{ secrets.SLACK_BOT_TOKEN_V2 }}\n"
  },
  {
    "path": ".github/workflows/slack-notify.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-16T15:20:50Z by kres e68c408.\n\n\"on\":\n  workflow_run:\n    workflows:\n      - default\n      - grype-scan-cron\n      - integration-qemu-cron\n      - integration-qemu-enforcing-cron\n      - integration-embedded-cron\n      - integration-conformance-cron\n      - integration-conformance-enforcing-cron\n      - integration-trusted-boot-cron\n      - integration-trusted-boot-enforcing-cron\n      - integration-provision-0-cron\n      - integration-provision-1-cron\n      - integration-provision-2-cron\n      - integration-provision-3-cron\n      - integration-airgapped-cron\n      - integration-misc-0-cron\n      - integration-misc-1-cron\n      - integration-misc-1-enforcing-cron\n      - integration-misc-2-cron\n      - integration-misc-3-cron\n      - integration-misc-3-enforcing-cron\n      - integration-misc-4-cron\n      - integration-misc-4-enforcing-cron\n      - integration-extensions-cron\n      - integration-cilium-cron\n      - integration-qemu-encrypted-vip-cron\n      - integration-qemu-race-cron\n      - integration-qemu-csi-rook-ceph-cron\n      - integration-qemu-csi-longhorn-cron\n      - integration-qemu-csi-openebs-cron\n      - integration-images-cron\n      - integration-reproducibility-test-cron\n      - integration-image-cache-cron\n      - integration-image-factory-cron\n      - integration-aws-cron\n      - integration-aws-nvidia-oss-lts-cron\n      - integration-aws-nvidia-oss-production-cron\n      - integration-aws-nvidia-nonfree-lts-cron\n      - integration-aws-nvidia-nonfree-production-cron\n      - integration-gcp-cron\n    types:\n      - completed\nname: slack-notify\njobs:\n  slack-notify:\n    runs-on:\n      group: generic\n    if: github.event.workflow_run.conclusion != 'skipped'\n    steps:\n      - name: Get PR number\n        id: get-pr-number\n        if: github.event.workflow_run.event == 'pull_request'\n        env:\n          GH_TOKEN: ${{ github.token }}\n        run: |\n          echo pull_request_number=$(gh pr view -R ${{ github.repository }} ${{ github.event.workflow_run.head_repository.owner.login }}:${{ github.event.workflow_run.head_branch }} --json number --jq .number) >> $GITHUB_OUTPUT\n      - name: Slack Notify\n        uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # version: v2.1.1\n        with:\n          method: chat.postMessage\n          payload: |\n            {\n                \"channel\": \"ci-all\",\n                \"text\": \"${{ github.event.workflow_run.conclusion }} - ${{ github.repository }}\",\n                \"icon_emoji\": \"${{ github.event.workflow_run.conclusion == 'success' && ':white_check_mark:' || github.event.workflow_run.conclusion == 'failure' && ':x:' || ':warning:' }}\",\n                \"username\": \"GitHub Actions\",\n                \"attachments\": [\n                    {\n                        \"blocks\": [\n                            {\n                                \"fields\": [\n                                    {\n                                        \"text\": \"${{ github.event.workflow_run.event == 'pull_request' && format('*Pull Request:* {0} (`{1}`)\\n<{2}/pull/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, steps.get-pr-number.outputs.pull_request_number, github.event.workflow_run.display_title) || format('*Build:* {0} (`{1}`)\\n<{2}/commit/{3}|{4}>', github.repository, github.ref_name, github.event.repository.html_url, github.sha, github.event.workflow_run.display_title) }}\",\n                                        \"type\": \"mrkdwn\"\n                                    },\n                                    {\n                                        \"text\": \"*Status:*\\n`${{ github.event.workflow_run.conclusion }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    }\n                                ],\n                                \"type\": \"section\"\n                            },\n                            {\n                                \"fields\": [\n                                    {\n                                        \"text\": \"*Author:*\\n`${{ github.actor }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    },\n                                    {\n                                        \"text\": \"*Event:*\\n`${{ github.event.workflow_run.event }}`\",\n                                        \"type\": \"mrkdwn\"\n                                    }\n                                ],\n                                \"type\": \"section\"\n                            },\n                            {\n                                \"type\": \"divider\"\n                            },\n                            {\n                                \"elements\": [\n                                    {\n                                        \"text\": {\n                                            \"text\": \"Logs\",\n                                            \"type\": \"plain_text\"\n                                        },\n                                        \"type\": \"button\",\n                                        \"url\": \"${{ github.event.workflow_run.html_url }}\"\n                                    },\n                                    {\n                                        \"text\": {\n                                            \"text\": \"Commit\",\n                                            \"type\": \"plain_text\"\n                                        },\n                                        \"type\": \"button\",\n                                        \"url\": \"${{ github.event.repository.html_url }}/commit/${{ github.sha }}\"\n                                    }\n                                ],\n                                \"type\": \"actions\"\n                            }\n                        ],\n                        \"color\": \"${{ github.event.workflow_run.conclusion == 'success' && '#2EB886' || github.event.workflow_run.conclusion == 'failure' && '#A30002' || '#FFCC00' }}\"\n                    }\n                ]\n            }\n          token: ${{ secrets.SLACK_BOT_TOKEN_V2 }}\n"
  },
  {
    "path": ".github/workflows/stale.yaml",
    "content": "name: 'Close stale issues and PRs'\non:\n  schedule:\n    - cron: '30 1 * * *'\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/stale@v9\n        with:\n          stale-issue-message: 'This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.'\n          stale-pr-message: 'This PR is stale because it has been open 45 days with no activity.'\n          close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'\n          days-before-issue-stale: 180\n          days-before-pr-stale: 45\n          days-before-issue-close: 5\n          days-before-pr-close: -1 # never close PRs\n          operations-per-run: 2000 # the maximum number of operations to perform per run\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2026-03-05T15:46:00Z by kres 1dd7316.\n\n\"on\":\n  schedule:\n    - cron: 30 1 * * *\nname: Close stale issues and PRs\npermissions:\n  issues: write\n  pull-requests: write\njobs:\n  stale:\n    runs-on:\n      - ubuntu-latest\n    steps:\n      - name: Close stale issues and PRs\n        uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # version: v10.2.0\n        with:\n          close-issue-message: This issue was closed because it has been stalled for 7 days with no activity.\n          days-before-issue-close: \"5\"\n          days-before-issue-stale: \"180\"\n          days-before-pr-close: \"-1\"\n          days-before-pr-stale: \"45\"\n          operations-per-run: \"2000\"\n          stale-issue-message: This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.\n          stale-pr-message: This PR is stale because it has been open 45 days with no activity.\n"
  },
  {
    "path": ".github/workflows/update-homebrew.yaml",
    "content": "name: update-homebrew\n\non:\n  release:\n    types: [published]\n\njobs:\n  update-formula:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Extract version from tag\n        id: version\n        run: |\n          VERSION=\"${GITHUB_REF#refs/tags/v}\"\n          echo \"version=${VERSION}\" >> $GITHUB_OUTPUT\n          echo \"Version: ${VERSION}\"\n\n      - name: Check if release is latest\n        id: check-latest\n        env:\n          GH_TOKEN: ${{ github.token }}\n        run: |\n          LATEST_TAG=$(gh release view --repo ${{ github.repository }} --json tagName -q '.tagName')\n          CURRENT_TAG=\"${GITHUB_REF#refs/tags/}\"\n\n          echo \"Latest release tag: ${LATEST_TAG}\"\n          echo \"Current release tag: ${CURRENT_TAG}\"\n\n          if [ \"${CURRENT_TAG}\" != \"${LATEST_TAG}\" ]; then\n            echo \"This release (${CURRENT_TAG}) is not the latest (${LATEST_TAG}). Skipping update.\"\n            echo \"is_latest=false\" >> $GITHUB_OUTPUT\n          else\n            echo \"This release is the latest. Proceeding with update.\"\n            echo \"is_latest=true\" >> $GITHUB_OUTPUT\n          fi\n\n      - name: Checkout homebrew-tap repository\n        if: steps.check-latest.outputs.is_latest == 'true'\n        uses: actions/checkout@v6\n        with:\n          repository: siderolabs/homebrew-tap\n          token: ${{ secrets.HOMEBREW_TAP_TOKEN }}\n          path: homebrew-tap\n\n      - name: Update Homebrew formula\n        if: steps.check-latest.outputs.is_latest == 'true'\n        env:\n          VERSION: ${{ steps.version.outputs.version }}\n        run: |\n          cd homebrew-tap\n\n          FORMULA=\"Formula/talosctl.rb\"\n          CURRENT_VERSION=$(grep -Po 'version \"\\K(\\d+\\.\\d+\\.\\d+)' \"${FORMULA}\")\n          echo \"Current version: ${CURRENT_VERSION}\"\n          echo \"New version: ${VERSION}\"\n\n          grep -Po '(url \"\\K[^\"]+)|(sha256 \"\\K[^\"]+)' \"${FORMULA}\" | while IFS= read -r url && read -r old_hash; do\n            new_url=\"${url//\\#\\{version\\}/${VERSION}}\"\n\n            echo \"===> Downloading ${new_url}...\"\n            wget -q -O /tmp/talosctl-binary \"${new_url}\"\n\n            echo \"=====> Calculating SHA256 checksum...\"\n            new_hash=$(sha256sum /tmp/talosctl-binary | awk '{print $1}')\n            echo \"=====> Old hash: ${old_hash}\"\n            echo \"=====> New hash: ${new_hash}\"\n\n            echo \"=====> Updating hash in formula...\"\n            sed -i \"s/${old_hash}/${new_hash}/\" \"${FORMULA}\"\n\n            rm /tmp/talosctl-binary\n          done\n\n          echo \"===> Updating version in formula: ${CURRENT_VERSION} -> ${VERSION}\"\n          sed -i \"s/${CURRENT_VERSION}/${VERSION}/g\" \"${FORMULA}\"\n\n          echo \"===> Updated formula:\"\n          cat \"${FORMULA}\"\n\n      - name: Commit and push changes\n        if: steps.check-latest.outputs.is_latest == 'true'\n        env:\n          VERSION: ${{ steps.version.outputs.version }}\n        run: |\n          cd homebrew-tap\n\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n\n          git checkout -b \"update-talosctl-v${VERSION}\"\n          git add Formula/talosctl.rb\n          git commit -m \"chore: update talosctl to v${VERSION}\"\n          git push origin \"update-talosctl-v${VERSION}\"\n\n      - name: Create Pull Request\n        if: steps.check-latest.outputs.is_latest == 'true'\n        env:\n          VERSION: ${{ steps.version.outputs.version }}\n          GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}\n        run: |\n          cd homebrew-tap\n\n          gh pr create \\\n            --title \"chore: update talosctl to v${VERSION}\" \\\n            --body \"Automated update of talosctl formula to version v${VERSION}\n\n          This PR was automatically generated by the update-homebrew workflow.\n\n          Release: https://github.com/${{ github.repository }}/releases/tag/v${VERSION}\" \\\n            --head \"update-talosctl-v${VERSION}\" \\\n            --base main\n"
  },
  {
    "path": ".gitignore",
    "content": ".env\n.envrc\nbin\n_out\n.vscode\n.idea\n*.code-workspace\ninit.yaml\ncontrolplane.yaml\njoin.yaml\nworker.yaml\nmachineconfig.yaml\ntalosconfig\n/kubeconfig\nhack/test/libvirt/matchbox/assets/*\n!hack/test/libvirt/matchbox/assets/.gitkeep\n\n# vim Swap\n[._]*.s[a-v][a-z]\n[._]*.sw[a-p]\n[._]s[a-rt-v][a-z]\n[._]ss[a-gi-z]\n[._]sw[a-p]\n\n# Go\n.artifacts/\ngo.work.sum\n\nsha256sum.txt\nsha512sum.txt\n\n**/packet-cluster.yaml\n\n# Local Netlify folder\n.netlify\n\n*.lock\nnode_modules\nwebsite/resources\nwebsite/public\nwebsite/.hugo_build.lock\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\nrun:\n  build-tags:\n    - integration\n    - integration_api\n    - integration_cli\n    - integration_k8s\n    - integration_provision\n  issues-exit-code: 1\n  tests: true\noutput:\n  formats:\n    text:\n      path: stdout\n      print-linter-name: true\n      print-issued-lines: true\n      colors: false\nlinters:\n  default: all\n  disable:\n    - contextcheck\n    - depguard\n    - dupword\n    - err113\n    - errorlint\n    - exhaustruct\n    - forbidigo\n    - forcetypeassert\n    - funcorder\n    - funlen\n    - gochecknoglobals\n    - gochecknoinits\n    - gocognit\n    - godoclint\n    - godox\n    - gosec\n    - inamedparam\n    - ireturn\n    - maintidx\n    - mnd\n    - musttag\n    - nakedret\n    - nestif\n    - nilnil\n    - noinlineerr\n    - nolintlint\n    - nonamedreturns\n    - paralleltest\n    - perfsprint\n    - promlinter\n    - protogetter\n    - recvcheck\n    - tagalign\n    - tagliatelle\n    - testifylint\n    - thelper\n    - varnamelen\n    - wrapcheck\n    - wsl # replaced by wsl_v5\n  settings:\n    cyclop:\n      max-complexity: 20\n    dupl:\n      threshold: 100\n    errcheck:\n      check-type-assertions: false\n      check-blank: true\n      exclude-functions:\n        - fmt.Fprintln\n        - fmt.Fprintf\n        - fmt.Fprint\n    goconst:\n      min-len: 3\n      min-occurrences: 3\n    gocyclo:\n      min-complexity: 10\n    gomoddirectives:\n      replace-allow-list:\n        - gopkg.in/yaml.v3\n        - github.com/coredns/coredns\n        - github.com/mdlayher/kobject\n        - golang.zx2c4.com/wireguard\n        - golang.zx2c4.com/wireguard/wgctrl\n        - cloud.google.com/go\n        - github.com/mdlayher/ethtool\n        - github.com/containerd/containerd/v2\n        - github.com/jsimonetti/rtnetlink/v2\n        - github.com/neticdk/go-stdlib\n      replace-local: true\n      exclude-forbidden: false\n      retract-allow-no-explanation: false\n    lll:\n      line-length: 200\n      tab-width: 1\n    misspell:\n      locale: US\n    nolintlint:\n      require-explanation: false\n      require-specific: true\n      allow-unused: false\n    prealloc:\n      simple: true\n      range-loops: true\n      for-loops: false\n    staticcheck:\n      checks: [\"all\", \"-ST1000\", \"-ST1003\", \"-ST1016\", \"-ST1020\", \"-ST1021\", \"-ST1022\", \"-QF1001\", \"-QF1008\"]\n    unused:\n      local-variables-are-used: false\n  exclusions:\n    generated: lax\n    rules:\n      - linters:\n          - dupl\n        path: cmd/talosctl/cmd\n      - linters:\n          - dupl\n        path: internal/app/machined/internal/phase\n      - linters:\n          - dupl\n        path: internal/app/machined/pkg/system/services\n      - linters:\n          - revive\n        path: cmd/talosctl/cmd/mgmt\n        text: should have a package comment\n      - linters:\n          - revive\n        path: cmd/talosctl/cmd/mgmt/inject\n        text: should have a package comment\n      - linters:\n          - revive\n        path: cmd/talosctl/cmd/talos\n        text: should have a package comment\n      - linters:\n          - revive\n        path: cmd/talosctl/pkg/talos/action\n        text: should have a package comment\n      - linters:\n          - revive\n        path: cmd/talosctl/pkg/talos/global\n        text: should have a package comment\n      - linters:\n          - revive\n        path: cmd/talosctl/pkg/talos/helpers\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/controllers/cri\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/controllers/kubeaccess/serviceaccount\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/controllers/perf\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/events\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/health\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/runner/containerd\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/runner/goroutine\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/runner/process\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system/runner/restart\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/system\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/maintenance\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/maintenance/server\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/poweroff\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/trustd/internal/reg\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/app/trustd\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/containers/image\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/etcd\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/install\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/mount\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/mount/switchroot\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/pkg/tui/components\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/argsbuilder\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/chunker\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/chunker/file\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/chunker/stream\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/download\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/grpc/dialer\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/grpc/factory\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/grpc/gen\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/grpc/middleware/auth/basic\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/grpc/middleware/authz\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/kubernetes\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/kubernetes/inject\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/provision/providers\n        text: should have a package comment\n      - linters:\n          - revive\n        path: pkg/provision/providers/qemu\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/encoder\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/kubespan\n        text: should have a package comment\n      - linters:\n          - revive\n        path: client/config\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/merge\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/types/v1alpha1/bundle\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/cri\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/runtime\n        text: should have a package comment\n      - linters:\n          - revive\n        path: kernel\n        text: should have a package comment\n      - linters:\n          - revive\n        path: constants\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/perf\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/cluster\n        text: should have a package comment\n      - linters:\n          - revive\n        path: role\n        text: should have a package comment\n      - linters:\n          - revive\n        path: resources/hardware\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/decoder\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/internal/cis\n        text: should have a package comment\n      - linters:\n          - revive\n        path: config/types/v1alpha1/machine\n        text: should have a package comment\n      - linters:\n          - revive\n        path: internal/integration/api\n        text: avoid meaningless package names\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/runtime/v1alpha1/platform/errors\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/controllers/time\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: pkg/machinery/resources/time\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: pkg/machinery/resources/runtime\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: pkg/machinery/version\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: pkg/machinery/config/types/runtime\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: cmd/talosctl/cmd/mgmt/debug\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/debug\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/machined/internal/server/v1alpha1\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/controllers/runtime\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/machined/pkg/runtime\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/app/syslogd/internal/parser\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/pkg/containers/image\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: internal/pkg/uki/internal/pe\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - revive\n        path: pkg/grpc/middleware/log\n        text: avoid package names that conflict with Go standard library package names\n      - linters:\n          - dupl\n        path: config/types/v1alpha1\n      - linters:\n          - unused\n        path: specs-go/config.go\n      - path: (.+)\\.go$\n        text: package comment should be of the form \"Package services ...\"\n      - path: (.+)\\.go$\n        text: ^ST1000\n      - path: (.+)\\.go$\n        text: parameter '\\w+' seems to be unused, consider removing or renaming it as _\n    paths:\n      - .*\\\\.pb\\\\.go$\n      - third_party$\n      - builtin$\n      - examples$\nissues:\n  max-issues-per-linter: 0\n  max-same-issues: 0\n  uniq-by-line: true\n  new: false\nformatters:\n  enable:\n    - gci\n    - gofmt\n    - gofumpt\n    - goimports\n  settings:\n    gci:\n      sections:\n        - standard\n        - default\n        - prefix(github.com/siderolabs/talos)\n  exclusions:\n    generated: lax\n    paths:\n      - .*\\\\.pb\\\\.go$\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": ".kres.yaml",
    "content": "---\nkind: auto.CI\nspec:\n  compileGHWorkflowsOnly: true\n---\nkind: common.SOPS\nspec:\n  enabled: true\n  config: |-\n    creation_rules:\n      - age: age1xrpa9ujxxcj2u2gzfrzv8mxak4rts94a6y60ypurv6rs5cpr4e4sg95f0k\n        # order: Andrey, Noel, Artem, Utku, Tim, Andy\n        pgp: >-\n          15D5721F5F5BAF121495363EFE042E3D4085A811,\n          CC51116A94490FA6FB3C18EB2401FCAE863A06CA,\n          4919F560F0D35F80CF382D76E084A2DF1143C14D,\n          11177A43C6E3752E682AC690DBD13117B0A14E93,\n          5D7964FF2DB426ACB3C3505AA2A702DD5B689F45,\n          E77ED9F8451E10BD242D07415444881046F92733\n---\nkind: common.Repository\nspec:\n  conformScopes:\n    - apid\n    - machined\n    - networkd\n    - talosctl\n    - trustd\n    - talosctl\n    - kernel\n    - security\n    - ci\n    - ^v1.13\n  licenseChecks:\n    - skipPaths:\n        - .git/\n        - testdata/\n      includeSuffixes:\n        - .go\n      excludeSuffixes:\n        - .pb.go\n        - .pb.gw.go\n        - _string.go\n        - _enumer.go\n        - _string_linux.go\n        - zz_generated.deepcopy.go\n      header: |\n        // This Source Code Form is subject to the terms of the Mozilla Public\n        // License, v. 2.0. If a copy of the MPL was not distributed with this\n        // file, You can obtain one at http://mozilla.org/MPL/2.0/.\n  enforceContexts:\n    - default\n    - base-lint\n    - base-unit-tests\n    - e2e-iso\n    - e2e-qemu-short\n    - e2e-docker-short\n    - integration-qemu\n    - integration-qemu-enforcing\n    - integration-embedded\n    - integration-trusted-boot\n    - integration-trusted-boot-enforcing\n    - integration-provision-0\n    - integration-provision-1\n    - integration-provision-2\n    - integration-provision-3\n    - integration-airgapped\n    - integration-misc-0\n    - integration-misc-1\n    - integration-misc-1-enforcing\n    - integration-misc-2\n    - integration-misc-3\n    - integration-misc-3-enforcing\n    - integration-misc-4\n    - integration-misc-4-enforcing\n    - integration-extensions\n    - integration-cilium\n    - integration-conformance\n    - integration-conformance-enforcing\n    - integration-qemu-encrypted-vip\n    - integration-qemu-race\n    - integration-qemu-csi-rook-ceph\n    - integration-qemu-csi-longhorn\n    - integration-qemu-csi-openebs\n    - integration-images\n    - integration-reproducibility-test\n    - integration-cloud-images\n    - integration-image-cache\n    - integration-image-factory\n    - integration-aws\n    - integration-aws-nvidia-oss-lts\n    - integration-aws-nvidia-oss-production\n    - integration-aws-nvidia-nonfree-lts\n    - integration-aws-nvidia-nonfree-production\n    - integration-gcp\n---\nkind: common.GHWorkflow\nspec:\n  jobs:\n    - name: default\n      buildxOptions:\n        enabled: true\n      runnerGroup: large\n      conditions:\n        - on-pull-request\n      steps:\n        - name: ci-temp-release-tag\n        - name: external-artifacts\n        - name: generate\n          command: generate docs\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n        - name: check-dirty\n        - name: build\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n        - name: sbom\n        - name: iso\n          command: iso secureboot-iso\n          environment:\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-artifacts\n          artifactStep:\n            type: upload\n            artifactName: talos-artifacts\n            artifactPath: _out\n    - name: push\n      buildxOptions:\n        enabled: true\n      runnerGroup: large\n      conditions:\n        - except-pull-request\n        - not-on-tag\n      steps:\n        - name: build\n          command: talosctl-all kernel sd-boot sd-stub initramfs installer-base imager talos\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n        - name: release-notes\n        - name: login-to-registry\n          registryLoginStep:\n            registry: ghcr.io\n        - name: push\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n        - name: push-latest\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n          conditions:\n            - only-on-main-branch\n    - name: tag\n      sops: true\n      buildxOptions:\n        enabled: true\n      runnerGroup: large\n      conditions:\n        - only-on-tag\n      steps:\n        - name: build\n          command: talosctl-all kernel sd-boot sd-stub initramfs installer-base imager talos talosctl-cni-bundle\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n        - name: release-notes\n        - name: sbom\n        - name: login-to-registry\n          registryLoginStep:\n            registry: ghcr.io\n        - name: push\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n        - name: images\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n        - name: release\n          releaseStep:\n            baseDirectory: _out\n            artifacts:\n              - initramfs-amd64.xz\n              - initramfs-arm64.xz\n              - metal-amd64.iso\n              - metal-arm64.iso\n              - metal-amd64-uki.efi\n              - metal-arm64-uki.efi\n              - metal-amd64.raw.zst\n              - metal-arm64.raw.zst\n              - talos-arm64.spdx.json\n              - talos-amd64.spdx.json\n              - talos-container-arm64.spdx.json\n              - talos-container-amd64.spdx.json\n              - talosctl-cni-bundle-amd64.tar.gz\n              - talosctl-cni-bundle-arm64.tar.gz\n              - talosctl-darwin-amd64\n              - talosctl-darwin-arm64\n              - talosctl-freebsd-amd64\n              - talosctl-freebsd-arm64\n              - talosctl-linux-amd64\n              - talosctl-linux-arm64\n              - talosctl-linux-armv7\n              - talosctl-linux-riscv64\n              - talosctl-windows-amd64.exe\n              - talosctl-windows-arm64.exe\n              - vmlinuz-amd64\n              - vmlinuz-arm64\n            generateChecksums: true\n            generateSignatures: true\n            releaseNotes: RELEASE_NOTES.md\n    - name: cloud-images\n      dispatchable: true\n      sops: true\n      runnerGroup: generic # this is not compute intensive - we are pulling images from factory\n      inputs:\n        - tag\n        - release\n      steps:\n        - name: cloud-images\n          environment:\n            CLOUD_IMAGES_EXTRA_ARGS: |-\n              --use-factory\n            PLATFORM: linux/amd64,linux/arm64\n            TAG: ${{ github.event.inputs.tag }}\n        - name: attach-images\n          nonMakeStep: true\n          environment:\n            RELEASE: ${{ github.event.inputs.release }}\n            GH_TOKEN: ${{ github.token }}\n          command: |-\n            gh release upload \"${RELEASE}\" --clobber \\\n              _out/cloud-images.json\n    - name: base-unit-tests\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      steps:\n        - name: download-artifacts\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n        - name: unit-tests\n        - name: unit-tests-fips\n        - name: unit-tests-race\n        - name: coverage\n          coverageStep:\n            files:\n              - _out/coverage.txt\n          timeoutMinutes: 3\n    - name: base-lint\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      steps:\n        - name: download-artifacts\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n        - name: lint\n    - name: grype-scan\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 7 * * *'\n      steps:\n        - name: login-to-registry\n          registryLoginStep:\n            registry: ghcr.io\n        - name: local-grype-scan-result\n          environment:\n            DEST: _out\n        # Fail the run if found vulnerabilities which do not have a statement\n        - name: target-grype-validate\n        - name: save-scan-result\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-grype-scan-result\n            disableExecutableListGeneration: true\n            artifactPath: _out/grype-scan.log\n    - name: e2e-iso\n      depends:\n        - default\n      runnerGroup: large\n      steps:\n        - name: download-artifacts\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n        - name: e2e-iso\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-e2e-iso\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: e2e-qemu-short\n      depends:\n        - default\n      runnerGroup: large\n      steps:\n        - name: download-artifacts\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n        - name: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-short\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            SHORT_INTEGRATION_TEST: yes\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-e2e-qemu-short\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: e2e-docker-short\n      depends:\n        - default\n      runnerGroup: large\n      steps:\n        - name: download-artifacts\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n        - name: e2e-docker\n          withSudo: false\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            SHORT_INTEGRATION_TEST: yes\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-e2e-docker-short\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-qemu\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            QEMU_EXTRA_DISKS: \"4\"\n            QEMU_EXTRA_DISKS_SIZE: \"10240\"\n            QEMU_EXTRA_DISKS_DRIVERS: \"virtiofs,ide,nvme\"\n            QEMU_EXTRA_DISKS_TAGS: \"disk0\"\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            WITH_CONFIG_PATCH_WORKER: \"@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml\"\n            WITH_USER_DISK: \"true\"\n            USER_DISKS_MOUNTS: \"/var/mnt/extra,/var/mnt/p1,/var/mnt/p2\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-enforcing\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: e2e-qemu\n          withSudo: true\n          environment:\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            QEMU_EXTRA_DISKS: \"3\"\n            QEMU_EXTRA_DISKS_SIZE: \"10240\"\n            QEMU_EXTRA_DISKS_DRIVERS: \"ide,nvme\"\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            WITH_CONFIG_PATCH_WORKER: \"@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml\"\n            WITH_USER_DISK: \"true\"\n            WITH_ENFORCING: true\n            USER_DISKS_MOUNTS: \"/var/mnt/extra,/var/mnt/p1,/var/mnt/p2\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-embedded\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/embedded\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-embedded\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-embedded\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-conformance\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/conformance\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: conformance-qemu\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n            QEMU_CPUS_WORKERS: 6\n            QEMU_MEMORY_WORKERS: 4096\n            TEST_MODE: fast-conformance\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-conformance\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-conformance-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/conformance-enforcing\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: conformance-qemu\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-conformance-qemu\n            QEMU_CPUS_WORKERS: 6\n            QEMU_MEMORY_WORKERS: 4096\n            TEST_MODE: fast-conformance\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-conformance-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-trusted-boot\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/trusted-boot\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: secureboot-iso\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: integration-trusted-boot\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot\n            VIA_MAINTENANCE_MODE: true\n            WITH_TRUSTED_BOOT_ISO: true\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            EXTRA_TEST_ARGS: \"-talos.trustedboot\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-trusted-boot\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-trusted-boot-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/trusted-boot-enforcing\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: secureboot-iso\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: integration-trusted-boot-enforcing\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-integration-trusted-boot-enforcing\n            VIA_MAINTENANCE_MODE: true\n            WITH_TRUSTED_BOOT_ISO: true\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: \"-talos.trustedboot -talos.enforcing\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-trusted-boot-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-provision-0\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/provision\n        - integration/provision-0\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: provision-tests-prepare\n        - name: provision-tests-track-0\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-provision-0\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-provision-1\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/provision\n        - integration/provision-1\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: provision-tests-prepare\n        - name: provision-tests-track-1\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-provision-1\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-provision-2\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/provision\n        - integration/provision-2\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: installer\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            IMAGER_ARGS: \"--extra-kernel-arg=talos.extra_cmdline=extra-super-cmdline\"\n            TAG_SUFFIX_OUT: -extra-cmdline\n        - name: provision-tests-prepare\n        - name: provision-tests-track-2\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-provision-2\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-provision-3\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 4 * * *'\n      triggerLabels:\n        - integration/provision\n        - integration/provision-3\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: provision-tests-prepare\n        - name: provision-tests-track-3\n          withSudo: true\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            GRPC_ENFORCE_ALPN_ENABLED: \"false\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-provision-3\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-airgapped\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/airgapped\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: integration-images-list\n          command: integration-images-list\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-airgapped-no-proxy\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-proxy\n            SHORT_INTEGRATION_TEST: yes\n            WITH_AIRGAPPED: no-proxy\n            WITH_CLUSTER_DISCOVERY: \"false\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-airgapped-http-proxy\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-http-proxy\n            SHORT_INTEGRATION_TEST: yes\n            WITH_AIRGAPPED: http-proxy\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-airgapped-secure-proxy\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-secure-proxy\n            SHORT_INTEGRATION_TEST: yes\n            WITH_AIRGAPPED: secure-http-proxy\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-airgapped-reverse-proxy\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-reverse-proxy\n            SHORT_INTEGRATION_TEST: yes\n            WITH_AIRGAPPED: https-reverse-proxy\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-airgapped\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n              - \"/tmp/airgapped*.log\"\n    - name: integration-misc-0\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/misc-0\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-metal-uki # needed for e2e-uki-4k\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-firewall\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-firewall\n            SHORT_INTEGRATION_TEST: yes\n            WITH_FIREWALL: block\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-canal-reset\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-canal-reset\n            INTEGRATION_TEST_RUN: TestIntegration/api.ResetSuite/TestResetWithSpec\n            CUSTOM_CNI_URL: https://raw.githubusercontent.com/projectcalico/calico/v3.30.3/manifests/canal.yaml\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-controlplane-port\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-controlplane-port\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONTROL_PLANE_PORT: 443\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_CONFIG_PATCH: \"@hack/test/patches/ephemeral-min-max.yaml\"\n        - name: e2e-uki-4k\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-uki-4k\n            SHORT_INTEGRATION_TEST: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_UKI_BOOT: true\n            WITH_4K_DISK: true\n        - name: e2e-flannel-netpol\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-flannel-netpol\n            SHORT_INTEGRATION_TEST: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_CONFIG_PATCH: \"@hack/test/patches/flannel-netpol.yaml\"\n            TEST_MODE: network-policy\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-0\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-1\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/misc-1\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-no-cluster-discovery\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CLUSTER_DISCOVERY: false\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-kubespan\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CLUSTER_DISCOVERY: true\n            WITH_KUBESPAN: \"true\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-default-hostname\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n            SHORT_INTEGRATION_TEST: yes\n            VIA_MAINTENANCE_MODE: true\n            DISABLE_DHCP_HOSTNAME: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-min-requirements\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n            SHORT_INTEGRATION_TEST: yes\n            QEMU_MEMORY_WORKERS: 1024\n            QEMU_MEMORY_CONTROLPLANES: 2048\n            QEMU_SYSTEM_DISK_SIZE: 10240\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-1\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-1-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc-enforcing\n        - integration/misc-1-enforcing\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: e2e-no-cluster-discovery\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-no-cluster-discovery\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CLUSTER_DISCOVERY: false\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-kubespan\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-kubespan\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CLUSTER_DISCOVERY: true\n            WITH_KUBESPAN: true\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-default-hostname\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-default-hostname\n            SHORT_INTEGRATION_TEST: yes\n            VIA_MAINTENANCE_MODE: true\n            DISABLE_DHCP_HOSTNAME: true\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-min-requirements\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-min-requirements\n            SHORT_INTEGRATION_TEST: yes\n            QEMU_MEMORY_WORKERS: 1024\n            QEMU_MEMORY_CONTROLPLANES: 2048\n            QEMU_SYSTEM_DISK_SIZE: 10240\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-1-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-2\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/misc-2\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: iso # needed for e2e-bios-iso\n          conditions:\n            - only-on-schedule\n          command: iso\n          environment:\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: images-essential\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-bios\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios\n            SHORT_INTEGRATION_TEST: yes\n            WITH_UEFI: false\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            EXTRA_TEST_ARGS: \"-talos.verifyukibooted=false\"\n        - name: e2e-bios-iso\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-bios-iso\n            SHORT_INTEGRATION_TEST: yes\n            WITH_UEFI: false\n            VIA_MAINTENANCE_MODE: true\n            WITH_ISO: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            EXTRA_TEST_ARGS: \"-talos.verifyukibooted=false\"\n        - name: e2e-disk-image\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n            SHORT_INTEGRATION_TEST: yes\n            USE_DISK_IMAGE: true\n            VIA_MAINTENANCE_MODE: true\n            WITH_DISK_ENCRYPTION: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            WITH_JSON_LOGS: \"false\" # test this path as well\n        - name: e2e-disk-image-bios\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image-bios\n            SHORT_INTEGRATION_TEST: yes\n            USE_DISK_IMAGE: true\n            VIA_MAINTENANCE_MODE: true\n            WITH_DISK_ENCRYPTION: true\n            WITH_UEFI: false\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            EXTRA_TEST_ARGS: \"-talos.verifyukibooted=false\"\n        - name: e2e-node-address-v2\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-disk-image\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONFIG_PATCH: \"@hack/test/patches/node-address-v2.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-tpm1_2\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-tpm1_2\n            SHORT_INTEGRATION_TEST: yes\n            WITH_TPM1_2: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-2\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-3\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/misc-3\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-network-chaos\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n            SHORT_INTEGRATION_TEST: yes\n            WITH_NETWORK_CHAOS: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-metal-iso\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONFIG_INJECTION_METHOD: \"metal-iso\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-iommu-pcidriverrebind\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n            SHORT_INTEGRATION_TEST: yes\n            WITH_IOMMU: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-3\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-3-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc-enforcing\n        - integration/misc-3-enforcing\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: e2e-network-chaos\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-network-chaos\n            SHORT_INTEGRATION_TEST: yes\n            WITH_NETWORK_CHAOS: yes\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-metal-iso\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-metal-iso\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONFIG_INJECTION_METHOD: \"metal-iso\"\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-iommu-pcidriverrebind\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-iommu-pcidriverrebind\n            SHORT_INTEGRATION_TEST: yes\n            WITH_IOMMU: yes\n            TAG_SUFFIX_IN: -enforcing\n            EXTRA_TEST_ARGS: -talos.enforcing\n            WITH_ENFORCING: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-3-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-4\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc\n        - integration/misc-4\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-siderolink\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: true\n            VIA_MAINTENANCE_MODE: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-siderolink-tunnel\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: tunnel\n            VIA_MAINTENANCE_MODE: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-siderolink-tls\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: wireguard+tls\n            VIA_MAINTENANCE_MODE: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-apparmor\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n            SHORT_INTEGRATION_TEST: yes\n            WITH_APPARMOR_LSM_ENABLED: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-k8s-user-namespace\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONFIG_PATCH: \"@hack/test/patches/usernamespace.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-4\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-misc-4-enforcing\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 5 * * *'\n      triggerLabels:\n        - integration/misc-enforcing\n        - integration/misc-4-enforcing\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: uki-certs\n          environment:\n            PLATFORM: linux/amd64\n          conditions:\n            - only-on-schedule\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential-enforcing\n          command: images-essential\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGER_ARGS: \"--extra-kernel-arg=console=ttyS0 --extra-kernel-arg=enforcing=1\"\n            TAG_SUFFIX_OUT: -enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: e2e-siderolink\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: true\n            VIA_MAINTENANCE_MODE: true\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-siderolink-tunnel\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tunnel\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: tunnel\n            VIA_MAINTENANCE_MODE: true\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-siderolink-tls\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-siderolink-tls\n            SHORT_INTEGRATION_TEST: yes\n            WITH_SIDEROLINK_AGENT: wireguard+tls\n            VIA_MAINTENANCE_MODE: true\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-apparmor\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-apparmor\n            SHORT_INTEGRATION_TEST: yes\n            WITH_APPARMOR_LSM_ENABLED: yes\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-k8s-user-namespace\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-k8s-user-namespace\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CONFIG_PATCH: \"@hack/test/patches/usernamespace.yaml\"\n            TAG_SUFFIX_IN: -enforcing\n            WITH_ENFORCING: true\n            EXTRA_TEST_ARGS: -talos.enforcing\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-misc-4-enforcing\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-extensions\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 6 * * *'\n      triggerLabels:\n        - integration/extensions\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: unshallow-extensions\n          nonMakeStep: true\n          command: git -C _out/extensions fetch --prune --unshallow\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: all extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: installer extensions\n          command: installer-with-extensions\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-extensions\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-extensions\n            QEMU_WORKERS: 1\n            QEMU_MEMORY_WORKERS: 4096\n            WITH_CONFIG_PATCH_WORKER: \"@_out/installer-extensions-patch.yaml:@hack/test/patches/extensions.yaml:@hack/test/patches/dm-raid-module.yaml\"\n            QEMU_EXTRA_DISKS: 3\n            SHORT_INTEGRATION_TEST: yes\n            EXTRA_TEST_ARGS: -talos.extensions.qemu\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-extensions\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-cilium\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/cilium\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-cilium\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CUSTOM_CNI: cilium\n            WITH_FIREWALL: accept\n            WITH_CONFIG_PATCH: \"@hack/test/patches/cilium-no-kubeproxy.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-cilium-strict\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CUSTOM_CNI: cilium\n            WITH_FIREWALL: accept\n            CILIUM_INSTALL_TYPE: strict\n            WITH_CONFIG_PATCH: \"@hack/test/patches/cilium-kubeproxy.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-cilium-strict-kubespan\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-cilium-strict-kubespan\n            SHORT_INTEGRATION_TEST: yes\n            WITH_CUSTOM_CNI: cilium\n            WITH_FIREWALL: accept\n            WITH_KUBESPAN: true\n            CILIUM_INSTALL_TYPE: strict\n            WITH_CONFIG_PATCH: \"@hack/test/patches/cilium-kubeproxy.yaml\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-cilium\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-encrypted-vip\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-encrypted-vip\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-qemu\n          withSudo: true\n          environment:\n            WITH_DISK_ENCRYPTION: true\n            WITH_VIRTUAL_IP: true\n            WITH_KUBESPAN: true\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            QEMU_EXTRA_DISKS: \"4\"\n            QEMU_EXTRA_DISKS_SIZE: \"10240\"\n            QEMU_EXTRA_DISKS_DRIVERS: \"virtiofs,ide,nvme\"\n            QEMU_EXTRA_DISKS_TAGS: \"disk0\"\n            WITH_CONFIG_PATCH: \"@hack/test/patches/image-verification.yaml\"\n            WITH_CONFIG_PATCH_WORKER: \"@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-encrypted-vip\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-race\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-race\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: build-race\n          command: initramfs installer-base imager installer\n          environment:\n            PUSH: true\n            TAG_SUFFIX: -race\n            WITH_RACE: 1\n            PLATFORM: linux/amd64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-qemu-race\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-race\n            QEMU_EXTRA_DISKS: \"4\"\n            QEMU_EXTRA_DISKS_SIZE: \"10240\"\n            QEMU_EXTRA_DISKS_DRIVERS: \"virtiofs,ide,nvme\"\n            QEMU_EXTRA_DISKS_TAGS: \"disk0\"\n            WITH_CONFIG_PATCH_WORKER: \"@hack/test/patches/ephemeral-nvme.yaml:@hack/test/patches/dm-raid-module.yaml\"\n            QEMU_MEMORY_CONTROLPLANES: 4096 # race-enabled Talos consumes lots of RAM\n            QEMU_MEMORY_WORKERS: 4096\n            EXTRA_TEST_ARGS: \"-talos.race\"\n            TAG_SUFFIX: -race\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-race\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-csi-rook-ceph\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-csi\n        - integration/qemu-csi-rook-ceph\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-qemu-csi-rook-ceph\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-rook-ceph\n            SHORT_INTEGRATION_TEST: yes\n            QEMU_WORKERS: 3\n            QEMU_CPUS_WORKERS: 6\n            QEMU_MEMORY_WORKERS: 8192\n            QEMU_EXTRA_DISKS: 1\n            QEMU_EXTRA_DISKS_SIZE: 12288\n            WITH_CONFIG_PATCH_CONTROLPLANE: \"@hack/test/patches/rook-ceph.yaml\"\n            EXTRA_TEST_ARGS: -talos.csi=rook-ceph\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-fio-benchmark\n          artifactStep:\n            type: upload\n            artifactName: fio-integration-qemu-csi-rook-ceph\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/fio-*.json\n            retentionDays: \"180\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-csi-rook-ceph\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-csi-longhorn\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-csi\n        - integration/extensions # since iscsi is tested with longhorn\n        - integration/qemu-csi-longhorn\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: iscsi-tools util-linux-tools extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: installer extensions\n          command: installer-with-extensions\n          environment:\n            EXTENSIONS_FILTER_COMMAND: \"grep -E '/iscsi-tools|util-linux-tools'\"\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: kubelet-fat-patch\n        - name: e2e-qemu-csi-longhorn\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-longhorn\n            SHORT_INTEGRATION_TEST: yes\n            QEMU_WORKERS: 3\n            QEMU_MEMORY_WORKERS: 8192\n            QEMU_SYSTEM_DISK_SIZE: 20480\n            QEMU_EXTRA_DISKS: 1\n            QEMU_EXTRA_DISKS_SIZE: 12288\n            QEMU_EXTRA_DISKS_DRIVERS: nvme\n            WITH_CONFIG_PATCH_CONTROLPLANE: \"@hack/test/patches/longhorn-cp.yaml\"\n            WITH_CONFIG_PATCH_WORKER: \"@_out/installer-extensions-patch.yaml:@_out/kubelet-fat-patch.yaml:@hack/test/patches/longhorn.yaml\"\n            EXTRA_TEST_ARGS: -talos.csi=longhorn\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-fio-benchmark\n          artifactStep:\n            type: upload\n            artifactName: fio-integration-qemu-csi-longhorn\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/fio-*.json\n            retentionDays: \"180\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-csi-longhorn\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-qemu-csi-openebs\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 3 * * *'\n      triggerLabels:\n        - integration/qemu-csi\n        - integration/qemu-csi-openebs\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: e2e-qemu-csi-openebs\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-qemu-csi-openebs\n            SHORT_INTEGRATION_TEST: yes\n            QEMU_WORKERS: 3\n            QEMU_CPUS_WORKERS: 4\n            QEMU_MEMORY_WORKERS: 8192\n            QEMU_EXTRA_DISKS: 1\n            QEMU_EXTRA_DISKS_SIZE: 12288\n            WITH_CONFIG_PATCH_CONTROLPLANE: \"@hack/test/patches/openebs-cp.yaml\"\n            WITH_CONFIG_PATCH_WORKER: \"@hack/test/patches/openebs.yaml\"\n            EXTRA_TEST_ARGS: -talos.csi=openebs\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: save-fio-benchmark\n          artifactStep:\n            type: upload\n            artifactName: fio-integration-qemu-csi-openebs\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/fio-*.json\n            retentionDays: \"180\"\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-qemu-csi-openebs\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-images\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: generic # this is pretty fast, so we can use generic\n      crons:\n        - '30 2 * * *'\n      triggerLabels:\n        - integration/images\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n    - name: integration-reproducibility-test\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 2 * * *'\n      triggerLabels:\n        - integration/reproducibility-test\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: reproducibility-test\n          environment:\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n    - name: integration-cloud-images\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # this is not compute intensive, so we can use generic\n      triggerLabels:\n        - integration/cloud-images\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: images\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: cloud-images\n    - name: integration-image-cache\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 2 * * *'\n      triggerLabels:\n        - integration/image-cache\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-cache\n          command: cache-create\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: e2e-image-cache\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            REGISTRY_MIRROR_FLAGS: no\n            SHORT_INTEGRATION_TEST: yes\n            VIA_MAINTENANCE_MODE: true\n            WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-verification.yaml'\n            WITH_ISO: true\n        - name: e2e-image-cache-encrypted\n          command: e2e-qemu\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-e2e-image-cache-encrypted\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            REGISTRY_MIRROR_FLAGS: no\n            SHORT_INTEGRATION_TEST: yes\n            VIA_MAINTENANCE_MODE: true\n            WITH_CONFIG_PATCH: '@hack/test/patches/image-cache.yaml:@hack/test/patches/image-cache-encrypted.yaml:@hack/test/patches/image-verification.yaml'\n            WITH_ISO: true\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-image-cache\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-image-factory\n      buildxOptions:\n        enabled: true\n      depends:\n        - default\n      runnerGroup: large\n      crons:\n        - '30 6 * * *'\n      triggerLabels:\n        - integration/image-factory\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: factory-1.11-iso\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-iso\n            FACTORY_BOOT_METHOD: iso\n            FACTORY_VERSION: v1.11.5\n            FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            KUBERNETES_VERSION: 1.34.3\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            FACTORY_UPGRADE_VERSION: v1.11.6\n        - name: factory-1.11-image\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-image\n            FACTORY_BOOT_METHOD: disk-image\n            FACTORY_VERSION: v1.11.5\n            FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            KUBERNETES_VERSION: 1.34.3\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            FACTORY_UPGRADE_VERSION: v1.11.6\n        - name: factory-1.11-pxe\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-pxe\n            FACTORY_BOOT_METHOD: ipxe\n            FACTORY_VERSION: v1.11.6\n            FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            KUBERNETES_VERSION: 1.34.3\n        - name: factory-1.11-secureboot\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.11-secureboot\n            FACTORY_BOOT_METHOD: secureboot-iso\n            FACTORY_VERSION: v1.11.5\n            FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            KUBERNETES_VERSION: 1.34.3\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            FACTORY_UPGRADE_VERSION: v1.11.6\n        - name: factory-1.10-secureboot\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-secureboot\n            FACTORY_BOOT_METHOD: secureboot-iso\n            FACTORY_VERSION: v1.10.8\n            FACTORY_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            KUBERNETES_VERSION: 1.33.7\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            FACTORY_UPGRADE_VERSION: v1.10.9\n        - name: factory-1.10-iso\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.10-iso\n            FACTORY_BOOT_METHOD: iso\n            FACTORY_VERSION: v1.10.8\n            FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            KUBERNETES_VERSION: 1.33.7\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            FACTORY_UPGRADE_VERSION: v1.10.9\n        - name: factory-1.9-iso\n          command: e2e-image-factory\n          withSudo: true\n          environment:\n            GITHUB_STEP_NAME: ${{ github.job}}-factory-1.9-iso\n            FACTORY_BOOT_METHOD: iso\n            FACTORY_VERSION: v1.9.5\n            FACTORY_SCHEMATIC: 376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\n            KUBERNETES_VERSION: 1.32.11\n            FACTORY_UPGRADE: true\n            FACTORY_UPGRADE_SCHEMATIC: cf9b7aab9ed7c365d5384509b4d31c02fdaa06d2b3ac6cc0bc806f28130eff1f\n            FACTORY_UPGRADE_VERSION: v1.9.6\n        - name: save-talos-logs\n          conditions:\n            - always\n          artifactStep:\n            type: upload\n            artifactName: talos-logs-integration-image-factory\n            disableExecutableListGeneration: true\n            artifactPath: /tmp/logs-*.tar.gz\n            additionalArtifacts:\n              - \"/tmp/support-*.zip\"\n    - name: integration-aws\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/aws\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: image-aws\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-aws-prepare\n          environment:\n            E2E_AWS_TARGET: default\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: apply\n        - name: e2e-aws\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n    - name: integration-aws-nvidia-oss-lts\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/aws-nvidia-oss-lts\n        - integration/aws-nvidia-oss\n        - integration/aws-nvidia\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-aws\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: nvidia-container-toolkit-lts nvidia-open-gpu-kernel-modules-lts extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-aws-prepare\n          environment:\n            EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n            E2E_AWS_TARGET: nvidia-oss-lts\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: apply\n        - name: e2e-aws-nvidia-oss-lts\n          command: e2e-aws\n          environment:\n            EXTRA_TEST_ARGS: \"-talos.extensions.nvidia -talos.verifyukibooted=false\"\n            INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n    - name: integration-aws-nvidia-oss-production\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/aws-nvidia-oss-production\n        - integration/aws-nvidia-oss\n        - integration/aws-nvidia\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-aws\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: nvidia-container-toolkit-production nvidia-open-gpu-kernel-modules-production extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-aws-prepare\n          environment:\n            EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n            E2E_AWS_TARGET: nvidia-oss-production\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: apply\n        - name: e2e-aws-nvidia-oss-production\n          command: e2e-aws\n          environment:\n            EXTRA_TEST_ARGS: \"-talos.extensions.nvidia -talos.verifyukibooted=false\"\n            INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n    - name: integration-aws-nvidia-nonfree-lts\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/aws-nvidia-nonfree-lts\n        - integration/aws-nvidia-nonfree\n        - integration/aws-nvidia\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-aws\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: nvidia-container-toolkit-lts nonfree-kmod-nvidia-lts extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-aws-prepare\n          environment:\n            EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n            E2E_AWS_TARGET: nvidia-nonfree-lts\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: apply\n        - name: e2e-aws-nvidia-nonfree-lts\n          command: e2e-aws\n          environment:\n            EXTRA_TEST_ARGS: -talos.extensions.nvidia\n            INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n    - name: integration-aws-nvidia-nonfree-production\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/aws-nvidia-nonfree-production\n        - integration/aws-nvidia-nonfree\n        - integration/aws-nvidia\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: generate\n          conditions:\n            - only-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: image-aws\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout extensions\n          checkoutStep:\n            repository: siderolabs/extensions\n            ref: main\n            path: _out/extensions\n        - name: set variables\n          nonMakeStep: true\n          command: cat _out/talos-metadata >> \"$GITHUB_ENV\"\n        - name: build extensions\n          command: nvidia-container-toolkit-production nonfree-kmod-nvidia-production extensions-metadata\n          arguments:\n            - -C\n            - _out/extensions\n          environment:\n            PLATFORM: linux/amd64\n            PUSH: true\n            REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-aws-prepare\n          environment:\n            EXTENSIONS_METADATA_FILE: _out/extensions/_out/extensions-metadata\n            E2E_AWS_TARGET: nvidia-nonfree-production\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: apply\n        - name: e2e-aws-nvidia-nonfree-production\n          command: e2e-aws\n          environment:\n            EXTRA_TEST_ARGS: -talos.extensions.nvidia\n            INTEGRATION_TEST_RUN: TestIntegration/api.ExtensionsSuiteNVIDIA\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: aws\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n    - name: integration-gcp\n      buildxOptions:\n        enabled: true\n      sops: true\n      depends:\n        - default\n      runnerGroup: generic # we can use generic here since the tests run against a remote talos cluster\n      crons:\n        - '30 7 * * *'\n      triggerLabels:\n        - integration/gcp\n        - integration/release-gate\n      steps:\n        - name: download-artifacts\n          conditions:\n            - not-on-schedule\n          artifactStep:\n            type: download\n            artifactName: talos-artifacts\n            artifactPath: _out\n        - name: ci-temp-release-tag\n          conditions:\n            - not-on-schedule\n        - name: uki-certs\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64\n        - name: build\n          conditions:\n            - only-on-schedule\n          command: talosctl-linux-amd64 kernel sd-boot sd-stub initramfs installer-base imager talos _out/integration-test-linux-amd64\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n            PUSH: true\n        - name: talosctl-cni-bundle\n          conditions:\n            - only-on-schedule\n        - name: images-essential\n          conditions:\n            - only-on-schedule\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: image-gcp\n          environment:\n            PLATFORM: linux/amd64,linux/arm64\n            IMAGE_REGISTRY: registry.dev.siderolabs.io\n        - name: e2e-gcp-prepare\n        - name: checkout contrib\n          checkoutStep:\n            repository: siderolabs/contrib\n            ref: main\n            path: _out/contrib\n        - name: setup tf\n          terraformStep: true\n        - name: tf apply\n          command: e2e-cloud-tf\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: gcp\n            TF_E2E_ACTION: apply\n        - name: e2e-gcp\n        - name: tf destroy\n          command: e2e-cloud-tf\n          conditions:\n            - always\n          environment:\n            TF_SCRIPT_DIR: _out/contrib\n            TF_E2E_TEST_TYPE: gcp\n            TF_E2E_ACTION: destroy\n            TF_E2E_REFRESH_ON_DESTROY: false\n---\nkind: common.Renovate\nspec:\n  customManagers:\n    - customType: regex\n      managerFilePatterns:\n        - Makefile\n      matchStrings:\n        - '# renovate: datasource=(?<datasource>.*?)(?:\\s+extractVersion=(?<extractVersion>.+?))?\\s+depName=(?<depName>.+?)\\s.*_VERSION\\s+\\?=\\s+(?<currentValue>.+)'\n      versioningTemplate: \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\"\n    - customType: regex\n      managerFilePatterns:\n        - pkg/machinery/constants/constants.go\n      matchStrings:\n        - '\\/\\/\\s+renovate: datasource=(?<datasource>.*?)(?:\\s+extractVersion=(?<extractVersion>.+?))?(?:\\s+versioning=(?<versioning>.+?))?\\s+depName=(?<depName>.+?)?\\s.*Version\\s+=\\s+\\\"(?<currentValue>.+?)\\\"'\n      versioningTemplate: \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\"\n    - customType: regex\n      managerFilePatterns:\n        - internal/integration/k8s/constants.go\n        - internal/integration/api/constants.go\n      matchStrings:\n        - '\\/\\/\\s+renovate: datasource=(?<datasource>.*?)(?:\\s+extractVersion=(?<extractVersion>.+?))?(?:\\s+versioning=(?<versioning>.+?))?\\s+depName=(?<depName>.+?)?(?:\\s+registryUrl=(?<registryUrl>.+?))?\\s.*Version\\s+=\\s+\\\"(?<currentValue>.+?)\\\"'\n      versioningTemplate: \"{{#if versioning}}{{versioning}}{{else}}semver{{/if}}\"\n    - customType: regex\n      managerFilePatterns:\n        - Dockerfile\n      matchStrings:\n        - '# syntax = docker\\/dockerfile-upstream:(?<currentValue>.*)'\n      depNameTemplate: docker/dockerfile-upstream\n      datasourceTemplate: docker\n      versioningTemplate: docker\n  packageRules:\n    - enabled: false\n      matchFileNames:\n        - \"website/**\"\n    - matchPackageNames:\n        - golang/go\n      versioning: 'regex:^(?<major>\\d+)\\.(?<minor>\\d+)'\n"
  },
  {
    "path": ".markdownlint.json",
    "content": "{\n  \"default\": true,\n  \"MD013\": false,\n  \"MD033\": false,\n  \"MD034\": false,\n  \"MD059\": false\n}\n"
  },
  {
    "path": ".secrets.yaml",
    "content": "secrets:\n    AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:WHaM6pwvIE3K619sS1o1eXGMZys=,iv:xsVmRsi682Y9UJfokxoQZomlztyMGh5z0cJOltYOgXk=,tag:kPd9IICZ5PO+iK/gA5D+Ww==,type:str]\n    AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:2Uh2LDkjJoS0/wB2eboeGq6xdb9jIi4D5D7yxGvPE4h+DH1rl/a2DA==,iv:804kZ8I2DtNL1NR4171WClJElaQgRPFKSgIKzAZHCHQ=,tag:Mp9bZVP3cMGA+UeKRIYqiA==,type:str]\n    AWS_DEFAULT_REGION: ENC[AES256_GCM,data:Q7KZm7eenYFn,iv:VuzTTfAHe9FOTcqrGiJU9qdNixTxszm23rSXuNDB3cA=,tag:eGbIm8M/1Lsl0aoa9NanOQ==,type:str]\n    GOOGLE_PROJECT_ID: ENC[AES256_GCM,data:egcG5hIa5aq6tSRjhA==,iv:g/6pkcSJIQNNgoon6X+6DH2JaQgLKfTDpPUNFjlJ6Xg=,tag:ygF0I8bLRRbj2RdogQqxmw==,type:str]\n    GOOGLE_CREDENTIALS: ENC[AES256_GCM,data:ucHNQ0fygvZnOfa5k3J1zO99122malyCB1aDDwTSOuQZsUHrnCg5FYsxJ5RgTl5mbpityJjKQtHLcMetRVLQ/S2/aPjhbx+OgYLmlFMnJR/NmqEQzuwe8YsPSjOg9NCqucE7BBfbKItQ/PD0+x6LRKxeMO/gr6BXTkL4dwPinCV9IgVZU2CEAdbvcGvxBGKWZ0mHEIvdznN3dK2OL27K+Q+VXZDhzUPfhR5V7u5WUu+PG0QsSby/lZNYdAHpxfkS0YjfTCpukCB0Zvix6cUaorA+BHNYA1qV3nzHDuHHdR6byoGYXMWU209RVG2HKiNAQRlmTsbjr641OWHustGo+Ann9Rv2pZ7r6Q08p0M8cvn5o42TB5H3lv72Iiiru2aV9ZQHpzy1PG4PH9vfebowO2VbZ/wKpRWvc6cpPrAQfoXZCLlaiLoJ1KaVZb9Br8vjlGCHCFzytb61R8BT36M687fRerwVQSu6F5cRzfW6W3Jh5Ufo31wYqdEe2XdN0f/jDG1w0rF2xX4oScgXI/uaVrJ3zCYlVkdbnQjSmu059SmRRkfYJqri+hyDilWKKDPK3+qmBbyeJ+lxcNNugksRMfq5ms5HV70JoUCbiEQF5KzsTCw9s7O4xFYjP5ELXgwHqQbXeOxMS4+GAaN9k+p4owLkVRkO3PkWHBvs+aqCBQvsdZW8XjikNeHWHTZLq4DpOuBrtpvwID5bEPqN70ah1hU9gc9oXC4ArUU5QlqGxNkzdea/cymO7W+0JeRKKRW4G984b1xbLjjjL0Zx8VCDDDx7BTd+DrBsJUZ2CO+u2XIZX6+LNqPt9n/DQUARv13KM4hUmugjhZxx0f0mro1bXMfEfbs8micuk7qDQtKVkRApUlCEb+kEVDXMQUeetLQfUhU7c23QA8tMBHz2IoEmY5yf6CI5PfcUSI9Oldez4+JlCFPf3a2UyVR0+4VITYdBFW0dKLhjR/eYNOh3kEYERksALRYoS2XtLLquHSxRgAPki62RQOrZclfdi1+IGT17l+PyoSKOusIUkHd/y0jUHBSIBjYAZrqZ2WolYpwTMzE3hz3lMys9RbrJV653QgLCndWDXD7k+imXsyyYy1me/JHssYu6ZZ7EsPTGNezdG1/9j7X1VHYKw0DMsYXwIVEI+7/flwHExVTT10+gO+WIVnf7QdUpvsqJNsniCS82Rq9tRhIwLIiePOdV1azMBVqbI8LUBm/E9iFW+iYEuezLL5YsQFvItrNuH5wwhdFNiWrdBWz7klxb0R61/EBPPr6UvVf5d5WyCYonn9UUmUfQrzhgplfr3Qk8a5IAoaT1SW+iS1e15O8PsARGKy/AcX+mTf2v1qgiPnk5IucsZGlH9dwl2gIBbJ8d8SZPl4mGjW9UMesyZxoBTyY1OOYZ3NQSCZnvEggiI+BpIt35nwMLf71LZrXJOY/Q/s2eQBih4FsNb32wlEFcfpxrvT42deh1fatDTZP9NLldbyXWJkyxdAiziUiFtTM3rBly6mNG5hBsbKQpjzN94Tb/9oMD9RbCBcyj1e96DAsRNamqkPlRecZtdh9OuAuq2EjfsEFE9sodtbdxHwDdnR40SElw4jrJ0Ga0QNq04FmXMP86dz/h+MRUO3ldDvax/kjAjR5MRJZXr117sW6fuls268Qo14zdL/nbd9jYdHn9hheCAdM0FvohuCXSWgvoVcpKKCD8kKvgIaXvaFxxAKqWisrxTbtSFoflYzMjaP7L3lY5LlcadTSb+KJl5RVY3ERuUnirMrxVKYRZFsug+Smr5hlcbup/wEESv2aFp3JkEqQxfGxD+g3tHwW9U3KvJ7iv/GQFsikZ2UfLJ0EVAuiVu4Dv25CcxlWx/NGJ3e/FC9nWLgpwnzezsuithZZXci2bH4NvnDxA669Jq3LjwTcKMguEbWOuDBDlO9JcvZsa+0vlQKzZmrzirwLIi8hXQyTeKaHk1ahcblbaZGYoI3E13u7DiGvaQ/+4Y65UFtGusR/NmXG1B4NrGb/EG3mc60JFfIi6CBhtugwEdGYGDkymgHiIM/fb6b8UHXV/kcfnTsGweH2Lc7sR5eMP5a8D7O2P4uvwp3r2NRLwrrGunOARpo835Kx/ZCheS5XCDuiy+LEaTHjDD5cDl2RlgheMjVAcXF/pc3+Q+JBccKdw1D/aN8tYTsPiJiCW6bAOVLwOm1vaa9ecQiNxnx8gym4bYERrx+hlDExS/I+xtmmdJe/s5EqGrVImZjXSkb3LON+ktATByoQVpNjsBpVfnyR7rFcz/UdLDIX3l9IS1cZhIBtkqGSylbOXMUEhhq70qcHpuNTpGxGP30K1c5A63BQB0hpM/wyV629WHUYD1SM48niVT36wVxj356secwI6JVA3hlZp5t7F/KcIuAG1WVy/GUf+cKBWNSnniRLUJdBXSXNamG5o+CN0AXvDNyP9I/xQsrbWzPC5eBNqRL0MEJsfZlWFR6fyI+5UyLlfIh0rwYTz7BK9l1wq1TRV7YqiFpALObtGVxclfKxdFymWwEfjUCwVqw8RAETGqOwfVLvvDlZp/RGup8M2ghsql1Uu/BlrCAoaiJbF8eeuIwNx6K/sq5P8RIFXRZBmWMqewg93Ea/hUIAhubz4fZtHvlh1mbOPWUkzlPCyBPd3uM93mw6wCp6xQM3DbZfQRnKD8HPr6+CFPIn1YGZ1oftBM9mEpH7PtpwJWwDA+Wdl1VbBjUjFG4XVdWxsqbS0W7pePEW1rnqv/bGuPHctEUAXN9IGKSW953T4ChFgYXGcNEURtkknE7bMlQSDZvLS/vtn89aaaL8gnfBF8NvFkB8uQSkQfn/CvQ00GdlhI1l0CyV0+xMrerUw+20nlhC7C7aNKsyx7S8HatUIEkvD6/XPRNoGa9M6w+81JYWbbDF6DFljiiNKtWmv5BkVhWFTwimEOmqKQc6DmXbvtGqH7Pts7PXS/5k83D8eV4kPHuiKNwdU0wsdo+PGSLP+OMWF3Ygbb71Bqq6dwnfciXQi/6yCUv3WdQf2MbMzyqEy9ugXeWI4uvbh+/u5HHzhwMTzhZVoGgwXuyX+nCFPCsqdzqzn8s+TSoU=,iv:nLXpwEqTJaQnZlE0CiQl+hWlBIJGSa8tEUebXpkMWec=,tag:MZ/FJeksYkqCsLaELJDq0A==,type:str]\nsops:\n    age:\n        - recipient: age1xrpa9ujxxcj2u2gzfrzv8mxak4rts94a6y60ypurv6rs5cpr4e4sg95f0k\n          enc: |\n            -----BEGIN AGE ENCRYPTED FILE-----\n            YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCa25HZSt1b05HTkxoWU41\n            anB3cm9MWGdRZkNhNENOd2RpSXdMS3ZKMjNVCkxDVEZqQ3U2YnlDdk85V29zQTdw\n            bUZOWnJPUFFZeS8yWmlaWjcxQzNwUGMKLS0tIGdydkVBbXdrQnNMejJZMjN5VS9r\n            TnhVWjdiWTFjN1RDTjVJVm9NNFl2TU0KAYNYtgdxBjEBJYRtT4dyISPPP8U0yXBn\n            zTKgwZePoa62YO1hM/yweMxsmdWxLg1yI4oVWltGwuIgd+WNOQivHQ==\n            -----END AGE ENCRYPTED FILE-----\n    lastmodified: \"2025-05-15T11:14:12Z\"\n    mac: ENC[AES256_GCM,data:btPhRw73wNtyNJKYXh8hMjiARs2uXUZDf3rtjBqmYUigXqRj+8binPWlySqHnccKwf9HBUWTp73++Fzuei+U5yGfk4pC8CXdZTDX5t6sLNLEWSjbdaiiT2dw6yqVp5O0yerp4pjRRf6Kl4QgGYgYEG6z/kDIbi7t05nm4FLcXpU=,iv:RRS84CcxvSjyDGwVWCOLXa6PUrfFumR4CT5oa9M5SEs=,tag:3ZJYfMcAUqzUGfu/gK5oNg==,type:str]\n    pgp:\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4D/dYBJRlWfQISAQdAgHuuKQrCedfoxAHg5zxM6E0s11EzwU0SXbu8ETcFFyIw\n            Q1EDd0T/ZW4VnjIDto8kUC0KMtUvrvR1s3FCG9mx2ZKMvIXwTHqMkLomjaXRHn4v\n            0l4BrQKkyX5Bm4mCzg8KC2e+JsvNdwNnkMJQHhU45q5TgBDV9FTA7Dri5IpNYt1L\n            AyGgUis+oRy4LBIN2vtjr5mV8nN71yWo6fpP0WsAh+ZHMumBiFc2ZklC6u5DIz/F\n            =M1T4\n            -----END PGP MESSAGE-----\n          fp: 15D5721F5F5BAF121495363EFE042E3D4085A811\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4D+EORkHurkvgSAQdAQpNEHt3PLkCDNl4vym+srqWPglF8+UG8DL/XPRXgh0Uw\n            SlMoGpu6qinl5bPFSJKbZnuYKj8dWtWoFfK9c1xURgbaqd3mckjbofI/5BrqPJJC\n            0l4BeyS+LrRZsFr0Ivyh/bI/0NTAw4WjSup6cQKO88XH+Q3Rhm6Kdzv57ZzIMpDd\n            0gAgFTL7uGz4at5VhZoZLjuVff0jkW0tw38i27jyTgGUXTfJhiNXjJXET3LnUgIQ\n            =OgdO\n            -----END PGP MESSAGE-----\n          fp: CC51116A94490FA6FB3C18EB2401FCAE863A06CA\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4DCsA/BhMt3V4SAQdAXEdFClqD2cSkNVYPqMSenULknpKAhaIgFvDD2j2WI18w\n            bq+Wxcz300c4bZNXROc8+hXNBzXW92MJ8uoNbD7hdefciF0UjcBf61mSQvYl/ueb\n            0l4B3k56RagBSmwUl8LytAUgF5OzY/6ICpe48d/+rguxBHvcI+KO3jBc6Da4FiAb\n            AGOVk2VdzVIeOBgc/eytAWjRlKYHk3mkXIfMlOYx2LFbFmrex5BWnrgVqoxo3hZU\n            =d+Ec\n            -----END PGP MESSAGE-----\n          fp: 4919F560F0D35F80CF382D76E084A2DF1143C14D\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4DRbry8yWl6IgSAQdAtRcYFWErls6e/h+TrDBuEQ+lECv2bfNEaZpg8yMIvRAw\n            G7Cm4X+lWBgeLD1mgrlF+kPsIxaolnXqM4V4dZAcAttrzffT1ssCtLe7dCRHZvfv\n            1GgBCQIQ+RzUnceJJToXtV98yJlxWCnu38pM8hL9PCBfFI0XEftKvdlScxRzBK/R\n            4nAIB29rAf9NHFeYDhIBjBdHQ9ju3T9kY0YH+585jsBCrWjMU+Hvj1JY7bVufrnV\n            ycoN0UtZ9f5Yag==\n            =H+8C\n            -----END PGP MESSAGE-----\n          fp: 11177A43C6E3752E682AC690DBD13117B0A14E93\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4DvbozpGPUDxgSAQdA/bTj9TEnbetB0jMR6ZNyQwzOJ7tvvPKUPbE7s4qrkmUw\n            GZBOamgGXU0UnnQ1Rk1hJ9rXXe4A6DqUAkOelaS/qUqCzRSNZboEijizAApaXGZe\n            0l4BbaCTNlLeJyI2jKbnO5hyv2DpHAFkKQ4CJna5KZj9TOrSrxnSkAJHLv0t0q9Z\n            M9weECX8RW3qvR75/H2T/ePfUYbGhB+7NpwN2BlU1wnTj7I9RkPetT8skCPxWY8G\n            =s/Bm\n            -----END PGP MESSAGE-----\n          fp: 5D7964FF2DB426ACB3C3505AA2A702DD5B689F45\n        - created_at: \"2025-05-13T14:07:57Z\"\n          enc: |-\n            -----BEGIN PGP MESSAGE-----\n\n            hF4D44lO7/xrMMASAQdAFbcv3Hu/AdGGSWC6kbPJcqbSlD1cTPX8sg8kb0oCpCcw\n            2/JLu9kJAEsO35DoyiYdRzBc2UVD26WSKtiNbD0XJOUo1yp/JTZ+xTH3fppE3Enf\n            1GgBCQIQtHg1HF6qEOfhnGrrW1ZZXEheX6+BPfOnQmN6BUcoevD4RrkbKS/x3mh3\n            A+y3MrdcaVtIQEWOMS1iuEKgJYeqYq6eOP0Y8B1Bbn3nKGK6G/zS7lqFDLUqWpMf\n            VT6LE5drfEXy5w==\n            =duo7\n            -----END PGP MESSAGE-----\n          fp: E77ED9F8451E10BD242D07415444881046F92733\n    unencrypted_suffix: _unencrypted\n    version: 3.10.2\n"
  },
  {
    "path": ".sops.yaml",
    "content": "# THIS FILE WAS AUTOMATICALLY GENERATED, PLEASE DO NOT EDIT.\n#\n# Generated on 2025-05-13T14:08:31Z by kres 5ad3e5f.\n\ncreation_rules:\n  - age: age1xrpa9ujxxcj2u2gzfrzv8mxak4rts94a6y60ypurv6rs5cpr4e4sg95f0k\n    # order: Andrey, Noel, Artem, Utku, Tim, Andy\n    pgp: >-\n      15D5721F5F5BAF121495363EFE042E3D4085A811,\n      CC51116A94490FA6FB3C18EB2401FCAE863A06CA,\n      4919F560F0D35F80CF382D76E084A2DF1143C14D,\n      11177A43C6E3752E682AC690DBD13117B0A14E93,\n      5D7964FF2DB426ACB3C3505AA2A702DD5B689F45,\n      E77ED9F8451E10BD242D07415444881046F92733"
  },
  {
    "path": ".textlintrc.json",
    "content": "{\n  \"rules\": {\n    \"one-sentence-per-line\": true\n  },\n  \"filters\": {\n    \"comments\": true\n  }\n}\n"
  },
  {
    "path": "ADOPTERS.md",
    "content": "# Adopters\n\nA list of adopters of Talos Linux, and the use\n\n## Adopters (listed alphabetically)\n\n- **[Ænix](https://aenix.io/)**  \n  Ænix provides consulting services for cloud providers and uses Talos Linux as base disto for free PaaS platform [Cozystack](https://cozystack.io) for running managed services, virtual machines and Kubernetes clusters.\n\n- **[DreeBot](https://dreebot.com)**  \n  DreeBot is a cloud host for on-demand multiplayer game servers. Talos is an integral part of our infrastructure, easily and efficiently managing all of our enterprise tools and services so we can keep our developers focused on development.\n\n- **[Equinix Managed Services NL](https://www.equinix.nl/services/managed-services/netherlands)**  \n  Equinix Managed Services NL offers various infrastructure services, amongst which [EQAP](https://www.equinix.nl/services/managed-services/netherlands/application-platform), which is a managed Kubernetes, based on Talos Linux.\n\n- **[Lofty](https://hirelofty.com)**  \n  Lofty makes amazing custom software for our clients that our employees are passionate about. Lofty's specialization in software development around GIS/geospatial applications, field data collection, and data science operations makes Lofty an ideal partner for our key industries. Lofty is using Talos as a secure and portable base Operating System for deploying our applications.\n\n- **[Mynewsdesk](https://mynewsdesk.com)**\n  Mynewsdesk provides a SaaS product for PR work. In 2022 they created [Reclaim the Stack](https://reclaim-the-stack.com), a Kubernetes based open source deployment platform to replace Heroku. They are now running their application on this platform using Talos Linux on Hetzner bare metal servers with 30+ nodes in the cluster.\n\n- **[Nedap Security Atlas](https://nedapsecurityatlas.com)**  \n  Nedap Security Atlas does all on-premise development, unit and integration testing in Gitlab running on Talos clusters.\n\n- **[Oceanbox.io](https://oceanbox.io)**  \n  Oceanbox leverages talos to deliver oceanography as a service. It is used on-premise in a rook-ceph storage cluster, and to host frontend and supporting services for the HPC cluster.\n\n- **[Redpill Linpro](https://redpill-linpro.com)**\n  Redpill Linpro uses Talos Linux for both internal and customer specific Kubernetes services. It is for example used to provide a triple-site platform for Norway's biggest online publisher.\n\n- **[SCHULZ Systemtechnik GmbH](https://schulz.st/en/page/schulz-systemtechnik)**  \n  SCHULZ is a provider of integrated automation solutions for a wide range of industries. We use Talos as a base for our edge devices that run IoT and ML applications.\n\n- **[SenseLabs](https://senselabs.de)**  \n  SenseLabs offers custom cloud-native geo applications and uses Talos-backed clusters for development and testing.\n- **[Sidero Labs](https://www.siderolabs.com)**  \n  Sidero Labs uses Talos to build & test Talos! All the unit and end-to-end testing happens on our CI platform running in Talos-backed Kubernetes clusters.\n- **[Nexxen](https://www.nexxen.com)**  \n  Nexxen is the flexible advertising platform that connects data to deliver desired outcomes.\n\n- **[TrueFullstaq](https://truefullstaq.com)**  \n  As a leading cloud native consultancy, TrueFullStaq designs, builds, and manages scalable and secure custom infrastructure for their clients. They have adopted Talos Linux as a foundational component for their\n  managed Kubernetes offerings, leveraging its immutable nature, API-driven management, and minimal footprint to deliver highly secure and easily maintainable Kubernetes environments. By building on Talos,\n  TrueFullStaq ensures their customers benefit from a declarative, robust, and production-ready foundation for their cloud native journey.\n\n- **[Vandebron](https://www.vandebron.nl)**  \n  Vandebron is a Dutch green-tech energy company on a mission to accelerate the transition towards 100% sustainable energy, 100% of the time. We use TalosOS on our edge devices contributing to stabilize the Dutch energy grid with curtailment and flexibility services.\n\n## Contributing\n\nIf you use Talos Linux and want to add your organization to this list, simply [edit](https://github.com/siderolabs/talos/edit/main/ADOPTERS.md) this file using the template below, then submit the changes in a pull request!\n\n### Template\n\n- **[ORG NAME](ORG URL)**  \n  ORG DESCRIPTION & TALOS USE\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [Talos 1.13.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.13.0-alpha.2) (2026-02-25)\n\nWelcome to the v1.13.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Clang built kernel and ThinLTO\n\nTalos now uses a kernel built using Clang compiler, and optimized using ThinLTO. This should bring a small performance improvement,\nalongside some hardening features, such as BTI on supported ARM systems.\n\n\n### talosctl debug\n\nTalos Linux now provides a way to run and attach to the privileged debug container with a user-provided container image.\nThe debug container might be used for troubleshooting and debugging purposes.\n\n\n### Environment Configuration Document\n\nA new `EnvironmentConfig` document has been introduced to allow users to specify environment variables for Talos components.\nIt replaces and deprecates the previous method of setting environment variables via the `.machine.env` field.\n\nMultiple values for the same environment variable will replace previous values, with the last one taking precedence.\n\nTo remove an environment variable, remove it from the `EnvironmentConfig` document and restart the node.\n\n\n### External Volumes\n\nTalos now supports virtiofs-based external volumes via the new\n[ExternalVolumeConfig](https://www.talos.dev/v1.13/reference/configuration/block/externalvolumeconfig/)\ndocument.\n\nThese virtiofs external volumes are not supported when SELinux is running\nin enforcing mode.\n\n\n### Extra Arguments accept slices in addition to strings\n\nSeveral Talos configuration fields that previously accepted single string values for extra arguments have been updated to accept slices of strings as well.\nThis includes fields such as `.cluster.apiServer.extraArgs`.\n\nBREAKING: If you were relying on the resources EtcdConfigs, KubeletConfigs, ControllerManagerConfigs, SchedulerConfigs or APIServerConfigs, the protobuf format has changed from `map<string,string>` to `map<string,message>`.\n\n\n### Talos Imager Enhancements\n\nTalos imager now supports running rootless. `--privileged` and `-v /dev:/dev` are no longer required.\n\n\n### Image APIs Updated\n\nTalos Linux provides new APIs to manage container images on the node: listing, pulling, importing and removing images.\nThe new pull APIs provides pull progress notifications.\n\nThe CLI commands `talosctl image pull`, `talosctl image list` and `talosctl image remove` have been updated to interact with the new APIs.\n\n\n### Talosctl images k8s-bundle subcommand accepts version parameter\n\nThe `talosctl images k8s-bundle` command now accepts an optional version overrides arguments.\n\n\n### Kubernetes server-side apply\n\nTalos now uses inventory backed server-side apply when applying bootsrap manifests (including `extraManifests` and `inlineManifests`).\nPurging of unneeded manifests is automatically performed.\nThe switch and inventory backfill is automatic and no action is needed from the user.\n\n\n### KubeSpan Configuration\n\nA new `KubeSpanConfig` document has been introduced to configure KubeSpan settings.\nIt replaces and deprecates the previous method of configuring KubeSpan via the `.machine.network.kubespan` field.\n\nThe old configuration field will continue to work for backward compatibility.\n\n\n### KubeSpan Advertised Network Filters\n\nKubeSpan now supports filtering of advertised networks using the `excludeAdvertisedNetworks` field in the `KubeSpanConfig` document.\nThis allows users to specify a list of CIDRs to exclude from the advertised networks. Please note that routing must be symmetric for any\npair of peers, so if one peer excludes a certain network, the other peer must also exclude it. In other words, for any given pair of peers,\nand any pair of their addresses, the traffic should either go through KubeSpan or not, but not one way or the other.\n\n\n### LinkAliasConfig Pattern-Based Multi-Alias\n\n`LinkAliasConfig` now supports pattern-based alias names using `%d` format verb (e.g. `net%d`).\n\nWhen the alias name contains a `%d` format verb, the selector is allowed to match multiple links.\nEach matched link receives a sequential alias (e.g. `net0`, `net1`, ...) based on hardware address order\nof the links. Links already aliased by a previous config are automatically skipped.\n\nThis enables creating stable aliases from any N links using a single config document,\nuseful for `BondConfig` and `BridgeConfig` member interfaces on varying hardware.\n\n\n### Negative Max Volume Size\n\nNegative max size represents the amount of space to be left free on the device, rather than the size the volume should consume.\nFor example:\n    * a max size of \"-10GiB\" means the volume can grow to the available space minus 10GiB.\n    * a max size of \"-25%\" means the volume can grow to the available space minus 25%.\n\n\n### Flannel CNI with Network Policy Support\n\nTalos Linux now supports optionally deploying Flannel CNI with [network policy support](https://kubernetes.io/docs/concepts/services-networking/network-policies/) enabled.\nThe network policy implementation is [kube-network-policies](https://github.com/kubernetes-sigs/kube-network-policies/).\n\nTo enable Flannel CNI with network policy support, use the following machine configuration patch:\n\n```yaml\ncluster:\n  network:\n    cni:\n      name: flannel\n      flannel:\n        kubeNetworkPoliciesEnabled: true\n```\n\n(If the cluster is already running, sync the bootstrap manifests after applying the patch to deploy the new CNI configuration.)\n\n\n### Container Image Decompression\n\nTalos now ships with `igzip` (amd64) and `pigz` (arm64) to speed up container image decompression.\n\n\n### ProbeConfig\n\nThe TCPProbeConfig configuration document allows to configure TCP probes for network reachability checks.\nThis allows to define a custom connectivity condition.\n\n\n### /proc/PID/mem Access Hardening\n\nA new kernel parameter `proc_mem.force_override=never` has been introduced by default to enhance system security\nby preventing unwanted writes to protected process memory via `/proc/PID/mem`.\nIf the kernel parameter is removed, default behavior is restored, allowing access only if the process is traced.\n\n\n### Reproducible Disk Images\n\nTalos disk images are now reproducible. Building the same version of Talos multiple times will yield\nidentical disk images.\n\nNote: VHD and VMDK (Azure and VMware) images are not currently reproducible due to limitations in the underlying image creation tools.\nUsers verifying reproducible images should use raw images, verify checksums, and convert them to VHD/VMDK as needed.\n\n\n### ResolverConfig\n\nThe nameservers configuration in machine configuration now overwrites any previous layers (defaults, platform, etc.) when specified.\nPreviously a smart merge was performed to keep IPv4/IPv6 nameservers from lower layers if the machine configuration specified only one type.\n\n\n### Service Account Issuer configuration\n\nIn API Server, passing extra args with `service-account-issuer` will append them after default value.\nThis allows easy migration, e.g. by changing `.cluster.controlPlane.endpoint` to new value, and keeping the old value in\n`.cluster.apiServer.extraArgs[\"service-account-issuer\"]`.\n\n\n### `talosctl images talos-bundle` can ignore reaching to the registry\n\nThe `talosctl images talos-bundle` command now accepts optional `--overlays` and `--extensions` flags.\nIf those are set to `false`, the command will not attempt to reach out to the container registry to fetch the latest versions and digests of the overlays and extensions.\n\n\n### Component Updates\n\nLinux: 6.18.13\ncontainerd: 2.2.1\netcd: 3.6.8\nCoreDNS: 1.14.1\nKubernetes: 1.36.0-alpha.1\nFlannel CNI plugin: v1.9.0-flannel1\nFlannel: 0.28.1\nLVM2: 2_03_38\nrunc: 1.4.0\nsystemd: 259.1\ncryptsetup: 2.8.3\nTenstorrent: 2.7.0\niptables: 1.8.12\n\nTalos is built with Go 1.26.0.\n\n\n### VM Hot-Add Support\n\nTalos now includes udev rules to support hot-adding of CPUs in virtualized environments.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Mateusz Urbanek\n* Noel Georgi\n* Dmitrii Sharshakov\n* Orzelius\n* Laura Brehm\n* Edward Sammut Alessi\n* Max Makarov\n* Andreas Freund\n* Artem Chernyshev\n* Bryan Lee\n* Fritz Schaal\n* Justin Garrison\n* Mickaël Canévet\n* Nico Berlee\n* Pranav Patil\n* Alexis La Goutte\n* Andras BALI\n* Andrei Kvapil\n* Birger Johan Nordølum\n* Camillo Rossi\n* Christopher Puschmann\n* Daniil Kivenko\n* Dmitrii Sharshakov\n* Florian Ströger\n* Gregor Gruener\n* Jaakko Sirén\n* Jan Paul\n* Jean-Francois Roy\n* Joakim Nohlgård\n* Jonas Lammler\n* Lennard Klein\n* Matthew Sanabria\n* Michal Baumgartner\n* Olav Thoresen\n* Serge van Ginderachter\n* Skye Soss\n* Spencer Smith\n* Sébastien Masset\n* Tim Jones\n* Utku Ozdemir\n* arita\n* dataprolet\n* drew\n* eseiker\n* greenpsi\n* lmacka\n* pranav767\n\n### Changes\n<details><summary>221 commits</summary>\n<p>\n\n* [`009f0d6ca`](https://github.com/siderolabs/talos/commit/009f0d6ca0cf13e5778a7c46587ac0dc9d30d5e9) chore: update pkgs\n* [`ba56b0295`](https://github.com/siderolabs/talos/commit/ba56b02954fb275f8ff2ed20e38b51a75c3a8371) feat: include hid-multitouch.ko kernel module in rootfs\n* [`ae29a0dcc`](https://github.com/siderolabs/talos/commit/ae29a0dcce527b90553b25230abbb5a8d4bd504c) feat: update Linux to 6.18.13\n* [`7cf1de279`](https://github.com/siderolabs/talos/commit/7cf1de2794a1d4838efca378aff433fad5e1823c) fix: bring in new version of go-cmd and go-blockdevice\n* [`c8800b41e`](https://github.com/siderolabs/talos/commit/c8800b41e511ce6bb4dda3e28b69c4d091177435) fix: update path handling on talosctl cgroups\n* [`0a7b6eb2c`](https://github.com/siderolabs/talos/commit/0a7b6eb2c98979aa8a604f677c4dd1d54f1285e5) chore: test extensions\n* [`8b1c974a2`](https://github.com/siderolabs/talos/commit/8b1c974a2a733c870f371ccb7a86ccc616dbc7ea) refactor: drop termui-widgets library\n* [`5baa0028e`](https://github.com/siderolabs/talos/commit/5baa0028e65765fc0fd1179f72377bf2a2085deb) fix: add owning inventory annotation to talos manifests\n* [`d3e793d14`](https://github.com/siderolabs/talos/commit/d3e793d14117891103ca4df8507124b18913a56c) fix: stop Kubernetes client from dynamically reloading the certs\n* [`6a5a0e3bd`](https://github.com/siderolabs/talos/commit/6a5a0e3bd4197a4fadfcfe094876e46d4b878a0a) feat: support pattern link aliases\n* [`9758bd4fe`](https://github.com/siderolabs/talos/commit/9758bd4fe0e28803acf11f3b9c9da744883aa9dc) feat: update Go to 1.26\n* [`e00aed0f6`](https://github.com/siderolabs/talos/commit/e00aed0f6694bb3c8e14a0ef413ef0e62ae02981) feat: update Kubernetes v1.36.0-alpha.1\n* [`f20445ad0`](https://github.com/siderolabs/talos/commit/f20445ad0981175d6444340325af5fc747993559) chore: improve logging of disk encryption handling\n* [`f018fbe7b`](https://github.com/siderolabs/talos/commit/f018fbe7ba145ff86ebe0d4d09b323b9715ef1a9) fix: handle raw encryption keys with `\\n` properly\n* [`e5b0eb017`](https://github.com/siderolabs/talos/commit/e5b0eb017ff989e812d6444f668bf17723bb7ec4) fix: hold user volumes root mountpoint\n* [`8a0e79774`](https://github.com/siderolabs/talos/commit/8a0e79774409ce7605f9cd21d769f47e5db656db) refactor: split locate and provision\n* [`a59db0e92`](https://github.com/siderolabs/talos/commit/a59db0e92213296c4c9599fb0d230908caabdf30) fix: improve OpenStack bare metal network configuration reliability\n* [`659009ad8`](https://github.com/siderolabs/talos/commit/659009ad875c0625ac24094dc44020b015ab8b50) fix: remove stale endpoints\n* [`dab0d4783`](https://github.com/siderolabs/talos/commit/dab0d478378dfc6c2862c38633ca4494a41e7ecd) fix: allow static hosts in `/etc/hosts` without hostname\n* [`45f214154`](https://github.com/siderolabs/talos/commit/45f214154cea364d86bfbba81a5ad4f272a4c8fd) feat: update go-kubernetes to use new Myers diff\n* [`35ad0448c`](https://github.com/siderolabs/talos/commit/35ad0448c9ae93cd642d80ebb7d95b768ba0ab9b) fix: switch to better Myers algorithm implementation\n* [`0048464be`](https://github.com/siderolabs/talos/commit/0048464be854d94fb607e38daa83e00767fe8cbc) feat: update etcd to v3.6.8\n* [`5df10f260`](https://github.com/siderolabs/talos/commit/5df10f2604b537504f76b14e028f88a946aacbd7) fix: use mcopy instead of diskfs to populate VFAT\n* [`ce53ffa90`](https://github.com/siderolabs/talos/commit/ce53ffa900a438f6669460a2ce9af874c1f87708) fix: disks flag parsing and handling in create qemu command\n* [`3bd3dd7ca`](https://github.com/siderolabs/talos/commit/3bd3dd7ca92401312079e37584bfbf7942eab93a) fix: memory overuse in imager VFAT\n* [`f118ee47e`](https://github.com/siderolabs/talos/commit/f118ee47eaba662dc161d37fae5ae8f2b3de9819) fix: read multi-doc machine config with newer talosctl\n* [`70c6c2154`](https://github.com/siderolabs/talos/commit/70c6c2154e87d4a6748aebdfa2c50cbc97a0dd89) feat: add filter for KubeSpan advertised networks\n* [`daf18abf4`](https://github.com/siderolabs/talos/commit/daf18abf419b21a6e70dcca0b5b83d33cfee6188) fix: fix talosctl debug in enforcing mode\n* [`33b5b2565`](https://github.com/siderolabs/talos/commit/33b5b25652360a114d0b2cea412bf018cbf84df3) fix: ignore volumes in wave calculation without provisioning\n* [`a16392559`](https://github.com/siderolabs/talos/commit/a16392559a488993c3e26810df57da3cae5c24c5) feat: add explicit service account support to Talos client\n* [`4d531884e`](https://github.com/siderolabs/talos/commit/4d531884e9c28d480f24b61a83f140df0ffbe4b3) chore: update dependencies\n* [`406b8c83c`](https://github.com/siderolabs/talos/commit/406b8c83c9b33b1917b9dd16aa1efeb2df189f0f) feat: update doc links to docs.siderolabs.com\n* [`87615f551`](https://github.com/siderolabs/talos/commit/87615f551183cd322dafebf368a347d928a14442) feat: implement network policies with Flannel CNI\n* [`6995bc1b1`](https://github.com/siderolabs/talos/commit/6995bc1b1ea54e1a8fd6426fef11293f35106ac7) chore: update homebrew formula on release\n* [`7942d5a98`](https://github.com/siderolabs/talos/commit/7942d5a98c1d689a94e78219be09a0fc69d07b08) fix: image gc controller config\n* [`52e8727d0`](https://github.com/siderolabs/talos/commit/52e8727d0112967a62a3d9ae6bf26d713db242e1) feat: add IPv6 GRE support\n* [`9690dbad0`](https://github.com/siderolabs/talos/commit/9690dbad02cfc8682d697679b655e753039c5254) chore: bump tools (including linter)\n* [`2628eb2ec`](https://github.com/siderolabs/talos/commit/2628eb2ece05d7f817fc42e12b979d3f8ca9710c) fix: typo with rpi_5 profile name\n* [`d5ebcd7ca`](https://github.com/siderolabs/talos/commit/d5ebcd7cae1a20c8000e2f4d5a02c81e4dbe5186) fix: stop building talosctl debug on Windows\n* [`8b85c7c63`](https://github.com/siderolabs/talos/commit/8b85c7c637cc08d35bbf6968abebb8c4cdfb82ad) chore: update deps\n* [`d905035b5`](https://github.com/siderolabs/talos/commit/d905035b5e5c7787a5171ba2e0127c89755e8774) fix: swap volume configuration for min/max size\n* [`d43a01ccb`](https://github.com/siderolabs/talos/commit/d43a01ccbdd318080b54e52d2f2fbec93042c458) feat: implement `talosctl debug`\n* [`34a31c979`](https://github.com/siderolabs/talos/commit/34a31c9797d5a7e1700c3d945a21367b81c79385) feat: add mount options support for existing volumes\n* [`1bf95eed1`](https://github.com/siderolabs/talos/commit/1bf95eed185152c38397cd3b43b6ff9d421678c5) feat: improve dashboard uptime display\n* [`055add7ae`](https://github.com/siderolabs/talos/commit/055add7aeb158b6f4e09ef06966de7622d1b3940) release(v1.13.0-alpha.1): prepare release\n* [`900516e68`](https://github.com/siderolabs/talos/commit/900516e68950e4b94696f6a9b481cefee44b3360) chore: update image signer\n* [`938de566e`](https://github.com/siderolabs/talos/commit/938de566eca30af3cc4355a94931186f19b682f2) feat: bump kernel\n* [`388cec727`](https://github.com/siderolabs/talos/commit/388cec72796d0ecd0c7103efcaab9066e9b62509) feat(overlays): add new overlays\n* [`9f2dd6312`](https://github.com/siderolabs/talos/commit/9f2dd6312f9d49e4d03347c98b100119f94cf807) refactor: api tests\n* [`a90783146`](https://github.com/siderolabs/talos/commit/a90783146fc2d475055bfce0f8b5120969f74dc7) feat: add a helper module to generate standard patches\n* [`1fec5b23d`](https://github.com/siderolabs/talos/commit/1fec5b23d0c10e53863a7c0f89f862708a7f4069) fix: implement merger for PercentageSize\n* [`8b245b8f2`](https://github.com/siderolabs/talos/commit/8b245b8f269b6c8cb463f2cf537d2ed2ab6924ec) feat: implement new image service APIs\n* [`d90c775b8`](https://github.com/siderolabs/talos/commit/d90c775b8441705003de3427b2e6831dcbfb449f) chore: rename internal `talosctl debug air-gapped`\n* [`2165280d0`](https://github.com/siderolabs/talos/commit/2165280d0eedf59899ad44e2f3289d81b3dab466) refactor: change the way one2many proxying is picked\n* [`b1b703dbe`](https://github.com/siderolabs/talos/commit/b1b703dbe2b25785ded0c77f23d674d9b9934975) chore: move sync logging code to go-kubernetes package\n* [`e48c6d7ab`](https://github.com/siderolabs/talos/commit/e48c6d7ab9c8a2e28ebe2115ac09f1557bbcca33) fix: allow to expose a port multiple times in Docker\n* [`410d8cb57`](https://github.com/siderolabs/talos/commit/410d8cb5727ccf054c9097f33bc916d87076a599) fix: undo CRLF on Windows (talosctl edit)\n* [`859d3f03c`](https://github.com/siderolabs/talos/commit/859d3f03c444d98b94a06adac3648562e3b1228b) feat: add RPi5 to the list of supported SBCs\n* [`0bd48bbc6`](https://github.com/siderolabs/talos/commit/0bd48bbc6f365770167ee753be563eb4179fcadb) fix(talosctl): pass --k8s-endpoint flag to rotate-ca kubernetes rotation\n* [`b9e27ebe7`](https://github.com/siderolabs/talos/commit/b9e27ebe72c4302c416fd8efb007c3966004ddd6) feat: update Linux kernel with dm-integrity\n* [`6aa9b0677`](https://github.com/siderolabs/talos/commit/6aa9b0677ed7ca4955fead474e36a533b3250ad9) fix: skip empty documents on config decoding\n* [`494492489`](https://github.com/siderolabs/talos/commit/494492489b29b615a8a874c0648690ed3b9adb58) fix: always set advertised peer URLs\n* [`782cc507d`](https://github.com/siderolabs/talos/commit/782cc507dc33c87caa5ff985eea5f4439c3e1012) fix: open the filesystem as read-only\n* [`28e61a740`](https://github.com/siderolabs/talos/commit/28e61a740a906fadfea098f38a9c9f4e8c32773e) fix: set GRUB prefix correctly on arm64\n* [`a4f1c5239`](https://github.com/siderolabs/talos/commit/a4f1c5239ef7227856640c230e0d0364d9eedbd2) feat: update GRUB to 2.14\n* [`562920701`](https://github.com/siderolabs/talos/commit/562920701e2999cbb6687e55de96719aba4064fd) fix: use node podCIDRs for kubespan advertiseKubernetesNetworks\n* [`39460365c`](https://github.com/siderolabs/talos/commit/39460365c1726095e20cf3cc7c079c234b8022d6) feat: implement layering for ProbeSpec\n* [`b5c760f70`](https://github.com/siderolabs/talos/commit/b5c760f7076570bc04be02af0ea493f95d8338d0) feat: add ProbeConfig for network connectivity probes\n* [`4b274f761`](https://github.com/siderolabs/talos/commit/4b274f76159495cc6c2977ec3bbade71e35aade8) feat: support aws cert manager in imager\n* [`417209512`](https://github.com/siderolabs/talos/commit/41720951251102f1c174e501a3103e55720a1d8b) fix: fallback to /proc/meminfo for memory modules\n* [`7f1147bed`](https://github.com/siderolabs/talos/commit/7f1147bed495a06d336f5be1da6073921b5e52dc) fix: add warnings to 802.3ad bond\n* [`ddd6b186e`](https://github.com/siderolabs/talos/commit/ddd6b186eb8f527324736576182dafbce3423da5) refactor: generate GRUB images\n* [`c7aa266ea`](https://github.com/siderolabs/talos/commit/c7aa266ea5c9d3fbd465dc651f2ebfec622612e7) fix: overwrite resolver config with machine config\n* [`cf70f05fa`](https://github.com/siderolabs/talos/commit/cf70f05fa40312c30d8345c2fb15ce8eda86a7a7) fix: oracle platform file format\n* [`8c7b8f5b7`](https://github.com/siderolabs/talos/commit/8c7b8f5b7d6dec144f7985a7c8a8a582c38f3154) feat: add support for negative max size\n* [`77bc3d21f`](https://github.com/siderolabs/talos/commit/77bc3d21fa40e188af4b5dd93e1cda289e858d56) fix: marshal of FailOverMac property\n* [`38e280c93`](https://github.com/siderolabs/talos/commit/38e280c9319ef1ecb1455b3cc8b8d0d1d7426ccd) fix: make OOM expression a bit less sensitive\n* [`3d1301640`](https://github.com/siderolabs/talos/commit/3d1301640d44d58303160400e4954c36f53341f9) fix: wipe the first/last 1MiB in addition to wiping by signatures\n* [`1aa6528ad`](https://github.com/siderolabs/talos/commit/1aa6528adcddfb6a5ed66cc26cac1a0fcdb37516) fix: make OOM controller more precise by considering separate cgroup PSI\n* [`f7072c050`](https://github.com/siderolabs/talos/commit/f7072c050e607de16781a65eb97ab2a1828b05fb) fix: check if the device is not mounted when wiping\n* [`743c3b94b`](https://github.com/siderolabs/talos/commit/743c3b94b958e4abcbf70d4064f2ae0e0bbb0712) fix: use correct containerd import path\n* [`f2dd08594`](https://github.com/siderolabs/talos/commit/f2dd08594e8e474c7b3891dc46c64f27c724dbc0) feat: report image pull progress in the console\n* [`72fe98a06`](https://github.com/siderolabs/talos/commit/72fe98a06f31536454f201d703f8ae6a071235b5) fix: boot with GRUB\n* [`d4ed13d93`](https://github.com/siderolabs/talos/commit/d4ed13d9394b087e8877eba25950f344894803a1) fix: add talos version to Hetzner Cloud client user agent\n* [`150c41c30`](https://github.com/siderolabs/talos/commit/150c41c30ed3f066f10bd2bdc2afa9b2c5a97597) feat: update Linux to 6.18.5\n* [`01a367891`](https://github.com/siderolabs/talos/commit/01a3678913de0fa4d309a361428c117d24ce0d1e) fix: use append instead of prepend in service-account-issuer\n* [`d1954278a`](https://github.com/siderolabs/talos/commit/d1954278a1ba3470b2e5ccae90762078c18d69e9) feat: add extraArgs from service-account-issuer\n* [`91b88f7f9`](https://github.com/siderolabs/talos/commit/91b88f7f994cccad15cbec1aa8019bd19b84ae91) feat: support multiple values for extraArgs\n* [`96e604874`](https://github.com/siderolabs/talos/commit/96e604874b17e7aa8b62bfb25737f349e539bc5a) fix: add hostname to endpoints\n* [`7033275a7`](https://github.com/siderolabs/talos/commit/7033275a7a22d51e83c9e760ba37d2ad6ab22f28) refactor: move BootloaderKind into machinery\n* [`71adaf0ea`](https://github.com/siderolabs/talos/commit/71adaf0ea5b558c8a16e2acfdec3671611455985) fix: sort mirrors and tls configs when generating the machine config\n* [`34f09a300`](https://github.com/siderolabs/talos/commit/34f09a3004fe1b77c16dd33b04adca95fb6876a5) feat: add VLAN support to OpenStack platform\n* [`5127ef7c2`](https://github.com/siderolabs/talos/commit/5127ef7c28b360f9c7c033f77c58cef729e5278d) fix: wipe disk by signatures\n* [`415bfaedb`](https://github.com/siderolabs/talos/commit/415bfaedb6ae8d42b5927fdc5b7cfe8aa781a791) fix: panic in configpatcher when the whole section is missing\n* [`e5aca71cd`](https://github.com/siderolabs/talos/commit/e5aca71cd0557557e50c39d82eda2c938f627d62) fix: fix healthcheck timeout\n* [`634b71e2d`](https://github.com/siderolabs/talos/commit/634b71e2d028bf13d838acad8809c95384b6eed9) docs: move talosctl pcap example to Example Block\n* [`818492731`](https://github.com/siderolabs/talos/commit/8184927316c5de7d9b04f21474a60cc791c3d26d) feat: implement KubeSpan multi-document configuration\n* [`4d0604b9d`](https://github.com/siderolabs/talos/commit/4d0604b9d93851f444a00dbd84fcac76d21d35c2) chore: remove unrelated machineconfig\n* [`e36863470`](https://github.com/siderolabs/talos/commit/e36863470b14496c3d84417e63fef45e6060603b) feat: add it87 hwmon module\n* [`308c75090`](https://github.com/siderolabs/talos/commit/308c75090774d2510c2ec08e63e179a5c0fa6987) fix: resolve SideroLink Wireguard endpoint on reconnect\n* [`e4ef494de`](https://github.com/siderolabs/talos/commit/e4ef494decdf97664c4803aa3861015fce49760e) fix: drop the persist config flag from gen config\n* [`c3176adcf`](https://github.com/siderolabs/talos/commit/c3176adcf981811a326c971c81c4b591f54e116a) feat: add EnvironmentConfig document\n* [`c839b3880`](https://github.com/siderolabs/talos/commit/c839b38809b3a0029061d43477555ec31e283aa5) feat: expose more SSA options in the upgrade-k8s command\n* [`b8ff9677e`](https://github.com/siderolabs/talos/commit/b8ff9677e4f9a64908ae00bb1d80aa2442a00a60) fix: handle correctly incomplete RegistryTLSConfig\n* [`99f2ddada`](https://github.com/siderolabs/talos/commit/99f2ddada895011036af1435dd10bac3be0a9171) fix: bond config via platform\n* [`2449ffea4`](https://github.com/siderolabs/talos/commit/2449ffea45304459ea8895b535b6f070a9249172) fix: allow HostnameConfig to be used with incomplete machine config\n* [`35fc52087`](https://github.com/siderolabs/talos/commit/35fc5208728dbc3e0b139aff4c06f25208445637) fix: lock down etcd listen address to IPv4 localhost\n* [`27253d731`](https://github.com/siderolabs/talos/commit/27253d7317a473cbbc0f5c0eee634173bdd2eda7) feat: use new xfs config file\n* [`c9d84ae21`](https://github.com/siderolabs/talos/commit/c9d84ae21e203529a6952c165ff04d602a2a6ad6) fix: generate OCI-compliant image config\n* [`7a4b2b33a`](https://github.com/siderolabs/talos/commit/7a4b2b33abe8a3011f37f0a8f4848dd846d0396f) fix: update VIP config example\n* [`080efcbda`](https://github.com/siderolabs/talos/commit/080efcbda2c4334f9d8c70804a5a37f0cdb2df2d) feat: add k8s-version parameter to k8s-bundle\n* [`b764f5f72`](https://github.com/siderolabs/talos/commit/b764f5f724bf8af3acaac74942ea91a86e593322) fix: skip sync test when kube-proxy is disabled\n* [`70e67787d`](https://github.com/siderolabs/talos/commit/70e67787d6d34d93a34871b2d25d64f6a7575d76) feat: imager: populate filesystems with root owned files\n* [`7416dca59`](https://github.com/siderolabs/talos/commit/7416dca59378dc282e42ea30107cf40326cc593c) fix: print talosctl images to release notes\n* [`dc2009e47`](https://github.com/siderolabs/talos/commit/dc2009e4779684a6a4252d4dfd2aa02d1b60c2da) chore: use context when creating filesystems\n* [`85f7be6e3`](https://github.com/siderolabs/talos/commit/85f7be6e3f14bf160cf32bccf7418b31968d474f) chore: update slack links\n* [`154952175`](https://github.com/siderolabs/talos/commit/154952175ab73ac65722732b146a0ee1c56b2f4d) fix: disable swap for system services\n* [`d98b415af`](https://github.com/siderolabs/talos/commit/d98b415afea7b1820153151c0273df24a101742e) fix: drop more non-overlay SBC stuff\n* [`226cd6bc1`](https://github.com/siderolabs/talos/commit/226cd6bc1d70662cb7f7736ac6fad117170a36fb) fix: do not allocate for the actual disk image file\n* [`53f5bf8d2`](https://github.com/siderolabs/talos/commit/53f5bf8d2c97e91bee06bcb5948170015486ea77) fix: overlay installers\n* [`10d0cfd93`](https://github.com/siderolabs/talos/commit/10d0cfd93a083fb8b71b7c0297df52feb55e044b) fix: overlay install in image mode\n* [`77086694d`](https://github.com/siderolabs/talos/commit/77086694d18b69802e542156fc12cd7cf066efc2) fix: partition data population\n* [`4d5657b1a`](https://github.com/siderolabs/talos/commit/4d5657b1a34c939b63b2cc3ee11ed45ad1bf23c3) fix: drop SBC board code\n* [`c4f3f6d3e`](https://github.com/siderolabs/talos/commit/c4f3f6d3e59b58016ba8546c5bd3e8e465fbbf52) feat: implement kubernetes server-side apply\n* [`f12fd2b0a`](https://github.com/siderolabs/talos/commit/f12fd2b0a9fdf8f53ec5714d3ad18b695973e0b0) test: bump Image Factory tests\n* [`c76484e58`](https://github.com/siderolabs/talos/commit/c76484e5879a7e48197e442cf22044d3d0363846) release(v1.13.0-alpha.0): prepare release\n* [`f0d8a6851`](https://github.com/siderolabs/talos/commit/f0d8a685173354e5fd148786872062a342c4282a) test: skip the source bundle on exact tag\n* [`c57701d65`](https://github.com/siderolabs/talos/commit/c57701d6590388e7d6418af67e8237c7d60ccf54) fix: remove interactive installer\n* [`43937c1cd`](https://github.com/siderolabs/talos/commit/43937c1cd42758a15026261fe8f0e06daaebdcbd) feat: update Linux and systemd\n* [`72a194df8`](https://github.com/siderolabs/talos/commit/72a194df88f2800cee3372241fbad419b07f7bbf) feat: add VM CPU hot-add rules\n* [`f09ae1e0d`](https://github.com/siderolabs/talos/commit/f09ae1e0d2e1b7842d504b594b71a325af7733e5) fix: probe small images correctly\n* [`8f2b33799`](https://github.com/siderolabs/talos/commit/8f2b337994fdeff76a0ae9e1730b4b9f596ff1bb) feat: imager support rootless builds\n* [`c7525a97e`](https://github.com/siderolabs/talos/commit/c7525a97ef8615e903be183d7938b6d2a3b89464) feat: support creating filesystems from folder\n* [`e2bffb5ce`](https://github.com/siderolabs/talos/commit/e2bffb5cebaaf28f9dfff24f41ecbb2809fc60e5) chore: refactor imager code so it's more clear\n* [`0fb50dbd0`](https://github.com/siderolabs/talos/commit/0fb50dbd0a5b7b80187e50d501cec4b3fe434dc2) fix: invalid versions check in talos-bundle\n* [`b5dd56032`](https://github.com/siderolabs/talos/commit/b5dd5603207a46d8eed240173f06aeffd6a9c0e7) test: upgrade versions in upgrade tests\n* [`3dfa4d6e4`](https://github.com/siderolabs/talos/commit/3dfa4d6e40dcae2db47e89443568be3ae48b3ae1) fix: make upgrade work with SELinux enforcing=1\n* [`786c8e2ee`](https://github.com/siderolabs/talos/commit/786c8e2ee757c2d7b30d5bded954e584af3a058e) feat: ship pigz/igzip in rootfs to speed up image decompression\n* [`48d242918`](https://github.com/siderolabs/talos/commit/48d242918bc97e6a01434bee6fcdcfa735fd1f5a) feat: update containerd to 2.2.1\n* [`536541afe`](https://github.com/siderolabs/talos/commit/536541afe497d5f61cfcd0c01cf580ab5b3be164) fix: mount volume mount/unmount race\n* [`39117d457`](https://github.com/siderolabs/talos/commit/39117d45766b139ed6a0c1290f757e4b26d31d92) feat: update dependencies\n* [`f0f420725`](https://github.com/siderolabs/talos/commit/f0f420725c6a4f628cdc1b80d59713c375beb9b7) fix: bond setting change detection\n* [`8d6a7a867`](https://github.com/siderolabs/talos/commit/8d6a7a8677a5d1d61432fa94ca030351fd9852f2) feat: update Kubernetes to 1.35.0\n* [`845a0d09c`](https://github.com/siderolabs/talos/commit/845a0d09cd770a15db762ddda4d3d27f58656cfe) feat: update etcd 3.6.7, CoreDNS 1.13.2\n* [`b95912e04`](https://github.com/siderolabs/talos/commit/b95912e04907b78bd06987c6d3948f8f1804d844) feat: enforce `proc_mem.force_override=never` by default\n* [`681f3e84c`](https://github.com/siderolabs/talos/commit/681f3e84c85677f49ddbcd4a47e325d4a85af692) test: run virtiofs tests only when virtiofsd is running\n* [`0592ff0cd`](https://github.com/siderolabs/talos/commit/0592ff0cdbf54475dc91bfb7c9b9c3047bbe13da) fix: drop the Omni API URL check on IP address\n* [`a4879a5fa`](https://github.com/siderolabs/talos/commit/a4879a5fa2ded9b7b52ff7506b5493ae12939bba) feat: update Linux to 6.18.1\n* [`43b43ff18`](https://github.com/siderolabs/talos/commit/43b43ff189b7e5f37eaa75f4926c26ee21ffa5cb) docs: split talosctl commands into groups\n* [`6d17c18bf`](https://github.com/siderolabs/talos/commit/6d17c18bf908d3cd69ff920d0cff67b653a385f3) feat: enable Powercap and Intel RAPL\n* [`884e76662`](https://github.com/siderolabs/talos/commit/884e76662af34448d9904372f1256f59ce161f99) docs: fix the talosctl cluster create help output\n* [`6dc31be4f`](https://github.com/siderolabs/talos/commit/6dc31be4f982f62ba4aeb1b3b4e65ce022447eb4) fix: exclude new Virtual IPs configured with new config\n* [`94905c73e`](https://github.com/siderolabs/talos/commit/94905c73e93fd7dac38d911dc4264e4d0fe0081d) feat(talosctl): support running qemu x86 on Mac\n* [`f871ab241`](https://github.com/siderolabs/talos/commit/f871ab241c0f034401fbf61e32e7201cced49441) fix: provide json support in `nft` binary\n* [`694f45413`](https://github.com/siderolabs/talos/commit/694f45413fec8cc4f58a79e76034bd4bcec2bbdf) feat: external volumes\n* [`39feb16d2`](https://github.com/siderolabs/talos/commit/39feb16d2ed3bcb65d66483c0729bcec29f7b93e) fix: update containerd 2.2.0 with cgroups patch\n* [`82027eb9b`](https://github.com/siderolabs/talos/commit/82027eb9b30aa128099b27f638098d78857ecb4b) fix: bond configuration with new settings\n* [`121b13b8f`](https://github.com/siderolabs/talos/commit/121b13b8f8d6e5a487971f727c6e028c7ffa20f3) fix: disable kexec on arm64\n* [`7eaa725d0`](https://github.com/siderolabs/talos/commit/7eaa725d0dba18392279f5b43d167aaf18f43b99) fix: selection of boot entry\n* [`949bdb90a`](https://github.com/siderolabs/talos/commit/949bdb90ab2fd711c47583d96bd29a1ca90bbf41) feat: add Secure Boot to CloudStack platform config\n* [`798143a88`](https://github.com/siderolabs/talos/commit/798143a886e4055e764a9ad17cefe8ad4db0572e) fix: discard better klog message from Kubernetes client\n* [`008cd0986`](https://github.com/siderolabs/talos/commit/008cd0986cbbbd5527d91c01b951e311ba014b97) fix: disable kexec in talosctl cluster create on arm64\n* [`bb62b29ed`](https://github.com/siderolabs/talos/commit/bb62b29edb2fb704846ceeed2019f0ebaced30be) chore: prepare talos for 1.13\n* [`c0935030a`](https://github.com/siderolabs/talos/commit/c0935030ac3d966149591a3aaa8e430da768d678) chore: fork reference docs for 1.13.x\n* [`e387e48b3`](https://github.com/siderolabs/talos/commit/e387e48b30b3a3b991f1f611099f48fddefa851b) fix: do not override DNS on MacOS\n* [`1e7e87fb1`](https://github.com/siderolabs/talos/commit/1e7e87fb192521937b581ecd94a0aa0c861f2a5f) fix: rework NFT rules for KubeSpan\n* [`51bcfb567`](https://github.com/siderolabs/talos/commit/51bcfb567915d2b27e4b5321e080220bc618086b) feat: rename image default and source bundle\n* [`585abe944`](https://github.com/siderolabs/talos/commit/585abe94431f06b3ebf4b6a64ad1b5918708f866) feat: update Kubernetes to v1.35.0-rc.1\n* [`f301e3e9b`](https://github.com/siderolabs/talos/commit/f301e3e9ba47d5f46f1990a9bd21fd4e671c38f3) fix: update KubeSpan MSS clamping\n* [`74c1df6f4`](https://github.com/siderolabs/talos/commit/74c1df6f4b2ac8d989d1e42d6c7c0016411638ee) test: propagate MTU size to QEMU in `talosctl cluster create`\n* [`d347ca1af`](https://github.com/siderolabs/talos/commit/d347ca1af162c8d948899d58fc3f76dd0a94f138) fix: update CNI plugins to 1.9.0\n* [`e3f8196b4`](https://github.com/siderolabs/talos/commit/e3f8196b4c767ca68df9f6c85ed25c7e12fb4d87) chore: update Grype and Syft\n* [`e1b8ab323`](https://github.com/siderolabs/talos/commit/e1b8ab3236e956bc4b37e227423aea0f97612a5c) docs: add misssing period\n* [`cd04c3dde`](https://github.com/siderolabs/talos/commit/cd04c3dde70f604603fd7996c62adf5a17cfbd41) docs: update release notes\n* [`fc8ae3249`](https://github.com/siderolabs/talos/commit/fc8ae3249fac82cbdb5521ca8797a8451bdaa9fd) docs: add omni join token example to create qemu command\n* [`9fa00773c`](https://github.com/siderolabs/talos/commit/9fa00773caf2d092d953ff58d04cf94803039b94) chore: update go-blockdevice\n* [`ba13b6786`](https://github.com/siderolabs/talos/commit/ba13b678654e2896e1a99b1af8b51a9239b0a559) fix: correct condition to use UKI cmdline in GRUB\n* [`d2ce3f47f`](https://github.com/siderolabs/talos/commit/d2ce3f47f8515231f27983abaaf269a059e2e90d) docs: drop machine.network example\n* [`cf087c1e0`](https://github.com/siderolabs/talos/commit/cf087c1e01bc1226049a57186f48b2e6b5739c5c) test: bird2 extension\n* [`13df94388`](https://github.com/siderolabs/talos/commit/13df943884a59bd1d42721ba42bcb36349d40624) fix: adapt SELinuxSuite.TestNoPtrace to new strace version\n* [`861787c38`](https://github.com/siderolabs/talos/commit/861787c380bff3ba2fa29f49837bc173a2719578) fix: mark secureboot as supported for metal\n* [`04e3e87ad`](https://github.com/siderolabs/talos/commit/04e3e87adcbd24ee0d82dce4cc27121d34d316f4) fix: clean up kubelet mounts\n* [`21057903a`](https://github.com/siderolabs/talos/commit/21057903a2ca01d88cc5f97c084567d1981f73c5) fix: clear provisioning data on SideroLink config change\n* [`0f9f4c05f`](https://github.com/siderolabs/talos/commit/0f9f4c05ffad9413e1f1533c68eae38dc91c9716) feat: update Kubernetes to 1.35.0-rc.0\n* [`d4309d7b1`](https://github.com/siderolabs/talos/commit/d4309d7b1aec9d2852173fd704b09dfabe2cf217) fix: add a timeout for DNS resolving for NTP\n* [`dd6c1089c`](https://github.com/siderolabs/talos/commit/dd6c1089c8f30d815c80ab10544a0fef27ddd14c) feat: update Linux to 6.18.0\n* [`e9a30bf9a`](https://github.com/siderolabs/talos/commit/e9a30bf9a8ee55ab9ae5d9c9a18362434b0202ad) test: revert add direct connectivity CA rotation test\n* [`cc95562bc`](https://github.com/siderolabs/talos/commit/cc95562bc830496986a395cdde352d48d4a1d146) fix: don't disable LACP by default\n* [`c9fe4679b`](https://github.com/siderolabs/talos/commit/c9fe4679bf9c1dcdf175b95a02f1eaacab4ff085) test: add platform acquire/not valid config unit-test\n* [`5a03a7a20`](https://github.com/siderolabs/talos/commit/5a03a7a20acffa8eedf40524f8d070e37e41f24e) chore: fix longhorn test\n* [`a0cfc3527`](https://github.com/siderolabs/talos/commit/a0cfc3527481c4784edf87c3d7823b10a21d1e4d) feat: implement logs persistence\n* [`51b732bea`](https://github.com/siderolabs/talos/commit/51b732beabc9948e58f9aa4d81b79afb9bd61243) fix: selection of boot entry\n* [`18f8ac369`](https://github.com/siderolabs/talos/commit/18f8ac369ba52f2640508134d3983f006f698129) feat: update Kubernetes to 1.35.0-beta.0\n* [`92fa7c5e4`](https://github.com/siderolabs/talos/commit/92fa7c5e43da96a492003a2c9184cf818fbbb9f0) chore: update pkgs for NVIDIA 580.105.08\n* [`f489299b6`](https://github.com/siderolabs/talos/commit/f489299b603a2aff0f292fa941ae8925fdda3492) chore: correct condition for running k8s integration tests\n* [`ab149750d`](https://github.com/siderolabs/talos/commit/ab149750d475ef059debfc3730e9e0a32ad6e601) chore: update tools/pkgs to 1.13.0-alpha.0\n* [`87ff9f860`](https://github.com/siderolabs/talos/commit/87ff9f8606e04fe99e23261418a762372647b077) test: fix the image-factory test to pass IF endpoint\n* [`2ffe538e7`](https://github.com/siderolabs/talos/commit/2ffe538e7307f0ac3dbac2eba4b36ea98162ec78) test: add direct connectivity CA rotation test\n* [`70f6b80e0`](https://github.com/siderolabs/talos/commit/70f6b80e03acd507580211724cc51b7867bf8a76) chore(ci): skip multipath extension tests\n* [`561cfb60c`](https://github.com/siderolabs/talos/commit/561cfb60c313a9bdc70ed2ff2729549bc8c50fcb) chore: update pkgs and tools version\n* [`2f42202a7`](https://github.com/siderolabs/talos/commit/2f42202a7ccee0e33e43b2081929b5510db5d713) fix: simplify OOM expression\n* [`7b06ae8c2`](https://github.com/siderolabs/talos/commit/7b06ae8c2cf1069cb77cddee0986afc5af837bcc) test: fix flaky LinkSpec/Wireguard test\n* [`e715f3871`](https://github.com/siderolabs/talos/commit/e715f387137fa566a4824c051b624e013a93c49f) feat: present kernel log as `talosctl logs kernel`\n* [`e2ee39b8a`](https://github.com/siderolabs/talos/commit/e2ee39b8ac54ada49dd0a7ffaab4b0ae5d684792) fix: support specifying patch file without '@' symbol\n* [`e202b1f9e`](https://github.com/siderolabs/talos/commit/e202b1f9e82823aa5b31625024bce65bcc53b29f) fix: trim trailing dots from certificate SANs\n* [`7f7079f9c`](https://github.com/siderolabs/talos/commit/7f7079f9c0fbb30ce781aa1223d7df1a175a6206) fix: assign value of multicast setting properly\n* [`eba96141e`](https://github.com/siderolabs/talos/commit/eba96141e0afc147af9a8f1969e207501232b1de) feat: update etcd to 3.6.6\n* [`9945ceef3`](https://github.com/siderolabs/talos/commit/9945ceef37b13bc6e93637dcf395a8c9019e60ed) docs: add API Server Cipher Suites changelog\n* [`9ed488d09`](https://github.com/siderolabs/talos/commit/9ed488d09648c09a9a5c1ed6a5cd245b84cd415d) feat: update TLS cipher suites for API server\n* [`f1c04e4d6`](https://github.com/siderolabs/talos/commit/f1c04e4d6af14243a328d22bf810f27b13d83898) feat: generate mirrors patch\n* [`a89108995`](https://github.com/siderolabs/talos/commit/a89108995ff13fbbef0bf5cbf429cede5ff81078) fix: add CA subject to generated certificate\n* [`35dd612a5`](https://github.com/siderolabs/talos/commit/35dd612a5e59d8781e147fc36eb14f3e8bc66811) fix: add more resilient move\n* [`83675838f`](https://github.com/siderolabs/talos/commit/83675838f3655b44cbd850fd82b4d17acfb00c33) feat: extend flags of cache-cert-gen\n* [`80ab7a064`](https://github.com/siderolabs/talos/commit/80ab7a0643fc8057283a8ba3eb912d0ee453c143) chore: remove spammy 'clean up unused volumes' logs\n* [`74d35900a`](https://github.com/siderolabs/talos/commit/74d35900af0f6451426b70eec3b6db4b72eb993c) chore: disable k8s integration tests for 1GiB worker nodes\n* [`4f6218674`](https://github.com/siderolabs/talos/commit/4f621867407ec8f568f67833172ebaf2ff400346) feat: support TALOS_HOME env var\n* [`0c59b3ea3`](https://github.com/siderolabs/talos/commit/0c59b3ea3f6bc49cef409a1456b4ffa3bf1d28df) feat: add multicast to linkconfig\n* [`6db06f4d5`](https://github.com/siderolabs/talos/commit/6db06f4d5d51abd9e80ead6e4417f0f68856c569) feat: implement multicast setting\n* [`eeded98f5`](https://github.com/siderolabs/talos/commit/eeded98f527a230c65cb041a29fefc5f693d9879) fix: add riscv64 talosctl to release artifacts\n* [`a6bbae91b`](https://github.com/siderolabs/talos/commit/a6bbae91bad56328851fa91e01c17b8af7340b3c) fix: fix typos across the project\n* [`83f2bdb9c`](https://github.com/siderolabs/talos/commit/83f2bdb9ce6c9466716a6ac9c94dc2222e569ee8) feat: support relative voume size\n</p>\n</details>\n\n### Changes since v1.13.0-alpha.1\n<details><summary>44 commits</summary>\n<p>\n\n* [`009f0d6ca`](https://github.com/siderolabs/talos/commit/009f0d6ca0cf13e5778a7c46587ac0dc9d30d5e9) chore: update pkgs\n* [`ba56b0295`](https://github.com/siderolabs/talos/commit/ba56b02954fb275f8ff2ed20e38b51a75c3a8371) feat: include hid-multitouch.ko kernel module in rootfs\n* [`ae29a0dcc`](https://github.com/siderolabs/talos/commit/ae29a0dcce527b90553b25230abbb5a8d4bd504c) feat: update Linux to 6.18.13\n* [`7cf1de279`](https://github.com/siderolabs/talos/commit/7cf1de2794a1d4838efca378aff433fad5e1823c) fix: bring in new version of go-cmd and go-blockdevice\n* [`c8800b41e`](https://github.com/siderolabs/talos/commit/c8800b41e511ce6bb4dda3e28b69c4d091177435) fix: update path handling on talosctl cgroups\n* [`0a7b6eb2c`](https://github.com/siderolabs/talos/commit/0a7b6eb2c98979aa8a604f677c4dd1d54f1285e5) chore: test extensions\n* [`8b1c974a2`](https://github.com/siderolabs/talos/commit/8b1c974a2a733c870f371ccb7a86ccc616dbc7ea) refactor: drop termui-widgets library\n* [`5baa0028e`](https://github.com/siderolabs/talos/commit/5baa0028e65765fc0fd1179f72377bf2a2085deb) fix: add owning inventory annotation to talos manifests\n* [`d3e793d14`](https://github.com/siderolabs/talos/commit/d3e793d14117891103ca4df8507124b18913a56c) fix: stop Kubernetes client from dynamically reloading the certs\n* [`6a5a0e3bd`](https://github.com/siderolabs/talos/commit/6a5a0e3bd4197a4fadfcfe094876e46d4b878a0a) feat: support pattern link aliases\n* [`9758bd4fe`](https://github.com/siderolabs/talos/commit/9758bd4fe0e28803acf11f3b9c9da744883aa9dc) feat: update Go to 1.26\n* [`e00aed0f6`](https://github.com/siderolabs/talos/commit/e00aed0f6694bb3c8e14a0ef413ef0e62ae02981) feat: update Kubernetes v1.36.0-alpha.1\n* [`f20445ad0`](https://github.com/siderolabs/talos/commit/f20445ad0981175d6444340325af5fc747993559) chore: improve logging of disk encryption handling\n* [`f018fbe7b`](https://github.com/siderolabs/talos/commit/f018fbe7ba145ff86ebe0d4d09b323b9715ef1a9) fix: handle raw encryption keys with `\\n` properly\n* [`e5b0eb017`](https://github.com/siderolabs/talos/commit/e5b0eb017ff989e812d6444f668bf17723bb7ec4) fix: hold user volumes root mountpoint\n* [`8a0e79774`](https://github.com/siderolabs/talos/commit/8a0e79774409ce7605f9cd21d769f47e5db656db) refactor: split locate and provision\n* [`a59db0e92`](https://github.com/siderolabs/talos/commit/a59db0e92213296c4c9599fb0d230908caabdf30) fix: improve OpenStack bare metal network configuration reliability\n* [`659009ad8`](https://github.com/siderolabs/talos/commit/659009ad875c0625ac24094dc44020b015ab8b50) fix: remove stale endpoints\n* [`dab0d4783`](https://github.com/siderolabs/talos/commit/dab0d478378dfc6c2862c38633ca4494a41e7ecd) fix: allow static hosts in `/etc/hosts` without hostname\n* [`45f214154`](https://github.com/siderolabs/talos/commit/45f214154cea364d86bfbba81a5ad4f272a4c8fd) feat: update go-kubernetes to use new Myers diff\n* [`35ad0448c`](https://github.com/siderolabs/talos/commit/35ad0448c9ae93cd642d80ebb7d95b768ba0ab9b) fix: switch to better Myers algorithm implementation\n* [`0048464be`](https://github.com/siderolabs/talos/commit/0048464be854d94fb607e38daa83e00767fe8cbc) feat: update etcd to v3.6.8\n* [`5df10f260`](https://github.com/siderolabs/talos/commit/5df10f2604b537504f76b14e028f88a946aacbd7) fix: use mcopy instead of diskfs to populate VFAT\n* [`ce53ffa90`](https://github.com/siderolabs/talos/commit/ce53ffa900a438f6669460a2ce9af874c1f87708) fix: disks flag parsing and handling in create qemu command\n* [`3bd3dd7ca`](https://github.com/siderolabs/talos/commit/3bd3dd7ca92401312079e37584bfbf7942eab93a) fix: memory overuse in imager VFAT\n* [`f118ee47e`](https://github.com/siderolabs/talos/commit/f118ee47eaba662dc161d37fae5ae8f2b3de9819) fix: read multi-doc machine config with newer talosctl\n* [`70c6c2154`](https://github.com/siderolabs/talos/commit/70c6c2154e87d4a6748aebdfa2c50cbc97a0dd89) feat: add filter for KubeSpan advertised networks\n* [`daf18abf4`](https://github.com/siderolabs/talos/commit/daf18abf419b21a6e70dcca0b5b83d33cfee6188) fix: fix talosctl debug in enforcing mode\n* [`33b5b2565`](https://github.com/siderolabs/talos/commit/33b5b25652360a114d0b2cea412bf018cbf84df3) fix: ignore volumes in wave calculation without provisioning\n* [`a16392559`](https://github.com/siderolabs/talos/commit/a16392559a488993c3e26810df57da3cae5c24c5) feat: add explicit service account support to Talos client\n* [`4d531884e`](https://github.com/siderolabs/talos/commit/4d531884e9c28d480f24b61a83f140df0ffbe4b3) chore: update dependencies\n* [`406b8c83c`](https://github.com/siderolabs/talos/commit/406b8c83c9b33b1917b9dd16aa1efeb2df189f0f) feat: update doc links to docs.siderolabs.com\n* [`87615f551`](https://github.com/siderolabs/talos/commit/87615f551183cd322dafebf368a347d928a14442) feat: implement network policies with Flannel CNI\n* [`6995bc1b1`](https://github.com/siderolabs/talos/commit/6995bc1b1ea54e1a8fd6426fef11293f35106ac7) chore: update homebrew formula on release\n* [`7942d5a98`](https://github.com/siderolabs/talos/commit/7942d5a98c1d689a94e78219be09a0fc69d07b08) fix: image gc controller config\n* [`52e8727d0`](https://github.com/siderolabs/talos/commit/52e8727d0112967a62a3d9ae6bf26d713db242e1) feat: add IPv6 GRE support\n* [`9690dbad0`](https://github.com/siderolabs/talos/commit/9690dbad02cfc8682d697679b655e753039c5254) chore: bump tools (including linter)\n* [`2628eb2ec`](https://github.com/siderolabs/talos/commit/2628eb2ece05d7f817fc42e12b979d3f8ca9710c) fix: typo with rpi_5 profile name\n* [`d5ebcd7ca`](https://github.com/siderolabs/talos/commit/d5ebcd7cae1a20c8000e2f4d5a02c81e4dbe5186) fix: stop building talosctl debug on Windows\n* [`8b85c7c63`](https://github.com/siderolabs/talos/commit/8b85c7c637cc08d35bbf6968abebb8c4cdfb82ad) chore: update deps\n* [`d905035b5`](https://github.com/siderolabs/talos/commit/d905035b5e5c7787a5171ba2e0127c89755e8774) fix: swap volume configuration for min/max size\n* [`d43a01ccb`](https://github.com/siderolabs/talos/commit/d43a01ccbdd318080b54e52d2f2fbec93042c458) feat: implement `talosctl debug`\n* [`34a31c979`](https://github.com/siderolabs/talos/commit/34a31c9797d5a7e1700c3d945a21367b81c79385) feat: add mount options support for existing volumes\n* [`1bf95eed1`](https://github.com/siderolabs/talos/commit/1bf95eed185152c38397cd3b43b6ff9d421678c5) feat: improve dashboard uptime display\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>2 commits</summary>\n<p>\n\n* [`9c06846`](https://github.com/siderolabs/discovery-api/commit/9c06846e6f9f4f5765d5e431f8e25dc44a7ff337) feat: change the way excluded addresses are specified\n* [`f71a14a`](https://github.com/siderolabs/discovery-api/commit/f71a14a251c1e267d7a3701342563965947cc76f) feat: add advertised filters to discovery data\n</p>\n</details>\n\n### Changes from siderolabs/go-cmd\n<details><summary>2 commits</summary>\n<p>\n\n* [`5f31ba9`](https://github.com/siderolabs/go-cmd/commit/5f31ba92aa18c3f9a5c39b9f65b6beb9c55c6fac) chore: rekres and update\n* [`fff5698`](https://github.com/siderolabs/go-cmd/commit/fff56983373a4e3e37120fa159444e04a4ef580a) feat: allow capturing full output to stdout, modernize API\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`47fce68`](https://github.com/siderolabs/go-debug/commit/47fce68bb9d064757e11a7a3a81ed1a0b9d7124d) feat: support Go 1.26, rekres\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>5 commits</summary>\n<p>\n\n* [`0a235c0`](https://github.com/siderolabs/go-kubernetes/commit/0a235c069d7d1cbf18a83cf73e23fed3e861a60b) feat: add early support for Kubernetes 1.36\n* [`3bea212`](https://github.com/siderolabs/go-kubernetes/commit/3bea21294056bf7cd894c9fe257eae423e8e2a28) fix: use new Myers diff algorithm\n* [`604c56b`](https://github.com/siderolabs/go-kubernetes/commit/604c56b7251e8ec03b644b47c69ee08d6f25780b) chore: extract common code to the go-kubernetes package\n* [`ec0e3ae`](https://github.com/siderolabs/go-kubernetes/commit/ec0e3aefdeb332f4a44e669c9f7eb877b5f50963) chore: expose more ssa options\n* [`ad2fccd`](https://github.com/siderolabs/go-kubernetes/commit/ad2fccd09d137231f5a8187643782e0e1c661c44) feat: add SSA and pruning support\n</p>\n</details>\n\n### Changes from siderolabs/kms-client\n<details><summary>3 commits</summary>\n<p>\n\n* [`296bf9a`](https://github.com/siderolabs/kms-client/commit/296bf9a1085bd1a8dd06ba81b6969dddf196133c) feat: add logging to the KMS server\n* [`2d6b082`](https://github.com/siderolabs/kms-client/commit/2d6b08285a1506bcc3c866227790f2435c3f0f9c) feat: add TLS support for KMS server\n* [`4233ecd`](https://github.com/siderolabs/kms-client/commit/4233ecd1e8062da6c1131501fa6f2c80a3be686e) chore: bump deps, rekres\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>70 commits</summary>\n<p>\n\n* [`3c982f8`](https://github.com/siderolabs/pkgs/commit/3c982f8df278cf76a7fd421711eaf23bdbf3e948) chore: update deps\n* [`d065c59`](https://github.com/siderolabs/pkgs/commit/d065c5993c5994bc855c2894b5d8ab671c98ee28) feat: update Linux firmware to 20260221\n* [`773ea3a`](https://github.com/siderolabs/pkgs/commit/773ea3a035cf01d01228cb95993dec17df77dd2c) feat: update Linux to 6.18.13\n* [`6ca02b3`](https://github.com/siderolabs/pkgs/commit/6ca02b3129118749b2da47c5cfd6f25c377c0360) fix: make udev rules read only\n* [`520141c`](https://github.com/siderolabs/pkgs/commit/520141cd49b156e3db33496f187360acc85c3e1f) feat: enable kernel irq time accounting\n* [`8f6df51`](https://github.com/siderolabs/pkgs/commit/8f6df518459513a107786b7020df3d9546d64e27) feat: enable CONFIG_HID_MULTITOUCH\n* [`6934b50`](https://github.com/siderolabs/pkgs/commit/6934b5057f6996997420d43fbe620729c8cf22d5) feat: add patch for Cilium BPF verifier rejection by the kernel\n* [`5760aa7`](https://github.com/siderolabs/pkgs/commit/5760aa774e043d121921304863d335db7e9e9adf) feat: enable MLX5 Scalable Functions and TC offload in kernel\n* [`c0c8bc5`](https://github.com/siderolabs/pkgs/commit/c0c8bc56eb19aa4b4246c1813ab284b329ee9ffe) feat: enable CONFIG_DRM_ACCEL and IVPU on amd64\n* [`b9cc39d`](https://github.com/siderolabs/pkgs/commit/b9cc39dcbbfb79141a644e614fb5e62da3fd93aa) feat: build kernel with Clang and ThinLTO, update Go to 1.26\n* [`3327386`](https://github.com/siderolabs/pkgs/commit/33273866b175bd09a1d1bbfd47a41798537cb1b0) chore: drop mellanox-ofed\n* [`9013985`](https://github.com/siderolabs/pkgs/commit/9013985d859828105d9e3cd60c08e44fc4e11d07) feat: update dependencies\n* [`17196f5`](https://github.com/siderolabs/pkgs/commit/17196f595e7347e1f233cf5c9a1f16d90ce4e04d) feat: update NVIDIA LTS to 580.126.16\n* [`8f53ad2`](https://github.com/siderolabs/pkgs/commit/8f53ad27bc7f70f4475cf71cabf7f86b1e20d794) feat: update Linux to 6.18.9\n* [`eff5ba0`](https://github.com/siderolabs/pkgs/commit/eff5ba0d0e720ca4e1e2ed58c0719490b7f6826b) feat: enable ip6_gre\n* [`605ac0d`](https://github.com/siderolabs/pkgs/commit/605ac0d9cbb88be263618a553bbb1be785af2e97) chore: update deps\n* [`7670ff4`](https://github.com/siderolabs/pkgs/commit/7670ff45458bd39f5ca6076ba4eb65f0b68cf2e4) feat: enable NFT_BRIDGE config\n* [`dc737a6`](https://github.com/siderolabs/pkgs/commit/dc737a68c470c9498ec11bde09196809355d2463) chore: update kernel\n* [`9b118b3`](https://github.com/siderolabs/pkgs/commit/9b118b3d0fe7f0df06a069065b86ab307fef3375) chore: update deps\n* [`a63c227`](https://github.com/siderolabs/pkgs/commit/a63c2276eea0013463487cebf95ee35a37c5d9f6) feat: update OpenSSL to v3.6.1\n* [`da7ab57`](https://github.com/siderolabs/pkgs/commit/da7ab5776bd1a6c551bfc6fe5919114721da0e1f) feat: add px-fuse pkg\n* [`553e0fb`](https://github.com/siderolabs/pkgs/commit/553e0fb70f076a8bc53e283253b30ff819e627ff) feat: enable dm-integrity\n* [`15a3cdf`](https://github.com/siderolabs/pkgs/commit/15a3cdf54884d5169895a1ff46682373688ac5e2) feat: update Linux to 6.18.6\n* [`b518a19`](https://github.com/siderolabs/pkgs/commit/b518a196de93dd33e70faaff2342f67acb7dc49b) feat: update dependencies\n* [`1b4fbf5`](https://github.com/siderolabs/pkgs/commit/1b4fbf56b270d5669116fa0d8f91a3b9495e0d97) feat: update GRUB to 2.14\n* [`30bc671`](https://github.com/siderolabs/pkgs/commit/30bc671d4be566ebf60b820edd54000616262e79) fix: enable pinctrl for Raspberry Pi 5\n* [`375983f`](https://github.com/siderolabs/pkgs/commit/375983f4685484a8be5796f815629a9a0d8bd146) feat: update Go to 1.25.6\n* [`d445c80`](https://github.com/siderolabs/pkgs/commit/d445c8076b7dd18b04f48e0a7e5cc2e50b3064d0) feat: update Linux to 6.18.5\n* [`6994400`](https://github.com/siderolabs/pkgs/commit/69944002f9ee681220dcb23031c23ee327e6c1f2) feat: update NVIDIA LTS and production driver versions\n* [`05c3d85`](https://github.com/siderolabs/pkgs/commit/05c3d856b7de6eb64af718d7266a5adf15e1224b) feat: update Linux firmware to 20260110\n* [`c61b466`](https://github.com/siderolabs/pkgs/commit/c61b466e130015b44962e7ef3bc1e9bec935b1df) feat: enable IT87 hwmon module\n* [`ae2572e`](https://github.com/siderolabs/pkgs/commit/ae2572e894a3d8d951418d447ec02f6cc65c8e72) feat: enable IPV6_MROUTE\n* [`d6b503e`](https://github.com/siderolabs/pkgs/commit/d6b503e0fe75d52f83d656a3460cb3614b352e51) feat: add RK3588 NPU Support\n* [`df4b4c8`](https://github.com/siderolabs/pkgs/commit/df4b4c885d4aabf702ce03bcb341f5b5f3641d76) feat: bump deps\n* [`a220898`](https://github.com/siderolabs/pkgs/commit/a2208985bd756ef6366497c5f9768e814b3f7583) feat: add libarchive\n* [`c2371b5`](https://github.com/siderolabs/pkgs/commit/c2371b5582836e27b3e80c4404c4ff5fbed90291) feat: enable ZRAM support\n* [`ab4d169`](https://github.com/siderolabs/pkgs/commit/ab4d169ad93203ba56b0677a10e78eb3e623762e) feat: add a patch to force uid when populating from a directory\n* [`972f44d`](https://github.com/siderolabs/pkgs/commit/972f44d5dae53809ef337544c52c835373439d34) feat: update dependencies\n* [`f8eb5b0`](https://github.com/siderolabs/pkgs/commit/f8eb5b02aaebaf76c59e71f57f4a689dc727e769) feat: update Linux to 6.18.2\n* [`3fb6291`](https://github.com/siderolabs/pkgs/commit/3fb629109a7e5f9650d0e641ff5076a29c319448) feat: update systemd to 259\n* [`59241bd`](https://github.com/siderolabs/pkgs/commit/59241bd58eeb07a18af1c9fc8fffff6365ecca0d) fix: add SBOMs for pigz/igzip\n* [`9377c78`](https://github.com/siderolabs/pkgs/commit/9377c786d112b4181f1e373f6e513130f11b7801) feat: optimize decompression for containerd\n* [`e8e61ce`](https://github.com/siderolabs/pkgs/commit/e8e61cedbbd687ed958db992e05b5d59e4a8ea60) feat: update containerd to 2.2.1\n* [`daa74ba`](https://github.com/siderolabs/pkgs/commit/daa74bab83f91bbc4b6c42625d2953299d5fe20a) feat: support xfs filesystem reproducibility\n* [`1f66513`](https://github.com/siderolabs/pkgs/commit/1f665130fbda76478c261dd54e3843c15027c9cd) feat: update OpenZFS to 2.4.0\n* [`b209af5`](https://github.com/siderolabs/pkgs/commit/b209af5baf1a67472ef431e5a8b7d48022392a1e) chore: rekres with latest changes\n* [`2b806b9`](https://github.com/siderolabs/pkgs/commit/2b806b9b2a7e05b97c2a7e8572e3a8edbd3721d3) feat: bump dependencies\n* [`65242fd`](https://github.com/siderolabs/pkgs/commit/65242fd0fef5c9c923aacce23d1655bad0d1b3e3) feat: enable CONFIG_MISC_RP1 in ARM64 config\n* [`4daecd8`](https://github.com/siderolabs/pkgs/commit/4daecd8e7b8d87110a9e552a60a5394014294e08) feat: update Linux to 6.18.1\n* [`9868a66`](https://github.com/siderolabs/pkgs/commit/9868a66e3c000f505c97ff68e61abac9c9e8e4c9) feat: enable Powercap and Intel RAPL\n* [`07883ee`](https://github.com/siderolabs/pkgs/commit/07883eee3729d4d3adaaebcd825452934c3baebb) feat: build and package perf binary\n* [`47abca0`](https://github.com/siderolabs/pkgs/commit/47abca0852b9555d88eba61661c65a7f93ec3590) fix: add json support to nftables binary\n* [`b961ff8`](https://github.com/siderolabs/pkgs/commit/b961ff898fc9eae68d7f3cea2ca22ff4d0b9c99d) feat: patch containerd 2.2.0 with cgroups fix patch\n* [`b7dd7f6`](https://github.com/siderolabs/pkgs/commit/b7dd7f6c809f670f058b78fd3b84f4cb977771cb) feat: add mstflint module\n* [`ae53351`](https://github.com/siderolabs/pkgs/commit/ae5335198e009da7b06bc0f0d6f42b0947650fc0) feat: update ZFS to 2.4.0-rc5\n* [`b8edf01`](https://github.com/siderolabs/pkgs/commit/b8edf0168171ffc5b87fcd962e37d5c2cd25b687) feat: update CNI plugins to v1.9.0\n* [`a57c1b0`](https://github.com/siderolabs/pkgs/commit/a57c1b0c9d143559a87b64fe9570eec39c14a771) feat: enable amd sev-snp\n* [`68562c1`](https://github.com/siderolabs/pkgs/commit/68562c1b4cdba656287021a1694440b2a7e4d24d) feat: update Linux to 6.18\n* [`6f4ff8c`](https://github.com/siderolabs/pkgs/commit/6f4ff8cc9f57452707588c05e5ca4e80c56548d2) feat: enable Amlogic Meson PCIe controller driver\n* [`c41127b`](https://github.com/siderolabs/pkgs/commit/c41127b94d22b9a5cb6b93f49b546f2ff477410c) feat: enable Intel GPIO/Pinctrl kernel modules\n* [`4a31ff7`](https://github.com/siderolabs/pkgs/commit/4a31ff7dd5c9266b68abded53a7399cb8102f4e3) feat: update NVIDIA LTS to 580.105.08\n* [`3e858d3`](https://github.com/siderolabs/pkgs/commit/3e858d3fa5b2719d8d83397fb89c2ffc91f86615) chore: fork pkgs for Talos 1.13\n* [`dcc5aa1`](https://github.com/siderolabs/pkgs/commit/dcc5aa1e71d6b2e9374d41029a2e6de22dbc61ce) feat: update runc to 1.3.4\n* [`8b6ae5b`](https://github.com/siderolabs/pkgs/commit/8b6ae5b7fc22c3bb2df4bbe31190ff90b0986e6f) fix: regenerate configs\n* [`2992598`](https://github.com/siderolabs/pkgs/commit/29925980896df1978a020505b2b061ffdbd240c7) fix: add missing kernel config entries\n* [`c8ea18a`](https://github.com/siderolabs/pkgs/commit/c8ea18a0873f5b31c54d567ef97d8d05634eb506) feat: rekres to alow multiple commits\n* [`2ddef8b`](https://github.com/siderolabs/pkgs/commit/2ddef8b65755610fc6dbb3f1fb976a6bc572478f) chore: update dependencies\n* [`d1f28e0`](https://github.com/siderolabs/pkgs/commit/d1f28e058972174af9ac819783a69f5f6596b37d) chore: update dependencies\n* [`ab253f5`](https://github.com/siderolabs/pkgs/commit/ab253f521d95b30710e258ebb54adbb7b8de8970) feat: enable gpio-fan module\n* [`0b10666`](https://github.com/siderolabs/pkgs/commit/0b1066635d9dd255bf0ad936e21099fd4bd03f1e) chore: use ubuntu mirrors\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>1 commit</summary>\n<p>\n\n* [`bd9c491`](https://github.com/siderolabs/proto-codec/commit/bd9c491b9e84d7274728ce7e3bde14009f5224bd) chore: bump and update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>17 commits</summary>\n<p>\n\n* [`9de9770`](https://github.com/siderolabs/tools/commit/9de9770aeffac63ebe0cbd9e02ebe8f77b4a9635) feat: update to Go 1.26\n* [`bd4ae8f`](https://github.com/siderolabs/tools/commit/bd4ae8f69c218c05e143a1a04c5710505b8559f2) feat: add LLVM+Clang+LLD toolchain\n* [`90bd70c`](https://github.com/siderolabs/tools/commit/90bd70c94cf434ff45dcd71d1f3d9435b8243093) feat: update dependencies\n* [`decb988`](https://github.com/siderolabs/tools/commit/decb9887929e8d3b3879d56a984244cfe8ae0213) chore: update deps\n* [`ca26e1c`](https://github.com/siderolabs/tools/commit/ca26e1c38cd0a76eb981db4dad2e6caccb0bbe4d) chore: update deps\n* [`0281af0`](https://github.com/siderolabs/tools/commit/0281af0545e17c409fb32d8db61a7d9b0ad8b1c2) feat: update OpenSSL to 3.6.1\n* [`721ad07`](https://github.com/siderolabs/tools/commit/721ad073f18b41407882727a3f0061e594f6c955) feat: update dependencies\n* [`2b3f514`](https://github.com/siderolabs/tools/commit/2b3f514d42a343d98c79a487e80bd4f225a41b70) fix: reproducible build for nasm\n* [`98c699e`](https://github.com/siderolabs/tools/commit/98c699eb624d0846455f08db77cc14e446cb6db9) feat: update Go to 1.25.6\n* [`cd5eb66`](https://github.com/siderolabs/tools/commit/cd5eb66bb0de4fb468a860e176267c3420b4a3a1) chore: run rekres and update dependencies\n* [`896f8b9`](https://github.com/siderolabs/tools/commit/896f8b9c1f88cd190d11b8ef3baa2c36e73d6dfe) fix: add sbom for zlib-ng\n* [`543a16f`](https://github.com/siderolabs/tools/commit/543a16fedf7170d8b015ea1391817328205e629a) feat: replace zlib -> zlib-ng, add nasm\n* [`b67c1a1`](https://github.com/siderolabs/tools/commit/b67c1a168b302539d2082a5513c4a0130c30e4df) chore: rekres with latest changes\n* [`5e087cb`](https://github.com/siderolabs/tools/commit/5e087cbcd158db1ce4f447145bd76a24d07159a1) feat: bump dependencies\n* [`da96a27`](https://github.com/siderolabs/tools/commit/da96a2771801627b4715f7a13199aa6846f87732) chore: rekres to fix reproducibility\n* [`e283ec8`](https://github.com/siderolabs/tools/commit/e283ec8d3831bb19b26938afb10f4955ea563ce2) feat: update Go to 1.25.5\n* [`c38ff0c`](https://github.com/siderolabs/tools/commit/c38ff0c03be69e5cc3795d9dc055896604a3041c) chore: update to 1.13.0-alpha.0 toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**   v1.20.0 -> v1.21.0\n* **github.com/aws/aws-sdk-go-v2/config**            v1.31.20 -> v1.32.7\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**  v1.18.13 -> v1.18.17\n* **github.com/aws/aws-sdk-go-v2/service/acm**       v1.37.19 **_new_**\n* **github.com/aws/aws-sdk-go-v2/service/kms**       v1.46.0 -> v1.49.5\n* **github.com/aws/smithy-go**                       v1.23.2 -> v1.24.0\n* **github.com/containerd/cgroups/v3**               v3.0.5 -> v3.1.2\n* **github.com/containerd/containerd/api**           v1.9.0 -> v1.10.0\n* **github.com/containerd/containerd/v2**            v2.1.5 -> v2.2.1\n* **github.com/containerd/platforms**                v1.0.0-rc.1 -> v1.0.0-rc.2\n* **github.com/cosi-project/runtime**                v1.12.0 -> v1.14.0\n* **github.com/docker/cli**                          v29.0.0 -> v29.2.1\n* **github.com/gdamore/tcell/v2**                    v2.9.0 -> v2.13.8\n* **github.com/godbus/dbus/v5**                      v5.1.0 -> v5.2.2\n* **github.com/google/cadvisor**                     v0.53.0 -> v0.56.2\n* **github.com/google/cel-go**                       v0.26.1 -> v0.27.0\n* **github.com/google/go-containerregistry**         v0.20.6 -> v0.20.7\n* **github.com/google/go-tpm**                       v0.9.7 -> v0.9.8\n* **github.com/hetznercloud/hcloud-go/v2**           v2.30.0 -> v2.36.0\n* **github.com/jsimonetti/rtnetlink/v2**             v2.1.0 -> v2.2.0\n* **github.com/klauspost/compress**                  v1.18.1 -> v1.18.4\n* **github.com/linode/go-metadata**                  v0.2.2 -> v0.2.4\n* **github.com/mdlayher/ethtool**                    v0.4.0 -> v0.5.1\n* **github.com/miekg/dns**                           v1.1.68 -> v1.1.72\n* **github.com/moby/moby/api**                       v1.52.0 -> v1.53.0\n* **github.com/moby/moby/client**                    v0.1.0 -> v0.2.2\n* **github.com/navidys/tvxwidgets**                  v0.13.0 **_new_**\n* **github.com/opencontainers/runtime-spec**         v1.2.1 -> v1.3.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.35 -> v1.0.0-beta.36\n* **github.com/siderolabs/discovery-api**            v0.1.6 -> v0.1.8\n* **github.com/siderolabs/go-blockdevice/v2**        v2.0.20 -> v2.0.25\n* **github.com/siderolabs/go-cmd**                   v0.1.3 -> v0.2.0\n* **github.com/siderolabs/go-debug**                 v0.6.1 -> v0.6.2\n* **github.com/siderolabs/go-kubernetes**            v0.2.28 -> v0.2.32\n* **github.com/siderolabs/kms-client**               v0.1.0 -> v0.2.0\n* **github.com/siderolabs/pkgs**                     v1.12.0-23-ge0b78b8 -> v1.13.0-alpha.0-61-g3c982f8\n* **github.com/siderolabs/proto-codec**              v0.1.2 -> v0.1.3\n* **github.com/siderolabs/talos/pkg/machinery**      v1.12.0 -> 35ad0448c9ae\n* **github.com/siderolabs/tools**                    v1.12.0-2-g7d57df0 -> v1.13.0-alpha.0-16-g9de9770\n* **github.com/sirupsen/logrus**                     v1.9.3 -> v1.9.4\n* **github.com/spf13/cobra**                         v1.10.1 -> v1.10.2\n* **go.etcd.io/etcd/api/v3**                         v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/v3**                      v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.6.6 -> v3.6.7\n* **go.uber.org/zap**                                v1.27.0 -> v1.27.1\n* **go.yaml.in/yaml/v4**                             v4.0.0-rc.3 -> v4.0.0-rc.4\n* **golang.org/x/net**                               v0.47.0 -> v0.50.0\n* **golang.org/x/oauth2**                            v0.33.0 -> v0.35.0\n* **golang.org/x/sync**                              v0.18.0 -> v0.19.0\n* **golang.org/x/sys**                               v0.38.0 -> v0.41.0\n* **golang.org/x/term**                              v0.37.0 -> v0.40.0\n* **golang.org/x/text**                              v0.31.0 -> v0.34.0\n* **google.golang.org/grpc**                         v1.76.0 -> v1.79.1\n* **google.golang.org/protobuf**                     v1.36.10 -> f2248ac996af\n* **sigs.k8s.io/cli-utils**                          77c836a69463 **_new_**\n\nPrevious release can be found at [v1.12.0](https://github.com/siderolabs/talos/releases/tag/v1.12.0)\n\n## [Talos 1.13.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.13.0-alpha.1) (2026-02-03)\n\nWelcome to the v1.13.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Environment Configuration Document\n\nA new `EnvironmentConfig` document has been introduced to allow users to specify environment variables for Talos components.\nIt replaces and deprecates the previous method of setting environment variables via the `.machine.env` field.\n\nMultiple values for the same environment variable will replace previous values, with the last one taking precedence.\n\nTo remove an environment variable, remove it from the `EnvironmentConfig` document and restart the node.\n\n\n### External Volumes\n\nTalos now supports virtiofs-based external volumes via the new\n[ExternalVolumeConfig](https://www.talos.dev/v1.13/reference/configuration/block/externalvolumeconfig/)\ndocument.\n\nThese virtiofs external volumes are not supported when SELinux is running\nin enforcing mode.\n\n\n### Extra Arguments accept slices in addition to strings\n\nSeveral Talos configuration fields that previously accepted single string values for extra arguments have been updated to accept slices of strings as well.\nThis includes fields such as `.cluster.apiServer.extraArgs`.\n\nBREAKING: If you were relying on the resources EtcdConfigs, KubeletConfigs, ControllerManagerConfigs, SchedulerConfigs or APIServerConfigs, the protobuf format has changed from `map<string,string>` to `map<string,message>`.\n\n\n### Talos Imager Enhancements\n\nTalos imager now supports running rootless. `--privileged` and `-v /dev:/dev` are no longer required.\n\n\n### Talosctl images k8s-bundle subcommand accepts version parameter\n\nThe `talosctl images k8s-bundle` command now accepts an optional version overrides arguments.\n\n\n### Kubernetes server-side apply\n\nTalos now uses inventory backed server-side apply when applying bootsrap manifests (including `extraManifests` and `inlineManifests`).\nPurging of unneeded manifests is automatically performed.\nThe switch and inventory backfill is automatic and no action is needed from the user.\n\n\n### KubeSpan Configuration\n\nA new `KubeSpanConfig` document has been introduced to configure KubeSpan settings.\nIt replaces and deprecates the previous method of configuring KubeSpan via the `.machine.network.kubespan` field.\n\nThe old configuration field will continue to work for backward compatibility.\n\n\n### Negative Max Volume Size\n\nNegative max size represents the amount of space to be left free on the device, rather than the size the volume should consume.\nFor example:\n    * a max size of \"-10GiB\" means the volume can grow to the available space minus 10GiB.\n    * a max size of \"-25%\" means the volume can grow to the available space minus 25%.\n\n\n### Container Image Decompression\n\nTalos now ships with `igzip` (amd64) and `pigz` (arm64) to speed up container image decompression.\n\n\n### ProbeConfig\n\nThe TCPProbeConfig configuration document allows to configure TCP probes for network reachability checks.\nThis allows to define a custom connectivity condition.\n\n\n### /proc/PID/mem Access Hardening\n\nA new kernel parameter `proc_mem.force_override=never` has been introduced by default to enhance system security\nby preventing unwanted writes to protected process memory via `/proc/PID/mem`.\nIf the kernel parameter is removed, default behavior is restored, allowing access only if the process is traced.\n\n\n### Reproducible Disk Images\n\nTalos disk images are now reproducible. Building the same version of Talos multiple times will yield\nidentical disk images.\n\nNote: VHD and VMDK (Azure and VMware) images are not currently reproducible due to limitations in the underlying image creation tools.\nUsers verifying reproducible images should use raw images, verify checksums, and convert them to VHD/VMDK as needed.\n\n\n### ResolverConfig\n\nThe nameservers configuration in machine configuration now overwrites any previous layers (defaults, platform, etc.) when specified.\nPreviously a smart merge was performed to keep IPv4/IPv6 nameservers from lower layers if the machine configuration specified only one type.\n\n\n### Service Account Issuer configuration\n\nIn API Server, passing extra args with `service-account-issuer` will append them after default value.\nThis allows easy migration, e.g. by changing `.cluster.controlPlane.endpoint` to new value, and keeping the old value in\n`.cluster.apiServer.extraArgs[\"service-account-issuer\"]`.\n\n\n### `talosctl images talos-bundle` can ignore reaching to the registry\n\nThe `talosctl images talos-bundle` command now accepts optional `--overlays` and `--extensions` flags.\nIf those are set to `false`, the command will not attempt to reach out to the container registry to fetch the latest versions and digests of the overlays and extensions.\n\n\n### Component Updates\n\nLinux: 6.18.8\ncontainerd: 2.2.1\netcd: 3.6.7\nCoreDNS: 1.13.2\nKubernetes: 1.35.0\nFlannel CNI plugin: v1.9.0-flannel1\nLVM2: 2_03_38\nrunc: 1.4.0\nsystemd: 259\ncryptsetup: 2.8.3\n\nTalos is built with Go 1.25.6.\n\n\n### VM Hot-Add Support\n\nTalos now includes udev rules to support hot-adding of CPUs in virtualized environments.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Mateusz Urbanek\n* Noel Georgi\n* Dmitrii Sharshakov\n* Orzelius\n* Laura Brehm\n* Bryan Lee\n* Edward Sammut Alessi\n* Alexis La Goutte\n* Andras BALI\n* Andrei Kvapil\n* Artem Chernyshev\n* Birger Johan Nordølum\n* Camillo Rossi\n* Christopher Puschmann\n* Florian Ströger\n* Gregor Gruener\n* Jaakko Sirén\n* Jean-Francois Roy\n* Joakim Nohlgård\n* Jonas Lammler\n* Justin Garrison\n* Lennard Klein\n* Matthew Sanabria\n* Max Makarov\n* Michal Baumgartner\n* Mickaël Canévet\n* Olav Thoresen\n* Pranav Patil\n* Serge van Ginderachter\n* Skye Soss\n* Spencer Smith\n* Tim Jones\n* dataprolet\n* eseiker\n* pranav767\n\n### Changes\n<details><summary>176 commits</summary>\n<p>\n\n* [`900516e68`](https://github.com/siderolabs/talos/commit/900516e68950e4b94696f6a9b481cefee44b3360) chore: update image signer\n* [`938de566e`](https://github.com/siderolabs/talos/commit/938de566eca30af3cc4355a94931186f19b682f2) feat: bump kernel\n* [`388cec727`](https://github.com/siderolabs/talos/commit/388cec72796d0ecd0c7103efcaab9066e9b62509) feat(overlays): add new overlays\n* [`9f2dd6312`](https://github.com/siderolabs/talos/commit/9f2dd6312f9d49e4d03347c98b100119f94cf807) refactor: api tests\n* [`a90783146`](https://github.com/siderolabs/talos/commit/a90783146fc2d475055bfce0f8b5120969f74dc7) feat: add a helper module to generate standard patches\n* [`1fec5b23d`](https://github.com/siderolabs/talos/commit/1fec5b23d0c10e53863a7c0f89f862708a7f4069) fix: implement merger for PercentageSize\n* [`8b245b8f2`](https://github.com/siderolabs/talos/commit/8b245b8f269b6c8cb463f2cf537d2ed2ab6924ec) feat: implement new image service APIs\n* [`d90c775b8`](https://github.com/siderolabs/talos/commit/d90c775b8441705003de3427b2e6831dcbfb449f) chore: rename internal `talosctl debug air-gapped`\n* [`2165280d0`](https://github.com/siderolabs/talos/commit/2165280d0eedf59899ad44e2f3289d81b3dab466) refactor: change the way one2many proxying is picked\n* [`b1b703dbe`](https://github.com/siderolabs/talos/commit/b1b703dbe2b25785ded0c77f23d674d9b9934975) chore: move sync logging code to go-kubernetes package\n* [`e48c6d7ab`](https://github.com/siderolabs/talos/commit/e48c6d7ab9c8a2e28ebe2115ac09f1557bbcca33) fix: allow to expose a port multiple times in Docker\n* [`410d8cb57`](https://github.com/siderolabs/talos/commit/410d8cb5727ccf054c9097f33bc916d87076a599) fix: undo CRLF on Windows (talosctl edit)\n* [`859d3f03c`](https://github.com/siderolabs/talos/commit/859d3f03c444d98b94a06adac3648562e3b1228b) feat: add RPi5 to the list of supported SBCs\n* [`0bd48bbc6`](https://github.com/siderolabs/talos/commit/0bd48bbc6f365770167ee753be563eb4179fcadb) fix(talosctl): pass --k8s-endpoint flag to rotate-ca kubernetes rotation\n* [`b9e27ebe7`](https://github.com/siderolabs/talos/commit/b9e27ebe72c4302c416fd8efb007c3966004ddd6) feat: update Linux kernel with dm-integrity\n* [`6aa9b0677`](https://github.com/siderolabs/talos/commit/6aa9b0677ed7ca4955fead474e36a533b3250ad9) fix: skip empty documents on config decoding\n* [`494492489`](https://github.com/siderolabs/talos/commit/494492489b29b615a8a874c0648690ed3b9adb58) fix: always set advertised peer URLs\n* [`782cc507d`](https://github.com/siderolabs/talos/commit/782cc507dc33c87caa5ff985eea5f4439c3e1012) fix: open the filesystem as read-only\n* [`28e61a740`](https://github.com/siderolabs/talos/commit/28e61a740a906fadfea098f38a9c9f4e8c32773e) fix: set GRUB prefix correctly on arm64\n* [`a4f1c5239`](https://github.com/siderolabs/talos/commit/a4f1c5239ef7227856640c230e0d0364d9eedbd2) feat: update GRUB to 2.14\n* [`562920701`](https://github.com/siderolabs/talos/commit/562920701e2999cbb6687e55de96719aba4064fd) fix: use node podCIDRs for kubespan advertiseKubernetesNetworks\n* [`39460365c`](https://github.com/siderolabs/talos/commit/39460365c1726095e20cf3cc7c079c234b8022d6) feat: implement layering for ProbeSpec\n* [`b5c760f70`](https://github.com/siderolabs/talos/commit/b5c760f7076570bc04be02af0ea493f95d8338d0) feat: add ProbeConfig for network connectivity probes\n* [`4b274f761`](https://github.com/siderolabs/talos/commit/4b274f76159495cc6c2977ec3bbade71e35aade8) feat: support aws cert manager in imager\n* [`417209512`](https://github.com/siderolabs/talos/commit/41720951251102f1c174e501a3103e55720a1d8b) fix: fallback to /proc/meminfo for memory modules\n* [`7f1147bed`](https://github.com/siderolabs/talos/commit/7f1147bed495a06d336f5be1da6073921b5e52dc) fix: add warnings to 802.3ad bond\n* [`ddd6b186e`](https://github.com/siderolabs/talos/commit/ddd6b186eb8f527324736576182dafbce3423da5) refactor: generate GRUB images\n* [`c7aa266ea`](https://github.com/siderolabs/talos/commit/c7aa266ea5c9d3fbd465dc651f2ebfec622612e7) fix: overwrite resolver config with machine config\n* [`cf70f05fa`](https://github.com/siderolabs/talos/commit/cf70f05fa40312c30d8345c2fb15ce8eda86a7a7) fix: oracle platform file format\n* [`8c7b8f5b7`](https://github.com/siderolabs/talos/commit/8c7b8f5b7d6dec144f7985a7c8a8a582c38f3154) feat: add support for negative max size\n* [`77bc3d21f`](https://github.com/siderolabs/talos/commit/77bc3d21fa40e188af4b5dd93e1cda289e858d56) fix: marshal of FailOverMac property\n* [`38e280c93`](https://github.com/siderolabs/talos/commit/38e280c9319ef1ecb1455b3cc8b8d0d1d7426ccd) fix: make OOM expression a bit less sensitive\n* [`3d1301640`](https://github.com/siderolabs/talos/commit/3d1301640d44d58303160400e4954c36f53341f9) fix: wipe the first/last 1MiB in addition to wiping by signatures\n* [`1aa6528ad`](https://github.com/siderolabs/talos/commit/1aa6528adcddfb6a5ed66cc26cac1a0fcdb37516) fix: make OOM controller more precise by considering separate cgroup PSI\n* [`f7072c050`](https://github.com/siderolabs/talos/commit/f7072c050e607de16781a65eb97ab2a1828b05fb) fix: check if the device is not mounted when wiping\n* [`743c3b94b`](https://github.com/siderolabs/talos/commit/743c3b94b958e4abcbf70d4064f2ae0e0bbb0712) fix: use correct containerd import path\n* [`f2dd08594`](https://github.com/siderolabs/talos/commit/f2dd08594e8e474c7b3891dc46c64f27c724dbc0) feat: report image pull progress in the console\n* [`72fe98a06`](https://github.com/siderolabs/talos/commit/72fe98a06f31536454f201d703f8ae6a071235b5) fix: boot with GRUB\n* [`d4ed13d93`](https://github.com/siderolabs/talos/commit/d4ed13d9394b087e8877eba25950f344894803a1) fix: add talos version to Hetzner Cloud client user agent\n* [`150c41c30`](https://github.com/siderolabs/talos/commit/150c41c30ed3f066f10bd2bdc2afa9b2c5a97597) feat: update Linux to 6.18.5\n* [`01a367891`](https://github.com/siderolabs/talos/commit/01a3678913de0fa4d309a361428c117d24ce0d1e) fix: use append instead of prepend in service-account-issuer\n* [`d1954278a`](https://github.com/siderolabs/talos/commit/d1954278a1ba3470b2e5ccae90762078c18d69e9) feat: add extraArgs from service-account-issuer\n* [`91b88f7f9`](https://github.com/siderolabs/talos/commit/91b88f7f994cccad15cbec1aa8019bd19b84ae91) feat: support multiple values for extraArgs\n* [`96e604874`](https://github.com/siderolabs/talos/commit/96e604874b17e7aa8b62bfb25737f349e539bc5a) fix: add hostname to endpoints\n* [`7033275a7`](https://github.com/siderolabs/talos/commit/7033275a7a22d51e83c9e760ba37d2ad6ab22f28) refactor: move BootloaderKind into machinery\n* [`71adaf0ea`](https://github.com/siderolabs/talos/commit/71adaf0ea5b558c8a16e2acfdec3671611455985) fix: sort mirrors and tls configs when generating the machine config\n* [`34f09a300`](https://github.com/siderolabs/talos/commit/34f09a3004fe1b77c16dd33b04adca95fb6876a5) feat: add VLAN support to OpenStack platform\n* [`5127ef7c2`](https://github.com/siderolabs/talos/commit/5127ef7c28b360f9c7c033f77c58cef729e5278d) fix: wipe disk by signatures\n* [`415bfaedb`](https://github.com/siderolabs/talos/commit/415bfaedb6ae8d42b5927fdc5b7cfe8aa781a791) fix: panic in configpatcher when the whole section is missing\n* [`e5aca71cd`](https://github.com/siderolabs/talos/commit/e5aca71cd0557557e50c39d82eda2c938f627d62) fix: fix healthcheck timeout\n* [`634b71e2d`](https://github.com/siderolabs/talos/commit/634b71e2d028bf13d838acad8809c95384b6eed9) docs: move talosctl pcap example to Example Block\n* [`818492731`](https://github.com/siderolabs/talos/commit/8184927316c5de7d9b04f21474a60cc791c3d26d) feat: implement KubeSpan multi-document configuration\n* [`4d0604b9d`](https://github.com/siderolabs/talos/commit/4d0604b9d93851f444a00dbd84fcac76d21d35c2) chore: remove unrelated machineconfig\n* [`e36863470`](https://github.com/siderolabs/talos/commit/e36863470b14496c3d84417e63fef45e6060603b) feat: add it87 hwmon module\n* [`308c75090`](https://github.com/siderolabs/talos/commit/308c75090774d2510c2ec08e63e179a5c0fa6987) fix: resolve SideroLink Wireguard endpoint on reconnect\n* [`e4ef494de`](https://github.com/siderolabs/talos/commit/e4ef494decdf97664c4803aa3861015fce49760e) fix: drop the persist config flag from gen config\n* [`c3176adcf`](https://github.com/siderolabs/talos/commit/c3176adcf981811a326c971c81c4b591f54e116a) feat: add EnvironmentConfig document\n* [`c839b3880`](https://github.com/siderolabs/talos/commit/c839b38809b3a0029061d43477555ec31e283aa5) feat: expose more SSA options in the upgrade-k8s command\n* [`b8ff9677e`](https://github.com/siderolabs/talos/commit/b8ff9677e4f9a64908ae00bb1d80aa2442a00a60) fix: handle correctly incomplete RegistryTLSConfig\n* [`99f2ddada`](https://github.com/siderolabs/talos/commit/99f2ddada895011036af1435dd10bac3be0a9171) fix: bond config via platform\n* [`2449ffea4`](https://github.com/siderolabs/talos/commit/2449ffea45304459ea8895b535b6f070a9249172) fix: allow HostnameConfig to be used with incomplete machine config\n* [`35fc52087`](https://github.com/siderolabs/talos/commit/35fc5208728dbc3e0b139aff4c06f25208445637) fix: lock down etcd listen address to IPv4 localhost\n* [`27253d731`](https://github.com/siderolabs/talos/commit/27253d7317a473cbbc0f5c0eee634173bdd2eda7) feat: use new xfs config file\n* [`c9d84ae21`](https://github.com/siderolabs/talos/commit/c9d84ae21e203529a6952c165ff04d602a2a6ad6) fix: generate OCI-compliant image config\n* [`7a4b2b33a`](https://github.com/siderolabs/talos/commit/7a4b2b33abe8a3011f37f0a8f4848dd846d0396f) fix: update VIP config example\n* [`080efcbda`](https://github.com/siderolabs/talos/commit/080efcbda2c4334f9d8c70804a5a37f0cdb2df2d) feat: add k8s-version parameter to k8s-bundle\n* [`b764f5f72`](https://github.com/siderolabs/talos/commit/b764f5f724bf8af3acaac74942ea91a86e593322) fix: skip sync test when kube-proxy is disabled\n* [`70e67787d`](https://github.com/siderolabs/talos/commit/70e67787d6d34d93a34871b2d25d64f6a7575d76) feat: imager: populate filesystems with root owned files\n* [`7416dca59`](https://github.com/siderolabs/talos/commit/7416dca59378dc282e42ea30107cf40326cc593c) fix: print talosctl images to release notes\n* [`dc2009e47`](https://github.com/siderolabs/talos/commit/dc2009e4779684a6a4252d4dfd2aa02d1b60c2da) chore: use context when creating filesystems\n* [`85f7be6e3`](https://github.com/siderolabs/talos/commit/85f7be6e3f14bf160cf32bccf7418b31968d474f) chore: update slack links\n* [`154952175`](https://github.com/siderolabs/talos/commit/154952175ab73ac65722732b146a0ee1c56b2f4d) fix: disable swap for system services\n* [`d98b415af`](https://github.com/siderolabs/talos/commit/d98b415afea7b1820153151c0273df24a101742e) fix: drop more non-overlay SBC stuff\n* [`226cd6bc1`](https://github.com/siderolabs/talos/commit/226cd6bc1d70662cb7f7736ac6fad117170a36fb) fix: do not allocate for the actual disk image file\n* [`53f5bf8d2`](https://github.com/siderolabs/talos/commit/53f5bf8d2c97e91bee06bcb5948170015486ea77) fix: overlay installers\n* [`10d0cfd93`](https://github.com/siderolabs/talos/commit/10d0cfd93a083fb8b71b7c0297df52feb55e044b) fix: overlay install in image mode\n* [`77086694d`](https://github.com/siderolabs/talos/commit/77086694d18b69802e542156fc12cd7cf066efc2) fix: partition data population\n* [`4d5657b1a`](https://github.com/siderolabs/talos/commit/4d5657b1a34c939b63b2cc3ee11ed45ad1bf23c3) fix: drop SBC board code\n* [`c4f3f6d3e`](https://github.com/siderolabs/talos/commit/c4f3f6d3e59b58016ba8546c5bd3e8e465fbbf52) feat: implement kubernetes server-side apply\n* [`f12fd2b0a`](https://github.com/siderolabs/talos/commit/f12fd2b0a9fdf8f53ec5714d3ad18b695973e0b0) test: bump Image Factory tests\n* [`c76484e58`](https://github.com/siderolabs/talos/commit/c76484e5879a7e48197e442cf22044d3d0363846) release(v1.13.0-alpha.0): prepare release\n* [`f0d8a6851`](https://github.com/siderolabs/talos/commit/f0d8a685173354e5fd148786872062a342c4282a) test: skip the source bundle on exact tag\n* [`c57701d65`](https://github.com/siderolabs/talos/commit/c57701d6590388e7d6418af67e8237c7d60ccf54) fix: remove interactive installer\n* [`43937c1cd`](https://github.com/siderolabs/talos/commit/43937c1cd42758a15026261fe8f0e06daaebdcbd) feat: update Linux and systemd\n* [`72a194df8`](https://github.com/siderolabs/talos/commit/72a194df88f2800cee3372241fbad419b07f7bbf) feat: add VM CPU hot-add rules\n* [`f09ae1e0d`](https://github.com/siderolabs/talos/commit/f09ae1e0d2e1b7842d504b594b71a325af7733e5) fix: probe small images correctly\n* [`8f2b33799`](https://github.com/siderolabs/talos/commit/8f2b337994fdeff76a0ae9e1730b4b9f596ff1bb) feat: imager support rootless builds\n* [`c7525a97e`](https://github.com/siderolabs/talos/commit/c7525a97ef8615e903be183d7938b6d2a3b89464) feat: support creating filesystems from folder\n* [`e2bffb5ce`](https://github.com/siderolabs/talos/commit/e2bffb5cebaaf28f9dfff24f41ecbb2809fc60e5) chore: refactor imager code so it's more clear\n* [`0fb50dbd0`](https://github.com/siderolabs/talos/commit/0fb50dbd0a5b7b80187e50d501cec4b3fe434dc2) fix: invalid versions check in talos-bundle\n* [`b5dd56032`](https://github.com/siderolabs/talos/commit/b5dd5603207a46d8eed240173f06aeffd6a9c0e7) test: upgrade versions in upgrade tests\n* [`3dfa4d6e4`](https://github.com/siderolabs/talos/commit/3dfa4d6e40dcae2db47e89443568be3ae48b3ae1) fix: make upgrade work with SELinux enforcing=1\n* [`786c8e2ee`](https://github.com/siderolabs/talos/commit/786c8e2ee757c2d7b30d5bded954e584af3a058e) feat: ship pigz/igzip in rootfs to speed up image decompression\n* [`48d242918`](https://github.com/siderolabs/talos/commit/48d242918bc97e6a01434bee6fcdcfa735fd1f5a) feat: update containerd to 2.2.1\n* [`536541afe`](https://github.com/siderolabs/talos/commit/536541afe497d5f61cfcd0c01cf580ab5b3be164) fix: mount volume mount/unmount race\n* [`39117d457`](https://github.com/siderolabs/talos/commit/39117d45766b139ed6a0c1290f757e4b26d31d92) feat: update dependencies\n* [`f0f420725`](https://github.com/siderolabs/talos/commit/f0f420725c6a4f628cdc1b80d59713c375beb9b7) fix: bond setting change detection\n* [`8d6a7a867`](https://github.com/siderolabs/talos/commit/8d6a7a8677a5d1d61432fa94ca030351fd9852f2) feat: update Kubernetes to 1.35.0\n* [`845a0d09c`](https://github.com/siderolabs/talos/commit/845a0d09cd770a15db762ddda4d3d27f58656cfe) feat: update etcd 3.6.7, CoreDNS 1.13.2\n* [`b95912e04`](https://github.com/siderolabs/talos/commit/b95912e04907b78bd06987c6d3948f8f1804d844) feat: enforce `proc_mem.force_override=never` by default\n* [`681f3e84c`](https://github.com/siderolabs/talos/commit/681f3e84c85677f49ddbcd4a47e325d4a85af692) test: run virtiofs tests only when virtiofsd is running\n* [`0592ff0cd`](https://github.com/siderolabs/talos/commit/0592ff0cdbf54475dc91bfb7c9b9c3047bbe13da) fix: drop the Omni API URL check on IP address\n* [`a4879a5fa`](https://github.com/siderolabs/talos/commit/a4879a5fa2ded9b7b52ff7506b5493ae12939bba) feat: update Linux to 6.18.1\n* [`43b43ff18`](https://github.com/siderolabs/talos/commit/43b43ff189b7e5f37eaa75f4926c26ee21ffa5cb) docs: split talosctl commands into groups\n* [`6d17c18bf`](https://github.com/siderolabs/talos/commit/6d17c18bf908d3cd69ff920d0cff67b653a385f3) feat: enable Powercap and Intel RAPL\n* [`884e76662`](https://github.com/siderolabs/talos/commit/884e76662af34448d9904372f1256f59ce161f99) docs: fix the talosctl cluster create help output\n* [`6dc31be4f`](https://github.com/siderolabs/talos/commit/6dc31be4f982f62ba4aeb1b3b4e65ce022447eb4) fix: exclude new Virtual IPs configured with new config\n* [`94905c73e`](https://github.com/siderolabs/talos/commit/94905c73e93fd7dac38d911dc4264e4d0fe0081d) feat(talosctl): support running qemu x86 on Mac\n* [`f871ab241`](https://github.com/siderolabs/talos/commit/f871ab241c0f034401fbf61e32e7201cced49441) fix: provide json support in `nft` binary\n* [`694f45413`](https://github.com/siderolabs/talos/commit/694f45413fec8cc4f58a79e76034bd4bcec2bbdf) feat: external volumes\n* [`39feb16d2`](https://github.com/siderolabs/talos/commit/39feb16d2ed3bcb65d66483c0729bcec29f7b93e) fix: update containerd 2.2.0 with cgroups patch\n* [`82027eb9b`](https://github.com/siderolabs/talos/commit/82027eb9b30aa128099b27f638098d78857ecb4b) fix: bond configuration with new settings\n* [`121b13b8f`](https://github.com/siderolabs/talos/commit/121b13b8f8d6e5a487971f727c6e028c7ffa20f3) fix: disable kexec on arm64\n* [`7eaa725d0`](https://github.com/siderolabs/talos/commit/7eaa725d0dba18392279f5b43d167aaf18f43b99) fix: selection of boot entry\n* [`949bdb90a`](https://github.com/siderolabs/talos/commit/949bdb90ab2fd711c47583d96bd29a1ca90bbf41) feat: add Secure Boot to CloudStack platform config\n* [`798143a88`](https://github.com/siderolabs/talos/commit/798143a886e4055e764a9ad17cefe8ad4db0572e) fix: discard better klog message from Kubernetes client\n* [`008cd0986`](https://github.com/siderolabs/talos/commit/008cd0986cbbbd5527d91c01b951e311ba014b97) fix: disable kexec in talosctl cluster create on arm64\n* [`bb62b29ed`](https://github.com/siderolabs/talos/commit/bb62b29edb2fb704846ceeed2019f0ebaced30be) chore: prepare talos for 1.13\n* [`c0935030a`](https://github.com/siderolabs/talos/commit/c0935030ac3d966149591a3aaa8e430da768d678) chore: fork reference docs for 1.13.x\n* [`e387e48b3`](https://github.com/siderolabs/talos/commit/e387e48b30b3a3b991f1f611099f48fddefa851b) fix: do not override DNS on MacOS\n* [`1e7e87fb1`](https://github.com/siderolabs/talos/commit/1e7e87fb192521937b581ecd94a0aa0c861f2a5f) fix: rework NFT rules for KubeSpan\n* [`51bcfb567`](https://github.com/siderolabs/talos/commit/51bcfb567915d2b27e4b5321e080220bc618086b) feat: rename image default and source bundle\n* [`585abe944`](https://github.com/siderolabs/talos/commit/585abe94431f06b3ebf4b6a64ad1b5918708f866) feat: update Kubernetes to v1.35.0-rc.1\n* [`f301e3e9b`](https://github.com/siderolabs/talos/commit/f301e3e9ba47d5f46f1990a9bd21fd4e671c38f3) fix: update KubeSpan MSS clamping\n* [`74c1df6f4`](https://github.com/siderolabs/talos/commit/74c1df6f4b2ac8d989d1e42d6c7c0016411638ee) test: propagate MTU size to QEMU in `talosctl cluster create`\n* [`d347ca1af`](https://github.com/siderolabs/talos/commit/d347ca1af162c8d948899d58fc3f76dd0a94f138) fix: update CNI plugins to 1.9.0\n* [`e3f8196b4`](https://github.com/siderolabs/talos/commit/e3f8196b4c767ca68df9f6c85ed25c7e12fb4d87) chore: update Grype and Syft\n* [`e1b8ab323`](https://github.com/siderolabs/talos/commit/e1b8ab3236e956bc4b37e227423aea0f97612a5c) docs: add misssing period\n* [`cd04c3dde`](https://github.com/siderolabs/talos/commit/cd04c3dde70f604603fd7996c62adf5a17cfbd41) docs: update release notes\n* [`fc8ae3249`](https://github.com/siderolabs/talos/commit/fc8ae3249fac82cbdb5521ca8797a8451bdaa9fd) docs: add omni join token example to create qemu command\n* [`9fa00773c`](https://github.com/siderolabs/talos/commit/9fa00773caf2d092d953ff58d04cf94803039b94) chore: update go-blockdevice\n* [`ba13b6786`](https://github.com/siderolabs/talos/commit/ba13b678654e2896e1a99b1af8b51a9239b0a559) fix: correct condition to use UKI cmdline in GRUB\n* [`d2ce3f47f`](https://github.com/siderolabs/talos/commit/d2ce3f47f8515231f27983abaaf269a059e2e90d) docs: drop machine.network example\n* [`cf087c1e0`](https://github.com/siderolabs/talos/commit/cf087c1e01bc1226049a57186f48b2e6b5739c5c) test: bird2 extension\n* [`13df94388`](https://github.com/siderolabs/talos/commit/13df943884a59bd1d42721ba42bcb36349d40624) fix: adapt SELinuxSuite.TestNoPtrace to new strace version\n* [`861787c38`](https://github.com/siderolabs/talos/commit/861787c380bff3ba2fa29f49837bc173a2719578) fix: mark secureboot as supported for metal\n* [`04e3e87ad`](https://github.com/siderolabs/talos/commit/04e3e87adcbd24ee0d82dce4cc27121d34d316f4) fix: clean up kubelet mounts\n* [`21057903a`](https://github.com/siderolabs/talos/commit/21057903a2ca01d88cc5f97c084567d1981f73c5) fix: clear provisioning data on SideroLink config change\n* [`0f9f4c05f`](https://github.com/siderolabs/talos/commit/0f9f4c05ffad9413e1f1533c68eae38dc91c9716) feat: update Kubernetes to 1.35.0-rc.0\n* [`d4309d7b1`](https://github.com/siderolabs/talos/commit/d4309d7b1aec9d2852173fd704b09dfabe2cf217) fix: add a timeout for DNS resolving for NTP\n* [`dd6c1089c`](https://github.com/siderolabs/talos/commit/dd6c1089c8f30d815c80ab10544a0fef27ddd14c) feat: update Linux to 6.18.0\n* [`e9a30bf9a`](https://github.com/siderolabs/talos/commit/e9a30bf9a8ee55ab9ae5d9c9a18362434b0202ad) test: revert add direct connectivity CA rotation test\n* [`cc95562bc`](https://github.com/siderolabs/talos/commit/cc95562bc830496986a395cdde352d48d4a1d146) fix: don't disable LACP by default\n* [`c9fe4679b`](https://github.com/siderolabs/talos/commit/c9fe4679bf9c1dcdf175b95a02f1eaacab4ff085) test: add platform acquire/not valid config unit-test\n* [`5a03a7a20`](https://github.com/siderolabs/talos/commit/5a03a7a20acffa8eedf40524f8d070e37e41f24e) chore: fix longhorn test\n* [`a0cfc3527`](https://github.com/siderolabs/talos/commit/a0cfc3527481c4784edf87c3d7823b10a21d1e4d) feat: implement logs persistence\n* [`51b732bea`](https://github.com/siderolabs/talos/commit/51b732beabc9948e58f9aa4d81b79afb9bd61243) fix: selection of boot entry\n* [`18f8ac369`](https://github.com/siderolabs/talos/commit/18f8ac369ba52f2640508134d3983f006f698129) feat: update Kubernetes to 1.35.0-beta.0\n* [`92fa7c5e4`](https://github.com/siderolabs/talos/commit/92fa7c5e43da96a492003a2c9184cf818fbbb9f0) chore: update pkgs for NVIDIA 580.105.08\n* [`f489299b6`](https://github.com/siderolabs/talos/commit/f489299b603a2aff0f292fa941ae8925fdda3492) chore: correct condition for running k8s integration tests\n* [`ab149750d`](https://github.com/siderolabs/talos/commit/ab149750d475ef059debfc3730e9e0a32ad6e601) chore: update tools/pkgs to 1.13.0-alpha.0\n* [`87ff9f860`](https://github.com/siderolabs/talos/commit/87ff9f8606e04fe99e23261418a762372647b077) test: fix the image-factory test to pass IF endpoint\n* [`2ffe538e7`](https://github.com/siderolabs/talos/commit/2ffe538e7307f0ac3dbac2eba4b36ea98162ec78) test: add direct connectivity CA rotation test\n* [`70f6b80e0`](https://github.com/siderolabs/talos/commit/70f6b80e03acd507580211724cc51b7867bf8a76) chore(ci): skip multipath extension tests\n* [`561cfb60c`](https://github.com/siderolabs/talos/commit/561cfb60c313a9bdc70ed2ff2729549bc8c50fcb) chore: update pkgs and tools version\n* [`2f42202a7`](https://github.com/siderolabs/talos/commit/2f42202a7ccee0e33e43b2081929b5510db5d713) fix: simplify OOM expression\n* [`7b06ae8c2`](https://github.com/siderolabs/talos/commit/7b06ae8c2cf1069cb77cddee0986afc5af837bcc) test: fix flaky LinkSpec/Wireguard test\n* [`e715f3871`](https://github.com/siderolabs/talos/commit/e715f387137fa566a4824c051b624e013a93c49f) feat: present kernel log as `talosctl logs kernel`\n* [`e2ee39b8a`](https://github.com/siderolabs/talos/commit/e2ee39b8ac54ada49dd0a7ffaab4b0ae5d684792) fix: support specifying patch file without '@' symbol\n* [`e202b1f9e`](https://github.com/siderolabs/talos/commit/e202b1f9e82823aa5b31625024bce65bcc53b29f) fix: trim trailing dots from certificate SANs\n* [`7f7079f9c`](https://github.com/siderolabs/talos/commit/7f7079f9c0fbb30ce781aa1223d7df1a175a6206) fix: assign value of multicast setting properly\n* [`eba96141e`](https://github.com/siderolabs/talos/commit/eba96141e0afc147af9a8f1969e207501232b1de) feat: update etcd to 3.6.6\n* [`9945ceef3`](https://github.com/siderolabs/talos/commit/9945ceef37b13bc6e93637dcf395a8c9019e60ed) docs: add API Server Cipher Suites changelog\n* [`9ed488d09`](https://github.com/siderolabs/talos/commit/9ed488d09648c09a9a5c1ed6a5cd245b84cd415d) feat: update TLS cipher suites for API server\n* [`f1c04e4d6`](https://github.com/siderolabs/talos/commit/f1c04e4d6af14243a328d22bf810f27b13d83898) feat: generate mirrors patch\n* [`a89108995`](https://github.com/siderolabs/talos/commit/a89108995ff13fbbef0bf5cbf429cede5ff81078) fix: add CA subject to generated certificate\n* [`35dd612a5`](https://github.com/siderolabs/talos/commit/35dd612a5e59d8781e147fc36eb14f3e8bc66811) fix: add more resilient move\n* [`83675838f`](https://github.com/siderolabs/talos/commit/83675838f3655b44cbd850fd82b4d17acfb00c33) feat: extend flags of cache-cert-gen\n* [`80ab7a064`](https://github.com/siderolabs/talos/commit/80ab7a0643fc8057283a8ba3eb912d0ee453c143) chore: remove spammy 'clean up unused volumes' logs\n* [`74d35900a`](https://github.com/siderolabs/talos/commit/74d35900af0f6451426b70eec3b6db4b72eb993c) chore: disable k8s integration tests for 1GiB worker nodes\n* [`4f6218674`](https://github.com/siderolabs/talos/commit/4f621867407ec8f568f67833172ebaf2ff400346) feat: support TALOS_HOME env var\n* [`0c59b3ea3`](https://github.com/siderolabs/talos/commit/0c59b3ea3f6bc49cef409a1456b4ffa3bf1d28df) feat: add multicast to linkconfig\n* [`6db06f4d5`](https://github.com/siderolabs/talos/commit/6db06f4d5d51abd9e80ead6e4417f0f68856c569) feat: implement multicast setting\n* [`eeded98f5`](https://github.com/siderolabs/talos/commit/eeded98f527a230c65cb041a29fefc5f693d9879) fix: add riscv64 talosctl to release artifacts\n* [`a6bbae91b`](https://github.com/siderolabs/talos/commit/a6bbae91bad56328851fa91e01c17b8af7340b3c) fix: fix typos across the project\n* [`83f2bdb9c`](https://github.com/siderolabs/talos/commit/83f2bdb9ce6c9466716a6ac9c94dc2222e569ee8) feat: support relative voume size\n</p>\n</details>\n\n### Changes since v1.13.0-alpha.0\n<details><summary>80 commits</summary>\n<p>\n\n* [`900516e68`](https://github.com/siderolabs/talos/commit/900516e68950e4b94696f6a9b481cefee44b3360) chore: update image signer\n* [`938de566e`](https://github.com/siderolabs/talos/commit/938de566eca30af3cc4355a94931186f19b682f2) feat: bump kernel\n* [`388cec727`](https://github.com/siderolabs/talos/commit/388cec72796d0ecd0c7103efcaab9066e9b62509) feat(overlays): add new overlays\n* [`9f2dd6312`](https://github.com/siderolabs/talos/commit/9f2dd6312f9d49e4d03347c98b100119f94cf807) refactor: api tests\n* [`a90783146`](https://github.com/siderolabs/talos/commit/a90783146fc2d475055bfce0f8b5120969f74dc7) feat: add a helper module to generate standard patches\n* [`1fec5b23d`](https://github.com/siderolabs/talos/commit/1fec5b23d0c10e53863a7c0f89f862708a7f4069) fix: implement merger for PercentageSize\n* [`8b245b8f2`](https://github.com/siderolabs/talos/commit/8b245b8f269b6c8cb463f2cf537d2ed2ab6924ec) feat: implement new image service APIs\n* [`d90c775b8`](https://github.com/siderolabs/talos/commit/d90c775b8441705003de3427b2e6831dcbfb449f) chore: rename internal `talosctl debug air-gapped`\n* [`2165280d0`](https://github.com/siderolabs/talos/commit/2165280d0eedf59899ad44e2f3289d81b3dab466) refactor: change the way one2many proxying is picked\n* [`b1b703dbe`](https://github.com/siderolabs/talos/commit/b1b703dbe2b25785ded0c77f23d674d9b9934975) chore: move sync logging code to go-kubernetes package\n* [`e48c6d7ab`](https://github.com/siderolabs/talos/commit/e48c6d7ab9c8a2e28ebe2115ac09f1557bbcca33) fix: allow to expose a port multiple times in Docker\n* [`410d8cb57`](https://github.com/siderolabs/talos/commit/410d8cb5727ccf054c9097f33bc916d87076a599) fix: undo CRLF on Windows (talosctl edit)\n* [`859d3f03c`](https://github.com/siderolabs/talos/commit/859d3f03c444d98b94a06adac3648562e3b1228b) feat: add RPi5 to the list of supported SBCs\n* [`0bd48bbc6`](https://github.com/siderolabs/talos/commit/0bd48bbc6f365770167ee753be563eb4179fcadb) fix(talosctl): pass --k8s-endpoint flag to rotate-ca kubernetes rotation\n* [`b9e27ebe7`](https://github.com/siderolabs/talos/commit/b9e27ebe72c4302c416fd8efb007c3966004ddd6) feat: update Linux kernel with dm-integrity\n* [`6aa9b0677`](https://github.com/siderolabs/talos/commit/6aa9b0677ed7ca4955fead474e36a533b3250ad9) fix: skip empty documents on config decoding\n* [`494492489`](https://github.com/siderolabs/talos/commit/494492489b29b615a8a874c0648690ed3b9adb58) fix: always set advertised peer URLs\n* [`782cc507d`](https://github.com/siderolabs/talos/commit/782cc507dc33c87caa5ff985eea5f4439c3e1012) fix: open the filesystem as read-only\n* [`28e61a740`](https://github.com/siderolabs/talos/commit/28e61a740a906fadfea098f38a9c9f4e8c32773e) fix: set GRUB prefix correctly on arm64\n* [`a4f1c5239`](https://github.com/siderolabs/talos/commit/a4f1c5239ef7227856640c230e0d0364d9eedbd2) feat: update GRUB to 2.14\n* [`562920701`](https://github.com/siderolabs/talos/commit/562920701e2999cbb6687e55de96719aba4064fd) fix: use node podCIDRs for kubespan advertiseKubernetesNetworks\n* [`39460365c`](https://github.com/siderolabs/talos/commit/39460365c1726095e20cf3cc7c079c234b8022d6) feat: implement layering for ProbeSpec\n* [`b5c760f70`](https://github.com/siderolabs/talos/commit/b5c760f7076570bc04be02af0ea493f95d8338d0) feat: add ProbeConfig for network connectivity probes\n* [`4b274f761`](https://github.com/siderolabs/talos/commit/4b274f76159495cc6c2977ec3bbade71e35aade8) feat: support aws cert manager in imager\n* [`417209512`](https://github.com/siderolabs/talos/commit/41720951251102f1c174e501a3103e55720a1d8b) fix: fallback to /proc/meminfo for memory modules\n* [`7f1147bed`](https://github.com/siderolabs/talos/commit/7f1147bed495a06d336f5be1da6073921b5e52dc) fix: add warnings to 802.3ad bond\n* [`ddd6b186e`](https://github.com/siderolabs/talos/commit/ddd6b186eb8f527324736576182dafbce3423da5) refactor: generate GRUB images\n* [`c7aa266ea`](https://github.com/siderolabs/talos/commit/c7aa266ea5c9d3fbd465dc651f2ebfec622612e7) fix: overwrite resolver config with machine config\n* [`cf70f05fa`](https://github.com/siderolabs/talos/commit/cf70f05fa40312c30d8345c2fb15ce8eda86a7a7) fix: oracle platform file format\n* [`8c7b8f5b7`](https://github.com/siderolabs/talos/commit/8c7b8f5b7d6dec144f7985a7c8a8a582c38f3154) feat: add support for negative max size\n* [`77bc3d21f`](https://github.com/siderolabs/talos/commit/77bc3d21fa40e188af4b5dd93e1cda289e858d56) fix: marshal of FailOverMac property\n* [`38e280c93`](https://github.com/siderolabs/talos/commit/38e280c9319ef1ecb1455b3cc8b8d0d1d7426ccd) fix: make OOM expression a bit less sensitive\n* [`3d1301640`](https://github.com/siderolabs/talos/commit/3d1301640d44d58303160400e4954c36f53341f9) fix: wipe the first/last 1MiB in addition to wiping by signatures\n* [`1aa6528ad`](https://github.com/siderolabs/talos/commit/1aa6528adcddfb6a5ed66cc26cac1a0fcdb37516) fix: make OOM controller more precise by considering separate cgroup PSI\n* [`f7072c050`](https://github.com/siderolabs/talos/commit/f7072c050e607de16781a65eb97ab2a1828b05fb) fix: check if the device is not mounted when wiping\n* [`743c3b94b`](https://github.com/siderolabs/talos/commit/743c3b94b958e4abcbf70d4064f2ae0e0bbb0712) fix: use correct containerd import path\n* [`f2dd08594`](https://github.com/siderolabs/talos/commit/f2dd08594e8e474c7b3891dc46c64f27c724dbc0) feat: report image pull progress in the console\n* [`72fe98a06`](https://github.com/siderolabs/talos/commit/72fe98a06f31536454f201d703f8ae6a071235b5) fix: boot with GRUB\n* [`d4ed13d93`](https://github.com/siderolabs/talos/commit/d4ed13d9394b087e8877eba25950f344894803a1) fix: add talos version to Hetzner Cloud client user agent\n* [`150c41c30`](https://github.com/siderolabs/talos/commit/150c41c30ed3f066f10bd2bdc2afa9b2c5a97597) feat: update Linux to 6.18.5\n* [`01a367891`](https://github.com/siderolabs/talos/commit/01a3678913de0fa4d309a361428c117d24ce0d1e) fix: use append instead of prepend in service-account-issuer\n* [`d1954278a`](https://github.com/siderolabs/talos/commit/d1954278a1ba3470b2e5ccae90762078c18d69e9) feat: add extraArgs from service-account-issuer\n* [`91b88f7f9`](https://github.com/siderolabs/talos/commit/91b88f7f994cccad15cbec1aa8019bd19b84ae91) feat: support multiple values for extraArgs\n* [`96e604874`](https://github.com/siderolabs/talos/commit/96e604874b17e7aa8b62bfb25737f349e539bc5a) fix: add hostname to endpoints\n* [`7033275a7`](https://github.com/siderolabs/talos/commit/7033275a7a22d51e83c9e760ba37d2ad6ab22f28) refactor: move BootloaderKind into machinery\n* [`71adaf0ea`](https://github.com/siderolabs/talos/commit/71adaf0ea5b558c8a16e2acfdec3671611455985) fix: sort mirrors and tls configs when generating the machine config\n* [`34f09a300`](https://github.com/siderolabs/talos/commit/34f09a3004fe1b77c16dd33b04adca95fb6876a5) feat: add VLAN support to OpenStack platform\n* [`5127ef7c2`](https://github.com/siderolabs/talos/commit/5127ef7c28b360f9c7c033f77c58cef729e5278d) fix: wipe disk by signatures\n* [`415bfaedb`](https://github.com/siderolabs/talos/commit/415bfaedb6ae8d42b5927fdc5b7cfe8aa781a791) fix: panic in configpatcher when the whole section is missing\n* [`e5aca71cd`](https://github.com/siderolabs/talos/commit/e5aca71cd0557557e50c39d82eda2c938f627d62) fix: fix healthcheck timeout\n* [`634b71e2d`](https://github.com/siderolabs/talos/commit/634b71e2d028bf13d838acad8809c95384b6eed9) docs: move talosctl pcap example to Example Block\n* [`818492731`](https://github.com/siderolabs/talos/commit/8184927316c5de7d9b04f21474a60cc791c3d26d) feat: implement KubeSpan multi-document configuration\n* [`4d0604b9d`](https://github.com/siderolabs/talos/commit/4d0604b9d93851f444a00dbd84fcac76d21d35c2) chore: remove unrelated machineconfig\n* [`e36863470`](https://github.com/siderolabs/talos/commit/e36863470b14496c3d84417e63fef45e6060603b) feat: add it87 hwmon module\n* [`308c75090`](https://github.com/siderolabs/talos/commit/308c75090774d2510c2ec08e63e179a5c0fa6987) fix: resolve SideroLink Wireguard endpoint on reconnect\n* [`e4ef494de`](https://github.com/siderolabs/talos/commit/e4ef494decdf97664c4803aa3861015fce49760e) fix: drop the persist config flag from gen config\n* [`c3176adcf`](https://github.com/siderolabs/talos/commit/c3176adcf981811a326c971c81c4b591f54e116a) feat: add EnvironmentConfig document\n* [`c839b3880`](https://github.com/siderolabs/talos/commit/c839b38809b3a0029061d43477555ec31e283aa5) feat: expose more SSA options in the upgrade-k8s command\n* [`b8ff9677e`](https://github.com/siderolabs/talos/commit/b8ff9677e4f9a64908ae00bb1d80aa2442a00a60) fix: handle correctly incomplete RegistryTLSConfig\n* [`99f2ddada`](https://github.com/siderolabs/talos/commit/99f2ddada895011036af1435dd10bac3be0a9171) fix: bond config via platform\n* [`2449ffea4`](https://github.com/siderolabs/talos/commit/2449ffea45304459ea8895b535b6f070a9249172) fix: allow HostnameConfig to be used with incomplete machine config\n* [`35fc52087`](https://github.com/siderolabs/talos/commit/35fc5208728dbc3e0b139aff4c06f25208445637) fix: lock down etcd listen address to IPv4 localhost\n* [`27253d731`](https://github.com/siderolabs/talos/commit/27253d7317a473cbbc0f5c0eee634173bdd2eda7) feat: use new xfs config file\n* [`c9d84ae21`](https://github.com/siderolabs/talos/commit/c9d84ae21e203529a6952c165ff04d602a2a6ad6) fix: generate OCI-compliant image config\n* [`7a4b2b33a`](https://github.com/siderolabs/talos/commit/7a4b2b33abe8a3011f37f0a8f4848dd846d0396f) fix: update VIP config example\n* [`080efcbda`](https://github.com/siderolabs/talos/commit/080efcbda2c4334f9d8c70804a5a37f0cdb2df2d) feat: add k8s-version parameter to k8s-bundle\n* [`b764f5f72`](https://github.com/siderolabs/talos/commit/b764f5f724bf8af3acaac74942ea91a86e593322) fix: skip sync test when kube-proxy is disabled\n* [`70e67787d`](https://github.com/siderolabs/talos/commit/70e67787d6d34d93a34871b2d25d64f6a7575d76) feat: imager: populate filesystems with root owned files\n* [`7416dca59`](https://github.com/siderolabs/talos/commit/7416dca59378dc282e42ea30107cf40326cc593c) fix: print talosctl images to release notes\n* [`dc2009e47`](https://github.com/siderolabs/talos/commit/dc2009e4779684a6a4252d4dfd2aa02d1b60c2da) chore: use context when creating filesystems\n* [`85f7be6e3`](https://github.com/siderolabs/talos/commit/85f7be6e3f14bf160cf32bccf7418b31968d474f) chore: update slack links\n* [`154952175`](https://github.com/siderolabs/talos/commit/154952175ab73ac65722732b146a0ee1c56b2f4d) fix: disable swap for system services\n* [`d98b415af`](https://github.com/siderolabs/talos/commit/d98b415afea7b1820153151c0273df24a101742e) fix: drop more non-overlay SBC stuff\n* [`226cd6bc1`](https://github.com/siderolabs/talos/commit/226cd6bc1d70662cb7f7736ac6fad117170a36fb) fix: do not allocate for the actual disk image file\n* [`53f5bf8d2`](https://github.com/siderolabs/talos/commit/53f5bf8d2c97e91bee06bcb5948170015486ea77) fix: overlay installers\n* [`10d0cfd93`](https://github.com/siderolabs/talos/commit/10d0cfd93a083fb8b71b7c0297df52feb55e044b) fix: overlay install in image mode\n* [`77086694d`](https://github.com/siderolabs/talos/commit/77086694d18b69802e542156fc12cd7cf066efc2) fix: partition data population\n* [`4d5657b1a`](https://github.com/siderolabs/talos/commit/4d5657b1a34c939b63b2cc3ee11ed45ad1bf23c3) fix: drop SBC board code\n* [`c4f3f6d3e`](https://github.com/siderolabs/talos/commit/c4f3f6d3e59b58016ba8546c5bd3e8e465fbbf52) feat: implement kubernetes server-side apply\n* [`f12fd2b0a`](https://github.com/siderolabs/talos/commit/f12fd2b0a9fdf8f53ec5714d3ad18b695973e0b0) test: bump Image Factory tests\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`604c56b`](https://github.com/siderolabs/go-kubernetes/commit/604c56b7251e8ec03b644b47c69ee08d6f25780b) chore: extract common code to the go-kubernetes package\n* [`ec0e3ae`](https://github.com/siderolabs/go-kubernetes/commit/ec0e3aefdeb332f4a44e669c9f7eb877b5f50963) chore: expose more ssa options\n* [`ad2fccd`](https://github.com/siderolabs/go-kubernetes/commit/ad2fccd09d137231f5a8187643782e0e1c661c44) feat: add SSA and pruning support\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>53 commits</summary>\n<p>\n\n* [`dc737a6`](https://github.com/siderolabs/pkgs/commit/dc737a68c470c9498ec11bde09196809355d2463) chore: update kernel\n* [`9b118b3`](https://github.com/siderolabs/pkgs/commit/9b118b3d0fe7f0df06a069065b86ab307fef3375) chore: update deps\n* [`a63c227`](https://github.com/siderolabs/pkgs/commit/a63c2276eea0013463487cebf95ee35a37c5d9f6) feat: update OpenSSL to v3.6.1\n* [`da7ab57`](https://github.com/siderolabs/pkgs/commit/da7ab5776bd1a6c551bfc6fe5919114721da0e1f) feat: add px-fuse pkg\n* [`553e0fb`](https://github.com/siderolabs/pkgs/commit/553e0fb70f076a8bc53e283253b30ff819e627ff) feat: enable dm-integrity\n* [`15a3cdf`](https://github.com/siderolabs/pkgs/commit/15a3cdf54884d5169895a1ff46682373688ac5e2) feat: update Linux to 6.18.6\n* [`b518a19`](https://github.com/siderolabs/pkgs/commit/b518a196de93dd33e70faaff2342f67acb7dc49b) feat: update dependencies\n* [`1b4fbf5`](https://github.com/siderolabs/pkgs/commit/1b4fbf56b270d5669116fa0d8f91a3b9495e0d97) feat: update GRUB to 2.14\n* [`30bc671`](https://github.com/siderolabs/pkgs/commit/30bc671d4be566ebf60b820edd54000616262e79) fix: enable pinctrl for Raspberry Pi 5\n* [`375983f`](https://github.com/siderolabs/pkgs/commit/375983f4685484a8be5796f815629a9a0d8bd146) feat: update Go to 1.25.6\n* [`d445c80`](https://github.com/siderolabs/pkgs/commit/d445c8076b7dd18b04f48e0a7e5cc2e50b3064d0) feat: update Linux to 6.18.5\n* [`6994400`](https://github.com/siderolabs/pkgs/commit/69944002f9ee681220dcb23031c23ee327e6c1f2) feat: update NVIDIA LTS and production driver versions\n* [`05c3d85`](https://github.com/siderolabs/pkgs/commit/05c3d856b7de6eb64af718d7266a5adf15e1224b) feat: update Linux firmware to 20260110\n* [`c61b466`](https://github.com/siderolabs/pkgs/commit/c61b466e130015b44962e7ef3bc1e9bec935b1df) feat: enable IT87 hwmon module\n* [`ae2572e`](https://github.com/siderolabs/pkgs/commit/ae2572e894a3d8d951418d447ec02f6cc65c8e72) feat: enable IPV6_MROUTE\n* [`d6b503e`](https://github.com/siderolabs/pkgs/commit/d6b503e0fe75d52f83d656a3460cb3614b352e51) feat: add RK3588 NPU Support\n* [`df4b4c8`](https://github.com/siderolabs/pkgs/commit/df4b4c885d4aabf702ce03bcb341f5b5f3641d76) feat: bump deps\n* [`a220898`](https://github.com/siderolabs/pkgs/commit/a2208985bd756ef6366497c5f9768e814b3f7583) feat: add libarchive\n* [`c2371b5`](https://github.com/siderolabs/pkgs/commit/c2371b5582836e27b3e80c4404c4ff5fbed90291) feat: enable ZRAM support\n* [`ab4d169`](https://github.com/siderolabs/pkgs/commit/ab4d169ad93203ba56b0677a10e78eb3e623762e) feat: add a patch to force uid when populating from a directory\n* [`972f44d`](https://github.com/siderolabs/pkgs/commit/972f44d5dae53809ef337544c52c835373439d34) feat: update dependencies\n* [`f8eb5b0`](https://github.com/siderolabs/pkgs/commit/f8eb5b02aaebaf76c59e71f57f4a689dc727e769) feat: update Linux to 6.18.2\n* [`3fb6291`](https://github.com/siderolabs/pkgs/commit/3fb629109a7e5f9650d0e641ff5076a29c319448) feat: update systemd to 259\n* [`59241bd`](https://github.com/siderolabs/pkgs/commit/59241bd58eeb07a18af1c9fc8fffff6365ecca0d) fix: add SBOMs for pigz/igzip\n* [`9377c78`](https://github.com/siderolabs/pkgs/commit/9377c786d112b4181f1e373f6e513130f11b7801) feat: optimize decompression for containerd\n* [`e8e61ce`](https://github.com/siderolabs/pkgs/commit/e8e61cedbbd687ed958db992e05b5d59e4a8ea60) feat: update containerd to 2.2.1\n* [`daa74ba`](https://github.com/siderolabs/pkgs/commit/daa74bab83f91bbc4b6c42625d2953299d5fe20a) feat: support xfs filesystem reproducibility\n* [`1f66513`](https://github.com/siderolabs/pkgs/commit/1f665130fbda76478c261dd54e3843c15027c9cd) feat: update OpenZFS to 2.4.0\n* [`b209af5`](https://github.com/siderolabs/pkgs/commit/b209af5baf1a67472ef431e5a8b7d48022392a1e) chore: rekres with latest changes\n* [`2b806b9`](https://github.com/siderolabs/pkgs/commit/2b806b9b2a7e05b97c2a7e8572e3a8edbd3721d3) feat: bump dependencies\n* [`65242fd`](https://github.com/siderolabs/pkgs/commit/65242fd0fef5c9c923aacce23d1655bad0d1b3e3) feat: enable CONFIG_MISC_RP1 in ARM64 config\n* [`4daecd8`](https://github.com/siderolabs/pkgs/commit/4daecd8e7b8d87110a9e552a60a5394014294e08) feat: update Linux to 6.18.1\n* [`9868a66`](https://github.com/siderolabs/pkgs/commit/9868a66e3c000f505c97ff68e61abac9c9e8e4c9) feat: enable Powercap and Intel RAPL\n* [`07883ee`](https://github.com/siderolabs/pkgs/commit/07883eee3729d4d3adaaebcd825452934c3baebb) feat: build and package perf binary\n* [`47abca0`](https://github.com/siderolabs/pkgs/commit/47abca0852b9555d88eba61661c65a7f93ec3590) fix: add json support to nftables binary\n* [`b961ff8`](https://github.com/siderolabs/pkgs/commit/b961ff898fc9eae68d7f3cea2ca22ff4d0b9c99d) feat: patch containerd 2.2.0 with cgroups fix patch\n* [`b7dd7f6`](https://github.com/siderolabs/pkgs/commit/b7dd7f6c809f670f058b78fd3b84f4cb977771cb) feat: add mstflint module\n* [`ae53351`](https://github.com/siderolabs/pkgs/commit/ae5335198e009da7b06bc0f0d6f42b0947650fc0) feat: update ZFS to 2.4.0-rc5\n* [`b8edf01`](https://github.com/siderolabs/pkgs/commit/b8edf0168171ffc5b87fcd962e37d5c2cd25b687) feat: update CNI plugins to v1.9.0\n* [`a57c1b0`](https://github.com/siderolabs/pkgs/commit/a57c1b0c9d143559a87b64fe9570eec39c14a771) feat: enable amd sev-snp\n* [`68562c1`](https://github.com/siderolabs/pkgs/commit/68562c1b4cdba656287021a1694440b2a7e4d24d) feat: update Linux to 6.18\n* [`6f4ff8c`](https://github.com/siderolabs/pkgs/commit/6f4ff8cc9f57452707588c05e5ca4e80c56548d2) feat: enable Amlogic Meson PCIe controller driver\n* [`c41127b`](https://github.com/siderolabs/pkgs/commit/c41127b94d22b9a5cb6b93f49b546f2ff477410c) feat: enable Intel GPIO/Pinctrl kernel modules\n* [`4a31ff7`](https://github.com/siderolabs/pkgs/commit/4a31ff7dd5c9266b68abded53a7399cb8102f4e3) feat: update NVIDIA LTS to 580.105.08\n* [`3e858d3`](https://github.com/siderolabs/pkgs/commit/3e858d3fa5b2719d8d83397fb89c2ffc91f86615) chore: fork pkgs for Talos 1.13\n* [`dcc5aa1`](https://github.com/siderolabs/pkgs/commit/dcc5aa1e71d6b2e9374d41029a2e6de22dbc61ce) feat: update runc to 1.3.4\n* [`8b6ae5b`](https://github.com/siderolabs/pkgs/commit/8b6ae5b7fc22c3bb2df4bbe31190ff90b0986e6f) fix: regenerate configs\n* [`2992598`](https://github.com/siderolabs/pkgs/commit/29925980896df1978a020505b2b061ffdbd240c7) fix: add missing kernel config entries\n* [`c8ea18a`](https://github.com/siderolabs/pkgs/commit/c8ea18a0873f5b31c54d567ef97d8d05634eb506) feat: rekres to alow multiple commits\n* [`2ddef8b`](https://github.com/siderolabs/pkgs/commit/2ddef8b65755610fc6dbb3f1fb976a6bc572478f) chore: update dependencies\n* [`d1f28e0`](https://github.com/siderolabs/pkgs/commit/d1f28e058972174af9ac819783a69f5f6596b37d) chore: update dependencies\n* [`ab253f5`](https://github.com/siderolabs/pkgs/commit/ab253f521d95b30710e258ebb54adbb7b8de8970) feat: enable gpio-fan module\n* [`0b10666`](https://github.com/siderolabs/pkgs/commit/0b1066635d9dd255bf0ad936e21099fd4bd03f1e) chore: use ubuntu mirrors\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>1 commit</summary>\n<p>\n\n* [`bd9c491`](https://github.com/siderolabs/proto-codec/commit/bd9c491b9e84d7274728ce7e3bde14009f5224bd) chore: bump and update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>13 commits</summary>\n<p>\n\n* [`ca26e1c`](https://github.com/siderolabs/tools/commit/ca26e1c38cd0a76eb981db4dad2e6caccb0bbe4d) chore: update deps\n* [`0281af0`](https://github.com/siderolabs/tools/commit/0281af0545e17c409fb32d8db61a7d9b0ad8b1c2) feat: update OpenSSL to 3.6.1\n* [`721ad07`](https://github.com/siderolabs/tools/commit/721ad073f18b41407882727a3f0061e594f6c955) feat: update dependencies\n* [`2b3f514`](https://github.com/siderolabs/tools/commit/2b3f514d42a343d98c79a487e80bd4f225a41b70) fix: reproducible build for nasm\n* [`98c699e`](https://github.com/siderolabs/tools/commit/98c699eb624d0846455f08db77cc14e446cb6db9) feat: update Go to 1.25.6\n* [`cd5eb66`](https://github.com/siderolabs/tools/commit/cd5eb66bb0de4fb468a860e176267c3420b4a3a1) chore: run rekres and update dependencies\n* [`896f8b9`](https://github.com/siderolabs/tools/commit/896f8b9c1f88cd190d11b8ef3baa2c36e73d6dfe) fix: add sbom for zlib-ng\n* [`543a16f`](https://github.com/siderolabs/tools/commit/543a16fedf7170d8b015ea1391817328205e629a) feat: replace zlib -> zlib-ng, add nasm\n* [`b67c1a1`](https://github.com/siderolabs/tools/commit/b67c1a168b302539d2082a5513c4a0130c30e4df) chore: rekres with latest changes\n* [`5e087cb`](https://github.com/siderolabs/tools/commit/5e087cbcd158db1ce4f447145bd76a24d07159a1) feat: bump dependencies\n* [`da96a27`](https://github.com/siderolabs/tools/commit/da96a2771801627b4715f7a13199aa6846f87732) chore: rekres to fix reproducibility\n* [`e283ec8`](https://github.com/siderolabs/tools/commit/e283ec8d3831bb19b26938afb10f4955ea563ce2) feat: update Go to 1.25.5\n* [`c38ff0c`](https://github.com/siderolabs/tools/commit/c38ff0c03be69e5cc3795d9dc055896604a3041c) chore: update to 1.13.0-alpha.0 toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go-v2/config**            v1.31.20 -> v1.32.6\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**  v1.18.13 -> v1.18.16\n* **github.com/aws/aws-sdk-go-v2/service/acm**       v1.37.19 **_new_**\n* **github.com/aws/aws-sdk-go-v2/service/kms**       v1.46.0 -> v1.49.4\n* **github.com/aws/smithy-go**                       v1.23.2 -> v1.24.0\n* **github.com/containerd/cgroups/v3**               v3.0.5 -> v3.1.0\n* **github.com/containerd/containerd/api**           v1.9.0 -> v1.10.0\n* **github.com/containerd/containerd/v2**            v2.1.5 -> v2.2.0\n* **github.com/containerd/platforms**                v1.0.0-rc.1 -> v1.0.0-rc.2\n* **github.com/cosi-project/runtime**                v1.12.0 -> v1.13.0\n* **github.com/diskfs/go-diskfs**                    fc569a00ea19 **_new_**\n* **github.com/docker/cli**                          v29.0.0 -> v29.1.3\n* **github.com/gdamore/tcell/v2**                    v2.9.0 -> v2.13.4\n* **github.com/godbus/dbus/v5**                      v5.1.0 -> v5.2.0\n* **github.com/google/cadvisor**                     v0.53.0 -> v0.54.1\n* **github.com/google/go-containerregistry**         v0.20.6 -> v0.20.7\n* **github.com/hetznercloud/hcloud-go/v2**           v2.30.0 -> v2.32.0\n* **github.com/klauspost/compress**                  v1.18.1 -> v1.18.3\n* **github.com/linode/go-metadata**                  v0.2.2 -> v0.2.3\n* **github.com/mdlayher/ethtool**                    v0.4.0 -> v0.5.0\n* **github.com/miekg/dns**                           v1.1.68 -> v1.1.69\n* **github.com/moby/moby/client**                    v0.1.0 -> v0.2.1\n* **github.com/siderolabs/go-blockdevice/v2**        v2.0.20 -> v2.0.23\n* **github.com/siderolabs/go-kubernetes**            v0.2.28 -> v0.2.31\n* **github.com/siderolabs/pkgs**                     v1.12.0-23-ge0b78b8 -> v1.13.0-alpha.0-44-gdc737a6\n* **github.com/siderolabs/proto-codec**              v0.1.2 -> v0.1.3\n* **github.com/siderolabs/talos/pkg/machinery**      v1.12.0 -> v1.13.0-alpha.0\n* **github.com/siderolabs/tools**                    v1.12.0-2-g7d57df0 -> v1.13.0-alpha.0-12-gca26e1c\n* **github.com/sirupsen/logrus**                     v1.9.3 -> dd1b4c2e81af\n* **go.etcd.io/etcd/api/v3**                         v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/v3**                      v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.6.6 -> v3.6.7\n* **go.uber.org/zap**                                v1.27.0 -> v1.27.1\n* **golang.org/x/net**                               v0.47.0 -> v0.48.0\n* **golang.org/x/oauth2**                            v0.33.0 -> v0.34.0\n* **golang.org/x/sync**                              v0.18.0 -> v0.19.0\n* **golang.org/x/sys**                               v0.38.0 -> v0.40.0\n* **golang.org/x/term**                              v0.37.0 -> v0.38.0\n* **golang.org/x/text**                              v0.31.0 -> v0.33.0\n* **google.golang.org/grpc**                         v1.76.0 -> v1.77.0\n* **google.golang.org/protobuf**                     v1.36.10 -> v1.36.11\n* **sigs.k8s.io/cli-utils**                          77c836a69463 **_new_**\n\nPrevious release can be found at [v1.12.0](https://github.com/siderolabs/talos/releases/tag/v1.12.0)\n\n## [Talos 1.13.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.13.0-alpha.0) (2025-12-25)\n\nWelcome to the v1.13.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### External Volumes\n\nTalos now supports virtiofs-based external volumes via the new\n[ExternalVolumeConfig](https://www.talos.dev/v1.13/reference/configuration/block/externalvolumeconfig/)\ndocument.\n\nThese virtiofs external volumes are not supported when SELinux is running\nin enforcing mode.\n\n\n### Talos Imager Enhancements\n\nTalos imager now supports running rootless. `--privileged` and `-v /dev:/dev` are no longer required.\n\n\n### Container Image Decompression\n\nTalos now ships with `igzip` (amd64) and `pigz` (arm64) to speed up container image decompression.\n\n\n### /proc/PID/mem Access Hardening\n\nA new kernel parameter `proc_mem.force_override=never` has been introduced by default to enhance system security\nby preventing unwanted writes to protected process memory via `/proc/PID/mem`.\nIf the kernel parameter is removed, default behavior is restored, allowing access only if the process is traced.\n\n\n### Reproducible Disk Images\n\nTalos disk images are now reproducible. Building the same version of Talos multiple times will yield\nidentical disk images.\n\nNote: VHD and VMDK (Azure and VMware) images are not currently reproducible due to limitations in the underlying image creation tools.\nUsers verifying reproducible images should use raw images, verify checksums, and convert them to VHD/VMDK as needed.\n\n\n### Component Updates\n\nLinux: 6.18.2\ncontainerd: 2.2.1\netcd: 3.6.7\nCoreDNS: 1.13.2\nKubernetes: 1.35.0\nFlannel CNI plugin: v1.9.0-flannel1\nLVM2: 2_03_38\nrunc: 1.4.0\nsystemd: 259\ncryptsetup: 2.8.3\n\nTalos is built with Go 1.25.5.\n\n\n### VM Hot-Add Support\n\nTalos now includes udev rules to support hot-adding of CPUs in virtualized environments.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Mateusz Urbanek\n* Noel Georgi\n* Dmitrii Sharshakov\n* Laura Brehm\n* Bryan Lee\n* Edward Sammut Alessi\n* Birger Johan Nordølum\n* Christopher Puschmann\n* Jaakko Sirén\n* Jean-Francois Roy\n* Joakim Nohlgård\n* Justin Garrison\n* Lennard Klein\n* Michal Baumgartner\n* Orzelius\n* Serge van Ginderachter\n* Skye Soss\n* dataprolet\n* eseiker\n* pranav767\n\n### Changes\n<details><summary>95 commits</summary>\n<p>\n\n* [`f0d8a6851`](https://github.com/siderolabs/talos/commit/f0d8a685173354e5fd148786872062a342c4282a) test: skip the source bundle on exact tag\n* [`c57701d65`](https://github.com/siderolabs/talos/commit/c57701d6590388e7d6418af67e8237c7d60ccf54) fix: remove interactive installer\n* [`43937c1cd`](https://github.com/siderolabs/talos/commit/43937c1cd42758a15026261fe8f0e06daaebdcbd) feat: update Linux and systemd\n* [`72a194df8`](https://github.com/siderolabs/talos/commit/72a194df88f2800cee3372241fbad419b07f7bbf) feat: add VM CPU hot-add rules\n* [`f09ae1e0d`](https://github.com/siderolabs/talos/commit/f09ae1e0d2e1b7842d504b594b71a325af7733e5) fix: probe small images correctly\n* [`8f2b33799`](https://github.com/siderolabs/talos/commit/8f2b337994fdeff76a0ae9e1730b4b9f596ff1bb) feat: imager support rootless builds\n* [`c7525a97e`](https://github.com/siderolabs/talos/commit/c7525a97ef8615e903be183d7938b6d2a3b89464) feat: support creating filesystems from folder\n* [`e2bffb5ce`](https://github.com/siderolabs/talos/commit/e2bffb5cebaaf28f9dfff24f41ecbb2809fc60e5) chore: refactor imager code so it's more clear\n* [`0fb50dbd0`](https://github.com/siderolabs/talos/commit/0fb50dbd0a5b7b80187e50d501cec4b3fe434dc2) fix: invalid versions check in talos-bundle\n* [`b5dd56032`](https://github.com/siderolabs/talos/commit/b5dd5603207a46d8eed240173f06aeffd6a9c0e7) test: upgrade versions in upgrade tests\n* [`3dfa4d6e4`](https://github.com/siderolabs/talos/commit/3dfa4d6e40dcae2db47e89443568be3ae48b3ae1) fix: make upgrade work with SELinux enforcing=1\n* [`786c8e2ee`](https://github.com/siderolabs/talos/commit/786c8e2ee757c2d7b30d5bded954e584af3a058e) feat: ship pigz/igzip in rootfs to speed up image decompression\n* [`48d242918`](https://github.com/siderolabs/talos/commit/48d242918bc97e6a01434bee6fcdcfa735fd1f5a) feat: update containerd to 2.2.1\n* [`536541afe`](https://github.com/siderolabs/talos/commit/536541afe497d5f61cfcd0c01cf580ab5b3be164) fix: mount volume mount/unmount race\n* [`39117d457`](https://github.com/siderolabs/talos/commit/39117d45766b139ed6a0c1290f757e4b26d31d92) feat: update dependencies\n* [`f0f420725`](https://github.com/siderolabs/talos/commit/f0f420725c6a4f628cdc1b80d59713c375beb9b7) fix: bond setting change detection\n* [`8d6a7a867`](https://github.com/siderolabs/talos/commit/8d6a7a8677a5d1d61432fa94ca030351fd9852f2) feat: update Kubernetes to 1.35.0\n* [`845a0d09c`](https://github.com/siderolabs/talos/commit/845a0d09cd770a15db762ddda4d3d27f58656cfe) feat: update etcd 3.6.7, CoreDNS 1.13.2\n* [`b95912e04`](https://github.com/siderolabs/talos/commit/b95912e04907b78bd06987c6d3948f8f1804d844) feat: enforce `proc_mem.force_override=never` by default\n* [`681f3e84c`](https://github.com/siderolabs/talos/commit/681f3e84c85677f49ddbcd4a47e325d4a85af692) test: run virtiofs tests only when virtiofsd is running\n* [`0592ff0cd`](https://github.com/siderolabs/talos/commit/0592ff0cdbf54475dc91bfb7c9b9c3047bbe13da) fix: drop the Omni API URL check on IP address\n* [`a4879a5fa`](https://github.com/siderolabs/talos/commit/a4879a5fa2ded9b7b52ff7506b5493ae12939bba) feat: update Linux to 6.18.1\n* [`43b43ff18`](https://github.com/siderolabs/talos/commit/43b43ff189b7e5f37eaa75f4926c26ee21ffa5cb) docs: split talosctl commands into groups\n* [`6d17c18bf`](https://github.com/siderolabs/talos/commit/6d17c18bf908d3cd69ff920d0cff67b653a385f3) feat: enable Powercap and Intel RAPL\n* [`884e76662`](https://github.com/siderolabs/talos/commit/884e76662af34448d9904372f1256f59ce161f99) docs: fix the talosctl cluster create help output\n* [`6dc31be4f`](https://github.com/siderolabs/talos/commit/6dc31be4f982f62ba4aeb1b3b4e65ce022447eb4) fix: exclude new Virtual IPs configured with new config\n* [`94905c73e`](https://github.com/siderolabs/talos/commit/94905c73e93fd7dac38d911dc4264e4d0fe0081d) feat(talosctl): support running qemu x86 on Mac\n* [`f871ab241`](https://github.com/siderolabs/talos/commit/f871ab241c0f034401fbf61e32e7201cced49441) fix: provide json support in `nft` binary\n* [`694f45413`](https://github.com/siderolabs/talos/commit/694f45413fec8cc4f58a79e76034bd4bcec2bbdf) feat: external volumes\n* [`39feb16d2`](https://github.com/siderolabs/talos/commit/39feb16d2ed3bcb65d66483c0729bcec29f7b93e) fix: update containerd 2.2.0 with cgroups patch\n* [`82027eb9b`](https://github.com/siderolabs/talos/commit/82027eb9b30aa128099b27f638098d78857ecb4b) fix: bond configuration with new settings\n* [`121b13b8f`](https://github.com/siderolabs/talos/commit/121b13b8f8d6e5a487971f727c6e028c7ffa20f3) fix: disable kexec on arm64\n* [`7eaa725d0`](https://github.com/siderolabs/talos/commit/7eaa725d0dba18392279f5b43d167aaf18f43b99) fix: selection of boot entry\n* [`949bdb90a`](https://github.com/siderolabs/talos/commit/949bdb90ab2fd711c47583d96bd29a1ca90bbf41) feat: add Secure Boot to CloudStack platform config\n* [`798143a88`](https://github.com/siderolabs/talos/commit/798143a886e4055e764a9ad17cefe8ad4db0572e) fix: discard better klog message from Kubernetes client\n* [`008cd0986`](https://github.com/siderolabs/talos/commit/008cd0986cbbbd5527d91c01b951e311ba014b97) fix: disable kexec in talosctl cluster create on arm64\n* [`bb62b29ed`](https://github.com/siderolabs/talos/commit/bb62b29edb2fb704846ceeed2019f0ebaced30be) chore: prepare talos for 1.13\n* [`c0935030a`](https://github.com/siderolabs/talos/commit/c0935030ac3d966149591a3aaa8e430da768d678) chore: fork reference docs for 1.13.x\n* [`e387e48b3`](https://github.com/siderolabs/talos/commit/e387e48b30b3a3b991f1f611099f48fddefa851b) fix: do not override DNS on MacOS\n* [`1e7e87fb1`](https://github.com/siderolabs/talos/commit/1e7e87fb192521937b581ecd94a0aa0c861f2a5f) fix: rework NFT rules for KubeSpan\n* [`51bcfb567`](https://github.com/siderolabs/talos/commit/51bcfb567915d2b27e4b5321e080220bc618086b) feat: rename image default and source bundle\n* [`585abe944`](https://github.com/siderolabs/talos/commit/585abe94431f06b3ebf4b6a64ad1b5918708f866) feat: update Kubernetes to v1.35.0-rc.1\n* [`f301e3e9b`](https://github.com/siderolabs/talos/commit/f301e3e9ba47d5f46f1990a9bd21fd4e671c38f3) fix: update KubeSpan MSS clamping\n* [`74c1df6f4`](https://github.com/siderolabs/talos/commit/74c1df6f4b2ac8d989d1e42d6c7c0016411638ee) test: propagate MTU size to QEMU in `talosctl cluster create`\n* [`d347ca1af`](https://github.com/siderolabs/talos/commit/d347ca1af162c8d948899d58fc3f76dd0a94f138) fix: update CNI plugins to 1.9.0\n* [`e3f8196b4`](https://github.com/siderolabs/talos/commit/e3f8196b4c767ca68df9f6c85ed25c7e12fb4d87) chore: update Grype and Syft\n* [`e1b8ab323`](https://github.com/siderolabs/talos/commit/e1b8ab3236e956bc4b37e227423aea0f97612a5c) docs: add misssing period\n* [`cd04c3dde`](https://github.com/siderolabs/talos/commit/cd04c3dde70f604603fd7996c62adf5a17cfbd41) docs: update release notes\n* [`fc8ae3249`](https://github.com/siderolabs/talos/commit/fc8ae3249fac82cbdb5521ca8797a8451bdaa9fd) docs: add omni join token example to create qemu command\n* [`9fa00773c`](https://github.com/siderolabs/talos/commit/9fa00773caf2d092d953ff58d04cf94803039b94) chore: update go-blockdevice\n* [`ba13b6786`](https://github.com/siderolabs/talos/commit/ba13b678654e2896e1a99b1af8b51a9239b0a559) fix: correct condition to use UKI cmdline in GRUB\n* [`d2ce3f47f`](https://github.com/siderolabs/talos/commit/d2ce3f47f8515231f27983abaaf269a059e2e90d) docs: drop machine.network example\n* [`cf087c1e0`](https://github.com/siderolabs/talos/commit/cf087c1e01bc1226049a57186f48b2e6b5739c5c) test: bird2 extension\n* [`13df94388`](https://github.com/siderolabs/talos/commit/13df943884a59bd1d42721ba42bcb36349d40624) fix: adapt SELinuxSuite.TestNoPtrace to new strace version\n* [`861787c38`](https://github.com/siderolabs/talos/commit/861787c380bff3ba2fa29f49837bc173a2719578) fix: mark secureboot as supported for metal\n* [`04e3e87ad`](https://github.com/siderolabs/talos/commit/04e3e87adcbd24ee0d82dce4cc27121d34d316f4) fix: clean up kubelet mounts\n* [`21057903a`](https://github.com/siderolabs/talos/commit/21057903a2ca01d88cc5f97c084567d1981f73c5) fix: clear provisioning data on SideroLink config change\n* [`0f9f4c05f`](https://github.com/siderolabs/talos/commit/0f9f4c05ffad9413e1f1533c68eae38dc91c9716) feat: update Kubernetes to 1.35.0-rc.0\n* [`d4309d7b1`](https://github.com/siderolabs/talos/commit/d4309d7b1aec9d2852173fd704b09dfabe2cf217) fix: add a timeout for DNS resolving for NTP\n* [`dd6c1089c`](https://github.com/siderolabs/talos/commit/dd6c1089c8f30d815c80ab10544a0fef27ddd14c) feat: update Linux to 6.18.0\n* [`e9a30bf9a`](https://github.com/siderolabs/talos/commit/e9a30bf9a8ee55ab9ae5d9c9a18362434b0202ad) test: revert add direct connectivity CA rotation test\n* [`cc95562bc`](https://github.com/siderolabs/talos/commit/cc95562bc830496986a395cdde352d48d4a1d146) fix: don't disable LACP by default\n* [`c9fe4679b`](https://github.com/siderolabs/talos/commit/c9fe4679bf9c1dcdf175b95a02f1eaacab4ff085) test: add platform acquire/not valid config unit-test\n* [`5a03a7a20`](https://github.com/siderolabs/talos/commit/5a03a7a20acffa8eedf40524f8d070e37e41f24e) chore: fix longhorn test\n* [`a0cfc3527`](https://github.com/siderolabs/talos/commit/a0cfc3527481c4784edf87c3d7823b10a21d1e4d) feat: implement logs persistence\n* [`51b732bea`](https://github.com/siderolabs/talos/commit/51b732beabc9948e58f9aa4d81b79afb9bd61243) fix: selection of boot entry\n* [`18f8ac369`](https://github.com/siderolabs/talos/commit/18f8ac369ba52f2640508134d3983f006f698129) feat: update Kubernetes to 1.35.0-beta.0\n* [`92fa7c5e4`](https://github.com/siderolabs/talos/commit/92fa7c5e43da96a492003a2c9184cf818fbbb9f0) chore: update pkgs for NVIDIA 580.105.08\n* [`f489299b6`](https://github.com/siderolabs/talos/commit/f489299b603a2aff0f292fa941ae8925fdda3492) chore: correct condition for running k8s integration tests\n* [`ab149750d`](https://github.com/siderolabs/talos/commit/ab149750d475ef059debfc3730e9e0a32ad6e601) chore: update tools/pkgs to 1.13.0-alpha.0\n* [`87ff9f860`](https://github.com/siderolabs/talos/commit/87ff9f8606e04fe99e23261418a762372647b077) test: fix the image-factory test to pass IF endpoint\n* [`2ffe538e7`](https://github.com/siderolabs/talos/commit/2ffe538e7307f0ac3dbac2eba4b36ea98162ec78) test: add direct connectivity CA rotation test\n* [`70f6b80e0`](https://github.com/siderolabs/talos/commit/70f6b80e03acd507580211724cc51b7867bf8a76) chore(ci): skip multipath extension tests\n* [`561cfb60c`](https://github.com/siderolabs/talos/commit/561cfb60c313a9bdc70ed2ff2729549bc8c50fcb) chore: update pkgs and tools version\n* [`2f42202a7`](https://github.com/siderolabs/talos/commit/2f42202a7ccee0e33e43b2081929b5510db5d713) fix: simplify OOM expression\n* [`7b06ae8c2`](https://github.com/siderolabs/talos/commit/7b06ae8c2cf1069cb77cddee0986afc5af837bcc) test: fix flaky LinkSpec/Wireguard test\n* [`e715f3871`](https://github.com/siderolabs/talos/commit/e715f387137fa566a4824c051b624e013a93c49f) feat: present kernel log as `talosctl logs kernel`\n* [`e2ee39b8a`](https://github.com/siderolabs/talos/commit/e2ee39b8ac54ada49dd0a7ffaab4b0ae5d684792) fix: support specifying patch file without '@' symbol\n* [`e202b1f9e`](https://github.com/siderolabs/talos/commit/e202b1f9e82823aa5b31625024bce65bcc53b29f) fix: trim trailing dots from certificate SANs\n* [`7f7079f9c`](https://github.com/siderolabs/talos/commit/7f7079f9c0fbb30ce781aa1223d7df1a175a6206) fix: assign value of multicast setting properly\n* [`eba96141e`](https://github.com/siderolabs/talos/commit/eba96141e0afc147af9a8f1969e207501232b1de) feat: update etcd to 3.6.6\n* [`9945ceef3`](https://github.com/siderolabs/talos/commit/9945ceef37b13bc6e93637dcf395a8c9019e60ed) docs: add API Server Cipher Suites changelog\n* [`9ed488d09`](https://github.com/siderolabs/talos/commit/9ed488d09648c09a9a5c1ed6a5cd245b84cd415d) feat: update TLS cipher suites for API server\n* [`f1c04e4d6`](https://github.com/siderolabs/talos/commit/f1c04e4d6af14243a328d22bf810f27b13d83898) feat: generate mirrors patch\n* [`a89108995`](https://github.com/siderolabs/talos/commit/a89108995ff13fbbef0bf5cbf429cede5ff81078) fix: add CA subject to generated certificate\n* [`35dd612a5`](https://github.com/siderolabs/talos/commit/35dd612a5e59d8781e147fc36eb14f3e8bc66811) fix: add more resilient move\n* [`83675838f`](https://github.com/siderolabs/talos/commit/83675838f3655b44cbd850fd82b4d17acfb00c33) feat: extend flags of cache-cert-gen\n* [`80ab7a064`](https://github.com/siderolabs/talos/commit/80ab7a0643fc8057283a8ba3eb912d0ee453c143) chore: remove spammy 'clean up unused volumes' logs\n* [`74d35900a`](https://github.com/siderolabs/talos/commit/74d35900af0f6451426b70eec3b6db4b72eb993c) chore: disable k8s integration tests for 1GiB worker nodes\n* [`4f6218674`](https://github.com/siderolabs/talos/commit/4f621867407ec8f568f67833172ebaf2ff400346) feat: support TALOS_HOME env var\n* [`0c59b3ea3`](https://github.com/siderolabs/talos/commit/0c59b3ea3f6bc49cef409a1456b4ffa3bf1d28df) feat: add multicast to linkconfig\n* [`6db06f4d5`](https://github.com/siderolabs/talos/commit/6db06f4d5d51abd9e80ead6e4417f0f68856c569) feat: implement multicast setting\n* [`eeded98f5`](https://github.com/siderolabs/talos/commit/eeded98f527a230c65cb041a29fefc5f693d9879) fix: add riscv64 talosctl to release artifacts\n* [`a6bbae91b`](https://github.com/siderolabs/talos/commit/a6bbae91bad56328851fa91e01c17b8af7340b3c) fix: fix typos across the project\n* [`83f2bdb9c`](https://github.com/siderolabs/talos/commit/83f2bdb9ce6c9466716a6ac9c94dc2222e569ee8) feat: support relative voume size\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>33 commits</summary>\n<p>\n\n* [`972f44d`](https://github.com/siderolabs/pkgs/commit/972f44d5dae53809ef337544c52c835373439d34) feat: update dependencies\n* [`f8eb5b0`](https://github.com/siderolabs/pkgs/commit/f8eb5b02aaebaf76c59e71f57f4a689dc727e769) feat: update Linux to 6.18.2\n* [`3fb6291`](https://github.com/siderolabs/pkgs/commit/3fb629109a7e5f9650d0e641ff5076a29c319448) feat: update systemd to 259\n* [`59241bd`](https://github.com/siderolabs/pkgs/commit/59241bd58eeb07a18af1c9fc8fffff6365ecca0d) fix: add SBOMs for pigz/igzip\n* [`9377c78`](https://github.com/siderolabs/pkgs/commit/9377c786d112b4181f1e373f6e513130f11b7801) feat: optimize decompression for containerd\n* [`e8e61ce`](https://github.com/siderolabs/pkgs/commit/e8e61cedbbd687ed958db992e05b5d59e4a8ea60) feat: update containerd to 2.2.1\n* [`daa74ba`](https://github.com/siderolabs/pkgs/commit/daa74bab83f91bbc4b6c42625d2953299d5fe20a) feat: support xfs filesystem reproducibility\n* [`1f66513`](https://github.com/siderolabs/pkgs/commit/1f665130fbda76478c261dd54e3843c15027c9cd) feat: update OpenZFS to 2.4.0\n* [`b209af5`](https://github.com/siderolabs/pkgs/commit/b209af5baf1a67472ef431e5a8b7d48022392a1e) chore: rekres with latest changes\n* [`2b806b9`](https://github.com/siderolabs/pkgs/commit/2b806b9b2a7e05b97c2a7e8572e3a8edbd3721d3) feat: bump dependencies\n* [`65242fd`](https://github.com/siderolabs/pkgs/commit/65242fd0fef5c9c923aacce23d1655bad0d1b3e3) feat: enable CONFIG_MISC_RP1 in ARM64 config\n* [`4daecd8`](https://github.com/siderolabs/pkgs/commit/4daecd8e7b8d87110a9e552a60a5394014294e08) feat: update Linux to 6.18.1\n* [`9868a66`](https://github.com/siderolabs/pkgs/commit/9868a66e3c000f505c97ff68e61abac9c9e8e4c9) feat: enable Powercap and Intel RAPL\n* [`07883ee`](https://github.com/siderolabs/pkgs/commit/07883eee3729d4d3adaaebcd825452934c3baebb) feat: build and package perf binary\n* [`47abca0`](https://github.com/siderolabs/pkgs/commit/47abca0852b9555d88eba61661c65a7f93ec3590) fix: add json support to nftables binary\n* [`b961ff8`](https://github.com/siderolabs/pkgs/commit/b961ff898fc9eae68d7f3cea2ca22ff4d0b9c99d) feat: patch containerd 2.2.0 with cgroups fix patch\n* [`b7dd7f6`](https://github.com/siderolabs/pkgs/commit/b7dd7f6c809f670f058b78fd3b84f4cb977771cb) feat: add mstflint module\n* [`ae53351`](https://github.com/siderolabs/pkgs/commit/ae5335198e009da7b06bc0f0d6f42b0947650fc0) feat: update ZFS to 2.4.0-rc5\n* [`b8edf01`](https://github.com/siderolabs/pkgs/commit/b8edf0168171ffc5b87fcd962e37d5c2cd25b687) feat: update CNI plugins to v1.9.0\n* [`a57c1b0`](https://github.com/siderolabs/pkgs/commit/a57c1b0c9d143559a87b64fe9570eec39c14a771) feat: enable amd sev-snp\n* [`68562c1`](https://github.com/siderolabs/pkgs/commit/68562c1b4cdba656287021a1694440b2a7e4d24d) feat: update Linux to 6.18\n* [`6f4ff8c`](https://github.com/siderolabs/pkgs/commit/6f4ff8cc9f57452707588c05e5ca4e80c56548d2) feat: enable Amlogic Meson PCIe controller driver\n* [`c41127b`](https://github.com/siderolabs/pkgs/commit/c41127b94d22b9a5cb6b93f49b546f2ff477410c) feat: enable Intel GPIO/Pinctrl kernel modules\n* [`4a31ff7`](https://github.com/siderolabs/pkgs/commit/4a31ff7dd5c9266b68abded53a7399cb8102f4e3) feat: update NVIDIA LTS to 580.105.08\n* [`3e858d3`](https://github.com/siderolabs/pkgs/commit/3e858d3fa5b2719d8d83397fb89c2ffc91f86615) chore: fork pkgs for Talos 1.13\n* [`dcc5aa1`](https://github.com/siderolabs/pkgs/commit/dcc5aa1e71d6b2e9374d41029a2e6de22dbc61ce) feat: update runc to 1.3.4\n* [`8b6ae5b`](https://github.com/siderolabs/pkgs/commit/8b6ae5b7fc22c3bb2df4bbe31190ff90b0986e6f) fix: regenerate configs\n* [`2992598`](https://github.com/siderolabs/pkgs/commit/29925980896df1978a020505b2b061ffdbd240c7) fix: add missing kernel config entries\n* [`c8ea18a`](https://github.com/siderolabs/pkgs/commit/c8ea18a0873f5b31c54d567ef97d8d05634eb506) feat: rekres to alow multiple commits\n* [`2ddef8b`](https://github.com/siderolabs/pkgs/commit/2ddef8b65755610fc6dbb3f1fb976a6bc572478f) chore: update dependencies\n* [`d1f28e0`](https://github.com/siderolabs/pkgs/commit/d1f28e058972174af9ac819783a69f5f6596b37d) chore: update dependencies\n* [`ab253f5`](https://github.com/siderolabs/pkgs/commit/ab253f521d95b30710e258ebb54adbb7b8de8970) feat: enable gpio-fan module\n* [`0b10666`](https://github.com/siderolabs/pkgs/commit/0b1066635d9dd255bf0ad936e21099fd4bd03f1e) chore: use ubuntu mirrors\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>1 commit</summary>\n<p>\n\n* [`bd9c491`](https://github.com/siderolabs/proto-codec/commit/bd9c491b9e84d7274728ce7e3bde14009f5224bd) chore: bump and update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>7 commits</summary>\n<p>\n\n* [`896f8b9`](https://github.com/siderolabs/tools/commit/896f8b9c1f88cd190d11b8ef3baa2c36e73d6dfe) fix: add sbom for zlib-ng\n* [`543a16f`](https://github.com/siderolabs/tools/commit/543a16fedf7170d8b015ea1391817328205e629a) feat: replace zlib -> zlib-ng, add nasm\n* [`b67c1a1`](https://github.com/siderolabs/tools/commit/b67c1a168b302539d2082a5513c4a0130c30e4df) chore: rekres with latest changes\n* [`5e087cb`](https://github.com/siderolabs/tools/commit/5e087cbcd158db1ce4f447145bd76a24d07159a1) feat: bump dependencies\n* [`da96a27`](https://github.com/siderolabs/tools/commit/da96a2771801627b4715f7a13199aa6846f87732) chore: rekres to fix reproducibility\n* [`e283ec8`](https://github.com/siderolabs/tools/commit/e283ec8d3831bb19b26938afb10f4955ea563ce2) feat: update Go to 1.25.5\n* [`c38ff0c`](https://github.com/siderolabs/tools/commit/c38ff0c03be69e5cc3795d9dc055896604a3041c) chore: update to 1.13.0-alpha.0 toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go-v2/config**            v1.31.20 -> v1.32.6\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**  v1.18.13 -> v1.18.16\n* **github.com/aws/aws-sdk-go-v2/service/kms**       v1.46.0 -> v1.49.4\n* **github.com/aws/smithy-go**                       v1.23.2 -> v1.24.0\n* **github.com/containerd/cgroups/v3**               v3.0.5 -> v3.1.0\n* **github.com/containerd/containerd/api**           v1.9.0 -> v1.10.0\n* **github.com/containerd/containerd/v2**            v2.1.5 -> v2.2.0\n* **github.com/containerd/platforms**                v1.0.0-rc.1 -> v1.0.0-rc.2\n* **github.com/cosi-project/runtime**                v1.12.0 -> v1.13.0\n* **github.com/diskfs/go-diskfs**                    fc569a00ea19 **_new_**\n* **github.com/docker/cli**                          v29.0.0 -> v29.1.3\n* **github.com/gdamore/tcell/v2**                    v2.9.0 -> v2.13.4\n* **github.com/godbus/dbus/v5**                      v5.1.0 -> v5.2.0\n* **github.com/google/cadvisor**                     v0.53.0 -> v0.54.1\n* **github.com/google/go-containerregistry**         v0.20.6 -> v0.20.7\n* **github.com/hetznercloud/hcloud-go/v2**           v2.30.0 -> v2.32.0\n* **github.com/klauspost/compress**                  v1.18.1 -> v1.18.2\n* **github.com/linode/go-metadata**                  v0.2.2 -> v0.2.3\n* **github.com/mdlayher/ethtool**                    v0.4.0 -> v0.5.0\n* **github.com/miekg/dns**                           v1.1.68 -> v1.1.69\n* **github.com/moby/moby/client**                    v0.1.0 -> v0.2.1\n* **github.com/siderolabs/go-blockdevice/v2**        v2.0.20 -> v2.0.22\n* **github.com/siderolabs/pkgs**                     v1.12.0-23-ge0b78b8 -> v1.13.0-alpha.0-24-g972f44d\n* **github.com/siderolabs/proto-codec**              v0.1.2 -> v0.1.3\n* **github.com/siderolabs/talos/pkg/machinery**      v1.12.0 -> v1.12.0-alpha.2\n* **github.com/siderolabs/tools**                    v1.12.0-2-g7d57df0 -> v1.13.0-alpha.0-6-g896f8b9\n* **github.com/sirupsen/logrus**                     v1.9.3 -> dd1b4c2e81af\n* **go.etcd.io/etcd/api/v3**                         v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/client/v3**                      v3.6.6 -> v3.6.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.6.6 -> v3.6.7\n* **go.uber.org/zap**                                v1.27.0 -> v1.27.1\n* **golang.org/x/net**                               v0.47.0 -> v0.48.0\n* **golang.org/x/oauth2**                            v0.33.0 -> v0.34.0\n* **golang.org/x/sync**                              v0.18.0 -> v0.19.0\n* **golang.org/x/sys**                               v0.38.0 -> v0.39.0\n* **golang.org/x/term**                              v0.37.0 -> v0.38.0\n* **golang.org/x/text**                              v0.31.0 -> v0.32.0\n* **google.golang.org/grpc**                         v1.76.0 -> v1.77.0\n* **google.golang.org/protobuf**                     v1.36.10 -> v1.36.11\n\nPrevious release can be found at [v1.12.0](https://github.com/siderolabs/talos/releases/tag/v1.12.0)\n\n## [Talos 1.12.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.12.0-alpha.2) (2025-10-28)\n\nWelcome to the v1.12.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Disk Encryption\n\nTalos versions prior to v1.12 used the state of PCR 7 and signed policies locked to PCR 11 for TPM based disk encryption.\n\nTalos now supports configuring which PCRs states are to be used for TPM based disk encryption via the `options.pcrs`\nfield in the `tpm` section of the disk encryption configuration.\n\nIf user doesn't specify any options Talos defaults to using PCR 7 for backwards compatibility with existing installations.\n\nThis change was made to improve compatibility with systems that may have varying states in PCR 7 due to UEFI Secure Boot configurations\nand users may wish to disable locking to PCR 7 state entirely.\n\nSigned PCR policies will still be bound to PCR 11.\n\nThe currently used PCR's can be seen with `talosctl get volumestatus <volume> -o yaml` command.\n\n\n### Embedded Config\n\nTalos Linux now supports [embedding the machine configuration](https://www.talos.dev/v1.12/talos-guides/configuration/acquire/) directly into the boot image.\n\n\n### etcd\n\netcd container image is now pulled from `registry.k8s.io/etcd` instead of `gcr.io/etcd-development/etcd`.\n\n\n### Ethernet Configuration\n\nThe Ethernet configuration now includes a `wakeOnLAN` field to enable Wake-on-LAN (WOL) support.\nThis field can be set to enable WOL and specify the desired WOL modes.\n\n\n### Extra Binaries\n\nTalos Linux now ships with `nft` binary in the rootfs to support CNIs which shell out to `nft` command.\n\n\n### Feature Lock\n\nTalos now ignores the following machine configuration fields:\n\n- `machine.features.rbac` (locked to true)\n- `machine.features.apidCheckExtKeyUsage` (locked to true)\n- `cluster.apiServer.disablePodSecurityPolicy` (locked to false)\n\nThese fields were removed from the default machine configuration schema in v1.12 and are now always set to the locked values above.\n\n\n### GRUB\n\nTalos Linux introduces new machine configuration option `.machine.install.grubUseUKICmdline` to control whether GRUB should use the kernel command line \nprovided by the boot assets (UKI) or to use the command line constructed by Talos itself (legacy behavior).\n\nThis option defaults to `true` for new installations, which means that GRUB will use the command line from the UKI, making it easier to customize kernel parameters via boot asset generation.\nFor existing installations upgrading to v1.12, this option will default to `false` to preserve the legacy behavior.\n\n\n### Kernel Module\n\nTalos now supports optionally disabling kernel module signature verification by setting `module.sig_enforce=0` kernel parameter.\nBy default module signature verification is enabled (`module.sig_enforce=1`).\nWhen using Factory or Imager supply as `-module.sig_enfore module.sig_enforce=0` kernel parameters to disable module signature enforcement.\n\n\n### Kernel Security Posture Profile (KSPP)\n\nTalos now enables a stricter set of KSPP sysctl settings by default.\nThe list of overridden settings is available with `talosctl get kernelparamstatus` command.\n\n\n### Encrypted Volumes\n\nTalos Linux now consistently provides mapped names for encrypted volumes in the format `/dev/mapper/luks2-<volume-id>`.\nThis change should not affect system or user volumes, but might allow easier identification of encrypted volumes,\nand specifically for raw encrypted volumes.\n\n\n### talosctl image cache-serve\n\n`talosctl` includes new subcommand `image cache-serve`.\nIt allows serving the created OCI image registry over HTTP/HTTPS.\nIt is a read-only registry, meaning images cannot be pushed to it, but the backing storage can be updated by re-running the `cache-create` command;\n\nAdditionally `talosctl image cache-create` has some changes:\n  * new flag `--layout`: `oci` (_default_), `flat`:\n    * `oci` preserves current behavior;\n    * `flat` does not repack artifact layer, but moves it to a destination directory, allowing it to be served by `talosctl image cache-serve`;\n  * changed flag `--platform`: now can accept multiple os/arch combinations:\n    * comma separated (`--platform=linux/amd64,linux/arm64`);\n    * multiple instances (`--platform=linux/amd64 --platform=linux/arm64`);\n\n\n### Component Updates\n\nLinux: 6.17.5\nKubernetes: 1.35.0-alpha.2\nCNI Plugins: 1.8.0\ncryptsetup: 2.8.1\nLVM2: 2_03_34\nsystemd-udevd: 257.8\nrunc: 1.3.2\nCoreDNS: 1.13.0\netcd: 3.6.5\nFlannel: 0.27.4\nFlannel CNI plugin: v1.8.0-flannel1\n\nTalos is built with Go 1.25.3.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Mateusz Urbanek\n* Dmitrii Sharshakov\n* Amarachi Iheanacho\n* Orzelius\n* Oguz Kilcan\n* Utku Ozdemir\n* George Gaál\n* Jorik Jonker\n* Justin Garrison\n* Michael Smith\n* 459below\n* Alp Celik\n* Andrew Longwill\n* Chris Sanders\n* Dmitry\n* Febrian\n* Florian Grignon\n* Fred Heinecke\n* Giau. Tran Minh\n* Grzegorz Rozniecki\n* Guillaume LEGRAIN\n* Markus Freitag\n* Max Makarov\n* Mike Beaumont\n* Misha Aksenov\n* MrMrRubic\n* Olivier Doucet\n* Sammy ETUR\n* Serge Logvinov\n* Skyler Mäntysaari\n* SuitDeer\n* Tom\n* aurh1l\n* frozenprocess\n* frozensprocess\n* kassad\n* leppeK\n* samoreno\n* theschles\n* winnie\n\n### Changes\n<details><summary>245 commits</summary>\n<p>\n\n* [`3d811a4c8`](https://github.com/siderolabs/talos/commit/3d811a4c81e010b157b277499d272dc0e934baa9) release(v1.12.0-alpha.2): prepare release\n* [`fb4bfe851`](https://github.com/siderolabs/talos/commit/fb4bfe851c7c308eeaf4a11e0ac5c944f66dc0c4) chore: fix LVM test\n* [`f4ee0d112`](https://github.com/siderolabs/talos/commit/f4ee0d1128ba2f35d54ec3d35a83fc62fd222f2e) chore: disable VIP operator test\n* [`288f63872`](https://github.com/siderolabs/talos/commit/288f6387260843570d53d28a4d77e564b3182979) feat: bump deps\n* [`b66482c52`](https://github.com/siderolabs/talos/commit/b66482c529beda8b1abf9ed6b71ece354c1540be) feat: allow disabling injection of extra cmdline in cluster create\n* [`704b5f99e`](https://github.com/siderolabs/talos/commit/704b5f99e6bef4410629427ac65fd2742ddb335d) feat: update Kubernetes to 1.35.0-alpha.2\n* [`1dffa5d99`](https://github.com/siderolabs/talos/commit/1dffa5d9965a6c7d872f052bfb1750ea550671c2) feat: implement virtual IP operator config\n* [`43b1d7537`](https://github.com/siderolabs/talos/commit/43b1d7537507a916629cc2d6db7440a99ffcb748) fix: validate provisioner when destroying local clusters\n* [`b494c54c8`](https://github.com/siderolabs/talos/commit/b494c54c81e6ca81cef8ce26da772c1fc336ea8d) fix: talos import on non-linux\n* [`61e95cb4b`](https://github.com/siderolabs/talos/commit/61e95cb4b7b354d175d1dfce3d0fa43deefad187) feat: support bootloader option for ISO\n* [`d11072726`](https://github.com/siderolabs/talos/commit/d110727263c57c02392f201938d2b71976b8c4d6) fix: provide offset for partitions in discovered volumes\n* [`39eeae963`](https://github.com/siderolabs/talos/commit/39eeae96311be2b8e2d3660d878f852ba92ca064) feat: update dependencies\n* [`9890a9a31`](https://github.com/siderolabs/talos/commit/9890a9a31deb11ab170b94c667143314db08f76f) test: fix OOM test\n* [`c0772b8ed`](https://github.com/siderolabs/talos/commit/c0772b8eda429675a06899b9c4a4d1dd7d5f6a5f) feat: add airgapped mode to QEMU backed talos\n* [`ac60a9e27`](https://github.com/siderolabs/talos/commit/ac60a9e27deed63db0e4e61ffa30d46f4cab590a) fix: update test for PCI driver rebind/IOMMU\n* [`6c98f4cdb`](https://github.com/siderolabs/talos/commit/6c98f4cdb049c58ef4f6e8193ef66c2338a2877d) feat: implement new DHCP network configuration\n* [`da92a756d`](https://github.com/siderolabs/talos/commit/da92a756d9668fa043b4794db45d5c985d8ea4a6) fix: drop 'ro' falg from defaults\n* [`28fd2390c`](https://github.com/siderolabs/talos/commit/28fd2390cb6e02f400bb237dd674c7d0d40f8ed3) fix: imager build on arm64\n* [`4e12df8c5`](https://github.com/siderolabs/talos/commit/4e12df8c5c27ae115c4eac70a7e2fceb03dac5f5) test: integration test for OOM controller\n* [`7e498faba`](https://github.com/siderolabs/talos/commit/7e498faba93f972ba82edf41550d3b94256e83e9) feat: use image signer\n* [`eccb21dd3`](https://github.com/siderolabs/talos/commit/eccb21dd3ba03eb4ab03c4da87a51a4e3d8da49a) feat: add presets to the 'cluster create qemu' command\n* [`ec0a813fa`](https://github.com/siderolabs/talos/commit/ec0a813facf5be5ca3e9ba65924ae18b2b05a7d9) feat: unify cmdline handling GRUB/systemd-boot\n* [`37e4c40c6`](https://github.com/siderolabs/talos/commit/37e4c40c6a2477e45bbf067effc4389d4639c905) fix: skip module signature tests on docker provisioner only\n* [`8124efb42`](https://github.com/siderolabs/talos/commit/8124efb42fd5a3eb81f41e84974e4242246ca7c4) fix: cache e2e\n* [`4adcda0f5`](https://github.com/siderolabs/talos/commit/4adcda0f5427e1bae49f6dda58318324a3b24ac5) fix: reserve the apid and trustd ports from the ephemeral port range\n* [`ced57b047`](https://github.com/siderolabs/talos/commit/ced57b047a389e26f7e5bfa3efab5b64f3fced87) feat: support optionally disabling module sig verification\n* [`1e5c4ed64`](https://github.com/siderolabs/talos/commit/1e5c4ed644cbc60d8518fe4298e63a5cf5dc8cf5) fix: build talosctl image cache-serve non-linux\n* [`dbdd2b237`](https://github.com/siderolabs/talos/commit/dbdd2b237e0aefbba439b90472abf9ec7eea6aa6) feat: add static registry to talosctl\n* [`77d8cc7c5`](https://github.com/siderolabs/talos/commit/77d8cc7c589a190c8cb86e6e1684233129b648a1) chore: push `latest` tag only on main\n* [`59d9b1c75`](https://github.com/siderolabs/talos/commit/59d9b1c75dbff09e405906ebcfb3ad1a69cb8f4b) feat: update dependencies\n* [`bf6ad5171`](https://github.com/siderolabs/talos/commit/bf6ad51710c367764e582ccc1fb77b4d989c874d) feat: add back install script\n* [`da451c5ba`](https://github.com/siderolabs/talos/commit/da451c5ba4ee97e7ef108bb6d73d5aa8bc7c72fd) chore: drop documentation except for fresh reference\n* [`2f23fedeb`](https://github.com/siderolabs/talos/commit/2f23fedeb725a5786b6ffac2aef8125eecd6cb6e) fix: file leak in reading cgroups\n* [`b412ffdbc`](https://github.com/siderolabs/talos/commit/b412ffdbc29d77a81aed88be62f21bc2999afcde) docs: update README.md for docs link\n* [`8dc51bae7`](https://github.com/siderolabs/talos/commit/8dc51bae79a37b56c058d40787dbda6e828fd0d3) feat: add drm_gpuvm and drm_gpusvm_helper modules\n* [`4ca58aeb8`](https://github.com/siderolabs/talos/commit/4ca58aeb81145cb7ebef071865b3d853a4712729) fix: make Akamai platform usable\n* [`061f8e76f`](https://github.com/siderolabs/talos/commit/061f8e76fd58906ff823a0e467d6efcf5161ed9f) feat: bump pkgs\n* [`a9fa852da`](https://github.com/siderolabs/talos/commit/a9fa852dadd75740d73588fd2156f6f1ad782fdd) feat: update uefi image to talos linux logo\n* [`04753ba69`](https://github.com/siderolabs/talos/commit/04753ba6983b6ff2754cf62b8d60cc6065921dbd) feat: update go to 1.25.2\n* [`9a42b05bd`](https://github.com/siderolabs/talos/commit/9a42b05bdac2bf0cbbc97d040be7860f48c69386) feat: implement link aliasing\n* [`d732bd0be`](https://github.com/siderolabs/talos/commit/d732bd0be73c3d17d140c00be0e9d27ea621909b) chore(ci): run only nvidia tests for NVIDIA workflows\n* [`8d1468209`](https://github.com/siderolabs/talos/commit/8d1468209aa28f59df9dc52466c506defa8c3cc3) fix: stop populating apiserver cert SANs\n* [`02473244c`](https://github.com/siderolabs/talos/commit/02473244c17ef0149515f300bcd201f9347acabc) fix: wait for mount status to be proper mode\n* [`825622d90`](https://github.com/siderolabs/talos/commit/825622d90a7716f7b6027651a5b9389173432393) fix: resource proto definitions\n* [`2c6003e79`](https://github.com/siderolabs/talos/commit/2c6003e790003f6ef1a03b8d2af8030fb57c5d02) docs: add Project Calico installation in two mode\n* [`4fb4c8678`](https://github.com/siderolabs/talos/commit/4fb4c86780def54eed4d999b1f0ce93042269076) feat: add disk.EnableUUID to generated ova\n* [`33fb48f8f`](https://github.com/siderolabs/talos/commit/33fb48f8f90ccf44e95c93ac7ec1adcd1b4e0373) fix: add dashboard spinner\n* [`053fd0bd4`](https://github.com/siderolabs/talos/commit/053fd0bd4d324bc21e076b3a30466ed61c7684e1) feat: update Linux to 6.17\n* [`34e107e1b`](https://github.com/siderolabs/talos/commit/34e107e1bd14b0a56ebfa0c65e0c7da715976d99) docs: fix broken link\n* [`dfbece56b`](https://github.com/siderolabs/talos/commit/dfbece56bd45e95c9ec477af4b53ffcefdfec66c) docs: update the kubespan docs\n* [`8b041a72c`](https://github.com/siderolabs/talos/commit/8b041a72ca9c07985c024c1136c85c85df92beda) docs: update scaleway.md\n* [`435dcbf82`](https://github.com/siderolabs/talos/commit/435dcbf820cd9f8cc9fecc0f7d42819acef36106) fix: provide nocloud metadata with missing network config\n* [`ec3bd878f`](https://github.com/siderolabs/talos/commit/ec3bd878f9770ceb932b654aabad1711880da829) refactor: remove the go-blockdevice v1 completely\n* [`33544bde9`](https://github.com/siderolabs/talos/commit/33544bde9c15745f4ae692c7647d661b32d4bed4) fix: minor improvements to fs\n* [`fd2eebf7f`](https://github.com/siderolabs/talos/commit/fd2eebf7fa4831d33383a53d6d058c74789553e4) feat: create merge patch from diff of two machine configs\n* [`eadbdda94`](https://github.com/siderolabs/talos/commit/eadbdda9471289fae5159c8cc024a735a1547807) fix: uefi boot order setting\n* [`cd9fb2743`](https://github.com/siderolabs/talos/commit/cd9fb274342c5a973b3d087b991a7eea5df4142a) fix: support secure HTTP proxy with gRPC dial\n* [`adf87b4b9`](https://github.com/siderolabs/talos/commit/adf87b4b931ded1edeb64217b0e9d5edfd046004) feat: update Flannel to v0.27.4\n* [`5dfb7e1fe`](https://github.com/siderolabs/talos/commit/5dfb7e1fe7d9cc6db3e4c2b6f587e641b4a0842b) feat: serve etcd image from registry.k8s.io\n* [`5ca841804`](https://github.com/siderolabs/talos/commit/5ca8418049e3b878585014a3764021f2d30a0df7) fix: nftables flaky test\n* [`a940e45a7`](https://github.com/siderolabs/talos/commit/a940e45a7fe041b17437f774eb52b9f3a42e3633) feat: generate list of images required to build talos\n* [`3472d6e79`](https://github.com/siderolabs/talos/commit/3472d6e79caa13fd42df7774101397b0a30f62f5) fix: revert \"chore: use new mount/v3 package in efivarfs\"\n* [`42c0bdbf3`](https://github.com/siderolabs/talos/commit/42c0bdbf320bf24311b2d56b2e0f7155e86b3713) feat: add provisioner flag to images default command\n* [`6bc0b1bcf`](https://github.com/siderolabs/talos/commit/6bc0b1bcf7d9dc9f2417a7db63d1e76e7ddc6aa3) feat: drop and lock deprecated features\n* [`362a8e63b`](https://github.com/siderolabs/talos/commit/362a8e63b798c4a4fc31fe5e728d2429fc953166) fix: change the compression format\n* [`6e58f58aa`](https://github.com/siderolabs/talos/commit/6e58f58aaeb6e16883d8dc8757ad92b6b6da7e84) fix: mkdir artifacts path\n* [`3165a2b84`](https://github.com/siderolabs/talos/commit/3165a2b84cb80dd5fd09bf496fdccaf1628593d0) release(v1.12.0-alpha.1): prepare release\n* [`e455c7ea9`](https://github.com/siderolabs/talos/commit/e455c7ea9c919a2f70ddecceaa8f3b4e25566048) chore: use testing/synctest in tests\n* [`7f048e962`](https://github.com/siderolabs/talos/commit/7f048e962e217687ab67ed7027c5228e8ccb7d16) feat: update dependencies\n* [`fe36b3d32`](https://github.com/siderolabs/talos/commit/fe36b3d3200db57f3e21017ff7a4808b330a1d55) fix: stop returning EINVAL on remount of detached mounts\n* [`c6279e04c`](https://github.com/siderolabs/talos/commit/c6279e04c45504af243c0aef9f255317426b4ca0) chore: use new mount/v3 package in efivarfs\n* [`d5197effb`](https://github.com/siderolabs/talos/commit/d5197effb0b48290d613140b68796cb8f30b9a70) feat: update etcd 3.6.5, CoreDNS 1.12.4\n* [`33714b715`](https://github.com/siderolabs/talos/commit/33714b7158a0d569be1d0b1d7b012280856db484) feat: release cloud image using factory\n* [`d10a2747e`](https://github.com/siderolabs/talos/commit/d10a2747e0e835876aff158e6b6f7882cef9fa44) docs: deprecate JSON6902 patches and interactive installer\n* [`1e604cbf5`](https://github.com/siderolabs/talos/commit/1e604cbf514bece1e112d8afd5d1cd6ccb1045c3) fix: don't set broadcast for /31 and /32 addresses\n* [`65a66097a`](https://github.com/siderolabs/talos/commit/65a66097a05e5c0e2334d5eff494a0e71534716f) refactor: split cluster create logic into smaller parts\n* [`ab847310e`](https://github.com/siderolabs/talos/commit/ab847310efde540b5bfe17570b99af1bb705832b) fix: provide refreshing CA pool (resolvers)\n* [`d63c3ed7d`](https://github.com/siderolabs/talos/commit/d63c3ed7db2b22f7e394fc45d101d03cba463177) docs: update secureboot docs\n* [`493f7ed9d`](https://github.com/siderolabs/talos/commit/493f7ed9d2710eb240eab6b6ab532f41abc818c1) feat: support embedded config\n* [`251df70f6`](https://github.com/siderolabs/talos/commit/251df70f6d33f1d5a3b1b9e4c0c249d8bc85c4b3) feat: add a userspace OOM controller\n* [`7bae5b40b`](https://github.com/siderolabs/talos/commit/7bae5b40b4f22f0f07a586ebd9cda9436086a5f8) feat: implement link configuration\n* [`724857dec`](https://github.com/siderolabs/talos/commit/724857decb95ddeebb2ac5d33c38a71bf7512805) fix(ci): skip netbird extension for tests\n* [`e06a08698`](https://github.com/siderolabs/talos/commit/e06a086989331f28406e8d4234e02d9a6b83f87d) fix: default gateway as string\n* [`7ed07412e`](https://github.com/siderolabs/talos/commit/7ed07412e963e6ee91615adbea095944aa6a56e5) fix: uefi boot entry handling logic\n* [`ea4ed165a`](https://github.com/siderolabs/talos/commit/ea4ed165ad860a5beea17ca2d404bdaa6e5ad933) refactor: efivarfs mock and tests\n* [`1fca111e2`](https://github.com/siderolabs/talos/commit/1fca111e24bcae81b78f007e67b71c9155c0169f) feat: support setting wake-on-lan for Ethernet\n* [`94f78dbe7`](https://github.com/siderolabs/talos/commit/94f78dbe798cb227a0c38b70a1d6840803989290) docs: add a documentation for running Talos in KVM\n* [`46902f8fd`](https://github.com/siderolabs/talos/commit/46902f8fdee257a09be4bc1753c6b3f845ef8089) docs: add TrueFullstaq to adopters\n* [`a28e5cbd5`](https://github.com/siderolabs/talos/commit/a28e5cbd50d11aa6c253a6a9ce1999b9d45effad) chore: update pkgs and tools\n* [`7cf403db8`](https://github.com/siderolabs/talos/commit/7cf403db8ca0e1719195001895cfbc12835b0fdd) docs: step-by-step scaleway documentation to get an image\n* [`687285fa2`](https://github.com/siderolabs/talos/commit/687285fa26ec42dadbfb72580099f6e20bbaf85e) docs: remove 'curl' in wget command\n* [`9db6dc06c`](https://github.com/siderolabs/talos/commit/9db6dc06c3010cd89ce4cb0ec0bde178db0447a4) feat: stop mounting state partition\n* [`53ce93aae`](https://github.com/siderolabs/talos/commit/53ce93aaed3bd5bfcbe926fa69ca3b4b8b45c74f) test: try to clear connection refused more aggressively\n* [`51db5279c`](https://github.com/siderolabs/talos/commit/51db5279c423e4b8637a05e52b26dfc5aa719cbc) fix: bump trustd memory limit\n* [`25204dc8a`](https://github.com/siderolabs/talos/commit/25204dc8a8df79bc876a0bec2492e1147a81d954) fix(machined): change `constants.MinimumGOAMD64Level` using build tag\n* [`9cd2d794d`](https://github.com/siderolabs/talos/commit/9cd2d794d060b637dbac5263ae417a4e83d54efe) feat: ship nft binary with Talos rootfs\n* [`b1416c9fe`](https://github.com/siderolabs/talos/commit/b1416c9fe1d5ea9cd68f9b6b766a288a267cee61) feat: record last log the failed service\n* [`0b129f9ef`](https://github.com/siderolabs/talos/commit/0b129f9efdf57dd9692f7cece6b97719a7ccf80e) feat: enforce more KSPP and hardening sysctls\n* [`11872643c`](https://github.com/siderolabs/talos/commit/11872643c310212c52b4fd7e13b6cc7d6ec7e4fc) chore: drop docs folder\n* [`d30fdcd88`](https://github.com/siderolabs/talos/commit/d30fdcd88f421824cf17b9ecec25be7c8044e857) chore: pass in github token to imager\n* [`b88f27d80`](https://github.com/siderolabs/talos/commit/b88f27d804d60a706f598b50676dad5dd2a9726a) chore: make reset test code a bit better\n* [`1cde53d01`](https://github.com/siderolabs/talos/commit/1cde53d0173fd1ae637855e15fe34bb74bb027a0) test: fix several issues with tests\n* [`16cd127a0`](https://github.com/siderolabs/talos/commit/16cd127a04bb5fc907b7ca04f1c81d4c7150eab2) docs: add docs on updating image cache\n* [`c3ae92b14`](https://github.com/siderolabs/talos/commit/c3ae92b1424d4a2c9bc18cfa394b10eda6c9a20f) fix: build kernel checks only on linux\n* [`2120904ec`](https://github.com/siderolabs/talos/commit/2120904ec534a91f66dcea419b5a29e36a16f6e4) feat: create detached tmpfs\n* [`6bbee6de5`](https://github.com/siderolabs/talos/commit/6bbee6de5b18b25deb4e6f515251187e259aa424) docs: remove 'ceph-data' from volume examples/docs\n* [`07acb3bd2`](https://github.com/siderolabs/talos/commit/07acb3bd2d4f92e80706d1835130bbe6e944d096) fix: use correct order to determine SideroV1 keys directory path\n* [`2d57fa002`](https://github.com/siderolabs/talos/commit/2d57fa00281f8090b85097c66df634101b0cde79) fix: trim zero bytes in the DHCP host & domain response\n* [`451cb5f78`](https://github.com/siderolabs/talos/commit/451cb5f78fac3b2ddfec7d545629fe8c88ea2367) docs: clarify disk partition confusion\n* [`a2122ee5c`](https://github.com/siderolabs/talos/commit/a2122ee5cb9c84f33e0c4b30e9223bb239621d55) feat: implement HostConfig multi-doc\n* [`69ab076b4`](https://github.com/siderolabs/talos/commit/69ab076b4d6e52484677ee7f68a853dc4edfe2bc) fix: re-create cgroups when restarting runners\n* [`297b5cc28`](https://github.com/siderolabs/talos/commit/297b5cc2856710b74b4e0e46b00ae33aea4c1bf7) docs: add docs on node labels\n* [`e168512dd`](https://github.com/siderolabs/talos/commit/e168512dd020da9eac654dae2ba891cf33415c44) fix: apply 'ro' flag to iso9660 filesystems\n* [`7f7acfbb9`](https://github.com/siderolabs/talos/commit/7f7acfbb9f10c243d0b132c1ef079cb77d2727e0) docs: fix typo in doc\n* [`d57882b18`](https://github.com/siderolabs/talos/commit/d57882b1830504fe4bfd5344edae613168db7f0e) feat: update Kubernetes to 1.34.1\n* [`f85f82f32`](https://github.com/siderolabs/talos/commit/f85f82f32f098f97588f404550f72d64786fe329) test: fix flakiness in RawVolumes test\n* [`82569e319`](https://github.com/siderolabs/talos/commit/82569e319eb57b1199db6bfd3e612fb771c8c7cd) feat: update Linux 6.16.6\n* [`2fd2ab4e4`](https://github.com/siderolabs/talos/commit/2fd2ab4e43e06910154705d6ef1d0576a7c04a2b) fix: remove CoreDNS cpu limit\n* [`ce9bc32a0`](https://github.com/siderolabs/talos/commit/ce9bc32a08695873d9054afe2608a76cf7c6088a) chore(ci): rekres to use new runner groups\n* [`8b64f68f6`](https://github.com/siderolabs/talos/commit/8b64f68f6946c2979f6fe2bf617f31639a927bf8) test: improve test stability\n* [`272cb860d`](https://github.com/siderolabs/talos/commit/272cb860d4cfb8464b29ff31567e25fe6c275849) chore: drop the --input-dir flag from the cluster create command\n* [`1b6533675`](https://github.com/siderolabs/talos/commit/1b65336752933acdcbf681767785157714866f88) docs: add note about ca-signed certs for secureboot\n* [`d3f88f50c`](https://github.com/siderolabs/talos/commit/d3f88f50c5394536ee80d19464359408a37d81ff) docs: document talos vip failover behavior\n* [`005fc8bd5`](https://github.com/siderolabs/talos/commit/005fc8bd50fbc4b15b26032b43d1d32c1da22f11) docs: add docs on syncing configs after a kube upgrade\n* [`4d876d9af`](https://github.com/siderolabs/talos/commit/4d876d9af9fcc9828f09d05db124fbdce9c17785) feat: update Go to 1.25.1\n* [`2b556cd22`](https://github.com/siderolabs/talos/commit/2b556cd22a3563f1d86a648ea6c69a4d45edad76) feat: implement multi-doc StaticHostConfig\n* [`a7b776842`](https://github.com/siderolabs/talos/commit/a7b7768420566b6840fc52bb2152e9bf165f8cd3) docs: replace Raspberry Pi 5 links with Talos builder\n* [`a349b20ed`](https://github.com/siderolabs/talos/commit/a349b20ed4b3c05dcd0175541b795331f0f7c64d) docs: clarify that talos does not support intermediate ca\n* [`895133de9`](https://github.com/siderolabs/talos/commit/895133de99158ce3f50b557b77c81d4f0f9d6b40) feat: support configuring PCR states to bind disk encryption\n* [`c1360103b`](https://github.com/siderolabs/talos/commit/c1360103b5e037cf713b7d787436f01e7182821c) docs: fix command for uploading image on Hetzner\n* [`43b5b9d89`](https://github.com/siderolabs/talos/commit/43b5b9d8992ad6df37619b3719b57948e4bd9671) fix: correctly handle status-code 204\n* [`feeb0d312`](https://github.com/siderolabs/talos/commit/feeb0d312ecacb451e5313390939c7c9349d2ba6) feat: update runc to 1.3.1\n* [`421634a14`](https://github.com/siderolabs/talos/commit/421634a1417f529551a75d0bb9be08b73f1120b1) docs: add docs on multihoming\n* [`41af2d230`](https://github.com/siderolabs/talos/commit/41af2d230c2dd5dce5bc931f76a2eb69405dc554) refactor: clean up internal cluster creation code\n* [`3000d9e43`](https://github.com/siderolabs/talos/commit/3000d9e431deaf952d08da724da40789cd743f2c) fix: don't bootstrap talos cluster if there's no config present\n* [`79cb871d0`](https://github.com/siderolabs/talos/commit/79cb871d088e5b1c3a3488610ded14e7a28cec29) feat: use the id of the volume in the mapped luks2 name\n* [`6c322710d`](https://github.com/siderolabs/talos/commit/6c322710d64786f19e2e0e39d65596c8dce71952) chore: refactor mount package\n* [`ced7186e2`](https://github.com/siderolabs/talos/commit/ced7186e2a5f0634d9441b12a5340f5ca4c451ff) refactor: update COSI to 1.11.0\n* [`de2e24fcd`](https://github.com/siderolabs/talos/commit/de2e24fcda590a1ef3f80a5372bb70865a2f47c3) docs: clarify that install-cni image is deprecated\n* [`bef8ef509`](https://github.com/siderolabs/talos/commit/bef8ef509380aba259efcc2f5d1f6632e034160b) docs: add docs on cilium's compatibility with kubespan\n* [`e5acb10fc`](https://github.com/siderolabs/talos/commit/e5acb10fcceba69060507a35caea21281bdc71cc) feat: update pkgs\n* [`c4c1daf0e`](https://github.com/siderolabs/talos/commit/c4c1daf0e2e6675626b974b0c008e101d919c8b5) docs: add info about br_netfilter\n* [`5c52ecac3`](https://github.com/siderolabs/talos/commit/5c52ecac364f917e5f45859f680494a08f85cb90) docs: clarify interactive dashboard resolution control\n* [`15ecb02a4`](https://github.com/siderolabs/talos/commit/15ecb02a4545639ffb8ba5c6e5a413e53129b619) feat: update Linux kernel (memcg_v1, ublk)\n* [`53f18c2f6`](https://github.com/siderolabs/talos/commit/53f18c2f60c84c4b0f944cc343ae1f538e8d1236) fix: enable support for VMWare arm64\n* [`3bbe1c0da`](https://github.com/siderolabs/talos/commit/3bbe1c0da5485b6cd3e7fadd8f020e0d0aca406a) docs: add docs on grow flag\n* [`b9fb09dcd`](https://github.com/siderolabs/talos/commit/b9fb09dcdbcca60f695ac317c45e18fa092541a8) release(v1.12.0-alpha.0): prepare release\n* [`6a389cad3`](https://github.com/siderolabs/talos/commit/6a389cad35f80b27fe9c43db9e701ee9f6f6142a) chore: update dependencies\n* [`9d98c2e89`](https://github.com/siderolabs/talos/commit/9d98c2e891258dcf2ef90519d38d0aefb77cd0db) feat: add a cgroup preset for PSI and --skip-cri-resolve\n* [`072f77b16`](https://github.com/siderolabs/talos/commit/072f77b1623cdc838093465b7266b26e20a248ea) chore: prepare for future Talos 1.12-alpha.0 release\n* [`96f41ce88`](https://github.com/siderolabs/talos/commit/96f41ce8840783f783fcc8e0fd6b43302b9bfe43) docs: update qemu and docker docs\n* [`a751cd6b7`](https://github.com/siderolabs/talos/commit/a751cd6b7474a4dc20137e917dbb2229fe9cc8bd) docs: activate Talos v1.11 docs by default\n* [`e8f1ec1c5`](https://github.com/siderolabs/talos/commit/e8f1ec1c5bbd8a6cfb68886e6283e7caaf5fb063) docs: fix broken create qemu command v1.11 docs\n* [`639f0dfdd`](https://github.com/siderolabs/talos/commit/639f0dfdd88c5596439601f3f9600b3aafb24227) feat: update Linux to 6.16.4\n* [`8aa7b3933`](https://github.com/siderolabs/talos/commit/8aa7b3933d07ea45a96844b9c91347a08950e243) fix: bring back linux/armv7 build and update xz\n* [`9cae7ba6b`](https://github.com/siderolabs/talos/commit/9cae7ba6b97a67a5d282c6f667ccb4c3e2111447) feat: update CoreDNS to 1.12.3\n* [`cfef3ad45`](https://github.com/siderolabs/talos/commit/cfef3ad4544498a47de17f6b05fb8374c35e3dd8) fix: drop linux/armv7 build\n* [`42ea2ac50`](https://github.com/siderolabs/talos/commit/42ea2ac5058457dafe666f8d79f08d3c8ee60cfb) fix: update xz module (security)\n* [`4fcfd35b9`](https://github.com/siderolabs/talos/commit/4fcfd35b9510f45d0ef7ae3657eb0916d549d2dd) docs: fix module name example\n* [`50824599a`](https://github.com/siderolabs/talos/commit/50824599a4fa7b72d563a35a4746ca063becf672) chore: update some tools\n* [`bcd297490`](https://github.com/siderolabs/talos/commit/bcd297490c608f593b6dd274945aa2b73c3fd3ee) feat: allow Ed25119 in FIPS mode\n* [`5992138bb`](https://github.com/siderolabs/talos/commit/5992138bb981e84dae917f0f0fdafee4049bc5ec) test: ignore one leaking goroutine\n* [`d155326c1`](https://github.com/siderolabs/talos/commit/d155326c1206979f30a5355f7bdb23cb051e9b78) docs: add sbc unofficial ports docs\n* [`285fa7d22`](https://github.com/siderolabs/talos/commit/285fa7d222be1f5e63c0bb725b206966e2722a3b) docs: add the deploy application docs\n* [`527791f09`](https://github.com/siderolabs/talos/commit/527791f0974afe9c8558b82fa19f4354487693ed) feat: update Kubernetes to 1.34.0\n* [`a1c0e237d`](https://github.com/siderolabs/talos/commit/a1c0e237d6e047bb59c4fbd48e2c2b9e36dd4808) feat: update Linux to 6.15.11, Go to 1.25\n* [`4d7fc25f8`](https://github.com/siderolabs/talos/commit/4d7fc25f8bf20d4489080795a3d0ce0dfb1bc6b8) docs: switch order of wipe disk command\n* [`7368a994d`](https://github.com/siderolabs/talos/commit/7368a994df07cc4e50e3709ac766d8062db070a0) feat: add SOCKS5 proxy support to dynamic proxy dialer\n* [`d63591069`](https://github.com/siderolabs/talos/commit/d635910697b221aee3e9afa6d9e5b398236b6a21) chore: silence linter warnings\n* [`07eb4d7ec`](https://github.com/siderolabs/talos/commit/07eb4d7ec148a7e3c4c6dde080469c1a2fb410fb) fix: set default ram unit to MiB instead of MB\n* [`6b732adc4`](https://github.com/siderolabs/talos/commit/6b732adc43684facfd329f424a34a7e4df36d77b) feat: update Linux to 6.12.43\n* [`b6410914f`](https://github.com/siderolabs/talos/commit/b6410914f74ce01672fdef7e912e37970909281c) feat: add human readable byte size cli flags\n* [`ec70cef99`](https://github.com/siderolabs/talos/commit/ec70cef99005fd7e383fea63b5c23774882fcf28) feat: update NVIDIA drivers and kernel\n* [`0879efa69`](https://github.com/siderolabs/talos/commit/0879efa690ad657e4aed251fcbeba8f5645d73ce) feat: update Kubernetes default to v1.34.0-rc.2\n* [`f504639df`](https://github.com/siderolabs/talos/commit/f504639df4388619f731196ed8e79a6818b6ed5f) feat: add a user-facing create qemu command\n* [`558e0b09a`](https://github.com/siderolabs/talos/commit/558e0b09ab65b353e83b98c9ddf6cb2b67fd060e) test: fix the Image Factory PXE boot test\n* [`d73f0a2e5`](https://github.com/siderolabs/talos/commit/d73f0a2e5b788c7b69c2fb827f7111d5f9c8e706) docs: make readme badges consistent\n* [`f1369af98`](https://github.com/siderolabs/talos/commit/f1369af98e1f6d48fed137e31237956abbd28b0f) chore: use new filesystem api on STATE partition\n* [`366cedbe7`](https://github.com/siderolabs/talos/commit/366cedbe7495ce15bcd0e6c6f7f0add65a41a861) docs: link to kubernetes linux swap tuning\n* [`2f5a16f5e`](https://github.com/siderolabs/talos/commit/2f5a16f5e4ae186a309aef5e3d285897d0fe2df1) fix: make --with-uuid-hostnames functionality available to qemu provider\n* [`70612c1f9`](https://github.com/siderolabs/talos/commit/70612c1f9fc9056e8a3669ff10a385c4e8e03350) refactor: split the PlatformConfigController\n* [`511748339`](https://github.com/siderolabs/talos/commit/51174833997fd9a0a599ab1dde947834b682ab14) docs: add system extension tier documentation\n* [`009fb1540`](https://github.com/siderolabs/talos/commit/009fb1540e0b9f5daac6302f42e8813e596fc87c) test: don't run nvidia tests on integration/aws\n* [`99674ef20`](https://github.com/siderolabs/talos/commit/99674ef20d34166d60563d4bf46fbbfc57399509) docs: apply fixes for what is new\n* [`92db677b5`](https://github.com/siderolabs/talos/commit/92db677b5d32de32ec7e785531b32202e03283b4) fix: image cache lockup on a missing volume\n* [`9c97ed886`](https://github.com/siderolabs/talos/commit/9c97ed886b89b2fb84f47866abdf1000839143c4) fix: version contract parsing in encryption keys handling\n* [`1fc670a08`](https://github.com/siderolabs/talos/commit/1fc670a08dc7af8eaeabdc7134eb77a5c939df40) fix: dial with proxy\n* [`18447d0af`](https://github.com/siderolabs/talos/commit/18447d0afdbcc8fa7db6ae008e4bc4d5b0a0b00a) feat: update Linux to 6.12.41\n* [`f65f39b78`](https://github.com/siderolabs/talos/commit/f65f39b78b0c7881e5f51c66ad022c17c2cd4960) fix: provide mitigation CVE-1999-0524\n* [`8817cc60c`](https://github.com/siderolabs/talos/commit/8817cc60cfaf4b50f11c38d3b25df7df48382033) fix: actually use SIDEROV1_KEYS_DIR env var if it's provided\n* [`b08b20a10`](https://github.com/siderolabs/talos/commit/b08b20a1005256a9e3fc7cae8bcf8eea87f6ac09) feat: use key provider with fallback option for auth type SideroV1\n* [`7a52d7489`](https://github.com/siderolabs/talos/commit/7a52d7489c9709708d55f8f001d70700addc7e1e) fix: kubernetes upgrade options for kubelet\n* [`ea8289f55`](https://github.com/siderolabs/talos/commit/ea8289f550787593b1cd35f2d8da59aa5311880e) feat: add a user facing docker command\n* [`54ad64765`](https://github.com/siderolabs/talos/commit/54ad64765090d90013e4917d1bf494592069beec) chore: re-enable vulncheck\n* [`26bbddea9`](https://github.com/siderolabs/talos/commit/26bbddea95669278363c604316ed85986f312d71) fix: darwin build\n* [`b5d5ef79e`](https://github.com/siderolabs/talos/commit/b5d5ef79e7a2d76e29a7c872c1c418fffc63b0df) fix: set secs field in DHCPv4 packets\n* [`c07911933`](https://github.com/siderolabs/talos/commit/c0791193373e36c35f29c70318432331b4c6ab2a) chore: refactor how tools are being installed\n* [`34f25815c`](https://github.com/siderolabs/talos/commit/34f25815c036d2c91bdfddc9c7d40ca2edf677bd) docs: fork docs for v1.12\n* [`b66b995d3`](https://github.com/siderolabs/talos/commit/b66b995d34306192cbaa4ef68fe39f821b37d1f0) feat: update default Kubernetes to v1.34.0-rc.1\n* [`b967c587d`](https://github.com/siderolabs/talos/commit/b967c587d9f217f25798e0bee0c90393e55dc085) docs: fix clone URL to include `.git`\n* [`b72c68398`](https://github.com/siderolabs/talos/commit/b72c6839806103ac0a76acd46f30eabea0375790) docs: edit the insecure, etcd-metrics, inline and extramanifests\n* [`e5b9c1fff`](https://github.com/siderolabs/talos/commit/e5b9c1ffffec9fd49ffb84a36c918e75eaa8f1ef) docs: remov RAS Syndrome\n* [`701fe774b`](https://github.com/siderolabs/talos/commit/701fe774bd19de7c9f21e043e1520161a8c5fff7) docs: fix cilium links and bump to 1.18.0\n* [`d306713a1`](https://github.com/siderolabs/talos/commit/d306713a13a18d7af6caffd5890d54d91d22cad7) feat: update Go to 1.24.6\n* [`721595a00`](https://github.com/siderolabs/talos/commit/721595a0009f78a2722802ab665957fd767c4d1e) chore: add deadcode elimination linter\n* [`dc4865915`](https://github.com/siderolabs/talos/commit/dc4865915d567942adea3efa66f8ad360f9c4cce) refactor: stop using `text/template` in `machined` code paths\n* [`545be55ed`](https://github.com/siderolabs/talos/commit/545be55edc863245638d4387cb9ee7e7b068f2ba) feat: add a pause function to dashboard\n* [`06a6c0fe3`](https://github.com/siderolabs/talos/commit/06a6c0fe332940b7a70ea2652bc2a5e7bc51bbf3) refactor: fix deadcode elimination with godbus\n* [`2dce8f8d4`](https://github.com/siderolabs/talos/commit/2dce8f8d4693a85d2f3bf46169af8cf502d49f9d) refactor: replace containerd/containerd/v2 module for proper DCE\n* [`9b11d8608`](https://github.com/siderolabs/talos/commit/9b11d86081df8cf77860d2d27eed5d8001ff721e) chore: rekres to configure slack notify workflow for CI failures\n* [`5ce6a660f`](https://github.com/siderolabs/talos/commit/5ce6a660f67f4e2776550a1e621179beb8a6788c) docs: augment the pod security docs\n* [`ada51ff69`](https://github.com/siderolabs/talos/commit/ada51ff696011e15dcd9c661da1d839bdc341745) fix: unmarshal encryption STATE from META\n* [`b9e9b2e07`](https://github.com/siderolabs/talos/commit/b9e9b2e07a645f53ca23355810d485a2622870c9) docs: add what is new notes for 1.11\n* [`53055bdf4`](https://github.com/siderolabs/talos/commit/53055bdf49ce4c81f63c159cdbaa8ea85d9ca2b8) docs: fix typo in kubevirt page\n* [`8d12db480`](https://github.com/siderolabs/talos/commit/8d12db480c38ec37aee5ae7721b2e5ca55ad733e) fix: one more attempt to fix volume mount race on restart\n* [`34d37a268`](https://github.com/siderolabs/talos/commit/34d37a268a9e0098179369af128261dbfc956d1d) chore: rekres to use correct slack channel for slack-notify\n* [`326a00538`](https://github.com/siderolabs/talos/commit/326a00538210bf98b01795d314c1e154a74d2d58) feat: implement `talos.config.early` command line arg\n* [`a5f3000f2`](https://github.com/siderolabs/talos/commit/a5f3000f2e8a79d4e9a5be95fbcac91a2d78675b) feat: implement encryption locking to STATE\n* [`c1e65a342`](https://github.com/siderolabs/talos/commit/c1e65a34256944743e768613b119c0caa517b54d) docs: remove talos API flags from mgmt commands\n* [`181d0bbf5`](https://github.com/siderolabs/talos/commit/181d0bbf5381343d35a01190da45e3442320d7c5) feat: bootedentry resource\n* [`7ad439ac3`](https://github.com/siderolabs/talos/commit/7ad439ac35859695074d3a3efdcdb5c0cab1a5c6) fix: enforce minimum size on user volumes if not set explicitly\n* [`50e37aefd`](https://github.com/siderolabs/talos/commit/50e37aefdbde973bcc8aa352639946490fbe7d94) fix: live reload of TLS client config for discovery client\n* [`87efd75ef`](https://github.com/siderolabs/talos/commit/87efd75efb3e62b88b4f65a221f9fbdd4b4d6ef9) feat: update containerd to 2.1.4\n* [`724b9de6d`](https://github.com/siderolabs/talos/commit/724b9de6d5195bcccc5f484c696429b2f09ab16e) feat: add F71808E watchdog driver\n* [`8af96f7af`](https://github.com/siderolabs/talos/commit/8af96f7afdac1c4d5e2697b897b81e2bddd15f66) docs: add ETCD downgrade documentation\n* [`44edd205d`](https://github.com/siderolabs/talos/commit/44edd205d5fdffab39b65ee62695a40e22ef188c) docs: add remark about 'exclude-from-external-load-balancers' label\n* [`727101926`](https://github.com/siderolabs/talos/commit/7271019263b0dc5b28d2764d19fe531e473222fc) fix(ci): use a random suffix for ami names\n* [`d621ce372`](https://github.com/siderolabs/talos/commit/d621ce3726f20ee568ea3b6ac57d9e8dfa0580cc) fix: grype scan\n* [`d62e255c2`](https://github.com/siderolabs/talos/commit/d62e255c260810a5f0f2959e32592a3331df28d3) fix: issues with reading GPT\n* [`5d0883e14`](https://github.com/siderolabs/talos/commit/5d0883e147163c12a77cd926db799ffed854aedf) feat: update PCI DB module to v0.3.2\n* [`3751c8ccf`](https://github.com/siderolabs/talos/commit/3751c8ccfa1bab9fcd435290f36e9012a5626e40) test: wait for service account test job longer\n* [`a592eb9f9`](https://github.com/siderolabs/talos/commit/a592eb9f98788883a7ec6d17772e10707230a0d8) feat: update Linux to 6.12.40\n* [`4c40e6d3f`](https://github.com/siderolabs/talos/commit/4c40e6d3fb4c2f451a8d7a671df5f6254161bd5d) feat: update etcd to 3.6.4\n* [`2bc37bd2c`](https://github.com/siderolabs/talos/commit/2bc37bd2c9679c8055fd7b52eb310f23a329af4e) docs: fix error in kernel module guide\n* [`bfc57fb86`](https://github.com/siderolabs/talos/commit/bfc57fb863224f7626f49e5b26be06f77bea2e40) chore: tag aws snapshots created via ci with the image name\n* [`06ef7108a`](https://github.com/siderolabs/talos/commit/06ef7108a6050b3a8fd7535f01a469f09042bf56) fix: issue with volume remount on service restart\n* [`03efbff18`](https://github.com/siderolabs/talos/commit/03efbff18e420c4fe960f490f91dd9f4751ece04) docs: add SBOM documentation\n* [`af8a2869d`](https://github.com/siderolabs/talos/commit/af8a2869dbbec073ffaf72a1378682e109b053ec) fix: do not download artifacts for cron Grype scan\n* [`5f442159b`](https://github.com/siderolabs/talos/commit/5f442159b224c96c90badc7176fed17bfb561709) feat: unify disk encryption configuration\n* [`38e176e59`](https://github.com/siderolabs/talos/commit/38e176e594edb3d271d98f78417b9fd5ba0c5288) chore(ci): fix datasource versioning\n* [`85d6b9198`](https://github.com/siderolabs/talos/commit/85d6b919890a1aa9c4f94d5b18861cc617134ff9) feat: update etcd to v3.5.22\n* [`dd7bd2dab`](https://github.com/siderolabs/talos/commit/dd7bd2dab8cf09334e3e353d6a477509bbaa303e) docs: rewrite the getting started and prod docs for v1.10 and v1.11\n* [`136a899aa`](https://github.com/siderolabs/talos/commit/136a899aa25b3fdcdd771594668278d563f09192) chore: regenerate release step with signing fixes\n* [`450b30d5a`](https://github.com/siderolabs/talos/commit/450b30d5a986563869efdbaa074e82d612f6f2ef) chore(ci): add more nvidia test matrix\n* [`451c2c4c3`](https://github.com/siderolabs/talos/commit/451c2c4c39e70c20df58fc31459cd5c789a0e46f) test: add talosctl:latest to the image cache\n</p>\n</details>\n\n### Changes since v1.12.0-alpha.1\n<details><summary>66 commits</summary>\n<p>\n\n* [`3d811a4c8`](https://github.com/siderolabs/talos/commit/3d811a4c81e010b157b277499d272dc0e934baa9) release(v1.12.0-alpha.2): prepare release\n* [`fb4bfe851`](https://github.com/siderolabs/talos/commit/fb4bfe851c7c308eeaf4a11e0ac5c944f66dc0c4) chore: fix LVM test\n* [`f4ee0d112`](https://github.com/siderolabs/talos/commit/f4ee0d1128ba2f35d54ec3d35a83fc62fd222f2e) chore: disable VIP operator test\n* [`288f63872`](https://github.com/siderolabs/talos/commit/288f6387260843570d53d28a4d77e564b3182979) feat: bump deps\n* [`b66482c52`](https://github.com/siderolabs/talos/commit/b66482c529beda8b1abf9ed6b71ece354c1540be) feat: allow disabling injection of extra cmdline in cluster create\n* [`704b5f99e`](https://github.com/siderolabs/talos/commit/704b5f99e6bef4410629427ac65fd2742ddb335d) feat: update Kubernetes to 1.35.0-alpha.2\n* [`1dffa5d99`](https://github.com/siderolabs/talos/commit/1dffa5d9965a6c7d872f052bfb1750ea550671c2) feat: implement virtual IP operator config\n* [`43b1d7537`](https://github.com/siderolabs/talos/commit/43b1d7537507a916629cc2d6db7440a99ffcb748) fix: validate provisioner when destroying local clusters\n* [`b494c54c8`](https://github.com/siderolabs/talos/commit/b494c54c81e6ca81cef8ce26da772c1fc336ea8d) fix: talos import on non-linux\n* [`61e95cb4b`](https://github.com/siderolabs/talos/commit/61e95cb4b7b354d175d1dfce3d0fa43deefad187) feat: support bootloader option for ISO\n* [`d11072726`](https://github.com/siderolabs/talos/commit/d110727263c57c02392f201938d2b71976b8c4d6) fix: provide offset for partitions in discovered volumes\n* [`39eeae963`](https://github.com/siderolabs/talos/commit/39eeae96311be2b8e2d3660d878f852ba92ca064) feat: update dependencies\n* [`9890a9a31`](https://github.com/siderolabs/talos/commit/9890a9a31deb11ab170b94c667143314db08f76f) test: fix OOM test\n* [`c0772b8ed`](https://github.com/siderolabs/talos/commit/c0772b8eda429675a06899b9c4a4d1dd7d5f6a5f) feat: add airgapped mode to QEMU backed talos\n* [`ac60a9e27`](https://github.com/siderolabs/talos/commit/ac60a9e27deed63db0e4e61ffa30d46f4cab590a) fix: update test for PCI driver rebind/IOMMU\n* [`6c98f4cdb`](https://github.com/siderolabs/talos/commit/6c98f4cdb049c58ef4f6e8193ef66c2338a2877d) feat: implement new DHCP network configuration\n* [`da92a756d`](https://github.com/siderolabs/talos/commit/da92a756d9668fa043b4794db45d5c985d8ea4a6) fix: drop 'ro' falg from defaults\n* [`28fd2390c`](https://github.com/siderolabs/talos/commit/28fd2390cb6e02f400bb237dd674c7d0d40f8ed3) fix: imager build on arm64\n* [`4e12df8c5`](https://github.com/siderolabs/talos/commit/4e12df8c5c27ae115c4eac70a7e2fceb03dac5f5) test: integration test for OOM controller\n* [`7e498faba`](https://github.com/siderolabs/talos/commit/7e498faba93f972ba82edf41550d3b94256e83e9) feat: use image signer\n* [`eccb21dd3`](https://github.com/siderolabs/talos/commit/eccb21dd3ba03eb4ab03c4da87a51a4e3d8da49a) feat: add presets to the 'cluster create qemu' command\n* [`ec0a813fa`](https://github.com/siderolabs/talos/commit/ec0a813facf5be5ca3e9ba65924ae18b2b05a7d9) feat: unify cmdline handling GRUB/systemd-boot\n* [`37e4c40c6`](https://github.com/siderolabs/talos/commit/37e4c40c6a2477e45bbf067effc4389d4639c905) fix: skip module signature tests on docker provisioner only\n* [`8124efb42`](https://github.com/siderolabs/talos/commit/8124efb42fd5a3eb81f41e84974e4242246ca7c4) fix: cache e2e\n* [`4adcda0f5`](https://github.com/siderolabs/talos/commit/4adcda0f5427e1bae49f6dda58318324a3b24ac5) fix: reserve the apid and trustd ports from the ephemeral port range\n* [`ced57b047`](https://github.com/siderolabs/talos/commit/ced57b047a389e26f7e5bfa3efab5b64f3fced87) feat: support optionally disabling module sig verification\n* [`1e5c4ed64`](https://github.com/siderolabs/talos/commit/1e5c4ed644cbc60d8518fe4298e63a5cf5dc8cf5) fix: build talosctl image cache-serve non-linux\n* [`dbdd2b237`](https://github.com/siderolabs/talos/commit/dbdd2b237e0aefbba439b90472abf9ec7eea6aa6) feat: add static registry to talosctl\n* [`77d8cc7c5`](https://github.com/siderolabs/talos/commit/77d8cc7c589a190c8cb86e6e1684233129b648a1) chore: push `latest` tag only on main\n* [`59d9b1c75`](https://github.com/siderolabs/talos/commit/59d9b1c75dbff09e405906ebcfb3ad1a69cb8f4b) feat: update dependencies\n* [`bf6ad5171`](https://github.com/siderolabs/talos/commit/bf6ad51710c367764e582ccc1fb77b4d989c874d) feat: add back install script\n* [`da451c5ba`](https://github.com/siderolabs/talos/commit/da451c5ba4ee97e7ef108bb6d73d5aa8bc7c72fd) chore: drop documentation except for fresh reference\n* [`2f23fedeb`](https://github.com/siderolabs/talos/commit/2f23fedeb725a5786b6ffac2aef8125eecd6cb6e) fix: file leak in reading cgroups\n* [`b412ffdbc`](https://github.com/siderolabs/talos/commit/b412ffdbc29d77a81aed88be62f21bc2999afcde) docs: update README.md for docs link\n* [`8dc51bae7`](https://github.com/siderolabs/talos/commit/8dc51bae79a37b56c058d40787dbda6e828fd0d3) feat: add drm_gpuvm and drm_gpusvm_helper modules\n* [`4ca58aeb8`](https://github.com/siderolabs/talos/commit/4ca58aeb81145cb7ebef071865b3d853a4712729) fix: make Akamai platform usable\n* [`061f8e76f`](https://github.com/siderolabs/talos/commit/061f8e76fd58906ff823a0e467d6efcf5161ed9f) feat: bump pkgs\n* [`a9fa852da`](https://github.com/siderolabs/talos/commit/a9fa852dadd75740d73588fd2156f6f1ad782fdd) feat: update uefi image to talos linux logo\n* [`04753ba69`](https://github.com/siderolabs/talos/commit/04753ba6983b6ff2754cf62b8d60cc6065921dbd) feat: update go to 1.25.2\n* [`9a42b05bd`](https://github.com/siderolabs/talos/commit/9a42b05bdac2bf0cbbc97d040be7860f48c69386) feat: implement link aliasing\n* [`d732bd0be`](https://github.com/siderolabs/talos/commit/d732bd0be73c3d17d140c00be0e9d27ea621909b) chore(ci): run only nvidia tests for NVIDIA workflows\n* [`8d1468209`](https://github.com/siderolabs/talos/commit/8d1468209aa28f59df9dc52466c506defa8c3cc3) fix: stop populating apiserver cert SANs\n* [`02473244c`](https://github.com/siderolabs/talos/commit/02473244c17ef0149515f300bcd201f9347acabc) fix: wait for mount status to be proper mode\n* [`825622d90`](https://github.com/siderolabs/talos/commit/825622d90a7716f7b6027651a5b9389173432393) fix: resource proto definitions\n* [`2c6003e79`](https://github.com/siderolabs/talos/commit/2c6003e790003f6ef1a03b8d2af8030fb57c5d02) docs: add Project Calico installation in two mode\n* [`4fb4c8678`](https://github.com/siderolabs/talos/commit/4fb4c86780def54eed4d999b1f0ce93042269076) feat: add disk.EnableUUID to generated ova\n* [`33fb48f8f`](https://github.com/siderolabs/talos/commit/33fb48f8f90ccf44e95c93ac7ec1adcd1b4e0373) fix: add dashboard spinner\n* [`053fd0bd4`](https://github.com/siderolabs/talos/commit/053fd0bd4d324bc21e076b3a30466ed61c7684e1) feat: update Linux to 6.17\n* [`34e107e1b`](https://github.com/siderolabs/talos/commit/34e107e1bd14b0a56ebfa0c65e0c7da715976d99) docs: fix broken link\n* [`dfbece56b`](https://github.com/siderolabs/talos/commit/dfbece56bd45e95c9ec477af4b53ffcefdfec66c) docs: update the kubespan docs\n* [`8b041a72c`](https://github.com/siderolabs/talos/commit/8b041a72ca9c07985c024c1136c85c85df92beda) docs: update scaleway.md\n* [`435dcbf82`](https://github.com/siderolabs/talos/commit/435dcbf820cd9f8cc9fecc0f7d42819acef36106) fix: provide nocloud metadata with missing network config\n* [`ec3bd878f`](https://github.com/siderolabs/talos/commit/ec3bd878f9770ceb932b654aabad1711880da829) refactor: remove the go-blockdevice v1 completely\n* [`33544bde9`](https://github.com/siderolabs/talos/commit/33544bde9c15745f4ae692c7647d661b32d4bed4) fix: minor improvements to fs\n* [`fd2eebf7f`](https://github.com/siderolabs/talos/commit/fd2eebf7fa4831d33383a53d6d058c74789553e4) feat: create merge patch from diff of two machine configs\n* [`eadbdda94`](https://github.com/siderolabs/talos/commit/eadbdda9471289fae5159c8cc024a735a1547807) fix: uefi boot order setting\n* [`cd9fb2743`](https://github.com/siderolabs/talos/commit/cd9fb274342c5a973b3d087b991a7eea5df4142a) fix: support secure HTTP proxy with gRPC dial\n* [`adf87b4b9`](https://github.com/siderolabs/talos/commit/adf87b4b931ded1edeb64217b0e9d5edfd046004) feat: update Flannel to v0.27.4\n* [`5dfb7e1fe`](https://github.com/siderolabs/talos/commit/5dfb7e1fe7d9cc6db3e4c2b6f587e641b4a0842b) feat: serve etcd image from registry.k8s.io\n* [`5ca841804`](https://github.com/siderolabs/talos/commit/5ca8418049e3b878585014a3764021f2d30a0df7) fix: nftables flaky test\n* [`a940e45a7`](https://github.com/siderolabs/talos/commit/a940e45a7fe041b17437f774eb52b9f3a42e3633) feat: generate list of images required to build talos\n* [`3472d6e79`](https://github.com/siderolabs/talos/commit/3472d6e79caa13fd42df7774101397b0a30f62f5) fix: revert \"chore: use new mount/v3 package in efivarfs\"\n* [`42c0bdbf3`](https://github.com/siderolabs/talos/commit/42c0bdbf320bf24311b2d56b2e0f7155e86b3713) feat: add provisioner flag to images default command\n* [`6bc0b1bcf`](https://github.com/siderolabs/talos/commit/6bc0b1bcf7d9dc9f2417a7db63d1e76e7ddc6aa3) feat: drop and lock deprecated features\n* [`362a8e63b`](https://github.com/siderolabs/talos/commit/362a8e63b798c4a4fc31fe5e728d2429fc953166) fix: change the compression format\n* [`6e58f58aa`](https://github.com/siderolabs/talos/commit/6e58f58aaeb6e16883d8dc8757ad92b6b6da7e84) fix: mkdir artifacts path\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`4154a77`](https://github.com/siderolabs/crypto/commit/4154a771b09f0023e0d258bba6aecc29febabecb) feat: implement dynamic certificate reloader\n* [`dae07fa`](https://github.com/siderolabs/crypto/commit/dae07fa14f963b34ea67abf0cbc50ba24f280524) chore: update to Go 1.25\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>2 commits</summary>\n<p>\n\n* [`184f94d`](https://github.com/siderolabs/go-api-signature/commit/184f94d36cdd4d8bf8770ef629191f63187d63da) chore: rekres and bump go to 1.25.2\n* [`68478e2`](https://github.com/siderolabs/go-api-signature/commit/68478e2f57a3bca4345c6e189c0a4216dfb9b1ed) fix: return `invalid signature` error when a signature is required\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>2 commits</summary>\n<p>\n\n* [`d51e25a`](https://github.com/siderolabs/go-debug/commit/d51e25a0f0b97c3427ff9f7bff4d60418be14d5d) chore: rekres, bump deps and go\n* [`e21721b`](https://github.com/siderolabs/go-debug/commit/e21721bc4faba9072b5e4e33af60a1f0292547af) chore: add support for Go 1.25\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>1 commit</summary>\n<p>\n\n* [`8454fe9`](https://github.com/siderolabs/go-kubernetes/commit/8454fe9977f5240a1251c2df1b4f93ca73b869a7) feat: add upgrade path for 1.35\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e7a8b2`](https://github.com/siderolabs/go-loadbalancer/commit/5e7a8b21cbdb156c6fe6f9fd98b8a1bb1186c21c) feat: add jitter and initial health check wait support to upstreams\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>47 commits</summary>\n<p>\n\n* [`da97c36`](https://github.com/siderolabs/pkgs/commit/da97c368be82a0d8effd8eae257a87e5f2e29079) feat: update linux-firmware\n* [`6d58d7f`](https://github.com/siderolabs/pkgs/commit/6d58d7f86e6499ac5c229d93e0c370ea6370c5e6) feat: bump deps\n* [`b535af8`](https://github.com/siderolabs/pkgs/commit/b535af8b28844dfb88904db531cffc5ec86aa490) feat: update dependencies\n* [`a098092`](https://github.com/siderolabs/pkgs/commit/a0980927d55c05aaab3bf3d8439d29304ad88972) feat: update Linux to 6.17.3, tt-kmd to 2.4.1\n* [`661e578`](https://github.com/siderolabs/pkgs/commit/661e5788713e20df7be51ae90f76f94e45039bf8) feat: add xe extension\n* [`8ddac2d`](https://github.com/siderolabs/pkgs/commit/8ddac2da15d625144cfee4613f04bcdec2224297) feat: bump go\n* [`332303e`](https://github.com/siderolabs/pkgs/commit/332303ee2228694fe12979aa3fe03748d4eb4bd0) fix: rollback libseccomp version\n* [`f62ebca`](https://github.com/siderolabs/pkgs/commit/f62ebca758af069f23c46817e248aaf1674f39be) chore: update dependencies\n* [`56f8ae3`](https://github.com/siderolabs/pkgs/commit/56f8ae370d784ef61420bdd053eceefeaa12e194) feat: update Linux to 6.17.1, NVIDIA LTS to 580.95.05\n* [`20b1849`](https://github.com/siderolabs/pkgs/commit/20b1849146c50bce39582455717776d330973579) fix: revert \"feat\" support adding extra trusted certificates in the kernel\"\n* [`1e3d375`](https://github.com/siderolabs/pkgs/commit/1e3d37514394b4ed9c7b86b1a55b7ff633252142) feat: bump go\n* [`ddfd7af`](https://github.com/siderolabs/pkgs/commit/ddfd7afebe9a73c1abe291c03ec3b2e0cb41c0c5) feat: bump dependencies\n* [`4dc7709`](https://github.com/siderolabs/pkgs/commit/4dc770905a581c471c7b6eb0eca85177f5cbdd24) feat: update runc to 1.3.2\n* [`61d8b44`](https://github.com/siderolabs/pkgs/commit/61d8b44a153211521c1787ebd2478d05232d9a97) chore: fix renovate config for urcu & hailort\n* [`5bda512`](https://github.com/siderolabs/pkgs/commit/5bda51205cee2090e83c33697812d2b80a3c6b67) feat: upgrade Linux to 6.17\n* [`202a8e6`](https://github.com/siderolabs/pkgs/commit/202a8e663efaf24b662f349c82c5b6addeb6b3a2) feat: update Linux to 6.16.9\n* [`3a0900f`](https://github.com/siderolabs/pkgs/commit/3a0900f8b464f22773a153c65d85c6dd075cadba) feat: enable SRv6 LWTUNNEL and BPF support\n* [`628efc8`](https://github.com/siderolabs/pkgs/commit/628efc86c2020464c4ee58f419b8b17c8f87aa45) chore: update linuxfirmware and rekres\n* [`9d1fb02`](https://github.com/siderolabs/pkgs/commit/9d1fb029db9837af5529f7de371cc9bc709e8cbe) feat: support adding extra trusted certificates in the kernel\n* [`7fe686d`](https://github.com/siderolabs/pkgs/commit/7fe686dec6959a32a6a6d6610cedd18d963412ad) fix: build nftables with embedded gmp\n* [`fede0a7`](https://github.com/siderolabs/pkgs/commit/fede0a7ec672e835372b8915896fd0e775da0297) feat: add nft binary\n* [`0dae01a`](https://github.com/siderolabs/pkgs/commit/0dae01a735bae635ab987febac42c382d851d7d0) feat: update NVIDIA to 580.82.07\n* [`9ac2392`](https://github.com/siderolabs/pkgs/commit/9ac23925cf350075a4931a54176fdd3d9b9b7cb7) feat: enable Kernel config options for IPVS Maglev hashing scheduler support\n* [`3c5315c`](https://github.com/siderolabs/pkgs/commit/3c5315cd2ae931eb76233d26283f861ace932b1d) feat: update dependencies\n* [`122fa66`](https://github.com/siderolabs/pkgs/commit/122fa6626ff8c300623caa625bdc6bc72e866494) feat: update Linux to 6.16.6\n* [`ab1e866`](https://github.com/siderolabs/pkgs/commit/ab1e86612ac903b811ecd3b76d55e85951190565) feat: update Go to 1.25.1\n* [`7d6ef1b`](https://github.com/siderolabs/pkgs/commit/7d6ef1b187956a8cb2c837f339169b6cb7eb9c12) feat: update runc to 1.3.1\n* [`e067c20`](https://github.com/siderolabs/pkgs/commit/e067c2015302c5069676727f047b6aef9ce0dc0c) feat: enable USB audio support\n* [`c4faa38`](https://github.com/siderolabs/pkgs/commit/c4faa389341f6be5dad5fdd575acf61e9eb170f8) feat: bump dependencies\n* [`453cdfc`](https://github.com/siderolabs/pkgs/commit/453cdfc2fdea9945c8e3531ef190971211eaaf13) feat: enable ublk support\n* [`9824684`](https://github.com/siderolabs/pkgs/commit/982468471d8118ac4653b704512e5f847a148dd7) fix: enable memcg v1\n* [`2447e11`](https://github.com/siderolabs/pkgs/commit/2447e11dcbcb5dc10703515e2185f753b04e20e0) feat: update Linux to 6.16, GCC to 15\n* [`2cfb920`](https://github.com/siderolabs/pkgs/commit/2cfb920acd88d63c3d3ced3a5760549aa180208c) feat: update Linux to 6.15.11, update tools, rekres\n* [`ab4e975`](https://github.com/siderolabs/pkgs/commit/ab4e9755b0e2dbf38c75db5d2ff7720f511fd50c) feat: update Linux to 6.12.43\n* [`cd67e36`](https://github.com/siderolabs/pkgs/commit/cd67e3660fa0a2ad25ca4b8dcd3c1ce9b96b0b72) chore: update kernel config to support max SMP CPUs\n* [`e3b2094`](https://github.com/siderolabs/pkgs/commit/e3b209474060f5a67e36c9239a3a066ee8ace2fe) fix: fix build for new NVIDIA drivers\n* [`fd5fdfd`](https://github.com/siderolabs/pkgs/commit/fd5fdfde0bdc4dfc1e9990300df46b9af23c0dfd) feat: update Nvidia LTS to 580.65.06 and production to 570.172.08\n* [`0edf426`](https://github.com/siderolabs/pkgs/commit/0edf426d758d67f7baaaa42facdc658396f02f9f) fix: backport CVE kernel patches to 6.12\n* [`26d8fef`](https://github.com/siderolabs/pkgs/commit/26d8fefe10329e8d1c285014af0bffe1b9a65431) feat: enable Infiniband IRDMA support\n* [`16b5fac`](https://github.com/siderolabs/pkgs/commit/16b5facdbb37f2ad0329bf131ded62cc9b1239a9) fix: re-enable CPUSETS_V1 cgroups controller\n* [`fd53886`](https://github.com/siderolabs/pkgs/commit/fd53886f4f36e73181b7b1a0718801bf8e2aadb9) feat: update backportable dependencies\n* [`d5f7467`](https://github.com/siderolabs/pkgs/commit/d5f746715727ec34fca7a87ab9f1fac2051f0f75) feat: update Go to 1.24.6\n* [`0bd019f`](https://github.com/siderolabs/pkgs/commit/0bd019f29031b7461fbe49552b88d0e26861f955) feat: update containerd to 2.1.4\n* [`0ba8b5b`](https://github.com/siderolabs/pkgs/commit/0ba8b5b49f3dedcc49f4040a6f5c57329f5c5605) feat: enable F71808E watchdog driver\n* [`895a86b`](https://github.com/siderolabs/pkgs/commit/895a86bcdfedfd9ca1a698d8f8aa71e3600a22c2) fix: enable ISCSI IBFT\n* [`a76a67c`](https://github.com/siderolabs/pkgs/commit/a76a67c860a5100f41223fea936712760b33a4cd) feat: update Linux to 6.12.40\n* [`8b0a561`](https://github.com/siderolabs/pkgs/commit/8b0a56180198d360ea71b2c62669545b867f9a67) feat: enable bootloader control on amd64\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>17 commits</summary>\n<p>\n\n* [`a08cc1f`](https://github.com/siderolabs/tools/commit/a08cc1ff80c045b3683ae06d27d2ea2abcabfad2) feat: update git to 2.51.1\n* [`e62d613`](https://github.com/siderolabs/tools/commit/e62d613d3113857052acd0eda598805ab73e3dcd) feat: bump go\n* [`916b464`](https://github.com/siderolabs/tools/commit/916b4646151ec97a26ef3d1701d084820c41479c) fix: add pkgconf for ncurses, fix Renovate configs, bump deps\n* [`11f0337`](https://github.com/siderolabs/tools/commit/11f0337f796f3e39b60ae2ade4babdf5fb67534f) feat: update Go\n* [`2c56d7a`](https://github.com/siderolabs/tools/commit/2c56d7ae2e68295ce4820b19e9dc96d108b76632) feat: update OpenSSL to 3.5.4\n* [`8f27cfa`](https://github.com/siderolabs/tools/commit/8f27cfab6454aea38a70a9500bf8859f4d04cc21) feat: update dependencies\n* [`1c1420e`](https://github.com/siderolabs/tools/commit/1c1420e33eea2ae3c6b0d054474d9bfe1b34c88f) feat: add tinfo to ncurses\n* [`7c7328b`](https://github.com/siderolabs/tools/commit/7c7328b599b4cbac35ed7140798dd61c372e628a) fix: set regex in renovate config directly\n* [`3ab353b`](https://github.com/siderolabs/tools/commit/3ab353bc82f0d0c76d5bcc4022c851ae5e802d77) fix: modify renovate regex on ca_certificates\n* [`4f90801`](https://github.com/siderolabs/tools/commit/4f908016475257651dc41a4250c2c843b5373d08) chore: update openssl, curl, libexpat and rekres\n* [`c37ac80`](https://github.com/siderolabs/tools/commit/c37ac805a17daa8c0dc26da18b768864b821920b) feat: update Go to 1.25.1\n* [`7c659e9`](https://github.com/siderolabs/tools/commit/7c659e92db3884737abda95e643995107aa14010) feat: update to GCC 15\n* [`83fd7b7`](https://github.com/siderolabs/tools/commit/83fd7b7be62f2f59abeb24c971699895759ebb88) feat: migrate from pkg-config to pkgconf\n* [`edafd5f`](https://github.com/siderolabs/tools/commit/edafd5f395b1fd31650270332a871c830a5fd781) feat: update toolchain for new Go and Linux headers\n* [`65789c7`](https://github.com/siderolabs/tools/commit/65789c75ebd4020a444789cfd74d35fefc2497c2) chore: drop unused vars from Pkgfile\n* [`52db66e`](https://github.com/siderolabs/tools/commit/52db66e8d9e1d83e4872a504d45fdabed31504f7) chore: drop protobuf-related stuff from tools\n* [`e3c3ef2`](https://github.com/siderolabs/tools/commit/e3c3ef2b604fb80143a17879eeec9f30ca7b07dd) feat: update Go to 1.24.6\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.7.0 -> v0.9.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.18.1 -> v1.19.1\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.10.1 -> v1.13.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.29.17 -> v1.31.13\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.32 -> v1.18.10\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.41.2 -> v1.46.0\n* **github.com/aws/smithy-go**                          v1.22.4 -> v1.23.1\n* **github.com/beevik/ntp**                             v1.4.3 -> v1.5.0\n* **github.com/containernetworking/plugins**            v1.7.1 -> v1.8.0\n* **github.com/cosi-project/runtime**                   v1.10.7 -> v1.11.0\n* **github.com/docker/cli**                             v28.3.3 -> v28.5.1\n* **github.com/docker/docker**                          v28.3.3 -> v28.5.1\n* **github.com/docker/go-connections**                  v0.5.0 -> v0.6.0\n* **github.com/equinix-ms/go-vmw-guestrpc**             v0.1.1 -> v1.0.0\n* **github.com/florianl/go-tc**                         v0.4.5 -> v0.4.7\n* **github.com/foxboron/go-uefi**                       a3183a1bfc84 -> d29549a44f29\n* **github.com/gdamore/tcell/v2**                       v2.8.1 -> v2.9.0\n* **github.com/google/cel-go**                          v0.26.0 -> v0.26.1\n* **github.com/google/go-tpm**                          v0.9.5 -> v0.9.6\n* **github.com/gopacket/gopacket**                      v1.3.1 -> v1.4.0\n* **github.com/hetznercloud/hcloud-go/v2**              v2.22.0 -> v2.28.0\n* **github.com/insomniacslk/dhcp**                      8abf58130905 -> 175e84fbb167\n* **github.com/mdlayher/netlink**                       fbb4dce95f42 -> v1.8.0\n* **github.com/miekg/dns**                              v1.1.67 -> v1.1.68\n* **github.com/rivo/tview**                             a4a78f1e05cb -> v0.42.0\n* **github.com/safchain/ethtool**                       v0.6.1 -> v0.6.2\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.34 -> v1.0.0-beta.35\n* **github.com/siderolabs/crypto**                      v0.6.3 -> v0.6.4\n* **github.com/siderolabs/go-api-signature**            v0.3.7 -> v0.3.9\n* **github.com/siderolabs/go-debug**                    v0.5.0 -> v0.6.1\n* **github.com/siderolabs/go-kubernetes**               v0.2.26 -> v0.2.27\n* **github.com/siderolabs/go-loadbalancer**             v0.4.0 -> v0.5.0\n* **github.com/siderolabs/pkgs**                        v1.11.0-15-g2ac857a -> v1.12.0-alpha.0-45-gda97c36\n* **github.com/siderolabs/talos/pkg/machinery**         v1.11.0 -> v1.12.0-alpha.1\n* **github.com/siderolabs/tools**                       v1.11.0-2-g8556c73 -> v1.12.0-alpha.0-16-ga08cc1f\n* **github.com/spf13/cobra**                            v1.9.1 -> v1.10.1\n* **github.com/spf13/pflag**                            v1.0.7 -> v1.0.10\n* **github.com/stretchr/testify**                       v1.10.0 -> v1.11.1\n* **github.com/u-root/u-root**                          v0.14.0 -> v0.15.0\n* **go.etcd.io/etcd/api/v3**                            v3.6.4 -> v3.6.5\n* **go.etcd.io/etcd/client/pkg/v3**                     v3.6.4 -> v3.6.5\n* **go.etcd.io/etcd/client/v3**                         v3.6.4 -> v3.6.5\n* **go.etcd.io/etcd/etcdutl/v3**                        v3.6.4 -> v3.6.5\n* **golang.org/x/net**                                  v0.42.0 -> v0.46.0\n* **golang.org/x/oauth2**                               v0.30.0 -> v0.32.0\n* **golang.org/x/sync**                                 v0.16.0 -> v0.17.0\n* **golang.org/x/sys**                                  v0.34.0 -> v0.37.0\n* **golang.org/x/term**                                 v0.33.0 -> v0.36.0\n* **golang.org/x/text**                                 v0.27.0 -> v0.30.0\n* **golang.org/x/time**                                 v0.12.0 -> v0.14.0\n* **google.golang.org/grpc**                            v1.73.0 -> v1.76.0\n* **google.golang.org/protobuf**                        v1.36.6 -> v1.36.10\n* **gopkg.in/typ.v4**                                   v4.4.0 **_new_**\n* **k8s.io/api**                                        v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/apiextensions-apiserver**                    v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/apimachinery**                               v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/apiserver**                                  v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/client-go**                                  v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/component-base**                             v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/cri-api**                                    v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/kube-scheduler**                             v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/kubectl**                                    v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/kubelet**                                    v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/pod-security-admission**                     v0.34.0 -> v0.35.0-alpha.2\n* **k8s.io/utils**                                      4c0f3b243397 -> bc988d571ff4\n\nPrevious release can be found at [v1.11.0](https://github.com/siderolabs/talos/releases/tag/v1.11.0)\n\n\n## [Talos 1.12.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.12.0-alpha.1) (2025-10-01)\n\nWelcome to the v1.12.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Disk Encryption\n\nTalos versions prior to v1.12 used the state of PCR 7 and signed policies locked to PCR 11 for TPM based disk encryption.\n\nTalos now supports configuring which PCRs states are to be used for TPM based disk encryption via the `options.pcrs`\nfield in the `tpm` section of the disk encryption configuration.\n\nIf user doesn't specify any options Talos defaults to using PCR 7 for backwards compatibility with existing installations.\n\nThis change was made to improve compatibility with systems that may have varying states in PCR 7 due to UEFI Secure Boot configurations\nand users may wish to disable locking to PCR 7 state entirely.\n\nSigned PCR policies will still be bound to PCR 11.\n\nThe currently used PCR's can be seen with `talosctl get volumestatus <volume> -o yaml` command.\n\n\n### Embedded Config\n\nTalos Linux now supports [embedding the machine configuration](https://www.talos.dev/v1.12/talos-guides/configuration/acquire/) directly into the boot image.\n\n\n### Ethernet Configuration\n\nThe Ethernet configuration now includes a `wakeOnLAN` field to enable Wake-on-LAN (WOL) support.\nThis field can be set to enable WOL and specify the desired WOL modes.\n\n\n### Extra Binaries\n\nTalos Linux now ships with `nft` binary in the rootfs to support CNIs which shell out to `nft` command.\n\n\n### Kernel Security Posture Profile (KSPP)\n\nTalos now enables a stricter set of KSPP sysctl settings by default.\nThe list of overridden settings is available with `talosctl get kernelparamstatus` command.\n\n\n### Encrypted Volumes\n\nTalos Linux now consistently provides mapped names for encrypted volumes in the format `/dev/mapper/luks2-<volume-id>`.\nThis change should not affect system or user volumes, but might allow easier identification of encrypted volumes,\nand specifically for raw encrypted volumes.\n\n\n### Component Updates\n\nLinux: 6.16.9\nKubernetes: 1.34.1\nCNI Plugins: 1.8.0\ncryptsetup: 2.8.1\nLVM2: 2_03_34\nsystemd-udevd: 257.8\nrunc: 1.3.1\nCoreDNS: 1.12.4\netcd: 3.6.5\n\nTalos is built with Go 1.25.1.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Amarachi Iheanacho\n* Dmitrii Sharshakov\n* Mateusz Urbanek\n* Orzelius\n* Oguz Kilcan\n* George Gaál\n* Utku Ozdemir\n* 459below\n* Alp Celik\n* Andrew Longwill\n* Chris Sanders\n* Dmitry\n* Febrian\n* Fred Heinecke\n* Giau. Tran Minh\n* Guillaume LEGRAIN\n* Jorik Jonker\n* Justin Garrison\n* Markus Freitag\n* Max Makarov\n* Mike Beaumont\n* Misha Aksenov\n* MrMrRubic\n* Olivier Doucet\n* Sammy ETUR\n* Serge Logvinov\n* Skyler Mäntysaari\n* Tom\n* aurh1l\n* frozenprocess\n* kassad\n* leppeK\n* winnie\n\n### Changes\n<details><summary>178 commits</summary>\n<p>\n\n* [`e455c7ea9`](https://github.com/siderolabs/talos/commit/e455c7ea9c919a2f70ddecceaa8f3b4e25566048) chore: use testing/synctest in tests\n* [`7f048e962`](https://github.com/siderolabs/talos/commit/7f048e962e217687ab67ed7027c5228e8ccb7d16) feat: update dependencies\n* [`fe36b3d32`](https://github.com/siderolabs/talos/commit/fe36b3d3200db57f3e21017ff7a4808b330a1d55) fix: stop returning EINVAL on remount of detached mounts\n* [`c6279e04c`](https://github.com/siderolabs/talos/commit/c6279e04c45504af243c0aef9f255317426b4ca0) chore: use new mount/v3 package in efivarfs\n* [`d5197effb`](https://github.com/siderolabs/talos/commit/d5197effb0b48290d613140b68796cb8f30b9a70) feat: update etcd 3.6.5, CoreDNS 1.12.4\n* [`33714b715`](https://github.com/siderolabs/talos/commit/33714b7158a0d569be1d0b1d7b012280856db484) feat: release cloud image using factory\n* [`d10a2747e`](https://github.com/siderolabs/talos/commit/d10a2747e0e835876aff158e6b6f7882cef9fa44) docs: deprecate JSON6902 patches and interactive installer\n* [`1e604cbf5`](https://github.com/siderolabs/talos/commit/1e604cbf514bece1e112d8afd5d1cd6ccb1045c3) fix: don't set broadcast for /31 and /32 addresses\n* [`65a66097a`](https://github.com/siderolabs/talos/commit/65a66097a05e5c0e2334d5eff494a0e71534716f) refactor: split cluster create logic into smaller parts\n* [`ab847310e`](https://github.com/siderolabs/talos/commit/ab847310efde540b5bfe17570b99af1bb705832b) fix: provide refreshing CA pool (resolvers)\n* [`d63c3ed7d`](https://github.com/siderolabs/talos/commit/d63c3ed7db2b22f7e394fc45d101d03cba463177) docs: update secureboot docs\n* [`493f7ed9d`](https://github.com/siderolabs/talos/commit/493f7ed9d2710eb240eab6b6ab532f41abc818c1) feat: support embedded config\n* [`251df70f6`](https://github.com/siderolabs/talos/commit/251df70f6d33f1d5a3b1b9e4c0c249d8bc85c4b3) feat: add a userspace OOM controller\n* [`7bae5b40b`](https://github.com/siderolabs/talos/commit/7bae5b40b4f22f0f07a586ebd9cda9436086a5f8) feat: implement link configuration\n* [`724857dec`](https://github.com/siderolabs/talos/commit/724857decb95ddeebb2ac5d33c38a71bf7512805) fix(ci): skip netbird extension for tests\n* [`e06a08698`](https://github.com/siderolabs/talos/commit/e06a086989331f28406e8d4234e02d9a6b83f87d) fix: default gateway as string\n* [`7ed07412e`](https://github.com/siderolabs/talos/commit/7ed07412e963e6ee91615adbea095944aa6a56e5) fix: uefi boot entry handling logic\n* [`ea4ed165a`](https://github.com/siderolabs/talos/commit/ea4ed165ad860a5beea17ca2d404bdaa6e5ad933) refactor: efivarfs mock and tests\n* [`1fca111e2`](https://github.com/siderolabs/talos/commit/1fca111e24bcae81b78f007e67b71c9155c0169f) feat: support setting wake-on-lan for Ethernet\n* [`94f78dbe7`](https://github.com/siderolabs/talos/commit/94f78dbe798cb227a0c38b70a1d6840803989290) docs: add a documentation for running Talos in KVM\n* [`46902f8fd`](https://github.com/siderolabs/talos/commit/46902f8fdee257a09be4bc1753c6b3f845ef8089) docs: add TrueFullstaq to adopters\n* [`a28e5cbd5`](https://github.com/siderolabs/talos/commit/a28e5cbd50d11aa6c253a6a9ce1999b9d45effad) chore: update pkgs and tools\n* [`7cf403db8`](https://github.com/siderolabs/talos/commit/7cf403db8ca0e1719195001895cfbc12835b0fdd) docs: step-by-step scaleway documentation to get an image\n* [`687285fa2`](https://github.com/siderolabs/talos/commit/687285fa26ec42dadbfb72580099f6e20bbaf85e) docs: remove 'curl' in wget command\n* [`9db6dc06c`](https://github.com/siderolabs/talos/commit/9db6dc06c3010cd89ce4cb0ec0bde178db0447a4) feat: stop mounting state partition\n* [`53ce93aae`](https://github.com/siderolabs/talos/commit/53ce93aaed3bd5bfcbe926fa69ca3b4b8b45c74f) test: try to clear connection refused more aggressively\n* [`51db5279c`](https://github.com/siderolabs/talos/commit/51db5279c423e4b8637a05e52b26dfc5aa719cbc) fix: bump trustd memory limit\n* [`25204dc8a`](https://github.com/siderolabs/talos/commit/25204dc8a8df79bc876a0bec2492e1147a81d954) fix(machined): change `constants.MinimumGOAMD64Level` using build tag\n* [`9cd2d794d`](https://github.com/siderolabs/talos/commit/9cd2d794d060b637dbac5263ae417a4e83d54efe) feat: ship nft binary with Talos rootfs\n* [`b1416c9fe`](https://github.com/siderolabs/talos/commit/b1416c9fe1d5ea9cd68f9b6b766a288a267cee61) feat: record last log the failed service\n* [`0b129f9ef`](https://github.com/siderolabs/talos/commit/0b129f9efdf57dd9692f7cece6b97719a7ccf80e) feat: enforce more KSPP and hardening sysctls\n* [`11872643c`](https://github.com/siderolabs/talos/commit/11872643c310212c52b4fd7e13b6cc7d6ec7e4fc) chore: drop docs folder\n* [`d30fdcd88`](https://github.com/siderolabs/talos/commit/d30fdcd88f421824cf17b9ecec25be7c8044e857) chore: pass in github token to imager\n* [`b88f27d80`](https://github.com/siderolabs/talos/commit/b88f27d804d60a706f598b50676dad5dd2a9726a) chore: make reset test code a bit better\n* [`1cde53d01`](https://github.com/siderolabs/talos/commit/1cde53d0173fd1ae637855e15fe34bb74bb027a0) test: fix several issues with tests\n* [`16cd127a0`](https://github.com/siderolabs/talos/commit/16cd127a04bb5fc907b7ca04f1c81d4c7150eab2) docs: add docs on updating image cache\n* [`c3ae92b14`](https://github.com/siderolabs/talos/commit/c3ae92b1424d4a2c9bc18cfa394b10eda6c9a20f) fix: build kernel checks only on linux\n* [`2120904ec`](https://github.com/siderolabs/talos/commit/2120904ec534a91f66dcea419b5a29e36a16f6e4) feat: create detached tmpfs\n* [`6bbee6de5`](https://github.com/siderolabs/talos/commit/6bbee6de5b18b25deb4e6f515251187e259aa424) docs: remove 'ceph-data' from volume examples/docs\n* [`07acb3bd2`](https://github.com/siderolabs/talos/commit/07acb3bd2d4f92e80706d1835130bbe6e944d096) fix: use correct order to determine SideroV1 keys directory path\n* [`2d57fa002`](https://github.com/siderolabs/talos/commit/2d57fa00281f8090b85097c66df634101b0cde79) fix: trim zero bytes in the DHCP host & domain response\n* [`451cb5f78`](https://github.com/siderolabs/talos/commit/451cb5f78fac3b2ddfec7d545629fe8c88ea2367) docs: clarify disk partition confusion\n* [`a2122ee5c`](https://github.com/siderolabs/talos/commit/a2122ee5cb9c84f33e0c4b30e9223bb239621d55) feat: implement HostConfig multi-doc\n* [`69ab076b4`](https://github.com/siderolabs/talos/commit/69ab076b4d6e52484677ee7f68a853dc4edfe2bc) fix: re-create cgroups when restarting runners\n* [`297b5cc28`](https://github.com/siderolabs/talos/commit/297b5cc2856710b74b4e0e46b00ae33aea4c1bf7) docs: add docs on node labels\n* [`e168512dd`](https://github.com/siderolabs/talos/commit/e168512dd020da9eac654dae2ba891cf33415c44) fix: apply 'ro' flag to iso9660 filesystems\n* [`7f7acfbb9`](https://github.com/siderolabs/talos/commit/7f7acfbb9f10c243d0b132c1ef079cb77d2727e0) docs: fix typo in doc\n* [`d57882b18`](https://github.com/siderolabs/talos/commit/d57882b1830504fe4bfd5344edae613168db7f0e) feat: update Kubernetes to 1.34.1\n* [`f85f82f32`](https://github.com/siderolabs/talos/commit/f85f82f32f098f97588f404550f72d64786fe329) test: fix flakiness in RawVolumes test\n* [`82569e319`](https://github.com/siderolabs/talos/commit/82569e319eb57b1199db6bfd3e612fb771c8c7cd) feat: update Linux 6.16.6\n* [`2fd2ab4e4`](https://github.com/siderolabs/talos/commit/2fd2ab4e43e06910154705d6ef1d0576a7c04a2b) fix: remove CoreDNS cpu limit\n* [`ce9bc32a0`](https://github.com/siderolabs/talos/commit/ce9bc32a08695873d9054afe2608a76cf7c6088a) chore(ci): rekres to use new runner groups\n* [`8b64f68f6`](https://github.com/siderolabs/talos/commit/8b64f68f6946c2979f6fe2bf617f31639a927bf8) test: improve test stability\n* [`272cb860d`](https://github.com/siderolabs/talos/commit/272cb860d4cfb8464b29ff31567e25fe6c275849) chore: drop the --input-dir flag from the cluster create command\n* [`1b6533675`](https://github.com/siderolabs/talos/commit/1b65336752933acdcbf681767785157714866f88) docs: add note about ca-signed certs for secureboot\n* [`d3f88f50c`](https://github.com/siderolabs/talos/commit/d3f88f50c5394536ee80d19464359408a37d81ff) docs: document talos vip failover behavior\n* [`005fc8bd5`](https://github.com/siderolabs/talos/commit/005fc8bd50fbc4b15b26032b43d1d32c1da22f11) docs: add docs on syncing configs after a kube upgrade\n* [`4d876d9af`](https://github.com/siderolabs/talos/commit/4d876d9af9fcc9828f09d05db124fbdce9c17785) feat: update Go to 1.25.1\n* [`2b556cd22`](https://github.com/siderolabs/talos/commit/2b556cd22a3563f1d86a648ea6c69a4d45edad76) feat: implement multi-doc StaticHostConfig\n* [`a7b776842`](https://github.com/siderolabs/talos/commit/a7b7768420566b6840fc52bb2152e9bf165f8cd3) docs: replace Raspberry Pi 5 links with Talos builder\n* [`a349b20ed`](https://github.com/siderolabs/talos/commit/a349b20ed4b3c05dcd0175541b795331f0f7c64d) docs: clarify that talos does not support intermediate ca\n* [`895133de9`](https://github.com/siderolabs/talos/commit/895133de99158ce3f50b557b77c81d4f0f9d6b40) feat: support configuring PCR states to bind disk encryption\n* [`c1360103b`](https://github.com/siderolabs/talos/commit/c1360103b5e037cf713b7d787436f01e7182821c) docs: fix command for uploading image on Hetzner\n* [`43b5b9d89`](https://github.com/siderolabs/talos/commit/43b5b9d8992ad6df37619b3719b57948e4bd9671) fix: correctly handle status-code 204\n* [`feeb0d312`](https://github.com/siderolabs/talos/commit/feeb0d312ecacb451e5313390939c7c9349d2ba6) feat: update runc to 1.3.1\n* [`421634a14`](https://github.com/siderolabs/talos/commit/421634a1417f529551a75d0bb9be08b73f1120b1) docs: add docs on multihoming\n* [`41af2d230`](https://github.com/siderolabs/talos/commit/41af2d230c2dd5dce5bc931f76a2eb69405dc554) refactor: clean up internal cluster creation code\n* [`3000d9e43`](https://github.com/siderolabs/talos/commit/3000d9e431deaf952d08da724da40789cd743f2c) fix: don't bootstrap talos cluster if there's no config present\n* [`79cb871d0`](https://github.com/siderolabs/talos/commit/79cb871d088e5b1c3a3488610ded14e7a28cec29) feat: use the id of the volume in the mapped luks2 name\n* [`6c322710d`](https://github.com/siderolabs/talos/commit/6c322710d64786f19e2e0e39d65596c8dce71952) chore: refactor mount package\n* [`ced7186e2`](https://github.com/siderolabs/talos/commit/ced7186e2a5f0634d9441b12a5340f5ca4c451ff) refactor: update COSI to 1.11.0\n* [`de2e24fcd`](https://github.com/siderolabs/talos/commit/de2e24fcda590a1ef3f80a5372bb70865a2f47c3) docs: clarify that install-cni image is deprecated\n* [`bef8ef509`](https://github.com/siderolabs/talos/commit/bef8ef509380aba259efcc2f5d1f6632e034160b) docs: add docs on cilium's compatibility with kubespan\n* [`e5acb10fc`](https://github.com/siderolabs/talos/commit/e5acb10fcceba69060507a35caea21281bdc71cc) feat: update pkgs\n* [`c4c1daf0e`](https://github.com/siderolabs/talos/commit/c4c1daf0e2e6675626b974b0c008e101d919c8b5) docs: add info about br_netfilter\n* [`5c52ecac3`](https://github.com/siderolabs/talos/commit/5c52ecac364f917e5f45859f680494a08f85cb90) docs: clarify interactive dashboard resolution control\n* [`15ecb02a4`](https://github.com/siderolabs/talos/commit/15ecb02a4545639ffb8ba5c6e5a413e53129b619) feat: update Linux kernel (memcg_v1, ublk)\n* [`53f18c2f6`](https://github.com/siderolabs/talos/commit/53f18c2f60c84c4b0f944cc343ae1f538e8d1236) fix: enable support for VMWare arm64\n* [`3bbe1c0da`](https://github.com/siderolabs/talos/commit/3bbe1c0da5485b6cd3e7fadd8f020e0d0aca406a) docs: add docs on grow flag\n* [`b9fb09dcd`](https://github.com/siderolabs/talos/commit/b9fb09dcdbcca60f695ac317c45e18fa092541a8) release(v1.12.0-alpha.0): prepare release\n* [`6a389cad3`](https://github.com/siderolabs/talos/commit/6a389cad35f80b27fe9c43db9e701ee9f6f6142a) chore: update dependencies\n* [`9d98c2e89`](https://github.com/siderolabs/talos/commit/9d98c2e891258dcf2ef90519d38d0aefb77cd0db) feat: add a cgroup preset for PSI and --skip-cri-resolve\n* [`072f77b16`](https://github.com/siderolabs/talos/commit/072f77b1623cdc838093465b7266b26e20a248ea) chore: prepare for future Talos 1.12-alpha.0 release\n* [`96f41ce88`](https://github.com/siderolabs/talos/commit/96f41ce8840783f783fcc8e0fd6b43302b9bfe43) docs: update qemu and docker docs\n* [`a751cd6b7`](https://github.com/siderolabs/talos/commit/a751cd6b7474a4dc20137e917dbb2229fe9cc8bd) docs: activate Talos v1.11 docs by default\n* [`e8f1ec1c5`](https://github.com/siderolabs/talos/commit/e8f1ec1c5bbd8a6cfb68886e6283e7caaf5fb063) docs: fix broken create qemu command v1.11 docs\n* [`639f0dfdd`](https://github.com/siderolabs/talos/commit/639f0dfdd88c5596439601f3f9600b3aafb24227) feat: update Linux to 6.16.4\n* [`8aa7b3933`](https://github.com/siderolabs/talos/commit/8aa7b3933d07ea45a96844b9c91347a08950e243) fix: bring back linux/armv7 build and update xz\n* [`9cae7ba6b`](https://github.com/siderolabs/talos/commit/9cae7ba6b97a67a5d282c6f667ccb4c3e2111447) feat: update CoreDNS to 1.12.3\n* [`cfef3ad45`](https://github.com/siderolabs/talos/commit/cfef3ad4544498a47de17f6b05fb8374c35e3dd8) fix: drop linux/armv7 build\n* [`42ea2ac50`](https://github.com/siderolabs/talos/commit/42ea2ac5058457dafe666f8d79f08d3c8ee60cfb) fix: update xz module (security)\n* [`4fcfd35b9`](https://github.com/siderolabs/talos/commit/4fcfd35b9510f45d0ef7ae3657eb0916d549d2dd) docs: fix module name example\n* [`50824599a`](https://github.com/siderolabs/talos/commit/50824599a4fa7b72d563a35a4746ca063becf672) chore: update some tools\n* [`bcd297490`](https://github.com/siderolabs/talos/commit/bcd297490c608f593b6dd274945aa2b73c3fd3ee) feat: allow Ed25119 in FIPS mode\n* [`5992138bb`](https://github.com/siderolabs/talos/commit/5992138bb981e84dae917f0f0fdafee4049bc5ec) test: ignore one leaking goroutine\n* [`d155326c1`](https://github.com/siderolabs/talos/commit/d155326c1206979f30a5355f7bdb23cb051e9b78) docs: add sbc unofficial ports docs\n* [`285fa7d22`](https://github.com/siderolabs/talos/commit/285fa7d222be1f5e63c0bb725b206966e2722a3b) docs: add the deploy application docs\n* [`527791f09`](https://github.com/siderolabs/talos/commit/527791f0974afe9c8558b82fa19f4354487693ed) feat: update Kubernetes to 1.34.0\n* [`a1c0e237d`](https://github.com/siderolabs/talos/commit/a1c0e237d6e047bb59c4fbd48e2c2b9e36dd4808) feat: update Linux to 6.15.11, Go to 1.25\n* [`4d7fc25f8`](https://github.com/siderolabs/talos/commit/4d7fc25f8bf20d4489080795a3d0ce0dfb1bc6b8) docs: switch order of wipe disk command\n* [`7368a994d`](https://github.com/siderolabs/talos/commit/7368a994df07cc4e50e3709ac766d8062db070a0) feat: add SOCKS5 proxy support to dynamic proxy dialer\n* [`d63591069`](https://github.com/siderolabs/talos/commit/d635910697b221aee3e9afa6d9e5b398236b6a21) chore: silence linter warnings\n* [`07eb4d7ec`](https://github.com/siderolabs/talos/commit/07eb4d7ec148a7e3c4c6dde080469c1a2fb410fb) fix: set default ram unit to MiB instead of MB\n* [`6b732adc4`](https://github.com/siderolabs/talos/commit/6b732adc43684facfd329f424a34a7e4df36d77b) feat: update Linux to 6.12.43\n* [`b6410914f`](https://github.com/siderolabs/talos/commit/b6410914f74ce01672fdef7e912e37970909281c) feat: add human readable byte size cli flags\n* [`ec70cef99`](https://github.com/siderolabs/talos/commit/ec70cef99005fd7e383fea63b5c23774882fcf28) feat: update NVIDIA drivers and kernel\n* [`0879efa69`](https://github.com/siderolabs/talos/commit/0879efa690ad657e4aed251fcbeba8f5645d73ce) feat: update Kubernetes default to v1.34.0-rc.2\n* [`f504639df`](https://github.com/siderolabs/talos/commit/f504639df4388619f731196ed8e79a6818b6ed5f) feat: add a user-facing create qemu command\n* [`558e0b09a`](https://github.com/siderolabs/talos/commit/558e0b09ab65b353e83b98c9ddf6cb2b67fd060e) test: fix the Image Factory PXE boot test\n* [`d73f0a2e5`](https://github.com/siderolabs/talos/commit/d73f0a2e5b788c7b69c2fb827f7111d5f9c8e706) docs: make readme badges consistent\n* [`f1369af98`](https://github.com/siderolabs/talos/commit/f1369af98e1f6d48fed137e31237956abbd28b0f) chore: use new filesystem api on STATE partition\n* [`366cedbe7`](https://github.com/siderolabs/talos/commit/366cedbe7495ce15bcd0e6c6f7f0add65a41a861) docs: link to kubernetes linux swap tuning\n* [`2f5a16f5e`](https://github.com/siderolabs/talos/commit/2f5a16f5e4ae186a309aef5e3d285897d0fe2df1) fix: make --with-uuid-hostnames functionality available to qemu provider\n* [`70612c1f9`](https://github.com/siderolabs/talos/commit/70612c1f9fc9056e8a3669ff10a385c4e8e03350) refactor: split the PlatformConfigController\n* [`511748339`](https://github.com/siderolabs/talos/commit/51174833997fd9a0a599ab1dde947834b682ab14) docs: add system extension tier documentation\n* [`009fb1540`](https://github.com/siderolabs/talos/commit/009fb1540e0b9f5daac6302f42e8813e596fc87c) test: don't run nvidia tests on integration/aws\n* [`99674ef20`](https://github.com/siderolabs/talos/commit/99674ef20d34166d60563d4bf46fbbfc57399509) docs: apply fixes for what is new\n* [`92db677b5`](https://github.com/siderolabs/talos/commit/92db677b5d32de32ec7e785531b32202e03283b4) fix: image cache lockup on a missing volume\n* [`9c97ed886`](https://github.com/siderolabs/talos/commit/9c97ed886b89b2fb84f47866abdf1000839143c4) fix: version contract parsing in encryption keys handling\n* [`1fc670a08`](https://github.com/siderolabs/talos/commit/1fc670a08dc7af8eaeabdc7134eb77a5c939df40) fix: dial with proxy\n* [`18447d0af`](https://github.com/siderolabs/talos/commit/18447d0afdbcc8fa7db6ae008e4bc4d5b0a0b00a) feat: update Linux to 6.12.41\n* [`f65f39b78`](https://github.com/siderolabs/talos/commit/f65f39b78b0c7881e5f51c66ad022c17c2cd4960) fix: provide mitigation CVE-1999-0524\n* [`8817cc60c`](https://github.com/siderolabs/talos/commit/8817cc60cfaf4b50f11c38d3b25df7df48382033) fix: actually use SIDEROV1_KEYS_DIR env var if it's provided\n* [`b08b20a10`](https://github.com/siderolabs/talos/commit/b08b20a1005256a9e3fc7cae8bcf8eea87f6ac09) feat: use key provider with fallback option for auth type SideroV1\n* [`7a52d7489`](https://github.com/siderolabs/talos/commit/7a52d7489c9709708d55f8f001d70700addc7e1e) fix: kubernetes upgrade options for kubelet\n* [`ea8289f55`](https://github.com/siderolabs/talos/commit/ea8289f550787593b1cd35f2d8da59aa5311880e) feat: add a user facing docker command\n* [`54ad64765`](https://github.com/siderolabs/talos/commit/54ad64765090d90013e4917d1bf494592069beec) chore: re-enable vulncheck\n* [`26bbddea9`](https://github.com/siderolabs/talos/commit/26bbddea95669278363c604316ed85986f312d71) fix: darwin build\n* [`b5d5ef79e`](https://github.com/siderolabs/talos/commit/b5d5ef79e7a2d76e29a7c872c1c418fffc63b0df) fix: set secs field in DHCPv4 packets\n* [`c07911933`](https://github.com/siderolabs/talos/commit/c0791193373e36c35f29c70318432331b4c6ab2a) chore: refactor how tools are being installed\n* [`34f25815c`](https://github.com/siderolabs/talos/commit/34f25815c036d2c91bdfddc9c7d40ca2edf677bd) docs: fork docs for v1.12\n* [`b66b995d3`](https://github.com/siderolabs/talos/commit/b66b995d34306192cbaa4ef68fe39f821b37d1f0) feat: update default Kubernetes to v1.34.0-rc.1\n* [`b967c587d`](https://github.com/siderolabs/talos/commit/b967c587d9f217f25798e0bee0c90393e55dc085) docs: fix clone URL to include `.git`\n* [`b72c68398`](https://github.com/siderolabs/talos/commit/b72c6839806103ac0a76acd46f30eabea0375790) docs: edit the insecure, etcd-metrics, inline and extramanifests\n* [`e5b9c1fff`](https://github.com/siderolabs/talos/commit/e5b9c1ffffec9fd49ffb84a36c918e75eaa8f1ef) docs: remov RAS Syndrome\n* [`701fe774b`](https://github.com/siderolabs/talos/commit/701fe774bd19de7c9f21e043e1520161a8c5fff7) docs: fix cilium links and bump to 1.18.0\n* [`d306713a1`](https://github.com/siderolabs/talos/commit/d306713a13a18d7af6caffd5890d54d91d22cad7) feat: update Go to 1.24.6\n* [`721595a00`](https://github.com/siderolabs/talos/commit/721595a0009f78a2722802ab665957fd767c4d1e) chore: add deadcode elimination linter\n* [`dc4865915`](https://github.com/siderolabs/talos/commit/dc4865915d567942adea3efa66f8ad360f9c4cce) refactor: stop using `text/template` in `machined` code paths\n* [`545be55ed`](https://github.com/siderolabs/talos/commit/545be55edc863245638d4387cb9ee7e7b068f2ba) feat: add a pause function to dashboard\n* [`06a6c0fe3`](https://github.com/siderolabs/talos/commit/06a6c0fe332940b7a70ea2652bc2a5e7bc51bbf3) refactor: fix deadcode elimination with godbus\n* [`2dce8f8d4`](https://github.com/siderolabs/talos/commit/2dce8f8d4693a85d2f3bf46169af8cf502d49f9d) refactor: replace containerd/containerd/v2 module for proper DCE\n* [`9b11d8608`](https://github.com/siderolabs/talos/commit/9b11d86081df8cf77860d2d27eed5d8001ff721e) chore: rekres to configure slack notify workflow for CI failures\n* [`5ce6a660f`](https://github.com/siderolabs/talos/commit/5ce6a660f67f4e2776550a1e621179beb8a6788c) docs: augment the pod security docs\n* [`ada51ff69`](https://github.com/siderolabs/talos/commit/ada51ff696011e15dcd9c661da1d839bdc341745) fix: unmarshal encryption STATE from META\n* [`b9e9b2e07`](https://github.com/siderolabs/talos/commit/b9e9b2e07a645f53ca23355810d485a2622870c9) docs: add what is new notes for 1.11\n* [`53055bdf4`](https://github.com/siderolabs/talos/commit/53055bdf49ce4c81f63c159cdbaa8ea85d9ca2b8) docs: fix typo in kubevirt page\n* [`8d12db480`](https://github.com/siderolabs/talos/commit/8d12db480c38ec37aee5ae7721b2e5ca55ad733e) fix: one more attempt to fix volume mount race on restart\n* [`34d37a268`](https://github.com/siderolabs/talos/commit/34d37a268a9e0098179369af128261dbfc956d1d) chore: rekres to use correct slack channel for slack-notify\n* [`326a00538`](https://github.com/siderolabs/talos/commit/326a00538210bf98b01795d314c1e154a74d2d58) feat: implement `talos.config.early` command line arg\n* [`a5f3000f2`](https://github.com/siderolabs/talos/commit/a5f3000f2e8a79d4e9a5be95fbcac91a2d78675b) feat: implement encryption locking to STATE\n* [`c1e65a342`](https://github.com/siderolabs/talos/commit/c1e65a34256944743e768613b119c0caa517b54d) docs: remove talos API flags from mgmt commands\n* [`181d0bbf5`](https://github.com/siderolabs/talos/commit/181d0bbf5381343d35a01190da45e3442320d7c5) feat: bootedentry resource\n* [`7ad439ac3`](https://github.com/siderolabs/talos/commit/7ad439ac35859695074d3a3efdcdb5c0cab1a5c6) fix: enforce minimum size on user volumes if not set explicitly\n* [`50e37aefd`](https://github.com/siderolabs/talos/commit/50e37aefdbde973bcc8aa352639946490fbe7d94) fix: live reload of TLS client config for discovery client\n* [`87efd75ef`](https://github.com/siderolabs/talos/commit/87efd75efb3e62b88b4f65a221f9fbdd4b4d6ef9) feat: update containerd to 2.1.4\n* [`724b9de6d`](https://github.com/siderolabs/talos/commit/724b9de6d5195bcccc5f484c696429b2f09ab16e) feat: add F71808E watchdog driver\n* [`8af96f7af`](https://github.com/siderolabs/talos/commit/8af96f7afdac1c4d5e2697b897b81e2bddd15f66) docs: add ETCD downgrade documentation\n* [`44edd205d`](https://github.com/siderolabs/talos/commit/44edd205d5fdffab39b65ee62695a40e22ef188c) docs: add remark about 'exclude-from-external-load-balancers' label\n* [`727101926`](https://github.com/siderolabs/talos/commit/7271019263b0dc5b28d2764d19fe531e473222fc) fix(ci): use a random suffix for ami names\n* [`d621ce372`](https://github.com/siderolabs/talos/commit/d621ce3726f20ee568ea3b6ac57d9e8dfa0580cc) fix: grype scan\n* [`d62e255c2`](https://github.com/siderolabs/talos/commit/d62e255c260810a5f0f2959e32592a3331df28d3) fix: issues with reading GPT\n* [`5d0883e14`](https://github.com/siderolabs/talos/commit/5d0883e147163c12a77cd926db799ffed854aedf) feat: update PCI DB module to v0.3.2\n* [`3751c8ccf`](https://github.com/siderolabs/talos/commit/3751c8ccfa1bab9fcd435290f36e9012a5626e40) test: wait for service account test job longer\n* [`a592eb9f9`](https://github.com/siderolabs/talos/commit/a592eb9f98788883a7ec6d17772e10707230a0d8) feat: update Linux to 6.12.40\n* [`4c40e6d3f`](https://github.com/siderolabs/talos/commit/4c40e6d3fb4c2f451a8d7a671df5f6254161bd5d) feat: update etcd to 3.6.4\n* [`2bc37bd2c`](https://github.com/siderolabs/talos/commit/2bc37bd2c9679c8055fd7b52eb310f23a329af4e) docs: fix error in kernel module guide\n* [`bfc57fb86`](https://github.com/siderolabs/talos/commit/bfc57fb863224f7626f49e5b26be06f77bea2e40) chore: tag aws snapshots created via ci with the image name\n* [`06ef7108a`](https://github.com/siderolabs/talos/commit/06ef7108a6050b3a8fd7535f01a469f09042bf56) fix: issue with volume remount on service restart\n* [`03efbff18`](https://github.com/siderolabs/talos/commit/03efbff18e420c4fe960f490f91dd9f4751ece04) docs: add SBOM documentation\n* [`af8a2869d`](https://github.com/siderolabs/talos/commit/af8a2869dbbec073ffaf72a1378682e109b053ec) fix: do not download artifacts for cron Grype scan\n* [`5f442159b`](https://github.com/siderolabs/talos/commit/5f442159b224c96c90badc7176fed17bfb561709) feat: unify disk encryption configuration\n* [`38e176e59`](https://github.com/siderolabs/talos/commit/38e176e594edb3d271d98f78417b9fd5ba0c5288) chore(ci): fix datasource versioning\n* [`85d6b9198`](https://github.com/siderolabs/talos/commit/85d6b919890a1aa9c4f94d5b18861cc617134ff9) feat: update etcd to v3.5.22\n* [`dd7bd2dab`](https://github.com/siderolabs/talos/commit/dd7bd2dab8cf09334e3e353d6a477509bbaa303e) docs: rewrite the getting started and prod docs for v1.10 and v1.11\n* [`136a899aa`](https://github.com/siderolabs/talos/commit/136a899aa25b3fdcdd771594668278d563f09192) chore: regenerate release step with signing fixes\n* [`450b30d5a`](https://github.com/siderolabs/talos/commit/450b30d5a986563869efdbaa074e82d612f6f2ef) chore(ci): add more nvidia test matrix\n* [`451c2c4c3`](https://github.com/siderolabs/talos/commit/451c2c4c39e70c20df58fc31459cd5c789a0e46f) test: add talosctl:latest to the image cache\n</p>\n</details>\n\n### Changes since v1.12.0-alpha.0\n<details><summary>79 commits</summary>\n<p>\n\n* [`e455c7ea9`](https://github.com/siderolabs/talos/commit/e455c7ea9c919a2f70ddecceaa8f3b4e25566048) chore: use testing/synctest in tests\n* [`7f048e962`](https://github.com/siderolabs/talos/commit/7f048e962e217687ab67ed7027c5228e8ccb7d16) feat: update dependencies\n* [`fe36b3d32`](https://github.com/siderolabs/talos/commit/fe36b3d3200db57f3e21017ff7a4808b330a1d55) fix: stop returning EINVAL on remount of detached mounts\n* [`c6279e04c`](https://github.com/siderolabs/talos/commit/c6279e04c45504af243c0aef9f255317426b4ca0) chore: use new mount/v3 package in efivarfs\n* [`d5197effb`](https://github.com/siderolabs/talos/commit/d5197effb0b48290d613140b68796cb8f30b9a70) feat: update etcd 3.6.5, CoreDNS 1.12.4\n* [`33714b715`](https://github.com/siderolabs/talos/commit/33714b7158a0d569be1d0b1d7b012280856db484) feat: release cloud image using factory\n* [`d10a2747e`](https://github.com/siderolabs/talos/commit/d10a2747e0e835876aff158e6b6f7882cef9fa44) docs: deprecate JSON6902 patches and interactive installer\n* [`1e604cbf5`](https://github.com/siderolabs/talos/commit/1e604cbf514bece1e112d8afd5d1cd6ccb1045c3) fix: don't set broadcast for /31 and /32 addresses\n* [`65a66097a`](https://github.com/siderolabs/talos/commit/65a66097a05e5c0e2334d5eff494a0e71534716f) refactor: split cluster create logic into smaller parts\n* [`ab847310e`](https://github.com/siderolabs/talos/commit/ab847310efde540b5bfe17570b99af1bb705832b) fix: provide refreshing CA pool (resolvers)\n* [`d63c3ed7d`](https://github.com/siderolabs/talos/commit/d63c3ed7db2b22f7e394fc45d101d03cba463177) docs: update secureboot docs\n* [`493f7ed9d`](https://github.com/siderolabs/talos/commit/493f7ed9d2710eb240eab6b6ab532f41abc818c1) feat: support embedded config\n* [`251df70f6`](https://github.com/siderolabs/talos/commit/251df70f6d33f1d5a3b1b9e4c0c249d8bc85c4b3) feat: add a userspace OOM controller\n* [`7bae5b40b`](https://github.com/siderolabs/talos/commit/7bae5b40b4f22f0f07a586ebd9cda9436086a5f8) feat: implement link configuration\n* [`724857dec`](https://github.com/siderolabs/talos/commit/724857decb95ddeebb2ac5d33c38a71bf7512805) fix(ci): skip netbird extension for tests\n* [`e06a08698`](https://github.com/siderolabs/talos/commit/e06a086989331f28406e8d4234e02d9a6b83f87d) fix: default gateway as string\n* [`7ed07412e`](https://github.com/siderolabs/talos/commit/7ed07412e963e6ee91615adbea095944aa6a56e5) fix: uefi boot entry handling logic\n* [`ea4ed165a`](https://github.com/siderolabs/talos/commit/ea4ed165ad860a5beea17ca2d404bdaa6e5ad933) refactor: efivarfs mock and tests\n* [`1fca111e2`](https://github.com/siderolabs/talos/commit/1fca111e24bcae81b78f007e67b71c9155c0169f) feat: support setting wake-on-lan for Ethernet\n* [`94f78dbe7`](https://github.com/siderolabs/talos/commit/94f78dbe798cb227a0c38b70a1d6840803989290) docs: add a documentation for running Talos in KVM\n* [`46902f8fd`](https://github.com/siderolabs/talos/commit/46902f8fdee257a09be4bc1753c6b3f845ef8089) docs: add TrueFullstaq to adopters\n* [`a28e5cbd5`](https://github.com/siderolabs/talos/commit/a28e5cbd50d11aa6c253a6a9ce1999b9d45effad) chore: update pkgs and tools\n* [`7cf403db8`](https://github.com/siderolabs/talos/commit/7cf403db8ca0e1719195001895cfbc12835b0fdd) docs: step-by-step scaleway documentation to get an image\n* [`687285fa2`](https://github.com/siderolabs/talos/commit/687285fa26ec42dadbfb72580099f6e20bbaf85e) docs: remove 'curl' in wget command\n* [`9db6dc06c`](https://github.com/siderolabs/talos/commit/9db6dc06c3010cd89ce4cb0ec0bde178db0447a4) feat: stop mounting state partition\n* [`53ce93aae`](https://github.com/siderolabs/talos/commit/53ce93aaed3bd5bfcbe926fa69ca3b4b8b45c74f) test: try to clear connection refused more aggressively\n* [`51db5279c`](https://github.com/siderolabs/talos/commit/51db5279c423e4b8637a05e52b26dfc5aa719cbc) fix: bump trustd memory limit\n* [`25204dc8a`](https://github.com/siderolabs/talos/commit/25204dc8a8df79bc876a0bec2492e1147a81d954) fix(machined): change `constants.MinimumGOAMD64Level` using build tag\n* [`9cd2d794d`](https://github.com/siderolabs/talos/commit/9cd2d794d060b637dbac5263ae417a4e83d54efe) feat: ship nft binary with Talos rootfs\n* [`b1416c9fe`](https://github.com/siderolabs/talos/commit/b1416c9fe1d5ea9cd68f9b6b766a288a267cee61) feat: record last log the failed service\n* [`0b129f9ef`](https://github.com/siderolabs/talos/commit/0b129f9efdf57dd9692f7cece6b97719a7ccf80e) feat: enforce more KSPP and hardening sysctls\n* [`11872643c`](https://github.com/siderolabs/talos/commit/11872643c310212c52b4fd7e13b6cc7d6ec7e4fc) chore: drop docs folder\n* [`d30fdcd88`](https://github.com/siderolabs/talos/commit/d30fdcd88f421824cf17b9ecec25be7c8044e857) chore: pass in github token to imager\n* [`b88f27d80`](https://github.com/siderolabs/talos/commit/b88f27d804d60a706f598b50676dad5dd2a9726a) chore: make reset test code a bit better\n* [`1cde53d01`](https://github.com/siderolabs/talos/commit/1cde53d0173fd1ae637855e15fe34bb74bb027a0) test: fix several issues with tests\n* [`16cd127a0`](https://github.com/siderolabs/talos/commit/16cd127a04bb5fc907b7ca04f1c81d4c7150eab2) docs: add docs on updating image cache\n* [`c3ae92b14`](https://github.com/siderolabs/talos/commit/c3ae92b1424d4a2c9bc18cfa394b10eda6c9a20f) fix: build kernel checks only on linux\n* [`2120904ec`](https://github.com/siderolabs/talos/commit/2120904ec534a91f66dcea419b5a29e36a16f6e4) feat: create detached tmpfs\n* [`6bbee6de5`](https://github.com/siderolabs/talos/commit/6bbee6de5b18b25deb4e6f515251187e259aa424) docs: remove 'ceph-data' from volume examples/docs\n* [`07acb3bd2`](https://github.com/siderolabs/talos/commit/07acb3bd2d4f92e80706d1835130bbe6e944d096) fix: use correct order to determine SideroV1 keys directory path\n* [`2d57fa002`](https://github.com/siderolabs/talos/commit/2d57fa00281f8090b85097c66df634101b0cde79) fix: trim zero bytes in the DHCP host & domain response\n* [`451cb5f78`](https://github.com/siderolabs/talos/commit/451cb5f78fac3b2ddfec7d545629fe8c88ea2367) docs: clarify disk partition confusion\n* [`a2122ee5c`](https://github.com/siderolabs/talos/commit/a2122ee5cb9c84f33e0c4b30e9223bb239621d55) feat: implement HostConfig multi-doc\n* [`69ab076b4`](https://github.com/siderolabs/talos/commit/69ab076b4d6e52484677ee7f68a853dc4edfe2bc) fix: re-create cgroups when restarting runners\n* [`297b5cc28`](https://github.com/siderolabs/talos/commit/297b5cc2856710b74b4e0e46b00ae33aea4c1bf7) docs: add docs on node labels\n* [`e168512dd`](https://github.com/siderolabs/talos/commit/e168512dd020da9eac654dae2ba891cf33415c44) fix: apply 'ro' flag to iso9660 filesystems\n* [`7f7acfbb9`](https://github.com/siderolabs/talos/commit/7f7acfbb9f10c243d0b132c1ef079cb77d2727e0) docs: fix typo in doc\n* [`d57882b18`](https://github.com/siderolabs/talos/commit/d57882b1830504fe4bfd5344edae613168db7f0e) feat: update Kubernetes to 1.34.1\n* [`f85f82f32`](https://github.com/siderolabs/talos/commit/f85f82f32f098f97588f404550f72d64786fe329) test: fix flakiness in RawVolumes test\n* [`82569e319`](https://github.com/siderolabs/talos/commit/82569e319eb57b1199db6bfd3e612fb771c8c7cd) feat: update Linux 6.16.6\n* [`2fd2ab4e4`](https://github.com/siderolabs/talos/commit/2fd2ab4e43e06910154705d6ef1d0576a7c04a2b) fix: remove CoreDNS cpu limit\n* [`ce9bc32a0`](https://github.com/siderolabs/talos/commit/ce9bc32a08695873d9054afe2608a76cf7c6088a) chore(ci): rekres to use new runner groups\n* [`8b64f68f6`](https://github.com/siderolabs/talos/commit/8b64f68f6946c2979f6fe2bf617f31639a927bf8) test: improve test stability\n* [`272cb860d`](https://github.com/siderolabs/talos/commit/272cb860d4cfb8464b29ff31567e25fe6c275849) chore: drop the --input-dir flag from the cluster create command\n* [`1b6533675`](https://github.com/siderolabs/talos/commit/1b65336752933acdcbf681767785157714866f88) docs: add note about ca-signed certs for secureboot\n* [`d3f88f50c`](https://github.com/siderolabs/talos/commit/d3f88f50c5394536ee80d19464359408a37d81ff) docs: document talos vip failover behavior\n* [`005fc8bd5`](https://github.com/siderolabs/talos/commit/005fc8bd50fbc4b15b26032b43d1d32c1da22f11) docs: add docs on syncing configs after a kube upgrade\n* [`4d876d9af`](https://github.com/siderolabs/talos/commit/4d876d9af9fcc9828f09d05db124fbdce9c17785) feat: update Go to 1.25.1\n* [`2b556cd22`](https://github.com/siderolabs/talos/commit/2b556cd22a3563f1d86a648ea6c69a4d45edad76) feat: implement multi-doc StaticHostConfig\n* [`a7b776842`](https://github.com/siderolabs/talos/commit/a7b7768420566b6840fc52bb2152e9bf165f8cd3) docs: replace Raspberry Pi 5 links with Talos builder\n* [`a349b20ed`](https://github.com/siderolabs/talos/commit/a349b20ed4b3c05dcd0175541b795331f0f7c64d) docs: clarify that talos does not support intermediate ca\n* [`895133de9`](https://github.com/siderolabs/talos/commit/895133de99158ce3f50b557b77c81d4f0f9d6b40) feat: support configuring PCR states to bind disk encryption\n* [`c1360103b`](https://github.com/siderolabs/talos/commit/c1360103b5e037cf713b7d787436f01e7182821c) docs: fix command for uploading image on Hetzner\n* [`43b5b9d89`](https://github.com/siderolabs/talos/commit/43b5b9d8992ad6df37619b3719b57948e4bd9671) fix: correctly handle status-code 204\n* [`feeb0d312`](https://github.com/siderolabs/talos/commit/feeb0d312ecacb451e5313390939c7c9349d2ba6) feat: update runc to 1.3.1\n* [`421634a14`](https://github.com/siderolabs/talos/commit/421634a1417f529551a75d0bb9be08b73f1120b1) docs: add docs on multihoming\n* [`41af2d230`](https://github.com/siderolabs/talos/commit/41af2d230c2dd5dce5bc931f76a2eb69405dc554) refactor: clean up internal cluster creation code\n* [`3000d9e43`](https://github.com/siderolabs/talos/commit/3000d9e431deaf952d08da724da40789cd743f2c) fix: don't bootstrap talos cluster if there's no config present\n* [`79cb871d0`](https://github.com/siderolabs/talos/commit/79cb871d088e5b1c3a3488610ded14e7a28cec29) feat: use the id of the volume in the mapped luks2 name\n* [`6c322710d`](https://github.com/siderolabs/talos/commit/6c322710d64786f19e2e0e39d65596c8dce71952) chore: refactor mount package\n* [`ced7186e2`](https://github.com/siderolabs/talos/commit/ced7186e2a5f0634d9441b12a5340f5ca4c451ff) refactor: update COSI to 1.11.0\n* [`de2e24fcd`](https://github.com/siderolabs/talos/commit/de2e24fcda590a1ef3f80a5372bb70865a2f47c3) docs: clarify that install-cni image is deprecated\n* [`bef8ef509`](https://github.com/siderolabs/talos/commit/bef8ef509380aba259efcc2f5d1f6632e034160b) docs: add docs on cilium's compatibility with kubespan\n* [`e5acb10fc`](https://github.com/siderolabs/talos/commit/e5acb10fcceba69060507a35caea21281bdc71cc) feat: update pkgs\n* [`c4c1daf0e`](https://github.com/siderolabs/talos/commit/c4c1daf0e2e6675626b974b0c008e101d919c8b5) docs: add info about br_netfilter\n* [`5c52ecac3`](https://github.com/siderolabs/talos/commit/5c52ecac364f917e5f45859f680494a08f85cb90) docs: clarify interactive dashboard resolution control\n* [`15ecb02a4`](https://github.com/siderolabs/talos/commit/15ecb02a4545639ffb8ba5c6e5a413e53129b619) feat: update Linux kernel (memcg_v1, ublk)\n* [`53f18c2f6`](https://github.com/siderolabs/talos/commit/53f18c2f60c84c4b0f944cc343ae1f538e8d1236) fix: enable support for VMWare arm64\n* [`3bbe1c0da`](https://github.com/siderolabs/talos/commit/3bbe1c0da5485b6cd3e7fadd8f020e0d0aca406a) docs: add docs on grow flag\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`4154a77`](https://github.com/siderolabs/crypto/commit/4154a771b09f0023e0d258bba6aecc29febabecb) feat: implement dynamic certificate reloader\n* [`dae07fa`](https://github.com/siderolabs/crypto/commit/dae07fa14f963b34ea67abf0cbc50ba24f280524) chore: update to Go 1.25\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>1 commit</summary>\n<p>\n\n* [`68478e2`](https://github.com/siderolabs/go-api-signature/commit/68478e2f57a3bca4345c6e189c0a4216dfb9b1ed) fix: return `invalid signature` error when a signature is required\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`e21721b`](https://github.com/siderolabs/go-debug/commit/e21721bc4faba9072b5e4e33af60a1f0292547af) chore: add support for Go 1.25\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e7a8b2`](https://github.com/siderolabs/go-loadbalancer/commit/5e7a8b21cbdb156c6fe6f9fd98b8a1bb1186c21c) feat: add jitter and initial health check wait support to upstreams\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>32 commits</summary>\n<p>\n\n* [`202a8e6`](https://github.com/siderolabs/pkgs/commit/202a8e663efaf24b662f349c82c5b6addeb6b3a2) feat: update Linux to 6.16.9\n* [`3a0900f`](https://github.com/siderolabs/pkgs/commit/3a0900f8b464f22773a153c65d85c6dd075cadba) feat: enable SRv6 LWTUNNEL and BPF support\n* [`628efc8`](https://github.com/siderolabs/pkgs/commit/628efc86c2020464c4ee58f419b8b17c8f87aa45) chore: update linuxfirmware and rekres\n* [`9d1fb02`](https://github.com/siderolabs/pkgs/commit/9d1fb029db9837af5529f7de371cc9bc709e8cbe) feat: support adding extra trusted certificates in the kernel\n* [`7fe686d`](https://github.com/siderolabs/pkgs/commit/7fe686dec6959a32a6a6d6610cedd18d963412ad) fix: build nftables with embedded gmp\n* [`fede0a7`](https://github.com/siderolabs/pkgs/commit/fede0a7ec672e835372b8915896fd0e775da0297) feat: add nft binary\n* [`0dae01a`](https://github.com/siderolabs/pkgs/commit/0dae01a735bae635ab987febac42c382d851d7d0) feat: update NVIDIA to 580.82.07\n* [`9ac2392`](https://github.com/siderolabs/pkgs/commit/9ac23925cf350075a4931a54176fdd3d9b9b7cb7) feat: enable Kernel config options for IPVS Maglev hashing scheduler support\n* [`3c5315c`](https://github.com/siderolabs/pkgs/commit/3c5315cd2ae931eb76233d26283f861ace932b1d) feat: update dependencies\n* [`122fa66`](https://github.com/siderolabs/pkgs/commit/122fa6626ff8c300623caa625bdc6bc72e866494) feat: update Linux to 6.16.6\n* [`ab1e866`](https://github.com/siderolabs/pkgs/commit/ab1e86612ac903b811ecd3b76d55e85951190565) feat: update Go to 1.25.1\n* [`7d6ef1b`](https://github.com/siderolabs/pkgs/commit/7d6ef1b187956a8cb2c837f339169b6cb7eb9c12) feat: update runc to 1.3.1\n* [`e067c20`](https://github.com/siderolabs/pkgs/commit/e067c2015302c5069676727f047b6aef9ce0dc0c) feat: enable USB audio support\n* [`c4faa38`](https://github.com/siderolabs/pkgs/commit/c4faa389341f6be5dad5fdd575acf61e9eb170f8) feat: bump dependencies\n* [`453cdfc`](https://github.com/siderolabs/pkgs/commit/453cdfc2fdea9945c8e3531ef190971211eaaf13) feat: enable ublk support\n* [`9824684`](https://github.com/siderolabs/pkgs/commit/982468471d8118ac4653b704512e5f847a148dd7) fix: enable memcg v1\n* [`2447e11`](https://github.com/siderolabs/pkgs/commit/2447e11dcbcb5dc10703515e2185f753b04e20e0) feat: update Linux to 6.16, GCC to 15\n* [`2cfb920`](https://github.com/siderolabs/pkgs/commit/2cfb920acd88d63c3d3ced3a5760549aa180208c) feat: update Linux to 6.15.11, update tools, rekres\n* [`ab4e975`](https://github.com/siderolabs/pkgs/commit/ab4e9755b0e2dbf38c75db5d2ff7720f511fd50c) feat: update Linux to 6.12.43\n* [`cd67e36`](https://github.com/siderolabs/pkgs/commit/cd67e3660fa0a2ad25ca4b8dcd3c1ce9b96b0b72) chore: update kernel config to support max SMP CPUs\n* [`e3b2094`](https://github.com/siderolabs/pkgs/commit/e3b209474060f5a67e36c9239a3a066ee8ace2fe) fix: fix build for new NVIDIA drivers\n* [`fd5fdfd`](https://github.com/siderolabs/pkgs/commit/fd5fdfde0bdc4dfc1e9990300df46b9af23c0dfd) feat: update Nvidia LTS to 580.65.06 and production to 570.172.08\n* [`0edf426`](https://github.com/siderolabs/pkgs/commit/0edf426d758d67f7baaaa42facdc658396f02f9f) fix: backport CVE kernel patches to 6.12\n* [`26d8fef`](https://github.com/siderolabs/pkgs/commit/26d8fefe10329e8d1c285014af0bffe1b9a65431) feat: enable Infiniband IRDMA support\n* [`16b5fac`](https://github.com/siderolabs/pkgs/commit/16b5facdbb37f2ad0329bf131ded62cc9b1239a9) fix: re-enable CPUSETS_V1 cgroups controller\n* [`fd53886`](https://github.com/siderolabs/pkgs/commit/fd53886f4f36e73181b7b1a0718801bf8e2aadb9) feat: update backportable dependencies\n* [`d5f7467`](https://github.com/siderolabs/pkgs/commit/d5f746715727ec34fca7a87ab9f1fac2051f0f75) feat: update Go to 1.24.6\n* [`0bd019f`](https://github.com/siderolabs/pkgs/commit/0bd019f29031b7461fbe49552b88d0e26861f955) feat: update containerd to 2.1.4\n* [`0ba8b5b`](https://github.com/siderolabs/pkgs/commit/0ba8b5b49f3dedcc49f4040a6f5c57329f5c5605) feat: enable F71808E watchdog driver\n* [`895a86b`](https://github.com/siderolabs/pkgs/commit/895a86bcdfedfd9ca1a698d8f8aa71e3600a22c2) fix: enable ISCSI IBFT\n* [`a76a67c`](https://github.com/siderolabs/pkgs/commit/a76a67c860a5100f41223fea936712760b33a4cd) feat: update Linux to 6.12.40\n* [`8b0a561`](https://github.com/siderolabs/pkgs/commit/8b0a56180198d360ea71b2c62669545b867f9a67) feat: enable bootloader control on amd64\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>8 commits</summary>\n<p>\n\n* [`4f90801`](https://github.com/siderolabs/tools/commit/4f908016475257651dc41a4250c2c843b5373d08) chore: update openssl, curl, libexpat and rekres\n* [`c37ac80`](https://github.com/siderolabs/tools/commit/c37ac805a17daa8c0dc26da18b768864b821920b) feat: update Go to 1.25.1\n* [`7c659e9`](https://github.com/siderolabs/tools/commit/7c659e92db3884737abda95e643995107aa14010) feat: update to GCC 15\n* [`83fd7b7`](https://github.com/siderolabs/tools/commit/83fd7b7be62f2f59abeb24c971699895759ebb88) feat: migrate from pkg-config to pkgconf\n* [`edafd5f`](https://github.com/siderolabs/tools/commit/edafd5f395b1fd31650270332a871c830a5fd781) feat: update toolchain for new Go and Linux headers\n* [`65789c7`](https://github.com/siderolabs/tools/commit/65789c75ebd4020a444789cfd74d35fefc2497c2) chore: drop unused vars from Pkgfile\n* [`52db66e`](https://github.com/siderolabs/tools/commit/52db66e8d9e1d83e4872a504d45fdabed31504f7) chore: drop protobuf-related stuff from tools\n* [`e3c3ef2`](https://github.com/siderolabs/tools/commit/e3c3ef2b604fb80143a17879eeec9f30ca7b07dd) feat: update Go to 1.24.6\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.7.0 -> v0.9.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.18.1 -> v1.19.1\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.10.1 -> v1.12.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.29.17 -> v1.31.12\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.32 -> v1.18.9\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.41.2 -> v1.45.6\n* **github.com/aws/smithy-go**                          v1.22.4 -> v1.23.0\n* **github.com/containernetworking/plugins**            v1.7.1 -> v1.8.0\n* **github.com/cosi-project/runtime**                   v1.10.7 -> v1.11.0\n* **github.com/docker/cli**                             v28.3.3 -> v28.4.0\n* **github.com/docker/docker**                          v28.3.3 -> v28.4.0\n* **github.com/docker/go-connections**                  v0.5.0 -> v0.6.0\n* **github.com/equinix-ms/go-vmw-guestrpc**             v0.1.1 -> v1.0.0\n* **github.com/foxboron/go-uefi**                       a3183a1bfc84 -> bf180abb62ac\n* **github.com/gdamore/tcell/v2**                       v2.8.1 -> v2.9.0\n* **github.com/google/cel-go**                          v0.26.0 -> v0.26.1\n* **github.com/google/go-tpm**                          v0.9.5 -> v0.9.6\n* **github.com/gopacket/gopacket**                      v1.3.1 -> v1.4.0\n* **github.com/hetznercloud/hcloud-go/v2**              v2.22.0 -> v2.25.1\n* **github.com/mdlayher/netlink**                       fbb4dce95f42 -> v1.8.0\n* **github.com/miekg/dns**                              v1.1.67 -> v1.1.68\n* **github.com/rivo/tview**                             a4a78f1e05cb -> v0.42.0\n* **github.com/safchain/ethtool**                       v0.6.1 -> v0.6.2\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.34 -> v1.0.0-beta.35\n* **github.com/siderolabs/crypto**                      v0.6.3 -> v0.6.4\n* **github.com/siderolabs/go-api-signature**            v0.3.7 -> v0.3.8\n* **github.com/siderolabs/go-debug**                    v0.5.0 -> v0.6.0\n* **github.com/siderolabs/go-loadbalancer**             v0.4.0 -> v0.5.0\n* **github.com/siderolabs/pkgs**                        v1.11.0-15-g2ac857a -> v1.12.0-alpha.0-30-g202a8e6\n* **github.com/siderolabs/talos/pkg/machinery**         v1.11.0 -> v1.12.0-alpha.0\n* **github.com/siderolabs/tools**                       v1.11.0-2-g8556c73 -> v1.12.0-alpha.0-7-g4f90801\n* **github.com/spf13/cobra**                            v1.9.1 -> v1.10.1\n* **github.com/spf13/pflag**                            v1.0.7 -> v1.0.10\n* **github.com/stretchr/testify**                       v1.10.0 -> v1.11.1\n* **github.com/u-root/u-root**                          v0.14.0 -> v0.15.0\n* **go.etcd.io/etcd/api/v3**                            v3.6.4 -> v3.6.5\n* **go.etcd.io/etcd/client/pkg/v3**                     v3.6.4 -> v3.6.5\n* **go.etcd.io/etcd/client/v3**                         v3.6.4 -> v3.6.5\n* **golang.org/x/net**                                  v0.42.0 -> v0.44.0\n* **golang.org/x/oauth2**                               v0.30.0 -> v0.31.0\n* **golang.org/x/sync**                                 v0.16.0 -> v0.17.0\n* **golang.org/x/sys**                                  v0.34.0 -> v0.36.0\n* **golang.org/x/term**                                 v0.33.0 -> v0.35.0\n* **golang.org/x/text**                                 v0.27.0 -> v0.29.0\n* **golang.org/x/time**                                 v0.12.0 -> v0.13.0\n* **google.golang.org/grpc**                            v1.73.0 -> v1.75.1\n* **google.golang.org/protobuf**                        v1.36.6 -> v1.36.9\n* **k8s.io/api**                                        v0.34.0 -> v0.34.1\n* **k8s.io/apiextensions-apiserver**                    v0.34.0 -> v0.34.1\n* **k8s.io/apiserver**                                  v0.34.0 -> v0.34.1\n* **k8s.io/client-go**                                  v0.34.0 -> v0.34.1\n* **k8s.io/component-base**                             v0.34.0 -> v0.34.1\n* **k8s.io/kube-scheduler**                             v0.34.0 -> v0.34.1\n* **k8s.io/kubectl**                                    v0.34.0 -> v0.34.1\n* **k8s.io/kubelet**                                    v0.34.0 -> v0.34.1\n* **k8s.io/pod-security-admission**                     v0.34.0 -> v0.34.1\n* **k8s.io/utils**                                      4c0f3b243397 -> 0af2bda4dd1d\n\nPrevious release can be found at [v1.11.0](https://github.com/siderolabs/talos/releases/tag/v1.11.0)\n\n## [Talos 1.12.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.12.0-alpha.0) (2025-09-02)\n\nWelcome to the v1.12.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\nLinux: 6.16.4\n\nTalos is built with Go 1.25.0.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitrii Sharshakov\n* Noel Georgi\n* Orzelius\n* Oguz Kilcan\n* Amarachi Iheanacho\n* Mateusz Urbanek\n* 459below\n* Alp Celik\n* Andrew Longwill\n* Dmitry\n* George Gaál\n* Guillaume LEGRAIN\n* Justin Garrison\n* Misha Aksenov\n* MrMrRubic\n* Olivier Doucet\n* Tom\n* Utku Ozdemir\n* kassad\n\n### Changes\n<details><summary>98 commits</summary>\n<p>\n\n* [`6a389cad3`](https://github.com/siderolabs/talos/commit/6a389cad35f80b27fe9c43db9e701ee9f6f6142a) chore: update dependencies\n* [`9d98c2e89`](https://github.com/siderolabs/talos/commit/9d98c2e891258dcf2ef90519d38d0aefb77cd0db) feat: add a cgroup preset for PSI and --skip-cri-resolve\n* [`072f77b16`](https://github.com/siderolabs/talos/commit/072f77b1623cdc838093465b7266b26e20a248ea) chore: prepare for future Talos 1.12-alpha.0 release\n* [`96f41ce88`](https://github.com/siderolabs/talos/commit/96f41ce8840783f783fcc8e0fd6b43302b9bfe43) docs: update qemu and docker docs\n* [`a751cd6b7`](https://github.com/siderolabs/talos/commit/a751cd6b7474a4dc20137e917dbb2229fe9cc8bd) docs: activate Talos v1.11 docs by default\n* [`e8f1ec1c5`](https://github.com/siderolabs/talos/commit/e8f1ec1c5bbd8a6cfb68886e6283e7caaf5fb063) docs: fix broken create qemu command v1.11 docs\n* [`639f0dfdd`](https://github.com/siderolabs/talos/commit/639f0dfdd88c5596439601f3f9600b3aafb24227) feat: update Linux to 6.16.4\n* [`8aa7b3933`](https://github.com/siderolabs/talos/commit/8aa7b3933d07ea45a96844b9c91347a08950e243) fix: bring back linux/armv7 build and update xz\n* [`9cae7ba6b`](https://github.com/siderolabs/talos/commit/9cae7ba6b97a67a5d282c6f667ccb4c3e2111447) feat: update CoreDNS to 1.12.3\n* [`cfef3ad45`](https://github.com/siderolabs/talos/commit/cfef3ad4544498a47de17f6b05fb8374c35e3dd8) fix: drop linux/armv7 build\n* [`42ea2ac50`](https://github.com/siderolabs/talos/commit/42ea2ac5058457dafe666f8d79f08d3c8ee60cfb) fix: update xz module (security)\n* [`4fcfd35b9`](https://github.com/siderolabs/talos/commit/4fcfd35b9510f45d0ef7ae3657eb0916d549d2dd) docs: fix module name example\n* [`50824599a`](https://github.com/siderolabs/talos/commit/50824599a4fa7b72d563a35a4746ca063becf672) chore: update some tools\n* [`bcd297490`](https://github.com/siderolabs/talos/commit/bcd297490c608f593b6dd274945aa2b73c3fd3ee) feat: allow Ed25119 in FIPS mode\n* [`5992138bb`](https://github.com/siderolabs/talos/commit/5992138bb981e84dae917f0f0fdafee4049bc5ec) test: ignore one leaking goroutine\n* [`d155326c1`](https://github.com/siderolabs/talos/commit/d155326c1206979f30a5355f7bdb23cb051e9b78) docs: add sbc unofficial ports docs\n* [`285fa7d22`](https://github.com/siderolabs/talos/commit/285fa7d222be1f5e63c0bb725b206966e2722a3b) docs: add the deploy application docs\n* [`527791f09`](https://github.com/siderolabs/talos/commit/527791f0974afe9c8558b82fa19f4354487693ed) feat: update Kubernetes to 1.34.0\n* [`a1c0e237d`](https://github.com/siderolabs/talos/commit/a1c0e237d6e047bb59c4fbd48e2c2b9e36dd4808) feat: update Linux to 6.15.11, Go to 1.25\n* [`4d7fc25f8`](https://github.com/siderolabs/talos/commit/4d7fc25f8bf20d4489080795a3d0ce0dfb1bc6b8) docs: switch order of wipe disk command\n* [`7368a994d`](https://github.com/siderolabs/talos/commit/7368a994df07cc4e50e3709ac766d8062db070a0) feat: add SOCKS5 proxy support to dynamic proxy dialer\n* [`d63591069`](https://github.com/siderolabs/talos/commit/d635910697b221aee3e9afa6d9e5b398236b6a21) chore: silence linter warnings\n* [`07eb4d7ec`](https://github.com/siderolabs/talos/commit/07eb4d7ec148a7e3c4c6dde080469c1a2fb410fb) fix: set default ram unit to MiB instead of MB\n* [`6b732adc4`](https://github.com/siderolabs/talos/commit/6b732adc43684facfd329f424a34a7e4df36d77b) feat: update Linux to 6.12.43\n* [`b6410914f`](https://github.com/siderolabs/talos/commit/b6410914f74ce01672fdef7e912e37970909281c) feat: add human readable byte size cli flags\n* [`ec70cef99`](https://github.com/siderolabs/talos/commit/ec70cef99005fd7e383fea63b5c23774882fcf28) feat: update NVIDIA drivers and kernel\n* [`0879efa69`](https://github.com/siderolabs/talos/commit/0879efa690ad657e4aed251fcbeba8f5645d73ce) feat: update Kubernetes default to v1.34.0-rc.2\n* [`f504639df`](https://github.com/siderolabs/talos/commit/f504639df4388619f731196ed8e79a6818b6ed5f) feat: add a user-facing create qemu command\n* [`558e0b09a`](https://github.com/siderolabs/talos/commit/558e0b09ab65b353e83b98c9ddf6cb2b67fd060e) test: fix the Image Factory PXE boot test\n* [`d73f0a2e5`](https://github.com/siderolabs/talos/commit/d73f0a2e5b788c7b69c2fb827f7111d5f9c8e706) docs: make readme badges consistent\n* [`f1369af98`](https://github.com/siderolabs/talos/commit/f1369af98e1f6d48fed137e31237956abbd28b0f) chore: use new filesystem api on STATE partition\n* [`366cedbe7`](https://github.com/siderolabs/talos/commit/366cedbe7495ce15bcd0e6c6f7f0add65a41a861) docs: link to kubernetes linux swap tuning\n* [`2f5a16f5e`](https://github.com/siderolabs/talos/commit/2f5a16f5e4ae186a309aef5e3d285897d0fe2df1) fix: make --with-uuid-hostnames functionality available to qemu provider\n* [`70612c1f9`](https://github.com/siderolabs/talos/commit/70612c1f9fc9056e8a3669ff10a385c4e8e03350) refactor: split the PlatformConfigController\n* [`511748339`](https://github.com/siderolabs/talos/commit/51174833997fd9a0a599ab1dde947834b682ab14) docs: add system extension tier documentation\n* [`009fb1540`](https://github.com/siderolabs/talos/commit/009fb1540e0b9f5daac6302f42e8813e596fc87c) test: don't run nvidia tests on integration/aws\n* [`99674ef20`](https://github.com/siderolabs/talos/commit/99674ef20d34166d60563d4bf46fbbfc57399509) docs: apply fixes for what is new\n* [`92db677b5`](https://github.com/siderolabs/talos/commit/92db677b5d32de32ec7e785531b32202e03283b4) fix: image cache lockup on a missing volume\n* [`9c97ed886`](https://github.com/siderolabs/talos/commit/9c97ed886b89b2fb84f47866abdf1000839143c4) fix: version contract parsing in encryption keys handling\n* [`1fc670a08`](https://github.com/siderolabs/talos/commit/1fc670a08dc7af8eaeabdc7134eb77a5c939df40) fix: dial with proxy\n* [`18447d0af`](https://github.com/siderolabs/talos/commit/18447d0afdbcc8fa7db6ae008e4bc4d5b0a0b00a) feat: update Linux to 6.12.41\n* [`f65f39b78`](https://github.com/siderolabs/talos/commit/f65f39b78b0c7881e5f51c66ad022c17c2cd4960) fix: provide mitigation CVE-1999-0524\n* [`8817cc60c`](https://github.com/siderolabs/talos/commit/8817cc60cfaf4b50f11c38d3b25df7df48382033) fix: actually use SIDEROV1_KEYS_DIR env var if it's provided\n* [`b08b20a10`](https://github.com/siderolabs/talos/commit/b08b20a1005256a9e3fc7cae8bcf8eea87f6ac09) feat: use key provider with fallback option for auth type SideroV1\n* [`7a52d7489`](https://github.com/siderolabs/talos/commit/7a52d7489c9709708d55f8f001d70700addc7e1e) fix: kubernetes upgrade options for kubelet\n* [`ea8289f55`](https://github.com/siderolabs/talos/commit/ea8289f550787593b1cd35f2d8da59aa5311880e) feat: add a user facing docker command\n* [`54ad64765`](https://github.com/siderolabs/talos/commit/54ad64765090d90013e4917d1bf494592069beec) chore: re-enable vulncheck\n* [`26bbddea9`](https://github.com/siderolabs/talos/commit/26bbddea95669278363c604316ed85986f312d71) fix: darwin build\n* [`b5d5ef79e`](https://github.com/siderolabs/talos/commit/b5d5ef79e7a2d76e29a7c872c1c418fffc63b0df) fix: set secs field in DHCPv4 packets\n* [`c07911933`](https://github.com/siderolabs/talos/commit/c0791193373e36c35f29c70318432331b4c6ab2a) chore: refactor how tools are being installed\n* [`34f25815c`](https://github.com/siderolabs/talos/commit/34f25815c036d2c91bdfddc9c7d40ca2edf677bd) docs: fork docs for v1.12\n* [`b66b995d3`](https://github.com/siderolabs/talos/commit/b66b995d34306192cbaa4ef68fe39f821b37d1f0) feat: update default Kubernetes to v1.34.0-rc.1\n* [`b967c587d`](https://github.com/siderolabs/talos/commit/b967c587d9f217f25798e0bee0c90393e55dc085) docs: fix clone URL to include `.git`\n* [`b72c68398`](https://github.com/siderolabs/talos/commit/b72c6839806103ac0a76acd46f30eabea0375790) docs: edit the insecure, etcd-metrics, inline and extramanifests\n* [`e5b9c1fff`](https://github.com/siderolabs/talos/commit/e5b9c1ffffec9fd49ffb84a36c918e75eaa8f1ef) docs: remov RAS Syndrome\n* [`701fe774b`](https://github.com/siderolabs/talos/commit/701fe774bd19de7c9f21e043e1520161a8c5fff7) docs: fix cilium links and bump to 1.18.0\n* [`d306713a1`](https://github.com/siderolabs/talos/commit/d306713a13a18d7af6caffd5890d54d91d22cad7) feat: update Go to 1.24.6\n* [`721595a00`](https://github.com/siderolabs/talos/commit/721595a0009f78a2722802ab665957fd767c4d1e) chore: add deadcode elimination linter\n* [`dc4865915`](https://github.com/siderolabs/talos/commit/dc4865915d567942adea3efa66f8ad360f9c4cce) refactor: stop using `text/template` in `machined` code paths\n* [`545be55ed`](https://github.com/siderolabs/talos/commit/545be55edc863245638d4387cb9ee7e7b068f2ba) feat: add a pause function to dashboard\n* [`06a6c0fe3`](https://github.com/siderolabs/talos/commit/06a6c0fe332940b7a70ea2652bc2a5e7bc51bbf3) refactor: fix deadcode elimination with godbus\n* [`2dce8f8d4`](https://github.com/siderolabs/talos/commit/2dce8f8d4693a85d2f3bf46169af8cf502d49f9d) refactor: replace containerd/containerd/v2 module for proper DCE\n* [`9b11d8608`](https://github.com/siderolabs/talos/commit/9b11d86081df8cf77860d2d27eed5d8001ff721e) chore: rekres to configure slack notify workflow for CI failures\n* [`5ce6a660f`](https://github.com/siderolabs/talos/commit/5ce6a660f67f4e2776550a1e621179beb8a6788c) docs: augment the pod security docs\n* [`ada51ff69`](https://github.com/siderolabs/talos/commit/ada51ff696011e15dcd9c661da1d839bdc341745) fix: unmarshal encryption STATE from META\n* [`b9e9b2e07`](https://github.com/siderolabs/talos/commit/b9e9b2e07a645f53ca23355810d485a2622870c9) docs: add what is new notes for 1.11\n* [`53055bdf4`](https://github.com/siderolabs/talos/commit/53055bdf49ce4c81f63c159cdbaa8ea85d9ca2b8) docs: fix typo in kubevirt page\n* [`8d12db480`](https://github.com/siderolabs/talos/commit/8d12db480c38ec37aee5ae7721b2e5ca55ad733e) fix: one more attempt to fix volume mount race on restart\n* [`34d37a268`](https://github.com/siderolabs/talos/commit/34d37a268a9e0098179369af128261dbfc956d1d) chore: rekres to use correct slack channel for slack-notify\n* [`326a00538`](https://github.com/siderolabs/talos/commit/326a00538210bf98b01795d314c1e154a74d2d58) feat: implement `talos.config.early` command line arg\n* [`a5f3000f2`](https://github.com/siderolabs/talos/commit/a5f3000f2e8a79d4e9a5be95fbcac91a2d78675b) feat: implement encryption locking to STATE\n* [`c1e65a342`](https://github.com/siderolabs/talos/commit/c1e65a34256944743e768613b119c0caa517b54d) docs: remove talos API flags from mgmt commands\n* [`181d0bbf5`](https://github.com/siderolabs/talos/commit/181d0bbf5381343d35a01190da45e3442320d7c5) feat: bootedentry resource\n* [`7ad439ac3`](https://github.com/siderolabs/talos/commit/7ad439ac35859695074d3a3efdcdb5c0cab1a5c6) fix: enforce minimum size on user volumes if not set explicitly\n* [`50e37aefd`](https://github.com/siderolabs/talos/commit/50e37aefdbde973bcc8aa352639946490fbe7d94) fix: live reload of TLS client config for discovery client\n* [`87efd75ef`](https://github.com/siderolabs/talos/commit/87efd75efb3e62b88b4f65a221f9fbdd4b4d6ef9) feat: update containerd to 2.1.4\n* [`724b9de6d`](https://github.com/siderolabs/talos/commit/724b9de6d5195bcccc5f484c696429b2f09ab16e) feat: add F71808E watchdog driver\n* [`8af96f7af`](https://github.com/siderolabs/talos/commit/8af96f7afdac1c4d5e2697b897b81e2bddd15f66) docs: add ETCD downgrade documentation\n* [`44edd205d`](https://github.com/siderolabs/talos/commit/44edd205d5fdffab39b65ee62695a40e22ef188c) docs: add remark about 'exclude-from-external-load-balancers' label\n* [`727101926`](https://github.com/siderolabs/talos/commit/7271019263b0dc5b28d2764d19fe531e473222fc) fix(ci): use a random suffix for ami names\n* [`d621ce372`](https://github.com/siderolabs/talos/commit/d621ce3726f20ee568ea3b6ac57d9e8dfa0580cc) fix: grype scan\n* [`d62e255c2`](https://github.com/siderolabs/talos/commit/d62e255c260810a5f0f2959e32592a3331df28d3) fix: issues with reading GPT\n* [`5d0883e14`](https://github.com/siderolabs/talos/commit/5d0883e147163c12a77cd926db799ffed854aedf) feat: update PCI DB module to v0.3.2\n* [`3751c8ccf`](https://github.com/siderolabs/talos/commit/3751c8ccfa1bab9fcd435290f36e9012a5626e40) test: wait for service account test job longer\n* [`a592eb9f9`](https://github.com/siderolabs/talos/commit/a592eb9f98788883a7ec6d17772e10707230a0d8) feat: update Linux to 6.12.40\n* [`4c40e6d3f`](https://github.com/siderolabs/talos/commit/4c40e6d3fb4c2f451a8d7a671df5f6254161bd5d) feat: update etcd to 3.6.4\n* [`2bc37bd2c`](https://github.com/siderolabs/talos/commit/2bc37bd2c9679c8055fd7b52eb310f23a329af4e) docs: fix error in kernel module guide\n* [`bfc57fb86`](https://github.com/siderolabs/talos/commit/bfc57fb863224f7626f49e5b26be06f77bea2e40) chore: tag aws snapshots created via ci with the image name\n* [`06ef7108a`](https://github.com/siderolabs/talos/commit/06ef7108a6050b3a8fd7535f01a469f09042bf56) fix: issue with volume remount on service restart\n* [`03efbff18`](https://github.com/siderolabs/talos/commit/03efbff18e420c4fe960f490f91dd9f4751ece04) docs: add SBOM documentation\n* [`af8a2869d`](https://github.com/siderolabs/talos/commit/af8a2869dbbec073ffaf72a1378682e109b053ec) fix: do not download artifacts for cron Grype scan\n* [`5f442159b`](https://github.com/siderolabs/talos/commit/5f442159b224c96c90badc7176fed17bfb561709) feat: unify disk encryption configuration\n* [`38e176e59`](https://github.com/siderolabs/talos/commit/38e176e594edb3d271d98f78417b9fd5ba0c5288) chore(ci): fix datasource versioning\n* [`85d6b9198`](https://github.com/siderolabs/talos/commit/85d6b919890a1aa9c4f94d5b18861cc617134ff9) feat: update etcd to v3.5.22\n* [`dd7bd2dab`](https://github.com/siderolabs/talos/commit/dd7bd2dab8cf09334e3e353d6a477509bbaa303e) docs: rewrite the getting started and prod docs for v1.10 and v1.11\n* [`136a899aa`](https://github.com/siderolabs/talos/commit/136a899aa25b3fdcdd771594668278d563f09192) chore: regenerate release step with signing fixes\n* [`450b30d5a`](https://github.com/siderolabs/talos/commit/450b30d5a986563869efdbaa074e82d612f6f2ef) chore(ci): add more nvidia test matrix\n* [`451c2c4c3`](https://github.com/siderolabs/talos/commit/451c2c4c39e70c20df58fc31459cd5c789a0e46f) test: add talosctl:latest to the image cache\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`e21721b`](https://github.com/siderolabs/go-debug/commit/e21721bc4faba9072b5e4e33af60a1f0292547af) chore: add support for Go 1.25\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e7a8b2`](https://github.com/siderolabs/go-loadbalancer/commit/5e7a8b21cbdb156c6fe6f9fd98b8a1bb1186c21c) feat: add jitter and initial health check wait support to upstreams\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>16 commits</summary>\n<p>\n\n* [`2447e11`](https://github.com/siderolabs/pkgs/commit/2447e11dcbcb5dc10703515e2185f753b04e20e0) feat: update Linux to 6.16, GCC to 15\n* [`2cfb920`](https://github.com/siderolabs/pkgs/commit/2cfb920acd88d63c3d3ced3a5760549aa180208c) feat: update Linux to 6.15.11, update tools, rekres\n* [`ab4e975`](https://github.com/siderolabs/pkgs/commit/ab4e9755b0e2dbf38c75db5d2ff7720f511fd50c) feat: update Linux to 6.12.43\n* [`cd67e36`](https://github.com/siderolabs/pkgs/commit/cd67e3660fa0a2ad25ca4b8dcd3c1ce9b96b0b72) chore: update kernel config to support max SMP CPUs\n* [`e3b2094`](https://github.com/siderolabs/pkgs/commit/e3b209474060f5a67e36c9239a3a066ee8ace2fe) fix: fix build for new NVIDIA drivers\n* [`fd5fdfd`](https://github.com/siderolabs/pkgs/commit/fd5fdfde0bdc4dfc1e9990300df46b9af23c0dfd) feat: update Nvidia LTS to 580.65.06 and production to 570.172.08\n* [`0edf426`](https://github.com/siderolabs/pkgs/commit/0edf426d758d67f7baaaa42facdc658396f02f9f) fix: backport CVE kernel patches to 6.12\n* [`26d8fef`](https://github.com/siderolabs/pkgs/commit/26d8fefe10329e8d1c285014af0bffe1b9a65431) feat: enable Infiniband IRDMA support\n* [`16b5fac`](https://github.com/siderolabs/pkgs/commit/16b5facdbb37f2ad0329bf131ded62cc9b1239a9) fix: re-enable CPUSETS_V1 cgroups controller\n* [`fd53886`](https://github.com/siderolabs/pkgs/commit/fd53886f4f36e73181b7b1a0718801bf8e2aadb9) feat: update backportable dependencies\n* [`d5f7467`](https://github.com/siderolabs/pkgs/commit/d5f746715727ec34fca7a87ab9f1fac2051f0f75) feat: update Go to 1.24.6\n* [`0bd019f`](https://github.com/siderolabs/pkgs/commit/0bd019f29031b7461fbe49552b88d0e26861f955) feat: update containerd to 2.1.4\n* [`0ba8b5b`](https://github.com/siderolabs/pkgs/commit/0ba8b5b49f3dedcc49f4040a6f5c57329f5c5605) feat: enable F71808E watchdog driver\n* [`895a86b`](https://github.com/siderolabs/pkgs/commit/895a86bcdfedfd9ca1a698d8f8aa71e3600a22c2) fix: enable ISCSI IBFT\n* [`a76a67c`](https://github.com/siderolabs/pkgs/commit/a76a67c860a5100f41223fea936712760b33a4cd) feat: update Linux to 6.12.40\n* [`8b0a561`](https://github.com/siderolabs/pkgs/commit/8b0a56180198d360ea71b2c62669545b867f9a67) feat: enable bootloader control on amd64\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`7c659e9`](https://github.com/siderolabs/tools/commit/7c659e92db3884737abda95e643995107aa14010) feat: update to GCC 15\n* [`83fd7b7`](https://github.com/siderolabs/tools/commit/83fd7b7be62f2f59abeb24c971699895759ebb88) feat: migrate from pkg-config to pkgconf\n* [`edafd5f`](https://github.com/siderolabs/tools/commit/edafd5f395b1fd31650270332a871c830a5fd781) feat: update toolchain for new Go and Linux headers\n* [`65789c7`](https://github.com/siderolabs/tools/commit/65789c75ebd4020a444789cfd74d35fefc2497c2) chore: drop unused vars from Pkgfile\n* [`52db66e`](https://github.com/siderolabs/tools/commit/52db66e8d9e1d83e4872a504d45fdabed31504f7) chore: drop protobuf-related stuff from tools\n* [`e3c3ef2`](https://github.com/siderolabs/tools/commit/e3c3ef2b604fb80143a17879eeec9f30ca7b07dd) feat: update Go to 1.24.6\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.7.0 -> v0.8.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.18.1 -> v1.19.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.10.1 -> v1.11.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.29.17 -> v1.31.6\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.32 -> v1.18.6\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.41.2 -> v1.45.1\n* **github.com/aws/smithy-go**                          v1.22.4 -> v1.23.0\n* **github.com/containernetworking/plugins**            v1.7.1 -> v1.8.0\n* **github.com/docker/go-connections**                  v0.5.0 -> v0.6.0\n* **github.com/gdamore/tcell/v2**                       v2.8.1 -> v2.9.0\n* **github.com/google/cel-go**                          v0.26.0 -> v0.26.1\n* **github.com/gopacket/gopacket**                      v1.3.1 -> v1.4.0\n* **github.com/mdlayher/netlink**                       fbb4dce95f42 -> v1.8.0\n* **github.com/miekg/dns**                              v1.1.67 -> v1.1.68\n* **github.com/rivo/tview**                             a4a78f1e05cb -> v0.42.0\n* **github.com/safchain/ethtool**                       v0.6.1 -> v0.6.2\n* **github.com/siderolabs/go-debug**                    v0.5.0 -> v0.6.0\n* **github.com/siderolabs/go-loadbalancer**             v0.4.0 -> v0.5.0\n* **github.com/siderolabs/pkgs**                        v1.11.0-15-g2ac857a -> v1.12.0-alpha.0-14-g2447e11\n* **github.com/siderolabs/talos/pkg/machinery**         v1.11.0 -> v1.11.0-alpha.3\n* **github.com/siderolabs/tools**                       v1.11.0-2-g8556c73 -> v1.12.0-alpha.0-5-g7c659e9\n* **github.com/spf13/cobra**                            v1.9.1 -> v1.10.1\n* **github.com/spf13/pflag**                            v1.0.7 -> v1.0.9\n* **github.com/stretchr/testify**                       v1.10.0 -> v1.11.1\n* **github.com/u-root/u-root**                          v0.14.0 -> v0.15.0\n* **golang.org/x/net**                                  v0.42.0 -> v0.43.0\n* **golang.org/x/sys**                                  v0.34.0 -> v0.35.0\n* **golang.org/x/term**                                 v0.33.0 -> v0.34.0\n* **golang.org/x/text**                                 v0.27.0 -> v0.28.0\n* **google.golang.org/grpc**                            v1.73.0 -> v1.75.0\n* **google.golang.org/protobuf**                        v1.36.6 -> v1.36.8\n* **k8s.io/utils**                                      4c0f3b243397 -> 0af2bda4dd1d\n\nPrevious release can be found at [v1.11.0](https://github.com/siderolabs/talos/releases/tag/v1.11.0)\n\n## [Talos 1.11.0-alpha.3](https://github.com/siderolabs/talos/releases/tag/v1.11.0-alpha.3) (2025-07-02)\n\nWelcome to the v1.11.0-alpha.3 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Azure\n\nTalos on Azure now defaults to MTU of 1400 bytes for the `eth0` interface to avoid packet fragmentation issues.\nThe default MTU can be overriden with machine configuration.\n\n\n### IMA support removed\n\nTalos now drops the IMA (Integrity Measurement Architecture) support. This feature was not used in Talos for any meaningful security purpose\nand has historically caused performance issues. See #11133 for more details.\n\n\n### Kubernetes Version Validation\n\nTalos now validates Kubernetes version in the image submitted in the machine configuration.\nPreviously this check was performed only on upgrade, but now it is consistently applied to upgrade, initial provisioning, and machine configuration updates.\n\nThis implies that all image references should contain the tag, even if the image is pinned by digest.\n\n\n### Qemu provisioner on MacOS\n\nOn MacOS `talosctl cluster create` command now supports the Qemu provisioner in addition to the Docker provisioner.\n\n\n### Swap Suport\n\nTalos now supports swap on block devices.\nThis feature can be enable by using [SwapVolumeConfig](https://www.talos.dev/v1.11/reference/configuration/block/swapvolumeconfig/) document in the machine configuration.  \n\n\n### Component Updates\n\nLinux: 6.12.35\nKubernetes: 1.34.0-alpha.2\nrunc: 1.3.0\ncontainerd: 2.1.3\nFlannel CNI plugin: 1.7.1-flannel1\nFlannel: 0.27.0\nCoreDNS: 1.12.2\n\nTalos is built with Go 1.24.4.\n\n\n### VMware\n\nTalos VMWare platform now supports `arm64` architecture in addition to `amd64`.\n\n\n### Zswap Support\n\nTalos now supports zswap, a compressed cache for swap pages.\nThis feature can be enabled by using [ZswapConfig](https://www.talos.dev/v1.11/reference/configuration/block/zswapconfig/) document in the machine configuration.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Orzelius\n* Orzelius\n* Justin Garrison\n* Spencer Smith\n* Till Hoffmann\n* Utku Ozdemir\n* Artem Chernyshev\n* Dmitrii Sharshakov\n* Michael Robbins\n* Steve Francis\n* Andrew Longwill\n* Marat Bakeev\n* Olav Thoresen\n* Thibault VINCENT\n* Alvaro \"Chamo\" Linares Cabre\n* Brian Brookman\n* Bryan Mora\n* Clément Nussbaumer\n* Damien\n* David R\n* Dennis Marttinen\n* Dmitriy Matrenichev\n* Joakim Nohlgård\n* Jorik Jonker\n* Justin Seely\n* Luke Cousins\n* Marco Mihai Condrache\n* Markus Reiter\n* Martyn Ranyard\n* Michael Moerz\n* Mike\n* Tan Siewert\n* Tom Keur\n* jvanthienen-gluo\n* killcity\n* yashutanu\n\n### Changes\n<details><summary>170 commits</summary>\n<p>\n\n* [`777335f23`](https://github.com/siderolabs/talos/commit/777335f2342abf1c04a738456678980fcc375e1b) chore: improve cloud image uploader resilience\n* [`14e5eee7d`](https://github.com/siderolabs/talos/commit/14e5eee7d14bdb95e7e632c54705d8753627ab2a) release(v1.11.0-alpha.2): prepare release\n* [`1e5a008f5`](https://github.com/siderolabs/talos/commit/1e5a008f5740af9dd9297ec5616bde9fd102f21f) fix: hold user volume mount point across kubelet restarts\n* [`cdad50590`](https://github.com/siderolabs/talos/commit/cdad50590d4436eb12b959f2ff04457d5632f941) docs: user volumes and kubernetes upgrade updates\n* [`c880835c8`](https://github.com/siderolabs/talos/commit/c880835c809c2a02f0bb6d0450d15df042a50781) feat: implement zswap support\n* [`7f0300f10`](https://github.com/siderolabs/talos/commit/7f0300f108e7f2e9192214f87a13c8ff2ea25866) feat: update dependencies, Kubernetes 1.34.0-alpha.2\n* [`61afbe3d2`](https://github.com/siderolabs/talos/commit/61afbe3d216862a9b9a5c8f521475a0f39cd710e) docs: add vc4 documentation\n* [`b9dbdc8e7`](https://github.com/siderolabs/talos/commit/b9dbdc8e7213c305e4de71516b990641e0fed706) fix: etcd recover with multiple advertised addresses\n* [`19d94c357`](https://github.com/siderolabs/talos/commit/19d94c3574b7b3ee3fbe21fdb56cff5a18e7b91e) feat: update Linux to 6.12.35, containerd to 2.1.3\n* [`44a1fc3b7`](https://github.com/siderolabs/talos/commit/44a1fc3b78589540f5a0d9b8ea4d898474da3a80) fix: treat context canceled as expected error on image pull\n* [`4da2dd537`](https://github.com/siderolabs/talos/commit/4da2dd537d5dae884f47bd3f04ddcd05ac6cd222) feat: enforce Kubernetes version compatibility\n* [`6c7f8201a`](https://github.com/siderolabs/talos/commit/6c7f8201a9ceeec6ecfd0a35b308805ec149f3de) fix: set default MTU on Azure to 1400\n* [`091cd6989`](https://github.com/siderolabs/talos/commit/091cd6989ce8c09885b3ae3e8c594c4770bd0748) docs: small yaml typo fix\n* [`66ecbd48f`](https://github.com/siderolabs/talos/commit/66ecbd48fdaf509bbb2b37327eb0e0891dd81910) docs: update support matrix with omni version\n* [`c948d7617`](https://github.com/siderolabs/talos/commit/c948d7617d1579c462a809b37956fc98270fcce4) docs: minor fixes for creating kernel modules\n* [`cc14c4a25`](https://github.com/siderolabs/talos/commit/cc14c4a25d355910a00e60c69ed641abbb7b40f6) docs: add docs for creating kernel modules\n* [`93bcd3b56`](https://github.com/siderolabs/talos/commit/93bcd3b5623d900a0f731c0f60d3ce0d69c9c32c) docs: create SBOM for Go dependencies\n* [`38c4ce415`](https://github.com/siderolabs/talos/commit/38c4ce415dc8535b4a7403f7a35c5440f2f4aeb6) feat: add user-space InfiniBand modules\n* [`251dc934f`](https://github.com/siderolabs/talos/commit/251dc934f3f4d9d81d6d11fd66cf4e52517d9878) feat: arm64 support for platform vmware\n* [`09b3ad577`](https://github.com/siderolabs/talos/commit/09b3ad5771b4ee813dcb4d53ad8d291b74b8d8fa) feat: update containerd to 2.1.2\n* [`0767dd07b`](https://github.com/siderolabs/talos/commit/0767dd07b9067aeb3470d463ff32874c69082853) chore: enable --with-siderolink-agent on Darwin\n* [`9642198d7`](https://github.com/siderolabs/talos/commit/9642198d76963bd9f6bdda03fb31c165f31f8087) fix: userspace wireguard library overrides\n* [`208f0763e`](https://github.com/siderolabs/talos/commit/208f0763ef2db94a913606051b5d223d1de61f24) chore: fix talosctl build on non-Linux hosts\n* [`87421af87`](https://github.com/siderolabs/talos/commit/87421af87a88851b78e576b2f9b4af9a48f0acb8) docs: expand documentation description\n* [`d32ccfa59`](https://github.com/siderolabs/talos/commit/d32ccfa598284450477af166734595dc952021fa) feat: implement swap support\n* [`8f5cf81db`](https://github.com/siderolabs/talos/commit/8f5cf81dba80015f66037ee181f17eb2294bb8a2) docs: update kvm documentation\n* [`8e84c8b0f`](https://github.com/siderolabs/talos/commit/8e84c8b0f8405be519a9f0530e34a612ff054373) fix: nil pointer deref in quirk\n* [`6e74a3676`](https://github.com/siderolabs/talos/commit/6e74a367636dc21e2bf017d6284bbf998a4bad7d) docs: aad ery basic details on how to run on scaleway\n* [`260d1bc9a`](https://github.com/siderolabs/talos/commit/260d1bc9a93f5f6added5e6998f3d2f08fedb770) fix: correctl close encrypted volumes\n* [`034ef42af`](https://github.com/siderolabs/talos/commit/034ef42af25ee3dacf5dd0391385ea881b6d5d32) fix: update siderolink library for wgtunnel panic fix\n* [`3035744a8`](https://github.com/siderolabs/talos/commit/3035744a8096270691f6bdccfabe34ad53da489c) fix: correctly predict interface name on darwin\n* [`cfcfad3c4`](https://github.com/siderolabs/talos/commit/cfcfad3c45376b8ebb989b865f3c13729c87d388) chore: move `checkUnknownKeys` function to `github.com/siderolabs/gen`\n* [`5ecc53c69`](https://github.com/siderolabs/talos/commit/5ecc53c695ec578dbc32f00fa7df65b31a5e77aa) docs: add macos section to developing-talos.md\n* [`b5b35307f`](https://github.com/siderolabs/talos/commit/b5b35307fe950d0de9ee2ff1d5686af858db13b4) chore: update Go to 1.24.4\n* [`fde772d8d`](https://github.com/siderolabs/talos/commit/fde772d8d82e9d6bc7e63b49c965b8d924e308ab) feat: update Flannel to 0.27.0\n* [`81ca27949`](https://github.com/siderolabs/talos/commit/81ca27949427c546f43b0409b56f733becabc2f6) release(v1.11.0-alpha.1): prepare release\n* [`58a868e68`](https://github.com/siderolabs/talos/commit/58a868e68833e94d691e7ed029dce629446fecc3) chore: fix renovate config, add release-gate label\n* [`a59aaee84`](https://github.com/siderolabs/talos/commit/a59aaee84bcceb20792bc4782748449ad93b0530) feat: bump dependencies, Linux 6.12.31\n* [`e954ee30a`](https://github.com/siderolabs/talos/commit/e954ee30add42de6f42cbb7d96927722102afdb7) docs: typo correction: LongHorn -> Longhorn\n* [`aab053394`](https://github.com/siderolabs/talos/commit/aab053394bafdf718196133e38be010d847db0ad) fix: mashal resource byte slices as strings in YAML\n* [`c7d4191e7`](https://github.com/siderolabs/talos/commit/c7d4191e78bf0a455ab596f46d4cf212dce694a4) fix: rework the way CRI config generation is waited for\n* [`0114183de`](https://github.com/siderolabs/talos/commit/0114183de62e4ab930ff0f10dd156f935d57cf10) docs: update `lastRelease` to 1.10.3\n* [`938b0760a`](https://github.com/siderolabs/talos/commit/938b0760abdb41be1be4da02b877e2c902d594be) docs: update issue template\n* [`2a7b735b2`](https://github.com/siderolabs/talos/commit/2a7b735b264ebcfa22dc2d6044c9d5cd3057b5c2) feat: drop IMA support\n* [`2d5a805b0`](https://github.com/siderolabs/talos/commit/2d5a805b0ebabb804b3c32be18db1d718a91070f) fix: typo in DiscoverdVolume spec\n* [`60c12bad9`](https://github.com/siderolabs/talos/commit/60c12bad93b422db2784b0203d94ca69fa31957c) feat: support nocloud include url userdata directive\n* [`0fd622c82`](https://github.com/siderolabs/talos/commit/0fd622c825ba1fbb833a4b8920ac4c4e56f08a1f) fix(talosctl): correct --help output for dashboard command\n* [`a90c936a1`](https://github.com/siderolabs/talos/commit/a90c936a16756cfe5fe451258f0022b808be17d2) feat: support qemu provisioner on darwin\n* [`5322ca0d3`](https://github.com/siderolabs/talos/commit/5322ca0d372aa20ad90e66f04699b75debb0ab80) docs: update overlay docs\n* [`a60b6322d`](https://github.com/siderolabs/talos/commit/a60b6322d1e8fbd75394e0bdb4435af605b32bbb) fix(ci): drop nebula from extensions test\n* [`dbbb59a67`](https://github.com/siderolabs/talos/commit/dbbb59a6781f79ee34a6e91a72575802561c58b6) docs: add note for default `dataDirHostPath` for Rook\n* [`e26054378`](https://github.com/siderolabs/talos/commit/e2605437826911cd60a6a4d9ee760a6a242e244b) docs: macos qemu provider\n* [`5d0224093`](https://github.com/siderolabs/talos/commit/5d022409357d41831fa1bfd34ccdcfceecca42df) docs: use the cilium-cli image repo in the job installation manifest\n* [`ff80e4cca`](https://github.com/siderolabs/talos/commit/ff80e4cca086fa01d84ceb750111dc9e31ccc978) docs: fix CIDR name\n* [`a5fd15e8b`](https://github.com/siderolabs/talos/commit/a5fd15e8bd4a4547e3658981543401fd9eb8cd80) fix(ci): reproducibility test\n* [`8f8963e50`](https://github.com/siderolabs/talos/commit/8f8963e50d7b05d1361fd44040c0f1ffb94693af) docs: update Nexxen brand\n* [`c6b86872d`](https://github.com/siderolabs/talos/commit/c6b86872dc0d62aef5ad70fce00c411080911ace) fix(ci): iso reproducibility file permissions\n* [`995a1dec4`](https://github.com/siderolabs/talos/commit/995a1dec4a34f49d84daff16b30f8920275a439d) chore: add a check for unsupported darwin flags\n* [`9db5d0c97`](https://github.com/siderolabs/talos/commit/9db5d0c97ac31c7f6ce0b23d999126fc6cc094ec) fix: nocloud metadata for hostname\n* [`3cf325654`](https://github.com/siderolabs/talos/commit/3cf325654e4a7f73196241e59e3ca6b5f24c3e19) feat: modularize more arm64 kernel\n* [`3524745cc`](https://github.com/siderolabs/talos/commit/3524745cc49c51e4f13da954a57ab56d467fd26e) fix: allow any PKI in Talos API\n* [`f438cdb09`](https://github.com/siderolabs/talos/commit/f438cdb0993b17f0e540ecefa39cde09f89730f4) chore: use custom dhcpd server on macos qemu\n* [`11c17fb9a`](https://github.com/siderolabs/talos/commit/11c17fb9aad2443b10e15295069b8e24e0d514e2) fix: metal-iso reproducibility\n* [`7fcb89ee3`](https://github.com/siderolabs/talos/commit/7fcb89ee385fdbf47dae4a8308299c00488df84a) chore: add darwin vmnet qemu support\n* [`fc1237343`](https://github.com/siderolabs/talos/commit/fc1237343f79a1be907c43ac3ce116168409ed17) chore: clean up `/usr/bin`\n* [`b551f32ce`](https://github.com/siderolabs/talos/commit/b551f32ce550f2bc3c679a9857f28d604a297bbf) feat: update containerd to v2.1.1\n* [`67f4154f9`](https://github.com/siderolabs/talos/commit/67f4154f920fc0c58a9a832e14fbc7f9430747b3) docs: update disk-management.md\n* [`0cb137ad7`](https://github.com/siderolabs/talos/commit/0cb137ad7366e2386f49a99aee0a3c5ffb7223f6) fix: make disk size check work on old Talos\n* [`7c057edd5`](https://github.com/siderolabs/talos/commit/7c057edd5f3636dff6932ad9fbd7c51867b0c2c8) fix: use vmdk-convert istead of qemu-img to create VMDK for OVA files\n* [`cd618dad0`](https://github.com/siderolabs/talos/commit/cd618dad0feb1390e5945e2bba1d20bcecf30c2a) chore: update the go-blockdevice package\n* [`0b99631a0`](https://github.com/siderolabs/talos/commit/0b99631a0b64ce8d65ddcf7f40b2168debf11a62) fix: bump apid memory limit\n* [`5451f35b1`](https://github.com/siderolabs/talos/commit/5451f35b148a630c6ab011dce44b52fd2ad327ba) docs: update virtualbox\n* [`bd4d202a5`](https://github.com/siderolabs/talos/commit/bd4d202a5a67c56b6c6e6bc962f6bd51c729759f) refactor: bring owned.State from COSI to simplify tests\n* [`0b96df574`](https://github.com/siderolabs/talos/commit/0b96df57476af86a37bcfdbf28a479444a9e6e5c) feat: update containerd to 2.1.0\n* [`e1a939144`](https://github.com/siderolabs/talos/commit/e1a939144f25acc6a2715feedb30a56a47f6793d) docs: fix formatting in disk encryption\n* [`7a817df1c`](https://github.com/siderolabs/talos/commit/7a817df1cce58de2a16b72b37a54ffc0103af79a) docs: fix typo\n* [`f35b213b2`](https://github.com/siderolabs/talos/commit/f35b213b2b448c2e0065d4698095a843dd2f5268) test: fix DHCP unicast failures in QEMU environment\n* [`7064bbf05`](https://github.com/siderolabs/talos/commit/7064bbf056f083de0f7174c9d3c600871189b4e5) docs: fix vmware factory URL\n* [`78c33bcdb`](https://github.com/siderolabs/talos/commit/78c33bcdb9a30195ce401311e82b2e189faf33f3) feat: update default Kubernetes to v1.33.1\n* [`da6795266`](https://github.com/siderolabs/talos/commit/da67952666d2db2b8b5636bd4cae8af09a139410) fix: disable automatic MAC assignment to bridge interfaces\n* [`ca34adf58`](https://github.com/siderolabs/talos/commit/ca34adf585bfe04d2d1b84f186cb87aa77fc8e00) chore(ci): drop azure keys\n* [`ea5de19fa`](https://github.com/siderolabs/talos/commit/ea5de19fad3f62889899c0d89d08b8b73dfa75da) fix: selinux detection\n* [`52c76ea3a`](https://github.com/siderolabs/talos/commit/52c76ea3a61a4a3cbd963dc2ff0d6d21b4210bcd) fix: consistently apply dynamic grpc proxy dialer\n* [`aa9569e5d`](https://github.com/siderolabs/talos/commit/aa9569e5d8c59b762dfd64a4e9ef42cfdc6f9d51) chore: refactor cluster create cmd flags\n* [`1161faa05`](https://github.com/siderolabs/talos/commit/1161faa0594c033bf032852b880439b2082c9722) docs: fix typo in Cilium docs\n* [`164745e44`](https://github.com/siderolabs/talos/commit/164745e44334146b8a6f696640692c25b731414a) docs: remove `preserve` flag mention in upgrade notes\n* [`9a2ecbaaf`](https://github.com/siderolabs/talos/commit/9a2ecbaaf7b7a3f393dd29272aca34e069a24c6e) fix: makefile operating system param\n* [`118aa69d6`](https://github.com/siderolabs/talos/commit/118aa69d6f6e71b88747db1e8234d478daa54ab4) chore: update cloud-image-uploader dependencies\n* [`acdd721cf`](https://github.com/siderolabs/talos/commit/acdd721cfa62f9888a9ceea1693c17348c0d663a) chore: dump qemu pachine ipam records on darwin\n* [`bb9094534`](https://github.com/siderolabs/talos/commit/bb90945344f02b9cdae6e0e01821792dca25096b) chore: rotate aws iam credentials\n* [`0bfa4ae1b`](https://github.com/siderolabs/talos/commit/0bfa4ae1b06e1e6330adf331e1a97651bbe39b4a) chore: update deps for cloud-image-uploader\n* [`956d7c71b`](https://github.com/siderolabs/talos/commit/956d7c71bcdff639b8261cf6cf1a5d19cf702f75) chore: update sops keys\n* [`e2f819d88`](https://github.com/siderolabs/talos/commit/e2f819d880373102f8a8c7f0ff549e37ba75a08e) test: fix the process runner log collection\n* [`fdac4cfb9`](https://github.com/siderolabs/talos/commit/fdac4cfb9143853eb21d38e1b3d517455b0ba0f2) fix: upgrade go-kubernetes for DRA flag bug\n* [`09d88e1e8`](https://github.com/siderolabs/talos/commit/09d88e1e8374ef19e5730994d9b098333347f0b7) test: fix some flaky tests\n* [`ec1f41a94`](https://github.com/siderolabs/talos/commit/ec1f41a948b1bda02096434e47f2a2a767951fe9) chore: make qemu config server bind work on darwin\n* [`980f4d2b9`](https://github.com/siderolabs/talos/commit/980f4d2b936cfdc3ebc9882f7c25fbf2d2aa49f8) feat: bump dependencies\n* [`95259337e`](https://github.com/siderolabs/talos/commit/95259337ee0ccb22d7e9125074818ac8f9afa7af) fix: k8s 1.32->1.33 upgrade check\n* [`c3c326b40`](https://github.com/siderolabs/talos/commit/c3c326b405804c258b68f19b8d7dacca32535e9b) fix: improve volume mounter automaton\n* [`918b94d9a`](https://github.com/siderolabs/talos/commit/918b94d9a0b71b759073f8f7eb0f5dc7fdff413f) refactor: rewrite disk size check\n* [`ab7e693d7`](https://github.com/siderolabs/talos/commit/ab7e693d76500b6cdc2068221bdfce16633a8b01) chore: make qemu lb address bind work on darwin\n* [`97ceab001`](https://github.com/siderolabs/talos/commit/97ceab001c1bb79407c40d8fff867342656187b9) fix: multiple logic issues in platform network config controller\n* [`46349a9df`](https://github.com/siderolabs/talos/commit/46349a9df5d026a4e4b807a94865d5b3c371d32a) docs: remove azure image gallery instructions\n* [`0cfcdd3de`](https://github.com/siderolabs/talos/commit/0cfcdd3de1a20690ce47d63bb56b3d33d11c1474) docs: fix search on base talos.dev\n* [`78646b4e0`](https://github.com/siderolabs/talos/commit/78646b4e050358b930d27e4eddcfb22c4c825b0c) docs: add registryd debug command\n* [`c6824c211`](https://github.com/siderolabs/talos/commit/c6824c211438a3fb663f4233e8663732ab2ddf44) fix: deny apply config requests without v1alpha1 in \"normal\" mode\n* [`7df0408e4`](https://github.com/siderolabs/talos/commit/7df0408e460ebc392c6927c7b23e3795b9bd2140) fix: interactive installer config gen\n* [`881c5d62b`](https://github.com/siderolabs/talos/commit/881c5d62bf0d1f3311b3cf946b7801f97c1fb94b) fix: suppress duplicate platform config updates\n* [`66d77888e`](https://github.com/siderolabs/talos/commit/66d77888e42798995ddc73db3869d16959e53376) fix: replace downloaded asset paths correctly in cluster create cmd\n* [`6bd6c9b5a`](https://github.com/siderolabs/talos/commit/6bd6c9b5a08ca3b0e9574e1a61edc54c6ff722bb) fix: generate iso greater than 4 gig\n* [`ac140324e`](https://github.com/siderolabs/talos/commit/ac140324ebfb54f580c9b9bbbb55549bd5ffa11e) fix: skip PCR extension if TPM1.2 is found\n* [`09ef1f8a4`](https://github.com/siderolabs/talos/commit/09ef1f8a41c84e6a16729e6b6aff81788da0e3f5) fix: ignore http proxy on grpc socket dial\n* [`22a72dc80`](https://github.com/siderolabs/talos/commit/22a72dc80f2037a4cc7ad696d8dff504deb22630) chore: split options between three structs\n* [`22c34a50f`](https://github.com/siderolabs/talos/commit/22c34a50fc66edd174ab4a65961257de28a6daa0) fix(ci): provision cron jobs\n* [`b3b20eff3`](https://github.com/siderolabs/talos/commit/b3b20eff3a29f74d18df634cbb01f41bde17f2c8) fix: containerd crashing with sigsegv\n* [`f7891c301`](https://github.com/siderolabs/talos/commit/f7891c3018de248c7c66483562227b614689413c) chore: calculate vmnet interface name preemptively\n* [`ae87edffb`](https://github.com/siderolabs/talos/commit/ae87edffbcdaed12fef41541622f27882ed63755) fix: drop libseccomp from rootfs\n* [`f74a805bb`](https://github.com/siderolabs/talos/commit/f74a805bb067f55619cae7aebb92f00bb8173c92) fix: do correct backoff for nocloud reconcile\n* [`01bb294af`](https://github.com/siderolabs/talos/commit/01bb294af63f193dafa12cb623ea77ad67b698fb) fix(ci): provision tests\n* [`e4945be3b`](https://github.com/siderolabs/talos/commit/e4945be3bc43cbc275e2ea5f399a0188c5e16ad8) docs: add registryd debug command\n* [`d8c670ad3`](https://github.com/siderolabs/talos/commit/d8c670ad3ecba32c70ff365eaf7a5a4ccb5d721a) release(v1.11.0-alpha.0): prepare release\n* [`ace44ea61`](https://github.com/siderolabs/talos/commit/ace44ea6169d419f188e0a2456c31f420e61ae77) test: update hydrophone to 0.7.0\n* [`3a1163692`](https://github.com/siderolabs/talos/commit/3a1163692da7b41b17f263ab43d0fd81abafc4f8) chore: cross platform qemu preflight checks\n* [`7914fb104`](https://github.com/siderolabs/talos/commit/7914fb10412d31a1b75c74b0c66578e55fb77bc7) chore: move the create command to it's own package\n* [`c8e619608`](https://github.com/siderolabs/talos/commit/c8e619608dc8898be71a17c54503085ef38abf37) chore: prepare for release 1.11\n* [`1299aaa45`](https://github.com/siderolabs/talos/commit/1299aaa45d997dd23aed380f858cec3bc6b975e4) chore(ci): add extensions test for Youki runtime\n* [`e50ceb221`](https://github.com/siderolabs/talos/commit/e50ceb221e56f0760d5f2fc9e4b821d6b29add05) docs: activate Talos 1.10 docs\n* [`9d12aaeb1`](https://github.com/siderolabs/talos/commit/9d12aaeb19d68c5e692921b938d72347f6129f65) test: improve config patch test\n* [`106a656b6`](https://github.com/siderolabs/talos/commit/106a656b6132e766e9e9ef7b1c12b97a413b5de6) chore: make qemu provider build on darwin\n* [`8013aa06c`](https://github.com/siderolabs/talos/commit/8013aa06cd338f1dd11061d3455767fee4b9783c) test: replace platform metadata test\n* [`2b89c2810`](https://github.com/siderolabs/talos/commit/2b89c2810551ab52678e62fcbf5355dd05c72030) fix: relax etcd APIs RBAC requirements\n* [`1e677587c`](https://github.com/siderolabs/talos/commit/1e677587c0e6c61f724a85f18ee9d436ae6da038) fix: preserve kubelet image suffix\n* [`62ab8af45`](https://github.com/siderolabs/talos/commit/62ab8af459475cbd24a2f34d8923ce70d1fda3db) fix: disk image generation with image cache\n* [`d60626f01`](https://github.com/siderolabs/talos/commit/d60626f017ef495210939ee4f8ef7f623dd325f9) fix: handle encryption type mismatch\n* [`a9109ebd0`](https://github.com/siderolabs/talos/commit/a9109ebd00fcd300bf4262142ade77df6788852b) feat: allow SideroLink unique token in machine config\n* [`2ff3a6e40`](https://github.com/siderolabs/talos/commit/2ff3a6e4079a29b6b45770204fd8cb30369518e9) feat(kernel): add bcache kernel module to core talos\n* [`fa95a2146`](https://github.com/siderolabs/talos/commit/fa95a2146056bfe1ae322cb574fd8d432745b5c9) fix(ci): bios provision test\n* [`f7c5b86be`](https://github.com/siderolabs/talos/commit/f7c5b86be7e2b28906cb66b466a017887ac5e2b6) fix: sync PCR extension with volume provisioning lifecycle\n* [`f90c79474`](https://github.com/siderolabs/talos/commit/f90c79474b50da35ab8e285ee9723957e4b6cf00) chore: show bound driver in pcidevices info\n* [`8db34624c`](https://github.com/siderolabs/talos/commit/8db34624c6ed9707ba1165da790f5b389bd1c92f) fix: handle correctly changing platform network config\n* [`77c7a075b`](https://github.com/siderolabs/talos/commit/77c7a075bbba7ffd24dbd9d5e069ccb50f8143b4) feat: update Kubernetes to 1.33.0\n* [`74f0c48c7`](https://github.com/siderolabs/talos/commit/74f0c48c738b0b80278667c3e5a1c5e1ecd5a078) feat: add version compatibility for Talos 1.11\n* [`c4fb7dad0`](https://github.com/siderolabs/talos/commit/c4fb7dad0ec390781cca54e2348f116cb1cf1866) fix: force DNS runner shutdown on timeout\n* [`c49b4836e`](https://github.com/siderolabs/talos/commit/c49b4836e46725940f4731e182475905ebee6019) docs: hetzner: add note about public iso\n* [`16ea2b113`](https://github.com/siderolabs/talos/commit/16ea2b113fad0c81a96dbcfdf4fd1b9f43bb1282) docs: add what is new for 1.10\n* [`be3f0c018`](https://github.com/siderolabs/talos/commit/be3f0c018c50da3d920ed8fe36d4f31c5d3edfac) fix: fix Gvisor tests with containerd patch\n* [`37db132b3`](https://github.com/siderolabs/talos/commit/37db132b3b3e6c58f15228c64b023e77c15cf012) chore(ci): add provision test with bios\n* [`ec60b70e7`](https://github.com/siderolabs/talos/commit/ec60b70e7245f49f6ac1d48cd4292b85f1d6f79e) fix: set media type to OCI for image cache layer\n* [`a471eb31b`](https://github.com/siderolabs/talos/commit/a471eb31b87b393ee9fc57fbc725801d08386ad4) feat: update Linux 6.12.24, containerd 2.0.5\n* [`54ad5b872`](https://github.com/siderolabs/talos/commit/54ad5b8729c7d54da2efa6baf7886163741176ed) fix: extension services logging to console\n* [`601f036ba`](https://github.com/siderolabs/talos/commit/601f036ba9cc762d6a3c6ae819654005f1d49527) docs: correct flannel extra args example\n* [`ae94377d1`](https://github.com/siderolabs/talos/commit/ae94377d15a3b70248fbb446d13d7ae96bb04e82) feat: support encryption config for user volumes\n* [`9616f6e8d`](https://github.com/siderolabs/talos/commit/9616f6e8d280e64815fe3e1ba324df1dd5d2122d) docs: add caveat for kubespan and host ports\n* [`a1d08a362`](https://github.com/siderolabs/talos/commit/a1d08a3624c7c8b5213b8e9dee1cf9289d6719dc) docs: fixes typo at OpenEBS Mayastor worker patches\n* [`a91e8726e`](https://github.com/siderolabs/talos/commit/a91e8726e433be9db58f1a7a09a4cca422b2b50c) docs: add a dark theme\n* [`c76189c58`](https://github.com/siderolabs/talos/commit/c76189c58a2fe65954924168d7077350974829dd) fix: grub EFI mount point\n* [`4ca985c65`](https://github.com/siderolabs/talos/commit/4ca985c656c1924e550d06c073a7c1b6cb03f392) fix: grub efi platform install\n* [`b31260281`](https://github.com/siderolabs/talos/commit/b31260281dba752e06fcfc645bb020872602d898) docs: update storage.md\n* [`396a29040`](https://github.com/siderolabs/talos/commit/396a290408eff5bda4ad31fafc33496bea9aa899) feat: add new SBCs\n* [`a902f6580`](https://github.com/siderolabs/talos/commit/a902f6580f8e104977521a335a41c0cd70256906) feat: update Flannel to v0.26.7\n* [`2bbefec1a`](https://github.com/siderolabs/talos/commit/2bbefec1abacae2952782fbd163ef52d34f09858) docs: use cache in preview\n* [`6028a8d2d`](https://github.com/siderolabs/talos/commit/6028a8d2da571a8a37712f9917e24372cf5af919) docs: update kubeprism.md\n* [`e51a8ef8c`](https://github.com/siderolabs/talos/commit/e51a8ef8c68bb1cfab2ac845a0b6792d7e000324) fix: prefer new `MountStatus` resource\n* [`d9c7e7946`](https://github.com/siderolabs/talos/commit/d9c7e79462496d6756c55b0672994aa262eaed4f) docs: fix search\n* [`b32fa029b`](https://github.com/siderolabs/talos/commit/b32fa029b3f550b3403e25e23aac889d61366389) feat: update Kubernetes to 1.33.0-rc.1\n* [`f0ea478cb`](https://github.com/siderolabs/talos/commit/f0ea478cb811675a450839b8dcd351e43404efd4) feat: support address priority\n* [`8cd3c8dc7`](https://github.com/siderolabs/talos/commit/8cd3c8dc77b25270ed8dea65cbbd4e87c203ee74) test: fix NVIDIA OSS tests\n* [`62f2d27cd`](https://github.com/siderolabs/talos/commit/62f2d27cd44de5112055b5b47f23b001cadccaae) docs: update virtualbox.md\n* [`141326ea3`](https://github.com/siderolabs/talos/commit/141326ea3bb2e471a5cb51fd565521683a9792fc) docs: fix tabpane styling\n* [`134aa53cc`](https://github.com/siderolabs/talos/commit/134aa53ccaba55754544977d695ad3ca5d34e604) feat: update base CoreDNS code in host DNS to 1.12.1\n</p>\n</details>\n\n### Changes since v1.11.0-alpha.2\n<details><summary>1 commit</summary>\n<p>\n\n* [`777335f23`](https://github.com/siderolabs/talos/commit/777335f2342abf1c04a738456678980fcc375e1b) chore: improve cloud image uploader resilience\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`17107ae`](https://github.com/siderolabs/crypto/commit/17107ae45403a2bcd4fecfb4660b60276652b00d) fix: add generic CSR generator and OpenSSL interop\n* [`53659fc`](https://github.com/siderolabs/crypto/commit/53659fc35f6abd4ada7ffa22ef1b148cf93c0f28) refactor: split into files\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>4 commits</summary>\n<p>\n\n* [`dcb2b74`](https://github.com/siderolabs/gen/commit/dcb2b7417879f230a569ce834dad5c89bd09d6bf) feat: add `panicsafe` package\n* [`b36ee43`](https://github.com/siderolabs/gen/commit/b36ee43f667a7a56b340a3e769868ff2a609bb5b) feat: make `xyaml.CheckUnknownKeys` public\n* [`3e319e7`](https://github.com/siderolabs/gen/commit/3e319e7e52c5a74d1730be8e47952b3d16d91148) feat: implement `xyaml.UnmarshalStrict`\n* [`7c0324f`](https://github.com/siderolabs/gen/commit/7c0324fee9a7cfbdd117f43702fa273689f0db97) chore: future-proof HashTrieMap\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`5b39ef8`](https://github.com/siderolabs/go-circular/commit/5b39ef87df04efeaa47fe6374a8114f39c126122) fix: do not log error if chunk zero was never written\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`657a74b`](https://github.com/siderolabs/go-kubernetes/commit/657a74b7163de7886a9581c446b1de6f21264fd2) feat: prepare for Kubernetes 1.34\n* [`9070be4`](https://github.com/siderolabs/go-kubernetes/commit/9070be4308e23d969ec4fc49b25dab4a27d512e7) fix: remove DynamicResourceAllocation feature gate\n* [`8cb588b`](https://github.com/siderolabs/go-kubernetes/commit/8cb588bc4c93d812de901a6a33e599ba2169cd96) fix: k8s 1.32->1.33 upgrade check\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>41 commits</summary>\n<p>\n\n* [`03bb94c`](https://github.com/siderolabs/pkgs/commit/03bb94c39c02b7028f5d595cb758f59b132fa1d3) feat: update dependencies\n* [`c613abd`](https://github.com/siderolabs/pkgs/commit/c613abd8c4f777ef588cce4ae5563d4024e50507) fix: iptables url\n* [`fae59df`](https://github.com/siderolabs/pkgs/commit/fae59df236da122c84990a187f4648878f2e4bf7) fix: download and copy hailo8 firmware\n* [`fadf1e2`](https://github.com/siderolabs/pkgs/commit/fadf1e22a263b3429fa8fd540b4ff5a71ce8ded2) feat: update containerd to 2.1.2\n* [`a0b0da1`](https://github.com/siderolabs/pkgs/commit/a0b0da10b5745616651d0bcd4b3aa5a06690fd5a) feat: enable io.latency cgroup controller\n* [`0aaa07a`](https://github.com/siderolabs/pkgs/commit/0aaa07a2a1af852efbc65a476cdcc17829e33a99) feat: add hailort package\n* [`8555e94`](https://github.com/siderolabs/pkgs/commit/8555e94f1ed54210ae7768e8ef977e5baec4b2cb) chore: use ftpmirror for GNU sources\n* [`9fbe2b4`](https://github.com/siderolabs/pkgs/commit/9fbe2b43874b701e04e5817f8a9d485139e96d50) feat: update Go to 1.24.4\n* [`79bfa9e`](https://github.com/siderolabs/pkgs/commit/79bfa9e06e5e69955236ffd58323c9936d638d45) feat: update NVIDIA drivers to 570.148.08\n* [`c8b8bd8`](https://github.com/siderolabs/pkgs/commit/c8b8bd8b5eb265f8e8c8955998e428b86d177ab5) feat: bump dependencies\n* [`54bf03e`](https://github.com/siderolabs/pkgs/commit/54bf03ebf24d9ef70a47d4b3b4f30d92191085da) feat: update Linux to 6.12.31\n* [`93b3aaa`](https://github.com/siderolabs/pkgs/commit/93b3aaae5369140058e6a5cbdf83d1da235eb735) feat: add patch for CephFS IMA performance regression\n* [`ebd6627`](https://github.com/siderolabs/pkgs/commit/ebd6627c68406076ed95b2cd629d2ace51bb49b6) feat: disable IMA support\n* [`8aad53b`](https://github.com/siderolabs/pkgs/commit/8aad53bab3201d7f87d39ab61953e04392402efc) feat: add CONFIG_NFT_CONNLIMIT to kernel\n* [`7a299fa`](https://github.com/siderolabs/pkgs/commit/7a299fa02106a7216926d6bcff21fb1cd2da7d73) feat: update Linux to 6.12.30\n* [`8c4603e`](https://github.com/siderolabs/pkgs/commit/8c4603e90335b9aaf180b954ebc43f65dcb2b7b6) feat: move more configs to modules on arm64\n* [`7b1183b`](https://github.com/siderolabs/pkgs/commit/7b1183bea84e46cd8f1a775f95683b8a0039c2d7) feat(kernel): enable IB user-space management and RDMA\n* [`1b1430e`](https://github.com/siderolabs/pkgs/commit/1b1430e82ef62efdd538588183ed27def2bebbaa) fix: drop pcre2 binaries\n* [`487610c`](https://github.com/siderolabs/pkgs/commit/487610c4f286210c22cd813427380af654297791) fix: drop broken symlinks\n* [`f31d518`](https://github.com/siderolabs/pkgs/commit/f31d518eefec0cb672760d00a5c2de37b45dfb45) fix: clean up some binaries\n* [`0f74b9b`](https://github.com/siderolabs/pkgs/commit/0f74b9bd1d097a283f3edd6165161e4e0688a79f) feat: update containerd to v2.1.1\n* [`89b4037`](https://github.com/siderolabs/pkgs/commit/89b40372b8964a9dc9ad3db17a46a9d9c797f60f) fix: tenstorrent pkg name\n* [`a14b544`](https://github.com/siderolabs/pkgs/commit/a14b54409704c1f3beb0f51089dadd3f3e8dc441) chore: drop qemu-tools vmdk support\n* [`2563e47`](https://github.com/siderolabs/pkgs/commit/2563e47ca1bfc755ee4ecf2b470cfed081b54e6f) feat: add tenstorrent package\n* [`2a1c42f`](https://github.com/siderolabs/pkgs/commit/2a1c42fde5fe4009c33d50d571d7d3cfe3a09888) fix(renovate): flannel config\n* [`bfa69a8`](https://github.com/siderolabs/pkgs/commit/bfa69a820e8190aed3a45c00dff5f4f1cc42b7a6) feat: add open-vmdk package\n* [`9f1ba1f`](https://github.com/siderolabs/pkgs/commit/9f1ba1f047c835abdf882540d316055a3e2d1bfc) fix: bring back updated containerd gvisor patch\n* [`1567cb6`](https://github.com/siderolabs/pkgs/commit/1567cb616691dc22fbc3374cdeac11cdbe51bb94) feat: update Linux 6.12.28, firmware\n* [`9bc66e6`](https://github.com/siderolabs/pkgs/commit/9bc66e6bd355f8a86c4becbd78aede1323e3681e) feat: update containerd to 2.1.0\n* [`c6b54e0`](https://github.com/siderolabs/pkgs/commit/c6b54e04fb5d943ff31f05b1e095af65eb901604) feat: enable zswap\n* [`4cd7084`](https://github.com/siderolabs/pkgs/commit/4cd7084634c2b79541da8c6f95c047d4eb0e66a2) feat: update dependencies\n* [`a3fcbf8`](https://github.com/siderolabs/pkgs/commit/a3fcbf812632aaa8e8f9027a88181c284e7d919d) feat(kernel): enable panthor driver\n* [`74d1665`](https://github.com/siderolabs/pkgs/commit/74d16657fd53c30249c3eba75769f90dd84366ce) feat: update ZFS to 2.3.2\n* [`ddc866b`](https://github.com/siderolabs/pkgs/commit/ddc866bc9dd0557c2e9d5d0b234348767769cfd3) feat: update Linux to 6.12.27\n* [`a347857`](https://github.com/siderolabs/pkgs/commit/a347857b33a6a41fe2661a7451c3af65a51404c9) fix: build containerd with Go 1.23\n* [`74da85c`](https://github.com/siderolabs/pkgs/commit/74da85c2cf61b8006af38b3d0d38dc13098d5227) fix: containerd build doesn't need seccomp\n* [`4effa05`](https://github.com/siderolabs/pkgs/commit/4effa0525dc87974052e9dec2685a0ad411773dd) fix: downgrade libseccomp to 2.5.5\n* [`9cea00b`](https://github.com/siderolabs/pkgs/commit/9cea00b4601d7bedf49606b647003f3c6cb0787b) feat: update Linux to 6.12.25\n* [`cb108a5`](https://github.com/siderolabs/pkgs/commit/cb108a514b55a302008fb4c1ce6d88ce0d769b58) feat(kernel): enable bcache module\n* [`d042432`](https://github.com/siderolabs/pkgs/commit/d04243270a4f10f9ecb889883ab42687e5ae6351) fix: backport sandbox fix for Gvisor\n* [`fa625dc`](https://github.com/siderolabs/pkgs/commit/fa625dc6dd97a61cb8479b8b0ab82126650de11b) feat: update Linux 6.12.24, containerd 2.0.5\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>3 commits</summary>\n<p>\n\n* [`5f46f65`](https://github.com/siderolabs/siderolink/commit/5f46f6583b9d03f91c9bb5f637149fe466d17bfc) feat: handle panics in goroutines\n* [`d09ff45`](https://github.com/siderolabs/siderolink/commit/d09ff45b450a37aa84652fa70b5cd3467ee8243d) fix: race in wait value\n* [`d2a79e0`](https://github.com/siderolabs/siderolink/commit/d2a79e0263806b68ff0a44ea9efa58b83fb269ec) fix: clean up device on failure\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`1dfd14b`](https://github.com/siderolabs/tools/commit/1dfd14bd4f2573d1070008c8f9d6a05ca064081e) feat: update Go to 1.24.4\n* [`af3fd64`](https://github.com/siderolabs/tools/commit/af3fd645d48a373396f8346af411c1c827c87376) feat: update dependencies\n* [`e35234b`](https://github.com/siderolabs/tools/commit/e35234bd94c3c16daf06d00848d7752f5e4c7d15) feat: update dependencies\n* [`c96a4e6`](https://github.com/siderolabs/tools/commit/c96a4e671e378f80f161e45942f80b10adfd562d) chore: update toolchain to the latest version\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.6.0 -> v0.7.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.9.0 -> v1.10.1\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.3.1 -> v1.4.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.3.1 -> v1.4.0\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.29.14 -> v1.29.17\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.30 -> v1.16.32\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.38.3 -> v1.41.2\n* **github.com/aws/smithy-go**                                                v1.22.3 -> v1.22.4\n* **github.com/containerd/containerd/api**                                    v1.8.0 -> v1.9.0\n* **github.com/containerd/containerd/v2**                                     v2.0.5 -> v2.1.3\n* **github.com/containernetworking/plugins**                                  v1.6.2 -> v1.7.1\n* **github.com/cosi-project/runtime**                                         v0.10.2 -> v0.10.6\n* **github.com/detailyang/go-fallocate**                                      432fa640bd2e **_new_**\n* **github.com/docker/cli**                                                   v28.0.4 -> v28.3.0\n* **github.com/docker/docker**                                                v28.0.4 -> v28.3.0\n* **github.com/equinix-ms/go-vmw-guestrpc**                                   v0.1.1 **_new_**\n* **github.com/foxboron/go-uefi**                                             69fb7dba244f -> a3183a1bfc84\n* **github.com/google/cadvisor**                                              v0.52.1 -> v0.53.0\n* **github.com/google/cel-go**                                                v0.24.1 -> v0.25.0\n* **github.com/google/go-containerregistry**                                  v0.20.3 -> v0.20.6\n* **github.com/google/go-tpm**                                                v0.9.3 -> v0.9.5\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**                         v2.3.1 -> v2.3.2\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.21.0 -> v2.21.1\n* **github.com/jsimonetti/rtnetlink/v2**                                      v2.0.3 -> v2.0.5\n* **github.com/klauspost/cpuid/v2**                                           v2.2.10 -> v2.2.11\n* **github.com/linode/go-metadata**                                           v0.2.1 -> v0.2.2\n* **github.com/miekg/dns**                                                    v1.1.65 -> v1.1.66\n* **github.com/pkg/xattr**                                                    v0.4.10 -> v0.4.11\n* **github.com/prometheus/procfs**                                            v0.16.0 -> v0.16.1\n* **github.com/rivo/tview**                                                   949945f8d922 -> a4a78f1e05cb\n* **github.com/safchain/ethtool**                                             v0.5.10 -> v0.6.1\n* **github.com/siderolabs/crypto**                                            v0.5.1 -> v0.6.0\n* **github.com/siderolabs/gen**                                               v0.8.0 -> v0.8.4\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.16 -> v2.0.18\n* **github.com/siderolabs/go-circular**                                       v0.2.2 -> v0.2.3\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.21 -> v0.2.24\n* **github.com/siderolabs/pkgs**                                              v1.10.0-5-g48dba3e -> v1.11.0-alpha.0-40-g03bb94c\n* **github.com/siderolabs/siderolink**                                        v0.3.13 -> v0.3.15\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.10.0 -> v1.11.0-alpha.2\n* **github.com/siderolabs/tools**                                             v1.10.0 -> v1.11.0-alpha.0-3-g1dfd14b\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/client/v3**                                               v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.21 -> v3.6.1\n* **golang.org/x/net**                                                        v0.39.0 -> v0.41.0\n* **golang.org/x/oauth2**                                                     v0.29.0 -> v0.30.0\n* **golang.org/x/sync**                                                       v0.13.0 -> v0.15.0\n* **golang.org/x/sys**                                                        v0.32.0 -> v0.33.0\n* **golang.org/x/term**                                                       v0.31.0 -> v0.32.0\n* **golang.org/x/text**                                                       v0.24.0 -> v0.26.0\n* **golang.org/x/time**                                                       v0.11.0 -> v0.12.0\n* **google.golang.org/grpc**                                                  v1.71.1 -> v1.73.0\n* **k8s.io/api**                                                              v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/apimachinery**                                                     v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/apiserver**                                                        v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/client-go**                                                        v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/component-base**                                                   v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/cri-api**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kube-scheduler**                                                   v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kubectl**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kubelet**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/pod-security-admission**                                           v0.33.0 -> v0.34.0-alpha.2\n* **sigs.k8s.io/hydrophone**                                                  b92baf7e0b04 -> v0.7.0\n* **sigs.k8s.io/yaml**                                                        v1.4.0 -> v1.5.0\n\nPrevious release can be found at [v1.10.0](https://github.com/siderolabs/talos/releases/tag/v1.10.0)\n\n## [Talos 1.11.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.11.0-alpha.2) (2025-07-01)\n\nWelcome to the v1.11.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Azure\n\nTalos on Azure now defaults to MTU of 1400 bytes for the `eth0` interface to avoid packet fragmentation issues.\nThe default MTU can be overriden with machine configuration.\n\n\n### IMA support removed\n\nTalos now drops the IMA (Integrity Measurement Architecture) support. This feature was not used in Talos for any meaningful security purpose\nand has historically caused performance issues. See #11133 for more details.\n\n\n### Kubernetes Version Validation\n\nTalos now validates Kubernetes version in the image submitted in the machine configuration.\nPreviously this check was performed only on upgrade, but now it is consistently applied to upgrade, initial provisioning, and machine configuration updates.\n\nThis implies that all image references should contain the tag, even if the image is pinned by digest.\n\n\n### Qemu provisioner on MacOS\n\nOn MacOS `talosctl cluster create` command now supports the Qemu provisioner in addition to the Docker provisioner.\n\n\n### Swap Suport\n\nTalos now supports swap on block devices.\nThis feature can be enable by using [SwapVolumeConfig](https://www.talos.dev/v1.11/reference/configuration/block/swapvolumeconfig/) document in the machine configuration.  \n\n\n### Component Updates\n\nLinux: 6.12.35\nKubernetes: 1.34.0-alpha.2\nrunc: 1.3.0\ncontainerd: 2.1.3\nFlannel CNI plugin: 1.7.1-flannel1\nFlannel: 0.27.0\nCoreDNS: 1.12.2\n\nTalos is built with Go 1.24.4.\n\n\n### VMware\n\nTalos VMWare platform now supports `arm64` architecture in addition to `amd64`.\n\n\n### Zswap Support\n\nTalos now supports zswap, a compressed cache for swap pages.\nThis feature can be enabled by using [ZswapConfig](https://www.talos.dev/v1.11/reference/configuration/block/zswapconfig/) document in the machine configuration.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Orzelius\n* Orzelius\n* Justin Garrison\n* Spencer Smith\n* Till Hoffmann\n* Utku Ozdemir\n* Artem Chernyshev\n* Dmitrii Sharshakov\n* Michael Robbins\n* Steve Francis\n* Andrew Longwill\n* Marat Bakeev\n* Olav Thoresen\n* Thibault VINCENT\n* Alvaro \"Chamo\" Linares Cabre\n* Brian Brookman\n* Bryan Mora\n* Clément Nussbaumer\n* Damien\n* David R\n* Dennis Marttinen\n* Dmitriy Matrenichev\n* Joakim Nohlgård\n* Jorik Jonker\n* Justin Seely\n* Luke Cousins\n* Marco Mihai Condrache\n* Markus Reiter\n* Martyn Ranyard\n* Michael Moerz\n* Mike\n* Tan Siewert\n* Tom Keur\n* jvanthienen-gluo\n* killcity\n* yashutanu\n\n### Changes\n<details><summary>168 commits</summary>\n<p>\n\n* [`1e5a008f5`](https://github.com/siderolabs/talos/commit/1e5a008f5740af9dd9297ec5616bde9fd102f21f) fix: hold user volume mount point across kubelet restarts\n* [`cdad50590`](https://github.com/siderolabs/talos/commit/cdad50590d4436eb12b959f2ff04457d5632f941) docs: user volumes and kubernetes upgrade updates\n* [`c880835c8`](https://github.com/siderolabs/talos/commit/c880835c809c2a02f0bb6d0450d15df042a50781) feat: implement zswap support\n* [`7f0300f10`](https://github.com/siderolabs/talos/commit/7f0300f108e7f2e9192214f87a13c8ff2ea25866) feat: update dependencies, Kubernetes 1.34.0-alpha.2\n* [`61afbe3d2`](https://github.com/siderolabs/talos/commit/61afbe3d216862a9b9a5c8f521475a0f39cd710e) docs: add vc4 documentation\n* [`b9dbdc8e7`](https://github.com/siderolabs/talos/commit/b9dbdc8e7213c305e4de71516b990641e0fed706) fix: etcd recover with multiple advertised addresses\n* [`19d94c357`](https://github.com/siderolabs/talos/commit/19d94c3574b7b3ee3fbe21fdb56cff5a18e7b91e) feat: update Linux to 6.12.35, containerd to 2.1.3\n* [`44a1fc3b7`](https://github.com/siderolabs/talos/commit/44a1fc3b78589540f5a0d9b8ea4d898474da3a80) fix: treat context canceled as expected error on image pull\n* [`4da2dd537`](https://github.com/siderolabs/talos/commit/4da2dd537d5dae884f47bd3f04ddcd05ac6cd222) feat: enforce Kubernetes version compatibility\n* [`6c7f8201a`](https://github.com/siderolabs/talos/commit/6c7f8201a9ceeec6ecfd0a35b308805ec149f3de) fix: set default MTU on Azure to 1400\n* [`091cd6989`](https://github.com/siderolabs/talos/commit/091cd6989ce8c09885b3ae3e8c594c4770bd0748) docs: small yaml typo fix\n* [`66ecbd48f`](https://github.com/siderolabs/talos/commit/66ecbd48fdaf509bbb2b37327eb0e0891dd81910) docs: update support matrix with omni version\n* [`c948d7617`](https://github.com/siderolabs/talos/commit/c948d7617d1579c462a809b37956fc98270fcce4) docs: minor fixes for creating kernel modules\n* [`cc14c4a25`](https://github.com/siderolabs/talos/commit/cc14c4a25d355910a00e60c69ed641abbb7b40f6) docs: add docs for creating kernel modules\n* [`93bcd3b56`](https://github.com/siderolabs/talos/commit/93bcd3b5623d900a0f731c0f60d3ce0d69c9c32c) docs: create SBOM for Go dependencies\n* [`38c4ce415`](https://github.com/siderolabs/talos/commit/38c4ce415dc8535b4a7403f7a35c5440f2f4aeb6) feat: add user-space InfiniBand modules\n* [`251dc934f`](https://github.com/siderolabs/talos/commit/251dc934f3f4d9d81d6d11fd66cf4e52517d9878) feat: arm64 support for platform vmware\n* [`09b3ad577`](https://github.com/siderolabs/talos/commit/09b3ad5771b4ee813dcb4d53ad8d291b74b8d8fa) feat: update containerd to 2.1.2\n* [`0767dd07b`](https://github.com/siderolabs/talos/commit/0767dd07b9067aeb3470d463ff32874c69082853) chore: enable --with-siderolink-agent on Darwin\n* [`9642198d7`](https://github.com/siderolabs/talos/commit/9642198d76963bd9f6bdda03fb31c165f31f8087) fix: userspace wireguard library overrides\n* [`208f0763e`](https://github.com/siderolabs/talos/commit/208f0763ef2db94a913606051b5d223d1de61f24) chore: fix talosctl build on non-Linux hosts\n* [`87421af87`](https://github.com/siderolabs/talos/commit/87421af87a88851b78e576b2f9b4af9a48f0acb8) docs: expand documentation description\n* [`d32ccfa59`](https://github.com/siderolabs/talos/commit/d32ccfa598284450477af166734595dc952021fa) feat: implement swap support\n* [`8f5cf81db`](https://github.com/siderolabs/talos/commit/8f5cf81dba80015f66037ee181f17eb2294bb8a2) docs: update kvm documentation\n* [`8e84c8b0f`](https://github.com/siderolabs/talos/commit/8e84c8b0f8405be519a9f0530e34a612ff054373) fix: nil pointer deref in quirk\n* [`6e74a3676`](https://github.com/siderolabs/talos/commit/6e74a367636dc21e2bf017d6284bbf998a4bad7d) docs: aad ery basic details on how to run on scaleway\n* [`260d1bc9a`](https://github.com/siderolabs/talos/commit/260d1bc9a93f5f6added5e6998f3d2f08fedb770) fix: correctl close encrypted volumes\n* [`034ef42af`](https://github.com/siderolabs/talos/commit/034ef42af25ee3dacf5dd0391385ea881b6d5d32) fix: update siderolink library for wgtunnel panic fix\n* [`3035744a8`](https://github.com/siderolabs/talos/commit/3035744a8096270691f6bdccfabe34ad53da489c) fix: correctly predict interface name on darwin\n* [`cfcfad3c4`](https://github.com/siderolabs/talos/commit/cfcfad3c45376b8ebb989b865f3c13729c87d388) chore: move `checkUnknownKeys` function to `github.com/siderolabs/gen`\n* [`5ecc53c69`](https://github.com/siderolabs/talos/commit/5ecc53c695ec578dbc32f00fa7df65b31a5e77aa) docs: add macos section to developing-talos.md\n* [`b5b35307f`](https://github.com/siderolabs/talos/commit/b5b35307fe950d0de9ee2ff1d5686af858db13b4) chore: update Go to 1.24.4\n* [`fde772d8d`](https://github.com/siderolabs/talos/commit/fde772d8d82e9d6bc7e63b49c965b8d924e308ab) feat: update Flannel to 0.27.0\n* [`81ca27949`](https://github.com/siderolabs/talos/commit/81ca27949427c546f43b0409b56f733becabc2f6) release(v1.11.0-alpha.1): prepare release\n* [`58a868e68`](https://github.com/siderolabs/talos/commit/58a868e68833e94d691e7ed029dce629446fecc3) chore: fix renovate config, add release-gate label\n* [`a59aaee84`](https://github.com/siderolabs/talos/commit/a59aaee84bcceb20792bc4782748449ad93b0530) feat: bump dependencies, Linux 6.12.31\n* [`e954ee30a`](https://github.com/siderolabs/talos/commit/e954ee30add42de6f42cbb7d96927722102afdb7) docs: typo correction: LongHorn -> Longhorn\n* [`aab053394`](https://github.com/siderolabs/talos/commit/aab053394bafdf718196133e38be010d847db0ad) fix: mashal resource byte slices as strings in YAML\n* [`c7d4191e7`](https://github.com/siderolabs/talos/commit/c7d4191e78bf0a455ab596f46d4cf212dce694a4) fix: rework the way CRI config generation is waited for\n* [`0114183de`](https://github.com/siderolabs/talos/commit/0114183de62e4ab930ff0f10dd156f935d57cf10) docs: update `lastRelease` to 1.10.3\n* [`938b0760a`](https://github.com/siderolabs/talos/commit/938b0760abdb41be1be4da02b877e2c902d594be) docs: update issue template\n* [`2a7b735b2`](https://github.com/siderolabs/talos/commit/2a7b735b264ebcfa22dc2d6044c9d5cd3057b5c2) feat: drop IMA support\n* [`2d5a805b0`](https://github.com/siderolabs/talos/commit/2d5a805b0ebabb804b3c32be18db1d718a91070f) fix: typo in DiscoverdVolume spec\n* [`60c12bad9`](https://github.com/siderolabs/talos/commit/60c12bad93b422db2784b0203d94ca69fa31957c) feat: support nocloud include url userdata directive\n* [`0fd622c82`](https://github.com/siderolabs/talos/commit/0fd622c825ba1fbb833a4b8920ac4c4e56f08a1f) fix(talosctl): correct --help output for dashboard command\n* [`a90c936a1`](https://github.com/siderolabs/talos/commit/a90c936a16756cfe5fe451258f0022b808be17d2) feat: support qemu provisioner on darwin\n* [`5322ca0d3`](https://github.com/siderolabs/talos/commit/5322ca0d372aa20ad90e66f04699b75debb0ab80) docs: update overlay docs\n* [`a60b6322d`](https://github.com/siderolabs/talos/commit/a60b6322d1e8fbd75394e0bdb4435af605b32bbb) fix(ci): drop nebula from extensions test\n* [`dbbb59a67`](https://github.com/siderolabs/talos/commit/dbbb59a6781f79ee34a6e91a72575802561c58b6) docs: add note for default `dataDirHostPath` for Rook\n* [`e26054378`](https://github.com/siderolabs/talos/commit/e2605437826911cd60a6a4d9ee760a6a242e244b) docs: macos qemu provider\n* [`5d0224093`](https://github.com/siderolabs/talos/commit/5d022409357d41831fa1bfd34ccdcfceecca42df) docs: use the cilium-cli image repo in the job installation manifest\n* [`ff80e4cca`](https://github.com/siderolabs/talos/commit/ff80e4cca086fa01d84ceb750111dc9e31ccc978) docs: fix CIDR name\n* [`a5fd15e8b`](https://github.com/siderolabs/talos/commit/a5fd15e8bd4a4547e3658981543401fd9eb8cd80) fix(ci): reproducibility test\n* [`8f8963e50`](https://github.com/siderolabs/talos/commit/8f8963e50d7b05d1361fd44040c0f1ffb94693af) docs: update Nexxen brand\n* [`c6b86872d`](https://github.com/siderolabs/talos/commit/c6b86872dc0d62aef5ad70fce00c411080911ace) fix(ci): iso reproducibility file permissions\n* [`995a1dec4`](https://github.com/siderolabs/talos/commit/995a1dec4a34f49d84daff16b30f8920275a439d) chore: add a check for unsupported darwin flags\n* [`9db5d0c97`](https://github.com/siderolabs/talos/commit/9db5d0c97ac31c7f6ce0b23d999126fc6cc094ec) fix: nocloud metadata for hostname\n* [`3cf325654`](https://github.com/siderolabs/talos/commit/3cf325654e4a7f73196241e59e3ca6b5f24c3e19) feat: modularize more arm64 kernel\n* [`3524745cc`](https://github.com/siderolabs/talos/commit/3524745cc49c51e4f13da954a57ab56d467fd26e) fix: allow any PKI in Talos API\n* [`f438cdb09`](https://github.com/siderolabs/talos/commit/f438cdb0993b17f0e540ecefa39cde09f89730f4) chore: use custom dhcpd server on macos qemu\n* [`11c17fb9a`](https://github.com/siderolabs/talos/commit/11c17fb9aad2443b10e15295069b8e24e0d514e2) fix: metal-iso reproducibility\n* [`7fcb89ee3`](https://github.com/siderolabs/talos/commit/7fcb89ee385fdbf47dae4a8308299c00488df84a) chore: add darwin vmnet qemu support\n* [`fc1237343`](https://github.com/siderolabs/talos/commit/fc1237343f79a1be907c43ac3ce116168409ed17) chore: clean up `/usr/bin`\n* [`b551f32ce`](https://github.com/siderolabs/talos/commit/b551f32ce550f2bc3c679a9857f28d604a297bbf) feat: update containerd to v2.1.1\n* [`67f4154f9`](https://github.com/siderolabs/talos/commit/67f4154f920fc0c58a9a832e14fbc7f9430747b3) docs: update disk-management.md\n* [`0cb137ad7`](https://github.com/siderolabs/talos/commit/0cb137ad7366e2386f49a99aee0a3c5ffb7223f6) fix: make disk size check work on old Talos\n* [`7c057edd5`](https://github.com/siderolabs/talos/commit/7c057edd5f3636dff6932ad9fbd7c51867b0c2c8) fix: use vmdk-convert istead of qemu-img to create VMDK for OVA files\n* [`cd618dad0`](https://github.com/siderolabs/talos/commit/cd618dad0feb1390e5945e2bba1d20bcecf30c2a) chore: update the go-blockdevice package\n* [`0b99631a0`](https://github.com/siderolabs/talos/commit/0b99631a0b64ce8d65ddcf7f40b2168debf11a62) fix: bump apid memory limit\n* [`5451f35b1`](https://github.com/siderolabs/talos/commit/5451f35b148a630c6ab011dce44b52fd2ad327ba) docs: update virtualbox\n* [`bd4d202a5`](https://github.com/siderolabs/talos/commit/bd4d202a5a67c56b6c6e6bc962f6bd51c729759f) refactor: bring owned.State from COSI to simplify tests\n* [`0b96df574`](https://github.com/siderolabs/talos/commit/0b96df57476af86a37bcfdbf28a479444a9e6e5c) feat: update containerd to 2.1.0\n* [`e1a939144`](https://github.com/siderolabs/talos/commit/e1a939144f25acc6a2715feedb30a56a47f6793d) docs: fix formatting in disk encryption\n* [`7a817df1c`](https://github.com/siderolabs/talos/commit/7a817df1cce58de2a16b72b37a54ffc0103af79a) docs: fix typo\n* [`f35b213b2`](https://github.com/siderolabs/talos/commit/f35b213b2b448c2e0065d4698095a843dd2f5268) test: fix DHCP unicast failures in QEMU environment\n* [`7064bbf05`](https://github.com/siderolabs/talos/commit/7064bbf056f083de0f7174c9d3c600871189b4e5) docs: fix vmware factory URL\n* [`78c33bcdb`](https://github.com/siderolabs/talos/commit/78c33bcdb9a30195ce401311e82b2e189faf33f3) feat: update default Kubernetes to v1.33.1\n* [`da6795266`](https://github.com/siderolabs/talos/commit/da67952666d2db2b8b5636bd4cae8af09a139410) fix: disable automatic MAC assignment to bridge interfaces\n* [`ca34adf58`](https://github.com/siderolabs/talos/commit/ca34adf585bfe04d2d1b84f186cb87aa77fc8e00) chore(ci): drop azure keys\n* [`ea5de19fa`](https://github.com/siderolabs/talos/commit/ea5de19fad3f62889899c0d89d08b8b73dfa75da) fix: selinux detection\n* [`52c76ea3a`](https://github.com/siderolabs/talos/commit/52c76ea3a61a4a3cbd963dc2ff0d6d21b4210bcd) fix: consistently apply dynamic grpc proxy dialer\n* [`aa9569e5d`](https://github.com/siderolabs/talos/commit/aa9569e5d8c59b762dfd64a4e9ef42cfdc6f9d51) chore: refactor cluster create cmd flags\n* [`1161faa05`](https://github.com/siderolabs/talos/commit/1161faa0594c033bf032852b880439b2082c9722) docs: fix typo in Cilium docs\n* [`164745e44`](https://github.com/siderolabs/talos/commit/164745e44334146b8a6f696640692c25b731414a) docs: remove `preserve` flag mention in upgrade notes\n* [`9a2ecbaaf`](https://github.com/siderolabs/talos/commit/9a2ecbaaf7b7a3f393dd29272aca34e069a24c6e) fix: makefile operating system param\n* [`118aa69d6`](https://github.com/siderolabs/talos/commit/118aa69d6f6e71b88747db1e8234d478daa54ab4) chore: update cloud-image-uploader dependencies\n* [`acdd721cf`](https://github.com/siderolabs/talos/commit/acdd721cfa62f9888a9ceea1693c17348c0d663a) chore: dump qemu pachine ipam records on darwin\n* [`bb9094534`](https://github.com/siderolabs/talos/commit/bb90945344f02b9cdae6e0e01821792dca25096b) chore: rotate aws iam credentials\n* [`0bfa4ae1b`](https://github.com/siderolabs/talos/commit/0bfa4ae1b06e1e6330adf331e1a97651bbe39b4a) chore: update deps for cloud-image-uploader\n* [`956d7c71b`](https://github.com/siderolabs/talos/commit/956d7c71bcdff639b8261cf6cf1a5d19cf702f75) chore: update sops keys\n* [`e2f819d88`](https://github.com/siderolabs/talos/commit/e2f819d880373102f8a8c7f0ff549e37ba75a08e) test: fix the process runner log collection\n* [`fdac4cfb9`](https://github.com/siderolabs/talos/commit/fdac4cfb9143853eb21d38e1b3d517455b0ba0f2) fix: upgrade go-kubernetes for DRA flag bug\n* [`09d88e1e8`](https://github.com/siderolabs/talos/commit/09d88e1e8374ef19e5730994d9b098333347f0b7) test: fix some flaky tests\n* [`ec1f41a94`](https://github.com/siderolabs/talos/commit/ec1f41a948b1bda02096434e47f2a2a767951fe9) chore: make qemu config server bind work on darwin\n* [`980f4d2b9`](https://github.com/siderolabs/talos/commit/980f4d2b936cfdc3ebc9882f7c25fbf2d2aa49f8) feat: bump dependencies\n* [`95259337e`](https://github.com/siderolabs/talos/commit/95259337ee0ccb22d7e9125074818ac8f9afa7af) fix: k8s 1.32->1.33 upgrade check\n* [`c3c326b40`](https://github.com/siderolabs/talos/commit/c3c326b405804c258b68f19b8d7dacca32535e9b) fix: improve volume mounter automaton\n* [`918b94d9a`](https://github.com/siderolabs/talos/commit/918b94d9a0b71b759073f8f7eb0f5dc7fdff413f) refactor: rewrite disk size check\n* [`ab7e693d7`](https://github.com/siderolabs/talos/commit/ab7e693d76500b6cdc2068221bdfce16633a8b01) chore: make qemu lb address bind work on darwin\n* [`97ceab001`](https://github.com/siderolabs/talos/commit/97ceab001c1bb79407c40d8fff867342656187b9) fix: multiple logic issues in platform network config controller\n* [`46349a9df`](https://github.com/siderolabs/talos/commit/46349a9df5d026a4e4b807a94865d5b3c371d32a) docs: remove azure image gallery instructions\n* [`0cfcdd3de`](https://github.com/siderolabs/talos/commit/0cfcdd3de1a20690ce47d63bb56b3d33d11c1474) docs: fix search on base talos.dev\n* [`78646b4e0`](https://github.com/siderolabs/talos/commit/78646b4e050358b930d27e4eddcfb22c4c825b0c) docs: add registryd debug command\n* [`c6824c211`](https://github.com/siderolabs/talos/commit/c6824c211438a3fb663f4233e8663732ab2ddf44) fix: deny apply config requests without v1alpha1 in \"normal\" mode\n* [`7df0408e4`](https://github.com/siderolabs/talos/commit/7df0408e460ebc392c6927c7b23e3795b9bd2140) fix: interactive installer config gen\n* [`881c5d62b`](https://github.com/siderolabs/talos/commit/881c5d62bf0d1f3311b3cf946b7801f97c1fb94b) fix: suppress duplicate platform config updates\n* [`66d77888e`](https://github.com/siderolabs/talos/commit/66d77888e42798995ddc73db3869d16959e53376) fix: replace downloaded asset paths correctly in cluster create cmd\n* [`6bd6c9b5a`](https://github.com/siderolabs/talos/commit/6bd6c9b5a08ca3b0e9574e1a61edc54c6ff722bb) fix: generate iso greater than 4 gig\n* [`ac140324e`](https://github.com/siderolabs/talos/commit/ac140324ebfb54f580c9b9bbbb55549bd5ffa11e) fix: skip PCR extension if TPM1.2 is found\n* [`09ef1f8a4`](https://github.com/siderolabs/talos/commit/09ef1f8a41c84e6a16729e6b6aff81788da0e3f5) fix: ignore http proxy on grpc socket dial\n* [`22a72dc80`](https://github.com/siderolabs/talos/commit/22a72dc80f2037a4cc7ad696d8dff504deb22630) chore: split options between three structs\n* [`22c34a50f`](https://github.com/siderolabs/talos/commit/22c34a50fc66edd174ab4a65961257de28a6daa0) fix(ci): provision cron jobs\n* [`b3b20eff3`](https://github.com/siderolabs/talos/commit/b3b20eff3a29f74d18df634cbb01f41bde17f2c8) fix: containerd crashing with sigsegv\n* [`f7891c301`](https://github.com/siderolabs/talos/commit/f7891c3018de248c7c66483562227b614689413c) chore: calculate vmnet interface name preemptively\n* [`ae87edffb`](https://github.com/siderolabs/talos/commit/ae87edffbcdaed12fef41541622f27882ed63755) fix: drop libseccomp from rootfs\n* [`f74a805bb`](https://github.com/siderolabs/talos/commit/f74a805bb067f55619cae7aebb92f00bb8173c92) fix: do correct backoff for nocloud reconcile\n* [`01bb294af`](https://github.com/siderolabs/talos/commit/01bb294af63f193dafa12cb623ea77ad67b698fb) fix(ci): provision tests\n* [`e4945be3b`](https://github.com/siderolabs/talos/commit/e4945be3bc43cbc275e2ea5f399a0188c5e16ad8) docs: add registryd debug command\n* [`d8c670ad3`](https://github.com/siderolabs/talos/commit/d8c670ad3ecba32c70ff365eaf7a5a4ccb5d721a) release(v1.11.0-alpha.0): prepare release\n* [`ace44ea61`](https://github.com/siderolabs/talos/commit/ace44ea6169d419f188e0a2456c31f420e61ae77) test: update hydrophone to 0.7.0\n* [`3a1163692`](https://github.com/siderolabs/talos/commit/3a1163692da7b41b17f263ab43d0fd81abafc4f8) chore: cross platform qemu preflight checks\n* [`7914fb104`](https://github.com/siderolabs/talos/commit/7914fb10412d31a1b75c74b0c66578e55fb77bc7) chore: move the create command to it's own package\n* [`c8e619608`](https://github.com/siderolabs/talos/commit/c8e619608dc8898be71a17c54503085ef38abf37) chore: prepare for release 1.11\n* [`1299aaa45`](https://github.com/siderolabs/talos/commit/1299aaa45d997dd23aed380f858cec3bc6b975e4) chore(ci): add extensions test for Youki runtime\n* [`e50ceb221`](https://github.com/siderolabs/talos/commit/e50ceb221e56f0760d5f2fc9e4b821d6b29add05) docs: activate Talos 1.10 docs\n* [`9d12aaeb1`](https://github.com/siderolabs/talos/commit/9d12aaeb19d68c5e692921b938d72347f6129f65) test: improve config patch test\n* [`106a656b6`](https://github.com/siderolabs/talos/commit/106a656b6132e766e9e9ef7b1c12b97a413b5de6) chore: make qemu provider build on darwin\n* [`8013aa06c`](https://github.com/siderolabs/talos/commit/8013aa06cd338f1dd11061d3455767fee4b9783c) test: replace platform metadata test\n* [`2b89c2810`](https://github.com/siderolabs/talos/commit/2b89c2810551ab52678e62fcbf5355dd05c72030) fix: relax etcd APIs RBAC requirements\n* [`1e677587c`](https://github.com/siderolabs/talos/commit/1e677587c0e6c61f724a85f18ee9d436ae6da038) fix: preserve kubelet image suffix\n* [`62ab8af45`](https://github.com/siderolabs/talos/commit/62ab8af459475cbd24a2f34d8923ce70d1fda3db) fix: disk image generation with image cache\n* [`d60626f01`](https://github.com/siderolabs/talos/commit/d60626f017ef495210939ee4f8ef7f623dd325f9) fix: handle encryption type mismatch\n* [`a9109ebd0`](https://github.com/siderolabs/talos/commit/a9109ebd00fcd300bf4262142ade77df6788852b) feat: allow SideroLink unique token in machine config\n* [`2ff3a6e40`](https://github.com/siderolabs/talos/commit/2ff3a6e4079a29b6b45770204fd8cb30369518e9) feat(kernel): add bcache kernel module to core talos\n* [`fa95a2146`](https://github.com/siderolabs/talos/commit/fa95a2146056bfe1ae322cb574fd8d432745b5c9) fix(ci): bios provision test\n* [`f7c5b86be`](https://github.com/siderolabs/talos/commit/f7c5b86be7e2b28906cb66b466a017887ac5e2b6) fix: sync PCR extension with volume provisioning lifecycle\n* [`f90c79474`](https://github.com/siderolabs/talos/commit/f90c79474b50da35ab8e285ee9723957e4b6cf00) chore: show bound driver in pcidevices info\n* [`8db34624c`](https://github.com/siderolabs/talos/commit/8db34624c6ed9707ba1165da790f5b389bd1c92f) fix: handle correctly changing platform network config\n* [`77c7a075b`](https://github.com/siderolabs/talos/commit/77c7a075bbba7ffd24dbd9d5e069ccb50f8143b4) feat: update Kubernetes to 1.33.0\n* [`74f0c48c7`](https://github.com/siderolabs/talos/commit/74f0c48c738b0b80278667c3e5a1c5e1ecd5a078) feat: add version compatibility for Talos 1.11\n* [`c4fb7dad0`](https://github.com/siderolabs/talos/commit/c4fb7dad0ec390781cca54e2348f116cb1cf1866) fix: force DNS runner shutdown on timeout\n* [`c49b4836e`](https://github.com/siderolabs/talos/commit/c49b4836e46725940f4731e182475905ebee6019) docs: hetzner: add note about public iso\n* [`16ea2b113`](https://github.com/siderolabs/talos/commit/16ea2b113fad0c81a96dbcfdf4fd1b9f43bb1282) docs: add what is new for 1.10\n* [`be3f0c018`](https://github.com/siderolabs/talos/commit/be3f0c018c50da3d920ed8fe36d4f31c5d3edfac) fix: fix Gvisor tests with containerd patch\n* [`37db132b3`](https://github.com/siderolabs/talos/commit/37db132b3b3e6c58f15228c64b023e77c15cf012) chore(ci): add provision test with bios\n* [`ec60b70e7`](https://github.com/siderolabs/talos/commit/ec60b70e7245f49f6ac1d48cd4292b85f1d6f79e) fix: set media type to OCI for image cache layer\n* [`a471eb31b`](https://github.com/siderolabs/talos/commit/a471eb31b87b393ee9fc57fbc725801d08386ad4) feat: update Linux 6.12.24, containerd 2.0.5\n* [`54ad5b872`](https://github.com/siderolabs/talos/commit/54ad5b8729c7d54da2efa6baf7886163741176ed) fix: extension services logging to console\n* [`601f036ba`](https://github.com/siderolabs/talos/commit/601f036ba9cc762d6a3c6ae819654005f1d49527) docs: correct flannel extra args example\n* [`ae94377d1`](https://github.com/siderolabs/talos/commit/ae94377d15a3b70248fbb446d13d7ae96bb04e82) feat: support encryption config for user volumes\n* [`9616f6e8d`](https://github.com/siderolabs/talos/commit/9616f6e8d280e64815fe3e1ba324df1dd5d2122d) docs: add caveat for kubespan and host ports\n* [`a1d08a362`](https://github.com/siderolabs/talos/commit/a1d08a3624c7c8b5213b8e9dee1cf9289d6719dc) docs: fixes typo at OpenEBS Mayastor worker patches\n* [`a91e8726e`](https://github.com/siderolabs/talos/commit/a91e8726e433be9db58f1a7a09a4cca422b2b50c) docs: add a dark theme\n* [`c76189c58`](https://github.com/siderolabs/talos/commit/c76189c58a2fe65954924168d7077350974829dd) fix: grub EFI mount point\n* [`4ca985c65`](https://github.com/siderolabs/talos/commit/4ca985c656c1924e550d06c073a7c1b6cb03f392) fix: grub efi platform install\n* [`b31260281`](https://github.com/siderolabs/talos/commit/b31260281dba752e06fcfc645bb020872602d898) docs: update storage.md\n* [`396a29040`](https://github.com/siderolabs/talos/commit/396a290408eff5bda4ad31fafc33496bea9aa899) feat: add new SBCs\n* [`a902f6580`](https://github.com/siderolabs/talos/commit/a902f6580f8e104977521a335a41c0cd70256906) feat: update Flannel to v0.26.7\n* [`2bbefec1a`](https://github.com/siderolabs/talos/commit/2bbefec1abacae2952782fbd163ef52d34f09858) docs: use cache in preview\n* [`6028a8d2d`](https://github.com/siderolabs/talos/commit/6028a8d2da571a8a37712f9917e24372cf5af919) docs: update kubeprism.md\n* [`e51a8ef8c`](https://github.com/siderolabs/talos/commit/e51a8ef8c68bb1cfab2ac845a0b6792d7e000324) fix: prefer new `MountStatus` resource\n* [`d9c7e7946`](https://github.com/siderolabs/talos/commit/d9c7e79462496d6756c55b0672994aa262eaed4f) docs: fix search\n* [`b32fa029b`](https://github.com/siderolabs/talos/commit/b32fa029b3f550b3403e25e23aac889d61366389) feat: update Kubernetes to 1.33.0-rc.1\n* [`f0ea478cb`](https://github.com/siderolabs/talos/commit/f0ea478cb811675a450839b8dcd351e43404efd4) feat: support address priority\n* [`8cd3c8dc7`](https://github.com/siderolabs/talos/commit/8cd3c8dc77b25270ed8dea65cbbd4e87c203ee74) test: fix NVIDIA OSS tests\n* [`62f2d27cd`](https://github.com/siderolabs/talos/commit/62f2d27cd44de5112055b5b47f23b001cadccaae) docs: update virtualbox.md\n* [`141326ea3`](https://github.com/siderolabs/talos/commit/141326ea3bb2e471a5cb51fd565521683a9792fc) docs: fix tabpane styling\n* [`134aa53cc`](https://github.com/siderolabs/talos/commit/134aa53ccaba55754544977d695ad3ca5d34e604) feat: update base CoreDNS code in host DNS to 1.12.1\n</p>\n</details>\n\n### Changes since v1.11.0-alpha.1\n<details><summary>33 commits</summary>\n<p>\n\n* [`1e5a008f5`](https://github.com/siderolabs/talos/commit/1e5a008f5740af9dd9297ec5616bde9fd102f21f) fix: hold user volume mount point across kubelet restarts\n* [`cdad50590`](https://github.com/siderolabs/talos/commit/cdad50590d4436eb12b959f2ff04457d5632f941) docs: user volumes and kubernetes upgrade updates\n* [`c880835c8`](https://github.com/siderolabs/talos/commit/c880835c809c2a02f0bb6d0450d15df042a50781) feat: implement zswap support\n* [`7f0300f10`](https://github.com/siderolabs/talos/commit/7f0300f108e7f2e9192214f87a13c8ff2ea25866) feat: update dependencies, Kubernetes 1.34.0-alpha.2\n* [`61afbe3d2`](https://github.com/siderolabs/talos/commit/61afbe3d216862a9b9a5c8f521475a0f39cd710e) docs: add vc4 documentation\n* [`b9dbdc8e7`](https://github.com/siderolabs/talos/commit/b9dbdc8e7213c305e4de71516b990641e0fed706) fix: etcd recover with multiple advertised addresses\n* [`19d94c357`](https://github.com/siderolabs/talos/commit/19d94c3574b7b3ee3fbe21fdb56cff5a18e7b91e) feat: update Linux to 6.12.35, containerd to 2.1.3\n* [`44a1fc3b7`](https://github.com/siderolabs/talos/commit/44a1fc3b78589540f5a0d9b8ea4d898474da3a80) fix: treat context canceled as expected error on image pull\n* [`4da2dd537`](https://github.com/siderolabs/talos/commit/4da2dd537d5dae884f47bd3f04ddcd05ac6cd222) feat: enforce Kubernetes version compatibility\n* [`6c7f8201a`](https://github.com/siderolabs/talos/commit/6c7f8201a9ceeec6ecfd0a35b308805ec149f3de) fix: set default MTU on Azure to 1400\n* [`091cd6989`](https://github.com/siderolabs/talos/commit/091cd6989ce8c09885b3ae3e8c594c4770bd0748) docs: small yaml typo fix\n* [`66ecbd48f`](https://github.com/siderolabs/talos/commit/66ecbd48fdaf509bbb2b37327eb0e0891dd81910) docs: update support matrix with omni version\n* [`c948d7617`](https://github.com/siderolabs/talos/commit/c948d7617d1579c462a809b37956fc98270fcce4) docs: minor fixes for creating kernel modules\n* [`cc14c4a25`](https://github.com/siderolabs/talos/commit/cc14c4a25d355910a00e60c69ed641abbb7b40f6) docs: add docs for creating kernel modules\n* [`93bcd3b56`](https://github.com/siderolabs/talos/commit/93bcd3b5623d900a0f731c0f60d3ce0d69c9c32c) docs: create SBOM for Go dependencies\n* [`38c4ce415`](https://github.com/siderolabs/talos/commit/38c4ce415dc8535b4a7403f7a35c5440f2f4aeb6) feat: add user-space InfiniBand modules\n* [`251dc934f`](https://github.com/siderolabs/talos/commit/251dc934f3f4d9d81d6d11fd66cf4e52517d9878) feat: arm64 support for platform vmware\n* [`09b3ad577`](https://github.com/siderolabs/talos/commit/09b3ad5771b4ee813dcb4d53ad8d291b74b8d8fa) feat: update containerd to 2.1.2\n* [`0767dd07b`](https://github.com/siderolabs/talos/commit/0767dd07b9067aeb3470d463ff32874c69082853) chore: enable --with-siderolink-agent on Darwin\n* [`9642198d7`](https://github.com/siderolabs/talos/commit/9642198d76963bd9f6bdda03fb31c165f31f8087) fix: userspace wireguard library overrides\n* [`208f0763e`](https://github.com/siderolabs/talos/commit/208f0763ef2db94a913606051b5d223d1de61f24) chore: fix talosctl build on non-Linux hosts\n* [`87421af87`](https://github.com/siderolabs/talos/commit/87421af87a88851b78e576b2f9b4af9a48f0acb8) docs: expand documentation description\n* [`d32ccfa59`](https://github.com/siderolabs/talos/commit/d32ccfa598284450477af166734595dc952021fa) feat: implement swap support\n* [`8f5cf81db`](https://github.com/siderolabs/talos/commit/8f5cf81dba80015f66037ee181f17eb2294bb8a2) docs: update kvm documentation\n* [`8e84c8b0f`](https://github.com/siderolabs/talos/commit/8e84c8b0f8405be519a9f0530e34a612ff054373) fix: nil pointer deref in quirk\n* [`6e74a3676`](https://github.com/siderolabs/talos/commit/6e74a367636dc21e2bf017d6284bbf998a4bad7d) docs: aad ery basic details on how to run on scaleway\n* [`260d1bc9a`](https://github.com/siderolabs/talos/commit/260d1bc9a93f5f6added5e6998f3d2f08fedb770) fix: correctl close encrypted volumes\n* [`034ef42af`](https://github.com/siderolabs/talos/commit/034ef42af25ee3dacf5dd0391385ea881b6d5d32) fix: update siderolink library for wgtunnel panic fix\n* [`3035744a8`](https://github.com/siderolabs/talos/commit/3035744a8096270691f6bdccfabe34ad53da489c) fix: correctly predict interface name on darwin\n* [`cfcfad3c4`](https://github.com/siderolabs/talos/commit/cfcfad3c45376b8ebb989b865f3c13729c87d388) chore: move `checkUnknownKeys` function to `github.com/siderolabs/gen`\n* [`5ecc53c69`](https://github.com/siderolabs/talos/commit/5ecc53c695ec578dbc32f00fa7df65b31a5e77aa) docs: add macos section to developing-talos.md\n* [`b5b35307f`](https://github.com/siderolabs/talos/commit/b5b35307fe950d0de9ee2ff1d5686af858db13b4) chore: update Go to 1.24.4\n* [`fde772d8d`](https://github.com/siderolabs/talos/commit/fde772d8d82e9d6bc7e63b49c965b8d924e308ab) feat: update Flannel to 0.27.0\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`17107ae`](https://github.com/siderolabs/crypto/commit/17107ae45403a2bcd4fecfb4660b60276652b00d) fix: add generic CSR generator and OpenSSL interop\n* [`53659fc`](https://github.com/siderolabs/crypto/commit/53659fc35f6abd4ada7ffa22ef1b148cf93c0f28) refactor: split into files\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>4 commits</summary>\n<p>\n\n* [`dcb2b74`](https://github.com/siderolabs/gen/commit/dcb2b7417879f230a569ce834dad5c89bd09d6bf) feat: add `panicsafe` package\n* [`b36ee43`](https://github.com/siderolabs/gen/commit/b36ee43f667a7a56b340a3e769868ff2a609bb5b) feat: make `xyaml.CheckUnknownKeys` public\n* [`3e319e7`](https://github.com/siderolabs/gen/commit/3e319e7e52c5a74d1730be8e47952b3d16d91148) feat: implement `xyaml.UnmarshalStrict`\n* [`7c0324f`](https://github.com/siderolabs/gen/commit/7c0324fee9a7cfbdd117f43702fa273689f0db97) chore: future-proof HashTrieMap\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`5b39ef8`](https://github.com/siderolabs/go-circular/commit/5b39ef87df04efeaa47fe6374a8114f39c126122) fix: do not log error if chunk zero was never written\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`657a74b`](https://github.com/siderolabs/go-kubernetes/commit/657a74b7163de7886a9581c446b1de6f21264fd2) feat: prepare for Kubernetes 1.34\n* [`9070be4`](https://github.com/siderolabs/go-kubernetes/commit/9070be4308e23d969ec4fc49b25dab4a27d512e7) fix: remove DynamicResourceAllocation feature gate\n* [`8cb588b`](https://github.com/siderolabs/go-kubernetes/commit/8cb588bc4c93d812de901a6a33e599ba2169cd96) fix: k8s 1.32->1.33 upgrade check\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>41 commits</summary>\n<p>\n\n* [`03bb94c`](https://github.com/siderolabs/pkgs/commit/03bb94c39c02b7028f5d595cb758f59b132fa1d3) feat: update dependencies\n* [`c613abd`](https://github.com/siderolabs/pkgs/commit/c613abd8c4f777ef588cce4ae5563d4024e50507) fix: iptables url\n* [`fae59df`](https://github.com/siderolabs/pkgs/commit/fae59df236da122c84990a187f4648878f2e4bf7) fix: download and copy hailo8 firmware\n* [`fadf1e2`](https://github.com/siderolabs/pkgs/commit/fadf1e22a263b3429fa8fd540b4ff5a71ce8ded2) feat: update containerd to 2.1.2\n* [`a0b0da1`](https://github.com/siderolabs/pkgs/commit/a0b0da10b5745616651d0bcd4b3aa5a06690fd5a) feat: enable io.latency cgroup controller\n* [`0aaa07a`](https://github.com/siderolabs/pkgs/commit/0aaa07a2a1af852efbc65a476cdcc17829e33a99) feat: add hailort package\n* [`8555e94`](https://github.com/siderolabs/pkgs/commit/8555e94f1ed54210ae7768e8ef977e5baec4b2cb) chore: use ftpmirror for GNU sources\n* [`9fbe2b4`](https://github.com/siderolabs/pkgs/commit/9fbe2b43874b701e04e5817f8a9d485139e96d50) feat: update Go to 1.24.4\n* [`79bfa9e`](https://github.com/siderolabs/pkgs/commit/79bfa9e06e5e69955236ffd58323c9936d638d45) feat: update NVIDIA drivers to 570.148.08\n* [`c8b8bd8`](https://github.com/siderolabs/pkgs/commit/c8b8bd8b5eb265f8e8c8955998e428b86d177ab5) feat: bump dependencies\n* [`54bf03e`](https://github.com/siderolabs/pkgs/commit/54bf03ebf24d9ef70a47d4b3b4f30d92191085da) feat: update Linux to 6.12.31\n* [`93b3aaa`](https://github.com/siderolabs/pkgs/commit/93b3aaae5369140058e6a5cbdf83d1da235eb735) feat: add patch for CephFS IMA performance regression\n* [`ebd6627`](https://github.com/siderolabs/pkgs/commit/ebd6627c68406076ed95b2cd629d2ace51bb49b6) feat: disable IMA support\n* [`8aad53b`](https://github.com/siderolabs/pkgs/commit/8aad53bab3201d7f87d39ab61953e04392402efc) feat: add CONFIG_NFT_CONNLIMIT to kernel\n* [`7a299fa`](https://github.com/siderolabs/pkgs/commit/7a299fa02106a7216926d6bcff21fb1cd2da7d73) feat: update Linux to 6.12.30\n* [`8c4603e`](https://github.com/siderolabs/pkgs/commit/8c4603e90335b9aaf180b954ebc43f65dcb2b7b6) feat: move more configs to modules on arm64\n* [`7b1183b`](https://github.com/siderolabs/pkgs/commit/7b1183bea84e46cd8f1a775f95683b8a0039c2d7) feat(kernel): enable IB user-space management and RDMA\n* [`1b1430e`](https://github.com/siderolabs/pkgs/commit/1b1430e82ef62efdd538588183ed27def2bebbaa) fix: drop pcre2 binaries\n* [`487610c`](https://github.com/siderolabs/pkgs/commit/487610c4f286210c22cd813427380af654297791) fix: drop broken symlinks\n* [`f31d518`](https://github.com/siderolabs/pkgs/commit/f31d518eefec0cb672760d00a5c2de37b45dfb45) fix: clean up some binaries\n* [`0f74b9b`](https://github.com/siderolabs/pkgs/commit/0f74b9bd1d097a283f3edd6165161e4e0688a79f) feat: update containerd to v2.1.1\n* [`89b4037`](https://github.com/siderolabs/pkgs/commit/89b40372b8964a9dc9ad3db17a46a9d9c797f60f) fix: tenstorrent pkg name\n* [`a14b544`](https://github.com/siderolabs/pkgs/commit/a14b54409704c1f3beb0f51089dadd3f3e8dc441) chore: drop qemu-tools vmdk support\n* [`2563e47`](https://github.com/siderolabs/pkgs/commit/2563e47ca1bfc755ee4ecf2b470cfed081b54e6f) feat: add tenstorrent package\n* [`2a1c42f`](https://github.com/siderolabs/pkgs/commit/2a1c42fde5fe4009c33d50d571d7d3cfe3a09888) fix(renovate): flannel config\n* [`bfa69a8`](https://github.com/siderolabs/pkgs/commit/bfa69a820e8190aed3a45c00dff5f4f1cc42b7a6) feat: add open-vmdk package\n* [`9f1ba1f`](https://github.com/siderolabs/pkgs/commit/9f1ba1f047c835abdf882540d316055a3e2d1bfc) fix: bring back updated containerd gvisor patch\n* [`1567cb6`](https://github.com/siderolabs/pkgs/commit/1567cb616691dc22fbc3374cdeac11cdbe51bb94) feat: update Linux 6.12.28, firmware\n* [`9bc66e6`](https://github.com/siderolabs/pkgs/commit/9bc66e6bd355f8a86c4becbd78aede1323e3681e) feat: update containerd to 2.1.0\n* [`c6b54e0`](https://github.com/siderolabs/pkgs/commit/c6b54e04fb5d943ff31f05b1e095af65eb901604) feat: enable zswap\n* [`4cd7084`](https://github.com/siderolabs/pkgs/commit/4cd7084634c2b79541da8c6f95c047d4eb0e66a2) feat: update dependencies\n* [`a3fcbf8`](https://github.com/siderolabs/pkgs/commit/a3fcbf812632aaa8e8f9027a88181c284e7d919d) feat(kernel): enable panthor driver\n* [`74d1665`](https://github.com/siderolabs/pkgs/commit/74d16657fd53c30249c3eba75769f90dd84366ce) feat: update ZFS to 2.3.2\n* [`ddc866b`](https://github.com/siderolabs/pkgs/commit/ddc866bc9dd0557c2e9d5d0b234348767769cfd3) feat: update Linux to 6.12.27\n* [`a347857`](https://github.com/siderolabs/pkgs/commit/a347857b33a6a41fe2661a7451c3af65a51404c9) fix: build containerd with Go 1.23\n* [`74da85c`](https://github.com/siderolabs/pkgs/commit/74da85c2cf61b8006af38b3d0d38dc13098d5227) fix: containerd build doesn't need seccomp\n* [`4effa05`](https://github.com/siderolabs/pkgs/commit/4effa0525dc87974052e9dec2685a0ad411773dd) fix: downgrade libseccomp to 2.5.5\n* [`9cea00b`](https://github.com/siderolabs/pkgs/commit/9cea00b4601d7bedf49606b647003f3c6cb0787b) feat: update Linux to 6.12.25\n* [`cb108a5`](https://github.com/siderolabs/pkgs/commit/cb108a514b55a302008fb4c1ce6d88ce0d769b58) feat(kernel): enable bcache module\n* [`d042432`](https://github.com/siderolabs/pkgs/commit/d04243270a4f10f9ecb889883ab42687e5ae6351) fix: backport sandbox fix for Gvisor\n* [`fa625dc`](https://github.com/siderolabs/pkgs/commit/fa625dc6dd97a61cb8479b8b0ab82126650de11b) feat: update Linux 6.12.24, containerd 2.0.5\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>3 commits</summary>\n<p>\n\n* [`5f46f65`](https://github.com/siderolabs/siderolink/commit/5f46f6583b9d03f91c9bb5f637149fe466d17bfc) feat: handle panics in goroutines\n* [`d09ff45`](https://github.com/siderolabs/siderolink/commit/d09ff45b450a37aa84652fa70b5cd3467ee8243d) fix: race in wait value\n* [`d2a79e0`](https://github.com/siderolabs/siderolink/commit/d2a79e0263806b68ff0a44ea9efa58b83fb269ec) fix: clean up device on failure\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`1dfd14b`](https://github.com/siderolabs/tools/commit/1dfd14bd4f2573d1070008c8f9d6a05ca064081e) feat: update Go to 1.24.4\n* [`af3fd64`](https://github.com/siderolabs/tools/commit/af3fd645d48a373396f8346af411c1c827c87376) feat: update dependencies\n* [`e35234b`](https://github.com/siderolabs/tools/commit/e35234bd94c3c16daf06d00848d7752f5e4c7d15) feat: update dependencies\n* [`c96a4e6`](https://github.com/siderolabs/tools/commit/c96a4e671e378f80f161e45942f80b10adfd562d) chore: update toolchain to the latest version\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.6.0 -> v0.7.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.9.0 -> v1.10.1\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.3.1 -> v1.4.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.3.1 -> v1.4.0\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.29.14 -> v1.29.17\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.30 -> v1.16.32\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.38.3 -> v1.41.2\n* **github.com/aws/smithy-go**                                                v1.22.3 -> v1.22.4\n* **github.com/containerd/containerd/api**                                    v1.8.0 -> v1.9.0\n* **github.com/containerd/containerd/v2**                                     v2.0.5 -> v2.1.3\n* **github.com/containernetworking/plugins**                                  v1.6.2 -> v1.7.1\n* **github.com/cosi-project/runtime**                                         v0.10.2 -> v0.10.6\n* **github.com/detailyang/go-fallocate**                                      432fa640bd2e **_new_**\n* **github.com/docker/cli**                                                   v28.0.4 -> v28.3.0\n* **github.com/docker/docker**                                                v28.0.4 -> v28.3.0\n* **github.com/equinix-ms/go-vmw-guestrpc**                                   v0.1.1 **_new_**\n* **github.com/foxboron/go-uefi**                                             69fb7dba244f -> a3183a1bfc84\n* **github.com/google/cadvisor**                                              v0.52.1 -> v0.53.0\n* **github.com/google/cel-go**                                                v0.24.1 -> v0.25.0\n* **github.com/google/go-containerregistry**                                  v0.20.3 -> v0.20.6\n* **github.com/google/go-tpm**                                                v0.9.3 -> v0.9.5\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**                         v2.3.1 -> v2.3.2\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.21.0 -> v2.21.1\n* **github.com/jsimonetti/rtnetlink/v2**                                      v2.0.3 -> v2.0.5\n* **github.com/klauspost/cpuid/v2**                                           v2.2.10 -> v2.2.11\n* **github.com/linode/go-metadata**                                           v0.2.1 -> v0.2.2\n* **github.com/miekg/dns**                                                    v1.1.65 -> v1.1.66\n* **github.com/pkg/xattr**                                                    v0.4.10 -> v0.4.11\n* **github.com/prometheus/procfs**                                            v0.16.0 -> v0.16.1\n* **github.com/rivo/tview**                                                   949945f8d922 -> a4a78f1e05cb\n* **github.com/safchain/ethtool**                                             v0.5.10 -> v0.6.1\n* **github.com/siderolabs/crypto**                                            v0.5.1 -> v0.6.0\n* **github.com/siderolabs/gen**                                               v0.8.0 -> v0.8.4\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.16 -> v2.0.18\n* **github.com/siderolabs/go-circular**                                       v0.2.2 -> v0.2.3\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.21 -> v0.2.24\n* **github.com/siderolabs/pkgs**                                              v1.10.0-5-g48dba3e -> v1.11.0-alpha.0-40-g03bb94c\n* **github.com/siderolabs/siderolink**                                        v0.3.13 -> v0.3.15\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.10.0 -> v1.11.0-alpha.1\n* **github.com/siderolabs/tools**                                             v1.10.0 -> v1.11.0-alpha.0-3-g1dfd14b\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/client/v3**                                               v3.5.21 -> v3.6.1\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.21 -> v3.6.1\n* **golang.org/x/net**                                                        v0.39.0 -> v0.41.0\n* **golang.org/x/oauth2**                                                     v0.29.0 -> v0.30.0\n* **golang.org/x/sync**                                                       v0.13.0 -> v0.15.0\n* **golang.org/x/sys**                                                        v0.32.0 -> v0.33.0\n* **golang.org/x/term**                                                       v0.31.0 -> v0.32.0\n* **golang.org/x/text**                                                       v0.24.0 -> v0.26.0\n* **golang.org/x/time**                                                       v0.11.0 -> v0.12.0\n* **google.golang.org/grpc**                                                  v1.71.1 -> v1.73.0\n* **k8s.io/api**                                                              v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/apimachinery**                                                     v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/apiserver**                                                        v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/client-go**                                                        v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/component-base**                                                   v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/cri-api**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kube-scheduler**                                                   v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kubectl**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/kubelet**                                                          v0.33.0 -> v0.34.0-alpha.2\n* **k8s.io/pod-security-admission**                                           v0.33.0 -> v0.34.0-alpha.2\n* **sigs.k8s.io/hydrophone**                                                  b92baf7e0b04 -> v0.7.0\n* **sigs.k8s.io/yaml**                                                        v1.4.0 -> v1.5.0\n\nPrevious release can be found at [v1.10.0](https://github.com/siderolabs/talos/releases/tag/v1.10.0)\n\n## [Talos 1.11.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.11.0-alpha.1) (2025-06-05)\n\nWelcome to the v1.11.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### IMA support removed\n\nTalos now drops the IMA (Integrity Measurement Architecture) support. This feature was not used in Talos for any meaningful security purpose\nand has historically caused performance issues. See #11133 for more details.\n\n\n### Qemu provisioner on MacOS\n\nOn MacOS `talosctl cluster create` command now supports the Qemu provisioner in addition to the Docker provisioner.\n\n\n### Component Updates\n\nLinux: 6.12.31\nKubernetes: 1.33.1\nrunc: 1.3.0\ncontainerd: 2.1.1\nFlannel CNI plugin: 1.7.1-flannel1\n\nTalos is built with Go 1.24.3.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Orzelius\n* Orzelius\n* Spencer Smith\n* Till Hoffmann\n* Justin Garrison\n* Steve Francis\n* Andrew Longwill\n* Dmitrii Sharshakov\n* Marat Bakeev\n* Olav Thoresen\n* Utku Ozdemir\n* Alvaro \"Chamo\" Linares Cabre\n* Brian Brookman\n* Bryan Mora\n* Clément Nussbaumer\n* Dennis Marttinen\n* Dmitriy Matrenichev\n* Joakim Nohlgård\n* Justin Seely\n* Luke Cousins\n* Marco Mihai Condrache\n* Markus Reiter\n* Michael Moerz\n* Mike\n* Tan Siewert\n* Thibault VINCENT\n* Tom Keur\n* killcity\n* yashutanu\n\n### Changes\n<details><summary>134 commits</summary>\n<p>\n\n* [`58a868e68`](https://github.com/siderolabs/talos/commit/58a868e68833e94d691e7ed029dce629446fecc3) chore: fix renovate config, add release-gate label\n* [`a59aaee84`](https://github.com/siderolabs/talos/commit/a59aaee84bcceb20792bc4782748449ad93b0530) feat: bump dependencies, Linux 6.12.31\n* [`e954ee30a`](https://github.com/siderolabs/talos/commit/e954ee30add42de6f42cbb7d96927722102afdb7) docs: typo correction: LongHorn -> Longhorn\n* [`aab053394`](https://github.com/siderolabs/talos/commit/aab053394bafdf718196133e38be010d847db0ad) fix: mashal resource byte slices as strings in YAML\n* [`c7d4191e7`](https://github.com/siderolabs/talos/commit/c7d4191e78bf0a455ab596f46d4cf212dce694a4) fix: rework the way CRI config generation is waited for\n* [`0114183de`](https://github.com/siderolabs/talos/commit/0114183de62e4ab930ff0f10dd156f935d57cf10) docs: update `lastRelease` to 1.10.3\n* [`938b0760a`](https://github.com/siderolabs/talos/commit/938b0760abdb41be1be4da02b877e2c902d594be) docs: update issue template\n* [`2a7b735b2`](https://github.com/siderolabs/talos/commit/2a7b735b264ebcfa22dc2d6044c9d5cd3057b5c2) feat: drop IMA support\n* [`2d5a805b0`](https://github.com/siderolabs/talos/commit/2d5a805b0ebabb804b3c32be18db1d718a91070f) fix: typo in DiscoverdVolume spec\n* [`60c12bad9`](https://github.com/siderolabs/talos/commit/60c12bad93b422db2784b0203d94ca69fa31957c) feat: support nocloud include url userdata directive\n* [`0fd622c82`](https://github.com/siderolabs/talos/commit/0fd622c825ba1fbb833a4b8920ac4c4e56f08a1f) fix(talosctl): correct --help output for dashboard command\n* [`a90c936a1`](https://github.com/siderolabs/talos/commit/a90c936a16756cfe5fe451258f0022b808be17d2) feat: support qemu provisioner on darwin\n* [`5322ca0d3`](https://github.com/siderolabs/talos/commit/5322ca0d372aa20ad90e66f04699b75debb0ab80) docs: update overlay docs\n* [`a60b6322d`](https://github.com/siderolabs/talos/commit/a60b6322d1e8fbd75394e0bdb4435af605b32bbb) fix(ci): drop nebula from extensions test\n* [`dbbb59a67`](https://github.com/siderolabs/talos/commit/dbbb59a6781f79ee34a6e91a72575802561c58b6) docs: add note for default `dataDirHostPath` for Rook\n* [`e26054378`](https://github.com/siderolabs/talos/commit/e2605437826911cd60a6a4d9ee760a6a242e244b) docs: macos qemu provider\n* [`5d0224093`](https://github.com/siderolabs/talos/commit/5d022409357d41831fa1bfd34ccdcfceecca42df) docs: use the cilium-cli image repo in the job installation manifest\n* [`ff80e4cca`](https://github.com/siderolabs/talos/commit/ff80e4cca086fa01d84ceb750111dc9e31ccc978) docs: fix CIDR name\n* [`a5fd15e8b`](https://github.com/siderolabs/talos/commit/a5fd15e8bd4a4547e3658981543401fd9eb8cd80) fix(ci): reproducibility test\n* [`8f8963e50`](https://github.com/siderolabs/talos/commit/8f8963e50d7b05d1361fd44040c0f1ffb94693af) docs: update Nexxen brand\n* [`c6b86872d`](https://github.com/siderolabs/talos/commit/c6b86872dc0d62aef5ad70fce00c411080911ace) fix(ci): iso reproducibility file permissions\n* [`995a1dec4`](https://github.com/siderolabs/talos/commit/995a1dec4a34f49d84daff16b30f8920275a439d) chore: add a check for unsupported darwin flags\n* [`9db5d0c97`](https://github.com/siderolabs/talos/commit/9db5d0c97ac31c7f6ce0b23d999126fc6cc094ec) fix: nocloud metadata for hostname\n* [`3cf325654`](https://github.com/siderolabs/talos/commit/3cf325654e4a7f73196241e59e3ca6b5f24c3e19) feat: modularize more arm64 kernel\n* [`3524745cc`](https://github.com/siderolabs/talos/commit/3524745cc49c51e4f13da954a57ab56d467fd26e) fix: allow any PKI in Talos API\n* [`f438cdb09`](https://github.com/siderolabs/talos/commit/f438cdb0993b17f0e540ecefa39cde09f89730f4) chore: use custom dhcpd server on macos qemu\n* [`11c17fb9a`](https://github.com/siderolabs/talos/commit/11c17fb9aad2443b10e15295069b8e24e0d514e2) fix: metal-iso reproducibility\n* [`7fcb89ee3`](https://github.com/siderolabs/talos/commit/7fcb89ee385fdbf47dae4a8308299c00488df84a) chore: add darwin vmnet qemu support\n* [`fc1237343`](https://github.com/siderolabs/talos/commit/fc1237343f79a1be907c43ac3ce116168409ed17) chore: clean up `/usr/bin`\n* [`b551f32ce`](https://github.com/siderolabs/talos/commit/b551f32ce550f2bc3c679a9857f28d604a297bbf) feat: update containerd to v2.1.1\n* [`67f4154f9`](https://github.com/siderolabs/talos/commit/67f4154f920fc0c58a9a832e14fbc7f9430747b3) docs: update disk-management.md\n* [`0cb137ad7`](https://github.com/siderolabs/talos/commit/0cb137ad7366e2386f49a99aee0a3c5ffb7223f6) fix: make disk size check work on old Talos\n* [`7c057edd5`](https://github.com/siderolabs/talos/commit/7c057edd5f3636dff6932ad9fbd7c51867b0c2c8) fix: use vmdk-convert istead of qemu-img to create VMDK for OVA files\n* [`cd618dad0`](https://github.com/siderolabs/talos/commit/cd618dad0feb1390e5945e2bba1d20bcecf30c2a) chore: update the go-blockdevice package\n* [`0b99631a0`](https://github.com/siderolabs/talos/commit/0b99631a0b64ce8d65ddcf7f40b2168debf11a62) fix: bump apid memory limit\n* [`5451f35b1`](https://github.com/siderolabs/talos/commit/5451f35b148a630c6ab011dce44b52fd2ad327ba) docs: update virtualbox\n* [`bd4d202a5`](https://github.com/siderolabs/talos/commit/bd4d202a5a67c56b6c6e6bc962f6bd51c729759f) refactor: bring owned.State from COSI to simplify tests\n* [`0b96df574`](https://github.com/siderolabs/talos/commit/0b96df57476af86a37bcfdbf28a479444a9e6e5c) feat: update containerd to 2.1.0\n* [`e1a939144`](https://github.com/siderolabs/talos/commit/e1a939144f25acc6a2715feedb30a56a47f6793d) docs: fix formatting in disk encryption\n* [`7a817df1c`](https://github.com/siderolabs/talos/commit/7a817df1cce58de2a16b72b37a54ffc0103af79a) docs: fix typo\n* [`f35b213b2`](https://github.com/siderolabs/talos/commit/f35b213b2b448c2e0065d4698095a843dd2f5268) test: fix DHCP unicast failures in QEMU environment\n* [`7064bbf05`](https://github.com/siderolabs/talos/commit/7064bbf056f083de0f7174c9d3c600871189b4e5) docs: fix vmware factory URL\n* [`78c33bcdb`](https://github.com/siderolabs/talos/commit/78c33bcdb9a30195ce401311e82b2e189faf33f3) feat: update default Kubernetes to v1.33.1\n* [`da6795266`](https://github.com/siderolabs/talos/commit/da67952666d2db2b8b5636bd4cae8af09a139410) fix: disable automatic MAC assignment to bridge interfaces\n* [`ca34adf58`](https://github.com/siderolabs/talos/commit/ca34adf585bfe04d2d1b84f186cb87aa77fc8e00) chore(ci): drop azure keys\n* [`ea5de19fa`](https://github.com/siderolabs/talos/commit/ea5de19fad3f62889899c0d89d08b8b73dfa75da) fix: selinux detection\n* [`52c76ea3a`](https://github.com/siderolabs/talos/commit/52c76ea3a61a4a3cbd963dc2ff0d6d21b4210bcd) fix: consistently apply dynamic grpc proxy dialer\n* [`aa9569e5d`](https://github.com/siderolabs/talos/commit/aa9569e5d8c59b762dfd64a4e9ef42cfdc6f9d51) chore: refactor cluster create cmd flags\n* [`1161faa05`](https://github.com/siderolabs/talos/commit/1161faa0594c033bf032852b880439b2082c9722) docs: fix typo in Cilium docs\n* [`164745e44`](https://github.com/siderolabs/talos/commit/164745e44334146b8a6f696640692c25b731414a) docs: remove `preserve` flag mention in upgrade notes\n* [`9a2ecbaaf`](https://github.com/siderolabs/talos/commit/9a2ecbaaf7b7a3f393dd29272aca34e069a24c6e) fix: makefile operating system param\n* [`118aa69d6`](https://github.com/siderolabs/talos/commit/118aa69d6f6e71b88747db1e8234d478daa54ab4) chore: update cloud-image-uploader dependencies\n* [`acdd721cf`](https://github.com/siderolabs/talos/commit/acdd721cfa62f9888a9ceea1693c17348c0d663a) chore: dump qemu pachine ipam records on darwin\n* [`bb9094534`](https://github.com/siderolabs/talos/commit/bb90945344f02b9cdae6e0e01821792dca25096b) chore: rotate aws iam credentials\n* [`0bfa4ae1b`](https://github.com/siderolabs/talos/commit/0bfa4ae1b06e1e6330adf331e1a97651bbe39b4a) chore: update deps for cloud-image-uploader\n* [`956d7c71b`](https://github.com/siderolabs/talos/commit/956d7c71bcdff639b8261cf6cf1a5d19cf702f75) chore: update sops keys\n* [`e2f819d88`](https://github.com/siderolabs/talos/commit/e2f819d880373102f8a8c7f0ff549e37ba75a08e) test: fix the process runner log collection\n* [`fdac4cfb9`](https://github.com/siderolabs/talos/commit/fdac4cfb9143853eb21d38e1b3d517455b0ba0f2) fix: upgrade go-kubernetes for DRA flag bug\n* [`09d88e1e8`](https://github.com/siderolabs/talos/commit/09d88e1e8374ef19e5730994d9b098333347f0b7) test: fix some flaky tests\n* [`ec1f41a94`](https://github.com/siderolabs/talos/commit/ec1f41a948b1bda02096434e47f2a2a767951fe9) chore: make qemu config server bind work on darwin\n* [`980f4d2b9`](https://github.com/siderolabs/talos/commit/980f4d2b936cfdc3ebc9882f7c25fbf2d2aa49f8) feat: bump dependencies\n* [`95259337e`](https://github.com/siderolabs/talos/commit/95259337ee0ccb22d7e9125074818ac8f9afa7af) fix: k8s 1.32->1.33 upgrade check\n* [`c3c326b40`](https://github.com/siderolabs/talos/commit/c3c326b405804c258b68f19b8d7dacca32535e9b) fix: improve volume mounter automaton\n* [`918b94d9a`](https://github.com/siderolabs/talos/commit/918b94d9a0b71b759073f8f7eb0f5dc7fdff413f) refactor: rewrite disk size check\n* [`ab7e693d7`](https://github.com/siderolabs/talos/commit/ab7e693d76500b6cdc2068221bdfce16633a8b01) chore: make qemu lb address bind work on darwin\n* [`97ceab001`](https://github.com/siderolabs/talos/commit/97ceab001c1bb79407c40d8fff867342656187b9) fix: multiple logic issues in platform network config controller\n* [`46349a9df`](https://github.com/siderolabs/talos/commit/46349a9df5d026a4e4b807a94865d5b3c371d32a) docs: remove azure image gallery instructions\n* [`0cfcdd3de`](https://github.com/siderolabs/talos/commit/0cfcdd3de1a20690ce47d63bb56b3d33d11c1474) docs: fix search on base talos.dev\n* [`78646b4e0`](https://github.com/siderolabs/talos/commit/78646b4e050358b930d27e4eddcfb22c4c825b0c) docs: add registryd debug command\n* [`c6824c211`](https://github.com/siderolabs/talos/commit/c6824c211438a3fb663f4233e8663732ab2ddf44) fix: deny apply config requests without v1alpha1 in \"normal\" mode\n* [`7df0408e4`](https://github.com/siderolabs/talos/commit/7df0408e460ebc392c6927c7b23e3795b9bd2140) fix: interactive installer config gen\n* [`881c5d62b`](https://github.com/siderolabs/talos/commit/881c5d62bf0d1f3311b3cf946b7801f97c1fb94b) fix: suppress duplicate platform config updates\n* [`66d77888e`](https://github.com/siderolabs/talos/commit/66d77888e42798995ddc73db3869d16959e53376) fix: replace downloaded asset paths correctly in cluster create cmd\n* [`6bd6c9b5a`](https://github.com/siderolabs/talos/commit/6bd6c9b5a08ca3b0e9574e1a61edc54c6ff722bb) fix: generate iso greater than 4 gig\n* [`ac140324e`](https://github.com/siderolabs/talos/commit/ac140324ebfb54f580c9b9bbbb55549bd5ffa11e) fix: skip PCR extension if TPM1.2 is found\n* [`09ef1f8a4`](https://github.com/siderolabs/talos/commit/09ef1f8a41c84e6a16729e6b6aff81788da0e3f5) fix: ignore http proxy on grpc socket dial\n* [`22a72dc80`](https://github.com/siderolabs/talos/commit/22a72dc80f2037a4cc7ad696d8dff504deb22630) chore: split options between three structs\n* [`22c34a50f`](https://github.com/siderolabs/talos/commit/22c34a50fc66edd174ab4a65961257de28a6daa0) fix(ci): provision cron jobs\n* [`b3b20eff3`](https://github.com/siderolabs/talos/commit/b3b20eff3a29f74d18df634cbb01f41bde17f2c8) fix: containerd crashing with sigsegv\n* [`f7891c301`](https://github.com/siderolabs/talos/commit/f7891c3018de248c7c66483562227b614689413c) chore: calculate vmnet interface name preemptively\n* [`ae87edffb`](https://github.com/siderolabs/talos/commit/ae87edffbcdaed12fef41541622f27882ed63755) fix: drop libseccomp from rootfs\n* [`f74a805bb`](https://github.com/siderolabs/talos/commit/f74a805bb067f55619cae7aebb92f00bb8173c92) fix: do correct backoff for nocloud reconcile\n* [`01bb294af`](https://github.com/siderolabs/talos/commit/01bb294af63f193dafa12cb623ea77ad67b698fb) fix(ci): provision tests\n* [`e4945be3b`](https://github.com/siderolabs/talos/commit/e4945be3bc43cbc275e2ea5f399a0188c5e16ad8) docs: add registryd debug command\n* [`d8c670ad3`](https://github.com/siderolabs/talos/commit/d8c670ad3ecba32c70ff365eaf7a5a4ccb5d721a) release(v1.11.0-alpha.0): prepare release\n* [`ace44ea61`](https://github.com/siderolabs/talos/commit/ace44ea6169d419f188e0a2456c31f420e61ae77) test: update hydrophone to 0.7.0\n* [`3a1163692`](https://github.com/siderolabs/talos/commit/3a1163692da7b41b17f263ab43d0fd81abafc4f8) chore: cross platform qemu preflight checks\n* [`7914fb104`](https://github.com/siderolabs/talos/commit/7914fb10412d31a1b75c74b0c66578e55fb77bc7) chore: move the create command to it's own package\n* [`c8e619608`](https://github.com/siderolabs/talos/commit/c8e619608dc8898be71a17c54503085ef38abf37) chore: prepare for release 1.11\n* [`1299aaa45`](https://github.com/siderolabs/talos/commit/1299aaa45d997dd23aed380f858cec3bc6b975e4) chore(ci): add extensions test for Youki runtime\n* [`e50ceb221`](https://github.com/siderolabs/talos/commit/e50ceb221e56f0760d5f2fc9e4b821d6b29add05) docs: activate Talos 1.10 docs\n* [`9d12aaeb1`](https://github.com/siderolabs/talos/commit/9d12aaeb19d68c5e692921b938d72347f6129f65) test: improve config patch test\n* [`106a656b6`](https://github.com/siderolabs/talos/commit/106a656b6132e766e9e9ef7b1c12b97a413b5de6) chore: make qemu provider build on darwin\n* [`8013aa06c`](https://github.com/siderolabs/talos/commit/8013aa06cd338f1dd11061d3455767fee4b9783c) test: replace platform metadata test\n* [`2b89c2810`](https://github.com/siderolabs/talos/commit/2b89c2810551ab52678e62fcbf5355dd05c72030) fix: relax etcd APIs RBAC requirements\n* [`1e677587c`](https://github.com/siderolabs/talos/commit/1e677587c0e6c61f724a85f18ee9d436ae6da038) fix: preserve kubelet image suffix\n* [`62ab8af45`](https://github.com/siderolabs/talos/commit/62ab8af459475cbd24a2f34d8923ce70d1fda3db) fix: disk image generation with image cache\n* [`d60626f01`](https://github.com/siderolabs/talos/commit/d60626f017ef495210939ee4f8ef7f623dd325f9) fix: handle encryption type mismatch\n* [`a9109ebd0`](https://github.com/siderolabs/talos/commit/a9109ebd00fcd300bf4262142ade77df6788852b) feat: allow SideroLink unique token in machine config\n* [`2ff3a6e40`](https://github.com/siderolabs/talos/commit/2ff3a6e4079a29b6b45770204fd8cb30369518e9) feat(kernel): add bcache kernel module to core talos\n* [`fa95a2146`](https://github.com/siderolabs/talos/commit/fa95a2146056bfe1ae322cb574fd8d432745b5c9) fix(ci): bios provision test\n* [`f7c5b86be`](https://github.com/siderolabs/talos/commit/f7c5b86be7e2b28906cb66b466a017887ac5e2b6) fix: sync PCR extension with volume provisioning lifecycle\n* [`f90c79474`](https://github.com/siderolabs/talos/commit/f90c79474b50da35ab8e285ee9723957e4b6cf00) chore: show bound driver in pcidevices info\n* [`8db34624c`](https://github.com/siderolabs/talos/commit/8db34624c6ed9707ba1165da790f5b389bd1c92f) fix: handle correctly changing platform network config\n* [`77c7a075b`](https://github.com/siderolabs/talos/commit/77c7a075bbba7ffd24dbd9d5e069ccb50f8143b4) feat: update Kubernetes to 1.33.0\n* [`74f0c48c7`](https://github.com/siderolabs/talos/commit/74f0c48c738b0b80278667c3e5a1c5e1ecd5a078) feat: add version compatibility for Talos 1.11\n* [`c4fb7dad0`](https://github.com/siderolabs/talos/commit/c4fb7dad0ec390781cca54e2348f116cb1cf1866) fix: force DNS runner shutdown on timeout\n* [`c49b4836e`](https://github.com/siderolabs/talos/commit/c49b4836e46725940f4731e182475905ebee6019) docs: hetzner: add note about public iso\n* [`16ea2b113`](https://github.com/siderolabs/talos/commit/16ea2b113fad0c81a96dbcfdf4fd1b9f43bb1282) docs: add what is new for 1.10\n* [`be3f0c018`](https://github.com/siderolabs/talos/commit/be3f0c018c50da3d920ed8fe36d4f31c5d3edfac) fix: fix Gvisor tests with containerd patch\n* [`37db132b3`](https://github.com/siderolabs/talos/commit/37db132b3b3e6c58f15228c64b023e77c15cf012) chore(ci): add provision test with bios\n* [`ec60b70e7`](https://github.com/siderolabs/talos/commit/ec60b70e7245f49f6ac1d48cd4292b85f1d6f79e) fix: set media type to OCI for image cache layer\n* [`a471eb31b`](https://github.com/siderolabs/talos/commit/a471eb31b87b393ee9fc57fbc725801d08386ad4) feat: update Linux 6.12.24, containerd 2.0.5\n* [`54ad5b872`](https://github.com/siderolabs/talos/commit/54ad5b8729c7d54da2efa6baf7886163741176ed) fix: extension services logging to console\n* [`601f036ba`](https://github.com/siderolabs/talos/commit/601f036ba9cc762d6a3c6ae819654005f1d49527) docs: correct flannel extra args example\n* [`ae94377d1`](https://github.com/siderolabs/talos/commit/ae94377d15a3b70248fbb446d13d7ae96bb04e82) feat: support encryption config for user volumes\n* [`9616f6e8d`](https://github.com/siderolabs/talos/commit/9616f6e8d280e64815fe3e1ba324df1dd5d2122d) docs: add caveat for kubespan and host ports\n* [`a1d08a362`](https://github.com/siderolabs/talos/commit/a1d08a3624c7c8b5213b8e9dee1cf9289d6719dc) docs: fixes typo at OpenEBS Mayastor worker patches\n* [`a91e8726e`](https://github.com/siderolabs/talos/commit/a91e8726e433be9db58f1a7a09a4cca422b2b50c) docs: add a dark theme\n* [`c76189c58`](https://github.com/siderolabs/talos/commit/c76189c58a2fe65954924168d7077350974829dd) fix: grub EFI mount point\n* [`4ca985c65`](https://github.com/siderolabs/talos/commit/4ca985c656c1924e550d06c073a7c1b6cb03f392) fix: grub efi platform install\n* [`b31260281`](https://github.com/siderolabs/talos/commit/b31260281dba752e06fcfc645bb020872602d898) docs: update storage.md\n* [`396a29040`](https://github.com/siderolabs/talos/commit/396a290408eff5bda4ad31fafc33496bea9aa899) feat: add new SBCs\n* [`a902f6580`](https://github.com/siderolabs/talos/commit/a902f6580f8e104977521a335a41c0cd70256906) feat: update Flannel to v0.26.7\n* [`2bbefec1a`](https://github.com/siderolabs/talos/commit/2bbefec1abacae2952782fbd163ef52d34f09858) docs: use cache in preview\n* [`6028a8d2d`](https://github.com/siderolabs/talos/commit/6028a8d2da571a8a37712f9917e24372cf5af919) docs: update kubeprism.md\n* [`e51a8ef8c`](https://github.com/siderolabs/talos/commit/e51a8ef8c68bb1cfab2ac845a0b6792d7e000324) fix: prefer new `MountStatus` resource\n* [`d9c7e7946`](https://github.com/siderolabs/talos/commit/d9c7e79462496d6756c55b0672994aa262eaed4f) docs: fix search\n* [`b32fa029b`](https://github.com/siderolabs/talos/commit/b32fa029b3f550b3403e25e23aac889d61366389) feat: update Kubernetes to 1.33.0-rc.1\n* [`f0ea478cb`](https://github.com/siderolabs/talos/commit/f0ea478cb811675a450839b8dcd351e43404efd4) feat: support address priority\n* [`8cd3c8dc7`](https://github.com/siderolabs/talos/commit/8cd3c8dc77b25270ed8dea65cbbd4e87c203ee74) test: fix NVIDIA OSS tests\n* [`62f2d27cd`](https://github.com/siderolabs/talos/commit/62f2d27cd44de5112055b5b47f23b001cadccaae) docs: update virtualbox.md\n* [`141326ea3`](https://github.com/siderolabs/talos/commit/141326ea3bb2e471a5cb51fd565521683a9792fc) docs: fix tabpane styling\n* [`134aa53cc`](https://github.com/siderolabs/talos/commit/134aa53ccaba55754544977d695ad3ca5d34e604) feat: update base CoreDNS code in host DNS to 1.12.1\n</p>\n</details>\n\n### Changes since v1.11.0-alpha.0\n<details><summary>84 commits</summary>\n<p>\n\n* [`58a868e68`](https://github.com/siderolabs/talos/commit/58a868e68833e94d691e7ed029dce629446fecc3) chore: fix renovate config, add release-gate label\n* [`a59aaee84`](https://github.com/siderolabs/talos/commit/a59aaee84bcceb20792bc4782748449ad93b0530) feat: bump dependencies, Linux 6.12.31\n* [`e954ee30a`](https://github.com/siderolabs/talos/commit/e954ee30add42de6f42cbb7d96927722102afdb7) docs: typo correction: LongHorn -> Longhorn\n* [`aab053394`](https://github.com/siderolabs/talos/commit/aab053394bafdf718196133e38be010d847db0ad) fix: mashal resource byte slices as strings in YAML\n* [`c7d4191e7`](https://github.com/siderolabs/talos/commit/c7d4191e78bf0a455ab596f46d4cf212dce694a4) fix: rework the way CRI config generation is waited for\n* [`0114183de`](https://github.com/siderolabs/talos/commit/0114183de62e4ab930ff0f10dd156f935d57cf10) docs: update `lastRelease` to 1.10.3\n* [`938b0760a`](https://github.com/siderolabs/talos/commit/938b0760abdb41be1be4da02b877e2c902d594be) docs: update issue template\n* [`2a7b735b2`](https://github.com/siderolabs/talos/commit/2a7b735b264ebcfa22dc2d6044c9d5cd3057b5c2) feat: drop IMA support\n* [`2d5a805b0`](https://github.com/siderolabs/talos/commit/2d5a805b0ebabb804b3c32be18db1d718a91070f) fix: typo in DiscoverdVolume spec\n* [`60c12bad9`](https://github.com/siderolabs/talos/commit/60c12bad93b422db2784b0203d94ca69fa31957c) feat: support nocloud include url userdata directive\n* [`0fd622c82`](https://github.com/siderolabs/talos/commit/0fd622c825ba1fbb833a4b8920ac4c4e56f08a1f) fix(talosctl): correct --help output for dashboard command\n* [`a90c936a1`](https://github.com/siderolabs/talos/commit/a90c936a16756cfe5fe451258f0022b808be17d2) feat: support qemu provisioner on darwin\n* [`5322ca0d3`](https://github.com/siderolabs/talos/commit/5322ca0d372aa20ad90e66f04699b75debb0ab80) docs: update overlay docs\n* [`a60b6322d`](https://github.com/siderolabs/talos/commit/a60b6322d1e8fbd75394e0bdb4435af605b32bbb) fix(ci): drop nebula from extensions test\n* [`dbbb59a67`](https://github.com/siderolabs/talos/commit/dbbb59a6781f79ee34a6e91a72575802561c58b6) docs: add note for default `dataDirHostPath` for Rook\n* [`e26054378`](https://github.com/siderolabs/talos/commit/e2605437826911cd60a6a4d9ee760a6a242e244b) docs: macos qemu provider\n* [`5d0224093`](https://github.com/siderolabs/talos/commit/5d022409357d41831fa1bfd34ccdcfceecca42df) docs: use the cilium-cli image repo in the job installation manifest\n* [`ff80e4cca`](https://github.com/siderolabs/talos/commit/ff80e4cca086fa01d84ceb750111dc9e31ccc978) docs: fix CIDR name\n* [`a5fd15e8b`](https://github.com/siderolabs/talos/commit/a5fd15e8bd4a4547e3658981543401fd9eb8cd80) fix(ci): reproducibility test\n* [`8f8963e50`](https://github.com/siderolabs/talos/commit/8f8963e50d7b05d1361fd44040c0f1ffb94693af) docs: update Nexxen brand\n* [`c6b86872d`](https://github.com/siderolabs/talos/commit/c6b86872dc0d62aef5ad70fce00c411080911ace) fix(ci): iso reproducibility file permissions\n* [`995a1dec4`](https://github.com/siderolabs/talos/commit/995a1dec4a34f49d84daff16b30f8920275a439d) chore: add a check for unsupported darwin flags\n* [`9db5d0c97`](https://github.com/siderolabs/talos/commit/9db5d0c97ac31c7f6ce0b23d999126fc6cc094ec) fix: nocloud metadata for hostname\n* [`3cf325654`](https://github.com/siderolabs/talos/commit/3cf325654e4a7f73196241e59e3ca6b5f24c3e19) feat: modularize more arm64 kernel\n* [`3524745cc`](https://github.com/siderolabs/talos/commit/3524745cc49c51e4f13da954a57ab56d467fd26e) fix: allow any PKI in Talos API\n* [`f438cdb09`](https://github.com/siderolabs/talos/commit/f438cdb0993b17f0e540ecefa39cde09f89730f4) chore: use custom dhcpd server on macos qemu\n* [`11c17fb9a`](https://github.com/siderolabs/talos/commit/11c17fb9aad2443b10e15295069b8e24e0d514e2) fix: metal-iso reproducibility\n* [`7fcb89ee3`](https://github.com/siderolabs/talos/commit/7fcb89ee385fdbf47dae4a8308299c00488df84a) chore: add darwin vmnet qemu support\n* [`fc1237343`](https://github.com/siderolabs/talos/commit/fc1237343f79a1be907c43ac3ce116168409ed17) chore: clean up `/usr/bin`\n* [`b551f32ce`](https://github.com/siderolabs/talos/commit/b551f32ce550f2bc3c679a9857f28d604a297bbf) feat: update containerd to v2.1.1\n* [`67f4154f9`](https://github.com/siderolabs/talos/commit/67f4154f920fc0c58a9a832e14fbc7f9430747b3) docs: update disk-management.md\n* [`0cb137ad7`](https://github.com/siderolabs/talos/commit/0cb137ad7366e2386f49a99aee0a3c5ffb7223f6) fix: make disk size check work on old Talos\n* [`7c057edd5`](https://github.com/siderolabs/talos/commit/7c057edd5f3636dff6932ad9fbd7c51867b0c2c8) fix: use vmdk-convert istead of qemu-img to create VMDK for OVA files\n* [`cd618dad0`](https://github.com/siderolabs/talos/commit/cd618dad0feb1390e5945e2bba1d20bcecf30c2a) chore: update the go-blockdevice package\n* [`0b99631a0`](https://github.com/siderolabs/talos/commit/0b99631a0b64ce8d65ddcf7f40b2168debf11a62) fix: bump apid memory limit\n* [`5451f35b1`](https://github.com/siderolabs/talos/commit/5451f35b148a630c6ab011dce44b52fd2ad327ba) docs: update virtualbox\n* [`bd4d202a5`](https://github.com/siderolabs/talos/commit/bd4d202a5a67c56b6c6e6bc962f6bd51c729759f) refactor: bring owned.State from COSI to simplify tests\n* [`0b96df574`](https://github.com/siderolabs/talos/commit/0b96df57476af86a37bcfdbf28a479444a9e6e5c) feat: update containerd to 2.1.0\n* [`e1a939144`](https://github.com/siderolabs/talos/commit/e1a939144f25acc6a2715feedb30a56a47f6793d) docs: fix formatting in disk encryption\n* [`7a817df1c`](https://github.com/siderolabs/talos/commit/7a817df1cce58de2a16b72b37a54ffc0103af79a) docs: fix typo\n* [`f35b213b2`](https://github.com/siderolabs/talos/commit/f35b213b2b448c2e0065d4698095a843dd2f5268) test: fix DHCP unicast failures in QEMU environment\n* [`7064bbf05`](https://github.com/siderolabs/talos/commit/7064bbf056f083de0f7174c9d3c600871189b4e5) docs: fix vmware factory URL\n* [`78c33bcdb`](https://github.com/siderolabs/talos/commit/78c33bcdb9a30195ce401311e82b2e189faf33f3) feat: update default Kubernetes to v1.33.1\n* [`da6795266`](https://github.com/siderolabs/talos/commit/da67952666d2db2b8b5636bd4cae8af09a139410) fix: disable automatic MAC assignment to bridge interfaces\n* [`ca34adf58`](https://github.com/siderolabs/talos/commit/ca34adf585bfe04d2d1b84f186cb87aa77fc8e00) chore(ci): drop azure keys\n* [`ea5de19fa`](https://github.com/siderolabs/talos/commit/ea5de19fad3f62889899c0d89d08b8b73dfa75da) fix: selinux detection\n* [`52c76ea3a`](https://github.com/siderolabs/talos/commit/52c76ea3a61a4a3cbd963dc2ff0d6d21b4210bcd) fix: consistently apply dynamic grpc proxy dialer\n* [`aa9569e5d`](https://github.com/siderolabs/talos/commit/aa9569e5d8c59b762dfd64a4e9ef42cfdc6f9d51) chore: refactor cluster create cmd flags\n* [`1161faa05`](https://github.com/siderolabs/talos/commit/1161faa0594c033bf032852b880439b2082c9722) docs: fix typo in Cilium docs\n* [`164745e44`](https://github.com/siderolabs/talos/commit/164745e44334146b8a6f696640692c25b731414a) docs: remove `preserve` flag mention in upgrade notes\n* [`9a2ecbaaf`](https://github.com/siderolabs/talos/commit/9a2ecbaaf7b7a3f393dd29272aca34e069a24c6e) fix: makefile operating system param\n* [`118aa69d6`](https://github.com/siderolabs/talos/commit/118aa69d6f6e71b88747db1e8234d478daa54ab4) chore: update cloud-image-uploader dependencies\n* [`acdd721cf`](https://github.com/siderolabs/talos/commit/acdd721cfa62f9888a9ceea1693c17348c0d663a) chore: dump qemu pachine ipam records on darwin\n* [`bb9094534`](https://github.com/siderolabs/talos/commit/bb90945344f02b9cdae6e0e01821792dca25096b) chore: rotate aws iam credentials\n* [`0bfa4ae1b`](https://github.com/siderolabs/talos/commit/0bfa4ae1b06e1e6330adf331e1a97651bbe39b4a) chore: update deps for cloud-image-uploader\n* [`956d7c71b`](https://github.com/siderolabs/talos/commit/956d7c71bcdff639b8261cf6cf1a5d19cf702f75) chore: update sops keys\n* [`e2f819d88`](https://github.com/siderolabs/talos/commit/e2f819d880373102f8a8c7f0ff549e37ba75a08e) test: fix the process runner log collection\n* [`fdac4cfb9`](https://github.com/siderolabs/talos/commit/fdac4cfb9143853eb21d38e1b3d517455b0ba0f2) fix: upgrade go-kubernetes for DRA flag bug\n* [`09d88e1e8`](https://github.com/siderolabs/talos/commit/09d88e1e8374ef19e5730994d9b098333347f0b7) test: fix some flaky tests\n* [`ec1f41a94`](https://github.com/siderolabs/talos/commit/ec1f41a948b1bda02096434e47f2a2a767951fe9) chore: make qemu config server bind work on darwin\n* [`980f4d2b9`](https://github.com/siderolabs/talos/commit/980f4d2b936cfdc3ebc9882f7c25fbf2d2aa49f8) feat: bump dependencies\n* [`95259337e`](https://github.com/siderolabs/talos/commit/95259337ee0ccb22d7e9125074818ac8f9afa7af) fix: k8s 1.32->1.33 upgrade check\n* [`c3c326b40`](https://github.com/siderolabs/talos/commit/c3c326b405804c258b68f19b8d7dacca32535e9b) fix: improve volume mounter automaton\n* [`918b94d9a`](https://github.com/siderolabs/talos/commit/918b94d9a0b71b759073f8f7eb0f5dc7fdff413f) refactor: rewrite disk size check\n* [`ab7e693d7`](https://github.com/siderolabs/talos/commit/ab7e693d76500b6cdc2068221bdfce16633a8b01) chore: make qemu lb address bind work on darwin\n* [`97ceab001`](https://github.com/siderolabs/talos/commit/97ceab001c1bb79407c40d8fff867342656187b9) fix: multiple logic issues in platform network config controller\n* [`46349a9df`](https://github.com/siderolabs/talos/commit/46349a9df5d026a4e4b807a94865d5b3c371d32a) docs: remove azure image gallery instructions\n* [`0cfcdd3de`](https://github.com/siderolabs/talos/commit/0cfcdd3de1a20690ce47d63bb56b3d33d11c1474) docs: fix search on base talos.dev\n* [`78646b4e0`](https://github.com/siderolabs/talos/commit/78646b4e050358b930d27e4eddcfb22c4c825b0c) docs: add registryd debug command\n* [`c6824c211`](https://github.com/siderolabs/talos/commit/c6824c211438a3fb663f4233e8663732ab2ddf44) fix: deny apply config requests without v1alpha1 in \"normal\" mode\n* [`7df0408e4`](https://github.com/siderolabs/talos/commit/7df0408e460ebc392c6927c7b23e3795b9bd2140) fix: interactive installer config gen\n* [`881c5d62b`](https://github.com/siderolabs/talos/commit/881c5d62bf0d1f3311b3cf946b7801f97c1fb94b) fix: suppress duplicate platform config updates\n* [`66d77888e`](https://github.com/siderolabs/talos/commit/66d77888e42798995ddc73db3869d16959e53376) fix: replace downloaded asset paths correctly in cluster create cmd\n* [`6bd6c9b5a`](https://github.com/siderolabs/talos/commit/6bd6c9b5a08ca3b0e9574e1a61edc54c6ff722bb) fix: generate iso greater than 4 gig\n* [`ac140324e`](https://github.com/siderolabs/talos/commit/ac140324ebfb54f580c9b9bbbb55549bd5ffa11e) fix: skip PCR extension if TPM1.2 is found\n* [`09ef1f8a4`](https://github.com/siderolabs/talos/commit/09ef1f8a41c84e6a16729e6b6aff81788da0e3f5) fix: ignore http proxy on grpc socket dial\n* [`22a72dc80`](https://github.com/siderolabs/talos/commit/22a72dc80f2037a4cc7ad696d8dff504deb22630) chore: split options between three structs\n* [`22c34a50f`](https://github.com/siderolabs/talos/commit/22c34a50fc66edd174ab4a65961257de28a6daa0) fix(ci): provision cron jobs\n* [`b3b20eff3`](https://github.com/siderolabs/talos/commit/b3b20eff3a29f74d18df634cbb01f41bde17f2c8) fix: containerd crashing with sigsegv\n* [`f7891c301`](https://github.com/siderolabs/talos/commit/f7891c3018de248c7c66483562227b614689413c) chore: calculate vmnet interface name preemptively\n* [`ae87edffb`](https://github.com/siderolabs/talos/commit/ae87edffbcdaed12fef41541622f27882ed63755) fix: drop libseccomp from rootfs\n* [`f74a805bb`](https://github.com/siderolabs/talos/commit/f74a805bb067f55619cae7aebb92f00bb8173c92) fix: do correct backoff for nocloud reconcile\n* [`01bb294af`](https://github.com/siderolabs/talos/commit/01bb294af63f193dafa12cb623ea77ad67b698fb) fix(ci): provision tests\n* [`e4945be3b`](https://github.com/siderolabs/talos/commit/e4945be3bc43cbc275e2ea5f399a0188c5e16ad8) docs: add registryd debug command\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`17107ae`](https://github.com/siderolabs/crypto/commit/17107ae45403a2bcd4fecfb4660b60276652b00d) fix: add generic CSR generator and OpenSSL interop\n* [`53659fc`](https://github.com/siderolabs/crypto/commit/53659fc35f6abd4ada7ffa22ef1b148cf93c0f28) refactor: split into files\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`7c0324f`](https://github.com/siderolabs/gen/commit/7c0324fee9a7cfbdd117f43702fa273689f0db97) chore: future-proof HashTrieMap\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`5b39ef8`](https://github.com/siderolabs/go-circular/commit/5b39ef87df04efeaa47fe6374a8114f39c126122) fix: do not log error if chunk zero was never written\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>2 commits</summary>\n<p>\n\n* [`9070be4`](https://github.com/siderolabs/go-kubernetes/commit/9070be4308e23d969ec4fc49b25dab4a27d512e7) fix: remove DynamicResourceAllocation feature gate\n* [`8cb588b`](https://github.com/siderolabs/go-kubernetes/commit/8cb588bc4c93d812de901a6a33e599ba2169cd96) fix: k8s 1.32->1.33 upgrade check\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>33 commits</summary>\n<p>\n\n* [`79bfa9e`](https://github.com/siderolabs/pkgs/commit/79bfa9e06e5e69955236ffd58323c9936d638d45) feat: update NVIDIA drivers to 570.148.08\n* [`c8b8bd8`](https://github.com/siderolabs/pkgs/commit/c8b8bd8b5eb265f8e8c8955998e428b86d177ab5) feat: bump dependencies\n* [`54bf03e`](https://github.com/siderolabs/pkgs/commit/54bf03ebf24d9ef70a47d4b3b4f30d92191085da) feat: update Linux to 6.12.31\n* [`93b3aaa`](https://github.com/siderolabs/pkgs/commit/93b3aaae5369140058e6a5cbdf83d1da235eb735) feat: add patch for CephFS IMA performance regression\n* [`ebd6627`](https://github.com/siderolabs/pkgs/commit/ebd6627c68406076ed95b2cd629d2ace51bb49b6) feat: disable IMA support\n* [`8aad53b`](https://github.com/siderolabs/pkgs/commit/8aad53bab3201d7f87d39ab61953e04392402efc) feat: add CONFIG_NFT_CONNLIMIT to kernel\n* [`7a299fa`](https://github.com/siderolabs/pkgs/commit/7a299fa02106a7216926d6bcff21fb1cd2da7d73) feat: update Linux to 6.12.30\n* [`8c4603e`](https://github.com/siderolabs/pkgs/commit/8c4603e90335b9aaf180b954ebc43f65dcb2b7b6) feat: move more configs to modules on arm64\n* [`7b1183b`](https://github.com/siderolabs/pkgs/commit/7b1183bea84e46cd8f1a775f95683b8a0039c2d7) feat(kernel): enable IB user-space management and RDMA\n* [`1b1430e`](https://github.com/siderolabs/pkgs/commit/1b1430e82ef62efdd538588183ed27def2bebbaa) fix: drop pcre2 binaries\n* [`487610c`](https://github.com/siderolabs/pkgs/commit/487610c4f286210c22cd813427380af654297791) fix: drop broken symlinks\n* [`f31d518`](https://github.com/siderolabs/pkgs/commit/f31d518eefec0cb672760d00a5c2de37b45dfb45) fix: clean up some binaries\n* [`0f74b9b`](https://github.com/siderolabs/pkgs/commit/0f74b9bd1d097a283f3edd6165161e4e0688a79f) feat: update containerd to v2.1.1\n* [`89b4037`](https://github.com/siderolabs/pkgs/commit/89b40372b8964a9dc9ad3db17a46a9d9c797f60f) fix: tenstorrent pkg name\n* [`a14b544`](https://github.com/siderolabs/pkgs/commit/a14b54409704c1f3beb0f51089dadd3f3e8dc441) chore: drop qemu-tools vmdk support\n* [`2563e47`](https://github.com/siderolabs/pkgs/commit/2563e47ca1bfc755ee4ecf2b470cfed081b54e6f) feat: add tenstorrent package\n* [`2a1c42f`](https://github.com/siderolabs/pkgs/commit/2a1c42fde5fe4009c33d50d571d7d3cfe3a09888) fix(renovate): flannel config\n* [`bfa69a8`](https://github.com/siderolabs/pkgs/commit/bfa69a820e8190aed3a45c00dff5f4f1cc42b7a6) feat: add open-vmdk package\n* [`9f1ba1f`](https://github.com/siderolabs/pkgs/commit/9f1ba1f047c835abdf882540d316055a3e2d1bfc) fix: bring back updated containerd gvisor patch\n* [`1567cb6`](https://github.com/siderolabs/pkgs/commit/1567cb616691dc22fbc3374cdeac11cdbe51bb94) feat: update Linux 6.12.28, firmware\n* [`9bc66e6`](https://github.com/siderolabs/pkgs/commit/9bc66e6bd355f8a86c4becbd78aede1323e3681e) feat: update containerd to 2.1.0\n* [`c6b54e0`](https://github.com/siderolabs/pkgs/commit/c6b54e04fb5d943ff31f05b1e095af65eb901604) feat: enable zswap\n* [`4cd7084`](https://github.com/siderolabs/pkgs/commit/4cd7084634c2b79541da8c6f95c047d4eb0e66a2) feat: update dependencies\n* [`a3fcbf8`](https://github.com/siderolabs/pkgs/commit/a3fcbf812632aaa8e8f9027a88181c284e7d919d) feat(kernel): enable panthor driver\n* [`74d1665`](https://github.com/siderolabs/pkgs/commit/74d16657fd53c30249c3eba75769f90dd84366ce) feat: update ZFS to 2.3.2\n* [`ddc866b`](https://github.com/siderolabs/pkgs/commit/ddc866bc9dd0557c2e9d5d0b234348767769cfd3) feat: update Linux to 6.12.27\n* [`a347857`](https://github.com/siderolabs/pkgs/commit/a347857b33a6a41fe2661a7451c3af65a51404c9) fix: build containerd with Go 1.23\n* [`74da85c`](https://github.com/siderolabs/pkgs/commit/74da85c2cf61b8006af38b3d0d38dc13098d5227) fix: containerd build doesn't need seccomp\n* [`4effa05`](https://github.com/siderolabs/pkgs/commit/4effa0525dc87974052e9dec2685a0ad411773dd) fix: downgrade libseccomp to 2.5.5\n* [`9cea00b`](https://github.com/siderolabs/pkgs/commit/9cea00b4601d7bedf49606b647003f3c6cb0787b) feat: update Linux to 6.12.25\n* [`cb108a5`](https://github.com/siderolabs/pkgs/commit/cb108a514b55a302008fb4c1ce6d88ce0d769b58) feat(kernel): enable bcache module\n* [`d042432`](https://github.com/siderolabs/pkgs/commit/d04243270a4f10f9ecb889883ab42687e5ae6351) fix: backport sandbox fix for Gvisor\n* [`fa625dc`](https://github.com/siderolabs/pkgs/commit/fa625dc6dd97a61cb8479b8b0ab82126650de11b) feat: update Linux 6.12.24, containerd 2.0.5\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`d2a79e0`](https://github.com/siderolabs/siderolink/commit/d2a79e0263806b68ff0a44ea9efa58b83fb269ec) fix: clean up device on failure\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>3 commits</summary>\n<p>\n\n* [`af3fd64`](https://github.com/siderolabs/tools/commit/af3fd645d48a373396f8346af411c1c827c87376) feat: update dependencies\n* [`e35234b`](https://github.com/siderolabs/tools/commit/e35234bd94c3c16daf06d00848d7752f5e4c7d15) feat: update dependencies\n* [`c96a4e6`](https://github.com/siderolabs/tools/commit/c96a4e671e378f80f161e45942f80b10adfd562d) chore: update toolchain to the latest version\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.6.0 -> v0.7.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.9.0 -> v1.10.0\n* **github.com/containerd/containerd/api**              v1.8.0 -> v1.9.0\n* **github.com/containerd/containerd/v2**               v2.0.5 -> v2.1.1\n* **github.com/containernetworking/plugins**            v1.6.2 -> v1.7.1\n* **github.com/cosi-project/runtime**                   v0.10.2 -> v0.10.6\n* **github.com/detailyang/go-fallocate**                432fa640bd2e **_new_**\n* **github.com/docker/cli**                             v28.0.4 -> v28.2.2\n* **github.com/docker/docker**                          v28.0.4 -> v28.2.2\n* **github.com/google/cel-go**                          v0.24.1 -> v0.25.0\n* **github.com/google/go-containerregistry**            v0.20.3 -> v0.20.5\n* **github.com/google/go-tpm**                          v0.9.3 -> v0.9.5\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**   v2.3.1 -> v2.3.2\n* **github.com/hetznercloud/hcloud-go/v2**              v2.21.0 -> v2.21.1\n* **github.com/linode/go-metadata**                     v0.2.1 -> v0.2.2\n* **github.com/miekg/dns**                              v1.1.65 -> v1.1.66\n* **github.com/prometheus/procfs**                      v0.16.0 -> v0.16.1\n* **github.com/rivo/tview**                             949945f8d922 -> 0c592cd31026\n* **github.com/safchain/ethtool**                       v0.5.10 -> v0.6.1\n* **github.com/siderolabs/crypto**                      v0.5.1 -> v0.6.0\n* **github.com/siderolabs/gen**                         v0.8.0 -> v0.8.1\n* **github.com/siderolabs/go-blockdevice/v2**           v2.0.16 -> v2.0.18\n* **github.com/siderolabs/go-circular**                 v0.2.2 -> v0.2.3\n* **github.com/siderolabs/go-kubernetes**               v0.2.21 -> v0.2.23\n* **github.com/siderolabs/pkgs**                        v1.10.0-5-g48dba3e -> v1.11.0-alpha.0-32-g79bfa9e\n* **github.com/siderolabs/siderolink**                  v0.3.13 -> v0.3.14\n* **github.com/siderolabs/talos/pkg/machinery**         v1.10.0 -> v1.11.0-alpha.0\n* **github.com/siderolabs/tools**                       v1.10.0 -> v1.11.0-alpha.0-2-gaf3fd64\n* **golang.org/x/net**                                  v0.39.0 -> v0.40.0\n* **golang.org/x/oauth2**                               v0.29.0 -> v0.30.0\n* **golang.org/x/sync**                                 v0.13.0 -> v0.14.0\n* **golang.org/x/sys**                                  v0.32.0 -> v0.33.0\n* **golang.org/x/term**                                 v0.31.0 -> v0.32.0\n* **golang.org/x/text**                                 v0.24.0 -> v0.25.0\n* **google.golang.org/grpc**                            v1.71.1 -> v1.72.2\n* **k8s.io/api**                                        v0.33.0 -> v0.33.1\n* **k8s.io/apimachinery**                               v0.33.0 -> v0.33.1\n* **k8s.io/apiserver**                                  v0.33.0 -> v0.33.1\n* **k8s.io/client-go**                                  v0.33.0 -> v0.33.1\n* **k8s.io/component-base**                             v0.33.0 -> v0.33.1\n* **k8s.io/kube-scheduler**                             v0.33.0 -> v0.33.1\n* **k8s.io/kubectl**                                    v0.33.0 -> v0.33.1\n* **k8s.io/kubelet**                                    v0.33.0 -> v0.33.1\n* **k8s.io/pod-security-admission**                     v0.33.0 -> v0.33.1\n* **sigs.k8s.io/hydrophone**                            b92baf7e0b04 -> v0.7.0\n\nPrevious release can be found at [v1.10.0](https://github.com/siderolabs/talos/releases/tag/v1.10.0)\n\n## [Talos 1.11.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.11.0-alpha.0) (2025-05-01)\n\nWelcome to the v1.11.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Orzelius\n* Dmitrii Sharshakov\n* Marat Bakeev\n* Steve Francis\n* Alvaro \"Chamo\" Linares Cabre\n* Andrew Longwill\n* Bryan Mora\n* Joakim Nohlgård\n* Spencer Smith\n* Tan Siewert\n\n### Changes\n<details><summary>49 commits</summary>\n<p>\n\n* [`ace44ea61`](https://github.com/siderolabs/talos/commit/ace44ea6169d419f188e0a2456c31f420e61ae77) test: update hydrophone to 0.7.0\n* [`3a1163692`](https://github.com/siderolabs/talos/commit/3a1163692da7b41b17f263ab43d0fd81abafc4f8) chore: cross platform qemu preflight checks\n* [`7914fb104`](https://github.com/siderolabs/talos/commit/7914fb10412d31a1b75c74b0c66578e55fb77bc7) chore: move the create command to it's own package\n* [`c8e619608`](https://github.com/siderolabs/talos/commit/c8e619608dc8898be71a17c54503085ef38abf37) chore: prepare for release 1.11\n* [`1299aaa45`](https://github.com/siderolabs/talos/commit/1299aaa45d997dd23aed380f858cec3bc6b975e4) chore(ci): add extensions test for Youki runtime\n* [`e50ceb221`](https://github.com/siderolabs/talos/commit/e50ceb221e56f0760d5f2fc9e4b821d6b29add05) docs: activate Talos 1.10 docs\n* [`9d12aaeb1`](https://github.com/siderolabs/talos/commit/9d12aaeb19d68c5e692921b938d72347f6129f65) test: improve config patch test\n* [`106a656b6`](https://github.com/siderolabs/talos/commit/106a656b6132e766e9e9ef7b1c12b97a413b5de6) chore: make qemu provider build on darwin\n* [`8013aa06c`](https://github.com/siderolabs/talos/commit/8013aa06cd338f1dd11061d3455767fee4b9783c) test: replace platform metadata test\n* [`2b89c2810`](https://github.com/siderolabs/talos/commit/2b89c2810551ab52678e62fcbf5355dd05c72030) fix: relax etcd APIs RBAC requirements\n* [`1e677587c`](https://github.com/siderolabs/talos/commit/1e677587c0e6c61f724a85f18ee9d436ae6da038) fix: preserve kubelet image suffix\n* [`62ab8af45`](https://github.com/siderolabs/talos/commit/62ab8af459475cbd24a2f34d8923ce70d1fda3db) fix: disk image generation with image cache\n* [`d60626f01`](https://github.com/siderolabs/talos/commit/d60626f017ef495210939ee4f8ef7f623dd325f9) fix: handle encryption type mismatch\n* [`a9109ebd0`](https://github.com/siderolabs/talos/commit/a9109ebd00fcd300bf4262142ade77df6788852b) feat: allow SideroLink unique token in machine config\n* [`2ff3a6e40`](https://github.com/siderolabs/talos/commit/2ff3a6e4079a29b6b45770204fd8cb30369518e9) feat(kernel): add bcache kernel module to core talos\n* [`fa95a2146`](https://github.com/siderolabs/talos/commit/fa95a2146056bfe1ae322cb574fd8d432745b5c9) fix(ci): bios provision test\n* [`f7c5b86be`](https://github.com/siderolabs/talos/commit/f7c5b86be7e2b28906cb66b466a017887ac5e2b6) fix: sync PCR extension with volume provisioning lifecycle\n* [`f90c79474`](https://github.com/siderolabs/talos/commit/f90c79474b50da35ab8e285ee9723957e4b6cf00) chore: show bound driver in pcidevices info\n* [`8db34624c`](https://github.com/siderolabs/talos/commit/8db34624c6ed9707ba1165da790f5b389bd1c92f) fix: handle correctly changing platform network config\n* [`77c7a075b`](https://github.com/siderolabs/talos/commit/77c7a075bbba7ffd24dbd9d5e069ccb50f8143b4) feat: update Kubernetes to 1.33.0\n* [`74f0c48c7`](https://github.com/siderolabs/talos/commit/74f0c48c738b0b80278667c3e5a1c5e1ecd5a078) feat: add version compatibility for Talos 1.11\n* [`c4fb7dad0`](https://github.com/siderolabs/talos/commit/c4fb7dad0ec390781cca54e2348f116cb1cf1866) fix: force DNS runner shutdown on timeout\n* [`c49b4836e`](https://github.com/siderolabs/talos/commit/c49b4836e46725940f4731e182475905ebee6019) docs: hetzner: add note about public iso\n* [`16ea2b113`](https://github.com/siderolabs/talos/commit/16ea2b113fad0c81a96dbcfdf4fd1b9f43bb1282) docs: add what is new for 1.10\n* [`be3f0c018`](https://github.com/siderolabs/talos/commit/be3f0c018c50da3d920ed8fe36d4f31c5d3edfac) fix: fix Gvisor tests with containerd patch\n* [`37db132b3`](https://github.com/siderolabs/talos/commit/37db132b3b3e6c58f15228c64b023e77c15cf012) chore(ci): add provision test with bios\n* [`ec60b70e7`](https://github.com/siderolabs/talos/commit/ec60b70e7245f49f6ac1d48cd4292b85f1d6f79e) fix: set media type to OCI for image cache layer\n* [`a471eb31b`](https://github.com/siderolabs/talos/commit/a471eb31b87b393ee9fc57fbc725801d08386ad4) feat: update Linux 6.12.24, containerd 2.0.5\n* [`54ad5b872`](https://github.com/siderolabs/talos/commit/54ad5b8729c7d54da2efa6baf7886163741176ed) fix: extension services logging to console\n* [`601f036ba`](https://github.com/siderolabs/talos/commit/601f036ba9cc762d6a3c6ae819654005f1d49527) docs: correct flannel extra args example\n* [`ae94377d1`](https://github.com/siderolabs/talos/commit/ae94377d15a3b70248fbb446d13d7ae96bb04e82) feat: support encryption config for user volumes\n* [`9616f6e8d`](https://github.com/siderolabs/talos/commit/9616f6e8d280e64815fe3e1ba324df1dd5d2122d) docs: add caveat for kubespan and host ports\n* [`a1d08a362`](https://github.com/siderolabs/talos/commit/a1d08a3624c7c8b5213b8e9dee1cf9289d6719dc) docs: fixes typo at OpenEBS Mayastor worker patches\n* [`a91e8726e`](https://github.com/siderolabs/talos/commit/a91e8726e433be9db58f1a7a09a4cca422b2b50c) docs: add a dark theme\n* [`c76189c58`](https://github.com/siderolabs/talos/commit/c76189c58a2fe65954924168d7077350974829dd) fix: grub EFI mount point\n* [`4ca985c65`](https://github.com/siderolabs/talos/commit/4ca985c656c1924e550d06c073a7c1b6cb03f392) fix: grub efi platform install\n* [`b31260281`](https://github.com/siderolabs/talos/commit/b31260281dba752e06fcfc645bb020872602d898) docs: update storage.md\n* [`396a29040`](https://github.com/siderolabs/talos/commit/396a290408eff5bda4ad31fafc33496bea9aa899) feat: add new SBCs\n* [`a902f6580`](https://github.com/siderolabs/talos/commit/a902f6580f8e104977521a335a41c0cd70256906) feat: update Flannel to v0.26.7\n* [`2bbefec1a`](https://github.com/siderolabs/talos/commit/2bbefec1abacae2952782fbd163ef52d34f09858) docs: use cache in preview\n* [`6028a8d2d`](https://github.com/siderolabs/talos/commit/6028a8d2da571a8a37712f9917e24372cf5af919) docs: update kubeprism.md\n* [`e51a8ef8c`](https://github.com/siderolabs/talos/commit/e51a8ef8c68bb1cfab2ac845a0b6792d7e000324) fix: prefer new `MountStatus` resource\n* [`d9c7e7946`](https://github.com/siderolabs/talos/commit/d9c7e79462496d6756c55b0672994aa262eaed4f) docs: fix search\n* [`b32fa029b`](https://github.com/siderolabs/talos/commit/b32fa029b3f550b3403e25e23aac889d61366389) feat: update Kubernetes to 1.33.0-rc.1\n* [`f0ea478cb`](https://github.com/siderolabs/talos/commit/f0ea478cb811675a450839b8dcd351e43404efd4) feat: support address priority\n* [`8cd3c8dc7`](https://github.com/siderolabs/talos/commit/8cd3c8dc77b25270ed8dea65cbbd4e87c203ee74) test: fix NVIDIA OSS tests\n* [`62f2d27cd`](https://github.com/siderolabs/talos/commit/62f2d27cd44de5112055b5b47f23b001cadccaae) docs: update virtualbox.md\n* [`141326ea3`](https://github.com/siderolabs/talos/commit/141326ea3bb2e471a5cb51fd565521683a9792fc) docs: fix tabpane styling\n* [`134aa53cc`](https://github.com/siderolabs/talos/commit/134aa53ccaba55754544977d695ad3ca5d34e604) feat: update base CoreDNS code in host DNS to 1.12.1\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>4 commits</summary>\n<p>\n\n* [`9cea00b`](https://github.com/siderolabs/pkgs/commit/9cea00b4601d7bedf49606b647003f3c6cb0787b) feat: update Linux to 6.12.25\n* [`cb108a5`](https://github.com/siderolabs/pkgs/commit/cb108a514b55a302008fb4c1ce6d88ce0d769b58) feat(kernel): enable bcache module\n* [`d042432`](https://github.com/siderolabs/pkgs/commit/d04243270a4f10f9ecb889883ab42687e5ae6351) fix: backport sandbox fix for Gvisor\n* [`fa625dc`](https://github.com/siderolabs/pkgs/commit/fa625dc6dd97a61cb8479b8b0ab82126650de11b) feat: update Linux 6.12.24, containerd 2.0.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/detailyang/go-fallocate**         432fa640bd2e **_new_**\n* **github.com/siderolabs/pkgs**                 v1.10.0-5-g48dba3e -> v1.11.0-alpha.0-3-g9cea00b\n* **github.com/siderolabs/talos/pkg/machinery**  v1.10.0 -> v1.10.0-alpha.3\n* **sigs.k8s.io/hydrophone**                     b92baf7e0b04 -> v0.7.0\n\nPrevious release can be found at [v1.10.0](https://github.com/siderolabs/talos/releases/tag/v1.10.0)\n\n## [Talos 1.10.0-alpha.3](https://github.com/siderolabs/talos/releases/tag/v1.10.0-alpha.3) (2025-03-24)\n\nWelcome to the v1.10.0-alpha.3 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### auditd\n\nKernel parameter `talos.auditd.disabled=1` can be used to disable Talos built-in `auditd` service.\n\n\n### cgroups v1\n\nTalos Linux no longer supports `cgroupsv1` when running in non-container mode.\nThe kernel argument `talos.unified_cgroup_hierarchy` is now ignored.\n\n\n### Disk Image\n\nTalos starting with 1.10 will have disk images that will use GRUB only for legacy BIOS and systemd-boot for modern UEFI systems.\nOn first boot Talos determines the boot method and will wipe the unused bootloader.\n\nSecureboot disk-images will be sd-boot only.\n\nFor ARM64 imager will still generate GRUB bootloader for Talos < 1.10 and for Talos >= 1.10 all ARM64 boot assets will use systemd-boot.\n\nImager supports overwriting bootloader when generating a disk image via the Imager profile `output` option.\n\nEg:\n\n```yaml\noutput:\n  kind: image\n  imageOptions:\n    bootloader: sd-boot # supported options are sd-boot, grub, dual-boot\n```\n\n\n\n### Driver Rebind\n\nTalos 1.10 now supports a new machine config document named `PCIDriverRebindConfig` that allows rebinding the driver of a PCI device to a different target driver.\nSee the [documentation](https://www.talos.dev/v1.10/reference/configuration/hardware/pcidriverrebindconfig/) for more information.\n\n\n### Ethernet\n\nTalos now provides `ethtool`-style Ethernet low-level configuration via `network/EthernetConfig` documents.\nCurrent status of the interface can be read by `talosctl get ethernetstatus`.\n\n\n### Machine Install Extensions\n\n`.machine.install.extensions` will have no effect starting from Talos 1.10, the machine config document field is still kept so upgrades from older versions are possible.\nUse [Boot Assets](https://www.talos.dev/v1.10/talos-guides/install/boot-assets/) instead.\n\n\n### Extra Kernel Args\n\nTalos 1.10 on fresh install on UEFI systems will now use systemd-boot and UKIs (Unified Kernel Images)[https://uapi-group.org/specifications/specs/unified_kernel_image/].\nThis means the kernel command line arguments are part of the UKI and cannot be modified without an upgrade to a new UKI.\n\nUpgrades to Talos 1.10 will preseve the existing bootloader (GRUB for non-secureboot) and sd-boot for Secureboot and this change will have no effect.\n\nTo build a [boot asset](https://www.talos.dev/v1.10/talos-guides/install/boot-assets/) with extra kernel arguments whether an `installer` or a boot image use either [Image Factory](https://www.talos.dev/v1.10/talos-guides/install/boot-assets/#image-factory) or\n[Imager](https://www.talos.dev/v1.10/talos-guides/install/boot-assets/#imager).\n\nThis means kernel arguments not part of the UKI will not be preserved across updates and a proper installer image generated via Imager Factory or Imager is required.\n\n\n### Ingress Firewall\n\nTalos Ingress Firewall now filters access to Kubernetes NodePort services correctly.\n\n\n### iSCSI Initiator\n\nTalos now generates `/etc/iscsi/initiatorname.iscsi` file based on the node identity which is tied to the lifecycle of the node.\nIf using `iscsi-tools` extension, starting with Talos 1.10 would have a more deterministic IQN for the initiator node.\nMake sure to update any iSCSI targets to use the new initiator IQN.\n\nThe iqn can be read by `talosctl read /etc/iscsi/initiatorname.iscsi`\n\n\n### ISO\n\nTalos starting with 1.10 will have ISO's that will use GRUB only for legacy BIOS and systemd-boot for modern UEFI systems.\n\n\n### kube-apiserver Authorization Config\n\nWhen using `.cluster.apiServer.authorizationConfig` the user provided order for the authorizers is honoured and `Node` and `RBAC` authorizers are always added to the end if not explicitly specified.\n\nEg: If user provides only `Webhook` authorizer, the final order will be `Webhook`, `Node`, `RBAC`.\n\nTo provide a specific order for `Node` or `RBAC` explicitly, user can provide the authorizer in the order they want.\n\nEg:\n\n```yaml\ncluster:\n  apiServer:\n    authorizationConfig:\n      - type: Node\n        name: Node\n      - type: Webhook\n        name: Webhook\n        webhook:\n          connectionInfo:\n            type: InClusterConfig\n        ...\n      - type: RBAC\n        name: rbac\n```\n\nUsage of `authorization-mode` CLI argument will not support this form of customization.\n\n\n### NVMe NQN\n\nTalos now generates `/etc/nvme/hostnqn` and `/etc/nvme/hostid` files based on the node identity which is tied to the lifecycle of the node.\n\nThe NQN can be read by `talosctl read /etc/nvme/hostnqn`\n\n\n### Fully bootstrapped builds\n\nTalos 1.10 is built with a toolchain based on [[Stageˣ]](https://stagex.tools/), which is a project building fully bootstrapped software.\nThis change increases reproducibility, auditability and security of Talos builds.\n\nThis also changes Talos root filesystem structure for unified /usr, with other directories symlinking to /usr/bin and /usr/lib.\nSystem extensions must move their directories accordingly for 1.10.\n\n\n### Component Updates\n\n* Linux: 6.12.19\n* CNI plugins: 1.6.2\n* runc: 1.2.6\n* containerd: 2.0.4\n* etcd: 3.5.20\n* Flannel: 0.26.4\n* Kubernetes: 1.33.0-beta.0\n\nTalos is built with Go 1.24.1.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitry Sharshakov\n* Dmitriy Matrenichev\n* Dmitrii Sharshakov\n* Joakim Nohlgård\n* 459below\n* Enrique Hernández Bello\n* Justin Garrison\n* Mathspy\n* Nico Berlee\n* Skyler Mäntysaari\n* Utku Ozdemir\n* ihelmer07\n* Adam Cirillo\n* Alex Lubbock\n* Alexis La Goutte\n* Andrew Longwill\n* Andrew Symington\n* Artem Chernyshev\n* Cazmill13\n* Christian Luetke-Stetzkamp\n* Christoph Hoopmann\n* Dennis\n* Devin Buhl\n* Dominik Masur\n* Ermeikin Sergei\n* Florian Grignon\n* Gabe Alford\n* Ganawa Juanah\n* Jason Benedicic\n* Joakim Nohlgård\n* Josef\n* K Birt\n* KillianCdP\n* L.J. Hanson\n* Louis SCHNEIDER\n* Marcel Hamer\n* Mikhail Petrov\n* Motte\n* Natalie Romana Albers\n* Omar\n* Orzelius\n* PRIHLOP\n* Ram\n* Robin Elfrink\n* Ryan Jacobs\n* Serge Logvinov\n* Shaderbug\n* Stepan Rabotkin\n* Thomas Gosteli\n* Tim Olson\n* Tine Jozelj\n* Tobias Kohlbau\n* TomyLobo\n* Valtteri Huuskonen\n* bzub\n* greenpsi\n* jvanthienen\n* mehlc\n* pphysch\n* sflotat2607\n* suse-coder\n\n### Changes\n<details><summary>270 commits</summary>\n<p>\n\n* [`a834219ac`](https://github.com/siderolabs/talos/commit/a834219ace76663e13bfc0cd5e59b19f32b63ac7) chore: update dependencies\n* [`857779b90`](https://github.com/siderolabs/talos/commit/857779b902ca8c235eb42988b0a8a17c0de2ac21) docs: clarify custom CA certificate with KMS STATE encryption\n* [`39ed45ae6`](https://github.com/siderolabs/talos/commit/39ed45ae61f8ff6a7d7475b87b9d4ff61377be8b) docs: add information about Cilium exclusive CNI\n* [`087a85f40`](https://github.com/siderolabs/talos/commit/087a85f40920e84344451959dbd570b3d1d77a99) feat: support running with SELinux enforcing\n* [`d4aacb0d8`](https://github.com/siderolabs/talos/commit/d4aacb0d85c239f5960a4ff223b28f387a1023ef) refactor: mount operation for STATE and user disks\n* [`44f3c7248`](https://github.com/siderolabs/talos/commit/44f3c72489350aab64eef67f7d803853819d3a74) fix: kata extension\n* [`7ca5ab5e9`](https://github.com/siderolabs/talos/commit/7ca5ab5e933f1cd28fb74c24ae2a0f00030b763b) fix: shrink installer and imager images\n* [`ea0994cfe`](https://github.com/siderolabs/talos/commit/ea0994cfef497412fecd3c345c03f70b1ebd62b9) fix: kexec with smbios type 11 string\n* [`8e20a5d28`](https://github.com/siderolabs/talos/commit/8e20a5d280523279b3039ea02f5c30137087b3b5) fix: pass /usr/etc/in-container to apid, trustd and extension containers\n* [`9b9512ba8`](https://github.com/siderolabs/talos/commit/9b9512ba88e0f2ebd78b72f4abdccb3f46f9320b) feat: update Linux 6.12.19, containerd 2.0.4\n* [`433b0237b`](https://github.com/siderolabs/talos/commit/433b0237bd11ac57aac8d6b8980337d37383c33d) fix: correct structprotogen example\n* [`6e68a522a`](https://github.com/siderolabs/talos/commit/6e68a522ab4303c316f6039e4beaaa7ea20a63f9) chore: fix conformance artifact name\n* [`f592730d9`](https://github.com/siderolabs/talos/commit/f592730d9db79b4d8a0823389dc35fce5c668920) fix(ci): fix image cache test\n* [`cc6c714ce`](https://github.com/siderolabs/talos/commit/cc6c714ce5fb7359028ecd4ef43c8bb0935250ae) feat: add Tegra modules to initrd\n* [`81d1fe0f8`](https://github.com/siderolabs/talos/commit/81d1fe0f807210346d59303ef05d30a1c5e53d02) fix: add missing TOOLS_PREFIX for WITH_DEBUG_SHELL builds\n* [`3e38bf6d4`](https://github.com/siderolabs/talos/commit/3e38bf6d44b6ea0abd065f7883b5320845a9d12e) fix: ignore missing config (nocloud) via cidata\n* [`27a4486a8`](https://github.com/siderolabs/talos/commit/27a4486a82151e3c28fe7f23521e3e3e7a5bf287) docs: fix typo cluser -> cluster\n* [`ac79b1ea0`](https://github.com/siderolabs/talos/commit/ac79b1ea0c033012ed3dd5a84190fb07de431c1c) feat: pull in Intel STTMAC network drivers\n* [`9bb5c060c`](https://github.com/siderolabs/talos/commit/9bb5c060c160ec2e1449f30c6ba85b92a50c1a9b) chore: bump go-kubernetes\n* [`2b8e08234`](https://github.com/siderolabs/talos/commit/2b8e082344d3bb62c3f5d83b9dc9edbe4f7fede8) feat: deprecate `.machine.install.extensions`\n* [`b7446372b`](https://github.com/siderolabs/talos/commit/b7446372b62152c235c30823b12a9e2df7a111a3) docs: add documentation on unofficial SBC forks\n* [`9bec765c4`](https://github.com/siderolabs/talos/commit/9bec765c41e49d872de29956cdae50ea7cd89d8a) feat: talosctl kubeconfig write to stdout option\n* [`11ebb1078`](https://github.com/siderolabs/talos/commit/11ebb107853a21d626d2c80a88f33bdc5df52641) fix: kexec when using sd-boot\n* [`61f1a32d2`](https://github.com/siderolabs/talos/commit/61f1a32d24be8a4d73f48d02fbd6281208bdf7ac) test: allocate more resources for conformance runs\n* [`b8b7b83f8`](https://github.com/siderolabs/talos/commit/b8b7b83f872ee4d4e8b52d51b42116d4bf8223ae) chore: extraKernelArgs validation for UKI's\n* [`e2df0c6d3`](https://github.com/siderolabs/talos/commit/e2df0c6d3628ea972e914a94af09d8606083825d) docs: update siderolink.md\n* [`f9b14e784`](https://github.com/siderolabs/talos/commit/f9b14e7848f2b08b6cc274a0ef7a01df98bcd48e) fix: reconnect on SideroLink tunnel on/off change\n* [`29f7b3bf3`](https://github.com/siderolabs/talos/commit/29f7b3bf37aead52f9e015aeeea20f4318f39dc4) test(ci): use k8s websocket executor for tests\n* [`9531c1c6d`](https://github.com/siderolabs/talos/commit/9531c1c6d2601b77febbdcc7bca8686f3163fd21) fix(ci): image-cache cron\n* [`90abdc489`](https://github.com/siderolabs/talos/commit/90abdc4893316516622b01e8c0d2d3bb8ba06416) feat: update Kubernetes to 1.33.0-beta.0\n* [`9a5914048`](https://github.com/siderolabs/talos/commit/9a5914048c66ebcaef1614f9efc0c656d8dff63a) refactor: ephemeral mount\n* [`e4fb1c06a`](https://github.com/siderolabs/talos/commit/e4fb1c06a486d45afe6adba0d2290595d0f680f4) docs: update for predictable interface naming\n* [`729fce306`](https://github.com/siderolabs/talos/commit/729fce3065b4e23bc9a09739dc2eb86521ca3fe7) feat: update Linux to 6.12.18\n* [`b4d2e1c3c`](https://github.com/siderolabs/talos/commit/b4d2e1c3c59db3d64fcb0fa10fbd250dcdd31d5b) fix: typo in machinery CloudPlatforms\n* [`7e0475488`](https://github.com/siderolabs/talos/commit/7e0475488d3a5c088fc02431c2ee55cf4a453b84) fix: qemu: archive cluster logs only after stopping VMs\n* [`dab30a8b9`](https://github.com/siderolabs/talos/commit/dab30a8b9fc48078a1cefca6cc6a9caaacef5a93) fix: ensure no goroutines escape in dns controller\n* [`fce824e2f`](https://github.com/siderolabs/talos/commit/fce824e2f3aa1c21a72e385a4daa2a546305cf0a) fix: change from \"init6\" to \"inet6\" in docs\n* [`f51ebd1bc`](https://github.com/siderolabs/talos/commit/f51ebd1bc8142b2ea649ee205f015dfde61e8ee5) chore: fix the mount cache ids in the Dockerfile\n* [`4365aecbd`](https://github.com/siderolabs/talos/commit/4365aecbd6dc4e54b22514938d6c41f7276c8e70) test: use standard installer for e2e-iso\n* [`431178327`](https://github.com/siderolabs/talos/commit/43117832725acf6fdf0b2ac6e0302de64958f85b) feat: update Kubernetes to v1.33.0-alpha.3\n* [`1259345e4`](https://github.com/siderolabs/talos/commit/1259345e4240c0ec3d84b5fd982d98897a39cc62) fix(ci): image-cache cron\n* [`18871a7eb`](https://github.com/siderolabs/talos/commit/18871a7eb87db2c536a4620e2c3ba64951171140) chore: tidy labeled-squashfs.sh\n* [`d45259f89`](https://github.com/siderolabs/talos/commit/d45259f89dce282eaf6bc3ed4c2106aa8a054eba) feat: update Flannel to 0.26.5\n* [`e83ef0e2e`](https://github.com/siderolabs/talos/commit/e83ef0e2ee8a564efecb1356d7e8246b2e9056f6) docs: update proxmox.md\n* [`3def5f9a6`](https://github.com/siderolabs/talos/commit/3def5f9a673ad2b57580ade483496c07d3945edc) feat: update etcd to 3.5.19\n* [`c3c0d2e42`](https://github.com/siderolabs/talos/commit/c3c0d2e42f3913b64463f13fb63a5e0a78bed627) test: fix dns test in race mode\n* [`17965c32f`](https://github.com/siderolabs/talos/commit/17965c32fa1f2e3b12cb2cf9ebd4550eb4dca672) chore: update Go to 1.24.1\n* [`1fbb2d1a7`](https://github.com/siderolabs/talos/commit/1fbb2d1a7cc658eedd8cdae2d0440324c709fe58) docs: update nvidia-gpu-proprietary.md\n* [`d60972bdf`](https://github.com/siderolabs/talos/commit/d60972bdf8c45f283e6e247b41053035eb6e1dbc) chore: add installer-base to the list of signed images\n* [`ab6cb3dfa`](https://github.com/siderolabs/talos/commit/ab6cb3dfa34a6a030a899cc0180b862c40c6fcb5) chore: disable azure upload\n* [`2355218e4`](https://github.com/siderolabs/talos/commit/2355218e4a24e8833d231bb08229ad2564046a45) release(v1.10.0-alpha.2): prepare release\n* [`d4e3e957c`](https://github.com/siderolabs/talos/commit/d4e3e957cb98d3fe6ee6685a807c25fafb128423) fix(ci): fix integration tests\n* [`1849b5388`](https://github.com/siderolabs/talos/commit/1849b53881e1ab12b28f9d8b537c8e43d607b4ea) feat: update dependencies\n* [`88fc6bbeb`](https://github.com/siderolabs/talos/commit/88fc6bbebeff1c0db0e43fb0a83d2b03a973da8a) test: fix UKI preserving talos.config and image cache\n* [`ba8cd304d`](https://github.com/siderolabs/talos/commit/ba8cd304d2029c93c31135b2003b1f2f064ff29f) test: enable image-cache in the cron\n* [`28b5dc738`](https://github.com/siderolabs/talos/commit/28b5dc738cd7af5bb06604b2778f808827544ee0) test: fix reproduciblity test\n* [`50998038b`](https://github.com/siderolabs/talos/commit/50998038bb45e33438cccdd8fba4c156f0f7b0b5) feat: prefer sd-boot for UEFI\n* [`e831e52e0`](https://github.com/siderolabs/talos/commit/e831e52e01a47f34e982e9cfa397ca9722094a82) feat: add support for qla2xx\n* [`ec5c049a5`](https://github.com/siderolabs/talos/commit/ec5c049a5a5063289a97271c2d145d298f5f1a43) feat: update Kubernetes to 1.33.0-alpha.2\n* [`ebfa82f35`](https://github.com/siderolabs/talos/commit/ebfa82f3558e5a44a332a0576416ce61f8235407) docs: update deprecated command\n* [`d79059a2c`](https://github.com/siderolabs/talos/commit/d79059a2c96565b1524b3869ad6b28f1cd8351da) chore: fix shutdown typo in shutdown sequence\n* [`a3f88d2ef`](https://github.com/siderolabs/talos/commit/a3f88d2ef5b726e1256a070a961bd4931d453a6a) fix: block NodePort services with ingress firewall\n* [`fd8131cb8`](https://github.com/siderolabs/talos/commit/fd8131cb86714b450334508abc0891eeaa2da9c8) feat: generate unified installer\n* [`ebfdb91b4`](https://github.com/siderolabs/talos/commit/ebfdb91b4cd36b48c36c1523dc74bc6e1860f815) fix: handle dynamic HTTP proxy settings for discovery client\n* [`d45eaeb74`](https://github.com/siderolabs/talos/commit/d45eaeb74cc43cc3154fcbce474958a613bc561b) fix: correctly map link names/aliases when using VIP operator\n* [`7c4e47c0c`](https://github.com/siderolabs/talos/commit/7c4e47c0c00e740bf0d63521baa1231354bc1966) chore: stop doing generate on each build\n* [`b1d410cb6`](https://github.com/siderolabs/talos/commit/b1d410cb6203f8a3847472db3990d2634bab22e2) feat: dual boot disk image\n* [`468e318ba`](https://github.com/siderolabs/talos/commit/468e318ba4137e1f11d231fe3ed66f10543073e3) fix: multiple fixes for dashboard/no data\n* [`3dd8d9aed`](https://github.com/siderolabs/talos/commit/3dd8d9aed8d311f84c61f3030fbf2031ee1d3df9) docs: update resetting-a-machine.md to include example of reset\n* [`7af8f6b2f`](https://github.com/siderolabs/talos/commit/7af8f6b2fa98f1ed4ad5adbcea6d54802013a086) feat: validate docker image references in upgrade options\n* [`c949f55e6`](https://github.com/siderolabs/talos/commit/c949f55e61b8c74202f2da50829c2e034e43682e) docs: remove typo on resetting a machine page\n* [`f5c097041`](https://github.com/siderolabs/talos/commit/f5c097041faac04808636703c94fe5d3ee208947) feat: add description to schema object defs\n* [`79ee304e1`](https://github.com/siderolabs/talos/commit/79ee304e11df7cfb2ccc6eeeb39ab6112975db45) chore: update enumer to a version that fixes Go 1.24 compatibility\n* [`46d67fe44`](https://github.com/siderolabs/talos/commit/46d67fe446edfabe23e3e8a91cc1f07436827c5e) chore: update Go to 1.24, update pkgs\n* [`7f1dd2669`](https://github.com/siderolabs/talos/commit/7f1dd2669734f496afbec6812a814d70dbaee3b4) fix(ci): fix integration-misc crons\n* [`26a773d3f`](https://github.com/siderolabs/talos/commit/26a773d3f27572a01d146ed356be5e78f8dc23e0) docs: add a note about syslog sending messages to services\n* [`7ce053638`](https://github.com/siderolabs/talos/commit/7ce053638db9c9abd4d966d412986c07615a750e) fix: ignore digest part of images when checking version\n* [`ae1b00354`](https://github.com/siderolabs/talos/commit/ae1b003542d01fc565a8478c9de512c3ea929f3d) feat: support noclooud instance-id from dmi\n* [`58661dea7`](https://github.com/siderolabs/talos/commit/58661dea71a706eaf57f9813b9672395e820e756) docs: update getting-started.md\n* [`94cf9fb84`](https://github.com/siderolabs/talos/commit/94cf9fb8470b88fac6523953ebb083ecf31e4274) chore: fix spurious generate failures\n* [`32a34791e`](https://github.com/siderolabs/talos/commit/32a34791e2e61e77531ccc8f8be92c76c4b83514) fix: typo in Makefile target talosctl-freebsd-arm64\n* [`1b4464c8a`](https://github.com/siderolabs/talos/commit/1b4464c8a65600b923d9790656f25e245db2e0aa) feat: update Kubernetes to 1.32.2\n* [`9463ac23e`](https://github.com/siderolabs/talos/commit/9463ac23e77067f6dce2c22a33e3937357745303) fix: make ingress firewall filter traffic to nodeports\n* [`8531d91a1`](https://github.com/siderolabs/talos/commit/8531d91a1f20ecc587a1b76c13637ab3555718e9) fix: blockdevice transport detection\n* [`ce616d93a`](https://github.com/siderolabs/talos/commit/ce616d93a5799163ae278bac477c4f612197d109) fix: path for ca-certificates\n* [`f35b58779`](https://github.com/siderolabs/talos/commit/f35b58779e912aeec64e6fc0a9964e76e97f9a9f) fix: fix diff printing\n* [`bf0f910a1`](https://github.com/siderolabs/talos/commit/bf0f910a16ce3707cc5741b88a176671a0dd40b3) chore: provide more logging for dns requests\n* [`607998ba2`](https://github.com/siderolabs/talos/commit/607998ba20d62fa13233daf139eb3126ffa6569f) feat: support uki profiles via imager\n* [`711cf2d99`](https://github.com/siderolabs/talos/commit/711cf2d99ac9c16b7a48c20271ecc2c60a3f3d6d) fix: ignore errors to stop pods\n* [`142d75483`](https://github.com/siderolabs/talos/commit/142d754835785cd4edf088e2827854ffc8580262) fix: handle empty registry config\n* [`47f377b21`](https://github.com/siderolabs/talos/commit/47f377b21f546f1950ed43171d6b4f374ab7f721) feat: implement the last ethtool feature - channels\n* [`88cf69b8c`](https://github.com/siderolabs/talos/commit/88cf69b8c5c5f9fd47107289a717f1083ae12807) feat: multi profile UKIs\n* [`557faad75`](https://github.com/siderolabs/talos/commit/557faad759e4f21b7dedc3c69a61d2b3c31e6bc4) feat: update Linux to 6.12.13\n* [`5dbf9e350`](https://github.com/siderolabs/talos/commit/5dbf9e35024192632aecda5fd817ab4558aced1a) refactor: implement volume mount controller\n* [`aa11e9abb`](https://github.com/siderolabs/talos/commit/aa11e9abb78d33ba66a167335b14fc79f4613ef9) fix: make image cache volume management less strict\n* [`26a62e342`](https://github.com/siderolabs/talos/commit/26a62e34211d642ddcdb0cff67013c0d4c640b78) docs: fix typo in Wireguard docs\n* [`0419f5d8b`](https://github.com/siderolabs/talos/commit/0419f5d8ba889faead5452af40fc70c8e1573084) feat: implement features in `ethtool`-like support\n* [`cd66fc6e8`](https://github.com/siderolabs/talos/commit/cd66fc6e8e7e5cf1a17c03de41c1d2e39cb71aa4) feat: use bootstrapped packages for building Talos\n* [`2b5bd5d1d`](https://github.com/siderolabs/talos/commit/2b5bd5d1dad65f653dfd77d363d0a76404099453) chore: upgrade siderolabs/go-loadbalancer\n* [`15191aa3e`](https://github.com/siderolabs/talos/commit/15191aa3e305feba6b5f8b084e6d9b7337e2143f) fix: extract cmdline multi profile UKIs\n* [`716f700da`](https://github.com/siderolabs/talos/commit/716f700da74608aa93c9d335ea17f0fea34865a6) feat: provide initial support for ethtool configuration\n* [`b726e2f9f`](https://github.com/siderolabs/talos/commit/b726e2f9f7057f1e7ed912bea28db3e4b63441cb) feat: update Flannel to 0.26.4\n* [`98d56d4d6`](https://github.com/siderolabs/talos/commit/98d56d4d647d455acc7324d84df05881ebe46d34) chore: track opened grpc connections\n* [`5e28c8e03`](https://github.com/siderolabs/talos/commit/5e28c8e039aae14427571bdd9bf9813ee6220743) fix: image cache volume provisioning\n* [`c9667813d`](https://github.com/siderolabs/talos/commit/c9667813d2b515306a775dabbefad378dc74a0a9) chore: remove containerd importer\n* [`270ffb69a`](https://github.com/siderolabs/talos/commit/270ffb69a39a9b10e3d98c44579eec20de51ba67) fix: duplicate qemu drive ids\n* [`71ec41be1`](https://github.com/siderolabs/talos/commit/71ec41be18541c31e887037bad59a7a3395a2bb1) fix: build of Talos on non-Linux host\n* [`e2aa7c98c`](https://github.com/siderolabs/talos/commit/e2aa7c98ccebca727cac792e53db5722aa79e213) fix: installer with SecureBoot should contain UKIs\n* [`6e22c06c3`](https://github.com/siderolabs/talos/commit/6e22c06c3c4c96bb02d34c7f61633137cd03f6f5) release(v1.10.0-alpha.1): prepare release\n* [`3a2d9867b`](https://github.com/siderolabs/talos/commit/3a2d9867b5cc3236b1d1c7981e5794657f3c155e) fix: do not close client.Client.conn with finalizer\n* [`73f30ff25`](https://github.com/siderolabs/talos/commit/73f30ff25e0adb7a47e2153756e0ea94bd605568) feat: bump pkgs for udev update\n* [`aea90cb8f`](https://github.com/siderolabs/talos/commit/aea90cb8f1dbe7d5f67d35714825133728c1490d) docs: update hyper-v\n* [`b7165615f`](https://github.com/siderolabs/talos/commit/b7165615f86afd09ea85dc91090a40860ae6fc9a) fix: use local NTP for AWS platform\n* [`673ca4bcb`](https://github.com/siderolabs/talos/commit/673ca4bcb2448b3c252fccff0d243932c97fd893) fix: ensure proper closure of client.Client.conn with finalizer\n* [`19040ffd6`](https://github.com/siderolabs/talos/commit/19040ffd6ef128daaf48a820d8826186c82c68c5) fix: handle of PE sections with duplicate names\n* [`83489d348`](https://github.com/siderolabs/talos/commit/83489d348905352497da0f6dc042f3e7f05cd4d7) docs: add note about vmxnet and flannel conflict\n* [`f1292f5e7`](https://github.com/siderolabs/talos/commit/f1292f5e7af4110270475d8bcc4bd39519419e03) docs: add iscsi-tools extension to prerequisites\n* [`93b4a3740`](https://github.com/siderolabs/talos/commit/93b4a3740ba0c35e8b62cbf8c70058d1e53c3b8e) test: bump timeout on rotate CA test\n* [`42e166984`](https://github.com/siderolabs/talos/commit/42e16698453a687a4293e7cfeeb0e09d4f084217) feat: support kexec from uki\n* [`8da264946`](https://github.com/siderolabs/talos/commit/8da264946cda9b4803fd9f2f4dfd0ed25445843b) docs: add Orange Pi 5 to Image Factory platforms and documentation\n* [`c5fb62e2e`](https://github.com/siderolabs/talos/commit/c5fb62e2e32690aa0235b0911ded1888084496a8) feat: update Linux to 6.2.11\n* [`83d007c16`](https://github.com/siderolabs/talos/commit/83d007c161e03311cede2153f35c32f608537290) feat: update etcd to 3.5.18\n* [`edf7c3288`](https://github.com/siderolabs/talos/commit/edf7c328835273e2bc6dd23c646091e6a03aa2e9) fix: pe uki extract\n* [`70f72c5b0`](https://github.com/siderolabs/talos/commit/70f72c5b00bce791d692ec3a0e9a91aaf9d88031) docs: update multus.md\n* [`807a3cd29`](https://github.com/siderolabs/talos/commit/807a3cd291e2e2cb22946826bccb64671a29d901) refactor: all network merge controllers\n* [`ec8c4660e`](https://github.com/siderolabs/talos/commit/ec8c4660e277dc11b5e70c014a0238d48cf15bda) docs: update vmware.md\n* [`baf81cd49`](https://github.com/siderolabs/talos/commit/baf81cd4914470b06393d762f70d0a94f7a9fe32) fix(ci): k8s integration suite wait for resource\n* [`cd5e54903`](https://github.com/siderolabs/talos/commit/cd5e549039b17add0a2ce09713e1a034bb3efccf) feat: generate iso's with both UKI and grub\n* [`75673b6a3`](https://github.com/siderolabs/talos/commit/75673b6a38eeb6361c6e6aeb389e8dbaaacb8b0b) feat: provide stable symlinks in disk resources\n* [`f407c88e4`](https://github.com/siderolabs/talos/commit/f407c88e4678ff6d5edb940f5d54461104be3643) fix(ci): wait for longhorn node resource\n* [`601cdccb9`](https://github.com/siderolabs/talos/commit/601cdccb979640a6b2ffcba41cc698015b1dacde) feat: extract kernel/initrd from uki for grub\n* [`ff175b9fb`](https://github.com/siderolabs/talos/commit/ff175b9fbdb2ac92ac53351d32de130bd0676038) docs: update disk-encryption.md\n* [`a8d84e315`](https://github.com/siderolabs/talos/commit/a8d84e3155137a114ad00ad7ae321af033020e7d) docs: fix typos and add more explanations in docs\n* [`3a384240e`](https://github.com/siderolabs/talos/commit/3a384240ecf660d310f2df98327f018649ebaa6d) fix: invalid date field in iqn/nqn\n* [`82c9ec158`](https://github.com/siderolabs/talos/commit/82c9ec158e82efea80daaf76fef9fbd31c3eb823) chore(ci): add tests with longhorn v2 engine\n* [`689ea1dbf`](https://github.com/siderolabs/talos/commit/689ea1dbfe29d70d91e0b41d31fc696e2ff96665) fix: bring back disk UUID\n* [`7a712fad2`](https://github.com/siderolabs/talos/commit/7a712fad2abb916f397a8dd0aebf66e59ee75904) fix: disks with 4k sector size and systemd-boot\n* [`d62a34aaf`](https://github.com/siderolabs/talos/commit/d62a34aaf4e4ff7dad9f6dbeb59a67016c70fffb) feat: update tools/pkgs/extras\n* [`b9a8ad6ac`](https://github.com/siderolabs/talos/commit/b9a8ad6acafd64c4217ba914184592c0cfb97962) chore: de-hardcode list of extra images for image-cache test\n* [`683153a33`](https://github.com/siderolabs/talos/commit/683153a33c1069e7f7cadf4e3a70bde3f8ba3331) docs: remove the last mentions of `preserve` flag for Talos 1.8+\n* [`33c7f4195`](https://github.com/siderolabs/talos/commit/33c7f4195816988af6f70199fdb4a31d027fa746) docs: fix typo an MacOS to on MacOS\n* [`21cff3919`](https://github.com/siderolabs/talos/commit/21cff3919b80f33f837b19728500fcb91e7caf8f) chore(ci): fio benchmark results as separate artifacts\n* [`0b7fc7cdf`](https://github.com/siderolabs/talos/commit/0b7fc7cdfea651a6f16db3f346473505d8df3e78) fix: abort node watch on hostname change\n* [`99ba53941`](https://github.com/siderolabs/talos/commit/99ba53941cecdc54c0ececa9876b25a7fc7668a5) docs: remove the mention of `preserve` flag for Talos 1.8+\n* [`bde516fde`](https://github.com/siderolabs/talos/commit/bde516fde62a25dd60691a9a3b6f3d30de11dad1) chore(ci): rework iscsi-tools extensions test\n* [`e1efbf656`](https://github.com/siderolabs/talos/commit/e1efbf656ae96ecedba1c132608c3ad2d3ae4a66) refactor: extract platform metadata into Talos machinery\n* [`79987c05d`](https://github.com/siderolabs/talos/commit/79987c05dcd39ca646c2d73c1e25488504f13a60) feat: generate iqn and nqn files\n* [`0cab6ed17`](https://github.com/siderolabs/talos/commit/0cab6ed170708549d69c04b163744854de0aa8f2) docs: update troubleshooting.md\n* [`921e10254`](https://github.com/siderolabs/talos/commit/921e10254d443c459a9775368ca080ecba273321) chore: update Go to 1.23.5\n* [`399d53b54`](https://github.com/siderolabs/talos/commit/399d53b543f6ca99f13d28313ae77b3472b0f728) fix: ignore forbidden error when waiting for pod eviction\n* [`8dea57a81`](https://github.com/siderolabs/talos/commit/8dea57a81b8393b518da60951713c711659291f9) fix: make etc binds read-only\n* [`63157dcb4`](https://github.com/siderolabs/talos/commit/63157dcb496ca767bfbff9e1b86f14277a44cdb7) docs: update SideroLinkConfig example\n* [`fc7080e34`](https://github.com/siderolabs/talos/commit/fc7080e34b990d2d50ec1e40734437ccd0ee95f7) chore: clear cache after updating upstreams\n* [`51e0f273f`](https://github.com/siderolabs/talos/commit/51e0f273f9199b8320cd5da247c702a4319a92c5) docs: update documentation for Talos 1.9.2\n* [`e06b14112`](https://github.com/siderolabs/talos/commit/e06b14112d2c978e3f6b5c4446090a7ae533ead9) feat: update Kubernetes to 1.32.1\n* [`4310b290d`](https://github.com/siderolabs/talos/commit/4310b290d5cff9697f86cc24f1c281e62cb7d72f) fix: generate UKI only if actually needed\n* [`a8cd99102`](https://github.com/siderolabs/talos/commit/a8cd991026fe7290013b7504a4e87af46c49d25b) docs: update OpenEBS Mayastor installation\n* [`cf45f4764`](https://github.com/siderolabs/talos/commit/cf45f4764ddd979fa81576833d9630eadea24f41) docs: add Radxa ROCK 5B docs to Single Board Computer section\n* [`b21bdc5e5`](https://github.com/siderolabs/talos/commit/b21bdc5e501bc2244e3e487827ffba79075f6642) chore(ci): save csi tests fio results\n* [`01c86832c`](https://github.com/siderolabs/talos/commit/01c86832cbbbe0b81b9500032f94298fd6e90b58) chore(ci): add test for OpenEBS MayaStor\n* [`c77483510`](https://github.com/siderolabs/talos/commit/c774835103ad139b44d7e4e13c003e2b13160347) test: update `talosctl debug air-gapped`\n* [`ddd695d93`](https://github.com/siderolabs/talos/commit/ddd695d933d39920da42219ba8b3d39b0681a3ea) feat: update containerd to 2.0.2\n* [`da2e81120`](https://github.com/siderolabs/talos/commit/da2e81120f7336d9633a98523e05d91f5750434f) fix: add informer resync period for node status watcher\n* [`9b957df64`](https://github.com/siderolabs/talos/commit/9b957df64680a97a16575db67d4af27cfc0ef7d2) chore: uki code restructure\n* [`e41a99525`](https://github.com/siderolabs/talos/commit/e41a995253428dde437eecec52cabfb4c80f90ea) fix: kube-apiserver authorizers order\n* [`db4ca5668`](https://github.com/siderolabs/talos/commit/db4ca5668ac0d85a98a5ea022f6546526d20aff1) feat: add a kernel parameter to disable built-in auditd\n* [`faa149003`](https://github.com/siderolabs/talos/commit/faa1490033df0a843010fa7154096d84f415afce) feat: update Linux to 6.12.9\n* [`8de19758d`](https://github.com/siderolabs/talos/commit/8de19758dafce802c0f93a63ae3083b5ad17162d) fix: a couple of imager panics/crashes\n* [`5bc3e34cb`](https://github.com/siderolabs/talos/commit/5bc3e34cb3a6fd8e3eb5d02dd612cf3cf9dc499f) fix: detect GPT before ZFS\n* [`ed7e47d15`](https://github.com/siderolabs/talos/commit/ed7e47d158e064204b2f14f9ff378bea70e9524e) refactor: drop usage of objcopy to generate UKIs\n* [`edf5c5e29`](https://github.com/siderolabs/talos/commit/edf5c5e29bc76299c63bb04f1d97a030ecb9b3f0) fix: extfs repair and resize\n* [`6e32ea5b7`](https://github.com/siderolabs/talos/commit/6e32ea5b7f1a22500014ecb365e13af36034187a) fix: merge of VolumeConfig documents with sizes\n* [`1be5f8ff2`](https://github.com/siderolabs/talos/commit/1be5f8ff25ac7042ee3334f657d6604ec5f8501d) feat: update Linux to 6.12.8\n* [`e6a4583ba`](https://github.com/siderolabs/talos/commit/e6a4583ba862da9f49ab0bd0cb6bc8436723bc67) feat: support generating unsigned UKIs\n* [`bbd6067d4`](https://github.com/siderolabs/talos/commit/bbd6067d426fb2be22ff8935f415ab6d729d8f19) fix: partition alignment on disks with 4k sectors\n* [`84fcc976f`](https://github.com/siderolabs/talos/commit/84fcc976f8da5af310771e1835a0347df5bcc97d) fix: yet another dashboard panic\n* [`6d605fc85`](https://github.com/siderolabs/talos/commit/6d605fc8595e2f06e43529966e396f2ae403c76c) fix: disable NRI plugin in a different way\n* [`499695e24`](https://github.com/siderolabs/talos/commit/499695e24ea02ffc2fd8c92276d5de41b0d4919e) fix: request previous IP address in discovery\n* [`cc84caf8c`](https://github.com/siderolabs/talos/commit/cc84caf8c0dffd9d59f360f84967c524be9ba369) docs: update Cilium documentation\n* [`fa5300d91`](https://github.com/siderolabs/talos/commit/fa5300d910a537f03939fcbf6362abdd8fa607dd) chore: revert: drop deprecated allowSchedulingOnMasters\n* [`0abb3dabf`](https://github.com/siderolabs/talos/commit/0abb3dabf6d50b9c1176af683ad74234334f822d) docs: fix command to wait for ceph-rook HEALTH_OK\n* [`32c67c27c`](https://github.com/siderolabs/talos/commit/32c67c27c393c989f9d70ccb8506c4735f70d494) chore: drop deprecated allowSchedulingOnMasters\n* [`ae6d065be`](https://github.com/siderolabs/talos/commit/ae6d065beb4897a1b877ecb30b06be456befbf91) fix: mount selinuxfs only when SELinux is enabled\n* [`5ccbf4bcd`](https://github.com/siderolabs/talos/commit/5ccbf4bcdbe9aa2096320d17eb2deab6a062faf9) feat: enable `configfs`\n* [`59582496d`](https://github.com/siderolabs/talos/commit/59582496d5fe419f833703be8e956163b6241d15) feat: bring in partity with sd-257\n* [`83d84a831`](https://github.com/siderolabs/talos/commit/83d84a831862c774b9bc2adc2e11e00bf2a79912) chore(ci): better zfs checks\n* [`650eb3a4f`](https://github.com/siderolabs/talos/commit/650eb3a4f2d89d173cdd6581a6d1232511a8e219) refactor: rewrite cloud uploader to use AWS SDK Go v2\n* [`01bf8449b`](https://github.com/siderolabs/talos/commit/01bf8449b917ece76336ca7f0eb11fd877195025) fix: update field name for bus path disk selector\n* [`e915c98d5`](https://github.com/siderolabs/talos/commit/e915c98d583e5901c1c2efe38efa656b39d72360) fix: exclude disks with empty transport for disk selector\n* [`b7a7fdc4b`](https://github.com/siderolabs/talos/commit/b7a7fdc4b8a715157bfa2614c9541b96643cd2ba) refactor: generate /etc/os-release file static way\n* [`e79c9e127`](https://github.com/siderolabs/talos/commit/e79c9e12772c998ff5b3e401efd7f074f85e5cef) chore(ci): drop equinix metal e2e-test\n* [`418945444`](https://github.com/siderolabs/talos/commit/418945444135c6d9e2e5960e7b9cbd754084fea2) fix: build of talosctl on non-Linux platforms\n* [`4761a9e6a`](https://github.com/siderolabs/talos/commit/4761a9e6aa0bf619a564807d02ebce030384d6a1) chore: update dependencies\n* [`f98efb333`](https://github.com/siderolabs/talos/commit/f98efb333f89b8493c55b91698c917437b7af310) fix: ignore member not found error on leave cluster\n* [`b72bda0a4`](https://github.com/siderolabs/talos/commit/b72bda0a420f75ea0439cc0240dcf6d3363e5d48) fix: talosctl support and race tests\n* [`27233cf0f`](https://github.com/siderolabs/talos/commit/27233cf0fcf4031cbc8001504bed67b6d4a104f9) test: use node informer instead of raw watch\n* [`5dc15e8db`](https://github.com/siderolabs/talos/commit/5dc15e8db459ac632f0ae106e1cfc7eaab672adf) fix: update go-blockdevice to v2.0.9\n* [`5f3acd0f2`](https://github.com/siderolabs/talos/commit/5f3acd0f26a35ac966d4ced01436f1dd3c03648b) fix: use correct default search domain\n* [`7e5d36d46`](https://github.com/siderolabs/talos/commit/7e5d36d469ff01153f40b16ab722f0ebe25d41ae) fix: pci driver rebind config validation\n* [`4b97bbc3f`](https://github.com/siderolabs/talos/commit/4b97bbc3fee1257d0d21be25e21493bfd1f45a80) fix: pull in containerd CNI deadlock fix\n* [`066480722`](https://github.com/siderolabs/talos/commit/0664807229e0688f092a453cbd3121dbe189ca39) test: fix apparmor tests\n* [`82ea44a6b`](https://github.com/siderolabs/talos/commit/82ea44a6b2aa0a35861ca454a09503a81332f824) fix: reduce installer image\n* [`78b3e7f4f`](https://github.com/siderolabs/talos/commit/78b3e7f4f1870085b719971c6f92dc866fe1e9d0) fix: get next rule number for IPv6 in the appropriate chain\n* [`675854aa0`](https://github.com/siderolabs/talos/commit/675854aa03b3913da3481337d995c206174cf004) docs: fix two typos\n* [`f70b7386a`](https://github.com/siderolabs/talos/commit/f70b7386ac3125f3b8ab6b1765338c7e3445ae5c) test: add a xfs makefs test\n* [`8212e4864`](https://github.com/siderolabs/talos/commit/8212e4864d11e69ed63be3f4e608e9ccbc788cc4) refactor: use quirks in kernel args\n* [`b4aa5189d`](https://github.com/siderolabs/talos/commit/b4aa5189d4d4565a42ad7ac8de24c424a215b42f) release(v1.10.0-alpha.0): prepare release\n* [`bd85bd5b7`](https://github.com/siderolabs/talos/commit/bd85bd5b731463a42b7c82c66e9add251a280d26) fix: fix `Failed to initialize SELinux labeling handle` udev error\n* [`73c82e3e5`](https://github.com/siderolabs/talos/commit/73c82e3e5625ec1899f93312a671dfe6dffaea61) feat: bring Linux 6.12.6, CNI plugins 1.6.1\n* [`c12b52491`](https://github.com/siderolabs/talos/commit/c12b52491456d1e52204eb290d0686a317358c7c) docs: document Kubernetes service registry incompat with K8s 1.32\n* [`a5660ed77`](https://github.com/siderolabs/talos/commit/a5660ed778108843fe15b2b1582dd6556cf52b6c) feat: pcirebind controller\n* [`4c3261626`](https://github.com/siderolabs/talos/commit/4c3261626fa3f5ac36df71ec878f103a7c85c5c5) docs: fix several typos\n* [`fb3675321`](https://github.com/siderolabs/talos/commit/fb36753216cba7740040f2ec117c783221f66192) fix: dashboard crash on CPU data\n* [`dec0185c8`](https://github.com/siderolabs/talos/commit/dec0185c8505a7d43244fdb01f7a5decc77d116d) chore: reduce memory usage for secureboot functions\n* [`cee6c60a0`](https://github.com/siderolabs/talos/commit/cee6c60a0fc301b22c50fdf8bd2fc1d2b7ba3d54) fix: make talosctl time work with PTP time sync\n* [`f75604313`](https://github.com/siderolabs/talos/commit/f75604313d535180c38b33df53253ad4acba2ec1) chore: support gcr.io auth for cache and image gen\n* [`6ef2596da`](https://github.com/siderolabs/talos/commit/6ef2596da7b7e8be90e5b981621461352be7b134) docs: improve Hetzner documentation\n* [`7d39b9ec2`](https://github.com/siderolabs/talos/commit/7d39b9ec2bdd7883116626bf889c1331717f8438) feat: remove cgroupsv1 in non-container mode\n* [`8003536c7`](https://github.com/siderolabs/talos/commit/8003536c7ca20356adcd900e64463bd166d445af) fix: restore previous disk serial fetching\n* [`03116ef9b`](https://github.com/siderolabs/talos/commit/03116ef9bd2a215c20a2c4c7db133dd857ce2b16) chore: prepare for Talos 1.10\n* [`00682fdd6`](https://github.com/siderolabs/talos/commit/00682fdd6e8fa23c6f9782840ea3e2b8ef250f66) docs: activate 1.9 docs as default\n* [`bea05f5c9`](https://github.com/siderolabs/talos/commit/bea05f5c9b6ce6f5d067eb357d26e30a49154b21) docs: update deploying-cilium.md\n* [`284ab1179`](https://github.com/siderolabs/talos/commit/284ab11794b3b076aa9ab2bb756e02292d854751) feat: support link altnames/aliases\n* [`5bfd829bf`](https://github.com/siderolabs/talos/commit/5bfd829bf9c8e46b6c51174be4b764d4c94b3320) docs: fix 'containter' typo\n* [`8d151b771`](https://github.com/siderolabs/talos/commit/8d151b771debc51d3fa40dfafc7a2e43f955a634) docs: clarify TALOSCONFIG for AWS\n* [`0ef19171f`](https://github.com/siderolabs/talos/commit/0ef19171f738e46346dfae71f43b8f7b47bf257d) fix: renovate typo\n* [`c568adc7d`](https://github.com/siderolabs/talos/commit/c568adc7dcd52c34924acc1eae849a2ca5b5a4d5) fix: renovate config\n* [`ec2e24fd9`](https://github.com/siderolabs/talos/commit/ec2e24fd9617db34e3bec753b5fe720670fa31a4) fix: match MAC addresses case-insensitive (nocloud)\n* [`41a0c440a`](https://github.com/siderolabs/talos/commit/41a0c440ad3f4de2a2ba9198d22609c55bdaf61b) chore: rekres for renovate changes\n* [`a49bb9ee4`](https://github.com/siderolabs/talos/commit/a49bb9ee45346268b26d3b9cff4dd017bfb9c829) feat: update Linux to 6.12.5\n* [`b15917ecc`](https://github.com/siderolabs/talos/commit/b15917ecc626781e13de0e84b794ab77c97b3159) chore: add more debugging logs for META and volumes\n* [`2b1b326f0`](https://github.com/siderolabs/talos/commit/2b1b326f08966615a5a2f8708f94e6d1355773a7) docs: mention different paths for OpenEBS\n* [`9470e842f`](https://github.com/siderolabs/talos/commit/9470e842fca2d7dd0dae185bff7210a8af355445) test: cleanup failed Kubernetes pods\n* [`c9c685150`](https://github.com/siderolabs/talos/commit/c9c6851504fcda7b66395fbbba1fbc8b0e085d4a) fix: node identity flip\n* [`590c01657`](https://github.com/siderolabs/talos/commit/590c0165712aee60e752766d6bd3875443c353cb) feat: update containerd to v2.0.1\n* [`18fa5a258`](https://github.com/siderolabs/talos/commit/18fa5a25876f41760ce8da5e918222e04b81949a) docs: update image-cache doc for iso\n* [`ab5bb6884`](https://github.com/siderolabs/talos/commit/ab5bb688420986a356aed55513a1dbd25de323e2) fix: generate and serve registries with port\n* [`58236066d`](https://github.com/siderolabs/talos/commit/58236066ddbcd7c401e945b70555ff315a2458f7) fix: support image cache on VFAT USB stick\n* [`e193a5071`](https://github.com/siderolabs/talos/commit/e193a507149c05e341abe019de219fe0b1bc83e3) fix: image cache integration test\n* [`08ee400fd`](https://github.com/siderolabs/talos/commit/08ee400fdbde368a54d6777cc31ceb91e1968ad2) test: fix flaky test NodeAddressSort\n* [`d45e8d1d1`](https://github.com/siderolabs/talos/commit/d45e8d1d1da28ca1b311198588d723cb491527eb) feat: update Kubernetes to 1.32.0\n* [`136b12912`](https://github.com/siderolabs/talos/commit/136b12912165d5eb5c7c716b7f7dfcfbc42b08d4) chore: drop semicolon for supporting vfat filesystems\n* [`3e9e027ef`](https://github.com/siderolabs/talos/commit/3e9e027efbd2988f72eb2da0c1ab0e83ba52b950) test: add an option to boot from an USB stick\n* [`ef8c3e3b3`](https://github.com/siderolabs/talos/commit/ef8c3e3b3b245f7ffefa6c19930d5a0925ce666b) docs: fix typo in multus.md\n* [`d54414add`](https://github.com/siderolabs/talos/commit/d54414add4e4df1b5a7b166f155cdcca512d4ee2) fix: authorization config gen\n* [`cce72cfe8`](https://github.com/siderolabs/talos/commit/cce72cfe86beeb7ada9641df611046f4789e3bd8) docs: replace deprecated Hetzner server plans\n* [`81805103d`](https://github.com/siderolabs/talos/commit/81805103deada24b12b7d7861b2df5a5c788c86b) chore: enable proper parallel usage of TestDepth\n* [`e1b824eba`](https://github.com/siderolabs/talos/commit/e1b824ebada3d3dad9d2793fd12b5a948d8b51b5) docs: update ceph-with-rook.md\n* [`470b75563`](https://github.com/siderolabs/talos/commit/470b75563add4ce5bbce312c1e3dc783e63af1fa) fix: use mtu network option for podman\n* [`61b1489a0`](https://github.com/siderolabs/talos/commit/61b1489a0f0868c5b7e124544520bc46badef85c) fix: order volume config by the requested size\n* [`bc3039acd`](https://github.com/siderolabs/talos/commit/bc3039acdbc57e6be16a1bc6555894dff2da65c9) feat: update runc to 1.2.3\n* [`30016a0a8`](https://github.com/siderolabs/talos/commit/30016a0a8d98d42e01c4d32acf9e600777d72d57) fix: avoid nil-pointer-panic in `RegistriesConfigController`\n* [`fe0457152`](https://github.com/siderolabs/talos/commit/fe045715277a4678b8e8c9632ec71e86bf17ace0) fix: power on the machine on reboot request in qemu power api\n* [`10da553ef`](https://github.com/siderolabs/talos/commit/10da553ef0dde5f87f09321400239baa51929a36) docs: build what's new for 1.9\n* [`d946ccae3`](https://github.com/siderolabs/talos/commit/d946ccae31b87559a06cb1cefcefe8f937b73d8b) feat: update Linux to 6.12.4\n* [`707a77bf6`](https://github.com/siderolabs/talos/commit/707a77bf64190470bf84c91cdff185981e80a31b) test: fix user namespace test, TPM2 fixes\n* [`c3537b2f5`](https://github.com/siderolabs/talos/commit/c3537b2f5491a890f626ba8fc47034d5059808af) feat: update Linux to 6.12.3\n* [`cb4d9d673`](https://github.com/siderolabs/talos/commit/cb4d9d673432e4a0fba0d87bc64fde620d991082) docs: fix a few mistakes in release notes\n* [`c4724fc97`](https://github.com/siderolabs/talos/commit/c4724fc97598d8764b00fb56971d997a349a92e5) chore: add integration tests for image-cache\n* [`07220fe7f`](https://github.com/siderolabs/talos/commit/07220fe7f5a22444f7a085f5868f628ddd912b6d) fix: install iptables-nft to the host\n* [`14841750b`](https://github.com/siderolabs/talos/commit/14841750bf2fc09a9de0b32a7af0dc3f76e1019a) chore: add version compatibility for Talos 1.10\n* [`852baf819`](https://github.com/siderolabs/talos/commit/852baf819d453a3d8d58ae9f029e280ae75e0cb1) feat: support vlan/bond in v1, vlan in v2 for nocloud\n* [`dd61ad861`](https://github.com/siderolabs/talos/commit/dd61ad86105c07c1ff8a101a0542af61699f0df3) fix: lock provisioning order of user disk partitions\n* [`d0773ff09`](https://github.com/siderolabs/talos/commit/d0773ff09df84b2dac8ecadc91023596050ce098) chore: update Go to 1.23.4\n* [`7d6507189`](https://github.com/siderolabs/talos/commit/7d6507189ff9a99b3b05ee9528701b65af4ad147) feat: implement new address sorting algorithm\n* [`9081506d6`](https://github.com/siderolabs/talos/commit/9081506d6cde26d60a29f08a090e28da501e4bd1) feat: add process scheduling options\n* [`77e9db4ab`](https://github.com/siderolabs/talos/commit/77e9db4abf9c9b694d60c8803b436121dfe30ccd) test: use two workers in qemu tests by default\n* [`5a4bdf62a`](https://github.com/siderolabs/talos/commit/5a4bdf62a9bf1387b6489eaf2c9cc0770aa0b68c) feat: update Kubernetes to 1.32.0-rc.1\n* [`d99bcc950`](https://github.com/siderolabs/talos/commit/d99bcc95031037f4b0990419d2ce1fd4280cbde9) chore: refactor mergeDNSServers func\n* [`0cde08d8b`](https://github.com/siderolabs/talos/commit/0cde08d8be1ad62c49fed148fd331ea5a212df4c) docs: add Turing RK1 docs to Single Board Computer section\n</p>\n</details>\n\n### Changes since v1.10.0-alpha.2\n<details><summary>49 commits</summary>\n<p>\n\n* [`a834219ac`](https://github.com/siderolabs/talos/commit/a834219ace76663e13bfc0cd5e59b19f32b63ac7) chore: update dependencies\n* [`857779b90`](https://github.com/siderolabs/talos/commit/857779b902ca8c235eb42988b0a8a17c0de2ac21) docs: clarify custom CA certificate with KMS STATE encryption\n* [`39ed45ae6`](https://github.com/siderolabs/talos/commit/39ed45ae61f8ff6a7d7475b87b9d4ff61377be8b) docs: add information about Cilium exclusive CNI\n* [`087a85f40`](https://github.com/siderolabs/talos/commit/087a85f40920e84344451959dbd570b3d1d77a99) feat: support running with SELinux enforcing\n* [`d4aacb0d8`](https://github.com/siderolabs/talos/commit/d4aacb0d85c239f5960a4ff223b28f387a1023ef) refactor: mount operation for STATE and user disks\n* [`44f3c7248`](https://github.com/siderolabs/talos/commit/44f3c72489350aab64eef67f7d803853819d3a74) fix: kata extension\n* [`7ca5ab5e9`](https://github.com/siderolabs/talos/commit/7ca5ab5e933f1cd28fb74c24ae2a0f00030b763b) fix: shrink installer and imager images\n* [`ea0994cfe`](https://github.com/siderolabs/talos/commit/ea0994cfef497412fecd3c345c03f70b1ebd62b9) fix: kexec with smbios type 11 string\n* [`8e20a5d28`](https://github.com/siderolabs/talos/commit/8e20a5d280523279b3039ea02f5c30137087b3b5) fix: pass /usr/etc/in-container to apid, trustd and extension containers\n* [`9b9512ba8`](https://github.com/siderolabs/talos/commit/9b9512ba88e0f2ebd78b72f4abdccb3f46f9320b) feat: update Linux 6.12.19, containerd 2.0.4\n* [`433b0237b`](https://github.com/siderolabs/talos/commit/433b0237bd11ac57aac8d6b8980337d37383c33d) fix: correct structprotogen example\n* [`6e68a522a`](https://github.com/siderolabs/talos/commit/6e68a522ab4303c316f6039e4beaaa7ea20a63f9) chore: fix conformance artifact name\n* [`f592730d9`](https://github.com/siderolabs/talos/commit/f592730d9db79b4d8a0823389dc35fce5c668920) fix(ci): fix image cache test\n* [`cc6c714ce`](https://github.com/siderolabs/talos/commit/cc6c714ce5fb7359028ecd4ef43c8bb0935250ae) feat: add Tegra modules to initrd\n* [`81d1fe0f8`](https://github.com/siderolabs/talos/commit/81d1fe0f807210346d59303ef05d30a1c5e53d02) fix: add missing TOOLS_PREFIX for WITH_DEBUG_SHELL builds\n* [`3e38bf6d4`](https://github.com/siderolabs/talos/commit/3e38bf6d44b6ea0abd065f7883b5320845a9d12e) fix: ignore missing config (nocloud) via cidata\n* [`27a4486a8`](https://github.com/siderolabs/talos/commit/27a4486a82151e3c28fe7f23521e3e3e7a5bf287) docs: fix typo cluser -> cluster\n* [`ac79b1ea0`](https://github.com/siderolabs/talos/commit/ac79b1ea0c033012ed3dd5a84190fb07de431c1c) feat: pull in Intel STTMAC network drivers\n* [`9bb5c060c`](https://github.com/siderolabs/talos/commit/9bb5c060c160ec2e1449f30c6ba85b92a50c1a9b) chore: bump go-kubernetes\n* [`2b8e08234`](https://github.com/siderolabs/talos/commit/2b8e082344d3bb62c3f5d83b9dc9edbe4f7fede8) feat: deprecate `.machine.install.extensions`\n* [`b7446372b`](https://github.com/siderolabs/talos/commit/b7446372b62152c235c30823b12a9e2df7a111a3) docs: add documentation on unofficial SBC forks\n* [`9bec765c4`](https://github.com/siderolabs/talos/commit/9bec765c41e49d872de29956cdae50ea7cd89d8a) feat: talosctl kubeconfig write to stdout option\n* [`11ebb1078`](https://github.com/siderolabs/talos/commit/11ebb107853a21d626d2c80a88f33bdc5df52641) fix: kexec when using sd-boot\n* [`61f1a32d2`](https://github.com/siderolabs/talos/commit/61f1a32d24be8a4d73f48d02fbd6281208bdf7ac) test: allocate more resources for conformance runs\n* [`b8b7b83f8`](https://github.com/siderolabs/talos/commit/b8b7b83f872ee4d4e8b52d51b42116d4bf8223ae) chore: extraKernelArgs validation for UKI's\n* [`e2df0c6d3`](https://github.com/siderolabs/talos/commit/e2df0c6d3628ea972e914a94af09d8606083825d) docs: update siderolink.md\n* [`f9b14e784`](https://github.com/siderolabs/talos/commit/f9b14e7848f2b08b6cc274a0ef7a01df98bcd48e) fix: reconnect on SideroLink tunnel on/off change\n* [`29f7b3bf3`](https://github.com/siderolabs/talos/commit/29f7b3bf37aead52f9e015aeeea20f4318f39dc4) test(ci): use k8s websocket executor for tests\n* [`9531c1c6d`](https://github.com/siderolabs/talos/commit/9531c1c6d2601b77febbdcc7bca8686f3163fd21) fix(ci): image-cache cron\n* [`90abdc489`](https://github.com/siderolabs/talos/commit/90abdc4893316516622b01e8c0d2d3bb8ba06416) feat: update Kubernetes to 1.33.0-beta.0\n* [`9a5914048`](https://github.com/siderolabs/talos/commit/9a5914048c66ebcaef1614f9efc0c656d8dff63a) refactor: ephemeral mount\n* [`e4fb1c06a`](https://github.com/siderolabs/talos/commit/e4fb1c06a486d45afe6adba0d2290595d0f680f4) docs: update for predictable interface naming\n* [`729fce306`](https://github.com/siderolabs/talos/commit/729fce3065b4e23bc9a09739dc2eb86521ca3fe7) feat: update Linux to 6.12.18\n* [`b4d2e1c3c`](https://github.com/siderolabs/talos/commit/b4d2e1c3c59db3d64fcb0fa10fbd250dcdd31d5b) fix: typo in machinery CloudPlatforms\n* [`7e0475488`](https://github.com/siderolabs/talos/commit/7e0475488d3a5c088fc02431c2ee55cf4a453b84) fix: qemu: archive cluster logs only after stopping VMs\n* [`dab30a8b9`](https://github.com/siderolabs/talos/commit/dab30a8b9fc48078a1cefca6cc6a9caaacef5a93) fix: ensure no goroutines escape in dns controller\n* [`fce824e2f`](https://github.com/siderolabs/talos/commit/fce824e2f3aa1c21a72e385a4daa2a546305cf0a) fix: change from \"init6\" to \"inet6\" in docs\n* [`f51ebd1bc`](https://github.com/siderolabs/talos/commit/f51ebd1bc8142b2ea649ee205f015dfde61e8ee5) chore: fix the mount cache ids in the Dockerfile\n* [`4365aecbd`](https://github.com/siderolabs/talos/commit/4365aecbd6dc4e54b22514938d6c41f7276c8e70) test: use standard installer for e2e-iso\n* [`431178327`](https://github.com/siderolabs/talos/commit/43117832725acf6fdf0b2ac6e0302de64958f85b) feat: update Kubernetes to v1.33.0-alpha.3\n* [`1259345e4`](https://github.com/siderolabs/talos/commit/1259345e4240c0ec3d84b5fd982d98897a39cc62) fix(ci): image-cache cron\n* [`18871a7eb`](https://github.com/siderolabs/talos/commit/18871a7eb87db2c536a4620e2c3ba64951171140) chore: tidy labeled-squashfs.sh\n* [`d45259f89`](https://github.com/siderolabs/talos/commit/d45259f89dce282eaf6bc3ed4c2106aa8a054eba) feat: update Flannel to 0.26.5\n* [`e83ef0e2e`](https://github.com/siderolabs/talos/commit/e83ef0e2ee8a564efecb1356d7e8246b2e9056f6) docs: update proxmox.md\n* [`3def5f9a6`](https://github.com/siderolabs/talos/commit/3def5f9a673ad2b57580ade483496c07d3945edc) feat: update etcd to 3.5.19\n* [`c3c0d2e42`](https://github.com/siderolabs/talos/commit/c3c0d2e42f3913b64463f13fb63a5e0a78bed627) test: fix dns test in race mode\n* [`17965c32f`](https://github.com/siderolabs/talos/commit/17965c32fa1f2e3b12cb2cf9ebd4550eb4dca672) chore: update Go to 1.24.1\n* [`1fbb2d1a7`](https://github.com/siderolabs/talos/commit/1fbb2d1a7cc658eedd8cdae2d0440324c709fe58) docs: update nvidia-gpu-proprietary.md\n* [`d60972bdf`](https://github.com/siderolabs/talos/commit/d60972bdf8c45f283e6e247b41053035eb6e1dbc) chore: add installer-base to the list of signed images\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`0d45dee`](https://github.com/siderolabs/crypto/commit/0d45deefbcdd4bd6b6e549433b859083df55fc16) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`64513a6`](https://github.com/siderolabs/discovery-api/commit/64513a6c4fb31c6a043159d5caea1d153ea133a4) feat: rekres, regenerate proto files\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b3632c4`](https://github.com/siderolabs/discovery-client/commit/b3632c4a8cd96ae36337e83308ef447361b51537) feat: support extra dial options in the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>7 commits</summary>\n<p>\n\n* [`c201b87`](https://github.com/siderolabs/extras/commit/c201b879d88095dd6c5de18490552e458357303f) feat: update dependencies\n* [`4102a78`](https://github.com/siderolabs/extras/commit/4102a783a23e298f3c7e600cb4dfb7a04888eaaf) feat: build hermetically using new bldr and pkgs\n* [`f4a110f`](https://github.com/siderolabs/extras/commit/f4a110f5f4b472743dc023413dca280bce491ec1) fix: build tc-redirect-tap as static binary\n* [`0840abb`](https://github.com/siderolabs/extras/commit/0840abb9b5e32560ff38577151fdc2f51812ce31) fix: pull in fixed CNI plugins from pkgs\n* [`52c217f`](https://github.com/siderolabs/extras/commit/52c217f693366bdf21772919ad94933fd160c5d4) feat: update dependencies\n* [`f755eb4`](https://github.com/siderolabs/extras/commit/f755eb483647d17e487f7cb62de8cc150a420c3c) chore: rekres to simplify `.kres.yaml` defaults\n* [`e5382fc`](https://github.com/siderolabs/extras/commit/e5382fc5f05d7ccfdb7c95819195caceac8ffcbf) chore: kresify renovate\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`5ae3afe`](https://github.com/siderolabs/gen/commit/5ae3afee65490ca9f4bd32ea41803ab3a17cad7e) chore: update hashtriemap implementation from the latest upstream\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>2 commits</summary>\n<p>\n\n* [`015a398`](https://github.com/siderolabs/go-circular/commit/015a398e79f2853714cd20d1135dc100f18b6c29) fix: replace static buffer allocation on growth\n* [`ed8685e`](https://github.com/siderolabs/go-circular/commit/ed8685e0cf9491d9a714e565e0e736439a94a73f) test: add more assertions for write length result\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`ea108ca`](https://github.com/siderolabs/go-debug/commit/ea108cacca8940426149e67ba00e414633e4ef3f) chore: add support for Go 1.24\n</p>\n</details>\n\n### Changes from siderolabs/go-kubeconfig\n<details><summary>1 commit</summary>\n<p>\n\n* [`cc42d09`](https://github.com/siderolabs/go-kubeconfig/commit/cc42d09846ec29c9f8ab8d6e5061bc037100756e) chore: rekres and update\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`9ba5654`](https://github.com/siderolabs/go-kubernetes/commit/9ba5654fcec6061322530394e336b68a8c764a1b) fix: fix ignoring alpha/beta version parsing\n* [`0fe1db4`](https://github.com/siderolabs/go-kubernetes/commit/0fe1db4603b591883fac9ce4afcab911bc57922c) feat: update for new changes in Kubernetes 1.33.0-alpha.3\n* [`804cb44`](https://github.com/siderolabs/go-kubernetes/commit/804cb440c2299488c7c68185c53b91ffdfb8bf32) feat: add support for Kubernetes to 1.33\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`589c33a`](https://github.com/siderolabs/go-loadbalancer/commit/589c33a96ac74a8c0e36b09f534fca62afd6de81) chore: upgrade `upstream.List` and `loadbalancer.TCP` to Go 1.23\n</p>\n</details>\n\n### Changes from siderolabs/go-pointer\n<details><summary>1 commit</summary>\n<p>\n\n* [`347ee9b`](https://github.com/siderolabs/go-pointer/commit/347ee9b78f625d420254f4ab01bb1d6174474bf4) chore: rekres, update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/go-talos-support\n<details><summary>1 commit</summary>\n<p>\n\n* [`0f784bd`](https://github.com/siderolabs/go-talos-support/commit/0f784bd58b320543663679693c817515067f3021) fix: avoid deadlock on context cancel\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>69 commits</summary>\n<p>\n\n* [`55d99ea`](https://github.com/siderolabs/pkgs/commit/55d99ea9574d6f535b0cccf2173070844e028f07) feat: update dependencies\n* [`668d25b`](https://github.com/siderolabs/pkgs/commit/668d25bf8059e90534708ce0e8adcda003eb57c6) fix: trim qemu-tools\n* [`143f50d`](https://github.com/siderolabs/pkgs/commit/143f50db4742b2b3df77e54b668dbbc9880397c8) feat(containerd): provide ctr as part of the build\n* [`990a9e8`](https://github.com/siderolabs/pkgs/commit/990a9e8ab1bf1d21ee5003c55ba259e0e6be1f78) feat: update Linux 6.12.19, Linux firmware 20250311\n* [`9af76d3`](https://github.com/siderolabs/pkgs/commit/9af76d3781a63dad3798246ae2b6edba2dfc443c) feat: update containerd 2.0.4, runc 1.2.6\n* [`5a0d262`](https://github.com/siderolabs/pkgs/commit/5a0d26239c68982d1f3981d042e95c87440c60be) feat: add CONFIG_DWMAC_DWC_QOS_ETH to arm64 config\n* [`9e9a817`](https://github.com/siderolabs/pkgs/commit/9e9a81768bccd2233497b4e20ecb8b3270003bfe) feat(kernel): add support for intel based edge device\n* [`4d4aaad`](https://github.com/siderolabs/pkgs/commit/4d4aaadb73038f2b2c446fcb72360e3319a533cf) fix: patch containerd with restart fix\n* [`dbdeff4`](https://github.com/siderolabs/pkgs/commit/dbdeff4613efcccd8b6f180a4f7c3beb25d1aaa1) feat: enable kernel drivers for tegra194, tegra234 SoCs\n* [`499e56f`](https://github.com/siderolabs/pkgs/commit/499e56f5810cb637199cecbbde53c08d2f42a619) feat(kernel): enable v3d as kernel module\n* [`988ec60`](https://github.com/siderolabs/pkgs/commit/988ec60e7479751a127306f2eeb693d021465601) feat: add intel pmt/pmc\n* [`8e2c6d8`](https://github.com/siderolabs/pkgs/commit/8e2c6d8e4ffd8f1af4d5704e2da04ebfedcd6787) feat: update Linux to 6.12.18\n* [`5246c32`](https://github.com/siderolabs/pkgs/commit/5246c3270d8d58269c16e8527d343554f0d5e31f) feat(kernel): add -@ to dtc flags for arm64 to enable overlay support\n* [`068171e`](https://github.com/siderolabs/pkgs/commit/068171ec0859c68adc5b5787114f7ee0cac24d44) chore: unify buildkits\n* [`a4ac508`](https://github.com/siderolabs/pkgs/commit/a4ac508531f6daff8719ff6ffab189c2a16bc690) feat: add panfrost kernel module\n* [`5d6ca21`](https://github.com/siderolabs/pkgs/commit/5d6ca21daa1c86510c0e88b0d6e14c99dbe7467c) fix: backport MGLRU patch from Linux 6.13\n* [`1d84473`](https://github.com/siderolabs/pkgs/commit/1d844735bb4777f6e2b9b66d721b1ee0c6a1fe59) feat: update dependencies\n* [`831bc76`](https://github.com/siderolabs/pkgs/commit/831bc7601f0deb1959755d25083c2ea31cf4dd43) feat(kernel): enable TPM SPI support in kernel config for arm64\n* [`023f092`](https://github.com/siderolabs/pkgs/commit/023f092857a5536dcb00f68e6fd81b84fc374b7f) feat: enable nfsd support in the kernel\n* [`347ad26`](https://github.com/siderolabs/pkgs/commit/347ad26815260d148a7aa42a20eafa5228cbc411) feat: update Linux 6.12.17, containerd 2.0.3\n* [`40241af`](https://github.com/siderolabs/pkgs/commit/40241af0b4d3a34ba5b89fc3a815b9f401f0e203) feat: enable qla2xxx module\n* [`6fb00b4`](https://github.com/siderolabs/pkgs/commit/6fb00b45c1e4c50d26822f9bd0fd462ed0dfb712) fix: pull in kmod from tools\n* [`cc5317a`](https://github.com/siderolabs/pkgs/commit/cc5317adec817d406c1fad1b4871cd7319b56f97) fix: patch Linux with blackhole patch\n* [`08389dd`](https://github.com/siderolabs/pkgs/commit/08389dd2d97aa53e9ac5523a5512c5bbead371c5) chore: support vmdk and cp format for qemu-img\n* [`7774b08`](https://github.com/siderolabs/pkgs/commit/7774b08f03f5c096efdcc7863260916d78a7b8a9) feat: update Linux to 6.12.16, validate package structure\n* [`40d288c`](https://github.com/siderolabs/pkgs/commit/40d288c66d67cfb1d0073288179224d22bf6c41a) fix: imager deps\n* [`351a1a1`](https://github.com/siderolabs/pkgs/commit/351a1a1ece7a79226f46f03f9d904e1d5600716d) feat: add tools needed for imager\n* [`80351ca`](https://github.com/siderolabs/pkgs/commit/80351ca6201f5e5efb51b2a2a6a2058fa2512a90) fix: reproducibility tests\n* [`e1f11f0`](https://github.com/siderolabs/pkgs/commit/e1f11f0991c23f86694b49a9e0fc0f7f592d093d) fix: remove patches and other files from copy-only packages\n* [`8fff06b`](https://github.com/siderolabs/pkgs/commit/8fff06bac029313278c632321f511c2918585872) chore: bump xfsprogs to 6.12.0\n* [`76a0316`](https://github.com/siderolabs/pkgs/commit/76a0316a84571c22eb0c6efd3ce51f3da54671c9) chore: systemd 257.3, runc 1.2.5, ipxe\n* [`359807b`](https://github.com/siderolabs/pkgs/commit/359807b4172e17fdcd1a1531070535d7ef772b20) feat: copy built packages, improve hermetic build\n* [`117a1d6`](https://github.com/siderolabs/pkgs/commit/117a1d6b48835310714166335d3821ac47b4c70a) feat: update Linux to 6.12.13\n* [`85f8901`](https://github.com/siderolabs/pkgs/commit/85f890180058a0865515ed76ca39f76ff0fe20d7) feat: make pkgs build bootstrapped\n* [`5763e3e`](https://github.com/siderolabs/pkgs/commit/5763e3e0fe00cbd9010398e795085ba0377802e8) feat: update systemd to 257.2\n* [`1e24b31`](https://github.com/siderolabs/pkgs/commit/1e24b31dc379251ad5248f94f548e5c7330f59ec) feat: update Linux to 6.12.11\n* [`38749d1`](https://github.com/siderolabs/pkgs/commit/38749d1f08fcb46e522450c1ad530309a8fa327d) fix: build CNI plugins statically linked\n* [`5da83db`](https://github.com/siderolabs/pkgs/commit/5da83dbbe320768db8eb6175b1e7c5e8ff78389d) feat: bump NVIDIA driver versions\n* [`5934363`](https://github.com/siderolabs/pkgs/commit/59343630a024e48dfeba826eac45589d0bdcfb99) fix: certificates CA\n* [`57f492d`](https://github.com/siderolabs/pkgs/commit/57f492d4c3e51e01ab85d2727a7862b21ab21795) feat: bump dependencies\n* [`45b9ebe`](https://github.com/siderolabs/pkgs/commit/45b9ebed9437752c6516792678356a595f1ec62b) feat: update Linux to 6.2.10\n* [`e00ad67`](https://github.com/siderolabs/pkgs/commit/e00ad677f0c7ef4005d26108143c3fe5e36aaab2) chore: rekres to fix reproducibility build\n* [`cfb4b0a`](https://github.com/siderolabs/pkgs/commit/cfb4b0a79490156864eab726debe20559d9c4240) feat: update Go to 1.23.5\n* [`72f19a2`](https://github.com/siderolabs/pkgs/commit/72f19a2983e7abcb620ab57fae6e039158663f1a) feat: update containerd to v2.0.2\n* [`17a80ee`](https://github.com/siderolabs/pkgs/commit/17a80eeb75b91211d4ffe8a910feb9fddcd1e585) feat: update Linux to 6.12.9\n* [`c9d718d`](https://github.com/siderolabs/pkgs/commit/c9d718d3d6fd762ca3a649a14aa2d74e47d707e2) fix: adjust kernel options around ACPI/PCI/EFI\n* [`eb9d566`](https://github.com/siderolabs/pkgs/commit/eb9d56617faa56e42648a07b6756c18850e4a045) feat: update Linux to 6.12.8\n* [`73e4353`](https://github.com/siderolabs/pkgs/commit/73e4353ad9e2dad6dc8544436776fd412c808d63) fix: update config-arm64 to add Rasperry Pi watchdog support\n* [`0ab2427`](https://github.com/siderolabs/pkgs/commit/0ab2427a8415d3f29cd4f52e3afd51f701aa5848) fix: dvb was missing I2C_MUX support and si2168 driver\n* [`c3ac8e2`](https://github.com/siderolabs/pkgs/commit/c3ac8e2d553b068dd982f5b9e48f6b1e0cfdd24d) chore: drop unused cert copy\n* [`e7eddcf`](https://github.com/siderolabs/pkgs/commit/e7eddcf9498634749a4241844660fd0e9d87fad4) feat: bump dependencies\n* [`0b00e86`](https://github.com/siderolabs/pkgs/commit/0b00e86ae92f821bdc19af73a5ba571b5051c89a) fix: patch containerd with CNI deadlock fix\n* [`9051c9a`](https://github.com/siderolabs/pkgs/commit/9051c9ac6f60e039c53248b52ba4ccd192e34b6b) feat: update Linux to 6.12.6\n* [`6695012`](https://github.com/siderolabs/pkgs/commit/6695012e8d93d28ea70fc3ba32ed90770eea4363) chore: rekres to simplify `.kres.yaml` defaults\n* [`611ca38`](https://github.com/siderolabs/pkgs/commit/611ca38153fece4f2b34519325fbca22d34db7a0) chore: rekres to bring renovate under kres\n* [`a4c4215`](https://github.com/siderolabs/pkgs/commit/a4c4215e74b68765ada0745165b2e2fb5ee508f5) fix: drop cgroupsv1 controllers\n* [`28c909d`](https://github.com/siderolabs/pkgs/commit/28c909ddeaf0d33e0fc6c5fdf2333a18801cf178) feat: update Linux firmware to 20241210\n* [`c40a9e9`](https://github.com/siderolabs/pkgs/commit/c40a9e9713b1fde14f7a967fd1be168bb905d7c9) feat: update Linux to 6.12.5\n* [`d54ca83`](https://github.com/siderolabs/pkgs/commit/d54ca835a8868e5df55e2d0ffe3cb0dfa82a3395) feat: update containerd to v2.0.1\n* [`86e3755`](https://github.com/siderolabs/pkgs/commit/86e3755deae2fc85d7e62bdcf82a54cb72fec6d5) fix: add CONFIG_INTEL_MEI_GSC_PROXY as module\n* [`8c31321`](https://github.com/siderolabs/pkgs/commit/8c3132135d5a0e01a9d66790b4b25c7c05e08fa5) feat: update ZFS to 2.2.7\n* [`605f493`](https://github.com/siderolabs/pkgs/commit/605f493abfeac79151c02a776733011f19d6c43b) feat: update runc to v1.2.3\n* [`1a55529`](https://github.com/siderolabs/pkgs/commit/1a555296764ab0ad83fb4eca6509bb64feff3b7b) feat: update Linux to 6.12.4\n* [`52ba9a5`](https://github.com/siderolabs/pkgs/commit/52ba9a57358ef37ce3e4aa4033991dc77ad17fbb) feat: update Linux 6.12.3\n* [`9cf35be`](https://github.com/siderolabs/pkgs/commit/9cf35bef274bb445e578f858a0a595b05b44a01f) feat: build host iptables with nftables support\n* [`71003a3`](https://github.com/siderolabs/pkgs/commit/71003a3c9bff00685917d6e272421a7206b1667e) feat: update Go to 1.23.4\n* [`5b4d402`](https://github.com/siderolabs/pkgs/commit/5b4d402bd33f9313a21e4924be57aacce569f9ad) feat: build dvb kernel modules and CX23885\n* [`b330af9`](https://github.com/siderolabs/pkgs/commit/b330af9b95d9115382c81f88b55c17b99f7ef355) chore: bring in KSPP recommendations\n* [`f81b190`](https://github.com/siderolabs/pkgs/commit/f81b190cc65dc93f9212d52cd95806ac79c170d2) feat: kernel driver support for RK3588 devices (Turing RK1)\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>1 commit</summary>\n<p>\n\n* [`3235c29`](https://github.com/siderolabs/proto-codec/commit/3235c2984fa1bb3cd8d38c088127c46dd3d2860e) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>2 commits</summary>\n<p>\n\n* [`a7af143`](https://github.com/siderolabs/siderolink/commit/a7af1431e0798541f8d3db0aa70af0e15b2c3eb6) feat: support packets filtering before writing them to the tun device\n* [`38e459e`](https://github.com/siderolabs/siderolink/commit/38e459e50c467791c9670a60ef41f58db246715a) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>24 commits</summary>\n<p>\n\n* [`6d456ca`](https://github.com/siderolabs/tools/commit/6d456cab5b18b175571a1745cd684917656c1953) fix: revert util-linux to 2.40.4\n* [`5bba094`](https://github.com/siderolabs/tools/commit/5bba094fe89752abe981c5d60d808a27d7aa5df2) feat: update dependencies\n* [`eeb1f9d`](https://github.com/siderolabs/tools/commit/eeb1f9d558f700f9ed391c1b769b028180c644c3) fix: revert swig update\n* [`6b082a6`](https://github.com/siderolabs/tools/commit/6b082a644db47678cdc48cf4c6c663a1a6d128d5) chore: unify buildkits\n* [`87acb27`](https://github.com/siderolabs/tools/commit/87acb27b9becc4947546907ef91b49fa1f8885ad) feat: update dependencies\n* [`fcee25b`](https://github.com/siderolabs/tools/commit/fcee25ba79e3663db2c0f20f371392e2b45c5f19) fix: revert kmod to 33\n* [`6a71711`](https://github.com/siderolabs/tools/commit/6a7171177b5e9a4b579db3614d140a399430c3ab) fix: do not install man and locale for exported packages\n* [`3389ba2`](https://github.com/siderolabs/tools/commit/3389ba22509cb85e0625dcb6dbbee218fc56d33d) chore: move zlib to be an external package\n* [`d93b780`](https://github.com/siderolabs/tools/commit/d93b780e8f63cf20a524d3ea76bd4f79b787b5f3) chore: expose more tools\n* [`46be459`](https://github.com/siderolabs/tools/commit/46be459d3a46f1fa096a9e58cbf060404dd3cbe2) chore: remove systemd version\n* [`f33fbe4`](https://github.com/siderolabs/tools/commit/f33fbe42517d5a856b360133c6330692b09ba824) fix: install policycoreutils under correct prefix\n* [`758d61c`](https://github.com/siderolabs/tools/commit/758d61cd71c43ba2a65372dc75b811864e113a29) chore: update dependencies\n* [`f398a04`](https://github.com/siderolabs/tools/commit/f398a04953666fa468b02851187f3dc4a77c5a44) chore: update dependencies, hermetic build\n* [`9db33dd`](https://github.com/siderolabs/tools/commit/9db33dd7457e026176fdea964de6d489e67b5fa0) feat: update to Go 1.23.6\n* [`ef0a679`](https://github.com/siderolabs/tools/commit/ef0a67955aa9191019e5ea2fe0fe572694606b02) fix: do not install anything to /usr/lib64\n* [`35748ea`](https://github.com/siderolabs/tools/commit/35748eac6666b66099b16ccfcfe989e34ea16076) feat: fully bootstrapped build\n* [`7200845`](https://github.com/siderolabs/tools/commit/7200845be9d0318d23eb77a57e1b8992dd7e8187) feat: update dependencies\n* [`bc30a2a`](https://github.com/siderolabs/tools/commit/bc30a2a3ace873c80e4657b622e3142efb55cc28) feat: update Go to 1.23.5\n* [`533b595`](https://github.com/siderolabs/tools/commit/533b5953d28213aae4d4ae576bedf5df84712458) chore: rekres to fix reproducibility\n* [`01568a5`](https://github.com/siderolabs/tools/commit/01568a5b42685c3ea19578a7f4d7ba07dc0f18cd) chore: use Make and Go from the toolchain image\n* [`0393558`](https://github.com/siderolabs/tools/commit/03935581049f82ff466defcc203c5bcc6db5b43a) feat: bump dependencies\n* [`7811a5f`](https://github.com/siderolabs/tools/commit/7811a5f2f23923cdfe5bfd47ee12ed9e88b29585) chore: rekres to simplify `.kres.yaml` defaults\n* [`0b8b905`](https://github.com/siderolabs/tools/commit/0b8b9054833d8187bb1f6209b2441719f6e62cfa) chore: kresify renovate config\n* [`fe34fb3`](https://github.com/siderolabs/tools/commit/fe34fb3d54ec9abe878a9304fbfc3e1e741c0ff4) feat: update Go to 1.23.4\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.5.2 -> v0.6.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.16.0 -> v1.17.1\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.8.0 -> v1.8.2\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.3.0 -> v1.3.1\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.3.0 -> v1.3.1\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.28.5 -> v1.29.9\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.20 -> v1.16.30\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.37.6 -> v1.38.1\n* **github.com/aws/smithy-go**                                                v1.22.1 -> v1.22.3\n* **github.com/containerd/cgroups/v3**                                        v3.0.4 -> v3.0.5\n* **github.com/containerd/containerd/v2**                                     v2.0.1 -> v2.0.4\n* **github.com/containerd/platforms**                                         v1.0.0-rc.0 -> v1.0.0-rc.1\n* **github.com/containernetworking/plugins**                                  v1.6.0 -> v1.6.2\n* **github.com/cosi-project/runtime**                                         v0.7.6 -> v0.10.1\n* **github.com/docker/cli**                                                   v27.3.1 -> v28.0.2\n* **github.com/docker/docker**                                                v27.3.1 -> v28.0.2\n* **github.com/elastic/go-libaudit/v2**                                       v2.6.1 -> v2.6.2\n* **github.com/florianl/go-tc**                                               v0.4.4 -> v0.4.5\n* **github.com/foxboron/go-uefi**                                             fab4fdf2f2f3 -> 69fb7dba244f\n* **github.com/gdamore/tcell/v2**                                             v2.7.4 -> v2.8.1\n* **github.com/google/cadvisor**                                              v0.51.0 -> v0.52.1\n* **github.com/google/cel-go**                                                v0.22.1 -> v0.24.1\n* **github.com/google/go-containerregistry**                                  v0.20.2 -> v0.20.3\n* **github.com/google/go-tpm**                                                v0.9.1 -> v0.9.3\n* **github.com/google/nftables**                                              v0.2.0 -> v0.3.0\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**                         v2.1.0 -> v2.3.1\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.17.0 -> v2.20.1\n* **github.com/insomniacslk/dhcp**                                            a3a4c1f04475 -> 8abf58130905\n* **github.com/klauspost/compress**                                           v1.17.11 -> v1.18.0\n* **github.com/klauspost/cpuid/v2**                                           v2.2.9 -> v2.2.10\n* **github.com/mdlayher/netlink**                                             v1.7.2 -> fbb4dce95f42\n* **github.com/mdp/qrterminal/v3**                                            v3.2.0 -> v3.2.1\n* **github.com/miekg/dns**                                                    v1.1.62 -> v1.1.64\n* **github.com/opencontainers/image-spec**                                    v1.1.0 -> v1.1.1\n* **github.com/opencontainers/runc**                                          v1.2.2 -> v1.2.6\n* **github.com/opencontainers/runtime-spec**                                  v1.2.0 -> v1.2.1\n* **github.com/prometheus/procfs**                                            v0.15.1 -> v0.16.0\n* **github.com/rivo/tview**                                                   c76f7879f592 -> 73a5bd7d6839\n* **github.com/safchain/ethtool**                                             v0.5.9 -> v0.5.10\n* **github.com/scaleway/scaleway-sdk-go**                                     v1.0.0-beta.30 -> v1.0.0-beta.32\n* **github.com/siderolabs/crypto**                                            v0.5.0 -> v0.5.1\n* **github.com/siderolabs/discovery-api**                                     v0.1.5 -> v0.1.6\n* **github.com/siderolabs/discovery-client**                                  v0.1.10 -> v0.1.11\n* **github.com/siderolabs/extras**                                            v1.9.0 -> v1.10.0-alpha.0-4-gc201b87\n* **github.com/siderolabs/gen**                                               v0.7.0 -> v0.8.0\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.7 -> v2.0.16\n* **github.com/siderolabs/go-circular**                                       v0.2.1 -> v0.2.2\n* **github.com/siderolabs/go-debug**                                          v0.4.0 -> v0.5.0\n* **github.com/siderolabs/go-kubeconfig**                                     v0.1.0 -> v0.1.1\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.17 -> v0.2.20\n* **github.com/siderolabs/go-loadbalancer**                                   v0.3.4 -> v0.4.0\n* **github.com/siderolabs/go-pointer**                                        v1.0.0 -> v1.0.1\n* **github.com/siderolabs/go-talos-support**                                  v0.1.1 -> v0.1.2\n* **github.com/siderolabs/pkgs**                                              v1.9.0-12-g9576b97 -> v1.10.0-alpha.0-68-g55d99ea\n* **github.com/siderolabs/proto-codec**                                       v0.1.1 -> v0.1.2\n* **github.com/siderolabs/siderolink**                                        v0.3.11 -> v0.3.13\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.9.0 -> v1.10.0-alpha.2\n* **github.com/siderolabs/tools**                                             v1.9.0-1-geaad82f -> v1.10.0-alpha.0-23-g6d456ca\n* **github.com/spf13/cobra**                                                  v1.8.1 -> v1.9.1\n* **github.com/spf13/pflag**                                                  v1.0.5 -> v1.0.6\n* **github.com/thejerf/suture/v4**                                            v4.0.5 -> v4.0.6\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.17 -> v3.5.20\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.17 -> v3.5.20\n* **go.etcd.io/etcd/client/v3**                                               v3.5.17 -> v3.5.20\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.17 -> v3.5.20\n* **go.uber.org/goleak**                                                      v1.3.0 **_new_**\n* **golang.org/x/net**                                                        v0.32.0 -> v0.37.0\n* **golang.org/x/oauth2**                                                     v0.24.0 -> v0.28.0\n* **golang.org/x/sync**                                                       v0.10.0 -> v0.12.0\n* **golang.org/x/sys**                                                        v0.28.0 -> v0.31.0\n* **golang.org/x/term**                                                       v0.27.0 -> v0.30.0\n* **golang.org/x/text**                                                       v0.21.0 -> v0.23.0\n* **golang.org/x/time**                                                       v0.8.0 -> v0.11.0\n* **golang.zx2c4.com/wireguard/wgctrl**                                       925a1e7659e6 -> a9ab2273dd10\n* **google.golang.org/grpc**                                                  v1.68.1 -> v1.71.0\n* **google.golang.org/protobuf**                                              v1.35.2 -> v1.36.5\n* **k8s.io/api**                                                              v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/apimachinery**                                                     v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/apiserver**                                                        v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/client-go**                                                        v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/component-base**                                                   v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/cri-api**                                                          v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/kube-scheduler**                                                   v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/kubectl**                                                          v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/kubelet**                                                          v0.32.0 -> v0.33.0-beta.0\n* **k8s.io/pod-security-admission**                                           v0.32.0 -> v0.33.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**                           v1.2.72 -> v1.2.75\n\nPrevious release can be found at [v1.9.0](https://github.com/siderolabs/talos/releases/tag/v1.9.0)\n\n## [Talos 1.10.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.10.0-alpha.2) (2025-03-05)\n\nWelcome to the v1.10.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### auditd\n\nKernel parameter `talos.auditd.disabled=1` can be used to disable Talos built-in `auditd` service.\n\n\n### cgroups v1\n\nTalos Linux no longer supports `cgroupsv1` when running in non-container mode.\nThe kernel argument `talos.unified_cgroup_hierarchy` is now ignored.\n\n\n### Disk Image\n\nTalos starting with 1.10 will have disk images that will use GRUB only for legacy BIOS and systemd-boot for modern UEFI systems.\nOn first boot Talos determines the boot method and will wipe the unused bootloader.\n\nSecureboot disk-images will be sd-boot only.\n\nFor ARM64 imager will still generate GRUB bootloader for Talos < 1.10 and for Talos >= 1.10 all ARM64 boot assets will use systemd-boot.\n\nImager supports overwriting bootloader when generating a disk image via the Imager profile `output` option.\n\nEg:\n\n```yaml\noutput:\n  kind: image\n  imageOptions:\n    bootloader: sd-boot # supported options are sd-boot, grub, dual-boot\n```\n\n\n\n### Driver Rebind\n\nTalos 1.10 now supports a new machine config document named `PCIDriverRebindConfig` that allows rebinding the driver of a PCI device to a different target driver.\nSee the [documentation](https://www.talos.dev/v1.10/reference/configuration/hardware/pcidriverrebindconfig/) for more information.\n\n\n### Ethernet\n\nTalos now provides `ethtool`-style Ethernet low-level configuration via `network/EthernetConfig` documents.\nCurrent status of the interface can be read by `talosctl get ethernetstatus`.\n\n\n### Ingress Firewall\n\nTalos Ingress Firewall now filters access to Kubernetes NodePort services correctly.\n\n\n### iSCSI Initiator\n\nTalos now generates `/etc/iscsi/initiatorname.iscsi` file based on the node identity which is tied to the lifecycle of the node.\nIf using `iscsi-tools` extension, starting with Talos 1.10 would have a more deterministic IQN for the initiator node.\nMake sure to update any iSCSI targets to use the new initiator IQN.\n\nThe iqn can be read by `talosctl read /etc/iscsi/initiatorname.iscsi`\n\n\n### ISO\n\nTalos starting with 1.10 will have ISO's that will use GRUB only for legacy BIOS and systemd-boot for modern UEFI systems.\n\n\n### kube-apiserver Authorization Config\n\nWhen using `.cluster.apiServer.authorizationConfig` the user provided order for the authorizers is honoured and `Node` and `RBAC` authorizers are always added to the end if not explicitly specified.\n\nEg: If user provides only `Webhook` authorizer, the final order will be `Webhook`, `Node`, `RBAC`.\n\nTo provide a specific order for `Node` or `RBAC` explicitly, user can provide the authorizer in the order they want.\n\nEg:\n\n```yaml\ncluster:\n  apiServer:\n    authorizationConfig:\n      - type: Node\n        name: Node\n      - type: Webhook\n        name: Webhook\n        webhook:\n          connectionInfo:\n            type: InClusterConfig\n        ...\n      - type: RBAC\n        name: rbac\n```\n\nUsage of `authorization-mode` CLI argument will not support this form of customization.\n\n\n### NVMe NQN\n\nTalos now generates `/etc/nvme/hostnqn` and `/etc/nvme/hostid` files based on the node identity which is tied to the lifecycle of the node.\n\nThe NQN can be read by `talosctl read /etc/nvme/hostnqn`\n\n\n### Fully bootstrapped builds\n\nTalos 1.10 is built with a toolchain based on [[Stageˣ]](https://stagex.tools/), which is a project building fully bootstrapped software.\nThis change increases reproducibility, auditability and security of Talos builds.\n\nThis also changes Talos root filesystem structure for unified /usr, with other directories symlinking to /usr/bin and /usr/lib.\nSystem extensions must move their directories accordingly for 1.10.\n\n\n### Component Updates\n\n* Linux: 6.12.17\n* CNI plugins: 1.6.2\n* runc: 1.2.5\n* containerd: 2.0.3\n* etcd: 3.5.18\n* Flannel: 0.26.4\n* Kubernetes: 1.33.0-alpha.2\n\nTalos is built with Go 1.24.0.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitry Sharshakov\n* Dmitriy Matrenichev\n* Dmitrii Sharshakov\n* Justin Garrison\n* Mathspy\n* Nico Berlee\n* Skyler Mäntysaari\n* Utku Ozdemir\n* ihelmer07\n* 459below\n* Alexis La Goutte\n* Andrew Longwill\n* Andrew Symington\n* Christian Luetke-Stetzkamp\n* Christoph Hoopmann\n* Devin Buhl\n* Dominik Masur\n* Florian Grignon\n* Ganawa Juanah\n* Jason Benedicic\n* Joakim Nohlgård\n* K Birt\n* KillianCdP\n* L.J. Hanson\n* Louis SCHNEIDER\n* Marcel Hamer\n* Mikhail Petrov\n* Motte\n* Natalie Romana Albers\n* Orzelius\n* PRIHLOP\n* Ram\n* Robin Elfrink\n* Ryan Jacobs\n* Serge Logvinov\n* Thomas Gosteli\n* Tim Olson\n* Tine Jozelj\n* TomyLobo\n* bzub\n* greenpsi\n* sflotat2607\n* suse-coder\n\n### Changes\n<details><summary>219 commits</summary>\n<p>\n\n* [`d4e3e957c`](https://github.com/siderolabs/talos/commit/d4e3e957cb98d3fe6ee6685a807c25fafb128423) fix(ci): fix integration tests\n* [`1849b5388`](https://github.com/siderolabs/talos/commit/1849b53881e1ab12b28f9d8b537c8e43d607b4ea) feat: update dependencies\n* [`88fc6bbeb`](https://github.com/siderolabs/talos/commit/88fc6bbebeff1c0db0e43fb0a83d2b03a973da8a) test: fix UKI preserving talos.config and image cache\n* [`ba8cd304d`](https://github.com/siderolabs/talos/commit/ba8cd304d2029c93c31135b2003b1f2f064ff29f) test: enable image-cache in the cron\n* [`28b5dc738`](https://github.com/siderolabs/talos/commit/28b5dc738cd7af5bb06604b2778f808827544ee0) test: fix reproduciblity test\n* [`50998038b`](https://github.com/siderolabs/talos/commit/50998038bb45e33438cccdd8fba4c156f0f7b0b5) feat: prefer sd-boot for UEFI\n* [`e831e52e0`](https://github.com/siderolabs/talos/commit/e831e52e01a47f34e982e9cfa397ca9722094a82) feat: add support for qla2xx\n* [`ec5c049a5`](https://github.com/siderolabs/talos/commit/ec5c049a5a5063289a97271c2d145d298f5f1a43) feat: update Kubernetes to 1.33.0-alpha.2\n* [`ebfa82f35`](https://github.com/siderolabs/talos/commit/ebfa82f3558e5a44a332a0576416ce61f8235407) docs: update deprecated command\n* [`d79059a2c`](https://github.com/siderolabs/talos/commit/d79059a2c96565b1524b3869ad6b28f1cd8351da) chore: fix shutdown typo in shutdown sequence\n* [`a3f88d2ef`](https://github.com/siderolabs/talos/commit/a3f88d2ef5b726e1256a070a961bd4931d453a6a) fix: block NodePort services with ingress firewall\n* [`fd8131cb8`](https://github.com/siderolabs/talos/commit/fd8131cb86714b450334508abc0891eeaa2da9c8) feat: generate unified installer\n* [`ebfdb91b4`](https://github.com/siderolabs/talos/commit/ebfdb91b4cd36b48c36c1523dc74bc6e1860f815) fix: handle dynamic HTTP proxy settings for discovery client\n* [`d45eaeb74`](https://github.com/siderolabs/talos/commit/d45eaeb74cc43cc3154fcbce474958a613bc561b) fix: correctly map link names/aliases when using VIP operator\n* [`7c4e47c0c`](https://github.com/siderolabs/talos/commit/7c4e47c0c00e740bf0d63521baa1231354bc1966) chore: stop doing generate on each build\n* [`b1d410cb6`](https://github.com/siderolabs/talos/commit/b1d410cb6203f8a3847472db3990d2634bab22e2) feat: dual boot disk image\n* [`468e318ba`](https://github.com/siderolabs/talos/commit/468e318ba4137e1f11d231fe3ed66f10543073e3) fix: multiple fixes for dashboard/no data\n* [`3dd8d9aed`](https://github.com/siderolabs/talos/commit/3dd8d9aed8d311f84c61f3030fbf2031ee1d3df9) docs: update resetting-a-machine.md to include example of reset\n* [`7af8f6b2f`](https://github.com/siderolabs/talos/commit/7af8f6b2fa98f1ed4ad5adbcea6d54802013a086) feat: validate docker image references in upgrade options\n* [`c949f55e6`](https://github.com/siderolabs/talos/commit/c949f55e61b8c74202f2da50829c2e034e43682e) docs: remove typo on resetting a machine page\n* [`f5c097041`](https://github.com/siderolabs/talos/commit/f5c097041faac04808636703c94fe5d3ee208947) feat: add description to schema object defs\n* [`79ee304e1`](https://github.com/siderolabs/talos/commit/79ee304e11df7cfb2ccc6eeeb39ab6112975db45) chore: update enumer to a version that fixes Go 1.24 compatibility\n* [`46d67fe44`](https://github.com/siderolabs/talos/commit/46d67fe446edfabe23e3e8a91cc1f07436827c5e) chore: update Go to 1.24, update pkgs\n* [`7f1dd2669`](https://github.com/siderolabs/talos/commit/7f1dd2669734f496afbec6812a814d70dbaee3b4) fix(ci): fix integration-misc crons\n* [`26a773d3f`](https://github.com/siderolabs/talos/commit/26a773d3f27572a01d146ed356be5e78f8dc23e0) docs: add a note about syslog sending messages to services\n* [`7ce053638`](https://github.com/siderolabs/talos/commit/7ce053638db9c9abd4d966d412986c07615a750e) fix: ignore digest part of images when checking version\n* [`ae1b00354`](https://github.com/siderolabs/talos/commit/ae1b003542d01fc565a8478c9de512c3ea929f3d) feat: support noclooud instance-id from dmi\n* [`58661dea7`](https://github.com/siderolabs/talos/commit/58661dea71a706eaf57f9813b9672395e820e756) docs: update getting-started.md\n* [`94cf9fb84`](https://github.com/siderolabs/talos/commit/94cf9fb8470b88fac6523953ebb083ecf31e4274) chore: fix spurious generate failures\n* [`32a34791e`](https://github.com/siderolabs/talos/commit/32a34791e2e61e77531ccc8f8be92c76c4b83514) fix: typo in Makefile target talosctl-freebsd-arm64\n* [`1b4464c8a`](https://github.com/siderolabs/talos/commit/1b4464c8a65600b923d9790656f25e245db2e0aa) feat: update Kubernetes to 1.32.2\n* [`9463ac23e`](https://github.com/siderolabs/talos/commit/9463ac23e77067f6dce2c22a33e3937357745303) fix: make ingress firewall filter traffic to nodeports\n* [`8531d91a1`](https://github.com/siderolabs/talos/commit/8531d91a1f20ecc587a1b76c13637ab3555718e9) fix: blockdevice transport detection\n* [`ce616d93a`](https://github.com/siderolabs/talos/commit/ce616d93a5799163ae278bac477c4f612197d109) fix: path for ca-certificates\n* [`f35b58779`](https://github.com/siderolabs/talos/commit/f35b58779e912aeec64e6fc0a9964e76e97f9a9f) fix: fix diff printing\n* [`bf0f910a1`](https://github.com/siderolabs/talos/commit/bf0f910a16ce3707cc5741b88a176671a0dd40b3) chore: provide more logging for dns requests\n* [`607998ba2`](https://github.com/siderolabs/talos/commit/607998ba20d62fa13233daf139eb3126ffa6569f) feat: support uki profiles via imager\n* [`711cf2d99`](https://github.com/siderolabs/talos/commit/711cf2d99ac9c16b7a48c20271ecc2c60a3f3d6d) fix: ignore errors to stop pods\n* [`142d75483`](https://github.com/siderolabs/talos/commit/142d754835785cd4edf088e2827854ffc8580262) fix: handle empty registry config\n* [`47f377b21`](https://github.com/siderolabs/talos/commit/47f377b21f546f1950ed43171d6b4f374ab7f721) feat: implement the last ethtool feature - channels\n* [`88cf69b8c`](https://github.com/siderolabs/talos/commit/88cf69b8c5c5f9fd47107289a717f1083ae12807) feat: multi profile UKIs\n* [`557faad75`](https://github.com/siderolabs/talos/commit/557faad759e4f21b7dedc3c69a61d2b3c31e6bc4) feat: update Linux to 6.12.13\n* [`5dbf9e350`](https://github.com/siderolabs/talos/commit/5dbf9e35024192632aecda5fd817ab4558aced1a) refactor: implement volume mount controller\n* [`aa11e9abb`](https://github.com/siderolabs/talos/commit/aa11e9abb78d33ba66a167335b14fc79f4613ef9) fix: make image cache volume management less strict\n* [`26a62e342`](https://github.com/siderolabs/talos/commit/26a62e34211d642ddcdb0cff67013c0d4c640b78) docs: fix typo in Wireguard docs\n* [`0419f5d8b`](https://github.com/siderolabs/talos/commit/0419f5d8ba889faead5452af40fc70c8e1573084) feat: implement features in `ethtool`-like support\n* [`cd66fc6e8`](https://github.com/siderolabs/talos/commit/cd66fc6e8e7e5cf1a17c03de41c1d2e39cb71aa4) feat: use bootstrapped packages for building Talos\n* [`2b5bd5d1d`](https://github.com/siderolabs/talos/commit/2b5bd5d1dad65f653dfd77d363d0a76404099453) chore: upgrade siderolabs/go-loadbalancer\n* [`15191aa3e`](https://github.com/siderolabs/talos/commit/15191aa3e305feba6b5f8b084e6d9b7337e2143f) fix: extract cmdline multi profile UKIs\n* [`716f700da`](https://github.com/siderolabs/talos/commit/716f700da74608aa93c9d335ea17f0fea34865a6) feat: provide initial support for ethtool configuration\n* [`b726e2f9f`](https://github.com/siderolabs/talos/commit/b726e2f9f7057f1e7ed912bea28db3e4b63441cb) feat: update Flannel to 0.26.4\n* [`98d56d4d6`](https://github.com/siderolabs/talos/commit/98d56d4d647d455acc7324d84df05881ebe46d34) chore: track opened grpc connections\n* [`5e28c8e03`](https://github.com/siderolabs/talos/commit/5e28c8e039aae14427571bdd9bf9813ee6220743) fix: image cache volume provisioning\n* [`c9667813d`](https://github.com/siderolabs/talos/commit/c9667813d2b515306a775dabbefad378dc74a0a9) chore: remove containerd importer\n* [`270ffb69a`](https://github.com/siderolabs/talos/commit/270ffb69a39a9b10e3d98c44579eec20de51ba67) fix: duplicate qemu drive ids\n* [`71ec41be1`](https://github.com/siderolabs/talos/commit/71ec41be18541c31e887037bad59a7a3395a2bb1) fix: build of Talos on non-Linux host\n* [`e2aa7c98c`](https://github.com/siderolabs/talos/commit/e2aa7c98ccebca727cac792e53db5722aa79e213) fix: installer with SecureBoot should contain UKIs\n* [`6e22c06c3`](https://github.com/siderolabs/talos/commit/6e22c06c3c4c96bb02d34c7f61633137cd03f6f5) release(v1.10.0-alpha.1): prepare release\n* [`3a2d9867b`](https://github.com/siderolabs/talos/commit/3a2d9867b5cc3236b1d1c7981e5794657f3c155e) fix: do not close client.Client.conn with finalizer\n* [`73f30ff25`](https://github.com/siderolabs/talos/commit/73f30ff25e0adb7a47e2153756e0ea94bd605568) feat: bump pkgs for udev update\n* [`aea90cb8f`](https://github.com/siderolabs/talos/commit/aea90cb8f1dbe7d5f67d35714825133728c1490d) docs: update hyper-v\n* [`b7165615f`](https://github.com/siderolabs/talos/commit/b7165615f86afd09ea85dc91090a40860ae6fc9a) fix: use local NTP for AWS platform\n* [`673ca4bcb`](https://github.com/siderolabs/talos/commit/673ca4bcb2448b3c252fccff0d243932c97fd893) fix: ensure proper closure of client.Client.conn with finalizer\n* [`19040ffd6`](https://github.com/siderolabs/talos/commit/19040ffd6ef128daaf48a820d8826186c82c68c5) fix: handle of PE sections with duplicate names\n* [`83489d348`](https://github.com/siderolabs/talos/commit/83489d348905352497da0f6dc042f3e7f05cd4d7) docs: add note about vmxnet and flannel conflict\n* [`f1292f5e7`](https://github.com/siderolabs/talos/commit/f1292f5e7af4110270475d8bcc4bd39519419e03) docs: add iscsi-tools extension to prerequisites\n* [`93b4a3740`](https://github.com/siderolabs/talos/commit/93b4a3740ba0c35e8b62cbf8c70058d1e53c3b8e) test: bump timeout on rotate CA test\n* [`42e166984`](https://github.com/siderolabs/talos/commit/42e16698453a687a4293e7cfeeb0e09d4f084217) feat: support kexec from uki\n* [`8da264946`](https://github.com/siderolabs/talos/commit/8da264946cda9b4803fd9f2f4dfd0ed25445843b) docs: add Orange Pi 5 to Image Factory platforms and documentation\n* [`c5fb62e2e`](https://github.com/siderolabs/talos/commit/c5fb62e2e32690aa0235b0911ded1888084496a8) feat: update Linux to 6.2.11\n* [`83d007c16`](https://github.com/siderolabs/talos/commit/83d007c161e03311cede2153f35c32f608537290) feat: update etcd to 3.5.18\n* [`edf7c3288`](https://github.com/siderolabs/talos/commit/edf7c328835273e2bc6dd23c646091e6a03aa2e9) fix: pe uki extract\n* [`70f72c5b0`](https://github.com/siderolabs/talos/commit/70f72c5b00bce791d692ec3a0e9a91aaf9d88031) docs: update multus.md\n* [`807a3cd29`](https://github.com/siderolabs/talos/commit/807a3cd291e2e2cb22946826bccb64671a29d901) refactor: all network merge controllers\n* [`ec8c4660e`](https://github.com/siderolabs/talos/commit/ec8c4660e277dc11b5e70c014a0238d48cf15bda) docs: update vmware.md\n* [`baf81cd49`](https://github.com/siderolabs/talos/commit/baf81cd4914470b06393d762f70d0a94f7a9fe32) fix(ci): k8s integration suite wait for resource\n* [`cd5e54903`](https://github.com/siderolabs/talos/commit/cd5e549039b17add0a2ce09713e1a034bb3efccf) feat: generate iso's with both UKI and grub\n* [`75673b6a3`](https://github.com/siderolabs/talos/commit/75673b6a38eeb6361c6e6aeb389e8dbaaacb8b0b) feat: provide stable symlinks in disk resources\n* [`f407c88e4`](https://github.com/siderolabs/talos/commit/f407c88e4678ff6d5edb940f5d54461104be3643) fix(ci): wait for longhorn node resource\n* [`601cdccb9`](https://github.com/siderolabs/talos/commit/601cdccb979640a6b2ffcba41cc698015b1dacde) feat: extract kernel/initrd from uki for grub\n* [`ff175b9fb`](https://github.com/siderolabs/talos/commit/ff175b9fbdb2ac92ac53351d32de130bd0676038) docs: update disk-encryption.md\n* [`a8d84e315`](https://github.com/siderolabs/talos/commit/a8d84e3155137a114ad00ad7ae321af033020e7d) docs: fix typos and add more explanations in docs\n* [`3a384240e`](https://github.com/siderolabs/talos/commit/3a384240ecf660d310f2df98327f018649ebaa6d) fix: invalid date field in iqn/nqn\n* [`82c9ec158`](https://github.com/siderolabs/talos/commit/82c9ec158e82efea80daaf76fef9fbd31c3eb823) chore(ci): add tests with longhorn v2 engine\n* [`689ea1dbf`](https://github.com/siderolabs/talos/commit/689ea1dbfe29d70d91e0b41d31fc696e2ff96665) fix: bring back disk UUID\n* [`7a712fad2`](https://github.com/siderolabs/talos/commit/7a712fad2abb916f397a8dd0aebf66e59ee75904) fix: disks with 4k sector size and systemd-boot\n* [`d62a34aaf`](https://github.com/siderolabs/talos/commit/d62a34aaf4e4ff7dad9f6dbeb59a67016c70fffb) feat: update tools/pkgs/extras\n* [`b9a8ad6ac`](https://github.com/siderolabs/talos/commit/b9a8ad6acafd64c4217ba914184592c0cfb97962) chore: de-hardcode list of extra images for image-cache test\n* [`683153a33`](https://github.com/siderolabs/talos/commit/683153a33c1069e7f7cadf4e3a70bde3f8ba3331) docs: remove the last mentions of `preserve` flag for Talos 1.8+\n* [`33c7f4195`](https://github.com/siderolabs/talos/commit/33c7f4195816988af6f70199fdb4a31d027fa746) docs: fix typo an MacOS to on MacOS\n* [`21cff3919`](https://github.com/siderolabs/talos/commit/21cff3919b80f33f837b19728500fcb91e7caf8f) chore(ci): fio benchmark results as separate artifacts\n* [`0b7fc7cdf`](https://github.com/siderolabs/talos/commit/0b7fc7cdfea651a6f16db3f346473505d8df3e78) fix: abort node watch on hostname change\n* [`99ba53941`](https://github.com/siderolabs/talos/commit/99ba53941cecdc54c0ececa9876b25a7fc7668a5) docs: remove the mention of `preserve` flag for Talos 1.8+\n* [`bde516fde`](https://github.com/siderolabs/talos/commit/bde516fde62a25dd60691a9a3b6f3d30de11dad1) chore(ci): rework iscsi-tools extensions test\n* [`e1efbf656`](https://github.com/siderolabs/talos/commit/e1efbf656ae96ecedba1c132608c3ad2d3ae4a66) refactor: extract platform metadata into Talos machinery\n* [`79987c05d`](https://github.com/siderolabs/talos/commit/79987c05dcd39ca646c2d73c1e25488504f13a60) feat: generate iqn and nqn files\n* [`0cab6ed17`](https://github.com/siderolabs/talos/commit/0cab6ed170708549d69c04b163744854de0aa8f2) docs: update troubleshooting.md\n* [`921e10254`](https://github.com/siderolabs/talos/commit/921e10254d443c459a9775368ca080ecba273321) chore: update Go to 1.23.5\n* [`399d53b54`](https://github.com/siderolabs/talos/commit/399d53b543f6ca99f13d28313ae77b3472b0f728) fix: ignore forbidden error when waiting for pod eviction\n* [`8dea57a81`](https://github.com/siderolabs/talos/commit/8dea57a81b8393b518da60951713c711659291f9) fix: make etc binds read-only\n* [`63157dcb4`](https://github.com/siderolabs/talos/commit/63157dcb496ca767bfbff9e1b86f14277a44cdb7) docs: update SideroLinkConfig example\n* [`fc7080e34`](https://github.com/siderolabs/talos/commit/fc7080e34b990d2d50ec1e40734437ccd0ee95f7) chore: clear cache after updating upstreams\n* [`51e0f273f`](https://github.com/siderolabs/talos/commit/51e0f273f9199b8320cd5da247c702a4319a92c5) docs: update documentation for Talos 1.9.2\n* [`e06b14112`](https://github.com/siderolabs/talos/commit/e06b14112d2c978e3f6b5c4446090a7ae533ead9) feat: update Kubernetes to 1.32.1\n* [`4310b290d`](https://github.com/siderolabs/talos/commit/4310b290d5cff9697f86cc24f1c281e62cb7d72f) fix: generate UKI only if actually needed\n* [`a8cd99102`](https://github.com/siderolabs/talos/commit/a8cd991026fe7290013b7504a4e87af46c49d25b) docs: update OpenEBS Mayastor installation\n* [`cf45f4764`](https://github.com/siderolabs/talos/commit/cf45f4764ddd979fa81576833d9630eadea24f41) docs: add Radxa ROCK 5B docs to Single Board Computer section\n* [`b21bdc5e5`](https://github.com/siderolabs/talos/commit/b21bdc5e501bc2244e3e487827ffba79075f6642) chore(ci): save csi tests fio results\n* [`01c86832c`](https://github.com/siderolabs/talos/commit/01c86832cbbbe0b81b9500032f94298fd6e90b58) chore(ci): add test for OpenEBS MayaStor\n* [`c77483510`](https://github.com/siderolabs/talos/commit/c774835103ad139b44d7e4e13c003e2b13160347) test: update `talosctl debug air-gapped`\n* [`ddd695d93`](https://github.com/siderolabs/talos/commit/ddd695d933d39920da42219ba8b3d39b0681a3ea) feat: update containerd to 2.0.2\n* [`da2e81120`](https://github.com/siderolabs/talos/commit/da2e81120f7336d9633a98523e05d91f5750434f) fix: add informer resync period for node status watcher\n* [`9b957df64`](https://github.com/siderolabs/talos/commit/9b957df64680a97a16575db67d4af27cfc0ef7d2) chore: uki code restructure\n* [`e41a99525`](https://github.com/siderolabs/talos/commit/e41a995253428dde437eecec52cabfb4c80f90ea) fix: kube-apiserver authorizers order\n* [`db4ca5668`](https://github.com/siderolabs/talos/commit/db4ca5668ac0d85a98a5ea022f6546526d20aff1) feat: add a kernel parameter to disable built-in auditd\n* [`faa149003`](https://github.com/siderolabs/talos/commit/faa1490033df0a843010fa7154096d84f415afce) feat: update Linux to 6.12.9\n* [`8de19758d`](https://github.com/siderolabs/talos/commit/8de19758dafce802c0f93a63ae3083b5ad17162d) fix: a couple of imager panics/crashes\n* [`5bc3e34cb`](https://github.com/siderolabs/talos/commit/5bc3e34cb3a6fd8e3eb5d02dd612cf3cf9dc499f) fix: detect GPT before ZFS\n* [`ed7e47d15`](https://github.com/siderolabs/talos/commit/ed7e47d158e064204b2f14f9ff378bea70e9524e) refactor: drop usage of objcopy to generate UKIs\n* [`edf5c5e29`](https://github.com/siderolabs/talos/commit/edf5c5e29bc76299c63bb04f1d97a030ecb9b3f0) fix: extfs repair and resize\n* [`6e32ea5b7`](https://github.com/siderolabs/talos/commit/6e32ea5b7f1a22500014ecb365e13af36034187a) fix: merge of VolumeConfig documents with sizes\n* [`1be5f8ff2`](https://github.com/siderolabs/talos/commit/1be5f8ff25ac7042ee3334f657d6604ec5f8501d) feat: update Linux to 6.12.8\n* [`e6a4583ba`](https://github.com/siderolabs/talos/commit/e6a4583ba862da9f49ab0bd0cb6bc8436723bc67) feat: support generating unsigned UKIs\n* [`bbd6067d4`](https://github.com/siderolabs/talos/commit/bbd6067d426fb2be22ff8935f415ab6d729d8f19) fix: partition alignment on disks with 4k sectors\n* [`84fcc976f`](https://github.com/siderolabs/talos/commit/84fcc976f8da5af310771e1835a0347df5bcc97d) fix: yet another dashboard panic\n* [`6d605fc85`](https://github.com/siderolabs/talos/commit/6d605fc8595e2f06e43529966e396f2ae403c76c) fix: disable NRI plugin in a different way\n* [`499695e24`](https://github.com/siderolabs/talos/commit/499695e24ea02ffc2fd8c92276d5de41b0d4919e) fix: request previous IP address in discovery\n* [`cc84caf8c`](https://github.com/siderolabs/talos/commit/cc84caf8c0dffd9d59f360f84967c524be9ba369) docs: update Cilium documentation\n* [`fa5300d91`](https://github.com/siderolabs/talos/commit/fa5300d910a537f03939fcbf6362abdd8fa607dd) chore: revert: drop deprecated allowSchedulingOnMasters\n* [`0abb3dabf`](https://github.com/siderolabs/talos/commit/0abb3dabf6d50b9c1176af683ad74234334f822d) docs: fix command to wait for ceph-rook HEALTH_OK\n* [`32c67c27c`](https://github.com/siderolabs/talos/commit/32c67c27c393c989f9d70ccb8506c4735f70d494) chore: drop deprecated allowSchedulingOnMasters\n* [`ae6d065be`](https://github.com/siderolabs/talos/commit/ae6d065beb4897a1b877ecb30b06be456befbf91) fix: mount selinuxfs only when SELinux is enabled\n* [`5ccbf4bcd`](https://github.com/siderolabs/talos/commit/5ccbf4bcdbe9aa2096320d17eb2deab6a062faf9) feat: enable `configfs`\n* [`59582496d`](https://github.com/siderolabs/talos/commit/59582496d5fe419f833703be8e956163b6241d15) feat: bring in partity with sd-257\n* [`83d84a831`](https://github.com/siderolabs/talos/commit/83d84a831862c774b9bc2adc2e11e00bf2a79912) chore(ci): better zfs checks\n* [`650eb3a4f`](https://github.com/siderolabs/talos/commit/650eb3a4f2d89d173cdd6581a6d1232511a8e219) refactor: rewrite cloud uploader to use AWS SDK Go v2\n* [`01bf8449b`](https://github.com/siderolabs/talos/commit/01bf8449b917ece76336ca7f0eb11fd877195025) fix: update field name for bus path disk selector\n* [`e915c98d5`](https://github.com/siderolabs/talos/commit/e915c98d583e5901c1c2efe38efa656b39d72360) fix: exclude disks with empty transport for disk selector\n* [`b7a7fdc4b`](https://github.com/siderolabs/talos/commit/b7a7fdc4b8a715157bfa2614c9541b96643cd2ba) refactor: generate /etc/os-release file static way\n* [`e79c9e127`](https://github.com/siderolabs/talos/commit/e79c9e12772c998ff5b3e401efd7f074f85e5cef) chore(ci): drop equinix metal e2e-test\n* [`418945444`](https://github.com/siderolabs/talos/commit/418945444135c6d9e2e5960e7b9cbd754084fea2) fix: build of talosctl on non-Linux platforms\n* [`4761a9e6a`](https://github.com/siderolabs/talos/commit/4761a9e6aa0bf619a564807d02ebce030384d6a1) chore: update dependencies\n* [`f98efb333`](https://github.com/siderolabs/talos/commit/f98efb333f89b8493c55b91698c917437b7af310) fix: ignore member not found error on leave cluster\n* [`b72bda0a4`](https://github.com/siderolabs/talos/commit/b72bda0a420f75ea0439cc0240dcf6d3363e5d48) fix: talosctl support and race tests\n* [`27233cf0f`](https://github.com/siderolabs/talos/commit/27233cf0fcf4031cbc8001504bed67b6d4a104f9) test: use node informer instead of raw watch\n* [`5dc15e8db`](https://github.com/siderolabs/talos/commit/5dc15e8db459ac632f0ae106e1cfc7eaab672adf) fix: update go-blockdevice to v2.0.9\n* [`5f3acd0f2`](https://github.com/siderolabs/talos/commit/5f3acd0f26a35ac966d4ced01436f1dd3c03648b) fix: use correct default search domain\n* [`7e5d36d46`](https://github.com/siderolabs/talos/commit/7e5d36d469ff01153f40b16ab722f0ebe25d41ae) fix: pci driver rebind config validation\n* [`4b97bbc3f`](https://github.com/siderolabs/talos/commit/4b97bbc3fee1257d0d21be25e21493bfd1f45a80) fix: pull in containerd CNI deadlock fix\n* [`066480722`](https://github.com/siderolabs/talos/commit/0664807229e0688f092a453cbd3121dbe189ca39) test: fix apparmor tests\n* [`82ea44a6b`](https://github.com/siderolabs/talos/commit/82ea44a6b2aa0a35861ca454a09503a81332f824) fix: reduce installer image\n* [`78b3e7f4f`](https://github.com/siderolabs/talos/commit/78b3e7f4f1870085b719971c6f92dc866fe1e9d0) fix: get next rule number for IPv6 in the appropriate chain\n* [`675854aa0`](https://github.com/siderolabs/talos/commit/675854aa03b3913da3481337d995c206174cf004) docs: fix two typos\n* [`f70b7386a`](https://github.com/siderolabs/talos/commit/f70b7386ac3125f3b8ab6b1765338c7e3445ae5c) test: add a xfs makefs test\n* [`8212e4864`](https://github.com/siderolabs/talos/commit/8212e4864d11e69ed63be3f4e608e9ccbc788cc4) refactor: use quirks in kernel args\n* [`b4aa5189d`](https://github.com/siderolabs/talos/commit/b4aa5189d4d4565a42ad7ac8de24c424a215b42f) release(v1.10.0-alpha.0): prepare release\n* [`bd85bd5b7`](https://github.com/siderolabs/talos/commit/bd85bd5b731463a42b7c82c66e9add251a280d26) fix: fix `Failed to initialize SELinux labeling handle` udev error\n* [`73c82e3e5`](https://github.com/siderolabs/talos/commit/73c82e3e5625ec1899f93312a671dfe6dffaea61) feat: bring Linux 6.12.6, CNI plugins 1.6.1\n* [`c12b52491`](https://github.com/siderolabs/talos/commit/c12b52491456d1e52204eb290d0686a317358c7c) docs: document Kubernetes service registry incompat with K8s 1.32\n* [`a5660ed77`](https://github.com/siderolabs/talos/commit/a5660ed778108843fe15b2b1582dd6556cf52b6c) feat: pcirebind controller\n* [`4c3261626`](https://github.com/siderolabs/talos/commit/4c3261626fa3f5ac36df71ec878f103a7c85c5c5) docs: fix several typos\n* [`fb3675321`](https://github.com/siderolabs/talos/commit/fb36753216cba7740040f2ec117c783221f66192) fix: dashboard crash on CPU data\n* [`dec0185c8`](https://github.com/siderolabs/talos/commit/dec0185c8505a7d43244fdb01f7a5decc77d116d) chore: reduce memory usage for secureboot functions\n* [`cee6c60a0`](https://github.com/siderolabs/talos/commit/cee6c60a0fc301b22c50fdf8bd2fc1d2b7ba3d54) fix: make talosctl time work with PTP time sync\n* [`f75604313`](https://github.com/siderolabs/talos/commit/f75604313d535180c38b33df53253ad4acba2ec1) chore: support gcr.io auth for cache and image gen\n* [`6ef2596da`](https://github.com/siderolabs/talos/commit/6ef2596da7b7e8be90e5b981621461352be7b134) docs: improve Hetzner documentation\n* [`7d39b9ec2`](https://github.com/siderolabs/talos/commit/7d39b9ec2bdd7883116626bf889c1331717f8438) feat: remove cgroupsv1 in non-container mode\n* [`8003536c7`](https://github.com/siderolabs/talos/commit/8003536c7ca20356adcd900e64463bd166d445af) fix: restore previous disk serial fetching\n* [`03116ef9b`](https://github.com/siderolabs/talos/commit/03116ef9bd2a215c20a2c4c7db133dd857ce2b16) chore: prepare for Talos 1.10\n* [`00682fdd6`](https://github.com/siderolabs/talos/commit/00682fdd6e8fa23c6f9782840ea3e2b8ef250f66) docs: activate 1.9 docs as default\n* [`bea05f5c9`](https://github.com/siderolabs/talos/commit/bea05f5c9b6ce6f5d067eb357d26e30a49154b21) docs: update deploying-cilium.md\n* [`284ab1179`](https://github.com/siderolabs/talos/commit/284ab11794b3b076aa9ab2bb756e02292d854751) feat: support link altnames/aliases\n* [`5bfd829bf`](https://github.com/siderolabs/talos/commit/5bfd829bf9c8e46b6c51174be4b764d4c94b3320) docs: fix 'containter' typo\n* [`8d151b771`](https://github.com/siderolabs/talos/commit/8d151b771debc51d3fa40dfafc7a2e43f955a634) docs: clarify TALOSCONFIG for AWS\n* [`0ef19171f`](https://github.com/siderolabs/talos/commit/0ef19171f738e46346dfae71f43b8f7b47bf257d) fix: renovate typo\n* [`c568adc7d`](https://github.com/siderolabs/talos/commit/c568adc7dcd52c34924acc1eae849a2ca5b5a4d5) fix: renovate config\n* [`ec2e24fd9`](https://github.com/siderolabs/talos/commit/ec2e24fd9617db34e3bec753b5fe720670fa31a4) fix: match MAC addresses case-insensitive (nocloud)\n* [`41a0c440a`](https://github.com/siderolabs/talos/commit/41a0c440ad3f4de2a2ba9198d22609c55bdaf61b) chore: rekres for renovate changes\n* [`a49bb9ee4`](https://github.com/siderolabs/talos/commit/a49bb9ee45346268b26d3b9cff4dd017bfb9c829) feat: update Linux to 6.12.5\n* [`b15917ecc`](https://github.com/siderolabs/talos/commit/b15917ecc626781e13de0e84b794ab77c97b3159) chore: add more debugging logs for META and volumes\n* [`2b1b326f0`](https://github.com/siderolabs/talos/commit/2b1b326f08966615a5a2f8708f94e6d1355773a7) docs: mention different paths for OpenEBS\n* [`9470e842f`](https://github.com/siderolabs/talos/commit/9470e842fca2d7dd0dae185bff7210a8af355445) test: cleanup failed Kubernetes pods\n* [`c9c685150`](https://github.com/siderolabs/talos/commit/c9c6851504fcda7b66395fbbba1fbc8b0e085d4a) fix: node identity flip\n* [`590c01657`](https://github.com/siderolabs/talos/commit/590c0165712aee60e752766d6bd3875443c353cb) feat: update containerd to v2.0.1\n* [`18fa5a258`](https://github.com/siderolabs/talos/commit/18fa5a25876f41760ce8da5e918222e04b81949a) docs: update image-cache doc for iso\n* [`ab5bb6884`](https://github.com/siderolabs/talos/commit/ab5bb688420986a356aed55513a1dbd25de323e2) fix: generate and serve registries with port\n* [`58236066d`](https://github.com/siderolabs/talos/commit/58236066ddbcd7c401e945b70555ff315a2458f7) fix: support image cache on VFAT USB stick\n* [`e193a5071`](https://github.com/siderolabs/talos/commit/e193a507149c05e341abe019de219fe0b1bc83e3) fix: image cache integration test\n* [`08ee400fd`](https://github.com/siderolabs/talos/commit/08ee400fdbde368a54d6777cc31ceb91e1968ad2) test: fix flaky test NodeAddressSort\n* [`d45e8d1d1`](https://github.com/siderolabs/talos/commit/d45e8d1d1da28ca1b311198588d723cb491527eb) feat: update Kubernetes to 1.32.0\n* [`136b12912`](https://github.com/siderolabs/talos/commit/136b12912165d5eb5c7c716b7f7dfcfbc42b08d4) chore: drop semicolon for supporting vfat filesystems\n* [`3e9e027ef`](https://github.com/siderolabs/talos/commit/3e9e027efbd2988f72eb2da0c1ab0e83ba52b950) test: add an option to boot from an USB stick\n* [`ef8c3e3b3`](https://github.com/siderolabs/talos/commit/ef8c3e3b3b245f7ffefa6c19930d5a0925ce666b) docs: fix typo in multus.md\n* [`d54414add`](https://github.com/siderolabs/talos/commit/d54414add4e4df1b5a7b166f155cdcca512d4ee2) fix: authorization config gen\n* [`cce72cfe8`](https://github.com/siderolabs/talos/commit/cce72cfe86beeb7ada9641df611046f4789e3bd8) docs: replace deprecated Hetzner server plans\n* [`81805103d`](https://github.com/siderolabs/talos/commit/81805103deada24b12b7d7861b2df5a5c788c86b) chore: enable proper parallel usage of TestDepth\n* [`e1b824eba`](https://github.com/siderolabs/talos/commit/e1b824ebada3d3dad9d2793fd12b5a948d8b51b5) docs: update ceph-with-rook.md\n* [`470b75563`](https://github.com/siderolabs/talos/commit/470b75563add4ce5bbce312c1e3dc783e63af1fa) fix: use mtu network option for podman\n* [`61b1489a0`](https://github.com/siderolabs/talos/commit/61b1489a0f0868c5b7e124544520bc46badef85c) fix: order volume config by the requested size\n* [`bc3039acd`](https://github.com/siderolabs/talos/commit/bc3039acdbc57e6be16a1bc6555894dff2da65c9) feat: update runc to 1.2.3\n* [`30016a0a8`](https://github.com/siderolabs/talos/commit/30016a0a8d98d42e01c4d32acf9e600777d72d57) fix: avoid nil-pointer-panic in `RegistriesConfigController`\n* [`fe0457152`](https://github.com/siderolabs/talos/commit/fe045715277a4678b8e8c9632ec71e86bf17ace0) fix: power on the machine on reboot request in qemu power api\n* [`10da553ef`](https://github.com/siderolabs/talos/commit/10da553ef0dde5f87f09321400239baa51929a36) docs: build what's new for 1.9\n* [`d946ccae3`](https://github.com/siderolabs/talos/commit/d946ccae31b87559a06cb1cefcefe8f937b73d8b) feat: update Linux to 6.12.4\n* [`707a77bf6`](https://github.com/siderolabs/talos/commit/707a77bf64190470bf84c91cdff185981e80a31b) test: fix user namespace test, TPM2 fixes\n* [`c3537b2f5`](https://github.com/siderolabs/talos/commit/c3537b2f5491a890f626ba8fc47034d5059808af) feat: update Linux to 6.12.3\n* [`cb4d9d673`](https://github.com/siderolabs/talos/commit/cb4d9d673432e4a0fba0d87bc64fde620d991082) docs: fix a few mistakes in release notes\n* [`c4724fc97`](https://github.com/siderolabs/talos/commit/c4724fc97598d8764b00fb56971d997a349a92e5) chore: add integration tests for image-cache\n* [`07220fe7f`](https://github.com/siderolabs/talos/commit/07220fe7f5a22444f7a085f5868f628ddd912b6d) fix: install iptables-nft to the host\n* [`14841750b`](https://github.com/siderolabs/talos/commit/14841750bf2fc09a9de0b32a7af0dc3f76e1019a) chore: add version compatibility for Talos 1.10\n* [`852baf819`](https://github.com/siderolabs/talos/commit/852baf819d453a3d8d58ae9f029e280ae75e0cb1) feat: support vlan/bond in v1, vlan in v2 for nocloud\n* [`dd61ad861`](https://github.com/siderolabs/talos/commit/dd61ad86105c07c1ff8a101a0542af61699f0df3) fix: lock provisioning order of user disk partitions\n* [`d0773ff09`](https://github.com/siderolabs/talos/commit/d0773ff09df84b2dac8ecadc91023596050ce098) chore: update Go to 1.23.4\n* [`7d6507189`](https://github.com/siderolabs/talos/commit/7d6507189ff9a99b3b05ee9528701b65af4ad147) feat: implement new address sorting algorithm\n* [`9081506d6`](https://github.com/siderolabs/talos/commit/9081506d6cde26d60a29f08a090e28da501e4bd1) feat: add process scheduling options\n* [`77e9db4ab`](https://github.com/siderolabs/talos/commit/77e9db4abf9c9b694d60c8803b436121dfe30ccd) test: use two workers in qemu tests by default\n* [`5a4bdf62a`](https://github.com/siderolabs/talos/commit/5a4bdf62a9bf1387b6489eaf2c9cc0770aa0b68c) feat: update Kubernetes to 1.32.0-rc.1\n* [`d99bcc950`](https://github.com/siderolabs/talos/commit/d99bcc95031037f4b0990419d2ce1fd4280cbde9) chore: refactor mergeDNSServers func\n* [`0cde08d8b`](https://github.com/siderolabs/talos/commit/0cde08d8be1ad62c49fed148fd331ea5a212df4c) docs: add Turing RK1 docs to Single Board Computer section\n</p>\n</details>\n\n### Changes since v1.10.0-alpha.1\n<details><summary>57 commits</summary>\n<p>\n\n* [`d4e3e957c`](https://github.com/siderolabs/talos/commit/d4e3e957cb98d3fe6ee6685a807c25fafb128423) fix(ci): fix integration tests\n* [`1849b5388`](https://github.com/siderolabs/talos/commit/1849b53881e1ab12b28f9d8b537c8e43d607b4ea) feat: update dependencies\n* [`88fc6bbeb`](https://github.com/siderolabs/talos/commit/88fc6bbebeff1c0db0e43fb0a83d2b03a973da8a) test: fix UKI preserving talos.config and image cache\n* [`ba8cd304d`](https://github.com/siderolabs/talos/commit/ba8cd304d2029c93c31135b2003b1f2f064ff29f) test: enable image-cache in the cron\n* [`28b5dc738`](https://github.com/siderolabs/talos/commit/28b5dc738cd7af5bb06604b2778f808827544ee0) test: fix reproduciblity test\n* [`50998038b`](https://github.com/siderolabs/talos/commit/50998038bb45e33438cccdd8fba4c156f0f7b0b5) feat: prefer sd-boot for UEFI\n* [`e831e52e0`](https://github.com/siderolabs/talos/commit/e831e52e01a47f34e982e9cfa397ca9722094a82) feat: add support for qla2xx\n* [`ec5c049a5`](https://github.com/siderolabs/talos/commit/ec5c049a5a5063289a97271c2d145d298f5f1a43) feat: update Kubernetes to 1.33.0-alpha.2\n* [`ebfa82f35`](https://github.com/siderolabs/talos/commit/ebfa82f3558e5a44a332a0576416ce61f8235407) docs: update deprecated command\n* [`d79059a2c`](https://github.com/siderolabs/talos/commit/d79059a2c96565b1524b3869ad6b28f1cd8351da) chore: fix shutdown typo in shutdown sequence\n* [`a3f88d2ef`](https://github.com/siderolabs/talos/commit/a3f88d2ef5b726e1256a070a961bd4931d453a6a) fix: block NodePort services with ingress firewall\n* [`fd8131cb8`](https://github.com/siderolabs/talos/commit/fd8131cb86714b450334508abc0891eeaa2da9c8) feat: generate unified installer\n* [`ebfdb91b4`](https://github.com/siderolabs/talos/commit/ebfdb91b4cd36b48c36c1523dc74bc6e1860f815) fix: handle dynamic HTTP proxy settings for discovery client\n* [`d45eaeb74`](https://github.com/siderolabs/talos/commit/d45eaeb74cc43cc3154fcbce474958a613bc561b) fix: correctly map link names/aliases when using VIP operator\n* [`7c4e47c0c`](https://github.com/siderolabs/talos/commit/7c4e47c0c00e740bf0d63521baa1231354bc1966) chore: stop doing generate on each build\n* [`b1d410cb6`](https://github.com/siderolabs/talos/commit/b1d410cb6203f8a3847472db3990d2634bab22e2) feat: dual boot disk image\n* [`468e318ba`](https://github.com/siderolabs/talos/commit/468e318ba4137e1f11d231fe3ed66f10543073e3) fix: multiple fixes for dashboard/no data\n* [`3dd8d9aed`](https://github.com/siderolabs/talos/commit/3dd8d9aed8d311f84c61f3030fbf2031ee1d3df9) docs: update resetting-a-machine.md to include example of reset\n* [`7af8f6b2f`](https://github.com/siderolabs/talos/commit/7af8f6b2fa98f1ed4ad5adbcea6d54802013a086) feat: validate docker image references in upgrade options\n* [`c949f55e6`](https://github.com/siderolabs/talos/commit/c949f55e61b8c74202f2da50829c2e034e43682e) docs: remove typo on resetting a machine page\n* [`f5c097041`](https://github.com/siderolabs/talos/commit/f5c097041faac04808636703c94fe5d3ee208947) feat: add description to schema object defs\n* [`79ee304e1`](https://github.com/siderolabs/talos/commit/79ee304e11df7cfb2ccc6eeeb39ab6112975db45) chore: update enumer to a version that fixes Go 1.24 compatibility\n* [`46d67fe44`](https://github.com/siderolabs/talos/commit/46d67fe446edfabe23e3e8a91cc1f07436827c5e) chore: update Go to 1.24, update pkgs\n* [`7f1dd2669`](https://github.com/siderolabs/talos/commit/7f1dd2669734f496afbec6812a814d70dbaee3b4) fix(ci): fix integration-misc crons\n* [`26a773d3f`](https://github.com/siderolabs/talos/commit/26a773d3f27572a01d146ed356be5e78f8dc23e0) docs: add a note about syslog sending messages to services\n* [`7ce053638`](https://github.com/siderolabs/talos/commit/7ce053638db9c9abd4d966d412986c07615a750e) fix: ignore digest part of images when checking version\n* [`ae1b00354`](https://github.com/siderolabs/talos/commit/ae1b003542d01fc565a8478c9de512c3ea929f3d) feat: support noclooud instance-id from dmi\n* [`58661dea7`](https://github.com/siderolabs/talos/commit/58661dea71a706eaf57f9813b9672395e820e756) docs: update getting-started.md\n* [`94cf9fb84`](https://github.com/siderolabs/talos/commit/94cf9fb8470b88fac6523953ebb083ecf31e4274) chore: fix spurious generate failures\n* [`32a34791e`](https://github.com/siderolabs/talos/commit/32a34791e2e61e77531ccc8f8be92c76c4b83514) fix: typo in Makefile target talosctl-freebsd-arm64\n* [`1b4464c8a`](https://github.com/siderolabs/talos/commit/1b4464c8a65600b923d9790656f25e245db2e0aa) feat: update Kubernetes to 1.32.2\n* [`9463ac23e`](https://github.com/siderolabs/talos/commit/9463ac23e77067f6dce2c22a33e3937357745303) fix: make ingress firewall filter traffic to nodeports\n* [`8531d91a1`](https://github.com/siderolabs/talos/commit/8531d91a1f20ecc587a1b76c13637ab3555718e9) fix: blockdevice transport detection\n* [`ce616d93a`](https://github.com/siderolabs/talos/commit/ce616d93a5799163ae278bac477c4f612197d109) fix: path for ca-certificates\n* [`f35b58779`](https://github.com/siderolabs/talos/commit/f35b58779e912aeec64e6fc0a9964e76e97f9a9f) fix: fix diff printing\n* [`bf0f910a1`](https://github.com/siderolabs/talos/commit/bf0f910a16ce3707cc5741b88a176671a0dd40b3) chore: provide more logging for dns requests\n* [`607998ba2`](https://github.com/siderolabs/talos/commit/607998ba20d62fa13233daf139eb3126ffa6569f) feat: support uki profiles via imager\n* [`711cf2d99`](https://github.com/siderolabs/talos/commit/711cf2d99ac9c16b7a48c20271ecc2c60a3f3d6d) fix: ignore errors to stop pods\n* [`142d75483`](https://github.com/siderolabs/talos/commit/142d754835785cd4edf088e2827854ffc8580262) fix: handle empty registry config\n* [`47f377b21`](https://github.com/siderolabs/talos/commit/47f377b21f546f1950ed43171d6b4f374ab7f721) feat: implement the last ethtool feature - channels\n* [`88cf69b8c`](https://github.com/siderolabs/talos/commit/88cf69b8c5c5f9fd47107289a717f1083ae12807) feat: multi profile UKIs\n* [`557faad75`](https://github.com/siderolabs/talos/commit/557faad759e4f21b7dedc3c69a61d2b3c31e6bc4) feat: update Linux to 6.12.13\n* [`5dbf9e350`](https://github.com/siderolabs/talos/commit/5dbf9e35024192632aecda5fd817ab4558aced1a) refactor: implement volume mount controller\n* [`aa11e9abb`](https://github.com/siderolabs/talos/commit/aa11e9abb78d33ba66a167335b14fc79f4613ef9) fix: make image cache volume management less strict\n* [`26a62e342`](https://github.com/siderolabs/talos/commit/26a62e34211d642ddcdb0cff67013c0d4c640b78) docs: fix typo in Wireguard docs\n* [`0419f5d8b`](https://github.com/siderolabs/talos/commit/0419f5d8ba889faead5452af40fc70c8e1573084) feat: implement features in `ethtool`-like support\n* [`cd66fc6e8`](https://github.com/siderolabs/talos/commit/cd66fc6e8e7e5cf1a17c03de41c1d2e39cb71aa4) feat: use bootstrapped packages for building Talos\n* [`2b5bd5d1d`](https://github.com/siderolabs/talos/commit/2b5bd5d1dad65f653dfd77d363d0a76404099453) chore: upgrade siderolabs/go-loadbalancer\n* [`15191aa3e`](https://github.com/siderolabs/talos/commit/15191aa3e305feba6b5f8b084e6d9b7337e2143f) fix: extract cmdline multi profile UKIs\n* [`716f700da`](https://github.com/siderolabs/talos/commit/716f700da74608aa93c9d335ea17f0fea34865a6) feat: provide initial support for ethtool configuration\n* [`b726e2f9f`](https://github.com/siderolabs/talos/commit/b726e2f9f7057f1e7ed912bea28db3e4b63441cb) feat: update Flannel to 0.26.4\n* [`98d56d4d6`](https://github.com/siderolabs/talos/commit/98d56d4d647d455acc7324d84df05881ebe46d34) chore: track opened grpc connections\n* [`5e28c8e03`](https://github.com/siderolabs/talos/commit/5e28c8e039aae14427571bdd9bf9813ee6220743) fix: image cache volume provisioning\n* [`c9667813d`](https://github.com/siderolabs/talos/commit/c9667813d2b515306a775dabbefad378dc74a0a9) chore: remove containerd importer\n* [`270ffb69a`](https://github.com/siderolabs/talos/commit/270ffb69a39a9b10e3d98c44579eec20de51ba67) fix: duplicate qemu drive ids\n* [`71ec41be1`](https://github.com/siderolabs/talos/commit/71ec41be18541c31e887037bad59a7a3395a2bb1) fix: build of Talos on non-Linux host\n* [`e2aa7c98c`](https://github.com/siderolabs/talos/commit/e2aa7c98ccebca727cac792e53db5722aa79e213) fix: installer with SecureBoot should contain UKIs\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`0d45dee`](https://github.com/siderolabs/crypto/commit/0d45deefbcdd4bd6b6e549433b859083df55fc16) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`64513a6`](https://github.com/siderolabs/discovery-api/commit/64513a6c4fb31c6a043159d5caea1d153ea133a4) feat: rekres, regenerate proto files\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b3632c4`](https://github.com/siderolabs/discovery-client/commit/b3632c4a8cd96ae36337e83308ef447361b51537) feat: support extra dial options in the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>6 commits</summary>\n<p>\n\n* [`4102a78`](https://github.com/siderolabs/extras/commit/4102a783a23e298f3c7e600cb4dfb7a04888eaaf) feat: build hermetically using new bldr and pkgs\n* [`f4a110f`](https://github.com/siderolabs/extras/commit/f4a110f5f4b472743dc023413dca280bce491ec1) fix: build tc-redirect-tap as static binary\n* [`0840abb`](https://github.com/siderolabs/extras/commit/0840abb9b5e32560ff38577151fdc2f51812ce31) fix: pull in fixed CNI plugins from pkgs\n* [`52c217f`](https://github.com/siderolabs/extras/commit/52c217f693366bdf21772919ad94933fd160c5d4) feat: update dependencies\n* [`f755eb4`](https://github.com/siderolabs/extras/commit/f755eb483647d17e487f7cb62de8cc150a420c3c) chore: rekres to simplify `.kres.yaml` defaults\n* [`e5382fc`](https://github.com/siderolabs/extras/commit/e5382fc5f05d7ccfdb7c95819195caceac8ffcbf) chore: kresify renovate\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`5ae3afe`](https://github.com/siderolabs/gen/commit/5ae3afee65490ca9f4bd32ea41803ab3a17cad7e) chore: update hashtriemap implementation from the latest upstream\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>2 commits</summary>\n<p>\n\n* [`015a398`](https://github.com/siderolabs/go-circular/commit/015a398e79f2853714cd20d1135dc100f18b6c29) fix: replace static buffer allocation on growth\n* [`ed8685e`](https://github.com/siderolabs/go-circular/commit/ed8685e0cf9491d9a714e565e0e736439a94a73f) test: add more assertions for write length result\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`ea108ca`](https://github.com/siderolabs/go-debug/commit/ea108cacca8940426149e67ba00e414633e4ef3f) chore: add support for Go 1.24\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>1 commit</summary>\n<p>\n\n* [`804cb44`](https://github.com/siderolabs/go-kubernetes/commit/804cb440c2299488c7c68185c53b91ffdfb8bf32) feat: add support for Kubernetes to 1.33\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`589c33a`](https://github.com/siderolabs/go-loadbalancer/commit/589c33a96ac74a8c0e36b09f534fca62afd6de81) chore: upgrade `upstream.List` and `loadbalancer.TCP` to Go 1.23\n</p>\n</details>\n\n### Changes from siderolabs/go-talos-support\n<details><summary>1 commit</summary>\n<p>\n\n* [`0f784bd`](https://github.com/siderolabs/go-talos-support/commit/0f784bd58b320543663679693c817515067f3021) fix: avoid deadlock on context cancel\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>50 commits</summary>\n<p>\n\n* [`347ad26`](https://github.com/siderolabs/pkgs/commit/347ad26815260d148a7aa42a20eafa5228cbc411) feat: update Linux 6.12.17, containerd 2.0.3\n* [`40241af`](https://github.com/siderolabs/pkgs/commit/40241af0b4d3a34ba5b89fc3a815b9f401f0e203) feat: enable qla2xxx module\n* [`6fb00b4`](https://github.com/siderolabs/pkgs/commit/6fb00b45c1e4c50d26822f9bd0fd462ed0dfb712) fix: pull in kmod from tools\n* [`cc5317a`](https://github.com/siderolabs/pkgs/commit/cc5317adec817d406c1fad1b4871cd7319b56f97) fix: patch Linux with blackhole patch\n* [`08389dd`](https://github.com/siderolabs/pkgs/commit/08389dd2d97aa53e9ac5523a5512c5bbead371c5) chore: support vmdk and cp format for qemu-img\n* [`7774b08`](https://github.com/siderolabs/pkgs/commit/7774b08f03f5c096efdcc7863260916d78a7b8a9) feat: update Linux to 6.12.16, validate package structure\n* [`40d288c`](https://github.com/siderolabs/pkgs/commit/40d288c66d67cfb1d0073288179224d22bf6c41a) fix: imager deps\n* [`351a1a1`](https://github.com/siderolabs/pkgs/commit/351a1a1ece7a79226f46f03f9d904e1d5600716d) feat: add tools needed for imager\n* [`80351ca`](https://github.com/siderolabs/pkgs/commit/80351ca6201f5e5efb51b2a2a6a2058fa2512a90) fix: reproducibility tests\n* [`e1f11f0`](https://github.com/siderolabs/pkgs/commit/e1f11f0991c23f86694b49a9e0fc0f7f592d093d) fix: remove patches and other files from copy-only packages\n* [`8fff06b`](https://github.com/siderolabs/pkgs/commit/8fff06bac029313278c632321f511c2918585872) chore: bump xfsprogs to 6.12.0\n* [`76a0316`](https://github.com/siderolabs/pkgs/commit/76a0316a84571c22eb0c6efd3ce51f3da54671c9) chore: systemd 257.3, runc 1.2.5, ipxe\n* [`359807b`](https://github.com/siderolabs/pkgs/commit/359807b4172e17fdcd1a1531070535d7ef772b20) feat: copy built packages, improve hermetic build\n* [`117a1d6`](https://github.com/siderolabs/pkgs/commit/117a1d6b48835310714166335d3821ac47b4c70a) feat: update Linux to 6.12.13\n* [`85f8901`](https://github.com/siderolabs/pkgs/commit/85f890180058a0865515ed76ca39f76ff0fe20d7) feat: make pkgs build bootstrapped\n* [`5763e3e`](https://github.com/siderolabs/pkgs/commit/5763e3e0fe00cbd9010398e795085ba0377802e8) feat: update systemd to 257.2\n* [`1e24b31`](https://github.com/siderolabs/pkgs/commit/1e24b31dc379251ad5248f94f548e5c7330f59ec) feat: update Linux to 6.12.11\n* [`38749d1`](https://github.com/siderolabs/pkgs/commit/38749d1f08fcb46e522450c1ad530309a8fa327d) fix: build CNI plugins statically linked\n* [`5da83db`](https://github.com/siderolabs/pkgs/commit/5da83dbbe320768db8eb6175b1e7c5e8ff78389d) feat: bump NVIDIA driver versions\n* [`5934363`](https://github.com/siderolabs/pkgs/commit/59343630a024e48dfeba826eac45589d0bdcfb99) fix: certificates CA\n* [`57f492d`](https://github.com/siderolabs/pkgs/commit/57f492d4c3e51e01ab85d2727a7862b21ab21795) feat: bump dependencies\n* [`45b9ebe`](https://github.com/siderolabs/pkgs/commit/45b9ebed9437752c6516792678356a595f1ec62b) feat: update Linux to 6.2.10\n* [`e00ad67`](https://github.com/siderolabs/pkgs/commit/e00ad677f0c7ef4005d26108143c3fe5e36aaab2) chore: rekres to fix reproducibility build\n* [`cfb4b0a`](https://github.com/siderolabs/pkgs/commit/cfb4b0a79490156864eab726debe20559d9c4240) feat: update Go to 1.23.5\n* [`72f19a2`](https://github.com/siderolabs/pkgs/commit/72f19a2983e7abcb620ab57fae6e039158663f1a) feat: update containerd to v2.0.2\n* [`17a80ee`](https://github.com/siderolabs/pkgs/commit/17a80eeb75b91211d4ffe8a910feb9fddcd1e585) feat: update Linux to 6.12.9\n* [`c9d718d`](https://github.com/siderolabs/pkgs/commit/c9d718d3d6fd762ca3a649a14aa2d74e47d707e2) fix: adjust kernel options around ACPI/PCI/EFI\n* [`eb9d566`](https://github.com/siderolabs/pkgs/commit/eb9d56617faa56e42648a07b6756c18850e4a045) feat: update Linux to 6.12.8\n* [`73e4353`](https://github.com/siderolabs/pkgs/commit/73e4353ad9e2dad6dc8544436776fd412c808d63) fix: update config-arm64 to add Rasperry Pi watchdog support\n* [`0ab2427`](https://github.com/siderolabs/pkgs/commit/0ab2427a8415d3f29cd4f52e3afd51f701aa5848) fix: dvb was missing I2C_MUX support and si2168 driver\n* [`c3ac8e2`](https://github.com/siderolabs/pkgs/commit/c3ac8e2d553b068dd982f5b9e48f6b1e0cfdd24d) chore: drop unused cert copy\n* [`e7eddcf`](https://github.com/siderolabs/pkgs/commit/e7eddcf9498634749a4241844660fd0e9d87fad4) feat: bump dependencies\n* [`0b00e86`](https://github.com/siderolabs/pkgs/commit/0b00e86ae92f821bdc19af73a5ba571b5051c89a) fix: patch containerd with CNI deadlock fix\n* [`9051c9a`](https://github.com/siderolabs/pkgs/commit/9051c9ac6f60e039c53248b52ba4ccd192e34b6b) feat: update Linux to 6.12.6\n* [`6695012`](https://github.com/siderolabs/pkgs/commit/6695012e8d93d28ea70fc3ba32ed90770eea4363) chore: rekres to simplify `.kres.yaml` defaults\n* [`611ca38`](https://github.com/siderolabs/pkgs/commit/611ca38153fece4f2b34519325fbca22d34db7a0) chore: rekres to bring renovate under kres\n* [`a4c4215`](https://github.com/siderolabs/pkgs/commit/a4c4215e74b68765ada0745165b2e2fb5ee508f5) fix: drop cgroupsv1 controllers\n* [`28c909d`](https://github.com/siderolabs/pkgs/commit/28c909ddeaf0d33e0fc6c5fdf2333a18801cf178) feat: update Linux firmware to 20241210\n* [`c40a9e9`](https://github.com/siderolabs/pkgs/commit/c40a9e9713b1fde14f7a967fd1be168bb905d7c9) feat: update Linux to 6.12.5\n* [`d54ca83`](https://github.com/siderolabs/pkgs/commit/d54ca835a8868e5df55e2d0ffe3cb0dfa82a3395) feat: update containerd to v2.0.1\n* [`86e3755`](https://github.com/siderolabs/pkgs/commit/86e3755deae2fc85d7e62bdcf82a54cb72fec6d5) fix: add CONFIG_INTEL_MEI_GSC_PROXY as module\n* [`8c31321`](https://github.com/siderolabs/pkgs/commit/8c3132135d5a0e01a9d66790b4b25c7c05e08fa5) feat: update ZFS to 2.2.7\n* [`605f493`](https://github.com/siderolabs/pkgs/commit/605f493abfeac79151c02a776733011f19d6c43b) feat: update runc to v1.2.3\n* [`1a55529`](https://github.com/siderolabs/pkgs/commit/1a555296764ab0ad83fb4eca6509bb64feff3b7b) feat: update Linux to 6.12.4\n* [`52ba9a5`](https://github.com/siderolabs/pkgs/commit/52ba9a57358ef37ce3e4aa4033991dc77ad17fbb) feat: update Linux 6.12.3\n* [`9cf35be`](https://github.com/siderolabs/pkgs/commit/9cf35bef274bb445e578f858a0a595b05b44a01f) feat: build host iptables with nftables support\n* [`71003a3`](https://github.com/siderolabs/pkgs/commit/71003a3c9bff00685917d6e272421a7206b1667e) feat: update Go to 1.23.4\n* [`5b4d402`](https://github.com/siderolabs/pkgs/commit/5b4d402bd33f9313a21e4924be57aacce569f9ad) feat: build dvb kernel modules and CX23885\n* [`b330af9`](https://github.com/siderolabs/pkgs/commit/b330af9b95d9115382c81f88b55c17b99f7ef355) chore: bring in KSPP recommendations\n* [`f81b190`](https://github.com/siderolabs/pkgs/commit/f81b190cc65dc93f9212d52cd95806ac79c170d2) feat: kernel driver support for RK3588 devices (Turing RK1)\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>1 commit</summary>\n<p>\n\n* [`3235c29`](https://github.com/siderolabs/proto-codec/commit/3235c2984fa1bb3cd8d38c088127c46dd3d2860e) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`38e459e`](https://github.com/siderolabs/siderolink/commit/38e459e50c467791c9670a60ef41f58db246715a) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>19 commits</summary>\n<p>\n\n* [`fcee25b`](https://github.com/siderolabs/tools/commit/fcee25ba79e3663db2c0f20f371392e2b45c5f19) fix: revert kmod to 33\n* [`6a71711`](https://github.com/siderolabs/tools/commit/6a7171177b5e9a4b579db3614d140a399430c3ab) fix: do not install man and locale for exported packages\n* [`3389ba2`](https://github.com/siderolabs/tools/commit/3389ba22509cb85e0625dcb6dbbee218fc56d33d) chore: move zlib to be an external package\n* [`d93b780`](https://github.com/siderolabs/tools/commit/d93b780e8f63cf20a524d3ea76bd4f79b787b5f3) chore: expose more tools\n* [`46be459`](https://github.com/siderolabs/tools/commit/46be459d3a46f1fa096a9e58cbf060404dd3cbe2) chore: remove systemd version\n* [`f33fbe4`](https://github.com/siderolabs/tools/commit/f33fbe42517d5a856b360133c6330692b09ba824) fix: install policycoreutils under correct prefix\n* [`758d61c`](https://github.com/siderolabs/tools/commit/758d61cd71c43ba2a65372dc75b811864e113a29) chore: update dependencies\n* [`f398a04`](https://github.com/siderolabs/tools/commit/f398a04953666fa468b02851187f3dc4a77c5a44) chore: update dependencies, hermetic build\n* [`9db33dd`](https://github.com/siderolabs/tools/commit/9db33dd7457e026176fdea964de6d489e67b5fa0) feat: update to Go 1.23.6\n* [`ef0a679`](https://github.com/siderolabs/tools/commit/ef0a67955aa9191019e5ea2fe0fe572694606b02) fix: do not install anything to /usr/lib64\n* [`35748ea`](https://github.com/siderolabs/tools/commit/35748eac6666b66099b16ccfcfe989e34ea16076) feat: fully bootstrapped build\n* [`7200845`](https://github.com/siderolabs/tools/commit/7200845be9d0318d23eb77a57e1b8992dd7e8187) feat: update dependencies\n* [`bc30a2a`](https://github.com/siderolabs/tools/commit/bc30a2a3ace873c80e4657b622e3142efb55cc28) feat: update Go to 1.23.5\n* [`533b595`](https://github.com/siderolabs/tools/commit/533b5953d28213aae4d4ae576bedf5df84712458) chore: rekres to fix reproducibility\n* [`01568a5`](https://github.com/siderolabs/tools/commit/01568a5b42685c3ea19578a7f4d7ba07dc0f18cd) chore: use Make and Go from the toolchain image\n* [`0393558`](https://github.com/siderolabs/tools/commit/03935581049f82ff466defcc203c5bcc6db5b43a) feat: bump dependencies\n* [`7811a5f`](https://github.com/siderolabs/tools/commit/7811a5f2f23923cdfe5bfd47ee12ed9e88b29585) chore: rekres to simplify `.kres.yaml` defaults\n* [`0b8b905`](https://github.com/siderolabs/tools/commit/0b8b9054833d8187bb1f6209b2441719f6e62cfa) chore: kresify renovate config\n* [`fe34fb3`](https://github.com/siderolabs/tools/commit/fe34fb3d54ec9abe878a9304fbfc3e1e741c0ff4) feat: update Go to 1.23.4\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.5.2 -> v0.6.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.16.0 -> v1.17.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.8.0 -> v1.8.2\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.3.0 -> v1.3.1\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.3.0 -> v1.3.1\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.28.5 -> v1.29.8\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.20 -> v1.16.30\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.37.6 -> v1.38.0\n* **github.com/aws/smithy-go**                                                v1.22.1 -> v1.22.3\n* **github.com/containerd/cgroups/v3**                                        v3.0.4 -> v3.0.5\n* **github.com/containerd/containerd/v2**                                     v2.0.1 -> v2.0.3\n* **github.com/containerd/platforms**                                         v1.0.0-rc.0 -> v1.0.0-rc.1\n* **github.com/containernetworking/plugins**                                  v1.6.0 -> v1.6.2\n* **github.com/cosi-project/runtime**                                         v0.7.6 -> v0.10.0\n* **github.com/docker/cli**                                                   v27.3.1 -> v28.0.1\n* **github.com/docker/docker**                                                v27.3.1 -> v28.0.1\n* **github.com/foxboron/go-uefi**                                             fab4fdf2f2f3 -> 69fb7dba244f\n* **github.com/gdamore/tcell/v2**                                             v2.7.4 -> v2.8.1\n* **github.com/google/cel-go**                                                v0.22.1 -> v0.24.1\n* **github.com/google/go-containerregistry**                                  v0.20.2 -> v0.20.3\n* **github.com/google/go-tpm**                                                v0.9.1 -> v0.9.3\n* **github.com/google/nftables**                                              v0.2.0 -> v0.3.0\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**                         v2.1.0 -> v2.3.0\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.17.0 -> v2.19.1\n* **github.com/insomniacslk/dhcp**                                            a3a4c1f04475 -> 8abf58130905\n* **github.com/klauspost/compress**                                           v1.17.11 -> v1.18.0\n* **github.com/klauspost/cpuid/v2**                                           v2.2.9 -> v2.2.10\n* **github.com/mdlayher/netlink**                                             v1.7.2 -> fbb4dce95f42\n* **github.com/miekg/dns**                                                    v1.1.62 -> v1.1.63\n* **github.com/opencontainers/runc**                                          v1.2.2 -> v1.2.5\n* **github.com/opencontainers/runtime-spec**                                  v1.2.0 -> v1.2.1\n* **github.com/rivo/tview**                                                   c76f7879f592 -> 17b7edb88c57\n* **github.com/safchain/ethtool**                                             v0.5.9 -> v0.5.10\n* **github.com/scaleway/scaleway-sdk-go**                                     v1.0.0-beta.30 -> v1.0.0-beta.32\n* **github.com/siderolabs/crypto**                                            v0.5.0 -> v0.5.1\n* **github.com/siderolabs/discovery-api**                                     v0.1.5 -> v0.1.6\n* **github.com/siderolabs/discovery-client**                                  v0.1.10 -> v0.1.11\n* **github.com/siderolabs/extras**                                            v1.9.0 -> v1.10.0-alpha.0-3-g4102a78\n* **github.com/siderolabs/gen**                                               v0.7.0 -> v0.8.0\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.7 -> v2.0.16\n* **github.com/siderolabs/go-circular**                                       v0.2.1 -> v0.2.2\n* **github.com/siderolabs/go-debug**                                          v0.4.0 -> v0.5.0\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.17 -> v0.2.18\n* **github.com/siderolabs/go-loadbalancer**                                   v0.3.4 -> v0.4.0\n* **github.com/siderolabs/go-talos-support**                                  v0.1.1 -> v0.1.2\n* **github.com/siderolabs/pkgs**                                              v1.9.0-12-g9576b97 -> v1.10.0-alpha.0-49-g347ad26\n* **github.com/siderolabs/proto-codec**                                       v0.1.1 -> v0.1.2\n* **github.com/siderolabs/siderolink**                                        v0.3.11 -> v0.3.12\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.9.0 -> v1.10.0-alpha.1\n* **github.com/siderolabs/tools**                                             v1.9.0-1-geaad82f -> v1.10.0-alpha.0-18-gfcee25b\n* **github.com/spf13/cobra**                                                  v1.8.1 -> v1.9.1\n* **github.com/spf13/pflag**                                                  v1.0.5 -> v1.0.6\n* **github.com/thejerf/suture/v4**                                            v4.0.5 -> v4.0.6\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/client/v3**                                               v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.17 -> v3.5.18\n* **golang.org/x/net**                                                        v0.32.0 -> v0.35.0\n* **golang.org/x/oauth2**                                                     v0.24.0 -> v0.27.0\n* **golang.org/x/sync**                                                       v0.10.0 -> v0.11.0\n* **golang.org/x/sys**                                                        v0.28.0 -> v0.30.0\n* **golang.org/x/term**                                                       v0.27.0 -> v0.29.0\n* **golang.org/x/text**                                                       v0.21.0 -> v0.22.0\n* **golang.org/x/time**                                                       v0.8.0 -> v0.10.0\n* **golang.zx2c4.com/wireguard/wgctrl**                                       925a1e7659e6 -> a9ab2273dd10\n* **google.golang.org/grpc**                                                  v1.68.1 -> v1.70.0\n* **google.golang.org/protobuf**                                              v1.35.2 -> v1.36.5\n* **k8s.io/api**                                                              v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/apimachinery**                                                     v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/apiserver**                                                        v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/client-go**                                                        v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/component-base**                                                   v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/cri-api**                                                          v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/kube-scheduler**                                                   v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/kubectl**                                                          v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/kubelet**                                                          v0.32.0 -> v0.33.0-alpha.2\n* **k8s.io/pod-security-admission**                                           v0.32.0 -> v0.33.0-alpha.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**                           v1.2.72 -> v1.2.73\n\nPrevious release can be found at [v1.9.0](https://github.com/siderolabs/talos/releases/tag/v1.9.0)\n\n## [Talos 1.10.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.10.0-alpha.1) (2025-01-31)\n\nWelcome to the v1.10.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### auditd\n\nKernel parameter `talos.auditd.disabled=1` can be used to disable Talos built-in `auditd` service.\n\n\n### cgroups v1\n\nTalos Linux no longer supports `cgroupsv1` when running in non-container mode.\nThe kernel argument `talos.unified_cgroup_hierarchy` is now ignored.\n\n\n### Driver Rebind\n\nTalos 1.10 now supports a new machine config document named `PCIDriverRebindConfig` that allows rebinding the driver of a PCI device to a different target driver.\nSee the [documentation](https://www.talos.dev/v1.10/reference/configuration/hardware/pcidriverrebindconfig/) for more information.\n\n\n### iSCSI Initiator\n\nTalos now generates `/etc/iscsi/initiatorname.iscsi` file based on the node identity which is tied to the lifecycle of the node.\nIf using `iscsi-tools` extension, starting with Talos 1.10 would have a more deterministic IQN for the initiator node.\nMake sure to update any iSCSI targets to use the new initiator IQN.\n\nThe iqn can be read by `talosctl read /etc/iscsi/initiatorname.iscsi`\n\n\n### ISO\n\nTalos starting with 1.10 will have ISO's that will use GRUB only for legacy BIOS and systemd-boot for modern UEFI systems.\n\n\n### kube-apiserver Authorization Config\n\nWhen using `.cluster.apiServer.authorizationConfig` the user provided order for the authorizers is honoured and `Node` and `RBAC` authorizers are always added to the end if not explicitly specified.\n\nEg: If user provides only `Webhook` authorizer, the final order will be `Webhook`, `Node`, `RBAC`.\n\nTo provide a specific order for `Node` or `RBAC` explicitly, user can provide the authorizer in the order they want.\n\nEg:\n\n```yaml\ncluster:\n  apiServer:\n    authorizationConfig:\n      - type: Node\n        name: Node\n      - type: Webhook\n        name: Webhook\n        webhook:\n          connectionInfo:\n            type: InClusterConfig\n        ...\n      - type: RBAC\n        name: rbac\n```\n\nUsage of `authorization-mode` CLI argument will not support this form of customization.\n\n\n### NVMe NQN\n\nTalos now generates `/etc/nvme/hostnqn` and `/etc/nvme/hostid` files based on the node identity which is tied to the lifecycle of the node.\n\nThe NQN can be read by `talosctl read /etc/nvme/hostnqn`\n\n\n### Component Updates\n\n* Linux: 6.12.11\n* CNI plugins: 1.6.2\n* runc: 1.2.4\n* containerd: 2.0.2\n* etcd: 3.5.18\n\nTalos is built with Go 1.23.5.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Dmitry Sharshakov\n* Justin Garrison\n* Nico Berlee\n* Skyler Mäntysaari\n* Utku Ozdemir\n* Alexis La Goutte\n* Andrew Symington\n* Christian Luetke-Stetzkamp\n* Christoph Hoopmann\n* Devin Buhl\n* Florian Grignon\n* Ganawa Juanah\n* Jason Benedicic\n* K Birt\n* KillianCdP\n* L.J. Hanson\n* Louis SCHNEIDER\n* Marcel Hamer\n* Motte\n* Natalie Romana Albers\n* PRIHLOP\n* Ram\n* Tim Olson\n* Tine Jozelj\n* TomyLobo\n* bzub\n* greenpsi\n* sflotat2607\n* suse-coder\n\n### Changes\n<details><summary>161 commits</summary>\n<p>\n\n* [`3a2d9867b`](https://github.com/siderolabs/talos/commit/3a2d9867b5cc3236b1d1c7981e5794657f3c155e) fix: do not close client.Client.conn with finalizer\n* [`73f30ff25`](https://github.com/siderolabs/talos/commit/73f30ff25e0adb7a47e2153756e0ea94bd605568) feat: bump pkgs for udev update\n* [`aea90cb8f`](https://github.com/siderolabs/talos/commit/aea90cb8f1dbe7d5f67d35714825133728c1490d) docs: update hyper-v\n* [`b7165615f`](https://github.com/siderolabs/talos/commit/b7165615f86afd09ea85dc91090a40860ae6fc9a) fix: use local NTP for AWS platform\n* [`673ca4bcb`](https://github.com/siderolabs/talos/commit/673ca4bcb2448b3c252fccff0d243932c97fd893) fix: ensure proper closure of client.Client.conn with finalizer\n* [`19040ffd6`](https://github.com/siderolabs/talos/commit/19040ffd6ef128daaf48a820d8826186c82c68c5) fix: handle of PE sections with duplicate names\n* [`83489d348`](https://github.com/siderolabs/talos/commit/83489d348905352497da0f6dc042f3e7f05cd4d7) docs: add note about vmxnet and flannel conflict\n* [`f1292f5e7`](https://github.com/siderolabs/talos/commit/f1292f5e7af4110270475d8bcc4bd39519419e03) docs: add iscsi-tools extension to prerequisites\n* [`93b4a3740`](https://github.com/siderolabs/talos/commit/93b4a3740ba0c35e8b62cbf8c70058d1e53c3b8e) test: bump timeout on rotate CA test\n* [`42e166984`](https://github.com/siderolabs/talos/commit/42e16698453a687a4293e7cfeeb0e09d4f084217) feat: support kexec from uki\n* [`8da264946`](https://github.com/siderolabs/talos/commit/8da264946cda9b4803fd9f2f4dfd0ed25445843b) docs: add Orange Pi 5 to Image Factory platforms and documentation\n* [`c5fb62e2e`](https://github.com/siderolabs/talos/commit/c5fb62e2e32690aa0235b0911ded1888084496a8) feat: update Linux to 6.2.11\n* [`83d007c16`](https://github.com/siderolabs/talos/commit/83d007c161e03311cede2153f35c32f608537290) feat: update etcd to 3.5.18\n* [`edf7c3288`](https://github.com/siderolabs/talos/commit/edf7c328835273e2bc6dd23c646091e6a03aa2e9) fix: pe uki extract\n* [`70f72c5b0`](https://github.com/siderolabs/talos/commit/70f72c5b00bce791d692ec3a0e9a91aaf9d88031) docs: update multus.md\n* [`807a3cd29`](https://github.com/siderolabs/talos/commit/807a3cd291e2e2cb22946826bccb64671a29d901) refactor: all network merge controllers\n* [`ec8c4660e`](https://github.com/siderolabs/talos/commit/ec8c4660e277dc11b5e70c014a0238d48cf15bda) docs: update vmware.md\n* [`baf81cd49`](https://github.com/siderolabs/talos/commit/baf81cd4914470b06393d762f70d0a94f7a9fe32) fix(ci): k8s integration suite wait for resource\n* [`cd5e54903`](https://github.com/siderolabs/talos/commit/cd5e549039b17add0a2ce09713e1a034bb3efccf) feat: generate iso's with both UKI and grub\n* [`75673b6a3`](https://github.com/siderolabs/talos/commit/75673b6a38eeb6361c6e6aeb389e8dbaaacb8b0b) feat: provide stable symlinks in disk resources\n* [`f407c88e4`](https://github.com/siderolabs/talos/commit/f407c88e4678ff6d5edb940f5d54461104be3643) fix(ci): wait for longhorn node resource\n* [`601cdccb9`](https://github.com/siderolabs/talos/commit/601cdccb979640a6b2ffcba41cc698015b1dacde) feat: extract kernel/initrd from uki for grub\n* [`ff175b9fb`](https://github.com/siderolabs/talos/commit/ff175b9fbdb2ac92ac53351d32de130bd0676038) docs: update disk-encryption.md\n* [`a8d84e315`](https://github.com/siderolabs/talos/commit/a8d84e3155137a114ad00ad7ae321af033020e7d) docs: fix typos and add more explanations in docs\n* [`3a384240e`](https://github.com/siderolabs/talos/commit/3a384240ecf660d310f2df98327f018649ebaa6d) fix: invalid date field in iqn/nqn\n* [`82c9ec158`](https://github.com/siderolabs/talos/commit/82c9ec158e82efea80daaf76fef9fbd31c3eb823) chore(ci): add tests with longhorn v2 engine\n* [`689ea1dbf`](https://github.com/siderolabs/talos/commit/689ea1dbfe29d70d91e0b41d31fc696e2ff96665) fix: bring back disk UUID\n* [`7a712fad2`](https://github.com/siderolabs/talos/commit/7a712fad2abb916f397a8dd0aebf66e59ee75904) fix: disks with 4k sector size and systemd-boot\n* [`d62a34aaf`](https://github.com/siderolabs/talos/commit/d62a34aaf4e4ff7dad9f6dbeb59a67016c70fffb) feat: update tools/pkgs/extras\n* [`b9a8ad6ac`](https://github.com/siderolabs/talos/commit/b9a8ad6acafd64c4217ba914184592c0cfb97962) chore: de-hardcode list of extra images for image-cache test\n* [`683153a33`](https://github.com/siderolabs/talos/commit/683153a33c1069e7f7cadf4e3a70bde3f8ba3331) docs: remove the last mentions of `preserve` flag for Talos 1.8+\n* [`33c7f4195`](https://github.com/siderolabs/talos/commit/33c7f4195816988af6f70199fdb4a31d027fa746) docs: fix typo an MacOS to on MacOS\n* [`21cff3919`](https://github.com/siderolabs/talos/commit/21cff3919b80f33f837b19728500fcb91e7caf8f) chore(ci): fio benchmark results as separate artifacts\n* [`0b7fc7cdf`](https://github.com/siderolabs/talos/commit/0b7fc7cdfea651a6f16db3f346473505d8df3e78) fix: abort node watch on hostname change\n* [`99ba53941`](https://github.com/siderolabs/talos/commit/99ba53941cecdc54c0ececa9876b25a7fc7668a5) docs: remove the mention of `preserve` flag for Talos 1.8+\n* [`bde516fde`](https://github.com/siderolabs/talos/commit/bde516fde62a25dd60691a9a3b6f3d30de11dad1) chore(ci): rework iscsi-tools extensions test\n* [`e1efbf656`](https://github.com/siderolabs/talos/commit/e1efbf656ae96ecedba1c132608c3ad2d3ae4a66) refactor: extract platform metadata into Talos machinery\n* [`79987c05d`](https://github.com/siderolabs/talos/commit/79987c05dcd39ca646c2d73c1e25488504f13a60) feat: generate iqn and nqn files\n* [`0cab6ed17`](https://github.com/siderolabs/talos/commit/0cab6ed170708549d69c04b163744854de0aa8f2) docs: update troubleshooting.md\n* [`921e10254`](https://github.com/siderolabs/talos/commit/921e10254d443c459a9775368ca080ecba273321) chore: update Go to 1.23.5\n* [`399d53b54`](https://github.com/siderolabs/talos/commit/399d53b543f6ca99f13d28313ae77b3472b0f728) fix: ignore forbidden error when waiting for pod eviction\n* [`8dea57a81`](https://github.com/siderolabs/talos/commit/8dea57a81b8393b518da60951713c711659291f9) fix: make etc binds read-only\n* [`63157dcb4`](https://github.com/siderolabs/talos/commit/63157dcb496ca767bfbff9e1b86f14277a44cdb7) docs: update SideroLinkConfig example\n* [`fc7080e34`](https://github.com/siderolabs/talos/commit/fc7080e34b990d2d50ec1e40734437ccd0ee95f7) chore: clear cache after updating upstreams\n* [`51e0f273f`](https://github.com/siderolabs/talos/commit/51e0f273f9199b8320cd5da247c702a4319a92c5) docs: update documentation for Talos 1.9.2\n* [`e06b14112`](https://github.com/siderolabs/talos/commit/e06b14112d2c978e3f6b5c4446090a7ae533ead9) feat: update Kubernetes to 1.32.1\n* [`4310b290d`](https://github.com/siderolabs/talos/commit/4310b290d5cff9697f86cc24f1c281e62cb7d72f) fix: generate UKI only if actually needed\n* [`a8cd99102`](https://github.com/siderolabs/talos/commit/a8cd991026fe7290013b7504a4e87af46c49d25b) docs: update OpenEBS Mayastor installation\n* [`cf45f4764`](https://github.com/siderolabs/talos/commit/cf45f4764ddd979fa81576833d9630eadea24f41) docs: add Radxa ROCK 5B docs to Single Board Computer section\n* [`b21bdc5e5`](https://github.com/siderolabs/talos/commit/b21bdc5e501bc2244e3e487827ffba79075f6642) chore(ci): save csi tests fio results\n* [`01c86832c`](https://github.com/siderolabs/talos/commit/01c86832cbbbe0b81b9500032f94298fd6e90b58) chore(ci): add test for OpenEBS MayaStor\n* [`c77483510`](https://github.com/siderolabs/talos/commit/c774835103ad139b44d7e4e13c003e2b13160347) test: update `talosctl debug air-gapped`\n* [`ddd695d93`](https://github.com/siderolabs/talos/commit/ddd695d933d39920da42219ba8b3d39b0681a3ea) feat: update containerd to 2.0.2\n* [`da2e81120`](https://github.com/siderolabs/talos/commit/da2e81120f7336d9633a98523e05d91f5750434f) fix: add informer resync period for node status watcher\n* [`9b957df64`](https://github.com/siderolabs/talos/commit/9b957df64680a97a16575db67d4af27cfc0ef7d2) chore: uki code restructure\n* [`e41a99525`](https://github.com/siderolabs/talos/commit/e41a995253428dde437eecec52cabfb4c80f90ea) fix: kube-apiserver authorizers order\n* [`db4ca5668`](https://github.com/siderolabs/talos/commit/db4ca5668ac0d85a98a5ea022f6546526d20aff1) feat: add a kernel parameter to disable built-in auditd\n* [`faa149003`](https://github.com/siderolabs/talos/commit/faa1490033df0a843010fa7154096d84f415afce) feat: update Linux to 6.12.9\n* [`8de19758d`](https://github.com/siderolabs/talos/commit/8de19758dafce802c0f93a63ae3083b5ad17162d) fix: a couple of imager panics/crashes\n* [`5bc3e34cb`](https://github.com/siderolabs/talos/commit/5bc3e34cb3a6fd8e3eb5d02dd612cf3cf9dc499f) fix: detect GPT before ZFS\n* [`ed7e47d15`](https://github.com/siderolabs/talos/commit/ed7e47d158e064204b2f14f9ff378bea70e9524e) refactor: drop usage of objcopy to generate UKIs\n* [`edf5c5e29`](https://github.com/siderolabs/talos/commit/edf5c5e29bc76299c63bb04f1d97a030ecb9b3f0) fix: extfs repair and resize\n* [`6e32ea5b7`](https://github.com/siderolabs/talos/commit/6e32ea5b7f1a22500014ecb365e13af36034187a) fix: merge of VolumeConfig documents with sizes\n* [`1be5f8ff2`](https://github.com/siderolabs/talos/commit/1be5f8ff25ac7042ee3334f657d6604ec5f8501d) feat: update Linux to 6.12.8\n* [`e6a4583ba`](https://github.com/siderolabs/talos/commit/e6a4583ba862da9f49ab0bd0cb6bc8436723bc67) feat: support generating unsigned UKIs\n* [`bbd6067d4`](https://github.com/siderolabs/talos/commit/bbd6067d426fb2be22ff8935f415ab6d729d8f19) fix: partition alignment on disks with 4k sectors\n* [`84fcc976f`](https://github.com/siderolabs/talos/commit/84fcc976f8da5af310771e1835a0347df5bcc97d) fix: yet another dashboard panic\n* [`6d605fc85`](https://github.com/siderolabs/talos/commit/6d605fc8595e2f06e43529966e396f2ae403c76c) fix: disable NRI plugin in a different way\n* [`499695e24`](https://github.com/siderolabs/talos/commit/499695e24ea02ffc2fd8c92276d5de41b0d4919e) fix: request previous IP address in discovery\n* [`cc84caf8c`](https://github.com/siderolabs/talos/commit/cc84caf8c0dffd9d59f360f84967c524be9ba369) docs: update Cilium documentation\n* [`fa5300d91`](https://github.com/siderolabs/talos/commit/fa5300d910a537f03939fcbf6362abdd8fa607dd) chore: revert: drop deprecated allowSchedulingOnMasters\n* [`0abb3dabf`](https://github.com/siderolabs/talos/commit/0abb3dabf6d50b9c1176af683ad74234334f822d) docs: fix command to wait for ceph-rook HEALTH_OK\n* [`32c67c27c`](https://github.com/siderolabs/talos/commit/32c67c27c393c989f9d70ccb8506c4735f70d494) chore: drop deprecated allowSchedulingOnMasters\n* [`ae6d065be`](https://github.com/siderolabs/talos/commit/ae6d065beb4897a1b877ecb30b06be456befbf91) fix: mount selinuxfs only when SELinux is enabled\n* [`5ccbf4bcd`](https://github.com/siderolabs/talos/commit/5ccbf4bcdbe9aa2096320d17eb2deab6a062faf9) feat: enable `configfs`\n* [`59582496d`](https://github.com/siderolabs/talos/commit/59582496d5fe419f833703be8e956163b6241d15) feat: bring in partity with sd-257\n* [`83d84a831`](https://github.com/siderolabs/talos/commit/83d84a831862c774b9bc2adc2e11e00bf2a79912) chore(ci): better zfs checks\n* [`650eb3a4f`](https://github.com/siderolabs/talos/commit/650eb3a4f2d89d173cdd6581a6d1232511a8e219) refactor: rewrite cloud uploader to use AWS SDK Go v2\n* [`01bf8449b`](https://github.com/siderolabs/talos/commit/01bf8449b917ece76336ca7f0eb11fd877195025) fix: update field name for bus path disk selector\n* [`e915c98d5`](https://github.com/siderolabs/talos/commit/e915c98d583e5901c1c2efe38efa656b39d72360) fix: exclude disks with empty transport for disk selector\n* [`b7a7fdc4b`](https://github.com/siderolabs/talos/commit/b7a7fdc4b8a715157bfa2614c9541b96643cd2ba) refactor: generate /etc/os-release file static way\n* [`e79c9e127`](https://github.com/siderolabs/talos/commit/e79c9e12772c998ff5b3e401efd7f074f85e5cef) chore(ci): drop equinix metal e2e-test\n* [`418945444`](https://github.com/siderolabs/talos/commit/418945444135c6d9e2e5960e7b9cbd754084fea2) fix: build of talosctl on non-Linux platforms\n* [`4761a9e6a`](https://github.com/siderolabs/talos/commit/4761a9e6aa0bf619a564807d02ebce030384d6a1) chore: update dependencies\n* [`f98efb333`](https://github.com/siderolabs/talos/commit/f98efb333f89b8493c55b91698c917437b7af310) fix: ignore member not found error on leave cluster\n* [`b72bda0a4`](https://github.com/siderolabs/talos/commit/b72bda0a420f75ea0439cc0240dcf6d3363e5d48) fix: talosctl support and race tests\n* [`27233cf0f`](https://github.com/siderolabs/talos/commit/27233cf0fcf4031cbc8001504bed67b6d4a104f9) test: use node informer instead of raw watch\n* [`5dc15e8db`](https://github.com/siderolabs/talos/commit/5dc15e8db459ac632f0ae106e1cfc7eaab672adf) fix: update go-blockdevice to v2.0.9\n* [`5f3acd0f2`](https://github.com/siderolabs/talos/commit/5f3acd0f26a35ac966d4ced01436f1dd3c03648b) fix: use correct default search domain\n* [`7e5d36d46`](https://github.com/siderolabs/talos/commit/7e5d36d469ff01153f40b16ab722f0ebe25d41ae) fix: pci driver rebind config validation\n* [`4b97bbc3f`](https://github.com/siderolabs/talos/commit/4b97bbc3fee1257d0d21be25e21493bfd1f45a80) fix: pull in containerd CNI deadlock fix\n* [`066480722`](https://github.com/siderolabs/talos/commit/0664807229e0688f092a453cbd3121dbe189ca39) test: fix apparmor tests\n* [`82ea44a6b`](https://github.com/siderolabs/talos/commit/82ea44a6b2aa0a35861ca454a09503a81332f824) fix: reduce installer image\n* [`78b3e7f4f`](https://github.com/siderolabs/talos/commit/78b3e7f4f1870085b719971c6f92dc866fe1e9d0) fix: get next rule number for IPv6 in the appropriate chain\n* [`675854aa0`](https://github.com/siderolabs/talos/commit/675854aa03b3913da3481337d995c206174cf004) docs: fix two typos\n* [`f70b7386a`](https://github.com/siderolabs/talos/commit/f70b7386ac3125f3b8ab6b1765338c7e3445ae5c) test: add a xfs makefs test\n* [`8212e4864`](https://github.com/siderolabs/talos/commit/8212e4864d11e69ed63be3f4e608e9ccbc788cc4) refactor: use quirks in kernel args\n* [`b4aa5189d`](https://github.com/siderolabs/talos/commit/b4aa5189d4d4565a42ad7ac8de24c424a215b42f) release(v1.10.0-alpha.0): prepare release\n* [`bd85bd5b7`](https://github.com/siderolabs/talos/commit/bd85bd5b731463a42b7c82c66e9add251a280d26) fix: fix `Failed to initialize SELinux labeling handle` udev error\n* [`73c82e3e5`](https://github.com/siderolabs/talos/commit/73c82e3e5625ec1899f93312a671dfe6dffaea61) feat: bring Linux 6.12.6, CNI plugins 1.6.1\n* [`c12b52491`](https://github.com/siderolabs/talos/commit/c12b52491456d1e52204eb290d0686a317358c7c) docs: document Kubernetes service registry incompat with K8s 1.32\n* [`a5660ed77`](https://github.com/siderolabs/talos/commit/a5660ed778108843fe15b2b1582dd6556cf52b6c) feat: pcirebind controller\n* [`4c3261626`](https://github.com/siderolabs/talos/commit/4c3261626fa3f5ac36df71ec878f103a7c85c5c5) docs: fix several typos\n* [`fb3675321`](https://github.com/siderolabs/talos/commit/fb36753216cba7740040f2ec117c783221f66192) fix: dashboard crash on CPU data\n* [`dec0185c8`](https://github.com/siderolabs/talos/commit/dec0185c8505a7d43244fdb01f7a5decc77d116d) chore: reduce memory usage for secureboot functions\n* [`cee6c60a0`](https://github.com/siderolabs/talos/commit/cee6c60a0fc301b22c50fdf8bd2fc1d2b7ba3d54) fix: make talosctl time work with PTP time sync\n* [`f75604313`](https://github.com/siderolabs/talos/commit/f75604313d535180c38b33df53253ad4acba2ec1) chore: support gcr.io auth for cache and image gen\n* [`6ef2596da`](https://github.com/siderolabs/talos/commit/6ef2596da7b7e8be90e5b981621461352be7b134) docs: improve Hetzner documentation\n* [`7d39b9ec2`](https://github.com/siderolabs/talos/commit/7d39b9ec2bdd7883116626bf889c1331717f8438) feat: remove cgroupsv1 in non-container mode\n* [`8003536c7`](https://github.com/siderolabs/talos/commit/8003536c7ca20356adcd900e64463bd166d445af) fix: restore previous disk serial fetching\n* [`03116ef9b`](https://github.com/siderolabs/talos/commit/03116ef9bd2a215c20a2c4c7db133dd857ce2b16) chore: prepare for Talos 1.10\n* [`00682fdd6`](https://github.com/siderolabs/talos/commit/00682fdd6e8fa23c6f9782840ea3e2b8ef250f66) docs: activate 1.9 docs as default\n* [`bea05f5c9`](https://github.com/siderolabs/talos/commit/bea05f5c9b6ce6f5d067eb357d26e30a49154b21) docs: update deploying-cilium.md\n* [`284ab1179`](https://github.com/siderolabs/talos/commit/284ab11794b3b076aa9ab2bb756e02292d854751) feat: support link altnames/aliases\n* [`5bfd829bf`](https://github.com/siderolabs/talos/commit/5bfd829bf9c8e46b6c51174be4b764d4c94b3320) docs: fix 'containter' typo\n* [`8d151b771`](https://github.com/siderolabs/talos/commit/8d151b771debc51d3fa40dfafc7a2e43f955a634) docs: clarify TALOSCONFIG for AWS\n* [`0ef19171f`](https://github.com/siderolabs/talos/commit/0ef19171f738e46346dfae71f43b8f7b47bf257d) fix: renovate typo\n* [`c568adc7d`](https://github.com/siderolabs/talos/commit/c568adc7dcd52c34924acc1eae849a2ca5b5a4d5) fix: renovate config\n* [`ec2e24fd9`](https://github.com/siderolabs/talos/commit/ec2e24fd9617db34e3bec753b5fe720670fa31a4) fix: match MAC addresses case-insensitive (nocloud)\n* [`41a0c440a`](https://github.com/siderolabs/talos/commit/41a0c440ad3f4de2a2ba9198d22609c55bdaf61b) chore: rekres for renovate changes\n* [`a49bb9ee4`](https://github.com/siderolabs/talos/commit/a49bb9ee45346268b26d3b9cff4dd017bfb9c829) feat: update Linux to 6.12.5\n* [`b15917ecc`](https://github.com/siderolabs/talos/commit/b15917ecc626781e13de0e84b794ab77c97b3159) chore: add more debugging logs for META and volumes\n* [`2b1b326f0`](https://github.com/siderolabs/talos/commit/2b1b326f08966615a5a2f8708f94e6d1355773a7) docs: mention different paths for OpenEBS\n* [`9470e842f`](https://github.com/siderolabs/talos/commit/9470e842fca2d7dd0dae185bff7210a8af355445) test: cleanup failed Kubernetes pods\n* [`c9c685150`](https://github.com/siderolabs/talos/commit/c9c6851504fcda7b66395fbbba1fbc8b0e085d4a) fix: node identity flip\n* [`590c01657`](https://github.com/siderolabs/talos/commit/590c0165712aee60e752766d6bd3875443c353cb) feat: update containerd to v2.0.1\n* [`18fa5a258`](https://github.com/siderolabs/talos/commit/18fa5a25876f41760ce8da5e918222e04b81949a) docs: update image-cache doc for iso\n* [`ab5bb6884`](https://github.com/siderolabs/talos/commit/ab5bb688420986a356aed55513a1dbd25de323e2) fix: generate and serve registries with port\n* [`58236066d`](https://github.com/siderolabs/talos/commit/58236066ddbcd7c401e945b70555ff315a2458f7) fix: support image cache on VFAT USB stick\n* [`e193a5071`](https://github.com/siderolabs/talos/commit/e193a507149c05e341abe019de219fe0b1bc83e3) fix: image cache integration test\n* [`08ee400fd`](https://github.com/siderolabs/talos/commit/08ee400fdbde368a54d6777cc31ceb91e1968ad2) test: fix flaky test NodeAddressSort\n* [`d45e8d1d1`](https://github.com/siderolabs/talos/commit/d45e8d1d1da28ca1b311198588d723cb491527eb) feat: update Kubernetes to 1.32.0\n* [`136b12912`](https://github.com/siderolabs/talos/commit/136b12912165d5eb5c7c716b7f7dfcfbc42b08d4) chore: drop semicolon for supporting vfat filesystems\n* [`3e9e027ef`](https://github.com/siderolabs/talos/commit/3e9e027efbd2988f72eb2da0c1ab0e83ba52b950) test: add an option to boot from an USB stick\n* [`ef8c3e3b3`](https://github.com/siderolabs/talos/commit/ef8c3e3b3b245f7ffefa6c19930d5a0925ce666b) docs: fix typo in multus.md\n* [`d54414add`](https://github.com/siderolabs/talos/commit/d54414add4e4df1b5a7b166f155cdcca512d4ee2) fix: authorization config gen\n* [`cce72cfe8`](https://github.com/siderolabs/talos/commit/cce72cfe86beeb7ada9641df611046f4789e3bd8) docs: replace deprecated Hetzner server plans\n* [`81805103d`](https://github.com/siderolabs/talos/commit/81805103deada24b12b7d7861b2df5a5c788c86b) chore: enable proper parallel usage of TestDepth\n* [`e1b824eba`](https://github.com/siderolabs/talos/commit/e1b824ebada3d3dad9d2793fd12b5a948d8b51b5) docs: update ceph-with-rook.md\n* [`470b75563`](https://github.com/siderolabs/talos/commit/470b75563add4ce5bbce312c1e3dc783e63af1fa) fix: use mtu network option for podman\n* [`61b1489a0`](https://github.com/siderolabs/talos/commit/61b1489a0f0868c5b7e124544520bc46badef85c) fix: order volume config by the requested size\n* [`bc3039acd`](https://github.com/siderolabs/talos/commit/bc3039acdbc57e6be16a1bc6555894dff2da65c9) feat: update runc to 1.2.3\n* [`30016a0a8`](https://github.com/siderolabs/talos/commit/30016a0a8d98d42e01c4d32acf9e600777d72d57) fix: avoid nil-pointer-panic in `RegistriesConfigController`\n* [`fe0457152`](https://github.com/siderolabs/talos/commit/fe045715277a4678b8e8c9632ec71e86bf17ace0) fix: power on the machine on reboot request in qemu power api\n* [`10da553ef`](https://github.com/siderolabs/talos/commit/10da553ef0dde5f87f09321400239baa51929a36) docs: build what's new for 1.9\n* [`d946ccae3`](https://github.com/siderolabs/talos/commit/d946ccae31b87559a06cb1cefcefe8f937b73d8b) feat: update Linux to 6.12.4\n* [`707a77bf6`](https://github.com/siderolabs/talos/commit/707a77bf64190470bf84c91cdff185981e80a31b) test: fix user namespace test, TPM2 fixes\n* [`c3537b2f5`](https://github.com/siderolabs/talos/commit/c3537b2f5491a890f626ba8fc47034d5059808af) feat: update Linux to 6.12.3\n* [`cb4d9d673`](https://github.com/siderolabs/talos/commit/cb4d9d673432e4a0fba0d87bc64fde620d991082) docs: fix a few mistakes in release notes\n* [`c4724fc97`](https://github.com/siderolabs/talos/commit/c4724fc97598d8764b00fb56971d997a349a92e5) chore: add integration tests for image-cache\n* [`07220fe7f`](https://github.com/siderolabs/talos/commit/07220fe7f5a22444f7a085f5868f628ddd912b6d) fix: install iptables-nft to the host\n* [`14841750b`](https://github.com/siderolabs/talos/commit/14841750bf2fc09a9de0b32a7af0dc3f76e1019a) chore: add version compatibility for Talos 1.10\n* [`852baf819`](https://github.com/siderolabs/talos/commit/852baf819d453a3d8d58ae9f029e280ae75e0cb1) feat: support vlan/bond in v1, vlan in v2 for nocloud\n* [`dd61ad861`](https://github.com/siderolabs/talos/commit/dd61ad86105c07c1ff8a101a0542af61699f0df3) fix: lock provisioning order of user disk partitions\n* [`d0773ff09`](https://github.com/siderolabs/talos/commit/d0773ff09df84b2dac8ecadc91023596050ce098) chore: update Go to 1.23.4\n* [`7d6507189`](https://github.com/siderolabs/talos/commit/7d6507189ff9a99b3b05ee9528701b65af4ad147) feat: implement new address sorting algorithm\n* [`9081506d6`](https://github.com/siderolabs/talos/commit/9081506d6cde26d60a29f08a090e28da501e4bd1) feat: add process scheduling options\n* [`77e9db4ab`](https://github.com/siderolabs/talos/commit/77e9db4abf9c9b694d60c8803b436121dfe30ccd) test: use two workers in qemu tests by default\n* [`5a4bdf62a`](https://github.com/siderolabs/talos/commit/5a4bdf62a9bf1387b6489eaf2c9cc0770aa0b68c) feat: update Kubernetes to 1.32.0-rc.1\n* [`d99bcc950`](https://github.com/siderolabs/talos/commit/d99bcc95031037f4b0990419d2ce1fd4280cbde9) chore: refactor mergeDNSServers func\n* [`0cde08d8b`](https://github.com/siderolabs/talos/commit/0cde08d8be1ad62c49fed148fd331ea5a212df4c) docs: add Turing RK1 docs to Single Board Computer section\n</p>\n</details>\n\n### Changes since v1.10.0-alpha.0\n<details><summary>97 commits</summary>\n<p>\n\n* [`3a2d9867b`](https://github.com/siderolabs/talos/commit/3a2d9867b5cc3236b1d1c7981e5794657f3c155e) fix: do not close client.Client.conn with finalizer\n* [`73f30ff25`](https://github.com/siderolabs/talos/commit/73f30ff25e0adb7a47e2153756e0ea94bd605568) feat: bump pkgs for udev update\n* [`aea90cb8f`](https://github.com/siderolabs/talos/commit/aea90cb8f1dbe7d5f67d35714825133728c1490d) docs: update hyper-v\n* [`b7165615f`](https://github.com/siderolabs/talos/commit/b7165615f86afd09ea85dc91090a40860ae6fc9a) fix: use local NTP for AWS platform\n* [`673ca4bcb`](https://github.com/siderolabs/talos/commit/673ca4bcb2448b3c252fccff0d243932c97fd893) fix: ensure proper closure of client.Client.conn with finalizer\n* [`19040ffd6`](https://github.com/siderolabs/talos/commit/19040ffd6ef128daaf48a820d8826186c82c68c5) fix: handle of PE sections with duplicate names\n* [`83489d348`](https://github.com/siderolabs/talos/commit/83489d348905352497da0f6dc042f3e7f05cd4d7) docs: add note about vmxnet and flannel conflict\n* [`f1292f5e7`](https://github.com/siderolabs/talos/commit/f1292f5e7af4110270475d8bcc4bd39519419e03) docs: add iscsi-tools extension to prerequisites\n* [`93b4a3740`](https://github.com/siderolabs/talos/commit/93b4a3740ba0c35e8b62cbf8c70058d1e53c3b8e) test: bump timeout on rotate CA test\n* [`42e166984`](https://github.com/siderolabs/talos/commit/42e16698453a687a4293e7cfeeb0e09d4f084217) feat: support kexec from uki\n* [`8da264946`](https://github.com/siderolabs/talos/commit/8da264946cda9b4803fd9f2f4dfd0ed25445843b) docs: add Orange Pi 5 to Image Factory platforms and documentation\n* [`c5fb62e2e`](https://github.com/siderolabs/talos/commit/c5fb62e2e32690aa0235b0911ded1888084496a8) feat: update Linux to 6.2.11\n* [`83d007c16`](https://github.com/siderolabs/talos/commit/83d007c161e03311cede2153f35c32f608537290) feat: update etcd to 3.5.18\n* [`edf7c3288`](https://github.com/siderolabs/talos/commit/edf7c328835273e2bc6dd23c646091e6a03aa2e9) fix: pe uki extract\n* [`70f72c5b0`](https://github.com/siderolabs/talos/commit/70f72c5b00bce791d692ec3a0e9a91aaf9d88031) docs: update multus.md\n* [`807a3cd29`](https://github.com/siderolabs/talos/commit/807a3cd291e2e2cb22946826bccb64671a29d901) refactor: all network merge controllers\n* [`ec8c4660e`](https://github.com/siderolabs/talos/commit/ec8c4660e277dc11b5e70c014a0238d48cf15bda) docs: update vmware.md\n* [`baf81cd49`](https://github.com/siderolabs/talos/commit/baf81cd4914470b06393d762f70d0a94f7a9fe32) fix(ci): k8s integration suite wait for resource\n* [`cd5e54903`](https://github.com/siderolabs/talos/commit/cd5e549039b17add0a2ce09713e1a034bb3efccf) feat: generate iso's with both UKI and grub\n* [`75673b6a3`](https://github.com/siderolabs/talos/commit/75673b6a38eeb6361c6e6aeb389e8dbaaacb8b0b) feat: provide stable symlinks in disk resources\n* [`f407c88e4`](https://github.com/siderolabs/talos/commit/f407c88e4678ff6d5edb940f5d54461104be3643) fix(ci): wait for longhorn node resource\n* [`601cdccb9`](https://github.com/siderolabs/talos/commit/601cdccb979640a6b2ffcba41cc698015b1dacde) feat: extract kernel/initrd from uki for grub\n* [`ff175b9fb`](https://github.com/siderolabs/talos/commit/ff175b9fbdb2ac92ac53351d32de130bd0676038) docs: update disk-encryption.md\n* [`a8d84e315`](https://github.com/siderolabs/talos/commit/a8d84e3155137a114ad00ad7ae321af033020e7d) docs: fix typos and add more explanations in docs\n* [`3a384240e`](https://github.com/siderolabs/talos/commit/3a384240ecf660d310f2df98327f018649ebaa6d) fix: invalid date field in iqn/nqn\n* [`82c9ec158`](https://github.com/siderolabs/talos/commit/82c9ec158e82efea80daaf76fef9fbd31c3eb823) chore(ci): add tests with longhorn v2 engine\n* [`689ea1dbf`](https://github.com/siderolabs/talos/commit/689ea1dbfe29d70d91e0b41d31fc696e2ff96665) fix: bring back disk UUID\n* [`7a712fad2`](https://github.com/siderolabs/talos/commit/7a712fad2abb916f397a8dd0aebf66e59ee75904) fix: disks with 4k sector size and systemd-boot\n* [`d62a34aaf`](https://github.com/siderolabs/talos/commit/d62a34aaf4e4ff7dad9f6dbeb59a67016c70fffb) feat: update tools/pkgs/extras\n* [`b9a8ad6ac`](https://github.com/siderolabs/talos/commit/b9a8ad6acafd64c4217ba914184592c0cfb97962) chore: de-hardcode list of extra images for image-cache test\n* [`683153a33`](https://github.com/siderolabs/talos/commit/683153a33c1069e7f7cadf4e3a70bde3f8ba3331) docs: remove the last mentions of `preserve` flag for Talos 1.8+\n* [`33c7f4195`](https://github.com/siderolabs/talos/commit/33c7f4195816988af6f70199fdb4a31d027fa746) docs: fix typo an MacOS to on MacOS\n* [`21cff3919`](https://github.com/siderolabs/talos/commit/21cff3919b80f33f837b19728500fcb91e7caf8f) chore(ci): fio benchmark results as separate artifacts\n* [`0b7fc7cdf`](https://github.com/siderolabs/talos/commit/0b7fc7cdfea651a6f16db3f346473505d8df3e78) fix: abort node watch on hostname change\n* [`99ba53941`](https://github.com/siderolabs/talos/commit/99ba53941cecdc54c0ececa9876b25a7fc7668a5) docs: remove the mention of `preserve` flag for Talos 1.8+\n* [`bde516fde`](https://github.com/siderolabs/talos/commit/bde516fde62a25dd60691a9a3b6f3d30de11dad1) chore(ci): rework iscsi-tools extensions test\n* [`e1efbf656`](https://github.com/siderolabs/talos/commit/e1efbf656ae96ecedba1c132608c3ad2d3ae4a66) refactor: extract platform metadata into Talos machinery\n* [`79987c05d`](https://github.com/siderolabs/talos/commit/79987c05dcd39ca646c2d73c1e25488504f13a60) feat: generate iqn and nqn files\n* [`0cab6ed17`](https://github.com/siderolabs/talos/commit/0cab6ed170708549d69c04b163744854de0aa8f2) docs: update troubleshooting.md\n* [`921e10254`](https://github.com/siderolabs/talos/commit/921e10254d443c459a9775368ca080ecba273321) chore: update Go to 1.23.5\n* [`399d53b54`](https://github.com/siderolabs/talos/commit/399d53b543f6ca99f13d28313ae77b3472b0f728) fix: ignore forbidden error when waiting for pod eviction\n* [`8dea57a81`](https://github.com/siderolabs/talos/commit/8dea57a81b8393b518da60951713c711659291f9) fix: make etc binds read-only\n* [`63157dcb4`](https://github.com/siderolabs/talos/commit/63157dcb496ca767bfbff9e1b86f14277a44cdb7) docs: update SideroLinkConfig example\n* [`fc7080e34`](https://github.com/siderolabs/talos/commit/fc7080e34b990d2d50ec1e40734437ccd0ee95f7) chore: clear cache after updating upstreams\n* [`51e0f273f`](https://github.com/siderolabs/talos/commit/51e0f273f9199b8320cd5da247c702a4319a92c5) docs: update documentation for Talos 1.9.2\n* [`e06b14112`](https://github.com/siderolabs/talos/commit/e06b14112d2c978e3f6b5c4446090a7ae533ead9) feat: update Kubernetes to 1.32.1\n* [`4310b290d`](https://github.com/siderolabs/talos/commit/4310b290d5cff9697f86cc24f1c281e62cb7d72f) fix: generate UKI only if actually needed\n* [`a8cd99102`](https://github.com/siderolabs/talos/commit/a8cd991026fe7290013b7504a4e87af46c49d25b) docs: update OpenEBS Mayastor installation\n* [`cf45f4764`](https://github.com/siderolabs/talos/commit/cf45f4764ddd979fa81576833d9630eadea24f41) docs: add Radxa ROCK 5B docs to Single Board Computer section\n* [`b21bdc5e5`](https://github.com/siderolabs/talos/commit/b21bdc5e501bc2244e3e487827ffba79075f6642) chore(ci): save csi tests fio results\n* [`01c86832c`](https://github.com/siderolabs/talos/commit/01c86832cbbbe0b81b9500032f94298fd6e90b58) chore(ci): add test for OpenEBS MayaStor\n* [`c77483510`](https://github.com/siderolabs/talos/commit/c774835103ad139b44d7e4e13c003e2b13160347) test: update `talosctl debug air-gapped`\n* [`ddd695d93`](https://github.com/siderolabs/talos/commit/ddd695d933d39920da42219ba8b3d39b0681a3ea) feat: update containerd to 2.0.2\n* [`da2e81120`](https://github.com/siderolabs/talos/commit/da2e81120f7336d9633a98523e05d91f5750434f) fix: add informer resync period for node status watcher\n* [`9b957df64`](https://github.com/siderolabs/talos/commit/9b957df64680a97a16575db67d4af27cfc0ef7d2) chore: uki code restructure\n* [`e41a99525`](https://github.com/siderolabs/talos/commit/e41a995253428dde437eecec52cabfb4c80f90ea) fix: kube-apiserver authorizers order\n* [`db4ca5668`](https://github.com/siderolabs/talos/commit/db4ca5668ac0d85a98a5ea022f6546526d20aff1) feat: add a kernel parameter to disable built-in auditd\n* [`faa149003`](https://github.com/siderolabs/talos/commit/faa1490033df0a843010fa7154096d84f415afce) feat: update Linux to 6.12.9\n* [`8de19758d`](https://github.com/siderolabs/talos/commit/8de19758dafce802c0f93a63ae3083b5ad17162d) fix: a couple of imager panics/crashes\n* [`5bc3e34cb`](https://github.com/siderolabs/talos/commit/5bc3e34cb3a6fd8e3eb5d02dd612cf3cf9dc499f) fix: detect GPT before ZFS\n* [`ed7e47d15`](https://github.com/siderolabs/talos/commit/ed7e47d158e064204b2f14f9ff378bea70e9524e) refactor: drop usage of objcopy to generate UKIs\n* [`edf5c5e29`](https://github.com/siderolabs/talos/commit/edf5c5e29bc76299c63bb04f1d97a030ecb9b3f0) fix: extfs repair and resize\n* [`6e32ea5b7`](https://github.com/siderolabs/talos/commit/6e32ea5b7f1a22500014ecb365e13af36034187a) fix: merge of VolumeConfig documents with sizes\n* [`1be5f8ff2`](https://github.com/siderolabs/talos/commit/1be5f8ff25ac7042ee3334f657d6604ec5f8501d) feat: update Linux to 6.12.8\n* [`e6a4583ba`](https://github.com/siderolabs/talos/commit/e6a4583ba862da9f49ab0bd0cb6bc8436723bc67) feat: support generating unsigned UKIs\n* [`bbd6067d4`](https://github.com/siderolabs/talos/commit/bbd6067d426fb2be22ff8935f415ab6d729d8f19) fix: partition alignment on disks with 4k sectors\n* [`84fcc976f`](https://github.com/siderolabs/talos/commit/84fcc976f8da5af310771e1835a0347df5bcc97d) fix: yet another dashboard panic\n* [`6d605fc85`](https://github.com/siderolabs/talos/commit/6d605fc8595e2f06e43529966e396f2ae403c76c) fix: disable NRI plugin in a different way\n* [`499695e24`](https://github.com/siderolabs/talos/commit/499695e24ea02ffc2fd8c92276d5de41b0d4919e) fix: request previous IP address in discovery\n* [`cc84caf8c`](https://github.com/siderolabs/talos/commit/cc84caf8c0dffd9d59f360f84967c524be9ba369) docs: update Cilium documentation\n* [`fa5300d91`](https://github.com/siderolabs/talos/commit/fa5300d910a537f03939fcbf6362abdd8fa607dd) chore: revert: drop deprecated allowSchedulingOnMasters\n* [`0abb3dabf`](https://github.com/siderolabs/talos/commit/0abb3dabf6d50b9c1176af683ad74234334f822d) docs: fix command to wait for ceph-rook HEALTH_OK\n* [`32c67c27c`](https://github.com/siderolabs/talos/commit/32c67c27c393c989f9d70ccb8506c4735f70d494) chore: drop deprecated allowSchedulingOnMasters\n* [`ae6d065be`](https://github.com/siderolabs/talos/commit/ae6d065beb4897a1b877ecb30b06be456befbf91) fix: mount selinuxfs only when SELinux is enabled\n* [`5ccbf4bcd`](https://github.com/siderolabs/talos/commit/5ccbf4bcdbe9aa2096320d17eb2deab6a062faf9) feat: enable `configfs`\n* [`59582496d`](https://github.com/siderolabs/talos/commit/59582496d5fe419f833703be8e956163b6241d15) feat: bring in partity with sd-257\n* [`83d84a831`](https://github.com/siderolabs/talos/commit/83d84a831862c774b9bc2adc2e11e00bf2a79912) chore(ci): better zfs checks\n* [`650eb3a4f`](https://github.com/siderolabs/talos/commit/650eb3a4f2d89d173cdd6581a6d1232511a8e219) refactor: rewrite cloud uploader to use AWS SDK Go v2\n* [`01bf8449b`](https://github.com/siderolabs/talos/commit/01bf8449b917ece76336ca7f0eb11fd877195025) fix: update field name for bus path disk selector\n* [`e915c98d5`](https://github.com/siderolabs/talos/commit/e915c98d583e5901c1c2efe38efa656b39d72360) fix: exclude disks with empty transport for disk selector\n* [`b7a7fdc4b`](https://github.com/siderolabs/talos/commit/b7a7fdc4b8a715157bfa2614c9541b96643cd2ba) refactor: generate /etc/os-release file static way\n* [`e79c9e127`](https://github.com/siderolabs/talos/commit/e79c9e12772c998ff5b3e401efd7f074f85e5cef) chore(ci): drop equinix metal e2e-test\n* [`418945444`](https://github.com/siderolabs/talos/commit/418945444135c6d9e2e5960e7b9cbd754084fea2) fix: build of talosctl on non-Linux platforms\n* [`4761a9e6a`](https://github.com/siderolabs/talos/commit/4761a9e6aa0bf619a564807d02ebce030384d6a1) chore: update dependencies\n* [`f98efb333`](https://github.com/siderolabs/talos/commit/f98efb333f89b8493c55b91698c917437b7af310) fix: ignore member not found error on leave cluster\n* [`b72bda0a4`](https://github.com/siderolabs/talos/commit/b72bda0a420f75ea0439cc0240dcf6d3363e5d48) fix: talosctl support and race tests\n* [`27233cf0f`](https://github.com/siderolabs/talos/commit/27233cf0fcf4031cbc8001504bed67b6d4a104f9) test: use node informer instead of raw watch\n* [`5dc15e8db`](https://github.com/siderolabs/talos/commit/5dc15e8db459ac632f0ae106e1cfc7eaab672adf) fix: update go-blockdevice to v2.0.9\n* [`5f3acd0f2`](https://github.com/siderolabs/talos/commit/5f3acd0f26a35ac966d4ced01436f1dd3c03648b) fix: use correct default search domain\n* [`7e5d36d46`](https://github.com/siderolabs/talos/commit/7e5d36d469ff01153f40b16ab722f0ebe25d41ae) fix: pci driver rebind config validation\n* [`4b97bbc3f`](https://github.com/siderolabs/talos/commit/4b97bbc3fee1257d0d21be25e21493bfd1f45a80) fix: pull in containerd CNI deadlock fix\n* [`066480722`](https://github.com/siderolabs/talos/commit/0664807229e0688f092a453cbd3121dbe189ca39) test: fix apparmor tests\n* [`82ea44a6b`](https://github.com/siderolabs/talos/commit/82ea44a6b2aa0a35861ca454a09503a81332f824) fix: reduce installer image\n* [`78b3e7f4f`](https://github.com/siderolabs/talos/commit/78b3e7f4f1870085b719971c6f92dc866fe1e9d0) fix: get next rule number for IPv6 in the appropriate chain\n* [`675854aa0`](https://github.com/siderolabs/talos/commit/675854aa03b3913da3481337d995c206174cf004) docs: fix two typos\n* [`f70b7386a`](https://github.com/siderolabs/talos/commit/f70b7386ac3125f3b8ab6b1765338c7e3445ae5c) test: add a xfs makefs test\n* [`8212e4864`](https://github.com/siderolabs/talos/commit/8212e4864d11e69ed63be3f4e608e9ccbc788cc4) refactor: use quirks in kernel args\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`0d45dee`](https://github.com/siderolabs/crypto/commit/0d45deefbcdd4bd6b6e549433b859083df55fc16) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>5 commits</summary>\n<p>\n\n* [`f4a110f`](https://github.com/siderolabs/extras/commit/f4a110f5f4b472743dc023413dca280bce491ec1) fix: build tc-redirect-tap as static binary\n* [`0840abb`](https://github.com/siderolabs/extras/commit/0840abb9b5e32560ff38577151fdc2f51812ce31) fix: pull in fixed CNI plugins from pkgs\n* [`52c217f`](https://github.com/siderolabs/extras/commit/52c217f693366bdf21772919ad94933fd160c5d4) feat: update dependencies\n* [`f755eb4`](https://github.com/siderolabs/extras/commit/f755eb483647d17e487f7cb62de8cc150a420c3c) chore: rekres to simplify `.kres.yaml` defaults\n* [`e5382fc`](https://github.com/siderolabs/extras/commit/e5382fc5f05d7ccfdb7c95819195caceac8ffcbf) chore: kresify renovate\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`5ae3afe`](https://github.com/siderolabs/gen/commit/5ae3afee65490ca9f4bd32ea41803ab3a17cad7e) chore: update hashtriemap implementation from the latest upstream\n</p>\n</details>\n\n### Changes from siderolabs/go-talos-support\n<details><summary>1 commit</summary>\n<p>\n\n* [`0f784bd`](https://github.com/siderolabs/go-talos-support/commit/0f784bd58b320543663679693c817515067f3021) fix: avoid deadlock on context cancel\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>35 commits</summary>\n<p>\n\n* [`5763e3e`](https://github.com/siderolabs/pkgs/commit/5763e3e0fe00cbd9010398e795085ba0377802e8) feat: update systemd to 257.2\n* [`1e24b31`](https://github.com/siderolabs/pkgs/commit/1e24b31dc379251ad5248f94f548e5c7330f59ec) feat: update Linux to 6.12.11\n* [`38749d1`](https://github.com/siderolabs/pkgs/commit/38749d1f08fcb46e522450c1ad530309a8fa327d) fix: build CNI plugins statically linked\n* [`5da83db`](https://github.com/siderolabs/pkgs/commit/5da83dbbe320768db8eb6175b1e7c5e8ff78389d) feat: bump NVIDIA driver versions\n* [`5934363`](https://github.com/siderolabs/pkgs/commit/59343630a024e48dfeba826eac45589d0bdcfb99) fix: certificates CA\n* [`57f492d`](https://github.com/siderolabs/pkgs/commit/57f492d4c3e51e01ab85d2727a7862b21ab21795) feat: bump dependencies\n* [`45b9ebe`](https://github.com/siderolabs/pkgs/commit/45b9ebed9437752c6516792678356a595f1ec62b) feat: update Linux to 6.2.10\n* [`e00ad67`](https://github.com/siderolabs/pkgs/commit/e00ad677f0c7ef4005d26108143c3fe5e36aaab2) chore: rekres to fix reproducibility build\n* [`cfb4b0a`](https://github.com/siderolabs/pkgs/commit/cfb4b0a79490156864eab726debe20559d9c4240) feat: update Go to 1.23.5\n* [`72f19a2`](https://github.com/siderolabs/pkgs/commit/72f19a2983e7abcb620ab57fae6e039158663f1a) feat: update containerd to v2.0.2\n* [`17a80ee`](https://github.com/siderolabs/pkgs/commit/17a80eeb75b91211d4ffe8a910feb9fddcd1e585) feat: update Linux to 6.12.9\n* [`c9d718d`](https://github.com/siderolabs/pkgs/commit/c9d718d3d6fd762ca3a649a14aa2d74e47d707e2) fix: adjust kernel options around ACPI/PCI/EFI\n* [`eb9d566`](https://github.com/siderolabs/pkgs/commit/eb9d56617faa56e42648a07b6756c18850e4a045) feat: update Linux to 6.12.8\n* [`73e4353`](https://github.com/siderolabs/pkgs/commit/73e4353ad9e2dad6dc8544436776fd412c808d63) fix: update config-arm64 to add Rasperry Pi watchdog support\n* [`0ab2427`](https://github.com/siderolabs/pkgs/commit/0ab2427a8415d3f29cd4f52e3afd51f701aa5848) fix: dvb was missing I2C_MUX support and si2168 driver\n* [`c3ac8e2`](https://github.com/siderolabs/pkgs/commit/c3ac8e2d553b068dd982f5b9e48f6b1e0cfdd24d) chore: drop unused cert copy\n* [`e7eddcf`](https://github.com/siderolabs/pkgs/commit/e7eddcf9498634749a4241844660fd0e9d87fad4) feat: bump dependencies\n* [`0b00e86`](https://github.com/siderolabs/pkgs/commit/0b00e86ae92f821bdc19af73a5ba571b5051c89a) fix: patch containerd with CNI deadlock fix\n* [`9051c9a`](https://github.com/siderolabs/pkgs/commit/9051c9ac6f60e039c53248b52ba4ccd192e34b6b) feat: update Linux to 6.12.6\n* [`6695012`](https://github.com/siderolabs/pkgs/commit/6695012e8d93d28ea70fc3ba32ed90770eea4363) chore: rekres to simplify `.kres.yaml` defaults\n* [`611ca38`](https://github.com/siderolabs/pkgs/commit/611ca38153fece4f2b34519325fbca22d34db7a0) chore: rekres to bring renovate under kres\n* [`a4c4215`](https://github.com/siderolabs/pkgs/commit/a4c4215e74b68765ada0745165b2e2fb5ee508f5) fix: drop cgroupsv1 controllers\n* [`28c909d`](https://github.com/siderolabs/pkgs/commit/28c909ddeaf0d33e0fc6c5fdf2333a18801cf178) feat: update Linux firmware to 20241210\n* [`c40a9e9`](https://github.com/siderolabs/pkgs/commit/c40a9e9713b1fde14f7a967fd1be168bb905d7c9) feat: update Linux to 6.12.5\n* [`d54ca83`](https://github.com/siderolabs/pkgs/commit/d54ca835a8868e5df55e2d0ffe3cb0dfa82a3395) feat: update containerd to v2.0.1\n* [`86e3755`](https://github.com/siderolabs/pkgs/commit/86e3755deae2fc85d7e62bdcf82a54cb72fec6d5) fix: add CONFIG_INTEL_MEI_GSC_PROXY as module\n* [`8c31321`](https://github.com/siderolabs/pkgs/commit/8c3132135d5a0e01a9d66790b4b25c7c05e08fa5) feat: update ZFS to 2.2.7\n* [`605f493`](https://github.com/siderolabs/pkgs/commit/605f493abfeac79151c02a776733011f19d6c43b) feat: update runc to v1.2.3\n* [`1a55529`](https://github.com/siderolabs/pkgs/commit/1a555296764ab0ad83fb4eca6509bb64feff3b7b) feat: update Linux to 6.12.4\n* [`52ba9a5`](https://github.com/siderolabs/pkgs/commit/52ba9a57358ef37ce3e4aa4033991dc77ad17fbb) feat: update Linux 6.12.3\n* [`9cf35be`](https://github.com/siderolabs/pkgs/commit/9cf35bef274bb445e578f858a0a595b05b44a01f) feat: build host iptables with nftables support\n* [`71003a3`](https://github.com/siderolabs/pkgs/commit/71003a3c9bff00685917d6e272421a7206b1667e) feat: update Go to 1.23.4\n* [`5b4d402`](https://github.com/siderolabs/pkgs/commit/5b4d402bd33f9313a21e4924be57aacce569f9ad) feat: build dvb kernel modules and CX23885\n* [`b330af9`](https://github.com/siderolabs/pkgs/commit/b330af9b95d9115382c81f88b55c17b99f7ef355) chore: bring in KSPP recommendations\n* [`f81b190`](https://github.com/siderolabs/pkgs/commit/f81b190cc65dc93f9212d52cd95806ac79c170d2) feat: kernel driver support for RK3588 devices (Turing RK1)\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>8 commits</summary>\n<p>\n\n* [`7200845`](https://github.com/siderolabs/tools/commit/7200845be9d0318d23eb77a57e1b8992dd7e8187) feat: update dependencies\n* [`bc30a2a`](https://github.com/siderolabs/tools/commit/bc30a2a3ace873c80e4657b622e3142efb55cc28) feat: update Go to 1.23.5\n* [`533b595`](https://github.com/siderolabs/tools/commit/533b5953d28213aae4d4ae576bedf5df84712458) chore: rekres to fix reproducibility\n* [`01568a5`](https://github.com/siderolabs/tools/commit/01568a5b42685c3ea19578a7f4d7ba07dc0f18cd) chore: use Make and Go from the toolchain image\n* [`0393558`](https://github.com/siderolabs/tools/commit/03935581049f82ff466defcc203c5bcc6db5b43a) feat: bump dependencies\n* [`7811a5f`](https://github.com/siderolabs/tools/commit/7811a5f2f23923cdfe5bfd47ee12ed9e88b29585) chore: rekres to simplify `.kres.yaml` defaults\n* [`0b8b905`](https://github.com/siderolabs/tools/commit/0b8b9054833d8187bb1f6209b2441719f6e62cfa) chore: kresify renovate config\n* [`fe34fb3`](https://github.com/siderolabs/tools/commit/fe34fb3d54ec9abe878a9304fbfc3e1e741c0ff4) feat: update Go to 1.23.4\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**             v0.5.2 -> v0.6.0\n* **github.com/aws/aws-sdk-go-v2/config**              v1.28.5 -> v1.28.7\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**    v1.16.20 -> v1.16.22\n* **github.com/aws/aws-sdk-go-v2/service/kms**         v1.37.6 -> v1.37.8\n* **github.com/containerd/cgroups/v3**                 v3.0.4 -> v3.0.5\n* **github.com/containerd/containerd/v2**              v2.0.1 -> v2.0.2\n* **github.com/containerd/platforms**                  v1.0.0-rc.0 -> v1.0.0-rc.1\n* **github.com/containernetworking/plugins**           v1.6.0 -> v1.6.1\n* **github.com/cosi-project/runtime**                  v0.7.6 -> v0.8.1\n* **github.com/docker/cli**                            v27.3.1 -> v27.4.1\n* **github.com/docker/docker**                         v27.3.1 -> v27.4.1\n* **github.com/foxboron/go-uefi**                      fab4fdf2f2f3 -> 19dc140271bf\n* **github.com/google/go-tpm**                         v0.9.1 -> v0.9.3\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**  v2.1.0 -> v2.2.0\n* **github.com/hetznercloud/hcloud-go/v2**             v2.17.0 -> v2.17.1\n* **github.com/opencontainers/runc**                   v1.2.2 -> v1.2.4\n* **github.com/siderolabs/crypto**                     v0.5.0 -> v0.5.1\n* **github.com/siderolabs/extras**                     v1.9.0 -> v1.10.0-alpha.0-2-gf4a110f\n* **github.com/siderolabs/gen**                        v0.7.0 -> v0.8.0\n* **github.com/siderolabs/go-blockdevice/v2**          v2.0.7 -> v2.0.13\n* **github.com/siderolabs/go-talos-support**           v0.1.1 -> v0.1.2\n* **github.com/siderolabs/pkgs**                       v1.9.0-12-g9576b97 -> v1.10.0-alpha.0-34-g5763e3e\n* **github.com/siderolabs/talos/pkg/machinery**        v1.9.0 -> v1.10.0-alpha.0\n* **github.com/siderolabs/tools**                      v1.9.0-1-geaad82f -> v1.10.0-alpha.0-7-g7200845\n* **github.com/thejerf/suture/v4**                     v4.0.5 -> v4.0.6\n* **go.etcd.io/etcd/api/v3**                           v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/client/pkg/v3**                    v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/client/v3**                        v3.5.17 -> v3.5.18\n* **go.etcd.io/etcd/etcdutl/v3**                       v3.5.17 -> v3.5.18\n* **golang.org/x/net**                                 v0.32.0 -> v0.34.0\n* **golang.org/x/sys**                                 v0.28.0 -> v0.29.0\n* **golang.org/x/term**                                v0.27.0 -> v0.28.0\n* **google.golang.org/grpc**                           v1.68.1 -> v1.69.2\n* **google.golang.org/protobuf**                       v1.35.2 -> v1.36.1\n* **k8s.io/api**                                       v0.32.0 -> v0.32.1\n* **k8s.io/apiserver**                                 v0.32.0 -> v0.32.1\n* **k8s.io/client-go**                                 v0.32.0 -> v0.32.1\n* **k8s.io/component-base**                            v0.32.0 -> v0.32.1\n* **k8s.io/kube-scheduler**                            v0.32.0 -> v0.32.1\n* **k8s.io/kubectl**                                   v0.32.0 -> v0.32.1\n* **k8s.io/kubelet**                                   v0.32.0 -> v0.32.1\n* **k8s.io/pod-security-admission**                    v0.32.0 -> v0.32.1\n* **kernel.org/pub/linux/libs/security/libcap/cap**    v1.2.72 -> v1.2.73\n\nPrevious release can be found at [v1.9.0](https://github.com/siderolabs/talos/releases/tag/v1.9.0)\n\n## [Talos 1.10.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.10.0-alpha.0) (2024-12-23)\n\nWelcome to the v1.10.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### cgroups v1\n\nTalos Linux no longer supports `cgroupsv1` when running in non-container mode.\nThe kernel argument `talos.unified_cgroup_hierarchy` is now ignored.\n\n\n### Driver Rebind\n\nTalos 1.10 now supports a new machine config document named `PCIDriverRebindConfig` that allows rebinding the driver of a PCI device to a different target driver.\nSee the [documentation](https://www.talos.dev/v1.10/reference/configuration/hardware/pcidriverrebindconfig/) for more information.\n\n\n### Component Updates\n\n* Linux: 6.12.6\n* CNI plugins: 1.6.1\n\nTalos is built with Go 1.23.4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Dmitry Sharshakov\n* Nico Berlee\n* Utku Ozdemir\n* Alexis La Goutte\n* Andrew Symington\n* Christian Luetke-Stetzkamp\n* Devin Buhl\n* Justin Garrison\n* KillianCdP\n* Marcel Hamer\n* PRIHLOP\n* Skyler Mäntysaari\n* Tine Jozelj\n* sflotat2607\n\n### Changes\n<details><summary>63 commits</summary>\n<p>\n\n* [`bd85bd5b7`](https://github.com/siderolabs/talos/commit/bd85bd5b731463a42b7c82c66e9add251a280d26) fix: fix `Failed to initialize SELinux labeling handle` udev error\n* [`73c82e3e5`](https://github.com/siderolabs/talos/commit/73c82e3e5625ec1899f93312a671dfe6dffaea61) feat: bring Linux 6.12.6, CNI plugins 1.6.1\n* [`c12b52491`](https://github.com/siderolabs/talos/commit/c12b52491456d1e52204eb290d0686a317358c7c) docs: document Kubernetes service registry incompat with K8s 1.32\n* [`a5660ed77`](https://github.com/siderolabs/talos/commit/a5660ed778108843fe15b2b1582dd6556cf52b6c) feat: pcirebind controller\n* [`4c3261626`](https://github.com/siderolabs/talos/commit/4c3261626fa3f5ac36df71ec878f103a7c85c5c5) docs: fix several typos\n* [`fb3675321`](https://github.com/siderolabs/talos/commit/fb36753216cba7740040f2ec117c783221f66192) fix: dashboard crash on CPU data\n* [`dec0185c8`](https://github.com/siderolabs/talos/commit/dec0185c8505a7d43244fdb01f7a5decc77d116d) chore: reduce memory usage for secureboot functions\n* [`cee6c60a0`](https://github.com/siderolabs/talos/commit/cee6c60a0fc301b22c50fdf8bd2fc1d2b7ba3d54) fix: make talosctl time work with PTP time sync\n* [`f75604313`](https://github.com/siderolabs/talos/commit/f75604313d535180c38b33df53253ad4acba2ec1) chore: support gcr.io auth for cache and image gen\n* [`6ef2596da`](https://github.com/siderolabs/talos/commit/6ef2596da7b7e8be90e5b981621461352be7b134) docs: improve Hetzner documentation\n* [`7d39b9ec2`](https://github.com/siderolabs/talos/commit/7d39b9ec2bdd7883116626bf889c1331717f8438) feat: remove cgroupsv1 in non-container mode\n* [`8003536c7`](https://github.com/siderolabs/talos/commit/8003536c7ca20356adcd900e64463bd166d445af) fix: restore previous disk serial fetching\n* [`03116ef9b`](https://github.com/siderolabs/talos/commit/03116ef9bd2a215c20a2c4c7db133dd857ce2b16) chore: prepare for Talos 1.10\n* [`00682fdd6`](https://github.com/siderolabs/talos/commit/00682fdd6e8fa23c6f9782840ea3e2b8ef250f66) docs: activate 1.9 docs as default\n* [`bea05f5c9`](https://github.com/siderolabs/talos/commit/bea05f5c9b6ce6f5d067eb357d26e30a49154b21) docs: update deploying-cilium.md\n* [`284ab1179`](https://github.com/siderolabs/talos/commit/284ab11794b3b076aa9ab2bb756e02292d854751) feat: support link altnames/aliases\n* [`5bfd829bf`](https://github.com/siderolabs/talos/commit/5bfd829bf9c8e46b6c51174be4b764d4c94b3320) docs: fix 'containter' typo\n* [`8d151b771`](https://github.com/siderolabs/talos/commit/8d151b771debc51d3fa40dfafc7a2e43f955a634) docs: clarify TALOSCONFIG for AWS\n* [`0ef19171f`](https://github.com/siderolabs/talos/commit/0ef19171f738e46346dfae71f43b8f7b47bf257d) fix: renovate typo\n* [`c568adc7d`](https://github.com/siderolabs/talos/commit/c568adc7dcd52c34924acc1eae849a2ca5b5a4d5) fix: renovate config\n* [`ec2e24fd9`](https://github.com/siderolabs/talos/commit/ec2e24fd9617db34e3bec753b5fe720670fa31a4) fix: match MAC addresses case-insensitive (nocloud)\n* [`41a0c440a`](https://github.com/siderolabs/talos/commit/41a0c440ad3f4de2a2ba9198d22609c55bdaf61b) chore: rekres for renovate changes\n* [`a49bb9ee4`](https://github.com/siderolabs/talos/commit/a49bb9ee45346268b26d3b9cff4dd017bfb9c829) feat: update Linux to 6.12.5\n* [`b15917ecc`](https://github.com/siderolabs/talos/commit/b15917ecc626781e13de0e84b794ab77c97b3159) chore: add more debugging logs for META and volumes\n* [`2b1b326f0`](https://github.com/siderolabs/talos/commit/2b1b326f08966615a5a2f8708f94e6d1355773a7) docs: mention different paths for OpenEBS\n* [`9470e842f`](https://github.com/siderolabs/talos/commit/9470e842fca2d7dd0dae185bff7210a8af355445) test: cleanup failed Kubernetes pods\n* [`c9c685150`](https://github.com/siderolabs/talos/commit/c9c6851504fcda7b66395fbbba1fbc8b0e085d4a) fix: node identity flip\n* [`590c01657`](https://github.com/siderolabs/talos/commit/590c0165712aee60e752766d6bd3875443c353cb) feat: update containerd to v2.0.1\n* [`18fa5a258`](https://github.com/siderolabs/talos/commit/18fa5a25876f41760ce8da5e918222e04b81949a) docs: update image-cache doc for iso\n* [`ab5bb6884`](https://github.com/siderolabs/talos/commit/ab5bb688420986a356aed55513a1dbd25de323e2) fix: generate and serve registries with port\n* [`58236066d`](https://github.com/siderolabs/talos/commit/58236066ddbcd7c401e945b70555ff315a2458f7) fix: support image cache on VFAT USB stick\n* [`e193a5071`](https://github.com/siderolabs/talos/commit/e193a507149c05e341abe019de219fe0b1bc83e3) fix: image cache integration test\n* [`08ee400fd`](https://github.com/siderolabs/talos/commit/08ee400fdbde368a54d6777cc31ceb91e1968ad2) test: fix flaky test NodeAddressSort\n* [`d45e8d1d1`](https://github.com/siderolabs/talos/commit/d45e8d1d1da28ca1b311198588d723cb491527eb) feat: update Kubernetes to 1.32.0\n* [`136b12912`](https://github.com/siderolabs/talos/commit/136b12912165d5eb5c7c716b7f7dfcfbc42b08d4) chore: drop semicolon for supporting vfat filesystems\n* [`3e9e027ef`](https://github.com/siderolabs/talos/commit/3e9e027efbd2988f72eb2da0c1ab0e83ba52b950) test: add an option to boot from an USB stick\n* [`ef8c3e3b3`](https://github.com/siderolabs/talos/commit/ef8c3e3b3b245f7ffefa6c19930d5a0925ce666b) docs: fix typo in multus.md\n* [`d54414add`](https://github.com/siderolabs/talos/commit/d54414add4e4df1b5a7b166f155cdcca512d4ee2) fix: authorization config gen\n* [`cce72cfe8`](https://github.com/siderolabs/talos/commit/cce72cfe86beeb7ada9641df611046f4789e3bd8) docs: replace deprecated Hetzner server plans\n* [`81805103d`](https://github.com/siderolabs/talos/commit/81805103deada24b12b7d7861b2df5a5c788c86b) chore: enable proper parallel usage of TestDepth\n* [`e1b824eba`](https://github.com/siderolabs/talos/commit/e1b824ebada3d3dad9d2793fd12b5a948d8b51b5) docs: update ceph-with-rook.md\n* [`470b75563`](https://github.com/siderolabs/talos/commit/470b75563add4ce5bbce312c1e3dc783e63af1fa) fix: use mtu network option for podman\n* [`61b1489a0`](https://github.com/siderolabs/talos/commit/61b1489a0f0868c5b7e124544520bc46badef85c) fix: order volume config by the requested size\n* [`bc3039acd`](https://github.com/siderolabs/talos/commit/bc3039acdbc57e6be16a1bc6555894dff2da65c9) feat: update runc to 1.2.3\n* [`30016a0a8`](https://github.com/siderolabs/talos/commit/30016a0a8d98d42e01c4d32acf9e600777d72d57) fix: avoid nil-pointer-panic in `RegistriesConfigController`\n* [`fe0457152`](https://github.com/siderolabs/talos/commit/fe045715277a4678b8e8c9632ec71e86bf17ace0) fix: power on the machine on reboot request in qemu power api\n* [`10da553ef`](https://github.com/siderolabs/talos/commit/10da553ef0dde5f87f09321400239baa51929a36) docs: build what's new for 1.9\n* [`d946ccae3`](https://github.com/siderolabs/talos/commit/d946ccae31b87559a06cb1cefcefe8f937b73d8b) feat: update Linux to 6.12.4\n* [`707a77bf6`](https://github.com/siderolabs/talos/commit/707a77bf64190470bf84c91cdff185981e80a31b) test: fix user namespace test, TPM2 fixes\n* [`c3537b2f5`](https://github.com/siderolabs/talos/commit/c3537b2f5491a890f626ba8fc47034d5059808af) feat: update Linux to 6.12.3\n* [`cb4d9d673`](https://github.com/siderolabs/talos/commit/cb4d9d673432e4a0fba0d87bc64fde620d991082) docs: fix a few mistakes in release notes\n* [`c4724fc97`](https://github.com/siderolabs/talos/commit/c4724fc97598d8764b00fb56971d997a349a92e5) chore: add integration tests for image-cache\n* [`07220fe7f`](https://github.com/siderolabs/talos/commit/07220fe7f5a22444f7a085f5868f628ddd912b6d) fix: install iptables-nft to the host\n* [`14841750b`](https://github.com/siderolabs/talos/commit/14841750bf2fc09a9de0b32a7af0dc3f76e1019a) chore: add version compatibility for Talos 1.10\n* [`852baf819`](https://github.com/siderolabs/talos/commit/852baf819d453a3d8d58ae9f029e280ae75e0cb1) feat: support vlan/bond in v1, vlan in v2 for nocloud\n* [`dd61ad861`](https://github.com/siderolabs/talos/commit/dd61ad86105c07c1ff8a101a0542af61699f0df3) fix: lock provisioning order of user disk partitions\n* [`d0773ff09`](https://github.com/siderolabs/talos/commit/d0773ff09df84b2dac8ecadc91023596050ce098) chore: update Go to 1.23.4\n* [`7d6507189`](https://github.com/siderolabs/talos/commit/7d6507189ff9a99b3b05ee9528701b65af4ad147) feat: implement new address sorting algorithm\n* [`9081506d6`](https://github.com/siderolabs/talos/commit/9081506d6cde26d60a29f08a090e28da501e4bd1) feat: add process scheduling options\n* [`77e9db4ab`](https://github.com/siderolabs/talos/commit/77e9db4abf9c9b694d60c8803b436121dfe30ccd) test: use two workers in qemu tests by default\n* [`5a4bdf62a`](https://github.com/siderolabs/talos/commit/5a4bdf62a9bf1387b6489eaf2c9cc0770aa0b68c) feat: update Kubernetes to 1.32.0-rc.1\n* [`d99bcc950`](https://github.com/siderolabs/talos/commit/d99bcc95031037f4b0990419d2ce1fd4280cbde9) chore: refactor mergeDNSServers func\n* [`0cde08d8b`](https://github.com/siderolabs/talos/commit/0cde08d8be1ad62c49fed148fd331ea5a212df4c) docs: add Turing RK1 docs to Single Board Computer section\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>17 commits</summary>\n<p>\n\n* [`9051c9a`](https://github.com/siderolabs/pkgs/commit/9051c9ac6f60e039c53248b52ba4ccd192e34b6b) feat: update Linux to 6.12.6\n* [`6695012`](https://github.com/siderolabs/pkgs/commit/6695012e8d93d28ea70fc3ba32ed90770eea4363) chore: rekres to simplify `.kres.yaml` defaults\n* [`611ca38`](https://github.com/siderolabs/pkgs/commit/611ca38153fece4f2b34519325fbca22d34db7a0) chore: rekres to bring renovate under kres\n* [`a4c4215`](https://github.com/siderolabs/pkgs/commit/a4c4215e74b68765ada0745165b2e2fb5ee508f5) fix: drop cgroupsv1 controllers\n* [`28c909d`](https://github.com/siderolabs/pkgs/commit/28c909ddeaf0d33e0fc6c5fdf2333a18801cf178) feat: update Linux firmware to 20241210\n* [`c40a9e9`](https://github.com/siderolabs/pkgs/commit/c40a9e9713b1fde14f7a967fd1be168bb905d7c9) feat: update Linux to 6.12.5\n* [`d54ca83`](https://github.com/siderolabs/pkgs/commit/d54ca835a8868e5df55e2d0ffe3cb0dfa82a3395) feat: update containerd to v2.0.1\n* [`86e3755`](https://github.com/siderolabs/pkgs/commit/86e3755deae2fc85d7e62bdcf82a54cb72fec6d5) fix: add CONFIG_INTEL_MEI_GSC_PROXY as module\n* [`8c31321`](https://github.com/siderolabs/pkgs/commit/8c3132135d5a0e01a9d66790b4b25c7c05e08fa5) feat: update ZFS to 2.2.7\n* [`605f493`](https://github.com/siderolabs/pkgs/commit/605f493abfeac79151c02a776733011f19d6c43b) feat: update runc to v1.2.3\n* [`1a55529`](https://github.com/siderolabs/pkgs/commit/1a555296764ab0ad83fb4eca6509bb64feff3b7b) feat: update Linux to 6.12.4\n* [`52ba9a5`](https://github.com/siderolabs/pkgs/commit/52ba9a57358ef37ce3e4aa4033991dc77ad17fbb) feat: update Linux 6.12.3\n* [`9cf35be`](https://github.com/siderolabs/pkgs/commit/9cf35bef274bb445e578f858a0a595b05b44a01f) feat: build host iptables with nftables support\n* [`71003a3`](https://github.com/siderolabs/pkgs/commit/71003a3c9bff00685917d6e272421a7206b1667e) feat: update Go to 1.23.4\n* [`5b4d402`](https://github.com/siderolabs/pkgs/commit/5b4d402bd33f9313a21e4924be57aacce569f9ad) feat: build dvb kernel modules and CX23885\n* [`b330af9`](https://github.com/siderolabs/pkgs/commit/b330af9b95d9115382c81f88b55c17b99f7ef355) chore: bring in KSPP recommendations\n* [`f81b190`](https://github.com/siderolabs/pkgs/commit/f81b190cc65dc93f9212d52cd95806ac79c170d2) feat: kernel driver support for RK3588 devices (Turing RK1)\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`fe34fb3`](https://github.com/siderolabs/tools/commit/fe34fb3d54ec9abe878a9304fbfc3e1e741c0ff4) feat: update Go to 1.23.4\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/containernetworking/plugins**     v1.6.0 -> v1.6.1\n* **github.com/foxboron/go-uefi**                fab4fdf2f2f3 -> 19dc140271bf\n* **github.com/opencontainers/runc**             v1.2.2 -> v1.2.3\n* **github.com/siderolabs/go-blockdevice/v2**    v2.0.7 -> v2.0.8\n* **github.com/siderolabs/pkgs**                 v1.9.0-12-g9576b97 -> v1.10.0-alpha.0-16-g9051c9a\n* **github.com/siderolabs/talos/pkg/machinery**  v1.9.0 -> v1.9.0-alpha.3\n* **github.com/siderolabs/tools**                v1.9.0-1-geaad82f -> v1.10.0-alpha.0\n* **golang.org/x/net**                           v0.32.0 -> v0.33.0\n\nPrevious release can be found at [v1.9.0](https://github.com/siderolabs/talos/releases/tag/v1.9.0)\n\n## [Talos 1.9.0-alpha.3](https://github.com/siderolabs/talos/releases/tag/v1.9.0-alpha.3) (2024-11-25)\n\nWelcome to the v1.9.0-alpha.3 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### AppArmor\n\nTalos Linux starting with v1.9 will ship with SELinux LSM enabled by default.\nIf you need to use AppArmor LSM add the following to the machine configuration:\n\n```yaml\nmachine:\n  install:\n     extraKernelArgs:\n      - -selinux\n      - lsm=lockdown,capability,yama,apparmor,bpf\n      - apparmor=1\n```\n\n\n### Auditd\n\nTalos Linux now starts a auditd service by default.\nLogs can be read with `talosctl logs auditd`.\n\n\n### `talosctl cgroups`\n\nThe `talosctl cgroups` command has been added to the `talosctl` tool.\nThis command allows you to view the cgroup resource consumption and limits for a machine, e.g.\n`talosctl cgroups --preset memory`.\n\n\n### Device Selectors\n\nTalos now supports matching on permanent hardware (MAC) address of the network interfaces.\nThis is specifically useful to match bond members, as they change their hardware addresses when they become part of the bond.\n\n\n### Direct Rendering Manager (DRM)\n\nStarting with Talos 1.9, the `i915` and `amdgpu` DRM drivers will be dropped from the Talos squashfs.\nThere will be new system extensions named `i915` and `amdgpu` that would contain both the drivers and firmware packaged together.\nUpgrades via Image Factory will automatically include the new extensions if previously `i915-ucode` or `amdgpu-firmware` were used.\n\n\n### Registry Mirrors\n\nIn versions before Talos 1.9, there was a discrepancy between the way Talos itself and CRI plugin resolves registry mirrors:\nTalos will never fall back to the default registry if endpoints are configured, while CRI plugin will.\n\n> Note: Talos Linux pulls images for the `installer`, `kubelet`, `etcd`, while all workload images are pulled by the CRI plugin.\n\nIn Talos 1.9 this was fixed, so that by default an upstream registry is used as a fallback in all cases, while new registry mirror\nconfiguration option `.skipFallback` can be used to disable this behavior both for Talos and CRI plugin.\n\n\n### talosctl disks\n\nThe command `talosctl disks` was removed, please use `talosctl get disks`, `talosctl get systemdisk`, and `talosctl get blockdevices` instead.\n\n\n### talosctl wipe\n\nThe new command `talosctl wipe disk` allows to wipe a disk or a partition which is not used as a volume.\n\n\n### udevd\n\nTalos previously used `eudev` to provide `udevd`, now it uses `systemd-udevd` instead.\n\n\n### Component Updates\n\n* Linux: 6.6.60\n* containerd: 2.0.0\n* Flannel: 0.26.0\n* Kubernetes: 1.32.0-beta.0\n* runc: 1.2.1\n\nTalos is built with Go 1.23.3.\n\n\n### User Namespaces\n\nTalos Linux now supports running Kubernetes pods with user namespaces enabled.\nRefer to the [documentation](https://www.talos.dev/v1.9/kubernetes-guides/configuration/usernamespace/) for more information.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitry Sharshakov\n* Dmitriy Matrenichev\n* Joakim Nohlgård\n* Jean-Francois Roy\n* Utku Ozdemir\n* blablu\n* Adolfo Ochagavía\n* Alessio Moiso\n* Dan Rue\n* David Backeus\n* Eddie Wang\n* Florian Ströger\n* Hexoplon\n* Jakob Maležič\n* KBAegis\n* Mike Beaumont\n* Nebula\n* Nico Berlee\n* OliviaBarrington\n* Philip Schmid\n* Philipp Kleber\n* Remko Molier\n* Robby Ciliberto\n* Roman Ivanov\n* Ryan Borstelmann\n* Sam Stelfox\n* Serge Logvinov\n* Sergey Melnik\n* Spencer Smith\n* SpiReCZ\n* Steven Cassamajor\n* Steven Kreitzer\n* Tim Jones\n* Variant9\n* adilTepe\n* ekarlso\n* naed3r\n* nevermarine\n* solidDoWant\n* sophia-coldren\n\n### Changes\n<details><summary>189 commits</summary>\n<p>\n\n* [`af5d6b8c41`](https://github.com/siderolabs/talos/commit/af5d6b8c4166c7461f1774991e2896b11d503585) fix: show SELinux labels on pseudo-fs\n* [`f46922fa9a`](https://github.com/siderolabs/talos/commit/f46922fa9a815a2e9002c31dcc2793bf6dd93952) chore: fix dockerfile warnings\n* [`a13f82c594`](https://github.com/siderolabs/talos/commit/a13f82c59456574238a75959ff395746c93f1cfa) feat: udev: label device nodes\n* [`e899fb37fd`](https://github.com/siderolabs/talos/commit/e899fb37fde7ec2b39d4b0fa77c7a6b1ac9d9f16) feat: label created files in /etc\n* [`5f68c17eda`](https://github.com/siderolabs/talos/commit/5f68c17edab70451ec775e292222d9c634f4e863) feat: implement image cache configuration\n* [`0ffb2187a3`](https://github.com/siderolabs/talos/commit/0ffb2187a3e56744a6b67698882acf8281c147dd) feat: registry proxy\n* [`77cf84fb57`](https://github.com/siderolabs/talos/commit/77cf84fb572213e59880a05edcc1b1b365987ac4) feat: support generating iso with imagecache\n* [`5de6275b8f`](https://github.com/siderolabs/talos/commit/5de6275b8f883f6c3e7a17c04b427c0ff8b9e3f5) chore: image cache generator improvements\n* [`1a8cc5f8b2`](https://github.com/siderolabs/talos/commit/1a8cc5f8b277faec7cf00a3acc8e91a31f99ce85) feat: add SELinux labels to volumes\n* [`61b9129e0c`](https://github.com/siderolabs/talos/commit/61b9129e0c29b2402235065f27888459e6054e7a) fix: add directory entries and filemode to tarball\n* [`4caeae21e5`](https://github.com/siderolabs/talos/commit/4caeae21e548039a6a03471d35405788515a8751) refactor: optimize flags and SetLabel\n* [`6074a870ad`](https://github.com/siderolabs/talos/commit/6074a870ad7c63775a39c84b72f79699976a4a1f) feat: add e2fsprogs to talos rootfs\n* [`7ffcf5b932`](https://github.com/siderolabs/talos/commit/7ffcf5b932cc4064e5680efb20bf6fe6e7179cd4) docs: update getting started\n* [`c4c1a0d7c7`](https://github.com/siderolabs/talos/commit/c4c1a0d7c73d13e78bef935612cfdd593749a783) fix: make vmware platform common code build on all arches\n* [`cc768037f8`](https://github.com/siderolabs/talos/commit/cc768037f8d4bb022e98ddd4762f483ffd2a7a7f) feat: implement block device wipe\n* [`6fb518ae57`](https://github.com/siderolabs/talos/commit/6fb518ae57a7cea0cf0959309167805c6f2582a5) fix: don't activate LVM volumes in agent mode\n* [`0e3ed30723`](https://github.com/siderolabs/talos/commit/0e3ed307232eff54a42236489433eb8b6757cb6d) fix: no longer leak `Close` reader\n* [`4dc58cfdf3`](https://github.com/siderolabs/talos/commit/4dc58cfdf3ef99c67d6d1885216154d21294da74) chore: small fixes\n* [`f400ae911b`](https://github.com/siderolabs/talos/commit/f400ae911b49bd87b2c085ecc794ba44f0be0118) fix: small fixes for image cache generation\n* [`93754b7de6`](https://github.com/siderolabs/talos/commit/93754b7de6cec285e8e48d330be3c938dcd3e9c4) fix: config and platform manifest generation\n* [`95b2fc946e`](https://github.com/siderolabs/talos/commit/95b2fc946ec1d8166738d7bb2573e5d20d336afe) feat: image cache gen\n* [`e4c6186c63`](https://github.com/siderolabs/talos/commit/e4c6186c63ea8faabf2feb82a997a7dbdd35d966) chore: remove i915/amdgpu drivers\n* [`744ad12a6e`](https://github.com/siderolabs/talos/commit/744ad12a6e59c57b88869c055d598244f25e2e38) docs: update replicated-local-storage-with-openebs.md\n* [`fd713e4514`](https://github.com/siderolabs/talos/commit/fd713e45140f08b69bf0c08a28ca734685cb7672) feat: add permanent hardware addr to device selectors\n* [`d55a96e8cb`](https://github.com/siderolabs/talos/commit/d55a96e8cbbc8d013b6258da304d5c63590e2679) refactor: remove SELinux client_u and client_r\n* [`3a5b55fd22`](https://github.com/siderolabs/talos/commit/3a5b55fd2215f1b3b88868766f4220fcd1bdf1b5) fix: allow CEL expressions config merge\n* [`f1b15f580e`](https://github.com/siderolabs/talos/commit/f1b15f580eed5be808b6f657570540ae1906488a) chore: remove replace for safchain/ethtool\n* [`f9697a9a07`](https://github.com/siderolabs/talos/commit/f9697a9a07316226e13aa0d9a659f67fedaf7f47) fix: register controlplane node with NoSchedule taint\n* [`30f8b5a9f7`](https://github.com/siderolabs/talos/commit/30f8b5a9f76441d933341b91d753ae141a9f4d10) fix: registry mirror fallback handling\n* [`0f41e77434`](https://github.com/siderolabs/talos/commit/0f41e77434d6080270a3a18a8af0387791e8f282) feat: allow for onlink directive (nocloud)\n* [`e26d0043e0`](https://github.com/siderolabs/talos/commit/e26d0043e022eccf5ea9c9d9b4a57e4bff1f80cc) chore: code cleanup\n* [`43fe3807a8`](https://github.com/siderolabs/talos/commit/43fe3807a807a58ecf264f1628c5919f86d369b4) feat: implement tracking of blockdevice secondaries\n* [`8a7476c3ae`](https://github.com/siderolabs/talos/commit/8a7476c3ae1fdf5d4314d8915da72bc2cce19e38) fix: install on non-empty disk\n* [`8b4253d185`](https://github.com/siderolabs/talos/commit/8b4253d18544318e55f4886782a41b0e74155101) feat: update etcd to v3.5.17\n* [`5a0fd5b882`](https://github.com/siderolabs/talos/commit/5a0fd5b8829657f487db594d90c5b31841c78a66) refactor: move early initialization functions to pre-initialize phase\n* [`9916e2cd8a`](https://github.com/siderolabs/talos/commit/9916e2cd8a32706a32572f408dc313bbfa159539) chore: update pkgs/tools/extras for Go 1.23.3\n* [`20bbf02355`](https://github.com/siderolabs/talos/commit/20bbf02355c1ab12084ba36b3d1bea151029c2d6) docs: update vultr documentation\n* [`aea98940b7`](https://github.com/siderolabs/talos/commit/aea98940b7047c9e7f343efbbb8315c1bc6226d2) fix: arch linux search paths and names for QEMU provisioner\n* [`682718d4c9`](https://github.com/siderolabs/talos/commit/682718d4c99ff0bbae7be8b82eb6548e9b939f41) fix: use imager incoming version for extension validation\n* [`9a02ecc49f`](https://github.com/siderolabs/talos/commit/9a02ecc49fa801d7282bba4733698b8d7d6c221e) feat: rewrite install disk selector to use CEL expressions\n* [`eba35f4413`](https://github.com/siderolabs/talos/commit/eba35f4413c732d351d82d5b646fc3053e6239e3) docs: add note about PSP in Rook-Ceph guide\n* [`38b80fb1da`](https://github.com/siderolabs/talos/commit/38b80fb1dab586a9f14473d03415b793c2dfcda0) docs: add missing `--talosconfig` parameter to end of Hetzner guide\n* [`a07f66c918`](https://github.com/siderolabs/talos/commit/a07f66c9187b7a99211d3f9af286844511d66954) docs: gcp: fix controlplane nodes tags\n* [`4fe6dc8a0a`](https://github.com/siderolabs/talos/commit/4fe6dc8a0a86e0096797b3ce433a627fb973c962) chore: clean dns code\n* [`0290a38818`](https://github.com/siderolabs/talos/commit/0290a38818d5d1dd3327457fe5da3c2ba0328ce3) release(v1.9.0-alpha.2): prepare release\n* [`a309f6aa57`](https://github.com/siderolabs/talos/commit/a309f6aa57f4d99bbf17d0fef2fab4602e12b067) chore: fix nil pointer dereference in AWS uploader\n* [`333737f176`](https://github.com/siderolabs/talos/commit/333737f176f918ca3dd4217ddfed87c4da86bb9b) test: fix unpriviliged process runner test\n* [`2001167058`](https://github.com/siderolabs/talos/commit/200116705885b1f9935b719de71d661c695eae99) chore(ci): save support zip always after tests\n* [`6a42c3b8ed`](https://github.com/siderolabs/talos/commit/6a42c3b8ed58b6363a62710709f20266ca190b36) release(v1.9.0-alpha.1): prepare release\n* [`fb72e4b7b7`](https://github.com/siderolabs/talos/commit/fb72e4b7b74979acf743d20c7c099bc5513836e0) fix(ci): skip test if `UserNamespacesSupport` feature gate is not set\n* [`11380f933d`](https://github.com/siderolabs/talos/commit/11380f933ddd3fe42dc01d5ed09ceff0d62b417d) feat: display current CPU frequency on dashboard\n* [`fbce267aee`](https://github.com/siderolabs/talos/commit/fbce267aee98e3b4b6acace156aa22d75ad01d3d) feat: check bridged interfaces should not have addresses\n* [`942962bf00`](https://github.com/siderolabs/talos/commit/942962bf005a7036e04f4e572f3434f476cb567c) docs: add docs on usernamespace support in k8s\n* [`0406a05a98`](https://github.com/siderolabs/talos/commit/0406a05a986fabc3834c5a0de48362826268edbe) chore: update pkgs to ones built with gcc 14.2\n* [`2e127627dc`](https://github.com/siderolabs/talos/commit/2e127627dce7251d5848718036780c91384c4396) docs: add apparmor enablement release notes\n* [`aa9311f3d8`](https://github.com/siderolabs/talos/commit/aa9311f3d840c7b5a69a1eb6ab4cb3b1a7bff135) fix: install disk matcher error\n* [`1800f81044`](https://github.com/siderolabs/talos/commit/1800f8104486f01e8a3437432e508893f02f809c) fix: selinux handling and apparmor tests\n* [`313bffadfb`](https://github.com/siderolabs/talos/commit/313bffadfb66b053f51046300764e94db088b18a) feat: update Kubernetes to v1.32.0-beta.0\n* [`bbfa144510`](https://github.com/siderolabs/talos/commit/bbfa144510063fdcdebbc017b4fb382ac839370c) feat: update containerd to v2.0.0\n* [`8e02b9fcbf`](https://github.com/siderolabs/talos/commit/8e02b9fcbfba421abd13ffe4fc8ea3892d4673eb) docs: update manual k8s upgrade docs\n* [`474949dc77`](https://github.com/siderolabs/talos/commit/474949dc77363123f0e8cf2c918ecacb82b4dbdd) feat: add dm-cache dm-cache-smq kernel modules\n* [`5112547d6b`](https://github.com/siderolabs/talos/commit/5112547d6b12b4ff40e7863f363cf519efb8c76c) chore: generate support zip for crashdump\n* [`a867f85e4c`](https://github.com/siderolabs/talos/commit/a867f85e4cb662a17b0738f1f0de4f1485ad925a) feat: label system socket and runtime files\n* [`398f714cff`](https://github.com/siderolabs/talos/commit/398f714cff04c524394933da17cbc21ad239cd42) feat: update Linux 6.6.59, runc 1.2.1\n* [`05c620957c`](https://github.com/siderolabs/talos/commit/05c620957ca741451da395036e8eca59e631fe8d) feat: allow extra mounts for docker-based `talosctl cluster create`\n* [`cedabeddf7`](https://github.com/siderolabs/talos/commit/cedabeddf7d191f39525a61e65164f280b6807f8) chore: cleanup code\n* [`61d363e1d0`](https://github.com/siderolabs/talos/commit/61d363e1d093047886638d5bc5b9f2181c8bd894) chore: update go-auditlib\n* [`960a040491`](https://github.com/siderolabs/talos/commit/960a040491de5c95b104b4a39ea519095eb47931) feat: start enabling SELinux\n* [`7f3aaa21cd`](https://github.com/siderolabs/talos/commit/7f3aaa21cd8d969e26721235a4191ba3bdbc1f8f) fix: update permissions for logging directories in /var\n* [`0e6c983b84`](https://github.com/siderolabs/talos/commit/0e6c983b847f679a074c1794fbe77d21a5994233) fix: mount /sys/kernel/security conditionally\n* [`74b0e8c371`](https://github.com/siderolabs/talos/commit/74b0e8c3713a01f83758556672583880ce5c684a) fix: make route normalization keep family\n* [`0a3761c22f`](https://github.com/siderolabs/talos/commit/0a3761c22f98783c6696f143611d600287a471a3) fix: talosctl windows arm64\n* [`4b10c5328b`](https://github.com/siderolabs/talos/commit/4b10c5328b861b4bcdcec3ca21bd55b91e969b44) chore: add Windows ARM64 build for talosctl\n* [`9abf16108e`](https://github.com/siderolabs/talos/commit/9abf16108ede75984845297d03673d56cb561c2f) feat: add auditd service\n* [`d464ca869f`](https://github.com/siderolabs/talos/commit/d464ca869f8949ffbb990c6fb02fbbcbe0abcbe1) chore: drop runc memfd bind added in #9069\n* [`b54d26c2c3`](https://github.com/siderolabs/talos/commit/b54d26c2c3f3a52c6d1ec3fddb7a373175815de3) fix: mount pseudo sub-mountpoints in init\n* [`7aeb15f730`](https://github.com/siderolabs/talos/commit/7aeb15f73094a23aea1d6b263ca2eca061c8a257) chore: disable coredns cache for cluster domain\n* [`d8b652150c`](https://github.com/siderolabs/talos/commit/d8b652150cec408f2bf3307565b9db691b21bfe9) docs: add warning about NVMe bus path bug\n* [`3e16ab135e`](https://github.com/siderolabs/talos/commit/3e16ab135e2be8c9b652d67f9e7eadbc3691c5ca) feat: update Kubernetes to v1.32.0-alpha.3\n* [`0b8b356777`](https://github.com/siderolabs/talos/commit/0b8b3567771fbe796926dc9a6e904e7102535170) feat: add BridgePort property to network machine configuration\n* [`b379506259`](https://github.com/siderolabs/talos/commit/b3795062596ef45dd309f1ca56aab31d2a1a0efc) fix: use more correct condition to skip generating hosts files\n* [`62ec7ec336`](https://github.com/siderolabs/talos/commit/62ec7ec3367233823c09befddc5ad312aa607822) refactor: replace the old v1 mount package with new one\n* [`0ece13c623`](https://github.com/siderolabs/talos/commit/0ece13c6236c7eda474d3734fcc4c4060299ac43) docs: update network-config.md (cont)\n* [`93827f0485`](https://github.com/siderolabs/talos/commit/93827f0485a92b46da83b80a2a55f2569f70fe57) docs: update network-config.md\n* [`423b1e5fb2`](https://github.com/siderolabs/talos/commit/423b1e5fb22d9e785a3832741d796120b84a5e38) fix: do not trim 0 from process SELinux label\n* [`2136358d65`](https://github.com/siderolabs/talos/commit/2136358d65ddf6ad040ed62c835b335f99a59399) feat: introduce metal agent mode\n* [`0e15955fcc`](https://github.com/siderolabs/talos/commit/0e15955fcc5d464c5f0ffd1a44eebf4bf32f4844) chore: small refactoring\n* [`66012a7f26`](https://github.com/siderolabs/talos/commit/66012a7f269010c5ed412d139b14c470063f2429) feat: remove wrapperd and launch processes directly\n* [`3a0a17ae66`](https://github.com/siderolabs/talos/commit/3a0a17ae66dab5c983571fab0f3eac3f87fbc17c) fix: prevent panic in nocloud platform code\n* [`dc0c6acbd7`](https://github.com/siderolabs/talos/commit/dc0c6acbd765b6e7838d6af4f1903242d5073782) refactor: remove unmaintained github.com/vishvananda/netlink\n* [`78353f7918`](https://github.com/siderolabs/talos/commit/78353f79188e81d064c354f6ef3fe3b2e023c644) feat: add parsing of vlanNNNN:ethX style VLAN cmdline args\n* [`9db7a36bfc`](https://github.com/siderolabs/talos/commit/9db7a36bfc45c9c15fd661fb2a6319dcf4fef210) fix: generation of SecureBoot iso\n* [`c755b6d7e4`](https://github.com/siderolabs/talos/commit/c755b6d7e4600fdfb32be50422b7efb0fdabef63) fix: update the CRI sandbox image reference\n* [`cec290b354`](https://github.com/siderolabs/talos/commit/cec290b354773b2b0f2c2ae9d57f36e06fe2654d) feat: allow extensions to log to console\n* [`b7801df827`](https://github.com/siderolabs/talos/commit/b7801df827d8e1e9a2db7dac0a62c3802de4d73c) fix: wait for udevd to be running before activating LVM\n* [`d4cb478a50`](https://github.com/siderolabs/talos/commit/d4cb478a50ce41c3699b7846388e537ddf18a703) docs: improve field description for BridgeSTP, BridgeVLAN\n* [`7329824b24`](https://github.com/siderolabs/talos/commit/7329824b2411fef3b23fd90380033441048f6512) docs: add Mynewsdesk to ADOPTERS.md\n* [`a13cf76a34`](https://github.com/siderolabs/talos/commit/a13cf76a3415f458ff3235981c1be8202e1800bb) chore: simplify `DNSUpstreamController` and `DNSUpstream` resource\n* [`62d185473e`](https://github.com/siderolabs/talos/commit/62d185473e258c0c34eff5aed4c18d81d4b92a89) fix: talosctl process null character\n* [`77d7368eae`](https://github.com/siderolabs/talos/commit/77d7368eae2da6d2c9aa896afc8013007909a958) feat: update containerd to v2.0.0-rc.6\n* [`d39393879a`](https://github.com/siderolabs/talos/commit/d39393879a1f98ac3de7a96808301d1e07fd95f3) fix: rework the 'metal-iso' config acquisition\n* [`1993afca9f`](https://github.com/siderolabs/talos/commit/1993afca9fff7e889b497ec3241cfdca42294f18) chore: create /usr/etc in a different step\n* [`8680351c13`](https://github.com/siderolabs/talos/commit/8680351c131d29a76682569742dbd44c8ffe47d3) chore: move system extensions' udev rules\n* [`3067f64c84`](https://github.com/siderolabs/talos/commit/3067f64c8435ef2d5453100a1584dc3c6915ba0b) feat: update Flannel to v0.26.0\n* [`8658d6865f`](https://github.com/siderolabs/talos/commit/8658d6865fa0bcbfcebe483b7332d3b56e239979) docs: typo in deploying cilium\n* [`49bbadc4bf`](https://github.com/siderolabs/talos/commit/49bbadc4bf1e79e48c057d473ae21426b273c588) docs: add documentation on performance tuning\n* [`534b0ce183`](https://github.com/siderolabs/talos/commit/534b0ce1833462b22f3761258e0e95813a355fb2) feat: update runc to 1.2.0 final\n* [`2172535237`](https://github.com/siderolabs/talos/commit/21725352373da7835d95f8f934847dab404782f8) docs: fix image factory links\n* [`375e3da73f`](https://github.com/siderolabs/talos/commit/375e3da73fcb02c7caea2576289fefdc395a1ed2) feat: update Kubernetes to 1.32.0-alpha.2\n* [`9e6f64df04`](https://github.com/siderolabs/talos/commit/9e6f64df047527ecb42df5fdf5fd2f9767d21437) fix: improve error messages for invalid bridge/bond configuration\n* [`7c8c72c2b2`](https://github.com/siderolabs/talos/commit/7c8c72c2b2a4edb412e097a9e013ab21727339cf) fix: correct error message for invalid ip=\n* [`ead46997c9`](https://github.com/siderolabs/talos/commit/ead46997c918ab1139ca12e87beefbbda29614e1) chore: rename tpm2.PCRExtent -> tpm2.PCRExtend\n* [`867c4b8125`](https://github.com/siderolabs/talos/commit/867c4b8125ee738f9a82e5e87809eb95bdd2f778) docs: fix typo in prodnotes.md\n* [`1b22df48a4`](https://github.com/siderolabs/talos/commit/1b22df48a41578d19fb512bd8111a481b64011e2) chore: support debug shell for advanced development\n* [`c14b446229`](https://github.com/siderolabs/talos/commit/c14b4462292bd7e6088fce35d6880a9b2b56335c) feat: update Kubernetes to v1.32.0-alpha.1\n* [`29780d35a0`](https://github.com/siderolabs/talos/commit/29780d35a052134d50576f6506c2728489a30506) test: add an integration test for verifying process parameters\n* [`3d342af447`](https://github.com/siderolabs/talos/commit/3d342af4479ed12e2af10021ec4e7ab9c2af6d75) fix: update incorrect alias for PCIDevice resource\n* [`f7d35a5e0b`](https://github.com/siderolabs/talos/commit/f7d35a5e0b4e3a04a639d663e5a580e22fea76db) release(v1.9.0-alpha.0): prepare release\n* [`e0434d77d7`](https://github.com/siderolabs/talos/commit/e0434d77d754f8834ba903f4c09b08634cfd3934) feat: update dependencies\n* [`5c5a248861`](https://github.com/siderolabs/talos/commit/5c5a248861c8e5848f9a23cd0cd7b3b749f21e4b) feat: add Talos 1.9 compatibility guarantees\n* [`bc4c21f41a`](https://github.com/siderolabs/talos/commit/bc4c21f41a0066ba6cefb5b753c52d76a6b0f629) test: add json logs test environment\n* [`71faa32942`](https://github.com/siderolabs/talos/commit/71faa3294246947f6bd212979ceb31e793ae0604) docs: nvidia proprietary/oss hardware requirement\n* [`59a78da42c`](https://github.com/siderolabs/talos/commit/59a78da42cdea8fbccc35d0851f9b0eef928261b) chore: add proto-codec/codec\n* [`7ff1cedfe3`](https://github.com/siderolabs/talos/commit/7ff1cedfe3eee51505c30439eec4a2df9b452b2e) chore: update siderolabs/crypto module and return proper ALPN\n* [`ccbd5aed39`](https://github.com/siderolabs/talos/commit/ccbd5aed39b360664d1f80c8b146050e9df9ff7b) feat: optionally decode hcloud userdata as base64\n* [`34f652ce82`](https://github.com/siderolabs/talos/commit/34f652ce822fcb70a292289fe6ba5d1bd7a34f97) feat: add well-known app.kubernetes.io labels to control-plane pods\n* [`fc89dc2164`](https://github.com/siderolabs/talos/commit/fc89dc21643a923cb7d0d3944405521bf849631b) fix: support `extra-disks` when using iso\n* [`f2bff814de`](https://github.com/siderolabs/talos/commit/f2bff814de0b237fbed419234b935dc9f9637554) chore: add arm64 target for integration-test\n* [`5853bb0ea4`](https://github.com/siderolabs/talos/commit/5853bb0ea4d6a65635086bdef617d6d0800cabd0) fix: json logging panic\n* [`a859cff364`](https://github.com/siderolabs/talos/commit/a859cff364aa4dc9b4b880417b821f7ecf5602ac) chore: use virtio driver for disks in arm64\n* [`db248de88d`](https://github.com/siderolabs/talos/commit/db248de88dec2467e4340f699cde98217979ba4b) chore(ci): add config for lldpd extension\n* [`9f0de9f43d`](https://github.com/siderolabs/talos/commit/9f0de9f43dc4467f0bdeda117b4946ae12db50ab) test: update provision upgrade tests for Talos 1.9\n* [`39fe285e69`](https://github.com/siderolabs/talos/commit/39fe285e69691059f91d8c7c5506e156356263d9) fix: skip ram disks\n* [`a9bff3a1d0`](https://github.com/siderolabs/talos/commit/a9bff3a1d084c32a654555e71e2592e60edbdcb6) test: skip no error test in Cilium\n* [`4d902021bb`](https://github.com/siderolabs/talos/commit/4d902021bb3c55bc212cbb3e2443b6552400622f) fix: do not use pflag csv comma reader for config-patch\n* [`5371788ce1`](https://github.com/siderolabs/talos/commit/5371788ce169a0381e08f0d902ac81f3f89ba5bd) fix: typo in documentation\n* [`8a228ba6bc`](https://github.com/siderolabs/talos/commit/8a228ba6bc702f21fca06dc2ecb3e8e846839cd3) docs: add egress documentation\n* [`182325cb07`](https://github.com/siderolabs/talos/commit/182325cb0791da1d4dcd3914a643c44232502524) test: skip lvm test if not enough user disks available\n* [`519a48302e`](https://github.com/siderolabs/talos/commit/519a48302e771fd9b331913166d55c50fff4961a) fix: wipe system partitions correctly via kernel args\n* [`0a2b4556c5`](https://github.com/siderolabs/talos/commit/0a2b4556c55eda27536ee563f60bcf5d69379479) fix: volume encryption with failing keyslots\n* [`6affbd3182`](https://github.com/siderolabs/talos/commit/6affbd3182ebe0209ed5433c534062b7ad672b6a) fix: update grpc-go the latest patch release\n* [`77a4a4adc7`](https://github.com/siderolabs/talos/commit/77a4a4adc7232b4382f2a530f4056a1fff6c50b4) fix: scaleway metadata\n* [`7acadc0c8f`](https://github.com/siderolabs/talos/commit/7acadc0c8fa969e4de7f0d4f68b0fd0cd833b489) fix: do not stop udevd before unmounting volumes\n* [`6a081055b0`](https://github.com/siderolabs/talos/commit/6a081055b0dd4e3ce5c40392c8415a0a55b2591c) feat: update Flannel to v0.25.7\n* [`2362f6d3ee`](https://github.com/siderolabs/talos/commit/2362f6d3ee51a0a8b541a872d39ac82892502e17) fix: improve container detection\n* [`b67bc73fd3`](https://github.com/siderolabs/talos/commit/b67bc73fd30a8e07f26c47a746ca53f2af41d366) fix: fix mdadm system extension\n* [`f08669c7a9`](https://github.com/siderolabs/talos/commit/f08669c7a9583a559dc53f233798305bbab07b8a) feat: bring in lpfc kernel module driver\n* [`6a014374be`](https://github.com/siderolabs/talos/commit/6a014374be26f0caf8faa90a34f2476e0e77a46a) feat: enable QEDF driver\n* [`f711907e03`](https://github.com/siderolabs/talos/commit/f711907e038cea20f6b831ea5ad8c3b18638c1b4) fix: make /var/run empty on reboots\n* [`7d02eb60f4`](https://github.com/siderolabs/talos/commit/7d02eb60f47652f4b72f170b28a8b964729af013) docs: fix typo in CloudStack docs\n* [`74861573a7`](https://github.com/siderolabs/talos/commit/74861573a793f9e143d7d2638990f37ec639aa88) fix: multiple fixes for LVM activation\n* [`74c12c20e0`](https://github.com/siderolabs/talos/commit/74c12c20e02e4ec29b2b374cebc996ddf8fa90c7) feat: replace eudev with systemd-udevd\n* [`0a4df4ef84`](https://github.com/siderolabs/talos/commit/0a4df4ef84467014d5be4b4ec57de0e778cfb21e) docs: fix nvidia CRI config example\n* [`afc1e1a46a`](https://github.com/siderolabs/talos/commit/afc1e1a46a559aac3aa5f4a2708ba8d2c9228929) docs: fix typo in extraMounts directory\n* [`a341bdb064`](https://github.com/siderolabs/talos/commit/a341bdb0640294a07939670919c56cbfa7a861c4) fix: prevent file descriptors leaks to child processes\n* [`dec653bfe1`](https://github.com/siderolabs/talos/commit/dec653bfe1feb84ea2ed1a779b1bfc783dc61160) chore: better lvm2 tests\n* [`908fd8789c`](https://github.com/siderolabs/talos/commit/908fd8789cc1b22e556a7ffe307409931976ba08) feat: support cgroup deep analysis in `talosctl`\n* [`aa846cc186`](https://github.com/siderolabs/talos/commit/aa846cc186c1c6125f8f39ea084fa2023512656f) feat: add support for CI Network config in nocloud\n* [`10f2539f23`](https://github.com/siderolabs/talos/commit/10f2539f237aeb3af2caeb3c349c062f203219b6) chore: disable cloud-images cron workflow\n* [`b07a8b36b2`](https://github.com/siderolabs/talos/commit/b07a8b36b24d57337323e72d6032304c4cade927) chore: ignore more plugins for system containerd\n* [`392c4798f0`](https://github.com/siderolabs/talos/commit/392c4798f0bff7cb4518609deae7c90581f013f5) feat: prepare for Talos 1.9\n* [`ea7bf9fb43`](https://github.com/siderolabs/talos/commit/ea7bf9fb43dff8cf8ec4dfd4f629e8f826bc2ded) docs: update storage.md\n* [`4ab8dee69a`](https://github.com/siderolabs/talos/commit/4ab8dee69ac07c811cbe121ca9e2d9bd01148863) fix: build talosctl without `tcell_minimal`\n* [`2fa019bd97`](https://github.com/siderolabs/talos/commit/2fa019bd9751ad96085ade52628023adf17658d3) docs: enable 'edit on GitHub' link\n* [`d2ccbc2b15`](https://github.com/siderolabs/talos/commit/d2ccbc2b1512b6323d48a764c4af534d49b4bd27) docs: update hetzner documentation for CCM\n* [`d498f647cd`](https://github.com/siderolabs/talos/commit/d498f647cd9dfcd575f51005c9b78c2c1c7b51ca) docs: fix Kernel Self Protection Project (KSPP) references\n* [`0ec75463ee`](https://github.com/siderolabs/talos/commit/0ec75463eecebfb543a64b0c859ba0b2477e406f) docs: make Talos 1.8 current release\n* [`9b77698cf2`](https://github.com/siderolabs/talos/commit/9b77698cf2ff64c6f6d198d05c2012ab7fa858be) fix: update blockdevice library to v2.0.2\n* [`e46227ab95`](https://github.com/siderolabs/talos/commit/e46227ab95a6d06132e82315f55b5ced533ddabb) docs: fix kubespan name inconsistency\n* [`6b15ca19cd`](https://github.com/siderolabs/talos/commit/6b15ca19cd1291b8a245d72d5153827945cad037) fix: audit and fix cgroup reservations\n* [`32b5d01ed3`](https://github.com/siderolabs/talos/commit/32b5d01ed3396e8f54a245cc6d9818119aec8291) chore: bump lvm2\n* [`6484581eb8`](https://github.com/siderolabs/talos/commit/6484581eb888996a8dc829915439fb63606dd794) feat: allow /sbin/ldconfig in extensions\n* [`9fa08e8437`](https://github.com/siderolabs/talos/commit/9fa08e843728dbd85ed7e0035f59cdd6232de9a9) chore: refactor tests\n* [`d8ab4981b6`](https://github.com/siderolabs/talos/commit/d8ab4981b626ff41fbcdb526a032a5584519e3df) feat: support lvm auto activation\n* [`8166a58b36`](https://github.com/siderolabs/talos/commit/8166a58b364f760212b2a610ce0d764b8b4c5c46) fix: filter out non-printable characters in process line\n* [`806b6aaf52`](https://github.com/siderolabs/talos/commit/806b6aaf52f20ed0f32107b3d0372d6e3ff974be) docs: add SECURITY.md\n* [`7bd26df308`](https://github.com/siderolabs/talos/commit/7bd26df30803307e4eece3e382aafebc55e7b260) docs: document `/dev/net/tun` compatibility\n* [`18daedb511`](https://github.com/siderolabs/talos/commit/18daedb511e769717ba56eb05cccab72118a4813) fix: strategic merge patch delete for map keys\n* [`f3370529ac`](https://github.com/siderolabs/talos/commit/f3370529ac042865a4b2d793465916fcae2d4b33) docs: correct typo\n* [`8d6884a8e2`](https://github.com/siderolabs/talos/commit/8d6884a8e28e1bfa29f9a479e0f7179819cf70cd) test: add a test for inline machine config trusted roots\n* [`d4a6d017db`](https://github.com/siderolabs/talos/commit/d4a6d017dbb91e22c60787cdf64b242057b1ebef) fix: ignore invalid NTP responses\n* [`869f8379f2`](https://github.com/siderolabs/talos/commit/869f8379f2317175901e8cb3deec4b800e7ab603) feat: update default Kubernetes version to 1.31.1\n* [`780a1f198a`](https://github.com/siderolabs/talos/commit/780a1f198a5eedd33a27060bdf116bd3a3b26426) fix: update CoreDNS health check\n* [`79cd031588`](https://github.com/siderolabs/talos/commit/79cd031588a0710b865414f919742ee3ffb998ed) chore: account for resource sorting in dns upstream resource\n* [`e17fafaca2`](https://github.com/siderolabs/talos/commit/e17fafaca2a16990bc424b54120c49ddbaf8cee1) chore: drop `activateLogicalVolumes` sequencer step\n* [`a294b366f2`](https://github.com/siderolabs/talos/commit/a294b366f24c6580d304c6c8ad34f481079dc795) fix: parse SideroLink API endpoint correctly\n* [`a9269ac7b1`](https://github.com/siderolabs/talos/commit/a9269ac7b1217aa2d247c0215c5f2755af468b44) fix: remove extra logging on ethtool ioctl failures\n* [`5c6277d171`](https://github.com/siderolabs/talos/commit/5c6277d171eea58878ce4fcb4d2fdb7154333ae7) feat: update etcd to 3.5.16\n* [`c1ed2984b8`](https://github.com/siderolabs/talos/commit/c1ed2984b85dca791a5081c5da26bba75e3cd579) docs: add what's new for Talos 1.8\n</p>\n</details>\n\n### Changes since v1.9.0-alpha.2\n<details><summary>44 commits</summary>\n<p>\n\n* [`af5d6b8c4`](https://github.com/siderolabs/talos/commit/af5d6b8c4166c7461f1774991e2896b11d503585) fix: show SELinux labels on pseudo-fs\n* [`f46922fa9`](https://github.com/siderolabs/talos/commit/f46922fa9a815a2e9002c31dcc2793bf6dd93952) chore: fix dockerfile warnings\n* [`a13f82c59`](https://github.com/siderolabs/talos/commit/a13f82c59456574238a75959ff395746c93f1cfa) feat: udev: label device nodes\n* [`e899fb37f`](https://github.com/siderolabs/talos/commit/e899fb37fde7ec2b39d4b0fa77c7a6b1ac9d9f16) feat: label created files in /etc\n* [`5f68c17ed`](https://github.com/siderolabs/talos/commit/5f68c17edab70451ec775e292222d9c634f4e863) feat: implement image cache configuration\n* [`0ffb2187a`](https://github.com/siderolabs/talos/commit/0ffb2187a3e56744a6b67698882acf8281c147dd) feat: registry proxy\n* [`77cf84fb5`](https://github.com/siderolabs/talos/commit/77cf84fb572213e59880a05edcc1b1b365987ac4) feat: support generating iso with imagecache\n* [`5de6275b8`](https://github.com/siderolabs/talos/commit/5de6275b8f883f6c3e7a17c04b427c0ff8b9e3f5) chore: image cache generator improvements\n* [`1a8cc5f8b`](https://github.com/siderolabs/talos/commit/1a8cc5f8b277faec7cf00a3acc8e91a31f99ce85) feat: add SELinux labels to volumes\n* [`61b9129e0`](https://github.com/siderolabs/talos/commit/61b9129e0c29b2402235065f27888459e6054e7a) fix: add directory entries and filemode to tarball\n* [`4caeae21e`](https://github.com/siderolabs/talos/commit/4caeae21e548039a6a03471d35405788515a8751) refactor: optimize flags and SetLabel\n* [`6074a870a`](https://github.com/siderolabs/talos/commit/6074a870ad7c63775a39c84b72f79699976a4a1f) feat: add e2fsprogs to talos rootfs\n* [`7ffcf5b93`](https://github.com/siderolabs/talos/commit/7ffcf5b932cc4064e5680efb20bf6fe6e7179cd4) docs: update getting started\n* [`c4c1a0d7c`](https://github.com/siderolabs/talos/commit/c4c1a0d7c73d13e78bef935612cfdd593749a783) fix: make vmware platform common code build on all arches\n* [`cc768037f`](https://github.com/siderolabs/talos/commit/cc768037f8d4bb022e98ddd4762f483ffd2a7a7f) feat: implement block device wipe\n* [`6fb518ae5`](https://github.com/siderolabs/talos/commit/6fb518ae57a7cea0cf0959309167805c6f2582a5) fix: don't activate LVM volumes in agent mode\n* [`0e3ed3072`](https://github.com/siderolabs/talos/commit/0e3ed307232eff54a42236489433eb8b6757cb6d) fix: no longer leak `Close` reader\n* [`4dc58cfdf`](https://github.com/siderolabs/talos/commit/4dc58cfdf3ef99c67d6d1885216154d21294da74) chore: small fixes\n* [`f400ae911`](https://github.com/siderolabs/talos/commit/f400ae911b49bd87b2c085ecc794ba44f0be0118) fix: small fixes for image cache generation\n* [`93754b7de`](https://github.com/siderolabs/talos/commit/93754b7de6cec285e8e48d330be3c938dcd3e9c4) fix: config and platform manifest generation\n* [`95b2fc946`](https://github.com/siderolabs/talos/commit/95b2fc946ec1d8166738d7bb2573e5d20d336afe) feat: image cache gen\n* [`e4c6186c6`](https://github.com/siderolabs/talos/commit/e4c6186c63ea8faabf2feb82a997a7dbdd35d966) chore: remove i915/amdgpu drivers\n* [`744ad12a6`](https://github.com/siderolabs/talos/commit/744ad12a6e59c57b88869c055d598244f25e2e38) docs: update replicated-local-storage-with-openebs.md\n* [`fd713e451`](https://github.com/siderolabs/talos/commit/fd713e45140f08b69bf0c08a28ca734685cb7672) feat: add permanent hardware addr to device selectors\n* [`d55a96e8c`](https://github.com/siderolabs/talos/commit/d55a96e8cbbc8d013b6258da304d5c63590e2679) refactor: remove SELinux client_u and client_r\n* [`3a5b55fd2`](https://github.com/siderolabs/talos/commit/3a5b55fd2215f1b3b88868766f4220fcd1bdf1b5) fix: allow CEL expressions config merge\n* [`f1b15f580`](https://github.com/siderolabs/talos/commit/f1b15f580eed5be808b6f657570540ae1906488a) chore: remove replace for safchain/ethtool\n* [`f9697a9a0`](https://github.com/siderolabs/talos/commit/f9697a9a07316226e13aa0d9a659f67fedaf7f47) fix: register controlplane node with NoSchedule taint\n* [`30f8b5a9f`](https://github.com/siderolabs/talos/commit/30f8b5a9f76441d933341b91d753ae141a9f4d10) fix: registry mirror fallback handling\n* [`0f41e7743`](https://github.com/siderolabs/talos/commit/0f41e77434d6080270a3a18a8af0387791e8f282) feat: allow for onlink directive (nocloud)\n* [`e26d0043e`](https://github.com/siderolabs/talos/commit/e26d0043e022eccf5ea9c9d9b4a57e4bff1f80cc) chore: code cleanup\n* [`43fe3807a`](https://github.com/siderolabs/talos/commit/43fe3807a807a58ecf264f1628c5919f86d369b4) feat: implement tracking of blockdevice secondaries\n* [`8a7476c3a`](https://github.com/siderolabs/talos/commit/8a7476c3ae1fdf5d4314d8915da72bc2cce19e38) fix: install on non-empty disk\n* [`8b4253d18`](https://github.com/siderolabs/talos/commit/8b4253d18544318e55f4886782a41b0e74155101) feat: update etcd to v3.5.17\n* [`5a0fd5b88`](https://github.com/siderolabs/talos/commit/5a0fd5b8829657f487db594d90c5b31841c78a66) refactor: move early initialization functions to pre-initialize phase\n* [`9916e2cd8`](https://github.com/siderolabs/talos/commit/9916e2cd8a32706a32572f408dc313bbfa159539) chore: update pkgs/tools/extras for Go 1.23.3\n* [`20bbf0235`](https://github.com/siderolabs/talos/commit/20bbf02355c1ab12084ba36b3d1bea151029c2d6) docs: update vultr documentation\n* [`aea98940b`](https://github.com/siderolabs/talos/commit/aea98940b7047c9e7f343efbbb8315c1bc6226d2) fix: arch linux search paths and names for QEMU provisioner\n* [`682718d4c`](https://github.com/siderolabs/talos/commit/682718d4c99ff0bbae7be8b82eb6548e9b939f41) fix: use imager incoming version for extension validation\n* [`9a02ecc49`](https://github.com/siderolabs/talos/commit/9a02ecc49fa801d7282bba4733698b8d7d6c221e) feat: rewrite install disk selector to use CEL expressions\n* [`eba35f441`](https://github.com/siderolabs/talos/commit/eba35f4413c732d351d82d5b646fc3053e6239e3) docs: add note about PSP in Rook-Ceph guide\n* [`38b80fb1d`](https://github.com/siderolabs/talos/commit/38b80fb1dab586a9f14473d03415b793c2dfcda0) docs: add missing `--talosconfig` parameter to end of Hetzner guide\n* [`a07f66c91`](https://github.com/siderolabs/talos/commit/a07f66c9187b7a99211d3f9af286844511d66954) docs: gcp: fix controlplane nodes tags\n* [`4fe6dc8a0`](https://github.com/siderolabs/talos/commit/4fe6dc8a0a86e0096797b3ce433a627fb973c962) chore: clean dns code\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`58b2f92`](https://github.com/siderolabs/crypto/commit/58b2f9291c7e763a7210cfa681f88a7fa2230bf3) chore: use HTTP/2 ALPN by default\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`005e92c`](https://github.com/siderolabs/discovery-api/commit/005e92cf4ad0059334bfd35285a97c85f12aa263) chore: rekres and regen\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b74fb90`](https://github.com/siderolabs/discovery-client/commit/b74fb9039fcfd8db9d6becf3044f9f41f387ea27) fix: allow custom TLS config for the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`78ba66b`](https://github.com/siderolabs/extras/commit/78ba66b040e3288c425c10055068784a19bec804) feat: update Go to 1.23.3\n* [`eab6e58`](https://github.com/siderolabs/extras/commit/eab6e58aa9bdf49789cd4d64d2e27f61023421ca) feat: update dependencies\n* [`1459d78`](https://github.com/siderolabs/extras/commit/1459d78cbeb297c023501a3eb785a27a5bdd4933) feat: update pkgs for 1.9\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`e847d2a`](https://github.com/siderolabs/gen/commit/e847d2ace9ede4a17283426dfbc8229121f2909b) chore: add more utilities to xiter\n* [`f3c5a2b`](https://github.com/siderolabs/gen/commit/f3c5a2b5aba74e4935d073a0135c4904ef3bbfef) chore: add `Empty` and `Empty2` iterators\n* [`c53b90b`](https://github.com/siderolabs/gen/commit/c53b90b4a418b8629d938af06900249ce5acd9e6) chore: add packages xiter/xstrings/xbytes\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`134c41b`](https://github.com/siderolabs/go-blockdevice/commit/134c41be6f4c498a149b8098fa8d862c5c47ca54) fix: fast wipe also last 1MB of the device\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`9a0f7b0`](https://github.com/siderolabs/go-circular/commit/9a0f7b02c80ad6c2d953b2d3dd388c56e89363ea) fix: multiple data race issues\n</p>\n</details>\n\n### Changes from siderolabs/go-cmd\n<details><summary>3 commits</summary>\n<p>\n\n* [`d735250`](https://github.com/siderolabs/go-cmd/commit/d73525092a1bb135da54d538e5d64c4dcc80259e) fix: return an error on process nonzero exit code\n* [`5662c7f`](https://github.com/siderolabs/go-cmd/commit/5662c7f8d5cf475c57b3a23b8d8546d960ebc60a) feat: add an equivalent of WaitWrapper for os.Process\n* [`71fced6`](https://github.com/siderolabs/go-cmd/commit/71fced673e013423bba83064767a90372dd6cf51) chore: rekres and move to GHA\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>4 commits</summary>\n<p>\n\n* [`0f62a7e`](https://github.com/siderolabs/go-kubernetes/commit/0f62a7e3c006d56601764088011d5dd20f70a7a5) feat: add one more deprecation/removal for v1.32\n* [`87d2e8e`](https://github.com/siderolabs/go-kubernetes/commit/87d2e8e664c3e3e64403bcfcfe2f8691f60c6481) feat: add one more deprecation for 1.32.0-beta.0\n* [`e56a7f6`](https://github.com/siderolabs/go-kubernetes/commit/e56a7f65808b90058df16a4133f19484beeedc31) fix: update deprecations based on Kubernetes 1.32.0-alpha.3\n* [`381f251`](https://github.com/siderolabs/go-kubernetes/commit/381f251662eaae9b48470ce00f504c2c64187612) feat: update for Kubernetes 1.32\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>2 commits</summary>\n<p>\n\n* [`de1c628`](https://github.com/siderolabs/grpc-proxy/commit/de1c6286b7d16d8485bf8bb55c8783c8773851a0) fix: copy data from big frame msg\n* [`ef47ec7`](https://github.com/siderolabs/grpc-proxy/commit/ef47ec77d2a9f0f42e713d456943dfe9ee86a629) chore: upgrade Codec implementations and usages to Codec2\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>46 commits</summary>\n<p>\n\n* [`a463a50`](https://github.com/siderolabs/pkgs/commit/a463a50df4b56dfa7a27ca5bd60db0a2937de736) feat: add e2fsprogs\n* [`bfd88f5`](https://github.com/siderolabs/pkgs/commit/bfd88f519a33da38d97e9cbce7dcca3e53ad4a41) chore: fix make kernel-menuconfig completely\n* [`cee356e`](https://github.com/siderolabs/pkgs/commit/cee356e919e271c63786f3964f3ffc8c733df871) chore: fix menuconfig build\n* [`a5530cf`](https://github.com/siderolabs/pkgs/commit/a5530cf13d299e2722015a512cd4134db575bfc7) feat: update Linux to 6.6.62, runc to 1.2.2\n* [`ac329c9`](https://github.com/siderolabs/pkgs/commit/ac329c9251db54f3add6f5a24eb8c24fdd041995) feat: enable CONFIG_INTEL_HFI_THERMAL + CONFIG_INTEL_TURBO_MAX_3\n* [`567a14a`](https://github.com/siderolabs/pkgs/commit/567a14adad773bd1ed44a4e965683cc88c0b96e6) fix: do not build unneeded utilities and man for SELinux libraries\n* [`b15a3d9`](https://github.com/siderolabs/pkgs/commit/b15a3d96113adbfe93bf004a9d870de4bfd00a7b) feat: bump dependencies\n* [`6bdba41`](https://github.com/siderolabs/pkgs/commit/6bdba415a78d399e90b3e5bc5294049bd24f5011) feat: update Linux to 6.6.60\n* [`4699763`](https://github.com/siderolabs/pkgs/commit/4699763c6d745620aecd0219fc78962e4fa0a01e) feat: update gcc to 14.2\n* [`9a98f73`](https://github.com/siderolabs/pkgs/commit/9a98f73de2c0353e9f8f194bd31c50eea1fb4d5b) feat: update containerd to v2.0.0\n* [`20e1e08`](https://github.com/siderolabs/pkgs/commit/20e1e0857a7d0cf05983998df3160fe0607d5075) feat: enable CONFIG_DM_CACHE\n* [`df45e16`](https://github.com/siderolabs/pkgs/commit/df45e1676828e49d77718e717b2e0e425122c62c) feat: update Linux to 6.6.59\n* [`2e733cc`](https://github.com/siderolabs/pkgs/commit/2e733cccfd225712eb7395cf04b6d8df0bf2b8d2) feat: bump dependencies\n* [`c92e123`](https://github.com/siderolabs/pkgs/commit/c92e123b40457f45e9fc0fe271804fa95c8d4f09) fix: enable nvme and 2.5gbit ethernet on nanopi-r5s\n* [`b160184`](https://github.com/siderolabs/pkgs/commit/b160184a479c85b8b19d2a874e5d6d52db9ed096) feat: update runc to v1.2.1\n* [`e9950d9`](https://github.com/siderolabs/pkgs/commit/e9950d9097fa002e79e2933344f68bb09ad6d4df) chore: drop syslinux\n* [`fc2e8dc`](https://github.com/siderolabs/pkgs/commit/fc2e8dc07ad096d0394f8deacb20d423ef102c2f) feat: update containerd to v2.0.0-rc.6\n* [`38304a6`](https://github.com/siderolabs/pkgs/commit/38304a60e3b32f0b3216ce8128df5f98d8be6812) feat: update Linux to 6.6.58\n* [`84b8df8`](https://github.com/siderolabs/pkgs/commit/84b8df8baf408ab22649b02910294154e0ad5f3b) chore: do not use /usr/etc/udev\n* [`c9282c8`](https://github.com/siderolabs/pkgs/commit/c9282c8dc6a535b69a953c0b4f43fd0780c5bb30) feat: update runc to 1.2.0\n* [`38ad08e`](https://github.com/siderolabs/pkgs/commit/38ad08ecb57d456b76f6d53a7d8a75c3b32f7d61) fix: default IOMMU mode to 'lazy'\n* [`be92da0`](https://github.com/siderolabs/pkgs/commit/be92da09f3196d96b1358efd6a7c667297d3ecfb) feat: update Linux to 6.6.57, update Linux firmware\n* [`0b67a13`](https://github.com/siderolabs/pkgs/commit/0b67a133b12c548ba6d28f2ea0c979cb10512812) feat: bump dependencies\n* [`dd5f928`](https://github.com/siderolabs/pkgs/commit/dd5f928266761215fc402085594493c9f9b329b4) feat: update Linux 6.6.56 and protect /proc/mem\n* [`b1bf972`](https://github.com/siderolabs/pkgs/commit/b1bf9725068029f34193b3abe1586a3d1f542b17) feat: enable CONFIG_XFRM_STATISTICS\n* [`c63beae`](https://github.com/siderolabs/pkgs/commit/c63beae426026c8ef1b3228b8d978ca5fcc9111b) feat: update Linux to 6.6.54\n* [`f474a55`](https://github.com/siderolabs/pkgs/commit/f474a55176dca7ab88b5a29f8d97ce6f31282abd) fix: libselinux: support running without /etc/selinux\n* [`ba0341e`](https://github.com/siderolabs/pkgs/commit/ba0341e39dafb3fe39b5efbc8a8e8d04df96a0e7) fix: systemd-udevd: search for config in /usr/etc\n* [`2b193f1`](https://github.com/siderolabs/pkgs/commit/2b193f14e035fa7d7785f26a591debe6ac357f00) feat: add lpfc kernel module\n* [`1adb946`](https://github.com/siderolabs/pkgs/commit/1adb946b1bb256b30b7bddd517a10d68ce209ada) feat: enable QEDF driver\n* [`dbbe3d0`](https://github.com/siderolabs/pkgs/commit/dbbe3d0116b24b9d1c2df19ae73b76714a37704e) feat: update containerd to v2.0.0-rc.5\n* [`f19590e`](https://github.com/siderolabs/pkgs/commit/f19590edb42a0247d5d509066b21ce35bfc42b93) feat: update Go to 1.23.2\n* [`e2a561f`](https://github.com/siderolabs/pkgs/commit/e2a561f576ea7dbc55ebb403d648daa1561c3101) fix: drop the LVM2 udev lvm rule\n* [`ae205aa`](https://github.com/siderolabs/pkgs/commit/ae205aac9d827783352071f9447f9f7cbf70da20) fix: force LVM to use `/run` as state directory\n* [`232a153`](https://github.com/siderolabs/pkgs/commit/232a15318a2d47f34b0772663fc3f417905b5406) feat: replace eudev with systemd-udevd\n* [`40fb82a`](https://github.com/siderolabs/pkgs/commit/40fb82a27a840f3442d6f52374007afb0a5a3770) feat: add libselinux, libsepol, pcre2 and libcap\n* [`6f40fbb`](https://github.com/siderolabs/pkgs/commit/6f40fbb5e00e449c954d54990085353d061a62c8) feat: update xfsprogs 6.10.1\n* [`a1709c7`](https://github.com/siderolabs/pkgs/commit/a1709c76db4ba70de526d7eec18c6b0637ebf7b0) feat: enable module unloading and memory hotplug (for NVIDIA UVM)\n* [`2c5785b`](https://github.com/siderolabs/pkgs/commit/2c5785b1639a22317a1f7775f0d1f4bd0b0a4b88) feat: enable transparent huge pages in madvise mode\n* [`ca2e8c8`](https://github.com/siderolabs/pkgs/commit/ca2e8c84b0881e7d1e359ceaf3b55c3b4bb384e7) fix: lvm2 modprobe path\n* [`6b334a6`](https://github.com/siderolabs/pkgs/commit/6b334a68fbd988ca69d05142a639aa3bcfd16721) feat: update Linux to 6.6.52\n* [`e90ae7e`](https://github.com/siderolabs/pkgs/commit/e90ae7ec316f1b9b4d15897f825d3c2c4cefde5e) feat: update Linux firmware to 20240909\n* [`79a4f92`](https://github.com/siderolabs/pkgs/commit/79a4f92c5aa4b8288a927351209542c274724475) feat: enable INET_DIAG\n* [`c9f7eb9`](https://github.com/siderolabs/pkgs/commit/c9f7eb94de2a8df5cfc41c6ea90596832894dc89) feat: update Linux to 6.6.51\n* [`126b6a4`](https://github.com/siderolabs/pkgs/commit/126b6a4f7632b2400139e306a0dbb0a545a0dda1) fix: add mpt3sas UBSAN patches\n* [`a09bf93`](https://github.com/siderolabs/pkgs/commit/a09bf93ce81bde59fcb06d662bc79effc9efaca6) chore: drop UBSAN patch\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>3 commits</summary>\n<p>\n\n* [`0d84c65`](https://github.com/siderolabs/proto-codec/commit/0d84c652784543012f43f8c8d4358c160b27577e) chore: add support for gogo protobuf generator\n* [`19f8d2e`](https://github.com/siderolabs/proto-codec/commit/19f8d2e5840c19937c60cee0c681343ab658f678) chore: add kres\n* [`e038bb4`](https://github.com/siderolabs/proto-codec/commit/e038bb42f2be8b80ca09e46bb8704be06a413919) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`1893385`](https://github.com/siderolabs/siderolink/commit/1893385fe45bf110357a770d31b06f5d79403065) fix: initialize tls listener properly\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>10 commits</summary>\n<p>\n\n* [`e061b6f`](https://github.com/siderolabs/tools/commit/e061b6fdc7ebbc9280d06433d99b9fc3c02773ef) feat: update dependencies\n* [`2704b85`](https://github.com/siderolabs/tools/commit/2704b8589fde4ea63f3063fdd1fc2ce0a8aa50e7) feat: update Go to 1.23.3\n* [`3750064`](https://github.com/siderolabs/tools/commit/375006431abb204c275adab2fdc9128060bb32f7) fix: update for musl with close_range\n* [`0a443c6`](https://github.com/siderolabs/tools/commit/0a443c6d5a1ac6764b22990be0945ef4cae8c32e) feat: update toolchain for gcc 14.2\n* [`63ecd80`](https://github.com/siderolabs/tools/commit/63ecd80a4709bcde5c6cc0f112c1faf43ab024ce) feat: bump depedendencies\n* [`2058296`](https://github.com/siderolabs/tools/commit/2058296cc223b683685f229a9a52de4db7171595) feat: bump dependencies\n* [`1151610`](https://github.com/siderolabs/tools/commit/1151610f5a5e70d07b715a2bdd76acd06d418595) feat: update Go to 1.23.2\n* [`9f2189b`](https://github.com/siderolabs/tools/commit/9f2189b2b032ed283f38b20c53018b921fa06895) fix: bump gettext-tiny to the latest dev version\n* [`95069d6`](https://github.com/siderolabs/tools/commit/95069d6fd8fccde7ab93465e4e49a5a6ac5d4ed0) feat: update Go to 1.23.1\n* [`eec0656`](https://github.com/siderolabs/tools/commit/eec0656aca652d0cc2e1973d5fab56bd4b54f64b) feat: replace gettext with gettext-tiny\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.5.0 -> v0.5.2\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.13.0 -> v1.16.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.7.0 -> v1.8.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.1.0 -> v1.3.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.1.0 -> v1.3.0\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.27.33 -> v1.28.3\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.13 -> v1.16.19\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.35.7 -> v1.37.5\n* **github.com/aws/smithy-go**                                                v1.20.4 -> v1.22.0\n* **github.com/containerd/containerd/api**                                    v1.8.0-rc.3 -> v1.8.0\n* **github.com/containerd/containerd/v2**                                     v2.0.0-rc.4 -> v2.0.0\n* **github.com/containerd/errdefs**                                           v0.1.0 -> v1.0.0\n* **github.com/containerd/platforms**                                         v0.2.1 -> v1.0.0-rc.0\n* **github.com/containerd/typeurl/v2**                                        v2.2.0 -> v2.2.3\n* **github.com/containernetworking/plugins**                                  v1.5.1 -> v1.6.0\n* **github.com/cosi-project/runtime**                                         v0.5.5 -> v0.7.1\n* **github.com/docker/cli**                                                   v27.3.1 **_new_**\n* **github.com/docker/docker**                                                v27.2.0 -> v27.3.1\n* **github.com/elastic/go-libaudit/v2**                                       v2.6.0 **_new_**\n* **github.com/fatih/color**                                                  v1.17.0 -> v1.18.0\n* **github.com/florianl/go-tc**                                               v0.4.4 **_new_**\n* **github.com/foxboron/go-uefi**                                             e2076f0e58ca -> fab4fdf2f2f3\n* **github.com/fsnotify/fsnotify**                                            v1.7.0 -> v1.8.0\n* **github.com/google/cadvisor**                                              v0.50.0 -> v0.51.0\n* **github.com/google/cel-go**                                                v0.22.0 **_new_**\n* **github.com/gopacket/gopacket**                                            v1.2.0 -> v1.3.1\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.13.1 -> v2.16.0\n* **github.com/klauspost/compress**                                           v1.17.9 -> v1.17.11\n* **github.com/klauspost/cpuid/v2**                                           v2.2.8 -> v2.2.9\n* **github.com/linode/go-metadata**                                           v0.2.0 -> v0.2.1\n* **github.com/mdlayher/ethtool**                                             v0.1.0 -> v0.2.0\n* **github.com/opencontainers/runc**                                          v1.2.0-rc.3 -> v1.2.1\n* **github.com/rivo/tview**                                                   fd649dbf1223 -> c76f7879f592\n* **github.com/safchain/ethtool**                                             v0.4.1 -> 4e3aff457298\n* **github.com/siderolabs/crypto**                                            v0.4.4 -> v0.5.0\n* **github.com/siderolabs/discovery-api**                                     v0.1.4 -> v0.1.5\n* **github.com/siderolabs/discovery-client**                                  v0.1.9 -> v0.1.10\n* **github.com/siderolabs/extras**                                            v1.8.0 -> v1.9.0-alpha.0-2-g78ba66b\n* **github.com/siderolabs/gen**                                               v0.5.0 -> v0.7.0\n* **github.com/siderolabs/go-blockdevice**                                    v0.4.7 -> v0.4.8\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.2 -> v2.0.6\n* **github.com/siderolabs/go-circular**                                       v0.2.0 -> v0.2.1\n* **github.com/siderolabs/go-cmd**                                            v0.1.1 -> v0.1.3\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.12 -> v0.2.16\n* **github.com/siderolabs/grpc-proxy**                                        v0.4.1 -> v0.5.1\n* **github.com/siderolabs/pkgs**                                              v1.8.0-8-gdf1a1a5 -> v1.9.0-alpha.0-45-ga463a50\n* **github.com/siderolabs/proto-codec**                                       v0.1.1 **_new_**\n* **github.com/siderolabs/siderolink**                                        v0.3.10 -> v0.3.11\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.8.0 -> v1.9.0-alpha.2\n* **github.com/siderolabs/tools**                                             v1.8.0-1-ga0c06c6 -> v1.9.0-alpha.0-9-ge061b6f\n* **github.com/thejerf/suture/v4**                                            v4.0.5 **_new_**\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.16 -> v3.5.17\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.16 -> v3.5.17\n* **go.etcd.io/etcd/client/v3**                                               v3.5.16 -> v3.5.17\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.16 -> v3.5.17\n* **golang.org/x/net**                                                        v0.29.0 -> v0.31.0\n* **golang.org/x/oauth2**                                                     v0.23.0 -> v0.24.0\n* **golang.org/x/sync**                                                       v0.8.0 -> v0.9.0\n* **golang.org/x/sys**                                                        v0.25.0 -> v0.27.0\n* **golang.org/x/term**                                                       v0.24.0 -> v0.26.0\n* **golang.org/x/text**                                                       v0.18.0 -> v0.20.0\n* **golang.org/x/time**                                                       v0.6.0 -> v0.8.0\n* **google.golang.org/grpc**                                                  v1.66.0 -> v1.68.0\n* **google.golang.org/protobuf**                                              v1.34.2 -> v1.35.1\n* **k8s.io/api**                                                              v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apimachinery**                                                     v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apiserver**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/client-go**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/component-base**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/cri-api**                                                          v0.32.0-alpha.0 -> v0.32.0-beta.0\n* **k8s.io/kube-scheduler**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubectl**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubelet**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/pod-security-admission**                                           v0.31.1 -> v0.32.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**                           v1.2.70 -> v1.2.72\n\nPrevious release can be found at [v1.8.0](https://github.com/siderolabs/talos/releases/tag/v1.8.0)\n\n## [Talos 1.9.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.9.0-alpha.2) (2024-11-08)\n\nWelcome to the v1.9.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### AppArmor\n\nTalos Linux starting with v1.9 will ship with SELinux LSM enabled by default.\nIf you need to use AppArmor LSM add the following to the machine configuration:\n\n```yaml\nmachine:\n  install:\n     extraKernelArgs:\n      - -selinux\n      - lsm=lockdown,capability,yama,apparmor,bpf\n      - apparmor=1\n```\n\n\n### Auditd\n\nTalos Linux now starts a auditd service by default.\nLogs can be read with `talosctl logs auditd`.\n\n\n### `talosctl cgroups`\n\nThe `talosctl cgroups` command has been added to the `talosctl` tool.\nThis command allows you to view the cgroup resource consumption and limits for a machine, e.g.\n`talosctl cgroups --preset memory`.\n\n\n### udevd\n\nTalos previously used `udevd` to provide `udevd`, now it uses `systemd-udevd` instead.\n\n\n### Component Updates\n\nLinux: 6.6.59\ncontainerd: 2.0.0\nFlannel: 0.26.0\nKubernetes: 1.32.0-beta.0\nrunc: 1.2.1\n\nTalos is built with Go 1.23.2.\n\n\n### User Namespaces\n\nTalos Linux now supports running Kubernetes pods with user namespaces enabled.\nRefer to the [documentation](https://www.talos.dev/v1.9/kubernetes-guides/configuration/usernamespace/) for more information.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Dmitry Sharshakov\n* Joakim Nohlgård\n* Jean-Francois Roy\n* Utku Ozdemir\n* blablu\n* Adolfo Ochagavía\n* Dan Rue\n* David Backeus\n* Eddie Wang\n* Florian Ströger\n* Hexoplon\n* Jakob Maležič\n* KBAegis\n* Mike Beaumont\n* Nebula\n* Nico Berlee\n* Philip Schmid\n* Philipp Kleber\n* Remko Molier\n* Robby Ciliberto\n* Ryan Borstelmann\n* Serge Logvinov\n* Spencer Smith\n* Steven Cassamajor\n* Tim Jones\n* adilTepe\n* ekarlso\n* naed3r\n* nevermarine\n* solidDoWant\n\n### Changes\n<details><summary>144 commits</summary>\n<p>\n\n* [`a309f6aa57`](https://github.com/siderolabs/talos/commit/a309f6aa57f4d99bbf17d0fef2fab4602e12b067) chore: fix nil pointer dereference in AWS uploader\n* [`333737f176`](https://github.com/siderolabs/talos/commit/333737f176f918ca3dd4217ddfed87c4da86bb9b) test: fix unpriviliged process runner test\n* [`2001167058`](https://github.com/siderolabs/talos/commit/200116705885b1f9935b719de71d661c695eae99) chore(ci): save support zip always after tests\n* [`6a42c3b8ed`](https://github.com/siderolabs/talos/commit/6a42c3b8ed58b6363a62710709f20266ca190b36) release(v1.9.0-alpha.1): prepare release\n* [`fb72e4b7b7`](https://github.com/siderolabs/talos/commit/fb72e4b7b74979acf743d20c7c099bc5513836e0) fix(ci): skip test if `UserNamespacesSupport` feature gate is not set\n* [`11380f933d`](https://github.com/siderolabs/talos/commit/11380f933ddd3fe42dc01d5ed09ceff0d62b417d) feat: display current CPU frequency on dashboard\n* [`fbce267aee`](https://github.com/siderolabs/talos/commit/fbce267aee98e3b4b6acace156aa22d75ad01d3d) feat: check bridged interfaces should not have addresses\n* [`942962bf00`](https://github.com/siderolabs/talos/commit/942962bf005a7036e04f4e572f3434f476cb567c) docs: add docs on usernamespace support in k8s\n* [`0406a05a98`](https://github.com/siderolabs/talos/commit/0406a05a986fabc3834c5a0de48362826268edbe) chore: update pkgs to ones built with gcc 14.2\n* [`2e127627dc`](https://github.com/siderolabs/talos/commit/2e127627dce7251d5848718036780c91384c4396) docs: add apparmor enablement release notes\n* [`aa9311f3d8`](https://github.com/siderolabs/talos/commit/aa9311f3d840c7b5a69a1eb6ab4cb3b1a7bff135) fix: install disk matcher error\n* [`1800f81044`](https://github.com/siderolabs/talos/commit/1800f8104486f01e8a3437432e508893f02f809c) fix: selinux handling and apparmor tests\n* [`313bffadfb`](https://github.com/siderolabs/talos/commit/313bffadfb66b053f51046300764e94db088b18a) feat: update Kubernetes to v1.32.0-beta.0\n* [`bbfa144510`](https://github.com/siderolabs/talos/commit/bbfa144510063fdcdebbc017b4fb382ac839370c) feat: update containerd to v2.0.0\n* [`8e02b9fcbf`](https://github.com/siderolabs/talos/commit/8e02b9fcbfba421abd13ffe4fc8ea3892d4673eb) docs: update manual k8s upgrade docs\n* [`474949dc77`](https://github.com/siderolabs/talos/commit/474949dc77363123f0e8cf2c918ecacb82b4dbdd) feat: add dm-cache dm-cache-smq kernel modules\n* [`5112547d6b`](https://github.com/siderolabs/talos/commit/5112547d6b12b4ff40e7863f363cf519efb8c76c) chore: generate support zip for crashdump\n* [`a867f85e4c`](https://github.com/siderolabs/talos/commit/a867f85e4cb662a17b0738f1f0de4f1485ad925a) feat: label system socket and runtime files\n* [`398f714cff`](https://github.com/siderolabs/talos/commit/398f714cff04c524394933da17cbc21ad239cd42) feat: update Linux 6.6.59, runc 1.2.1\n* [`05c620957c`](https://github.com/siderolabs/talos/commit/05c620957ca741451da395036e8eca59e631fe8d) feat: allow extra mounts for docker-based `talosctl cluster create`\n* [`cedabeddf7`](https://github.com/siderolabs/talos/commit/cedabeddf7d191f39525a61e65164f280b6807f8) chore: cleanup code\n* [`61d363e1d0`](https://github.com/siderolabs/talos/commit/61d363e1d093047886638d5bc5b9f2181c8bd894) chore: update go-auditlib\n* [`960a040491`](https://github.com/siderolabs/talos/commit/960a040491de5c95b104b4a39ea519095eb47931) feat: start enabling SELinux\n* [`7f3aaa21cd`](https://github.com/siderolabs/talos/commit/7f3aaa21cd8d969e26721235a4191ba3bdbc1f8f) fix: update permissions for logging directories in /var\n* [`0e6c983b84`](https://github.com/siderolabs/talos/commit/0e6c983b847f679a074c1794fbe77d21a5994233) fix: mount /sys/kernel/security conditionally\n* [`74b0e8c371`](https://github.com/siderolabs/talos/commit/74b0e8c3713a01f83758556672583880ce5c684a) fix: make route normalization keep family\n* [`0a3761c22f`](https://github.com/siderolabs/talos/commit/0a3761c22f98783c6696f143611d600287a471a3) fix: talosctl windows arm64\n* [`4b10c5328b`](https://github.com/siderolabs/talos/commit/4b10c5328b861b4bcdcec3ca21bd55b91e969b44) chore: add Windows ARM64 build for talosctl\n* [`9abf16108e`](https://github.com/siderolabs/talos/commit/9abf16108ede75984845297d03673d56cb561c2f) feat: add auditd service\n* [`d464ca869f`](https://github.com/siderolabs/talos/commit/d464ca869f8949ffbb990c6fb02fbbcbe0abcbe1) chore: drop runc memfd bind added in #9069\n* [`b54d26c2c3`](https://github.com/siderolabs/talos/commit/b54d26c2c3f3a52c6d1ec3fddb7a373175815de3) fix: mount pseudo sub-mountpoints in init\n* [`7aeb15f730`](https://github.com/siderolabs/talos/commit/7aeb15f73094a23aea1d6b263ca2eca061c8a257) chore: disable coredns cache for cluster domain\n* [`d8b652150c`](https://github.com/siderolabs/talos/commit/d8b652150cec408f2bf3307565b9db691b21bfe9) docs: add warning about NVMe bus path bug\n* [`3e16ab135e`](https://github.com/siderolabs/talos/commit/3e16ab135e2be8c9b652d67f9e7eadbc3691c5ca) feat: update Kubernetes to v1.32.0-alpha.3\n* [`0b8b356777`](https://github.com/siderolabs/talos/commit/0b8b3567771fbe796926dc9a6e904e7102535170) feat: add BridgePort property to network machine configuration\n* [`b379506259`](https://github.com/siderolabs/talos/commit/b3795062596ef45dd309f1ca56aab31d2a1a0efc) fix: use more correct condition to skip generating hosts files\n* [`62ec7ec336`](https://github.com/siderolabs/talos/commit/62ec7ec3367233823c09befddc5ad312aa607822) refactor: replace the old v1 mount package with new one\n* [`0ece13c623`](https://github.com/siderolabs/talos/commit/0ece13c6236c7eda474d3734fcc4c4060299ac43) docs: update network-config.md (cont)\n* [`93827f0485`](https://github.com/siderolabs/talos/commit/93827f0485a92b46da83b80a2a55f2569f70fe57) docs: update network-config.md\n* [`423b1e5fb2`](https://github.com/siderolabs/talos/commit/423b1e5fb22d9e785a3832741d796120b84a5e38) fix: do not trim 0 from process SELinux label\n* [`2136358d65`](https://github.com/siderolabs/talos/commit/2136358d65ddf6ad040ed62c835b335f99a59399) feat: introduce metal agent mode\n* [`0e15955fcc`](https://github.com/siderolabs/talos/commit/0e15955fcc5d464c5f0ffd1a44eebf4bf32f4844) chore: small refactoring\n* [`66012a7f26`](https://github.com/siderolabs/talos/commit/66012a7f269010c5ed412d139b14c470063f2429) feat: remove wrapperd and launch processes directly\n* [`3a0a17ae66`](https://github.com/siderolabs/talos/commit/3a0a17ae66dab5c983571fab0f3eac3f87fbc17c) fix: prevent panic in nocloud platform code\n* [`dc0c6acbd7`](https://github.com/siderolabs/talos/commit/dc0c6acbd765b6e7838d6af4f1903242d5073782) refactor: remove unmaintained github.com/vishvananda/netlink\n* [`78353f7918`](https://github.com/siderolabs/talos/commit/78353f79188e81d064c354f6ef3fe3b2e023c644) feat: add parsing of vlanNNNN:ethX style VLAN cmdline args\n* [`9db7a36bfc`](https://github.com/siderolabs/talos/commit/9db7a36bfc45c9c15fd661fb2a6319dcf4fef210) fix: generation of SecureBoot iso\n* [`c755b6d7e4`](https://github.com/siderolabs/talos/commit/c755b6d7e4600fdfb32be50422b7efb0fdabef63) fix: update the CRI sandbox image reference\n* [`cec290b354`](https://github.com/siderolabs/talos/commit/cec290b354773b2b0f2c2ae9d57f36e06fe2654d) feat: allow extensions to log to console\n* [`b7801df827`](https://github.com/siderolabs/talos/commit/b7801df827d8e1e9a2db7dac0a62c3802de4d73c) fix: wait for udevd to be running before activating LVM\n* [`d4cb478a50`](https://github.com/siderolabs/talos/commit/d4cb478a50ce41c3699b7846388e537ddf18a703) docs: improve field description for BridgeSTP, BridgeVLAN\n* [`7329824b24`](https://github.com/siderolabs/talos/commit/7329824b2411fef3b23fd90380033441048f6512) docs: add Mynewsdesk to ADOPTERS.md\n* [`a13cf76a34`](https://github.com/siderolabs/talos/commit/a13cf76a3415f458ff3235981c1be8202e1800bb) chore: simplify `DNSUpstreamController` and `DNSUpstream` resource\n* [`62d185473e`](https://github.com/siderolabs/talos/commit/62d185473e258c0c34eff5aed4c18d81d4b92a89) fix: talosctl process null character\n* [`77d7368eae`](https://github.com/siderolabs/talos/commit/77d7368eae2da6d2c9aa896afc8013007909a958) feat: update containerd to v2.0.0-rc.6\n* [`d39393879a`](https://github.com/siderolabs/talos/commit/d39393879a1f98ac3de7a96808301d1e07fd95f3) fix: rework the 'metal-iso' config acquisition\n* [`1993afca9f`](https://github.com/siderolabs/talos/commit/1993afca9fff7e889b497ec3241cfdca42294f18) chore: create /usr/etc in a different step\n* [`8680351c13`](https://github.com/siderolabs/talos/commit/8680351c131d29a76682569742dbd44c8ffe47d3) chore: move system extensions' udev rules\n* [`3067f64c84`](https://github.com/siderolabs/talos/commit/3067f64c8435ef2d5453100a1584dc3c6915ba0b) feat: update Flannel to v0.26.0\n* [`8658d6865f`](https://github.com/siderolabs/talos/commit/8658d6865fa0bcbfcebe483b7332d3b56e239979) docs: typo in deploying cilium\n* [`49bbadc4bf`](https://github.com/siderolabs/talos/commit/49bbadc4bf1e79e48c057d473ae21426b273c588) docs: add documentation on performance tuning\n* [`534b0ce183`](https://github.com/siderolabs/talos/commit/534b0ce1833462b22f3761258e0e95813a355fb2) feat: update runc to 1.2.0 final\n* [`2172535237`](https://github.com/siderolabs/talos/commit/21725352373da7835d95f8f934847dab404782f8) docs: fix image factory links\n* [`375e3da73f`](https://github.com/siderolabs/talos/commit/375e3da73fcb02c7caea2576289fefdc395a1ed2) feat: update Kubernetes to 1.32.0-alpha.2\n* [`9e6f64df04`](https://github.com/siderolabs/talos/commit/9e6f64df047527ecb42df5fdf5fd2f9767d21437) fix: improve error messages for invalid bridge/bond configuration\n* [`7c8c72c2b2`](https://github.com/siderolabs/talos/commit/7c8c72c2b2a4edb412e097a9e013ab21727339cf) fix: correct error message for invalid ip=\n* [`ead46997c9`](https://github.com/siderolabs/talos/commit/ead46997c918ab1139ca12e87beefbbda29614e1) chore: rename tpm2.PCRExtent -> tpm2.PCRExtend\n* [`867c4b8125`](https://github.com/siderolabs/talos/commit/867c4b8125ee738f9a82e5e87809eb95bdd2f778) docs: fix typo in prodnotes.md\n* [`1b22df48a4`](https://github.com/siderolabs/talos/commit/1b22df48a41578d19fb512bd8111a481b64011e2) chore: support debug shell for advanced development\n* [`c14b446229`](https://github.com/siderolabs/talos/commit/c14b4462292bd7e6088fce35d6880a9b2b56335c) feat: update Kubernetes to v1.32.0-alpha.1\n* [`29780d35a0`](https://github.com/siderolabs/talos/commit/29780d35a052134d50576f6506c2728489a30506) test: add an integration test for verifying process parameters\n* [`3d342af447`](https://github.com/siderolabs/talos/commit/3d342af4479ed12e2af10021ec4e7ab9c2af6d75) fix: update incorrect alias for PCIDevice resource\n* [`f7d35a5e0b`](https://github.com/siderolabs/talos/commit/f7d35a5e0b4e3a04a639d663e5a580e22fea76db) release(v1.9.0-alpha.0): prepare release\n* [`e0434d77d7`](https://github.com/siderolabs/talos/commit/e0434d77d754f8834ba903f4c09b08634cfd3934) feat: update dependencies\n* [`5c5a248861`](https://github.com/siderolabs/talos/commit/5c5a248861c8e5848f9a23cd0cd7b3b749f21e4b) feat: add Talos 1.9 compatibility guarantees\n* [`bc4c21f41a`](https://github.com/siderolabs/talos/commit/bc4c21f41a0066ba6cefb5b753c52d76a6b0f629) test: add json logs test environment\n* [`71faa32942`](https://github.com/siderolabs/talos/commit/71faa3294246947f6bd212979ceb31e793ae0604) docs: nvidia proprietary/oss hardware requirement\n* [`59a78da42c`](https://github.com/siderolabs/talos/commit/59a78da42cdea8fbccc35d0851f9b0eef928261b) chore: add proto-codec/codec\n* [`7ff1cedfe3`](https://github.com/siderolabs/talos/commit/7ff1cedfe3eee51505c30439eec4a2df9b452b2e) chore: update siderolabs/crypto module and return proper ALPN\n* [`ccbd5aed39`](https://github.com/siderolabs/talos/commit/ccbd5aed39b360664d1f80c8b146050e9df9ff7b) feat: optionally decode hcloud userdata as base64\n* [`34f652ce82`](https://github.com/siderolabs/talos/commit/34f652ce822fcb70a292289fe6ba5d1bd7a34f97) feat: add well-known app.kubernetes.io labels to control-plane pods\n* [`fc89dc2164`](https://github.com/siderolabs/talos/commit/fc89dc21643a923cb7d0d3944405521bf849631b) fix: support `extra-disks` when using iso\n* [`f2bff814de`](https://github.com/siderolabs/talos/commit/f2bff814de0b237fbed419234b935dc9f9637554) chore: add arm64 target for integration-test\n* [`5853bb0ea4`](https://github.com/siderolabs/talos/commit/5853bb0ea4d6a65635086bdef617d6d0800cabd0) fix: json logging panic\n* [`a859cff364`](https://github.com/siderolabs/talos/commit/a859cff364aa4dc9b4b880417b821f7ecf5602ac) chore: use virtio driver for disks in arm64\n* [`db248de88d`](https://github.com/siderolabs/talos/commit/db248de88dec2467e4340f699cde98217979ba4b) chore(ci): add config for lldpd extension\n* [`9f0de9f43d`](https://github.com/siderolabs/talos/commit/9f0de9f43dc4467f0bdeda117b4946ae12db50ab) test: update provision upgrade tests for Talos 1.9\n* [`39fe285e69`](https://github.com/siderolabs/talos/commit/39fe285e69691059f91d8c7c5506e156356263d9) fix: skip ram disks\n* [`a9bff3a1d0`](https://github.com/siderolabs/talos/commit/a9bff3a1d084c32a654555e71e2592e60edbdcb6) test: skip no error test in Cilium\n* [`4d902021bb`](https://github.com/siderolabs/talos/commit/4d902021bb3c55bc212cbb3e2443b6552400622f) fix: do not use pflag csv comma reader for config-patch\n* [`5371788ce1`](https://github.com/siderolabs/talos/commit/5371788ce169a0381e08f0d902ac81f3f89ba5bd) fix: typo in documentation\n* [`8a228ba6bc`](https://github.com/siderolabs/talos/commit/8a228ba6bc702f21fca06dc2ecb3e8e846839cd3) docs: add egress documentation\n* [`182325cb07`](https://github.com/siderolabs/talos/commit/182325cb0791da1d4dcd3914a643c44232502524) test: skip lvm test if not enough user disks available\n* [`519a48302e`](https://github.com/siderolabs/talos/commit/519a48302e771fd9b331913166d55c50fff4961a) fix: wipe system partitions correctly via kernel args\n* [`0a2b4556c5`](https://github.com/siderolabs/talos/commit/0a2b4556c55eda27536ee563f60bcf5d69379479) fix: volume encryption with failing keyslots\n* [`6affbd3182`](https://github.com/siderolabs/talos/commit/6affbd3182ebe0209ed5433c534062b7ad672b6a) fix: update grpc-go the latest patch release\n* [`77a4a4adc7`](https://github.com/siderolabs/talos/commit/77a4a4adc7232b4382f2a530f4056a1fff6c50b4) fix: scaleway metadata\n* [`7acadc0c8f`](https://github.com/siderolabs/talos/commit/7acadc0c8fa969e4de7f0d4f68b0fd0cd833b489) fix: do not stop udevd before unmounting volumes\n* [`6a081055b0`](https://github.com/siderolabs/talos/commit/6a081055b0dd4e3ce5c40392c8415a0a55b2591c) feat: update Flannel to v0.25.7\n* [`2362f6d3ee`](https://github.com/siderolabs/talos/commit/2362f6d3ee51a0a8b541a872d39ac82892502e17) fix: improve container detection\n* [`b67bc73fd3`](https://github.com/siderolabs/talos/commit/b67bc73fd30a8e07f26c47a746ca53f2af41d366) fix: fix mdadm system extension\n* [`f08669c7a9`](https://github.com/siderolabs/talos/commit/f08669c7a9583a559dc53f233798305bbab07b8a) feat: bring in lpfc kernel module driver\n* [`6a014374be`](https://github.com/siderolabs/talos/commit/6a014374be26f0caf8faa90a34f2476e0e77a46a) feat: enable QEDF driver\n* [`f711907e03`](https://github.com/siderolabs/talos/commit/f711907e038cea20f6b831ea5ad8c3b18638c1b4) fix: make /var/run empty on reboots\n* [`7d02eb60f4`](https://github.com/siderolabs/talos/commit/7d02eb60f47652f4b72f170b28a8b964729af013) docs: fix typo in CloudStack docs\n* [`74861573a7`](https://github.com/siderolabs/talos/commit/74861573a793f9e143d7d2638990f37ec639aa88) fix: multiple fixes for LVM activation\n* [`74c12c20e0`](https://github.com/siderolabs/talos/commit/74c12c20e02e4ec29b2b374cebc996ddf8fa90c7) feat: replace eudev with systemd-udevd\n* [`0a4df4ef84`](https://github.com/siderolabs/talos/commit/0a4df4ef84467014d5be4b4ec57de0e778cfb21e) docs: fix nvidia CRI config example\n* [`afc1e1a46a`](https://github.com/siderolabs/talos/commit/afc1e1a46a559aac3aa5f4a2708ba8d2c9228929) docs: fix typo in extraMounts directory\n* [`a341bdb064`](https://github.com/siderolabs/talos/commit/a341bdb0640294a07939670919c56cbfa7a861c4) fix: prevent file descriptors leaks to child processes\n* [`dec653bfe1`](https://github.com/siderolabs/talos/commit/dec653bfe1feb84ea2ed1a779b1bfc783dc61160) chore: better lvm2 tests\n* [`908fd8789c`](https://github.com/siderolabs/talos/commit/908fd8789cc1b22e556a7ffe307409931976ba08) feat: support cgroup deep analysis in `talosctl`\n* [`aa846cc186`](https://github.com/siderolabs/talos/commit/aa846cc186c1c6125f8f39ea084fa2023512656f) feat: add support for CI Network config in nocloud\n* [`10f2539f23`](https://github.com/siderolabs/talos/commit/10f2539f237aeb3af2caeb3c349c062f203219b6) chore: disable cloud-images cron workflow\n* [`b07a8b36b2`](https://github.com/siderolabs/talos/commit/b07a8b36b24d57337323e72d6032304c4cade927) chore: ignore more plugins for system containerd\n* [`392c4798f0`](https://github.com/siderolabs/talos/commit/392c4798f0bff7cb4518609deae7c90581f013f5) feat: prepare for Talos 1.9\n* [`ea7bf9fb43`](https://github.com/siderolabs/talos/commit/ea7bf9fb43dff8cf8ec4dfd4f629e8f826bc2ded) docs: update storage.md\n* [`4ab8dee69a`](https://github.com/siderolabs/talos/commit/4ab8dee69ac07c811cbe121ca9e2d9bd01148863) fix: build talosctl without `tcell_minimal`\n* [`2fa019bd97`](https://github.com/siderolabs/talos/commit/2fa019bd9751ad96085ade52628023adf17658d3) docs: enable 'edit on GitHub' link\n* [`d2ccbc2b15`](https://github.com/siderolabs/talos/commit/d2ccbc2b1512b6323d48a764c4af534d49b4bd27) docs: update hetzner documentation for CCM\n* [`d498f647cd`](https://github.com/siderolabs/talos/commit/d498f647cd9dfcd575f51005c9b78c2c1c7b51ca) docs: fix Kernel Self Protection Project (KSPP) references\n* [`0ec75463ee`](https://github.com/siderolabs/talos/commit/0ec75463eecebfb543a64b0c859ba0b2477e406f) docs: make Talos 1.8 current release\n* [`9b77698cf2`](https://github.com/siderolabs/talos/commit/9b77698cf2ff64c6f6d198d05c2012ab7fa858be) fix: update blockdevice library to v2.0.2\n* [`e46227ab95`](https://github.com/siderolabs/talos/commit/e46227ab95a6d06132e82315f55b5ced533ddabb) docs: fix kubespan name inconsistency\n* [`6b15ca19cd`](https://github.com/siderolabs/talos/commit/6b15ca19cd1291b8a245d72d5153827945cad037) fix: audit and fix cgroup reservations\n* [`32b5d01ed3`](https://github.com/siderolabs/talos/commit/32b5d01ed3396e8f54a245cc6d9818119aec8291) chore: bump lvm2\n* [`6484581eb8`](https://github.com/siderolabs/talos/commit/6484581eb888996a8dc829915439fb63606dd794) feat: allow /sbin/ldconfig in extensions\n* [`9fa08e8437`](https://github.com/siderolabs/talos/commit/9fa08e843728dbd85ed7e0035f59cdd6232de9a9) chore: refactor tests\n* [`d8ab4981b6`](https://github.com/siderolabs/talos/commit/d8ab4981b626ff41fbcdb526a032a5584519e3df) feat: support lvm auto activation\n* [`8166a58b36`](https://github.com/siderolabs/talos/commit/8166a58b364f760212b2a610ce0d764b8b4c5c46) fix: filter out non-printable characters in process line\n* [`806b6aaf52`](https://github.com/siderolabs/talos/commit/806b6aaf52f20ed0f32107b3d0372d6e3ff974be) docs: add SECURITY.md\n* [`7bd26df308`](https://github.com/siderolabs/talos/commit/7bd26df30803307e4eece3e382aafebc55e7b260) docs: document `/dev/net/tun` compatibility\n* [`18daedb511`](https://github.com/siderolabs/talos/commit/18daedb511e769717ba56eb05cccab72118a4813) fix: strategic merge patch delete for map keys\n* [`f3370529ac`](https://github.com/siderolabs/talos/commit/f3370529ac042865a4b2d793465916fcae2d4b33) docs: correct typo\n* [`8d6884a8e2`](https://github.com/siderolabs/talos/commit/8d6884a8e28e1bfa29f9a479e0f7179819cf70cd) test: add a test for inline machine config trusted roots\n* [`d4a6d017db`](https://github.com/siderolabs/talos/commit/d4a6d017dbb91e22c60787cdf64b242057b1ebef) fix: ignore invalid NTP responses\n* [`869f8379f2`](https://github.com/siderolabs/talos/commit/869f8379f2317175901e8cb3deec4b800e7ab603) feat: update default Kubernetes version to 1.31.1\n* [`780a1f198a`](https://github.com/siderolabs/talos/commit/780a1f198a5eedd33a27060bdf116bd3a3b26426) fix: update CoreDNS health check\n* [`79cd031588`](https://github.com/siderolabs/talos/commit/79cd031588a0710b865414f919742ee3ffb998ed) chore: account for resource sorting in dns upstream resource\n* [`e17fafaca2`](https://github.com/siderolabs/talos/commit/e17fafaca2a16990bc424b54120c49ddbaf8cee1) chore: drop `activateLogicalVolumes` sequencer step\n* [`a294b366f2`](https://github.com/siderolabs/talos/commit/a294b366f24c6580d304c6c8ad34f481079dc795) fix: parse SideroLink API endpoint correctly\n* [`a9269ac7b1`](https://github.com/siderolabs/talos/commit/a9269ac7b1217aa2d247c0215c5f2755af468b44) fix: remove extra logging on ethtool ioctl failures\n* [`5c6277d171`](https://github.com/siderolabs/talos/commit/5c6277d171eea58878ce4fcb4d2fdb7154333ae7) feat: update etcd to 3.5.16\n* [`c1ed2984b8`](https://github.com/siderolabs/talos/commit/c1ed2984b85dca791a5081c5da26bba75e3cd579) docs: add what's new for Talos 1.8\n</p>\n</details>\n\n### Changes since v1.9.0-alpha.1\n<details><summary>3 commits</summary>\n<p>\n\n* [`a309f6aa5`](https://github.com/siderolabs/talos/commit/a309f6aa57f4d99bbf17d0fef2fab4602e12b067) chore: fix nil pointer dereference in AWS uploader\n* [`333737f17`](https://github.com/siderolabs/talos/commit/333737f176f918ca3dd4217ddfed87c4da86bb9b) test: fix unpriviliged process runner test\n* [`200116705`](https://github.com/siderolabs/talos/commit/200116705885b1f9935b719de71d661c695eae99) chore(ci): save support zip always after tests\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`58b2f92`](https://github.com/siderolabs/crypto/commit/58b2f9291c7e763a7210cfa681f88a7fa2230bf3) chore: use HTTP/2 ALPN by default\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`005e92c`](https://github.com/siderolabs/discovery-api/commit/005e92cf4ad0059334bfd35285a97c85f12aa263) chore: rekres and regen\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b74fb90`](https://github.com/siderolabs/discovery-client/commit/b74fb9039fcfd8db9d6becf3044f9f41f387ea27) fix: allow custom TLS config for the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`eab6e58`](https://github.com/siderolabs/extras/commit/eab6e58aa9bdf49789cd4d64d2e27f61023421ca) feat: update dependencies\n* [`1459d78`](https://github.com/siderolabs/extras/commit/1459d78cbeb297c023501a3eb785a27a5bdd4933) feat: update pkgs for 1.9\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`e847d2a`](https://github.com/siderolabs/gen/commit/e847d2ace9ede4a17283426dfbc8229121f2909b) chore: add more utilities to xiter\n* [`f3c5a2b`](https://github.com/siderolabs/gen/commit/f3c5a2b5aba74e4935d073a0135c4904ef3bbfef) chore: add `Empty` and `Empty2` iterators\n* [`c53b90b`](https://github.com/siderolabs/gen/commit/c53b90b4a418b8629d938af06900249ce5acd9e6) chore: add packages xiter/xstrings/xbytes\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`134c41b`](https://github.com/siderolabs/go-blockdevice/commit/134c41be6f4c498a149b8098fa8d862c5c47ca54) fix: fast wipe also last 1MB of the device\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`9a0f7b0`](https://github.com/siderolabs/go-circular/commit/9a0f7b02c80ad6c2d953b2d3dd388c56e89363ea) fix: multiple data race issues\n</p>\n</details>\n\n### Changes from siderolabs/go-cmd\n<details><summary>3 commits</summary>\n<p>\n\n* [`d735250`](https://github.com/siderolabs/go-cmd/commit/d73525092a1bb135da54d538e5d64c4dcc80259e) fix: return an error on process nonzero exit code\n* [`5662c7f`](https://github.com/siderolabs/go-cmd/commit/5662c7f8d5cf475c57b3a23b8d8546d960ebc60a) feat: add an equivalent of WaitWrapper for os.Process\n* [`71fced6`](https://github.com/siderolabs/go-cmd/commit/71fced673e013423bba83064767a90372dd6cf51) chore: rekres and move to GHA\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`87d2e8e`](https://github.com/siderolabs/go-kubernetes/commit/87d2e8e664c3e3e64403bcfcfe2f8691f60c6481) feat: add one more deprecation for 1.32.0-beta.0\n* [`e56a7f6`](https://github.com/siderolabs/go-kubernetes/commit/e56a7f65808b90058df16a4133f19484beeedc31) fix: update deprecations based on Kubernetes 1.32.0-alpha.3\n* [`381f251`](https://github.com/siderolabs/go-kubernetes/commit/381f251662eaae9b48470ce00f504c2c64187612) feat: update for Kubernetes 1.32\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>2 commits</summary>\n<p>\n\n* [`de1c628`](https://github.com/siderolabs/grpc-proxy/commit/de1c6286b7d16d8485bf8bb55c8783c8773851a0) fix: copy data from big frame msg\n* [`ef47ec7`](https://github.com/siderolabs/grpc-proxy/commit/ef47ec77d2a9f0f42e713d456943dfe9ee86a629) chore: upgrade Codec implementations and usages to Codec2\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>38 commits</summary>\n<p>\n\n* [`4699763`](https://github.com/siderolabs/pkgs/commit/4699763c6d745620aecd0219fc78962e4fa0a01e) feat: update gcc to 14.2\n* [`9a98f73`](https://github.com/siderolabs/pkgs/commit/9a98f73de2c0353e9f8f194bd31c50eea1fb4d5b) feat: update containerd to v2.0.0\n* [`20e1e08`](https://github.com/siderolabs/pkgs/commit/20e1e0857a7d0cf05983998df3160fe0607d5075) feat: enable CONFIG_DM_CACHE\n* [`df45e16`](https://github.com/siderolabs/pkgs/commit/df45e1676828e49d77718e717b2e0e425122c62c) feat: update Linux to 6.6.59\n* [`2e733cc`](https://github.com/siderolabs/pkgs/commit/2e733cccfd225712eb7395cf04b6d8df0bf2b8d2) feat: bump dependencies\n* [`c92e123`](https://github.com/siderolabs/pkgs/commit/c92e123b40457f45e9fc0fe271804fa95c8d4f09) fix: enable nvme and 2.5gbit ethernet on nanopi-r5s\n* [`b160184`](https://github.com/siderolabs/pkgs/commit/b160184a479c85b8b19d2a874e5d6d52db9ed096) feat: update runc to v1.2.1\n* [`e9950d9`](https://github.com/siderolabs/pkgs/commit/e9950d9097fa002e79e2933344f68bb09ad6d4df) chore: drop syslinux\n* [`fc2e8dc`](https://github.com/siderolabs/pkgs/commit/fc2e8dc07ad096d0394f8deacb20d423ef102c2f) feat: update containerd to v2.0.0-rc.6\n* [`38304a6`](https://github.com/siderolabs/pkgs/commit/38304a60e3b32f0b3216ce8128df5f98d8be6812) feat: update Linux to 6.6.58\n* [`84b8df8`](https://github.com/siderolabs/pkgs/commit/84b8df8baf408ab22649b02910294154e0ad5f3b) chore: do not use /usr/etc/udev\n* [`c9282c8`](https://github.com/siderolabs/pkgs/commit/c9282c8dc6a535b69a953c0b4f43fd0780c5bb30) feat: update runc to 1.2.0\n* [`38ad08e`](https://github.com/siderolabs/pkgs/commit/38ad08ecb57d456b76f6d53a7d8a75c3b32f7d61) fix: default IOMMU mode to 'lazy'\n* [`be92da0`](https://github.com/siderolabs/pkgs/commit/be92da09f3196d96b1358efd6a7c667297d3ecfb) feat: update Linux to 6.6.57, update Linux firmware\n* [`0b67a13`](https://github.com/siderolabs/pkgs/commit/0b67a133b12c548ba6d28f2ea0c979cb10512812) feat: bump dependencies\n* [`dd5f928`](https://github.com/siderolabs/pkgs/commit/dd5f928266761215fc402085594493c9f9b329b4) feat: update Linux 6.6.56 and protect /proc/mem\n* [`b1bf972`](https://github.com/siderolabs/pkgs/commit/b1bf9725068029f34193b3abe1586a3d1f542b17) feat: enable CONFIG_XFRM_STATISTICS\n* [`c63beae`](https://github.com/siderolabs/pkgs/commit/c63beae426026c8ef1b3228b8d978ca5fcc9111b) feat: update Linux to 6.6.54\n* [`f474a55`](https://github.com/siderolabs/pkgs/commit/f474a55176dca7ab88b5a29f8d97ce6f31282abd) fix: libselinux: support running without /etc/selinux\n* [`ba0341e`](https://github.com/siderolabs/pkgs/commit/ba0341e39dafb3fe39b5efbc8a8e8d04df96a0e7) fix: systemd-udevd: search for config in /usr/etc\n* [`2b193f1`](https://github.com/siderolabs/pkgs/commit/2b193f14e035fa7d7785f26a591debe6ac357f00) feat: add lpfc kernel module\n* [`1adb946`](https://github.com/siderolabs/pkgs/commit/1adb946b1bb256b30b7bddd517a10d68ce209ada) feat: enable QEDF driver\n* [`dbbe3d0`](https://github.com/siderolabs/pkgs/commit/dbbe3d0116b24b9d1c2df19ae73b76714a37704e) feat: update containerd to v2.0.0-rc.5\n* [`f19590e`](https://github.com/siderolabs/pkgs/commit/f19590edb42a0247d5d509066b21ce35bfc42b93) feat: update Go to 1.23.2\n* [`e2a561f`](https://github.com/siderolabs/pkgs/commit/e2a561f576ea7dbc55ebb403d648daa1561c3101) fix: drop the LVM2 udev lvm rule\n* [`ae205aa`](https://github.com/siderolabs/pkgs/commit/ae205aac9d827783352071f9447f9f7cbf70da20) fix: force LVM to use `/run` as state directory\n* [`232a153`](https://github.com/siderolabs/pkgs/commit/232a15318a2d47f34b0772663fc3f417905b5406) feat: replace eudev with systemd-udevd\n* [`40fb82a`](https://github.com/siderolabs/pkgs/commit/40fb82a27a840f3442d6f52374007afb0a5a3770) feat: add libselinux, libsepol, pcre2 and libcap\n* [`6f40fbb`](https://github.com/siderolabs/pkgs/commit/6f40fbb5e00e449c954d54990085353d061a62c8) feat: update xfsprogs 6.10.1\n* [`a1709c7`](https://github.com/siderolabs/pkgs/commit/a1709c76db4ba70de526d7eec18c6b0637ebf7b0) feat: enable module unloading and memory hotplug (for NVIDIA UVM)\n* [`2c5785b`](https://github.com/siderolabs/pkgs/commit/2c5785b1639a22317a1f7775f0d1f4bd0b0a4b88) feat: enable transparent huge pages in madvise mode\n* [`ca2e8c8`](https://github.com/siderolabs/pkgs/commit/ca2e8c84b0881e7d1e359ceaf3b55c3b4bb384e7) fix: lvm2 modprobe path\n* [`6b334a6`](https://github.com/siderolabs/pkgs/commit/6b334a68fbd988ca69d05142a639aa3bcfd16721) feat: update Linux to 6.6.52\n* [`e90ae7e`](https://github.com/siderolabs/pkgs/commit/e90ae7ec316f1b9b4d15897f825d3c2c4cefde5e) feat: update Linux firmware to 20240909\n* [`79a4f92`](https://github.com/siderolabs/pkgs/commit/79a4f92c5aa4b8288a927351209542c274724475) feat: enable INET_DIAG\n* [`c9f7eb9`](https://github.com/siderolabs/pkgs/commit/c9f7eb94de2a8df5cfc41c6ea90596832894dc89) feat: update Linux to 6.6.51\n* [`126b6a4`](https://github.com/siderolabs/pkgs/commit/126b6a4f7632b2400139e306a0dbb0a545a0dda1) fix: add mpt3sas UBSAN patches\n* [`a09bf93`](https://github.com/siderolabs/pkgs/commit/a09bf93ce81bde59fcb06d662bc79effc9efaca6) chore: drop UBSAN patch\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>3 commits</summary>\n<p>\n\n* [`0d84c65`](https://github.com/siderolabs/proto-codec/commit/0d84c652784543012f43f8c8d4358c160b27577e) chore: add support for gogo protobuf generator\n* [`19f8d2e`](https://github.com/siderolabs/proto-codec/commit/19f8d2e5840c19937c60cee0c681343ab658f678) chore: add kres\n* [`e038bb4`](https://github.com/siderolabs/proto-codec/commit/e038bb42f2be8b80ca09e46bb8704be06a413919) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`1893385`](https://github.com/siderolabs/siderolink/commit/1893385fe45bf110357a770d31b06f5d79403065) fix: initialize tls listener properly\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>8 commits</summary>\n<p>\n\n* [`3750064`](https://github.com/siderolabs/tools/commit/375006431abb204c275adab2fdc9128060bb32f7) fix: update for musl with close_range\n* [`0a443c6`](https://github.com/siderolabs/tools/commit/0a443c6d5a1ac6764b22990be0945ef4cae8c32e) feat: update toolchain for gcc 14.2\n* [`63ecd80`](https://github.com/siderolabs/tools/commit/63ecd80a4709bcde5c6cc0f112c1faf43ab024ce) feat: bump depedendencies\n* [`2058296`](https://github.com/siderolabs/tools/commit/2058296cc223b683685f229a9a52de4db7171595) feat: bump dependencies\n* [`1151610`](https://github.com/siderolabs/tools/commit/1151610f5a5e70d07b715a2bdd76acd06d418595) feat: update Go to 1.23.2\n* [`9f2189b`](https://github.com/siderolabs/tools/commit/9f2189b2b032ed283f38b20c53018b921fa06895) fix: bump gettext-tiny to the latest dev version\n* [`95069d6`](https://github.com/siderolabs/tools/commit/95069d6fd8fccde7ab93465e4e49a5a6ac5d4ed0) feat: update Go to 1.23.1\n* [`eec0656`](https://github.com/siderolabs/tools/commit/eec0656aca652d0cc2e1973d5fab56bd4b54f64b) feat: replace gettext with gettext-tiny\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.5.0 -> v0.5.2\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.13.0 -> v1.16.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.7.0 -> v1.8.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.1.0 -> v1.2.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.1.0 -> v1.2.0\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.27.33 -> v1.28.1\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.13 -> v1.16.18\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.35.7 -> v1.37.3\n* **github.com/aws/smithy-go**                                                v1.20.4 -> v1.22.0\n* **github.com/containerd/containerd/api**                                    v1.8.0-rc.3 -> v1.8.0\n* **github.com/containerd/containerd/v2**                                     v2.0.0-rc.4 -> v2.0.0\n* **github.com/containerd/errdefs**                                           v0.1.0 -> v1.0.0\n* **github.com/containerd/platforms**                                         v0.2.1 -> v1.0.0-rc.0\n* **github.com/containerd/typeurl/v2**                                        v2.2.0 -> v2.2.2\n* **github.com/containernetworking/plugins**                                  v1.5.1 -> v1.6.0\n* **github.com/cosi-project/runtime**                                         v0.5.5 -> v0.7.1\n* **github.com/docker/cli**                                                   v27.3.1 **_new_**\n* **github.com/docker/docker**                                                v27.2.0 -> v27.3.1\n* **github.com/elastic/go-libaudit/v2**                                       1df86e79cca7 **_new_**\n* **github.com/fatih/color**                                                  v1.17.0 -> v1.18.0\n* **github.com/florianl/go-tc**                                               v0.4.4 **_new_**\n* **github.com/foxboron/go-uefi**                                             e2076f0e58ca -> fab4fdf2f2f3\n* **github.com/fsnotify/fsnotify**                                            v1.7.0 -> v1.8.0\n* **github.com/google/cadvisor**                                              v0.50.0 -> v0.51.0\n* **github.com/gopacket/gopacket**                                            v1.2.0 -> v1.3.0\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.13.1 -> v2.15.0\n* **github.com/klauspost/compress**                                           v1.17.9 -> v1.17.11\n* **github.com/linode/go-metadata**                                           v0.2.0 -> v0.2.1\n* **github.com/mdlayher/ethtool**                                             v0.1.0 -> v0.2.0\n* **github.com/opencontainers/runc**                                          v1.2.0-rc.3 -> v1.2.1\n* **github.com/rivo/tview**                                                   fd649dbf1223 -> c76f7879f592\n* **github.com/siderolabs/crypto**                                            v0.4.4 -> v0.5.0\n* **github.com/siderolabs/discovery-api**                                     v0.1.4 -> v0.1.5\n* **github.com/siderolabs/discovery-client**                                  v0.1.9 -> v0.1.10\n* **github.com/siderolabs/extras**                                            v1.8.0 -> v1.9.0-alpha.0-1-geab6e58\n* **github.com/siderolabs/gen**                                               v0.5.0 -> v0.7.0\n* **github.com/siderolabs/go-blockdevice**                                    v0.4.7 -> v0.4.8\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.2 -> v2.0.3\n* **github.com/siderolabs/go-circular**                                       v0.2.0 -> v0.2.1\n* **github.com/siderolabs/go-cmd**                                            v0.1.1 -> v0.1.3\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.12 -> v0.2.15\n* **github.com/siderolabs/grpc-proxy**                                        v0.4.1 -> v0.5.1\n* **github.com/siderolabs/pkgs**                                              v1.8.0-8-gdf1a1a5 -> v1.9.0-alpha.0-37-g4699763\n* **github.com/siderolabs/proto-codec**                                       v0.1.1 **_new_**\n* **github.com/siderolabs/siderolink**                                        v0.3.10 -> v0.3.11\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.8.0 -> v1.9.0-alpha.1\n* **github.com/siderolabs/tools**                                             v1.8.0-1-ga0c06c6 -> v1.9.0-alpha.0-7-g3750064\n* **golang.org/x/net**                                                        v0.29.0 -> v0.30.0\n* **golang.org/x/sys**                                                        v0.25.0 -> v0.26.0\n* **golang.org/x/term**                                                       v0.24.0 -> v0.25.0\n* **golang.org/x/text**                                                       v0.18.0 -> v0.19.0\n* **golang.org/x/time**                                                       v0.6.0 -> v0.7.0\n* **google.golang.org/grpc**                                                  v1.66.0 -> v1.67.1\n* **google.golang.org/protobuf**                                              v1.34.2 -> v1.35.1\n* **k8s.io/api**                                                              v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apimachinery**                                                     v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apiserver**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/client-go**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/component-base**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/cri-api**                                                          v0.32.0-alpha.0 -> v0.32.0-beta.0\n* **k8s.io/kube-scheduler**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubectl**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubelet**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/pod-security-admission**                                           v0.31.1 -> v0.32.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**                           v1.2.70 -> v1.2.71\n\nPrevious release can be found at [v1.8.0](https://github.com/siderolabs/talos/releases/tag/v1.8.0)\n\n## [Talos 1.9.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.9.0-alpha.1) (2024-11-08)\n\nWelcome to the v1.9.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### AppArmor\n\nTalos Linux starting with v1.9 will ship with SELinux LSM enabled by default.\nIf you need to use AppArmor LSM add the following to the machine configuration:\n\n```yaml\nmachine:\n  install:\n     extraKernelArgs:\n      - -selinux\n      - lsm=lockdown,capability,yama,apparmor,bpf\n      - apparmor=1\n```\n\n\n### Auditd\n\nTalos Linux now starts a auditd service by default.\nLogs can be read with `talosctl logs auditd`.\n\n\n### `talosctl cgroups`\n\nThe `talosctl cgroups` command has been added to the `talosctl` tool.\nThis command allows you to view the cgroup resource consumption and limits for a machine, e.g.\n`talosctl cgroups --preset memory`.\n\n\n### udevd\n\nTalos previously used `udevd` to provide `udevd`, now it uses `systemd-udevd` instead.\n\n\n### Component Updates\n\nLinux: 6.6.59\ncontainerd: 2.0.0\nFlannel: 0.26.0\nKubernetes: 1.32.0-beta.0\nrunc: 1.2.1\n\nTalos is built with Go 1.23.2.\n\n\n### User Namespaces\n\nTalos Linux now supports running Kubernetes pods with user namespaces enabled.\nRefer to the [documentation](https://www.talos.dev/v1.9/kubernetes-guides/configuration/usernamespace/) for more information.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Dmitry Sharshakov\n* Joakim Nohlgård\n* Jean-Francois Roy\n* Utku Ozdemir\n* blablu\n* Adolfo Ochagavía\n* Dan Rue\n* David Backeus\n* Eddie Wang\n* Florian Ströger\n* Hexoplon\n* Jakob Maležič\n* KBAegis\n* Mike Beaumont\n* Nebula\n* Nico Berlee\n* Philip Schmid\n* Philipp Kleber\n* Remko Molier\n* Robby Ciliberto\n* Ryan Borstelmann\n* Serge Logvinov\n* Spencer Smith\n* Steven Cassamajor\n* Tim Jones\n* adilTepe\n* ekarlso\n* naed3r\n* nevermarine\n* solidDoWant\n\n### Changes\n<details><summary>140 commits</summary>\n<p>\n\n* [`fb72e4b7b7`](https://github.com/siderolabs/talos/commit/fb72e4b7b74979acf743d20c7c099bc5513836e0) fix(ci): skip test if `UserNamespacesSupport` feature gate is not set\n* [`11380f933d`](https://github.com/siderolabs/talos/commit/11380f933ddd3fe42dc01d5ed09ceff0d62b417d) feat: display current CPU frequency on dashboard\n* [`fbce267aee`](https://github.com/siderolabs/talos/commit/fbce267aee98e3b4b6acace156aa22d75ad01d3d) feat: check bridged interfaces should not have addresses\n* [`942962bf00`](https://github.com/siderolabs/talos/commit/942962bf005a7036e04f4e572f3434f476cb567c) docs: add docs on usernamespace support in k8s\n* [`0406a05a98`](https://github.com/siderolabs/talos/commit/0406a05a986fabc3834c5a0de48362826268edbe) chore: update pkgs to ones built with gcc 14.2\n* [`2e127627dc`](https://github.com/siderolabs/talos/commit/2e127627dce7251d5848718036780c91384c4396) docs: add apparmor enablement release notes\n* [`aa9311f3d8`](https://github.com/siderolabs/talos/commit/aa9311f3d840c7b5a69a1eb6ab4cb3b1a7bff135) fix: install disk matcher error\n* [`1800f81044`](https://github.com/siderolabs/talos/commit/1800f8104486f01e8a3437432e508893f02f809c) fix: selinux handling and apparmor tests\n* [`313bffadfb`](https://github.com/siderolabs/talos/commit/313bffadfb66b053f51046300764e94db088b18a) feat: update Kubernetes to v1.32.0-beta.0\n* [`bbfa144510`](https://github.com/siderolabs/talos/commit/bbfa144510063fdcdebbc017b4fb382ac839370c) feat: update containerd to v2.0.0\n* [`8e02b9fcbf`](https://github.com/siderolabs/talos/commit/8e02b9fcbfba421abd13ffe4fc8ea3892d4673eb) docs: update manual k8s upgrade docs\n* [`474949dc77`](https://github.com/siderolabs/talos/commit/474949dc77363123f0e8cf2c918ecacb82b4dbdd) feat: add dm-cache dm-cache-smq kernel modules\n* [`5112547d6b`](https://github.com/siderolabs/talos/commit/5112547d6b12b4ff40e7863f363cf519efb8c76c) chore: generate support zip for crashdump\n* [`a867f85e4c`](https://github.com/siderolabs/talos/commit/a867f85e4cb662a17b0738f1f0de4f1485ad925a) feat: label system socket and runtime files\n* [`398f714cff`](https://github.com/siderolabs/talos/commit/398f714cff04c524394933da17cbc21ad239cd42) feat: update Linux 6.6.59, runc 1.2.1\n* [`05c620957c`](https://github.com/siderolabs/talos/commit/05c620957ca741451da395036e8eca59e631fe8d) feat: allow extra mounts for docker-based `talosctl cluster create`\n* [`cedabeddf7`](https://github.com/siderolabs/talos/commit/cedabeddf7d191f39525a61e65164f280b6807f8) chore: cleanup code\n* [`61d363e1d0`](https://github.com/siderolabs/talos/commit/61d363e1d093047886638d5bc5b9f2181c8bd894) chore: update go-auditlib\n* [`960a040491`](https://github.com/siderolabs/talos/commit/960a040491de5c95b104b4a39ea519095eb47931) feat: start enabling SELinux\n* [`7f3aaa21cd`](https://github.com/siderolabs/talos/commit/7f3aaa21cd8d969e26721235a4191ba3bdbc1f8f) fix: update permissions for logging directories in /var\n* [`0e6c983b84`](https://github.com/siderolabs/talos/commit/0e6c983b847f679a074c1794fbe77d21a5994233) fix: mount /sys/kernel/security conditionally\n* [`74b0e8c371`](https://github.com/siderolabs/talos/commit/74b0e8c3713a01f83758556672583880ce5c684a) fix: make route normalization keep family\n* [`0a3761c22f`](https://github.com/siderolabs/talos/commit/0a3761c22f98783c6696f143611d600287a471a3) fix: talosctl windows arm64\n* [`4b10c5328b`](https://github.com/siderolabs/talos/commit/4b10c5328b861b4bcdcec3ca21bd55b91e969b44) chore: add Windows ARM64 build for talosctl\n* [`9abf16108e`](https://github.com/siderolabs/talos/commit/9abf16108ede75984845297d03673d56cb561c2f) feat: add auditd service\n* [`d464ca869f`](https://github.com/siderolabs/talos/commit/d464ca869f8949ffbb990c6fb02fbbcbe0abcbe1) chore: drop runc memfd bind added in #9069\n* [`b54d26c2c3`](https://github.com/siderolabs/talos/commit/b54d26c2c3f3a52c6d1ec3fddb7a373175815de3) fix: mount pseudo sub-mountpoints in init\n* [`7aeb15f730`](https://github.com/siderolabs/talos/commit/7aeb15f73094a23aea1d6b263ca2eca061c8a257) chore: disable coredns cache for cluster domain\n* [`d8b652150c`](https://github.com/siderolabs/talos/commit/d8b652150cec408f2bf3307565b9db691b21bfe9) docs: add warning about NVMe bus path bug\n* [`3e16ab135e`](https://github.com/siderolabs/talos/commit/3e16ab135e2be8c9b652d67f9e7eadbc3691c5ca) feat: update Kubernetes to v1.32.0-alpha.3\n* [`0b8b356777`](https://github.com/siderolabs/talos/commit/0b8b3567771fbe796926dc9a6e904e7102535170) feat: add BridgePort property to network machine configuration\n* [`b379506259`](https://github.com/siderolabs/talos/commit/b3795062596ef45dd309f1ca56aab31d2a1a0efc) fix: use more correct condition to skip generating hosts files\n* [`62ec7ec336`](https://github.com/siderolabs/talos/commit/62ec7ec3367233823c09befddc5ad312aa607822) refactor: replace the old v1 mount package with new one\n* [`0ece13c623`](https://github.com/siderolabs/talos/commit/0ece13c6236c7eda474d3734fcc4c4060299ac43) docs: update network-config.md (cont)\n* [`93827f0485`](https://github.com/siderolabs/talos/commit/93827f0485a92b46da83b80a2a55f2569f70fe57) docs: update network-config.md\n* [`423b1e5fb2`](https://github.com/siderolabs/talos/commit/423b1e5fb22d9e785a3832741d796120b84a5e38) fix: do not trim 0 from process SELinux label\n* [`2136358d65`](https://github.com/siderolabs/talos/commit/2136358d65ddf6ad040ed62c835b335f99a59399) feat: introduce metal agent mode\n* [`0e15955fcc`](https://github.com/siderolabs/talos/commit/0e15955fcc5d464c5f0ffd1a44eebf4bf32f4844) chore: small refactoring\n* [`66012a7f26`](https://github.com/siderolabs/talos/commit/66012a7f269010c5ed412d139b14c470063f2429) feat: remove wrapperd and launch processes directly\n* [`3a0a17ae66`](https://github.com/siderolabs/talos/commit/3a0a17ae66dab5c983571fab0f3eac3f87fbc17c) fix: prevent panic in nocloud platform code\n* [`dc0c6acbd7`](https://github.com/siderolabs/talos/commit/dc0c6acbd765b6e7838d6af4f1903242d5073782) refactor: remove unmaintained github.com/vishvananda/netlink\n* [`78353f7918`](https://github.com/siderolabs/talos/commit/78353f79188e81d064c354f6ef3fe3b2e023c644) feat: add parsing of vlanNNNN:ethX style VLAN cmdline args\n* [`9db7a36bfc`](https://github.com/siderolabs/talos/commit/9db7a36bfc45c9c15fd661fb2a6319dcf4fef210) fix: generation of SecureBoot iso\n* [`c755b6d7e4`](https://github.com/siderolabs/talos/commit/c755b6d7e4600fdfb32be50422b7efb0fdabef63) fix: update the CRI sandbox image reference\n* [`cec290b354`](https://github.com/siderolabs/talos/commit/cec290b354773b2b0f2c2ae9d57f36e06fe2654d) feat: allow extensions to log to console\n* [`b7801df827`](https://github.com/siderolabs/talos/commit/b7801df827d8e1e9a2db7dac0a62c3802de4d73c) fix: wait for udevd to be running before activating LVM\n* [`d4cb478a50`](https://github.com/siderolabs/talos/commit/d4cb478a50ce41c3699b7846388e537ddf18a703) docs: improve field description for BridgeSTP, BridgeVLAN\n* [`7329824b24`](https://github.com/siderolabs/talos/commit/7329824b2411fef3b23fd90380033441048f6512) docs: add Mynewsdesk to ADOPTERS.md\n* [`a13cf76a34`](https://github.com/siderolabs/talos/commit/a13cf76a3415f458ff3235981c1be8202e1800bb) chore: simplify `DNSUpstreamController` and `DNSUpstream` resource\n* [`62d185473e`](https://github.com/siderolabs/talos/commit/62d185473e258c0c34eff5aed4c18d81d4b92a89) fix: talosctl process null character\n* [`77d7368eae`](https://github.com/siderolabs/talos/commit/77d7368eae2da6d2c9aa896afc8013007909a958) feat: update containerd to v2.0.0-rc.6\n* [`d39393879a`](https://github.com/siderolabs/talos/commit/d39393879a1f98ac3de7a96808301d1e07fd95f3) fix: rework the 'metal-iso' config acquisition\n* [`1993afca9f`](https://github.com/siderolabs/talos/commit/1993afca9fff7e889b497ec3241cfdca42294f18) chore: create /usr/etc in a different step\n* [`8680351c13`](https://github.com/siderolabs/talos/commit/8680351c131d29a76682569742dbd44c8ffe47d3) chore: move system extensions' udev rules\n* [`3067f64c84`](https://github.com/siderolabs/talos/commit/3067f64c8435ef2d5453100a1584dc3c6915ba0b) feat: update Flannel to v0.26.0\n* [`8658d6865f`](https://github.com/siderolabs/talos/commit/8658d6865fa0bcbfcebe483b7332d3b56e239979) docs: typo in deploying cilium\n* [`49bbadc4bf`](https://github.com/siderolabs/talos/commit/49bbadc4bf1e79e48c057d473ae21426b273c588) docs: add documentation on performance tuning\n* [`534b0ce183`](https://github.com/siderolabs/talos/commit/534b0ce1833462b22f3761258e0e95813a355fb2) feat: update runc to 1.2.0 final\n* [`2172535237`](https://github.com/siderolabs/talos/commit/21725352373da7835d95f8f934847dab404782f8) docs: fix image factory links\n* [`375e3da73f`](https://github.com/siderolabs/talos/commit/375e3da73fcb02c7caea2576289fefdc395a1ed2) feat: update Kubernetes to 1.32.0-alpha.2\n* [`9e6f64df04`](https://github.com/siderolabs/talos/commit/9e6f64df047527ecb42df5fdf5fd2f9767d21437) fix: improve error messages for invalid bridge/bond configuration\n* [`7c8c72c2b2`](https://github.com/siderolabs/talos/commit/7c8c72c2b2a4edb412e097a9e013ab21727339cf) fix: correct error message for invalid ip=\n* [`ead46997c9`](https://github.com/siderolabs/talos/commit/ead46997c918ab1139ca12e87beefbbda29614e1) chore: rename tpm2.PCRExtent -> tpm2.PCRExtend\n* [`867c4b8125`](https://github.com/siderolabs/talos/commit/867c4b8125ee738f9a82e5e87809eb95bdd2f778) docs: fix typo in prodnotes.md\n* [`1b22df48a4`](https://github.com/siderolabs/talos/commit/1b22df48a41578d19fb512bd8111a481b64011e2) chore: support debug shell for advanced development\n* [`c14b446229`](https://github.com/siderolabs/talos/commit/c14b4462292bd7e6088fce35d6880a9b2b56335c) feat: update Kubernetes to v1.32.0-alpha.1\n* [`29780d35a0`](https://github.com/siderolabs/talos/commit/29780d35a052134d50576f6506c2728489a30506) test: add an integration test for verifying process parameters\n* [`3d342af447`](https://github.com/siderolabs/talos/commit/3d342af4479ed12e2af10021ec4e7ab9c2af6d75) fix: update incorrect alias for PCIDevice resource\n* [`f7d35a5e0b`](https://github.com/siderolabs/talos/commit/f7d35a5e0b4e3a04a639d663e5a580e22fea76db) release(v1.9.0-alpha.0): prepare release\n* [`e0434d77d7`](https://github.com/siderolabs/talos/commit/e0434d77d754f8834ba903f4c09b08634cfd3934) feat: update dependencies\n* [`5c5a248861`](https://github.com/siderolabs/talos/commit/5c5a248861c8e5848f9a23cd0cd7b3b749f21e4b) feat: add Talos 1.9 compatibility guarantees\n* [`bc4c21f41a`](https://github.com/siderolabs/talos/commit/bc4c21f41a0066ba6cefb5b753c52d76a6b0f629) test: add json logs test environment\n* [`71faa32942`](https://github.com/siderolabs/talos/commit/71faa3294246947f6bd212979ceb31e793ae0604) docs: nvidia proprietary/oss hardware requirement\n* [`59a78da42c`](https://github.com/siderolabs/talos/commit/59a78da42cdea8fbccc35d0851f9b0eef928261b) chore: add proto-codec/codec\n* [`7ff1cedfe3`](https://github.com/siderolabs/talos/commit/7ff1cedfe3eee51505c30439eec4a2df9b452b2e) chore: update siderolabs/crypto module and return proper ALPN\n* [`ccbd5aed39`](https://github.com/siderolabs/talos/commit/ccbd5aed39b360664d1f80c8b146050e9df9ff7b) feat: optionally decode hcloud userdata as base64\n* [`34f652ce82`](https://github.com/siderolabs/talos/commit/34f652ce822fcb70a292289fe6ba5d1bd7a34f97) feat: add well-known app.kubernetes.io labels to control-plane pods\n* [`fc89dc2164`](https://github.com/siderolabs/talos/commit/fc89dc21643a923cb7d0d3944405521bf849631b) fix: support `extra-disks` when using iso\n* [`f2bff814de`](https://github.com/siderolabs/talos/commit/f2bff814de0b237fbed419234b935dc9f9637554) chore: add arm64 target for integration-test\n* [`5853bb0ea4`](https://github.com/siderolabs/talos/commit/5853bb0ea4d6a65635086bdef617d6d0800cabd0) fix: json logging panic\n* [`a859cff364`](https://github.com/siderolabs/talos/commit/a859cff364aa4dc9b4b880417b821f7ecf5602ac) chore: use virtio driver for disks in arm64\n* [`db248de88d`](https://github.com/siderolabs/talos/commit/db248de88dec2467e4340f699cde98217979ba4b) chore(ci): add config for lldpd extension\n* [`9f0de9f43d`](https://github.com/siderolabs/talos/commit/9f0de9f43dc4467f0bdeda117b4946ae12db50ab) test: update provision upgrade tests for Talos 1.9\n* [`39fe285e69`](https://github.com/siderolabs/talos/commit/39fe285e69691059f91d8c7c5506e156356263d9) fix: skip ram disks\n* [`a9bff3a1d0`](https://github.com/siderolabs/talos/commit/a9bff3a1d084c32a654555e71e2592e60edbdcb6) test: skip no error test in Cilium\n* [`4d902021bb`](https://github.com/siderolabs/talos/commit/4d902021bb3c55bc212cbb3e2443b6552400622f) fix: do not use pflag csv comma reader for config-patch\n* [`5371788ce1`](https://github.com/siderolabs/talos/commit/5371788ce169a0381e08f0d902ac81f3f89ba5bd) fix: typo in documentation\n* [`8a228ba6bc`](https://github.com/siderolabs/talos/commit/8a228ba6bc702f21fca06dc2ecb3e8e846839cd3) docs: add egress documentation\n* [`182325cb07`](https://github.com/siderolabs/talos/commit/182325cb0791da1d4dcd3914a643c44232502524) test: skip lvm test if not enough user disks available\n* [`519a48302e`](https://github.com/siderolabs/talos/commit/519a48302e771fd9b331913166d55c50fff4961a) fix: wipe system partitions correctly via kernel args\n* [`0a2b4556c5`](https://github.com/siderolabs/talos/commit/0a2b4556c55eda27536ee563f60bcf5d69379479) fix: volume encryption with failing keyslots\n* [`6affbd3182`](https://github.com/siderolabs/talos/commit/6affbd3182ebe0209ed5433c534062b7ad672b6a) fix: update grpc-go the latest patch release\n* [`77a4a4adc7`](https://github.com/siderolabs/talos/commit/77a4a4adc7232b4382f2a530f4056a1fff6c50b4) fix: scaleway metadata\n* [`7acadc0c8f`](https://github.com/siderolabs/talos/commit/7acadc0c8fa969e4de7f0d4f68b0fd0cd833b489) fix: do not stop udevd before unmounting volumes\n* [`6a081055b0`](https://github.com/siderolabs/talos/commit/6a081055b0dd4e3ce5c40392c8415a0a55b2591c) feat: update Flannel to v0.25.7\n* [`2362f6d3ee`](https://github.com/siderolabs/talos/commit/2362f6d3ee51a0a8b541a872d39ac82892502e17) fix: improve container detection\n* [`b67bc73fd3`](https://github.com/siderolabs/talos/commit/b67bc73fd30a8e07f26c47a746ca53f2af41d366) fix: fix mdadm system extension\n* [`f08669c7a9`](https://github.com/siderolabs/talos/commit/f08669c7a9583a559dc53f233798305bbab07b8a) feat: bring in lpfc kernel module driver\n* [`6a014374be`](https://github.com/siderolabs/talos/commit/6a014374be26f0caf8faa90a34f2476e0e77a46a) feat: enable QEDF driver\n* [`f711907e03`](https://github.com/siderolabs/talos/commit/f711907e038cea20f6b831ea5ad8c3b18638c1b4) fix: make /var/run empty on reboots\n* [`7d02eb60f4`](https://github.com/siderolabs/talos/commit/7d02eb60f47652f4b72f170b28a8b964729af013) docs: fix typo in CloudStack docs\n* [`74861573a7`](https://github.com/siderolabs/talos/commit/74861573a793f9e143d7d2638990f37ec639aa88) fix: multiple fixes for LVM activation\n* [`74c12c20e0`](https://github.com/siderolabs/talos/commit/74c12c20e02e4ec29b2b374cebc996ddf8fa90c7) feat: replace eudev with systemd-udevd\n* [`0a4df4ef84`](https://github.com/siderolabs/talos/commit/0a4df4ef84467014d5be4b4ec57de0e778cfb21e) docs: fix nvidia CRI config example\n* [`afc1e1a46a`](https://github.com/siderolabs/talos/commit/afc1e1a46a559aac3aa5f4a2708ba8d2c9228929) docs: fix typo in extraMounts directory\n* [`a341bdb064`](https://github.com/siderolabs/talos/commit/a341bdb0640294a07939670919c56cbfa7a861c4) fix: prevent file descriptors leaks to child processes\n* [`dec653bfe1`](https://github.com/siderolabs/talos/commit/dec653bfe1feb84ea2ed1a779b1bfc783dc61160) chore: better lvm2 tests\n* [`908fd8789c`](https://github.com/siderolabs/talos/commit/908fd8789cc1b22e556a7ffe307409931976ba08) feat: support cgroup deep analysis in `talosctl`\n* [`aa846cc186`](https://github.com/siderolabs/talos/commit/aa846cc186c1c6125f8f39ea084fa2023512656f) feat: add support for CI Network config in nocloud\n* [`10f2539f23`](https://github.com/siderolabs/talos/commit/10f2539f237aeb3af2caeb3c349c062f203219b6) chore: disable cloud-images cron workflow\n* [`b07a8b36b2`](https://github.com/siderolabs/talos/commit/b07a8b36b24d57337323e72d6032304c4cade927) chore: ignore more plugins for system containerd\n* [`392c4798f0`](https://github.com/siderolabs/talos/commit/392c4798f0bff7cb4518609deae7c90581f013f5) feat: prepare for Talos 1.9\n* [`ea7bf9fb43`](https://github.com/siderolabs/talos/commit/ea7bf9fb43dff8cf8ec4dfd4f629e8f826bc2ded) docs: update storage.md\n* [`4ab8dee69a`](https://github.com/siderolabs/talos/commit/4ab8dee69ac07c811cbe121ca9e2d9bd01148863) fix: build talosctl without `tcell_minimal`\n* [`2fa019bd97`](https://github.com/siderolabs/talos/commit/2fa019bd9751ad96085ade52628023adf17658d3) docs: enable 'edit on GitHub' link\n* [`d2ccbc2b15`](https://github.com/siderolabs/talos/commit/d2ccbc2b1512b6323d48a764c4af534d49b4bd27) docs: update hetzner documentation for CCM\n* [`d498f647cd`](https://github.com/siderolabs/talos/commit/d498f647cd9dfcd575f51005c9b78c2c1c7b51ca) docs: fix Kernel Self Protection Project (KSPP) references\n* [`0ec75463ee`](https://github.com/siderolabs/talos/commit/0ec75463eecebfb543a64b0c859ba0b2477e406f) docs: make Talos 1.8 current release\n* [`9b77698cf2`](https://github.com/siderolabs/talos/commit/9b77698cf2ff64c6f6d198d05c2012ab7fa858be) fix: update blockdevice library to v2.0.2\n* [`e46227ab95`](https://github.com/siderolabs/talos/commit/e46227ab95a6d06132e82315f55b5ced533ddabb) docs: fix kubespan name inconsistency\n* [`6b15ca19cd`](https://github.com/siderolabs/talos/commit/6b15ca19cd1291b8a245d72d5153827945cad037) fix: audit and fix cgroup reservations\n* [`32b5d01ed3`](https://github.com/siderolabs/talos/commit/32b5d01ed3396e8f54a245cc6d9818119aec8291) chore: bump lvm2\n* [`6484581eb8`](https://github.com/siderolabs/talos/commit/6484581eb888996a8dc829915439fb63606dd794) feat: allow /sbin/ldconfig in extensions\n* [`9fa08e8437`](https://github.com/siderolabs/talos/commit/9fa08e843728dbd85ed7e0035f59cdd6232de9a9) chore: refactor tests\n* [`d8ab4981b6`](https://github.com/siderolabs/talos/commit/d8ab4981b626ff41fbcdb526a032a5584519e3df) feat: support lvm auto activation\n* [`8166a58b36`](https://github.com/siderolabs/talos/commit/8166a58b364f760212b2a610ce0d764b8b4c5c46) fix: filter out non-printable characters in process line\n* [`806b6aaf52`](https://github.com/siderolabs/talos/commit/806b6aaf52f20ed0f32107b3d0372d6e3ff974be) docs: add SECURITY.md\n* [`7bd26df308`](https://github.com/siderolabs/talos/commit/7bd26df30803307e4eece3e382aafebc55e7b260) docs: document `/dev/net/tun` compatibility\n* [`18daedb511`](https://github.com/siderolabs/talos/commit/18daedb511e769717ba56eb05cccab72118a4813) fix: strategic merge patch delete for map keys\n* [`f3370529ac`](https://github.com/siderolabs/talos/commit/f3370529ac042865a4b2d793465916fcae2d4b33) docs: correct typo\n* [`8d6884a8e2`](https://github.com/siderolabs/talos/commit/8d6884a8e28e1bfa29f9a479e0f7179819cf70cd) test: add a test for inline machine config trusted roots\n* [`d4a6d017db`](https://github.com/siderolabs/talos/commit/d4a6d017dbb91e22c60787cdf64b242057b1ebef) fix: ignore invalid NTP responses\n* [`869f8379f2`](https://github.com/siderolabs/talos/commit/869f8379f2317175901e8cb3deec4b800e7ab603) feat: update default Kubernetes version to 1.31.1\n* [`780a1f198a`](https://github.com/siderolabs/talos/commit/780a1f198a5eedd33a27060bdf116bd3a3b26426) fix: update CoreDNS health check\n* [`79cd031588`](https://github.com/siderolabs/talos/commit/79cd031588a0710b865414f919742ee3ffb998ed) chore: account for resource sorting in dns upstream resource\n* [`e17fafaca2`](https://github.com/siderolabs/talos/commit/e17fafaca2a16990bc424b54120c49ddbaf8cee1) chore: drop `activateLogicalVolumes` sequencer step\n* [`a294b366f2`](https://github.com/siderolabs/talos/commit/a294b366f24c6580d304c6c8ad34f481079dc795) fix: parse SideroLink API endpoint correctly\n* [`a9269ac7b1`](https://github.com/siderolabs/talos/commit/a9269ac7b1217aa2d247c0215c5f2755af468b44) fix: remove extra logging on ethtool ioctl failures\n* [`5c6277d171`](https://github.com/siderolabs/talos/commit/5c6277d171eea58878ce4fcb4d2fdb7154333ae7) feat: update etcd to 3.5.16\n* [`c1ed2984b8`](https://github.com/siderolabs/talos/commit/c1ed2984b85dca791a5081c5da26bba75e3cd579) docs: add what's new for Talos 1.8\n</p>\n</details>\n\n### Changes since v1.9.0-alpha.0\n<details><summary>68 commits</summary>\n<p>\n\n* [`fb72e4b7b`](https://github.com/siderolabs/talos/commit/fb72e4b7b74979acf743d20c7c099bc5513836e0) fix(ci): skip test if `UserNamespacesSupport` feature gate is not set\n* [`11380f933`](https://github.com/siderolabs/talos/commit/11380f933ddd3fe42dc01d5ed09ceff0d62b417d) feat: display current CPU frequency on dashboard\n* [`fbce267ae`](https://github.com/siderolabs/talos/commit/fbce267aee98e3b4b6acace156aa22d75ad01d3d) feat: check bridged interfaces should not have addresses\n* [`942962bf0`](https://github.com/siderolabs/talos/commit/942962bf005a7036e04f4e572f3434f476cb567c) docs: add docs on usernamespace support in k8s\n* [`0406a05a9`](https://github.com/siderolabs/talos/commit/0406a05a986fabc3834c5a0de48362826268edbe) chore: update pkgs to ones built with gcc 14.2\n* [`2e127627d`](https://github.com/siderolabs/talos/commit/2e127627dce7251d5848718036780c91384c4396) docs: add apparmor enablement release notes\n* [`aa9311f3d`](https://github.com/siderolabs/talos/commit/aa9311f3d840c7b5a69a1eb6ab4cb3b1a7bff135) fix: install disk matcher error\n* [`1800f8104`](https://github.com/siderolabs/talos/commit/1800f8104486f01e8a3437432e508893f02f809c) fix: selinux handling and apparmor tests\n* [`313bffadf`](https://github.com/siderolabs/talos/commit/313bffadfb66b053f51046300764e94db088b18a) feat: update Kubernetes to v1.32.0-beta.0\n* [`bbfa14451`](https://github.com/siderolabs/talos/commit/bbfa144510063fdcdebbc017b4fb382ac839370c) feat: update containerd to v2.0.0\n* [`8e02b9fcb`](https://github.com/siderolabs/talos/commit/8e02b9fcbfba421abd13ffe4fc8ea3892d4673eb) docs: update manual k8s upgrade docs\n* [`474949dc7`](https://github.com/siderolabs/talos/commit/474949dc77363123f0e8cf2c918ecacb82b4dbdd) feat: add dm-cache dm-cache-smq kernel modules\n* [`5112547d6`](https://github.com/siderolabs/talos/commit/5112547d6b12b4ff40e7863f363cf519efb8c76c) chore: generate support zip for crashdump\n* [`a867f85e4`](https://github.com/siderolabs/talos/commit/a867f85e4cb662a17b0738f1f0de4f1485ad925a) feat: label system socket and runtime files\n* [`398f714cf`](https://github.com/siderolabs/talos/commit/398f714cff04c524394933da17cbc21ad239cd42) feat: update Linux 6.6.59, runc 1.2.1\n* [`05c620957`](https://github.com/siderolabs/talos/commit/05c620957ca741451da395036e8eca59e631fe8d) feat: allow extra mounts for docker-based `talosctl cluster create`\n* [`cedabeddf`](https://github.com/siderolabs/talos/commit/cedabeddf7d191f39525a61e65164f280b6807f8) chore: cleanup code\n* [`61d363e1d`](https://github.com/siderolabs/talos/commit/61d363e1d093047886638d5bc5b9f2181c8bd894) chore: update go-auditlib\n* [`960a04049`](https://github.com/siderolabs/talos/commit/960a040491de5c95b104b4a39ea519095eb47931) feat: start enabling SELinux\n* [`7f3aaa21c`](https://github.com/siderolabs/talos/commit/7f3aaa21cd8d969e26721235a4191ba3bdbc1f8f) fix: update permissions for logging directories in /var\n* [`0e6c983b8`](https://github.com/siderolabs/talos/commit/0e6c983b847f679a074c1794fbe77d21a5994233) fix: mount /sys/kernel/security conditionally\n* [`74b0e8c37`](https://github.com/siderolabs/talos/commit/74b0e8c3713a01f83758556672583880ce5c684a) fix: make route normalization keep family\n* [`0a3761c22`](https://github.com/siderolabs/talos/commit/0a3761c22f98783c6696f143611d600287a471a3) fix: talosctl windows arm64\n* [`4b10c5328`](https://github.com/siderolabs/talos/commit/4b10c5328b861b4bcdcec3ca21bd55b91e969b44) chore: add Windows ARM64 build for talosctl\n* [`9abf16108`](https://github.com/siderolabs/talos/commit/9abf16108ede75984845297d03673d56cb561c2f) feat: add auditd service\n* [`d464ca869`](https://github.com/siderolabs/talos/commit/d464ca869f8949ffbb990c6fb02fbbcbe0abcbe1) chore: drop runc memfd bind added in #9069\n* [`b54d26c2c`](https://github.com/siderolabs/talos/commit/b54d26c2c3f3a52c6d1ec3fddb7a373175815de3) fix: mount pseudo sub-mountpoints in init\n* [`7aeb15f73`](https://github.com/siderolabs/talos/commit/7aeb15f73094a23aea1d6b263ca2eca061c8a257) chore: disable coredns cache for cluster domain\n* [`d8b652150`](https://github.com/siderolabs/talos/commit/d8b652150cec408f2bf3307565b9db691b21bfe9) docs: add warning about NVMe bus path bug\n* [`3e16ab135`](https://github.com/siderolabs/talos/commit/3e16ab135e2be8c9b652d67f9e7eadbc3691c5ca) feat: update Kubernetes to v1.32.0-alpha.3\n* [`0b8b35677`](https://github.com/siderolabs/talos/commit/0b8b3567771fbe796926dc9a6e904e7102535170) feat: add BridgePort property to network machine configuration\n* [`b37950625`](https://github.com/siderolabs/talos/commit/b3795062596ef45dd309f1ca56aab31d2a1a0efc) fix: use more correct condition to skip generating hosts files\n* [`62ec7ec33`](https://github.com/siderolabs/talos/commit/62ec7ec3367233823c09befddc5ad312aa607822) refactor: replace the old v1 mount package with new one\n* [`0ece13c62`](https://github.com/siderolabs/talos/commit/0ece13c6236c7eda474d3734fcc4c4060299ac43) docs: update network-config.md (cont)\n* [`93827f048`](https://github.com/siderolabs/talos/commit/93827f0485a92b46da83b80a2a55f2569f70fe57) docs: update network-config.md\n* [`423b1e5fb`](https://github.com/siderolabs/talos/commit/423b1e5fb22d9e785a3832741d796120b84a5e38) fix: do not trim 0 from process SELinux label\n* [`2136358d6`](https://github.com/siderolabs/talos/commit/2136358d65ddf6ad040ed62c835b335f99a59399) feat: introduce metal agent mode\n* [`0e15955fc`](https://github.com/siderolabs/talos/commit/0e15955fcc5d464c5f0ffd1a44eebf4bf32f4844) chore: small refactoring\n* [`66012a7f2`](https://github.com/siderolabs/talos/commit/66012a7f269010c5ed412d139b14c470063f2429) feat: remove wrapperd and launch processes directly\n* [`3a0a17ae6`](https://github.com/siderolabs/talos/commit/3a0a17ae66dab5c983571fab0f3eac3f87fbc17c) fix: prevent panic in nocloud platform code\n* [`dc0c6acbd`](https://github.com/siderolabs/talos/commit/dc0c6acbd765b6e7838d6af4f1903242d5073782) refactor: remove unmaintained github.com/vishvananda/netlink\n* [`78353f791`](https://github.com/siderolabs/talos/commit/78353f79188e81d064c354f6ef3fe3b2e023c644) feat: add parsing of vlanNNNN:ethX style VLAN cmdline args\n* [`9db7a36bf`](https://github.com/siderolabs/talos/commit/9db7a36bfc45c9c15fd661fb2a6319dcf4fef210) fix: generation of SecureBoot iso\n* [`c755b6d7e`](https://github.com/siderolabs/talos/commit/c755b6d7e4600fdfb32be50422b7efb0fdabef63) fix: update the CRI sandbox image reference\n* [`cec290b35`](https://github.com/siderolabs/talos/commit/cec290b354773b2b0f2c2ae9d57f36e06fe2654d) feat: allow extensions to log to console\n* [`b7801df82`](https://github.com/siderolabs/talos/commit/b7801df827d8e1e9a2db7dac0a62c3802de4d73c) fix: wait for udevd to be running before activating LVM\n* [`d4cb478a5`](https://github.com/siderolabs/talos/commit/d4cb478a50ce41c3699b7846388e537ddf18a703) docs: improve field description for BridgeSTP, BridgeVLAN\n* [`7329824b2`](https://github.com/siderolabs/talos/commit/7329824b2411fef3b23fd90380033441048f6512) docs: add Mynewsdesk to ADOPTERS.md\n* [`a13cf76a3`](https://github.com/siderolabs/talos/commit/a13cf76a3415f458ff3235981c1be8202e1800bb) chore: simplify `DNSUpstreamController` and `DNSUpstream` resource\n* [`62d185473`](https://github.com/siderolabs/talos/commit/62d185473e258c0c34eff5aed4c18d81d4b92a89) fix: talosctl process null character\n* [`77d7368ea`](https://github.com/siderolabs/talos/commit/77d7368eae2da6d2c9aa896afc8013007909a958) feat: update containerd to v2.0.0-rc.6\n* [`d39393879`](https://github.com/siderolabs/talos/commit/d39393879a1f98ac3de7a96808301d1e07fd95f3) fix: rework the 'metal-iso' config acquisition\n* [`1993afca9`](https://github.com/siderolabs/talos/commit/1993afca9fff7e889b497ec3241cfdca42294f18) chore: create /usr/etc in a different step\n* [`8680351c1`](https://github.com/siderolabs/talos/commit/8680351c131d29a76682569742dbd44c8ffe47d3) chore: move system extensions' udev rules\n* [`3067f64c8`](https://github.com/siderolabs/talos/commit/3067f64c8435ef2d5453100a1584dc3c6915ba0b) feat: update Flannel to v0.26.0\n* [`8658d6865`](https://github.com/siderolabs/talos/commit/8658d6865fa0bcbfcebe483b7332d3b56e239979) docs: typo in deploying cilium\n* [`49bbadc4b`](https://github.com/siderolabs/talos/commit/49bbadc4bf1e79e48c057d473ae21426b273c588) docs: add documentation on performance tuning\n* [`534b0ce18`](https://github.com/siderolabs/talos/commit/534b0ce1833462b22f3761258e0e95813a355fb2) feat: update runc to 1.2.0 final\n* [`217253523`](https://github.com/siderolabs/talos/commit/21725352373da7835d95f8f934847dab404782f8) docs: fix image factory links\n* [`375e3da73`](https://github.com/siderolabs/talos/commit/375e3da73fcb02c7caea2576289fefdc395a1ed2) feat: update Kubernetes to 1.32.0-alpha.2\n* [`9e6f64df0`](https://github.com/siderolabs/talos/commit/9e6f64df047527ecb42df5fdf5fd2f9767d21437) fix: improve error messages for invalid bridge/bond configuration\n* [`7c8c72c2b`](https://github.com/siderolabs/talos/commit/7c8c72c2b2a4edb412e097a9e013ab21727339cf) fix: correct error message for invalid ip=\n* [`ead46997c`](https://github.com/siderolabs/talos/commit/ead46997c918ab1139ca12e87beefbbda29614e1) chore: rename tpm2.PCRExtent -> tpm2.PCRExtend\n* [`867c4b812`](https://github.com/siderolabs/talos/commit/867c4b8125ee738f9a82e5e87809eb95bdd2f778) docs: fix typo in prodnotes.md\n* [`1b22df48a`](https://github.com/siderolabs/talos/commit/1b22df48a41578d19fb512bd8111a481b64011e2) chore: support debug shell for advanced development\n* [`c14b44622`](https://github.com/siderolabs/talos/commit/c14b4462292bd7e6088fce35d6880a9b2b56335c) feat: update Kubernetes to v1.32.0-alpha.1\n* [`29780d35a`](https://github.com/siderolabs/talos/commit/29780d35a052134d50576f6506c2728489a30506) test: add an integration test for verifying process parameters\n* [`3d342af44`](https://github.com/siderolabs/talos/commit/3d342af4479ed12e2af10021ec4e7ab9c2af6d75) fix: update incorrect alias for PCIDevice resource\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`58b2f92`](https://github.com/siderolabs/crypto/commit/58b2f9291c7e763a7210cfa681f88a7fa2230bf3) chore: use HTTP/2 ALPN by default\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`005e92c`](https://github.com/siderolabs/discovery-api/commit/005e92cf4ad0059334bfd35285a97c85f12aa263) chore: rekres and regen\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b74fb90`](https://github.com/siderolabs/discovery-client/commit/b74fb9039fcfd8db9d6becf3044f9f41f387ea27) fix: allow custom TLS config for the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`eab6e58`](https://github.com/siderolabs/extras/commit/eab6e58aa9bdf49789cd4d64d2e27f61023421ca) feat: update dependencies\n* [`1459d78`](https://github.com/siderolabs/extras/commit/1459d78cbeb297c023501a3eb785a27a5bdd4933) feat: update pkgs for 1.9\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`e847d2a`](https://github.com/siderolabs/gen/commit/e847d2ace9ede4a17283426dfbc8229121f2909b) chore: add more utilities to xiter\n* [`f3c5a2b`](https://github.com/siderolabs/gen/commit/f3c5a2b5aba74e4935d073a0135c4904ef3bbfef) chore: add `Empty` and `Empty2` iterators\n* [`c53b90b`](https://github.com/siderolabs/gen/commit/c53b90b4a418b8629d938af06900249ce5acd9e6) chore: add packages xiter/xstrings/xbytes\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`134c41b`](https://github.com/siderolabs/go-blockdevice/commit/134c41be6f4c498a149b8098fa8d862c5c47ca54) fix: fast wipe also last 1MB of the device\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`9a0f7b0`](https://github.com/siderolabs/go-circular/commit/9a0f7b02c80ad6c2d953b2d3dd388c56e89363ea) fix: multiple data race issues\n</p>\n</details>\n\n### Changes from siderolabs/go-cmd\n<details><summary>3 commits</summary>\n<p>\n\n* [`d735250`](https://github.com/siderolabs/go-cmd/commit/d73525092a1bb135da54d538e5d64c4dcc80259e) fix: return an error on process nonzero exit code\n* [`5662c7f`](https://github.com/siderolabs/go-cmd/commit/5662c7f8d5cf475c57b3a23b8d8546d960ebc60a) feat: add an equivalent of WaitWrapper for os.Process\n* [`71fced6`](https://github.com/siderolabs/go-cmd/commit/71fced673e013423bba83064767a90372dd6cf51) chore: rekres and move to GHA\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>3 commits</summary>\n<p>\n\n* [`87d2e8e`](https://github.com/siderolabs/go-kubernetes/commit/87d2e8e664c3e3e64403bcfcfe2f8691f60c6481) feat: add one more deprecation for 1.32.0-beta.0\n* [`e56a7f6`](https://github.com/siderolabs/go-kubernetes/commit/e56a7f65808b90058df16a4133f19484beeedc31) fix: update deprecations based on Kubernetes 1.32.0-alpha.3\n* [`381f251`](https://github.com/siderolabs/go-kubernetes/commit/381f251662eaae9b48470ce00f504c2c64187612) feat: update for Kubernetes 1.32\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>2 commits</summary>\n<p>\n\n* [`de1c628`](https://github.com/siderolabs/grpc-proxy/commit/de1c6286b7d16d8485bf8bb55c8783c8773851a0) fix: copy data from big frame msg\n* [`ef47ec7`](https://github.com/siderolabs/grpc-proxy/commit/ef47ec77d2a9f0f42e713d456943dfe9ee86a629) chore: upgrade Codec implementations and usages to Codec2\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>38 commits</summary>\n<p>\n\n* [`4699763`](https://github.com/siderolabs/pkgs/commit/4699763c6d745620aecd0219fc78962e4fa0a01e) feat: update gcc to 14.2\n* [`9a98f73`](https://github.com/siderolabs/pkgs/commit/9a98f73de2c0353e9f8f194bd31c50eea1fb4d5b) feat: update containerd to v2.0.0\n* [`20e1e08`](https://github.com/siderolabs/pkgs/commit/20e1e0857a7d0cf05983998df3160fe0607d5075) feat: enable CONFIG_DM_CACHE\n* [`df45e16`](https://github.com/siderolabs/pkgs/commit/df45e1676828e49d77718e717b2e0e425122c62c) feat: update Linux to 6.6.59\n* [`2e733cc`](https://github.com/siderolabs/pkgs/commit/2e733cccfd225712eb7395cf04b6d8df0bf2b8d2) feat: bump dependencies\n* [`c92e123`](https://github.com/siderolabs/pkgs/commit/c92e123b40457f45e9fc0fe271804fa95c8d4f09) fix: enable nvme and 2.5gbit ethernet on nanopi-r5s\n* [`b160184`](https://github.com/siderolabs/pkgs/commit/b160184a479c85b8b19d2a874e5d6d52db9ed096) feat: update runc to v1.2.1\n* [`e9950d9`](https://github.com/siderolabs/pkgs/commit/e9950d9097fa002e79e2933344f68bb09ad6d4df) chore: drop syslinux\n* [`fc2e8dc`](https://github.com/siderolabs/pkgs/commit/fc2e8dc07ad096d0394f8deacb20d423ef102c2f) feat: update containerd to v2.0.0-rc.6\n* [`38304a6`](https://github.com/siderolabs/pkgs/commit/38304a60e3b32f0b3216ce8128df5f98d8be6812) feat: update Linux to 6.6.58\n* [`84b8df8`](https://github.com/siderolabs/pkgs/commit/84b8df8baf408ab22649b02910294154e0ad5f3b) chore: do not use /usr/etc/udev\n* [`c9282c8`](https://github.com/siderolabs/pkgs/commit/c9282c8dc6a535b69a953c0b4f43fd0780c5bb30) feat: update runc to 1.2.0\n* [`38ad08e`](https://github.com/siderolabs/pkgs/commit/38ad08ecb57d456b76f6d53a7d8a75c3b32f7d61) fix: default IOMMU mode to 'lazy'\n* [`be92da0`](https://github.com/siderolabs/pkgs/commit/be92da09f3196d96b1358efd6a7c667297d3ecfb) feat: update Linux to 6.6.57, update Linux firmware\n* [`0b67a13`](https://github.com/siderolabs/pkgs/commit/0b67a133b12c548ba6d28f2ea0c979cb10512812) feat: bump dependencies\n* [`dd5f928`](https://github.com/siderolabs/pkgs/commit/dd5f928266761215fc402085594493c9f9b329b4) feat: update Linux 6.6.56 and protect /proc/mem\n* [`b1bf972`](https://github.com/siderolabs/pkgs/commit/b1bf9725068029f34193b3abe1586a3d1f542b17) feat: enable CONFIG_XFRM_STATISTICS\n* [`c63beae`](https://github.com/siderolabs/pkgs/commit/c63beae426026c8ef1b3228b8d978ca5fcc9111b) feat: update Linux to 6.6.54\n* [`f474a55`](https://github.com/siderolabs/pkgs/commit/f474a55176dca7ab88b5a29f8d97ce6f31282abd) fix: libselinux: support running without /etc/selinux\n* [`ba0341e`](https://github.com/siderolabs/pkgs/commit/ba0341e39dafb3fe39b5efbc8a8e8d04df96a0e7) fix: systemd-udevd: search for config in /usr/etc\n* [`2b193f1`](https://github.com/siderolabs/pkgs/commit/2b193f14e035fa7d7785f26a591debe6ac357f00) feat: add lpfc kernel module\n* [`1adb946`](https://github.com/siderolabs/pkgs/commit/1adb946b1bb256b30b7bddd517a10d68ce209ada) feat: enable QEDF driver\n* [`dbbe3d0`](https://github.com/siderolabs/pkgs/commit/dbbe3d0116b24b9d1c2df19ae73b76714a37704e) feat: update containerd to v2.0.0-rc.5\n* [`f19590e`](https://github.com/siderolabs/pkgs/commit/f19590edb42a0247d5d509066b21ce35bfc42b93) feat: update Go to 1.23.2\n* [`e2a561f`](https://github.com/siderolabs/pkgs/commit/e2a561f576ea7dbc55ebb403d648daa1561c3101) fix: drop the LVM2 udev lvm rule\n* [`ae205aa`](https://github.com/siderolabs/pkgs/commit/ae205aac9d827783352071f9447f9f7cbf70da20) fix: force LVM to use `/run` as state directory\n* [`232a153`](https://github.com/siderolabs/pkgs/commit/232a15318a2d47f34b0772663fc3f417905b5406) feat: replace eudev with systemd-udevd\n* [`40fb82a`](https://github.com/siderolabs/pkgs/commit/40fb82a27a840f3442d6f52374007afb0a5a3770) feat: add libselinux, libsepol, pcre2 and libcap\n* [`6f40fbb`](https://github.com/siderolabs/pkgs/commit/6f40fbb5e00e449c954d54990085353d061a62c8) feat: update xfsprogs 6.10.1\n* [`a1709c7`](https://github.com/siderolabs/pkgs/commit/a1709c76db4ba70de526d7eec18c6b0637ebf7b0) feat: enable module unloading and memory hotplug (for NVIDIA UVM)\n* [`2c5785b`](https://github.com/siderolabs/pkgs/commit/2c5785b1639a22317a1f7775f0d1f4bd0b0a4b88) feat: enable transparent huge pages in madvise mode\n* [`ca2e8c8`](https://github.com/siderolabs/pkgs/commit/ca2e8c84b0881e7d1e359ceaf3b55c3b4bb384e7) fix: lvm2 modprobe path\n* [`6b334a6`](https://github.com/siderolabs/pkgs/commit/6b334a68fbd988ca69d05142a639aa3bcfd16721) feat: update Linux to 6.6.52\n* [`e90ae7e`](https://github.com/siderolabs/pkgs/commit/e90ae7ec316f1b9b4d15897f825d3c2c4cefde5e) feat: update Linux firmware to 20240909\n* [`79a4f92`](https://github.com/siderolabs/pkgs/commit/79a4f92c5aa4b8288a927351209542c274724475) feat: enable INET_DIAG\n* [`c9f7eb9`](https://github.com/siderolabs/pkgs/commit/c9f7eb94de2a8df5cfc41c6ea90596832894dc89) feat: update Linux to 6.6.51\n* [`126b6a4`](https://github.com/siderolabs/pkgs/commit/126b6a4f7632b2400139e306a0dbb0a545a0dda1) fix: add mpt3sas UBSAN patches\n* [`a09bf93`](https://github.com/siderolabs/pkgs/commit/a09bf93ce81bde59fcb06d662bc79effc9efaca6) chore: drop UBSAN patch\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>3 commits</summary>\n<p>\n\n* [`0d84c65`](https://github.com/siderolabs/proto-codec/commit/0d84c652784543012f43f8c8d4358c160b27577e) chore: add support for gogo protobuf generator\n* [`19f8d2e`](https://github.com/siderolabs/proto-codec/commit/19f8d2e5840c19937c60cee0c681343ab658f678) chore: add kres\n* [`e038bb4`](https://github.com/siderolabs/proto-codec/commit/e038bb42f2be8b80ca09e46bb8704be06a413919) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`1893385`](https://github.com/siderolabs/siderolink/commit/1893385fe45bf110357a770d31b06f5d79403065) fix: initialize tls listener properly\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>8 commits</summary>\n<p>\n\n* [`3750064`](https://github.com/siderolabs/tools/commit/375006431abb204c275adab2fdc9128060bb32f7) fix: update for musl with close_range\n* [`0a443c6`](https://github.com/siderolabs/tools/commit/0a443c6d5a1ac6764b22990be0945ef4cae8c32e) feat: update toolchain for gcc 14.2\n* [`63ecd80`](https://github.com/siderolabs/tools/commit/63ecd80a4709bcde5c6cc0f112c1faf43ab024ce) feat: bump depedendencies\n* [`2058296`](https://github.com/siderolabs/tools/commit/2058296cc223b683685f229a9a52de4db7171595) feat: bump dependencies\n* [`1151610`](https://github.com/siderolabs/tools/commit/1151610f5a5e70d07b715a2bdd76acd06d418595) feat: update Go to 1.23.2\n* [`9f2189b`](https://github.com/siderolabs/tools/commit/9f2189b2b032ed283f38b20c53018b921fa06895) fix: bump gettext-tiny to the latest dev version\n* [`95069d6`](https://github.com/siderolabs/tools/commit/95069d6fd8fccde7ab93465e4e49a5a6ac5d4ed0) feat: update Go to 1.23.1\n* [`eec0656`](https://github.com/siderolabs/tools/commit/eec0656aca652d0cc2e1973d5fab56bd4b54f64b) feat: replace gettext with gettext-tiny\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**                                    v0.5.0 -> v0.5.2\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.13.0 -> v1.16.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.7.0 -> v1.8.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.1.0 -> v1.2.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.1.0 -> v1.2.0\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.27.33 -> v1.28.1\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.16.13 -> v1.16.18\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.35.7 -> v1.37.3\n* **github.com/aws/smithy-go**                                                v1.20.4 -> v1.22.0\n* **github.com/containerd/containerd/api**                                    v1.8.0-rc.3 -> v1.8.0\n* **github.com/containerd/containerd/v2**                                     v2.0.0-rc.4 -> v2.0.0\n* **github.com/containerd/errdefs**                                           v0.1.0 -> v1.0.0\n* **github.com/containerd/platforms**                                         v0.2.1 -> v1.0.0-rc.0\n* **github.com/containerd/typeurl/v2**                                        v2.2.0 -> v2.2.2\n* **github.com/containernetworking/plugins**                                  v1.5.1 -> v1.6.0\n* **github.com/cosi-project/runtime**                                         v0.5.5 -> v0.7.1\n* **github.com/docker/cli**                                                   v27.3.1 **_new_**\n* **github.com/docker/docker**                                                v27.2.0 -> v27.3.1\n* **github.com/elastic/go-libaudit/v2**                                       1df86e79cca7 **_new_**\n* **github.com/fatih/color**                                                  v1.17.0 -> v1.18.0\n* **github.com/florianl/go-tc**                                               v0.4.4 **_new_**\n* **github.com/foxboron/go-uefi**                                             e2076f0e58ca -> fab4fdf2f2f3\n* **github.com/fsnotify/fsnotify**                                            v1.7.0 -> v1.8.0\n* **github.com/google/cadvisor**                                              v0.50.0 -> v0.51.0\n* **github.com/gopacket/gopacket**                                            v1.2.0 -> v1.3.0\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.13.1 -> v2.15.0\n* **github.com/klauspost/compress**                                           v1.17.9 -> v1.17.11\n* **github.com/linode/go-metadata**                                           v0.2.0 -> v0.2.1\n* **github.com/mdlayher/ethtool**                                             v0.1.0 -> v0.2.0\n* **github.com/opencontainers/runc**                                          v1.2.0-rc.3 -> v1.2.1\n* **github.com/rivo/tview**                                                   fd649dbf1223 -> c76f7879f592\n* **github.com/siderolabs/crypto**                                            v0.4.4 -> v0.5.0\n* **github.com/siderolabs/discovery-api**                                     v0.1.4 -> v0.1.5\n* **github.com/siderolabs/discovery-client**                                  v0.1.9 -> v0.1.10\n* **github.com/siderolabs/extras**                                            v1.8.0 -> v1.9.0-alpha.0-1-geab6e58\n* **github.com/siderolabs/gen**                                               v0.5.0 -> v0.7.0\n* **github.com/siderolabs/go-blockdevice**                                    v0.4.7 -> v0.4.8\n* **github.com/siderolabs/go-blockdevice/v2**                                 v2.0.2 -> v2.0.3\n* **github.com/siderolabs/go-circular**                                       v0.2.0 -> v0.2.1\n* **github.com/siderolabs/go-cmd**                                            v0.1.1 -> v0.1.3\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.12 -> v0.2.15\n* **github.com/siderolabs/grpc-proxy**                                        v0.4.1 -> v0.5.1\n* **github.com/siderolabs/pkgs**                                              v1.8.0-8-gdf1a1a5 -> v1.9.0-alpha.0-37-g4699763\n* **github.com/siderolabs/proto-codec**                                       v0.1.1 **_new_**\n* **github.com/siderolabs/siderolink**                                        v0.3.10 -> v0.3.11\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.8.0 -> v1.9.0-alpha.0\n* **github.com/siderolabs/tools**                                             v1.8.0-1-ga0c06c6 -> v1.9.0-alpha.0-7-g3750064\n* **golang.org/x/net**                                                        v0.29.0 -> v0.30.0\n* **golang.org/x/sys**                                                        v0.25.0 -> v0.26.0\n* **golang.org/x/term**                                                       v0.24.0 -> v0.25.0\n* **golang.org/x/text**                                                       v0.18.0 -> v0.19.0\n* **golang.org/x/time**                                                       v0.6.0 -> v0.7.0\n* **google.golang.org/grpc**                                                  v1.66.0 -> v1.67.1\n* **google.golang.org/protobuf**                                              v1.34.2 -> v1.35.1\n* **k8s.io/api**                                                              v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apimachinery**                                                     v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/apiserver**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/client-go**                                                        v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/component-base**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/cri-api**                                                          v0.32.0-alpha.0 -> v0.32.0-beta.0\n* **k8s.io/kube-scheduler**                                                   v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubectl**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/kubelet**                                                          v0.31.1 -> v0.32.0-beta.0\n* **k8s.io/pod-security-admission**                                           v0.31.1 -> v0.32.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**                           v1.2.70 -> v1.2.71\n\nPrevious release can be found at [v1.8.0](https://github.com/siderolabs/talos/releases/tag/v1.8.0)\n\n## [Talos 1.9.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.9.0-alpha.0) (2024-10-18)\n\nWelcome to the v1.9.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### `talosctl cgroups`\n\nThe `talosctl cgroups` command has been added to the `talosctl` tool.\nThis command allows you to view the cgroup resource consumption and limits for a machine, e.g.\n`talosctl cgroups --preset memory`.\n\n\n### udevd\n\nTalos previously used `udevd` to provide `udevd`, now it uses `systemd-udevd` instead.\n\n\n### Component Updates\n\nLinux: 6.6.57\ncontainerd: 2.0.0-rc.5\nFlannel: 0.25.7\n\nTalos is built with Go 1.23.2.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Noel Georgi\n* Dmitry Sharshakov\n* Jean-Francois Roy\n* Adolfo Ochagavía\n* Dan Rue\n* Eddie Wang\n* Florian Ströger\n* Hexoplon\n* Mike Beaumont\n* Philip Schmid\n* Philipp Kleber\n* Robby Ciliberto\n* Ryan Borstelmann\n* Serge Logvinov\n* Spencer Smith\n* Steven Cassamajor\n* Tim Jones\n* adilTepe\n* ekarlso\n* naed3r\n\n### Changes\n<details><summary>72 commits</summary>\n<p>\n\n* [`4529cf52d`](https://github.com/siderolabs/talos/commit/4529cf52db76cd59d5240f6589f463b6fa5f70be) release(v1.9.0-alpha.0): prepare release\n* [`e0434d77d`](https://github.com/siderolabs/talos/commit/e0434d77d754f8834ba903f4c09b08634cfd3934) feat: update dependencies\n* [`5c5a24886`](https://github.com/siderolabs/talos/commit/5c5a248861c8e5848f9a23cd0cd7b3b749f21e4b) feat: add Talos 1.9 compatibility guarantees\n* [`bc4c21f41`](https://github.com/siderolabs/talos/commit/bc4c21f41a0066ba6cefb5b753c52d76a6b0f629) test: add json logs test environment\n* [`71faa3294`](https://github.com/siderolabs/talos/commit/71faa3294246947f6bd212979ceb31e793ae0604) docs: nvidia proprietary/oss hardware requirement\n* [`59a78da42`](https://github.com/siderolabs/talos/commit/59a78da42cdea8fbccc35d0851f9b0eef928261b) chore: add proto-codec/codec\n* [`7ff1cedfe`](https://github.com/siderolabs/talos/commit/7ff1cedfe3eee51505c30439eec4a2df9b452b2e) chore: update siderolabs/crypto module and return proper ALPN\n* [`ccbd5aed3`](https://github.com/siderolabs/talos/commit/ccbd5aed39b360664d1f80c8b146050e9df9ff7b) feat: optionally decode hcloud userdata as base64\n* [`34f652ce8`](https://github.com/siderolabs/talos/commit/34f652ce822fcb70a292289fe6ba5d1bd7a34f97) feat: add well-known app.kubernetes.io labels to control-plane pods\n* [`fc89dc216`](https://github.com/siderolabs/talos/commit/fc89dc21643a923cb7d0d3944405521bf849631b) fix: support `extra-disks` when using iso\n* [`f2bff814d`](https://github.com/siderolabs/talos/commit/f2bff814de0b237fbed419234b935dc9f9637554) chore: add arm64 target for integration-test\n* [`5853bb0ea`](https://github.com/siderolabs/talos/commit/5853bb0ea4d6a65635086bdef617d6d0800cabd0) fix: json logging panic\n* [`a859cff36`](https://github.com/siderolabs/talos/commit/a859cff364aa4dc9b4b880417b821f7ecf5602ac) chore: use virtio driver for disks in arm64\n* [`db248de88`](https://github.com/siderolabs/talos/commit/db248de88dec2467e4340f699cde98217979ba4b) chore(ci): add config for lldpd extension\n* [`9f0de9f43`](https://github.com/siderolabs/talos/commit/9f0de9f43dc4467f0bdeda117b4946ae12db50ab) test: update provision upgrade tests for Talos 1.9\n* [`39fe285e6`](https://github.com/siderolabs/talos/commit/39fe285e69691059f91d8c7c5506e156356263d9) fix: skip ram disks\n* [`a9bff3a1d`](https://github.com/siderolabs/talos/commit/a9bff3a1d084c32a654555e71e2592e60edbdcb6) test: skip no error test in Cilium\n* [`4d902021b`](https://github.com/siderolabs/talos/commit/4d902021bb3c55bc212cbb3e2443b6552400622f) fix: do not use pflag csv comma reader for config-patch\n* [`5371788ce`](https://github.com/siderolabs/talos/commit/5371788ce169a0381e08f0d902ac81f3f89ba5bd) fix: typo in documentation\n* [`8a228ba6b`](https://github.com/siderolabs/talos/commit/8a228ba6bc702f21fca06dc2ecb3e8e846839cd3) docs: add egress documentation\n* [`182325cb0`](https://github.com/siderolabs/talos/commit/182325cb0791da1d4dcd3914a643c44232502524) test: skip lvm test if not enough user disks available\n* [`519a48302`](https://github.com/siderolabs/talos/commit/519a48302e771fd9b331913166d55c50fff4961a) fix: wipe system partitions correctly via kernel args\n* [`0a2b4556c`](https://github.com/siderolabs/talos/commit/0a2b4556c55eda27536ee563f60bcf5d69379479) fix: volume encryption with failing keyslots\n* [`6affbd318`](https://github.com/siderolabs/talos/commit/6affbd3182ebe0209ed5433c534062b7ad672b6a) fix: update grpc-go the latest patch release\n* [`77a4a4adc`](https://github.com/siderolabs/talos/commit/77a4a4adc7232b4382f2a530f4056a1fff6c50b4) fix: scaleway metadata\n* [`7acadc0c8`](https://github.com/siderolabs/talos/commit/7acadc0c8fa969e4de7f0d4f68b0fd0cd833b489) fix: do not stop udevd before unmounting volumes\n* [`6a081055b`](https://github.com/siderolabs/talos/commit/6a081055b0dd4e3ce5c40392c8415a0a55b2591c) feat: update Flannel to v0.25.7\n* [`2362f6d3e`](https://github.com/siderolabs/talos/commit/2362f6d3ee51a0a8b541a872d39ac82892502e17) fix: improve container detection\n* [`b67bc73fd`](https://github.com/siderolabs/talos/commit/b67bc73fd30a8e07f26c47a746ca53f2af41d366) fix: fix mdadm system extension\n* [`f08669c7a`](https://github.com/siderolabs/talos/commit/f08669c7a9583a559dc53f233798305bbab07b8a) feat: bring in lpfc kernel module driver\n* [`6a014374b`](https://github.com/siderolabs/talos/commit/6a014374be26f0caf8faa90a34f2476e0e77a46a) feat: enable QEDF driver\n* [`f711907e0`](https://github.com/siderolabs/talos/commit/f711907e038cea20f6b831ea5ad8c3b18638c1b4) fix: make /var/run empty on reboots\n* [`7d02eb60f`](https://github.com/siderolabs/talos/commit/7d02eb60f47652f4b72f170b28a8b964729af013) docs: fix typo in CloudStack docs\n* [`74861573a`](https://github.com/siderolabs/talos/commit/74861573a793f9e143d7d2638990f37ec639aa88) fix: multiple fixes for LVM activation\n* [`74c12c20e`](https://github.com/siderolabs/talos/commit/74c12c20e02e4ec29b2b374cebc996ddf8fa90c7) feat: replace eudev with systemd-udevd\n* [`0a4df4ef8`](https://github.com/siderolabs/talos/commit/0a4df4ef84467014d5be4b4ec57de0e778cfb21e) docs: fix nvidia CRI config example\n* [`afc1e1a46`](https://github.com/siderolabs/talos/commit/afc1e1a46a559aac3aa5f4a2708ba8d2c9228929) docs: fix typo in extraMounts directory\n* [`a341bdb06`](https://github.com/siderolabs/talos/commit/a341bdb0640294a07939670919c56cbfa7a861c4) fix: prevent file descriptors leaks to child processes\n* [`dec653bfe`](https://github.com/siderolabs/talos/commit/dec653bfe1feb84ea2ed1a779b1bfc783dc61160) chore: better lvm2 tests\n* [`908fd8789`](https://github.com/siderolabs/talos/commit/908fd8789cc1b22e556a7ffe307409931976ba08) feat: support cgroup deep analysis in `talosctl`\n* [`aa846cc18`](https://github.com/siderolabs/talos/commit/aa846cc186c1c6125f8f39ea084fa2023512656f) feat: add support for CI Network config in nocloud\n* [`10f2539f2`](https://github.com/siderolabs/talos/commit/10f2539f237aeb3af2caeb3c349c062f203219b6) chore: disable cloud-images cron workflow\n* [`b07a8b36b`](https://github.com/siderolabs/talos/commit/b07a8b36b24d57337323e72d6032304c4cade927) chore: ignore more plugins for system containerd\n* [`392c4798f`](https://github.com/siderolabs/talos/commit/392c4798f0bff7cb4518609deae7c90581f013f5) feat: prepare for Talos 1.9\n* [`ea7bf9fb4`](https://github.com/siderolabs/talos/commit/ea7bf9fb43dff8cf8ec4dfd4f629e8f826bc2ded) docs: update storage.md\n* [`4ab8dee69`](https://github.com/siderolabs/talos/commit/4ab8dee69ac07c811cbe121ca9e2d9bd01148863) fix: build talosctl without `tcell_minimal`\n* [`2fa019bd9`](https://github.com/siderolabs/talos/commit/2fa019bd9751ad96085ade52628023adf17658d3) docs: enable 'edit on GitHub' link\n* [`d2ccbc2b1`](https://github.com/siderolabs/talos/commit/d2ccbc2b1512b6323d48a764c4af534d49b4bd27) docs: update hetzner documentation for CCM\n* [`d498f647c`](https://github.com/siderolabs/talos/commit/d498f647cd9dfcd575f51005c9b78c2c1c7b51ca) docs: fix Kernel Self Protection Project (KSPP) references\n* [`0ec75463e`](https://github.com/siderolabs/talos/commit/0ec75463eecebfb543a64b0c859ba0b2477e406f) docs: make Talos 1.8 current release\n* [`9b77698cf`](https://github.com/siderolabs/talos/commit/9b77698cf2ff64c6f6d198d05c2012ab7fa858be) fix: update blockdevice library to v2.0.2\n* [`e46227ab9`](https://github.com/siderolabs/talos/commit/e46227ab95a6d06132e82315f55b5ced533ddabb) docs: fix kubespan name inconsistency\n* [`6b15ca19c`](https://github.com/siderolabs/talos/commit/6b15ca19cd1291b8a245d72d5153827945cad037) fix: audit and fix cgroup reservations\n* [`32b5d01ed`](https://github.com/siderolabs/talos/commit/32b5d01ed3396e8f54a245cc6d9818119aec8291) chore: bump lvm2\n* [`6484581eb`](https://github.com/siderolabs/talos/commit/6484581eb888996a8dc829915439fb63606dd794) feat: allow /sbin/ldconfig in extensions\n* [`9fa08e843`](https://github.com/siderolabs/talos/commit/9fa08e843728dbd85ed7e0035f59cdd6232de9a9) chore: refactor tests\n* [`d8ab4981b`](https://github.com/siderolabs/talos/commit/d8ab4981b626ff41fbcdb526a032a5584519e3df) feat: support lvm auto activation\n* [`8166a58b3`](https://github.com/siderolabs/talos/commit/8166a58b364f760212b2a610ce0d764b8b4c5c46) fix: filter out non-printable characters in process line\n* [`806b6aaf5`](https://github.com/siderolabs/talos/commit/806b6aaf52f20ed0f32107b3d0372d6e3ff974be) docs: add SECURITY.md\n* [`7bd26df30`](https://github.com/siderolabs/talos/commit/7bd26df30803307e4eece3e382aafebc55e7b260) docs: document `/dev/net/tun` compatibility\n* [`18daedb51`](https://github.com/siderolabs/talos/commit/18daedb511e769717ba56eb05cccab72118a4813) fix: strategic merge patch delete for map keys\n* [`f3370529a`](https://github.com/siderolabs/talos/commit/f3370529ac042865a4b2d793465916fcae2d4b33) docs: correct typo\n* [`8d6884a8e`](https://github.com/siderolabs/talos/commit/8d6884a8e28e1bfa29f9a479e0f7179819cf70cd) test: add a test for inline machine config trusted roots\n* [`d4a6d017d`](https://github.com/siderolabs/talos/commit/d4a6d017dbb91e22c60787cdf64b242057b1ebef) fix: ignore invalid NTP responses\n* [`869f8379f`](https://github.com/siderolabs/talos/commit/869f8379f2317175901e8cb3deec4b800e7ab603) feat: update default Kubernetes version to 1.31.1\n* [`780a1f198`](https://github.com/siderolabs/talos/commit/780a1f198a5eedd33a27060bdf116bd3a3b26426) fix: update CoreDNS health check\n* [`79cd03158`](https://github.com/siderolabs/talos/commit/79cd031588a0710b865414f919742ee3ffb998ed) chore: account for resource sorting in dns upstream resource\n* [`e17fafaca`](https://github.com/siderolabs/talos/commit/e17fafaca2a16990bc424b54120c49ddbaf8cee1) chore: drop `activateLogicalVolumes` sequencer step\n* [`a294b366f`](https://github.com/siderolabs/talos/commit/a294b366f24c6580d304c6c8ad34f481079dc795) fix: parse SideroLink API endpoint correctly\n* [`a9269ac7b`](https://github.com/siderolabs/talos/commit/a9269ac7b1217aa2d247c0215c5f2755af468b44) fix: remove extra logging on ethtool ioctl failures\n* [`5c6277d17`](https://github.com/siderolabs/talos/commit/5c6277d171eea58878ce4fcb4d2fdb7154333ae7) feat: update etcd to 3.5.16\n* [`c1ed2984b`](https://github.com/siderolabs/talos/commit/c1ed2984b85dca791a5081c5da26bba75e3cd579) docs: add what's new for Talos 1.8\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`58b2f92`](https://github.com/siderolabs/crypto/commit/58b2f9291c7e763a7210cfa681f88a7fa2230bf3) chore: use HTTP/2 ALPN by default\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`b74fb90`](https://github.com/siderolabs/discovery-client/commit/b74fb9039fcfd8db9d6becf3044f9f41f387ea27) fix: allow custom TLS config for the client\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`eab6e58`](https://github.com/siderolabs/extras/commit/eab6e58aa9bdf49789cd4d64d2e27f61023421ca) feat: update dependencies\n* [`1459d78`](https://github.com/siderolabs/extras/commit/1459d78cbeb297c023501a3eb785a27a5bdd4933) feat: update pkgs for 1.9\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`134c41b`](https://github.com/siderolabs/go-blockdevice/commit/134c41be6f4c498a149b8098fa8d862c5c47ca54) fix: fast wipe also last 1MB of the device\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>1 commit</summary>\n<p>\n\n* [`9a0f7b0`](https://github.com/siderolabs/go-circular/commit/9a0f7b02c80ad6c2d953b2d3dd388c56e89363ea) fix: multiple data race issues\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>1 commit</summary>\n<p>\n\n* [`381f251`](https://github.com/siderolabs/go-kubernetes/commit/381f251662eaae9b48470ce00f504c2c64187612) feat: update for Kubernetes 1.32\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>2 commits</summary>\n<p>\n\n* [`de1c628`](https://github.com/siderolabs/grpc-proxy/commit/de1c6286b7d16d8485bf8bb55c8783c8773851a0) fix: copy data from big frame msg\n* [`ef47ec7`](https://github.com/siderolabs/grpc-proxy/commit/ef47ec77d2a9f0f42e713d456943dfe9ee86a629) chore: upgrade Codec implementations and usages to Codec2\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>25 commits</summary>\n<p>\n\n* [`be92da0`](https://github.com/siderolabs/pkgs/commit/be92da09f3196d96b1358efd6a7c667297d3ecfb) feat: update Linux to 6.6.57, update Linux firmware\n* [`0b67a13`](https://github.com/siderolabs/pkgs/commit/0b67a133b12c548ba6d28f2ea0c979cb10512812) feat: bump dependencies\n* [`dd5f928`](https://github.com/siderolabs/pkgs/commit/dd5f928266761215fc402085594493c9f9b329b4) feat: update Linux 6.6.56 and protect /proc/mem\n* [`b1bf972`](https://github.com/siderolabs/pkgs/commit/b1bf9725068029f34193b3abe1586a3d1f542b17) feat: enable CONFIG_XFRM_STATISTICS\n* [`c63beae`](https://github.com/siderolabs/pkgs/commit/c63beae426026c8ef1b3228b8d978ca5fcc9111b) feat: update Linux to 6.6.54\n* [`f474a55`](https://github.com/siderolabs/pkgs/commit/f474a55176dca7ab88b5a29f8d97ce6f31282abd) fix: libselinux: support running without /etc/selinux\n* [`ba0341e`](https://github.com/siderolabs/pkgs/commit/ba0341e39dafb3fe39b5efbc8a8e8d04df96a0e7) fix: systemd-udevd: search for config in /usr/etc\n* [`2b193f1`](https://github.com/siderolabs/pkgs/commit/2b193f14e035fa7d7785f26a591debe6ac357f00) feat: add lpfc kernel module\n* [`1adb946`](https://github.com/siderolabs/pkgs/commit/1adb946b1bb256b30b7bddd517a10d68ce209ada) feat: enable QEDF driver\n* [`dbbe3d0`](https://github.com/siderolabs/pkgs/commit/dbbe3d0116b24b9d1c2df19ae73b76714a37704e) feat: update containerd to v2.0.0-rc.5\n* [`f19590e`](https://github.com/siderolabs/pkgs/commit/f19590edb42a0247d5d509066b21ce35bfc42b93) feat: update Go to 1.23.2\n* [`e2a561f`](https://github.com/siderolabs/pkgs/commit/e2a561f576ea7dbc55ebb403d648daa1561c3101) fix: drop the LVM2 udev lvm rule\n* [`ae205aa`](https://github.com/siderolabs/pkgs/commit/ae205aac9d827783352071f9447f9f7cbf70da20) fix: force LVM to use `/run` as state directory\n* [`232a153`](https://github.com/siderolabs/pkgs/commit/232a15318a2d47f34b0772663fc3f417905b5406) feat: replace eudev with systemd-udevd\n* [`40fb82a`](https://github.com/siderolabs/pkgs/commit/40fb82a27a840f3442d6f52374007afb0a5a3770) feat: add libselinux, libsepol, pcre2 and libcap\n* [`6f40fbb`](https://github.com/siderolabs/pkgs/commit/6f40fbb5e00e449c954d54990085353d061a62c8) feat: update xfsprogs 6.10.1\n* [`a1709c7`](https://github.com/siderolabs/pkgs/commit/a1709c76db4ba70de526d7eec18c6b0637ebf7b0) feat: enable module unloading and memory hotplug (for NVIDIA UVM)\n* [`2c5785b`](https://github.com/siderolabs/pkgs/commit/2c5785b1639a22317a1f7775f0d1f4bd0b0a4b88) feat: enable transparent huge pages in madvise mode\n* [`ca2e8c8`](https://github.com/siderolabs/pkgs/commit/ca2e8c84b0881e7d1e359ceaf3b55c3b4bb384e7) fix: lvm2 modprobe path\n* [`6b334a6`](https://github.com/siderolabs/pkgs/commit/6b334a68fbd988ca69d05142a639aa3bcfd16721) feat: update Linux to 6.6.52\n* [`e90ae7e`](https://github.com/siderolabs/pkgs/commit/e90ae7ec316f1b9b4d15897f825d3c2c4cefde5e) feat: update Linux firmware to 20240909\n* [`79a4f92`](https://github.com/siderolabs/pkgs/commit/79a4f92c5aa4b8288a927351209542c274724475) feat: enable INET_DIAG\n* [`c9f7eb9`](https://github.com/siderolabs/pkgs/commit/c9f7eb94de2a8df5cfc41c6ea90596832894dc89) feat: update Linux to 6.6.51\n* [`126b6a4`](https://github.com/siderolabs/pkgs/commit/126b6a4f7632b2400139e306a0dbb0a545a0dda1) fix: add mpt3sas UBSAN patches\n* [`a09bf93`](https://github.com/siderolabs/pkgs/commit/a09bf93ce81bde59fcb06d662bc79effc9efaca6) chore: drop UBSAN patch\n</p>\n</details>\n\n### Changes from siderolabs/proto-codec\n<details><summary>3 commits</summary>\n<p>\n\n* [`0d84c65`](https://github.com/siderolabs/proto-codec/commit/0d84c652784543012f43f8c8d4358c160b27577e) chore: add support for gogo protobuf generator\n* [`19f8d2e`](https://github.com/siderolabs/proto-codec/commit/19f8d2e5840c19937c60cee0c681343ab658f678) chore: add kres\n* [`e038bb4`](https://github.com/siderolabs/proto-codec/commit/e038bb42f2be8b80ca09e46bb8704be06a413919) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>1 commit</summary>\n<p>\n\n* [`1893385`](https://github.com/siderolabs/siderolink/commit/1893385fe45bf110357a770d31b06f5d79403065) fix: initialize tls listener properly\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`2058296`](https://github.com/siderolabs/tools/commit/2058296cc223b683685f229a9a52de4db7171595) feat: bump dependencies\n* [`1151610`](https://github.com/siderolabs/tools/commit/1151610f5a5e70d07b715a2bdd76acd06d418595) feat: update Go to 1.23.2\n* [`9f2189b`](https://github.com/siderolabs/tools/commit/9f2189b2b032ed283f38b20c53018b921fa06895) fix: bump gettext-tiny to the latest dev version\n* [`95069d6`](https://github.com/siderolabs/tools/commit/95069d6fd8fccde7ab93465e4e49a5a6ac5d4ed0) feat: update Go to 1.23.1\n* [`eec0656`](https://github.com/siderolabs/tools/commit/eec0656aca652d0cc2e1973d5fab56bd4b54f64b) feat: replace gettext with gettext-tiny\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.5.0 -> v0.5.2\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.13.0 -> v1.15.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.7.0 -> v1.8.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.27.33 -> v1.28.0\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.13 -> v1.16.17\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.35.7 -> v1.37.2\n* **github.com/aws/smithy-go**                          v1.20.4 -> v1.22.0\n* **github.com/containerd/containerd/v2**               v2.0.0-rc.4 -> v2.0.0-rc.5\n* **github.com/containernetworking/plugins**            v1.5.1 -> v1.6.0\n* **github.com/cosi-project/runtime**                   v0.5.5 -> v0.6.4\n* **github.com/docker/docker**                          v27.2.0 -> v27.3.1\n* **github.com/gopacket/gopacket**                      v1.2.0 -> v1.3.0\n* **github.com/klauspost/compress**                     v1.17.9 -> v1.17.11\n* **github.com/mdlayher/ethtool**                       v0.1.0 -> v0.2.0\n* **github.com/rivo/tview**                             fd649dbf1223 -> c5e4fb24af13\n* **github.com/siderolabs/crypto**                      v0.4.4 -> v0.5.0\n* **github.com/siderolabs/discovery-client**            v0.1.9 -> v0.1.10\n* **github.com/siderolabs/extras**                      v1.8.0 -> v1.9.0-alpha.0-1-geab6e58\n* **github.com/siderolabs/go-blockdevice**              v0.4.7 -> v0.4.8\n* **github.com/siderolabs/go-blockdevice/v2**           v2.0.2 -> v2.0.3\n* **github.com/siderolabs/go-circular**                 v0.2.0 -> v0.2.1\n* **github.com/siderolabs/go-kubernetes**               v0.2.12 -> v0.2.13\n* **github.com/siderolabs/grpc-proxy**                  v0.4.1 -> v0.5.1\n* **github.com/siderolabs/pkgs**                        v1.8.0-8-gdf1a1a5 -> v1.9.0-alpha.0-24-gbe92da0\n* **github.com/siderolabs/proto-codec**                 v0.1.1 **_new_**\n* **github.com/siderolabs/siderolink**                  v0.3.10 -> v0.3.11\n* **github.com/siderolabs/talos/pkg/machinery**         v1.8.0 -> v1.8.1\n* **github.com/siderolabs/tools**                       v1.8.0-1-ga0c06c6 -> v1.9.0-alpha.0-4-g2058296\n* **golang.org/x/net**                                  v0.29.0 -> v0.30.0\n* **golang.org/x/sys**                                  v0.25.0 -> v0.26.0\n* **golang.org/x/term**                                 v0.24.0 -> v0.25.0\n* **golang.org/x/text**                                 v0.18.0 -> v0.19.0\n* **golang.org/x/time**                                 v0.6.0 -> v0.7.0\n* **google.golang.org/grpc**                            v1.66.0 -> v1.67.1\n* **google.golang.org/protobuf**                        v1.34.2 -> v1.35.1\n\nPrevious release can be found at [v1.8.0](https://github.com/siderolabs/talos/releases/tag/v1.8.0)\n\n## [Talos 1.8.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.8.0-alpha.2) (2024-09-02)\n\nWelcome to the v1.8.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\nStarting with Talos v1.8.0, only standard assets would be published as github release assets. These include:\n\n* `cloud-images.json`\n* `talosctl` binaries\n* `kernel`\n* `initramfs`\n* `metal` iso and disk images\n* `talosctl-cni-bundle`\n\nAll other release assets can be downloaded from [Image Factory](https://www.talos.dev/latest/talos-guides/install/boot-assets/#image-factory).\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Node Annotations\n\nTalos Linux now supports configuring Kubernetes node annotations via machine configuration (`.machine.nodeAnnotations`) in a way similar to node labels.\n\n\n### Workload Apparmor Profile\n\nTalos Linux can now apply the default AppArmor profiles to all workloads started via containerd, if the machine is installed with the AppArmor LSM enforced via the extraKernelArgs.\n\nEg:\n\n```yaml\nmachine:\n    install:\n        extraKernelArgs:\n            - security=apparmor\n```\n\n\n### Bridge Interface\n\nTalos Linux now support configuring 'vlan_filtering' for bridge interfaces.\n\n\n### CNI Plugins\n\nTalos Linux now bundles by default the following standard CNI plugins:\n\n* `bridge`\n* `firewall`\n* `flannel`\n* `host-local`\n* `loopback`\n* `portmap`\n\nThe Talos bundled Flannel manifest was simplified to remove the `install-cni` step.\n\n\n### Diagnostics\n\nTalos Linux now shows diagnostics information for common problems related to misconfiguration via `talosctl health` and Talos dashboard.\n\n\n### Extensions in Kubernetes Nodes\n\nTalos Linux now publishes list of installed extensions as Kubernetes node labels/annotations.\n\nThe key format is `extensions.talos.dev/<name>` and the value is the extension version.\nIf the extension name is not valid as a label key, it will be skipped.\nIf the extension version is a valid label value, it will be put to the label; otherwise it will be put to the annotation.\n\nFor Talos machines booted of the Image Factory artifacts, this means that the schematic ID will be published as the annotation\n`extensions.talos.dev/schematic` (as it is longer than 63 characters).\n\n\n### DNS Forwarding for CoreDNS pods\n\nUsage of the host DNS resolver as upstream for Kubernetes CoreDNS pods is now enabled by default. You can disable it\nwith:\n\n```yaml\nmachine:\n  features:\n    hostDNS:\n      enabled: true\n      forwardKubeDNSToHost: false\n```\n\nPlease note that on running cluster you will have to kill CoreDNS pods for this change to apply.\n\nThe IP address used to forward DNS queries has changed to the fixed `169.254.116.108` address.\nFor those upgrading from Talos 1.7 with `forwardKubeDNSToHost` enabled, the old Kubernetes service\ncan be cleaned up with `kubectl delete -n kube-system service host-dns`.\n\n\n### Installer\n\nTalos Linux installer now never wipes the system disk on upgrades, which means that the flag\n`--preserve` is always set for `talosctl upgrade`.\n\n\n### `talos.halt_if_installed` kernel argument\n\nStarting with Talos 1.8, ISO's generated from Boot Assets would have a new kernel argument `talos.halt_if_installed` which would pause the boot sequence until boot timeout if Talos is already installed on the disk.\nISO generated for pre 1.8 versions would not have this kernel argument.\n\nThis can be also explicitly enabled by setting `talos.halt_if_installed=1` in kernel argument.\n\n\n### Slim Kubelet Image\n\nKubelet container image includes various utilities that kubelet might use to perform various tasks.\n\nStarting with Kubernetes 1.31.0, `kubelet` image now includes less utilities, as the in-tree CSI plugins were\nremoved in Kubernetes 1.31.0. This reduces `kubelet` image size and potential attack surface.\n\n For Kubernetes < 1.31.0, there will be two images built:\n\n* `v1.x.y` (default, fat)\n* `v1.x.y-slim` (slim)\n\nFor Kubernetes >= 1.31.0, there will be same two images built, but the\ndefault tag would point to slim image:\n\n* `v1.x.y` (default, slim)\n* `v1.x.y-fat` (fat)\n\n\n### Default Node Labels\n\nTalos Linux on config generation now adds a label `node.kubernetes.io/exclude-from-external-load-balancers` by default for the control plane nodes.\n\n\n### PCI Devices\n\nA list of PCI devices can now be obtained via `PCIDevices` resource, e.g. `talosctl get pcidevices`.\n\n\n### Metal images\n\nStarting with Talos 1.8, `console=ttyS0` kernel argument is removed from the metal images and installer. If running virtualized in QEMU (For eg: Proxmox), this can be added as an extra kernel argument if needed via Image Factory or using Imager.\n\nThis should fix slow boot or no console output issues on most bare metal hardware.\n\n\n### NVIDIA GPU Support\n\nStarting with Talos 1.8.0, SideroLabs would ships extensions for both LTS and Production versions of NVIDIA extensions.\nFor more details see the CHANGELOG of [extensions](https://github.com/siderolabs/extensions/releases).\n\nUpgrades with an exisiting schematic id from Image Factory would keep the existing LTS version of the NVIDIA extension.\n\n\n### Platform Support\n\nTalos Linux now supports Apache CloudStack platform.\n\n\n### kube-proxy\n\nTalos Linux configures kube-proxy >= v1.31.0 to use 'nftables' backend by default.\n\n\n### Secure Boot\n\nTalos Linux now can optionally include well-known UEFI (Microsoft) SecureBoot keys into the auto-enrollment UEFI database.\n\n\n### Custom Trusted Roots\n\nTalos Linux now supports adding [custom trusted roots](https://www.talos.dev/v1.8/talos-guides/configuration/certificate-authorities/) (CA certificates) via `TrustedRootsConfig` configuration documents.\n\n\n### Device Extra Settle Timeout\n\nTalos Linux now supports a kernel command line argument `talos.device.settle_time=3m` to set the device extra settle timeout to workaround issues with broken drivers.\n\n\n### Component Updates\n\nKubernetes: 1.31.0\nLinux: 6.6.47\ncontainerd: 2.0.0-rc.4\nrunc: 1.2.0-rc.2\netcd: 3.5.15\nFlannel: 0.25.6\nFlannel CNI plugin: 1.5.1\nCoreDNS: 1.1.13\n\nTalos is built with Go 1.22.6.\n\n\n### ZSTD Compression\n\nTalos Linux now compresses kernel and initramfs using ZSTD.\nLinux arm64 kernel is now compressed (previously it was uncompressed).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Noel Georgi\n* Utku Ozdemir\n* Artem Chernyshev\n* Dmitry Sharshakov\n* Justin Garrison\n* Spencer Smith\n* Steve Francis\n* Bernard Gütermann\n* Jean-Francois Roy\n* Konrad Eriksson\n* Serge Logvinov\n* doctor_ew\n* Amadeus Mader\n* Andrew Rynhard\n* Anthony ARNAUD\n* Attila Oláh\n* Birger J. Nordølum\n* Caleb Woodbine\n* Claus Albøge\n* Daniel Höxtermann\n* David Birks\n* Dean\n* Dennis Marttinen\n* Eddie Zaneski\n* Enrique Hernández Bello\n* EricMa\n* Evan Johnson\n* Fabian Topfstedt\n* Fredrik Lundhag\n* George Gaál\n* Grzegorz Rozniecki\n* Grzegorz Rożniecki\n* Igor Rzegocki\n* Josia Scheytt\n* Judah Rand\n* Marcel Richter\n* Marco Franssen\n* Marcus Förster\n* Matthias Riegler\n* Matthieu Mottet\n* Maxime Brunet\n* Michael Trip\n* Mike Beaumont\n* Nick Meyer\n* Nicklas Frahm\n* Ole-Magnus Sæther\n* Roman Ivanov\n* Ron Olson\n* Saravanan G\n* Simon-Boyer\n* Skyler Mäntysaari\n* Steve Fan\n* Steve Martinelli\n* Steven Fackler\n* Syoc\n* Tim Jones\n* USBAkimbo\n* Will Bush\n* cryptk\n* darox\n* dhaines-quera\n* leppeK\n* looklose\n\n### Changes\n<details><summary>279 commits</summary>\n<p>\n\n* [`6f7c3a8e5`](https://github.com/siderolabs/talos/commit/6f7c3a8e5c6311bf1a2f9b1cbc6cd02d48746e02) fix: build of talosctl on non-Linux arches\n* [`f0a59cec7`](https://github.com/siderolabs/talos/commit/f0a59cec71739dd377082b0279684bb6ce46a0db) release(v1.8.0-alpha.2): prepare release\n* [`c8aed3be4`](https://github.com/siderolabs/talos/commit/c8aed3be4db9f4a510ddddb4c4baeff83432ee1f) fix: correctly add console args for ttyS0\n* [`b453385bd`](https://github.com/siderolabs/talos/commit/b453385bd960cacc4baf43ff274a5c88e46d5f79) feat: support volume configuration, provisioning, etc\n* [`b6b16b35f`](https://github.com/siderolabs/talos/commit/b6b16b35fbccc861410f53bc29ad4cade962f1d6) chore: pause sequencer when talos installed and iso booted\n* [`eade0a9f2`](https://github.com/siderolabs/talos/commit/eade0a9f22f606f28241dbbcc92b93bea25aec6f) chore: bring in `uio` modules\n* [`81f9fcd9c`](https://github.com/siderolabs/talos/commit/81f9fcd9ce83c632dbbcbc1594605888d31e3ca3) fix: report errors correctly when pulling, fix EEXIST\n* [`b309e87b4`](https://github.com/siderolabs/talos/commit/b309e87b409fe5dd4a5579bee23879bb83bcb433) docs: fix invalid input in field user_data\n* [`c7474877a`](https://github.com/siderolabs/talos/commit/c7474877a46279a9f6330486a77b103c13216dae) docs: kubeProxyReplacement from \"disabled\" to \"false\"\n* [`be2ebf6b4`](https://github.com/siderolabs/talos/commit/be2ebf6b4d146d91cdfd7ba081d244775241bda8) chore: bump dependencies\n* [`88601bff4`](https://github.com/siderolabs/talos/commit/88601bff4e172841015761a5e74f01c5cb128069) chore: drop calico from interactive installer\n* [`106c17d0b`](https://github.com/siderolabs/talos/commit/106c17d0b5cdf3fa8f81f029e306cfd96f7ccfaf) chore: aarch64 qemu local secureboot support\n* [`da6263506`](https://github.com/siderolabs/talos/commit/da6263506ac772abe555e5937e2d21a517dc46cb) feat: update Flannel to v0.25.6\n* [`19a44c2b0`](https://github.com/siderolabs/talos/commit/19a44c2b0bd4a4f4a9910c49bfdd9838f1a2bc54) chore: drop console `ttyS0` argument\n* [`75cecb421`](https://github.com/siderolabs/talos/commit/75cecb4210ad0d6ef201dafd307b4d023ccd7d39) feat: add Apache Cloudstack support\n* [`951cf66fd`](https://github.com/siderolabs/talos/commit/951cf66fdc6201186ec44276b818136f2f19b3d6) feat: add Cisco fnic driver\n* [`2d3bc94bf`](https://github.com/siderolabs/talos/commit/2d3bc94bf1840848bfe7e9f814a9b523132349c2) fix(ci): fix broken tests\n* [`a9551b7ca`](https://github.com/siderolabs/talos/commit/a9551b7caa413b03d4ed9b249b0cc957dd7a6edc) fix: host DNS access with firewall enabled\n* [`4834a61a8`](https://github.com/siderolabs/talos/commit/4834a61a8e4e67f4da3d14708dc7c699a8d3bc7c) feat: report SELinux labels\n* [`8fe39eacb`](https://github.com/siderolabs/talos/commit/8fe39eacba0db6d9372047172cf68825d57d0195) chore: move csi tests as go test\n* [`e4f8cb854`](https://github.com/siderolabs/talos/commit/e4f8cb854fc47daaba0ba969c52cc39329ae2ae0) fix: merge extension service config files by `mountPath`\n* [`5ba1df469`](https://github.com/siderolabs/talos/commit/5ba1df469542df0d1971a8f5fdd686a7d274dfa3) chore: add java package to protos\n* [`823480800`](https://github.com/siderolabs/talos/commit/823480800480babe4460d4d1a7f6e2f0ba3ab904) fix: add missing host/nvme-rdma\n* [`5b4b64979`](https://github.com/siderolabs/talos/commit/5b4b64979e4563e981064749c1b161f748fd4ff2) fix: bump go-smbios for broken SMIOS tables\n* [`f57d1f07e`](https://github.com/siderolabs/talos/commit/f57d1f07e9a690237eeaaadc6314d6da225ed625) fix: add NVMe target kernel modules\n* [`5ff6cf82c`](https://github.com/siderolabs/talos/commit/5ff6cf82ca593a7b701584dd76abdd09d96eb22e) fix: drop /opt mount for containers/tink\n* [`3c0db34d8`](https://github.com/siderolabs/talos/commit/3c0db34d8507571e49c0c49b6b615cfbe9cc5195) docs: update kubespan docs\n* [`3041d9075`](https://github.com/siderolabs/talos/commit/3041d90751fde279fc4ea28e149c1057e50a6947) fix: always handle `PermissionDenied` in dashboard resource watches\n* [`36f83eea9`](https://github.com/siderolabs/talos/commit/36f83eea9f6baba358c1d98223a330b2cb26e988) chore: make qemu check flag consistent with code\n* [`fe52cb074`](https://github.com/siderolabs/talos/commit/fe52cb0749e2d6aaaf9dbd3fb2c134b94792c425) chore: update protoc-gen-doc\n* [`ee4290f68`](https://github.com/siderolabs/talos/commit/ee4290f6849722af82db3f6a62039d9a3316f840) fix: bind HostDNS to 169.254.x link-local address\n* [`c312a46f6`](https://github.com/siderolabs/talos/commit/c312a46f69940cf96ce6c52d840f9fa00a01b87b) chore: restructure k8s component health checks\n* [`e193e7db9`](https://github.com/siderolabs/talos/commit/e193e7db98cfa9bbb689513751a7da39d8db9d14) docs: fix incorrect path for openebs in documentation\n* [`beadbac21`](https://github.com/siderolabs/talos/commit/beadbac210da8da391d52e13fc096b28a2c2538a) docs: update Oracle Cloud Talos custom image docs\n* [`6f969e364`](https://github.com/siderolabs/talos/commit/6f969e3645edc9ba561d23e02383f2331064f8eb) chore: improve `cluster create` UX on aarch64\n* [`45cc8688a`](https://github.com/siderolabs/talos/commit/45cc8688a1c6a85665efb70ebf63ef7a3eb53213) chore: replace `if` blocks with `min`/`max` functions\n* [`a5bd770bf`](https://github.com/siderolabs/talos/commit/a5bd770bf923b7bf72759f6565e4dfd97e8d9bc6) fix: retry with another upstream if the previous failed\n* [`82e19f38a`](https://github.com/siderolabs/talos/commit/82e19f38ac276693610655fa7a8708bdd4521cc2) docs: add high-level overlay development guide\n* [`872599c9a`](https://github.com/siderolabs/talos/commit/872599c9a9ec9fbddd4820ba453ff29933525f14) chore: drop image assets from release\n* [`3c36c41a9`](https://github.com/siderolabs/talos/commit/3c36c41a91c95d9df3701b595a7b09285a390b71) feat: provide device extra settle timeout\n* [`9e348ef35`](https://github.com/siderolabs/talos/commit/9e348ef3501e95dc7c906c7d4d6df63f3c86715e) feat: update Kubernetes to 1.31.0\n* [`61a1c946b`](https://github.com/siderolabs/talos/commit/61a1c946bff11b2fb9f85dfe826dfd890eac4986) feat: bundle (some) CNI plugins with Talos core\n* [`091da163b`](https://github.com/siderolabs/talos/commit/091da163b77db1014048a56cba1acbb6264711fb) chore: support arm64 kexec from zboot kernel images\n* [`73511c1ef`](https://github.com/siderolabs/talos/commit/73511c1ef3600c813835d7afd852fda4280e2323) chore: fix release notes\n* [`2bf924c7b`](https://github.com/siderolabs/talos/commit/2bf924c7be8869f8da869850f1df0e4d82651960) feat: update ISO VolumeID with Talos version\n* [`9a33dce10`](https://github.com/siderolabs/talos/commit/9a33dce10502aa05826adcc9cd9b66d9781111b3) docs: fix the VMWare docs\n* [`12562c2d5`](https://github.com/siderolabs/talos/commit/12562c2d5eb5a92b199018383bde6af58795dd28) docs: fix talos version in vmware.sh\n* [`ee67da14c`](https://github.com/siderolabs/talos/commit/ee67da14c5c8ae3bedfb2d8e321c9e127d61f565) feat: scaleway routed ip\n* [`eba5dafb9`](https://github.com/siderolabs/talos/commit/eba5dafb9eba450863fb295a4215559f32576666) fix: add dns-resolve-cache to the support bundle\n* [`d4f8100bd`](https://github.com/siderolabs/talos/commit/d4f8100bd4fc7d4e14a070c3eff600a259684d9a) docs: fix default openebs folder\n* [`60e163d54`](https://github.com/siderolabs/talos/commit/60e163d545392d17639809980d3041ec6fd9af09) docs: fix typo in doc\n* [`98d9abdd0`](https://github.com/siderolabs/talos/commit/98d9abdd0eaef72c8964fc58551670a0ec78783c) chore(ci): fix cilium ci tests\n* [`beb9602e3`](https://github.com/siderolabs/talos/commit/beb9602e35cff1ff072d60c86e1bc3faa6f8c002) chore: bump github.com/docker/docker to v27.1.1+incompatible\n* [`0698a4921`](https://github.com/siderolabs/talos/commit/0698a4921ba29bd1088f89406dfc89744a47e175) docs: aws getting started re-write\n* [`4d7d7a589`](https://github.com/siderolabs/talos/commit/4d7d7a58955468b7bbe42bacd8f53c782d12e074) chore(ci): update nvidia integration tests\n* [`60e901c1d`](https://github.com/siderolabs/talos/commit/60e901c1dcfdd728c7497a3c0d0ae28e0adb0580) chore: document slim kubelet image\n* [`622d66a98`](https://github.com/siderolabs/talos/commit/622d66a98f4d4eb809ff8dcdb67563e1c6be9b68) chore: bump deps\n* [`f9f5e0ef5`](https://github.com/siderolabs/talos/commit/f9f5e0ef556c575acc1cab85fafc0d89a1a4b4cc) chore: fix k8s tests\n* [`2ac8d2274`](https://github.com/siderolabs/talos/commit/2ac8d2274fcc5c9fc398575da2ddabb36984455a) chore: support `unsupported` flag for mkfs\n* [`9b9159d1e`](https://github.com/siderolabs/talos/commit/9b9159d1e04d337dc3a51e41be57f4795e71255d) docs: update support matrix for nvidia drivers\n* [`9d3415850`](https://github.com/siderolabs/talos/commit/9d34158500a155a7065e259d68f588112c5834ea) fix: fix graph diffs in dashboard when node aliases are used\n* [`9a126d70e`](https://github.com/siderolabs/talos/commit/9a126d70e0adab35a028f219b872cfc90e8d70d6) chore: generate deepcopy for SecureBootAssets type\n* [`dff56d824`](https://github.com/siderolabs/talos/commit/dff56d8246a481b163e1f49477efef324a106334) chore: remove arch-specific etcd image tag\n* [`c9f1dece5`](https://github.com/siderolabs/talos/commit/c9f1dece5d967e210b699234d365c27b5c397788) feat: update Kubernetes to 1.31.0-rc.1\n* [`49831c56f`](https://github.com/siderolabs/talos/commit/49831c56fb10506bb0ea2546b1b09d924571fc6d) docs: replace removed Cilium/kubeProxyReplacement value\n* [`33a316369`](https://github.com/siderolabs/talos/commit/33a3163698084da3c43a5ea41c6600ab883b2ec9) docs: update aws.md for loop\n* [`e02bd2093`](https://github.com/siderolabs/talos/commit/e02bd20933b300f3b89ab9e9f385e23a0946eec8) feat: update Kubernetes to 1.31.0-rc.0\n* [`64914b086`](https://github.com/siderolabs/talos/commit/64914b086ca0d72720c2f416b4543a1ba250986e) chore: add test for crun extension\n* [`7a1c62b8b`](https://github.com/siderolabs/talos/commit/7a1c62b8bc63f10dbad7673c59b6f62a6c9497bd) feat: publish installed extensions as node labels/annotations\n* [`3f2058aba`](https://github.com/siderolabs/talos/commit/3f2058aba29c1e30c9daaadea54b0035811ce318) fix: update containerd configuration and settings\n* [`81bd20f5a`](https://github.com/siderolabs/talos/commit/81bd20f5ad007a5f9c464a2ec7f6ad863f1c7fa8) docs: remove deprecated jiva from openebs instructions\n* [`480ffb88a`](https://github.com/siderolabs/talos/commit/480ffb88aed33214f23d21c31130a63f7b66dafc) docs: fix the amd64 PXE boot script URL\n* [`20fe34dbd`](https://github.com/siderolabs/talos/commit/20fe34dbde2613ed2e95378c3ff637a62bc015e5) docs: fix docker getting started typo\n* [`0fd7dfd2a`](https://github.com/siderolabs/talos/commit/0fd7dfd2ae1d74a8d4ea9d7f130018e972fe6674) docs: update Equinix Guide\n* [`3d1474ac0`](https://github.com/siderolabs/talos/commit/3d1474ac0bb4df3184423a7dfa4f4d981799ac41) feat: update CoreDNS to 1.1.3\n* [`50e5f37ef`](https://github.com/siderolabs/talos/commit/50e5f37efb99ac2df2c58f9f5a248350eea1b594) chore: add test for apparmor\n* [`96492c097`](https://github.com/siderolabs/talos/commit/96492c0977e3a292336eb84d4e14563921896cb2) docs: extend multus configuration for Cilium\n* [`19aa44c54`](https://github.com/siderolabs/talos/commit/19aa44c54975f9f4d6c92b86c4dfb95a75d1adb0) fix: generate kubeconfig using proper types\n* [`240104e45`](https://github.com/siderolabs/talos/commit/240104e45fae2d8f80a3a229648a80b19f4dcbd0) feat: update Linux to 6.6.43\n* [`32db8db60`](https://github.com/siderolabs/talos/commit/32db8db606773daf2d75d261387e591da8477ef1) chore: lock microsoft secureboot certs\n* [`3ce5492f8`](https://github.com/siderolabs/talos/commit/3ce5492f852c4e4e07d02c9a93f0b0fffcb00184) feat: runc memfd-bind service\n* [`341b55cd3`](https://github.com/siderolabs/talos/commit/341b55cd37d2225b163d92aa920965a7bca5d0a4) docs: update vmware.sh\n* [`117628aa6`](https://github.com/siderolabs/talos/commit/117628aa60c16e5b7a4102b71965cb0e77f95279) chore: add test for gvisor extension with platform kvm\n* [`fd01571c4`](https://github.com/siderolabs/talos/commit/fd01571c4037513fdb6287a8769dfbe46e9ed4b9) feat: update Linux, enable Broadcom MPI3 driver\n* [`b333ec07d`](https://github.com/siderolabs/talos/commit/b333ec07d96a27c721c07fd5c3ac29daec58690c) feat: update etcd to 3.5.15, Flannel to 0.25.5\n* [`087290178`](https://github.com/siderolabs/talos/commit/0872901783785239920d4f484a2ab1e224f84b6f) feat: use ethtool ioctl to get link status when netlink api not available\n* [`395c64290`](https://github.com/siderolabs/talos/commit/395c642909765da17ed44771a08290c15a8b052c) docs: update openebs-jiva helm repo\n* [`f132d3f40`](https://github.com/siderolabs/talos/commit/f132d3f40320904d3a420ca94b8f95718075c251) chore(ci): remove artifacts directory prefix for checksums\n* [`fd54dc191`](https://github.com/siderolabs/talos/commit/fd54dc191d06305d7b5fbfe71cd937e7f95d4f10) feat(talosctl): append microsoft secure boot certs\n* [`fd6ddd11e`](https://github.com/siderolabs/talos/commit/fd6ddd11ef810f92190fe0d7490f2314ce21d595) feat: provide POD_IP env var to scheduler and controller-manager\n* [`407347a7a`](https://github.com/siderolabs/talos/commit/407347a7a0a955d2ea610ca06ebab4593ff0c03c) feat: update Kubernetes to 1.31.0-beta.0\n* [`1b8c9ccbb`](https://github.com/siderolabs/talos/commit/1b8c9ccbb0285b678466f2b8eb7e5931bc8d44e4) fix: enforce secureboot enroll option only for supported releases\n* [`d52b89cb9`](https://github.com/siderolabs/talos/commit/d52b89cb91be238da08dd50d0cdd2ee50d93ed45) chore: ensure tls required on s3 buckets\n* [`c288ace7b`](https://github.com/siderolabs/talos/commit/c288ace7b185cd3fad569c0848afbda7217ac269) fix: be more smart when merging DNS resolver config\n* [`d983e4430`](https://github.com/siderolabs/talos/commit/d983e44308b677b07d2d135f0e73349cfb7e0ca8) fix: panic on shutdown\n* [`01404edff`](https://github.com/siderolabs/talos/commit/01404edff970888c968ff1b77d7dbd76cb724094) chore: reduce memory requirement for contrplane nodes\n* [`980f9ebc0`](https://github.com/siderolabs/talos/commit/980f9ebc07256280c74c6da8d473b49d0739a420) fix: fix log format in cluster provisioning\n* [`ea626a963`](https://github.com/siderolabs/talos/commit/ea626a96313dc8b56bd6256e0aae4b3a6c69f5be) feat: add label 'exclude-from-external-load-balancers' for cp nodes\n* [`1cf76cfbc`](https://github.com/siderolabs/talos/commit/1cf76cfbc28af980665e57d756c2e3ac002f5d8e) docs: fix talosctl spelling\n* [`b07338f54`](https://github.com/siderolabs/talos/commit/b07338f5471363457da94286cae6ef8075561aa2) feat: provide machine config document to update trusted CA roots\n* [`f14c4795e`](https://github.com/siderolabs/talos/commit/f14c4795e5e60bf564d584a707e261bed78bcaf8) fix: sort ports and merge adjacent ones in the nft rule\n* [`cf5effabb`](https://github.com/siderolabs/talos/commit/cf5effabb209fb570f59ba305bdab0b6409c7b93) feat: provide an option to enforce SecureBoot for TPM enrollment\n* [`736c1485e`](https://github.com/siderolabs/talos/commit/736c1485e27a597b8bf720b2dba4f8664cb9321a) fix: change the UEFI firmware search path order\n* [`a727a1d97`](https://github.com/siderolabs/talos/commit/a727a1d97a22001eb8b1ef3f9f22fc39a653ad09) chore: make using action tracker easier\n* [`0aebeff35`](https://github.com/siderolabs/talos/commit/0aebeff3560e276fb7ee984b5362b80ad5873c0f) docs: add missing backslashes\n* [`398151e64`](https://github.com/siderolabs/talos/commit/398151e64fb6490a8dc3e828fcc8a191857e41d4) fix: remove host bind mount for `/tmp` for trustd\n* [`ce4c404e1`](https://github.com/siderolabs/talos/commit/ce4c404e144deffe8b6a52488453c157f23497dd) chore: redo FilterMessages as generic function\n* [`fbde9c556`](https://github.com/siderolabs/talos/commit/fbde9c556f0107734ff1216ea80d9156c35d4e3c) chore: bump deps\n* [`3bab15214`](https://github.com/siderolabs/talos/commit/3bab15214de985b7738250f2a6d84a796c5e9253) feat: update Kubernetes to 1.31.0-alpha.3\n* [`c2a5213ee`](https://github.com/siderolabs/talos/commit/c2a5213eefa6dc977ded541316c96f516ea2ecfb) docs: add note about mayastor nvme_tcp init container check\n* [`dad9c40c7`](https://github.com/siderolabs/talos/commit/dad9c40c736d55dee05d4b74e94db610dd119ce2) chore: simplify code\n* [`963612bcc`](https://github.com/siderolabs/talos/commit/963612bccaead87d5bbb4b79014d5f9821eeb95e) chore: redo EncodeString and EncodeBytes using buffer interface\n* [`d9db360ab`](https://github.com/siderolabs/talos/commit/d9db360ab47b24dd5bccf3a36c938e5e648ff095) fix: properly output multi-doc machine config in `get mc`\n* [`31af6b3f8`](https://github.com/siderolabs/talos/commit/31af6b3f8cc11ae0336c6e7d65a460aff4a71a1f) chore: fix the release step to include CNI bundle\n* [`d7cd46643`](https://github.com/siderolabs/talos/commit/d7cd46643dc4461891af883fc86d2faff321855f) chore: fix the push/tag steps\n* [`c9aeeca3d`](https://github.com/siderolabs/talos/commit/c9aeeca3d47fb235cd013e10da55c296e532c1c3) chore: fix the Makefile\n* [`48cdbe0de`](https://github.com/siderolabs/talos/commit/48cdbe0de78041f97ca433ce7c8975ec56e262f2) release(v1.8.0-alpha.1): prepare release\n* [`2512ef435`](https://github.com/siderolabs/talos/commit/2512ef435f0bfb1ffcf7da12c57d7812d9ea207c) test: fix the integrtion tests for apply-config\n* [`076f3c4f2`](https://github.com/siderolabs/talos/commit/076f3c4f20006f732fa07ada14f45458dc65a9e8) chore: improve link spec controller code\n* [`0454130ad`](https://github.com/siderolabs/talos/commit/0454130ad97a61624fb0b916bf14a51dce8f199d) feat: suppress controller runtime first N failures on the console\n* [`3d35e5468`](https://github.com/siderolabs/talos/commit/3d35e54683b4930fa716c7afe6ecbad2af2f700b) chore: update hydrophone library\n* [`1f28726d4`](https://github.com/siderolabs/talos/commit/1f28726d46953262f33c91082528cd190f53b143) chore: support version with and without `v` prefix\n* [`9a56b8527`](https://github.com/siderolabs/talos/commit/9a56b8527b81c9653f5d01386c66ec1bde5d730a) chore(ci): fix parallel runs of tf pipelines\n* [`be35f380c`](https://github.com/siderolabs/talos/commit/be35f380ccf09d7667c3221765d6927546cffbca) chore: update pkgs/tools/extras\n* [`93df23444`](https://github.com/siderolabs/talos/commit/93df2344451e8f370f7f1d0f9590f65d6b02b936) docs: update opengraph image for main landing pages\n* [`d9d62d4da`](https://github.com/siderolabs/talos/commit/d9d62d4da6e30ac8f97a06dafd362a9e2ddc7006) feat: update Linux to 6.6.36\n* [`6b0fe5b8c`](https://github.com/siderolabs/talos/commit/6b0fe5b8ca9aa11d195b4b66608ad179bca7be44) docs: update deploying cilium docs for v1.7 and v1.8\n* [`52611a90d`](https://github.com/siderolabs/talos/commit/52611a90d870a131084375015d4d7270fa32cde8) feat: update Kubernetes to v1.30.2\n* [`c19cc4ccb`](https://github.com/siderolabs/talos/commit/c19cc4ccbc8c37b6dde49853dfc442a0f5404ab4) docs: clarify direct access needed to nodes in insecure mode\n* [`b4c871e4b`](https://github.com/siderolabs/talos/commit/b4c871e4b74014553ab81f7ff593ff7fa736df2d) chore: bump dependencies\n* [`cc345c8c9`](https://github.com/siderolabs/talos/commit/cc345c8c9413692148360684390c910de9e94748) feat: add support for configuring vlan filtering on the bridge\n* [`2d054ad35`](https://github.com/siderolabs/talos/commit/2d054ad3551428d8b3d93c8356b38aec7e9225eb) chore: handle documents diff in `apply-config` dry run\n* [`bd34f71f3`](https://github.com/siderolabs/talos/commit/bd34f71f3e5eae34907951a6480e0559736bfd72) feat: add apparmor pkg\n* [`71857fd4d`](https://github.com/siderolabs/talos/commit/71857fd4d3a262a6b41cad3af7d3abb7355d8509) docs: fix typo: `messure` -> `measure`\n* [`f75f16b0a`](https://github.com/siderolabs/talos/commit/f75f16b0a8088ac47a47c9ebabdf4803db5a397e) chore(ci): fix cluster name generation\n* [`c603d2bf9`](https://github.com/siderolabs/talos/commit/c603d2bf9552ed169e5baf012ad44305a54056a4) chore: output more info when `ExecuteCommandInPod` fails\n* [`4b5a7445e`](https://github.com/siderolabs/talos/commit/4b5a7445e9c3f7f2f53e958f6c2e91a1a86c2641) docs: fix missing Akamai platform in supported matrix\n* [`4701498a1`](https://github.com/siderolabs/talos/commit/4701498a1b5a213816962fb1acb56192423f525f) chore(ci): run e2e-aws-nvidia with zfs extension enabled\n* [`86a3222ae`](https://github.com/siderolabs/talos/commit/86a3222aeecb895cab233a0cd2474189f79a6f12) chore: use new disks api for iscsi tests\n* [`5ffc3f14b`](https://github.com/siderolabs/talos/commit/5ffc3f14bd2b49a2ee09f36fe9e66bcf7b5283e8) feat: show siderolink status on dashboard\n* [`6f6a5d105`](https://github.com/siderolabs/talos/commit/6f6a5d10573028662448a57c66c2255bb7703319) chore: upgrade to rtnetlink/v2 library\n* [`1fb8453c2`](https://github.com/siderolabs/talos/commit/1fb8453c2db1659dd6c1670e4174125b26e777c5) chore: update Go modules\n* [`8e15621e8`](https://github.com/siderolabs/talos/commit/8e15621e83a1005c3b7d8d682652f984765996c1) chore(ci): add conformance pipelines\n* [`7fcb521a6`](https://github.com/siderolabs/talos/commit/7fcb521a6a2d14de02926489d7297cf9429c7b38) feat: use hydrophone instead of sonobuoy\n* [`d1a0c1f98`](https://github.com/siderolabs/talos/commit/d1a0c1f983281593b4e6a71e2110ae9f81890edc) test: fix the integration test for no META name\n* [`535006334`](https://github.com/siderolabs/talos/commit/5350063340a80b99a8866afb94ac8673dd4e7ace) chore: fix our dns server implementation\n* [`c6f90d014`](https://github.com/siderolabs/talos/commit/c6f90d01493454bcf3281c9532b61fcb7e3dbb24) chore: replace sync.Map with concurrent.HashTrieMap\n* [`e8ced2c2d`](https://github.com/siderolabs/talos/commit/e8ced2c2ddc9e3f61138dd566628f7d11cf90c76) chore: drop k8s timeout in the default kubeconfig\n* [`7cbdce73f`](https://github.com/siderolabs/talos/commit/7cbdce73f74351954e506303ed9964b9668a3b40) fix: detect CD devices, fix user disks wipe test\n* [`aca475c66`](https://github.com/siderolabs/talos/commit/aca475c66509fa1fa7e7a0ca1b2a29f6542637fc) chore: small usability fixes\n* [`26cf566dc`](https://github.com/siderolabs/talos/commit/26cf566dc8c53263cbaae72855995e418da0852b) chore: bump our coredns fork\n* [`5e66e117e`](https://github.com/siderolabs/talos/commit/5e66e117e2ec19527fe949bf2d689df90835d63f) fix: initial assignment of Hetzner Cloud Alias IP\n* [`f07b79f4a`](https://github.com/siderolabs/talos/commit/f07b79f4a8c647d358b8cd41b3704eccf0341d33) feat: provide disk detection based on new blockdevices\n* [`8ee087268`](https://github.com/siderolabs/talos/commit/8ee087268317a73dc240c2b7569c2dab8d9df142) chore(ci): drop crashdump, save logs as artifacts\n* [`7c9a14383`](https://github.com/siderolabs/talos/commit/7c9a14383ee034b05cb9bd1ff49f8078cbbf5e66) fix: volume discovery improvements\n* [`80ca8ff71`](https://github.com/siderolabs/talos/commit/80ca8ff7135b0950b83d2ceaa32ee1eacce049e0) fix: update the cgroups for Talos core services\n* [`fe317f1e1`](https://github.com/siderolabs/talos/commit/fe317f1e1611d2f48595bfaf67c5e4ea3cd692e3) docs: fix typo in QEMU guest agent support on Proxmox\n* [`8dbe2128a`](https://github.com/siderolabs/talos/commit/8dbe2128a909a38ead8b6dfe1cc99e1ae36078d2) feat: implement Talos diagnostics\n* [`357d7754f`](https://github.com/siderolabs/talos/commit/357d7754fd739e9e875d17e0f8e63c333553090e) fix: clean up VM runners on cluster destroy\n* [`41f92e0ba`](https://github.com/siderolabs/talos/commit/41f92e0ba46b8ad9ddc3a4eabe86be915dea6b8e) chore: update Go to 1.22.4, other updates\n* [`4621e9bb7`](https://github.com/siderolabs/talos/commit/4621e9bb770e2a45c7c1ea8da76cbdabf76a4671) chore: add stale and lock issue workflows\n* [`82d9cd322`](https://github.com/siderolabs/talos/commit/82d9cd32298431760aef67f553924e4b4f48e207) fix: add upgrade errata for arm64/zboot kernels\n* [`9a23d846c`](https://github.com/siderolabs/talos/commit/9a23d846c1f6a88c30ffe55d2bf5a21d6cee150e) fix: downgrade Azure IMDS required version\n* [`30860210c`](https://github.com/siderolabs/talos/commit/30860210cce628839e97b8ece7edf90300556ed7) test: fix hardware test not to require PCI devices\n* [`9fcc9b841`](https://github.com/siderolabs/talos/commit/9fcc9b84152cb186324c13e317575f6da8b7bfa6) feat: update Flannel to v0.25.3\n* [`9d395b9de`](https://github.com/siderolabs/talos/commit/9d395b9de94f28fb9bf56bf795f916f783a847a0) chore: use bun instead of npm\n* [`a1684bdf8`](https://github.com/siderolabs/talos/commit/a1684bdf8f24858942cf61bee1efc81f7ef76f85) chore: speed up go generate for enumer\n* [`4dd0aa712`](https://github.com/siderolabs/talos/commit/4dd0aa7120b52cab5de219010f2b78b7dd9b73ce) feat: implement PCI device bus enumeration\n* [`b0466e0ab`](https://github.com/siderolabs/talos/commit/b0466e0abf2f8af43f3fb6c9661f44000fe1d54b) fix: disable kexec on GCP/Azure\n* [`911c25574`](https://github.com/siderolabs/talos/commit/911c255742d02440806e5f3df6967c091bb5288e) chore: fix go.work resolution\n* [`2f088ede0`](https://github.com/siderolabs/talos/commit/2f088ede0952d72dbb7bf33dd0510cb8ff8b8e3a) docs: add another example for installing cilium\n* [`3967e0777`](https://github.com/siderolabs/talos/commit/3967e07777707fa8af339f46596b678e1eaaa9f2) feat: update etcd to 3.5.14\n* [`3367ded9f`](https://github.com/siderolabs/talos/commit/3367ded9feac84e9c6c1f3efcea9e61f3083b4ac) fix: correct time adjustment in `time.SyncController`\n* [`893e64fcb`](https://github.com/siderolabs/talos/commit/893e64fcb1f09efed990b9b642359d7bcabffd42) fix: replace `nslookup` with `dig` in integration tests\n* [`0359c8537`](https://github.com/siderolabs/talos/commit/0359c8537c1b3b01e94394604e16fd817b986f9e) chore: unify toml packages being used\n* [`4feb94ca0`](https://github.com/siderolabs/talos/commit/4feb94ca099746e3a90106522b920a77cfe77ce0) feat: add multidoc check to the Talos quirks module\n* [`0b4a9777f`](https://github.com/siderolabs/talos/commit/0b4a9777fc2ddcc61430db23837455ff383ba1a3) docs: update talosctl install instructions for 1.8\n* [`da8305ffb`](https://github.com/siderolabs/talos/commit/da8305ffb46d285662bca12ec02760d6121342c8) test: add a test for watchdog timers\n* [`da7f27640`](https://github.com/siderolabs/talos/commit/da7f2764092b883bcdf5daf81b8f6f7ef997ac0a) fix: mount `tracefs` filesystem\n* [`7b37e5b63`](https://github.com/siderolabs/talos/commit/7b37e5b63d54c2d197336e4fbee941fa5f2423c0) chore(ci): fix integration extensions\n* [`de7553d77`](https://github.com/siderolabs/talos/commit/de7553d77f7e02a83f764820a71badbf0d851bc9) fix(ci): cron jobs\n* [`eb510d9fd`](https://github.com/siderolabs/talos/commit/eb510d9fdf3a40b2ae881e3dd19a94058d4ef529) chore: require enabled bootloader for docker provisioner\n* [`a9cf9b789`](https://github.com/siderolabs/talos/commit/a9cf9b78921bef76b66aa5fa5940977767124bfe) fix: correctly handle dns messages in our dns implementation\n* [`c2b19dcb9`](https://github.com/siderolabs/talos/commit/c2b19dcb978ab015bd9b3c5a4eb47a53ee25e297) chore: move to containerd 2.0 API\n* [`92a274e9a`](https://github.com/siderolabs/talos/commit/92a274e9a0a83b3e240784bf12817f08559ac8e8) fix: workaround problems with udevd races\n* [`31b24ea3d`](https://github.com/siderolabs/talos/commit/31b24ea3d70f88d031d81bd0f914754b0cee411e) chore(ci): split integration misc\n* [`8a1371337`](https://github.com/siderolabs/talos/commit/8a1371337faea406c9193e91c8de8ffc056b5135) fix: produce stable order of bonds with equinix\n* [`6406193f4`](https://github.com/siderolabs/talos/commit/6406193f4637157c3d31219dc2c39aca7fa736a4) test: add Equnix Metal sample metadata with two bonds\n* [`01ea82053`](https://github.com/siderolabs/talos/commit/01ea82053e0a2ffe4193243e235aae2ade0e2d88) fix: time sync over NTP from future era\n* [`5aea42427`](https://github.com/siderolabs/talos/commit/5aea4242782d4ff00ba51e85422fbdf7c2ceca64) fix(ci): fix crons by setting up buildx always\n* [`84706c3e2`](https://github.com/siderolabs/talos/commit/84706c3e2920b9bf68c7b6dcfb73f1e16f3f656b) docs: default to brew docs for talosctl\n* [`fcd65ff65`](https://github.com/siderolabs/talos/commit/fcd65ff65ce78aa5ebe7ca4b12aea2571bd54c49) feat: enable forwardKubeDNSToHost by default\n* [`2e64e9e4e`](https://github.com/siderolabs/talos/commit/2e64e9e4e026817f844765b4c8a7d346d85bf983) fix: require accepted CAs on worker nodes\n* [`23c1c4560`](https://github.com/siderolabs/talos/commit/23c1c4560ecd2084e505a64b0b701707aa79c5e6) fix(ci): fix crons fby rekres\n* [`2d50392c5`](https://github.com/siderolabs/talos/commit/2d50392c5a16a97a2daa47edcfd362b0891c4a06) feat: update containerd to 2.0.0-rc.2, runc to 1.2.0-rc.1\n* [`a12e4bb24`](https://github.com/siderolabs/talos/commit/a12e4bb24e19701e926103753ec3ee0f98e8d3a2) chore(ci): fix github action crons\n* [`e7bd9cd2b`](https://github.com/siderolabs/talos/commit/e7bd9cd2bbbd337ef72adc2a3be5adc8b530cd6e) fix: decrease maximum negative ttl for dns responses\n* [`9c3ebad9f`](https://github.com/siderolabs/talos/commit/9c3ebad9fd7a62418fc6748364a23d27ff1c3ff7) chore(ci): kresify gh actions\n* [`ff60f6fde`](https://github.com/siderolabs/talos/commit/ff60f6fde6cb325b9f1f4801f658f4e9554c6c2b) refactor: make some of the extensions package public\n* [`ce8c86d64`](https://github.com/siderolabs/talos/commit/ce8c86d640949d24107d9057358b39c860fc1e70) fix: panic in osroot controller\n* [`e1711cd3c`](https://github.com/siderolabs/talos/commit/e1711cd3c9852137956f1cce7174b0a337d53b63) chore: stop using containerd package for cri namespace\n* [`d4307043f`](https://github.com/siderolabs/talos/commit/d4307043ffbfcadb5b67b12c95816c2a3a5819c3) fix: update go-tail library to fix 'short read' error\n* [`7cd13ef4a`](https://github.com/siderolabs/talos/commit/7cd13ef4a619fa5c13dc9ed147e6626ddcabbaf2) docs: add documentation on using Multus with Talos\n* [`4784da3ef`](https://github.com/siderolabs/talos/commit/4784da3ef88745d1ce38f1e49239c882c081e6fb) feat: use new circular buffer compressed chunks feature\n* [`78b48eb3a`](https://github.com/siderolabs/talos/commit/78b48eb3ae78ec9953104247ec73cafa26a61264) feat: include EDAC drivers\n* [`0bf2d69fb`](https://github.com/siderolabs/talos/commit/0bf2d69fbb2f2c1f693565243b46391da00d4dba) feat: update Kubernetes to 1.30.1\n* [`53f548913`](https://github.com/siderolabs/talos/commit/53f54891302b193bf35ede52af235457396e91ce) fix: increase host dns packet ttl for pods\n* [`dedb6d360`](https://github.com/siderolabs/talos/commit/dedb6d360d25e6d00d560ddb40563c2a5a95bb1f) fix: update github.com/siderolabs/siderolink to v0.3.7\n* [`43939f1a6`](https://github.com/siderolabs/talos/commit/43939f1a6e4b65cf9b64d1d09dc19df709a41275) docs: fix typos, add docker socket info\n* [`6663068bb`](https://github.com/siderolabs/talos/commit/6663068bbd1750fd57ddf9ca63b0f305d895b33b) chore: update project in GCP testing\n* [`b86edc677`](https://github.com/siderolabs/talos/commit/b86edc6776f77a65d3a254cf0f0d713ce7a9145e) chore: update office hours in talos repo\n* [`cfa25d22d`](https://github.com/siderolabs/talos/commit/cfa25d22dc30b877ea47ba1bfae3ca5f29977f1b) chore: remove docs prior to 1.0 from website navigation\n* [`120705459`](https://github.com/siderolabs/talos/commit/12070545996af3435454654500cd75a50111cca9) chore: handle I/O error for xfs_repair\n* [`b7afe2669`](https://github.com/siderolabs/talos/commit/b7afe2669b2a9a32ca37bbcc7a7e8af4879cf403) feat: update Linux 6.6.30\n* [`26519ceed`](https://github.com/siderolabs/talos/commit/26519ceed0c790abd851de310409baf6af89e2b7) docs: update proxmox.md\n* [`851b91a0e`](https://github.com/siderolabs/talos/commit/851b91a0e22055443eabace9b89a566e0cbec679) fix: don't enable hostDNS for versions of Talos which do not have it\n* [`42ac5cd0c`](https://github.com/siderolabs/talos/commit/42ac5cd0c2ef610f055afb208384e60fc9389e82) fix: check for `nil` machine config during installation\n* [`1d29111d4`](https://github.com/siderolabs/talos/commit/1d29111d4310cc16078248e66817843e6e740821) chore: update Go to 1.22.3\n* [`f4d7b9d9a`](https://github.com/siderolabs/talos/commit/f4d7b9d9a921cdaf33b9efdae1569dd921628270) feat: gather plaform dns names\n* [`0b0f9995a`](https://github.com/siderolabs/talos/commit/0b0f9995a6cd2b41f48dc867f4e0248284e53463) docs: add resource information, some grammar fixes\n* [`763dae250`](https://github.com/siderolabs/talos/commit/763dae2508242ee91a7e38e5962facb334691289) fix: add cluster name to the worker machine config\n* [`4aac5b4ec`](https://github.com/siderolabs/talos/commit/4aac5b4ec30f4a9ee0f2e4a4239b399357930b6c) feat: mount /sys/kernel/security into kubelet\n* [`817f18153`](https://github.com/siderolabs/talos/commit/817f18153f592f5bf38884f05aed2e4ce2fd3ad7) docs: remove mention of enabling KubePrism after v1.6\n* [`c08d79732`](https://github.com/siderolabs/talos/commit/c08d797326686434dc035de3ca40200293d74701) docs: fix the variable name typo\n* [`478b862b4`](https://github.com/siderolabs/talos/commit/478b862b4c38bd5a5ba1313a3779f9395e4ba38d) fix: do not fail cli action tracker when boot id cannot be read\n* [`be510f9eb`](https://github.com/siderolabs/talos/commit/be510f9eb2b84a88ce730fab36bf575c976efa8b) docs: fix grpc_tunnel value to true\n* [`b7b8a8d8f`](https://github.com/siderolabs/talos/commit/b7b8a8d8fa6335d3f0036c50792971adefe5e240) docs: add logs example for the certificate errors troubleshooting\n* [`8df5b85ec`](https://github.com/siderolabs/talos/commit/8df5b85ec7e8ca53fd73c9c095ee5c453d5c4e51) release(v1.8.0-alpha.0): prepare release\n* [`07f78182c`](https://github.com/siderolabs/talos/commit/07f78182c621296e6c694b64ead8f14695b2e3b7) fix: use a fresh context for etcd unlock\n* [`84cd7dbec`](https://github.com/siderolabs/talos/commit/84cd7dbec4ce01a8f80a855267e1c44dfc6dcacc) feat: update Linux to 6.6.29\n* [`70fdca6a4`](https://github.com/siderolabs/talos/commit/70fdca6a43abcb48030239047500fa8819f9346d) chore: update minimum hardware requirement for vmware ova\n* [`b690ffeb8`](https://github.com/siderolabs/talos/commit/b690ffeb899c4a133f98e212826830e3b320abe4) test: improve DNS resolver test stability\n* [`5aa0299b6`](https://github.com/siderolabs/talos/commit/5aa0299b6e3efefa7077aab5955526a5136b8761) style: use correct capitalization for openstack\n* [`4c0c626b7`](https://github.com/siderolabs/talos/commit/4c0c626b786f14c5eabdc65e88d2aae92829bf73) feat: use zstd compression in place of xz\n* [`98906ed6e`](https://github.com/siderolabs/talos/commit/98906ed6ea1afc5a758871a7c2d8251fccaef106) fix: use reboot delay only in case of error\n* [`05fd042bb`](https://github.com/siderolabs/talos/commit/05fd042bb3600541a8e2587b66b8b4c4e9f99c27) test: improve the reset integration tests\n* [`8cdf0f7cb`](https://github.com/siderolabs/talos/commit/8cdf0f7cb007790190197356355a16c8e427afab) docs: fix typo in Cilium instructions\n* [`dd1d279da`](https://github.com/siderolabs/talos/commit/dd1d279daa8c2a18c2477839b2c11e5f2f554693) fix: allow more flags in `talosctl cluster create --input-dir`\n* [`ef4394e58`](https://github.com/siderolabs/talos/commit/ef4394e586e42c4b5085299029a2aacb3b89502d) chore: update kernel and other packages\n* [`ccdb4c8b1`](https://github.com/siderolabs/talos/commit/ccdb4c8b10450aa7fb6c32b0559bda73746a03ed) chore: update google.golang.org/grpc to 1.63.2\n* [`c5b59df69`](https://github.com/siderolabs/talos/commit/c5b59df6976095aca5c4bac367084874242e9e80) fix: wait for devices to be discovered before probing filesystems\n* [`0821b9c50`](https://github.com/siderolabs/talos/commit/0821b9c50b86bf9f7d08a1ba7b177abb7e2568c4) feat: add `--non-masquerade-cidrs` flag to `talosctl cluster create`\n* [`2bf613ad3`](https://github.com/siderolabs/talos/commit/2bf613ad3bd1582b520b2f661b7e0bfab4207eed) fix: add endpoints for \"virtual\" `host-dns` service\n* [`f4163aefe`](https://github.com/siderolabs/talos/commit/f4163aefeda2bf91be36af45239716c53ec982b1) fix: bump priority of OpenStack routes if IPv6 and default gateway\n* [`6fbd1263c`](https://github.com/siderolabs/talos/commit/6fbd1263ccbe20857cca90b5f69906651caa4f54) feat: report process MAC labels\n* [`d46032821`](https://github.com/siderolabs/talos/commit/d460328210ee3beea1b98ea5f23fcda5c2e2fd44) fix: return proper value from Bridge.STP instead of plain nil\n* [`bac1d00c3`](https://github.com/siderolabs/talos/commit/bac1d00c35cb6e1407884298118ee7b4ffc5fdfa) chore: prepare for Talos 1.8\n* [`d6c8067e1`](https://github.com/siderolabs/talos/commit/d6c8067e15d8177c7394abad65b95ea98c597b9d) docs: make 1.7 docs the default\n* [`d7c3a0735`](https://github.com/siderolabs/talos/commit/d7c3a0735eab85dd24e86fe3e0872253067e8f10) docs: add what's new for v1.7\n* [`908f67fa1`](https://github.com/siderolabs/talos/commit/908f67fa15e0de507c2f69fac0851d42376a66ce) feat: add host dns support for resolving member addrs\n* [`0d20b637d`](https://github.com/siderolabs/talos/commit/0d20b637d68a581354361bbceecb90395f24fedb) feat: update Kubernetes to 1.30.0\n* [`ec69d7a78`](https://github.com/siderolabs/talos/commit/ec69d7a7855753e3e458f2cf7c211bf67e703220) chore: replace math/rand with math/rand/v2\n* [`89040ce43`](https://github.com/siderolabs/talos/commit/89040ce4329743fa2037fb1cf65d978801753dbe) chore: update go-blockdevice/v2 library to the latest version\n* [`0a785802e`](https://github.com/siderolabs/talos/commit/0a785802ea22071e67d7ec85944513e73624b1ac) fix: overlay installer operations\n* [`b1b63f658`](https://github.com/siderolabs/talos/commit/b1b63f658eba5cbb08cbd05af959c6d397662e05) fix: mark overlay installer executable\n* [`3433fa13b`](https://github.com/siderolabs/talos/commit/3433fa13bf555a871e76f8ce726d5afd141a16e1) feat: use container DNS when in container mode\n* [`5d07ac5a7`](https://github.com/siderolabs/talos/commit/5d07ac5a7db9d2291a86ee966ee704b30afea342) fix: close apid inter-backend connections gracefully for real\n* [`7ba18555b`](https://github.com/siderolabs/talos/commit/7ba18555b098ba2617efce2438d6bfbec1dc0041) docs: fix typos in Akamai and AWS platform docs\n* [`3dd1f4e88`](https://github.com/siderolabs/talos/commit/3dd1f4e88c22734f03f7609791558b8bbbae3756) chore: extract `pkg/imager/quirks` to `pkg/machinery`\n* [`78bc3a433`](https://github.com/siderolabs/talos/commit/78bc3a433e8b10839034bd40b73fcc720438b943) docs: update Cilium docs\n* [`831f3d39e`](https://github.com/siderolabs/talos/commit/831f3d39e9b030cd1bcd3313246ebccf34f34205) feat: update Flannel to v0.25.1\n* [`ea5b3ff0c`](https://github.com/siderolabs/talos/commit/ea5b3ff0c27cb033d525d172d4006e0645a924ba) feat: update Kubernetes to v1.30.0-rc.2\n* [`54dac5ed4`](https://github.com/siderolabs/talos/commit/54dac5ed40698b8886096c620ac19ed55a4b99a1) feat: update Linux 6.6.24, containerd 1.7.15\n* [`c51f146da`](https://github.com/siderolabs/talos/commit/c51f146daf3265bbeb4513c649938b2656ff1686) docs: update Akamai platform docs\n* [`9550f5ff7`](https://github.com/siderolabs/talos/commit/9550f5ff7a285df7c251df425e8f28d4c668224f) docs: fix getAuthenticationMethod and completePathFromNode docs\n* [`bfbd02abf`](https://github.com/siderolabs/talos/commit/bfbd02abfb1d84d14a73f1e247d62e728860d2f3) fix: assign different priority to IPv6 default gateway on OpenStack\n* [`c8f674bd3`](https://github.com/siderolabs/talos/commit/c8f674bd3d582f606848475bca3d22f309b2367c) test: add a test for 'spin' container runtime\n* [`5390ccd48`](https://github.com/siderolabs/talos/commit/5390ccd48c78e864f53cc45848772c931276380d) chore: replace []byte with string and use go:embed for templates\n* [`ba7cdc8c8`](https://github.com/siderolabs/talos/commit/ba7cdc8c8baf85e3015db4fa9e4446eaccf01115) chore: optimize DNSResolveCacheController\n* [`145f24063`](https://github.com/siderolabs/talos/commit/145f2406307e57a6f2eb1601d4f7d542d39a9f51) fix: don't modify a global map of profiles\n* [`6fe91ad9c`](https://github.com/siderolabs/talos/commit/6fe91ad9cf9f99401fc39a6ece24eed61f17b0e2) feat: provide Kubernets/Talos version compatibility for 1.8\n* [`909a5800e`](https://github.com/siderolabs/talos/commit/909a5800e4a9ada42288ae15992579e9acf6c372) fix: generate secureboot ISO .der certificate correctly\n* [`b0fdc3c8c`](https://github.com/siderolabs/talos/commit/b0fdc3c8caaf6ef756cdc4440dae45891bd96d01) fix: make static pods check output consistent\n* [`c6ad0fcce`](https://github.com/siderolabs/talos/commit/c6ad0fcceb8220f0bf96a45e131ba999cb723f79) fix: validate that workers don't get cluster CA key\n* [`3735add87`](https://github.com/siderolabs/talos/commit/3735add87cec47038a88ba641322c26cd487ac58) fix: reconnect to the logs stream in dashboard after reboot\n* [`9aa1e1b79`](https://github.com/siderolabs/talos/commit/9aa1e1b79b4a02902e0573c10e1c0bf71a2341af) fix: present all accepted CAs to the kube-apiserver\n* [`336e61174`](https://github.com/siderolabs/talos/commit/336e61174624741f697c77b98dd84ab9a7a749f4) fix: close the apid connection to other machines gracefully\n* [`ff2c427b0`](https://github.com/siderolabs/talos/commit/ff2c427b04963d69ba2eaa1084a0a078d742b9ac) fix: pre-create nftables chain to make kubelet use nftables\n* [`5622f0e45`](https://github.com/siderolabs/talos/commit/5622f0e450eda589f4b9a2af28b8517d08c2aae2) docs: change localDNS to hostDNS in release notes yaml section\n</p>\n</details>\n\n### Changes since v1.8.0-alpha.1\n<details><summary>113 commits</summary>\n<p>\n\n* [`6f7c3a8e5`](https://github.com/siderolabs/talos/commit/6f7c3a8e5c6311bf1a2f9b1cbc6cd02d48746e02) fix: build of talosctl on non-Linux arches\n* [`f0a59cec7`](https://github.com/siderolabs/talos/commit/f0a59cec71739dd377082b0279684bb6ce46a0db) release(v1.8.0-alpha.2): prepare release\n* [`c8aed3be4`](https://github.com/siderolabs/talos/commit/c8aed3be4db9f4a510ddddb4c4baeff83432ee1f) fix: correctly add console args for ttyS0\n* [`b453385bd`](https://github.com/siderolabs/talos/commit/b453385bd960cacc4baf43ff274a5c88e46d5f79) feat: support volume configuration, provisioning, etc\n* [`b6b16b35f`](https://github.com/siderolabs/talos/commit/b6b16b35fbccc861410f53bc29ad4cade962f1d6) chore: pause sequencer when talos installed and iso booted\n* [`eade0a9f2`](https://github.com/siderolabs/talos/commit/eade0a9f22f606f28241dbbcc92b93bea25aec6f) chore: bring in `uio` modules\n* [`81f9fcd9c`](https://github.com/siderolabs/talos/commit/81f9fcd9ce83c632dbbcbc1594605888d31e3ca3) fix: report errors correctly when pulling, fix EEXIST\n* [`b309e87b4`](https://github.com/siderolabs/talos/commit/b309e87b409fe5dd4a5579bee23879bb83bcb433) docs: fix invalid input in field user_data\n* [`c7474877a`](https://github.com/siderolabs/talos/commit/c7474877a46279a9f6330486a77b103c13216dae) docs: kubeProxyReplacement from \"disabled\" to \"false\"\n* [`be2ebf6b4`](https://github.com/siderolabs/talos/commit/be2ebf6b4d146d91cdfd7ba081d244775241bda8) chore: bump dependencies\n* [`88601bff4`](https://github.com/siderolabs/talos/commit/88601bff4e172841015761a5e74f01c5cb128069) chore: drop calico from interactive installer\n* [`106c17d0b`](https://github.com/siderolabs/talos/commit/106c17d0b5cdf3fa8f81f029e306cfd96f7ccfaf) chore: aarch64 qemu local secureboot support\n* [`da6263506`](https://github.com/siderolabs/talos/commit/da6263506ac772abe555e5937e2d21a517dc46cb) feat: update Flannel to v0.25.6\n* [`19a44c2b0`](https://github.com/siderolabs/talos/commit/19a44c2b0bd4a4f4a9910c49bfdd9838f1a2bc54) chore: drop console `ttyS0` argument\n* [`75cecb421`](https://github.com/siderolabs/talos/commit/75cecb4210ad0d6ef201dafd307b4d023ccd7d39) feat: add Apache Cloudstack support\n* [`951cf66fd`](https://github.com/siderolabs/talos/commit/951cf66fdc6201186ec44276b818136f2f19b3d6) feat: add Cisco fnic driver\n* [`2d3bc94bf`](https://github.com/siderolabs/talos/commit/2d3bc94bf1840848bfe7e9f814a9b523132349c2) fix(ci): fix broken tests\n* [`a9551b7ca`](https://github.com/siderolabs/talos/commit/a9551b7caa413b03d4ed9b249b0cc957dd7a6edc) fix: host DNS access with firewall enabled\n* [`4834a61a8`](https://github.com/siderolabs/talos/commit/4834a61a8e4e67f4da3d14708dc7c699a8d3bc7c) feat: report SELinux labels\n* [`8fe39eacb`](https://github.com/siderolabs/talos/commit/8fe39eacba0db6d9372047172cf68825d57d0195) chore: move csi tests as go test\n* [`e4f8cb854`](https://github.com/siderolabs/talos/commit/e4f8cb854fc47daaba0ba969c52cc39329ae2ae0) fix: merge extension service config files by `mountPath`\n* [`5ba1df469`](https://github.com/siderolabs/talos/commit/5ba1df469542df0d1971a8f5fdd686a7d274dfa3) chore: add java package to protos\n* [`823480800`](https://github.com/siderolabs/talos/commit/823480800480babe4460d4d1a7f6e2f0ba3ab904) fix: add missing host/nvme-rdma\n* [`5b4b64979`](https://github.com/siderolabs/talos/commit/5b4b64979e4563e981064749c1b161f748fd4ff2) fix: bump go-smbios for broken SMIOS tables\n* [`f57d1f07e`](https://github.com/siderolabs/talos/commit/f57d1f07e9a690237eeaaadc6314d6da225ed625) fix: add NVMe target kernel modules\n* [`5ff6cf82c`](https://github.com/siderolabs/talos/commit/5ff6cf82ca593a7b701584dd76abdd09d96eb22e) fix: drop /opt mount for containers/tink\n* [`3c0db34d8`](https://github.com/siderolabs/talos/commit/3c0db34d8507571e49c0c49b6b615cfbe9cc5195) docs: update kubespan docs\n* [`3041d9075`](https://github.com/siderolabs/talos/commit/3041d90751fde279fc4ea28e149c1057e50a6947) fix: always handle `PermissionDenied` in dashboard resource watches\n* [`36f83eea9`](https://github.com/siderolabs/talos/commit/36f83eea9f6baba358c1d98223a330b2cb26e988) chore: make qemu check flag consistent with code\n* [`fe52cb074`](https://github.com/siderolabs/talos/commit/fe52cb0749e2d6aaaf9dbd3fb2c134b94792c425) chore: update protoc-gen-doc\n* [`ee4290f68`](https://github.com/siderolabs/talos/commit/ee4290f6849722af82db3f6a62039d9a3316f840) fix: bind HostDNS to 169.254.x link-local address\n* [`c312a46f6`](https://github.com/siderolabs/talos/commit/c312a46f69940cf96ce6c52d840f9fa00a01b87b) chore: restructure k8s component health checks\n* [`e193e7db9`](https://github.com/siderolabs/talos/commit/e193e7db98cfa9bbb689513751a7da39d8db9d14) docs: fix incorrect path for openebs in documentation\n* [`beadbac21`](https://github.com/siderolabs/talos/commit/beadbac210da8da391d52e13fc096b28a2c2538a) docs: update Oracle Cloud Talos custom image docs\n* [`6f969e364`](https://github.com/siderolabs/talos/commit/6f969e3645edc9ba561d23e02383f2331064f8eb) chore: improve `cluster create` UX on aarch64\n* [`45cc8688a`](https://github.com/siderolabs/talos/commit/45cc8688a1c6a85665efb70ebf63ef7a3eb53213) chore: replace `if` blocks with `min`/`max` functions\n* [`a5bd770bf`](https://github.com/siderolabs/talos/commit/a5bd770bf923b7bf72759f6565e4dfd97e8d9bc6) fix: retry with another upstream if the previous failed\n* [`82e19f38a`](https://github.com/siderolabs/talos/commit/82e19f38ac276693610655fa7a8708bdd4521cc2) docs: add high-level overlay development guide\n* [`872599c9a`](https://github.com/siderolabs/talos/commit/872599c9a9ec9fbddd4820ba453ff29933525f14) chore: drop image assets from release\n* [`3c36c41a9`](https://github.com/siderolabs/talos/commit/3c36c41a91c95d9df3701b595a7b09285a390b71) feat: provide device extra settle timeout\n* [`9e348ef35`](https://github.com/siderolabs/talos/commit/9e348ef3501e95dc7c906c7d4d6df63f3c86715e) feat: update Kubernetes to 1.31.0\n* [`61a1c946b`](https://github.com/siderolabs/talos/commit/61a1c946bff11b2fb9f85dfe826dfd890eac4986) feat: bundle (some) CNI plugins with Talos core\n* [`091da163b`](https://github.com/siderolabs/talos/commit/091da163b77db1014048a56cba1acbb6264711fb) chore: support arm64 kexec from zboot kernel images\n* [`73511c1ef`](https://github.com/siderolabs/talos/commit/73511c1ef3600c813835d7afd852fda4280e2323) chore: fix release notes\n* [`2bf924c7b`](https://github.com/siderolabs/talos/commit/2bf924c7be8869f8da869850f1df0e4d82651960) feat: update ISO VolumeID with Talos version\n* [`9a33dce10`](https://github.com/siderolabs/talos/commit/9a33dce10502aa05826adcc9cd9b66d9781111b3) docs: fix the VMWare docs\n* [`12562c2d5`](https://github.com/siderolabs/talos/commit/12562c2d5eb5a92b199018383bde6af58795dd28) docs: fix talos version in vmware.sh\n* [`ee67da14c`](https://github.com/siderolabs/talos/commit/ee67da14c5c8ae3bedfb2d8e321c9e127d61f565) feat: scaleway routed ip\n* [`eba5dafb9`](https://github.com/siderolabs/talos/commit/eba5dafb9eba450863fb295a4215559f32576666) fix: add dns-resolve-cache to the support bundle\n* [`d4f8100bd`](https://github.com/siderolabs/talos/commit/d4f8100bd4fc7d4e14a070c3eff600a259684d9a) docs: fix default openebs folder\n* [`60e163d54`](https://github.com/siderolabs/talos/commit/60e163d545392d17639809980d3041ec6fd9af09) docs: fix typo in doc\n* [`98d9abdd0`](https://github.com/siderolabs/talos/commit/98d9abdd0eaef72c8964fc58551670a0ec78783c) chore(ci): fix cilium ci tests\n* [`beb9602e3`](https://github.com/siderolabs/talos/commit/beb9602e35cff1ff072d60c86e1bc3faa6f8c002) chore: bump github.com/docker/docker to v27.1.1+incompatible\n* [`0698a4921`](https://github.com/siderolabs/talos/commit/0698a4921ba29bd1088f89406dfc89744a47e175) docs: aws getting started re-write\n* [`4d7d7a589`](https://github.com/siderolabs/talos/commit/4d7d7a58955468b7bbe42bacd8f53c782d12e074) chore(ci): update nvidia integration tests\n* [`60e901c1d`](https://github.com/siderolabs/talos/commit/60e901c1dcfdd728c7497a3c0d0ae28e0adb0580) chore: document slim kubelet image\n* [`622d66a98`](https://github.com/siderolabs/talos/commit/622d66a98f4d4eb809ff8dcdb67563e1c6be9b68) chore: bump deps\n* [`f9f5e0ef5`](https://github.com/siderolabs/talos/commit/f9f5e0ef556c575acc1cab85fafc0d89a1a4b4cc) chore: fix k8s tests\n* [`2ac8d2274`](https://github.com/siderolabs/talos/commit/2ac8d2274fcc5c9fc398575da2ddabb36984455a) chore: support `unsupported` flag for mkfs\n* [`9b9159d1e`](https://github.com/siderolabs/talos/commit/9b9159d1e04d337dc3a51e41be57f4795e71255d) docs: update support matrix for nvidia drivers\n* [`9d3415850`](https://github.com/siderolabs/talos/commit/9d34158500a155a7065e259d68f588112c5834ea) fix: fix graph diffs in dashboard when node aliases are used\n* [`9a126d70e`](https://github.com/siderolabs/talos/commit/9a126d70e0adab35a028f219b872cfc90e8d70d6) chore: generate deepcopy for SecureBootAssets type\n* [`dff56d824`](https://github.com/siderolabs/talos/commit/dff56d8246a481b163e1f49477efef324a106334) chore: remove arch-specific etcd image tag\n* [`c9f1dece5`](https://github.com/siderolabs/talos/commit/c9f1dece5d967e210b699234d365c27b5c397788) feat: update Kubernetes to 1.31.0-rc.1\n* [`49831c56f`](https://github.com/siderolabs/talos/commit/49831c56fb10506bb0ea2546b1b09d924571fc6d) docs: replace removed Cilium/kubeProxyReplacement value\n* [`33a316369`](https://github.com/siderolabs/talos/commit/33a3163698084da3c43a5ea41c6600ab883b2ec9) docs: update aws.md for loop\n* [`e02bd2093`](https://github.com/siderolabs/talos/commit/e02bd20933b300f3b89ab9e9f385e23a0946eec8) feat: update Kubernetes to 1.31.0-rc.0\n* [`64914b086`](https://github.com/siderolabs/talos/commit/64914b086ca0d72720c2f416b4543a1ba250986e) chore: add test for crun extension\n* [`7a1c62b8b`](https://github.com/siderolabs/talos/commit/7a1c62b8bc63f10dbad7673c59b6f62a6c9497bd) feat: publish installed extensions as node labels/annotations\n* [`3f2058aba`](https://github.com/siderolabs/talos/commit/3f2058aba29c1e30c9daaadea54b0035811ce318) fix: update containerd configuration and settings\n* [`81bd20f5a`](https://github.com/siderolabs/talos/commit/81bd20f5ad007a5f9c464a2ec7f6ad863f1c7fa8) docs: remove deprecated jiva from openebs instructions\n* [`480ffb88a`](https://github.com/siderolabs/talos/commit/480ffb88aed33214f23d21c31130a63f7b66dafc) docs: fix the amd64 PXE boot script URL\n* [`20fe34dbd`](https://github.com/siderolabs/talos/commit/20fe34dbde2613ed2e95378c3ff637a62bc015e5) docs: fix docker getting started typo\n* [`0fd7dfd2a`](https://github.com/siderolabs/talos/commit/0fd7dfd2ae1d74a8d4ea9d7f130018e972fe6674) docs: update Equinix Guide\n* [`3d1474ac0`](https://github.com/siderolabs/talos/commit/3d1474ac0bb4df3184423a7dfa4f4d981799ac41) feat: update CoreDNS to 1.1.3\n* [`50e5f37ef`](https://github.com/siderolabs/talos/commit/50e5f37efb99ac2df2c58f9f5a248350eea1b594) chore: add test for apparmor\n* [`96492c097`](https://github.com/siderolabs/talos/commit/96492c0977e3a292336eb84d4e14563921896cb2) docs: extend multus configuration for Cilium\n* [`19aa44c54`](https://github.com/siderolabs/talos/commit/19aa44c54975f9f4d6c92b86c4dfb95a75d1adb0) fix: generate kubeconfig using proper types\n* [`240104e45`](https://github.com/siderolabs/talos/commit/240104e45fae2d8f80a3a229648a80b19f4dcbd0) feat: update Linux to 6.6.43\n* [`32db8db60`](https://github.com/siderolabs/talos/commit/32db8db606773daf2d75d261387e591da8477ef1) chore: lock microsoft secureboot certs\n* [`3ce5492f8`](https://github.com/siderolabs/talos/commit/3ce5492f852c4e4e07d02c9a93f0b0fffcb00184) feat: runc memfd-bind service\n* [`341b55cd3`](https://github.com/siderolabs/talos/commit/341b55cd37d2225b163d92aa920965a7bca5d0a4) docs: update vmware.sh\n* [`117628aa6`](https://github.com/siderolabs/talos/commit/117628aa60c16e5b7a4102b71965cb0e77f95279) chore: add test for gvisor extension with platform kvm\n* [`fd01571c4`](https://github.com/siderolabs/talos/commit/fd01571c4037513fdb6287a8769dfbe46e9ed4b9) feat: update Linux, enable Broadcom MPI3 driver\n* [`b333ec07d`](https://github.com/siderolabs/talos/commit/b333ec07d96a27c721c07fd5c3ac29daec58690c) feat: update etcd to 3.5.15, Flannel to 0.25.5\n* [`087290178`](https://github.com/siderolabs/talos/commit/0872901783785239920d4f484a2ab1e224f84b6f) feat: use ethtool ioctl to get link status when netlink api not available\n* [`395c64290`](https://github.com/siderolabs/talos/commit/395c642909765da17ed44771a08290c15a8b052c) docs: update openebs-jiva helm repo\n* [`f132d3f40`](https://github.com/siderolabs/talos/commit/f132d3f40320904d3a420ca94b8f95718075c251) chore(ci): remove artifacts directory prefix for checksums\n* [`fd54dc191`](https://github.com/siderolabs/talos/commit/fd54dc191d06305d7b5fbfe71cd937e7f95d4f10) feat(talosctl): append microsoft secure boot certs\n* [`fd6ddd11e`](https://github.com/siderolabs/talos/commit/fd6ddd11ef810f92190fe0d7490f2314ce21d595) feat: provide POD_IP env var to scheduler and controller-manager\n* [`407347a7a`](https://github.com/siderolabs/talos/commit/407347a7a0a955d2ea610ca06ebab4593ff0c03c) feat: update Kubernetes to 1.31.0-beta.0\n* [`1b8c9ccbb`](https://github.com/siderolabs/talos/commit/1b8c9ccbb0285b678466f2b8eb7e5931bc8d44e4) fix: enforce secureboot enroll option only for supported releases\n* [`d52b89cb9`](https://github.com/siderolabs/talos/commit/d52b89cb91be238da08dd50d0cdd2ee50d93ed45) chore: ensure tls required on s3 buckets\n* [`c288ace7b`](https://github.com/siderolabs/talos/commit/c288ace7b185cd3fad569c0848afbda7217ac269) fix: be more smart when merging DNS resolver config\n* [`d983e4430`](https://github.com/siderolabs/talos/commit/d983e44308b677b07d2d135f0e73349cfb7e0ca8) fix: panic on shutdown\n* [`01404edff`](https://github.com/siderolabs/talos/commit/01404edff970888c968ff1b77d7dbd76cb724094) chore: reduce memory requirement for contrplane nodes\n* [`980f9ebc0`](https://github.com/siderolabs/talos/commit/980f9ebc07256280c74c6da8d473b49d0739a420) fix: fix log format in cluster provisioning\n* [`ea626a963`](https://github.com/siderolabs/talos/commit/ea626a96313dc8b56bd6256e0aae4b3a6c69f5be) feat: add label 'exclude-from-external-load-balancers' for cp nodes\n* [`1cf76cfbc`](https://github.com/siderolabs/talos/commit/1cf76cfbc28af980665e57d756c2e3ac002f5d8e) docs: fix talosctl spelling\n* [`b07338f54`](https://github.com/siderolabs/talos/commit/b07338f5471363457da94286cae6ef8075561aa2) feat: provide machine config document to update trusted CA roots\n* [`f14c4795e`](https://github.com/siderolabs/talos/commit/f14c4795e5e60bf564d584a707e261bed78bcaf8) fix: sort ports and merge adjacent ones in the nft rule\n* [`cf5effabb`](https://github.com/siderolabs/talos/commit/cf5effabb209fb570f59ba305bdab0b6409c7b93) feat: provide an option to enforce SecureBoot for TPM enrollment\n* [`736c1485e`](https://github.com/siderolabs/talos/commit/736c1485e27a597b8bf720b2dba4f8664cb9321a) fix: change the UEFI firmware search path order\n* [`a727a1d97`](https://github.com/siderolabs/talos/commit/a727a1d97a22001eb8b1ef3f9f22fc39a653ad09) chore: make using action tracker easier\n* [`0aebeff35`](https://github.com/siderolabs/talos/commit/0aebeff3560e276fb7ee984b5362b80ad5873c0f) docs: add missing backslashes\n* [`398151e64`](https://github.com/siderolabs/talos/commit/398151e64fb6490a8dc3e828fcc8a191857e41d4) fix: remove host bind mount for `/tmp` for trustd\n* [`ce4c404e1`](https://github.com/siderolabs/talos/commit/ce4c404e144deffe8b6a52488453c157f23497dd) chore: redo FilterMessages as generic function\n* [`fbde9c556`](https://github.com/siderolabs/talos/commit/fbde9c556f0107734ff1216ea80d9156c35d4e3c) chore: bump deps\n* [`3bab15214`](https://github.com/siderolabs/talos/commit/3bab15214de985b7738250f2a6d84a796c5e9253) feat: update Kubernetes to 1.31.0-alpha.3\n* [`c2a5213ee`](https://github.com/siderolabs/talos/commit/c2a5213eefa6dc977ded541316c96f516ea2ecfb) docs: add note about mayastor nvme_tcp init container check\n* [`dad9c40c7`](https://github.com/siderolabs/talos/commit/dad9c40c736d55dee05d4b74e94db610dd119ce2) chore: simplify code\n* [`963612bcc`](https://github.com/siderolabs/talos/commit/963612bccaead87d5bbb4b79014d5f9821eeb95e) chore: redo EncodeString and EncodeBytes using buffer interface\n* [`d9db360ab`](https://github.com/siderolabs/talos/commit/d9db360ab47b24dd5bccf3a36c938e5e648ff095) fix: properly output multi-doc machine config in `get mc`\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`ca662d2`](https://github.com/siderolabs/discovery-client/commit/ca662d218418eb50eb22d84560c290bef4369702) feat: export default GRPC dial options for the client\n* [`7a767fa`](https://github.com/siderolabs/discovery-client/commit/7a767fa89005209f5f39b2f5891ca7b169f52d89) chore: bump Go, deps and rekres\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>7 commits</summary>\n<p>\n\n* [`43a2821`](https://github.com/siderolabs/extras/commit/43a2821da1783c4431a0494e853435a75451d687) feat: bump deps\n* [`6f4a373`](https://github.com/siderolabs/extras/commit/6f4a373cf517926dc9ac62045c05b5434acfb9ec) chore: use Go 1.22.6\n* [`e7d16d8`](https://github.com/siderolabs/extras/commit/e7d16d88e095a05b8ced99a272ece9d403452b45) chore: bump deps\n* [`cab51d8`](https://github.com/siderolabs/extras/commit/cab51d8f49fec77266b74d2535f61bf73bb8b2c4) feat: update dependencies\n* [`0efb05f`](https://github.com/siderolabs/extras/commit/0efb05f989d7e745f61955570992c54094d3fddf) feat: update Go to 1.22.4\n* [`01ad9f5`](https://github.com/siderolabs/extras/commit/01ad9f5e2aa7e0ef2b6d9e0a19e7bf6a39dd5d94) feat: update Go to 1.22.3\n* [`fa6663c`](https://github.com/siderolabs/extras/commit/fa6663c2abf90d82667a6c33cbc6f5edb2d1c525) feat: update Go to 1.22.2\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`7654108`](https://github.com/siderolabs/gen/commit/7654108fe6ae15d4765584342709bc0bced6b3d6) chore: add hashtriemap implementation\n* [`8485864`](https://github.com/siderolabs/gen/commit/84858640dc9c3032219380885283b995d4f2b0d1) chore: optimize maps.Values and maps.Keys\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>3 commits</summary>\n<p>\n\n* [`1b35ea8`](https://github.com/siderolabs/go-api-signature/commit/1b35ea8d3a334418aa273159ea5732ae0625a317) chore: bump deps and fix data race\n* [`4bf0f02`](https://github.com/siderolabs/go-api-signature/commit/4bf0f025dd94a8117997028d35c8b4497de497b4) fix: get rid of data race in the key sign interceptor\n* [`782aac0`](https://github.com/siderolabs/go-api-signature/commit/782aac0d69752fe7c6eba36bae8d1383ffdc0b04) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>3 commits</summary>\n<p>\n\n* [`cbce5c3`](https://github.com/siderolabs/go-circular/commit/cbce5c3e47d1c6a26a588cbb6f77af2f9bc3e5b7) feat: add persistence support\n* [`3c48c53`](https://github.com/siderolabs/go-circular/commit/3c48c53c1449b2b5e5ddde14e0351d93a351b021) feat: implement extra compressed chunks\n* [`835f04c`](https://github.com/siderolabs/go-circular/commit/835f04c9ba6083ef451b5bbba748200202d1a0a9) chore: rekres, update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`c8f9b12`](https://github.com/siderolabs/go-debug/commit/c8f9b12c041a3242472ad56b970487432552d2be) chore: add support for Go 1.23\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>2 commits</summary>\n<p>\n\n* [`ee8c6b8`](https://github.com/siderolabs/go-kubernetes/commit/ee8c6b8a5bb2c2c45e961d0f08faa5673905545c) fix: add one more removed feature gate for 1.31\n* [`37dd61f`](https://github.com/siderolabs/go-kubernetes/commit/37dd61fad48b9f4bb6bce5a0a361a247228e86d2) feat: add support for Kubernetes 1.31\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`0639758`](https://github.com/siderolabs/go-loadbalancer/commit/0639758a06785c0c8c65e18774b81d85ab40acdf) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/go-pcidb\n<details><summary>1 commit</summary>\n<p>\n\n* [`2e79017`](https://github.com/siderolabs/go-pcidb/commit/2e7901711733e2d7e5e5a767a68cae08df148dc5) feat: rekres, update PCI IDs\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>2 commits</summary>\n<p>\n\n* [`e781237`](https://github.com/siderolabs/go-smbios/commit/e781237bb6d0b04cfb9d380bc36b552f5ee53af2) fix: stop decoding without error if EOF encountered during header read\n* [`6a719a6`](https://github.com/siderolabs/go-smbios/commit/6a719a63dcd3b2c58ee14412973fa6a565e2905e) chore: rekres, bump deps\n</p>\n</details>\n\n### Changes from siderolabs/go-tail\n<details><summary>1 commit</summary>\n<p>\n\n* [`7cb7294`](https://github.com/siderolabs/go-tail/commit/7cb7294b8af33175bc463c84493776e6e4da9c4f) fix: remove unexpected short read error\n</p>\n</details>\n\n### Changes from siderolabs/go-talos-support\n<details><summary>3 commits</summary>\n<p>\n\n* [`58f4f0f`](https://github.com/siderolabs/go-talos-support/commit/58f4f0fde6be11e5d5da37ceaab52286b4b0be05) chore: bump Go dependencies\n* [`f9d46fd`](https://github.com/siderolabs/go-talos-support/commit/f9d46fd8a607a928dc0382f308ad577f36b0a8b8) fix: add `dns-resolve-cache` to the list of logs gathered\n* [`69891cf`](https://github.com/siderolabs/go-talos-support/commit/69891cf046628969e651fc751e433aad86ec22c4) chore: remove containerd dependency\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>5 commits</summary>\n<p>\n\n* [`ec3b59c`](https://github.com/siderolabs/grpc-proxy/commit/ec3b59c869000243e9794d162354c83738475a32) fix: address all gRPC deprecations\n* [`02f82db`](https://github.com/siderolabs/grpc-proxy/commit/02f82db9c921eea3a48184bc4a4cf83a98b5b227) chore: rekres, bump deps\n* [`62b29be`](https://github.com/siderolabs/grpc-proxy/commit/62b29beccb302d80e7a1b25acf86d755a769970b) chore: rekres, update dependencies\n* [`2decdd1`](https://github.com/siderolabs/grpc-proxy/commit/2decdd1f77e64b61761e27c077ec3a420bfb2781) chore: add no-op github workflow\n* [`77d7adc`](https://github.com/siderolabs/grpc-proxy/commit/77d7adc7105b6132b1352bf9e737bacc47fba5e5) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>56 commits</summary>\n<p>\n\n* [`4ce5bc6`](https://github.com/siderolabs/pkgs/commit/4ce5bc6bbb87f1feeabadc90ef304e4f16c6da8f) feat: add uio_pci_generic kernel module\n* [`18d3b85`](https://github.com/siderolabs/pkgs/commit/18d3b85b1cff5d239f02b4b2bdaedbc8e7958dd4) feat: add `uinput` kernel module\n* [`4fd2541`](https://github.com/siderolabs/pkgs/commit/4fd254154408d1d25d54e96dbf6ae4739e7766ac) feat: bump dependencies\n* [`467d127`](https://github.com/siderolabs/pkgs/commit/467d127922d96b213d7f077e04924e438e7adadf) feat: enable Cisco FCoE HBA Driver (fnic)\n* [`4e6dec2`](https://github.com/siderolabs/pkgs/commit/4e6dec2ee54486b7f38565da3cd90665d9706ddb) feat: enable more PCI options\n* [`5f919c5`](https://github.com/siderolabs/pkgs/commit/5f919c50624a91308667dedeb007c3f501e1fcaa) fix: add virtio-net GSO issue patch\n* [`7b2e46b`](https://github.com/siderolabs/pkgs/commit/7b2e46bafdb9c68f44c271c7a9628b2926604d20) feat: update Linux to 6.6.45\n* [`a6db229`](https://github.com/siderolabs/pkgs/commit/a6db229a8a9180695da0c2abbba074af193a79df) fix: strip CNI plugins\n* [`124d35b`](https://github.com/siderolabs/pkgs/commit/124d35b83988a9ab410fcef05fbb2f7379bddb41) chore: bump deps\n* [`af6b4e6`](https://github.com/siderolabs/pkgs/commit/af6b4e6ccfd37fec021892a434de75de02dca5d3) chore: bump nvidia drivers\n* [`5e8a15a`](https://github.com/siderolabs/pkgs/commit/5e8a15a85ac4c4d395a9e7fe5548576862f5e750) chore: bump deps\n* [`99650c8`](https://github.com/siderolabs/pkgs/commit/99650c8c7c0362477073dcd9cc598e0500c19c45) fix: enable TPROXY for nftables\n* [`75adbde`](https://github.com/siderolabs/pkgs/commit/75adbde1afac432b3674522bfdb88e75364bf7ce) feat: support lts and production nvidia modules\n* [`a97d58f`](https://github.com/siderolabs/pkgs/commit/a97d58f4b74a37604e8e330b4d4e0c79f7630d02) feat: add Intel management engine modules for Intel Arc support\n* [`4e940f8`](https://github.com/siderolabs/pkgs/commit/4e940f850745a0d6a934e06e4d425f11babf4b37) feat: update Linux to 6.6.43\n* [`7f9c802`](https://github.com/siderolabs/pkgs/commit/7f9c8026e042735002724db98b2bfe2968823fca) fix(kernel): array-index-out-of-bounds error on bpf\n* [`8cc6455`](https://github.com/siderolabs/pkgs/commit/8cc6455e1ff1c601a67e4a8a7d90db45020d1a3d) feat: add driver for Broadcom MPI3\n* [`d01fb35`](https://github.com/siderolabs/pkgs/commit/d01fb359b6ecbd6e8c9ee2ec9466c0ca5e0f51b5) feat: update Linux to 6.6.39\n* [`25f3a99`](https://github.com/siderolabs/pkgs/commit/25f3a99c543a1f6cc6259aa0326b7bfaa1d120dc) fix: update ca-certificates in pkgs\n* [`60a91b2`](https://github.com/siderolabs/pkgs/commit/60a91b2fcf9415b2caaaf10b98c5793ff3d858a6) fix: enable CONFIG_PROC_CHILDREN for amd64 kernel\n* [`ce49757`](https://github.com/siderolabs/pkgs/commit/ce497578fd6911be16848df71156558565616ac1) feat: update flannel-cni plugin to v1.5.1\n* [`289ed6b`](https://github.com/siderolabs/pkgs/commit/289ed6ba2de66c7230b154df9ca65581f7619055) feat: bump deps\n* [`8d6b19a`](https://github.com/siderolabs/pkgs/commit/8d6b19a8a15c6f0b8b76c0dc65657d10830bbf3a) feat: update Linux to 6.6.36\n* [`b671d46`](https://github.com/siderolabs/pkgs/commit/b671d4604db736c7ac541c40ba2c5deeaf03baee) feat: update containerd/runc to the next rc versions\n* [`c7e9591`](https://github.com/siderolabs/pkgs/commit/c7e9591dcdd18f94a391a329789fa2ddf93a509f) feat: enable CONFIG_X86_AMD_PSTATE\n* [`84bad89`](https://github.com/siderolabs/pkgs/commit/84bad890a6eed3b1fa2d01df494c26e695d5a290) feat: add 'apparmor' package\n* [`4d9869a`](https://github.com/siderolabs/pkgs/commit/4d9869a06f06cab4ed56b42b93974804f33b6435) feat: update Linux to 6.6.33\n* [`e5990e8`](https://github.com/siderolabs/pkgs/commit/e5990e87dc8e491adbe42df246f607eddd25af94) feat: enable CONFIG_KSM\n* [`a37f382`](https://github.com/siderolabs/pkgs/commit/a37f382b8c11a478d1015b9fd1042257684529bc) fix: network for Rockchip boards like Rock64\n* [`95218c7`](https://github.com/siderolabs/pkgs/commit/95218c7868047d7075465fb4e112975460acff00) fix: enable PAGE_TABLE_CHECK\n* [`cbd9cd7`](https://github.com/siderolabs/pkgs/commit/cbd9cd79a73ada392bc03f04dca2a982878ce2b6) feat: enable SCTP support\n* [`c309452`](https://github.com/siderolabs/pkgs/commit/c309452aefee22fbc3d714781b4cc880881e0a5d) feat: bump dependencies\n* [`3a56032`](https://github.com/siderolabs/pkgs/commit/3a56032bf8e49296cf4a02655925767ab9c8b1d2) chore: rekres\n* [`db7f60c`](https://github.com/siderolabs/pkgs/commit/db7f60c77b2effcfc5640fd50b871052e842b1eb) feat: bump Linux to 6.6.32\n* [`c647a05`](https://github.com/siderolabs/pkgs/commit/c647a0591741916e4bc28c35dc6a9cc36add65e0) feat: update ipxe to the latest\n* [`f350879`](https://github.com/siderolabs/pkgs/commit/f350879ba82443c662582d1b43e6d9fc06826c55) feat: update containerd to 2.0.0-rc.2, runc to 1.2.0-rc.1\n* [`f8392fb`](https://github.com/siderolabs/pkgs/commit/f8392fb597559eaf3e12c4284acc7805667e7f8e) feat: update Linux firmware to 20240513\n* [`f414bbd`](https://github.com/siderolabs/pkgs/commit/f414bbdb189e3ab880ee65efe2a030667aae77ec) fix: disable CONFIG_EFI_DISABLE_PCI_DMA option\n* [`9ebfd1b`](https://github.com/siderolabs/pkgs/commit/9ebfd1b90ed674a984eb69f03b6bc79f21573313) feat: enable EDAC drivers\n* [`f9559de`](https://github.com/siderolabs/pkgs/commit/f9559de4cb7961bd54745ddeb0ffb3414f7125aa) fix: drbd module installation\n* [`492638d`](https://github.com/siderolabs/pkgs/commit/492638d5d8242d733da4cf2a573380be1e780f2f) feat: update dependencies\n* [`bd70572`](https://github.com/siderolabs/pkgs/commit/bd70572339f6cc28dd88d0e4e28f079299268c8b) feat: update Go to 1.22.3\n* [`edb600a`](https://github.com/siderolabs/pkgs/commit/edb600aa02ff620217cc430bdc4a699d9c9eba82) feat: update zfs package to v2.2.4\n* [`6775002`](https://github.com/siderolabs/pkgs/commit/67750020042162af7fc01e5f14a678fc6eeaaf6b) feat: enable NFT FIB lookups\n* [`28c5696`](https://github.com/siderolabs/pkgs/commit/28c5696e7c97b12765e65bd1bb758f8cb19e6adc) feat: update Linux to 6.6.29\n* [`9c8a02c`](https://github.com/siderolabs/pkgs/commit/9c8a02c234b52cf3624ebf79f7e76065cbc1eeff) feat: update containerd to 1.7.16\n* [`ca6249b`](https://github.com/siderolabs/pkgs/commit/ca6249b4b7d00b6f16e1a7264f55a4814300df63) feat: compress amd64 Linux kernel using zstd\n* [`718a7da`](https://github.com/siderolabs/pkgs/commit/718a7da83fe843cd59745078fe1a814c75bc4384) feat: enable SELinux\n* [`207481f`](https://github.com/siderolabs/pkgs/commit/207481f7b16d2b0c98053432f4ad86484bf0b1ec) feat(intel): add support for power management and ACPI options for Intel CPUs\n* [`dfa7dce`](https://github.com/siderolabs/pkgs/commit/dfa7dceb5ae50af454f527ac7c774c93d00054cf) feat: update Linux to 6.6.28\n* [`7b30b61`](https://github.com/siderolabs/pkgs/commit/7b30b61ef3ba104f3ea21469632d3d043c5fd6f6) fix: use proper EFI zBoot image\n* [`010913b`](https://github.com/siderolabs/pkgs/commit/010913b8bf2b7c7df2d16efcdf23a4efbb9913ab) feat: update Linux 6.6.26, containerd 1.7.15\n* [`da397fa`](https://github.com/siderolabs/pkgs/commit/da397fa0e55284f466af982f98cf93e7075e6298) feat: enable BFQ IO scheduler\n* [`c839801`](https://github.com/siderolabs/pkgs/commit/c83980113db4aabbda4393d7aa8e6ab734a6069b) feat: enable zboot on arm64 with zstd compression\n* [`1b28e2c`](https://github.com/siderolabs/pkgs/commit/1b28e2ce58e5702bcbbd5ed13fbd7cf6420dc12d) feat: go 1.22.2, Linux 6.6.24\n* [`05db2a8`](https://github.com/siderolabs/pkgs/commit/05db2a88e6985470f4e7dc6b21fbdd9df1e63aea) fix: revert musl to 1.2.4\n</p>\n</details>\n\n### Changes from siderolabs/protoenc\n<details><summary>19 commits</summary>\n<p>\n\n* [`684f268`](https://github.com/siderolabs/protoenc/commit/684f2683c83568076b1f7d573f40555c508df7a5) chore: bump deps, add repeated <-> single field example\n* [`82f0774`](https://github.com/siderolabs/protoenc/commit/82f07747c640f96ce03cc9f3efa3d337fdd553ac) fix: encode (u)int(16|8)s as varints\n* [`d8ddbd5`](https://github.com/siderolabs/protoenc/commit/d8ddbd5d49cd8fd80cf5f8cc1d719bf9e9ba22c9) chore: add more tests\n* [`dceb5a6`](https://github.com/siderolabs/protoenc/commit/dceb5a69a0d707d3bcd72098beca26c247bf734b) fix: proper order for custom EncoderDecoder\n* [`3617e19`](https://github.com/siderolabs/protoenc/commit/3617e19073cb4db7b8a018bb7227cae45054b626) fix: add missing test and proper check for `map[string]interface{}`\n* [`647e9da`](https://github.com/siderolabs/protoenc/commit/647e9da005a1d059e2078fdb8239c8c95f41ee75) chore: various additions\n* [`3e56913`](https://github.com/siderolabs/protoenc/commit/3e569130fb14c536952ea8e212d763680c84decc) fix: support pointer to structs in marshal/unmarshal\n* [`49a85fa`](https://github.com/siderolabs/protoenc/commit/49a85fa966f82025092615dc3900e5592fd78d9f) chore: add support for map[string]interface{}\n* [`bf5e39b`](https://github.com/siderolabs/protoenc/commit/bf5e39bc5ed0b316270f4f8aa492e48ca06c11b7) chore: support (u)int(8|16) fields ans slices, fix map issues,\n* [`d618d0d`](https://github.com/siderolabs/protoenc/commit/d618d0ded21d763fd56589feecc8674e115bd1f1) chore: no longer treat T and *T as the same types in RegisterEncoderDecoder\n* [`aa7ee6c`](https://github.com/siderolabs/protoenc/commit/aa7ee6c221e10a92c0f7c235f216b26fa087d31a) chore: add fast path for ints, fixed ints and floats\n* [`6427893`](https://github.com/siderolabs/protoenc/commit/64278935504606ae2d5ff984edeaaf68cf773a71) chore: bump Go and fix lint issues\n* [`94427a5`](https://github.com/siderolabs/protoenc/commit/94427a5723dd6f37c2bfd55c63861c97b2de524b) chore: even more various fixes and small refactorings\n* [`76e5695`](https://github.com/siderolabs/protoenc/commit/76e56952b611a270e356e60996a7b90a9a542ecc) chore: various fixes and small refactorings\n* [`8a48bf0`](https://github.com/siderolabs/protoenc/commit/8a48bf027476e8456478fcd03f9e9b4c37e05a48) feat: implement custom encoders/decoders\n* [`549761b`](https://github.com/siderolabs/protoenc/commit/549761b029e126ee8ba6ee6c967d67c1d7d119a4) chore: various embedding fixes\n* [`ab9b1ff`](https://github.com/siderolabs/protoenc/commit/ab9b1ffdc4582c3c6f152ba6883568c66326f816) chore: add side-by-side tests with official proto.Marshal and Unmarshal\n* [`2519db3`](https://github.com/siderolabs/protoenc/commit/2519db3bc80b9d2024cd0fb72e1ae7deed8b380a) feat: implement Marshal/Unmarshal functions for protobuf encoding\n* [`485db9f`](https://github.com/siderolabs/protoenc/commit/485db9f2005db2155d723711328c59026af84f9a) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>4 commits</summary>\n<p>\n\n* [`e76747b`](https://github.com/siderolabs/siderolink/commit/e76747ba523b336ab8b9143293c920ff64bc4f14) chore: migrate to rtnetlink/2\n* [`3a587fc`](https://github.com/siderolabs/siderolink/commit/3a587fcf9dbb259e216495496a523faaea427d04) fix: do not ever skip updates which have remove flag\n* [`be00ff5`](https://github.com/siderolabs/siderolink/commit/be00ff59bac50e0da4cd0747f8e5f30c7b029ded) chore: redo event filtering as a sequence of iterators\n* [`a936b60`](https://github.com/siderolabs/siderolink/commit/a936b60645267d2e7320083b402df5ad19de76f5) chore: handle peer events in batches\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>14 commits</summary>\n<p>\n\n* [`50e55e6`](https://github.com/siderolabs/tools/commit/50e55e61e6d1c0d5b220d3cf5e7db0900f3022f6) feat: bump dependencies\n* [`2b8dab4`](https://github.com/siderolabs/tools/commit/2b8dab4c892e1755b068323758d8fc0952f28500) feat: add policycoreutils for building squashfs with SELinux\n* [`ef48079`](https://github.com/siderolabs/tools/commit/ef48079b3fbe0b414437728b411f7e033ea2f47f) feat: add fakeroot as a build dependency\n* [`86b5363`](https://github.com/siderolabs/tools/commit/86b5363b67b9dcfa2fabb093e95624e8c6190a89) feat: add secilc\n* [`41ed4b2`](https://github.com/siderolabs/tools/commit/41ed4b2ff91d273594716cd98a5f193fcb50dc85) fix: fix Tcl tag hashes\n* [`a764e8d`](https://github.com/siderolabs/tools/commit/a764e8dc4888601f30f1a2d09d37cbe3d00d78fc) chore: bump deps\n* [`7d807bd`](https://github.com/siderolabs/tools/commit/7d807bdc7532cc1f72b8288a0c36dd4f656a3af3) chore: bump deps\n* [`31ad71b`](https://github.com/siderolabs/tools/commit/31ad71bdb3b2b33ab1c74175ffc1eff0cae33866) feat: update dependencies\n* [`d2746e5`](https://github.com/siderolabs/tools/commit/d2746e5a7a60a22ad957c8bc04831bae8c191af6) feat: update Go to 1.22.4\n* [`06ba64e`](https://github.com/siderolabs/tools/commit/06ba64ec3044c9c4ea51b8a624c46503a4f5fe26) feat: update dependencies\n* [`7e5a248`](https://github.com/siderolabs/tools/commit/7e5a2482284e00f60cd44a5d155fcdf2291f1fc9) feat: update dependencies\n* [`c34ec5b`](https://github.com/siderolabs/tools/commit/c34ec5bfd44faa4a5ccced07136246fb25858635) feat: update Go to 1.22.3\n* [`3c25a6f`](https://github.com/siderolabs/tools/commit/3c25a6f164f3004d222bb13f5b663e01b80ff882) fix: update pkg-config configure flag\n* [`bd405ff`](https://github.com/siderolabs/tools/commit/bd405ff5d8d511eeef17f0a6126ad6cdd3a849bb) feat: update go to 1.22.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.2.3 -> v0.5.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.11.1 -> v1.13.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.5.1 -> v1.7.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.27.10 -> v1.27.31\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.1 -> v1.16.12\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.30.1 -> v1.35.5\n* **github.com/aws/smithy-go**                          v1.20.2 -> v1.20.4\n* **github.com/beevik/ntp**                             v1.3.1 -> v1.4.3\n* **github.com/containerd/containerd/api**              v1.8.0-rc.3 **_new_**\n* **github.com/containerd/containerd/v2**               v2.0.0-rc.4 **_new_**\n* **github.com/containerd/errdefs**                     v0.1.0 **_new_**\n* **github.com/containerd/platforms**                   v0.2.1 **_new_**\n* **github.com/containerd/typeurl/v2**                  v2.1.1 -> v2.2.0\n* **github.com/containernetworking/cni**                v1.1.2 -> v1.2.3\n* **github.com/containernetworking/plugins**            v1.4.1 -> v1.5.1\n* **github.com/coreos/go-iptables**                     v0.7.0 -> v0.8.0\n* **github.com/cosi-project/runtime**                   v0.4.1 -> v0.5.5\n* **github.com/docker/docker**                          v26.0.0 -> v27.2.0\n* **github.com/fatih/color**                            v1.16.0 -> v1.17.0\n* **github.com/foxboron/go-uefi**                       48be911532c2 -> e2076f0e58ca\n* **github.com/google/go-containerregistry**            v0.19.1 -> v0.20.2\n* **github.com/google/go-tpm**                          ee6cbcd136f8 -> v0.9.1\n* **github.com/hashicorp/go-getter/v2**                 v2.2.1 -> v2.2.3\n* **github.com/hetznercloud/hcloud-go/v2**              v2.7.0 -> v2.13.1\n* **github.com/insomniacslk/dhcp**                      c728f5dd21c8 -> a3a4c1f04475\n* **github.com/jsimonetti/rtnetlink/v2**                v2.0.2 **_new_**\n* **github.com/klauspost/compress**                     v1.17.9 **_new_**\n* **github.com/klauspost/cpuid/v2**                     v2.2.7 -> v2.2.8\n* **github.com/miekg/dns**                              v1.1.58 -> v1.1.62\n* **github.com/opencontainers/runc**                    v1.2.0-rc.2 **_new_**\n* **github.com/pelletier/go-toml/v2**                   v2.2.3 **_new_**\n* **github.com/pkg/xattr**                              v0.4.10 **_new_**\n* **github.com/prometheus/procfs**                      v0.13.0 -> v0.15.1\n* **github.com/rivo/tview**                             a22293bda944 -> fd649dbf1223\n* **github.com/rs/xid**                                 v1.5.0 -> v1.6.0\n* **github.com/safchain/ethtool**                       v0.3.0 -> v0.4.1\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.25 -> v1.0.0-beta.29\n* **github.com/siderolabs/discovery-client**            v0.1.8 -> v0.1.9\n* **github.com/siderolabs/extras**                      v1.7.0-1-gbb76755 -> v1.8.0-alpha.0-6-g43a2821\n* **github.com/siderolabs/gen**                         v0.4.8 -> v0.5.0\n* **github.com/siderolabs/go-api-signature**            v0.3.2 -> v0.3.5\n* **github.com/siderolabs/go-blockdevice/v2**           3265299b0192 -> v2.0.1\n* **github.com/siderolabs/go-circular**                 v0.1.0 -> v0.2.0\n* **github.com/siderolabs/go-debug**                    v0.3.0 -> v0.4.0\n* **github.com/siderolabs/go-kubernetes**               v0.2.9 -> v0.2.11\n* **github.com/siderolabs/go-loadbalancer**             v0.3.3 -> v0.3.4\n* **github.com/siderolabs/go-pcidb**                    v0.2.0 -> v0.3.0\n* **github.com/siderolabs/go-smbios**                   v0.3.2 -> v0.3.3\n* **github.com/siderolabs/go-tail**                     v0.1.0 -> v0.1.1\n* **github.com/siderolabs/go-talos-support**            v0.1.0 -> v0.1.1\n* **github.com/siderolabs/grpc-proxy**                  v0.4.0 -> v0.4.1\n* **github.com/siderolabs/pkgs**                        v1.7.0-6-g29106c0 -> v1.8.0-alpha.0-54-g4ce5bc6\n* **github.com/siderolabs/protoenc**                    v0.2.1 **_new_**\n* **github.com/siderolabs/siderolink**                  v0.3.5 -> v0.3.9\n* **github.com/siderolabs/talos/pkg/machinery**         v1.7.0 -> v1.8.0-alpha.2\n* **github.com/siderolabs/tools**                       v1.7.0-1-g10b2a69 -> v1.8.0\n* **github.com/spf13/cobra**                            v1.8.0 -> v1.8.1\n* **github.com/vishvananda/netlink**                    v1.2.1-beta.2 -> v1.3.0\n* **go.etcd.io/etcd/api/v3**                            v3.5.13 -> v3.5.15\n* **go.etcd.io/etcd/client/pkg/v3**                     v3.5.13 -> v3.5.15\n* **go.etcd.io/etcd/client/v3**                         v3.5.13 -> v3.5.15\n* **go.etcd.io/etcd/etcdutl/v3**                        v3.5.13 -> v3.5.15\n* **golang.org/x/net**                                  v0.23.0 -> v0.28.0\n* **golang.org/x/oauth2**                               v0.18.0 -> v0.22.0\n* **golang.org/x/sync**                                 v0.6.0 -> v0.8.0\n* **golang.org/x/sys**                                  v0.18.0 -> v0.24.0\n* **golang.org/x/term**                                 v0.18.0 -> v0.23.0\n* **golang.org/x/text**                                 v0.14.0 -> v0.17.0\n* **golang.org/x/time**                                 v0.5.0 -> v0.6.0\n* **google.golang.org/grpc**                            v1.62.1 -> v1.66.0\n* **google.golang.org/protobuf**                        v1.33.0 -> v1.34.2\n* **k8s.io/api**                                        v0.30.0 -> v0.31.0\n* **k8s.io/apimachinery**                               v0.30.0 -> v0.31.0\n* **k8s.io/apiserver**                                  v0.30.0 -> v0.31.0\n* **k8s.io/client-go**                                  v0.30.0 -> v0.31.0\n* **k8s.io/component-base**                             v0.30.0 -> v0.31.0\n* **k8s.io/cri-api**                                    v0.30.0 -> v0.32.0-alpha.0\n* **k8s.io/klog/v2**                                    v2.120.1 -> v2.130.1\n* **k8s.io/kube-scheduler**                             v0.30.0 -> v0.31.0\n* **k8s.io/kubectl**                                    v0.30.0 -> v0.31.0\n* **k8s.io/kubelet**                                    v0.30.0 -> v0.31.0\n* **k8s.io/pod-security-admission**                     v0.30.0 -> v0.31.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**     v1.2.69 -> v1.2.70\n* **sigs.k8s.io/hydrophone**                            b92baf7e0b04 **_new_**\n\nPrevious release can be found at [v1.7.0](https://github.com/siderolabs/talos/releases/tag/v1.7.0)\n\n## [Talos 1.8.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.8.0-alpha.1) (2024-07-05)\n\nWelcome to the v1.8.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Workload Apparmor Profile\n\nTalos Linux can now apply the default AppArmor profiles to all workloads started via containerd, if the machine is installed with the AppArmor LSM enforced via the extraKernelArgs.\n\nEg:\n\n```yaml\nmachine:\n    install:\n        extraKernelArgs:\n            - security=apparmor\n```\n\n\n### Bridge Interface\n\nTalos Linux now support configuring 'vlan_filtering' for bridge interfaces.\n\n\n### Diagnostics\n\nTalos Linux now shows diagnostics information for common problems related to misconfiguration via `talosctl health` and Talos dashboard.\n\n\n### DNS Forwarding for CoreDNS pods\n\nUsage of the host DNS resolver as upstream for Kubernetes CoreDNS pods is now enabled by default. You can disable it\nwith:\n\n```yaml\nmachine:\n  features:\n    hostDNS:\n      enabled: true\n      forwardKubeDNSToHost: false\n```\n\nPlease note that on running cluster you will have to kill CoreDNS pods for this change to apply.\n\n\n### PCI Devices\n\nA list of PCI devices can now be obtained via `PCIDevices` resource, e.g. `talosctl get pcidevices`.\n\n\n### Component Updates\n\nKubernetes: 1.30.2\nLinux: 6.6.36\ncontainerd: 2.0.0-rc.3\nrunc: 1.2.0-rc.2\netcd: 3.5.14\nFlannel: 0.25.3\nFlannel CNI plugin: 1.5.1\n\nTalos is built with Go 1.22.5.\n\n\n### ZSTD Compression\n\nTalos Linux now compresses kernel and initramfs using ZSTD.\nLinux arm64 kernel is now compressed (previously it was uncompressed).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Noel Georgi\n* Utku Ozdemir\n* Artem Chernyshev\n* Dmitry Sharshakov\n* Spencer Smith\n* Justin Garrison\n* Steve Francis\n* Bernard Gütermann\n* Konrad Eriksson\n* Andrew Rynhard\n* Attila Oláh\n* Birger J. Nordølum\n* Dennis Marttinen\n* Enrique Hernández Bello\n* Evan Johnson\n* Fabian Topfstedt\n* Grzegorz Rozniecki\n* Grzegorz Rożniecki\n* Igor Rzegocki\n* Jean-Francois Roy\n* Marcel Richter\n* Marco Franssen\n* Michael Trip\n* Ron Olson\n* Serge Logvinov\n* Simon-Boyer\n* Steve Fan\n* USBAkimbo\n* Will Bush\n* darox\n* dhaines-quera\n* leppeK\n* looklose\n\n### Changes\n<details><summary>160 commits</summary>\n<p>\n\n* [`0454130ad`](https://github.com/siderolabs/talos/commit/0454130ad97a61624fb0b916bf14a51dce8f199d) feat: suppress controller runtime first N failures on the console\n* [`3d35e5468`](https://github.com/siderolabs/talos/commit/3d35e54683b4930fa716c7afe6ecbad2af2f700b) chore: update hydrophone library\n* [`1f28726d4`](https://github.com/siderolabs/talos/commit/1f28726d46953262f33c91082528cd190f53b143) chore: support version with and without `v` prefix\n* [`9a56b8527`](https://github.com/siderolabs/talos/commit/9a56b8527b81c9653f5d01386c66ec1bde5d730a) chore(ci): fix parallel runs of tf pipelines\n* [`be35f380c`](https://github.com/siderolabs/talos/commit/be35f380ccf09d7667c3221765d6927546cffbca) chore: update pkgs/tools/extras\n* [`93df23444`](https://github.com/siderolabs/talos/commit/93df2344451e8f370f7f1d0f9590f65d6b02b936) docs: update opengraph image for main landing pages\n* [`d9d62d4da`](https://github.com/siderolabs/talos/commit/d9d62d4da6e30ac8f97a06dafd362a9e2ddc7006) feat: update Linux to 6.6.36\n* [`6b0fe5b8c`](https://github.com/siderolabs/talos/commit/6b0fe5b8ca9aa11d195b4b66608ad179bca7be44) docs: update deploying cilium docs for v1.7 and v1.8\n* [`52611a90d`](https://github.com/siderolabs/talos/commit/52611a90d870a131084375015d4d7270fa32cde8) feat: update Kubernetes to v1.30.2\n* [`c19cc4ccb`](https://github.com/siderolabs/talos/commit/c19cc4ccbc8c37b6dde49853dfc442a0f5404ab4) docs: clarify direct access needed to nodes in insecure mode\n* [`b4c871e4b`](https://github.com/siderolabs/talos/commit/b4c871e4b74014553ab81f7ff593ff7fa736df2d) chore: bump dependencies\n* [`cc345c8c9`](https://github.com/siderolabs/talos/commit/cc345c8c9413692148360684390c910de9e94748) feat: add support for configuring vlan filtering on the bridge\n* [`2d054ad35`](https://github.com/siderolabs/talos/commit/2d054ad3551428d8b3d93c8356b38aec7e9225eb) chore: handle documents diff in `apply-config` dry run\n* [`bd34f71f3`](https://github.com/siderolabs/talos/commit/bd34f71f3e5eae34907951a6480e0559736bfd72) feat: add apparmor pkg\n* [`71857fd4d`](https://github.com/siderolabs/talos/commit/71857fd4d3a262a6b41cad3af7d3abb7355d8509) docs: fix typo: `messure` -> `measure`\n* [`f75f16b0a`](https://github.com/siderolabs/talos/commit/f75f16b0a8088ac47a47c9ebabdf4803db5a397e) chore(ci): fix cluster name generation\n* [`c603d2bf9`](https://github.com/siderolabs/talos/commit/c603d2bf9552ed169e5baf012ad44305a54056a4) chore: output more info when `ExecuteCommandInPod` fails\n* [`4b5a7445e`](https://github.com/siderolabs/talos/commit/4b5a7445e9c3f7f2f53e958f6c2e91a1a86c2641) docs: fix missing Akamai platform in supported matrix\n* [`4701498a1`](https://github.com/siderolabs/talos/commit/4701498a1b5a213816962fb1acb56192423f525f) chore(ci): run e2e-aws-nvidia with zfs extension enabled\n* [`86a3222ae`](https://github.com/siderolabs/talos/commit/86a3222aeecb895cab233a0cd2474189f79a6f12) chore: use new disks api for iscsi tests\n* [`5ffc3f14b`](https://github.com/siderolabs/talos/commit/5ffc3f14bd2b49a2ee09f36fe9e66bcf7b5283e8) feat: show siderolink status on dashboard\n* [`6f6a5d105`](https://github.com/siderolabs/talos/commit/6f6a5d10573028662448a57c66c2255bb7703319) chore: upgrade to rtnetlink/v2 library\n* [`1fb8453c2`](https://github.com/siderolabs/talos/commit/1fb8453c2db1659dd6c1670e4174125b26e777c5) chore: update Go modules\n* [`8e15621e8`](https://github.com/siderolabs/talos/commit/8e15621e83a1005c3b7d8d682652f984765996c1) chore(ci): add conformance pipelines\n* [`7fcb521a6`](https://github.com/siderolabs/talos/commit/7fcb521a6a2d14de02926489d7297cf9429c7b38) feat: use hydrophone instead of sonobuoy\n* [`d1a0c1f98`](https://github.com/siderolabs/talos/commit/d1a0c1f983281593b4e6a71e2110ae9f81890edc) test: fix the integration test for no META name\n* [`535006334`](https://github.com/siderolabs/talos/commit/5350063340a80b99a8866afb94ac8673dd4e7ace) chore: fix our dns server implementation\n* [`c6f90d014`](https://github.com/siderolabs/talos/commit/c6f90d01493454bcf3281c9532b61fcb7e3dbb24) chore: replace sync.Map with concurrent.HashTrieMap\n* [`e8ced2c2d`](https://github.com/siderolabs/talos/commit/e8ced2c2ddc9e3f61138dd566628f7d11cf90c76) chore: drop k8s timeout in the default kubeconfig\n* [`7cbdce73f`](https://github.com/siderolabs/talos/commit/7cbdce73f74351954e506303ed9964b9668a3b40) fix: detect CD devices, fix user disks wipe test\n* [`aca475c66`](https://github.com/siderolabs/talos/commit/aca475c66509fa1fa7e7a0ca1b2a29f6542637fc) chore: small usability fixes\n* [`26cf566dc`](https://github.com/siderolabs/talos/commit/26cf566dc8c53263cbaae72855995e418da0852b) chore: bump our coredns fork\n* [`5e66e117e`](https://github.com/siderolabs/talos/commit/5e66e117e2ec19527fe949bf2d689df90835d63f) fix: initial assignment of Hetzner Cloud Alias IP\n* [`f07b79f4a`](https://github.com/siderolabs/talos/commit/f07b79f4a8c647d358b8cd41b3704eccf0341d33) feat: provide disk detection based on new blockdevices\n* [`8ee087268`](https://github.com/siderolabs/talos/commit/8ee087268317a73dc240c2b7569c2dab8d9df142) chore(ci): drop crashdump, save logs as artifacts\n* [`7c9a14383`](https://github.com/siderolabs/talos/commit/7c9a14383ee034b05cb9bd1ff49f8078cbbf5e66) fix: volume discovery improvements\n* [`80ca8ff71`](https://github.com/siderolabs/talos/commit/80ca8ff7135b0950b83d2ceaa32ee1eacce049e0) fix: update the cgroups for Talos core services\n* [`fe317f1e1`](https://github.com/siderolabs/talos/commit/fe317f1e1611d2f48595bfaf67c5e4ea3cd692e3) docs: fix typo in QEMU guest agent support on Proxmox\n* [`8dbe2128a`](https://github.com/siderolabs/talos/commit/8dbe2128a909a38ead8b6dfe1cc99e1ae36078d2) feat: implement Talos diagnostics\n* [`357d7754f`](https://github.com/siderolabs/talos/commit/357d7754fd739e9e875d17e0f8e63c333553090e) fix: clean up VM runners on cluster destroy\n* [`41f92e0ba`](https://github.com/siderolabs/talos/commit/41f92e0ba46b8ad9ddc3a4eabe86be915dea6b8e) chore: update Go to 1.22.4, other updates\n* [`4621e9bb7`](https://github.com/siderolabs/talos/commit/4621e9bb770e2a45c7c1ea8da76cbdabf76a4671) chore: add stale and lock issue workflows\n* [`82d9cd322`](https://github.com/siderolabs/talos/commit/82d9cd32298431760aef67f553924e4b4f48e207) fix: add upgrade errata for arm64/zboot kernels\n* [`9a23d846c`](https://github.com/siderolabs/talos/commit/9a23d846c1f6a88c30ffe55d2bf5a21d6cee150e) fix: downgrade Azure IMDS required version\n* [`30860210c`](https://github.com/siderolabs/talos/commit/30860210cce628839e97b8ece7edf90300556ed7) test: fix hardware test not to require PCI devices\n* [`9fcc9b841`](https://github.com/siderolabs/talos/commit/9fcc9b84152cb186324c13e317575f6da8b7bfa6) feat: update Flannel to v0.25.3\n* [`9d395b9de`](https://github.com/siderolabs/talos/commit/9d395b9de94f28fb9bf56bf795f916f783a847a0) chore: use bun instead of npm\n* [`a1684bdf8`](https://github.com/siderolabs/talos/commit/a1684bdf8f24858942cf61bee1efc81f7ef76f85) chore: speed up go generate for enumer\n* [`4dd0aa712`](https://github.com/siderolabs/talos/commit/4dd0aa7120b52cab5de219010f2b78b7dd9b73ce) feat: implement PCI device bus enumeration\n* [`b0466e0ab`](https://github.com/siderolabs/talos/commit/b0466e0abf2f8af43f3fb6c9661f44000fe1d54b) fix: disable kexec on GCP/Azure\n* [`911c25574`](https://github.com/siderolabs/talos/commit/911c255742d02440806e5f3df6967c091bb5288e) chore: fix go.work resolution\n* [`2f088ede0`](https://github.com/siderolabs/talos/commit/2f088ede0952d72dbb7bf33dd0510cb8ff8b8e3a) docs: add another example for installing cilium\n* [`3967e0777`](https://github.com/siderolabs/talos/commit/3967e07777707fa8af339f46596b678e1eaaa9f2) feat: update etcd to 3.5.14\n* [`3367ded9f`](https://github.com/siderolabs/talos/commit/3367ded9feac84e9c6c1f3efcea9e61f3083b4ac) fix: correct time adjustment in `time.SyncController`\n* [`893e64fcb`](https://github.com/siderolabs/talos/commit/893e64fcb1f09efed990b9b642359d7bcabffd42) fix: replace `nslookup` with `dig` in integration tests\n* [`0359c8537`](https://github.com/siderolabs/talos/commit/0359c8537c1b3b01e94394604e16fd817b986f9e) chore: unify toml packages being used\n* [`4feb94ca0`](https://github.com/siderolabs/talos/commit/4feb94ca099746e3a90106522b920a77cfe77ce0) feat: add multidoc check to the Talos quirks module\n* [`0b4a9777f`](https://github.com/siderolabs/talos/commit/0b4a9777fc2ddcc61430db23837455ff383ba1a3) docs: update talosctl install instructions for 1.8\n* [`da8305ffb`](https://github.com/siderolabs/talos/commit/da8305ffb46d285662bca12ec02760d6121342c8) test: add a test for watchdog timers\n* [`da7f27640`](https://github.com/siderolabs/talos/commit/da7f2764092b883bcdf5daf81b8f6f7ef997ac0a) fix: mount `tracefs` filesystem\n* [`7b37e5b63`](https://github.com/siderolabs/talos/commit/7b37e5b63d54c2d197336e4fbee941fa5f2423c0) chore(ci): fix integration extensions\n* [`de7553d77`](https://github.com/siderolabs/talos/commit/de7553d77f7e02a83f764820a71badbf0d851bc9) fix(ci): cron jobs\n* [`eb510d9fd`](https://github.com/siderolabs/talos/commit/eb510d9fdf3a40b2ae881e3dd19a94058d4ef529) chore: require enabled bootloader for docker provisioner\n* [`a9cf9b789`](https://github.com/siderolabs/talos/commit/a9cf9b78921bef76b66aa5fa5940977767124bfe) fix: correctly handle dns messages in our dns implementation\n* [`c2b19dcb9`](https://github.com/siderolabs/talos/commit/c2b19dcb978ab015bd9b3c5a4eb47a53ee25e297) chore: move to containerd 2.0 API\n* [`92a274e9a`](https://github.com/siderolabs/talos/commit/92a274e9a0a83b3e240784bf12817f08559ac8e8) fix: workaround problems with udevd races\n* [`31b24ea3d`](https://github.com/siderolabs/talos/commit/31b24ea3d70f88d031d81bd0f914754b0cee411e) chore(ci): split integration misc\n* [`8a1371337`](https://github.com/siderolabs/talos/commit/8a1371337faea406c9193e91c8de8ffc056b5135) fix: produce stable order of bonds with equinix\n* [`6406193f4`](https://github.com/siderolabs/talos/commit/6406193f4637157c3d31219dc2c39aca7fa736a4) test: add Equnix Metal sample metadata with two bonds\n* [`01ea82053`](https://github.com/siderolabs/talos/commit/01ea82053e0a2ffe4193243e235aae2ade0e2d88) fix: time sync over NTP from future era\n* [`5aea42427`](https://github.com/siderolabs/talos/commit/5aea4242782d4ff00ba51e85422fbdf7c2ceca64) fix(ci): fix crons by setting up buildx always\n* [`84706c3e2`](https://github.com/siderolabs/talos/commit/84706c3e2920b9bf68c7b6dcfb73f1e16f3f656b) docs: default to brew docs for talosctl\n* [`fcd65ff65`](https://github.com/siderolabs/talos/commit/fcd65ff65ce78aa5ebe7ca4b12aea2571bd54c49) feat: enable forwardKubeDNSToHost by default\n* [`2e64e9e4e`](https://github.com/siderolabs/talos/commit/2e64e9e4e026817f844765b4c8a7d346d85bf983) fix: require accepted CAs on worker nodes\n* [`23c1c4560`](https://github.com/siderolabs/talos/commit/23c1c4560ecd2084e505a64b0b701707aa79c5e6) fix(ci): fix crons fby rekres\n* [`2d50392c5`](https://github.com/siderolabs/talos/commit/2d50392c5a16a97a2daa47edcfd362b0891c4a06) feat: update containerd to 2.0.0-rc.2, runc to 1.2.0-rc.1\n* [`a12e4bb24`](https://github.com/siderolabs/talos/commit/a12e4bb24e19701e926103753ec3ee0f98e8d3a2) chore(ci): fix github action crons\n* [`e7bd9cd2b`](https://github.com/siderolabs/talos/commit/e7bd9cd2bbbd337ef72adc2a3be5adc8b530cd6e) fix: decrease maximum negative ttl for dns responses\n* [`9c3ebad9f`](https://github.com/siderolabs/talos/commit/9c3ebad9fd7a62418fc6748364a23d27ff1c3ff7) chore(ci): kresify gh actions\n* [`ff60f6fde`](https://github.com/siderolabs/talos/commit/ff60f6fde6cb325b9f1f4801f658f4e9554c6c2b) refactor: make some of the extensions package public\n* [`ce8c86d64`](https://github.com/siderolabs/talos/commit/ce8c86d640949d24107d9057358b39c860fc1e70) fix: panic in osroot controller\n* [`e1711cd3c`](https://github.com/siderolabs/talos/commit/e1711cd3c9852137956f1cce7174b0a337d53b63) chore: stop using containerd package for cri namespace\n* [`d4307043f`](https://github.com/siderolabs/talos/commit/d4307043ffbfcadb5b67b12c95816c2a3a5819c3) fix: update go-tail library to fix 'short read' error\n* [`7cd13ef4a`](https://github.com/siderolabs/talos/commit/7cd13ef4a619fa5c13dc9ed147e6626ddcabbaf2) docs: add documentation on using Multus with Talos\n* [`4784da3ef`](https://github.com/siderolabs/talos/commit/4784da3ef88745d1ce38f1e49239c882c081e6fb) feat: use new circular buffer compressed chunks feature\n* [`78b48eb3a`](https://github.com/siderolabs/talos/commit/78b48eb3ae78ec9953104247ec73cafa26a61264) feat: include EDAC drivers\n* [`0bf2d69fb`](https://github.com/siderolabs/talos/commit/0bf2d69fbb2f2c1f693565243b46391da00d4dba) feat: update Kubernetes to 1.30.1\n* [`53f548913`](https://github.com/siderolabs/talos/commit/53f54891302b193bf35ede52af235457396e91ce) fix: increase host dns packet ttl for pods\n* [`dedb6d360`](https://github.com/siderolabs/talos/commit/dedb6d360d25e6d00d560ddb40563c2a5a95bb1f) fix: update github.com/siderolabs/siderolink to v0.3.7\n* [`43939f1a6`](https://github.com/siderolabs/talos/commit/43939f1a6e4b65cf9b64d1d09dc19df709a41275) docs: fix typos, add docker socket info\n* [`6663068bb`](https://github.com/siderolabs/talos/commit/6663068bbd1750fd57ddf9ca63b0f305d895b33b) chore: update project in GCP testing\n* [`b86edc677`](https://github.com/siderolabs/talos/commit/b86edc6776f77a65d3a254cf0f0d713ce7a9145e) chore: update office hours in talos repo\n* [`cfa25d22d`](https://github.com/siderolabs/talos/commit/cfa25d22dc30b877ea47ba1bfae3ca5f29977f1b) chore: remove docs prior to 1.0 from website navigation\n* [`120705459`](https://github.com/siderolabs/talos/commit/12070545996af3435454654500cd75a50111cca9) chore: handle I/O error for xfs_repair\n* [`b7afe2669`](https://github.com/siderolabs/talos/commit/b7afe2669b2a9a32ca37bbcc7a7e8af4879cf403) feat: update Linux 6.6.30\n* [`26519ceed`](https://github.com/siderolabs/talos/commit/26519ceed0c790abd851de310409baf6af89e2b7) docs: update proxmox.md\n* [`851b91a0e`](https://github.com/siderolabs/talos/commit/851b91a0e22055443eabace9b89a566e0cbec679) fix: don't enable hostDNS for versions of Talos which do not have it\n* [`42ac5cd0c`](https://github.com/siderolabs/talos/commit/42ac5cd0c2ef610f055afb208384e60fc9389e82) fix: check for `nil` machine config during installation\n* [`1d29111d4`](https://github.com/siderolabs/talos/commit/1d29111d4310cc16078248e66817843e6e740821) chore: update Go to 1.22.3\n* [`f4d7b9d9a`](https://github.com/siderolabs/talos/commit/f4d7b9d9a921cdaf33b9efdae1569dd921628270) feat: gather plaform dns names\n* [`0b0f9995a`](https://github.com/siderolabs/talos/commit/0b0f9995a6cd2b41f48dc867f4e0248284e53463) docs: add resource information, some grammar fixes\n* [`763dae250`](https://github.com/siderolabs/talos/commit/763dae2508242ee91a7e38e5962facb334691289) fix: add cluster name to the worker machine config\n* [`4aac5b4ec`](https://github.com/siderolabs/talos/commit/4aac5b4ec30f4a9ee0f2e4a4239b399357930b6c) feat: mount /sys/kernel/security into kubelet\n* [`817f18153`](https://github.com/siderolabs/talos/commit/817f18153f592f5bf38884f05aed2e4ce2fd3ad7) docs: remove mention of enabling KubePrism after v1.6\n* [`c08d79732`](https://github.com/siderolabs/talos/commit/c08d797326686434dc035de3ca40200293d74701) docs: fix the variable name typo\n* [`478b862b4`](https://github.com/siderolabs/talos/commit/478b862b4c38bd5a5ba1313a3779f9395e4ba38d) fix: do not fail cli action tracker when boot id cannot be read\n* [`be510f9eb`](https://github.com/siderolabs/talos/commit/be510f9eb2b84a88ce730fab36bf575c976efa8b) docs: fix grpc_tunnel value to true\n* [`b7b8a8d8f`](https://github.com/siderolabs/talos/commit/b7b8a8d8fa6335d3f0036c50792971adefe5e240) docs: add logs example for the certificate errors troubleshooting\n* [`8df5b85ec`](https://github.com/siderolabs/talos/commit/8df5b85ec7e8ca53fd73c9c095ee5c453d5c4e51) release(v1.8.0-alpha.0): prepare release\n* [`07f78182c`](https://github.com/siderolabs/talos/commit/07f78182c621296e6c694b64ead8f14695b2e3b7) fix: use a fresh context for etcd unlock\n* [`84cd7dbec`](https://github.com/siderolabs/talos/commit/84cd7dbec4ce01a8f80a855267e1c44dfc6dcacc) feat: update Linux to 6.6.29\n* [`70fdca6a4`](https://github.com/siderolabs/talos/commit/70fdca6a43abcb48030239047500fa8819f9346d) chore: update minimum hardware requirement for vmware ova\n* [`b690ffeb8`](https://github.com/siderolabs/talos/commit/b690ffeb899c4a133f98e212826830e3b320abe4) test: improve DNS resolver test stability\n* [`5aa0299b6`](https://github.com/siderolabs/talos/commit/5aa0299b6e3efefa7077aab5955526a5136b8761) style: use correct capitalization for openstack\n* [`4c0c626b7`](https://github.com/siderolabs/talos/commit/4c0c626b786f14c5eabdc65e88d2aae92829bf73) feat: use zstd compression in place of xz\n* [`98906ed6e`](https://github.com/siderolabs/talos/commit/98906ed6ea1afc5a758871a7c2d8251fccaef106) fix: use reboot delay only in case of error\n* [`05fd042bb`](https://github.com/siderolabs/talos/commit/05fd042bb3600541a8e2587b66b8b4c4e9f99c27) test: improve the reset integration tests\n* [`8cdf0f7cb`](https://github.com/siderolabs/talos/commit/8cdf0f7cb007790190197356355a16c8e427afab) docs: fix typo in Cilium instructions\n* [`dd1d279da`](https://github.com/siderolabs/talos/commit/dd1d279daa8c2a18c2477839b2c11e5f2f554693) fix: allow more flags in `talosctl cluster create --input-dir`\n* [`ef4394e58`](https://github.com/siderolabs/talos/commit/ef4394e586e42c4b5085299029a2aacb3b89502d) chore: update kernel and other packages\n* [`ccdb4c8b1`](https://github.com/siderolabs/talos/commit/ccdb4c8b10450aa7fb6c32b0559bda73746a03ed) chore: update google.golang.org/grpc to 1.63.2\n* [`c5b59df69`](https://github.com/siderolabs/talos/commit/c5b59df6976095aca5c4bac367084874242e9e80) fix: wait for devices to be discovered before probing filesystems\n* [`0821b9c50`](https://github.com/siderolabs/talos/commit/0821b9c50b86bf9f7d08a1ba7b177abb7e2568c4) feat: add `--non-masquerade-cidrs` flag to `talosctl cluster create`\n* [`2bf613ad3`](https://github.com/siderolabs/talos/commit/2bf613ad3bd1582b520b2f661b7e0bfab4207eed) fix: add endpoints for \"virtual\" `host-dns` service\n* [`f4163aefe`](https://github.com/siderolabs/talos/commit/f4163aefeda2bf91be36af45239716c53ec982b1) fix: bump priority of OpenStack routes if IPv6 and default gateway\n* [`6fbd1263c`](https://github.com/siderolabs/talos/commit/6fbd1263ccbe20857cca90b5f69906651caa4f54) feat: report process MAC labels\n* [`d46032821`](https://github.com/siderolabs/talos/commit/d460328210ee3beea1b98ea5f23fcda5c2e2fd44) fix: return proper value from Bridge.STP instead of plain nil\n* [`bac1d00c3`](https://github.com/siderolabs/talos/commit/bac1d00c35cb6e1407884298118ee7b4ffc5fdfa) chore: prepare for Talos 1.8\n* [`d6c8067e1`](https://github.com/siderolabs/talos/commit/d6c8067e15d8177c7394abad65b95ea98c597b9d) docs: make 1.7 docs the default\n* [`d7c3a0735`](https://github.com/siderolabs/talos/commit/d7c3a0735eab85dd24e86fe3e0872253067e8f10) docs: add what's new for v1.7\n* [`908f67fa1`](https://github.com/siderolabs/talos/commit/908f67fa15e0de507c2f69fac0851d42376a66ce) feat: add host dns support for resolving member addrs\n* [`0d20b637d`](https://github.com/siderolabs/talos/commit/0d20b637d68a581354361bbceecb90395f24fedb) feat: update Kubernetes to 1.30.0\n* [`ec69d7a78`](https://github.com/siderolabs/talos/commit/ec69d7a7855753e3e458f2cf7c211bf67e703220) chore: replace math/rand with math/rand/v2\n* [`89040ce43`](https://github.com/siderolabs/talos/commit/89040ce4329743fa2037fb1cf65d978801753dbe) chore: update go-blockdevice/v2 library to the latest version\n* [`0a785802e`](https://github.com/siderolabs/talos/commit/0a785802ea22071e67d7ec85944513e73624b1ac) fix: overlay installer operations\n* [`b1b63f658`](https://github.com/siderolabs/talos/commit/b1b63f658eba5cbb08cbd05af959c6d397662e05) fix: mark overlay installer executable\n* [`3433fa13b`](https://github.com/siderolabs/talos/commit/3433fa13bf555a871e76f8ce726d5afd141a16e1) feat: use container DNS when in container mode\n* [`5d07ac5a7`](https://github.com/siderolabs/talos/commit/5d07ac5a7db9d2291a86ee966ee704b30afea342) fix: close apid inter-backend connections gracefully for real\n* [`7ba18555b`](https://github.com/siderolabs/talos/commit/7ba18555b098ba2617efce2438d6bfbec1dc0041) docs: fix typos in Akamai and AWS platform docs\n* [`3dd1f4e88`](https://github.com/siderolabs/talos/commit/3dd1f4e88c22734f03f7609791558b8bbbae3756) chore: extract `pkg/imager/quirks` to `pkg/machinery`\n* [`78bc3a433`](https://github.com/siderolabs/talos/commit/78bc3a433e8b10839034bd40b73fcc720438b943) docs: update Cilium docs\n* [`831f3d39e`](https://github.com/siderolabs/talos/commit/831f3d39e9b030cd1bcd3313246ebccf34f34205) feat: update Flannel to v0.25.1\n* [`ea5b3ff0c`](https://github.com/siderolabs/talos/commit/ea5b3ff0c27cb033d525d172d4006e0645a924ba) feat: update Kubernetes to v1.30.0-rc.2\n* [`54dac5ed4`](https://github.com/siderolabs/talos/commit/54dac5ed40698b8886096c620ac19ed55a4b99a1) feat: update Linux 6.6.24, containerd 1.7.15\n* [`c51f146da`](https://github.com/siderolabs/talos/commit/c51f146daf3265bbeb4513c649938b2656ff1686) docs: update Akamai platform docs\n* [`9550f5ff7`](https://github.com/siderolabs/talos/commit/9550f5ff7a285df7c251df425e8f28d4c668224f) docs: fix getAuthenticationMethod and completePathFromNode docs\n* [`bfbd02abf`](https://github.com/siderolabs/talos/commit/bfbd02abfb1d84d14a73f1e247d62e728860d2f3) fix: assign different priority to IPv6 default gateway on OpenStack\n* [`c8f674bd3`](https://github.com/siderolabs/talos/commit/c8f674bd3d582f606848475bca3d22f309b2367c) test: add a test for 'spin' container runtime\n* [`5390ccd48`](https://github.com/siderolabs/talos/commit/5390ccd48c78e864f53cc45848772c931276380d) chore: replace []byte with string and use go:embed for templates\n* [`ba7cdc8c8`](https://github.com/siderolabs/talos/commit/ba7cdc8c8baf85e3015db4fa9e4446eaccf01115) chore: optimize DNSResolveCacheController\n* [`145f24063`](https://github.com/siderolabs/talos/commit/145f2406307e57a6f2eb1601d4f7d542d39a9f51) fix: don't modify a global map of profiles\n* [`6fe91ad9c`](https://github.com/siderolabs/talos/commit/6fe91ad9cf9f99401fc39a6ece24eed61f17b0e2) feat: provide Kubernets/Talos version compatibility for 1.8\n* [`909a5800e`](https://github.com/siderolabs/talos/commit/909a5800e4a9ada42288ae15992579e9acf6c372) fix: generate secureboot ISO .der certificate correctly\n* [`b0fdc3c8c`](https://github.com/siderolabs/talos/commit/b0fdc3c8caaf6ef756cdc4440dae45891bd96d01) fix: make static pods check output consistent\n* [`c6ad0fcce`](https://github.com/siderolabs/talos/commit/c6ad0fcceb8220f0bf96a45e131ba999cb723f79) fix: validate that workers don't get cluster CA key\n* [`3735add87`](https://github.com/siderolabs/talos/commit/3735add87cec47038a88ba641322c26cd487ac58) fix: reconnect to the logs stream in dashboard after reboot\n* [`9aa1e1b79`](https://github.com/siderolabs/talos/commit/9aa1e1b79b4a02902e0573c10e1c0bf71a2341af) fix: present all accepted CAs to the kube-apiserver\n* [`336e61174`](https://github.com/siderolabs/talos/commit/336e61174624741f697c77b98dd84ab9a7a749f4) fix: close the apid connection to other machines gracefully\n* [`ff2c427b0`](https://github.com/siderolabs/talos/commit/ff2c427b04963d69ba2eaa1084a0a078d742b9ac) fix: pre-create nftables chain to make kubelet use nftables\n* [`5622f0e45`](https://github.com/siderolabs/talos/commit/5622f0e450eda589f4b9a2af28b8517d08c2aae2) docs: change localDNS to hostDNS in release notes yaml section\n</p>\n</details>\n\n### Changes since v1.8.0-alpha.0\n<details><summary>108 commits</summary>\n<p>\n\n* [`0454130ad`](https://github.com/siderolabs/talos/commit/0454130ad97a61624fb0b916bf14a51dce8f199d) feat: suppress controller runtime first N failures on the console\n* [`3d35e5468`](https://github.com/siderolabs/talos/commit/3d35e54683b4930fa716c7afe6ecbad2af2f700b) chore: update hydrophone library\n* [`1f28726d4`](https://github.com/siderolabs/talos/commit/1f28726d46953262f33c91082528cd190f53b143) chore: support version with and without `v` prefix\n* [`9a56b8527`](https://github.com/siderolabs/talos/commit/9a56b8527b81c9653f5d01386c66ec1bde5d730a) chore(ci): fix parallel runs of tf pipelines\n* [`be35f380c`](https://github.com/siderolabs/talos/commit/be35f380ccf09d7667c3221765d6927546cffbca) chore: update pkgs/tools/extras\n* [`93df23444`](https://github.com/siderolabs/talos/commit/93df2344451e8f370f7f1d0f9590f65d6b02b936) docs: update opengraph image for main landing pages\n* [`d9d62d4da`](https://github.com/siderolabs/talos/commit/d9d62d4da6e30ac8f97a06dafd362a9e2ddc7006) feat: update Linux to 6.6.36\n* [`6b0fe5b8c`](https://github.com/siderolabs/talos/commit/6b0fe5b8ca9aa11d195b4b66608ad179bca7be44) docs: update deploying cilium docs for v1.7 and v1.8\n* [`52611a90d`](https://github.com/siderolabs/talos/commit/52611a90d870a131084375015d4d7270fa32cde8) feat: update Kubernetes to v1.30.2\n* [`c19cc4ccb`](https://github.com/siderolabs/talos/commit/c19cc4ccbc8c37b6dde49853dfc442a0f5404ab4) docs: clarify direct access needed to nodes in insecure mode\n* [`b4c871e4b`](https://github.com/siderolabs/talos/commit/b4c871e4b74014553ab81f7ff593ff7fa736df2d) chore: bump dependencies\n* [`cc345c8c9`](https://github.com/siderolabs/talos/commit/cc345c8c9413692148360684390c910de9e94748) feat: add support for configuring vlan filtering on the bridge\n* [`2d054ad35`](https://github.com/siderolabs/talos/commit/2d054ad3551428d8b3d93c8356b38aec7e9225eb) chore: handle documents diff in `apply-config` dry run\n* [`bd34f71f3`](https://github.com/siderolabs/talos/commit/bd34f71f3e5eae34907951a6480e0559736bfd72) feat: add apparmor pkg\n* [`71857fd4d`](https://github.com/siderolabs/talos/commit/71857fd4d3a262a6b41cad3af7d3abb7355d8509) docs: fix typo: `messure` -> `measure`\n* [`f75f16b0a`](https://github.com/siderolabs/talos/commit/f75f16b0a8088ac47a47c9ebabdf4803db5a397e) chore(ci): fix cluster name generation\n* [`c603d2bf9`](https://github.com/siderolabs/talos/commit/c603d2bf9552ed169e5baf012ad44305a54056a4) chore: output more info when `ExecuteCommandInPod` fails\n* [`4b5a7445e`](https://github.com/siderolabs/talos/commit/4b5a7445e9c3f7f2f53e958f6c2e91a1a86c2641) docs: fix missing Akamai platform in supported matrix\n* [`4701498a1`](https://github.com/siderolabs/talos/commit/4701498a1b5a213816962fb1acb56192423f525f) chore(ci): run e2e-aws-nvidia with zfs extension enabled\n* [`86a3222ae`](https://github.com/siderolabs/talos/commit/86a3222aeecb895cab233a0cd2474189f79a6f12) chore: use new disks api for iscsi tests\n* [`5ffc3f14b`](https://github.com/siderolabs/talos/commit/5ffc3f14bd2b49a2ee09f36fe9e66bcf7b5283e8) feat: show siderolink status on dashboard\n* [`6f6a5d105`](https://github.com/siderolabs/talos/commit/6f6a5d10573028662448a57c66c2255bb7703319) chore: upgrade to rtnetlink/v2 library\n* [`1fb8453c2`](https://github.com/siderolabs/talos/commit/1fb8453c2db1659dd6c1670e4174125b26e777c5) chore: update Go modules\n* [`8e15621e8`](https://github.com/siderolabs/talos/commit/8e15621e83a1005c3b7d8d682652f984765996c1) chore(ci): add conformance pipelines\n* [`7fcb521a6`](https://github.com/siderolabs/talos/commit/7fcb521a6a2d14de02926489d7297cf9429c7b38) feat: use hydrophone instead of sonobuoy\n* [`d1a0c1f98`](https://github.com/siderolabs/talos/commit/d1a0c1f983281593b4e6a71e2110ae9f81890edc) test: fix the integration test for no META name\n* [`535006334`](https://github.com/siderolabs/talos/commit/5350063340a80b99a8866afb94ac8673dd4e7ace) chore: fix our dns server implementation\n* [`c6f90d014`](https://github.com/siderolabs/talos/commit/c6f90d01493454bcf3281c9532b61fcb7e3dbb24) chore: replace sync.Map with concurrent.HashTrieMap\n* [`e8ced2c2d`](https://github.com/siderolabs/talos/commit/e8ced2c2ddc9e3f61138dd566628f7d11cf90c76) chore: drop k8s timeout in the default kubeconfig\n* [`7cbdce73f`](https://github.com/siderolabs/talos/commit/7cbdce73f74351954e506303ed9964b9668a3b40) fix: detect CD devices, fix user disks wipe test\n* [`aca475c66`](https://github.com/siderolabs/talos/commit/aca475c66509fa1fa7e7a0ca1b2a29f6542637fc) chore: small usability fixes\n* [`26cf566dc`](https://github.com/siderolabs/talos/commit/26cf566dc8c53263cbaae72855995e418da0852b) chore: bump our coredns fork\n* [`5e66e117e`](https://github.com/siderolabs/talos/commit/5e66e117e2ec19527fe949bf2d689df90835d63f) fix: initial assignment of Hetzner Cloud Alias IP\n* [`f07b79f4a`](https://github.com/siderolabs/talos/commit/f07b79f4a8c647d358b8cd41b3704eccf0341d33) feat: provide disk detection based on new blockdevices\n* [`8ee087268`](https://github.com/siderolabs/talos/commit/8ee087268317a73dc240c2b7569c2dab8d9df142) chore(ci): drop crashdump, save logs as artifacts\n* [`7c9a14383`](https://github.com/siderolabs/talos/commit/7c9a14383ee034b05cb9bd1ff49f8078cbbf5e66) fix: volume discovery improvements\n* [`80ca8ff71`](https://github.com/siderolabs/talos/commit/80ca8ff7135b0950b83d2ceaa32ee1eacce049e0) fix: update the cgroups for Talos core services\n* [`fe317f1e1`](https://github.com/siderolabs/talos/commit/fe317f1e1611d2f48595bfaf67c5e4ea3cd692e3) docs: fix typo in QEMU guest agent support on Proxmox\n* [`8dbe2128a`](https://github.com/siderolabs/talos/commit/8dbe2128a909a38ead8b6dfe1cc99e1ae36078d2) feat: implement Talos diagnostics\n* [`357d7754f`](https://github.com/siderolabs/talos/commit/357d7754fd739e9e875d17e0f8e63c333553090e) fix: clean up VM runners on cluster destroy\n* [`41f92e0ba`](https://github.com/siderolabs/talos/commit/41f92e0ba46b8ad9ddc3a4eabe86be915dea6b8e) chore: update Go to 1.22.4, other updates\n* [`4621e9bb7`](https://github.com/siderolabs/talos/commit/4621e9bb770e2a45c7c1ea8da76cbdabf76a4671) chore: add stale and lock issue workflows\n* [`82d9cd322`](https://github.com/siderolabs/talos/commit/82d9cd32298431760aef67f553924e4b4f48e207) fix: add upgrade errata for arm64/zboot kernels\n* [`9a23d846c`](https://github.com/siderolabs/talos/commit/9a23d846c1f6a88c30ffe55d2bf5a21d6cee150e) fix: downgrade Azure IMDS required version\n* [`30860210c`](https://github.com/siderolabs/talos/commit/30860210cce628839e97b8ece7edf90300556ed7) test: fix hardware test not to require PCI devices\n* [`9fcc9b841`](https://github.com/siderolabs/talos/commit/9fcc9b84152cb186324c13e317575f6da8b7bfa6) feat: update Flannel to v0.25.3\n* [`9d395b9de`](https://github.com/siderolabs/talos/commit/9d395b9de94f28fb9bf56bf795f916f783a847a0) chore: use bun instead of npm\n* [`a1684bdf8`](https://github.com/siderolabs/talos/commit/a1684bdf8f24858942cf61bee1efc81f7ef76f85) chore: speed up go generate for enumer\n* [`4dd0aa712`](https://github.com/siderolabs/talos/commit/4dd0aa7120b52cab5de219010f2b78b7dd9b73ce) feat: implement PCI device bus enumeration\n* [`b0466e0ab`](https://github.com/siderolabs/talos/commit/b0466e0abf2f8af43f3fb6c9661f44000fe1d54b) fix: disable kexec on GCP/Azure\n* [`911c25574`](https://github.com/siderolabs/talos/commit/911c255742d02440806e5f3df6967c091bb5288e) chore: fix go.work resolution\n* [`2f088ede0`](https://github.com/siderolabs/talos/commit/2f088ede0952d72dbb7bf33dd0510cb8ff8b8e3a) docs: add another example for installing cilium\n* [`3967e0777`](https://github.com/siderolabs/talos/commit/3967e07777707fa8af339f46596b678e1eaaa9f2) feat: update etcd to 3.5.14\n* [`3367ded9f`](https://github.com/siderolabs/talos/commit/3367ded9feac84e9c6c1f3efcea9e61f3083b4ac) fix: correct time adjustment in `time.SyncController`\n* [`893e64fcb`](https://github.com/siderolabs/talos/commit/893e64fcb1f09efed990b9b642359d7bcabffd42) fix: replace `nslookup` with `dig` in integration tests\n* [`0359c8537`](https://github.com/siderolabs/talos/commit/0359c8537c1b3b01e94394604e16fd817b986f9e) chore: unify toml packages being used\n* [`4feb94ca0`](https://github.com/siderolabs/talos/commit/4feb94ca099746e3a90106522b920a77cfe77ce0) feat: add multidoc check to the Talos quirks module\n* [`0b4a9777f`](https://github.com/siderolabs/talos/commit/0b4a9777fc2ddcc61430db23837455ff383ba1a3) docs: update talosctl install instructions for 1.8\n* [`da8305ffb`](https://github.com/siderolabs/talos/commit/da8305ffb46d285662bca12ec02760d6121342c8) test: add a test for watchdog timers\n* [`da7f27640`](https://github.com/siderolabs/talos/commit/da7f2764092b883bcdf5daf81b8f6f7ef997ac0a) fix: mount `tracefs` filesystem\n* [`7b37e5b63`](https://github.com/siderolabs/talos/commit/7b37e5b63d54c2d197336e4fbee941fa5f2423c0) chore(ci): fix integration extensions\n* [`de7553d77`](https://github.com/siderolabs/talos/commit/de7553d77f7e02a83f764820a71badbf0d851bc9) fix(ci): cron jobs\n* [`eb510d9fd`](https://github.com/siderolabs/talos/commit/eb510d9fdf3a40b2ae881e3dd19a94058d4ef529) chore: require enabled bootloader for docker provisioner\n* [`a9cf9b789`](https://github.com/siderolabs/talos/commit/a9cf9b78921bef76b66aa5fa5940977767124bfe) fix: correctly handle dns messages in our dns implementation\n* [`c2b19dcb9`](https://github.com/siderolabs/talos/commit/c2b19dcb978ab015bd9b3c5a4eb47a53ee25e297) chore: move to containerd 2.0 API\n* [`92a274e9a`](https://github.com/siderolabs/talos/commit/92a274e9a0a83b3e240784bf12817f08559ac8e8) fix: workaround problems with udevd races\n* [`31b24ea3d`](https://github.com/siderolabs/talos/commit/31b24ea3d70f88d031d81bd0f914754b0cee411e) chore(ci): split integration misc\n* [`8a1371337`](https://github.com/siderolabs/talos/commit/8a1371337faea406c9193e91c8de8ffc056b5135) fix: produce stable order of bonds with equinix\n* [`6406193f4`](https://github.com/siderolabs/talos/commit/6406193f4637157c3d31219dc2c39aca7fa736a4) test: add Equnix Metal sample metadata with two bonds\n* [`01ea82053`](https://github.com/siderolabs/talos/commit/01ea82053e0a2ffe4193243e235aae2ade0e2d88) fix: time sync over NTP from future era\n* [`5aea42427`](https://github.com/siderolabs/talos/commit/5aea4242782d4ff00ba51e85422fbdf7c2ceca64) fix(ci): fix crons by setting up buildx always\n* [`84706c3e2`](https://github.com/siderolabs/talos/commit/84706c3e2920b9bf68c7b6dcfb73f1e16f3f656b) docs: default to brew docs for talosctl\n* [`fcd65ff65`](https://github.com/siderolabs/talos/commit/fcd65ff65ce78aa5ebe7ca4b12aea2571bd54c49) feat: enable forwardKubeDNSToHost by default\n* [`2e64e9e4e`](https://github.com/siderolabs/talos/commit/2e64e9e4e026817f844765b4c8a7d346d85bf983) fix: require accepted CAs on worker nodes\n* [`23c1c4560`](https://github.com/siderolabs/talos/commit/23c1c4560ecd2084e505a64b0b701707aa79c5e6) fix(ci): fix crons fby rekres\n* [`2d50392c5`](https://github.com/siderolabs/talos/commit/2d50392c5a16a97a2daa47edcfd362b0891c4a06) feat: update containerd to 2.0.0-rc.2, runc to 1.2.0-rc.1\n* [`a12e4bb24`](https://github.com/siderolabs/talos/commit/a12e4bb24e19701e926103753ec3ee0f98e8d3a2) chore(ci): fix github action crons\n* [`e7bd9cd2b`](https://github.com/siderolabs/talos/commit/e7bd9cd2bbbd337ef72adc2a3be5adc8b530cd6e) fix: decrease maximum negative ttl for dns responses\n* [`9c3ebad9f`](https://github.com/siderolabs/talos/commit/9c3ebad9fd7a62418fc6748364a23d27ff1c3ff7) chore(ci): kresify gh actions\n* [`ff60f6fde`](https://github.com/siderolabs/talos/commit/ff60f6fde6cb325b9f1f4801f658f4e9554c6c2b) refactor: make some of the extensions package public\n* [`ce8c86d64`](https://github.com/siderolabs/talos/commit/ce8c86d640949d24107d9057358b39c860fc1e70) fix: panic in osroot controller\n* [`e1711cd3c`](https://github.com/siderolabs/talos/commit/e1711cd3c9852137956f1cce7174b0a337d53b63) chore: stop using containerd package for cri namespace\n* [`d4307043f`](https://github.com/siderolabs/talos/commit/d4307043ffbfcadb5b67b12c95816c2a3a5819c3) fix: update go-tail library to fix 'short read' error\n* [`7cd13ef4a`](https://github.com/siderolabs/talos/commit/7cd13ef4a619fa5c13dc9ed147e6626ddcabbaf2) docs: add documentation on using Multus with Talos\n* [`4784da3ef`](https://github.com/siderolabs/talos/commit/4784da3ef88745d1ce38f1e49239c882c081e6fb) feat: use new circular buffer compressed chunks feature\n* [`78b48eb3a`](https://github.com/siderolabs/talos/commit/78b48eb3ae78ec9953104247ec73cafa26a61264) feat: include EDAC drivers\n* [`0bf2d69fb`](https://github.com/siderolabs/talos/commit/0bf2d69fbb2f2c1f693565243b46391da00d4dba) feat: update Kubernetes to 1.30.1\n* [`53f548913`](https://github.com/siderolabs/talos/commit/53f54891302b193bf35ede52af235457396e91ce) fix: increase host dns packet ttl for pods\n* [`dedb6d360`](https://github.com/siderolabs/talos/commit/dedb6d360d25e6d00d560ddb40563c2a5a95bb1f) fix: update github.com/siderolabs/siderolink to v0.3.7\n* [`43939f1a6`](https://github.com/siderolabs/talos/commit/43939f1a6e4b65cf9b64d1d09dc19df709a41275) docs: fix typos, add docker socket info\n* [`6663068bb`](https://github.com/siderolabs/talos/commit/6663068bbd1750fd57ddf9ca63b0f305d895b33b) chore: update project in GCP testing\n* [`b86edc677`](https://github.com/siderolabs/talos/commit/b86edc6776f77a65d3a254cf0f0d713ce7a9145e) chore: update office hours in talos repo\n* [`cfa25d22d`](https://github.com/siderolabs/talos/commit/cfa25d22dc30b877ea47ba1bfae3ca5f29977f1b) chore: remove docs prior to 1.0 from website navigation\n* [`120705459`](https://github.com/siderolabs/talos/commit/12070545996af3435454654500cd75a50111cca9) chore: handle I/O error for xfs_repair\n* [`b7afe2669`](https://github.com/siderolabs/talos/commit/b7afe2669b2a9a32ca37bbcc7a7e8af4879cf403) feat: update Linux 6.6.30\n* [`26519ceed`](https://github.com/siderolabs/talos/commit/26519ceed0c790abd851de310409baf6af89e2b7) docs: update proxmox.md\n* [`851b91a0e`](https://github.com/siderolabs/talos/commit/851b91a0e22055443eabace9b89a566e0cbec679) fix: don't enable hostDNS for versions of Talos which do not have it\n* [`42ac5cd0c`](https://github.com/siderolabs/talos/commit/42ac5cd0c2ef610f055afb208384e60fc9389e82) fix: check for `nil` machine config during installation\n* [`1d29111d4`](https://github.com/siderolabs/talos/commit/1d29111d4310cc16078248e66817843e6e740821) chore: update Go to 1.22.3\n* [`f4d7b9d9a`](https://github.com/siderolabs/talos/commit/f4d7b9d9a921cdaf33b9efdae1569dd921628270) feat: gather plaform dns names\n* [`0b0f9995a`](https://github.com/siderolabs/talos/commit/0b0f9995a6cd2b41f48dc867f4e0248284e53463) docs: add resource information, some grammar fixes\n* [`763dae250`](https://github.com/siderolabs/talos/commit/763dae2508242ee91a7e38e5962facb334691289) fix: add cluster name to the worker machine config\n* [`4aac5b4ec`](https://github.com/siderolabs/talos/commit/4aac5b4ec30f4a9ee0f2e4a4239b399357930b6c) feat: mount /sys/kernel/security into kubelet\n* [`817f18153`](https://github.com/siderolabs/talos/commit/817f18153f592f5bf38884f05aed2e4ce2fd3ad7) docs: remove mention of enabling KubePrism after v1.6\n* [`c08d79732`](https://github.com/siderolabs/talos/commit/c08d797326686434dc035de3ca40200293d74701) docs: fix the variable name typo\n* [`478b862b4`](https://github.com/siderolabs/talos/commit/478b862b4c38bd5a5ba1313a3779f9395e4ba38d) fix: do not fail cli action tracker when boot id cannot be read\n* [`be510f9eb`](https://github.com/siderolabs/talos/commit/be510f9eb2b84a88ce730fab36bf575c976efa8b) docs: fix grpc_tunnel value to true\n* [`b7b8a8d8f`](https://github.com/siderolabs/talos/commit/b7b8a8d8fa6335d3f0036c50792971adefe5e240) docs: add logs example for the certificate errors troubleshooting\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`ca662d2`](https://github.com/siderolabs/discovery-client/commit/ca662d218418eb50eb22d84560c290bef4369702) feat: export default GRPC dial options for the client\n* [`7a767fa`](https://github.com/siderolabs/discovery-client/commit/7a767fa89005209f5f39b2f5891ca7b169f52d89) chore: bump Go, deps and rekres\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>4 commits</summary>\n<p>\n\n* [`cab51d8`](https://github.com/siderolabs/extras/commit/cab51d8f49fec77266b74d2535f61bf73bb8b2c4) feat: update dependencies\n* [`0efb05f`](https://github.com/siderolabs/extras/commit/0efb05f989d7e745f61955570992c54094d3fddf) feat: update Go to 1.22.4\n* [`01ad9f5`](https://github.com/siderolabs/extras/commit/01ad9f5e2aa7e0ef2b6d9e0a19e7bf6a39dd5d94) feat: update Go to 1.22.3\n* [`fa6663c`](https://github.com/siderolabs/extras/commit/fa6663c2abf90d82667a6c33cbc6f5edb2d1c525) feat: update Go to 1.22.2\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`7654108`](https://github.com/siderolabs/gen/commit/7654108fe6ae15d4765584342709bc0bced6b3d6) chore: add hashtriemap implementation\n* [`8485864`](https://github.com/siderolabs/gen/commit/84858640dc9c3032219380885283b995d4f2b0d1) chore: optimize maps.Values and maps.Keys\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>1 commit</summary>\n<p>\n\n* [`782aac0`](https://github.com/siderolabs/go-api-signature/commit/782aac0d69752fe7c6eba36bae8d1383ffdc0b04) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>3 commits</summary>\n<p>\n\n* [`cbce5c3`](https://github.com/siderolabs/go-circular/commit/cbce5c3e47d1c6a26a588cbb6f77af2f9bc3e5b7) feat: add persistence support\n* [`3c48c53`](https://github.com/siderolabs/go-circular/commit/3c48c53c1449b2b5e5ddde14e0351d93a351b021) feat: implement extra compressed chunks\n* [`835f04c`](https://github.com/siderolabs/go-circular/commit/835f04c9ba6083ef451b5bbba748200202d1a0a9) chore: rekres, update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`0639758`](https://github.com/siderolabs/go-loadbalancer/commit/0639758a06785c0c8c65e18774b81d85ab40acdf) chore: bump deps\n</p>\n</details>\n\n### Changes from siderolabs/go-pcidb\n<details><summary>1 commit</summary>\n<p>\n\n* [`2e79017`](https://github.com/siderolabs/go-pcidb/commit/2e7901711733e2d7e5e5a767a68cae08df148dc5) feat: rekres, update PCI IDs\n</p>\n</details>\n\n### Changes from siderolabs/go-tail\n<details><summary>1 commit</summary>\n<p>\n\n* [`7cb7294`](https://github.com/siderolabs/go-tail/commit/7cb7294b8af33175bc463c84493776e6e4da9c4f) fix: remove unexpected short read error\n</p>\n</details>\n\n### Changes from siderolabs/go-talos-support\n<details><summary>1 commit</summary>\n<p>\n\n* [`69891cf`](https://github.com/siderolabs/go-talos-support/commit/69891cf046628969e651fc751e433aad86ec22c4) chore: remove containerd dependency\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>36 commits</summary>\n<p>\n\n* [`ce49757`](https://github.com/siderolabs/pkgs/commit/ce497578fd6911be16848df71156558565616ac1) feat: update flannel-cni plugin to v1.5.1\n* [`289ed6b`](https://github.com/siderolabs/pkgs/commit/289ed6ba2de66c7230b154df9ca65581f7619055) feat: bump deps\n* [`8d6b19a`](https://github.com/siderolabs/pkgs/commit/8d6b19a8a15c6f0b8b76c0dc65657d10830bbf3a) feat: update Linux to 6.6.36\n* [`b671d46`](https://github.com/siderolabs/pkgs/commit/b671d4604db736c7ac541c40ba2c5deeaf03baee) feat: update containerd/runc to the next rc versions\n* [`c7e9591`](https://github.com/siderolabs/pkgs/commit/c7e9591dcdd18f94a391a329789fa2ddf93a509f) feat: enable CONFIG_X86_AMD_PSTATE\n* [`84bad89`](https://github.com/siderolabs/pkgs/commit/84bad890a6eed3b1fa2d01df494c26e695d5a290) feat: add 'apparmor' package\n* [`4d9869a`](https://github.com/siderolabs/pkgs/commit/4d9869a06f06cab4ed56b42b93974804f33b6435) feat: update Linux to 6.6.33\n* [`e5990e8`](https://github.com/siderolabs/pkgs/commit/e5990e87dc8e491adbe42df246f607eddd25af94) feat: enable CONFIG_KSM\n* [`a37f382`](https://github.com/siderolabs/pkgs/commit/a37f382b8c11a478d1015b9fd1042257684529bc) fix: network for Rockchip boards like Rock64\n* [`95218c7`](https://github.com/siderolabs/pkgs/commit/95218c7868047d7075465fb4e112975460acff00) fix: enable PAGE_TABLE_CHECK\n* [`cbd9cd7`](https://github.com/siderolabs/pkgs/commit/cbd9cd79a73ada392bc03f04dca2a982878ce2b6) feat: enable SCTP support\n* [`c309452`](https://github.com/siderolabs/pkgs/commit/c309452aefee22fbc3d714781b4cc880881e0a5d) feat: bump dependencies\n* [`3a56032`](https://github.com/siderolabs/pkgs/commit/3a56032bf8e49296cf4a02655925767ab9c8b1d2) chore: rekres\n* [`db7f60c`](https://github.com/siderolabs/pkgs/commit/db7f60c77b2effcfc5640fd50b871052e842b1eb) feat: bump Linux to 6.6.32\n* [`c647a05`](https://github.com/siderolabs/pkgs/commit/c647a0591741916e4bc28c35dc6a9cc36add65e0) feat: update ipxe to the latest\n* [`f350879`](https://github.com/siderolabs/pkgs/commit/f350879ba82443c662582d1b43e6d9fc06826c55) feat: update containerd to 2.0.0-rc.2, runc to 1.2.0-rc.1\n* [`f8392fb`](https://github.com/siderolabs/pkgs/commit/f8392fb597559eaf3e12c4284acc7805667e7f8e) feat: update Linux firmware to 20240513\n* [`f414bbd`](https://github.com/siderolabs/pkgs/commit/f414bbdb189e3ab880ee65efe2a030667aae77ec) fix: disable CONFIG_EFI_DISABLE_PCI_DMA option\n* [`9ebfd1b`](https://github.com/siderolabs/pkgs/commit/9ebfd1b90ed674a984eb69f03b6bc79f21573313) feat: enable EDAC drivers\n* [`f9559de`](https://github.com/siderolabs/pkgs/commit/f9559de4cb7961bd54745ddeb0ffb3414f7125aa) fix: drbd module installation\n* [`492638d`](https://github.com/siderolabs/pkgs/commit/492638d5d8242d733da4cf2a573380be1e780f2f) feat: update dependencies\n* [`bd70572`](https://github.com/siderolabs/pkgs/commit/bd70572339f6cc28dd88d0e4e28f079299268c8b) feat: update Go to 1.22.3\n* [`edb600a`](https://github.com/siderolabs/pkgs/commit/edb600aa02ff620217cc430bdc4a699d9c9eba82) feat: update zfs package to v2.2.4\n* [`6775002`](https://github.com/siderolabs/pkgs/commit/67750020042162af7fc01e5f14a678fc6eeaaf6b) feat: enable NFT FIB lookups\n* [`28c5696`](https://github.com/siderolabs/pkgs/commit/28c5696e7c97b12765e65bd1bb758f8cb19e6adc) feat: update Linux to 6.6.29\n* [`9c8a02c`](https://github.com/siderolabs/pkgs/commit/9c8a02c234b52cf3624ebf79f7e76065cbc1eeff) feat: update containerd to 1.7.16\n* [`ca6249b`](https://github.com/siderolabs/pkgs/commit/ca6249b4b7d00b6f16e1a7264f55a4814300df63) feat: compress amd64 Linux kernel using zstd\n* [`718a7da`](https://github.com/siderolabs/pkgs/commit/718a7da83fe843cd59745078fe1a814c75bc4384) feat: enable SELinux\n* [`207481f`](https://github.com/siderolabs/pkgs/commit/207481f7b16d2b0c98053432f4ad86484bf0b1ec) feat(intel): add support for power management and ACPI options for Intel CPUs\n* [`dfa7dce`](https://github.com/siderolabs/pkgs/commit/dfa7dceb5ae50af454f527ac7c774c93d00054cf) feat: update Linux to 6.6.28\n* [`7b30b61`](https://github.com/siderolabs/pkgs/commit/7b30b61ef3ba104f3ea21469632d3d043c5fd6f6) fix: use proper EFI zBoot image\n* [`010913b`](https://github.com/siderolabs/pkgs/commit/010913b8bf2b7c7df2d16efcdf23a4efbb9913ab) feat: update Linux 6.6.26, containerd 1.7.15\n* [`da397fa`](https://github.com/siderolabs/pkgs/commit/da397fa0e55284f466af982f98cf93e7075e6298) feat: enable BFQ IO scheduler\n* [`c839801`](https://github.com/siderolabs/pkgs/commit/c83980113db4aabbda4393d7aa8e6ab734a6069b) feat: enable zboot on arm64 with zstd compression\n* [`1b28e2c`](https://github.com/siderolabs/pkgs/commit/1b28e2ce58e5702bcbbd5ed13fbd7cf6420dc12d) feat: go 1.22.2, Linux 6.6.24\n* [`05db2a8`](https://github.com/siderolabs/pkgs/commit/05db2a88e6985470f4e7dc6b21fbdd9df1e63aea) fix: revert musl to 1.2.4\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>4 commits</summary>\n<p>\n\n* [`e76747b`](https://github.com/siderolabs/siderolink/commit/e76747ba523b336ab8b9143293c920ff64bc4f14) chore: migrate to rtnetlink/2\n* [`3a587fc`](https://github.com/siderolabs/siderolink/commit/3a587fcf9dbb259e216495496a523faaea427d04) fix: do not ever skip updates which have remove flag\n* [`be00ff5`](https://github.com/siderolabs/siderolink/commit/be00ff59bac50e0da4cd0747f8e5f30c7b029ded) chore: redo event filtering as a sequence of iterators\n* [`a936b60`](https://github.com/siderolabs/siderolink/commit/a936b60645267d2e7320083b402df5ad19de76f5) chore: handle peer events in batches\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>7 commits</summary>\n<p>\n\n* [`31ad71b`](https://github.com/siderolabs/tools/commit/31ad71bdb3b2b33ab1c74175ffc1eff0cae33866) feat: update dependencies\n* [`d2746e5`](https://github.com/siderolabs/tools/commit/d2746e5a7a60a22ad957c8bc04831bae8c191af6) feat: update Go to 1.22.4\n* [`06ba64e`](https://github.com/siderolabs/tools/commit/06ba64ec3044c9c4ea51b8a624c46503a4f5fe26) feat: update dependencies\n* [`7e5a248`](https://github.com/siderolabs/tools/commit/7e5a2482284e00f60cd44a5d155fcdf2291f1fc9) feat: update dependencies\n* [`c34ec5b`](https://github.com/siderolabs/tools/commit/c34ec5bfd44faa4a5ccced07136246fb25858635) feat: update Go to 1.22.3\n* [`3c25a6f`](https://github.com/siderolabs/tools/commit/3c25a6f164f3004d222bb13f5b663e01b80ff882) fix: update pkg-config configure flag\n* [`bd405ff`](https://github.com/siderolabs/tools/commit/bd405ff5d8d511eeef17f0a6126ad6cdd3a849bb) feat: update go to 1.22.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.2.3 -> v0.4.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.11.1 -> v1.12.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.5.1 -> v1.7.0\n* **github.com/aws/aws-sdk-go-v2/config**               v1.27.10 -> v1.27.23\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.16.1 -> v1.16.9\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.30.1 -> v1.35.1\n* **github.com/aws/smithy-go**                          v1.20.2 -> v1.20.3\n* **github.com/beevik/ntp**                             v1.3.1 -> v1.4.3\n* **github.com/containerd/containerd/api**              v1.8.0-rc.2 **_new_**\n* **github.com/containerd/containerd/v2**               v2.0.0-rc.3 **_new_**\n* **github.com/containerd/errdefs**                     v0.1.0 **_new_**\n* **github.com/containerd/platforms**                   v0.2.1 **_new_**\n* **github.com/containernetworking/cni**                v1.1.2 -> v1.2.2\n* **github.com/containernetworking/plugins**            v1.4.1 -> v1.5.1\n* **github.com/cosi-project/runtime**                   v0.4.1 -> v0.5.0\n* **github.com/docker/docker**                          v26.0.0 -> v27.0.3\n* **github.com/fatih/color**                            v1.16.0 -> v1.17.0\n* **github.com/foxboron/go-uefi**                       48be911532c2 -> 205d5597883a\n* **github.com/google/go-containerregistry**            v0.19.1 -> v0.19.2\n* **github.com/google/go-tpm**                          ee6cbcd136f8 -> v0.9.1\n* **github.com/hashicorp/go-getter/v2**                 v2.2.1 -> v2.2.2\n* **github.com/hetznercloud/hcloud-go/v2**              v2.7.0 -> v2.10.2\n* **github.com/insomniacslk/dhcp**                      c728f5dd21c8 -> bf3278ac95c1\n* **github.com/jsimonetti/rtnetlink/v2**                v2.0.2 **_new_**\n* **github.com/klauspost/compress**                     v1.17.9 **_new_**\n* **github.com/klauspost/cpuid/v2**                     v2.2.7 -> v2.2.8\n* **github.com/miekg/dns**                              v1.1.58 -> v1.1.61\n* **github.com/pelletier/go-toml/v2**                   v2.2.2 **_new_**\n* **github.com/prometheus/procfs**                      v0.13.0 -> v0.15.1\n* **github.com/rivo/tview**                             a22293bda944 -> b0a7293b8130\n* **github.com/safchain/ethtool**                       v0.3.0 -> v0.4.1\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.25 -> v1.0.0-beta.28\n* **github.com/siderolabs/discovery-client**            v0.1.8 -> v0.1.9\n* **github.com/siderolabs/extras**                      v1.7.0-1-gbb76755 -> v1.8.0-alpha.0-3-gcab51d8\n* **github.com/siderolabs/gen**                         v0.4.8 -> v0.5.0\n* **github.com/siderolabs/go-api-signature**            v0.3.2 -> v0.3.3\n* **github.com/siderolabs/go-blockdevice/v2**           3265299b0192 -> f4a4030394f4\n* **github.com/siderolabs/go-circular**                 v0.1.0 -> v0.2.0\n* **github.com/siderolabs/go-loadbalancer**             v0.3.3 -> v0.3.4\n* **github.com/siderolabs/go-pcidb**                    v0.2.0 -> v0.3.0\n* **github.com/siderolabs/go-tail**                     v0.1.0 -> v0.1.1\n* **github.com/siderolabs/go-talos-support**            v0.1.0 -> 69891cf04662\n* **github.com/siderolabs/pkgs**                        v1.7.0-6-g29106c0 -> v1.8.0-alpha.0-34-gce49757\n* **github.com/siderolabs/siderolink**                  v0.3.5 -> v0.3.9\n* **github.com/siderolabs/talos/pkg/machinery**         v1.7.0 -> e1711cd3c985\n* **github.com/siderolabs/tools**                       v1.7.0-1-g10b2a69 -> v1.8.0-alpha.0-6-g31ad71b\n* **github.com/spf13/cobra**                            v1.8.0 -> v1.8.1\n* **go.etcd.io/etcd/api/v3**                            v3.5.13 -> v3.5.14\n* **go.etcd.io/etcd/client/pkg/v3**                     v3.5.13 -> v3.5.14\n* **go.etcd.io/etcd/client/v3**                         v3.5.13 -> v3.5.14\n* **go.etcd.io/etcd/etcdutl/v3**                        v3.5.13 -> v3.5.14\n* **golang.org/x/net**                                  v0.23.0 -> v0.26.0\n* **golang.org/x/oauth2**                               v0.18.0 -> v0.21.0\n* **golang.org/x/sync**                                 v0.6.0 -> v0.7.0\n* **golang.org/x/sys**                                  v0.18.0 -> v0.21.0\n* **golang.org/x/term**                                 v0.18.0 -> v0.21.0\n* **golang.org/x/text**                                 v0.14.0 -> v0.16.0\n* **google.golang.org/grpc**                            v1.62.1 -> v1.64.0\n* **google.golang.org/protobuf**                        v1.33.0 -> v1.34.2\n* **k8s.io/api**                                        v0.30.0 -> v0.30.2\n* **k8s.io/apiserver**                                  v0.30.0 -> v0.30.2\n* **k8s.io/client-go**                                  v0.30.0 -> v0.30.2\n* **k8s.io/component-base**                             v0.30.0 -> v0.30.2\n* **k8s.io/cri-api**                                    v0.30.0 -> 3a66d9d86654\n* **k8s.io/klog/v2**                                    v2.120.1 -> v2.130.1\n* **k8s.io/kube-scheduler**                             v0.30.0 -> v0.30.2\n* **k8s.io/kubectl**                                    v0.30.0 -> v0.30.2\n* **k8s.io/kubelet**                                    v0.30.0 -> v0.30.2\n* **k8s.io/pod-security-admission**                     v0.30.0 -> v0.30.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**     v1.2.69 -> v1.2.70\n* **sigs.k8s.io/hydrophone**                            91065c9fe3a5 **_new_**\n\nPrevious release can be found at [v1.7.0](https://github.com/siderolabs/talos/releases/tag/v1.7.0)\n\n## [Talos 1.8.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.8.0-alpha.0) (2024-05-01)\n\nWelcome to the v1.8.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\nLinux: 6.6.29\ncontainerd: 1.7.16\n\nTalos is built with Go 1.22.2.\n\n\n### ZSTD Compression\n\nTalos Linux now compresses kernel and initramfs using ZSTD.\nLinux arm64 kernel is now compressed (previously it was uncompressed).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Dmitry Sharshakov\n* Artem Chernyshev\n* Bernard Gütermann\n* Birger J. Nordølum\n* Dennis Marttinen\n* Evan Johnson\n* Grzegorz Rożniecki\n* Igor Rzegocki\n* Noel Georgi\n* Spencer Smith\n* darox\n* looklose\n\n### Changes\n<details><summary>51 commits</summary>\n<p>\n\n* [`07f78182c`](https://github.com/siderolabs/talos/commit/07f78182c621296e6c694b64ead8f14695b2e3b7) fix: use a fresh context for etcd unlock\n* [`84cd7dbec`](https://github.com/siderolabs/talos/commit/84cd7dbec4ce01a8f80a855267e1c44dfc6dcacc) feat: update Linux to 6.6.29\n* [`70fdca6a4`](https://github.com/siderolabs/talos/commit/70fdca6a43abcb48030239047500fa8819f9346d) chore: update minimum hardware requirement for vmware ova\n* [`b690ffeb8`](https://github.com/siderolabs/talos/commit/b690ffeb899c4a133f98e212826830e3b320abe4) test: improve DNS resolver test stability\n* [`5aa0299b6`](https://github.com/siderolabs/talos/commit/5aa0299b6e3efefa7077aab5955526a5136b8761) style: use correct capitalization for openstack\n* [`4c0c626b7`](https://github.com/siderolabs/talos/commit/4c0c626b786f14c5eabdc65e88d2aae92829bf73) feat: use zstd compression in place of xz\n* [`98906ed6e`](https://github.com/siderolabs/talos/commit/98906ed6ea1afc5a758871a7c2d8251fccaef106) fix: use reboot delay only in case of error\n* [`05fd042bb`](https://github.com/siderolabs/talos/commit/05fd042bb3600541a8e2587b66b8b4c4e9f99c27) test: improve the reset integration tests\n* [`8cdf0f7cb`](https://github.com/siderolabs/talos/commit/8cdf0f7cb007790190197356355a16c8e427afab) docs: fix typo in Cilium instructions\n* [`dd1d279da`](https://github.com/siderolabs/talos/commit/dd1d279daa8c2a18c2477839b2c11e5f2f554693) fix: allow more flags in `talosctl cluster create --input-dir`\n* [`ef4394e58`](https://github.com/siderolabs/talos/commit/ef4394e586e42c4b5085299029a2aacb3b89502d) chore: update kernel and other packages\n* [`ccdb4c8b1`](https://github.com/siderolabs/talos/commit/ccdb4c8b10450aa7fb6c32b0559bda73746a03ed) chore: update google.golang.org/grpc to 1.63.2\n* [`c5b59df69`](https://github.com/siderolabs/talos/commit/c5b59df6976095aca5c4bac367084874242e9e80) fix: wait for devices to be discovered before probing filesystems\n* [`0821b9c50`](https://github.com/siderolabs/talos/commit/0821b9c50b86bf9f7d08a1ba7b177abb7e2568c4) feat: add `--non-masquerade-cidrs` flag to `talosctl cluster create`\n* [`2bf613ad3`](https://github.com/siderolabs/talos/commit/2bf613ad3bd1582b520b2f661b7e0bfab4207eed) fix: add endpoints for \"virtual\" `host-dns` service\n* [`f4163aefe`](https://github.com/siderolabs/talos/commit/f4163aefeda2bf91be36af45239716c53ec982b1) fix: bump priority of OpenStack routes if IPv6 and default gateway\n* [`6fbd1263c`](https://github.com/siderolabs/talos/commit/6fbd1263ccbe20857cca90b5f69906651caa4f54) feat: report process MAC labels\n* [`d46032821`](https://github.com/siderolabs/talos/commit/d460328210ee3beea1b98ea5f23fcda5c2e2fd44) fix: return proper value from Bridge.STP instead of plain nil\n* [`bac1d00c3`](https://github.com/siderolabs/talos/commit/bac1d00c35cb6e1407884298118ee7b4ffc5fdfa) chore: prepare for Talos 1.8\n* [`d6c8067e1`](https://github.com/siderolabs/talos/commit/d6c8067e15d8177c7394abad65b95ea98c597b9d) docs: make 1.7 docs the default\n* [`d7c3a0735`](https://github.com/siderolabs/talos/commit/d7c3a0735eab85dd24e86fe3e0872253067e8f10) docs: add what's new for v1.7\n* [`908f67fa1`](https://github.com/siderolabs/talos/commit/908f67fa15e0de507c2f69fac0851d42376a66ce) feat: add host dns support for resolving member addrs\n* [`0d20b637d`](https://github.com/siderolabs/talos/commit/0d20b637d68a581354361bbceecb90395f24fedb) feat: update Kubernetes to 1.30.0\n* [`ec69d7a78`](https://github.com/siderolabs/talos/commit/ec69d7a7855753e3e458f2cf7c211bf67e703220) chore: replace math/rand with math/rand/v2\n* [`89040ce43`](https://github.com/siderolabs/talos/commit/89040ce4329743fa2037fb1cf65d978801753dbe) chore: update go-blockdevice/v2 library to the latest version\n* [`0a785802e`](https://github.com/siderolabs/talos/commit/0a785802ea22071e67d7ec85944513e73624b1ac) fix: overlay installer operations\n* [`b1b63f658`](https://github.com/siderolabs/talos/commit/b1b63f658eba5cbb08cbd05af959c6d397662e05) fix: mark overlay installer executable\n* [`3433fa13b`](https://github.com/siderolabs/talos/commit/3433fa13bf555a871e76f8ce726d5afd141a16e1) feat: use container DNS when in container mode\n* [`5d07ac5a7`](https://github.com/siderolabs/talos/commit/5d07ac5a7db9d2291a86ee966ee704b30afea342) fix: close apid inter-backend connections gracefully for real\n* [`7ba18555b`](https://github.com/siderolabs/talos/commit/7ba18555b098ba2617efce2438d6bfbec1dc0041) docs: fix typos in Akamai and AWS platform docs\n* [`3dd1f4e88`](https://github.com/siderolabs/talos/commit/3dd1f4e88c22734f03f7609791558b8bbbae3756) chore: extract `pkg/imager/quirks` to `pkg/machinery`\n* [`78bc3a433`](https://github.com/siderolabs/talos/commit/78bc3a433e8b10839034bd40b73fcc720438b943) docs: update Cilium docs\n* [`831f3d39e`](https://github.com/siderolabs/talos/commit/831f3d39e9b030cd1bcd3313246ebccf34f34205) feat: update Flannel to v0.25.1\n* [`ea5b3ff0c`](https://github.com/siderolabs/talos/commit/ea5b3ff0c27cb033d525d172d4006e0645a924ba) feat: update Kubernetes to v1.30.0-rc.2\n* [`54dac5ed4`](https://github.com/siderolabs/talos/commit/54dac5ed40698b8886096c620ac19ed55a4b99a1) feat: update Linux 6.6.24, containerd 1.7.15\n* [`c51f146da`](https://github.com/siderolabs/talos/commit/c51f146daf3265bbeb4513c649938b2656ff1686) docs: update Akamai platform docs\n* [`9550f5ff7`](https://github.com/siderolabs/talos/commit/9550f5ff7a285df7c251df425e8f28d4c668224f) docs: fix getAuthenticationMethod and completePathFromNode docs\n* [`bfbd02abf`](https://github.com/siderolabs/talos/commit/bfbd02abfb1d84d14a73f1e247d62e728860d2f3) fix: assign different priority to IPv6 default gateway on OpenStack\n* [`c8f674bd3`](https://github.com/siderolabs/talos/commit/c8f674bd3d582f606848475bca3d22f309b2367c) test: add a test for 'spin' container runtime\n* [`5390ccd48`](https://github.com/siderolabs/talos/commit/5390ccd48c78e864f53cc45848772c931276380d) chore: replace []byte with string and use go:embed for templates\n* [`ba7cdc8c8`](https://github.com/siderolabs/talos/commit/ba7cdc8c8baf85e3015db4fa9e4446eaccf01115) chore: optimize DNSResolveCacheController\n* [`145f24063`](https://github.com/siderolabs/talos/commit/145f2406307e57a6f2eb1601d4f7d542d39a9f51) fix: don't modify a global map of profiles\n* [`6fe91ad9c`](https://github.com/siderolabs/talos/commit/6fe91ad9cf9f99401fc39a6ece24eed61f17b0e2) feat: provide Kubernets/Talos version compatibility for 1.8\n* [`909a5800e`](https://github.com/siderolabs/talos/commit/909a5800e4a9ada42288ae15992579e9acf6c372) fix: generate secureboot ISO .der certificate correctly\n* [`b0fdc3c8c`](https://github.com/siderolabs/talos/commit/b0fdc3c8caaf6ef756cdc4440dae45891bd96d01) fix: make static pods check output consistent\n* [`c6ad0fcce`](https://github.com/siderolabs/talos/commit/c6ad0fcceb8220f0bf96a45e131ba999cb723f79) fix: validate that workers don't get cluster CA key\n* [`3735add87`](https://github.com/siderolabs/talos/commit/3735add87cec47038a88ba641322c26cd487ac58) fix: reconnect to the logs stream in dashboard after reboot\n* [`9aa1e1b79`](https://github.com/siderolabs/talos/commit/9aa1e1b79b4a02902e0573c10e1c0bf71a2341af) fix: present all accepted CAs to the kube-apiserver\n* [`336e61174`](https://github.com/siderolabs/talos/commit/336e61174624741f697c77b98dd84ab9a7a749f4) fix: close the apid connection to other machines gracefully\n* [`ff2c427b0`](https://github.com/siderolabs/talos/commit/ff2c427b04963d69ba2eaa1084a0a078d742b9ac) fix: pre-create nftables chain to make kubelet use nftables\n* [`5622f0e45`](https://github.com/siderolabs/talos/commit/5622f0e450eda589f4b9a2af28b8517d08c2aae2) docs: change localDNS to hostDNS in release notes yaml section\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`ca662d2`](https://github.com/siderolabs/discovery-client/commit/ca662d218418eb50eb22d84560c290bef4369702) feat: export default GRPC dial options for the client\n* [`7a767fa`](https://github.com/siderolabs/discovery-client/commit/7a767fa89005209f5f39b2f5891ca7b169f52d89) chore: bump Go, deps and rekres\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`fa6663c`](https://github.com/siderolabs/extras/commit/fa6663c2abf90d82667a6c33cbc6f5edb2d1c525) feat: update Go to 1.22.2\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>12 commits</summary>\n<p>\n\n* [`28c5696`](https://github.com/siderolabs/pkgs/commit/28c5696e7c97b12765e65bd1bb758f8cb19e6adc) feat: update Linux to 6.6.29\n* [`9c8a02c`](https://github.com/siderolabs/pkgs/commit/9c8a02c234b52cf3624ebf79f7e76065cbc1eeff) feat: update containerd to 1.7.16\n* [`ca6249b`](https://github.com/siderolabs/pkgs/commit/ca6249b4b7d00b6f16e1a7264f55a4814300df63) feat: compress amd64 Linux kernel using zstd\n* [`718a7da`](https://github.com/siderolabs/pkgs/commit/718a7da83fe843cd59745078fe1a814c75bc4384) feat: enable SELinux\n* [`207481f`](https://github.com/siderolabs/pkgs/commit/207481f7b16d2b0c98053432f4ad86484bf0b1ec) feat(intel): add support for power management and ACPI options for Intel CPUs\n* [`dfa7dce`](https://github.com/siderolabs/pkgs/commit/dfa7dceb5ae50af454f527ac7c774c93d00054cf) feat: update Linux to 6.6.28\n* [`7b30b61`](https://github.com/siderolabs/pkgs/commit/7b30b61ef3ba104f3ea21469632d3d043c5fd6f6) fix: use proper EFI zBoot image\n* [`010913b`](https://github.com/siderolabs/pkgs/commit/010913b8bf2b7c7df2d16efcdf23a4efbb9913ab) feat: update Linux 6.6.26, containerd 1.7.15\n* [`da397fa`](https://github.com/siderolabs/pkgs/commit/da397fa0e55284f466af982f98cf93e7075e6298) feat: enable BFQ IO scheduler\n* [`c839801`](https://github.com/siderolabs/pkgs/commit/c83980113db4aabbda4393d7aa8e6ab734a6069b) feat: enable zboot on arm64 with zstd compression\n* [`1b28e2c`](https://github.com/siderolabs/pkgs/commit/1b28e2ce58e5702bcbbd5ed13fbd7cf6420dc12d) feat: go 1.22.2, Linux 6.6.24\n* [`05db2a8`](https://github.com/siderolabs/pkgs/commit/05db2a88e6985470f4e7dc6b21fbdd9df1e63aea) fix: revert musl to 1.2.4\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`bd405ff`](https://github.com/siderolabs/tools/commit/bd405ff5d8d511eeef17f0a6126ad6cdd3a849bb) feat: update go to 1.22.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**              v0.2.3 -> v0.3.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.5.1 -> v1.5.2\n* **github.com/aws/aws-sdk-go-v2/config**               v1.27.10 -> v1.27.11\n* **github.com/aws/aws-sdk-go-v2/service/kms**          v1.30.1 -> v1.31.0\n* **github.com/containerd/containerd**                  v1.7.14 -> v1.7.16\n* **github.com/containernetworking/cni**                v1.1.2 -> v1.2.0\n* **github.com/docker/docker**                          v26.0.0 -> v26.0.2\n* **github.com/google/go-tpm**                          ee6cbcd136f8 -> 1fb84445f623\n* **github.com/hetznercloud/hcloud-go/v2**              v2.7.0 -> v2.7.2\n* **github.com/insomniacslk/dhcp**                      c728f5dd21c8 -> f1cffa2c0c49\n* **github.com/klauspost/compress**                     v1.17.7 **_new_**\n* **github.com/miekg/dns**                              v1.1.58 -> v1.1.59\n* **github.com/prometheus/procfs**                      v0.13.0 -> v0.14.0\n* **github.com/rivo/tview**                             a22293bda944 -> e119d15762fe\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.25 -> v1.0.0-beta.26\n* **github.com/siderolabs/discovery-client**            v0.1.8 -> v0.1.9\n* **github.com/siderolabs/extras**                      v1.7.0-1-gbb76755 -> v1.8.0-alpha.0\n* **github.com/siderolabs/pkgs**                        v1.7.0-6-g29106c0 -> v1.8.0-alpha.0-10-g28c5696\n* **github.com/siderolabs/talos/pkg/machinery**         v1.7.0 -> v1.7.0-alpha.1\n* **github.com/siderolabs/tools**                       v1.7.0-1-g10b2a69 -> v1.8.0-alpha.0\n* **golang.org/x/net**                                  v0.23.0 -> v0.24.0\n* **golang.org/x/oauth2**                               v0.18.0 -> v0.19.0\n* **golang.org/x/sync**                                 v0.6.0 -> v0.7.0\n* **golang.org/x/sys**                                  v0.18.0 -> v0.19.0\n* **golang.org/x/term**                                 v0.18.0 -> v0.19.0\n* **google.golang.org/grpc**                            v1.62.1 -> v1.63.2\n\nPrevious release can be found at [v1.7.0](https://github.com/siderolabs/talos/releases/tag/v1.7.0)\n\n## [Talos 1.7.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.7.0-alpha.1) (2024-03-14)\n\nWelcome to the v1.7.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Device Selectors\n\nTalos Linux now supports `physical: true` qualifier for device selectors, it selects non-virtual network interfaces (i.e. `en0` is selected, while `bond0` is not).\n\n\n### DNS Caching\n\nTalos Linux now  provides a caching DNS resolver for host workloads (including host networking pods). It can be disabled with:\n\n```yaml\nmachine:\n   features:\n       localDNS: false\n```\n\n\n### Extension Services Config\n\nTalos now supports supplying configuration files and environment variables for extension services.\nThe extension service configuration is a separate config document. An example is shown below:\n\n```yaml\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: nut-client\nconfigFiles:\n  - content: MONITOR ${upsmonHost} 1 remote pass password\n    mountPath: /usr/local/etc/nut/upsmon.conf\nenvironment:\n  - UPS_NAME=ups\n```\n\nFor documentation, see [Extension Services Config Files](https://www.talos.dev/v1.7/reference/configuration/extensions/extensionserviceconfig/).\n\n**Note**: The use of `environmentFile` in extension service spec is now deprecated and will be removed in a future release of Talos.\nUse `ExtensionServiceConfig` instead.\n\n\n### Kubernetes Upgrade\n\nThe command `talosctl upgrade-k8s` now supports specifying custom image references for Kubernetes components via `--*-image` flags.\nThe default behavior is unchanged, and the flags are optional.\n\n\n### KubeSpan\n\nTalos Linux disables by default a KubeSpan feature to harvest additional endpoints from KubeSpan members.\nThis feature turned out to be less helpful than expected and caused unnecessary performance issues.\n\nPrevious behavior can be restored with:\n\n```yaml\nmachine:\n  network:\n    kubespan:\n        harvestExtraEndpoints: true\n```\n\n\n### NTP\n\nDefault NTP server was updated to be `time.cloudflare.com` instead of `pool.ntp.org`.\nDefault server is only used if the user does not specify any NTP servers in the configuration.\n\n\n### OpenNebula\n\nTalos Linux now supports OpenNebula platform.\n\n\n### Known Problems\n\nDRBD extension is disabled in this release due to incompatibility with the latest Linux kernel.\n\n\n### Kubernetes API Server Service Account Key\n\nTalos Linux starting from this release uses RSA key for Kubernetes API Server Service Account instead of ECDSA key to provide better compatibility with external OpenID Connect implementations.\n\n\n### SBC\n\nTalos core will drop support for SBC's and will not include the SBC binaries in the release.\n*Overlays* are being developed to support SBC's.\n\n\n### Secure Boot Image\n\nTalos Linux now provides a way to configure systemd-boot ISO 'secure-boot-enroll' option while generating a SecureBoot ISO image:\n\n```yaml\noutput:\n    kind: iso\n    isoOptions:\n        sdBootEnrollKeys: force # default is still if-safe\n    outFormat: raw\n```\n\n\n### Syslog\n\nTalos Linux now starts a basic syslog receiver listening on `/dev/log`.\nThe receiver can mostly parse both RFC3164 and RFC5424 messages and writes them as JSON formatted message.\nThe logs can be viewed via `talosctl logs syslogd`.\n\nThis is mostly implemented for extension services that log to syslog.\n\n\n### Component Updates\n\nLinux: 6.6.21\netcd: 3.5.11\nKubernetes: 1.30.0-beta.0\ncontainerd: 1.7.14\nrunc: 1.1.12\nFlannel: 0.24.1\n\nTalos is built with Go 1.22.1.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Andrey Smirnov\n* Artem Chernyshev\n* Radosław Piliszek\n* Spencer Smith\n* Anthony ARNAUD\n* Justin Garrison\n* Steve Francis\n* Anastasios Papagiannis\n* Andrei Kvapil\n* Andrian Zubovic\n* AvnarJakob\n* Cas de Reuver\n* Christian Mohn\n* Christian WALDBILLIG\n* Dmitry Sharshakov\n* Dmitry Sharshakov\n* Drew Hess\n* ExtraClock\n* Fabiano Fidêncio\n* Henno Schooljan\n* Hervé Werner\n* JJGadgets\n* Jacob McSwain\n* Jonomir\n* Kai Hanssen\n* Louis SCHNEIDER\n* Matthieu S\n* Michael Stephenson\n* Nico Berlee\n* Pip Oomen\n* Saiyam Pathak\n* Sebastiaan Gerritsen\n* Sebastian Gaiser\n* Serge Logvinov\n* Tim Jones\n* bri\n* ebcrypto\n* edwinavalos\n* fazledyn-or\n* james-dreebot\n* pardomue\n* shurkys\n* stereobutter\n\n### Changes\n<details><summary>162 commits</summary>\n<p>\n\n* [`403ad93c3`](https://github.com/siderolabs/talos/commit/403ad93c35b4cee9c012addb4667cb04e23e1c61) feat: update dependencies\n* [`7376f34e8`](https://github.com/siderolabs/talos/commit/7376f34e823f6399ed2c66ae1296a8a47a0a00ef) fix: remove maintenance config when maintenance service is shut down\n* [`952801d8b`](https://github.com/siderolabs/talos/commit/952801d8b2af27a49531b8a19f8b74400b6d4eb8) fix: handle overlay partition options\n* [`465b9a4e6`](https://github.com/siderolabs/talos/commit/465b9a4e6ca9367326cb862b501f1146989b07d4) fix: update discovery client with the fix for keepalive interval\n* [`1e9f866ac`](https://github.com/siderolabs/talos/commit/1e9f866aca14ec5ecc4d5619f42e02d44b6968d1) feat: update Kubernetes to v1.30.0-beta.0\n* [`d118a852b`](https://github.com/siderolabs/talos/commit/d118a852b995f13fc5160acb7c95d2186adaac41) feat: implement `Install` for imager overlays\n* [`cd5a5a447`](https://github.com/siderolabs/talos/commit/cd5a5a4474914cb64a23698b6656763b253a4d01) chore: migrate to go-grpc-middleware/v2\n* [`e3c2a6398`](https://github.com/siderolabs/talos/commit/e3c2a639810ad325c2b5d1b1a92aa09d52ac6997) feat: set default NTP server to time.cloudflare.com\n* [`32e087760`](https://github.com/siderolabs/talos/commit/32e08776078f9ca78ed27a382665589229c0ccb4) chore: print all available logs containers in `logs` command completions\n* [`e89d755c5`](https://github.com/siderolabs/talos/commit/e89d755c523065a257d34dff9a88df97fc1908b3) fix: etcd config validation for worker\n* [`1aa3c9182`](https://github.com/siderolabs/talos/commit/1aa3c91821fb9889e9859c880d602457791f6a14) docs: add DreeBot to ADOPTERS.md\n* [`1bb6027cc`](https://github.com/siderolabs/talos/commit/1bb6027ccd7c63ae3a012eb310d1e05027ec1f80) fix: fix nil panic on maintenance upgrade with partial config\n* [`aa70bfb9d`](https://github.com/siderolabs/talos/commit/aa70bfb9dc4fc886a6c5b771947a146ee2f58ef7) docs: add Redpill Linpro to adopters list\n* [`f02aeec92`](https://github.com/siderolabs/talos/commit/f02aeec922b6327dad6d4fee917987b147abbf2a) fix: do not fail cluster create when input dir does not contain talosconfig\n* [`1ec6683e0`](https://github.com/siderolabs/talos/commit/1ec6683e0c1d60b55a25e495c2dfc18f5bbf05b0) chore: use go-copy\n* [`3c8f51d70`](https://github.com/siderolabs/talos/commit/3c8f51d707b897fb34ed3a9f7c32b7cd3e5ee5b0) chore: move cli formatters and version modules to machinery\n* [`8152a6dd6`](https://github.com/siderolabs/talos/commit/8152a6dd6b7484e3f313b7cc9dd84fefba84d106) feat: update Go to 1.22.1\n* [`8c7953991`](https://github.com/siderolabs/talos/commit/8c79539914324eee64dbdaf1f535fc4e20da55e8) docs: update replicated-local-storage-with-openebs-jiva.md\n* [`f23bd8144`](https://github.com/siderolabs/talos/commit/f23bd81448b640b37006d6bfffa9315f84cad492) fix: syslog parser\n* [`bbed07e03`](https://github.com/siderolabs/talos/commit/bbed07e03a815869cbae5aaa2667864697fd5d65) feat: update Linux to 6.6.18\n* [`8125e754b`](https://github.com/siderolabs/talos/commit/8125e754b8a4c8db891dcd2dbd6ee3702daa2393) feat: imager overlay\n* [`0b9b4da12`](https://github.com/siderolabs/talos/commit/0b9b4da12abe6bf19d9eaaa48b42cd1a794ca8fa) feat: update Kubernetes to 1.30.0-alpha.3\n* [`3a764029e`](https://github.com/siderolabs/talos/commit/3a764029ea2d3f888c2d4d83ebffd6f97a46e3a9) docs: fix typo in word governor\n* [`d81d49000`](https://github.com/siderolabs/talos/commit/d81d4900030e93cacda34646732f24816dd3d85f) chore: update CoreDNS renovate source\n* [`b2ad5dc5f`](https://github.com/siderolabs/talos/commit/b2ad5dc5f809da9665b41c25d9ab6359a87ec942) fix: workaround a race in CNI setup (talosctl cluster create)\n* [`457507803`](https://github.com/siderolabs/talos/commit/457507803d302a31b47f5e386ce1e398861550bd) fix: provide auth when pulling images in the imager\n* [`e707175ab`](https://github.com/siderolabs/talos/commit/e707175ab5bdeb0f79ad242e2c81f36eec928342) docs: update config patch in cilium docs\n* [`f8c556a1c`](https://github.com/siderolabs/talos/commit/f8c556a1ce9aa49c1af1bfe97c3694c00fcc67bc) chore: listen for dns requests on 127.0.0.53\n* [`8872a7a21`](https://github.com/siderolabs/talos/commit/8872a7a2105034d8d6550e628355fe5f09131691) fix: ignore 'no such device' in addition to 'no such file'\n* [`1cb544353`](https://github.com/siderolabs/talos/commit/1cb5443530abc2f6333566ec8e8429b2a784f791) chore: uki der certs in iso\n* [`67ac6933d`](https://github.com/siderolabs/talos/commit/67ac6933d3c23b8ea31f01bd45d0192573e64ef3) fix: handle errors to watch apid/trustd certs\n* [`c79d69c2e`](https://github.com/siderolabs/talos/commit/c79d69c2e25ee588f45a8978117300c31871f749) fix: only set gateway if set in context (opennebula)\n* [`4575dd8e7`](https://github.com/siderolabs/talos/commit/4575dd8e741e99ab92ac63afdf48d816562f744c) chore: allow not preallocated disks for QEMU cluster\n* [`0bddfea81`](https://github.com/siderolabs/talos/commit/0bddfea818994288285f442c27a339e6d1dc6cf0) chore: add oceanbox.io to adopters\n* [`136427592`](https://github.com/siderolabs/talos/commit/1364275926df312204e006751dacc7af8e7d6726) chore: use proper `talos_version_contract` for TF tests\n* [`6bf50fdc1`](https://github.com/siderolabs/talos/commit/6bf50fdc14ad97d97fd8fcec3132f0b183c93e5a) chore: disable x/net/trace in gRPC to enable dead code elimination\n* [`815a8e9cc`](https://github.com/siderolabs/talos/commit/815a8e9cc5ad2c22acf11f223d8a64abbbf4b3cb) feat: add partial config support to `talosctl cluster create`\n* [`64e9703f8`](https://github.com/siderolabs/talos/commit/64e9703f8648f997ff2e2e0fff932f74fd52d585) chore: add tests for the Kata Containers extension\n* [`9b6291925`](https://github.com/siderolabs/talos/commit/9b62919253f16cbbfec999da26f11e8751fbb345) feat: update pkgs\n* [`66f3ffdd4`](https://github.com/siderolabs/talos/commit/66f3ffdd4ad69ec690c680868cc95697eb1fba48) fix: ensure that Talos runs in a pod (container)\n* [`9dbc33972`](https://github.com/siderolabs/talos/commit/9dbc33972a2ded3818fabd9b157604d26926e3c9) feat: add basic syslog implementation\n* [`0b7a27e6a`](https://github.com/siderolabs/talos/commit/0b7a27e6a122e7cacb5ff82a7f6cae005435ae54) feat: allow access to all resources over siderolink in maintenance mode\n* [`53721883d`](https://github.com/siderolabs/talos/commit/53721883d50bd9979edeb4f94a0f1cfcf74d4d80) feat: support AWS KMS for the SecureBoot signing\n* [`7ee999f8a`](https://github.com/siderolabs/talos/commit/7ee999f8a3906eda23b7657da4c4212886a81626) fix: disable KubeSpan endpoint harvesting by default\n* [`7b87c7fe9`](https://github.com/siderolabs/talos/commit/7b87c7fe97d01f33eb621bb631d482f975da3feb) chore: bump Go dependencies\n* [`8e9596d3c`](https://github.com/siderolabs/talos/commit/8e9596d3c65246824e921f6cb9dfcda96b5ff52c) docs: rpi talosctl install update\n* [`493bb60f8`](https://github.com/siderolabs/talos/commit/493bb60f81075181c4f71af546674871f4616067) fix: correctly handle partial configs in `DNSUpstreamController`\n* [`6deb10ae2`](https://github.com/siderolabs/talos/commit/6deb10ae25efa1d96dd7416045c99b178b04e020) chore: deprecate `environmentFile` for extensions\n* [`f8b4ee82a`](https://github.com/siderolabs/talos/commit/f8b4ee82aeba990d8e34b7c95debf30c4a626298) chore: update extensions test\n* [`1366ce14a`](https://github.com/siderolabs/talos/commit/1366ce14a8b0bf72ac884147497e354fb33ef3fa) feat: update Kubernetes to v1.30.0-alpha.2\n* [`559308ef7`](https://github.com/siderolabs/talos/commit/559308ef7e482786cc3554002bcd9fb05e0459c8) fix: use MachineStatus resource to check for boot done\n* [`15e8bca2b`](https://github.com/siderolabs/talos/commit/15e8bca2b2f839ee138faa14cb3931af173d258f) feat: support environment in `ExtensionServicesConfig`\n* [`3fe82ec46`](https://github.com/siderolabs/talos/commit/3fe82ec461995b680ecf060af75b47cd175a6342) feat: custom image settings for k8s upgrade\n* [`fa3b93370`](https://github.com/siderolabs/talos/commit/fa3b93370501009283e110b74876b18ce6bad4f9) chore: replace fmt.Errorf with errors.New where possible\n* [`d4521ee9c`](https://github.com/siderolabs/talos/commit/d4521ee9c472622fb2ef3c8570c1fa1c46332c16) feat: update kernel with sfc driver and LSM updates\n* [`2f0421b40`](https://github.com/siderolabs/talos/commit/2f0421b406ee252e9197c0b4589c0b33662bef34) fix: run xfs_repair on invalid argument error\n* [`f868fb8e8`](https://github.com/siderolabs/talos/commit/f868fb8e8f50e1acaa1743001d5b4f702bf29294) docs: update vmware tools url\n* [`fa2d34dd8`](https://github.com/siderolabs/talos/commit/fa2d34dd8875e6a09c257acfb9321c1230658b87) chore: enable v6 support on the same port\n* [`83e0b0c19`](https://github.com/siderolabs/talos/commit/83e0b0c19aaca7d413483b3a908c9dc3b4289203) chore: adjust dns sockets settings\n* [`a1ec1705b`](https://github.com/siderolabs/talos/commit/a1ec1705bc5d1f7c66dbb8549af42fc3b4778400) chore: update Go to 1.22.0\n* [`76b50fcd4`](https://github.com/siderolabs/talos/commit/76b50fcd4ae2a5d602997cc360c9dcb45e4243e8) chore: add Ænix to the Adopters list\n* [`5324d3916`](https://github.com/siderolabs/talos/commit/5324d391671dfbf918aee1bd6b095adffadecf8e) chore: bump stuff\n* [`087b50f42`](https://github.com/siderolabs/talos/commit/087b50f42932e4da883de254984bce4ad7858b90) feat: support systemd-boot ISO enroll keys option\n* [`afa71d6b0`](https://github.com/siderolabs/talos/commit/afa71d6b028c33333db51495a3db41b758f38435) chore: use \"handle-like\" resource in `DNSResolveCacheController`\n* [`013e13070`](https://github.com/siderolabs/talos/commit/013e130702758dcd8f44c84de8090d624aa5c7b9) fix: error with decoding config document with wrong apiVersion\n* [`1e77bb1c3`](https://github.com/siderolabs/talos/commit/1e77bb1c3dde3c6a54bc4174eafc09846ff59e62) chore: allow custom pkgs to build talos\n* [`3f8a85f1b`](https://github.com/siderolabs/talos/commit/3f8a85f1b390936cf7d76a146f6b76973be1e474) fix: unlock the upgrade mutex properly\n* [`61c3331b1`](https://github.com/siderolabs/talos/commit/61c3331b148901a3137de6a087d561a6db8f4dfc) docs: update indentation in vip.md\n* [`383e528df`](https://github.com/siderolabs/talos/commit/383e528df8c52ad44402c830fb3611b66c71fc7a) chore: allow uuid-based hostnames in talosctl cluster create\n* [`1e6c8c4de`](https://github.com/siderolabs/talos/commit/1e6c8c4dec1e71f0d83914c3a0d7b907b21dc3b0) feat: extensions services config\n* [`989ca3ade`](https://github.com/siderolabs/talos/commit/989ca3ade194bb0cd5c162d5d8973c133e381501) feat: add OpenNebula platform support\n* [`914f88778`](https://github.com/siderolabs/talos/commit/914f88778838abe51f24ec3a9574e91836561e9e) docs: update nocloud.md Proxmox information\n* [`a04cc8015`](https://github.com/siderolabs/talos/commit/a04cc80154ed94e970615714fd8dff9cd8cf8ca9) fix: pass TTL when generating client certificate\n* [`3fe8c12ca`](https://github.com/siderolabs/talos/commit/3fe8c12ca654790695417b3d4f6bb5517e5902b5) fix: add log line about controller runtime failing\n* [`ddbabc7e5`](https://github.com/siderolabs/talos/commit/ddbabc7e58e476c95d7bb15f325f612a3d8fc86c) fix: use a separate cgroup for each extension service\n* [`6ccdd2c09`](https://github.com/siderolabs/talos/commit/6ccdd2c09c88eb2fe8b5b382dbd94816865381d3) chore: fix markdown-lint call\n* [`4184e617a`](https://github.com/siderolabs/talos/commit/4184e617ab92b8f41c2540bf55aa4d502778dcad) chore: add test for wasmedge runtime extension\n* [`95ea3a6c6`](https://github.com/siderolabs/talos/commit/95ea3a6c65a952fef533016b7116212c21609aac) chore: bump timeout in acquire tests\n* [`c19a505d8`](https://github.com/siderolabs/talos/commit/c19a505d8cde234e12f729183e8c7272ac049159) chore: bump docker dind image\n* [`d7d4154d5`](https://github.com/siderolabs/talos/commit/d7d4154d5dc817f91771b25b358825dae803de7f) chore: remove channel blocking in qemu launch\n* [`029d7f7b9`](https://github.com/siderolabs/talos/commit/029d7f7b9b2ba610b9bd68dd00a9d8a060bfd280) release(v1.7.0-alpha.0): prepare release\n* [`2ff81c06b`](https://github.com/siderolabs/talos/commit/2ff81c06bc1123af2fa7286fff15d9de0b8a868a) feat: update runc 1.1.12, containerd 1.7.13\n* [`9d8cd4d05`](https://github.com/siderolabs/talos/commit/9d8cd4d058e73d30e4864e67377cf55390467725) chore: drop deprecated method EtcdRemoveMember\n* [`17567f19b`](https://github.com/siderolabs/talos/commit/17567f19be39eeaf0d9a9aa3cd773b73d537814a) fix: take into account the moment seen when cleaning up CRI images\n* [`aa03204b8`](https://github.com/siderolabs/talos/commit/aa03204b864d8d8ac5a7ee4986a06230863043fb) docs: document the process of building custom kernel packages\n* [`7af48bd55`](https://github.com/siderolabs/talos/commit/7af48bd5598e61357cdb9b31dd57de6479b1ce7c) feat: use RSA key for kube-apiserver service account key\n* [`a5e13c696`](https://github.com/siderolabs/talos/commit/a5e13c696d1e1cb8e894a4133791c74470687553) fix: retry blockdevice open in the installer\n* [`593afeea3`](https://github.com/siderolabs/talos/commit/593afeea38a75de01041e3126cb0ad3443f6e1a1) fix: run the interactive installer loop to report errors\n* [`87be76b87`](https://github.com/siderolabs/talos/commit/87be76b8788d179058be14c53e1092054b08c5dd) fix: be more tolerant to error handling in Mounts API\n* [`03add7503`](https://github.com/siderolabs/talos/commit/03add750309dcdeb7c2b87cd72da29a3e228e56e) docs: add section on using imager with extensions from tarball\n* [`ee0fb5eff`](https://github.com/siderolabs/talos/commit/ee0fb5effce82fec99860b5910e0fb6e5147b49b) docs: consolidate certificate management articles\n* [`9c14dea20`](https://github.com/siderolabs/talos/commit/9c14dea209bba69b471fd43eb2e8ba05de3ff549) chore: bump coredns\n* [`ebeef2852`](https://github.com/siderolabs/talos/commit/ebeef28525f71189727200115d62fe8d713d1d07) feat: implement local caching dns server\n* [`4a3691a27`](https://github.com/siderolabs/talos/commit/4a3691a2739871be5eff4b313c30d454a143fbc4) docs: fix broken links in metal-network-configuration.md\n* [`c4ed189a6`](https://github.com/siderolabs/talos/commit/c4ed189a6912238350efd5f0181a6ef45728fc63) docs: provide sane defaults for each release series in vmware script\n* [`8138d54c6`](https://github.com/siderolabs/talos/commit/8138d54c6c9bae4255216007595fa302bc418c1a) docs: clarify node taints/labels for worker nodes\n* [`b44551ccd`](https://github.com/siderolabs/talos/commit/b44551ccdb0dd0ceaffd2e484c86ce91b25fe841) feat: update Linux to 6.6.13\n* [`385707c5f`](https://github.com/siderolabs/talos/commit/385707c5f39e733c8f27532435cd14f5f2ff067d) docs: update vmware.sh\n* [`d1a79b845`](https://github.com/siderolabs/talos/commit/d1a79b845f025defafb468fb6b5e86957cfad4fc) docs: fix small typo in etcd maintenance guide\n* [`cf0603330`](https://github.com/siderolabs/talos/commit/cf0603330a5c852163642a6b3844d1dcc3892cf6) docs: copy generated JSON schema to host\n* [`f11139c22`](https://github.com/siderolabs/talos/commit/f11139c229765cf82cadc84e6fa81d860005100b) docs: document local path provisioner install\n* [`e0dfbb8fb`](https://github.com/siderolabs/talos/commit/e0dfbb8fba3c50652d0ecbae1db0b0660d0766a6) fix: allow META encoded values to be compressed\n* [`d677901b6`](https://github.com/siderolabs/talos/commit/d677901b672eec46b8b5edf57c680813b8fcf697) feat: implement device selector for 'physical'\n* [`7d1117289`](https://github.com/siderolabs/talos/commit/7d1117289658ac04707b09f64a1dc70514a9fba9) docs: add missing talosconfig flag\n* [`8a1732bcb`](https://github.com/siderolabs/talos/commit/8a1732bcb12deb4444ae87d22cc15d8b968b867d) fix: pull in `mptspi` driver\n* [`c1e45071f`](https://github.com/siderolabs/talos/commit/c1e45071f0cb0e48ee35d2f87b483fffb05c6123) refactor: use etcd configuration from the EtcdSpec resource\n* [`4e9b688d3`](https://github.com/siderolabs/talos/commit/4e9b688d3f8bc809e0b2f012d5e58c27de85d1e0) fix: use correct TTL for talosconfig in `talosctl config new`\n* [`fb5ad0555`](https://github.com/siderolabs/talos/commit/fb5ad05551e08404cb8acde01202c4ae88ddd25a) feat: update Kubernetes default to 1.29.1\n* [`fe24139f3`](https://github.com/siderolabs/talos/commit/fe24139f3c0b3f37c8266e5d6c5091950e3a647c) docs: fork docs for v1.7\n* [`1c2d10ccc`](https://github.com/siderolabs/talos/commit/1c2d10ccccb84a6d1e008af23866fa13cc14d094) chore: bump dependencies\n* [`a599e3867`](https://github.com/siderolabs/talos/commit/a599e38674af448fe5cac210f5d80826d3b08a12) chore: allow custom registry to build installer/imager\n* [`3911ddf7b`](https://github.com/siderolabs/talos/commit/3911ddf7bd630286358f1696adf9bdac207e1b9d) docs: add how-to for cert management\n* [`b0ee0bfba`](https://github.com/siderolabs/talos/commit/b0ee0bfba3f4c9172c76422a8f8f10a4046c352b) fix: strategic patch merging for audit policy\n* [`474eccdc4`](https://github.com/siderolabs/talos/commit/474eccdc4cb1d0fab3ba0b370cc388bc8c9d363a) fix: watch bufer overrun for RouteStatus\n* [`cc06b5d7a`](https://github.com/siderolabs/talos/commit/cc06b5d7a659a7f5a35e86a82ee242344c303302) fix: fix .der output in `talosctl gen secureboot`\n* [`1dbb4abf4`](https://github.com/siderolabs/talos/commit/1dbb4abf43695d1dd18d51b0386cf644aba67d73) fix: update discovery service client to v0.1.6\n* [`9782319c3`](https://github.com/siderolabs/talos/commit/9782319c31e496d998bdf9d505f32a4d8e6e937e) fix: support KubePrism settings in Kubernetes Discovery\n* [`6c5a0c281`](https://github.com/siderolabs/talos/commit/6c5a0c2811e3c0f3e1ca2a8fb871065df5bf9b46) feat: generate a single JSON schema for multidoc config\n* [`f70b47ddd`](https://github.com/siderolabs/talos/commit/f70b47dddc2599a618c68d8b403d9b37c61f2b71) fix: force KubePrism to connect using IPv4\n* [`d5321e085`](https://github.com/siderolabs/talos/commit/d5321e085eb6c877b1b5b38d69eabb839b505297) fix: update kmsg with utf-8 fix\n* [`7fa7362dd`](https://github.com/siderolabs/talos/commit/7fa7362ddc0e8a0b85cffcaebc38abd772b355e2) fix: fix nodes on dashboard footer when node names are used in `--nodes`\n* [`ba88678f1`](https://github.com/siderolabs/talos/commit/ba88678f1a42b4e9f6c9de25bdc827330cfb254c) fix: merge ports and ingress configs correctly in NetworkRuleConfig\n* [`dea9bda2d`](https://github.com/siderolabs/talos/commit/dea9bda2d00feeb29bf4b2c91c2ca24b6cd362f2) fix: disk UUID & WWID always empty in `talosctl disks`\n* [`8dc112f36`](https://github.com/siderolabs/talos/commit/8dc112f36bd77ec72e5c501755aa4f056803efd0) chore: pull in NBD modules\n* [`f6926faab`](https://github.com/siderolabs/talos/commit/f6926faab5a8b878c600d60ef9d693026277f3ee) fix: default priority for ipv6\n* [`e8758dcba`](https://github.com/siderolabs/talos/commit/e8758dcbad6d3188dfccd235dbab04c19dd1a6ed) chore: support http downloads for assets in talosctl cluster create\n* [`265f21be0`](https://github.com/siderolabs/talos/commit/265f21be09d68cc23764d690e9f9479b9d92d749) fix: replace the filemap implementation to not buffer in memory\n* [`8db3c5b3c`](https://github.com/siderolabs/talos/commit/8db3c5b3c63ad67043b876265ac4687cdcb0f0ff) fix: pick correctly base installer image layers\n* [`0a30ef784`](https://github.com/siderolabs/talos/commit/0a30ef78456e854419d0c593f9c97f40166102f3) fix: imager should support different Talos versions\n* [`d6342cda5`](https://github.com/siderolabs/talos/commit/d6342cda53027eb5d46dcb6f57fbb1cc31f920dd) docs: update latest version to v1.6.1\n* [`e6e422b92`](https://github.com/siderolabs/talos/commit/e6e422b92ade5f24c898e09affdb6de8ee671cb0) chore: bump dependencies\n* [`5a19d078a`](https://github.com/siderolabs/talos/commit/5a19d078ad3205d201b11e0d60d5e07b379aba91) fix: properly overwrite files on install\n* [`9eb6cea78`](https://github.com/siderolabs/talos/commit/9eb6cea7890854173917a096bcffd6202487d38c) docs: secureboot sd-boot menu clarification\n* [`01f0cbe61`](https://github.com/siderolabs/talos/commit/01f0cbe61c32b3ff6e9d05f2c14c83223ce043fa) feat: support iPXE direct booting in `talosctl cluster create`\n* [`3ba84701d`](https://github.com/siderolabs/talos/commit/3ba84701d9f87f533b3039395d350b311f4a484f) feat: pull in kernel modules for mlx Infiniband and VFIO\n* [`ba993e0ed`](https://github.com/siderolabs/talos/commit/ba993e0edd20f927ff8d59f418e47c6cbf8a95b3) docs: announce that SecureBoot is available\n* [`241bc9312`](https://github.com/siderolabs/talos/commit/241bc9312edcadce83a64e92db807dbca74c80cc) fix: update the way secureboot signer fetches certificate (azure)\n* [`59b62398f`](https://github.com/siderolabs/talos/commit/59b62398f6265f310108954e9a775e4b8c080679) chore: modernize machined/pkg/controllers/k8s\n* [`760f793d5`](https://github.com/siderolabs/talos/commit/760f793d55f3965792f58fa3194977aea4f90e03) fix: use correct prefix when installing SBC files\n* [`0b94550c4`](https://github.com/siderolabs/talos/commit/0b94550c42730121c3d270758286dbefa95ea61c) chore: fix the gvisor test\n* [`3a787c1d6`](https://github.com/siderolabs/talos/commit/3a787c1d67ddca5102c7d9cbdab4ef1c17a605f4) docs: update 1.6 docs with Noel's feedback\n* [`d803e40ef`](https://github.com/siderolabs/talos/commit/d803e40ef2cf1030aab522006ba7287bac8b64c4) docs: provide documentation for Talos 1.6\n* [`9a185a30f`](https://github.com/siderolabs/talos/commit/9a185a30f79a8d3481606235609c0e5a11c880cc) feat: update Kubernetes to v1.29.0\n* [`5934815d2`](https://github.com/siderolabs/talos/commit/5934815d2fe975c4d8ddb2a26ef733d29565cdb2) chore: split more kernel modules on amd64\n* [`10c59a6b9`](https://github.com/siderolabs/talos/commit/10c59a6b90310b8c58babf5beb108b59f4d74e4d) fix: leave discovery service later in the reset sequence\n* [`0c86ca1cc`](https://github.com/siderolabs/talos/commit/0c86ca1cc68e2646d63d19d96b01d3d5486dfc42) chore: enable kubespan+firewall for cilium tests\n* [`98fd722d5`](https://github.com/siderolabs/talos/commit/98fd722d5110b1422a15ede23873bcd15ab9562e) feat: provide compatibility for future Talos 1.7\n* [`131a1b167`](https://github.com/siderolabs/talos/commit/131a1b1671899666d8676b5082cef39efb8f0fa1) fix: add a KubeSpan option to disable extra endpoint harvesting\n* [`4547ad9af`](https://github.com/siderolabs/talos/commit/4547ad9afa206405032618f9d94470d00ace8684) feat: send `actor id` to the SideroLink events sink\n* [`04e774547`](https://github.com/siderolabs/talos/commit/04e774547146f0733633b296c4432f4eef847265) docs: cap max heading level\n* [`6bb1e99aa`](https://github.com/siderolabs/talos/commit/6bb1e99aa3a8132508479b4ca8606522545d8d9a) chore: optimize pcap dump\n* [`4f9d3b975`](https://github.com/siderolabs/talos/commit/4f9d3b975fa689dc9eea4e44ff453d8b68ae54ef) feat: update Kubernetes to v1.29.0-rc.2\n* [`46121c9fe`](https://github.com/siderolabs/talos/commit/46121c9fecb3603c2d2ae2de6152861ee7f19eaf) docs: rework machine config documentation generation\n* [`e128d3c82`](https://github.com/siderolabs/talos/commit/e128d3c827a406f96457322da87cbde2af233fa0) fix: talosctl cluster create not to enforce kubeprism always\n* [`320064c5a`](https://github.com/siderolabs/talos/commit/320064c5a869de6d52ba9a23394acaa5549e7aa1) feat: update Go 1.21.5, Linux 6.1.65, etcd 3.5.11\n* [`270604bea`](https://github.com/siderolabs/talos/commit/270604bead50423697d6fabffa6bbd7c7b2fbe9e) fix: support user disks via symlinks\n* [`4f195dd27`](https://github.com/siderolabs/talos/commit/4f195dd271eb38446561f8708a9623324072a0e9) chore: fix the release.toml\n* [`474fa0480`](https://github.com/siderolabs/talos/commit/474fa0480dd68d112a608548e4d0a0c4efa39e20) fix: store and execute desired action on emergency action\n* [`515ae2a18`](https://github.com/siderolabs/talos/commit/515ae2a184374e0ac72e3321104265918e45e391) docs: extend hetzner-cloud docs for arm64\n* [`eecc4dbd5`](https://github.com/siderolabs/talos/commit/eecc4dbd5198cca5b66e5c3018c407cd38b13c80) fix: trim leading spaces\\newlines in inline manifest contents\n* [`dbf274ddf`](https://github.com/siderolabs/talos/commit/dbf274ddf7b819941c88932e28d2fe362876ec68) fix: skip writing the file if the contents haven't changed\n* [`6329222bd`](https://github.com/siderolabs/talos/commit/6329222bdcfd5ab29bc46ca03bb0b1d22ada9424) fix: do not panic in `merge.Merge` if map value is nil\n</p>\n</details>\n\n### Changes since v1.7.0-alpha.0\n<details><summary>80 commits</summary>\n<p>\n\n* [`403ad93c3`](https://github.com/siderolabs/talos/commit/403ad93c35b4cee9c012addb4667cb04e23e1c61) feat: update dependencies\n* [`7376f34e8`](https://github.com/siderolabs/talos/commit/7376f34e823f6399ed2c66ae1296a8a47a0a00ef) fix: remove maintenance config when maintenance service is shut down\n* [`952801d8b`](https://github.com/siderolabs/talos/commit/952801d8b2af27a49531b8a19f8b74400b6d4eb8) fix: handle overlay partition options\n* [`465b9a4e6`](https://github.com/siderolabs/talos/commit/465b9a4e6ca9367326cb862b501f1146989b07d4) fix: update discovery client with the fix for keepalive interval\n* [`1e9f866ac`](https://github.com/siderolabs/talos/commit/1e9f866aca14ec5ecc4d5619f42e02d44b6968d1) feat: update Kubernetes to v1.30.0-beta.0\n* [`d118a852b`](https://github.com/siderolabs/talos/commit/d118a852b995f13fc5160acb7c95d2186adaac41) feat: implement `Install` for imager overlays\n* [`cd5a5a447`](https://github.com/siderolabs/talos/commit/cd5a5a4474914cb64a23698b6656763b253a4d01) chore: migrate to go-grpc-middleware/v2\n* [`e3c2a6398`](https://github.com/siderolabs/talos/commit/e3c2a639810ad325c2b5d1b1a92aa09d52ac6997) feat: set default NTP server to time.cloudflare.com\n* [`32e087760`](https://github.com/siderolabs/talos/commit/32e08776078f9ca78ed27a382665589229c0ccb4) chore: print all available logs containers in `logs` command completions\n* [`e89d755c5`](https://github.com/siderolabs/talos/commit/e89d755c523065a257d34dff9a88df97fc1908b3) fix: etcd config validation for worker\n* [`1aa3c9182`](https://github.com/siderolabs/talos/commit/1aa3c91821fb9889e9859c880d602457791f6a14) docs: add DreeBot to ADOPTERS.md\n* [`1bb6027cc`](https://github.com/siderolabs/talos/commit/1bb6027ccd7c63ae3a012eb310d1e05027ec1f80) fix: fix nil panic on maintenance upgrade with partial config\n* [`aa70bfb9d`](https://github.com/siderolabs/talos/commit/aa70bfb9dc4fc886a6c5b771947a146ee2f58ef7) docs: add Redpill Linpro to adopters list\n* [`f02aeec92`](https://github.com/siderolabs/talos/commit/f02aeec922b6327dad6d4fee917987b147abbf2a) fix: do not fail cluster create when input dir does not contain talosconfig\n* [`1ec6683e0`](https://github.com/siderolabs/talos/commit/1ec6683e0c1d60b55a25e495c2dfc18f5bbf05b0) chore: use go-copy\n* [`3c8f51d70`](https://github.com/siderolabs/talos/commit/3c8f51d707b897fb34ed3a9f7c32b7cd3e5ee5b0) chore: move cli formatters and version modules to machinery\n* [`8152a6dd6`](https://github.com/siderolabs/talos/commit/8152a6dd6b7484e3f313b7cc9dd84fefba84d106) feat: update Go to 1.22.1\n* [`8c7953991`](https://github.com/siderolabs/talos/commit/8c79539914324eee64dbdaf1f535fc4e20da55e8) docs: update replicated-local-storage-with-openebs-jiva.md\n* [`f23bd8144`](https://github.com/siderolabs/talos/commit/f23bd81448b640b37006d6bfffa9315f84cad492) fix: syslog parser\n* [`bbed07e03`](https://github.com/siderolabs/talos/commit/bbed07e03a815869cbae5aaa2667864697fd5d65) feat: update Linux to 6.6.18\n* [`8125e754b`](https://github.com/siderolabs/talos/commit/8125e754b8a4c8db891dcd2dbd6ee3702daa2393) feat: imager overlay\n* [`0b9b4da12`](https://github.com/siderolabs/talos/commit/0b9b4da12abe6bf19d9eaaa48b42cd1a794ca8fa) feat: update Kubernetes to 1.30.0-alpha.3\n* [`3a764029e`](https://github.com/siderolabs/talos/commit/3a764029ea2d3f888c2d4d83ebffd6f97a46e3a9) docs: fix typo in word governor\n* [`d81d49000`](https://github.com/siderolabs/talos/commit/d81d4900030e93cacda34646732f24816dd3d85f) chore: update CoreDNS renovate source\n* [`b2ad5dc5f`](https://github.com/siderolabs/talos/commit/b2ad5dc5f809da9665b41c25d9ab6359a87ec942) fix: workaround a race in CNI setup (talosctl cluster create)\n* [`457507803`](https://github.com/siderolabs/talos/commit/457507803d302a31b47f5e386ce1e398861550bd) fix: provide auth when pulling images in the imager\n* [`e707175ab`](https://github.com/siderolabs/talos/commit/e707175ab5bdeb0f79ad242e2c81f36eec928342) docs: update config patch in cilium docs\n* [`f8c556a1c`](https://github.com/siderolabs/talos/commit/f8c556a1ce9aa49c1af1bfe97c3694c00fcc67bc) chore: listen for dns requests on 127.0.0.53\n* [`8872a7a21`](https://github.com/siderolabs/talos/commit/8872a7a2105034d8d6550e628355fe5f09131691) fix: ignore 'no such device' in addition to 'no such file'\n* [`1cb544353`](https://github.com/siderolabs/talos/commit/1cb5443530abc2f6333566ec8e8429b2a784f791) chore: uki der certs in iso\n* [`67ac6933d`](https://github.com/siderolabs/talos/commit/67ac6933d3c23b8ea31f01bd45d0192573e64ef3) fix: handle errors to watch apid/trustd certs\n* [`c79d69c2e`](https://github.com/siderolabs/talos/commit/c79d69c2e25ee588f45a8978117300c31871f749) fix: only set gateway if set in context (opennebula)\n* [`4575dd8e7`](https://github.com/siderolabs/talos/commit/4575dd8e741e99ab92ac63afdf48d816562f744c) chore: allow not preallocated disks for QEMU cluster\n* [`0bddfea81`](https://github.com/siderolabs/talos/commit/0bddfea818994288285f442c27a339e6d1dc6cf0) chore: add oceanbox.io to adopters\n* [`136427592`](https://github.com/siderolabs/talos/commit/1364275926df312204e006751dacc7af8e7d6726) chore: use proper `talos_version_contract` for TF tests\n* [`6bf50fdc1`](https://github.com/siderolabs/talos/commit/6bf50fdc14ad97d97fd8fcec3132f0b183c93e5a) chore: disable x/net/trace in gRPC to enable dead code elimination\n* [`815a8e9cc`](https://github.com/siderolabs/talos/commit/815a8e9cc5ad2c22acf11f223d8a64abbbf4b3cb) feat: add partial config support to `talosctl cluster create`\n* [`64e9703f8`](https://github.com/siderolabs/talos/commit/64e9703f8648f997ff2e2e0fff932f74fd52d585) chore: add tests for the Kata Containers extension\n* [`9b6291925`](https://github.com/siderolabs/talos/commit/9b62919253f16cbbfec999da26f11e8751fbb345) feat: update pkgs\n* [`66f3ffdd4`](https://github.com/siderolabs/talos/commit/66f3ffdd4ad69ec690c680868cc95697eb1fba48) fix: ensure that Talos runs in a pod (container)\n* [`9dbc33972`](https://github.com/siderolabs/talos/commit/9dbc33972a2ded3818fabd9b157604d26926e3c9) feat: add basic syslog implementation\n* [`0b7a27e6a`](https://github.com/siderolabs/talos/commit/0b7a27e6a122e7cacb5ff82a7f6cae005435ae54) feat: allow access to all resources over siderolink in maintenance mode\n* [`53721883d`](https://github.com/siderolabs/talos/commit/53721883d50bd9979edeb4f94a0f1cfcf74d4d80) feat: support AWS KMS for the SecureBoot signing\n* [`7ee999f8a`](https://github.com/siderolabs/talos/commit/7ee999f8a3906eda23b7657da4c4212886a81626) fix: disable KubeSpan endpoint harvesting by default\n* [`7b87c7fe9`](https://github.com/siderolabs/talos/commit/7b87c7fe97d01f33eb621bb631d482f975da3feb) chore: bump Go dependencies\n* [`8e9596d3c`](https://github.com/siderolabs/talos/commit/8e9596d3c65246824e921f6cb9dfcda96b5ff52c) docs: rpi talosctl install update\n* [`493bb60f8`](https://github.com/siderolabs/talos/commit/493bb60f81075181c4f71af546674871f4616067) fix: correctly handle partial configs in `DNSUpstreamController`\n* [`6deb10ae2`](https://github.com/siderolabs/talos/commit/6deb10ae25efa1d96dd7416045c99b178b04e020) chore: deprecate `environmentFile` for extensions\n* [`f8b4ee82a`](https://github.com/siderolabs/talos/commit/f8b4ee82aeba990d8e34b7c95debf30c4a626298) chore: update extensions test\n* [`1366ce14a`](https://github.com/siderolabs/talos/commit/1366ce14a8b0bf72ac884147497e354fb33ef3fa) feat: update Kubernetes to v1.30.0-alpha.2\n* [`559308ef7`](https://github.com/siderolabs/talos/commit/559308ef7e482786cc3554002bcd9fb05e0459c8) fix: use MachineStatus resource to check for boot done\n* [`15e8bca2b`](https://github.com/siderolabs/talos/commit/15e8bca2b2f839ee138faa14cb3931af173d258f) feat: support environment in `ExtensionServicesConfig`\n* [`3fe82ec46`](https://github.com/siderolabs/talos/commit/3fe82ec461995b680ecf060af75b47cd175a6342) feat: custom image settings for k8s upgrade\n* [`fa3b93370`](https://github.com/siderolabs/talos/commit/fa3b93370501009283e110b74876b18ce6bad4f9) chore: replace fmt.Errorf with errors.New where possible\n* [`d4521ee9c`](https://github.com/siderolabs/talos/commit/d4521ee9c472622fb2ef3c8570c1fa1c46332c16) feat: update kernel with sfc driver and LSM updates\n* [`2f0421b40`](https://github.com/siderolabs/talos/commit/2f0421b406ee252e9197c0b4589c0b33662bef34) fix: run xfs_repair on invalid argument error\n* [`f868fb8e8`](https://github.com/siderolabs/talos/commit/f868fb8e8f50e1acaa1743001d5b4f702bf29294) docs: update vmware tools url\n* [`fa2d34dd8`](https://github.com/siderolabs/talos/commit/fa2d34dd8875e6a09c257acfb9321c1230658b87) chore: enable v6 support on the same port\n* [`83e0b0c19`](https://github.com/siderolabs/talos/commit/83e0b0c19aaca7d413483b3a908c9dc3b4289203) chore: adjust dns sockets settings\n* [`a1ec1705b`](https://github.com/siderolabs/talos/commit/a1ec1705bc5d1f7c66dbb8549af42fc3b4778400) chore: update Go to 1.22.0\n* [`76b50fcd4`](https://github.com/siderolabs/talos/commit/76b50fcd4ae2a5d602997cc360c9dcb45e4243e8) chore: add Ænix to the Adopters list\n* [`5324d3916`](https://github.com/siderolabs/talos/commit/5324d391671dfbf918aee1bd6b095adffadecf8e) chore: bump stuff\n* [`087b50f42`](https://github.com/siderolabs/talos/commit/087b50f42932e4da883de254984bce4ad7858b90) feat: support systemd-boot ISO enroll keys option\n* [`afa71d6b0`](https://github.com/siderolabs/talos/commit/afa71d6b028c33333db51495a3db41b758f38435) chore: use \"handle-like\" resource in `DNSResolveCacheController`\n* [`013e13070`](https://github.com/siderolabs/talos/commit/013e130702758dcd8f44c84de8090d624aa5c7b9) fix: error with decoding config document with wrong apiVersion\n* [`1e77bb1c3`](https://github.com/siderolabs/talos/commit/1e77bb1c3dde3c6a54bc4174eafc09846ff59e62) chore: allow custom pkgs to build talos\n* [`3f8a85f1b`](https://github.com/siderolabs/talos/commit/3f8a85f1b390936cf7d76a146f6b76973be1e474) fix: unlock the upgrade mutex properly\n* [`61c3331b1`](https://github.com/siderolabs/talos/commit/61c3331b148901a3137de6a087d561a6db8f4dfc) docs: update indentation in vip.md\n* [`383e528df`](https://github.com/siderolabs/talos/commit/383e528df8c52ad44402c830fb3611b66c71fc7a) chore: allow uuid-based hostnames in talosctl cluster create\n* [`1e6c8c4de`](https://github.com/siderolabs/talos/commit/1e6c8c4dec1e71f0d83914c3a0d7b907b21dc3b0) feat: extensions services config\n* [`989ca3ade`](https://github.com/siderolabs/talos/commit/989ca3ade194bb0cd5c162d5d8973c133e381501) feat: add OpenNebula platform support\n* [`914f88778`](https://github.com/siderolabs/talos/commit/914f88778838abe51f24ec3a9574e91836561e9e) docs: update nocloud.md Proxmox information\n* [`a04cc8015`](https://github.com/siderolabs/talos/commit/a04cc80154ed94e970615714fd8dff9cd8cf8ca9) fix: pass TTL when generating client certificate\n* [`3fe8c12ca`](https://github.com/siderolabs/talos/commit/3fe8c12ca654790695417b3d4f6bb5517e5902b5) fix: add log line about controller runtime failing\n* [`ddbabc7e5`](https://github.com/siderolabs/talos/commit/ddbabc7e58e476c95d7bb15f325f612a3d8fc86c) fix: use a separate cgroup for each extension service\n* [`6ccdd2c09`](https://github.com/siderolabs/talos/commit/6ccdd2c09c88eb2fe8b5b382dbd94816865381d3) chore: fix markdown-lint call\n* [`4184e617a`](https://github.com/siderolabs/talos/commit/4184e617ab92b8f41c2540bf55aa4d502778dcad) chore: add test for wasmedge runtime extension\n* [`95ea3a6c6`](https://github.com/siderolabs/talos/commit/95ea3a6c65a952fef533016b7116212c21609aac) chore: bump timeout in acquire tests\n* [`c19a505d8`](https://github.com/siderolabs/talos/commit/c19a505d8cde234e12f729183e8c7272ac049159) chore: bump docker dind image\n* [`d7d4154d5`](https://github.com/siderolabs/talos/commit/d7d4154d5dc817f91771b25b358825dae803de7f) chore: remove channel blocking in qemu launch\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`1c94bb3`](https://github.com/siderolabs/crypto/commit/1c94bb3967a427ba52c779a1b705f5aea466dc57) chore: bump dependencies\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`e1dc7bb`](https://github.com/siderolabs/discovery-api/commit/e1dc7bbd44f52e799fe65a6bd43a40973d611a3c) chore: rekres, update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>3 commits</summary>\n<p>\n\n* [`f4095a1`](https://github.com/siderolabs/discovery-client/commit/f4095a109d3947d1a1f470446ef40e1b386aeaf1) chore: bump discovery API to v0.1.4\n* [`fbb1cea`](https://github.com/siderolabs/discovery-client/commit/fbb1cea89609242e20f6cb35b4bfec12ade4144e) fix: keepalive interval calculation\n* [`ff8f4be`](https://github.com/siderolabs/discovery-client/commit/ff8f4be618f077f91ce1f9b8240c050719623582) fix: enable gRPC keepalives\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>4 commits</summary>\n<p>\n\n* [`47bb718`](https://github.com/siderolabs/extras/commit/47bb718838db5bda55c4c8fcf2f17424db4325a9) chore: update base pkgs\n* [`60793cd`](https://github.com/siderolabs/extras/commit/60793cdc4cc9ef1b0690a49ce0d8a79790de519b) feat: update Go to 1.22.1\n* [`c4934e1`](https://github.com/siderolabs/extras/commit/c4934e1f88ba9e16d500239831ce8412c6f93c38) feat: update Go to 1.22\n* [`8909d6f`](https://github.com/siderolabs/extras/commit/8909d6f7773542450c756ce4950c9725a05a8f65) chore: update Go to 1.21.5\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`238baf9`](https://github.com/siderolabs/gen/commit/238baf95e228d40f9f5b765b346688c704052715) chore: add typesafe `SyncMap` and bump stuff\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>21 commits</summary>\n<p>\n\n* [`cf2bd06`](https://github.com/siderolabs/go-api-signature/commit/cf2bd06af87c946d6cdd61e127528f89e6f50591) chore: bump dependencies\n* [`370cebf`](https://github.com/siderolabs/go-api-signature/commit/370cebf63d5b26a3b711ec05b0dedc283d94b136) fix: always print the login URL on key renew flow\n* [`d28609a`](https://github.com/siderolabs/go-api-signature/commit/d28609aa214f364166cf60533d03a811f9ce2af6) feat: move in the cli grpc interceptor logic, support service account in env\n* [`4602acc`](https://github.com/siderolabs/go-api-signature/commit/4602acc2f06134aed4940c6c45f3a5fbd9332a72) chore: add a dummy workflow\n* [`cfd21b6`](https://github.com/siderolabs/go-api-signature/commit/cfd21b6a51d21a344e98b7f434bf3e9198e12b42) fix: support validating signatures generated with the time in the future\n* [`74dd3dc`](https://github.com/siderolabs/go-api-signature/commit/74dd3dcc1d980837eced68e47d897b03945dd4ee) chore: bump deps\n* [`d78bedb`](https://github.com/siderolabs/go-api-signature/commit/d78bedb1a7d348832ba9db0438b1fc099aa2dd99) chore: bump deps\n* [`a034e9f`](https://github.com/siderolabs/go-api-signature/commit/a034e9ff315ba4a56115acc7ad0fb99d0dc77800) feat: replace scopes with roles\n* [`5b4f3bb`](https://github.com/siderolabs/go-api-signature/commit/5b4f3bb291b7bbec70b690f2969954255ccb8a22) chore: run rekres\n* [`9dba116`](https://github.com/siderolabs/go-api-signature/commit/9dba116c0838ecc0342a9af1e81e68e04b133623) chore: remove time.Sleep hack\n* [`e84e686`](https://github.com/siderolabs/go-api-signature/commit/e84e68658095aecead59982255b242ba8bef0fc5) chore: bump dependencies\n* [`8baaf8a`](https://github.com/siderolabs/go-api-signature/commit/8baaf8a99a28adda6dbdc0d7c38e78b290c84d96) chore: bump deps\n* [`5f27e1e`](https://github.com/siderolabs/go-api-signature/commit/5f27e1ebc06e26dea6a8102630a5b3529283eb9e) chore: add renovate bot and bump deps\n* [`69886dc`](https://github.com/siderolabs/go-api-signature/commit/69886dcc1343561add3b4b86ef160e0a1876d97f) feat: allow custom validations on PGP key\n* [`63d4da3`](https://github.com/siderolabs/go-api-signature/commit/63d4da31ae67052129c5ec795b61fb9c05a52441) fix: limit clock skew for short-lived keys\n* [`cdb9722`](https://github.com/siderolabs/go-api-signature/commit/cdb9722becf1aaeeaa1e9529dac19f3d5281f0a1) feat: add support for +-5 min clock skew\n* [`7b80a50`](https://github.com/siderolabs/go-api-signature/commit/7b80a50eea28d9273a49445cc3d39492db2e085b) refactor: use options pattern in RegisterPGPPublicKey\n* [`c647861`](https://github.com/siderolabs/go-api-signature/commit/c6478610d97a99967e903bdba1a4b7fab20e64b9) feat: add scopes to RegisterPublicKeyRequest\n* [`5d3647e`](https://github.com/siderolabs/go-api-signature/commit/5d3647e1d988e3162d0e851757fec951f6bb00c9) feat: provide more client PGP functions\n* [`2b682ec`](https://github.com/siderolabs/go-api-signature/commit/2b682ec61e83260b11cdf65d2f3723a89e4afa88) feat: initial version\n* [`a4c2943`](https://github.com/siderolabs/go-api-signature/commit/a4c294367c35d1234470d09c6151eed616a0c031) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-copy\n<details><summary>2 commits</summary>\n<p>\n\n* [`aa4ade4`](https://github.com/siderolabs/go-copy/commit/aa4ade4dfbac3695846016d4c3e49bae88da22a3) chore: add initial code\n* [`52a6d48`](https://github.com/siderolabs/go-copy/commit/52a6d485fc7dce9c3d1f00977ed61ea75c4a4e3b) chore: go-copy repo\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`0c2be80`](https://github.com/siderolabs/go-debug/commit/0c2be80d9d60034f3352a34841b615ef7bb0a62c) chore: run rekres (update to Go 1.22)\n</p>\n</details>\n\n### Changes from siderolabs/go-kmsg\n<details><summary>2 commits</summary>\n<p>\n\n* [`e358d13`](https://github.com/siderolabs/go-kmsg/commit/e358d13e5bdab79568d6ffea4b071c1530aa8e3d) fix: decode escape sequences while reading from kmsg\n* [`4297bd5`](https://github.com/siderolabs/go-kmsg/commit/4297bd599c918a5a874fb3b9f3119b394bd70899) feat: add BSD support\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>1 commit</summary>\n<p>\n\n* [`ddd4c69`](https://github.com/siderolabs/go-kubernetes/commit/ddd4c69a16f173e080f24aeabb6b472f42d140b6) feat: add support for Kubernetes 1.30\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`aab4671`](https://github.com/siderolabs/go-loadbalancer/commit/aab4671fae0d14662a8d7167829c8c6725d28b38) chore: rekres, update dependencies\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>37 commits</summary>\n<p>\n\n* [`8804a60`](https://github.com/siderolabs/pkgs/commit/8804a608bfc19b64df03b2dab404b52c9b54c85d) chore: update dependencies\n* [`a587b42`](https://github.com/siderolabs/pkgs/commit/a587b423a9a0b9173631d588947703501522d4d0) feat: enable most common amd64 watchdog drivers\n* [`3aacf03`](https://github.com/siderolabs/pkgs/commit/3aacf0345329e60c49f3116882c56fa14856dec7) feat: update releases\n* [`e5c0c79`](https://github.com/siderolabs/pkgs/commit/e5c0c79b8d62448875bb21ca5701eacccd07c7e9) feat: build NVMe target module\n* [`cb39126`](https://github.com/siderolabs/pkgs/commit/cb3912640aa8acd5571b4883f385058dd2993724) chore: re-enable zfs pkg\n* [`d9c1540`](https://github.com/siderolabs/pkgs/commit/d9c15407b5b32a7c3cec91b560f2306fd8438d14) feat: update releases\n* [`1904994`](https://github.com/siderolabs/pkgs/commit/1904994b740a5990f0b41e0ff134628ffe41650d) feat: enable VRF module\n* [`87eb013`](https://github.com/siderolabs/pkgs/commit/87eb0134fab2aa7e6a3d52d541a84847dd265329) feat: disable PCI busmastering on bridges during boot\n* [`30f18c8`](https://github.com/siderolabs/pkgs/commit/30f18c8727885ae3957791bd030b3ce35cc3ffbb) chore: remove symlinks and broken binaries\n* [`7811e5e`](https://github.com/siderolabs/pkgs/commit/7811e5eee6620431bd3d2aaf588623600b50b4a2) chore: set `PREEMPT_NONE` as recommended for servers\n* [`65006ed`](https://github.com/siderolabs/pkgs/commit/65006ed198f31e97a77ddfded52043182f2c6e92) fix: enable KFD support in kernel\n* [`510a3f9`](https://github.com/siderolabs/pkgs/commit/510a3f9a0b09617c5a6350b16076ee5720c520d8) feat: add support for Solarflare SFC9100 and SFC9200 family\n* [`4340508`](https://github.com/siderolabs/pkgs/commit/4340508d59acb9ca6da2cdad0165910f7216a990) feat: enable CONFIG_SECURITY_PATH and CONFIG_BPF_LSM\n* [`0ec4cc3`](https://github.com/siderolabs/pkgs/commit/0ec4cc32a50cf6a98dc26dcccbc1f19fea0b2692) feat: update Go to 1.22\n* [`36c08ae`](https://github.com/siderolabs/pkgs/commit/36c08ae1a6cff80d5571017aaadbb0d57faaa29b) feat: enable PSI (pressure stall information)\n* [`0853224`](https://github.com/siderolabs/pkgs/commit/08532249972b4a490ea8c4f08a34ebedffb4adda) feat: update Linux to 6.6.16\n* [`96cc841`](https://github.com/siderolabs/pkgs/commit/96cc841fda61f4b91b3a6d57a3baa6650c223957) chore: bump deps\n* [`064fd58`](https://github.com/siderolabs/pkgs/commit/064fd581bb529db7cef32b7b4adb9b1a2f8fbd98) feat: update Linux to 6.6.14, enable XDP\n* [`efbbd23`](https://github.com/siderolabs/pkgs/commit/efbbd2382e1e5cfeef8717d2212b43a9b760feaf) feat: update Linux to 6.6.13\n* [`dfb5026`](https://github.com/siderolabs/pkgs/commit/dfb5026b73f641ee3000e2460e250ec33a7e9a56) chore: switch to git ref for raspberrypi firmware\n* [`4af2d0f`](https://github.com/siderolabs/pkgs/commit/4af2d0fdfaf31c31d7f5d24fdc01d5d9d0b27e37) feat: update Linux to 6.1.74\n* [`2358efe`](https://github.com/siderolabs/pkgs/commit/2358efe6701139f074213a32d39a314729821cf1) fix: enable FUSION_SPI driver\n* [`f376a53`](https://github.com/siderolabs/pkgs/commit/f376a539352926b402e7685700defedafa4c58b0) chore: bump dependencies\n* [`583e519`](https://github.com/siderolabs/pkgs/commit/583e519f2dad762bc63bc5b2bff963c61a7e1c16) feat: add v4l usb video class (webcam) drivers\n* [`2d3ca68`](https://github.com/siderolabs/pkgs/commit/2d3ca68152d39560b8f34087cdd2e6d386f020d2) feat: enable NBD\n* [`f647edd`](https://github.com/siderolabs/pkgs/commit/f647edd497852feb4d537d191ef895d33420b5c4) feat: update Linux to 6.1.69\n* [`6af1691`](https://github.com/siderolabs/pkgs/commit/6af169101a8a5459706f45a9fe861f90ed766284) feat: enable VFIO also on amd64\n* [`d633cd6`](https://github.com/siderolabs/pkgs/commit/d633cd657081623a3681a905c4b875ed84fb4e6f) feat: enable modules for mlx infiniband\n* [`4c59641`](https://github.com/siderolabs/pkgs/commit/4c596414acd8722c97f45e0839c6d772f3e045a8) fix: zfs module build\n* [`e325097`](https://github.com/siderolabs/pkgs/commit/e32509763b2953b920c73791ca157c2c1180f0be) feat: enable nct6683 sensors as module\n* [`d6185ec`](https://github.com/siderolabs/pkgs/commit/d6185ec3ad68e10a9545ca0528f7e517c803f1a8) feat: enable IRQ remapping on amd64\n* [`814dc60`](https://github.com/siderolabs/pkgs/commit/814dc601fb79e2b973d41e82cd16872dee513161) feat: update containerd to 1.7.11\n* [`dd71790`](https://github.com/siderolabs/pkgs/commit/dd717902792d68576f7ab799a1342138fae475b2) chore: rekres to fix 'failed' build on main\n* [`a36dec4`](https://github.com/siderolabs/pkgs/commit/a36dec48a1c0de4ca178222ee88251701a881bdb) feat: split more device drivers into modules\n* [`97270a2`](https://github.com/siderolabs/pkgs/commit/97270a2c26a9c61c2fff5fb104ff0a2bc9fbdd5d) feat: update Linux to 6.1.67\n* [`8a73907`](https://github.com/siderolabs/pkgs/commit/8a73907886c003c33cbc03a2a81f0a473fa93c00) feat: update Go to 1.21.5\n* [`8f0ffb9`](https://github.com/siderolabs/pkgs/commit/8f0ffb92f88b1a795cfc627abd3ca74cb910cb78) feat: update zfs to v2.2.2\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>12 commits</summary>\n<p>\n\n* [`cb5fd56`](https://github.com/siderolabs/tools/commit/cb5fd5627c87cc49a730d6b30fcdb61d6dcb7caf) chore: update xz to 5.6.1\n* [`14bf457`](https://github.com/siderolabs/tools/commit/14bf457275686e64dad8c596e869b4e78e7c9494) fix: use musl 1.2.4 in tools, revert kmod back to 32\n* [`6c1f73d`](https://github.com/siderolabs/tools/commit/6c1f73d4f51fae028a3aa3c97884b80801826a40) fix: revert kmod to version 31\n* [`59fd552`](https://github.com/siderolabs/tools/commit/59fd5520aadd761943982ce7e52b005f8b60bc8b) feat: update releases\n* [`eff5d16`](https://github.com/siderolabs/tools/commit/eff5d16b3af4726b4757ce3a2c78372b4afaf7eb) feat: update Go to 1.22.1\n* [`b6b4d9e`](https://github.com/siderolabs/tools/commit/b6b4d9eb8aba4648eb39001d25c3dd711b2d8fce) feat: update Go to 1.22\n* [`f4b41d1`](https://github.com/siderolabs/tools/commit/f4b41d189844957a71814ee3e98983553f7ba0ad) fix: rust toolchain\n* [`8cc79e6`](https://github.com/siderolabs/tools/commit/8cc79e68499624d4dde77d5c7d12aab957aaa22a) feat: update dependencies\n* [`c7076eb`](https://github.com/siderolabs/tools/commit/c7076eb9f2246f1d6cca431968d2fcce6bd1f951) chore: bump dependencies\n* [`a80a2aa`](https://github.com/siderolabs/tools/commit/a80a2aa0307d90f07c8a239459191a3f68cdd5d3) feat: update Go to 1.21.6\n* [`b677a2b`](https://github.com/siderolabs/tools/commit/b677a2b99fd658710c34f7472df350787346ea35) feat: add rust build stage\n* [`1659d82`](https://github.com/siderolabs/tools/commit/1659d82e78511522e2820efccb892235d6d7b279) feat: update Go to 1.21.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.9.0 -> v1.10.0\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.4.0 -> v1.5.1\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.0.0 -> v1.1.0\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.0.1 -> v1.1.0\n* **github.com/alexflint/go-filemutex**                                       v1.3.0 **_new_**\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.25.6 -> v1.27.7\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.14.5 -> v1.15.3\n* **github.com/aws/aws-sdk-go-v2/service/kms**                                v1.29.2 **_new_**\n* **github.com/aws/smithy-go**                                                v1.17.0 -> v1.20.1\n* **github.com/beevik/ntp**                                                   v1.3.0 -> v1.3.1\n* **github.com/containerd/cgroups/v3**                                        v3.0.2 -> v3.0.3\n* **github.com/containerd/containerd**                                        v1.7.9 -> v1.7.14\n* **github.com/containernetworking/plugins**                                  v1.3.0 -> v1.4.1\n* **github.com/coredns/coredns**                                              v1.11.1 **_new_**\n* **github.com/cosi-project/runtime**                                         v0.3.19 -> v0.4.0-alpha.9\n* **github.com/docker/docker**                                                v24.0.7 -> v25.0.4\n* **github.com/docker/go-connections**                                        v0.4.0 -> v0.5.0\n* **github.com/foxboron/go-uefi**                                             18b9ba9cd4c3 -> 48be911532c2\n* **github.com/gdamore/tcell/v2**                                             v2.6.0 -> v2.7.4\n* **github.com/google/go-containerregistry**                                  v0.16.1 -> v0.19.0\n* **github.com/google/go-tpm**                                                v0.9.0 -> ee6cbcd136f8\n* **github.com/google/nftables**                                              v0.1.0 -> v0.2.0\n* **github.com/google/uuid**                                                  v1.4.0 -> v1.6.0\n* **github.com/grpc-ecosystem/go-grpc-middleware/v2**                         v2.1.0 **_new_**\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.4.0 -> v2.6.0\n* **github.com/insomniacslk/dhcp**                                            b0416c0f187a -> c728f5dd21c8\n* **github.com/jeromer/syslogparser**                                         v1.1.0 **_new_**\n* **github.com/jsimonetti/rtnetlink**                                         v1.4.0 -> v1.4.1\n* **github.com/miekg/dns**                                                    v1.1.58 **_new_**\n* **github.com/opencontainers/image-spec**                                    v1.1.0-rc4 -> v1.1.0\n* **github.com/opencontainers/runtime-spec**                                  v1.1.0-rc.1 -> v1.2.0\n* **github.com/packethost/packngo**                                           v0.30.0 -> v0.31.0\n* **github.com/pmorjan/kmod**                                                 v1.1.0 -> v1.1.1\n* **github.com/prometheus/procfs**                                            v0.12.0 -> v0.13.0\n* **github.com/rivo/tview**                                                   33a1d271f2b6 -> e804876934a1\n* **github.com/scaleway/scaleway-sdk-go**                                     v1.0.0-beta.21 -> v1.0.0-beta.25\n* **github.com/siderolabs/crypto**                                            v0.4.1 -> v0.4.2\n* **github.com/siderolabs/discovery-api**                                     v0.1.3 -> v0.1.4\n* **github.com/siderolabs/discovery-client**                                  v0.1.5 -> v0.1.8\n* **github.com/siderolabs/extras**                                            v1.6.0-1-g113887a -> v1.7.0-alpha.0-3-g47bb718\n* **github.com/siderolabs/gen**                                               v0.4.7 -> v0.4.8\n* **github.com/siderolabs/go-api-signature**                                  v0.3.2 **_new_**\n* **github.com/siderolabs/go-copy**                                           v0.1.0 **_new_**\n* **github.com/siderolabs/go-debug**                                          v0.2.3 -> v0.3.0\n* **github.com/siderolabs/go-kmsg**                                           v0.1.3 -> v0.1.4\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.8 -> v0.2.9\n* **github.com/siderolabs/go-loadbalancer**                                   v0.3.2 -> v0.3.3\n* **github.com/siderolabs/pkgs**                                              v1.6.0-5-g3ae2450 -> v1.7.0-alpha.0-35-g8804a60\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.6.0 -> v1.7.0-alpha.0\n* **github.com/siderolabs/tools**                                             v1.6.0-1-g336d248 -> v1.7.0-alpha.0-11-gcb5fd56\n* **github.com/stretchr/testify**                                             v1.8.4 -> v1.9.0\n* **github.com/u-root/u-root**                                                v0.11.0 -> v0.14.0\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/client/v3**                                               v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.11 -> v3.5.12\n* **go.uber.org/zap**                                                         v1.26.0 -> v1.27.0\n* **go4.org/netipx**                                                          6213f710f925 -> fdeea329fbba\n* **golang.org/x/net**                                                        v0.19.0 -> v0.22.0\n* **golang.org/x/oauth2**                                                     v0.15.0 -> v0.18.0\n* **golang.org/x/sync**                                                       v0.5.0 -> v0.6.0\n* **golang.org/x/sys**                                                        v0.15.0 -> v0.18.0\n* **golang.org/x/term**                                                       v0.15.0 -> v0.18.0\n* **google.golang.org/grpc**                                                  v1.59.0 -> v1.62.1\n* **google.golang.org/protobuf**                                              v1.31.0 -> v1.33.0\n* **k8s.io/api**                                                              v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/apimachinery**                                                     v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/apiserver**                                                        v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/client-go**                                                        v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/component-base**                                                   v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/cri-api**                                                          v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/klog/v2**                                                          v2.110.1 -> v2.120.1\n* **k8s.io/kube-scheduler**                                                   v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/kubectl**                                                          v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/kubelet**                                                          v0.29.0 -> v0.30.0-beta.0\n* **k8s.io/pod-security-admission**                                           v0.30.0-beta.0 **_new_**\n\nPrevious release can be found at [v1.6.0](https://github.com/siderolabs/talos/releases/tag/v1.6.0)\n\n## [Talos 1.7.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.7.0-alpha.0) (2024-02-01)\n\nWelcome to the v1.7.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Device Selectors\n\nTalos Linux now supports `physical: true` qualifier for device selectors, it selects non-virtual network interfaces (i.e. `en0` is selected, while `bond0` is not).\n\n\n### DNS Caching\n\nTalos Linux now  provides a caching DNS resolver for host workloads (including host networking pods). It can be disabled with:\n\n```yaml\nmachine:\n   features:\n       localDNS: false\n```\n\n\n### Known Problems\n\nZFS and DRBD extensions are disabled in this release due to incompatibility with the latest Linux kernel.\n\n\n### Kubernetes API Server Service Account Key\n\nTalos Linux starting from this release uses RSA key for Kubernetes API Server Service Account instead of ECDSA key to provide better compatibility with external OpenID Connect implementations.\n\n\n### Component Updates\n\nLinux: 6.6.14\netcd: 3.5.11\nKubernetes: 1.29.1\ncontainerd: 1.7.13\nrunc: 1.1.12\nFlannel: 0.24.1\n\nTalos is built with Go 1.21.6.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Noel Georgi\n* Andrey Smirnov\n* Radosław Piliszek\n* Artem Chernyshev\n* Spencer Smith\n* Steve Francis\n* Anthony ARNAUD\n* Cas de Reuver\n* Christian Mohn\n* Drew Hess\n* ExtraClock\n* Hervé Werner\n* JJGadgets\n* Jacob McSwain\n* Jonomir\n* Sebastian Gaiser\n* Serge Logvinov\n* Tim Jones\n* edwinavalos\n* stereobutter\n\n### Changes\n<details><summary>81 commits</summary>\n<p>\n\n* [`2ff81c06b`](https://github.com/siderolabs/talos/commit/2ff81c06bc1123af2fa7286fff15d9de0b8a868a) feat: update runc 1.1.12, containerd 1.7.13\n* [`9d8cd4d05`](https://github.com/siderolabs/talos/commit/9d8cd4d058e73d30e4864e67377cf55390467725) chore: drop deprecated method EtcdRemoveMember\n* [`17567f19b`](https://github.com/siderolabs/talos/commit/17567f19be39eeaf0d9a9aa3cd773b73d537814a) fix: take into account the moment seen when cleaning up CRI images\n* [`aa03204b8`](https://github.com/siderolabs/talos/commit/aa03204b864d8d8ac5a7ee4986a06230863043fb) docs: document the process of building custom kernel packages\n* [`7af48bd55`](https://github.com/siderolabs/talos/commit/7af48bd5598e61357cdb9b31dd57de6479b1ce7c) feat: use RSA key for kube-apiserver service account key\n* [`a5e13c696`](https://github.com/siderolabs/talos/commit/a5e13c696d1e1cb8e894a4133791c74470687553) fix: retry blockdevice open in the installer\n* [`593afeea3`](https://github.com/siderolabs/talos/commit/593afeea38a75de01041e3126cb0ad3443f6e1a1) fix: run the interactive installer loop to report errors\n* [`87be76b87`](https://github.com/siderolabs/talos/commit/87be76b8788d179058be14c53e1092054b08c5dd) fix: be more tolerant to error handling in Mounts API\n* [`03add7503`](https://github.com/siderolabs/talos/commit/03add750309dcdeb7c2b87cd72da29a3e228e56e) docs: add section on using imager with extensions from tarball\n* [`ee0fb5eff`](https://github.com/siderolabs/talos/commit/ee0fb5effce82fec99860b5910e0fb6e5147b49b) docs: consolidate certificate management articles\n* [`9c14dea20`](https://github.com/siderolabs/talos/commit/9c14dea209bba69b471fd43eb2e8ba05de3ff549) chore: bump coredns\n* [`ebeef2852`](https://github.com/siderolabs/talos/commit/ebeef28525f71189727200115d62fe8d713d1d07) feat: implement local caching dns server\n* [`4a3691a27`](https://github.com/siderolabs/talos/commit/4a3691a2739871be5eff4b313c30d454a143fbc4) docs: fix broken links in metal-network-configuration.md\n* [`c4ed189a6`](https://github.com/siderolabs/talos/commit/c4ed189a6912238350efd5f0181a6ef45728fc63) docs: provide sane defaults for each release series in vmware script\n* [`8138d54c6`](https://github.com/siderolabs/talos/commit/8138d54c6c9bae4255216007595fa302bc418c1a) docs: clarify node taints/labels for worker nodes\n* [`b44551ccd`](https://github.com/siderolabs/talos/commit/b44551ccdb0dd0ceaffd2e484c86ce91b25fe841) feat: update Linux to 6.6.13\n* [`385707c5f`](https://github.com/siderolabs/talos/commit/385707c5f39e733c8f27532435cd14f5f2ff067d) docs: update vmware.sh\n* [`d1a79b845`](https://github.com/siderolabs/talos/commit/d1a79b845f025defafb468fb6b5e86957cfad4fc) docs: fix small typo in etcd maintenance guide\n* [`cf0603330`](https://github.com/siderolabs/talos/commit/cf0603330a5c852163642a6b3844d1dcc3892cf6) docs: copy generated JSON schema to host\n* [`f11139c22`](https://github.com/siderolabs/talos/commit/f11139c229765cf82cadc84e6fa81d860005100b) docs: document local path provisioner install\n* [`e0dfbb8fb`](https://github.com/siderolabs/talos/commit/e0dfbb8fba3c50652d0ecbae1db0b0660d0766a6) fix: allow META encoded values to be compressed\n* [`d677901b6`](https://github.com/siderolabs/talos/commit/d677901b672eec46b8b5edf57c680813b8fcf697) feat: implement device selector for 'physical'\n* [`7d1117289`](https://github.com/siderolabs/talos/commit/7d1117289658ac04707b09f64a1dc70514a9fba9) docs: add missing talosconfig flag\n* [`8a1732bcb`](https://github.com/siderolabs/talos/commit/8a1732bcb12deb4444ae87d22cc15d8b968b867d) fix: pull in `mptspi` driver\n* [`c1e45071f`](https://github.com/siderolabs/talos/commit/c1e45071f0cb0e48ee35d2f87b483fffb05c6123) refactor: use etcd configuration from the EtcdSpec resource\n* [`4e9b688d3`](https://github.com/siderolabs/talos/commit/4e9b688d3f8bc809e0b2f012d5e58c27de85d1e0) fix: use correct TTL for talosconfig in `talosctl config new`\n* [`fb5ad0555`](https://github.com/siderolabs/talos/commit/fb5ad05551e08404cb8acde01202c4ae88ddd25a) feat: update Kubernetes default to 1.29.1\n* [`fe24139f3`](https://github.com/siderolabs/talos/commit/fe24139f3c0b3f37c8266e5d6c5091950e3a647c) docs: fork docs for v1.7\n* [`1c2d10ccc`](https://github.com/siderolabs/talos/commit/1c2d10ccccb84a6d1e008af23866fa13cc14d094) chore: bump dependencies\n* [`a599e3867`](https://github.com/siderolabs/talos/commit/a599e38674af448fe5cac210f5d80826d3b08a12) chore: allow custom registry to build installer/imager\n* [`3911ddf7b`](https://github.com/siderolabs/talos/commit/3911ddf7bd630286358f1696adf9bdac207e1b9d) docs: add how-to for cert management\n* [`b0ee0bfba`](https://github.com/siderolabs/talos/commit/b0ee0bfba3f4c9172c76422a8f8f10a4046c352b) fix: strategic patch merging for audit policy\n* [`474eccdc4`](https://github.com/siderolabs/talos/commit/474eccdc4cb1d0fab3ba0b370cc388bc8c9d363a) fix: watch bufer overrun for RouteStatus\n* [`cc06b5d7a`](https://github.com/siderolabs/talos/commit/cc06b5d7a659a7f5a35e86a82ee242344c303302) fix: fix .der output in `talosctl gen secureboot`\n* [`1dbb4abf4`](https://github.com/siderolabs/talos/commit/1dbb4abf43695d1dd18d51b0386cf644aba67d73) fix: update discovery service client to v0.1.6\n* [`9782319c3`](https://github.com/siderolabs/talos/commit/9782319c31e496d998bdf9d505f32a4d8e6e937e) fix: support KubePrism settings in Kubernetes Discovery\n* [`6c5a0c281`](https://github.com/siderolabs/talos/commit/6c5a0c2811e3c0f3e1ca2a8fb871065df5bf9b46) feat: generate a single JSON schema for multidoc config\n* [`f70b47ddd`](https://github.com/siderolabs/talos/commit/f70b47dddc2599a618c68d8b403d9b37c61f2b71) fix: force KubePrism to connect using IPv4\n* [`d5321e085`](https://github.com/siderolabs/talos/commit/d5321e085eb6c877b1b5b38d69eabb839b505297) fix: update kmsg with utf-8 fix\n* [`7fa7362dd`](https://github.com/siderolabs/talos/commit/7fa7362ddc0e8a0b85cffcaebc38abd772b355e2) fix: fix nodes on dashboard footer when node names are used in `--nodes`\n* [`ba88678f1`](https://github.com/siderolabs/talos/commit/ba88678f1a42b4e9f6c9de25bdc827330cfb254c) fix: merge ports and ingress configs correctly in NetworkRuleConfig\n* [`dea9bda2d`](https://github.com/siderolabs/talos/commit/dea9bda2d00feeb29bf4b2c91c2ca24b6cd362f2) fix: disk UUID & WWID always empty in `talosctl disks`\n* [`8dc112f36`](https://github.com/siderolabs/talos/commit/8dc112f36bd77ec72e5c501755aa4f056803efd0) chore: pull in NBD modules\n* [`f6926faab`](https://github.com/siderolabs/talos/commit/f6926faab5a8b878c600d60ef9d693026277f3ee) fix: default priority for ipv6\n* [`e8758dcba`](https://github.com/siderolabs/talos/commit/e8758dcbad6d3188dfccd235dbab04c19dd1a6ed) chore: support http downloads for assets in talosctl cluster create\n* [`265f21be0`](https://github.com/siderolabs/talos/commit/265f21be09d68cc23764d690e9f9479b9d92d749) fix: replace the filemap implementation to not buffer in memory\n* [`8db3c5b3c`](https://github.com/siderolabs/talos/commit/8db3c5b3c63ad67043b876265ac4687cdcb0f0ff) fix: pick correctly base installer image layers\n* [`0a30ef784`](https://github.com/siderolabs/talos/commit/0a30ef78456e854419d0c593f9c97f40166102f3) fix: imager should support different Talos versions\n* [`d6342cda5`](https://github.com/siderolabs/talos/commit/d6342cda53027eb5d46dcb6f57fbb1cc31f920dd) docs: update latest version to v1.6.1\n* [`e6e422b92`](https://github.com/siderolabs/talos/commit/e6e422b92ade5f24c898e09affdb6de8ee671cb0) chore: bump dependencies\n* [`5a19d078a`](https://github.com/siderolabs/talos/commit/5a19d078ad3205d201b11e0d60d5e07b379aba91) fix: properly overwrite files on install\n* [`9eb6cea78`](https://github.com/siderolabs/talos/commit/9eb6cea7890854173917a096bcffd6202487d38c) docs: secureboot sd-boot menu clarification\n* [`01f0cbe61`](https://github.com/siderolabs/talos/commit/01f0cbe61c32b3ff6e9d05f2c14c83223ce043fa) feat: support iPXE direct booting in `talosctl cluster create`\n* [`3ba84701d`](https://github.com/siderolabs/talos/commit/3ba84701d9f87f533b3039395d350b311f4a484f) feat: pull in kernel modules for mlx Infiniband and VFIO\n* [`ba993e0ed`](https://github.com/siderolabs/talos/commit/ba993e0edd20f927ff8d59f418e47c6cbf8a95b3) docs: announce that SecureBoot is available\n* [`241bc9312`](https://github.com/siderolabs/talos/commit/241bc9312edcadce83a64e92db807dbca74c80cc) fix: update the way secureboot signer fetches certificate (azure)\n* [`59b62398f`](https://github.com/siderolabs/talos/commit/59b62398f6265f310108954e9a775e4b8c080679) chore: modernize machined/pkg/controllers/k8s\n* [`760f793d5`](https://github.com/siderolabs/talos/commit/760f793d55f3965792f58fa3194977aea4f90e03) fix: use correct prefix when installing SBC files\n* [`0b94550c4`](https://github.com/siderolabs/talos/commit/0b94550c42730121c3d270758286dbefa95ea61c) chore: fix the gvisor test\n* [`3a787c1d6`](https://github.com/siderolabs/talos/commit/3a787c1d67ddca5102c7d9cbdab4ef1c17a605f4) docs: update 1.6 docs with Noel's feedback\n* [`d803e40ef`](https://github.com/siderolabs/talos/commit/d803e40ef2cf1030aab522006ba7287bac8b64c4) docs: provide documentation for Talos 1.6\n* [`9a185a30f`](https://github.com/siderolabs/talos/commit/9a185a30f79a8d3481606235609c0e5a11c880cc) feat: update Kubernetes to v1.29.0\n* [`5934815d2`](https://github.com/siderolabs/talos/commit/5934815d2fe975c4d8ddb2a26ef733d29565cdb2) chore: split more kernel modules on amd64\n* [`10c59a6b9`](https://github.com/siderolabs/talos/commit/10c59a6b90310b8c58babf5beb108b59f4d74e4d) fix: leave discovery service later in the reset sequence\n* [`0c86ca1cc`](https://github.com/siderolabs/talos/commit/0c86ca1cc68e2646d63d19d96b01d3d5486dfc42) chore: enable kubespan+firewall for cilium tests\n* [`98fd722d5`](https://github.com/siderolabs/talos/commit/98fd722d5110b1422a15ede23873bcd15ab9562e) feat: provide compatibility for future Talos 1.7\n* [`131a1b167`](https://github.com/siderolabs/talos/commit/131a1b1671899666d8676b5082cef39efb8f0fa1) fix: add a KubeSpan option to disable extra endpoint harvesting\n* [`4547ad9af`](https://github.com/siderolabs/talos/commit/4547ad9afa206405032618f9d94470d00ace8684) feat: send `actor id` to the SideroLink events sink\n* [`04e774547`](https://github.com/siderolabs/talos/commit/04e774547146f0733633b296c4432f4eef847265) docs: cap max heading level\n* [`6bb1e99aa`](https://github.com/siderolabs/talos/commit/6bb1e99aa3a8132508479b4ca8606522545d8d9a) chore: optimize pcap dump\n* [`4f9d3b975`](https://github.com/siderolabs/talos/commit/4f9d3b975fa689dc9eea4e44ff453d8b68ae54ef) feat: update Kubernetes to v1.29.0-rc.2\n* [`46121c9fe`](https://github.com/siderolabs/talos/commit/46121c9fecb3603c2d2ae2de6152861ee7f19eaf) docs: rework machine config documentation generation\n* [`e128d3c82`](https://github.com/siderolabs/talos/commit/e128d3c827a406f96457322da87cbde2af233fa0) fix: talosctl cluster create not to enforce kubeprism always\n* [`320064c5a`](https://github.com/siderolabs/talos/commit/320064c5a869de6d52ba9a23394acaa5549e7aa1) feat: update Go 1.21.5, Linux 6.1.65, etcd 3.5.11\n* [`270604bea`](https://github.com/siderolabs/talos/commit/270604bead50423697d6fabffa6bbd7c7b2fbe9e) fix: support user disks via symlinks\n* [`4f195dd27`](https://github.com/siderolabs/talos/commit/4f195dd271eb38446561f8708a9623324072a0e9) chore: fix the release.toml\n* [`474fa0480`](https://github.com/siderolabs/talos/commit/474fa0480dd68d112a608548e4d0a0c4efa39e20) fix: store and execute desired action on emergency action\n* [`515ae2a18`](https://github.com/siderolabs/talos/commit/515ae2a184374e0ac72e3321104265918e45e391) docs: extend hetzner-cloud docs for arm64\n* [`eecc4dbd5`](https://github.com/siderolabs/talos/commit/eecc4dbd5198cca5b66e5c3018c407cd38b13c80) fix: trim leading spaces\\newlines in inline manifest contents\n* [`dbf274ddf`](https://github.com/siderolabs/talos/commit/dbf274ddf7b819941c88932e28d2fe362876ec68) fix: skip writing the file if the contents haven't changed\n* [`6329222bd`](https://github.com/siderolabs/talos/commit/6329222bdcfd5ab29bc46ca03bb0b1d22ada9424) fix: do not panic in `merge.Merge` if map value is nil\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`ff8f4be`](https://github.com/siderolabs/discovery-client/commit/ff8f4be618f077f91ce1f9b8240c050719623582) fix: enable gRPC keepalives\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`8909d6f`](https://github.com/siderolabs/extras/commit/8909d6f7773542450c756ce4950c9725a05a8f65) chore: update Go to 1.21.5\n</p>\n</details>\n\n### Changes from siderolabs/go-api-signature\n<details><summary>20 commits</summary>\n<p>\n\n* [`370cebf`](https://github.com/siderolabs/go-api-signature/commit/370cebf63d5b26a3b711ec05b0dedc283d94b136) fix: always print the login URL on key renew flow\n* [`d28609a`](https://github.com/siderolabs/go-api-signature/commit/d28609aa214f364166cf60533d03a811f9ce2af6) feat: move in the cli grpc interceptor logic, support service account in env\n* [`4602acc`](https://github.com/siderolabs/go-api-signature/commit/4602acc2f06134aed4940c6c45f3a5fbd9332a72) chore: add a dummy workflow\n* [`cfd21b6`](https://github.com/siderolabs/go-api-signature/commit/cfd21b6a51d21a344e98b7f434bf3e9198e12b42) fix: support validating signatures generated with the time in the future\n* [`74dd3dc`](https://github.com/siderolabs/go-api-signature/commit/74dd3dcc1d980837eced68e47d897b03945dd4ee) chore: bump deps\n* [`d78bedb`](https://github.com/siderolabs/go-api-signature/commit/d78bedb1a7d348832ba9db0438b1fc099aa2dd99) chore: bump deps\n* [`a034e9f`](https://github.com/siderolabs/go-api-signature/commit/a034e9ff315ba4a56115acc7ad0fb99d0dc77800) feat: replace scopes with roles\n* [`5b4f3bb`](https://github.com/siderolabs/go-api-signature/commit/5b4f3bb291b7bbec70b690f2969954255ccb8a22) chore: run rekres\n* [`9dba116`](https://github.com/siderolabs/go-api-signature/commit/9dba116c0838ecc0342a9af1e81e68e04b133623) chore: remove time.Sleep hack\n* [`e84e686`](https://github.com/siderolabs/go-api-signature/commit/e84e68658095aecead59982255b242ba8bef0fc5) chore: bump dependencies\n* [`8baaf8a`](https://github.com/siderolabs/go-api-signature/commit/8baaf8a99a28adda6dbdc0d7c38e78b290c84d96) chore: bump deps\n* [`5f27e1e`](https://github.com/siderolabs/go-api-signature/commit/5f27e1ebc06e26dea6a8102630a5b3529283eb9e) chore: add renovate bot and bump deps\n* [`69886dc`](https://github.com/siderolabs/go-api-signature/commit/69886dcc1343561add3b4b86ef160e0a1876d97f) feat: allow custom validations on PGP key\n* [`63d4da3`](https://github.com/siderolabs/go-api-signature/commit/63d4da31ae67052129c5ec795b61fb9c05a52441) fix: limit clock skew for short-lived keys\n* [`cdb9722`](https://github.com/siderolabs/go-api-signature/commit/cdb9722becf1aaeeaa1e9529dac19f3d5281f0a1) feat: add support for +-5 min clock skew\n* [`7b80a50`](https://github.com/siderolabs/go-api-signature/commit/7b80a50eea28d9273a49445cc3d39492db2e085b) refactor: use options pattern in RegisterPGPPublicKey\n* [`c647861`](https://github.com/siderolabs/go-api-signature/commit/c6478610d97a99967e903bdba1a4b7fab20e64b9) feat: add scopes to RegisterPublicKeyRequest\n* [`5d3647e`](https://github.com/siderolabs/go-api-signature/commit/5d3647e1d988e3162d0e851757fec951f6bb00c9) feat: provide more client PGP functions\n* [`2b682ec`](https://github.com/siderolabs/go-api-signature/commit/2b682ec61e83260b11cdf65d2f3723a89e4afa88) feat: initial version\n* [`a4c2943`](https://github.com/siderolabs/go-api-signature/commit/a4c294367c35d1234470d09c6151eed616a0c031) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-kmsg\n<details><summary>2 commits</summary>\n<p>\n\n* [`e358d13`](https://github.com/siderolabs/go-kmsg/commit/e358d13e5bdab79568d6ffea4b071c1530aa8e3d) fix: decode escape sequences while reading from kmsg\n* [`4297bd5`](https://github.com/siderolabs/go-kmsg/commit/4297bd599c918a5a874fb3b9f3119b394bd70899) feat: add BSD support\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>21 commits</summary>\n<p>\n\n* [`96cc841`](https://github.com/siderolabs/pkgs/commit/96cc841fda61f4b91b3a6d57a3baa6650c223957) chore: bump deps\n* [`064fd58`](https://github.com/siderolabs/pkgs/commit/064fd581bb529db7cef32b7b4adb9b1a2f8fbd98) feat: update Linux to 6.6.14, enable XDP\n* [`efbbd23`](https://github.com/siderolabs/pkgs/commit/efbbd2382e1e5cfeef8717d2212b43a9b760feaf) feat: update Linux to 6.6.13\n* [`dfb5026`](https://github.com/siderolabs/pkgs/commit/dfb5026b73f641ee3000e2460e250ec33a7e9a56) chore: switch to git ref for raspberrypi firmware\n* [`4af2d0f`](https://github.com/siderolabs/pkgs/commit/4af2d0fdfaf31c31d7f5d24fdc01d5d9d0b27e37) feat: update Linux to 6.1.74\n* [`2358efe`](https://github.com/siderolabs/pkgs/commit/2358efe6701139f074213a32d39a314729821cf1) fix: enable FUSION_SPI driver\n* [`f376a53`](https://github.com/siderolabs/pkgs/commit/f376a539352926b402e7685700defedafa4c58b0) chore: bump dependencies\n* [`583e519`](https://github.com/siderolabs/pkgs/commit/583e519f2dad762bc63bc5b2bff963c61a7e1c16) feat: add v4l usb video class (webcam) drivers\n* [`2d3ca68`](https://github.com/siderolabs/pkgs/commit/2d3ca68152d39560b8f34087cdd2e6d386f020d2) feat: enable NBD\n* [`f647edd`](https://github.com/siderolabs/pkgs/commit/f647edd497852feb4d537d191ef895d33420b5c4) feat: update Linux to 6.1.69\n* [`6af1691`](https://github.com/siderolabs/pkgs/commit/6af169101a8a5459706f45a9fe861f90ed766284) feat: enable VFIO also on amd64\n* [`d633cd6`](https://github.com/siderolabs/pkgs/commit/d633cd657081623a3681a905c4b875ed84fb4e6f) feat: enable modules for mlx infiniband\n* [`4c59641`](https://github.com/siderolabs/pkgs/commit/4c596414acd8722c97f45e0839c6d772f3e045a8) fix: zfs module build\n* [`e325097`](https://github.com/siderolabs/pkgs/commit/e32509763b2953b920c73791ca157c2c1180f0be) feat: enable nct6683 sensors as module\n* [`d6185ec`](https://github.com/siderolabs/pkgs/commit/d6185ec3ad68e10a9545ca0528f7e517c803f1a8) feat: enable IRQ remapping on amd64\n* [`814dc60`](https://github.com/siderolabs/pkgs/commit/814dc601fb79e2b973d41e82cd16872dee513161) feat: update containerd to 1.7.11\n* [`dd71790`](https://github.com/siderolabs/pkgs/commit/dd717902792d68576f7ab799a1342138fae475b2) chore: rekres to fix 'failed' build on main\n* [`a36dec4`](https://github.com/siderolabs/pkgs/commit/a36dec48a1c0de4ca178222ee88251701a881bdb) feat: split more device drivers into modules\n* [`97270a2`](https://github.com/siderolabs/pkgs/commit/97270a2c26a9c61c2fff5fb104ff0a2bc9fbdd5d) feat: update Linux to 6.1.67\n* [`8a73907`](https://github.com/siderolabs/pkgs/commit/8a73907886c003c33cbc03a2a81f0a473fa93c00) feat: update Go to 1.21.5\n* [`8f0ffb9`](https://github.com/siderolabs/pkgs/commit/8f0ffb92f88b1a795cfc627abd3ca74cb910cb78) feat: update zfs to v2.2.2\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`f4b41d1`](https://github.com/siderolabs/tools/commit/f4b41d189844957a71814ee3e98983553f7ba0ad) fix: rust toolchain\n* [`8cc79e6`](https://github.com/siderolabs/tools/commit/8cc79e68499624d4dde77d5c7d12aab957aaa22a) feat: update dependencies\n* [`c7076eb`](https://github.com/siderolabs/tools/commit/c7076eb9f2246f1d6cca431968d2fcce6bd1f951) chore: bump dependencies\n* [`a80a2aa`](https://github.com/siderolabs/tools/commit/a80a2aa0307d90f07c8a239459191a3f68cdd5d3) feat: update Go to 1.21.6\n* [`b677a2b`](https://github.com/siderolabs/tools/commit/b677a2b99fd658710c34f7472df350787346ea35) feat: add rust build stage\n* [`1659d82`](https://github.com/siderolabs/tools/commit/1659d82e78511522e2820efccb892235d6d7b279) feat: update Go to 1.21.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**      v1.9.0 -> v1.9.1\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**  v1.4.0 -> v1.5.1\n* **github.com/aws/aws-sdk-go-v2/config**               v1.25.6 -> v1.26.6\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**     v1.14.5 -> v1.14.11\n* **github.com/aws/smithy-go**                          v1.17.0 -> v1.19.0\n* **github.com/beevik/ntp**                             v1.3.0 -> v1.3.1\n* **github.com/containerd/cgroups/v3**                  v3.0.2 -> v3.0.3\n* **github.com/containerd/containerd**                  v1.7.9 -> v1.7.13\n* **github.com/containernetworking/plugins**            v1.3.0 -> v1.4.0\n* **github.com/coredns/coredns**                        v1.11.1 **_new_**\n* **github.com/cosi-project/runtime**                   v0.3.19 -> v0.3.20\n* **github.com/docker/docker**                          v24.0.7 -> v25.0.2\n* **github.com/docker/go-connections**                  v0.4.0 -> v0.5.0\n* **github.com/emicklei/dot**                           v1.6.0 -> v1.6.1\n* **github.com/foxboron/go-uefi**                       18b9ba9cd4c3 -> 48be911532c2\n* **github.com/gdamore/tcell/v2**                       v2.6.0 -> v2.7.0\n* **github.com/google/go-containerregistry**            v0.16.1 -> v0.19.0\n* **github.com/google/go-tpm**                          v0.9.0 -> ee6cbcd136f8\n* **github.com/google/uuid**                            v1.4.0 -> v1.6.0\n* **github.com/hetznercloud/hcloud-go/v2**              v2.4.0 -> v2.6.0\n* **github.com/insomniacslk/dhcp**                      b0416c0f187a -> 15c9b8791914\n* **github.com/jsimonetti/rtnetlink**                   v1.4.0 -> v1.4.1\n* **github.com/miekg/dns**                              v1.1.58 **_new_**\n* **github.com/opencontainers/image-spec**              v1.1.0-rc4 -> v1.1.0-rc6\n* **github.com/opencontainers/runtime-spec**            v1.1.0-rc.1 -> v1.1.0\n* **github.com/packethost/packngo**                     v0.30.0 -> v0.31.0\n* **github.com/pin/tftp**                               2f79be2dba4e **_new_**\n* **github.com/pmorjan/kmod**                           v1.1.0 -> v1.1.1\n* **github.com/rivo/tview**                             33a1d271f2b6 -> 8526c9fe1b54\n* **github.com/scaleway/scaleway-sdk-go**               v1.0.0-beta.21 -> v1.0.0-beta.22\n* **github.com/siderolabs/discovery-client**            v0.1.5 -> v0.1.6\n* **github.com/siderolabs/extras**                      v1.6.0-1-g113887a -> v1.7.0-alpha.0\n* **github.com/siderolabs/go-api-signature**            v0.3.1 **_new_**\n* **github.com/siderolabs/go-kmsg**                     v0.1.3 -> v0.1.4\n* **github.com/siderolabs/pkgs**                        v1.6.0-5-g3ae2450 -> v1.7.0-alpha.0-19-g96cc841\n* **github.com/siderolabs/talos/pkg/machinery**         v1.6.0 -> v1.6.0-alpha.2\n* **github.com/siderolabs/tools**                       v1.6.0-1-g336d248 -> v1.7.0-alpha.0-5-gf4b41d1\n* **github.com/u-root/u-root**                          v0.11.0 -> v0.12.0\n* **go.etcd.io/etcd/api/v3**                            v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/client/pkg/v3**                     v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/client/v3**                         v3.5.11 -> v3.5.12\n* **go.etcd.io/etcd/etcdutl/v3**                        v3.5.11 -> v3.5.12\n* **go4.org/netipx**                                    6213f710f925 -> fdeea329fbba\n* **golang.org/x/net**                                  v0.19.0 -> v0.20.0\n* **golang.org/x/oauth2**                               v0.15.0 -> v0.16.0\n* **golang.org/x/sync**                                 v0.5.0 -> v0.6.0\n* **golang.org/x/sys**                                  v0.15.0 -> v0.16.0\n* **golang.org/x/term**                                 v0.15.0 -> v0.16.0\n* **google.golang.org/grpc**                            v1.59.0 -> v1.61.0\n* **google.golang.org/protobuf**                        v1.31.0 -> v1.32.0\n* **k8s.io/api**                                        v0.29.0 -> v0.29.1\n* **k8s.io/apimachinery**                               v0.29.0 -> v0.29.1\n* **k8s.io/apiserver**                                  v0.29.0 -> v0.29.1\n* **k8s.io/client-go**                                  v0.29.0 -> v0.29.1\n* **k8s.io/component-base**                             v0.29.0 -> v0.29.1\n* **k8s.io/cri-api**                                    v0.29.0 -> v0.29.1\n* **k8s.io/klog/v2**                                    v2.110.1 -> v2.120.1\n* **k8s.io/kube-scheduler**                             v0.29.0 -> v0.29.1\n* **k8s.io/kubectl**                                    v0.29.0 -> v0.29.1\n* **k8s.io/kubelet**                                    v0.29.0 -> v0.29.1\n\nPrevious release can be found at [v1.6.0](https://github.com/siderolabs/talos/releases/tag/v1.6.0)\n\n## [Talos 1.6.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.6.0-alpha.2) (2023-11-21)\n\nWelcome to the v1.6.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Kubelet Credential Provider Configuration\n\nTalos now supports specifying the kubelet credential provider configuration in the Talos configuration file.\nIt can be set under `machine.kubelet.credentialProviderConfig` and kubelet will be automatically configured to with the correct flags.\nThe credential binaries are expected to be present under `/usr/local/lib/kubelet/credentialproviders`.\nTalos System Extensions can be used to install the credential binaries.\n\n\n### Network Device Selectors\n\nPreviously, [network device selectors](https://www.talos.dev/v1.6/talos-guides/network/device-selector/) only matched the first link, now the configuration is applied to all matching links.\n\n\n### Linux Firmware\n\nStarting with Talos 1.6, there is no Linux firmware included in the initramfs.\nCustomers who need Linux firmware can pull them as extension during install time using the image factory service.\nIf the initial boot requires firmware, a custom iso can be built with the firmware included using the image factory service.\nThis also ensures that the linux-firmware is not tied to a specific Talos version.\n\n\n### Kube-Scheduler Configuration\n\nTalos now supports specifying the kube-scheduler configuration in the Talos configuration file.\nIt can be set under `cluster.scheduler.config` and kube-scheduler will be automatically configured to with the correct flags.\n\n\n### KubePrism\n\n[KubePrism](https://www.talos.dev/v1.6/kubernetes-guides/configuration/kubeprism/) is enabled by default on port 7445.\n\n\n### Sysctl\n\nTalos now handles sysctl/sysfs key names in line with sysctl.conf(5):\n\n* if the first separator is '/', no conversion is done\n* if the first separator is '.', dots and slashes are remapped\n\nExample (both sysctls are equivalent):\n\n```yaml\nmachine:\n  sysctls:\n    net/ipv6/conf/eth0.100/disable_ipv6: \"1\"\n    net.ipv6.conf.eth0/100.disable_ipv6: \"1\"\n```\n\n\n### talosctl CLI\n\nThe command `images` deprecated in Talos 1.5 was removed, please use `talosctl images default` instead.\n\n\n### Component Updates\n\nLinux: 6.1.63\ncontainerd: 1.7.9\nCoreDNS: 1.11.1\nKubernetes: 1.29.0-alpha.3\nFlannel: 0.22.3\netcd: 3.5.10\nrunc: 1.1.10\n\nTalos is built with Go 1.21.4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Andrey Smirnov\n* Oscar Utbult\n* Serge Logvinov\n* Utku Ozdemir\n* Artem Chernyshev\n* Nico Berlee\n* Radosław Piliszek\n* Steve Francis\n* Thomas Way\n* ndbrew\n* Andrei Kvapil\n* Christian Rolland\n* Drew Hess\n* Enno Boland\n* Florian Berchtold\n* Henry Sachs\n* Jacob McSwain\n* Jacob McSwain\n* Jared Davenport\n* Mans Matulewicz\n* Nebula\n* Sascha Desch\n* Spencer Smith\n* Thomas Lemarchand\n* Tim Jones\n* Zachary Milonas\n* budimanjojo\n* guoguangwu\n* mikucat0309\n\n### Changes\n<details><summary>177 commits</summary>\n<p>\n\n* [`514e514ba`](https://github.com/siderolabs/talos/commit/514e514ba650419a4caad4ee87c52a367ce1e323) feat: update Linux 6.1.63, containerd 1.7.9\n* [`aca8b5e17`](https://github.com/siderolabs/talos/commit/aca8b5e179962c8e1dc27ca8de527e981f763004) fix: ignore kernel command line in container mode\n* [`020a0eb63`](https://github.com/siderolabs/talos/commit/020a0eb63ea39d25faa8eba8568584243d814457) docs: fix table formatting for bootstraprequest\n* [`0eb245e04`](https://github.com/siderolabs/talos/commit/0eb245e04374cd21a369d298b73e8bc6db11d153) docs: fix talosctl pcap example indentation\n* [`de6caf534`](https://github.com/siderolabs/talos/commit/de6caf5348f815dddbd4a595d40d4c4ad71282bc) docs: fix table formatting for machineservice api\n* [`27d208c26`](https://github.com/siderolabs/talos/commit/27d208c26bd1fe5a37b127cd83cab76b5671758a) feat: implement OAuth2 device flow for machine config\n* [`5c8fa2a80`](https://github.com/siderolabs/talos/commit/5c8fa2a80382b6ea83d81c434b2e28a9901fdcad) chore: start containerd early in boot\n* [`95a252cfc`](https://github.com/siderolabs/talos/commit/95a252cfc91eeeeb48ac3b3e3cd6ad7ba14ab1eb) docs: fix link in what is new page\n* [`0d3c3ed71`](https://github.com/siderolabs/talos/commit/0d3c3ed716670c80d33351d912620e5b91f6c7e3) feat: support kube scheduler config\n* [`06941b7e5`](https://github.com/siderolabs/talos/commit/06941b7e5ca4f937c1996828e5a543967902656d) fix: allow rootfs propagation configuration for extension services\n* [`57dc796f3`](https://github.com/siderolabs/talos/commit/57dc796f381e87f398cfed3ac7cd87ff51454b75) docs: update lastRelease to v1.5.5 in _index.md\n* [`21d944a64`](https://github.com/siderolabs/talos/commit/21d944a643d8eec104d703cc8995e9ac80d2417b) docs: add timezone information\n* [`4f1ad16c7`](https://github.com/siderolabs/talos/commit/4f1ad16c764e643f7bf71ed8ca46e840875011ec) feat: support kubelet credentialprovider config\n* [`71a3bf0e3`](https://github.com/siderolabs/talos/commit/71a3bf0e3e42117e7283b41116419d7d2f28d82c) fix: allow extra kernel args for secureboot installer\n* [`f38eaaab8`](https://github.com/siderolabs/talos/commit/f38eaaab87f77f33b0317d4405c84575023ee0da) feat: rework secureboot and PCR signing key\n* [`6eade3d5e`](https://github.com/siderolabs/talos/commit/6eade3d5ef5c5356d0bfc0e3d52263a39d2e9f1a) chore: add ability to rewrite uuids and set unique tokens for Talos\n* [`e9c7ac17a`](https://github.com/siderolabs/talos/commit/e9c7ac17a9b707950b249e08e11ed7ddac64e8ae) fix: set max msg recv size when proxying\n* [`e22ab440d`](https://github.com/siderolabs/talos/commit/e22ab440d7794a9c46edf1357124571057b6b19d) feat: update Linux 6.1.61, containerd 1.7.8, runc 1.1.10\n* [`8245361f9`](https://github.com/siderolabs/talos/commit/8245361f9cfb66d68bc54330a47814eb730eb839) feat: show first 32 bytes of response body on download error\n* [`75d3987c0`](https://github.com/siderolabs/talos/commit/75d3987c05390d3c0a7cf4de855895f1d10c8a84) chore: drop sha1 from genereated pcr json\n* [`6f32d2990`](https://github.com/siderolabs/talos/commit/6f32d2990f438a9e8134d7e94558a54b3912854e) feat: add `.der` output `talosctl gen secureboot pcr`\n* [`87c40da6c`](https://github.com/siderolabs/talos/commit/87c40da6cc5d9ae62d20984ba5d3762da734a49e) fix: proper logging in machined on startup\n* [`a54da5f64`](https://github.com/siderolabs/talos/commit/a54da5f641886d723465e0a8cfa95b15bc2e96aa) fix: image build for nanopi_4s\n* [`6f3cd0593`](https://github.com/siderolabs/talos/commit/6f3cd05935a2faaf14d16c2e643f54e6f9134c0f) refactor: update packet capture to use 'afpacket' interface\n* [`813442dd7`](https://github.com/siderolabs/talos/commit/813442dd7a08b2781829ef190b110aa38c725932) fix: don't validate machine.install if installed\n* [`dff60069c`](https://github.com/siderolabs/talos/commit/dff60069c0230ecf531c5593724211fd75f26d7c) feat: update Kubernetes to 1.29.0-alpha.3\n* [`c97db5dfe`](https://github.com/siderolabs/talos/commit/c97db5dfe174032f012bdd525a3479ebea200c93) chore: bump Go dependencies\n* [`807a9950a`](https://github.com/siderolabs/talos/commit/807a9950ac5cb542e41d65af0f9f80f1c73550a3) fix: use custom Talos/kernel version when generating UKI\n* [`eb94468a6`](https://github.com/siderolabs/talos/commit/eb94468a659b4518b317398f92346b62e6adefe4) docs: add documentation for Image Factory\n* [`2e78513e1`](https://github.com/siderolabs/talos/commit/2e78513e16b2eb0d83a4a7e107c470058d30837d) refactor: drop the dependency link platform -> network ctrl\n* [`6dc776b8a`](https://github.com/siderolabs/talos/commit/6dc776b8aaa2d9382737d41a90023e8e4ea1a601) fix: when writing to META in the installer/imager, use fixed name\n* [`3703041e9`](https://github.com/siderolabs/talos/commit/3703041e989c83c1ad7496851c6687f729cb207f) chore: remove uneeded code\n* [`cbe6e7622`](https://github.com/siderolabs/talos/commit/cbe6e7622d0180ca53ab0ce92d38e4704d466d1a) fix: generate images for SBCs using imager\n* [`5dff164f1`](https://github.com/siderolabs/talos/commit/5dff164f1c8fc08b66f0ea509db36561eaef464c) fix: fix error output of cli action tracker\n* [`ef5056122`](https://github.com/siderolabs/talos/commit/ef5056122b38a168dd8ee429a6bc4cad0860177d) feat: update etcd to 3.5.10\n* [`45ae80873`](https://github.com/siderolabs/talos/commit/45ae80873f1a7a3cb5643f7d94108a96f36cad32) chore: bump go-api-signature dependency to v0.3.1\n* [`ffa5e05cb`](https://github.com/siderolabs/talos/commit/ffa5e05cb9c8028897ce5e08183be52965004726) fix: make Talos work on Rockpi 4c boards again\n* [`8eba4c599`](https://github.com/siderolabs/talos/commit/8eba4c5999ca4a43220704ff2297706fd9e9d27b) feat: generate secrets bundle from the machine config\n* [`c7de745f6`](https://github.com/siderolabs/talos/commit/c7de745f61490ee8192bbab34fbb8a4bad21de9f) chore: drop deprecated code\n* [`cc0c3ab69`](https://github.com/siderolabs/talos/commit/cc0c3ab69c7807236955eb53ccac4cc70fcca32a) docs: update rpi_generic.md\n* [`a009f5c60`](https://github.com/siderolabs/talos/commit/a009f5c60c9506dd5064106bbef38fe36813db64) fix: accept sysctl paths with dots\n* [`4919f6ee2`](https://github.com/siderolabs/talos/commit/4919f6ee22b5f6cf53f801e13072f6d64027c215) feat: add GOMEMLIMIT to shipped manifests with memory limits\n* [`73ee576ea`](https://github.com/siderolabs/talos/commit/73ee576ea711a9f36a8d35ceba4716276a2e5f70) chore: update sonobuouy library, drop the fork\n* [`c23bc2f4a`](https://github.com/siderolabs/talos/commit/c23bc2f4a77c3e9b2e88f99d05266fcd8fb4a51b) chore: support OCI layout as a source for profile input\n* [`154bbd70f`](https://github.com/siderolabs/talos/commit/154bbd70f7bdfd464ad6136c7e7e057d2402c0f6) docs: fix talos version in guide for docker\n* [`11d1f6163`](https://github.com/siderolabs/talos/commit/11d1f616350885bfe5ab3e9d3310ee2b0eee4201) release(v1.6.0-alpha.1): prepare release\n* [`9dfae8467`](https://github.com/siderolabs/talos/commit/9dfae8467d5a0bf7d3fd753b980bc7801bf3e5f8) chore: update dependencies\n* [`38ce3c827`](https://github.com/siderolabs/talos/commit/38ce3c827a06c44e0399cd0a3d8a396687001b20) feat: nocloud prefer mac address\n* [`401e89411`](https://github.com/siderolabs/talos/commit/401e8941124056f9cd9649a555aafebb063bb94d) feat: customize image size\n* [`865f08f86`](https://github.com/siderolabs/talos/commit/865f08f867fa5784c5a25bfeb929dbe25a6eb763) docs: kubeadm migration guide improvements\n* [`c3e418200`](https://github.com/siderolabs/talos/commit/c3e418200032be376aa30f6db133f2dcbf8b67c2) refactor: use COSI runtime with new controller runtime DB\n* [`c1ee24465`](https://github.com/siderolabs/talos/commit/c1ee24465aaac079f84c58ac86f74e89dfeb01ed) feat: update Kubernetes to v1.29.0-alpha.2\n* [`0ff7350ab`](https://github.com/siderolabs/talos/commit/0ff7350abe94c046b8c7759ca6a1c64d9b80e497) fix: oracle integration fixes\n* [`675bada45`](https://github.com/siderolabs/talos/commit/675bada45473a91f5a99134193acf48da2789545) test: add config generation stability tests\n* [`f9639fb53`](https://github.com/siderolabs/talos/commit/f9639fb531797f4db16696e81371d9043d7041a9) test: fix 'talosctl gen' tests\n* [`6142d87a0`](https://github.com/siderolabs/talos/commit/6142d87a0f3e0a5e4babb97667a22e2497c67b4c) feat: hostname configuration improvements on the NoCloud platform\n* [`7bb205ebe`](https://github.com/siderolabs/talos/commit/7bb205ebe2efdbd691dd81b49fc6acbd3a289fa5) fix: don't use runtime-specs Mount struct in machine config\n* [`d1b27926c`](https://github.com/siderolabs/talos/commit/d1b27926c24109a2044cd07b3bb2d1e2824857c2) feat: update Go to 1.21.3\n* [`b87092ab6`](https://github.com/siderolabs/talos/commit/b87092ab69e8a4928727ad71f3ce01502f76c966) fix: handle secure boot state policy pcr digest error\n* [`498aeb8c3`](https://github.com/siderolabs/talos/commit/498aeb8c32a590b20140541a1a334fdf2da84105) docs: fix incorrect image suffix\n* [`c14a5d4f7`](https://github.com/siderolabs/talos/commit/c14a5d4f79a3af0d075288cc9fb74f15fa34faf1) feat: support service account auth in cli\n* [`336aee0fd`](https://github.com/siderolabs/talos/commit/336aee0fdb1302443f627f848bed8081bdb0d9b0) fix: use tpm2 hash algorithm constants and allow non-SHA-256 PCRs\n* [`69d8054c9`](https://github.com/siderolabs/talos/commit/69d8054c9ec194b801f8d3185519c4b26a6a6b07) chore: drop UpdateEndpointSuite\n* [`ef7be16c8`](https://github.com/siderolabs/talos/commit/ef7be16c801176fc983299229841a98f935e18ed) fix: clear the encryption config in META when STATE is reset\n* [`5fc60d2ca`](https://github.com/siderolabs/talos/commit/5fc60d2caa75a6e886e3a70c22b63a708f68ad43) feat: add Solarflare SFC9000 support\n* [`9b5cfdd0b`](https://github.com/siderolabs/talos/commit/9b5cfdd0bc252a9594f6d7112ebf7401e41d1546) chore: add tests for iscsi\n* [`b897764f8`](https://github.com/siderolabs/talos/commit/b897764f8e90fa237cedecba50a63f5f2f852543) docs: update proxmox.md\n* [`159f45bde`](https://github.com/siderolabs/talos/commit/159f45bde65097efe311674b253284cf7d167b26) docs: fix typos in CLI calls to endpoints\n* [`0bd1bdd74`](https://github.com/siderolabs/talos/commit/0bd1bdd744f68dc42ac64678972fede992a7189e) chore: allow insecure access to installer base image (imager)\n* [`10ed13067`](https://github.com/siderolabs/talos/commit/10ed13067958f3afa0819a3d8557933b218a391b) fix: the node IP for kubelet shouldn't change if nothing matches\n* [`e7575ecaa`](https://github.com/siderolabs/talos/commit/e7575ecaaea9625be471c9db1965e256959f0730) feat: support n-5 latest Kubernetes versions\n* [`e71508ec1`](https://github.com/siderolabs/talos/commit/e71508ec104b42d1882b26d6bab22fc43ca0d8bb) chore: update dependencies\n* [`6d7fa4668`](https://github.com/siderolabs/talos/commit/6d7fa466807ffcd3b6a5c84ae34a90c728fcb8be) docs: add metal network configuration guide\n* [`2b548ad0d`](https://github.com/siderolabs/talos/commit/2b548ad0d9fa7b1f1e057c160464494b1828eb77) feat: update containerd to 1.7.x\n* [`62dcfe81e`](https://github.com/siderolabs/talos/commit/62dcfe81eb17ad2927dff43a855f0169fd84271e) fix: update kubernetes library to support 1.29 upgrades\n* [`52caf0763`](https://github.com/siderolabs/talos/commit/52caf0763393bc171b95464fefd3af1a3efd5f1c) feat: update Kubernetes to 1.29.0-alpha.1\n* [`390137447`](https://github.com/siderolabs/talos/commit/390137447fbf2a8e87cb7bb313a202dbd5a31045) feat: enable KubePrism by default\n* [`1beb5e86e`](https://github.com/siderolabs/talos/commit/1beb5e86e621595af0d93798c9e158bb48e2b363) docs: add KubePrism video\n* [`a52d3cda3`](https://github.com/siderolabs/talos/commit/a52d3cda3b2eecc8aabf64b99a3ded0dad7e84c3) chore: update gen and COSI runtime\n* [`29b201d61`](https://github.com/siderolabs/talos/commit/29b201d61902017be355853a8f11c903fe9fefae) feat: enable common h/w sensors\n* [`9c2ba7c6f`](https://github.com/siderolabs/talos/commit/9c2ba7c6fa1162cb946e91a7e7d4dfecd62027a5) chore: add tests for chelsio drivers\n* [`5ca4d58dc`](https://github.com/siderolabs/talos/commit/5ca4d58dc9a2477db44d34c9f30ed21b0c3d2131) fix: generate of modules.dep when on the machine\n* [`5efcccb6b`](https://github.com/siderolabs/talos/commit/5efcccb6b14f59a9c065273493e0b82af1a85226) chore: bump kernel to 6.1.54\n* [`29c767a02`](https://github.com/siderolabs/talos/commit/29c767a028e346c635e99e491cdab150c756f77c) docs: add control plane nodes as users of apid also for control plane nodes\n* [`4874cfb95`](https://github.com/siderolabs/talos/commit/4874cfb95a8148dc7feec00de8c299d4ac022c53) chore: fix typo\n* [`96f2a62ea`](https://github.com/siderolabs/talos/commit/96f2a62eafb5c3cee254d6e15f6f8c3e91359b9a) test: update upgrade tests versions\n* [`f3a370acb`](https://github.com/siderolabs/talos/commit/f3a370acb21c83fd1393da30bad2a37ca6a09b2c) feat: update Flannel to 0.22.3\n* [`efdee6965`](https://github.com/siderolabs/talos/commit/efdee69658cfea44681954dac2552cfeee5bb30e) feat: update Kubernetes to 1.28.2\n* [`e3b494058`](https://github.com/siderolabs/talos/commit/e3b49405884186dc1db0d9592f95965a0904691d) fix: build CPU ucode correctly for early loader\n* [`c5bd0ac5c`](https://github.com/siderolabs/talos/commit/c5bd0ac5cf033a9e3084a5fe98f42ee784926636) refactor: reimplement the depmod extension rebuilder\n* [`0b883f52a`](https://github.com/siderolabs/talos/commit/0b883f52a5a81a36a0e777f6f87e2d1d176e2294) docs: add notes about stable addressing\n* [`3ef670a9e`](https://github.com/siderolabs/talos/commit/3ef670a9e8e7efff5af9872e1e13d8521ce2dca6) chore: pull in dm modules\n* [`8f4a36b0d`](https://github.com/siderolabs/talos/commit/8f4a36b0d4c35f5841a270b7b5cd7da7c798165f) docs: update aws to add command to allow KubeSpan wireguard port\n* [`a7edd0523`](https://github.com/siderolabs/talos/commit/a7edd0523f9e5a7fccc6c382b453000beab4a8ff) fix: set default route priority for hcloud platform\n* [`87c1b3ddd`](https://github.com/siderolabs/talos/commit/87c1b3ddd83f038c62d34e94ad7e34a98236130b) fix: calculate UKI ISO size dynamically\n* [`9698e4547`](https://github.com/siderolabs/talos/commit/9698e45479cb293bbefe1651b94344bd7b0a4e52) fix: handle correctly change of listen address for maintenance service\n* [`a096f05a5`](https://github.com/siderolabs/talos/commit/a096f05a56003c317ffade2c87aa8d327592e3b8) chore: update gRPC library and enable shared write buffers\n* [`9e78fecca`](https://github.com/siderolabs/talos/commit/9e78feccaecda53778acba43fb9ad177051a009c) chore: improve image signing process\n* [`f00567e20`](https://github.com/siderolabs/talos/commit/f00567e20f239e781975636b12e31501ee39bbfa) chore: add PKG_KERNEL arg to customize used kernel\n* [`2960f93ba`](https://github.com/siderolabs/talos/commit/2960f93baa55f6ea2cb3690cbc652df9aee17af8) feat: add readonly information to the disks API response\n* [`735bf9ed0`](https://github.com/siderolabs/talos/commit/735bf9ed08a5d8dd302ef3e1f61317ff9169549c) feat: bring in Google vNIC driver\n* [`3f5232075`](https://github.com/siderolabs/talos/commit/3f523207522aa69452516408f914cc792abb78b9) feat: upgrade-k8s without comments\n* [`e44875106`](https://github.com/siderolabs/talos/commit/e44875106e28e50b15c38fa8b889f51083325800) docs: update deploying-cilium.md\n* [`7046cae43`](https://github.com/siderolabs/talos/commit/7046cae43dd4e8a4ea7d80934b02cc7c8b84e53a) chore: update gopacket to reduce init memory allocs\n* [`da73b563d`](https://github.com/siderolabs/talos/commit/da73b563dd0a7d77f4490d10cc506b5570c2bf11) chore: update Go to 1.21.1\n* [`5e11f08a6`](https://github.com/siderolabs/talos/commit/5e11f08a639bd791fa7fafe3df35349959b4eb24) fix: trim file path in the container image\n* [`3d2dad4e6`](https://github.com/siderolabs/talos/commit/3d2dad4e69ba458fb406a7d7441d9e3f2fe8fde2) chore: show securtiystate on dashboard\n* [`b48510874`](https://github.com/siderolabs/talos/commit/b4851087404e6fcad52da588fd4827046011b271) chore: e2e-aws cleanup\n* [`1eebbce35`](https://github.com/siderolabs/talos/commit/1eebbce357311aaea739abe55c9e0de947791f39) chore: add output flag for talosctl config info\n* [`3fbed806c`](https://github.com/siderolabs/talos/commit/3fbed806c4e5a4167f0a357eb20486bb406103a8) chore: add tests for util-linux extensions\n* [`7c514a1a6`](https://github.com/siderolabs/talos/commit/7c514a1a6c258a5f5f3ed6a4dbb15ed531a7e0b2) docs: update header links\n* [`6058c3602`](https://github.com/siderolabs/talos/commit/6058c360238ba70c780df7a24a0f6a13fa46a833) fix: shorten VLAN link names to fit into the limit of 15 characters\n* [`9c2f765c8`](https://github.com/siderolabs/talos/commit/9c2f765c86ca73d6d14957b7ae1bc7bd32fed0fd) fix: allow network device selector to match multiple links\n* [`a04b98637`](https://github.com/siderolabs/talos/commit/a04b9863762acefe2030a8a64f9c8d8608432fd2) fix: update kubernetes library for 1.28 upgrade pre-checks\n* [`f7473e477`](https://github.com/siderolabs/talos/commit/f7473e4778fe2d36ce600378cfc8d7630096f2d7) feat: update default Kubernetes to 1.28.1\n* [`d693604a1`](https://github.com/siderolabs/talos/commit/d693604a1d76aa72698eed2c1cab19e3cd34dc01) chore: fix default image list in the release notes\n* [`d91b5b3a3`](https://github.com/siderolabs/talos/commit/d91b5b3a31188d64cbc5ad8385000fae0fcf55e5) feat: set environment variables early in the boot\n* [`c918c0855`](https://github.com/siderolabs/talos/commit/c918c0855d08e06b832699e8c8b66017e457abc9) fix: set correct (1 year) talosconfig expiration\n* [`79bbdf454`](https://github.com/siderolabs/talos/commit/79bbdf454eb9bb891e845efff73db1bbdfd6d43e) fix: set proper timeouts for KubePrism loadbalancer\n* [`b8fb55d5c`](https://github.com/siderolabs/talos/commit/b8fb55d5c2e0433df46ac7bc3eeaea08e12d572d) fix: use a mount prefix when installing a bootloader\n* [`44f59a804`](https://github.com/siderolabs/talos/commit/44f59a8049beed1db453ef1d5a74f0e771ae39ff) feat: improve imager APIs\n* [`2d3ac925e`](https://github.com/siderolabs/talos/commit/2d3ac925ea519b8b5160190e1fdb8aba01a9ef74) refactor: update NTP spike detector\n* [`af0cc70e3`](https://github.com/siderolabs/talos/commit/af0cc70e3775cf7017387c541273a2580c55c78c) test: update e2e-aws to use worker groups\n* [`d03dc7a8a`](https://github.com/siderolabs/talos/commit/d03dc7a8afdd3fbf084a6d91544de5423f56d68c) chore: validate new system extensions\n* [`bbeb489aa`](https://github.com/siderolabs/talos/commit/bbeb489aa8282809bf65e89b3a571193814d3b1e) chore: drop firmware from initramfs\n* [`3c9f7a7de`](https://github.com/siderolabs/talos/commit/3c9f7a7de641bed699533ace6451387ddbfec44e) chore: re-enable nolintlint and typecheck linters\n* [`c51e2c9b4`](https://github.com/siderolabs/talos/commit/c51e2c9b482a113b154d3e6d7b2b37346a1b1043) feat: update CoreDNS to 1.11.1\n* [`8670450d2`](https://github.com/siderolabs/talos/commit/8670450d28040f35e08aa4d771a1415cd5c1920d) release(v1.6.0-alpha.0): prepare release\n* [`6778ded29`](https://github.com/siderolabs/talos/commit/6778ded29de5369b1869194a0710f627121b5334) feat: add e2e-aws for nvidia extensions\n* [`74c07ed71`](https://github.com/siderolabs/talos/commit/74c07ed714d5751336e8745977caa3dca5060d7d) chore: update Go to 1.21\n* [`a28d72e9c`](https://github.com/siderolabs/talos/commit/a28d72e9c262bd8fb84959ede952542a6e95d0be) fix: ova contents to be named `disk.*`\n* [`c0ea4d7ba`](https://github.com/siderolabs/talos/commit/c0ea4d7ba504dd8e1558f11e0cddd41dbf8bc720) fix: properly calculate overal of node address with subnet filters\n* [`d6b2719e2`](https://github.com/siderolabs/talos/commit/d6b2719e2e824cf5df9314523e3a4138b404e615) chore: drone: move extensions step to a function\n* [`9608ef56d`](https://github.com/siderolabs/talos/commit/9608ef56dc602636da1449ff05d237e0e20e5154) chore: allow bridge traffic with DHCP broadcast traffic\n* [`c99316457`](https://github.com/siderolabs/talos/commit/c993164576453fd03eb8fc517badd7de8004f4ad) docs: fix the installing system extensions doc\n* [`833895940`](https://github.com/siderolabs/talos/commit/833895940b173e247816751ca7287ccde7a36d03) chore: add tests for zfs extension\n* [`cb468c41c`](https://github.com/siderolabs/talos/commit/cb468c41cbbec6cd5f28c3cd3457aa4a30b81d4c) fix: copy proper modules to arm64 squashfs\n* [`ea0d6e8c6`](https://github.com/siderolabs/talos/commit/ea0d6e8c6a8ce8cd516bc05c99534241dff60b9f) fix: prevent dashboard crashes when process info is not available\n* [`e9077a6fb`](https://github.com/siderolabs/talos/commit/e9077a6fb9db5bcadea342200f057c1dc6ffb9af) feat: filter the hostname to produce nodename\n* [`dc8361c1d`](https://github.com/siderolabs/talos/commit/dc8361c1d524e3a52dfa18ee1b539fb81a02ef8d) fix: properly GC images supplied with both tag and digest\n* [`ccfa8de11`](https://github.com/siderolabs/talos/commit/ccfa8de1174b4e5d59c2f92b44d8dd65235b590a) fix: automatically change `rpi_4` board on upgrade\n* [`b56e8b7d9`](https://github.com/siderolabs/talos/commit/b56e8b7d9babe9a963b1fc9a2f41882d08fbafe3) fix: support 'List' type manifests\n* [`574d48e54`](https://github.com/siderolabs/talos/commit/574d48e54020b02f74c2aeadca1c10499bf967b0) fix: use image digest when starting a container\n* [`175747cea`](https://github.com/siderolabs/talos/commit/175747cea58d73f8532c114b7754668d24ab9c92) fix: ntp query error with bare IPv6 address\n* [`c8b507fb2`](https://github.com/siderolabs/talos/commit/c8b507fb26ca30cf0aa98c8cf669a2a03583fc1c) docs: fix kubeprism typo\n* [`0cdcb2e0e`](https://github.com/siderolabs/talos/commit/0cdcb2e0e8131510aab654211d3622fb17f8375e) docs: restructure docs for nvidia drivers for v1.4\n* [`676db9768`](https://github.com/siderolabs/talos/commit/676db9768433027ebc6ff22a0414692ccec2ccf4) docs: fork docs for Talos 1.6\n* [`92ad18c18`](https://github.com/siderolabs/talos/commit/92ad18c18fae5ac073cdd98d24c5aeb5edb4091a) fix: write correct capacity to the ovf\n* [`6b0373ebe`](https://github.com/siderolabs/talos/commit/6b0373ebef88600571ec54c189fd6ea3b0c777e8) chore: move bash tests to integration\n* [`52b3d8d37`](https://github.com/siderolabs/talos/commit/52b3d8d37cd1cf4eb3aa046781f105a1c39e69a0) docs: make Talos 1.5 documentation the default one\n* [`dc873df9b`](https://github.com/siderolabs/talos/commit/dc873df9b4cf169b4f7789690b80ac1e02b27d57) chore: fix the filenames of openstack images\n* [`b5c0e7b24`](https://github.com/siderolabs/talos/commit/b5c0e7b24cbd1546304ca33328b89e022e6e0675) docs: update nvidia docs\n* [`9606e871e`](https://github.com/siderolabs/talos/commit/9606e871e422b72aaef39ae03e334119602b8f31) docs: update Jiva Pod Security Policy\n* [`a86ed4362`](https://github.com/siderolabs/talos/commit/a86ed4362c009c389766ecd4bfcbc0ade999bb2e) chore: update Kubernetes Go modules to 0.28.0\n* [`97b4e3e91`](https://github.com/siderolabs/talos/commit/97b4e3e91cb4a238a8f81c8ce2983c0033a355cb) feat: update Kubernetes to 1.28.0\n* [`79ca1a3df`](https://github.com/siderolabs/talos/commit/79ca1a3dfb485fc5180bda38ab58a2d4c595a6aa) feat: e2e-aws using tf code\n* [`bf3a5e011`](https://github.com/siderolabs/talos/commit/bf3a5e01190e1cf80769343cf94af4c1bfb80318) chore: add version compatibility for Talos 1.6\n* [`969e8097c`](https://github.com/siderolabs/talos/commit/969e8097ce062197c9011d206cdbc7de1dc87df5) feat: update Kubernetes to 1.28.0-rc.1\n* [`ca41b611e`](https://github.com/siderolabs/talos/commit/ca41b611e97a0ef5020f01011267b82a155d136a) chore: drone jsonnet cleanup\n* [`bc198e98e`](https://github.com/siderolabs/talos/commit/bc198e98ef6dd03e07d75ab2eb8b944d10ad3739) docs: retain cilium autoMount pending upstream hostPath fix\n* [`86c94eff8`](https://github.com/siderolabs/talos/commit/86c94eff8d9e1abec11039f79dc6a9b35d46c7f3) refactor: docgen and config examples\n* [`ee6d639f6`](https://github.com/siderolabs/talos/commit/ee6d639f6c374cf8e1843dd3720047fea7dd3325) fix: match routes on the priority properly\n* [`bff0d8f32`](https://github.com/siderolabs/talos/commit/bff0d8f32c55d0cec9aed67592a6ccad8e5efee8) chore: fix dependencies in the release pipeline\n* [`e1b288679`](https://github.com/siderolabs/talos/commit/e1b288679e922fa0e255273adf4b7a1226518424) refactor: compile regex in validation method on the first use\n* [`daa4c185a`](https://github.com/siderolabs/talos/commit/daa4c185ae9a6318d779f45c730ac695e14ca6c7) docs: add what's new and documentation for Talos 1.5\n* [`c4a1ca8d6`](https://github.com/siderolabs/talos/commit/c4a1ca8d61fcb1338da1ca223b9b4349a6af76e2) chore: remove <-errCh where possible in grpc methods\n* [`e0f383598`](https://github.com/siderolabs/talos/commit/e0f383598e2f285c04264e9a3787fcdcd56add85) chore: clean up the output of the `imager`\n* [`fb536af4d`](https://github.com/siderolabs/talos/commit/fb536af4d1804b8b802a4211739ac410fd34bb93) chore: optimize memory usage of `tcell` library on init\n* [`7c86a365e`](https://github.com/siderolabs/talos/commit/7c86a365e2691065e5e06a4789621bc9f43f3c4b) chore: publish systemd-boot and systemd-stub assets\n* [`7d688ccfe`](https://github.com/siderolabs/talos/commit/7d688ccfeb00ca46999b98512e49ac94f17d2693) fix: make encryption config provider default to `luks2` if not set\n* [`80238a05a`](https://github.com/siderolabs/talos/commit/80238a05a6f83b2d8bf3b04816d2b0a5c499eca8) chore: unify semver under `github.com/blang/semver/v4`\n* [`0f1920bdd`](https://github.com/siderolabs/talos/commit/0f1920bdda5b7f2e2291e75d14453cf81a1b6cd6) chore: provide a resource to peek into Linux clock adjustments\n* [`4eab3017b`](https://github.com/siderolabs/talos/commit/4eab3017b036d3229a6fa7dc9612050d1499e2b6) fix: calculate log2i properly\n* [`bcf284530`](https://github.com/siderolabs/talos/commit/bcf2845307ad2c4395967cbb8e756d6a0d8caf2c) fix: update providerid prefix for aws\n* [`ac2aff5cc`](https://github.com/siderolabs/talos/commit/ac2aff5cc5e5234fecf1f49b0f5d583c633aafa4) fix: fix azure portion of cloud uploader\n* [`793dcedc9`](https://github.com/siderolabs/talos/commit/793dcedc957389c9d91da62517a43968bd99b09d) fix: fast-wipe the system disk on talosctl reset\n* [`76fa45afb`](https://github.com/siderolabs/talos/commit/76fa45afbac5d212faa534047255c0256e78d08a) docs: update cilium instructions\n</p>\n</details>\n\n### Changes since v1.6.0-alpha.1\n<details><summary>45 commits</summary>\n<p>\n\n* [`514e514ba`](https://github.com/siderolabs/talos/commit/514e514ba650419a4caad4ee87c52a367ce1e323) feat: update Linux 6.1.63, containerd 1.7.9\n* [`aca8b5e17`](https://github.com/siderolabs/talos/commit/aca8b5e179962c8e1dc27ca8de527e981f763004) fix: ignore kernel command line in container mode\n* [`020a0eb63`](https://github.com/siderolabs/talos/commit/020a0eb63ea39d25faa8eba8568584243d814457) docs: fix table formatting for bootstraprequest\n* [`0eb245e04`](https://github.com/siderolabs/talos/commit/0eb245e04374cd21a369d298b73e8bc6db11d153) docs: fix talosctl pcap example indentation\n* [`de6caf534`](https://github.com/siderolabs/talos/commit/de6caf5348f815dddbd4a595d40d4c4ad71282bc) docs: fix table formatting for machineservice api\n* [`27d208c26`](https://github.com/siderolabs/talos/commit/27d208c26bd1fe5a37b127cd83cab76b5671758a) feat: implement OAuth2 device flow for machine config\n* [`5c8fa2a80`](https://github.com/siderolabs/talos/commit/5c8fa2a80382b6ea83d81c434b2e28a9901fdcad) chore: start containerd early in boot\n* [`95a252cfc`](https://github.com/siderolabs/talos/commit/95a252cfc91eeeeb48ac3b3e3cd6ad7ba14ab1eb) docs: fix link in what is new page\n* [`0d3c3ed71`](https://github.com/siderolabs/talos/commit/0d3c3ed716670c80d33351d912620e5b91f6c7e3) feat: support kube scheduler config\n* [`06941b7e5`](https://github.com/siderolabs/talos/commit/06941b7e5ca4f937c1996828e5a543967902656d) fix: allow rootfs propagation configuration for extension services\n* [`57dc796f3`](https://github.com/siderolabs/talos/commit/57dc796f381e87f398cfed3ac7cd87ff51454b75) docs: update lastRelease to v1.5.5 in _index.md\n* [`21d944a64`](https://github.com/siderolabs/talos/commit/21d944a643d8eec104d703cc8995e9ac80d2417b) docs: add timezone information\n* [`4f1ad16c7`](https://github.com/siderolabs/talos/commit/4f1ad16c764e643f7bf71ed8ca46e840875011ec) feat: support kubelet credentialprovider config\n* [`71a3bf0e3`](https://github.com/siderolabs/talos/commit/71a3bf0e3e42117e7283b41116419d7d2f28d82c) fix: allow extra kernel args for secureboot installer\n* [`f38eaaab8`](https://github.com/siderolabs/talos/commit/f38eaaab87f77f33b0317d4405c84575023ee0da) feat: rework secureboot and PCR signing key\n* [`6eade3d5e`](https://github.com/siderolabs/talos/commit/6eade3d5ef5c5356d0bfc0e3d52263a39d2e9f1a) chore: add ability to rewrite uuids and set unique tokens for Talos\n* [`e9c7ac17a`](https://github.com/siderolabs/talos/commit/e9c7ac17a9b707950b249e08e11ed7ddac64e8ae) fix: set max msg recv size when proxying\n* [`e22ab440d`](https://github.com/siderolabs/talos/commit/e22ab440d7794a9c46edf1357124571057b6b19d) feat: update Linux 6.1.61, containerd 1.7.8, runc 1.1.10\n* [`8245361f9`](https://github.com/siderolabs/talos/commit/8245361f9cfb66d68bc54330a47814eb730eb839) feat: show first 32 bytes of response body on download error\n* [`75d3987c0`](https://github.com/siderolabs/talos/commit/75d3987c05390d3c0a7cf4de855895f1d10c8a84) chore: drop sha1 from genereated pcr json\n* [`6f32d2990`](https://github.com/siderolabs/talos/commit/6f32d2990f438a9e8134d7e94558a54b3912854e) feat: add `.der` output `talosctl gen secureboot pcr`\n* [`87c40da6c`](https://github.com/siderolabs/talos/commit/87c40da6cc5d9ae62d20984ba5d3762da734a49e) fix: proper logging in machined on startup\n* [`a54da5f64`](https://github.com/siderolabs/talos/commit/a54da5f641886d723465e0a8cfa95b15bc2e96aa) fix: image build for nanopi_4s\n* [`6f3cd0593`](https://github.com/siderolabs/talos/commit/6f3cd05935a2faaf14d16c2e643f54e6f9134c0f) refactor: update packet capture to use 'afpacket' interface\n* [`813442dd7`](https://github.com/siderolabs/talos/commit/813442dd7a08b2781829ef190b110aa38c725932) fix: don't validate machine.install if installed\n* [`dff60069c`](https://github.com/siderolabs/talos/commit/dff60069c0230ecf531c5593724211fd75f26d7c) feat: update Kubernetes to 1.29.0-alpha.3\n* [`c97db5dfe`](https://github.com/siderolabs/talos/commit/c97db5dfe174032f012bdd525a3479ebea200c93) chore: bump Go dependencies\n* [`807a9950a`](https://github.com/siderolabs/talos/commit/807a9950ac5cb542e41d65af0f9f80f1c73550a3) fix: use custom Talos/kernel version when generating UKI\n* [`eb94468a6`](https://github.com/siderolabs/talos/commit/eb94468a659b4518b317398f92346b62e6adefe4) docs: add documentation for Image Factory\n* [`2e78513e1`](https://github.com/siderolabs/talos/commit/2e78513e16b2eb0d83a4a7e107c470058d30837d) refactor: drop the dependency link platform -> network ctrl\n* [`6dc776b8a`](https://github.com/siderolabs/talos/commit/6dc776b8aaa2d9382737d41a90023e8e4ea1a601) fix: when writing to META in the installer/imager, use fixed name\n* [`3703041e9`](https://github.com/siderolabs/talos/commit/3703041e989c83c1ad7496851c6687f729cb207f) chore: remove uneeded code\n* [`cbe6e7622`](https://github.com/siderolabs/talos/commit/cbe6e7622d0180ca53ab0ce92d38e4704d466d1a) fix: generate images for SBCs using imager\n* [`5dff164f1`](https://github.com/siderolabs/talos/commit/5dff164f1c8fc08b66f0ea509db36561eaef464c) fix: fix error output of cli action tracker\n* [`ef5056122`](https://github.com/siderolabs/talos/commit/ef5056122b38a168dd8ee429a6bc4cad0860177d) feat: update etcd to 3.5.10\n* [`45ae80873`](https://github.com/siderolabs/talos/commit/45ae80873f1a7a3cb5643f7d94108a96f36cad32) chore: bump go-api-signature dependency to v0.3.1\n* [`ffa5e05cb`](https://github.com/siderolabs/talos/commit/ffa5e05cb9c8028897ce5e08183be52965004726) fix: make Talos work on Rockpi 4c boards again\n* [`8eba4c599`](https://github.com/siderolabs/talos/commit/8eba4c5999ca4a43220704ff2297706fd9e9d27b) feat: generate secrets bundle from the machine config\n* [`c7de745f6`](https://github.com/siderolabs/talos/commit/c7de745f61490ee8192bbab34fbb8a4bad21de9f) chore: drop deprecated code\n* [`cc0c3ab69`](https://github.com/siderolabs/talos/commit/cc0c3ab69c7807236955eb53ccac4cc70fcca32a) docs: update rpi_generic.md\n* [`a009f5c60`](https://github.com/siderolabs/talos/commit/a009f5c60c9506dd5064106bbef38fe36813db64) fix: accept sysctl paths with dots\n* [`4919f6ee2`](https://github.com/siderolabs/talos/commit/4919f6ee22b5f6cf53f801e13072f6d64027c215) feat: add GOMEMLIMIT to shipped manifests with memory limits\n* [`73ee576ea`](https://github.com/siderolabs/talos/commit/73ee576ea711a9f36a8d35ceba4716276a2e5f70) chore: update sonobuouy library, drop the fork\n* [`c23bc2f4a`](https://github.com/siderolabs/talos/commit/c23bc2f4a77c3e9b2e88f99d05266fcd8fb4a51b) chore: support OCI layout as a source for profile input\n* [`154bbd70f`](https://github.com/siderolabs/talos/commit/154bbd70f7bdfd464ad6136c7e7e057d2402c0f6) docs: fix talos version in guide for docker\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>7 commits</summary>\n<p>\n\n* [`e8e801b`](https://github.com/siderolabs/extras/commit/e8e801b0038ee23385e6a195e0f3d27fdb4f34b1) feat: update Go to 1.21.4\n* [`d816a02`](https://github.com/siderolabs/extras/commit/d816a0246b054c94eb7a6ecbf7c0d287a55cfab4) chore: move project to using kres\n* [`3893789`](https://github.com/siderolabs/extras/commit/389378913436bc1c282c9e38a9066e847b4f1b51) chore: move to github workflows\n* [`6d48418`](https://github.com/siderolabs/extras/commit/6d484185f40337f1455a99bbe8d8e1bed716bc6a) feat: update Go to 1.21.3\n* [`09d7c3e`](https://github.com/siderolabs/extras/commit/09d7c3e93d4fbad01579bb89b8b5ccac06b914fc) chore: update releases\n* [`a011245`](https://github.com/siderolabs/extras/commit/a011245588d652ef1bfe23ec9a66c0500868b829) feat: update Go to 1.21.1\n* [`d3f54c7`](https://github.com/siderolabs/extras/commit/d3f54c7fed6c664f966ebfef76fb338f2fc2bc45) feat: update Go to 1.20.8\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`efca710`](https://github.com/siderolabs/gen/commit/efca710d509e6088d7a1a825bd49317df1427639) chore: add `FilterInPlace` method to maps and update module\n* [`36a3ae3`](https://github.com/siderolabs/gen/commit/36a3ae312ce03876b2c961a1bcb4ef4c221593d7) feat: update module\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>7 commits</summary>\n<p>\n\n* [`fa05430`](https://github.com/siderolabs/go-kubernetes/commit/fa054302843bf48d96d839d0b3ffc6621261ff45) chore: support kube-scheduler config version\n* [`68bf392`](https://github.com/siderolabs/go-kubernetes/commit/68bf392083adbe2b13487ac418930e71e1c318c7) feat: add dropped API resource for 1.29\n* [`09fa006`](https://github.com/siderolabs/go-kubernetes/commit/09fa0066c89220f0df6beaddd544ab0100802258) fix: retry Windows connection errors\n* [`3aa47a4`](https://github.com/siderolabs/go-kubernetes/commit/3aa47a46f28c8a8c62650a00002f88411202e9d8) feat: support Kubernetes 1.29 upgrades\n* [`ae33a4a`](https://github.com/siderolabs/go-kubernetes/commit/ae33a4a3939cddfceedd2846c0711676775de57e) feat: introduce support for Kubernetes version compatibility checks\n* [`cf2754e`](https://github.com/siderolabs/go-kubernetes/commit/cf2754eecb4ae54e5333d4f31cc725950963ecf5) chore: update to use GHA\n* [`44e26b3`](https://github.com/siderolabs/go-kubernetes/commit/44e26b35ffe85bc3e310d0b8dafd4db9bbe99db2) feat: update removed feature gates for 1.28\n</p>\n</details>\n\n### Changes from siderolabs/go-retry\n<details><summary>1 commit</summary>\n<p>\n\n* [`23b6fc2`](https://github.com/siderolabs/go-retry/commit/23b6fc21e54e702f324dbdd2576b6c7c60fb7bd5) fix: provider modern error unwrapping\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>32 commits</summary>\n<p>\n\n* [`3aea711`](https://github.com/siderolabs/pkgs/commit/3aea71139fe19d8161c0e3f90272add239b51b62) feat: bump dependencies\n* [`d59cb3e`](https://github.com/siderolabs/pkgs/commit/d59cb3e3052f861f02e33b9980dd2a4cb859a2e2) feat(lvm2): configure thin support\n* [`252a59f`](https://github.com/siderolabs/pkgs/commit/252a59ffe374ce98c71b0c9b959e691addd38919) feat: bump dependencies\n* [`0bb2a79`](https://github.com/siderolabs/pkgs/commit/0bb2a79ac7dadb6f1cf13ae061b4a6ca63cc2b7e) feat: update Go to 1.21.4\n* [`f57b0a9`](https://github.com/siderolabs/pkgs/commit/f57b0a9b3efff0410c758b662f8a717b643526fb) chore: fix kernel target to honor `PLATFORM`\n* [`5f84302`](https://github.com/siderolabs/pkgs/commit/5f843025416b6e7b5a7b5920f48b610fe94d7611) chore: move to using kres\n* [`d7509f1`](https://github.com/siderolabs/pkgs/commit/d7509f19c9971155a14d1a3ecda5b23424d02cd6) chore: bump deps\n* [`3a66437`](https://github.com/siderolabs/pkgs/commit/3a6643741d423de6286457cfb71097d420f038a1) chore: add gh workflows\n* [`2e892fd`](https://github.com/siderolabs/pkgs/commit/2e892fdca61391fdb060797ed372f86ca71bb5b8) feat: update versions\n* [`37348d6`](https://github.com/siderolabs/pkgs/commit/37348d6cf39459ff38359a651013136e5c644cb9) feat: update Go to 1.21.3\n* [`34f3c41`](https://github.com/siderolabs/pkgs/commit/34f3c41d45980a3282432be79d940d1c87e32708) feat: add Solarflare SFC9000 support\n* [`0c84090`](https://github.com/siderolabs/pkgs/commit/0c8409060699e20eac8d7123b5213b443d3b7b5e) feat: update releases\n* [`19cdf71`](https://github.com/siderolabs/pkgs/commit/19cdf71b84363929092b7ad8f2f4a7464abd98fc) feat: enable common sensors\n* [`acee18e`](https://github.com/siderolabs/pkgs/commit/acee18e8a3cce66a0df47c927cb7fe2b4bc81685) chore: bump kernel to 6.1.54\n* [`1d16fd2`](https://github.com/siderolabs/pkgs/commit/1d16fd2e22ce0a444df3df82f8c99a93347698c2) feat: add Chelsio support\n* [`4504f83`](https://github.com/siderolabs/pkgs/commit/4504f83f668776161af56853c3faec61edc4cdb6) chore: rename kconfig-hardened-check\n* [`847a9c3`](https://github.com/siderolabs/pkgs/commit/847a9c3bbea9a8c350dc0b2b84d473c2fd23feb2) chore: enable dm thin provisioning\n* [`1401505`](https://github.com/siderolabs/pkgs/commit/1401505a95eebb1ff9e2baac6239baf822b7576f) chore: drop `-pkgs` for upstream kernel modules\n* [`a62471d`](https://github.com/siderolabs/pkgs/commit/a62471daea9b4e6f1d7ed03c208a5603096037f3) feat: add binfmt_misc support\n* [`518c441`](https://github.com/siderolabs/pkgs/commit/518c441851a434e72939a3f27e8dfb64e3360bb6) feat: add gVNIC support\n* [`7d9e60e`](https://github.com/siderolabs/pkgs/commit/7d9e60e33fb602c81c61112f3557808a7064bb9a) feat: update Go to 1.21.1\n* [`d3d7d29`](https://github.com/siderolabs/pkgs/commit/d3d7d295221d951e8f8bb3935f04392f9efe0e1f) chore: bump deps\n* [`3b70656`](https://github.com/siderolabs/pkgs/commit/3b70656344332f553e0ae16e8bb39e1c3d92287a) chore: fix cacert perms\n* [`cca80b7`](https://github.com/siderolabs/pkgs/commit/cca80b7b939a2e5eb4769cc9e84d471bc4a6aec1) feat: update Linux to 6.1.46\n* [`2e1c0b9`](https://github.com/siderolabs/pkgs/commit/2e1c0b912b2bcde35f04d63fe6840d5e4dc74d60) fix: nonfree kmod pkg name\n* [`cff5beb`](https://github.com/siderolabs/pkgs/commit/cff5bebf2f23ab02591ca1d72a87208d94328ab4) feat: add btrfs support\n* [`7717b7e`](https://github.com/siderolabs/pkgs/commit/7717b7e01c4c7170c7a6dcfaf74513585f40b14c) chore: bump deps\n* [`2f19f18`](https://github.com/siderolabs/pkgs/commit/2f19f18d145096766dea3c592c28e62f08113b38) feat: update containerd to 1.6.23\n* [`30d4b74`](https://github.com/siderolabs/pkgs/commit/30d4b743f49396d62dc3ffadcf25511cf891e964) feat: update Go to 1.21\n* [`eda123d`](https://github.com/siderolabs/pkgs/commit/eda123ddbd7ea5682ffe62164c41daf8ba531416) feat: update runc to 1.1.9\n* [`30cd584`](https://github.com/siderolabs/pkgs/commit/30cd5846bd7a9cbf5e79c23b9e42a65a213276e2) chore: enable pushing of non-free packages\n* [`fb247b5`](https://github.com/siderolabs/pkgs/commit/fb247b5dcc465b6d77248b544465f582a0dd6e6c) chore: update kernel and microcode\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>5 commits</summary>\n<p>\n\n* [`5ab8f9d`](https://github.com/siderolabs/siderolink/commit/5ab8f9d2e62237eb3b9a26c6ee1e8c39a866487d) feat: allow persistent keepalive to be set for the peer\n* [`71dd308`](https://github.com/siderolabs/siderolink/commit/71dd3084984dfd78880efab9e9a9cc1a2313ad4d) chore: provide unique_token and Talos version in ProvisionRequest\n* [`0ee5425`](https://github.com/siderolabs/siderolink/commit/0ee54251337fd509e83b714f2fdaf9f48dbf022c) chore: revert sys moduel to 0.13.0\n* [`6be9ba7`](https://github.com/siderolabs/siderolink/commit/6be9ba7600782a885f2c11f8dbb81b818d136de1) chore: bump deps\n* [`448cbe1`](https://github.com/siderolabs/siderolink/commit/448cbe19086c8f3a99869b675054cce6df8cd2c7) chore: bump `golang.org/x/net` to 0.8.0\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>13 commits</summary>\n<p>\n\n* [`ff7fe96`](https://github.com/siderolabs/tools/commit/ff7fe96d1de23ca4c61db36b333e135ec5af4404) feat: update Go to 1.21.4\n* [`6216d64`](https://github.com/siderolabs/tools/commit/6216d641c29afefd22e757f73b2dfa7428891971) fix: org name\n* [`4334b92`](https://github.com/siderolabs/tools/commit/4334b92a02577e6ed7a3bb1645bef45f6465cb1c) chore: move to using kres\n* [`024ef25`](https://github.com/siderolabs/tools/commit/024ef257f4b13a1b0f31399f00881dd492d9cf20) chore: bump deps\n* [`5a22409`](https://github.com/siderolabs/tools/commit/5a2240995c086b97d05189ebc965c5ff281e65ad) chore: refactor github actions\n* [`9a05d12`](https://github.com/siderolabs/tools/commit/9a05d126f5bd2cc14af5d4c55499c07023f058d8) feat: move to gh workflow\n* [`a4a52e2`](https://github.com/siderolabs/tools/commit/a4a52e235c6debd23c2fbd938ceb6e97326d1b6f) chore: add dummy gh workflow\n* [`9c09b00`](https://github.com/siderolabs/tools/commit/9c09b00ded2aa843a2142bc6659cdcade607c566) feat: update dependencies\n* [`35948af`](https://github.com/siderolabs/tools/commit/35948af8c3f955d02900c9dcd76f1c9e33502f52) feat: update Go to 1.21.3\n* [`09023c1`](https://github.com/siderolabs/tools/commit/09023c1d6eec46f43ccdba3bd703d0d3ac72220e) feat: update OpenSSL to 3.1.3\n* [`7fa8bb5`](https://github.com/siderolabs/tools/commit/7fa8bb542cb2984992e002ccceb0d655d336be96) feat: update releases\n* [`fa388de`](https://github.com/siderolabs/tools/commit/fa388de914cc3efd54a23ad2a650437e600fbb09) feat: update Go to 1.21.1\n* [`33fb4b3`](https://github.com/siderolabs/tools/commit/33fb4b35661b12fcf023ec96746e04281cc8c911) feat: update Go to 1.21\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/Azure/azure-sdk-for-go/sdk/azcore**                            v1.9.0 **_new_**\n* **github.com/Azure/azure-sdk-for-go/sdk/azidentity**                        v1.4.0 **_new_**\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates**  v1.0.0 **_new_**\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys**          v1.0.1 **_new_**\n* **github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets**       v1.0.1 **_new_**\n* **github.com/aws/aws-sdk-go-v2/config**                                     v1.18.32 -> v1.25.4\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**                           v1.13.7 -> v1.14.5\n* **github.com/aws/smithy-go**                                                v1.14.0 -> v1.17.0\n* **github.com/beevik/ntp**                                                   v1.2.0 -> v1.3.0\n* **github.com/blang/semver/v4**                                              v4.0.0 **_new_**\n* **github.com/containerd/cgroups/v3**                                        v3.0.2 **_new_**\n* **github.com/containerd/containerd**                                        v1.6.23 -> v1.7.9\n* **github.com/cosi-project/runtime**                                         v0.3.1 -> v0.3.17\n* **github.com/distribution/reference**                                       v0.5.0 **_new_**\n* **github.com/docker/docker**                                                v24.0.5 -> v24.0.7\n* **github.com/fatih/color**                                                  v1.15.0 -> v1.16.0\n* **github.com/foxboron/go-uefi**                                             32187aa193d0 -> 18b9ba9cd4c3\n* **github.com/fsnotify/fsnotify**                                            v1.6.0 -> v1.7.0\n* **github.com/google/go-cmp**                                                v0.5.9 -> v0.6.0\n* **github.com/google/go-containerregistry**                                  v0.15.2 -> v0.16.1\n* **github.com/google/uuid**                                                  v1.3.0 -> v1.4.0\n* **github.com/gopacket/gopacket**                                            v1.1.1 -> e79bddbcb4a7\n* **github.com/hetznercloud/hcloud-go/v2**                                    v2.0.0 -> v2.4.0\n* **github.com/insomniacslk/dhcp**                                            0f9eb93a696c -> 6a2c8fbdcc1c\n* **github.com/jsimonetti/rtnetlink**                                         v1.3.4 -> v1.3.5\n* **github.com/mattn/go-isatty**                                              v0.0.19 -> v0.0.20\n* **github.com/mdp/qrterminal/v3**                                            v3.2.0 **_new_**\n* **github.com/opencontainers/runtime-spec**                                  1c3f411f0417 -> v1.1.0-rc.1\n* **github.com/prometheus/procfs**                                            v0.11.1 -> v0.12.0\n* **github.com/rivo/tview**                                                   6cc0565babaf -> 7c9e464bac02\n* **github.com/scaleway/scaleway-sdk-go**                                     v1.0.0-beta.20 -> v1.0.0-beta.21\n* **github.com/siderolabs/extras**                                            v1.5.0 -> v1.6.0-alpha.0-5-ge8e801b\n* **github.com/siderolabs/gen**                                               v0.4.5 -> v0.4.7\n* **github.com/siderolabs/go-kubernetes**                                     v0.2.2 -> v0.2.8\n* **github.com/siderolabs/go-retry**                                          v0.3.2 -> v0.3.3\n* **github.com/siderolabs/pkgs**                                              v1.5.0-6-g2f2c9cd -> v1.6.0-alpha.0-31-g3aea711\n* **github.com/siderolabs/siderolink**                                        v0.3.1 -> v0.3.2\n* **github.com/siderolabs/talos/pkg/machinery**                               v1.5.0 -> v1.6.0-alpha.1\n* **github.com/siderolabs/tools**                                             v1.5.0 -> v1.6.0-alpha.0-12-gff7fe96\n* **github.com/spf13/cobra**                                                  v1.7.0 -> v1.8.0\n* **github.com/vmware-tanzu/sonobuoy**                                        v0.56.17 -> v0.57.1\n* **go.etcd.io/etcd/api/v3**                                                  v3.5.9 -> v3.5.10\n* **go.etcd.io/etcd/client/pkg/v3**                                           v3.5.9 -> v3.5.10\n* **go.etcd.io/etcd/client/v3**                                               v3.5.9 -> v3.5.10\n* **go.etcd.io/etcd/etcdutl/v3**                                              v3.5.9 -> v3.5.10\n* **go.uber.org/zap**                                                         v1.25.0 -> v1.26.0\n* **go4.org/netipx**                                                          ec4c8b891b28 -> 6213f710f925\n* **golang.org/x/net**                                                        v0.13.0 -> v0.18.0\n* **golang.org/x/oauth2**                                                     v0.14.0 **_new_**\n* **golang.org/x/sync**                                                       v0.3.0 -> v0.5.0\n* **golang.org/x/sys**                                                        v0.10.0 -> v0.14.0\n* **golang.org/x/term**                                                       v0.10.0 -> v0.14.0\n* **golang.org/x/text**                                                       v0.11.0 -> v0.14.0\n* **golang.org/x/time**                                                       v0.3.0 -> v0.4.0\n* **google.golang.org/grpc**                                                  v1.57.0 -> v1.59.0\n* **k8s.io/api**                                                              v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/apimachinery**                                                     v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/apiserver**                                                        v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/client-go**                                                        v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/component-base**                                                   v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/cri-api**                                                          v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/klog/v2**                                                          v2.100.1 -> v2.110.1\n* **k8s.io/kube-scheduler**                                                   v0.29.0-alpha.3 **_new_**\n* **k8s.io/kubectl**                                                          v0.28.0 -> v0.29.0-alpha.3\n* **k8s.io/kubelet**                                                          v0.28.0 -> v0.29.0-alpha.3\n* **sigs.k8s.io/yaml**                                                        v1.3.0 -> v1.4.0\n\nPrevious release can be found at [v1.5.0](https://github.com/siderolabs/talos/releases/tag/v1.5.0)\n\n## [Talos 1.6.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.6.0-alpha.1) (2023-10-17)\n\nWelcome to the v1.6.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Network Device Selectors\n\nPreviously, [network device selectors](https://www.talos.dev/v1.6/talos-guides/network/device-selector/) only matched the first link, now the configuration is applied to all matching links.\n\n\n### Linux Firmware\n\nStarting with Talos 1.6, there is no Linux firmware included in the initramfs.\nCustomers who need Linux firmware can pull them as extension during install time using the image factory service.\nIf the initial boot requires firmware, a custom iso can be built with the firmware included using the image factory service.\nThis also ensures that the linux-firmware is not tied to a specific Talos version.\n\n\n### KubePrism\n\n[KubePrism](https://www.talos.dev/v1.6/kubernetes-guides/configuration/kubeprism/) is enabled by default on port 7445.\n\n\n### talosctl CLI\n\nThe command `images` deprecated in Talos 1.5 was removed, please use `talosctl images default` instead.\n\n\n### Component Updates\n\nLinux: 6.1.58\ncontainerd: 1.7.7\nCoreDNS: 1.11.1\nKubernetes: 1.29.0-alpha.2\nFlannel: 0.22.3\n\nTalos is built with Go 1.21.3.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Serge Logvinov\n* Radosław Piliszek\n* Artem Chernyshev\n* Thomas Way\n* Utku Ozdemir\n* Andrei Kvapil\n* Christian Rolland\n* Drew Hess\n* Enno Boland\n* Henry Sachs\n* Jacob McSwain\n* Jacob McSwain\n* Jared Davenport\n* Mans Matulewicz\n* Nebula\n* Nico Berlee\n* Sascha Desch\n* Spencer Smith\n* Steve Francis\n* Thomas Lemarchand\n* Tim Jones\n* Zachary Milonas\n* guoguangwu\n* mikucat0309\n* ndbrew\n\n### Changes\n<details><summary>131 commits</summary>\n<p>\n\n* [`9dfae8467`](https://github.com/siderolabs/talos/commit/9dfae8467d5a0bf7d3fd753b980bc7801bf3e5f8) chore: update dependencies\n* [`38ce3c827`](https://github.com/siderolabs/talos/commit/38ce3c827a06c44e0399cd0a3d8a396687001b20) feat: nocloud prefer mac address\n* [`401e89411`](https://github.com/siderolabs/talos/commit/401e8941124056f9cd9649a555aafebb063bb94d) feat: customize image size\n* [`865f08f86`](https://github.com/siderolabs/talos/commit/865f08f867fa5784c5a25bfeb929dbe25a6eb763) docs: kubeadm migration guide improvements\n* [`c3e418200`](https://github.com/siderolabs/talos/commit/c3e418200032be376aa30f6db133f2dcbf8b67c2) refactor: use COSI runtime with new controller runtime DB\n* [`c1ee24465`](https://github.com/siderolabs/talos/commit/c1ee24465aaac079f84c58ac86f74e89dfeb01ed) feat: update Kubernetes to v1.29.0-alpha.2\n* [`0ff7350ab`](https://github.com/siderolabs/talos/commit/0ff7350abe94c046b8c7759ca6a1c64d9b80e497) fix: oracle integration fixes\n* [`675bada45`](https://github.com/siderolabs/talos/commit/675bada45473a91f5a99134193acf48da2789545) test: add config generation stability tests\n* [`f9639fb53`](https://github.com/siderolabs/talos/commit/f9639fb531797f4db16696e81371d9043d7041a9) test: fix 'talosctl gen' tests\n* [`6142d87a0`](https://github.com/siderolabs/talos/commit/6142d87a0f3e0a5e4babb97667a22e2497c67b4c) feat: hostname configuration improvements on the NoCloud platform\n* [`7bb205ebe`](https://github.com/siderolabs/talos/commit/7bb205ebe2efdbd691dd81b49fc6acbd3a289fa5) fix: don't use runtime-specs Mount struct in machine config\n* [`d1b27926c`](https://github.com/siderolabs/talos/commit/d1b27926c24109a2044cd07b3bb2d1e2824857c2) feat: update Go to 1.21.3\n* [`b87092ab6`](https://github.com/siderolabs/talos/commit/b87092ab69e8a4928727ad71f3ce01502f76c966) fix: handle secure boot state policy pcr digest error\n* [`498aeb8c3`](https://github.com/siderolabs/talos/commit/498aeb8c32a590b20140541a1a334fdf2da84105) docs: fix incorrect image suffix\n* [`c14a5d4f7`](https://github.com/siderolabs/talos/commit/c14a5d4f79a3af0d075288cc9fb74f15fa34faf1) feat: support service account auth in cli\n* [`336aee0fd`](https://github.com/siderolabs/talos/commit/336aee0fdb1302443f627f848bed8081bdb0d9b0) fix: use tpm2 hash algorithm constants and allow non-SHA-256 PCRs\n* [`69d8054c9`](https://github.com/siderolabs/talos/commit/69d8054c9ec194b801f8d3185519c4b26a6a6b07) chore: drop UpdateEndpointSuite\n* [`ef7be16c8`](https://github.com/siderolabs/talos/commit/ef7be16c801176fc983299229841a98f935e18ed) fix: clear the encryption config in META when STATE is reset\n* [`5fc60d2ca`](https://github.com/siderolabs/talos/commit/5fc60d2caa75a6e886e3a70c22b63a708f68ad43) feat: add Solarflare SFC9000 support\n* [`9b5cfdd0b`](https://github.com/siderolabs/talos/commit/9b5cfdd0bc252a9594f6d7112ebf7401e41d1546) chore: add tests for iscsi\n* [`b897764f8`](https://github.com/siderolabs/talos/commit/b897764f8e90fa237cedecba50a63f5f2f852543) docs: update proxmox.md\n* [`159f45bde`](https://github.com/siderolabs/talos/commit/159f45bde65097efe311674b253284cf7d167b26) docs: fix typos in CLI calls to endpoints\n* [`0bd1bdd74`](https://github.com/siderolabs/talos/commit/0bd1bdd744f68dc42ac64678972fede992a7189e) chore: allow insecure access to installer base image (imager)\n* [`10ed13067`](https://github.com/siderolabs/talos/commit/10ed13067958f3afa0819a3d8557933b218a391b) fix: the node IP for kubelet shouldn't change if nothing matches\n* [`e7575ecaa`](https://github.com/siderolabs/talos/commit/e7575ecaaea9625be471c9db1965e256959f0730) feat: support n-5 latest Kubernetes versions\n* [`e71508ec1`](https://github.com/siderolabs/talos/commit/e71508ec104b42d1882b26d6bab22fc43ca0d8bb) chore: update dependencies\n* [`6d7fa4668`](https://github.com/siderolabs/talos/commit/6d7fa466807ffcd3b6a5c84ae34a90c728fcb8be) docs: add metal network configuration guide\n* [`2b548ad0d`](https://github.com/siderolabs/talos/commit/2b548ad0d9fa7b1f1e057c160464494b1828eb77) feat: update containerd to 1.7.x\n* [`62dcfe81e`](https://github.com/siderolabs/talos/commit/62dcfe81eb17ad2927dff43a855f0169fd84271e) fix: update kubernetes library to support 1.29 upgrades\n* [`52caf0763`](https://github.com/siderolabs/talos/commit/52caf0763393bc171b95464fefd3af1a3efd5f1c) feat: update Kubernetes to 1.29.0-alpha.1\n* [`390137447`](https://github.com/siderolabs/talos/commit/390137447fbf2a8e87cb7bb313a202dbd5a31045) feat: enable KubePrism by default\n* [`1beb5e86e`](https://github.com/siderolabs/talos/commit/1beb5e86e621595af0d93798c9e158bb48e2b363) docs: add KubePrism video\n* [`a52d3cda3`](https://github.com/siderolabs/talos/commit/a52d3cda3b2eecc8aabf64b99a3ded0dad7e84c3) chore: update gen and COSI runtime\n* [`29b201d61`](https://github.com/siderolabs/talos/commit/29b201d61902017be355853a8f11c903fe9fefae) feat: enable common h/w sensors\n* [`9c2ba7c6f`](https://github.com/siderolabs/talos/commit/9c2ba7c6fa1162cb946e91a7e7d4dfecd62027a5) chore: add tests for chelsio drivers\n* [`5ca4d58dc`](https://github.com/siderolabs/talos/commit/5ca4d58dc9a2477db44d34c9f30ed21b0c3d2131) fix: generate of modules.dep when on the machine\n* [`5efcccb6b`](https://github.com/siderolabs/talos/commit/5efcccb6b14f59a9c065273493e0b82af1a85226) chore: bump kernel to 6.1.54\n* [`29c767a02`](https://github.com/siderolabs/talos/commit/29c767a028e346c635e99e491cdab150c756f77c) docs: add control plane nodes as users of apid also for control plane nodes\n* [`4874cfb95`](https://github.com/siderolabs/talos/commit/4874cfb95a8148dc7feec00de8c299d4ac022c53) chore: fix typo\n* [`96f2a62ea`](https://github.com/siderolabs/talos/commit/96f2a62eafb5c3cee254d6e15f6f8c3e91359b9a) test: update upgrade tests versions\n* [`f3a370acb`](https://github.com/siderolabs/talos/commit/f3a370acb21c83fd1393da30bad2a37ca6a09b2c) feat: update Flannel to 0.22.3\n* [`efdee6965`](https://github.com/siderolabs/talos/commit/efdee69658cfea44681954dac2552cfeee5bb30e) feat: update Kubernetes to 1.28.2\n* [`e3b494058`](https://github.com/siderolabs/talos/commit/e3b49405884186dc1db0d9592f95965a0904691d) fix: build CPU ucode correctly for early loader\n* [`c5bd0ac5c`](https://github.com/siderolabs/talos/commit/c5bd0ac5cf033a9e3084a5fe98f42ee784926636) refactor: reimplement the depmod extension rebuilder\n* [`0b883f52a`](https://github.com/siderolabs/talos/commit/0b883f52a5a81a36a0e777f6f87e2d1d176e2294) docs: add notes about stable addressing\n* [`3ef670a9e`](https://github.com/siderolabs/talos/commit/3ef670a9e8e7efff5af9872e1e13d8521ce2dca6) chore: pull in dm modules\n* [`8f4a36b0d`](https://github.com/siderolabs/talos/commit/8f4a36b0d4c35f5841a270b7b5cd7da7c798165f) docs: update aws to add command to allow KubeSpan wireguard port\n* [`a7edd0523`](https://github.com/siderolabs/talos/commit/a7edd0523f9e5a7fccc6c382b453000beab4a8ff) fix: set default route priority for hcloud platform\n* [`87c1b3ddd`](https://github.com/siderolabs/talos/commit/87c1b3ddd83f038c62d34e94ad7e34a98236130b) fix: calculate UKI ISO size dynamically\n* [`9698e4547`](https://github.com/siderolabs/talos/commit/9698e45479cb293bbefe1651b94344bd7b0a4e52) fix: handle correctly change of listen address for maintenance service\n* [`a096f05a5`](https://github.com/siderolabs/talos/commit/a096f05a56003c317ffade2c87aa8d327592e3b8) chore: update gRPC library and enable shared write buffers\n* [`9e78fecca`](https://github.com/siderolabs/talos/commit/9e78feccaecda53778acba43fb9ad177051a009c) chore: improve image signing process\n* [`f00567e20`](https://github.com/siderolabs/talos/commit/f00567e20f239e781975636b12e31501ee39bbfa) chore: add PKG_KERNEL arg to customize used kernel\n* [`2960f93ba`](https://github.com/siderolabs/talos/commit/2960f93baa55f6ea2cb3690cbc652df9aee17af8) feat: add readonly information to the disks API response\n* [`735bf9ed0`](https://github.com/siderolabs/talos/commit/735bf9ed08a5d8dd302ef3e1f61317ff9169549c) feat: bring in Google vNIC driver\n* [`3f5232075`](https://github.com/siderolabs/talos/commit/3f523207522aa69452516408f914cc792abb78b9) feat: upgrade-k8s without comments\n* [`e44875106`](https://github.com/siderolabs/talos/commit/e44875106e28e50b15c38fa8b889f51083325800) docs: update deploying-cilium.md\n* [`7046cae43`](https://github.com/siderolabs/talos/commit/7046cae43dd4e8a4ea7d80934b02cc7c8b84e53a) chore: update gopacket to reduce init memory allocs\n* [`da73b563d`](https://github.com/siderolabs/talos/commit/da73b563dd0a7d77f4490d10cc506b5570c2bf11) chore: update Go to 1.21.1\n* [`5e11f08a6`](https://github.com/siderolabs/talos/commit/5e11f08a639bd791fa7fafe3df35349959b4eb24) fix: trim file path in the container image\n* [`3d2dad4e6`](https://github.com/siderolabs/talos/commit/3d2dad4e69ba458fb406a7d7441d9e3f2fe8fde2) chore: show securtiystate on dashboard\n* [`b48510874`](https://github.com/siderolabs/talos/commit/b4851087404e6fcad52da588fd4827046011b271) chore: e2e-aws cleanup\n* [`1eebbce35`](https://github.com/siderolabs/talos/commit/1eebbce357311aaea739abe55c9e0de947791f39) chore: add output flag for talosctl config info\n* [`3fbed806c`](https://github.com/siderolabs/talos/commit/3fbed806c4e5a4167f0a357eb20486bb406103a8) chore: add tests for util-linux extensions\n* [`7c514a1a6`](https://github.com/siderolabs/talos/commit/7c514a1a6c258a5f5f3ed6a4dbb15ed531a7e0b2) docs: update header links\n* [`6058c3602`](https://github.com/siderolabs/talos/commit/6058c360238ba70c780df7a24a0f6a13fa46a833) fix: shorten VLAN link names to fit into the limit of 15 characters\n* [`9c2f765c8`](https://github.com/siderolabs/talos/commit/9c2f765c86ca73d6d14957b7ae1bc7bd32fed0fd) fix: allow network device selector to match multiple links\n* [`a04b98637`](https://github.com/siderolabs/talos/commit/a04b9863762acefe2030a8a64f9c8d8608432fd2) fix: update kubernetes library for 1.28 upgrade pre-checks\n* [`f7473e477`](https://github.com/siderolabs/talos/commit/f7473e4778fe2d36ce600378cfc8d7630096f2d7) feat: update default Kubernetes to 1.28.1\n* [`d693604a1`](https://github.com/siderolabs/talos/commit/d693604a1d76aa72698eed2c1cab19e3cd34dc01) chore: fix default image list in the release notes\n* [`d91b5b3a3`](https://github.com/siderolabs/talos/commit/d91b5b3a31188d64cbc5ad8385000fae0fcf55e5) feat: set environment variables early in the boot\n* [`c918c0855`](https://github.com/siderolabs/talos/commit/c918c0855d08e06b832699e8c8b66017e457abc9) fix: set correct (1 year) talosconfig expiration\n* [`79bbdf454`](https://github.com/siderolabs/talos/commit/79bbdf454eb9bb891e845efff73db1bbdfd6d43e) fix: set proper timeouts for KubePrism loadbalancer\n* [`b8fb55d5c`](https://github.com/siderolabs/talos/commit/b8fb55d5c2e0433df46ac7bc3eeaea08e12d572d) fix: use a mount prefix when installing a bootloader\n* [`44f59a804`](https://github.com/siderolabs/talos/commit/44f59a8049beed1db453ef1d5a74f0e771ae39ff) feat: improve imager APIs\n* [`2d3ac925e`](https://github.com/siderolabs/talos/commit/2d3ac925ea519b8b5160190e1fdb8aba01a9ef74) refactor: update NTP spike detector\n* [`af0cc70e3`](https://github.com/siderolabs/talos/commit/af0cc70e3775cf7017387c541273a2580c55c78c) test: update e2e-aws to use worker groups\n* [`d03dc7a8a`](https://github.com/siderolabs/talos/commit/d03dc7a8afdd3fbf084a6d91544de5423f56d68c) chore: validate new system extensions\n* [`bbeb489aa`](https://github.com/siderolabs/talos/commit/bbeb489aa8282809bf65e89b3a571193814d3b1e) chore: drop firmware from initramfs\n* [`3c9f7a7de`](https://github.com/siderolabs/talos/commit/3c9f7a7de641bed699533ace6451387ddbfec44e) chore: re-enable nolintlint and typecheck linters\n* [`c51e2c9b4`](https://github.com/siderolabs/talos/commit/c51e2c9b482a113b154d3e6d7b2b37346a1b1043) feat: update CoreDNS to 1.11.1\n* [`8670450d2`](https://github.com/siderolabs/talos/commit/8670450d28040f35e08aa4d771a1415cd5c1920d) release(v1.6.0-alpha.0): prepare release\n* [`6778ded29`](https://github.com/siderolabs/talos/commit/6778ded29de5369b1869194a0710f627121b5334) feat: add e2e-aws for nvidia extensions\n* [`74c07ed71`](https://github.com/siderolabs/talos/commit/74c07ed714d5751336e8745977caa3dca5060d7d) chore: update Go to 1.21\n* [`a28d72e9c`](https://github.com/siderolabs/talos/commit/a28d72e9c262bd8fb84959ede952542a6e95d0be) fix: ova contents to be named `disk.*`\n* [`c0ea4d7ba`](https://github.com/siderolabs/talos/commit/c0ea4d7ba504dd8e1558f11e0cddd41dbf8bc720) fix: properly calculate overal of node address with subnet filters\n* [`d6b2719e2`](https://github.com/siderolabs/talos/commit/d6b2719e2e824cf5df9314523e3a4138b404e615) chore: drone: move extensions step to a function\n* [`9608ef56d`](https://github.com/siderolabs/talos/commit/9608ef56dc602636da1449ff05d237e0e20e5154) chore: allow bridge traffic with DHCP broadcast traffic\n* [`c99316457`](https://github.com/siderolabs/talos/commit/c993164576453fd03eb8fc517badd7de8004f4ad) docs: fix the installing system extensions doc\n* [`833895940`](https://github.com/siderolabs/talos/commit/833895940b173e247816751ca7287ccde7a36d03) chore: add tests for zfs extension\n* [`cb468c41c`](https://github.com/siderolabs/talos/commit/cb468c41cbbec6cd5f28c3cd3457aa4a30b81d4c) fix: copy proper modules to arm64 squashfs\n* [`ea0d6e8c6`](https://github.com/siderolabs/talos/commit/ea0d6e8c6a8ce8cd516bc05c99534241dff60b9f) fix: prevent dashboard crashes when process info is not available\n* [`e9077a6fb`](https://github.com/siderolabs/talos/commit/e9077a6fb9db5bcadea342200f057c1dc6ffb9af) feat: filter the hostname to produce nodename\n* [`dc8361c1d`](https://github.com/siderolabs/talos/commit/dc8361c1d524e3a52dfa18ee1b539fb81a02ef8d) fix: properly GC images supplied with both tag and digest\n* [`ccfa8de11`](https://github.com/siderolabs/talos/commit/ccfa8de1174b4e5d59c2f92b44d8dd65235b590a) fix: automatically change `rpi_4` board on upgrade\n* [`b56e8b7d9`](https://github.com/siderolabs/talos/commit/b56e8b7d9babe9a963b1fc9a2f41882d08fbafe3) fix: support 'List' type manifests\n* [`574d48e54`](https://github.com/siderolabs/talos/commit/574d48e54020b02f74c2aeadca1c10499bf967b0) fix: use image digest when starting a container\n* [`175747cea`](https://github.com/siderolabs/talos/commit/175747cea58d73f8532c114b7754668d24ab9c92) fix: ntp query error with bare IPv6 address\n* [`c8b507fb2`](https://github.com/siderolabs/talos/commit/c8b507fb26ca30cf0aa98c8cf669a2a03583fc1c) docs: fix kubeprism typo\n* [`0cdcb2e0e`](https://github.com/siderolabs/talos/commit/0cdcb2e0e8131510aab654211d3622fb17f8375e) docs: restructure docs for nvidia drivers for v1.4\n* [`676db9768`](https://github.com/siderolabs/talos/commit/676db9768433027ebc6ff22a0414692ccec2ccf4) docs: fork docs for Talos 1.6\n* [`92ad18c18`](https://github.com/siderolabs/talos/commit/92ad18c18fae5ac073cdd98d24c5aeb5edb4091a) fix: write correct capacity to the ovf\n* [`6b0373ebe`](https://github.com/siderolabs/talos/commit/6b0373ebef88600571ec54c189fd6ea3b0c777e8) chore: move bash tests to integration\n* [`52b3d8d37`](https://github.com/siderolabs/talos/commit/52b3d8d37cd1cf4eb3aa046781f105a1c39e69a0) docs: make Talos 1.5 documentation the default one\n* [`dc873df9b`](https://github.com/siderolabs/talos/commit/dc873df9b4cf169b4f7789690b80ac1e02b27d57) chore: fix the filenames of openstack images\n* [`b5c0e7b24`](https://github.com/siderolabs/talos/commit/b5c0e7b24cbd1546304ca33328b89e022e6e0675) docs: update nvidia docs\n* [`9606e871e`](https://github.com/siderolabs/talos/commit/9606e871e422b72aaef39ae03e334119602b8f31) docs: update Jiva Pod Security Policy\n* [`a86ed4362`](https://github.com/siderolabs/talos/commit/a86ed4362c009c389766ecd4bfcbc0ade999bb2e) chore: update Kubernetes Go modules to 0.28.0\n* [`97b4e3e91`](https://github.com/siderolabs/talos/commit/97b4e3e91cb4a238a8f81c8ce2983c0033a355cb) feat: update Kubernetes to 1.28.0\n* [`79ca1a3df`](https://github.com/siderolabs/talos/commit/79ca1a3dfb485fc5180bda38ab58a2d4c595a6aa) feat: e2e-aws using tf code\n* [`bf3a5e011`](https://github.com/siderolabs/talos/commit/bf3a5e01190e1cf80769343cf94af4c1bfb80318) chore: add version compatibility for Talos 1.6\n* [`969e8097c`](https://github.com/siderolabs/talos/commit/969e8097ce062197c9011d206cdbc7de1dc87df5) feat: update Kubernetes to 1.28.0-rc.1\n* [`ca41b611e`](https://github.com/siderolabs/talos/commit/ca41b611e97a0ef5020f01011267b82a155d136a) chore: drone jsonnet cleanup\n* [`bc198e98e`](https://github.com/siderolabs/talos/commit/bc198e98ef6dd03e07d75ab2eb8b944d10ad3739) docs: retain cilium autoMount pending upstream hostPath fix\n* [`86c94eff8`](https://github.com/siderolabs/talos/commit/86c94eff8d9e1abec11039f79dc6a9b35d46c7f3) refactor: docgen and config examples\n* [`ee6d639f6`](https://github.com/siderolabs/talos/commit/ee6d639f6c374cf8e1843dd3720047fea7dd3325) fix: match routes on the priority properly\n* [`bff0d8f32`](https://github.com/siderolabs/talos/commit/bff0d8f32c55d0cec9aed67592a6ccad8e5efee8) chore: fix dependencies in the release pipeline\n* [`e1b288679`](https://github.com/siderolabs/talos/commit/e1b288679e922fa0e255273adf4b7a1226518424) refactor: compile regex in validation method on the first use\n* [`daa4c185a`](https://github.com/siderolabs/talos/commit/daa4c185ae9a6318d779f45c730ac695e14ca6c7) docs: add what's new and documentation for Talos 1.5\n* [`c4a1ca8d6`](https://github.com/siderolabs/talos/commit/c4a1ca8d61fcb1338da1ca223b9b4349a6af76e2) chore: remove <-errCh where possible in grpc methods\n* [`e0f383598`](https://github.com/siderolabs/talos/commit/e0f383598e2f285c04264e9a3787fcdcd56add85) chore: clean up the output of the `imager`\n* [`fb536af4d`](https://github.com/siderolabs/talos/commit/fb536af4d1804b8b802a4211739ac410fd34bb93) chore: optimize memory usage of `tcell` library on init\n* [`7c86a365e`](https://github.com/siderolabs/talos/commit/7c86a365e2691065e5e06a4789621bc9f43f3c4b) chore: publish systemd-boot and systemd-stub assets\n* [`7d688ccfe`](https://github.com/siderolabs/talos/commit/7d688ccfeb00ca46999b98512e49ac94f17d2693) fix: make encryption config provider default to `luks2` if not set\n* [`80238a05a`](https://github.com/siderolabs/talos/commit/80238a05a6f83b2d8bf3b04816d2b0a5c499eca8) chore: unify semver under `github.com/blang/semver/v4`\n* [`0f1920bdd`](https://github.com/siderolabs/talos/commit/0f1920bdda5b7f2e2291e75d14453cf81a1b6cd6) chore: provide a resource to peek into Linux clock adjustments\n* [`4eab3017b`](https://github.com/siderolabs/talos/commit/4eab3017b036d3229a6fa7dc9612050d1499e2b6) fix: calculate log2i properly\n* [`bcf284530`](https://github.com/siderolabs/talos/commit/bcf2845307ad2c4395967cbb8e756d6a0d8caf2c) fix: update providerid prefix for aws\n* [`ac2aff5cc`](https://github.com/siderolabs/talos/commit/ac2aff5cc5e5234fecf1f49b0f5d583c633aafa4) fix: fix azure portion of cloud uploader\n* [`793dcedc9`](https://github.com/siderolabs/talos/commit/793dcedc957389c9d91da62517a43968bd99b09d) fix: fast-wipe the system disk on talosctl reset\n* [`76fa45afb`](https://github.com/siderolabs/talos/commit/76fa45afbac5d212faa534047255c0256e78d08a) docs: update cilium instructions\n</p>\n</details>\n\n### Changes since v1.6.0-alpha.0\n<details><summary>81 commits</summary>\n<p>\n\n* [`9dfae8467`](https://github.com/siderolabs/talos/commit/9dfae8467d5a0bf7d3fd753b980bc7801bf3e5f8) chore: update dependencies\n* [`38ce3c827`](https://github.com/siderolabs/talos/commit/38ce3c827a06c44e0399cd0a3d8a396687001b20) feat: nocloud prefer mac address\n* [`401e89411`](https://github.com/siderolabs/talos/commit/401e8941124056f9cd9649a555aafebb063bb94d) feat: customize image size\n* [`865f08f86`](https://github.com/siderolabs/talos/commit/865f08f867fa5784c5a25bfeb929dbe25a6eb763) docs: kubeadm migration guide improvements\n* [`c3e418200`](https://github.com/siderolabs/talos/commit/c3e418200032be376aa30f6db133f2dcbf8b67c2) refactor: use COSI runtime with new controller runtime DB\n* [`c1ee24465`](https://github.com/siderolabs/talos/commit/c1ee24465aaac079f84c58ac86f74e89dfeb01ed) feat: update Kubernetes to v1.29.0-alpha.2\n* [`0ff7350ab`](https://github.com/siderolabs/talos/commit/0ff7350abe94c046b8c7759ca6a1c64d9b80e497) fix: oracle integration fixes\n* [`675bada45`](https://github.com/siderolabs/talos/commit/675bada45473a91f5a99134193acf48da2789545) test: add config generation stability tests\n* [`f9639fb53`](https://github.com/siderolabs/talos/commit/f9639fb531797f4db16696e81371d9043d7041a9) test: fix 'talosctl gen' tests\n* [`6142d87a0`](https://github.com/siderolabs/talos/commit/6142d87a0f3e0a5e4babb97667a22e2497c67b4c) feat: hostname configuration improvements on the NoCloud platform\n* [`7bb205ebe`](https://github.com/siderolabs/talos/commit/7bb205ebe2efdbd691dd81b49fc6acbd3a289fa5) fix: don't use runtime-specs Mount struct in machine config\n* [`d1b27926c`](https://github.com/siderolabs/talos/commit/d1b27926c24109a2044cd07b3bb2d1e2824857c2) feat: update Go to 1.21.3\n* [`b87092ab6`](https://github.com/siderolabs/talos/commit/b87092ab69e8a4928727ad71f3ce01502f76c966) fix: handle secure boot state policy pcr digest error\n* [`498aeb8c3`](https://github.com/siderolabs/talos/commit/498aeb8c32a590b20140541a1a334fdf2da84105) docs: fix incorrect image suffix\n* [`c14a5d4f7`](https://github.com/siderolabs/talos/commit/c14a5d4f79a3af0d075288cc9fb74f15fa34faf1) feat: support service account auth in cli\n* [`336aee0fd`](https://github.com/siderolabs/talos/commit/336aee0fdb1302443f627f848bed8081bdb0d9b0) fix: use tpm2 hash algorithm constants and allow non-SHA-256 PCRs\n* [`69d8054c9`](https://github.com/siderolabs/talos/commit/69d8054c9ec194b801f8d3185519c4b26a6a6b07) chore: drop UpdateEndpointSuite\n* [`ef7be16c8`](https://github.com/siderolabs/talos/commit/ef7be16c801176fc983299229841a98f935e18ed) fix: clear the encryption config in META when STATE is reset\n* [`5fc60d2ca`](https://github.com/siderolabs/talos/commit/5fc60d2caa75a6e886e3a70c22b63a708f68ad43) feat: add Solarflare SFC9000 support\n* [`9b5cfdd0b`](https://github.com/siderolabs/talos/commit/9b5cfdd0bc252a9594f6d7112ebf7401e41d1546) chore: add tests for iscsi\n* [`b897764f8`](https://github.com/siderolabs/talos/commit/b897764f8e90fa237cedecba50a63f5f2f852543) docs: update proxmox.md\n* [`159f45bde`](https://github.com/siderolabs/talos/commit/159f45bde65097efe311674b253284cf7d167b26) docs: fix typos in CLI calls to endpoints\n* [`0bd1bdd74`](https://github.com/siderolabs/talos/commit/0bd1bdd744f68dc42ac64678972fede992a7189e) chore: allow insecure access to installer base image (imager)\n* [`10ed13067`](https://github.com/siderolabs/talos/commit/10ed13067958f3afa0819a3d8557933b218a391b) fix: the node IP for kubelet shouldn't change if nothing matches\n* [`e7575ecaa`](https://github.com/siderolabs/talos/commit/e7575ecaaea9625be471c9db1965e256959f0730) feat: support n-5 latest Kubernetes versions\n* [`e71508ec1`](https://github.com/siderolabs/talos/commit/e71508ec104b42d1882b26d6bab22fc43ca0d8bb) chore: update dependencies\n* [`6d7fa4668`](https://github.com/siderolabs/talos/commit/6d7fa466807ffcd3b6a5c84ae34a90c728fcb8be) docs: add metal network configuration guide\n* [`2b548ad0d`](https://github.com/siderolabs/talos/commit/2b548ad0d9fa7b1f1e057c160464494b1828eb77) feat: update containerd to 1.7.x\n* [`62dcfe81e`](https://github.com/siderolabs/talos/commit/62dcfe81eb17ad2927dff43a855f0169fd84271e) fix: update kubernetes library to support 1.29 upgrades\n* [`52caf0763`](https://github.com/siderolabs/talos/commit/52caf0763393bc171b95464fefd3af1a3efd5f1c) feat: update Kubernetes to 1.29.0-alpha.1\n* [`390137447`](https://github.com/siderolabs/talos/commit/390137447fbf2a8e87cb7bb313a202dbd5a31045) feat: enable KubePrism by default\n* [`1beb5e86e`](https://github.com/siderolabs/talos/commit/1beb5e86e621595af0d93798c9e158bb48e2b363) docs: add KubePrism video\n* [`a52d3cda3`](https://github.com/siderolabs/talos/commit/a52d3cda3b2eecc8aabf64b99a3ded0dad7e84c3) chore: update gen and COSI runtime\n* [`29b201d61`](https://github.com/siderolabs/talos/commit/29b201d61902017be355853a8f11c903fe9fefae) feat: enable common h/w sensors\n* [`9c2ba7c6f`](https://github.com/siderolabs/talos/commit/9c2ba7c6fa1162cb946e91a7e7d4dfecd62027a5) chore: add tests for chelsio drivers\n* [`5ca4d58dc`](https://github.com/siderolabs/talos/commit/5ca4d58dc9a2477db44d34c9f30ed21b0c3d2131) fix: generate of modules.dep when on the machine\n* [`5efcccb6b`](https://github.com/siderolabs/talos/commit/5efcccb6b14f59a9c065273493e0b82af1a85226) chore: bump kernel to 6.1.54\n* [`29c767a02`](https://github.com/siderolabs/talos/commit/29c767a028e346c635e99e491cdab150c756f77c) docs: add control plane nodes as users of apid also for control plane nodes\n* [`4874cfb95`](https://github.com/siderolabs/talos/commit/4874cfb95a8148dc7feec00de8c299d4ac022c53) chore: fix typo\n* [`96f2a62ea`](https://github.com/siderolabs/talos/commit/96f2a62eafb5c3cee254d6e15f6f8c3e91359b9a) test: update upgrade tests versions\n* [`f3a370acb`](https://github.com/siderolabs/talos/commit/f3a370acb21c83fd1393da30bad2a37ca6a09b2c) feat: update Flannel to 0.22.3\n* [`efdee6965`](https://github.com/siderolabs/talos/commit/efdee69658cfea44681954dac2552cfeee5bb30e) feat: update Kubernetes to 1.28.2\n* [`e3b494058`](https://github.com/siderolabs/talos/commit/e3b49405884186dc1db0d9592f95965a0904691d) fix: build CPU ucode correctly for early loader\n* [`c5bd0ac5c`](https://github.com/siderolabs/talos/commit/c5bd0ac5cf033a9e3084a5fe98f42ee784926636) refactor: reimplement the depmod extension rebuilder\n* [`0b883f52a`](https://github.com/siderolabs/talos/commit/0b883f52a5a81a36a0e777f6f87e2d1d176e2294) docs: add notes about stable addressing\n* [`3ef670a9e`](https://github.com/siderolabs/talos/commit/3ef670a9e8e7efff5af9872e1e13d8521ce2dca6) chore: pull in dm modules\n* [`8f4a36b0d`](https://github.com/siderolabs/talos/commit/8f4a36b0d4c35f5841a270b7b5cd7da7c798165f) docs: update aws to add command to allow KubeSpan wireguard port\n* [`a7edd0523`](https://github.com/siderolabs/talos/commit/a7edd0523f9e5a7fccc6c382b453000beab4a8ff) fix: set default route priority for hcloud platform\n* [`87c1b3ddd`](https://github.com/siderolabs/talos/commit/87c1b3ddd83f038c62d34e94ad7e34a98236130b) fix: calculate UKI ISO size dynamically\n* [`9698e4547`](https://github.com/siderolabs/talos/commit/9698e45479cb293bbefe1651b94344bd7b0a4e52) fix: handle correctly change of listen address for maintenance service\n* [`a096f05a5`](https://github.com/siderolabs/talos/commit/a096f05a56003c317ffade2c87aa8d327592e3b8) chore: update gRPC library and enable shared write buffers\n* [`9e78fecca`](https://github.com/siderolabs/talos/commit/9e78feccaecda53778acba43fb9ad177051a009c) chore: improve image signing process\n* [`f00567e20`](https://github.com/siderolabs/talos/commit/f00567e20f239e781975636b12e31501ee39bbfa) chore: add PKG_KERNEL arg to customize used kernel\n* [`2960f93ba`](https://github.com/siderolabs/talos/commit/2960f93baa55f6ea2cb3690cbc652df9aee17af8) feat: add readonly information to the disks API response\n* [`735bf9ed0`](https://github.com/siderolabs/talos/commit/735bf9ed08a5d8dd302ef3e1f61317ff9169549c) feat: bring in Google vNIC driver\n* [`3f5232075`](https://github.com/siderolabs/talos/commit/3f523207522aa69452516408f914cc792abb78b9) feat: upgrade-k8s without comments\n* [`e44875106`](https://github.com/siderolabs/talos/commit/e44875106e28e50b15c38fa8b889f51083325800) docs: update deploying-cilium.md\n* [`7046cae43`](https://github.com/siderolabs/talos/commit/7046cae43dd4e8a4ea7d80934b02cc7c8b84e53a) chore: update gopacket to reduce init memory allocs\n* [`da73b563d`](https://github.com/siderolabs/talos/commit/da73b563dd0a7d77f4490d10cc506b5570c2bf11) chore: update Go to 1.21.1\n* [`5e11f08a6`](https://github.com/siderolabs/talos/commit/5e11f08a639bd791fa7fafe3df35349959b4eb24) fix: trim file path in the container image\n* [`3d2dad4e6`](https://github.com/siderolabs/talos/commit/3d2dad4e69ba458fb406a7d7441d9e3f2fe8fde2) chore: show securtiystate on dashboard\n* [`b48510874`](https://github.com/siderolabs/talos/commit/b4851087404e6fcad52da588fd4827046011b271) chore: e2e-aws cleanup\n* [`1eebbce35`](https://github.com/siderolabs/talos/commit/1eebbce357311aaea739abe55c9e0de947791f39) chore: add output flag for talosctl config info\n* [`3fbed806c`](https://github.com/siderolabs/talos/commit/3fbed806c4e5a4167f0a357eb20486bb406103a8) chore: add tests for util-linux extensions\n* [`7c514a1a6`](https://github.com/siderolabs/talos/commit/7c514a1a6c258a5f5f3ed6a4dbb15ed531a7e0b2) docs: update header links\n* [`6058c3602`](https://github.com/siderolabs/talos/commit/6058c360238ba70c780df7a24a0f6a13fa46a833) fix: shorten VLAN link names to fit into the limit of 15 characters\n* [`9c2f765c8`](https://github.com/siderolabs/talos/commit/9c2f765c86ca73d6d14957b7ae1bc7bd32fed0fd) fix: allow network device selector to match multiple links\n* [`a04b98637`](https://github.com/siderolabs/talos/commit/a04b9863762acefe2030a8a64f9c8d8608432fd2) fix: update kubernetes library for 1.28 upgrade pre-checks\n* [`f7473e477`](https://github.com/siderolabs/talos/commit/f7473e4778fe2d36ce600378cfc8d7630096f2d7) feat: update default Kubernetes to 1.28.1\n* [`d693604a1`](https://github.com/siderolabs/talos/commit/d693604a1d76aa72698eed2c1cab19e3cd34dc01) chore: fix default image list in the release notes\n* [`d91b5b3a3`](https://github.com/siderolabs/talos/commit/d91b5b3a31188d64cbc5ad8385000fae0fcf55e5) feat: set environment variables early in the boot\n* [`c918c0855`](https://github.com/siderolabs/talos/commit/c918c0855d08e06b832699e8c8b66017e457abc9) fix: set correct (1 year) talosconfig expiration\n* [`79bbdf454`](https://github.com/siderolabs/talos/commit/79bbdf454eb9bb891e845efff73db1bbdfd6d43e) fix: set proper timeouts for KubePrism loadbalancer\n* [`b8fb55d5c`](https://github.com/siderolabs/talos/commit/b8fb55d5c2e0433df46ac7bc3eeaea08e12d572d) fix: use a mount prefix when installing a bootloader\n* [`44f59a804`](https://github.com/siderolabs/talos/commit/44f59a8049beed1db453ef1d5a74f0e771ae39ff) feat: improve imager APIs\n* [`2d3ac925e`](https://github.com/siderolabs/talos/commit/2d3ac925ea519b8b5160190e1fdb8aba01a9ef74) refactor: update NTP spike detector\n* [`af0cc70e3`](https://github.com/siderolabs/talos/commit/af0cc70e3775cf7017387c541273a2580c55c78c) test: update e2e-aws to use worker groups\n* [`d03dc7a8a`](https://github.com/siderolabs/talos/commit/d03dc7a8afdd3fbf084a6d91544de5423f56d68c) chore: validate new system extensions\n* [`bbeb489aa`](https://github.com/siderolabs/talos/commit/bbeb489aa8282809bf65e89b3a571193814d3b1e) chore: drop firmware from initramfs\n* [`3c9f7a7de`](https://github.com/siderolabs/talos/commit/3c9f7a7de641bed699533ace6451387ddbfec44e) chore: re-enable nolintlint and typecheck linters\n* [`c51e2c9b4`](https://github.com/siderolabs/talos/commit/c51e2c9b482a113b154d3e6d7b2b37346a1b1043) feat: update CoreDNS to 1.11.1\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>4 commits</summary>\n<p>\n\n* [`6d48418`](https://github.com/siderolabs/extras/commit/6d484185f40337f1455a99bbe8d8e1bed716bc6a) feat: update Go to 1.21.3\n* [`09d7c3e`](https://github.com/siderolabs/extras/commit/09d7c3e93d4fbad01579bb89b8b5ccac06b914fc) chore: update releases\n* [`a011245`](https://github.com/siderolabs/extras/commit/a011245588d652ef1bfe23ec9a66c0500868b829) feat: update Go to 1.21.1\n* [`d3f54c7`](https://github.com/siderolabs/extras/commit/d3f54c7fed6c664f966ebfef76fb338f2fc2bc45) feat: update Go to 1.20.8\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`efca710`](https://github.com/siderolabs/gen/commit/efca710d509e6088d7a1a825bd49317df1427639) chore: add `FilterInPlace` method to maps and update module\n* [`36a3ae3`](https://github.com/siderolabs/gen/commit/36a3ae312ce03876b2c961a1bcb4ef4c221593d7) feat: update module\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>5 commits</summary>\n<p>\n\n* [`09fa006`](https://github.com/siderolabs/go-kubernetes/commit/09fa0066c89220f0df6beaddd544ab0100802258) fix: retry Windows connection errors\n* [`3aa47a4`](https://github.com/siderolabs/go-kubernetes/commit/3aa47a46f28c8a8c62650a00002f88411202e9d8) feat: support Kubernetes 1.29 upgrades\n* [`ae33a4a`](https://github.com/siderolabs/go-kubernetes/commit/ae33a4a3939cddfceedd2846c0711676775de57e) feat: introduce support for Kubernetes version compatibility checks\n* [`cf2754e`](https://github.com/siderolabs/go-kubernetes/commit/cf2754eecb4ae54e5333d4f31cc725950963ecf5) chore: update to use GHA\n* [`44e26b3`](https://github.com/siderolabs/go-kubernetes/commit/44e26b35ffe85bc3e310d0b8dafd4db9bbe99db2) feat: update removed feature gates for 1.28\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>24 commits</summary>\n<p>\n\n* [`2e892fd`](https://github.com/siderolabs/pkgs/commit/2e892fdca61391fdb060797ed372f86ca71bb5b8) feat: update versions\n* [`37348d6`](https://github.com/siderolabs/pkgs/commit/37348d6cf39459ff38359a651013136e5c644cb9) feat: update Go to 1.21.3\n* [`34f3c41`](https://github.com/siderolabs/pkgs/commit/34f3c41d45980a3282432be79d940d1c87e32708) feat: add Solarflare SFC9000 support\n* [`0c84090`](https://github.com/siderolabs/pkgs/commit/0c8409060699e20eac8d7123b5213b443d3b7b5e) feat: update releases\n* [`19cdf71`](https://github.com/siderolabs/pkgs/commit/19cdf71b84363929092b7ad8f2f4a7464abd98fc) feat: enable common sensors\n* [`acee18e`](https://github.com/siderolabs/pkgs/commit/acee18e8a3cce66a0df47c927cb7fe2b4bc81685) chore: bump kernel to 6.1.54\n* [`1d16fd2`](https://github.com/siderolabs/pkgs/commit/1d16fd2e22ce0a444df3df82f8c99a93347698c2) feat: add Chelsio support\n* [`4504f83`](https://github.com/siderolabs/pkgs/commit/4504f83f668776161af56853c3faec61edc4cdb6) chore: rename kconfig-hardened-check\n* [`847a9c3`](https://github.com/siderolabs/pkgs/commit/847a9c3bbea9a8c350dc0b2b84d473c2fd23feb2) chore: enable dm thin provisioning\n* [`1401505`](https://github.com/siderolabs/pkgs/commit/1401505a95eebb1ff9e2baac6239baf822b7576f) chore: drop `-pkgs` for upstream kernel modules\n* [`a62471d`](https://github.com/siderolabs/pkgs/commit/a62471daea9b4e6f1d7ed03c208a5603096037f3) feat: add binfmt_misc support\n* [`518c441`](https://github.com/siderolabs/pkgs/commit/518c441851a434e72939a3f27e8dfb64e3360bb6) feat: add gVNIC support\n* [`7d9e60e`](https://github.com/siderolabs/pkgs/commit/7d9e60e33fb602c81c61112f3557808a7064bb9a) feat: update Go to 1.21.1\n* [`d3d7d29`](https://github.com/siderolabs/pkgs/commit/d3d7d295221d951e8f8bb3935f04392f9efe0e1f) chore: bump deps\n* [`3b70656`](https://github.com/siderolabs/pkgs/commit/3b70656344332f553e0ae16e8bb39e1c3d92287a) chore: fix cacert perms\n* [`cca80b7`](https://github.com/siderolabs/pkgs/commit/cca80b7b939a2e5eb4769cc9e84d471bc4a6aec1) feat: update Linux to 6.1.46\n* [`2e1c0b9`](https://github.com/siderolabs/pkgs/commit/2e1c0b912b2bcde35f04d63fe6840d5e4dc74d60) fix: nonfree kmod pkg name\n* [`cff5beb`](https://github.com/siderolabs/pkgs/commit/cff5bebf2f23ab02591ca1d72a87208d94328ab4) feat: add btrfs support\n* [`7717b7e`](https://github.com/siderolabs/pkgs/commit/7717b7e01c4c7170c7a6dcfaf74513585f40b14c) chore: bump deps\n* [`2f19f18`](https://github.com/siderolabs/pkgs/commit/2f19f18d145096766dea3c592c28e62f08113b38) feat: update containerd to 1.6.23\n* [`30d4b74`](https://github.com/siderolabs/pkgs/commit/30d4b743f49396d62dc3ffadcf25511cf891e964) feat: update Go to 1.21\n* [`eda123d`](https://github.com/siderolabs/pkgs/commit/eda123ddbd7ea5682ffe62164c41daf8ba531416) feat: update runc to 1.1.9\n* [`30cd584`](https://github.com/siderolabs/pkgs/commit/30cd5846bd7a9cbf5e79c23b9e42a65a213276e2) chore: enable pushing of non-free packages\n* [`fb247b5`](https://github.com/siderolabs/pkgs/commit/fb247b5dcc465b6d77248b544465f582a0dd6e6c) chore: update kernel and microcode\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`9c09b00`](https://github.com/siderolabs/tools/commit/9c09b00ded2aa843a2142bc6659cdcade607c566) feat: update dependencies\n* [`35948af`](https://github.com/siderolabs/tools/commit/35948af8c3f955d02900c9dcd76f1c9e33502f52) feat: update Go to 1.21.3\n* [`09023c1`](https://github.com/siderolabs/tools/commit/09023c1d6eec46f43ccdba3bd703d0d3ac72220e) feat: update OpenSSL to 3.1.3\n* [`7fa8bb5`](https://github.com/siderolabs/tools/commit/7fa8bb542cb2984992e002ccceb0d655d336be96) feat: update releases\n* [`fa388de`](https://github.com/siderolabs/tools/commit/fa388de914cc3efd54a23ad2a650437e600fbb09) feat: update Go to 1.21.1\n* [`33fb4b3`](https://github.com/siderolabs/tools/commit/33fb4b35661b12fcf023ec96746e04281cc8c911) feat: update Go to 1.21\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go-v2/config**            v1.18.32 -> v1.19.0\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**  v1.13.7 -> v1.13.13\n* **github.com/aws/smithy-go**                       v1.14.0 -> v1.15.0\n* **github.com/beevik/ntp**                          v1.2.0 -> v1.3.0\n* **github.com/blang/semver/v4**                     v4.0.0 **_new_**\n* **github.com/containerd/cgroups/v3**               v3.0.2 **_new_**\n* **github.com/containerd/containerd**               v1.6.23 -> v1.7.7\n* **github.com/cosi-project/runtime**                v0.3.1 -> v0.3.13\n* **github.com/distribution/reference**              v0.5.0 **_new_**\n* **github.com/docker/docker**                       v24.0.5 -> v24.0.6\n* **github.com/foxboron/go-uefi**                    32187aa193d0 -> 18b9ba9cd4c3\n* **github.com/google/go-cmp**                       v0.5.9 -> v0.6.0\n* **github.com/google/go-containerregistry**         v0.15.2 -> v0.16.1\n* **github.com/google/uuid**                         v1.3.0 -> v1.3.1\n* **github.com/gopacket/gopacket**                   v1.1.1 -> 4769cf270e9e\n* **github.com/hetznercloud/hcloud-go/v2**           v2.0.0 -> v2.4.0\n* **github.com/insomniacslk/dhcp**                   0f9eb93a696c -> 6a2c8fbdcc1c\n* **github.com/jsimonetti/rtnetlink**                v1.3.4 -> v1.3.5\n* **github.com/opencontainers/runtime-spec**         1c3f411f0417 -> v1.1.0-rc.1\n* **github.com/prometheus/procfs**                   v0.11.1 -> v0.12.0\n* **github.com/rivo/tview**                          6cc0565babaf -> 6c844bdc5f7a\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.20 -> v1.0.0-beta.21\n* **github.com/siderolabs/extras**                   v1.5.0 -> v1.6.0-alpha.0-2-g6d48418\n* **github.com/siderolabs/gen**                      v0.4.5 -> v0.4.7\n* **github.com/siderolabs/go-kubernetes**            v0.2.2 -> v0.2.6\n* **github.com/siderolabs/pkgs**                     v1.5.0-6-g2f2c9cd -> v1.6.0-alpha.0-23-g2e892fd\n* **github.com/siderolabs/talos/pkg/machinery**      v1.5.0 -> v1.6.0-alpha.0\n* **github.com/siderolabs/tools**                    v1.5.0 -> v1.6.0-alpha.0-5-g9c09b00\n* **go.uber.org/zap**                                v1.25.0 -> v1.26.0\n* **go4.org/netipx**                                 ec4c8b891b28 -> 6213f710f925\n* **golang.org/x/net**                               v0.13.0 -> v0.17.0\n* **golang.org/x/sync**                              v0.3.0 -> v0.4.0\n* **golang.org/x/sys**                               v0.10.0 -> v0.13.0\n* **golang.org/x/term**                              v0.10.0 -> v0.13.0\n* **golang.org/x/text**                              v0.11.0 -> v0.13.0\n* **google.golang.org/grpc**                         v1.57.0 -> v1.58.3\n* **k8s.io/api**                                     v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/apimachinery**                            v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/apiserver**                               v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/client-go**                               v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/component-base**                          v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/cri-api**                                 v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/kubectl**                                 v0.28.0 -> v0.29.0-alpha.2\n* **k8s.io/kubelet**                                 v0.28.0 -> v0.29.0-alpha.2\n\nPrevious release can be found at [v1.5.0](https://github.com/siderolabs/talos/releases/tag/v1.5.0)\n\n## [Talos 1.6.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.6.0-alpha.0) (2023-08-24)\n\nWelcome to the v1.6.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### talosctl CLI\n\nThe command `images` deprecated in Talos 1.5 was removed, please use `talosctl images default` instead.\n\n\n### Component Updates\n\nLinux: 6.1.46\n\nTalos is built with Go 1.21.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Andrey Smirnov\n* Dmitriy Matrenichev\n* Artem Chernyshev\n* Christian Rolland\n* Enno Boland\n* Henry Sachs\n* Jared Davenport\n* Nico Berlee\n* Sascha Desch\n* Tim Jones\n* Utku Ozdemir\n\n### Changes\n<details><summary>48 commits</summary>\n<p>\n\n* [`74c07ed71`](https://github.com/siderolabs/talos/commit/74c07ed714d5751336e8745977caa3dca5060d7d) chore: update Go to 1.21\n* [`a28d72e9c`](https://github.com/siderolabs/talos/commit/a28d72e9c262bd8fb84959ede952542a6e95d0be) fix: ova contents to be named `disk.*`\n* [`c0ea4d7ba`](https://github.com/siderolabs/talos/commit/c0ea4d7ba504dd8e1558f11e0cddd41dbf8bc720) fix: properly calculate overal of node address with subnet filters\n* [`d6b2719e2`](https://github.com/siderolabs/talos/commit/d6b2719e2e824cf5df9314523e3a4138b404e615) chore: drone: move extensions step to a function\n* [`9608ef56d`](https://github.com/siderolabs/talos/commit/9608ef56dc602636da1449ff05d237e0e20e5154) chore: allow bridge traffic with DHCP broadcast traffic\n* [`c99316457`](https://github.com/siderolabs/talos/commit/c993164576453fd03eb8fc517badd7de8004f4ad) docs: fix the installing system extensions doc\n* [`833895940`](https://github.com/siderolabs/talos/commit/833895940b173e247816751ca7287ccde7a36d03) chore: add tests for zfs extension\n* [`cb468c41c`](https://github.com/siderolabs/talos/commit/cb468c41cbbec6cd5f28c3cd3457aa4a30b81d4c) fix: copy proper modules to arm64 squashfs\n* [`ea0d6e8c6`](https://github.com/siderolabs/talos/commit/ea0d6e8c6a8ce8cd516bc05c99534241dff60b9f) fix: prevent dashboard crashes when process info is not available\n* [`e9077a6fb`](https://github.com/siderolabs/talos/commit/e9077a6fb9db5bcadea342200f057c1dc6ffb9af) feat: filter the hostname to produce nodename\n* [`dc8361c1d`](https://github.com/siderolabs/talos/commit/dc8361c1d524e3a52dfa18ee1b539fb81a02ef8d) fix: properly GC images supplied with both tag and digest\n* [`ccfa8de11`](https://github.com/siderolabs/talos/commit/ccfa8de1174b4e5d59c2f92b44d8dd65235b590a) fix: automatically change `rpi_4` board on upgrade\n* [`b56e8b7d9`](https://github.com/siderolabs/talos/commit/b56e8b7d9babe9a963b1fc9a2f41882d08fbafe3) fix: support 'List' type manifests\n* [`574d48e54`](https://github.com/siderolabs/talos/commit/574d48e54020b02f74c2aeadca1c10499bf967b0) fix: use image digest when starting a container\n* [`175747cea`](https://github.com/siderolabs/talos/commit/175747cea58d73f8532c114b7754668d24ab9c92) fix: ntp query error with bare IPv6 address\n* [`c8b507fb2`](https://github.com/siderolabs/talos/commit/c8b507fb26ca30cf0aa98c8cf669a2a03583fc1c) docs: fix kubeprism typo\n* [`0cdcb2e0e`](https://github.com/siderolabs/talos/commit/0cdcb2e0e8131510aab654211d3622fb17f8375e) docs: restructure docs for nvidia drivers for v1.4\n* [`676db9768`](https://github.com/siderolabs/talos/commit/676db9768433027ebc6ff22a0414692ccec2ccf4) docs: fork docs for Talos 1.6\n* [`92ad18c18`](https://github.com/siderolabs/talos/commit/92ad18c18fae5ac073cdd98d24c5aeb5edb4091a) fix: write correct capacity to the ovf\n* [`6b0373ebe`](https://github.com/siderolabs/talos/commit/6b0373ebef88600571ec54c189fd6ea3b0c777e8) chore: move bash tests to integration\n* [`52b3d8d37`](https://github.com/siderolabs/talos/commit/52b3d8d37cd1cf4eb3aa046781f105a1c39e69a0) docs: make Talos 1.5 documentation the default one\n* [`dc873df9b`](https://github.com/siderolabs/talos/commit/dc873df9b4cf169b4f7789690b80ac1e02b27d57) chore: fix the filenames of openstack images\n* [`b5c0e7b24`](https://github.com/siderolabs/talos/commit/b5c0e7b24cbd1546304ca33328b89e022e6e0675) docs: update nvidia docs\n* [`9606e871e`](https://github.com/siderolabs/talos/commit/9606e871e422b72aaef39ae03e334119602b8f31) docs: update Jiva Pod Security Policy\n* [`a86ed4362`](https://github.com/siderolabs/talos/commit/a86ed4362c009c389766ecd4bfcbc0ade999bb2e) chore: update Kubernetes Go modules to 0.28.0\n* [`97b4e3e91`](https://github.com/siderolabs/talos/commit/97b4e3e91cb4a238a8f81c8ce2983c0033a355cb) feat: update Kubernetes to 1.28.0\n* [`79ca1a3df`](https://github.com/siderolabs/talos/commit/79ca1a3dfb485fc5180bda38ab58a2d4c595a6aa) feat: e2e-aws using tf code\n* [`bf3a5e011`](https://github.com/siderolabs/talos/commit/bf3a5e01190e1cf80769343cf94af4c1bfb80318) chore: add version compatibility for Talos 1.6\n* [`969e8097c`](https://github.com/siderolabs/talos/commit/969e8097ce062197c9011d206cdbc7de1dc87df5) feat: update Kubernetes to 1.28.0-rc.1\n* [`ca41b611e`](https://github.com/siderolabs/talos/commit/ca41b611e97a0ef5020f01011267b82a155d136a) chore: drone jsonnet cleanup\n* [`bc198e98e`](https://github.com/siderolabs/talos/commit/bc198e98ef6dd03e07d75ab2eb8b944d10ad3739) docs: retain cilium autoMount pending upstream hostPath fix\n* [`86c94eff8`](https://github.com/siderolabs/talos/commit/86c94eff8d9e1abec11039f79dc6a9b35d46c7f3) refactor: docgen and config examples\n* [`ee6d639f6`](https://github.com/siderolabs/talos/commit/ee6d639f6c374cf8e1843dd3720047fea7dd3325) fix: match routes on the priority properly\n* [`bff0d8f32`](https://github.com/siderolabs/talos/commit/bff0d8f32c55d0cec9aed67592a6ccad8e5efee8) chore: fix dependencies in the release pipeline\n* [`e1b288679`](https://github.com/siderolabs/talos/commit/e1b288679e922fa0e255273adf4b7a1226518424) refactor: compile regex in validation method on the first use\n* [`daa4c185a`](https://github.com/siderolabs/talos/commit/daa4c185ae9a6318d779f45c730ac695e14ca6c7) docs: add what's new and documentation for Talos 1.5\n* [`c4a1ca8d6`](https://github.com/siderolabs/talos/commit/c4a1ca8d61fcb1338da1ca223b9b4349a6af76e2) chore: remove <-errCh where possible in grpc methods\n* [`e0f383598`](https://github.com/siderolabs/talos/commit/e0f383598e2f285c04264e9a3787fcdcd56add85) chore: clean up the output of the `imager`\n* [`fb536af4d`](https://github.com/siderolabs/talos/commit/fb536af4d1804b8b802a4211739ac410fd34bb93) chore: optimize memory usage of `tcell` library on init\n* [`7c86a365e`](https://github.com/siderolabs/talos/commit/7c86a365e2691065e5e06a4789621bc9f43f3c4b) chore: publish systemd-boot and systemd-stub assets\n* [`7d688ccfe`](https://github.com/siderolabs/talos/commit/7d688ccfeb00ca46999b98512e49ac94f17d2693) fix: make encryption config provider default to `luks2` if not set\n* [`80238a05a`](https://github.com/siderolabs/talos/commit/80238a05a6f83b2d8bf3b04816d2b0a5c499eca8) chore: unify semver under `github.com/blang/semver/v4`\n* [`0f1920bdd`](https://github.com/siderolabs/talos/commit/0f1920bdda5b7f2e2291e75d14453cf81a1b6cd6) chore: provide a resource to peek into Linux clock adjustments\n* [`4eab3017b`](https://github.com/siderolabs/talos/commit/4eab3017b036d3229a6fa7dc9612050d1499e2b6) fix: calculate log2i properly\n* [`bcf284530`](https://github.com/siderolabs/talos/commit/bcf2845307ad2c4395967cbb8e756d6a0d8caf2c) fix: update providerid prefix for aws\n* [`ac2aff5cc`](https://github.com/siderolabs/talos/commit/ac2aff5cc5e5234fecf1f49b0f5d583c633aafa4) fix: fix azure portion of cloud uploader\n* [`793dcedc9`](https://github.com/siderolabs/talos/commit/793dcedc957389c9d91da62517a43968bd99b09d) fix: fast-wipe the system disk on talosctl reset\n* [`76fa45afb`](https://github.com/siderolabs/talos/commit/76fa45afbac5d212faa534047255c0256e78d08a) docs: update cilium instructions\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>8 commits</summary>\n<p>\n\n* [`2e1c0b9`](https://github.com/siderolabs/pkgs/commit/2e1c0b912b2bcde35f04d63fe6840d5e4dc74d60) fix: nonfree kmod pkg name\n* [`cff5beb`](https://github.com/siderolabs/pkgs/commit/cff5bebf2f23ab02591ca1d72a87208d94328ab4) feat: add btrfs support\n* [`7717b7e`](https://github.com/siderolabs/pkgs/commit/7717b7e01c4c7170c7a6dcfaf74513585f40b14c) chore: bump deps\n* [`2f19f18`](https://github.com/siderolabs/pkgs/commit/2f19f18d145096766dea3c592c28e62f08113b38) feat: update containerd to 1.6.23\n* [`30d4b74`](https://github.com/siderolabs/pkgs/commit/30d4b743f49396d62dc3ffadcf25511cf891e964) feat: update Go to 1.21\n* [`eda123d`](https://github.com/siderolabs/pkgs/commit/eda123ddbd7ea5682ffe62164c41daf8ba531416) feat: update runc to 1.1.9\n* [`30cd584`](https://github.com/siderolabs/pkgs/commit/30cd5846bd7a9cbf5e79c23b9e42a65a213276e2) chore: enable pushing of non-free packages\n* [`fb247b5`](https://github.com/siderolabs/pkgs/commit/fb247b5dcc465b6d77248b544465f582a0dd6e6c) chore: update kernel and microcode\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`33fb4b3`](https://github.com/siderolabs/tools/commit/33fb4b35661b12fcf023ec96746e04281cc8c911) feat: update Go to 1.21\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go-v2/config**            v1.18.32 -> v1.18.36\n* **github.com/aws/aws-sdk-go-v2/feature/ec2/imds**  v1.13.7 -> v1.13.11\n* **github.com/aws/smithy-go**                       v1.14.0 -> v1.14.2\n* **github.com/beevik/ntp**                          v1.2.0 -> v1.3.0\n* **github.com/blang/semver/v4**                     v4.0.0 **_new_**\n* **github.com/containerd/containerd**               v1.6.23 -> v1.6.22\n* **github.com/foxboron/go-uefi**                    32187aa193d0 -> 18b9ba9cd4c3\n* **github.com/google/go-containerregistry**         v0.15.2 -> v0.16.1\n* **github.com/google/uuid**                         v1.3.0 -> v1.3.1\n* **github.com/hetznercloud/hcloud-go/v2**           v2.0.0 -> v2.1.1\n* **github.com/insomniacslk/dhcp**                   0f9eb93a696c -> b3ca2534940d\n* **github.com/jsimonetti/rtnetlink**                v1.3.4 -> v1.3.5\n* **github.com/rivo/tview**                          6cc0565babaf -> ccc2c8119703\n* **github.com/siderolabs/pkgs**                     v1.5.0-6-g2f2c9cd -> v1.6.0-alpha.0-7-g2e1c0b9\n* **github.com/siderolabs/talos/pkg/machinery**      v1.5.0 -> v1.5.0-alpha.3\n* **github.com/siderolabs/tools**                    v1.5.0 -> v1.6.0-alpha.0\n* **golang.org/x/net**                               v0.13.0 -> v0.14.0\n* **golang.org/x/sys**                               v0.10.0 -> v0.11.0\n* **golang.org/x/term**                              v0.10.0 -> v0.11.0\n* **golang.org/x/text**                              v0.11.0 -> v0.12.0\n\nPrevious release can be found at [v1.5.0](https://github.com/siderolabs/talos/releases/tag/v1.5.0)\n\n## [Talos 1.5.0-alpha.3](https://github.com/siderolabs/talos/releases/tag/v1.5.0-alpha.3) (2023-07-25)\n\nWelcome to the v1.5.0-alpha.3 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Extension Services\n\nTalos now supports setting `environmentFile` for an extension service container spec. Refer: https://www.talos.dev/v1.5/advanced/extension-services/#container\nThe extension waits for the file to be present before starting the service.\n\n\n### Predictable Network Interface Names\n\nStarting with version Talos 1.5, network interfaces are renamed to [predictable names](https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/)\nsame way as `systemd` does that in other Linux distributions.\n\nThe naming schema `enx78e7d1ea46da` (based on MAC addresses) is enabled by default, the order of interface naming decisions is:\n\n* firmware/BIOS provided index numbers for on-board devices (example: `eno1`)\n* firmware/BIOS provided PCI Express hotplug slot index numbers (example: `ens1`)\n* physical/geographical location of the connector of the hardware (example: `enp2s0`)\n* interfaces's MAC address (example: `enx78e7d1ea46da`)\n\nThe predictable network interface names features can be disabled by specifying `net.ifnames=0` in the kernel command line.\nTalos automatically adds the `net.ifnames=0` kernel argument when upgrading from Talos versions before 1.5.\n\nThis change doesn't affect \"cloud\" platforms, like AWS, as Talos automatically adds `net.ifnames=0` to the kernel command line.\n\n\n### Network KMS Disk Encryption\n\nTalos now supports new type of encryption keys which are sealed/unsealed with an external KMS server:\n\n```\nsystemDiskEncryption:\n  ephemeral:\n    keys:\n      - kms:\n          endpoint: https://1.2.3.4:443\n        slot: 0\n```\ngRPC API definitions and a simple reference implementation of the KMS server can be found in this\n[repository](https://github.com/siderolabs/kms-client/blob/main/cmd/kms-server/main.go).\n\n\n### KubePrism - Kubernetes API Server In-Cluster Load Balancer\n\nTalos now supports configuring the KubePrism - Kubernetes API Server in-cluster load balancer with machine config\n`features.kubePrism.port` and `features.kubePrism.enabled` fields.\n\nIf enabled, KubePrism binds to `localhost` and runs on the same port on every machine in the cluster.\nThe default value for KubePrism endpoint is https://localhost:7445.\n\nThe KubePrism is used by the `kubelet`, `kube-scheduler`, `kube-controller-manager`\nand `kube-proxy` by default and can be passed to the CNIs like Cilium and Calico.\n\nThe KubePrism provides access to the Kubernetes API endpoint even if the external loadbalancer\nis not healthy, provided that the worker nodes can reach to the controlplane machine addresses directly.\n\n\n### Machine Config option `.machine.install.bootloader`\n\nThe `.machine.install.bootloader` option in the machine config is deprecated and will be removed in Talos 1.6.\nThis was a no-op for a long time. The bootloader is always installed.\n\n\n### XFS Quota\n\nTalos 1.5+ enables XFS project quota support by default, also enabling by default\nkubelet feature gate `LocalStorageCapacityIsolationFSQuotaMonitoring` to use xfs quotas\nto monitor volume usage instead of `du`.\n\nThis feature is controlled by the `.machine.features.diskQuotaSupport` field in the machine config,\nit is set to true for new clusters.\n\nWhen upgrading from a previous version, the feature can be enabled by setting the field to true.\nOn the first mount of a volume, the quota information will be recalculated, which may take some time.\n\n\n### RDMA/RoCE support\n\nTalos no longer loads by default `rdma_rxe` Linux driver, which is required for RoCE support.\nIf the driver is required, it can be enabled by specifying `rdma_rxe` in the `.machine.kernel.modules` field in the machine config.\n\n\n### SecureBoot\n\nTalos now supports generating a custom iso that can be used with SecureBoot. Key generation and enrolling has to be done manually.\n\n\n### `talosctl image` Command\n\nA new set of commands was introduced to manage container images in the CRI:\n\n* `talosctl image list` shows list of available images\n* `talosctl image pull` allows to pre-pull an image into the CRI\n\nBoth new commands accept `--namespace` flag with two possible values:\n\n* `cri` (default): images managed by the CRI (Kubernetes workloads)\n* `system`: images managed by Talos (`etcd` and `kubelet`)\n```\n\n\n### `talosctl images` Command\n\nThe command `talosctl images` was renamed to `talosctl image default`.\n\nThe backward-compatible alias is kept in Talos 1.5, but it will be dropped in Talos 1.6.\n\n\n### TPM Disk Encryption\n\nTalos now supports encrypting STATE/EPHEMERAL with keys bound to a TPM device. The TPM device must be TPM2.0 compatible.\nThis is ideally supported when booting with new Talos SecureBoot UKI ISOs/Metal images. This feature would still work if SecureBoot\nis not enabled for UKI images, but not recommended since there is no way to verify the trust of the bootloader.\n\nExample machine config:\n\n```\nsystemDiskEncryption:\n  ephemeral:\n    keys:\n      - slot: 0\n        tpm: {}\n  state:\n    keys:\n      - slot: 0\n        tpm: {}\n```\n\n\n### Component Updates\n\n* Linux: 6.1.39\n* containerd: 1.6.21\n* runc: 1.1.8\n* etcd: 3.5.9\n* Kubernetes: 1.28.0-beta.0\n* Flannel: 0.22.0\n\nTalos is built with Go 1.20.6.\n\n\n### `talosctl upgrade-k8s` Image Pre-pulling\n\nThe command `talosctl upgrade-k8s` now by default pre-pulls images for Kubernetes controlplane components\nand kubelet. This provides an early check for missing images, and minimizes downtime during Kubernetes\nrolling component update.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Artem Chernyshev\n* Christian Rolland\n* Steve Francis\n* Nanfei Chen\n* Nico Berlee\n* Spencer Smith\n* Alex Corcoles\n* Alex Corcoles\n* Alex Lubbock\n* Andrei Kvapil\n* Artem Chernyshev\n* Budiman Jojo\n* Chris Hoffman\n* DJAlPee\n* Dennis Marttinen\n* Eirik Askheim\n* Florian Klink\n* Henk Kraal\n* Igor Rzegocki\n* James Callahan\n* LukasAuerbeck\n* Markus Reiter\n* Michael A. Davis\n* Michael Fornaro\n* Niklas Wik\n* Piotr Maksymiuk\n* Ricky Sadowski\n* Roee Klinger\n* Sacha Trémoureux\n* Scott Cariss\n* Serge Logvinov\n* Thomas Lemarchand\n* Thomas Perronin\n* Tim Jones\n* Victor Bajada\n* Walt Chen\n* bdronneau\n\n### Changes\n<details><summary>194 commits</summary>\n<p>\n\n* [`d2f64af86`](https://github.com/siderolabs/talos/commit/d2f64af863e14b1d111bbeeaa6d9077aadaf6085) chore: disable cloud-images, pull in new kernel and gre module\n* [`8edce4906`](https://github.com/siderolabs/talos/commit/8edce490639c213cd8c45989a5a87e3388179d37) docs: improve proxmox install guide\n* [`c783458be`](https://github.com/siderolabs/talos/commit/c783458be0c90b779bcc2fe3c10e37fd3dfe01db) docs: typo dhcp -> dhcp\n* [`003cbd161`](https://github.com/siderolabs/talos/commit/003cbd161196375edc8ee5033be62014eb88202e) docs: warn about secretboxEncryptionSecret in kubeadm migration guide\n* [`786e86f5b`](https://github.com/siderolabs/talos/commit/786e86f5b8219ef37c5c6480d97c440cbbd53e30) refactor: rewrite the way Talos acquires the machine configuration\n* [`5e13cafe5`](https://github.com/siderolabs/talos/commit/5e13cafe5b506039fdd652372b1d1f71a1c1c10b) feat: enforce kernel lockdown for UKI\n* [`4d96d642f`](https://github.com/siderolabs/talos/commit/4d96d642fd9c462db2c084afee1428009d454a9e) feat: update default Kubernetes version to 1.28.0-beta.0\n* [`170a73e16`](https://github.com/siderolabs/talos/commit/170a73e161eacb0e21ce95e7a7e406533552bf1d) chore: support creating qemu guest socket\n* [`59ac38a6b`](https://github.com/siderolabs/talos/commit/59ac38a6bffe943fa634b124b8ec2a907f95a006) docs: add docs for installing azure ccm and csi\n* [`6288cd970`](https://github.com/siderolabs/talos/commit/6288cd970e83f18e8b1cadca777deabe3ff9fc91) release(v1.5.0-alpha.2): prepare release\n* [`60c304126`](https://github.com/siderolabs/talos/commit/60c304126fce95fd4995c416e7757f85505b90fb) chore: bump dependencies\n* [`9ef4e5efc`](https://github.com/siderolabs/talos/commit/9ef4e5efca4b537a550a5e902fc2479ebb5e53e3) fix: log explicitly when kubelet has no nodeIP match\n* [`6b39c6a4d`](https://github.com/siderolabs/talos/commit/6b39c6a4d326752f92d98388bbb418f2e50d3ddb) fix: enable compression and bump gRPC max msg size\n* [`2f2eca861`](https://github.com/siderolabs/talos/commit/2f2eca86175fe98b3bf491f38ff907599333b139) chore: basic support for shutdown/poweroff flags\n* [`b84277d7d`](https://github.com/siderolabs/talos/commit/b84277d7dc50b196b7cd27e7f2ceff6bf8f58a8d) docs: fix wrong capability name\n* [`59d7d9344`](https://github.com/siderolabs/talos/commit/59d7d9344b27529af420ec31c7b599027cda044f) chore: use machined for `shutdown`, `poweroff`\n* [`2439bfb71`](https://github.com/siderolabs/talos/commit/2439bfb719d9f50107cee500d03c90bd50649e05) chore: explicitly add timestamps to machined logs\n* [`14966e718`](https://github.com/siderolabs/talos/commit/14966e718a07906ff389ecdda063fd16b22baab9) fix: skip over tpm2 1.2 devices\n* [`6716e7bc0`](https://github.com/siderolabs/talos/commit/6716e7bc0ba6da31b8bc19aa4bd5edb7749b39a1) docs: update cilium documentation about KubePrism usage\n* [`166d75fe8`](https://github.com/siderolabs/talos/commit/166d75fe888d334349f57dcf405b6867ca5305e2) fix: tpm2 encrypt/decrypt flow\n* [`130518de7`](https://github.com/siderolabs/talos/commit/130518de71ae96cdf7d733a35e4c306940e1b845) chore: change missing renames of KubePrism\n* [`5f34f5b41`](https://github.com/siderolabs/talos/commit/5f34f5b41f03d6d455d7b843084d2951c365a7ee) chore: rename api load balancer to KubePrism\n* [`c8b7095c0`](https://github.com/siderolabs/talos/commit/c8b7095c01f597cd8b41964b42aa7e35c85ae307) refactor: use tpm2 library to calculate policy hash\n* [`078aac92e`](https://github.com/siderolabs/talos/commit/078aac92ee30c9666235219d4623b82d66362d4d) chore: bump deps\n* [`53873b844`](https://github.com/siderolabs/talos/commit/53873b8444acaa97d85c50caec625b9dbfdfef93) refactor: move ukify into Talos code\n* [`d5f6fb9ff`](https://github.com/siderolabs/talos/commit/d5f6fb9ff2980df03365719d9e2690cb5ac788af) chore: add vendor info\n* [`79365d9ba`](https://github.com/siderolabs/talos/commit/79365d9bacf0e8a6660cdc6b7172c79edf5f3ba3) feat: tpm2 based disk encryption\n* [`06369e819`](https://github.com/siderolabs/talos/commit/06369e8195e76f96d232d077efb2bfb059b7aa96) fix: retry CRI pod removal, fix upgrade flow in the tests\n* [`d32dd3a82`](https://github.com/siderolabs/talos/commit/d32dd3a820b07d58ca89c4226c986d87ff0e2b65) chore: update Go to 1.20.6\n* [`8017afb10`](https://github.com/siderolabs/talos/commit/8017afb107b901a8785bccaac65d63f34e506568) feat: implement CRI image management and pre-pull on K8s upgrade\n* [`1c2f19b36`](https://github.com/siderolabs/talos/commit/1c2f19b367af8b04fc49174540e5b141f4b34156) feat: update Kubernetes to 1.28.0-alpha.4\n* [`94e9891c1`](https://github.com/siderolabs/talos/commit/94e9891c1bb44a1e7c285b4ccf1fad59ea05aa62) chore: bump sd-boot to v254-rc1\n* [`936111ce0`](https://github.com/siderolabs/talos/commit/936111ce062d23ed11b30ea35585c0519260f9c5) fix: properly set up tls for KMS endpoint\n* [`cb226eec4`](https://github.com/siderolabs/talos/commit/cb226eec46b59372c684c3946e0ba0910066573d) fix: rewrite encryption system information flow\n* [`3206db528`](https://github.com/siderolabs/talos/commit/3206db52895416d1eb936caa4e953312b34b8549) feat: drop tpm simulator for ukify measure\n* [`bd4f89f63`](https://github.com/siderolabs/talos/commit/bd4f89f6338423a79b7ce89bda1bd6704caaae59) fix: disable dashboard on Azure, GCP and Scaleway\n* [`bdb96189f`](https://github.com/siderolabs/talos/commit/bdb96189faadc48e93146f9fd7b03e006bf1dd75) refactor: make maintenance service controller-based\n* [`d23d04de2`](https://github.com/siderolabs/talos/commit/d23d04de2a5dee30ccf21efe767daf229de78bdb) feat: seed the kernel random pool from the TPM\n* [`c81ce8cfb`](https://github.com/siderolabs/talos/commit/c81ce8cfb0bc7df66ffd1e1819b64dad6357d890) feat: support controlplane resources configuration\n* [`74de562b2`](https://github.com/siderolabs/talos/commit/74de562b29c748fda3140871ea3fab99698341ef) fix: mount hugepages with nosuid + nodev\n* [`ce63abb21`](https://github.com/siderolabs/talos/commit/ce63abb219a2fd4a9d3fdd93a13c343af123efc2) feat: add KMS assisted encryption key handler\n* [`dafbe9deb`](https://github.com/siderolabs/talos/commit/dafbe9debdee2b015ed574ac4f5f722bce997b31) chore: optimize dockerfile instructions\n* [`a4289e870`](https://github.com/siderolabs/talos/commit/a4289e8703d9f9e52b739b19b5b38e30a75a1454) chore: fix CLI docs generation stability\n* [`2fec8388f`](https://github.com/siderolabs/talos/commit/2fec8388fc2fe3058b7b6f141ce9eae2c6a8268f) chore: bump dependencies\n* [`c1b4262dd`](https://github.com/siderolabs/talos/commit/c1b4262dd60f6cbea6d46a8d0433499bf6365b36) docs: split simple and more complex getting started guides\n* [`c9a9f9561`](https://github.com/siderolabs/talos/commit/c9a9f95611e38cf5c298f0d9fb0890a9bc0f8b98) refactor: extract secure boot certificate generation\n* [`6be5a13d5`](https://github.com/siderolabs/talos/commit/6be5a13d5d8341c58d0d2fe75c49ba1de9bf7316) feat: implement machine config documents for event and log streaming\n* [`e241be85b`](https://github.com/siderolabs/talos/commit/e241be85ba748163268eaeed2a88c8e295f84b28) fix: properly handle YAML comment stripping for multi-doc\n* [`c02ada7d9`](https://github.com/siderolabs/talos/commit/c02ada7d952255bffe67b3c84f1f832253e1a3b5) fix: capabilities including `ALL` should be uppercase\n* [`cbdf96d46`](https://github.com/siderolabs/talos/commit/cbdf96d461ec0cf8929c2c76614081ef042dda31) feat: support environment file for extensions\n* [`35d6adcb9`](https://github.com/siderolabs/talos/commit/35d6adcb9ad7e9420a5bcdfcf3378a05c0b65d46) fix: provide stashed META values before installation\n* [`258f07449`](https://github.com/siderolabs/talos/commit/258f07449050d69c369fdc71ac613a1a225807bf) fix: ukify cert generation\n* [`bf3febb7e`](https://github.com/siderolabs/talos/commit/bf3febb7e2bf3ebf1bd66ee088f3885a178c953c) fix: refine OVMF search paths\n* [`fbebc17f8`](https://github.com/siderolabs/talos/commit/fbebc17f8be7a3ca6c45c3c84d306e52c47d441d) fix: disable LVM backups/archive\n* [`e5306ef26`](https://github.com/siderolabs/talos/commit/e5306ef2637dd2eb7464691b55159a43933c7419) chore: format and cleanup test scripts\n* [`bc371ecfd`](https://github.com/siderolabs/talos/commit/bc371ecfdafe51f8cf34461caf9e6f51c0a93108) chore: add `/sbin/shutdown`\n* [`0d313b973`](https://github.com/siderolabs/talos/commit/0d313b973367906b2fd4bcad4b2def79344dbd67) feat: add `reboot-mode` flag to `talosctl upgrade`\n* [`7ce87f20c`](https://github.com/siderolabs/talos/commit/7ce87f20c39c615f4d23a3be23780a36008dcb19) fix: compare only basename of `os.Args[0]` in machined\n* [`53389b1e7`](https://github.com/siderolabs/talos/commit/53389b1e724751e28046167b44f05c6ecf06f184) feat: auto-enroll secure boot keys\n* [`d77f0bc7b`](https://github.com/siderolabs/talos/commit/d77f0bc7bbe01b7fc8efa21a7c57d73ecb94a01f) docs: fix broken link to powershell module\n* [`e1b150a11`](https://github.com/siderolabs/talos/commit/e1b150a11014ddd0c60585d320dd7cd556cf2a0c) release(v1.5.0-alpha.1): prepare release\n* [`8daf432b2`](https://github.com/siderolabs/talos/commit/8daf432b2957a8f9d5c59970cf68e7e8414038f5) chore: bump deps\n* [`e3f3f5794`](https://github.com/siderolabs/talos/commit/e3f3f5794d276433748d0e677ed8476a54f8a98e) feat: implement revert for sd-boot\n* [`d8b0903d7`](https://github.com/siderolabs/talos/commit/d8b0903d70181afc901d8ddb71bdfa964d4df2cd) docs: vagrant setup document fix\n* [`fe0f46980`](https://github.com/siderolabs/talos/commit/fe0f46980f348852907218d6f49581efe4b45d49) feat: implement secure boot from disk\n* [`445f5ad54`](https://github.com/siderolabs/talos/commit/445f5ad5426b125e29d86ff096695399bd01eb32) feat: support API server load balancer\n* [`19bc223de`](https://github.com/siderolabs/talos/commit/19bc223de8ad878bffe539bda617d5f861af3cfe) refactor: bootloader interface, labels\n* [`665702ddd`](https://github.com/siderolabs/talos/commit/665702ddd351e902336e6ab81108ea94d61db5c1) chore: fix cilium e2e tests\n* [`71a548d18`](https://github.com/siderolabs/talos/commit/71a548d18013ee16394921759e819b0fabb43758) chore: generic boootloader implementation\n* [`e9dbc9311`](https://github.com/siderolabs/talos/commit/e9dbc9311bcbbbcaab2c7eb7f7128013194c234a) test: bump versions for upgrade tests\n* [`0a99965ef`](https://github.com/siderolabs/talos/commit/0a99965efbdd5dc0d927eb2cbae209dc143c9541) refactor: replace `uncordonNode` with controllers\n* [`e858bca3a`](https://github.com/siderolabs/talos/commit/e858bca3a2f75d5035710d52229c8142f3eb6982) test: fix cilium integration tests\n* [`455328d05`](https://github.com/siderolabs/talos/commit/455328d058fba3a5a8b3358820a02e2b4fabad95) fix: allow time skew for generated kubeconfig\n* [`3ae05648a`](https://github.com/siderolabs/talos/commit/3ae05648ae0a2f79bebd678f85d63d4e5dafde0a) fix: usage of custom kernels\n* [`0797b0d16`](https://github.com/siderolabs/talos/commit/0797b0d16808d115649a9e0e37b355bbbc2a30b5) chore: add a pipeline to test cloud-images step without a release\n* [`e5a36268b`](https://github.com/siderolabs/talos/commit/e5a36268b63e588ea6cd2439bf0de356ee07d752) docs: include `allowSchedulingOnControlPlanes` on `talosctl gen config` output\n* [`c74d93728`](https://github.com/siderolabs/talos/commit/c74d937280c2ec707936a72d07dc2a5dd252c5d2) chore: bump github.com/cosi-project/runtime\n* [`dbaf5c699`](https://github.com/siderolabs/talos/commit/dbaf5c69978fd1d22737385ddd096798d408254c) refactor: task `labelControlPlane` into controllers\n* [`1865a0c29`](https://github.com/siderolabs/talos/commit/1865a0c29663a1a78db7ef6e901d450d67a3cbe1) chore: modify some usages that are not recommended\n* [`3816318b9`](https://github.com/siderolabs/talos/commit/3816318b9e2e205da0c949c0ec59a087decd0b78) chore: wrap config.Provider in atomic wrapper\n* [`d04cf1978`](https://github.com/siderolabs/talos/commit/d04cf19788df20c802eadb9678570a4f15d339b2) chore: clean up unnecessary self assignment\n* [`a34a94898`](https://github.com/siderolabs/talos/commit/a34a948985fed7c3054c4342c48e0e0620569625) fix: copy missing modules.* files\n* [`f5e3272fc`](https://github.com/siderolabs/talos/commit/f5e3272fce641a878eefa66437d28d3ed9917ab6) refactor: task 'updateBootLoader' as controller\n* [`e7be6ee7c`](https://github.com/siderolabs/talos/commit/e7be6ee7c3636eebd557d93e440e9749c8093360) refactor: make event log streaming fully reactive\n* [`aef2192a6`](https://github.com/siderolabs/talos/commit/aef2192a6584e7934086eae0caab6faba52a8ac1) chore: use fixed module list\n* [`c719aa231`](https://github.com/siderolabs/talos/commit/c719aa2316bffa3b614d27d630ea3d8731684f4e) fix: allow http:// for discovery service URL\n* [`39134d8d5`](https://github.com/siderolabs/talos/commit/39134d8d5304cec5e1a1c5fe23f62ed957241213) chore: fix cron pipeline\n* [`a61dcdbbd`](https://github.com/siderolabs/talos/commit/a61dcdbbd5c917b49c810108ff96854ad51269b1) fix: don't load RDMA over Ethernet driver by default\n* [`aac441f61`](https://github.com/siderolabs/talos/commit/aac441f618ac60f2298d9e17a2044916f7da9d69) chore: update Go to 1.20.5, bump dependencies\n* [`1c0c7933d`](https://github.com/siderolabs/talos/commit/1c0c7933dfef23544e2fb0fc04c4c5ad7d5b5d9b) chore: cleanup partition code\n* [`31b988281`](https://github.com/siderolabs/talos/commit/31b988281efb9d0c66975bbfc20b893ad32c161d) docs: add some words about certifcates\n* [`e912c0dfc`](https://github.com/siderolabs/talos/commit/e912c0dfcf515c5a6c852f4b935c9b48e61b13f1) chore: use go-blockdevice for zeroing partitions\n* [`e6dde8ffc`](https://github.com/siderolabs/talos/commit/e6dde8ffc50e435a42d11eb96cf6aea2cf3520ca) feat: add network chaos to qemu development environment\n* [`47986cb79`](https://github.com/siderolabs/talos/commit/47986cb79eb30c6e9c0d091ee37b2b1c2f20885c) chore: unify kexec phase\n* [`3a865370f`](https://github.com/siderolabs/talos/commit/3a865370f5152243e08a69626de023f924e22689) feat: qemu secureboot\n* [`5dab45e86`](https://github.com/siderolabs/talos/commit/5dab45e86917837b0991a62ab94a7b96b3ef777e) refactor: allow kmsg log streaming to be reconfigured on the fly\n* [`8a02ecd4c`](https://github.com/siderolabs/talos/commit/8a02ecd4cb97bcaafe5761d464fec8a4e44b672f) chore: add endpoints balancer controller\n* [`423a31ac9`](https://github.com/siderolabs/talos/commit/423a31ac9d8f28c2bcf00794bacf5446e43fc0b7) chore: deprectae `bootloader` installer option\n* [`cdfece7d6`](https://github.com/siderolabs/talos/commit/cdfece7d64a9269afcc213f8d604d0b7e525cb8a) chore: optimize image compression\n* [`bfc341937`](https://github.com/siderolabs/talos/commit/bfc34193762cb309ef2230f4d79673c4a56f4db5) chore: add default console args\n* [`2749aeeda`](https://github.com/siderolabs/talos/commit/2749aeeda0451b286369d911696070e2cf4359e9) feat: add support for multi-doc strategic merge patching\n* [`3f68485e4`](https://github.com/siderolabs/talos/commit/3f68485e44800a0c50b5855531ec10507e7d0df9) feat: add uki iso generation\n* [`bab484a40`](https://github.com/siderolabs/talos/commit/bab484a405cb598d1c5f35f7602c2ac27e6efa97) feat: use stable network interface names\n* [`196dfb99b`](https://github.com/siderolabs/talos/commit/196dfb99b0329d5c52fd7089e62fbfa1b09df3c6) fix: do not probe kernel args in dashboard if not needed\n* [`8c071b579`](https://github.com/siderolabs/talos/commit/8c071b5796db05ecb17e46295eb2140827a58ca8) fix: skip DHCP RENEW if server IP in the lease is all zeroes\n* [`badbc51e6`](https://github.com/siderolabs/talos/commit/badbc51e63b685e22fffb82ae294a35cd9f65922) refactor: rewrite code to include preliminary support for multi-doc\n* [`ecce29dee`](https://github.com/siderolabs/talos/commit/ecce29dee9625842e419496e18560291ef90b1b5) fix: upgrade-k8s use internal IP first, external IP fallback\n* [`3c64a5ffb`](https://github.com/siderolabs/talos/commit/3c64a5ffba2109ccf5102f71652e54def52f8dbf) chore: optimize image generation time\n* [`2292f36d9`](https://github.com/siderolabs/talos/commit/2292f36d970d3edcf39b5d5f12d0051d7d75f390) chore: registry.k8s.io for coredns image\n* [`f2b258b37`](https://github.com/siderolabs/talos/commit/f2b258b3733a8fcc34bccde3bf01855a512d519a) docs: document talosctl version for upgrades\n* [`a0773f783`](https://github.com/siderolabs/talos/commit/a0773f783cfb3cfab8cbbeffb6449159754d785e) chore: add ukify Go script\n* [`b69e38d1f`](https://github.com/siderolabs/talos/commit/b69e38d1ff069ba8fac7a6524621f8b3c7256238) chore: bump dependencies\n* [`adce65103`](https://github.com/siderolabs/talos/commit/adce65103424f9f895e6b8c4858b27b3eb6bd74b) docs: add piraeus/drbd to storage documentation\n* [`a982cabe7`](https://github.com/siderolabs/talos/commit/a982cabe7011c87e863f7bb0829921e927ddf782) docs: link support matrix in k8s update doc\n* [`1fb29a56a`](https://github.com/siderolabs/talos/commit/1fb29a56a8abe5d72b8a3a336693e798424c63e0) fix: fail quickly if upgrade-k8s is used with multiple nodes\n* [`51d931c47`](https://github.com/siderolabs/talos/commit/51d931c4705fc7ca0bdadc59d732e56fae318dda) chore: faster dev cycle\n* [`dc6764871`](https://github.com/siderolabs/talos/commit/dc6764871c9e732b88f7cddc1784e943e9d952bb) refactor: move around config interfaces, make RawV1Alpha1 typed\n* [`ea9a97dba`](https://github.com/siderolabs/talos/commit/ea9a97dba38c6ab2de830e3b0c3d202d22bdb668) fix: fall back to external IP when discovering nodes in upgrade-k8s\n* [`0bb7e8a5c`](https://github.com/siderolabs/talos/commit/0bb7e8a5cf8b8f3bf31d9f8c3a85b4153921c126) refactor: split config.Provider into Config & Container\n* [`85d8a1619`](https://github.com/siderolabs/talos/commit/85d8a1619431989eb05cb15ad01a1bc06b0f63e9) chore: bump deps\n* [`39b7a56f0`](https://github.com/siderolabs/talos/commit/39b7a56f01d41d33eb96a0feb6e34d43965a99fd) chore: use 8GiB instead of 10GiB for cloud images\n* [`ff11fd39c`](https://github.com/siderolabs/talos/commit/ff11fd39c723a40c01abe6348f64b1f892856175) fix: race with `udevd` and `mountUserDisks`\n* [`c3fabb982`](https://github.com/siderolabs/talos/commit/c3fabb9829d12353770d6436a1d726b15820ebce) chore: update default image sizes to 10GB for all \"cloud\" images\n* [`10155c390`](https://github.com/siderolabs/talos/commit/10155c390e87898098426600709657fbd51e02e8) feat: enable xfs project quota support, kubelet feature\n* [`eba818564`](https://github.com/siderolabs/talos/commit/eba81856427dd3f6c0cf317f027e63d65a079029) release(v1.5.0-alpha.0): prepare release\n* [`383471c3e`](https://github.com/siderolabs/talos/commit/383471c3e956ff6e077a1de75b02a50835fbf352) feat: update default Kubernetes to v1.27.2\n* [`8f68d1abe`](https://github.com/siderolabs/talos/commit/8f68d1abeff83c3ff0e6c5d9f61cb14807b44ca5) chore: bump deps\n* [`e0c1585d3`](https://github.com/siderolabs/talos/commit/e0c1585d3047ef213134331dc57f8e2e8c23a93d) feat: create azure community gallery image version on release\n* [`dd8336c9e`](https://github.com/siderolabs/talos/commit/dd8336c9ee7f8a3a44d45c9f9e3cbbf741f84c44) fix: refresh kubelet self-issued serving certificates\n* [`bb02dd263`](https://github.com/siderolabs/talos/commit/bb02dd263cbc5e7e3839148d86a4a0a5f7ea998b) chore: drop deprecated stuff for Talos 1.5\n* [`61cad8673`](https://github.com/siderolabs/talos/commit/61cad86731e5c0aa80d7df41ea02d0b7ff579c45) chore: bump deps\n* [`01dfd3af7`](https://github.com/siderolabs/talos/commit/01dfd3af7d64dacd179d17d9d5eaf4bc44cf72af) feat: update etcd to v3.5.9\n* [`aa65fbb8a`](https://github.com/siderolabs/talos/commit/aa65fbb8a1752a70e7bac4e4e9872f35e88d1cc9) chore: update KUBECTL_URL to reflect the community bucket\n* [`cc3128d94`](https://github.com/siderolabs/talos/commit/cc3128d944abacfb633bc783b7fed6d0a6f80661) chore: bump kernel to 6.1.28\n* [`97fffaf78`](https://github.com/siderolabs/talos/commit/97fffaf78a0b9a1dc67709de11d37ea20aefde59) chore: use ctest.UpdateWithConflicts instead of plain UpdateWithConflicts\n* [`3b36993b9`](https://github.com/siderolabs/talos/commit/3b36993b9926392f4290e6fabc82e635f4c98149) fix: rlimit nofile test\n* [`45e6e27af`](https://github.com/siderolabs/talos/commit/45e6e27af75746fd0cc8b0f98a2d14579eb0ed40) chore: bump runtime\n* [`4f720d465`](https://github.com/siderolabs/talos/commit/4f720d46532af39165fc5051052d5c42595d91af) fix: revert: set rlimit explicitly in wrapperd\n* [`a2565f674`](https://github.com/siderolabs/talos/commit/a2565f67416e9b9bc22f2d5506df9ea7771c0c8c) fix: set rlimit explicitly in wrapperd\n* [`cdfc242b8`](https://github.com/siderolabs/talos/commit/cdfc242b8354f4cc4e7ce51bbe3a8fb20b35995d) chore: re-enable Go buildid\n* [`e67f3f5c5`](https://github.com/siderolabs/talos/commit/e67f3f5c5453f947355194ea9656c15ff008c35e) feat: linux 6.1.27, containerd 1.6.21, go 1.20.4\n* [`55ae59a0a`](https://github.com/siderolabs/talos/commit/55ae59a0ad71293676b3efed461f5ab98101401a) fix: properly skip/cleanup controlplane configs for workers\n* [`64eade9bd`](https://github.com/siderolabs/talos/commit/64eade9bde271bce4e629e6ac09407c8c42e01be) chore: clean up unused constant\n* [`62c6e9655`](https://github.com/siderolabs/talos/commit/62c6e9655cb639d4993aaa4c9b364342688599cb) feat: introduce siderolink config resource & reconnect\n* [`860002c73`](https://github.com/siderolabs/talos/commit/860002c7352bedd10845e11da37c80685ff0e720) fix: don't reload control plane pods on cert SANs changes\n* [`d43c61e80`](https://github.com/siderolabs/talos/commit/d43c61e80f5b05b81f2a021cdfe012e500c3d98e) fix: enforce nolock option for all NFS mounts by default\n* [`339986db9`](https://github.com/siderolabs/talos/commit/339986db9d3675b78ce0d268f799ad654862fb0f) fix: inhibit timer to follow kubelet timer\n* [`cbf6dc100`](https://github.com/siderolabs/talos/commit/cbf6dc1009ad47a2804774839e4e0301efa8ac78) fix: set timeout for unmount calls\n* [`b58f913d5`](https://github.com/siderolabs/talos/commit/b58f913d5f4b8ecf39be183d0bafe1109f0f0737) fix: set the static pod priority as values\n* [`f8a7a5b6b`](https://github.com/siderolabs/talos/commit/f8a7a5b6bf4138a33cbe5c9afe85db99de167aec) docs: add information about KubeSpan ports and topology\n* [`2bad74d64`](https://github.com/siderolabs/talos/commit/2bad74d6423c083ec34f1b422f23b0024d5f8798) docs: add how to on scaling down\n* [`7442ff8b0`](https://github.com/siderolabs/talos/commit/7442ff8b095ef1337f54332a71d08053a2832144) chore: fix typos inteface -> interface (docs and tests)\n* [`d4e94f7a1`](https://github.com/siderolabs/talos/commit/d4e94f7a15acf7f3c9e7532b067cdacd0e805bec) fix: add back required TARGETARCH for installer\n* [`e6fffda01`](https://github.com/siderolabs/talos/commit/e6fffda01385a2daaa901a5742f30a4edc9186a7) chore: linux 6.1.26, runc 1.1.7\n* [`344746ae2`](https://github.com/siderolabs/talos/commit/344746ae2fa038b704d02fec04c3d358762fe938) fix: bump max inhibit delay to 20 min\n* [`d9bdea2b5`](https://github.com/siderolabs/talos/commit/d9bdea2b54772f067783ee64eb85c834957d386a) chore: fork docs and compatibility modules for Talos 1.5\n* [`3d99610fc`](https://github.com/siderolabs/talos/commit/3d99610fc9b0d0084be822be29bb1bf2fbe85833) docs: document building, verifying image and process caps\n* [`014008ea2`](https://github.com/siderolabs/talos/commit/014008ea25208afbeabb42ef89238802705ad4e0) fix: udevd rules trigger\n* [`9b36bb613`](https://github.com/siderolabs/talos/commit/9b36bb613b44f182e47ae63bc74e4a8b6342d68d) feat: update Linux to 6.1.25, fix virtio on arm64\n* [`08ec66c55`](https://github.com/siderolabs/talos/commit/08ec66c55ccca3f9aa82a9703ebf183913b19a7e) feat: clean up (garbage collect) system images which are not referenced\n* [`b097efcde`](https://github.com/siderolabs/talos/commit/b097efcde29c20cdc4fed23fe8366bd683db634c) fix: display correct number of machines on dashboard\n* [`cad43f0ad`](https://github.com/siderolabs/talos/commit/cad43f0ad3bc2ede8a6ae81767c9226b6bc69f19) chore: remove k8s master label\n* [`e296a566e`](https://github.com/siderolabs/talos/commit/e296a566e6efb0cbdd119e73aff1feaa772d38bd) fix: support kernel userspace module loading\n* [`103f0ffdd`](https://github.com/siderolabs/talos/commit/103f0ffdd3ebd57a5086852f3502a8a7d4428faa) feat: add startup probes to controller-manager and scheduler\n* [`5a1ae8aae`](https://github.com/siderolabs/talos/commit/5a1ae8aae89e54d5540586d6f2e99ef3e80a72eb) chore: bump dependences\n* [`ec8c8dbaf`](https://github.com/siderolabs/talos/commit/ec8c8dbafcdaf63d036bdba92fa153d4d1c90100) chore: fix container image reproducibility\n* [`f661d8487`](https://github.com/siderolabs/talos/commit/f661d84877e6db5bc8856b982990926dcbfe949c) fix: allow `talosctl cp` to handle special files in `/proc`\n* [`2d824b563`](https://github.com/siderolabs/talos/commit/2d824b5639a4b8c3b673d13b08b2b97c69aafe0d) fix: do not show control plane status for workers on dashboard\n* [`e5491ddad`](https://github.com/siderolabs/talos/commit/e5491ddadeb1776bd5c17dd35917e05ec4847d0f) docs: update documentation for nocloud\n* [`7a004a6f7`](https://github.com/siderolabs/talos/commit/7a004a6f7f47fa5d17e855eb02650754d8411574) fix: parse errors correctly\n* [`374ef5385`](https://github.com/siderolabs/talos/commit/374ef53853947811dc221d99751cf0e16294508c) test: submit verbose flag to e2e tests\n* [`e1d38b6fe`](https://github.com/siderolabs/talos/commit/e1d38b6febf26fe31a6b9d6ed8f9b6bdba29aa3b) feat: show template URL in dashboard config URL tab\n* [`45d7f0ce9`](https://github.com/siderolabs/talos/commit/45d7f0ce95454ce85c403fc493ddb97e4d478238) docs: fix the latest url\n* [`96efbf147`](https://github.com/siderolabs/talos/commit/96efbf14769579d514ef9c75d01d9f44d276113a) docs: activate 1.4.0 docs by default\n* [`8c1f515b1`](https://github.com/siderolabs/talos/commit/8c1f515b1b8e40bce42e2fc04755afe5bf8a56aa) feat: update Linux to 6.1.24\n* [`8689bef5f`](https://github.com/siderolabs/talos/commit/8689bef5f10839091cf131edb6c8efad4ccba034) docs: update documentation for Talos 1.4\n* [`a781dfb8e`](https://github.com/siderolabs/talos/commit/a781dfb8e3ded67edcb2a6a1048bfe76c6bd0d24) feat: update Kubernetes to 1.27.1\n* [`a737dd83a`](https://github.com/siderolabs/talos/commit/a737dd83a4cd7549f85f8df0882f1c9a4446060d) chore: typo in `compatibility.ParseKubernetesVersion`\n* [`f14928b0a`](https://github.com/siderolabs/talos/commit/f14928b0a9dd3d85664605f4f6a206236ea94614) fix: fix dashboard crash when a non-existent node is specified\n* [`3e406d9b0`](https://github.com/siderolabs/talos/commit/3e406d9b07c0e67a2fb61e612bc3f378f3c35247) feat: update etcd to v3.5.8\n* [`bd1cff3e8`](https://github.com/siderolabs/talos/commit/bd1cff3e83530b9b89b27d8083ea8f3f0cf6ede4) chore: remove Go buildid\n* [`e31f7f50b`](https://github.com/siderolabs/talos/commit/e31f7f50b1b455beb98cd25859a44bbbccc1ff64) feat: update Kubernetes to 1.27.0\n* [`aa3640d74`](https://github.com/siderolabs/talos/commit/aa3640d74ce2e3619476453381909fa3520eb87d) docs: update storage.md\n* [`07bb61e60`](https://github.com/siderolabs/talos/commit/07bb61e60c53b267756dc97874b9c9554f2b1486) chore: module-sig-verify cleanup\n* [`5e9d836c3`](https://github.com/siderolabs/talos/commit/5e9d836c3d075c3edb2d48b2868c31a1c963e2de) chore: add kernel module signtaure verification\n* [`3cd1c6bb0`](https://github.com/siderolabs/talos/commit/3cd1c6bb0b83e5747a7356140a44b16deb4727e6) fix: send 'STOP' event on phase end\n* [`5176d27dc`](https://github.com/siderolabs/talos/commit/5176d27dc566d8689bb305398da7250269ebe9a3) feat: update Kubernetes to 1.27.0-rc.1\n* [`2c55550a6`](https://github.com/siderolabs/talos/commit/2c55550a66b49b49d8dc95b83516b7c0f8107300) fix: quote ISO kernel args for GRUB\n* [`319d76e38`](https://github.com/siderolabs/talos/commit/319d76e38978406d8d37e89ada2c403969d6c972) fix: respect BROWSER=echo in client auth interceptor\n* [`4e4ace839`](https://github.com/siderolabs/talos/commit/4e4ace839c0f558e7b00979fa4c64c32985aa3ce) chore: update Go to 1.20.3\n* [`170f73899`](https://github.com/siderolabs/talos/commit/170f73899a3bf29e9c6f76fdc5e510be08edf4aa) fix: correctly parse static pod phase\n* [`c3a595d5b`](https://github.com/siderolabs/talos/commit/c3a595d5b7d3c7c3091229caef6b2553416edb56) fix: improve action tracking post checks\n* [`eb01edbc8`](https://github.com/siderolabs/talos/commit/eb01edbc8a0ef5810693afe450861d5b63877b72) fix: rework DHCP flow\n* [`e095150a6`](https://github.com/siderolabs/talos/commit/e095150a6e34cbdc805a2cac85ec7f28f98629b4) test: bump CAPI components versions\n</p>\n</details>\n\n### Changes since v1.5.0-alpha.2\n<details><summary>9 commits</summary>\n<p>\n\n* [`d2f64af86`](https://github.com/siderolabs/talos/commit/d2f64af863e14b1d111bbeeaa6d9077aadaf6085) chore: disable cloud-images, pull in new kernel and gre module\n* [`8edce4906`](https://github.com/siderolabs/talos/commit/8edce490639c213cd8c45989a5a87e3388179d37) docs: improve proxmox install guide\n* [`c783458be`](https://github.com/siderolabs/talos/commit/c783458be0c90b779bcc2fe3c10e37fd3dfe01db) docs: typo dhcp -> dhcp\n* [`003cbd161`](https://github.com/siderolabs/talos/commit/003cbd161196375edc8ee5033be62014eb88202e) docs: warn about secretboxEncryptionSecret in kubeadm migration guide\n* [`786e86f5b`](https://github.com/siderolabs/talos/commit/786e86f5b8219ef37c5c6480d97c440cbbd53e30) refactor: rewrite the way Talos acquires the machine configuration\n* [`5e13cafe5`](https://github.com/siderolabs/talos/commit/5e13cafe5b506039fdd652372b1d1f71a1c1c10b) feat: enforce kernel lockdown for UKI\n* [`4d96d642f`](https://github.com/siderolabs/talos/commit/4d96d642fd9c462db2c084afee1428009d454a9e) feat: update default Kubernetes version to 1.28.0-beta.0\n* [`170a73e16`](https://github.com/siderolabs/talos/commit/170a73e161eacb0e21ce95e7a7e406533552bf1d) chore: support creating qemu guest socket\n* [`59ac38a6b`](https://github.com/siderolabs/talos/commit/59ac38a6bffe943fa634b124b8ec2a907f95a006) docs: add docs for installing azure ccm and csi\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`8f77da3`](https://github.com/siderolabs/crypto/commit/8f77da30a5193d207a6660b562a273a06d73aae0) feat: add a method to load PEM key from file\n* [`c03ff58`](https://github.com/siderolabs/crypto/commit/c03ff58af5051acb9b56e08377200324a3ea1d5e) feat: add a way to represent redacted x509 private keys\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e3db3c`](https://github.com/siderolabs/discovery-api/commit/5e3db3c1a656ebdc717494e5384f10c7b11eef0f) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`9ba5f03`](https://github.com/siderolabs/discovery-client/commit/9ba5f033a47d41448153962c5fe22db2d9a8a00c) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`f415aac`](https://github.com/siderolabs/extras/commit/f415aac20c245592612a02157d247cb2dd4a5d45) feat: update Go to 1.20.6\n* [`a73d524`](https://github.com/siderolabs/extras/commit/a73d5243f443fd32376780bf2a4f97b08f28917c) feat: update Go to 1.20.5\n* [`36c8ac4`](https://github.com/siderolabs/extras/commit/36c8ac4ab98300059acaad501c2adc8abd39179f) chore: update to Go 1.20.3\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`f9f5805`](https://github.com/siderolabs/gen/commit/f9f5805973d30fe6bbac2f4a79ad4197fe59970e) chore: bump rekres and add functions from exp\n* [`b968d21`](https://github.com/siderolabs/gen/commit/b968d21c9671d97e54317f80cdf781d6f963e44b) feat: add `TryRecv` and `RecvWithContext` functions\n* [`476dfea`](https://github.com/siderolabs/gen/commit/476dfeae70882e1ca6e5cfed3d6e12dc36841a26) feat: add foreach and clear to lazymap\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>4 commits</summary>\n<p>\n\n* [`fbb01f7`](https://github.com/siderolabs/go-blockdevice/commit/fbb01f714bdc9c32ea3459345b730b1043ce10c0) fix: properly detect token not found error\n* [`3e08968`](https://github.com/siderolabs/go-blockdevice/commit/3e089682439e885c6386f833e35728ce54daff44) fix: do not attach token to a key slot\n* [`f2c419e`](https://github.com/siderolabs/go-blockdevice/commit/f2c419e81dcba3c5be007130f677d2075e2aec3c) feat: support LUKS token management\n* [`076874a`](https://github.com/siderolabs/go-blockdevice/commit/076874a155ad44d764d25081125f950e8194d023) chore: resolve blockdevice symlinks\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`43d9100`](https://github.com/siderolabs/go-debug/commit/43d9100eba3a30ff0d7f1bed0058e6631243cc47) chore: allow enabling pprof manually\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>2 commits</summary>\n<p>\n\n* [`69fea5b`](https://github.com/siderolabs/go-kubernetes/commit/69fea5b840fb51aa08e5fbf380fa924b9d444094) feat: support upgrades to Kubernetes 1.28\n* [`5a3df5b`](https://github.com/siderolabs/go-kubernetes/commit/5a3df5b002d74ba9f4d773dc1278047481b1d4ba) fix: remove removed APIs for 1.27 upgrade\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>6 commits</summary>\n<p>\n\n* [`574126c`](https://github.com/siderolabs/go-loadbalancer/commit/574126cbf0e1e45a06cabaf602e5070dd7d441e2) chore: add 0.1ms tier and fix tiers\n* [`5301800`](https://github.com/siderolabs/go-loadbalancer/commit/5301800a874e853d97f8e12195558f79c97c0beb) chore: fix logging and tests\n* [`b23a173`](https://github.com/siderolabs/go-loadbalancer/commit/b23a1733aa9b303bda82175b4f5e9f8a4765a27b) chore: replace std log with zap\n* [`1a2f374`](https://github.com/siderolabs/go-loadbalancer/commit/1a2f374df7804dffe683e8be90e9829f2dfb5e95) feat: add multi-tier scoring based for generic List\n* [`56a27da`](https://github.com/siderolabs/go-loadbalancer/commit/56a27da7083139b71898f4f9207dc40088e8c815) chore: move to siderolabs/tcpproxy of inet.af/tcpproxy\n* [`f3a0e24`](https://github.com/siderolabs/go-loadbalancer/commit/f3a0e2411e08eef9c79876f3dc6e09e770710379) fix: use SO_LINGER option when doing TCP healthchecks\n</p>\n</details>\n\n### Changes from siderolabs/kms-client\n<details><summary>3 commits</summary>\n<p>\n\n* [`50064b6`](https://github.com/siderolabs/kms-client/commit/50064b67ac73c0a3f6f89c6a44ef914711107df0) fix: pass context to the key handler in the server wrapper\n* [`83e0a2e`](https://github.com/siderolabs/kms-client/commit/83e0a2ec6b06668940ec31d64491d9b8a630524b) feat: define API and add reference implementation for KMS server\n* [`8c37ee8`](https://github.com/siderolabs/kms-client/commit/8c37ee83099a6563197c89166b0ea596eebf0598) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>41 commits</summary>\n<p>\n\n* [`fedfafa`](https://github.com/siderolabs/pkgs/commit/fedfafa77de930ae7945e16ace61c13568024ac5) feat: add thunderbolt/USB4 module\n* [`17d5b94`](https://github.com/siderolabs/pkgs/commit/17d5b94cc7b3e9f9c86a9f5080dcc70f095659fe) feat: enable NET_IPGRE kernel config\n* [`84cdfb6`](https://github.com/siderolabs/pkgs/commit/84cdfb6d270201b166dacdcd928669d028e12deb) feat: add 'zfs' package\n* [`d0eaedc`](https://github.com/siderolabs/pkgs/commit/d0eaedcb5cd2510925e4609369e25c3e3572d5fe) feat: enable DM_RAID kernel config\n* [`d5e0fad`](https://github.com/siderolabs/pkgs/commit/d5e0fad0d59dfb8d2386ab2ad6c7df749e0b9413) feat: update dependencies\n* [`c644633`](https://github.com/siderolabs/pkgs/commit/c644633324ed1e56ab19f146c04ed3984736a88a) feat: enable multi-gen lru by default\n* [`75696ba`](https://github.com/siderolabs/pkgs/commit/75696ba81581ef0f1af668db565a08950145e45d) feat: update Go to 1.20.6\n* [`205cab6`](https://github.com/siderolabs/pkgs/commit/205cab6d0e6be2721c5338bef232e3345d3a299f) chore: feat use new sd-boot\n* [`fb817fe`](https://github.com/siderolabs/pkgs/commit/fb817fe20789ca48895275e1877808a9206630dd) fix: enable USB attached SCSI driver on x86 systems\n* [`43451e6`](https://github.com/siderolabs/pkgs/commit/43451e68a0ddf634b90c7c12cca9437faa52d183) chore: bump dependencies\n* [`eca94f8`](https://github.com/siderolabs/pkgs/commit/eca94f8f1b9c3ceb62efb53fd1260d49ce17f1dd) feat: enable sriov\n* [`5a8e8e5`](https://github.com/siderolabs/pkgs/commit/5a8e8e594248847bb606ca07b3ea29e187e20d26) feat: enable VMWARE/HYPERV vsockets\n* [`edd725a`](https://github.com/siderolabs/pkgs/commit/edd725a0f9d07d39256d98a67be5dc4c56631078) chore: bump deps\n* [`c0ac69b`](https://github.com/siderolabs/pkgs/commit/c0ac69b70cfac3cdcf100a35f6d766c5ae47d950) feat: enable CONFIG_NVME_{MULTIPATH|AUTH}\n* [`f7cd916`](https://github.com/siderolabs/pkgs/commit/f7cd916b47975e61c6732079c1c5c4684dfb8c96) fix: bump drbd to 9.2.4\n* [`a56d15a`](https://github.com/siderolabs/pkgs/commit/a56d15ad626b6e76a137636d6088361be9a73a9f) fix: copy missing `modules.*` files\n* [`1eefa66`](https://github.com/siderolabs/pkgs/commit/1eefa664fc7c65491e956a6f403ada774e73a7d3) feat: build isb modem drivers as module\n* [`a859f4f`](https://github.com/siderolabs/pkgs/commit/a859f4fb257e17fa19b1c10efcae594d33a86618) fix: build RDMA_RXE as a module\n* [`5fb5e95`](https://github.com/siderolabs/pkgs/commit/5fb5e9517de9fe35e383b96e92fa873aa045a845) feat: bump dependencies\n* [`39a64b2`](https://github.com/siderolabs/pkgs/commit/39a64b23e2c8689c44b9891b1e70149b8d003655) feat: update Linux to 6.1.31, add GENEVE for arm64\n* [`97177be`](https://github.com/siderolabs/pkgs/commit/97177be803cc91c8fabccfec575b7d920bc78c38) feat: update Linux to 6.1.30\n* [`b1f9d4e`](https://github.com/siderolabs/pkgs/commit/b1f9d4e717fbd0132b820d45c226ca643d7f577e) chore: prevent unsigned kexec with secureboot\n* [`9232a42`](https://github.com/siderolabs/pkgs/commit/9232a425b85b1058cd38eab30304f6cf243ab32c) feat: add reproducibility pipelines\n* [`702d7a7`](https://github.com/siderolabs/pkgs/commit/702d7a7e90099d8fdc9cc4ba50e86c8ba6e91d77) chore: bump deps\n* [`7958db1`](https://github.com/siderolabs/pkgs/commit/7958db1549a7c7560eeeb8f9c06d3be9487d8804) chore: copy over sd-boot and sd-stub from tools\n* [`813b3c3`](https://github.com/siderolabs/pkgs/commit/813b3c3d3276d0d9156919307e9ffe521925d40b) chore: revert xfsprogs\n* [`0cc78ab`](https://github.com/siderolabs/pkgs/commit/0cc78ab82ce920c8fa5654c73738050107e190bb) chore: bump kernel to 6.1.28\n* [`70189e3`](https://github.com/siderolabs/pkgs/commit/70189e3df555fed4afade93798d72cd31aad99c5) chore: bump deps\n* [`c5d3bf1`](https://github.com/siderolabs/pkgs/commit/c5d3bf1985b49e688d29d06db6730834f65ee480) feat: add sd-stub and sd-boot\n* [`30a7ac2`](https://github.com/siderolabs/pkgs/commit/30a7ac2974fb7580e83819c76502fde77d777ea0) feat: update Linux 6.1.27, containerd 1.6.21\n* [`fbc6ee5`](https://github.com/siderolabs/pkgs/commit/fbc6ee55b6ffae44c117255901ab0fbecae79cc3) chore: bump deps\n* [`82b9489`](https://github.com/siderolabs/pkgs/commit/82b9489b88b108f144b45fb55432576bfd767f91) chore: bump dependencies\n* [`f37e520`](https://github.com/siderolabs/pkgs/commit/f37e5205cf10fe10296e86565fa018d149f5d8c4) feat: update Linux to 6.1.25\n* [`3920b16`](https://github.com/siderolabs/pkgs/commit/3920b163a5c6a6d7c7969155a909a7b2122e65f6) feat: add multi-gen LRU kernel support\n* [`988f1ec`](https://github.com/siderolabs/pkgs/commit/988f1ecf95536fb259cbd79e044a556728bc7332) feat: update Linux to 6.1.24\n* [`5327d12`](https://github.com/siderolabs/pkgs/commit/5327d1263680f76706ea667906ca08222c8398da) fix: remove FB_NVIDIA drivers, Linux 6.1.23\n* [`4eae958`](https://github.com/siderolabs/pkgs/commit/4eae958770573613bc29568d130be7aaa775e530) chore: copy over the kernel signing public key\n* [`174f8fc`](https://github.com/siderolabs/pkgs/commit/174f8fc9c80d871f1c03ea0a53dc8b6eb7112ccf) chore: update Go to 1.20.3\n* [`41629b0`](https://github.com/siderolabs/pkgs/commit/41629b03e82bfb77623a812000ef8e98d15d56fa) chore: reorder pkgs for better kernel caching\n* [`b483a6b`](https://github.com/siderolabs/pkgs/commit/b483a6b01f539b0da13ca09882015044bff24e41) feat: build 'snp.efi' for iPXE\n* [`fb853ff`](https://github.com/siderolabs/pkgs/commit/fb853ff6b1194cdc1f2412c776347cf4b55c3336) feat: update containerd to 1.6.20\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>20 commits</summary>\n<p>\n\n* [`dc7dd9e`](https://github.com/siderolabs/tools/commit/dc7dd9e5b949f6f5d7626f11cb3b001526e8d1de) chore: remove libseccomp\n* [`e27c249`](https://github.com/siderolabs/tools/commit/e27c249c3213af6d12be4fb440a8f896c8e1b3d4) feat: update Go to 1.20.6\n* [`9b6d512`](https://github.com/siderolabs/tools/commit/9b6d5123fa1e28160019a4b6e8b0f04482c49dc0) feat: use systemd 254-rc1\n* [`cd3b692`](https://github.com/siderolabs/tools/commit/cd3b692b0cf5c663548cbe75db43036e11ee1014) chore: bump deps\n* [`c1027a6`](https://github.com/siderolabs/tools/commit/c1027a63d058b77f6cce7351fa7b63d4c94883ad) chore: remove sbsign\n* [`e0c76c0`](https://github.com/siderolabs/tools/commit/e0c76c096d06ef11afdb54287d5f15add108399b) chore: bump dependencies\n* [`7d0cd58`](https://github.com/siderolabs/tools/commit/7d0cd58b34bba6b9415db5e39bed351e7f00d44d) feat: update Go to 1.20.5\n* [`150efc2`](https://github.com/siderolabs/tools/commit/150efc22508043bfadc9d84a8c3c5fee6c2aac5f) chore: remove non needed tools\n* [`88ebb40`](https://github.com/siderolabs/tools/commit/88ebb40dd348b6c9e4dc5551b616e4a1892b4e42) feat: add swtpm\n* [`4c5d7fe`](https://github.com/siderolabs/tools/commit/4c5d7feb88dcbae2f7bf45f51f9e5e1ba339abac) chore: use same source epoch everywhere\n* [`2e46e5b`](https://github.com/siderolabs/tools/commit/2e46e5be764f8180a0762a5ab080ccff04534a8a) feat: add reproducibility pipelines\n* [`c6a41b6`](https://github.com/siderolabs/tools/commit/c6a41b6c5108d676f8573d3dd47ee29ae46e5cc0) fix: add sd-stub assertion patch\n* [`d2dde48`](https://github.com/siderolabs/tools/commit/d2dde48f72343aa3c541336f5319b8e649e80c87) chore: bump deps\n* [`8e45ad7`](https://github.com/siderolabs/tools/commit/8e45ad75ea78e353ca3eae21b18da9a42d1edf49) feat: add sbsign\n* [`271c4a6`](https://github.com/siderolabs/tools/commit/271c4a66b6987d9de2c0d1d69891b5ff277ebd43) feat: add sd-tools\n* [`eedc294`](https://github.com/siderolabs/tools/commit/eedc294967d415cca40d4c427d3521cd198661d7) chore: bump deps\n* [`81b09a5`](https://github.com/siderolabs/tools/commit/81b09a5ab204f16306c980eeff518a0d1a37ddf2) feat: add libcap and gnuefi\n* [`47b0fd3`](https://github.com/siderolabs/tools/commit/47b0fd3e364d4fbcfffe10965f740db7acd82f70) chore: bump go to 1.20.4\n* [`ff4cf2b`](https://github.com/siderolabs/tools/commit/ff4cf2beabab310365ad9887abb6234570f5092a) chore: bump deps\n* [`1563556`](https://github.com/siderolabs/tools/commit/1563556b8f8fdf20d8aa58ac5340104c7ffe732e) feat: update Go to 1.20.3\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/BurntSushi/toml**                     v1.2.1 -> v1.3.2\n* **github.com/aws/aws-sdk-go**                      v1.44.232 -> v1.44.304\n* **github.com/beevik/ntp**                          v0.3.0 -> v1.2.0\n* **github.com/benbjohnson/clock**                   v1.1.0 -> v1.3.5\n* **github.com/cenkalti/backoff/v4**                 v4.2.0 -> v4.2.1\n* **github.com/containerd/containerd**               v1.6.19 -> v1.6.21\n* **github.com/containerd/typeurl/v2**               v2.1.1 **_new_**\n* **github.com/containernetworking/plugins**         v1.2.0 -> v1.3.0\n* **github.com/cosi-project/runtime**                v0.3.0 -> v0.3.1-alpha.8\n* **github.com/docker/distribution**                 v2.8.1 -> v2.8.2\n* **github.com/docker/docker**                       v23.0.2 -> v24.0.4\n* **github.com/ecks/uefi**                           caef65d070eb **_new_**\n* **github.com/emicklei/dot**                        v1.4.2 -> v1.5.0\n* **github.com/foxboron/go-uefi**                    32187aa193d0 **_new_**\n* **github.com/google/go-tpm**                       v0.9.0 **_new_**\n* **github.com/hashicorp/go-envparse**               v0.1.0 **_new_**\n* **github.com/hetznercloud/hcloud-go**              v1.41.0 -> v1.48.0\n* **github.com/insomniacslk/dhcp**                   74ae03f2425e -> 5648422c16cd\n* **github.com/jsimonetti/rtnetlink**                v1.3.1 -> v1.3.4\n* **github.com/mattn/go-isatty**                     v0.0.18 -> v0.0.19\n* **github.com/mdlayher/ethtool**                    ba3b4bc2e02c -> v0.1.0\n* **github.com/mdlayher/genetlink**                  v1.3.1 -> v1.3.2\n* **github.com/mdlayher/netlink**                    v1.7.1 -> v1.7.2\n* **github.com/mdlayher/netx**                       c711c2f8512f -> 7e21880baee8\n* **github.com/nberlee/go-netstat**                  v0.1.1 -> v0.1.2\n* **github.com/opencontainers/go-digest**            v1.0.0 **_new_**\n* **github.com/opencontainers/image-spec**           v1.1.0-rc2 -> v1.1.0-rc4\n* **github.com/packethost/packngo**                  v0.29.0 -> v0.30.0\n* **github.com/prometheus/procfs**                   v0.9.0 -> v0.11.0\n* **github.com/rivo/tview**                          281d14d896d7 -> 6cc0565babaf\n* **github.com/rs/xid**                              v1.4.0 -> v1.5.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.15 -> v1.0.0-beta.19\n* **github.com/siderolabs/crypto**                   v0.4.0 -> v0.4.1\n* **github.com/siderolabs/discovery-api**            v0.1.2 -> v0.1.3\n* **github.com/siderolabs/discovery-client**         v0.1.4 -> v0.1.5\n* **github.com/siderolabs/extras**                   v1.4.0-1-g9b07505 -> v1.5.0-alpha.0-2-gf415aac\n* **github.com/siderolabs/gen**                      v0.4.3 -> v0.4.5\n* **github.com/siderolabs/go-blockdevice**           v0.4.4 -> v0.4.6\n* **github.com/siderolabs/go-debug**                 v0.2.2 -> v0.2.3\n* **github.com/siderolabs/go-kubernetes**            v0.2.0 -> v0.2.2\n* **github.com/siderolabs/go-loadbalancer**          v0.2.1 -> v0.3.2\n* **github.com/siderolabs/kms-client**               v0.1.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.4.1-5-ga333a84 -> v1.5.0-alpha.0-40-gfedfafa\n* **github.com/siderolabs/talos/pkg/machinery**      v1.4.0 -> v1.5.0-alpha.2\n* **github.com/siderolabs/tools**                    v1.4.0-1-g955aabc -> v1.5.0-alpha.0-19-gdc7dd9e\n* **github.com/spf13/cobra**                         v1.6.1 -> v1.7.0\n* **github.com/stretchr/testify**                    v1.8.2 -> v1.8.4\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.16 -> v0.56.17\n* **github.com/vmware/govmomi**                      v0.30.4 -> v0.30.6\n* **go.etcd.io/etcd/api/v3**                         v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/v3**                      v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.8 -> v3.5.9\n* **golang.org/x/net**                               v0.8.0 -> v0.12.0\n* **golang.org/x/sync**                              v0.1.0 -> v0.3.0\n* **golang.org/x/sys**                               v0.6.0 -> v0.10.0\n* **golang.org/x/term**                              v0.6.0 -> v0.10.0\n* **golang.org/x/text**                              v0.11.0 **_new_**\n* **golang.zx2c4.com/wireguard/wgctrl**              9c5414ab4bde -> 925a1e7659e6\n* **google.golang.org/grpc**                         v1.54.0 -> v1.56.2\n* **google.golang.org/protobuf**                     v1.30.0 -> v1.31.0\n* **k8s.io/api**                                     v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/apimachinery**                            v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/apiserver**                               v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/client-go**                               v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/component-base**                          v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/cri-api**                                 v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/klog/v2**                                 v2.90.1 -> v2.100.1\n* **k8s.io/kubectl**                                 v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/kubelet**                                 v0.27.1 -> v0.28.0-alpha.4\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.68 -> v1.2.69\n\nPrevious release can be found at [v1.4.0](https://github.com/siderolabs/talos/releases/tag/v1.4.0)\n\n## [Talos 1.5.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.5.0-alpha.2) (2023-07-20)\n\nWelcome to the v1.5.0-alpha.2 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Extension Services\n\nTalos now supports setting `environmentFile` for an extension service container spec. Refer: https://www.talos.dev/v1.5/advanced/extension-services/#container\nThe extension waits for the file to be present before starting the service.\n\n\n### Predictable Network Interface Names\n\nStarting with version Talos 1.5, network interfaces are renamed to [predictable names](https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/)\nsame way as `systemd` does that in other Linux distributions.\n\nThe naming schema `enx78e7d1ea46da` (based on MAC addresses) is enabled by default, the order of interface naming decisions is:\n\n* firmware/BIOS provided index numbers for on-board devices (example: `eno1`)\n* firmware/BIOS provided PCI Express hotplug slot index numbers (example: `ens1`)\n* physical/geographical location of the connector of the hardware (example: `enp2s0`)\n* interfaces's MAC address (example: `enx78e7d1ea46da`)\n\nThe predictable network interface names features can be disabled by specifying `net.ifnames=0` in the kernel command line.\nTalos automatically adds the `net.ifnames=0` kernel argument when upgrading from Talos versions before 1.5.\n\nThis change doesn't affect \"cloud\" platforms, like AWS, as Talos automatically adds `net.ifnames=0` to the kernel command line.\n\n\n### Network KMS Disk Encryption\n\nTalos now supports new type of encryption keys which are sealed/unsealed with an external KMS server:\n\n```\nsystemDiskEncryption:\n  ephemeral:\n    keys:\n      - kms:\n          endpoint: https://1.2.3.4:443\n        slot: 0\n```\ngRPC API definitions and a simple reference implementation of the KMS server can be found in this\n[repository](https://github.com/siderolabs/kms-client/blob/main/cmd/kms-server/main.go).\n\n\n### KubePrism - Kubernetes API Server In-Cluster Load Balancer\n\nTalos now supports configuring the KubePrism - Kubernetes API Server in-cluster load balancer with machine config\n`features.kubePrism.port` and `features.kubePrism.enabled` fields.\n\nIf enabled, KubePrism binds to `localhost` and runs on the same port on every machine in the cluster.\nThe default value for KubePrism endpoint is https://localhost:7445.\n\nThe KubePrism is used by the `kubelet`, `kube-scheduler`, `kube-controller-manager`\nand `kube-proxy` by default and can be passed to the CNIs like Cilium and Calico.\n\nThe KubePrism provides access to the Kubernetes API endpoint even if the external loadbalancer\nis not healthy, provided that the worker nodes can reach to the controlplane machine addresses directly.\n\n\n### Machine Config option `.machine.install.bootloader`\n\nThe `.machine.install.bootloader` option in the machine config is deprecated and will be removed in Talos 1.6.\nThis was a no-op for a long time. The bootloader is always installed.\n\n\n### XFS Quota\n\nTalos 1.5+ enables XFS project quota support by default, also enabling by default\nkubelet feature gate `LocalStorageCapacityIsolationFSQuotaMonitoring` to use xfs quotas\nto monitor volume usage instead of `du`.\n\nThis feature is controlled by the `.machine.features.diskQuotaSupport` field in the machine config,\nit is set to true for new clusters.\n\nWhen upgrading from a previous version, the feature can be enabled by setting the field to true.\nOn the first mount of a volume, the quota information will be recalculated, which may take some time.\n\n\n### RDMA/RoCE support\n\nTalos no longer loads by default `rdma_rxe` Linux driver, which is required for RoCE support.\nIf the driver is required, it can be enabled by specifying `rdma_rxe` in the `.machine.kernel.modules` field in the machine config.\n\n\n### SecureBoot\n\nTalos now supports generating a custom iso that can be used with SecureBoot. Key generation and enrolling has to be done manually.\n\n\n### `talosctl image` Command\n\nA new set of commands was introduced to manage container images in the CRI:\n\n* `talosctl image list` shows list of available images\n* `talosctl image pull` allows to pre-pull an image into the CRI\n\nBoth new commands accept `--namespace` flag with two possible values:\n\n* `cri` (default): images managed by the CRI (Kubernetes workloads)\n* `system`: images managed by Talos (`etcd` and `kubelet`)\n```\n\n\n### `talosctl images` Command\n\nThe command `talosctl images` was renamed to `talosctl image default`.\n\nThe backward-compatible alias is kept in Talos 1.5, but it will be dropped in Talos 1.6.\n\n\n### TPM Disk Encryption\n\nTalos now supports encrypting STATE/EPHEMERAL with keys bound to a TPM device. The TPM device must be TPM2.0 compatible.\nThis is ideally supported when booting with new Talos SecureBoot UKI ISOs/Metal images. This feature would still work if SecureBoot\nis not enabled for UKI images, but not recommended since there is no way to verify the trust of the bootloader.\n\nExample machine config:\n\n```\nsystemDiskEncryption:\n  ephemeral:\n    keys:\n      - slot: 0\n        tpm: {}\n  state:\n    keys:\n      - slot: 0\n        tpm: {}\n```\n\n\n### Component Updates\n\n* Linux: 6.1.39\n* containerd: 1.6.21\n* runc: 1.1.8\n* etcd: 3.5.9\n* Kubernetes: 1.28.0-alpha.4\n* Flannel: 0.22.0\n\nTalos is built with Go 1.20.6.\n\n\n### `talosctl upgrade-k8s` Image Pre-pulling\n\nThe command `talosctl upgrade-k8s` now by default pre-pulls images for Kubernetes controlplane components\nand kubelet. This provides an early check for missing images, and minimizes downtime during Kubernetes\nrolling component update.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Artem Chernyshev\n* Steve Francis\n* Christian Rolland\n* Nanfei Chen\n* Nico Berlee\n* Spencer Smith\n* Alex Corcoles\n* Alex Corcoles\n* Alex Lubbock\n* Artem Chernyshev\n* Budiman Jojo\n* Chris Hoffman\n* DJAlPee\n* Dennis Marttinen\n* Eirik Askheim\n* Florian Klink\n* Henk Kraal\n* James Callahan\n* LukasAuerbeck\n* Markus Reiter\n* Michael A. Davis\n* Michael Fornaro\n* Niklas Wik\n* Piotr Maksymiuk\n* Ricky Sadowski\n* Roee Klinger\n* Serge Logvinov\n* Thomas Perronin\n* Tim Jones\n* Victor Bajada\n* Walt Chen\n* bdronneau\n\n### Changes\n<details><summary>184 commits</summary>\n<p>\n\n* [`60c304126`](https://github.com/siderolabs/talos/commit/60c304126fce95fd4995c416e7757f85505b90fb) chore: bump dependencies\n* [`9ef4e5efc`](https://github.com/siderolabs/talos/commit/9ef4e5efca4b537a550a5e902fc2479ebb5e53e3) fix: log explicitly when kubelet has no nodeIP match\n* [`6b39c6a4d`](https://github.com/siderolabs/talos/commit/6b39c6a4d326752f92d98388bbb418f2e50d3ddb) fix: enable compression and bump gRPC max msg size\n* [`2f2eca861`](https://github.com/siderolabs/talos/commit/2f2eca86175fe98b3bf491f38ff907599333b139) chore: basic support for shutdown/poweroff flags\n* [`b84277d7d`](https://github.com/siderolabs/talos/commit/b84277d7dc50b196b7cd27e7f2ceff6bf8f58a8d) docs: fix wrong capability name\n* [`59d7d9344`](https://github.com/siderolabs/talos/commit/59d7d9344b27529af420ec31c7b599027cda044f) chore: use machined for `shutdown`, `poweroff`\n* [`2439bfb71`](https://github.com/siderolabs/talos/commit/2439bfb719d9f50107cee500d03c90bd50649e05) chore: explicitly add timestamps to machined logs\n* [`14966e718`](https://github.com/siderolabs/talos/commit/14966e718a07906ff389ecdda063fd16b22baab9) fix: skip over tpm2 1.2 devices\n* [`6716e7bc0`](https://github.com/siderolabs/talos/commit/6716e7bc0ba6da31b8bc19aa4bd5edb7749b39a1) docs: update cilium documentation about KubePrism usage\n* [`166d75fe8`](https://github.com/siderolabs/talos/commit/166d75fe888d334349f57dcf405b6867ca5305e2) fix: tpm2 encrypt/decrypt flow\n* [`130518de7`](https://github.com/siderolabs/talos/commit/130518de71ae96cdf7d733a35e4c306940e1b845) chore: change missing renames of KubePrism\n* [`5f34f5b41`](https://github.com/siderolabs/talos/commit/5f34f5b41f03d6d455d7b843084d2951c365a7ee) chore: rename api load balancer to KubePrism\n* [`c8b7095c0`](https://github.com/siderolabs/talos/commit/c8b7095c01f597cd8b41964b42aa7e35c85ae307) refactor: use tpm2 library to calculate policy hash\n* [`078aac92e`](https://github.com/siderolabs/talos/commit/078aac92ee30c9666235219d4623b82d66362d4d) chore: bump deps\n* [`53873b844`](https://github.com/siderolabs/talos/commit/53873b8444acaa97d85c50caec625b9dbfdfef93) refactor: move ukify into Talos code\n* [`d5f6fb9ff`](https://github.com/siderolabs/talos/commit/d5f6fb9ff2980df03365719d9e2690cb5ac788af) chore: add vendor info\n* [`79365d9ba`](https://github.com/siderolabs/talos/commit/79365d9bacf0e8a6660cdc6b7172c79edf5f3ba3) feat: tpm2 based disk encryption\n* [`06369e819`](https://github.com/siderolabs/talos/commit/06369e8195e76f96d232d077efb2bfb059b7aa96) fix: retry CRI pod removal, fix upgrade flow in the tests\n* [`d32dd3a82`](https://github.com/siderolabs/talos/commit/d32dd3a820b07d58ca89c4226c986d87ff0e2b65) chore: update Go to 1.20.6\n* [`8017afb10`](https://github.com/siderolabs/talos/commit/8017afb107b901a8785bccaac65d63f34e506568) feat: implement CRI image management and pre-pull on K8s upgrade\n* [`1c2f19b36`](https://github.com/siderolabs/talos/commit/1c2f19b367af8b04fc49174540e5b141f4b34156) feat: update Kubernetes to 1.28.0-alpha.4\n* [`94e9891c1`](https://github.com/siderolabs/talos/commit/94e9891c1bb44a1e7c285b4ccf1fad59ea05aa62) chore: bump sd-boot to v254-rc1\n* [`936111ce0`](https://github.com/siderolabs/talos/commit/936111ce062d23ed11b30ea35585c0519260f9c5) fix: properly set up tls for KMS endpoint\n* [`cb226eec4`](https://github.com/siderolabs/talos/commit/cb226eec46b59372c684c3946e0ba0910066573d) fix: rewrite encryption system information flow\n* [`3206db528`](https://github.com/siderolabs/talos/commit/3206db52895416d1eb936caa4e953312b34b8549) feat: drop tpm simulator for ukify measure\n* [`bd4f89f63`](https://github.com/siderolabs/talos/commit/bd4f89f6338423a79b7ce89bda1bd6704caaae59) fix: disable dashboard on Azure, GCP and Scaleway\n* [`bdb96189f`](https://github.com/siderolabs/talos/commit/bdb96189faadc48e93146f9fd7b03e006bf1dd75) refactor: make maintenance service controller-based\n* [`d23d04de2`](https://github.com/siderolabs/talos/commit/d23d04de2a5dee30ccf21efe767daf229de78bdb) feat: seed the kernel random pool from the TPM\n* [`c81ce8cfb`](https://github.com/siderolabs/talos/commit/c81ce8cfb0bc7df66ffd1e1819b64dad6357d890) feat: support controlplane resources configuration\n* [`74de562b2`](https://github.com/siderolabs/talos/commit/74de562b29c748fda3140871ea3fab99698341ef) fix: mount hugepages with nosuid + nodev\n* [`ce63abb21`](https://github.com/siderolabs/talos/commit/ce63abb219a2fd4a9d3fdd93a13c343af123efc2) feat: add KMS assisted encryption key handler\n* [`dafbe9deb`](https://github.com/siderolabs/talos/commit/dafbe9debdee2b015ed574ac4f5f722bce997b31) chore: optimize dockerfile instructions\n* [`a4289e870`](https://github.com/siderolabs/talos/commit/a4289e8703d9f9e52b739b19b5b38e30a75a1454) chore: fix CLI docs generation stability\n* [`2fec8388f`](https://github.com/siderolabs/talos/commit/2fec8388fc2fe3058b7b6f141ce9eae2c6a8268f) chore: bump dependencies\n* [`c1b4262dd`](https://github.com/siderolabs/talos/commit/c1b4262dd60f6cbea6d46a8d0433499bf6365b36) docs: split simple and more complex getting started guides\n* [`c9a9f9561`](https://github.com/siderolabs/talos/commit/c9a9f95611e38cf5c298f0d9fb0890a9bc0f8b98) refactor: extract secure boot certificate generation\n* [`6be5a13d5`](https://github.com/siderolabs/talos/commit/6be5a13d5d8341c58d0d2fe75c49ba1de9bf7316) feat: implement machine config documents for event and log streaming\n* [`e241be85b`](https://github.com/siderolabs/talos/commit/e241be85ba748163268eaeed2a88c8e295f84b28) fix: properly handle YAML comment stripping for multi-doc\n* [`c02ada7d9`](https://github.com/siderolabs/talos/commit/c02ada7d952255bffe67b3c84f1f832253e1a3b5) fix: capabilities including `ALL` should be uppercase\n* [`cbdf96d46`](https://github.com/siderolabs/talos/commit/cbdf96d461ec0cf8929c2c76614081ef042dda31) feat: support environment file for extensions\n* [`35d6adcb9`](https://github.com/siderolabs/talos/commit/35d6adcb9ad7e9420a5bcdfcf3378a05c0b65d46) fix: provide stashed META values before installation\n* [`258f07449`](https://github.com/siderolabs/talos/commit/258f07449050d69c369fdc71ac613a1a225807bf) fix: ukify cert generation\n* [`bf3febb7e`](https://github.com/siderolabs/talos/commit/bf3febb7e2bf3ebf1bd66ee088f3885a178c953c) fix: refine OVMF search paths\n* [`fbebc17f8`](https://github.com/siderolabs/talos/commit/fbebc17f8be7a3ca6c45c3c84d306e52c47d441d) fix: disable LVM backups/archive\n* [`e5306ef26`](https://github.com/siderolabs/talos/commit/e5306ef2637dd2eb7464691b55159a43933c7419) chore: format and cleanup test scripts\n* [`bc371ecfd`](https://github.com/siderolabs/talos/commit/bc371ecfdafe51f8cf34461caf9e6f51c0a93108) chore: add `/sbin/shutdown`\n* [`0d313b973`](https://github.com/siderolabs/talos/commit/0d313b973367906b2fd4bcad4b2def79344dbd67) feat: add `reboot-mode` flag to `talosctl upgrade`\n* [`7ce87f20c`](https://github.com/siderolabs/talos/commit/7ce87f20c39c615f4d23a3be23780a36008dcb19) fix: compare only basename of `os.Args[0]` in machined\n* [`53389b1e7`](https://github.com/siderolabs/talos/commit/53389b1e724751e28046167b44f05c6ecf06f184) feat: auto-enroll secure boot keys\n* [`d77f0bc7b`](https://github.com/siderolabs/talos/commit/d77f0bc7bbe01b7fc8efa21a7c57d73ecb94a01f) docs: fix broken link to powershell module\n* [`e1b150a11`](https://github.com/siderolabs/talos/commit/e1b150a11014ddd0c60585d320dd7cd556cf2a0c) release(v1.5.0-alpha.1): prepare release\n* [`8daf432b2`](https://github.com/siderolabs/talos/commit/8daf432b2957a8f9d5c59970cf68e7e8414038f5) chore: bump deps\n* [`e3f3f5794`](https://github.com/siderolabs/talos/commit/e3f3f5794d276433748d0e677ed8476a54f8a98e) feat: implement revert for sd-boot\n* [`d8b0903d7`](https://github.com/siderolabs/talos/commit/d8b0903d70181afc901d8ddb71bdfa964d4df2cd) docs: vagrant setup document fix\n* [`fe0f46980`](https://github.com/siderolabs/talos/commit/fe0f46980f348852907218d6f49581efe4b45d49) feat: implement secure boot from disk\n* [`445f5ad54`](https://github.com/siderolabs/talos/commit/445f5ad5426b125e29d86ff096695399bd01eb32) feat: support API server load balancer\n* [`19bc223de`](https://github.com/siderolabs/talos/commit/19bc223de8ad878bffe539bda617d5f861af3cfe) refactor: bootloader interface, labels\n* [`665702ddd`](https://github.com/siderolabs/talos/commit/665702ddd351e902336e6ab81108ea94d61db5c1) chore: fix cilium e2e tests\n* [`71a548d18`](https://github.com/siderolabs/talos/commit/71a548d18013ee16394921759e819b0fabb43758) chore: generic boootloader implementation\n* [`e9dbc9311`](https://github.com/siderolabs/talos/commit/e9dbc9311bcbbbcaab2c7eb7f7128013194c234a) test: bump versions for upgrade tests\n* [`0a99965ef`](https://github.com/siderolabs/talos/commit/0a99965efbdd5dc0d927eb2cbae209dc143c9541) refactor: replace `uncordonNode` with controllers\n* [`e858bca3a`](https://github.com/siderolabs/talos/commit/e858bca3a2f75d5035710d52229c8142f3eb6982) test: fix cilium integration tests\n* [`455328d05`](https://github.com/siderolabs/talos/commit/455328d058fba3a5a8b3358820a02e2b4fabad95) fix: allow time skew for generated kubeconfig\n* [`3ae05648a`](https://github.com/siderolabs/talos/commit/3ae05648ae0a2f79bebd678f85d63d4e5dafde0a) fix: usage of custom kernels\n* [`0797b0d16`](https://github.com/siderolabs/talos/commit/0797b0d16808d115649a9e0e37b355bbbc2a30b5) chore: add a pipeline to test cloud-images step without a release\n* [`e5a36268b`](https://github.com/siderolabs/talos/commit/e5a36268b63e588ea6cd2439bf0de356ee07d752) docs: include `allowSchedulingOnControlPlanes` on `talosctl gen config` output\n* [`c74d93728`](https://github.com/siderolabs/talos/commit/c74d937280c2ec707936a72d07dc2a5dd252c5d2) chore: bump github.com/cosi-project/runtime\n* [`dbaf5c699`](https://github.com/siderolabs/talos/commit/dbaf5c69978fd1d22737385ddd096798d408254c) refactor: task `labelControlPlane` into controllers\n* [`1865a0c29`](https://github.com/siderolabs/talos/commit/1865a0c29663a1a78db7ef6e901d450d67a3cbe1) chore: modify some usages that are not recommended\n* [`3816318b9`](https://github.com/siderolabs/talos/commit/3816318b9e2e205da0c949c0ec59a087decd0b78) chore: wrap config.Provider in atomic wrapper\n* [`d04cf1978`](https://github.com/siderolabs/talos/commit/d04cf19788df20c802eadb9678570a4f15d339b2) chore: clean up unnecessary self assignment\n* [`a34a94898`](https://github.com/siderolabs/talos/commit/a34a948985fed7c3054c4342c48e0e0620569625) fix: copy missing modules.* files\n* [`f5e3272fc`](https://github.com/siderolabs/talos/commit/f5e3272fce641a878eefa66437d28d3ed9917ab6) refactor: task 'updateBootLoader' as controller\n* [`e7be6ee7c`](https://github.com/siderolabs/talos/commit/e7be6ee7c3636eebd557d93e440e9749c8093360) refactor: make event log streaming fully reactive\n* [`aef2192a6`](https://github.com/siderolabs/talos/commit/aef2192a6584e7934086eae0caab6faba52a8ac1) chore: use fixed module list\n* [`c719aa231`](https://github.com/siderolabs/talos/commit/c719aa2316bffa3b614d27d630ea3d8731684f4e) fix: allow http:// for discovery service URL\n* [`39134d8d5`](https://github.com/siderolabs/talos/commit/39134d8d5304cec5e1a1c5fe23f62ed957241213) chore: fix cron pipeline\n* [`a61dcdbbd`](https://github.com/siderolabs/talos/commit/a61dcdbbd5c917b49c810108ff96854ad51269b1) fix: don't load RDMA over Ethernet driver by default\n* [`aac441f61`](https://github.com/siderolabs/talos/commit/aac441f618ac60f2298d9e17a2044916f7da9d69) chore: update Go to 1.20.5, bump dependencies\n* [`1c0c7933d`](https://github.com/siderolabs/talos/commit/1c0c7933dfef23544e2fb0fc04c4c5ad7d5b5d9b) chore: cleanup partition code\n* [`31b988281`](https://github.com/siderolabs/talos/commit/31b988281efb9d0c66975bbfc20b893ad32c161d) docs: add some words about certifcates\n* [`e912c0dfc`](https://github.com/siderolabs/talos/commit/e912c0dfcf515c5a6c852f4b935c9b48e61b13f1) chore: use go-blockdevice for zeroing partitions\n* [`e6dde8ffc`](https://github.com/siderolabs/talos/commit/e6dde8ffc50e435a42d11eb96cf6aea2cf3520ca) feat: add network chaos to qemu development environment\n* [`47986cb79`](https://github.com/siderolabs/talos/commit/47986cb79eb30c6e9c0d091ee37b2b1c2f20885c) chore: unify kexec phase\n* [`3a865370f`](https://github.com/siderolabs/talos/commit/3a865370f5152243e08a69626de023f924e22689) feat: qemu secureboot\n* [`5dab45e86`](https://github.com/siderolabs/talos/commit/5dab45e86917837b0991a62ab94a7b96b3ef777e) refactor: allow kmsg log streaming to be reconfigured on the fly\n* [`8a02ecd4c`](https://github.com/siderolabs/talos/commit/8a02ecd4cb97bcaafe5761d464fec8a4e44b672f) chore: add endpoints balancer controller\n* [`423a31ac9`](https://github.com/siderolabs/talos/commit/423a31ac9d8f28c2bcf00794bacf5446e43fc0b7) chore: deprectae `bootloader` installer option\n* [`cdfece7d6`](https://github.com/siderolabs/talos/commit/cdfece7d64a9269afcc213f8d604d0b7e525cb8a) chore: optimize image compression\n* [`bfc341937`](https://github.com/siderolabs/talos/commit/bfc34193762cb309ef2230f4d79673c4a56f4db5) chore: add default console args\n* [`2749aeeda`](https://github.com/siderolabs/talos/commit/2749aeeda0451b286369d911696070e2cf4359e9) feat: add support for multi-doc strategic merge patching\n* [`3f68485e4`](https://github.com/siderolabs/talos/commit/3f68485e44800a0c50b5855531ec10507e7d0df9) feat: add uki iso generation\n* [`bab484a40`](https://github.com/siderolabs/talos/commit/bab484a405cb598d1c5f35f7602c2ac27e6efa97) feat: use stable network interface names\n* [`196dfb99b`](https://github.com/siderolabs/talos/commit/196dfb99b0329d5c52fd7089e62fbfa1b09df3c6) fix: do not probe kernel args in dashboard if not needed\n* [`8c071b579`](https://github.com/siderolabs/talos/commit/8c071b5796db05ecb17e46295eb2140827a58ca8) fix: skip DHCP RENEW if server IP in the lease is all zeroes\n* [`badbc51e6`](https://github.com/siderolabs/talos/commit/badbc51e63b685e22fffb82ae294a35cd9f65922) refactor: rewrite code to include preliminary support for multi-doc\n* [`ecce29dee`](https://github.com/siderolabs/talos/commit/ecce29dee9625842e419496e18560291ef90b1b5) fix: upgrade-k8s use internal IP first, external IP fallback\n* [`3c64a5ffb`](https://github.com/siderolabs/talos/commit/3c64a5ffba2109ccf5102f71652e54def52f8dbf) chore: optimize image generation time\n* [`2292f36d9`](https://github.com/siderolabs/talos/commit/2292f36d970d3edcf39b5d5f12d0051d7d75f390) chore: registry.k8s.io for coredns image\n* [`f2b258b37`](https://github.com/siderolabs/talos/commit/f2b258b3733a8fcc34bccde3bf01855a512d519a) docs: document talosctl version for upgrades\n* [`a0773f783`](https://github.com/siderolabs/talos/commit/a0773f783cfb3cfab8cbbeffb6449159754d785e) chore: add ukify Go script\n* [`b69e38d1f`](https://github.com/siderolabs/talos/commit/b69e38d1ff069ba8fac7a6524621f8b3c7256238) chore: bump dependencies\n* [`adce65103`](https://github.com/siderolabs/talos/commit/adce65103424f9f895e6b8c4858b27b3eb6bd74b) docs: add piraeus/drbd to storage documentation\n* [`a982cabe7`](https://github.com/siderolabs/talos/commit/a982cabe7011c87e863f7bb0829921e927ddf782) docs: link support matrix in k8s update doc\n* [`1fb29a56a`](https://github.com/siderolabs/talos/commit/1fb29a56a8abe5d72b8a3a336693e798424c63e0) fix: fail quickly if upgrade-k8s is used with multiple nodes\n* [`51d931c47`](https://github.com/siderolabs/talos/commit/51d931c4705fc7ca0bdadc59d732e56fae318dda) chore: faster dev cycle\n* [`dc6764871`](https://github.com/siderolabs/talos/commit/dc6764871c9e732b88f7cddc1784e943e9d952bb) refactor: move around config interfaces, make RawV1Alpha1 typed\n* [`ea9a97dba`](https://github.com/siderolabs/talos/commit/ea9a97dba38c6ab2de830e3b0c3d202d22bdb668) fix: fall back to external IP when discovering nodes in upgrade-k8s\n* [`0bb7e8a5c`](https://github.com/siderolabs/talos/commit/0bb7e8a5cf8b8f3bf31d9f8c3a85b4153921c126) refactor: split config.Provider into Config & Container\n* [`85d8a1619`](https://github.com/siderolabs/talos/commit/85d8a1619431989eb05cb15ad01a1bc06b0f63e9) chore: bump deps\n* [`39b7a56f0`](https://github.com/siderolabs/talos/commit/39b7a56f01d41d33eb96a0feb6e34d43965a99fd) chore: use 8GiB instead of 10GiB for cloud images\n* [`ff11fd39c`](https://github.com/siderolabs/talos/commit/ff11fd39c723a40c01abe6348f64b1f892856175) fix: race with `udevd` and `mountUserDisks`\n* [`c3fabb982`](https://github.com/siderolabs/talos/commit/c3fabb9829d12353770d6436a1d726b15820ebce) chore: update default image sizes to 10GB for all \"cloud\" images\n* [`10155c390`](https://github.com/siderolabs/talos/commit/10155c390e87898098426600709657fbd51e02e8) feat: enable xfs project quota support, kubelet feature\n* [`eba818564`](https://github.com/siderolabs/talos/commit/eba81856427dd3f6c0cf317f027e63d65a079029) release(v1.5.0-alpha.0): prepare release\n* [`383471c3e`](https://github.com/siderolabs/talos/commit/383471c3e956ff6e077a1de75b02a50835fbf352) feat: update default Kubernetes to v1.27.2\n* [`8f68d1abe`](https://github.com/siderolabs/talos/commit/8f68d1abeff83c3ff0e6c5d9f61cb14807b44ca5) chore: bump deps\n* [`e0c1585d3`](https://github.com/siderolabs/talos/commit/e0c1585d3047ef213134331dc57f8e2e8c23a93d) feat: create azure community gallery image version on release\n* [`dd8336c9e`](https://github.com/siderolabs/talos/commit/dd8336c9ee7f8a3a44d45c9f9e3cbbf741f84c44) fix: refresh kubelet self-issued serving certificates\n* [`bb02dd263`](https://github.com/siderolabs/talos/commit/bb02dd263cbc5e7e3839148d86a4a0a5f7ea998b) chore: drop deprecated stuff for Talos 1.5\n* [`61cad8673`](https://github.com/siderolabs/talos/commit/61cad86731e5c0aa80d7df41ea02d0b7ff579c45) chore: bump deps\n* [`01dfd3af7`](https://github.com/siderolabs/talos/commit/01dfd3af7d64dacd179d17d9d5eaf4bc44cf72af) feat: update etcd to v3.5.9\n* [`aa65fbb8a`](https://github.com/siderolabs/talos/commit/aa65fbb8a1752a70e7bac4e4e9872f35e88d1cc9) chore: update KUBECTL_URL to reflect the community bucket\n* [`cc3128d94`](https://github.com/siderolabs/talos/commit/cc3128d944abacfb633bc783b7fed6d0a6f80661) chore: bump kernel to 6.1.28\n* [`97fffaf78`](https://github.com/siderolabs/talos/commit/97fffaf78a0b9a1dc67709de11d37ea20aefde59) chore: use ctest.UpdateWithConflicts instead of plain UpdateWithConflicts\n* [`3b36993b9`](https://github.com/siderolabs/talos/commit/3b36993b9926392f4290e6fabc82e635f4c98149) fix: rlimit nofile test\n* [`45e6e27af`](https://github.com/siderolabs/talos/commit/45e6e27af75746fd0cc8b0f98a2d14579eb0ed40) chore: bump runtime\n* [`4f720d465`](https://github.com/siderolabs/talos/commit/4f720d46532af39165fc5051052d5c42595d91af) fix: revert: set rlimit explicitly in wrapperd\n* [`a2565f674`](https://github.com/siderolabs/talos/commit/a2565f67416e9b9bc22f2d5506df9ea7771c0c8c) fix: set rlimit explicitly in wrapperd\n* [`cdfc242b8`](https://github.com/siderolabs/talos/commit/cdfc242b8354f4cc4e7ce51bbe3a8fb20b35995d) chore: re-enable Go buildid\n* [`e67f3f5c5`](https://github.com/siderolabs/talos/commit/e67f3f5c5453f947355194ea9656c15ff008c35e) feat: linux 6.1.27, containerd 1.6.21, go 1.20.4\n* [`55ae59a0a`](https://github.com/siderolabs/talos/commit/55ae59a0ad71293676b3efed461f5ab98101401a) fix: properly skip/cleanup controlplane configs for workers\n* [`64eade9bd`](https://github.com/siderolabs/talos/commit/64eade9bde271bce4e629e6ac09407c8c42e01be) chore: clean up unused constant\n* [`62c6e9655`](https://github.com/siderolabs/talos/commit/62c6e9655cb639d4993aaa4c9b364342688599cb) feat: introduce siderolink config resource & reconnect\n* [`860002c73`](https://github.com/siderolabs/talos/commit/860002c7352bedd10845e11da37c80685ff0e720) fix: don't reload control plane pods on cert SANs changes\n* [`d43c61e80`](https://github.com/siderolabs/talos/commit/d43c61e80f5b05b81f2a021cdfe012e500c3d98e) fix: enforce nolock option for all NFS mounts by default\n* [`339986db9`](https://github.com/siderolabs/talos/commit/339986db9d3675b78ce0d268f799ad654862fb0f) fix: inhibit timer to follow kubelet timer\n* [`cbf6dc100`](https://github.com/siderolabs/talos/commit/cbf6dc1009ad47a2804774839e4e0301efa8ac78) fix: set timeout for unmount calls\n* [`b58f913d5`](https://github.com/siderolabs/talos/commit/b58f913d5f4b8ecf39be183d0bafe1109f0f0737) fix: set the static pod priority as values\n* [`f8a7a5b6b`](https://github.com/siderolabs/talos/commit/f8a7a5b6bf4138a33cbe5c9afe85db99de167aec) docs: add information about KubeSpan ports and topology\n* [`2bad74d64`](https://github.com/siderolabs/talos/commit/2bad74d6423c083ec34f1b422f23b0024d5f8798) docs: add how to on scaling down\n* [`7442ff8b0`](https://github.com/siderolabs/talos/commit/7442ff8b095ef1337f54332a71d08053a2832144) chore: fix typos inteface -> interface (docs and tests)\n* [`d4e94f7a1`](https://github.com/siderolabs/talos/commit/d4e94f7a15acf7f3c9e7532b067cdacd0e805bec) fix: add back required TARGETARCH for installer\n* [`e6fffda01`](https://github.com/siderolabs/talos/commit/e6fffda01385a2daaa901a5742f30a4edc9186a7) chore: linux 6.1.26, runc 1.1.7\n* [`344746ae2`](https://github.com/siderolabs/talos/commit/344746ae2fa038b704d02fec04c3d358762fe938) fix: bump max inhibit delay to 20 min\n* [`d9bdea2b5`](https://github.com/siderolabs/talos/commit/d9bdea2b54772f067783ee64eb85c834957d386a) chore: fork docs and compatibility modules for Talos 1.5\n* [`3d99610fc`](https://github.com/siderolabs/talos/commit/3d99610fc9b0d0084be822be29bb1bf2fbe85833) docs: document building, verifying image and process caps\n* [`014008ea2`](https://github.com/siderolabs/talos/commit/014008ea25208afbeabb42ef89238802705ad4e0) fix: udevd rules trigger\n* [`9b36bb613`](https://github.com/siderolabs/talos/commit/9b36bb613b44f182e47ae63bc74e4a8b6342d68d) feat: update Linux to 6.1.25, fix virtio on arm64\n* [`08ec66c55`](https://github.com/siderolabs/talos/commit/08ec66c55ccca3f9aa82a9703ebf183913b19a7e) feat: clean up (garbage collect) system images which are not referenced\n* [`b097efcde`](https://github.com/siderolabs/talos/commit/b097efcde29c20cdc4fed23fe8366bd683db634c) fix: display correct number of machines on dashboard\n* [`cad43f0ad`](https://github.com/siderolabs/talos/commit/cad43f0ad3bc2ede8a6ae81767c9226b6bc69f19) chore: remove k8s master label\n* [`e296a566e`](https://github.com/siderolabs/talos/commit/e296a566e6efb0cbdd119e73aff1feaa772d38bd) fix: support kernel userspace module loading\n* [`103f0ffdd`](https://github.com/siderolabs/talos/commit/103f0ffdd3ebd57a5086852f3502a8a7d4428faa) feat: add startup probes to controller-manager and scheduler\n* [`5a1ae8aae`](https://github.com/siderolabs/talos/commit/5a1ae8aae89e54d5540586d6f2e99ef3e80a72eb) chore: bump dependences\n* [`ec8c8dbaf`](https://github.com/siderolabs/talos/commit/ec8c8dbafcdaf63d036bdba92fa153d4d1c90100) chore: fix container image reproducibility\n* [`f661d8487`](https://github.com/siderolabs/talos/commit/f661d84877e6db5bc8856b982990926dcbfe949c) fix: allow `talosctl cp` to handle special files in `/proc`\n* [`2d824b563`](https://github.com/siderolabs/talos/commit/2d824b5639a4b8c3b673d13b08b2b97c69aafe0d) fix: do not show control plane status for workers on dashboard\n* [`e5491ddad`](https://github.com/siderolabs/talos/commit/e5491ddadeb1776bd5c17dd35917e05ec4847d0f) docs: update documentation for nocloud\n* [`7a004a6f7`](https://github.com/siderolabs/talos/commit/7a004a6f7f47fa5d17e855eb02650754d8411574) fix: parse errors correctly\n* [`374ef5385`](https://github.com/siderolabs/talos/commit/374ef53853947811dc221d99751cf0e16294508c) test: submit verbose flag to e2e tests\n* [`e1d38b6fe`](https://github.com/siderolabs/talos/commit/e1d38b6febf26fe31a6b9d6ed8f9b6bdba29aa3b) feat: show template URL in dashboard config URL tab\n* [`45d7f0ce9`](https://github.com/siderolabs/talos/commit/45d7f0ce95454ce85c403fc493ddb97e4d478238) docs: fix the latest url\n* [`96efbf147`](https://github.com/siderolabs/talos/commit/96efbf14769579d514ef9c75d01d9f44d276113a) docs: activate 1.4.0 docs by default\n* [`8c1f515b1`](https://github.com/siderolabs/talos/commit/8c1f515b1b8e40bce42e2fc04755afe5bf8a56aa) feat: update Linux to 6.1.24\n* [`8689bef5f`](https://github.com/siderolabs/talos/commit/8689bef5f10839091cf131edb6c8efad4ccba034) docs: update documentation for Talos 1.4\n* [`a781dfb8e`](https://github.com/siderolabs/talos/commit/a781dfb8e3ded67edcb2a6a1048bfe76c6bd0d24) feat: update Kubernetes to 1.27.1\n* [`a737dd83a`](https://github.com/siderolabs/talos/commit/a737dd83a4cd7549f85f8df0882f1c9a4446060d) chore: typo in `compatibility.ParseKubernetesVersion`\n* [`f14928b0a`](https://github.com/siderolabs/talos/commit/f14928b0a9dd3d85664605f4f6a206236ea94614) fix: fix dashboard crash when a non-existent node is specified\n* [`3e406d9b0`](https://github.com/siderolabs/talos/commit/3e406d9b07c0e67a2fb61e612bc3f378f3c35247) feat: update etcd to v3.5.8\n* [`bd1cff3e8`](https://github.com/siderolabs/talos/commit/bd1cff3e83530b9b89b27d8083ea8f3f0cf6ede4) chore: remove Go buildid\n* [`e31f7f50b`](https://github.com/siderolabs/talos/commit/e31f7f50b1b455beb98cd25859a44bbbccc1ff64) feat: update Kubernetes to 1.27.0\n* [`aa3640d74`](https://github.com/siderolabs/talos/commit/aa3640d74ce2e3619476453381909fa3520eb87d) docs: update storage.md\n* [`07bb61e60`](https://github.com/siderolabs/talos/commit/07bb61e60c53b267756dc97874b9c9554f2b1486) chore: module-sig-verify cleanup\n* [`5e9d836c3`](https://github.com/siderolabs/talos/commit/5e9d836c3d075c3edb2d48b2868c31a1c963e2de) chore: add kernel module signtaure verification\n* [`3cd1c6bb0`](https://github.com/siderolabs/talos/commit/3cd1c6bb0b83e5747a7356140a44b16deb4727e6) fix: send 'STOP' event on phase end\n* [`5176d27dc`](https://github.com/siderolabs/talos/commit/5176d27dc566d8689bb305398da7250269ebe9a3) feat: update Kubernetes to 1.27.0-rc.1\n* [`2c55550a6`](https://github.com/siderolabs/talos/commit/2c55550a66b49b49d8dc95b83516b7c0f8107300) fix: quote ISO kernel args for GRUB\n* [`319d76e38`](https://github.com/siderolabs/talos/commit/319d76e38978406d8d37e89ada2c403969d6c972) fix: respect BROWSER=echo in client auth interceptor\n* [`4e4ace839`](https://github.com/siderolabs/talos/commit/4e4ace839c0f558e7b00979fa4c64c32985aa3ce) chore: update Go to 1.20.3\n* [`170f73899`](https://github.com/siderolabs/talos/commit/170f73899a3bf29e9c6f76fdc5e510be08edf4aa) fix: correctly parse static pod phase\n* [`c3a595d5b`](https://github.com/siderolabs/talos/commit/c3a595d5b7d3c7c3091229caef6b2553416edb56) fix: improve action tracking post checks\n* [`eb01edbc8`](https://github.com/siderolabs/talos/commit/eb01edbc8a0ef5810693afe450861d5b63877b72) fix: rework DHCP flow\n* [`e095150a6`](https://github.com/siderolabs/talos/commit/e095150a6e34cbdc805a2cac85ec7f28f98629b4) test: bump CAPI components versions\n</p>\n</details>\n\n### Changes since v1.5.0-alpha.1\n<details><summary>50 commits</summary>\n<p>\n\n* [`60c304126`](https://github.com/siderolabs/talos/commit/60c304126fce95fd4995c416e7757f85505b90fb) chore: bump dependencies\n* [`9ef4e5efc`](https://github.com/siderolabs/talos/commit/9ef4e5efca4b537a550a5e902fc2479ebb5e53e3) fix: log explicitly when kubelet has no nodeIP match\n* [`6b39c6a4d`](https://github.com/siderolabs/talos/commit/6b39c6a4d326752f92d98388bbb418f2e50d3ddb) fix: enable compression and bump gRPC max msg size\n* [`2f2eca861`](https://github.com/siderolabs/talos/commit/2f2eca86175fe98b3bf491f38ff907599333b139) chore: basic support for shutdown/poweroff flags\n* [`b84277d7d`](https://github.com/siderolabs/talos/commit/b84277d7dc50b196b7cd27e7f2ceff6bf8f58a8d) docs: fix wrong capability name\n* [`59d7d9344`](https://github.com/siderolabs/talos/commit/59d7d9344b27529af420ec31c7b599027cda044f) chore: use machined for `shutdown`, `poweroff`\n* [`2439bfb71`](https://github.com/siderolabs/talos/commit/2439bfb719d9f50107cee500d03c90bd50649e05) chore: explicitly add timestamps to machined logs\n* [`14966e718`](https://github.com/siderolabs/talos/commit/14966e718a07906ff389ecdda063fd16b22baab9) fix: skip over tpm2 1.2 devices\n* [`6716e7bc0`](https://github.com/siderolabs/talos/commit/6716e7bc0ba6da31b8bc19aa4bd5edb7749b39a1) docs: update cilium documentation about KubePrism usage\n* [`166d75fe8`](https://github.com/siderolabs/talos/commit/166d75fe888d334349f57dcf405b6867ca5305e2) fix: tpm2 encrypt/decrypt flow\n* [`130518de7`](https://github.com/siderolabs/talos/commit/130518de71ae96cdf7d733a35e4c306940e1b845) chore: change missing renames of KubePrism\n* [`5f34f5b41`](https://github.com/siderolabs/talos/commit/5f34f5b41f03d6d455d7b843084d2951c365a7ee) chore: rename api load balancer to KubePrism\n* [`c8b7095c0`](https://github.com/siderolabs/talos/commit/c8b7095c01f597cd8b41964b42aa7e35c85ae307) refactor: use tpm2 library to calculate policy hash\n* [`078aac92e`](https://github.com/siderolabs/talos/commit/078aac92ee30c9666235219d4623b82d66362d4d) chore: bump deps\n* [`53873b844`](https://github.com/siderolabs/talos/commit/53873b8444acaa97d85c50caec625b9dbfdfef93) refactor: move ukify into Talos code\n* [`d5f6fb9ff`](https://github.com/siderolabs/talos/commit/d5f6fb9ff2980df03365719d9e2690cb5ac788af) chore: add vendor info\n* [`79365d9ba`](https://github.com/siderolabs/talos/commit/79365d9bacf0e8a6660cdc6b7172c79edf5f3ba3) feat: tpm2 based disk encryption\n* [`06369e819`](https://github.com/siderolabs/talos/commit/06369e8195e76f96d232d077efb2bfb059b7aa96) fix: retry CRI pod removal, fix upgrade flow in the tests\n* [`d32dd3a82`](https://github.com/siderolabs/talos/commit/d32dd3a820b07d58ca89c4226c986d87ff0e2b65) chore: update Go to 1.20.6\n* [`8017afb10`](https://github.com/siderolabs/talos/commit/8017afb107b901a8785bccaac65d63f34e506568) feat: implement CRI image management and pre-pull on K8s upgrade\n* [`1c2f19b36`](https://github.com/siderolabs/talos/commit/1c2f19b367af8b04fc49174540e5b141f4b34156) feat: update Kubernetes to 1.28.0-alpha.4\n* [`94e9891c1`](https://github.com/siderolabs/talos/commit/94e9891c1bb44a1e7c285b4ccf1fad59ea05aa62) chore: bump sd-boot to v254-rc1\n* [`936111ce0`](https://github.com/siderolabs/talos/commit/936111ce062d23ed11b30ea35585c0519260f9c5) fix: properly set up tls for KMS endpoint\n* [`cb226eec4`](https://github.com/siderolabs/talos/commit/cb226eec46b59372c684c3946e0ba0910066573d) fix: rewrite encryption system information flow\n* [`3206db528`](https://github.com/siderolabs/talos/commit/3206db52895416d1eb936caa4e953312b34b8549) feat: drop tpm simulator for ukify measure\n* [`bd4f89f63`](https://github.com/siderolabs/talos/commit/bd4f89f6338423a79b7ce89bda1bd6704caaae59) fix: disable dashboard on Azure, GCP and Scaleway\n* [`bdb96189f`](https://github.com/siderolabs/talos/commit/bdb96189faadc48e93146f9fd7b03e006bf1dd75) refactor: make maintenance service controller-based\n* [`d23d04de2`](https://github.com/siderolabs/talos/commit/d23d04de2a5dee30ccf21efe767daf229de78bdb) feat: seed the kernel random pool from the TPM\n* [`c81ce8cfb`](https://github.com/siderolabs/talos/commit/c81ce8cfb0bc7df66ffd1e1819b64dad6357d890) feat: support controlplane resources configuration\n* [`74de562b2`](https://github.com/siderolabs/talos/commit/74de562b29c748fda3140871ea3fab99698341ef) fix: mount hugepages with nosuid + nodev\n* [`ce63abb21`](https://github.com/siderolabs/talos/commit/ce63abb219a2fd4a9d3fdd93a13c343af123efc2) feat: add KMS assisted encryption key handler\n* [`dafbe9deb`](https://github.com/siderolabs/talos/commit/dafbe9debdee2b015ed574ac4f5f722bce997b31) chore: optimize dockerfile instructions\n* [`a4289e870`](https://github.com/siderolabs/talos/commit/a4289e8703d9f9e52b739b19b5b38e30a75a1454) chore: fix CLI docs generation stability\n* [`2fec8388f`](https://github.com/siderolabs/talos/commit/2fec8388fc2fe3058b7b6f141ce9eae2c6a8268f) chore: bump dependencies\n* [`c1b4262dd`](https://github.com/siderolabs/talos/commit/c1b4262dd60f6cbea6d46a8d0433499bf6365b36) docs: split simple and more complex getting started guides\n* [`c9a9f9561`](https://github.com/siderolabs/talos/commit/c9a9f95611e38cf5c298f0d9fb0890a9bc0f8b98) refactor: extract secure boot certificate generation\n* [`6be5a13d5`](https://github.com/siderolabs/talos/commit/6be5a13d5d8341c58d0d2fe75c49ba1de9bf7316) feat: implement machine config documents for event and log streaming\n* [`e241be85b`](https://github.com/siderolabs/talos/commit/e241be85ba748163268eaeed2a88c8e295f84b28) fix: properly handle YAML comment stripping for multi-doc\n* [`c02ada7d9`](https://github.com/siderolabs/talos/commit/c02ada7d952255bffe67b3c84f1f832253e1a3b5) fix: capabilities including `ALL` should be uppercase\n* [`cbdf96d46`](https://github.com/siderolabs/talos/commit/cbdf96d461ec0cf8929c2c76614081ef042dda31) feat: support environment file for extensions\n* [`35d6adcb9`](https://github.com/siderolabs/talos/commit/35d6adcb9ad7e9420a5bcdfcf3378a05c0b65d46) fix: provide stashed META values before installation\n* [`258f07449`](https://github.com/siderolabs/talos/commit/258f07449050d69c369fdc71ac613a1a225807bf) fix: ukify cert generation\n* [`bf3febb7e`](https://github.com/siderolabs/talos/commit/bf3febb7e2bf3ebf1bd66ee088f3885a178c953c) fix: refine OVMF search paths\n* [`fbebc17f8`](https://github.com/siderolabs/talos/commit/fbebc17f8be7a3ca6c45c3c84d306e52c47d441d) fix: disable LVM backups/archive\n* [`e5306ef26`](https://github.com/siderolabs/talos/commit/e5306ef2637dd2eb7464691b55159a43933c7419) chore: format and cleanup test scripts\n* [`bc371ecfd`](https://github.com/siderolabs/talos/commit/bc371ecfdafe51f8cf34461caf9e6f51c0a93108) chore: add `/sbin/shutdown`\n* [`0d313b973`](https://github.com/siderolabs/talos/commit/0d313b973367906b2fd4bcad4b2def79344dbd67) feat: add `reboot-mode` flag to `talosctl upgrade`\n* [`7ce87f20c`](https://github.com/siderolabs/talos/commit/7ce87f20c39c615f4d23a3be23780a36008dcb19) fix: compare only basename of `os.Args[0]` in machined\n* [`53389b1e7`](https://github.com/siderolabs/talos/commit/53389b1e724751e28046167b44f05c6ecf06f184) feat: auto-enroll secure boot keys\n* [`d77f0bc7b`](https://github.com/siderolabs/talos/commit/d77f0bc7bbe01b7fc8efa21a7c57d73ecb94a01f) docs: fix broken link to powershell module\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`8f77da3`](https://github.com/siderolabs/crypto/commit/8f77da30a5193d207a6660b562a273a06d73aae0) feat: add a method to load PEM key from file\n* [`c03ff58`](https://github.com/siderolabs/crypto/commit/c03ff58af5051acb9b56e08377200324a3ea1d5e) feat: add a way to represent redacted x509 private keys\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e3db3c`](https://github.com/siderolabs/discovery-api/commit/5e3db3c1a656ebdc717494e5384f10c7b11eef0f) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`9ba5f03`](https://github.com/siderolabs/discovery-client/commit/9ba5f033a47d41448153962c5fe22db2d9a8a00c) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`f415aac`](https://github.com/siderolabs/extras/commit/f415aac20c245592612a02157d247cb2dd4a5d45) feat: update Go to 1.20.6\n* [`a73d524`](https://github.com/siderolabs/extras/commit/a73d5243f443fd32376780bf2a4f97b08f28917c) feat: update Go to 1.20.5\n* [`36c8ac4`](https://github.com/siderolabs/extras/commit/36c8ac4ab98300059acaad501c2adc8abd39179f) chore: update to Go 1.20.3\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`f9f5805`](https://github.com/siderolabs/gen/commit/f9f5805973d30fe6bbac2f4a79ad4197fe59970e) chore: bump rekres and add functions from exp\n* [`b968d21`](https://github.com/siderolabs/gen/commit/b968d21c9671d97e54317f80cdf781d6f963e44b) feat: add `TryRecv` and `RecvWithContext` functions\n* [`476dfea`](https://github.com/siderolabs/gen/commit/476dfeae70882e1ca6e5cfed3d6e12dc36841a26) feat: add foreach and clear to lazymap\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>4 commits</summary>\n<p>\n\n* [`fbb01f7`](https://github.com/siderolabs/go-blockdevice/commit/fbb01f714bdc9c32ea3459345b730b1043ce10c0) fix: properly detect token not found error\n* [`3e08968`](https://github.com/siderolabs/go-blockdevice/commit/3e089682439e885c6386f833e35728ce54daff44) fix: do not attach token to a key slot\n* [`f2c419e`](https://github.com/siderolabs/go-blockdevice/commit/f2c419e81dcba3c5be007130f677d2075e2aec3c) feat: support LUKS token management\n* [`076874a`](https://github.com/siderolabs/go-blockdevice/commit/076874a155ad44d764d25081125f950e8194d023) chore: resolve blockdevice symlinks\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>1 commit</summary>\n<p>\n\n* [`43d9100`](https://github.com/siderolabs/go-debug/commit/43d9100eba3a30ff0d7f1bed0058e6631243cc47) chore: allow enabling pprof manually\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>2 commits</summary>\n<p>\n\n* [`69fea5b`](https://github.com/siderolabs/go-kubernetes/commit/69fea5b840fb51aa08e5fbf380fa924b9d444094) feat: support upgrades to Kubernetes 1.28\n* [`5a3df5b`](https://github.com/siderolabs/go-kubernetes/commit/5a3df5b002d74ba9f4d773dc1278047481b1d4ba) fix: remove removed APIs for 1.27 upgrade\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>6 commits</summary>\n<p>\n\n* [`574126c`](https://github.com/siderolabs/go-loadbalancer/commit/574126cbf0e1e45a06cabaf602e5070dd7d441e2) chore: add 0.1ms tier and fix tiers\n* [`5301800`](https://github.com/siderolabs/go-loadbalancer/commit/5301800a874e853d97f8e12195558f79c97c0beb) chore: fix logging and tests\n* [`b23a173`](https://github.com/siderolabs/go-loadbalancer/commit/b23a1733aa9b303bda82175b4f5e9f8a4765a27b) chore: replace std log with zap\n* [`1a2f374`](https://github.com/siderolabs/go-loadbalancer/commit/1a2f374df7804dffe683e8be90e9829f2dfb5e95) feat: add multi-tier scoring based for generic List\n* [`56a27da`](https://github.com/siderolabs/go-loadbalancer/commit/56a27da7083139b71898f4f9207dc40088e8c815) chore: move to siderolabs/tcpproxy of inet.af/tcpproxy\n* [`f3a0e24`](https://github.com/siderolabs/go-loadbalancer/commit/f3a0e2411e08eef9c79876f3dc6e09e770710379) fix: use SO_LINGER option when doing TCP healthchecks\n</p>\n</details>\n\n### Changes from siderolabs/kms-client\n<details><summary>3 commits</summary>\n<p>\n\n* [`50064b6`](https://github.com/siderolabs/kms-client/commit/50064b67ac73c0a3f6f89c6a44ef914711107df0) fix: pass context to the key handler in the server wrapper\n* [`83e0a2e`](https://github.com/siderolabs/kms-client/commit/83e0a2ec6b06668940ec31d64491d9b8a630524b) feat: define API and add reference implementation for KMS server\n* [`8c37ee8`](https://github.com/siderolabs/kms-client/commit/8c37ee83099a6563197c89166b0ea596eebf0598) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>38 commits</summary>\n<p>\n\n* [`d0eaedc`](https://github.com/siderolabs/pkgs/commit/d0eaedcb5cd2510925e4609369e25c3e3572d5fe) feat: enable DM_RAID kernel config\n* [`d5e0fad`](https://github.com/siderolabs/pkgs/commit/d5e0fad0d59dfb8d2386ab2ad6c7df749e0b9413) feat: update dependencies\n* [`c644633`](https://github.com/siderolabs/pkgs/commit/c644633324ed1e56ab19f146c04ed3984736a88a) feat: enable multi-gen lru by default\n* [`75696ba`](https://github.com/siderolabs/pkgs/commit/75696ba81581ef0f1af668db565a08950145e45d) feat: update Go to 1.20.6\n* [`205cab6`](https://github.com/siderolabs/pkgs/commit/205cab6d0e6be2721c5338bef232e3345d3a299f) chore: feat use new sd-boot\n* [`fb817fe`](https://github.com/siderolabs/pkgs/commit/fb817fe20789ca48895275e1877808a9206630dd) fix: enable USB attached SCSI driver on x86 systems\n* [`43451e6`](https://github.com/siderolabs/pkgs/commit/43451e68a0ddf634b90c7c12cca9437faa52d183) chore: bump dependencies\n* [`eca94f8`](https://github.com/siderolabs/pkgs/commit/eca94f8f1b9c3ceb62efb53fd1260d49ce17f1dd) feat: enable sriov\n* [`5a8e8e5`](https://github.com/siderolabs/pkgs/commit/5a8e8e594248847bb606ca07b3ea29e187e20d26) feat: enable VMWARE/HYPERV vsockets\n* [`edd725a`](https://github.com/siderolabs/pkgs/commit/edd725a0f9d07d39256d98a67be5dc4c56631078) chore: bump deps\n* [`c0ac69b`](https://github.com/siderolabs/pkgs/commit/c0ac69b70cfac3cdcf100a35f6d766c5ae47d950) feat: enable CONFIG_NVME_{MULTIPATH|AUTH}\n* [`f7cd916`](https://github.com/siderolabs/pkgs/commit/f7cd916b47975e61c6732079c1c5c4684dfb8c96) fix: bump drbd to 9.2.4\n* [`a56d15a`](https://github.com/siderolabs/pkgs/commit/a56d15ad626b6e76a137636d6088361be9a73a9f) fix: copy missing `modules.*` files\n* [`1eefa66`](https://github.com/siderolabs/pkgs/commit/1eefa664fc7c65491e956a6f403ada774e73a7d3) feat: build isb modem drivers as module\n* [`a859f4f`](https://github.com/siderolabs/pkgs/commit/a859f4fb257e17fa19b1c10efcae594d33a86618) fix: build RDMA_RXE as a module\n* [`5fb5e95`](https://github.com/siderolabs/pkgs/commit/5fb5e9517de9fe35e383b96e92fa873aa045a845) feat: bump dependencies\n* [`39a64b2`](https://github.com/siderolabs/pkgs/commit/39a64b23e2c8689c44b9891b1e70149b8d003655) feat: update Linux to 6.1.31, add GENEVE for arm64\n* [`97177be`](https://github.com/siderolabs/pkgs/commit/97177be803cc91c8fabccfec575b7d920bc78c38) feat: update Linux to 6.1.30\n* [`b1f9d4e`](https://github.com/siderolabs/pkgs/commit/b1f9d4e717fbd0132b820d45c226ca643d7f577e) chore: prevent unsigned kexec with secureboot\n* [`9232a42`](https://github.com/siderolabs/pkgs/commit/9232a425b85b1058cd38eab30304f6cf243ab32c) feat: add reproducibility pipelines\n* [`702d7a7`](https://github.com/siderolabs/pkgs/commit/702d7a7e90099d8fdc9cc4ba50e86c8ba6e91d77) chore: bump deps\n* [`7958db1`](https://github.com/siderolabs/pkgs/commit/7958db1549a7c7560eeeb8f9c06d3be9487d8804) chore: copy over sd-boot and sd-stub from tools\n* [`813b3c3`](https://github.com/siderolabs/pkgs/commit/813b3c3d3276d0d9156919307e9ffe521925d40b) chore: revert xfsprogs\n* [`0cc78ab`](https://github.com/siderolabs/pkgs/commit/0cc78ab82ce920c8fa5654c73738050107e190bb) chore: bump kernel to 6.1.28\n* [`70189e3`](https://github.com/siderolabs/pkgs/commit/70189e3df555fed4afade93798d72cd31aad99c5) chore: bump deps\n* [`c5d3bf1`](https://github.com/siderolabs/pkgs/commit/c5d3bf1985b49e688d29d06db6730834f65ee480) feat: add sd-stub and sd-boot\n* [`30a7ac2`](https://github.com/siderolabs/pkgs/commit/30a7ac2974fb7580e83819c76502fde77d777ea0) feat: update Linux 6.1.27, containerd 1.6.21\n* [`fbc6ee5`](https://github.com/siderolabs/pkgs/commit/fbc6ee55b6ffae44c117255901ab0fbecae79cc3) chore: bump deps\n* [`82b9489`](https://github.com/siderolabs/pkgs/commit/82b9489b88b108f144b45fb55432576bfd767f91) chore: bump dependencies\n* [`f37e520`](https://github.com/siderolabs/pkgs/commit/f37e5205cf10fe10296e86565fa018d149f5d8c4) feat: update Linux to 6.1.25\n* [`3920b16`](https://github.com/siderolabs/pkgs/commit/3920b163a5c6a6d7c7969155a909a7b2122e65f6) feat: add multi-gen LRU kernel support\n* [`988f1ec`](https://github.com/siderolabs/pkgs/commit/988f1ecf95536fb259cbd79e044a556728bc7332) feat: update Linux to 6.1.24\n* [`5327d12`](https://github.com/siderolabs/pkgs/commit/5327d1263680f76706ea667906ca08222c8398da) fix: remove FB_NVIDIA drivers, Linux 6.1.23\n* [`4eae958`](https://github.com/siderolabs/pkgs/commit/4eae958770573613bc29568d130be7aaa775e530) chore: copy over the kernel signing public key\n* [`174f8fc`](https://github.com/siderolabs/pkgs/commit/174f8fc9c80d871f1c03ea0a53dc8b6eb7112ccf) chore: update Go to 1.20.3\n* [`41629b0`](https://github.com/siderolabs/pkgs/commit/41629b03e82bfb77623a812000ef8e98d15d56fa) chore: reorder pkgs for better kernel caching\n* [`b483a6b`](https://github.com/siderolabs/pkgs/commit/b483a6b01f539b0da13ca09882015044bff24e41) feat: build 'snp.efi' for iPXE\n* [`fb853ff`](https://github.com/siderolabs/pkgs/commit/fb853ff6b1194cdc1f2412c776347cf4b55c3336) feat: update containerd to 1.6.20\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>20 commits</summary>\n<p>\n\n* [`dc7dd9e`](https://github.com/siderolabs/tools/commit/dc7dd9e5b949f6f5d7626f11cb3b001526e8d1de) chore: remove libseccomp\n* [`e27c249`](https://github.com/siderolabs/tools/commit/e27c249c3213af6d12be4fb440a8f896c8e1b3d4) feat: update Go to 1.20.6\n* [`9b6d512`](https://github.com/siderolabs/tools/commit/9b6d5123fa1e28160019a4b6e8b0f04482c49dc0) feat: use systemd 254-rc1\n* [`cd3b692`](https://github.com/siderolabs/tools/commit/cd3b692b0cf5c663548cbe75db43036e11ee1014) chore: bump deps\n* [`c1027a6`](https://github.com/siderolabs/tools/commit/c1027a63d058b77f6cce7351fa7b63d4c94883ad) chore: remove sbsign\n* [`e0c76c0`](https://github.com/siderolabs/tools/commit/e0c76c096d06ef11afdb54287d5f15add108399b) chore: bump dependencies\n* [`7d0cd58`](https://github.com/siderolabs/tools/commit/7d0cd58b34bba6b9415db5e39bed351e7f00d44d) feat: update Go to 1.20.5\n* [`150efc2`](https://github.com/siderolabs/tools/commit/150efc22508043bfadc9d84a8c3c5fee6c2aac5f) chore: remove non needed tools\n* [`88ebb40`](https://github.com/siderolabs/tools/commit/88ebb40dd348b6c9e4dc5551b616e4a1892b4e42) feat: add swtpm\n* [`4c5d7fe`](https://github.com/siderolabs/tools/commit/4c5d7feb88dcbae2f7bf45f51f9e5e1ba339abac) chore: use same source epoch everywhere\n* [`2e46e5b`](https://github.com/siderolabs/tools/commit/2e46e5be764f8180a0762a5ab080ccff04534a8a) feat: add reproducibility pipelines\n* [`c6a41b6`](https://github.com/siderolabs/tools/commit/c6a41b6c5108d676f8573d3dd47ee29ae46e5cc0) fix: add sd-stub assertion patch\n* [`d2dde48`](https://github.com/siderolabs/tools/commit/d2dde48f72343aa3c541336f5319b8e649e80c87) chore: bump deps\n* [`8e45ad7`](https://github.com/siderolabs/tools/commit/8e45ad75ea78e353ca3eae21b18da9a42d1edf49) feat: add sbsign\n* [`271c4a6`](https://github.com/siderolabs/tools/commit/271c4a66b6987d9de2c0d1d69891b5ff277ebd43) feat: add sd-tools\n* [`eedc294`](https://github.com/siderolabs/tools/commit/eedc294967d415cca40d4c427d3521cd198661d7) chore: bump deps\n* [`81b09a5`](https://github.com/siderolabs/tools/commit/81b09a5ab204f16306c980eeff518a0d1a37ddf2) feat: add libcap and gnuefi\n* [`47b0fd3`](https://github.com/siderolabs/tools/commit/47b0fd3e364d4fbcfffe10965f740db7acd82f70) chore: bump go to 1.20.4\n* [`ff4cf2b`](https://github.com/siderolabs/tools/commit/ff4cf2beabab310365ad9887abb6234570f5092a) chore: bump deps\n* [`1563556`](https://github.com/siderolabs/tools/commit/1563556b8f8fdf20d8aa58ac5340104c7ffe732e) feat: update Go to 1.20.3\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/BurntSushi/toml**                     v1.2.1 -> v1.3.2\n* **github.com/aws/aws-sdk-go**                      v1.44.232 -> v1.44.304\n* **github.com/beevik/ntp**                          v0.3.0 -> v1.2.0\n* **github.com/benbjohnson/clock**                   v1.1.0 -> v1.3.5\n* **github.com/cenkalti/backoff/v4**                 v4.2.0 -> v4.2.1\n* **github.com/containerd/containerd**               v1.6.19 -> v1.6.21\n* **github.com/containerd/typeurl/v2**               v2.1.1 **_new_**\n* **github.com/containernetworking/plugins**         v1.2.0 -> v1.3.0\n* **github.com/cosi-project/runtime**                v0.3.0 -> v0.3.1-alpha.8\n* **github.com/docker/distribution**                 v2.8.1 -> v2.8.2\n* **github.com/docker/docker**                       v23.0.2 -> v24.0.4\n* **github.com/ecks/uefi**                           caef65d070eb **_new_**\n* **github.com/emicklei/dot**                        v1.4.2 -> v1.5.0\n* **github.com/foxboron/go-uefi**                    32187aa193d0 **_new_**\n* **github.com/google/go-tpm**                       v0.9.0 **_new_**\n* **github.com/hashicorp/go-envparse**               v0.1.0 **_new_**\n* **github.com/hetznercloud/hcloud-go**              v1.41.0 -> v1.48.0\n* **github.com/insomniacslk/dhcp**                   74ae03f2425e -> 5648422c16cd\n* **github.com/jsimonetti/rtnetlink**                v1.3.1 -> v1.3.4\n* **github.com/mattn/go-isatty**                     v0.0.18 -> v0.0.19\n* **github.com/mdlayher/ethtool**                    ba3b4bc2e02c -> v0.1.0\n* **github.com/mdlayher/genetlink**                  v1.3.1 -> v1.3.2\n* **github.com/mdlayher/netlink**                    v1.7.1 -> v1.7.2\n* **github.com/mdlayher/netx**                       c711c2f8512f -> 7e21880baee8\n* **github.com/nberlee/go-netstat**                  v0.1.1 -> v0.1.2\n* **github.com/opencontainers/go-digest**            v1.0.0 **_new_**\n* **github.com/opencontainers/image-spec**           v1.1.0-rc2 -> v1.1.0-rc4\n* **github.com/packethost/packngo**                  v0.29.0 -> v0.30.0\n* **github.com/prometheus/procfs**                   v0.9.0 -> v0.11.0\n* **github.com/rivo/tview**                          281d14d896d7 -> 6cc0565babaf\n* **github.com/rs/xid**                              v1.4.0 -> v1.5.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.15 -> v1.0.0-beta.19\n* **github.com/siderolabs/crypto**                   v0.4.0 -> v0.4.1\n* **github.com/siderolabs/discovery-api**            v0.1.2 -> v0.1.3\n* **github.com/siderolabs/discovery-client**         v0.1.4 -> v0.1.5\n* **github.com/siderolabs/extras**                   v1.4.0-1-g9b07505 -> v1.5.0-alpha.0-2-gf415aac\n* **github.com/siderolabs/gen**                      v0.4.3 -> v0.4.5\n* **github.com/siderolabs/go-blockdevice**           v0.4.4 -> v0.4.6\n* **github.com/siderolabs/go-debug**                 v0.2.2 -> v0.2.3\n* **github.com/siderolabs/go-kubernetes**            v0.2.0 -> v0.2.2\n* **github.com/siderolabs/go-loadbalancer**          v0.2.1 -> v0.3.2\n* **github.com/siderolabs/kms-client**               v0.1.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.4.1-5-ga333a84 -> v1.5.0-alpha.0-37-gd0eaedc\n* **github.com/siderolabs/talos/pkg/machinery**      v1.4.0 -> v1.5.0-alpha.1\n* **github.com/siderolabs/tools**                    v1.4.0-1-g955aabc -> v1.5.0-alpha.0-19-gdc7dd9e\n* **github.com/spf13/cobra**                         v1.6.1 -> v1.7.0\n* **github.com/stretchr/testify**                    v1.8.2 -> v1.8.4\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.16 -> v0.56.17\n* **github.com/vmware/govmomi**                      v0.30.4 -> v0.30.6\n* **go.etcd.io/etcd/api/v3**                         v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/v3**                      v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.8 -> v3.5.9\n* **golang.org/x/net**                               v0.8.0 -> v0.12.0\n* **golang.org/x/sync**                              v0.1.0 -> v0.3.0\n* **golang.org/x/sys**                               v0.6.0 -> v0.10.0\n* **golang.org/x/term**                              v0.6.0 -> v0.10.0\n* **golang.org/x/text**                              v0.11.0 **_new_**\n* **golang.zx2c4.com/wireguard/wgctrl**              9c5414ab4bde -> 925a1e7659e6\n* **google.golang.org/grpc**                         v1.54.0 -> v1.56.2\n* **google.golang.org/protobuf**                     v1.30.0 -> v1.31.0\n* **k8s.io/api**                                     v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/apimachinery**                            v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/apiserver**                               v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/client-go**                               v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/component-base**                          v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/cri-api**                                 v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/klog/v2**                                 v2.90.1 -> v2.100.1\n* **k8s.io/kubectl**                                 v0.27.1 -> v0.28.0-alpha.4\n* **k8s.io/kubelet**                                 v0.27.1 -> v0.28.0-alpha.4\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.68 -> v1.2.69\n\nPrevious release can be found at [v1.4.0](https://github.com/siderolabs/talos/releases/tag/v1.4.0)\n\n## [Talos 1.5.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.5.0-alpha.1) (2023-06-22)\n\nWelcome to the v1.5.0-alpha.1 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Kubernetes API Server In-Cluster Load Balancer\n\nTalos now supports configuring the Kubernetes API Server in-cluster load balancer with machine config\n`features.apiServerBalancerSupport.port` and `features.apiServerBalancerSupport.enabled` fields.\n\nIf enabled, the loadbalancer binds to `localhost` and runs on the same port on every machine in the cluster.\nThe default value for loadbalancer endpoint is https://localhost:7445.\n\nThe in-cluster loadbalancer endpoint is used by the `kubelet`, `kube-scheduler`, `kube-controller-manager`\nand `kube-proxy` by default and can be passed to the CNIs like Cilium and Calico.\n\nThe in-cluster loadbalancer provides access to the Kubernetes API endpoint even if the external loadbalancer\nis not healthy, provided that the worker nodes can reach to the controlplane machine addresses directly.\n\n\n### Predictable Network Interface Names\n\nStarting with version Talos 1.5, network interfaces are renamed to [predictable names](https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/)\nsame way as `systemd` does that in other Linux distributions.\n\nThe naming schema `enx78e7d1ea46da` (based on MAC addresses) is enabled by default, the order of interface naming decisions is:\n\n* firmware/BIOS provided index numbers for on-board devices (example: `eno1`)\n* firmware/BIOS provided PCI Express hotplug slot index numbers (example: `ens1`)\n* physical/geographical location of the connector of the hardware (example: `enp2s0`)\n* interfaces's MAC address (example: `enx78e7d1ea46da`)\n\nThe predictable network interface names features can be disabled by specifying `net.ifnames=0` in the kernel command line.\nTalos automatically adds the `net.ifnames=0` kernel argument when upgrading from Talos versions before 1.5.\n\nThis change doesn't affect \"cloud\" platforms, like AWS, as Talos automatically adds `net.ifnames=0` to the kernel command line.\n\n\n### Machine Config option `.machine.install.bootloader`\n\nThe `.machine.install.bootloader` option in the machine config is deprecated and will be removed in Talos 1.6.\nThis was a no-op for a long time. The bootloader is always installed.\n\n\n### XFS Quota\n\nTalos 1.5+ enables XFS project quota support by default, also enabling by default\nkubelet feature gate `LocalStorageCapacityIsolationFSQuotaMonitoring` to use xfs quotas\nto monitor volume usage instead of `du`.\n\nThis feature is controlled by the `.machine.features.diskQuotaSupport` field in the machine config,\nit is set to true for new clusters.\n\nWhen upgrading from a previous version, the feature can be enabled by setting the field to true.\nOn the first mount of a volume, the quota information will be recalculated, which may take some time.\n\n\n### RDMA/RoCE support\n\nTalos no longer loads by default `rdma_rxe` Linux driver, which is required for RoCE support.\nIf the driver is required, it can be enabled by specifying `rdma_rxe` in the `.machine.kernel.modules` field in the machine config.\n\n\n### SecureBoot\n\nTalos now supports generating a custom iso that can be used with SecureBoot. Key generation and enrolling has to be done manually.\n\n\n### Component Updates\n\n* Linux: 6.1.35\n* containerd: 1.6.21\n* runc: 1.1.7\n* etcd: 3.5.9\n* Kubernetes: 1.27.3\n* Flannel: 0.22.0\n\nTalos is built with Go 1.20.5.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Christian Rolland\n* Nanfei Chen\n* Spencer Smith\n* Steve Francis\n* Alex Corcoles\n* Alex Corcoles\n* Alex Lubbock\n* Budiman Jojo\n* DJAlPee\n* Eirik Askheim\n* Henk Kraal\n* Michael A. Davis\n* Michael Fornaro\n* Nico Berlee\n* Niklas Wik\n* Piotr Maksymiuk\n* Ricky Sadowski\n* Roee Klinger\n* Thomas Perronin\n* Walt Chen\n* bdronneau\n\n### Changes\n<details><summary>133 commits</summary>\n<p>\n\n* [`8daf432b2`](https://github.com/siderolabs/talos/commit/8daf432b2957a8f9d5c59970cf68e7e8414038f5) chore: bump deps\n* [`e3f3f5794`](https://github.com/siderolabs/talos/commit/e3f3f5794d276433748d0e677ed8476a54f8a98e) feat: implement revert for sd-boot\n* [`d8b0903d7`](https://github.com/siderolabs/talos/commit/d8b0903d70181afc901d8ddb71bdfa964d4df2cd) docs: vagrant setup document fix\n* [`fe0f46980`](https://github.com/siderolabs/talos/commit/fe0f46980f348852907218d6f49581efe4b45d49) feat: implement secure boot from disk\n* [`445f5ad54`](https://github.com/siderolabs/talos/commit/445f5ad5426b125e29d86ff096695399bd01eb32) feat: support API server load balancer\n* [`19bc223de`](https://github.com/siderolabs/talos/commit/19bc223de8ad878bffe539bda617d5f861af3cfe) refactor: bootloader interface, labels\n* [`665702ddd`](https://github.com/siderolabs/talos/commit/665702ddd351e902336e6ab81108ea94d61db5c1) chore: fix cilium e2e tests\n* [`71a548d18`](https://github.com/siderolabs/talos/commit/71a548d18013ee16394921759e819b0fabb43758) chore: generic boootloader implementation\n* [`e9dbc9311`](https://github.com/siderolabs/talos/commit/e9dbc9311bcbbbcaab2c7eb7f7128013194c234a) test: bump versions for upgrade tests\n* [`0a99965ef`](https://github.com/siderolabs/talos/commit/0a99965efbdd5dc0d927eb2cbae209dc143c9541) refactor: replace `uncordonNode` with controllers\n* [`e858bca3a`](https://github.com/siderolabs/talos/commit/e858bca3a2f75d5035710d52229c8142f3eb6982) test: fix cilium integration tests\n* [`455328d05`](https://github.com/siderolabs/talos/commit/455328d058fba3a5a8b3358820a02e2b4fabad95) fix: allow time skew for generated kubeconfig\n* [`3ae05648a`](https://github.com/siderolabs/talos/commit/3ae05648ae0a2f79bebd678f85d63d4e5dafde0a) fix: usage of custom kernels\n* [`0797b0d16`](https://github.com/siderolabs/talos/commit/0797b0d16808d115649a9e0e37b355bbbc2a30b5) chore: add a pipeline to test cloud-images step without a release\n* [`e5a36268b`](https://github.com/siderolabs/talos/commit/e5a36268b63e588ea6cd2439bf0de356ee07d752) docs: include `allowSchedulingOnControlPlanes` on `talosctl gen config` output\n* [`c74d93728`](https://github.com/siderolabs/talos/commit/c74d937280c2ec707936a72d07dc2a5dd252c5d2) chore: bump github.com/cosi-project/runtime\n* [`dbaf5c699`](https://github.com/siderolabs/talos/commit/dbaf5c69978fd1d22737385ddd096798d408254c) refactor: task `labelControlPlane` into controllers\n* [`1865a0c29`](https://github.com/siderolabs/talos/commit/1865a0c29663a1a78db7ef6e901d450d67a3cbe1) chore: modify some usages that are not recommended\n* [`3816318b9`](https://github.com/siderolabs/talos/commit/3816318b9e2e205da0c949c0ec59a087decd0b78) chore: wrap config.Provider in atomic wrapper\n* [`d04cf1978`](https://github.com/siderolabs/talos/commit/d04cf19788df20c802eadb9678570a4f15d339b2) chore: clean up unnecessary self assignment\n* [`a34a94898`](https://github.com/siderolabs/talos/commit/a34a948985fed7c3054c4342c48e0e0620569625) fix: copy missing modules.* files\n* [`f5e3272fc`](https://github.com/siderolabs/talos/commit/f5e3272fce641a878eefa66437d28d3ed9917ab6) refactor: task 'updateBootLoader' as controller\n* [`e7be6ee7c`](https://github.com/siderolabs/talos/commit/e7be6ee7c3636eebd557d93e440e9749c8093360) refactor: make event log streaming fully reactive\n* [`aef2192a6`](https://github.com/siderolabs/talos/commit/aef2192a6584e7934086eae0caab6faba52a8ac1) chore: use fixed module list\n* [`c719aa231`](https://github.com/siderolabs/talos/commit/c719aa2316bffa3b614d27d630ea3d8731684f4e) fix: allow http:// for discovery service URL\n* [`39134d8d5`](https://github.com/siderolabs/talos/commit/39134d8d5304cec5e1a1c5fe23f62ed957241213) chore: fix cron pipeline\n* [`a61dcdbbd`](https://github.com/siderolabs/talos/commit/a61dcdbbd5c917b49c810108ff96854ad51269b1) fix: don't load RDMA over Ethernet driver by default\n* [`aac441f61`](https://github.com/siderolabs/talos/commit/aac441f618ac60f2298d9e17a2044916f7da9d69) chore: update Go to 1.20.5, bump dependencies\n* [`1c0c7933d`](https://github.com/siderolabs/talos/commit/1c0c7933dfef23544e2fb0fc04c4c5ad7d5b5d9b) chore: cleanup partition code\n* [`31b988281`](https://github.com/siderolabs/talos/commit/31b988281efb9d0c66975bbfc20b893ad32c161d) docs: add some words about certifcates\n* [`e912c0dfc`](https://github.com/siderolabs/talos/commit/e912c0dfcf515c5a6c852f4b935c9b48e61b13f1) chore: use go-blockdevice for zeroing partitions\n* [`e6dde8ffc`](https://github.com/siderolabs/talos/commit/e6dde8ffc50e435a42d11eb96cf6aea2cf3520ca) feat: add network chaos to qemu development environment\n* [`47986cb79`](https://github.com/siderolabs/talos/commit/47986cb79eb30c6e9c0d091ee37b2b1c2f20885c) chore: unify kexec phase\n* [`3a865370f`](https://github.com/siderolabs/talos/commit/3a865370f5152243e08a69626de023f924e22689) feat: qemu secureboot\n* [`5dab45e86`](https://github.com/siderolabs/talos/commit/5dab45e86917837b0991a62ab94a7b96b3ef777e) refactor: allow kmsg log streaming to be reconfigured on the fly\n* [`8a02ecd4c`](https://github.com/siderolabs/talos/commit/8a02ecd4cb97bcaafe5761d464fec8a4e44b672f) chore: add endpoints balancer controller\n* [`423a31ac9`](https://github.com/siderolabs/talos/commit/423a31ac9d8f28c2bcf00794bacf5446e43fc0b7) chore: deprectae `bootloader` installer option\n* [`cdfece7d6`](https://github.com/siderolabs/talos/commit/cdfece7d64a9269afcc213f8d604d0b7e525cb8a) chore: optimize image compression\n* [`bfc341937`](https://github.com/siderolabs/talos/commit/bfc34193762cb309ef2230f4d79673c4a56f4db5) chore: add default console args\n* [`2749aeeda`](https://github.com/siderolabs/talos/commit/2749aeeda0451b286369d911696070e2cf4359e9) feat: add support for multi-doc strategic merge patching\n* [`3f68485e4`](https://github.com/siderolabs/talos/commit/3f68485e44800a0c50b5855531ec10507e7d0df9) feat: add uki iso generation\n* [`bab484a40`](https://github.com/siderolabs/talos/commit/bab484a405cb598d1c5f35f7602c2ac27e6efa97) feat: use stable network interface names\n* [`196dfb99b`](https://github.com/siderolabs/talos/commit/196dfb99b0329d5c52fd7089e62fbfa1b09df3c6) fix: do not probe kernel args in dashboard if not needed\n* [`8c071b579`](https://github.com/siderolabs/talos/commit/8c071b5796db05ecb17e46295eb2140827a58ca8) fix: skip DHCP RENEW if server IP in the lease is all zeroes\n* [`badbc51e6`](https://github.com/siderolabs/talos/commit/badbc51e63b685e22fffb82ae294a35cd9f65922) refactor: rewrite code to include preliminary support for multi-doc\n* [`ecce29dee`](https://github.com/siderolabs/talos/commit/ecce29dee9625842e419496e18560291ef90b1b5) fix: upgrade-k8s use internal IP first, external IP fallback\n* [`3c64a5ffb`](https://github.com/siderolabs/talos/commit/3c64a5ffba2109ccf5102f71652e54def52f8dbf) chore: optimize image generation time\n* [`2292f36d9`](https://github.com/siderolabs/talos/commit/2292f36d970d3edcf39b5d5f12d0051d7d75f390) chore: registry.k8s.io for coredns image\n* [`f2b258b37`](https://github.com/siderolabs/talos/commit/f2b258b3733a8fcc34bccde3bf01855a512d519a) docs: document talosctl version for upgrades\n* [`a0773f783`](https://github.com/siderolabs/talos/commit/a0773f783cfb3cfab8cbbeffb6449159754d785e) chore: add ukify Go script\n* [`b69e38d1f`](https://github.com/siderolabs/talos/commit/b69e38d1ff069ba8fac7a6524621f8b3c7256238) chore: bump dependencies\n* [`adce65103`](https://github.com/siderolabs/talos/commit/adce65103424f9f895e6b8c4858b27b3eb6bd74b) docs: add piraeus/drbd to storage documentation\n* [`a982cabe7`](https://github.com/siderolabs/talos/commit/a982cabe7011c87e863f7bb0829921e927ddf782) docs: link support matrix in k8s update doc\n* [`1fb29a56a`](https://github.com/siderolabs/talos/commit/1fb29a56a8abe5d72b8a3a336693e798424c63e0) fix: fail quickly if upgrade-k8s is used with multiple nodes\n* [`51d931c47`](https://github.com/siderolabs/talos/commit/51d931c4705fc7ca0bdadc59d732e56fae318dda) chore: faster dev cycle\n* [`dc6764871`](https://github.com/siderolabs/talos/commit/dc6764871c9e732b88f7cddc1784e943e9d952bb) refactor: move around config interfaces, make RawV1Alpha1 typed\n* [`ea9a97dba`](https://github.com/siderolabs/talos/commit/ea9a97dba38c6ab2de830e3b0c3d202d22bdb668) fix: fall back to external IP when discovering nodes in upgrade-k8s\n* [`0bb7e8a5c`](https://github.com/siderolabs/talos/commit/0bb7e8a5cf8b8f3bf31d9f8c3a85b4153921c126) refactor: split config.Provider into Config & Container\n* [`85d8a1619`](https://github.com/siderolabs/talos/commit/85d8a1619431989eb05cb15ad01a1bc06b0f63e9) chore: bump deps\n* [`39b7a56f0`](https://github.com/siderolabs/talos/commit/39b7a56f01d41d33eb96a0feb6e34d43965a99fd) chore: use 8GiB instead of 10GiB for cloud images\n* [`ff11fd39c`](https://github.com/siderolabs/talos/commit/ff11fd39c723a40c01abe6348f64b1f892856175) fix: race with `udevd` and `mountUserDisks`\n* [`c3fabb982`](https://github.com/siderolabs/talos/commit/c3fabb9829d12353770d6436a1d726b15820ebce) chore: update default image sizes to 10GB for all \"cloud\" images\n* [`10155c390`](https://github.com/siderolabs/talos/commit/10155c390e87898098426600709657fbd51e02e8) feat: enable xfs project quota support, kubelet feature\n* [`eba818564`](https://github.com/siderolabs/talos/commit/eba81856427dd3f6c0cf317f027e63d65a079029) release(v1.5.0-alpha.0): prepare release\n* [`383471c3e`](https://github.com/siderolabs/talos/commit/383471c3e956ff6e077a1de75b02a50835fbf352) feat: update default Kubernetes to v1.27.2\n* [`8f68d1abe`](https://github.com/siderolabs/talos/commit/8f68d1abeff83c3ff0e6c5d9f61cb14807b44ca5) chore: bump deps\n* [`e0c1585d3`](https://github.com/siderolabs/talos/commit/e0c1585d3047ef213134331dc57f8e2e8c23a93d) feat: create azure community gallery image version on release\n* [`dd8336c9e`](https://github.com/siderolabs/talos/commit/dd8336c9ee7f8a3a44d45c9f9e3cbbf741f84c44) fix: refresh kubelet self-issued serving certificates\n* [`bb02dd263`](https://github.com/siderolabs/talos/commit/bb02dd263cbc5e7e3839148d86a4a0a5f7ea998b) chore: drop deprecated stuff for Talos 1.5\n* [`61cad8673`](https://github.com/siderolabs/talos/commit/61cad86731e5c0aa80d7df41ea02d0b7ff579c45) chore: bump deps\n* [`01dfd3af7`](https://github.com/siderolabs/talos/commit/01dfd3af7d64dacd179d17d9d5eaf4bc44cf72af) feat: update etcd to v3.5.9\n* [`aa65fbb8a`](https://github.com/siderolabs/talos/commit/aa65fbb8a1752a70e7bac4e4e9872f35e88d1cc9) chore: update KUBECTL_URL to reflect the community bucket\n* [`cc3128d94`](https://github.com/siderolabs/talos/commit/cc3128d944abacfb633bc783b7fed6d0a6f80661) chore: bump kernel to 6.1.28\n* [`97fffaf78`](https://github.com/siderolabs/talos/commit/97fffaf78a0b9a1dc67709de11d37ea20aefde59) chore: use ctest.UpdateWithConflicts instead of plain UpdateWithConflicts\n* [`3b36993b9`](https://github.com/siderolabs/talos/commit/3b36993b9926392f4290e6fabc82e635f4c98149) fix: rlimit nofile test\n* [`45e6e27af`](https://github.com/siderolabs/talos/commit/45e6e27af75746fd0cc8b0f98a2d14579eb0ed40) chore: bump runtime\n* [`4f720d465`](https://github.com/siderolabs/talos/commit/4f720d46532af39165fc5051052d5c42595d91af) fix: revert: set rlimit explicitly in wrapperd\n* [`a2565f674`](https://github.com/siderolabs/talos/commit/a2565f67416e9b9bc22f2d5506df9ea7771c0c8c) fix: set rlimit explicitly in wrapperd\n* [`cdfc242b8`](https://github.com/siderolabs/talos/commit/cdfc242b8354f4cc4e7ce51bbe3a8fb20b35995d) chore: re-enable Go buildid\n* [`e67f3f5c5`](https://github.com/siderolabs/talos/commit/e67f3f5c5453f947355194ea9656c15ff008c35e) feat: linux 6.1.27, containerd 1.6.21, go 1.20.4\n* [`55ae59a0a`](https://github.com/siderolabs/talos/commit/55ae59a0ad71293676b3efed461f5ab98101401a) fix: properly skip/cleanup controlplane configs for workers\n* [`64eade9bd`](https://github.com/siderolabs/talos/commit/64eade9bde271bce4e629e6ac09407c8c42e01be) chore: clean up unused constant\n* [`62c6e9655`](https://github.com/siderolabs/talos/commit/62c6e9655cb639d4993aaa4c9b364342688599cb) feat: introduce siderolink config resource & reconnect\n* [`860002c73`](https://github.com/siderolabs/talos/commit/860002c7352bedd10845e11da37c80685ff0e720) fix: don't reload control plane pods on cert SANs changes\n* [`d43c61e80`](https://github.com/siderolabs/talos/commit/d43c61e80f5b05b81f2a021cdfe012e500c3d98e) fix: enforce nolock option for all NFS mounts by default\n* [`339986db9`](https://github.com/siderolabs/talos/commit/339986db9d3675b78ce0d268f799ad654862fb0f) fix: inhibit timer to follow kubelet timer\n* [`cbf6dc100`](https://github.com/siderolabs/talos/commit/cbf6dc1009ad47a2804774839e4e0301efa8ac78) fix: set timeout for unmount calls\n* [`b58f913d5`](https://github.com/siderolabs/talos/commit/b58f913d5f4b8ecf39be183d0bafe1109f0f0737) fix: set the static pod priority as values\n* [`f8a7a5b6b`](https://github.com/siderolabs/talos/commit/f8a7a5b6bf4138a33cbe5c9afe85db99de167aec) docs: add information about KubeSpan ports and topology\n* [`2bad74d64`](https://github.com/siderolabs/talos/commit/2bad74d6423c083ec34f1b422f23b0024d5f8798) docs: add how to on scaling down\n* [`7442ff8b0`](https://github.com/siderolabs/talos/commit/7442ff8b095ef1337f54332a71d08053a2832144) chore: fix typos inteface -> interface (docs and tests)\n* [`d4e94f7a1`](https://github.com/siderolabs/talos/commit/d4e94f7a15acf7f3c9e7532b067cdacd0e805bec) fix: add back required TARGETARCH for installer\n* [`e6fffda01`](https://github.com/siderolabs/talos/commit/e6fffda01385a2daaa901a5742f30a4edc9186a7) chore: linux 6.1.26, runc 1.1.7\n* [`344746ae2`](https://github.com/siderolabs/talos/commit/344746ae2fa038b704d02fec04c3d358762fe938) fix: bump max inhibit delay to 20 min\n* [`d9bdea2b5`](https://github.com/siderolabs/talos/commit/d9bdea2b54772f067783ee64eb85c834957d386a) chore: fork docs and compatibility modules for Talos 1.5\n* [`3d99610fc`](https://github.com/siderolabs/talos/commit/3d99610fc9b0d0084be822be29bb1bf2fbe85833) docs: document building, verifying image and process caps\n* [`014008ea2`](https://github.com/siderolabs/talos/commit/014008ea25208afbeabb42ef89238802705ad4e0) fix: udevd rules trigger\n* [`9b36bb613`](https://github.com/siderolabs/talos/commit/9b36bb613b44f182e47ae63bc74e4a8b6342d68d) feat: update Linux to 6.1.25, fix virtio on arm64\n* [`08ec66c55`](https://github.com/siderolabs/talos/commit/08ec66c55ccca3f9aa82a9703ebf183913b19a7e) feat: clean up (garbage collect) system images which are not referenced\n* [`b097efcde`](https://github.com/siderolabs/talos/commit/b097efcde29c20cdc4fed23fe8366bd683db634c) fix: display correct number of machines on dashboard\n* [`cad43f0ad`](https://github.com/siderolabs/talos/commit/cad43f0ad3bc2ede8a6ae81767c9226b6bc69f19) chore: remove k8s master label\n* [`e296a566e`](https://github.com/siderolabs/talos/commit/e296a566e6efb0cbdd119e73aff1feaa772d38bd) fix: support kernel userspace module loading\n* [`103f0ffdd`](https://github.com/siderolabs/talos/commit/103f0ffdd3ebd57a5086852f3502a8a7d4428faa) feat: add startup probes to controller-manager and scheduler\n* [`5a1ae8aae`](https://github.com/siderolabs/talos/commit/5a1ae8aae89e54d5540586d6f2e99ef3e80a72eb) chore: bump dependences\n* [`ec8c8dbaf`](https://github.com/siderolabs/talos/commit/ec8c8dbafcdaf63d036bdba92fa153d4d1c90100) chore: fix container image reproducibility\n* [`f661d8487`](https://github.com/siderolabs/talos/commit/f661d84877e6db5bc8856b982990926dcbfe949c) fix: allow `talosctl cp` to handle special files in `/proc`\n* [`2d824b563`](https://github.com/siderolabs/talos/commit/2d824b5639a4b8c3b673d13b08b2b97c69aafe0d) fix: do not show control plane status for workers on dashboard\n* [`e5491ddad`](https://github.com/siderolabs/talos/commit/e5491ddadeb1776bd5c17dd35917e05ec4847d0f) docs: update documentation for nocloud\n* [`7a004a6f7`](https://github.com/siderolabs/talos/commit/7a004a6f7f47fa5d17e855eb02650754d8411574) fix: parse errors correctly\n* [`374ef5385`](https://github.com/siderolabs/talos/commit/374ef53853947811dc221d99751cf0e16294508c) test: submit verbose flag to e2e tests\n* [`e1d38b6fe`](https://github.com/siderolabs/talos/commit/e1d38b6febf26fe31a6b9d6ed8f9b6bdba29aa3b) feat: show template URL in dashboard config URL tab\n* [`45d7f0ce9`](https://github.com/siderolabs/talos/commit/45d7f0ce95454ce85c403fc493ddb97e4d478238) docs: fix the latest url\n* [`96efbf147`](https://github.com/siderolabs/talos/commit/96efbf14769579d514ef9c75d01d9f44d276113a) docs: activate 1.4.0 docs by default\n* [`8c1f515b1`](https://github.com/siderolabs/talos/commit/8c1f515b1b8e40bce42e2fc04755afe5bf8a56aa) feat: update Linux to 6.1.24\n* [`8689bef5f`](https://github.com/siderolabs/talos/commit/8689bef5f10839091cf131edb6c8efad4ccba034) docs: update documentation for Talos 1.4\n* [`a781dfb8e`](https://github.com/siderolabs/talos/commit/a781dfb8e3ded67edcb2a6a1048bfe76c6bd0d24) feat: update Kubernetes to 1.27.1\n* [`a737dd83a`](https://github.com/siderolabs/talos/commit/a737dd83a4cd7549f85f8df0882f1c9a4446060d) chore: typo in `compatibility.ParseKubernetesVersion`\n* [`f14928b0a`](https://github.com/siderolabs/talos/commit/f14928b0a9dd3d85664605f4f6a206236ea94614) fix: fix dashboard crash when a non-existent node is specified\n* [`3e406d9b0`](https://github.com/siderolabs/talos/commit/3e406d9b07c0e67a2fb61e612bc3f378f3c35247) feat: update etcd to v3.5.8\n* [`bd1cff3e8`](https://github.com/siderolabs/talos/commit/bd1cff3e83530b9b89b27d8083ea8f3f0cf6ede4) chore: remove Go buildid\n* [`e31f7f50b`](https://github.com/siderolabs/talos/commit/e31f7f50b1b455beb98cd25859a44bbbccc1ff64) feat: update Kubernetes to 1.27.0\n* [`aa3640d74`](https://github.com/siderolabs/talos/commit/aa3640d74ce2e3619476453381909fa3520eb87d) docs: update storage.md\n* [`07bb61e60`](https://github.com/siderolabs/talos/commit/07bb61e60c53b267756dc97874b9c9554f2b1486) chore: module-sig-verify cleanup\n* [`5e9d836c3`](https://github.com/siderolabs/talos/commit/5e9d836c3d075c3edb2d48b2868c31a1c963e2de) chore: add kernel module signtaure verification\n* [`3cd1c6bb0`](https://github.com/siderolabs/talos/commit/3cd1c6bb0b83e5747a7356140a44b16deb4727e6) fix: send 'STOP' event on phase end\n* [`5176d27dc`](https://github.com/siderolabs/talos/commit/5176d27dc566d8689bb305398da7250269ebe9a3) feat: update Kubernetes to 1.27.0-rc.1\n* [`2c55550a6`](https://github.com/siderolabs/talos/commit/2c55550a66b49b49d8dc95b83516b7c0f8107300) fix: quote ISO kernel args for GRUB\n* [`319d76e38`](https://github.com/siderolabs/talos/commit/319d76e38978406d8d37e89ada2c403969d6c972) fix: respect BROWSER=echo in client auth interceptor\n* [`4e4ace839`](https://github.com/siderolabs/talos/commit/4e4ace839c0f558e7b00979fa4c64c32985aa3ce) chore: update Go to 1.20.3\n* [`170f73899`](https://github.com/siderolabs/talos/commit/170f73899a3bf29e9c6f76fdc5e510be08edf4aa) fix: correctly parse static pod phase\n* [`c3a595d5b`](https://github.com/siderolabs/talos/commit/c3a595d5b7d3c7c3091229caef6b2553416edb56) fix: improve action tracking post checks\n* [`eb01edbc8`](https://github.com/siderolabs/talos/commit/eb01edbc8a0ef5810693afe450861d5b63877b72) fix: rework DHCP flow\n* [`e095150a6`](https://github.com/siderolabs/talos/commit/e095150a6e34cbdc805a2cac85ec7f28f98629b4) test: bump CAPI components versions\n</p>\n</details>\n\n### Changes since v1.5.0-alpha.0\n<details><summary>63 commits</summary>\n<p>\n\n* [`8daf432b2`](https://github.com/siderolabs/talos/commit/8daf432b2957a8f9d5c59970cf68e7e8414038f5) chore: bump deps\n* [`e3f3f5794`](https://github.com/siderolabs/talos/commit/e3f3f5794d276433748d0e677ed8476a54f8a98e) feat: implement revert for sd-boot\n* [`d8b0903d7`](https://github.com/siderolabs/talos/commit/d8b0903d70181afc901d8ddb71bdfa964d4df2cd) docs: vagrant setup document fix\n* [`fe0f46980`](https://github.com/siderolabs/talos/commit/fe0f46980f348852907218d6f49581efe4b45d49) feat: implement secure boot from disk\n* [`445f5ad54`](https://github.com/siderolabs/talos/commit/445f5ad5426b125e29d86ff096695399bd01eb32) feat: support API server load balancer\n* [`19bc223de`](https://github.com/siderolabs/talos/commit/19bc223de8ad878bffe539bda617d5f861af3cfe) refactor: bootloader interface, labels\n* [`665702ddd`](https://github.com/siderolabs/talos/commit/665702ddd351e902336e6ab81108ea94d61db5c1) chore: fix cilium e2e tests\n* [`71a548d18`](https://github.com/siderolabs/talos/commit/71a548d18013ee16394921759e819b0fabb43758) chore: generic boootloader implementation\n* [`e9dbc9311`](https://github.com/siderolabs/talos/commit/e9dbc9311bcbbbcaab2c7eb7f7128013194c234a) test: bump versions for upgrade tests\n* [`0a99965ef`](https://github.com/siderolabs/talos/commit/0a99965efbdd5dc0d927eb2cbae209dc143c9541) refactor: replace `uncordonNode` with controllers\n* [`e858bca3a`](https://github.com/siderolabs/talos/commit/e858bca3a2f75d5035710d52229c8142f3eb6982) test: fix cilium integration tests\n* [`455328d05`](https://github.com/siderolabs/talos/commit/455328d058fba3a5a8b3358820a02e2b4fabad95) fix: allow time skew for generated kubeconfig\n* [`3ae05648a`](https://github.com/siderolabs/talos/commit/3ae05648ae0a2f79bebd678f85d63d4e5dafde0a) fix: usage of custom kernels\n* [`0797b0d16`](https://github.com/siderolabs/talos/commit/0797b0d16808d115649a9e0e37b355bbbc2a30b5) chore: add a pipeline to test cloud-images step without a release\n* [`e5a36268b`](https://github.com/siderolabs/talos/commit/e5a36268b63e588ea6cd2439bf0de356ee07d752) docs: include `allowSchedulingOnControlPlanes` on `talosctl gen config` output\n* [`c74d93728`](https://github.com/siderolabs/talos/commit/c74d937280c2ec707936a72d07dc2a5dd252c5d2) chore: bump github.com/cosi-project/runtime\n* [`dbaf5c699`](https://github.com/siderolabs/talos/commit/dbaf5c69978fd1d22737385ddd096798d408254c) refactor: task `labelControlPlane` into controllers\n* [`1865a0c29`](https://github.com/siderolabs/talos/commit/1865a0c29663a1a78db7ef6e901d450d67a3cbe1) chore: modify some usages that are not recommended\n* [`3816318b9`](https://github.com/siderolabs/talos/commit/3816318b9e2e205da0c949c0ec59a087decd0b78) chore: wrap config.Provider in atomic wrapper\n* [`d04cf1978`](https://github.com/siderolabs/talos/commit/d04cf19788df20c802eadb9678570a4f15d339b2) chore: clean up unnecessary self assignment\n* [`a34a94898`](https://github.com/siderolabs/talos/commit/a34a948985fed7c3054c4342c48e0e0620569625) fix: copy missing modules.* files\n* [`f5e3272fc`](https://github.com/siderolabs/talos/commit/f5e3272fce641a878eefa66437d28d3ed9917ab6) refactor: task 'updateBootLoader' as controller\n* [`e7be6ee7c`](https://github.com/siderolabs/talos/commit/e7be6ee7c3636eebd557d93e440e9749c8093360) refactor: make event log streaming fully reactive\n* [`aef2192a6`](https://github.com/siderolabs/talos/commit/aef2192a6584e7934086eae0caab6faba52a8ac1) chore: use fixed module list\n* [`c719aa231`](https://github.com/siderolabs/talos/commit/c719aa2316bffa3b614d27d630ea3d8731684f4e) fix: allow http:// for discovery service URL\n* [`39134d8d5`](https://github.com/siderolabs/talos/commit/39134d8d5304cec5e1a1c5fe23f62ed957241213) chore: fix cron pipeline\n* [`a61dcdbbd`](https://github.com/siderolabs/talos/commit/a61dcdbbd5c917b49c810108ff96854ad51269b1) fix: don't load RDMA over Ethernet driver by default\n* [`aac441f61`](https://github.com/siderolabs/talos/commit/aac441f618ac60f2298d9e17a2044916f7da9d69) chore: update Go to 1.20.5, bump dependencies\n* [`1c0c7933d`](https://github.com/siderolabs/talos/commit/1c0c7933dfef23544e2fb0fc04c4c5ad7d5b5d9b) chore: cleanup partition code\n* [`31b988281`](https://github.com/siderolabs/talos/commit/31b988281efb9d0c66975bbfc20b893ad32c161d) docs: add some words about certifcates\n* [`e912c0dfc`](https://github.com/siderolabs/talos/commit/e912c0dfcf515c5a6c852f4b935c9b48e61b13f1) chore: use go-blockdevice for zeroing partitions\n* [`e6dde8ffc`](https://github.com/siderolabs/talos/commit/e6dde8ffc50e435a42d11eb96cf6aea2cf3520ca) feat: add network chaos to qemu development environment\n* [`47986cb79`](https://github.com/siderolabs/talos/commit/47986cb79eb30c6e9c0d091ee37b2b1c2f20885c) chore: unify kexec phase\n* [`3a865370f`](https://github.com/siderolabs/talos/commit/3a865370f5152243e08a69626de023f924e22689) feat: qemu secureboot\n* [`5dab45e86`](https://github.com/siderolabs/talos/commit/5dab45e86917837b0991a62ab94a7b96b3ef777e) refactor: allow kmsg log streaming to be reconfigured on the fly\n* [`8a02ecd4c`](https://github.com/siderolabs/talos/commit/8a02ecd4cb97bcaafe5761d464fec8a4e44b672f) chore: add endpoints balancer controller\n* [`423a31ac9`](https://github.com/siderolabs/talos/commit/423a31ac9d8f28c2bcf00794bacf5446e43fc0b7) chore: deprectae `bootloader` installer option\n* [`cdfece7d6`](https://github.com/siderolabs/talos/commit/cdfece7d64a9269afcc213f8d604d0b7e525cb8a) chore: optimize image compression\n* [`bfc341937`](https://github.com/siderolabs/talos/commit/bfc34193762cb309ef2230f4d79673c4a56f4db5) chore: add default console args\n* [`2749aeeda`](https://github.com/siderolabs/talos/commit/2749aeeda0451b286369d911696070e2cf4359e9) feat: add support for multi-doc strategic merge patching\n* [`3f68485e4`](https://github.com/siderolabs/talos/commit/3f68485e44800a0c50b5855531ec10507e7d0df9) feat: add uki iso generation\n* [`bab484a40`](https://github.com/siderolabs/talos/commit/bab484a405cb598d1c5f35f7602c2ac27e6efa97) feat: use stable network interface names\n* [`196dfb99b`](https://github.com/siderolabs/talos/commit/196dfb99b0329d5c52fd7089e62fbfa1b09df3c6) fix: do not probe kernel args in dashboard if not needed\n* [`8c071b579`](https://github.com/siderolabs/talos/commit/8c071b5796db05ecb17e46295eb2140827a58ca8) fix: skip DHCP RENEW if server IP in the lease is all zeroes\n* [`badbc51e6`](https://github.com/siderolabs/talos/commit/badbc51e63b685e22fffb82ae294a35cd9f65922) refactor: rewrite code to include preliminary support for multi-doc\n* [`ecce29dee`](https://github.com/siderolabs/talos/commit/ecce29dee9625842e419496e18560291ef90b1b5) fix: upgrade-k8s use internal IP first, external IP fallback\n* [`3c64a5ffb`](https://github.com/siderolabs/talos/commit/3c64a5ffba2109ccf5102f71652e54def52f8dbf) chore: optimize image generation time\n* [`2292f36d9`](https://github.com/siderolabs/talos/commit/2292f36d970d3edcf39b5d5f12d0051d7d75f390) chore: registry.k8s.io for coredns image\n* [`f2b258b37`](https://github.com/siderolabs/talos/commit/f2b258b3733a8fcc34bccde3bf01855a512d519a) docs: document talosctl version for upgrades\n* [`a0773f783`](https://github.com/siderolabs/talos/commit/a0773f783cfb3cfab8cbbeffb6449159754d785e) chore: add ukify Go script\n* [`b69e38d1f`](https://github.com/siderolabs/talos/commit/b69e38d1ff069ba8fac7a6524621f8b3c7256238) chore: bump dependencies\n* [`adce65103`](https://github.com/siderolabs/talos/commit/adce65103424f9f895e6b8c4858b27b3eb6bd74b) docs: add piraeus/drbd to storage documentation\n* [`a982cabe7`](https://github.com/siderolabs/talos/commit/a982cabe7011c87e863f7bb0829921e927ddf782) docs: link support matrix in k8s update doc\n* [`1fb29a56a`](https://github.com/siderolabs/talos/commit/1fb29a56a8abe5d72b8a3a336693e798424c63e0) fix: fail quickly if upgrade-k8s is used with multiple nodes\n* [`51d931c47`](https://github.com/siderolabs/talos/commit/51d931c4705fc7ca0bdadc59d732e56fae318dda) chore: faster dev cycle\n* [`dc6764871`](https://github.com/siderolabs/talos/commit/dc6764871c9e732b88f7cddc1784e943e9d952bb) refactor: move around config interfaces, make RawV1Alpha1 typed\n* [`ea9a97dba`](https://github.com/siderolabs/talos/commit/ea9a97dba38c6ab2de830e3b0c3d202d22bdb668) fix: fall back to external IP when discovering nodes in upgrade-k8s\n* [`0bb7e8a5c`](https://github.com/siderolabs/talos/commit/0bb7e8a5cf8b8f3bf31d9f8c3a85b4153921c126) refactor: split config.Provider into Config & Container\n* [`85d8a1619`](https://github.com/siderolabs/talos/commit/85d8a1619431989eb05cb15ad01a1bc06b0f63e9) chore: bump deps\n* [`39b7a56f0`](https://github.com/siderolabs/talos/commit/39b7a56f01d41d33eb96a0feb6e34d43965a99fd) chore: use 8GiB instead of 10GiB for cloud images\n* [`ff11fd39c`](https://github.com/siderolabs/talos/commit/ff11fd39c723a40c01abe6348f64b1f892856175) fix: race with `udevd` and `mountUserDisks`\n* [`c3fabb982`](https://github.com/siderolabs/talos/commit/c3fabb9829d12353770d6436a1d726b15820ebce) chore: update default image sizes to 10GB for all \"cloud\" images\n* [`10155c390`](https://github.com/siderolabs/talos/commit/10155c390e87898098426600709657fbd51e02e8) feat: enable xfs project quota support, kubelet feature\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`5e3db3c`](https://github.com/siderolabs/discovery-api/commit/5e3db3c1a656ebdc717494e5384f10c7b11eef0f) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`9ba5f03`](https://github.com/siderolabs/discovery-client/commit/9ba5f033a47d41448153962c5fe22db2d9a8a00c) chore: app optional ControlPlane data\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`a73d524`](https://github.com/siderolabs/extras/commit/a73d5243f443fd32376780bf2a4f97b08f28917c) feat: update Go to 1.20.5\n* [`36c8ac4`](https://github.com/siderolabs/extras/commit/36c8ac4ab98300059acaad501c2adc8abd39179f) chore: update to Go 1.20.3\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`f9f5805`](https://github.com/siderolabs/gen/commit/f9f5805973d30fe6bbac2f4a79ad4197fe59970e) chore: bump rekres and add functions from exp\n* [`b968d21`](https://github.com/siderolabs/gen/commit/b968d21c9671d97e54317f80cdf781d6f963e44b) feat: add `TryRecv` and `RecvWithContext` functions\n* [`476dfea`](https://github.com/siderolabs/gen/commit/476dfeae70882e1ca6e5cfed3d6e12dc36841a26) feat: add foreach and clear to lazymap\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`076874a`](https://github.com/siderolabs/go-blockdevice/commit/076874a155ad44d764d25081125f950e8194d023) chore: resolve blockdevice symlinks\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>1 commit</summary>\n<p>\n\n* [`5a3df5b`](https://github.com/siderolabs/go-kubernetes/commit/5a3df5b002d74ba9f4d773dc1278047481b1d4ba) fix: remove removed APIs for 1.27 upgrade\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>5 commits</summary>\n<p>\n\n* [`5301800`](https://github.com/siderolabs/go-loadbalancer/commit/5301800a874e853d97f8e12195558f79c97c0beb) chore: fix logging and tests\n* [`b23a173`](https://github.com/siderolabs/go-loadbalancer/commit/b23a1733aa9b303bda82175b4f5e9f8a4765a27b) chore: replace std log with zap\n* [`1a2f374`](https://github.com/siderolabs/go-loadbalancer/commit/1a2f374df7804dffe683e8be90e9829f2dfb5e95) feat: add multi-tier scoring based for generic List\n* [`56a27da`](https://github.com/siderolabs/go-loadbalancer/commit/56a27da7083139b71898f4f9207dc40088e8c815) chore: move to siderolabs/tcpproxy of inet.af/tcpproxy\n* [`f3a0e24`](https://github.com/siderolabs/go-loadbalancer/commit/f3a0e2411e08eef9c79876f3dc6e09e770710379) fix: use SO_LINGER option when doing TCP healthchecks\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>29 commits</summary>\n<p>\n\n* [`edd725a`](https://github.com/siderolabs/pkgs/commit/edd725a0f9d07d39256d98a67be5dc4c56631078) chore: bump deps\n* [`c0ac69b`](https://github.com/siderolabs/pkgs/commit/c0ac69b70cfac3cdcf100a35f6d766c5ae47d950) feat: enable CONFIG_NVME_{MULTIPATH|AUTH}\n* [`f7cd916`](https://github.com/siderolabs/pkgs/commit/f7cd916b47975e61c6732079c1c5c4684dfb8c96) fix: bump drbd to 9.2.4\n* [`a56d15a`](https://github.com/siderolabs/pkgs/commit/a56d15ad626b6e76a137636d6088361be9a73a9f) fix: copy missing `modules.*` files\n* [`1eefa66`](https://github.com/siderolabs/pkgs/commit/1eefa664fc7c65491e956a6f403ada774e73a7d3) feat: build isb modem drivers as module\n* [`a859f4f`](https://github.com/siderolabs/pkgs/commit/a859f4fb257e17fa19b1c10efcae594d33a86618) fix: build RDMA_RXE as a module\n* [`5fb5e95`](https://github.com/siderolabs/pkgs/commit/5fb5e9517de9fe35e383b96e92fa873aa045a845) feat: bump dependencies\n* [`39a64b2`](https://github.com/siderolabs/pkgs/commit/39a64b23e2c8689c44b9891b1e70149b8d003655) feat: update Linux to 6.1.31, add GENEVE for arm64\n* [`97177be`](https://github.com/siderolabs/pkgs/commit/97177be803cc91c8fabccfec575b7d920bc78c38) feat: update Linux to 6.1.30\n* [`b1f9d4e`](https://github.com/siderolabs/pkgs/commit/b1f9d4e717fbd0132b820d45c226ca643d7f577e) chore: prevent unsigned kexec with secureboot\n* [`9232a42`](https://github.com/siderolabs/pkgs/commit/9232a425b85b1058cd38eab30304f6cf243ab32c) feat: add reproducibility pipelines\n* [`702d7a7`](https://github.com/siderolabs/pkgs/commit/702d7a7e90099d8fdc9cc4ba50e86c8ba6e91d77) chore: bump deps\n* [`7958db1`](https://github.com/siderolabs/pkgs/commit/7958db1549a7c7560eeeb8f9c06d3be9487d8804) chore: copy over sd-boot and sd-stub from tools\n* [`813b3c3`](https://github.com/siderolabs/pkgs/commit/813b3c3d3276d0d9156919307e9ffe521925d40b) chore: revert xfsprogs\n* [`0cc78ab`](https://github.com/siderolabs/pkgs/commit/0cc78ab82ce920c8fa5654c73738050107e190bb) chore: bump kernel to 6.1.28\n* [`70189e3`](https://github.com/siderolabs/pkgs/commit/70189e3df555fed4afade93798d72cd31aad99c5) chore: bump deps\n* [`c5d3bf1`](https://github.com/siderolabs/pkgs/commit/c5d3bf1985b49e688d29d06db6730834f65ee480) feat: add sd-stub and sd-boot\n* [`30a7ac2`](https://github.com/siderolabs/pkgs/commit/30a7ac2974fb7580e83819c76502fde77d777ea0) feat: update Linux 6.1.27, containerd 1.6.21\n* [`fbc6ee5`](https://github.com/siderolabs/pkgs/commit/fbc6ee55b6ffae44c117255901ab0fbecae79cc3) chore: bump deps\n* [`82b9489`](https://github.com/siderolabs/pkgs/commit/82b9489b88b108f144b45fb55432576bfd767f91) chore: bump dependencies\n* [`f37e520`](https://github.com/siderolabs/pkgs/commit/f37e5205cf10fe10296e86565fa018d149f5d8c4) feat: update Linux to 6.1.25\n* [`3920b16`](https://github.com/siderolabs/pkgs/commit/3920b163a5c6a6d7c7969155a909a7b2122e65f6) feat: add multi-gen LRU kernel support\n* [`988f1ec`](https://github.com/siderolabs/pkgs/commit/988f1ecf95536fb259cbd79e044a556728bc7332) feat: update Linux to 6.1.24\n* [`5327d12`](https://github.com/siderolabs/pkgs/commit/5327d1263680f76706ea667906ca08222c8398da) fix: remove FB_NVIDIA drivers, Linux 6.1.23\n* [`4eae958`](https://github.com/siderolabs/pkgs/commit/4eae958770573613bc29568d130be7aaa775e530) chore: copy over the kernel signing public key\n* [`174f8fc`](https://github.com/siderolabs/pkgs/commit/174f8fc9c80d871f1c03ea0a53dc8b6eb7112ccf) chore: update Go to 1.20.3\n* [`41629b0`](https://github.com/siderolabs/pkgs/commit/41629b03e82bfb77623a812000ef8e98d15d56fa) chore: reorder pkgs for better kernel caching\n* [`b483a6b`](https://github.com/siderolabs/pkgs/commit/b483a6b01f539b0da13ca09882015044bff24e41) feat: build 'snp.efi' for iPXE\n* [`fb853ff`](https://github.com/siderolabs/pkgs/commit/fb853ff6b1194cdc1f2412c776347cf4b55c3336) feat: update containerd to 1.6.20\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>15 commits</summary>\n<p>\n\n* [`e0c76c0`](https://github.com/siderolabs/tools/commit/e0c76c096d06ef11afdb54287d5f15add108399b) chore: bump dependencies\n* [`7d0cd58`](https://github.com/siderolabs/tools/commit/7d0cd58b34bba6b9415db5e39bed351e7f00d44d) feat: update Go to 1.20.5\n* [`150efc2`](https://github.com/siderolabs/tools/commit/150efc22508043bfadc9d84a8c3c5fee6c2aac5f) chore: remove non needed tools\n* [`88ebb40`](https://github.com/siderolabs/tools/commit/88ebb40dd348b6c9e4dc5551b616e4a1892b4e42) feat: add swtpm\n* [`4c5d7fe`](https://github.com/siderolabs/tools/commit/4c5d7feb88dcbae2f7bf45f51f9e5e1ba339abac) chore: use same source epoch everywhere\n* [`2e46e5b`](https://github.com/siderolabs/tools/commit/2e46e5be764f8180a0762a5ab080ccff04534a8a) feat: add reproducibility pipelines\n* [`c6a41b6`](https://github.com/siderolabs/tools/commit/c6a41b6c5108d676f8573d3dd47ee29ae46e5cc0) fix: add sd-stub assertion patch\n* [`d2dde48`](https://github.com/siderolabs/tools/commit/d2dde48f72343aa3c541336f5319b8e649e80c87) chore: bump deps\n* [`8e45ad7`](https://github.com/siderolabs/tools/commit/8e45ad75ea78e353ca3eae21b18da9a42d1edf49) feat: add sbsign\n* [`271c4a6`](https://github.com/siderolabs/tools/commit/271c4a66b6987d9de2c0d1d69891b5ff277ebd43) feat: add sd-tools\n* [`eedc294`](https://github.com/siderolabs/tools/commit/eedc294967d415cca40d4c427d3521cd198661d7) chore: bump deps\n* [`81b09a5`](https://github.com/siderolabs/tools/commit/81b09a5ab204f16306c980eeff518a0d1a37ddf2) feat: add libcap and gnuefi\n* [`47b0fd3`](https://github.com/siderolabs/tools/commit/47b0fd3e364d4fbcfffe10965f740db7acd82f70) chore: bump go to 1.20.4\n* [`ff4cf2b`](https://github.com/siderolabs/tools/commit/ff4cf2beabab310365ad9887abb6234570f5092a) chore: bump deps\n* [`1563556`](https://github.com/siderolabs/tools/commit/1563556b8f8fdf20d8aa58ac5340104c7ffe732e) feat: update Go to 1.20.3\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/BurntSushi/toml**                     v1.2.1 -> v1.3.2\n* **github.com/aws/aws-sdk-go**                      v1.44.232 -> v1.44.287\n* **github.com/beevik/ntp**                          v0.3.0 -> v1.1.1\n* **github.com/benbjohnson/clock**                   v1.1.0 -> v1.3.5\n* **github.com/cenkalti/backoff/v4**                 v4.2.0 -> v4.2.1\n* **github.com/containerd/containerd**               v1.6.19 -> v1.6.21\n* **github.com/containerd/typeurl/v2**               v2.1.1 **_new_**\n* **github.com/containernetworking/plugins**         v1.2.0 -> v1.3.0\n* **github.com/cosi-project/runtime**                v0.3.0 -> v0.3.1-alpha.5\n* **github.com/docker/distribution**                 v2.8.1 -> v2.8.2\n* **github.com/docker/docker**                       v23.0.2 -> v24.0.2\n* **github.com/ecks/uefi**                           caef65d070eb **_new_**\n* **github.com/emicklei/dot**                        v1.4.2 -> v1.5.0\n* **github.com/hetznercloud/hcloud-go**              v1.41.0 -> v1.47.0\n* **github.com/insomniacslk/dhcp**                   74ae03f2425e -> b20c9ba983df\n* **github.com/jsimonetti/rtnetlink**                v1.3.1 -> v1.3.3\n* **github.com/mattn/go-isatty**                     v0.0.18 -> v0.0.19\n* **github.com/mdlayher/ethtool**                    ba3b4bc2e02c -> v0.1.0\n* **github.com/mdlayher/genetlink**                  v1.3.1 -> v1.3.2\n* **github.com/mdlayher/netlink**                    v1.7.1 -> v1.7.2\n* **github.com/mdlayher/netx**                       c711c2f8512f -> 7e21880baee8\n* **github.com/nberlee/go-netstat**                  v0.1.1 -> v0.1.2\n* **github.com/opencontainers/image-spec**           v1.1.0-rc2 -> v1.1.0-rc3\n* **github.com/packethost/packngo**                  v0.29.0 -> v0.30.0\n* **github.com/prometheus/procfs**                   v0.9.0 -> v0.11.0\n* **github.com/rivo/tview**                          281d14d896d7 -> 6cc0565babaf\n* **github.com/rs/xid**                              v1.4.0 -> v1.5.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.15 -> v1.0.0-beta.17\n* **github.com/siderolabs/discovery-api**            v0.1.2 -> v0.1.3\n* **github.com/siderolabs/discovery-client**         v0.1.4 -> v0.1.5\n* **github.com/siderolabs/extras**                   v1.4.0-1-g9b07505 -> v1.5.0-alpha.0-1-ga73d524\n* **github.com/siderolabs/gen**                      v0.4.3 -> v0.4.5\n* **github.com/siderolabs/go-blockdevice**           v0.4.4 -> v0.4.5\n* **github.com/siderolabs/go-kubernetes**            v0.2.0 -> v0.2.1\n* **github.com/siderolabs/go-loadbalancer**          v0.2.1 -> v0.3.1\n* **github.com/siderolabs/pkgs**                     v1.4.1-5-ga333a84 -> v1.5.0-alpha.0-28-gedd725a\n* **github.com/siderolabs/talos/pkg/machinery**      v1.4.0 -> v1.5.0-alpha.0\n* **github.com/siderolabs/tools**                    v1.4.0-1-g955aabc -> v1.5.0-alpha.0-14-ge0c76c0\n* **github.com/spf13/cobra**                         v1.6.1 -> v1.7.0\n* **github.com/stretchr/testify**                    v1.8.2 -> v1.8.4\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.16 -> v0.56.17\n* **go.etcd.io/etcd/api/v3**                         v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/v3**                      v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.8 -> v3.5.9\n* **golang.org/x/net**                               v0.8.0 -> v0.11.0\n* **golang.org/x/sync**                              v0.1.0 -> v0.3.0\n* **golang.org/x/sys**                               v0.6.0 -> v0.9.0\n* **golang.org/x/term**                              v0.6.0 -> v0.9.0\n* **golang.org/x/text**                              v0.10.0 **_new_**\n* **golang.zx2c4.com/wireguard/wgctrl**              9c5414ab4bde -> 925a1e7659e6\n* **google.golang.org/grpc**                         v1.54.0 -> v1.56.1\n* **k8s.io/api**                                     v0.27.1 -> v0.27.3\n* **k8s.io/apimachinery**                            v0.27.1 -> v0.27.3\n* **k8s.io/apiserver**                               v0.27.1 -> v0.27.3\n* **k8s.io/client-go**                               v0.27.1 -> v0.27.3\n* **k8s.io/component-base**                          v0.27.1 -> v0.27.3\n* **k8s.io/cri-api**                                 v0.27.1 -> v0.27.3\n* **k8s.io/klog/v2**                                 v2.90.1 -> v2.100.1\n* **k8s.io/kubectl**                                 v0.27.1 -> v0.27.3\n* **k8s.io/kubelet**                                 v0.27.1 -> v0.27.3\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.68 -> v1.2.69\n\nPrevious release can be found at [v1.4.0](https://github.com/siderolabs/talos/releases/tag/v1.4.0)\n\n## [Talos 1.5.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.5.0-alpha.0) (2023-05-19)\n\nWelcome to the v1.5.0-alpha.0 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\n* Linux: 6.1.28\n* containerd: 1.6.21\n* runc: 1.1.7\n* etcd: 3.5.9\n* Kubernetes: 1.27.2\n\nTalos is built with Go 1.20.4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Utku Ozdemir\n* Dmitriy Matrenichev\n* Steve Francis\n* Budiman Jojo\n* Christian Rolland\n* Henk Kraal\n* Michael A. Davis\n* Michael Fornaro\n* Nico Berlee\n* Niklas Wik\n* Ricky Sadowski\n* Thomas Perronin\n\n### Changes\n<details><summary>69 commits</summary>\n<p>\n\n* [`383471c3e`](https://github.com/siderolabs/talos/commit/383471c3e956ff6e077a1de75b02a50835fbf352) feat: update default Kubernetes to v1.27.2\n* [`8f68d1abe`](https://github.com/siderolabs/talos/commit/8f68d1abeff83c3ff0e6c5d9f61cb14807b44ca5) chore: bump deps\n* [`e0c1585d3`](https://github.com/siderolabs/talos/commit/e0c1585d3047ef213134331dc57f8e2e8c23a93d) feat: create azure community gallery image version on release\n* [`dd8336c9e`](https://github.com/siderolabs/talos/commit/dd8336c9ee7f8a3a44d45c9f9e3cbbf741f84c44) fix: refresh kubelet self-issued serving certificates\n* [`bb02dd263`](https://github.com/siderolabs/talos/commit/bb02dd263cbc5e7e3839148d86a4a0a5f7ea998b) chore: drop deprecated stuff for Talos 1.5\n* [`61cad8673`](https://github.com/siderolabs/talos/commit/61cad86731e5c0aa80d7df41ea02d0b7ff579c45) chore: bump deps\n* [`01dfd3af7`](https://github.com/siderolabs/talos/commit/01dfd3af7d64dacd179d17d9d5eaf4bc44cf72af) feat: update etcd to v3.5.9\n* [`aa65fbb8a`](https://github.com/siderolabs/talos/commit/aa65fbb8a1752a70e7bac4e4e9872f35e88d1cc9) chore: update KUBECTL_URL to reflect the community bucket\n* [`cc3128d94`](https://github.com/siderolabs/talos/commit/cc3128d944abacfb633bc783b7fed6d0a6f80661) chore: bump kernel to 6.1.28\n* [`97fffaf78`](https://github.com/siderolabs/talos/commit/97fffaf78a0b9a1dc67709de11d37ea20aefde59) chore: use ctest.UpdateWithConflicts instead of plain UpdateWithConflicts\n* [`3b36993b9`](https://github.com/siderolabs/talos/commit/3b36993b9926392f4290e6fabc82e635f4c98149) fix: rlimit nofile test\n* [`45e6e27af`](https://github.com/siderolabs/talos/commit/45e6e27af75746fd0cc8b0f98a2d14579eb0ed40) chore: bump runtime\n* [`4f720d465`](https://github.com/siderolabs/talos/commit/4f720d46532af39165fc5051052d5c42595d91af) fix: revert: set rlimit explicitly in wrapperd\n* [`a2565f674`](https://github.com/siderolabs/talos/commit/a2565f67416e9b9bc22f2d5506df9ea7771c0c8c) fix: set rlimit explicitly in wrapperd\n* [`cdfc242b8`](https://github.com/siderolabs/talos/commit/cdfc242b8354f4cc4e7ce51bbe3a8fb20b35995d) chore: re-enable Go buildid\n* [`e67f3f5c5`](https://github.com/siderolabs/talos/commit/e67f3f5c5453f947355194ea9656c15ff008c35e) feat: linux 6.1.27, containerd 1.6.21, go 1.20.4\n* [`55ae59a0a`](https://github.com/siderolabs/talos/commit/55ae59a0ad71293676b3efed461f5ab98101401a) fix: properly skip/cleanup controlplane configs for workers\n* [`64eade9bd`](https://github.com/siderolabs/talos/commit/64eade9bde271bce4e629e6ac09407c8c42e01be) chore: clean up unused constant\n* [`62c6e9655`](https://github.com/siderolabs/talos/commit/62c6e9655cb639d4993aaa4c9b364342688599cb) feat: introduce siderolink config resource & reconnect\n* [`860002c73`](https://github.com/siderolabs/talos/commit/860002c7352bedd10845e11da37c80685ff0e720) fix: don't reload control plane pods on cert SANs changes\n* [`d43c61e80`](https://github.com/siderolabs/talos/commit/d43c61e80f5b05b81f2a021cdfe012e500c3d98e) fix: enforce nolock option for all NFS mounts by default\n* [`339986db9`](https://github.com/siderolabs/talos/commit/339986db9d3675b78ce0d268f799ad654862fb0f) fix: inhibit timer to follow kubelet timer\n* [`cbf6dc100`](https://github.com/siderolabs/talos/commit/cbf6dc1009ad47a2804774839e4e0301efa8ac78) fix: set timeout for unmount calls\n* [`b58f913d5`](https://github.com/siderolabs/talos/commit/b58f913d5f4b8ecf39be183d0bafe1109f0f0737) fix: set the static pod priority as values\n* [`f8a7a5b6b`](https://github.com/siderolabs/talos/commit/f8a7a5b6bf4138a33cbe5c9afe85db99de167aec) docs: add information about KubeSpan ports and topology\n* [`2bad74d64`](https://github.com/siderolabs/talos/commit/2bad74d6423c083ec34f1b422f23b0024d5f8798) docs: add how to on scaling down\n* [`7442ff8b0`](https://github.com/siderolabs/talos/commit/7442ff8b095ef1337f54332a71d08053a2832144) chore: fix typos inteface -> interface (docs and tests)\n* [`d4e94f7a1`](https://github.com/siderolabs/talos/commit/d4e94f7a15acf7f3c9e7532b067cdacd0e805bec) fix: add back required TARGETARCH for installer\n* [`e6fffda01`](https://github.com/siderolabs/talos/commit/e6fffda01385a2daaa901a5742f30a4edc9186a7) chore: linux 6.1.26, runc 1.1.7\n* [`344746ae2`](https://github.com/siderolabs/talos/commit/344746ae2fa038b704d02fec04c3d358762fe938) fix: bump max inhibit delay to 20 min\n* [`d9bdea2b5`](https://github.com/siderolabs/talos/commit/d9bdea2b54772f067783ee64eb85c834957d386a) chore: fork docs and compatibility modules for Talos 1.5\n* [`3d99610fc`](https://github.com/siderolabs/talos/commit/3d99610fc9b0d0084be822be29bb1bf2fbe85833) docs: document building, verifying image and process caps\n* [`014008ea2`](https://github.com/siderolabs/talos/commit/014008ea25208afbeabb42ef89238802705ad4e0) fix: udevd rules trigger\n* [`9b36bb613`](https://github.com/siderolabs/talos/commit/9b36bb613b44f182e47ae63bc74e4a8b6342d68d) feat: update Linux to 6.1.25, fix virtio on arm64\n* [`08ec66c55`](https://github.com/siderolabs/talos/commit/08ec66c55ccca3f9aa82a9703ebf183913b19a7e) feat: clean up (garbage collect) system images which are not referenced\n* [`b097efcde`](https://github.com/siderolabs/talos/commit/b097efcde29c20cdc4fed23fe8366bd683db634c) fix: display correct number of machines on dashboard\n* [`cad43f0ad`](https://github.com/siderolabs/talos/commit/cad43f0ad3bc2ede8a6ae81767c9226b6bc69f19) chore: remove k8s master label\n* [`e296a566e`](https://github.com/siderolabs/talos/commit/e296a566e6efb0cbdd119e73aff1feaa772d38bd) fix: support kernel userspace module loading\n* [`103f0ffdd`](https://github.com/siderolabs/talos/commit/103f0ffdd3ebd57a5086852f3502a8a7d4428faa) feat: add startup probes to controller-manager and scheduler\n* [`5a1ae8aae`](https://github.com/siderolabs/talos/commit/5a1ae8aae89e54d5540586d6f2e99ef3e80a72eb) chore: bump dependences\n* [`ec8c8dbaf`](https://github.com/siderolabs/talos/commit/ec8c8dbafcdaf63d036bdba92fa153d4d1c90100) chore: fix container image reproducibility\n* [`f661d8487`](https://github.com/siderolabs/talos/commit/f661d84877e6db5bc8856b982990926dcbfe949c) fix: allow `talosctl cp` to handle special files in `/proc`\n* [`2d824b563`](https://github.com/siderolabs/talos/commit/2d824b5639a4b8c3b673d13b08b2b97c69aafe0d) fix: do not show control plane status for workers on dashboard\n* [`e5491ddad`](https://github.com/siderolabs/talos/commit/e5491ddadeb1776bd5c17dd35917e05ec4847d0f) docs: update documentation for nocloud\n* [`7a004a6f7`](https://github.com/siderolabs/talos/commit/7a004a6f7f47fa5d17e855eb02650754d8411574) fix: parse errors correctly\n* [`374ef5385`](https://github.com/siderolabs/talos/commit/374ef53853947811dc221d99751cf0e16294508c) test: submit verbose flag to e2e tests\n* [`e1d38b6fe`](https://github.com/siderolabs/talos/commit/e1d38b6febf26fe31a6b9d6ed8f9b6bdba29aa3b) feat: show template URL in dashboard config URL tab\n* [`45d7f0ce9`](https://github.com/siderolabs/talos/commit/45d7f0ce95454ce85c403fc493ddb97e4d478238) docs: fix the latest url\n* [`96efbf147`](https://github.com/siderolabs/talos/commit/96efbf14769579d514ef9c75d01d9f44d276113a) docs: activate 1.4.0 docs by default\n* [`8c1f515b1`](https://github.com/siderolabs/talos/commit/8c1f515b1b8e40bce42e2fc04755afe5bf8a56aa) feat: update Linux to 6.1.24\n* [`8689bef5f`](https://github.com/siderolabs/talos/commit/8689bef5f10839091cf131edb6c8efad4ccba034) docs: update documentation for Talos 1.4\n* [`a781dfb8e`](https://github.com/siderolabs/talos/commit/a781dfb8e3ded67edcb2a6a1048bfe76c6bd0d24) feat: update Kubernetes to 1.27.1\n* [`a737dd83a`](https://github.com/siderolabs/talos/commit/a737dd83a4cd7549f85f8df0882f1c9a4446060d) chore: typo in `compatibility.ParseKubernetesVersion`\n* [`f14928b0a`](https://github.com/siderolabs/talos/commit/f14928b0a9dd3d85664605f4f6a206236ea94614) fix: fix dashboard crash when a non-existent node is specified\n* [`3e406d9b0`](https://github.com/siderolabs/talos/commit/3e406d9b07c0e67a2fb61e612bc3f378f3c35247) feat: update etcd to v3.5.8\n* [`bd1cff3e8`](https://github.com/siderolabs/talos/commit/bd1cff3e83530b9b89b27d8083ea8f3f0cf6ede4) chore: remove Go buildid\n* [`e31f7f50b`](https://github.com/siderolabs/talos/commit/e31f7f50b1b455beb98cd25859a44bbbccc1ff64) feat: update Kubernetes to 1.27.0\n* [`aa3640d74`](https://github.com/siderolabs/talos/commit/aa3640d74ce2e3619476453381909fa3520eb87d) docs: update storage.md\n* [`07bb61e60`](https://github.com/siderolabs/talos/commit/07bb61e60c53b267756dc97874b9c9554f2b1486) chore: module-sig-verify cleanup\n* [`5e9d836c3`](https://github.com/siderolabs/talos/commit/5e9d836c3d075c3edb2d48b2868c31a1c963e2de) chore: add kernel module signtaure verification\n* [`3cd1c6bb0`](https://github.com/siderolabs/talos/commit/3cd1c6bb0b83e5747a7356140a44b16deb4727e6) fix: send 'STOP' event on phase end\n* [`5176d27dc`](https://github.com/siderolabs/talos/commit/5176d27dc566d8689bb305398da7250269ebe9a3) feat: update Kubernetes to 1.27.0-rc.1\n* [`2c55550a6`](https://github.com/siderolabs/talos/commit/2c55550a66b49b49d8dc95b83516b7c0f8107300) fix: quote ISO kernel args for GRUB\n* [`319d76e38`](https://github.com/siderolabs/talos/commit/319d76e38978406d8d37e89ada2c403969d6c972) fix: respect BROWSER=echo in client auth interceptor\n* [`4e4ace839`](https://github.com/siderolabs/talos/commit/4e4ace839c0f558e7b00979fa4c64c32985aa3ce) chore: update Go to 1.20.3\n* [`170f73899`](https://github.com/siderolabs/talos/commit/170f73899a3bf29e9c6f76fdc5e510be08edf4aa) fix: correctly parse static pod phase\n* [`c3a595d5b`](https://github.com/siderolabs/talos/commit/c3a595d5b7d3c7c3091229caef6b2553416edb56) fix: improve action tracking post checks\n* [`eb01edbc8`](https://github.com/siderolabs/talos/commit/eb01edbc8a0ef5810693afe450861d5b63877b72) fix: rework DHCP flow\n* [`e095150a6`](https://github.com/siderolabs/talos/commit/e095150a6e34cbdc805a2cac85ec7f28f98629b4) test: bump CAPI components versions\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`36c8ac4`](https://github.com/siderolabs/extras/commit/36c8ac4ab98300059acaad501c2adc8abd39179f) chore: update to Go 1.20.3\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>3 commits</summary>\n<p>\n\n* [`f9f5805`](https://github.com/siderolabs/gen/commit/f9f5805973d30fe6bbac2f4a79ad4197fe59970e) chore: bump rekres and add functions from exp\n* [`b968d21`](https://github.com/siderolabs/gen/commit/b968d21c9671d97e54317f80cdf781d6f963e44b) feat: add `TryRecv` and `RecvWithContext` functions\n* [`476dfea`](https://github.com/siderolabs/gen/commit/476dfeae70882e1ca6e5cfed3d6e12dc36841a26) feat: add foreach and clear to lazymap\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`076874a`](https://github.com/siderolabs/go-blockdevice/commit/076874a155ad44d764d25081125f950e8194d023) chore: resolve blockdevice symlinks\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>1 commit</summary>\n<p>\n\n* [`f3a0e24`](https://github.com/siderolabs/go-loadbalancer/commit/f3a0e2411e08eef9c79876f3dc6e09e770710379) fix: use SO_LINGER option when doing TCP healthchecks\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>18 commits</summary>\n<p>\n\n* [`702d7a7`](https://github.com/siderolabs/pkgs/commit/702d7a7e90099d8fdc9cc4ba50e86c8ba6e91d77) chore: bump deps\n* [`7958db1`](https://github.com/siderolabs/pkgs/commit/7958db1549a7c7560eeeb8f9c06d3be9487d8804) chore: copy over sd-boot and sd-stub from tools\n* [`813b3c3`](https://github.com/siderolabs/pkgs/commit/813b3c3d3276d0d9156919307e9ffe521925d40b) chore: revert xfsprogs\n* [`0cc78ab`](https://github.com/siderolabs/pkgs/commit/0cc78ab82ce920c8fa5654c73738050107e190bb) chore: bump kernel to 6.1.28\n* [`70189e3`](https://github.com/siderolabs/pkgs/commit/70189e3df555fed4afade93798d72cd31aad99c5) chore: bump deps\n* [`c5d3bf1`](https://github.com/siderolabs/pkgs/commit/c5d3bf1985b49e688d29d06db6730834f65ee480) feat: add sd-stub and sd-boot\n* [`30a7ac2`](https://github.com/siderolabs/pkgs/commit/30a7ac2974fb7580e83819c76502fde77d777ea0) feat: update Linux 6.1.27, containerd 1.6.21\n* [`fbc6ee5`](https://github.com/siderolabs/pkgs/commit/fbc6ee55b6ffae44c117255901ab0fbecae79cc3) chore: bump deps\n* [`82b9489`](https://github.com/siderolabs/pkgs/commit/82b9489b88b108f144b45fb55432576bfd767f91) chore: bump dependencies\n* [`f37e520`](https://github.com/siderolabs/pkgs/commit/f37e5205cf10fe10296e86565fa018d149f5d8c4) feat: update Linux to 6.1.25\n* [`3920b16`](https://github.com/siderolabs/pkgs/commit/3920b163a5c6a6d7c7969155a909a7b2122e65f6) feat: add multi-gen LRU kernel support\n* [`988f1ec`](https://github.com/siderolabs/pkgs/commit/988f1ecf95536fb259cbd79e044a556728bc7332) feat: update Linux to 6.1.24\n* [`5327d12`](https://github.com/siderolabs/pkgs/commit/5327d1263680f76706ea667906ca08222c8398da) fix: remove FB_NVIDIA drivers, Linux 6.1.23\n* [`4eae958`](https://github.com/siderolabs/pkgs/commit/4eae958770573613bc29568d130be7aaa775e530) chore: copy over the kernel signing public key\n* [`174f8fc`](https://github.com/siderolabs/pkgs/commit/174f8fc9c80d871f1c03ea0a53dc8b6eb7112ccf) chore: update Go to 1.20.3\n* [`41629b0`](https://github.com/siderolabs/pkgs/commit/41629b03e82bfb77623a812000ef8e98d15d56fa) chore: reorder pkgs for better kernel caching\n* [`b483a6b`](https://github.com/siderolabs/pkgs/commit/b483a6b01f539b0da13ca09882015044bff24e41) feat: build 'snp.efi' for iPXE\n* [`fb853ff`](https://github.com/siderolabs/pkgs/commit/fb853ff6b1194cdc1f2412c776347cf4b55c3336) feat: update containerd to 1.6.20\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>8 commits</summary>\n<p>\n\n* [`d2dde48`](https://github.com/siderolabs/tools/commit/d2dde48f72343aa3c541336f5319b8e649e80c87) chore: bump deps\n* [`8e45ad7`](https://github.com/siderolabs/tools/commit/8e45ad75ea78e353ca3eae21b18da9a42d1edf49) feat: add sbsign\n* [`271c4a6`](https://github.com/siderolabs/tools/commit/271c4a66b6987d9de2c0d1d69891b5ff277ebd43) feat: add sd-tools\n* [`eedc294`](https://github.com/siderolabs/tools/commit/eedc294967d415cca40d4c427d3521cd198661d7) chore: bump deps\n* [`81b09a5`](https://github.com/siderolabs/tools/commit/81b09a5ab204f16306c980eeff518a0d1a37ddf2) feat: add libcap and gnuefi\n* [`47b0fd3`](https://github.com/siderolabs/tools/commit/47b0fd3e364d4fbcfffe10965f740db7acd82f70) chore: bump go to 1.20.4\n* [`ff4cf2b`](https://github.com/siderolabs/tools/commit/ff4cf2beabab310365ad9887abb6234570f5092a) chore: bump deps\n* [`1563556`](https://github.com/siderolabs/tools/commit/1563556b8f8fdf20d8aa58ac5340104c7ffe732e) feat: update Go to 1.20.3\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go**                      v1.44.232 -> v1.44.264\n* **github.com/beevik/ntp**                          v0.3.0 -> v1.0.0\n* **github.com/benbjohnson/clock**                   v1.1.0 -> v1.3.5\n* **github.com/cenkalti/backoff/v4**                 v4.2.0 -> v4.2.1\n* **github.com/containerd/containerd**               v1.6.19 -> v1.6.20\n* **github.com/containerd/typeurl/v2**               v2.1.1 **_new_**\n* **github.com/containernetworking/plugins**         v1.2.0 -> v1.3.0\n* **github.com/cosi-project/runtime**                v0.3.0 -> 82b69d862a7a\n* **github.com/docker/docker**                       v23.0.2 -> v23.0.6\n* **github.com/hetznercloud/hcloud-go**              v1.41.0 -> v1.45.1\n* **github.com/insomniacslk/dhcp**                   74ae03f2425e -> 49801966e6cb\n* **github.com/jsimonetti/rtnetlink**                v1.3.1 -> v1.3.3\n* **github.com/mdlayher/genetlink**                  v1.3.1 -> v1.3.2\n* **github.com/mdlayher/netlink**                    v1.7.1 -> v1.7.2\n* **github.com/mdlayher/netx**                       c711c2f8512f -> 7e21880baee8\n* **github.com/nberlee/go-netstat**                  v0.1.1 -> v0.1.2\n* **github.com/opencontainers/image-spec**           v1.1.0-rc2 -> v1.1.0-rc3\n* **github.com/rivo/tview**                          281d14d896d7 -> 822bd067b165\n* **github.com/rs/xid**                              v1.4.0 -> v1.5.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.15 -> v1.0.0-beta.16\n* **github.com/siderolabs/extras**                   v1.4.0-1-g9b07505 -> v1.5.0-alpha.0\n* **github.com/siderolabs/gen**                      v0.4.3 -> v0.4.5\n* **github.com/siderolabs/go-blockdevice**           v0.4.4 -> v0.4.5\n* **github.com/siderolabs/go-loadbalancer**          v0.2.1 -> v0.2.2\n* **github.com/siderolabs/pkgs**                     v1.4.1-5-ga333a84 -> v1.5.0-alpha.0-17-g702d7a7\n* **github.com/siderolabs/talos/pkg/machinery**      v1.4.0 -> v1.4.4\n* **github.com/siderolabs/tools**                    v1.4.0-1-g955aabc -> v1.5.0-alpha.0-7-gd2dde48\n* **github.com/spf13/cobra**                         v1.6.1 -> v1.7.0\n* **go.etcd.io/etcd/api/v3**                         v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/client/v3**                      v3.5.8 -> v3.5.9\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.8 -> v3.5.9\n* **golang.org/x/net**                               v0.8.0 -> v0.10.0\n* **golang.org/x/sync**                              v0.1.0 -> v0.2.0\n* **golang.org/x/sys**                               v0.6.0 -> v0.8.0\n* **golang.org/x/term**                              v0.6.0 -> v0.8.0\n* **golang.zx2c4.com/wireguard/wgctrl**              9c5414ab4bde -> 925a1e7659e6\n* **google.golang.org/grpc**                         v1.54.0 -> v1.55.0\n* **k8s.io/api**                                     v0.27.1 -> v0.27.2\n* **k8s.io/apimachinery**                            v0.27.1 -> v0.27.2\n* **k8s.io/apiserver**                               v0.27.1 -> v0.27.2\n* **k8s.io/client-go**                               v0.27.1 -> v0.27.2\n* **k8s.io/component-base**                          v0.27.1 -> v0.27.2\n* **k8s.io/klog/v2**                                 v2.90.1 -> v2.100.1\n* **k8s.io/kubectl**                                 v0.27.1 -> v0.27.2\n* **k8s.io/kubelet**                                 v0.27.1 -> v0.27.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.68 -> v1.2.69\n\nPrevious release can be found at [v1.4.0](https://github.com/siderolabs/talos/releases/tag/v1.4.0)\n\n## [Talos 1.4.0-alpha.4](https://github.com/siderolabs/talos/releases/tag/v1.4.0-alpha.4) (2023-03-31)\n\nWelcome to the v1.4.0-alpha.4 release of Talos!  \n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Bond Device Selectors\n\nBond links can now be described using device selectors instead of explicit device names:\n\n```yaml\nmachine:\n  network:\n    interfaces:\n      - interface: bond0\n        bond:\n          deviceSelectors:\n            - hardwareAddr: '00:50:56:*'\n            - hardwareAddr: '00:50:57:9c:2c:2d'\n```\n\n\n### talosctl containers\n\n`talosctl logs -k` and `talosctl containers -k` now support and output container display names with their ids.\nThis allows to distinguish between containers with the same name.\n\n\n### Registry Mirror Catch-All Option\n\nTalos now supports a catch-all option for registry mirrors:\n\n```yaml\nmachine:\n    registries:\n        mirrors:\n            docker.io:\n                - https://registry-1.docker.io/\n            \"*\":\n                - https://my-registry.example.com/\n```\n\n\n### Talos Dashboard on TTY2\n\nTalos now starts a text-based UI dashboard on virtual console `/dev/tty2` and switches to it by default upon boot.\nKernel logs remain available on `/dev/tty1`.\n\nTo switch TTYs, use the `Alt+F1` through `Alt+F2` keys.\n\nYou can disable this behavior by setting the kernel parameter `talos.dashboard.disabled=1`.\n\nThis behavior is disabled by default on SBCs.\n\n\n### Kernel Argument `talos.environment`\n\nTalos now supports passing environment variables via `talos.environment` kernel argument.\n\nExample:\n\n```\ntalos.environment=http_proxy=http://proxy.example.com:8080 talos.environment=https_proxy=http://proxy.example.com:8080\n```\n\n\n### etcd Maintenance\n\nTalos adds new APIs to make it easier to perform etcd maintenance operations.\n\nThese APIs are available via new `talosctl etcd` sub-commands:\n\n* `talosctl etcd alarm list|disarm`\n* `talosctl etcd defrag`\n* `talosctl etcd status`\n\nSee also [etcd maintenance guide](https://talos.dev/v1.4/advanced/etcd-maintenance/).\n\n\n### Kernel Modules\n\nTalos now supports automatically loading kernel drivers built as modules.\nIf any system extensions or the Talos base kernel build provides kernel modules and if they matches the system hardware (via PCI IDs), they will be loaded automatically.\nModules can still be loaded explicitly by defining it in [machine configuration](https://www.talos.dev/v1.4/reference/configuration/#kernelconfig).\n\n\n### Kernel Modules Tree\n\nTalos now supports re-building the kernel modules dependency tree information on upgrades.\nThis allows modules of same name to co-exist as in-tree and external modules.\nSystem Extensions can provide modules installed into `extras` directory and when loading it'll take precendence over the in-tree module.\n\n\n### Kernel Reset Argument\n\nTalos now supports `talos.experimental.wipe=system:EPHEMERAL,STATE` kernel argument.\nTalos now also supports the new GRUB boot option - \"Reset Talos installation and return to maintenance mode\".\nBoth of this options will reset EPHEMERAL and STATE partitions and will return Talos into maintenance mode after the reboot.\n\n\n### Machine Configuration\n\nStrategic merge config patches correctly support merging `.vlans` sections of the network interface.\n\n\n### talosctl netstat\n\nTalos API was extended to support retrieving a list of network connections (sockets) from the node and pods.\n`talosctl netstat` command was added to retrieve the list of network connections.\n\n\n### Reset API Enhancements\n\nTalos now supports resetting user disks through the Reset API,\nthe list of disks to wipe is set using the `--user-disks-to-wipe` parameter in `talosctl`.\nAdditionally, the Reset API can now function in maintenance mode\nand has the capability to wipe the node's system disk (partial wipe is not supported).\n\n\n### New Talos API os:operator role\n\nTalos now supports a new `os:operator` role for the Talos API.\nThis role allows everything `os:reader` role allows plus access to maintenance APIs:\nrebooting, shutting down a node, accessing packet capture, etcd alarm APIs, etcd backup, etc.\n\n\n### Component Updates\n\n* Linux: 6.1.22\n* containerd: v1.6.20\n* runc: v1.1.5\n* Kubernetes: v1.27.0-rc.0\n* etcd: v3.5.7\n* CoreDNS: v1.10.1\n* Flannel: v0.21.4\n\nTalos is built with Go 1.20.2.\n\n\n### VMware Platform\n\nTalos now supports loading network configuration on VMWare platform from the `metadata` key.\nSee [CAPV IPAM Support](https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/main/docs/proposal/20220929-ipam-support.md) and\n[Talos issue 6708](https://github.com/siderolabs/talos/issues/6708) for details.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Spencer Smith\n* Artem Chernyshev\n* Serge Logvinov\n* Steve Francis\n* Nico Berlee\n* Tim Jones\n* Seán C McCord\n* Steffen Windoffer\n* Andrey Smirnov\n* Cees-Jan Kiewiet\n* Chris van de Sande\n* Dennis Marttinen\n* Dzerom Dzenkins\n* Erik Lund\n* Jori Huisman\n* Lance R. Vick\n* Matthias Riegler\n* Michael Vorburger\n* Murtaza Udaipurwala\n* Niklas Wik\n* Rowan Smith\n* Samuel Kees\n* Sander Maijers\n* Thomas Way\n* Tim van Druenen\n* Victor Seva\n* budimanjojo\n* xyhhx\n\n### Changes\n<details><summary>200 commits</summary>\n<p>\n\n* [`7ffabe0f1`](https://github.com/siderolabs/talos/commit/7ffabe0f14dd3432857423743701ed5cdb3fe07f) feat: support network bond device selectors\n* [`cbab12e3a`](https://github.com/siderolabs/talos/commit/cbab12e3a1f2c576164bb721dc70073e6b8d3767) refactor: rename outbound to connectivity on dashboard\n* [`07c3c5d59`](https://github.com/siderolabs/talos/commit/07c3c5d59e02d82dbc1ff6f5392c2aa428503e0e) feat: return disk subsystem in the `Disks API`\n* [`b8497b99e`](https://github.com/siderolabs/talos/commit/b8497b99eb46fafd0f908c768d92683771f58cc3) feat: update containerd to 1.6.20\n* [`aa1499353`](https://github.com/siderolabs/talos/commit/aa149935390b0ea49e6b6de51a2eeccd6cbcbbcb) feat: introduce network probes\n* [`9dc1150e3`](https://github.com/siderolabs/talos/commit/9dc1150e3aa08e5cb85c8fb6ecf0cfec5c613029) docs: update nvidia instructions\n* [`7967ccfc1`](https://github.com/siderolabs/talos/commit/7967ccfc13a534cce32bb49558bb4bbeb5ee4480) feat: add config code entry screen to dashboard\n* [`ddb014cfd`](https://github.com/siderolabs/talos/commit/ddb014cfdcb3630055d5b7be7f480080612dfc11) fix: udevd rules trigger\n* [`0af8fe2fb`](https://github.com/siderolabs/talos/commit/0af8fe2fb547e01be1b1231d69ccf2fdc5f2ea0d) feat: netstat pod support\n* [`52e857f55`](https://github.com/siderolabs/talos/commit/52e857f55ef14e88ed5ac6f7fb73a08a5ec8fe7a) feat: linux 6.1.22, runc 1.1.5\n* [`aa662ff63`](https://github.com/siderolabs/talos/commit/aa662ff635f4739343489076bdb9a11722e28798) fix: apply small fixes on dashboard\n* [`188560a33`](https://github.com/siderolabs/talos/commit/188560a334a39f4e6472d196ce33bcfa88e41102) fix: add a link-scope route if the cmdline gateway is not reachable\n* [`45c5b47a5`](https://github.com/siderolabs/talos/commit/45c5b47a57c0c7efdc126f24f880238b9aec9781) feat: dhcpv4: send current hostname, fix spec compliance of renewals\n* [`289b41fe4`](https://github.com/siderolabs/talos/commit/289b41fe4b3af7bd4e1e61a1ca30dc1ed2b0d027) fix: output of `talosctl logs` might be corruped\n* [`02f0a4526`](https://github.com/siderolabs/talos/commit/02f0a4526d09334757a71d868d9e2ae70aa1aade) feat: allow writing initial META values into the image\n* [`ea0e9bdbe`](https://github.com/siderolabs/talos/commit/ea0e9bdbe454041f8895e0a869e28eabb5156430) feat: environment variables via the kernel arguments\n* [`94c24ca64`](https://github.com/siderolabs/talos/commit/94c24ca64e70f227da29cd02bd367d3c2701b96c) chore: add machine config version contract for v1.4\n* [`cefa9c3ec`](https://github.com/siderolabs/talos/commit/cefa9c3ecb5675c80b44a2fe3aaa55e402cab7a6) feat: update Kubernetes to 1.27.0-rc.0\n* [`9e8603f53`](https://github.com/siderolabs/talos/commit/9e8603f53b83e326a2529b2c595b619e04f2b85b) feat: implement new download URL variable `${code}`\n* [`d30cf9c86`](https://github.com/siderolabs/talos/commit/d30cf9c86efc30ce2c61b82be1bfb431cc74dd78) test: fix misprint in e2e scripts\n* [`0d0bb31cf`](https://github.com/siderolabs/talos/commit/0d0bb31cf766ece4c78ffe3f4094f94a9990d88c) fix: use stripped kernel modules\n* [`3583eea98`](https://github.com/siderolabs/talos/commit/3583eea9830d6701a1e5ee4a128e1819de4c94fd) release(v1.4.0-alpha.3): prepare release\n* [`a7b79ef1b`](https://github.com/siderolabs/talos/commit/a7b79ef1be79ca7e0ea1530d469c3790f43e6c6b) feat: add network config screen to dashboard\n* [`cf2ccc521`](https://github.com/siderolabs/talos/commit/cf2ccc521f6a15b8b82bf5fbaab572f481f8edf7) fix: always shutdown maintenance API service\n* [`a0a5db590`](https://github.com/siderolabs/talos/commit/a0a5db590d9b5f312f9e59bec4ddc7379183c705) feat: update Flannel to 0.21.4\n* [`d1a61fd34`](https://github.com/siderolabs/talos/commit/d1a61fd34343e58192864b1464759b78eb57e917) chore: bump golangci-lint\n* [`36a9a208e`](https://github.com/siderolabs/talos/commit/36a9a208ecf01114f5cc47449bb69099fca99e83) chore: bump deps\n* [`c63cf90e3`](https://github.com/siderolabs/talos/commit/c63cf90e32ce61e788a00ed79a5ff662d3d25e50) feat: update k8s to v1.27.0-beta.0\n* [`b246c90ab`](https://github.com/siderolabs/talos/commit/b246c90abdec14c305dbad8af82147ebe44328ce) fix: add uint32 to Magic1 and Magic2\n* [`777c8d6f6`](https://github.com/siderolabs/talos/commit/777c8d6f6ecb438d11ac829a297bf2c6b5660479) chore: update COSI to watch aggregated version\n* [`bec89bf6e`](https://github.com/siderolabs/talos/commit/bec89bf6e575923f348a4885841de27eead020df) fix: use 'no block' etcd dial with multiple endpoints\n* [`28713c2c4`](https://github.com/siderolabs/talos/commit/28713c2c4d4d20d5ff455c40cbb8aa004d725801) feat: update Kubernetes to 1.26.3\n* [`a3cf41647`](https://github.com/siderolabs/talos/commit/a3cf4164755609e80de5dafa2c49bfaa0fc655fd) docs: add InstallConfig ignored notice to doc\n* [`df9b851fb`](https://github.com/siderolabs/talos/commit/df9b851fbadaa7c652f343c2facc2bd0a9dd22ca) chore: load all external artifacts earlier\n* [`2dd0964c5`](https://github.com/siderolabs/talos/commit/2dd0964c5f617a7072af08bd45c35d57bc47e838) refactor: use resource watches on dashboard\n* [`9933ebb6a`](https://github.com/siderolabs/talos/commit/9933ebb6aa86249d2118ef5fb50bf23cedadb0a5) chore: fix loaded artifacts file permission\n* [`a14a0aba0`](https://github.com/siderolabs/talos/commit/a14a0aba04a2daf277bf2703575def39b7f2e5e9) fix: nil pointer exception in syncLink\n* [`cf101e56f`](https://github.com/siderolabs/talos/commit/cf101e56fbf18bb401bebb95e9fe005f65765d3d) fix: add `--force` flag for `talosctl gen`\n* [`ea2aa0611`](https://github.com/siderolabs/talos/commit/ea2aa06116a1b3c58d40ad42787749783516ef6c) fix: fix data race on network config read\n* [`64e3d24c6`](https://github.com/siderolabs/talos/commit/64e3d24c6bfe60b5556c41822c8e81f63d0a06d2) feat: provide platform network config for 'metal' in META\n* [`442cb9c1b`](https://github.com/siderolabs/talos/commit/442cb9c1b0757a9c8204cc92baab11f664cbcb19) feat: implement APIs to write to META\n* [`9e07832db`](https://github.com/siderolabs/talos/commit/9e07832db9e19e602332821769f479b881fae178) feat: implement summary dashboard\n* [`1df841bb5`](https://github.com/siderolabs/talos/commit/1df841bb542323adce92013cd55eb24ab238a1dc) refactor: change the interface of META\n* [`e9962bc3e`](https://github.com/siderolabs/talos/commit/e9962bc3eaa31b9a782c2fcd0c7857a86cba0c28) chore: update CI to tag azure buckets\n* [`9f5f5cf9b`](https://github.com/siderolabs/talos/commit/9f5f5cf9bf83e9cff0be7720d6bffc13fec97570) feat: update Flannel to v0.21.3\n* [`02b0ff35e`](https://github.com/siderolabs/talos/commit/02b0ff35ee2273e59899ac4a999fa101d895aec0) feat: generate Flannel CNI manifest from upstream\n* [`6656d35ec`](https://github.com/siderolabs/talos/commit/6656d35eca5ec78cd52e7a6478369200ce16b176) docs: fix Talos version to use template\n* [`72a6d1d70`](https://github.com/siderolabs/talos/commit/72a6d1d70813986f6e9f4b7fc92e594f6ff7da1f) docs: update nocloud\n* [`9948a646d`](https://github.com/siderolabs/talos/commit/9948a646d20f4ba80916a263ed7bca3e5ca2f0ad) feat: coredns node uninitialized toleration\n* [`e03902b54`](https://github.com/siderolabs/talos/commit/e03902b546b379c19ea80081bbfaef666d03812d) feat: update Go to 1.20.2\n* [`c8f8579f2`](https://github.com/siderolabs/talos/commit/c8f8579f2dcf485e66922679d37e56742b65cc53) fix: upgrade-k8s to flag should not be required since there is a default\n* [`230cfaf80`](https://github.com/siderolabs/talos/commit/230cfaf80312518222469939e969880040c379f2) feat: use network information from guestinfo.metadata\n* [`97048f7c3`](https://github.com/siderolabs/talos/commit/97048f7c37ed7b7aceadf6f2e40f007a09c57730) feat: netstat in API and client\n* [`fda6da692`](https://github.com/siderolabs/talos/commit/fda6da692956d863d320f25cd50833da2f93104c) fix: successful ACPI shutdown in maintenance mode\n* [`b97e1abaa`](https://github.com/siderolabs/talos/commit/b97e1abaa6a1543bc7b6e8fa7e4fa9e0cb5d8e14) feat: set default image, validate empty image\n* [`121220a3b`](https://github.com/siderolabs/talos/commit/121220a3b3202de9bd08dce391740c9a66ad9cf2) chore: bump dependencies via renovate bot\n* [`ebc92f3c1`](https://github.com/siderolabs/talos/commit/ebc92f3c1de97a8b11046268854e957be0b64f81) chore: add container id to `talosctl -k containers` and `talosctl -k logs`\n* [`22ef81c1e`](https://github.com/siderolabs/talos/commit/22ef81c1e78963a8f46e2f54d00cd111742dd95c) feat: add grub option to drop to maintenance mode\n* [`642fe0c90`](https://github.com/siderolabs/talos/commit/642fe0c90c4714aeb5f880946c1d337c53bc6fa4) feat: update pkgs with framebuffer console\n* [`69cb414f0`](https://github.com/siderolabs/talos/commit/69cb414f01d3193931e838f89e21b0c9ac26bf61) docs: update cilium install instructions\n* [`e71cc6619`](https://github.com/siderolabs/talos/commit/e71cc6619b2cdc34efe8dccca3cc296befef43f9) fix: redo assertHostnames in HostnameMergeSuite.TestMerge\n* [`8ea4bfad8`](https://github.com/siderolabs/talos/commit/8ea4bfad8feae5f4806be0ea4f6fdd1b79a8197a) refactor: improve the kubernetes upgrade flow\n* [`81879fc0c`](https://github.com/siderolabs/talos/commit/81879fc0ca98cc3e5df619bd071c279a735697e3) docs: add how tos for workloads on control planes, and scaling up\n* [`05b0b721c`](https://github.com/siderolabs/talos/commit/05b0b721c9d2acd211519d554d1c23926472a5b4) chore: move blob storage to azure for builds\n* [`a78281214`](https://github.com/siderolabs/talos/commit/a78281214d349c147498e3b000a9e9aeecb29eb6) feat: add cilium e2e tests\n* [`061640ccc`](https://github.com/siderolabs/talos/commit/061640cccf69d065806140e670e484c8b1c5a26e) feat: add pod ip to kube-proxy spec\n* [`dea17d723`](https://github.com/siderolabs/talos/commit/dea17d72340b1deddea2215b556a4f193d1feb7f) feat: update Kubernetes to v1.26.2\n* [`337aaba7a`](https://github.com/siderolabs/talos/commit/337aaba7a705536b885d7336343b828dd13e1de4) feat: add 'os:operator' role\n* [`40e69af22`](https://github.com/siderolabs/talos/commit/40e69af2242fcd91f4a351da02de1b94158d419c) fix: improve etcd leave on reset process\n* [`638dc9128`](https://github.com/siderolabs/talos/commit/638dc9128fd89f70ddab8d6f342ca5a2e5131be8) fix: fix \"defer\" leak in ResetUserDisks\n* [`bfba3677b`](https://github.com/siderolabs/talos/commit/bfba3677b0e85a27a8b92235f5763ac6fc8e0375) chore: handle grub option - \"wipe\"\n* [`594f27d87`](https://github.com/siderolabs/talos/commit/594f27d87870ef26fc7166a95a64a40d27cb165a) release(v1.4.0-alpha.2): prepare release\n* [`b52071081`](https://github.com/siderolabs/talos/commit/b5207108104eda426361c256ec4d78ae9e0b2890) feat: introduce new flag in reset API that makes Talos reset user disks\n* [`f55f5df73`](https://github.com/siderolabs/talos/commit/f55f5df7396b7073e75267c7e10a35814f1185c9) feat: move dashboard package & run it in tty2\n* [`36e077ead`](https://github.com/siderolabs/talos/commit/36e077ead458f15e864f62eeb0d7afa59187c226) chore: bump deps\n* [`5a01d5fd4`](https://github.com/siderolabs/talos/commit/5a01d5fd473cdc4e0b9fba48047d6434cf31ee42) chore: run extension build as downstream\n* [`426fe9687`](https://github.com/siderolabs/talos/commit/426fe9687d74690df26ce3cfd6aee47c13e994a8) fix: extension base folder permission\n* [`609d3a8a6`](https://github.com/siderolabs/talos/commit/609d3a8a694ff90426ce33be86791f2616ec4852) feat: support strategic merge patches on VLAN configuration\n* [`7e19f32d7`](https://github.com/siderolabs/talos/commit/7e19f32d762dc1363f29e988ddbe334bd00610f2) chore: provide version compatibility data for Talos 1.2.x\n* [`230e46e56`](https://github.com/siderolabs/talos/commit/230e46e567012d8e12e384c777d6f57db5e7cfee) refactor: extract parts of kubernetes libraries\n* [`f3d3f0f26`](https://github.com/siderolabs/talos/commit/f3d3f0f2625f1be41a17366ee1c0bd2a3193c08c) fix: update go-smbios library with Hyper-V data fix\n* [`8711eea96`](https://github.com/siderolabs/talos/commit/8711eea9626a60a996347aaa7e6a89eea87d4b9e) fix: use passed `--context` in `talosctl config` cmd\n* [`5ac9f43e4`](https://github.com/siderolabs/talos/commit/5ac9f43e45f85f8d37c2855051b9a5cc9ad389ac) feat: start machined earlier & in maintenance mode\n* [`36ab414a1`](https://github.com/siderolabs/talos/commit/36ab414a1d7c5472522d20a7b698c4eebb3423b9) docs: fix the endpoints in the libvirt guide\n* [`3d55bd80f`](https://github.com/siderolabs/talos/commit/3d55bd80f42b7d2439541909c9534c386607e578) fix: add `--force` flag to `talosctl gen config`\n* [`660b8874d`](https://github.com/siderolabs/talos/commit/660b8874da7bd91946aab5f400e7d1dfddefb827) feat: cmdline integer netmask\n* [`1e3daacc4`](https://github.com/siderolabs/talos/commit/1e3daacc48c0b8ef2eab41b2c2c53f55522e1acf) docs: update nvidia component versions\n* [`b5c03a7fa`](https://github.com/siderolabs/talos/commit/b5c03a7fab8d213e7048a8f5fc129125b81eb205) fix: docker talosctl cluster create provisioner\n* [`6e8f13529`](https://github.com/siderolabs/talos/commit/6e8f13529c17ff4c658b340d16d9ee429cfd9a4c) fix: add support for a fallback '*' mirror configuration\n* [`dcd4eb1a9`](https://github.com/siderolabs/talos/commit/dcd4eb1a93737d60f60693d8c33a20052eee4a4f) fix: improve error message on single node upgrade\n* [`ed5af3f78`](https://github.com/siderolabs/talos/commit/ed5af3f780732fb0004ddb263feedbf2de9fd09a) chore: bump deps\n* [`0dc6858e5`](https://github.com/siderolabs/talos/commit/0dc6858e5ba4b110eac9ca74294eb3a29790a323) chore: bump cosi-project/runtime\n* [`da2edb9de`](https://github.com/siderolabs/talos/commit/da2edb9de067fc21c792e948903bc2c880b2c2d1) chore: bump dependencies\n* [`e51a110f0`](https://github.com/siderolabs/talos/commit/e51a110f0e876fc091aee0828aca0135499def9c) chore: bump dependencies\n* [`2d0148018`](https://github.com/siderolabs/talos/commit/2d014801803fa0d5f08a344bdc9ff078b3931633) feat: automatically load modules based on hw info\n* [`7b75cd8b9`](https://github.com/siderolabs/talos/commit/7b75cd8b94367645adb2dd5be016e6f98d8e6a89) fix: kernel module dependency tree generation\n* [`65d02e5ad`](https://github.com/siderolabs/talos/commit/65d02e5ade08354aeec794d4131a1f8913fba2b5) fix: dbus shutdown when it's not initialized\n* [`a7079ce85`](https://github.com/siderolabs/talos/commit/a7079ce85c9839933544b637100f104f02fd3f3a) fix: quote the ampersand character in GRUB config\n* [`933ba2d82`](https://github.com/siderolabs/talos/commit/933ba2d8203e4418414b3de1c4240c1f88cb033e) fix: display correct blockdevice size\n* [`c449cb736`](https://github.com/siderolabs/talos/commit/c449cb736b24b268b965da5e2932f18bd4fb7785) fix: talosctl reboot command passing mode in wait mode\n* [`34ab0007a`](https://github.com/siderolabs/talos/commit/34ab0007a61bbb685d8c194c06568974db2a7375) docs: port is needed for wireguard endpoint\n* [`1e1aa84f6`](https://github.com/siderolabs/talos/commit/1e1aa84f6cdd0fbe6dd35841b6195cc56f10d333) fix: kubernetes removed resource version check\n* [`dcbcf5a93`](https://github.com/siderolabs/talos/commit/dcbcf5a93c3d82f8fdd7b8ffef3819010bd1c481) fix: wait for network and retry in platform get config funcs\n* [`3d7566ec7`](https://github.com/siderolabs/talos/commit/3d7566ec743f573a43a4a49ecb80f6ba59cbb27b) test: update Canal CNI manifest URL\n* [`e09e10666`](https://github.com/siderolabs/talos/commit/e09e106665aa8716f14ba49d527d8cb182592da7) fix: default dns domain to 'cluster.local' in local case\n* [`cc6e37a47`](https://github.com/siderolabs/talos/commit/cc6e37a47fd2ca9f1e43ce8ba2c1e8d8bfe44776) feat: use process wrapper for dropping capabilities\n* [`0c6c88874`](https://github.com/siderolabs/talos/commit/0c6c888745c5482fcf3891c922cc7cc7f72e6af4) fix: trackable action flag usage text. --no-wait does not exist\n* [`5cb2915d8`](https://github.com/siderolabs/talos/commit/5cb2915d8ea6e4ba913396abe3f45235e6a67213) feat: use wrapper for starting processes\n* [`56d945326`](https://github.com/siderolabs/talos/commit/56d9453261d47c0739be21cb7a5fe6beb25cb92c) fix: panic in talosctl cluster show\n* [`38a51191e`](https://github.com/siderolabs/talos/commit/38a51191e49059e93f4adfea479c039819a7f730) fix: correctly expand parameters in the URL\n* [`af21860a2`](https://github.com/siderolabs/talos/commit/af21860a22598361f68cf49e62a12da54bc95337) fix: return proper error if download attempts time out\n* [`54f7d4c92`](https://github.com/siderolabs/talos/commit/54f7d4c9231e858216f3b69b2662d7cc188df4f9) fix: correctly quote and unquote strings in GRUB config\n* [`54cf0672a`](https://github.com/siderolabs/talos/commit/54cf0672a71a8c9427c66bb2601521a9d24f8e13) fix: omit zero MTU in the machine config\n* [`bdc53ac25`](https://github.com/siderolabs/talos/commit/bdc53ac254a4aaa37ffd917c7c3ad506368205de) docs: add hyperlink to Docker API docs about `config.json`\n* [`b3bc06dd1`](https://github.com/siderolabs/talos/commit/b3bc06dd14c7faa75269cb6686b2d93ce765595c) chore: bump vtprotobuf to v0.4.0\n* [`0ba5e59f6`](https://github.com/siderolabs/talos/commit/0ba5e59f69c08ab566177df9e26a21648bcde54f) fix: drone config for renovate PR's\n* [`590a393de`](https://github.com/siderolabs/talos/commit/590a393de968556bb5e19594b2f057d4233c378d) fix: udevd healthcheck\n* [`2b6b6deac`](https://github.com/siderolabs/talos/commit/2b6b6deacda4a3cdf6c5b65ac586cad1363be094) docs: simplify and clarify digital ocean docs\n* [`92bc15f7f`](https://github.com/siderolabs/talos/commit/92bc15f7f1c561b1e7810371df23f84c7e0d6a1c) release(v1.4.0-alpha.1): prepare release\n* [`e3da4754e`](https://github.com/siderolabs/talos/commit/e3da4754e7a2e69b998b861034c6f77e2cf6355b) feat: update Linux to 6.1.7\n* [`006449e46`](https://github.com/siderolabs/talos/commit/006449e464ac009e15d78bb4d71cee80f2540f31) test: build integration test early in the pipeline\n* [`09aa71264`](https://github.com/siderolabs/talos/commit/09aa7126422b9b41e74c3d2aacb563daeca33bc5) fix: renovate config\n* [`2d136f187`](https://github.com/siderolabs/talos/commit/2d136f1879ee66dbd61ab40bb001a45c0bafaad5) feat: set markdown and html descriptions in config json schema\n* [`f0804027a`](https://github.com/siderolabs/talos/commit/f0804027a499a6e195f049144bff4f939dee3780) fix: renovate config\n* [`812a2877c`](https://github.com/siderolabs/talos/commit/812a2877cdc1e631ae0244f9696a65e2347594c0) chore: bump deps + renovate cleanup\n* [`aa9f66c1c`](https://github.com/siderolabs/talos/commit/aa9f66c1c88a1bb35aefe24ea0a5c3a6e7aa966d) fix: mark DigitalOcean anchor IP as scope link\n* [`bb4937f1b`](https://github.com/siderolabs/talos/commit/bb4937f1b339384fb486cb0cb675df8bf9b9f916) feat: enable renovate\n* [`3e0057162`](https://github.com/siderolabs/talos/commit/3e00571627568d8c5ab10a72e59207677a89e4cc) fix: unwrap gRPC errors on stop/remove pods check\n* [`00e52ae07`](https://github.com/siderolabs/talos/commit/00e52ae07867deff9a5877fcb498252bc1b1a740) fix: build correctly etcd initial cluster URL\n* [`ae83b10ae`](https://github.com/siderolabs/talos/commit/ae83b10ae89dbe600ddfaa338be95ea819546007) feat: create JSON schema for v1alpha1.Config\n* [`703d96595`](https://github.com/siderolabs/talos/commit/703d9659512d744a606e520faf230e20efddfc4a) feat: update Kubernetes to 1.26.1, etcd to 3.5.7\n* [`965e64591`](https://github.com/siderolabs/talos/commit/965e645915d080487a74b35dc8f1d2e4051f0504) docs: update to use talosctl install script\n* [`c5954f434`](https://github.com/siderolabs/talos/commit/c5954f4345cbf3a92c777a0e7fc5d39e883609bf) chore: bump deps\n* [`bb50f6a56`](https://github.com/siderolabs/talos/commit/bb50f6a56d971915abb6a895aac9d7e0612a3255) chore: preallocate disk images for QEMU VMs\n* [`d4b8b35de`](https://github.com/siderolabs/talos/commit/d4b8b35de7849d887c41f9a13dadb59ccd8c08c4) feat: generate kernel module dependency tree\n* [`18122ae73`](https://github.com/siderolabs/talos/commit/18122ae73e0489a0497956c6d4621c05c6a77387) fix: service restart (including extension services)\n* [`680fd5e45`](https://github.com/siderolabs/talos/commit/680fd5e452e02b108b7938d0136079c16e6cfd79) fix: bump COSI runtime with the panic controller restart fix\n* [`0b65bbfc8`](https://github.com/siderolabs/talos/commit/0b65bbfc878fe2a5c01c5d2cd08006b53fda7cf9) fix: handle overwriting tags in syslinux ADV\n* [`70d9428a1`](https://github.com/siderolabs/talos/commit/70d9428a1d00d9894d68f38b255debb66fe8a440) fix: kubespan MSS clamping\n* [`683b4ccb4`](https://github.com/siderolabs/talos/commit/683b4ccb4faab6c3da2de00f7314773f42899c25) chore: update Go to 1.19.5 and kernel to 6.1.4\n* [`062c7d754`](https://github.com/siderolabs/talos/commit/062c7d754be1714c7763b8f2b399436d64c90ea4) test: fix integration test on cp endpoint update\n* [`8e9fc13d7`](https://github.com/siderolabs/talos/commit/8e9fc13d7c48da5c5354501e0ad96688670438cf) feat: implement enum generator for proto files\n* [`771b0dc06`](https://github.com/siderolabs/talos/commit/771b0dc061e0fa33085b28bd0d0a7e4da13081f1) docs: update left over rpi_4 ref to rpi_generic\n* [`6c04b5f79`](https://github.com/siderolabs/talos/commit/6c04b5f79e6e01e0a3cdabfc99f12c944edd1f0a) chore: bump dependencies\n* [`0a5a8802e`](https://github.com/siderolabs/talos/commit/0a5a8802e7e337e1f30a40c9f566e57642c39c1a) feat: use 'localhost' endpoint for controlplane nodes\n* [`b0775ebf2`](https://github.com/siderolabs/talos/commit/b0775ebf2c776c7133cf74c6259de9dc9573786c) feat: add ISO wipe GRUB boot option\n* [`29020cb9c`](https://github.com/siderolabs/talos/commit/29020cb9c788d87a0457028ce73c8d297959116e) fix: report fatal sequence errors as reboots\n* [`96629d5ba`](https://github.com/siderolabs/talos/commit/96629d5ba6c1ae9d820824fb38f68112bce27f2c) feat: implement etcd maintenance commands\n* [`80fed3194`](https://github.com/siderolabs/talos/commit/80fed319408be9e493141fb2c01e5731708835c7) feat: include Kubernetes controlplane endpoint as one of the endpoints\n* [`c6cb36cc1`](https://github.com/siderolabs/talos/commit/c6cb36cc1f50b5d0e59a5284867e7534dc9f73bb) docs: fix auditpolicy example typo\n* [`ba8265bc5`](https://github.com/siderolabs/talos/commit/ba8265bc5ce63bcbc6fbd6c1a1076dc3f2ee6bd0) feat: new talosctl config remove to remove context\n* [`fcb19ff51`](https://github.com/siderolabs/talos/commit/fcb19ff516cc1200ec81f2a954bb6d2ce39ebdc6) fix: implement upgrade version checks for Talos 1.4\n* [`80f150ac8`](https://github.com/siderolabs/talos/commit/80f150ac859f5dbf95060c12440afab8c0bc77a8) feat: enable ipv6 on gcp\n* [`8db622f3d`](https://github.com/siderolabs/talos/commit/8db622f3dc75aed90dd2d0bd92d03aa7e8aefd10) docs: add Vandebron to adopters list\n* [`f6a86ae90`](https://github.com/siderolabs/talos/commit/f6a86ae90607914c29875df750fe79cbbfcc5897) fix: oralce cloud zone\n* [`89dbb0ecf`](https://github.com/siderolabs/talos/commit/89dbb0ecf089bb746479238df274ccba4fcb049a) release(v1.4.0-alpha.0): prepare release\n* [`31fb90535`](https://github.com/siderolabs/talos/commit/31fb9053582190b3b536a309c30e2b78c4611885) feat: update Linux 6.1.1, containerd 1.6.14\n* [`a0c0352dd`](https://github.com/siderolabs/talos/commit/a0c0352ddca253e1efb3679224b317692d46b2fd) fix: send diagnostic output to stderr consistently\n* [`9a5f4c08a`](https://github.com/siderolabs/talos/commit/9a5f4c08a206504a1d30277dcc0597333e5a927a) fix: default the manifest namespace if not set\n* [`3c6cce5fe`](https://github.com/siderolabs/talos/commit/3c6cce5fe47075f43a73682b57a7b40fa0899795) docs: update last release for Talos 1.2.x\n* [`703624c43`](https://github.com/siderolabs/talos/commit/703624c43dd8e58c147ccbc3989c6c436c9f3a7f) docs: fix the 1.3 release date\n* [`386c9293a`](https://github.com/siderolabs/talos/commit/386c9293a33e9d237fbeda0492b01b11fdadc501) docs: update nvidia-container-runtime version\n* [`ff83d9fd7`](https://github.com/siderolabs/talos/commit/ff83d9fd7bed2e04d5c8107713150c2513f47991) fix: improve talosctl completion\n* [`31ff431fa`](https://github.com/siderolabs/talos/commit/31ff431faec22c09cad88d565102e6a24785ecb4) chore: add schulz systemtechnik to the list\n* [`97bef7c47`](https://github.com/siderolabs/talos/commit/97bef7c47bfd133f2b3ad19efe3f30a88dd67460) docs: vsphere.sh > vmware.sh\n* [`34babe858`](https://github.com/siderolabs/talos/commit/34babe858d15145a1c596febb5e577473e4ffce0) chore: make organization selection an interface\n* [`a9643b477`](https://github.com/siderolabs/talos/commit/a9643b477417029db73aacbfcf5778cedd97cd95) fix: use proper key usage for apid client certificate\n* [`171aa9467`](https://github.com/siderolabs/talos/commit/171aa9467966f5869e72374961ea05abc8d9fda9) fix: disable Wireless Lan using dtoverlay\n* [`2e84d2ab3`](https://github.com/siderolabs/talos/commit/2e84d2ab3417515f539a70d58885dcb69e9f098c) chore: update conformance product.yaml\n* [`b7763843a`](https://github.com/siderolabs/talos/commit/b7763843af63bbc186f08701a62c19ea96fb7e3c) feat: add install script that improves talosctl installation user experience This install script detects the platform and architecture, and downloads the correct talosctl, and checks the gpg checksums. It also installs and chmods the binary.\n* [`afc45ad63`](https://github.com/siderolabs/talos/commit/afc45ad632e63cc3afc095b1f3efe6df3ecb9cb1) docs: mark Talos 1.3 docs as default\n* [`873bd3807`](https://github.com/siderolabs/talos/commit/873bd3807c0fcca2e212deb7fd044662557964c1) fix: redact service account key in config in RedactSecrets method\n* [`b3aebfadf`](https://github.com/siderolabs/talos/commit/b3aebfadfc15544e5ab448d979129dba5e516c59) feat: validate Talos API access roles in machine config\n* [`40761e17d`](https://github.com/siderolabs/talos/commit/40761e17db5789f30eef2f15f0b5c6396e09a9e5) docs: fork docs for Talos 1.4\n* [`474604cd2`](https://github.com/siderolabs/talos/commit/474604cd279def7a6798e24ede27feef955ba5a3) docs: update documentation for Talos 1.3\n* [`faf49218c`](https://github.com/siderolabs/talos/commit/faf49218ce14a48829dae7b3b8d7801188453a89) feat: add more checks for K8s upgrade\n* [`5b992bd86`](https://github.com/siderolabs/talos/commit/5b992bd8610f41d23d8b7dbd01f9a1be298eda96) fix: allow empty dnsDomain in machine config\n* [`eb332cfcb`](https://github.com/siderolabs/talos/commit/eb332cfcb785e250c422d6a7ea2b23679189a946) feat: add health check for a minimal memory / disk size\n* [`d04970dfa`](https://github.com/siderolabs/talos/commit/d04970dfa9d6554e1ee447fd9383bf65b8953671) fix: ignore k8s additional addresses if nil\n* [`63c17104c`](https://github.com/siderolabs/talos/commit/63c17104c594dfd9ca4066ba41d8a03507464874) feat: update Kubernets to 1.26.0\n* [`f7a9a90db`](https://github.com/siderolabs/talos/commit/f7a9a90db2bfd316ea01551daba9becb15361f94) chore: update pkgs/tools (Go 1.19.4, containerd 1.6.11)\n* [`cf7adc51c`](https://github.com/siderolabs/talos/commit/cf7adc51c9f53234e469dd9f0cca06eed0230e8b) feat: add RedactSecrets method to v1alpha1.Config\n* [`4c31b9b1a`](https://github.com/siderolabs/talos/commit/4c31b9b1a3a00df0fe817c3edc15260ca3cadd6d) docs: clarify what the deal is with /var\n* [`a8ebcca4a`](https://github.com/siderolabs/talos/commit/a8ebcca4a9f63643f68d8e85bcb0b9ddb49205ed) chore: remove `watchErr` from `metal.getResource`\n* [`1253513bd`](https://github.com/siderolabs/talos/commit/1253513bd1deecc4cc42330bad0a713b3630240a) fix: fix nil pointer panic and incorrect error output\n* [`82e8c9e1f`](https://github.com/siderolabs/talos/commit/82e8c9e1f63371f41b0794b4c1be3209847c5f8b) fix: workaround panic in the kubelet service controller\n* [`a505b8909`](https://github.com/siderolabs/talos/commit/a505b8909a1c733b30f22a8d46eebc022475431a) fix: update COSI and reset restart backoff on success\n* [`e92fdcbad`](https://github.com/siderolabs/talos/commit/e92fdcbad1de595d119f78dbed3a97ae46df9bbf) chore: bump kernel to 5.15.81\n* [`f0dddca2a`](https://github.com/siderolabs/talos/commit/f0dddca2a3d2e976cee543ab57816a6395fe3d65) docs: expand help for 'talosctl get'\n* [`fcffc8879`](https://github.com/siderolabs/talos/commit/fcffc88790b5a3006b3b85744771a7eef6e8ac5c) fix: add ext4 filesystem detection\n* [`5b2960eff`](https://github.com/siderolabs/talos/commit/5b2960efff8b38af85b687a25fa93f01256016de) fix: introduce 'overridePath' setting and fix Talos resolver\n* [`0219d1124`](https://github.com/siderolabs/talos/commit/0219d1124e5125696364bf92ecf0e8dcad644001) fix: use only kube-apiserver endpoints for Talos API access endpoints\n* [`dc5e0f4af`](https://github.com/siderolabs/talos/commit/dc5e0f4af087d3b662b0240b4f8fd76379ed0de2) fix: report errors to Equinix Metal event API\n* [`7ab140a94`](https://github.com/siderolabs/talos/commit/7ab140a94ad1a279be43669d6d70687f3a0c47de) feat: add talosctl machineconfig patch command\n* [`d3cf06114`](https://github.com/siderolabs/talos/commit/d3cf061149a4a502317d7728c45b6cfb4d38f89f) fix: ignore many more filesystems in IMA\n* [`44e2799b8`](https://github.com/siderolabs/talos/commit/44e2799b8cb928083f3a777d5cce45ad8dbf6864) feat: add stdout and single config type support to talosctl gen config\n* [`4452f0e17`](https://github.com/siderolabs/talos/commit/4452f0e179db16c59dc65ccdb5a496ad3306684e) docs: bump talos version\n* [`38e57bd12`](https://github.com/siderolabs/talos/commit/38e57bd12b8c50d668fcde6ee9aa493682778dcc) feat: update Kubernetes to v1.26.0-rc.1\n* [`4cd125d49`](https://github.com/siderolabs/talos/commit/4cd125d499a24798dfde1dddf6fa1c689d16c93f) fix: correctly handle new watch event types\n* [`881b84152`](https://github.com/siderolabs/talos/commit/881b84152084d157fbd4ff992089a5392aadfd3c) feat: update Flannel to 0.20.2\n</p>\n</details>\n\n### Changes since v1.4.0-alpha.3\n<details><summary>21 commits</summary>\n<p>\n\n* [`7ffabe0f1`](https://github.com/siderolabs/talos/commit/7ffabe0f14dd3432857423743701ed5cdb3fe07f) feat: support network bond device selectors\n* [`cbab12e3a`](https://github.com/siderolabs/talos/commit/cbab12e3a1f2c576164bb721dc70073e6b8d3767) refactor: rename outbound to connectivity on dashboard\n* [`07c3c5d59`](https://github.com/siderolabs/talos/commit/07c3c5d59e02d82dbc1ff6f5392c2aa428503e0e) feat: return disk subsystem in the `Disks API`\n* [`b8497b99e`](https://github.com/siderolabs/talos/commit/b8497b99eb46fafd0f908c768d92683771f58cc3) feat: update containerd to 1.6.20\n* [`aa1499353`](https://github.com/siderolabs/talos/commit/aa149935390b0ea49e6b6de51a2eeccd6cbcbbcb) feat: introduce network probes\n* [`9dc1150e3`](https://github.com/siderolabs/talos/commit/9dc1150e3aa08e5cb85c8fb6ecf0cfec5c613029) docs: update nvidia instructions\n* [`7967ccfc1`](https://github.com/siderolabs/talos/commit/7967ccfc13a534cce32bb49558bb4bbeb5ee4480) feat: add config code entry screen to dashboard\n* [`ddb014cfd`](https://github.com/siderolabs/talos/commit/ddb014cfdcb3630055d5b7be7f480080612dfc11) fix: udevd rules trigger\n* [`0af8fe2fb`](https://github.com/siderolabs/talos/commit/0af8fe2fb547e01be1b1231d69ccf2fdc5f2ea0d) feat: netstat pod support\n* [`52e857f55`](https://github.com/siderolabs/talos/commit/52e857f55ef14e88ed5ac6f7fb73a08a5ec8fe7a) feat: linux 6.1.22, runc 1.1.5\n* [`aa662ff63`](https://github.com/siderolabs/talos/commit/aa662ff635f4739343489076bdb9a11722e28798) fix: apply small fixes on dashboard\n* [`188560a33`](https://github.com/siderolabs/talos/commit/188560a334a39f4e6472d196ce33bcfa88e41102) fix: add a link-scope route if the cmdline gateway is not reachable\n* [`45c5b47a5`](https://github.com/siderolabs/talos/commit/45c5b47a57c0c7efdc126f24f880238b9aec9781) feat: dhcpv4: send current hostname, fix spec compliance of renewals\n* [`289b41fe4`](https://github.com/siderolabs/talos/commit/289b41fe4b3af7bd4e1e61a1ca30dc1ed2b0d027) fix: output of `talosctl logs` might be corruped\n* [`02f0a4526`](https://github.com/siderolabs/talos/commit/02f0a4526d09334757a71d868d9e2ae70aa1aade) feat: allow writing initial META values into the image\n* [`ea0e9bdbe`](https://github.com/siderolabs/talos/commit/ea0e9bdbe454041f8895e0a869e28eabb5156430) feat: environment variables via the kernel arguments\n* [`94c24ca64`](https://github.com/siderolabs/talos/commit/94c24ca64e70f227da29cd02bd367d3c2701b96c) chore: add machine config version contract for v1.4\n* [`cefa9c3ec`](https://github.com/siderolabs/talos/commit/cefa9c3ecb5675c80b44a2fe3aaa55e402cab7a6) feat: update Kubernetes to 1.27.0-rc.0\n* [`9e8603f53`](https://github.com/siderolabs/talos/commit/9e8603f53b83e326a2529b2c595b619e04f2b85b) feat: implement new download URL variable `${code}`\n* [`d30cf9c86`](https://github.com/siderolabs/talos/commit/d30cf9c86efc30ce2c61b82be1bfb431cc74dd78) test: fix misprint in e2e scripts\n* [`0d0bb31cf`](https://github.com/siderolabs/talos/commit/0d0bb31cf766ece4c78ffe3f4094f94a9990d88c) fix: use stripped kernel modules\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`ac75538`](https://github.com/siderolabs/discovery-api/commit/ac75538ee3a9f7b71b6619f509d95ff5057f6754) chore: regen the proto definitions with vtprotobuf v0.4.0\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`269a832`](https://github.com/siderolabs/discovery-client/commit/269a832ce9e35d4edeeddba2a23cf5682a2ca425) chore: rekres, update discovery api\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>9 commits</summary>\n<p>\n\n* [`7faf14a`](https://github.com/siderolabs/extras/commit/7faf14a523df4a25073fc463d459d7565b90551d) chore: bump pkgs to v1.4.0\n* [`343956e`](https://github.com/siderolabs/extras/commit/343956eb882eed775c68ef5af3bd37407aa914f4) feat: update Go to 1.20.2\n* [`6209d87`](https://github.com/siderolabs/extras/commit/6209d8774d2ace990f532ab88cf2fa6464c8bafa) chore: bump tc-redirect-tap\n* [`8b28b6b`](https://github.com/siderolabs/extras/commit/8b28b6b5a0153c65af596086016faea9d64e95c2) chore: bump deps\n* [`5ab4f59`](https://github.com/siderolabs/extras/commit/5ab4f5939c830c7043e3939e519305eb810cdfc2) chore: disable renovate builds\n* [`ddeddbd`](https://github.com/siderolabs/extras/commit/ddeddbd1976813de6b1563f662ca4f2b3f5e0f53) chore: update packages, tc_redirect_tap\n* [`8cb4792`](https://github.com/siderolabs/extras/commit/8cb4792da9b9e2b2663daca747d24c3b5c973e0f) chore: update Go to 1.19.5\n* [`3ca2df3`](https://github.com/siderolabs/extras/commit/3ca2df3ead2a64a5ad30c350b87bfe02bf1f49c7) chore: disable provenance in buildx\n* [`55d8452`](https://github.com/siderolabs/extras/commit/55d845241c8456909ab36f9b0f4e26cc2b49c256) feat: update releases\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`214c1ef`](https://github.com/siderolabs/gen/commit/214c1efe795cf426e5ebcc48cb305bfc7a16fdb8) chore: set `slice.Filter` result slice cap to len\n* [`8e89b1e`](https://github.com/siderolabs/gen/commit/8e89b1ede9f35ff4c18a41ee44a69259181c892b) feat: add GetOrCreate and GetOrCall methods\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`b4386f3`](https://github.com/siderolabs/go-blockdevice/commit/b4386f37510bc25e39b231fa587288ad0abf0b68) feat: make disk utils read subsystem information from the `/sys/block`\n* [`8c7ea19`](https://github.com/siderolabs/go-blockdevice/commit/8c7ea1910b27e0660e3e1a6f98b9f7e24bc11ff0) fix: blockdevice size is reported by Linux in 512 blocks always\n</p>\n</details>\n\n### Changes from siderolabs/go-kmsg\n<details><summary>1 commit</summary>\n<p>\n\n* [`7a51094`](https://github.com/siderolabs/go-kmsg/commit/7a51094e29290697aaeed8f09ccb045634876801) fix: exit properly on context cancel\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>4 commits</summary>\n<p>\n\n* [`81887dc`](https://github.com/siderolabs/go-kubernetes/commit/81887dcae8916ccee820af000efe73c151de29a4) feat: add kubelet flag checks\n* [`fe473c0`](https://github.com/siderolabs/go-kubernetes/commit/fe473c0595e8e2e861fc16d0cddb1ba2cedf1ab3) refactor: make sync easier to consume without CLI\n* [`570819b`](https://github.com/siderolabs/go-kubernetes/commit/570819b93ecc63218b3db8d90e4810765a069ee0) feat: initial version of the library\n* [`fb79215`](https://github.com/siderolabs/go-kubernetes/commit/fb7921556e96fc7c0a84ac23834350bcd37cfa38) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`c526764`](https://github.com/siderolabs/go-smbios/commit/c5267640be317efd9cbbe936ab78b2a49c757edf) feat: fix reading \"broken\" Hyper-V DMI data\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>39 commits</summary>\n<p>\n\n* [`aadb943`](https://github.com/siderolabs/pkgs/commit/aadb9439f6eabe1996aec742e086dcb21a0912ab) feat: update containerd to 1.6.20\n* [`5a7b33e`](https://github.com/siderolabs/pkgs/commit/5a7b33e9d025a945caf02363f6a0ca2d8b552ffc) chore: bump deps\n* [`5d77814`](https://github.com/siderolabs/pkgs/commit/5d77814d3789807aed0b6e52acc21f68168ba977) fix: strip kernel modules when installing\n* [`c26b0b5`](https://github.com/siderolabs/pkgs/commit/c26b0b504e5fd0f68432503aabd2653c07888706) chore: bump deps\n* [`7d8f5bd`](https://github.com/siderolabs/pkgs/commit/7d8f5bd7170464c4f017c8e747dd5eda40c35639) feat: enable Hyper-V dynamic memory driver\n* [`ea40205`](https://github.com/siderolabs/pkgs/commit/ea4020599aeb1cd0f78abcfd19c546026bfb0634) chore: bump deps\n* [`21e5a68`](https://github.com/siderolabs/pkgs/commit/21e5a6806288f535773cd8afc20b12ee3082caa8) feat: update Go 1.20.2, Linux 6.1.15 and other\n* [`1d7e60c`](https://github.com/siderolabs/pkgs/commit/1d7e60cc2da55b0a31bd225479c86f517c7a878f) feat: enable framebuffer drivers and console fonts\n* [`0e63e95`](https://github.com/siderolabs/pkgs/commit/0e63e955dd118b6d5e8a9dd443c72a5d35d639a6) chore: bump deps\n* [`5dbce6b`](https://github.com/siderolabs/pkgs/commit/5dbce6b19ff6a1e1b5ae88468e34925c3d30d627) fix: xz url\n* [`0097233`](https://github.com/siderolabs/pkgs/commit/00972336c3fcc22df8fc1d3774c35b26fdc957b9) chore: re-enable drbd\n* [`7493721`](https://github.com/siderolabs/pkgs/commit/749372110c6c8e226139cd662832b5a4169db894) fix: sourcefourge url shasums\n* [`185f482`](https://github.com/siderolabs/pkgs/commit/185f482db6a5c13a3b14feec02a4e361b53bec55) feat: update containerd to 1.6.18\n* [`e3cab6c`](https://github.com/siderolabs/pkgs/commit/e3cab6cbd62b96143958ed5e0219d68107a5f583) chore: bump deps\n* [`18661b0`](https://github.com/siderolabs/pkgs/commit/18661b096559e673152ce0fed45ab74ef3305dff) chore: bump deps\n* [`885a68b`](https://github.com/siderolabs/pkgs/commit/885a68b6280f3bf4ff75508ccceef73158c53560) chore: bump deps\n* [`c3a6e18`](https://github.com/siderolabs/pkgs/commit/c3a6e185178d7571e891c7b2614bf6017ab5c913) chore: bump dependencies\n* [`1fae0b2`](https://github.com/siderolabs/pkgs/commit/1fae0b229a625d692d36e7d6c096f8476e0f56d7) feat: virtio drivers as modules\n* [`61d8ff4`](https://github.com/siderolabs/pkgs/commit/61d8ff4aaea93b86b82bc2a36a2bbd6d54da3bb8) chore: bump deps and disable un-needed kconfig\n* [`15fe6d8`](https://github.com/siderolabs/pkgs/commit/15fe6d8555b42e55f920a5576ad55504e356995b) fix: kernel module tree files missing\n* [`987d24a`](https://github.com/siderolabs/pkgs/commit/987d24aeaa4fb2278954cd96e6bc6a29a4c8dd61) feat: mellanox drivers are modules\n* [`b82a015`](https://github.com/siderolabs/pkgs/commit/b82a015c78c407d17d23542eba6a4114f3c2c4d7) feat: mellanox oped\n* [`057d4f9`](https://github.com/siderolabs/pkgs/commit/057d4f96aa3ba63cc456b06a70a6b3a008cf803f) chore: bump deps\n* [`4ac4138`](https://github.com/siderolabs/pkgs/commit/4ac4138c6b94622646c9f32f0885496c5475d905) feat: enable nvme support for raspberrypi cm4\n* [`ccb9d39`](https://github.com/siderolabs/pkgs/commit/ccb9d39dc43cf53431a0d7609839ed9c7141972d) fix: disable magic sysrq\n* [`d33202d`](https://github.com/siderolabs/pkgs/commit/d33202d99daa6ccf136fca54ebbadda727a43a75) chore: bump u-boot to 2023.01\n* [`cb83e16`](https://github.com/siderolabs/pkgs/commit/cb83e169df4a2020994a63e5be61524461ef93e3) chore: bump dependencies\n* [`e561dcb`](https://github.com/siderolabs/pkgs/commit/e561dcb45beae80161faccedb0303e58d41b1ded) feat: bump Go to 1.19.5\n* [`c7797c7`](https://github.com/siderolabs/pkgs/commit/c7797c77bd311449e1f116980166d8d818102f4f) feat: update Linux to 6.1.4, restore RPi support\n* [`5e8ebb0`](https://github.com/siderolabs/pkgs/commit/5e8ebb073d9b58555a75912cd90490af8a435c7d) feat: add AMD K10 sensor support\n* [`73ac37d`](https://github.com/siderolabs/pkgs/commit/73ac37d683274e60340d2767f2b8201e7f13474c) chore: disable provenance in buildx\n* [`8965bee`](https://github.com/siderolabs/pkgs/commit/8965bee65313539e8b6534073d06341f4fb78586) chore: use default symlinks to `/bin` in `base`\n* [`325c9bf`](https://github.com/siderolabs/pkgs/commit/325c9bf0f3ed2bf7603d1eaea022ea650388cf2b) feat: bump dependencies\n* [`165dff6`](https://github.com/siderolabs/pkgs/commit/165dff6c3cdb2d05f170c8ae0616d9224416455e) fix: patch ipmitool IANA URL\n* [`c542f39`](https://github.com/siderolabs/pkgs/commit/c542f398a150567d5cdffc17b4248be5416fe242) feat: add kernel support for usb setrial console\n* [`f564f45`](https://github.com/siderolabs/pkgs/commit/f564f45645d102b7e3a9563ac7bdb1e816156e65) chore: bump tools, containerd\n* [`268ea7c`](https://github.com/siderolabs/pkgs/commit/268ea7c593ff04c4e4a9ea5676b3c58d41cbff14) chore: bump deps\n* [`dcf3ceb`](https://github.com/siderolabs/pkgs/commit/dcf3cebf283698e010aaac5417d91a7385dc2441) feat: add nitro enclave support in kernel\n* [`17ea5e6`](https://github.com/siderolabs/pkgs/commit/17ea5e680b2438c59fa1773e8b58d6b749cb0d34) chore: bump kernel to 5.15.81\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>31 commits</summary>\n<p>\n\n* [`95f814a`](https://github.com/siderolabs/tools/commit/95f814ab50a28d9418b5c5f1c20ca8eb6e3590de) feat: cmake 3.26.2\n* [`a3d5bac`](https://github.com/siderolabs/tools/commit/a3d5bac13858653922ecb0fe57056f20ad9a47b9) chore: bump deps\n* [`2d710f9`](https://github.com/siderolabs/tools/commit/2d710f9074caefcbd1cd37190dda02372e851500) chore: bump deps\n* [`9bea7d0`](https://github.com/siderolabs/tools/commit/9bea7d04310bfb1177e55a9e4fe1606b81ad8dbd) chore: skip rc versions for util-linux\n* [`a94850e`](https://github.com/siderolabs/tools/commit/a94850e6dd52a2b2d08c3e4e1fe95adddcb68f20) chore: bump deps\n* [`e6b2956`](https://github.com/siderolabs/tools/commit/e6b29564537a54549165ea99fceff160d21634dd) fix: protoc install\n* [`601e347`](https://github.com/siderolabs/tools/commit/601e3475b6bb9249bcf4e2bee16791ea4f91e8f9) feat: go 1.20.2 + other bumps\n* [`ca67d0b`](https://github.com/siderolabs/tools/commit/ca67d0ba6ccb45f30da328fd210cbe92782c2151) chore: bump deps\n* [`662a906`](https://github.com/siderolabs/tools/commit/662a90650841ab6c8ffd74e4abc51654b713dd4e) feat: add libnl\n* [`a8440a9`](https://github.com/siderolabs/tools/commit/a8440a9c866d9837d358b53a869bcb43774f4e78) fix: partially revert e6c98fdf54425e6382f226e33bccca6f3875aad3a\n* [`e6c98fd`](https://github.com/siderolabs/tools/commit/e6c98fdf54425e6382f226e33bccca6f3875aad3) chore: remove swig\n* [`cd9687b`](https://github.com/siderolabs/tools/commit/cd9687b4323b20493b4d582cfaa48c321cd04288) fix: renovate config\n* [`977e3fc`](https://github.com/siderolabs/tools/commit/977e3fcba92d129eb78cb77300f38428f860b34d) chore: bump go to 1.20.1\n* [`15748aa`](https://github.com/siderolabs/tools/commit/15748aa32d7c1d67b190ab7a27ace9922c8d6b56) chore: bump deps\n* [`d4b719a`](https://github.com/siderolabs/tools/commit/d4b719a1c2055eaa27f80422f93755b0de9ca3f8) chore: bump deps\n* [`8c36dbd`](https://github.com/siderolabs/tools/commit/8c36dbd05ee27ecc2a7340462a3b49efb7327184) chore: bump toolchain, bump protoc-gen-go-grpc\n* [`a62e365`](https://github.com/siderolabs/tools/commit/a62e365b223e7ca9d2728865b40b23115764a0ed) feat: update Go to 1.20\n* [`28d4a57`](https://github.com/siderolabs/tools/commit/28d4a5721ce1c57fc3f643185386d5c4b5c7e39a) chore: reduce renovate noise\n* [`e130fd5`](https://github.com/siderolabs/tools/commit/e130fd5b9835d8cc178ec53d5a89dfc6cc2ce7a1) chore: bump deps\n* [`37612fe`](https://github.com/siderolabs/tools/commit/37612feb7222b943a84f1f98d0901a204d491926) fix: revert enabling provenance\n* [`e0b01e3`](https://github.com/siderolabs/tools/commit/e0b01e3b7420e8b0b1e0d9077515e007a6b83b56) chore: bump deps\n* [`d0e6bd0`](https://github.com/siderolabs/tools/commit/d0e6bd06fcfcadc330cf30339488536961f9f70e) feat: add gnutls\n* [`3d34b5d`](https://github.com/siderolabs/tools/commit/3d34b5d401a67048d365e8faf2f1edf293887a97) chore: bump dependencies\n* [`763c1d9`](https://github.com/siderolabs/tools/commit/763c1d927822517b3d63c624302e11e8e5a49f5b) feat: update Go to 1.19.5\n* [`136958f`](https://github.com/siderolabs/tools/commit/136958f9f8c8cfc439228dec31b840549bca4374) chore: disable provenance in buildx\n* [`e2a8692`](https://github.com/siderolabs/tools/commit/e2a869294be7e77e295ca651400f85551fb7e665) feat: update releases\n* [`0e48f37`](https://github.com/siderolabs/tools/commit/0e48f37496a79ce4997d15fefb6300b2324f5668) chore: bump protobuf\n* [`a21aa1c`](https://github.com/siderolabs/tools/commit/a21aa1c583a10d017ace8da14c6f604f86ce5709) chore: bump toolchain and mpc versions\n* [`1a75d0f`](https://github.com/siderolabs/tools/commit/1a75d0f6796c4abf1c9a23cfe697d3e38a9ce587) chore: bump deps\n* [`55bd185`](https://github.com/siderolabs/tools/commit/55bd18532667e325e8938bf0a72cab40a936eadf) feat: update Go to 1.19.4\n* [`f291f46`](https://github.com/siderolabs/tools/commit/f291f46e84ec02f5d22718f7ecb476a3f815ae45) chore: bump tools\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**           v0.2.1 -> v0.2.3\n* **github.com/aws/aws-sdk-go**                      v1.44.147 -> v1.44.232\n* **github.com/benbjohnson/clock**                   v1.1.0 **_new_**\n* **github.com/containerd/cgroups**                  v1.0.4 -> v1.1.0\n* **github.com/containerd/containerd**               v1.6.12 -> v1.6.19\n* **github.com/containernetworking/plugins**         v1.1.1 -> v1.2.0\n* **github.com/coreos/go-semver**                    v0.3.0 -> v0.3.1\n* **github.com/cosi-project/runtime**                v0.2.0 -> v0.3.0\n* **github.com/docker/docker**                       v20.10.21 -> v23.0.2\n* **github.com/dustin/go-humanize**                  v1.0.0 -> v1.0.1\n* **github.com/emicklei/dot**                        v1.2.0 -> v1.4.2\n* **github.com/fatih/color**                         v1.13.0 -> v1.15.0\n* **github.com/freddierice/go-losetup/v2**           v2.0.1 **_new_**\n* **github.com/gdamore/tcell/v2**                    v2.5.3 -> v2.6.0\n* **github.com/grpc-ecosystem/go-grpc-middleware**   v1.3.0 -> v1.4.0\n* **github.com/hashicorp/go-getter**                 v1.6.2 -> v1.7.1\n* **github.com/hetznercloud/hcloud-go**              v1.37.0 -> v1.41.0\n* **github.com/insomniacslk/dhcp**                   f26e6d78f622 -> 74ae03f2425e\n* **github.com/jsimonetti/rtnetlink**                v1.3.0 -> v1.3.1\n* **github.com/mattn/go-isatty**                     v0.0.16 -> v0.0.18\n* **github.com/mdlayher/ethtool**                    0e16326d06d1 -> ba3b4bc2e02c\n* **github.com/mdlayher/genetlink**                  v1.3.0 -> v1.3.1\n* **github.com/mdlayher/netlink**                    v1.7.0 -> v1.7.1\n* **github.com/nberlee/go-netstat**                  v0.1.1 **_new_**\n* **github.com/prometheus/procfs**                   v0.8.0 -> v0.9.0\n* **github.com/rivo/tview**                          db36428c92d9 -> 281d14d896d7\n* **github.com/safchain/ethtool**                    v0.2.0 -> v0.3.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.10 -> v1.0.0-beta.15\n* **github.com/siderolabs/discovery-api**            v0.1.1 -> v0.1.2\n* **github.com/siderolabs/discovery-client**         v0.1.3 -> v0.1.4\n* **github.com/siderolabs/extras**                   v1.3.0-1-g3773d71 -> v1.4.0\n* **github.com/siderolabs/gen**                      v0.4.1 -> v0.4.3\n* **github.com/siderolabs/go-blockdevice**           v0.4.2 -> v0.4.4\n* **github.com/siderolabs/go-kmsg**                  v0.1.2 -> v0.1.3\n* **github.com/siderolabs/go-kubernetes**            v0.2.0 **_new_**\n* **github.com/siderolabs/go-smbios**                v0.3.1 -> v0.3.2\n* **github.com/siderolabs/pkgs**                     v1.3.0-5-g6509d23 -> v1.4.0-1-gaadb943\n* **github.com/siderolabs/talos/pkg/machinery**      v1.3.0 -> v1.4.0-alpha.3\n* **github.com/siderolabs/tools**                    v1.3.0-1-g712379c -> v1.4.0\n* **github.com/stretchr/testify**                    v1.8.1 -> v1.8.2\n* **github.com/u-root/u-root**                       v0.10.0 -> v0.11.0\n* **github.com/ulikunitz/xz**                        v0.5.11 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.12 -> v0.56.16\n* **github.com/vmware/govmomi**                      v0.29.0 -> v0.30.4\n* **go.etcd.io/etcd/api/v3**                         v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/v3**                      v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.6 -> v3.5.7\n* **go.uber.org/zap**                                v1.23.0 -> v1.24.0\n* **go4.org/netipx**                                 797b0c90d8ab -> f1b76eb4bb35\n* **golang.org/x/net**                               v0.4.0 -> v0.8.0\n* **golang.org/x/sys**                               v0.3.0 -> v0.6.0\n* **golang.org/x/term**                              v0.3.0 -> v0.6.0\n* **golang.org/x/time**                              v0.2.0 -> v0.3.0\n* **golang.zx2c4.com/wireguard/wgctrl**              97bc4ad4a1cb -> 9c5414ab4bde\n* **google.golang.org/grpc**                         v1.51.0 -> v1.54.0\n* **google.golang.org/protobuf**                     v1.28.1 -> v1.30.0\n* **k8s.io/api**                                     v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/apimachinery**                            v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/apiserver**                               v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/client-go**                               v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/component-base**                          v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/cri-api**                                 v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/klog/v2**                                 v2.80.1 -> v2.90.1\n* **k8s.io/kubectl**                                 v0.26.0 -> v0.27.0-rc.0\n* **k8s.io/kubelet**                                 v0.26.0 -> v0.27.0-rc.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.66 -> v1.2.68\n\nPrevious release can be found at [v1.3.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0)\n\n\n\n\n## [Talos 1.4.0-alpha.3](https://github.com/siderolabs/talos/releases/tag/v1.4.0-alpha.3) (2023-03-23)\n\nWelcome to the v1.4.0-alpha.3 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### talosctl containers\n\n`talosctl logs -k` and `talosctl containers -k` now support and output container display names with their ids.\nThis allows to distinguish between containers with the same name.\n\n\n### Registry Mirror Catch-All Option\n\nTalos now supports a catch-all option for registry mirrors:\n\n```yaml\nmachine:\n    registries:\n        mirrors:\n            docker.io:\n                - https://registry-1.docker.io/\n            \"*\":\n                - https://my-registry.example.com/\n```\n\n\n### Talos Dashboard on TTY2\n\nTalos now starts a text-based UI dashboard on virtual console `/dev/tty2` and switches to it by default upon boot.\nKernel logs remain available on `/dev/tty1`.\n\nTo switch TTYs, use the `Alt+F1` through `Alt+F2` keys.\n\nYou can disable this behavior by setting the kernel parameter `talos.dashboard.disabled=1`.\n\nThis behavior is disabled by default on SBCs.\n\n\n### etcd Maintenance\n\nTalos adds new APIs to make it easier to perform etcd maintenance operations.\n\nThese APIs are available via new `talosctl etcd` sub-commands:\n\n* `talosctl etcd alarm list|disarm`\n* `talosctl etcd defrag`\n* `talosctl etcd status`\n\nSee also [etcd maintenance guide](https://talos.dev/v1.4/advanced/etcd-maintenance/).\n\n\n### Kernel Modules\n\nTalos now supports automatically loading kernel drivers built as modules.\nIf any system extensions or the Talos base kernel build provides kernel modules and if they matches the system hardware (via PCI IDs), they will be loaded automatically.\nModules can still be loaded explicitly by defining it in [machine configuration](https://www.talos.dev/v1.4/reference/configuration/#kernelconfig).\n\n\n### Kernel Modules Tree\n\nTalos now supports re-building the kernel modules dependency tree information on upgrades.\nThis allows modules of same name to co-exist as in-tree and external modules.\nSystem Extensions can provide modules installed into `extras` directory and when loading it'll take precendence over the in-tree module.\n\n\n### Kernel Reset Argument\n\nTalos now supports `talos.experimental.wipe=system:EPHEMERAL,STATE` kernel argument.\nTalos now also supports the new GRUB boot option - \"Reset Talos installation and return to maintenance mode\".\nBoth of this options will reset EPHEMERAL and STATE partitions and will return Talos into maintenance mode after the reboot.\n\n\n### Machine Configuration\n\nStrategic merge config patches correctly support merging `.vlans` sections of the network interface.\n\n\n### talosctl netstat\n\nTalos API was extended to support retrieving a list of network connections (sockets) from the node.\n`talosctl netstat` command was added to retrieve the list of network connections.\n\n\n### Reset API Enhancements\n\nTalos now supports resetting user disks through the Reset API,\nthe list of disks to wipe is set using the `--user-disks-to-wipe` parameter in `talosctl`.\nAdditionally, the Reset API can now function in maintenance mode\nand has the capability to wipe the node's system disk (partial wipe is not supported).\n\n\n### New Talos API os:operator role\n\nTalos now supports a new `os:operator` role for the Talos API.\nThis role allows everything `os:reader` role allows plus access to maintenance APIs:\nrebooting, shutting down a node, accessing packet capture, etcd alarm APIs, etcd backup, etc.\n\n\n### Component Updates\n\n* Linux: 6.1.20\n* containerd: v1.6.19\n* Kubernetes: v1.27.0-beta.0\n* etcd: v3.5.7\n* CoreDNS: v1.10.1\n* Flannel: v0.21.4\n\nTalos is built with Go 1.20.2.\n\n\n### VMware Platform\n\nTalos now supports loading network configuration on VMWare platform from the `metadata` key.\nSee [CAPV IPAM Support](https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/main/docs/proposal/20220929-ipam-support.md) and\n[Talos issue 6708](https://github.com/siderolabs/talos/issues/6708) for details.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Spencer Smith\n* Serge Logvinov\n* Artem Chernyshev\n* Steve Francis\n* Tim Jones\n* Nico Berlee\n* Seán C McCord\n* Steffen Windoffer\n* Andrey Smirnov\n* Cees-Jan Kiewiet\n* Chris van de Sande\n* Dzerom Dzenkins\n* Erik Lund\n* Jori Huisman\n* Lance R. Vick\n* Matthias Riegler\n* Michael Vorburger\n* Murtaza Udaipurwala\n* Niklas Wik\n* Rowan Smith\n* Samuel Kees\n* Sander Maijers\n* Tim van Druenen\n* Victor Seva\n* budimanjojo\n* xyhhx\n\n### Changes\n<details><summary>178 commits</summary>\n<p>\n\n* [`a7b79ef1b`](https://github.com/siderolabs/talos/commit/a7b79ef1be79ca7e0ea1530d469c3790f43e6c6b) feat: add network config screen to dashboard\n* [`cf2ccc521`](https://github.com/siderolabs/talos/commit/cf2ccc521f6a15b8b82bf5fbaab572f481f8edf7) fix: always shutdown maintenance API service\n* [`a0a5db590`](https://github.com/siderolabs/talos/commit/a0a5db590d9b5f312f9e59bec4ddc7379183c705) feat: update Flannel to 0.21.4\n* [`d1a61fd34`](https://github.com/siderolabs/talos/commit/d1a61fd34343e58192864b1464759b78eb57e917) chore: bump golangci-lint\n* [`36a9a208e`](https://github.com/siderolabs/talos/commit/36a9a208ecf01114f5cc47449bb69099fca99e83) chore: bump deps\n* [`c63cf90e3`](https://github.com/siderolabs/talos/commit/c63cf90e32ce61e788a00ed79a5ff662d3d25e50) feat: update k8s to v1.27.0-beta.0\n* [`b246c90ab`](https://github.com/siderolabs/talos/commit/b246c90abdec14c305dbad8af82147ebe44328ce) fix: add uint32 to Magic1 and Magic2\n* [`777c8d6f6`](https://github.com/siderolabs/talos/commit/777c8d6f6ecb438d11ac829a297bf2c6b5660479) chore: update COSI to watch aggregated version\n* [`bec89bf6e`](https://github.com/siderolabs/talos/commit/bec89bf6e575923f348a4885841de27eead020df) fix: use 'no block' etcd dial with multiple endpoints\n* [`28713c2c4`](https://github.com/siderolabs/talos/commit/28713c2c4d4d20d5ff455c40cbb8aa004d725801) feat: update Kubernetes to 1.26.3\n* [`a3cf41647`](https://github.com/siderolabs/talos/commit/a3cf4164755609e80de5dafa2c49bfaa0fc655fd) docs: add InstallConfig ignored notice to doc\n* [`df9b851fb`](https://github.com/siderolabs/talos/commit/df9b851fbadaa7c652f343c2facc2bd0a9dd22ca) chore: load all external artifacts earlier\n* [`2dd0964c5`](https://github.com/siderolabs/talos/commit/2dd0964c5f617a7072af08bd45c35d57bc47e838) refactor: use resource watches on dashboard\n* [`9933ebb6a`](https://github.com/siderolabs/talos/commit/9933ebb6aa86249d2118ef5fb50bf23cedadb0a5) chore: fix loaded artifacts file permission\n* [`a14a0aba0`](https://github.com/siderolabs/talos/commit/a14a0aba04a2daf277bf2703575def39b7f2e5e9) fix: nil pointer exception in syncLink\n* [`cf101e56f`](https://github.com/siderolabs/talos/commit/cf101e56fbf18bb401bebb95e9fe005f65765d3d) fix: add `--force` flag for `talosctl gen`\n* [`ea2aa0611`](https://github.com/siderolabs/talos/commit/ea2aa06116a1b3c58d40ad42787749783516ef6c) fix: fix data race on network config read\n* [`64e3d24c6`](https://github.com/siderolabs/talos/commit/64e3d24c6bfe60b5556c41822c8e81f63d0a06d2) feat: provide platform network config for 'metal' in META\n* [`442cb9c1b`](https://github.com/siderolabs/talos/commit/442cb9c1b0757a9c8204cc92baab11f664cbcb19) feat: implement APIs to write to META\n* [`9e07832db`](https://github.com/siderolabs/talos/commit/9e07832db9e19e602332821769f479b881fae178) feat: implement summary dashboard\n* [`1df841bb5`](https://github.com/siderolabs/talos/commit/1df841bb542323adce92013cd55eb24ab238a1dc) refactor: change the interface of META\n* [`e9962bc3e`](https://github.com/siderolabs/talos/commit/e9962bc3eaa31b9a782c2fcd0c7857a86cba0c28) chore: update CI to tag azure buckets\n* [`9f5f5cf9b`](https://github.com/siderolabs/talos/commit/9f5f5cf9bf83e9cff0be7720d6bffc13fec97570) feat: update Flannel to v0.21.3\n* [`02b0ff35e`](https://github.com/siderolabs/talos/commit/02b0ff35ee2273e59899ac4a999fa101d895aec0) feat: generate Flannel CNI manifest from upstream\n* [`6656d35ec`](https://github.com/siderolabs/talos/commit/6656d35eca5ec78cd52e7a6478369200ce16b176) docs: fix Talos version to use template\n* [`72a6d1d70`](https://github.com/siderolabs/talos/commit/72a6d1d70813986f6e9f4b7fc92e594f6ff7da1f) docs: update nocloud\n* [`9948a646d`](https://github.com/siderolabs/talos/commit/9948a646d20f4ba80916a263ed7bca3e5ca2f0ad) feat: coredns node uninitialized toleration\n* [`e03902b54`](https://github.com/siderolabs/talos/commit/e03902b546b379c19ea80081bbfaef666d03812d) feat: update Go to 1.20.2\n* [`c8f8579f2`](https://github.com/siderolabs/talos/commit/c8f8579f2dcf485e66922679d37e56742b65cc53) fix: upgrade-k8s to flag should not be required since there is a default\n* [`230cfaf80`](https://github.com/siderolabs/talos/commit/230cfaf80312518222469939e969880040c379f2) feat: use network information from guestinfo.metadata\n* [`97048f7c3`](https://github.com/siderolabs/talos/commit/97048f7c37ed7b7aceadf6f2e40f007a09c57730) feat: netstat in API and client\n* [`fda6da692`](https://github.com/siderolabs/talos/commit/fda6da692956d863d320f25cd50833da2f93104c) fix: successful ACPI shutdown in maintenance mode\n* [`b97e1abaa`](https://github.com/siderolabs/talos/commit/b97e1abaa6a1543bc7b6e8fa7e4fa9e0cb5d8e14) feat: set default image, validate empty image\n* [`121220a3b`](https://github.com/siderolabs/talos/commit/121220a3b3202de9bd08dce391740c9a66ad9cf2) chore: bump dependencies via renovate bot\n* [`ebc92f3c1`](https://github.com/siderolabs/talos/commit/ebc92f3c1de97a8b11046268854e957be0b64f81) chore: add container id to `talosctl -k containers` and `talosctl -k logs`\n* [`22ef81c1e`](https://github.com/siderolabs/talos/commit/22ef81c1e78963a8f46e2f54d00cd111742dd95c) feat: add grub option to drop to maintenance mode\n* [`642fe0c90`](https://github.com/siderolabs/talos/commit/642fe0c90c4714aeb5f880946c1d337c53bc6fa4) feat: update pkgs with framebuffer console\n* [`69cb414f0`](https://github.com/siderolabs/talos/commit/69cb414f01d3193931e838f89e21b0c9ac26bf61) docs: update cilium install instructions\n* [`e71cc6619`](https://github.com/siderolabs/talos/commit/e71cc6619b2cdc34efe8dccca3cc296befef43f9) fix: redo assertHostnames in HostnameMergeSuite.TestMerge\n* [`8ea4bfad8`](https://github.com/siderolabs/talos/commit/8ea4bfad8feae5f4806be0ea4f6fdd1b79a8197a) refactor: improve the kubernetes upgrade flow\n* [`81879fc0c`](https://github.com/siderolabs/talos/commit/81879fc0ca98cc3e5df619bd071c279a735697e3) docs: add how tos for workloads on control planes, and scaling up\n* [`05b0b721c`](https://github.com/siderolabs/talos/commit/05b0b721c9d2acd211519d554d1c23926472a5b4) chore: move blob storage to azure for builds\n* [`a78281214`](https://github.com/siderolabs/talos/commit/a78281214d349c147498e3b000a9e9aeecb29eb6) feat: add cilium e2e tests\n* [`061640ccc`](https://github.com/siderolabs/talos/commit/061640cccf69d065806140e670e484c8b1c5a26e) feat: add pod ip to kube-proxy spec\n* [`dea17d723`](https://github.com/siderolabs/talos/commit/dea17d72340b1deddea2215b556a4f193d1feb7f) feat: update Kubernetes to v1.26.2\n* [`337aaba7a`](https://github.com/siderolabs/talos/commit/337aaba7a705536b885d7336343b828dd13e1de4) feat: add 'os:operator' role\n* [`40e69af22`](https://github.com/siderolabs/talos/commit/40e69af2242fcd91f4a351da02de1b94158d419c) fix: improve etcd leave on reset process\n* [`638dc9128`](https://github.com/siderolabs/talos/commit/638dc9128fd89f70ddab8d6f342ca5a2e5131be8) fix: fix \"defer\" leak in ResetUserDisks\n* [`bfba3677b`](https://github.com/siderolabs/talos/commit/bfba3677b0e85a27a8b92235f5763ac6fc8e0375) chore: handle grub option - \"wipe\"\n* [`594f27d87`](https://github.com/siderolabs/talos/commit/594f27d87870ef26fc7166a95a64a40d27cb165a) release(v1.4.0-alpha.2): prepare release\n* [`b52071081`](https://github.com/siderolabs/talos/commit/b5207108104eda426361c256ec4d78ae9e0b2890) feat: introduce new flag in reset API that makes Talos reset user disks\n* [`f55f5df73`](https://github.com/siderolabs/talos/commit/f55f5df7396b7073e75267c7e10a35814f1185c9) feat: move dashboard package & run it in tty2\n* [`36e077ead`](https://github.com/siderolabs/talos/commit/36e077ead458f15e864f62eeb0d7afa59187c226) chore: bump deps\n* [`5a01d5fd4`](https://github.com/siderolabs/talos/commit/5a01d5fd473cdc4e0b9fba48047d6434cf31ee42) chore: run extension build as downstream\n* [`426fe9687`](https://github.com/siderolabs/talos/commit/426fe9687d74690df26ce3cfd6aee47c13e994a8) fix: extension base folder permission\n* [`609d3a8a6`](https://github.com/siderolabs/talos/commit/609d3a8a694ff90426ce33be86791f2616ec4852) feat: support strategic merge patches on VLAN configuration\n* [`7e19f32d7`](https://github.com/siderolabs/talos/commit/7e19f32d762dc1363f29e988ddbe334bd00610f2) chore: provide version compatibility data for Talos 1.2.x\n* [`230e46e56`](https://github.com/siderolabs/talos/commit/230e46e567012d8e12e384c777d6f57db5e7cfee) refactor: extract parts of kubernetes libraries\n* [`f3d3f0f26`](https://github.com/siderolabs/talos/commit/f3d3f0f2625f1be41a17366ee1c0bd2a3193c08c) fix: update go-smbios library with Hyper-V data fix\n* [`8711eea96`](https://github.com/siderolabs/talos/commit/8711eea9626a60a996347aaa7e6a89eea87d4b9e) fix: use passed `--context` in `talosctl config` cmd\n* [`5ac9f43e4`](https://github.com/siderolabs/talos/commit/5ac9f43e45f85f8d37c2855051b9a5cc9ad389ac) feat: start machined earlier & in maintenance mode\n* [`36ab414a1`](https://github.com/siderolabs/talos/commit/36ab414a1d7c5472522d20a7b698c4eebb3423b9) docs: fix the endpoints in the libvirt guide\n* [`3d55bd80f`](https://github.com/siderolabs/talos/commit/3d55bd80f42b7d2439541909c9534c386607e578) fix: add `--force` flag to `talosctl gen config`\n* [`660b8874d`](https://github.com/siderolabs/talos/commit/660b8874da7bd91946aab5f400e7d1dfddefb827) feat: cmdline integer netmask\n* [`1e3daacc4`](https://github.com/siderolabs/talos/commit/1e3daacc48c0b8ef2eab41b2c2c53f55522e1acf) docs: update nvidia component versions\n* [`b5c03a7fa`](https://github.com/siderolabs/talos/commit/b5c03a7fab8d213e7048a8f5fc129125b81eb205) fix: docker talosctl cluster create provisioner\n* [`6e8f13529`](https://github.com/siderolabs/talos/commit/6e8f13529c17ff4c658b340d16d9ee429cfd9a4c) fix: add support for a fallback '*' mirror configuration\n* [`dcd4eb1a9`](https://github.com/siderolabs/talos/commit/dcd4eb1a93737d60f60693d8c33a20052eee4a4f) fix: improve error message on single node upgrade\n* [`ed5af3f78`](https://github.com/siderolabs/talos/commit/ed5af3f780732fb0004ddb263feedbf2de9fd09a) chore: bump deps\n* [`0dc6858e5`](https://github.com/siderolabs/talos/commit/0dc6858e5ba4b110eac9ca74294eb3a29790a323) chore: bump cosi-project/runtime\n* [`da2edb9de`](https://github.com/siderolabs/talos/commit/da2edb9de067fc21c792e948903bc2c880b2c2d1) chore: bump dependencies\n* [`e51a110f0`](https://github.com/siderolabs/talos/commit/e51a110f0e876fc091aee0828aca0135499def9c) chore: bump dependencies\n* [`2d0148018`](https://github.com/siderolabs/talos/commit/2d014801803fa0d5f08a344bdc9ff078b3931633) feat: automatically load modules based on hw info\n* [`7b75cd8b9`](https://github.com/siderolabs/talos/commit/7b75cd8b94367645adb2dd5be016e6f98d8e6a89) fix: kernel module dependency tree generation\n* [`65d02e5ad`](https://github.com/siderolabs/talos/commit/65d02e5ade08354aeec794d4131a1f8913fba2b5) fix: dbus shutdown when it's not initialized\n* [`a7079ce85`](https://github.com/siderolabs/talos/commit/a7079ce85c9839933544b637100f104f02fd3f3a) fix: quote the ampersand character in GRUB config\n* [`933ba2d82`](https://github.com/siderolabs/talos/commit/933ba2d8203e4418414b3de1c4240c1f88cb033e) fix: display correct blockdevice size\n* [`c449cb736`](https://github.com/siderolabs/talos/commit/c449cb736b24b268b965da5e2932f18bd4fb7785) fix: talosctl reboot command passing mode in wait mode\n* [`34ab0007a`](https://github.com/siderolabs/talos/commit/34ab0007a61bbb685d8c194c06568974db2a7375) docs: port is needed for wireguard endpoint\n* [`1e1aa84f6`](https://github.com/siderolabs/talos/commit/1e1aa84f6cdd0fbe6dd35841b6195cc56f10d333) fix: kubernetes removed resource version check\n* [`dcbcf5a93`](https://github.com/siderolabs/talos/commit/dcbcf5a93c3d82f8fdd7b8ffef3819010bd1c481) fix: wait for network and retry in platform get config funcs\n* [`3d7566ec7`](https://github.com/siderolabs/talos/commit/3d7566ec743f573a43a4a49ecb80f6ba59cbb27b) test: update Canal CNI manifest URL\n* [`e09e10666`](https://github.com/siderolabs/talos/commit/e09e106665aa8716f14ba49d527d8cb182592da7) fix: default dns domain to 'cluster.local' in local case\n* [`cc6e37a47`](https://github.com/siderolabs/talos/commit/cc6e37a47fd2ca9f1e43ce8ba2c1e8d8bfe44776) feat: use process wrapper for dropping capabilities\n* [`0c6c88874`](https://github.com/siderolabs/talos/commit/0c6c888745c5482fcf3891c922cc7cc7f72e6af4) fix: trackable action flag usage text. --no-wait does not exist\n* [`5cb2915d8`](https://github.com/siderolabs/talos/commit/5cb2915d8ea6e4ba913396abe3f45235e6a67213) feat: use wrapper for starting processes\n* [`56d945326`](https://github.com/siderolabs/talos/commit/56d9453261d47c0739be21cb7a5fe6beb25cb92c) fix: panic in talosctl cluster show\n* [`38a51191e`](https://github.com/siderolabs/talos/commit/38a51191e49059e93f4adfea479c039819a7f730) fix: correctly expand parameters in the URL\n* [`af21860a2`](https://github.com/siderolabs/talos/commit/af21860a22598361f68cf49e62a12da54bc95337) fix: return proper error if download attempts time out\n* [`54f7d4c92`](https://github.com/siderolabs/talos/commit/54f7d4c9231e858216f3b69b2662d7cc188df4f9) fix: correctly quote and unquote strings in GRUB config\n* [`54cf0672a`](https://github.com/siderolabs/talos/commit/54cf0672a71a8c9427c66bb2601521a9d24f8e13) fix: omit zero MTU in the machine config\n* [`bdc53ac25`](https://github.com/siderolabs/talos/commit/bdc53ac254a4aaa37ffd917c7c3ad506368205de) docs: add hyperlink to Docker API docs about `config.json`\n* [`b3bc06dd1`](https://github.com/siderolabs/talos/commit/b3bc06dd14c7faa75269cb6686b2d93ce765595c) chore: bump vtprotobuf to v0.4.0\n* [`0ba5e59f6`](https://github.com/siderolabs/talos/commit/0ba5e59f69c08ab566177df9e26a21648bcde54f) fix: drone config for renovate PR's\n* [`590a393de`](https://github.com/siderolabs/talos/commit/590a393de968556bb5e19594b2f057d4233c378d) fix: udevd healthcheck\n* [`2b6b6deac`](https://github.com/siderolabs/talos/commit/2b6b6deacda4a3cdf6c5b65ac586cad1363be094) docs: simplify and clarify digital ocean docs\n* [`92bc15f7f`](https://github.com/siderolabs/talos/commit/92bc15f7f1c561b1e7810371df23f84c7e0d6a1c) release(v1.4.0-alpha.1): prepare release\n* [`e3da4754e`](https://github.com/siderolabs/talos/commit/e3da4754e7a2e69b998b861034c6f77e2cf6355b) feat: update Linux to 6.1.7\n* [`006449e46`](https://github.com/siderolabs/talos/commit/006449e464ac009e15d78bb4d71cee80f2540f31) test: build integration test early in the pipeline\n* [`09aa71264`](https://github.com/siderolabs/talos/commit/09aa7126422b9b41e74c3d2aacb563daeca33bc5) fix: renovate config\n* [`2d136f187`](https://github.com/siderolabs/talos/commit/2d136f1879ee66dbd61ab40bb001a45c0bafaad5) feat: set markdown and html descriptions in config json schema\n* [`f0804027a`](https://github.com/siderolabs/talos/commit/f0804027a499a6e195f049144bff4f939dee3780) fix: renovate config\n* [`812a2877c`](https://github.com/siderolabs/talos/commit/812a2877cdc1e631ae0244f9696a65e2347594c0) chore: bump deps + renovate cleanup\n* [`aa9f66c1c`](https://github.com/siderolabs/talos/commit/aa9f66c1c88a1bb35aefe24ea0a5c3a6e7aa966d) fix: mark DigitalOcean anchor IP as scope link\n* [`bb4937f1b`](https://github.com/siderolabs/talos/commit/bb4937f1b339384fb486cb0cb675df8bf9b9f916) feat: enable renovate\n* [`3e0057162`](https://github.com/siderolabs/talos/commit/3e00571627568d8c5ab10a72e59207677a89e4cc) fix: unwrap gRPC errors on stop/remove pods check\n* [`00e52ae07`](https://github.com/siderolabs/talos/commit/00e52ae07867deff9a5877fcb498252bc1b1a740) fix: build correctly etcd initial cluster URL\n* [`ae83b10ae`](https://github.com/siderolabs/talos/commit/ae83b10ae89dbe600ddfaa338be95ea819546007) feat: create JSON schema for v1alpha1.Config\n* [`703d96595`](https://github.com/siderolabs/talos/commit/703d9659512d744a606e520faf230e20efddfc4a) feat: update Kubernetes to 1.26.1, etcd to 3.5.7\n* [`965e64591`](https://github.com/siderolabs/talos/commit/965e645915d080487a74b35dc8f1d2e4051f0504) docs: update to use talosctl install script\n* [`c5954f434`](https://github.com/siderolabs/talos/commit/c5954f4345cbf3a92c777a0e7fc5d39e883609bf) chore: bump deps\n* [`bb50f6a56`](https://github.com/siderolabs/talos/commit/bb50f6a56d971915abb6a895aac9d7e0612a3255) chore: preallocate disk images for QEMU VMs\n* [`d4b8b35de`](https://github.com/siderolabs/talos/commit/d4b8b35de7849d887c41f9a13dadb59ccd8c08c4) feat: generate kernel module dependency tree\n* [`18122ae73`](https://github.com/siderolabs/talos/commit/18122ae73e0489a0497956c6d4621c05c6a77387) fix: service restart (including extension services)\n* [`680fd5e45`](https://github.com/siderolabs/talos/commit/680fd5e452e02b108b7938d0136079c16e6cfd79) fix: bump COSI runtime with the panic controller restart fix\n* [`0b65bbfc8`](https://github.com/siderolabs/talos/commit/0b65bbfc878fe2a5c01c5d2cd08006b53fda7cf9) fix: handle overwriting tags in syslinux ADV\n* [`70d9428a1`](https://github.com/siderolabs/talos/commit/70d9428a1d00d9894d68f38b255debb66fe8a440) fix: kubespan MSS clamping\n* [`683b4ccb4`](https://github.com/siderolabs/talos/commit/683b4ccb4faab6c3da2de00f7314773f42899c25) chore: update Go to 1.19.5 and kernel to 6.1.4\n* [`062c7d754`](https://github.com/siderolabs/talos/commit/062c7d754be1714c7763b8f2b399436d64c90ea4) test: fix integration test on cp endpoint update\n* [`8e9fc13d7`](https://github.com/siderolabs/talos/commit/8e9fc13d7c48da5c5354501e0ad96688670438cf) feat: implement enum generator for proto files\n* [`771b0dc06`](https://github.com/siderolabs/talos/commit/771b0dc061e0fa33085b28bd0d0a7e4da13081f1) docs: update left over rpi_4 ref to rpi_generic\n* [`6c04b5f79`](https://github.com/siderolabs/talos/commit/6c04b5f79e6e01e0a3cdabfc99f12c944edd1f0a) chore: bump dependencies\n* [`0a5a8802e`](https://github.com/siderolabs/talos/commit/0a5a8802e7e337e1f30a40c9f566e57642c39c1a) feat: use 'localhost' endpoint for controlplane nodes\n* [`b0775ebf2`](https://github.com/siderolabs/talos/commit/b0775ebf2c776c7133cf74c6259de9dc9573786c) feat: add ISO wipe GRUB boot option\n* [`29020cb9c`](https://github.com/siderolabs/talos/commit/29020cb9c788d87a0457028ce73c8d297959116e) fix: report fatal sequence errors as reboots\n* [`96629d5ba`](https://github.com/siderolabs/talos/commit/96629d5ba6c1ae9d820824fb38f68112bce27f2c) feat: implement etcd maintenance commands\n* [`80fed3194`](https://github.com/siderolabs/talos/commit/80fed319408be9e493141fb2c01e5731708835c7) feat: include Kubernetes controlplane endpoint as one of the endpoints\n* [`c6cb36cc1`](https://github.com/siderolabs/talos/commit/c6cb36cc1f50b5d0e59a5284867e7534dc9f73bb) docs: fix auditpolicy example typo\n* [`ba8265bc5`](https://github.com/siderolabs/talos/commit/ba8265bc5ce63bcbc6fbd6c1a1076dc3f2ee6bd0) feat: new talosctl config remove to remove context\n* [`fcb19ff51`](https://github.com/siderolabs/talos/commit/fcb19ff516cc1200ec81f2a954bb6d2ce39ebdc6) fix: implement upgrade version checks for Talos 1.4\n* [`80f150ac8`](https://github.com/siderolabs/talos/commit/80f150ac859f5dbf95060c12440afab8c0bc77a8) feat: enable ipv6 on gcp\n* [`8db622f3d`](https://github.com/siderolabs/talos/commit/8db622f3dc75aed90dd2d0bd92d03aa7e8aefd10) docs: add Vandebron to adopters list\n* [`f6a86ae90`](https://github.com/siderolabs/talos/commit/f6a86ae90607914c29875df750fe79cbbfcc5897) fix: oralce cloud zone\n* [`89dbb0ecf`](https://github.com/siderolabs/talos/commit/89dbb0ecf089bb746479238df274ccba4fcb049a) release(v1.4.0-alpha.0): prepare release\n* [`31fb90535`](https://github.com/siderolabs/talos/commit/31fb9053582190b3b536a309c30e2b78c4611885) feat: update Linux 6.1.1, containerd 1.6.14\n* [`a0c0352dd`](https://github.com/siderolabs/talos/commit/a0c0352ddca253e1efb3679224b317692d46b2fd) fix: send diagnostic output to stderr consistently\n* [`9a5f4c08a`](https://github.com/siderolabs/talos/commit/9a5f4c08a206504a1d30277dcc0597333e5a927a) fix: default the manifest namespace if not set\n* [`3c6cce5fe`](https://github.com/siderolabs/talos/commit/3c6cce5fe47075f43a73682b57a7b40fa0899795) docs: update last release for Talos 1.2.x\n* [`703624c43`](https://github.com/siderolabs/talos/commit/703624c43dd8e58c147ccbc3989c6c436c9f3a7f) docs: fix the 1.3 release date\n* [`386c9293a`](https://github.com/siderolabs/talos/commit/386c9293a33e9d237fbeda0492b01b11fdadc501) docs: update nvidia-container-runtime version\n* [`ff83d9fd7`](https://github.com/siderolabs/talos/commit/ff83d9fd7bed2e04d5c8107713150c2513f47991) fix: improve talosctl completion\n* [`31ff431fa`](https://github.com/siderolabs/talos/commit/31ff431faec22c09cad88d565102e6a24785ecb4) chore: add schulz systemtechnik to the list\n* [`97bef7c47`](https://github.com/siderolabs/talos/commit/97bef7c47bfd133f2b3ad19efe3f30a88dd67460) docs: vsphere.sh > vmware.sh\n* [`34babe858`](https://github.com/siderolabs/talos/commit/34babe858d15145a1c596febb5e577473e4ffce0) chore: make organization selection an interface\n* [`a9643b477`](https://github.com/siderolabs/talos/commit/a9643b477417029db73aacbfcf5778cedd97cd95) fix: use proper key usage for apid client certificate\n* [`171aa9467`](https://github.com/siderolabs/talos/commit/171aa9467966f5869e72374961ea05abc8d9fda9) fix: disable Wireless Lan using dtoverlay\n* [`2e84d2ab3`](https://github.com/siderolabs/talos/commit/2e84d2ab3417515f539a70d58885dcb69e9f098c) chore: update conformance product.yaml\n* [`b7763843a`](https://github.com/siderolabs/talos/commit/b7763843af63bbc186f08701a62c19ea96fb7e3c) feat: add install script that improves talosctl installation user experience This install script detects the platform and architecture, and downloads the correct talosctl, and checks the gpg checksums. It also installs and chmods the binary.\n* [`afc45ad63`](https://github.com/siderolabs/talos/commit/afc45ad632e63cc3afc095b1f3efe6df3ecb9cb1) docs: mark Talos 1.3 docs as default\n* [`873bd3807`](https://github.com/siderolabs/talos/commit/873bd3807c0fcca2e212deb7fd044662557964c1) fix: redact service account key in config in RedactSecrets method\n* [`b3aebfadf`](https://github.com/siderolabs/talos/commit/b3aebfadfc15544e5ab448d979129dba5e516c59) feat: validate Talos API access roles in machine config\n* [`40761e17d`](https://github.com/siderolabs/talos/commit/40761e17db5789f30eef2f15f0b5c6396e09a9e5) docs: fork docs for Talos 1.4\n* [`474604cd2`](https://github.com/siderolabs/talos/commit/474604cd279def7a6798e24ede27feef955ba5a3) docs: update documentation for Talos 1.3\n* [`faf49218c`](https://github.com/siderolabs/talos/commit/faf49218ce14a48829dae7b3b8d7801188453a89) feat: add more checks for K8s upgrade\n* [`5b992bd86`](https://github.com/siderolabs/talos/commit/5b992bd8610f41d23d8b7dbd01f9a1be298eda96) fix: allow empty dnsDomain in machine config\n* [`eb332cfcb`](https://github.com/siderolabs/talos/commit/eb332cfcb785e250c422d6a7ea2b23679189a946) feat: add health check for a minimal memory / disk size\n* [`d04970dfa`](https://github.com/siderolabs/talos/commit/d04970dfa9d6554e1ee447fd9383bf65b8953671) fix: ignore k8s additional addresses if nil\n* [`63c17104c`](https://github.com/siderolabs/talos/commit/63c17104c594dfd9ca4066ba41d8a03507464874) feat: update Kubernets to 1.26.0\n* [`f7a9a90db`](https://github.com/siderolabs/talos/commit/f7a9a90db2bfd316ea01551daba9becb15361f94) chore: update pkgs/tools (Go 1.19.4, containerd 1.6.11)\n* [`cf7adc51c`](https://github.com/siderolabs/talos/commit/cf7adc51c9f53234e469dd9f0cca06eed0230e8b) feat: add RedactSecrets method to v1alpha1.Config\n* [`4c31b9b1a`](https://github.com/siderolabs/talos/commit/4c31b9b1a3a00df0fe817c3edc15260ca3cadd6d) docs: clarify what the deal is with /var\n* [`a8ebcca4a`](https://github.com/siderolabs/talos/commit/a8ebcca4a9f63643f68d8e85bcb0b9ddb49205ed) chore: remove `watchErr` from `metal.getResource`\n* [`1253513bd`](https://github.com/siderolabs/talos/commit/1253513bd1deecc4cc42330bad0a713b3630240a) fix: fix nil pointer panic and incorrect error output\n* [`82e8c9e1f`](https://github.com/siderolabs/talos/commit/82e8c9e1f63371f41b0794b4c1be3209847c5f8b) fix: workaround panic in the kubelet service controller\n* [`a505b8909`](https://github.com/siderolabs/talos/commit/a505b8909a1c733b30f22a8d46eebc022475431a) fix: update COSI and reset restart backoff on success\n* [`e92fdcbad`](https://github.com/siderolabs/talos/commit/e92fdcbad1de595d119f78dbed3a97ae46df9bbf) chore: bump kernel to 5.15.81\n* [`f0dddca2a`](https://github.com/siderolabs/talos/commit/f0dddca2a3d2e976cee543ab57816a6395fe3d65) docs: expand help for 'talosctl get'\n* [`fcffc8879`](https://github.com/siderolabs/talos/commit/fcffc88790b5a3006b3b85744771a7eef6e8ac5c) fix: add ext4 filesystem detection\n* [`5b2960eff`](https://github.com/siderolabs/talos/commit/5b2960efff8b38af85b687a25fa93f01256016de) fix: introduce 'overridePath' setting and fix Talos resolver\n* [`0219d1124`](https://github.com/siderolabs/talos/commit/0219d1124e5125696364bf92ecf0e8dcad644001) fix: use only kube-apiserver endpoints for Talos API access endpoints\n* [`dc5e0f4af`](https://github.com/siderolabs/talos/commit/dc5e0f4af087d3b662b0240b4f8fd76379ed0de2) fix: report errors to Equinix Metal event API\n* [`7ab140a94`](https://github.com/siderolabs/talos/commit/7ab140a94ad1a279be43669d6d70687f3a0c47de) feat: add talosctl machineconfig patch command\n* [`d3cf06114`](https://github.com/siderolabs/talos/commit/d3cf061149a4a502317d7728c45b6cfb4d38f89f) fix: ignore many more filesystems in IMA\n* [`44e2799b8`](https://github.com/siderolabs/talos/commit/44e2799b8cb928083f3a777d5cce45ad8dbf6864) feat: add stdout and single config type support to talosctl gen config\n* [`4452f0e17`](https://github.com/siderolabs/talos/commit/4452f0e179db16c59dc65ccdb5a496ad3306684e) docs: bump talos version\n* [`38e57bd12`](https://github.com/siderolabs/talos/commit/38e57bd12b8c50d668fcde6ee9aa493682778dcc) feat: update Kubernetes to v1.26.0-rc.1\n* [`4cd125d49`](https://github.com/siderolabs/talos/commit/4cd125d499a24798dfde1dddf6fa1c689d16c93f) fix: correctly handle new watch event types\n* [`881b84152`](https://github.com/siderolabs/talos/commit/881b84152084d157fbd4ff992089a5392aadfd3c) feat: update Flannel to 0.20.2\n</p>\n</details>\n\n### Changes since v1.4.0-alpha.2\n<details><summary>50 commits</summary>\n<p>\n\n* [`a7b79ef1b`](https://github.com/siderolabs/talos/commit/a7b79ef1be79ca7e0ea1530d469c3790f43e6c6b) feat: add network config screen to dashboard\n* [`cf2ccc521`](https://github.com/siderolabs/talos/commit/cf2ccc521f6a15b8b82bf5fbaab572f481f8edf7) fix: always shutdown maintenance API service\n* [`a0a5db590`](https://github.com/siderolabs/talos/commit/a0a5db590d9b5f312f9e59bec4ddc7379183c705) feat: update Flannel to 0.21.4\n* [`d1a61fd34`](https://github.com/siderolabs/talos/commit/d1a61fd34343e58192864b1464759b78eb57e917) chore: bump golangci-lint\n* [`36a9a208e`](https://github.com/siderolabs/talos/commit/36a9a208ecf01114f5cc47449bb69099fca99e83) chore: bump deps\n* [`c63cf90e3`](https://github.com/siderolabs/talos/commit/c63cf90e32ce61e788a00ed79a5ff662d3d25e50) feat: update k8s to v1.27.0-beta.0\n* [`b246c90ab`](https://github.com/siderolabs/talos/commit/b246c90abdec14c305dbad8af82147ebe44328ce) fix: add uint32 to Magic1 and Magic2\n* [`777c8d6f6`](https://github.com/siderolabs/talos/commit/777c8d6f6ecb438d11ac829a297bf2c6b5660479) chore: update COSI to watch aggregated version\n* [`bec89bf6e`](https://github.com/siderolabs/talos/commit/bec89bf6e575923f348a4885841de27eead020df) fix: use 'no block' etcd dial with multiple endpoints\n* [`28713c2c4`](https://github.com/siderolabs/talos/commit/28713c2c4d4d20d5ff455c40cbb8aa004d725801) feat: update Kubernetes to 1.26.3\n* [`a3cf41647`](https://github.com/siderolabs/talos/commit/a3cf4164755609e80de5dafa2c49bfaa0fc655fd) docs: add InstallConfig ignored notice to doc\n* [`df9b851fb`](https://github.com/siderolabs/talos/commit/df9b851fbadaa7c652f343c2facc2bd0a9dd22ca) chore: load all external artifacts earlier\n* [`2dd0964c5`](https://github.com/siderolabs/talos/commit/2dd0964c5f617a7072af08bd45c35d57bc47e838) refactor: use resource watches on dashboard\n* [`9933ebb6a`](https://github.com/siderolabs/talos/commit/9933ebb6aa86249d2118ef5fb50bf23cedadb0a5) chore: fix loaded artifacts file permission\n* [`a14a0aba0`](https://github.com/siderolabs/talos/commit/a14a0aba04a2daf277bf2703575def39b7f2e5e9) fix: nil pointer exception in syncLink\n* [`cf101e56f`](https://github.com/siderolabs/talos/commit/cf101e56fbf18bb401bebb95e9fe005f65765d3d) fix: add `--force` flag for `talosctl gen`\n* [`ea2aa0611`](https://github.com/siderolabs/talos/commit/ea2aa06116a1b3c58d40ad42787749783516ef6c) fix: fix data race on network config read\n* [`64e3d24c6`](https://github.com/siderolabs/talos/commit/64e3d24c6bfe60b5556c41822c8e81f63d0a06d2) feat: provide platform network config for 'metal' in META\n* [`442cb9c1b`](https://github.com/siderolabs/talos/commit/442cb9c1b0757a9c8204cc92baab11f664cbcb19) feat: implement APIs to write to META\n* [`9e07832db`](https://github.com/siderolabs/talos/commit/9e07832db9e19e602332821769f479b881fae178) feat: implement summary dashboard\n* [`1df841bb5`](https://github.com/siderolabs/talos/commit/1df841bb542323adce92013cd55eb24ab238a1dc) refactor: change the interface of META\n* [`e9962bc3e`](https://github.com/siderolabs/talos/commit/e9962bc3eaa31b9a782c2fcd0c7857a86cba0c28) chore: update CI to tag azure buckets\n* [`9f5f5cf9b`](https://github.com/siderolabs/talos/commit/9f5f5cf9bf83e9cff0be7720d6bffc13fec97570) feat: update Flannel to v0.21.3\n* [`02b0ff35e`](https://github.com/siderolabs/talos/commit/02b0ff35ee2273e59899ac4a999fa101d895aec0) feat: generate Flannel CNI manifest from upstream\n* [`6656d35ec`](https://github.com/siderolabs/talos/commit/6656d35eca5ec78cd52e7a6478369200ce16b176) docs: fix Talos version to use template\n* [`72a6d1d70`](https://github.com/siderolabs/talos/commit/72a6d1d70813986f6e9f4b7fc92e594f6ff7da1f) docs: update nocloud\n* [`9948a646d`](https://github.com/siderolabs/talos/commit/9948a646d20f4ba80916a263ed7bca3e5ca2f0ad) feat: coredns node uninitialized toleration\n* [`e03902b54`](https://github.com/siderolabs/talos/commit/e03902b546b379c19ea80081bbfaef666d03812d) feat: update Go to 1.20.2\n* [`c8f8579f2`](https://github.com/siderolabs/talos/commit/c8f8579f2dcf485e66922679d37e56742b65cc53) fix: upgrade-k8s to flag should not be required since there is a default\n* [`230cfaf80`](https://github.com/siderolabs/talos/commit/230cfaf80312518222469939e969880040c379f2) feat: use network information from guestinfo.metadata\n* [`97048f7c3`](https://github.com/siderolabs/talos/commit/97048f7c37ed7b7aceadf6f2e40f007a09c57730) feat: netstat in API and client\n* [`fda6da692`](https://github.com/siderolabs/talos/commit/fda6da692956d863d320f25cd50833da2f93104c) fix: successful ACPI shutdown in maintenance mode\n* [`b97e1abaa`](https://github.com/siderolabs/talos/commit/b97e1abaa6a1543bc7b6e8fa7e4fa9e0cb5d8e14) feat: set default image, validate empty image\n* [`121220a3b`](https://github.com/siderolabs/talos/commit/121220a3b3202de9bd08dce391740c9a66ad9cf2) chore: bump dependencies via renovate bot\n* [`ebc92f3c1`](https://github.com/siderolabs/talos/commit/ebc92f3c1de97a8b11046268854e957be0b64f81) chore: add container id to `talosctl -k containers` and `talosctl -k logs`\n* [`22ef81c1e`](https://github.com/siderolabs/talos/commit/22ef81c1e78963a8f46e2f54d00cd111742dd95c) feat: add grub option to drop to maintenance mode\n* [`642fe0c90`](https://github.com/siderolabs/talos/commit/642fe0c90c4714aeb5f880946c1d337c53bc6fa4) feat: update pkgs with framebuffer console\n* [`69cb414f0`](https://github.com/siderolabs/talos/commit/69cb414f01d3193931e838f89e21b0c9ac26bf61) docs: update cilium install instructions\n* [`e71cc6619`](https://github.com/siderolabs/talos/commit/e71cc6619b2cdc34efe8dccca3cc296befef43f9) fix: redo assertHostnames in HostnameMergeSuite.TestMerge\n* [`8ea4bfad8`](https://github.com/siderolabs/talos/commit/8ea4bfad8feae5f4806be0ea4f6fdd1b79a8197a) refactor: improve the kubernetes upgrade flow\n* [`81879fc0c`](https://github.com/siderolabs/talos/commit/81879fc0ca98cc3e5df619bd071c279a735697e3) docs: add how tos for workloads on control planes, and scaling up\n* [`05b0b721c`](https://github.com/siderolabs/talos/commit/05b0b721c9d2acd211519d554d1c23926472a5b4) chore: move blob storage to azure for builds\n* [`a78281214`](https://github.com/siderolabs/talos/commit/a78281214d349c147498e3b000a9e9aeecb29eb6) feat: add cilium e2e tests\n* [`061640ccc`](https://github.com/siderolabs/talos/commit/061640cccf69d065806140e670e484c8b1c5a26e) feat: add pod ip to kube-proxy spec\n* [`dea17d723`](https://github.com/siderolabs/talos/commit/dea17d72340b1deddea2215b556a4f193d1feb7f) feat: update Kubernetes to v1.26.2\n* [`337aaba7a`](https://github.com/siderolabs/talos/commit/337aaba7a705536b885d7336343b828dd13e1de4) feat: add 'os:operator' role\n* [`40e69af22`](https://github.com/siderolabs/talos/commit/40e69af2242fcd91f4a351da02de1b94158d419c) fix: improve etcd leave on reset process\n* [`638dc9128`](https://github.com/siderolabs/talos/commit/638dc9128fd89f70ddab8d6f342ca5a2e5131be8) fix: fix \"defer\" leak in ResetUserDisks\n* [`bfba3677b`](https://github.com/siderolabs/talos/commit/bfba3677b0e85a27a8b92235f5763ac6fc8e0375) chore: handle grub option - \"wipe\"\n* [`594f27d87`](https://github.com/siderolabs/talos/commit/594f27d87870ef26fc7166a95a64a40d27cb165a) release(v1.4.0-alpha.2): prepare release\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`ac75538`](https://github.com/siderolabs/discovery-api/commit/ac75538ee3a9f7b71b6619f509d95ff5057f6754) chore: regen the proto definitions with vtprotobuf v0.4.0\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`269a832`](https://github.com/siderolabs/discovery-client/commit/269a832ce9e35d4edeeddba2a23cf5682a2ca425) chore: rekres, update discovery api\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>8 commits</summary>\n<p>\n\n* [`343956e`](https://github.com/siderolabs/extras/commit/343956eb882eed775c68ef5af3bd37407aa914f4) feat: update Go to 1.20.2\n* [`6209d87`](https://github.com/siderolabs/extras/commit/6209d8774d2ace990f532ab88cf2fa6464c8bafa) chore: bump tc-redirect-tap\n* [`8b28b6b`](https://github.com/siderolabs/extras/commit/8b28b6b5a0153c65af596086016faea9d64e95c2) chore: bump deps\n* [`5ab4f59`](https://github.com/siderolabs/extras/commit/5ab4f5939c830c7043e3939e519305eb810cdfc2) chore: disable renovate builds\n* [`ddeddbd`](https://github.com/siderolabs/extras/commit/ddeddbd1976813de6b1563f662ca4f2b3f5e0f53) chore: update packages, tc_redirect_tap\n* [`8cb4792`](https://github.com/siderolabs/extras/commit/8cb4792da9b9e2b2663daca747d24c3b5c973e0f) chore: update Go to 1.19.5\n* [`3ca2df3`](https://github.com/siderolabs/extras/commit/3ca2df3ead2a64a5ad30c350b87bfe02bf1f49c7) chore: disable provenance in buildx\n* [`55d8452`](https://github.com/siderolabs/extras/commit/55d845241c8456909ab36f9b0f4e26cc2b49c256) feat: update releases\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`214c1ef`](https://github.com/siderolabs/gen/commit/214c1efe795cf426e5ebcc48cb305bfc7a16fdb8) chore: set `slice.Filter` result slice cap to len\n* [`8e89b1e`](https://github.com/siderolabs/gen/commit/8e89b1ede9f35ff4c18a41ee44a69259181c892b) feat: add GetOrCreate and GetOrCall methods\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`8c7ea19`](https://github.com/siderolabs/go-blockdevice/commit/8c7ea1910b27e0660e3e1a6f98b9f7e24bc11ff0) fix: blockdevice size is reported by Linux in 512 blocks always\n</p>\n</details>\n\n### Changes from siderolabs/go-kmsg\n<details><summary>1 commit</summary>\n<p>\n\n* [`7a51094`](https://github.com/siderolabs/go-kmsg/commit/7a51094e29290697aaeed8f09ccb045634876801) fix: exit properly on context cancel\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>4 commits</summary>\n<p>\n\n* [`81887dc`](https://github.com/siderolabs/go-kubernetes/commit/81887dcae8916ccee820af000efe73c151de29a4) feat: add kubelet flag checks\n* [`fe473c0`](https://github.com/siderolabs/go-kubernetes/commit/fe473c0595e8e2e861fc16d0cddb1ba2cedf1ab3) refactor: make sync easier to consume without CLI\n* [`570819b`](https://github.com/siderolabs/go-kubernetes/commit/570819b93ecc63218b3db8d90e4810765a069ee0) feat: initial version of the library\n* [`fb79215`](https://github.com/siderolabs/go-kubernetes/commit/fb7921556e96fc7c0a84ac23834350bcd37cfa38) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`c526764`](https://github.com/siderolabs/go-smbios/commit/c5267640be317efd9cbbe936ab78b2a49c757edf) feat: fix reading \"broken\" Hyper-V DMI data\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>36 commits</summary>\n<p>\n\n* [`c26b0b5`](https://github.com/siderolabs/pkgs/commit/c26b0b504e5fd0f68432503aabd2653c07888706) chore: bump deps\n* [`7d8f5bd`](https://github.com/siderolabs/pkgs/commit/7d8f5bd7170464c4f017c8e747dd5eda40c35639) feat: enable Hyper-V dynamic memory driver\n* [`ea40205`](https://github.com/siderolabs/pkgs/commit/ea4020599aeb1cd0f78abcfd19c546026bfb0634) chore: bump deps\n* [`21e5a68`](https://github.com/siderolabs/pkgs/commit/21e5a6806288f535773cd8afc20b12ee3082caa8) feat: update Go 1.20.2, Linux 6.1.15 and other\n* [`1d7e60c`](https://github.com/siderolabs/pkgs/commit/1d7e60cc2da55b0a31bd225479c86f517c7a878f) feat: enable framebuffer drivers and console fonts\n* [`0e63e95`](https://github.com/siderolabs/pkgs/commit/0e63e955dd118b6d5e8a9dd443c72a5d35d639a6) chore: bump deps\n* [`5dbce6b`](https://github.com/siderolabs/pkgs/commit/5dbce6b19ff6a1e1b5ae88468e34925c3d30d627) fix: xz url\n* [`0097233`](https://github.com/siderolabs/pkgs/commit/00972336c3fcc22df8fc1d3774c35b26fdc957b9) chore: re-enable drbd\n* [`7493721`](https://github.com/siderolabs/pkgs/commit/749372110c6c8e226139cd662832b5a4169db894) fix: sourcefourge url shasums\n* [`185f482`](https://github.com/siderolabs/pkgs/commit/185f482db6a5c13a3b14feec02a4e361b53bec55) feat: update containerd to 1.6.18\n* [`e3cab6c`](https://github.com/siderolabs/pkgs/commit/e3cab6cbd62b96143958ed5e0219d68107a5f583) chore: bump deps\n* [`18661b0`](https://github.com/siderolabs/pkgs/commit/18661b096559e673152ce0fed45ab74ef3305dff) chore: bump deps\n* [`885a68b`](https://github.com/siderolabs/pkgs/commit/885a68b6280f3bf4ff75508ccceef73158c53560) chore: bump deps\n* [`c3a6e18`](https://github.com/siderolabs/pkgs/commit/c3a6e185178d7571e891c7b2614bf6017ab5c913) chore: bump dependencies\n* [`1fae0b2`](https://github.com/siderolabs/pkgs/commit/1fae0b229a625d692d36e7d6c096f8476e0f56d7) feat: virtio drivers as modules\n* [`61d8ff4`](https://github.com/siderolabs/pkgs/commit/61d8ff4aaea93b86b82bc2a36a2bbd6d54da3bb8) chore: bump deps and disable un-needed kconfig\n* [`15fe6d8`](https://github.com/siderolabs/pkgs/commit/15fe6d8555b42e55f920a5576ad55504e356995b) fix: kernel module tree files missing\n* [`987d24a`](https://github.com/siderolabs/pkgs/commit/987d24aeaa4fb2278954cd96e6bc6a29a4c8dd61) feat: mellanox drivers are modules\n* [`b82a015`](https://github.com/siderolabs/pkgs/commit/b82a015c78c407d17d23542eba6a4114f3c2c4d7) feat: mellanox oped\n* [`057d4f9`](https://github.com/siderolabs/pkgs/commit/057d4f96aa3ba63cc456b06a70a6b3a008cf803f) chore: bump deps\n* [`4ac4138`](https://github.com/siderolabs/pkgs/commit/4ac4138c6b94622646c9f32f0885496c5475d905) feat: enable nvme support for raspberrypi cm4\n* [`ccb9d39`](https://github.com/siderolabs/pkgs/commit/ccb9d39dc43cf53431a0d7609839ed9c7141972d) fix: disable magic sysrq\n* [`d33202d`](https://github.com/siderolabs/pkgs/commit/d33202d99daa6ccf136fca54ebbadda727a43a75) chore: bump u-boot to 2023.01\n* [`cb83e16`](https://github.com/siderolabs/pkgs/commit/cb83e169df4a2020994a63e5be61524461ef93e3) chore: bump dependencies\n* [`e561dcb`](https://github.com/siderolabs/pkgs/commit/e561dcb45beae80161faccedb0303e58d41b1ded) feat: bump Go to 1.19.5\n* [`c7797c7`](https://github.com/siderolabs/pkgs/commit/c7797c77bd311449e1f116980166d8d818102f4f) feat: update Linux to 6.1.4, restore RPi support\n* [`5e8ebb0`](https://github.com/siderolabs/pkgs/commit/5e8ebb073d9b58555a75912cd90490af8a435c7d) feat: add AMD K10 sensor support\n* [`73ac37d`](https://github.com/siderolabs/pkgs/commit/73ac37d683274e60340d2767f2b8201e7f13474c) chore: disable provenance in buildx\n* [`8965bee`](https://github.com/siderolabs/pkgs/commit/8965bee65313539e8b6534073d06341f4fb78586) chore: use default symlinks to `/bin` in `base`\n* [`325c9bf`](https://github.com/siderolabs/pkgs/commit/325c9bf0f3ed2bf7603d1eaea022ea650388cf2b) feat: bump dependencies\n* [`165dff6`](https://github.com/siderolabs/pkgs/commit/165dff6c3cdb2d05f170c8ae0616d9224416455e) fix: patch ipmitool IANA URL\n* [`c542f39`](https://github.com/siderolabs/pkgs/commit/c542f398a150567d5cdffc17b4248be5416fe242) feat: add kernel support for usb setrial console\n* [`f564f45`](https://github.com/siderolabs/pkgs/commit/f564f45645d102b7e3a9563ac7bdb1e816156e65) chore: bump tools, containerd\n* [`268ea7c`](https://github.com/siderolabs/pkgs/commit/268ea7c593ff04c4e4a9ea5676b3c58d41cbff14) chore: bump deps\n* [`dcf3ceb`](https://github.com/siderolabs/pkgs/commit/dcf3cebf283698e010aaac5417d91a7385dc2441) feat: add nitro enclave support in kernel\n* [`17ea5e6`](https://github.com/siderolabs/pkgs/commit/17ea5e680b2438c59fa1773e8b58d6b749cb0d34) chore: bump kernel to 5.15.81\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>29 commits</summary>\n<p>\n\n* [`2d710f9`](https://github.com/siderolabs/tools/commit/2d710f9074caefcbd1cd37190dda02372e851500) chore: bump deps\n* [`9bea7d0`](https://github.com/siderolabs/tools/commit/9bea7d04310bfb1177e55a9e4fe1606b81ad8dbd) chore: skip rc versions for util-linux\n* [`a94850e`](https://github.com/siderolabs/tools/commit/a94850e6dd52a2b2d08c3e4e1fe95adddcb68f20) chore: bump deps\n* [`e6b2956`](https://github.com/siderolabs/tools/commit/e6b29564537a54549165ea99fceff160d21634dd) fix: protoc install\n* [`601e347`](https://github.com/siderolabs/tools/commit/601e3475b6bb9249bcf4e2bee16791ea4f91e8f9) feat: go 1.20.2 + other bumps\n* [`ca67d0b`](https://github.com/siderolabs/tools/commit/ca67d0ba6ccb45f30da328fd210cbe92782c2151) chore: bump deps\n* [`662a906`](https://github.com/siderolabs/tools/commit/662a90650841ab6c8ffd74e4abc51654b713dd4e) feat: add libnl\n* [`a8440a9`](https://github.com/siderolabs/tools/commit/a8440a9c866d9837d358b53a869bcb43774f4e78) fix: partially revert e6c98fdf54425e6382f226e33bccca6f3875aad3a\n* [`e6c98fd`](https://github.com/siderolabs/tools/commit/e6c98fdf54425e6382f226e33bccca6f3875aad3) chore: remove swig\n* [`cd9687b`](https://github.com/siderolabs/tools/commit/cd9687b4323b20493b4d582cfaa48c321cd04288) fix: renovate config\n* [`977e3fc`](https://github.com/siderolabs/tools/commit/977e3fcba92d129eb78cb77300f38428f860b34d) chore: bump go to 1.20.1\n* [`15748aa`](https://github.com/siderolabs/tools/commit/15748aa32d7c1d67b190ab7a27ace9922c8d6b56) chore: bump deps\n* [`d4b719a`](https://github.com/siderolabs/tools/commit/d4b719a1c2055eaa27f80422f93755b0de9ca3f8) chore: bump deps\n* [`8c36dbd`](https://github.com/siderolabs/tools/commit/8c36dbd05ee27ecc2a7340462a3b49efb7327184) chore: bump toolchain, bump protoc-gen-go-grpc\n* [`a62e365`](https://github.com/siderolabs/tools/commit/a62e365b223e7ca9d2728865b40b23115764a0ed) feat: update Go to 1.20\n* [`28d4a57`](https://github.com/siderolabs/tools/commit/28d4a5721ce1c57fc3f643185386d5c4b5c7e39a) chore: reduce renovate noise\n* [`e130fd5`](https://github.com/siderolabs/tools/commit/e130fd5b9835d8cc178ec53d5a89dfc6cc2ce7a1) chore: bump deps\n* [`37612fe`](https://github.com/siderolabs/tools/commit/37612feb7222b943a84f1f98d0901a204d491926) fix: revert enabling provenance\n* [`e0b01e3`](https://github.com/siderolabs/tools/commit/e0b01e3b7420e8b0b1e0d9077515e007a6b83b56) chore: bump deps\n* [`d0e6bd0`](https://github.com/siderolabs/tools/commit/d0e6bd06fcfcadc330cf30339488536961f9f70e) feat: add gnutls\n* [`3d34b5d`](https://github.com/siderolabs/tools/commit/3d34b5d401a67048d365e8faf2f1edf293887a97) chore: bump dependencies\n* [`763c1d9`](https://github.com/siderolabs/tools/commit/763c1d927822517b3d63c624302e11e8e5a49f5b) feat: update Go to 1.19.5\n* [`136958f`](https://github.com/siderolabs/tools/commit/136958f9f8c8cfc439228dec31b840549bca4374) chore: disable provenance in buildx\n* [`e2a8692`](https://github.com/siderolabs/tools/commit/e2a869294be7e77e295ca651400f85551fb7e665) feat: update releases\n* [`0e48f37`](https://github.com/siderolabs/tools/commit/0e48f37496a79ce4997d15fefb6300b2324f5668) chore: bump protobuf\n* [`a21aa1c`](https://github.com/siderolabs/tools/commit/a21aa1c583a10d017ace8da14c6f604f86ce5709) chore: bump toolchain and mpc versions\n* [`1a75d0f`](https://github.com/siderolabs/tools/commit/1a75d0f6796c4abf1c9a23cfe697d3e38a9ce587) chore: bump deps\n* [`55bd185`](https://github.com/siderolabs/tools/commit/55bd18532667e325e8938bf0a72cab40a936eadf) feat: update Go to 1.19.4\n* [`f291f46`](https://github.com/siderolabs/tools/commit/f291f46e84ec02f5d22718f7ecb476a3f815ae45) chore: bump tools\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**           v0.2.1 -> v0.2.3\n* **github.com/aws/aws-sdk-go**                      v1.44.147 -> v1.44.226\n* **github.com/containerd/cgroups**                  v1.0.4 -> v1.1.0\n* **github.com/containerd/containerd**               v1.6.12 -> v1.6.19\n* **github.com/containernetworking/plugins**         v1.1.1 -> v1.2.0\n* **github.com/coreos/go-semver**                    v0.3.0 -> v0.3.1\n* **github.com/cosi-project/runtime**                v0.2.0 -> v0.3.0-alpha.10\n* **github.com/docker/docker**                       v20.10.21 -> v23.0.1\n* **github.com/dustin/go-humanize**                  v1.0.0 -> v1.0.1\n* **github.com/emicklei/dot**                        v1.2.0 -> v1.3.1\n* **github.com/fatih/color**                         v1.13.0 -> v1.15.0\n* **github.com/freddierice/go-losetup/v2**           v2.0.1 **_new_**\n* **github.com/gdamore/tcell/v2**                    v2.5.3 -> v2.6.0\n* **github.com/grpc-ecosystem/go-grpc-middleware**   v1.3.0 -> v1.4.0\n* **github.com/hashicorp/go-getter**                 v1.6.2 -> v1.7.1\n* **github.com/hetznercloud/hcloud-go**              v1.37.0 -> v1.41.0\n* **github.com/insomniacslk/dhcp**                   f26e6d78f622 -> e252950ab961\n* **github.com/jsimonetti/rtnetlink**                v1.3.0 -> v1.3.1\n* **github.com/mattn/go-isatty**                     v0.0.16 -> v0.0.17\n* **github.com/mdlayher/ethtool**                    0e16326d06d1 -> ba3b4bc2e02c\n* **github.com/mdlayher/genetlink**                  v1.3.0 -> v1.3.1\n* **github.com/mdlayher/netlink**                    v1.7.0 -> v1.7.1\n* **github.com/nberlee/go-netstat**                  19cc338ee40a **_new_**\n* **github.com/prometheus/procfs**                   v0.8.0 -> v0.9.0\n* **github.com/rivo/tview**                          db36428c92d9 -> 84f9c0ff9de8\n* **github.com/safchain/ethtool**                    v0.2.0 -> v0.3.0\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.10 -> v1.0.0-beta.15\n* **github.com/siderolabs/discovery-api**            v0.1.1 -> v0.1.2\n* **github.com/siderolabs/discovery-client**         v0.1.3 -> v0.1.4\n* **github.com/siderolabs/extras**                   v1.3.0-1-g3773d71 -> v1.4.0-alpha.0-7-g343956e\n* **github.com/siderolabs/gen**                      v0.4.1 -> v0.4.3\n* **github.com/siderolabs/go-blockdevice**           v0.4.2 -> v0.4.3\n* **github.com/siderolabs/go-kmsg**                  v0.1.2 -> v0.1.3\n* **github.com/siderolabs/go-kubernetes**            v0.2.0 **_new_**\n* **github.com/siderolabs/go-smbios**                v0.3.1 -> v0.3.2\n* **github.com/siderolabs/pkgs**                     v1.3.0-5-g6509d23 -> v1.4.0-alpha.0-35-gc26b0b5\n* **github.com/siderolabs/talos/pkg/machinery**      v1.3.0 -> v1.4.0-alpha.2\n* **github.com/siderolabs/tools**                    v1.3.0-1-g712379c -> v1.4.0-alpha.0-26-g2d710f9\n* **github.com/stretchr/testify**                    v1.8.1 -> v1.8.2\n* **github.com/u-root/u-root**                       v0.10.0 -> v0.11.0\n* **github.com/ulikunitz/xz**                        v0.5.11 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.12 -> v0.56.16\n* **github.com/vmware/govmomi**                      v0.29.0 -> v0.30.4\n* **go.etcd.io/etcd/api/v3**                         v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/v3**                      v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.6 -> v3.5.7\n* **go.uber.org/zap**                                v1.23.0 -> v1.24.0\n* **go4.org/netipx**                                 797b0c90d8ab -> f1b76eb4bb35\n* **golang.org/x/net**                               v0.4.0 -> v0.8.0\n* **golang.org/x/sys**                               v0.3.0 -> v0.6.0\n* **golang.org/x/term**                              v0.3.0 -> v0.6.0\n* **golang.org/x/time**                              v0.2.0 -> v0.3.0\n* **golang.zx2c4.com/wireguard/wgctrl**              97bc4ad4a1cb -> 9c5414ab4bde\n* **google.golang.org/grpc**                         v1.51.0 -> v1.54.0\n* **google.golang.org/protobuf**                     v1.28.1 -> v1.30.0\n* **k8s.io/api**                                     v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/apimachinery**                            v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/apiserver**                               v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/client-go**                               v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/component-base**                          v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/cri-api**                                 v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/klog/v2**                                 v2.80.1 -> v2.90.1\n* **k8s.io/kubectl**                                 v0.26.0 -> v0.27.0-beta.0\n* **k8s.io/kubelet**                                 v0.26.0 -> v0.27.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.66 -> v1.2.67\n\nPrevious release can be found at [v1.3.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0)\n\n\n\n\n\n\n\n## [Talos 1.4.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.4.0-alpha.2) (2023-02-28)\n\nWelcome to the v1.4.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Registry Mirror Catch-All Option\n\nTalos now supports a catch-all option for registry mirrors:\n\n```yaml\nmachine:\n    registries:\n        mirrors:\n            docker.io:\n                - https://registry-1.docker.io/\n            \"*\":\n                - https://my-registry.example.com/\n```\n\n\n### Talos Dashboard on TTY2\n\nTalos now starts a text-based UI dashboard on virtual console `/dev/tty2` and switches to it by default upon boot.\nKernel logs remain available on `/dev/tty1`.\n\nTo switch TTYs, use the `Alt+F1` through `Alt+F2` keys.\n\nYou can disable this behavior by setting the kernel parameter `talos.dashboard.disabled=1`.\n\nThis behavior is disabled by default on SBCs.\n\n\n### etcd Maintenance\n\nTalos adds new APIs to make it easier to perform etcd maintenance operations.\n\nThese APIs are available via new `talosctl etcd` sub-commands:\n\n* `talosctl etcd alarm list|disarm`\n* `talosctl etcd defrag`\n* `talosctl etcd status`\n\nSee also [etcd maintenance guide](https://talos.dev/v1.4/advanced/etcd-maintenance/).\n\n\n### Kernel Modules\n\nTalos now supports automatically loading kernel drivers built as modules.\nIf any system extensions or the Talos base kernel build provides kernel modules and if they matches the system hardware (via PCI IDs), they will be loaded automatically.\nModules can still be loaded explicitly by defining it in [machine configuration](https://www.talos.dev/v1.4/reference/configuration/#kernelconfig).\n\n\n### Kernel Modules Tree\n\nTalos now supports re-building the kernel modules dependency tree information on upgrades.\nThis allows modules of same name to co-exist as in-tree and external modules.\nSystem Extensions can provide modules installed into `extras` directory and when loading it'll take precendence over the in-tree module.\n\n\n### Machine Configuration\n\nStrategic merge config patches correctly support merging `.vlans` sections of the network interface.\n\n\n### Reset API Enhancements\n\nTalos now supports resetting user disks through the Reset API,\nthe list of disks to wipe is set using the `--user-disks-to-wipe` parameter in `talosctl`.\nAdditionally, the Reset API can now function in maintenance mode\nand has the capability to wipe the node's system disk (partial wipe is not supported).\n\n\n### Component Updates\n\n* Linux: 6.1.12\n* containerd: v1.6.18\n* Kubernetes: v1.26.1\n* etcd: v3.5.7\n* CoreDNS: v1.10.1\n\nTalos is built with Go 1.20.1.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Spencer Smith\n* Serge Logvinov\n* Steve Francis\n* Artem Chernyshev\n* Tim Jones\n* Andrey Smirnov\n* Cees-Jan Kiewiet\n* Chris van de Sande\n* Lance R. Vick\n* Matthias Riegler\n* Michael Vorburger\n* Murtaza Udaipurwala\n* Nico Berlee\n* Niklas Wik\n* Rowan Smith\n* Samuel Kees\n* Sander Maijers\n* Seán C McCord\n* Steffen Windoffer\n* Tim van Druenen\n* Victor Seva\n* budimanjojo\n\n### Changes\n<details><summary>128 commits</summary>\n<p>\n\n* [`b52071081`](https://github.com/siderolabs/talos/commit/b5207108104eda426361c256ec4d78ae9e0b2890) feat: introduce new flag in reset API that makes Talos reset user disks\n* [`f55f5df73`](https://github.com/siderolabs/talos/commit/f55f5df7396b7073e75267c7e10a35814f1185c9) feat: move dashboard package & run it in tty2\n* [`36e077ead`](https://github.com/siderolabs/talos/commit/36e077ead458f15e864f62eeb0d7afa59187c226) chore: bump deps\n* [`5a01d5fd4`](https://github.com/siderolabs/talos/commit/5a01d5fd473cdc4e0b9fba48047d6434cf31ee42) chore: run extension build as downstream\n* [`426fe9687`](https://github.com/siderolabs/talos/commit/426fe9687d74690df26ce3cfd6aee47c13e994a8) fix: extension base folder permission\n* [`609d3a8a6`](https://github.com/siderolabs/talos/commit/609d3a8a694ff90426ce33be86791f2616ec4852) feat: support strategic merge patches on VLAN configuration\n* [`7e19f32d7`](https://github.com/siderolabs/talos/commit/7e19f32d762dc1363f29e988ddbe334bd00610f2) chore: provide version compatibility data for Talos 1.2.x\n* [`230e46e56`](https://github.com/siderolabs/talos/commit/230e46e567012d8e12e384c777d6f57db5e7cfee) refactor: extract parts of kubernetes libraries\n* [`f3d3f0f26`](https://github.com/siderolabs/talos/commit/f3d3f0f2625f1be41a17366ee1c0bd2a3193c08c) fix: update go-smbios library with Hyper-V data fix\n* [`8711eea96`](https://github.com/siderolabs/talos/commit/8711eea9626a60a996347aaa7e6a89eea87d4b9e) fix: use passed `--context` in `talosctl config` cmd\n* [`5ac9f43e4`](https://github.com/siderolabs/talos/commit/5ac9f43e45f85f8d37c2855051b9a5cc9ad389ac) feat: start machined earlier & in maintenance mode\n* [`36ab414a1`](https://github.com/siderolabs/talos/commit/36ab414a1d7c5472522d20a7b698c4eebb3423b9) docs: fix the endpoints in the libvirt guide\n* [`3d55bd80f`](https://github.com/siderolabs/talos/commit/3d55bd80f42b7d2439541909c9534c386607e578) fix: add `--force` flag to `talosctl gen config`\n* [`660b8874d`](https://github.com/siderolabs/talos/commit/660b8874da7bd91946aab5f400e7d1dfddefb827) feat: cmdline integer netmask\n* [`1e3daacc4`](https://github.com/siderolabs/talos/commit/1e3daacc48c0b8ef2eab41b2c2c53f55522e1acf) docs: update nvidia component versions\n* [`b5c03a7fa`](https://github.com/siderolabs/talos/commit/b5c03a7fab8d213e7048a8f5fc129125b81eb205) fix: docker talosctl cluster create provisioner\n* [`6e8f13529`](https://github.com/siderolabs/talos/commit/6e8f13529c17ff4c658b340d16d9ee429cfd9a4c) fix: add support for a fallback '*' mirror configuration\n* [`dcd4eb1a9`](https://github.com/siderolabs/talos/commit/dcd4eb1a93737d60f60693d8c33a20052eee4a4f) fix: improve error message on single node upgrade\n* [`ed5af3f78`](https://github.com/siderolabs/talos/commit/ed5af3f780732fb0004ddb263feedbf2de9fd09a) chore: bump deps\n* [`0dc6858e5`](https://github.com/siderolabs/talos/commit/0dc6858e5ba4b110eac9ca74294eb3a29790a323) chore: bump cosi-project/runtime\n* [`da2edb9de`](https://github.com/siderolabs/talos/commit/da2edb9de067fc21c792e948903bc2c880b2c2d1) chore: bump dependencies\n* [`e51a110f0`](https://github.com/siderolabs/talos/commit/e51a110f0e876fc091aee0828aca0135499def9c) chore: bump dependencies\n* [`2d0148018`](https://github.com/siderolabs/talos/commit/2d014801803fa0d5f08a344bdc9ff078b3931633) feat: automatically load modules based on hw info\n* [`7b75cd8b9`](https://github.com/siderolabs/talos/commit/7b75cd8b94367645adb2dd5be016e6f98d8e6a89) fix: kernel module dependency tree generation\n* [`65d02e5ad`](https://github.com/siderolabs/talos/commit/65d02e5ade08354aeec794d4131a1f8913fba2b5) fix: dbus shutdown when it's not initialized\n* [`a7079ce85`](https://github.com/siderolabs/talos/commit/a7079ce85c9839933544b637100f104f02fd3f3a) fix: quote the ampersand character in GRUB config\n* [`933ba2d82`](https://github.com/siderolabs/talos/commit/933ba2d8203e4418414b3de1c4240c1f88cb033e) fix: display correct blockdevice size\n* [`c449cb736`](https://github.com/siderolabs/talos/commit/c449cb736b24b268b965da5e2932f18bd4fb7785) fix: talosctl reboot command passing mode in wait mode\n* [`34ab0007a`](https://github.com/siderolabs/talos/commit/34ab0007a61bbb685d8c194c06568974db2a7375) docs: port is needed for wireguard endpoint\n* [`1e1aa84f6`](https://github.com/siderolabs/talos/commit/1e1aa84f6cdd0fbe6dd35841b6195cc56f10d333) fix: kubernetes removed resource version check\n* [`dcbcf5a93`](https://github.com/siderolabs/talos/commit/dcbcf5a93c3d82f8fdd7b8ffef3819010bd1c481) fix: wait for network and retry in platform get config funcs\n* [`3d7566ec7`](https://github.com/siderolabs/talos/commit/3d7566ec743f573a43a4a49ecb80f6ba59cbb27b) test: update Canal CNI manifest URL\n* [`e09e10666`](https://github.com/siderolabs/talos/commit/e09e106665aa8716f14ba49d527d8cb182592da7) fix: default dns domain to 'cluster.local' in local case\n* [`cc6e37a47`](https://github.com/siderolabs/talos/commit/cc6e37a47fd2ca9f1e43ce8ba2c1e8d8bfe44776) feat: use process wrapper for dropping capabilities\n* [`0c6c88874`](https://github.com/siderolabs/talos/commit/0c6c888745c5482fcf3891c922cc7cc7f72e6af4) fix: trackable action flag usage text. --no-wait does not exist\n* [`5cb2915d8`](https://github.com/siderolabs/talos/commit/5cb2915d8ea6e4ba913396abe3f45235e6a67213) feat: use wrapper for starting processes\n* [`56d945326`](https://github.com/siderolabs/talos/commit/56d9453261d47c0739be21cb7a5fe6beb25cb92c) fix: panic in talosctl cluster show\n* [`38a51191e`](https://github.com/siderolabs/talos/commit/38a51191e49059e93f4adfea479c039819a7f730) fix: correctly expand parameters in the URL\n* [`af21860a2`](https://github.com/siderolabs/talos/commit/af21860a22598361f68cf49e62a12da54bc95337) fix: return proper error if download attempts time out\n* [`54f7d4c92`](https://github.com/siderolabs/talos/commit/54f7d4c9231e858216f3b69b2662d7cc188df4f9) fix: correctly quote and unquote strings in GRUB config\n* [`54cf0672a`](https://github.com/siderolabs/talos/commit/54cf0672a71a8c9427c66bb2601521a9d24f8e13) fix: omit zero MTU in the machine config\n* [`bdc53ac25`](https://github.com/siderolabs/talos/commit/bdc53ac254a4aaa37ffd917c7c3ad506368205de) docs: add hyperlink to Docker API docs about `config.json`\n* [`b3bc06dd1`](https://github.com/siderolabs/talos/commit/b3bc06dd14c7faa75269cb6686b2d93ce765595c) chore: bump vtprotobuf to v0.4.0\n* [`0ba5e59f6`](https://github.com/siderolabs/talos/commit/0ba5e59f69c08ab566177df9e26a21648bcde54f) fix: drone config for renovate PR's\n* [`590a393de`](https://github.com/siderolabs/talos/commit/590a393de968556bb5e19594b2f057d4233c378d) fix: udevd healthcheck\n* [`2b6b6deac`](https://github.com/siderolabs/talos/commit/2b6b6deacda4a3cdf6c5b65ac586cad1363be094) docs: simplify and clarify digital ocean docs\n* [`92bc15f7f`](https://github.com/siderolabs/talos/commit/92bc15f7f1c561b1e7810371df23f84c7e0d6a1c) release(v1.4.0-alpha.1): prepare release\n* [`e3da4754e`](https://github.com/siderolabs/talos/commit/e3da4754e7a2e69b998b861034c6f77e2cf6355b) feat: update Linux to 6.1.7\n* [`006449e46`](https://github.com/siderolabs/talos/commit/006449e464ac009e15d78bb4d71cee80f2540f31) test: build integration test early in the pipeline\n* [`09aa71264`](https://github.com/siderolabs/talos/commit/09aa7126422b9b41e74c3d2aacb563daeca33bc5) fix: renovate config\n* [`2d136f187`](https://github.com/siderolabs/talos/commit/2d136f1879ee66dbd61ab40bb001a45c0bafaad5) feat: set markdown and html descriptions in config json schema\n* [`f0804027a`](https://github.com/siderolabs/talos/commit/f0804027a499a6e195f049144bff4f939dee3780) fix: renovate config\n* [`812a2877c`](https://github.com/siderolabs/talos/commit/812a2877cdc1e631ae0244f9696a65e2347594c0) chore: bump deps + renovate cleanup\n* [`aa9f66c1c`](https://github.com/siderolabs/talos/commit/aa9f66c1c88a1bb35aefe24ea0a5c3a6e7aa966d) fix: mark DigitalOcean anchor IP as scope link\n* [`bb4937f1b`](https://github.com/siderolabs/talos/commit/bb4937f1b339384fb486cb0cb675df8bf9b9f916) feat: enable renovate\n* [`3e0057162`](https://github.com/siderolabs/talos/commit/3e00571627568d8c5ab10a72e59207677a89e4cc) fix: unwrap gRPC errors on stop/remove pods check\n* [`00e52ae07`](https://github.com/siderolabs/talos/commit/00e52ae07867deff9a5877fcb498252bc1b1a740) fix: build correctly etcd initial cluster URL\n* [`ae83b10ae`](https://github.com/siderolabs/talos/commit/ae83b10ae89dbe600ddfaa338be95ea819546007) feat: create JSON schema for v1alpha1.Config\n* [`703d96595`](https://github.com/siderolabs/talos/commit/703d9659512d744a606e520faf230e20efddfc4a) feat: update Kubernetes to 1.26.1, etcd to 3.5.7\n* [`965e64591`](https://github.com/siderolabs/talos/commit/965e645915d080487a74b35dc8f1d2e4051f0504) docs: update to use talosctl install script\n* [`c5954f434`](https://github.com/siderolabs/talos/commit/c5954f4345cbf3a92c777a0e7fc5d39e883609bf) chore: bump deps\n* [`bb50f6a56`](https://github.com/siderolabs/talos/commit/bb50f6a56d971915abb6a895aac9d7e0612a3255) chore: preallocate disk images for QEMU VMs\n* [`d4b8b35de`](https://github.com/siderolabs/talos/commit/d4b8b35de7849d887c41f9a13dadb59ccd8c08c4) feat: generate kernel module dependency tree\n* [`18122ae73`](https://github.com/siderolabs/talos/commit/18122ae73e0489a0497956c6d4621c05c6a77387) fix: service restart (including extension services)\n* [`680fd5e45`](https://github.com/siderolabs/talos/commit/680fd5e452e02b108b7938d0136079c16e6cfd79) fix: bump COSI runtime with the panic controller restart fix\n* [`0b65bbfc8`](https://github.com/siderolabs/talos/commit/0b65bbfc878fe2a5c01c5d2cd08006b53fda7cf9) fix: handle overwriting tags in syslinux ADV\n* [`70d9428a1`](https://github.com/siderolabs/talos/commit/70d9428a1d00d9894d68f38b255debb66fe8a440) fix: kubespan MSS clamping\n* [`683b4ccb4`](https://github.com/siderolabs/talos/commit/683b4ccb4faab6c3da2de00f7314773f42899c25) chore: update Go to 1.19.5 and kernel to 6.1.4\n* [`062c7d754`](https://github.com/siderolabs/talos/commit/062c7d754be1714c7763b8f2b399436d64c90ea4) test: fix integration test on cp endpoint update\n* [`8e9fc13d7`](https://github.com/siderolabs/talos/commit/8e9fc13d7c48da5c5354501e0ad96688670438cf) feat: implement enum generator for proto files\n* [`771b0dc06`](https://github.com/siderolabs/talos/commit/771b0dc061e0fa33085b28bd0d0a7e4da13081f1) docs: update left over rpi_4 ref to rpi_generic\n* [`6c04b5f79`](https://github.com/siderolabs/talos/commit/6c04b5f79e6e01e0a3cdabfc99f12c944edd1f0a) chore: bump dependencies\n* [`0a5a8802e`](https://github.com/siderolabs/talos/commit/0a5a8802e7e337e1f30a40c9f566e57642c39c1a) feat: use 'localhost' endpoint for controlplane nodes\n* [`b0775ebf2`](https://github.com/siderolabs/talos/commit/b0775ebf2c776c7133cf74c6259de9dc9573786c) feat: add ISO wipe GRUB boot option\n* [`29020cb9c`](https://github.com/siderolabs/talos/commit/29020cb9c788d87a0457028ce73c8d297959116e) fix: report fatal sequence errors as reboots\n* [`96629d5ba`](https://github.com/siderolabs/talos/commit/96629d5ba6c1ae9d820824fb38f68112bce27f2c) feat: implement etcd maintenance commands\n* [`80fed3194`](https://github.com/siderolabs/talos/commit/80fed319408be9e493141fb2c01e5731708835c7) feat: include Kubernetes controlplane endpoint as one of the endpoints\n* [`c6cb36cc1`](https://github.com/siderolabs/talos/commit/c6cb36cc1f50b5d0e59a5284867e7534dc9f73bb) docs: fix auditpolicy example typo\n* [`ba8265bc5`](https://github.com/siderolabs/talos/commit/ba8265bc5ce63bcbc6fbd6c1a1076dc3f2ee6bd0) feat: new talosctl config remove to remove context\n* [`fcb19ff51`](https://github.com/siderolabs/talos/commit/fcb19ff516cc1200ec81f2a954bb6d2ce39ebdc6) fix: implement upgrade version checks for Talos 1.4\n* [`80f150ac8`](https://github.com/siderolabs/talos/commit/80f150ac859f5dbf95060c12440afab8c0bc77a8) feat: enable ipv6 on gcp\n* [`8db622f3d`](https://github.com/siderolabs/talos/commit/8db622f3dc75aed90dd2d0bd92d03aa7e8aefd10) docs: add Vandebron to adopters list\n* [`f6a86ae90`](https://github.com/siderolabs/talos/commit/f6a86ae90607914c29875df750fe79cbbfcc5897) fix: oralce cloud zone\n* [`89dbb0ecf`](https://github.com/siderolabs/talos/commit/89dbb0ecf089bb746479238df274ccba4fcb049a) release(v1.4.0-alpha.0): prepare release\n* [`31fb90535`](https://github.com/siderolabs/talos/commit/31fb9053582190b3b536a309c30e2b78c4611885) feat: update Linux 6.1.1, containerd 1.6.14\n* [`a0c0352dd`](https://github.com/siderolabs/talos/commit/a0c0352ddca253e1efb3679224b317692d46b2fd) fix: send diagnostic output to stderr consistently\n* [`9a5f4c08a`](https://github.com/siderolabs/talos/commit/9a5f4c08a206504a1d30277dcc0597333e5a927a) fix: default the manifest namespace if not set\n* [`3c6cce5fe`](https://github.com/siderolabs/talos/commit/3c6cce5fe47075f43a73682b57a7b40fa0899795) docs: update last release for Talos 1.2.x\n* [`703624c43`](https://github.com/siderolabs/talos/commit/703624c43dd8e58c147ccbc3989c6c436c9f3a7f) docs: fix the 1.3 release date\n* [`386c9293a`](https://github.com/siderolabs/talos/commit/386c9293a33e9d237fbeda0492b01b11fdadc501) docs: update nvidia-container-runtime version\n* [`ff83d9fd7`](https://github.com/siderolabs/talos/commit/ff83d9fd7bed2e04d5c8107713150c2513f47991) fix: improve talosctl completion\n* [`31ff431fa`](https://github.com/siderolabs/talos/commit/31ff431faec22c09cad88d565102e6a24785ecb4) chore: add schulz systemtechnik to the list\n* [`97bef7c47`](https://github.com/siderolabs/talos/commit/97bef7c47bfd133f2b3ad19efe3f30a88dd67460) docs: vsphere.sh > vmware.sh\n* [`34babe858`](https://github.com/siderolabs/talos/commit/34babe858d15145a1c596febb5e577473e4ffce0) chore: make organization selection an interface\n* [`a9643b477`](https://github.com/siderolabs/talos/commit/a9643b477417029db73aacbfcf5778cedd97cd95) fix: use proper key usage for apid client certificate\n* [`171aa9467`](https://github.com/siderolabs/talos/commit/171aa9467966f5869e72374961ea05abc8d9fda9) fix: disable Wireless Lan using dtoverlay\n* [`2e84d2ab3`](https://github.com/siderolabs/talos/commit/2e84d2ab3417515f539a70d58885dcb69e9f098c) chore: update conformance product.yaml\n* [`b7763843a`](https://github.com/siderolabs/talos/commit/b7763843af63bbc186f08701a62c19ea96fb7e3c) feat: add install script that improves talosctl installation user experience This install script detects the platform and architecture, and downloads the correct talosctl, and checks the gpg checksums. It also installs and chmods the binary.\n* [`afc45ad63`](https://github.com/siderolabs/talos/commit/afc45ad632e63cc3afc095b1f3efe6df3ecb9cb1) docs: mark Talos 1.3 docs as default\n* [`873bd3807`](https://github.com/siderolabs/talos/commit/873bd3807c0fcca2e212deb7fd044662557964c1) fix: redact service account key in config in RedactSecrets method\n* [`b3aebfadf`](https://github.com/siderolabs/talos/commit/b3aebfadfc15544e5ab448d979129dba5e516c59) feat: validate Talos API access roles in machine config\n* [`40761e17d`](https://github.com/siderolabs/talos/commit/40761e17db5789f30eef2f15f0b5c6396e09a9e5) docs: fork docs for Talos 1.4\n* [`474604cd2`](https://github.com/siderolabs/talos/commit/474604cd279def7a6798e24ede27feef955ba5a3) docs: update documentation for Talos 1.3\n* [`faf49218c`](https://github.com/siderolabs/talos/commit/faf49218ce14a48829dae7b3b8d7801188453a89) feat: add more checks for K8s upgrade\n* [`5b992bd86`](https://github.com/siderolabs/talos/commit/5b992bd8610f41d23d8b7dbd01f9a1be298eda96) fix: allow empty dnsDomain in machine config\n* [`eb332cfcb`](https://github.com/siderolabs/talos/commit/eb332cfcb785e250c422d6a7ea2b23679189a946) feat: add health check for a minimal memory / disk size\n* [`d04970dfa`](https://github.com/siderolabs/talos/commit/d04970dfa9d6554e1ee447fd9383bf65b8953671) fix: ignore k8s additional addresses if nil\n* [`63c17104c`](https://github.com/siderolabs/talos/commit/63c17104c594dfd9ca4066ba41d8a03507464874) feat: update Kubernets to 1.26.0\n* [`f7a9a90db`](https://github.com/siderolabs/talos/commit/f7a9a90db2bfd316ea01551daba9becb15361f94) chore: update pkgs/tools (Go 1.19.4, containerd 1.6.11)\n* [`cf7adc51c`](https://github.com/siderolabs/talos/commit/cf7adc51c9f53234e469dd9f0cca06eed0230e8b) feat: add RedactSecrets method to v1alpha1.Config\n* [`4c31b9b1a`](https://github.com/siderolabs/talos/commit/4c31b9b1a3a00df0fe817c3edc15260ca3cadd6d) docs: clarify what the deal is with /var\n* [`a8ebcca4a`](https://github.com/siderolabs/talos/commit/a8ebcca4a9f63643f68d8e85bcb0b9ddb49205ed) chore: remove `watchErr` from `metal.getResource`\n* [`1253513bd`](https://github.com/siderolabs/talos/commit/1253513bd1deecc4cc42330bad0a713b3630240a) fix: fix nil pointer panic and incorrect error output\n* [`82e8c9e1f`](https://github.com/siderolabs/talos/commit/82e8c9e1f63371f41b0794b4c1be3209847c5f8b) fix: workaround panic in the kubelet service controller\n* [`a505b8909`](https://github.com/siderolabs/talos/commit/a505b8909a1c733b30f22a8d46eebc022475431a) fix: update COSI and reset restart backoff on success\n* [`e92fdcbad`](https://github.com/siderolabs/talos/commit/e92fdcbad1de595d119f78dbed3a97ae46df9bbf) chore: bump kernel to 5.15.81\n* [`f0dddca2a`](https://github.com/siderolabs/talos/commit/f0dddca2a3d2e976cee543ab57816a6395fe3d65) docs: expand help for 'talosctl get'\n* [`fcffc8879`](https://github.com/siderolabs/talos/commit/fcffc88790b5a3006b3b85744771a7eef6e8ac5c) fix: add ext4 filesystem detection\n* [`5b2960eff`](https://github.com/siderolabs/talos/commit/5b2960efff8b38af85b687a25fa93f01256016de) fix: introduce 'overridePath' setting and fix Talos resolver\n* [`0219d1124`](https://github.com/siderolabs/talos/commit/0219d1124e5125696364bf92ecf0e8dcad644001) fix: use only kube-apiserver endpoints for Talos API access endpoints\n* [`dc5e0f4af`](https://github.com/siderolabs/talos/commit/dc5e0f4af087d3b662b0240b4f8fd76379ed0de2) fix: report errors to Equinix Metal event API\n* [`7ab140a94`](https://github.com/siderolabs/talos/commit/7ab140a94ad1a279be43669d6d70687f3a0c47de) feat: add talosctl machineconfig patch command\n* [`d3cf06114`](https://github.com/siderolabs/talos/commit/d3cf061149a4a502317d7728c45b6cfb4d38f89f) fix: ignore many more filesystems in IMA\n* [`44e2799b8`](https://github.com/siderolabs/talos/commit/44e2799b8cb928083f3a777d5cce45ad8dbf6864) feat: add stdout and single config type support to talosctl gen config\n* [`4452f0e17`](https://github.com/siderolabs/talos/commit/4452f0e179db16c59dc65ccdb5a496ad3306684e) docs: bump talos version\n* [`38e57bd12`](https://github.com/siderolabs/talos/commit/38e57bd12b8c50d668fcde6ee9aa493682778dcc) feat: update Kubernetes to v1.26.0-rc.1\n* [`4cd125d49`](https://github.com/siderolabs/talos/commit/4cd125d499a24798dfde1dddf6fa1c689d16c93f) fix: correctly handle new watch event types\n* [`881b84152`](https://github.com/siderolabs/talos/commit/881b84152084d157fbd4ff992089a5392aadfd3c) feat: update Flannel to 0.20.2\n</p>\n</details>\n\n### Changes since v1.4.0-alpha.1\n<details><summary>46 commits</summary>\n<p>\n\n* [`b52071081`](https://github.com/siderolabs/talos/commit/b5207108104eda426361c256ec4d78ae9e0b2890) feat: introduce new flag in reset API that makes Talos reset user disks\n* [`f55f5df73`](https://github.com/siderolabs/talos/commit/f55f5df7396b7073e75267c7e10a35814f1185c9) feat: move dashboard package & run it in tty2\n* [`36e077ead`](https://github.com/siderolabs/talos/commit/36e077ead458f15e864f62eeb0d7afa59187c226) chore: bump deps\n* [`5a01d5fd4`](https://github.com/siderolabs/talos/commit/5a01d5fd473cdc4e0b9fba48047d6434cf31ee42) chore: run extension build as downstream\n* [`426fe9687`](https://github.com/siderolabs/talos/commit/426fe9687d74690df26ce3cfd6aee47c13e994a8) fix: extension base folder permission\n* [`609d3a8a6`](https://github.com/siderolabs/talos/commit/609d3a8a694ff90426ce33be86791f2616ec4852) feat: support strategic merge patches on VLAN configuration\n* [`7e19f32d7`](https://github.com/siderolabs/talos/commit/7e19f32d762dc1363f29e988ddbe334bd00610f2) chore: provide version compatibility data for Talos 1.2.x\n* [`230e46e56`](https://github.com/siderolabs/talos/commit/230e46e567012d8e12e384c777d6f57db5e7cfee) refactor: extract parts of kubernetes libraries\n* [`f3d3f0f26`](https://github.com/siderolabs/talos/commit/f3d3f0f2625f1be41a17366ee1c0bd2a3193c08c) fix: update go-smbios library with Hyper-V data fix\n* [`8711eea96`](https://github.com/siderolabs/talos/commit/8711eea9626a60a996347aaa7e6a89eea87d4b9e) fix: use passed `--context` in `talosctl config` cmd\n* [`5ac9f43e4`](https://github.com/siderolabs/talos/commit/5ac9f43e45f85f8d37c2855051b9a5cc9ad389ac) feat: start machined earlier & in maintenance mode\n* [`36ab414a1`](https://github.com/siderolabs/talos/commit/36ab414a1d7c5472522d20a7b698c4eebb3423b9) docs: fix the endpoints in the libvirt guide\n* [`3d55bd80f`](https://github.com/siderolabs/talos/commit/3d55bd80f42b7d2439541909c9534c386607e578) fix: add `--force` flag to `talosctl gen config`\n* [`660b8874d`](https://github.com/siderolabs/talos/commit/660b8874da7bd91946aab5f400e7d1dfddefb827) feat: cmdline integer netmask\n* [`1e3daacc4`](https://github.com/siderolabs/talos/commit/1e3daacc48c0b8ef2eab41b2c2c53f55522e1acf) docs: update nvidia component versions\n* [`b5c03a7fa`](https://github.com/siderolabs/talos/commit/b5c03a7fab8d213e7048a8f5fc129125b81eb205) fix: docker talosctl cluster create provisioner\n* [`6e8f13529`](https://github.com/siderolabs/talos/commit/6e8f13529c17ff4c658b340d16d9ee429cfd9a4c) fix: add support for a fallback '*' mirror configuration\n* [`dcd4eb1a9`](https://github.com/siderolabs/talos/commit/dcd4eb1a93737d60f60693d8c33a20052eee4a4f) fix: improve error message on single node upgrade\n* [`ed5af3f78`](https://github.com/siderolabs/talos/commit/ed5af3f780732fb0004ddb263feedbf2de9fd09a) chore: bump deps\n* [`0dc6858e5`](https://github.com/siderolabs/talos/commit/0dc6858e5ba4b110eac9ca74294eb3a29790a323) chore: bump cosi-project/runtime\n* [`da2edb9de`](https://github.com/siderolabs/talos/commit/da2edb9de067fc21c792e948903bc2c880b2c2d1) chore: bump dependencies\n* [`e51a110f0`](https://github.com/siderolabs/talos/commit/e51a110f0e876fc091aee0828aca0135499def9c) chore: bump dependencies\n* [`2d0148018`](https://github.com/siderolabs/talos/commit/2d014801803fa0d5f08a344bdc9ff078b3931633) feat: automatically load modules based on hw info\n* [`7b75cd8b9`](https://github.com/siderolabs/talos/commit/7b75cd8b94367645adb2dd5be016e6f98d8e6a89) fix: kernel module dependency tree generation\n* [`65d02e5ad`](https://github.com/siderolabs/talos/commit/65d02e5ade08354aeec794d4131a1f8913fba2b5) fix: dbus shutdown when it's not initialized\n* [`a7079ce85`](https://github.com/siderolabs/talos/commit/a7079ce85c9839933544b637100f104f02fd3f3a) fix: quote the ampersand character in GRUB config\n* [`933ba2d82`](https://github.com/siderolabs/talos/commit/933ba2d8203e4418414b3de1c4240c1f88cb033e) fix: display correct blockdevice size\n* [`c449cb736`](https://github.com/siderolabs/talos/commit/c449cb736b24b268b965da5e2932f18bd4fb7785) fix: talosctl reboot command passing mode in wait mode\n* [`34ab0007a`](https://github.com/siderolabs/talos/commit/34ab0007a61bbb685d8c194c06568974db2a7375) docs: port is needed for wireguard endpoint\n* [`1e1aa84f6`](https://github.com/siderolabs/talos/commit/1e1aa84f6cdd0fbe6dd35841b6195cc56f10d333) fix: kubernetes removed resource version check\n* [`dcbcf5a93`](https://github.com/siderolabs/talos/commit/dcbcf5a93c3d82f8fdd7b8ffef3819010bd1c481) fix: wait for network and retry in platform get config funcs\n* [`3d7566ec7`](https://github.com/siderolabs/talos/commit/3d7566ec743f573a43a4a49ecb80f6ba59cbb27b) test: update Canal CNI manifest URL\n* [`e09e10666`](https://github.com/siderolabs/talos/commit/e09e106665aa8716f14ba49d527d8cb182592da7) fix: default dns domain to 'cluster.local' in local case\n* [`cc6e37a47`](https://github.com/siderolabs/talos/commit/cc6e37a47fd2ca9f1e43ce8ba2c1e8d8bfe44776) feat: use process wrapper for dropping capabilities\n* [`0c6c88874`](https://github.com/siderolabs/talos/commit/0c6c888745c5482fcf3891c922cc7cc7f72e6af4) fix: trackable action flag usage text. --no-wait does not exist\n* [`5cb2915d8`](https://github.com/siderolabs/talos/commit/5cb2915d8ea6e4ba913396abe3f45235e6a67213) feat: use wrapper for starting processes\n* [`56d945326`](https://github.com/siderolabs/talos/commit/56d9453261d47c0739be21cb7a5fe6beb25cb92c) fix: panic in talosctl cluster show\n* [`38a51191e`](https://github.com/siderolabs/talos/commit/38a51191e49059e93f4adfea479c039819a7f730) fix: correctly expand parameters in the URL\n* [`af21860a2`](https://github.com/siderolabs/talos/commit/af21860a22598361f68cf49e62a12da54bc95337) fix: return proper error if download attempts time out\n* [`54f7d4c92`](https://github.com/siderolabs/talos/commit/54f7d4c9231e858216f3b69b2662d7cc188df4f9) fix: correctly quote and unquote strings in GRUB config\n* [`54cf0672a`](https://github.com/siderolabs/talos/commit/54cf0672a71a8c9427c66bb2601521a9d24f8e13) fix: omit zero MTU in the machine config\n* [`bdc53ac25`](https://github.com/siderolabs/talos/commit/bdc53ac254a4aaa37ffd917c7c3ad506368205de) docs: add hyperlink to Docker API docs about `config.json`\n* [`b3bc06dd1`](https://github.com/siderolabs/talos/commit/b3bc06dd14c7faa75269cb6686b2d93ce765595c) chore: bump vtprotobuf to v0.4.0\n* [`0ba5e59f6`](https://github.com/siderolabs/talos/commit/0ba5e59f69c08ab566177df9e26a21648bcde54f) fix: drone config for renovate PR's\n* [`590a393de`](https://github.com/siderolabs/talos/commit/590a393de968556bb5e19594b2f057d4233c378d) fix: udevd healthcheck\n* [`2b6b6deac`](https://github.com/siderolabs/talos/commit/2b6b6deacda4a3cdf6c5b65ac586cad1363be094) docs: simplify and clarify digital ocean docs\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>1 commit</summary>\n<p>\n\n* [`ac75538`](https://github.com/siderolabs/discovery-api/commit/ac75538ee3a9f7b71b6619f509d95ff5057f6754) chore: regen the proto definitions with vtprotobuf v0.4.0\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`269a832`](https://github.com/siderolabs/discovery-client/commit/269a832ce9e35d4edeeddba2a23cf5682a2ca425) chore: rekres, update discovery api\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>6 commits</summary>\n<p>\n\n* [`8b28b6b`](https://github.com/siderolabs/extras/commit/8b28b6b5a0153c65af596086016faea9d64e95c2) chore: bump deps\n* [`5ab4f59`](https://github.com/siderolabs/extras/commit/5ab4f5939c830c7043e3939e519305eb810cdfc2) chore: disable renovate builds\n* [`ddeddbd`](https://github.com/siderolabs/extras/commit/ddeddbd1976813de6b1563f662ca4f2b3f5e0f53) chore: update packages, tc_redirect_tap\n* [`8cb4792`](https://github.com/siderolabs/extras/commit/8cb4792da9b9e2b2663daca747d24c3b5c973e0f) chore: update Go to 1.19.5\n* [`3ca2df3`](https://github.com/siderolabs/extras/commit/3ca2df3ead2a64a5ad30c350b87bfe02bf1f49c7) chore: disable provenance in buildx\n* [`55d8452`](https://github.com/siderolabs/extras/commit/55d845241c8456909ab36f9b0f4e26cc2b49c256) feat: update releases\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`214c1ef`](https://github.com/siderolabs/gen/commit/214c1efe795cf426e5ebcc48cb305bfc7a16fdb8) chore: set `slice.Filter` result slice cap to len\n* [`8e89b1e`](https://github.com/siderolabs/gen/commit/8e89b1ede9f35ff4c18a41ee44a69259181c892b) feat: add GetOrCreate and GetOrCall methods\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`8c7ea19`](https://github.com/siderolabs/go-blockdevice/commit/8c7ea1910b27e0660e3e1a6f98b9f7e24bc11ff0) fix: blockdevice size is reported by Linux in 512 blocks always\n</p>\n</details>\n\n### Changes from siderolabs/go-kubernetes\n<details><summary>2 commits</summary>\n<p>\n\n* [`570819b`](https://github.com/siderolabs/go-kubernetes/commit/570819b93ecc63218b3db8d90e4810765a069ee0) feat: initial version of the library\n* [`fb79215`](https://github.com/siderolabs/go-kubernetes/commit/fb7921556e96fc7c0a84ac23834350bcd37cfa38) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`c526764`](https://github.com/siderolabs/go-smbios/commit/c5267640be317efd9cbbe936ab78b2a49c757edf) feat: fix reading \"broken\" Hyper-V DMI data\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>30 commits</summary>\n<p>\n\n* [`5dbce6b`](https://github.com/siderolabs/pkgs/commit/5dbce6b19ff6a1e1b5ae88468e34925c3d30d627) fix: xz url\n* [`0097233`](https://github.com/siderolabs/pkgs/commit/00972336c3fcc22df8fc1d3774c35b26fdc957b9) chore: re-enable drbd\n* [`7493721`](https://github.com/siderolabs/pkgs/commit/749372110c6c8e226139cd662832b5a4169db894) fix: sourcefourge url shasums\n* [`185f482`](https://github.com/siderolabs/pkgs/commit/185f482db6a5c13a3b14feec02a4e361b53bec55) feat: update containerd to 1.6.18\n* [`e3cab6c`](https://github.com/siderolabs/pkgs/commit/e3cab6cbd62b96143958ed5e0219d68107a5f583) chore: bump deps\n* [`18661b0`](https://github.com/siderolabs/pkgs/commit/18661b096559e673152ce0fed45ab74ef3305dff) chore: bump deps\n* [`885a68b`](https://github.com/siderolabs/pkgs/commit/885a68b6280f3bf4ff75508ccceef73158c53560) chore: bump deps\n* [`c3a6e18`](https://github.com/siderolabs/pkgs/commit/c3a6e185178d7571e891c7b2614bf6017ab5c913) chore: bump dependencies\n* [`1fae0b2`](https://github.com/siderolabs/pkgs/commit/1fae0b229a625d692d36e7d6c096f8476e0f56d7) feat: virtio drivers as modules\n* [`61d8ff4`](https://github.com/siderolabs/pkgs/commit/61d8ff4aaea93b86b82bc2a36a2bbd6d54da3bb8) chore: bump deps and disable un-needed kconfig\n* [`15fe6d8`](https://github.com/siderolabs/pkgs/commit/15fe6d8555b42e55f920a5576ad55504e356995b) fix: kernel module tree files missing\n* [`987d24a`](https://github.com/siderolabs/pkgs/commit/987d24aeaa4fb2278954cd96e6bc6a29a4c8dd61) feat: mellanox drivers are modules\n* [`b82a015`](https://github.com/siderolabs/pkgs/commit/b82a015c78c407d17d23542eba6a4114f3c2c4d7) feat: mellanox oped\n* [`057d4f9`](https://github.com/siderolabs/pkgs/commit/057d4f96aa3ba63cc456b06a70a6b3a008cf803f) chore: bump deps\n* [`4ac4138`](https://github.com/siderolabs/pkgs/commit/4ac4138c6b94622646c9f32f0885496c5475d905) feat: enable nvme support for raspberrypi cm4\n* [`ccb9d39`](https://github.com/siderolabs/pkgs/commit/ccb9d39dc43cf53431a0d7609839ed9c7141972d) fix: disable magic sysrq\n* [`d33202d`](https://github.com/siderolabs/pkgs/commit/d33202d99daa6ccf136fca54ebbadda727a43a75) chore: bump u-boot to 2023.01\n* [`cb83e16`](https://github.com/siderolabs/pkgs/commit/cb83e169df4a2020994a63e5be61524461ef93e3) chore: bump dependencies\n* [`e561dcb`](https://github.com/siderolabs/pkgs/commit/e561dcb45beae80161faccedb0303e58d41b1ded) feat: bump Go to 1.19.5\n* [`c7797c7`](https://github.com/siderolabs/pkgs/commit/c7797c77bd311449e1f116980166d8d818102f4f) feat: update Linux to 6.1.4, restore RPi support\n* [`5e8ebb0`](https://github.com/siderolabs/pkgs/commit/5e8ebb073d9b58555a75912cd90490af8a435c7d) feat: add AMD K10 sensor support\n* [`73ac37d`](https://github.com/siderolabs/pkgs/commit/73ac37d683274e60340d2767f2b8201e7f13474c) chore: disable provenance in buildx\n* [`8965bee`](https://github.com/siderolabs/pkgs/commit/8965bee65313539e8b6534073d06341f4fb78586) chore: use default symlinks to `/bin` in `base`\n* [`325c9bf`](https://github.com/siderolabs/pkgs/commit/325c9bf0f3ed2bf7603d1eaea022ea650388cf2b) feat: bump dependencies\n* [`165dff6`](https://github.com/siderolabs/pkgs/commit/165dff6c3cdb2d05f170c8ae0616d9224416455e) fix: patch ipmitool IANA URL\n* [`c542f39`](https://github.com/siderolabs/pkgs/commit/c542f398a150567d5cdffc17b4248be5416fe242) feat: add kernel support for usb setrial console\n* [`f564f45`](https://github.com/siderolabs/pkgs/commit/f564f45645d102b7e3a9563ac7bdb1e816156e65) chore: bump tools, containerd\n* [`268ea7c`](https://github.com/siderolabs/pkgs/commit/268ea7c593ff04c4e4a9ea5676b3c58d41cbff14) chore: bump deps\n* [`dcf3ceb`](https://github.com/siderolabs/pkgs/commit/dcf3cebf283698e010aaac5417d91a7385dc2441) feat: add nitro enclave support in kernel\n* [`17ea5e6`](https://github.com/siderolabs/pkgs/commit/17ea5e680b2438c59fa1773e8b58d6b749cb0d34) chore: bump kernel to 5.15.81\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>20 commits</summary>\n<p>\n\n* [`cd9687b`](https://github.com/siderolabs/tools/commit/cd9687b4323b20493b4d582cfaa48c321cd04288) fix: renovate config\n* [`977e3fc`](https://github.com/siderolabs/tools/commit/977e3fcba92d129eb78cb77300f38428f860b34d) chore: bump go to 1.20.1\n* [`15748aa`](https://github.com/siderolabs/tools/commit/15748aa32d7c1d67b190ab7a27ace9922c8d6b56) chore: bump deps\n* [`d4b719a`](https://github.com/siderolabs/tools/commit/d4b719a1c2055eaa27f80422f93755b0de9ca3f8) chore: bump deps\n* [`8c36dbd`](https://github.com/siderolabs/tools/commit/8c36dbd05ee27ecc2a7340462a3b49efb7327184) chore: bump toolchain, bump protoc-gen-go-grpc\n* [`a62e365`](https://github.com/siderolabs/tools/commit/a62e365b223e7ca9d2728865b40b23115764a0ed) feat: update Go to 1.20\n* [`28d4a57`](https://github.com/siderolabs/tools/commit/28d4a5721ce1c57fc3f643185386d5c4b5c7e39a) chore: reduce renovate noise\n* [`e130fd5`](https://github.com/siderolabs/tools/commit/e130fd5b9835d8cc178ec53d5a89dfc6cc2ce7a1) chore: bump deps\n* [`37612fe`](https://github.com/siderolabs/tools/commit/37612feb7222b943a84f1f98d0901a204d491926) fix: revert enabling provenance\n* [`e0b01e3`](https://github.com/siderolabs/tools/commit/e0b01e3b7420e8b0b1e0d9077515e007a6b83b56) chore: bump deps\n* [`d0e6bd0`](https://github.com/siderolabs/tools/commit/d0e6bd06fcfcadc330cf30339488536961f9f70e) feat: add gnutls\n* [`3d34b5d`](https://github.com/siderolabs/tools/commit/3d34b5d401a67048d365e8faf2f1edf293887a97) chore: bump dependencies\n* [`763c1d9`](https://github.com/siderolabs/tools/commit/763c1d927822517b3d63c624302e11e8e5a49f5b) feat: update Go to 1.19.5\n* [`136958f`](https://github.com/siderolabs/tools/commit/136958f9f8c8cfc439228dec31b840549bca4374) chore: disable provenance in buildx\n* [`e2a8692`](https://github.com/siderolabs/tools/commit/e2a869294be7e77e295ca651400f85551fb7e665) feat: update releases\n* [`0e48f37`](https://github.com/siderolabs/tools/commit/0e48f37496a79ce4997d15fefb6300b2324f5668) chore: bump protobuf\n* [`a21aa1c`](https://github.com/siderolabs/tools/commit/a21aa1c583a10d017ace8da14c6f604f86ce5709) chore: bump toolchain and mpc versions\n* [`1a75d0f`](https://github.com/siderolabs/tools/commit/1a75d0f6796c4abf1c9a23cfe697d3e38a9ce587) chore: bump deps\n* [`55bd185`](https://github.com/siderolabs/tools/commit/55bd18532667e325e8938bf0a72cab40a936eadf) feat: update Go to 1.19.4\n* [`f291f46`](https://github.com/siderolabs/tools/commit/f291f46e84ec02f5d22718f7ecb476a3f815ae45) chore: bump tools\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**           v0.2.1 -> v0.2.3\n* **github.com/aws/aws-sdk-go**                      v1.44.147 -> v1.44.209\n* **github.com/containerd/cgroups**                  v1.0.4 -> v1.1.0\n* **github.com/containerd/containerd**               v1.6.12 -> v1.6.18\n* **github.com/containernetworking/plugins**         v1.1.1 -> v1.2.0\n* **github.com/coreos/go-semver**                    v0.3.0 -> v0.3.1\n* **github.com/cosi-project/runtime**                v0.2.0 -> v0.3.0-alpha.7\n* **github.com/docker/docker**                       v20.10.21 -> v23.0.1\n* **github.com/dustin/go-humanize**                  v1.0.0 -> v1.0.1\n* **github.com/emicklei/dot**                        v1.2.0 -> v1.3.1\n* **github.com/fatih/color**                         v1.13.0 -> v1.14.1\n* **github.com/freddierice/go-losetup/v2**           v2.0.1 **_new_**\n* **github.com/gdamore/tcell/v2**                    v2.5.3 -> v2.6.0\n* **github.com/hashicorp/go-getter**                 v1.6.2 -> v1.7.0\n* **github.com/hetznercloud/hcloud-go**              v1.37.0 -> v1.40.0\n* **github.com/insomniacslk/dhcp**                   f26e6d78f622 -> 5369909a5de7\n* **github.com/jsimonetti/rtnetlink**                v1.3.0 -> v1.3.1\n* **github.com/mattn/go-isatty**                     v0.0.16 -> v0.0.17\n* **github.com/mdlayher/ethtool**                    0e16326d06d1 -> ba3b4bc2e02c\n* **github.com/mdlayher/genetlink**                  v1.3.0 -> v1.3.1\n* **github.com/mdlayher/netlink**                    v1.7.0 -> v1.7.1\n* **github.com/prometheus/procfs**                   v0.8.0 -> v0.9.0\n* **github.com/rivo/tview**                          db36428c92d9 -> 47e7db7885b4\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.10 -> v1.0.0-beta.13\n* **github.com/siderolabs/discovery-api**            v0.1.1 -> v0.1.2\n* **github.com/siderolabs/discovery-client**         v0.1.3 -> v0.1.4\n* **github.com/siderolabs/extras**                   v1.3.0-1-g3773d71 -> v1.4.0-alpha.0-5-g8b28b6b\n* **github.com/siderolabs/gen**                      v0.4.1 -> v0.4.3\n* **github.com/siderolabs/go-blockdevice**           v0.4.2 -> v0.4.3\n* **github.com/siderolabs/go-kubernetes**            v0.1.0 **_new_**\n* **github.com/siderolabs/go-smbios**                v0.3.1 -> v0.3.2\n* **github.com/siderolabs/pkgs**                     v1.3.0-5-g6509d23 -> v1.4.0-alpha.0-29-g5dbce6b\n* **github.com/siderolabs/talos/pkg/machinery**      v1.3.0 -> v1.4.0-alpha.1\n* **github.com/siderolabs/tools**                    v1.3.0-1-g712379c -> v1.4.0-alpha.0-17-gcd9687b\n* **github.com/stretchr/testify**                    v1.8.1 -> v1.8.2\n* **github.com/u-root/u-root**                       v0.10.0 -> v0.11.0\n* **github.com/ulikunitz/xz**                        v0.5.11 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.12 -> v0.56.15\n* **github.com/vmware/govmomi**                      v0.29.0 -> v0.30.2\n* **go.etcd.io/etcd/api/v3**                         v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/v3**                      v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.6 -> v3.5.7\n* **go.uber.org/zap**                                v1.23.0 -> v1.24.0\n* **go4.org/netipx**                                 797b0c90d8ab -> 8449b0a6169f\n* **golang.org/x/net**                               v0.4.0 -> v0.7.0\n* **golang.org/x/sys**                               v0.3.0 -> v0.5.0\n* **golang.org/x/term**                              v0.3.0 -> v0.5.0\n* **golang.org/x/time**                              v0.2.0 -> v0.3.0\n* **golang.zx2c4.com/wireguard/wgctrl**              97bc4ad4a1cb -> 9c5414ab4bde\n* **google.golang.org/grpc**                         v1.51.0 -> v1.53.0\n* **k8s.io/api**                                     v0.26.0 -> v0.26.1\n* **k8s.io/apimachinery**                            v0.26.0 -> v0.26.1\n* **k8s.io/apiserver**                               v0.26.0 -> v0.26.1\n* **k8s.io/client-go**                               v0.26.0 -> v0.26.1\n* **k8s.io/component-base**                          v0.26.0 -> v0.26.1\n* **k8s.io/klog/v2**                                 v2.80.1 -> v2.90.0\n* **k8s.io/kubectl**                                 v0.26.0 -> v0.26.1\n* **k8s.io/kubelet**                                 v0.26.0 -> v0.26.1\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.66 -> v1.2.67\n\nPrevious release can be found at [v1.3.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0)\n\n## [Talos 1.4.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.4.0-alpha.1) (2023-01-25)\n\nWelcome to the v1.4.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### etcd Maintenance\n\nTalos adds new APIs to make it easier to perform etcd maintenance operations.\n\nThese APIs are available via new `talosctl etcd` sub-commands:\n\n* `talosctl etcd alarm list|disarm`\n* `talosctl etcd defrag`\n* `talosctl etcd status`\n\nSee also [etcd maintenance guide](https://talos.dev/v1.4/advanced/etcd-maintenance/).\n\n\n### Component Updates\n\n* Linux: 6.1.7\n* containerd: v1.6.15\n* Kubernetes: v1.26.1\n* etcd: v3.5.7\n\nTalos is built with Go 1.19.5.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Dmitriy Matrenichev\n* Utku Ozdemir\n* Serge Logvinov\n* Spencer Smith\n* Steve Francis\n* Cees-Jan Kiewiet\n* Chris van de Sande\n* Lance R. Vick\n* Matthias Riegler\n* Michael Vorburger\n* Murtaza Udaipurwala\n* Nico Berlee\n* Niklas Wik\n* Rowan Smith\n* Samuel Kees\n* Seán C McCord\n* Tim Jones\n* Tim van Druenen\n* Victor Seva\n\n### Changes\n<details><summary>81 commits</summary>\n<p>\n\n* [`e3da4754e`](https://github.com/siderolabs/talos/commit/e3da4754e7a2e69b998b861034c6f77e2cf6355b) feat: update Linux to 6.1.7\n* [`006449e46`](https://github.com/siderolabs/talos/commit/006449e464ac009e15d78bb4d71cee80f2540f31) test: build integration test early in the pipeline\n* [`09aa71264`](https://github.com/siderolabs/talos/commit/09aa7126422b9b41e74c3d2aacb563daeca33bc5) fix: renovate config\n* [`2d136f187`](https://github.com/siderolabs/talos/commit/2d136f1879ee66dbd61ab40bb001a45c0bafaad5) feat: set markdown and html descriptions in config json schema\n* [`f0804027a`](https://github.com/siderolabs/talos/commit/f0804027a499a6e195f049144bff4f939dee3780) fix: renovate config\n* [`812a2877c`](https://github.com/siderolabs/talos/commit/812a2877cdc1e631ae0244f9696a65e2347594c0) chore: bump deps + renovate cleanup\n* [`aa9f66c1c`](https://github.com/siderolabs/talos/commit/aa9f66c1c88a1bb35aefe24ea0a5c3a6e7aa966d) fix: mark DigitalOcean anchor IP as scope link\n* [`bb4937f1b`](https://github.com/siderolabs/talos/commit/bb4937f1b339384fb486cb0cb675df8bf9b9f916) feat: enable renovate\n* [`3e0057162`](https://github.com/siderolabs/talos/commit/3e00571627568d8c5ab10a72e59207677a89e4cc) fix: unwrap gRPC errors on stop/remove pods check\n* [`00e52ae07`](https://github.com/siderolabs/talos/commit/00e52ae07867deff9a5877fcb498252bc1b1a740) fix: build correctly etcd initial cluster URL\n* [`ae83b10ae`](https://github.com/siderolabs/talos/commit/ae83b10ae89dbe600ddfaa338be95ea819546007) feat: create JSON schema for v1alpha1.Config\n* [`703d96595`](https://github.com/siderolabs/talos/commit/703d9659512d744a606e520faf230e20efddfc4a) feat: update Kubernetes to 1.26.1, etcd to 3.5.7\n* [`965e64591`](https://github.com/siderolabs/talos/commit/965e645915d080487a74b35dc8f1d2e4051f0504) docs: update to use talosctl install script\n* [`c5954f434`](https://github.com/siderolabs/talos/commit/c5954f4345cbf3a92c777a0e7fc5d39e883609bf) chore: bump deps\n* [`bb50f6a56`](https://github.com/siderolabs/talos/commit/bb50f6a56d971915abb6a895aac9d7e0612a3255) chore: preallocate disk images for QEMU VMs\n* [`d4b8b35de`](https://github.com/siderolabs/talos/commit/d4b8b35de7849d887c41f9a13dadb59ccd8c08c4) feat: generate kernel module dependency tree\n* [`18122ae73`](https://github.com/siderolabs/talos/commit/18122ae73e0489a0497956c6d4621c05c6a77387) fix: service restart (including extension services)\n* [`680fd5e45`](https://github.com/siderolabs/talos/commit/680fd5e452e02b108b7938d0136079c16e6cfd79) fix: bump COSI runtime with the panic controller restart fix\n* [`0b65bbfc8`](https://github.com/siderolabs/talos/commit/0b65bbfc878fe2a5c01c5d2cd08006b53fda7cf9) fix: handle overwriting tags in syslinux ADV\n* [`70d9428a1`](https://github.com/siderolabs/talos/commit/70d9428a1d00d9894d68f38b255debb66fe8a440) fix: kubespan MSS clamping\n* [`683b4ccb4`](https://github.com/siderolabs/talos/commit/683b4ccb4faab6c3da2de00f7314773f42899c25) chore: update Go to 1.19.5 and kernel to 6.1.4\n* [`062c7d754`](https://github.com/siderolabs/talos/commit/062c7d754be1714c7763b8f2b399436d64c90ea4) test: fix integration test on cp endpoint update\n* [`8e9fc13d7`](https://github.com/siderolabs/talos/commit/8e9fc13d7c48da5c5354501e0ad96688670438cf) feat: implement enum generator for proto files\n* [`771b0dc06`](https://github.com/siderolabs/talos/commit/771b0dc061e0fa33085b28bd0d0a7e4da13081f1) docs: update left over rpi_4 ref to rpi_generic\n* [`6c04b5f79`](https://github.com/siderolabs/talos/commit/6c04b5f79e6e01e0a3cdabfc99f12c944edd1f0a) chore: bump dependencies\n* [`0a5a8802e`](https://github.com/siderolabs/talos/commit/0a5a8802e7e337e1f30a40c9f566e57642c39c1a) feat: use 'localhost' endpoint for controlplane nodes\n* [`b0775ebf2`](https://github.com/siderolabs/talos/commit/b0775ebf2c776c7133cf74c6259de9dc9573786c) feat: add ISO wipe GRUB boot option\n* [`29020cb9c`](https://github.com/siderolabs/talos/commit/29020cb9c788d87a0457028ce73c8d297959116e) fix: report fatal sequence errors as reboots\n* [`96629d5ba`](https://github.com/siderolabs/talos/commit/96629d5ba6c1ae9d820824fb38f68112bce27f2c) feat: implement etcd maintenance commands\n* [`80fed3194`](https://github.com/siderolabs/talos/commit/80fed319408be9e493141fb2c01e5731708835c7) feat: include Kubernetes controlplane endpoint as one of the endpoints\n* [`c6cb36cc1`](https://github.com/siderolabs/talos/commit/c6cb36cc1f50b5d0e59a5284867e7534dc9f73bb) docs: fix auditpolicy example typo\n* [`ba8265bc5`](https://github.com/siderolabs/talos/commit/ba8265bc5ce63bcbc6fbd6c1a1076dc3f2ee6bd0) feat: new talosctl config remove to remove context\n* [`fcb19ff51`](https://github.com/siderolabs/talos/commit/fcb19ff516cc1200ec81f2a954bb6d2ce39ebdc6) fix: implement upgrade version checks for Talos 1.4\n* [`80f150ac8`](https://github.com/siderolabs/talos/commit/80f150ac859f5dbf95060c12440afab8c0bc77a8) feat: enable ipv6 on gcp\n* [`8db622f3d`](https://github.com/siderolabs/talos/commit/8db622f3dc75aed90dd2d0bd92d03aa7e8aefd10) docs: add Vandebron to adopters list\n* [`f6a86ae90`](https://github.com/siderolabs/talos/commit/f6a86ae90607914c29875df750fe79cbbfcc5897) fix: oralce cloud zone\n* [`89dbb0ecf`](https://github.com/siderolabs/talos/commit/89dbb0ecf089bb746479238df274ccba4fcb049a) release(v1.4.0-alpha.0): prepare release\n* [`31fb90535`](https://github.com/siderolabs/talos/commit/31fb9053582190b3b536a309c30e2b78c4611885) feat: update Linux 6.1.1, containerd 1.6.14\n* [`a0c0352dd`](https://github.com/siderolabs/talos/commit/a0c0352ddca253e1efb3679224b317692d46b2fd) fix: send diagnostic output to stderr consistently\n* [`9a5f4c08a`](https://github.com/siderolabs/talos/commit/9a5f4c08a206504a1d30277dcc0597333e5a927a) fix: default the manifest namespace if not set\n* [`3c6cce5fe`](https://github.com/siderolabs/talos/commit/3c6cce5fe47075f43a73682b57a7b40fa0899795) docs: update last release for Talos 1.2.x\n* [`703624c43`](https://github.com/siderolabs/talos/commit/703624c43dd8e58c147ccbc3989c6c436c9f3a7f) docs: fix the 1.3 release date\n* [`386c9293a`](https://github.com/siderolabs/talos/commit/386c9293a33e9d237fbeda0492b01b11fdadc501) docs: update nvidia-container-runtime version\n* [`ff83d9fd7`](https://github.com/siderolabs/talos/commit/ff83d9fd7bed2e04d5c8107713150c2513f47991) fix: improve talosctl completion\n* [`31ff431fa`](https://github.com/siderolabs/talos/commit/31ff431faec22c09cad88d565102e6a24785ecb4) chore: add schulz systemtechnik to the list\n* [`97bef7c47`](https://github.com/siderolabs/talos/commit/97bef7c47bfd133f2b3ad19efe3f30a88dd67460) docs: vsphere.sh > vmware.sh\n* [`34babe858`](https://github.com/siderolabs/talos/commit/34babe858d15145a1c596febb5e577473e4ffce0) chore: make organization selection an interface\n* [`a9643b477`](https://github.com/siderolabs/talos/commit/a9643b477417029db73aacbfcf5778cedd97cd95) fix: use proper key usage for apid client certificate\n* [`171aa9467`](https://github.com/siderolabs/talos/commit/171aa9467966f5869e72374961ea05abc8d9fda9) fix: disable Wireless Lan using dtoverlay\n* [`2e84d2ab3`](https://github.com/siderolabs/talos/commit/2e84d2ab3417515f539a70d58885dcb69e9f098c) chore: update conformance product.yaml\n* [`b7763843a`](https://github.com/siderolabs/talos/commit/b7763843af63bbc186f08701a62c19ea96fb7e3c) feat: add install script that improves talosctl installation user experience This install script detects the platform and architecture, and downloads the correct talosctl, and checks the gpg checksums. It also installs and chmods the binary.\n* [`afc45ad63`](https://github.com/siderolabs/talos/commit/afc45ad632e63cc3afc095b1f3efe6df3ecb9cb1) docs: mark Talos 1.3 docs as default\n* [`873bd3807`](https://github.com/siderolabs/talos/commit/873bd3807c0fcca2e212deb7fd044662557964c1) fix: redact service account key in config in RedactSecrets method\n* [`b3aebfadf`](https://github.com/siderolabs/talos/commit/b3aebfadfc15544e5ab448d979129dba5e516c59) feat: validate Talos API access roles in machine config\n* [`40761e17d`](https://github.com/siderolabs/talos/commit/40761e17db5789f30eef2f15f0b5c6396e09a9e5) docs: fork docs for Talos 1.4\n* [`474604cd2`](https://github.com/siderolabs/talos/commit/474604cd279def7a6798e24ede27feef955ba5a3) docs: update documentation for Talos 1.3\n* [`faf49218c`](https://github.com/siderolabs/talos/commit/faf49218ce14a48829dae7b3b8d7801188453a89) feat: add more checks for K8s upgrade\n* [`5b992bd86`](https://github.com/siderolabs/talos/commit/5b992bd8610f41d23d8b7dbd01f9a1be298eda96) fix: allow empty dnsDomain in machine config\n* [`eb332cfcb`](https://github.com/siderolabs/talos/commit/eb332cfcb785e250c422d6a7ea2b23679189a946) feat: add health check for a minimal memory / disk size\n* [`d04970dfa`](https://github.com/siderolabs/talos/commit/d04970dfa9d6554e1ee447fd9383bf65b8953671) fix: ignore k8s additional addresses if nil\n* [`63c17104c`](https://github.com/siderolabs/talos/commit/63c17104c594dfd9ca4066ba41d8a03507464874) feat: update Kubernets to 1.26.0\n* [`f7a9a90db`](https://github.com/siderolabs/talos/commit/f7a9a90db2bfd316ea01551daba9becb15361f94) chore: update pkgs/tools (Go 1.19.4, containerd 1.6.11)\n* [`cf7adc51c`](https://github.com/siderolabs/talos/commit/cf7adc51c9f53234e469dd9f0cca06eed0230e8b) feat: add RedactSecrets method to v1alpha1.Config\n* [`4c31b9b1a`](https://github.com/siderolabs/talos/commit/4c31b9b1a3a00df0fe817c3edc15260ca3cadd6d) docs: clarify what the deal is with /var\n* [`a8ebcca4a`](https://github.com/siderolabs/talos/commit/a8ebcca4a9f63643f68d8e85bcb0b9ddb49205ed) chore: remove `watchErr` from `metal.getResource`\n* [`1253513bd`](https://github.com/siderolabs/talos/commit/1253513bd1deecc4cc42330bad0a713b3630240a) fix: fix nil pointer panic and incorrect error output\n* [`82e8c9e1f`](https://github.com/siderolabs/talos/commit/82e8c9e1f63371f41b0794b4c1be3209847c5f8b) fix: workaround panic in the kubelet service controller\n* [`a505b8909`](https://github.com/siderolabs/talos/commit/a505b8909a1c733b30f22a8d46eebc022475431a) fix: update COSI and reset restart backoff on success\n* [`e92fdcbad`](https://github.com/siderolabs/talos/commit/e92fdcbad1de595d119f78dbed3a97ae46df9bbf) chore: bump kernel to 5.15.81\n* [`f0dddca2a`](https://github.com/siderolabs/talos/commit/f0dddca2a3d2e976cee543ab57816a6395fe3d65) docs: expand help for 'talosctl get'\n* [`fcffc8879`](https://github.com/siderolabs/talos/commit/fcffc88790b5a3006b3b85744771a7eef6e8ac5c) fix: add ext4 filesystem detection\n* [`5b2960eff`](https://github.com/siderolabs/talos/commit/5b2960efff8b38af85b687a25fa93f01256016de) fix: introduce 'overridePath' setting and fix Talos resolver\n* [`0219d1124`](https://github.com/siderolabs/talos/commit/0219d1124e5125696364bf92ecf0e8dcad644001) fix: use only kube-apiserver endpoints for Talos API access endpoints\n* [`dc5e0f4af`](https://github.com/siderolabs/talos/commit/dc5e0f4af087d3b662b0240b4f8fd76379ed0de2) fix: report errors to Equinix Metal event API\n* [`7ab140a94`](https://github.com/siderolabs/talos/commit/7ab140a94ad1a279be43669d6d70687f3a0c47de) feat: add talosctl machineconfig patch command\n* [`d3cf06114`](https://github.com/siderolabs/talos/commit/d3cf061149a4a502317d7728c45b6cfb4d38f89f) fix: ignore many more filesystems in IMA\n* [`44e2799b8`](https://github.com/siderolabs/talos/commit/44e2799b8cb928083f3a777d5cce45ad8dbf6864) feat: add stdout and single config type support to talosctl gen config\n* [`4452f0e17`](https://github.com/siderolabs/talos/commit/4452f0e179db16c59dc65ccdb5a496ad3306684e) docs: bump talos version\n* [`38e57bd12`](https://github.com/siderolabs/talos/commit/38e57bd12b8c50d668fcde6ee9aa493682778dcc) feat: update Kubernetes to v1.26.0-rc.1\n* [`4cd125d49`](https://github.com/siderolabs/talos/commit/4cd125d499a24798dfde1dddf6fa1c689d16c93f) fix: correctly handle new watch event types\n* [`881b84152`](https://github.com/siderolabs/talos/commit/881b84152084d157fbd4ff992089a5392aadfd3c) feat: update Flannel to 0.20.2\n</p>\n</details>\n\n### Changes since v1.4.0-alpha.0\n<details><summary>36 commits</summary>\n<p>\n\n* [`e3da4754e`](https://github.com/siderolabs/talos/commit/e3da4754e7a2e69b998b861034c6f77e2cf6355b) feat: update Linux to 6.1.7\n* [`006449e46`](https://github.com/siderolabs/talos/commit/006449e464ac009e15d78bb4d71cee80f2540f31) test: build integration test early in the pipeline\n* [`09aa71264`](https://github.com/siderolabs/talos/commit/09aa7126422b9b41e74c3d2aacb563daeca33bc5) fix: renovate config\n* [`2d136f187`](https://github.com/siderolabs/talos/commit/2d136f1879ee66dbd61ab40bb001a45c0bafaad5) feat: set markdown and html descriptions in config json schema\n* [`f0804027a`](https://github.com/siderolabs/talos/commit/f0804027a499a6e195f049144bff4f939dee3780) fix: renovate config\n* [`812a2877c`](https://github.com/siderolabs/talos/commit/812a2877cdc1e631ae0244f9696a65e2347594c0) chore: bump deps + renovate cleanup\n* [`aa9f66c1c`](https://github.com/siderolabs/talos/commit/aa9f66c1c88a1bb35aefe24ea0a5c3a6e7aa966d) fix: mark DigitalOcean anchor IP as scope link\n* [`bb4937f1b`](https://github.com/siderolabs/talos/commit/bb4937f1b339384fb486cb0cb675df8bf9b9f916) feat: enable renovate\n* [`3e0057162`](https://github.com/siderolabs/talos/commit/3e00571627568d8c5ab10a72e59207677a89e4cc) fix: unwrap gRPC errors on stop/remove pods check\n* [`00e52ae07`](https://github.com/siderolabs/talos/commit/00e52ae07867deff9a5877fcb498252bc1b1a740) fix: build correctly etcd initial cluster URL\n* [`ae83b10ae`](https://github.com/siderolabs/talos/commit/ae83b10ae89dbe600ddfaa338be95ea819546007) feat: create JSON schema for v1alpha1.Config\n* [`703d96595`](https://github.com/siderolabs/talos/commit/703d9659512d744a606e520faf230e20efddfc4a) feat: update Kubernetes to 1.26.1, etcd to 3.5.7\n* [`965e64591`](https://github.com/siderolabs/talos/commit/965e645915d080487a74b35dc8f1d2e4051f0504) docs: update to use talosctl install script\n* [`c5954f434`](https://github.com/siderolabs/talos/commit/c5954f4345cbf3a92c777a0e7fc5d39e883609bf) chore: bump deps\n* [`bb50f6a56`](https://github.com/siderolabs/talos/commit/bb50f6a56d971915abb6a895aac9d7e0612a3255) chore: preallocate disk images for QEMU VMs\n* [`d4b8b35de`](https://github.com/siderolabs/talos/commit/d4b8b35de7849d887c41f9a13dadb59ccd8c08c4) feat: generate kernel module dependency tree\n* [`18122ae73`](https://github.com/siderolabs/talos/commit/18122ae73e0489a0497956c6d4621c05c6a77387) fix: service restart (including extension services)\n* [`680fd5e45`](https://github.com/siderolabs/talos/commit/680fd5e452e02b108b7938d0136079c16e6cfd79) fix: bump COSI runtime with the panic controller restart fix\n* [`0b65bbfc8`](https://github.com/siderolabs/talos/commit/0b65bbfc878fe2a5c01c5d2cd08006b53fda7cf9) fix: handle overwriting tags in syslinux ADV\n* [`70d9428a1`](https://github.com/siderolabs/talos/commit/70d9428a1d00d9894d68f38b255debb66fe8a440) fix: kubespan MSS clamping\n* [`683b4ccb4`](https://github.com/siderolabs/talos/commit/683b4ccb4faab6c3da2de00f7314773f42899c25) chore: update Go to 1.19.5 and kernel to 6.1.4\n* [`062c7d754`](https://github.com/siderolabs/talos/commit/062c7d754be1714c7763b8f2b399436d64c90ea4) test: fix integration test on cp endpoint update\n* [`8e9fc13d7`](https://github.com/siderolabs/talos/commit/8e9fc13d7c48da5c5354501e0ad96688670438cf) feat: implement enum generator for proto files\n* [`771b0dc06`](https://github.com/siderolabs/talos/commit/771b0dc061e0fa33085b28bd0d0a7e4da13081f1) docs: update left over rpi_4 ref to rpi_generic\n* [`6c04b5f79`](https://github.com/siderolabs/talos/commit/6c04b5f79e6e01e0a3cdabfc99f12c944edd1f0a) chore: bump dependencies\n* [`0a5a8802e`](https://github.com/siderolabs/talos/commit/0a5a8802e7e337e1f30a40c9f566e57642c39c1a) feat: use 'localhost' endpoint for controlplane nodes\n* [`b0775ebf2`](https://github.com/siderolabs/talos/commit/b0775ebf2c776c7133cf74c6259de9dc9573786c) feat: add ISO wipe GRUB boot option\n* [`29020cb9c`](https://github.com/siderolabs/talos/commit/29020cb9c788d87a0457028ce73c8d297959116e) fix: report fatal sequence errors as reboots\n* [`96629d5ba`](https://github.com/siderolabs/talos/commit/96629d5ba6c1ae9d820824fb38f68112bce27f2c) feat: implement etcd maintenance commands\n* [`80fed3194`](https://github.com/siderolabs/talos/commit/80fed319408be9e493141fb2c01e5731708835c7) feat: include Kubernetes controlplane endpoint as one of the endpoints\n* [`c6cb36cc1`](https://github.com/siderolabs/talos/commit/c6cb36cc1f50b5d0e59a5284867e7534dc9f73bb) docs: fix auditpolicy example typo\n* [`ba8265bc5`](https://github.com/siderolabs/talos/commit/ba8265bc5ce63bcbc6fbd6c1a1076dc3f2ee6bd0) feat: new talosctl config remove to remove context\n* [`fcb19ff51`](https://github.com/siderolabs/talos/commit/fcb19ff516cc1200ec81f2a954bb6d2ce39ebdc6) fix: implement upgrade version checks for Talos 1.4\n* [`80f150ac8`](https://github.com/siderolabs/talos/commit/80f150ac859f5dbf95060c12440afab8c0bc77a8) feat: enable ipv6 on gcp\n* [`8db622f3d`](https://github.com/siderolabs/talos/commit/8db622f3dc75aed90dd2d0bd92d03aa7e8aefd10) docs: add Vandebron to adopters list\n* [`f6a86ae90`](https://github.com/siderolabs/talos/commit/f6a86ae90607914c29875df750fe79cbbfcc5897) fix: oralce cloud zone\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`8cb4792`](https://github.com/siderolabs/extras/commit/8cb4792da9b9e2b2663daca747d24c3b5c973e0f) chore: update Go to 1.19.5\n* [`3ca2df3`](https://github.com/siderolabs/extras/commit/3ca2df3ead2a64a5ad30c350b87bfe02bf1f49c7) chore: disable provenance in buildx\n* [`55d8452`](https://github.com/siderolabs/extras/commit/55d845241c8456909ab36f9b0f4e26cc2b49c256) feat: update releases\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>2 commits</summary>\n<p>\n\n* [`214c1ef`](https://github.com/siderolabs/gen/commit/214c1efe795cf426e5ebcc48cb305bfc7a16fdb8) chore: set `slice.Filter` result slice cap to len\n* [`8e89b1e`](https://github.com/siderolabs/gen/commit/8e89b1ede9f35ff4c18a41ee44a69259181c892b) feat: add GetOrCreate and GetOrCall methods\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>19 commits</summary>\n<p>\n\n* [`987d24a`](https://github.com/siderolabs/pkgs/commit/987d24aeaa4fb2278954cd96e6bc6a29a4c8dd61) feat: mellanox drivers are modules\n* [`b82a015`](https://github.com/siderolabs/pkgs/commit/b82a015c78c407d17d23542eba6a4114f3c2c4d7) feat: mellanox oped\n* [`057d4f9`](https://github.com/siderolabs/pkgs/commit/057d4f96aa3ba63cc456b06a70a6b3a008cf803f) chore: bump deps\n* [`4ac4138`](https://github.com/siderolabs/pkgs/commit/4ac4138c6b94622646c9f32f0885496c5475d905) feat: enable nvme support for raspberrypi cm4\n* [`ccb9d39`](https://github.com/siderolabs/pkgs/commit/ccb9d39dc43cf53431a0d7609839ed9c7141972d) fix: disable magic sysrq\n* [`d33202d`](https://github.com/siderolabs/pkgs/commit/d33202d99daa6ccf136fca54ebbadda727a43a75) chore: bump u-boot to 2023.01\n* [`cb83e16`](https://github.com/siderolabs/pkgs/commit/cb83e169df4a2020994a63e5be61524461ef93e3) chore: bump dependencies\n* [`e561dcb`](https://github.com/siderolabs/pkgs/commit/e561dcb45beae80161faccedb0303e58d41b1ded) feat: bump Go to 1.19.5\n* [`c7797c7`](https://github.com/siderolabs/pkgs/commit/c7797c77bd311449e1f116980166d8d818102f4f) feat: update Linux to 6.1.4, restore RPi support\n* [`5e8ebb0`](https://github.com/siderolabs/pkgs/commit/5e8ebb073d9b58555a75912cd90490af8a435c7d) feat: add AMD K10 sensor support\n* [`73ac37d`](https://github.com/siderolabs/pkgs/commit/73ac37d683274e60340d2767f2b8201e7f13474c) chore: disable provenance in buildx\n* [`8965bee`](https://github.com/siderolabs/pkgs/commit/8965bee65313539e8b6534073d06341f4fb78586) chore: use default symlinks to `/bin` in `base`\n* [`325c9bf`](https://github.com/siderolabs/pkgs/commit/325c9bf0f3ed2bf7603d1eaea022ea650388cf2b) feat: bump dependencies\n* [`165dff6`](https://github.com/siderolabs/pkgs/commit/165dff6c3cdb2d05f170c8ae0616d9224416455e) fix: patch ipmitool IANA URL\n* [`c542f39`](https://github.com/siderolabs/pkgs/commit/c542f398a150567d5cdffc17b4248be5416fe242) feat: add kernel support for usb setrial console\n* [`f564f45`](https://github.com/siderolabs/pkgs/commit/f564f45645d102b7e3a9563ac7bdb1e816156e65) chore: bump tools, containerd\n* [`268ea7c`](https://github.com/siderolabs/pkgs/commit/268ea7c593ff04c4e4a9ea5676b3c58d41cbff14) chore: bump deps\n* [`dcf3ceb`](https://github.com/siderolabs/pkgs/commit/dcf3cebf283698e010aaac5417d91a7385dc2441) feat: add nitro enclave support in kernel\n* [`17ea5e6`](https://github.com/siderolabs/pkgs/commit/17ea5e680b2438c59fa1773e8b58d6b749cb0d34) chore: bump kernel to 5.15.81\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>14 commits</summary>\n<p>\n\n* [`28d4a57`](https://github.com/siderolabs/tools/commit/28d4a5721ce1c57fc3f643185386d5c4b5c7e39a) chore: reduce renovate noise\n* [`e130fd5`](https://github.com/siderolabs/tools/commit/e130fd5b9835d8cc178ec53d5a89dfc6cc2ce7a1) chore: bump deps\n* [`37612fe`](https://github.com/siderolabs/tools/commit/37612feb7222b943a84f1f98d0901a204d491926) fix: revert enabling provenance\n* [`e0b01e3`](https://github.com/siderolabs/tools/commit/e0b01e3b7420e8b0b1e0d9077515e007a6b83b56) chore: bump deps\n* [`d0e6bd0`](https://github.com/siderolabs/tools/commit/d0e6bd06fcfcadc330cf30339488536961f9f70e) feat: add gnutls\n* [`3d34b5d`](https://github.com/siderolabs/tools/commit/3d34b5d401a67048d365e8faf2f1edf293887a97) chore: bump dependencies\n* [`763c1d9`](https://github.com/siderolabs/tools/commit/763c1d927822517b3d63c624302e11e8e5a49f5b) feat: update Go to 1.19.5\n* [`136958f`](https://github.com/siderolabs/tools/commit/136958f9f8c8cfc439228dec31b840549bca4374) chore: disable provenance in buildx\n* [`e2a8692`](https://github.com/siderolabs/tools/commit/e2a869294be7e77e295ca651400f85551fb7e665) feat: update releases\n* [`0e48f37`](https://github.com/siderolabs/tools/commit/0e48f37496a79ce4997d15fefb6300b2324f5668) chore: bump protobuf\n* [`a21aa1c`](https://github.com/siderolabs/tools/commit/a21aa1c583a10d017ace8da14c6f604f86ce5709) chore: bump toolchain and mpc versions\n* [`1a75d0f`](https://github.com/siderolabs/tools/commit/1a75d0f6796c4abf1c9a23cfe697d3e38a9ce587) chore: bump deps\n* [`55bd185`](https://github.com/siderolabs/tools/commit/55bd18532667e325e8938bf0a72cab40a936eadf) feat: update Go to 1.19.4\n* [`f291f46`](https://github.com/siderolabs/tools/commit/f291f46e84ec02f5d22718f7ecb476a3f815ae45) chore: bump tools\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**       v0.2.1 -> v0.2.3\n* **github.com/aws/aws-sdk-go**                  v1.44.147 -> v1.44.184\n* **github.com/containerd/containerd**           v1.6.12 -> v1.6.15\n* **github.com/containernetworking/plugins**     v1.1.1 -> v1.2.0\n* **github.com/coreos/go-semver**                v0.3.0 -> v0.3.1\n* **github.com/cosi-project/runtime**            v0.2.0 -> v0.3.0-alpha.4\n* **github.com/docker/docker**                   v20.10.21 -> v20.10.23\n* **github.com/dustin/go-humanize**              v1.0.0 -> v1.0.1\n* **github.com/fatih/color**                     v1.13.0 -> v1.14.1\n* **github.com/freddierice/go-losetup/v2**       v2.0.1 **_new_**\n* **github.com/gdamore/tcell/v2**                v2.5.3 -> v2.5.4\n* **github.com/hetznercloud/hcloud-go**          v1.37.0 -> v1.39.0\n* **github.com/insomniacslk/dhcp**               f26e6d78f622 -> de60144f33f8\n* **github.com/mattn/go-isatty**                 v0.0.16 -> v0.0.17\n* **github.com/mdlayher/ethtool**                0e16326d06d1 -> ba3b4bc2e02c\n* **github.com/mdlayher/genetlink**              v1.3.0 -> v1.3.1\n* **github.com/mdlayher/netlink**                v1.7.0 -> v1.7.1\n* **github.com/prometheus/procfs**               v0.8.0 -> v0.9.0\n* **github.com/rivo/tview**                      db36428c92d9 -> 892d1a2eb0da\n* **github.com/scaleway/scaleway-sdk-go**        v1.0.0-beta.10 -> v1.0.0-beta.12\n* **github.com/siderolabs/extras**               v1.3.0-1-g3773d71 -> v1.4.0-alpha.0-2-g8cb4792\n* **github.com/siderolabs/gen**                  v0.4.1 -> v0.4.3\n* **github.com/siderolabs/pkgs**                 v1.3.0-5-g6509d23 -> v1.4.0-alpha.0-18-g987d24a\n* **github.com/siderolabs/talos/pkg/machinery**  v1.3.0 -> v1.4.0-alpha.0\n* **github.com/siderolabs/tools**                v1.3.0-1-g712379c -> v1.4.0-alpha.0-11-g28d4a57\n* **github.com/ulikunitz/xz**                    v0.5.11 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**           v0.56.12 -> v0.56.14\n* **github.com/vmware/govmomi**                  v0.29.0 -> v0.30.0\n* **go.etcd.io/etcd/api/v3**                     v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/pkg/v3**              v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/client/v3**                  v3.5.6 -> v3.5.7\n* **go.etcd.io/etcd/etcdutl/v3**                 v3.5.6 -> v3.5.7\n* **go.uber.org/zap**                            v1.23.0 -> v1.24.0\n* **go4.org/netipx**                             797b0c90d8ab -> 987e16ee2705\n* **golang.org/x/net**                           v0.4.0 -> v0.5.0\n* **golang.org/x/sys**                           v0.3.0 -> v0.4.0\n* **golang.org/x/term**                          v0.3.0 -> v0.4.0\n* **golang.org/x/time**                          v0.2.0 -> v0.3.0\n* **google.golang.org/grpc**                     v1.51.0 -> v1.52.0\n* **k8s.io/api**                                 v0.26.0 -> v0.26.1\n* **k8s.io/apimachinery**                        v0.26.0 -> v0.26.1\n* **k8s.io/apiserver**                           v0.26.0 -> v0.26.1\n* **k8s.io/client-go**                           v0.26.0 -> v0.26.1\n* **k8s.io/component-base**                      v0.26.0 -> v0.26.1\n* **k8s.io/klog/v2**                             v2.80.1 -> v2.90.0\n* **k8s.io/kubectl**                             v0.26.0 -> v0.26.1\n* **k8s.io/kubelet**                             v0.26.0 -> v0.26.1\n\nPrevious release can be found at [v1.3.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0)\n\n## [Talos 1.4.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.4.0-alpha.0) (2022-12-23)\n\nWelcome to the v1.4.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\n* Linux: 6.1.1\n* containerd: v1.6.14\n\nTalos is built with Go 1.19.4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Utku Ozdemir\n* Dmitriy Matrenichev\n* Spencer Smith\n* Lance R. Vick\n* Michael Vorburger\n* Nico Berlee\n* Niklas Wik\n* Rowan Smith\n* Samuel Kees\n* Steve Francis\n* Victor Seva\n\n### Changes\n<details><summary>44 commits</summary>\n<p>\n\n* [`31fb90535`](https://github.com/siderolabs/talos/commit/31fb9053582190b3b536a309c30e2b78c4611885) feat: update Linux 6.1.1, containerd 1.6.14\n* [`a0c0352dd`](https://github.com/siderolabs/talos/commit/a0c0352ddca253e1efb3679224b317692d46b2fd) fix: send diagnostic output to stderr consistently\n* [`9a5f4c08a`](https://github.com/siderolabs/talos/commit/9a5f4c08a206504a1d30277dcc0597333e5a927a) fix: default the manifest namespace if not set\n* [`3c6cce5fe`](https://github.com/siderolabs/talos/commit/3c6cce5fe47075f43a73682b57a7b40fa0899795) docs: update last release for Talos 1.2.x\n* [`703624c43`](https://github.com/siderolabs/talos/commit/703624c43dd8e58c147ccbc3989c6c436c9f3a7f) docs: fix the 1.3 release date\n* [`386c9293a`](https://github.com/siderolabs/talos/commit/386c9293a33e9d237fbeda0492b01b11fdadc501) docs: update nvidia-container-runtime version\n* [`ff83d9fd7`](https://github.com/siderolabs/talos/commit/ff83d9fd7bed2e04d5c8107713150c2513f47991) fix: improve talosctl completion\n* [`31ff431fa`](https://github.com/siderolabs/talos/commit/31ff431faec22c09cad88d565102e6a24785ecb4) chore: add schulz systemtechnik to the list\n* [`97bef7c47`](https://github.com/siderolabs/talos/commit/97bef7c47bfd133f2b3ad19efe3f30a88dd67460) docs: vsphere.sh > vmware.sh\n* [`34babe858`](https://github.com/siderolabs/talos/commit/34babe858d15145a1c596febb5e577473e4ffce0) chore: make organization selection an interface\n* [`a9643b477`](https://github.com/siderolabs/talos/commit/a9643b477417029db73aacbfcf5778cedd97cd95) fix: use proper key usage for apid client certificate\n* [`171aa9467`](https://github.com/siderolabs/talos/commit/171aa9467966f5869e72374961ea05abc8d9fda9) fix: disable Wireless Lan using dtoverlay\n* [`2e84d2ab3`](https://github.com/siderolabs/talos/commit/2e84d2ab3417515f539a70d58885dcb69e9f098c) chore: update conformance product.yaml\n* [`b7763843a`](https://github.com/siderolabs/talos/commit/b7763843af63bbc186f08701a62c19ea96fb7e3c) feat: add install script that improves talosctl installation user experience This install script detects the platform and architecture, and downloads the correct talosctl, and checks the gpg checksums. It also installs and chmods the binary.\n* [`afc45ad63`](https://github.com/siderolabs/talos/commit/afc45ad632e63cc3afc095b1f3efe6df3ecb9cb1) docs: mark Talos 1.3 docs as default\n* [`873bd3807`](https://github.com/siderolabs/talos/commit/873bd3807c0fcca2e212deb7fd044662557964c1) fix: redact service account key in config in RedactSecrets method\n* [`b3aebfadf`](https://github.com/siderolabs/talos/commit/b3aebfadfc15544e5ab448d979129dba5e516c59) feat: validate Talos API access roles in machine config\n* [`40761e17d`](https://github.com/siderolabs/talos/commit/40761e17db5789f30eef2f15f0b5c6396e09a9e5) docs: fork docs for Talos 1.4\n* [`474604cd2`](https://github.com/siderolabs/talos/commit/474604cd279def7a6798e24ede27feef955ba5a3) docs: update documentation for Talos 1.3\n* [`faf49218c`](https://github.com/siderolabs/talos/commit/faf49218ce14a48829dae7b3b8d7801188453a89) feat: add more checks for K8s upgrade\n* [`5b992bd86`](https://github.com/siderolabs/talos/commit/5b992bd8610f41d23d8b7dbd01f9a1be298eda96) fix: allow empty dnsDomain in machine config\n* [`eb332cfcb`](https://github.com/siderolabs/talos/commit/eb332cfcb785e250c422d6a7ea2b23679189a946) feat: add health check for a minimal memory / disk size\n* [`d04970dfa`](https://github.com/siderolabs/talos/commit/d04970dfa9d6554e1ee447fd9383bf65b8953671) fix: ignore k8s additional addresses if nil\n* [`63c17104c`](https://github.com/siderolabs/talos/commit/63c17104c594dfd9ca4066ba41d8a03507464874) feat: update Kubernets to 1.26.0\n* [`f7a9a90db`](https://github.com/siderolabs/talos/commit/f7a9a90db2bfd316ea01551daba9becb15361f94) chore: update pkgs/tools (Go 1.19.4, containerd 1.6.11)\n* [`cf7adc51c`](https://github.com/siderolabs/talos/commit/cf7adc51c9f53234e469dd9f0cca06eed0230e8b) feat: add RedactSecrets method to v1alpha1.Config\n* [`4c31b9b1a`](https://github.com/siderolabs/talos/commit/4c31b9b1a3a00df0fe817c3edc15260ca3cadd6d) docs: clarify what the deal is with /var\n* [`a8ebcca4a`](https://github.com/siderolabs/talos/commit/a8ebcca4a9f63643f68d8e85bcb0b9ddb49205ed) chore: remove `watchErr` from `metal.getResource`\n* [`1253513bd`](https://github.com/siderolabs/talos/commit/1253513bd1deecc4cc42330bad0a713b3630240a) fix: fix nil pointer panic and incorrect error output\n* [`82e8c9e1f`](https://github.com/siderolabs/talos/commit/82e8c9e1f63371f41b0794b4c1be3209847c5f8b) fix: workaround panic in the kubelet service controller\n* [`a505b8909`](https://github.com/siderolabs/talos/commit/a505b8909a1c733b30f22a8d46eebc022475431a) fix: update COSI and reset restart backoff on success\n* [`e92fdcbad`](https://github.com/siderolabs/talos/commit/e92fdcbad1de595d119f78dbed3a97ae46df9bbf) chore: bump kernel to 5.15.81\n* [`f0dddca2a`](https://github.com/siderolabs/talos/commit/f0dddca2a3d2e976cee543ab57816a6395fe3d65) docs: expand help for 'talosctl get'\n* [`fcffc8879`](https://github.com/siderolabs/talos/commit/fcffc88790b5a3006b3b85744771a7eef6e8ac5c) fix: add ext4 filesystem detection\n* [`5b2960eff`](https://github.com/siderolabs/talos/commit/5b2960efff8b38af85b687a25fa93f01256016de) fix: introduce 'overridePath' setting and fix Talos resolver\n* [`0219d1124`](https://github.com/siderolabs/talos/commit/0219d1124e5125696364bf92ecf0e8dcad644001) fix: use only kube-apiserver endpoints for Talos API access endpoints\n* [`dc5e0f4af`](https://github.com/siderolabs/talos/commit/dc5e0f4af087d3b662b0240b4f8fd76379ed0de2) fix: report errors to Equinix Metal event API\n* [`7ab140a94`](https://github.com/siderolabs/talos/commit/7ab140a94ad1a279be43669d6d70687f3a0c47de) feat: add talosctl machineconfig patch command\n* [`d3cf06114`](https://github.com/siderolabs/talos/commit/d3cf061149a4a502317d7728c45b6cfb4d38f89f) fix: ignore many more filesystems in IMA\n* [`44e2799b8`](https://github.com/siderolabs/talos/commit/44e2799b8cb928083f3a777d5cce45ad8dbf6864) feat: add stdout and single config type support to talosctl gen config\n* [`4452f0e17`](https://github.com/siderolabs/talos/commit/4452f0e179db16c59dc65ccdb5a496ad3306684e) docs: bump talos version\n* [`38e57bd12`](https://github.com/siderolabs/talos/commit/38e57bd12b8c50d668fcde6ee9aa493682778dcc) feat: update Kubernetes to v1.26.0-rc.1\n* [`4cd125d49`](https://github.com/siderolabs/talos/commit/4cd125d499a24798dfde1dddf6fa1c689d16c93f) fix: correctly handle new watch event types\n* [`881b84152`](https://github.com/siderolabs/talos/commit/881b84152084d157fbd4ff992089a5392aadfd3c) feat: update Flannel to 0.20.2\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`55d8452`](https://github.com/siderolabs/extras/commit/55d845241c8456909ab36f9b0f4e26cc2b49c256) feat: update releases\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>1 commit</summary>\n<p>\n\n* [`8e89b1e`](https://github.com/siderolabs/gen/commit/8e89b1ede9f35ff4c18a41ee44a69259181c892b) feat: add GetOrCreate and GetOrCall methods\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>7 commits</summary>\n<p>\n\n* [`325c9bf`](https://github.com/siderolabs/pkgs/commit/325c9bf0f3ed2bf7603d1eaea022ea650388cf2b) feat: bump dependencies\n* [`165dff6`](https://github.com/siderolabs/pkgs/commit/165dff6c3cdb2d05f170c8ae0616d9224416455e) fix: patch ipmitool IANA URL\n* [`c542f39`](https://github.com/siderolabs/pkgs/commit/c542f398a150567d5cdffc17b4248be5416fe242) feat: add kernel support for usb setrial console\n* [`f564f45`](https://github.com/siderolabs/pkgs/commit/f564f45645d102b7e3a9563ac7bdb1e816156e65) chore: bump tools, containerd\n* [`268ea7c`](https://github.com/siderolabs/pkgs/commit/268ea7c593ff04c4e4a9ea5676b3c58d41cbff14) chore: bump deps\n* [`dcf3ceb`](https://github.com/siderolabs/pkgs/commit/dcf3cebf283698e010aaac5417d91a7385dc2441) feat: add nitro enclave support in kernel\n* [`17ea5e6`](https://github.com/siderolabs/pkgs/commit/17ea5e680b2438c59fa1773e8b58d6b749cb0d34) chore: bump kernel to 5.15.81\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`e2a8692`](https://github.com/siderolabs/tools/commit/e2a869294be7e77e295ca651400f85551fb7e665) feat: update releases\n* [`0e48f37`](https://github.com/siderolabs/tools/commit/0e48f37496a79ce4997d15fefb6300b2324f5668) chore: bump protobuf\n* [`a21aa1c`](https://github.com/siderolabs/tools/commit/a21aa1c583a10d017ace8da14c6f604f86ce5709) chore: bump toolchain and mpc versions\n* [`1a75d0f`](https://github.com/siderolabs/tools/commit/1a75d0f6796c4abf1c9a23cfe697d3e38a9ce587) chore: bump deps\n* [`55bd185`](https://github.com/siderolabs/tools/commit/55bd18532667e325e8938bf0a72cab40a936eadf) feat: update Go to 1.19.4\n* [`f291f46`](https://github.com/siderolabs/tools/commit/f291f46e84ec02f5d22718f7ecb476a3f815ae45) chore: bump tools\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**       v0.2.1 -> v0.2.3\n* **github.com/aws/aws-sdk-go**                  v1.44.147 -> v1.44.166\n* **github.com/containerd/containerd**           v1.6.12 -> v1.6.14\n* **github.com/cosi-project/runtime**            v0.2.0 -> v0.3.0-alpha.2\n* **github.com/docker/docker**                   v20.10.21 -> v20.10.22\n* **github.com/hetznercloud/hcloud-go**          v1.37.0 -> v1.38.0\n* **github.com/insomniacslk/dhcp**               f26e6d78f622 -> de60144f33f8\n* **github.com/mdlayher/ethtool**                0e16326d06d1 -> ba3b4bc2e02c\n* **github.com/mdlayher/genetlink**              v1.3.0 -> v1.3.1\n* **github.com/mdlayher/netlink**                v1.7.0 -> v1.7.1\n* **github.com/prometheus/procfs**               v0.8.0 -> v0.9.0\n* **github.com/rivo/tview**                      db36428c92d9 -> 02e38ea9604c\n* **github.com/siderolabs/extras**               v1.3.0-1-g3773d71 -> v1.4.0-alpha.0\n* **github.com/siderolabs/gen**                  v0.4.1 -> v0.4.2\n* **github.com/siderolabs/pkgs**                 v1.3.0-5-g6509d23 -> v1.4.0-alpha.0-6-g325c9bf\n* **github.com/siderolabs/talos/pkg/machinery**  v1.3.0 -> v1.3.0-alpha.2\n* **github.com/siderolabs/tools**                v1.3.0-1-g712379c -> v1.4.0-alpha.0-3-ge2a8692\n* **github.com/vmware-tanzu/sonobuoy**           v0.56.12 -> v0.56.14\n* **github.com/vmware/govmomi**                  v0.29.0 -> v0.30.0\n* **go.uber.org/zap**                            v1.23.0 -> v1.24.0\n* **golang.org/x/time**                          v0.2.0 -> v0.3.0\n\nPrevious release can be found at [v1.3.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0)\n\n## [Talos 1.3.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.3.0-alpha.2) (2022-11-16)\n\nWelcome to the v1.3.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### kube-apiserver Audit Policy\n\nTalos now supports setting custom audit policy for `kube-apiserver` in the machine configuration.\n\n\n### cgroups v1\n\nTalos defaults to using cgroups v2 when Talos doesn't run in a container (when running in a container\nTalos follows host cgroups mode).\nTalos can now be forced to use cgroups v1 by setting boot kernel argument `talos.unified_cgroup_hierarchy=0`:\n\n```yaml\nmachine:\n  install:\n    extraKernelArgs:\n      - \"talos.unified_cgroup_hierarchy=0\"\n```\n\nCurrent cgroups mode can be checked with `talosctl ls /sys/fs/cgroup`:\n\ncgroups v1:\n\n```\nblkio\ncpu\ncpuacct\ncpuset\ndevices\nfreezer\nhugetlb\nmemory\nnet_cls\nnet_prio\nperf_event\npids\n```\n\ncgroups v2:\n\n```\ncgroup.controllers\ncgroup.max.depth\ncgroup.max.descendants\ncgroup.procs\ncgroup.stat\ncgroup.subtree_control\ncgroup.threads\ncpu.stat\ncpuset.cpus.effective\ncpuset.mems.effective\ninit\nio.stat\nkubepods\nmemory.numa_stat\nmemory.stat\npodruntime\nsystem\n```\n\n> Note: `cgroupsv1` is deprecated and it should be used only for compatibility with workloads which don't support `cgroupsv2` yet.\n\n\n### Kernel Command Line ip= Argument\n\nTalos now supports referencing interface name via `enxMAC` address notation:\n\n```\nip=172.20.0.2::172.20.0.1:255.255.255.0::enx7085c2dfbc59\n```\n\n\n### CRI Configuration Overrides\n\nTalos no longer supports CRI config overrides placed in `/var/cri/conf.d` directory.\n\n[New way](https://www.talos.dev/v1.3/talos-guides/configuration/containerd/) correctly handles merging of containerd/CRI plugin configuration.\n\n\n### etcd Consistency Check\n\nTalos enables [--experimental-compact-hash-check-enabled](https://github.com/etcd-io/etcd/pull/14120) option by default to improve\netcd store consistency guarantees.\n\nThis options is only available with etcd >= v3.5.5, so Talos doesn't support version of etcd before v3.5.5.\n\n\n### etcd Member ID\n\nTalos now internally handles etcd member removal by member ID instead of member name (hostname).\nThis resolves the case when member name is not accurate or empty (eg: when etcd hasn't fully joined yet).\n\nCommand `talosctl etcd remove-member` now accepts member IDs instead of member names.\n\nNew resource can be used to get member ID of the Talos node:\n\n```bash\ntalosctl get etcdmember\n```\n\n\n### Exocale Platform\n\nTalos now supports new platform: Exoscale.\n\nExoscale provides a firewall, TCP load balancer and autoscale groups.\nIt works well with CCM and Kubernetes node autoscaler.\n\n\n### Kernel Modules\n\nTalos now supports settings kernel module parameters.\n\nEg:\n\n```yaml\nmachine:\n  kernel:\n    modules:\n      - name: \"br_netfilter\"\n        parameters:\n          - nf_conntrack_max=131072\n```\n\n\n### KubeSpan\n\nKubeSpan MTU link size is now configurable via `network.kubespan.mtu` setting in the machine configuration.\n\n\n### Node Labels\n\nTalos now supports specifying node labels in the machine configuration:\n\n```yaml\nmachine:\n  nodeLabels:\n    rack: rack1a\n    zone: us-east-1a\n```\n\nChanges to the node labels will be applied immediately without `kubelet` restart.\n\nTalos keeps track of the owned node labels in the `talos.dev/owned-labels` annotation.\n\n\n### Routes\n\nTalos now supports setting MTU for a specific route.\n\n\n### Nano Pi R4S\n\nTalos now supports the Nano Pi R4S SBC.\n\n\n### Raspberry Generic Images\n\nThe Raspberry Pi 4 specific image has been deprecated and will be removed in the v1.4 release of Talos.\nTalos now ships a generic Raspberry Pi image that should support more Raspberry Pi variants.\nRefer to the docs at https://www.talos.dev/v1.3/talos-guides/install/single-board-computers/rpi_generic/ to find which ones are supported.\n\n\n### Encryption with secretbox\n\nBy default new clusters will use secretbox for encryption instead of AESCBC.\nIf both are configured secretbox will take precedence.\nOld clusters may keep using AESCBC.\nTo enable secretbox you may add an encryption secret at `cluster.secretboxEncryptionSecret`.\nYou should keep `aescbcEncryptionSecret` however, even if secretbox is enabled older data will still be encrypted with AESCBC.\n\nHow to generate the secret:\n\n```bash\ndd if=/dev/random of=/dev/stdout bs=32 count=1 | base64\n```\n\n\n### Static Pod Manifests\n\nThe directory \"/etc/kubernetes/manifests\" is now deprecated.\nStatic pods should always be configured in machine.pods.\nTo reenable support you may set `machine.kubelet.disableManifestsDirectory`.\n\nEg:\n\n```yaml\nmachine:\n  kubelet:\n    disableManifestsDirectory: no\n```\n\n\n### Component Updates\n\n* Kubernetes: v1.26.0-rc.0\n* Flannel: v0.20.1\n* CoreDNS: v1.10.0\n* etcd: v3.5.5\n* Linux: 5.15.77\n* containerd: v1.6.9\n\nTalos is built with Go 1.19.3.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Andrey Smirnov\n* Michal Witkowski\n* Artem Chernyshev\n* Artem Chernyshev\n* Dmitriy Matrenichev\n* Alexey Palazhchenko\n* Serge Logvinov\n* Andrey Smirnov\n* Philipp Sauter\n* Andrew Rynhard\n* Steve Francis\n* Utku Ozdemir\n* Andrew Rynhard\n* Tim Jones\n* Seán C McCord\n* Kris Reeves\n* Marvin Drees\n* Spencer Smith\n* Branden Cash\n* Brandon Nason\n* Cameron Brunner\n* DJAlPee\n* Daniel Low\n* Gerard de Leeuw\n* Jack Wink\n* Jon Stelly\n* Martin Stone\n* Matt Zahorik\n* Maxim Makarov\n* Olli Janatuinen\n* Pau Campana\n* Rubens Farias\n* Sander Maijers\n* Spencer Smith\n* ankitm123\n* emattiza\n* killcity\n\n### Changes\n<details><summary>173 commits</summary>\n<p>\n\n* [`aa56aed79`](https://github.com/siderolabs/talos/commit/aa56aed7981b4bdb29a5f668296597cf4a5c1d3b) feat: publish discovered public IP as one of the KubeSpan endpoint\n* [`9382443ba`](https://github.com/siderolabs/talos/commit/9382443baa8005f84aa177c6dbeb68b995d09084) feat: update Kubernetes to v1.26.0-rc.0\n* [`6ffc381c5`](https://github.com/siderolabs/talos/commit/6ffc381c59b919a3d922a99f896f601cf4f6898a) feat: implement CRI configuration customization\n* [`e1e340bdd`](https://github.com/siderolabs/talos/commit/e1e340bdd910dc1f9c7fd08f71fb14352e96dbbf) feat: expose Talos node labels as a machine configuration field\n* [`c78bbbfda`](https://github.com/siderolabs/talos/commit/c78bbbfda3d545c3f50e0ad141369279dd2f4ca0) docs: specify that only XFS partitions are detected\n* [`b881a9a79`](https://github.com/siderolabs/talos/commit/b881a9a795937ba0c5d94ee4104209652bb992ab) chore: bump dependencies\n* [`5bfd7dbfa`](https://github.com/siderolabs/talos/commit/5bfd7dbfa75c2d9b4ec4d6a61b2da91e72113a71) test: fix assertion on reboot test\n* [`1cfb6188b`](https://github.com/siderolabs/talos/commit/1cfb6188bcc2aefaa0b4f707f16053a8a1fd9a28) feat: implement support for cgroupsv1\n* [`3866d0e33`](https://github.com/siderolabs/talos/commit/3866d0e334cd4d8146cdc8d17196d7f7aa4877a5) feat: update Kubernetes to v1.26.0-beta.0\n* [`e1590ba7b`](https://github.com/siderolabs/talos/commit/e1590ba7b9f0c1b0be9b78a1dd4381f2d2e90e57) fix: lifecycle action tracking\n* [`804762c59`](https://github.com/siderolabs/talos/commit/804762c597f3aebdc3521cefc93bbbf0ff4a57eb) feat: add timeout to cli action tracking, track by default & refactor\n* [`4e114ca12`](https://github.com/siderolabs/talos/commit/4e114ca120a1ee7de5a5822dba14c732f1dc7610) feat: use the etcd member id for etcd operations instead of hostname\n* [`06fea2441`](https://github.com/siderolabs/talos/commit/06fea244140e82fd30a4ac4c5e4433253bd930ab) feat: expand platform metadata resources\n* [`03a20da9d`](https://github.com/siderolabs/talos/commit/03a20da9da5916c63015d355f4b56823778e994f) fix: filter up duplicate IPs out of NodeAddresses\n* [`6b771bc73`](https://github.com/siderolabs/talos/commit/6b771bc73984d755dce06bd5452131add5ecf487) chore: bump deps\n* [`96aa9638f`](https://github.com/siderolabs/talos/commit/96aa9638f724d81ba8ef64db0ed7032694e7da5d) chore: rename talos-systems/talos to siderolabs/talos\n* [`30bbf6463`](https://github.com/siderolabs/talos/commit/30bbf6463a85c10b4273633e928b6c419731e31d) refactor: use siderolabs/net version with netip.Addr\n* [`343c55762`](https://github.com/siderolabs/talos/commit/343c55762e4af279ceeb0066540124ef66c77602) chore: replace talos-systems Go modules with siderolabs\n* [`0301bbe93`](https://github.com/siderolabs/talos/commit/0301bbe9369eb2811aa9d5177fcc024606c71ed4) fix: check if processes is nil to avoid panic\n* [`08e7e49a2`](https://github.com/siderolabs/talos/commit/08e7e49a29018ed1932709779349a8c056125090) test: update versions for upgrade tests\n* [`0b41923c3`](https://github.com/siderolabs/talos/commit/0b41923c3608a815d14bccd84a6abcf1bc99db43) fix: restore the StaticPodStatus resource\n* [`1947092ae`](https://github.com/siderolabs/talos/commit/1947092ae225abe408c1b2c20633af671ae9c2a2) chore: introduce a healthcheck for `machined` service\n* [`3333cd93c`](https://github.com/siderolabs/talos/commit/3333cd93c821b00bd523584509075d21e2ec16be) fix: generate correct Flannel config for IPv6-only clusters\n* [`d7070f5e7`](https://github.com/siderolabs/talos/commit/d7070f5e7498f56e644e07402ed30933047b6f8e) release(v1.3.0-alpha.1): prepare release\n* [`869f3b5a5`](https://github.com/siderolabs/talos/commit/869f3b5a51ac783e8b0a5a31a103c212a068672b) feat: network configuration improvements on the OpenStack platform\n* [`29f2195e1`](https://github.com/siderolabs/talos/commit/29f2195e130ecf66a911d0c75343486ee7c86046) feat: support exoscale cloud\n* [`8b4ae08d1`](https://github.com/siderolabs/talos/commit/8b4ae08d1c42a2cab4bbf0daac090e0882b5d4e9) fix: etcd snapshot command on Windows\n* [`8bfa7ac1d`](https://github.com/siderolabs/talos/commit/8bfa7ac1d6012746bf7264528eac5cacdd752e2b) feat: platform metadata resource\n* [`7e50e24c0`](https://github.com/siderolabs/talos/commit/7e50e24c0187e514876222857d44eedda79acc5a) fix: properly cleanup legacy static pod manifests directory\n* [`6ee47bcc6`](https://github.com/siderolabs/talos/commit/6ee47bcc61bd5b8684c43c0d8c020c574631c832) fix: support serving config for qemu launcher on IPv6\n* [`6c3d11b49`](https://github.com/siderolabs/talos/commit/6c3d11b49e94b33ccfdf29f93d3233e480b5e7f0) docs: admission control patch note\n* [`4ea3b99b5`](https://github.com/siderolabs/talos/commit/4ea3b99b527406b0bbf9cbfd22867431b143ed49) fix: serve static pod files on 127.0.0.1 instead of localhost\n* [`23842114f`](https://github.com/siderolabs/talos/commit/23842114f077d98cf7bdbf8912454623dff41bbb) feat: support encryption with secretbox\n* [`f6773c472`](https://github.com/siderolabs/talos/commit/f6773c472c0c1094045a26e34be2472a98dad510) docs: talos support on equinix metal\n* [`b307160f6`](https://github.com/siderolabs/talos/commit/b307160f613f2544c70be115c9a1ae0a7439ec52) chore: bump dependencies\n* [`d7edd0e2e`](https://github.com/siderolabs/talos/commit/d7edd0e2e6ec5e4cba8bfa119d244c7be09078d9) refactor: use go-circular, go-kubeconfig, and go-tail\n* [`c6e1702ec`](https://github.com/siderolabs/talos/commit/c6e1702eca2d310f6fad52e0f00bc91d7d6c4996) feat: use URL-based manifests to present static pods to the kubelet\n* [`136a795e5`](https://github.com/siderolabs/talos/commit/136a795e55b5be5f093aaf6b07039e86df971674) docs: update system requirements to mention dedicated disk usage\n* [`879e8c0bf`](https://github.com/siderolabs/talos/commit/879e8c0bfe31f6b35f8833cf55624cd934ded50b) chore: update kernel with BTF support\n* [`ceb0cd99a`](https://github.com/siderolabs/talos/commit/ceb0cd99ae0e29cadf69e121afdc439f3296ff74) feat: implement Talos API auth using SideroV1 signatures\n* [`e6fba7d3b`](https://github.com/siderolabs/talos/commit/e6fba7d3bc83d008518d7a032b309ddd212e0f81) chore: update dependencies\n* [`93e55b85f`](https://github.com/siderolabs/talos/commit/93e55b85f207060d053ba9f16267d98c2599a2df) chore: bump golangci-lint to v1.50.0\n* [`aa3d9b4ca`](https://github.com/siderolabs/talos/commit/aa3d9b4ca60f0a7e47867e1de134753eb914606b) fix: regenerate cert on node labeling retry\n* [`021c73c35`](https://github.com/siderolabs/talos/commit/021c73c35233ee5e6cb9cf5e83336eeb70ae05d3) fix: lowercase nodename\n* [`b902036e1`](https://github.com/siderolabs/talos/commit/b902036e12843d6348d945097d3826a50b040b25) docs: update office hours time link\n* [`7fcb8c681`](https://github.com/siderolabs/talos/commit/7fcb8c68164d72f14bca284daffc69605002acb5) feat: update Flannel to v0.20.0\n* [`dc70d892a`](https://github.com/siderolabs/talos/commit/dc70d892a341f0694be0c0ff5517b63ea6bbadd9) fix: support setting KubeSpan link MTU\n* [`7d52bad37`](https://github.com/siderolabs/talos/commit/7d52bad370d544d1a2862891e089426dff7c52a3) feat: update Linux to 5.15.73\n* [`9c78b3aff`](https://github.com/siderolabs/talos/commit/9c78b3aff48fd95f48ab2c951f7eb61273338e9a) feat: update Kubernetes to v1.26.0-alpha.2\n* [`94913a672`](https://github.com/siderolabs/talos/commit/94913a6727e9a802d2e14c141a831a8fddc8d9b2) docs: add lofty to talos adopters\n* [`0a0bdfe16`](https://github.com/siderolabs/talos/commit/0a0bdfe164625013e807cf5a08f590835894bf92) docs: add Tremor Video to adopters\n* [`b7b1d4fd6`](https://github.com/siderolabs/talos/commit/b7b1d4fd6a492c8e4c73b9f7f17449241903f868) feat: use readonly containers\n* [`d210338e3`](https://github.com/siderolabs/talos/commit/d210338e33438919fc8d2d83fc479981077d5164) fix: skip protobuf full unmarshaling for some talosctl commands\n* [`b3c679d18`](https://github.com/siderolabs/talos/commit/b3c679d18e698092795725e6fcb05d6569d681b1) chore: bump dependencies\n* [`993743f63`](https://github.com/siderolabs/talos/commit/993743f63495a59020670619abde5a0d5cd322e2) fix: skip hostname via DHCP on OpenStack platform\n* [`db076e7b5`](https://github.com/siderolabs/talos/commit/db076e7b5afca7c725c4c6876a7e05d643a219a1) feat: pin interface by mac address in cmdline args\n* [`63de93722`](https://github.com/siderolabs/talos/commit/63de937227362064a05fa3a9ba11f55891458cc7) fix: update go-smbios to v0.3.1\n* [`49e9f808e`](https://github.com/siderolabs/talos/commit/49e9f808e7b14af90959c7fca9457128e82f9cb5) chore: bump kernel and go\n* [`c7372144d`](https://github.com/siderolabs/talos/commit/c7372144de4b953ebe2494676143ea6d0e53e666) docs: add constraints to upgrade docs\n* [`c71c8ca18`](https://github.com/siderolabs/talos/commit/c71c8ca18fd4bb7dcae2f69ea253c16b9abd7a9d) docs: consolidate, simplify and correct various docs\n* [`06f76bfeb`](https://github.com/siderolabs/talos/commit/06f76bfebb14e7d826b8c7efe4564a94d841a74a) chore: bump dependencies\n* [`b1c421b9a`](https://github.com/siderolabs/talos/commit/b1c421b9ad90d36e8a3562aacdcc30c521da585a) chore: publish ami's with imds v2 enabled\n* [`195c40ab5`](https://github.com/siderolabs/talos/commit/195c40ab5908c3bcd0c8ecf5b6f7275bb9b7a499) docs: add information about applicable use cases of disk encryption\n* [`54a687fb8`](https://github.com/siderolabs/talos/commit/54a687fb8e68f3669ff140d37ff3fd01595a494d) docs: consolidate and expand on discovery service\n* [`139c62d76`](https://github.com/siderolabs/talos/commit/139c62d762c2a9001808d4e1bed38145ea86a95d) feat: allow upgrades in maintenance mode (only over SideroLink)\n* [`48dee4805`](https://github.com/siderolabs/talos/commit/48dee480577c9d1bb4620f78c6b4bbeba0f0d0bc) feat: support mtu for routes\n* [`1c43c72ae`](https://github.com/siderolabs/talos/commit/1c43c72aebd1a2bcc1991787dcd94c8bab00df42) docs: fix talos required kernel params\n* [`67cc45ae3`](https://github.com/siderolabs/talos/commit/67cc45ae3f9351cf5ae27c2c1a4c5d762a2d8b77) release(v1.3.0-alpha.0): prepare release\n* [`18c377a4d`](https://github.com/siderolabs/talos/commit/18c377a4d1ce046b310e3609033e9c1f39f9337b) feat: customize audit policy\n* [`23c9ea46b`](https://github.com/siderolabs/talos/commit/23c9ea46bba20d8b7cc336bbc64e04af46cccf5d) fix: raspberry pi install\n* [`f17cdee16`](https://github.com/siderolabs/talos/commit/f17cdee167cfd6d673e2ed71fd5c8d28399a80f3) feat: jsonpath filter for talosctl get outputs\n* [`6bd3cca1a`](https://github.com/siderolabs/talos/commit/6bd3cca1a8d206fb40199a9f0352aa2670fca754) chore: generic raspberry pi images\n* [`d914ab8bb`](https://github.com/siderolabs/talos/commit/d914ab8bb4a34cdb5ffc396a20a32a437c5989e1) chore: add vulncheck tool as a linter\n* [`a0151aa13`](https://github.com/siderolabs/talos/commit/a0151aa13e63b24aba7e39082f6cef3dac923a22) feat: add generic rpi u-boot support\n* [`30f851d09`](https://github.com/siderolabs/talos/commit/30f851d0931f5d6767e13142876c94dac67ec38b) chore: bump dependences\n* [`8b2235c3b`](https://github.com/siderolabs/talos/commit/8b2235c3b6de64abb15bf77e9648bf6bebc18e1f) fix: lookup Equinix Metal bond slaves using 'permanent addr'\n* [`b3257ebb1`](https://github.com/siderolabs/talos/commit/b3257ebb1c529a8f266ba3852d5e4191e0261a79) chore: bump kernel to 5.15.70\n* [`0b2767c16`](https://github.com/siderolabs/talos/commit/0b2767c1646e84ce147030692f3904b9feb02b3e) feat: implement 'permanent addr' in link statuses\n* [`c90e20251`](https://github.com/siderolabs/talos/commit/c90e20251d09a9bedcbd8b1a2055de5e126fc97e) fix: kubeconfig permission\n* [`fc48849d0`](https://github.com/siderolabs/talos/commit/fc48849d00c185442fb37c72e2c20462cc573a69) chore: move maps/slices/ordered to gen module\n* [`8b09bd4b0`](https://github.com/siderolabs/talos/commit/8b09bd4b0400f17ef543f0d117ae35e4ba2356cb) feat: update Kubernetes to v1.26.0-alpha.1\n* [`276d4175b`](https://github.com/siderolabs/talos/commit/276d4175bbd168d12409a1e96b191abdf09f2ff0) chore: bump extension versions in testing\n* [`357b770cb`](https://github.com/siderolabs/talos/commit/357b770cb593196fccaf9b6ba3cd740463351a07) fix: cryptsetup delete slot\n* [`711128839`](https://github.com/siderolabs/talos/commit/7111288393ae4dfdfa7331e39df1803724bc93c0) fix: continue applying bootstrap manifests on some errors\n* [`ce12c7b38`](https://github.com/siderolabs/talos/commit/ce12c7b3805da65315309a465aeed1764f0ce20a) chore: update COSI runtime to v0.2.0-alpha.1\n* [`1b435c0b3`](https://github.com/siderolabs/talos/commit/1b435c0b36a8d0d3e48c5a5e6121117933deeb69) chore: bump kernel + ice drivers\n* [`18e041f1e`](https://github.com/siderolabs/talos/commit/18e041f1ecb88d0b1e8e874d9b1fb580bc7c2297) docs: fix typo in patching example\n* [`0ad6452ca`](https://github.com/siderolabs/talos/commit/0ad6452ca152afef2f3c0e97a2255a237b30941a) feat: update CoreDNS to v1.10.0\n* [`479f3f52e`](https://github.com/siderolabs/talos/commit/479f3f52ee7149ff2a39bec3d8f78b59978af70a) chore: bump dependencies\n* [`e07c6ae99`](https://github.com/siderolabs/talos/commit/e07c6ae99ec347735cf0316294ef0c54ebc45234) feat: update Kubernetes to v1.25.1\n* [`13fdfaffc`](https://github.com/siderolabs/talos/commit/13fdfaffc4a0eb812cd63c5d188efd4aff6da51c) test: fix up default branch name\n* [`ef181321a`](https://github.com/siderolabs/talos/commit/ef181321a5be4d03e4f87aab1483b95a8e61f0fe) docs: add component diagram; K8s & Talos Linux\n* [`aade73643`](https://github.com/siderolabs/talos/commit/aade7364357da6644e8b70ad1dd939130f2fe470) docs: fix missing variable in OpenEBS docs\n* [`472590aa8`](https://github.com/siderolabs/talos/commit/472590aa82d16e1bd3825ecc8106886e7e1b9053) chore: return InvalidArgument on invalid config in maintenance mode\n* [`e5cabd42c`](https://github.com/siderolabs/talos/commit/e5cabd42cc7f86bee5486f73fa4068382bf6a7fb) feat: enable etcd consistency hashcheck\n* [`015535d90`](https://github.com/siderolabs/talos/commit/015535d9051dea243f439b385577d17fd57a122e) fix: update discovery client with the redirect fix\n* [`d0c8e7699`](https://github.com/siderolabs/talos/commit/d0c8e7699cf3e2415c5712ff9ff620c38857a0dc) chore: bump kernel and go\n* [`985b0c2e7`](https://github.com/siderolabs/talos/commit/985b0c2e796006f401376ebf30a1ce888d90a1c9) chore: remove go.work.sum\n* [`69124f102`](https://github.com/siderolabs/talos/commit/69124f10263bdabc556b58b98a3e1f129b85b8ab) feat: update etcd to v3.5.5\n* [`1985a796c`](https://github.com/siderolabs/talos/commit/1985a796c0d5a984c397754445b33827f5690806) docs: update docs for pod security\n* [`94b088f02`](https://github.com/siderolabs/talos/commit/94b088f02f8f8e5b63f0c38e8e091f2ba3329dde) fix: set etcd options consistently\n* [`92ae7ef4b`](https://github.com/siderolabs/talos/commit/92ae7ef4b1abe0a510fea31e0fde2566281f38b1) fix: fix protoenc encoding for enums and types with custom encoders\n* [`93809017c`](https://github.com/siderolabs/talos/commit/93809017c594b1faf1405932d884852eb0ce567c) docs: cpu scaling governor knowledgebase\n* [`7b270ff33`](https://github.com/siderolabs/talos/commit/7b270ff33d6bf74d1fa195c07f98233098b337e9) test: fix api controller test\n* [`2dadcd669`](https://github.com/siderolabs/talos/commit/2dadcd6695003eb940848583caa6ade53ef94fa0) fix: stop worker nodes from acting as apid routers\n* [`9eaf33f3f`](https://github.com/siderolabs/talos/commit/9eaf33f3f274e746ca1b442c0a1a0dae0cec088f) fix: never sign client certificate requests in trustd\n* [`436749124`](https://github.com/siderolabs/talos/commit/43674912479d3fb58c30e350fea9c4daf4ba45d4) feat: environment vars for extension service\n* [`0c0cb671e`](https://github.com/siderolabs/talos/commit/0c0cb671ead1f514b1f1eb89e8d78f455e1efedb) chore: mark machine configuration validation failure as InvalidArgument\n* [`f424e5340`](https://github.com/siderolabs/talos/commit/f424e53404db61bbdbcbe8fab7cfec91785aa628) fix: stop containers more thoroughly\n* [`12827b861`](https://github.com/siderolabs/talos/commit/12827b861c13bb9b83a2f0ea2960582e8be319f0) chore: move \"implements\" checks to compile time\n* [`3a67c42cb`](https://github.com/siderolabs/talos/commit/3a67c42cbfdbd565e0af500d97c264ef6095637b) fix: kill the task processes when cleaning up stale task\n* [`14a79e325`](https://github.com/siderolabs/talos/commit/14a79e325bf0ffa107aaee9c07d3501b7010693c) chore: bump dependencies\n* [`9beee92e7`](https://github.com/siderolabs/talos/commit/9beee92e71e712a2af24dee612e27c30cac39d0d) docs: fix double vv in Kubernetes version\n* [`688272515`](https://github.com/siderolabs/talos/commit/6882725157f4c2ea79c248f79160e362be6c2c07) fix: use different username for Talos Kubernetes API access\n* [`161a52a9e`](https://github.com/siderolabs/talos/commit/161a52a9ef60eb9c1c1a6c31b06d06894456300c) feat: check apid client certificate extended key usage\n* [`9dadc4a59`](https://github.com/siderolabs/talos/commit/9dadc4a599f52cc564f5411dd35bc981e482d24a) fix: include all node addresses into etcd cert SANs\n* [`71bfd3e43`](https://github.com/siderolabs/talos/commit/71bfd3e43cdc9790d3cb7a134c3b49256b1942a1) feat: update CoreDNS to 1.9.4\n* [`9df8f1ff1`](https://github.com/siderolabs/talos/commit/9df8f1ff1aebb24a6b0649ba491b10b23a0b2198) fix: list COSI APIs for the apid authenticator\n* [`31462450f`](https://github.com/siderolabs/talos/commit/31462450f19700dd6691ebc4b0c18edca4f6a1b7) fix: pass a pointer to specs.Mount into protoenc.Marshal\n* [`e626540df`](https://github.com/siderolabs/talos/commit/e626540dfb470386d0750f2f8bbaf4b5cb36b203) chore: avoid double API request logging in trustd\n* [`f62d17125`](https://github.com/siderolabs/talos/commit/f62d17125b8c1b26b0b62d22c2846f3a2ece37d1) chore: update crypto to use new import path siderolabs/crypto\n* [`ef27dd855`](https://github.com/siderolabs/talos/commit/ef27dd8553ee0e5467c3baaf4be18d1ccb30dad1) chore: bump dependencies\n* [`6472ae00b`](https://github.com/siderolabs/talos/commit/6472ae00b21c0f637b1e6610a8f3f71a1b775628) fix: automatically discard VIPs for etcd advertised addresses\n* [`5e21cca52`](https://github.com/siderolabs/talos/commit/5e21cca52d7462240bb42aafa225ee97d08bdc25) feat: support setting kernel parameters\n* [`bd56621cd`](https://github.com/siderolabs/talos/commit/bd56621cdf50d25013756a8792dc7b4d5354396f) feat: add structprotogen tool\n* [`cdb6bb2cc`](https://github.com/siderolabs/talos/commit/cdb6bb2cc78685c218506c61a477c8a8e569e861) feat: add Nano Pi R4S support\n* [`36c1f1d6e`](https://github.com/siderolabs/talos/commit/36c1f1d6e6aa50379343acba5348d8cc038b137e) fix: flip the client-server version check\n* [`cd6c53a97`](https://github.com/siderolabs/talos/commit/cd6c53a979236543afc302a67da627ee633883b3) docs: fork docs for v1.3\n* [`0847400f7`](https://github.com/siderolabs/talos/commit/0847400f728d67889b9f740a0359eb916108d8ea) fix: prevent panic on health check if a member has no IPs\n* [`7471d7f01`](https://github.com/siderolabs/talos/commit/7471d7f0174a5240fa3c4cd2f16325ec2a4f1810) feat: update Flannel to v0.19.2\n* [`148c75cfb`](https://github.com/siderolabs/talos/commit/148c75cfb99537f64d43a3add3259bf591cb79a9) docs: consolidate the control-plane documentation\n* [`353154281`](https://github.com/siderolabs/talos/commit/353154281a4cf72076b99160e50e617109f72996) fix: drop kube-system SA default binding\n* [`4f37b668b`](https://github.com/siderolabs/talos/commit/4f37b668befdbd26bc2d32106e0bcc654f7e6119) chore: remove capi hacks\n* [`1369afea8`](https://github.com/siderolabs/talos/commit/1369afea853423f22fde20effd431c3f8d906a9d) docs: make 1.2.0 docs default ones\n* [`7627cb0e3`](https://github.com/siderolabs/talos/commit/7627cb0e30a8b2a5a1cc30906b547511c9d3c98b) docs: add new `talosctl gen secrets`\n* [`8aa60a37a`](https://github.com/siderolabs/talos/commit/8aa60a37a6ea57bf54d558c7a2f54d806fad3173) chore: bump kernel to 5.15.64\n* [`a798dbd5d`](https://github.com/siderolabs/talos/commit/a798dbd5d2d9bc6d1410a56035550d44de934950) docs: update docs for upcoming 1.2.0 release\n* [`b2fec3c97`](https://github.com/siderolabs/talos/commit/b2fec3c975dba7b0bc2dc7d5447e62350057061b) fix: properly handle `configContext` being `nil` in Talos client\n* [`1c0977b3a`](https://github.com/siderolabs/talos/commit/1c0977b3af22f9f4b61b80ca6dcedf14a5ef63ae) fix: change the type of returned gRPC connection object from the client\n* [`41848e421`](https://github.com/siderolabs/talos/commit/41848e421496184008ad2302e3cb03a882c0f5bf) fix: expose Talos client gRPC connection via the function `Conn`\n* [`2e9be4af8`](https://github.com/siderolabs/talos/commit/2e9be4af8b521eca985c425f62dfc7a59d19e7da) chore: bump dependencies\n* [`d283aba3a`](https://github.com/siderolabs/talos/commit/d283aba3a3670cfde8ab9137deba3ab3b343906f) test: fix cli reboot test\n* [`0b339a9dc`](https://github.com/siderolabs/talos/commit/0b339a9dc508327347777619749ff1e2c3e47f37) feat: track progress of action API calls\n* [`072349812`](https://github.com/siderolabs/talos/commit/072349812506c5cd32159bb14bab5b294ee59811) fix: update COSI to the version with gRPC Wait fix\n* [`89d57aa81`](https://github.com/siderolabs/talos/commit/89d57aa816a57448d6e350698a8f6a5d128209ac) fix: always abort the maintenance service\n* [`f6fa74619`](https://github.com/siderolabs/talos/commit/f6fa7461932462160f40f670a5252fbc2981bdc3) fix: limit apid backoff max delay\n* [`d7ef346db`](https://github.com/siderolabs/talos/commit/d7ef346db8ea7d4f7676ae5e032a3c0d06823d47) fix: get command in the case 'nodes' are not set in the context\n* [`4e9c32256`](https://github.com/siderolabs/talos/commit/4e9c322564d7f65c82d636a9f80c0c5354455967) fix: correctly render hosts.toml with multiple endpoints\n* [`cdd0f08bc`](https://github.com/siderolabs/talos/commit/cdd0f08bc5d8d47bc2d21745ee5a13ced3632c8a) feat: check client <> server version in some Talos commands\n* [`446b0af58`](https://github.com/siderolabs/talos/commit/446b0af58bf273712374472bfa2777de5b7ac46f) chore: bump kernel and runc\n* [`8c203ce9b`](https://github.com/siderolabs/talos/commit/8c203ce9b1722c5832c506857cb56e14e2a34fe1) feat: remove the machine from the discovery service on reset\n* [`b59ca5810`](https://github.com/siderolabs/talos/commit/b59ca5810e6cf75f6a3042a47535431110004201) chore: move from inet.af/netaddr to net/netip and go4.org/netipx\n* [`053af1d59`](https://github.com/siderolabs/talos/commit/053af1d59ea266b84bb049460f92b33b32c1b82e) fix: update etcd certificates when node addresses changes\n* [`11edb2c6f`](https://github.com/siderolabs/talos/commit/11edb2c6f84fbbfba437361ce4dcd70c50eb08d8) test: re-enable upgrade tests\n* [`0310e2089`](https://github.com/siderolabs/talos/commit/0310e20890b11e1f4015e923eb9984aea1188d20) chore: bump github.com/siderolabs/protoenc to v0.1.5\n* [`29bd63240`](https://github.com/siderolabs/talos/commit/29bd632401ca694df0a2ab921a2a525b4c3440d8) chore: remove old build tags syntax\n* [`b500d0aa9`](https://github.com/siderolabs/talos/commit/b500d0aa9052ab5066eb6cde06bcdac3e998705a) chore: bump k8s to v1.25.0\n* [`29e574be7`](https://github.com/siderolabs/talos/commit/29e574be74c96211fd010ee5bd06675898f04db8) docs: update to v1.2.0-beta.1\n* [`26b549f2a`](https://github.com/siderolabs/talos/commit/26b549f2a12c3486b52a8877b8a0a4f985695c7d) chore: bump dependencies\n* [`8c3ac4c42`](https://github.com/siderolabs/talos/commit/8c3ac4c42bff1f1678ddb62e0f20a9c419460ad4) chore: limit GOMAXPROCS for Talos services\n* [`361e85b74`](https://github.com/siderolabs/talos/commit/361e85b7443f6f4ff24fbf99a9f9276b73b73ed4) fix: properly read kexec disabled sysctl\n* [`cfe6c2bc2`](https://github.com/siderolabs/talos/commit/cfe6c2bc2d42ca28f3a5b3217aa4d126777e3db6) docs: nvidia oss drivers\n* [`2f2d97b6b`](https://github.com/siderolabs/talos/commit/2f2d97b6b5663a0873db9d47b7706f2c0a531d8c) fix: don't wait for the hostname in maintenance mode\n* [`b15a63924`](https://github.com/siderolabs/talos/commit/b15a6392465aa2aa0df231c622ca1762972ccd20) chore: bump kernel to 5.15.62\n* [`a0d94be30`](https://github.com/siderolabs/talos/commit/a0d94be30d3dcf41b2b8b34a1caa6928a029f81a) fix: stable default hostname bias\n* [`da4cd34ef`](https://github.com/siderolabs/talos/commit/da4cd34ef5c5a01cfc3c3ee56b3f8c2f77997b49) feat: update etcd advertised peer addresses on the fly\n* [`faf92ce01`](https://github.com/siderolabs/talos/commit/faf92ce01661c5a9a86f9e579da3a2822d93f1f6) chore: bump kubernetes to v1.25.0-rc.1\n* [`52de919e3`](https://github.com/siderolabs/talos/commit/52de919e34789c36c4ee71ca133240b50b068064) chore: bump containerd to v1.6.8\n* [`7d43fc79b`](https://github.com/siderolabs/talos/commit/7d43fc79b1e913d51f111ecc7c2c8b3bfb36e679) fix: make 'ca', 'crt' and 'key' flags optional for 'talosctl config add'\n* [`fd467e02c`](https://github.com/siderolabs/talos/commit/fd467e02c1edcfc0eff656392ece5dd8ba1114f2) fix: handle grub config being empty in the `Revert` function\n* [`9492aca65`](https://github.com/siderolabs/talos/commit/9492aca652eec4d4049fef1c8d141696ed72a197) fix: clean up `cancelCtxMu` leftovers in PriorityLock\n* [`61e3eb2ea`](https://github.com/siderolabs/talos/commit/61e3eb2eaab1c7974a27440ddd98139a27dfb9dc) fix: talosctl edit mc loop\n* [`32db7a7f5`](https://github.com/siderolabs/talos/commit/32db7a7f5d6638fc0f731a009dfb0c1870c69083) fix: surround `cancelCtx` with the mutex\n</p>\n</details>\n\n### Changes since v1.3.0-alpha.1\n<details><summary>23 commits</summary>\n<p>\n\n* [`aa56aed79`](https://github.com/siderolabs/talos/commit/aa56aed7981b4bdb29a5f668296597cf4a5c1d3b) feat: publish discovered public IP as one of the KubeSpan endpoint\n* [`9382443ba`](https://github.com/siderolabs/talos/commit/9382443baa8005f84aa177c6dbeb68b995d09084) feat: update Kubernetes to v1.26.0-rc.0\n* [`6ffc381c5`](https://github.com/siderolabs/talos/commit/6ffc381c59b919a3d922a99f896f601cf4f6898a) feat: implement CRI configuration customization\n* [`e1e340bdd`](https://github.com/siderolabs/talos/commit/e1e340bdd910dc1f9c7fd08f71fb14352e96dbbf) feat: expose Talos node labels as a machine configuration field\n* [`c78bbbfda`](https://github.com/siderolabs/talos/commit/c78bbbfda3d545c3f50e0ad141369279dd2f4ca0) docs: specify that only XFS partitions are detected\n* [`b881a9a79`](https://github.com/siderolabs/talos/commit/b881a9a795937ba0c5d94ee4104209652bb992ab) chore: bump dependencies\n* [`5bfd7dbfa`](https://github.com/siderolabs/talos/commit/5bfd7dbfa75c2d9b4ec4d6a61b2da91e72113a71) test: fix assertion on reboot test\n* [`1cfb6188b`](https://github.com/siderolabs/talos/commit/1cfb6188bcc2aefaa0b4f707f16053a8a1fd9a28) feat: implement support for cgroupsv1\n* [`3866d0e33`](https://github.com/siderolabs/talos/commit/3866d0e334cd4d8146cdc8d17196d7f7aa4877a5) feat: update Kubernetes to v1.26.0-beta.0\n* [`e1590ba7b`](https://github.com/siderolabs/talos/commit/e1590ba7b9f0c1b0be9b78a1dd4381f2d2e90e57) fix: lifecycle action tracking\n* [`804762c59`](https://github.com/siderolabs/talos/commit/804762c597f3aebdc3521cefc93bbbf0ff4a57eb) feat: add timeout to cli action tracking, track by default & refactor\n* [`4e114ca12`](https://github.com/siderolabs/talos/commit/4e114ca120a1ee7de5a5822dba14c732f1dc7610) feat: use the etcd member id for etcd operations instead of hostname\n* [`06fea2441`](https://github.com/siderolabs/talos/commit/06fea244140e82fd30a4ac4c5e4433253bd930ab) feat: expand platform metadata resources\n* [`03a20da9d`](https://github.com/siderolabs/talos/commit/03a20da9da5916c63015d355f4b56823778e994f) fix: filter up duplicate IPs out of NodeAddresses\n* [`6b771bc73`](https://github.com/siderolabs/talos/commit/6b771bc73984d755dce06bd5452131add5ecf487) chore: bump deps\n* [`96aa9638f`](https://github.com/siderolabs/talos/commit/96aa9638f724d81ba8ef64db0ed7032694e7da5d) chore: rename talos-systems/talos to siderolabs/talos\n* [`30bbf6463`](https://github.com/siderolabs/talos/commit/30bbf6463a85c10b4273633e928b6c419731e31d) refactor: use siderolabs/net version with netip.Addr\n* [`343c55762`](https://github.com/siderolabs/talos/commit/343c55762e4af279ceeb0066540124ef66c77602) chore: replace talos-systems Go modules with siderolabs\n* [`0301bbe93`](https://github.com/siderolabs/talos/commit/0301bbe9369eb2811aa9d5177fcc024606c71ed4) fix: check if processes is nil to avoid panic\n* [`08e7e49a2`](https://github.com/siderolabs/talos/commit/08e7e49a29018ed1932709779349a8c056125090) test: update versions for upgrade tests\n* [`0b41923c3`](https://github.com/siderolabs/talos/commit/0b41923c3608a815d14bccd84a6abcf1bc99db43) fix: restore the StaticPodStatus resource\n* [`1947092ae`](https://github.com/siderolabs/talos/commit/1947092ae225abe408c1b2c20633af671ae9c2a2) chore: introduce a healthcheck for `machined` service\n* [`3333cd93c`](https://github.com/siderolabs/talos/commit/3333cd93c821b00bd523584509075d21e2ec16be) fix: generate correct Flannel config for IPv6-only clusters\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>27 commits</summary>\n<p>\n\n* [`c3225ee`](https://github.com/siderolabs/crypto/commit/c3225eee603a8d1218c67e1bfe33ddde7953ed74) feat: allow CSR template subject field to be overridden\n* [`8570669`](https://github.com/siderolabs/crypto/commit/85706698dac8cddd0e9f41006bed059347d2ea26) chore: rename to siderolabs/crypto\n* [`e9df1b8`](https://github.com/siderolabs/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n* [`510b0d2`](https://github.com/siderolabs/crypto/commit/510b0d2753a89170d0c0f60e052a66484997a5b2) chore: add json tags\n* [`6fa2d93`](https://github.com/siderolabs/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n* [`9a63cba`](https://github.com/siderolabs/crypto/commit/9a63cba8dabd278f3080fa8c160613efc48c43f8) fix: add back support for generating ECDSA keys with P-256 and SHA512\n* [`893bc66`](https://github.com/siderolabs/crypto/commit/893bc66e4716a4cb7d1d5e66b5660ffc01f22823) fix: use SHA256 for ECDSA-P256\n* [`deec8d4`](https://github.com/siderolabs/crypto/commit/deec8d47700e10e3ea813bdce01377bd93c83367) chore: implement DeepCopy methods for PEMEncoded* types\n* [`d3cb772`](https://github.com/siderolabs/crypto/commit/d3cb77220384b3a3119a6f3ddb1340bbc811f1d1) feat: make possible to change KeyUsage\n* [`6bc5bb5`](https://github.com/siderolabs/crypto/commit/6bc5bb50c52767296a1b1cab6580e3fcf1358f34) chore: remove unused argument\n* [`cd18ef6`](https://github.com/siderolabs/crypto/commit/cd18ef62eb9f65d8b6730a2eb73e47e629949e1b) feat: add support for several organizations\n* [`97c888b`](https://github.com/siderolabs/crypto/commit/97c888b3924dd5ac70b8d30dd66b4370b5ab1edc) chore: add options to CSR\n* [`7776057`](https://github.com/siderolabs/crypto/commit/7776057f5086157873f62f6a21ec23fa9fd86e05) chore: fix typos\n* [`80df078`](https://github.com/siderolabs/crypto/commit/80df078327030af7e822668405bb4853c512bd7c) chore: remove named result parameters\n* [`15bdd28`](https://github.com/siderolabs/crypto/commit/15bdd282b74ac406ab243853c1b50338a1bc29d0) chore: minor updates\n* [`4f80b97`](https://github.com/siderolabs/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n* [`39584f1`](https://github.com/siderolabs/crypto/commit/39584f1b6e54e9966db1f16369092b2215707134) feat: support for key/certificate types RSA, Ed25519, ECDSA\n* [`cf75519`](https://github.com/siderolabs/crypto/commit/cf75519cab82bd1b128ae9b45107c6bb422bd96a) fix: function NewKeyPair should create certificate with proper subject\n* [`751c95a`](https://github.com/siderolabs/crypto/commit/751c95aa9434832a74deb6884cff7c5fd785db0b) feat: add 'PEMEncodedKey' which allows to transport keys in YAML\n* [`562c3b6`](https://github.com/siderolabs/crypto/commit/562c3b66f89866746c0ba47927c55f41afed0f7f) feat: add support for public RSA key in RSAKey\n* [`bda0e9c`](https://github.com/siderolabs/crypto/commit/bda0e9c24e80c658333822e2002e0bc671ac53a3) feat: enable more conversions between encoded and raw versions\n* [`e0dd56a`](https://github.com/siderolabs/crypto/commit/e0dd56ac47456f85c0b247999afa93fb87ebc78b) feat: add NotBefore option for x509 cert creation\n* [`12a4897`](https://github.com/siderolabs/crypto/commit/12a489768a6bb2c13e16e54617139c980f99a658) feat: add support for SPKI fingerprint generation and matching\n* [`d0c3eef`](https://github.com/siderolabs/crypto/commit/d0c3eef149ec9b713e7eca8c35a6214bd0a64bc4) fix: implement NewKeyPair\n* [`196679e`](https://github.com/siderolabs/crypto/commit/196679e9ec77cb709db54879ddeddd4eaafaea01) feat: move `pkg/grpc/tls` from `github.com/talos-systems/talos` as `./tls`\n* [`1ff6242`](https://github.com/siderolabs/crypto/commit/1ff6242c91bb298ceeb4acd65685cba952fe4178) chore: initial version as imported from talos-systems/talos\n* [`835063e`](https://github.com/siderolabs/crypto/commit/835063e055b28a525038b826a6d80cbe76402414) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>3 commits</summary>\n<p>\n\n* [`5b0c5e7`](https://github.com/siderolabs/discovery-api/commit/5b0c5e78097c1489457b148a7f13c73890f5ecad) chore: rename to siderolabs, rekres, etc\n* [`db279ef`](https://github.com/siderolabs/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/siderolabs/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`a5c19c6`](https://github.com/siderolabs/discovery-client/commit/a5c19c65f4833a104ac68f35a3c0f8f37be8fe87) feat: provide public IP discovered from the server\n* [`230f317`](https://github.com/siderolabs/discovery-client/commit/230f317a8e6e9542b82efcbac9f5cd7b9cff34b6) fix: reconnect the client on update failure\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`b155fa0`](https://github.com/siderolabs/extras/commit/b155fa067c36717ac84205e73e6ef7f47ba13842) chore: enable renovate\n* [`8f00d77`](https://github.com/siderolabs/extras/commit/8f00d7719f0a2312eaa3815ae8c7a91d000db661) feat: update tc-redirect-tap to the latest version\n* [`7c91844`](https://github.com/siderolabs/extras/commit/7c91844de76568335b7ccaec63cecec17401dd83) chore: bump go to 1.19.2\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>6 commits</summary>\n<p>\n\n* [`b3b6db8`](https://github.com/siderolabs/gen/commit/b3b6db858cb6ce46005edeb70776608e3f9bc402) fix: fix Copy documentation and implementation\n* [`521f737`](https://github.com/siderolabs/gen/commit/521f7371f40556ddce7f730c8de5e1888e40b621) feat: add xerrors package which contains additions to the std errors\n* [`726e066`](https://github.com/siderolabs/gen/commit/726e066dcb35c86f82866097bed806f22b936292) fix: rename tuples.go to pair.go and set proper package name\n* [`d8d7d25`](https://github.com/siderolabs/gen/commit/d8d7d25ce9a588609c00cb798206a01a866bf7a6) chore: minor additions\n* [`338a650`](https://github.com/siderolabs/gen/commit/338a65065f92eb6426a66c4a88a0cc02cc02e529) chore: add initial implementation and documentation\n* [`4fd8667`](https://github.com/siderolabs/gen/commit/4fd866707052c792a6adccbc28efec5debdd18a8) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>56 commits</summary>\n<p>\n\n* [`694ac62`](https://github.com/siderolabs/go-blockdevice/commit/694ac62b3dcf995beea95a77659fdc6064b457b3) chore: update imports to siderolabs, rekres\n* [`dcf6044`](https://github.com/siderolabs/go-blockdevice/commit/dcf6044c906b36f183e11b6553458c680126d1d9) chore: rekres and rename\n* [`9c4af49`](https://github.com/siderolabs/go-blockdevice/commit/9c4af492cc17279f0281fcd271e7423be78442bb) fix: cryptsetup remove slot\n* [`74ea471`](https://github.com/siderolabs/go-blockdevice/commit/74ea47109c4525bec139640fed6354ad3097f5fb) feat: add freebsd stubs\n* [`9fa801c`](https://github.com/siderolabs/go-blockdevice/commit/9fa801cf4da184e3560b9a18ba43d13316f172f9) feat: add ReadOnly attribute to Disk\n* [`fccee8b`](https://github.com/siderolabs/go-blockdevice/commit/fccee8bb082b105cb60db40cb01636efc3241b5f) chore: rekres the source, fix issues\n* [`d9c3a27`](https://github.com/siderolabs/go-blockdevice/commit/d9c3a273886113e24809ef1e9930fc982318217d) feat: support probing FAT12/FAT16 filesystems\n* [`b374eb4`](https://github.com/siderolabs/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n* [`ec428fe`](https://github.com/siderolabs/go-blockdevice/commit/ec428fed2ecd5a389833a88f8dc333762816db99) fix: lookup filesystem labels on the actual device path\n* [`7b9de26`](https://github.com/siderolabs/go-blockdevice/commit/7b9de26bc6bc3d54b95bd8e8fb3aade4b45adc6c) feat: read symlink fullpath in block device list function\n* [`6928ee4`](https://github.com/siderolabs/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/siderolabs/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n* [`15b182d`](https://github.com/siderolabs/go-blockdevice/commit/15b182db0cd233b163ed83d1724c7e28cf29d71a) fix: return partition table not exist when trying to read an empty dev\n* [`b9517d5`](https://github.com/siderolabs/go-blockdevice/commit/b9517d51120d385f97b0026f99ce3c4782940c37) fix: resize partition\n* [`70d2865`](https://github.com/siderolabs/go-blockdevice/commit/70d28650b398a14469cbb5356417355b0ba62956) fix: try to find cdrom disks\n* [`667bf53`](https://github.com/siderolabs/go-blockdevice/commit/667bf539b99ac34b629a0103ef7a7278a5a5f35d) fix: revert gpt partition not found\n* [`d7d4cdd`](https://github.com/siderolabs/go-blockdevice/commit/d7d4cdd7ac56c82caab19246b5decd59f12195eb) fix: gpt partition not found\n* [`33afba3`](https://github.com/siderolabs/go-blockdevice/commit/33afba347c0dce38a436c46a0aac26d2f99427c1) fix: also open in readonly mode when running `All` lookup method\n* [`e367f9d`](https://github.com/siderolabs/go-blockdevice/commit/e367f9dc7fa935f11672de0fdc8a89429285a07a) feat: make probe always open blockdevices in readonly mode\n* [`d981156`](https://github.com/siderolabs/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n* [`fe24303`](https://github.com/siderolabs/go-blockdevice/commit/fe2430349e9d734ce6dbf4e7b2e0f8a37bb22679) fix: perform correct PMBR partition calculations\n* [`2ec0c3c`](https://github.com/siderolabs/go-blockdevice/commit/2ec0c3cc0ff5ff705ed5c910ca1bcd5d93c7b102) fix: preserve the PMBR bootable flag when opening GPT partition\n* [`87816a8`](https://github.com/siderolabs/go-blockdevice/commit/87816a81cefc728cfe3cb221b476d8ed4b609fd8) feat: align partition to minimum I/O size\n* [`c34b59f`](https://github.com/siderolabs/go-blockdevice/commit/c34b59fb33a7ad8be18bb19bc8c8d8294b4b3a78) feat: expose more encryption options in the LUKS module\n* [`30c2bc3`](https://github.com/siderolabs/go-blockdevice/commit/30c2bc3cb62af52f0aea9ce347923b0649fb7928) feat: mark MBR bootable\n* [`1292574`](https://github.com/siderolabs/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/siderolabs/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n* [`1d830a2`](https://github.com/siderolabs/go-blockdevice/commit/1d830a25f64f6fb96a1bedd800c0b40b107dc833) fix: revert mark the EFI partition in PMBR as bootable\n* [`bec914f`](https://github.com/siderolabs/go-blockdevice/commit/bec914ffdda42abcfe642bc2cdfc9fcda56a74ee) fix: mark the EFI partition in PMBR as bootable\n* [`776b37d`](https://github.com/siderolabs/go-blockdevice/commit/776b37d31de0781f098f5d9d1894fbea3f2dfa1d) feat: add options to probe disk by various sysblock parameters\n* [`bb3ad73`](https://github.com/siderolabs/go-blockdevice/commit/bb3ad73f69836acc2785ec659435e24a531359e7) fix: align partition start to physical sector size\n* [`8f976c2`](https://github.com/siderolabs/go-blockdevice/commit/8f976c2031108651738ebd4db69fb09758754a28) feat: replace exec.Command with go-cmd module\n* [`1cf7f25`](https://github.com/siderolabs/go-blockdevice/commit/1cf7f252c38cf11ef07723de2debc27d1da6b520) fix: properly handle no child processes error from cmd.Wait\n* [`04a9851`](https://github.com/siderolabs/go-blockdevice/commit/04a98510c07fe8477f598befbfe6eaec4f4b73a2) feat: implement luks encryption provider\n* [`b0375e4`](https://github.com/siderolabs/go-blockdevice/commit/b0375e4267fdc6108bd9ff7a5dc97b80cd924b1d) feat: add an option to open block device with exclusive flock\n* [`5a1c7f7`](https://github.com/siderolabs/go-blockdevice/commit/5a1c7f768e016c93f6c0be130ffeaf34109b5b4d) refactor: add devname into gpt.Partition, refactor probe package\n* [`f2728a5`](https://github.com/siderolabs/go-blockdevice/commit/f2728a581972be977d863d5d9177a873b8f3fc7b) fix: keep contents of PMBR when writing it\n* [`2878460`](https://github.com/siderolabs/go-blockdevice/commit/2878460b54e8b8c3846c6a882ca9e1472c8b6b3b) fix: write second copy of partition entries\n* [`943b08b`](https://github.com/siderolabs/go-blockdevice/commit/943b08bc32a2156cffb23e92b8be9288de4a7421) fix: blockdevice reset should read partition table from disk\n* [`5b4ee44`](https://github.com/siderolabs/go-blockdevice/commit/5b4ee44cfd434a03ec2d7167bcc56d0f164c3fa2) fix: ignore `/dev/ram` devices\n* [`98754ec`](https://github.com/siderolabs/go-blockdevice/commit/98754ec2bb200acc9e9e573fa766754d60e25ff2) refactor: rewrite GPT library\n* [`2a1baad`](https://github.com/siderolabs/go-blockdevice/commit/2a1baadffdf8c9b65355e9af6e744aeab838c9db) fix: correctly build paths for `mmcblk` devices\n* [`8076344`](https://github.com/siderolabs/go-blockdevice/commit/8076344a95021f25ab5d1fbf5ea4fefc790f6c3c) fix: return proper disk size from GetDisks function\n* [`8742133`](https://github.com/siderolabs/go-blockdevice/commit/874213371a3fb0925aab45cbba68a957e3319525) chore: add common method to list available disks using /sys/block\n* [`c4b5833`](https://github.com/siderolabs/go-blockdevice/commit/c4b583363d63503ed7e4adb9a9fa64335f7e198d) feat: implement \"fast\" wipe\n* [`b4e67d7`](https://github.com/siderolabs/go-blockdevice/commit/b4e67d73d70d8dc06aa2b4986622dcb854dfc40c) feat: return resize status from Resize() function\n* [`ceae64e`](https://github.com/siderolabs/go-blockdevice/commit/ceae64edb3a591c6f6bbd75b1149d1cfe426dd8e) fix: sync kernel partition table incrementally\n* [`2cb9516`](https://github.com/siderolabs/go-blockdevice/commit/2cb95165aa67b0b839863b5ad89920c3ac7e2c82) fix: return correct error value from blkpg functions\n* [`cebe43d`](https://github.com/siderolabs/go-blockdevice/commit/cebe43d1fdc1e509437198e578faa9d5a804cc37) refactor: expose `InsertAt` method via interface\n* [`c40dcd8`](https://github.com/siderolabs/go-blockdevice/commit/c40dcd80c50b41c1f2a60ea6aa9d5fb3d3b180a3) fix: properly inform kernel about partition deletion\n* [`bb8ac5d`](https://github.com/siderolabs/go-blockdevice/commit/bb8ac5d6a25e279e16213f585dc8d02ba6ed645f) feat: implement disk wiping via several methods\n* [`23fb7dc`](https://github.com/siderolabs/go-blockdevice/commit/23fb7dc755325cfe12e48c8e8e31bebab9ddc2bc) feat: expose partition name (label)\n* [`ff3a821`](https://github.com/siderolabs/go-blockdevice/commit/ff3a8210be999b8bfb2019f19f8a8b50901c64cc) feat: implement 'InsertAt' method to insert partitions at any position\n* [`3d1ce4f`](https://github.com/siderolabs/go-blockdevice/commit/3d1ce4fc859fa614a4c5c54a10c0f5f4fce38bb6) fix: calculate last lba of partition correctly\n* [`b71540f`](https://github.com/siderolabs/go-blockdevice/commit/b71540f6c398e958bdb7c118396a736419f735d4) feat: copy initial version from talos-systems/talos\n* [`ca3c078`](https://github.com/siderolabs/go-blockdevice/commit/ca3c078da95e6497c9d41667dc242e32682e517d) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>2 commits</summary>\n<p>\n\n* [`507e0ec`](https://github.com/siderolabs/go-circular/commit/507e0ec7b70e7c8336c25640929ae7b04869dfa1) refactor: extract circular Go module\n* [`2234b3a`](https://github.com/siderolabs/go-circular/commit/2234b3ab14ec6a49b5ce48aaec108c6b3f33dc7f) docs: add README\n</p>\n</details>\n\n### Changes from siderolabs/go-cmd\n<details><summary>5 commits</summary>\n<p>\n\n* [`0aea518`](https://github.com/siderolabs/go-cmd/commit/0aea518205cb71e4126a88d605009b44d4e15f7e) chore: rekres and update\n* [`68eb006`](https://github.com/siderolabs/go-cmd/commit/68eb0067e0f0fa18db1eb91257764d5a7b69ab30) feat: return typed error for exit error\n* [`333ccf1`](https://github.com/siderolabs/go-cmd/commit/333ccf125e0e8f36e4d67d05ea0f0e0f09827c73) feat: add stdin support into the Run methods\n* [`c5c8f1c`](https://github.com/siderolabs/go-cmd/commit/c5c8f1c4f9d549b11fda70358ff21c9956c5f295) feat: extract cmd module from Talos into a separate module\n* [`77685fc`](https://github.com/siderolabs/go-cmd/commit/77685fc53eb44020f11e2fc5451a86235231903b) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-debug\n<details><summary>6 commits</summary>\n<p>\n\n* [`c1bc4bf`](https://github.com/siderolabs/go-debug/commit/c1bc4bf306e54879ce9f4b002527876ac0cbf88f) chore: rekres, rename, etc\n* [`3d0a6e1`](https://github.com/siderolabs/go-debug/commit/3d0a6e1bf5e3c521e83ead2c8b7faad3638b8c5d) feat: race build tag flag detector\n* [`5b292e5`](https://github.com/siderolabs/go-debug/commit/5b292e50198b8ed91c434f00e2772db394dbf0b9) feat: disable memory profiling by default\n* [`c6d0ae2`](https://github.com/siderolabs/go-debug/commit/c6d0ae2c0ee099fa0940405401e6a02716a15bd8) fix: linters and CI\n* [`d969f95`](https://github.com/siderolabs/go-debug/commit/d969f952af9e02feea59963671298fc236ca4399) feat: initial implementation\n* [`b2044b7`](https://github.com/siderolabs/go-debug/commit/b2044b70379c84f9706de74044bd2fd6a8e891cf) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-kmsg\n<details><summary>4 commits</summary>\n<p>\n\n* [`e2a0000`](https://github.com/siderolabs/go-kmsg/commit/e2a0000c52ff2735a2e4a535b7ad24bb73499c75) chore: rekres, rename\n* [`b08e4d3`](https://github.com/siderolabs/go-kmsg/commit/b08e4d36a2f3df0a3d031b1a3028e2d6e4c26710) feat: replace tab character with space in console output\n* [`2edcd3a`](https://github.com/siderolabs/go-kmsg/commit/2edcd3a913508e2d922776f729bfc4bcab031a8b) feat: add initial version\n* [`53cdd8d`](https://github.com/siderolabs/go-kmsg/commit/53cdd8d67b9dbab692471a2d5161e7e0b3d04cca) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-kubeconfig\n<details><summary>2 commits</summary>\n<p>\n\n* [`e7fdd94`](https://github.com/siderolabs/go-kubeconfig/commit/e7fdd94573fa175784700cbb24b37a087e6ca35b) refactor: extract kubeconfig library as a Go module\n* [`50e91b8`](https://github.com/siderolabs/go-kubeconfig/commit/50e91b8ba9df2c14a82d0ba95ee8acad262497b6) docs: add REAMDE\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>12 commits</summary>\n<p>\n\n* [`f54e3c9`](https://github.com/siderolabs/go-loadbalancer/commit/f54e3c9a5450d8c734f915d7038f798afa8c0d0d) chore: update dependencies to siderolabs, rekres\n* [`438b71d`](https://github.com/siderolabs/go-loadbalancer/commit/438b71da2474525311ee6435606d7a6143696651) chore: update package path and rekres\n* [`5341eec`](https://github.com/siderolabs/go-loadbalancer/commit/5341eec63c6d3396a37be17506e081ad72ccaeb6) feat: implement public method to check if the route is Healthy\n* [`b578d47`](https://github.com/siderolabs/go-loadbalancer/commit/b578d477211476bbc34b1ea2c86d54f0d1b0cdc1) feat: add a way to configure loadbalancer options\n* [`c54d95d`](https://github.com/siderolabs/go-loadbalancer/commit/c54d95d8252780dc374032dc5fe10e7e84a15062) feat: implement control plane loadbalancer\n* [`4a6e29e`](https://github.com/siderolabs/go-loadbalancer/commit/4a6e29e7c02a2a94193a6014de04c2d2c79bdb02) refactor: clean up names, fix the lingering goroutines\n* [`af87d1c`](https://github.com/siderolabs/go-loadbalancer/commit/af87d1cbb79da35adabb9587a028db9b3e9fde1c) chore: apply new Kres rules\n* [`a445702`](https://github.com/siderolabs/go-loadbalancer/commit/a4457024d5189d754b2da4a30b14072a0e3f5f05) feat: allow dial timeout and keep alive period to be configurable\n* [`3c8f347`](https://github.com/siderolabs/go-loadbalancer/commit/3c8f3471d14e37866c65f73170ef83c038ae5a8c) feat: provide a way to configure logger for the loadbalancer\n* [`da8e987`](https://github.com/siderolabs/go-loadbalancer/commit/da8e987434c3d407679a40e213b12a8e1c98abb8) feat: implement Reconcile - ability to change upstream list on the fly\n* [`8b1dfa6`](https://github.com/siderolabs/go-loadbalancer/commit/8b1dfa6e80dea53d699a551221695ca99b2aadb2) feat: copy initial version from talos-systems/talos\n* [`c2f6a8f`](https://github.com/siderolabs/go-loadbalancer/commit/c2f6a8f88439608ea4b7623e6becdcf079cad217) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-procfs\n<details><summary>10 commits</summary>\n<p>\n\n* [`a062a4c`](https://github.com/siderolabs/go-procfs/commit/a062a4ca078a6b3b3f119edf86e5f80620e67a55) chore: rekres, rename\n* [`8cbc42d`](https://github.com/siderolabs/go-procfs/commit/8cbc42d3dc246a693d9b307c5358f6f7f3cb60bc) feat: provide an option to overwrite some args in AppendAll\n* [`24d06a9`](https://github.com/siderolabs/go-procfs/commit/24d06a955782ed7d468f5117e986ec632f316310) refactor: remove talos kernel default args\n* [`a82654e`](https://github.com/siderolabs/go-procfs/commit/a82654edcec13531a3f6baf1d9c2933b074326cf) feat: implement SetAll method\n* [`16ce2ef`](https://github.com/siderolabs/go-procfs/commit/16ce2ef52acd0f351c93365e5c9263af442bec12) fix: update cmdline.Set() to drop the value being overwritten\n* [`5a9a4a7`](https://github.com/siderolabs/go-procfs/commit/5a9a4a75d559eab694afcdad2496d268473db432) feat: update kernel args for new KSPP requirements\n* [`57c7311`](https://github.com/siderolabs/go-procfs/commit/57c7311fdd4524bc17f528486bf9b417536153c3) refactor: change directory layout\n* [`a077c96`](https://github.com/siderolabs/go-procfs/commit/a077c96480d04ad432ce909295cfd969d8c4da7d) fix: fix go module name\n* [`698666f`](https://github.com/siderolabs/go-procfs/commit/698666fd4540a0460b5141425d47df084f9a6e20) chore: move package to new repo\n* [`dabb425`](https://github.com/siderolabs/go-procfs/commit/dabb42542312758dd0edc22ece49d8daa5476bbd) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-retry\n<details><summary>9 commits</summary>\n<p>\n\n* [`6d45449`](https://github.com/siderolabs/go-retry/commit/6d45449c83129d00cc73eb40f9e52294d2e107fc) chore: rekres, rename\n* [`c78cc95`](https://github.com/siderolabs/go-retry/commit/c78cc953d9e95992575305b4e8648392c6c9b9e6) fix: implement `errors.Is` for all errors in the set\n* [`7885e16`](https://github.com/siderolabs/go-retry/commit/7885e16b2cb0267bcc8b07cdd0eced14e8005864) feat: add ExpectedErrorf\n* [`3d83f61`](https://github.com/siderolabs/go-retry/commit/3d83f6126c1a3a238d1d1d59bfb6273e4087bdac) feat: deprecate UnexpectedError\n* [`b9dc1a9`](https://github.com/siderolabs/go-retry/commit/b9dc1a990133dd3399549b4ea199759bdfe58bb8) feat: add support for `context.Context` in Retry\n* [`8c63d29`](https://github.com/siderolabs/go-retry/commit/8c63d290a6884095ea2e754c52e575603abe4bc0) fix: correctly implement error interfaces on wrapped errors\n* [`752f081`](https://github.com/siderolabs/go-retry/commit/752f081252cfef6106151dc285fcbe4849ab0a0c) feat: add an option to log errors being retried\n* [`073067b`](https://github.com/siderolabs/go-retry/commit/073067bd95a70e9b0a2a8d07d33311be69c24923) feat: copy initial version from talos-systems/talos\n* [`c7968c5`](https://github.com/siderolabs/go-retry/commit/c7968c54b4b1743d14dedce51431bf6e79a67a4f) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>11 commits</summary>\n<p>\n\n* [`10c1dd8`](https://github.com/siderolabs/go-smbios/commit/10c1dd8f2a7a30cc4a00b90d76afcf3ff22bf8ae) fix: check for end of the slice properly\n* [`9ca8ce7`](https://github.com/siderolabs/go-smbios/commit/9ca8ce77b796f3f49c0b7fd70f184911da294dc1) chore: treat invalid strings as empty\n* [`dbc5f79`](https://github.com/siderolabs/go-smbios/commit/dbc5f794726f18f0736c1203a440b8148675bc04) chore: rekres+rename\n* [`3f1e775`](https://github.com/siderolabs/go-smbios/commit/3f1e775b7e3ef74be41461417d800ac81671a553) feat: rework destructuring of SMBIOS information and added some tests\n* [`fd5ec8c`](https://github.com/siderolabs/go-smbios/commit/fd5ec8ce4873790b7fbd46dba9d7f49c9de7176a) fix: remove useless (?) goroutines leading to data race error\n* [`d3a32be`](https://github.com/siderolabs/go-smbios/commit/d3a32bea731a0c2a60ce7f5eae60253300ef27e1) fix: return UUID in middle endian only on SMBIOS >= 2.6\n* [`fb425d4`](https://github.com/siderolabs/go-smbios/commit/fb425d4727e620b6a2b6ba49e405a2c6f0e46304) feat: add memory device\n* [`0bb4f96`](https://github.com/siderolabs/go-smbios/commit/0bb4f96a6679e8fc958903c4f451ca068f8e3c41) feat: add physical memory array\n* [`8019619`](https://github.com/siderolabs/go-smbios/commit/80196199691e7094946a207463c67fc42da6a0e2) feat: supply wake-up type in SMBIOS info\n* [`94b8c4e`](https://github.com/siderolabs/go-smbios/commit/94b8c4e489eef8c44cb1a2768678945d73e16e88) feat: initial implementation\n* [`864ed80`](https://github.com/siderolabs/go-smbios/commit/864ed80937edf072f7e7e63551aef0d1f7776111) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-tail\n<details><summary>2 commits</summary>\n<p>\n\n* [`962ae43`](https://github.com/siderolabs/go-tail/commit/962ae433288845cfc7f2aab0c0ef74777e2bd992) refactor: extract go-tail module\n* [`359c3cb`](https://github.com/siderolabs/go-tail/commit/359c3cbde0f6a0a49d6893b2d1f8cb7ee6df9efc) docs: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>51 commits</summary>\n<p>\n\n* [`4cc7bbe`](https://github.com/siderolabs/grpc-proxy/commit/4cc7bbe397d74ee731398d67d34c214747957122) chore: rename to siderolabs/grpc-proxy, rekres\n* [`2c586db`](https://github.com/siderolabs/grpc-proxy/commit/2c586dbdda4e9c2bd09754beb13014c52b626db1) feat: pass fullMethodName to GetConnection\n* [`6dfa2cc`](https://github.com/siderolabs/grpc-proxy/commit/6dfa2cc80b6195844cae2dc2b2bc0b9b62246d8d) fix: ignore errors on duplicate `SetHeader` calls\n* [`b076302`](https://github.com/siderolabs/grpc-proxy/commit/b076302cc46ec6742e71fe1d49f6ec2d5d3a15dc) fix: use io.EOF error when no backend connections are available\n* [`82daca0`](https://github.com/siderolabs/grpc-proxy/commit/82daca0322a4293bd27071ae1ba8dd5097509d21) docs: update README\n* [`fa6843a`](https://github.com/siderolabs/grpc-proxy/commit/fa6843ae5b64500d481a1d031790406ed9df77d7) chore: fix spelling\n* [`c0a87d9`](https://github.com/siderolabs/grpc-proxy/commit/c0a87d95be9c62b0c4fd1fa694ef768e1f8e2391) chore: major cleanup of the code and build\n* [`ca3bc61`](https://github.com/siderolabs/grpc-proxy/commit/ca3bc6131f052aa000517339211335aaa4ebb640) fix: ignore some errors so that we don't spam the logs\n* [`5c579a7`](https://github.com/siderolabs/grpc-proxy/commit/5c579a7a61475bde3ec9c1efe000d2a55e2a3cb2) feat: allow different formats for messages streaming/unary\n* [`6c9f7b3`](https://github.com/siderolabs/grpc-proxy/commit/6c9f7b399173dd5769dbc4e8e366e78f05cead85) fix: allow mode to be set for each request being proxied\n* [`cc91c09`](https://github.com/siderolabs/grpc-proxy/commit/cc91c09782824e261bf1c861961a272aedb2b123) refactor: provide better public API, enforce proxying mode\n* [`d8d3a75`](https://github.com/siderolabs/grpc-proxy/commit/d8d3a751d1e71d006ba90379eed388c487bbb246) chore: update import paths after repo move\n* [`dbf07a4`](https://github.com/siderolabs/grpc-proxy/commit/dbf07a4d9e16fe3cf7407b9921c1746aa24ffaf6) Merge pull request  [#7](https://github.com/siderolabs/grpc-proxy/pull/7) from smira/one2many-4\n* [`fc0d27d`](https://github.com/siderolabs/grpc-proxy/commit/fc0d27dc6b5b9db35173f3e78778784a9e7c95bf) More tests, small code fixes, updated README.\n* [`d9ce0b1`](https://github.com/siderolabs/grpc-proxy/commit/d9ce0b1053a7f15ea65bf46e94cfe4154493bad7) Merge pull request  [#6](https://github.com/siderolabs/grpc-proxy/pull/6) from smira/one2many-3\n* [`2d37ba4`](https://github.com/siderolabs/grpc-proxy/commit/2d37ba444528a00f988671f3a01666e692739a37) Support for one2many streaming calls, tests.\n* [`817b035`](https://github.com/siderolabs/grpc-proxy/commit/817b03553ed7d97bd0da09283776d54592d7b5d4) Merge pull request  [#5](https://github.com/siderolabs/grpc-proxy/pull/5) from smira/one2many-2\n* [`436b338`](https://github.com/siderolabs/grpc-proxy/commit/436b3383a39fd860f3b2379ffab80a44ae1809f7) More unary one-2-many tests, error propagation.\n* [`1f0cb46`](https://github.com/siderolabs/grpc-proxy/commit/1f0cb466268f046e8e9fb78b1902411ac3a753ba) Merge pull request  [#4](https://github.com/siderolabs/grpc-proxy/pull/4) from smira/one2many-1\n* [`992a975`](https://github.com/siderolabs/grpc-proxy/commit/992a975ccf0b97e4be329c84bd3018652e8e50ae) Proxying one to many: first iteration\n* [`a0988ff`](https://github.com/siderolabs/grpc-proxy/commit/a0988ff2b29839892a7913acd76f26f4e7edcc3a) Merge pull request  [#3](https://github.com/siderolabs/grpc-proxy/pull/3) from smira/small-fixups\n* [`e3111ef`](https://github.com/siderolabs/grpc-proxy/commit/e3111ef2c16f0ee4bba597a2ab1ab6a2818c2734) Small fixups in preparation to add one-to-many proxying.\n* [`6d76ffc`](https://github.com/siderolabs/grpc-proxy/commit/6d76ffcff89f6636d3689ed1c9b0eebe87722114) Merge pull request  [#2](https://github.com/siderolabs/grpc-proxy/pull/2) from smira/backend-concept\n* [`2aad63a`](https://github.com/siderolabs/grpc-proxy/commit/2aad63ac5bae09232ea5ac80b42338e9e3af67c4) Add concept of a 'Backend', but still one to one proxying\n* [`7cc4610`](https://github.com/siderolabs/grpc-proxy/commit/7cc46101114a2779d6393e0e8f841bf3febb2753) Merge pull request  [#1](https://github.com/siderolabs/grpc-proxy/pull/1) from smira/build\n* [`37f01f3`](https://github.com/siderolabs/grpc-proxy/commit/37f01f3aab3b978a8fecb428fca4d4c722141229) Rework build to use GitHub Actions, linting updates.\n* [`0f1106e`](https://github.com/siderolabs/grpc-proxy/commit/0f1106ef9c766333b9acb4b81e705da4bade7215) Move error checking further up (#34)\n* [`d5b35f6`](https://github.com/siderolabs/grpc-proxy/commit/d5b35f634383bf8931f8798797daaf9c1a59235e) Update gRPC and fix tests (#27)\n* [`67591eb`](https://github.com/siderolabs/grpc-proxy/commit/67591eb23c48346a480470e462289835d96f70da) Break StreamDirector interface, fix metadata propagation for gRPC-Go>1.5. (#20)\n* [`97396d9`](https://github.com/siderolabs/grpc-proxy/commit/97396d94749c00db659393ba5123f707062f829f) Merge pull request  [#11](https://github.com/siderolabs/grpc-proxy/pull/11) from mwitkow/fix-close-bug\n* [`3fcbd37`](https://github.com/siderolabs/grpc-proxy/commit/3fcbd3737ec6baff505795417e48f162a7a3183c) fixup closing conns\n* [`a8f5f87`](https://github.com/siderolabs/grpc-proxy/commit/a8f5f87a2f5e6bc3643b78d64594195b2395a238) fixup tests, extend readme\n* [`428fa1c`](https://github.com/siderolabs/grpc-proxy/commit/428fa1c450320041e0ad8e251d6aed435401174e) Fix a channel closing bug\n* [`af55d61`](https://github.com/siderolabs/grpc-proxy/commit/af55d612de6c5723a5a59340704db7bc771023ff) Merge pull request  [#10](https://github.com/siderolabs/grpc-proxy/pull/10) from mwitkow/bugfix/streaming-fix\n* [`de4d3db`](https://github.com/siderolabs/grpc-proxy/commit/de4d3db538565636e1e977102f6f0bd1ed0ce9c2) remove spurious printfs\n* [`84242c4`](https://github.com/siderolabs/grpc-proxy/commit/84242c4e690da18d16d2ab8f2fa47e45986220b6) fix the \"i don't know who finished\" case\n* [`9b22f41`](https://github.com/siderolabs/grpc-proxy/commit/9b22f41d8535fa3e40908c78ae66066c7972b6d9) fix full duplex streaming\n* [`c2f7c98`](https://github.com/siderolabs/grpc-proxy/commit/c2f7c98b0b6cd180659aed31e98cbbc18d616b1c) update readme\n* [`d654141`](https://github.com/siderolabs/grpc-proxy/commit/d654141edcb92b7fa2bba9d3e690e569c72f8e9d) update README\n* [`f457856`](https://github.com/siderolabs/grpc-proxy/commit/f4578565f2d34dc89774128db2bfda3a328cba40) move to proxy subdirectory\n* [`4889d78`](https://github.com/siderolabs/grpc-proxy/commit/4889d78e468681601b8229c81807dcf37b00ff63) Add fixup scripts\n* [`ef60a37`](https://github.com/siderolabs/grpc-proxy/commit/ef60a37547d137e52873be183f2d7a5626d7c034) version 2 of the grpc-proxy, this time with fewer grpc upstream deps\n* [`07aeac1`](https://github.com/siderolabs/grpc-proxy/commit/07aeac13e988c0c0b3a886c79972e20408a765e0) Merge pull request  [#2](https://github.com/siderolabs/grpc-proxy/pull/2) from daniellowtw/master\n* [`e5c3df5`](https://github.com/siderolabs/grpc-proxy/commit/e5c3df5b2f0a1ffc4cb755cbe6b30b435e35de37) Fix compatibility with latest grpc library\n* [`52be0a5`](https://github.com/siderolabs/grpc-proxy/commit/52be0a559a85f0e2480bde6725f3f144396aa6ef) bugfix: fix gRPC Java deadlock, due to different dispatch logic\n* [`822df7d`](https://github.com/siderolabs/grpc-proxy/commit/822df7d86b556b703fc11798a3bdcbaeb60c18a6) Fix reference to mwitkow.\n* [`28341d1`](https://github.com/siderolabs/grpc-proxy/commit/28341d171dd4c1a52f46371ddfb5fd2240b79731) move out forward logic to method, allowing for use as `grpc.Server` not found handler.\n* [`89e28b4`](https://github.com/siderolabs/grpc-proxy/commit/89e28b42ee9dda8e36522b77e3771d9debc645e0) add reference to upstream grpc bug\n* [`00dd588`](https://github.com/siderolabs/grpc-proxy/commit/00dd588ae68adf4187a7fca87db45a73af4c834d) merge upstream `grpc.Server` changes changing the dispatch logic\n* [`77edc97`](https://github.com/siderolabs/grpc-proxy/commit/77edc9715de187dcbc9969e2f0e8a04d2087fd13) move to upstream `protobuf` from `gogo`\n* [`db71c3e`](https://github.com/siderolabs/grpc-proxy/commit/db71c3e7e812db8d75cb282dac38d953fcb436b3) initial commit, tested and working.\n</p>\n</details>\n\n### Changes from siderolabs/net\n<details><summary>12 commits</summary>\n<p>\n\n* [`19eb1c4`](https://github.com/siderolabs/net/commit/19eb1c4afb54b76fc38523834ec0490f41b50447) feat: switch to use `netip.Addr` instead of `net.IP`\n* [`5b21171`](https://github.com/siderolabs/net/commit/5b21171f9e5c5eb6b5ffc0110f48c6de451ffe34) chore: rename, rekres\n* [`409926a`](https://github.com/siderolabs/net/commit/409926aec1c3e659d6c245db4c0b90b0eaa4fdbc) fix: parse correctly some IPv6 CIDRs\n* [`b4b7181`](https://github.com/siderolabs/net/commit/b4b718179a1aa68e4f54422baf08ca3761723d2d) feat: add a way to filter list of IPs for the machine\n* [`0abe5bd`](https://github.com/siderolabs/net/commit/0abe5bdae8f85e4e976bc4d90e95dcb4be8fb853) feat: implement FilterIPs function\n* [`0519054`](https://github.com/siderolabs/net/commit/05190541b0fafc44fc6f3a2f8ba98d9b4a7b527a) feat: add ParseCIDR\n* [`52c7509`](https://github.com/siderolabs/net/commit/52c75099437634e312f54dd0941a44c626da9b66) feat: add a function to format IPs in CIDR notation\n* [`005a94f`](https://github.com/siderolabs/net/commit/005a94f8b36b5dfd56873cb168af9efceb072eeb) feat: add methods to manage CIDR list, check for non-local IPv6\n* [`8b56890`](https://github.com/siderolabs/net/commit/8b568905bbcede25e492e4d224f85538678c2342) feat: add ValidateEndpointURI\n* [`402fa79`](https://github.com/siderolabs/net/commit/402fa79a10b453acbbc0079ce093652740c348db) chore: apply kres to get the latest build scripts\n* [`c7bc477`](https://github.com/siderolabs/net/commit/c7bc477975f89cba217cdff945ea097b00243972) chore: initial version of the package\n* [`393246a`](https://github.com/siderolabs/net/commit/393246ae638089425bb989427ec7793ae6a65826) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>39 commits</summary>\n<p>\n\n* [`8b975a7`](https://github.com/siderolabs/pkgs/commit/8b975a7f8456fd33db7c75191941a4bd2631d376) chore: bump deps\n* [`b153ce6`](https://github.com/siderolabs/pkgs/commit/b153ce616c29c56cd603c757efaab151a8ca4599) chore: bump deps\n* [`535b8f9`](https://github.com/siderolabs/pkgs/commit/535b8f9f7d4d4293f8b12f91cd7edcd4d6c946b1) chore: update packages version\n* [`66c77e9`](https://github.com/siderolabs/pkgs/commit/66c77e9669a7e1c2ca6a2477fac809a34e3ce3f6) feat: re-enable build kernel with BTF enabled\n* [`98ef073`](https://github.com/siderolabs/pkgs/commit/98ef0736130e660b95720db1ac23b7a6e1506f3e) feat: enable INET_DIAG and FANOTFY_PERMISSIONS\n* [`8fe5cbc`](https://github.com/siderolabs/pkgs/commit/8fe5cbca8243eaa0a60cf1aee80ab3e2ad987e81) chore: update dependencies\n* [`554c0fe`](https://github.com/siderolabs/pkgs/commit/554c0fe295719e425453e3d763559193b01a8b03) feat: add fanotify and kprobes kernel options\n* [`54d7e5c`](https://github.com/siderolabs/pkgs/commit/54d7e5c8db1e54c999ba0b4a466fe65c54e0c663) fix: drbd package name\n* [`b4cb9e2`](https://github.com/siderolabs/pkgs/commit/b4cb9e2125e20aea52a57aaba981326deb8ae0df) feat: add 'drbd' package\n* [`91e73b3`](https://github.com/siderolabs/pkgs/commit/91e73b325431f997b0e19d6ba083c48a6ae5ff2a) feat: update dependencies\n* [`b6d0d96`](https://github.com/siderolabs/pkgs/commit/b6d0d969942234defbf08745c57e3141152662e3) chore: bump kernel to 5.15.72\n* [`b16dfe9`](https://github.com/siderolabs/pkgs/commit/b16dfe9699e43a03e47109c95ac0707cce038a49) chore: bump go to 1.19.2\n* [`861cc32`](https://github.com/siderolabs/pkgs/commit/861cc32274db424975544b67e6f10b3568980a11) chore: bump kernel to 5.15.71\n* [`0ac7773`](https://github.com/siderolabs/pkgs/commit/0ac77733506d2f0b0944ff569b6817ae44821bda) chore: use generic raspberry pi u-boot\n* [`d5633d4`](https://github.com/siderolabs/pkgs/commit/d5633d4838bd6e168b9c80f124540a30c29ae7be) chore: bump kernel to 5.15.70\n* [`39c0d43`](https://github.com/siderolabs/pkgs/commit/39c0d4364fd4eedd281e46ce7d305f2562e2cf78) feat: add generic rpi_arm64_defconfig configuration\n* [`ed269ca`](https://github.com/siderolabs/pkgs/commit/ed269cabad82446095221e45078c8ba85bce5c2e) chore: bump kernel to 5.15.69\n* [`f2f8333`](https://github.com/siderolabs/pkgs/commit/f2f83331f93a0a5d2dd1c013e2ff46900684096a) fix: no slack notifications on failure\n* [`6f0af33`](https://github.com/siderolabs/pkgs/commit/6f0af3390fc170f0cf57450adfada6a87de7ece4) chore: disable drone slack pipeline for renovate\n* [`32aea3f`](https://github.com/siderolabs/pkgs/commit/32aea3f005b93aaa91d52e4dfd04dd9ce9d564a9) chore: disable drone for renovate/dependabot\n* [`44579f0`](https://github.com/siderolabs/pkgs/commit/44579f0238993f529e2c141f42c99b32803fd6a5) fix: rollback xfsprogs to 5.18.0\n* [`792c0e3`](https://github.com/siderolabs/pkgs/commit/792c0e32ef6b1cf13514dc2693c4c302e1440d3b) feat: add gasket driver package\n* [`07f1898`](https://github.com/siderolabs/pkgs/commit/07f1898b231390b85519f83638946ed65adacc64) chore: update deps\n* [`f78f410`](https://github.com/siderolabs/pkgs/commit/f78f410d193953e730aeb14f4e148e47dfa827fd) chore: enable conntrack zones and timestamps\n* [`049b3c6`](https://github.com/siderolabs/pkgs/commit/049b3c6f080b9af76b1b2e924baade69db27bc0b) chore: enable intel ice drivers\n* [`606ff32`](https://github.com/siderolabs/pkgs/commit/606ff32cb7e75b6975749b6250b68352b71e943b) chore: bump deps\n* [`eee5c8a`](https://github.com/siderolabs/pkgs/commit/eee5c8af13ee1fe0b1e660a9581d4f1b14158a39) chore: disable irc in conntrack\n* [`70e6c46`](https://github.com/siderolabs/pkgs/commit/70e6c460d7b3bd5e154a4e681858832afcf32368) chore: bump kernel to 5.15.64\n* [`e510321`](https://github.com/siderolabs/pkgs/commit/e5103217e714bea04e06fd0c4940e84406cb68cf) chore: update renovate config\n* [`d1fa510`](https://github.com/siderolabs/pkgs/commit/d1fa510cc66ddc63a53482f6ced5573466049d49) feat: enable renovate bot\n* [`e427a77`](https://github.com/siderolabs/pkgs/commit/e427a778146664b988664008bfe20611f91216b0) chore: bump runc to v1.1.4\n* [`40e1215`](https://github.com/siderolabs/pkgs/commit/40e12152a027eb509330c41db21680b9a662fa05) chore: enable nfsv4.2 client support\n* [`15efada`](https://github.com/siderolabs/pkgs/commit/15efadaa9db4b8dc8003359d6d0ed84016f54746) chore: bump kernel to 5.15.63\n* [`e70e3c1`](https://github.com/siderolabs/pkgs/commit/e70e3c1af2b11d4b4646401a617b3d0efa2db4a3) fix: nvidia oss pkg name\n* [`30b8d79`](https://github.com/siderolabs/pkgs/commit/30b8d79b9ca3e463b5f403f01d39e64e89edc7b1) chore: bump kernel to 5.15.62\n* [`862c392`](https://github.com/siderolabs/pkgs/commit/862c392b6defe3c9ce90f9b15eae154e021b0b4d) chore: bump gcc to 12.2.0\n* [`2ecd14e`](https://github.com/siderolabs/pkgs/commit/2ecd14ede04637a581fbe7dcbbf612cdd6f9d882) fix: containerd version\n* [`01df058`](https://github.com/siderolabs/pkgs/commit/01df0583a430f3793f19725c920e942cf37efee4) feat: add NanoPi R4S configuration\n* [`d4cb33b`](https://github.com/siderolabs/pkgs/commit/d4cb33b9bdfb8c27ea86a42ea60a88e294129ad4) chore: bump containerd to v1.6.8\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>19 commits</summary>\n<p>\n\n* [`575c5cc`](https://github.com/siderolabs/siderolink/commit/575c5cc53bf854c8f6261d2b16bf52fe00868669) refactor: drop dependency on Talos machinery package\n* [`61ab1c4`](https://github.com/siderolabs/siderolink/commit/61ab1c43dd04faeb046c51dca7d891213762a31e) fix: include MachineStatusEvent into the list of supported events\n* [`16a84eb`](https://github.com/siderolabs/siderolink/commit/16a84ebe6759535c7a5284271418f7f04443e25f) chore: rename to siderolabs/siderolink\n* [`ca470c7`](https://github.com/siderolabs/siderolink/commit/ca470c735e6922b7d5afea91aef50c043f9563ee) chore: update Talos to the latest master, migrate netaddr -> netip/x\n* [`93b65f0`](https://github.com/siderolabs/siderolink/commit/93b65f0619c38de7641d75f31a0c88f88b6a46d4) fix: ignore 'exist' error on interface managmeent\n* [`3c4d9e0`](https://github.com/siderolabs/siderolink/commit/3c4d9e0fac88d30d9b794c254e4e015633156001) chore: move IP to interface binding into NewDevice\n* [`f0b5e39`](https://github.com/siderolabs/siderolink/commit/f0b5e39d523c633f3345bf06071571385db8aecc) feat: use kernel wireguard implementation when available\n* [`1d2b7e1`](https://github.com/siderolabs/siderolink/commit/1d2b7e13e7d055b5717dfb7f5111ec242e41ab01) feat: allow setting peer endpoint using peer event\n* [`5d085d6`](https://github.com/siderolabs/siderolink/commit/5d085d6eac27471a1c0e256c55d8f6ae01b55b8e) feat: expose `wgDevice.Peers` from the `wireguard.Device` wrapper\n* [`3a5be65`](https://github.com/siderolabs/siderolink/commit/3a5be65da5bbf3f565766993093578094d72e3eb) fix: use correct method to generate Wireguard private key\n* [`8318a7e`](https://github.com/siderolabs/siderolink/commit/8318a7e1747cb43ec5879d45df2e9a7e2533486e) feat: accept join token in Provision payload\n* [`b38c192`](https://github.com/siderolabs/siderolink/commit/b38c192875e10a0a9758dde42c7f17cf66694d61) fix: build on Windows\n* [`9902ad2`](https://github.com/siderolabs/siderolink/commit/9902ad2774f0655e050233854b9d28dad0431f6c) feat: pass request context and node address to the events sink adapter\n* [`d0612a7`](https://github.com/siderolabs/siderolink/commit/d0612a724a1b1336a2bc6a99ed3178e3e40f6d9b) refactor: pass in listener to the log receiver\n* [`d86cdd5`](https://github.com/siderolabs/siderolink/commit/d86cdd59ee7a0e0504b739a913991c272c7fb3f5) feat: implement logreceiver for kernel logs\n* [`f7cadbc`](https://github.com/siderolabs/siderolink/commit/f7cadbcdfbb84d367e27b5af32e89c138d72d9d7) fix: handle duplicate peer updates\n* [`0755b24`](https://github.com/siderolabs/siderolink/commit/0755b24d4682410b251a2a9d662960da15153106) feat: initial implementation of SideroLink\n* [`ee73ea9`](https://github.com/siderolabs/siderolink/commit/ee73ea9575a81be7685f24936b2c48a4508a159e) feat: add Talos events sink proto files and the reference implementation\n* [`1e2cd9d`](https://github.com/siderolabs/siderolink/commit/1e2cd9d38621234a0a6010e33b1bab264f4d9bdf) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>22 commits</summary>\n<p>\n\n* [`e8f92b3`](https://github.com/siderolabs/tools/commit/e8f92b324a97cc2dabdf8dbd27e7024ae184cbdc) chore: bump tools\n* [`3b5f89a`](https://github.com/siderolabs/tools/commit/3b5f89a4be0f6c754d1c5bf6dd9a295ff2b6eb94) chore: update dependencies\n* [`6402b99`](https://github.com/siderolabs/tools/commit/6402b9990964789ff257e9e83823f52dd93540d2) feat: update OpenSSL to 1.1.1r\n* [`00e91b1`](https://github.com/siderolabs/tools/commit/00e91b1a3ca59f2e0a999f8345556527460683a4) feat: update releases\n* [`a264809`](https://github.com/siderolabs/tools/commit/a26480967908b86d57c787e55c81f788bdf00ce4) chore: bump go to 1.19.2\n* [`858cfe7`](https://github.com/siderolabs/tools/commit/858cfe7077b516d963149cd650a5e92f2c3c38ca) fix: no slack notifications on failure\n* [`ed85950`](https://github.com/siderolabs/tools/commit/ed859505f1ba7d6ace02e128e297b01b3eb62fee) chore: disable drone slack pipeline for renovate\n* [`5df6589`](https://github.com/siderolabs/tools/commit/5df658937f7bd667ceda8760e2e15ed85c80dc2c) chore: disable drone for renovate/dependabot\n* [`1f00d2e`](https://github.com/siderolabs/tools/commit/1f00d2e854cdf357c1192428bd44ee846af1b4e4) fix: revert gawk to 5.1.1\n* [`feeda1f`](https://github.com/siderolabs/tools/commit/feeda1fc708a0cdb461ac5967ec34bf24ccc2b62) chore: bump grpc-go\n* [`8542014`](https://github.com/siderolabs/tools/commit/8542014568a101fb6c03a76c91e59dcfb1b893b6) chore: bump deps\n* [`e5c4968`](https://github.com/siderolabs/tools/commit/e5c496893fb71ff19a33daa4c86792ed03187356) chore: update renovate config\n* [`f34f94d`](https://github.com/siderolabs/tools/commit/f34f94daa300baab0803f22cecee65b57ee3c1fd) chore: update renovate config\n* [`cef4cc6`](https://github.com/siderolabs/tools/commit/cef4cc67342c06904258bcf4b7ec681d4c732d53) chore: update renovate config\n* [`bab8e9e`](https://github.com/siderolabs/tools/commit/bab8e9ee8d0fc2dc1b5676a45175b507d8927e49) chore: add libbpf to tools\n* [`0a15f7b`](https://github.com/siderolabs/tools/commit/0a15f7bb35f479fbf5551ea4bf02f3716783e33f) chore: build pahole properly\n* [`a322d06`](https://github.com/siderolabs/tools/commit/a322d066483814db80a15b8c0c7f44224b134429) chore: remove img\n* [`c7ff47b`](https://github.com/siderolabs/tools/commit/c7ff47b27962cf0f6a95e07c6f45aa2a3c2c5c8b) feat: enable renovate dependency updates (3/3)\n* [`6e095cf`](https://github.com/siderolabs/tools/commit/6e095cf86a6f734b2f07cc1b854a9a37b055cacc) feat: enable renovate dependency updates (2/n)\n* [`bad1ad1`](https://github.com/siderolabs/tools/commit/bad1ad17f7fd1208fcbb70b950320f805a765868) feat: add renovatebot\n* [`7d6f9c3`](https://github.com/siderolabs/tools/commit/7d6f9c35a81392918560ea0c20b3c06b18501ea0) chore: bump gcc to 12.2.0\n* [`2719b4b`](https://github.com/siderolabs/tools/commit/2719b4be551134a9d70ab235f56889708377f3c5) chore: bump toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute/metadata**           v0.2.1 **_new_**\n* **github.com/BurntSushi/toml**                     v1.2.0 -> v1.2.1\n* **github.com/aws/aws-sdk-go**                      v1.44.76 -> v1.44.136\n* **github.com/containerd/containerd**               v1.6.8 -> v1.6.9\n* **github.com/cosi-project/runtime**                v0.1.1 -> v0.2.0-alpha.3\n* **github.com/docker/docker**                       v20.10.17 -> v20.10.21\n* **github.com/emicklei/dot**                        v1.0.0 -> v1.1.0\n* **github.com/fsnotify/fsnotify**                   v1.5.4 -> v1.6.0\n* **github.com/gdamore/tcell/v2**                    v2.5.2 -> v2.5.3\n* **github.com/google/go-cmp**                       v0.5.8 -> v0.5.9\n* **github.com/google/nftables**                     2eca00135732 -> 130caa4c31c9\n* **github.com/hetznercloud/hcloud-go**              v1.35.2 -> v1.37.0\n* **github.com/insomniacslk/dhcp**                   509691fd59ec -> 5308ebe5334c\n* **github.com/jsimonetti/rtnetlink**                v1.2.2 -> v1.2.3\n* **github.com/mdlayher/ethtool**                    856bd6cb8a38 -> 0e16326d06d1\n* **github.com/mdlayher/genetlink**                  v1.2.0 -> v1.3.0\n* **github.com/mdlayher/netlink**                    v1.6.0 -> v1.7.0\n* **github.com/opencontainers/image-spec**           c5a74bcca799 -> v1.1.0-rc2\n* **github.com/packethost/packngo**                  v0.25.0 -> v0.29.0\n* **github.com/pmorjan/kmod**                        v1.0.0 -> v1.1.0\n* **github.com/rivo/tview**                          0e6b21a48e96 -> 04a46906d2e9\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.9 -> v1.0.0-beta.10\n* **github.com/siderolabs/crypto**                   v0.4.0 **_new_**\n* **github.com/siderolabs/discovery-api**            v0.1.1 **_new_**\n* **github.com/siderolabs/discovery-client**         v0.1.1 -> v0.1.3\n* **github.com/siderolabs/extras**                   v1.2.0 -> v1.3.0-alpha.0-2-gb155fa0\n* **github.com/siderolabs/gen**                      v0.4.0 **_new_**\n* **github.com/siderolabs/go-blockdevice**           v0.4.1 **_new_**\n* **github.com/siderolabs/go-circular**              v0.1.0 **_new_**\n* **github.com/siderolabs/go-cmd**                   v0.1.1 **_new_**\n* **github.com/siderolabs/go-debug**                 v0.2.2 **_new_**\n* **github.com/siderolabs/go-kmsg**                  v0.1.2 **_new_**\n* **github.com/siderolabs/go-kubeconfig**            v0.1.0 **_new_**\n* **github.com/siderolabs/go-loadbalancer**          v0.2.1 **_new_**\n* **github.com/siderolabs/go-procfs**                v0.1.1 **_new_**\n* **github.com/siderolabs/go-retry**                 v0.3.2 **_new_**\n* **github.com/siderolabs/go-smbios**                v0.3.1 **_new_**\n* **github.com/siderolabs/go-tail**                  v0.1.0 **_new_**\n* **github.com/siderolabs/grpc-proxy**               v0.4.0 **_new_**\n* **github.com/siderolabs/net**                      v0.4.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.2.0-8-g970860d -> v1.3.0-alpha.0-38-g8b975a7\n* **github.com/siderolabs/siderolink**               v0.3.0 **_new_**\n* **github.com/siderolabs/talos/pkg/machinery**      v1.3.0-alpha.1 **_new_**\n* **github.com/siderolabs/tools**                    v1.2.0 -> v1.3.0-alpha.0-21-ge8f92b3\n* **github.com/spf13/cobra**                         v1.5.0 -> v1.6.1\n* **github.com/stretchr/testify**                    v1.8.0 -> v1.8.1\n* **github.com/u-root/u-root**                       v0.9.0 -> v0.10.0\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.9 -> v0.56.11\n* **go.etcd.io/etcd/api/v3**                         v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/v3**                      v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.4 -> v3.5.5\n* **go.uber.org/atomic**                             v1.9.0 -> v1.10.0\n* **go.uber.org/zap**                                v1.22.0 -> v1.23.0\n* **go4.org/netipx**                                 797b0c90d8ab **_new_**\n* **golang.org/x/net**                               3211cb980234 -> v0.2.0\n* **golang.org/x/sync**                              886fb9371eb4 -> v0.1.0\n* **golang.org/x/sys**                               fbc7d0a398ab -> v0.2.0\n* **golang.org/x/term**                              a9ba230a4035 -> v0.2.0\n* **golang.org/x/time**                              e5dcc9cfc0b9 -> v0.2.0\n* **golang.zx2c4.com/wireguard/wgctrl**              3d4a969bb56b -> 97bc4ad4a1cb\n* **google.golang.org/grpc**                         v1.48.0 -> v1.50.1\n* **k8s.io/api**                                     v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/apimachinery**                            v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/apiserver**                               v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/client-go**                               v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/component-base**                          v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/cri-api**                                 v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/klog/v2**                                 v2.70.1 -> v2.80.1\n* **k8s.io/kubectl**                                 v0.25.0 -> v0.26.0-beta.0\n* **k8s.io/kubelet**                                 v0.25.0 -> v0.26.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.65 -> v1.2.66\n\nPrevious release can be found at [v1.2.0](https://github.com/siderolabs/talos/releases/tag/v1.2.0)\n\n## [Talos 1.3.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.3.0-alpha.1) (2022-10-28)\n\nWelcome to the v1.3.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### kube-apiserver Audit Policy\n\nTalos now supports setting custom audit policy for `kube-apiserver` in the machine configuration.\n\n\n### Kernel Command Line ip= Argument\n\nTalos now supports referencing interface name via `enxMAC` address notation:\n\n```\nip=172.20.0.2::172.20.0.1:255.255.255.0::enx7085c2dfbc59\n```\n\n\n### etcd Consistency Check\n\nTalos enables [--experimental-compact-hash-check-enabled](https://github.com/etcd-io/etcd/pull/14120) option by default to improve\netcd store consistency guarantees.\n\nThis options is only available with etcd >= v3.5.5, so Talos doesn't support version of etcd before v3.5.5.\n\n\n### Exocale Platform\n\nTalos now supports new platform: Exoscale.\n\nExoscale provides a firewall, TCP load balancer and autoscale groups.\nIt works well with CCM and Kubernetes node autoscaler.\n\n\n### Kernel Modules\n\nTalos now supports settings kernel module parameters.\n\nEg:\n\n```yaml\nmachine:\n  kernel:\n    modules:\n      - name: \"br_netfilter\"\n        parameters:\n          - nf_conntrack_max=131072\n```\n\n\n### KubeSpan\n\nKubeSpan MTU link size is now configurable via `network.kubespan.mtu` setting in the machine configuration.\n\n\n### Routes\n\nTalos now supports setting MTU for a specific route.\n\n\n### Nano Pi R4S\n\nTalos now supports the Nano Pi R4S SBC.\n\n\n### Raspberry Generic Images\n\nThe Raspberry Pi 4 specific image has been deprecated and will be removed in the v1.4 release of Talos.\nTalos now ships a generic Raspberry Pi image that should support more Raspberry Pi variants.\nRefer to the docs at https://www.talos.dev/v1.3/talos-guides/install/single-board-computers/rpi_generic/ to find which ones are supported.\n\n\n### Encryption with secretbox\n\nBy default new clusters will use secretbox for encryption instead of AESCBC.\nIf both are configured secretbox will take precedence.\nOld clusters may keep using AESCBC.\nTo enable secretbox you may add an encryption secret at `cluster.secretboxEncryptionSecret`.\nYou should keep `aescbcEncryptionSecret` however, even if secretbox is enabled older data will still be encrypted with AESCBC.\n\nHow to generate the secret:\n\n```bash\ndd if=/dev/random of=/dev/stdout bs=32 count=1 | base64\n```\n\n\n### Static Pod Manifests\n\nThe directory \"/etc/kubernetes/manifests\" is now deprecated.\nStatic pods should always be configured in machine.pods.\nTo reenable support you may set `machine.kubelet.disableManifestsDirectory`.\n\nEg:\n\n```yaml\nmachine:\n  kubelet:\n    disableManifestsDirectory: no\n```\n\n\n### Component Updates\n\n* Kubernetes: v1.26.0-alpha.2\n* Flannel: v0.20.0\n* CoreDNS: v1.10.0\n* etcd: v3.5.5\n* Linux: 5.15.74\n\nTalos is built with Go 1.19.2.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Andrey Smirnov\n* Michal Witkowski\n* Artem Chernyshev\n* Dmitriy Matrenichev\n* Artem Chernyshev\n* Serge Logvinov\n* Andrey Smirnov\n* Philipp Sauter\n* Steve Francis\n* Alexey Palazhchenko\n* Andrew Rynhard\n* Tim Jones\n* Utku Ozdemir\n* Andrew Rynhard\n* Kris Reeves\n* Marvin Drees\n* Spencer Smith\n* Branden Cash\n* Brandon Nason\n* Cameron Brunner\n* DJAlPee\n* Daniel Low\n* Gerard de Leeuw\n* Jack Wink\n* Jon Stelly\n* Matt Zahorik\n* Maxim Makarov\n* Olli Janatuinen\n* Pau Campana\n* Rubens Farias\n* Sander Maijers\n* Seán C McCord\n* Spencer Smith\n* emattiza\n* killcity\n\n### Changes\n<details><summary>149 commits</summary>\n<p>\n\n* [`869f3b5a5`](https://github.com/siderolabs/talos/commit/869f3b5a51ac783e8b0a5a31a103c212a068672b) feat: network configuration improvements on the OpenStack platform\n* [`29f2195e1`](https://github.com/siderolabs/talos/commit/29f2195e130ecf66a911d0c75343486ee7c86046) feat: support exoscale cloud\n* [`8b4ae08d1`](https://github.com/siderolabs/talos/commit/8b4ae08d1c42a2cab4bbf0daac090e0882b5d4e9) fix: etcd snapshot command on Windows\n* [`8bfa7ac1d`](https://github.com/siderolabs/talos/commit/8bfa7ac1d6012746bf7264528eac5cacdd752e2b) feat: platform metadata resource\n* [`7e50e24c0`](https://github.com/siderolabs/talos/commit/7e50e24c0187e514876222857d44eedda79acc5a) fix: properly cleanup legacy static pod manifests directory\n* [`6ee47bcc6`](https://github.com/siderolabs/talos/commit/6ee47bcc61bd5b8684c43c0d8c020c574631c832) fix: support serving config for qemu launcher on IPv6\n* [`6c3d11b49`](https://github.com/siderolabs/talos/commit/6c3d11b49e94b33ccfdf29f93d3233e480b5e7f0) docs: admission control patch note\n* [`4ea3b99b5`](https://github.com/siderolabs/talos/commit/4ea3b99b527406b0bbf9cbfd22867431b143ed49) fix: serve static pod files on 127.0.0.1 instead of localhost\n* [`23842114f`](https://github.com/siderolabs/talos/commit/23842114f077d98cf7bdbf8912454623dff41bbb) feat: support encryption with secretbox\n* [`f6773c472`](https://github.com/siderolabs/talos/commit/f6773c472c0c1094045a26e34be2472a98dad510) docs: talos support on equinix metal\n* [`b307160f6`](https://github.com/siderolabs/talos/commit/b307160f613f2544c70be115c9a1ae0a7439ec52) chore: bump dependencies\n* [`d7edd0e2e`](https://github.com/siderolabs/talos/commit/d7edd0e2e6ec5e4cba8bfa119d244c7be09078d9) refactor: use go-circular, go-kubeconfig, and go-tail\n* [`c6e1702ec`](https://github.com/siderolabs/talos/commit/c6e1702eca2d310f6fad52e0f00bc91d7d6c4996) feat: use URL-based manifests to present static pods to the kubelet\n* [`136a795e5`](https://github.com/siderolabs/talos/commit/136a795e55b5be5f093aaf6b07039e86df971674) docs: update system requirements to mention dedicated disk usage\n* [`879e8c0bf`](https://github.com/siderolabs/talos/commit/879e8c0bfe31f6b35f8833cf55624cd934ded50b) chore: update kernel with BTF support\n* [`ceb0cd99a`](https://github.com/siderolabs/talos/commit/ceb0cd99ae0e29cadf69e121afdc439f3296ff74) feat: implement Talos API auth using SideroV1 signatures\n* [`e6fba7d3b`](https://github.com/siderolabs/talos/commit/e6fba7d3bc83d008518d7a032b309ddd212e0f81) chore: update dependencies\n* [`93e55b85f`](https://github.com/siderolabs/talos/commit/93e55b85f207060d053ba9f16267d98c2599a2df) chore: bump golangci-lint to v1.50.0\n* [`aa3d9b4ca`](https://github.com/siderolabs/talos/commit/aa3d9b4ca60f0a7e47867e1de134753eb914606b) fix: regenerate cert on node labeling retry\n* [`021c73c35`](https://github.com/siderolabs/talos/commit/021c73c35233ee5e6cb9cf5e83336eeb70ae05d3) fix: lowercase nodename\n* [`b902036e1`](https://github.com/siderolabs/talos/commit/b902036e12843d6348d945097d3826a50b040b25) docs: update office hours time link\n* [`7fcb8c681`](https://github.com/siderolabs/talos/commit/7fcb8c68164d72f14bca284daffc69605002acb5) feat: update Flannel to v0.20.0\n* [`dc70d892a`](https://github.com/siderolabs/talos/commit/dc70d892a341f0694be0c0ff5517b63ea6bbadd9) fix: support setting KubeSpan link MTU\n* [`7d52bad37`](https://github.com/siderolabs/talos/commit/7d52bad370d544d1a2862891e089426dff7c52a3) feat: update Linux to 5.15.73\n* [`9c78b3aff`](https://github.com/siderolabs/talos/commit/9c78b3aff48fd95f48ab2c951f7eb61273338e9a) feat: update Kubernetes to v1.26.0-alpha.2\n* [`94913a672`](https://github.com/siderolabs/talos/commit/94913a6727e9a802d2e14c141a831a8fddc8d9b2) docs: add lofty to talos adopters\n* [`0a0bdfe16`](https://github.com/siderolabs/talos/commit/0a0bdfe164625013e807cf5a08f590835894bf92) docs: add Tremor Video to adopters\n* [`b7b1d4fd6`](https://github.com/siderolabs/talos/commit/b7b1d4fd6a492c8e4c73b9f7f17449241903f868) feat: use readonly containers\n* [`d210338e3`](https://github.com/siderolabs/talos/commit/d210338e33438919fc8d2d83fc479981077d5164) fix: skip protobuf full unmarshaling for some talosctl commands\n* [`b3c679d18`](https://github.com/siderolabs/talos/commit/b3c679d18e698092795725e6fcb05d6569d681b1) chore: bump dependencies\n* [`993743f63`](https://github.com/siderolabs/talos/commit/993743f63495a59020670619abde5a0d5cd322e2) fix: skip hostname via DHCP on OpenStack platform\n* [`db076e7b5`](https://github.com/siderolabs/talos/commit/db076e7b5afca7c725c4c6876a7e05d643a219a1) feat: pin interface by mac address in cmdline args\n* [`63de93722`](https://github.com/siderolabs/talos/commit/63de937227362064a05fa3a9ba11f55891458cc7) fix: update go-smbios to v0.3.1\n* [`49e9f808e`](https://github.com/siderolabs/talos/commit/49e9f808e7b14af90959c7fca9457128e82f9cb5) chore: bump kernel and go\n* [`c7372144d`](https://github.com/siderolabs/talos/commit/c7372144de4b953ebe2494676143ea6d0e53e666) docs: add constraints to upgrade docs\n* [`c71c8ca18`](https://github.com/siderolabs/talos/commit/c71c8ca18fd4bb7dcae2f69ea253c16b9abd7a9d) docs: consolidate, simplify and correct various docs\n* [`06f76bfeb`](https://github.com/siderolabs/talos/commit/06f76bfebb14e7d826b8c7efe4564a94d841a74a) chore: bump dependencies\n* [`b1c421b9a`](https://github.com/siderolabs/talos/commit/b1c421b9ad90d36e8a3562aacdcc30c521da585a) chore: publish ami's with imds v2 enabled\n* [`195c40ab5`](https://github.com/siderolabs/talos/commit/195c40ab5908c3bcd0c8ecf5b6f7275bb9b7a499) docs: add information about applicable use cases of disk encryption\n* [`54a687fb8`](https://github.com/siderolabs/talos/commit/54a687fb8e68f3669ff140d37ff3fd01595a494d) docs: consolidate and expand on discovery service\n* [`139c62d76`](https://github.com/siderolabs/talos/commit/139c62d762c2a9001808d4e1bed38145ea86a95d) feat: allow upgrades in maintenance mode (only over SideroLink)\n* [`48dee4805`](https://github.com/siderolabs/talos/commit/48dee480577c9d1bb4620f78c6b4bbeba0f0d0bc) feat: support mtu for routes\n* [`1c43c72ae`](https://github.com/siderolabs/talos/commit/1c43c72aebd1a2bcc1991787dcd94c8bab00df42) docs: fix talos required kernel params\n* [`67cc45ae3`](https://github.com/siderolabs/talos/commit/67cc45ae3f9351cf5ae27c2c1a4c5d762a2d8b77) release(v1.3.0-alpha.0): prepare release\n* [`18c377a4d`](https://github.com/siderolabs/talos/commit/18c377a4d1ce046b310e3609033e9c1f39f9337b) feat: customize audit policy\n* [`23c9ea46b`](https://github.com/siderolabs/talos/commit/23c9ea46bba20d8b7cc336bbc64e04af46cccf5d) fix: raspberry pi install\n* [`f17cdee16`](https://github.com/siderolabs/talos/commit/f17cdee167cfd6d673e2ed71fd5c8d28399a80f3) feat: jsonpath filter for talosctl get outputs\n* [`6bd3cca1a`](https://github.com/siderolabs/talos/commit/6bd3cca1a8d206fb40199a9f0352aa2670fca754) chore: generic raspberry pi images\n* [`d914ab8bb`](https://github.com/siderolabs/talos/commit/d914ab8bb4a34cdb5ffc396a20a32a437c5989e1) chore: add vulncheck tool as a linter\n* [`a0151aa13`](https://github.com/siderolabs/talos/commit/a0151aa13e63b24aba7e39082f6cef3dac923a22) feat: add generic rpi u-boot support\n* [`30f851d09`](https://github.com/siderolabs/talos/commit/30f851d0931f5d6767e13142876c94dac67ec38b) chore: bump dependences\n* [`8b2235c3b`](https://github.com/siderolabs/talos/commit/8b2235c3b6de64abb15bf77e9648bf6bebc18e1f) fix: lookup Equinix Metal bond slaves using 'permanent addr'\n* [`b3257ebb1`](https://github.com/siderolabs/talos/commit/b3257ebb1c529a8f266ba3852d5e4191e0261a79) chore: bump kernel to 5.15.70\n* [`0b2767c16`](https://github.com/siderolabs/talos/commit/0b2767c1646e84ce147030692f3904b9feb02b3e) feat: implement 'permanent addr' in link statuses\n* [`c90e20251`](https://github.com/siderolabs/talos/commit/c90e20251d09a9bedcbd8b1a2055de5e126fc97e) fix: kubeconfig permission\n* [`fc48849d0`](https://github.com/siderolabs/talos/commit/fc48849d00c185442fb37c72e2c20462cc573a69) chore: move maps/slices/ordered to gen module\n* [`8b09bd4b0`](https://github.com/siderolabs/talos/commit/8b09bd4b0400f17ef543f0d117ae35e4ba2356cb) feat: update Kubernetes to v1.26.0-alpha.1\n* [`276d4175b`](https://github.com/siderolabs/talos/commit/276d4175bbd168d12409a1e96b191abdf09f2ff0) chore: bump extension versions in testing\n* [`357b770cb`](https://github.com/siderolabs/talos/commit/357b770cb593196fccaf9b6ba3cd740463351a07) fix: cryptsetup delete slot\n* [`711128839`](https://github.com/siderolabs/talos/commit/7111288393ae4dfdfa7331e39df1803724bc93c0) fix: continue applying bootstrap manifests on some errors\n* [`ce12c7b38`](https://github.com/siderolabs/talos/commit/ce12c7b3805da65315309a465aeed1764f0ce20a) chore: update COSI runtime to v0.2.0-alpha.1\n* [`1b435c0b3`](https://github.com/siderolabs/talos/commit/1b435c0b36a8d0d3e48c5a5e6121117933deeb69) chore: bump kernel + ice drivers\n* [`18e041f1e`](https://github.com/siderolabs/talos/commit/18e041f1ecb88d0b1e8e874d9b1fb580bc7c2297) docs: fix typo in patching example\n* [`0ad6452ca`](https://github.com/siderolabs/talos/commit/0ad6452ca152afef2f3c0e97a2255a237b30941a) feat: update CoreDNS to v1.10.0\n* [`479f3f52e`](https://github.com/siderolabs/talos/commit/479f3f52ee7149ff2a39bec3d8f78b59978af70a) chore: bump dependencies\n* [`e07c6ae99`](https://github.com/siderolabs/talos/commit/e07c6ae99ec347735cf0316294ef0c54ebc45234) feat: update Kubernetes to v1.25.1\n* [`13fdfaffc`](https://github.com/siderolabs/talos/commit/13fdfaffc4a0eb812cd63c5d188efd4aff6da51c) test: fix up default branch name\n* [`ef181321a`](https://github.com/siderolabs/talos/commit/ef181321a5be4d03e4f87aab1483b95a8e61f0fe) docs: add component diagram; K8s & Talos Linux\n* [`aade73643`](https://github.com/siderolabs/talos/commit/aade7364357da6644e8b70ad1dd939130f2fe470) docs: fix missing variable in OpenEBS docs\n* [`472590aa8`](https://github.com/siderolabs/talos/commit/472590aa82d16e1bd3825ecc8106886e7e1b9053) chore: return InvalidArgument on invalid config in maintenance mode\n* [`e5cabd42c`](https://github.com/siderolabs/talos/commit/e5cabd42cc7f86bee5486f73fa4068382bf6a7fb) feat: enable etcd consistency hashcheck\n* [`015535d90`](https://github.com/siderolabs/talos/commit/015535d9051dea243f439b385577d17fd57a122e) fix: update discovery client with the redirect fix\n* [`d0c8e7699`](https://github.com/siderolabs/talos/commit/d0c8e7699cf3e2415c5712ff9ff620c38857a0dc) chore: bump kernel and go\n* [`985b0c2e7`](https://github.com/siderolabs/talos/commit/985b0c2e796006f401376ebf30a1ce888d90a1c9) chore: remove go.work.sum\n* [`69124f102`](https://github.com/siderolabs/talos/commit/69124f10263bdabc556b58b98a3e1f129b85b8ab) feat: update etcd to v3.5.5\n* [`1985a796c`](https://github.com/siderolabs/talos/commit/1985a796c0d5a984c397754445b33827f5690806) docs: update docs for pod security\n* [`94b088f02`](https://github.com/siderolabs/talos/commit/94b088f02f8f8e5b63f0c38e8e091f2ba3329dde) fix: set etcd options consistently\n* [`92ae7ef4b`](https://github.com/siderolabs/talos/commit/92ae7ef4b1abe0a510fea31e0fde2566281f38b1) fix: fix protoenc encoding for enums and types with custom encoders\n* [`93809017c`](https://github.com/siderolabs/talos/commit/93809017c594b1faf1405932d884852eb0ce567c) docs: cpu scaling governor knowledgebase\n* [`7b270ff33`](https://github.com/siderolabs/talos/commit/7b270ff33d6bf74d1fa195c07f98233098b337e9) test: fix api controller test\n* [`2dadcd669`](https://github.com/siderolabs/talos/commit/2dadcd6695003eb940848583caa6ade53ef94fa0) fix: stop worker nodes from acting as apid routers\n* [`9eaf33f3f`](https://github.com/siderolabs/talos/commit/9eaf33f3f274e746ca1b442c0a1a0dae0cec088f) fix: never sign client certificate requests in trustd\n* [`436749124`](https://github.com/siderolabs/talos/commit/43674912479d3fb58c30e350fea9c4daf4ba45d4) feat: environment vars for extension service\n* [`0c0cb671e`](https://github.com/siderolabs/talos/commit/0c0cb671ead1f514b1f1eb89e8d78f455e1efedb) chore: mark machine configuration validation failure as InvalidArgument\n* [`f424e5340`](https://github.com/siderolabs/talos/commit/f424e53404db61bbdbcbe8fab7cfec91785aa628) fix: stop containers more thoroughly\n* [`12827b861`](https://github.com/siderolabs/talos/commit/12827b861c13bb9b83a2f0ea2960582e8be319f0) chore: move \"implements\" checks to compile time\n* [`3a67c42cb`](https://github.com/siderolabs/talos/commit/3a67c42cbfdbd565e0af500d97c264ef6095637b) fix: kill the task processes when cleaning up stale task\n* [`14a79e325`](https://github.com/siderolabs/talos/commit/14a79e325bf0ffa107aaee9c07d3501b7010693c) chore: bump dependencies\n* [`9beee92e7`](https://github.com/siderolabs/talos/commit/9beee92e71e712a2af24dee612e27c30cac39d0d) docs: fix double vv in Kubernetes version\n* [`688272515`](https://github.com/siderolabs/talos/commit/6882725157f4c2ea79c248f79160e362be6c2c07) fix: use different username for Talos Kubernetes API access\n* [`161a52a9e`](https://github.com/siderolabs/talos/commit/161a52a9ef60eb9c1c1a6c31b06d06894456300c) feat: check apid client certificate extended key usage\n* [`9dadc4a59`](https://github.com/siderolabs/talos/commit/9dadc4a599f52cc564f5411dd35bc981e482d24a) fix: include all node addresses into etcd cert SANs\n* [`71bfd3e43`](https://github.com/siderolabs/talos/commit/71bfd3e43cdc9790d3cb7a134c3b49256b1942a1) feat: update CoreDNS to 1.9.4\n* [`9df8f1ff1`](https://github.com/siderolabs/talos/commit/9df8f1ff1aebb24a6b0649ba491b10b23a0b2198) fix: list COSI APIs for the apid authenticator\n* [`31462450f`](https://github.com/siderolabs/talos/commit/31462450f19700dd6691ebc4b0c18edca4f6a1b7) fix: pass a pointer to specs.Mount into protoenc.Marshal\n* [`e626540df`](https://github.com/siderolabs/talos/commit/e626540dfb470386d0750f2f8bbaf4b5cb36b203) chore: avoid double API request logging in trustd\n* [`f62d17125`](https://github.com/siderolabs/talos/commit/f62d17125b8c1b26b0b62d22c2846f3a2ece37d1) chore: update crypto to use new import path siderolabs/crypto\n* [`ef27dd855`](https://github.com/siderolabs/talos/commit/ef27dd8553ee0e5467c3baaf4be18d1ccb30dad1) chore: bump dependencies\n* [`6472ae00b`](https://github.com/siderolabs/talos/commit/6472ae00b21c0f637b1e6610a8f3f71a1b775628) fix: automatically discard VIPs for etcd advertised addresses\n* [`5e21cca52`](https://github.com/siderolabs/talos/commit/5e21cca52d7462240bb42aafa225ee97d08bdc25) feat: support setting kernel parameters\n* [`bd56621cd`](https://github.com/siderolabs/talos/commit/bd56621cdf50d25013756a8792dc7b4d5354396f) feat: add structprotogen tool\n* [`cdb6bb2cc`](https://github.com/siderolabs/talos/commit/cdb6bb2cc78685c218506c61a477c8a8e569e861) feat: add Nano Pi R4S support\n* [`36c1f1d6e`](https://github.com/siderolabs/talos/commit/36c1f1d6e6aa50379343acba5348d8cc038b137e) fix: flip the client-server version check\n* [`cd6c53a97`](https://github.com/siderolabs/talos/commit/cd6c53a979236543afc302a67da627ee633883b3) docs: fork docs for v1.3\n* [`0847400f7`](https://github.com/siderolabs/talos/commit/0847400f728d67889b9f740a0359eb916108d8ea) fix: prevent panic on health check if a member has no IPs\n* [`7471d7f01`](https://github.com/siderolabs/talos/commit/7471d7f0174a5240fa3c4cd2f16325ec2a4f1810) feat: update Flannel to v0.19.2\n* [`148c75cfb`](https://github.com/siderolabs/talos/commit/148c75cfb99537f64d43a3add3259bf591cb79a9) docs: consolidate the control-plane documentation\n* [`353154281`](https://github.com/siderolabs/talos/commit/353154281a4cf72076b99160e50e617109f72996) fix: drop kube-system SA default binding\n* [`4f37b668b`](https://github.com/siderolabs/talos/commit/4f37b668befdbd26bc2d32106e0bcc654f7e6119) chore: remove capi hacks\n* [`1369afea8`](https://github.com/siderolabs/talos/commit/1369afea853423f22fde20effd431c3f8d906a9d) docs: make 1.2.0 docs default ones\n* [`7627cb0e3`](https://github.com/siderolabs/talos/commit/7627cb0e30a8b2a5a1cc30906b547511c9d3c98b) docs: add new `talosctl gen secrets`\n* [`8aa60a37a`](https://github.com/siderolabs/talos/commit/8aa60a37a6ea57bf54d558c7a2f54d806fad3173) chore: bump kernel to 5.15.64\n* [`a798dbd5d`](https://github.com/siderolabs/talos/commit/a798dbd5d2d9bc6d1410a56035550d44de934950) docs: update docs for upcoming 1.2.0 release\n* [`b2fec3c97`](https://github.com/siderolabs/talos/commit/b2fec3c975dba7b0bc2dc7d5447e62350057061b) fix: properly handle `configContext` being `nil` in Talos client\n* [`1c0977b3a`](https://github.com/siderolabs/talos/commit/1c0977b3af22f9f4b61b80ca6dcedf14a5ef63ae) fix: change the type of returned gRPC connection object from the client\n* [`41848e421`](https://github.com/siderolabs/talos/commit/41848e421496184008ad2302e3cb03a882c0f5bf) fix: expose Talos client gRPC connection via the function `Conn`\n* [`2e9be4af8`](https://github.com/siderolabs/talos/commit/2e9be4af8b521eca985c425f62dfc7a59d19e7da) chore: bump dependencies\n* [`d283aba3a`](https://github.com/siderolabs/talos/commit/d283aba3a3670cfde8ab9137deba3ab3b343906f) test: fix cli reboot test\n* [`0b339a9dc`](https://github.com/siderolabs/talos/commit/0b339a9dc508327347777619749ff1e2c3e47f37) feat: track progress of action API calls\n* [`072349812`](https://github.com/siderolabs/talos/commit/072349812506c5cd32159bb14bab5b294ee59811) fix: update COSI to the version with gRPC Wait fix\n* [`89d57aa81`](https://github.com/siderolabs/talos/commit/89d57aa816a57448d6e350698a8f6a5d128209ac) fix: always abort the maintenance service\n* [`f6fa74619`](https://github.com/siderolabs/talos/commit/f6fa7461932462160f40f670a5252fbc2981bdc3) fix: limit apid backoff max delay\n* [`d7ef346db`](https://github.com/siderolabs/talos/commit/d7ef346db8ea7d4f7676ae5e032a3c0d06823d47) fix: get command in the case 'nodes' are not set in the context\n* [`4e9c32256`](https://github.com/siderolabs/talos/commit/4e9c322564d7f65c82d636a9f80c0c5354455967) fix: correctly render hosts.toml with multiple endpoints\n* [`cdd0f08bc`](https://github.com/siderolabs/talos/commit/cdd0f08bc5d8d47bc2d21745ee5a13ced3632c8a) feat: check client <> server version in some Talos commands\n* [`446b0af58`](https://github.com/siderolabs/talos/commit/446b0af58bf273712374472bfa2777de5b7ac46f) chore: bump kernel and runc\n* [`8c203ce9b`](https://github.com/siderolabs/talos/commit/8c203ce9b1722c5832c506857cb56e14e2a34fe1) feat: remove the machine from the discovery service on reset\n* [`b59ca5810`](https://github.com/siderolabs/talos/commit/b59ca5810e6cf75f6a3042a47535431110004201) chore: move from inet.af/netaddr to net/netip and go4.org/netipx\n* [`053af1d59`](https://github.com/siderolabs/talos/commit/053af1d59ea266b84bb049460f92b33b32c1b82e) fix: update etcd certificates when node addresses changes\n* [`11edb2c6f`](https://github.com/siderolabs/talos/commit/11edb2c6f84fbbfba437361ce4dcd70c50eb08d8) test: re-enable upgrade tests\n* [`0310e2089`](https://github.com/siderolabs/talos/commit/0310e20890b11e1f4015e923eb9984aea1188d20) chore: bump github.com/siderolabs/protoenc to v0.1.5\n* [`29bd63240`](https://github.com/siderolabs/talos/commit/29bd632401ca694df0a2ab921a2a525b4c3440d8) chore: remove old build tags syntax\n* [`b500d0aa9`](https://github.com/siderolabs/talos/commit/b500d0aa9052ab5066eb6cde06bcdac3e998705a) chore: bump k8s to v1.25.0\n* [`29e574be7`](https://github.com/siderolabs/talos/commit/29e574be74c96211fd010ee5bd06675898f04db8) docs: update to v1.2.0-beta.1\n* [`26b549f2a`](https://github.com/siderolabs/talos/commit/26b549f2a12c3486b52a8877b8a0a4f985695c7d) chore: bump dependencies\n* [`8c3ac4c42`](https://github.com/siderolabs/talos/commit/8c3ac4c42bff1f1678ddb62e0f20a9c419460ad4) chore: limit GOMAXPROCS for Talos services\n* [`361e85b74`](https://github.com/siderolabs/talos/commit/361e85b7443f6f4ff24fbf99a9f9276b73b73ed4) fix: properly read kexec disabled sysctl\n* [`cfe6c2bc2`](https://github.com/siderolabs/talos/commit/cfe6c2bc2d42ca28f3a5b3217aa4d126777e3db6) docs: nvidia oss drivers\n* [`2f2d97b6b`](https://github.com/siderolabs/talos/commit/2f2d97b6b5663a0873db9d47b7706f2c0a531d8c) fix: don't wait for the hostname in maintenance mode\n* [`b15a63924`](https://github.com/siderolabs/talos/commit/b15a6392465aa2aa0df231c622ca1762972ccd20) chore: bump kernel to 5.15.62\n* [`a0d94be30`](https://github.com/siderolabs/talos/commit/a0d94be30d3dcf41b2b8b34a1caa6928a029f81a) fix: stable default hostname bias\n* [`da4cd34ef`](https://github.com/siderolabs/talos/commit/da4cd34ef5c5a01cfc3c3ee56b3f8c2f77997b49) feat: update etcd advertised peer addresses on the fly\n* [`faf92ce01`](https://github.com/siderolabs/talos/commit/faf92ce01661c5a9a86f9e579da3a2822d93f1f6) chore: bump kubernetes to v1.25.0-rc.1\n* [`52de919e3`](https://github.com/siderolabs/talos/commit/52de919e34789c36c4ee71ca133240b50b068064) chore: bump containerd to v1.6.8\n* [`7d43fc79b`](https://github.com/siderolabs/talos/commit/7d43fc79b1e913d51f111ecc7c2c8b3bfb36e679) fix: make 'ca', 'crt' and 'key' flags optional for 'talosctl config add'\n* [`fd467e02c`](https://github.com/siderolabs/talos/commit/fd467e02c1edcfc0eff656392ece5dd8ba1114f2) fix: handle grub config being empty in the `Revert` function\n* [`9492aca65`](https://github.com/siderolabs/talos/commit/9492aca652eec4d4049fef1c8d141696ed72a197) fix: clean up `cancelCtxMu` leftovers in PriorityLock\n* [`61e3eb2ea`](https://github.com/siderolabs/talos/commit/61e3eb2eaab1c7974a27440ddd98139a27dfb9dc) fix: talosctl edit mc loop\n* [`32db7a7f5`](https://github.com/siderolabs/talos/commit/32db7a7f5d6638fc0f731a009dfb0c1870c69083) fix: surround `cancelCtx` with the mutex\n</p>\n</details>\n\n### Changes since v1.3.0-alpha.0\n<details><summary>43 commits</summary>\n<p>\n\n* [`869f3b5a5`](https://github.com/siderolabs/talos/commit/869f3b5a51ac783e8b0a5a31a103c212a068672b) feat: network configuration improvements on the OpenStack platform\n* [`29f2195e1`](https://github.com/siderolabs/talos/commit/29f2195e130ecf66a911d0c75343486ee7c86046) feat: support exoscale cloud\n* [`8b4ae08d1`](https://github.com/siderolabs/talos/commit/8b4ae08d1c42a2cab4bbf0daac090e0882b5d4e9) fix: etcd snapshot command on Windows\n* [`8bfa7ac1d`](https://github.com/siderolabs/talos/commit/8bfa7ac1d6012746bf7264528eac5cacdd752e2b) feat: platform metadata resource\n* [`7e50e24c0`](https://github.com/siderolabs/talos/commit/7e50e24c0187e514876222857d44eedda79acc5a) fix: properly cleanup legacy static pod manifests directory\n* [`6ee47bcc6`](https://github.com/siderolabs/talos/commit/6ee47bcc61bd5b8684c43c0d8c020c574631c832) fix: support serving config for qemu launcher on IPv6\n* [`6c3d11b49`](https://github.com/siderolabs/talos/commit/6c3d11b49e94b33ccfdf29f93d3233e480b5e7f0) docs: admission control patch note\n* [`4ea3b99b5`](https://github.com/siderolabs/talos/commit/4ea3b99b527406b0bbf9cbfd22867431b143ed49) fix: serve static pod files on 127.0.0.1 instead of localhost\n* [`23842114f`](https://github.com/siderolabs/talos/commit/23842114f077d98cf7bdbf8912454623dff41bbb) feat: support encryption with secretbox\n* [`f6773c472`](https://github.com/siderolabs/talos/commit/f6773c472c0c1094045a26e34be2472a98dad510) docs: talos support on equinix metal\n* [`b307160f6`](https://github.com/siderolabs/talos/commit/b307160f613f2544c70be115c9a1ae0a7439ec52) chore: bump dependencies\n* [`d7edd0e2e`](https://github.com/siderolabs/talos/commit/d7edd0e2e6ec5e4cba8bfa119d244c7be09078d9) refactor: use go-circular, go-kubeconfig, and go-tail\n* [`c6e1702ec`](https://github.com/siderolabs/talos/commit/c6e1702eca2d310f6fad52e0f00bc91d7d6c4996) feat: use URL-based manifests to present static pods to the kubelet\n* [`136a795e5`](https://github.com/siderolabs/talos/commit/136a795e55b5be5f093aaf6b07039e86df971674) docs: update system requirements to mention dedicated disk usage\n* [`879e8c0bf`](https://github.com/siderolabs/talos/commit/879e8c0bfe31f6b35f8833cf55624cd934ded50b) chore: update kernel with BTF support\n* [`ceb0cd99a`](https://github.com/siderolabs/talos/commit/ceb0cd99ae0e29cadf69e121afdc439f3296ff74) feat: implement Talos API auth using SideroV1 signatures\n* [`e6fba7d3b`](https://github.com/siderolabs/talos/commit/e6fba7d3bc83d008518d7a032b309ddd212e0f81) chore: update dependencies\n* [`93e55b85f`](https://github.com/siderolabs/talos/commit/93e55b85f207060d053ba9f16267d98c2599a2df) chore: bump golangci-lint to v1.50.0\n* [`aa3d9b4ca`](https://github.com/siderolabs/talos/commit/aa3d9b4ca60f0a7e47867e1de134753eb914606b) fix: regenerate cert on node labeling retry\n* [`021c73c35`](https://github.com/siderolabs/talos/commit/021c73c35233ee5e6cb9cf5e83336eeb70ae05d3) fix: lowercase nodename\n* [`b902036e1`](https://github.com/siderolabs/talos/commit/b902036e12843d6348d945097d3826a50b040b25) docs: update office hours time link\n* [`7fcb8c681`](https://github.com/siderolabs/talos/commit/7fcb8c68164d72f14bca284daffc69605002acb5) feat: update Flannel to v0.20.0\n* [`dc70d892a`](https://github.com/siderolabs/talos/commit/dc70d892a341f0694be0c0ff5517b63ea6bbadd9) fix: support setting KubeSpan link MTU\n* [`7d52bad37`](https://github.com/siderolabs/talos/commit/7d52bad370d544d1a2862891e089426dff7c52a3) feat: update Linux to 5.15.73\n* [`9c78b3aff`](https://github.com/siderolabs/talos/commit/9c78b3aff48fd95f48ab2c951f7eb61273338e9a) feat: update Kubernetes to v1.26.0-alpha.2\n* [`94913a672`](https://github.com/siderolabs/talos/commit/94913a6727e9a802d2e14c141a831a8fddc8d9b2) docs: add lofty to talos adopters\n* [`0a0bdfe16`](https://github.com/siderolabs/talos/commit/0a0bdfe164625013e807cf5a08f590835894bf92) docs: add Tremor Video to adopters\n* [`b7b1d4fd6`](https://github.com/siderolabs/talos/commit/b7b1d4fd6a492c8e4c73b9f7f17449241903f868) feat: use readonly containers\n* [`d210338e3`](https://github.com/siderolabs/talos/commit/d210338e33438919fc8d2d83fc479981077d5164) fix: skip protobuf full unmarshaling for some talosctl commands\n* [`b3c679d18`](https://github.com/siderolabs/talos/commit/b3c679d18e698092795725e6fcb05d6569d681b1) chore: bump dependencies\n* [`993743f63`](https://github.com/siderolabs/talos/commit/993743f63495a59020670619abde5a0d5cd322e2) fix: skip hostname via DHCP on OpenStack platform\n* [`db076e7b5`](https://github.com/siderolabs/talos/commit/db076e7b5afca7c725c4c6876a7e05d643a219a1) feat: pin interface by mac address in cmdline args\n* [`63de93722`](https://github.com/siderolabs/talos/commit/63de937227362064a05fa3a9ba11f55891458cc7) fix: update go-smbios to v0.3.1\n* [`49e9f808e`](https://github.com/siderolabs/talos/commit/49e9f808e7b14af90959c7fca9457128e82f9cb5) chore: bump kernel and go\n* [`c7372144d`](https://github.com/siderolabs/talos/commit/c7372144de4b953ebe2494676143ea6d0e53e666) docs: add constraints to upgrade docs\n* [`c71c8ca18`](https://github.com/siderolabs/talos/commit/c71c8ca18fd4bb7dcae2f69ea253c16b9abd7a9d) docs: consolidate, simplify and correct various docs\n* [`06f76bfeb`](https://github.com/siderolabs/talos/commit/06f76bfebb14e7d826b8c7efe4564a94d841a74a) chore: bump dependencies\n* [`b1c421b9a`](https://github.com/siderolabs/talos/commit/b1c421b9ad90d36e8a3562aacdcc30c521da585a) chore: publish ami's with imds v2 enabled\n* [`195c40ab5`](https://github.com/siderolabs/talos/commit/195c40ab5908c3bcd0c8ecf5b6f7275bb9b7a499) docs: add information about applicable use cases of disk encryption\n* [`54a687fb8`](https://github.com/siderolabs/talos/commit/54a687fb8e68f3669ff140d37ff3fd01595a494d) docs: consolidate and expand on discovery service\n* [`139c62d76`](https://github.com/siderolabs/talos/commit/139c62d762c2a9001808d4e1bed38145ea86a95d) feat: allow upgrades in maintenance mode (only over SideroLink)\n* [`48dee4805`](https://github.com/siderolabs/talos/commit/48dee480577c9d1bb4620f78c6b4bbeba0f0d0bc) feat: support mtu for routes\n* [`1c43c72ae`](https://github.com/siderolabs/talos/commit/1c43c72aebd1a2bcc1991787dcd94c8bab00df42) docs: fix talos required kernel params\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>27 commits</summary>\n<p>\n\n* [`c3225ee`](https://github.com/siderolabs/crypto/commit/c3225eee603a8d1218c67e1bfe33ddde7953ed74) feat: allow CSR template subject field to be overridden\n* [`8570669`](https://github.com/siderolabs/crypto/commit/85706698dac8cddd0e9f41006bed059347d2ea26) chore: rename to siderolabs/crypto\n* [`e9df1b8`](https://github.com/siderolabs/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n* [`510b0d2`](https://github.com/siderolabs/crypto/commit/510b0d2753a89170d0c0f60e052a66484997a5b2) chore: add json tags\n* [`6fa2d93`](https://github.com/siderolabs/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n* [`9a63cba`](https://github.com/siderolabs/crypto/commit/9a63cba8dabd278f3080fa8c160613efc48c43f8) fix: add back support for generating ECDSA keys with P-256 and SHA512\n* [`893bc66`](https://github.com/siderolabs/crypto/commit/893bc66e4716a4cb7d1d5e66b5660ffc01f22823) fix: use SHA256 for ECDSA-P256\n* [`deec8d4`](https://github.com/siderolabs/crypto/commit/deec8d47700e10e3ea813bdce01377bd93c83367) chore: implement DeepCopy methods for PEMEncoded* types\n* [`d3cb772`](https://github.com/siderolabs/crypto/commit/d3cb77220384b3a3119a6f3ddb1340bbc811f1d1) feat: make possible to change KeyUsage\n* [`6bc5bb5`](https://github.com/siderolabs/crypto/commit/6bc5bb50c52767296a1b1cab6580e3fcf1358f34) chore: remove unused argument\n* [`cd18ef6`](https://github.com/siderolabs/crypto/commit/cd18ef62eb9f65d8b6730a2eb73e47e629949e1b) feat: add support for several organizations\n* [`97c888b`](https://github.com/siderolabs/crypto/commit/97c888b3924dd5ac70b8d30dd66b4370b5ab1edc) chore: add options to CSR\n* [`7776057`](https://github.com/siderolabs/crypto/commit/7776057f5086157873f62f6a21ec23fa9fd86e05) chore: fix typos\n* [`80df078`](https://github.com/siderolabs/crypto/commit/80df078327030af7e822668405bb4853c512bd7c) chore: remove named result parameters\n* [`15bdd28`](https://github.com/siderolabs/crypto/commit/15bdd282b74ac406ab243853c1b50338a1bc29d0) chore: minor updates\n* [`4f80b97`](https://github.com/siderolabs/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n* [`39584f1`](https://github.com/siderolabs/crypto/commit/39584f1b6e54e9966db1f16369092b2215707134) feat: support for key/certificate types RSA, Ed25519, ECDSA\n* [`cf75519`](https://github.com/siderolabs/crypto/commit/cf75519cab82bd1b128ae9b45107c6bb422bd96a) fix: function NewKeyPair should create certificate with proper subject\n* [`751c95a`](https://github.com/siderolabs/crypto/commit/751c95aa9434832a74deb6884cff7c5fd785db0b) feat: add 'PEMEncodedKey' which allows to transport keys in YAML\n* [`562c3b6`](https://github.com/siderolabs/crypto/commit/562c3b66f89866746c0ba47927c55f41afed0f7f) feat: add support for public RSA key in RSAKey\n* [`bda0e9c`](https://github.com/siderolabs/crypto/commit/bda0e9c24e80c658333822e2002e0bc671ac53a3) feat: enable more conversions between encoded and raw versions\n* [`e0dd56a`](https://github.com/siderolabs/crypto/commit/e0dd56ac47456f85c0b247999afa93fb87ebc78b) feat: add NotBefore option for x509 cert creation\n* [`12a4897`](https://github.com/siderolabs/crypto/commit/12a489768a6bb2c13e16e54617139c980f99a658) feat: add support for SPKI fingerprint generation and matching\n* [`d0c3eef`](https://github.com/siderolabs/crypto/commit/d0c3eef149ec9b713e7eca8c35a6214bd0a64bc4) fix: implement NewKeyPair\n* [`196679e`](https://github.com/siderolabs/crypto/commit/196679e9ec77cb709db54879ddeddd4eaafaea01) feat: move `pkg/grpc/tls` from `github.com/talos-systems/talos` as `./tls`\n* [`1ff6242`](https://github.com/siderolabs/crypto/commit/1ff6242c91bb298ceeb4acd65685cba952fe4178) chore: initial version as imported from talos-systems/talos\n* [`835063e`](https://github.com/siderolabs/crypto/commit/835063e055b28a525038b826a6d80cbe76402414) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>3 commits</summary>\n<p>\n\n* [`5b0c5e7`](https://github.com/siderolabs/discovery-api/commit/5b0c5e78097c1489457b148a7f13c73890f5ecad) chore: rename to siderolabs, rekres, etc\n* [`db279ef`](https://github.com/siderolabs/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/siderolabs/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`230f317`](https://github.com/siderolabs/discovery-client/commit/230f317a8e6e9542b82efcbac9f5cd7b9cff34b6) fix: reconnect the client on update failure\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`8f00d77`](https://github.com/siderolabs/extras/commit/8f00d7719f0a2312eaa3815ae8c7a91d000db661) feat: update tc-redirect-tap to the latest version\n* [`7c91844`](https://github.com/siderolabs/extras/commit/7c91844de76568335b7ccaec63cecec17401dd83) chore: bump go to 1.19.2\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>6 commits</summary>\n<p>\n\n* [`b3b6db8`](https://github.com/siderolabs/gen/commit/b3b6db858cb6ce46005edeb70776608e3f9bc402) fix: fix Copy documentation and implementation\n* [`521f737`](https://github.com/siderolabs/gen/commit/521f7371f40556ddce7f730c8de5e1888e40b621) feat: add xerrors package which contains additions to the std errors\n* [`726e066`](https://github.com/siderolabs/gen/commit/726e066dcb35c86f82866097bed806f22b936292) fix: rename tuples.go to pair.go and set proper package name\n* [`d8d7d25`](https://github.com/siderolabs/gen/commit/d8d7d25ce9a588609c00cb798206a01a866bf7a6) chore: minor additions\n* [`338a650`](https://github.com/siderolabs/gen/commit/338a65065f92eb6426a66c4a88a0cc02cc02e529) chore: add initial implementation and documentation\n* [`4fd8667`](https://github.com/siderolabs/gen/commit/4fd866707052c792a6adccbc28efec5debdd18a8) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>55 commits</summary>\n<p>\n\n* [`dcf6044`](https://github.com/siderolabs/go-blockdevice/commit/dcf6044c906b36f183e11b6553458c680126d1d9) chore: rekres and rename\n* [`9c4af49`](https://github.com/siderolabs/go-blockdevice/commit/9c4af492cc17279f0281fcd271e7423be78442bb) fix: cryptsetup remove slot\n* [`74ea471`](https://github.com/siderolabs/go-blockdevice/commit/74ea47109c4525bec139640fed6354ad3097f5fb) feat: add freebsd stubs\n* [`9fa801c`](https://github.com/siderolabs/go-blockdevice/commit/9fa801cf4da184e3560b9a18ba43d13316f172f9) feat: add ReadOnly attribute to Disk\n* [`fccee8b`](https://github.com/siderolabs/go-blockdevice/commit/fccee8bb082b105cb60db40cb01636efc3241b5f) chore: rekres the source, fix issues\n* [`d9c3a27`](https://github.com/siderolabs/go-blockdevice/commit/d9c3a273886113e24809ef1e9930fc982318217d) feat: support probing FAT12/FAT16 filesystems\n* [`b374eb4`](https://github.com/siderolabs/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n* [`ec428fe`](https://github.com/siderolabs/go-blockdevice/commit/ec428fed2ecd5a389833a88f8dc333762816db99) fix: lookup filesystem labels on the actual device path\n* [`7b9de26`](https://github.com/siderolabs/go-blockdevice/commit/7b9de26bc6bc3d54b95bd8e8fb3aade4b45adc6c) feat: read symlink fullpath in block device list function\n* [`6928ee4`](https://github.com/siderolabs/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/siderolabs/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n* [`15b182d`](https://github.com/siderolabs/go-blockdevice/commit/15b182db0cd233b163ed83d1724c7e28cf29d71a) fix: return partition table not exist when trying to read an empty dev\n* [`b9517d5`](https://github.com/siderolabs/go-blockdevice/commit/b9517d51120d385f97b0026f99ce3c4782940c37) fix: resize partition\n* [`70d2865`](https://github.com/siderolabs/go-blockdevice/commit/70d28650b398a14469cbb5356417355b0ba62956) fix: try to find cdrom disks\n* [`667bf53`](https://github.com/siderolabs/go-blockdevice/commit/667bf539b99ac34b629a0103ef7a7278a5a5f35d) fix: revert gpt partition not found\n* [`d7d4cdd`](https://github.com/siderolabs/go-blockdevice/commit/d7d4cdd7ac56c82caab19246b5decd59f12195eb) fix: gpt partition not found\n* [`33afba3`](https://github.com/siderolabs/go-blockdevice/commit/33afba347c0dce38a436c46a0aac26d2f99427c1) fix: also open in readonly mode when running `All` lookup method\n* [`e367f9d`](https://github.com/siderolabs/go-blockdevice/commit/e367f9dc7fa935f11672de0fdc8a89429285a07a) feat: make probe always open blockdevices in readonly mode\n* [`d981156`](https://github.com/siderolabs/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n* [`fe24303`](https://github.com/siderolabs/go-blockdevice/commit/fe2430349e9d734ce6dbf4e7b2e0f8a37bb22679) fix: perform correct PMBR partition calculations\n* [`2ec0c3c`](https://github.com/siderolabs/go-blockdevice/commit/2ec0c3cc0ff5ff705ed5c910ca1bcd5d93c7b102) fix: preserve the PMBR bootable flag when opening GPT partition\n* [`87816a8`](https://github.com/siderolabs/go-blockdevice/commit/87816a81cefc728cfe3cb221b476d8ed4b609fd8) feat: align partition to minimum I/O size\n* [`c34b59f`](https://github.com/siderolabs/go-blockdevice/commit/c34b59fb33a7ad8be18bb19bc8c8d8294b4b3a78) feat: expose more encryption options in the LUKS module\n* [`30c2bc3`](https://github.com/siderolabs/go-blockdevice/commit/30c2bc3cb62af52f0aea9ce347923b0649fb7928) feat: mark MBR bootable\n* [`1292574`](https://github.com/siderolabs/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/siderolabs/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n* [`1d830a2`](https://github.com/siderolabs/go-blockdevice/commit/1d830a25f64f6fb96a1bedd800c0b40b107dc833) fix: revert mark the EFI partition in PMBR as bootable\n* [`bec914f`](https://github.com/siderolabs/go-blockdevice/commit/bec914ffdda42abcfe642bc2cdfc9fcda56a74ee) fix: mark the EFI partition in PMBR as bootable\n* [`776b37d`](https://github.com/siderolabs/go-blockdevice/commit/776b37d31de0781f098f5d9d1894fbea3f2dfa1d) feat: add options to probe disk by various sysblock parameters\n* [`bb3ad73`](https://github.com/siderolabs/go-blockdevice/commit/bb3ad73f69836acc2785ec659435e24a531359e7) fix: align partition start to physical sector size\n* [`8f976c2`](https://github.com/siderolabs/go-blockdevice/commit/8f976c2031108651738ebd4db69fb09758754a28) feat: replace exec.Command with go-cmd module\n* [`1cf7f25`](https://github.com/siderolabs/go-blockdevice/commit/1cf7f252c38cf11ef07723de2debc27d1da6b520) fix: properly handle no child processes error from cmd.Wait\n* [`04a9851`](https://github.com/siderolabs/go-blockdevice/commit/04a98510c07fe8477f598befbfe6eaec4f4b73a2) feat: implement luks encryption provider\n* [`b0375e4`](https://github.com/siderolabs/go-blockdevice/commit/b0375e4267fdc6108bd9ff7a5dc97b80cd924b1d) feat: add an option to open block device with exclusive flock\n* [`5a1c7f7`](https://github.com/siderolabs/go-blockdevice/commit/5a1c7f768e016c93f6c0be130ffeaf34109b5b4d) refactor: add devname into gpt.Partition, refactor probe package\n* [`f2728a5`](https://github.com/siderolabs/go-blockdevice/commit/f2728a581972be977d863d5d9177a873b8f3fc7b) fix: keep contents of PMBR when writing it\n* [`2878460`](https://github.com/siderolabs/go-blockdevice/commit/2878460b54e8b8c3846c6a882ca9e1472c8b6b3b) fix: write second copy of partition entries\n* [`943b08b`](https://github.com/siderolabs/go-blockdevice/commit/943b08bc32a2156cffb23e92b8be9288de4a7421) fix: blockdevice reset should read partition table from disk\n* [`5b4ee44`](https://github.com/siderolabs/go-blockdevice/commit/5b4ee44cfd434a03ec2d7167bcc56d0f164c3fa2) fix: ignore `/dev/ram` devices\n* [`98754ec`](https://github.com/siderolabs/go-blockdevice/commit/98754ec2bb200acc9e9e573fa766754d60e25ff2) refactor: rewrite GPT library\n* [`2a1baad`](https://github.com/siderolabs/go-blockdevice/commit/2a1baadffdf8c9b65355e9af6e744aeab838c9db) fix: correctly build paths for `mmcblk` devices\n* [`8076344`](https://github.com/siderolabs/go-blockdevice/commit/8076344a95021f25ab5d1fbf5ea4fefc790f6c3c) fix: return proper disk size from GetDisks function\n* [`8742133`](https://github.com/siderolabs/go-blockdevice/commit/874213371a3fb0925aab45cbba68a957e3319525) chore: add common method to list available disks using /sys/block\n* [`c4b5833`](https://github.com/siderolabs/go-blockdevice/commit/c4b583363d63503ed7e4adb9a9fa64335f7e198d) feat: implement \"fast\" wipe\n* [`b4e67d7`](https://github.com/siderolabs/go-blockdevice/commit/b4e67d73d70d8dc06aa2b4986622dcb854dfc40c) feat: return resize status from Resize() function\n* [`ceae64e`](https://github.com/siderolabs/go-blockdevice/commit/ceae64edb3a591c6f6bbd75b1149d1cfe426dd8e) fix: sync kernel partition table incrementally\n* [`2cb9516`](https://github.com/siderolabs/go-blockdevice/commit/2cb95165aa67b0b839863b5ad89920c3ac7e2c82) fix: return correct error value from blkpg functions\n* [`cebe43d`](https://github.com/siderolabs/go-blockdevice/commit/cebe43d1fdc1e509437198e578faa9d5a804cc37) refactor: expose `InsertAt` method via interface\n* [`c40dcd8`](https://github.com/siderolabs/go-blockdevice/commit/c40dcd80c50b41c1f2a60ea6aa9d5fb3d3b180a3) fix: properly inform kernel about partition deletion\n* [`bb8ac5d`](https://github.com/siderolabs/go-blockdevice/commit/bb8ac5d6a25e279e16213f585dc8d02ba6ed645f) feat: implement disk wiping via several methods\n* [`23fb7dc`](https://github.com/siderolabs/go-blockdevice/commit/23fb7dc755325cfe12e48c8e8e31bebab9ddc2bc) feat: expose partition name (label)\n* [`ff3a821`](https://github.com/siderolabs/go-blockdevice/commit/ff3a8210be999b8bfb2019f19f8a8b50901c64cc) feat: implement 'InsertAt' method to insert partitions at any position\n* [`3d1ce4f`](https://github.com/siderolabs/go-blockdevice/commit/3d1ce4fc859fa614a4c5c54a10c0f5f4fce38bb6) fix: calculate last lba of partition correctly\n* [`b71540f`](https://github.com/siderolabs/go-blockdevice/commit/b71540f6c398e958bdb7c118396a736419f735d4) feat: copy initial version from talos-systems/talos\n* [`ca3c078`](https://github.com/siderolabs/go-blockdevice/commit/ca3c078da95e6497c9d41667dc242e32682e517d) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-circular\n<details><summary>2 commits</summary>\n<p>\n\n* [`507e0ec`](https://github.com/siderolabs/go-circular/commit/507e0ec7b70e7c8336c25640929ae7b04869dfa1) refactor: extract circular Go module\n* [`2234b3a`](https://github.com/siderolabs/go-circular/commit/2234b3ab14ec6a49b5ce48aaec108c6b3f33dc7f) docs: add README\n</p>\n</details>\n\n### Changes from siderolabs/go-kubeconfig\n<details><summary>2 commits</summary>\n<p>\n\n* [`e7fdd94`](https://github.com/siderolabs/go-kubeconfig/commit/e7fdd94573fa175784700cbb24b37a087e6ca35b) refactor: extract kubeconfig library as a Go module\n* [`50e91b8`](https://github.com/siderolabs/go-kubeconfig/commit/50e91b8ba9df2c14a82d0ba95ee8acad262497b6) docs: add REAMDE\n</p>\n</details>\n\n### Changes from siderolabs/go-loadbalancer\n<details><summary>11 commits</summary>\n<p>\n\n* [`438b71d`](https://github.com/siderolabs/go-loadbalancer/commit/438b71da2474525311ee6435606d7a6143696651) chore: update package path and rekres\n* [`5341eec`](https://github.com/siderolabs/go-loadbalancer/commit/5341eec63c6d3396a37be17506e081ad72ccaeb6) feat: implement public method to check if the route is Healthy\n* [`b578d47`](https://github.com/siderolabs/go-loadbalancer/commit/b578d477211476bbc34b1ea2c86d54f0d1b0cdc1) feat: add a way to configure loadbalancer options\n* [`c54d95d`](https://github.com/siderolabs/go-loadbalancer/commit/c54d95d8252780dc374032dc5fe10e7e84a15062) feat: implement control plane loadbalancer\n* [`4a6e29e`](https://github.com/siderolabs/go-loadbalancer/commit/4a6e29e7c02a2a94193a6014de04c2d2c79bdb02) refactor: clean up names, fix the lingering goroutines\n* [`af87d1c`](https://github.com/siderolabs/go-loadbalancer/commit/af87d1cbb79da35adabb9587a028db9b3e9fde1c) chore: apply new Kres rules\n* [`a445702`](https://github.com/siderolabs/go-loadbalancer/commit/a4457024d5189d754b2da4a30b14072a0e3f5f05) feat: allow dial timeout and keep alive period to be configurable\n* [`3c8f347`](https://github.com/siderolabs/go-loadbalancer/commit/3c8f3471d14e37866c65f73170ef83c038ae5a8c) feat: provide a way to configure logger for the loadbalancer\n* [`da8e987`](https://github.com/siderolabs/go-loadbalancer/commit/da8e987434c3d407679a40e213b12a8e1c98abb8) feat: implement Reconcile - ability to change upstream list on the fly\n* [`8b1dfa6`](https://github.com/siderolabs/go-loadbalancer/commit/8b1dfa6e80dea53d699a551221695ca99b2aadb2) feat: copy initial version from talos-systems/talos\n* [`c2f6a8f`](https://github.com/siderolabs/go-loadbalancer/commit/c2f6a8f88439608ea4b7623e6becdcf079cad217) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-smbios\n<details><summary>11 commits</summary>\n<p>\n\n* [`10c1dd8`](https://github.com/siderolabs/go-smbios/commit/10c1dd8f2a7a30cc4a00b90d76afcf3ff22bf8ae) fix: check for end of the slice properly\n* [`9ca8ce7`](https://github.com/siderolabs/go-smbios/commit/9ca8ce77b796f3f49c0b7fd70f184911da294dc1) chore: treat invalid strings as empty\n* [`dbc5f79`](https://github.com/siderolabs/go-smbios/commit/dbc5f794726f18f0736c1203a440b8148675bc04) chore: rekres+rename\n* [`3f1e775`](https://github.com/siderolabs/go-smbios/commit/3f1e775b7e3ef74be41461417d800ac81671a553) feat: rework destructuring of SMBIOS information and added some tests\n* [`fd5ec8c`](https://github.com/siderolabs/go-smbios/commit/fd5ec8ce4873790b7fbd46dba9d7f49c9de7176a) fix: remove useless (?) goroutines leading to data race error\n* [`d3a32be`](https://github.com/siderolabs/go-smbios/commit/d3a32bea731a0c2a60ce7f5eae60253300ef27e1) fix: return UUID in middle endian only on SMBIOS >= 2.6\n* [`fb425d4`](https://github.com/siderolabs/go-smbios/commit/fb425d4727e620b6a2b6ba49e405a2c6f0e46304) feat: add memory device\n* [`0bb4f96`](https://github.com/siderolabs/go-smbios/commit/0bb4f96a6679e8fc958903c4f451ca068f8e3c41) feat: add physical memory array\n* [`8019619`](https://github.com/siderolabs/go-smbios/commit/80196199691e7094946a207463c67fc42da6a0e2) feat: supply wake-up type in SMBIOS info\n* [`94b8c4e`](https://github.com/siderolabs/go-smbios/commit/94b8c4e489eef8c44cb1a2768678945d73e16e88) feat: initial implementation\n* [`864ed80`](https://github.com/siderolabs/go-smbios/commit/864ed80937edf072f7e7e63551aef0d1f7776111) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-tail\n<details><summary>2 commits</summary>\n<p>\n\n* [`962ae43`](https://github.com/siderolabs/go-tail/commit/962ae433288845cfc7f2aab0c0ef74777e2bd992) refactor: extract go-tail module\n* [`359c3cb`](https://github.com/siderolabs/go-tail/commit/359c3cbde0f6a0a49d6893b2d1f8cb7ee6df9efc) docs: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/grpc-proxy\n<details><summary>51 commits</summary>\n<p>\n\n* [`4cc7bbe`](https://github.com/siderolabs/grpc-proxy/commit/4cc7bbe397d74ee731398d67d34c214747957122) chore: rename to siderolabs/grpc-proxy, rekres\n* [`2c586db`](https://github.com/siderolabs/grpc-proxy/commit/2c586dbdda4e9c2bd09754beb13014c52b626db1) feat: pass fullMethodName to GetConnection\n* [`6dfa2cc`](https://github.com/siderolabs/grpc-proxy/commit/6dfa2cc80b6195844cae2dc2b2bc0b9b62246d8d) fix: ignore errors on duplicate `SetHeader` calls\n* [`b076302`](https://github.com/siderolabs/grpc-proxy/commit/b076302cc46ec6742e71fe1d49f6ec2d5d3a15dc) fix: use io.EOF error when no backend connections are available\n* [`82daca0`](https://github.com/siderolabs/grpc-proxy/commit/82daca0322a4293bd27071ae1ba8dd5097509d21) docs: update README\n* [`fa6843a`](https://github.com/siderolabs/grpc-proxy/commit/fa6843ae5b64500d481a1d031790406ed9df77d7) chore: fix spelling\n* [`c0a87d9`](https://github.com/siderolabs/grpc-proxy/commit/c0a87d95be9c62b0c4fd1fa694ef768e1f8e2391) chore: major cleanup of the code and build\n* [`ca3bc61`](https://github.com/siderolabs/grpc-proxy/commit/ca3bc6131f052aa000517339211335aaa4ebb640) fix: ignore some errors so that we don't spam the logs\n* [`5c579a7`](https://github.com/siderolabs/grpc-proxy/commit/5c579a7a61475bde3ec9c1efe000d2a55e2a3cb2) feat: allow different formats for messages streaming/unary\n* [`6c9f7b3`](https://github.com/siderolabs/grpc-proxy/commit/6c9f7b399173dd5769dbc4e8e366e78f05cead85) fix: allow mode to be set for each request being proxied\n* [`cc91c09`](https://github.com/siderolabs/grpc-proxy/commit/cc91c09782824e261bf1c861961a272aedb2b123) refactor: provide better public API, enforce proxying mode\n* [`d8d3a75`](https://github.com/siderolabs/grpc-proxy/commit/d8d3a751d1e71d006ba90379eed388c487bbb246) chore: update import paths after repo move\n* [`dbf07a4`](https://github.com/siderolabs/grpc-proxy/commit/dbf07a4d9e16fe3cf7407b9921c1746aa24ffaf6) Merge pull request  [#7](https://github.com/siderolabs/grpc-proxy/pull/7) from smira/one2many-4\n* [`fc0d27d`](https://github.com/siderolabs/grpc-proxy/commit/fc0d27dc6b5b9db35173f3e78778784a9e7c95bf) More tests, small code fixes, updated README.\n* [`d9ce0b1`](https://github.com/siderolabs/grpc-proxy/commit/d9ce0b1053a7f15ea65bf46e94cfe4154493bad7) Merge pull request  [#6](https://github.com/siderolabs/grpc-proxy/pull/6) from smira/one2many-3\n* [`2d37ba4`](https://github.com/siderolabs/grpc-proxy/commit/2d37ba444528a00f988671f3a01666e692739a37) Support for one2many streaming calls, tests.\n* [`817b035`](https://github.com/siderolabs/grpc-proxy/commit/817b03553ed7d97bd0da09283776d54592d7b5d4) Merge pull request  [#5](https://github.com/siderolabs/grpc-proxy/pull/5) from smira/one2many-2\n* [`436b338`](https://github.com/siderolabs/grpc-proxy/commit/436b3383a39fd860f3b2379ffab80a44ae1809f7) More unary one-2-many tests, error propagation.\n* [`1f0cb46`](https://github.com/siderolabs/grpc-proxy/commit/1f0cb466268f046e8e9fb78b1902411ac3a753ba) Merge pull request  [#4](https://github.com/siderolabs/grpc-proxy/pull/4) from smira/one2many-1\n* [`992a975`](https://github.com/siderolabs/grpc-proxy/commit/992a975ccf0b97e4be329c84bd3018652e8e50ae) Proxying one to many: first iteration\n* [`a0988ff`](https://github.com/siderolabs/grpc-proxy/commit/a0988ff2b29839892a7913acd76f26f4e7edcc3a) Merge pull request  [#3](https://github.com/siderolabs/grpc-proxy/pull/3) from smira/small-fixups\n* [`e3111ef`](https://github.com/siderolabs/grpc-proxy/commit/e3111ef2c16f0ee4bba597a2ab1ab6a2818c2734) Small fixups in preparation to add one-to-many proxying.\n* [`6d76ffc`](https://github.com/siderolabs/grpc-proxy/commit/6d76ffcff89f6636d3689ed1c9b0eebe87722114) Merge pull request  [#2](https://github.com/siderolabs/grpc-proxy/pull/2) from smira/backend-concept\n* [`2aad63a`](https://github.com/siderolabs/grpc-proxy/commit/2aad63ac5bae09232ea5ac80b42338e9e3af67c4) Add concept of a 'Backend', but still one to one proxying\n* [`7cc4610`](https://github.com/siderolabs/grpc-proxy/commit/7cc46101114a2779d6393e0e8f841bf3febb2753) Merge pull request  [#1](https://github.com/siderolabs/grpc-proxy/pull/1) from smira/build\n* [`37f01f3`](https://github.com/siderolabs/grpc-proxy/commit/37f01f3aab3b978a8fecb428fca4d4c722141229) Rework build to use GitHub Actions, linting updates.\n* [`0f1106e`](https://github.com/siderolabs/grpc-proxy/commit/0f1106ef9c766333b9acb4b81e705da4bade7215) Move error checking further up (#34)\n* [`d5b35f6`](https://github.com/siderolabs/grpc-proxy/commit/d5b35f634383bf8931f8798797daaf9c1a59235e) Update gRPC and fix tests (#27)\n* [`67591eb`](https://github.com/siderolabs/grpc-proxy/commit/67591eb23c48346a480470e462289835d96f70da) Break StreamDirector interface, fix metadata propagation for gRPC-Go>1.5. (#20)\n* [`97396d9`](https://github.com/siderolabs/grpc-proxy/commit/97396d94749c00db659393ba5123f707062f829f) Merge pull request  [#11](https://github.com/siderolabs/grpc-proxy/pull/11) from mwitkow/fix-close-bug\n* [`3fcbd37`](https://github.com/siderolabs/grpc-proxy/commit/3fcbd3737ec6baff505795417e48f162a7a3183c) fixup closing conns\n* [`a8f5f87`](https://github.com/siderolabs/grpc-proxy/commit/a8f5f87a2f5e6bc3643b78d64594195b2395a238) fixup tests, extend readme\n* [`428fa1c`](https://github.com/siderolabs/grpc-proxy/commit/428fa1c450320041e0ad8e251d6aed435401174e) Fix a channel closing bug\n* [`af55d61`](https://github.com/siderolabs/grpc-proxy/commit/af55d612de6c5723a5a59340704db7bc771023ff) Merge pull request  [#10](https://github.com/siderolabs/grpc-proxy/pull/10) from mwitkow/bugfix/streaming-fix\n* [`de4d3db`](https://github.com/siderolabs/grpc-proxy/commit/de4d3db538565636e1e977102f6f0bd1ed0ce9c2) remove spurious printfs\n* [`84242c4`](https://github.com/siderolabs/grpc-proxy/commit/84242c4e690da18d16d2ab8f2fa47e45986220b6) fix the \"i don't know who finished\" case\n* [`9b22f41`](https://github.com/siderolabs/grpc-proxy/commit/9b22f41d8535fa3e40908c78ae66066c7972b6d9) fix full duplex streaming\n* [`c2f7c98`](https://github.com/siderolabs/grpc-proxy/commit/c2f7c98b0b6cd180659aed31e98cbbc18d616b1c) update readme\n* [`d654141`](https://github.com/siderolabs/grpc-proxy/commit/d654141edcb92b7fa2bba9d3e690e569c72f8e9d) update README\n* [`f457856`](https://github.com/siderolabs/grpc-proxy/commit/f4578565f2d34dc89774128db2bfda3a328cba40) move to proxy subdirectory\n* [`4889d78`](https://github.com/siderolabs/grpc-proxy/commit/4889d78e468681601b8229c81807dcf37b00ff63) Add fixup scripts\n* [`ef60a37`](https://github.com/siderolabs/grpc-proxy/commit/ef60a37547d137e52873be183f2d7a5626d7c034) version 2 of the grpc-proxy, this time with fewer grpc upstream deps\n* [`07aeac1`](https://github.com/siderolabs/grpc-proxy/commit/07aeac13e988c0c0b3a886c79972e20408a765e0) Merge pull request  [#2](https://github.com/siderolabs/grpc-proxy/pull/2) from daniellowtw/master\n* [`e5c3df5`](https://github.com/siderolabs/grpc-proxy/commit/e5c3df5b2f0a1ffc4cb755cbe6b30b435e35de37) Fix compatibility with latest grpc library\n* [`52be0a5`](https://github.com/siderolabs/grpc-proxy/commit/52be0a559a85f0e2480bde6725f3f144396aa6ef) bugfix: fix gRPC Java deadlock, due to different dispatch logic\n* [`822df7d`](https://github.com/siderolabs/grpc-proxy/commit/822df7d86b556b703fc11798a3bdcbaeb60c18a6) Fix reference to mwitkow.\n* [`28341d1`](https://github.com/siderolabs/grpc-proxy/commit/28341d171dd4c1a52f46371ddfb5fd2240b79731) move out forward logic to method, allowing for use as `grpc.Server` not found handler.\n* [`89e28b4`](https://github.com/siderolabs/grpc-proxy/commit/89e28b42ee9dda8e36522b77e3771d9debc645e0) add reference to upstream grpc bug\n* [`00dd588`](https://github.com/siderolabs/grpc-proxy/commit/00dd588ae68adf4187a7fca87db45a73af4c834d) merge upstream `grpc.Server` changes changing the dispatch logic\n* [`77edc97`](https://github.com/siderolabs/grpc-proxy/commit/77edc9715de187dcbc9969e2f0e8a04d2087fd13) move to upstream `protobuf` from `gogo`\n* [`db71c3e`](https://github.com/siderolabs/grpc-proxy/commit/db71c3e7e812db8d75cb282dac38d953fcb436b3) initial commit, tested and working.\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>36 commits</summary>\n<p>\n\n* [`66c77e9`](https://github.com/siderolabs/pkgs/commit/66c77e9669a7e1c2ca6a2477fac809a34e3ce3f6) feat: re-enable build kernel with BTF enabled\n* [`98ef073`](https://github.com/siderolabs/pkgs/commit/98ef0736130e660b95720db1ac23b7a6e1506f3e) feat: enable INET_DIAG and FANOTFY_PERMISSIONS\n* [`8fe5cbc`](https://github.com/siderolabs/pkgs/commit/8fe5cbca8243eaa0a60cf1aee80ab3e2ad987e81) chore: update dependencies\n* [`554c0fe`](https://github.com/siderolabs/pkgs/commit/554c0fe295719e425453e3d763559193b01a8b03) feat: add fanotify and kprobes kernel options\n* [`54d7e5c`](https://github.com/siderolabs/pkgs/commit/54d7e5c8db1e54c999ba0b4a466fe65c54e0c663) fix: drbd package name\n* [`b4cb9e2`](https://github.com/siderolabs/pkgs/commit/b4cb9e2125e20aea52a57aaba981326deb8ae0df) feat: add 'drbd' package\n* [`91e73b3`](https://github.com/siderolabs/pkgs/commit/91e73b325431f997b0e19d6ba083c48a6ae5ff2a) feat: update dependencies\n* [`b6d0d96`](https://github.com/siderolabs/pkgs/commit/b6d0d969942234defbf08745c57e3141152662e3) chore: bump kernel to 5.15.72\n* [`b16dfe9`](https://github.com/siderolabs/pkgs/commit/b16dfe9699e43a03e47109c95ac0707cce038a49) chore: bump go to 1.19.2\n* [`861cc32`](https://github.com/siderolabs/pkgs/commit/861cc32274db424975544b67e6f10b3568980a11) chore: bump kernel to 5.15.71\n* [`0ac7773`](https://github.com/siderolabs/pkgs/commit/0ac77733506d2f0b0944ff569b6817ae44821bda) chore: use generic raspberry pi u-boot\n* [`d5633d4`](https://github.com/siderolabs/pkgs/commit/d5633d4838bd6e168b9c80f124540a30c29ae7be) chore: bump kernel to 5.15.70\n* [`39c0d43`](https://github.com/siderolabs/pkgs/commit/39c0d4364fd4eedd281e46ce7d305f2562e2cf78) feat: add generic rpi_arm64_defconfig configuration\n* [`ed269ca`](https://github.com/siderolabs/pkgs/commit/ed269cabad82446095221e45078c8ba85bce5c2e) chore: bump kernel to 5.15.69\n* [`f2f8333`](https://github.com/siderolabs/pkgs/commit/f2f83331f93a0a5d2dd1c013e2ff46900684096a) fix: no slack notifications on failure\n* [`6f0af33`](https://github.com/siderolabs/pkgs/commit/6f0af3390fc170f0cf57450adfada6a87de7ece4) chore: disable drone slack pipeline for renovate\n* [`32aea3f`](https://github.com/siderolabs/pkgs/commit/32aea3f005b93aaa91d52e4dfd04dd9ce9d564a9) chore: disable drone for renovate/dependabot\n* [`44579f0`](https://github.com/siderolabs/pkgs/commit/44579f0238993f529e2c141f42c99b32803fd6a5) fix: rollback xfsprogs to 5.18.0\n* [`792c0e3`](https://github.com/siderolabs/pkgs/commit/792c0e32ef6b1cf13514dc2693c4c302e1440d3b) feat: add gasket driver package\n* [`07f1898`](https://github.com/siderolabs/pkgs/commit/07f1898b231390b85519f83638946ed65adacc64) chore: update deps\n* [`f78f410`](https://github.com/siderolabs/pkgs/commit/f78f410d193953e730aeb14f4e148e47dfa827fd) chore: enable conntrack zones and timestamps\n* [`049b3c6`](https://github.com/siderolabs/pkgs/commit/049b3c6f080b9af76b1b2e924baade69db27bc0b) chore: enable intel ice drivers\n* [`606ff32`](https://github.com/siderolabs/pkgs/commit/606ff32cb7e75b6975749b6250b68352b71e943b) chore: bump deps\n* [`eee5c8a`](https://github.com/siderolabs/pkgs/commit/eee5c8af13ee1fe0b1e660a9581d4f1b14158a39) chore: disable irc in conntrack\n* [`70e6c46`](https://github.com/siderolabs/pkgs/commit/70e6c460d7b3bd5e154a4e681858832afcf32368) chore: bump kernel to 5.15.64\n* [`e510321`](https://github.com/siderolabs/pkgs/commit/e5103217e714bea04e06fd0c4940e84406cb68cf) chore: update renovate config\n* [`d1fa510`](https://github.com/siderolabs/pkgs/commit/d1fa510cc66ddc63a53482f6ced5573466049d49) feat: enable renovate bot\n* [`e427a77`](https://github.com/siderolabs/pkgs/commit/e427a778146664b988664008bfe20611f91216b0) chore: bump runc to v1.1.4\n* [`40e1215`](https://github.com/siderolabs/pkgs/commit/40e12152a027eb509330c41db21680b9a662fa05) chore: enable nfsv4.2 client support\n* [`15efada`](https://github.com/siderolabs/pkgs/commit/15efadaa9db4b8dc8003359d6d0ed84016f54746) chore: bump kernel to 5.15.63\n* [`e70e3c1`](https://github.com/siderolabs/pkgs/commit/e70e3c1af2b11d4b4646401a617b3d0efa2db4a3) fix: nvidia oss pkg name\n* [`30b8d79`](https://github.com/siderolabs/pkgs/commit/30b8d79b9ca3e463b5f403f01d39e64e89edc7b1) chore: bump kernel to 5.15.62\n* [`862c392`](https://github.com/siderolabs/pkgs/commit/862c392b6defe3c9ce90f9b15eae154e021b0b4d) chore: bump gcc to 12.2.0\n* [`2ecd14e`](https://github.com/siderolabs/pkgs/commit/2ecd14ede04637a581fbe7dcbbf612cdd6f9d882) fix: containerd version\n* [`01df058`](https://github.com/siderolabs/pkgs/commit/01df0583a430f3793f19725c920e942cf37efee4) feat: add NanoPi R4S configuration\n* [`d4cb33b`](https://github.com/siderolabs/pkgs/commit/d4cb33b9bdfb8c27ea86a42ea60a88e294129ad4) chore: bump containerd to v1.6.8\n</p>\n</details>\n\n### Changes from siderolabs/siderolink\n<details><summary>18 commits</summary>\n<p>\n\n* [`61ab1c4`](https://github.com/siderolabs/siderolink/commit/61ab1c43dd04faeb046c51dca7d891213762a31e) fix: include MachineStatusEvent into the list of supported events\n* [`16a84eb`](https://github.com/siderolabs/siderolink/commit/16a84ebe6759535c7a5284271418f7f04443e25f) chore: rename to siderolabs/siderolink\n* [`ca470c7`](https://github.com/siderolabs/siderolink/commit/ca470c735e6922b7d5afea91aef50c043f9563ee) chore: update Talos to the latest master, migrate netaddr -> netip/x\n* [`93b65f0`](https://github.com/siderolabs/siderolink/commit/93b65f0619c38de7641d75f31a0c88f88b6a46d4) fix: ignore 'exist' error on interface managmeent\n* [`3c4d9e0`](https://github.com/siderolabs/siderolink/commit/3c4d9e0fac88d30d9b794c254e4e015633156001) chore: move IP to interface binding into NewDevice\n* [`f0b5e39`](https://github.com/siderolabs/siderolink/commit/f0b5e39d523c633f3345bf06071571385db8aecc) feat: use kernel wireguard implementation when available\n* [`1d2b7e1`](https://github.com/siderolabs/siderolink/commit/1d2b7e13e7d055b5717dfb7f5111ec242e41ab01) feat: allow setting peer endpoint using peer event\n* [`5d085d6`](https://github.com/siderolabs/siderolink/commit/5d085d6eac27471a1c0e256c55d8f6ae01b55b8e) feat: expose `wgDevice.Peers` from the `wireguard.Device` wrapper\n* [`3a5be65`](https://github.com/siderolabs/siderolink/commit/3a5be65da5bbf3f565766993093578094d72e3eb) fix: use correct method to generate Wireguard private key\n* [`8318a7e`](https://github.com/siderolabs/siderolink/commit/8318a7e1747cb43ec5879d45df2e9a7e2533486e) feat: accept join token in Provision payload\n* [`b38c192`](https://github.com/siderolabs/siderolink/commit/b38c192875e10a0a9758dde42c7f17cf66694d61) fix: build on Windows\n* [`9902ad2`](https://github.com/siderolabs/siderolink/commit/9902ad2774f0655e050233854b9d28dad0431f6c) feat: pass request context and node address to the events sink adapter\n* [`d0612a7`](https://github.com/siderolabs/siderolink/commit/d0612a724a1b1336a2bc6a99ed3178e3e40f6d9b) refactor: pass in listener to the log receiver\n* [`d86cdd5`](https://github.com/siderolabs/siderolink/commit/d86cdd59ee7a0e0504b739a913991c272c7fb3f5) feat: implement logreceiver for kernel logs\n* [`f7cadbc`](https://github.com/siderolabs/siderolink/commit/f7cadbcdfbb84d367e27b5af32e89c138d72d9d7) fix: handle duplicate peer updates\n* [`0755b24`](https://github.com/siderolabs/siderolink/commit/0755b24d4682410b251a2a9d662960da15153106) feat: initial implementation of SideroLink\n* [`ee73ea9`](https://github.com/siderolabs/siderolink/commit/ee73ea9575a81be7685f24936b2c48a4508a159e) feat: add Talos events sink proto files and the reference implementation\n* [`1e2cd9d`](https://github.com/siderolabs/siderolink/commit/1e2cd9d38621234a0a6010e33b1bab264f4d9bdf) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>21 commits</summary>\n<p>\n\n* [`3b5f89a`](https://github.com/siderolabs/tools/commit/3b5f89a4be0f6c754d1c5bf6dd9a295ff2b6eb94) chore: update dependencies\n* [`6402b99`](https://github.com/siderolabs/tools/commit/6402b9990964789ff257e9e83823f52dd93540d2) feat: update OpenSSL to 1.1.1r\n* [`00e91b1`](https://github.com/siderolabs/tools/commit/00e91b1a3ca59f2e0a999f8345556527460683a4) feat: update releases\n* [`a264809`](https://github.com/siderolabs/tools/commit/a26480967908b86d57c787e55c81f788bdf00ce4) chore: bump go to 1.19.2\n* [`858cfe7`](https://github.com/siderolabs/tools/commit/858cfe7077b516d963149cd650a5e92f2c3c38ca) fix: no slack notifications on failure\n* [`ed85950`](https://github.com/siderolabs/tools/commit/ed859505f1ba7d6ace02e128e297b01b3eb62fee) chore: disable drone slack pipeline for renovate\n* [`5df6589`](https://github.com/siderolabs/tools/commit/5df658937f7bd667ceda8760e2e15ed85c80dc2c) chore: disable drone for renovate/dependabot\n* [`1f00d2e`](https://github.com/siderolabs/tools/commit/1f00d2e854cdf357c1192428bd44ee846af1b4e4) fix: revert gawk to 5.1.1\n* [`feeda1f`](https://github.com/siderolabs/tools/commit/feeda1fc708a0cdb461ac5967ec34bf24ccc2b62) chore: bump grpc-go\n* [`8542014`](https://github.com/siderolabs/tools/commit/8542014568a101fb6c03a76c91e59dcfb1b893b6) chore: bump deps\n* [`e5c4968`](https://github.com/siderolabs/tools/commit/e5c496893fb71ff19a33daa4c86792ed03187356) chore: update renovate config\n* [`f34f94d`](https://github.com/siderolabs/tools/commit/f34f94daa300baab0803f22cecee65b57ee3c1fd) chore: update renovate config\n* [`cef4cc6`](https://github.com/siderolabs/tools/commit/cef4cc67342c06904258bcf4b7ec681d4c732d53) chore: update renovate config\n* [`bab8e9e`](https://github.com/siderolabs/tools/commit/bab8e9ee8d0fc2dc1b5676a45175b507d8927e49) chore: add libbpf to tools\n* [`0a15f7b`](https://github.com/siderolabs/tools/commit/0a15f7bb35f479fbf5551ea4bf02f3716783e33f) chore: build pahole properly\n* [`a322d06`](https://github.com/siderolabs/tools/commit/a322d066483814db80a15b8c0c7f44224b134429) chore: remove img\n* [`c7ff47b`](https://github.com/siderolabs/tools/commit/c7ff47b27962cf0f6a95e07c6f45aa2a3c2c5c8b) feat: enable renovate dependency updates (3/3)\n* [`6e095cf`](https://github.com/siderolabs/tools/commit/6e095cf86a6f734b2f07cc1b854a9a37b055cacc) feat: enable renovate dependency updates (2/n)\n* [`bad1ad1`](https://github.com/siderolabs/tools/commit/bad1ad17f7fd1208fcbb70b950320f805a765868) feat: add renovatebot\n* [`7d6f9c3`](https://github.com/siderolabs/tools/commit/7d6f9c35a81392918560ea0c20b3c06b18501ea0) chore: bump gcc to 12.2.0\n* [`2719b4b`](https://github.com/siderolabs/tools/commit/2719b4be551134a9d70ab235f56889708377f3c5) chore: bump toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.8.0 -> v1.10.0\n* **github.com/BurntSushi/toml**                     v1.2.0 -> v1.2.1\n* **github.com/aws/aws-sdk-go**                      v1.44.76 -> v1.44.122\n* **github.com/containerd/containerd**               v1.6.8 -> v1.6.9\n* **github.com/cosi-project/runtime**                v0.1.1 -> e8a8fdcc7548\n* **github.com/docker/docker**                       v20.10.17 -> v20.10.20\n* **github.com/fsnotify/fsnotify**                   v1.5.4 -> v1.6.0\n* **github.com/google/go-cmp**                       v0.5.8 -> v0.5.9\n* **github.com/google/nftables**                     2eca00135732 -> 4f5cd5826fbd\n* **github.com/hetznercloud/hcloud-go**              v1.35.2 -> v1.35.3\n* **github.com/insomniacslk/dhcp**                   509691fd59ec -> 5308ebe5334c\n* **github.com/jsimonetti/rtnetlink**                v1.2.2 -> v1.2.3\n* **github.com/mdlayher/ethtool**                    856bd6cb8a38 -> 0e16326d06d1\n* **github.com/mdlayher/netlink**                    v1.6.0 -> v1.6.2\n* **github.com/opencontainers/image-spec**           c5a74bcca799 -> v1.1.0-rc2\n* **github.com/packethost/packngo**                  v0.25.0 -> v0.28.1\n* **github.com/rivo/tview**                          0e6b21a48e96 -> 2e69b7385a37\n* **github.com/siderolabs/crypto**                   v0.4.0 **_new_**\n* **github.com/siderolabs/discovery-api**            v0.1.1 **_new_**\n* **github.com/siderolabs/discovery-client**         v0.1.1 -> v0.1.2\n* **github.com/siderolabs/extras**                   v1.2.0 -> v1.3.0-alpha.0-1-g8f00d77\n* **github.com/siderolabs/gen**                      v0.4.0 **_new_**\n* **github.com/siderolabs/go-blockdevice**           v0.4.0 **_new_**\n* **github.com/siderolabs/go-circular**              v0.1.0 **_new_**\n* **github.com/siderolabs/go-kubeconfig**            v0.1.0 **_new_**\n* **github.com/siderolabs/go-loadbalancer**          v0.2.0 **_new_**\n* **github.com/siderolabs/go-smbios**                v0.3.1 **_new_**\n* **github.com/siderolabs/go-tail**                  v0.1.0 **_new_**\n* **github.com/siderolabs/grpc-proxy**               v0.4.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.2.0-8-g970860d -> v1.3.0-alpha.0-35-g66c77e9\n* **github.com/siderolabs/siderolink**               v0.2.0 **_new_**\n* **github.com/siderolabs/tools**                    v1.2.0 -> v1.3.0-alpha.0-20-g3b5f89a\n* **github.com/spf13/cobra**                         v1.5.0 -> v1.6.1\n* **github.com/stretchr/testify**                    v1.8.0 -> v1.8.1\n* **github.com/u-root/u-root**                       v0.9.0 -> v0.10.0\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.9 -> v0.56.10\n* **go.etcd.io/etcd/api/v3**                         v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/v3**                      v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.4 -> v3.5.5\n* **go.uber.org/atomic**                             v1.9.0 -> v1.10.0\n* **go.uber.org/zap**                                v1.22.0 -> v1.23.0\n* **go4.org/netipx**                                 797b0c90d8ab **_new_**\n* **golang.org/x/net**                               3211cb980234 -> v0.1.0\n* **golang.org/x/sync**                              886fb9371eb4 -> v0.1.0\n* **golang.org/x/sys**                               fbc7d0a398ab -> v0.1.0\n* **golang.org/x/term**                              a9ba230a4035 -> v0.1.0\n* **golang.org/x/time**                              e5dcc9cfc0b9 -> v0.1.0\n* **golang.zx2c4.com/wireguard/wgctrl**              3d4a969bb56b -> 473347a5e6e3\n* **google.golang.org/grpc**                         v1.48.0 -> v1.50.1\n* **k8s.io/api**                                     v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/apimachinery**                            v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/apiserver**                               v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/client-go**                               v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/component-base**                          v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/cri-api**                                 v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/kubectl**                                 v0.25.0 -> v0.26.0-alpha.2\n* **k8s.io/kubelet**                                 v0.25.0 -> v0.26.0-alpha.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.65 -> v1.2.66\n\nPrevious release can be found at [v1.2.0](https://github.com/siderolabs/talos/releases/tag/v1.2.0)\n\n## [Talos 1.3.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.3.0-alpha.0) (2022-09-28)\n\nWelcome to the v1.3.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### kube-apiserver Audit Policy\n\nTalos now supports setting custom audit policy for `kube-apiserver` in the machine configuration.\n\n\n### etcd Consistency Check\n\nTalos enables [--experimental-compact-hash-check-enabled](https://github.com/etcd-io/etcd/pull/14120) option by default to improve\netcd store consistency guarantees.\n\nThis options is only available with etcd >= v3.5.5, so Talos doesn't support version of etcd before v3.5.5.\n\n\n### Kernel Modules\n\nTalos now supports settings kernel module parameters.\n\nEg:\n\n```yaml\nmachine:\n  kernel:\n    modules:\n      - name: \"br_netfilter\"\n        parameters:\n          - nf_conntrack_max=131072\n```\n\n\n### Nano Pi R4S\n\nTalos now supports the Nano Pi R4S SBC.\n\n\n### Raspberry Generic Images\n\nThe Raspberry Pi 4 specific image has been deprecated and will be removed in the v1.4 release of Talos.\nTalos now ships a generic Raspberry Pi image that should support more Raspberry Pi variants.\nRefer to the docs at https://www.talos.dev/v1.3/talos-guides/install/single-board-computers/rpi_generic/ to find which ones are supported.\n\n\n### Component Updates\n\n* Kubernetes: v1.26.0-alpha.1\n* Flannel: v0.19.2\n* CoreDNS: v1.10.0\n* etcd: v3.5.5\n* Linux: 5.15.70\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Andrey Smirnov\n* Artem Chernyshev\n* Dmitriy Matrenichev\n* Artem Chernyshev\n* Alexey Palazhchenko\n* Serge Logvinov\n* Andrew Rynhard\n* Utku Ozdemir\n* Kris Reeves\n* Marvin Drees\n* Philipp Sauter\n* Andrew Rynhard\n* Branden Cash\n* Matt Zahorik\n* Olli Janatuinen\n* Pau Campana\n* Sander Maijers\n* Seán C McCord\n* Spencer Smith\n* Steve Francis\n* Tim Jones\n\n### Changes\n<details><summary>105 commits</summary>\n<p>\n\n* [`18c377a4d`](https://github.com/siderolabs/talos/commit/18c377a4d1ce046b310e3609033e9c1f39f9337b) feat: customize audit policy\n* [`23c9ea46b`](https://github.com/siderolabs/talos/commit/23c9ea46bba20d8b7cc336bbc64e04af46cccf5d) fix: raspberry pi install\n* [`f17cdee16`](https://github.com/siderolabs/talos/commit/f17cdee167cfd6d673e2ed71fd5c8d28399a80f3) feat: jsonpath filter for talosctl get outputs\n* [`6bd3cca1a`](https://github.com/siderolabs/talos/commit/6bd3cca1a8d206fb40199a9f0352aa2670fca754) chore: generic raspberry pi images\n* [`d914ab8bb`](https://github.com/siderolabs/talos/commit/d914ab8bb4a34cdb5ffc396a20a32a437c5989e1) chore: add vulncheck tool as a linter\n* [`a0151aa13`](https://github.com/siderolabs/talos/commit/a0151aa13e63b24aba7e39082f6cef3dac923a22) feat: add generic rpi u-boot support\n* [`30f851d09`](https://github.com/siderolabs/talos/commit/30f851d0931f5d6767e13142876c94dac67ec38b) chore: bump dependences\n* [`8b2235c3b`](https://github.com/siderolabs/talos/commit/8b2235c3b6de64abb15bf77e9648bf6bebc18e1f) fix: lookup Equinix Metal bond slaves using 'permanent addr'\n* [`b3257ebb1`](https://github.com/siderolabs/talos/commit/b3257ebb1c529a8f266ba3852d5e4191e0261a79) chore: bump kernel to 5.15.70\n* [`0b2767c16`](https://github.com/siderolabs/talos/commit/0b2767c1646e84ce147030692f3904b9feb02b3e) feat: implement 'permanent addr' in link statuses\n* [`c90e20251`](https://github.com/siderolabs/talos/commit/c90e20251d09a9bedcbd8b1a2055de5e126fc97e) fix: kubeconfig permission\n* [`fc48849d0`](https://github.com/siderolabs/talos/commit/fc48849d00c185442fb37c72e2c20462cc573a69) chore: move maps/slices/ordered to gen module\n* [`8b09bd4b0`](https://github.com/siderolabs/talos/commit/8b09bd4b0400f17ef543f0d117ae35e4ba2356cb) feat: update Kubernetes to v1.26.0-alpha.1\n* [`276d4175b`](https://github.com/siderolabs/talos/commit/276d4175bbd168d12409a1e96b191abdf09f2ff0) chore: bump extension versions in testing\n* [`357b770cb`](https://github.com/siderolabs/talos/commit/357b770cb593196fccaf9b6ba3cd740463351a07) fix: cryptsetup delete slot\n* [`711128839`](https://github.com/siderolabs/talos/commit/7111288393ae4dfdfa7331e39df1803724bc93c0) fix: continue applying bootstrap manifests on some errors\n* [`ce12c7b38`](https://github.com/siderolabs/talos/commit/ce12c7b3805da65315309a465aeed1764f0ce20a) chore: update COSI runtime to v0.2.0-alpha.1\n* [`1b435c0b3`](https://github.com/siderolabs/talos/commit/1b435c0b36a8d0d3e48c5a5e6121117933deeb69) chore: bump kernel + ice drivers\n* [`18e041f1e`](https://github.com/siderolabs/talos/commit/18e041f1ecb88d0b1e8e874d9b1fb580bc7c2297) docs: fix typo in patching example\n* [`0ad6452ca`](https://github.com/siderolabs/talos/commit/0ad6452ca152afef2f3c0e97a2255a237b30941a) feat: update CoreDNS to v1.10.0\n* [`479f3f52e`](https://github.com/siderolabs/talos/commit/479f3f52ee7149ff2a39bec3d8f78b59978af70a) chore: bump dependencies\n* [`e07c6ae99`](https://github.com/siderolabs/talos/commit/e07c6ae99ec347735cf0316294ef0c54ebc45234) feat: update Kubernetes to v1.25.1\n* [`13fdfaffc`](https://github.com/siderolabs/talos/commit/13fdfaffc4a0eb812cd63c5d188efd4aff6da51c) test: fix up default branch name\n* [`ef181321a`](https://github.com/siderolabs/talos/commit/ef181321a5be4d03e4f87aab1483b95a8e61f0fe) docs: add component diagram; K8s & Talos Linux\n* [`aade73643`](https://github.com/siderolabs/talos/commit/aade7364357da6644e8b70ad1dd939130f2fe470) docs: fix missing variable in OpenEBS docs\n* [`472590aa8`](https://github.com/siderolabs/talos/commit/472590aa82d16e1bd3825ecc8106886e7e1b9053) chore: return InvalidArgument on invalid config in maintenance mode\n* [`e5cabd42c`](https://github.com/siderolabs/talos/commit/e5cabd42cc7f86bee5486f73fa4068382bf6a7fb) feat: enable etcd consistency hashcheck\n* [`015535d90`](https://github.com/siderolabs/talos/commit/015535d9051dea243f439b385577d17fd57a122e) fix: update discovery client with the redirect fix\n* [`d0c8e7699`](https://github.com/siderolabs/talos/commit/d0c8e7699cf3e2415c5712ff9ff620c38857a0dc) chore: bump kernel and go\n* [`985b0c2e7`](https://github.com/siderolabs/talos/commit/985b0c2e796006f401376ebf30a1ce888d90a1c9) chore: remove go.work.sum\n* [`69124f102`](https://github.com/siderolabs/talos/commit/69124f10263bdabc556b58b98a3e1f129b85b8ab) feat: update etcd to v3.5.5\n* [`1985a796c`](https://github.com/siderolabs/talos/commit/1985a796c0d5a984c397754445b33827f5690806) docs: update docs for pod security\n* [`94b088f02`](https://github.com/siderolabs/talos/commit/94b088f02f8f8e5b63f0c38e8e091f2ba3329dde) fix: set etcd options consistently\n* [`92ae7ef4b`](https://github.com/siderolabs/talos/commit/92ae7ef4b1abe0a510fea31e0fde2566281f38b1) fix: fix protoenc encoding for enums and types with custom encoders\n* [`93809017c`](https://github.com/siderolabs/talos/commit/93809017c594b1faf1405932d884852eb0ce567c) docs: cpu scaling governor knowledgebase\n* [`7b270ff33`](https://github.com/siderolabs/talos/commit/7b270ff33d6bf74d1fa195c07f98233098b337e9) test: fix api controller test\n* [`2dadcd669`](https://github.com/siderolabs/talos/commit/2dadcd6695003eb940848583caa6ade53ef94fa0) fix: stop worker nodes from acting as apid routers\n* [`9eaf33f3f`](https://github.com/siderolabs/talos/commit/9eaf33f3f274e746ca1b442c0a1a0dae0cec088f) fix: never sign client certificate requests in trustd\n* [`436749124`](https://github.com/siderolabs/talos/commit/43674912479d3fb58c30e350fea9c4daf4ba45d4) feat: environment vars for extension service\n* [`0c0cb671e`](https://github.com/siderolabs/talos/commit/0c0cb671ead1f514b1f1eb89e8d78f455e1efedb) chore: mark machine configuration validation failure as InvalidArgument\n* [`f424e5340`](https://github.com/siderolabs/talos/commit/f424e53404db61bbdbcbe8fab7cfec91785aa628) fix: stop containers more thoroughly\n* [`12827b861`](https://github.com/siderolabs/talos/commit/12827b861c13bb9b83a2f0ea2960582e8be319f0) chore: move \"implements\" checks to compile time\n* [`3a67c42cb`](https://github.com/siderolabs/talos/commit/3a67c42cbfdbd565e0af500d97c264ef6095637b) fix: kill the task processes when cleaning up stale task\n* [`14a79e325`](https://github.com/siderolabs/talos/commit/14a79e325bf0ffa107aaee9c07d3501b7010693c) chore: bump dependencies\n* [`9beee92e7`](https://github.com/siderolabs/talos/commit/9beee92e71e712a2af24dee612e27c30cac39d0d) docs: fix double vv in Kubernetes version\n* [`688272515`](https://github.com/siderolabs/talos/commit/6882725157f4c2ea79c248f79160e362be6c2c07) fix: use different username for Talos Kubernetes API access\n* [`161a52a9e`](https://github.com/siderolabs/talos/commit/161a52a9ef60eb9c1c1a6c31b06d06894456300c) feat: check apid client certificate extended key usage\n* [`9dadc4a59`](https://github.com/siderolabs/talos/commit/9dadc4a599f52cc564f5411dd35bc981e482d24a) fix: include all node addresses into etcd cert SANs\n* [`71bfd3e43`](https://github.com/siderolabs/talos/commit/71bfd3e43cdc9790d3cb7a134c3b49256b1942a1) feat: update CoreDNS to 1.9.4\n* [`9df8f1ff1`](https://github.com/siderolabs/talos/commit/9df8f1ff1aebb24a6b0649ba491b10b23a0b2198) fix: list COSI APIs for the apid authenticator\n* [`31462450f`](https://github.com/siderolabs/talos/commit/31462450f19700dd6691ebc4b0c18edca4f6a1b7) fix: pass a pointer to specs.Mount into protoenc.Marshal\n* [`e626540df`](https://github.com/siderolabs/talos/commit/e626540dfb470386d0750f2f8bbaf4b5cb36b203) chore: avoid double API request logging in trustd\n* [`f62d17125`](https://github.com/siderolabs/talos/commit/f62d17125b8c1b26b0b62d22c2846f3a2ece37d1) chore: update crypto to use new import path siderolabs/crypto\n* [`ef27dd855`](https://github.com/siderolabs/talos/commit/ef27dd8553ee0e5467c3baaf4be18d1ccb30dad1) chore: bump dependencies\n* [`6472ae00b`](https://github.com/siderolabs/talos/commit/6472ae00b21c0f637b1e6610a8f3f71a1b775628) fix: automatically discard VIPs for etcd advertised addresses\n* [`5e21cca52`](https://github.com/siderolabs/talos/commit/5e21cca52d7462240bb42aafa225ee97d08bdc25) feat: support setting kernel parameters\n* [`bd56621cd`](https://github.com/siderolabs/talos/commit/bd56621cdf50d25013756a8792dc7b4d5354396f) feat: add structprotogen tool\n* [`cdb6bb2cc`](https://github.com/siderolabs/talos/commit/cdb6bb2cc78685c218506c61a477c8a8e569e861) feat: add Nano Pi R4S support\n* [`36c1f1d6e`](https://github.com/siderolabs/talos/commit/36c1f1d6e6aa50379343acba5348d8cc038b137e) fix: flip the client-server version check\n* [`cd6c53a97`](https://github.com/siderolabs/talos/commit/cd6c53a979236543afc302a67da627ee633883b3) docs: fork docs for v1.3\n* [`0847400f7`](https://github.com/siderolabs/talos/commit/0847400f728d67889b9f740a0359eb916108d8ea) fix: prevent panic on health check if a member has no IPs\n* [`7471d7f01`](https://github.com/siderolabs/talos/commit/7471d7f0174a5240fa3c4cd2f16325ec2a4f1810) feat: update Flannel to v0.19.2\n* [`148c75cfb`](https://github.com/siderolabs/talos/commit/148c75cfb99537f64d43a3add3259bf591cb79a9) docs: consolidate the control-plane documentation\n* [`353154281`](https://github.com/siderolabs/talos/commit/353154281a4cf72076b99160e50e617109f72996) fix: drop kube-system SA default binding\n* [`4f37b668b`](https://github.com/siderolabs/talos/commit/4f37b668befdbd26bc2d32106e0bcc654f7e6119) chore: remove capi hacks\n* [`1369afea8`](https://github.com/siderolabs/talos/commit/1369afea853423f22fde20effd431c3f8d906a9d) docs: make 1.2.0 docs default ones\n* [`7627cb0e3`](https://github.com/siderolabs/talos/commit/7627cb0e30a8b2a5a1cc30906b547511c9d3c98b) docs: add new `talosctl gen secrets`\n* [`8aa60a37a`](https://github.com/siderolabs/talos/commit/8aa60a37a6ea57bf54d558c7a2f54d806fad3173) chore: bump kernel to 5.15.64\n* [`a798dbd5d`](https://github.com/siderolabs/talos/commit/a798dbd5d2d9bc6d1410a56035550d44de934950) docs: update docs for upcoming 1.2.0 release\n* [`b2fec3c97`](https://github.com/siderolabs/talos/commit/b2fec3c975dba7b0bc2dc7d5447e62350057061b) fix: properly handle `configContext` being `nil` in Talos client\n* [`1c0977b3a`](https://github.com/siderolabs/talos/commit/1c0977b3af22f9f4b61b80ca6dcedf14a5ef63ae) fix: change the type of returned gRPC connection object from the client\n* [`41848e421`](https://github.com/siderolabs/talos/commit/41848e421496184008ad2302e3cb03a882c0f5bf) fix: expose Talos client gRPC connection via the function `Conn`\n* [`2e9be4af8`](https://github.com/siderolabs/talos/commit/2e9be4af8b521eca985c425f62dfc7a59d19e7da) chore: bump dependencies\n* [`d283aba3a`](https://github.com/siderolabs/talos/commit/d283aba3a3670cfde8ab9137deba3ab3b343906f) test: fix cli reboot test\n* [`0b339a9dc`](https://github.com/siderolabs/talos/commit/0b339a9dc508327347777619749ff1e2c3e47f37) feat: track progress of action API calls\n* [`072349812`](https://github.com/siderolabs/talos/commit/072349812506c5cd32159bb14bab5b294ee59811) fix: update COSI to the version with gRPC Wait fix\n* [`89d57aa81`](https://github.com/siderolabs/talos/commit/89d57aa816a57448d6e350698a8f6a5d128209ac) fix: always abort the maintenance service\n* [`f6fa74619`](https://github.com/siderolabs/talos/commit/f6fa7461932462160f40f670a5252fbc2981bdc3) fix: limit apid backoff max delay\n* [`d7ef346db`](https://github.com/siderolabs/talos/commit/d7ef346db8ea7d4f7676ae5e032a3c0d06823d47) fix: get command in the case 'nodes' are not set in the context\n* [`4e9c32256`](https://github.com/siderolabs/talos/commit/4e9c322564d7f65c82d636a9f80c0c5354455967) fix: correctly render hosts.toml with multiple endpoints\n* [`cdd0f08bc`](https://github.com/siderolabs/talos/commit/cdd0f08bc5d8d47bc2d21745ee5a13ced3632c8a) feat: check client <> server version in some Talos commands\n* [`446b0af58`](https://github.com/siderolabs/talos/commit/446b0af58bf273712374472bfa2777de5b7ac46f) chore: bump kernel and runc\n* [`8c203ce9b`](https://github.com/siderolabs/talos/commit/8c203ce9b1722c5832c506857cb56e14e2a34fe1) feat: remove the machine from the discovery service on reset\n* [`b59ca5810`](https://github.com/siderolabs/talos/commit/b59ca5810e6cf75f6a3042a47535431110004201) chore: move from inet.af/netaddr to net/netip and go4.org/netipx\n* [`053af1d59`](https://github.com/siderolabs/talos/commit/053af1d59ea266b84bb049460f92b33b32c1b82e) fix: update etcd certificates when node addresses changes\n* [`11edb2c6f`](https://github.com/siderolabs/talos/commit/11edb2c6f84fbbfba437361ce4dcd70c50eb08d8) test: re-enable upgrade tests\n* [`0310e2089`](https://github.com/siderolabs/talos/commit/0310e20890b11e1f4015e923eb9984aea1188d20) chore: bump github.com/siderolabs/protoenc to v0.1.5\n* [`29bd63240`](https://github.com/siderolabs/talos/commit/29bd632401ca694df0a2ab921a2a525b4c3440d8) chore: remove old build tags syntax\n* [`b500d0aa9`](https://github.com/siderolabs/talos/commit/b500d0aa9052ab5066eb6cde06bcdac3e998705a) chore: bump k8s to v1.25.0\n* [`29e574be7`](https://github.com/siderolabs/talos/commit/29e574be74c96211fd010ee5bd06675898f04db8) docs: update to v1.2.0-beta.1\n* [`26b549f2a`](https://github.com/siderolabs/talos/commit/26b549f2a12c3486b52a8877b8a0a4f985695c7d) chore: bump dependencies\n* [`8c3ac4c42`](https://github.com/siderolabs/talos/commit/8c3ac4c42bff1f1678ddb62e0f20a9c419460ad4) chore: limit GOMAXPROCS for Talos services\n* [`361e85b74`](https://github.com/siderolabs/talos/commit/361e85b7443f6f4ff24fbf99a9f9276b73b73ed4) fix: properly read kexec disabled sysctl\n* [`cfe6c2bc2`](https://github.com/siderolabs/talos/commit/cfe6c2bc2d42ca28f3a5b3217aa4d126777e3db6) docs: nvidia oss drivers\n* [`2f2d97b6b`](https://github.com/siderolabs/talos/commit/2f2d97b6b5663a0873db9d47b7706f2c0a531d8c) fix: don't wait for the hostname in maintenance mode\n* [`b15a63924`](https://github.com/siderolabs/talos/commit/b15a6392465aa2aa0df231c622ca1762972ccd20) chore: bump kernel to 5.15.62\n* [`a0d94be30`](https://github.com/siderolabs/talos/commit/a0d94be30d3dcf41b2b8b34a1caa6928a029f81a) fix: stable default hostname bias\n* [`da4cd34ef`](https://github.com/siderolabs/talos/commit/da4cd34ef5c5a01cfc3c3ee56b3f8c2f77997b49) feat: update etcd advertised peer addresses on the fly\n* [`faf92ce01`](https://github.com/siderolabs/talos/commit/faf92ce01661c5a9a86f9e579da3a2822d93f1f6) chore: bump kubernetes to v1.25.0-rc.1\n* [`52de919e3`](https://github.com/siderolabs/talos/commit/52de919e34789c36c4ee71ca133240b50b068064) chore: bump containerd to v1.6.8\n* [`7d43fc79b`](https://github.com/siderolabs/talos/commit/7d43fc79b1e913d51f111ecc7c2c8b3bfb36e679) fix: make 'ca', 'crt' and 'key' flags optional for 'talosctl config add'\n* [`fd467e02c`](https://github.com/siderolabs/talos/commit/fd467e02c1edcfc0eff656392ece5dd8ba1114f2) fix: handle grub config being empty in the `Revert` function\n* [`9492aca65`](https://github.com/siderolabs/talos/commit/9492aca652eec4d4049fef1c8d141696ed72a197) fix: clean up `cancelCtxMu` leftovers in PriorityLock\n* [`61e3eb2ea`](https://github.com/siderolabs/talos/commit/61e3eb2eaab1c7974a27440ddd98139a27dfb9dc) fix: talosctl edit mc loop\n* [`32db7a7f5`](https://github.com/siderolabs/talos/commit/32db7a7f5d6638fc0f731a009dfb0c1870c69083) fix: surround `cancelCtx` with the mutex\n</p>\n</details>\n\n### Changes from siderolabs/crypto\n<details><summary>27 commits</summary>\n<p>\n\n* [`c3225ee`](https://github.com/siderolabs/crypto/commit/c3225eee603a8d1218c67e1bfe33ddde7953ed74) feat: allow CSR template subject field to be overridden\n* [`8570669`](https://github.com/siderolabs/crypto/commit/85706698dac8cddd0e9f41006bed059347d2ea26) chore: rename to siderolabs/crypto\n* [`e9df1b8`](https://github.com/siderolabs/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n* [`510b0d2`](https://github.com/siderolabs/crypto/commit/510b0d2753a89170d0c0f60e052a66484997a5b2) chore: add json tags\n* [`6fa2d93`](https://github.com/siderolabs/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n* [`9a63cba`](https://github.com/siderolabs/crypto/commit/9a63cba8dabd278f3080fa8c160613efc48c43f8) fix: add back support for generating ECDSA keys with P-256 and SHA512\n* [`893bc66`](https://github.com/siderolabs/crypto/commit/893bc66e4716a4cb7d1d5e66b5660ffc01f22823) fix: use SHA256 for ECDSA-P256\n* [`deec8d4`](https://github.com/siderolabs/crypto/commit/deec8d47700e10e3ea813bdce01377bd93c83367) chore: implement DeepCopy methods for PEMEncoded* types\n* [`d3cb772`](https://github.com/siderolabs/crypto/commit/d3cb77220384b3a3119a6f3ddb1340bbc811f1d1) feat: make possible to change KeyUsage\n* [`6bc5bb5`](https://github.com/siderolabs/crypto/commit/6bc5bb50c52767296a1b1cab6580e3fcf1358f34) chore: remove unused argument\n* [`cd18ef6`](https://github.com/siderolabs/crypto/commit/cd18ef62eb9f65d8b6730a2eb73e47e629949e1b) feat: add support for several organizations\n* [`97c888b`](https://github.com/siderolabs/crypto/commit/97c888b3924dd5ac70b8d30dd66b4370b5ab1edc) chore: add options to CSR\n* [`7776057`](https://github.com/siderolabs/crypto/commit/7776057f5086157873f62f6a21ec23fa9fd86e05) chore: fix typos\n* [`80df078`](https://github.com/siderolabs/crypto/commit/80df078327030af7e822668405bb4853c512bd7c) chore: remove named result parameters\n* [`15bdd28`](https://github.com/siderolabs/crypto/commit/15bdd282b74ac406ab243853c1b50338a1bc29d0) chore: minor updates\n* [`4f80b97`](https://github.com/siderolabs/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n* [`39584f1`](https://github.com/siderolabs/crypto/commit/39584f1b6e54e9966db1f16369092b2215707134) feat: support for key/certificate types RSA, Ed25519, ECDSA\n* [`cf75519`](https://github.com/siderolabs/crypto/commit/cf75519cab82bd1b128ae9b45107c6bb422bd96a) fix: function NewKeyPair should create certificate with proper subject\n* [`751c95a`](https://github.com/siderolabs/crypto/commit/751c95aa9434832a74deb6884cff7c5fd785db0b) feat: add 'PEMEncodedKey' which allows to transport keys in YAML\n* [`562c3b6`](https://github.com/siderolabs/crypto/commit/562c3b66f89866746c0ba47927c55f41afed0f7f) feat: add support for public RSA key in RSAKey\n* [`bda0e9c`](https://github.com/siderolabs/crypto/commit/bda0e9c24e80c658333822e2002e0bc671ac53a3) feat: enable more conversions between encoded and raw versions\n* [`e0dd56a`](https://github.com/siderolabs/crypto/commit/e0dd56ac47456f85c0b247999afa93fb87ebc78b) feat: add NotBefore option for x509 cert creation\n* [`12a4897`](https://github.com/siderolabs/crypto/commit/12a489768a6bb2c13e16e54617139c980f99a658) feat: add support for SPKI fingerprint generation and matching\n* [`d0c3eef`](https://github.com/siderolabs/crypto/commit/d0c3eef149ec9b713e7eca8c35a6214bd0a64bc4) fix: implement NewKeyPair\n* [`196679e`](https://github.com/siderolabs/crypto/commit/196679e9ec77cb709db54879ddeddd4eaafaea01) feat: move `pkg/grpc/tls` from `github.com/talos-systems/talos` as `./tls`\n* [`1ff6242`](https://github.com/siderolabs/crypto/commit/1ff6242c91bb298ceeb4acd65685cba952fe4178) chore: initial version as imported from talos-systems/talos\n* [`835063e`](https://github.com/siderolabs/crypto/commit/835063e055b28a525038b826a6d80cbe76402414) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-api\n<details><summary>3 commits</summary>\n<p>\n\n* [`5b0c5e7`](https://github.com/siderolabs/discovery-api/commit/5b0c5e78097c1489457b148a7f13c73890f5ecad) chore: rename to siderolabs, rekres, etc\n* [`db279ef`](https://github.com/siderolabs/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/siderolabs/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from siderolabs/discovery-client\n<details><summary>1 commit</summary>\n<p>\n\n* [`230f317`](https://github.com/siderolabs/discovery-client/commit/230f317a8e6e9542b82efcbac9f5cd7b9cff34b6) fix: reconnect the client on update failure\n</p>\n</details>\n\n### Changes from siderolabs/gen\n<details><summary>4 commits</summary>\n<p>\n\n* [`726e066`](https://github.com/siderolabs/gen/commit/726e066dcb35c86f82866097bed806f22b936292) fix: rename tuples.go to pair.go and set proper package name\n* [`d8d7d25`](https://github.com/siderolabs/gen/commit/d8d7d25ce9a588609c00cb798206a01a866bf7a6) chore: minor additions\n* [`338a650`](https://github.com/siderolabs/gen/commit/338a65065f92eb6426a66c4a88a0cc02cc02e529) chore: add initial implementation and documentation\n* [`4fd8667`](https://github.com/siderolabs/gen/commit/4fd866707052c792a6adccbc28efec5debdd18a8) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/go-blockdevice\n<details><summary>55 commits</summary>\n<p>\n\n* [`dcf6044`](https://github.com/siderolabs/go-blockdevice/commit/dcf6044c906b36f183e11b6553458c680126d1d9) chore: rekres and rename\n* [`9c4af49`](https://github.com/siderolabs/go-blockdevice/commit/9c4af492cc17279f0281fcd271e7423be78442bb) fix: cryptsetup remove slot\n* [`74ea471`](https://github.com/siderolabs/go-blockdevice/commit/74ea47109c4525bec139640fed6354ad3097f5fb) feat: add freebsd stubs\n* [`9fa801c`](https://github.com/siderolabs/go-blockdevice/commit/9fa801cf4da184e3560b9a18ba43d13316f172f9) feat: add ReadOnly attribute to Disk\n* [`fccee8b`](https://github.com/siderolabs/go-blockdevice/commit/fccee8bb082b105cb60db40cb01636efc3241b5f) chore: rekres the source, fix issues\n* [`d9c3a27`](https://github.com/siderolabs/go-blockdevice/commit/d9c3a273886113e24809ef1e9930fc982318217d) feat: support probing FAT12/FAT16 filesystems\n* [`b374eb4`](https://github.com/siderolabs/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n* [`ec428fe`](https://github.com/siderolabs/go-blockdevice/commit/ec428fed2ecd5a389833a88f8dc333762816db99) fix: lookup filesystem labels on the actual device path\n* [`7b9de26`](https://github.com/siderolabs/go-blockdevice/commit/7b9de26bc6bc3d54b95bd8e8fb3aade4b45adc6c) feat: read symlink fullpath in block device list function\n* [`6928ee4`](https://github.com/siderolabs/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/siderolabs/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n* [`15b182d`](https://github.com/siderolabs/go-blockdevice/commit/15b182db0cd233b163ed83d1724c7e28cf29d71a) fix: return partition table not exist when trying to read an empty dev\n* [`b9517d5`](https://github.com/siderolabs/go-blockdevice/commit/b9517d51120d385f97b0026f99ce3c4782940c37) fix: resize partition\n* [`70d2865`](https://github.com/siderolabs/go-blockdevice/commit/70d28650b398a14469cbb5356417355b0ba62956) fix: try to find cdrom disks\n* [`667bf53`](https://github.com/siderolabs/go-blockdevice/commit/667bf539b99ac34b629a0103ef7a7278a5a5f35d) fix: revert gpt partition not found\n* [`d7d4cdd`](https://github.com/siderolabs/go-blockdevice/commit/d7d4cdd7ac56c82caab19246b5decd59f12195eb) fix: gpt partition not found\n* [`33afba3`](https://github.com/siderolabs/go-blockdevice/commit/33afba347c0dce38a436c46a0aac26d2f99427c1) fix: also open in readonly mode when running `All` lookup method\n* [`e367f9d`](https://github.com/siderolabs/go-blockdevice/commit/e367f9dc7fa935f11672de0fdc8a89429285a07a) feat: make probe always open blockdevices in readonly mode\n* [`d981156`](https://github.com/siderolabs/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n* [`fe24303`](https://github.com/siderolabs/go-blockdevice/commit/fe2430349e9d734ce6dbf4e7b2e0f8a37bb22679) fix: perform correct PMBR partition calculations\n* [`2ec0c3c`](https://github.com/siderolabs/go-blockdevice/commit/2ec0c3cc0ff5ff705ed5c910ca1bcd5d93c7b102) fix: preserve the PMBR bootable flag when opening GPT partition\n* [`87816a8`](https://github.com/siderolabs/go-blockdevice/commit/87816a81cefc728cfe3cb221b476d8ed4b609fd8) feat: align partition to minimum I/O size\n* [`c34b59f`](https://github.com/siderolabs/go-blockdevice/commit/c34b59fb33a7ad8be18bb19bc8c8d8294b4b3a78) feat: expose more encryption options in the LUKS module\n* [`30c2bc3`](https://github.com/siderolabs/go-blockdevice/commit/30c2bc3cb62af52f0aea9ce347923b0649fb7928) feat: mark MBR bootable\n* [`1292574`](https://github.com/siderolabs/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/siderolabs/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n* [`1d830a2`](https://github.com/siderolabs/go-blockdevice/commit/1d830a25f64f6fb96a1bedd800c0b40b107dc833) fix: revert mark the EFI partition in PMBR as bootable\n* [`bec914f`](https://github.com/siderolabs/go-blockdevice/commit/bec914ffdda42abcfe642bc2cdfc9fcda56a74ee) fix: mark the EFI partition in PMBR as bootable\n* [`776b37d`](https://github.com/siderolabs/go-blockdevice/commit/776b37d31de0781f098f5d9d1894fbea3f2dfa1d) feat: add options to probe disk by various sysblock parameters\n* [`bb3ad73`](https://github.com/siderolabs/go-blockdevice/commit/bb3ad73f69836acc2785ec659435e24a531359e7) fix: align partition start to physical sector size\n* [`8f976c2`](https://github.com/siderolabs/go-blockdevice/commit/8f976c2031108651738ebd4db69fb09758754a28) feat: replace exec.Command with go-cmd module\n* [`1cf7f25`](https://github.com/siderolabs/go-blockdevice/commit/1cf7f252c38cf11ef07723de2debc27d1da6b520) fix: properly handle no child processes error from cmd.Wait\n* [`04a9851`](https://github.com/siderolabs/go-blockdevice/commit/04a98510c07fe8477f598befbfe6eaec4f4b73a2) feat: implement luks encryption provider\n* [`b0375e4`](https://github.com/siderolabs/go-blockdevice/commit/b0375e4267fdc6108bd9ff7a5dc97b80cd924b1d) feat: add an option to open block device with exclusive flock\n* [`5a1c7f7`](https://github.com/siderolabs/go-blockdevice/commit/5a1c7f768e016c93f6c0be130ffeaf34109b5b4d) refactor: add devname into gpt.Partition, refactor probe package\n* [`f2728a5`](https://github.com/siderolabs/go-blockdevice/commit/f2728a581972be977d863d5d9177a873b8f3fc7b) fix: keep contents of PMBR when writing it\n* [`2878460`](https://github.com/siderolabs/go-blockdevice/commit/2878460b54e8b8c3846c6a882ca9e1472c8b6b3b) fix: write second copy of partition entries\n* [`943b08b`](https://github.com/siderolabs/go-blockdevice/commit/943b08bc32a2156cffb23e92b8be9288de4a7421) fix: blockdevice reset should read partition table from disk\n* [`5b4ee44`](https://github.com/siderolabs/go-blockdevice/commit/5b4ee44cfd434a03ec2d7167bcc56d0f164c3fa2) fix: ignore `/dev/ram` devices\n* [`98754ec`](https://github.com/siderolabs/go-blockdevice/commit/98754ec2bb200acc9e9e573fa766754d60e25ff2) refactor: rewrite GPT library\n* [`2a1baad`](https://github.com/siderolabs/go-blockdevice/commit/2a1baadffdf8c9b65355e9af6e744aeab838c9db) fix: correctly build paths for `mmcblk` devices\n* [`8076344`](https://github.com/siderolabs/go-blockdevice/commit/8076344a95021f25ab5d1fbf5ea4fefc790f6c3c) fix: return proper disk size from GetDisks function\n* [`8742133`](https://github.com/siderolabs/go-blockdevice/commit/874213371a3fb0925aab45cbba68a957e3319525) chore: add common method to list available disks using /sys/block\n* [`c4b5833`](https://github.com/siderolabs/go-blockdevice/commit/c4b583363d63503ed7e4adb9a9fa64335f7e198d) feat: implement \"fast\" wipe\n* [`b4e67d7`](https://github.com/siderolabs/go-blockdevice/commit/b4e67d73d70d8dc06aa2b4986622dcb854dfc40c) feat: return resize status from Resize() function\n* [`ceae64e`](https://github.com/siderolabs/go-blockdevice/commit/ceae64edb3a591c6f6bbd75b1149d1cfe426dd8e) fix: sync kernel partition table incrementally\n* [`2cb9516`](https://github.com/siderolabs/go-blockdevice/commit/2cb95165aa67b0b839863b5ad89920c3ac7e2c82) fix: return correct error value from blkpg functions\n* [`cebe43d`](https://github.com/siderolabs/go-blockdevice/commit/cebe43d1fdc1e509437198e578faa9d5a804cc37) refactor: expose `InsertAt` method via interface\n* [`c40dcd8`](https://github.com/siderolabs/go-blockdevice/commit/c40dcd80c50b41c1f2a60ea6aa9d5fb3d3b180a3) fix: properly inform kernel about partition deletion\n* [`bb8ac5d`](https://github.com/siderolabs/go-blockdevice/commit/bb8ac5d6a25e279e16213f585dc8d02ba6ed645f) feat: implement disk wiping via several methods\n* [`23fb7dc`](https://github.com/siderolabs/go-blockdevice/commit/23fb7dc755325cfe12e48c8e8e31bebab9ddc2bc) feat: expose partition name (label)\n* [`ff3a821`](https://github.com/siderolabs/go-blockdevice/commit/ff3a8210be999b8bfb2019f19f8a8b50901c64cc) feat: implement 'InsertAt' method to insert partitions at any position\n* [`3d1ce4f`](https://github.com/siderolabs/go-blockdevice/commit/3d1ce4fc859fa614a4c5c54a10c0f5f4fce38bb6) fix: calculate last lba of partition correctly\n* [`b71540f`](https://github.com/siderolabs/go-blockdevice/commit/b71540f6c398e958bdb7c118396a736419f735d4) feat: copy initial version from talos-systems/talos\n* [`ca3c078`](https://github.com/siderolabs/go-blockdevice/commit/ca3c078da95e6497c9d41667dc242e32682e517d) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>26 commits</summary>\n<p>\n\n* [`0ac7773`](https://github.com/siderolabs/pkgs/commit/0ac77733506d2f0b0944ff569b6817ae44821bda) chore: use generic raspberry pi u-boot\n* [`d5633d4`](https://github.com/siderolabs/pkgs/commit/d5633d4838bd6e168b9c80f124540a30c29ae7be) chore: bump kernel to 5.15.70\n* [`39c0d43`](https://github.com/siderolabs/pkgs/commit/39c0d4364fd4eedd281e46ce7d305f2562e2cf78) feat: add generic rpi_arm64_defconfig configuration\n* [`ed269ca`](https://github.com/siderolabs/pkgs/commit/ed269cabad82446095221e45078c8ba85bce5c2e) chore: bump kernel to 5.15.69\n* [`f2f8333`](https://github.com/siderolabs/pkgs/commit/f2f83331f93a0a5d2dd1c013e2ff46900684096a) fix: no slack notifications on failure\n* [`6f0af33`](https://github.com/siderolabs/pkgs/commit/6f0af3390fc170f0cf57450adfada6a87de7ece4) chore: disable drone slack pipeline for renovate\n* [`32aea3f`](https://github.com/siderolabs/pkgs/commit/32aea3f005b93aaa91d52e4dfd04dd9ce9d564a9) chore: disable drone for renovate/dependabot\n* [`44579f0`](https://github.com/siderolabs/pkgs/commit/44579f0238993f529e2c141f42c99b32803fd6a5) fix: rollback xfsprogs to 5.18.0\n* [`792c0e3`](https://github.com/siderolabs/pkgs/commit/792c0e32ef6b1cf13514dc2693c4c302e1440d3b) feat: add gasket driver package\n* [`07f1898`](https://github.com/siderolabs/pkgs/commit/07f1898b231390b85519f83638946ed65adacc64) chore: update deps\n* [`f78f410`](https://github.com/siderolabs/pkgs/commit/f78f410d193953e730aeb14f4e148e47dfa827fd) chore: enable conntrack zones and timestamps\n* [`049b3c6`](https://github.com/siderolabs/pkgs/commit/049b3c6f080b9af76b1b2e924baade69db27bc0b) chore: enable intel ice drivers\n* [`606ff32`](https://github.com/siderolabs/pkgs/commit/606ff32cb7e75b6975749b6250b68352b71e943b) chore: bump deps\n* [`eee5c8a`](https://github.com/siderolabs/pkgs/commit/eee5c8af13ee1fe0b1e660a9581d4f1b14158a39) chore: disable irc in conntrack\n* [`70e6c46`](https://github.com/siderolabs/pkgs/commit/70e6c460d7b3bd5e154a4e681858832afcf32368) chore: bump kernel to 5.15.64\n* [`e510321`](https://github.com/siderolabs/pkgs/commit/e5103217e714bea04e06fd0c4940e84406cb68cf) chore: update renovate config\n* [`d1fa510`](https://github.com/siderolabs/pkgs/commit/d1fa510cc66ddc63a53482f6ced5573466049d49) feat: enable renovate bot\n* [`e427a77`](https://github.com/siderolabs/pkgs/commit/e427a778146664b988664008bfe20611f91216b0) chore: bump runc to v1.1.4\n* [`40e1215`](https://github.com/siderolabs/pkgs/commit/40e12152a027eb509330c41db21680b9a662fa05) chore: enable nfsv4.2 client support\n* [`15efada`](https://github.com/siderolabs/pkgs/commit/15efadaa9db4b8dc8003359d6d0ed84016f54746) chore: bump kernel to 5.15.63\n* [`e70e3c1`](https://github.com/siderolabs/pkgs/commit/e70e3c1af2b11d4b4646401a617b3d0efa2db4a3) fix: nvidia oss pkg name\n* [`30b8d79`](https://github.com/siderolabs/pkgs/commit/30b8d79b9ca3e463b5f403f01d39e64e89edc7b1) chore: bump kernel to 5.15.62\n* [`862c392`](https://github.com/siderolabs/pkgs/commit/862c392b6defe3c9ce90f9b15eae154e021b0b4d) chore: bump gcc to 12.2.0\n* [`2ecd14e`](https://github.com/siderolabs/pkgs/commit/2ecd14ede04637a581fbe7dcbbf612cdd6f9d882) fix: containerd version\n* [`01df058`](https://github.com/siderolabs/pkgs/commit/01df0583a430f3793f19725c920e942cf37efee4) feat: add NanoPi R4S configuration\n* [`d4cb33b`](https://github.com/siderolabs/pkgs/commit/d4cb33b9bdfb8c27ea86a42ea60a88e294129ad4) chore: bump containerd to v1.6.8\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>15 commits</summary>\n<p>\n\n* [`5df6589`](https://github.com/siderolabs/tools/commit/5df658937f7bd667ceda8760e2e15ed85c80dc2c) chore: disable drone for renovate/dependabot\n* [`1f00d2e`](https://github.com/siderolabs/tools/commit/1f00d2e854cdf357c1192428bd44ee846af1b4e4) fix: revert gawk to 5.1.1\n* [`feeda1f`](https://github.com/siderolabs/tools/commit/feeda1fc708a0cdb461ac5967ec34bf24ccc2b62) chore: bump grpc-go\n* [`8542014`](https://github.com/siderolabs/tools/commit/8542014568a101fb6c03a76c91e59dcfb1b893b6) chore: bump deps\n* [`e5c4968`](https://github.com/siderolabs/tools/commit/e5c496893fb71ff19a33daa4c86792ed03187356) chore: update renovate config\n* [`f34f94d`](https://github.com/siderolabs/tools/commit/f34f94daa300baab0803f22cecee65b57ee3c1fd) chore: update renovate config\n* [`cef4cc6`](https://github.com/siderolabs/tools/commit/cef4cc67342c06904258bcf4b7ec681d4c732d53) chore: update renovate config\n* [`bab8e9e`](https://github.com/siderolabs/tools/commit/bab8e9ee8d0fc2dc1b5676a45175b507d8927e49) chore: add libbpf to tools\n* [`0a15f7b`](https://github.com/siderolabs/tools/commit/0a15f7bb35f479fbf5551ea4bf02f3716783e33f) chore: build pahole properly\n* [`a322d06`](https://github.com/siderolabs/tools/commit/a322d066483814db80a15b8c0c7f44224b134429) chore: remove img\n* [`c7ff47b`](https://github.com/siderolabs/tools/commit/c7ff47b27962cf0f6a95e07c6f45aa2a3c2c5c8b) feat: enable renovate dependency updates (3/3)\n* [`6e095cf`](https://github.com/siderolabs/tools/commit/6e095cf86a6f734b2f07cc1b854a9a37b055cacc) feat: enable renovate dependency updates (2/n)\n* [`bad1ad1`](https://github.com/siderolabs/tools/commit/bad1ad17f7fd1208fcbb70b950320f805a765868) feat: add renovatebot\n* [`7d6f9c3`](https://github.com/siderolabs/tools/commit/7d6f9c35a81392918560ea0c20b3c06b18501ea0) chore: bump gcc to 12.2.0\n* [`2719b4b`](https://github.com/siderolabs/tools/commit/2719b4be551134a9d70ab235f56889708377f3c5) chore: bump toolchain\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.8.0 -> v1.10.0\n* **github.com/aws/aws-sdk-go**                      v1.44.76 -> v1.44.105\n* **github.com/cosi-project/runtime**                v0.1.1 -> v0.2.0-alpha.1\n* **github.com/docker/docker**                       v20.10.17 -> v20.10.18\n* **github.com/google/go-cmp**                       v0.5.8 -> v0.5.9\n* **github.com/google/nftables**                     2eca00135732 -> cbeb0fb1eccf\n* **github.com/hetznercloud/hcloud-go**              v1.35.2 -> v1.35.3\n* **github.com/insomniacslk/dhcp**                   509691fd59ec -> 043f1726f02e\n* **github.com/mdlayher/ethtool**                    856bd6cb8a38 -> 0e16326d06d1\n* **github.com/mdlayher/netlink**                    v1.6.0 -> v1.6.2\n* **github.com/opencontainers/image-spec**           c5a74bcca799 -> v1.1.0-rc1\n* **github.com/packethost/packngo**                  v0.25.0 -> v0.26.0\n* **github.com/rivo/tview**                          0e6b21a48e96 -> 2e69b7385a37\n* **github.com/siderolabs/crypto**                   v0.4.0 **_new_**\n* **github.com/siderolabs/discovery-api**            v0.1.1 **_new_**\n* **github.com/siderolabs/discovery-client**         v0.1.1 -> v0.1.2\n* **github.com/siderolabs/gen**                      v0.2.0 **_new_**\n* **github.com/siderolabs/go-blockdevice**           v0.4.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.2.0-8-g970860d -> v1.3.0-alpha.0-25-g0ac7773\n* **github.com/siderolabs/tools**                    v1.2.0 -> v1.3.0-alpha.0-14-g5df6589\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.9 -> v0.56.10\n* **go.etcd.io/etcd/api/v3**                         v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/client/v3**                      v3.5.4 -> v3.5.5\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.4 -> v3.5.5\n* **go.uber.org/atomic**                             v1.9.0 -> v1.10.0\n* **go.uber.org/zap**                                v1.22.0 -> v1.23.0\n* **go4.org/netipx**                                 797b0c90d8ab **_new_**\n* **golang.org/x/net**                               3211cb980234 -> 8be639271d50\n* **golang.org/x/sync**                              886fb9371eb4 -> 7f9b1623fab7\n* **golang.org/x/sys**                               fbc7d0a398ab -> fb04ddd9f9c8\n* **golang.org/x/term**                              a9ba230a4035 -> 7a66f970e087\n* **golang.org/x/time**                              e5dcc9cfc0b9 -> f3bd1da661af\n* **golang.zx2c4.com/wireguard/wgctrl**              3d4a969bb56b -> 473347a5e6e3\n* **google.golang.org/grpc**                         v1.48.0 -> v1.49.0\n* **k8s.io/api**                                     v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/apimachinery**                            v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/apiserver**                               v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/client-go**                               v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/component-base**                          v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/cri-api**                                 v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/kubectl**                                 v0.25.0 -> v0.26.0-alpha.1\n* **k8s.io/kubelet**                                 v0.25.0 -> v0.26.0-alpha.1\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.65 -> v1.2.66\n\nPrevious release can be found at [v1.2.0](https://github.com/siderolabs/talos/releases/tag/v1.2.0)\n\n## [Talos 1.2.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.2.0-alpha.2) (2022-08-10)\n\nWelcome to the v1.2.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Talos API access from Kubernetes\n\nTalos now supports access to its API from within Kubernetes. It can be configured in the machine config as below:\n\n```yaml\nmachine:\n  features:\n    kubernetesTalosAPIAccess:\n      enabled: true\n      allowedRoles:\n        - os:reader\n      allowedKubernetesNamespaces:\n        - kube-system\n```\n\nThis feature introduces a new custom resource definition, `serviceaccounts.talos.dev`.\nCreating custom resources of this type will provide credentials to access Talos API from within Kubernetes.\n\nThe new CLI subcommand `talosctl inject serviceaccount` can be used to configure Kubernetes manifests with Talos service accounts as below:\n```\ntalosctl inject serviceaccount -f manifests.yaml > manifests-injected.yaml\nkubectl apply -f manifests-injected.yaml\n```\n\nSee [documentation](https://www.talos.dev/v1.2/advanced/configuration/talos-api-access-from-k8s/) for more details.\n\n\n### Generating Talos secrets from PKI directory\n\nIt is now possible to generate a secrets bundle from a Kubernetes PKI directory (e.g. `/etc/kubernetes/pki`).\n\nYou can also specify a bootstrap token to be used in the secrets bundle.\n\nThis secrets bundle can then be used to generate a machine config.\n\nThis facilitates migrating clusters (e.g. created using `kubeadm`) to Talos.\n\n```\ntalosctl gen secrets --kubernetes-bootstrap-token znzio1.1ifu15frz7jd59pv --from-kubernetes-pki /etc/kubernetes/pki\ntalosctl gen config --with-secrets secrets.yaml my-cluster https://172.20.0.1:6443\n```\n\n\n### Kubernetes ControlPlane Components\n\nTalos now run all Kubernetes Control Plane Components with the CRI default Seccomp Profile and other recommendations as described in\n[KEP-2568](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/kubeadm/2568-kubeadm-non-root-control-plane).\n\n\n### Kubelet Default Runtime Seccomp Profile\n\nTalos now runs Kubelet with the CRI default Seccomp Profile enabled.\nThis can be disabled by setting `.machine.kubelet.defaultRuntimeSeccompProfileEnabled` to `false`.\n\nThis is not enabled automatically on upgrades, so upgrading to Talos v1.2 needs this to be explicitly enabled.\n\n\n### Kubernetes Control Plane labels and taints\n\nTalos now defaults to `node-role.kubernetes.io/control-plane` label/taint.\nOn upgrades Talos now removes the `node-role.kubernetes.io/master` label/taint on control-plane nodes and replaces it with the `node-role.kubernetes.io/control-plane` label/taint.\nWorkloads that tolerate the old taints or having node selectors with the old labels will need to be updated.\n\n\n### Kubernetes Discovery Backend\n\nKubernetes cluster discovery backend is now disabled by default for new clusters.\nThis backend doesn't provide any benefits over the Discovery Service based backend, while it\ncauses issues for KubeSpan enabled clusters when control plane endpoint is KubeSpan-routed.\n\nFor air-gapped installations when the Discovery Service is not enabled, Kubernetes Discovery Backend can be enabled by applying\nthe following machine configuration patch:\n\n```yaml\ncluster:\n  discovery:\n    registries:\n      kubernetes:\n        disabled: false\n```\n\n\n### KubeSpan Kubernetes Network Advertisement\n\nKubeSpan no longer by default advertises Kubernetes pod networks of the node over KubeSpan.\nThis means that CNI should handle encapsulation of pod-to-pod traffic into the node-to-node tunnel,\nand node-to-node traffic will be handled by KubeSpan.\nThis provides better compatibility with popular CNIs like Calico and Cilium.\n\nOld behavior can be restored by setting `.machine.kubespan.advertiseKubernetesNetworks = true` in the machine config.\n\n\n### MachineConfig `.cluster.allowSchedulingOnMasters` deprecated\n\nThe `.cluster.allowSchedulingOnMasters` is deprecated and replaced by `.cluster.allowSchedulingOnControlPlanes`.\nThe `.cluster.allowSchedulingOnMasters` will be removed in a future release of Talos.\nIf both `.cluster.allowSchedulingOnMasters` and `.cluster.allowSchedulingOnControlPlanes` are set to `true`, the `.cluster.allowSchedulingOnControlPlanes` will be used.\n\n\n### `k8s.gcr.io` mirror configuration\n\nTalos now defaults to adding a registry mirror configuration in the machineconfig for `k8s.gcr.io` pointing to both `registry.k8s.io` and `k8s.gcr.io` unless overridden.\nThis is in line with the Kubernetes 1.25 release having the new `registry.k8s.io` registry endpoint.\n\nThis is only enabled by default on newly generated configurations and not on upgrades.\nThis can be enabled with a machine configuration as follows:\n\n```yaml\nmachine:\n  registries:\n    mirrors:\n      k8s.gcr.io:\n        endpoints:\n          - https://registry.k8s.io\n          - https://k8s.gcr.io\n```\n\n\n### Network bridge support\n\nTalos now supports configuring Linux bridges. It can be configured in the machine config like the following:\n\n```yaml\nmachine:\n  network:\n    interfaces:\n      - interface: br0\n        bridge:\n          stp:\n            enabled: true\n          interfaces:\n            - eth0\n            - eth1\n```\n\nSee [documentation](https://www.talos.dev/v1.2/reference/configuration/#bridge) for more details.\n\n\n### VLAN support in cmdline arguments\n\nTalos now supports dracut-style `vlan` kernel argument to allow\ninstalling Talos Linux in networks where ports are not tagged\nwith a default VLAN:\n\n```\nvlan=eth1.5:eth1 ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1.5:::::\n```\n\n\n\n### Packet Capture\n\nTalos now supports capturing packets on a network interface with `talosctl pcap` command:\n\n  talosctl pcap --interface eth0\n\n\n### Seccomp Profiles\n\nTalos now supports creating custom seccomp profiles on the host machine which in turn can be used by Kubernetes workloads.\nIt can be configured in the machine config as below:\n\n```yaml\nmachine:\n  seccompProfiles:\n    - name: audit.json\n      value:\n        defaultAction: SCMP_ACT_LOG\n    - name: deny.json\n      value: {\"defaultAction\":\"SCMP_ACT_LOG\"}\n```\n\nThis profile data can be either configured as a YAML definition or as a JSON string.\n\nThe profiles are created on the host under `/var/lib/seccomp/profiles` and bind mounted at `/var/lib/kubelet/seccomp/profiles` so Kubelet can use it.\n\nSee [documentation](https://www.talos.dev/v1.2/kubernetes-guides/configuration/seccomp-profiles/) for more details.\n\n\n### Stable Default Hostname\n\nTalos now generates the default hostname (when there is no explicitly specified hostname) for the nodes based on the\nnode id (e.g. `talos-2gd-76y`) instead of using the DHCP assigned IP address (e.g. `talos-172-20-0-2`).\n\nThis ensures that the node hostname is not changed when DHCP assigns a new IP to a node.\n\n\n### Strategic merge machine configuration patching\n\nIn addition to JSON (RFC6902) patches Talos now supports [strategic merge patching](https://www.talos.dev/v1.2/talos-guides/configuration/patching/).\n\nFor example, machine hostname can be set with the following patch:\n\n```yaml\nmachine:\n  network:\n    hostname: worker1\n```\n\nPatch format is detected automatically.\n\n\n### Variable substitution for URL query parameter in the talos.config kernel parameter\n\nThe kernel parameter talos.config can now substitute system information into placeholders inside its URL query values. This example shows all supported variables:\n\n```http://example.com/metadata?h=${hostname}&m=${mac}&s=${serial}&u=${uuid}```\n\n\n### talosctl\n\n`--masters` flag on `talosctl cluster create` is deprecated. Use `--controlplanes` instead.\n\n\n### Component Updates\n\n* Linux: 5.15.59\n* Flannel 0.19.1\n* containerd 1.16.7\n* Kubernetes: v1.25.0-beta.0\n\nTalos is built with Go 1.19.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Utku Ozdemir\n* Dmitriy Matrenichev\n* Philipp Sauter\n* Tim Jones\n* Artem Chernyshev\n* Spencer Smith\n* Davincible\n* Eirik Askheim\n* AMet\n* Alex Wied\n* Bermi Ferrer\n* Christoph Schmatzler\n* Dennis Marttinen\n* Eng Zer Jun\n* Flightkick\n* Florian Klink\n* Gwyn\n* Han Cen\n* Larry Rosenman\n* Markus Reiter\n* Matthew Richardson\n* Nico Berlee\n* Rio Kierkels\n* RyanSquared\n* Serge Logvinov\n* Seán C McCord\n* Steve Francis\n* Tommy Botten Jensen\n* hobyte\n* nett_hier\n* zebernst\n\n### Changes\n<details><summary>164 commits</summary>\n<p>\n\n* [`5dd1b4002`](https://github.com/siderolabs/talos/commit/5dd1b400205d794b41de5ffc166d5bfe1605533a) feat: disable Kubernetes discovery backend by default\n* [`b62b18a97`](https://github.com/siderolabs/talos/commit/b62b18a9722f3b48a600dd5abd25f5f98af76b31) feat: bump k8s to v1.25.0-beta.0\n* [`7b80a747b`](https://github.com/siderolabs/talos/commit/7b80a747bcd140918c7be1acc9db74fa9a8952f2) feat: add protobuf encoding/decoding for Go structs\n* [`00c3ee3ac`](https://github.com/siderolabs/talos/commit/00c3ee3ac3119249fd92d558283404018de2f1bf) docs: remove obsolete references to init nodes\n* [`6eefa9d9c`](https://github.com/siderolabs/talos/commit/6eefa9d9cb439b073f84ac18f53a889b55a4b4df) fix: properly filter resources in maintenance server\n* [`fa5aad01a`](https://github.com/siderolabs/talos/commit/fa5aad01a0d9144ab9d20a168a50c747f5a9258c) docs: fix issues in GCP docs\n* [`98f056603`](https://github.com/siderolabs/talos/commit/98f056603e876ad41fc66af9a586cb921a91583a) chore: bump dependencies\n* [`84e712a9f`](https://github.com/siderolabs/talos/commit/84e712a9f1626b78638a4fe2524a2b860cb7185f) feat: introduce Talos API access from Kubernetes\n* [`d7be30892`](https://github.com/siderolabs/talos/commit/d7be3089211691e5c5f62c83915d789eeeca31b8) chore: bump kernel to 5.15.59\n* [`c2c2d65bc`](https://github.com/siderolabs/talos/commit/c2c2d65bc98b3ea58df7253df76f3266d7562e48) refactor: use COSI access filter for resource access\n* [`1dee0579e`](https://github.com/siderolabs/talos/commit/1dee0579e9ef6886b2ca8e42b33fce533dc10008) feat: add support for proxying one-to-one to `apid`\n* [`86eb01cd6`](https://github.com/siderolabs/talos/commit/86eb01cd6c905f87532a3d0f697b87e8866fd399) docs: add missing dev tools\n* [`4fd676c04`](https://github.com/siderolabs/talos/commit/4fd676c0468c67799b5d5a1b449551d6243999a5) docs: fix typo in theila name\n* [`856beb21c`](https://github.com/siderolabs/talos/commit/856beb21cc3505c10d17e030d2ce0487e019c7ab) feat: containerd 1.6.7, Flannel 1.19.1\n* [`e97b9f6d3`](https://github.com/siderolabs/talos/commit/e97b9f6d3e14757288d7b2f415b69aef222e8e99) feat: support dhcp options for vlan\n* [`92314e47b`](https://github.com/siderolabs/talos/commit/92314e47bf66319a67d5c302d4f40a4772cb44b7) refactor: use controllers/resources to feed trustd with data\n* [`80d298abf`](https://github.com/siderolabs/talos/commit/80d298abfbf35e411f5dfbebf4c4d5334e36fbe3) feat: support skipping node registration\n* [`7795de313`](https://github.com/siderolabs/talos/commit/7795de313a11918bccda261c184363a8ed750cbb) fix: use controllers/resources for etcd configuration\n* [`f9b664c94`](https://github.com/siderolabs/talos/commit/f9b664c9470be14f840d33c7d1ebf43fa84d1127) fix: reload trusted CA list when client is recreated\n* [`8847ccd03`](https://github.com/siderolabs/talos/commit/8847ccd03106d525b40b0f3719d9632b00db9753) fix: shutdown some streaming API calls when machined API is shuting down\n* [`f95b53726`](https://github.com/siderolabs/talos/commit/f95b5372625a1ad83f61ea86e54ac6a74f2fd09a) fix: allow files in extension spec\n* [`1a8f6ec8e`](https://github.com/siderolabs/talos/commit/1a8f6ec8e1b47ee63dcc85b9f70b43871a7a5bd4) fix: don't advertise Kubernetes pod networks over KubeSpan by default\n* [`e3d4a0e4d`](https://github.com/siderolabs/talos/commit/e3d4a0e4d12fc87675178bc34e3a96817c0ad73b) fix: make reset work even if the node is not bootstrapped/not joined\n* [`a6b010a8b`](https://github.com/siderolabs/talos/commit/a6b010a8b45981a41feb03876828e29e3510a8e9) chore: update Go to 1.19, Linux to 5.15.58\n* [`fb058a7c9`](https://github.com/siderolabs/talos/commit/fb058a7c9236a80c333c21bbd2bbda785f33ced6) test: use `T.TempDir` to create temporary test directory\n* [`6fc38bae6`](https://github.com/siderolabs/talos/commit/6fc38bae690906d628e89f9cb19c17e16500f27f) fix: iterate over etcd members endpoints for member promotion\n* [`c70b692fb`](https://github.com/siderolabs/talos/commit/c70b692fb34becf651042019c675b1e0750ec703) fix: update default address if removed from the host\n* [`cf620d473`](https://github.com/siderolabs/talos/commit/cf620d4733d4bd4c243213676caf7c5fe6a20d9d) feat: read talosconfig from secrets directory\n* [`1ad8e6122`](https://github.com/siderolabs/talos/commit/1ad8e6122c5a9bed71ab74bcc66a60d1c26556c1) fix: keep entire vlan id when parsing cmdline\n* [`fe2ee3b10`](https://github.com/siderolabs/talos/commit/fe2ee3b100d37297f3d040d92a07b12b152b8f5f) feat: implement MachineStatus resource\n* [`670d274c4`](https://github.com/siderolabs/talos/commit/670d274c458f8cc3a72bcef2bd3e1b22f053c4e5) chore: bump dependencies\n* [`08d2612e0`](https://github.com/siderolabs/talos/commit/08d2612e07a348c7cfd003d094812ba4f506d9d4) docs: bond devices are comma separated\n* [`c3c3e14db`](https://github.com/siderolabs/talos/commit/c3c3e14db5c916c24bf4f64acfa8735ebf6b6540) chore: add gotagsrewrite tool and use it to add tags to resources\n* [`2e790526f`](https://github.com/siderolabs/talos/commit/2e790526f760c890ad892fffd165ac27ab0dd9b4) refactor: make apid stop gracefully and be stopped late\n* [`0cdf22243`](https://github.com/siderolabs/talos/commit/0cdf22243169a9e5c6e0ecb351a8b841584d99b8) fix: retry Conflict errors when upgrading k8s manifests\n* [`1db097f50`](https://github.com/siderolabs/talos/commit/1db097f509031f86b4d2c72b590c9c657cd09b77) release(v1.2.0-alpha.1): prepare release\n* [`5ac4947b6`](https://github.com/siderolabs/talos/commit/5ac4947b634865104003ac91590d81cae4dd5e53) feat: enable default seccomp profile for kubelet\n* [`e5994ff7a`](https://github.com/siderolabs/talos/commit/e5994ff7a776e9f43f82340ef9916160d2a24149) fix: skip `ResetDuringBoot` test if the `Cluster` config is unknown\n* [`8028e1074`](https://github.com/siderolabs/talos/commit/8028e10749bfc53940651a1cb3eb0dcd56c1507c) fix: wait for boot done when rebooting a node in the integration tests\n* [`ae1bec59e`](https://github.com/siderolabs/talos/commit/ae1bec59e9ce1a9b5f3a2f6a040a16bb26d991a7) feat: allow running only one sequence at a time\n* [`ec05aee04`](https://github.com/siderolabs/talos/commit/ec05aee040371e7261911bdebb03004140ad8eed) fix: correctly unwrap errors when streaming\n* [`7c7f2d8c3`](https://github.com/siderolabs/talos/commit/7c7f2d8c3be3a49f9409b67a98984d5a3d6e6404) feat: refactor disk size matcher to be compatible with DeepEqual\n* [`3addea83b`](https://github.com/siderolabs/talos/commit/3addea83b9ba73418bd1cfd6e083fd4252b41356) feat: introduce support for Talos API access from Kubernetes\n* [`34d3a4164`](https://github.com/siderolabs/talos/commit/34d3a41643162eaedca9210c0edbc813ca77c3bb) docs: add missing <> to relref\n* [`c4d2d20c4`](https://github.com/siderolabs/talos/commit/c4d2d20c419fbbac7888b4b033ef939ff476e3a4) fix: enable stable hostnames for worker configs as well\n* [`0326bac1f`](https://github.com/siderolabs/talos/commit/0326bac1f92c6aa2fc929b768027a71c7285d800) chore: bump kernel to 5.15.57\n* [`86820c33f`](https://github.com/siderolabs/talos/commit/86820c33f1055ce0efbfe2934e84c5627919ed07) chore: bump dependencies\n* [`6e7dfeeb3`](https://github.com/siderolabs/talos/commit/6e7dfeeb38fe5cf0065faa49ca36c3a292e86fae) fix: data race in packet capture (part 2)\n* [`c11e1dae7`](https://github.com/siderolabs/talos/commit/c11e1dae7033e5a530eb7185eabf5c89deacaace) docs: fix spelling and grammar errors\n* [`30f7851d2`](https://github.com/siderolabs/talos/commit/30f7851d2a25ed0f9d7cf28548c3a1f09cd664cd) chore: bump golangci-lint from 1.45.2 to 1.47.2\n* [`2cce9112d`](https://github.com/siderolabs/talos/commit/2cce9112d17384e491ab91b75494241de664ec18) chore: bump goimports from 0.1.10 to 0.1.11\n* [`18756c7ff`](https://github.com/siderolabs/talos/commit/18756c7ff6a9e81615aec1b1ecb3808f500fdaf1) fix: folder permissions of overlay mounted folders\n* [`47c35dc47`](https://github.com/siderolabs/talos/commit/47c35dc4740cad3f758969b5d93885c9782b439a) feat: set stable default hostname based on machine-id\n* [`1ed3df295`](https://github.com/siderolabs/talos/commit/1ed3df295c1a26ed8243c58d6bfecb8c7398daec) chore: support glibc apps extension spec\n* [`a2aea9726`](https://github.com/siderolabs/talos/commit/a2aea97263c787de81f911e085cf81f56dfd0d82) fix: write etcd PKI files in a controller\n* [`bb4abc096`](https://github.com/siderolabs/talos/commit/bb4abc0961dba4c2e158cfebdd7b3d8c010a30b3) fix: regenerate kubelet certs when hostname changes\n* [`d650afb6c`](https://github.com/siderolabs/talos/commit/d650afb6cdd405292515be266f3ee05f19f014ec) chore: fix typo in `powercycle`\n* [`644e803ad`](https://github.com/siderolabs/talos/commit/644e803adf35eaa735af5487ffdcfb7471d17f3e) fix: use masks and different firewall mark for KubeSpan\n* [`80444a43d`](https://github.com/siderolabs/talos/commit/80444a43d9382f44c515224a02610443c77b0fe9) fix: remove data race in pcap capture\n* [`04a45dff2`](https://github.com/siderolabs/talos/commit/04a45dff2831b87b2373664e87794dbf5ecabd08) docs: remove katacoda links\n* [`065b59276`](https://github.com/siderolabs/talos/commit/065b59276c9ac48f2e5fa051c132efc5bfb4b849) feat: implement packet capture API\n* [`7c006cabc`](https://github.com/siderolabs/talos/commit/7c006cabc7ee15146a8db4358156c049d4525cfe) feat: update Kubernetes to 1.24.3\n* [`551290195`](https://github.com/siderolabs/talos/commit/551290195c868c1f23ea0307ef8058537da73064) chore: bump dependencies\n* [`1677bcc4b`](https://github.com/siderolabs/talos/commit/1677bcc4b243886c75f7acc95fe3225032aeee7e) fix: skip bond itself when matching interface (Equinix Metal)\n* [`f1c2b5c55`](https://github.com/siderolabs/talos/commit/f1c2b5c558f96ad45261f0f4f50ecbd50475543e) feat: implement strategic merge patching for API server admission config\n* [`be98cb82b`](https://github.com/siderolabs/talos/commit/be98cb82b5d56e26210e0be0d5d54338df0bb092) feat: follow KEP-2568 non-root enhancements\n* [`87ea1d961`](https://github.com/siderolabs/talos/commit/87ea1d9611332f4552bcf35a2fc80e43fbef89ed) fix: update kubelet kubeconfig when cluster control plane endpoint changes\n* [`a75fe7600`](https://github.com/siderolabs/talos/commit/a75fe7600d554c7d8404a32e9a790c27dfdebb44) feat: gen secrets from kubernetes pki dir\n* [`a1d7b535a`](https://github.com/siderolabs/talos/commit/a1d7b535ad59ec900f8e907bcd8085cece77c1e4) docs: add kubeadm migration guide\n* [`9e0c56581`](https://github.com/siderolabs/talos/commit/9e0c56581e8ab144324a148dc7489da595b0edcb) docs: guide for setting up synology-csi driver\n* [`f0b8eea5e`](https://github.com/siderolabs/talos/commit/f0b8eea5e5b30ca6864eda6872d5e23f41ffdf7d) refactor: remove bootstrap sequence\n* [`89c7da899`](https://github.com/siderolabs/talos/commit/89c7da8991eb1760f220ce7bf7bc7fec7dd4a089) docs: add documentation for vagrant & libvirt\n* [`014b85fdc`](https://github.com/siderolabs/talos/commit/014b85fdcb6575b3db19d6cc7c848c02957f5913) docs: improve talos kubernetes upgrade note\n* [`88bb017ed`](https://github.com/siderolabs/talos/commit/88bb017ed0a57139380dcf07db4c9585d96a4b7e) docs: remove old docs from site\n* [`c92c90655`](https://github.com/siderolabs/talos/commit/c92c90655ace0a0465599483004793c68611af5b) feat: build talosctl for FreeBSD\n* [`616da3069`](https://github.com/siderolabs/talos/commit/616da30695c0a0f8ffd9eb5fed99e2d4aeaf159f) docs: update last release for 1.1\n* [`091e6ef0e`](https://github.com/siderolabs/talos/commit/091e6ef0eb4d5b5fa1245968abb25ebaafcd2a96) feat: resubstitute talos.config url variables on retry\n* [`ec74ab38a`](https://github.com/siderolabs/talos/commit/ec74ab38aa95c222a26048071cd9911024fe3ae2) feat: update Go to 1.18.4, Linux to 5.15.54\n* [`641f6a1e4`](https://github.com/siderolabs/talos/commit/641f6a1e4e106414f9e7667792a84586d49171b9) feat: expose strategic merge config patches\n* [`6e3d2d647`](https://github.com/siderolabs/talos/commit/6e3d2d647d031ff9f11f595a607ae5227cb1035c) docs: fix disk encryption params\n* [`c43d6a31d`](https://github.com/siderolabs/talos/commit/c43d6a31d92db98dd44b2f533d1d6dcd6d8a8c48) docs: fix typos\n* [`551887528`](https://github.com/siderolabs/talos/commit/551887528cf3a29e60c540dc02355a4937cc5b25) chore: bump dependencies\n* [`626ef05e6`](https://github.com/siderolabs/talos/commit/626ef05e6063df3010aee805f6ac442e3298e568) fix: correct SANs for etcd certs\n* [`83ce92c5f`](https://github.com/siderolabs/talos/commit/83ce92c5ff8f8c55ab8e2dddcc45a253b7b9191b) docs: fix theila docs\n* [`8a038d40e`](https://github.com/siderolabs/talos/commit/8a038d40ee9071cf77c559a813ecaa681f730a66) fix: stabilize etcd join and promote sequences\n* [`136122556`](https://github.com/siderolabs/talos/commit/136122556c596ebf579be3aa00e767d05b0e4bb5) fix: use correct etcd cert path\n* [`c170ec0b0`](https://github.com/siderolabs/talos/commit/c170ec0b09e20d2277862057a6f5cefbc963d276) chore: bump kernel to 5.15.53\n* [`d924901b7`](https://github.com/siderolabs/talos/commit/d924901b79d91c3ce5292b7d95487485a7ce0abc) feat: add cli subcommand to generate secrets\n* [`34aabedd8`](https://github.com/siderolabs/talos/commit/34aabedd805a6cb804c9db5e54d80b58c00da0de) feat: more circular pkg from internal to pkg\n* [`4f044e466`](https://github.com/siderolabs/talos/commit/4f044e46643a275a987b61fa4da60f700ccde774) feat: implement strategic merge machine config patching\n* [`c2a512608`](https://github.com/siderolabs/talos/commit/c2a51260881e95e18567962e437c1081ae59968c) fix: avoid double append of `talos.platform` kernel argument\n* [`27dfe7c03`](https://github.com/siderolabs/talos/commit/27dfe7c0352b62fee9895f4ae172467499072af5) fix: perform accurate conflict resolution on overal (kubespan)\n* [`e437445b4`](https://github.com/siderolabs/talos/commit/e437445b4044f58bcad35b171a7f259de6f6ac6d) chore: bump kernel to 5.15.52\n* [`d27a6a4ac`](https://github.com/siderolabs/talos/commit/d27a6a4ac0e058e5e526ee51be512c5d01ea7a19) feat: add vlan support to cmdline\n* [`fdca5d8a9`](https://github.com/siderolabs/talos/commit/fdca5d8a95a04d865a0417624628740480c18b5f) chore: bump dependencies\n* [`ae3840dbc`](https://github.com/siderolabs/talos/commit/ae3840dbc34f32faf8da426378a8a32f1c009659) refactor: move kubeconfig package under public api\n* [`184e113f3`](https://github.com/siderolabs/talos/commit/184e113f35f4a3cd2f036502862af325ee6e3d2f) chore: disable systeminfo controller in container\n* [`86a0a7bdf`](https://github.com/siderolabs/talos/commit/86a0a7bdf70d318bed2143d65784faae6f9125d4) refactor: use pointer types more in machine config structs\n* [`3a1eb10e6`](https://github.com/siderolabs/talos/commit/3a1eb10e61edeef2af497c6ad9101d6cec539a34) docs: update the Proxmox `kvm64` note\n* [`30e220fcd`](https://github.com/siderolabs/talos/commit/30e220fcd265337790ccc9a8070fd7b509336fe0) docs: kernel cmdline params updated on upgrades\n* [`915de9cf9`](https://github.com/siderolabs/talos/commit/915de9cf9bfd33d95b766f8ed5ce0ebb863f60f6) docs: fix bridge documentation\n* [`52cd12951`](https://github.com/siderolabs/talos/commit/52cd12951c567d76c9dfa3ca11ba53d16cdbc5d3) test: bump Talos versions in upgrade tests\n* [`022581d80`](https://github.com/siderolabs/talos/commit/022581d8092840f4c1d9aa4b198650db4f3ba78b) release(v1.2.0-alpha.0): prepare release\n* [`643e81cfe`](https://github.com/siderolabs/talos/commit/643e81cfed675a018ec3af20b74fdcfcdc665d60) feat: add SenseLabs to ADOPTERS.md\n* [`bdfee2b3b`](https://github.com/siderolabs/talos/commit/bdfee2b3b7bf773326bd839ea6049e0262382071) chore: bump kernel to 5.15.51\n* [`36c44a651`](https://github.com/siderolabs/talos/commit/36c44a65110713274fbb4b6638a36f3377c96bb3) fix: provide CA certificates in `/etc/ssl/certs/ca-certificates.crt`\n* [`7ebd9bcce`](https://github.com/siderolabs/talos/commit/7ebd9bcce6f2b1e6a030e551f41f590996294573) docs: fix pod security talos resource name\n* [`57b625e0a`](https://github.com/siderolabs/talos/commit/57b625e0a68534fdb3847e1fff5c18906630d1da) refactor: avoid recreating grpc clients in service health checks\n* [`a68a00f1b`](https://github.com/siderolabs/talos/commit/a68a00f1b9bdbb519966bbf1ac7f463796a85abb) docs: recommend setting \"host\" Processor Type on proxmox\n* [`923600a73`](https://github.com/siderolabs/talos/commit/923600a73c7368fd9217680fdfcc0dc2e9dc4b8e) chore: bump kernel to 5.15.50\n* [`758a9bf59`](https://github.com/siderolabs/talos/commit/758a9bf59fad2f49ca03937c7d1bcfb3c13a9a0b) docs: add theila ui\n* [`b81016e62`](https://github.com/siderolabs/talos/commit/b81016e628642d93fb0b123f7146558279e0c648) chore: update blockdevice library to v0.3.3\n* [`284a2f959`](https://github.com/siderolabs/talos/commit/284a2f9596ce899236d78d43c6d42a287f60540a) fix: filter static pods correctly and optimize fetching\n* [`61abf3111`](https://github.com/siderolabs/talos/commit/61abf311109f2d604d227bb6d290ccaeca19b3f0) docs: change command for cluster create to keep $HOME with sudo\n* [`6ae1e9bf2`](https://github.com/siderolabs/talos/commit/6ae1e9bf2ba7778dbe8a0919cbdf81fbe74b8e8c) chore: bump dependencies\n* [`2deff6b6e`](https://github.com/siderolabs/talos/commit/2deff6b6e148d99e9c88159f4895594417cdf080) feat: add support for variable substitution in talos.config kernel parameter\n* [`103c94225`](https://github.com/siderolabs/talos/commit/103c942256e7832b18e973f3fd698d7e94818c6f) fix: update crypto library with support for RSA-SHA*\n* [`448de7194`](https://github.com/siderolabs/talos/commit/448de7194911b3f8bd79cec3a3e93515ffd2e0a9) docs: add UpCloud installation guide\n* [`07014e0a8`](https://github.com/siderolabs/talos/commit/07014e0a8ee291ab4f2848787fc7462676c11fec) fix: generate correct bootstrap manifests when only IPv6 CIDR is used\n* [`465edbb47`](https://github.com/siderolabs/talos/commit/465edbb4791315d8709daeeba19f14b3e53680f3) fix: look for qemu-kvm binary\n* [`63caa281a`](https://github.com/siderolabs/talos/commit/63caa281ae8b83add1b070014282a6f792843845) fix: create native image format for DigitalOcean\n* [`f15ce549e`](https://github.com/siderolabs/talos/commit/f15ce549e940e6a0a95b8f78a4d7ad967f0a3900) fix: siderlink api assume port 443 with https schema\n* [`797596229`](https://github.com/siderolabs/talos/commit/797596229a7c4a883810c4229492cdfd0b441f19) feat: add support for configuring network bridges\n* [`2b23fabcc`](https://github.com/siderolabs/talos/commit/2b23fabcc1c3f5f495ea4d7fa6597fa639d4ce82) docs: use SVG image for K8s conformance\n* [`d4606c33e`](https://github.com/siderolabs/talos/commit/d4606c33ec36563d29b5ac95f11d1479c61a1905) chore: bump kernel to 5.15.49\n* [`cfb640222`](https://github.com/siderolabs/talos/commit/cfb640222b80e1a2a6c3a8a505c5f6acfb148d24) docs: update docs for release 1.1\n* [`b816d0b60`](https://github.com/siderolabs/talos/commit/b816d0b60077e83028b950a544c810d0875be268) docs: fix the vendor information for Kubernetes conformance tests\n* [`a167a5402`](https://github.com/siderolabs/talos/commit/a167a54021c979a1ca761674d8e368d5fb7dda6a) test: fix CLI nodes discovery without provisioner data\n* [`916a30682`](https://github.com/siderolabs/talos/commit/916a306829190c8eccbb993cfc166aa3cf08042e) docs: add twitter meta info\n* [`80090a3ed`](https://github.com/siderolabs/talos/commit/80090a3eda00e9808b0ba15241ea36dc6835f6d1) test: fix health endpoint cli test when discovery is disabled\n* [`3c263bb44`](https://github.com/siderolabs/talos/commit/3c263bb44639edf456d1c6203f41c71fa4d6d1d0) chore: bump dependencies\n* [`e8113527f`](https://github.com/siderolabs/talos/commit/e8113527f94f0fbc6cf6fdb9390dfb09d984213d) chore: bump kubernetes to v1.24.2\n* [`068f1b6d0`](https://github.com/siderolabs/talos/commit/068f1b6d0517f62d2a76c7b1a761f15104220644) feat: add ctest package and base for test suite\n* [`2aad3a1e4`](https://github.com/siderolabs/talos/commit/2aad3a1e4911ebcd3eb970f09baa74e10383a959) chore: bump kernel to 5.15.48\n* [`a31a858e0`](https://github.com/siderolabs/talos/commit/a31a858e08a7e022dc26c729ef097b6ed56a83ad) docs: snippets for logging api server audit logs\n* [`89aaaef9f`](https://github.com/siderolabs/talos/commit/89aaaef9f5dd403919535fc3e81ef635d233c0da) chore: bump kernel to 5.15.47\n* [`6759fcd4a`](https://github.com/siderolabs/talos/commit/6759fcd4aeeca74e78e346b4265e86580991d800) feat: use discovery service on cluster health checks\n* [`f54d90787`](https://github.com/siderolabs/talos/commit/f54d9078719a62bcefcab367957f166e7a43decc) fix: enable orderly poweroff in hyper-v on Azure\n* [`35475ce45`](https://github.com/siderolabs/talos/commit/35475ce45b1ad64bb34149be9960f5acdd2bfe86) docs: openebs jiva example with iscsi-tools extension\n* [`8d2be5e31`](https://github.com/siderolabs/talos/commit/8d2be5e315fb05002587570d759322c9c00ad525) feat: extend node definition used in health checks\n* [`7a11b4def`](https://github.com/siderolabs/talos/commit/7a11b4def78e5b4506611fe85d083a12b695bd05) fix: make `talosctl bootstrap` accept only single node\n* [`217fba288`](https://github.com/siderolabs/talos/commit/217fba288f07ccf7053e804c226a2e0b9301f864) test: fix csi tests\n* [`90bf34fed`](https://github.com/siderolabs/talos/commit/90bf34fed98cb9ff524097da4043d4ff221a0b20) docs: fork docs for Talos 1.2\n* [`a0dd010a8`](https://github.com/siderolabs/talos/commit/a0dd010a87b0ef0350299db3944f3a941fca09b4) docs: add link to discovery service in kubespan\n* [`c0371410e`](https://github.com/siderolabs/talos/commit/c0371410ee93f9773938b5b73be6eba246fd8f47) fix: support SideroLink \"secure\" gRPC connection\n* [`b03709620`](https://github.com/siderolabs/talos/commit/b03709620201b44f6464a7df804e2003c9751a30) feat: build Talos images with system extensions included\n* [`43def7490`](https://github.com/siderolabs/talos/commit/43def7490ffa598ba973f35903eaea462db374b1) chore: bump kernel and runc\n* [`4dbbf4ac5`](https://github.com/siderolabs/talos/commit/4dbbf4ac50f6b1ccd62efb1c06c8a92d8f91e65c) chore: add generic methods and use them part #2\n* [`7114292b6`](https://github.com/siderolabs/talos/commit/7114292b6cd5f93a51b905db6377ffdadf429f19) docs: fix latest release version in docs\n* [`da2985fe1`](https://github.com/siderolabs/talos/commit/da2985fe1b29abac46b761a5ec2f4557d12ce985) fix: respect local API server port\n* [`e03266667`](https://github.com/siderolabs/talos/commit/e03266667f11d751f16a7208e774996ebadf8842) fix: correctly validate reboot mode in CLI\n* [`70fc42409`](https://github.com/siderolabs/talos/commit/70fc42409980a1a78b98a962284460ea18c42513) chore: add generic methods and use them\n* [`3ae8bdd92`](https://github.com/siderolabs/talos/commit/3ae8bdd92e43c8a5fedd455d4479678ccb263a6b) chore: run `xfs_repair` on xfs filesystem returing `EUCLEAN`\n* [`0c91c89f4`](https://github.com/siderolabs/talos/commit/0c91c89f4f0732147f5b6c41fb4f3da8437ae9f1) chore: revert day-two tests for csi tests\n* [`f71b58312`](https://github.com/siderolabs/talos/commit/f71b58312251ec2924607fb5166afa6c8aaf01bb) feat: disallow anonymous requests by default (kube-apiserver)\n* [`c19dd1b89`](https://github.com/siderolabs/talos/commit/c19dd1b8925fc8ec25a721d336ad0b363fc27fd4) feat: add 'etcd members should be control plane nodes' health check\n* [`f2997c0f2`](https://github.com/siderolabs/talos/commit/f2997c0f22b93382bfb61ff556961de56445807f) chore: bump dependencies\n* [`f3efec4b5`](https://github.com/siderolabs/talos/commit/f3efec4b56bc72dc5c769a76f6254d14d3f20b1b) feat: update containerd 1.6.6, Linux 5.15.45, Flannel 0.18.1\n* [`27f8e50ce`](https://github.com/siderolabs/talos/commit/27f8e50ce90c47f5ddc82645e0ebcdb1a8ed778b) fix: add ovmf image path for rhel\n* [`87e7de30c`](https://github.com/siderolabs/talos/commit/87e7de30cb6ed02991cb46e25d20343555cc6317) docs: fix required ports\n* [`c126f2ee8`](https://github.com/siderolabs/talos/commit/c126f2ee85572bdfde61f9a3ba878f0595c74cfe) chore: bump golang to 1.18.3\n* [`c1aed6240`](https://github.com/siderolabs/talos/commit/c1aed62405dddb2cbd2d47d699aae0c94df70886) fix: wait for `/var` to be mounted in kubelet service controller\n* [`d7a64f5d2`](https://github.com/siderolabs/talos/commit/d7a64f5d2a6ff9dccdf3bdb948684d9513912be9) fix: improve vip operator shutdown sequence\n* [`7b9dfcb85`](https://github.com/siderolabs/talos/commit/7b9dfcb852af6a48f00ddfca7337a571aa56a2b3) chore: add 'make go-mod-outdated'\n</p>\n</details>\n\n### Changes since v1.2.0-alpha.1\n<details><summary>35 commits</summary>\n<p>\n\n* [`5dd1b4002`](https://github.com/siderolabs/talos/commit/5dd1b400205d794b41de5ffc166d5bfe1605533a) feat: disable Kubernetes discovery backend by default\n* [`b62b18a97`](https://github.com/siderolabs/talos/commit/b62b18a9722f3b48a600dd5abd25f5f98af76b31) feat: bump k8s to v1.25.0-beta.0\n* [`7b80a747b`](https://github.com/siderolabs/talos/commit/7b80a747bcd140918c7be1acc9db74fa9a8952f2) feat: add protobuf encoding/decoding for Go structs\n* [`00c3ee3ac`](https://github.com/siderolabs/talos/commit/00c3ee3ac3119249fd92d558283404018de2f1bf) docs: remove obsolete references to init nodes\n* [`6eefa9d9c`](https://github.com/siderolabs/talos/commit/6eefa9d9cb439b073f84ac18f53a889b55a4b4df) fix: properly filter resources in maintenance server\n* [`fa5aad01a`](https://github.com/siderolabs/talos/commit/fa5aad01a0d9144ab9d20a168a50c747f5a9258c) docs: fix issues in GCP docs\n* [`98f056603`](https://github.com/siderolabs/talos/commit/98f056603e876ad41fc66af9a586cb921a91583a) chore: bump dependencies\n* [`84e712a9f`](https://github.com/siderolabs/talos/commit/84e712a9f1626b78638a4fe2524a2b860cb7185f) feat: introduce Talos API access from Kubernetes\n* [`d7be30892`](https://github.com/siderolabs/talos/commit/d7be3089211691e5c5f62c83915d789eeeca31b8) chore: bump kernel to 5.15.59\n* [`c2c2d65bc`](https://github.com/siderolabs/talos/commit/c2c2d65bc98b3ea58df7253df76f3266d7562e48) refactor: use COSI access filter for resource access\n* [`1dee0579e`](https://github.com/siderolabs/talos/commit/1dee0579e9ef6886b2ca8e42b33fce533dc10008) feat: add support for proxying one-to-one to `apid`\n* [`86eb01cd6`](https://github.com/siderolabs/talos/commit/86eb01cd6c905f87532a3d0f697b87e8866fd399) docs: add missing dev tools\n* [`4fd676c04`](https://github.com/siderolabs/talos/commit/4fd676c0468c67799b5d5a1b449551d6243999a5) docs: fix typo in theila name\n* [`856beb21c`](https://github.com/siderolabs/talos/commit/856beb21cc3505c10d17e030d2ce0487e019c7ab) feat: containerd 1.6.7, Flannel 1.19.1\n* [`e97b9f6d3`](https://github.com/siderolabs/talos/commit/e97b9f6d3e14757288d7b2f415b69aef222e8e99) feat: support dhcp options for vlan\n* [`92314e47b`](https://github.com/siderolabs/talos/commit/92314e47bf66319a67d5c302d4f40a4772cb44b7) refactor: use controllers/resources to feed trustd with data\n* [`80d298abf`](https://github.com/siderolabs/talos/commit/80d298abfbf35e411f5dfbebf4c4d5334e36fbe3) feat: support skipping node registration\n* [`7795de313`](https://github.com/siderolabs/talos/commit/7795de313a11918bccda261c184363a8ed750cbb) fix: use controllers/resources for etcd configuration\n* [`f9b664c94`](https://github.com/siderolabs/talos/commit/f9b664c9470be14f840d33c7d1ebf43fa84d1127) fix: reload trusted CA list when client is recreated\n* [`8847ccd03`](https://github.com/siderolabs/talos/commit/8847ccd03106d525b40b0f3719d9632b00db9753) fix: shutdown some streaming API calls when machined API is shuting down\n* [`f95b53726`](https://github.com/siderolabs/talos/commit/f95b5372625a1ad83f61ea86e54ac6a74f2fd09a) fix: allow files in extension spec\n* [`1a8f6ec8e`](https://github.com/siderolabs/talos/commit/1a8f6ec8e1b47ee63dcc85b9f70b43871a7a5bd4) fix: don't advertise Kubernetes pod networks over KubeSpan by default\n* [`e3d4a0e4d`](https://github.com/siderolabs/talos/commit/e3d4a0e4d12fc87675178bc34e3a96817c0ad73b) fix: make reset work even if the node is not bootstrapped/not joined\n* [`a6b010a8b`](https://github.com/siderolabs/talos/commit/a6b010a8b45981a41feb03876828e29e3510a8e9) chore: update Go to 1.19, Linux to 5.15.58\n* [`fb058a7c9`](https://github.com/siderolabs/talos/commit/fb058a7c9236a80c333c21bbd2bbda785f33ced6) test: use `T.TempDir` to create temporary test directory\n* [`6fc38bae6`](https://github.com/siderolabs/talos/commit/6fc38bae690906d628e89f9cb19c17e16500f27f) fix: iterate over etcd members endpoints for member promotion\n* [`c70b692fb`](https://github.com/siderolabs/talos/commit/c70b692fb34becf651042019c675b1e0750ec703) fix: update default address if removed from the host\n* [`cf620d473`](https://github.com/siderolabs/talos/commit/cf620d4733d4bd4c243213676caf7c5fe6a20d9d) feat: read talosconfig from secrets directory\n* [`1ad8e6122`](https://github.com/siderolabs/talos/commit/1ad8e6122c5a9bed71ab74bcc66a60d1c26556c1) fix: keep entire vlan id when parsing cmdline\n* [`fe2ee3b10`](https://github.com/siderolabs/talos/commit/fe2ee3b100d37297f3d040d92a07b12b152b8f5f) feat: implement MachineStatus resource\n* [`670d274c4`](https://github.com/siderolabs/talos/commit/670d274c458f8cc3a72bcef2bd3e1b22f053c4e5) chore: bump dependencies\n* [`08d2612e0`](https://github.com/siderolabs/talos/commit/08d2612e07a348c7cfd003d094812ba4f506d9d4) docs: bond devices are comma separated\n* [`c3c3e14db`](https://github.com/siderolabs/talos/commit/c3c3e14db5c916c24bf4f64acfa8735ebf6b6540) chore: add gotagsrewrite tool and use it to add tags to resources\n* [`2e790526f`](https://github.com/siderolabs/talos/commit/2e790526f760c890ad892fffd165ac27ab0dd9b4) refactor: make apid stop gracefully and be stopped late\n* [`0cdf22243`](https://github.com/siderolabs/talos/commit/0cdf22243169a9e5c6e0ecb351a8b841584d99b8) fix: retry Conflict errors when upgrading k8s manifests\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`da35a63`](https://github.com/siderolabs/extras/commit/da35a6309dff8cf34316d2c1503a9e44cafa4e1d) feat: update Go to 1.19\n* [`17a319f`](https://github.com/siderolabs/extras/commit/17a319ffeecba7f20c2fa9f75ccc677b3964e754) chore: update Go to 1.18.4\n* [`892407f`](https://github.com/siderolabs/extras/commit/892407fd7c1a032ec4d7de5d52595ef3bcc7b484) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>28 commits</summary>\n<p>\n\n* [`7783ee3`](https://github.com/siderolabs/pkgs/commit/7783ee3df01fb153629e0745dcec7ebe37b5b597) chore: bump kernel to 5.15.59\n* [`360d596`](https://github.com/siderolabs/pkgs/commit/360d5968b7841f425f9d3605f419877aa2829c6e) feat: update containerd to 1.6.7\n* [`6feece4`](https://github.com/siderolabs/pkgs/commit/6feece4a08ec9bb7b23f0849d8aa3926c3242841) feat: update Go to 1.19\n* [`9ad3aeb`](https://github.com/siderolabs/pkgs/commit/9ad3aeb88edb8087db83fdfcdb3c0b604906cf3f) chore: bump kernel to 5.15.58\n* [`dcc0311`](https://github.com/siderolabs/pkgs/commit/dcc031138e336747daeee4b77d8813f4a8078abd) chore: bump kernel to 5.15.57\n* [`b943a9d`](https://github.com/siderolabs/pkgs/commit/b943a9da08124042a56cf939c2cfc4c2591201d2) chore: update Go to 1.18.4\n* [`a44e324`](https://github.com/siderolabs/pkgs/commit/a44e32412d667b26ce682288584d3f413ce888d4) chore: bump kernel to 5.15.54\n* [`247f567`](https://github.com/siderolabs/pkgs/commit/247f567b8490bba7b02b54a42c33177521733701) chore: bump kernel to 5.15.53\n* [`4fe9867`](https://github.com/siderolabs/pkgs/commit/4fe98672466f361fb7de4e1ddb3449b59e6a4193) chore: bump openssl to 1.1.1q\n* [`9ee662c`](https://github.com/siderolabs/pkgs/commit/9ee662c5d808c75e3373d0e1fb3dfbfe3cd9663c) chore: bump kernel to 5.15.52\n* [`4412db8`](https://github.com/siderolabs/pkgs/commit/4412db88987acf91ffc2a83c09dd0dd5d84819eb) chore: bump kernel to 5.15.51\n* [`6fedbdc`](https://github.com/siderolabs/pkgs/commit/6fedbdc826cffe5b0740c43f5641218df58e767c) chore: bump tools\n* [`f1f44e6`](https://github.com/siderolabs/pkgs/commit/f1f44e6a254e571c34f667e086e50afec099500b) chore: bump kernel to 5.15.50\n* [`388af5e`](https://github.com/siderolabs/pkgs/commit/388af5e4eea16e0b19ce58879ea9d79676b9608b) chore: bump openssl to 1.1.1p\n* [`ed75c50`](https://github.com/siderolabs/pkgs/commit/ed75c5011e29107a59ffca1bececee1d22937ba2) chore: enable `RANDOM_TRUST_BOOTLOADER` by default\n* [`7c243f6`](https://github.com/siderolabs/pkgs/commit/7c243f6da5b3c0476106ff47d37b5d7a8ad28d98) chore: bump kernel to 5.15.49\n* [`6e1269e`](https://github.com/siderolabs/pkgs/commit/6e1269e67f1e8a81cccf6ed45980595f2d6343f5) chore: bump kernel to 5.15.48\n* [`5d671a3`](https://github.com/siderolabs/pkgs/commit/5d671a3cd6ebed495022f23e0073c1f971477305) chore: bump nvidia drivers to 515.48.07\n* [`b35d835`](https://github.com/siderolabs/pkgs/commit/b35d835a1cfc3215d631f8ace3d3b1b7c83da008) chore: bump kernel to 5.15.47\n* [`6604d6b`](https://github.com/siderolabs/pkgs/commit/6604d6b0686ea36983119edd7fb70755d3a812e0) feat: hyperv arm64\n* [`c474058`](https://github.com/siderolabs/pkgs/commit/c4740588733138df9503c37304d1460166a3e233) chore: bump nvidia driver to 515.43.04\n* [`5bc7e34`](https://github.com/siderolabs/pkgs/commit/5bc7e341fa0c035bbecc999bca3811b853684c5f) feat: update runc to 1.1.3, libseccomp to 2.5.4\n* [`c02cd7a`](https://github.com/siderolabs/pkgs/commit/c02cd7a7086098698d1edd1d5ecb024ad9456a48) chore: bump kernel to 5.15.46\n* [`b9c72a5`](https://github.com/siderolabs/pkgs/commit/b9c72a59cd6077ceb0ce53f11241d294c137f68b) feat: update containerd to 1.6.6\n* [`f7786a3`](https://github.com/siderolabs/pkgs/commit/f7786a3a74bbf79c81cbcb031c357eae0e07726f) chore: bump kernel to 5.15.45\n* [`b1c207d`](https://github.com/siderolabs/pkgs/commit/b1c207d63b1cac99b90025d530c57da4f51fc652) feat: update containerd to 1.6.5\n* [`4d47830`](https://github.com/siderolabs/pkgs/commit/4d47830f86bfda0ae8cc9c89a6ca8ae3a73772cd) chore: bump golang to 1.18.3\n* [`dc21e30`](https://github.com/siderolabs/pkgs/commit/dc21e30a2f31effab56b6e32c785fd0644eb90d2) chore: bump kernel to 5.15.44\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>7 commits</summary>\n<p>\n\n* [`cd35510`](https://github.com/siderolabs/tools/commit/cd355105d5c3acb2f8bf96d79693ed4b48447c73) feat: update Go to 1.19\n* [`e83198d`](https://github.com/siderolabs/tools/commit/e83198d7045f376f517274c298a3b0830637d8b7) chore: bump git to v2.37.1\n* [`0d669dd`](https://github.com/siderolabs/tools/commit/0d669dd415a044e5279f36c468834848ed6447bf) feat: update Go 1.18.4\n* [`26b32d5`](https://github.com/siderolabs/tools/commit/26b32d582f13a9ea3ab55558bb8b8c2500008da0) chore: bump openssl to 1.1.1q\n* [`d8015e7`](https://github.com/siderolabs/tools/commit/d8015e756d74def09cee0503da08186eeccecb9a) chore: bump curl to 7.84.0\n* [`3ec03ed`](https://github.com/siderolabs/tools/commit/3ec03edef31e971f48cb3202667af2045bcc233f) chore: bump openssl to 1.1.1p\n* [`3df9e13`](https://github.com/siderolabs/tools/commit/3df9e13ab89600655f5371adf254d66dda36ef02) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`e9df1b8`](https://github.com/talos-systems/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`74ea471`](https://github.com/talos-systems/go-blockdevice/commit/74ea47109c4525bec139640fed6354ad3097f5fb) feat: add freebsd stubs\n* [`9fa801c`](https://github.com/talos-systems/go-blockdevice/commit/9fa801cf4da184e3560b9a18ba43d13316f172f9) feat: add ReadOnly attribute to Disk\n</p>\n</details>\n\n### Changes from talos-systems/grpc-proxy\n<details><summary>1 commit</summary>\n<p>\n\n* [`6dfa2cc`](https://github.com/talos-systems/grpc-proxy/commit/6dfa2cc80b6195844cae2dc2b2bc0b9b62246d8d) fix: ignore errors on duplicate `SetHeader` calls\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.6.1 -> v1.7.0\n* **github.com/BurntSushi/toml**                     v1.1.0 -> v1.2.0\n* **github.com/aws/aws-sdk-go**                      v1.44.24 -> v1.44.71\n* **github.com/containerd/containerd**               v1.6.4 -> v1.6.8\n* **github.com/containernetworking/cni**             v1.1.0 -> v1.1.2\n* **github.com/cosi-project/runtime**                95d06feaf8b5 -> cd5f564066ad\n* **github.com/docker/docker**                       v20.10.16 -> v20.10.17\n* **github.com/emicklei/dot**                        v0.16.0 -> v1.0.0\n* **github.com/google/gopacket**                     v1.1.19 **_new_**\n* **github.com/google/nftables**                     a9775fb167d2 -> 2eca00135732\n* **github.com/hashicorp/go-getter**                 v1.6.1 -> v1.6.2\n* **github.com/hashicorp/go-version**                v1.5.0 -> v1.6.0\n* **github.com/hetznercloud/hcloud-go**              v1.33.2 -> v1.35.2\n* **github.com/jsimonetti/rtnetlink**                v1.2.0 -> v1.2.1\n* **github.com/martinlindhe/base36**                 v1.1.1 **_new_**\n* **github.com/packethost/packngo**                  v0.24.0 -> v0.25.0\n* **github.com/prometheus/procfs**                   v0.7.3 -> v0.8.0\n* **github.com/rivo/tview**                          9994674d60a8 -> 37ad0bb93703\n* **github.com/siderolabs/extras**                   v1.1.0-1-g5800284 -> v1.2.0-alpha.0-2-gda35a63\n* **github.com/siderolabs/pkgs**                     v1.1.0-8-gfa9a488 -> v1.2.0-alpha.0-27-g7783ee3\n* **github.com/siderolabs/tools**                    v1.1.0-1-g134974c -> v1.2.0-alpha.0-6-gcd35510\n* **github.com/spf13/cobra**                         v1.4.0 -> v1.5.0\n* **github.com/stretchr/testify**                    v1.7.1 -> v1.8.0\n* **github.com/talos-systems/crypto**                v0.3.5 -> e9df1b8ca74c\n* **github.com/talos-systems/go-blockdevice**        v0.3.2 -> v0.3.4\n* **github.com/talos-systems/grpc-proxy**            v0.3.0 -> v0.3.1\n* **github.com/u-root/u-root**                       v0.8.0 -> v0.9.0\n* **github.com/vishvananda/netlink**                 v1.2.0-beta -> v1.2.1-beta.2\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.6 -> v0.56.9\n* **github.com/vmware/govmomi**                      v0.28.0 -> v0.29.0\n* **golang.org/x/net**                               5463443f8c37 -> a33c5aa5df48\n* **golang.org/x/sync**                              0976fa681c29 -> 886fb9371eb4\n* **golang.org/x/sys**                               bc2c85ada10a -> 1c4a2a72c664\n* **golang.org/x/term**                              065cf7ba2467 -> a9ba230a4035\n* **golang.org/x/time**                              583f2d630306 -> e5dcc9cfc0b9\n* **google.golang.org/grpc**                         v1.46.2 -> v1.48.0\n* **google.golang.org/protobuf**                     v1.28.0 -> v1.28.1\n* **gopkg.in/yaml.v3**                               496545a6307b -> v3.0.1\n* **inet.af/netaddr**                                c74959edd3b6 -> 097006376321\n* **k8s.io/api**                                     v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/apimachinery**                            v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/apiserver**                               v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/client-go**                               v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/component-base**                          v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/cri-api**                                 v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/kubectl**                                 v0.24.2 -> v0.25.0-beta.0\n* **k8s.io/kubelet**                                 v0.24.2 -> v0.25.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.64 -> v1.2.65\n\nPrevious release can be found at [v1.1.0](https://github.com/siderolabs/talos/releases/tag/v1.1.0)\n\n## [Talos 1.2.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.2.0-alpha.1) (2022-07-28)\n\nWelcome to the v1.2.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Generating Talos secrets from PKI directory\n\nIt is now possible to generate a secrets bundle from a Kubernetes PKI directory (e.g. `/etc/kubernetes/pki`).\n\nYou can also specify a bootstrap token to be used in the secrets bundle.\n\nThis secrets bundle can then be used to generate a machine config.\n\nThis facilitates migrating clusters (e.g. created using `kubeadm`) to Talos.\n\n```\ntalosctl gen secrets --kubernetes-bootstrap-token znzio1.1ifu15frz7jd59pv --from-kubernetes-pki /etc/kubernetes/pki\ntalosctl gen config --with-secrets secrets.yaml my-cluster https://172.20.0.1:6443\n```\n\n\n### Kubernetes ControlPlane Components\n\nTalos now run all Kubernetes Control Plane Components with the CRI default Seccomp Profile and other recommendations as described in\n[KEP-2568](https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/kubeadm/2568-kubeadm-non-root-control-plane).\n\n\n### Kubelet Default Runtime Seccomp Profile\n\nTalos now runs Kubelet with the CRI default Seccomp Profile enabled.\nThis can be disabled by setting `.machine.kubelet.defaultRuntimeSeccompProfileEnabled` to `false`.\n\nThis is not enabled automatically on upgrades, so upgrading to Talos v1.2 needs this to be explicitly enabled.\n\n\n### Network bridge support\n\nTalos now supports configuring Linux bridges. It can be configured in the machine config like the following:\n\n```yaml\nmachine:\n  network:\n    interfaces:\n      - interface: br0\n        bridge:\n          stp:\n            enabled: true\n          interfaces:\n            - eth0\n            - eth1\n```\n\nSee [documentation](https://www.talos.dev/v1.2/reference/configuration/#bridge) for more details.\n\n\n### VLAN support in cmdline arguments\n\nTalos now supports dracut-style `vlan` kernel argument to allow\ninstalling Talos Linux in networks where ports are not tagged\nwith a default VLAN:\n\n```\nvlan=eth1.5:eth1 ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1.5:::::\n```\n\n\n\n### Packet Capture\n\nTalos now supports capturing packets on a network interface with `talosctl pcap` command:\n\n  talosctl pcap --interface eth0\n\n\n### Seccomp Profiles\n\nTalos now supports creating custom seccomp profiles on the host machine which in turn can be used by Kubernetes workloads.\nIt can be configured in the machine config as below:\n\n```yaml\nmachine:\n  seccompProfiles:\n    - name: audit.json\n      value:\n        defaultAction: SCMP_ACT_LOG\n    - name: deny.json\n      value: {\"defaultAction\":\"SCMP_ACT_LOG\"}\n```\n\nThis profile data can be either configured as a YAML definition or as a JSON string.\n\nThe profiles are created on the host under `/var/lib/seccomp/profiles` and bind mounted at `/var/lib/kubelet/seccomp/profiles` so Kubelet can use it.\n\nSee [documentation](https://www.talos.dev/v1.2/kubernetes-guides/configuration/seccomp-profiles/) for more details.\n\n\n### Stable Default Hostname\n\nTalos now generates the default hostname (when there is no explicitly specified hostname) for the nodes based on the\nnode id (e.g. `talos-2gd-76y`) instead of using the DHCP assigned IP address (e.g. `talos-172-20-0-2`).\n\nThis ensures that the node hostname is not changed when DHCP assigns a new IP to a node.\n\n\n### Strategic merge machine configuration patching\n\nIn addition to JSON (RFC6902) patches Talos now supports [strategic merge patching](https://www.talos.dev/v1.2/talos-guides/configuration/patching/).\n\nFor example, machine hostname can be set with the following patch:\n\n```yaml\nmachine:\n  network:\n    hostname: worker1\n```\n\nPatch format is detected automatically.\n\n\n### Variable substitution for URL query parameter in the talos.config kernel parameter\n\nThe kernel parameter talos.config can now substitute system information into placeholders inside its URL query values. This example shows all supported variables:\n\n```http://example.com/metadata?h=${hostname}&m=${mac}&s=${serial}&u=${uuid}```\n\n\n### Component Updates\n\n* Linux: 5.15.57\n\nTalos is built with Go 1.18.4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Utku Ozdemir\n* Dmitriy Matrenichev\n* Philipp Sauter\n* Tim Jones\n* Spencer Smith\n* Artem Chernyshev\n* Davincible\n* AMet\n* Alex Wied\n* Bermi Ferrer\n* Christoph Schmatzler\n* Dennis Marttinen\n* Eirik Askheim\n* Florian Klink\n* Han Cen\n* Larry Rosenman\n* Markus Reiter\n* Matthew Richardson\n* Nico Berlee\n* Rio Kierkels\n* RyanSquared\n* Serge Logvinov\n* Seán C McCord\n* hobyte\n* nett_hier\n* zebernst\n\n### Changes\n<details><summary>128 commits</summary>\n<p>\n\n* [`5ac4947b6`](https://github.com/siderolabs/talos/commit/5ac4947b634865104003ac91590d81cae4dd5e53) feat: enable default seccomp profile for kubelet\n* [`e5994ff7a`](https://github.com/siderolabs/talos/commit/e5994ff7a776e9f43f82340ef9916160d2a24149) fix: skip `ResetDuringBoot` test if the `Cluster` config is unknown\n* [`8028e1074`](https://github.com/siderolabs/talos/commit/8028e10749bfc53940651a1cb3eb0dcd56c1507c) fix: wait for boot done when rebooting a node in the integration tests\n* [`ae1bec59e`](https://github.com/siderolabs/talos/commit/ae1bec59e9ce1a9b5f3a2f6a040a16bb26d991a7) feat: allow running only one sequence at a time\n* [`ec05aee04`](https://github.com/siderolabs/talos/commit/ec05aee040371e7261911bdebb03004140ad8eed) fix: correctly unwrap errors when streaming\n* [`7c7f2d8c3`](https://github.com/siderolabs/talos/commit/7c7f2d8c3be3a49f9409b67a98984d5a3d6e6404) feat: refactor disk size matcher to be compatible with DeepEqual\n* [`3addea83b`](https://github.com/siderolabs/talos/commit/3addea83b9ba73418bd1cfd6e083fd4252b41356) feat: introduce support for Talos API access from Kubernetes\n* [`34d3a4164`](https://github.com/siderolabs/talos/commit/34d3a41643162eaedca9210c0edbc813ca77c3bb) docs: add missing <> to relref\n* [`c4d2d20c4`](https://github.com/siderolabs/talos/commit/c4d2d20c419fbbac7888b4b033ef939ff476e3a4) fix: enable stable hostnames for worker configs as well\n* [`0326bac1f`](https://github.com/siderolabs/talos/commit/0326bac1f92c6aa2fc929b768027a71c7285d800) chore: bump kernel to 5.15.57\n* [`86820c33f`](https://github.com/siderolabs/talos/commit/86820c33f1055ce0efbfe2934e84c5627919ed07) chore: bump dependencies\n* [`6e7dfeeb3`](https://github.com/siderolabs/talos/commit/6e7dfeeb38fe5cf0065faa49ca36c3a292e86fae) fix: data race in packet capture (part 2)\n* [`c11e1dae7`](https://github.com/siderolabs/talos/commit/c11e1dae7033e5a530eb7185eabf5c89deacaace) docs: fix spelling and grammar errors\n* [`30f7851d2`](https://github.com/siderolabs/talos/commit/30f7851d2a25ed0f9d7cf28548c3a1f09cd664cd) chore: bump golangci-lint from 1.45.2 to 1.47.2\n* [`2cce9112d`](https://github.com/siderolabs/talos/commit/2cce9112d17384e491ab91b75494241de664ec18) chore: bump goimports from 0.1.10 to 0.1.11\n* [`18756c7ff`](https://github.com/siderolabs/talos/commit/18756c7ff6a9e81615aec1b1ecb3808f500fdaf1) fix: folder permissions of overlay mounted folders\n* [`47c35dc47`](https://github.com/siderolabs/talos/commit/47c35dc4740cad3f758969b5d93885c9782b439a) feat: set stable default hostname based on machine-id\n* [`1ed3df295`](https://github.com/siderolabs/talos/commit/1ed3df295c1a26ed8243c58d6bfecb8c7398daec) chore: support glibc apps extension spec\n* [`a2aea9726`](https://github.com/siderolabs/talos/commit/a2aea97263c787de81f911e085cf81f56dfd0d82) fix: write etcd PKI files in a controller\n* [`bb4abc096`](https://github.com/siderolabs/talos/commit/bb4abc0961dba4c2e158cfebdd7b3d8c010a30b3) fix: regenerate kubelet certs when hostname changes\n* [`d650afb6c`](https://github.com/siderolabs/talos/commit/d650afb6cdd405292515be266f3ee05f19f014ec) chore: fix typo in `powercycle`\n* [`644e803ad`](https://github.com/siderolabs/talos/commit/644e803adf35eaa735af5487ffdcfb7471d17f3e) fix: use masks and different firewall mark for KubeSpan\n* [`80444a43d`](https://github.com/siderolabs/talos/commit/80444a43d9382f44c515224a02610443c77b0fe9) fix: remove data race in pcap capture\n* [`04a45dff2`](https://github.com/siderolabs/talos/commit/04a45dff2831b87b2373664e87794dbf5ecabd08) docs: remove katacoda links\n* [`065b59276`](https://github.com/siderolabs/talos/commit/065b59276c9ac48f2e5fa051c132efc5bfb4b849) feat: implement packet capture API\n* [`7c006cabc`](https://github.com/siderolabs/talos/commit/7c006cabc7ee15146a8db4358156c049d4525cfe) feat: update Kubernetes to 1.24.3\n* [`551290195`](https://github.com/siderolabs/talos/commit/551290195c868c1f23ea0307ef8058537da73064) chore: bump dependencies\n* [`1677bcc4b`](https://github.com/siderolabs/talos/commit/1677bcc4b243886c75f7acc95fe3225032aeee7e) fix: skip bond itself when matching interface (Equinix Metal)\n* [`f1c2b5c55`](https://github.com/siderolabs/talos/commit/f1c2b5c558f96ad45261f0f4f50ecbd50475543e) feat: implement strategic merge patching for API server admission config\n* [`be98cb82b`](https://github.com/siderolabs/talos/commit/be98cb82b5d56e26210e0be0d5d54338df0bb092) feat: follow KEP-2568 non-root enhancements\n* [`87ea1d961`](https://github.com/siderolabs/talos/commit/87ea1d9611332f4552bcf35a2fc80e43fbef89ed) fix: update kubelet kubeconfig when cluster control plane endpoint changes\n* [`a75fe7600`](https://github.com/siderolabs/talos/commit/a75fe7600d554c7d8404a32e9a790c27dfdebb44) feat: gen secrets from kubernetes pki dir\n* [`a1d7b535a`](https://github.com/siderolabs/talos/commit/a1d7b535ad59ec900f8e907bcd8085cece77c1e4) docs: add kubeadm migration guide\n* [`9e0c56581`](https://github.com/siderolabs/talos/commit/9e0c56581e8ab144324a148dc7489da595b0edcb) docs: guide for setting up synology-csi driver\n* [`f0b8eea5e`](https://github.com/siderolabs/talos/commit/f0b8eea5e5b30ca6864eda6872d5e23f41ffdf7d) refactor: remove bootstrap sequence\n* [`89c7da899`](https://github.com/siderolabs/talos/commit/89c7da8991eb1760f220ce7bf7bc7fec7dd4a089) docs: add documentation for vagrant & libvirt\n* [`014b85fdc`](https://github.com/siderolabs/talos/commit/014b85fdcb6575b3db19d6cc7c848c02957f5913) docs: improve talos kubernetes upgrade note\n* [`88bb017ed`](https://github.com/siderolabs/talos/commit/88bb017ed0a57139380dcf07db4c9585d96a4b7e) docs: remove old docs from site\n* [`c92c90655`](https://github.com/siderolabs/talos/commit/c92c90655ace0a0465599483004793c68611af5b) feat: build talosctl for FreeBSD\n* [`616da3069`](https://github.com/siderolabs/talos/commit/616da30695c0a0f8ffd9eb5fed99e2d4aeaf159f) docs: update last release for 1.1\n* [`091e6ef0e`](https://github.com/siderolabs/talos/commit/091e6ef0eb4d5b5fa1245968abb25ebaafcd2a96) feat: resubstitute talos.config url variables on retry\n* [`ec74ab38a`](https://github.com/siderolabs/talos/commit/ec74ab38aa95c222a26048071cd9911024fe3ae2) feat: update Go to 1.18.4, Linux to 5.15.54\n* [`641f6a1e4`](https://github.com/siderolabs/talos/commit/641f6a1e4e106414f9e7667792a84586d49171b9) feat: expose strategic merge config patches\n* [`6e3d2d647`](https://github.com/siderolabs/talos/commit/6e3d2d647d031ff9f11f595a607ae5227cb1035c) docs: fix disk encryption params\n* [`c43d6a31d`](https://github.com/siderolabs/talos/commit/c43d6a31d92db98dd44b2f533d1d6dcd6d8a8c48) docs: fix typos\n* [`551887528`](https://github.com/siderolabs/talos/commit/551887528cf3a29e60c540dc02355a4937cc5b25) chore: bump dependencies\n* [`626ef05e6`](https://github.com/siderolabs/talos/commit/626ef05e6063df3010aee805f6ac442e3298e568) fix: correct SANs for etcd certs\n* [`83ce92c5f`](https://github.com/siderolabs/talos/commit/83ce92c5ff8f8c55ab8e2dddcc45a253b7b9191b) docs: fix theila docs\n* [`8a038d40e`](https://github.com/siderolabs/talos/commit/8a038d40ee9071cf77c559a813ecaa681f730a66) fix: stabilize etcd join and promote sequences\n* [`136122556`](https://github.com/siderolabs/talos/commit/136122556c596ebf579be3aa00e767d05b0e4bb5) fix: use correct etcd cert path\n* [`c170ec0b0`](https://github.com/siderolabs/talos/commit/c170ec0b09e20d2277862057a6f5cefbc963d276) chore: bump kernel to 5.15.53\n* [`d924901b7`](https://github.com/siderolabs/talos/commit/d924901b79d91c3ce5292b7d95487485a7ce0abc) feat: add cli subcommand to generate secrets\n* [`34aabedd8`](https://github.com/siderolabs/talos/commit/34aabedd805a6cb804c9db5e54d80b58c00da0de) feat: more circular pkg from internal to pkg\n* [`4f044e466`](https://github.com/siderolabs/talos/commit/4f044e46643a275a987b61fa4da60f700ccde774) feat: implement strategic merge machine config patching\n* [`c2a512608`](https://github.com/siderolabs/talos/commit/c2a51260881e95e18567962e437c1081ae59968c) fix: avoid double append of `talos.platform` kernel argument\n* [`27dfe7c03`](https://github.com/siderolabs/talos/commit/27dfe7c0352b62fee9895f4ae172467499072af5) fix: perform accurate conflict resolution on overal (kubespan)\n* [`e437445b4`](https://github.com/siderolabs/talos/commit/e437445b4044f58bcad35b171a7f259de6f6ac6d) chore: bump kernel to 5.15.52\n* [`d27a6a4ac`](https://github.com/siderolabs/talos/commit/d27a6a4ac0e058e5e526ee51be512c5d01ea7a19) feat: add vlan support to cmdline\n* [`fdca5d8a9`](https://github.com/siderolabs/talos/commit/fdca5d8a95a04d865a0417624628740480c18b5f) chore: bump dependencies\n* [`ae3840dbc`](https://github.com/siderolabs/talos/commit/ae3840dbc34f32faf8da426378a8a32f1c009659) refactor: move kubeconfig package under public api\n* [`184e113f3`](https://github.com/siderolabs/talos/commit/184e113f35f4a3cd2f036502862af325ee6e3d2f) chore: disable systeminfo controller in container\n* [`86a0a7bdf`](https://github.com/siderolabs/talos/commit/86a0a7bdf70d318bed2143d65784faae6f9125d4) refactor: use pointer types more in machine config structs\n* [`3a1eb10e6`](https://github.com/siderolabs/talos/commit/3a1eb10e61edeef2af497c6ad9101d6cec539a34) docs: update the Proxmox `kvm64` note\n* [`30e220fcd`](https://github.com/siderolabs/talos/commit/30e220fcd265337790ccc9a8070fd7b509336fe0) docs: kernel cmdline params updated on upgrades\n* [`915de9cf9`](https://github.com/siderolabs/talos/commit/915de9cf9bfd33d95b766f8ed5ce0ebb863f60f6) docs: fix bridge documentation\n* [`52cd12951`](https://github.com/siderolabs/talos/commit/52cd12951c567d76c9dfa3ca11ba53d16cdbc5d3) test: bump Talos versions in upgrade tests\n* [`022581d80`](https://github.com/siderolabs/talos/commit/022581d8092840f4c1d9aa4b198650db4f3ba78b) release(v1.2.0-alpha.0): prepare release\n* [`643e81cfe`](https://github.com/siderolabs/talos/commit/643e81cfed675a018ec3af20b74fdcfcdc665d60) feat: add SenseLabs to ADOPTERS.md\n* [`bdfee2b3b`](https://github.com/siderolabs/talos/commit/bdfee2b3b7bf773326bd839ea6049e0262382071) chore: bump kernel to 5.15.51\n* [`36c44a651`](https://github.com/siderolabs/talos/commit/36c44a65110713274fbb4b6638a36f3377c96bb3) fix: provide CA certificates in `/etc/ssl/certs/ca-certificates.crt`\n* [`7ebd9bcce`](https://github.com/siderolabs/talos/commit/7ebd9bcce6f2b1e6a030e551f41f590996294573) docs: fix pod security talos resource name\n* [`57b625e0a`](https://github.com/siderolabs/talos/commit/57b625e0a68534fdb3847e1fff5c18906630d1da) refactor: avoid recreating grpc clients in service health checks\n* [`a68a00f1b`](https://github.com/siderolabs/talos/commit/a68a00f1b9bdbb519966bbf1ac7f463796a85abb) docs: recommend setting \"host\" Processor Type on proxmox\n* [`923600a73`](https://github.com/siderolabs/talos/commit/923600a73c7368fd9217680fdfcc0dc2e9dc4b8e) chore: bump kernel to 5.15.50\n* [`758a9bf59`](https://github.com/siderolabs/talos/commit/758a9bf59fad2f49ca03937c7d1bcfb3c13a9a0b) docs: add theila ui\n* [`b81016e62`](https://github.com/siderolabs/talos/commit/b81016e628642d93fb0b123f7146558279e0c648) chore: update blockdevice library to v0.3.3\n* [`284a2f959`](https://github.com/siderolabs/talos/commit/284a2f9596ce899236d78d43c6d42a287f60540a) fix: filter static pods correctly and optimize fetching\n* [`61abf3111`](https://github.com/siderolabs/talos/commit/61abf311109f2d604d227bb6d290ccaeca19b3f0) docs: change command for cluster create to keep $HOME with sudo\n* [`6ae1e9bf2`](https://github.com/siderolabs/talos/commit/6ae1e9bf2ba7778dbe8a0919cbdf81fbe74b8e8c) chore: bump dependencies\n* [`2deff6b6e`](https://github.com/siderolabs/talos/commit/2deff6b6e148d99e9c88159f4895594417cdf080) feat: add support for variable substitution in talos.config kernel parameter\n* [`103c94225`](https://github.com/siderolabs/talos/commit/103c942256e7832b18e973f3fd698d7e94818c6f) fix: update crypto library with support for RSA-SHA*\n* [`448de7194`](https://github.com/siderolabs/talos/commit/448de7194911b3f8bd79cec3a3e93515ffd2e0a9) docs: add UpCloud installation guide\n* [`07014e0a8`](https://github.com/siderolabs/talos/commit/07014e0a8ee291ab4f2848787fc7462676c11fec) fix: generate correct bootstrap manifests when only IPv6 CIDR is used\n* [`465edbb47`](https://github.com/siderolabs/talos/commit/465edbb4791315d8709daeeba19f14b3e53680f3) fix: look for qemu-kvm binary\n* [`63caa281a`](https://github.com/siderolabs/talos/commit/63caa281ae8b83add1b070014282a6f792843845) fix: create native image format for DigitalOcean\n* [`f15ce549e`](https://github.com/siderolabs/talos/commit/f15ce549e940e6a0a95b8f78a4d7ad967f0a3900) fix: siderlink api assume port 443 with https schema\n* [`797596229`](https://github.com/siderolabs/talos/commit/797596229a7c4a883810c4229492cdfd0b441f19) feat: add support for configuring network bridges\n* [`2b23fabcc`](https://github.com/siderolabs/talos/commit/2b23fabcc1c3f5f495ea4d7fa6597fa639d4ce82) docs: use SVG image for K8s conformance\n* [`d4606c33e`](https://github.com/siderolabs/talos/commit/d4606c33ec36563d29b5ac95f11d1479c61a1905) chore: bump kernel to 5.15.49\n* [`cfb640222`](https://github.com/siderolabs/talos/commit/cfb640222b80e1a2a6c3a8a505c5f6acfb148d24) docs: update docs for release 1.1\n* [`b816d0b60`](https://github.com/siderolabs/talos/commit/b816d0b60077e83028b950a544c810d0875be268) docs: fix the vendor information for Kubernetes conformance tests\n* [`a167a5402`](https://github.com/siderolabs/talos/commit/a167a54021c979a1ca761674d8e368d5fb7dda6a) test: fix CLI nodes discovery without provisioner data\n* [`916a30682`](https://github.com/siderolabs/talos/commit/916a306829190c8eccbb993cfc166aa3cf08042e) docs: add twitter meta info\n* [`80090a3ed`](https://github.com/siderolabs/talos/commit/80090a3eda00e9808b0ba15241ea36dc6835f6d1) test: fix health endpoint cli test when discovery is disabled\n* [`3c263bb44`](https://github.com/siderolabs/talos/commit/3c263bb44639edf456d1c6203f41c71fa4d6d1d0) chore: bump dependencies\n* [`e8113527f`](https://github.com/siderolabs/talos/commit/e8113527f94f0fbc6cf6fdb9390dfb09d984213d) chore: bump kubernetes to v1.24.2\n* [`068f1b6d0`](https://github.com/siderolabs/talos/commit/068f1b6d0517f62d2a76c7b1a761f15104220644) feat: add ctest package and base for test suite\n* [`2aad3a1e4`](https://github.com/siderolabs/talos/commit/2aad3a1e4911ebcd3eb970f09baa74e10383a959) chore: bump kernel to 5.15.48\n* [`a31a858e0`](https://github.com/siderolabs/talos/commit/a31a858e08a7e022dc26c729ef097b6ed56a83ad) docs: snippets for logging api server audit logs\n* [`89aaaef9f`](https://github.com/siderolabs/talos/commit/89aaaef9f5dd403919535fc3e81ef635d233c0da) chore: bump kernel to 5.15.47\n* [`6759fcd4a`](https://github.com/siderolabs/talos/commit/6759fcd4aeeca74e78e346b4265e86580991d800) feat: use discovery service on cluster health checks\n* [`f54d90787`](https://github.com/siderolabs/talos/commit/f54d9078719a62bcefcab367957f166e7a43decc) fix: enable orderly poweroff in hyper-v on Azure\n* [`35475ce45`](https://github.com/siderolabs/talos/commit/35475ce45b1ad64bb34149be9960f5acdd2bfe86) docs: openebs jiva example with iscsi-tools extension\n* [`8d2be5e31`](https://github.com/siderolabs/talos/commit/8d2be5e315fb05002587570d759322c9c00ad525) feat: extend node definition used in health checks\n* [`7a11b4def`](https://github.com/siderolabs/talos/commit/7a11b4def78e5b4506611fe85d083a12b695bd05) fix: make `talosctl bootstrap` accept only single node\n* [`217fba288`](https://github.com/siderolabs/talos/commit/217fba288f07ccf7053e804c226a2e0b9301f864) test: fix csi tests\n* [`90bf34fed`](https://github.com/siderolabs/talos/commit/90bf34fed98cb9ff524097da4043d4ff221a0b20) docs: fork docs for Talos 1.2\n* [`a0dd010a8`](https://github.com/siderolabs/talos/commit/a0dd010a87b0ef0350299db3944f3a941fca09b4) docs: add link to discovery service in kubespan\n* [`c0371410e`](https://github.com/siderolabs/talos/commit/c0371410ee93f9773938b5b73be6eba246fd8f47) fix: support SideroLink \"secure\" gRPC connection\n* [`b03709620`](https://github.com/siderolabs/talos/commit/b03709620201b44f6464a7df804e2003c9751a30) feat: build Talos images with system extensions included\n* [`43def7490`](https://github.com/siderolabs/talos/commit/43def7490ffa598ba973f35903eaea462db374b1) chore: bump kernel and runc\n* [`4dbbf4ac5`](https://github.com/siderolabs/talos/commit/4dbbf4ac50f6b1ccd62efb1c06c8a92d8f91e65c) chore: add generic methods and use them part #2\n* [`7114292b6`](https://github.com/siderolabs/talos/commit/7114292b6cd5f93a51b905db6377ffdadf429f19) docs: fix latest release version in docs\n* [`da2985fe1`](https://github.com/siderolabs/talos/commit/da2985fe1b29abac46b761a5ec2f4557d12ce985) fix: respect local API server port\n* [`e03266667`](https://github.com/siderolabs/talos/commit/e03266667f11d751f16a7208e774996ebadf8842) fix: correctly validate reboot mode in CLI\n* [`70fc42409`](https://github.com/siderolabs/talos/commit/70fc42409980a1a78b98a962284460ea18c42513) chore: add generic methods and use them\n* [`3ae8bdd92`](https://github.com/siderolabs/talos/commit/3ae8bdd92e43c8a5fedd455d4479678ccb263a6b) chore: run `xfs_repair` on xfs filesystem returing `EUCLEAN`\n* [`0c91c89f4`](https://github.com/siderolabs/talos/commit/0c91c89f4f0732147f5b6c41fb4f3da8437ae9f1) chore: revert day-two tests for csi tests\n* [`f71b58312`](https://github.com/siderolabs/talos/commit/f71b58312251ec2924607fb5166afa6c8aaf01bb) feat: disallow anonymous requests by default (kube-apiserver)\n* [`c19dd1b89`](https://github.com/siderolabs/talos/commit/c19dd1b8925fc8ec25a721d336ad0b363fc27fd4) feat: add 'etcd members should be control plane nodes' health check\n* [`f2997c0f2`](https://github.com/siderolabs/talos/commit/f2997c0f22b93382bfb61ff556961de56445807f) chore: bump dependencies\n* [`f3efec4b5`](https://github.com/siderolabs/talos/commit/f3efec4b56bc72dc5c769a76f6254d14d3f20b1b) feat: update containerd 1.6.6, Linux 5.15.45, Flannel 0.18.1\n* [`27f8e50ce`](https://github.com/siderolabs/talos/commit/27f8e50ce90c47f5ddc82645e0ebcdb1a8ed778b) fix: add ovmf image path for rhel\n* [`87e7de30c`](https://github.com/siderolabs/talos/commit/87e7de30cb6ed02991cb46e25d20343555cc6317) docs: fix required ports\n* [`c126f2ee8`](https://github.com/siderolabs/talos/commit/c126f2ee85572bdfde61f9a3ba878f0595c74cfe) chore: bump golang to 1.18.3\n* [`c1aed6240`](https://github.com/siderolabs/talos/commit/c1aed62405dddb2cbd2d47d699aae0c94df70886) fix: wait for `/var` to be mounted in kubelet service controller\n* [`d7a64f5d2`](https://github.com/siderolabs/talos/commit/d7a64f5d2a6ff9dccdf3bdb948684d9513912be9) fix: improve vip operator shutdown sequence\n* [`7b9dfcb85`](https://github.com/siderolabs/talos/commit/7b9dfcb852af6a48f00ddfca7337a571aa56a2b3) chore: add 'make go-mod-outdated'\n</p>\n</details>\n\n### Changes since v1.2.0-alpha.0\n<details><summary>66 commits</summary>\n<p>\n\n* [`5ac4947b6`](https://github.com/siderolabs/talos/commit/5ac4947b634865104003ac91590d81cae4dd5e53) feat: enable default seccomp profile for kubelet\n* [`e5994ff7a`](https://github.com/siderolabs/talos/commit/e5994ff7a776e9f43f82340ef9916160d2a24149) fix: skip `ResetDuringBoot` test if the `Cluster` config is unknown\n* [`8028e1074`](https://github.com/siderolabs/talos/commit/8028e10749bfc53940651a1cb3eb0dcd56c1507c) fix: wait for boot done when rebooting a node in the integration tests\n* [`ae1bec59e`](https://github.com/siderolabs/talos/commit/ae1bec59e9ce1a9b5f3a2f6a040a16bb26d991a7) feat: allow running only one sequence at a time\n* [`ec05aee04`](https://github.com/siderolabs/talos/commit/ec05aee040371e7261911bdebb03004140ad8eed) fix: correctly unwrap errors when streaming\n* [`7c7f2d8c3`](https://github.com/siderolabs/talos/commit/7c7f2d8c3be3a49f9409b67a98984d5a3d6e6404) feat: refactor disk size matcher to be compatible with DeepEqual\n* [`3addea83b`](https://github.com/siderolabs/talos/commit/3addea83b9ba73418bd1cfd6e083fd4252b41356) feat: introduce support for Talos API access from Kubernetes\n* [`34d3a4164`](https://github.com/siderolabs/talos/commit/34d3a41643162eaedca9210c0edbc813ca77c3bb) docs: add missing <> to relref\n* [`c4d2d20c4`](https://github.com/siderolabs/talos/commit/c4d2d20c419fbbac7888b4b033ef939ff476e3a4) fix: enable stable hostnames for worker configs as well\n* [`0326bac1f`](https://github.com/siderolabs/talos/commit/0326bac1f92c6aa2fc929b768027a71c7285d800) chore: bump kernel to 5.15.57\n* [`86820c33f`](https://github.com/siderolabs/talos/commit/86820c33f1055ce0efbfe2934e84c5627919ed07) chore: bump dependencies\n* [`6e7dfeeb3`](https://github.com/siderolabs/talos/commit/6e7dfeeb38fe5cf0065faa49ca36c3a292e86fae) fix: data race in packet capture (part 2)\n* [`c11e1dae7`](https://github.com/siderolabs/talos/commit/c11e1dae7033e5a530eb7185eabf5c89deacaace) docs: fix spelling and grammar errors\n* [`30f7851d2`](https://github.com/siderolabs/talos/commit/30f7851d2a25ed0f9d7cf28548c3a1f09cd664cd) chore: bump golangci-lint from 1.45.2 to 1.47.2\n* [`2cce9112d`](https://github.com/siderolabs/talos/commit/2cce9112d17384e491ab91b75494241de664ec18) chore: bump goimports from 0.1.10 to 0.1.11\n* [`18756c7ff`](https://github.com/siderolabs/talos/commit/18756c7ff6a9e81615aec1b1ecb3808f500fdaf1) fix: folder permissions of overlay mounted folders\n* [`47c35dc47`](https://github.com/siderolabs/talos/commit/47c35dc4740cad3f758969b5d93885c9782b439a) feat: set stable default hostname based on machine-id\n* [`1ed3df295`](https://github.com/siderolabs/talos/commit/1ed3df295c1a26ed8243c58d6bfecb8c7398daec) chore: support glibc apps extension spec\n* [`a2aea9726`](https://github.com/siderolabs/talos/commit/a2aea97263c787de81f911e085cf81f56dfd0d82) fix: write etcd PKI files in a controller\n* [`bb4abc096`](https://github.com/siderolabs/talos/commit/bb4abc0961dba4c2e158cfebdd7b3d8c010a30b3) fix: regenerate kubelet certs when hostname changes\n* [`d650afb6c`](https://github.com/siderolabs/talos/commit/d650afb6cdd405292515be266f3ee05f19f014ec) chore: fix typo in `powercycle`\n* [`644e803ad`](https://github.com/siderolabs/talos/commit/644e803adf35eaa735af5487ffdcfb7471d17f3e) fix: use masks and different firewall mark for KubeSpan\n* [`80444a43d`](https://github.com/siderolabs/talos/commit/80444a43d9382f44c515224a02610443c77b0fe9) fix: remove data race in pcap capture\n* [`04a45dff2`](https://github.com/siderolabs/talos/commit/04a45dff2831b87b2373664e87794dbf5ecabd08) docs: remove katacoda links\n* [`065b59276`](https://github.com/siderolabs/talos/commit/065b59276c9ac48f2e5fa051c132efc5bfb4b849) feat: implement packet capture API\n* [`7c006cabc`](https://github.com/siderolabs/talos/commit/7c006cabc7ee15146a8db4358156c049d4525cfe) feat: update Kubernetes to 1.24.3\n* [`551290195`](https://github.com/siderolabs/talos/commit/551290195c868c1f23ea0307ef8058537da73064) chore: bump dependencies\n* [`1677bcc4b`](https://github.com/siderolabs/talos/commit/1677bcc4b243886c75f7acc95fe3225032aeee7e) fix: skip bond itself when matching interface (Equinix Metal)\n* [`f1c2b5c55`](https://github.com/siderolabs/talos/commit/f1c2b5c558f96ad45261f0f4f50ecbd50475543e) feat: implement strategic merge patching for API server admission config\n* [`be98cb82b`](https://github.com/siderolabs/talos/commit/be98cb82b5d56e26210e0be0d5d54338df0bb092) feat: follow KEP-2568 non-root enhancements\n* [`87ea1d961`](https://github.com/siderolabs/talos/commit/87ea1d9611332f4552bcf35a2fc80e43fbef89ed) fix: update kubelet kubeconfig when cluster control plane endpoint changes\n* [`a75fe7600`](https://github.com/siderolabs/talos/commit/a75fe7600d554c7d8404a32e9a790c27dfdebb44) feat: gen secrets from kubernetes pki dir\n* [`a1d7b535a`](https://github.com/siderolabs/talos/commit/a1d7b535ad59ec900f8e907bcd8085cece77c1e4) docs: add kubeadm migration guide\n* [`9e0c56581`](https://github.com/siderolabs/talos/commit/9e0c56581e8ab144324a148dc7489da595b0edcb) docs: guide for setting up synology-csi driver\n* [`f0b8eea5e`](https://github.com/siderolabs/talos/commit/f0b8eea5e5b30ca6864eda6872d5e23f41ffdf7d) refactor: remove bootstrap sequence\n* [`89c7da899`](https://github.com/siderolabs/talos/commit/89c7da8991eb1760f220ce7bf7bc7fec7dd4a089) docs: add documentation for vagrant & libvirt\n* [`014b85fdc`](https://github.com/siderolabs/talos/commit/014b85fdcb6575b3db19d6cc7c848c02957f5913) docs: improve talos kubernetes upgrade note\n* [`88bb017ed`](https://github.com/siderolabs/talos/commit/88bb017ed0a57139380dcf07db4c9585d96a4b7e) docs: remove old docs from site\n* [`c92c90655`](https://github.com/siderolabs/talos/commit/c92c90655ace0a0465599483004793c68611af5b) feat: build talosctl for FreeBSD\n* [`616da3069`](https://github.com/siderolabs/talos/commit/616da30695c0a0f8ffd9eb5fed99e2d4aeaf159f) docs: update last release for 1.1\n* [`091e6ef0e`](https://github.com/siderolabs/talos/commit/091e6ef0eb4d5b5fa1245968abb25ebaafcd2a96) feat: resubstitute talos.config url variables on retry\n* [`ec74ab38a`](https://github.com/siderolabs/talos/commit/ec74ab38aa95c222a26048071cd9911024fe3ae2) feat: update Go to 1.18.4, Linux to 5.15.54\n* [`641f6a1e4`](https://github.com/siderolabs/talos/commit/641f6a1e4e106414f9e7667792a84586d49171b9) feat: expose strategic merge config patches\n* [`6e3d2d647`](https://github.com/siderolabs/talos/commit/6e3d2d647d031ff9f11f595a607ae5227cb1035c) docs: fix disk encryption params\n* [`c43d6a31d`](https://github.com/siderolabs/talos/commit/c43d6a31d92db98dd44b2f533d1d6dcd6d8a8c48) docs: fix typos\n* [`551887528`](https://github.com/siderolabs/talos/commit/551887528cf3a29e60c540dc02355a4937cc5b25) chore: bump dependencies\n* [`626ef05e6`](https://github.com/siderolabs/talos/commit/626ef05e6063df3010aee805f6ac442e3298e568) fix: correct SANs for etcd certs\n* [`83ce92c5f`](https://github.com/siderolabs/talos/commit/83ce92c5ff8f8c55ab8e2dddcc45a253b7b9191b) docs: fix theila docs\n* [`8a038d40e`](https://github.com/siderolabs/talos/commit/8a038d40ee9071cf77c559a813ecaa681f730a66) fix: stabilize etcd join and promote sequences\n* [`136122556`](https://github.com/siderolabs/talos/commit/136122556c596ebf579be3aa00e767d05b0e4bb5) fix: use correct etcd cert path\n* [`c170ec0b0`](https://github.com/siderolabs/talos/commit/c170ec0b09e20d2277862057a6f5cefbc963d276) chore: bump kernel to 5.15.53\n* [`d924901b7`](https://github.com/siderolabs/talos/commit/d924901b79d91c3ce5292b7d95487485a7ce0abc) feat: add cli subcommand to generate secrets\n* [`34aabedd8`](https://github.com/siderolabs/talos/commit/34aabedd805a6cb804c9db5e54d80b58c00da0de) feat: more circular pkg from internal to pkg\n* [`4f044e466`](https://github.com/siderolabs/talos/commit/4f044e46643a275a987b61fa4da60f700ccde774) feat: implement strategic merge machine config patching\n* [`c2a512608`](https://github.com/siderolabs/talos/commit/c2a51260881e95e18567962e437c1081ae59968c) fix: avoid double append of `talos.platform` kernel argument\n* [`27dfe7c03`](https://github.com/siderolabs/talos/commit/27dfe7c0352b62fee9895f4ae172467499072af5) fix: perform accurate conflict resolution on overal (kubespan)\n* [`e437445b4`](https://github.com/siderolabs/talos/commit/e437445b4044f58bcad35b171a7f259de6f6ac6d) chore: bump kernel to 5.15.52\n* [`d27a6a4ac`](https://github.com/siderolabs/talos/commit/d27a6a4ac0e058e5e526ee51be512c5d01ea7a19) feat: add vlan support to cmdline\n* [`fdca5d8a9`](https://github.com/siderolabs/talos/commit/fdca5d8a95a04d865a0417624628740480c18b5f) chore: bump dependencies\n* [`ae3840dbc`](https://github.com/siderolabs/talos/commit/ae3840dbc34f32faf8da426378a8a32f1c009659) refactor: move kubeconfig package under public api\n* [`184e113f3`](https://github.com/siderolabs/talos/commit/184e113f35f4a3cd2f036502862af325ee6e3d2f) chore: disable systeminfo controller in container\n* [`86a0a7bdf`](https://github.com/siderolabs/talos/commit/86a0a7bdf70d318bed2143d65784faae6f9125d4) refactor: use pointer types more in machine config structs\n* [`3a1eb10e6`](https://github.com/siderolabs/talos/commit/3a1eb10e61edeef2af497c6ad9101d6cec539a34) docs: update the Proxmox `kvm64` note\n* [`30e220fcd`](https://github.com/siderolabs/talos/commit/30e220fcd265337790ccc9a8070fd7b509336fe0) docs: kernel cmdline params updated on upgrades\n* [`915de9cf9`](https://github.com/siderolabs/talos/commit/915de9cf9bfd33d95b766f8ed5ce0ebb863f60f6) docs: fix bridge documentation\n* [`52cd12951`](https://github.com/siderolabs/talos/commit/52cd12951c567d76c9dfa3ca11ba53d16cdbc5d3) test: bump Talos versions in upgrade tests\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`17a319f`](https://github.com/siderolabs/extras/commit/17a319ffeecba7f20c2fa9f75ccc677b3964e754) chore: update Go to 1.18.4\n* [`892407f`](https://github.com/siderolabs/extras/commit/892407fd7c1a032ec4d7de5d52595ef3bcc7b484) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>24 commits</summary>\n<p>\n\n* [`dcc0311`](https://github.com/siderolabs/pkgs/commit/dcc031138e336747daeee4b77d8813f4a8078abd) chore: bump kernel to 5.15.57\n* [`b943a9d`](https://github.com/siderolabs/pkgs/commit/b943a9da08124042a56cf939c2cfc4c2591201d2) chore: update Go to 1.18.4\n* [`a44e324`](https://github.com/siderolabs/pkgs/commit/a44e32412d667b26ce682288584d3f413ce888d4) chore: bump kernel to 5.15.54\n* [`247f567`](https://github.com/siderolabs/pkgs/commit/247f567b8490bba7b02b54a42c33177521733701) chore: bump kernel to 5.15.53\n* [`4fe9867`](https://github.com/siderolabs/pkgs/commit/4fe98672466f361fb7de4e1ddb3449b59e6a4193) chore: bump openssl to 1.1.1q\n* [`9ee662c`](https://github.com/siderolabs/pkgs/commit/9ee662c5d808c75e3373d0e1fb3dfbfe3cd9663c) chore: bump kernel to 5.15.52\n* [`4412db8`](https://github.com/siderolabs/pkgs/commit/4412db88987acf91ffc2a83c09dd0dd5d84819eb) chore: bump kernel to 5.15.51\n* [`6fedbdc`](https://github.com/siderolabs/pkgs/commit/6fedbdc826cffe5b0740c43f5641218df58e767c) chore: bump tools\n* [`f1f44e6`](https://github.com/siderolabs/pkgs/commit/f1f44e6a254e571c34f667e086e50afec099500b) chore: bump kernel to 5.15.50\n* [`388af5e`](https://github.com/siderolabs/pkgs/commit/388af5e4eea16e0b19ce58879ea9d79676b9608b) chore: bump openssl to 1.1.1p\n* [`ed75c50`](https://github.com/siderolabs/pkgs/commit/ed75c5011e29107a59ffca1bececee1d22937ba2) chore: enable `RANDOM_TRUST_BOOTLOADER` by default\n* [`7c243f6`](https://github.com/siderolabs/pkgs/commit/7c243f6da5b3c0476106ff47d37b5d7a8ad28d98) chore: bump kernel to 5.15.49\n* [`6e1269e`](https://github.com/siderolabs/pkgs/commit/6e1269e67f1e8a81cccf6ed45980595f2d6343f5) chore: bump kernel to 5.15.48\n* [`5d671a3`](https://github.com/siderolabs/pkgs/commit/5d671a3cd6ebed495022f23e0073c1f971477305) chore: bump nvidia drivers to 515.48.07\n* [`b35d835`](https://github.com/siderolabs/pkgs/commit/b35d835a1cfc3215d631f8ace3d3b1b7c83da008) chore: bump kernel to 5.15.47\n* [`6604d6b`](https://github.com/siderolabs/pkgs/commit/6604d6b0686ea36983119edd7fb70755d3a812e0) feat: hyperv arm64\n* [`c474058`](https://github.com/siderolabs/pkgs/commit/c4740588733138df9503c37304d1460166a3e233) chore: bump nvidia driver to 515.43.04\n* [`5bc7e34`](https://github.com/siderolabs/pkgs/commit/5bc7e341fa0c035bbecc999bca3811b853684c5f) feat: update runc to 1.1.3, libseccomp to 2.5.4\n* [`c02cd7a`](https://github.com/siderolabs/pkgs/commit/c02cd7a7086098698d1edd1d5ecb024ad9456a48) chore: bump kernel to 5.15.46\n* [`b9c72a5`](https://github.com/siderolabs/pkgs/commit/b9c72a59cd6077ceb0ce53f11241d294c137f68b) feat: update containerd to 1.6.6\n* [`f7786a3`](https://github.com/siderolabs/pkgs/commit/f7786a3a74bbf79c81cbcb031c357eae0e07726f) chore: bump kernel to 5.15.45\n* [`b1c207d`](https://github.com/siderolabs/pkgs/commit/b1c207d63b1cac99b90025d530c57da4f51fc652) feat: update containerd to 1.6.5\n* [`4d47830`](https://github.com/siderolabs/pkgs/commit/4d47830f86bfda0ae8cc9c89a6ca8ae3a73772cd) chore: bump golang to 1.18.3\n* [`dc21e30`](https://github.com/siderolabs/pkgs/commit/dc21e30a2f31effab56b6e32c785fd0644eb90d2) chore: bump kernel to 5.15.44\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`0d669dd`](https://github.com/siderolabs/tools/commit/0d669dd415a044e5279f36c468834848ed6447bf) feat: update Go 1.18.4\n* [`26b32d5`](https://github.com/siderolabs/tools/commit/26b32d582f13a9ea3ab55558bb8b8c2500008da0) chore: bump openssl to 1.1.1q\n* [`d8015e7`](https://github.com/siderolabs/tools/commit/d8015e756d74def09cee0503da08186eeccecb9a) chore: bump curl to 7.84.0\n* [`3ec03ed`](https://github.com/siderolabs/tools/commit/3ec03edef31e971f48cb3202667af2045bcc233f) chore: bump openssl to 1.1.1p\n* [`3df9e13`](https://github.com/siderolabs/tools/commit/3df9e13ab89600655f5371adf254d66dda36ef02) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`e9df1b8`](https://github.com/talos-systems/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`74ea471`](https://github.com/talos-systems/go-blockdevice/commit/74ea47109c4525bec139640fed6354ad3097f5fb) feat: add freebsd stubs\n* [`9fa801c`](https://github.com/talos-systems/go-blockdevice/commit/9fa801cf4da184e3560b9a18ba43d13316f172f9) feat: add ReadOnly attribute to Disk\n</p>\n</details>\n\n### Changes from talos-systems/grpc-proxy\n<details><summary>1 commit</summary>\n<p>\n\n* [`6dfa2cc`](https://github.com/talos-systems/grpc-proxy/commit/6dfa2cc80b6195844cae2dc2b2bc0b9b62246d8d) fix: ignore errors on duplicate `SetHeader` calls\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.6.1 -> v1.7.0\n* **github.com/BurntSushi/toml**                     v1.1.0 -> v1.2.0\n* **github.com/aws/aws-sdk-go**                      v1.44.24 -> v1.44.61\n* **github.com/containerd/containerd**               v1.6.4 -> v1.6.6\n* **github.com/containernetworking/cni**             v1.1.0 -> v1.1.1\n* **github.com/cosi-project/runtime**                95d06feaf8b5 -> 22c6aa1ca7ec\n* **github.com/docker/docker**                       v20.10.16 -> v20.10.17\n* **github.com/emicklei/dot**                        v0.16.0 -> v1.0.0\n* **github.com/google/gopacket**                     v1.1.19 **_new_**\n* **github.com/google/nftables**                     a9775fb167d2 -> a346d51f53b3\n* **github.com/hashicorp/go-getter**                 v1.6.1 -> v1.6.2\n* **github.com/hashicorp/go-version**                v1.5.0 -> v1.6.0\n* **github.com/hetznercloud/hcloud-go**              v1.33.2 -> v1.35.1\n* **github.com/martinlindhe/base36**                 v1.1.1 **_new_**\n* **github.com/packethost/packngo**                  v0.24.0 -> v0.25.0\n* **github.com/rivo/tview**                          9994674d60a8 -> 73bf2902b59a\n* **github.com/siderolabs/extras**                   v1.1.0-1-g5800284 -> v1.2.0-alpha.0-1-g17a319f\n* **github.com/siderolabs/pkgs**                     v1.1.0-8-gfa9a488 -> v1.2.0-alpha.0-23-gdcc0311\n* **github.com/siderolabs/tools**                    v1.1.0-1-g134974c -> v1.2.0-alpha.0-4-g0d669dd\n* **github.com/spf13/cobra**                         v1.4.0 -> v1.5.0\n* **github.com/stretchr/testify**                    v1.7.1 -> v1.8.0\n* **github.com/talos-systems/crypto**                v0.3.5 -> e9df1b8ca74c\n* **github.com/talos-systems/go-blockdevice**        v0.3.2 -> v0.3.4\n* **github.com/talos-systems/grpc-proxy**            v0.3.0 -> v0.3.1\n* **github.com/vishvananda/netlink**                 v1.2.0-beta -> v1.2.1-beta.2\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.6 -> v0.56.8\n* **github.com/vmware/govmomi**                      v0.28.0 -> v0.29.0\n* **golang.org/x/net**                               5463443f8c37 -> a158d28d115b\n* **golang.org/x/sync**                              0976fa681c29 -> 886fb9371eb4\n* **golang.org/x/sys**                               bc2c85ada10a -> 8c9f86f7a55f\n* **golang.org/x/term**                              065cf7ba2467 -> a9ba230a4035\n* **golang.org/x/time**                              583f2d630306 -> e5dcc9cfc0b9\n* **google.golang.org/grpc**                         v1.46.2 -> v1.48.0\n* **gopkg.in/yaml.v3**                               496545a6307b -> v3.0.1\n* **inet.af/netaddr**                                c74959edd3b6 -> 097006376321\n* **k8s.io/api**                                     v0.24.2 -> v0.24.3\n* **k8s.io/apiserver**                               v0.24.2 -> v0.24.3\n* **k8s.io/client-go**                               v0.24.2 -> v0.24.3\n* **k8s.io/component-base**                          v0.24.2 -> v0.24.3\n* **k8s.io/kubectl**                                 v0.24.2 -> v0.24.3\n* **k8s.io/kubelet**                                 v0.24.2 -> v0.24.3\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.64 -> v1.2.65\n\nPrevious release can be found at [v1.1.0](https://github.com/siderolabs/talos/releases/tag/v1.1.0)\n\n## [Talos 1.2.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.2.0-alpha.0) (2022-06-30)\n\nWelcome to the v1.2.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Network bridge support\n\nTalos now supports configuring Linux bridges. It can be configured in the machine config like the following:\n```yaml\nspec:\n  machine:\n    network:\n      interfaces:\n        - interface: br0\n          bridge:\n            stp:\n              enabled: true\n            interfaces:\n              - eth0\n              - eth1\n```\n\nSee [documentation](https://www.talos.dev/v1.1/reference/configuration/#bridge) for more details.\n\n\n### Variable substitution for URL query parameter in the talos.config kernel parameter\n\nThe kernel parameter talos.config can now substitute system information into placeholders inside its URL query values. This example shows all supported variables:\n\n```http://example.com/metadata?h=${hostname}&m=${mac}&s=${serial}&u=${uuid}```\n\n\n### Component Updates\n\n* Linux: 5.15.51\n\n\n### Contributors\n\n* Noel Georgi\n* Andrey Smirnov\n* Utku Ozdemir\n* Philipp Sauter\n* Tim Jones\n* Dmitriy Matrenichev\n* Davincible\n* Han Cen\n* Rio Kierkels\n* RyanSquared\n* Serge Logvinov\n* Spencer Smith\n* hobyte\n* nett_hier\n\n### Changes\n<details><summary>61 commits</summary>\n<p>\n\n* [`643e81cfe`](https://github.com/siderolabs/talos/commit/643e81cfed675a018ec3af20b74fdcfcdc665d60) feat: add SenseLabs to ADOPTERS.md\n* [`bdfee2b3b`](https://github.com/siderolabs/talos/commit/bdfee2b3b7bf773326bd839ea6049e0262382071) chore: bump kernel to 5.15.51\n* [`36c44a651`](https://github.com/siderolabs/talos/commit/36c44a65110713274fbb4b6638a36f3377c96bb3) fix: provide CA certificates in `/etc/ssl/certs/ca-certificates.crt`\n* [`7ebd9bcce`](https://github.com/siderolabs/talos/commit/7ebd9bcce6f2b1e6a030e551f41f590996294573) docs: fix pod security talos resource name\n* [`57b625e0a`](https://github.com/siderolabs/talos/commit/57b625e0a68534fdb3847e1fff5c18906630d1da) refactor: avoid recreating grpc clients in service health checks\n* [`a68a00f1b`](https://github.com/siderolabs/talos/commit/a68a00f1b9bdbb519966bbf1ac7f463796a85abb) docs: recommend setting \"host\" Processor Type on proxmox\n* [`923600a73`](https://github.com/siderolabs/talos/commit/923600a73c7368fd9217680fdfcc0dc2e9dc4b8e) chore: bump kernel to 5.15.50\n* [`758a9bf59`](https://github.com/siderolabs/talos/commit/758a9bf59fad2f49ca03937c7d1bcfb3c13a9a0b) docs: add theila ui\n* [`b81016e62`](https://github.com/siderolabs/talos/commit/b81016e628642d93fb0b123f7146558279e0c648) chore: update blockdevice library to v0.3.3\n* [`284a2f959`](https://github.com/siderolabs/talos/commit/284a2f9596ce899236d78d43c6d42a287f60540a) fix: filter static pods correctly and optimize fetching\n* [`61abf3111`](https://github.com/siderolabs/talos/commit/61abf311109f2d604d227bb6d290ccaeca19b3f0) docs: change command for cluster create to keep $HOME with sudo\n* [`6ae1e9bf2`](https://github.com/siderolabs/talos/commit/6ae1e9bf2ba7778dbe8a0919cbdf81fbe74b8e8c) chore: bump dependencies\n* [`2deff6b6e`](https://github.com/siderolabs/talos/commit/2deff6b6e148d99e9c88159f4895594417cdf080) feat: add support for variable substitution in talos.config kernel parameter\n* [`103c94225`](https://github.com/siderolabs/talos/commit/103c942256e7832b18e973f3fd698d7e94818c6f) fix: update crypto library with support for RSA-SHA*\n* [`448de7194`](https://github.com/siderolabs/talos/commit/448de7194911b3f8bd79cec3a3e93515ffd2e0a9) docs: add UpCloud installation guide\n* [`07014e0a8`](https://github.com/siderolabs/talos/commit/07014e0a8ee291ab4f2848787fc7462676c11fec) fix: generate correct bootstrap manifests when only IPv6 CIDR is used\n* [`465edbb47`](https://github.com/siderolabs/talos/commit/465edbb4791315d8709daeeba19f14b3e53680f3) fix: look for qemu-kvm binary\n* [`63caa281a`](https://github.com/siderolabs/talos/commit/63caa281ae8b83add1b070014282a6f792843845) fix: create native image format for DigitalOcean\n* [`f15ce549e`](https://github.com/siderolabs/talos/commit/f15ce549e940e6a0a95b8f78a4d7ad967f0a3900) fix: siderlink api assume port 443 with https schema\n* [`797596229`](https://github.com/siderolabs/talos/commit/797596229a7c4a883810c4229492cdfd0b441f19) feat: add support for configuring network bridges\n* [`2b23fabcc`](https://github.com/siderolabs/talos/commit/2b23fabcc1c3f5f495ea4d7fa6597fa639d4ce82) docs: use SVG image for K8s conformance\n* [`d4606c33e`](https://github.com/siderolabs/talos/commit/d4606c33ec36563d29b5ac95f11d1479c61a1905) chore: bump kernel to 5.15.49\n* [`cfb640222`](https://github.com/siderolabs/talos/commit/cfb640222b80e1a2a6c3a8a505c5f6acfb148d24) docs: update docs for release 1.1\n* [`b816d0b60`](https://github.com/siderolabs/talos/commit/b816d0b60077e83028b950a544c810d0875be268) docs: fix the vendor information for Kubernetes conformance tests\n* [`a167a5402`](https://github.com/siderolabs/talos/commit/a167a54021c979a1ca761674d8e368d5fb7dda6a) test: fix CLI nodes discovery without provisioner data\n* [`916a30682`](https://github.com/siderolabs/talos/commit/916a306829190c8eccbb993cfc166aa3cf08042e) docs: add twitter meta info\n* [`80090a3ed`](https://github.com/siderolabs/talos/commit/80090a3eda00e9808b0ba15241ea36dc6835f6d1) test: fix health endpoint cli test when discovery is disabled\n* [`3c263bb44`](https://github.com/siderolabs/talos/commit/3c263bb44639edf456d1c6203f41c71fa4d6d1d0) chore: bump dependencies\n* [`e8113527f`](https://github.com/siderolabs/talos/commit/e8113527f94f0fbc6cf6fdb9390dfb09d984213d) chore: bump kubernetes to v1.24.2\n* [`068f1b6d0`](https://github.com/siderolabs/talos/commit/068f1b6d0517f62d2a76c7b1a761f15104220644) feat: add ctest package and base for test suite\n* [`2aad3a1e4`](https://github.com/siderolabs/talos/commit/2aad3a1e4911ebcd3eb970f09baa74e10383a959) chore: bump kernel to 5.15.48\n* [`a31a858e0`](https://github.com/siderolabs/talos/commit/a31a858e08a7e022dc26c729ef097b6ed56a83ad) docs: snippets for logging api server audit logs\n* [`89aaaef9f`](https://github.com/siderolabs/talos/commit/89aaaef9f5dd403919535fc3e81ef635d233c0da) chore: bump kernel to 5.15.47\n* [`6759fcd4a`](https://github.com/siderolabs/talos/commit/6759fcd4aeeca74e78e346b4265e86580991d800) feat: use discovery service on cluster health checks\n* [`f54d90787`](https://github.com/siderolabs/talos/commit/f54d9078719a62bcefcab367957f166e7a43decc) fix: enable orderly poweroff in hyper-v on Azure\n* [`35475ce45`](https://github.com/siderolabs/talos/commit/35475ce45b1ad64bb34149be9960f5acdd2bfe86) docs: openebs jiva example with iscsi-tools extension\n* [`8d2be5e31`](https://github.com/siderolabs/talos/commit/8d2be5e315fb05002587570d759322c9c00ad525) feat: extend node definition used in health checks\n* [`7a11b4def`](https://github.com/siderolabs/talos/commit/7a11b4def78e5b4506611fe85d083a12b695bd05) fix: make `talosctl bootstrap` accept only single node\n* [`217fba288`](https://github.com/siderolabs/talos/commit/217fba288f07ccf7053e804c226a2e0b9301f864) test: fix csi tests\n* [`90bf34fed`](https://github.com/siderolabs/talos/commit/90bf34fed98cb9ff524097da4043d4ff221a0b20) docs: fork docs for Talos 1.2\n* [`a0dd010a8`](https://github.com/siderolabs/talos/commit/a0dd010a87b0ef0350299db3944f3a941fca09b4) docs: add link to discovery service in kubespan\n* [`c0371410e`](https://github.com/siderolabs/talos/commit/c0371410ee93f9773938b5b73be6eba246fd8f47) fix: support SideroLink \"secure\" gRPC connection\n* [`b03709620`](https://github.com/siderolabs/talos/commit/b03709620201b44f6464a7df804e2003c9751a30) feat: build Talos images with system extensions included\n* [`43def7490`](https://github.com/siderolabs/talos/commit/43def7490ffa598ba973f35903eaea462db374b1) chore: bump kernel and runc\n* [`4dbbf4ac5`](https://github.com/siderolabs/talos/commit/4dbbf4ac50f6b1ccd62efb1c06c8a92d8f91e65c) chore: add generic methods and use them part #2\n* [`7114292b6`](https://github.com/siderolabs/talos/commit/7114292b6cd5f93a51b905db6377ffdadf429f19) docs: fix latest release version in docs\n* [`da2985fe1`](https://github.com/siderolabs/talos/commit/da2985fe1b29abac46b761a5ec2f4557d12ce985) fix: respect local API server port\n* [`e03266667`](https://github.com/siderolabs/talos/commit/e03266667f11d751f16a7208e774996ebadf8842) fix: correctly validate reboot mode in CLI\n* [`70fc42409`](https://github.com/siderolabs/talos/commit/70fc42409980a1a78b98a962284460ea18c42513) chore: add generic methods and use them\n* [`3ae8bdd92`](https://github.com/siderolabs/talos/commit/3ae8bdd92e43c8a5fedd455d4479678ccb263a6b) chore: run `xfs_repair` on xfs filesystem returing `EUCLEAN`\n* [`0c91c89f4`](https://github.com/siderolabs/talos/commit/0c91c89f4f0732147f5b6c41fb4f3da8437ae9f1) chore: revert day-two tests for csi tests\n* [`f71b58312`](https://github.com/siderolabs/talos/commit/f71b58312251ec2924607fb5166afa6c8aaf01bb) feat: disallow anonymous requests by default (kube-apiserver)\n* [`c19dd1b89`](https://github.com/siderolabs/talos/commit/c19dd1b8925fc8ec25a721d336ad0b363fc27fd4) feat: add 'etcd members should be control plane nodes' health check\n* [`f2997c0f2`](https://github.com/siderolabs/talos/commit/f2997c0f22b93382bfb61ff556961de56445807f) chore: bump dependencies\n* [`f3efec4b5`](https://github.com/siderolabs/talos/commit/f3efec4b56bc72dc5c769a76f6254d14d3f20b1b) feat: update containerd 1.6.6, Linux 5.15.45, Flannel 0.18.1\n* [`27f8e50ce`](https://github.com/siderolabs/talos/commit/27f8e50ce90c47f5ddc82645e0ebcdb1a8ed778b) fix: add ovmf image path for rhel\n* [`87e7de30c`](https://github.com/siderolabs/talos/commit/87e7de30cb6ed02991cb46e25d20343555cc6317) docs: fix required ports\n* [`c126f2ee8`](https://github.com/siderolabs/talos/commit/c126f2ee85572bdfde61f9a3ba878f0595c74cfe) chore: bump golang to 1.18.3\n* [`c1aed6240`](https://github.com/siderolabs/talos/commit/c1aed62405dddb2cbd2d47d699aae0c94df70886) fix: wait for `/var` to be mounted in kubelet service controller\n* [`d7a64f5d2`](https://github.com/siderolabs/talos/commit/d7a64f5d2a6ff9dccdf3bdb948684d9513912be9) fix: improve vip operator shutdown sequence\n* [`7b9dfcb85`](https://github.com/siderolabs/talos/commit/7b9dfcb852af6a48f00ddfca7337a571aa56a2b3) chore: add 'make go-mod-outdated'\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`892407f`](https://github.com/siderolabs/extras/commit/892407fd7c1a032ec4d7de5d52595ef3bcc7b484) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>18 commits</summary>\n<p>\n\n* [`4412db8`](https://github.com/siderolabs/pkgs/commit/4412db88987acf91ffc2a83c09dd0dd5d84819eb) chore: bump kernel to 5.15.51\n* [`6fedbdc`](https://github.com/siderolabs/pkgs/commit/6fedbdc826cffe5b0740c43f5641218df58e767c) chore: bump tools\n* [`f1f44e6`](https://github.com/siderolabs/pkgs/commit/f1f44e6a254e571c34f667e086e50afec099500b) chore: bump kernel to 5.15.50\n* [`388af5e`](https://github.com/siderolabs/pkgs/commit/388af5e4eea16e0b19ce58879ea9d79676b9608b) chore: bump openssl to 1.1.1p\n* [`ed75c50`](https://github.com/siderolabs/pkgs/commit/ed75c5011e29107a59ffca1bececee1d22937ba2) chore: enable `RANDOM_TRUST_BOOTLOADER` by default\n* [`7c243f6`](https://github.com/siderolabs/pkgs/commit/7c243f6da5b3c0476106ff47d37b5d7a8ad28d98) chore: bump kernel to 5.15.49\n* [`6e1269e`](https://github.com/siderolabs/pkgs/commit/6e1269e67f1e8a81cccf6ed45980595f2d6343f5) chore: bump kernel to 5.15.48\n* [`5d671a3`](https://github.com/siderolabs/pkgs/commit/5d671a3cd6ebed495022f23e0073c1f971477305) chore: bump nvidia drivers to 515.48.07\n* [`b35d835`](https://github.com/siderolabs/pkgs/commit/b35d835a1cfc3215d631f8ace3d3b1b7c83da008) chore: bump kernel to 5.15.47\n* [`6604d6b`](https://github.com/siderolabs/pkgs/commit/6604d6b0686ea36983119edd7fb70755d3a812e0) feat: hyperv arm64\n* [`c474058`](https://github.com/siderolabs/pkgs/commit/c4740588733138df9503c37304d1460166a3e233) chore: bump nvidia driver to 515.43.04\n* [`5bc7e34`](https://github.com/siderolabs/pkgs/commit/5bc7e341fa0c035bbecc999bca3811b853684c5f) feat: update runc to 1.1.3, libseccomp to 2.5.4\n* [`c02cd7a`](https://github.com/siderolabs/pkgs/commit/c02cd7a7086098698d1edd1d5ecb024ad9456a48) chore: bump kernel to 5.15.46\n* [`b9c72a5`](https://github.com/siderolabs/pkgs/commit/b9c72a59cd6077ceb0ce53f11241d294c137f68b) feat: update containerd to 1.6.6\n* [`f7786a3`](https://github.com/siderolabs/pkgs/commit/f7786a3a74bbf79c81cbcb031c357eae0e07726f) chore: bump kernel to 5.15.45\n* [`b1c207d`](https://github.com/siderolabs/pkgs/commit/b1c207d63b1cac99b90025d530c57da4f51fc652) feat: update containerd to 1.6.5\n* [`4d47830`](https://github.com/siderolabs/pkgs/commit/4d47830f86bfda0ae8cc9c89a6ca8ae3a73772cd) chore: bump golang to 1.18.3\n* [`dc21e30`](https://github.com/siderolabs/pkgs/commit/dc21e30a2f31effab56b6e32c785fd0644eb90d2) chore: bump kernel to 5.15.44\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`3df9e13`](https://github.com/siderolabs/tools/commit/3df9e13ab89600655f5371adf254d66dda36ef02) chore: bump golang to 1.18.3\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`e9df1b8`](https://github.com/talos-systems/crypto/commit/e9df1b8ca74c6efdc7f72191e5d2613830162fd5) feat: add support for generating keys from RSA-SHA256 CAs\n</p>\n</details>\n\n### Changes from talos-systems/grpc-proxy\n<details><summary>1 commit</summary>\n<p>\n\n* [`6dfa2cc`](https://github.com/talos-systems/grpc-proxy/commit/6dfa2cc80b6195844cae2dc2b2bc0b9b62246d8d) fix: ignore errors on duplicate `SetHeader` calls\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**          v1.6.1 -> v1.7.0\n* **github.com/aws/aws-sdk-go**            v1.44.24 -> v1.44.42\n* **github.com/containerd/containerd**     v1.6.4 -> v1.6.6\n* **github.com/containernetworking/cni**   v1.1.0 -> v1.1.1\n* **github.com/cosi-project/runtime**      95d06feaf8b5 -> ee09cee2aab7\n* **github.com/docker/docker**             v20.10.16 -> v20.10.17\n* **github.com/emicklei/dot**              v0.16.0 -> v1.0.0\n* **github.com/google/nftables**           a9775fb167d2 -> a346d51f53b3\n* **github.com/hashicorp/go-getter**       v1.6.1 -> v1.6.2\n* **github.com/hetznercloud/hcloud-go**    v1.33.2 -> v1.34.0\n* **github.com/packethost/packngo**        v0.24.0 -> v0.25.0\n* **github.com/rivo/tview**                9994674d60a8 -> 691f46d6f500\n* **github.com/siderolabs/extras**         v1.1.0-1-g5800284 -> v1.2.0-alpha.0\n* **github.com/siderolabs/pkgs**           v1.1.0-8-gfa9a488 -> v1.2.0-alpha.0-17-g4412db8\n* **github.com/siderolabs/tools**          v1.1.0-1-g134974c -> v1.2.0-alpha.0\n* **github.com/spf13/cobra**               v1.4.0 -> v1.5.0\n* **github.com/stretchr/testify**          v1.7.1 -> v1.7.5\n* **github.com/talos-systems/crypto**      v0.3.5 -> e9df1b8ca74c\n* **github.com/talos-systems/grpc-proxy**  v0.3.0 -> v0.3.1\n* **github.com/vishvananda/netlink**       v1.2.0-beta -> v1.2.1-beta.2\n* **github.com/vmware-tanzu/sonobuoy**     v0.56.6 -> v0.56.7\n* **golang.org/x/net**                     5463443f8c37 -> 1bab6f366d9e\n* **golang.org/x/sync**                    0976fa681c29 -> 0de741cfad7f\n* **golang.org/x/sys**                     bc2c85ada10a -> 87e55d714810\n* **golang.org/x/time**                    583f2d630306 -> 579cf78fd858\n* **google.golang.org/grpc**               v1.46.2 -> v1.47.0\n* **gopkg.in/yaml.v3**                     496545a6307b -> v3.0.1\n* **inet.af/netaddr**                      c74959edd3b6 -> 097006376321\n\nPrevious release can be found at [v1.1.0](https://github.com/siderolabs/talos/releases/tag/v1.1.0)\n\n## [Talos 1.1.0-alpha.2](https://github.com/siderolabs/talos/releases/tag/v1.1.0-alpha.2) (2022-05-12)\n\nWelcome to the v1.1.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Apply Config `--dry-run`\n\nThe commands `talosctl apply-config`, `talosctl patch mc` and `talosctl edit mc` now support `--dry-run` flag.\nIf enabled it just prints out the selected config application mode and the configuration diff.\n\n\n### Apply Config `--mode=try`\n\nThe commands `talosctl apply-config`, `talosctl patch mc` and `talosctl edit mc` now support the new mode called `try`.\nIn this mode the config change is applied for a period of time and then reverted back to the state it was before the change.\n`--timeout` parameter can be used to customize the config rollback timeout.\nThis new mode can be used only with the parts of the config that can be changed without a reboot and can help to check that\nthe new configuration doesn't break the node.\nCan be especially useful to check network interfaces changes that may lead to the loss of connectivity to the node.\n\n\n### IPv6 in Docker-based Talos Clusters\n\nThe command `talosctl cluster create` now enables IPv6 by default for the Docker containers\ncreated for Talos nodes. This allows to use IPv6 addresses in Kubernetes networking.\n\nIf `talosctl cluster create` fails to work on Linux due to the lack of IPv6 support,\nplease use the flag `--disable-docker-ipv6` to revert the change.\n\n\n### drop some default rules shipped by eudev\n\nDrops some default eudev rules that doesn't make sense in the context of Talos OS.\nEspecially the ones around sound devices, cd-roms and renaming the network interfaces to be predictable\n\n\n### Pod Security Admission\n\n[Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) controller is enabled by default with the following policy:\n\n```yaml\napiVersion: apiserver.config.k8s.io/v1\nkind: AdmissionConfiguration\nplugins:\n- configuration:\n    apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n    defaults:\n      audit: restricted\n      audit-version: latest\n      enforce: baseline\n      enforce-version: latest\n      warn: restricted\n      warn-version: latest\n    exemptions:\n      namespaces:\n      - kube-system\n      runtimeClasses: []\n      usernames: []\n    kind: PodSecurityConfiguration\n  name: PodSecurity\n  path: \"\"\n```\n\nThe policy is part of the Talos machine configuration, and it can be modified to suite your needs.\n\n\n### Support RockPi 4 variants A and B\n\nTalos now supports RockPi variants A and B in addition to RockPi 4C\n\n\n### Raspberry Pi PoE hat fan\n\nTalos now enables the Raspberry Pi PoE fan control by pulling in the poe overlay that works with upstream kernel\n\n\n### Component Updates\n\n* Linux: 5.15.39\n* Containerd: v1.6.4\n* Kubernetes: 1.24.0\n* Flannel: 0.17.0\n* runc: 1.1.2\n* CoreDNS: v1.9.2\n\nTalos is built with Go 1.18.2\n\n\n### x86-64 Architecture\n\nTalos is built for x86-64 architecture with support for [x86-64-v2 microarchitecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels),\nso Talos no longer runs on processors supporting only baseline `x86-64` microarchitecture (before 2009).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Tim Jones\n* Dmitriy Matrenichev\n* Spencer Smith\n* Artem Chernyshev\n* Andrew Rynhard\n* Serge Logvinov\n* Steve Francis\n* Philipp Sauter\n* Steve Francis\n* Andrei Dobre\n* Bastiaan Schaap\n* Caleb Woodbine\n* Daniel Höxtermann\n* Jori Huisman\n* Jorik Jonker\n* Nico Berlee\n* Philipp Sauter\n* Sebastian Hasler\n* Seán C McCord\n* Suraj Shirvankar\n* Tames McTigue\n* Tim Jones\n* Tomasz Zurkowski\n* William Ashton\n\n### Changes\n<details><summary>211 commits</summary>\n<p>\n\n* [`91a49c4e7`](https://github.com/siderolabs/talos/commit/91a49c4e7c0495794a991ab7742cd06339ce072d) fix: dhcpv6 leasetime segfault loop\n* [`afb679586`](https://github.com/siderolabs/talos/commit/afb679586a7319746e59071b6ce0b85df0d77f48) fix: reset certificate SANs on update\n* [`c87432fe1`](https://github.com/siderolabs/talos/commit/c87432fe1feab8a157c858cf04aefe40c9f84895) fix: detect WSL for `talosctl cluster create` on Docker\n* [`166d2585c`](https://github.com/siderolabs/talos/commit/166d2585c6d94791d8a3392fc597cd9c489c1958) chore: bump kernel and runc\n* [`8d9b0cde0`](https://github.com/siderolabs/talos/commit/8d9b0cde0ab51f16421e3db23d301349626b49d8) chore: update deps to go 1.18.2\n* [`86741d998`](https://github.com/siderolabs/talos/commit/86741d99845ab36218417bd1e00f446bfe71b922) fix: append hostname to cluster SANs when port is not specified\n* [`9885bbe17`](https://github.com/siderolabs/talos/commit/9885bbe17762af22d704b6c4e33ef99032e85956) docs: fix typos, edited for clarity\n* [`7fd1c80c3`](https://github.com/siderolabs/talos/commit/7fd1c80c3ee2ea33fe1aeb2e6cb21a3d0bc98537) fix: ignore failures to dial wireguard client\n* [`b8e7cdb70`](https://github.com/siderolabs/talos/commit/b8e7cdb7012c89f980dc4c2ac29d6a503c55206a) docs: add vultr guide\n* [`c2be65b66`](https://github.com/siderolabs/talos/commit/c2be65b6684b208a8ac2e1b598e005b72dd24b8f) fix: openstack unable to parseIP\n* [`2ae0e3a56`](https://github.com/siderolabs/talos/commit/2ae0e3a56971ece0be47b741ddbf5f652b7244f1) test: add a test for version of Go Talos was built with\n* [`bef1a13fa`](https://github.com/siderolabs/talos/commit/bef1a13fa2968dd483a45d766ca7fe1de5aedace) docs: update latest Talos in 1.0 docs to 1.0.4\n* [`b52962c44`](https://github.com/siderolabs/talos/commit/b52962c44075a34399a4ceb0210b733df812775f) chore: bump dependencies\n* [`79ae76a6f`](https://github.com/siderolabs/talos/commit/79ae76a6f220683b318e2df6af7326e20c255a79) fix: properly set `allowSchedulingOnMasters` in the interactive install\n* [`2b7e7d4dc`](https://github.com/siderolabs/talos/commit/2b7e7d4dc49189dd18b1bb5646a1c621d27d82df) feat: print the status of services during boot\n* [`802d4a23c`](https://github.com/siderolabs/talos/commit/802d4a23c9c6634686136eb80bf86336c5dc6084) fix: load kubelet system service in StartAllServices task\n* [`67019c434`](https://github.com/siderolabs/talos/commit/67019c434b7e4b20f4986433340bc626b30d16bc) fix: add source path for ovmf flash image\n* [`da7b24ba5`](https://github.com/siderolabs/talos/commit/da7b24ba57fcfb589bb34f1947b3744c9953bb6b) chore: bump kernel to 5.15.38\n* [`8ca8effd6`](https://github.com/siderolabs/talos/commit/8ca8effd6165fb39120c6b30266f0b4ee3b06bfd) chore: add Equinix Managed Services NL to adopters\n* [`8bc97a30f`](https://github.com/siderolabs/talos/commit/8bc97a30f239ed5b2bbb24e620ffa7bd31a0ebf9) fix: remove D-Bus sockets before listen attempts\n* [`54cfa039a`](https://github.com/siderolabs/talos/commit/54cfa039ab8196b3d8eec9b69aa723ad90e3054b) fix: use json.Unmarshal instead of yaml.Unmarshal\n* [`6d30c4822`](https://github.com/siderolabs/talos/commit/6d30c48223022a369556e5a678a78bbab2316e67) docs: update networking resource documentation\n* [`bc88de729`](https://github.com/siderolabs/talos/commit/bc88de729c69683ac74e3312b154a722b2100a44) chore: bump coredns to v1.9.2\n* [`c6722b637`](https://github.com/siderolabs/talos/commit/c6722b637b2f39ecc83f32a1f61a6591d6a2aff6) docs: when mentioning partitions, link to partition docs\n* [`b189e8426`](https://github.com/siderolabs/talos/commit/b189e84269bdc14b041d7f225545b7c9ee948dbc) chore: fix incorrect ManifestSpec.MarshalYAML signature\n* [`5d5280200`](https://github.com/siderolabs/talos/commit/5d52802001d4fef74fe2d47e436bfd52dda7617b) feat: add more hardware information to the link status resources\n* [`2ff6db749`](https://github.com/siderolabs/talos/commit/2ff6db749af4d38959f0adc113e1d406234b05ea) chore: add Nedap Security Atlas as adopter\n* [`89cab200b`](https://github.com/siderolabs/talos/commit/89cab200b8515a6bbc62659164da61e8913860b1) chore: bump kubernetes to v1.24.0\n* [`09d16349f`](https://github.com/siderolabs/talos/commit/09d16349f4e10dfe2f32eaaa824ecf7b9e078074) chore: refactor StaticPod and StaticPodStatus into typed.Resource\n* [`d2935f98c`](https://github.com/siderolabs/talos/commit/d2935f98c4f9ae99bc8e1c0f63a4b0825a2678f6) chore: refactor LinkRefresh and LinkStatus into typed.Resource\n* [`b52e0b9b9`](https://github.com/siderolabs/talos/commit/b52e0b9b9ecb84a7b73771a80f3425af4814ada0) fix: talosctl throws error if gen option and --input-dir flags are combined\n* [`0e15de3a8`](https://github.com/siderolabs/talos/commit/0e15de3a8a4057866e5e51c99936fad1c629098f) docs: add adopters file\n* [`bb932c297`](https://github.com/siderolabs/talos/commit/bb932c29706c1eb77088d734c65857cd63035031) chore: bump containerd to v1.6.4\n* [`4eaaa2d59`](https://github.com/siderolabs/talos/commit/4eaaa2d597d12d8ec4fa265499790d0891beac42) chore: bump kernel to 5.15.37\n* [`89dde8f2c`](https://github.com/siderolabs/talos/commit/89dde8f2c426e2eb53de507b69f48bb8b6b5b7fe) chore: refactor remaining resources into typed.Resource\n* [`bd089e702`](https://github.com/siderolabs/talos/commit/bd089e702d247b2ee5f31bde542cf407e155e10b) chore: bump dependencies\n* [`3136334b9`](https://github.com/siderolabs/talos/commit/3136334b935e37e4a2f11bd4c02f89aee4806ddb) docs: fix links in VMware documentation\n* [`403df0e18`](https://github.com/siderolabs/talos/commit/403df0e1802186c409eb8cc255ca1233898a5eda) docs: provide example on using config generation package\n* [`635192861`](https://github.com/siderolabs/talos/commit/63519286110e75adc03edb89b4dc9cb432b15d46) chore: redo pointer with github.com/siderolabs/go-pointer module\n* [`a269f740c`](https://github.com/siderolabs/talos/commit/a269f740ce323b21e532b24aa327b1f4b4b1e951) docs: copy knowledge base to v1.0 docs\n* [`483201026`](https://github.com/siderolabs/talos/commit/48320102630a6a551aaa05202181daad62757180) fix: return an error if there is no byte slice in ReadonlyProvider\n* [`6e7486f09`](https://github.com/siderolabs/talos/commit/6e7486f099026724c21a73a4d4ff40134ac864b1) fix: allow graceful node shutdown to be overridden\n* [`867d38f28`](https://github.com/siderolabs/talos/commit/867d38f28f3b65b373206528d18360b714331cec) feat: add bond slaves ordering\n* [`03ef62ad8`](https://github.com/siderolabs/talos/commit/03ef62ad8bf10eccacbd490ebbcaceb0794f5378) fix: include Go primitive types into unstructured deepcopy\n* [`f06e6acf2`](https://github.com/siderolabs/talos/commit/f06e6acf2f76c48a59654e53503ae82eb9a6532c) chore: bump kernel to 5.15.36\n* [`c0d386abb`](https://github.com/siderolabs/talos/commit/c0d386abb6e427fa0da5ab416a9a3caf9ab1f1d6) fix: don't mount D-Bus socket via mount under recursive bind mount\n* [`9a8ff76df`](https://github.com/siderolabs/talos/commit/9a8ff76df2fa7366ccdeb597226285a77528442e) refactor: rewrite perf resource to use typed.Resource\n* [`71d04c4d5`](https://github.com/siderolabs/talos/commit/71d04c4d5cbaeadfc86b6eb5164f7f8026a9b66a) refactor: rewrite runtime resources to use typed.Resource\n* [`7568d51fc`](https://github.com/siderolabs/talos/commit/7568d51fc8e40c57cef3d86c77a662508ee3f0cd) fix: trigger CRI config merge on correct resource update\n* [`c456dbcb9`](https://github.com/siderolabs/talos/commit/c456dbcb934533e3026246635911ce44045dfb17) docs: remove references to init nodes\n* [`1973095d1`](https://github.com/siderolabs/talos/commit/1973095d146a9b10408f972904a06ed555524bd2) feat: update containerd to 1.6.3\n* [`b51292d88`](https://github.com/siderolabs/talos/commit/b51292d884b420b30cd5eb8eba29286f72681b72) docs: reformat config reference\n* [`c0709d970`](https://github.com/siderolabs/talos/commit/c0709d97078f6574be3b6413a1513d91adeea26e) feat: increase aio-max-nr and inotify.max_user_instances\n* [`85b328e99`](https://github.com/siderolabs/talos/commit/85b328e99719e549346a39ffc4a782e993dc7696) refactor: convert secrets resources to use typed.Resource\n* [`e91350acd`](https://github.com/siderolabs/talos/commit/e91350acd727581478b852f171b69a67b4322999) refactor: convert time & v1alpha1 resources to use typed.Resource\n* [`45464412e`](https://github.com/siderolabs/talos/commit/45464412e0526195c3a7f3e447f8f5bee108407d) chore: bump dependencies\n* [`0af6b35a6`](https://github.com/siderolabs/talos/commit/0af6b35a66ae4145d678796d6b7fea2cf77ea9de) feat: update etcd to 3.5.4\n* [`7ad27751c`](https://github.com/siderolabs/talos/commit/7ad27751cbd2a44290b7c5fa708129df5a912375) docs: fix analytics and sitemap\n* [`55ff876dc`](https://github.com/siderolabs/talos/commit/55ff876dc649f102cb6608efa6fb738d9ea69bba) chore: bump K8s Go modules to 1.24.0-rc.0\n* [`f1f43131f`](https://github.com/siderolabs/talos/commit/f1f43131f8f1070240fc32cc96a7b1ccf78e3f76) fix: strip 'v' prefix from versions on Kubernetes upgrade\n* [`ec621477b`](https://github.com/siderolabs/talos/commit/ec621477bd089d1672bf5ea94378ffa397bee227) chore: tune QEMU disk provisioner options\n* [`b085343dc`](https://github.com/siderolabs/talos/commit/b085343dcb0bff77eb03a9754843b68c8f2f90af) feat: use discovery information for etcd join (and other etcd calls)\n* [`2b03057b9`](https://github.com/siderolabs/talos/commit/2b03057b91928f550e22b96885878c2369379e98) feat: implement a new mode `try` in the config manipulation commands\n* [`51a68c31f`](https://github.com/siderolabs/talos/commit/51a68c31ff6d9bb4dc96500c158ea9968680703a) chore: allow mounting files from the host\n* [`f3e330a0a`](https://github.com/siderolabs/talos/commit/f3e330a0aaf4611cd1ffc1d2abd90487132e16e9) docs: fix network dependency\n* [`7ba39bd60`](https://github.com/siderolabs/talos/commit/7ba39bd60052eb41f718d920fa916e5c9b80a036) docs: clarify discovery service\n* [`8057d076a`](https://github.com/siderolabs/talos/commit/8057d076ada80a19d26a7cd0d678c18ad14dab31) release(v1.1.0-alpha.1): prepare release\n* [`1d5c08e74`](https://github.com/siderolabs/talos/commit/1d5c08e74f2c9009ff2b3103157eb105e2a32254) chore: bump kernel to 5.15.35\n* [`9bf23e516`](https://github.com/siderolabs/talos/commit/9bf23e5162bded75a8c52009a360de1a43060858) feat: update Kubernetes to 1.24.0-rc.0\n* [`d78ed320b`](https://github.com/siderolabs/talos/commit/d78ed320b7c9853d5c118223f2289db153ea8145) docs: fix the docs reference to star registry redirects\n* [`257dfb870`](https://github.com/siderolabs/talos/commit/257dfb870933321175f859348539de6d26161618) fix: run the 'post' stage of the service always\n* [`992e23023`](https://github.com/siderolabs/talos/commit/992e2302346fb4e34a23d28f4c3a67564ddbb241) fix: correctly handle stopping services with reverse dependencies\n* [`bb7a50bd5`](https://github.com/siderolabs/talos/commit/bb7a50bd5b31d28cef6a250a056f81c2e1eace80) docs: fix netlify redirects\n* [`486f79bc7`](https://github.com/siderolabs/talos/commit/486f79bc775564f9fdd2a114b86b70d55324d18a) docs: fix netlify deploy url\n* [`e8cbedb05`](https://github.com/siderolabs/talos/commit/e8cbedb05bb19bdea339a806576215ae71eee4d8) docs: add canonical link ref\n* [`0fe4a7832`](https://github.com/siderolabs/talos/commit/0fe4a7832b1327e68d2829ae27078780434f00b3) docs: improve latest-version banner\n* [`23984efcd`](https://github.com/siderolabs/talos/commit/23984efcdf6ae530301c885c6105aa18d790d9b6) fix: detect lingering mounts in the installer correctly\n* [`54dba925f`](https://github.com/siderolabs/talos/commit/54dba925f88881f41246a9198955ac6ce95d81d9) chore: refactor network resource to use typed resource\n* [`4eb9f45cc`](https://github.com/siderolabs/talos/commit/4eb9f45cc82669ac31ffc17bc53a5be05563823e) refactor: split polymorphic K8sControlPlane into typed resources\n* [`68dfdd331`](https://github.com/siderolabs/talos/commit/68dfdd3311c602faaeb5e5f7970c0e7d13a32600) fix: provide logger to the etcd snapshot restore\n* [`f190403f0`](https://github.com/siderolabs/talos/commit/f190403f01118c7f60d5e97a4c2349c638ed7e0b) docs: add how to get config after interactive setup\n* [`fac7b9466`](https://github.com/siderolabs/talos/commit/fac7b94667bb9aae680677b5e3e936f107315062) docs: improve vip caveats documentation\n* [`250df9e67`](https://github.com/siderolabs/talos/commit/250df9e670c8e4221fa376791b88ee03fa2022ae) docs: improve rook-ceph description\n* [`b5c1d868d`](https://github.com/siderolabs/talos/commit/b5c1d868deac9fd8d124cda35693b4f12372589f) docs: add talos/kubernetes config faq\n* [`39721ee93`](https://github.com/siderolabs/talos/commit/39721ee9392ed43da572c71eb056a8a4b1a795fd) chore: bump dependencies\n* [`610945774`](https://github.com/siderolabs/talos/commit/610945774a8f9cf849ddfefda0e4d456bb8ba2c3) chore: bump tools and pkgs\n* [`2b68c8b67`](https://github.com/siderolabs/talos/commit/2b68c8b67bf1ea88d471b8baa405a65fcd1aa40f) fix: enable long timestamps for xfs\n* [`be00d7749`](https://github.com/siderolabs/talos/commit/be00d774921b28ebc9b81727a6e4cf29a06385ee) chore: implement cluster resources using cosi typed resource\n* [`460d5ab13`](https://github.com/siderolabs/talos/commit/460d5ab13f007a89e72013c443132a845dcc3a09) docs: fix extension services alias\n* [`bbdfda2dd`](https://github.com/siderolabs/talos/commit/bbdfda2dd2e72f1fd5981dd6fc589d90cd692b72) chore: xfs quota support in kernel\n* [`8ff8fc77f`](https://github.com/siderolabs/talos/commit/8ff8fc77f3b14679daa31067528f6bcf62e9aca9) chore: enable rpi4 poe hat fan control\n* [`2b9722d1f`](https://github.com/siderolabs/talos/commit/2b9722d1f5fac39390fde8223d40262af80b1ef2) feat: add `dry-run` flag in `apply-config` and `edit` commands\n* [`8af50fcd2`](https://github.com/siderolabs/talos/commit/8af50fcd27bed2a437d6d9668233657a47bd9798) fix: correct cri package import path\n* [`ce09ede83`](https://github.com/siderolabs/talos/commit/ce09ede839e7500df1dd862f8c2726b02798b725) feat: update etcd to 3.5.3\n* [`13f41badd`](https://github.com/siderolabs/talos/commit/13f41baddff997dfa15c773d8f078bd0921fb40b) chore: bump kernel to 5.15.34\n* [`fa57b5d92`](https://github.com/siderolabs/talos/commit/fa57b5d9225d3075b08a9d07ce29480a4c050143) docs: reorganize documentation\n* [`a91eb9358`](https://github.com/siderolabs/talos/commit/a91eb9358dfc49e2afc1523f804c0f01660cfb1f) chore: bump deps\n* [`0aad0df2e`](https://github.com/siderolabs/talos/commit/0aad0df2eb6a8727dfff253619a9b2cb1915d9be) refactor: remove `String()` for resource implementation\n* [`a4060513c`](https://github.com/siderolabs/talos/commit/a4060513c694f2d45be95a060e4bb719840d8739) feat: build Talos with support for x86-64-v2 microarchitecture\n* [`8faebd410`](https://github.com/siderolabs/talos/commit/8faebd410be9653808f50df698345ee613be6e68) chore: bump tools and pkgs\n* [`8499b7e7d`](https://github.com/siderolabs/talos/commit/8499b7e7dcbd5fbcb9aa94a8028a73168a304a06) chore: bump dependencies\n* [`a7ba7ea67`](https://github.com/siderolabs/talos/commit/a7ba7ea679f10e99b31ee3b4b6c92265d43c12df) feat: migrate to go 1.18\n* [`9dace93b5`](https://github.com/siderolabs/talos/commit/9dace93b59e8e1e1d8a7595fda82dc85b9c835cf) feat: enable Pod Security Admission by default\n* [`c382cb8cd`](https://github.com/siderolabs/talos/commit/c382cb8cd26f2eaece665bcb471f27d188ea1ad5) docs: update vmware docs\n* [`da0e638f0`](https://github.com/siderolabs/talos/commit/da0e638f04cfab1ed93891231035439ad77666d1) docs: stableize tools versioning\n* [`f2d2267e7`](https://github.com/siderolabs/talos/commit/f2d2267e749a14b8a060e56f274f603415d69731) docs: use template for netlify redirects\n* [`88f1d8fcc`](https://github.com/siderolabs/talos/commit/88f1d8fcc0e3bd28a9db4677ad9d782c80ffdbb9) docs: update sitemap to point to direct url\n* [`a6eebee36`](https://github.com/siderolabs/talos/commit/a6eebee36f9a3f6fbde441ccb5e170dae9727a58) chore: update eudev\n* [`0cb84e8c1`](https://github.com/siderolabs/talos/commit/0cb84e8c1a09c5b391461aa17c277a0a7803f725) fix: correctly parse tags out of images\n* [`17d09739f`](https://github.com/siderolabs/talos/commit/17d09739f3fe8cb942008a44f902b65705e39575) docs: enable nested arrow\n* [`1e4320b64`](https://github.com/siderolabs/talos/commit/1e4320b64e2477a55f808c6b8720b0779088d0f8) chore: add support for rockpi 4A and 4B\n* [`d1869d948`](https://github.com/siderolabs/talos/commit/d1869d948c84cf7191819eddac9c2aa27b365eb9) docs: update to Sidero Metal, mention clusterctl\n* [`18d0038ec`](https://github.com/siderolabs/talos/commit/18d0038ecaa2cf43164f72f3acad5445e395b37e) fix: avoid panic in DHCPv6 operator on nil dereference\n* [`9e3d438db`](https://github.com/siderolabs/talos/commit/9e3d438db461529abf3dfa6ef750b4fa4a9125ec) docs: fix code fence formatting\n* [`b3f1bb2cf`](https://github.com/siderolabs/talos/commit/b3f1bb2cff544a35f767b32ca8ca1d13b83c535e) fix: add support for FAT12/16 filesystems\n* [`8619f95c5`](https://github.com/siderolabs/talos/commit/8619f95c5c7779815a87118cbb0a1e493251355d) chore: bump dependencies\n* [`8c4f72004`](https://github.com/siderolabs/talos/commit/8c4f720048c0187b203ca869befd759249bac79f) docs: override sitemap.xml to only include latest results\n* [`5192ba4e2`](https://github.com/siderolabs/talos/commit/5192ba4e2314c05e107adcc0a2a71a65ec35bfc3) docs: fix a typo in QEMU VM setup guide\n* [`663e3e879`](https://github.com/siderolabs/talos/commit/663e3e8796c3f501275fdd7836687b811318b685) refactor: change the stages for embed files generation\n* [`19bf12af0`](https://github.com/siderolabs/talos/commit/19bf12af07aaf6b54d08027676d8a01b4dd4ed29) fix: enable IPv6 in Docker-based Talos clusters\n* [`3889a5839`](https://github.com/siderolabs/talos/commit/3889a583970c73ea4c6089b1fe8438b183ec756e) docs: update config.yaml, storage.md, digital-rebar.md\n* [`25d19131d`](https://github.com/siderolabs/talos/commit/25d19131d378960603a510cb70b35352b07bf7cb) release(v1.1.0-alpha.0): prepare release\n* [`2ca5279e5`](https://github.com/siderolabs/talos/commit/2ca5279e56d154fdf21fab7ed5c73edb30494560) fix: retry manifest updates in upgrade-k8s\n* [`eeb756168`](https://github.com/siderolabs/talos/commit/eeb756168f31c8e7a1e0cb2f80e1ae2bc2eed0a9) feat: use kexec when resetting a node\n* [`1ed1f73e5`](https://github.com/siderolabs/talos/commit/1ed1f73e511f4a5cf4d1db5f97422cf1eb088fda) test: bump CAPI to 1.1.3\n* [`2ee1d2c72`](https://github.com/siderolabs/talos/commit/2ee1d2c72085df41ec0355bac0d33bedcb4f2786) feat: update Kuberentes to 1.24.0-beta.0\n* [`c26fa4ccc`](https://github.com/siderolabs/talos/commit/c26fa4ccc1e109c889c01384422f88387ad512a2) test: push GITHUB_TOKEN to the e2e-aws/gcp steps\n* [`95d900de7`](https://github.com/siderolabs/talos/commit/95d900de7799cfa9d0a16049586ba246bddb09d0) feat: use kubeconfig env var\n* [`0b407dd17`](https://github.com/siderolabs/talos/commit/0b407dd17e9515fecd8083fd5ac1fc84f6085106) feat: add dhcp-v6 NTP/DHCP-DUID\n* [`a140a6bad`](https://github.com/siderolabs/talos/commit/a140a6bad74bcf34e62e13b6efa63a17741eb5b1) docs: update releases shortcode in upgrade guide\n* [`12931dced`](https://github.com/siderolabs/talos/commit/12931dcedd38c407a2a03f692d910853130986db) fix: align partitions on 1M boundary\n* [`37f868e37`](https://github.com/siderolabs/talos/commit/37f868e37454f63a4dfe38d94dbbeef5bb40a2a8) fix: validate empty TLS config for registries\n* [`ca8b9c0a3`](https://github.com/siderolabs/talos/commit/ca8b9c0a3a15898d9562a6f22aded138d6c3ed7f) feat: update Kubernetes to 1.24.0-alpha.4\n* [`d9ec6b215`](https://github.com/siderolabs/talos/commit/d9ec6b2151e94c94eea44771e455555eaf1f257a) chore: drop dirty from abbreviated tag\n* [`08624fd0b`](https://github.com/siderolabs/talos/commit/08624fd0b12039e5a77ce43f14df65a6c95f7a39) docs: add banner to main page\n* [`fc23c7a59`](https://github.com/siderolabs/talos/commit/fc23c7a5952d87a51f29d61ead585bf060eeab1c) test: bump versions for upgrade tests\n* [`4bfe68610`](https://github.com/siderolabs/talos/commit/4bfe686105d5734b282f4817673972b71954e620) feat: update runc to 1.1.1\n* [`b315ed953`](https://github.com/siderolabs/talos/commit/b315ed95327a9b7cfb1f83a9da02e96bafecbb1d) chore: use go:embed instead of ldflags\n* [`a5d64fc81`](https://github.com/siderolabs/talos/commit/a5d64fc814f122fb7e282b97283a46ac0e5d6709) feat: update Flannel to 0.17.0\n* [`6d6eb3f6a`](https://github.com/siderolabs/talos/commit/6d6eb3f6a52626c8c94a75439133e7bc22b25e60) docs: fork docs for 1.1\n* [`1d55f05d1`](https://github.com/siderolabs/talos/commit/1d55f05d11e5a03a8de0e7ce5ec0167971b03135) docs: update index page\n* [`ad6b7ec1a`](https://github.com/siderolabs/talos/commit/ad6b7ec1a4347753488de3ab5813947f01967078) fix: enable etcd consistency on check startup\n* [`65a31f753`](https://github.com/siderolabs/talos/commit/65a31f7531a629b29fbf86ddcbaba20767475924) docs: re-add GA token\n* [`741c04832`](https://github.com/siderolabs/talos/commit/741c048320b931228336034ad17de10272ff5a77) docs: mark 1.0 docs as latest\n* [`e97433c8a`](https://github.com/siderolabs/talos/commit/e97433c8a37ca504577355d98c917e083aaedafe) docs: update jetson nano\n* [`6665e0f00`](https://github.com/siderolabs/talos/commit/6665e0f00c1c5d45123eb28d8755d0815af4822a) docs: code block copying\n* [`c41f2b216`](https://github.com/siderolabs/talos/commit/c41f2b216717db80e44654f54080a9d462946d45) docs: update whats-new-v1.0\n* [`0a36fbbf3`](https://github.com/siderolabs/talos/commit/0a36fbbf3ca579becd0a7f2e5a9715ff4196e8ae) docs: add release notes for 1.0\n* [`bd0035f6a`](https://github.com/siderolabs/talos/commit/bd0035f6a285f8b7e4c7c0b5013a271a8d18c5f4) docs: add NVIDIA docs\n* [`efa3f2898`](https://github.com/siderolabs/talos/commit/efa3f289853a47ae0d4bca5dbf656e527cf312dd) fix: correctly find partitions with config data (`metal-iso`)\n* [`9ebeec0d0`](https://github.com/siderolabs/talos/commit/9ebeec0d0ea4dd3cc1ba3b7171fe0a9bda943fe8) docs: fix incorrect path for talosconfig\n* [`9fef4540e`](https://github.com/siderolabs/talos/commit/9fef4540e1c7a7deb5d4745d3de17c6e5cc45369) docs: fix non-latest download links\n* [`f8ef6a081`](https://github.com/siderolabs/talos/commit/f8ef6a081e055637a5652366a6e344b6df911871) docs: add rook ceph configuration guide\n* [`e2666f58f`](https://github.com/siderolabs/talos/commit/e2666f58f5835db6ff8802b2370a480d8afcd8fc) chore: bump kernel to 5.15.32\n* [`957b2f233`](https://github.com/siderolabs/talos/commit/957b2f233c4b81eacdb5a3190c0070fa36ef0d82) chore: bump dependencies\n* [`0fd2aa08b`](https://github.com/siderolabs/talos/commit/0fd2aa08bd70d1c869e0dca136ca0c487bfcdefe) fix: correctly escape '.' in volume names\n* [`108fd03a7`](https://github.com/siderolabs/talos/commit/108fd03a72534cebbab7c09d63051021483566ac) fix: give up virtual IPs before the kubelet workloads are shut down\n* [`856e1333d`](https://github.com/siderolabs/talos/commit/856e1333dcfb8c0244ca8ead415025b32a4819fc) fix: use 'localhost' endpoint in docker provisioner on Windows\n* [`c5da38609`](https://github.com/siderolabs/talos/commit/c5da386092185fe4ed4173b08f95eac4e435ff99) docs: use variables and templates in the docs\n* [`4c83847b9`](https://github.com/siderolabs/talos/commit/4c83847b9091a4e8968544a515632a3391c06cd0) docs: target search results\n* [`67fb72d96`](https://github.com/siderolabs/talos/commit/67fb72d96db1cb772392dcab9b5a3a08ee50ff03) docs: add algolia versions to all content\n* [`5344d6e7c`](https://github.com/siderolabs/talos/commit/5344d6e7ce2b7febc6109acc566cf49346eca6d9) docs: fix extension service `path` dependency\n* [`9b9191c5e`](https://github.com/siderolabs/talos/commit/9b9191c5e7a4a03bb7fa271ab49b52874e63ee31) fix: increase intiial window and connection window sizes\n* [`7a88a0224`](https://github.com/siderolabs/talos/commit/7a88a0224155755a64c911165bf25bff775e1ec2) docs: show archived/pre-release banner based on version\n* [`e403470bf`](https://github.com/siderolabs/talos/commit/e403470bfefe7af0217d91cb18d900b7046254f9) docs: filter algolia results by latest\n* [`0497d5f9f`](https://github.com/siderolabs/talos/commit/0497d5f9fee404f68d09c0c500cb446126cfc6aa) docs: tag latest docs for search\n* [`a25425483`](https://github.com/siderolabs/talos/commit/a25425483518adc5bdd575c5fb8cc1b3464444ea) feat: update containerd to 1.6.2, Linux to 5.15.31\n* [`9b6422fcc`](https://github.com/siderolabs/talos/commit/9b6422fcc39c2f4e0723c0db0b6aefe3e4fc8267) feat: update CoreDNS to 1.9.1\n* [`020856f80`](https://github.com/siderolabs/talos/commit/020856f80dd93fb47170351c083602ffd516d113) docs: remove second search bar\n* [`5f27f4c63`](https://github.com/siderolabs/talos/commit/5f27f4c6384e9bb6df4fc969c3a318ad3052cf3f) docs: update asset links\n* [`9ff42b432`](https://github.com/siderolabs/talos/commit/9ff42b43202bb59845439a88014011ff002a7770) docs: fix redirects for /docs URLs\n* [`7283efd56`](https://github.com/siderolabs/talos/commit/7283efd568d35e6d2c68aa2bc101a7af86db8c62) chore: update the talosctl CNI download url\n* [`e0eee7fcc`](https://github.com/siderolabs/talos/commit/e0eee7fcc68f03243ae3248f84d50eb278998e07) test: use clusterctl.yaml overrides after org rename\n* [`73966f51e`](https://github.com/siderolabs/talos/commit/73966f51e83b7f166e4f7fe013bfed36e9b9a15a) docs: fix extensions\n* [`f9766edb5`](https://github.com/siderolabs/talos/commit/f9766edb52d6a029d12ac5d74fdb45b6294be058) docs: remove empty doc file\n* [`e06e1473b`](https://github.com/siderolabs/talos/commit/e06e1473b02cea088499c25f48a9b5e2b75cf879) feat: update golangci-lint to 1.45.0 and gofumpt to 0.3.0\n* [`a92c614b2`](https://github.com/siderolabs/talos/commit/a92c614b2f712fb046fb40e00b37773d1390df71) docs: add enterprise link to docs header\n* [`0ae7174ba`](https://github.com/siderolabs/talos/commit/0ae7174ba3a6c1674c77cf074087a68915e3e612) docs: update search settings and redirects\n* [`883d401f9`](https://github.com/siderolabs/talos/commit/883d401f9f62229305c2e24f58a0bb0e2e4bb409) chore: rename github organization to siderolabs\n* [`d1294d014`](https://github.com/siderolabs/talos/commit/d1294d014f5bee7fc1b5dfd6865f22b22f18f5f1) chore: add day-two tests for e2e-qemu\n* [`a6240e4b6`](https://github.com/siderolabs/talos/commit/a6240e4b67060357c4250e7e5a3a7960408f7c08) feat: update Linux to 5.15.30\n* [`e3fda049f`](https://github.com/siderolabs/talos/commit/e3fda049fee62f3c5cef4ae08eaf848826a6dbed) docs: overhaul all the docs\n* [`f47750726`](https://github.com/siderolabs/talos/commit/f477507262041a24def6ac9b32fa92d276d4d4e6) fix: the etcd recovery client and tests\n* [`69e07cddc`](https://github.com/siderolabs/talos/commit/69e07cddc77d6ff2c2477ec64f860ef824132000) fix: trigger properly `udevd` on types and actions\n* [`47d0e629d`](https://github.com/siderolabs/talos/commit/47d0e629d48930f6cb02dff32469bcb34440c73c) fix: clean up custom udev rules if the config is cleared\n* [`b6691b350`](https://github.com/siderolabs/talos/commit/b6691b35085e4e614752b60441c17fe39fe15928) chore: bump dependencies\n* [`27af5d41c`](https://github.com/siderolabs/talos/commit/27af5d41c6c58f4d2fc2f5c222d9de39539de1c0) feat: pause the boot process on some failures instead of rebooting\n* [`58cb9db1e`](https://github.com/siderolabs/talos/commit/58cb9db1e2b3d8fa86c0db0cf38c9f21a843da9d) feat: allow hardlinks in the system extension images\n* [`1e982808f`](https://github.com/siderolabs/talos/commit/1e982808fbac0a7f897bafacde348c5d83db38b2) fix: ignore pod CIDRs for kubelet node IPs\n* [`5e0c80f61`](https://github.com/siderolabs/talos/commit/5e0c80f6168ac8a171e35e0c3ee53d959c2dd80d) fix: ignore connection reset errors on k8s upgrade\n* [`c156580a3`](https://github.com/siderolabs/talos/commit/c156580a386e19d020b550b8459af339f440bf3e) fix: split regular network operation configuration and virtual IP\n* [`cd4d4c605`](https://github.com/siderolabs/talos/commit/cd4d4c6054107cd6c9274acb2abb4a045368a9fc) feat: relax extensions file structure validation\n* [`50594ab1a`](https://github.com/siderolabs/talos/commit/50594ab1a7e4d7d025f41873aaa1bf6954827d3e) fix: ignore terminated pods in pod health checks\n* [`9d69fb6b4`](https://github.com/siderolabs/talos/commit/9d69fb6b40f47061ff96bd7fb3952aa9c16ed601) feat: update Kubernetes to 1.23.5\n* [`327ce5aba`](https://github.com/siderolabs/talos/commit/327ce5aba352054837c9cc03c1ba3993a1d18158) fix: invert the condition to skip kubelet kernel checks\n* [`cf85b3f07`](https://github.com/siderolabs/talos/commit/cf85b3f07ccc3a6845f82f7853da298f5fce62a3) docs: update cilium inline install\n* [`84ee1795d`](https://github.com/siderolabs/talos/commit/84ee1795dc914574d299b1b0f1ede42bfaee110a) docs: update logo\n* [`cc7719c9d`](https://github.com/siderolabs/talos/commit/cc7719c9d014ca8c16828a84ccc95c0344bb34ed) docs: improve comments in security proto\n* [`caf800fe8`](https://github.com/siderolabs/talos/commit/caf800fe843aca5d3559ae5baf08b59db21cccd7) feat: implement D-Bus systemd-compatible shutdown for kubelet\n* [`6bec08429`](https://github.com/siderolabs/talos/commit/6bec084299062ec6df6e319d4a83313de97e3c67) feat: add talosctl completions to copy, usage, logs, restart and service\n* [`355b1a4be`](https://github.com/siderolabs/talos/commit/355b1a4bedd6755dbbaa9e98505f5c8540520bb5) fix: refresh etcd certs on startup/join\n* [`d256b5c5e`](https://github.com/siderolabs/talos/commit/d256b5c5e46ac87edf5681611eeda95fe091d922) docs: fix spelling mistakes\n* [`5fdedae20`](https://github.com/siderolabs/talos/commit/5fdedae208bfa561b7ca1a04f140adcee3deb565) chore: bump kernel to 5.15.28\n* [`18a21b5f2`](https://github.com/siderolabs/talos/commit/18a21b5f24baeea5b876d99b29f5397cc3617399) chore: add dependency images-essential -> images\n* [`714e5eca6`](https://github.com/siderolabs/talos/commit/714e5eca63ee0dd4a81ca5937081779829092111) chore: bump dependencies\n* [`58be4067e`](https://github.com/siderolabs/talos/commit/58be4067e6ddc7ba3a346469c30c435b560df377) docs: update README.md\n* [`c5fb20930`](https://github.com/siderolabs/talos/commit/c5fb20930555e5e31ea01e75aa3690d2cf628f29) docs: add loki note\n* [`f448cb4f3`](https://github.com/siderolabs/talos/commit/f448cb4f3c1620669fa34250e39aeec0e4002d37) feat: bump boot partition size to 1000 MiB\n* [`a095acb09`](https://github.com/siderolabs/talos/commit/a095acb09f225bce0e1c17f86576400549789608) chore: fix equinixMetal platform name\n* [`2a7f9a445`](https://github.com/siderolabs/talos/commit/2a7f9a4457bcb18e66b9ee6eb0ff49a290c381ce) fix: check for IPv6 before applying accept_ra\n* [`59681b8c9`](https://github.com/siderolabs/talos/commit/59681b8c9a47701092c7287c2375123134d3f9ba) fix: backport fixes from release-1.0 branch\n</p>\n</details>\n\n### Changes since v1.1.0-alpha.1\n<details><summary>66 commits</summary>\n<p>\n\n* [`91a49c4e7`](https://github.com/siderolabs/talos/commit/91a49c4e7c0495794a991ab7742cd06339ce072d) fix: dhcpv6 leasetime segfault loop\n* [`afb679586`](https://github.com/siderolabs/talos/commit/afb679586a7319746e59071b6ce0b85df0d77f48) fix: reset certificate SANs on update\n* [`c87432fe1`](https://github.com/siderolabs/talos/commit/c87432fe1feab8a157c858cf04aefe40c9f84895) fix: detect WSL for `talosctl cluster create` on Docker\n* [`166d2585c`](https://github.com/siderolabs/talos/commit/166d2585c6d94791d8a3392fc597cd9c489c1958) chore: bump kernel and runc\n* [`8d9b0cde0`](https://github.com/siderolabs/talos/commit/8d9b0cde0ab51f16421e3db23d301349626b49d8) chore: update deps to go 1.18.2\n* [`86741d998`](https://github.com/siderolabs/talos/commit/86741d99845ab36218417bd1e00f446bfe71b922) fix: append hostname to cluster SANs when port is not specified\n* [`9885bbe17`](https://github.com/siderolabs/talos/commit/9885bbe17762af22d704b6c4e33ef99032e85956) docs: fix typos, edited for clarity\n* [`7fd1c80c3`](https://github.com/siderolabs/talos/commit/7fd1c80c3ee2ea33fe1aeb2e6cb21a3d0bc98537) fix: ignore failures to dial wireguard client\n* [`b8e7cdb70`](https://github.com/siderolabs/talos/commit/b8e7cdb7012c89f980dc4c2ac29d6a503c55206a) docs: add vultr guide\n* [`c2be65b66`](https://github.com/siderolabs/talos/commit/c2be65b6684b208a8ac2e1b598e005b72dd24b8f) fix: openstack unable to parseIP\n* [`2ae0e3a56`](https://github.com/siderolabs/talos/commit/2ae0e3a56971ece0be47b741ddbf5f652b7244f1) test: add a test for version of Go Talos was built with\n* [`bef1a13fa`](https://github.com/siderolabs/talos/commit/bef1a13fa2968dd483a45d766ca7fe1de5aedace) docs: update latest Talos in 1.0 docs to 1.0.4\n* [`b52962c44`](https://github.com/siderolabs/talos/commit/b52962c44075a34399a4ceb0210b733df812775f) chore: bump dependencies\n* [`79ae76a6f`](https://github.com/siderolabs/talos/commit/79ae76a6f220683b318e2df6af7326e20c255a79) fix: properly set `allowSchedulingOnMasters` in the interactive install\n* [`2b7e7d4dc`](https://github.com/siderolabs/talos/commit/2b7e7d4dc49189dd18b1bb5646a1c621d27d82df) feat: print the status of services during boot\n* [`802d4a23c`](https://github.com/siderolabs/talos/commit/802d4a23c9c6634686136eb80bf86336c5dc6084) fix: load kubelet system service in StartAllServices task\n* [`67019c434`](https://github.com/siderolabs/talos/commit/67019c434b7e4b20f4986433340bc626b30d16bc) fix: add source path for ovmf flash image\n* [`da7b24ba5`](https://github.com/siderolabs/talos/commit/da7b24ba57fcfb589bb34f1947b3744c9953bb6b) chore: bump kernel to 5.15.38\n* [`8ca8effd6`](https://github.com/siderolabs/talos/commit/8ca8effd6165fb39120c6b30266f0b4ee3b06bfd) chore: add Equinix Managed Services NL to adopters\n* [`8bc97a30f`](https://github.com/siderolabs/talos/commit/8bc97a30f239ed5b2bbb24e620ffa7bd31a0ebf9) fix: remove D-Bus sockets before listen attempts\n* [`54cfa039a`](https://github.com/siderolabs/talos/commit/54cfa039ab8196b3d8eec9b69aa723ad90e3054b) fix: use json.Unmarshal instead of yaml.Unmarshal\n* [`6d30c4822`](https://github.com/siderolabs/talos/commit/6d30c48223022a369556e5a678a78bbab2316e67) docs: update networking resource documentation\n* [`bc88de729`](https://github.com/siderolabs/talos/commit/bc88de729c69683ac74e3312b154a722b2100a44) chore: bump coredns to v1.9.2\n* [`c6722b637`](https://github.com/siderolabs/talos/commit/c6722b637b2f39ecc83f32a1f61a6591d6a2aff6) docs: when mentioning partitions, link to partition docs\n* [`b189e8426`](https://github.com/siderolabs/talos/commit/b189e84269bdc14b041d7f225545b7c9ee948dbc) chore: fix incorrect ManifestSpec.MarshalYAML signature\n* [`5d5280200`](https://github.com/siderolabs/talos/commit/5d52802001d4fef74fe2d47e436bfd52dda7617b) feat: add more hardware information to the link status resources\n* [`2ff6db749`](https://github.com/siderolabs/talos/commit/2ff6db749af4d38959f0adc113e1d406234b05ea) chore: add Nedap Security Atlas as adopter\n* [`89cab200b`](https://github.com/siderolabs/talos/commit/89cab200b8515a6bbc62659164da61e8913860b1) chore: bump kubernetes to v1.24.0\n* [`09d16349f`](https://github.com/siderolabs/talos/commit/09d16349f4e10dfe2f32eaaa824ecf7b9e078074) chore: refactor StaticPod and StaticPodStatus into typed.Resource\n* [`d2935f98c`](https://github.com/siderolabs/talos/commit/d2935f98c4f9ae99bc8e1c0f63a4b0825a2678f6) chore: refactor LinkRefresh and LinkStatus into typed.Resource\n* [`b52e0b9b9`](https://github.com/siderolabs/talos/commit/b52e0b9b9ecb84a7b73771a80f3425af4814ada0) fix: talosctl throws error if gen option and --input-dir flags are combined\n* [`0e15de3a8`](https://github.com/siderolabs/talos/commit/0e15de3a8a4057866e5e51c99936fad1c629098f) docs: add adopters file\n* [`bb932c297`](https://github.com/siderolabs/talos/commit/bb932c29706c1eb77088d734c65857cd63035031) chore: bump containerd to v1.6.4\n* [`4eaaa2d59`](https://github.com/siderolabs/talos/commit/4eaaa2d597d12d8ec4fa265499790d0891beac42) chore: bump kernel to 5.15.37\n* [`89dde8f2c`](https://github.com/siderolabs/talos/commit/89dde8f2c426e2eb53de507b69f48bb8b6b5b7fe) chore: refactor remaining resources into typed.Resource\n* [`bd089e702`](https://github.com/siderolabs/talos/commit/bd089e702d247b2ee5f31bde542cf407e155e10b) chore: bump dependencies\n* [`3136334b9`](https://github.com/siderolabs/talos/commit/3136334b935e37e4a2f11bd4c02f89aee4806ddb) docs: fix links in VMware documentation\n* [`403df0e18`](https://github.com/siderolabs/talos/commit/403df0e1802186c409eb8cc255ca1233898a5eda) docs: provide example on using config generation package\n* [`635192861`](https://github.com/siderolabs/talos/commit/63519286110e75adc03edb89b4dc9cb432b15d46) chore: redo pointer with github.com/siderolabs/go-pointer module\n* [`a269f740c`](https://github.com/siderolabs/talos/commit/a269f740ce323b21e532b24aa327b1f4b4b1e951) docs: copy knowledge base to v1.0 docs\n* [`483201026`](https://github.com/siderolabs/talos/commit/48320102630a6a551aaa05202181daad62757180) fix: return an error if there is no byte slice in ReadonlyProvider\n* [`6e7486f09`](https://github.com/siderolabs/talos/commit/6e7486f099026724c21a73a4d4ff40134ac864b1) fix: allow graceful node shutdown to be overridden\n* [`867d38f28`](https://github.com/siderolabs/talos/commit/867d38f28f3b65b373206528d18360b714331cec) feat: add bond slaves ordering\n* [`03ef62ad8`](https://github.com/siderolabs/talos/commit/03ef62ad8bf10eccacbd490ebbcaceb0794f5378) fix: include Go primitive types into unstructured deepcopy\n* [`f06e6acf2`](https://github.com/siderolabs/talos/commit/f06e6acf2f76c48a59654e53503ae82eb9a6532c) chore: bump kernel to 5.15.36\n* [`c0d386abb`](https://github.com/siderolabs/talos/commit/c0d386abb6e427fa0da5ab416a9a3caf9ab1f1d6) fix: don't mount D-Bus socket via mount under recursive bind mount\n* [`9a8ff76df`](https://github.com/siderolabs/talos/commit/9a8ff76df2fa7366ccdeb597226285a77528442e) refactor: rewrite perf resource to use typed.Resource\n* [`71d04c4d5`](https://github.com/siderolabs/talos/commit/71d04c4d5cbaeadfc86b6eb5164f7f8026a9b66a) refactor: rewrite runtime resources to use typed.Resource\n* [`7568d51fc`](https://github.com/siderolabs/talos/commit/7568d51fc8e40c57cef3d86c77a662508ee3f0cd) fix: trigger CRI config merge on correct resource update\n* [`c456dbcb9`](https://github.com/siderolabs/talos/commit/c456dbcb934533e3026246635911ce44045dfb17) docs: remove references to init nodes\n* [`1973095d1`](https://github.com/siderolabs/talos/commit/1973095d146a9b10408f972904a06ed555524bd2) feat: update containerd to 1.6.3\n* [`b51292d88`](https://github.com/siderolabs/talos/commit/b51292d884b420b30cd5eb8eba29286f72681b72) docs: reformat config reference\n* [`c0709d970`](https://github.com/siderolabs/talos/commit/c0709d97078f6574be3b6413a1513d91adeea26e) feat: increase aio-max-nr and inotify.max_user_instances\n* [`85b328e99`](https://github.com/siderolabs/talos/commit/85b328e99719e549346a39ffc4a782e993dc7696) refactor: convert secrets resources to use typed.Resource\n* [`e91350acd`](https://github.com/siderolabs/talos/commit/e91350acd727581478b852f171b69a67b4322999) refactor: convert time & v1alpha1 resources to use typed.Resource\n* [`45464412e`](https://github.com/siderolabs/talos/commit/45464412e0526195c3a7f3e447f8f5bee108407d) chore: bump dependencies\n* [`0af6b35a6`](https://github.com/siderolabs/talos/commit/0af6b35a66ae4145d678796d6b7fea2cf77ea9de) feat: update etcd to 3.5.4\n* [`7ad27751c`](https://github.com/siderolabs/talos/commit/7ad27751cbd2a44290b7c5fa708129df5a912375) docs: fix analytics and sitemap\n* [`55ff876dc`](https://github.com/siderolabs/talos/commit/55ff876dc649f102cb6608efa6fb738d9ea69bba) chore: bump K8s Go modules to 1.24.0-rc.0\n* [`f1f43131f`](https://github.com/siderolabs/talos/commit/f1f43131f8f1070240fc32cc96a7b1ccf78e3f76) fix: strip 'v' prefix from versions on Kubernetes upgrade\n* [`ec621477b`](https://github.com/siderolabs/talos/commit/ec621477bd089d1672bf5ea94378ffa397bee227) chore: tune QEMU disk provisioner options\n* [`b085343dc`](https://github.com/siderolabs/talos/commit/b085343dcb0bff77eb03a9754843b68c8f2f90af) feat: use discovery information for etcd join (and other etcd calls)\n* [`2b03057b9`](https://github.com/siderolabs/talos/commit/2b03057b91928f550e22b96885878c2369379e98) feat: implement a new mode `try` in the config manipulation commands\n* [`51a68c31f`](https://github.com/siderolabs/talos/commit/51a68c31ff6d9bb4dc96500c158ea9968680703a) chore: allow mounting files from the host\n* [`f3e330a0a`](https://github.com/siderolabs/talos/commit/f3e330a0aaf4611cd1ffc1d2abd90487132e16e9) docs: fix network dependency\n* [`7ba39bd60`](https://github.com/siderolabs/talos/commit/7ba39bd60052eb41f718d920fa916e5c9b80a036) docs: clarify discovery service\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`a77a6f4`](https://github.com/siderolabs/extras/commit/a77a6f42b96fb23dffd5b909b75792511bcc219c) chore: bump Go to 1.18.2\n* [`ac3b9a4`](https://github.com/siderolabs/extras/commit/ac3b9a4be9bc102583f9a8cf37a53f13916d4ce7) chore: bump pkgs\n* [`d4f8e88`](https://github.com/siderolabs/extras/commit/d4f8e886147749e29026943cff3f5c701aaadf00) chore: update references after org rename\n</p>\n</details>\n\n### Changes from siderolabs/go-pointer\n<details><summary>2 commits</summary>\n<p>\n\n* [`71ccdf0`](https://github.com/siderolabs/go-pointer/commit/71ccdf0d65330596f4def36da37625e4f362f2a9) chore: implement main functionality\n* [`c1c3b23`](https://github.com/siderolabs/go-pointer/commit/c1c3b235d30cb0de97ed0645809f2b21af3b021e) Initial commit\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>44 commits</summary>\n<p>\n\n* [`7add479`](https://github.com/siderolabs/pkgs/commit/7add479f747b4cb1d77983c7a1d363ff0da588a3) chore: bump kernel to 5.15.39\n* [`0886699`](https://github.com/siderolabs/pkgs/commit/08866997587225b89007d3a101b227083ddfb62a) chore: bump runc to v1.1.2\n* [`dd06fa9`](https://github.com/siderolabs/pkgs/commit/dd06fa93cdada067b93bf721b5ee4f7e7734e975) chore: bump nvidia drivers to 510.68.02\n* [`91bb939`](https://github.com/siderolabs/pkgs/commit/91bb939f5dac2642458250be1c381c0ff0b3e6b8) chore: bump Go to 1.18.2\n* [`8bd8397`](https://github.com/siderolabs/pkgs/commit/8bd8397176345e8bfe41ccc5ee96898b29b16cf4) chore: bump kernel to 5.15.38\n* [`de96a44`](https://github.com/siderolabs/pkgs/commit/de96a445748f925468e885e0e44c26775e937f8a) chore: bump containerd to v1.6.4\n* [`45906c1`](https://github.com/siderolabs/pkgs/commit/45906c10ce195268482336b954f91c22620bb39e) chore: bump ca-certificates to 2022-04-26\n* [`d847adc`](https://github.com/siderolabs/pkgs/commit/d847adc118d1cad5886fe22b9fcd732c3103a98a) chore: bump kernel to 5.15.37\n* [`c4cfa72`](https://github.com/siderolabs/pkgs/commit/c4cfa721258abf7d7f57786aa7d5d4caeffb8b8c) chore: bump util-linux to 2.38\n* [`e22317d`](https://github.com/siderolabs/pkgs/commit/e22317dda8a731e41d483e02c486bee81071ab42) chore: bump tools\n* [`422ed8e`](https://github.com/siderolabs/pkgs/commit/422ed8e5962f983e30f0c7908ce4564ec0e64fa6) chore: bump kernel to 5.15.36\n* [`1e833c6`](https://github.com/siderolabs/pkgs/commit/1e833c6b8f15099d7c6f389ae126945f574b9e3e) chore: enable nvme hardware monitor\n* [`fe7c46f`](https://github.com/siderolabs/pkgs/commit/fe7c46f913a821e62ded2e64294d623df43eecb3) feat: update containerd to 1.6.3\n* [`95f4418`](https://github.com/siderolabs/pkgs/commit/95f4418db567226338ba8ab629ace0de39811cc8) chore: bump kernel to 5.15.35\n* [`201af71`](https://github.com/siderolabs/pkgs/commit/201af71e96b176033854f3386b4160c3a38d4d1b) chore: bump tools and bldr\n* [`3de14d7`](https://github.com/siderolabs/pkgs/commit/3de14d725c18f09e05a7db1cf0b6c424f784e977) chore: enable xfs quota support\n* [`6955fd0`](https://github.com/siderolabs/pkgs/commit/6955fd003aeff46d6d51d4d5c0e9ba64dccbeb26) chore: bump raspberrypi-firmware to 1.20220331\n* [`5b498d8`](https://github.com/siderolabs/pkgs/commit/5b498d846d032f625048a5bd4ad2ce23429c5f6d) chore: bump linux-firmware 20220401\n* [`9cda5c0`](https://github.com/siderolabs/pkgs/commit/9cda5c0542555c8dc45b34956f50ba721ac2eb05) chore: bump kernel to 5.15.34\n* [`8b48af6`](https://github.com/siderolabs/pkgs/commit/8b48af678020d203c065bac750a633f686eaafce) chore: bump tools\n* [`ff13660`](https://github.com/siderolabs/pkgs/commit/ff1366042afbe1f7fede53f5fc68d7e51d73e613) chore: bump kernel to 5.15.33\n* [`415020f`](https://github.com/siderolabs/pkgs/commit/415020fc27129aff334f3a6cd76a60f1d1064e79) chore: bump eudev, remove non-relevant default rules\n* [`6691342`](https://github.com/siderolabs/pkgs/commit/6691342a3a270954f87663a3b5efb0cf61b19979) chore: add rockpi4c\n* [`5bd5fad`](https://github.com/siderolabs/pkgs/commit/5bd5fad8fb2aae865797fa1f7374e82bce169067) chore: build u-boot spi image for rockpi\n* [`4dace49`](https://github.com/siderolabs/pkgs/commit/4dace49282b610d54b5b39917598a80ac3e1ce6a) fix: ipxe prompt arm64\n* [`6041fd7`](https://github.com/siderolabs/pkgs/commit/6041fd7963ca910a743c4b69f4fd8b9416a549af) chore: update to use latest tools (specifically go 1.18)\n* [`4b3e70e`](https://github.com/siderolabs/pkgs/commit/4b3e70e783906cf8b12b467d1a046ddeab695b94) chore: upstream u-boot for jetson nano\n* [`cc1c8c7`](https://github.com/siderolabs/pkgs/commit/cc1c8c7062c77d352f743fe4735bae5c39b00356) feat: update runc to 1.1.1\n* [`3baf4e4`](https://github.com/siderolabs/pkgs/commit/3baf4e4e1fda9ead732bee3578fc55f4f846d48a) chore: enable random trust CPU\n* [`df31920`](https://github.com/siderolabs/pkgs/commit/df319204730f890f35740837f2d6878a27f5728c) chore: disable sound\n* [`c27751b`](https://github.com/siderolabs/pkgs/commit/c27751b9f811d4b52701031c26a741333b45cbe9) chore: bump nvidia drivers to 510.60.02\n* [`ba98e20`](https://github.com/siderolabs/pkgs/commit/ba98e20d12daa200343869444a568fec231ed239) chore: bump kernel to 5.15.32\n* [`a76edfd`](https://github.com/siderolabs/pkgs/commit/a76edfdf941455237f8f16b7a833233257ae63a4) feat: update containerd to 1.6.2\n* [`0c38670`](https://github.com/siderolabs/pkgs/commit/0c38670333f788946090e42897b44871ac179ed1) chore: bump kernel to 5.15.31\n* [`bc4fb0c`](https://github.com/siderolabs/pkgs/commit/bc4fb0c2619e960d84984696aeb7e7e9368e38e9) chore: org update\n* [`41f291d`](https://github.com/siderolabs/pkgs/commit/41f291df5806b832c53ee6e042d3561a1bb52582) feat: update Flannel CNI to 1.0.1\n* [`58603ba`](https://github.com/siderolabs/pkgs/commit/58603bae512a70c5206d9fe4394139c5aa0f757c) chore: bump kernel to 5.15.30\n* [`d3bb262`](https://github.com/siderolabs/pkgs/commit/d3bb262acb78831dd3bf3ee57dc02fb6f628e78a) chore: bump kernel to 5.15.29\n* [`76a24b5`](https://github.com/siderolabs/pkgs/commit/76a24b5c9727b17f900331093c5bab86ba49f61e) chore: update openssl to 1.1.1n\n* [`490c7b7`](https://github.com/siderolabs/pkgs/commit/490c7b77052d182e09e25abe77ee27b4b54d7c7a) chore: enable aarch64 NVIDIA drivers\n* [`b794b7a`](https://github.com/siderolabs/pkgs/commit/b794b7a78c62a418edab4759a5f7bb7e0bd83dbe) chore: bump linux-firmware to 20220310\n* [`acda207`](https://github.com/siderolabs/pkgs/commit/acda20721dea1fa6af611a260c3a320f52a8ee16) chore: bump kernel to 5.15.28\n* [`e0fec11`](https://github.com/siderolabs/pkgs/commit/e0fec11a010e3958a617d7417be3a69fe43ba1b5) chore: bump nvidia driver to 510.54\n* [`0407f05`](https://github.com/siderolabs/pkgs/commit/0407f057edb8b96a7e51c5222f5b2ce171eb11c6) chore: bump kernel to 5.15.27\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>18 commits</summary>\n<p>\n\n* [`967ebd9`](https://github.com/siderolabs/tools/commit/967ebd998f099b73493f1403dcf19373f665fbdf) chore: bump curl to 7.83.1\n* [`e61f856`](https://github.com/siderolabs/tools/commit/e61f85612303fb1c855a9e1c15a55f6006e773e5) chore: bump go to 1.18.2\n* [`315890f`](https://github.com/siderolabs/tools/commit/315890f8fe487a1a0d5e3a84c493eb1006a3b247) chore: bump ca-certificates to 2022-04-26\n* [`a1d3530`](https://github.com/siderolabs/tools/commit/a1d35309614e18979c81f0f657e8e22ed8be2b02) chore: bump util-linux to 2.38\n* [`d229fe1`](https://github.com/siderolabs/tools/commit/d229fe141577bc1f4d32f9eb921984c2c8afcdfb) chore: update bldr\n* [`e9f123c`](https://github.com/siderolabs/tools/commit/e9f123caeed4d28dc5dc93c59cc9d82dfc21d42a) chore: bump curl to 7.83.0\n* [`8473ef2`](https://github.com/siderolabs/tools/commit/8473ef2f81fbb2e3fbe61740d35f675f20220a22) chore: bump git to 2.36.0\n* [`8c1f801`](https://github.com/siderolabs/tools/commit/8c1f8012f2d399bc119a0a35869e6bfd0013a7a8) chore: bump coreutils to 9.1\n* [`533d5c9`](https://github.com/siderolabs/tools/commit/533d5c9c05e4d8b4852e4f0d86d94fdeb0fddbde) chore: bump git to 2.35.2\n* [`a15cbee`](https://github.com/siderolabs/tools/commit/a15cbee68e65e6c5835a027879349f8fb6a0fa58) chore: bump go to 1.18.1\n* [`718ec10`](https://github.com/siderolabs/tools/commit/718ec10e0d80fceb46a93ad602cca0af25813f51) chore: enable conform\n* [`a60a332`](https://github.com/siderolabs/tools/commit/a60a33251d9bea2606b33f0a616a1da21e5361e9) chore: bump xz and gzip\n* [`c8a3d4d`](https://github.com/siderolabs/tools/commit/c8a3d4d894fd584ad8ca66c6b9864c447f87eab9) chore: update go to 1.18\n* [`1684fdc`](https://github.com/siderolabs/tools/commit/1684fdce5f46cf09401ffb28652f820722bf2d37) chore: bump expat to 2.4.8\n* [`7f5e44c`](https://github.com/siderolabs/tools/commit/7f5e44c1ed984732c5ab9bd22fec7d934829f2be) chore: bump zlib to 1.2.12\n* [`bfc99ca`](https://github.com/siderolabs/tools/commit/bfc99cae42ef06cf9ca30e5a5fd0771f64115cbd) chore: rename org\n* [`99be089`](https://github.com/siderolabs/tools/commit/99be089c5f17500146e7345f3228c52b2b61a9be) chore: update openssl to 1.1.1n\n* [`b63872b`](https://github.com/siderolabs/tools/commit/b63872bb8dba101a519ea2579b0e37f23b92e0e9) chore: update golang to 1.17.8\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`d9c3a27`](https://github.com/talos-systems/go-blockdevice/commit/d9c3a273886113e24809ef1e9930fc982318217d) feat: support probing FAT12/FAT16 filesystems\n* [`b374eb4`](https://github.com/talos-systems/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.5.0 -> v1.6.1\n* **github.com/BurntSushi/toml**                     v1.0.0 -> v1.1.0\n* **github.com/aws/aws-sdk-go**                      v1.43.8 -> v1.44.11\n* **github.com/containerd/containerd**               v1.6.2 -> v1.6.4\n* **github.com/containernetworking/cni**             v1.0.1 -> v1.1.0\n* **github.com/containernetworking/plugins**         v1.1.0 -> v1.1.1\n* **github.com/cosi-project/runtime**                264f8fcd1a4f -> e22a85955e81\n* **github.com/docker/distribution**                 v2.8.0 -> v2.8.1\n* **github.com/docker/docker**                       v20.10.12 -> v20.10.15\n* **github.com/fsnotify/fsnotify**                   v1.5.1 -> v1.5.4\n* **github.com/gdamore/tcell/v2**                    f057f0a857a1 -> v2.5.1\n* **github.com/google/go-cmp**                       v0.5.7 -> v0.5.8\n* **github.com/google/nftables**                     211824995dcb -> eeaebcf55295\n* **github.com/hetznercloud/hcloud-go**              v1.33.1 -> v1.33.2\n* **github.com/insomniacslk/dhcp**                   3c283ff8b7dd -> 1ca156eafb9f\n* **github.com/jsimonetti/rtnetlink**                v1.1.0 -> v1.2.0\n* **github.com/mdlayher/netx**                       669a06fde734 -> c711c2f8512f\n* **github.com/opencontainers/image-spec**           v1.0.2 -> c5a74bcca799\n* **github.com/packethost/packngo**                  v0.22.0 -> v0.24.0\n* **github.com/pelletier/go-toml**                   v1.9.4 -> v1.9.5\n* **github.com/rivo/tview**                          96063d6082f3 -> 9994674d60a8\n* **github.com/rs/xid**                              v1.3.0 -> v1.4.0\n* **github.com/siderolabs/extras**                   v1.0.0 -> v1.1.0-alpha.0-2-ga77a6f4\n* **github.com/siderolabs/go-pointer**               v1.0.0 **_new_**\n* **github.com/siderolabs/pkgs**                     v1.0.0-6-g7c293d5 -> v1.1.0-alpha.0-41-g7add479\n* **github.com/siderolabs/tools**                    v1.0.0-1-g4c77d96 -> v1.1.0-alpha.0-17-g967ebd9\n* **github.com/spf13/cobra**                         v1.3.0 -> v1.4.0\n* **github.com/spf13/pflag**                         v1.0.5 **_new_**\n* **github.com/stretchr/testify**                    v1.7.0 -> v1.7.1\n* **github.com/talos-systems/go-blockdevice**        v0.3.1 -> d9c3a2738861\n* **github.com/vishvananda/netlink**                 650dca95af54 -> v1.2.0-beta\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.2 -> v0.56.5\n* **github.com/vmware/govmomi**                      v0.27.4 -> v0.28.0\n* **github.com/vmware/vmw-guestinfo**                cc1fd90d572c -> 510905f0efa3\n* **go.etcd.io/etcd/api/v3**                         v3.5.2 -> v3.5.4\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.2 -> v3.5.4\n* **go.etcd.io/etcd/client/v3**                      v3.5.2 -> v3.5.4\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.2 -> v3.5.4\n* **golang.org/x/net**                               27dd8689420f -> 2871e0cb64e4\n* **golang.org/x/sys**                               4e6760a101f9 -> 988cb79eb6c6\n* **golang.org/x/term**                              03fcf44c2211 -> e5f449aeb171\n* **golang.org/x/time**                              0e9765cccd65 -> 583f2d630306\n* **golang.zx2c4.com/wireguard/wgctrl**              fde48d68ee68 -> 3d4a969bb56b\n* **google.golang.org/grpc**                         v1.44.0 -> v1.46.0\n* **google.golang.org/protobuf**                     v1.27.1 -> v1.28.0\n* **k8s.io/api**                                     v0.23.5 -> v0.24.0\n* **k8s.io/apimachinery**                            v0.23.5 -> v0.24.0\n* **k8s.io/apiserver**                               v0.23.5 -> v0.24.0\n* **k8s.io/client-go**                               v0.23.5 -> v0.24.0\n* **k8s.io/component-base**                          v0.23.5 -> v0.24.0\n* **k8s.io/cri-api**                                 v0.23.5 -> v0.24.0\n* **k8s.io/klog/v2**                                 v2.60.1 **_new_**\n* **k8s.io/kubectl**                                 v0.23.5 -> v0.24.0\n* **k8s.io/kubelet**                                 v0.23.5 -> v0.24.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.63 -> v1.2.64\n\nPrevious release can be found at [v1.0.0](https://github.com/siderolabs/talos/releases/tag/v1.0.0)\n\n## [Talos 1.1.0-alpha.1](https://github.com/siderolabs/talos/releases/tag/v1.1.0-alpha.1) (2022-04-20)\n\nWelcome to the v1.1.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Apply Config `--dry-run`\n\nThe commands `talosctl apply-config`, `talosctl patch mc` and `talosctl edit mc` now support `--dry-run` flag.\nIf enabled it just prints out the selected config application mode and the configuration diff.\n\n\n### IPv6 in Docker-based Talos Clusters\n\nThe command `talosctl cluster create` now enables IPv6 by default for the Docker containers\ncreated for Talos nodes. This allows to use IPv6 addresses in Kubernetes networking.\n\nIf `talosctl cluster create` fails to work on Linux due to the lack of IPv6 support,\nplease use the flag `--disable-docker-ipv6` to revert the change.\n\n\n### drop some default rules shipped by eudev\n\nDrops some default eudev rules that doesn't make sense in the context of Talos OS.\nEspecially the ones around sound devices, cd-roms and renaming the network interfaces to be predictable\n\n\n### Pod Security Admission\n\n[Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) controller is enabled by default with the following policy:\n\n```yaml\napiVersion: apiserver.config.k8s.io/v1\nkind: AdmissionConfiguration\nplugins:\n- configuration:\n    apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n    defaults:\n      audit: restricted\n      audit-version: latest\n      enforce: baseline\n      enforce-version: latest\n      warn: restricted\n      warn-version: latest\n    exemptions:\n      namespaces:\n      - kube-system\n      runtimeClasses: []\n      usernames: []\n    kind: PodSecurityConfiguration\n  name: PodSecurity\n  path: \"\"\n```\n\nThe policy is part of the Talos machine configuration, and it can be modified to suite your needs.\n\n\n### Support RockPi 4 variants A and B\n\nTalos now supports RockPi variants A and B in addition to RockPi 4C\n\n\n### Raspberry Pi PoE hat fan\n\nTalos now enables the Raspberry Pi PoE fan control by pulling in the poe overlay that works with upstream kernel\n\n\n### Component Updates\n\n* Linux: 5.15.35\n* Kubernetes: 1.24.0-rc.0\n* Flannel: 0.17.0\n* runc: 1.1.1\n\nTalos is built with Go 1.18.1.\n\n\n### x86-64 Architecture\n\nTalos is built for x86-64 architecture with support for [x86-64-v2 microarchitecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels),\nso Talos no longer runs on processors supporting only baseline `x86-64` microarchitecture (before 2009).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Tim Jones\n* Spencer Smith\n* Dmitriy Matrenichev\n* Andrew Rynhard\n* Artem Chernyshev\n* Steve Francis\n* Andrei Dobre\n* Caleb Woodbine\n* Daniel Höxtermann\n* Jori Huisman\n* Nico Berlee\n* Serge Logvinov\n* Seán C McCord\n* Steve Francis\n* Suraj Shirvankar\n* Tim Jones\n* Tomasz Zurkowski\n* William Ashton\n\n### Changes\n<details><summary>144 commits</summary>\n<p>\n\n* [`1d5c08e74`](https://github.com/siderolabs/talos/commit/1d5c08e74f2c9009ff2b3103157eb105e2a32254) chore: bump kernel to 5.15.35\n* [`9bf23e516`](https://github.com/siderolabs/talos/commit/9bf23e5162bded75a8c52009a360de1a43060858) feat: update Kubernetes to 1.24.0-rc.0\n* [`d78ed320b`](https://github.com/siderolabs/talos/commit/d78ed320b7c9853d5c118223f2289db153ea8145) docs: fix the docs reference to star registry redirects\n* [`257dfb870`](https://github.com/siderolabs/talos/commit/257dfb870933321175f859348539de6d26161618) fix: run the 'post' stage of the service always\n* [`992e23023`](https://github.com/siderolabs/talos/commit/992e2302346fb4e34a23d28f4c3a67564ddbb241) fix: correctly handle stopping services with reverse dependencies\n* [`bb7a50bd5`](https://github.com/siderolabs/talos/commit/bb7a50bd5b31d28cef6a250a056f81c2e1eace80) docs: fix netlify redirects\n* [`486f79bc7`](https://github.com/siderolabs/talos/commit/486f79bc775564f9fdd2a114b86b70d55324d18a) docs: fix netlify deploy url\n* [`e8cbedb05`](https://github.com/siderolabs/talos/commit/e8cbedb05bb19bdea339a806576215ae71eee4d8) docs: add canonical link ref\n* [`0fe4a7832`](https://github.com/siderolabs/talos/commit/0fe4a7832b1327e68d2829ae27078780434f00b3) docs: improve latest-version banner\n* [`23984efcd`](https://github.com/siderolabs/talos/commit/23984efcdf6ae530301c885c6105aa18d790d9b6) fix: detect lingering mounts in the installer correctly\n* [`54dba925f`](https://github.com/siderolabs/talos/commit/54dba925f88881f41246a9198955ac6ce95d81d9) chore: refactor network resource to use typed resource\n* [`4eb9f45cc`](https://github.com/siderolabs/talos/commit/4eb9f45cc82669ac31ffc17bc53a5be05563823e) refactor: split polymorphic K8sControlPlane into typed resources\n* [`68dfdd331`](https://github.com/siderolabs/talos/commit/68dfdd3311c602faaeb5e5f7970c0e7d13a32600) fix: provide logger to the etcd snapshot restore\n* [`f190403f0`](https://github.com/siderolabs/talos/commit/f190403f01118c7f60d5e97a4c2349c638ed7e0b) docs: add how to get config after interactive setup\n* [`fac7b9466`](https://github.com/siderolabs/talos/commit/fac7b94667bb9aae680677b5e3e936f107315062) docs: improve vip caveats documentation\n* [`250df9e67`](https://github.com/siderolabs/talos/commit/250df9e670c8e4221fa376791b88ee03fa2022ae) docs: improve rook-ceph description\n* [`b5c1d868d`](https://github.com/siderolabs/talos/commit/b5c1d868deac9fd8d124cda35693b4f12372589f) docs: add talos/kubernetes config faq\n* [`39721ee93`](https://github.com/siderolabs/talos/commit/39721ee9392ed43da572c71eb056a8a4b1a795fd) chore: bump dependencies\n* [`610945774`](https://github.com/siderolabs/talos/commit/610945774a8f9cf849ddfefda0e4d456bb8ba2c3) chore: bump tools and pkgs\n* [`2b68c8b67`](https://github.com/siderolabs/talos/commit/2b68c8b67bf1ea88d471b8baa405a65fcd1aa40f) fix: enable long timestamps for xfs\n* [`be00d7749`](https://github.com/siderolabs/talos/commit/be00d774921b28ebc9b81727a6e4cf29a06385ee) chore: implement cluster resources using cosi typed resource\n* [`460d5ab13`](https://github.com/siderolabs/talos/commit/460d5ab13f007a89e72013c443132a845dcc3a09) docs: fix extension services alias\n* [`bbdfda2dd`](https://github.com/siderolabs/talos/commit/bbdfda2dd2e72f1fd5981dd6fc589d90cd692b72) chore: xfs quota support in kernel\n* [`8ff8fc77f`](https://github.com/siderolabs/talos/commit/8ff8fc77f3b14679daa31067528f6bcf62e9aca9) chore: enable rpi4 poe hat fan control\n* [`2b9722d1f`](https://github.com/siderolabs/talos/commit/2b9722d1f5fac39390fde8223d40262af80b1ef2) feat: add `dry-run` flag in `apply-config` and `edit` commands\n* [`8af50fcd2`](https://github.com/siderolabs/talos/commit/8af50fcd27bed2a437d6d9668233657a47bd9798) fix: correct cri package import path\n* [`ce09ede83`](https://github.com/siderolabs/talos/commit/ce09ede839e7500df1dd862f8c2726b02798b725) feat: update etcd to 3.5.3\n* [`13f41badd`](https://github.com/siderolabs/talos/commit/13f41baddff997dfa15c773d8f078bd0921fb40b) chore: bump kernel to 5.15.34\n* [`fa57b5d92`](https://github.com/siderolabs/talos/commit/fa57b5d9225d3075b08a9d07ce29480a4c050143) docs: reorganize documentation\n* [`a91eb9358`](https://github.com/siderolabs/talos/commit/a91eb9358dfc49e2afc1523f804c0f01660cfb1f) chore: bump deps\n* [`0aad0df2e`](https://github.com/siderolabs/talos/commit/0aad0df2eb6a8727dfff253619a9b2cb1915d9be) refactor: remove `String()` for resource implementation\n* [`a4060513c`](https://github.com/siderolabs/talos/commit/a4060513c694f2d45be95a060e4bb719840d8739) feat: build Talos with support for x86-64-v2 microarchitecture\n* [`8faebd410`](https://github.com/siderolabs/talos/commit/8faebd410be9653808f50df698345ee613be6e68) chore: bump tools and pkgs\n* [`8499b7e7d`](https://github.com/siderolabs/talos/commit/8499b7e7dcbd5fbcb9aa94a8028a73168a304a06) chore: bump dependencies\n* [`a7ba7ea67`](https://github.com/siderolabs/talos/commit/a7ba7ea679f10e99b31ee3b4b6c92265d43c12df) feat: migrate to go 1.18\n* [`9dace93b5`](https://github.com/siderolabs/talos/commit/9dace93b59e8e1e1d8a7595fda82dc85b9c835cf) feat: enable Pod Security Admission by default\n* [`c382cb8cd`](https://github.com/siderolabs/talos/commit/c382cb8cd26f2eaece665bcb471f27d188ea1ad5) docs: update vmware docs\n* [`da0e638f0`](https://github.com/siderolabs/talos/commit/da0e638f04cfab1ed93891231035439ad77666d1) docs: stableize tools versioning\n* [`f2d2267e7`](https://github.com/siderolabs/talos/commit/f2d2267e749a14b8a060e56f274f603415d69731) docs: use template for netlify redirects\n* [`88f1d8fcc`](https://github.com/siderolabs/talos/commit/88f1d8fcc0e3bd28a9db4677ad9d782c80ffdbb9) docs: update sitemap to point to direct url\n* [`a6eebee36`](https://github.com/siderolabs/talos/commit/a6eebee36f9a3f6fbde441ccb5e170dae9727a58) chore: update eudev\n* [`0cb84e8c1`](https://github.com/siderolabs/talos/commit/0cb84e8c1a09c5b391461aa17c277a0a7803f725) fix: correctly parse tags out of images\n* [`17d09739f`](https://github.com/siderolabs/talos/commit/17d09739f3fe8cb942008a44f902b65705e39575) docs: enable nested arrow\n* [`1e4320b64`](https://github.com/siderolabs/talos/commit/1e4320b64e2477a55f808c6b8720b0779088d0f8) chore: add support for rockpi 4A and 4B\n* [`d1869d948`](https://github.com/siderolabs/talos/commit/d1869d948c84cf7191819eddac9c2aa27b365eb9) docs: update to Sidero Metal, mention clusterctl\n* [`18d0038ec`](https://github.com/siderolabs/talos/commit/18d0038ecaa2cf43164f72f3acad5445e395b37e) fix: avoid panic in DHCPv6 operator on nil dereference\n* [`9e3d438db`](https://github.com/siderolabs/talos/commit/9e3d438db461529abf3dfa6ef750b4fa4a9125ec) docs: fix code fence formatting\n* [`b3f1bb2cf`](https://github.com/siderolabs/talos/commit/b3f1bb2cff544a35f767b32ca8ca1d13b83c535e) fix: add support for FAT12/16 filesystems\n* [`8619f95c5`](https://github.com/siderolabs/talos/commit/8619f95c5c7779815a87118cbb0a1e493251355d) chore: bump dependencies\n* [`8c4f72004`](https://github.com/siderolabs/talos/commit/8c4f720048c0187b203ca869befd759249bac79f) docs: override sitemap.xml to only include latest results\n* [`5192ba4e2`](https://github.com/siderolabs/talos/commit/5192ba4e2314c05e107adcc0a2a71a65ec35bfc3) docs: fix a typo in QEMU VM setup guide\n* [`663e3e879`](https://github.com/siderolabs/talos/commit/663e3e8796c3f501275fdd7836687b811318b685) refactor: change the stages for embed files generation\n* [`19bf12af0`](https://github.com/siderolabs/talos/commit/19bf12af07aaf6b54d08027676d8a01b4dd4ed29) fix: enable IPv6 in Docker-based Talos clusters\n* [`3889a5839`](https://github.com/siderolabs/talos/commit/3889a583970c73ea4c6089b1fe8438b183ec756e) docs: update config.yaml, storage.md, digital-rebar.md\n* [`25d19131d`](https://github.com/siderolabs/talos/commit/25d19131d378960603a510cb70b35352b07bf7cb) release(v1.1.0-alpha.0): prepare release\n* [`2ca5279e5`](https://github.com/siderolabs/talos/commit/2ca5279e56d154fdf21fab7ed5c73edb30494560) fix: retry manifest updates in upgrade-k8s\n* [`eeb756168`](https://github.com/siderolabs/talos/commit/eeb756168f31c8e7a1e0cb2f80e1ae2bc2eed0a9) feat: use kexec when resetting a node\n* [`1ed1f73e5`](https://github.com/siderolabs/talos/commit/1ed1f73e511f4a5cf4d1db5f97422cf1eb088fda) test: bump CAPI to 1.1.3\n* [`2ee1d2c72`](https://github.com/siderolabs/talos/commit/2ee1d2c72085df41ec0355bac0d33bedcb4f2786) feat: update Kuberentes to 1.24.0-beta.0\n* [`c26fa4ccc`](https://github.com/siderolabs/talos/commit/c26fa4ccc1e109c889c01384422f88387ad512a2) test: push GITHUB_TOKEN to the e2e-aws/gcp steps\n* [`95d900de7`](https://github.com/siderolabs/talos/commit/95d900de7799cfa9d0a16049586ba246bddb09d0) feat: use kubeconfig env var\n* [`0b407dd17`](https://github.com/siderolabs/talos/commit/0b407dd17e9515fecd8083fd5ac1fc84f6085106) feat: add dhcp-v6 NTP/DHCP-DUID\n* [`a140a6bad`](https://github.com/siderolabs/talos/commit/a140a6bad74bcf34e62e13b6efa63a17741eb5b1) docs: update releases shortcode in upgrade guide\n* [`12931dced`](https://github.com/siderolabs/talos/commit/12931dcedd38c407a2a03f692d910853130986db) fix: align partitions on 1M boundary\n* [`37f868e37`](https://github.com/siderolabs/talos/commit/37f868e37454f63a4dfe38d94dbbeef5bb40a2a8) fix: validate empty TLS config for registries\n* [`ca8b9c0a3`](https://github.com/siderolabs/talos/commit/ca8b9c0a3a15898d9562a6f22aded138d6c3ed7f) feat: update Kubernetes to 1.24.0-alpha.4\n* [`d9ec6b215`](https://github.com/siderolabs/talos/commit/d9ec6b2151e94c94eea44771e455555eaf1f257a) chore: drop dirty from abbreviated tag\n* [`08624fd0b`](https://github.com/siderolabs/talos/commit/08624fd0b12039e5a77ce43f14df65a6c95f7a39) docs: add banner to main page\n* [`fc23c7a59`](https://github.com/siderolabs/talos/commit/fc23c7a5952d87a51f29d61ead585bf060eeab1c) test: bump versions for upgrade tests\n* [`4bfe68610`](https://github.com/siderolabs/talos/commit/4bfe686105d5734b282f4817673972b71954e620) feat: update runc to 1.1.1\n* [`b315ed953`](https://github.com/siderolabs/talos/commit/b315ed95327a9b7cfb1f83a9da02e96bafecbb1d) chore: use go:embed instead of ldflags\n* [`a5d64fc81`](https://github.com/siderolabs/talos/commit/a5d64fc814f122fb7e282b97283a46ac0e5d6709) feat: update Flannel to 0.17.0\n* [`6d6eb3f6a`](https://github.com/siderolabs/talos/commit/6d6eb3f6a52626c8c94a75439133e7bc22b25e60) docs: fork docs for 1.1\n* [`1d55f05d1`](https://github.com/siderolabs/talos/commit/1d55f05d11e5a03a8de0e7ce5ec0167971b03135) docs: update index page\n* [`ad6b7ec1a`](https://github.com/siderolabs/talos/commit/ad6b7ec1a4347753488de3ab5813947f01967078) fix: enable etcd consistency on check startup\n* [`65a31f753`](https://github.com/siderolabs/talos/commit/65a31f7531a629b29fbf86ddcbaba20767475924) docs: re-add GA token\n* [`741c04832`](https://github.com/siderolabs/talos/commit/741c048320b931228336034ad17de10272ff5a77) docs: mark 1.0 docs as latest\n* [`e97433c8a`](https://github.com/siderolabs/talos/commit/e97433c8a37ca504577355d98c917e083aaedafe) docs: update jetson nano\n* [`6665e0f00`](https://github.com/siderolabs/talos/commit/6665e0f00c1c5d45123eb28d8755d0815af4822a) docs: code block copying\n* [`c41f2b216`](https://github.com/siderolabs/talos/commit/c41f2b216717db80e44654f54080a9d462946d45) docs: update whats-new-v1.0\n* [`0a36fbbf3`](https://github.com/siderolabs/talos/commit/0a36fbbf3ca579becd0a7f2e5a9715ff4196e8ae) docs: add release notes for 1.0\n* [`bd0035f6a`](https://github.com/siderolabs/talos/commit/bd0035f6a285f8b7e4c7c0b5013a271a8d18c5f4) docs: add NVIDIA docs\n* [`efa3f2898`](https://github.com/siderolabs/talos/commit/efa3f289853a47ae0d4bca5dbf656e527cf312dd) fix: correctly find partitions with config data (`metal-iso`)\n* [`9ebeec0d0`](https://github.com/siderolabs/talos/commit/9ebeec0d0ea4dd3cc1ba3b7171fe0a9bda943fe8) docs: fix incorrect path for talosconfig\n* [`9fef4540e`](https://github.com/siderolabs/talos/commit/9fef4540e1c7a7deb5d4745d3de17c6e5cc45369) docs: fix non-latest download links\n* [`f8ef6a081`](https://github.com/siderolabs/talos/commit/f8ef6a081e055637a5652366a6e344b6df911871) docs: add rook ceph configuration guide\n* [`e2666f58f`](https://github.com/siderolabs/talos/commit/e2666f58f5835db6ff8802b2370a480d8afcd8fc) chore: bump kernel to 5.15.32\n* [`957b2f233`](https://github.com/siderolabs/talos/commit/957b2f233c4b81eacdb5a3190c0070fa36ef0d82) chore: bump dependencies\n* [`0fd2aa08b`](https://github.com/siderolabs/talos/commit/0fd2aa08bd70d1c869e0dca136ca0c487bfcdefe) fix: correctly escape '.' in volume names\n* [`108fd03a7`](https://github.com/siderolabs/talos/commit/108fd03a72534cebbab7c09d63051021483566ac) fix: give up virtual IPs before the kubelet workloads are shut down\n* [`856e1333d`](https://github.com/siderolabs/talos/commit/856e1333dcfb8c0244ca8ead415025b32a4819fc) fix: use 'localhost' endpoint in docker provisioner on Windows\n* [`c5da38609`](https://github.com/siderolabs/talos/commit/c5da386092185fe4ed4173b08f95eac4e435ff99) docs: use variables and templates in the docs\n* [`4c83847b9`](https://github.com/siderolabs/talos/commit/4c83847b9091a4e8968544a515632a3391c06cd0) docs: target search results\n* [`67fb72d96`](https://github.com/siderolabs/talos/commit/67fb72d96db1cb772392dcab9b5a3a08ee50ff03) docs: add algolia versions to all content\n* [`5344d6e7c`](https://github.com/siderolabs/talos/commit/5344d6e7ce2b7febc6109acc566cf49346eca6d9) docs: fix extension service `path` dependency\n* [`9b9191c5e`](https://github.com/siderolabs/talos/commit/9b9191c5e7a4a03bb7fa271ab49b52874e63ee31) fix: increase intiial window and connection window sizes\n* [`7a88a0224`](https://github.com/siderolabs/talos/commit/7a88a0224155755a64c911165bf25bff775e1ec2) docs: show archived/pre-release banner based on version\n* [`e403470bf`](https://github.com/siderolabs/talos/commit/e403470bfefe7af0217d91cb18d900b7046254f9) docs: filter algolia results by latest\n* [`0497d5f9f`](https://github.com/siderolabs/talos/commit/0497d5f9fee404f68d09c0c500cb446126cfc6aa) docs: tag latest docs for search\n* [`a25425483`](https://github.com/siderolabs/talos/commit/a25425483518adc5bdd575c5fb8cc1b3464444ea) feat: update containerd to 1.6.2, Linux to 5.15.31\n* [`9b6422fcc`](https://github.com/siderolabs/talos/commit/9b6422fcc39c2f4e0723c0db0b6aefe3e4fc8267) feat: update CoreDNS to 1.9.1\n* [`020856f80`](https://github.com/siderolabs/talos/commit/020856f80dd93fb47170351c083602ffd516d113) docs: remove second search bar\n* [`5f27f4c63`](https://github.com/siderolabs/talos/commit/5f27f4c6384e9bb6df4fc969c3a318ad3052cf3f) docs: update asset links\n* [`9ff42b432`](https://github.com/siderolabs/talos/commit/9ff42b43202bb59845439a88014011ff002a7770) docs: fix redirects for /docs URLs\n* [`7283efd56`](https://github.com/siderolabs/talos/commit/7283efd568d35e6d2c68aa2bc101a7af86db8c62) chore: update the talosctl CNI download url\n* [`e0eee7fcc`](https://github.com/siderolabs/talos/commit/e0eee7fcc68f03243ae3248f84d50eb278998e07) test: use clusterctl.yaml overrides after org rename\n* [`73966f51e`](https://github.com/siderolabs/talos/commit/73966f51e83b7f166e4f7fe013bfed36e9b9a15a) docs: fix extensions\n* [`f9766edb5`](https://github.com/siderolabs/talos/commit/f9766edb52d6a029d12ac5d74fdb45b6294be058) docs: remove empty doc file\n* [`e06e1473b`](https://github.com/siderolabs/talos/commit/e06e1473b02cea088499c25f48a9b5e2b75cf879) feat: update golangci-lint to 1.45.0 and gofumpt to 0.3.0\n* [`a92c614b2`](https://github.com/siderolabs/talos/commit/a92c614b2f712fb046fb40e00b37773d1390df71) docs: add enterprise link to docs header\n* [`0ae7174ba`](https://github.com/siderolabs/talos/commit/0ae7174ba3a6c1674c77cf074087a68915e3e612) docs: update search settings and redirects\n* [`883d401f9`](https://github.com/siderolabs/talos/commit/883d401f9f62229305c2e24f58a0bb0e2e4bb409) chore: rename github organization to siderolabs\n* [`d1294d014`](https://github.com/siderolabs/talos/commit/d1294d014f5bee7fc1b5dfd6865f22b22f18f5f1) chore: add day-two tests for e2e-qemu\n* [`a6240e4b6`](https://github.com/siderolabs/talos/commit/a6240e4b67060357c4250e7e5a3a7960408f7c08) feat: update Linux to 5.15.30\n* [`e3fda049f`](https://github.com/siderolabs/talos/commit/e3fda049fee62f3c5cef4ae08eaf848826a6dbed) docs: overhaul all the docs\n* [`f47750726`](https://github.com/siderolabs/talos/commit/f477507262041a24def6ac9b32fa92d276d4d4e6) fix: the etcd recovery client and tests\n* [`69e07cddc`](https://github.com/siderolabs/talos/commit/69e07cddc77d6ff2c2477ec64f860ef824132000) fix: trigger properly `udevd` on types and actions\n* [`47d0e629d`](https://github.com/siderolabs/talos/commit/47d0e629d48930f6cb02dff32469bcb34440c73c) fix: clean up custom udev rules if the config is cleared\n* [`b6691b350`](https://github.com/siderolabs/talos/commit/b6691b35085e4e614752b60441c17fe39fe15928) chore: bump dependencies\n* [`27af5d41c`](https://github.com/siderolabs/talos/commit/27af5d41c6c58f4d2fc2f5c222d9de39539de1c0) feat: pause the boot process on some failures instead of rebooting\n* [`58cb9db1e`](https://github.com/siderolabs/talos/commit/58cb9db1e2b3d8fa86c0db0cf38c9f21a843da9d) feat: allow hardlinks in the system extension images\n* [`1e982808f`](https://github.com/siderolabs/talos/commit/1e982808fbac0a7f897bafacde348c5d83db38b2) fix: ignore pod CIDRs for kubelet node IPs\n* [`5e0c80f61`](https://github.com/siderolabs/talos/commit/5e0c80f6168ac8a171e35e0c3ee53d959c2dd80d) fix: ignore connection reset errors on k8s upgrade\n* [`c156580a3`](https://github.com/siderolabs/talos/commit/c156580a386e19d020b550b8459af339f440bf3e) fix: split regular network operation configuration and virtual IP\n* [`cd4d4c605`](https://github.com/siderolabs/talos/commit/cd4d4c6054107cd6c9274acb2abb4a045368a9fc) feat: relax extensions file structure validation\n* [`50594ab1a`](https://github.com/siderolabs/talos/commit/50594ab1a7e4d7d025f41873aaa1bf6954827d3e) fix: ignore terminated pods in pod health checks\n* [`9d69fb6b4`](https://github.com/siderolabs/talos/commit/9d69fb6b40f47061ff96bd7fb3952aa9c16ed601) feat: update Kubernetes to 1.23.5\n* [`327ce5aba`](https://github.com/siderolabs/talos/commit/327ce5aba352054837c9cc03c1ba3993a1d18158) fix: invert the condition to skip kubelet kernel checks\n* [`cf85b3f07`](https://github.com/siderolabs/talos/commit/cf85b3f07ccc3a6845f82f7853da298f5fce62a3) docs: update cilium inline install\n* [`84ee1795d`](https://github.com/siderolabs/talos/commit/84ee1795dc914574d299b1b0f1ede42bfaee110a) docs: update logo\n* [`cc7719c9d`](https://github.com/siderolabs/talos/commit/cc7719c9d014ca8c16828a84ccc95c0344bb34ed) docs: improve comments in security proto\n* [`caf800fe8`](https://github.com/siderolabs/talos/commit/caf800fe843aca5d3559ae5baf08b59db21cccd7) feat: implement D-Bus systemd-compatible shutdown for kubelet\n* [`6bec08429`](https://github.com/siderolabs/talos/commit/6bec084299062ec6df6e319d4a83313de97e3c67) feat: add talosctl completions to copy, usage, logs, restart and service\n* [`355b1a4be`](https://github.com/siderolabs/talos/commit/355b1a4bedd6755dbbaa9e98505f5c8540520bb5) fix: refresh etcd certs on startup/join\n* [`d256b5c5e`](https://github.com/siderolabs/talos/commit/d256b5c5e46ac87edf5681611eeda95fe091d922) docs: fix spelling mistakes\n* [`5fdedae20`](https://github.com/siderolabs/talos/commit/5fdedae208bfa561b7ca1a04f140adcee3deb565) chore: bump kernel to 5.15.28\n* [`18a21b5f2`](https://github.com/siderolabs/talos/commit/18a21b5f24baeea5b876d99b29f5397cc3617399) chore: add dependency images-essential -> images\n* [`714e5eca6`](https://github.com/siderolabs/talos/commit/714e5eca63ee0dd4a81ca5937081779829092111) chore: bump dependencies\n* [`58be4067e`](https://github.com/siderolabs/talos/commit/58be4067e6ddc7ba3a346469c30c435b560df377) docs: update README.md\n* [`c5fb20930`](https://github.com/siderolabs/talos/commit/c5fb20930555e5e31ea01e75aa3690d2cf628f29) docs: add loki note\n* [`f448cb4f3`](https://github.com/siderolabs/talos/commit/f448cb4f3c1620669fa34250e39aeec0e4002d37) feat: bump boot partition size to 1000 MiB\n* [`a095acb09`](https://github.com/siderolabs/talos/commit/a095acb09f225bce0e1c17f86576400549789608) chore: fix equinixMetal platform name\n* [`2a7f9a445`](https://github.com/siderolabs/talos/commit/2a7f9a4457bcb18e66b9ee6eb0ff49a290c381ce) fix: check for IPv6 before applying accept_ra\n* [`59681b8c9`](https://github.com/siderolabs/talos/commit/59681b8c9a47701092c7287c2375123134d3f9ba) fix: backport fixes from release-1.0 branch\n</p>\n</details>\n\n### Changes since v1.1.0-alpha.0\n<details><summary>54 commits</summary>\n<p>\n\n* [`1d5c08e74`](https://github.com/siderolabs/talos/commit/1d5c08e74f2c9009ff2b3103157eb105e2a32254) chore: bump kernel to 5.15.35\n* [`9bf23e516`](https://github.com/siderolabs/talos/commit/9bf23e5162bded75a8c52009a360de1a43060858) feat: update Kubernetes to 1.24.0-rc.0\n* [`d78ed320b`](https://github.com/siderolabs/talos/commit/d78ed320b7c9853d5c118223f2289db153ea8145) docs: fix the docs reference to star registry redirects\n* [`257dfb870`](https://github.com/siderolabs/talos/commit/257dfb870933321175f859348539de6d26161618) fix: run the 'post' stage of the service always\n* [`992e23023`](https://github.com/siderolabs/talos/commit/992e2302346fb4e34a23d28f4c3a67564ddbb241) fix: correctly handle stopping services with reverse dependencies\n* [`bb7a50bd5`](https://github.com/siderolabs/talos/commit/bb7a50bd5b31d28cef6a250a056f81c2e1eace80) docs: fix netlify redirects\n* [`486f79bc7`](https://github.com/siderolabs/talos/commit/486f79bc775564f9fdd2a114b86b70d55324d18a) docs: fix netlify deploy url\n* [`e8cbedb05`](https://github.com/siderolabs/talos/commit/e8cbedb05bb19bdea339a806576215ae71eee4d8) docs: add canonical link ref\n* [`0fe4a7832`](https://github.com/siderolabs/talos/commit/0fe4a7832b1327e68d2829ae27078780434f00b3) docs: improve latest-version banner\n* [`23984efcd`](https://github.com/siderolabs/talos/commit/23984efcdf6ae530301c885c6105aa18d790d9b6) fix: detect lingering mounts in the installer correctly\n* [`54dba925f`](https://github.com/siderolabs/talos/commit/54dba925f88881f41246a9198955ac6ce95d81d9) chore: refactor network resource to use typed resource\n* [`4eb9f45cc`](https://github.com/siderolabs/talos/commit/4eb9f45cc82669ac31ffc17bc53a5be05563823e) refactor: split polymorphic K8sControlPlane into typed resources\n* [`68dfdd331`](https://github.com/siderolabs/talos/commit/68dfdd3311c602faaeb5e5f7970c0e7d13a32600) fix: provide logger to the etcd snapshot restore\n* [`f190403f0`](https://github.com/siderolabs/talos/commit/f190403f01118c7f60d5e97a4c2349c638ed7e0b) docs: add how to get config after interactive setup\n* [`fac7b9466`](https://github.com/siderolabs/talos/commit/fac7b94667bb9aae680677b5e3e936f107315062) docs: improve vip caveats documentation\n* [`250df9e67`](https://github.com/siderolabs/talos/commit/250df9e670c8e4221fa376791b88ee03fa2022ae) docs: improve rook-ceph description\n* [`b5c1d868d`](https://github.com/siderolabs/talos/commit/b5c1d868deac9fd8d124cda35693b4f12372589f) docs: add talos/kubernetes config faq\n* [`39721ee93`](https://github.com/siderolabs/talos/commit/39721ee9392ed43da572c71eb056a8a4b1a795fd) chore: bump dependencies\n* [`610945774`](https://github.com/siderolabs/talos/commit/610945774a8f9cf849ddfefda0e4d456bb8ba2c3) chore: bump tools and pkgs\n* [`2b68c8b67`](https://github.com/siderolabs/talos/commit/2b68c8b67bf1ea88d471b8baa405a65fcd1aa40f) fix: enable long timestamps for xfs\n* [`be00d7749`](https://github.com/siderolabs/talos/commit/be00d774921b28ebc9b81727a6e4cf29a06385ee) chore: implement cluster resources using cosi typed resource\n* [`460d5ab13`](https://github.com/siderolabs/talos/commit/460d5ab13f007a89e72013c443132a845dcc3a09) docs: fix extension services alias\n* [`bbdfda2dd`](https://github.com/siderolabs/talos/commit/bbdfda2dd2e72f1fd5981dd6fc589d90cd692b72) chore: xfs quota support in kernel\n* [`8ff8fc77f`](https://github.com/siderolabs/talos/commit/8ff8fc77f3b14679daa31067528f6bcf62e9aca9) chore: enable rpi4 poe hat fan control\n* [`2b9722d1f`](https://github.com/siderolabs/talos/commit/2b9722d1f5fac39390fde8223d40262af80b1ef2) feat: add `dry-run` flag in `apply-config` and `edit` commands\n* [`8af50fcd2`](https://github.com/siderolabs/talos/commit/8af50fcd27bed2a437d6d9668233657a47bd9798) fix: correct cri package import path\n* [`ce09ede83`](https://github.com/siderolabs/talos/commit/ce09ede839e7500df1dd862f8c2726b02798b725) feat: update etcd to 3.5.3\n* [`13f41badd`](https://github.com/siderolabs/talos/commit/13f41baddff997dfa15c773d8f078bd0921fb40b) chore: bump kernel to 5.15.34\n* [`fa57b5d92`](https://github.com/siderolabs/talos/commit/fa57b5d9225d3075b08a9d07ce29480a4c050143) docs: reorganize documentation\n* [`a91eb9358`](https://github.com/siderolabs/talos/commit/a91eb9358dfc49e2afc1523f804c0f01660cfb1f) chore: bump deps\n* [`0aad0df2e`](https://github.com/siderolabs/talos/commit/0aad0df2eb6a8727dfff253619a9b2cb1915d9be) refactor: remove `String()` for resource implementation\n* [`a4060513c`](https://github.com/siderolabs/talos/commit/a4060513c694f2d45be95a060e4bb719840d8739) feat: build Talos with support for x86-64-v2 microarchitecture\n* [`8faebd410`](https://github.com/siderolabs/talos/commit/8faebd410be9653808f50df698345ee613be6e68) chore: bump tools and pkgs\n* [`8499b7e7d`](https://github.com/siderolabs/talos/commit/8499b7e7dcbd5fbcb9aa94a8028a73168a304a06) chore: bump dependencies\n* [`a7ba7ea67`](https://github.com/siderolabs/talos/commit/a7ba7ea679f10e99b31ee3b4b6c92265d43c12df) feat: migrate to go 1.18\n* [`9dace93b5`](https://github.com/siderolabs/talos/commit/9dace93b59e8e1e1d8a7595fda82dc85b9c835cf) feat: enable Pod Security Admission by default\n* [`c382cb8cd`](https://github.com/siderolabs/talos/commit/c382cb8cd26f2eaece665bcb471f27d188ea1ad5) docs: update vmware docs\n* [`da0e638f0`](https://github.com/siderolabs/talos/commit/da0e638f04cfab1ed93891231035439ad77666d1) docs: stableize tools versioning\n* [`f2d2267e7`](https://github.com/siderolabs/talos/commit/f2d2267e749a14b8a060e56f274f603415d69731) docs: use template for netlify redirects\n* [`88f1d8fcc`](https://github.com/siderolabs/talos/commit/88f1d8fcc0e3bd28a9db4677ad9d782c80ffdbb9) docs: update sitemap to point to direct url\n* [`a6eebee36`](https://github.com/siderolabs/talos/commit/a6eebee36f9a3f6fbde441ccb5e170dae9727a58) chore: update eudev\n* [`0cb84e8c1`](https://github.com/siderolabs/talos/commit/0cb84e8c1a09c5b391461aa17c277a0a7803f725) fix: correctly parse tags out of images\n* [`17d09739f`](https://github.com/siderolabs/talos/commit/17d09739f3fe8cb942008a44f902b65705e39575) docs: enable nested arrow\n* [`1e4320b64`](https://github.com/siderolabs/talos/commit/1e4320b64e2477a55f808c6b8720b0779088d0f8) chore: add support for rockpi 4A and 4B\n* [`d1869d948`](https://github.com/siderolabs/talos/commit/d1869d948c84cf7191819eddac9c2aa27b365eb9) docs: update to Sidero Metal, mention clusterctl\n* [`18d0038ec`](https://github.com/siderolabs/talos/commit/18d0038ecaa2cf43164f72f3acad5445e395b37e) fix: avoid panic in DHCPv6 operator on nil dereference\n* [`9e3d438db`](https://github.com/siderolabs/talos/commit/9e3d438db461529abf3dfa6ef750b4fa4a9125ec) docs: fix code fence formatting\n* [`b3f1bb2cf`](https://github.com/siderolabs/talos/commit/b3f1bb2cff544a35f767b32ca8ca1d13b83c535e) fix: add support for FAT12/16 filesystems\n* [`8619f95c5`](https://github.com/siderolabs/talos/commit/8619f95c5c7779815a87118cbb0a1e493251355d) chore: bump dependencies\n* [`8c4f72004`](https://github.com/siderolabs/talos/commit/8c4f720048c0187b203ca869befd759249bac79f) docs: override sitemap.xml to only include latest results\n* [`5192ba4e2`](https://github.com/siderolabs/talos/commit/5192ba4e2314c05e107adcc0a2a71a65ec35bfc3) docs: fix a typo in QEMU VM setup guide\n* [`663e3e879`](https://github.com/siderolabs/talos/commit/663e3e8796c3f501275fdd7836687b811318b685) refactor: change the stages for embed files generation\n* [`19bf12af0`](https://github.com/siderolabs/talos/commit/19bf12af07aaf6b54d08027676d8a01b4dd4ed29) fix: enable IPv6 in Docker-based Talos clusters\n* [`3889a5839`](https://github.com/siderolabs/talos/commit/3889a583970c73ea4c6089b1fe8438b183ec756e) docs: update config.yaml, storage.md, digital-rebar.md\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`ac3b9a4`](https://github.com/siderolabs/extras/commit/ac3b9a4be9bc102583f9a8cf37a53f13916d4ce7) chore: bump pkgs\n* [`d4f8e88`](https://github.com/siderolabs/extras/commit/d4f8e886147749e29026943cff3f5c701aaadf00) chore: update references after org rename\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>31 commits</summary>\n<p>\n\n* [`95f4418`](https://github.com/siderolabs/pkgs/commit/95f4418db567226338ba8ab629ace0de39811cc8) chore: bump kernel to 5.15.35\n* [`201af71`](https://github.com/siderolabs/pkgs/commit/201af71e96b176033854f3386b4160c3a38d4d1b) chore: bump tools and bldr\n* [`3de14d7`](https://github.com/siderolabs/pkgs/commit/3de14d725c18f09e05a7db1cf0b6c424f784e977) chore: enable xfs quota support\n* [`6955fd0`](https://github.com/siderolabs/pkgs/commit/6955fd003aeff46d6d51d4d5c0e9ba64dccbeb26) chore: bump raspberrypi-firmware to 1.20220331\n* [`5b498d8`](https://github.com/siderolabs/pkgs/commit/5b498d846d032f625048a5bd4ad2ce23429c5f6d) chore: bump linux-firmware 20220401\n* [`9cda5c0`](https://github.com/siderolabs/pkgs/commit/9cda5c0542555c8dc45b34956f50ba721ac2eb05) chore: bump kernel to 5.15.34\n* [`8b48af6`](https://github.com/siderolabs/pkgs/commit/8b48af678020d203c065bac750a633f686eaafce) chore: bump tools\n* [`ff13660`](https://github.com/siderolabs/pkgs/commit/ff1366042afbe1f7fede53f5fc68d7e51d73e613) chore: bump kernel to 5.15.33\n* [`415020f`](https://github.com/siderolabs/pkgs/commit/415020fc27129aff334f3a6cd76a60f1d1064e79) chore: bump eudev, remove non-relevant default rules\n* [`6691342`](https://github.com/siderolabs/pkgs/commit/6691342a3a270954f87663a3b5efb0cf61b19979) chore: add rockpi4c\n* [`5bd5fad`](https://github.com/siderolabs/pkgs/commit/5bd5fad8fb2aae865797fa1f7374e82bce169067) chore: build u-boot spi image for rockpi\n* [`4dace49`](https://github.com/siderolabs/pkgs/commit/4dace49282b610d54b5b39917598a80ac3e1ce6a) fix: ipxe prompt arm64\n* [`6041fd7`](https://github.com/siderolabs/pkgs/commit/6041fd7963ca910a743c4b69f4fd8b9416a549af) chore: update to use latest tools (specifically go 1.18)\n* [`4b3e70e`](https://github.com/siderolabs/pkgs/commit/4b3e70e783906cf8b12b467d1a046ddeab695b94) chore: upstream u-boot for jetson nano\n* [`cc1c8c7`](https://github.com/siderolabs/pkgs/commit/cc1c8c7062c77d352f743fe4735bae5c39b00356) feat: update runc to 1.1.1\n* [`3baf4e4`](https://github.com/siderolabs/pkgs/commit/3baf4e4e1fda9ead732bee3578fc55f4f846d48a) chore: enable random trust CPU\n* [`df31920`](https://github.com/siderolabs/pkgs/commit/df319204730f890f35740837f2d6878a27f5728c) chore: disable sound\n* [`c27751b`](https://github.com/siderolabs/pkgs/commit/c27751b9f811d4b52701031c26a741333b45cbe9) chore: bump nvidia drivers to 510.60.02\n* [`ba98e20`](https://github.com/siderolabs/pkgs/commit/ba98e20d12daa200343869444a568fec231ed239) chore: bump kernel to 5.15.32\n* [`a76edfd`](https://github.com/siderolabs/pkgs/commit/a76edfdf941455237f8f16b7a833233257ae63a4) feat: update containerd to 1.6.2\n* [`0c38670`](https://github.com/siderolabs/pkgs/commit/0c38670333f788946090e42897b44871ac179ed1) chore: bump kernel to 5.15.31\n* [`bc4fb0c`](https://github.com/siderolabs/pkgs/commit/bc4fb0c2619e960d84984696aeb7e7e9368e38e9) chore: org update\n* [`41f291d`](https://github.com/siderolabs/pkgs/commit/41f291df5806b832c53ee6e042d3561a1bb52582) feat: update Flannel CNI to 1.0.1\n* [`58603ba`](https://github.com/siderolabs/pkgs/commit/58603bae512a70c5206d9fe4394139c5aa0f757c) chore: bump kernel to 5.15.30\n* [`d3bb262`](https://github.com/siderolabs/pkgs/commit/d3bb262acb78831dd3bf3ee57dc02fb6f628e78a) chore: bump kernel to 5.15.29\n* [`76a24b5`](https://github.com/siderolabs/pkgs/commit/76a24b5c9727b17f900331093c5bab86ba49f61e) chore: update openssl to 1.1.1n\n* [`490c7b7`](https://github.com/siderolabs/pkgs/commit/490c7b77052d182e09e25abe77ee27b4b54d7c7a) chore: enable aarch64 NVIDIA drivers\n* [`b794b7a`](https://github.com/siderolabs/pkgs/commit/b794b7a78c62a418edab4759a5f7bb7e0bd83dbe) chore: bump linux-firmware to 20220310\n* [`acda207`](https://github.com/siderolabs/pkgs/commit/acda20721dea1fa6af611a260c3a320f52a8ee16) chore: bump kernel to 5.15.28\n* [`e0fec11`](https://github.com/siderolabs/pkgs/commit/e0fec11a010e3958a617d7417be3a69fe43ba1b5) chore: bump nvidia driver to 510.54\n* [`0407f05`](https://github.com/siderolabs/pkgs/commit/0407f057edb8b96a7e51c5222f5b2ce171eb11c6) chore: bump kernel to 5.15.27\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>11 commits</summary>\n<p>\n\n* [`8c1f801`](https://github.com/siderolabs/tools/commit/8c1f8012f2d399bc119a0a35869e6bfd0013a7a8) chore: bump coreutils to 9.1\n* [`533d5c9`](https://github.com/siderolabs/tools/commit/533d5c9c05e4d8b4852e4f0d86d94fdeb0fddbde) chore: bump git to 2.35.2\n* [`a15cbee`](https://github.com/siderolabs/tools/commit/a15cbee68e65e6c5835a027879349f8fb6a0fa58) chore: bump go to 1.18.1\n* [`718ec10`](https://github.com/siderolabs/tools/commit/718ec10e0d80fceb46a93ad602cca0af25813f51) chore: enable conform\n* [`a60a332`](https://github.com/siderolabs/tools/commit/a60a33251d9bea2606b33f0a616a1da21e5361e9) chore: bump xz and gzip\n* [`c8a3d4d`](https://github.com/siderolabs/tools/commit/c8a3d4d894fd584ad8ca66c6b9864c447f87eab9) chore: update go to 1.18\n* [`1684fdc`](https://github.com/siderolabs/tools/commit/1684fdce5f46cf09401ffb28652f820722bf2d37) chore: bump expat to 2.4.8\n* [`7f5e44c`](https://github.com/siderolabs/tools/commit/7f5e44c1ed984732c5ab9bd22fec7d934829f2be) chore: bump zlib to 1.2.12\n* [`bfc99ca`](https://github.com/siderolabs/tools/commit/bfc99cae42ef06cf9ca30e5a5fd0771f64115cbd) chore: rename org\n* [`99be089`](https://github.com/siderolabs/tools/commit/99be089c5f17500146e7345f3228c52b2b61a9be) chore: update openssl to 1.1.1n\n* [`b63872b`](https://github.com/siderolabs/tools/commit/b63872bb8dba101a519ea2579b0e37f23b92e0e9) chore: update golang to 1.17.8\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`d9c3a27`](https://github.com/talos-systems/go-blockdevice/commit/d9c3a273886113e24809ef1e9930fc982318217d) feat: support probing FAT12/FAT16 filesystems\n* [`b374eb4`](https://github.com/talos-systems/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.5.0 -> v1.6.0\n* **github.com/BurntSushi/toml**                     v1.0.0 -> v1.1.0\n* **github.com/aws/aws-sdk-go**                      v1.43.8 -> v1.43.41\n* **github.com/containernetworking/plugins**         v1.1.0 -> v1.1.1\n* **github.com/cosi-project/runtime**                264f8fcd1a4f -> 639b4a2e6120\n* **github.com/docker/distribution**                 v2.8.0 -> v2.8.1\n* **github.com/docker/docker**                       v20.10.12 -> v20.10.14\n* **github.com/gdamore/tcell/v2**                    f057f0a857a1 -> v2.5.1\n* **github.com/google/nftables**                     211824995dcb -> 950e408d48c6\n* **github.com/insomniacslk/dhcp**                   3c283ff8b7dd -> 12fbdcb11b41\n* **github.com/jsimonetti/rtnetlink**                v1.1.0 -> v1.2.0\n* **github.com/rivo/tview**                          96063d6082f3 -> 9994674d60a8\n* **github.com/rs/xid**                              v1.3.0 -> v1.4.0\n* **github.com/siderolabs/extras**                   v1.0.0 -> v1.1.0-alpha.0-1-gac3b9a4\n* **github.com/siderolabs/pkgs**                     v1.0.0-6-g7c293d5 -> v1.1.0-alpha.0-28-g95f4418\n* **github.com/siderolabs/tools**                    v1.0.0-1-g4c77d96 -> v1.1.0-alpha.0-10-g8c1f801\n* **github.com/spf13/cobra**                         v1.3.0 -> v1.4.0\n* **github.com/stretchr/testify**                    v1.7.0 -> v1.7.1\n* **github.com/talos-systems/go-blockdevice**        v0.3.1 -> d9c3a2738861\n* **github.com/vishvananda/netlink**                 650dca95af54 -> v1.2.0-beta\n* **github.com/vmware-tanzu/sonobuoy**               v0.56.2 -> v0.56.4\n* **github.com/vmware/vmw-guestinfo**                cc1fd90d572c -> 510905f0efa3\n* **go.etcd.io/etcd/api/v3**                         v3.5.2 -> v3.5.3\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.2 -> v3.5.3\n* **go.etcd.io/etcd/client/v3**                      v3.5.2 -> v3.5.3\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.2 -> v3.5.3\n* **golang.org/x/net**                               27dd8689420f -> 290c469a71a5\n* **golang.org/x/sys**                               4e6760a101f9 -> 33da011f77ad\n* **golang.org/x/term**                              03fcf44c2211 -> e5f449aeb171\n* **golang.org/x/time**                              0e9765cccd65 -> 583f2d630306\n* **golang.zx2c4.com/wireguard/wgctrl**              fde48d68ee68 -> fec8f2be4827\n* **google.golang.org/grpc**                         v1.44.0 -> v1.45.0\n* **google.golang.org/protobuf**                     v1.27.1 -> v1.28.0\n* **k8s.io/api**                                     v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/apimachinery**                            v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/apiserver**                               v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/client-go**                               v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/component-base**                          v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/cri-api**                                 v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/kubectl**                                 v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/kubelet**                                 v0.23.5 -> v0.24.0-beta.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.63 -> v1.2.64\n\nPrevious release can be found at [v1.0.0](https://github.com/siderolabs/talos/releases/tag/v1.0.0)\n\n## [Talos 1.1.0-alpha.0](https://github.com/siderolabs/talos/releases/tag/v1.1.0-alpha.0) (2022-04-01)\n\nWelcome to the v1.1.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/siderolabs/talos/issues.\n\n### Component Updates\n\n* Kubernetes: 1.24.0-beta.0\n* Flannel: 0.17.0\n* runc: 1.1.1\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Spencer Smith\n* Tim Jones\n* Andrew Rynhard\n* Dmitriy Matrenichev\n* Steve Francis\n* Artem Chernyshev\n* Caleb Woodbine\n* Daniel Höxtermann\n* Jori Huisman\n* Nico Berlee\n* Serge Logvinov\n* Seán C McCord\n* Suraj Shirvankar\n* Tomasz Zurkowski\n\n### Changes\n<details><summary>90 commits</summary>\n<p>\n\n* [`e860312df`](https://github.com/siderolabs/talos/commit/e860312df099fa51422a3361982790fb457c1558) release(v1.1.0-alpha.0): prepare release\n* [`2ca5279e5`](https://github.com/siderolabs/talos/commit/2ca5279e56d154fdf21fab7ed5c73edb30494560) fix: retry manifest updates in upgrade-k8s\n* [`eeb756168`](https://github.com/siderolabs/talos/commit/eeb756168f31c8e7a1e0cb2f80e1ae2bc2eed0a9) feat: use kexec when resetting a node\n* [`1ed1f73e5`](https://github.com/siderolabs/talos/commit/1ed1f73e511f4a5cf4d1db5f97422cf1eb088fda) test: bump CAPI to 1.1.3\n* [`2ee1d2c72`](https://github.com/siderolabs/talos/commit/2ee1d2c72085df41ec0355bac0d33bedcb4f2786) feat: update Kuberentes to 1.24.0-beta.0\n* [`c26fa4ccc`](https://github.com/siderolabs/talos/commit/c26fa4ccc1e109c889c01384422f88387ad512a2) test: push GITHUB_TOKEN to the e2e-aws/gcp steps\n* [`95d900de7`](https://github.com/siderolabs/talos/commit/95d900de7799cfa9d0a16049586ba246bddb09d0) feat: use kubeconfig env var\n* [`0b407dd17`](https://github.com/siderolabs/talos/commit/0b407dd17e9515fecd8083fd5ac1fc84f6085106) feat: add dhcp-v6 NTP/DHCP-DUID\n* [`a140a6bad`](https://github.com/siderolabs/talos/commit/a140a6bad74bcf34e62e13b6efa63a17741eb5b1) docs: update releases shortcode in upgrade guide\n* [`12931dced`](https://github.com/siderolabs/talos/commit/12931dcedd38c407a2a03f692d910853130986db) fix: align partitions on 1M boundary\n* [`37f868e37`](https://github.com/siderolabs/talos/commit/37f868e37454f63a4dfe38d94dbbeef5bb40a2a8) fix: validate empty TLS config for registries\n* [`ca8b9c0a3`](https://github.com/siderolabs/talos/commit/ca8b9c0a3a15898d9562a6f22aded138d6c3ed7f) feat: update Kubernetes to 1.24.0-alpha.4\n* [`d9ec6b215`](https://github.com/siderolabs/talos/commit/d9ec6b2151e94c94eea44771e455555eaf1f257a) chore: drop dirty from abbreviated tag\n* [`08624fd0b`](https://github.com/siderolabs/talos/commit/08624fd0b12039e5a77ce43f14df65a6c95f7a39) docs: add banner to main page\n* [`fc23c7a59`](https://github.com/siderolabs/talos/commit/fc23c7a5952d87a51f29d61ead585bf060eeab1c) test: bump versions for upgrade tests\n* [`4bfe68610`](https://github.com/siderolabs/talos/commit/4bfe686105d5734b282f4817673972b71954e620) feat: update runc to 1.1.1\n* [`b315ed953`](https://github.com/siderolabs/talos/commit/b315ed95327a9b7cfb1f83a9da02e96bafecbb1d) chore: use go:embed instead of ldflags\n* [`a5d64fc81`](https://github.com/siderolabs/talos/commit/a5d64fc814f122fb7e282b97283a46ac0e5d6709) feat: update Flannel to 0.17.0\n* [`6d6eb3f6a`](https://github.com/siderolabs/talos/commit/6d6eb3f6a52626c8c94a75439133e7bc22b25e60) docs: fork docs for 1.1\n* [`1d55f05d1`](https://github.com/siderolabs/talos/commit/1d55f05d11e5a03a8de0e7ce5ec0167971b03135) docs: update index page\n* [`ad6b7ec1a`](https://github.com/siderolabs/talos/commit/ad6b7ec1a4347753488de3ab5813947f01967078) fix: enable etcd consistency on check startup\n* [`65a31f753`](https://github.com/siderolabs/talos/commit/65a31f7531a629b29fbf86ddcbaba20767475924) docs: re-add GA token\n* [`741c04832`](https://github.com/siderolabs/talos/commit/741c048320b931228336034ad17de10272ff5a77) docs: mark 1.0 docs as latest\n* [`e97433c8a`](https://github.com/siderolabs/talos/commit/e97433c8a37ca504577355d98c917e083aaedafe) docs: update jetson nano\n* [`6665e0f00`](https://github.com/siderolabs/talos/commit/6665e0f00c1c5d45123eb28d8755d0815af4822a) docs: code block copying\n* [`c41f2b216`](https://github.com/siderolabs/talos/commit/c41f2b216717db80e44654f54080a9d462946d45) docs: update whats-new-v1.0\n* [`0a36fbbf3`](https://github.com/siderolabs/talos/commit/0a36fbbf3ca579becd0a7f2e5a9715ff4196e8ae) docs: add release notes for 1.0\n* [`bd0035f6a`](https://github.com/siderolabs/talos/commit/bd0035f6a285f8b7e4c7c0b5013a271a8d18c5f4) docs: add NVIDIA docs\n* [`efa3f2898`](https://github.com/siderolabs/talos/commit/efa3f289853a47ae0d4bca5dbf656e527cf312dd) fix: correctly find partitions with config data (`metal-iso`)\n* [`9ebeec0d0`](https://github.com/siderolabs/talos/commit/9ebeec0d0ea4dd3cc1ba3b7171fe0a9bda943fe8) docs: fix incorrect path for talosconfig\n* [`9fef4540e`](https://github.com/siderolabs/talos/commit/9fef4540e1c7a7deb5d4745d3de17c6e5cc45369) docs: fix non-latest download links\n* [`f8ef6a081`](https://github.com/siderolabs/talos/commit/f8ef6a081e055637a5652366a6e344b6df911871) docs: add rook ceph configuration guide\n* [`e2666f58f`](https://github.com/siderolabs/talos/commit/e2666f58f5835db6ff8802b2370a480d8afcd8fc) chore: bump kernel to 5.15.32\n* [`957b2f233`](https://github.com/siderolabs/talos/commit/957b2f233c4b81eacdb5a3190c0070fa36ef0d82) chore: bump dependencies\n* [`0fd2aa08b`](https://github.com/siderolabs/talos/commit/0fd2aa08bd70d1c869e0dca136ca0c487bfcdefe) fix: correctly escape '.' in volume names\n* [`108fd03a7`](https://github.com/siderolabs/talos/commit/108fd03a72534cebbab7c09d63051021483566ac) fix: give up virtual IPs before the kubelet workloads are shut down\n* [`856e1333d`](https://github.com/siderolabs/talos/commit/856e1333dcfb8c0244ca8ead415025b32a4819fc) fix: use 'localhost' endpoint in docker provisioner on Windows\n* [`c5da38609`](https://github.com/siderolabs/talos/commit/c5da386092185fe4ed4173b08f95eac4e435ff99) docs: use variables and templates in the docs\n* [`4c83847b9`](https://github.com/siderolabs/talos/commit/4c83847b9091a4e8968544a515632a3391c06cd0) docs: target search results\n* [`67fb72d96`](https://github.com/siderolabs/talos/commit/67fb72d96db1cb772392dcab9b5a3a08ee50ff03) docs: add algolia versions to all content\n* [`5344d6e7c`](https://github.com/siderolabs/talos/commit/5344d6e7ce2b7febc6109acc566cf49346eca6d9) docs: fix extension service `path` dependency\n* [`9b9191c5e`](https://github.com/siderolabs/talos/commit/9b9191c5e7a4a03bb7fa271ab49b52874e63ee31) fix: increase intiial window and connection window sizes\n* [`7a88a0224`](https://github.com/siderolabs/talos/commit/7a88a0224155755a64c911165bf25bff775e1ec2) docs: show archived/pre-release banner based on version\n* [`e403470bf`](https://github.com/siderolabs/talos/commit/e403470bfefe7af0217d91cb18d900b7046254f9) docs: filter algolia results by latest\n* [`0497d5f9f`](https://github.com/siderolabs/talos/commit/0497d5f9fee404f68d09c0c500cb446126cfc6aa) docs: tag latest docs for search\n* [`a25425483`](https://github.com/siderolabs/talos/commit/a25425483518adc5bdd575c5fb8cc1b3464444ea) feat: update containerd to 1.6.2, Linux to 5.15.31\n* [`9b6422fcc`](https://github.com/siderolabs/talos/commit/9b6422fcc39c2f4e0723c0db0b6aefe3e4fc8267) feat: update CoreDNS to 1.9.1\n* [`020856f80`](https://github.com/siderolabs/talos/commit/020856f80dd93fb47170351c083602ffd516d113) docs: remove second search bar\n* [`5f27f4c63`](https://github.com/siderolabs/talos/commit/5f27f4c6384e9bb6df4fc969c3a318ad3052cf3f) docs: update asset links\n* [`9ff42b432`](https://github.com/siderolabs/talos/commit/9ff42b43202bb59845439a88014011ff002a7770) docs: fix redirects for /docs URLs\n* [`7283efd56`](https://github.com/siderolabs/talos/commit/7283efd568d35e6d2c68aa2bc101a7af86db8c62) chore: update the talosctl CNI download url\n* [`e0eee7fcc`](https://github.com/siderolabs/talos/commit/e0eee7fcc68f03243ae3248f84d50eb278998e07) test: use clusterctl.yaml overrides after org rename\n* [`73966f51e`](https://github.com/siderolabs/talos/commit/73966f51e83b7f166e4f7fe013bfed36e9b9a15a) docs: fix extensions\n* [`f9766edb5`](https://github.com/siderolabs/talos/commit/f9766edb52d6a029d12ac5d74fdb45b6294be058) docs: remove empty doc file\n* [`e06e1473b`](https://github.com/siderolabs/talos/commit/e06e1473b02cea088499c25f48a9b5e2b75cf879) feat: update golangci-lint to 1.45.0 and gofumpt to 0.3.0\n* [`a92c614b2`](https://github.com/siderolabs/talos/commit/a92c614b2f712fb046fb40e00b37773d1390df71) docs: add enterprise link to docs header\n* [`0ae7174ba`](https://github.com/siderolabs/talos/commit/0ae7174ba3a6c1674c77cf074087a68915e3e612) docs: update search settings and redirects\n* [`883d401f9`](https://github.com/siderolabs/talos/commit/883d401f9f62229305c2e24f58a0bb0e2e4bb409) chore: rename github organization to siderolabs\n* [`d1294d014`](https://github.com/siderolabs/talos/commit/d1294d014f5bee7fc1b5dfd6865f22b22f18f5f1) chore: add day-two tests for e2e-qemu\n* [`a6240e4b6`](https://github.com/siderolabs/talos/commit/a6240e4b67060357c4250e7e5a3a7960408f7c08) feat: update Linux to 5.15.30\n* [`e3fda049f`](https://github.com/siderolabs/talos/commit/e3fda049fee62f3c5cef4ae08eaf848826a6dbed) docs: overhaul all the docs\n* [`f47750726`](https://github.com/siderolabs/talos/commit/f477507262041a24def6ac9b32fa92d276d4d4e6) fix: the etcd recovery client and tests\n* [`69e07cddc`](https://github.com/siderolabs/talos/commit/69e07cddc77d6ff2c2477ec64f860ef824132000) fix: trigger properly `udevd` on types and actions\n* [`47d0e629d`](https://github.com/siderolabs/talos/commit/47d0e629d48930f6cb02dff32469bcb34440c73c) fix: clean up custom udev rules if the config is cleared\n* [`b6691b350`](https://github.com/siderolabs/talos/commit/b6691b35085e4e614752b60441c17fe39fe15928) chore: bump dependencies\n* [`27af5d41c`](https://github.com/siderolabs/talos/commit/27af5d41c6c58f4d2fc2f5c222d9de39539de1c0) feat: pause the boot process on some failures instead of rebooting\n* [`58cb9db1e`](https://github.com/siderolabs/talos/commit/58cb9db1e2b3d8fa86c0db0cf38c9f21a843da9d) feat: allow hardlinks in the system extension images\n* [`1e982808f`](https://github.com/siderolabs/talos/commit/1e982808fbac0a7f897bafacde348c5d83db38b2) fix: ignore pod CIDRs for kubelet node IPs\n* [`5e0c80f61`](https://github.com/siderolabs/talos/commit/5e0c80f6168ac8a171e35e0c3ee53d959c2dd80d) fix: ignore connection reset errors on k8s upgrade\n* [`c156580a3`](https://github.com/siderolabs/talos/commit/c156580a386e19d020b550b8459af339f440bf3e) fix: split regular network operation configuration and virtual IP\n* [`cd4d4c605`](https://github.com/siderolabs/talos/commit/cd4d4c6054107cd6c9274acb2abb4a045368a9fc) feat: relax extensions file structure validation\n* [`50594ab1a`](https://github.com/siderolabs/talos/commit/50594ab1a7e4d7d025f41873aaa1bf6954827d3e) fix: ignore terminated pods in pod health checks\n* [`9d69fb6b4`](https://github.com/siderolabs/talos/commit/9d69fb6b40f47061ff96bd7fb3952aa9c16ed601) feat: update Kubernetes to 1.23.5\n* [`327ce5aba`](https://github.com/siderolabs/talos/commit/327ce5aba352054837c9cc03c1ba3993a1d18158) fix: invert the condition to skip kubelet kernel checks\n* [`cf85b3f07`](https://github.com/siderolabs/talos/commit/cf85b3f07ccc3a6845f82f7853da298f5fce62a3) docs: update cilium inline install\n* [`84ee1795d`](https://github.com/siderolabs/talos/commit/84ee1795dc914574d299b1b0f1ede42bfaee110a) docs: update logo\n* [`cc7719c9d`](https://github.com/siderolabs/talos/commit/cc7719c9d014ca8c16828a84ccc95c0344bb34ed) docs: improve comments in security proto\n* [`caf800fe8`](https://github.com/siderolabs/talos/commit/caf800fe843aca5d3559ae5baf08b59db21cccd7) feat: implement D-Bus systemd-compatible shutdown for kubelet\n* [`6bec08429`](https://github.com/siderolabs/talos/commit/6bec084299062ec6df6e319d4a83313de97e3c67) feat: add talosctl completions to copy, usage, logs, restart and service\n* [`355b1a4be`](https://github.com/siderolabs/talos/commit/355b1a4bedd6755dbbaa9e98505f5c8540520bb5) fix: refresh etcd certs on startup/join\n* [`d256b5c5e`](https://github.com/siderolabs/talos/commit/d256b5c5e46ac87edf5681611eeda95fe091d922) docs: fix spelling mistakes\n* [`5fdedae20`](https://github.com/siderolabs/talos/commit/5fdedae208bfa561b7ca1a04f140adcee3deb565) chore: bump kernel to 5.15.28\n* [`18a21b5f2`](https://github.com/siderolabs/talos/commit/18a21b5f24baeea5b876d99b29f5397cc3617399) chore: add dependency images-essential -> images\n* [`714e5eca6`](https://github.com/siderolabs/talos/commit/714e5eca63ee0dd4a81ca5937081779829092111) chore: bump dependencies\n* [`58be4067e`](https://github.com/siderolabs/talos/commit/58be4067e6ddc7ba3a346469c30c435b560df377) docs: update README.md\n* [`c5fb20930`](https://github.com/siderolabs/talos/commit/c5fb20930555e5e31ea01e75aa3690d2cf628f29) docs: add loki note\n* [`f448cb4f3`](https://github.com/siderolabs/talos/commit/f448cb4f3c1620669fa34250e39aeec0e4002d37) feat: bump boot partition size to 1000 MiB\n* [`a095acb09`](https://github.com/siderolabs/talos/commit/a095acb09f225bce0e1c17f86576400549789608) chore: fix equinixMetal platform name\n* [`2a7f9a445`](https://github.com/siderolabs/talos/commit/2a7f9a4457bcb18e66b9ee6eb0ff49a290c381ce) fix: check for IPv6 before applying accept_ra\n* [`59681b8c9`](https://github.com/siderolabs/talos/commit/59681b8c9a47701092c7287c2375123134d3f9ba) fix: backport fixes from release-1.0 branch\n</p>\n</details>\n\n### Changes from siderolabs/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`d4f8e88`](https://github.com/siderolabs/extras/commit/d4f8e886147749e29026943cff3f5c701aaadf00) chore: update references after org rename\n</p>\n</details>\n\n### Changes from siderolabs/pkgs\n<details><summary>18 commits</summary>\n<p>\n\n* [`4b3e70e`](https://github.com/siderolabs/pkgs/commit/4b3e70e783906cf8b12b467d1a046ddeab695b94) chore: upstream u-boot for jetson nano\n* [`cc1c8c7`](https://github.com/siderolabs/pkgs/commit/cc1c8c7062c77d352f743fe4735bae5c39b00356) feat: update runc to 1.1.1\n* [`3baf4e4`](https://github.com/siderolabs/pkgs/commit/3baf4e4e1fda9ead732bee3578fc55f4f846d48a) chore: enable random trust CPU\n* [`df31920`](https://github.com/siderolabs/pkgs/commit/df319204730f890f35740837f2d6878a27f5728c) chore: disable sound\n* [`c27751b`](https://github.com/siderolabs/pkgs/commit/c27751b9f811d4b52701031c26a741333b45cbe9) chore: bump nvidia drivers to 510.60.02\n* [`ba98e20`](https://github.com/siderolabs/pkgs/commit/ba98e20d12daa200343869444a568fec231ed239) chore: bump kernel to 5.15.32\n* [`a76edfd`](https://github.com/siderolabs/pkgs/commit/a76edfdf941455237f8f16b7a833233257ae63a4) feat: update containerd to 1.6.2\n* [`0c38670`](https://github.com/siderolabs/pkgs/commit/0c38670333f788946090e42897b44871ac179ed1) chore: bump kernel to 5.15.31\n* [`bc4fb0c`](https://github.com/siderolabs/pkgs/commit/bc4fb0c2619e960d84984696aeb7e7e9368e38e9) chore: org update\n* [`41f291d`](https://github.com/siderolabs/pkgs/commit/41f291df5806b832c53ee6e042d3561a1bb52582) feat: update Flannel CNI to 1.0.1\n* [`58603ba`](https://github.com/siderolabs/pkgs/commit/58603bae512a70c5206d9fe4394139c5aa0f757c) chore: bump kernel to 5.15.30\n* [`d3bb262`](https://github.com/siderolabs/pkgs/commit/d3bb262acb78831dd3bf3ee57dc02fb6f628e78a) chore: bump kernel to 5.15.29\n* [`76a24b5`](https://github.com/siderolabs/pkgs/commit/76a24b5c9727b17f900331093c5bab86ba49f61e) chore: update openssl to 1.1.1n\n* [`490c7b7`](https://github.com/siderolabs/pkgs/commit/490c7b77052d182e09e25abe77ee27b4b54d7c7a) chore: enable aarch64 NVIDIA drivers\n* [`b794b7a`](https://github.com/siderolabs/pkgs/commit/b794b7a78c62a418edab4759a5f7bb7e0bd83dbe) chore: bump linux-firmware to 20220310\n* [`acda207`](https://github.com/siderolabs/pkgs/commit/acda20721dea1fa6af611a260c3a320f52a8ee16) chore: bump kernel to 5.15.28\n* [`e0fec11`](https://github.com/siderolabs/pkgs/commit/e0fec11a010e3958a617d7417be3a69fe43ba1b5) chore: bump nvidia driver to 510.54\n* [`0407f05`](https://github.com/siderolabs/pkgs/commit/0407f057edb8b96a7e51c5222f5b2ce171eb11c6) chore: bump kernel to 5.15.27\n</p>\n</details>\n\n### Changes from siderolabs/tools\n<details><summary>2 commits</summary>\n<p>\n\n* [`99be089`](https://github.com/siderolabs/tools/commit/99be089c5f17500146e7345f3228c52b2b61a9be) chore: update openssl to 1.1.1n\n* [`b63872b`](https://github.com/siderolabs/tools/commit/b63872bb8dba101a519ea2579b0e37f23b92e0e9) chore: update golang to 1.17.8\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`b374eb4`](https://github.com/talos-systems/go-blockdevice/commit/b374eb48148dc92a82d8bf9540432bb8531f73f3) fix: align partition to 1M boundary by default\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go**                v1.43.8 -> v1.43.26\n* **github.com/containernetworking/plugins**   v1.1.0 -> v1.1.1\n* **github.com/docker/distribution**           v2.8.0 -> v2.8.1\n* **github.com/docker/docker**                 v20.10.12 -> v20.10.14\n* **github.com/jsimonetti/rtnetlink**          v1.1.0 -> v1.1.1\n* **github.com/rivo/tview**                    96063d6082f3 -> 9994674d60a8\n* **github.com/rs/xid**                        v1.3.0 -> v1.4.0\n* **github.com/siderolabs/extras**             v1.0.0 -> v1.1.0-alpha.0\n* **github.com/siderolabs/pkgs**               v1.0.0-6-g7c293d5 -> v1.1.0-alpha.0-15-g4b3e70e\n* **github.com/siderolabs/tools**              v1.0.0-1-g4c77d96 -> v1.1.0-alpha.0-1-g99be089\n* **github.com/spf13/cobra**                   v1.3.0 -> v1.4.0\n* **github.com/stretchr/testify**              v1.7.0 -> v1.7.1\n* **github.com/talos-systems/go-blockdevice**  v0.3.1 -> b374eb48148d\n* **github.com/vmware-tanzu/sonobuoy**         v0.56.2 -> v0.56.3\n* **github.com/vmware/vmw-guestinfo**          cc1fd90d572c -> 510905f0efa3\n* **golang.org/x/net**                         27dd8689420f -> de3da57026de\n* **golang.org/x/sys**                         4e6760a101f9 -> 530d0810a4d0\n* **golang.zx2c4.com/wireguard/wgctrl**        fde48d68ee68 -> 056925b7df31\n* **google.golang.org/grpc**                   v1.44.0 -> v1.45.0\n* **google.golang.org/protobuf**               v1.27.1 -> v1.28.0\n* **k8s.io/api**                               v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/apimachinery**                      v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/apiserver**                         v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/client-go**                         v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/component-base**                    v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/cri-api**                           v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/kubectl**                           v0.23.5 -> v0.24.0-beta.0\n* **k8s.io/kubelet**                           v0.23.5 -> v0.24.0-beta.0\n\nPrevious release can be found at [v1.0.0](https://github.com/siderolabs/talos/releases/tag/v1.0.0)\n\n## [Talos 0.15.0-alpha.2](https://github.com/talos-systems/talos/releases/tag/v0.15.0-alpha.2) (2022-02-11)\n\nWelcome to the v0.15.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Apply Config Enhancements\n\n`talosctl apply/patch/edit` cli commands got revamped.\nSeparate flags `--on-reboot`, `--immediate`, `--interactive` were replaced\nwith a single `--mode` flag that can take the following values:\n- `auto` new mode that automatically applies the configuration in immediate/reboot mode.\n- `no-reboot` force apply immediately, if not possible, then fail.\n- `reboot` force reboot with apply config.\n- `staged` write new machine configuration to STATE, but don't apply it (it will be applied after a reboot).\n- `interactive` starts interactive installer, only for `apply`.\n\n\n### Pinned Kubernets Version\n\nCommand `talosctl gen config` now defaults to Kubernetes version pinning in the generate machine configuration.\nPreviously default was to omit explicit Kubernetes version, so Talos picked up the default version it was built against.\nOld behavior can be achieved by specifying empty flag value: `--kubernetes-version=`.\n\n\n### Machine Configuration\n\nTalos now preserves machine configuration as it was submitted to the node.\n\n\n### Machine Configuration Patching\n\n`talosctl` commands which accept JSON patches (`gen config`, `cluster create`, `patch machineconfig`) now support multiple patches, loading patches\nfrom files with `@file.json` syntax, and support loading from YAML format.\n\n\n### Platform Support\n\nTalos now supports Oracle Cloud.\n\nPlatform network configuration was rewritten to avoid modifying Talos machine configuration.\nNetwork configuration is performed independent of the machine configuration presence, so it works\neven if Talos is booted in maintenance mode (without machine configuration is platform userdata).\n\n\n### SBC Support\n\nTalos now supports Jetson Nano SBC.\n\n\n### Static Pods in the Machine Configuration\n\nTalos now accepts static pod definitions in the `.machine.pods` key of the machine configuration.\nPlease note that static pod definitions are not validated by Talos.\nStatic pod definitions can be updated without a node reboot.\n\n\n### System Extensions\n\nSystem extensions allow extending Talos root filesystem, which enables a set of different features, including custom\ncontainer runtimes, additional firmware, etc.\n\nSystem extensions are only activated during Talos installation (or upgrade), and with system extensions installed, Talos\nroot filesystem is still immutable and read-only.\n\nPlease see [extensions repository](https://github.com/talos-systems/extensions) and [documentation](https://www.talos.dev/docs/v0.15/guides/system-extensions/) for more information.\n\n\n### Component Updates\n\n* Linux: 5.15.23\n* Kubernetes: 1.23.3\n* CoreDNS: 1.8.7\n* etcd: 3.5.2\n* containerd: 1.6.0-rc.0\n* runc: 1.1.0\n\nTalos is built with Go 1.17.7\n\n\n### Wipe System Kernel Parameter\n\nAdded new kernel parameter `talos.experimental.wipe=system` which can help resetting system disk for the machine\nand start over with a fresh installation.\nSee [Resetting a Machine](https://www.talos.dev/docs/v0.15/guides/resetting-a-machine/#kernel-parameter) on how to use it.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Artem Chernyshev\n* Spencer Smith\n* Serge Logvinov\n* Seán C McCord\n* Florian Klink\n* Steve Francis\n* Andrew Rynhard\n* Anthony Rabbito\n* Bernard Sébastien\n* Charlie Haley\n* Eric Wohltman\n* Niklas Metje\n* Philipp Sauter\n* Shahar Naveh\n* Tim Jones\n* nebulait\n\n### Changes\n<details><summary>137 commits</summary>\n<p>\n\n* [`1e9f0ad4c`](https://github.com/talos-systems/talos/commit/1e9f0ad4c6abcfb5244f0d4159b7085b387f2cc1) feat: update Go to 1.17.7, Linux to 5.15.23\n* [`fef99892d`](https://github.com/talos-systems/talos/commit/fef99892d5ba11c9c87d047e23fb7023de5116a6) chore: pin kubernetes version to `talosctl gen config`\n* [`bcf928134`](https://github.com/talos-systems/talos/commit/bcf928134c8d1a17d69d425061350040d3ed15a4) feat: udev extensions support\n* [`47619f832`](https://github.com/talos-systems/talos/commit/47619f8320f8e03246ffa43d19dcd759b1d9511c) docs: update system extensions guide with grammar fixes\n* [`2bcceb6e4`](https://github.com/talos-systems/talos/commit/2bcceb6e437b5e30f856ea495eccdb0ab4d5e1ca) chore: disable TIPC and B.A.T.M.A.N\n* [`c6bca1b33`](https://github.com/talos-systems/talos/commit/c6bca1b33b5b0522ee7b997c2bcc5afadc991a94) docs: add guide on system extensions\n* [`492b156da`](https://github.com/talos-systems/talos/commit/492b156dabca6552002881f9d8ca57b02a04add2) feat: implement static pods via machine configuration\n* [`6fadfa8db`](https://github.com/talos-systems/talos/commit/6fadfa8dbcc22b80dc83ed477f81f5c55727298c) fix: parse properly IPv6 address in the cmdline `ip=` arg\n* [`d991f3982`](https://github.com/talos-systems/talos/commit/d991f3982c329e97c78d068eae0abf02020d21a9) chore: update the kernel with IGC driver enabled\n* [`cbc9610be`](https://github.com/talos-systems/talos/commit/cbc9610be66f4b2552e2c7374118cfa71764a148) feat: sysctl system optimization\n* [`8b6d6220d`](https://github.com/talos-systems/talos/commit/8b6d6220d3799cb79cd66267017b54d0a09e2c63) fix: parse interface ip correctly (nocloud)\n* [`54632b1be`](https://github.com/talos-systems/talos/commit/54632b1be7b08440b562dfb0bf44ef9784317dbf) docs: fix developing Talos docs\n* [`0da370dfe`](https://github.com/talos-systems/talos/commit/0da370dfefecdba9c981ccafa3255c4dc256d4d2) test: unlock CABPT/CACPPT provider versions\n* [`df0e388a4`](https://github.com/talos-systems/talos/commit/df0e388a4fa1995124d4e722fc1b8a1bfdffed58) feat: extract firmware part of system extensions into initramfs\n* [`8899dd349`](https://github.com/talos-systems/talos/commit/8899dd34945105e7276fa453341cc0aa4dbe51d4) chore: add json-tags for SecretsBundle\n* [`4f391cd5c`](https://github.com/talos-systems/talos/commit/4f391cd5c540a0a955f294d628adc7437b7513b5) chore: bump kernel to 5.15.22\n* [`6bd07406e`](https://github.com/talos-systems/talos/commit/6bd07406e1895d190b5bbd9838ee84f85d02cd3f) feat: disable reboots via kexec\n* [`1e3f2f952`](https://github.com/talos-systems/talos/commit/1e3f2f95275aa5f71abe931015799caaca42bf61) fix: validate kubelet node IP subnets correctly\n* [`d211bff47`](https://github.com/talos-systems/talos/commit/d211bff47d661697926fece893784519dbf4f8f3) feat: enable accept_ra when IPv6 forwarding\n* [`930205831`](https://github.com/talos-systems/talos/commit/93020583195d066e879ccb19da38b8cfd6b93e96) chore: update kernel to 5.15.21\n* [`c7186ed08`](https://github.com/talos-systems/talos/commit/c7186ed08013efaa9957fe064152ccfca8ec1ab8) chore: bump dependencies\n* [`9ee470f95`](https://github.com/talos-systems/talos/commit/9ee470f9556462dd3fda656d58358e7ae78f4d47) feat: set /etc/localtime to UTC\n* [`c34768367`](https://github.com/talos-systems/talos/commit/c347683670d489230a2e87e4f04f05009173aca0) fix: disable auto-tls for etcd\n* [`9bffc7e8d`](https://github.com/talos-systems/talos/commit/9bffc7e8d5eff6d5ce0b83d627557f4110fc5c58) fix: pass proper sequence to shutdown sequence on ACPI shutdown\n* [`e47387e41`](https://github.com/talos-systems/talos/commit/e47387e4197974366844b2741cae345666d474da) chore: bump CAPI to 1.0.4\n* [`5462f5ed1`](https://github.com/talos-systems/talos/commit/5462f5ed18b7ffe023b3a41f1ac7d9b4ca9b726d) feat: update etcd to 3.5.2\n* [`f6fa12e53`](https://github.com/talos-systems/talos/commit/f6fa12e53697c763bd0463d91e92a446eb1ac2f7) docs: update upgrading Talos, Kubernetes, and Docker guides\n* [`5484579c1`](https://github.com/talos-systems/talos/commit/5484579c1a897f2378aacbef94bd4381d6b8299c) feat: allow link scope routes in the machine config\n* [`56b83b087`](https://github.com/talos-systems/talos/commit/56b83b08730c13910b0e5eb724decaf27e187047) feat: enable persistence for docker provider\n* [`949464e4b`](https://github.com/talos-systems/talos/commit/949464e4b6e1e807d9299b451758a6d144725fb1) fix: use leaf certificate in the apid RBAC check\n* [`446972f21`](https://github.com/talos-systems/talos/commit/446972f2113ada8e6c511ce56f630ec170ef0f26) chore: bump kernel to 5.15.19\n* [`fe40e7b1b`](https://github.com/talos-systems/talos/commit/fe40e7b1b39281f9bc14393b8c9db55ab6d6f8cd) feat: drain node on shutdown\n* [`7f0b3aae0`](https://github.com/talos-systems/talos/commit/7f0b3aae0a37b519623422841e3cbcda8bdd21a1) feat: add multiple config patches, patches from files, YAML support\n* [`202290be7`](https://github.com/talos-systems/talos/commit/202290be7b9b04ec909d369326d463c3b462eafa) docs: update Kubernetes upgrade video\n* [`036644f7a`](https://github.com/talos-systems/talos/commit/036644f7a03383922fd8407b1d514c7f79d44d0d) chore: bump kernel to 5.15.18\n* [`dcde2c4f6`](https://github.com/talos-systems/talos/commit/dcde2c4f68982974d6e55c52ba0fa8665e7f40b8) chore: update k8s upgrade message\n* [`1c949335c`](https://github.com/talos-systems/talos/commit/1c949335cc41cc9157e4c7dead44826c99b336f3) docs: add documentation for Hyper-V\n* [`7f9790912`](https://github.com/talos-systems/talos/commit/7f9790912308dfa88457a6db4f94728e5337c399) fix: clean up containerd state on installer run/validate\n* [`8b98d8eb3`](https://github.com/talos-systems/talos/commit/8b98d8eb3976cb8e64ffa94cfdf0305216f7dbeb) docs: clarify Filebeat example\n* [`74c03120c`](https://github.com/talos-systems/talos/commit/74c03120cf1da93d79fd786036e8d296c00c221e) docs: replace Talos upgrades video\n* [`65e64d425`](https://github.com/talos-systems/talos/commit/65e64d425e0253ae6780d52063d227c47df1ae29) chore: update kernel to stable 5.15.17\n* [`4245f72d3`](https://github.com/talos-systems/talos/commit/4245f72d3ff3712742d6d7d6ec3310f40f900c79) feat: add --extra-uefi-search-paths option\n* [`7ffeb6c2e`](https://github.com/talos-systems/talos/commit/7ffeb6c2e2bef1482b641725e4075c44264e899e) docs: update oracle cloud example\n* [`151c9df09`](https://github.com/talos-systems/talos/commit/151c9df091f32d00748e7e5effbb2c759916e8b9) chore: add CSI tests for e2e-qemu\n* [`cdb621c82`](https://github.com/talos-systems/talos/commit/cdb621c82e15026a851bbfb567afd834d88165e7) feat: provide a way to list installed system extensions\n* [`abfb25812`](https://github.com/talos-systems/talos/commit/abfb2581289c72c9e7bda8bc1f7bc2aa2ba758f7) feat: share `/lib/firmware` across initramfs and rootfs\n* [`ebec5d4a0`](https://github.com/talos-systems/talos/commit/ebec5d4a0c20fe20aa1fd5d1f9b28c0745a08fe7) feat: support full disk path in the diskSelector\n* [`831f65a07`](https://github.com/talos-systems/talos/commit/831f65a07f3b0a93ee9f38327dc5b84ce97a3237) fix: close client provider instead of Talos client in the upgrade module\n* [`0bf161dff`](https://github.com/talos-systems/talos/commit/0bf161dffb8c7805c44a4fb2c3db191dfa901b88) test: add integration test for system extensions\n* [`7b3962745`](https://github.com/talos-systems/talos/commit/7b3962745625decb720c53ca3b454f65079715f6) fix: handle 404 errors from AWS IMDS correctly\n* [`85782faa2`](https://github.com/talos-systems/talos/commit/85782faa24772dc9fa757aac3803a196f0325544) feat: update Kubernetes to 1.23.3\n* [`c5e5922e5`](https://github.com/talos-systems/talos/commit/c5e5922e536533badcaae568171f1b78cac40105) chore: bump dependencies\n* [`b3c3ef29b`](https://github.com/talos-systems/talos/commit/b3c3ef29bdf0f21805adf3489972cb92c98c00aa) feat: install system extensions\n* [`a0889600f`](https://github.com/talos-systems/talos/commit/a0889600fb19f62a2503244c32364808777ffdcc) chore: fix golangci-lint install\n* [`a50c42980`](https://github.com/talos-systems/talos/commit/a50c42980febfe51ba1e4ce750768f01de8c2d47) fix: use #!/usr/bin/env bash as shebang instead of #!/bin/bash\n* [`4464b725c`](https://github.com/talos-systems/talos/commit/4464b725c4fea4234961959e884426c384822eab) fix: qemu: always use runtime.GOARCH for CNI bundle\n* [`e7379c81b`](https://github.com/talos-systems/talos/commit/e7379c81b222341633d6f1011bcdbffa1bf429fc) release(v0.15.0-alpha.1): prepare release\n* [`58eb3600f`](https://github.com/talos-systems/talos/commit/58eb3600fc44dc2fccaa82322207291ffd807205) fix: enforce reasonable TLS min tls-min-version\n* [`b8d4c5dfa`](https://github.com/talos-systems/talos/commit/b8d4c5dfad4585c0af52287513176411a79fc20c) fix: use correct error in `kernel_param_spec` Modify call handling\n* [`4961d6867`](https://github.com/talos-systems/talos/commit/4961d6867cadab5e8b48e73355b23b91d36f70b4) docs: drop talos.interface kernel arg\n* [`b1e61fa5b`](https://github.com/talos-systems/talos/commit/b1e61fa5b1bcd5affd42b498711b9e3378344c33) chore: update Linux to 5.15.16\n* [`d4b844593`](https://github.com/talos-systems/talos/commit/d4b844593587ae3f82efcdbdfe0f24cda4262474) feat: support CRI configuration merging and reimplement registry config\n* [`f94c8c6e1`](https://github.com/talos-systems/talos/commit/f94c8c6e1c3915c962c331943120bdfd2b76259f) feat: update Kubernetes to 1.23.2\n* [`21f497b3e`](https://github.com/talos-systems/talos/commit/21f497b3e20f3b1cc9b744f1787ba80cf396d3e0) feat: install readonly overlay mounts during talos chroot sequence\n* [`9ad5a67d2`](https://github.com/talos-systems/talos/commit/9ad5a67d21b0788d1b43f1bea8e39c003a4a8ecc) feat: inject platform network configuration as network resources\n* [`907f8cbfb`](https://github.com/talos-systems/talos/commit/907f8cbfb8ed28cf399b9797230790718fc04a58) docs: fix patch flag\n* [`caa434426`](https://github.com/talos-systems/talos/commit/caa43442640744a0aa7a17aa1a205f1641e6445a) docs: add documentation on developing Talos\n* [`16eeb6776`](https://github.com/talos-systems/talos/commit/16eeb677625c0859d73b82948c1a073ba6e17e8d) docs: readme updates\n* [`3c0737027`](https://github.com/talos-systems/talos/commit/3c0737027b5574581a6461211199274ee709b1da) chore: update release notes\n* [`6d8bea5d5`](https://github.com/talos-systems/talos/commit/6d8bea5d559b1156f7d0b576b7b5784c25cd3595) feat: jetson nano SoC\n* [`1d8955ebe`](https://github.com/talos-systems/talos/commit/1d8955ebe43259a5e072b8a89f37cb728b6fcf53) feat: update CoreDNS to 1.8.7\n* [`6af83afd5`](https://github.com/talos-systems/talos/commit/6af83afd5aba64ffa7887d62f84c434109b7579b) fix: handle multiple-IP cluster nodes\n* [`43b2d8137`](https://github.com/talos-systems/talos/commit/43b2d8137116863cfc5ca969c429c13483465b01) chore: bump dependencies\n* [`529e80f4f`](https://github.com/talos-systems/talos/commit/529e80f4f529f066872b5768cd80eeeb7b766a31) docs: update home page and footer\n* [`37630e70c`](https://github.com/talos-systems/talos/commit/37630e70ccc9950e139bf7fcfcded6a18d0c7a01) Update twitter link\n* [`af440919b`](https://github.com/talos-systems/talos/commit/af440919bbaf12f414f04a5a621c1e2d5ed84ae2) fix: avoid panic in config loading/validation\n* [`4b8e9de59`](https://github.com/talos-systems/talos/commit/4b8e9de599812f82275605a93de7f5c05471f7f5) docs: add guide on adding proprietary kernel modules\n* [`833dc4169`](https://github.com/talos-systems/talos/commit/833dc4169a9702383930816d13be39f6b81c7a31) docs: rework vmware assets\n* [`2869b5eea`](https://github.com/talos-systems/talos/commit/2869b5eeacf0b6c96aedcb605bfa8a5f9fb87625) feat: add oraclecloud.com platform support\n* [`f3ec24beb`](https://github.com/talos-systems/talos/commit/f3ec24bebf0aaa7983228a09b21a67b9a2a098c1) fix: vmware documentation typo\n* [`2f2bdb26a`](https://github.com/talos-systems/talos/commit/2f2bdb26aa5367066c12a6402af554b7a5a148d6) feat: replace flags with --mode in `apply`, `edit` and `patch` commands\n* [`b09be2a69`](https://github.com/talos-systems/talos/commit/b09be2a69c6b6f8064a676fc014e6e60ea01a08d) docs: update index.md and sync across versions\n* [`ca65b918a`](https://github.com/talos-systems/talos/commit/ca65b918a7292ae53d40e410cca4e89be91e4261) docs: add nocloud documentation\n* [`59437d6d8`](https://github.com/talos-systems/talos/commit/59437d6d8360ad7dd8f801797ab91ac0791270f7) fix: filter down nameservers for docker-based cluster create\n* [`194eaa6f2`](https://github.com/talos-systems/talos/commit/194eaa6f22249fe4f43958bd897744a2cc57279f) chore: clean up /usr/bin from unneeded files\n* [`74e727240`](https://github.com/talos-systems/talos/commit/74e7272401ccb75464dd42ed0427d73842af74e1) docs: update office office\n* [`539af338c`](https://github.com/talos-systems/talos/commit/539af338c4b8f6e4291654f66628c81022aeda72) docs: update vmware docs\n* [`279a3fda7`](https://github.com/talos-systems/talos/commit/279a3fda7ba24037e06377f01cc495207722caa9) feat: update Go to 1.17.6, containerd to 1.5.9\n* [`3d3088941`](https://github.com/talos-systems/talos/commit/3d308894120092fe095b41970d6341362ab80a6b) chore: bump Go dependencies\n* [`d02d944ec`](https://github.com/talos-systems/talos/commit/d02d944ec767441612b84c164af31bc27c0c0659) chore: provide umarshal from YAML methods for network resource specs\n* [`2e735714d`](https://github.com/talos-systems/talos/commit/2e735714d9218cbc335d9c418730c146821fb8d4) fix: derive machine-id from node identity\n* [`d8a2721e1`](https://github.com/talos-systems/talos/commit/d8a2721e129be33f4a3c37be1bf5b89a1cd91685) test: update CAPI components to latest\n* [`7dff8a53e`](https://github.com/talos-systems/talos/commit/7dff8a53ee7bc37afe9dc216ca8a9113718d76af) fix: ignore missing init.yaml for cluster create\n* [`f4516c7d8`](https://github.com/talos-systems/talos/commit/f4516c7d847d905b49b4e2127eb86a1f38156d53) chore: bump dependencies\n* [`944f13221`](https://github.com/talos-systems/talos/commit/944f13221d50694d5c59ace1c12f8769d7ade9ae) chore: fix release pipeline\n* [`cb548a368`](https://github.com/talos-systems/talos/commit/cb548a368a75ca379209213948518c880b242b0c) release(v0.15.0-alpha.0): prepare release\n* [`da0b36e61`](https://github.com/talos-systems/talos/commit/da0b36e616f7da7eb0c6791b9cf5e4ee2757f08f) feat: introduce `talos.exp.wipe` kernel param to wipe system disk\n* [`c079eb32b`](https://github.com/talos-systems/talos/commit/c079eb32bd7fc19d506146e2a9edf5b406e25e02) refactor: use AWS SDK to access AWS metadata service\n* [`2f4b9d8d6`](https://github.com/talos-systems/talos/commit/2f4b9d8d6d10c0aa753f405282aa99696b923bb4) feat: make machine configuration read-only in Talos (almost)\n* [`524f83d3d`](https://github.com/talos-systems/talos/commit/524f83d3d8af3857f178c179a9552a5f32b70f47) feat: use official Go SDK to fetch GCP instance metadata\n* [`d2a7e082c`](https://github.com/talos-systems/talos/commit/d2a7e082c24d0b42820b3ea454329a19178ba0a4) test: retry in discovery tests\n* [`f4219e530`](https://github.com/talos-systems/talos/commit/f4219e530ca7635ada666ae69071746d698939a8) chore: remove unused methods in AWS platform\n* [`35bc2940e`](https://github.com/talos-systems/talos/commit/35bc2940e375b99e0d6e22a26a05c25d642bf35a) fix: kexec on RPI4\n* [`f235cfbae`](https://github.com/talos-systems/talos/commit/f235cfbaed8b5254e19616bfaaa8b48fd7d32e64) fix: multiple usability fixes\n* [`b3fbb2f31`](https://github.com/talos-systems/talos/commit/b3fbb2f312d5de0c14ffee567956b868a317aba7) test: don't build all images in the default CI pipeline\n* [`dac550a50`](https://github.com/talos-systems/talos/commit/dac550a50f4793194e4aeee98702a052925a0e88) docs: fix troubleshooting guide\n* [`83e8bec6b`](https://github.com/talos-systems/talos/commit/83e8bec6b9d4c0ecc689f45b15d7203bbf9bf0cc) feat: update Linux to 5.15.11\n* [`d5a82b37e`](https://github.com/talos-systems/talos/commit/d5a82b37eb147a68ffd08fc8ec800edc92da9f9c) feat: remove `ApplyDynamicConfig`\n* [`3623da136`](https://github.com/talos-systems/talos/commit/3623da136bde51422ba1aec06e22dea2e3dfa756) feat: provide a way to load Linux kernel modules\n* [`4d1514add`](https://github.com/talos-systems/talos/commit/4d1514add6e0b972aee26a8ad63ef8f972050d46) docs: update Mayastor deployment process\n* [`cff1ff6d5`](https://github.com/talos-systems/talos/commit/cff1ff6d5c3a68063ed2c0c063daadf2474cc43f) feat: shell completion for `list`, `read`\n* [`19728437e`](https://github.com/talos-systems/talos/commit/19728437ead7ab6e95afc8bd7f70be3f861c9a6e) feat: output IPs when etcd needs to be bootstrapped\n* [`c297d66a1`](https://github.com/talos-systems/talos/commit/c297d66a130cba708fcb42f8f2e6b356c36f5109) test: attempt number on two on proper retries in CLI time tests\n* [`dc299da9e`](https://github.com/talos-systems/talos/commit/dc299da9e8e885b7a44c184ef3d251726aa934a8) docs: add arm64 option to talosctl download\n* [`f49f40a33`](https://github.com/talos-systems/talos/commit/f49f40a3361381e51d6986547be12ec3b4a3f24a) fix: pass path to conformance retrieve results\n* [`942c8074f`](https://github.com/talos-systems/talos/commit/942c8074fd14478089769e2b8132ea2796109721) docs: fork docs for 0.15\n* [`880a7782c`](https://github.com/talos-systems/talos/commit/880a7782cbc703b38a2ff2b3d76c1eda621524ba) docs: update documentation for 0.14.0 release\n* [`dc9a0cfe9`](https://github.com/talos-systems/talos/commit/dc9a0cfe94b59c688d65ef74ebc04f273b8a72fb) chore: bump Go dependencies\n* [`773496935`](https://github.com/talos-systems/talos/commit/7734969356abac8355a31da08d47fafd4000e814) fix: config apply immediate\n* [`17c147488`](https://github.com/talos-systems/talos/commit/17c14748815e2ab928a9c0c8a079f65a63f0194e) test: retry `talosctl time` call in the tests\n* [`acf1ac0f1`](https://github.com/talos-systems/talos/commit/acf1ac0f1aff929ae9bf66b1c0322b4f83c0fef1) feat: show human-readable aliases in `talosctl get rd`\n* [`5532867b0`](https://github.com/talos-systems/talos/commit/5532867b05bb596f42516ff121b0a3a97176b3d1) refactor: rewrite the implementation of Processes API\n* [`80350861a`](https://github.com/talos-systems/talos/commit/80350861a2c1cee234d2f3a571d3993841c554d9) feat: update Kubernetes to 1.23.1\n* [`4c96e936e`](https://github.com/talos-systems/talos/commit/4c96e936ed467ae7838258699bdd83fd6da15ae6) docs: add cilium guide\n* [`e3f2acb5e`](https://github.com/talos-systems/talos/commit/e3f2acb5e57f9b3e7b11986f180e287f1f693079) refactor: rewrite the check for unknown keys in the machine configuration\n* [`4175396a8`](https://github.com/talos-systems/talos/commit/4175396a89f836bb1835d201b59224b286eeb62a) refactor: use update go-blockdevice library with allocation fixes\n* [`b58f567a1`](https://github.com/talos-systems/talos/commit/b58f567a133b661cc045a995dd29ab5090dfe194) refactor: optimize Runtime config interface to avoid config marshaling\n* [`bb355c9ab`](https://github.com/talos-systems/talos/commit/bb355c9ab38a417ed471bf3ce7b1879609f5e806) chore: remove govalidator library\n* [`3af56bd2e`](https://github.com/talos-systems/talos/commit/3af56bd2e70e8964cc48b430b1e67e48052af682) test: update capi templates to v1beta1\n* [`936b4c4ce`](https://github.com/talos-systems/talos/commit/936b4c4cee87697b3f08d51f22208b44b8a02db5) fix: update DHCP library with the panic fix\n* [`ab42886bf`](https://github.com/talos-systems/talos/commit/ab42886bf333dcaa9d3a1b765781ab19354de397) fix: allow kubelet to be started via the API\n* [`ec641f729`](https://github.com/talos-systems/talos/commit/ec641f7296ce62b2f9ba1353ff2eba70c2287c08) fix: use default time servers in time API if none are configured\n* [`79f213eec`](https://github.com/talos-systems/talos/commit/79f213eec65af46c4a3a4c4494d67ffc1b0a53ec) fix: cleanup affiliates\n* [`2dd0b5b68`](https://github.com/talos-systems/talos/commit/2dd0b5b68aa5b8efbc9b0bc4f8ebc159e2d991ab) chore: update Go to 1.17.5\n* [`97ffa7a64`](https://github.com/talos-systems/talos/commit/97ffa7a645d7db93ee58032795f91131f6950e89) feat: upgrade kubelet version in `talosctl upgrade-k8s`\n* [`5bc5123eb`](https://github.com/talos-systems/talos/commit/5bc5123eb91386ca12e7e7f9fc0f66637343a642) docs: document `ip=` kernel argument\n* [`8e1d0bfb5`](https://github.com/talos-systems/talos/commit/8e1d0bfb5fbaf0849bdd07b73a8e3bda4e8c3b75) feat: update Kubernetes to 1.23.0\n</p>\n</details>\n\n### Changes since v0.15.0-alpha.1\n<details><summary>56 commits</summary>\n<p>\n\n* [`1e9f0ad4c`](https://github.com/talos-systems/talos/commit/1e9f0ad4c6abcfb5244f0d4159b7085b387f2cc1) feat: update Go to 1.17.7, Linux to 5.15.23\n* [`fef99892d`](https://github.com/talos-systems/talos/commit/fef99892d5ba11c9c87d047e23fb7023de5116a6) chore: pin kubernetes version to `talosctl gen config`\n* [`bcf928134`](https://github.com/talos-systems/talos/commit/bcf928134c8d1a17d69d425061350040d3ed15a4) feat: udev extensions support\n* [`47619f832`](https://github.com/talos-systems/talos/commit/47619f8320f8e03246ffa43d19dcd759b1d9511c) docs: update system extensions guide with grammar fixes\n* [`2bcceb6e4`](https://github.com/talos-systems/talos/commit/2bcceb6e437b5e30f856ea495eccdb0ab4d5e1ca) chore: disable TIPC and B.A.T.M.A.N\n* [`c6bca1b33`](https://github.com/talos-systems/talos/commit/c6bca1b33b5b0522ee7b997c2bcc5afadc991a94) docs: add guide on system extensions\n* [`492b156da`](https://github.com/talos-systems/talos/commit/492b156dabca6552002881f9d8ca57b02a04add2) feat: implement static pods via machine configuration\n* [`6fadfa8db`](https://github.com/talos-systems/talos/commit/6fadfa8dbcc22b80dc83ed477f81f5c55727298c) fix: parse properly IPv6 address in the cmdline `ip=` arg\n* [`d991f3982`](https://github.com/talos-systems/talos/commit/d991f3982c329e97c78d068eae0abf02020d21a9) chore: update the kernel with IGC driver enabled\n* [`cbc9610be`](https://github.com/talos-systems/talos/commit/cbc9610be66f4b2552e2c7374118cfa71764a148) feat: sysctl system optimization\n* [`8b6d6220d`](https://github.com/talos-systems/talos/commit/8b6d6220d3799cb79cd66267017b54d0a09e2c63) fix: parse interface ip correctly (nocloud)\n* [`54632b1be`](https://github.com/talos-systems/talos/commit/54632b1be7b08440b562dfb0bf44ef9784317dbf) docs: fix developing Talos docs\n* [`0da370dfe`](https://github.com/talos-systems/talos/commit/0da370dfefecdba9c981ccafa3255c4dc256d4d2) test: unlock CABPT/CACPPT provider versions\n* [`df0e388a4`](https://github.com/talos-systems/talos/commit/df0e388a4fa1995124d4e722fc1b8a1bfdffed58) feat: extract firmware part of system extensions into initramfs\n* [`8899dd349`](https://github.com/talos-systems/talos/commit/8899dd34945105e7276fa453341cc0aa4dbe51d4) chore: add json-tags for SecretsBundle\n* [`4f391cd5c`](https://github.com/talos-systems/talos/commit/4f391cd5c540a0a955f294d628adc7437b7513b5) chore: bump kernel to 5.15.22\n* [`6bd07406e`](https://github.com/talos-systems/talos/commit/6bd07406e1895d190b5bbd9838ee84f85d02cd3f) feat: disable reboots via kexec\n* [`1e3f2f952`](https://github.com/talos-systems/talos/commit/1e3f2f95275aa5f71abe931015799caaca42bf61) fix: validate kubelet node IP subnets correctly\n* [`d211bff47`](https://github.com/talos-systems/talos/commit/d211bff47d661697926fece893784519dbf4f8f3) feat: enable accept_ra when IPv6 forwarding\n* [`930205831`](https://github.com/talos-systems/talos/commit/93020583195d066e879ccb19da38b8cfd6b93e96) chore: update kernel to 5.15.21\n* [`c7186ed08`](https://github.com/talos-systems/talos/commit/c7186ed08013efaa9957fe064152ccfca8ec1ab8) chore: bump dependencies\n* [`9ee470f95`](https://github.com/talos-systems/talos/commit/9ee470f9556462dd3fda656d58358e7ae78f4d47) feat: set /etc/localtime to UTC\n* [`c34768367`](https://github.com/talos-systems/talos/commit/c347683670d489230a2e87e4f04f05009173aca0) fix: disable auto-tls for etcd\n* [`9bffc7e8d`](https://github.com/talos-systems/talos/commit/9bffc7e8d5eff6d5ce0b83d627557f4110fc5c58) fix: pass proper sequence to shutdown sequence on ACPI shutdown\n* [`e47387e41`](https://github.com/talos-systems/talos/commit/e47387e4197974366844b2741cae345666d474da) chore: bump CAPI to 1.0.4\n* [`5462f5ed1`](https://github.com/talos-systems/talos/commit/5462f5ed18b7ffe023b3a41f1ac7d9b4ca9b726d) feat: update etcd to 3.5.2\n* [`f6fa12e53`](https://github.com/talos-systems/talos/commit/f6fa12e53697c763bd0463d91e92a446eb1ac2f7) docs: update upgrading Talos, Kubernetes, and Docker guides\n* [`5484579c1`](https://github.com/talos-systems/talos/commit/5484579c1a897f2378aacbef94bd4381d6b8299c) feat: allow link scope routes in the machine config\n* [`56b83b087`](https://github.com/talos-systems/talos/commit/56b83b08730c13910b0e5eb724decaf27e187047) feat: enable persistence for docker provider\n* [`949464e4b`](https://github.com/talos-systems/talos/commit/949464e4b6e1e807d9299b451758a6d144725fb1) fix: use leaf certificate in the apid RBAC check\n* [`446972f21`](https://github.com/talos-systems/talos/commit/446972f2113ada8e6c511ce56f630ec170ef0f26) chore: bump kernel to 5.15.19\n* [`fe40e7b1b`](https://github.com/talos-systems/talos/commit/fe40e7b1b39281f9bc14393b8c9db55ab6d6f8cd) feat: drain node on shutdown\n* [`7f0b3aae0`](https://github.com/talos-systems/talos/commit/7f0b3aae0a37b519623422841e3cbcda8bdd21a1) feat: add multiple config patches, patches from files, YAML support\n* [`202290be7`](https://github.com/talos-systems/talos/commit/202290be7b9b04ec909d369326d463c3b462eafa) docs: update Kubernetes upgrade video\n* [`036644f7a`](https://github.com/talos-systems/talos/commit/036644f7a03383922fd8407b1d514c7f79d44d0d) chore: bump kernel to 5.15.18\n* [`dcde2c4f6`](https://github.com/talos-systems/talos/commit/dcde2c4f68982974d6e55c52ba0fa8665e7f40b8) chore: update k8s upgrade message\n* [`1c949335c`](https://github.com/talos-systems/talos/commit/1c949335cc41cc9157e4c7dead44826c99b336f3) docs: add documentation for Hyper-V\n* [`7f9790912`](https://github.com/talos-systems/talos/commit/7f9790912308dfa88457a6db4f94728e5337c399) fix: clean up containerd state on installer run/validate\n* [`8b98d8eb3`](https://github.com/talos-systems/talos/commit/8b98d8eb3976cb8e64ffa94cfdf0305216f7dbeb) docs: clarify Filebeat example\n* [`74c03120c`](https://github.com/talos-systems/talos/commit/74c03120cf1da93d79fd786036e8d296c00c221e) docs: replace Talos upgrades video\n* [`65e64d425`](https://github.com/talos-systems/talos/commit/65e64d425e0253ae6780d52063d227c47df1ae29) chore: update kernel to stable 5.15.17\n* [`4245f72d3`](https://github.com/talos-systems/talos/commit/4245f72d3ff3712742d6d7d6ec3310f40f900c79) feat: add --extra-uefi-search-paths option\n* [`7ffeb6c2e`](https://github.com/talos-systems/talos/commit/7ffeb6c2e2bef1482b641725e4075c44264e899e) docs: update oracle cloud example\n* [`151c9df09`](https://github.com/talos-systems/talos/commit/151c9df091f32d00748e7e5effbb2c759916e8b9) chore: add CSI tests for e2e-qemu\n* [`cdb621c82`](https://github.com/talos-systems/talos/commit/cdb621c82e15026a851bbfb567afd834d88165e7) feat: provide a way to list installed system extensions\n* [`abfb25812`](https://github.com/talos-systems/talos/commit/abfb2581289c72c9e7bda8bc1f7bc2aa2ba758f7) feat: share `/lib/firmware` across initramfs and rootfs\n* [`ebec5d4a0`](https://github.com/talos-systems/talos/commit/ebec5d4a0c20fe20aa1fd5d1f9b28c0745a08fe7) feat: support full disk path in the diskSelector\n* [`831f65a07`](https://github.com/talos-systems/talos/commit/831f65a07f3b0a93ee9f38327dc5b84ce97a3237) fix: close client provider instead of Talos client in the upgrade module\n* [`0bf161dff`](https://github.com/talos-systems/talos/commit/0bf161dffb8c7805c44a4fb2c3db191dfa901b88) test: add integration test for system extensions\n* [`7b3962745`](https://github.com/talos-systems/talos/commit/7b3962745625decb720c53ca3b454f65079715f6) fix: handle 404 errors from AWS IMDS correctly\n* [`85782faa2`](https://github.com/talos-systems/talos/commit/85782faa24772dc9fa757aac3803a196f0325544) feat: update Kubernetes to 1.23.3\n* [`c5e5922e5`](https://github.com/talos-systems/talos/commit/c5e5922e536533badcaae568171f1b78cac40105) chore: bump dependencies\n* [`b3c3ef29b`](https://github.com/talos-systems/talos/commit/b3c3ef29bdf0f21805adf3489972cb92c98c00aa) feat: install system extensions\n* [`a0889600f`](https://github.com/talos-systems/talos/commit/a0889600fb19f62a2503244c32364808777ffdcc) chore: fix golangci-lint install\n* [`a50c42980`](https://github.com/talos-systems/talos/commit/a50c42980febfe51ba1e4ce750768f01de8c2d47) fix: use #!/usr/bin/env bash as shebang instead of #!/bin/bash\n* [`4464b725c`](https://github.com/talos-systems/talos/commit/4464b725c4fea4234961959e884426c384822eab) fix: qemu: always use runtime.GOARCH for CNI bundle\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>2 commits</summary>\n<p>\n\n* [`510b0d2`](https://github.com/talos-systems/crypto/commit/510b0d2753a89170d0c0f60e052a66484997a5b2) chore: add json tags\n* [`6fa2d93`](https://github.com/talos-systems/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`8f607fc`](https://github.com/talos-systems/extras/commit/8f607fc575b854c48b91ac01d8a233a68577ef29) chore: bump to Go 1.17.7\n* [`7c1f3cc`](https://github.com/talos-systems/extras/commit/7c1f3cc0edbba59f2731cd01c0369af0490cebf9) feat: update Go to 1.17.6\n* [`495a5b2`](https://github.com/talos-systems/extras/commit/495a5b2a4964e11a9ae8629788c46a5140d07b10) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>3 commits</summary>\n<p>\n\n* [`7b9de26`](https://github.com/talos-systems/go-blockdevice/commit/7b9de26bc6bc3d54b95bd8e8fb3aade4b45adc6c) feat: read symlink fullpath in block device list function\n* [`6928ee4`](https://github.com/talos-systems/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/talos-systems/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n</p>\n</details>\n\n### Changes from talos-systems/net\n<details><summary>1 commit</summary>\n<p>\n\n* [`409926a`](https://github.com/talos-systems/net/commit/409926aec1c3e659d6c245db4c0b90b0eaa4fdbc) fix: parse correctly some IPv6 CIDRs\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>25 commits</summary>\n<p>\n\n* [`6019223`](https://github.com/talos-systems/pkgs/commit/601922368a7b82d8eb87f946e314e70df7f2f6eb) chore: bump kernel to 5.15.23\n* [`ff4b2d8`](https://github.com/talos-systems/pkgs/commit/ff4b2d8ae80bb0802251d3aba0708a603782c267) chore: bump tools for Go 1.17.7\n* [`e34f883`](https://github.com/talos-systems/pkgs/commit/e34f88339ed02c94006e6f6c874d6878d558b26b) chore: disable TIPC and B.A.T.M.A.N\n* [`2b8cd88`](https://github.com/talos-systems/pkgs/commit/2b8cd882e6dc0e6409e8087934bb3f179153f8f3) feat: add Intel Ethernet Controller I225-V driver\n* [`407459d`](https://github.com/talos-systems/pkgs/commit/407459da274c80620282a2b690dac1fd3c32394f) feat: enable zstd squashfs compression and firmware (xz) compression\n* [`81a4b1c`](https://github.com/talos-systems/pkgs/commit/81a4b1c3a9f9a941cec751c6370bd8a92a177052) chore: bump kernel to 5.15.22\n* [`c9a6415`](https://github.com/talos-systems/pkgs/commit/c9a64154f11b36e21f25a99c4251bf4ed2bebe48) chore: bump kernel to 5.15.21\n* [`90dcd00`](https://github.com/talos-systems/pkgs/commit/90dcd000f68ffe447ad82d15c081923cd2054568) chore: bump kernel to 5.15.19\n* [`d457b87`](https://github.com/talos-systems/pkgs/commit/d457b87b18d3a6bff6fb9b22c25658e6f2eb30b2) chore: bump kernel to 5.15.18\n* [`dd69678`](https://github.com/talos-systems/pkgs/commit/dd6967866cc38029f8eb30d30b78f6579b14c595) chore: disable ATA-over-Ethernet driver for arm64\n* [`388ce13`](https://github.com/talos-systems/pkgs/commit/388ce1365e2508f38efbb925000659663d12987d) chore: bump kernel to 5.15.17\n* [`c14eb99`](https://github.com/talos-systems/pkgs/commit/c14eb99ec16603fc1fcbd93fab22ade7b55259ac) feat: update Linux to 5.15.16\n* [`5d4d8d6`](https://github.com/talos-systems/pkgs/commit/5d4d8d6e57814fbbdcf1abebe148827f68fd81ec) feat: bump containerd to 1.6.0-rc.0, runc to 1.1.0\n* [`5dd08a7`](https://github.com/talos-systems/pkgs/commit/5dd08a771be617720e5fadb9cb4df7b4641d83ba) feat: jetson nano SoC\n* [`402b960`](https://github.com/talos-systems/pkgs/commit/402b9601d3a0521575006c5f0c0cc1fbdab6af42) chore: bump u-boot to 2022.01\n* [`6ce1a40`](https://github.com/talos-systems/pkgs/commit/6ce1a4036d78113e9b66c6c2e074909b05b70caf) feat: update Go to 1.17.6\n* [`08f2519`](https://github.com/talos-systems/pkgs/commit/08f25196d91c4c3a1ebcb8e0ec8efc16098214bc) feat: update containerd to 1.5.9\n* [`fbb5c5c`](https://github.com/talos-systems/pkgs/commit/fbb5c5ccb83f6779a6a8ec0d4d867fd0fa7c5f56) feat: add qlcnic drivers to kernel\n* [`0505e01`](https://github.com/talos-systems/pkgs/commit/0505e0147ec27bf2c7f4d2b3c7d16fab796cc9de) chore: fix `=m` kernel build options\n* [`54aa902`](https://github.com/talos-systems/pkgs/commit/54aa902c3a3e7c3c427450b54271fb92190625e4) feat: enable amdgpu in kernel\n* [`2779c3f`](https://github.com/talos-systems/pkgs/commit/2779c3fe825a47a7c392d077f4a38d7f7b2f8eb5) fix: kexec on rpi4\n* [`950361f`](https://github.com/talos-systems/pkgs/commit/950361f79c03f718d73b60ddfbc6f661f4aa93b6) feat: update Linux to 5.15.11\n* [`ad611bc`](https://github.com/talos-systems/pkgs/commit/ad611bc512bd67366e16f0b58c24dfca35f38a12) feat: provide build instructions for NVIDIA kernel module\n* [`b22723d`](https://github.com/talos-systems/pkgs/commit/b22723d0fb4766488f1bc50244d3cdfb9a9d8bbf) feat: update iPXE to the latest available version\n* [`a675c67`](https://github.com/talos-systems/pkgs/commit/a675c676e894c33626563f57e9c124e7628bc78f) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`4c9e7a4`](https://github.com/talos-systems/tools/commit/4c9e7a4a01843363e07687b6d2e5145cf8329368) chore: bump go to 1.17.7\n* [`d33b4b6`](https://github.com/talos-systems/tools/commit/d33b4b65642d2989249a16ce207cd5cab156a55f) feat: support zstd compression\n* [`67314b1`](https://github.com/talos-systems/tools/commit/67314b13104ab1eb1ae9d7137d640499f35caead) feat: update Go to 1.17.6\n* [`9c2b9df`](https://github.com/talos-systems/tools/commit/9c2b9dfde84366c486f212cc074405cfb4d52127) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.2.0 **_new_**\n* **github.com/BurntSushi/toml**                     v0.4.1 -> v1.0.0\n* **github.com/aws/aws-sdk-go**                      v1.42.47 **_new_**\n* **github.com/containerd/cgroups**                  v1.0.2 -> v1.0.3\n* **github.com/containerd/containerd**               v1.5.8 -> v1.6.0-rc.2\n* **github.com/docker/docker**                       v20.10.11 -> v20.10.12\n* **github.com/google/go-cmp**                       v0.5.6 -> v0.5.7\n* **github.com/google/nftables**                     16a134723a96 -> 91d3b4571db1\n* **github.com/hashicorp/go-getter**                 v1.5.9 -> v1.5.11\n* **github.com/hashicorp/go-version**                v1.4.0 **_new_**\n* **github.com/insomniacslk/dhcp**                   5297eed8f489 -> 3c283ff8b7dd\n* **github.com/jsimonetti/rtnetlink**                fd9a11f42291 -> v1.1.0\n* **github.com/jxskiss/base62**                      v1.0.0 -> v1.1.0\n* **github.com/mdlayher/ethtool**                    288d040e9d60 -> 81c2608dd90e\n* **github.com/mdlayher/genetlink**                  v1.0.0 -> v1.2.0\n* **github.com/mdlayher/netlink**                    v1.4.2 -> v1.6.0\n* **github.com/opencontainers/image-spec**           v1.0.2 **_new_**\n* **github.com/packethost/packngo**                  v0.20.0 -> v0.21.0\n* **github.com/pelletier/go-toml**                   v1.9.4 **_new_**\n* **github.com/pmorjan/kmod**                        v1.0.0 **_new_**\n* **github.com/rivo/tview**                          2a6de950f73b -> 1f7581b67bd1\n* **github.com/spf13/cobra**                         v1.2.1 -> v1.3.0\n* **github.com/talos-systems/crypto**                v0.3.4 -> 510b0d2753a8\n* **github.com/talos-systems/extras**                v0.7.0-1-gd6b73a7 -> v0.8.0-alpha.0-2-g8f607fc\n* **github.com/talos-systems/go-blockdevice**        v0.2.5 -> 7b9de26bc6bc\n* **github.com/talos-systems/net**                   v0.3.1 -> 409926aec1c3\n* **github.com/talos-systems/pkgs**                  v0.9.0-1-g7a3419a -> v0.10.0-alpha.0-24-g6019223\n* **github.com/talos-systems/tools**                 v0.9.0-1-gb1146f9 -> v0.10.0-alpha.0-3-g4c9e7a4\n* **github.com/u-root/u-root**                       v7.0.0 -> v0.8.0\n* **github.com/vishvananda/netlink**                 f5de75959ad5 -> 650dca95af54\n* **github.com/vmware-tanzu/sonobuoy**               v0.55.1 -> v0.56.0\n* **github.com/vmware/govmomi**                      v0.27.2 -> v0.27.3\n* **go.etcd.io/etcd/api/v3**                         v3.5.1 -> v3.5.2\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.1 -> v3.5.2\n* **go.etcd.io/etcd/client/v3**                      v3.5.1 -> v3.5.2\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.1 -> v3.5.2\n* **go.uber.org/zap**                                v1.19.1 -> v1.20.0\n* **golang.org/x/net**                               491a49abca63 -> cd36cc0744dd\n* **golang.org/x/sys**                               97ca703d548d -> 1c1b9b1eba6a\n* **golang.zx2c4.com/wireguard/wgctrl**              dd7407c86d22 -> daad0b7ba671\n* **google.golang.org/grpc**                         v1.42.0 -> v1.44.0\n* **k8s.io/api**                                     v0.23.1 -> v0.23.3\n* **k8s.io/apimachinery**                            v0.23.1 -> v0.23.3\n* **k8s.io/client-go**                               v0.23.1 -> v0.23.3\n* **k8s.io/component-base**                          v0.23.1 -> v0.23.3\n* **k8s.io/kubectl**                                 v0.23.1 -> v0.23.3\n* **k8s.io/kubelet**                                 v0.23.1 -> v0.23.3\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.61 -> v1.2.63\n\nPrevious release can be found at [v0.14.0](https://github.com/talos-systems/talos/releases/tag/v0.14.0)\n\n## [Talos 0.15.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.15.0-alpha.1) (2022-01-24)\n\nWelcome to the v0.15.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Apply Config Enhancements\n\n`talosctl apply/patch/edit` cli commands got revamped.\nSeparate flags `--on-reboot`, `--immediate`, `--interactive` were replaced\nwith a single `--mode` flag that can take the following values:\n- `auto` new mode that automatically applies the configuration in immediate/reboot mode.\n- `no-reboot` force apply immediately, if not possible, then fail.\n- `reboot` force reboot with apply config.\n- `staged` write new machine configuration to STATE, but don't apply it (it will be applied after a reboot).\n- `interactive` starts interactive installer, only for `apply`.\n\n\n### Machine Configuration\n\nTalos now preserves machine configuration as it was submitted to the node.\n\n\n### Platform Support\n\nTalos now supports Oracle Cloud.\n\nPlatform network configuration was rewritten to avoid modifying Talos machine configuration.\nNetwork configuration is performed independent of the machine configuration presence, so it works\neven if Talos is booted in maintenance mode (without machine configuration is platform userdata).\n\n\n### SBC Support\n\nTalos now supports Jetson Nano SBC.\n\n\n### Component Updates\n\n* Linux: 5.15.16\n* containerd: 1.5.9\n* CoreDNS: 1.8.7\n* containerd: 1.6.0-rc.0\n* runc: 1.1.0\n\nTalos is built with Go 1.17.6\n\n\n### Wipe System Kernel Parameter\n\nAdded new kernel parameter `talos.experimental.wipe=system` which can help resetting system disk for the machine\nand start over with a fresh installation.\nSee [Resetting a Machine](https://www.talos.dev/docs/v0.15/guides/resetting-a-machine/#kernel-parameter) on how to use it.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Spencer Smith\n* Artem Chernyshev\n* Seán C McCord\n* Steve Francis\n* Serge Logvinov\n* Andrew Rynhard\n* Anthony Rabbito\n* Eric Wohltman\n* Niklas Metje\n* Shahar Naveh\n\n### Changes\n<details><summary>80 commits</summary>\n<p>\n\n* [`58eb3600f`](https://github.com/talos-systems/talos/commit/58eb3600fc44dc2fccaa82322207291ffd807205) fix: enforce reasonable TLS min tls-min-version\n* [`b8d4c5dfa`](https://github.com/talos-systems/talos/commit/b8d4c5dfad4585c0af52287513176411a79fc20c) fix: use correct error in `kernel_param_spec` Modify call handling\n* [`4961d6867`](https://github.com/talos-systems/talos/commit/4961d6867cadab5e8b48e73355b23b91d36f70b4) docs: drop talos.interface kernel arg\n* [`b1e61fa5b`](https://github.com/talos-systems/talos/commit/b1e61fa5b1bcd5affd42b498711b9e3378344c33) chore: update Linux to 5.15.16\n* [`d4b844593`](https://github.com/talos-systems/talos/commit/d4b844593587ae3f82efcdbdfe0f24cda4262474) feat: support CRI configuration merging and reimplement registry config\n* [`f94c8c6e1`](https://github.com/talos-systems/talos/commit/f94c8c6e1c3915c962c331943120bdfd2b76259f) feat: update Kubernetes to 1.23.2\n* [`21f497b3e`](https://github.com/talos-systems/talos/commit/21f497b3e20f3b1cc9b744f1787ba80cf396d3e0) feat: install readonly overlay mounts during talos chroot sequence\n* [`9ad5a67d2`](https://github.com/talos-systems/talos/commit/9ad5a67d21b0788d1b43f1bea8e39c003a4a8ecc) feat: inject platform network configuration as network resources\n* [`907f8cbfb`](https://github.com/talos-systems/talos/commit/907f8cbfb8ed28cf399b9797230790718fc04a58) docs: fix patch flag\n* [`caa434426`](https://github.com/talos-systems/talos/commit/caa43442640744a0aa7a17aa1a205f1641e6445a) docs: add documentation on developing Talos\n* [`16eeb6776`](https://github.com/talos-systems/talos/commit/16eeb677625c0859d73b82948c1a073ba6e17e8d) docs: readme updates\n* [`3c0737027`](https://github.com/talos-systems/talos/commit/3c0737027b5574581a6461211199274ee709b1da) chore: update release notes\n* [`6d8bea5d5`](https://github.com/talos-systems/talos/commit/6d8bea5d559b1156f7d0b576b7b5784c25cd3595) feat: jetson nano SoC\n* [`1d8955ebe`](https://github.com/talos-systems/talos/commit/1d8955ebe43259a5e072b8a89f37cb728b6fcf53) feat: update CoreDNS to 1.8.7\n* [`6af83afd5`](https://github.com/talos-systems/talos/commit/6af83afd5aba64ffa7887d62f84c434109b7579b) fix: handle multiple-IP cluster nodes\n* [`43b2d8137`](https://github.com/talos-systems/talos/commit/43b2d8137116863cfc5ca969c429c13483465b01) chore: bump dependencies\n* [`529e80f4f`](https://github.com/talos-systems/talos/commit/529e80f4f529f066872b5768cd80eeeb7b766a31) docs: update home page and footer\n* [`37630e70c`](https://github.com/talos-systems/talos/commit/37630e70ccc9950e139bf7fcfcded6a18d0c7a01) Update twitter link\n* [`af440919b`](https://github.com/talos-systems/talos/commit/af440919bbaf12f414f04a5a621c1e2d5ed84ae2) fix: avoid panic in config loading/validation\n* [`4b8e9de59`](https://github.com/talos-systems/talos/commit/4b8e9de599812f82275605a93de7f5c05471f7f5) docs: add guide on adding proprietary kernel modules\n* [`833dc4169`](https://github.com/talos-systems/talos/commit/833dc4169a9702383930816d13be39f6b81c7a31) docs: rework vmware assets\n* [`2869b5eea`](https://github.com/talos-systems/talos/commit/2869b5eeacf0b6c96aedcb605bfa8a5f9fb87625) feat: add oraclecloud.com platform support\n* [`f3ec24beb`](https://github.com/talos-systems/talos/commit/f3ec24bebf0aaa7983228a09b21a67b9a2a098c1) fix: vmware documentation typo\n* [`2f2bdb26a`](https://github.com/talos-systems/talos/commit/2f2bdb26aa5367066c12a6402af554b7a5a148d6) feat: replace flags with --mode in `apply`, `edit` and `patch` commands\n* [`b09be2a69`](https://github.com/talos-systems/talos/commit/b09be2a69c6b6f8064a676fc014e6e60ea01a08d) docs: update index.md and sync across versions\n* [`ca65b918a`](https://github.com/talos-systems/talos/commit/ca65b918a7292ae53d40e410cca4e89be91e4261) docs: add nocloud documentation\n* [`59437d6d8`](https://github.com/talos-systems/talos/commit/59437d6d8360ad7dd8f801797ab91ac0791270f7) fix: filter down nameservers for docker-based cluster create\n* [`194eaa6f2`](https://github.com/talos-systems/talos/commit/194eaa6f22249fe4f43958bd897744a2cc57279f) chore: clean up /usr/bin from unneeded files\n* [`74e727240`](https://github.com/talos-systems/talos/commit/74e7272401ccb75464dd42ed0427d73842af74e1) docs: update office office\n* [`539af338c`](https://github.com/talos-systems/talos/commit/539af338c4b8f6e4291654f66628c81022aeda72) docs: update vmware docs\n* [`279a3fda7`](https://github.com/talos-systems/talos/commit/279a3fda7ba24037e06377f01cc495207722caa9) feat: update Go to 1.17.6, containerd to 1.5.9\n* [`3d3088941`](https://github.com/talos-systems/talos/commit/3d308894120092fe095b41970d6341362ab80a6b) chore: bump Go dependencies\n* [`d02d944ec`](https://github.com/talos-systems/talos/commit/d02d944ec767441612b84c164af31bc27c0c0659) chore: provide umarshal from YAML methods for network resource specs\n* [`2e735714d`](https://github.com/talos-systems/talos/commit/2e735714d9218cbc335d9c418730c146821fb8d4) fix: derive machine-id from node identity\n* [`d8a2721e1`](https://github.com/talos-systems/talos/commit/d8a2721e129be33f4a3c37be1bf5b89a1cd91685) test: update CAPI components to latest\n* [`7dff8a53e`](https://github.com/talos-systems/talos/commit/7dff8a53ee7bc37afe9dc216ca8a9113718d76af) fix: ignore missing init.yaml for cluster create\n* [`f4516c7d8`](https://github.com/talos-systems/talos/commit/f4516c7d847d905b49b4e2127eb86a1f38156d53) chore: bump dependencies\n* [`944f13221`](https://github.com/talos-systems/talos/commit/944f13221d50694d5c59ace1c12f8769d7ade9ae) chore: fix release pipeline\n* [`cb548a368`](https://github.com/talos-systems/talos/commit/cb548a368a75ca379209213948518c880b242b0c) release(v0.15.0-alpha.0): prepare release\n* [`da0b36e61`](https://github.com/talos-systems/talos/commit/da0b36e616f7da7eb0c6791b9cf5e4ee2757f08f) feat: introduce `talos.exp.wipe` kernel param to wipe system disk\n* [`c079eb32b`](https://github.com/talos-systems/talos/commit/c079eb32bd7fc19d506146e2a9edf5b406e25e02) refactor: use AWS SDK to access AWS metadata service\n* [`2f4b9d8d6`](https://github.com/talos-systems/talos/commit/2f4b9d8d6d10c0aa753f405282aa99696b923bb4) feat: make machine configuration read-only in Talos (almost)\n* [`524f83d3d`](https://github.com/talos-systems/talos/commit/524f83d3d8af3857f178c179a9552a5f32b70f47) feat: use official Go SDK to fetch GCP instance metadata\n* [`d2a7e082c`](https://github.com/talos-systems/talos/commit/d2a7e082c24d0b42820b3ea454329a19178ba0a4) test: retry in discovery tests\n* [`f4219e530`](https://github.com/talos-systems/talos/commit/f4219e530ca7635ada666ae69071746d698939a8) chore: remove unused methods in AWS platform\n* [`35bc2940e`](https://github.com/talos-systems/talos/commit/35bc2940e375b99e0d6e22a26a05c25d642bf35a) fix: kexec on RPI4\n* [`f235cfbae`](https://github.com/talos-systems/talos/commit/f235cfbaed8b5254e19616bfaaa8b48fd7d32e64) fix: multiple usability fixes\n* [`b3fbb2f31`](https://github.com/talos-systems/talos/commit/b3fbb2f312d5de0c14ffee567956b868a317aba7) test: don't build all images in the default CI pipeline\n* [`dac550a50`](https://github.com/talos-systems/talos/commit/dac550a50f4793194e4aeee98702a052925a0e88) docs: fix troubleshooting guide\n* [`83e8bec6b`](https://github.com/talos-systems/talos/commit/83e8bec6b9d4c0ecc689f45b15d7203bbf9bf0cc) feat: update Linux to 5.15.11\n* [`d5a82b37e`](https://github.com/talos-systems/talos/commit/d5a82b37eb147a68ffd08fc8ec800edc92da9f9c) feat: remove `ApplyDynamicConfig`\n* [`3623da136`](https://github.com/talos-systems/talos/commit/3623da136bde51422ba1aec06e22dea2e3dfa756) feat: provide a way to load Linux kernel modules\n* [`4d1514add`](https://github.com/talos-systems/talos/commit/4d1514add6e0b972aee26a8ad63ef8f972050d46) docs: update Mayastor deployment process\n* [`cff1ff6d5`](https://github.com/talos-systems/talos/commit/cff1ff6d5c3a68063ed2c0c063daadf2474cc43f) feat: shell completion for `list`, `read`\n* [`19728437e`](https://github.com/talos-systems/talos/commit/19728437ead7ab6e95afc8bd7f70be3f861c9a6e) feat: output IPs when etcd needs to be bootstrapped\n* [`c297d66a1`](https://github.com/talos-systems/talos/commit/c297d66a130cba708fcb42f8f2e6b356c36f5109) test: attempt number on two on proper retries in CLI time tests\n* [`dc299da9e`](https://github.com/talos-systems/talos/commit/dc299da9e8e885b7a44c184ef3d251726aa934a8) docs: add arm64 option to talosctl download\n* [`f49f40a33`](https://github.com/talos-systems/talos/commit/f49f40a3361381e51d6986547be12ec3b4a3f24a) fix: pass path to conformance retrieve results\n* [`942c8074f`](https://github.com/talos-systems/talos/commit/942c8074fd14478089769e2b8132ea2796109721) docs: fork docs for 0.15\n* [`880a7782c`](https://github.com/talos-systems/talos/commit/880a7782cbc703b38a2ff2b3d76c1eda621524ba) docs: update documentation for 0.14.0 release\n* [`dc9a0cfe9`](https://github.com/talos-systems/talos/commit/dc9a0cfe94b59c688d65ef74ebc04f273b8a72fb) chore: bump Go dependencies\n* [`773496935`](https://github.com/talos-systems/talos/commit/7734969356abac8355a31da08d47fafd4000e814) fix: config apply immediate\n* [`17c147488`](https://github.com/talos-systems/talos/commit/17c14748815e2ab928a9c0c8a079f65a63f0194e) test: retry `talosctl time` call in the tests\n* [`acf1ac0f1`](https://github.com/talos-systems/talos/commit/acf1ac0f1aff929ae9bf66b1c0322b4f83c0fef1) feat: show human-readable aliases in `talosctl get rd`\n* [`5532867b0`](https://github.com/talos-systems/talos/commit/5532867b05bb596f42516ff121b0a3a97176b3d1) refactor: rewrite the implementation of Processes API\n* [`80350861a`](https://github.com/talos-systems/talos/commit/80350861a2c1cee234d2f3a571d3993841c554d9) feat: update Kubernetes to 1.23.1\n* [`4c96e936e`](https://github.com/talos-systems/talos/commit/4c96e936ed467ae7838258699bdd83fd6da15ae6) docs: add cilium guide\n* [`e3f2acb5e`](https://github.com/talos-systems/talos/commit/e3f2acb5e57f9b3e7b11986f180e287f1f693079) refactor: rewrite the check for unknown keys in the machine configuration\n* [`4175396a8`](https://github.com/talos-systems/talos/commit/4175396a89f836bb1835d201b59224b286eeb62a) refactor: use update go-blockdevice library with allocation fixes\n* [`b58f567a1`](https://github.com/talos-systems/talos/commit/b58f567a133b661cc045a995dd29ab5090dfe194) refactor: optimize Runtime config interface to avoid config marshaling\n* [`bb355c9ab`](https://github.com/talos-systems/talos/commit/bb355c9ab38a417ed471bf3ce7b1879609f5e806) chore: remove govalidator library\n* [`3af56bd2e`](https://github.com/talos-systems/talos/commit/3af56bd2e70e8964cc48b430b1e67e48052af682) test: update capi templates to v1beta1\n* [`936b4c4ce`](https://github.com/talos-systems/talos/commit/936b4c4cee87697b3f08d51f22208b44b8a02db5) fix: update DHCP library with the panic fix\n* [`ab42886bf`](https://github.com/talos-systems/talos/commit/ab42886bf333dcaa9d3a1b765781ab19354de397) fix: allow kubelet to be started via the API\n* [`ec641f729`](https://github.com/talos-systems/talos/commit/ec641f7296ce62b2f9ba1353ff2eba70c2287c08) fix: use default time servers in time API if none are configured\n* [`79f213eec`](https://github.com/talos-systems/talos/commit/79f213eec65af46c4a3a4c4494d67ffc1b0a53ec) fix: cleanup affiliates\n* [`2dd0b5b68`](https://github.com/talos-systems/talos/commit/2dd0b5b68aa5b8efbc9b0bc4f8ebc159e2d991ab) chore: update Go to 1.17.5\n* [`97ffa7a64`](https://github.com/talos-systems/talos/commit/97ffa7a645d7db93ee58032795f91131f6950e89) feat: upgrade kubelet version in `talosctl upgrade-k8s`\n* [`5bc5123eb`](https://github.com/talos-systems/talos/commit/5bc5123eb91386ca12e7e7f9fc0f66637343a642) docs: document `ip=` kernel argument\n* [`8e1d0bfb5`](https://github.com/talos-systems/talos/commit/8e1d0bfb5fbaf0849bdd07b73a8e3bda4e8c3b75) feat: update Kubernetes to 1.23.0\n</p>\n</details>\n\n### Changes since v0.15.0-alpha.0\n<details><summary>37 commits</summary>\n<p>\n\n* [`58eb3600f`](https://github.com/talos-systems/talos/commit/58eb3600fc44dc2fccaa82322207291ffd807205) fix: enforce reasonable TLS min tls-min-version\n* [`b8d4c5dfa`](https://github.com/talos-systems/talos/commit/b8d4c5dfad4585c0af52287513176411a79fc20c) fix: use correct error in `kernel_param_spec` Modify call handling\n* [`4961d6867`](https://github.com/talos-systems/talos/commit/4961d6867cadab5e8b48e73355b23b91d36f70b4) docs: drop talos.interface kernel arg\n* [`b1e61fa5b`](https://github.com/talos-systems/talos/commit/b1e61fa5b1bcd5affd42b498711b9e3378344c33) chore: update Linux to 5.15.16\n* [`d4b844593`](https://github.com/talos-systems/talos/commit/d4b844593587ae3f82efcdbdfe0f24cda4262474) feat: support CRI configuration merging and reimplement registry config\n* [`f94c8c6e1`](https://github.com/talos-systems/talos/commit/f94c8c6e1c3915c962c331943120bdfd2b76259f) feat: update Kubernetes to 1.23.2\n* [`21f497b3e`](https://github.com/talos-systems/talos/commit/21f497b3e20f3b1cc9b744f1787ba80cf396d3e0) feat: install readonly overlay mounts during talos chroot sequence\n* [`9ad5a67d2`](https://github.com/talos-systems/talos/commit/9ad5a67d21b0788d1b43f1bea8e39c003a4a8ecc) feat: inject platform network configuration as network resources\n* [`907f8cbfb`](https://github.com/talos-systems/talos/commit/907f8cbfb8ed28cf399b9797230790718fc04a58) docs: fix patch flag\n* [`caa434426`](https://github.com/talos-systems/talos/commit/caa43442640744a0aa7a17aa1a205f1641e6445a) docs: add documentation on developing Talos\n* [`16eeb6776`](https://github.com/talos-systems/talos/commit/16eeb677625c0859d73b82948c1a073ba6e17e8d) docs: readme updates\n* [`3c0737027`](https://github.com/talos-systems/talos/commit/3c0737027b5574581a6461211199274ee709b1da) chore: update release notes\n* [`6d8bea5d5`](https://github.com/talos-systems/talos/commit/6d8bea5d559b1156f7d0b576b7b5784c25cd3595) feat: jetson nano SoC\n* [`1d8955ebe`](https://github.com/talos-systems/talos/commit/1d8955ebe43259a5e072b8a89f37cb728b6fcf53) feat: update CoreDNS to 1.8.7\n* [`6af83afd5`](https://github.com/talos-systems/talos/commit/6af83afd5aba64ffa7887d62f84c434109b7579b) fix: handle multiple-IP cluster nodes\n* [`43b2d8137`](https://github.com/talos-systems/talos/commit/43b2d8137116863cfc5ca969c429c13483465b01) chore: bump dependencies\n* [`529e80f4f`](https://github.com/talos-systems/talos/commit/529e80f4f529f066872b5768cd80eeeb7b766a31) docs: update home page and footer\n* [`37630e70c`](https://github.com/talos-systems/talos/commit/37630e70ccc9950e139bf7fcfcded6a18d0c7a01) Update twitter link\n* [`af440919b`](https://github.com/talos-systems/talos/commit/af440919bbaf12f414f04a5a621c1e2d5ed84ae2) fix: avoid panic in config loading/validation\n* [`4b8e9de59`](https://github.com/talos-systems/talos/commit/4b8e9de599812f82275605a93de7f5c05471f7f5) docs: add guide on adding proprietary kernel modules\n* [`833dc4169`](https://github.com/talos-systems/talos/commit/833dc4169a9702383930816d13be39f6b81c7a31) docs: rework vmware assets\n* [`2869b5eea`](https://github.com/talos-systems/talos/commit/2869b5eeacf0b6c96aedcb605bfa8a5f9fb87625) feat: add oraclecloud.com platform support\n* [`f3ec24beb`](https://github.com/talos-systems/talos/commit/f3ec24bebf0aaa7983228a09b21a67b9a2a098c1) fix: vmware documentation typo\n* [`2f2bdb26a`](https://github.com/talos-systems/talos/commit/2f2bdb26aa5367066c12a6402af554b7a5a148d6) feat: replace flags with --mode in `apply`, `edit` and `patch` commands\n* [`b09be2a69`](https://github.com/talos-systems/talos/commit/b09be2a69c6b6f8064a676fc014e6e60ea01a08d) docs: update index.md and sync across versions\n* [`ca65b918a`](https://github.com/talos-systems/talos/commit/ca65b918a7292ae53d40e410cca4e89be91e4261) docs: add nocloud documentation\n* [`59437d6d8`](https://github.com/talos-systems/talos/commit/59437d6d8360ad7dd8f801797ab91ac0791270f7) fix: filter down nameservers for docker-based cluster create\n* [`194eaa6f2`](https://github.com/talos-systems/talos/commit/194eaa6f22249fe4f43958bd897744a2cc57279f) chore: clean up /usr/bin from unneeded files\n* [`74e727240`](https://github.com/talos-systems/talos/commit/74e7272401ccb75464dd42ed0427d73842af74e1) docs: update office office\n* [`539af338c`](https://github.com/talos-systems/talos/commit/539af338c4b8f6e4291654f66628c81022aeda72) docs: update vmware docs\n* [`279a3fda7`](https://github.com/talos-systems/talos/commit/279a3fda7ba24037e06377f01cc495207722caa9) feat: update Go to 1.17.6, containerd to 1.5.9\n* [`3d3088941`](https://github.com/talos-systems/talos/commit/3d308894120092fe095b41970d6341362ab80a6b) chore: bump Go dependencies\n* [`d02d944ec`](https://github.com/talos-systems/talos/commit/d02d944ec767441612b84c164af31bc27c0c0659) chore: provide umarshal from YAML methods for network resource specs\n* [`2e735714d`](https://github.com/talos-systems/talos/commit/2e735714d9218cbc335d9c418730c146821fb8d4) fix: derive machine-id from node identity\n* [`d8a2721e1`](https://github.com/talos-systems/talos/commit/d8a2721e129be33f4a3c37be1bf5b89a1cd91685) test: update CAPI components to latest\n* [`7dff8a53e`](https://github.com/talos-systems/talos/commit/7dff8a53ee7bc37afe9dc216ca8a9113718d76af) fix: ignore missing init.yaml for cluster create\n* [`f4516c7d8`](https://github.com/talos-systems/talos/commit/f4516c7d847d905b49b4e2127eb86a1f38156d53) chore: bump dependencies\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`6fa2d93`](https://github.com/talos-systems/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`7c1f3cc`](https://github.com/talos-systems/extras/commit/7c1f3cc0edbba59f2731cd01c0369af0490cebf9) feat: update Go to 1.17.6\n* [`495a5b2`](https://github.com/talos-systems/extras/commit/495a5b2a4964e11a9ae8629788c46a5140d07b10) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`6928ee4`](https://github.com/talos-systems/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/talos-systems/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>14 commits</summary>\n<p>\n\n* [`c14eb99`](https://github.com/talos-systems/pkgs/commit/c14eb99ec16603fc1fcbd93fab22ade7b55259ac) feat: update Linux to 5.15.16\n* [`5d4d8d6`](https://github.com/talos-systems/pkgs/commit/5d4d8d6e57814fbbdcf1abebe148827f68fd81ec) feat: bump containerd to 1.6.0-rc.0, runc to 1.1.0\n* [`5dd08a7`](https://github.com/talos-systems/pkgs/commit/5dd08a771be617720e5fadb9cb4df7b4641d83ba) feat: jetson nano SoC\n* [`402b960`](https://github.com/talos-systems/pkgs/commit/402b9601d3a0521575006c5f0c0cc1fbdab6af42) chore: bump u-boot to 2022.01\n* [`6ce1a40`](https://github.com/talos-systems/pkgs/commit/6ce1a4036d78113e9b66c6c2e074909b05b70caf) feat: update Go to 1.17.6\n* [`08f2519`](https://github.com/talos-systems/pkgs/commit/08f25196d91c4c3a1ebcb8e0ec8efc16098214bc) feat: update containerd to 1.5.9\n* [`fbb5c5c`](https://github.com/talos-systems/pkgs/commit/fbb5c5ccb83f6779a6a8ec0d4d867fd0fa7c5f56) feat: add qlcnic drivers to kernel\n* [`0505e01`](https://github.com/talos-systems/pkgs/commit/0505e0147ec27bf2c7f4d2b3c7d16fab796cc9de) chore: fix `=m` kernel build options\n* [`54aa902`](https://github.com/talos-systems/pkgs/commit/54aa902c3a3e7c3c427450b54271fb92190625e4) feat: enable amdgpu in kernel\n* [`2779c3f`](https://github.com/talos-systems/pkgs/commit/2779c3fe825a47a7c392d077f4a38d7f7b2f8eb5) fix: kexec on rpi4\n* [`950361f`](https://github.com/talos-systems/pkgs/commit/950361f79c03f718d73b60ddfbc6f661f4aa93b6) feat: update Linux to 5.15.11\n* [`ad611bc`](https://github.com/talos-systems/pkgs/commit/ad611bc512bd67366e16f0b58c24dfca35f38a12) feat: provide build instructions for NVIDIA kernel module\n* [`b22723d`](https://github.com/talos-systems/pkgs/commit/b22723d0fb4766488f1bc50244d3cdfb9a9d8bbf) feat: update iPXE to the latest available version\n* [`a675c67`](https://github.com/talos-systems/pkgs/commit/a675c676e894c33626563f57e9c124e7628bc78f) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>2 commits</summary>\n<p>\n\n* [`67314b1`](https://github.com/talos-systems/tools/commit/67314b13104ab1eb1ae9d7137d640499f35caead) feat: update Go to 1.17.6\n* [`9c2b9df`](https://github.com/talos-systems/tools/commit/9c2b9dfde84366c486f212cc074405cfb4d52127) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go/compute**                    v1.0.0 **_new_**\n* **github.com/BurntSushi/toml**                     v0.4.1 -> v1.0.0\n* **github.com/aws/aws-sdk-go**                      v1.42.35 **_new_**\n* **github.com/containerd/containerd**               v1.5.8 -> v1.6.0-rc.0\n* **github.com/containerd/containerd/api**           v1.6.0-beta.3 **_new_**\n* **github.com/docker/docker**                       v20.10.11 -> v20.10.12\n* **github.com/google/nftables**                     16a134723a96 -> 6f19c4381e13\n* **github.com/hashicorp/go-getter**                 v1.5.9 -> v1.5.11\n* **github.com/jsimonetti/rtnetlink**                fd9a11f42291 -> 9dff439f7e79\n* **github.com/jxskiss/base62**                      v1.0.0 -> v1.1.0\n* **github.com/mdlayher/ethtool**                    288d040e9d60 -> bc8fdcf6e99c\n* **github.com/mdlayher/genetlink**                  v1.0.0 -> v1.1.0\n* **github.com/mdlayher/netlink**                    v1.4.2 -> v1.5.0\n* **github.com/packethost/packngo**                  v0.20.0 -> v0.21.0\n* **github.com/pelletier/go-toml**                   v1.9.4 **_new_**\n* **github.com/pmorjan/kmod**                        v1.0.0 **_new_**\n* **github.com/rivo/tview**                          2a6de950f73b -> 90d72bc664f5\n* **github.com/spf13/cobra**                         v1.2.1 -> v1.3.0\n* **github.com/talos-systems/crypto**                v0.3.4 -> 6fa2d93d0382\n* **github.com/talos-systems/extras**                v0.7.0-1-gd6b73a7 -> v0.8.0-alpha.0-1-g7c1f3cc\n* **github.com/talos-systems/go-blockdevice**        v0.2.5 -> 6928ee43c303\n* **github.com/talos-systems/pkgs**                  v0.9.0-1-g7a3419a -> v0.10.0-alpha.0-13-gc14eb99\n* **github.com/talos-systems/tools**                 v0.9.0-1-gb1146f9 -> v0.10.0-alpha.0-1-g67314b1\n* **github.com/u-root/u-root**                       v7.0.0 -> v0.8.0\n* **github.com/vishvananda/netlink**                 f5de75959ad5 -> 650dca95af54\n* **go.uber.org/zap**                                v1.19.1 -> v1.20.0\n* **golang.org/x/net**                               491a49abca63 -> 0dd24b26b47d\n* **golang.org/x/sys**                               97ca703d548d -> da31bd327af9\n* **golang.zx2c4.com/wireguard/wgctrl**              dd7407c86d22 -> daad0b7ba671\n* **google.golang.org/grpc**                         v1.42.0 -> v1.43.0\n* **k8s.io/api**                                     v0.23.1 -> v0.23.2\n* **k8s.io/apimachinery**                            v0.23.1 -> v0.23.2\n* **k8s.io/client-go**                               v0.23.1 -> v0.23.2\n* **k8s.io/component-base**                          v0.23.1 -> v0.23.2\n* **k8s.io/kubectl**                                 v0.23.1 -> v0.23.2\n* **k8s.io/kubelet**                                 v0.23.1 -> v0.23.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.61 -> v1.2.62\n\nPrevious release can be found at [v0.14.0](https://github.com/talos-systems/talos/releases/tag/v0.14.0)\n\n## [Talos 0.15.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.15.0-alpha.0) (2021-12-30)\n\nWelcome to the v0.15.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Machine Configuration\n\nTalos now preserves machine configuration as it was submitted to the node.\nThere is some work still going on various cloud platforms to stop modifying machine configuration on the fly.\n\n\n### Component Updates\n\n* Linux: 5.15.11\n\n\n### Wipe System Kernel Parameter\n\nAdded new kernel parameter `talos.experimental.wipe=system` which can help resetting system disk for the machine\nand start over with a fresh installation.\nSee [Resetting a Machine](https://www.talos.dev/docs/v0.15/guides/resetting-a-machine/#kernel-parameter) on how to use it.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Noel Georgi\n* Spencer Smith\n* Artem Chernyshev\n* Niklas Metje\n\n### Changes\n<details><summary>41 commits</summary>\n<p>\n\n* [`da0b36e61`](https://github.com/talos-systems/talos/commit/da0b36e616f7da7eb0c6791b9cf5e4ee2757f08f) feat: introduce `talos.exp.wipe` kernel param to wipe system disk\n* [`c079eb32b`](https://github.com/talos-systems/talos/commit/c079eb32bd7fc19d506146e2a9edf5b406e25e02) refactor: use AWS SDK to access AWS metadata service\n* [`2f4b9d8d6`](https://github.com/talos-systems/talos/commit/2f4b9d8d6d10c0aa753f405282aa99696b923bb4) feat: make machine configuration read-only in Talos (almost)\n* [`524f83d3d`](https://github.com/talos-systems/talos/commit/524f83d3d8af3857f178c179a9552a5f32b70f47) feat: use official Go SDK to fetch GCP instance metadata\n* [`d2a7e082c`](https://github.com/talos-systems/talos/commit/d2a7e082c24d0b42820b3ea454329a19178ba0a4) test: retry in discovery tests\n* [`f4219e530`](https://github.com/talos-systems/talos/commit/f4219e530ca7635ada666ae69071746d698939a8) chore: remove unused methods in AWS platform\n* [`35bc2940e`](https://github.com/talos-systems/talos/commit/35bc2940e375b99e0d6e22a26a05c25d642bf35a) fix: kexec on RPI4\n* [`f235cfbae`](https://github.com/talos-systems/talos/commit/f235cfbaed8b5254e19616bfaaa8b48fd7d32e64) fix: multiple usability fixes\n* [`b3fbb2f31`](https://github.com/talos-systems/talos/commit/b3fbb2f312d5de0c14ffee567956b868a317aba7) test: don't build all images in the default CI pipeline\n* [`dac550a50`](https://github.com/talos-systems/talos/commit/dac550a50f4793194e4aeee98702a052925a0e88) docs: fix troubleshooting guide\n* [`83e8bec6b`](https://github.com/talos-systems/talos/commit/83e8bec6b9d4c0ecc689f45b15d7203bbf9bf0cc) feat: update Linux to 5.15.11\n* [`d5a82b37e`](https://github.com/talos-systems/talos/commit/d5a82b37eb147a68ffd08fc8ec800edc92da9f9c) feat: remove `ApplyDynamicConfig`\n* [`3623da136`](https://github.com/talos-systems/talos/commit/3623da136bde51422ba1aec06e22dea2e3dfa756) feat: provide a way to load Linux kernel modules\n* [`4d1514add`](https://github.com/talos-systems/talos/commit/4d1514add6e0b972aee26a8ad63ef8f972050d46) docs: update Mayastor deployment process\n* [`cff1ff6d5`](https://github.com/talos-systems/talos/commit/cff1ff6d5c3a68063ed2c0c063daadf2474cc43f) feat: shell completion for `list`, `read`\n* [`19728437e`](https://github.com/talos-systems/talos/commit/19728437ead7ab6e95afc8bd7f70be3f861c9a6e) feat: output IPs when etcd needs to be bootstrapped\n* [`c297d66a1`](https://github.com/talos-systems/talos/commit/c297d66a130cba708fcb42f8f2e6b356c36f5109) test: attempt number on two on proper retries in CLI time tests\n* [`dc299da9e`](https://github.com/talos-systems/talos/commit/dc299da9e8e885b7a44c184ef3d251726aa934a8) docs: add arm64 option to talosctl download\n* [`f49f40a33`](https://github.com/talos-systems/talos/commit/f49f40a3361381e51d6986547be12ec3b4a3f24a) fix: pass path to conformance retrieve results\n* [`942c8074f`](https://github.com/talos-systems/talos/commit/942c8074fd14478089769e2b8132ea2796109721) docs: fork docs for 0.15\n* [`880a7782c`](https://github.com/talos-systems/talos/commit/880a7782cbc703b38a2ff2b3d76c1eda621524ba) docs: update documentation for 0.14.0 release\n* [`dc9a0cfe9`](https://github.com/talos-systems/talos/commit/dc9a0cfe94b59c688d65ef74ebc04f273b8a72fb) chore: bump Go dependencies\n* [`773496935`](https://github.com/talos-systems/talos/commit/7734969356abac8355a31da08d47fafd4000e814) fix: config apply immediate\n* [`17c147488`](https://github.com/talos-systems/talos/commit/17c14748815e2ab928a9c0c8a079f65a63f0194e) test: retry `talosctl time` call in the tests\n* [`acf1ac0f1`](https://github.com/talos-systems/talos/commit/acf1ac0f1aff929ae9bf66b1c0322b4f83c0fef1) feat: show human-readable aliases in `talosctl get rd`\n* [`5532867b0`](https://github.com/talos-systems/talos/commit/5532867b05bb596f42516ff121b0a3a97176b3d1) refactor: rewrite the implementation of Processes API\n* [`80350861a`](https://github.com/talos-systems/talos/commit/80350861a2c1cee234d2f3a571d3993841c554d9) feat: update Kubernetes to 1.23.1\n* [`4c96e936e`](https://github.com/talos-systems/talos/commit/4c96e936ed467ae7838258699bdd83fd6da15ae6) docs: add cilium guide\n* [`e3f2acb5e`](https://github.com/talos-systems/talos/commit/e3f2acb5e57f9b3e7b11986f180e287f1f693079) refactor: rewrite the check for unknown keys in the machine configuration\n* [`4175396a8`](https://github.com/talos-systems/talos/commit/4175396a89f836bb1835d201b59224b286eeb62a) refactor: use update go-blockdevice library with allocation fixes\n* [`b58f567a1`](https://github.com/talos-systems/talos/commit/b58f567a133b661cc045a995dd29ab5090dfe194) refactor: optimize Runtime config interface to avoid config marshaling\n* [`bb355c9ab`](https://github.com/talos-systems/talos/commit/bb355c9ab38a417ed471bf3ce7b1879609f5e806) chore: remove govalidator library\n* [`3af56bd2e`](https://github.com/talos-systems/talos/commit/3af56bd2e70e8964cc48b430b1e67e48052af682) test: update capi templates to v1beta1\n* [`936b4c4ce`](https://github.com/talos-systems/talos/commit/936b4c4cee87697b3f08d51f22208b44b8a02db5) fix: update DHCP library with the panic fix\n* [`ab42886bf`](https://github.com/talos-systems/talos/commit/ab42886bf333dcaa9d3a1b765781ab19354de397) fix: allow kubelet to be started via the API\n* [`ec641f729`](https://github.com/talos-systems/talos/commit/ec641f7296ce62b2f9ba1353ff2eba70c2287c08) fix: use default time servers in time API if none are configured\n* [`79f213eec`](https://github.com/talos-systems/talos/commit/79f213eec65af46c4a3a4c4494d67ffc1b0a53ec) fix: cleanup affiliates\n* [`2dd0b5b68`](https://github.com/talos-systems/talos/commit/2dd0b5b68aa5b8efbc9b0bc4f8ebc159e2d991ab) chore: update Go to 1.17.5\n* [`97ffa7a64`](https://github.com/talos-systems/talos/commit/97ffa7a645d7db93ee58032795f91131f6950e89) feat: upgrade kubelet version in `talosctl upgrade-k8s`\n* [`5bc5123eb`](https://github.com/talos-systems/talos/commit/5bc5123eb91386ca12e7e7f9fc0f66637343a642) docs: document `ip=` kernel argument\n* [`8e1d0bfb5`](https://github.com/talos-systems/talos/commit/8e1d0bfb5fbaf0849bdd07b73a8e3bda4e8c3b75) feat: update Kubernetes to 1.23.0\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`6fa2d93`](https://github.com/talos-systems/crypto/commit/6fa2d93d0382299d5471e0de8e831c923398aaa8) fix: deepcopy nil fields as `nil`\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`495a5b2`](https://github.com/talos-systems/extras/commit/495a5b2a4964e11a9ae8629788c46a5140d07b10) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`6928ee4`](https://github.com/talos-systems/go-blockdevice/commit/6928ee43c3034549e32f000f8b7bc16a6ebb7ed4) refactor: rewrite GPT serialize/deserialize functions\n* [`0c7e429`](https://github.com/talos-systems/go-blockdevice/commit/0c7e4296e01b3df815a935db3e30de6b9d4cc1d1) refactor: simplify middle endian functions\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>5 commits</summary>\n<p>\n\n* [`2779c3f`](https://github.com/talos-systems/pkgs/commit/2779c3fe825a47a7c392d077f4a38d7f7b2f8eb5) fix: kexec on rpi4\n* [`950361f`](https://github.com/talos-systems/pkgs/commit/950361f79c03f718d73b60ddfbc6f661f4aa93b6) feat: update Linux to 5.15.11\n* [`ad611bc`](https://github.com/talos-systems/pkgs/commit/ad611bc512bd67366e16f0b58c24dfca35f38a12) feat: provide build instructions for NVIDIA kernel module\n* [`b22723d`](https://github.com/talos-systems/pkgs/commit/b22723d0fb4766488f1bc50244d3cdfb9a9d8bbf) feat: update iPXE to the latest available version\n* [`a675c67`](https://github.com/talos-systems/pkgs/commit/a675c676e894c33626563f57e9c124e7628bc78f) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`9c2b9df`](https://github.com/talos-systems/tools/commit/9c2b9dfde84366c486f212cc074405cfb4d52127) feat: update Go to 1.17.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **cloud.google.com/go**                            v0.99.0 **_new_**\n* **github.com/aws/aws-sdk-go**                      v1.42.25 **_new_**\n* **github.com/docker/docker**                       v20.10.11 -> v20.10.12\n* **github.com/google/nftables**                     16a134723a96 -> 6f19c4381e13\n* **github.com/jsimonetti/rtnetlink**                fd9a11f42291 -> 9dff439f7e79\n* **github.com/mdlayher/ethtool**                    288d040e9d60 -> bc8fdcf6e99c\n* **github.com/mdlayher/genetlink**                  v1.0.0 -> v1.1.0\n* **github.com/mdlayher/netlink**                    v1.4.2 -> v1.5.0\n* **github.com/pmorjan/kmod**                        v1.0.0 **_new_**\n* **github.com/spf13/cobra**                         v1.2.1 -> v1.3.0\n* **github.com/talos-systems/crypto**                v0.3.4 -> 6fa2d93d0382\n* **github.com/talos-systems/extras**                v0.7.0-1-gd6b73a7 -> v0.8.0-alpha.0\n* **github.com/talos-systems/go-blockdevice**        v0.2.5 -> 6928ee43c303\n* **github.com/talos-systems/pkgs**                  v0.9.0-1-g7a3419a -> v0.10.0-alpha.0-4-g2779c3f\n* **github.com/talos-systems/tools**                 v0.9.0-1-gb1146f9 -> v0.10.0-alpha.0\n* **golang.org/x/net**                               491a49abca63 -> fe4d6282115f\n* **golang.org/x/sys**                               97ca703d548d -> 1d35b9e2eb4e\n* **golang.zx2c4.com/wireguard/wgctrl**              dd7407c86d22 -> 7a385b3431de\n* **google.golang.org/grpc**                         v1.42.0 -> v1.43.0\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.61 -> v1.2.62\n\nPrevious release can be found at [v0.14.0](https://github.com/talos-systems/talos/releases/tag/v0.14.0)\n\n## [Talos 0.14.0-alpha.2](https://github.com/talos-systems/talos/releases/tag/v0.14.0-alpha.2) (2021-11-30)\n\nWelcome to the v0.14.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Kexec and capabilities\n\nWhen kexec support is disabled\nTalos no longer drops Linux capabilities (`CAP_SYS_BOOT` and `CAP_SYS_MODULES`) for child processes.\nThat is helpful for advanced use-cases like Docker-in-Docker.\n\nIf you want to permanently disable kexec and capabilities dropping, pass `kexec_load_disabled=1` argument to the kernel.\n\nFor example:\n\n```yaml\ninstall:\n  extraKernelArgs:\n    - sysctl.kernel.kexec_load_disabled=1\n```\n\nPlease note that capabilities are dropped before machine configuration is loaded,\nso disabling kexec via `machine.sysctls` will not be enough.\n\n\n### Cluster Discovery\n\n[Cluster Discovery](https://www.talos.dev/docs/v0.14/guides/discovery/) is enabled by default for Talos 0.14.\nCluster Discovery can be disabled with `talosctl gen config --with-cluster-discovery=false`.\n\n\n### Kubelet\n\nKubelet service can now be restarted with `talosctl service kubelet restart`.\n\nKubelet node IP configuration (`.machine.kubelet.nodeIP.validSubnets`) can now include negative subnet matches (prefixed with `!`).\n\n\n### Log Shipping\n\nTalos can now [ship system logs](https://www.talos.dev/docs/v0.14/guides/logging/)\nto the configured destination using either JSON-over-UDP or JSON-over-TCP:\nsee `.machine.logging` machine configuration option.\n\n\n### NTP Sync\n\nTalos NTP sync process was improved to align better with kernel time adjustment periods and to filter out spikes.\n\n\n### SideroLink\n\nA set of Talos ehancements is going to unlock a number of exciting features in the upcoming release of [Sidero](https://www.sidero.dev/):\n\n* `SideroLink`: a point-to-point Wireguard tunnel connecting Talos node back to the provisioning platform (Sidero).\n* event sink (kernel arg `talos.event.sink=http://10.0.0.1:4000`) delivers Talos internal events to the specified destination.\n* kmsg log delivery (kernel arg `talos.logging.kernel=tcp://10.0.0.1:4001`) sends kernel logs as JSON lines over TCP or UDP.\n\n\n### `talosctl support`\n\n`talosctl` CLI tool now has a new subcommand called `support`, that can gather all\ncluster information that could help with future debugging in a single run.\n\nOutput of the command is a `zip` archive with all talos service logs, kubernetes pod logs and manifests,\ntalos resources manifests and so on.\nGenerated archive does not contain any secret information so it is safe to send it for analysis to a third party.\n\n\n### Component Updates\n\n* Linux: 5.15.5\n* etcd: 3.5.1\n* containerd: 1.5.8\n* Kubernetes: 1.23.0-rc.0\n* CoreDNS: 1.8.6\n\nTalos is built with Go 1.17.3\n\n\n### Kubernetes Upgrade Enhancements\n\n`talosctl upgrade-k8s` now syncs all Talos manifest resources generated from templates.\n\nSo there is no need to update CoreDNS, Flannel container manually after running `upgrade-k8s` anymore.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Serge Logvinov\n* Noel Georgi\n* Nico Berlee\n* Spencer Smith\n* Alex Zero\n* Andrew Rynhard\n* Branden Cash\n* David Haines\n* Gerard de Leeuw\n* Michael Fornaro\n* Rui Lopes\n\n### Changes\n<details><summary>136 commits</summary>\n<p>\n\n* [`e9f4b7b2`](https://github.com/talos-systems/talos/commit/e9f4b7b2041223309467227fa8b99cf35b797c72) feat: update Linux to 5.15.5\n* [`4d0a75a3`](https://github.com/talos-systems/talos/commit/4d0a75a3f0795d5a0537c3b59007f97423c072ab) docs: add documentation about logging\n* [`8d1cbeef`](https://github.com/talos-systems/talos/commit/8d1cbeef9f2ae95d04035f5d999aa181fb88e9fc) chore: add API breaking changes detector\n* [`ed7fb9db`](https://github.com/talos-systems/talos/commit/ed7fb9db14554ccc191cc0c989aba38021a59690) feat: move kubelet proccesses to /podruntime cgroup\n* [`2cd3f9be`](https://github.com/talos-systems/talos/commit/2cd3f9be1f36dd3389ee528fa8f0b2548032c2f7) feat: filter out SideroLink addresses by default\n* [`0f169bf9`](https://github.com/talos-systems/talos/commit/0f169bf9b15239bfd35f371832211c42caf4349c) chore: add API deprecations mechanism\n* [`eaf6d472`](https://github.com/talos-systems/talos/commit/eaf6d4720383881c0dcf967dbc4e960d5ef49dd8) refactor: use random port listener in kernel log delivery tests\n* [`bf4c81e7`](https://github.com/talos-systems/talos/commit/bf4c81e7da854b7e9491f4ecb6fce89b026f4a9f) feat: kernel log (kmsg) delivery controller\n* [`f3149780`](https://github.com/talos-systems/talos/commit/f3149780e6663f7dc0fd0091cd6e3df605eac848) feat: update Kubernetes to 1.23.0-rc.0\n* [`b824909d`](https://github.com/talos-systems/talos/commit/b824909d686b1f5a8cd20afe9ca5a4f291a6f12d) fix: disable kexec on RPi4\n* [`3257751b`](https://github.com/talos-systems/talos/commit/3257751bc0a18e0d3bb7097191989440ae473ee6) fix: initialize Drainer properly\n* [`e4bc68bf`](https://github.com/talos-systems/talos/commit/e4bc68bf026966a3326872a1d342ef3b9c05cc9d) fix: leave only a single IPv4/IPv6 address as kubelet's node IP\n* [`e6d00741`](https://github.com/talos-systems/talos/commit/e6d007418efeb5d7f82eb82a35cddacc64ec99ba) feat: update pkgs - Linux 5.15.4, LibreSSL 3.2.7\n* [`d5cbc364`](https://github.com/talos-systems/talos/commit/d5cbc3640256090e354b3896ffea72b8e58874bb) feat: add GCP ccm\n* [`7433150f`](https://github.com/talos-systems/talos/commit/7433150fd84ef0935e1aad91ca654892dc522806) feat: implement events sink controller\n* [`b4a406ae`](https://github.com/talos-systems/talos/commit/b4a406ae7c72e30ba488493682045495cd31dc4e) test: pin cluster API templates version to tag v1alpha4\n* [`9427e78d`](https://github.com/talos-systems/talos/commit/9427e78dc6d581e752bf41a20f1e0379cc99d92d) fix: catch panics in network operator runs\n* [`d1f55f90`](https://github.com/talos-systems/talos/commit/d1f55f90128859d41ada63159d6b2d12e83fabac) fix: update blockdevice library to properly handle absent GPT\n* [`5ac64b2d`](https://github.com/talos-systems/talos/commit/5ac64b2d97c6e013c83a6618c6bece2e70dedd98) chore: set version in unit-tests\n* [`20d39c0b`](https://github.com/talos-systems/talos/commit/20d39c0b48b64f237270e13df7f277abd262d10b) chore: format .proto files\n* [`852bf4a7`](https://github.com/talos-systems/talos/commit/852bf4a7de815b75e2e632de18fae30bd1bc22be) feat: talosctl fish completion support\n* [`6bb75150`](https://github.com/talos-systems/talos/commit/6bb75150a394ee1ef4a3677ab4d8e73f27172209) fix: allow add_key and request_key in kubelet seccomp profile\n* [`6487b21f`](https://github.com/talos-systems/talos/commit/6487b21feb12291419c6fd1f6635a051b0a60afc) feat: update pkgs for u-boot, containerd, etc\n* [`f7d1e777`](https://github.com/talos-systems/talos/commit/f7d1e7776917475507aa99847f88b9c22c9f7b95) feat: provide SideroLink client implementation\n* [`58892cd6`](https://github.com/talos-systems/talos/commit/58892cd697676c19f830f55e8ba1d84cd6000621) fix: unblock events watch on context cancel\n* [`caa76be2`](https://github.com/talos-systems/talos/commit/caa76be2c982d9d6bc8d3103f16b5915796f76b1) fix: containerd failed to load plugin\n* [`1ffa8e04`](https://github.com/talos-systems/talos/commit/1ffa8e0480084264eee551ad177b2443ddb02ead) feat: add ULA prefix for SideroLink\n* [`c6a67b86`](https://github.com/talos-systems/talos/commit/c6a67b8662bb3c6efbe912b19699ace19e70dd3f) fix: ignore not existing nodes on cordoning\n* [`f7302525`](https://github.com/talos-systems/talos/commit/f730252579879df2e95878de292f17f791740804) feat: add new event types\n* [`7c9b082f`](https://github.com/talos-systems/talos/commit/7c9b082f74f26349a0e309d9818d5bc55e672378) feat: update Kubernetes to 1.23.0-beta.0\n* [`750e31c4`](https://github.com/talos-systems/talos/commit/750e31c4a46f2835eca9fc9a085d2bb64e582e40) fix: ignore EBUSY from `kexec_file_load`\n* [`2d11b595`](https://github.com/talos-systems/talos/commit/2d11b59558c98f4cd07a50b25be29b5c355a4495) fix: ignore virtual IP as kubelet node IPs\n* [`030fd349`](https://github.com/talos-systems/talos/commit/030fd349b1c0669d7059f8c6883c85096f6f9ef5) fix: don't run kexec prepare on shutdown and reset\n* [`6dcce20e`](https://github.com/talos-systems/talos/commit/6dcce20e6fa088c3063aab728912731f5e827eb7) test: set proper pod CIDR for Cilium tests\n* [`695300da`](https://github.com/talos-systems/talos/commit/695300dac46c114b8e7e40abdaeece25f7079c88) release(v0.14.0-alpha.1): prepare release\n* [`753a8218`](https://github.com/talos-systems/talos/commit/753a82188f227da4f2f40da5f4d46ebe45774455) refactor: move pkg/resources to machinery\n* [`0102a64a`](https://github.com/talos-systems/talos/commit/0102a64a5f6de2c3fe5d7792c2c5845fc737edff) refactor: remove pkg/resources dependencies on wgtypes, netx\n* [`7462733b`](https://github.com/talos-systems/talos/commit/7462733bcb075b923b8c7ba4a763308c641c49a2) chore: update golangci-lint\n* [`032c99a0`](https://github.com/talos-systems/talos/commit/032c99a0300ccb09105a07434884d2b1f57e537d) refactor: remove pkg/resources dependencies on k8s and base62\n* [`4a5cff45`](https://github.com/talos-systems/talos/commit/4a5cff45f397ac29b7bfc390f11691c32d8615b2) perf: raspberry PIs clockspeed as fast as firmware allows\n* [`a76f6d69`](https://github.com/talos-systems/talos/commit/a76f6d69dbfdf34e4383dd5d2ee9f8cca4661e87) feat: allow kubelet to be restarted and provide negative nodeIP subnets\n* [`189221d5`](https://github.com/talos-systems/talos/commit/189221d589c1c9d4fc012dd9e31fd6d142d88dde) chore: update dependencies\n* [`41f0aecc`](https://github.com/talos-systems/talos/commit/41f0aecc1d3c4afce96d034f160fa9f120c67e85) docs: update partition info\n* [`95105071`](https://github.com/talos-systems/talos/commit/95105071de29f70552bd7c0881c2cc2e7c78c0ac) chore: fix simple issues found by golangci-lint\n* [`d4b0ca21`](https://github.com/talos-systems/talos/commit/d4b0ca21a1ee1183b28738bb3d9ca251e1968fe7) test: retry upgrade mutex lock failures\n* [`4357e9a8`](https://github.com/talos-systems/talos/commit/4357e9a849fcb7fb66378bdd767a926dde0c4318) docs: add Talos partions info\n* [`8e8687d7`](https://github.com/talos-systems/talos/commit/8e8687d7592d4bc071981478491d70489e7dd4a9) fix: use temporary sonobuoy version\n* [`e4e8e873`](https://github.com/talos-systems/talos/commit/e4e8e8737f564be47098e284706a63ef84636890) test: disable e2e-misc test with Canal CNI\n* [`897da2f6`](https://github.com/talos-systems/talos/commit/897da2f6efc571a66d14722a67bbc401bad31887) docs: common typos\n* [`a50483dd`](https://github.com/talos-systems/talos/commit/a50483dddfd9a742b998f509ee713af996a2484e) feat: update Linux to 5.15.1\n* [`a2233bfe`](https://github.com/talos-systems/talos/commit/a2233bfe46bfb55d71cfc07174f6f22aee6d2651) fix: improve NTP sync process\n* [`7efc1238`](https://github.com/talos-systems/talos/commit/7efc1238ee285d55c4619b6a40190b54ff953a66) fix: parse partition size correctly\n* [`d6147eb1`](https://github.com/talos-systems/talos/commit/d6147eb17d2ebf263ca0537068bbbba6d3ced061) chore: update sonobuoy\n* [`efbae785`](https://github.com/talos-systems/talos/commit/efbae7857d09aa7e5e704d5989efced5aa655259) fix: use etc folder for du cli tests\n* [`198eea51`](https://github.com/talos-systems/talos/commit/198eea51a81bf041470c3c88cb6cb97af3a4e203) fix: wait for follow reader to start before writing to the file\n* [`e7f715eb`](https://github.com/talos-systems/talos/commit/e7f715eb0ca0587a05949910cafdeb486654b577) chore: log KubeSpan IPs overlaps\n* [`82a1ad16`](https://github.com/talos-systems/talos/commit/82a1ad1681bf262dcc68fc9cbac71ff2eb5639af) chore: bump dependencies\n* [`e8fccbf5`](https://github.com/talos-systems/talos/commit/e8fccbf5351ec2481813553181cb73b8f16c915a) fix: clear time adjustment error when setting time to specific value\n* [`e6f90bb4`](https://github.com/talos-systems/talos/commit/e6f90bb41a757b5173bbbf7554b6f85c08aaf58e) chore: remove unused parameters\n* [`785161d1`](https://github.com/talos-systems/talos/commit/785161d19f68fb64451cf3d887b67f85a8bcb952) feat: update k8s to 1.23.0-alpha.4\n* [`fe228d7c`](https://github.com/talos-systems/talos/commit/fe228d7c85a1f8437398061b18c090962adc9f29) fix: do not use yaml.v2 in the support cmd\n* [`9b48ca21`](https://github.com/talos-systems/talos/commit/9b48ca21731cce53f0a61f05f74dcd264417d784) fix: endpoints and nodes in generated talosconfig\n* [`6e16fd2f`](https://github.com/talos-systems/talos/commit/6e16fd2feeb3f8bf0b99e6cbe21047b7a5c1f05c) chore: update tools, pkgs, and extras\n* [`261c497c`](https://github.com/talos-systems/talos/commit/261c497c71eb5ab5197bef05d8c209dbeb770d3f) feat: implement `talosctl support` command\n* [`fc7dc454`](https://github.com/talos-systems/talos/commit/fc7dc454840e100d82bb036a7f065293234593f7) chore: check our API idiosyncrasies\n* [`b1584429`](https://github.com/talos-systems/talos/commit/b15844298a6bfedca5acc0cc27061666481eb94b) feat: use GCP deployment manager\n* [`3e7d4df9`](https://github.com/talos-systems/talos/commit/3e7d4df99019e3cc6d9a90920d377c73a76ac577) chore: bump dependencies\n* [`88f24229`](https://github.com/talos-systems/talos/commit/88f2422955690d1eca1e21cd60a35e1d49141e3d) refactor: get rid of prometheus/procfs dependency in pkg/resources\n* [`dd196d30`](https://github.com/talos-systems/talos/commit/dd196d3006d29ae5cae5d43b648da1ca2e5af236) refactor: prepare for move of pkg/resources to machinery\n* [`f6110f80`](https://github.com/talos-systems/talos/commit/f6110f8036bc176188abb583bfa51296c4d3897d) fix: remove listening socket to fix Talos in a container restart\n* [`53bbb13e`](https://github.com/talos-systems/talos/commit/53bbb13ed8592978dc27578fa79b3a2018941427) docs: update docs with emmc boot guide\n* [`8329d211`](https://github.com/talos-systems/talos/commit/8329d21114abf841788be64765378343c12eaf69) chore: split polymorphic RootSecret resource into specific types\n* [`c97becdd`](https://github.com/talos-systems/talos/commit/c97becdd9548d85b2b894a05765f93dcdf9ad803) chore: remove interfaces and routes APIs\n* [`d798635d`](https://github.com/talos-systems/talos/commit/d798635d993a21392b8a7972a689c4be0728db32) feat: automatically limit kubelet node IP family based on service CIDRs\n* [`205a8d6d`](https://github.com/talos-systems/talos/commit/205a8d6dc495e25af87bf0b920d0f55b8a27bbfd) chore: make nethelpers build on all OSes\n* [`5b5dd49f`](https://github.com/talos-systems/talos/commit/5b5dd49f64bef584000655687e5b9c5d25af6a93) feat: extract JSON fields from more log messages\n* [`eb4f1182`](https://github.com/talos-systems/talos/commit/eb4f11822dc0b35541e0576a75ca263ca96d4981) docs: create cluster in hetzner cloud\n* [`728164e2`](https://github.com/talos-systems/talos/commit/728164e25a5705ae5194b416941f3607d592b140) docs: fix kexec_load_disabled param name in release notes\n* [`f6328f09`](https://github.com/talos-systems/talos/commit/f6328f09a2bf8d233a48354dd548fb740e509341) fix: fix filename typo\n* [`01b0f0ab`](https://github.com/talos-systems/talos/commit/01b0f0abb341b387f16d9b3a142af742f36c8c2b) release(v0.14.0-alpha.0): prepare release\n* [`8b620653`](https://github.com/talos-systems/talos/commit/8b6206537a30be049f74f8c4c7350028e6e56c74) fix: skip generating empty `.machine.logging`\n* [`60ad0063`](https://github.com/talos-systems/talos/commit/60ad006367e73f56fd69726e0044f1ce48f18a8b) fix: don't drop ability to use ambient capabilities\n* [`b6b78e7f`](https://github.com/talos-systems/talos/commit/b6b78e7fef3f6ef0c566e1815d1e28f16f868c93) test: add cluster discovery integration tests\n* [`97d64d16`](https://github.com/talos-systems/talos/commit/97d64d160ce7e71c3107adbd31404853f543f7cc) fix: hcloud network config changes\n* [`4c76865d`](https://github.com/talos-systems/talos/commit/4c76865d0ecec726e801a4b8f87e09476481d808) feat: multiple logging improvements\n* [`1d1e1df6`](https://github.com/talos-systems/talos/commit/1d1e1df643832478aaa715aea5f51ad2e61e2880) fix: handle skipped mounts correctly\n* [`0a964d92`](https://github.com/talos-systems/talos/commit/0a964d921922a247293e36b5fecaab466b91d924) test: fix openstack unit-test stability\n* [`72f62ac2`](https://github.com/talos-systems/talos/commit/72f62ac27b5d0a72db409fd003a7cf9c41a03d7c) chore: bump Go and Docker dependencies\n* [`9c48ebe8`](https://github.com/talos-systems/talos/commit/9c48ebe8f94afa85921ee5f1c1e9315201905a92) fix: gcp fetching externalIP\n* [`6c297268`](https://github.com/talos-systems/talos/commit/6c297268ce596c2a875b7c419c85317dc24d9f4f) test: fix e2e k8s version\n* [`ae5af9d3`](https://github.com/talos-systems/talos/commit/ae5af9d3fad399dea95c316d94e3e66b124bfb24) feat: update Kubernetes to 1.23.0-alpha.3\n* [`28d3a69e`](https://github.com/talos-systems/talos/commit/28d3a69e9d4ae7ffa231804e26af6d1f39c07afd) feat: openstack config-drive support\n* [`2258bc49`](https://github.com/talos-systems/talos/commit/2258bc4918e89b3d6fcb841b2ad677f114ddba7e) test: update GCP e2e script to work with new templates\n* [`36b6ace2`](https://github.com/talos-systems/talos/commit/36b6ace25378e8c4a607de6efb6b89a2d52f5cea) feat: update Linux to 5.10.75\n* [`38516a54`](https://github.com/talos-systems/talos/commit/38516a5499d933a8038ce6768946ff096e7c6f98) test: update Talos versions in upgrade tests\n* [`cff20ec7`](https://github.com/talos-systems/talos/commit/cff20ec78340b3855751e13f2ad0e54bd47e9989) fix: change services OOM score\n* [`666a2b62`](https://github.com/talos-systems/talos/commit/666a2b6207d257edda20c9e0411b0d4cd4112aa6) feat: azure platform ipv6 support\n* [`d32814e3`](https://github.com/talos-systems/talos/commit/d32814e302c370ec1e82aa2879186a034cd2a905) feat: extract JSON fields from log lines\n* [`e77d81ff`](https://github.com/talos-systems/talos/commit/e77d81fff31d68f762da3741846f95a6d2303903) fix: treat literal 'unknown' as a valid machine type\n* [`c8e404e3`](https://github.com/talos-systems/talos/commit/c8e404e356878f6cd819a33386b351c1c152c3f5) test: update vars for AWS cluster\n* [`ad23891b`](https://github.com/talos-systems/talos/commit/ad23891b1f6b33409721528c6771304b7ab94b2c) feat: update CoreDNS version 1.8.6\n* [`41299cae`](https://github.com/talos-systems/talos/commit/41299cae9961665c2bf2a642290f8309683f040d) feat: udev rules support\n* [`5237fdc9`](https://github.com/talos-systems/talos/commit/5237fdc957efbb018649b866bfb756f280f589a2) feat: send JSON logs over UDP\n* [`6d44587a`](https://github.com/talos-systems/talos/commit/6d44587a4d4c16defa6bb06329cdfc6e39c95188) feat: coredns service dualstack\n* [`12f7888b`](https://github.com/talos-systems/talos/commit/12f7888b75fa2498e0f8305f5d6910cecad5c65c) feat: feed control plane endpoints on workers from cluster discovery\n* [`431e4fb4`](https://github.com/talos-systems/talos/commit/431e4fb4b690fa4955c407d8dd8156bdecd9a2c5) chore: bump Go and Docker dependencies\n* [`89f3b9f8`](https://github.com/talos-systems/talos/commit/89f3b9f8d41e33c4cb736917f418ab5cfb9edd83) feat: update etcd to 3.5.1\n* [`e60469a3`](https://github.com/talos-systems/talos/commit/e60469a38cb81ace2039bae1927eb6c5f1f0ad1f) feat: initial support for JSON logging\n* [`68c420e3`](https://github.com/talos-systems/talos/commit/68c420e3c96a0fdc3b3e6cd75be24cc797c48e09) feat: enable cluster discovery by default\n* [`3e100aa9`](https://github.com/talos-systems/talos/commit/3e100aa97734ea809563e23fc36e19bdd3df1920) test: workaround EventsWatch test flakiness\n* [`9bd4838a`](https://github.com/talos-systems/talos/commit/9bd4838ac10abbd4760da4fb905d7639a1c26f9f) chore: stop using sonobuoy CLI\n* [`6ad45951`](https://github.com/talos-systems/talos/commit/6ad45951975aac48fdcc282e5a0e31344058d07e) docs: fix field names for bonding configuration\n* [`d7a3b7b5`](https://github.com/talos-systems/talos/commit/d7a3b7b5b70293884d2e19c6a59b14ebcfa24397) chore: use discovery-client and discovery-api modules\n* [`d6309eed`](https://github.com/talos-systems/talos/commit/d6309eed6618abd1b4efd0e3cd18a6c0df39378f) docs: create docs for Talos 0.14\n* [`c0fda643`](https://github.com/talos-systems/talos/commit/c0fda6436ae27d8bbc210ee74a1128968108f6a6) fix: attempt to clean up tasks in containerd runner\n* [`8cf442da`](https://github.com/talos-systems/talos/commit/8cf442daa60d911caff59d1c2c05dd77652c8b51) chore: bump tools, pkgs, extras\n* [`0dad5f4d`](https://github.com/talos-systems/talos/commit/0dad5f4d7846f3fb41ff4ba27395023d33796a61) chore: small cleanup\n* [`e3e2113a`](https://github.com/talos-systems/talos/commit/e3e2113adc058940725b1041827d7adb8895c6cf) feat: upgrade CoreDNS during `upgrade-k8s` call\n* [`d92c98e1`](https://github.com/talos-systems/talos/commit/d92c98e19a054472bff3e0d646756f16c5e65bbf) docs: fix discovery service documentation link\n* [`e44b11c5`](https://github.com/talos-systems/talos/commit/e44b11c595e4cab796128a932843b90734ff6d1d) feat: update containerd to 1.5.7, bump Go dependencies\n* [`24129307`](https://github.com/talos-systems/talos/commit/24129307a14d6e59c6bc0d3586c0c95969bde679) docs: make Talos 0.13 docs latest, update documentation\n* [`31b6e39e`](https://github.com/talos-systems/talos/commit/31b6e39e58a27e1f2c1be500fca8636971bfa5c6) fix: delete expired affiliates from the discovery service\n* [`877a2b6f`](https://github.com/talos-systems/talos/commit/877a2b6fc00eaa7574349f9086d78c04df163840) test: bump CAPI components to v1alpha4\n* [`2ba0e0ac`](https://github.com/talos-systems/talos/commit/2ba0e0ac4ad460409101f5f2374e66698adbba4c) docs: add KubeSpan documentation\n* [`997873b6`](https://github.com/talos-systems/talos/commit/997873b6d3116b59ebb46df66b8aa1cee06df92f) fix: use ECDSA-SHA512 when generating certs for Talos < 0.13\n* [`7137166d`](https://github.com/talos-systems/talos/commit/7137166d1d5817e2d44ead4a01796275f92a9d4a) fix: allow overriding `audit-policy-file` in `kube-apiserver` static pod\n* [`8fcd4219`](https://github.com/talos-systems/talos/commit/8fcd4219671a9359880ba344a2ec7fd65dfe5e2a) chore: fix integration-qemu-race\n* [`91a858b5`](https://github.com/talos-systems/talos/commit/91a858b53704ede86392fe3c155ce9ab3c2d406f) fix: sort output of the argument builder\n* [`657f7a56`](https://github.com/talos-systems/talos/commit/657f7a56b10089e0dc551e178bc85b28d8003243) fix: use ECDSA-SHA256 signature algorithm for Kubernetes certs\n* [`983d2459`](https://github.com/talos-systems/talos/commit/983d2459e2aa036774828f773bbaba5697665ae7) feat: suppress logging NTP sync to the console\n* [`022c7335`](https://github.com/talos-systems/talos/commit/022c7335f3063675ab744454a2ad4b2c0c19bfbc) fix: add interface route if DHCP4 router is not directly routeable\n* [`66a1579e`](https://github.com/talos-systems/talos/commit/66a1579ea7d2a9c4fdf15b762cd024c54b3e8ffb) fix: don't enable 'no new privs' on the system level\n* [`423861cf`](https://github.com/talos-systems/talos/commit/423861cf9f99eaf034a4f0cb243d73d1275c3f38) feat: don't drop capabilities if kexec is disabled\n* [`facc8c38`](https://github.com/talos-systems/talos/commit/facc8c38a021610da900a45f397aea8ddfc74f1c) docs: fix documentation for cluster discovery\n* [`ce65ca4e`](https://github.com/talos-systems/talos/commit/ce65ca4e4a2994f901f01ce5ca269d6df86f0de8) chore: build using only amd64 builders\n* [`e9b0f010`](https://github.com/talos-systems/talos/commit/e9b0f010d2855b968a5d8b8b5fbcd268e06ba302) chore: update docker image in the pipeline\n</p>\n</details>\n\n### Changes since v0.14.0-alpha.1\n<details><summary>34 commits</summary>\n<p>\n\n* [`e9f4b7b2`](https://github.com/talos-systems/talos/commit/e9f4b7b2041223309467227fa8b99cf35b797c72) feat: update Linux to 5.15.5\n* [`4d0a75a3`](https://github.com/talos-systems/talos/commit/4d0a75a3f0795d5a0537c3b59007f97423c072ab) docs: add documentation about logging\n* [`8d1cbeef`](https://github.com/talos-systems/talos/commit/8d1cbeef9f2ae95d04035f5d999aa181fb88e9fc) chore: add API breaking changes detector\n* [`ed7fb9db`](https://github.com/talos-systems/talos/commit/ed7fb9db14554ccc191cc0c989aba38021a59690) feat: move kubelet proccesses to /podruntime cgroup\n* [`2cd3f9be`](https://github.com/talos-systems/talos/commit/2cd3f9be1f36dd3389ee528fa8f0b2548032c2f7) feat: filter out SideroLink addresses by default\n* [`0f169bf9`](https://github.com/talos-systems/talos/commit/0f169bf9b15239bfd35f371832211c42caf4349c) chore: add API deprecations mechanism\n* [`eaf6d472`](https://github.com/talos-systems/talos/commit/eaf6d4720383881c0dcf967dbc4e960d5ef49dd8) refactor: use random port listener in kernel log delivery tests\n* [`bf4c81e7`](https://github.com/talos-systems/talos/commit/bf4c81e7da854b7e9491f4ecb6fce89b026f4a9f) feat: kernel log (kmsg) delivery controller\n* [`f3149780`](https://github.com/talos-systems/talos/commit/f3149780e6663f7dc0fd0091cd6e3df605eac848) feat: update Kubernetes to 1.23.0-rc.0\n* [`b824909d`](https://github.com/talos-systems/talos/commit/b824909d686b1f5a8cd20afe9ca5a4f291a6f12d) fix: disable kexec on RPi4\n* [`3257751b`](https://github.com/talos-systems/talos/commit/3257751bc0a18e0d3bb7097191989440ae473ee6) fix: initialize Drainer properly\n* [`e4bc68bf`](https://github.com/talos-systems/talos/commit/e4bc68bf026966a3326872a1d342ef3b9c05cc9d) fix: leave only a single IPv4/IPv6 address as kubelet's node IP\n* [`e6d00741`](https://github.com/talos-systems/talos/commit/e6d007418efeb5d7f82eb82a35cddacc64ec99ba) feat: update pkgs - Linux 5.15.4, LibreSSL 3.2.7\n* [`d5cbc364`](https://github.com/talos-systems/talos/commit/d5cbc3640256090e354b3896ffea72b8e58874bb) feat: add GCP ccm\n* [`7433150f`](https://github.com/talos-systems/talos/commit/7433150fd84ef0935e1aad91ca654892dc522806) feat: implement events sink controller\n* [`b4a406ae`](https://github.com/talos-systems/talos/commit/b4a406ae7c72e30ba488493682045495cd31dc4e) test: pin cluster API templates version to tag v1alpha4\n* [`9427e78d`](https://github.com/talos-systems/talos/commit/9427e78dc6d581e752bf41a20f1e0379cc99d92d) fix: catch panics in network operator runs\n* [`d1f55f90`](https://github.com/talos-systems/talos/commit/d1f55f90128859d41ada63159d6b2d12e83fabac) fix: update blockdevice library to properly handle absent GPT\n* [`5ac64b2d`](https://github.com/talos-systems/talos/commit/5ac64b2d97c6e013c83a6618c6bece2e70dedd98) chore: set version in unit-tests\n* [`20d39c0b`](https://github.com/talos-systems/talos/commit/20d39c0b48b64f237270e13df7f277abd262d10b) chore: format .proto files\n* [`852bf4a7`](https://github.com/talos-systems/talos/commit/852bf4a7de815b75e2e632de18fae30bd1bc22be) feat: talosctl fish completion support\n* [`6bb75150`](https://github.com/talos-systems/talos/commit/6bb75150a394ee1ef4a3677ab4d8e73f27172209) fix: allow add_key and request_key in kubelet seccomp profile\n* [`6487b21f`](https://github.com/talos-systems/talos/commit/6487b21feb12291419c6fd1f6635a051b0a60afc) feat: update pkgs for u-boot, containerd, etc\n* [`f7d1e777`](https://github.com/talos-systems/talos/commit/f7d1e7776917475507aa99847f88b9c22c9f7b95) feat: provide SideroLink client implementation\n* [`58892cd6`](https://github.com/talos-systems/talos/commit/58892cd697676c19f830f55e8ba1d84cd6000621) fix: unblock events watch on context cancel\n* [`caa76be2`](https://github.com/talos-systems/talos/commit/caa76be2c982d9d6bc8d3103f16b5915796f76b1) fix: containerd failed to load plugin\n* [`1ffa8e04`](https://github.com/talos-systems/talos/commit/1ffa8e0480084264eee551ad177b2443ddb02ead) feat: add ULA prefix for SideroLink\n* [`c6a67b86`](https://github.com/talos-systems/talos/commit/c6a67b8662bb3c6efbe912b19699ace19e70dd3f) fix: ignore not existing nodes on cordoning\n* [`f7302525`](https://github.com/talos-systems/talos/commit/f730252579879df2e95878de292f17f791740804) feat: add new event types\n* [`7c9b082f`](https://github.com/talos-systems/talos/commit/7c9b082f74f26349a0e309d9818d5bc55e672378) feat: update Kubernetes to 1.23.0-beta.0\n* [`750e31c4`](https://github.com/talos-systems/talos/commit/750e31c4a46f2835eca9fc9a085d2bb64e582e40) fix: ignore EBUSY from `kexec_file_load`\n* [`2d11b595`](https://github.com/talos-systems/talos/commit/2d11b59558c98f4cd07a50b25be29b5c355a4495) fix: ignore virtual IP as kubelet node IPs\n* [`030fd349`](https://github.com/talos-systems/talos/commit/030fd349b1c0669d7059f8c6883c85096f6f9ef5) fix: don't run kexec prepare on shutdown and reset\n* [`6dcce20e`](https://github.com/talos-systems/talos/commit/6dcce20e6fa088c3063aab728912731f5e827eb7) test: set proper pod CIDR for Cilium tests\n</p>\n</details>\n\n### Changes from talos-systems/discovery-api\n<details><summary>2 commits</summary>\n<p>\n\n* [`db279ef`](https://github.com/talos-systems/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/talos-systems/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`a9a5e9b`](https://github.com/talos-systems/discovery-client/commit/a9a5e9bfddaa670e0fb4f57510167d377cf09b07) feat: initial client code\n* [`98eb999`](https://github.com/talos-systems/discovery-client/commit/98eb9999c0c76d2f93378108b7e22de6bcae6e81) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`2bb2efc`](https://github.com/talos-systems/extras/commit/2bb2efcbe68bcce2172b9ac7771dde1d0d2b6d3c) chore: update pkgs and tools\n* [`d6e8b3a`](https://github.com/talos-systems/extras/commit/d6e8b3a78e9a3371472753286c559627932466c3) chore: update pkgs and tools\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`15b182d`](https://github.com/talos-systems/go-blockdevice/commit/15b182db0cd233b163ed83d1724c7e28cf29d71a) fix: return partition table not exist when trying to read an empty dev\n* [`b9517d5`](https://github.com/talos-systems/go-blockdevice/commit/b9517d51120d385f97b0026f99ce3c4782940c37) fix: resize partition\n</p>\n</details>\n\n### Changes from talos-systems/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`fd5ec8c`](https://github.com/talos-systems/go-smbios/commit/fd5ec8ce4873790b7fbd46dba9d7f49c9de7176a) fix: remove useless (?) goroutines leading to data race error\n</p>\n</details>\n\n### Changes from talos-systems/net\n<details><summary>2 commits</summary>\n<p>\n\n* [`b4b7181`](https://github.com/talos-systems/net/commit/b4b718179a1aa68e4f54422baf08ca3761723d2d) feat: add a way to filter list of IPs for the machine\n* [`0abe5bd`](https://github.com/talos-systems/net/commit/0abe5bdae8f85e4e976bc4d90e95dcb4be8fb853) feat: implement FilterIPs function\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>22 commits</summary>\n<p>\n\n* [`422276d`](https://github.com/talos-systems/pkgs/commit/422276d5c06b00e63ec0ba0c70b642eedd13eea6) feat: update Linux to 5.15.5\n* [`d385e24`](https://github.com/talos-systems/pkgs/commit/d385e24e868682ca68c74ecdae94af2bd17b4a28) chore: update LibreSSL to 3.2.7\n* [`39a3b76`](https://github.com/talos-systems/pkgs/commit/39a3b76c3dd6d50b266b594c8ee2cc2d5537a5e0) feat: update Linux to 5.15.4\n* [`ca30b50`](https://github.com/talos-systems/pkgs/commit/ca30b509b4cd3ab591a27eb6f76d5c2fd9da3b7e) feat: update u-boot to 2021.10\n* [`cea93f1`](https://github.com/talos-systems/pkgs/commit/cea93f1163d79cea8b44e2f9f0bd645aa2404003) chore: add conformance\n* [`79d16b8`](https://github.com/talos-systems/pkgs/commit/79d16b87f31759a1fbb3eab0a06728382983fce1) feat: update containerd to 1.5.8\n* [`1c76107`](https://github.com/talos-systems/pkgs/commit/1c761077176f46388c4335bb7ceb9f58cc456c44) feat: add mdraid 1/0/10\n* [`740da24`](https://github.com/talos-systems/pkgs/commit/740da24d801cc5a8f47f6badf788faea872a6e72) feat: bump raspberrypi-firmware to 1.20211029\n* [`832dae4`](https://github.com/talos-systems/pkgs/commit/832dae4175d7cd3336fb3637134833e7b9fe1719) fix: enable CONFIG_DM_SNAPSHOT\n* [`f307e64`](https://github.com/talos-systems/pkgs/commit/f307e64e6b2e8a29cff5508ae2da4ae92286771e) feat: update Linux to 5.15.1\n* [`4f0f238`](https://github.com/talos-systems/pkgs/commit/4f0f238decfb93561c5871207da8dd3b1d350961) chore: update tools\n* [`932c3cf`](https://github.com/talos-systems/pkgs/commit/932c3cfff9fcb9ffb671d7e5e10b0ca7c290c058) feat: update libseccomp to 2.5.3\n* [`7f3311e`](https://github.com/talos-systems/pkgs/commit/7f3311e2a3d2ef759d9f909f9872e5b98f9682a5) feat: update cpu governor to schedutil\n* [`b4cdb99`](https://github.com/talos-systems/pkgs/commit/b4cdb991a4aa60b1fa859b44efcd57705d89e9ee) fix: update containerd shas\n* [`80a63d4`](https://github.com/talos-systems/pkgs/commit/80a63d4cf2231383266f244f608a958b94872a99) feat: update Linux to 5.10.75\n* [`5c98efd`](https://github.com/talos-systems/pkgs/commit/5c98efd95d2e2e036d845c63b6268583d853d3fd) feat: add QLogic QED 25/40/100Gb Ethernet NIC driver\n* [`bfb2365`](https://github.com/talos-systems/pkgs/commit/bfb2365b04aa7f92ef87799c47ffde6bc2395785) feat: enable driver for SuperMicro raid controller\n* [`657e16b`](https://github.com/talos-systems/pkgs/commit/657e16b3976ba376401797277e85dd67c9b7e64e) feat: enable Intel VMD driver\n* [`f7d9d72`](https://github.com/talos-systems/pkgs/commit/f7d9d728d468b9e3af2552595c9fb145f9008ef3) feat: enable smarpqi driver and related options\n* [`bca3be0`](https://github.com/talos-systems/pkgs/commit/bca3be04e22367585a60afa421e78707d2c6a1de) feat: enable aqtion device driver\n* [`b88127a`](https://github.com/talos-systems/pkgs/commit/b88127afec39d3039e93dfd6bc20a62415d396f0) chore: update tools\n* [`971735f`](https://github.com/talos-systems/pkgs/commit/971735f4b1914cb1c8f2575aeda9b354ecf842f6) feat: update containerd to 1.5.7\n</p>\n</details>\n\n### Changes from talos-systems/siderolink\n<details><summary>6 commits</summary>\n<p>\n\n* [`d0612a7`](https://github.com/talos-systems/siderolink/commit/d0612a724a1b1336a2bc6a99ed3178e3e40f6d9b) refactor: pass in listener to the log receiver\n* [`d86cdd5`](https://github.com/talos-systems/siderolink/commit/d86cdd59ee7a0e0504b739a913991c272c7fb3f5) feat: implement logreceiver for kernel logs\n* [`f7cadbc`](https://github.com/talos-systems/siderolink/commit/f7cadbcdfbb84d367e27b5af32e89c138d72d9d7) fix: handle duplicate peer updates\n* [`0755b24`](https://github.com/talos-systems/siderolink/commit/0755b24d4682410b251a2a9d662960da15153106) feat: initial implementation of SideroLink\n* [`ee73ea9`](https://github.com/talos-systems/siderolink/commit/ee73ea9575a81be7685f24936b2c48a4508a159e) feat: add Talos events sink proto files and the reference implementation\n* [`1e2cd9d`](https://github.com/talos-systems/siderolink/commit/1e2cd9d38621234a0a6010e33b1bab264f4d9bdf) Initial commit\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`96e0231`](https://github.com/talos-systems/tools/commit/96e0231c0f01a9fe6120a941b21c40e1a37bab36) feat: update squashfs-tools to 4.5\n* [`2c9c826`](https://github.com/talos-systems/tools/commit/2c9c826201dc9f4d869fc00ffac63ee10f5e1101) feat: update libseccomp to 2.5.3\n* [`f713a7c`](https://github.com/talos-systems/tools/commit/f713a7cd96fb1176687f5a6c4ec7d1345bb5e568) feat: update protobuf to 3.19.1, grpc-go to 1.42.0\n* [`972c5ef`](https://github.com/talos-systems/tools/commit/972c5ef413f721ab5ad835dab526850620d05003) feat: update Go to 1.17.3\n* [`f63848c`](https://github.com/talos-systems/tools/commit/f63848c1a756807879f22c752155fe1f36ccec32) feat: update PCRE version and source host\n* [`fab7532`](https://github.com/talos-systems/tools/commit/fab7532fd59519d62a3985684a250273a14f1893) feat: update Go to 1.17.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/AlekSi/pointer**                      v1.1.0 -> v1.2.0\n* **github.com/cenkalti/backoff/v4**                 v4.1.2 **_new_**\n* **github.com/containerd/cgroups**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/containerd**               v1.5.5 -> v1.5.8\n* **github.com/docker/docker**                       v20.10.8 -> v20.10.11\n* **github.com/evanphx/json-patch**                  v4.11.0 -> v5.6.0\n* **github.com/gosuri/uiprogress**                   v0.0.1 **_new_**\n* **github.com/hashicorp/go-getter**                 v1.5.8 -> v1.5.9\n* **github.com/hetznercloud/hcloud-go**              v1.32.0 -> v1.33.1\n* **github.com/insomniacslk/dhcp**                   b95caade3eac -> ad197bcd36fd\n* **github.com/jsimonetti/rtnetlink**                435639c8e6a8 -> 93da33804786\n* **github.com/jxskiss/base62**                      4f11678b909b -> v1.0.0\n* **github.com/mdlayher/ethtool**                    2b88debcdd43 -> 288d040e9d60\n* **github.com/rivo/tview**                          ee97a7ab3975 -> badfa0f0b301\n* **github.com/talos-systems/discovery-api**         v0.1.0 **_new_**\n* **github.com/talos-systems/discovery-client**      v0.1.0 **_new_**\n* **github.com/talos-systems/extras**                v0.6.0 -> v0.7.0-alpha.0-1-g2bb2efc\n* **github.com/talos-systems/go-blockdevice**        v0.2.4 -> 15b182db0cd2\n* **github.com/talos-systems/go-smbios**             v0.1.0 -> fd5ec8ce4873\n* **github.com/talos-systems/net**                   v0.3.0 -> b4b718179a1a\n* **github.com/talos-systems/pkgs**                  v0.8.0 -> v0.9.0-alpha.0-21-g422276d\n* **github.com/talos-systems/siderolink**            v0.1.0 **_new_**\n* **github.com/talos-systems/talos/pkg/machinery**   v0.13.0 -> 1ffa8e048008\n* **github.com/talos-systems/tools**                 v0.8.0 -> v0.9.0-alpha.0-5-g96e0231\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.2 -> v0.55.1\n* **github.com/vmware/govmomi**                      v0.26.1 -> v0.27.2\n* **github.com/vmware/vmw-guestinfo**                687661b8bd8e -> cc1fd90d572c\n* **go.etcd.io/etcd/api/v3**                         v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/v3**                      v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.0 -> v3.5.1\n* **go.uber.org/atomic**                             v1.7.0 **_new_**\n* **golang.org/x/net**                               3ad01bbaa167 -> d83791d6bcd9\n* **golang.org/x/sys**                               39ccf1dd6fa6 -> fe61309f8881\n* **golang.org/x/term**                              140adaaadfaf -> 03fcf44c2211\n* **golang.org/x/time**                              1f47c861a9ac -> f0f3c7e86c11\n* **golang.zx2c4.com/wireguard/wgctrl**              0a2f4901cba6 -> dd7407c86d22\n* **google.golang.org/grpc**                         v1.41.0 -> v1.42.0\n* **inet.af/netaddr**                                85fa6c94624e -> c74959edd3b6\n* **k8s.io/api**                                     v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/apimachinery**                            v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/client-go**                               v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/cri-api**                                 v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/kubectl**                                 v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/kubelet**                                 v0.22.2 -> v0.23.0-alpha.4\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.59 -> v1.2.61\n* **sigs.k8s.io/yaml**                               v1.3.0 **_new_**\n\nPrevious release can be found at [v0.13.0](https://github.com/talos-systems/talos/releases/tag/v0.13.0)\n\n## [Talos 0.14.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.14.0-alpha.1) (2021-11-15)\n\nWelcome to the v0.14.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Kexec and capabilities\n\nWhen kexec support is disabled\nTalos no longer drops Linux capabilities (`CAP_SYS_BOOT` and `CAP_SYS_MODULES`) for child processes.\nThat is helpful for advanced use-cases like Docker-in-Docker.\n\nIf you want to permanently disable kexec and capabilities dropping, pass `kexec_load_disabled=1` argument to the kernel.\n\nFor example:\n\n```yaml\ninstall:\n  extraKernelArgs:\n    - sysctl.kernel.kexec_load_disabled=1\n```\n\nPlease note that capabilities are dropped before machine configuration is loaded,\nso disabling kexec via `machine.sysctls` will not be enough.\n\n\n### Cluster Discovery\n\nCluster Discovery is enabled by default for Talos 0.14.\nCluster Discovery can be disabled with `talosctl gen config --with-cluster-discovery=false`.\n\n\n### Kubelet\n\nKubelet service can now be restarted with `talosctl service kubelet restart`.\n\nKubelet node IP configuration (`.machine.kubelet.nodeIP.validSubnets`) can now include negative subnet matches (prefixed with `!`).\n\n\n### Log Shipping\n\nTalos can now ship system logs to the configured destination using either JSON-over-UDP or JSON-over-TCP:\nsee `.machine.logging` machine configuration option.\n\n\n### `talosctl support`\n\n`talosctl` CLI tool now has a new subcommand called `support`, that can gather all\ncluster information that could help with future debugging in a single run.\n\nOutput of the command is a `zip` archive with all talos service logs, kubernetes pod logs and manifests,\ntalos resources manifests and so on.\nGenerated archive does not contain any secret information so it is safe to send it for analysis to a third party.\n\n\n### Component Updates\n\n* Linux: 5.15.1\n* etcd: 3.5.1\n* containerd: 1.5.7\n* Kubernetes: 1.23.0-alpha.4\n* CoreDNS: 1.8.6\n\nTalos is built with Go 1.17.2\n\n\n### Kubernetes Upgrade Enhancements\n\n`talosctl upgrade-k8s` now syncs all Talos manifest resources generated from templates.\n\nSo there is no need to update CoreDNS, Flannel container manually after running `upgrade-k8s` anymore.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Serge Logvinov\n* Noel Georgi\n* Spencer Smith\n* Nico Berlee\n* Alex Zero\n* Andrew Rynhard\n* Branden Cash\n* David Haines\n* Gerard de Leeuw\n* Michael Fornaro\n* Rui Lopes\n\n### Changes\n<details><summary>101 commits</summary>\n<p>\n\n* [`753a8218`](https://github.com/talos-systems/talos/commit/753a82188f227da4f2f40da5f4d46ebe45774455) refactor: move pkg/resources to machinery\n* [`0102a64a`](https://github.com/talos-systems/talos/commit/0102a64a5f6de2c3fe5d7792c2c5845fc737edff) refactor: remove pkg/resources dependencies on wgtypes, netx\n* [`7462733b`](https://github.com/talos-systems/talos/commit/7462733bcb075b923b8c7ba4a763308c641c49a2) chore: update golangci-lint\n* [`032c99a0`](https://github.com/talos-systems/talos/commit/032c99a0300ccb09105a07434884d2b1f57e537d) refactor: remove pkg/resources dependencies on k8s and base62\n* [`4a5cff45`](https://github.com/talos-systems/talos/commit/4a5cff45f397ac29b7bfc390f11691c32d8615b2) perf: raspberry PIs clockspeed as fast as firmware allows\n* [`a76f6d69`](https://github.com/talos-systems/talos/commit/a76f6d69dbfdf34e4383dd5d2ee9f8cca4661e87) feat: allow kubelet to be restarted and provide negative nodeIP subnets\n* [`189221d5`](https://github.com/talos-systems/talos/commit/189221d589c1c9d4fc012dd9e31fd6d142d88dde) chore: update dependencies\n* [`41f0aecc`](https://github.com/talos-systems/talos/commit/41f0aecc1d3c4afce96d034f160fa9f120c67e85) docs: update partition info\n* [`95105071`](https://github.com/talos-systems/talos/commit/95105071de29f70552bd7c0881c2cc2e7c78c0ac) chore: fix simple issues found by golangci-lint\n* [`d4b0ca21`](https://github.com/talos-systems/talos/commit/d4b0ca21a1ee1183b28738bb3d9ca251e1968fe7) test: retry upgrade mutex lock failures\n* [`4357e9a8`](https://github.com/talos-systems/talos/commit/4357e9a849fcb7fb66378bdd767a926dde0c4318) docs: add Talos partions info\n* [`8e8687d7`](https://github.com/talos-systems/talos/commit/8e8687d7592d4bc071981478491d70489e7dd4a9) fix: use temporary sonobuoy version\n* [`e4e8e873`](https://github.com/talos-systems/talos/commit/e4e8e8737f564be47098e284706a63ef84636890) test: disable e2e-misc test with Canal CNI\n* [`897da2f6`](https://github.com/talos-systems/talos/commit/897da2f6efc571a66d14722a67bbc401bad31887) docs: common typos\n* [`a50483dd`](https://github.com/talos-systems/talos/commit/a50483dddfd9a742b998f509ee713af996a2484e) feat: update Linux to 5.15.1\n* [`a2233bfe`](https://github.com/talos-systems/talos/commit/a2233bfe46bfb55d71cfc07174f6f22aee6d2651) fix: improve NTP sync process\n* [`7efc1238`](https://github.com/talos-systems/talos/commit/7efc1238ee285d55c4619b6a40190b54ff953a66) fix: parse partition size correctly\n* [`d6147eb1`](https://github.com/talos-systems/talos/commit/d6147eb17d2ebf263ca0537068bbbba6d3ced061) chore: update sonobuoy\n* [`efbae785`](https://github.com/talos-systems/talos/commit/efbae7857d09aa7e5e704d5989efced5aa655259) fix: use etc folder for du cli tests\n* [`198eea51`](https://github.com/talos-systems/talos/commit/198eea51a81bf041470c3c88cb6cb97af3a4e203) fix: wait for follow reader to start before writing to the file\n* [`e7f715eb`](https://github.com/talos-systems/talos/commit/e7f715eb0ca0587a05949910cafdeb486654b577) chore: log KubeSpan IPs overlaps\n* [`82a1ad16`](https://github.com/talos-systems/talos/commit/82a1ad1681bf262dcc68fc9cbac71ff2eb5639af) chore: bump dependencies\n* [`e8fccbf5`](https://github.com/talos-systems/talos/commit/e8fccbf5351ec2481813553181cb73b8f16c915a) fix: clear time adjustment error when setting time to specific value\n* [`e6f90bb4`](https://github.com/talos-systems/talos/commit/e6f90bb41a757b5173bbbf7554b6f85c08aaf58e) chore: remove unused parameters\n* [`785161d1`](https://github.com/talos-systems/talos/commit/785161d19f68fb64451cf3d887b67f85a8bcb952) feat: update k8s to 1.23.0-alpha.4\n* [`fe228d7c`](https://github.com/talos-systems/talos/commit/fe228d7c85a1f8437398061b18c090962adc9f29) fix: do not use yaml.v2 in the support cmd\n* [`9b48ca21`](https://github.com/talos-systems/talos/commit/9b48ca21731cce53f0a61f05f74dcd264417d784) fix: endpoints and nodes in generated talosconfig\n* [`6e16fd2f`](https://github.com/talos-systems/talos/commit/6e16fd2feeb3f8bf0b99e6cbe21047b7a5c1f05c) chore: update tools, pkgs, and extras\n* [`261c497c`](https://github.com/talos-systems/talos/commit/261c497c71eb5ab5197bef05d8c209dbeb770d3f) feat: implement `talosctl support` command\n* [`fc7dc454`](https://github.com/talos-systems/talos/commit/fc7dc454840e100d82bb036a7f065293234593f7) chore: check our API idiosyncrasies\n* [`b1584429`](https://github.com/talos-systems/talos/commit/b15844298a6bfedca5acc0cc27061666481eb94b) feat: use GCP deployment manager\n* [`3e7d4df9`](https://github.com/talos-systems/talos/commit/3e7d4df99019e3cc6d9a90920d377c73a76ac577) chore: bump dependencies\n* [`88f24229`](https://github.com/talos-systems/talos/commit/88f2422955690d1eca1e21cd60a35e1d49141e3d) refactor: get rid of prometheus/procfs dependency in pkg/resources\n* [`dd196d30`](https://github.com/talos-systems/talos/commit/dd196d3006d29ae5cae5d43b648da1ca2e5af236) refactor: prepare for move of pkg/resources to machinery\n* [`f6110f80`](https://github.com/talos-systems/talos/commit/f6110f8036bc176188abb583bfa51296c4d3897d) fix: remove listening socket to fix Talos in a container restart\n* [`53bbb13e`](https://github.com/talos-systems/talos/commit/53bbb13ed8592978dc27578fa79b3a2018941427) docs: update docs with emmc boot guide\n* [`8329d211`](https://github.com/talos-systems/talos/commit/8329d21114abf841788be64765378343c12eaf69) chore: split polymorphic RootSecret resource into specific types\n* [`c97becdd`](https://github.com/talos-systems/talos/commit/c97becdd9548d85b2b894a05765f93dcdf9ad803) chore: remove interfaces and routes APIs\n* [`d798635d`](https://github.com/talos-systems/talos/commit/d798635d993a21392b8a7972a689c4be0728db32) feat: automatically limit kubelet node IP family based on service CIDRs\n* [`205a8d6d`](https://github.com/talos-systems/talos/commit/205a8d6dc495e25af87bf0b920d0f55b8a27bbfd) chore: make nethelpers build on all OSes\n* [`5b5dd49f`](https://github.com/talos-systems/talos/commit/5b5dd49f64bef584000655687e5b9c5d25af6a93) feat: extract JSON fields from more log messages\n* [`eb4f1182`](https://github.com/talos-systems/talos/commit/eb4f11822dc0b35541e0576a75ca263ca96d4981) docs: create cluster in hetzner cloud\n* [`728164e2`](https://github.com/talos-systems/talos/commit/728164e25a5705ae5194b416941f3607d592b140) docs: fix kexec_load_disabled param name in release notes\n* [`f6328f09`](https://github.com/talos-systems/talos/commit/f6328f09a2bf8d233a48354dd548fb740e509341) fix: fix filename typo\n* [`01b0f0ab`](https://github.com/talos-systems/talos/commit/01b0f0abb341b387f16d9b3a142af742f36c8c2b) release(v0.14.0-alpha.0): prepare release\n* [`8b620653`](https://github.com/talos-systems/talos/commit/8b6206537a30be049f74f8c4c7350028e6e56c74) fix: skip generating empty `.machine.logging`\n* [`60ad0063`](https://github.com/talos-systems/talos/commit/60ad006367e73f56fd69726e0044f1ce48f18a8b) fix: don't drop ability to use ambient capabilities\n* [`b6b78e7f`](https://github.com/talos-systems/talos/commit/b6b78e7fef3f6ef0c566e1815d1e28f16f868c93) test: add cluster discovery integration tests\n* [`97d64d16`](https://github.com/talos-systems/talos/commit/97d64d160ce7e71c3107adbd31404853f543f7cc) fix: hcloud network config changes\n* [`4c76865d`](https://github.com/talos-systems/talos/commit/4c76865d0ecec726e801a4b8f87e09476481d808) feat: multiple logging improvements\n* [`1d1e1df6`](https://github.com/talos-systems/talos/commit/1d1e1df643832478aaa715aea5f51ad2e61e2880) fix: handle skipped mounts correctly\n* [`0a964d92`](https://github.com/talos-systems/talos/commit/0a964d921922a247293e36b5fecaab466b91d924) test: fix openstack unit-test stability\n* [`72f62ac2`](https://github.com/talos-systems/talos/commit/72f62ac27b5d0a72db409fd003a7cf9c41a03d7c) chore: bump Go and Docker dependencies\n* [`9c48ebe8`](https://github.com/talos-systems/talos/commit/9c48ebe8f94afa85921ee5f1c1e9315201905a92) fix: gcp fetching externalIP\n* [`6c297268`](https://github.com/talos-systems/talos/commit/6c297268ce596c2a875b7c419c85317dc24d9f4f) test: fix e2e k8s version\n* [`ae5af9d3`](https://github.com/talos-systems/talos/commit/ae5af9d3fad399dea95c316d94e3e66b124bfb24) feat: update Kubernetes to 1.23.0-alpha.3\n* [`28d3a69e`](https://github.com/talos-systems/talos/commit/28d3a69e9d4ae7ffa231804e26af6d1f39c07afd) feat: openstack config-drive support\n* [`2258bc49`](https://github.com/talos-systems/talos/commit/2258bc4918e89b3d6fcb841b2ad677f114ddba7e) test: update GCP e2e script to work with new templates\n* [`36b6ace2`](https://github.com/talos-systems/talos/commit/36b6ace25378e8c4a607de6efb6b89a2d52f5cea) feat: update Linux to 5.10.75\n* [`38516a54`](https://github.com/talos-systems/talos/commit/38516a5499d933a8038ce6768946ff096e7c6f98) test: update Talos versions in upgrade tests\n* [`cff20ec7`](https://github.com/talos-systems/talos/commit/cff20ec78340b3855751e13f2ad0e54bd47e9989) fix: change services OOM score\n* [`666a2b62`](https://github.com/talos-systems/talos/commit/666a2b6207d257edda20c9e0411b0d4cd4112aa6) feat: azure platform ipv6 support\n* [`d32814e3`](https://github.com/talos-systems/talos/commit/d32814e302c370ec1e82aa2879186a034cd2a905) feat: extract JSON fields from log lines\n* [`e77d81ff`](https://github.com/talos-systems/talos/commit/e77d81fff31d68f762da3741846f95a6d2303903) fix: treat literal 'unknown' as a valid machine type\n* [`c8e404e3`](https://github.com/talos-systems/talos/commit/c8e404e356878f6cd819a33386b351c1c152c3f5) test: update vars for AWS cluster\n* [`ad23891b`](https://github.com/talos-systems/talos/commit/ad23891b1f6b33409721528c6771304b7ab94b2c) feat: update CoreDNS version 1.8.6\n* [`41299cae`](https://github.com/talos-systems/talos/commit/41299cae9961665c2bf2a642290f8309683f040d) feat: udev rules support\n* [`5237fdc9`](https://github.com/talos-systems/talos/commit/5237fdc957efbb018649b866bfb756f280f589a2) feat: send JSON logs over UDP\n* [`6d44587a`](https://github.com/talos-systems/talos/commit/6d44587a4d4c16defa6bb06329cdfc6e39c95188) feat: coredns service dualstack\n* [`12f7888b`](https://github.com/talos-systems/talos/commit/12f7888b75fa2498e0f8305f5d6910cecad5c65c) feat: feed control plane endpoints on workers from cluster discovery\n* [`431e4fb4`](https://github.com/talos-systems/talos/commit/431e4fb4b690fa4955c407d8dd8156bdecd9a2c5) chore: bump Go and Docker dependencies\n* [`89f3b9f8`](https://github.com/talos-systems/talos/commit/89f3b9f8d41e33c4cb736917f418ab5cfb9edd83) feat: update etcd to 3.5.1\n* [`e60469a3`](https://github.com/talos-systems/talos/commit/e60469a38cb81ace2039bae1927eb6c5f1f0ad1f) feat: initial support for JSON logging\n* [`68c420e3`](https://github.com/talos-systems/talos/commit/68c420e3c96a0fdc3b3e6cd75be24cc797c48e09) feat: enable cluster discovery by default\n* [`3e100aa9`](https://github.com/talos-systems/talos/commit/3e100aa97734ea809563e23fc36e19bdd3df1920) test: workaround EventsWatch test flakiness\n* [`9bd4838a`](https://github.com/talos-systems/talos/commit/9bd4838ac10abbd4760da4fb905d7639a1c26f9f) chore: stop using sonobuoy CLI\n* [`6ad45951`](https://github.com/talos-systems/talos/commit/6ad45951975aac48fdcc282e5a0e31344058d07e) docs: fix field names for bonding configuration\n* [`d7a3b7b5`](https://github.com/talos-systems/talos/commit/d7a3b7b5b70293884d2e19c6a59b14ebcfa24397) chore: use discovery-client and discovery-api modules\n* [`d6309eed`](https://github.com/talos-systems/talos/commit/d6309eed6618abd1b4efd0e3cd18a6c0df39378f) docs: create docs for Talos 0.14\n* [`c0fda643`](https://github.com/talos-systems/talos/commit/c0fda6436ae27d8bbc210ee74a1128968108f6a6) fix: attempt to clean up tasks in containerd runner\n* [`8cf442da`](https://github.com/talos-systems/talos/commit/8cf442daa60d911caff59d1c2c05dd77652c8b51) chore: bump tools, pkgs, extras\n* [`0dad5f4d`](https://github.com/talos-systems/talos/commit/0dad5f4d7846f3fb41ff4ba27395023d33796a61) chore: small cleanup\n* [`e3e2113a`](https://github.com/talos-systems/talos/commit/e3e2113adc058940725b1041827d7adb8895c6cf) feat: upgrade CoreDNS during `upgrade-k8s` call\n* [`d92c98e1`](https://github.com/talos-systems/talos/commit/d92c98e19a054472bff3e0d646756f16c5e65bbf) docs: fix discovery service documentation link\n* [`e44b11c5`](https://github.com/talos-systems/talos/commit/e44b11c595e4cab796128a932843b90734ff6d1d) feat: update containerd to 1.5.7, bump Go dependencies\n* [`24129307`](https://github.com/talos-systems/talos/commit/24129307a14d6e59c6bc0d3586c0c95969bde679) docs: make Talos 0.13 docs latest, update documentation\n* [`31b6e39e`](https://github.com/talos-systems/talos/commit/31b6e39e58a27e1f2c1be500fca8636971bfa5c6) fix: delete expired affiliates from the discovery service\n* [`877a2b6f`](https://github.com/talos-systems/talos/commit/877a2b6fc00eaa7574349f9086d78c04df163840) test: bump CAPI components to v1alpha4\n* [`2ba0e0ac`](https://github.com/talos-systems/talos/commit/2ba0e0ac4ad460409101f5f2374e66698adbba4c) docs: add KubeSpan documentation\n* [`997873b6`](https://github.com/talos-systems/talos/commit/997873b6d3116b59ebb46df66b8aa1cee06df92f) fix: use ECDSA-SHA512 when generating certs for Talos < 0.13\n* [`7137166d`](https://github.com/talos-systems/talos/commit/7137166d1d5817e2d44ead4a01796275f92a9d4a) fix: allow overriding `audit-policy-file` in `kube-apiserver` static pod\n* [`8fcd4219`](https://github.com/talos-systems/talos/commit/8fcd4219671a9359880ba344a2ec7fd65dfe5e2a) chore: fix integration-qemu-race\n* [`91a858b5`](https://github.com/talos-systems/talos/commit/91a858b53704ede86392fe3c155ce9ab3c2d406f) fix: sort output of the argument builder\n* [`657f7a56`](https://github.com/talos-systems/talos/commit/657f7a56b10089e0dc551e178bc85b28d8003243) fix: use ECDSA-SHA256 signature algorithm for Kubernetes certs\n* [`983d2459`](https://github.com/talos-systems/talos/commit/983d2459e2aa036774828f773bbaba5697665ae7) feat: suppress logging NTP sync to the console\n* [`022c7335`](https://github.com/talos-systems/talos/commit/022c7335f3063675ab744454a2ad4b2c0c19bfbc) fix: add interface route if DHCP4 router is not directly routeable\n* [`66a1579e`](https://github.com/talos-systems/talos/commit/66a1579ea7d2a9c4fdf15b762cd024c54b3e8ffb) fix: don't enable 'no new privs' on the system level\n* [`423861cf`](https://github.com/talos-systems/talos/commit/423861cf9f99eaf034a4f0cb243d73d1275c3f38) feat: don't drop capabilities if kexec is disabled\n* [`facc8c38`](https://github.com/talos-systems/talos/commit/facc8c38a021610da900a45f397aea8ddfc74f1c) docs: fix documentation for cluster discovery\n* [`ce65ca4e`](https://github.com/talos-systems/talos/commit/ce65ca4e4a2994f901f01ce5ca269d6df86f0de8) chore: build using only amd64 builders\n* [`e9b0f010`](https://github.com/talos-systems/talos/commit/e9b0f010d2855b968a5d8b8b5fbcd268e06ba302) chore: update docker image in the pipeline\n</p>\n</details>\n\n### Changes since v0.14.0-alpha.0\n<details><summary>44 commits</summary>\n<p>\n\n* [`753a8218`](https://github.com/talos-systems/talos/commit/753a82188f227da4f2f40da5f4d46ebe45774455) refactor: move pkg/resources to machinery\n* [`0102a64a`](https://github.com/talos-systems/talos/commit/0102a64a5f6de2c3fe5d7792c2c5845fc737edff) refactor: remove pkg/resources dependencies on wgtypes, netx\n* [`7462733b`](https://github.com/talos-systems/talos/commit/7462733bcb075b923b8c7ba4a763308c641c49a2) chore: update golangci-lint\n* [`032c99a0`](https://github.com/talos-systems/talos/commit/032c99a0300ccb09105a07434884d2b1f57e537d) refactor: remove pkg/resources dependencies on k8s and base62\n* [`4a5cff45`](https://github.com/talos-systems/talos/commit/4a5cff45f397ac29b7bfc390f11691c32d8615b2) perf: raspberry PIs clockspeed as fast as firmware allows\n* [`a76f6d69`](https://github.com/talos-systems/talos/commit/a76f6d69dbfdf34e4383dd5d2ee9f8cca4661e87) feat: allow kubelet to be restarted and provide negative nodeIP subnets\n* [`189221d5`](https://github.com/talos-systems/talos/commit/189221d589c1c9d4fc012dd9e31fd6d142d88dde) chore: update dependencies\n* [`41f0aecc`](https://github.com/talos-systems/talos/commit/41f0aecc1d3c4afce96d034f160fa9f120c67e85) docs: update partition info\n* [`95105071`](https://github.com/talos-systems/talos/commit/95105071de29f70552bd7c0881c2cc2e7c78c0ac) chore: fix simple issues found by golangci-lint\n* [`d4b0ca21`](https://github.com/talos-systems/talos/commit/d4b0ca21a1ee1183b28738bb3d9ca251e1968fe7) test: retry upgrade mutex lock failures\n* [`4357e9a8`](https://github.com/talos-systems/talos/commit/4357e9a849fcb7fb66378bdd767a926dde0c4318) docs: add Talos partions info\n* [`8e8687d7`](https://github.com/talos-systems/talos/commit/8e8687d7592d4bc071981478491d70489e7dd4a9) fix: use temporary sonobuoy version\n* [`e4e8e873`](https://github.com/talos-systems/talos/commit/e4e8e8737f564be47098e284706a63ef84636890) test: disable e2e-misc test with Canal CNI\n* [`897da2f6`](https://github.com/talos-systems/talos/commit/897da2f6efc571a66d14722a67bbc401bad31887) docs: common typos\n* [`a50483dd`](https://github.com/talos-systems/talos/commit/a50483dddfd9a742b998f509ee713af996a2484e) feat: update Linux to 5.15.1\n* [`a2233bfe`](https://github.com/talos-systems/talos/commit/a2233bfe46bfb55d71cfc07174f6f22aee6d2651) fix: improve NTP sync process\n* [`7efc1238`](https://github.com/talos-systems/talos/commit/7efc1238ee285d55c4619b6a40190b54ff953a66) fix: parse partition size correctly\n* [`d6147eb1`](https://github.com/talos-systems/talos/commit/d6147eb17d2ebf263ca0537068bbbba6d3ced061) chore: update sonobuoy\n* [`efbae785`](https://github.com/talos-systems/talos/commit/efbae7857d09aa7e5e704d5989efced5aa655259) fix: use etc folder for du cli tests\n* [`198eea51`](https://github.com/talos-systems/talos/commit/198eea51a81bf041470c3c88cb6cb97af3a4e203) fix: wait for follow reader to start before writing to the file\n* [`e7f715eb`](https://github.com/talos-systems/talos/commit/e7f715eb0ca0587a05949910cafdeb486654b577) chore: log KubeSpan IPs overlaps\n* [`82a1ad16`](https://github.com/talos-systems/talos/commit/82a1ad1681bf262dcc68fc9cbac71ff2eb5639af) chore: bump dependencies\n* [`e8fccbf5`](https://github.com/talos-systems/talos/commit/e8fccbf5351ec2481813553181cb73b8f16c915a) fix: clear time adjustment error when setting time to specific value\n* [`e6f90bb4`](https://github.com/talos-systems/talos/commit/e6f90bb41a757b5173bbbf7554b6f85c08aaf58e) chore: remove unused parameters\n* [`785161d1`](https://github.com/talos-systems/talos/commit/785161d19f68fb64451cf3d887b67f85a8bcb952) feat: update k8s to 1.23.0-alpha.4\n* [`fe228d7c`](https://github.com/talos-systems/talos/commit/fe228d7c85a1f8437398061b18c090962adc9f29) fix: do not use yaml.v2 in the support cmd\n* [`9b48ca21`](https://github.com/talos-systems/talos/commit/9b48ca21731cce53f0a61f05f74dcd264417d784) fix: endpoints and nodes in generated talosconfig\n* [`6e16fd2f`](https://github.com/talos-systems/talos/commit/6e16fd2feeb3f8bf0b99e6cbe21047b7a5c1f05c) chore: update tools, pkgs, and extras\n* [`261c497c`](https://github.com/talos-systems/talos/commit/261c497c71eb5ab5197bef05d8c209dbeb770d3f) feat: implement `talosctl support` command\n* [`fc7dc454`](https://github.com/talos-systems/talos/commit/fc7dc454840e100d82bb036a7f065293234593f7) chore: check our API idiosyncrasies\n* [`b1584429`](https://github.com/talos-systems/talos/commit/b15844298a6bfedca5acc0cc27061666481eb94b) feat: use GCP deployment manager\n* [`3e7d4df9`](https://github.com/talos-systems/talos/commit/3e7d4df99019e3cc6d9a90920d377c73a76ac577) chore: bump dependencies\n* [`88f24229`](https://github.com/talos-systems/talos/commit/88f2422955690d1eca1e21cd60a35e1d49141e3d) refactor: get rid of prometheus/procfs dependency in pkg/resources\n* [`dd196d30`](https://github.com/talos-systems/talos/commit/dd196d3006d29ae5cae5d43b648da1ca2e5af236) refactor: prepare for move of pkg/resources to machinery\n* [`f6110f80`](https://github.com/talos-systems/talos/commit/f6110f8036bc176188abb583bfa51296c4d3897d) fix: remove listening socket to fix Talos in a container restart\n* [`53bbb13e`](https://github.com/talos-systems/talos/commit/53bbb13ed8592978dc27578fa79b3a2018941427) docs: update docs with emmc boot guide\n* [`8329d211`](https://github.com/talos-systems/talos/commit/8329d21114abf841788be64765378343c12eaf69) chore: split polymorphic RootSecret resource into specific types\n* [`c97becdd`](https://github.com/talos-systems/talos/commit/c97becdd9548d85b2b894a05765f93dcdf9ad803) chore: remove interfaces and routes APIs\n* [`d798635d`](https://github.com/talos-systems/talos/commit/d798635d993a21392b8a7972a689c4be0728db32) feat: automatically limit kubelet node IP family based on service CIDRs\n* [`205a8d6d`](https://github.com/talos-systems/talos/commit/205a8d6dc495e25af87bf0b920d0f55b8a27bbfd) chore: make nethelpers build on all OSes\n* [`5b5dd49f`](https://github.com/talos-systems/talos/commit/5b5dd49f64bef584000655687e5b9c5d25af6a93) feat: extract JSON fields from more log messages\n* [`eb4f1182`](https://github.com/talos-systems/talos/commit/eb4f11822dc0b35541e0576a75ca263ca96d4981) docs: create cluster in hetzner cloud\n* [`728164e2`](https://github.com/talos-systems/talos/commit/728164e25a5705ae5194b416941f3607d592b140) docs: fix kexec_load_disabled param name in release notes\n* [`f6328f09`](https://github.com/talos-systems/talos/commit/f6328f09a2bf8d233a48354dd548fb740e509341) fix: fix filename typo\n</p>\n</details>\n\n### Changes from talos-systems/discovery-api\n<details><summary>2 commits</summary>\n<p>\n\n* [`db279ef`](https://github.com/talos-systems/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/talos-systems/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`a9a5e9b`](https://github.com/talos-systems/discovery-client/commit/a9a5e9bfddaa670e0fb4f57510167d377cf09b07) feat: initial client code\n* [`98eb999`](https://github.com/talos-systems/discovery-client/commit/98eb9999c0c76d2f93378108b7e22de6bcae6e81) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`2bb2efc`](https://github.com/talos-systems/extras/commit/2bb2efcbe68bcce2172b9ac7771dde1d0d2b6d3c) chore: update pkgs and tools\n* [`d6e8b3a`](https://github.com/talos-systems/extras/commit/d6e8b3a78e9a3371472753286c559627932466c3) chore: update pkgs and tools\n</p>\n</details>\n\n### Changes from talos-systems/net\n<details><summary>1 commit</summary>\n<p>\n\n* [`0abe5bd`](https://github.com/talos-systems/net/commit/0abe5bdae8f85e4e976bc4d90e95dcb4be8fb853) feat: implement FilterIPs function\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>15 commits</summary>\n<p>\n\n* [`740da24`](https://github.com/talos-systems/pkgs/commit/740da24d801cc5a8f47f6badf788faea872a6e72) feat: bump raspberrypi-firmware to 1.20211029\n* [`832dae4`](https://github.com/talos-systems/pkgs/commit/832dae4175d7cd3336fb3637134833e7b9fe1719) fix: enable CONFIG_DM_SNAPSHOT\n* [`f307e64`](https://github.com/talos-systems/pkgs/commit/f307e64e6b2e8a29cff5508ae2da4ae92286771e) feat: update Linux to 5.15.1\n* [`4f0f238`](https://github.com/talos-systems/pkgs/commit/4f0f238decfb93561c5871207da8dd3b1d350961) chore: update tools\n* [`932c3cf`](https://github.com/talos-systems/pkgs/commit/932c3cfff9fcb9ffb671d7e5e10b0ca7c290c058) feat: update libseccomp to 2.5.3\n* [`7f3311e`](https://github.com/talos-systems/pkgs/commit/7f3311e2a3d2ef759d9f909f9872e5b98f9682a5) feat: update cpu governor to schedutil\n* [`b4cdb99`](https://github.com/talos-systems/pkgs/commit/b4cdb991a4aa60b1fa859b44efcd57705d89e9ee) fix: update containerd shas\n* [`80a63d4`](https://github.com/talos-systems/pkgs/commit/80a63d4cf2231383266f244f608a958b94872a99) feat: update Linux to 5.10.75\n* [`5c98efd`](https://github.com/talos-systems/pkgs/commit/5c98efd95d2e2e036d845c63b6268583d853d3fd) feat: add QLogic QED 25/40/100Gb Ethernet NIC driver\n* [`bfb2365`](https://github.com/talos-systems/pkgs/commit/bfb2365b04aa7f92ef87799c47ffde6bc2395785) feat: enable driver for SuperMicro raid controller\n* [`657e16b`](https://github.com/talos-systems/pkgs/commit/657e16b3976ba376401797277e85dd67c9b7e64e) feat: enable Intel VMD driver\n* [`f7d9d72`](https://github.com/talos-systems/pkgs/commit/f7d9d728d468b9e3af2552595c9fb145f9008ef3) feat: enable smarpqi driver and related options\n* [`bca3be0`](https://github.com/talos-systems/pkgs/commit/bca3be04e22367585a60afa421e78707d2c6a1de) feat: enable aqtion device driver\n* [`b88127a`](https://github.com/talos-systems/pkgs/commit/b88127afec39d3039e93dfd6bc20a62415d396f0) chore: update tools\n* [`971735f`](https://github.com/talos-systems/pkgs/commit/971735f4b1914cb1c8f2575aeda9b354ecf842f6) feat: update containerd to 1.5.7\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>6 commits</summary>\n<p>\n\n* [`96e0231`](https://github.com/talos-systems/tools/commit/96e0231c0f01a9fe6120a941b21c40e1a37bab36) feat: update squashfs-tools to 4.5\n* [`2c9c826`](https://github.com/talos-systems/tools/commit/2c9c826201dc9f4d869fc00ffac63ee10f5e1101) feat: update libseccomp to 2.5.3\n* [`f713a7c`](https://github.com/talos-systems/tools/commit/f713a7cd96fb1176687f5a6c4ec7d1345bb5e568) feat: update protobuf to 3.19.1, grpc-go to 1.42.0\n* [`972c5ef`](https://github.com/talos-systems/tools/commit/972c5ef413f721ab5ad835dab526850620d05003) feat: update Go to 1.17.3\n* [`f63848c`](https://github.com/talos-systems/tools/commit/f63848c1a756807879f22c752155fe1f36ccec32) feat: update PCRE version and source host\n* [`fab7532`](https://github.com/talos-systems/tools/commit/fab7532fd59519d62a3985684a250273a14f1893) feat: update Go to 1.17.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/AlekSi/pointer**                      v1.1.0 -> v1.2.0\n* **github.com/containerd/cgroups**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/containerd**               v1.5.5 -> v1.5.7\n* **github.com/docker/docker**                       v20.10.8 -> v20.10.10\n* **github.com/evanphx/json-patch**                  v4.11.0 -> v4.12.0\n* **github.com/gosuri/uiprogress**                   v0.0.1 **_new_**\n* **github.com/hashicorp/go-getter**                 v1.5.8 -> v1.5.9\n* **github.com/hetznercloud/hcloud-go**              v1.32.0 -> v1.33.1\n* **github.com/insomniacslk/dhcp**                   b95caade3eac -> ad197bcd36fd\n* **github.com/jsimonetti/rtnetlink**                435639c8e6a8 -> 93da33804786\n* **github.com/jxskiss/base62**                      4f11678b909b -> v1.0.0\n* **github.com/mdlayher/ethtool**                    2b88debcdd43 -> 288d040e9d60\n* **github.com/rivo/tview**                          ee97a7ab3975 -> badfa0f0b301\n* **github.com/talos-systems/discovery-api**         v0.1.0 **_new_**\n* **github.com/talos-systems/discovery-client**      v0.1.0 **_new_**\n* **github.com/talos-systems/extras**                v0.6.0 -> v0.7.0-alpha.0-1-g2bb2efc\n* **github.com/talos-systems/net**                   v0.3.0 -> 0abe5bdae8f8\n* **github.com/talos-systems/pkgs**                  v0.8.0 -> v0.9.0-alpha.0-14-g740da24\n* **github.com/talos-systems/talos/pkg/machinery**   v0.13.0 -> 000000000000\n* **github.com/talos-systems/tools**                 v0.8.0 -> v0.9.0-alpha.0-5-g96e0231\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.2 -> v0.55.0\n* **github.com/vmware/govmomi**                      v0.26.1 -> v0.27.1\n* **github.com/vmware/vmw-guestinfo**                687661b8bd8e -> cc1fd90d572c\n* **go.etcd.io/etcd/api/v3**                         v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/v3**                      v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.0 -> v3.5.1\n* **golang.org/x/net**                               3ad01bbaa167 -> 69e39bad7dc2\n* **golang.org/x/sys**                               39ccf1dd6fa6 -> 0c823b97ae02\n* **golang.org/x/term**                              140adaaadfaf -> 03fcf44c2211\n* **golang.zx2c4.com/wireguard/wgctrl**              0a2f4901cba6 -> 0073765f69ba\n* **google.golang.org/grpc**                         v1.41.0 -> v1.42.0\n* **inet.af/netaddr**                                85fa6c94624e -> c74959edd3b6\n* **k8s.io/api**                                     v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/apimachinery**                            v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/client-go**                               v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/cri-api**                                 v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/kubectl**                                 v0.22.2 -> v0.23.0-alpha.4\n* **k8s.io/kubelet**                                 v0.22.2 -> v0.23.0-alpha.4\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.59 -> v1.2.60\n* **sigs.k8s.io/yaml**                               v1.3.0 **_new_**\n\nPrevious release can be found at [v0.13.0](https://github.com/talos-systems/talos/releases/tag/v0.13.0)\n\n## [Talos 0.14.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.14.0-alpha.0) (2021-10-25)\n\nWelcome to the v0.14.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Kexec and capabilities\n\nWhen kexec support is disabled\nTalos no longer drops Linux capabilities (`CAP_SYS_BOOT` and `CAP_SYS_MODULES`) for child processes.\nThat is helpful for advanced use-cases like Docker-in-Docker.\n\nIf you want to permanently disable kexec and capabilities dropping, pass `kexec_load_disabled=1` argument to the kernel.\n\nFor example:\n\n```yaml\ninstall:\n  extraKernelArgs:\n    - kexec_load_disabled=1\n```\n\nPlease note that capabilities are dropped before machine configuration is loaded,\nso disabling kexec via `machine.sysctls` will not be enough.\n\n\n### Cluster Discovery\n\nCluster Discovery is enabled by default for Talos 0.14.\nCluster Discovery can be disabled with `talosctl gen config --with-cluster-discovery=false`.\n\n\n### Log Shipping\n\nTalos can now ship system logs to the configured destination using either JSON-over-UDP or JSON-over-TCP:\nsee `.machine.logging` machine configuration option.\n\n\n### Component Updates\n\n* Linux: 5.10.75\n* etcd: 3.5.1\n* containerd: 1.5.7\n* Kubernetes: 1.23.0-alpha.0\n* CoreDNS: 1.8.6\n\nTalos is built with Go 1.17.2\n\n\n### Kubernetes Upgrade Enhancements\n\n`talosctl upgrade-k8s` now syncs all Talos manifest resources generated from templates.\n\nSo there is no need to update CoreDNS, Flannel container manually after running `upgrade-k8s` anymore.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Serge Logvinov\n* Artem Chernyshev\n* Spencer Smith\n* Andrew Rynhard\n* Branden Cash\n* Gerard de Leeuw\n\n### Changes\n<details><summary>56 commits</summary>\n<p>\n\n* [`8b620653`](https://github.com/talos-systems/talos/commit/8b6206537a30be049f74f8c4c7350028e6e56c74) fix: skip generating empty `.machine.logging`\n* [`60ad0063`](https://github.com/talos-systems/talos/commit/60ad006367e73f56fd69726e0044f1ce48f18a8b) fix: don't drop ability to use ambient capabilities\n* [`b6b78e7f`](https://github.com/talos-systems/talos/commit/b6b78e7fef3f6ef0c566e1815d1e28f16f868c93) test: add cluster discovery integration tests\n* [`97d64d16`](https://github.com/talos-systems/talos/commit/97d64d160ce7e71c3107adbd31404853f543f7cc) fix: hcloud network config changes\n* [`4c76865d`](https://github.com/talos-systems/talos/commit/4c76865d0ecec726e801a4b8f87e09476481d808) feat: multiple logging improvements\n* [`1d1e1df6`](https://github.com/talos-systems/talos/commit/1d1e1df643832478aaa715aea5f51ad2e61e2880) fix: handle skipped mounts correctly\n* [`0a964d92`](https://github.com/talos-systems/talos/commit/0a964d921922a247293e36b5fecaab466b91d924) test: fix openstack unit-test stability\n* [`72f62ac2`](https://github.com/talos-systems/talos/commit/72f62ac27b5d0a72db409fd003a7cf9c41a03d7c) chore: bump Go and Docker dependencies\n* [`9c48ebe8`](https://github.com/talos-systems/talos/commit/9c48ebe8f94afa85921ee5f1c1e9315201905a92) fix: gcp fetching externalIP\n* [`6c297268`](https://github.com/talos-systems/talos/commit/6c297268ce596c2a875b7c419c85317dc24d9f4f) test: fix e2e k8s version\n* [`ae5af9d3`](https://github.com/talos-systems/talos/commit/ae5af9d3fad399dea95c316d94e3e66b124bfb24) feat: update Kubernetes to 1.23.0-alpha.3\n* [`28d3a69e`](https://github.com/talos-systems/talos/commit/28d3a69e9d4ae7ffa231804e26af6d1f39c07afd) feat: openstack config-drive support\n* [`2258bc49`](https://github.com/talos-systems/talos/commit/2258bc4918e89b3d6fcb841b2ad677f114ddba7e) test: update GCP e2e script to work with new templates\n* [`36b6ace2`](https://github.com/talos-systems/talos/commit/36b6ace25378e8c4a607de6efb6b89a2d52f5cea) feat: update Linux to 5.10.75\n* [`38516a54`](https://github.com/talos-systems/talos/commit/38516a5499d933a8038ce6768946ff096e7c6f98) test: update Talos versions in upgrade tests\n* [`cff20ec7`](https://github.com/talos-systems/talos/commit/cff20ec78340b3855751e13f2ad0e54bd47e9989) fix: change services OOM score\n* [`666a2b62`](https://github.com/talos-systems/talos/commit/666a2b6207d257edda20c9e0411b0d4cd4112aa6) feat: azure platform ipv6 support\n* [`d32814e3`](https://github.com/talos-systems/talos/commit/d32814e302c370ec1e82aa2879186a034cd2a905) feat: extract JSON fields from log lines\n* [`e77d81ff`](https://github.com/talos-systems/talos/commit/e77d81fff31d68f762da3741846f95a6d2303903) fix: treat literal 'unknown' as a valid machine type\n* [`c8e404e3`](https://github.com/talos-systems/talos/commit/c8e404e356878f6cd819a33386b351c1c152c3f5) test: update vars for AWS cluster\n* [`ad23891b`](https://github.com/talos-systems/talos/commit/ad23891b1f6b33409721528c6771304b7ab94b2c) feat: update CoreDNS version 1.8.6\n* [`41299cae`](https://github.com/talos-systems/talos/commit/41299cae9961665c2bf2a642290f8309683f040d) feat: udev rules support\n* [`5237fdc9`](https://github.com/talos-systems/talos/commit/5237fdc957efbb018649b866bfb756f280f589a2) feat: send JSON logs over UDP\n* [`6d44587a`](https://github.com/talos-systems/talos/commit/6d44587a4d4c16defa6bb06329cdfc6e39c95188) feat: coredns service dualstack\n* [`12f7888b`](https://github.com/talos-systems/talos/commit/12f7888b75fa2498e0f8305f5d6910cecad5c65c) feat: feed control plane endpoints on workers from cluster discovery\n* [`431e4fb4`](https://github.com/talos-systems/talos/commit/431e4fb4b690fa4955c407d8dd8156bdecd9a2c5) chore: bump Go and Docker dependencies\n* [`89f3b9f8`](https://github.com/talos-systems/talos/commit/89f3b9f8d41e33c4cb736917f418ab5cfb9edd83) feat: update etcd to 3.5.1\n* [`e60469a3`](https://github.com/talos-systems/talos/commit/e60469a38cb81ace2039bae1927eb6c5f1f0ad1f) feat: initial support for JSON logging\n* [`68c420e3`](https://github.com/talos-systems/talos/commit/68c420e3c96a0fdc3b3e6cd75be24cc797c48e09) feat: enable cluster discovery by default\n* [`3e100aa9`](https://github.com/talos-systems/talos/commit/3e100aa97734ea809563e23fc36e19bdd3df1920) test: workaround EventsWatch test flakiness\n* [`9bd4838a`](https://github.com/talos-systems/talos/commit/9bd4838ac10abbd4760da4fb905d7639a1c26f9f) chore: stop using sonobuoy CLI\n* [`6ad45951`](https://github.com/talos-systems/talos/commit/6ad45951975aac48fdcc282e5a0e31344058d07e) docs: fix field names for bonding configuration\n* [`d7a3b7b5`](https://github.com/talos-systems/talos/commit/d7a3b7b5b70293884d2e19c6a59b14ebcfa24397) chore: use discovery-client and discovery-api modules\n* [`d6309eed`](https://github.com/talos-systems/talos/commit/d6309eed6618abd1b4efd0e3cd18a6c0df39378f) docs: create docs for Talos 0.14\n* [`c0fda643`](https://github.com/talos-systems/talos/commit/c0fda6436ae27d8bbc210ee74a1128968108f6a6) fix: attempt to clean up tasks in containerd runner\n* [`8cf442da`](https://github.com/talos-systems/talos/commit/8cf442daa60d911caff59d1c2c05dd77652c8b51) chore: bump tools, pkgs, extras\n* [`0dad5f4d`](https://github.com/talos-systems/talos/commit/0dad5f4d7846f3fb41ff4ba27395023d33796a61) chore: small cleanup\n* [`e3e2113a`](https://github.com/talos-systems/talos/commit/e3e2113adc058940725b1041827d7adb8895c6cf) feat: upgrade CoreDNS during `upgrade-k8s` call\n* [`d92c98e1`](https://github.com/talos-systems/talos/commit/d92c98e19a054472bff3e0d646756f16c5e65bbf) docs: fix discovery service documentation link\n* [`e44b11c5`](https://github.com/talos-systems/talos/commit/e44b11c595e4cab796128a932843b90734ff6d1d) feat: update containerd to 1.5.7, bump Go dependencies\n* [`24129307`](https://github.com/talos-systems/talos/commit/24129307a14d6e59c6bc0d3586c0c95969bde679) docs: make Talos 0.13 docs latest, update documentation\n* [`31b6e39e`](https://github.com/talos-systems/talos/commit/31b6e39e58a27e1f2c1be500fca8636971bfa5c6) fix: delete expired affiliates from the discovery service\n* [`877a2b6f`](https://github.com/talos-systems/talos/commit/877a2b6fc00eaa7574349f9086d78c04df163840) test: bump CAPI components to v1alpha4\n* [`2ba0e0ac`](https://github.com/talos-systems/talos/commit/2ba0e0ac4ad460409101f5f2374e66698adbba4c) docs: add KubeSpan documentation\n* [`997873b6`](https://github.com/talos-systems/talos/commit/997873b6d3116b59ebb46df66b8aa1cee06df92f) fix: use ECDSA-SHA512 when generating certs for Talos < 0.13\n* [`7137166d`](https://github.com/talos-systems/talos/commit/7137166d1d5817e2d44ead4a01796275f92a9d4a) fix: allow overriding `audit-policy-file` in `kube-apiserver` static pod\n* [`8fcd4219`](https://github.com/talos-systems/talos/commit/8fcd4219671a9359880ba344a2ec7fd65dfe5e2a) chore: fix integration-qemu-race\n* [`91a858b5`](https://github.com/talos-systems/talos/commit/91a858b53704ede86392fe3c155ce9ab3c2d406f) fix: sort output of the argument builder\n* [`657f7a56`](https://github.com/talos-systems/talos/commit/657f7a56b10089e0dc551e178bc85b28d8003243) fix: use ECDSA-SHA256 signature algorithm for Kubernetes certs\n* [`983d2459`](https://github.com/talos-systems/talos/commit/983d2459e2aa036774828f773bbaba5697665ae7) feat: suppress logging NTP sync to the console\n* [`022c7335`](https://github.com/talos-systems/talos/commit/022c7335f3063675ab744454a2ad4b2c0c19bfbc) fix: add interface route if DHCP4 router is not directly routeable\n* [`66a1579e`](https://github.com/talos-systems/talos/commit/66a1579ea7d2a9c4fdf15b762cd024c54b3e8ffb) fix: don't enable 'no new privs' on the system level\n* [`423861cf`](https://github.com/talos-systems/talos/commit/423861cf9f99eaf034a4f0cb243d73d1275c3f38) feat: don't drop capabilities if kexec is disabled\n* [`facc8c38`](https://github.com/talos-systems/talos/commit/facc8c38a021610da900a45f397aea8ddfc74f1c) docs: fix documentation for cluster discovery\n* [`ce65ca4e`](https://github.com/talos-systems/talos/commit/ce65ca4e4a2994f901f01ce5ca269d6df86f0de8) chore: build using only amd64 builders\n* [`e9b0f010`](https://github.com/talos-systems/talos/commit/e9b0f010d2855b968a5d8b8b5fbcd268e06ba302) chore: update docker image in the pipeline\n</p>\n</details>\n\n### Changes from talos-systems/discovery-api\n<details><summary>2 commits</summary>\n<p>\n\n* [`db279ef`](https://github.com/talos-systems/discovery-api/commit/db279ef42a1fad2e1feb4902150b4969f7082c81) feat: initial set of APIs and generated files\n* [`ac52a37`](https://github.com/talos-systems/discovery-api/commit/ac52a378211475ebd281dcbb00954eec42459778) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/discovery-client\n<details><summary>2 commits</summary>\n<p>\n\n* [`a9a5e9b`](https://github.com/talos-systems/discovery-client/commit/a9a5e9bfddaa670e0fb4f57510167d377cf09b07) feat: initial client code\n* [`98eb999`](https://github.com/talos-systems/discovery-client/commit/98eb9999c0c76d2f93378108b7e22de6bcae6e81) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`d6e8b3a`](https://github.com/talos-systems/extras/commit/d6e8b3a78e9a3371472753286c559627932466c3) chore: update pkgs and tools\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>8 commits</summary>\n<p>\n\n* [`80a63d4`](https://github.com/talos-systems/pkgs/commit/80a63d4cf2231383266f244f608a958b94872a99) feat: update Linux to 5.10.75\n* [`5c98efd`](https://github.com/talos-systems/pkgs/commit/5c98efd95d2e2e036d845c63b6268583d853d3fd) feat: add QLogic QED 25/40/100Gb Ethernet NIC driver\n* [`bfb2365`](https://github.com/talos-systems/pkgs/commit/bfb2365b04aa7f92ef87799c47ffde6bc2395785) feat: enable driver for SuperMicro raid controller\n* [`657e16b`](https://github.com/talos-systems/pkgs/commit/657e16b3976ba376401797277e85dd67c9b7e64e) feat: enable Intel VMD driver\n* [`f7d9d72`](https://github.com/talos-systems/pkgs/commit/f7d9d728d468b9e3af2552595c9fb145f9008ef3) feat: enable smarpqi driver and related options\n* [`bca3be0`](https://github.com/talos-systems/pkgs/commit/bca3be04e22367585a60afa421e78707d2c6a1de) feat: enable aqtion device driver\n* [`b88127a`](https://github.com/talos-systems/pkgs/commit/b88127afec39d3039e93dfd6bc20a62415d396f0) chore: update tools\n* [`971735f`](https://github.com/talos-systems/pkgs/commit/971735f4b1914cb1c8f2575aeda9b354ecf842f6) feat: update containerd to 1.5.7\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`fab7532`](https://github.com/talos-systems/tools/commit/fab7532fd59519d62a3985684a250273a14f1893) feat: update Go to 1.17.2\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/AlekSi/pointer**                      v1.1.0 -> v1.2.0\n* **github.com/containerd/cgroups**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/containerd**               v1.5.5 -> v1.5.7\n* **github.com/docker/docker**                       v20.10.8 -> v20.10.9\n* **github.com/hashicorp/go-getter**                 v1.5.8 -> v1.5.9\n* **github.com/insomniacslk/dhcp**                   b95caade3eac -> 509557e9f781\n* **github.com/jsimonetti/rtnetlink**                435639c8e6a8 -> e34540a94caa\n* **github.com/jxskiss/base62**                      4f11678b909b -> v1.0.0\n* **github.com/rivo/tview**                          ee97a7ab3975 -> 5508f4b00266\n* **github.com/talos-systems/discovery-api**         v0.1.0 **_new_**\n* **github.com/talos-systems/discovery-client**      v0.1.0 **_new_**\n* **github.com/talos-systems/extras**                v0.6.0 -> v0.7.0-alpha.0\n* **github.com/talos-systems/pkgs**                  v0.8.0 -> v0.9.0-alpha.0-7-g80a63d4\n* **github.com/talos-systems/talos/pkg/machinery**   v0.13.0 -> 000000000000\n* **github.com/talos-systems/tools**                 v0.8.0 -> v0.9.0-alpha.0\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.2 -> v0.54.0\n* **github.com/vmware/govmomi**                      v0.26.1 -> v0.27.1\n* **github.com/vmware/vmw-guestinfo**                687661b8bd8e -> cc1fd90d572c\n* **go.etcd.io/etcd/api/v3**                         v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/pkg/v3**                  v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/client/v3**                      v3.5.0 -> v3.5.1\n* **go.etcd.io/etcd/etcdutl/v3**                     v3.5.0 -> v3.5.1\n* **golang.org/x/net**                               3ad01bbaa167 -> d418f374d309\n* **golang.org/x/sys**                               39ccf1dd6fa6 -> d6a326fbbf70\n* **golang.org/x/term**                              140adaaadfaf -> 03fcf44c2211\n* **golang.zx2c4.com/wireguard/wgctrl**              0a2f4901cba6 -> 5be1d6054c42\n* **k8s.io/api**                                     v0.22.2 -> v0.23.0-alpha.3\n* **k8s.io/apimachinery**                            v0.22.2 -> v0.23.0-alpha.3\n* **k8s.io/client-go**                               v0.22.2 -> v0.23.0-alpha.3\n* **k8s.io/cri-api**                                 v0.22.2 -> v0.23.0-alpha.3\n* **k8s.io/kubectl**                                 v0.22.2 -> v0.23.0-alpha.3\n* **k8s.io/kubelet**                                 v0.22.2 -> v0.23.0-alpha.3\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.59 -> v1.2.60\n* **sigs.k8s.io/yaml**                               v1.3.0 **_new_**\n\nPrevious release can be found at [v0.13.0](https://github.com/talos-systems/talos/releases/tag/v0.13.0)\n\n## [Talos 0.13.0-alpha.3](https://github.com/talos-systems/talos/releases/tag/v0.13.0-alpha.3) (2021-09-29)\n\nWelcome to the v0.13.0-alpha.3 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Hetzner, Scaleway, Upcloud and Vultr\n\nTalos now natively supports three new cloud platforms:\n\n* [Hetzner](https://www.hetzner.com/), including VIP support\n* [Scaleway](https://www.scaleway.com/en/)\n* [Upcloud](https://upcloud.com/)\n* [Vultr](https://www.vultr.com/)\n\nAlso generic `cloud-init` `nocloud` platform is supported in both networking and storage-based modes.\n\n\n### etcd Advertised Address\n\nThe address advertised by etcd can now be controlled with new machine configuration option `machine.etcd.subnet`.\n\n\n### Reboots via kexec\n\nTalos now reboots by default via kexec syscall which means BIOS POST process is skipped.\nOn bare-metal hardware BIOS POST process might take 10-15 minutes, so Talos reboots 10-15 minutes faster on bare-metal.\n\nKexec support can be disabled with the following change to the machine configuration:\n\n```\nmachine:\n  sysctls:\n    kernel.kexec_load_disabled: \"1\"\n```\n\n\n### Cluster Discovery and KubeSpan\n\nThis release of Talos provides initial support for cluster membership discovery and [KubeSpan](https://www.talos-systems.com/kubespan/).\n\nThese new features are not enabled by default, to enable them please make following changes to the machine configuration:\n\n```yaml\nmachine:\n  network:\n    kubespan:\n      enabled: true\ncluster:\n  discovery:\n    enabled: true\n```\n\n\n\n### Windows Support\n\nCLI tool talosctl is now built for Windows and published as part of the release.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Artem Chernyshev\n* Seán C McCord\n* Serge Logvinov\n* Alexey Palazhchenko\n* Andrew Rynhard\n* Olli Janatuinen\n* Andrey Smirnov\n* Lennard Klein\n* Rui Lopes\n* Spencer Smith\n\n### Changes\n<details><summary>100 commits</summary>\n<p>\n\n* [`4044372e`](https://github.com/talos-systems/talos/commit/4044372e12ff5308ba9cb9178a7e6b3b32955aab) feat: harvest discovered endpoints and push them via discovery svc\n* [`9a51aa83`](https://github.com/talos-systems/talos/commit/9a51aa83581b25bdb0604904027a4cedf21b8123) feat: add an option to skip downed peers in KubeSpan\n* [`cbbd7c68`](https://github.com/talos-systems/talos/commit/cbbd7c68219808a4f4b0d805203326019ce14ec9) feat: publish node's ExternalIPs as node addresses\n* [`0f60ef6d`](https://github.com/talos-systems/talos/commit/0f60ef6d38f9f5978a19e0ca4c6729af03a11f0e) fix: reset inputs back to initial state in secrets.APIController\n* [`64cb873e`](https://github.com/talos-systems/talos/commit/64cb873ec4421d43b291acb8afe75f65728d5732) feat: override static pods default args by extra Args\n* [`ecdd7757`](https://github.com/talos-systems/talos/commit/ecdd7757fb5906d6fa904581efff74a16b22ae4b) test: workaround race in the tests with zaptest package\n* [`9c67fde7`](https://github.com/talos-systems/talos/commit/9c67fde759de1e2a9f2b4406d85485d3d71c3d99) release(v0.13.0-alpha.2): prepare release\n* [`30ae7142`](https://github.com/talos-systems/talos/commit/30ae714243379aaa3fb1e93023c2249ff3c3b4e3) feat: implement integration with Discovery Service\n* [`353d632a`](https://github.com/talos-systems/talos/commit/353d632ae5d944a8662f0746ff8e757a67ffca53) feat: add nocloud platform support\n* [`628fbf9b`](https://github.com/talos-systems/talos/commit/628fbf9b48d98df1063285b14958c94d246ce102) chore: update Linux to 5.10.69\n* [`62acd625`](https://github.com/talos-systems/talos/commit/62acd6251637250dbea7d408d8cd4d5eb1f18713) fix: check trustd API CA on worker nodes\n* [`ba27bc36`](https://github.com/talos-systems/talos/commit/ba27bc366fb3166b22f1bda909b9ede486ad8c7d) feat: implement Hetzner Cloud support for virtual (shared) IP\n* [`95f440ea`](https://github.com/talos-systems/talos/commit/95f440eaa06d2a558fc828c11b451b6aed8d5855) test: add fuzz test for configloader\n* [`d2cf021d`](https://github.com/talos-systems/talos/commit/d2cf021d8ffb6d6188b2d50f1f7b9c24df0aac84) chore: remove deprecated \"join\" term\n* [`0e18e280`](https://github.com/talos-systems/talos/commit/0e18e2800fc038a86ed2fd9b042278ae29070bb5) chore: bump dependencies\n* [`b450b7ce`](https://github.com/talos-systems/talos/commit/b450b7cef0d84a9ad975d8b50b93854bb0645173) chore: deprecate Interfaces and Routes APIs\n* [`cddcb962`](https://github.com/talos-systems/talos/commit/cddcb9622bce7ae3626b8b9dce8c622a0e30ba66) fix: find devices without partition table\n* [`b1b6d613`](https://github.com/talos-systems/talos/commit/b1b6d61365c900c4ebfc377b86067ddbe4fe8353) fix: check for existence of dhcp6 FQDN first\n* [`519999b8`](https://github.com/talos-systems/talos/commit/519999b8462ff4931ed12323417b9a9c8c20b369) fix: use readonly mode when probing devices with `All` lookup\n* [`2b520420`](https://github.com/talos-systems/talos/commit/2b5204200a4bd22aa78245b201c471136016ce3a) feat: enable resource API in the maintenance mode\n* [`452893c2`](https://github.com/talos-systems/talos/commit/452893c260b920c601b0fc22ff018dc2d4341fca) fix: make probe open blockdevice in readonly mode\n* [`96bccdd3`](https://github.com/talos-systems/talos/commit/96bccdd3b625f0edefd685cadf5f2cd46e3111f5) test: update CABPT provider to 0.3 release\n* [`d9eb18bf`](https://github.com/talos-systems/talos/commit/d9eb18bfddf69a61712d930b53aec489a806394a) fix: containerd log symlink\n* [`efa7f48e`](https://github.com/talos-systems/talos/commit/efa7f48e08382249609e0ecd3241c01a2e46df73) docs: quicklinks on landing page\n* [`1cb9f282`](https://github.com/talos-systems/talos/commit/1cb9f282b541505f2d61ae0a57655cba9ae62843) fix: don't marshal clock with SecretsBundle\n* [`b27c75b3`](https://github.com/talos-systems/talos/commit/b27c75b30f689dafa7d4effd0c2eaf8f0f3f8caf) release(v0.13.0-alpha.1): prepare release\n* [`9d803d75`](https://github.com/talos-systems/talos/commit/9d803d75bfbe788fa5c2ef2ae0639de31e172c7b) chore: bump dependencies and drop firecracker support\n* [`50a24104`](https://github.com/talos-systems/talos/commit/50a24104820e26bb99e66ab68be2bd9a6c17b0be) feat: add operating system version field to discovery\n* [`085c61b2`](https://github.com/talos-systems/talos/commit/085c61b2ec432c586daa77464910e967a223ebe0) chore: add a special condition to check for kubeconfig readiness\n* [`21cdd854`](https://github.com/talos-systems/talos/commit/21cdd854036498fbeb9f6e4d058a0edd55ed4856) fix: add node address to the list of allowed IPs (kubespan)\n* [`fdd80a12`](https://github.com/talos-systems/talos/commit/fdd80a1234dc993cc01daa7764ba5a9db2fdc275) feat: add an option to continue booting on NTP timeout\n* [`ef368498`](https://github.com/talos-systems/talos/commit/ef36849899b18bbb35c6116fdf35aa580a50a5e5) feat: add routes, routing rules and nftables rules for KubeSpan\n* [`ed12379f`](https://github.com/talos-systems/talos/commit/ed12379f2f49fcbca84080f1066cf52dc202bd2d) fix: patch multi nodes support\n* [`d943bb0e`](https://github.com/talos-systems/talos/commit/d943bb0e280e90f3592d9f7b67813b7a15818c84) feat: update Kubernetes to 1.22.2\n* [`d0585fb6`](https://github.com/talos-systems/talos/commit/d0585fb6b303dfdd7fc80a76024915df31c72389) feat: reboot via kexec\n* [`3de505c8`](https://github.com/talos-systems/talos/commit/3de505c894274bfd5248b6c597f6e3a53f873ba1) fix: skip bad cloud-config in OpenStack platform\n* [`a394d1e2`](https://github.com/talos-systems/talos/commit/a394d1e20ba82de7d05e4d3f91823a98362ac9ee) fix: tear down control plane static pods when etcd is stopped\n* [`1c05089b`](https://github.com/talos-systems/talos/commit/1c05089bb22c7c1050e95cf8d7bea8b763a0e86f) feat: implement KubeSpan manager for Wireguard peer state\n* [`ec7f44ef`](https://github.com/talos-systems/talos/commit/ec7f44efe4f89e7ed207cbd5fe3748953ccfdf28) fix: completely prevent editing resources other than mc\n* [`19a8ae97`](https://github.com/talos-systems/talos/commit/19a8ae97c69949f7c2421154b2ae4e52a905ff63) feat: add vultr.com cloud support\n* [`0ff4c7cd`](https://github.com/talos-systems/talos/commit/0ff4c7cdb2b9505823f4c4504ec9bf4d7fddf5c5) fix: write KubernetesCACert chmodded 0400 instead of 0500\n* [`a1c9d649`](https://github.com/talos-systems/talos/commit/a1c9d64907cce75bcb566f3ee394734e29b3932d) fix: update the way results are retrieved for certified conformance\n* [`a0594540`](https://github.com/talos-systems/talos/commit/a0594540451a7636f8cd4bbe835913d31f66d0de) chore: build using Go 1.17\n* [`7c5045bd`](https://github.com/talos-systems/talos/commit/7c5045bd929fcf5028cae3840970e692ef3bc7c9) release(v0.13.0-alpha.0): prepare release\n* [`ee2dce6c`](https://github.com/talos-systems/talos/commit/ee2dce6c1a0e8838e587a9136afd1b7381000432) chore: bump dependencies\n* [`ef022959`](https://github.com/talos-systems/talos/commit/ef022959280f156d6311836ef9cc2d01e5e3ae7d) fix: print etcd member ID in hex\n* [`5ca1fb82`](https://github.com/talos-systems/talos/commit/5ca1fb822125483be290e79d8828bba246fda51c) fix: multiple fixes for KubeSpan and Wireguard implementation\n* [`b1bd6425`](https://github.com/talos-systems/talos/commit/b1bd64250820df3fcb5214368ce9c8cf4634970a) fix: build platform images\n* [`3b5f4038`](https://github.com/talos-systems/talos/commit/3b5f4038de2f855b3b634e4abb1c564da624e2fc) feat: add scaleway.com cloud support\n* [`f156ab18`](https://github.com/talos-systems/talos/commit/f156ab1847f2ad1ca2a2548b299a713ee5fe0fcd) feat: add upcloud.com cloud support\n* [`c3b2429c`](https://github.com/talos-systems/talos/commit/c3b2429ce91edc4f8f9e720a4b144bc941046fc3) fix: suppress spurious Kubernetes API server cert updates\n* [`ff90b575`](https://github.com/talos-systems/talos/commit/ff90b5751e17a60fc6ca4274f35da7ddcca44fea) feat: implement KubeSpan peer generation controller\n* [`14c69df5`](https://github.com/talos-systems/talos/commit/14c69df5063e71765b9316ae37657fda2388c60e) fix: correctly parse multiple pod/service CIDRs\n* [`69897dbb`](https://github.com/talos-systems/talos/commit/69897dbba402812403c0c15d6cb8d2a771ea5a88) feat: drop some capabilities to be never available\n* [`51e9836b`](https://github.com/talos-systems/talos/commit/51e9836b01926d1619d662e6e08df29210ff94e5) docs: promote 0.12 docs to be the latest\n* [`812d59c7`](https://github.com/talos-systems/talos/commit/812d59c70085b54136e3b56127b0efea7ddb60af) feat: add hetzner.com cloud support\n* [`d53e9e89`](https://github.com/talos-systems/talos/commit/d53e9e89633258d85c2232b85855535ebb42c417) chore: use named constants\n* [`2dfe7f1f`](https://github.com/talos-systems/talos/commit/2dfe7f1fc654c8bec83b632a98dbaa8d1b90a521) chore: bump tools to the latest version\n* [`82b130e7`](https://github.com/talos-systems/talos/commit/82b130e789aa4376e1f0e2d086233e630b410f74) docs: document required options for extraMounts\n* [`af662210`](https://github.com/talos-systems/talos/commit/af6622109faecdf03aed43b047035904110c7580) feat: implement Kubernetes cluster discovery registry\n* [`2c66e1b3`](https://github.com/talos-systems/talos/commit/2c66e1b3c5d4c34c5d4cdc155c32f2808a5f1c69) feat: provide building of local `Affiliate` structure (for the node)\n* [`d69bd2af`](https://github.com/talos-systems/talos/commit/d69bd2af3e3d3bf12b6d74078e9eedf3dc8752fc) chore: enable GPG identity check for Talos\n* [`8dbd851f`](https://github.com/talos-systems/talos/commit/8dbd851fde3febb5999df694a079121b43519aa9) chore: update tools/pkgs/extras to the new version\n* [`0b347570`](https://github.com/talos-systems/talos/commit/0b347570a7aca0a133d6b6e6cc8d3e0355630480) feat: use dynamic NodeAddresses/HostnameStatus in Kubernetes certs\n* [`bd5b9c96`](https://github.com/talos-systems/talos/commit/bd5b9c96e2563249a5633433703493b292b83ee9) fix: correctly define example for `extraMounts`\n* [`01cca099`](https://github.com/talos-systems/talos/commit/01cca099f40ec75d1e047a84c89692eb254e8adf) docs: update docs for Talos 0.12 release\n* [`668627d5`](https://github.com/talos-systems/talos/commit/668627d5b8ec79ec955eb1254732b1cc031d3aec) feat: add subnet filter for etcd address\n* [`3c3c281b`](https://github.com/talos-systems/talos/commit/3c3c281bff8481f680feca9cf01af413a38e6973) chore: bump dependencies via dependabot\n* [`f8bebba2`](https://github.com/talos-systems/talos/commit/f8bebba2de3999b7a36fecb2d6b90e583372c98f) fix: ignore error on duplicate for `MountStatus`\n* [`6956edd0`](https://github.com/talos-systems/talos/commit/6956edd0bfae6c6c5d6eba00a22bc3a4cb7f54ea) feat: add node address filters, filter out k8s addresses for Talos API\n* [`caee24bf`](https://github.com/talos-systems/talos/commit/caee24bf61136daecb095991a6e439f7fbf40da2) feat: implement KubeSpan identity controller\n* [`da0f6e7e`](https://github.com/talos-systems/talos/commit/da0f6e7e1d295dce0c44c1854363528a6ffedde1) fix: allow updating diskSelector option\n* [`761ccaf3`](https://github.com/talos-systems/talos/commit/761ccaf32348d8664eb0d5d1a51f6abb19ca52a6) feat: provide machine configuration for KubeSpan and cluster discovery\n* [`a81e30cb`](https://github.com/talos-systems/talos/commit/a81e30cb46326fbdd433f37dc37549b588a2bc7a) docs: add bootstrap command to VMware docs\n* [`97da354c`](https://github.com/talos-systems/talos/commit/97da354cc0e4a965e14b8939c426150d5c12f228) fix: do not panic on invalid machine configs\n* [`c4048e26`](https://github.com/talos-systems/talos/commit/c4048e263d22682142f12fc4af6ac58c679273f0) fix: don't extract nil IPs in the GCP platform\n* [`ba169c6f`](https://github.com/talos-systems/talos/commit/ba169c6f91948cf057251236fa7a727a05253639) feat: provide talosctl.exe for Windows\n* [`6312f473`](https://github.com/talos-systems/talos/commit/6312f473e63df50287e6801c079242e2311a23e6) fix: properly handle omitempty fields in the validator\n* [`7f22879a`](https://github.com/talos-systems/talos/commit/7f22879af0882af4cdebe9c84afb96ae68eb9f20) feat: provide random node identity\n* [`032e7c6b`](https://github.com/talos-systems/talos/commit/032e7c6b863b5ca02cfa16df79c88950544dbffb) chore: import yaml.v3 consistently\n* [`80b5f0e7`](https://github.com/talos-systems/talos/commit/80b5f0e7f78f09a11ed249f9f1dc7b05ea275ab0) fix: validate IP address returned as HTTP response in platform code\n* [`c9af8f7f`](https://github.com/talos-systems/talos/commit/c9af8f7ff17facc18f10675879ed04982a000f6f) docs: fork docs for 0.13\n* [`85cda1b9`](https://github.com/talos-systems/talos/commit/85cda1b956b042ba20696637248999d46f63ccc9) feat: provide MountStatus resource for system partition mounts\n* [`950f122c`](https://github.com/talos-systems/talos/commit/950f122c95e225858e77083f2490481ed8d21aef) chore: update versions in upgrade tests\n* [`83fdb772`](https://github.com/talos-systems/talos/commit/83fdb7721f45aa075898caf05a4b6856d3c5f330) feat: provide first NIC hardware addr as a resource\n* [`5f5ac12f`](https://github.com/talos-systems/talos/commit/5f5ac12f1dc8aeb3a8598e57d965471e93fe3724) fix: properly case the VMware name\n* [`0a6048f4`](https://github.com/talos-systems/talos/commit/0a6048f469da02efad7e84eb237e6fdeb85b7e33) fix: don't allow bootstrap if etcd data directory is not empty\n* [`e24b93b4`](https://github.com/talos-systems/talos/commit/e24b93b4e120448f37109599f3e9eb15954b147a) fix: cgroup delegate\n* [`751f64f9`](https://github.com/talos-systems/talos/commit/751f64f9bc10e9ad8508ade9e3a6a14aaaa54d57) docs: add release notes for 0.12, support matrix\n* [`57a77696`](https://github.com/talos-systems/talos/commit/57a77696ef2b255a59ee4ed213a1a3971a5e2943) feat: update Kubernetes to 1.22.1\n* [`244b08cc`](https://github.com/talos-systems/talos/commit/244b08cc198a8ba676bb9acadcbdd23a161b0876) chore: bump dependencies\n* [`576ba195`](https://github.com/talos-systems/talos/commit/576ba195784abf275256c861d5f811ab1f7b1102) fix: do not set KSPP kernel params in container mode\n* [`b8c92ede`](https://github.com/talos-systems/talos/commit/b8c92ede52ed515dba68abf4fb1cc6494d510827) fix: don't support cgroups nesting in process runner\n* [`9bb0b797`](https://github.com/talos-systems/talos/commit/9bb0b79709a502ab49ea9bacd7e54617554d4cc3) test: adapt tests to the cgroupsv2\n* [`1abc12be`](https://github.com/talos-systems/talos/commit/1abc12be13208ad1da03492a1b88d2c1ec0d5d33) fix: extramount should have `yaml:\",inline\"` tag\n* [`2b614e43`](https://github.com/talos-systems/talos/commit/2b614e430e478cc111db018996ab2c8f763e4f92) feat: check if cluster has deprecated resources versions\n* [`0b86edab`](https://github.com/talos-systems/talos/commit/0b86edab80cf4dd01f330d7721b130f5017d84a5) fix: don't panic if the machine config doesn't have network (EM)\n* [`8bef41e4`](https://github.com/talos-systems/talos/commit/8bef41e4bacc4190976657ae5021afecd2d6e001) fix: make sure file mode is same (reproducibility issue)\n* [`fcfca55a`](https://github.com/talos-systems/talos/commit/fcfca55a059e92fcda198baa321c4c63bda1f0a4) chore: do not check that go mod tidy gives empty output\n* [`5ce92ca5`](https://github.com/talos-systems/talos/commit/5ce92ca5163616fcd7abe16c4efc3a100953b246) docs: ensure azure VMs are 0 indexed\n</p>\n</details>\n\n### Changes since v0.13.0-alpha.2\n<details><summary>6 commits</summary>\n<p>\n\n* [`4044372e`](https://github.com/talos-systems/talos/commit/4044372e12ff5308ba9cb9178a7e6b3b32955aab) feat: harvest discovered endpoints and push them via discovery svc\n* [`9a51aa83`](https://github.com/talos-systems/talos/commit/9a51aa83581b25bdb0604904027a4cedf21b8123) feat: add an option to skip downed peers in KubeSpan\n* [`cbbd7c68`](https://github.com/talos-systems/talos/commit/cbbd7c68219808a4f4b0d805203326019ce14ec9) feat: publish node's ExternalIPs as node addresses\n* [`0f60ef6d`](https://github.com/talos-systems/talos/commit/0f60ef6d38f9f5978a19e0ca4c6729af03a11f0e) fix: reset inputs back to initial state in secrets.APIController\n* [`64cb873e`](https://github.com/talos-systems/talos/commit/64cb873ec4421d43b291acb8afe75f65728d5732) feat: override static pods default args by extra Args\n* [`ecdd7757`](https://github.com/talos-systems/talos/commit/ecdd7757fb5906d6fa904581efff74a16b22ae4b) test: workaround race in the tests with zaptest package\n</p>\n</details>\n\n### Changes from talos-systems/discovery-service\n<details><summary>17 commits</summary>\n<p>\n\n* [`b2e2079`](https://github.com/talos-systems/discovery-service/commit/b2e2079088a5b08d0466b36e0f56927fe4524d78) fix: properly encrypt IPv6 endpoints\n* [`e9d5dfa`](https://github.com/talos-systems/discovery-service/commit/e9d5dfa15e92fc1bdee620b2687eecd2ff929ac3) fix: enable connections to endpoints with public certs\n* [`509e9b2`](https://github.com/talos-systems/discovery-service/commit/509e9b2ced989631224afd3bfd5e8bdcbcf13137) feat: implement client wrapper around discovery service API\n* [`6195466`](https://github.com/talos-systems/discovery-service/commit/619546696afe99c1b58b46ca819bb32e74560f5b) feat: enable vtprotobuf, watch batching, more limits\n* [`7174ec1`](https://github.com/talos-systems/discovery-service/commit/7174ec10426ff17172aaa195423e2588b23aa868) feat: implement new discovery service\n* [`1a43970`](https://github.com/talos-systems/discovery-service/commit/1a4397082659a2b6bca6fd53a5080e109d978627) feat: add node and cluster validation\n* [`6454cfc`](https://github.com/talos-systems/discovery-service/commit/6454cfcb726bba64823f25d962bc04007d057a8b) refactor: kresify, fix linter and rename to Kubespan manager\n* [`d782452`](https://github.com/talos-systems/discovery-service/commit/d782452e86bf94c1194f806384fc339835a96d2d) add redis database backend\n* [`924fed4`](https://github.com/talos-systems/discovery-service/commit/924fed4ecc939887c55a4a8a5f5dfe737ca29c78) refactor to flexible addresses\n* [`cd02b5a`](https://github.com/talos-systems/discovery-service/commit/cd02b5a36783454f7650df5709984f01ccc8bd6e) revert to string IDs\n* [`576288f`](https://github.com/talos-systems/discovery-service/commit/576288fc7559f9eac1966627b6c1e2c731e0c322) add self-reported IPs\n* [`6ad15ca`](https://github.com/talos-systems/discovery-service/commit/6ad15ca825bdf4636855f2b77535945d07462a17) strong typing and known endpoint API\n* [`3437ff2`](https://github.com/talos-systems/discovery-service/commit/3437ff28fb9ab6efb96cc79da1c75bd81bfb50cc) fixes from testing\n* [`d3fd1f3`](https://github.com/talos-systems/discovery-service/commit/d3fd1f324d7af60f2ddf425c9c2cf9b9743e6d62) add Name to Node\n* [`eb0e8ba`](https://github.com/talos-systems/discovery-service/commit/eb0e8baadacd702044ca419f933dd409ae58977e) add simple client pkg\n* [`5e0c1df`](https://github.com/talos-systems/discovery-service/commit/5e0c1df0f1823cce1b92ccffb1e18fb1e540117d) add cluster hash grouping\n* [`f982696`](https://github.com/talos-systems/discovery-service/commit/f982696ec1b45f8d7e6d2dfa1d780b3b0d515dbb) initial commit\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`52b27da`](https://github.com/talos-systems/extras/commit/52b27dad5aeeb5d14225a99e4b5902614c993022) chore: update pkgs and tools to 0.8.0-alpha.0\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>6 commits</summary>\n<p>\n\n* [`70d2865`](https://github.com/talos-systems/go-blockdevice/commit/70d28650b398a14469cbb5356417355b0ba62956) fix: try to find cdrom disks\n* [`667bf53`](https://github.com/talos-systems/go-blockdevice/commit/667bf539b99ac34b629a0103ef7a7278a5a5f35d) fix: revert gpt partition not found\n* [`d7d4cdd`](https://github.com/talos-systems/go-blockdevice/commit/d7d4cdd7ac56c82caab19246b5decd59f12195eb) fix: gpt partition not found\n* [`33afba3`](https://github.com/talos-systems/go-blockdevice/commit/33afba347c0dce38a436c46a0aac26d2f99427c1) fix: also open in readonly mode when running `All` lookup method\n* [`e367f9d`](https://github.com/talos-systems/go-blockdevice/commit/e367f9dc7fa935f11672de0fdc8a89429285a07a) feat: make probe always open blockdevices in readonly mode\n* [`d981156`](https://github.com/talos-systems/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>7 commits</summary>\n<p>\n\n* [`28cda67`](https://github.com/talos-systems/pkgs/commit/28cda67f9b518cb4d4a299bac62be1c3ed3cddda) feat: update Linux kernel to 5.10.69\n* [`db90f93`](https://github.com/talos-systems/pkgs/commit/db90f93c0b462dcaefa081c18f8adebae5d5744a) chore: update tools\n* [`ca38c59`](https://github.com/talos-systems/pkgs/commit/ca38c599b71334d5a108021c7e7ccec12701ff18) feat: enable KEXEC_FILE_LOAD in the kernel\n* [`982bc18`](https://github.com/talos-systems/pkgs/commit/982bc18a4ecf5d4e15a73c350abb97f02adb8871) chore: update tools\n* [`a243ab8`](https://github.com/talos-systems/pkgs/commit/a243ab8a9345b8bc39cc65254015b6eb07605f61) feat: add /usr/src to FHS\n* [`428abdb`](https://github.com/talos-systems/pkgs/commit/428abdbfd303fce69cf583f5a8a4f5ed43253807) chore: support builds with HTTP_PROXY\n* [`13151c5`](https://github.com/talos-systems/pkgs/commit/13151c59b5b29541ed5828aa9c75a061ec920ff1) chore: update bldr version, update tools\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`2790b55`](https://github.com/talos-systems/tools/commit/2790b5586e810c7dfc0a197ef9d1e6d77a646e3b) feat: update Go to 1.17.1\n* [`5b9d214`](https://github.com/talos-systems/tools/commit/5b9d214c38515a55232ce36591036748fd8c49cc) fix: restore static library for ncurses\n* [`01104e5`](https://github.com/talos-systems/tools/commit/01104e562efdbff34fb2d597d4cf27d04ba44ea6) chore: reproducible builds\n* [`53fe146`](https://github.com/talos-systems/tools/commit/53fe146ca8ba55c959fee04302a5ce215a927f1d) chore: update bldr with new version\n* [`bf4540d`](https://github.com/talos-systems/tools/commit/bf4540d0ed0728cd7751e0c3ab3bb4b8927e334c) chore: add patch dependency\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/containerd/go-cni**                   v1.0.2 -> v1.1.0\n* **github.com/containernetworking/cni**             v0.8.1 -> v1.0.1\n* **github.com/containernetworking/plugins**         v0.9.1 -> v1.0.1\n* **github.com/cosi-project/runtime**                25f235cd0682 -> 5cb7f5002d77\n* **github.com/fatih/color**                         v1.12.0 -> v1.13.0\n* **github.com/fsnotify/fsnotify**                   v1.4.9 -> v1.5.1\n* **github.com/gdamore/tcell/v2**                    v2.4.0 -> f057f0a857a1\n* **github.com/google/nftables**                     16a134723a96 **_new_**\n* **github.com/hashicorp/go-getter**                 v1.5.7 -> v1.5.8\n* **github.com/hetznercloud/hcloud-go**              v1.32.0 **_new_**\n* **github.com/insomniacslk/dhcp**                   1cac67f12b1e -> b95caade3eac\n* **github.com/jsimonetti/rtnetlink**                9c52e516c709 -> 435639c8e6a8\n* **github.com/jxskiss/base62**                      4f11678b909b **_new_**\n* **github.com/mattn/go-isatty**                     v0.0.13 -> v0.0.14\n* **github.com/mdlayher/netx**                       669a06fde734 **_new_**\n* **github.com/packethost/packngo**                  v0.19.0 -> v0.19.1\n* **github.com/prometheus/procfs**                   v0.7.2 -> v0.7.3\n* **github.com/rivo/tview**                          29d673af0ce2 -> ee97a7ab3975\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.7 **_new_**\n* **github.com/talos-systems/discovery-service**     b2e2079088a5 **_new_**\n* **github.com/talos-systems/extras**                v0.5.0 -> v0.6.0-alpha.0\n* **github.com/talos-systems/go-blockdevice**        v0.2.3 -> 70d28650b398\n* **github.com/talos-systems/pkgs**                  v0.7.0 -> v0.8.0-alpha.0-4-g28cda67\n* **github.com/talos-systems/tools**                 v0.7.0-1-ga33ccc1 -> v0.8.0-alpha.0-3-g2790b55\n* **github.com/vishvananda/netlink**                 f5de75959ad5 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.1 -> v0.53.2\n* **github.com/vmware/govmomi**                      v0.26.0 -> v0.26.1\n* **github.com/vultr/metadata**                      v1.0.3 **_new_**\n* **go.uber.org/zap**                                v1.19.0 -> v1.19.1\n* **golang.org/x/net**                               853a461950ff -> 3ad01bbaa167\n* **golang.org/x/sys**                               0f9fa26af87c -> 39ccf1dd6fa6\n* **golang.org/x/term**                              6886f2dfbf5b -> 140adaaadfaf\n* **golang.zx2c4.com/wireguard/wgctrl**              92e472f520a5 -> 0a2f4901cba6\n* **google.golang.org/grpc**                         v1.40.0 -> v1.41.0\n* **inet.af/netaddr**                                ce7a8ad02cc1 -> 85fa6c94624e\n* **k8s.io/api**                                     v0.22.1 -> v0.22.2\n* **k8s.io/apimachinery**                            v0.22.1 -> v0.22.2\n* **k8s.io/client-go**                               v0.22.1 -> v0.22.2\n* **k8s.io/kubectl**                                 v0.22.1 -> v0.22.2\n* **k8s.io/kubelet**                                 v0.22.1 -> v0.22.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.59 **_new_**\n\nPrevious release can be found at [v0.12.0](https://github.com/talos-systems/talos/releases/tag/v0.12.0)\n\n## [Talos 0.13.0-alpha.2](https://github.com/talos-systems/talos/releases/tag/v0.13.0-alpha.2) (2021-09-28)\n\nWelcome to the v0.13.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Hetzner, Scaleway, Upcloud and Vultr\n\nTalos now natively supports three new cloud platforms:\n\n* [Hetzner](https://www.hetzner.com/), including VIP support\n* [Scaleway](https://www.scaleway.com/en/)\n* [Upcloud](https://upcloud.com/)\n* [Vultr](https://www.vultr.com/)\n\nAlso generic `cloud-init` `nocloud` platform is supported in both networking and storage-based modes.\n\n\n### etcd Advertised Address\n\nThe address advertised by etcd can now be controlled with new machine configuration option `machine.etcd.subnet`.\n\n\n### Reboots via kexec\n\nTalos now reboots by default via kexec syscall which means BIOS POST process is skipped.\nOn bare-metal hardware BIOS POST process might take 10-15 minutes, so Talos reboots 10-15 minutes faster on bare-metal.\n\nKexec support can be disabled with the following change to the machine configuration:\n\n```\nmachine:\n  sysctls:\n    kernel.kexec_load_disabled: \"1\"\n```\n\n\n### Cluster Discovery and KubeSpan\n\nThis release of Talos provides initial support for cluster membership discovery and [KubeSpan](https://www.talos-systems.com/kubespan/).\n\nThese new features are not enabled by default, to enable them please make following changes to the machine configuration:\n\n```yaml\nmachine:\n  network:\n    kubespan:\n      enabled: true\ncluster:\n  discovery:\n    enabled: true\n```\n\n\n\n### Windows Support\n\nCLI tool talosctl is now built for Windows and published as part of the release.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Artem Chernyshev\n* Seán C McCord\n* Serge Logvinov\n* Alexey Palazhchenko\n* Andrew Rynhard\n* Olli Janatuinen\n* Andrey Smirnov\n* Lennard Klein\n* Rui Lopes\n* Spencer Smith\n\n### Changes\n<details><summary>93 commits</summary>\n<p>\n\n* [`30ae7142`](https://github.com/talos-systems/talos/commit/30ae714243379aaa3fb1e93023c2249ff3c3b4e3) feat: implement integration with Discovery Service\n* [`353d632a`](https://github.com/talos-systems/talos/commit/353d632ae5d944a8662f0746ff8e757a67ffca53) feat: add nocloud platform support\n* [`628fbf9b`](https://github.com/talos-systems/talos/commit/628fbf9b48d98df1063285b14958c94d246ce102) chore: update Linux to 5.10.69\n* [`62acd625`](https://github.com/talos-systems/talos/commit/62acd6251637250dbea7d408d8cd4d5eb1f18713) fix: check trustd API CA on worker nodes\n* [`ba27bc36`](https://github.com/talos-systems/talos/commit/ba27bc366fb3166b22f1bda909b9ede486ad8c7d) feat: implement Hetzner Cloud support for virtual (shared) IP\n* [`95f440ea`](https://github.com/talos-systems/talos/commit/95f440eaa06d2a558fc828c11b451b6aed8d5855) test: add fuzz test for configloader\n* [`d2cf021d`](https://github.com/talos-systems/talos/commit/d2cf021d8ffb6d6188b2d50f1f7b9c24df0aac84) chore: remove deprecated \"join\" term\n* [`0e18e280`](https://github.com/talos-systems/talos/commit/0e18e2800fc038a86ed2fd9b042278ae29070bb5) chore: bump dependencies\n* [`b450b7ce`](https://github.com/talos-systems/talos/commit/b450b7cef0d84a9ad975d8b50b93854bb0645173) chore: deprecate Interfaces and Routes APIs\n* [`cddcb962`](https://github.com/talos-systems/talos/commit/cddcb9622bce7ae3626b8b9dce8c622a0e30ba66) fix: find devices without partition table\n* [`b1b6d613`](https://github.com/talos-systems/talos/commit/b1b6d61365c900c4ebfc377b86067ddbe4fe8353) fix: check for existence of dhcp6 FQDN first\n* [`519999b8`](https://github.com/talos-systems/talos/commit/519999b8462ff4931ed12323417b9a9c8c20b369) fix: use readonly mode when probing devices with `All` lookup\n* [`2b520420`](https://github.com/talos-systems/talos/commit/2b5204200a4bd22aa78245b201c471136016ce3a) feat: enable resource API in the maintenance mode\n* [`452893c2`](https://github.com/talos-systems/talos/commit/452893c260b920c601b0fc22ff018dc2d4341fca) fix: make probe open blockdevice in readonly mode\n* [`96bccdd3`](https://github.com/talos-systems/talos/commit/96bccdd3b625f0edefd685cadf5f2cd46e3111f5) test: update CABPT provider to 0.3 release\n* [`d9eb18bf`](https://github.com/talos-systems/talos/commit/d9eb18bfddf69a61712d930b53aec489a806394a) fix: containerd log symlink\n* [`efa7f48e`](https://github.com/talos-systems/talos/commit/efa7f48e08382249609e0ecd3241c01a2e46df73) docs: quicklinks on landing page\n* [`1cb9f282`](https://github.com/talos-systems/talos/commit/1cb9f282b541505f2d61ae0a57655cba9ae62843) fix: don't marshal clock with SecretsBundle\n* [`b27c75b3`](https://github.com/talos-systems/talos/commit/b27c75b30f689dafa7d4effd0c2eaf8f0f3f8caf) release(v0.13.0-alpha.1): prepare release\n* [`9d803d75`](https://github.com/talos-systems/talos/commit/9d803d75bfbe788fa5c2ef2ae0639de31e172c7b) chore: bump dependencies and drop firecracker support\n* [`50a24104`](https://github.com/talos-systems/talos/commit/50a24104820e26bb99e66ab68be2bd9a6c17b0be) feat: add operating system version field to discovery\n* [`085c61b2`](https://github.com/talos-systems/talos/commit/085c61b2ec432c586daa77464910e967a223ebe0) chore: add a special condition to check for kubeconfig readiness\n* [`21cdd854`](https://github.com/talos-systems/talos/commit/21cdd854036498fbeb9f6e4d058a0edd55ed4856) fix: add node address to the list of allowed IPs (kubespan)\n* [`fdd80a12`](https://github.com/talos-systems/talos/commit/fdd80a1234dc993cc01daa7764ba5a9db2fdc275) feat: add an option to continue booting on NTP timeout\n* [`ef368498`](https://github.com/talos-systems/talos/commit/ef36849899b18bbb35c6116fdf35aa580a50a5e5) feat: add routes, routing rules and nftables rules for KubeSpan\n* [`ed12379f`](https://github.com/talos-systems/talos/commit/ed12379f2f49fcbca84080f1066cf52dc202bd2d) fix: patch multi nodes support\n* [`d943bb0e`](https://github.com/talos-systems/talos/commit/d943bb0e280e90f3592d9f7b67813b7a15818c84) feat: update Kubernetes to 1.22.2\n* [`d0585fb6`](https://github.com/talos-systems/talos/commit/d0585fb6b303dfdd7fc80a76024915df31c72389) feat: reboot via kexec\n* [`3de505c8`](https://github.com/talos-systems/talos/commit/3de505c894274bfd5248b6c597f6e3a53f873ba1) fix: skip bad cloud-config in OpenStack platform\n* [`a394d1e2`](https://github.com/talos-systems/talos/commit/a394d1e20ba82de7d05e4d3f91823a98362ac9ee) fix: tear down control plane static pods when etcd is stopped\n* [`1c05089b`](https://github.com/talos-systems/talos/commit/1c05089bb22c7c1050e95cf8d7bea8b763a0e86f) feat: implement KubeSpan manager for Wireguard peer state\n* [`ec7f44ef`](https://github.com/talos-systems/talos/commit/ec7f44efe4f89e7ed207cbd5fe3748953ccfdf28) fix: completely prevent editing resources other than mc\n* [`19a8ae97`](https://github.com/talos-systems/talos/commit/19a8ae97c69949f7c2421154b2ae4e52a905ff63) feat: add vultr.com cloud support\n* [`0ff4c7cd`](https://github.com/talos-systems/talos/commit/0ff4c7cdb2b9505823f4c4504ec9bf4d7fddf5c5) fix: write KubernetesCACert chmodded 0400 instead of 0500\n* [`a1c9d649`](https://github.com/talos-systems/talos/commit/a1c9d64907cce75bcb566f3ee394734e29b3932d) fix: update the way results are retrieved for certified conformance\n* [`a0594540`](https://github.com/talos-systems/talos/commit/a0594540451a7636f8cd4bbe835913d31f66d0de) chore: build using Go 1.17\n* [`7c5045bd`](https://github.com/talos-systems/talos/commit/7c5045bd929fcf5028cae3840970e692ef3bc7c9) release(v0.13.0-alpha.0): prepare release\n* [`ee2dce6c`](https://github.com/talos-systems/talos/commit/ee2dce6c1a0e8838e587a9136afd1b7381000432) chore: bump dependencies\n* [`ef022959`](https://github.com/talos-systems/talos/commit/ef022959280f156d6311836ef9cc2d01e5e3ae7d) fix: print etcd member ID in hex\n* [`5ca1fb82`](https://github.com/talos-systems/talos/commit/5ca1fb822125483be290e79d8828bba246fda51c) fix: multiple fixes for KubeSpan and Wireguard implementation\n* [`b1bd6425`](https://github.com/talos-systems/talos/commit/b1bd64250820df3fcb5214368ce9c8cf4634970a) fix: build platform images\n* [`3b5f4038`](https://github.com/talos-systems/talos/commit/3b5f4038de2f855b3b634e4abb1c564da624e2fc) feat: add scaleway.com cloud support\n* [`f156ab18`](https://github.com/talos-systems/talos/commit/f156ab1847f2ad1ca2a2548b299a713ee5fe0fcd) feat: add upcloud.com cloud support\n* [`c3b2429c`](https://github.com/talos-systems/talos/commit/c3b2429ce91edc4f8f9e720a4b144bc941046fc3) fix: suppress spurious Kubernetes API server cert updates\n* [`ff90b575`](https://github.com/talos-systems/talos/commit/ff90b5751e17a60fc6ca4274f35da7ddcca44fea) feat: implement KubeSpan peer generation controller\n* [`14c69df5`](https://github.com/talos-systems/talos/commit/14c69df5063e71765b9316ae37657fda2388c60e) fix: correctly parse multiple pod/service CIDRs\n* [`69897dbb`](https://github.com/talos-systems/talos/commit/69897dbba402812403c0c15d6cb8d2a771ea5a88) feat: drop some capabilities to be never available\n* [`51e9836b`](https://github.com/talos-systems/talos/commit/51e9836b01926d1619d662e6e08df29210ff94e5) docs: promote 0.12 docs to be the latest\n* [`812d59c7`](https://github.com/talos-systems/talos/commit/812d59c70085b54136e3b56127b0efea7ddb60af) feat: add hetzner.com cloud support\n* [`d53e9e89`](https://github.com/talos-systems/talos/commit/d53e9e89633258d85c2232b85855535ebb42c417) chore: use named constants\n* [`2dfe7f1f`](https://github.com/talos-systems/talos/commit/2dfe7f1fc654c8bec83b632a98dbaa8d1b90a521) chore: bump tools to the latest version\n* [`82b130e7`](https://github.com/talos-systems/talos/commit/82b130e789aa4376e1f0e2d086233e630b410f74) docs: document required options for extraMounts\n* [`af662210`](https://github.com/talos-systems/talos/commit/af6622109faecdf03aed43b047035904110c7580) feat: implement Kubernetes cluster discovery registry\n* [`2c66e1b3`](https://github.com/talos-systems/talos/commit/2c66e1b3c5d4c34c5d4cdc155c32f2808a5f1c69) feat: provide building of local `Affiliate` structure (for the node)\n* [`d69bd2af`](https://github.com/talos-systems/talos/commit/d69bd2af3e3d3bf12b6d74078e9eedf3dc8752fc) chore: enable GPG identity check for Talos\n* [`8dbd851f`](https://github.com/talos-systems/talos/commit/8dbd851fde3febb5999df694a079121b43519aa9) chore: update tools/pkgs/extras to the new version\n* [`0b347570`](https://github.com/talos-systems/talos/commit/0b347570a7aca0a133d6b6e6cc8d3e0355630480) feat: use dynamic NodeAddresses/HostnameStatus in Kubernetes certs\n* [`bd5b9c96`](https://github.com/talos-systems/talos/commit/bd5b9c96e2563249a5633433703493b292b83ee9) fix: correctly define example for `extraMounts`\n* [`01cca099`](https://github.com/talos-systems/talos/commit/01cca099f40ec75d1e047a84c89692eb254e8adf) docs: update docs for Talos 0.12 release\n* [`668627d5`](https://github.com/talos-systems/talos/commit/668627d5b8ec79ec955eb1254732b1cc031d3aec) feat: add subnet filter for etcd address\n* [`3c3c281b`](https://github.com/talos-systems/talos/commit/3c3c281bff8481f680feca9cf01af413a38e6973) chore: bump dependencies via dependabot\n* [`f8bebba2`](https://github.com/talos-systems/talos/commit/f8bebba2de3999b7a36fecb2d6b90e583372c98f) fix: ignore error on duplicate for `MountStatus`\n* [`6956edd0`](https://github.com/talos-systems/talos/commit/6956edd0bfae6c6c5d6eba00a22bc3a4cb7f54ea) feat: add node address filters, filter out k8s addresses for Talos API\n* [`caee24bf`](https://github.com/talos-systems/talos/commit/caee24bf61136daecb095991a6e439f7fbf40da2) feat: implement KubeSpan identity controller\n* [`da0f6e7e`](https://github.com/talos-systems/talos/commit/da0f6e7e1d295dce0c44c1854363528a6ffedde1) fix: allow updating diskSelector option\n* [`761ccaf3`](https://github.com/talos-systems/talos/commit/761ccaf32348d8664eb0d5d1a51f6abb19ca52a6) feat: provide machine configuration for KubeSpan and cluster discovery\n* [`a81e30cb`](https://github.com/talos-systems/talos/commit/a81e30cb46326fbdd433f37dc37549b588a2bc7a) docs: add bootstrap command to VMware docs\n* [`97da354c`](https://github.com/talos-systems/talos/commit/97da354cc0e4a965e14b8939c426150d5c12f228) fix: do not panic on invalid machine configs\n* [`c4048e26`](https://github.com/talos-systems/talos/commit/c4048e263d22682142f12fc4af6ac58c679273f0) fix: don't extract nil IPs in the GCP platform\n* [`ba169c6f`](https://github.com/talos-systems/talos/commit/ba169c6f91948cf057251236fa7a727a05253639) feat: provide talosctl.exe for Windows\n* [`6312f473`](https://github.com/talos-systems/talos/commit/6312f473e63df50287e6801c079242e2311a23e6) fix: properly handle omitempty fields in the validator\n* [`7f22879a`](https://github.com/talos-systems/talos/commit/7f22879af0882af4cdebe9c84afb96ae68eb9f20) feat: provide random node identity\n* [`032e7c6b`](https://github.com/talos-systems/talos/commit/032e7c6b863b5ca02cfa16df79c88950544dbffb) chore: import yaml.v3 consistently\n* [`80b5f0e7`](https://github.com/talos-systems/talos/commit/80b5f0e7f78f09a11ed249f9f1dc7b05ea275ab0) fix: validate IP address returned as HTTP response in platform code\n* [`c9af8f7f`](https://github.com/talos-systems/talos/commit/c9af8f7ff17facc18f10675879ed04982a000f6f) docs: fork docs for 0.13\n* [`85cda1b9`](https://github.com/talos-systems/talos/commit/85cda1b956b042ba20696637248999d46f63ccc9) feat: provide MountStatus resource for system partition mounts\n* [`950f122c`](https://github.com/talos-systems/talos/commit/950f122c95e225858e77083f2490481ed8d21aef) chore: update versions in upgrade tests\n* [`83fdb772`](https://github.com/talos-systems/talos/commit/83fdb7721f45aa075898caf05a4b6856d3c5f330) feat: provide first NIC hardware addr as a resource\n* [`5f5ac12f`](https://github.com/talos-systems/talos/commit/5f5ac12f1dc8aeb3a8598e57d965471e93fe3724) fix: properly case the VMware name\n* [`0a6048f4`](https://github.com/talos-systems/talos/commit/0a6048f469da02efad7e84eb237e6fdeb85b7e33) fix: don't allow bootstrap if etcd data directory is not empty\n* [`e24b93b4`](https://github.com/talos-systems/talos/commit/e24b93b4e120448f37109599f3e9eb15954b147a) fix: cgroup delegate\n* [`751f64f9`](https://github.com/talos-systems/talos/commit/751f64f9bc10e9ad8508ade9e3a6a14aaaa54d57) docs: add release notes for 0.12, support matrix\n* [`57a77696`](https://github.com/talos-systems/talos/commit/57a77696ef2b255a59ee4ed213a1a3971a5e2943) feat: update Kubernetes to 1.22.1\n* [`244b08cc`](https://github.com/talos-systems/talos/commit/244b08cc198a8ba676bb9acadcbdd23a161b0876) chore: bump dependencies\n* [`576ba195`](https://github.com/talos-systems/talos/commit/576ba195784abf275256c861d5f811ab1f7b1102) fix: do not set KSPP kernel params in container mode\n* [`b8c92ede`](https://github.com/talos-systems/talos/commit/b8c92ede52ed515dba68abf4fb1cc6494d510827) fix: don't support cgroups nesting in process runner\n* [`9bb0b797`](https://github.com/talos-systems/talos/commit/9bb0b79709a502ab49ea9bacd7e54617554d4cc3) test: adapt tests to the cgroupsv2\n* [`1abc12be`](https://github.com/talos-systems/talos/commit/1abc12be13208ad1da03492a1b88d2c1ec0d5d33) fix: extramount should have `yaml:\",inline\"` tag\n* [`2b614e43`](https://github.com/talos-systems/talos/commit/2b614e430e478cc111db018996ab2c8f763e4f92) feat: check if cluster has deprecated resources versions\n* [`0b86edab`](https://github.com/talos-systems/talos/commit/0b86edab80cf4dd01f330d7721b130f5017d84a5) fix: don't panic if the machine config doesn't have network (EM)\n* [`8bef41e4`](https://github.com/talos-systems/talos/commit/8bef41e4bacc4190976657ae5021afecd2d6e001) fix: make sure file mode is same (reproducibility issue)\n* [`fcfca55a`](https://github.com/talos-systems/talos/commit/fcfca55a059e92fcda198baa321c4c63bda1f0a4) chore: do not check that go mod tidy gives empty output\n* [`5ce92ca5`](https://github.com/talos-systems/talos/commit/5ce92ca5163616fcd7abe16c4efc3a100953b246) docs: ensure azure VMs are 0 indexed\n</p>\n</details>\n\n### Changes since v0.13.0-alpha.1\n<details><summary>18 commits</summary>\n<p>\n\n* [`30ae7142`](https://github.com/talos-systems/talos/commit/30ae714243379aaa3fb1e93023c2249ff3c3b4e3) feat: implement integration with Discovery Service\n* [`353d632a`](https://github.com/talos-systems/talos/commit/353d632ae5d944a8662f0746ff8e757a67ffca53) feat: add nocloud platform support\n* [`628fbf9b`](https://github.com/talos-systems/talos/commit/628fbf9b48d98df1063285b14958c94d246ce102) chore: update Linux to 5.10.69\n* [`62acd625`](https://github.com/talos-systems/talos/commit/62acd6251637250dbea7d408d8cd4d5eb1f18713) fix: check trustd API CA on worker nodes\n* [`ba27bc36`](https://github.com/talos-systems/talos/commit/ba27bc366fb3166b22f1bda909b9ede486ad8c7d) feat: implement Hetzner Cloud support for virtual (shared) IP\n* [`95f440ea`](https://github.com/talos-systems/talos/commit/95f440eaa06d2a558fc828c11b451b6aed8d5855) test: add fuzz test for configloader\n* [`d2cf021d`](https://github.com/talos-systems/talos/commit/d2cf021d8ffb6d6188b2d50f1f7b9c24df0aac84) chore: remove deprecated \"join\" term\n* [`0e18e280`](https://github.com/talos-systems/talos/commit/0e18e2800fc038a86ed2fd9b042278ae29070bb5) chore: bump dependencies\n* [`b450b7ce`](https://github.com/talos-systems/talos/commit/b450b7cef0d84a9ad975d8b50b93854bb0645173) chore: deprecate Interfaces and Routes APIs\n* [`cddcb962`](https://github.com/talos-systems/talos/commit/cddcb9622bce7ae3626b8b9dce8c622a0e30ba66) fix: find devices without partition table\n* [`b1b6d613`](https://github.com/talos-systems/talos/commit/b1b6d61365c900c4ebfc377b86067ddbe4fe8353) fix: check for existence of dhcp6 FQDN first\n* [`519999b8`](https://github.com/talos-systems/talos/commit/519999b8462ff4931ed12323417b9a9c8c20b369) fix: use readonly mode when probing devices with `All` lookup\n* [`2b520420`](https://github.com/talos-systems/talos/commit/2b5204200a4bd22aa78245b201c471136016ce3a) feat: enable resource API in the maintenance mode\n* [`452893c2`](https://github.com/talos-systems/talos/commit/452893c260b920c601b0fc22ff018dc2d4341fca) fix: make probe open blockdevice in readonly mode\n* [`96bccdd3`](https://github.com/talos-systems/talos/commit/96bccdd3b625f0edefd685cadf5f2cd46e3111f5) test: update CABPT provider to 0.3 release\n* [`d9eb18bf`](https://github.com/talos-systems/talos/commit/d9eb18bfddf69a61712d930b53aec489a806394a) fix: containerd log symlink\n* [`efa7f48e`](https://github.com/talos-systems/talos/commit/efa7f48e08382249609e0ecd3241c01a2e46df73) docs: quicklinks on landing page\n* [`1cb9f282`](https://github.com/talos-systems/talos/commit/1cb9f282b541505f2d61ae0a57655cba9ae62843) fix: don't marshal clock with SecretsBundle\n</p>\n</details>\n\n### Changes from talos-systems/discovery-service\n<details><summary>16 commits</summary>\n<p>\n\n* [`e9d5dfa`](https://github.com/talos-systems/discovery-service/commit/e9d5dfa15e92fc1bdee620b2687eecd2ff929ac3) fix: enable connections to endpoints with public certs\n* [`509e9b2`](https://github.com/talos-systems/discovery-service/commit/509e9b2ced989631224afd3bfd5e8bdcbcf13137) feat: implement client wrapper around discovery service API\n* [`6195466`](https://github.com/talos-systems/discovery-service/commit/619546696afe99c1b58b46ca819bb32e74560f5b) feat: enable vtprotobuf, watch batching, more limits\n* [`7174ec1`](https://github.com/talos-systems/discovery-service/commit/7174ec10426ff17172aaa195423e2588b23aa868) feat: implement new discovery service\n* [`1a43970`](https://github.com/talos-systems/discovery-service/commit/1a4397082659a2b6bca6fd53a5080e109d978627) feat: add node and cluster validation\n* [`6454cfc`](https://github.com/talos-systems/discovery-service/commit/6454cfcb726bba64823f25d962bc04007d057a8b) refactor: kresify, fix linter and rename to Kubespan manager\n* [`d782452`](https://github.com/talos-systems/discovery-service/commit/d782452e86bf94c1194f806384fc339835a96d2d) add redis database backend\n* [`924fed4`](https://github.com/talos-systems/discovery-service/commit/924fed4ecc939887c55a4a8a5f5dfe737ca29c78) refactor to flexible addresses\n* [`cd02b5a`](https://github.com/talos-systems/discovery-service/commit/cd02b5a36783454f7650df5709984f01ccc8bd6e) revert to string IDs\n* [`576288f`](https://github.com/talos-systems/discovery-service/commit/576288fc7559f9eac1966627b6c1e2c731e0c322) add self-reported IPs\n* [`6ad15ca`](https://github.com/talos-systems/discovery-service/commit/6ad15ca825bdf4636855f2b77535945d07462a17) strong typing and known endpoint API\n* [`3437ff2`](https://github.com/talos-systems/discovery-service/commit/3437ff28fb9ab6efb96cc79da1c75bd81bfb50cc) fixes from testing\n* [`d3fd1f3`](https://github.com/talos-systems/discovery-service/commit/d3fd1f324d7af60f2ddf425c9c2cf9b9743e6d62) add Name to Node\n* [`eb0e8ba`](https://github.com/talos-systems/discovery-service/commit/eb0e8baadacd702044ca419f933dd409ae58977e) add simple client pkg\n* [`5e0c1df`](https://github.com/talos-systems/discovery-service/commit/5e0c1df0f1823cce1b92ccffb1e18fb1e540117d) add cluster hash grouping\n* [`f982696`](https://github.com/talos-systems/discovery-service/commit/f982696ec1b45f8d7e6d2dfa1d780b3b0d515dbb) initial commit\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`52b27da`](https://github.com/talos-systems/extras/commit/52b27dad5aeeb5d14225a99e4b5902614c993022) chore: update pkgs and tools to 0.8.0-alpha.0\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>6 commits</summary>\n<p>\n\n* [`70d2865`](https://github.com/talos-systems/go-blockdevice/commit/70d28650b398a14469cbb5356417355b0ba62956) fix: try to find cdrom disks\n* [`667bf53`](https://github.com/talos-systems/go-blockdevice/commit/667bf539b99ac34b629a0103ef7a7278a5a5f35d) fix: revert gpt partition not found\n* [`d7d4cdd`](https://github.com/talos-systems/go-blockdevice/commit/d7d4cdd7ac56c82caab19246b5decd59f12195eb) fix: gpt partition not found\n* [`33afba3`](https://github.com/talos-systems/go-blockdevice/commit/33afba347c0dce38a436c46a0aac26d2f99427c1) fix: also open in readonly mode when running `All` lookup method\n* [`e367f9d`](https://github.com/talos-systems/go-blockdevice/commit/e367f9dc7fa935f11672de0fdc8a89429285a07a) feat: make probe always open blockdevices in readonly mode\n* [`d981156`](https://github.com/talos-systems/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>7 commits</summary>\n<p>\n\n* [`28cda67`](https://github.com/talos-systems/pkgs/commit/28cda67f9b518cb4d4a299bac62be1c3ed3cddda) feat: update Linux kernel to 5.10.69\n* [`db90f93`](https://github.com/talos-systems/pkgs/commit/db90f93c0b462dcaefa081c18f8adebae5d5744a) chore: update tools\n* [`ca38c59`](https://github.com/talos-systems/pkgs/commit/ca38c599b71334d5a108021c7e7ccec12701ff18) feat: enable KEXEC_FILE_LOAD in the kernel\n* [`982bc18`](https://github.com/talos-systems/pkgs/commit/982bc18a4ecf5d4e15a73c350abb97f02adb8871) chore: update tools\n* [`a243ab8`](https://github.com/talos-systems/pkgs/commit/a243ab8a9345b8bc39cc65254015b6eb07605f61) feat: add /usr/src to FHS\n* [`428abdb`](https://github.com/talos-systems/pkgs/commit/428abdbfd303fce69cf583f5a8a4f5ed43253807) chore: support builds with HTTP_PROXY\n* [`13151c5`](https://github.com/talos-systems/pkgs/commit/13151c59b5b29541ed5828aa9c75a061ec920ff1) chore: update bldr version, update tools\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`2790b55`](https://github.com/talos-systems/tools/commit/2790b5586e810c7dfc0a197ef9d1e6d77a646e3b) feat: update Go to 1.17.1\n* [`5b9d214`](https://github.com/talos-systems/tools/commit/5b9d214c38515a55232ce36591036748fd8c49cc) fix: restore static library for ncurses\n* [`01104e5`](https://github.com/talos-systems/tools/commit/01104e562efdbff34fb2d597d4cf27d04ba44ea6) chore: reproducible builds\n* [`53fe146`](https://github.com/talos-systems/tools/commit/53fe146ca8ba55c959fee04302a5ce215a927f1d) chore: update bldr with new version\n* [`bf4540d`](https://github.com/talos-systems/tools/commit/bf4540d0ed0728cd7751e0c3ab3bb4b8927e334c) chore: add patch dependency\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/containerd/go-cni**                   v1.0.2 -> v1.1.0\n* **github.com/containernetworking/cni**             v0.8.1 -> v1.0.1\n* **github.com/containernetworking/plugins**         v0.9.1 -> v1.0.1\n* **github.com/cosi-project/runtime**                25f235cd0682 -> 5cb7f5002d77\n* **github.com/fatih/color**                         v1.12.0 -> v1.13.0\n* **github.com/fsnotify/fsnotify**                   v1.4.9 -> v1.5.1\n* **github.com/gdamore/tcell/v2**                    v2.4.0 -> f057f0a857a1\n* **github.com/google/nftables**                     16a134723a96 **_new_**\n* **github.com/hashicorp/go-getter**                 v1.5.7 -> v1.5.8\n* **github.com/hetznercloud/hcloud-go**              v1.32.0 **_new_**\n* **github.com/insomniacslk/dhcp**                   1cac67f12b1e -> b95caade3eac\n* **github.com/jsimonetti/rtnetlink**                9c52e516c709 -> 435639c8e6a8\n* **github.com/jxskiss/base62**                      4f11678b909b **_new_**\n* **github.com/mattn/go-isatty**                     v0.0.13 -> v0.0.14\n* **github.com/mdlayher/netx**                       669a06fde734 **_new_**\n* **github.com/packethost/packngo**                  v0.19.0 -> v0.19.1\n* **github.com/prometheus/procfs**                   v0.7.2 -> v0.7.3\n* **github.com/rivo/tview**                          29d673af0ce2 -> ee97a7ab3975\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.7 **_new_**\n* **github.com/talos-systems/discovery-service**     e9d5dfa15e92 **_new_**\n* **github.com/talos-systems/extras**                v0.5.0 -> v0.6.0-alpha.0\n* **github.com/talos-systems/go-blockdevice**        v0.2.3 -> 70d28650b398\n* **github.com/talos-systems/pkgs**                  v0.7.0 -> v0.8.0-alpha.0-4-g28cda67\n* **github.com/talos-systems/tools**                 v0.7.0-1-ga33ccc1 -> v0.8.0-alpha.0-3-g2790b55\n* **github.com/vishvananda/netlink**                 f5de75959ad5 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.1 -> v0.53.2\n* **github.com/vmware/govmomi**                      v0.26.0 -> v0.26.1\n* **github.com/vultr/metadata**                      v1.0.3 **_new_**\n* **go.uber.org/zap**                                v1.19.0 -> v1.19.1\n* **golang.org/x/net**                               853a461950ff -> 3ad01bbaa167\n* **golang.org/x/sys**                               0f9fa26af87c -> 39ccf1dd6fa6\n* **golang.org/x/term**                              6886f2dfbf5b -> 140adaaadfaf\n* **golang.zx2c4.com/wireguard/wgctrl**              92e472f520a5 -> 0a2f4901cba6\n* **google.golang.org/grpc**                         v1.40.0 -> v1.41.0\n* **inet.af/netaddr**                                ce7a8ad02cc1 -> 85fa6c94624e\n* **k8s.io/api**                                     v0.22.1 -> v0.22.2\n* **k8s.io/apimachinery**                            v0.22.1 -> v0.22.2\n* **k8s.io/client-go**                               v0.22.1 -> v0.22.2\n* **k8s.io/kubectl**                                 v0.22.1 -> v0.22.2\n* **k8s.io/kubelet**                                 v0.22.1 -> v0.22.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.59 **_new_**\n\nPrevious release can be found at [v0.12.0](https://github.com/talos-systems/talos/releases/tag/v0.12.0)\n\n## [Talos 0.13.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.13.0-alpha.1) (2021-09-20)\n\nWelcome to the v0.13.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Hetzner, Scaleway, Upcloud and Vultr\n\nTalos now natively supports three new cloud platforms:\n\n* [Hetzner](https://www.hetzner.com/)\n* [Scaleway](https://www.scaleway.com/en/)\n* [Upcloud](https://upcloud.com/)\n* [Vultr](https://www.vultr.com/)\n\n\n### etcd Advertised Address\n\nThe address advertised by etcd can now be controlled with new machine configuration option `machine.etcd.subnet`.\n\n\n### Reboots via kexec\n\nTalos now reboots by default via kexec syscall which means BIOS POST process is skipped.\nOn bare-metal hardware BIOS POST process might take 10-15 minutes, so Talos reboots 10-15 minutes faster on bare-metal.\n\nKexec support can be disabled with the following change to the machine configuration:\n\n```\nmachine:\n  sysctls:\n    kernel.kexec_load_disabled: \"1\"\n```\n\n\n### Cluster Discovery and KubeSpan\n\nThis release of Talos provides initial support for cluster membership discovery and [KubeSpan](https://www.talos-systems.com/kubespan/).\n\nThese new features are not enabled by default, to enable them please make following changes to the machine configuration:\n\n```yaml\nmachine:\n  network:\n    kubespan:\n      enabled: true\ncluster:\n  discovery:\n    enabled: true\n```\n\n\n\n### Windows Support\n\nCLI tool talosctl is now built for Windows and published as part of the release.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Serge Logvinov\n* Andrew Rynhard\n* Olli Janatuinen\n* Andrey Smirnov\n* Lennard Klein\n* Rui Lopes\n* Spencer Smith\n\n### Changes\n<details><summary>74 commits</summary>\n<p>\n\n* [`9d803d75`](https://github.com/talos-systems/talos/commit/9d803d75bfbe788fa5c2ef2ae0639de31e172c7b) chore: bump dependencies and drop firecracker support\n* [`50a24104`](https://github.com/talos-systems/talos/commit/50a24104820e26bb99e66ab68be2bd9a6c17b0be) feat: add operating system version field to discovery\n* [`085c61b2`](https://github.com/talos-systems/talos/commit/085c61b2ec432c586daa77464910e967a223ebe0) chore: add a special condition to check for kubeconfig readiness\n* [`21cdd854`](https://github.com/talos-systems/talos/commit/21cdd854036498fbeb9f6e4d058a0edd55ed4856) fix: add node address to the list of allowed IPs (kubespan)\n* [`fdd80a12`](https://github.com/talos-systems/talos/commit/fdd80a1234dc993cc01daa7764ba5a9db2fdc275) feat: add an option to continue booting on NTP timeout\n* [`ef368498`](https://github.com/talos-systems/talos/commit/ef36849899b18bbb35c6116fdf35aa580a50a5e5) feat: add routes, routing rules and nftables rules for KubeSpan\n* [`ed12379f`](https://github.com/talos-systems/talos/commit/ed12379f2f49fcbca84080f1066cf52dc202bd2d) fix: patch multi nodes support\n* [`d943bb0e`](https://github.com/talos-systems/talos/commit/d943bb0e280e90f3592d9f7b67813b7a15818c84) feat: update Kubernetes to 1.22.2\n* [`d0585fb6`](https://github.com/talos-systems/talos/commit/d0585fb6b303dfdd7fc80a76024915df31c72389) feat: reboot via kexec\n* [`3de505c8`](https://github.com/talos-systems/talos/commit/3de505c894274bfd5248b6c597f6e3a53f873ba1) fix: skip bad cloud-config in OpenStack platform\n* [`a394d1e2`](https://github.com/talos-systems/talos/commit/a394d1e20ba82de7d05e4d3f91823a98362ac9ee) fix: tear down control plane static pods when etcd is stopped\n* [`1c05089b`](https://github.com/talos-systems/talos/commit/1c05089bb22c7c1050e95cf8d7bea8b763a0e86f) feat: implement KubeSpan manager for Wireguard peer state\n* [`ec7f44ef`](https://github.com/talos-systems/talos/commit/ec7f44efe4f89e7ed207cbd5fe3748953ccfdf28) fix: completely prevent editing resources other than mc\n* [`19a8ae97`](https://github.com/talos-systems/talos/commit/19a8ae97c69949f7c2421154b2ae4e52a905ff63) feat: add vultr.com cloud support\n* [`0ff4c7cd`](https://github.com/talos-systems/talos/commit/0ff4c7cdb2b9505823f4c4504ec9bf4d7fddf5c5) fix: write KubernetesCACert chmodded 0400 instead of 0500\n* [`a1c9d649`](https://github.com/talos-systems/talos/commit/a1c9d64907cce75bcb566f3ee394734e29b3932d) fix: update the way results are retrieved for certified conformance\n* [`a0594540`](https://github.com/talos-systems/talos/commit/a0594540451a7636f8cd4bbe835913d31f66d0de) chore: build using Go 1.17\n* [`7c5045bd`](https://github.com/talos-systems/talos/commit/7c5045bd929fcf5028cae3840970e692ef3bc7c9) release(v0.13.0-alpha.0): prepare release\n* [`ee2dce6c`](https://github.com/talos-systems/talos/commit/ee2dce6c1a0e8838e587a9136afd1b7381000432) chore: bump dependencies\n* [`ef022959`](https://github.com/talos-systems/talos/commit/ef022959280f156d6311836ef9cc2d01e5e3ae7d) fix: print etcd member ID in hex\n* [`5ca1fb82`](https://github.com/talos-systems/talos/commit/5ca1fb822125483be290e79d8828bba246fda51c) fix: multiple fixes for KubeSpan and Wireguard implementation\n* [`b1bd6425`](https://github.com/talos-systems/talos/commit/b1bd64250820df3fcb5214368ce9c8cf4634970a) fix: build platform images\n* [`3b5f4038`](https://github.com/talos-systems/talos/commit/3b5f4038de2f855b3b634e4abb1c564da624e2fc) feat: add scaleway.com cloud support\n* [`f156ab18`](https://github.com/talos-systems/talos/commit/f156ab1847f2ad1ca2a2548b299a713ee5fe0fcd) feat: add upcloud.com cloud support\n* [`c3b2429c`](https://github.com/talos-systems/talos/commit/c3b2429ce91edc4f8f9e720a4b144bc941046fc3) fix: suppress spurious Kubernetes API server cert updates\n* [`ff90b575`](https://github.com/talos-systems/talos/commit/ff90b5751e17a60fc6ca4274f35da7ddcca44fea) feat: implement KubeSpan peer generation controller\n* [`14c69df5`](https://github.com/talos-systems/talos/commit/14c69df5063e71765b9316ae37657fda2388c60e) fix: correctly parse multiple pod/service CIDRs\n* [`69897dbb`](https://github.com/talos-systems/talos/commit/69897dbba402812403c0c15d6cb8d2a771ea5a88) feat: drop some capabilities to be never available\n* [`51e9836b`](https://github.com/talos-systems/talos/commit/51e9836b01926d1619d662e6e08df29210ff94e5) docs: promote 0.12 docs to be the latest\n* [`812d59c7`](https://github.com/talos-systems/talos/commit/812d59c70085b54136e3b56127b0efea7ddb60af) feat: add hetzner.com cloud support\n* [`d53e9e89`](https://github.com/talos-systems/talos/commit/d53e9e89633258d85c2232b85855535ebb42c417) chore: use named constants\n* [`2dfe7f1f`](https://github.com/talos-systems/talos/commit/2dfe7f1fc654c8bec83b632a98dbaa8d1b90a521) chore: bump tools to the latest version\n* [`82b130e7`](https://github.com/talos-systems/talos/commit/82b130e789aa4376e1f0e2d086233e630b410f74) docs: document required options for extraMounts\n* [`af662210`](https://github.com/talos-systems/talos/commit/af6622109faecdf03aed43b047035904110c7580) feat: implement Kubernetes cluster discovery registry\n* [`2c66e1b3`](https://github.com/talos-systems/talos/commit/2c66e1b3c5d4c34c5d4cdc155c32f2808a5f1c69) feat: provide building of local `Affiliate` structure (for the node)\n* [`d69bd2af`](https://github.com/talos-systems/talos/commit/d69bd2af3e3d3bf12b6d74078e9eedf3dc8752fc) chore: enable GPG identity check for Talos\n* [`8dbd851f`](https://github.com/talos-systems/talos/commit/8dbd851fde3febb5999df694a079121b43519aa9) chore: update tools/pkgs/extras to the new version\n* [`0b347570`](https://github.com/talos-systems/talos/commit/0b347570a7aca0a133d6b6e6cc8d3e0355630480) feat: use dynamic NodeAddresses/HostnameStatus in Kubernetes certs\n* [`bd5b9c96`](https://github.com/talos-systems/talos/commit/bd5b9c96e2563249a5633433703493b292b83ee9) fix: correctly define example for `extraMounts`\n* [`01cca099`](https://github.com/talos-systems/talos/commit/01cca099f40ec75d1e047a84c89692eb254e8adf) docs: update docs for Talos 0.12 release\n* [`668627d5`](https://github.com/talos-systems/talos/commit/668627d5b8ec79ec955eb1254732b1cc031d3aec) feat: add subnet filter for etcd address\n* [`3c3c281b`](https://github.com/talos-systems/talos/commit/3c3c281bff8481f680feca9cf01af413a38e6973) chore: bump dependencies via dependabot\n* [`f8bebba2`](https://github.com/talos-systems/talos/commit/f8bebba2de3999b7a36fecb2d6b90e583372c98f) fix: ignore error on duplicate for `MountStatus`\n* [`6956edd0`](https://github.com/talos-systems/talos/commit/6956edd0bfae6c6c5d6eba00a22bc3a4cb7f54ea) feat: add node address filters, filter out k8s addresses for Talos API\n* [`caee24bf`](https://github.com/talos-systems/talos/commit/caee24bf61136daecb095991a6e439f7fbf40da2) feat: implement KubeSpan identity controller\n* [`da0f6e7e`](https://github.com/talos-systems/talos/commit/da0f6e7e1d295dce0c44c1854363528a6ffedde1) fix: allow updating diskSelector option\n* [`761ccaf3`](https://github.com/talos-systems/talos/commit/761ccaf32348d8664eb0d5d1a51f6abb19ca52a6) feat: provide machine configuration for KubeSpan and cluster discovery\n* [`a81e30cb`](https://github.com/talos-systems/talos/commit/a81e30cb46326fbdd433f37dc37549b588a2bc7a) docs: add bootstrap command to VMware docs\n* [`97da354c`](https://github.com/talos-systems/talos/commit/97da354cc0e4a965e14b8939c426150d5c12f228) fix: do not panic on invalid machine configs\n* [`c4048e26`](https://github.com/talos-systems/talos/commit/c4048e263d22682142f12fc4af6ac58c679273f0) fix: don't extract nil IPs in the GCP platform\n* [`ba169c6f`](https://github.com/talos-systems/talos/commit/ba169c6f91948cf057251236fa7a727a05253639) feat: provide talosctl.exe for Windows\n* [`6312f473`](https://github.com/talos-systems/talos/commit/6312f473e63df50287e6801c079242e2311a23e6) fix: properly handle omitempty fields in the validator\n* [`7f22879a`](https://github.com/talos-systems/talos/commit/7f22879af0882af4cdebe9c84afb96ae68eb9f20) feat: provide random node identity\n* [`032e7c6b`](https://github.com/talos-systems/talos/commit/032e7c6b863b5ca02cfa16df79c88950544dbffb) chore: import yaml.v3 consistently\n* [`80b5f0e7`](https://github.com/talos-systems/talos/commit/80b5f0e7f78f09a11ed249f9f1dc7b05ea275ab0) fix: validate IP address returned as HTTP response in platform code\n* [`c9af8f7f`](https://github.com/talos-systems/talos/commit/c9af8f7ff17facc18f10675879ed04982a000f6f) docs: fork docs for 0.13\n* [`85cda1b9`](https://github.com/talos-systems/talos/commit/85cda1b956b042ba20696637248999d46f63ccc9) feat: provide MountStatus resource for system partition mounts\n* [`950f122c`](https://github.com/talos-systems/talos/commit/950f122c95e225858e77083f2490481ed8d21aef) chore: update versions in upgrade tests\n* [`83fdb772`](https://github.com/talos-systems/talos/commit/83fdb7721f45aa075898caf05a4b6856d3c5f330) feat: provide first NIC hardware addr as a resource\n* [`5f5ac12f`](https://github.com/talos-systems/talos/commit/5f5ac12f1dc8aeb3a8598e57d965471e93fe3724) fix: properly case the VMware name\n* [`0a6048f4`](https://github.com/talos-systems/talos/commit/0a6048f469da02efad7e84eb237e6fdeb85b7e33) fix: don't allow bootstrap if etcd data directory is not empty\n* [`e24b93b4`](https://github.com/talos-systems/talos/commit/e24b93b4e120448f37109599f3e9eb15954b147a) fix: cgroup delegate\n* [`751f64f9`](https://github.com/talos-systems/talos/commit/751f64f9bc10e9ad8508ade9e3a6a14aaaa54d57) docs: add release notes for 0.12, support matrix\n* [`57a77696`](https://github.com/talos-systems/talos/commit/57a77696ef2b255a59ee4ed213a1a3971a5e2943) feat: update Kubernetes to 1.22.1\n* [`244b08cc`](https://github.com/talos-systems/talos/commit/244b08cc198a8ba676bb9acadcbdd23a161b0876) chore: bump dependencies\n* [`576ba195`](https://github.com/talos-systems/talos/commit/576ba195784abf275256c861d5f811ab1f7b1102) fix: do not set KSPP kernel params in container mode\n* [`b8c92ede`](https://github.com/talos-systems/talos/commit/b8c92ede52ed515dba68abf4fb1cc6494d510827) fix: don't support cgroups nesting in process runner\n* [`9bb0b797`](https://github.com/talos-systems/talos/commit/9bb0b79709a502ab49ea9bacd7e54617554d4cc3) test: adapt tests to the cgroupsv2\n* [`1abc12be`](https://github.com/talos-systems/talos/commit/1abc12be13208ad1da03492a1b88d2c1ec0d5d33) fix: extramount should have `yaml:\",inline\"` tag\n* [`2b614e43`](https://github.com/talos-systems/talos/commit/2b614e430e478cc111db018996ab2c8f763e4f92) feat: check if cluster has deprecated resources versions\n* [`0b86edab`](https://github.com/talos-systems/talos/commit/0b86edab80cf4dd01f330d7721b130f5017d84a5) fix: don't panic if the machine config doesn't have network (EM)\n* [`8bef41e4`](https://github.com/talos-systems/talos/commit/8bef41e4bacc4190976657ae5021afecd2d6e001) fix: make sure file mode is same (reproducibility issue)\n* [`fcfca55a`](https://github.com/talos-systems/talos/commit/fcfca55a059e92fcda198baa321c4c63bda1f0a4) chore: do not check that go mod tidy gives empty output\n* [`5ce92ca5`](https://github.com/talos-systems/talos/commit/5ce92ca5163616fcd7abe16c4efc3a100953b246) docs: ensure azure VMs are 0 indexed\n</p>\n</details>\n\n### Changes since v0.13.0-alpha.0\n<details><summary>17 commits</summary>\n<p>\n\n* [`9d803d75`](https://github.com/talos-systems/talos/commit/9d803d75bfbe788fa5c2ef2ae0639de31e172c7b) chore: bump dependencies and drop firecracker support\n* [`50a24104`](https://github.com/talos-systems/talos/commit/50a24104820e26bb99e66ab68be2bd9a6c17b0be) feat: add operating system version field to discovery\n* [`085c61b2`](https://github.com/talos-systems/talos/commit/085c61b2ec432c586daa77464910e967a223ebe0) chore: add a special condition to check for kubeconfig readiness\n* [`21cdd854`](https://github.com/talos-systems/talos/commit/21cdd854036498fbeb9f6e4d058a0edd55ed4856) fix: add node address to the list of allowed IPs (kubespan)\n* [`fdd80a12`](https://github.com/talos-systems/talos/commit/fdd80a1234dc993cc01daa7764ba5a9db2fdc275) feat: add an option to continue booting on NTP timeout\n* [`ef368498`](https://github.com/talos-systems/talos/commit/ef36849899b18bbb35c6116fdf35aa580a50a5e5) feat: add routes, routing rules and nftables rules for KubeSpan\n* [`ed12379f`](https://github.com/talos-systems/talos/commit/ed12379f2f49fcbca84080f1066cf52dc202bd2d) fix: patch multi nodes support\n* [`d943bb0e`](https://github.com/talos-systems/talos/commit/d943bb0e280e90f3592d9f7b67813b7a15818c84) feat: update Kubernetes to 1.22.2\n* [`d0585fb6`](https://github.com/talos-systems/talos/commit/d0585fb6b303dfdd7fc80a76024915df31c72389) feat: reboot via kexec\n* [`3de505c8`](https://github.com/talos-systems/talos/commit/3de505c894274bfd5248b6c597f6e3a53f873ba1) fix: skip bad cloud-config in OpenStack platform\n* [`a394d1e2`](https://github.com/talos-systems/talos/commit/a394d1e20ba82de7d05e4d3f91823a98362ac9ee) fix: tear down control plane static pods when etcd is stopped\n* [`1c05089b`](https://github.com/talos-systems/talos/commit/1c05089bb22c7c1050e95cf8d7bea8b763a0e86f) feat: implement KubeSpan manager for Wireguard peer state\n* [`ec7f44ef`](https://github.com/talos-systems/talos/commit/ec7f44efe4f89e7ed207cbd5fe3748953ccfdf28) fix: completely prevent editing resources other than mc\n* [`19a8ae97`](https://github.com/talos-systems/talos/commit/19a8ae97c69949f7c2421154b2ae4e52a905ff63) feat: add vultr.com cloud support\n* [`0ff4c7cd`](https://github.com/talos-systems/talos/commit/0ff4c7cdb2b9505823f4c4504ec9bf4d7fddf5c5) fix: write KubernetesCACert chmodded 0400 instead of 0500\n* [`a1c9d649`](https://github.com/talos-systems/talos/commit/a1c9d64907cce75bcb566f3ee394734e29b3932d) fix: update the way results are retrieved for certified conformance\n* [`a0594540`](https://github.com/talos-systems/talos/commit/a0594540451a7636f8cd4bbe835913d31f66d0de) chore: build using Go 1.17\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`52b27da`](https://github.com/talos-systems/extras/commit/52b27dad5aeeb5d14225a99e4b5902614c993022) chore: update pkgs and tools to 0.8.0-alpha.0\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`d981156`](https://github.com/talos-systems/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>6 commits</summary>\n<p>\n\n* [`db90f93`](https://github.com/talos-systems/pkgs/commit/db90f93c0b462dcaefa081c18f8adebae5d5744a) chore: update tools\n* [`ca38c59`](https://github.com/talos-systems/pkgs/commit/ca38c599b71334d5a108021c7e7ccec12701ff18) feat: enable KEXEC_FILE_LOAD in the kernel\n* [`982bc18`](https://github.com/talos-systems/pkgs/commit/982bc18a4ecf5d4e15a73c350abb97f02adb8871) chore: update tools\n* [`a243ab8`](https://github.com/talos-systems/pkgs/commit/a243ab8a9345b8bc39cc65254015b6eb07605f61) feat: add /usr/src to FHS\n* [`428abdb`](https://github.com/talos-systems/pkgs/commit/428abdbfd303fce69cf583f5a8a4f5ed43253807) chore: support builds with HTTP_PROXY\n* [`13151c5`](https://github.com/talos-systems/pkgs/commit/13151c59b5b29541ed5828aa9c75a061ec920ff1) chore: update bldr version, update tools\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`2790b55`](https://github.com/talos-systems/tools/commit/2790b5586e810c7dfc0a197ef9d1e6d77a646e3b) feat: update Go to 1.17.1\n* [`5b9d214`](https://github.com/talos-systems/tools/commit/5b9d214c38515a55232ce36591036748fd8c49cc) fix: restore static library for ncurses\n* [`01104e5`](https://github.com/talos-systems/tools/commit/01104e562efdbff34fb2d597d4cf27d04ba44ea6) chore: reproducible builds\n* [`53fe146`](https://github.com/talos-systems/tools/commit/53fe146ca8ba55c959fee04302a5ce215a927f1d) chore: update bldr with new version\n* [`bf4540d`](https://github.com/talos-systems/tools/commit/bf4540d0ed0728cd7751e0c3ab3bb4b8927e334c) chore: add patch dependency\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/containerd/go-cni**                   v1.0.2 -> v1.1.0\n* **github.com/containernetworking/cni**             v0.8.1 -> v1.0.1\n* **github.com/containernetworking/plugins**         v0.9.1 -> v1.0.1\n* **github.com/cosi-project/runtime**                25f235cd0682 -> 5cb7f5002d77\n* **github.com/fsnotify/fsnotify**                   v1.4.9 -> v1.5.1\n* **github.com/gdamore/tcell/v2**                    v2.4.0 -> f057f0a857a1\n* **github.com/google/nftables**                     16a134723a96 **_new_**\n* **github.com/hashicorp/go-getter**                 v1.5.7 -> v1.5.8\n* **github.com/insomniacslk/dhcp**                   1cac67f12b1e -> b95caade3eac\n* **github.com/jsimonetti/rtnetlink**                9c52e516c709 -> 4cc3c1489576\n* **github.com/jxskiss/base62**                      4f11678b909b **_new_**\n* **github.com/mattn/go-isatty**                     v0.0.13 -> v0.0.14\n* **github.com/mdlayher/netx**                       669a06fde734 **_new_**\n* **github.com/packethost/packngo**                  v0.19.0 -> v0.19.1\n* **github.com/prometheus/procfs**                   v0.7.2 -> v0.7.3\n* **github.com/rivo/tview**                          29d673af0ce2 -> f7430b878d17\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.7 **_new_**\n* **github.com/talos-systems/extras**                v0.5.0 -> v0.6.0-alpha.0\n* **github.com/talos-systems/go-blockdevice**        v0.2.3 -> d9811569588b\n* **github.com/talos-systems/pkgs**                  v0.7.0 -> v0.8.0-alpha.0-3-gdb90f93\n* **github.com/talos-systems/tools**                 v0.7.0-1-ga33ccc1 -> v0.8.0-alpha.0-3-g2790b55\n* **github.com/vishvananda/netlink**                 f5de75959ad5 **_new_**\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.1 -> v0.53.2\n* **github.com/vmware/govmomi**                      v0.26.0 -> v0.26.1\n* **github.com/vultr/metadata**                      v1.0.3 **_new_**\n* **go.uber.org/zap**                                v1.19.0 -> v1.19.1\n* **golang.org/x/net**                               853a461950ff -> 978cfadd31cf\n* **golang.org/x/sys**                               0f9fa26af87c -> d61c044b1678\n* **golang.org/x/term**                              6886f2dfbf5b -> 140adaaadfaf\n* **golang.zx2c4.com/wireguard/wgctrl**              92e472f520a5 -> 91d1988e44de\n* **inet.af/netaddr**                                ce7a8ad02cc1 -> 85fa6c94624e\n* **k8s.io/api**                                     v0.22.1 -> v0.22.2\n* **k8s.io/apimachinery**                            v0.22.1 -> v0.22.2\n* **k8s.io/client-go**                               v0.22.1 -> v0.22.2\n* **k8s.io/kubectl**                                 v0.22.1 -> v0.22.2\n* **k8s.io/kubelet**                                 v0.22.1 -> v0.22.2\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.58 **_new_**\n\nPrevious release can be found at [v0.12.0](https://github.com/talos-systems/talos/releases/tag/v0.12.0)\n\n## [Talos 0.13.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.13.0-alpha.0) (2021-09-13)\n\nWelcome to the v0.13.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Hetzner, Scaleway and Upcloud\n\nTalos now natively supports three new cloud platforms:\n\n* [Hetzner](https://www.hetzner.com/)\n* [Scaleway](https://www.scaleway.com/en/)\n* [Upcloud](https://upcloud.com/)\n\n\n### etcd Advertised Address\n\nThe address advertised by etcd can now be controlled with new machine configuration option `machine.etcd.subnet`.\n\n\n### Cluster Discovery and KubeSpan\n\nThis release of Talos provides some initial support for cluster membership discovery and [KubeSpan](https://www.talos-systems.com/kubespan/).\n\nThese new features are not enabled by default.\n\n\n### Windows Support\n\nCLI tool talosctl is now built for Windows and published as part of the release.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Artem Chernyshev\n* Alexey Palazhchenko\n* Serge Logvinov\n* Andrew Rynhard\n* Olli Janatuinen\n* Andrey Smirnov\n* Rui Lopes\n* Spencer Smith\n\n### Changes\n<details><summary>55 commits</summary>\n<p>\n\n* [`ef022959`](https://github.com/talos-systems/talos/commit/ef022959280f156d6311836ef9cc2d01e5e3ae7d) fix: print etcd member ID in hex\n* [`5ca1fb82`](https://github.com/talos-systems/talos/commit/5ca1fb822125483be290e79d8828bba246fda51c) fix: multiple fixes for KubeSpan and Wireguard implementation\n* [`b1bd6425`](https://github.com/talos-systems/talos/commit/b1bd64250820df3fcb5214368ce9c8cf4634970a) fix: build platform images\n* [`3b5f4038`](https://github.com/talos-systems/talos/commit/3b5f4038de2f855b3b634e4abb1c564da624e2fc) feat: add scaleway.com cloud support\n* [`f156ab18`](https://github.com/talos-systems/talos/commit/f156ab1847f2ad1ca2a2548b299a713ee5fe0fcd) feat: add upcloud.com cloud support\n* [`c3b2429c`](https://github.com/talos-systems/talos/commit/c3b2429ce91edc4f8f9e720a4b144bc941046fc3) fix: suppress spurious Kubernetes API server cert updates\n* [`ff90b575`](https://github.com/talos-systems/talos/commit/ff90b5751e17a60fc6ca4274f35da7ddcca44fea) feat: implement KubeSpan peer generation controller\n* [`14c69df5`](https://github.com/talos-systems/talos/commit/14c69df5063e71765b9316ae37657fda2388c60e) fix: correctly parse multiple pod/service CIDRs\n* [`69897dbb`](https://github.com/talos-systems/talos/commit/69897dbba402812403c0c15d6cb8d2a771ea5a88) feat: drop some capabilities to be never available\n* [`51e9836b`](https://github.com/talos-systems/talos/commit/51e9836b01926d1619d662e6e08df29210ff94e5) docs: promote 0.12 docs to be the latest\n* [`812d59c7`](https://github.com/talos-systems/talos/commit/812d59c70085b54136e3b56127b0efea7ddb60af) feat: add hetzner.com cloud support\n* [`d53e9e89`](https://github.com/talos-systems/talos/commit/d53e9e89633258d85c2232b85855535ebb42c417) chore: use named constants\n* [`2dfe7f1f`](https://github.com/talos-systems/talos/commit/2dfe7f1fc654c8bec83b632a98dbaa8d1b90a521) chore: bump tools to the latest version\n* [`82b130e7`](https://github.com/talos-systems/talos/commit/82b130e789aa4376e1f0e2d086233e630b410f74) docs: document required options for extraMounts\n* [`af662210`](https://github.com/talos-systems/talos/commit/af6622109faecdf03aed43b047035904110c7580) feat: implement Kubernetes cluster discovery registry\n* [`2c66e1b3`](https://github.com/talos-systems/talos/commit/2c66e1b3c5d4c34c5d4cdc155c32f2808a5f1c69) feat: provide building of local `Affiliate` structure (for the node)\n* [`d69bd2af`](https://github.com/talos-systems/talos/commit/d69bd2af3e3d3bf12b6d74078e9eedf3dc8752fc) chore: enable GPG identity check for Talos\n* [`8dbd851f`](https://github.com/talos-systems/talos/commit/8dbd851fde3febb5999df694a079121b43519aa9) chore: update tools/pkgs/extras to the new version\n* [`0b347570`](https://github.com/talos-systems/talos/commit/0b347570a7aca0a133d6b6e6cc8d3e0355630480) feat: use dynamic NodeAddresses/HostnameStatus in Kubernetes certs\n* [`bd5b9c96`](https://github.com/talos-systems/talos/commit/bd5b9c96e2563249a5633433703493b292b83ee9) fix: correctly define example for `extraMounts`\n* [`01cca099`](https://github.com/talos-systems/talos/commit/01cca099f40ec75d1e047a84c89692eb254e8adf) docs: update docs for Talos 0.12 release\n* [`668627d5`](https://github.com/talos-systems/talos/commit/668627d5b8ec79ec955eb1254732b1cc031d3aec) feat: add subnet filter for etcd address\n* [`3c3c281b`](https://github.com/talos-systems/talos/commit/3c3c281bff8481f680feca9cf01af413a38e6973) chore: bump dependencies via dependabot\n* [`f8bebba2`](https://github.com/talos-systems/talos/commit/f8bebba2de3999b7a36fecb2d6b90e583372c98f) fix: ignore error on duplicate for `MountStatus`\n* [`6956edd0`](https://github.com/talos-systems/talos/commit/6956edd0bfae6c6c5d6eba00a22bc3a4cb7f54ea) feat: add node address filters, filter out k8s addresses for Talos API\n* [`caee24bf`](https://github.com/talos-systems/talos/commit/caee24bf61136daecb095991a6e439f7fbf40da2) feat: implement KubeSpan identity controller\n* [`da0f6e7e`](https://github.com/talos-systems/talos/commit/da0f6e7e1d295dce0c44c1854363528a6ffedde1) fix: allow updating diskSelector option\n* [`761ccaf3`](https://github.com/talos-systems/talos/commit/761ccaf32348d8664eb0d5d1a51f6abb19ca52a6) feat: provide machine configuration for KubeSpan and cluster discovery\n* [`a81e30cb`](https://github.com/talos-systems/talos/commit/a81e30cb46326fbdd433f37dc37549b588a2bc7a) docs: add bootstrap command to VMware docs\n* [`97da354c`](https://github.com/talos-systems/talos/commit/97da354cc0e4a965e14b8939c426150d5c12f228) fix: do not panic on invalid machine configs\n* [`c4048e26`](https://github.com/talos-systems/talos/commit/c4048e263d22682142f12fc4af6ac58c679273f0) fix: don't extract nil IPs in the GCP platform\n* [`ba169c6f`](https://github.com/talos-systems/talos/commit/ba169c6f91948cf057251236fa7a727a05253639) feat: provide talosctl.exe for Windows\n* [`6312f473`](https://github.com/talos-systems/talos/commit/6312f473e63df50287e6801c079242e2311a23e6) fix: properly handle omitempty fields in the validator\n* [`7f22879a`](https://github.com/talos-systems/talos/commit/7f22879af0882af4cdebe9c84afb96ae68eb9f20) feat: provide random node identity\n* [`032e7c6b`](https://github.com/talos-systems/talos/commit/032e7c6b863b5ca02cfa16df79c88950544dbffb) chore: import yaml.v3 consistently\n* [`80b5f0e7`](https://github.com/talos-systems/talos/commit/80b5f0e7f78f09a11ed249f9f1dc7b05ea275ab0) fix: validate IP address returned as HTTP response in platform code\n* [`c9af8f7f`](https://github.com/talos-systems/talos/commit/c9af8f7ff17facc18f10675879ed04982a000f6f) docs: fork docs for 0.13\n* [`85cda1b9`](https://github.com/talos-systems/talos/commit/85cda1b956b042ba20696637248999d46f63ccc9) feat: provide MountStatus resource for system partition mounts\n* [`950f122c`](https://github.com/talos-systems/talos/commit/950f122c95e225858e77083f2490481ed8d21aef) chore: update versions in upgrade tests\n* [`83fdb772`](https://github.com/talos-systems/talos/commit/83fdb7721f45aa075898caf05a4b6856d3c5f330) feat: provide first NIC hardware addr as a resource\n* [`5f5ac12f`](https://github.com/talos-systems/talos/commit/5f5ac12f1dc8aeb3a8598e57d965471e93fe3724) fix: properly case the VMware name\n* [`0a6048f4`](https://github.com/talos-systems/talos/commit/0a6048f469da02efad7e84eb237e6fdeb85b7e33) fix: don't allow bootstrap if etcd data directory is not empty\n* [`e24b93b4`](https://github.com/talos-systems/talos/commit/e24b93b4e120448f37109599f3e9eb15954b147a) fix: cgroup delegate\n* [`751f64f9`](https://github.com/talos-systems/talos/commit/751f64f9bc10e9ad8508ade9e3a6a14aaaa54d57) docs: add release notes for 0.12, support matrix\n* [`57a77696`](https://github.com/talos-systems/talos/commit/57a77696ef2b255a59ee4ed213a1a3971a5e2943) feat: update Kubernetes to 1.22.1\n* [`244b08cc`](https://github.com/talos-systems/talos/commit/244b08cc198a8ba676bb9acadcbdd23a161b0876) chore: bump dependencies\n* [`576ba195`](https://github.com/talos-systems/talos/commit/576ba195784abf275256c861d5f811ab1f7b1102) fix: do not set KSPP kernel params in container mode\n* [`b8c92ede`](https://github.com/talos-systems/talos/commit/b8c92ede52ed515dba68abf4fb1cc6494d510827) fix: don't support cgroups nesting in process runner\n* [`9bb0b797`](https://github.com/talos-systems/talos/commit/9bb0b79709a502ab49ea9bacd7e54617554d4cc3) test: adapt tests to the cgroupsv2\n* [`1abc12be`](https://github.com/talos-systems/talos/commit/1abc12be13208ad1da03492a1b88d2c1ec0d5d33) fix: extramount should have `yaml:\",inline\"` tag\n* [`2b614e43`](https://github.com/talos-systems/talos/commit/2b614e430e478cc111db018996ab2c8f763e4f92) feat: check if cluster has deprecated resources versions\n* [`0b86edab`](https://github.com/talos-systems/talos/commit/0b86edab80cf4dd01f330d7721b130f5017d84a5) fix: don't panic if the machine config doesn't have network (EM)\n* [`8bef41e4`](https://github.com/talos-systems/talos/commit/8bef41e4bacc4190976657ae5021afecd2d6e001) fix: make sure file mode is same (reproducibility issue)\n* [`fcfca55a`](https://github.com/talos-systems/talos/commit/fcfca55a059e92fcda198baa321c4c63bda1f0a4) chore: do not check that go mod tidy gives empty output\n* [`5ce92ca5`](https://github.com/talos-systems/talos/commit/5ce92ca5163616fcd7abe16c4efc3a100953b246) docs: ensure azure VMs are 0 indexed\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`52b27da`](https://github.com/talos-systems/extras/commit/52b27dad5aeeb5d14225a99e4b5902614c993022) chore: update pkgs and tools to 0.8.0-alpha.0\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`d981156`](https://github.com/talos-systems/go-blockdevice/commit/d9811569588ba44be878a00ce316f59a37abed8b) fix: allow Build for Windows\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>3 commits</summary>\n<p>\n\n* [`a243ab8`](https://github.com/talos-systems/pkgs/commit/a243ab8a9345b8bc39cc65254015b6eb07605f61) feat: add /usr/src to FHS\n* [`428abdb`](https://github.com/talos-systems/pkgs/commit/428abdbfd303fce69cf583f5a8a4f5ed43253807) chore: support builds with HTTP_PROXY\n* [`13151c5`](https://github.com/talos-systems/pkgs/commit/13151c59b5b29541ed5828aa9c75a061ec920ff1) chore: update bldr version, update tools\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`5b9d214`](https://github.com/talos-systems/tools/commit/5b9d214c38515a55232ce36591036748fd8c49cc) fix: restore static library for ncurses\n* [`01104e5`](https://github.com/talos-systems/tools/commit/01104e562efdbff34fb2d597d4cf27d04ba44ea6) chore: reproducible builds\n* [`53fe146`](https://github.com/talos-systems/tools/commit/53fe146ca8ba55c959fee04302a5ce215a927f1d) chore: update bldr with new version\n* [`bf4540d`](https://github.com/talos-systems/tools/commit/bf4540d0ed0728cd7751e0c3ab3bb4b8927e334c) chore: add patch dependency\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/cosi-project/runtime**                25f235cd0682 -> 57b048cd66b0\n* **github.com/fsnotify/fsnotify**                   v1.4.9 -> v1.5.1\n* **github.com/insomniacslk/dhcp**                   1cac67f12b1e -> d82598001386\n* **github.com/jxskiss/base62**                      4f11678b909b **_new_**\n* **github.com/mdlayher/netx**                       669a06fde734 **_new_**\n* **github.com/prometheus/procfs**                   v0.7.2 -> v0.7.3\n* **github.com/scaleway/scaleway-sdk-go**            v1.0.0-beta.7 **_new_**\n* **github.com/talos-systems/extras**                v0.5.0 -> v0.6.0-alpha.0\n* **github.com/talos-systems/go-blockdevice**        v0.2.3 -> d9811569588b\n* **github.com/talos-systems/pkgs**                  v0.7.0 -> v0.8.0-alpha.0\n* **github.com/talos-systems/tools**                 v0.7.0-1-ga33ccc1 -> v0.8.0-alpha.0-2-g5b9d214\n* **github.com/vmware-tanzu/sonobuoy**               v0.53.1 -> v0.53.2\n* **github.com/vmware/govmomi**                      v0.26.0 -> v0.26.1\n* **golang.org/x/net**                               853a461950ff -> 60bc85c4be6d\n* **golang.org/x/sys**                               0f9fa26af87c -> 63515b42dcdf\n* **kernel.org/pub/linux/libs/security/libcap/cap**  v1.2.56 **_new_**\n\nPrevious release can be found at [v0.12.0](https://github.com/talos-systems/talos/releases/tag/v0.12.0)\n\n## [Talos 0.12.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.12.0-alpha.1) (2021-08-13)\n\nWelcome to the v0.12.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Support for Self-hosted Control Plane Dropped\n\n> **Note**: This item only applies to clusters bootstrapped with Talos <= 0.8.\n\nTalos 0.12 completely removes support for self-hosted Kubernetes control plane (bootkube-based).\nTalos 0.9 introduced support for Talos-managed control plane and provided migration path to convert self-hosted control plane\nto Talos-managed static pods.\nAutomated and manual conversion process is available in Talos from 0.9.x to 0.11.x.\nFor clusters bootstrapped with bootkube (Talos <= 0.8), please make sure control plane is converted to Talos-managed before\nbefore upgrading to Talos 0.12.\nCurrent control plane status can be checked with `talosctl get bootstrapstatus` before performing upgrade to Talos 0.12.\n\n\n### Cluster API v0.3.x\n\nCluster API v0.3.x (v1alpha3) is not compatible with Kubernetes 1.22 used by default in Talos 0.12.\nTalos can be configued to use Kubernetes 1.21 or CAPI v0.4.x components can be used instead.\n\n\n### Machine Config Validation\n\nUnknown keys in the machine config now make the config invalid,\nso any attempt to apply/edit the configuration with the unknown keys will lead into an error.\n\n\n### Sysctl Configuration\n\nSysctl Kernel Params configuration was completely rewritten to be based on controllers and resources,\nwhich makes it possible to apply `.machine.sysctls` in immediate mode (without a reboot).\n`talosctl get kernelparams` returns merged list of KSPP, Kubernetes and user defined params along with\nthe default values overwritten by Talos.\n\n\n### Equinix Metal\n\nAdded support for Equinix Metal IPs for the Talos virtual (shared) IP (option `equnixMetal` under `vip` in the machine configuration).\nTalos automatically re-assigns IP using the Equinix Metal API when leadership changes.\n\n\n### etcd\n\nNew etcd cluster members are now joined in [learner mode](https://etcd.io/docs/v3.4/learning/design-learner/), which improves cluster resiliency\nto member join issues.\n\n\n### Join Node Type\n\nNode type `join` was renamed to `worker` for clarity. The old value is still accepted in the machine configuration but deprecated.\n`talosctl gen config` now generates `worker.yaml` instead of `join.yaml`.\n\n\n### Networking\n\n* multiple static addresses can be specified for the interface with new `.addresses` field (old `.cidr` field is deprecated now)\n* static addresses can be set on interfaces configured with DHCP\n\n\n### Performance\n\n* machined uses less memory and CPU time\n* more disk encryption options are exposed via the machine configuration\n* disk partitions are now aligned properly with minimum I/O size\n* Talos system processes are moved under proper cgroups, resource metrics are now available via the kubelet\n* OOM score is set on the system processes making sure they are killed last under memory pressure\n\n\n### Security\n\n* etcd PKI moved to `/system/secrets`\n* kubelet bootstrap CSR auto-signing scoped to kubelet bootstrap tokens only\n* enforce default seccomp profile on all system containers\n* run system services apid, trustd, and etcd as non-root users\n\n\n### Component Updates\n\n* Linux: 5.10.57\n* Kubernetes: 1.22.0\n* containerd: 1.5.5\n* runc: 1.0.1\n* GRUB: 2.06\n* Talos is built with Go 1.16.7\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Andrey Smirnov\n* Serge Logvinov\n* Artem Chernyshev\n* Spencer Smith\n* Alexey Palazhchenko\n* dependabot[bot]\n* Andrew Rynhard\n* Artem Chernyshev\n* Rui Lopes\n* Caleb Woodbine\n* Seán C McCord\n\n### Changes\n<details><summary>109 commits</summary>\n<p>\n\n* [`1ed5e545`](https://github.com/talos-systems/talos/commit/1ed5e545385e160fe3b61e6dbbcaa8a701437b62) feat: add ClusterID and ClusterSecret\n* [`228b3761`](https://github.com/talos-systems/talos/commit/228b376163597cd825e4a142e6b4bdea0f870365) chore: run etcd as non-root user\n* [`3518219b`](https://github.com/talos-systems/talos/commit/3518219bff44f71a60ad8e448e518844d1b933fd) chore: drop deprecated `--no-reboot` param and KernelCurrentRoot const\n* [`33d1c3e4`](https://github.com/talos-systems/talos/commit/33d1c3e42582649f25a44fc3c86007bcebbc80b3) chore: run apid and trustd services as non-root user\n* [`dadaa65d`](https://github.com/talos-systems/talos/commit/dadaa65d542171d25317840fcf35fa3979cf0632) feat: print uid/gid for the files in `ls -l`\n* [`e6fa401b`](https://github.com/talos-systems/talos/commit/e6fa401b663d0ebd4374c9e47a7ca6150a4756cd) fix: enable seccomp default profile by default\n* [`8ddbcc96`](https://github.com/talos-systems/talos/commit/8ddbcc9643113c15de538fc070b7053d1c6efdfc) feat: validate if extra fields present in the decoder\n* [`5b57a980`](https://github.com/talos-systems/talos/commit/5b57a98008c64d7cb07729fd9b31a0e3493c289c) chore: update Go to 1.16.7, Linux to 5.10.57\n* [`eefe1c21`](https://github.com/talos-systems/talos/commit/eefe1c21c30fa2cd281fc5524b2e88553f6fdfcc) feat: add new etcd members in learner mode\n* [`b1c66fba`](https://github.com/talos-systems/talos/commit/b1c66fbad113400729cf4db806e30192bf7e0462) feat: implement Equinix Metal support for virtual (shared) IP\n* [`62242f97`](https://github.com/talos-systems/talos/commit/62242f979e1921ed8abfa06a26564ea0bf8a5fb3) chore: require GPG signatures\n* [`faecae44`](https://github.com/talos-systems/talos/commit/faecae44fde60fc626ccb01da3b221519a9d41d7) feat: make ISO builds reproducible\n* [`887c2326`](https://github.com/talos-systems/talos/commit/887c2326a4f81c846e3aa3bd1787bc840877e494) release(v0.12.0-alpha.0): prepare release\n* [`a15f0184`](https://github.com/talos-systems/talos/commit/a15f01844fdaf0d3e2dad2750d9353d03e18dea2) fix: move etcd PKI under /system/secrets\n* [`eb02afe1`](https://github.com/talos-systems/talos/commit/eb02afe18be63bf483a0467f655611561aef10f6) fix: match correctly routes on the address family\n* [`cb948acc`](https://github.com/talos-systems/talos/commit/cb948accfeca13c57b3b512dc8a06425989294f9) feat: allow multiple addresses per interface\n* [`e030b2e8`](https://github.com/talos-systems/talos/commit/e030b2e8bb0a65abf4e1f7b5f27348631210ebc4) chore: use k8s 1.21.3 in CAPI tests for now\n* [`e08b4f8f`](https://github.com/talos-systems/talos/commit/e08b4f8f9e72f8db1116b4bbe395d49b4bccb460) feat: implement sysctl controllers\n* [`fdf6b243`](https://github.com/talos-systems/talos/commit/fdf6b2433c40613bcb039852a96196dbe9b7b5e2) chore: revert \"improve artifacts generation reproducibility\"\n* [`b68ed1eb`](https://github.com/talos-systems/talos/commit/b68ed1eb896039ec1319db2e3d6d364034c86863) fix: make route resources ID match closer routing table primary key\n* [`585f6337`](https://github.com/talos-systems/talos/commit/585f633710abb7a6d863b54c37aa65c50a3c7312) fix: correctly handle nodoc for struct fields\n* [`f2d394dc`](https://github.com/talos-systems/talos/commit/f2d394dc42f9ec704050db0a8a928a889483ce3e) docs: add AMIs for v0.11.5\n* [`d0970cbf`](https://github.com/talos-systems/talos/commit/d0970cbfd696b28b201b232a03da2119f664afbd) feat: bootstrap token limit\n* [`5285a46d`](https://github.com/talos-systems/talos/commit/5285a46d78ef2fc76594aad4ad4acb75312bc0a7) fix: maintenance mode reason message\n* [`009d15e8`](https://github.com/talos-systems/talos/commit/009d15e8dc6e75eca6b5963dddf8063941099f14) chore: use etcd client TryLock function on upgrade\n* [`4dae9ea5`](https://github.com/talos-systems/talos/commit/4dae9ea55c087c28a9d7a8d241e0ec3a7a1b8ca3) chore: use vtprotobuf compiled marshaling in Talos API\n* [`7ca5749a`](https://github.com/talos-systems/talos/commit/7ca5749ad4267701ce639d0f0d91c10a7f9c1d3d) chore: bump dependencies via dependabot\n* [`b2507b41`](https://github.com/talos-systems/talos/commit/b2507b41d250b989b9c13ad23e16202cd53a18d2) chore: improve artifacts generation reproducibility\n* [`1f7dad23`](https://github.com/talos-systems/talos/commit/1f7dad234b480c7a5e3484ccf10180747c979036) chore: update PKGS version (512 cpus, new ca-certficates)\n* [`1a2e78a2`](https://github.com/talos-systems/talos/commit/1a2e78a24e997241c4cd18dfac3c2d971ba78116) fix: update go-blockdevice\n* [`6d6ed117`](https://github.com/talos-systems/talos/commit/6d6ed1170f3f28e7f559ccdf64e7c34dfee022a0) chore: use parallel xz with higher compression level\n* [`571f7db1`](https://github.com/talos-systems/talos/commit/571f7db1bb44a0dcb5e373f9c37396d50eb0e8f4) chore: workaround GitHub new release notes limit\n* [`09d70b7e`](https://github.com/talos-systems/talos/commit/09d70b7eafb18343eb4ca57d7f8b84e4ccd2fcfb) feat: update Kubernetes to v1.22.0\n* [`f25f10e7`](https://github.com/talos-systems/talos/commit/f25f10e73ec534acd7cc483f254d612d8a7c1858) feat: add an option to disable PSP\n* [`7c6e4cf2`](https://github.com/talos-systems/talos/commit/7c6e4cf230ba1f30da664374c41c934d1e6620bc) feat: allow both DHCP and static addressing for the interface\n* [`3c566dbc`](https://github.com/talos-systems/talos/commit/3c566dbc30595467a3789707c6e993aa92f36df6) fix: remove admission plugins enabled by default from the list\n* [`69ead373`](https://github.com/talos-systems/talos/commit/69ead37353b7e3aa7f089c70073037a6eba37767) fix: preserve PMBR bootable flag correctly\n* [`dee63051`](https://github.com/talos-systems/talos/commit/dee63051702d49f495bfb28b4be74ed8b39143ad) fix: align partitions with minimal I/O size\n* [`62890229`](https://github.com/talos-systems/talos/commit/628902297d2efe93e6388377b2ea6d4beda83095) feat: update GRUB to 2.06\n* [`b9d04928`](https://github.com/talos-systems/talos/commit/b9d04928d960f9d576671c6f3511cf242ff31cb7) feat: move system processes to cgroups\n* [`0b8681b4`](https://github.com/talos-systems/talos/commit/0b8681b4b49ab109b8863792d48c2f551d1ceeb5) fix: resolve several issues with Wireguard link specs\n* [`f8f4bf3b`](https://github.com/talos-systems/talos/commit/f8f4bf3baef31d4ac957ec68cd869adea1e931cd) docs: add disk encryptions examples\n* [`79b8fa64`](https://github.com/talos-systems/talos/commit/79b8fa64b9453917860faae3df5d14647186b9ba) feat: update containerd to 1.5.5\n* [`539f4209`](https://github.com/talos-systems/talos/commit/539f42090e436921a23087296cde6eaf7e495b5e) chore: bump dependencies via dependabot\n* [`0c7ce1cd`](https://github.com/talos-systems/talos/commit/0c7ce1cd814354213a1a6c7a9251b166ee58c493) feat: remove remnants of bootkube support\n* [`d4f9804f`](https://github.com/talos-systems/talos/commit/d4f9804f8659562f6152ae73cb1788f6f6d6ad89) chore: fix typos\n* [`5f027615`](https://github.com/talos-systems/talos/commit/5f027615ffac68e0a484a5da4827a6589bae3880) feat: expose more encryption options to the machine config\n* [`585152a0`](https://github.com/talos-systems/talos/commit/585152a0be051accd4cb8b7c2f130c5a92dfd32d) chore: bump dependencies\n* [`fc66ec59`](https://github.com/talos-systems/talos/commit/fc66ec59691fb1b9d00b27e1f7b34c870a09d717) feat: set oom score for main processes\n* [`df54584a`](https://github.com/talos-systems/talos/commit/df54584a33d88de13deadcb87a5cfa9c1f9b3961) fix: drop linux capabilities\n* [`f65d0b73`](https://github.com/talos-systems/talos/commit/f65d0b739bd36a57979f9bf26c3092ac544e607c) docs: add 0.11.3 AMIs\n* [`7332d636`](https://github.com/talos-systems/talos/commit/7332d63695074dd5eef35ad545d48aff857fbde8) fix: bump pkgs for new kernel 5.10.52\n* [`70d2505b`](https://github.com/talos-systems/talos/commit/70d2505b7c8807cb5d4f8a017f9f6200757e13e0) fix: do not require ToVersion to be set when detecting version\n* [`0953b199`](https://github.com/talos-systems/talos/commit/0953b1998579f855adffff4b83db917f26687a7b) chore: update extras to bring a new CNI bundle\n* [`b6c47f86`](https://github.com/talos-systems/talos/commit/b6c47f866a57bafb60f85fb1ce10428ed3f52c4a) fix: set the /etc/os-release HOME_URL parameter\n* [`c780821d`](https://github.com/talos-systems/talos/commit/c780821d0b8fda0b3ef6d33b63b595e40970a897) feat: update containerd to 1.5.3, runc to 1.0.1\n* [`f8f1c83a`](https://github.com/talos-systems/talos/commit/f8f1c83a757f5a729896174f95f83c6d804d4858) feat: detect the lowest Kubernetes version in upgrade-k8s CLI command\n* [`55e17ccd`](https://github.com/talos-systems/talos/commit/55e17ccdd1df789466ccfb0c9cfe55a62b437f77) chore: bump dependencies\n* [`da6f786c`](https://github.com/talos-systems/talos/commit/da6f786cab80cbacb886d34b7c5e0ed957cc24c9) fix: kuberentes => kubernetes typo\n* [`2e463348`](https://github.com/talos-systems/talos/commit/2e463348b26fb8b36657b8cb6871e4bce8030b0b) fix: pass all logs through the options.Log method\n* [`4e9c5afb`](https://github.com/talos-systems/talos/commit/4e9c5afb6dd6bdedb4032b7cf4a24b6f1bf88144) fix: make ethtool optional in link status controller\n* [`bf61c2cc`](https://github.com/talos-systems/talos/commit/bf61c2cc4a51d290fe98aaeb80224bdd52bb7ac5) fix: write upgrade logs only to the LogOutput if it's defined\n* [`9c73257c`](https://github.com/talos-systems/talos/commit/9c73257cb128a76459b7d4442b56a50feed089d6) feat: update Go to 1.16.6\n* [`23ef1d40`](https://github.com/talos-systems/talos/commit/23ef1d40af44b873d60337d691f878e2cfe0fe8d) chore: add ability to redirect talos upgrade module logs to io.Writer\n* [`33e9d6c9`](https://github.com/talos-systems/talos/commit/33e9d6c984f82af24ad79e002758841935e60a6a) chore: bump github.com/aws/aws-sdk-go in /hack/cloud-image-uploader\n* [`604434c4`](https://github.com/talos-systems/talos/commit/604434c43eb63aa760cd2176aa1041b653c9bd75) chore: bump github.com/prometheus/procfs from 0.6.0 to 0.7.0\n* [`2ea28f62`](https://github.com/talos-systems/talos/commit/2ea28f62d8dcac3280d7a133ae6532f3ca5709cc) chore: bump node from 16.3.0-alpine to 16.4.2-alpine\n* [`b358a189`](https://github.com/talos-systems/talos/commit/b358a189bcbaa480d1bb3fbcc58eecd1b61f447d) fix: correctly pick route scope for link-local destination\n* [`6848d431`](https://github.com/talos-systems/talos/commit/6848d431427636e415436cdda95543a9a0da5676) feat: can change clusterdns ip lists\n* [`72b76abf`](https://github.com/talos-systems/talos/commit/72b76abfd43d04aa7a9283669925bd49498dc05f) fix: workaround issues when IPv6 is fully or partially disabled\n* [`679b08f4`](https://github.com/talos-systems/talos/commit/679b08f4fabd098311786551e75e38c2a027bd31) docs: update docs for 0.12\n* [`6fbec9e0`](https://github.com/talos-systems/talos/commit/6fbec9e0cb656f411cceb986560473b1a40b6a45) fix: cache etcd client used for healthchecks\n* [`eea750de`](https://github.com/talos-systems/talos/commit/eea750de2c11a9883f343c65a36e30712b987f89) chore: rename \"join\" type to \"worker\"\n* [`951493ac`](https://github.com/talos-systems/talos/commit/951493ac8356a414ff85fce25e30e4bd808b412c) docs: update what's new for Talos 0.11\n* [`b47d1098`](https://github.com/talos-systems/talos/commit/b47d1098b1f1cbd21c501266ffc4a38711ed213f) docs: promote 0.11 docs to be the latest\n* [`d930a265`](https://github.com/talos-systems/talos/commit/d930a26502759cebccb05d9b78741e1fc147b30b) chore: implement DeepCopy for machine configuration\n* [`fe4ed3c7`](https://github.com/talos-systems/talos/commit/fe4ed3c734e5713b2fa1d639bd80bffc7888d7e7) chore: ignore tags which don't look like semantic version\n* [`b969e772`](https://github.com/talos-systems/talos/commit/b969e7720ebcb0103e94494533d819a91dba59f5) chore: update references to old protobuf package\n* [`2ba8ac9a`](https://github.com/talos-systems/talos/commit/2ba8ac9ab4b24572512c2a877acd26b912b5423a) docs: add documentation directory for 0.12\n* [`011e2885`](https://github.com/talos-systems/talos/commit/011e2885e7f88a3a92f3f495fdc1d3be6ed0c877) fix: validate bond slaves addressing\n* [`10c28758`](https://github.com/talos-systems/talos/commit/10c28758a4fc50a5e5a29097769b4a3a92ed249a) fix: ignore DeadlineExceeded error correctly on bootstrap\n* [`77fabace`](https://github.com/talos-systems/talos/commit/77fabaceca242f89949d4bf231e9754b4d04eb5e) chore: ignore future pkg/machinery/vX.Y.Z tags\n* [`6b661114`](https://github.com/talos-systems/talos/commit/6b661114d03a7cd1ddd8939ea323d4fe2ce9976c) fix: make COSI runtime history depth smaller\n* [`9bf899bd`](https://github.com/talos-systems/talos/commit/9bf899bdd852befbb4aa5ac4f3ceecb3c33502c8) fix: make forfeit leadership connect to the right node\n* [`4708beae`](https://github.com/talos-systems/talos/commit/4708beaee53e3aacbeec07c38cdd2c7316d16a4c) feat: implement `talosctl config info` command\n* [`6d13d2cf`](https://github.com/talos-systems/talos/commit/6d13d2cf9243adce739673f1982cbc1f12252ef1) fix: close Kubernetes API client\n* [`aaa36f3b`](https://github.com/talos-systems/talos/commit/aaa36f3b4fb250d2921f35c09bcb01b6c31ad423) fix: ignore 'not a leader' error on forfeit leadership\n* [`22a41936`](https://github.com/talos-systems/talos/commit/22a4193678d2245b4c24b7e173d4cfd5fa876e95) fix: workaround 'Unauthorized' errors when accessing Kubernetes API\n* [`71c6f700`](https://github.com/talos-systems/talos/commit/71c6f7004e28c8a72410652d7d38f770bcf8a5f8) chore: bump go.mod dependencies\n* [`915cd8fe`](https://github.com/talos-systems/talos/commit/915cd8fe20c55112cc1fa7776c115ac85c7f3da9) docs: add guide for RBAC\n* [`f5721050`](https://github.com/talos-systems/talos/commit/f5721050deffe61f892a9fca2d20b3fccb5021a6) fix: controlplane keyusage\n* [`3d772661`](https://github.com/talos-systems/talos/commit/3d7726613ca5c5e6b14b4854564d71ee3644d32e) fix: fill uuid argument correctly in the config download URL\n* [`d8602025`](https://github.com/talos-systems/talos/commit/d8602025c828189fa15350a15bf3ccefe39bd0ce) chore: update containerd config version 2\n* [`5949ec4e`](https://github.com/talos-systems/talos/commit/5949ec4e6e05ada904d69a24c9d21e20cc7dea85) docs: describe the new network configuration subsystem\n* [`444d72b4`](https://github.com/talos-systems/talos/commit/444d72b4d7cff7b38c8e3a483bbe10c74251448a) feat: update pkgs version\n* [`e883c12b`](https://github.com/talos-systems/talos/commit/e883c12b31e2ddc3860abc04e7c0867701f46026) fix: make output of `upgrade-k8s` command less scary\n* [`7f8e50de`](https://github.com/talos-systems/talos/commit/7f8e50de4d9a36dae9de7783d71a981fb6a72854) fix: restart the merge controllers on conflict\n* [`60d73609`](https://github.com/talos-systems/talos/commit/60d7360944ff6fc1e75f98e37a754f3bb2962144) fix: ignore deadline exceeded errors on bootstrap\n* [`ee06dd69`](https://github.com/talos-systems/talos/commit/ee06dd69fc39d5df720a88991caaf3646c6fa349) fix: don't print git sha of the release twice in the dashboard\n* [`07fb61e5`](https://github.com/talos-systems/talos/commit/07fb61e5d22da86b434d30f12b84b845ac1a4df7) fix: issue worker apid certs properly on renewal\n* [`84817f73`](https://github.com/talos-systems/talos/commit/84817f733458cbd35549eebc72df6a5df202b299) chore: bump Talos version in upgrade tests\n* [`2fa54107`](https://github.com/talos-systems/talos/commit/2fa54107b2c84cabe948ace5d70836dd4be95799) chore: fix tests for disabled RBAC\n* [`78583ba9`](https://github.com/talos-systems/talos/commit/78583ba985fa2b90ec610d148b2cbeb0b92d646b) fix: don't set bond delay options if miimon is not enabled\n* [`bbf1c091`](https://github.com/talos-systems/talos/commit/bbf1c091d4cea0b4610bce7165a98c7572423b01) feat: add RBAC to `talosctl version` output\n* [`5f6ec3ef`](https://github.com/talos-systems/talos/commit/5f6ec3ef66c8bf2cb334e02b5aa9869330c985d8) fix: handle cases when merged resource re-appears before being destroyed\n* [`1e9a0e74`](https://github.com/talos-systems/talos/commit/1e9a0e745db73bd45ec0881aa19e43d7badb5914) fix: documentation typos\n* [`f228af40`](https://github.com/talos-systems/talos/commit/f228af4061e2025531c953fdb7f8bf83de4bf8b0) chore: bump go.mod dependencies\n* [`2060ceaa`](https://github.com/talos-systems/talos/commit/2060ceaa0b16be04a61a00e0085e25889ffe613a) chore: add CAPI version to CI setup\n* [`ad047a7d`](https://github.com/talos-systems/talos/commit/ad047a7dee4c0ac26c01862bdaa923fab93cc2e1) chore: small RBAC improvements\n</p>\n</details>\n\n### Changes since v0.12.0-alpha.0\n<details><summary>12 commits</summary>\n<p>\n\n* [`1ed5e545`](https://github.com/talos-systems/talos/commit/1ed5e545385e160fe3b61e6dbbcaa8a701437b62) feat: add ClusterID and ClusterSecret\n* [`228b3761`](https://github.com/talos-systems/talos/commit/228b376163597cd825e4a142e6b4bdea0f870365) chore: run etcd as non-root user\n* [`3518219b`](https://github.com/talos-systems/talos/commit/3518219bff44f71a60ad8e448e518844d1b933fd) chore: drop deprecated `--no-reboot` param and KernelCurrentRoot const\n* [`33d1c3e4`](https://github.com/talos-systems/talos/commit/33d1c3e42582649f25a44fc3c86007bcebbc80b3) chore: run apid and trustd services as non-root user\n* [`dadaa65d`](https://github.com/talos-systems/talos/commit/dadaa65d542171d25317840fcf35fa3979cf0632) feat: print uid/gid for the files in `ls -l`\n* [`e6fa401b`](https://github.com/talos-systems/talos/commit/e6fa401b663d0ebd4374c9e47a7ca6150a4756cd) fix: enable seccomp default profile by default\n* [`8ddbcc96`](https://github.com/talos-systems/talos/commit/8ddbcc9643113c15de538fc070b7053d1c6efdfc) feat: validate if extra fields present in the decoder\n* [`5b57a980`](https://github.com/talos-systems/talos/commit/5b57a98008c64d7cb07729fd9b31a0e3493c289c) chore: update Go to 1.16.7, Linux to 5.10.57\n* [`eefe1c21`](https://github.com/talos-systems/talos/commit/eefe1c21c30fa2cd281fc5524b2e88553f6fdfcc) feat: add new etcd members in learner mode\n* [`b1c66fba`](https://github.com/talos-systems/talos/commit/b1c66fbad113400729cf4db806e30192bf7e0462) feat: implement Equinix Metal support for virtual (shared) IP\n* [`62242f97`](https://github.com/talos-systems/talos/commit/62242f979e1921ed8abfa06a26564ea0bf8a5fb3) chore: require GPG signatures\n* [`faecae44`](https://github.com/talos-systems/talos/commit/faecae44fde60fc626ccb01da3b221519a9d41d7) feat: make ISO builds reproducible\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`deec8d4`](https://github.com/talos-systems/crypto/commit/deec8d47700e10e3ea813bdce01377bd93c83367) chore: implement DeepCopy methods for PEMEncoded* types\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`8ce17e5`](https://github.com/talos-systems/extras/commit/8ce17e5e5d60dce7b46cf87555400f7951fe9fda) chore: bump tools and packages for Go 1.16.7\n* [`4957f3c`](https://github.com/talos-systems/extras/commit/4957f3c64bc5fd1574fe3d3f251f52e914e78e41) chore: update pkgs to use CNI plugins v0.9.1\n* [`233716a`](https://github.com/talos-systems/extras/commit/233716a04f1e4e1762101b279308630caa46d17d) feat: update Go to 1.16.6\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>4 commits</summary>\n<p>\n\n* [`fe24303`](https://github.com/talos-systems/go-blockdevice/commit/fe2430349e9d734ce6dbf4e7b2e0f8a37bb22679) fix: perform correct PMBR partition calculations\n* [`2ec0c3c`](https://github.com/talos-systems/go-blockdevice/commit/2ec0c3cc0ff5ff705ed5c910ca1bcd5d93c7b102) fix: preserve the PMBR bootable flag when opening GPT partition\n* [`87816a8`](https://github.com/talos-systems/go-blockdevice/commit/87816a81cefc728cfe3cb221b476d8ed4b609fd8) feat: align partition to minimum I/O size\n* [`c34b59f`](https://github.com/talos-systems/go-blockdevice/commit/c34b59fb33a7ad8be18bb19bc8c8d8294b4b3a78) feat: expose more encryption options in the LUKS module\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>17 commits</summary>\n<p>\n\n* [`da4ac04`](https://github.com/talos-systems/pkgs/commit/da4ac04969924256df4ebc66d3bf435a52e30cb7) chore: bump tools for Go 1.16.7\n* [`10275fb`](https://github.com/talos-systems/pkgs/commit/10275fbf737aaa0ac41cc7220d824f5d68d3b0fa) feat: update Linux to 5.10.57\n* [`875c7ec`](https://github.com/talos-systems/pkgs/commit/875c7ecaacc9e999416a2ba17bea3130261120eb) chore: patch grub with support for reproducible ISO builds\n* [`12856ce`](https://github.com/talos-systems/pkgs/commit/12856ce15d6d72814a2f40bbaf3f8ab6efb849f9) feat: increase number of CPUs supported by the kernel to 512\n* [`cbfabac`](https://github.com/talos-systems/pkgs/commit/cbfabaca6a3faf20914aae5c535e44a393a4f422) chore: update ca-certificates to 2021-07-05\n* [`0c011c0`](https://github.com/talos-systems/pkgs/commit/0c011c088068e5fdb55066008b526ca3ef69f218) feat: update GRUB to 2.06\n* [`5090d14`](https://github.com/talos-systems/pkgs/commit/5090d149a669f7eb3cc922196b7e82869c152dae) chore: update containerd to v1.5.5\n* [`6653902`](https://github.com/talos-systems/pkgs/commit/66539021daf1037782b1c4009dd96544057628d3) feat: add kernel drivers for fusion and scsi-isci\n* [`9b4041f`](https://github.com/talos-systems/pkgs/commit/9b4041fb79d9c5d8e18391f1e2f4843a88d26c19) chore: update containerd to v1.5.4\n* [`7b6cc05`](https://github.com/talos-systems/pkgs/commit/7b6cc05ceee8c24e746afa7ed105f9f55fef589b) feat: update kernel to latest 5.10.52\n* [`65159fb`](https://github.com/talos-systems/pkgs/commit/65159fb19c3138ec612cdca507e5cc795b657a7d) chore: update runc and CNI plugins\n* [`514ba34`](https://github.com/talos-systems/pkgs/commit/514ba3420a0773ac7305d00e8b582858f9685953) feat: disable aufs, devmapper, zfs\n* [`6bc118f`](https://github.com/talos-systems/pkgs/commit/6bc118f37cfd018183952b9feb009c54f1a3c215) chore: update runc and containerd\n* [`b6fca88`](https://github.com/talos-systems/pkgs/commit/b6fca88d22436a0fb78b8a4e06792b7af1a22ef5) feat: update Go to 1.16.6\n* [`fd56852`](https://github.com/talos-systems/pkgs/commit/fd568520e8c77bd8d96f96efb47dd2bdd2f36c1a) chore: update `open-isns` and `open-iscsi`\n* [`d779204`](https://github.com/talos-systems/pkgs/commit/d779204c0d9e9c8e90f32b1f68eb9ff4b030b83c) chore: update dosfstools to v4.2\n* [`bc7c0d7`](https://github.com/talos-systems/pkgs/commit/bc7c0d7c6afaec8226c2a52299981ac519b5e595) feat: add support for hotplug of PCIE devices\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`2368154`](https://github.com/talos-systems/tools/commit/23681542fc7e29ede59b3775e04089c5b1a0f666) feat: update Go and protoc-gen-go tools\n* [`7172a5d`](https://github.com/talos-systems/tools/commit/7172a5db9d361527aa7bd9c7af407b9d578e2e02) feat: update Go to 1.16.6\n* [`1de34d7`](https://github.com/talos-systems/tools/commit/1de34d7961c7ac86f369217dea4ce69cdde04122) chore: update musl\n* [`76979a1`](https://github.com/talos-systems/tools/commit/76979a1c194c74c25db22c9ec90ec36f97179e3f) chore: update protobuf deps\n* [`0846c64`](https://github.com/talos-systems/tools/commit/0846c6493316b5d00ecc241b7051ced1bac1cf7e) chore: update expat\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/BurntSushi/toml**               v0.3.1 -> v0.4.1\n* **github.com/aws/aws-sdk-go**                v1.38.66 -> v1.40.2\n* **github.com/containerd/containerd**         v1.5.2 -> v1.5.5\n* **github.com/cosi-project/runtime**          93ead370bf57 -> 25f235cd0682\n* **github.com/docker/docker**                 v20.10.7 -> v20.10.8\n* **github.com/google/uuid**                   v1.2.0 -> v1.3.0\n* **github.com/hashicorp/go-getter**           v1.5.4 -> v1.5.6\n* **github.com/opencontainers/runtime-spec**   e6143ca7d51d -> 1c3f411f0417\n* **github.com/packethost/packngo**            v0.19.0 **_new_**\n* **github.com/prometheus/procfs**             v0.6.0 -> v0.7.2\n* **github.com/rivo/tview**                    d4fb0348227b -> 29d673af0ce2\n* **github.com/spf13/cobra**                   v1.1.3 -> v1.2.1\n* **github.com/talos-systems/crypto**          v0.3.1 -> deec8d47700e\n* **github.com/talos-systems/extras**          v0.4.0 -> v0.5.0-alpha.0-2-g8ce17e5\n* **github.com/talos-systems/go-blockdevice**  v0.2.1 -> v0.2.3\n* **github.com/talos-systems/pkgs**            v0.6.0-1-g7b2e126 -> v0.7.0-alpha.0-16-gda4ac04\n* **github.com/talos-systems/tools**           v0.6.0 -> v0.7.0-alpha.0-3-g2368154\n* **github.com/vmware-tanzu/sonobuoy**         v0.52.0 -> v0.53.0\n* **go.uber.org/zap**                          v1.17.0 -> v1.18.1\n* **golang.org/x/net**                         04defd469f4e -> 853a461950ff\n* **golang.org/x/sys**                         59db8d763f22 -> 0f9fa26af87c\n* **golang.org/x/time**                        38a9dc6acbc6 -> 1f47c861a9ac\n* **google.golang.org/grpc**                   v1.38.0 -> v1.39.1\n* **google.golang.org/protobuf**               v1.26.0 -> v1.27.1\n* **inet.af/netaddr**                          bf05d8b52dda -> ce7a8ad02cc1\n* **k8s.io/api**                               v0.21.2 -> v0.22.0\n* **k8s.io/apimachinery**                      v0.21.2 -> v0.22.0\n* **k8s.io/apiserver**                         v0.21.2 -> v0.22.0\n* **k8s.io/client-go**                         v0.21.2 -> v0.22.0\n* **k8s.io/cri-api**                           v0.21.2 -> v0.22.0\n* **k8s.io/kubectl**                           v0.21.2 -> v0.22.0\n* **k8s.io/kubelet**                           v0.21.2 -> v0.22.0\n\nPrevious release can be found at [v0.11.0](https://github.com/talos-systems/talos/releases/tag/v0.11.0)\n\n## [Talos 0.12.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.12.0-alpha.0) (2021-08-11)\n\nWelcome to the v0.12.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Support for Self-hosted Control Plane Dropped\n\n> **Note**: This item only applies to clusters bootstrapped with Talos <= 0.8.\n\nTalos 0.12 completely removes support for self-hosted Kubernetes control plane (bootkube-based).\nTalos 0.9 introduced support for Talos-managed control plane and provided migration path to convert self-hosted control plane\nto Talos-managed static pods.\nAutomated and manual conversion process is available in Talos from 0.9.x to 0.11.x.\nFor clusters bootstrapped with bootkube (Talos <= 0.8), please make sure control plane is converted to Talos-managed before\nbefore upgrading to Talos 0.12.\nCurrent control plane status can be checked with `talosctl get bootstrapstatus` before performing upgrade to Talos 0.12.\n\n\n### Cluster API v0.3.x\n\nCluster API v0.3.x (v1alpha3) is not compatible with Kubernetes 1.22 used by default in Talos 0.12.\nTalos can be configued to use Kubernetes 1.21 or CAPI v0.4.x components can be used instead.\n\n\n### Sysctl Configuration\n\nSysctl Kernel Params configuration was completely rewritten to be based on controllers and resources,\nwhich makes it possible to apply `.machine.sysctls` in immediate mode (without a reboot).\n`talosctl get kernelparams` returns merged list of KSPP, Kubernetes and user defined params along with\nthe default values overwritten by Talos.\n\n\n### Join Node Type\n\nNode type `join` was renamed to `worker` for clarity. The old value is still accepted in the machine configuration but deprecated.\n`talosctl gen config` now generates `worker.yaml` instead of `join.yaml`.\n\n\n### Networking\n\n* multiple static addresses can be specified for the interface with new `.addresses` field (old `.cidr` field is deprecated now)\n* static addresses can be set on interfaces configured with DHCP\n\n\n### Performance\n\n* machined uses less memory and CPU time\n* more disk encryption options are exposed via the machine configuration\n* disk partitions are now aligned properly with minimum I/O size\n* Talos system processes are moved under proper cgroups, resource metrics are now available via the kubelet\n* OOM score is set on the system processes making sure they are killed last under memory pressure\n\n\n### Security\n\n* etcd PKI moved to `/system/secrets`\n* kubelet bootstrap CSR auto-signing scoped to kubelet bootstrap tokens only\n\n\n### Component Updates\n\n* Linux: 5.10.52\n* Kubernetes: 1.22.0\n* containerd: 1.5.5\n* runc: 1.0.1\n* GRUB: 2.06\n* Talos is built with Go 1.16.6\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Serge Logvinov\n* Andrey Smirnov\n* Artem Chernyshev\n* Spencer Smith\n* Alexey Palazhchenko\n* dependabot[bot]\n* Rui Lopes\n* Andrew Rynhard\n* Caleb Woodbine\n\n### Changes\n<details><summary>96 commits</summary>\n<p>\n\n* [`a15f0184`](https://github.com/talos-systems/talos/commit/a15f01844fdaf0d3e2dad2750d9353d03e18dea2) fix: move etcd PKI under /system/secrets\n* [`eb02afe1`](https://github.com/talos-systems/talos/commit/eb02afe18be63bf483a0467f655611561aef10f6) fix: match correctly routes on the address family\n* [`cb948acc`](https://github.com/talos-systems/talos/commit/cb948accfeca13c57b3b512dc8a06425989294f9) feat: allow multiple addresses per interface\n* [`e030b2e8`](https://github.com/talos-systems/talos/commit/e030b2e8bb0a65abf4e1f7b5f27348631210ebc4) chore: use k8s 1.21.3 in CAPI tests for now\n* [`e08b4f8f`](https://github.com/talos-systems/talos/commit/e08b4f8f9e72f8db1116b4bbe395d49b4bccb460) feat: implement sysctl controllers\n* [`fdf6b243`](https://github.com/talos-systems/talos/commit/fdf6b2433c40613bcb039852a96196dbe9b7b5e2) chore: revert \"improve artifacts generation reproducibility\"\n* [`b68ed1eb`](https://github.com/talos-systems/talos/commit/b68ed1eb896039ec1319db2e3d6d364034c86863) fix: make route resources ID match closer routing table primary key\n* [`585f6337`](https://github.com/talos-systems/talos/commit/585f633710abb7a6d863b54c37aa65c50a3c7312) fix: correctly handle nodoc for struct fields\n* [`f2d394dc`](https://github.com/talos-systems/talos/commit/f2d394dc42f9ec704050db0a8a928a889483ce3e) docs: add AMIs for v0.11.5\n* [`d0970cbf`](https://github.com/talos-systems/talos/commit/d0970cbfd696b28b201b232a03da2119f664afbd) feat: bootstrap token limit\n* [`5285a46d`](https://github.com/talos-systems/talos/commit/5285a46d78ef2fc76594aad4ad4acb75312bc0a7) fix: maintenance mode reason message\n* [`009d15e8`](https://github.com/talos-systems/talos/commit/009d15e8dc6e75eca6b5963dddf8063941099f14) chore: use etcd client TryLock function on upgrade\n* [`4dae9ea5`](https://github.com/talos-systems/talos/commit/4dae9ea55c087c28a9d7a8d241e0ec3a7a1b8ca3) chore: use vtprotobuf compiled marshaling in Talos API\n* [`7ca5749a`](https://github.com/talos-systems/talos/commit/7ca5749ad4267701ce639d0f0d91c10a7f9c1d3d) chore: bump dependencies via dependabot\n* [`b2507b41`](https://github.com/talos-systems/talos/commit/b2507b41d250b989b9c13ad23e16202cd53a18d2) chore: improve artifacts generation reproducibility\n* [`1f7dad23`](https://github.com/talos-systems/talos/commit/1f7dad234b480c7a5e3484ccf10180747c979036) chore: update PKGS version (512 cpus, new ca-certficates)\n* [`1a2e78a2`](https://github.com/talos-systems/talos/commit/1a2e78a24e997241c4cd18dfac3c2d971ba78116) fix: update go-blockdevice\n* [`6d6ed117`](https://github.com/talos-systems/talos/commit/6d6ed1170f3f28e7f559ccdf64e7c34dfee022a0) chore: use parallel xz with higher compression level\n* [`571f7db1`](https://github.com/talos-systems/talos/commit/571f7db1bb44a0dcb5e373f9c37396d50eb0e8f4) chore: workaround GitHub new release notes limit\n* [`09d70b7e`](https://github.com/talos-systems/talos/commit/09d70b7eafb18343eb4ca57d7f8b84e4ccd2fcfb) feat: update Kubernetes to v1.22.0\n* [`f25f10e7`](https://github.com/talos-systems/talos/commit/f25f10e73ec534acd7cc483f254d612d8a7c1858) feat: add an option to disable PSP\n* [`7c6e4cf2`](https://github.com/talos-systems/talos/commit/7c6e4cf230ba1f30da664374c41c934d1e6620bc) feat: allow both DHCP and static addressing for the interface\n* [`3c566dbc`](https://github.com/talos-systems/talos/commit/3c566dbc30595467a3789707c6e993aa92f36df6) fix: remove admission plugins enabled by default from the list\n* [`69ead373`](https://github.com/talos-systems/talos/commit/69ead37353b7e3aa7f089c70073037a6eba37767) fix: preserve PMBR bootable flag correctly\n* [`dee63051`](https://github.com/talos-systems/talos/commit/dee63051702d49f495bfb28b4be74ed8b39143ad) fix: align partitions with minimal I/O size\n* [`62890229`](https://github.com/talos-systems/talos/commit/628902297d2efe93e6388377b2ea6d4beda83095) feat: update GRUB to 2.06\n* [`b9d04928`](https://github.com/talos-systems/talos/commit/b9d04928d960f9d576671c6f3511cf242ff31cb7) feat: move system processes to cgroups\n* [`0b8681b4`](https://github.com/talos-systems/talos/commit/0b8681b4b49ab109b8863792d48c2f551d1ceeb5) fix: resolve several issues with Wireguard link specs\n* [`f8f4bf3b`](https://github.com/talos-systems/talos/commit/f8f4bf3baef31d4ac957ec68cd869adea1e931cd) docs: add disk encryptions examples\n* [`79b8fa64`](https://github.com/talos-systems/talos/commit/79b8fa64b9453917860faae3df5d14647186b9ba) feat: update containerd to 1.5.5\n* [`539f4209`](https://github.com/talos-systems/talos/commit/539f42090e436921a23087296cde6eaf7e495b5e) chore: bump dependencies via dependabot\n* [`0c7ce1cd`](https://github.com/talos-systems/talos/commit/0c7ce1cd814354213a1a6c7a9251b166ee58c493) feat: remove remnants of bootkube support\n* [`d4f9804f`](https://github.com/talos-systems/talos/commit/d4f9804f8659562f6152ae73cb1788f6f6d6ad89) chore: fix typos\n* [`5f027615`](https://github.com/talos-systems/talos/commit/5f027615ffac68e0a484a5da4827a6589bae3880) feat: expose more encryption options to the machine config\n* [`585152a0`](https://github.com/talos-systems/talos/commit/585152a0be051accd4cb8b7c2f130c5a92dfd32d) chore: bump dependencies\n* [`fc66ec59`](https://github.com/talos-systems/talos/commit/fc66ec59691fb1b9d00b27e1f7b34c870a09d717) feat: set oom score for main processes\n* [`df54584a`](https://github.com/talos-systems/talos/commit/df54584a33d88de13deadcb87a5cfa9c1f9b3961) fix: drop linux capabilities\n* [`f65d0b73`](https://github.com/talos-systems/talos/commit/f65d0b739bd36a57979f9bf26c3092ac544e607c) docs: add 0.11.3 AMIs\n* [`7332d636`](https://github.com/talos-systems/talos/commit/7332d63695074dd5eef35ad545d48aff857fbde8) fix: bump pkgs for new kernel 5.10.52\n* [`70d2505b`](https://github.com/talos-systems/talos/commit/70d2505b7c8807cb5d4f8a017f9f6200757e13e0) fix: do not require ToVersion to be set when detecting version\n* [`0953b199`](https://github.com/talos-systems/talos/commit/0953b1998579f855adffff4b83db917f26687a7b) chore: update extras to bring a new CNI bundle\n* [`b6c47f86`](https://github.com/talos-systems/talos/commit/b6c47f866a57bafb60f85fb1ce10428ed3f52c4a) fix: set the /etc/os-release HOME_URL parameter\n* [`c780821d`](https://github.com/talos-systems/talos/commit/c780821d0b8fda0b3ef6d33b63b595e40970a897) feat: update containerd to 1.5.3, runc to 1.0.1\n* [`f8f1c83a`](https://github.com/talos-systems/talos/commit/f8f1c83a757f5a729896174f95f83c6d804d4858) feat: detect the lowest Kubernetes version in upgrade-k8s CLI command\n* [`55e17ccd`](https://github.com/talos-systems/talos/commit/55e17ccdd1df789466ccfb0c9cfe55a62b437f77) chore: bump dependencies\n* [`da6f786c`](https://github.com/talos-systems/talos/commit/da6f786cab80cbacb886d34b7c5e0ed957cc24c9) fix: kuberentes => kubernetes typo\n* [`2e463348`](https://github.com/talos-systems/talos/commit/2e463348b26fb8b36657b8cb6871e4bce8030b0b) fix: pass all logs through the options.Log method\n* [`4e9c5afb`](https://github.com/talos-systems/talos/commit/4e9c5afb6dd6bdedb4032b7cf4a24b6f1bf88144) fix: make ethtool optional in link status controller\n* [`bf61c2cc`](https://github.com/talos-systems/talos/commit/bf61c2cc4a51d290fe98aaeb80224bdd52bb7ac5) fix: write upgrade logs only to the LogOutput if it's defined\n* [`9c73257c`](https://github.com/talos-systems/talos/commit/9c73257cb128a76459b7d4442b56a50feed089d6) feat: update Go to 1.16.6\n* [`23ef1d40`](https://github.com/talos-systems/talos/commit/23ef1d40af44b873d60337d691f878e2cfe0fe8d) chore: add ability to redirect talos upgrade module logs to io.Writer\n* [`33e9d6c9`](https://github.com/talos-systems/talos/commit/33e9d6c984f82af24ad79e002758841935e60a6a) chore: bump github.com/aws/aws-sdk-go in /hack/cloud-image-uploader\n* [`604434c4`](https://github.com/talos-systems/talos/commit/604434c43eb63aa760cd2176aa1041b653c9bd75) chore: bump github.com/prometheus/procfs from 0.6.0 to 0.7.0\n* [`2ea28f62`](https://github.com/talos-systems/talos/commit/2ea28f62d8dcac3280d7a133ae6532f3ca5709cc) chore: bump node from 16.3.0-alpine to 16.4.2-alpine\n* [`b358a189`](https://github.com/talos-systems/talos/commit/b358a189bcbaa480d1bb3fbcc58eecd1b61f447d) fix: correctly pick route scope for link-local destination\n* [`6848d431`](https://github.com/talos-systems/talos/commit/6848d431427636e415436cdda95543a9a0da5676) feat: can change clusterdns ip lists\n* [`72b76abf`](https://github.com/talos-systems/talos/commit/72b76abfd43d04aa7a9283669925bd49498dc05f) fix: workaround issues when IPv6 is fully or partially disabled\n* [`679b08f4`](https://github.com/talos-systems/talos/commit/679b08f4fabd098311786551e75e38c2a027bd31) docs: update docs for 0.12\n* [`6fbec9e0`](https://github.com/talos-systems/talos/commit/6fbec9e0cb656f411cceb986560473b1a40b6a45) fix: cache etcd client used for healthchecks\n* [`eea750de`](https://github.com/talos-systems/talos/commit/eea750de2c11a9883f343c65a36e30712b987f89) chore: rename \"join\" type to \"worker\"\n* [`951493ac`](https://github.com/talos-systems/talos/commit/951493ac8356a414ff85fce25e30e4bd808b412c) docs: update what's new for Talos 0.11\n* [`b47d1098`](https://github.com/talos-systems/talos/commit/b47d1098b1f1cbd21c501266ffc4a38711ed213f) docs: promote 0.11 docs to be the latest\n* [`d930a265`](https://github.com/talos-systems/talos/commit/d930a26502759cebccb05d9b78741e1fc147b30b) chore: implement DeepCopy for machine configuration\n* [`fe4ed3c7`](https://github.com/talos-systems/talos/commit/fe4ed3c734e5713b2fa1d639bd80bffc7888d7e7) chore: ignore tags which don't look like semantic version\n* [`b969e772`](https://github.com/talos-systems/talos/commit/b969e7720ebcb0103e94494533d819a91dba59f5) chore: update references to old protobuf package\n* [`2ba8ac9a`](https://github.com/talos-systems/talos/commit/2ba8ac9ab4b24572512c2a877acd26b912b5423a) docs: add documentation directory for 0.12\n* [`011e2885`](https://github.com/talos-systems/talos/commit/011e2885e7f88a3a92f3f495fdc1d3be6ed0c877) fix: validate bond slaves addressing\n* [`10c28758`](https://github.com/talos-systems/talos/commit/10c28758a4fc50a5e5a29097769b4a3a92ed249a) fix: ignore DeadlineExceeded error correctly on bootstrap\n* [`77fabace`](https://github.com/talos-systems/talos/commit/77fabaceca242f89949d4bf231e9754b4d04eb5e) chore: ignore future pkg/machinery/vX.Y.Z tags\n* [`6b661114`](https://github.com/talos-systems/talos/commit/6b661114d03a7cd1ddd8939ea323d4fe2ce9976c) fix: make COSI runtime history depth smaller\n* [`9bf899bd`](https://github.com/talos-systems/talos/commit/9bf899bdd852befbb4aa5ac4f3ceecb3c33502c8) fix: make forfeit leadership connect to the right node\n* [`4708beae`](https://github.com/talos-systems/talos/commit/4708beaee53e3aacbeec07c38cdd2c7316d16a4c) feat: implement `talosctl config info` command\n* [`6d13d2cf`](https://github.com/talos-systems/talos/commit/6d13d2cf9243adce739673f1982cbc1f12252ef1) fix: close Kubernetes API client\n* [`aaa36f3b`](https://github.com/talos-systems/talos/commit/aaa36f3b4fb250d2921f35c09bcb01b6c31ad423) fix: ignore 'not a leader' error on forfeit leadership\n* [`22a41936`](https://github.com/talos-systems/talos/commit/22a4193678d2245b4c24b7e173d4cfd5fa876e95) fix: workaround 'Unauthorized' errors when accessing Kubernetes API\n* [`71c6f700`](https://github.com/talos-systems/talos/commit/71c6f7004e28c8a72410652d7d38f770bcf8a5f8) chore: bump go.mod dependencies\n* [`915cd8fe`](https://github.com/talos-systems/talos/commit/915cd8fe20c55112cc1fa7776c115ac85c7f3da9) docs: add guide for RBAC\n* [`f5721050`](https://github.com/talos-systems/talos/commit/f5721050deffe61f892a9fca2d20b3fccb5021a6) fix: controlplane keyusage\n* [`3d772661`](https://github.com/talos-systems/talos/commit/3d7726613ca5c5e6b14b4854564d71ee3644d32e) fix: fill uuid argument correctly in the config download URL\n* [`d8602025`](https://github.com/talos-systems/talos/commit/d8602025c828189fa15350a15bf3ccefe39bd0ce) chore: update containerd config version 2\n* [`5949ec4e`](https://github.com/talos-systems/talos/commit/5949ec4e6e05ada904d69a24c9d21e20cc7dea85) docs: describe the new network configuration subsystem\n* [`444d72b4`](https://github.com/talos-systems/talos/commit/444d72b4d7cff7b38c8e3a483bbe10c74251448a) feat: update pkgs version\n* [`e883c12b`](https://github.com/talos-systems/talos/commit/e883c12b31e2ddc3860abc04e7c0867701f46026) fix: make output of `upgrade-k8s` command less scary\n* [`7f8e50de`](https://github.com/talos-systems/talos/commit/7f8e50de4d9a36dae9de7783d71a981fb6a72854) fix: restart the merge controllers on conflict\n* [`60d73609`](https://github.com/talos-systems/talos/commit/60d7360944ff6fc1e75f98e37a754f3bb2962144) fix: ignore deadline exceeded errors on bootstrap\n* [`ee06dd69`](https://github.com/talos-systems/talos/commit/ee06dd69fc39d5df720a88991caaf3646c6fa349) fix: don't print git sha of the release twice in the dashboard\n* [`07fb61e5`](https://github.com/talos-systems/talos/commit/07fb61e5d22da86b434d30f12b84b845ac1a4df7) fix: issue worker apid certs properly on renewal\n* [`84817f73`](https://github.com/talos-systems/talos/commit/84817f733458cbd35549eebc72df6a5df202b299) chore: bump Talos version in upgrade tests\n* [`2fa54107`](https://github.com/talos-systems/talos/commit/2fa54107b2c84cabe948ace5d70836dd4be95799) chore: fix tests for disabled RBAC\n* [`78583ba9`](https://github.com/talos-systems/talos/commit/78583ba985fa2b90ec610d148b2cbeb0b92d646b) fix: don't set bond delay options if miimon is not enabled\n* [`bbf1c091`](https://github.com/talos-systems/talos/commit/bbf1c091d4cea0b4610bce7165a98c7572423b01) feat: add RBAC to `talosctl version` output\n* [`5f6ec3ef`](https://github.com/talos-systems/talos/commit/5f6ec3ef66c8bf2cb334e02b5aa9869330c985d8) fix: handle cases when merged resource re-appears before being destroyed\n* [`1e9a0e74`](https://github.com/talos-systems/talos/commit/1e9a0e745db73bd45ec0881aa19e43d7badb5914) fix: documentation typos\n* [`f228af40`](https://github.com/talos-systems/talos/commit/f228af4061e2025531c953fdb7f8bf83de4bf8b0) chore: bump go.mod dependencies\n* [`2060ceaa`](https://github.com/talos-systems/talos/commit/2060ceaa0b16be04a61a00e0085e25889ffe613a) chore: add CAPI version to CI setup\n* [`ad047a7d`](https://github.com/talos-systems/talos/commit/ad047a7dee4c0ac26c01862bdaa923fab93cc2e1) chore: small RBAC improvements\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`deec8d4`](https://github.com/talos-systems/crypto/commit/deec8d47700e10e3ea813bdce01377bd93c83367) chore: implement DeepCopy methods for PEMEncoded* types\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`4957f3c`](https://github.com/talos-systems/extras/commit/4957f3c64bc5fd1574fe3d3f251f52e914e78e41) chore: update pkgs to use CNI plugins v0.9.1\n* [`233716a`](https://github.com/talos-systems/extras/commit/233716a04f1e4e1762101b279308630caa46d17d) feat: update Go to 1.16.6\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>4 commits</summary>\n<p>\n\n* [`fe24303`](https://github.com/talos-systems/go-blockdevice/commit/fe2430349e9d734ce6dbf4e7b2e0f8a37bb22679) fix: perform correct PMBR partition calculations\n* [`2ec0c3c`](https://github.com/talos-systems/go-blockdevice/commit/2ec0c3cc0ff5ff705ed5c910ca1bcd5d93c7b102) fix: preserve the PMBR bootable flag when opening GPT partition\n* [`87816a8`](https://github.com/talos-systems/go-blockdevice/commit/87816a81cefc728cfe3cb221b476d8ed4b609fd8) feat: align partition to minimum I/O size\n* [`c34b59f`](https://github.com/talos-systems/go-blockdevice/commit/c34b59fb33a7ad8be18bb19bc8c8d8294b4b3a78) feat: expose more encryption options in the LUKS module\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>14 commits</summary>\n<p>\n\n* [`12856ce`](https://github.com/talos-systems/pkgs/commit/12856ce15d6d72814a2f40bbaf3f8ab6efb849f9) feat: increase number of CPUs supported by the kernel to 512\n* [`cbfabac`](https://github.com/talos-systems/pkgs/commit/cbfabaca6a3faf20914aae5c535e44a393a4f422) chore: update ca-certificates to 2021-07-05\n* [`0c011c0`](https://github.com/talos-systems/pkgs/commit/0c011c088068e5fdb55066008b526ca3ef69f218) feat: update GRUB to 2.06\n* [`5090d14`](https://github.com/talos-systems/pkgs/commit/5090d149a669f7eb3cc922196b7e82869c152dae) chore: update containerd to v1.5.5\n* [`6653902`](https://github.com/talos-systems/pkgs/commit/66539021daf1037782b1c4009dd96544057628d3) feat: add kernel drivers for fusion and scsi-isci\n* [`9b4041f`](https://github.com/talos-systems/pkgs/commit/9b4041fb79d9c5d8e18391f1e2f4843a88d26c19) chore: update containerd to v1.5.4\n* [`7b6cc05`](https://github.com/talos-systems/pkgs/commit/7b6cc05ceee8c24e746afa7ed105f9f55fef589b) feat: update kernel to latest 5.10.52\n* [`65159fb`](https://github.com/talos-systems/pkgs/commit/65159fb19c3138ec612cdca507e5cc795b657a7d) chore: update runc and CNI plugins\n* [`514ba34`](https://github.com/talos-systems/pkgs/commit/514ba3420a0773ac7305d00e8b582858f9685953) feat: disable aufs, devmapper, zfs\n* [`6bc118f`](https://github.com/talos-systems/pkgs/commit/6bc118f37cfd018183952b9feb009c54f1a3c215) chore: update runc and containerd\n* [`b6fca88`](https://github.com/talos-systems/pkgs/commit/b6fca88d22436a0fb78b8a4e06792b7af1a22ef5) feat: update Go to 1.16.6\n* [`fd56852`](https://github.com/talos-systems/pkgs/commit/fd568520e8c77bd8d96f96efb47dd2bdd2f36c1a) chore: update `open-isns` and `open-iscsi`\n* [`d779204`](https://github.com/talos-systems/pkgs/commit/d779204c0d9e9c8e90f32b1f68eb9ff4b030b83c) chore: update dosfstools to v4.2\n* [`bc7c0d7`](https://github.com/talos-systems/pkgs/commit/bc7c0d7c6afaec8226c2a52299981ac519b5e595) feat: add support for hotplug of PCIE devices\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`7172a5d`](https://github.com/talos-systems/tools/commit/7172a5db9d361527aa7bd9c7af407b9d578e2e02) feat: update Go to 1.16.6\n* [`1de34d7`](https://github.com/talos-systems/tools/commit/1de34d7961c7ac86f369217dea4ce69cdde04122) chore: update musl\n* [`76979a1`](https://github.com/talos-systems/tools/commit/76979a1c194c74c25db22c9ec90ec36f97179e3f) chore: update protobuf deps\n* [`0846c64`](https://github.com/talos-systems/tools/commit/0846c6493316b5d00ecc241b7051ced1bac1cf7e) chore: update expat\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/BurntSushi/toml**               v0.3.1 -> v0.4.1\n* **github.com/aws/aws-sdk-go**                v1.38.66 -> v1.40.2\n* **github.com/containerd/containerd**         v1.5.2 -> v1.5.5\n* **github.com/cosi-project/runtime**          93ead370bf57 -> 25f235cd0682\n* **github.com/docker/docker**                 v20.10.7 -> v20.10.8\n* **github.com/google/uuid**                   v1.2.0 -> v1.3.0\n* **github.com/hashicorp/go-getter**           v1.5.4 -> v1.5.6\n* **github.com/opencontainers/runtime-spec**   e6143ca7d51d -> 1c3f411f0417\n* **github.com/prometheus/procfs**             v0.6.0 -> v0.7.2\n* **github.com/rivo/tview**                    d4fb0348227b -> 29d673af0ce2\n* **github.com/spf13/cobra**                   v1.1.3 -> v1.2.1\n* **github.com/talos-systems/crypto**          v0.3.1 -> deec8d47700e\n* **github.com/talos-systems/extras**          v0.4.0 -> v0.5.0-alpha.0-1-g4957f3c\n* **github.com/talos-systems/go-blockdevice**  v0.2.1 -> v0.2.3\n* **github.com/talos-systems/pkgs**            v0.6.0-1-g7b2e126 -> v0.7.0-alpha.0-13-g12856ce\n* **github.com/talos-systems/tools**           v0.6.0 -> v0.7.0-alpha.0-2-g7172a5d\n* **github.com/vmware-tanzu/sonobuoy**         v0.52.0 -> v0.53.0\n* **go.uber.org/zap**                          v1.17.0 -> v1.18.1\n* **golang.org/x/net**                         04defd469f4e -> 853a461950ff\n* **golang.org/x/sys**                         59db8d763f22 -> 0f9fa26af87c\n* **golang.org/x/time**                        38a9dc6acbc6 -> 1f47c861a9ac\n* **google.golang.org/grpc**                   v1.38.0 -> v1.39.1\n* **google.golang.org/protobuf**               v1.26.0 -> v1.27.1\n* **inet.af/netaddr**                          bf05d8b52dda -> ce7a8ad02cc1\n* **k8s.io/api**                               v0.21.2 -> v0.22.0\n* **k8s.io/apimachinery**                      v0.21.2 -> v0.22.0\n* **k8s.io/apiserver**                         v0.21.2 -> v0.22.0\n* **k8s.io/client-go**                         v0.21.2 -> v0.22.0\n* **k8s.io/cri-api**                           v0.21.2 -> v0.22.0\n* **k8s.io/kubectl**                           v0.21.2 -> v0.22.0\n* **k8s.io/kubelet**                           v0.21.2 -> v0.22.0\n\nPrevious release can be found at [v0.11.0](https://github.com/talos-systems/talos/releases/tag/v0.11.0)\n\n## [Talos 0.11.0-alpha.2](https://github.com/talos-systems/talos/releases/tag/v0.11.0-alpha.2) (2021-06-23)\n\nWelcome to the v0.11.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Default to Bootstrap workflow\n\nThe `init.yaml` is no longer an output of `talosctl gen config`.\nWe now encourage using the bootstrap API, instead of `init` node types, as we\nintend on deprecating this machine type in the future.\nThe `init.yaml` and `controlplane.yaml` machine configs are identical with the\nexception of the machine type.\nUsers can use a modified `controlplane.yaml` with the machine type set to\n`init` if they would like to avoid using the bootstrap API.\n\n\n### Component Updates\n\n* containerd was updated to 1.5.2\n* Linux kernel was updated to 5.10.45\n* Kubernetes was updated to 1.21.2\n* etcd was updated to 3.4.16\n\n\n### CoreDNS\n\nAdded the flag `cluster.coreDNS.disabled` to coreDNS deployment during the cluster bootstrap.\n\n\n### Legacy BIOS Support\n\nAdded an option to the `machine.install` section of the machine config that can enable marking MBR partition bootable\nfor the machines that have legacy BIOS which does not support GPT partitioning scheme.\n\n\n### Multi-arch Installer\n\nTalos installer image (for any arch) now contains artifacts for both `amd64` and `arm64` architecture.\nThis means that e.g. images for arm64 SBCs can be generated on amd64 host.\n\n\n### Networking Configuration\n\nTalos networking configuration was completely rewritten to be based on controllers\nand resources.\nThere are no changes to the machine configuration, but any update to `.machine.network` can now\nbe applied in immediate mode (without a reboot).\nTalos should be setting up network configuration much faster on boot now, not blocking on DHCP for unconfigured\ninterfaces and skipping the reset network step.\n\n\n### Talos API RBAC\n\nLimited RBAC support in Talos API is now enabled by default for Talos 0.11.\nDefault `talosconfig` has `os:admin` role embedded in the certificate so that all the APIs are available.\nCertificates with reduced set of roles can be created with `talosctl config new` command.\n\nWhen upgrading from Talos 0.10, RBAC is not enabled by default. Before enabling RBAC, generate `talosconfig` with\n`os:admin` role first to make sure that administrator still has access to the cluster when RBAC is enabled.\n\nList of available roles:\n\n* `os:admin` role enables every Talos API\n* `os:reader` role limits access to read-only APIs which do not return sensitive data\n* `os:etcd:backup` role only allows `talosctl etcd snapshot` API call (for etcd backup automation)\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Serge Logvinov\n* Jorik Jonker\n* Spencer Smith\n* Andrew Rynhard\n* Andrew LeCody\n* Kevin Hellemun\n* Seán C McCord\n* Boran Car\n* Brandon Nason\n* Gabor Nyiri\n* Gabor Nyiri\n* Joost Coelingh\n* Lance R. Vick\n* Lennard Klein\n* Sébastien Bernard\n* Sébastien Bernard\n\n### Changes\n<details><summary>162 commits</summary>\n<p>\n\n* [`0731be90`](https://github.com/talos-systems/talos/commit/0731be908bfe130b37db3d5f54b96f3981b1c860) feat: add cloud images to releases\n* [`b52b2066`](https://github.com/talos-systems/talos/commit/b52b206665ba963ceec0b7a4ff41bcee77aa8a67) feat: split etcd certificates to peer/client\n* [`33119d2b`](https://github.com/talos-systems/talos/commit/33119d2b8e4b48367421ed8e66aa4b11e639b2ac) chore: add an option to launch cluster with bad RTC state\n* [`d8c2bca1`](https://github.com/talos-systems/talos/commit/d8c2bca1b53dc9d0e7bb627fe43c629a52489dec) feat: reimplement apid certificate generation on top of COSI\n* [`3c1b3219`](https://github.com/talos-systems/talos/commit/3c1b32199d294bd52983c4dd57738cad29aa8738) chore: refactor CLI tests\n* [`0fd9ea2d`](https://github.com/talos-systems/talos/commit/0fd9ea2d63af00f7d2423c2daba2988c38cdae78) feat: enable MACVTAP support\n* [`898673e8`](https://github.com/talos-systems/talos/commit/898673e8d3e53a0022f2564ee26a29991c145aa8) chore: update e2e tests to use latest capi releases\n* [`e26c5583`](https://github.com/talos-systems/talos/commit/e26c5583c2dbe771bd50a7f9efe958cdc9c60d54) docs: add AMI IDs for Talos 0.10.4\n* [`72ef48f0`](https://github.com/talos-systems/talos/commit/72ef48f0ea1898e80977f56724e931c73d7aff94) fix: assign source address to the DHCP default gateway routes\n* [`004885a3`](https://github.com/talos-systems/talos/commit/004885a379a8617a874bd97062eb7af00fe7dc3b) feat: update Linux kernel to 5.10.45, etcd to 3.4.16\n* [`821f469a`](https://github.com/talos-systems/talos/commit/821f469a1d82e180528dc07afffde05f08a57dd1) feat: skip overlay mount checks with docker\n* [`b6e02311`](https://github.com/talos-systems/talos/commit/b6e02311a36a7eeb5bfb22037989f49483b9e3f0) feat: use COSI RD's sensitivity for RBAC\n* [`46751c1a`](https://github.com/talos-systems/talos/commit/46751c1ad2b2102ea6b8e151bdbe854d041250cb) feat: improve security of Kubernetes control plane components\n* [`0f659622`](https://github.com/talos-systems/talos/commit/0f659622d02260731a30d4862da99697adc7ab5c) fix: build with custom kernel/rootfs\n* [`5b5089ab`](https://github.com/talos-systems/talos/commit/5b5089ab95e2a7a345e18232520d9071180d9f10) fix: mark kube-proxy as system critical priority\n* [`42c16f67`](https://github.com/talos-systems/talos/commit/42c16f67f4476b8b57c39fea2bd3ec8168cb8193) chore: bump dependencies\n* [`60f78419`](https://github.com/talos-systems/talos/commit/60f78419e490f47dc1424008f33cc1baa05097b4) chore: bump etcd client libraries to final 3.5.0 release\n* [`2b0de9ed`](https://github.com/talos-systems/talos/commit/2b0de9edb2b0f158f12cd320ac672c3c3a5a339b) feat: improve security of Kubernetes control plane components\n* [`48a5c460`](https://github.com/talos-systems/talos/commit/48a5c460a140b50026210576a46a691393511461) docs: provide more storage details\n* [`e13d905c`](https://github.com/talos-systems/talos/commit/e13d905c2e682b8470e62fd1ee9cd4f07a6c6c65) release(v0.11.0-alpha.1): prepare release\n* [`70ac771e`](https://github.com/talos-systems/talos/commit/70ac771e0846247dbebf484aca20ef950d8b99c7) fix: use localhost API server endpoint for internal communication\n* [`a941eb7d`](https://github.com/talos-systems/talos/commit/a941eb7da06246d59cec1b63883f2d7e3f91ce73) feat: improve security of Kubernetes control plane components\n* [`3aae94e5`](https://github.com/talos-systems/talos/commit/3aae94e5306c0d6e31df4aee127ee3562709edd3) feat: provide Kubernetes nodename as a COSI resource\n* [`06209bba`](https://github.com/talos-systems/talos/commit/06209bba2867829561a60f0e7cd9847fa9a8edd3) chore: update RBAC rules, remove old APIs\n* [`9f24b519`](https://github.com/talos-systems/talos/commit/9f24b519dce07ce05099b242ba95e8a1e319630e) chore: remove bootkube check from cluster health check\n* [`4ac9bea2`](https://github.com/talos-systems/talos/commit/4ac9bea27dc098ebdfdc0958f3000d960fad50de) fix: stop etcd client logs from going to the server console\n* [`f63ab9dd`](https://github.com/talos-systems/talos/commit/f63ab9dd9bb6c734873dc8073892f5f10a2ed2e1) feat: implement `talosctl config new` command\n* [`fa15a668`](https://github.com/talos-systems/talos/commit/fa15a6687fc56820fbc5566d494bedbc1a5f600f) fix: don't enable RBAC feature in the config for Talos < 0.11\n* [`2dc27d99`](https://github.com/talos-systems/talos/commit/2dc27d9964fa3df08a6ec11c0b045d7325ea0d2b) fix: do not format state partition in the initialize sequence\n* [`b609f33c`](https://github.com/talos-systems/talos/commit/b609f33cdebb0659738d4fa3802035b2b344b9b9) fix: update networking stack after Equnix Metal testing\n* [`243a3b53`](https://github.com/talos-systems/talos/commit/243a3b53e0e7591d5958a3b8373ab963990c40d6) fix: separate healthy and unknown flags in the service resource\n* [`1a1378be`](https://github.com/talos-systems/talos/commit/1a1378be16fdce45273bdc81fb72715c4766ee4b) fix: update retry package with a fix for errors.Is\n* [`cb83edd7`](https://github.com/talos-systems/talos/commit/cb83edd7fcf14bd199950a04e366fc573bcf4270) fix: wait for the network to be ready in mainteancne mode\n* [`96f89071`](https://github.com/talos-systems/talos/commit/96f89071c3ecd809d912762e40cb9d98ce052018) feat: update controller-runtime logs to console level on config.debug\n* [`973069b6`](https://github.com/talos-systems/talos/commit/973069b611456f758037c9ca4dc50a4a84e7a59c) feat: support NFS 4.1\n* [`654dcad4`](https://github.com/talos-systems/talos/commit/654dcad4753211599d12655ec0f0466f27f49589) chore: bump dependencies via dependabot\n* [`d7394457`](https://github.com/talos-systems/talos/commit/d7394457d978d073690bec589ea78d957539e333) fix: don't treat ethtool errors as fatal\n* [`f2ae9cd0`](https://github.com/talos-systems/talos/commit/f2ae9cd0c1b7d27b5b9971f4820e5feae7934124) feat: replace networkd with new network implementation\n* [`caec3063`](https://github.com/talos-systems/talos/commit/caec3063c82777f82599632ca4914a58515cb9a9) fix: do not complain about empty roles\n* [`11918a11`](https://github.com/talos-systems/talos/commit/11918a110a628d7e0b8749fce92ef572aca47874) docs: update community meeting time\n* [`aeddb9c0`](https://github.com/talos-systems/talos/commit/aeddb9c0977a51e7aca72f69edda8b69d917db13) feat: implement platform config controller (hostnames)\n* [`1ece334d`](https://github.com/talos-systems/talos/commit/1ece334da9d7bb247c385dba08202345b83c1a0f) feat: implement controller which runs network operators\n* [`744ea8a5`](https://github.com/talos-systems/talos/commit/744ea8a5d4b4cb4ff69c2c2fc636e499af892fee) fix: do not add bootstrap contents option if tail events is not 0\n* [`5029edfb`](https://github.com/talos-systems/talos/commit/5029edfb71990581515cabe9634d0519a9988316) fix: overwrite nodes in the gRPC metadata\n* [`6a35c8f1`](https://github.com/talos-systems/talos/commit/6a35c8f110abaf0017530650c55a34f1caae6288) feat: implement virtual IP (shared IP) network operator\n* [`0f3b8380`](https://github.com/talos-systems/talos/commit/0f3b83803d812a30e1418666fa5758734c20e5c2) chore: expose WatchRequest in the resources client\n* [`11e258b1`](https://github.com/talos-systems/talos/commit/11e258b15097493d2b4efd596b2fde2d52579455) feat: implement operator configuration controller\n* [`ce3815e7`](https://github.com/talos-systems/talos/commit/ce3815e75e889de32d9473a23e75863f56b893da) feat: implement DHCP6 operator\n* [`f010d99a`](https://github.com/talos-systems/talos/commit/f010d99afbc6095ad8fe218187fda306c59d3e1e) feat: implement operator framework with DHCP4 as the first example\n* [`f93c9c8f`](https://github.com/talos-systems/talos/commit/f93c9c8fa607a5116274d7e090f49568d01814e7) feat: bring unconfigured links with link carrier up by default\n* [`02bd657b`](https://github.com/talos-systems/talos/commit/02bd657b252ae64ea054b2dc338e55ce9352b420) feat: implement network.Status resource and controller\n* [`da329f00`](https://github.com/talos-systems/talos/commit/da329f00ab0af9f670207da1e13541aef36c4ca6) feat: enable RBAC by default\n* [`0f168a88`](https://github.com/talos-systems/talos/commit/0f168a880143141d8637d21aa9da403383dcf025) feat: add configuration for enabling RBAC\n* [`e74f789b`](https://github.com/talos-systems/talos/commit/e74f789b01b9910f8193415dcefb4b32abcb5f5c) feat: implement EtcFileController to render files in `/etc`\n* [`5aede1a8`](https://github.com/talos-systems/talos/commit/5aede1a83313152bd83891d0cae4b388a54bd9c2) fix: prefer extraConfig over OVF env, skip empty config\n* [`5ad314fe`](https://github.com/talos-systems/talos/commit/5ad314fe7e7cfca8196770071d52b93aa4f767f6) feat: implement basic RBAC interceptors\n* [`c031be81`](https://github.com/talos-systems/talos/commit/c031be8139dbe1f803b70fc9941cfe438b9ddeb9) chore: use Go 1.16.5\n* [`8b0763f6`](https://github.com/talos-systems/talos/commit/8b0763f6a20691d36d2c82f2a756171c55450a8a) chore: bump dependencies via dependabot\n* [`8b8de11d`](https://github.com/talos-systems/talos/commit/8b8de11d9f4d1b1fde43b7fdd56b96d5e3eb5413) feat: implement new controllers for hostname, resolvers and time servers\n* [`24859b14`](https://github.com/talos-systems/talos/commit/24859b14108df7c5895022043d02d4d5ca7660a4) docs: update Rpi4 firmware guide\n* [`62c702c4`](https://github.com/talos-systems/talos/commit/62c702c4fd6e7a11654f542bbe31d1adfc896731) fix: remove conflicting etcd member on rejoin with empty data directory\n* [`ff62a599`](https://github.com/talos-systems/talos/commit/ff62a59984ef0c61dcf549ab38d39584e3630724) fix: drop into maintenance mode if config URL is `none` (metal)\n* [`14e696d0`](https://github.com/talos-systems/talos/commit/14e696d068b5d895b4fefc06bc6d26b4ac2bc450) feat: update COSI runtime and add support for tail in the Talos gRPC\n* [`a71053fc`](https://github.com/talos-systems/talos/commit/a71053fcd88d7651e536ce29b574e18f84678f3e) feat: default to bootstrap workflow\n* [`76aac4bb`](https://github.com/talos-systems/talos/commit/76aac4bb25d8bc6a86458b8ac5be10ca67f236be) feat: implement CPU and Memory stats controller\n* [`8f90c6a8`](https://github.com/talos-systems/talos/commit/8f90c6a8e1d76a3ddecc99be4e4b9f0ce0235daa) feat: parse Talos-specific cmdline params\n* [`ed10e139`](https://github.com/talos-systems/talos/commit/ed10e139c161b0a6e0f3460e21e4e1752b26cb46) feat: implement NodeAddress controller\n* [`33db8857`](https://github.com/talos-systems/talos/commit/33db8857aaf6e411464d08c51560473455e8e156) fix: use COSI runtime DestroyReady input type\n* [`6e775363`](https://github.com/talos-systems/talos/commit/6e775363920b7869b83775d1b674807163039eb1) refactor: rename *.Status() to *.TypedSpec() in the resources\n* [`97627061`](https://github.com/talos-systems/talos/commit/97627061d7e8de90e2f2745efa7497137447d116) docs: set static IP on ISO install mode\n* [`5811f4dd`](https://github.com/talos-systems/talos/commit/5811f4dda1b62848eefae9be56e8b91d443f4d34) feat: implement link (interface) controllers\n* [`046b229b`](https://github.com/talos-systems/talos/commit/046b229b13708c3ffe1d77b8884242fc100097d0) chore: skip building multi-arch installer for race-enabled build\n* [`73fbb4b5`](https://github.com/talos-systems/talos/commit/73fbb4b523b41d266840eced306242d57a332b4d) fix: only fetch machine uuid if it's not set\n* [`f112a540`](https://github.com/talos-systems/talos/commit/f112a540b0e776f06820ee900d6ce9f4f2de02ec) fix: clean up stale snapshots on container start\n* [`c036b949`](https://github.com/talos-systems/talos/commit/c036b949486d94cbbce54c7511633d398f75797c) chore: bump dependencies\n* [`a4d67a01`](https://github.com/talos-systems/talos/commit/a4d67a01820894d3ebf8c65a06345232fae4f93b) feat: add the ability to disable CoreDNS\n* [`76dbfb36`](https://github.com/talos-systems/talos/commit/76dbfb3699df0725a8acf29bff39c43e4aa34f9d) feat: add ability to mark MBR partition bootable\n* [`e0f5b1e2`](https://github.com/talos-systems/talos/commit/e0f5b1e20aa0d22898274ddc0f9026c0d813cee2) chore: split mgmt/gen.go into several files\n* [`fad1b4f1`](https://github.com/talos-systems/talos/commit/fad1b4f1fdce962b779ceb960f81d572ee5033af) chore: fix go generate for the machinery\n* [`1117294a`](https://github.com/talos-systems/talos/commit/1117294ad21945d24b0954d223cc4996df01dd81) release(v0.11.0-alpha.0): prepare release\n* [`c0962946`](https://github.com/talos-systems/talos/commit/c09629466321f4d220454164784edf41fd3d5813) chore: prepare for 0.11 release series\n* [`72359765`](https://github.com/talos-systems/talos/commit/723597657ad78e9766190ea2e110208c62d0093b) feat: enable GORACE=halt_on_panic=1 in machined binary\n* [`0acb04ad`](https://github.com/talos-systems/talos/commit/0acb04ad7a2a0a7b75471f0251b0e04eccd927cd) feat: implement route network controllers\n* [`f5bf88a4`](https://github.com/talos-systems/talos/commit/f5bf88a4c2ab8f48fd93bc7ac13543c613bf9bd1) feat: create certificates with os:admin role\n* [`1db301ed`](https://github.com/talos-systems/talos/commit/1db301edf6a4057814a6d5b8f87fbfe1e020caeb) feat: switch controller-runtime to zap.Logger\n* [`f7cf64d4`](https://github.com/talos-systems/talos/commit/f7cf64d42ec77ca68408ecb0f437ab5f86bc787a) fix: add talos.config to the vApp Properties in VMware OVA\n* [`209527ec`](https://github.com/talos-systems/talos/commit/209527eccc6c93edad33a01a3f3d24fb978f2f07) docs: add AMIs for Talos 0.10.3\n* [`59cfd312`](https://github.com/talos-systems/talos/commit/59cfd312c1ac531528c4ceb2adeb3f85829cc4e1) chore: bump dependencies via dependabot\n* [`1edb20cf`](https://github.com/talos-systems/talos/commit/1edb20cf98fe2e641cefc658d17206e09acabc26) feat: extract config generation\n* [`af77c295`](https://github.com/talos-systems/talos/commit/af77c29565b65766d135884ec7740f67b56626e3) docs: update wirguard guide\n* [`4fe69121`](https://github.com/talos-systems/talos/commit/4fe691214366c08ea846bdc6233dd592da0d4769) test: better `talosctl ls` tests\n* [`04ddda96`](https://github.com/talos-systems/talos/commit/04ddda962fbcfdeaae59d232e7bb7f9c5bb63bc7) feat: update containerd to 1.5.2, runc to 1.0.0-rc95\n* [`49c7276b`](https://github.com/talos-systems/talos/commit/49c7276b16a82b7da8c83f8bd930361768f0e249) chore: fix markdown linting\n* [`7270495a`](https://github.com/talos-systems/talos/commit/7270495ace9faf48a73829bbed0e4eb2c939eecb) docs: add mayastor quickstart\n* [`d3d9112f`](https://github.com/talos-systems/talos/commit/d3d9112f288d3b0f3ebe1c8b28b1c4e2fc8512b2) docs: fix spelling/grammar in What's New for Talos 0.9\n* [`82804414`](https://github.com/talos-systems/talos/commit/82804414fc2fcb21da77edc2fbbefe92a14fc30d) test: provide a way to force different boot order in provision library\n* [`a1c0e99a`](https://github.com/talos-systems/talos/commit/a1c0e99a1729c704a633dcc557dc46466b828e11) docs: add guide for deploying metrics-server\n* [`6bc6658b`](https://github.com/talos-systems/talos/commit/6bc6658b518379d418baafcf9b1045a3b84f48ec) feat: update containerd to 1.5.1\n* [`c6567fae`](https://github.com/talos-systems/talos/commit/c6567fae9c59da5148c9876289a4bf248240b99d) chore: dependabot updates\n* [`61ccbb3f`](https://github.com/talos-systems/talos/commit/61ccbb3f5a2564376af13ea9bbfe51e364fcb3a1) chore: keep debug symbols in debug builds\n* [`1ce362e0`](https://github.com/talos-systems/talos/commit/1ce362e05e41cd76cdda17a6fc971767e036df37) docs: update customizing kernel build steps\n* [`a26174b5`](https://github.com/talos-systems/talos/commit/a26174b54846bdfa0b66d2f9147bfe1dc8f2eb52) fix: properly compose pattern and header in etcd members output\n* [`0825cf11`](https://github.com/talos-systems/talos/commit/0825cf11f412eef930db269b6cae02d059058101) fix: stop networkd and pods before leaving etcd on upgrade\n* [`bed6b15d`](https://github.com/talos-systems/talos/commit/bed6b15d6fcf0634a887b79797d639e221fe9387) fix: properly populate AllowSchedulingOnMasters option in gen config RPC\n* [`071f0445`](https://github.com/talos-systems/talos/commit/071f044562dd247dd54584d7b9fa0bb24d6f7599) feat: implement AddressSpec handling\n* [`76e38b7b`](https://github.com/talos-systems/talos/commit/76e38b7b8251548292ae15ecda2bfa1c8ddc5cf3) feat: update Kubernetes to 1.21.1\n* [`9b1338d9`](https://github.com/talos-systems/talos/commit/9b1338d989e6cdf7e0b6d5fe1ba3c32d27fc2251) chore: parse \"boolean\" variables\n* [`c81cfb21`](https://github.com/talos-systems/talos/commit/c81cfb21670b82e518cf4c32230e8fbbce6be8ff) chore: allow building with debug handlers\n* [`c9651673`](https://github.com/talos-systems/talos/commit/c9651673b9eaf811ae4acfed313debbf78bd80e8) feat: update go-smbios library\n* [`95c656fb`](https://github.com/talos-systems/talos/commit/95c656fb72b6b858b55dae37020cb59ba26115f8) feat: update containerd to 1.5.0, runc to 1.0.0-rc94\n* [`db9c35b5`](https://github.com/talos-systems/talos/commit/db9c35b570b39f4423f4636f9e9f1d14cac5d7c1) feat: implement AddressStatusController\n* [`1cf011a8`](https://github.com/talos-systems/talos/commit/1cf011a809b924fc8f2083566d169704c6e07cd5) chore: bump dependencies via dependabot\n* [`e3f407a1`](https://github.com/talos-systems/talos/commit/e3f407a1dff3f4ee7e024bbfb64f17b5cb5d625d) fix: properly pass disk type selector from config to matcher\n* [`66b2b450`](https://github.com/talos-systems/talos/commit/66b2b450582593e93598fac80c8b3c29e8c8a944) feat: add resources and use HTTPS checks in control plane pods\n* [`4ffd7c0a`](https://github.com/talos-systems/talos/commit/4ffd7c0adf281033ac02d37ca434e7f9ad71e692) fix: stop networkd before leaving etcd on 'reset' path\n* [`610d38d3`](https://github.com/talos-systems/talos/commit/610d38d309dabaa623494ade12234f1ccf018a9e) docs: add AMIs for 0.10.1, collapse list of AMIs by default\n* [`807497ec`](https://github.com/talos-systems/talos/commit/807497ec20dee15953186bda0fe7a45ffec0307c) chore: make conformance pipeline depend on cron-default\n* [`3c121359`](https://github.com/talos-systems/talos/commit/3c1213596cdf03daf09050103f57b29e756439b1) feat: implement LinkStatusController\n* [`0e8de046`](https://github.com/talos-systems/talos/commit/0e8de04698aac95062f3037da0a9af8b6ee916b0) fix: update go-blockdevice to fix disk type detection\n* [`4d50a4ed`](https://github.com/talos-systems/talos/commit/4d50a4edd0eb413c16e899536ccdc2642e37aeaa) fix: update the way NTP sync uses `adjtimex` syscall\n* [`1a85c14a`](https://github.com/talos-systems/talos/commit/1a85c14a51fdab43ae84274563bf89b30e4e6d92) fix: avoid data race on CRI pod stop\n* [`5de8dbc0`](https://github.com/talos-systems/talos/commit/5de8dbc06c7ed36c8f3af9adea8b1abedeb372b6) fix: repair pine64 support\n* [`38239097`](https://github.com/talos-systems/talos/commit/3823909735859f2ac5d95bc39c051fc9c2c07685) fix: properly parse matcher expressions\n* [`e54b6b7a`](https://github.com/talos-systems/talos/commit/e54b6b7a3d7412ddce1467dfbd35efe3cfd76f3f) chore: update dependencies via dependabot\n* [`f2caed0d`](https://github.com/talos-systems/talos/commit/f2caed0df5b76c4a719f968191081a6e5e2e95c7) chore: use extracted talos-systems/go-kmsg library\n* [`79d804c5`](https://github.com/talos-systems/talos/commit/79d804c5b4af50a0fd73db17d2522d6a6b45c9ca) docs: fix typos\n* [`a2bb390e`](https://github.com/talos-systems/talos/commit/a2bb390e1d56106d6d3c1526f3f76b34846b0274) feat: deterministic builds\n* [`e480fedf`](https://github.com/talos-systems/talos/commit/e480fedff047233e78ad2c22e7b84cbbb22798d5) feat: add USB serial drivers\n* [`79299d76`](https://github.com/talos-systems/talos/commit/79299d761c50aff386ab7b3c12f39c1797585632) docs: add Matrix room links\n* [`1b3e8b09`](https://github.com/talos-systems/talos/commit/1b3e8b09edcd51cf3df2d43d14c8fbf1e912a465) docs: add survey to README\n* [`8d51c9bb`](https://github.com/talos-systems/talos/commit/8d51c9bb190c2c60fa9be6a00572d2eaf4221e94) docs: update redirects to Talos 0.10\n* [`1092c3a5`](https://github.com/talos-systems/talos/commit/1092c3a5069a3add439860d90c3615111fa03c98) feat: add Pine64 SBC support\n* [`63e01754`](https://github.com/talos-systems/talos/commit/63e0175437e45c8f7e5296841337a640c600982c) feat: pull kernel with VMware balloon module enabled\n* [`aeec99d8`](https://github.com/talos-systems/talos/commit/aeec99d8247f4eb534e0db1ed639f95cd726fe08) chore: remove temporary fork\n* [`0f49722d`](https://github.com/talos-systems/talos/commit/0f49722d0ff4e731f17a55d1ca50472714334748) feat: add `--config-patch` flag by node type\n* [`a01b1d22`](https://github.com/talos-systems/talos/commit/a01b1d22d9f3fa94355817217fefd80fe34628f3) chore: dump dependencies via dependabot\n* [`d540a4a4`](https://github.com/talos-systems/talos/commit/d540a4a4711367a0ada203f668382e39876ba081) fix: bump crypto library for the CSR verification fix\n* [`c3a4173e`](https://github.com/talos-systems/talos/commit/c3a4173e11a92c2bc51ea4f284ad38c9750105d2) chore: remove security API ReadFile/WriteFile\n* [`38037131`](https://github.com/talos-systems/talos/commit/38037131cddc2aefbae0f48fb7e355ec76247b67) chore: update wgctrl dependecy\n* [`d9ba0fd0`](https://github.com/talos-systems/talos/commit/d9ba0fd0164b2bfb2bc4ffe7a2d9d6c665a38e4d) docs: create v0.11 docs, promote v0.10 docs, add v0.10 AMIs\n* [`2261d7ed`](https://github.com/talos-systems/talos/commit/2261d7ed0212c287273eac647647e4390c530a6e) fix: use both self-signed and Kubernetes CA to verify Kubelet cert\n* [`a3537a69`](https://github.com/talos-systems/talos/commit/a3537a691320430eeb7149abe73419ee242312fc) docs: update cloud images for Talos v0.9.3\n* [`5b9ee861`](https://github.com/talos-systems/talos/commit/5b9ee86179fb92989b02533d6d6745a5b0f37566) docs: add what's new for Talos 0.10\n* [`f1107fa3`](https://github.com/talos-systems/talos/commit/f1107fa3a33955f3aa57a49991c87f9ee47b6e67) docs: add survey\n* [`93623d47`](https://github.com/talos-systems/talos/commit/93623d47f24fef0d149fa006678b61e3182ef771) docs: update AWS instructions\n* [`a739d1b8`](https://github.com/talos-systems/talos/commit/a739d1b8adbc026796d1c55f7319677f9010f727) feat: add support of custom registry CA certificate usage\n* [`7f468d35`](https://github.com/talos-systems/talos/commit/7f468d350a6f80d2815149376fa24f7d7629402c) fix: update osType in OVA other3xLinux64Guest\"\n* [`4a184b67`](https://github.com/talos-systems/talos/commit/4a184b67d6ae25b21b35373e7dd6eab41b042c96) docs: add etcd backup and restore guide\n* [`5fb38d3e`](https://github.com/talos-systems/talos/commit/5fb38d3e5f201934d64bae186c5300e7de7af3d4) chore: refactor Dockerfile for cross-compilation\n* [`a8f1e526`](https://github.com/talos-systems/talos/commit/a8f1e526bfc00107c915572df2be08b3f154f4e6) chore: build talosctl for Darwin / Apple Silicon\n* [`eb0b64d3`](https://github.com/talos-systems/talos/commit/eb0b64d3138228a6c751387c720ca81c338b834d) chore: list specifically for enabled regions\n* [`669a0cbd`](https://github.com/talos-systems/talos/commit/669a0cbdc4756f0ad8f0dacc56a20f71e96fe4cd) fix: check if OVF env is empty\n* [`da92049c`](https://github.com/talos-systems/talos/commit/da92049c0b4beae32af80205f50849443cd6dad3) chore: use codecov from the build container\n* [`9996d4b0`](https://github.com/talos-systems/talos/commit/9996d4b028f3845071850def75f2b534e4d2b190) chore: use REGISTRY_MIRROR_FLAGS if defined\n* [`05cbe250`](https://github.com/talos-systems/talos/commit/05cbe250c87339e097d435d6b10b9d8a5f2eb49e) chore: bump dependencies via dependabot\n* [`9a91142a`](https://github.com/talos-systems/talos/commit/9a91142a38b3b1f210773acf8df01ed6a45599c2) feat: print complete member info in etcd members\n* [`bb40d6dd`](https://github.com/talos-systems/talos/commit/bb40d6dd06a967464c24ab33744bbf460aa84038) feat: update pkgs version\n* [`e7a9164b`](https://github.com/talos-systems/talos/commit/e7a9164b1e1630f953a420d99c865aef6e652d15) test: implement `talosctl conformance` command to run e2e tests\n* [`6cb266e7`](https://github.com/talos-systems/talos/commit/6cb266e74e60d9d5423feaad550a7861dc73f11d) fix: update etcd client errors, print etcd join failures\n* [`0bd8b0e8`](https://github.com/talos-systems/talos/commit/0bd8b0e8008c12e4914c6e9b5faf06dda6c744f7) feat: provide an option to recover etcd from data directory copy\n* [`f9818540`](https://github.com/talos-systems/talos/commit/f98185408d618ebcc780247ea2c42239df27a74e) chore: fix conform with scopes\n* [`21018f28`](https://github.com/talos-systems/talos/commit/21018f28c732719535c30c8e1abdbb346f1dc4bf) chore: bump website node.js dependencies\n</p>\n</details>\n\n### Changes since v0.11.0-alpha.1\n<details><summary>19 commits</summary>\n<p>\n\n* [`0731be90`](https://github.com/talos-systems/talos/commit/0731be908bfe130b37db3d5f54b96f3981b1c860) feat: add cloud images to releases\n* [`b52b2066`](https://github.com/talos-systems/talos/commit/b52b206665ba963ceec0b7a4ff41bcee77aa8a67) feat: split etcd certificates to peer/client\n* [`33119d2b`](https://github.com/talos-systems/talos/commit/33119d2b8e4b48367421ed8e66aa4b11e639b2ac) chore: add an option to launch cluster with bad RTC state\n* [`d8c2bca1`](https://github.com/talos-systems/talos/commit/d8c2bca1b53dc9d0e7bb627fe43c629a52489dec) feat: reimplement apid certificate generation on top of COSI\n* [`3c1b3219`](https://github.com/talos-systems/talos/commit/3c1b32199d294bd52983c4dd57738cad29aa8738) chore: refactor CLI tests\n* [`0fd9ea2d`](https://github.com/talos-systems/talos/commit/0fd9ea2d63af00f7d2423c2daba2988c38cdae78) feat: enable MACVTAP support\n* [`898673e8`](https://github.com/talos-systems/talos/commit/898673e8d3e53a0022f2564ee26a29991c145aa8) chore: update e2e tests to use latest capi releases\n* [`e26c5583`](https://github.com/talos-systems/talos/commit/e26c5583c2dbe771bd50a7f9efe958cdc9c60d54) docs: add AMI IDs for Talos 0.10.4\n* [`72ef48f0`](https://github.com/talos-systems/talos/commit/72ef48f0ea1898e80977f56724e931c73d7aff94) fix: assign source address to the DHCP default gateway routes\n* [`004885a3`](https://github.com/talos-systems/talos/commit/004885a379a8617a874bd97062eb7af00fe7dc3b) feat: update Linux kernel to 5.10.45, etcd to 3.4.16\n* [`821f469a`](https://github.com/talos-systems/talos/commit/821f469a1d82e180528dc07afffde05f08a57dd1) feat: skip overlay mount checks with docker\n* [`b6e02311`](https://github.com/talos-systems/talos/commit/b6e02311a36a7eeb5bfb22037989f49483b9e3f0) feat: use COSI RD's sensitivity for RBAC\n* [`46751c1a`](https://github.com/talos-systems/talos/commit/46751c1ad2b2102ea6b8e151bdbe854d041250cb) feat: improve security of Kubernetes control plane components\n* [`0f659622`](https://github.com/talos-systems/talos/commit/0f659622d02260731a30d4862da99697adc7ab5c) fix: build with custom kernel/rootfs\n* [`5b5089ab`](https://github.com/talos-systems/talos/commit/5b5089ab95e2a7a345e18232520d9071180d9f10) fix: mark kube-proxy as system critical priority\n* [`42c16f67`](https://github.com/talos-systems/talos/commit/42c16f67f4476b8b57c39fea2bd3ec8168cb8193) chore: bump dependencies\n* [`60f78419`](https://github.com/talos-systems/talos/commit/60f78419e490f47dc1424008f33cc1baa05097b4) chore: bump etcd client libraries to final 3.5.0 release\n* [`2b0de9ed`](https://github.com/talos-systems/talos/commit/2b0de9edb2b0f158f12cd320ac672c3c3a5a339b) feat: improve security of Kubernetes control plane components\n* [`48a5c460`](https://github.com/talos-systems/talos/commit/48a5c460a140b50026210576a46a691393511461) docs: provide more storage details\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>8 commits</summary>\n<p>\n\n* [`d3cb772`](https://github.com/talos-systems/crypto/commit/d3cb77220384b3a3119a6f3ddb1340bbc811f1d1) feat: make possible to change KeyUsage\n* [`6bc5bb5`](https://github.com/talos-systems/crypto/commit/6bc5bb50c52767296a1b1cab6580e3fcf1358f34) chore: remove unused argument\n* [`cd18ef6`](https://github.com/talos-systems/crypto/commit/cd18ef62eb9f65d8b6730a2eb73e47e629949e1b) feat: add support for several organizations\n* [`97c888b`](https://github.com/talos-systems/crypto/commit/97c888b3924dd5ac70b8d30dd66b4370b5ab1edc) chore: add options to CSR\n* [`7776057`](https://github.com/talos-systems/crypto/commit/7776057f5086157873f62f6a21ec23fa9fd86e05) chore: fix typos\n* [`80df078`](https://github.com/talos-systems/crypto/commit/80df078327030af7e822668405bb4853c512bd7c) chore: remove named result parameters\n* [`15bdd28`](https://github.com/talos-systems/crypto/commit/15bdd282b74ac406ab243853c1b50338a1bc29d0) chore: minor updates\n* [`4f80b97`](https://github.com/talos-systems/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`4fe2706`](https://github.com/talos-systems/extras/commit/4fe27060347c861b716392eec3dfee698becb5f3) feat: build with Go 1.16.5\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>3 commits</summary>\n<p>\n\n* [`30c2bc3`](https://github.com/talos-systems/go-blockdevice/commit/30c2bc3cb62af52f0aea9ce347923b0649fb7928) feat: mark MBR bootable\n* [`1292574`](https://github.com/talos-systems/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/talos-systems/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n</p>\n</details>\n\n### Changes from talos-systems/go-debug\n<details><summary>5 commits</summary>\n<p>\n\n* [`3d0a6e1`](https://github.com/talos-systems/go-debug/commit/3d0a6e1bf5e3c521e83ead2c8b7faad3638b8c5d) feat: race build tag flag detector\n* [`5b292e5`](https://github.com/talos-systems/go-debug/commit/5b292e50198b8ed91c434f00e2772db394dbf0b9) feat: disable memory profiling by default\n* [`c6d0ae2`](https://github.com/talos-systems/go-debug/commit/c6d0ae2c0ee099fa0940405401e6a02716a15bd8) fix: linters and CI\n* [`d969f95`](https://github.com/talos-systems/go-debug/commit/d969f952af9e02feea59963671298fc236ca4399) feat: initial implementation\n* [`b2044b7`](https://github.com/talos-systems/go-debug/commit/b2044b70379c84f9706de74044bd2fd6a8e891cf) Initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-kmsg\n<details><summary>2 commits</summary>\n<p>\n\n* [`2edcd3a`](https://github.com/talos-systems/go-kmsg/commit/2edcd3a913508e2d922776f729bfc4bcab031a8b) feat: add initial version\n* [`53cdd8d`](https://github.com/talos-systems/go-kmsg/commit/53cdd8d67b9dbab692471a2d5161e7e0b3d04cca) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-loadbalancer\n<details><summary>3 commits</summary>\n<p>\n\n* [`a445702`](https://github.com/talos-systems/go-loadbalancer/commit/a4457024d5189d754b2da4a30b14072a0e3f5f05) feat: allow dial timeout and keep alive period to be configurable\n* [`3c8f347`](https://github.com/talos-systems/go-loadbalancer/commit/3c8f3471d14e37866c65f73170ef83c038ae5a8c) feat: provide a way to configure logger for the loadbalancer\n* [`da8e987`](https://github.com/talos-systems/go-loadbalancer/commit/da8e987434c3d407679a40e213b12a8e1c98abb8) feat: implement Reconcile - ability to change upstream list on the fly\n</p>\n</details>\n\n### Changes from talos-systems/go-retry\n<details><summary>3 commits</summary>\n<p>\n\n* [`c78cc95`](https://github.com/talos-systems/go-retry/commit/c78cc953d9e95992575305b4e8648392c6c9b9e6) fix: implement `errors.Is` for all errors in the set\n* [`7885e16`](https://github.com/talos-systems/go-retry/commit/7885e16b2cb0267bcc8b07cdd0eced14e8005864) feat: add ExpectedErrorf\n* [`3d83f61`](https://github.com/talos-systems/go-retry/commit/3d83f6126c1a3a238d1d1d59bfb6273e4087bdac) feat: deprecate UnexpectedError\n</p>\n</details>\n\n### Changes from talos-systems/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`d3a32be`](https://github.com/talos-systems/go-smbios/commit/d3a32bea731a0c2a60ce7f5eae60253300ef27e1) fix: return UUID in middle endian only on SMBIOS >= 2.6\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>22 commits</summary>\n<p>\n\n* [`41d6ccc`](https://github.com/talos-systems/pkgs/commit/41d6ccc8d40259e77da6cc46b047f265e6ebc58b) feat: enable MACVTAP support\n* [`96072f8`](https://github.com/talos-systems/pkgs/commit/96072f89ac6b6b7dccd25e54ebbb33eef312c8e4) feat: enable adiantum block encryption (both amd64 arm64)\n* [`f5eac03`](https://github.com/talos-systems/pkgs/commit/f5eac033223b1116de70c51204af3a096d9130a5) feat: update Linux to 5.10.45\n* [`d756119`](https://github.com/talos-systems/pkgs/commit/d756119b2b0dfabda50a945ee16ee4fd62109cb0) feat: enable HP ILO kernel module (both amd64 arm64)\n* [`2d51360`](https://github.com/talos-systems/pkgs/commit/2d51360a254b237943e92cd445e42912d39fce7a) feat: support NFS 4.1\n* [`e63e4e9`](https://github.com/talos-systems/pkgs/commit/e63e4e97b4c398e090028eaf7b967cc9eafadf96) feat: bump tools for Go 1.16.5\n* [`1f8af29`](https://github.com/talos-systems/pkgs/commit/1f8af290e5d242f7dfc784fd2fc7fcfd714500bd) feat: update Linux to 5.10.38\n* [`a3a6650`](https://github.com/talos-systems/pkgs/commit/a3a66505f36b9e9f92f4980df3708a872d56caec) feat: update containerd to 1.5.2\n* [`c70ea44`](https://github.com/talos-systems/pkgs/commit/c70ea44ba4bc1ffabdb1422deda107a94e1fe94c) feat: update runc to 1.0.0-rc95\n* [`db60235`](https://github.com/talos-systems/pkgs/commit/db602359cc594b35291911b4220dc5b331b323bb) feat: add support for netxen card\n* [`f934187`](https://github.com/talos-systems/pkgs/commit/f934187ebdc455f18cc6d2da847be3d48a6e3d8f) feat: update containerd to 1.5.1\n* [`e8ed5bc`](https://github.com/talos-systems/pkgs/commit/e8ed5bcb848954ca30967de8d7c81afecdea4825) feat: add geneve encapsulation support for openvswitch\n* [`9f7903c`](https://github.com/talos-systems/pkgs/commit/9f7903cb5c110f77db8093347b69ec141325d47c) feat: update containerd to 1.5.0, runc to -rc94\n* [`d7c0f70`](https://github.com/talos-systems/pkgs/commit/d7c0f70e41bb7bf542092f2882b062ff52f5ae44) feat: add AES-NI support for amd64\n* [`b0d9cd2`](https://github.com/talos-systems/pkgs/commit/b0d9cd2c36e37190c5ce7b85acea6a51a853faaf) fix: build `zbin` utility for both amd64 and arm64\n* [`bb39b97`](https://github.com/talos-systems/pkgs/commit/bb39b9744c0c4a29ccfa190a0d2cce0f8547676b) feat: add IPMI support in kernel\n* [`1148f9a`](https://github.com/talos-systems/pkgs/commit/1148f9a897d9a52b6013396151e1eab264709037) feat: add DS1307 RTC support for arm64\n* [`350aa6f`](https://github.com/talos-systems/pkgs/commit/350aa6f200d441d7dbbf60ec8ebb39a6761d6a8b) feat: add USB serial support\n* [`de9c582`](https://github.com/talos-systems/pkgs/commit/de9c58238483219a574fb697ddb1126f36a02da3) feat: add Pine64 SBC support\n* [`b56f36b`](https://github.com/talos-systems/pkgs/commit/b56f36bedbe9270ae5cf969f8078a10345457e83) feat: enable VMware baloon kernel module\n* [`f87c194`](https://github.com/talos-systems/pkgs/commit/f87c19425352eb9b68d20dec987d0c484987dea9) feat: add iPXE build with embedded placeholder script\n* [`a8b9e71`](https://github.com/talos-systems/pkgs/commit/a8b9e71e6538d7554b7a48d1361709d5495bb4de) feat: add cpu scaling for rpi\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`c8c2a18`](https://github.com/talos-systems/tools/commit/c8c2a18b7e587e0b8464574e375a680c5a09a028) feat: update Go to 1.16.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go**                     v1.27.0 **_new_**\n* **github.com/containerd/cgroups**                 4cbc285b3327 -> v1.0.1\n* **github.com/containerd/containerd**              v1.4.4 -> v1.5.2\n* **github.com/containerd/go-cni**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/typeurl**                 v1.0.1 -> v1.0.2\n* **github.com/coreos/go-iptables**                 v0.5.0 -> v0.6.0\n* **github.com/cosi-project/runtime**               10d6103c19ab -> f1649aff7641\n* **github.com/docker/docker**                      v20.10.4 -> v20.10.7\n* **github.com/emicklei/dot**                       v0.15.0 -> v0.16.0\n* **github.com/evanphx/json-patch**                 v4.9.0 -> v4.11.0\n* **github.com/fatih/color**                        v1.10.0 -> v1.12.0\n* **github.com/google/go-cmp**                      v0.5.5 -> v0.5.6\n* **github.com/google/gofuzz**                      v1.2.0 **_new_**\n* **github.com/googleapis/gnostic**                 v0.5.5 **_new_**\n* **github.com/grpc-ecosystem/go-grpc-middleware**  v1.2.2 -> v1.3.0\n* **github.com/hashicorp/go-getter**                v1.5.2 -> v1.5.4\n* **github.com/imdario/mergo**                      v0.3.12 **_new_**\n* **github.com/insomniacslk/dhcp**                  cc9239ac6294 -> 465dd6c35f6c\n* **github.com/jsimonetti/rtnetlink**               1b79e63a70a0 -> 9c52e516c709\n* **github.com/magiconair/properties**              v1.8.5 **_new_**\n* **github.com/mattn/go-isatty**                    v0.0.12 -> v0.0.13\n* **github.com/mdlayher/arp**                       f72070a231fc **_new_**\n* **github.com/mdlayher/ethtool**                   2b88debcdd43 **_new_**\n* **github.com/mdlayher/netlink**                   v1.4.0 -> v1.4.1\n* **github.com/mdlayher/raw**                       51b895745faf **_new_**\n* **github.com/mitchellh/mapstructure**             v1.4.1 **_new_**\n* **github.com/opencontainers/runtime-spec**        4d89ac9fbff6 -> e6143ca7d51d\n* **github.com/pelletier/go-toml**                  v1.9.0 **_new_**\n* **github.com/rivo/tview**                         8a8f78a6dd01 -> d4fb0348227b\n* **github.com/rs/xid**                             v1.2.1 -> v1.3.0\n* **github.com/sirupsen/logrus**                    v1.8.1 **_new_**\n* **github.com/spf13/afero**                        v1.6.0 **_new_**\n* **github.com/spf13/cast**                         v1.3.1 **_new_**\n* **github.com/spf13/viper**                        v1.7.1 **_new_**\n* **github.com/talos-systems/crypto**               39584f1b6e54 -> d3cb77220384\n* **github.com/talos-systems/extras**               v0.3.0 -> v0.3.0-1-g4fe2706\n* **github.com/talos-systems/go-blockdevice**       1d830a25f64f -> v0.2.1\n* **github.com/talos-systems/go-debug**             3d0a6e1bf5e3 **_new_**\n* **github.com/talos-systems/go-kmsg**              v0.1.0 **_new_**\n* **github.com/talos-systems/go-loadbalancer**      v0.1.0 -> v0.1.1\n* **github.com/talos-systems/go-retry**             b9dc1a990133 -> c78cc953d9e9\n* **github.com/talos-systems/go-smbios**            fb425d4727e6 -> d3a32bea731a\n* **github.com/talos-systems/pkgs**                 v0.5.0-1-g5dd650b -> v0.6.0-alpha.0-12-g41d6ccc\n* **github.com/talos-systems/talos/pkg/machinery**  8ffb55943c71 -> 000000000000\n* **github.com/talos-systems/tools**                v0.5.0 -> v0.5.0-1-gc8c2a18\n* **github.com/vishvananda/netns**                  2eb08e3e575f **_new_**\n* **github.com/vmware-tanzu/sonobuoy**              v0.20.0 -> v0.51.0\n* **github.com/vmware/govmomi**                     v0.24.0 -> v0.26.0\n* **go.etcd.io/etcd/api/v3**                        v3.5.0-alpha.0 -> v3.5.0\n* **go.etcd.io/etcd/client/pkg/v3**                 v3.5.0 **_new_**\n* **go.etcd.io/etcd/client/v3**                     v3.5.0-alpha.0 -> v3.5.0\n* **go.etcd.io/etcd/etcdutl/v3**                    v3.5.0 **_new_**\n* **go.uber.org/zap**                               v1.17.0 **_new_**\n* **golang.org/x/net**                              e18ecbb05110 -> 04defd469f4e\n* **golang.org/x/oauth2**                           81ed05c6b58c **_new_**\n* **golang.org/x/sys**                              77cc2087c03b -> 59db8d763f22\n* **golang.org/x/term**                             6a3ed077a48d -> 6886f2dfbf5b\n* **golang.org/x/time**                             f8bda1e9f3ba -> 38a9dc6acbc6\n* **golang.zx2c4.com/wireguard/wgctrl**             bd2cb7843e1b -> 92e472f520a5\n* **google.golang.org/appengine**                   v1.6.7 **_new_**\n* **google.golang.org/grpc**                        v1.37.0 -> v1.38.0\n* **gopkg.in/ini.v1**                               v1.62.0 **_new_**\n* **inet.af/netaddr**                               1d252cf8125e **_new_**\n* **k8s.io/api**                                    v0.21.0 -> v0.21.2\n* **k8s.io/apimachinery**                           v0.21.0 -> v0.21.2\n* **k8s.io/apiserver**                              v0.21.0 -> v0.21.2\n* **k8s.io/client-go**                              v0.21.0 -> v0.21.2\n* **k8s.io/cri-api**                                v0.21.0 -> v0.21.2\n* **k8s.io/kubectl**                                v0.21.0 -> v0.21.2\n* **k8s.io/kubelet**                                v0.21.0 -> v0.21.2\n* **k8s.io/utils**                                  2afb4311ab10 **_new_**\n* **sigs.k8s.io/structured-merge-diff/v4**          v4.1.1 **_new_**\n\nPrevious release can be found at [v0.10.0](https://github.com/talos-systems/talos/releases/tag/v0.10.0)\n\n## [Talos 0.11.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.11.0-alpha.1) (2021-06-18)\n\nWelcome to the v0.11.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Default to Bootstrap workflow\n\nThe `init.yaml` is no longer an output of `talosctl gen config`.\nWe now encourage using the bootstrap API, instead of `init` node types, as we\nintend on deprecating this machine type in the future.\nThe `init.yaml` and `controlplane.yaml` machine configs are identical with the\nexception of the machine type.\nUsers can use a modified `controlplane.yaml` with the machine type set to\n`init` if they would like to avoid using the bootstrap API.\n\n\n### Component Updates\n\n* containerd was updated to 1.5.2\n* Linux kernel was updated to 5.10.38\n\n\n### CoreDNS\n\nAdded the flag `cluster.coreDNS.disabled` to coreDNS deployment during the cluster bootstrap.\n\n\n### Legacy BIOS Support\n\nAdded an option to the `machine.install` section of the machine config that can enable marking MBR partition bootable\nfor the machines that have legacy BIOS which does not support GPT partitioning scheme.\n\n\n### Multi-arch Installer\n\nTalos installer image (for any arch) now contains artifacts for both `amd64` and `arm64` architecture.\nThis means that e.g. images for arm64 SBCs can be generated on amd64 host.\n\n\n### Networking Configuration\n\nTalos networking configuration was completely rewritten to be based on controllers\nand resources.\nThere are no changes to the machine configuration, but any update to `.machine.network` can now\nbe applied in immediate mode (without a reboot).\nTalos should be setting up network configuration much faster on boot now, not blocking on DHCP for unconfigured\ninterfaces and skipping the reset network step.\n\n\n### Talos API RBAC\n\nLimited RBAC support in Talos API is now enabled by default for Talos 0.11.\nDefault `talosconfig` has `os:admin` role embedded in the certificate so that all the APIs are available.\nCertificates with reduced set of roles can be created with `talosctl config new` command.\n\nWhen upgrading from Talos 0.10, RBAC is not enabled by default. Before enabling RBAC, generate `talosconfig` with\n`os:admin` role first to make sure that administrator still have access to the cluster when RBAC is enabled.\n\nList of available roles:\n\n* `os:admin` role enables every Talos API\n* `os:reader` role limits access to read-only APIs which do not return sensitive informtation\n* `os:etcd:backup` role only allows `talosctl etcd snapshot` API call (for etcd backup automation)\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Jorik Jonker\n* Spencer Smith\n* Andrew Rynhard\n* Serge Logvinov\n* Andrew LeCody\n* Kevin Hellemun\n* Boran Car\n* Brandon Nason\n* Gabor Nyiri\n* Joost Coelingh\n* Lance R. Vick\n* Lennard Klein\n* Seán C McCord\n* Sébastien Bernard\n* Sébastien Bernard\n\n### Changes\n<details><summary>143 commits</summary>\n<p>\n\n* [`f8e1cf09`](https://github.com/talos-systems/talos/commit/f8e1cf09d09c5a3d8c8ed0bdcae3d564a97e6446) release(v0.11.0-alpha.1): prepare release\n* [`70ac771e`](https://github.com/talos-systems/talos/commit/70ac771e0846247dbebf484aca20ef950d8b99c7) fix: use localhost API server endpoint for internal communication\n* [`a941eb7d`](https://github.com/talos-systems/talos/commit/a941eb7da06246d59cec1b63883f2d7e3f91ce73) feat: improve security of Kubernetes control plane components\n* [`3aae94e5`](https://github.com/talos-systems/talos/commit/3aae94e5306c0d6e31df4aee127ee3562709edd3) feat: provide Kubernetes nodename as a COSI resource\n* [`06209bba`](https://github.com/talos-systems/talos/commit/06209bba2867829561a60f0e7cd9847fa9a8edd3) chore: update RBAC rules, remove old APIs\n* [`9f24b519`](https://github.com/talos-systems/talos/commit/9f24b519dce07ce05099b242ba95e8a1e319630e) chore: remove bootkube check from cluster health check\n* [`4ac9bea2`](https://github.com/talos-systems/talos/commit/4ac9bea27dc098ebdfdc0958f3000d960fad50de) fix: stop etcd client logs from going to the server console\n* [`f63ab9dd`](https://github.com/talos-systems/talos/commit/f63ab9dd9bb6c734873dc8073892f5f10a2ed2e1) feat: implement `talosctl config new` command\n* [`fa15a668`](https://github.com/talos-systems/talos/commit/fa15a6687fc56820fbc5566d494bedbc1a5f600f) fix: don't enable RBAC feature in the config for Talos < 0.11\n* [`2dc27d99`](https://github.com/talos-systems/talos/commit/2dc27d9964fa3df08a6ec11c0b045d7325ea0d2b) fix: do not format state partition in the initialize sequence\n* [`b609f33c`](https://github.com/talos-systems/talos/commit/b609f33cdebb0659738d4fa3802035b2b344b9b9) fix: update networking stack after Equnix Metal testing\n* [`243a3b53`](https://github.com/talos-systems/talos/commit/243a3b53e0e7591d5958a3b8373ab963990c40d6) fix: separate healthy and unknown flags in the service resource\n* [`1a1378be`](https://github.com/talos-systems/talos/commit/1a1378be16fdce45273bdc81fb72715c4766ee4b) fix: update retry package with a fix for errors.Is\n* [`cb83edd7`](https://github.com/talos-systems/talos/commit/cb83edd7fcf14bd199950a04e366fc573bcf4270) fix: wait for the network to be ready in mainteancne mode\n* [`96f89071`](https://github.com/talos-systems/talos/commit/96f89071c3ecd809d912762e40cb9d98ce052018) feat: update controller-runtime logs to console level on config.debug\n* [`973069b6`](https://github.com/talos-systems/talos/commit/973069b611456f758037c9ca4dc50a4a84e7a59c) feat: support NFS 4.1\n* [`654dcad4`](https://github.com/talos-systems/talos/commit/654dcad4753211599d12655ec0f0466f27f49589) chore: bump dependencies via dependabot\n* [`d7394457`](https://github.com/talos-systems/talos/commit/d7394457d978d073690bec589ea78d957539e333) fix: don't treat ethtool errors as fatal\n* [`f2ae9cd0`](https://github.com/talos-systems/talos/commit/f2ae9cd0c1b7d27b5b9971f4820e5feae7934124) feat: replace networkd with new network implementation\n* [`caec3063`](https://github.com/talos-systems/talos/commit/caec3063c82777f82599632ca4914a58515cb9a9) fix: do not complain about empty roles\n* [`11918a11`](https://github.com/talos-systems/talos/commit/11918a110a628d7e0b8749fce92ef572aca47874) docs: update community meeting time\n* [`aeddb9c0`](https://github.com/talos-systems/talos/commit/aeddb9c0977a51e7aca72f69edda8b69d917db13) feat: implement platform config controller (hostnames)\n* [`1ece334d`](https://github.com/talos-systems/talos/commit/1ece334da9d7bb247c385dba08202345b83c1a0f) feat: implement controller which runs network operators\n* [`744ea8a5`](https://github.com/talos-systems/talos/commit/744ea8a5d4b4cb4ff69c2c2fc636e499af892fee) fix: do not add bootstrap contents option if tail events is not 0\n* [`5029edfb`](https://github.com/talos-systems/talos/commit/5029edfb71990581515cabe9634d0519a9988316) fix: overwrite nodes in the gRPC metadata\n* [`6a35c8f1`](https://github.com/talos-systems/talos/commit/6a35c8f110abaf0017530650c55a34f1caae6288) feat: implement virtual IP (shared IP) network operator\n* [`0f3b8380`](https://github.com/talos-systems/talos/commit/0f3b83803d812a30e1418666fa5758734c20e5c2) chore: expose WatchRequest in the resources client\n* [`11e258b1`](https://github.com/talos-systems/talos/commit/11e258b15097493d2b4efd596b2fde2d52579455) feat: implement operator configuration controller\n* [`ce3815e7`](https://github.com/talos-systems/talos/commit/ce3815e75e889de32d9473a23e75863f56b893da) feat: implement DHCP6 operator\n* [`f010d99a`](https://github.com/talos-systems/talos/commit/f010d99afbc6095ad8fe218187fda306c59d3e1e) feat: implement operator framework with DHCP4 as the first example\n* [`f93c9c8f`](https://github.com/talos-systems/talos/commit/f93c9c8fa607a5116274d7e090f49568d01814e7) feat: bring unconfigured links with link carrier up by default\n* [`02bd657b`](https://github.com/talos-systems/talos/commit/02bd657b252ae64ea054b2dc338e55ce9352b420) feat: implement network.Status resource and controller\n* [`da329f00`](https://github.com/talos-systems/talos/commit/da329f00ab0af9f670207da1e13541aef36c4ca6) feat: enable RBAC by default\n* [`0f168a88`](https://github.com/talos-systems/talos/commit/0f168a880143141d8637d21aa9da403383dcf025) feat: add configuration for enabling RBAC\n* [`e74f789b`](https://github.com/talos-systems/talos/commit/e74f789b01b9910f8193415dcefb4b32abcb5f5c) feat: implement EtcFileController to render files in `/etc`\n* [`5aede1a8`](https://github.com/talos-systems/talos/commit/5aede1a83313152bd83891d0cae4b388a54bd9c2) fix: prefer extraConfig over OVF env, skip empty config\n* [`5ad314fe`](https://github.com/talos-systems/talos/commit/5ad314fe7e7cfca8196770071d52b93aa4f767f6) feat: implement basic RBAC interceptors\n* [`c031be81`](https://github.com/talos-systems/talos/commit/c031be8139dbe1f803b70fc9941cfe438b9ddeb9) chore: use Go 1.16.5\n* [`8b0763f6`](https://github.com/talos-systems/talos/commit/8b0763f6a20691d36d2c82f2a756171c55450a8a) chore: bump dependencies via dependabot\n* [`8b8de11d`](https://github.com/talos-systems/talos/commit/8b8de11d9f4d1b1fde43b7fdd56b96d5e3eb5413) feat: implement new controllers for hostname, resolvers and time servers\n* [`24859b14`](https://github.com/talos-systems/talos/commit/24859b14108df7c5895022043d02d4d5ca7660a4) docs: update Rpi4 firmware guide\n* [`62c702c4`](https://github.com/talos-systems/talos/commit/62c702c4fd6e7a11654f542bbe31d1adfc896731) fix: remove conflicting etcd member on rejoin with empty data directory\n* [`ff62a599`](https://github.com/talos-systems/talos/commit/ff62a59984ef0c61dcf549ab38d39584e3630724) fix: drop into maintenance mode if config URL is `none` (metal)\n* [`14e696d0`](https://github.com/talos-systems/talos/commit/14e696d068b5d895b4fefc06bc6d26b4ac2bc450) feat: update COSI runtime and add support for tail in the Talos gRPC\n* [`a71053fc`](https://github.com/talos-systems/talos/commit/a71053fcd88d7651e536ce29b574e18f84678f3e) feat: default to bootstrap workflow\n* [`76aac4bb`](https://github.com/talos-systems/talos/commit/76aac4bb25d8bc6a86458b8ac5be10ca67f236be) feat: implement CPU and Memory stats controller\n* [`8f90c6a8`](https://github.com/talos-systems/talos/commit/8f90c6a8e1d76a3ddecc99be4e4b9f0ce0235daa) feat: parse Talos-specific cmdline params\n* [`ed10e139`](https://github.com/talos-systems/talos/commit/ed10e139c161b0a6e0f3460e21e4e1752b26cb46) feat: implement NodeAddress controller\n* [`33db8857`](https://github.com/talos-systems/talos/commit/33db8857aaf6e411464d08c51560473455e8e156) fix: use COSI runtime DestroyReady input type\n* [`6e775363`](https://github.com/talos-systems/talos/commit/6e775363920b7869b83775d1b674807163039eb1) refactor: rename *.Status() to *.TypedSpec() in the resources\n* [`97627061`](https://github.com/talos-systems/talos/commit/97627061d7e8de90e2f2745efa7497137447d116) docs: set static IP on ISO install mode\n* [`5811f4dd`](https://github.com/talos-systems/talos/commit/5811f4dda1b62848eefae9be56e8b91d443f4d34) feat: implement link (interface) controllers\n* [`046b229b`](https://github.com/talos-systems/talos/commit/046b229b13708c3ffe1d77b8884242fc100097d0) chore: skip building multi-arch installer for race-enabled build\n* [`73fbb4b5`](https://github.com/talos-systems/talos/commit/73fbb4b523b41d266840eced306242d57a332b4d) fix: only fetch machine uuid if it's not set\n* [`f112a540`](https://github.com/talos-systems/talos/commit/f112a540b0e776f06820ee900d6ce9f4f2de02ec) fix: clean up stale snapshots on container start\n* [`c036b949`](https://github.com/talos-systems/talos/commit/c036b949486d94cbbce54c7511633d398f75797c) chore: bump dependencies\n* [`a4d67a01`](https://github.com/talos-systems/talos/commit/a4d67a01820894d3ebf8c65a06345232fae4f93b) feat: add the ability to disable CoreDNS\n* [`76dbfb36`](https://github.com/talos-systems/talos/commit/76dbfb3699df0725a8acf29bff39c43e4aa34f9d) feat: add ability to mark MBR partition bootable\n* [`e0f5b1e2`](https://github.com/talos-systems/talos/commit/e0f5b1e20aa0d22898274ddc0f9026c0d813cee2) chore: split mgmt/gen.go into several files\n* [`fad1b4f1`](https://github.com/talos-systems/talos/commit/fad1b4f1fdce962b779ceb960f81d572ee5033af) chore: fix go generate for the machinery\n* [`1117294a`](https://github.com/talos-systems/talos/commit/1117294ad21945d24b0954d223cc4996df01dd81) release(v0.11.0-alpha.0): prepare release\n* [`c0962946`](https://github.com/talos-systems/talos/commit/c09629466321f4d220454164784edf41fd3d5813) chore: prepare for 0.11 release series\n* [`72359765`](https://github.com/talos-systems/talos/commit/723597657ad78e9766190ea2e110208c62d0093b) feat: enable GORACE=halt_on_panic=1 in machined binary\n* [`0acb04ad`](https://github.com/talos-systems/talos/commit/0acb04ad7a2a0a7b75471f0251b0e04eccd927cd) feat: implement route network controllers\n* [`f5bf88a4`](https://github.com/talos-systems/talos/commit/f5bf88a4c2ab8f48fd93bc7ac13543c613bf9bd1) feat: create certificates with os:admin role\n* [`1db301ed`](https://github.com/talos-systems/talos/commit/1db301edf6a4057814a6d5b8f87fbfe1e020caeb) feat: switch controller-runtime to zap.Logger\n* [`f7cf64d4`](https://github.com/talos-systems/talos/commit/f7cf64d42ec77ca68408ecb0f437ab5f86bc787a) fix: add talos.config to the vApp Properties in VMware OVA\n* [`209527ec`](https://github.com/talos-systems/talos/commit/209527eccc6c93edad33a01a3f3d24fb978f2f07) docs: add AMIs for Talos 0.10.3\n* [`59cfd312`](https://github.com/talos-systems/talos/commit/59cfd312c1ac531528c4ceb2adeb3f85829cc4e1) chore: bump dependencies via dependabot\n* [`1edb20cf`](https://github.com/talos-systems/talos/commit/1edb20cf98fe2e641cefc658d17206e09acabc26) feat: extract config generation\n* [`af77c295`](https://github.com/talos-systems/talos/commit/af77c29565b65766d135884ec7740f67b56626e3) docs: update wirguard guide\n* [`4fe69121`](https://github.com/talos-systems/talos/commit/4fe691214366c08ea846bdc6233dd592da0d4769) test: better `talosctl ls` tests\n* [`04ddda96`](https://github.com/talos-systems/talos/commit/04ddda962fbcfdeaae59d232e7bb7f9c5bb63bc7) feat: update containerd to 1.5.2, runc to 1.0.0-rc95\n* [`49c7276b`](https://github.com/talos-systems/talos/commit/49c7276b16a82b7da8c83f8bd930361768f0e249) chore: fix markdown linting\n* [`7270495a`](https://github.com/talos-systems/talos/commit/7270495ace9faf48a73829bbed0e4eb2c939eecb) docs: add mayastor quickstart\n* [`d3d9112f`](https://github.com/talos-systems/talos/commit/d3d9112f288d3b0f3ebe1c8b28b1c4e2fc8512b2) docs: fix spelling/grammar in What's New for Talos 0.9\n* [`82804414`](https://github.com/talos-systems/talos/commit/82804414fc2fcb21da77edc2fbbefe92a14fc30d) test: provide a way to force different boot order in provision library\n* [`a1c0e99a`](https://github.com/talos-systems/talos/commit/a1c0e99a1729c704a633dcc557dc46466b828e11) docs: add guide for deploying metrics-server\n* [`6bc6658b`](https://github.com/talos-systems/talos/commit/6bc6658b518379d418baafcf9b1045a3b84f48ec) feat: update containerd to 1.5.1\n* [`c6567fae`](https://github.com/talos-systems/talos/commit/c6567fae9c59da5148c9876289a4bf248240b99d) chore: dependabot updates\n* [`61ccbb3f`](https://github.com/talos-systems/talos/commit/61ccbb3f5a2564376af13ea9bbfe51e364fcb3a1) chore: keep debug symbols in debug builds\n* [`1ce362e0`](https://github.com/talos-systems/talos/commit/1ce362e05e41cd76cdda17a6fc971767e036df37) docs: update customizing kernel build steps\n* [`a26174b5`](https://github.com/talos-systems/talos/commit/a26174b54846bdfa0b66d2f9147bfe1dc8f2eb52) fix: properly compose pattern and header in etcd members output\n* [`0825cf11`](https://github.com/talos-systems/talos/commit/0825cf11f412eef930db269b6cae02d059058101) fix: stop networkd and pods before leaving etcd on upgrade\n* [`bed6b15d`](https://github.com/talos-systems/talos/commit/bed6b15d6fcf0634a887b79797d639e221fe9387) fix: properly populate AllowSchedulingOnMasters option in gen config RPC\n* [`071f0445`](https://github.com/talos-systems/talos/commit/071f044562dd247dd54584d7b9fa0bb24d6f7599) feat: implement AddressSpec handling\n* [`76e38b7b`](https://github.com/talos-systems/talos/commit/76e38b7b8251548292ae15ecda2bfa1c8ddc5cf3) feat: update Kubernetes to 1.21.1\n* [`9b1338d9`](https://github.com/talos-systems/talos/commit/9b1338d989e6cdf7e0b6d5fe1ba3c32d27fc2251) chore: parse \"boolean\" variables\n* [`c81cfb21`](https://github.com/talos-systems/talos/commit/c81cfb21670b82e518cf4c32230e8fbbce6be8ff) chore: allow building with debug handlers\n* [`c9651673`](https://github.com/talos-systems/talos/commit/c9651673b9eaf811ae4acfed313debbf78bd80e8) feat: update go-smbios library\n* [`95c656fb`](https://github.com/talos-systems/talos/commit/95c656fb72b6b858b55dae37020cb59ba26115f8) feat: update containerd to 1.5.0, runc to 1.0.0-rc94\n* [`db9c35b5`](https://github.com/talos-systems/talos/commit/db9c35b570b39f4423f4636f9e9f1d14cac5d7c1) feat: implement AddressStatusController\n* [`1cf011a8`](https://github.com/talos-systems/talos/commit/1cf011a809b924fc8f2083566d169704c6e07cd5) chore: bump dependencies via dependabot\n* [`e3f407a1`](https://github.com/talos-systems/talos/commit/e3f407a1dff3f4ee7e024bbfb64f17b5cb5d625d) fix: properly pass disk type selector from config to matcher\n* [`66b2b450`](https://github.com/talos-systems/talos/commit/66b2b450582593e93598fac80c8b3c29e8c8a944) feat: add resources and use HTTPS checks in control plane pods\n* [`4ffd7c0a`](https://github.com/talos-systems/talos/commit/4ffd7c0adf281033ac02d37ca434e7f9ad71e692) fix: stop networkd before leaving etcd on 'reset' path\n* [`610d38d3`](https://github.com/talos-systems/talos/commit/610d38d309dabaa623494ade12234f1ccf018a9e) docs: add AMIs for 0.10.1, collapse list of AMIs by default\n* [`807497ec`](https://github.com/talos-systems/talos/commit/807497ec20dee15953186bda0fe7a45ffec0307c) chore: make conformance pipeline depend on cron-default\n* [`3c121359`](https://github.com/talos-systems/talos/commit/3c1213596cdf03daf09050103f57b29e756439b1) feat: implement LinkStatusController\n* [`0e8de046`](https://github.com/talos-systems/talos/commit/0e8de04698aac95062f3037da0a9af8b6ee916b0) fix: update go-blockdevice to fix disk type detection\n* [`4d50a4ed`](https://github.com/talos-systems/talos/commit/4d50a4edd0eb413c16e899536ccdc2642e37aeaa) fix: update the way NTP sync uses `adjtimex` syscall\n* [`1a85c14a`](https://github.com/talos-systems/talos/commit/1a85c14a51fdab43ae84274563bf89b30e4e6d92) fix: avoid data race on CRI pod stop\n* [`5de8dbc0`](https://github.com/talos-systems/talos/commit/5de8dbc06c7ed36c8f3af9adea8b1abedeb372b6) fix: repair pine64 support\n* [`38239097`](https://github.com/talos-systems/talos/commit/3823909735859f2ac5d95bc39c051fc9c2c07685) fix: properly parse matcher expressions\n* [`e54b6b7a`](https://github.com/talos-systems/talos/commit/e54b6b7a3d7412ddce1467dfbd35efe3cfd76f3f) chore: update dependencies via dependabot\n* [`f2caed0d`](https://github.com/talos-systems/talos/commit/f2caed0df5b76c4a719f968191081a6e5e2e95c7) chore: use extracted talos-systems/go-kmsg library\n* [`79d804c5`](https://github.com/talos-systems/talos/commit/79d804c5b4af50a0fd73db17d2522d6a6b45c9ca) docs: fix typos\n* [`a2bb390e`](https://github.com/talos-systems/talos/commit/a2bb390e1d56106d6d3c1526f3f76b34846b0274) feat: deterministic builds\n* [`e480fedf`](https://github.com/talos-systems/talos/commit/e480fedff047233e78ad2c22e7b84cbbb22798d5) feat: add USB serial drivers\n* [`79299d76`](https://github.com/talos-systems/talos/commit/79299d761c50aff386ab7b3c12f39c1797585632) docs: add Matrix room links\n* [`1b3e8b09`](https://github.com/talos-systems/talos/commit/1b3e8b09edcd51cf3df2d43d14c8fbf1e912a465) docs: add survey to README\n* [`8d51c9bb`](https://github.com/talos-systems/talos/commit/8d51c9bb190c2c60fa9be6a00572d2eaf4221e94) docs: update redirects to Talos 0.10\n* [`1092c3a5`](https://github.com/talos-systems/talos/commit/1092c3a5069a3add439860d90c3615111fa03c98) feat: add Pine64 SBC support\n* [`63e01754`](https://github.com/talos-systems/talos/commit/63e0175437e45c8f7e5296841337a640c600982c) feat: pull kernel with VMware balloon module enabled\n* [`aeec99d8`](https://github.com/talos-systems/talos/commit/aeec99d8247f4eb534e0db1ed639f95cd726fe08) chore: remove temporary fork\n* [`0f49722d`](https://github.com/talos-systems/talos/commit/0f49722d0ff4e731f17a55d1ca50472714334748) feat: add `--config-patch` flag by node type\n* [`a01b1d22`](https://github.com/talos-systems/talos/commit/a01b1d22d9f3fa94355817217fefd80fe34628f3) chore: dump dependencies via dependabot\n* [`d540a4a4`](https://github.com/talos-systems/talos/commit/d540a4a4711367a0ada203f668382e39876ba081) fix: bump crypto library for the CSR verification fix\n* [`c3a4173e`](https://github.com/talos-systems/talos/commit/c3a4173e11a92c2bc51ea4f284ad38c9750105d2) chore: remove security API ReadFile/WriteFile\n* [`38037131`](https://github.com/talos-systems/talos/commit/38037131cddc2aefbae0f48fb7e355ec76247b67) chore: update wgctrl dependecy\n* [`d9ba0fd0`](https://github.com/talos-systems/talos/commit/d9ba0fd0164b2bfb2bc4ffe7a2d9d6c665a38e4d) docs: create v0.11 docs, promote v0.10 docs, add v0.10 AMIs\n* [`2261d7ed`](https://github.com/talos-systems/talos/commit/2261d7ed0212c287273eac647647e4390c530a6e) fix: use both self-signed and Kubernetes CA to verify Kubelet cert\n* [`a3537a69`](https://github.com/talos-systems/talos/commit/a3537a691320430eeb7149abe73419ee242312fc) docs: update cloud images for Talos v0.9.3\n* [`5b9ee861`](https://github.com/talos-systems/talos/commit/5b9ee86179fb92989b02533d6d6745a5b0f37566) docs: add what's new for Talos 0.10\n* [`f1107fa3`](https://github.com/talos-systems/talos/commit/f1107fa3a33955f3aa57a49991c87f9ee47b6e67) docs: add survey\n* [`93623d47`](https://github.com/talos-systems/talos/commit/93623d47f24fef0d149fa006678b61e3182ef771) docs: update AWS instructions\n* [`a739d1b8`](https://github.com/talos-systems/talos/commit/a739d1b8adbc026796d1c55f7319677f9010f727) feat: add support of custom registry CA certificate usage\n* [`7f468d35`](https://github.com/talos-systems/talos/commit/7f468d350a6f80d2815149376fa24f7d7629402c) fix: update osType in OVA other3xLinux64Guest\"\n* [`4a184b67`](https://github.com/talos-systems/talos/commit/4a184b67d6ae25b21b35373e7dd6eab41b042c96) docs: add etcd backup and restore guide\n* [`5fb38d3e`](https://github.com/talos-systems/talos/commit/5fb38d3e5f201934d64bae186c5300e7de7af3d4) chore: refactor Dockerfile for cross-compilation\n* [`a8f1e526`](https://github.com/talos-systems/talos/commit/a8f1e526bfc00107c915572df2be08b3f154f4e6) chore: build talosctl for Darwin / Apple Silicon\n* [`eb0b64d3`](https://github.com/talos-systems/talos/commit/eb0b64d3138228a6c751387c720ca81c338b834d) chore: list specifically for enabled regions\n* [`669a0cbd`](https://github.com/talos-systems/talos/commit/669a0cbdc4756f0ad8f0dacc56a20f71e96fe4cd) fix: check if OVF env is empty\n* [`da92049c`](https://github.com/talos-systems/talos/commit/da92049c0b4beae32af80205f50849443cd6dad3) chore: use codecov from the build container\n* [`9996d4b0`](https://github.com/talos-systems/talos/commit/9996d4b028f3845071850def75f2b534e4d2b190) chore: use REGISTRY_MIRROR_FLAGS if defined\n* [`05cbe250`](https://github.com/talos-systems/talos/commit/05cbe250c87339e097d435d6b10b9d8a5f2eb49e) chore: bump dependencies via dependabot\n* [`9a91142a`](https://github.com/talos-systems/talos/commit/9a91142a38b3b1f210773acf8df01ed6a45599c2) feat: print complete member info in etcd members\n* [`bb40d6dd`](https://github.com/talos-systems/talos/commit/bb40d6dd06a967464c24ab33744bbf460aa84038) feat: update pkgs version\n* [`e7a9164b`](https://github.com/talos-systems/talos/commit/e7a9164b1e1630f953a420d99c865aef6e652d15) test: implement `talosctl conformance` command to run e2e tests\n* [`6cb266e7`](https://github.com/talos-systems/talos/commit/6cb266e74e60d9d5423feaad550a7861dc73f11d) fix: update etcd client errors, print etcd join failures\n* [`0bd8b0e8`](https://github.com/talos-systems/talos/commit/0bd8b0e8008c12e4914c6e9b5faf06dda6c744f7) feat: provide an option to recover etcd from data directory copy\n* [`f9818540`](https://github.com/talos-systems/talos/commit/f98185408d618ebcc780247ea2c42239df27a74e) chore: fix conform with scopes\n* [`21018f28`](https://github.com/talos-systems/talos/commit/21018f28c732719535c30c8e1abdbb346f1dc4bf) chore: bump website node.js dependencies\n</p>\n</details>\n\n### Changes since v0.11.0-alpha.0\n<details><summary>60 commits</summary>\n<p>\n\n* [`f8e1cf09`](https://github.com/talos-systems/talos/commit/f8e1cf09d09c5a3d8c8ed0bdcae3d564a97e6446) release(v0.11.0-alpha.1): prepare release\n* [`70ac771e`](https://github.com/talos-systems/talos/commit/70ac771e0846247dbebf484aca20ef950d8b99c7) fix: use localhost API server endpoint for internal communication\n* [`a941eb7d`](https://github.com/talos-systems/talos/commit/a941eb7da06246d59cec1b63883f2d7e3f91ce73) feat: improve security of Kubernetes control plane components\n* [`3aae94e5`](https://github.com/talos-systems/talos/commit/3aae94e5306c0d6e31df4aee127ee3562709edd3) feat: provide Kubernetes nodename as a COSI resource\n* [`06209bba`](https://github.com/talos-systems/talos/commit/06209bba2867829561a60f0e7cd9847fa9a8edd3) chore: update RBAC rules, remove old APIs\n* [`9f24b519`](https://github.com/talos-systems/talos/commit/9f24b519dce07ce05099b242ba95e8a1e319630e) chore: remove bootkube check from cluster health check\n* [`4ac9bea2`](https://github.com/talos-systems/talos/commit/4ac9bea27dc098ebdfdc0958f3000d960fad50de) fix: stop etcd client logs from going to the server console\n* [`f63ab9dd`](https://github.com/talos-systems/talos/commit/f63ab9dd9bb6c734873dc8073892f5f10a2ed2e1) feat: implement `talosctl config new` command\n* [`fa15a668`](https://github.com/talos-systems/talos/commit/fa15a6687fc56820fbc5566d494bedbc1a5f600f) fix: don't enable RBAC feature in the config for Talos < 0.11\n* [`2dc27d99`](https://github.com/talos-systems/talos/commit/2dc27d9964fa3df08a6ec11c0b045d7325ea0d2b) fix: do not format state partition in the initialize sequence\n* [`b609f33c`](https://github.com/talos-systems/talos/commit/b609f33cdebb0659738d4fa3802035b2b344b9b9) fix: update networking stack after Equnix Metal testing\n* [`243a3b53`](https://github.com/talos-systems/talos/commit/243a3b53e0e7591d5958a3b8373ab963990c40d6) fix: separate healthy and unknown flags in the service resource\n* [`1a1378be`](https://github.com/talos-systems/talos/commit/1a1378be16fdce45273bdc81fb72715c4766ee4b) fix: update retry package with a fix for errors.Is\n* [`cb83edd7`](https://github.com/talos-systems/talos/commit/cb83edd7fcf14bd199950a04e366fc573bcf4270) fix: wait for the network to be ready in mainteancne mode\n* [`96f89071`](https://github.com/talos-systems/talos/commit/96f89071c3ecd809d912762e40cb9d98ce052018) feat: update controller-runtime logs to console level on config.debug\n* [`973069b6`](https://github.com/talos-systems/talos/commit/973069b611456f758037c9ca4dc50a4a84e7a59c) feat: support NFS 4.1\n* [`654dcad4`](https://github.com/talos-systems/talos/commit/654dcad4753211599d12655ec0f0466f27f49589) chore: bump dependencies via dependabot\n* [`d7394457`](https://github.com/talos-systems/talos/commit/d7394457d978d073690bec589ea78d957539e333) fix: don't treat ethtool errors as fatal\n* [`f2ae9cd0`](https://github.com/talos-systems/talos/commit/f2ae9cd0c1b7d27b5b9971f4820e5feae7934124) feat: replace networkd with new network implementation\n* [`caec3063`](https://github.com/talos-systems/talos/commit/caec3063c82777f82599632ca4914a58515cb9a9) fix: do not complain about empty roles\n* [`11918a11`](https://github.com/talos-systems/talos/commit/11918a110a628d7e0b8749fce92ef572aca47874) docs: update community meeting time\n* [`aeddb9c0`](https://github.com/talos-systems/talos/commit/aeddb9c0977a51e7aca72f69edda8b69d917db13) feat: implement platform config controller (hostnames)\n* [`1ece334d`](https://github.com/talos-systems/talos/commit/1ece334da9d7bb247c385dba08202345b83c1a0f) feat: implement controller which runs network operators\n* [`744ea8a5`](https://github.com/talos-systems/talos/commit/744ea8a5d4b4cb4ff69c2c2fc636e499af892fee) fix: do not add bootstrap contents option if tail events is not 0\n* [`5029edfb`](https://github.com/talos-systems/talos/commit/5029edfb71990581515cabe9634d0519a9988316) fix: overwrite nodes in the gRPC metadata\n* [`6a35c8f1`](https://github.com/talos-systems/talos/commit/6a35c8f110abaf0017530650c55a34f1caae6288) feat: implement virtual IP (shared IP) network operator\n* [`0f3b8380`](https://github.com/talos-systems/talos/commit/0f3b83803d812a30e1418666fa5758734c20e5c2) chore: expose WatchRequest in the resources client\n* [`11e258b1`](https://github.com/talos-systems/talos/commit/11e258b15097493d2b4efd596b2fde2d52579455) feat: implement operator configuration controller\n* [`ce3815e7`](https://github.com/talos-systems/talos/commit/ce3815e75e889de32d9473a23e75863f56b893da) feat: implement DHCP6 operator\n* [`f010d99a`](https://github.com/talos-systems/talos/commit/f010d99afbc6095ad8fe218187fda306c59d3e1e) feat: implement operator framework with DHCP4 as the first example\n* [`f93c9c8f`](https://github.com/talos-systems/talos/commit/f93c9c8fa607a5116274d7e090f49568d01814e7) feat: bring unconfigured links with link carrier up by default\n* [`02bd657b`](https://github.com/talos-systems/talos/commit/02bd657b252ae64ea054b2dc338e55ce9352b420) feat: implement network.Status resource and controller\n* [`da329f00`](https://github.com/talos-systems/talos/commit/da329f00ab0af9f670207da1e13541aef36c4ca6) feat: enable RBAC by default\n* [`0f168a88`](https://github.com/talos-systems/talos/commit/0f168a880143141d8637d21aa9da403383dcf025) feat: add configuration for enabling RBAC\n* [`e74f789b`](https://github.com/talos-systems/talos/commit/e74f789b01b9910f8193415dcefb4b32abcb5f5c) feat: implement EtcFileController to render files in `/etc`\n* [`5aede1a8`](https://github.com/talos-systems/talos/commit/5aede1a83313152bd83891d0cae4b388a54bd9c2) fix: prefer extraConfig over OVF env, skip empty config\n* [`5ad314fe`](https://github.com/talos-systems/talos/commit/5ad314fe7e7cfca8196770071d52b93aa4f767f6) feat: implement basic RBAC interceptors\n* [`c031be81`](https://github.com/talos-systems/talos/commit/c031be8139dbe1f803b70fc9941cfe438b9ddeb9) chore: use Go 1.16.5\n* [`8b0763f6`](https://github.com/talos-systems/talos/commit/8b0763f6a20691d36d2c82f2a756171c55450a8a) chore: bump dependencies via dependabot\n* [`8b8de11d`](https://github.com/talos-systems/talos/commit/8b8de11d9f4d1b1fde43b7fdd56b96d5e3eb5413) feat: implement new controllers for hostname, resolvers and time servers\n* [`24859b14`](https://github.com/talos-systems/talos/commit/24859b14108df7c5895022043d02d4d5ca7660a4) docs: update Rpi4 firmware guide\n* [`62c702c4`](https://github.com/talos-systems/talos/commit/62c702c4fd6e7a11654f542bbe31d1adfc896731) fix: remove conflicting etcd member on rejoin with empty data directory\n* [`ff62a599`](https://github.com/talos-systems/talos/commit/ff62a59984ef0c61dcf549ab38d39584e3630724) fix: drop into maintenance mode if config URL is `none` (metal)\n* [`14e696d0`](https://github.com/talos-systems/talos/commit/14e696d068b5d895b4fefc06bc6d26b4ac2bc450) feat: update COSI runtime and add support for tail in the Talos gRPC\n* [`a71053fc`](https://github.com/talos-systems/talos/commit/a71053fcd88d7651e536ce29b574e18f84678f3e) feat: default to bootstrap workflow\n* [`76aac4bb`](https://github.com/talos-systems/talos/commit/76aac4bb25d8bc6a86458b8ac5be10ca67f236be) feat: implement CPU and Memory stats controller\n* [`8f90c6a8`](https://github.com/talos-systems/talos/commit/8f90c6a8e1d76a3ddecc99be4e4b9f0ce0235daa) feat: parse Talos-specific cmdline params\n* [`ed10e139`](https://github.com/talos-systems/talos/commit/ed10e139c161b0a6e0f3460e21e4e1752b26cb46) feat: implement NodeAddress controller\n* [`33db8857`](https://github.com/talos-systems/talos/commit/33db8857aaf6e411464d08c51560473455e8e156) fix: use COSI runtime DestroyReady input type\n* [`6e775363`](https://github.com/talos-systems/talos/commit/6e775363920b7869b83775d1b674807163039eb1) refactor: rename *.Status() to *.TypedSpec() in the resources\n* [`97627061`](https://github.com/talos-systems/talos/commit/97627061d7e8de90e2f2745efa7497137447d116) docs: set static IP on ISO install mode\n* [`5811f4dd`](https://github.com/talos-systems/talos/commit/5811f4dda1b62848eefae9be56e8b91d443f4d34) feat: implement link (interface) controllers\n* [`046b229b`](https://github.com/talos-systems/talos/commit/046b229b13708c3ffe1d77b8884242fc100097d0) chore: skip building multi-arch installer for race-enabled build\n* [`73fbb4b5`](https://github.com/talos-systems/talos/commit/73fbb4b523b41d266840eced306242d57a332b4d) fix: only fetch machine uuid if it's not set\n* [`f112a540`](https://github.com/talos-systems/talos/commit/f112a540b0e776f06820ee900d6ce9f4f2de02ec) fix: clean up stale snapshots on container start\n* [`c036b949`](https://github.com/talos-systems/talos/commit/c036b949486d94cbbce54c7511633d398f75797c) chore: bump dependencies\n* [`a4d67a01`](https://github.com/talos-systems/talos/commit/a4d67a01820894d3ebf8c65a06345232fae4f93b) feat: add the ability to disable CoreDNS\n* [`76dbfb36`](https://github.com/talos-systems/talos/commit/76dbfb3699df0725a8acf29bff39c43e4aa34f9d) feat: add ability to mark MBR partition bootable\n* [`e0f5b1e2`](https://github.com/talos-systems/talos/commit/e0f5b1e20aa0d22898274ddc0f9026c0d813cee2) chore: split mgmt/gen.go into several files\n* [`fad1b4f1`](https://github.com/talos-systems/talos/commit/fad1b4f1fdce962b779ceb960f81d572ee5033af) chore: fix go generate for the machinery\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>7 commits</summary>\n<p>\n\n* [`6bc5bb5`](https://github.com/talos-systems/crypto/commit/6bc5bb50c52767296a1b1cab6580e3fcf1358f34) chore: remove unused argument\n* [`cd18ef6`](https://github.com/talos-systems/crypto/commit/cd18ef62eb9f65d8b6730a2eb73e47e629949e1b) feat: add support for several organizations\n* [`97c888b`](https://github.com/talos-systems/crypto/commit/97c888b3924dd5ac70b8d30dd66b4370b5ab1edc) chore: add options to CSR\n* [`7776057`](https://github.com/talos-systems/crypto/commit/7776057f5086157873f62f6a21ec23fa9fd86e05) chore: fix typos\n* [`80df078`](https://github.com/talos-systems/crypto/commit/80df078327030af7e822668405bb4853c512bd7c) chore: remove named result parameters\n* [`15bdd28`](https://github.com/talos-systems/crypto/commit/15bdd282b74ac406ab243853c1b50338a1bc29d0) chore: minor updates\n* [`4f80b97`](https://github.com/talos-systems/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`4fe2706`](https://github.com/talos-systems/extras/commit/4fe27060347c861b716392eec3dfee698becb5f3) feat: build with Go 1.16.5\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>3 commits</summary>\n<p>\n\n* [`30c2bc3`](https://github.com/talos-systems/go-blockdevice/commit/30c2bc3cb62af52f0aea9ce347923b0649fb7928) feat: mark MBR bootable\n* [`1292574`](https://github.com/talos-systems/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/talos-systems/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n</p>\n</details>\n\n### Changes from talos-systems/go-debug\n<details><summary>5 commits</summary>\n<p>\n\n* [`3d0a6e1`](https://github.com/talos-systems/go-debug/commit/3d0a6e1bf5e3c521e83ead2c8b7faad3638b8c5d) feat: race build tag flag detector\n* [`5b292e5`](https://github.com/talos-systems/go-debug/commit/5b292e50198b8ed91c434f00e2772db394dbf0b9) feat: disable memory profiling by default\n* [`c6d0ae2`](https://github.com/talos-systems/go-debug/commit/c6d0ae2c0ee099fa0940405401e6a02716a15bd8) fix: linters and CI\n* [`d969f95`](https://github.com/talos-systems/go-debug/commit/d969f952af9e02feea59963671298fc236ca4399) feat: initial implementation\n* [`b2044b7`](https://github.com/talos-systems/go-debug/commit/b2044b70379c84f9706de74044bd2fd6a8e891cf) Initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-kmsg\n<details><summary>2 commits</summary>\n<p>\n\n* [`2edcd3a`](https://github.com/talos-systems/go-kmsg/commit/2edcd3a913508e2d922776f729bfc4bcab031a8b) feat: add initial version\n* [`53cdd8d`](https://github.com/talos-systems/go-kmsg/commit/53cdd8d67b9dbab692471a2d5161e7e0b3d04cca) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-loadbalancer\n<details><summary>3 commits</summary>\n<p>\n\n* [`a445702`](https://github.com/talos-systems/go-loadbalancer/commit/a4457024d5189d754b2da4a30b14072a0e3f5f05) feat: allow dial timeout and keep alive period to be configurable\n* [`3c8f347`](https://github.com/talos-systems/go-loadbalancer/commit/3c8f3471d14e37866c65f73170ef83c038ae5a8c) feat: provide a way to configure logger for the loadbalancer\n* [`da8e987`](https://github.com/talos-systems/go-loadbalancer/commit/da8e987434c3d407679a40e213b12a8e1c98abb8) feat: implement Reconcile - ability to change upstream list on the fly\n</p>\n</details>\n\n### Changes from talos-systems/go-retry\n<details><summary>3 commits</summary>\n<p>\n\n* [`c78cc95`](https://github.com/talos-systems/go-retry/commit/c78cc953d9e95992575305b4e8648392c6c9b9e6) fix: implement `errors.Is` for all errors in the set\n* [`7885e16`](https://github.com/talos-systems/go-retry/commit/7885e16b2cb0267bcc8b07cdd0eced14e8005864) feat: add ExpectedErrorf\n* [`3d83f61`](https://github.com/talos-systems/go-retry/commit/3d83f6126c1a3a238d1d1d59bfb6273e4087bdac) feat: deprecate UnexpectedError\n</p>\n</details>\n\n### Changes from talos-systems/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`d3a32be`](https://github.com/talos-systems/go-smbios/commit/d3a32bea731a0c2a60ce7f5eae60253300ef27e1) fix: return UUID in middle endian only on SMBIOS >= 2.6\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>18 commits</summary>\n<p>\n\n* [`2d51360`](https://github.com/talos-systems/pkgs/commit/2d51360a254b237943e92cd445e42912d39fce7a) feat: support NFS 4.1\n* [`e63e4e9`](https://github.com/talos-systems/pkgs/commit/e63e4e97b4c398e090028eaf7b967cc9eafadf96) feat: bump tools for Go 1.16.5\n* [`1f8af29`](https://github.com/talos-systems/pkgs/commit/1f8af290e5d242f7dfc784fd2fc7fcfd714500bd) feat: update Linux to 5.10.38\n* [`a3a6650`](https://github.com/talos-systems/pkgs/commit/a3a66505f36b9e9f92f4980df3708a872d56caec) feat: update containerd to 1.5.2\n* [`c70ea44`](https://github.com/talos-systems/pkgs/commit/c70ea44ba4bc1ffabdb1422deda107a94e1fe94c) feat: update runc to 1.0.0-rc95\n* [`db60235`](https://github.com/talos-systems/pkgs/commit/db602359cc594b35291911b4220dc5b331b323bb) feat: add support for netxen card\n* [`f934187`](https://github.com/talos-systems/pkgs/commit/f934187ebdc455f18cc6d2da847be3d48a6e3d8f) feat: update containerd to 1.5.1\n* [`e8ed5bc`](https://github.com/talos-systems/pkgs/commit/e8ed5bcb848954ca30967de8d7c81afecdea4825) feat: add geneve encapsulation support for openvswitch\n* [`9f7903c`](https://github.com/talos-systems/pkgs/commit/9f7903cb5c110f77db8093347b69ec141325d47c) feat: update containerd to 1.5.0, runc to -rc94\n* [`d7c0f70`](https://github.com/talos-systems/pkgs/commit/d7c0f70e41bb7bf542092f2882b062ff52f5ae44) feat: add AES-NI support for amd64\n* [`b0d9cd2`](https://github.com/talos-systems/pkgs/commit/b0d9cd2c36e37190c5ce7b85acea6a51a853faaf) fix: build `zbin` utility for both amd64 and arm64\n* [`bb39b97`](https://github.com/talos-systems/pkgs/commit/bb39b9744c0c4a29ccfa190a0d2cce0f8547676b) feat: add IPMI support in kernel\n* [`1148f9a`](https://github.com/talos-systems/pkgs/commit/1148f9a897d9a52b6013396151e1eab264709037) feat: add DS1307 RTC support for arm64\n* [`350aa6f`](https://github.com/talos-systems/pkgs/commit/350aa6f200d441d7dbbf60ec8ebb39a6761d6a8b) feat: add USB serial support\n* [`de9c582`](https://github.com/talos-systems/pkgs/commit/de9c58238483219a574fb697ddb1126f36a02da3) feat: add Pine64 SBC support\n* [`b56f36b`](https://github.com/talos-systems/pkgs/commit/b56f36bedbe9270ae5cf969f8078a10345457e83) feat: enable VMware baloon kernel module\n* [`f87c194`](https://github.com/talos-systems/pkgs/commit/f87c19425352eb9b68d20dec987d0c484987dea9) feat: add iPXE build with embedded placeholder script\n* [`a8b9e71`](https://github.com/talos-systems/pkgs/commit/a8b9e71e6538d7554b7a48d1361709d5495bb4de) feat: add cpu scaling for rpi\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>1 commit</summary>\n<p>\n\n* [`c8c2a18`](https://github.com/talos-systems/tools/commit/c8c2a18b7e587e0b8464574e375a680c5a09a028) feat: update Go to 1.16.5\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/aws/aws-sdk-go**                     v1.27.0 **_new_**\n* **github.com/containerd/cgroups**                 4cbc285b3327 -> v1.0.1\n* **github.com/containerd/containerd**              v1.4.4 -> v1.5.2\n* **github.com/containerd/go-cni**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/typeurl**                 v1.0.1 -> v1.0.2\n* **github.com/coreos/go-iptables**                 v0.5.0 -> v0.6.0\n* **github.com/cosi-project/runtime**               10d6103c19ab -> ca95c7538d17\n* **github.com/docker/docker**                      v20.10.4 -> v20.10.7\n* **github.com/emicklei/dot**                       v0.15.0 -> v0.16.0\n* **github.com/fatih/color**                        v1.10.0 -> v1.12.0\n* **github.com/google/go-cmp**                      v0.5.5 -> v0.5.6\n* **github.com/google/gofuzz**                      v1.2.0 **_new_**\n* **github.com/googleapis/gnostic**                 v0.5.5 **_new_**\n* **github.com/grpc-ecosystem/go-grpc-middleware**  v1.2.2 -> v1.3.0\n* **github.com/hashicorp/go-getter**                v1.5.2 -> v1.5.3\n* **github.com/imdario/mergo**                      v0.3.12 **_new_**\n* **github.com/insomniacslk/dhcp**                  cc9239ac6294 -> fb4eaaa00ad2\n* **github.com/jsimonetti/rtnetlink**               1b79e63a70a0 -> b34cb89a106b\n* **github.com/magiconair/properties**              v1.8.5 **_new_**\n* **github.com/mattn/go-isatty**                    v0.0.12 -> v0.0.13\n* **github.com/mdlayher/arp**                       f72070a231fc **_new_**\n* **github.com/mdlayher/ethtool**                   2b88debcdd43 **_new_**\n* **github.com/mdlayher/netlink**                   v1.4.0 -> v1.4.1\n* **github.com/mdlayher/raw**                       51b895745faf **_new_**\n* **github.com/mitchellh/mapstructure**             v1.4.1 **_new_**\n* **github.com/opencontainers/runtime-spec**        4d89ac9fbff6 -> e6143ca7d51d\n* **github.com/pelletier/go-toml**                  v1.9.0 **_new_**\n* **github.com/rivo/tview**                         8a8f78a6dd01 -> 807e706f86d1\n* **github.com/rs/xid**                             v1.2.1 -> v1.3.0\n* **github.com/sirupsen/logrus**                    v1.8.1 **_new_**\n* **github.com/spf13/afero**                        v1.6.0 **_new_**\n* **github.com/spf13/cast**                         v1.3.1 **_new_**\n* **github.com/spf13/viper**                        v1.7.1 **_new_**\n* **github.com/talos-systems/crypto**               39584f1b6e54 -> 6bc5bb50c527\n* **github.com/talos-systems/extras**               v0.3.0 -> v0.3.0-1-g4fe2706\n* **github.com/talos-systems/go-blockdevice**       1d830a25f64f -> 30c2bc3cb62a\n* **github.com/talos-systems/go-debug**             3d0a6e1bf5e3 **_new_**\n* **github.com/talos-systems/go-kmsg**              v0.1.0 **_new_**\n* **github.com/talos-systems/go-loadbalancer**      v0.1.0 -> v0.1.1\n* **github.com/talos-systems/go-retry**             b9dc1a990133 -> c78cc953d9e9\n* **github.com/talos-systems/go-smbios**            fb425d4727e6 -> d3a32bea731a\n* **github.com/talos-systems/pkgs**                 v0.5.0-1-g5dd650b -> v0.6.0-alpha.0-8-g2d51360\n* **github.com/talos-systems/talos/pkg/machinery**  8ffb55943c71 -> 000000000000\n* **github.com/talos-systems/tools**                v0.5.0 -> v0.5.0-1-gc8c2a18\n* **github.com/vishvananda/netns**                  2eb08e3e575f **_new_**\n* **github.com/vmware-tanzu/sonobuoy**              v0.20.0 -> v0.51.0\n* **github.com/vmware/govmomi**                     v0.24.0 -> v0.26.0\n* **go.etcd.io/etcd/api/v3**                        v3.5.0-alpha.0 -> v3.5.0-rc.1\n* **go.etcd.io/etcd/client/pkg/v3**                 v3.5.0-rc.1 **_new_**\n* **go.etcd.io/etcd/client/v3**                     v3.5.0-alpha.0 -> v3.5.0-rc.1\n* **go.etcd.io/etcd/etcdutl/v3**                    v3.5.0-rc.1 **_new_**\n* **go.uber.org/zap**                               v1.17.0 **_new_**\n* **golang.org/x/net**                              e18ecbb05110 -> abc453219eb5\n* **golang.org/x/oauth2**                           81ed05c6b58c **_new_**\n* **golang.org/x/sys**                              77cc2087c03b -> ebe580a85c40\n* **golang.org/x/term**                             6a3ed077a48d -> a79de5458b56\n* **golang.zx2c4.com/wireguard/wgctrl**             bd2cb7843e1b -> 92e472f520a5\n* **google.golang.org/appengine**                   v1.6.7 **_new_**\n* **google.golang.org/grpc**                        v1.37.0 -> v1.38.0\n* **gopkg.in/ini.v1**                               v1.62.0 **_new_**\n* **inet.af/netaddr**                               1d252cf8125e **_new_**\n* **k8s.io/api**                                    v0.21.0 -> v0.21.1\n* **k8s.io/apimachinery**                           v0.21.0 -> v0.21.1\n* **k8s.io/apiserver**                              v0.21.0 -> v0.21.1\n* **k8s.io/client-go**                              v0.21.0 -> v0.21.1\n* **k8s.io/kubectl**                                v0.21.0 -> v0.21.1\n* **k8s.io/kubelet**                                v0.21.0 -> v0.21.1\n* **k8s.io/utils**                                  2afb4311ab10 **_new_**\n* **sigs.k8s.io/structured-merge-diff/v4**          v4.1.1 **_new_**\n\nPrevious release can be found at [v0.10.0](https://github.com/talos-systems/talos/releases/tag/v0.10.0)\n\n## [Talos 0.11.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.11.0-alpha.0) (2021-05-26)\n\nWelcome to the v0.11.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Component Updates\n\n* containerd was updated to 1.5.2\n* Linux kernel was updated to 5.10.29\n\n\n### Multi-arch Installer\n\nTalos installer image (for any arch) now contains artifacts for both `amd64` and `arm64` architecture.\nThis means that e.g. images for arm64 SBCs can be generated on amd64 host.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Jorik Jonker\n* Spencer Smith\n* Serge Logvinov\n* Andrew LeCody\n* Andrew Rynhard\n* Boran Car\n* Brandon Nason\n* Gabor Nyiri\n* Joost Coelingh\n* Kevin Hellemun\n* Lance R. Vick\n* Lennard Klein\n* Seán C McCord\n* Sébastien Bernard\n* Sébastien Bernard\n\n### Changes\n<details><summary>82 commits</summary>\n<p>\n\n* [`c0962946`](https://github.com/talos-systems/talos/commit/c09629466321f4d220454164784edf41fd3d5813) chore: prepare for 0.11 release series\n* [`72359765`](https://github.com/talos-systems/talos/commit/723597657ad78e9766190ea2e110208c62d0093b) feat: enable GORACE=halt_on_panic=1 in machined binary\n* [`0acb04ad`](https://github.com/talos-systems/talos/commit/0acb04ad7a2a0a7b75471f0251b0e04eccd927cd) feat: implement route network controllers\n* [`f5bf88a4`](https://github.com/talos-systems/talos/commit/f5bf88a4c2ab8f48fd93bc7ac13543c613bf9bd1) feat: create certificates with os:admin role\n* [`1db301ed`](https://github.com/talos-systems/talos/commit/1db301edf6a4057814a6d5b8f87fbfe1e020caeb) feat: switch controller-runtime to zap.Logger\n* [`f7cf64d4`](https://github.com/talos-systems/talos/commit/f7cf64d42ec77ca68408ecb0f437ab5f86bc787a) fix: add talos.config to the vApp Properties in VMware OVA\n* [`209527ec`](https://github.com/talos-systems/talos/commit/209527eccc6c93edad33a01a3f3d24fb978f2f07) docs: add AMIs for Talos 0.10.3\n* [`59cfd312`](https://github.com/talos-systems/talos/commit/59cfd312c1ac531528c4ceb2adeb3f85829cc4e1) chore: bump dependencies via dependabot\n* [`1edb20cf`](https://github.com/talos-systems/talos/commit/1edb20cf98fe2e641cefc658d17206e09acabc26) feat: extract config generation\n* [`af77c295`](https://github.com/talos-systems/talos/commit/af77c29565b65766d135884ec7740f67b56626e3) docs: update wirguard guide\n* [`4fe69121`](https://github.com/talos-systems/talos/commit/4fe691214366c08ea846bdc6233dd592da0d4769) test: better `talosctl ls` tests\n* [`04ddda96`](https://github.com/talos-systems/talos/commit/04ddda962fbcfdeaae59d232e7bb7f9c5bb63bc7) feat: update containerd to 1.5.2, runc to 1.0.0-rc95\n* [`49c7276b`](https://github.com/talos-systems/talos/commit/49c7276b16a82b7da8c83f8bd930361768f0e249) chore: fix markdown linting\n* [`7270495a`](https://github.com/talos-systems/talos/commit/7270495ace9faf48a73829bbed0e4eb2c939eecb) docs: add mayastor quickstart\n* [`d3d9112f`](https://github.com/talos-systems/talos/commit/d3d9112f288d3b0f3ebe1c8b28b1c4e2fc8512b2) docs: fix spelling/grammar in What's New for Talos 0.9\n* [`82804414`](https://github.com/talos-systems/talos/commit/82804414fc2fcb21da77edc2fbbefe92a14fc30d) test: provide a way to force different boot order in provision library\n* [`a1c0e99a`](https://github.com/talos-systems/talos/commit/a1c0e99a1729c704a633dcc557dc46466b828e11) docs: add guide for deploying metrics-server\n* [`6bc6658b`](https://github.com/talos-systems/talos/commit/6bc6658b518379d418baafcf9b1045a3b84f48ec) feat: update containerd to 1.5.1\n* [`c6567fae`](https://github.com/talos-systems/talos/commit/c6567fae9c59da5148c9876289a4bf248240b99d) chore: dependabot updates\n* [`61ccbb3f`](https://github.com/talos-systems/talos/commit/61ccbb3f5a2564376af13ea9bbfe51e364fcb3a1) chore: keep debug symbols in debug builds\n* [`1ce362e0`](https://github.com/talos-systems/talos/commit/1ce362e05e41cd76cdda17a6fc971767e036df37) docs: update customizing kernel build steps\n* [`a26174b5`](https://github.com/talos-systems/talos/commit/a26174b54846bdfa0b66d2f9147bfe1dc8f2eb52) fix: properly compose pattern and header in etcd members output\n* [`0825cf11`](https://github.com/talos-systems/talos/commit/0825cf11f412eef930db269b6cae02d059058101) fix: stop networkd and pods before leaving etcd on upgrade\n* [`bed6b15d`](https://github.com/talos-systems/talos/commit/bed6b15d6fcf0634a887b79797d639e221fe9387) fix: properly populate AllowSchedulingOnMasters option in gen config RPC\n* [`071f0445`](https://github.com/talos-systems/talos/commit/071f044562dd247dd54584d7b9fa0bb24d6f7599) feat: implement AddressSpec handling\n* [`76e38b7b`](https://github.com/talos-systems/talos/commit/76e38b7b8251548292ae15ecda2bfa1c8ddc5cf3) feat: update Kubernetes to 1.21.1\n* [`9b1338d9`](https://github.com/talos-systems/talos/commit/9b1338d989e6cdf7e0b6d5fe1ba3c32d27fc2251) chore: parse \"boolean\" variables\n* [`c81cfb21`](https://github.com/talos-systems/talos/commit/c81cfb21670b82e518cf4c32230e8fbbce6be8ff) chore: allow building with debug handlers\n* [`c9651673`](https://github.com/talos-systems/talos/commit/c9651673b9eaf811ae4acfed313debbf78bd80e8) feat: update go-smbios library\n* [`95c656fb`](https://github.com/talos-systems/talos/commit/95c656fb72b6b858b55dae37020cb59ba26115f8) feat: update containerd to 1.5.0, runc to 1.0.0-rc94\n* [`db9c35b5`](https://github.com/talos-systems/talos/commit/db9c35b570b39f4423f4636f9e9f1d14cac5d7c1) feat: implement AddressStatusController\n* [`1cf011a8`](https://github.com/talos-systems/talos/commit/1cf011a809b924fc8f2083566d169704c6e07cd5) chore: bump dependencies via dependabot\n* [`e3f407a1`](https://github.com/talos-systems/talos/commit/e3f407a1dff3f4ee7e024bbfb64f17b5cb5d625d) fix: properly pass disk type selector from config to matcher\n* [`66b2b450`](https://github.com/talos-systems/talos/commit/66b2b450582593e93598fac80c8b3c29e8c8a944) feat: add resources and use HTTPS checks in control plane pods\n* [`4ffd7c0a`](https://github.com/talos-systems/talos/commit/4ffd7c0adf281033ac02d37ca434e7f9ad71e692) fix: stop networkd before leaving etcd on 'reset' path\n* [`610d38d3`](https://github.com/talos-systems/talos/commit/610d38d309dabaa623494ade12234f1ccf018a9e) docs: add AMIs for 0.10.1, collapse list of AMIs by default\n* [`807497ec`](https://github.com/talos-systems/talos/commit/807497ec20dee15953186bda0fe7a45ffec0307c) chore: make conformance pipeline depend on cron-default\n* [`3c121359`](https://github.com/talos-systems/talos/commit/3c1213596cdf03daf09050103f57b29e756439b1) feat: implement LinkStatusController\n* [`0e8de046`](https://github.com/talos-systems/talos/commit/0e8de04698aac95062f3037da0a9af8b6ee916b0) fix: update go-blockdevice to fix disk type detection\n* [`4d50a4ed`](https://github.com/talos-systems/talos/commit/4d50a4edd0eb413c16e899536ccdc2642e37aeaa) fix: update the way NTP sync uses `adjtimex` syscall\n* [`1a85c14a`](https://github.com/talos-systems/talos/commit/1a85c14a51fdab43ae84274563bf89b30e4e6d92) fix: avoid data race on CRI pod stop\n* [`5de8dbc0`](https://github.com/talos-systems/talos/commit/5de8dbc06c7ed36c8f3af9adea8b1abedeb372b6) fix: repair pine64 support\n* [`38239097`](https://github.com/talos-systems/talos/commit/3823909735859f2ac5d95bc39c051fc9c2c07685) fix: properly parse matcher expressions\n* [`e54b6b7a`](https://github.com/talos-systems/talos/commit/e54b6b7a3d7412ddce1467dfbd35efe3cfd76f3f) chore: update dependencies via dependabot\n* [`f2caed0d`](https://github.com/talos-systems/talos/commit/f2caed0df5b76c4a719f968191081a6e5e2e95c7) chore: use extracted talos-systems/go-kmsg library\n* [`79d804c5`](https://github.com/talos-systems/talos/commit/79d804c5b4af50a0fd73db17d2522d6a6b45c9ca) docs: fix typos\n* [`a2bb390e`](https://github.com/talos-systems/talos/commit/a2bb390e1d56106d6d3c1526f3f76b34846b0274) feat: deterministic builds\n* [`e480fedf`](https://github.com/talos-systems/talos/commit/e480fedff047233e78ad2c22e7b84cbbb22798d5) feat: add USB serial drivers\n* [`79299d76`](https://github.com/talos-systems/talos/commit/79299d761c50aff386ab7b3c12f39c1797585632) docs: add Matrix room links\n* [`1b3e8b09`](https://github.com/talos-systems/talos/commit/1b3e8b09edcd51cf3df2d43d14c8fbf1e912a465) docs: add survey to README\n* [`8d51c9bb`](https://github.com/talos-systems/talos/commit/8d51c9bb190c2c60fa9be6a00572d2eaf4221e94) docs: update redirects to Talos 0.10\n* [`1092c3a5`](https://github.com/talos-systems/talos/commit/1092c3a5069a3add439860d90c3615111fa03c98) feat: add Pine64 SBC support\n* [`63e01754`](https://github.com/talos-systems/talos/commit/63e0175437e45c8f7e5296841337a640c600982c) feat: pull kernel with VMware balloon module enabled\n* [`aeec99d8`](https://github.com/talos-systems/talos/commit/aeec99d8247f4eb534e0db1ed639f95cd726fe08) chore: remove temporary fork\n* [`0f49722d`](https://github.com/talos-systems/talos/commit/0f49722d0ff4e731f17a55d1ca50472714334748) feat: add `--config-patch` flag by node type\n* [`a01b1d22`](https://github.com/talos-systems/talos/commit/a01b1d22d9f3fa94355817217fefd80fe34628f3) chore: dump dependencies via dependabot\n* [`d540a4a4`](https://github.com/talos-systems/talos/commit/d540a4a4711367a0ada203f668382e39876ba081) fix: bump crypto library for the CSR verification fix\n* [`c3a4173e`](https://github.com/talos-systems/talos/commit/c3a4173e11a92c2bc51ea4f284ad38c9750105d2) chore: remove security API ReadFile/WriteFile\n* [`38037131`](https://github.com/talos-systems/talos/commit/38037131cddc2aefbae0f48fb7e355ec76247b67) chore: update wgctrl dependecy\n* [`d9ba0fd0`](https://github.com/talos-systems/talos/commit/d9ba0fd0164b2bfb2bc4ffe7a2d9d6c665a38e4d) docs: create v0.11 docs, promote v0.10 docs, add v0.10 AMIs\n* [`2261d7ed`](https://github.com/talos-systems/talos/commit/2261d7ed0212c287273eac647647e4390c530a6e) fix: use both self-signed and Kubernetes CA to verify Kubelet cert\n* [`a3537a69`](https://github.com/talos-systems/talos/commit/a3537a691320430eeb7149abe73419ee242312fc) docs: update cloud images for Talos v0.9.3\n* [`5b9ee861`](https://github.com/talos-systems/talos/commit/5b9ee86179fb92989b02533d6d6745a5b0f37566) docs: add what's new for Talos 0.10\n* [`f1107fa3`](https://github.com/talos-systems/talos/commit/f1107fa3a33955f3aa57a49991c87f9ee47b6e67) docs: add survey\n* [`93623d47`](https://github.com/talos-systems/talos/commit/93623d47f24fef0d149fa006678b61e3182ef771) docs: update AWS instructions\n* [`a739d1b8`](https://github.com/talos-systems/talos/commit/a739d1b8adbc026796d1c55f7319677f9010f727) feat: add support of custom registry CA certificate usage\n* [`7f468d35`](https://github.com/talos-systems/talos/commit/7f468d350a6f80d2815149376fa24f7d7629402c) fix: update osType in OVA other3xLinux64Guest\"\n* [`4a184b67`](https://github.com/talos-systems/talos/commit/4a184b67d6ae25b21b35373e7dd6eab41b042c96) docs: add etcd backup and restore guide\n* [`5fb38d3e`](https://github.com/talos-systems/talos/commit/5fb38d3e5f201934d64bae186c5300e7de7af3d4) chore: refactor Dockerfile for cross-compilation\n* [`a8f1e526`](https://github.com/talos-systems/talos/commit/a8f1e526bfc00107c915572df2be08b3f154f4e6) chore: build talosctl for Darwin / Apple Silicon\n* [`eb0b64d3`](https://github.com/talos-systems/talos/commit/eb0b64d3138228a6c751387c720ca81c338b834d) chore: list specifically for enabled regions\n* [`669a0cbd`](https://github.com/talos-systems/talos/commit/669a0cbdc4756f0ad8f0dacc56a20f71e96fe4cd) fix: check if OVF env is empty\n* [`da92049c`](https://github.com/talos-systems/talos/commit/da92049c0b4beae32af80205f50849443cd6dad3) chore: use codecov from the build container\n* [`9996d4b0`](https://github.com/talos-systems/talos/commit/9996d4b028f3845071850def75f2b534e4d2b190) chore: use REGISTRY_MIRROR_FLAGS if defined\n* [`05cbe250`](https://github.com/talos-systems/talos/commit/05cbe250c87339e097d435d6b10b9d8a5f2eb49e) chore: bump dependencies via dependabot\n* [`9a91142a`](https://github.com/talos-systems/talos/commit/9a91142a38b3b1f210773acf8df01ed6a45599c2) feat: print complete member info in etcd members\n* [`bb40d6dd`](https://github.com/talos-systems/talos/commit/bb40d6dd06a967464c24ab33744bbf460aa84038) feat: update pkgs version\n* [`e7a9164b`](https://github.com/talos-systems/talos/commit/e7a9164b1e1630f953a420d99c865aef6e652d15) test: implement `talosctl conformance` command to run e2e tests\n* [`6cb266e7`](https://github.com/talos-systems/talos/commit/6cb266e74e60d9d5423feaad550a7861dc73f11d) fix: update etcd client errors, print etcd join failures\n* [`0bd8b0e8`](https://github.com/talos-systems/talos/commit/0bd8b0e8008c12e4914c6e9b5faf06dda6c744f7) feat: provide an option to recover etcd from data directory copy\n* [`f9818540`](https://github.com/talos-systems/talos/commit/f98185408d618ebcc780247ea2c42239df27a74e) chore: fix conform with scopes\n* [`21018f28`](https://github.com/talos-systems/talos/commit/21018f28c732719535c30c8e1abdbb346f1dc4bf) chore: bump website node.js dependencies\n</p>\n</details>\n\n### Changes from talos-systems/crypto\n<details><summary>1 commit</summary>\n<p>\n\n* [`4f80b97`](https://github.com/talos-systems/crypto/commit/4f80b976b640d773fb025d981bf85bcc8190815b) fix: verify CSR signature before issuing a certificate\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>2 commits</summary>\n<p>\n\n* [`1292574`](https://github.com/talos-systems/go-blockdevice/commit/1292574643e06512255fb0f45107e0c296eb5a3b) fix: make disk type matcher parser case insensitive\n* [`b77400e`](https://github.com/talos-systems/go-blockdevice/commit/b77400e0a7261bf25da77c1f28c2f393f367bfa9) fix: properly detect nvme and sd card disk types\n</p>\n</details>\n\n### Changes from talos-systems/go-debug\n<details><summary>5 commits</summary>\n<p>\n\n* [`3d0a6e1`](https://github.com/talos-systems/go-debug/commit/3d0a6e1bf5e3c521e83ead2c8b7faad3638b8c5d) feat: race build tag flag detector\n* [`5b292e5`](https://github.com/talos-systems/go-debug/commit/5b292e50198b8ed91c434f00e2772db394dbf0b9) feat: disable memory profiling by default\n* [`c6d0ae2`](https://github.com/talos-systems/go-debug/commit/c6d0ae2c0ee099fa0940405401e6a02716a15bd8) fix: linters and CI\n* [`d969f95`](https://github.com/talos-systems/go-debug/commit/d969f952af9e02feea59963671298fc236ca4399) feat: initial implementation\n* [`b2044b7`](https://github.com/talos-systems/go-debug/commit/b2044b70379c84f9706de74044bd2fd6a8e891cf) Initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-kmsg\n<details><summary>2 commits</summary>\n<p>\n\n* [`2edcd3a`](https://github.com/talos-systems/go-kmsg/commit/2edcd3a913508e2d922776f729bfc4bcab031a8b) feat: add initial version\n* [`53cdd8d`](https://github.com/talos-systems/go-kmsg/commit/53cdd8d67b9dbab692471a2d5161e7e0b3d04cca) chore: initial commit\n</p>\n</details>\n\n### Changes from talos-systems/go-loadbalancer\n<details><summary>3 commits</summary>\n<p>\n\n* [`a445702`](https://github.com/talos-systems/go-loadbalancer/commit/a4457024d5189d754b2da4a30b14072a0e3f5f05) feat: allow dial timeout and keep alive period to be configurable\n* [`3c8f347`](https://github.com/talos-systems/go-loadbalancer/commit/3c8f3471d14e37866c65f73170ef83c038ae5a8c) feat: provide a way to configure logger for the loadbalancer\n* [`da8e987`](https://github.com/talos-systems/go-loadbalancer/commit/da8e987434c3d407679a40e213b12a8e1c98abb8) feat: implement Reconcile - ability to change upstream list on the fly\n</p>\n</details>\n\n### Changes from talos-systems/go-smbios\n<details><summary>1 commit</summary>\n<p>\n\n* [`d3a32be`](https://github.com/talos-systems/go-smbios/commit/d3a32bea731a0c2a60ce7f5eae60253300ef27e1) fix: return UUID in middle endian only on SMBIOS >= 2.6\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>15 commits</summary>\n<p>\n\n* [`a3a6650`](https://github.com/talos-systems/pkgs/commit/a3a66505f36b9e9f92f4980df3708a872d56caec) feat: update containerd to 1.5.2\n* [`c70ea44`](https://github.com/talos-systems/pkgs/commit/c70ea44ba4bc1ffabdb1422deda107a94e1fe94c) feat: update runc to 1.0.0-rc95\n* [`db60235`](https://github.com/talos-systems/pkgs/commit/db602359cc594b35291911b4220dc5b331b323bb) feat: add support for netxen card\n* [`f934187`](https://github.com/talos-systems/pkgs/commit/f934187ebdc455f18cc6d2da847be3d48a6e3d8f) feat: update containerd to 1.5.1\n* [`e8ed5bc`](https://github.com/talos-systems/pkgs/commit/e8ed5bcb848954ca30967de8d7c81afecdea4825) feat: add geneve encapsulation support for openvswitch\n* [`9f7903c`](https://github.com/talos-systems/pkgs/commit/9f7903cb5c110f77db8093347b69ec141325d47c) feat: update containerd to 1.5.0, runc to -rc94\n* [`d7c0f70`](https://github.com/talos-systems/pkgs/commit/d7c0f70e41bb7bf542092f2882b062ff52f5ae44) feat: add AES-NI support for amd64\n* [`b0d9cd2`](https://github.com/talos-systems/pkgs/commit/b0d9cd2c36e37190c5ce7b85acea6a51a853faaf) fix: build `zbin` utility for both amd64 and arm64\n* [`bb39b97`](https://github.com/talos-systems/pkgs/commit/bb39b9744c0c4a29ccfa190a0d2cce0f8547676b) feat: add IPMI support in kernel\n* [`1148f9a`](https://github.com/talos-systems/pkgs/commit/1148f9a897d9a52b6013396151e1eab264709037) feat: add DS1307 RTC support for arm64\n* [`350aa6f`](https://github.com/talos-systems/pkgs/commit/350aa6f200d441d7dbbf60ec8ebb39a6761d6a8b) feat: add USB serial support\n* [`de9c582`](https://github.com/talos-systems/pkgs/commit/de9c58238483219a574fb697ddb1126f36a02da3) feat: add Pine64 SBC support\n* [`b56f36b`](https://github.com/talos-systems/pkgs/commit/b56f36bedbe9270ae5cf969f8078a10345457e83) feat: enable VMware baloon kernel module\n* [`f87c194`](https://github.com/talos-systems/pkgs/commit/f87c19425352eb9b68d20dec987d0c484987dea9) feat: add iPXE build with embedded placeholder script\n* [`a8b9e71`](https://github.com/talos-systems/pkgs/commit/a8b9e71e6538d7554b7a48d1361709d5495bb4de) feat: add cpu scaling for rpi\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/containerd/cgroups**                 4cbc285b3327 -> v1.0.1\n* **github.com/containerd/containerd**              v1.4.4 -> v1.5.2\n* **github.com/containerd/go-cni**                  v1.0.1 -> v1.0.2\n* **github.com/containerd/typeurl**                 v1.0.1 -> v1.0.2\n* **github.com/coreos/go-iptables**                 v0.5.0 -> v0.6.0\n* **github.com/cosi-project/runtime**               10d6103c19ab -> 8a4533ce68e2\n* **github.com/docker/docker**                      v20.10.4 -> v20.10.6\n* **github.com/emicklei/dot**                       v0.15.0 -> v0.16.0\n* **github.com/fatih/color**                        v1.10.0 -> v1.11.0\n* **github.com/grpc-ecosystem/go-grpc-middleware**  v1.2.2 -> v1.3.0\n* **github.com/hashicorp/go-getter**                v1.5.2 -> v1.5.3\n* **github.com/mdlayher/ethtool**                   2b88debcdd43 **_new_**\n* **github.com/opencontainers/runtime-spec**        4d89ac9fbff6 -> e6143ca7d51d\n* **github.com/plunder-app/kube-vip**               v0.3.2 -> v0.3.4\n* **github.com/rs/xid**                             v1.2.1 -> v1.3.0\n* **github.com/talos-systems/crypto**               39584f1b6e54 -> 4f80b976b640\n* **github.com/talos-systems/go-blockdevice**       1d830a25f64f -> 1292574643e0\n* **github.com/talos-systems/go-debug**             3d0a6e1bf5e3 **_new_**\n* **github.com/talos-systems/go-kmsg**              v0.1.0 **_new_**\n* **github.com/talos-systems/go-loadbalancer**      v0.1.0 -> v0.1.1\n* **github.com/talos-systems/go-smbios**            fb425d4727e6 -> d3a32bea731a\n* **github.com/talos-systems/pkgs**                 v0.5.0-1-g5dd650b -> v0.6.0-alpha.0-5-ga3a6650\n* **github.com/vmware-tanzu/sonobuoy**              v0.20.0 -> v0.50.0\n* **github.com/vmware/govmomi**                     v0.24.0 -> v0.25.0\n* **go.etcd.io/etcd/api/v3**                        v3.5.0-alpha.0 -> v3.5.0-beta.3\n* **go.etcd.io/etcd/client/pkg/v3**                 v3.5.0-beta.3 **_new_**\n* **go.etcd.io/etcd/client/v3**                     v3.5.0-alpha.0 -> v3.5.0-beta.3\n* **go.etcd.io/etcd/etcdutl/v3**                    v3.5.0-beta.3 **_new_**\n* **go.uber.org/zap**                               c23abee72d19 **_new_**\n* **golang.org/x/net**                              e18ecbb05110 -> 0714010a04ed\n* **golang.org/x/sys**                              77cc2087c03b -> 0981d6026fa6\n* **golang.org/x/term**                             6a3ed077a48d -> a79de5458b56\n* **golang.zx2c4.com/wireguard/wgctrl**             bd2cb7843e1b -> f9ad6d392236\n* **google.golang.org/grpc**                        v1.37.0 -> v1.38.0\n* **inet.af/netaddr**                               1d252cf8125e **_new_**\n* **k8s.io/api**                                    v0.21.0 -> v0.21.1\n* **k8s.io/apimachinery**                           v0.21.0 -> v0.21.1\n* **k8s.io/apiserver**                              v0.21.0 -> v0.21.1\n* **k8s.io/client-go**                              v0.21.0 -> v0.21.1\n* **k8s.io/kubectl**                                v0.21.0 -> v0.21.1\n* **k8s.io/kubelet**                                v0.21.0 -> v0.21.1\n\nPrevious release can be found at [v0.10.0](https://github.com/talos-systems/talos/releases/tag/v0.10.0)\n\n## [Talos 0.10.0-alpha.2](https://github.com/talos-systems/talos/releases/tag/v0.10.0-alpha.2) (2021-04-08)\n\nWelcome to the v0.10.0-alpha.2 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Disaster Recovery\n\n* support for creating etcd snapshots (backups) with `talosctl etcd snapshot` command.\n* etcd cluster can be recovered from a snapshot using `talosctl boostrap --recover-from=` command.\n\n\n### Install Disk Selector\n\nInstall section of the machine config now has `diskSelector` field that allows querying install disk using the list of qualifiers:\n\n```yaml\n...\n  install:\n    diskSelector:\n      size: >= 500GB\n      model: WDC*\n...\n```\n\n`talosctl disks -n <node> -i` can be used to check allowed disk qualifiers when the node is running in the maintenance mode.\n\n\n### Optimizations\n\n* Talos `system` services now run without container images on initramfs from the single executable; this change reduces RAM usage, initramfs size and boot time..\n\n\n### SBCs\n\n* u-boot version was updated to fix the boot and USB issues on Raspberry Pi 4 8GiB version.\n* added support for Rock Pi 4.\n\n\n### Time Syncrhonization\n\n* `timed` service was replaced with a time sync controller, no machine configuration changes.\n* Talos now prefers last successful time server (by IP address) on each sync attempt (improves sync accuracy).\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Spencer Smith\n* Seán C McCord\n* Andrew Rynhard\n* Branden Cash\n* Jorik Jonker\n* Matt Zahorik\n* bzub\n\n### Changes\n<details><summary>104 commits</summary>\n<p>\n\n* [`e0650218`](https://github.com/talos-systems/talos/commit/e0650218a6b0a05a8e109262a0d7ed3d7359ea37) feat: support etcd recovery from snapshot on bootstrap\n* [`247bd50e`](https://github.com/talos-systems/talos/commit/247bd50e0510f57c969e3bb8fee5b53bfcdbb074) docs: describe steps to install and boot Talos from the SSD on rockpi4\n* [`e6b4e524`](https://github.com/talos-systems/talos/commit/e6b4e524ffa33a5c76368f0fe8e9c372e3297cfc) test: update CAPA to 0.6.4\n* [`28753f6d`](https://github.com/talos-systems/talos/commit/28753f6dcb85450965e4d4a0fb68f448e1deee23) fix: trim endpoints/nodes from arguments in talosctl config\n* [`aca63b88`](https://github.com/talos-systems/talos/commit/aca63b8829ad0eebd449573120bff2d9b90ba828) docs: fix \"DigitalOcean\" spelling\n* [`33035901`](https://github.com/talos-systems/talos/commit/33035901ff7875bdf9eb99fb86b377318f60d74b) fix: revert mark PMBR EFI partition as bootable\n* [`fbfd1eb2`](https://github.com/talos-systems/talos/commit/fbfd1eb2b1684fe38caa12b8d46d608c42b5daf6) refactor: pull new version of os-runtime, update code\n* [`8737ea71`](https://github.com/talos-systems/talos/commit/8737ea716a5d9adf24959a56a73dd61e1139b808) feat: allow external cloud provides configration\n* [`3909e2d0`](https://github.com/talos-systems/talos/commit/3909e2d011b9d11653903687e5a4210daa440ef2) chore: update Go to 1.16.3\n* [`690eb20e`](https://github.com/talos-systems/talos/commit/690eb20e9763d8f3036f0a1b4b9447f19c5ec05b) chore: update blockdevice library for PMBR bootable fix\n* [`a8761b8e`](https://github.com/talos-systems/talos/commit/a8761b8e1efd07a3bda3d8f706d3d7bf658955bb) fix: require leader on etcd member operations\n* [`3dc84625`](https://github.com/talos-systems/talos/commit/3dc84625cb1b323bad1dd93d89a13d3d59ea22d8) fix: make both HDMI ports work on RPi 4\n* [`bd5ae1e0`](https://github.com/talos-systems/talos/commit/bd5ae1e0b5dd303a017156ba7af733f79d3c13ef) fix: add a check for overlay mounts in installer pre-flight checks\n* [`df8649cb`](https://github.com/talos-systems/talos/commit/df8649cbe6f4fcf04c4b84a444ec2519e37ac171) refactor: download modules before `go generate`\n* [`39ae0415`](https://github.com/talos-systems/talos/commit/39ae0415e9d932c01ff33163d97daef375c21a7f) chore: bump dependencies via dependabot\n* [`e16d6d34`](https://github.com/talos-systems/talos/commit/e16d6d3468a7a072b41e94fdc352df15b8321376) fix: publish rockpi4 image to release artifacts\n* [`39c6dbcc`](https://github.com/talos-systems/talos/commit/39c6dbcc7ae8f07e1ab4c2a82508ebee07f66207) feat: add --config-patch parameter to talosctl gen config\n* [`e664362c`](https://github.com/talos-systems/talos/commit/e664362cecb476a41360143a05c0cfad718b2e0f) feat: add API and command to save etcd snapshot (backup)\n* [`61b694b9`](https://github.com/talos-systems/talos/commit/61b694b94896da47e2ddf677cbf12b18007268a5) fix: create rootfs for system services via /system tmpfs\n* [`abc2e17e`](https://github.com/talos-systems/talos/commit/abc2e17ebb6d440438e407e5a5d1c5c1f7d1eeff) test: update 0.9.x version in upgrade tests to 0.9.1\n* [`a1e64154`](https://github.com/talos-systems/talos/commit/a1e6415403df9827fb486492a4b292b9aab3076b) fix: retry Kubernetes API errors on cordon/uncordon/etc\n* [`063d1abe`](https://github.com/talos-systems/talos/commit/063d1abe9cf1634f3517893977fc907dd9004c55) fix: print task failure error immediately\n* [`e039172e`](https://github.com/talos-systems/talos/commit/e039172edac115afbd5bf36a1f266e5967ca5398) fix: ignore EOF errors from Kubernetes API when converting control plane\n* [`7bcb91a4`](https://github.com/talos-systems/talos/commit/7bcb91a433f14a29a0d2bbe9d70eb5a997eb9ab0) docs: fix typo for stage flag\n* [`a43acb21`](https://github.com/talos-systems/talos/commit/a43acb2150cadd78da51c41569b7f219b704f089) feat: bring in Linux 5.10.27, support for 32-bit time syscalls\n* [`e2bb5973`](https://github.com/talos-systems/talos/commit/e2bb5973da5b2dc15aba2a809e0e31426b6f22b3) release(v0.10.0-alpha.1): prepare release\n* [`8309312a`](https://github.com/talos-systems/talos/commit/8309312a3db89cea17b673d0d1c73175db5258ac) chore: build components with race detector enabled in dev mode\n* [`7d912584`](https://github.com/talos-systems/talos/commit/7d9125847506dfadc7e137a30bf0c93ab9ca0b50) test: fix data race in apply config tests\n* [`204caf8e`](https://github.com/talos-systems/talos/commit/204caf8eb9c6c43a90c20ebaea8387584201e7f5) test: fix apply-config integration test, bump clusterctl version\n* [`d812099d`](https://github.com/talos-systems/talos/commit/d812099df3d060ae74cd3d28405ddacbdd72ab15) fix: address several issues in TUI installer\n* [`269c9ad0`](https://github.com/talos-systems/talos/commit/269c9ad0988f0f966a4e31a5ab744fed7d585385) fix: don't write to config object on access\n* [`a9451f57`](https://github.com/talos-systems/talos/commit/a9451f57129b0b452825850bba9477ac3c536547) feat: update Kubernetes to 1.21.0-beta.1\n* [`4b42ced4`](https://github.com/talos-systems/talos/commit/4b42ced4c2a300aa22f253435a4d6330770ec5c2) feat: add ability to disable comments in talosctl gen config\n* [`a0dcfc3d`](https://github.com/talos-systems/talos/commit/a0dcfc3d5288e633db80bf3e32d31e41756cc90f) fix: workaround race in containerd runner with stdin pipe\n* [`2ea20f59`](https://github.com/talos-systems/talos/commit/2ea20f598a01f3de95f633bdfaf5711738524ba2) feat: replace timed with time sync controller\n* [`c38a161a`](https://github.com/talos-systems/talos/commit/c38a161ade34f00f7af52d9ae047d7936246e7f0) test: add unit-test for machine config validation\n* [`a6106815`](https://github.com/talos-systems/talos/commit/a6106815b72efcb7f4df0caab6b93be49a7590ea) chore: bump dependencies via dependabot\n* [`35598f39`](https://github.com/talos-systems/talos/commit/35598f391d5d0659e3390d4db67c7ed88c17b6eb) chore: refactor: extract ClusterConfig\n* [`03285184`](https://github.com/talos-systems/talos/commit/032851844fdea4b1bde7507720025c981ee3b12c) fix: get rid of data race in encoder and fix concurrent map access\n* [`4b3580aa`](https://github.com/talos-systems/talos/commit/4b3580aa57d83358434238ad953793070cfc67a7) fix: prevent panic in validate config if `machine.install` is missing\n* [`d7e9f6d6`](https://github.com/talos-systems/talos/commit/d7e9f6d6a89143f0def74a270a21ed5e53556e07) chore: build integration tests with -race\n* [`9f7d67ac`](https://github.com/talos-systems/talos/commit/9f7d67ac717834ed428b8f13d4061db5f33c81f9) chore: fix typo\n* [`672c9707`](https://github.com/talos-systems/talos/commit/672c970739971dd0c558ad0319fe9fdbd66a741b) fix: allow `convert-k8s --remove-initialized-keys` with K8s cp is down\n* [`fb605a0f`](https://github.com/talos-systems/talos/commit/fb605a0fc56e6df1ceae8c391524ac987bbba09d) chore: tweak nolintlint settings\n* [`1f5a0c40`](https://github.com/talos-systems/talos/commit/1f5a0c4065e1fbd63ebe6d48c13e669bfb1dbeac) fix: resolve the issue with Kubernetes upgrade\n* [`74b2b557`](https://github.com/talos-systems/talos/commit/74b2b5578cbe639a6f2663df6ab7a5e80b139fe0) docs: update AWS docs to ensure instances are tagged\n* [`dc21d9b4`](https://github.com/talos-systems/talos/commit/dc21d9b4b0f5858fbe0d4072e8a47a934780c3dd) chore: remove old file\n* [`966caf7a`](https://github.com/talos-systems/talos/commit/966caf7a674c20047c1184e64f3727abc0c54296) chore: remove unused module replace directives\n* [`98b22f1e`](https://github.com/talos-systems/talos/commit/98b22f1e0b0f5e85b71d344041265efa95e1bb91) feat: show short options in talosctl kubeconfig\n* [`51139d54`](https://github.com/talos-systems/talos/commit/51139d54d4ce4acf2e78f11ab0f384f91f86ff33) chore: cache go modules in the build\n* [`65701aa7`](https://github.com/talos-systems/talos/commit/65701aa724130645fcabe521557225ff41b359b0) fix: resolve the issue with DHCP lease not being renewed\n* [`711f5b23`](https://github.com/talos-systems/talos/commit/711f5b23be69665d6204dbb80064e0ab0d1468c0) fix: config validation: CNI should apply to cp nodes, encryption config\n* [`5ff491d9`](https://github.com/talos-systems/talos/commit/5ff491d9686434a6208583dca97171bfbecf3f70) fix: allow empty list for CNI URLs\n* [`946e74f0`](https://github.com/talos-systems/talos/commit/946e74f047f30180bf5f0554fd8ae1043e0d1f52) docs: update path for kernel downloads in qemu docs\n* [`ed272e60`](https://github.com/talos-systems/talos/commit/ed272e604e67dc38557812e5f4dbcb8666c4b546) feat: update Kubernetes to 1.21.0-beta.0\n* [`b0209fd2`](https://github.com/talos-systems/talos/commit/b0209fd29d3895d7a0b8806e505bbefcf2bba520) refactor: move networkd, timed APIs to machined, remove routerd\n* [`6ffabe51`](https://github.com/talos-systems/talos/commit/6ffabe51691907b43f9f970f22d7aec4df19a6c3) feat: add ability to find disk by disk properties\n* [`ac876470`](https://github.com/talos-systems/talos/commit/ac8764702f980a8dea5b6a67f0bc33b5203efecb) refactor: move apid, routerd, timed and trustd to single executable\n* [`89a4b09f`](https://github.com/talos-systems/talos/commit/89a4b09fe8015e70f7074d9af72d47023ece2f1d) refactor: run networkd as a goroutine in machined\n* [`f4a6a19c`](https://github.com/talos-systems/talos/commit/f4a6a19cd1bf1da7f2610276c00e8144a78f8694) chore: update sonobuoy\n* [`dc294db1`](https://github.com/talos-systems/talos/commit/dc294db16c8bdb10e3f63987c87c0bbdf629b158) chore: bump dependencies via dependabot\n* [`2b1641a3`](https://github.com/talos-systems/talos/commit/2b1641a3b543d736eb0d2e359d2a25dbc906e631) docs: add AMIs for Talos 0.9.0\n* [`79ceb428`](https://github.com/talos-systems/talos/commit/79ceb428d4216a06418933058485ec2273474e3c) docs: make v0.9 the default docs\n* [`a5b62f4d`](https://github.com/talos-systems/talos/commit/a5b62f4dc20da721b0f74c5fbb5082038e05e4f4) docs: add documentation for Talos 0.10\n* [`ce795f1c`](https://github.com/talos-systems/talos/commit/ce795f1cea9d78c26edbcd4a40bb5d3637fde629) fix: command `etcd remove-member` shouldn't remove etcd data directory\n* [`aab49a16`](https://github.com/talos-systems/talos/commit/aab49a167b1f1cd3974e3aa1244d636ba712f678) fix: repair zsh completion\n* [`fc9c416a`](https://github.com/talos-systems/talos/commit/fc9c416a3c8425bb42892f740c910894610acd00) fix: build rockpi4 metal image as part of CI build\n* [`125b86f4`](https://github.com/talos-systems/talos/commit/125b86f4efbc2ed3e0a4bdfc945e97b05f1cb82c) fix: upgrade-k8s bug with empty config values and provision script\n* [`8b2d228d`](https://github.com/talos-systems/talos/commit/8b2d228dc42c196090aae1e6958683e265ebc05c) chore: add script for starting registry proxies\n* [`f7d276b8`](https://github.com/talos-systems/talos/commit/f7d276b854c4c06f85155c517cc1de7109a53359) chore: remove old `osctl` reference\n* [`5b14d6f2`](https://github.com/talos-systems/talos/commit/5b14d6f2b89c5b86f9ec2cb0271c6605272269d4) chore: fix `make help` output\n* [`f0512dfc`](https://github.com/talos-systems/talos/commit/f0512dfce9443cf20790ef8b4fd8e87906cc5bda) feat: update Kubernetes to 1.20.5\n* [`24cd0a20`](https://github.com/talos-systems/talos/commit/24cd0a20678f2728a0b36c1c401dd8af3d4932ed) feat: publish talosctl container image\n* [`6e17102c`](https://github.com/talos-systems/talos/commit/6e17102c210dccd4bf78d347de07cfe2ba7737c4) chore: remove unused code\n* [`88104407`](https://github.com/talos-systems/talos/commit/8810440744453550697ad39530633b81889d38b7) docs: add control plane in-depth guide\n* [`ecf03449`](https://github.com/talos-systems/talos/commit/ecf034496e7450f89369140ad1791188580dee0d) chore: bump Go to 1.16.2\n* [`cbc38418`](https://github.com/talos-systems/talos/commit/cbc38418d856a00ffb35d31676e1efb14fb6da36) release(v0.10.0-alpha.0): prepare release\n* [`3455a8e8`](https://github.com/talos-systems/talos/commit/3455a8e8185ba25777784d392d6150a4a7e2d4a9) chore: use new release tool for changelogs and release notes\n* [`08271ba9`](https://github.com/talos-systems/talos/commit/08271ba93178c17a7c495788fea00c5c380f8301) chore: use Go 1.16 language version\n* [`7662d033`](https://github.com/talos-systems/talos/commit/7662d033bfc3d6e3878e2c2a2a1ec4d71dc2502e) fix: talosctl health should not check kube-proxy when it is disabled\n* [`0dbaeb9e`](https://github.com/talos-systems/talos/commit/0dbaeb9e655acdc44f8b4db6d1bc6da2ddf6cc9d) chore: update tools, use new generators\n* [`e31790f6`](https://github.com/talos-systems/talos/commit/e31790f6f548095fe3f1b9a5c88b47e70c197d2c) fix: properly format spec comments in the resources\n* [`78d384eb`](https://github.com/talos-systems/talos/commit/78d384ebb6246cf41a73014312dfb0d86a8008d6) test: update aws cloud provider version\n* [`3c5bfbb4`](https://github.com/talos-systems/talos/commit/3c5bfbb4736c86f493a665dbfe63a6e2d20acb3d) fix: don't touch any partitions on upgrade with --preserve\n* [`891f90fe`](https://github.com/talos-systems/talos/commit/891f90fee9818f0f013878c0c77c1920e6427a91) chore: update Linux to 5.10.23\n* [`d4d77882`](https://github.com/talos-systems/talos/commit/d4d77882e3f53f2449f50f54116a407726f41ede) chore: update dependencies via dependabot\n* [`2e22f20b`](https://github.com/talos-systems/talos/commit/2e22f20bd876e4972bfdebd44fee13356b70b83f) docs: minor fixes to getting started\n* [`ca8a5596`](https://github.com/talos-systems/talos/commit/ca8a5596c79f638e52601e850236b715f906e3d2) chore: fix provision tests after changes to build-container\n* [`4aae924c`](https://github.com/talos-systems/talos/commit/4aae924c685ff578af06a1adceeec4f1938576a6) refactor: provide explicit logger for networkd\n* [`22f37530`](https://github.com/talos-systems/talos/commit/22f375300c1cc1d95db540afd510a21b66d7c8a3) chore: update golanci-lint to 1.38.0\n* [`83b4e7f7`](https://github.com/talos-systems/talos/commit/83b4e7f744e3a8ed21443642a9afcf5b1342c62b) feat: add Rock pi 4 support\n* [`1362966f`](https://github.com/talos-systems/talos/commit/1362966ff546ee620c14e9312255616685743eed) docs: rewrite getting-started for ISO\n* [`8e57fc4f`](https://github.com/talos-systems/talos/commit/8e57fc4f526096878213048658bae50cfac4cda8) fix: move containerd CRI config files under `/var/`\n* [`6f7df3da`](https://github.com/talos-systems/talos/commit/6f7df3da1e147212e6d4b40a5de65e5ca8be84db) fix: update output of `convert-k8s` command\n* [`dce6118c`](https://github.com/talos-systems/talos/commit/dce6118c290afe957e375586b6bbc5b10ef6ba09) docs: add guide for VIP\n* [`ee5d9ffa`](https://github.com/talos-systems/talos/commit/ee5d9ffac60c93561874995d8926fc329e2b67dc) chore: bump Go to 1.16.1\n* [`7c529e1c`](https://github.com/talos-systems/talos/commit/7c529e1cbd2be66d71e8496304781dd406495bdd) docs: fix links in the documentation\n* [`f596c7f6`](https://github.com/talos-systems/talos/commit/f596c7f6be3880be994faf7c5361628024c6be7d) docs: add video for raspberry pi install\n* [`47324dca`](https://github.com/talos-systems/talos/commit/47324dcaeaee94e4963eb3764fc01cd2d2d43041) docs: add guide on editing machine configuration\n* [`99d5f894`](https://github.com/talos-systems/talos/commit/99d5f894e17f39004e61ee9d5b64d5a8139f33d0) chore: update website npm dependencies\n* [`11056a80`](https://github.com/talos-systems/talos/commit/11056a80349e4c8df10a9ea98b6e3d53f96b971c) docs: add highlights for 0.9 release\n* [`ae8bedb9`](https://github.com/talos-systems/talos/commit/ae8bedb9a0d999bfbe97b6e18dc2eff62f0fcb80) docs: add control plane conversion guide and 0.9 upgrade notes\n* [`ed9673e5`](https://github.com/talos-systems/talos/commit/ed9673e50a7cb973fc49be9c2d659447a4c5bd62) docs: add troubleshooting control plane documentation\n* [`485cb126`](https://github.com/talos-systems/talos/commit/485cb1262f97e982ea81597b49d173836c75558d) docs: update Kubernetes upgrade guide\n</p>\n</details>\n\n### Changes since v0.10.0-alpha.1\n<details><summary>25 commits</summary>\n<p>\n\n* [`e0650218`](https://github.com/talos-systems/talos/commit/e0650218a6b0a05a8e109262a0d7ed3d7359ea37) feat: support etcd recovery from snapshot on bootstrap\n* [`247bd50e`](https://github.com/talos-systems/talos/commit/247bd50e0510f57c969e3bb8fee5b53bfcdbb074) docs: describe steps to install and boot Talos from the SSD on rockpi4\n* [`e6b4e524`](https://github.com/talos-systems/talos/commit/e6b4e524ffa33a5c76368f0fe8e9c372e3297cfc) test: update CAPA to 0.6.4\n* [`28753f6d`](https://github.com/talos-systems/talos/commit/28753f6dcb85450965e4d4a0fb68f448e1deee23) fix: trim endpoints/nodes from arguments in talosctl config\n* [`aca63b88`](https://github.com/talos-systems/talos/commit/aca63b8829ad0eebd449573120bff2d9b90ba828) docs: fix \"DigitalOcean\" spelling\n* [`33035901`](https://github.com/talos-systems/talos/commit/33035901ff7875bdf9eb99fb86b377318f60d74b) fix: revert mark PMBR EFI partition as bootable\n* [`fbfd1eb2`](https://github.com/talos-systems/talos/commit/fbfd1eb2b1684fe38caa12b8d46d608c42b5daf6) refactor: pull new version of os-runtime, update code\n* [`8737ea71`](https://github.com/talos-systems/talos/commit/8737ea716a5d9adf24959a56a73dd61e1139b808) feat: allow external cloud provides configration\n* [`3909e2d0`](https://github.com/talos-systems/talos/commit/3909e2d011b9d11653903687e5a4210daa440ef2) chore: update Go to 1.16.3\n* [`690eb20e`](https://github.com/talos-systems/talos/commit/690eb20e9763d8f3036f0a1b4b9447f19c5ec05b) chore: update blockdevice library for PMBR bootable fix\n* [`a8761b8e`](https://github.com/talos-systems/talos/commit/a8761b8e1efd07a3bda3d8f706d3d7bf658955bb) fix: require leader on etcd member operations\n* [`3dc84625`](https://github.com/talos-systems/talos/commit/3dc84625cb1b323bad1dd93d89a13d3d59ea22d8) fix: make both HDMI ports work on RPi 4\n* [`bd5ae1e0`](https://github.com/talos-systems/talos/commit/bd5ae1e0b5dd303a017156ba7af733f79d3c13ef) fix: add a check for overlay mounts in installer pre-flight checks\n* [`df8649cb`](https://github.com/talos-systems/talos/commit/df8649cbe6f4fcf04c4b84a444ec2519e37ac171) refactor: download modules before `go generate`\n* [`39ae0415`](https://github.com/talos-systems/talos/commit/39ae0415e9d932c01ff33163d97daef375c21a7f) chore: bump dependencies via dependabot\n* [`e16d6d34`](https://github.com/talos-systems/talos/commit/e16d6d3468a7a072b41e94fdc352df15b8321376) fix: publish rockpi4 image to release artifacts\n* [`39c6dbcc`](https://github.com/talos-systems/talos/commit/39c6dbcc7ae8f07e1ab4c2a82508ebee07f66207) feat: add --config-patch parameter to talosctl gen config\n* [`e664362c`](https://github.com/talos-systems/talos/commit/e664362cecb476a41360143a05c0cfad718b2e0f) feat: add API and command to save etcd snapshot (backup)\n* [`61b694b9`](https://github.com/talos-systems/talos/commit/61b694b94896da47e2ddf677cbf12b18007268a5) fix: create rootfs for system services via /system tmpfs\n* [`abc2e17e`](https://github.com/talos-systems/talos/commit/abc2e17ebb6d440438e407e5a5d1c5c1f7d1eeff) test: update 0.9.x version in upgrade tests to 0.9.1\n* [`a1e64154`](https://github.com/talos-systems/talos/commit/a1e6415403df9827fb486492a4b292b9aab3076b) fix: retry Kubernetes API errors on cordon/uncordon/etc\n* [`063d1abe`](https://github.com/talos-systems/talos/commit/063d1abe9cf1634f3517893977fc907dd9004c55) fix: print task failure error immediately\n* [`e039172e`](https://github.com/talos-systems/talos/commit/e039172edac115afbd5bf36a1f266e5967ca5398) fix: ignore EOF errors from Kubernetes API when converting control plane\n* [`7bcb91a4`](https://github.com/talos-systems/talos/commit/7bcb91a433f14a29a0d2bbe9d70eb5a997eb9ab0) docs: fix typo for stage flag\n* [`a43acb21`](https://github.com/talos-systems/talos/commit/a43acb2150cadd78da51c41569b7f219b704f089) feat: bring in Linux 5.10.27, support for 32-bit time syscalls\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>3 commits</summary>\n<p>\n\n* [`cf3934a`](https://github.com/talos-systems/extras/commit/cf3934ae09b22c396226bed6618b3d03ab298e33) feat: build with Go 1.16.3\n* [`c0fa0c0`](https://github.com/talos-systems/extras/commit/c0fa0c04641d8dfc418888c210788a6894e8d40c) feat: bump Go to 1.16.2\n* [`5f89d77`](https://github.com/talos-systems/extras/commit/5f89d77a91f44d52146dae9c23b4654d219042b9) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>3 commits</summary>\n<p>\n\n* [`1d830a2`](https://github.com/talos-systems/go-blockdevice/commit/1d830a25f64f6fb96a1bedd800c0b40b107dc833) fix: revert mark the EFI partition in PMBR as bootable\n* [`bec914f`](https://github.com/talos-systems/go-blockdevice/commit/bec914ffdda42abcfe642bc2cdfc9fcda56a74ee) fix: mark the EFI partition in PMBR as bootable\n* [`776b37d`](https://github.com/talos-systems/go-blockdevice/commit/776b37d31de0781f098f5d9d1894fbea3f2dfa1d) feat: add options to probe disk by various sysblock parameters\n</p>\n</details>\n\n### Changes from talos-systems/os-runtime\n<details><summary>5 commits</summary>\n<p>\n\n* [`86d9e09`](https://github.com/talos-systems/os-runtime/commit/86d9e090bdc4ebfdc8bba0333a067ce189e839da) chore: bump go.mod dependencies\n* [`2de411a`](https://github.com/talos-systems/os-runtime/commit/2de411a4765de15de1d5b1524131d262801eb395) feat: major rewrite of the os-runtime with new features\n* [`ded40a7`](https://github.com/talos-systems/os-runtime/commit/ded40a78343f77dfc02ba5e5857a6baea99da682) feat: implement controller runtime gRPC bridge\n* [`0d5b5a9`](https://github.com/talos-systems/os-runtime/commit/0d5b5a942c26c8de35e741c078a38ab6529a54b7) feat: implement resource state service and client\n* [`d04ec51`](https://github.com/talos-systems/os-runtime/commit/d04ec51da46abf20110d6a4d5acc250fa7810c17) feat: add common COSI resource protobuf, implement bridge with state\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>8 commits</summary>\n<p>\n\n* [`9a6cf6b`](https://github.com/talos-systems/pkgs/commit/9a6cf6b99e1b8c0ef49e5dba2ce7e0260212c30d) feat: build with Go 1.16.3\n* [`60ce626`](https://github.com/talos-systems/pkgs/commit/60ce6260e3956566d40ef77e2194c31c18c92d10) feat: update Linux to 5.10.27, enable 32-bit time syscalls\n* [`fdf4866`](https://github.com/talos-systems/pkgs/commit/fdf48667851b4c80b0ca220c574d2fb57a943f64) feat: bump tools for Go 1.16.2\n* [`35f9b6f`](https://github.com/talos-systems/pkgs/commit/35f9b6f22bbe094e93723559132b2a23f0853c2b) feat: update kernel to 5.10.23\n* [`dbae83e`](https://github.com/talos-systems/pkgs/commit/dbae83e704da264066ceeca20e0fe66883b542ba) fix: do not use git-lfs for rockpi4 binaries\n* [`1c6b9a3`](https://github.com/talos-systems/pkgs/commit/1c6b9a3a6ef91bce4f0cba18c466a9ece7b14750) feat: bump tools for Go 1.16.1\n* [`c18073f`](https://github.com/talos-systems/pkgs/commit/c18073fe79b9d7ec36411c6f329fa60c580d4cea) feat: add u-boot for Rock Pi 4\n* [`6b85a2b`](https://github.com/talos-systems/pkgs/commit/6b85a2bffbb144f25356eed6ed9dc8bb9a3fd392) feat: upgrade u-boot to 2021.04-rc3\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>5 commits</summary>\n<p>\n\n* [`1f26def`](https://github.com/talos-systems/tools/commit/1f26def38066c41fdb5c4bfe85559a87aa832c51) feat: update Go to 1.16.3\n* [`41b8073`](https://github.com/talos-systems/tools/commit/41b807369779606f54d76e56038bfaf88d4f0f25) feat: bump protobuf-related tools\n* [`f7bce92`](https://github.com/talos-systems/tools/commit/f7bce92febdf9f58f2940952d5138494b9232ea8) chore: bump Go to 1.16.2\n* [`bcf3380`](https://github.com/talos-systems/tools/commit/bcf3380dd55810e556851acbe20e20cb4ddd5ef0) feat: bump protobuf deps, add protoc-gen-go-grpc\n* [`b49c40e`](https://github.com/talos-systems/tools/commit/b49c40e0ad701f13192c1ad85ec616224343dc3f) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/coreos/go-semver**              v0.3.0 **_new_**\n* **github.com/golang/protobuf**               v1.4.3 -> v1.5.2\n* **github.com/google/go-cmp**                 v0.5.4 -> v0.5.5\n* **github.com/hashicorp/go-multierror**       v1.1.0 -> v1.1.1\n* **github.com/talos-systems/extras**          v0.2.0-1-g0db3328 -> v0.3.0-alpha.0-2-gcf3934a\n* **github.com/talos-systems/go-blockdevice**  bb3ad73f6983 -> 1d830a25f64f\n* **github.com/talos-systems/os-runtime**      7b3d14457439 -> 86d9e090bdc4\n* **github.com/talos-systems/pkgs**            v0.4.1-2-gd471b60 -> v0.5.0-alpha.0-5-g9a6cf6b\n* **github.com/talos-systems/tools**           v0.4.0-1-g3b25a7e -> v0.5.0-alpha.0-4-g1f26def\n* **go.etcd.io/etcd/etcdctl/v3**               v3.5.0-alpha.0 **_new_**\n* **google.golang.org/grpc**                   v1.36.0 -> v1.36.1\n* **google.golang.org/protobuf**               v1.25.0 -> v1.26.0\n* **k8s.io/api**                               v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/apimachinery**                      v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/apiserver**                         v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/client-go**                         v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/cri-api**                           v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/kubectl**                           v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/kubelet**                           v0.20.5 -> v0.21.0-rc.0\n\nPrevious release can be found at [v0.9.0](https://github.com/talos-systems/talos/releases/tag/v0.9.0)\n\n## [Talos 0.10.0-alpha.1](https://github.com/talos-systems/talos/releases/tag/v0.10.0-alpha.1) (2021-03-31)\n\nWelcome to the v0.10.0-alpha.1 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### Install Disk Selector\n\nInstall section of the machine config now has `diskSelector` field that allows querying install disk using the list of qualifiers:\n\n```yaml\n...\n  install:\n    diskSelector:\n      size: >= 500GB\n      model: WDC*\n...\n```\n\n`talosctl disks -n <node> -i` can be used to check allowed disk qualifiers when the node is running in the maintenance mode.\n\n\n### Optimizations\n\n* Talos `system` services now run without container images on initramfs from the single executable; this change reduces RAM usage, initramfs size and boot time..\n\n\n### SBCs\n\n* u-boot version was updated to fix the boot and USB issues on Raspberry Pi 4 8GiB version.\n* added support for Rock Pi 4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Spencer Smith\n* Seán C McCord\n* Andrew Rynhard\n* Jorik Jonker\n* bzub\n\n### Changes\n<details><summary>78 commits</summary>\n<p>\n\n* [`8309312a`](https://github.com/talos-systems/talos/commit/8309312a3db89cea17b673d0d1c73175db5258ac) chore: build components with race detector enabled in dev mode\n* [`7d912584`](https://github.com/talos-systems/talos/commit/7d9125847506dfadc7e137a30bf0c93ab9ca0b50) test: fix data race in apply config tests\n* [`204caf8e`](https://github.com/talos-systems/talos/commit/204caf8eb9c6c43a90c20ebaea8387584201e7f5) test: fix apply-config integration test, bump clusterctl version\n* [`d812099d`](https://github.com/talos-systems/talos/commit/d812099df3d060ae74cd3d28405ddacbdd72ab15) fix: address several issues in TUI installer\n* [`269c9ad0`](https://github.com/talos-systems/talos/commit/269c9ad0988f0f966a4e31a5ab744fed7d585385) fix: don't write to config object on access\n* [`a9451f57`](https://github.com/talos-systems/talos/commit/a9451f57129b0b452825850bba9477ac3c536547) feat: update Kubernetes to 1.21.0-beta.1\n* [`4b42ced4`](https://github.com/talos-systems/talos/commit/4b42ced4c2a300aa22f253435a4d6330770ec5c2) feat: add ability to disable comments in talosctl gen config\n* [`a0dcfc3d`](https://github.com/talos-systems/talos/commit/a0dcfc3d5288e633db80bf3e32d31e41756cc90f) fix: workaround race in containerd runner with stdin pipe\n* [`2ea20f59`](https://github.com/talos-systems/talos/commit/2ea20f598a01f3de95f633bdfaf5711738524ba2) feat: replace timed with time sync controller\n* [`c38a161a`](https://github.com/talos-systems/talos/commit/c38a161ade34f00f7af52d9ae047d7936246e7f0) test: add unit-test for machine config validation\n* [`a6106815`](https://github.com/talos-systems/talos/commit/a6106815b72efcb7f4df0caab6b93be49a7590ea) chore: bump dependencies via dependabot\n* [`35598f39`](https://github.com/talos-systems/talos/commit/35598f391d5d0659e3390d4db67c7ed88c17b6eb) chore: refactor: extract ClusterConfig\n* [`03285184`](https://github.com/talos-systems/talos/commit/032851844fdea4b1bde7507720025c981ee3b12c) fix: get rid of data race in encoder and fix concurrent map access\n* [`4b3580aa`](https://github.com/talos-systems/talos/commit/4b3580aa57d83358434238ad953793070cfc67a7) fix: prevent panic in validate config if `machine.install` is missing\n* [`d7e9f6d6`](https://github.com/talos-systems/talos/commit/d7e9f6d6a89143f0def74a270a21ed5e53556e07) chore: build integration tests with -race\n* [`9f7d67ac`](https://github.com/talos-systems/talos/commit/9f7d67ac717834ed428b8f13d4061db5f33c81f9) chore: fix typo\n* [`672c9707`](https://github.com/talos-systems/talos/commit/672c970739971dd0c558ad0319fe9fdbd66a741b) fix: allow `convert-k8s --remove-initialized-keys` with K8s cp is down\n* [`fb605a0f`](https://github.com/talos-systems/talos/commit/fb605a0fc56e6df1ceae8c391524ac987bbba09d) chore: tweak nolintlint settings\n* [`1f5a0c40`](https://github.com/talos-systems/talos/commit/1f5a0c4065e1fbd63ebe6d48c13e669bfb1dbeac) fix: resolve the issue with Kubernetes upgrade\n* [`74b2b557`](https://github.com/talos-systems/talos/commit/74b2b5578cbe639a6f2663df6ab7a5e80b139fe0) docs: update AWS docs to ensure instances are tagged\n* [`dc21d9b4`](https://github.com/talos-systems/talos/commit/dc21d9b4b0f5858fbe0d4072e8a47a934780c3dd) chore: remove old file\n* [`966caf7a`](https://github.com/talos-systems/talos/commit/966caf7a674c20047c1184e64f3727abc0c54296) chore: remove unused module replace directives\n* [`98b22f1e`](https://github.com/talos-systems/talos/commit/98b22f1e0b0f5e85b71d344041265efa95e1bb91) feat: show short options in talosctl kubeconfig\n* [`51139d54`](https://github.com/talos-systems/talos/commit/51139d54d4ce4acf2e78f11ab0f384f91f86ff33) chore: cache go modules in the build\n* [`65701aa7`](https://github.com/talos-systems/talos/commit/65701aa724130645fcabe521557225ff41b359b0) fix: resolve the issue with DHCP lease not being renewed\n* [`711f5b23`](https://github.com/talos-systems/talos/commit/711f5b23be69665d6204dbb80064e0ab0d1468c0) fix: config validation: CNI should apply to cp nodes, encryption config\n* [`5ff491d9`](https://github.com/talos-systems/talos/commit/5ff491d9686434a6208583dca97171bfbecf3f70) fix: allow empty list for CNI URLs\n* [`946e74f0`](https://github.com/talos-systems/talos/commit/946e74f047f30180bf5f0554fd8ae1043e0d1f52) docs: update path for kernel downloads in qemu docs\n* [`ed272e60`](https://github.com/talos-systems/talos/commit/ed272e604e67dc38557812e5f4dbcb8666c4b546) feat: update Kubernetes to 1.21.0-beta.0\n* [`b0209fd2`](https://github.com/talos-systems/talos/commit/b0209fd29d3895d7a0b8806e505bbefcf2bba520) refactor: move networkd, timed APIs to machined, remove routerd\n* [`6ffabe51`](https://github.com/talos-systems/talos/commit/6ffabe51691907b43f9f970f22d7aec4df19a6c3) feat: add ability to find disk by disk properties\n* [`ac876470`](https://github.com/talos-systems/talos/commit/ac8764702f980a8dea5b6a67f0bc33b5203efecb) refactor: move apid, routerd, timed and trustd to single executable\n* [`89a4b09f`](https://github.com/talos-systems/talos/commit/89a4b09fe8015e70f7074d9af72d47023ece2f1d) refactor: run networkd as a goroutine in machined\n* [`f4a6a19c`](https://github.com/talos-systems/talos/commit/f4a6a19cd1bf1da7f2610276c00e8144a78f8694) chore: update sonobuoy\n* [`dc294db1`](https://github.com/talos-systems/talos/commit/dc294db16c8bdb10e3f63987c87c0bbdf629b158) chore: bump dependencies via dependabot\n* [`2b1641a3`](https://github.com/talos-systems/talos/commit/2b1641a3b543d736eb0d2e359d2a25dbc906e631) docs: add AMIs for Talos 0.9.0\n* [`79ceb428`](https://github.com/talos-systems/talos/commit/79ceb428d4216a06418933058485ec2273474e3c) docs: make v0.9 the default docs\n* [`a5b62f4d`](https://github.com/talos-systems/talos/commit/a5b62f4dc20da721b0f74c5fbb5082038e05e4f4) docs: add documentation for Talos 0.10\n* [`ce795f1c`](https://github.com/talos-systems/talos/commit/ce795f1cea9d78c26edbcd4a40bb5d3637fde629) fix: command `etcd remove-member` shouldn't remove etcd data directory\n* [`aab49a16`](https://github.com/talos-systems/talos/commit/aab49a167b1f1cd3974e3aa1244d636ba712f678) fix: repair zsh completion\n* [`fc9c416a`](https://github.com/talos-systems/talos/commit/fc9c416a3c8425bb42892f740c910894610acd00) fix: build rockpi4 metal image as part of CI build\n* [`125b86f4`](https://github.com/talos-systems/talos/commit/125b86f4efbc2ed3e0a4bdfc945e97b05f1cb82c) fix: upgrade-k8s bug with empty config values and provision script\n* [`8b2d228d`](https://github.com/talos-systems/talos/commit/8b2d228dc42c196090aae1e6958683e265ebc05c) chore: add script for starting registry proxies\n* [`f7d276b8`](https://github.com/talos-systems/talos/commit/f7d276b854c4c06f85155c517cc1de7109a53359) chore: remove old `osctl` reference\n* [`5b14d6f2`](https://github.com/talos-systems/talos/commit/5b14d6f2b89c5b86f9ec2cb0271c6605272269d4) chore: fix `make help` output\n* [`f0512dfc`](https://github.com/talos-systems/talos/commit/f0512dfce9443cf20790ef8b4fd8e87906cc5bda) feat: update Kubernetes to 1.20.5\n* [`24cd0a20`](https://github.com/talos-systems/talos/commit/24cd0a20678f2728a0b36c1c401dd8af3d4932ed) feat: publish talosctl container image\n* [`6e17102c`](https://github.com/talos-systems/talos/commit/6e17102c210dccd4bf78d347de07cfe2ba7737c4) chore: remove unused code\n* [`88104407`](https://github.com/talos-systems/talos/commit/8810440744453550697ad39530633b81889d38b7) docs: add control plane in-depth guide\n* [`ecf03449`](https://github.com/talos-systems/talos/commit/ecf034496e7450f89369140ad1791188580dee0d) chore: bump Go to 1.16.2\n* [`cbc38418`](https://github.com/talos-systems/talos/commit/cbc38418d856a00ffb35d31676e1efb14fb6da36) release(v0.10.0-alpha.0): prepare release\n* [`3455a8e8`](https://github.com/talos-systems/talos/commit/3455a8e8185ba25777784d392d6150a4a7e2d4a9) chore: use new release tool for changelogs and release notes\n* [`08271ba9`](https://github.com/talos-systems/talos/commit/08271ba93178c17a7c495788fea00c5c380f8301) chore: use Go 1.16 language version\n* [`7662d033`](https://github.com/talos-systems/talos/commit/7662d033bfc3d6e3878e2c2a2a1ec4d71dc2502e) fix: talosctl health should not check kube-proxy when it is disabled\n* [`0dbaeb9e`](https://github.com/talos-systems/talos/commit/0dbaeb9e655acdc44f8b4db6d1bc6da2ddf6cc9d) chore: update tools, use new generators\n* [`e31790f6`](https://github.com/talos-systems/talos/commit/e31790f6f548095fe3f1b9a5c88b47e70c197d2c) fix: properly format spec comments in the resources\n* [`78d384eb`](https://github.com/talos-systems/talos/commit/78d384ebb6246cf41a73014312dfb0d86a8008d6) test: update aws cloud provider version\n* [`3c5bfbb4`](https://github.com/talos-systems/talos/commit/3c5bfbb4736c86f493a665dbfe63a6e2d20acb3d) fix: don't touch any partitions on upgrade with --preserve\n* [`891f90fe`](https://github.com/talos-systems/talos/commit/891f90fee9818f0f013878c0c77c1920e6427a91) chore: update Linux to 5.10.23\n* [`d4d77882`](https://github.com/talos-systems/talos/commit/d4d77882e3f53f2449f50f54116a407726f41ede) chore: update dependencies via dependabot\n* [`2e22f20b`](https://github.com/talos-systems/talos/commit/2e22f20bd876e4972bfdebd44fee13356b70b83f) docs: minor fixes to getting started\n* [`ca8a5596`](https://github.com/talos-systems/talos/commit/ca8a5596c79f638e52601e850236b715f906e3d2) chore: fix provision tests after changes to build-container\n* [`4aae924c`](https://github.com/talos-systems/talos/commit/4aae924c685ff578af06a1adceeec4f1938576a6) refactor: provide explicit logger for networkd\n* [`22f37530`](https://github.com/talos-systems/talos/commit/22f375300c1cc1d95db540afd510a21b66d7c8a3) chore: update golanci-lint to 1.38.0\n* [`83b4e7f7`](https://github.com/talos-systems/talos/commit/83b4e7f744e3a8ed21443642a9afcf5b1342c62b) feat: add Rock pi 4 support\n* [`1362966f`](https://github.com/talos-systems/talos/commit/1362966ff546ee620c14e9312255616685743eed) docs: rewrite getting-started for ISO\n* [`8e57fc4f`](https://github.com/talos-systems/talos/commit/8e57fc4f526096878213048658bae50cfac4cda8) fix: move containerd CRI config files under `/var/`\n* [`6f7df3da`](https://github.com/talos-systems/talos/commit/6f7df3da1e147212e6d4b40a5de65e5ca8be84db) fix: update output of `convert-k8s` command\n* [`dce6118c`](https://github.com/talos-systems/talos/commit/dce6118c290afe957e375586b6bbc5b10ef6ba09) docs: add guide for VIP\n* [`ee5d9ffa`](https://github.com/talos-systems/talos/commit/ee5d9ffac60c93561874995d8926fc329e2b67dc) chore: bump Go to 1.16.1\n* [`7c529e1c`](https://github.com/talos-systems/talos/commit/7c529e1cbd2be66d71e8496304781dd406495bdd) docs: fix links in the documentation\n* [`f596c7f6`](https://github.com/talos-systems/talos/commit/f596c7f6be3880be994faf7c5361628024c6be7d) docs: add video for raspberry pi install\n* [`47324dca`](https://github.com/talos-systems/talos/commit/47324dcaeaee94e4963eb3764fc01cd2d2d43041) docs: add guide on editing machine configuration\n* [`99d5f894`](https://github.com/talos-systems/talos/commit/99d5f894e17f39004e61ee9d5b64d5a8139f33d0) chore: update website npm dependencies\n* [`11056a80`](https://github.com/talos-systems/talos/commit/11056a80349e4c8df10a9ea98b6e3d53f96b971c) docs: add highlights for 0.9 release\n* [`ae8bedb9`](https://github.com/talos-systems/talos/commit/ae8bedb9a0d999bfbe97b6e18dc2eff62f0fcb80) docs: add control plane conversion guide and 0.9 upgrade notes\n* [`ed9673e5`](https://github.com/talos-systems/talos/commit/ed9673e50a7cb973fc49be9c2d659447a4c5bd62) docs: add troubleshooting control plane documentation\n* [`485cb126`](https://github.com/talos-systems/talos/commit/485cb1262f97e982ea81597b49d173836c75558d) docs: update Kubernetes upgrade guide\n</p>\n</details>\n\n### Changes since v0.10.0-alpha.0\n<details><summary>50 commits</summary>\n<p>\n\n* [`8309312a`](https://github.com/talos-systems/talos/commit/8309312a3db89cea17b673d0d1c73175db5258ac) chore: build components with race detector enabled in dev mode\n* [`7d912584`](https://github.com/talos-systems/talos/commit/7d9125847506dfadc7e137a30bf0c93ab9ca0b50) test: fix data race in apply config tests\n* [`204caf8e`](https://github.com/talos-systems/talos/commit/204caf8eb9c6c43a90c20ebaea8387584201e7f5) test: fix apply-config integration test, bump clusterctl version\n* [`d812099d`](https://github.com/talos-systems/talos/commit/d812099df3d060ae74cd3d28405ddacbdd72ab15) fix: address several issues in TUI installer\n* [`269c9ad0`](https://github.com/talos-systems/talos/commit/269c9ad0988f0f966a4e31a5ab744fed7d585385) fix: don't write to config object on access\n* [`a9451f57`](https://github.com/talos-systems/talos/commit/a9451f57129b0b452825850bba9477ac3c536547) feat: update Kubernetes to 1.21.0-beta.1\n* [`4b42ced4`](https://github.com/talos-systems/talos/commit/4b42ced4c2a300aa22f253435a4d6330770ec5c2) feat: add ability to disable comments in talosctl gen config\n* [`a0dcfc3d`](https://github.com/talos-systems/talos/commit/a0dcfc3d5288e633db80bf3e32d31e41756cc90f) fix: workaround race in containerd runner with stdin pipe\n* [`2ea20f59`](https://github.com/talos-systems/talos/commit/2ea20f598a01f3de95f633bdfaf5711738524ba2) feat: replace timed with time sync controller\n* [`c38a161a`](https://github.com/talos-systems/talos/commit/c38a161ade34f00f7af52d9ae047d7936246e7f0) test: add unit-test for machine config validation\n* [`a6106815`](https://github.com/talos-systems/talos/commit/a6106815b72efcb7f4df0caab6b93be49a7590ea) chore: bump dependencies via dependabot\n* [`35598f39`](https://github.com/talos-systems/talos/commit/35598f391d5d0659e3390d4db67c7ed88c17b6eb) chore: refactor: extract ClusterConfig\n* [`03285184`](https://github.com/talos-systems/talos/commit/032851844fdea4b1bde7507720025c981ee3b12c) fix: get rid of data race in encoder and fix concurrent map access\n* [`4b3580aa`](https://github.com/talos-systems/talos/commit/4b3580aa57d83358434238ad953793070cfc67a7) fix: prevent panic in validate config if `machine.install` is missing\n* [`d7e9f6d6`](https://github.com/talos-systems/talos/commit/d7e9f6d6a89143f0def74a270a21ed5e53556e07) chore: build integration tests with -race\n* [`9f7d67ac`](https://github.com/talos-systems/talos/commit/9f7d67ac717834ed428b8f13d4061db5f33c81f9) chore: fix typo\n* [`672c9707`](https://github.com/talos-systems/talos/commit/672c970739971dd0c558ad0319fe9fdbd66a741b) fix: allow `convert-k8s --remove-initialized-keys` with K8s cp is down\n* [`fb605a0f`](https://github.com/talos-systems/talos/commit/fb605a0fc56e6df1ceae8c391524ac987bbba09d) chore: tweak nolintlint settings\n* [`1f5a0c40`](https://github.com/talos-systems/talos/commit/1f5a0c4065e1fbd63ebe6d48c13e669bfb1dbeac) fix: resolve the issue with Kubernetes upgrade\n* [`74b2b557`](https://github.com/talos-systems/talos/commit/74b2b5578cbe639a6f2663df6ab7a5e80b139fe0) docs: update AWS docs to ensure instances are tagged\n* [`dc21d9b4`](https://github.com/talos-systems/talos/commit/dc21d9b4b0f5858fbe0d4072e8a47a934780c3dd) chore: remove old file\n* [`966caf7a`](https://github.com/talos-systems/talos/commit/966caf7a674c20047c1184e64f3727abc0c54296) chore: remove unused module replace directives\n* [`98b22f1e`](https://github.com/talos-systems/talos/commit/98b22f1e0b0f5e85b71d344041265efa95e1bb91) feat: show short options in talosctl kubeconfig\n* [`51139d54`](https://github.com/talos-systems/talos/commit/51139d54d4ce4acf2e78f11ab0f384f91f86ff33) chore: cache go modules in the build\n* [`65701aa7`](https://github.com/talos-systems/talos/commit/65701aa724130645fcabe521557225ff41b359b0) fix: resolve the issue with DHCP lease not being renewed\n* [`711f5b23`](https://github.com/talos-systems/talos/commit/711f5b23be69665d6204dbb80064e0ab0d1468c0) fix: config validation: CNI should apply to cp nodes, encryption config\n* [`5ff491d9`](https://github.com/talos-systems/talos/commit/5ff491d9686434a6208583dca97171bfbecf3f70) fix: allow empty list for CNI URLs\n* [`946e74f0`](https://github.com/talos-systems/talos/commit/946e74f047f30180bf5f0554fd8ae1043e0d1f52) docs: update path for kernel downloads in qemu docs\n* [`ed272e60`](https://github.com/talos-systems/talos/commit/ed272e604e67dc38557812e5f4dbcb8666c4b546) feat: update Kubernetes to 1.21.0-beta.0\n* [`b0209fd2`](https://github.com/talos-systems/talos/commit/b0209fd29d3895d7a0b8806e505bbefcf2bba520) refactor: move networkd, timed APIs to machined, remove routerd\n* [`6ffabe51`](https://github.com/talos-systems/talos/commit/6ffabe51691907b43f9f970f22d7aec4df19a6c3) feat: add ability to find disk by disk properties\n* [`ac876470`](https://github.com/talos-systems/talos/commit/ac8764702f980a8dea5b6a67f0bc33b5203efecb) refactor: move apid, routerd, timed and trustd to single executable\n* [`89a4b09f`](https://github.com/talos-systems/talos/commit/89a4b09fe8015e70f7074d9af72d47023ece2f1d) refactor: run networkd as a goroutine in machined\n* [`f4a6a19c`](https://github.com/talos-systems/talos/commit/f4a6a19cd1bf1da7f2610276c00e8144a78f8694) chore: update sonobuoy\n* [`dc294db1`](https://github.com/talos-systems/talos/commit/dc294db16c8bdb10e3f63987c87c0bbdf629b158) chore: bump dependencies via dependabot\n* [`2b1641a3`](https://github.com/talos-systems/talos/commit/2b1641a3b543d736eb0d2e359d2a25dbc906e631) docs: add AMIs for Talos 0.9.0\n* [`79ceb428`](https://github.com/talos-systems/talos/commit/79ceb428d4216a06418933058485ec2273474e3c) docs: make v0.9 the default docs\n* [`a5b62f4d`](https://github.com/talos-systems/talos/commit/a5b62f4dc20da721b0f74c5fbb5082038e05e4f4) docs: add documentation for Talos 0.10\n* [`ce795f1c`](https://github.com/talos-systems/talos/commit/ce795f1cea9d78c26edbcd4a40bb5d3637fde629) fix: command `etcd remove-member` shouldn't remove etcd data directory\n* [`aab49a16`](https://github.com/talos-systems/talos/commit/aab49a167b1f1cd3974e3aa1244d636ba712f678) fix: repair zsh completion\n* [`fc9c416a`](https://github.com/talos-systems/talos/commit/fc9c416a3c8425bb42892f740c910894610acd00) fix: build rockpi4 metal image as part of CI build\n* [`125b86f4`](https://github.com/talos-systems/talos/commit/125b86f4efbc2ed3e0a4bdfc945e97b05f1cb82c) fix: upgrade-k8s bug with empty config values and provision script\n* [`8b2d228d`](https://github.com/talos-systems/talos/commit/8b2d228dc42c196090aae1e6958683e265ebc05c) chore: add script for starting registry proxies\n* [`f7d276b8`](https://github.com/talos-systems/talos/commit/f7d276b854c4c06f85155c517cc1de7109a53359) chore: remove old `osctl` reference\n* [`5b14d6f2`](https://github.com/talos-systems/talos/commit/5b14d6f2b89c5b86f9ec2cb0271c6605272269d4) chore: fix `make help` output\n* [`f0512dfc`](https://github.com/talos-systems/talos/commit/f0512dfce9443cf20790ef8b4fd8e87906cc5bda) feat: update Kubernetes to 1.20.5\n* [`24cd0a20`](https://github.com/talos-systems/talos/commit/24cd0a20678f2728a0b36c1c401dd8af3d4932ed) feat: publish talosctl container image\n* [`6e17102c`](https://github.com/talos-systems/talos/commit/6e17102c210dccd4bf78d347de07cfe2ba7737c4) chore: remove unused code\n* [`88104407`](https://github.com/talos-systems/talos/commit/8810440744453550697ad39530633b81889d38b7) docs: add control plane in-depth guide\n* [`ecf03449`](https://github.com/talos-systems/talos/commit/ecf034496e7450f89369140ad1791188580dee0d) chore: bump Go to 1.16.2\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>2 commits</summary>\n<p>\n\n* [`c0fa0c0`](https://github.com/talos-systems/extras/commit/c0fa0c04641d8dfc418888c210788a6894e8d40c) feat: bump Go to 1.16.2\n* [`5f89d77`](https://github.com/talos-systems/extras/commit/5f89d77a91f44d52146dae9c23b4654d219042b9) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Changes from talos-systems/go-blockdevice\n<details><summary>1 commit</summary>\n<p>\n\n* [`776b37d`](https://github.com/talos-systems/go-blockdevice/commit/776b37d31de0781f098f5d9d1894fbea3f2dfa1d) feat: add options to probe disk by various sysblock parameters\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>6 commits</summary>\n<p>\n\n* [`fdf4866`](https://github.com/talos-systems/pkgs/commit/fdf48667851b4c80b0ca220c574d2fb57a943f64) feat: bump tools for Go 1.16.2\n* [`35f9b6f`](https://github.com/talos-systems/pkgs/commit/35f9b6f22bbe094e93723559132b2a23f0853c2b) feat: update kernel to 5.10.23\n* [`dbae83e`](https://github.com/talos-systems/pkgs/commit/dbae83e704da264066ceeca20e0fe66883b542ba) fix: do not use git-lfs for rockpi4 binaries\n* [`1c6b9a3`](https://github.com/talos-systems/pkgs/commit/1c6b9a3a6ef91bce4f0cba18c466a9ece7b14750) feat: bump tools for Go 1.16.1\n* [`c18073f`](https://github.com/talos-systems/pkgs/commit/c18073fe79b9d7ec36411c6f329fa60c580d4cea) feat: add u-boot for Rock Pi 4\n* [`6b85a2b`](https://github.com/talos-systems/pkgs/commit/6b85a2bffbb144f25356eed6ed9dc8bb9a3fd392) feat: upgrade u-boot to 2021.04-rc3\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>4 commits</summary>\n<p>\n\n* [`41b8073`](https://github.com/talos-systems/tools/commit/41b807369779606f54d76e56038bfaf88d4f0f25) feat: bump protobuf-related tools\n* [`f7bce92`](https://github.com/talos-systems/tools/commit/f7bce92febdf9f58f2940952d5138494b9232ea8) chore: bump Go to 1.16.2\n* [`bcf3380`](https://github.com/talos-systems/tools/commit/bcf3380dd55810e556851acbe20e20cb4ddd5ef0) feat: bump protobuf deps, add protoc-gen-go-grpc\n* [`b49c40e`](https://github.com/talos-systems/tools/commit/b49c40e0ad701f13192c1ad85ec616224343dc3f) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/coreos/go-semver**              v0.3.0 **_new_**\n* **github.com/golang/protobuf**               v1.4.3 -> v1.5.1\n* **github.com/google/go-cmp**                 v0.5.4 -> v0.5.5\n* **github.com/hashicorp/go-multierror**       v1.1.0 -> v1.1.1\n* **github.com/talos-systems/extras**          v0.2.0-1-g0db3328 -> v0.3.0-alpha.0-1-gc0fa0c0\n* **github.com/talos-systems/go-blockdevice**  bb3ad73f6983 -> 776b37d31de0\n* **github.com/talos-systems/pkgs**            v0.4.1-2-gd471b60 -> v0.5.0-alpha.0-3-gfdf4866\n* **github.com/talos-systems/tools**           v0.4.0-1-g3b25a7e -> v0.5.0-alpha.0-3-g41b8073\n* **google.golang.org/grpc**                   v1.36.0 -> v1.36.1\n* **google.golang.org/protobuf**               v1.25.0 -> v1.26.0\n* **k8s.io/api**                               v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/apimachinery**                      v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/apiserver**                         v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/client-go**                         v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/cri-api**                           v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/kubectl**                           v0.20.5 -> v0.21.0-rc.0\n* **k8s.io/kubelet**                           v0.20.5 -> v0.21.0-rc.0\n\nPrevious release can be found at [v0.9.0](https://github.com/talos-systems/talos/releases/tag/v0.9.0)\n\n## [Talos 0.10.0-alpha.0](https://github.com/talos-systems/talos/releases/tag/v0.10.0-alpha.0) (2021-03-17)\n\nWelcome to the v0.10.0-alpha.0 release of Talos!\n*This is a pre-release of Talos*\n\n\n\nPlease try out the release binaries and report any issues at\nhttps://github.com/talos-systems/talos/issues.\n\n### SBCs\n\n* u-boot version was updated to fix the boot and USB issues on Raspberry Pi 4 8GiB version.\n* added support for Rock Pi 4.\n\n\n### Contributors\n\n* Andrey Smirnov\n* Alexey Palazhchenko\n* Artem Chernyshev\n* Seán C McCord\n* Spencer Smith\n* Andrew Rynhard\n\n### Changes\n<details><summary>27 commits</summary>\n<p>\n\n* [`3455a8e8`](https://github.com/talos-systems/talos/commit/3455a8e8185ba25777784d392d6150a4a7e2d4a9) chore: use new release tool for changelogs and release notes\n* [`08271ba9`](https://github.com/talos-systems/talos/commit/08271ba93178c17a7c495788fea00c5c380f8301) chore: use Go 1.16 language version\n* [`7662d033`](https://github.com/talos-systems/talos/commit/7662d033bfc3d6e3878e2c2a2a1ec4d71dc2502e) fix: talosctl health should not check kube-proxy when it is disabled\n* [`0dbaeb9e`](https://github.com/talos-systems/talos/commit/0dbaeb9e655acdc44f8b4db6d1bc6da2ddf6cc9d) chore: update tools, use new generators\n* [`e31790f6`](https://github.com/talos-systems/talos/commit/e31790f6f548095fe3f1b9a5c88b47e70c197d2c) fix: properly format spec comments in the resources\n* [`78d384eb`](https://github.com/talos-systems/talos/commit/78d384ebb6246cf41a73014312dfb0d86a8008d6) test: update aws cloud provider version\n* [`3c5bfbb4`](https://github.com/talos-systems/talos/commit/3c5bfbb4736c86f493a665dbfe63a6e2d20acb3d) fix: don't touch any partitions on upgrade with --preserve\n* [`891f90fe`](https://github.com/talos-systems/talos/commit/891f90fee9818f0f013878c0c77c1920e6427a91) chore: update Linux to 5.10.23\n* [`d4d77882`](https://github.com/talos-systems/talos/commit/d4d77882e3f53f2449f50f54116a407726f41ede) chore: update dependencies via dependabot\n* [`2e22f20b`](https://github.com/talos-systems/talos/commit/2e22f20bd876e4972bfdebd44fee13356b70b83f) docs: minor fixes to getting started\n* [`ca8a5596`](https://github.com/talos-systems/talos/commit/ca8a5596c79f638e52601e850236b715f906e3d2) chore: fix provision tests after changes to build-container\n* [`4aae924c`](https://github.com/talos-systems/talos/commit/4aae924c685ff578af06a1adceeec4f1938576a6) refactor: provide explicit logger for networkd\n* [`22f37530`](https://github.com/talos-systems/talos/commit/22f375300c1cc1d95db540afd510a21b66d7c8a3) chore: update golanci-lint to 1.38.0\n* [`83b4e7f7`](https://github.com/talos-systems/talos/commit/83b4e7f744e3a8ed21443642a9afcf5b1342c62b) feat: add Rock pi 4 support\n* [`1362966f`](https://github.com/talos-systems/talos/commit/1362966ff546ee620c14e9312255616685743eed) docs: rewrite getting-started for ISO\n* [`8e57fc4f`](https://github.com/talos-systems/talos/commit/8e57fc4f526096878213048658bae50cfac4cda8) fix: move containerd CRI config files under `/var/`\n* [`6f7df3da`](https://github.com/talos-systems/talos/commit/6f7df3da1e147212e6d4b40a5de65e5ca8be84db) fix: update output of `convert-k8s` command\n* [`dce6118c`](https://github.com/talos-systems/talos/commit/dce6118c290afe957e375586b6bbc5b10ef6ba09) docs: add guide for VIP\n* [`ee5d9ffa`](https://github.com/talos-systems/talos/commit/ee5d9ffac60c93561874995d8926fc329e2b67dc) chore: bump Go to 1.16.1\n* [`7c529e1c`](https://github.com/talos-systems/talos/commit/7c529e1cbd2be66d71e8496304781dd406495bdd) docs: fix links in the documentation\n* [`f596c7f6`](https://github.com/talos-systems/talos/commit/f596c7f6be3880be994faf7c5361628024c6be7d) docs: add video for raspberry pi install\n* [`47324dca`](https://github.com/talos-systems/talos/commit/47324dcaeaee94e4963eb3764fc01cd2d2d43041) docs: add guide on editing machine configuration\n* [`99d5f894`](https://github.com/talos-systems/talos/commit/99d5f894e17f39004e61ee9d5b64d5a8139f33d0) chore: update website npm dependencies\n* [`11056a80`](https://github.com/talos-systems/talos/commit/11056a80349e4c8df10a9ea98b6e3d53f96b971c) docs: add highlights for 0.9 release\n* [`ae8bedb9`](https://github.com/talos-systems/talos/commit/ae8bedb9a0d999bfbe97b6e18dc2eff62f0fcb80) docs: add control plane conversion guide and 0.9 upgrade notes\n* [`ed9673e5`](https://github.com/talos-systems/talos/commit/ed9673e50a7cb973fc49be9c2d659447a4c5bd62) docs: add troubleshooting control plane documentation\n* [`485cb126`](https://github.com/talos-systems/talos/commit/485cb1262f97e982ea81597b49d173836c75558d) docs: update Kubernetes upgrade guide\n</p>\n</details>\n\n### Changes since v0.10.0-alpha.0\n<details><summary>0 commit</summary>\n<p>\n\n</p>\n</details>\n\n### Changes from talos-systems/extras\n<details><summary>1 commit</summary>\n<p>\n\n* [`5f89d77`](https://github.com/talos-systems/extras/commit/5f89d77a91f44d52146dae9c23b4654d219042b9) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Changes from talos-systems/os-runtime\n<details><summary>1 commit</summary>\n<p>\n\n* [`7b3d144`](https://github.com/talos-systems/os-runtime/commit/7b3d14457439d4fc10928cd6332c867b4acbae45) feat: use go-yaml fork and serialize spec as RawYAML objects\n</p>\n</details>\n\n### Changes from talos-systems/pkgs\n<details><summary>5 commits</summary>\n<p>\n\n* [`35f9b6f`](https://github.com/talos-systems/pkgs/commit/35f9b6f22bbe094e93723559132b2a23f0853c2b) feat: update kernel to 5.10.23\n* [`dbae83e`](https://github.com/talos-systems/pkgs/commit/dbae83e704da264066ceeca20e0fe66883b542ba) fix: do not use git-lfs for rockpi4 binaries\n* [`1c6b9a3`](https://github.com/talos-systems/pkgs/commit/1c6b9a3a6ef91bce4f0cba18c466a9ece7b14750) feat: bump tools for Go 1.16.1\n* [`c18073f`](https://github.com/talos-systems/pkgs/commit/c18073fe79b9d7ec36411c6f329fa60c580d4cea) feat: add u-boot for Rock Pi 4\n* [`6b85a2b`](https://github.com/talos-systems/pkgs/commit/6b85a2bffbb144f25356eed6ed9dc8bb9a3fd392) feat: upgrade u-boot to 2021.04-rc3\n</p>\n</details>\n\n### Changes from talos-systems/tools\n<details><summary>2 commits</summary>\n<p>\n\n* [`bcf3380`](https://github.com/talos-systems/tools/commit/bcf3380dd55810e556851acbe20e20cb4ddd5ef0) feat: bump protobuf deps, add protoc-gen-go-grpc\n* [`b49c40e`](https://github.com/talos-systems/tools/commit/b49c40e0ad701f13192c1ad85ec616224343dc3f) feat: bump Go to 1.16.1\n</p>\n</details>\n\n### Dependency Changes\n\n* **github.com/hashicorp/go-multierror**   v1.1.0 -> v1.1.1\n* **github.com/talos-systems/extras**      v0.2.0 -> v0.3.0-alpha.0\n* **github.com/talos-systems/os-runtime**  84c3c875eb2b -> 7b3d14457439\n* **github.com/talos-systems/pkgs**        v0.4.1 -> v0.5.0-alpha.0-2-g35f9b6f\n* **github.com/talos-systems/tools**       v0.4.0 -> v0.5.0-alpha.0-1-gbcf3380\n\nPrevious release can be found at [v0.9.0-beta.0](https://github.com/talos-systems/talos/releases/tag/v0.9.0-beta.0)\n\n<a name=\"v0.9.0-alpha.5\"></a>\n## [v0.9.0-alpha.5](https://github.com/talos-systems/talos/compare/v0.9.0-alpha.4...v0.9.0-alpha.5) (2021-03-03)\n\n### Chore\n\n* bump Go module dependencies\n* properly propagate context object in the controller\n\n### Feat\n\n* bypass lock if ACPI reboot/shutdown issued\n* add `--on-reboot` flag to talosctl edit/patch machineConfig\n* support JSON output in `talosctl get`, event types\n* rename namespaces, resources, types etc\n\n<a name=\"v0.9.0-alpha.4\"></a>\n## [v0.9.0-alpha.4](https://github.com/talos-systems/talos/compare/v0.9.0-alpha.3...v0.9.0-alpha.4) (2021-03-02)\n\n### Chore\n\n* update provision/upgrade tests to 0.9.0-alpha.3\n\n### Docs\n\n* bump v0.8 release version in the SBCs guides\n* add disk encryption guide\n\n### Feat\n\n* update linux kernel to 5.10.19\n\n### Fix\n\n* ignore 'ENOENT' (no such file directory) on mount\n* move etcd to `cri` containerd runner\n\n<a name=\"v0.9.0-alpha.3\"></a>\n## [v0.9.0-alpha.3](https://github.com/talos-systems/talos/compare/v0.9.0-alpha.2...v0.9.0-alpha.3) (2021-03-01)\n\n### Chore\n\n* bump dependencies via dependabot\n* build both Darwin and Linux versions of talosctl\n* bump dependencies via dependabot\n* switch CI to stop embedding local registry into the builds\n\n### Docs\n\n* update AMI images for 0.8.4\n\n### Feat\n\n* implement etcd remove-member cli command\n* update etcd to 3.4.15\n* talosctl: allow v-prefixed k8s versions\n* implement simple layer 2 shared IP for CP\n* implement talosctl edit and patch config commands\n* bump etcd client library to 3.5.0-alpha.0\n\n### Fix\n\n* update in-cluster kubeconfig validity to match other certs\n* add ApplyDynamicConfig call in the apply-config --immediate mode\n* set hdmi_safe=1 on Raspberry Pi for maximum HDMI compatibility\n* show stopped/exited containers via CRI inspector\n* make ApplyDynamicConfig idempotent\n* improve the drain function\n* correctly set service state in the resource\n* update the layout of the Disks API to match proxying requirements\n* stop and clean up installer container  correctly\n* sanitize volume name better in static pod extra volumes\n\n### Refactor\n\n* add context to the networkd\n* split WithNetworkConfig into sub-options\n\n### Test\n\n* add integration test with Canal CNI and reset API\n* upgrade master to master tests\n\n<a name=\"v0.9.0-alpha.2\"></a>\n## [v0.9.0-alpha.2](https://github.com/talos-systems/talos/compare/v0.9.0-alpha.1...v0.9.0-alpha.2) (2021-02-20)\n\n### Chore\n\n* add default cron pipeline to the list of pipelines\n* run default pipeline as part of the `cron` pipeline\n\n### Docs\n\n* add link to GitHub Discussions as a support forum\n\n### Feat\n\n* u-boot 2021.01, ca-certificates update, Linux file ACLs\n* support control plane upgrades with Talos managed control plane\n* add support for extra volume mounts for control plane pods\n* add a warning to boot log if running self-hosted control plane\n* add an option to disable kube-proxy manifest\n* update Kubernetes to 1.20.4\n* add state encryption support\n\n### Fix\n\n* redirect warnings in manifest apply k8s client\n* handle case when kubelet serving certificates are issued\n* correctly escape extra args in kube-proxy manifest\n* skip empty manifest YAML sub-documents\n\n### Refactor\n\n* split kubernetes/etcd resource generation into subresources\n\n### Test\n\n* enable disk encryption key rotation test\n* update integration tests to use wrapped client for etcd APIs\n\n<a name=\"v0.9.0-alpha.1\"></a>\n## [v0.9.0-alpha.1](https://github.com/talos-systems/talos/compare/v0.9.0-alpha.0...v0.9.0-alpha.1) (2021-02-09)\n\n### Chore\n\n* update artifacts bucket name in Drone\n* rework Drone pipelines\n* update dependencies via dependabot\n* **ci:** fix schedules in Drone pipelines\n* **ci:** update gcp templates\n\n### Docs\n\n* update AMI list for 0.8.2\n* fix typos\n\n### Feat\n\n* add a tool and package to convert self-hosted CP to static pods\n* implement ephemeral partition encryption\n* add resource watch API + CLI\n* rename apply-config --no-reboot to --on-reboot\n* skip filesystem for state and ephemeral partitions in the installer\n* stop all pods before unmounting ephemeral partition\n* bump Go to 1.15.8\n* support version contract for Talos config generation\n* update Linux to 5.10.14\n* add an option to force upgrade without checks\n* upgrade CoreDNS to 1.8.0\n* implement IPv6 DHCP client in networkd\n\n### Fix\n\n* correctly unwrap responses for etcd commands\n* drop cri dependency on etcd\n* move versions to annotations in control plane static pods\n* find master node IPs correctly in health checks\n* add 3 seconds grub boot timeout\n* don't use filename from URL when downloading manifest\n* pass attributes when adding routes\n* correct response structure for GenerateConfig API\n* correctly extract wrapped error messages\n* prevent crash in machined on apid service stop\n* wait for time sync before generating Kubernetes certificates\n* set proper hostname on docker nodes\n* mount kubelet secrets from system instead of ephemeral\n* allow loading of empty config files\n* prefer configured nameservers, fix DHCP6 in container\n* refresh control plane endpoints on worker apids on schedule\n* update DHCP client to use Request-Ack sequence after an Offer\n\n### Refactor\n\n* extract go-cmd into a separate library\n\n### Test\n\n* trigger e2e on thrice daily\n* update aws templates\n* add support for IPv6 in talosctl cluster create\n\n<a name=\"v0.9.0-alpha.0\"></a>\n## [v0.9.0-alpha.0](https://github.com/talos-systems/talos/compare/v0.8.1...v0.9.0-alpha.0) (2021-02-01)\n\n### Chore\n\n* bump dependencies (via dependabot)\n* fix import path for fsnotify\n* add dependabot config\n* enable virtio-balloon and monitor in QEMU provisioner\n* update protobuf, grpc-go, prototool\n* update upgrade test version used\n\n### Docs\n\n* update components.md\n* add v0.9 docs\n* add modes to validate command\n* document omitting DiskPartition size\n* update references to 0.8.0, add 0.8.0 AWS AMIs\n* fix latest docs\n* set latest docs to v0.8\n* provide AMIs for 0.8.0-beta.0\n* fix SBC docs to point to beta.0 instead of beta.1\n* update Talos release for SBCs\n\n### Feat\n\n* move to ECDSA keys for all Kubernetes/etcd certs and keys\n* update kernel\n* mount hugetlbfs\n* allow fqdn to be used when registering k8s node\n* copy cryptsetup executable from pkgs\n* use multi-arch images for k8s and Flannel CNI\n* replace bootkube with Talos-managed control plane\n* implement resource API in Talos\n* update Linux to 5.10.7, musl-libc to 1.2.2\n* update Kubernetes to 1.20.2\n* support Wireguard networking\n* bump pkgs for kernel with CONFIG_IPV6_MULTIPLE_TABLES\n* support type filter in list API and CLI\n* add commands to manage/query etcd cluster\n* support disk image in talosctl cluster create\n* update Kubernetes to 1.20.1\n\n### Fix\n\n* use hugetlbfs instead of none\n* use grpc load-balancing when connecting to trustd\n* lower memory usage a bit by disabling memory profiling\n* don't probe disks in container mode\n* prefix rendered Talos-owned static pod manifests\n* bump timeout for worker apid waiting for kubelet client config\n* kill all processes and umount all disk on reboot/shutdown\n* open blockdevices with exclusive flock for partitioning\n* list command unlimited recursion default behavior\n* pick first interface valid hostname (vs. last one)\n* allow 'console' argument in kernel args to be always overridden\n* bring up bonded interfaces correctly on packet\n* checkpoint controller-manager and scheduler\n* correctly transport gRPC errors from apid\n* use SetAll instead of AppendAll when building kernel args\n* add more dependencies for bootstrap services\n* pass disk image flags to e2e-qemu cluster create command\n* ignore pods spun up from checkpoints in health checks\n* leave etcd for staged upgrades\n* ignore errors on stopping/removing pod sandboxes\n* use the correct console on Banana Pi M64\n* don't run LabelNodeAsMaster in two sequences\n\n### Refactor\n\n* update go-blockdevice and restructure disk interaction code\n* define default kernel flags in machinery instead of procfs\n\n### Test\n\n* clear connection refused errors after reset\n* skip etcd tests on non-HA clusters\n\n\n<a name=\"v0.8.0-alpha.3\"></a>\n## [v0.8.0-alpha.3](https://github.com/talos-systems/talos/compare/v0.8.0-alpha.2...v0.8.0-alpha.3) (2020-12-10)\n\n### Chore\n\n* update CONTRIBUTING.md\n* limit unit-test run concurrency\n* bump Go to 1.15.6\n* bump dockerfile frontend version\n* fix conform for releases\n\n### Docs\n\n* update Equinix Metal guide\n* add architectural doc on the root file system layout\n* add a note on caveats in container mode\n* add storage doc\n* add guide for custom CAs\n* add docs for network connectivity\n* improve SBC documentation\n\n### Feat\n\n* update kernel to 5.9.13, new KSPP requirements\n* reset with system disk wipe spec\n* add talosctl merge config command\n* add talosctl config contexts\n* update Kubernetes to 1.20.0\n* implement \"staged\" (failsafe/backup) upgrades\n* allow disabling NoSchedule taint on masters using TUI installer\n\n### Fix\n\n* remove kmsg ratelimiting on startup\n* zero out partitions without filesystems on install\n* make interactive installer work without endpoints provided\n\n### Test\n\n* add ISO test\n* add support for mounting ISO in talosctl cluster create\n* bump Talos release version for upgrade test to 0.7.1\n* bump defaults for provision tests resources\n\n\n<a name=\"v0.8.0-alpha.2\"></a>\n## [v0.8.0-alpha.2](https://github.com/talos-systems/talos/compare/v0.8.0-alpha.1...v0.8.0-alpha.2) (2020-12-04)\n\n### Chore\n\n* publish Rock64 image\n* enable thrice daily pipeline\n* run integration test thrice daily\n* output SBC images as compressed raw images\n* build SBC images\n* update module dependencies\n* drop support for `docker load`\n* fix metal image name\n* use IMAGE_TAG instead of TAG for :latest pushes\n\n### Docs\n\n* fix typos\n* add openstack docs\n* ensure port for vbox and proxmox docs\n* add console kernel arg to rpi_4 image generation\n* add console kernel arg to libretech_all_h3_cc_h5 image generation\n\n### Feat\n\n* add support for the Pine64 Rock64\n* add TUI for configuring network interfaces settings\n* make GenerateConfiguration accept current time as a parameter\n* introduce configpatcher package in machinery\n* suggest fixed control plane endpoints in talosctl gen config\n* update kubernetes to 1.20.0-rc.0\n* allow boards to set kernel args\n* add support for the Banana Pi M64\n* stop including K8s version by default in `talosctl gen config`\n* add support for the Raspberry Pi 4 Model B\n* implement network interfaces list API\n* bump package for kernel with CIFS support\n* upgrade etcd to 3.4.14\n* update Containerd and Linux\n* add support for installing to SBCs\n* add ability to choose CNI config\n\n### Fix\n\n* make default generate image arch dynamic based on arch\n* stabilize serial console on RPi4, add video console\n* make reset work again\n* node taint doesn't contain value anymore\n* defer resolving config context in client code\n* remove value (change to empty) for `NoSchedule` taint\n* prevent endless loop with DHCP requests in networkd\n* skip `board` argument to the installer if it's not set\n* use the dtb from kernel pkg for libretech_all_h3_cc_h5\n* prevent crash in `talosctl config` commands\n* update generated .ova manifest for raw disk size\n* **security:** update Containerd to v1.4.3\n\n### Release\n\n* **v0.8.0-alpha.2:** prepare release\n\n\n<a name=\"v0.8.0-alpha.1\"></a>\n## [v0.8.0-alpha.1](https://github.com/talos-systems/talos/compare/v0.8.0-alpha.0...v0.8.0-alpha.1) (2020-11-26)\n\n### Chore\n\n* add cloud image uploader (AWS AMIs for now)\n* bump K8s to 1.19.4 in e2e scripts with CABPT version\n* build arm64 images in CI\n* remove maintenance service interface and use machine service\n\n### Docs\n\n* provide list of AMIs on AWS documentation page\n* add 0.8 docs for the upcoming release\n* ensure we configure nodes in guides\n* ensure gcp docs have firewall and node info\n* add qemu diagram and video walkthrough\n* graduate v0.7 docs\n* improve configuration reference documentation\n* fix small typo in talosctl processes cast\n* update asciinemas with talosctl\n* add proxmox doc\n* add live walkthroughs where applicable\n\n### Feat\n\n* support openstack platform\n* update Kubernetes to v1.20.0-beta.2\n* change UI component for disks selector\n* support cluster expansion in the interactive installer\n* implement apply configuration without reboot\n* make GenerateConfiguration API reuse current node auth\n* sync time before installer runs\n* set interface MTU in DHCP mode even if DHCP is not successful\n* print hint about using interative installer in mainenance mode\n* add TUI based talos interactive installer\n* support ipv6 routes\n* return client config as the second value in GenerateConfiguration\n* correctly merge talosconfig (don't ever overwrite)\n* drop to maintenance mode in cloud platforms if userdata is missing\n* read config from extra guestinfo key (vmware)\n* update Go to 1.15.5\n* add generate config gRPC API\n* upgrade Kubernetes default version to 1.19.4\n* add example command in maintenance, enforce cert fingerprint\n* add storage API\n\n### Fix\n\n* bump blockdevice library for `mmcblk` part name fix\n* ignore 'not found' errors when stopping/removing CRI pods\n* return hostname from packet platform\n* make fingerprint clearly optional in a boot hint\n* ensure packet nics get all IPs\n* use ghcr.io/talos-systems/kubelet\n* bump timeout for config downloading on bare metal\n\n### Refactor\n\n* drop osd compatibility layer\n\n### Release\n\n* **v0.8.0-alpha.1:** prepare release\n\n### Test\n\n* update integration test versions, clean up names\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at [INSERT EMAIL ADDRESS]. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nMore information about contributing to Talos can be found in the [Documentation](https://docs.siderolabs.com/talos/latest/build-and-extend-talos/custom-images-and-development/developing-talos).\n\n## Developer Certificate of Origin\n\nAll commits require a [DCO](https://developercertificate.org/) sign-off.\nThis is done by committing with the `--signoff` flag.\n\n## Development\n\nThe build process for this project is designed to run entirely in containers.\nTo get started, run `make help` and follow the instructions.\n\n## Conformance\n\nTo verify conformance status, run `make conformance`.\nThis runs a series of tests on the working tree and is required to pass before a contribution is accepted.\n"
  },
  {
    "path": "Dockerfile",
    "content": "# syntax = docker/dockerfile-upstream:1.22.0-labs\n\n# Meta args applied to stage base names.\n\nARG TOOLS=scratch\nARG PKGS=scratch\nARG INSTALLER_ARCH=scratch\nARG DEBUG_TOOLS_SOURCE=scratch\n\nARG PKGS_PREFIX=scratch\nARG TOOLS_PREFIX=scratch\n\nARG GENERATE_VEX_PREFIX=scratch\nARG GENERATE_VEX=scratch\n\nARG PKG_APPARMOR=scratch\nARG PKG_CA_CERTIFICATES=scratch\nARG PKG_CNI=scratch\nARG PKG_CONTAINERD=scratch\nARG PKG_CPIO=scratch\nARG PKG_CRYPTSETUP=scratch\nARG PKG_DOSFSTOOLS=scratch\nARG PKG_E2FSPROGS=scratch\nARG PKG_FHS=scratch\nARG PKG_FLANNEL_CNI=scratch\nARG PKG_GLIB=scratch\nARG PKG_GRUB=scratch\nARG PKG_IGZIP=scratch\nARG PKG_IPTABLES=scratch\nARG PKG_IPXE=scratch\nARG PKG_KERNEL=scratch\nARG PKG_KMOD=scratch\nARG PKG_LIBAIO=scratch\nARG PKG_LIBARCHIVE=scratch\nARG PKG_LIBATTR=scratch\nARG PKG_LIBBURN=scratch\nARG PKG_LIBCAP=scratch\nARG PKG_LIBINIH=scratch\nARG PKG_LIBISOBURN=scratch\nARG PKG_LIBISOFS=scratch\nARG PKG_LIBJANSSON=scratch\nARG PKG_LIBJSON_C=scratch\nARG PKG_LIBLZMA=scratch\nARG PKG_LIBMNL=scratch\nARG PKG_LIBNFTNL=scratch\nARG PKG_LIBPOPT=scratch\nARG PKG_LIBSELINUX=scratch\nARG PKG_LIBSEPOL=scratch\nARG PKG_LIBURCU=scratch\nARG PKG_LINUX_FIRMWARE=scratch\nARG PKG_LVM2=scratch\nARG PKG_MTOOLS=scratch\nARG PKG_MUSL=scratch\nARG PKG_NFTABLES=scratch\nARG PKG_OPENSSL=scratch\nARG PKG_OPEN_VMDK=scratch\nARG PKG_PCRE2=scratch\nARG PKG_PIGZ=scratch\nARG PKG_QEMU_TOOLS=scratch\nARG PKG_RUNC=scratch\nARG PKG_SD_BOOT=scratch\nARG PKG_SQUASHFS_TOOLS=scratch\nARG PKG_SYSTEMD_UDEVD=scratch\nARG PKG_TALOSCTL_CNI_BUNDLE=scratch\nARG PKG_TAR=scratch\nARG PKG_UTIL_LINUX=scratch\nARG PKG_XFSPROGS=scratch\nARG PKG_XZ=scratch\nARG PKG_ZLIB=scratch\nARG PKG_ZSTD=scratch\n\nARG DEBUG_TOOLS_SOURCE=scratch\n\nARG EMBED_TARGET=embed\n\n# Resolve package images using ${PKGS} to be used later in COPY --from=.\n\nFROM ${PKG_FHS} AS pkg-fhs\nFROM ${PKG_CA_CERTIFICATES} AS pkg-ca-certificates\n\nFROM --platform=amd64 ${PKG_APPARMOR} AS pkg-apparmor-amd64\nFROM --platform=arm64 ${PKG_APPARMOR} AS pkg-apparmor-arm64\n\nFROM --platform=amd64 ${PKG_CRYPTSETUP} AS pkg-cryptsetup-amd64\nFROM --platform=arm64 ${PKG_CRYPTSETUP} AS pkg-cryptsetup-arm64\n\nFROM --platform=amd64 ${PKG_CONTAINERD} AS pkg-containerd-amd64\nFROM --platform=arm64 ${PKG_CONTAINERD} AS pkg-containerd-arm64\n\nFROM --platform=amd64 ${PKG_DOSFSTOOLS} AS pkg-dosfstools-amd64\nFROM --platform=arm64 ${PKG_DOSFSTOOLS} AS pkg-dosfstools-arm64\n\nFROM --platform=amd64 ${PKG_E2FSPROGS} AS pkg-e2fsprogs-amd64\nFROM --platform=arm64 ${PKG_E2FSPROGS} AS pkg-e2fsprogs-arm64\n\nFROM --platform=amd64 ${PKG_SYSTEMD_UDEVD} AS pkg-systemd-udevd-amd64\nFROM --platform=arm64 ${PKG_SYSTEMD_UDEVD} AS pkg-systemd-udevd-arm64\n\nFROM --platform=amd64 ${PKG_LIBCAP} AS pkg-libcap-amd64\nFROM --platform=arm64 ${PKG_LIBCAP} AS pkg-libcap-arm64\n\nFROM ${PKG_GRUB} AS pkg-grub\nFROM --platform=amd64 ${PKG_GRUB} AS pkg-grub-amd64\nFROM --platform=arm64 ${PKG_GRUB} AS pkg-grub-arm64\n\nFROM ${PKG_SD_BOOT} AS pkg-sd-boot\nFROM --platform=amd64 ${PKG_SD_BOOT} AS pkg-sd-boot-amd64\nFROM --platform=arm64 ${PKG_SD_BOOT} AS pkg-sd-boot-arm64\n\nFROM --platform=amd64 ${PKG_IPTABLES} AS pkg-iptables-amd64\nFROM --platform=arm64 ${PKG_IPTABLES} AS pkg-iptables-arm64\n\nFROM --platform=amd64 ${PKG_IPXE} AS pkg-ipxe-amd64\nFROM --platform=arm64 ${PKG_IPXE} AS pkg-ipxe-arm64\n\nFROM --platform=amd64 ${PKG_LIBARCHIVE} AS pkg-libarchive-amd64\nFROM --platform=arm64 ${PKG_LIBARCHIVE} AS pkg-libarchive-arm64\n\nFROM --platform=amd64 ${PKG_LIBATTR} AS pkg-libattr-amd64\nFROM --platform=arm64 ${PKG_LIBATTR} AS pkg-libattr-arm64\n\nFROM --platform=amd64 ${PKG_LIBINIH} AS pkg-libinih-amd64\nFROM --platform=arm64 ${PKG_LIBINIH} AS pkg-libinih-arm64\n\nFROM --platform=amd64 ${PKG_LIBJANSSON} AS pkg-libjansson-amd64\nFROM --platform=arm64 ${PKG_LIBJANSSON} AS pkg-libjansson-arm64\n\nFROM --platform=amd64 ${PKG_LIBJSON_C} AS pkg-libjson-c-amd64\nFROM --platform=arm64 ${PKG_LIBJSON_C} AS pkg-libjson-c-arm64\n\nFROM --platform=amd64 ${PKG_LIBMNL} AS pkg-libmnl-amd64\nFROM --platform=arm64 ${PKG_LIBMNL} AS pkg-libmnl-arm64\n\nFROM --platform=amd64 ${PKG_LIBNFTNL} AS pkg-libnftnl-amd64\nFROM --platform=arm64 ${PKG_LIBNFTNL} AS pkg-libnftnl-arm64\n\nFROM --platform=amd64 ${PKG_LIBPOPT} AS pkg-libpopt-amd64\nFROM --platform=arm64 ${PKG_LIBPOPT} AS pkg-libpopt-arm64\n\nFROM --platform=amd64 ${PKG_LIBURCU} AS pkg-liburcu-amd64\nFROM --platform=arm64 ${PKG_LIBURCU} AS pkg-liburcu-arm64\n\nFROM --platform=amd64 ${PKG_LIBSEPOL} AS pkg-libsepol-amd64\nFROM --platform=arm64 ${PKG_LIBSEPOL} AS pkg-libsepol-arm64\n\nFROM --platform=amd64 ${PKG_LIBSELINUX} AS pkg-libselinux-amd64\nFROM --platform=arm64 ${PKG_LIBSELINUX} AS pkg-libselinux-arm64\n\nFROM --platform=amd64 ${PKG_PCRE2} AS pkg-pcre2-amd64\nFROM --platform=arm64 ${PKG_PCRE2} AS pkg-pcre2-arm64\n\nFROM --platform=amd64 ${PKG_OPENSSL} AS pkg-openssl-amd64\nFROM --platform=arm64 ${PKG_OPENSSL} AS pkg-openssl-arm64\n\n# linux-firmware is not arch-specific\nFROM --platform=amd64 ${PKG_LINUX_FIRMWARE} AS pkg-linux-firmware\n\nFROM --platform=amd64 ${PKG_LVM2} AS pkg-lvm2-amd64\nFROM --platform=arm64 ${PKG_LVM2} AS pkg-lvm2-arm64\n\nFROM --platform=amd64 ${PKG_LIBAIO} AS pkg-libaio-amd64\nFROM --platform=arm64 ${PKG_LIBAIO} AS pkg-libaio-arm64\n\nFROM --platform=amd64 ${PKG_NFTABLES} AS pkg-nftables-amd64\nFROM --platform=arm64 ${PKG_NFTABLES} AS pkg-nftables-arm64\n\nFROM --platform=amd64 ${PKG_MUSL} AS pkg-musl-amd64\nFROM --platform=arm64 ${PKG_MUSL} AS pkg-musl-arm64\n\nFROM --platform=amd64 ${PKG_RUNC} AS pkg-runc-amd64\nFROM --platform=arm64 ${PKG_RUNC} AS pkg-runc-arm64\n\nFROM --platform=amd64 ${PKG_XFSPROGS} AS pkg-xfsprogs-amd64\nFROM --platform=arm64 ${PKG_XFSPROGS} AS pkg-xfsprogs-arm64\n\nFROM ${PKG_UTIL_LINUX} AS pkg-util-linux\nFROM --platform=amd64 ${PKG_UTIL_LINUX} AS pkg-util-linux-amd64\nFROM --platform=arm64 ${PKG_UTIL_LINUX} AS pkg-util-linux-arm64\n\nFROM --platform=amd64 ${PKG_KMOD} AS pkg-kmod-amd64\nFROM --platform=arm64 ${PKG_KMOD} AS pkg-kmod-arm64\n\nFROM --platform=amd64 ${PKG_CNI} AS pkg-cni-amd64\nFROM --platform=arm64 ${PKG_CNI} AS pkg-cni-arm64\n\nFROM --platform=amd64 ${PKG_FLANNEL_CNI} AS pkg-flannel-cni-amd64\nFROM --platform=arm64 ${PKG_FLANNEL_CNI} AS pkg-flannel-cni-arm64\n\nFROM ${PKG_KERNEL} AS pkg-kernel\nFROM --platform=amd64 ${PKG_KERNEL} AS pkg-kernel-amd64\nFROM --platform=arm64 ${PKG_KERNEL} AS pkg-kernel-arm64\n\nFROM ${PKG_PIGZ} AS pkg-pigz\nFROM --platform=arm64 ${PKG_PIGZ} AS pkg-pigz-arm64\n\nFROM ${PKG_ZLIB} AS pkg-zlib\nFROM --platform=arm64 ${PKG_ZLIB} AS pkg-zlib-arm64\n\nFROM --platform=amd64 ${PKG_IGZIP} AS pkg-igzip-amd64\n\nFROM ${PKG_CPIO} AS pkg-cpio\nFROM ${PKG_DOSFSTOOLS} AS pkg-dosfstools\nFROM ${PKG_E2FSPROGS} AS pkg-e2fsprogs\nFROM ${PKG_GLIB} AS pkg-glib\nFROM ${PKG_KMOD} AS pkg-kmod\nFROM ${PKG_LIBARCHIVE} AS pkg-libarchive\nFROM ${PKG_LIBATTR} AS pkg-libattr\nFROM ${PKG_LIBBURN} AS pkg-libburn\nFROM ${PKG_LIBINIH} AS pkg-libinih\nFROM ${PKG_LIBISOBURN} AS pkg-libisoburn\nFROM ${PKG_LIBISOFS} AS pkg-libisofs\nFROM ${PKG_LIBLZMA} AS pkg-liblzma\nFROM ${PKG_LIBURCU} AS pkg-liburcu\nFROM ${PKG_MTOOLS} AS pkg-mtools\nFROM ${PKG_MUSL} AS pkg-musl\nFROM ${PKG_OPENSSL} AS pkg-openssl\nFROM ${PKG_OPEN_VMDK} AS pkg-open-vmdk\nFROM ${PKG_PCRE2} AS pkg-pcre2\nFROM ${PKG_QEMU_TOOLS} AS pkg-qemu-tools\nFROM ${PKG_SQUASHFS_TOOLS} AS pkg-squashfs-tools\nFROM ${PKG_TAR} AS pkg-tar\nFROM ${PKG_XFSPROGS} AS pkg-xfsprogs\nFROM ${PKG_XZ} AS pkg-xz\nFROM ${PKG_ZSTD} AS pkg-zstd\n\nFROM --platform=amd64 ${TOOLS_PREFIX}:${TOOLS} AS tools-amd64\nFROM --platform=arm64 ${TOOLS_PREFIX}:${TOOLS} AS tools-arm64\n\nFROM scratch AS pkg-debug-tools-scratch-amd64\nFROM scratch AS pkg-debug-tools-scratch-arm64\n\nFROM scratch AS pkg-debug-tools-bash-minimal-amd64\nCOPY --from=tools-amd64 /usr/bin/bash /bin/bash\nCOPY --from=tools-amd64 /usr/lib/ld-musl-x86_64.so.1 /lib/ld-musl-x86_64.so.1\nCOPY --from=tools-amd64 /usr/bin/cat /bin/cat\nCOPY --from=tools-amd64 /usr/bin/ls /bin/ls\nCOPY --from=tools-amd64 /usr/bin/tee /bin/tee\n\nFROM scratch AS pkg-debug-tools-bash-minimal-arm64\nCOPY --from=tools-arm64 /usr/bin/bash /bin/bash\nCOPY --from=tools-arm64 /usr/lib/ld-musl-aarch64.so.1 /lib/ld-musl-aarch64.so.1\nCOPY --from=tools-arm64 /usr/bin/cat /bin/cat\nCOPY --from=tools-arm64 /usr/bin/ls /bin/ls\nCOPY --from=tools-arm64 /usr/bin/tee /bin/tee\n\nFROM pkg-debug-tools-${DEBUG_TOOLS_SOURCE}-amd64 AS pkg-debug-tools-amd64\nFROM pkg-debug-tools-${DEBUG_TOOLS_SOURCE}-arm64 AS pkg-debug-tools-arm64\n\n# Strip CNI package.\n\nFROM scratch AS pkg-cni-stripped-amd64\nCOPY --from=pkg-cni-amd64 /opt/cni/bin/bridge /opt/cni/bin/bridge\nCOPY --from=pkg-cni-amd64 /opt/cni/bin/firewall /opt/cni/bin/firewall\nCOPY --from=pkg-cni-amd64 /opt/cni/bin/host-local /opt/cni/bin/host-local\nCOPY --from=pkg-cni-amd64 /opt/cni/bin/loopback /opt/cni/bin/loopback\nCOPY --from=pkg-cni-amd64 /opt/cni/bin/portmap /opt/cni/bin/portmap\nCOPY --from=pkg-cni-amd64 /usr/share/spdx/cni.spdx.json /usr/share/spdx/cni.spdx.json\n\nFROM scratch AS pkg-cni-stripped-arm64\nCOPY --from=pkg-cni-arm64 /opt/cni/bin/bridge /opt/cni/bin/bridge\nCOPY --from=pkg-cni-arm64 /opt/cni/bin/firewall /opt/cni/bin/firewall\nCOPY --from=pkg-cni-arm64 /opt/cni/bin/host-local /opt/cni/bin/host-local\nCOPY --from=pkg-cni-arm64 /opt/cni/bin/loopback /opt/cni/bin/loopback\nCOPY --from=pkg-cni-arm64 /opt/cni/bin/portmap /opt/cni/bin/portmap\nCOPY --from=pkg-cni-arm64 /usr/share/spdx/cni.spdx.json /usr/share/spdx/cni.spdx.json\n\nFROM ${PKG_TALOSCTL_CNI_BUNDLE} AS pkgs-talosctl-cni-bundle\n\n# The tools target provides base toolchain for the build.\n\nFROM --platform=${BUILDPLATFORM} ${TOOLS_PREFIX}:${TOOLS} AS tools\nENV GOTOOLCHAIN=local\nENV CGO_ENABLED=0\nSHELL [\"/bin/bash\", \"-c\"]\n\n# The build target creates a container that will be used to build Talos source\n# code.\n\nFROM --platform=${BUILDPLATFORM} tools AS build\nSHELL [\"/bin/bash\", \"-c\"]\nENV GO111MODULE=on\nENV GOPROXY=https://proxy.golang.org\nARG CGO_ENABLED\nENV CGO_ENABLED=${CGO_ENABLED}\nARG GOFIPS140\nENV GOFIPS140=${GOFIPS140}\nENV GOCACHE=/.cache/go-build\nENV GOMODCACHE=/.cache/mod\nARG SOURCE_DATE_EPOCH\nENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}\n# Go standard library is shipped with Talos, thus it must be tracked in SBOM\nCOPY --link --from=tools /usr/share/spdx/golang.spdx.json /rootfs/usr/share/spdx/golang.spdx.json\nWORKDIR /src\n\n# The build-go target creates a container to build Go code with Go modules downloaded and verified.\n\nFROM build AS build-go\nCOPY ./go.mod ./go.sum ./go.work ./\nCOPY ./pkg/machinery/go.mod ./pkg/machinery/go.sum ./pkg/machinery/\nCOPY ./hack/cloud-image-uploader/go.mod ./hack/cloud-image-uploader/go.sum ./hack/cloud-image-uploader/\nCOPY ./tools ./tools\nWORKDIR /src\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go mod download\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go mod verify\n\n# The generate target generates code from protobuf service definitions and machinery config.\n\nFROM build AS embed-generate\nARG NAME\nARG SHA\nARG USERNAME\nARG REGISTRY\nARG TAG\nARG ARTIFACTS\nARG PKGS\nARG TOOLS\nRUN mkdir -p pkg/machinery/gendata/data && \\\n    echo -n ${NAME} > pkg/machinery/gendata/data/name && \\\n    echo -n ${SHA} > pkg/machinery/gendata/data/sha && \\\n    echo -n ${USERNAME} > pkg/machinery/gendata/data/username && \\\n    echo -n ${REGISTRY} > pkg/machinery/gendata/data/registry && \\\n    echo -n ${PKGS} > pkg/machinery/gendata/data/pkgs && \\\n    echo -n ${TOOLS} > pkg/machinery/gendata/data/tools && \\\n    echo -n ${TAG} > pkg/machinery/gendata/data/tag && \\\n    echo -n ${ARTIFACTS} > pkg/machinery/gendata/data/artifacts\n\nFROM scratch AS embed\nCOPY --from=embed-generate /src/pkg/machinery/gendata/data /pkg/machinery/gendata/data\n\nFROM embed-generate AS embed-abbrev-generate\nARG ABBREV_TAG\nRUN echo -n \"undefined\" > pkg/machinery/gendata/data/sha && \\\n    echo -n ${ABBREV_TAG} > pkg/machinery/gendata/data/tag\nRUN mkdir -p _out && \\\n    echo PKGS=${PKGS} >> _out/talos-metadata && \\\n    echo TOOLS=${TOOLS} >> _out/talos-metadata && \\\n    echo TAG=${TAG} >> _out/talos-metadata\n\nFROM scratch AS embed-abbrev\nCOPY --from=embed-abbrev-generate /src/pkg/machinery/gendata/data /pkg/machinery/gendata/data\nCOPY --from=embed-abbrev-generate /src/_out/talos-metadata /_out/talos-metadata\n\nFROM ${EMBED_TARGET} AS embed-target\n\n# generate API descriptors\nFROM build-go AS api-descriptors-build\nWORKDIR /src/api\nCOPY api .\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf format\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf build --exclude-source-info -o lock.binpb\n\nFROM --platform=${BUILDPLATFORM} scratch AS api-descriptors\nCOPY --from=api-descriptors-build /src/api/lock.binpb /api/lock.binpb\n\n# format protobuf service definitions\nFROM build-go AS proto-format-build\nWORKDIR /src/api\nCOPY api .\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf format\n\nFROM --platform=${BUILDPLATFORM} scratch AS fmt-protobuf\nCOPY --from=proto-format-build /src/api/ /api/\n\n# run docgen for machinery config\nFROM build-go AS go-generate\nCOPY ./pkg ./pkg\nCOPY ./hack/boilerplate.txt ./hack/boilerplate.txt\nCOPY --from=embed-target / ./\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go generate ./pkg/...\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool golang.org/x/tools/cmd/goimports -w -local github.com/siderolabs/talos ./pkg/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool mvdan.cc/gofumpt -w ./pkg/\nWORKDIR /src/pkg/machinery\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go generate ./...\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/siderolabs/talos/tools/gotagsrewrite .\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool golang.org/x/tools/cmd/goimports -w -local github.com/siderolabs/talos ./\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool mvdan.cc/gofumpt -w ./\n\nFROM go-generate AS gen-proto-go\nWORKDIR /src/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/siderolabs/talos/tools/structprotogen github.com/siderolabs/talos/pkg/machinery/... /api/resource/definitions/\n\n# compile protobuf service definitions\nFROM build-go AS generate-build\nCOPY --from=proto-format-build /src/api /src/api/\nCOPY --from=gen-proto-go /api/resource/definitions/ /src/api/resource/definitions/\nWORKDIR /src/api\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf build\nRUN --mount=type=cache,target=/.cache,id=talos/.cache,sharing=locked go tool github.com/bufbuild/buf/cmd/buf generate\n# Goimports and gofumpt generated files to adjust import order\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool golang.org/x/tools/cmd/goimports -w -local github.com/siderolabs/talos /src/api/machinery/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool mvdan.cc/gofumpt -w /src/api/machinery/\n\nFROM scratch AS generate-build-clean\nCOPY --from=generate-build /src/api /api/\n\nFROM tools AS selinux\nCOPY ./internal/pkg/selinux/policy/* /selinux/\nRUN mkdir /policy; secilc -o /policy/policy.33 -f /policy/file_contexts -c 33 /selinux/**/*.cil -vvvvv -O\n\nFROM scratch AS selinux-generate\nCOPY --from=selinux /policy /policy\n\nFROM scratch AS ipxe-generate\nCOPY --from=pkg-ipxe-amd64 /usr/libexec/snp.efi /amd64/snp.efi\nCOPY --from=pkg-ipxe-arm64 /usr/libexec/snp.efi /arm64/snp.efi\n\nFROM scratch AS microsoft-secureboot-database\nARG MICROSOFT_SECUREBOOT_RELEASE\nADD https://github.com/microsoft/secureboot_objects.git#${MICROSOFT_SECUREBOOT_RELEASE}:PreSignedObjects /\n\nFROM scratch AS microsoft-key-keys\nCOPY --from=microsoft-secureboot-database /KEK/Certificates/*.der /kek/\n\nFROM scratch AS microsoft-db-keys\nCOPY --from=microsoft-secureboot-database /DB/Certificates/MicCor*.der /db/\nCOPY --from=microsoft-secureboot-database /DB/Certificates/microsoft*.der /db/\n\nFROM --platform=${BUILDPLATFORM} scratch AS generate\nCOPY --from=proto-format-build /src/api /api/\nCOPY --from=generate-build-clean /api/resource/definitions/ /api/resource/definitions/\nCOPY --from=generate-build-clean /api/machinery /pkg/machinery/\nCOPY --from=go-generate /src/pkg/imager/profile/ /pkg/imager/profile/\nCOPY --from=go-generate /src/pkg/machinery/resources/ /pkg/machinery/resources/\nCOPY --from=go-generate /src/pkg/machinery/config/schemas/ /pkg/machinery/config/schemas/\nCOPY --from=go-generate /src/pkg/machinery/config/types/ /pkg/machinery/config/types/\nCOPY --from=go-generate /src/pkg/machinery/imager/imageropts/ /pkg/machinery/imager/imageropts/\nCOPY --from=go-generate /src/pkg/machinery/nethelpers/ /pkg/machinery/nethelpers/\nCOPY --from=go-generate /src/pkg/machinery/extensions/ /pkg/machinery/extensions/\nCOPY --from=go-generate /src/pkg/machinery/version/os-release /pkg/machinery/version/os-release\nCOPY --from=ipxe-generate / /pkg/provision/providers/vm/internal/ipxe/data/ipxe/\nCOPY --from=selinux-generate / /internal/pkg/selinux/\nCOPY --from=embed-abbrev / /\nCOPY --from=pkg-ca-certificates /etc/ssl/certs/ca-certificates /internal/app/machined/pkg/controllers/secrets/data/\nCOPY --from=microsoft-key-keys / /internal/pkg/secureboot/database/certs/\nCOPY --from=microsoft-db-keys / /internal/pkg/secureboot/database/certs/\n\n# The base target provides a container that can be used to build all Talos\n# assets.\n\nFROM build-go AS base\nCOPY ./cmd ./cmd\nCOPY ./pkg ./pkg\nCOPY ./internal ./internal\nCOPY --from=embed / ./\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go list all >/dev/null\nWORKDIR /src/pkg/machinery\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go list all >/dev/null\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go generate -v ./version\nWORKDIR /src\n\n# The vulncheck target runs the vulnerability check tool.\n\nFROM base AS lint-vulncheck\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool golang.org/x/vuln/cmd/govulncheck ./...\n\n# The lint-deadcode target runs the deadcode elimination check.\nFROM base AS lint-deadcode\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nARG GO_MACHINED_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS} ${GO_MACHINED_LDFLAGS} -dumpdep\" ./internal/app/machined \\\n    |& go tool github.com/aarzilli/whydeadcode > deadcode.txt\nRUN if [[ -s deadcode.txt ]]; then \\\n    echo \"Dead code elimination problem found:\"; \\\n    cat deadcode.txt; \\\n    exit 1; \\\n    else \\\n    echo \"No dead code elimination issues found\"; \\\n    fi\n\n# The init target builds the init binary.\n\nFROM base AS init-build-amd64\nWORKDIR /src/internal/app/init\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=v1 go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS}\" -o /init\nRUN chmod +x /init\n\nFROM base AS init-build-arm64\nWORKDIR /src/internal/app/init\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=arm64 go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS}\" -o /init\nRUN chmod +x /init\n\nFROM init-build-${TARGETARCH} AS init-build\n\nFROM scratch AS init\nCOPY --from=init-build /init /init\n\n# The machined target builds the machined binary.\n\nFROM base AS machined-build-amd64\nWORKDIR /src/internal/app/machined\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nARG GO_MACHINED_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS} ${GO_MACHINED_LDFLAGS}\" -o /machined\nRUN chmod +x /machined\n\nFROM base AS machined-build-arm64\nWORKDIR /src/internal/app/machined\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nARG GO_MACHINED_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=arm64 go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS} ${GO_MACHINED_LDFLAGS}\" -o /machined\nRUN chmod +x /machined\n\nFROM machined-build-${TARGETARCH} AS machined-build\n\nFROM scratch AS machined\nCOPY --from=machined-build /machined /machined\n\n# The talosctl targets build the talosctl binaries.\n\nFROM base AS talosctl-linux-amd64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-linux-amd64\nRUN chmod +x /talosctl-linux-amd64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-linux-amd64\n\nFROM base AS talosctl-linux-arm64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=arm64 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-linux-arm64\nRUN chmod +x /talosctl-linux-arm64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-linux-arm64\n\nFROM base AS talosctl-linux-armv7-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=arm GOARM=7 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-linux-armv7\nRUN chmod +x /talosctl-linux-armv7\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-linux-armv7\n\nFROM base AS talosctl-linux-riscv64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=riscv64 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-linux-riscv64\nRUN chmod +x /talosctl-linux-riscv64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-linux-riscv64\n\nFROM base AS talosctl-darwin-amd64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=darwin GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-darwin-amd64\nRUN chmod +x /talosctl-darwin-amd64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-darwin-amd64\n\nFROM base AS talosctl-darwin-arm64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=darwin GOARCH=arm64 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-darwin-arm64\nRUN chmod +x /talosctl-darwin-arm64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" talosctl-darwin-arm64\n\nFROM base AS talosctl-windows-amd64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=windows GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-windows-amd64.exe\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-windows-amd64.exe\n\nFROM base AS talosctl-windows-arm64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=windows GOARCH=arm64 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-windows-arm64.exe\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-windows-arm64.exe\n\nFROM base AS talosctl-freebsd-amd64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=freebsd GOARCH=amd64 GOAMD64=${GOAMD64} go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-freebsd-amd64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-freebsd-amd64\n\nFROM base AS talosctl-freebsd-arm64-build\nWORKDIR /src/cmd/talosctl\nARG GO_BUILDFLAGS_TALOSCTL\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=freebsd GOARCH=arm64 go build ${GO_BUILDFLAGS_TALOSCTL} -ldflags \"${GO_LDFLAGS}\" -o /talosctl-freebsd-arm64\nRUN touch --date=\"@${SOURCE_DATE_EPOCH}\" /talosctl-freebsd-arm64\n\nFROM scratch AS talosctl-linux-amd64\nCOPY --from=talosctl-linux-amd64-build /talosctl-linux-amd64 /talosctl-linux-amd64\n\nFROM scratch AS talosctl-linux-arm64\nCOPY --from=talosctl-linux-arm64-build /talosctl-linux-arm64 /talosctl-linux-arm64\n\nFROM scratch AS talosctl-linux-armv7\nCOPY --from=talosctl-linux-armv7-build /talosctl-linux-armv7 /talosctl-linux-armv7\n\nFROM scratch AS talosctl-linux-riscv64\nCOPY --from=talosctl-linux-riscv64-build /talosctl-linux-riscv64 /talosctl-linux-riscv64\n\nFROM scratch AS talosctl-darwin-amd64\nCOPY --from=talosctl-darwin-amd64-build /talosctl-darwin-amd64 /talosctl-darwin-amd64\n\nFROM scratch AS talosctl-darwin-arm64\nCOPY --from=talosctl-darwin-arm64-build /talosctl-darwin-arm64 /talosctl-darwin-arm64\n\nFROM scratch AS talosctl-freebsd-amd64\nCOPY --from=talosctl-freebsd-amd64-build /talosctl-freebsd-amd64 /talosctl-freebsd-amd64\n\nFROM scratch AS talosctl-freebsd-arm64\nCOPY --from=talosctl-freebsd-arm64-build /talosctl-freebsd-arm64 /talosctl-freebsd-arm64\n\nFROM scratch AS talosctl-windows-amd64\nCOPY --from=talosctl-windows-amd64-build /talosctl-windows-amd64.exe /talosctl-windows-amd64.exe\n\nFROM scratch AS talosctl-windows-arm64\nCOPY --from=talosctl-windows-arm64-build /talosctl-windows-arm64.exe /talosctl-windows-arm64.exe\n\nFROM --platform=${BUILDPLATFORM} talosctl-${TARGETOS}-${TARGETARCH} AS talosctl-targetarch\n\nFROM scratch AS talosctl-all\nCOPY --from=talosctl-linux-amd64 / /\nCOPY --from=talosctl-linux-arm64 / /\nCOPY --from=talosctl-linux-armv7 / /\nCOPY --from=talosctl-linux-riscv64 / /\nCOPY --from=talosctl-darwin-amd64 / /\nCOPY --from=talosctl-darwin-arm64 / /\nCOPY --from=talosctl-freebsd-amd64 / /\nCOPY --from=talosctl-freebsd-arm64 / /\nCOPY --from=talosctl-windows-amd64 / /\nCOPY --from=talosctl-windows-arm64 / /\n\nFROM scratch AS talosctl\nARG TARGETARCH\nCOPY --from=talosctl-all /talosctl-linux-${TARGETARCH} /talosctl\nARG TAG\nENV VERSION=${TAG}\nLABEL \"alpha.talos.dev/version\"=\"${VERSION}\"\nLABEL org.opencontainers.image.source=https://github.com/siderolabs/talos\nENTRYPOINT [\"/talosctl\"]\n\n# The kernel target is the linux kernel.\nFROM scratch AS kernel\nARG TARGETARCH\nCOPY --from=pkg-kernel /boot/vmlinuz /vmlinuz-${TARGETARCH}\n\n# The sd-boot target is the systemd-boot asset.\nFROM scratch AS sd-boot\nARG TARGETARCH\nCOPY --from=pkg-sd-boot /*.efi /sd-boot-${TARGETARCH}.efi\n\n# The sd-stub target is the systemd-stub asset.\nFROM scratch AS sd-stub\nARG TARGETARCH\nCOPY --from=pkg-sd-boot /*.efi.stub /sd-stub-${TARGETARCH}.efi\n\nFROM tools AS depmod-amd64\nWORKDIR /staging\nCOPY hack/modules-amd64.txt .\nCOPY --from=pkg-kernel-amd64 /usr/lib/modules usr/lib/modules\nRUN <<EOF\nset -euo pipefail\n\nKERNEL_VERSION=$(ls usr/lib/modules)\n\nxargs -a modules-amd64.txt -I {} install -D usr/lib/modules/${KERNEL_VERSION}/{} /build/usr/lib/modules/${KERNEL_VERSION}/{}\n\ndepmod -b /build/usr ${KERNEL_VERSION}\nEOF\n\nFROM scratch AS modules-amd64\nCOPY --from=depmod-amd64 /build/usr/lib/modules /usr/lib/modules\n\nFROM tools AS depmod-arm64\nWORKDIR /staging\nCOPY hack/modules-arm64.txt .\nCOPY --from=pkg-kernel-arm64 /usr/lib/modules usr/lib/modules\nRUN <<EOF\nset -euo pipefail\n\nKERNEL_VERSION=$(ls usr/lib/modules)\n\nxargs -a modules-arm64.txt -I {} install -D usr/lib/modules/${KERNEL_VERSION}/{} /build/usr/lib/modules/${KERNEL_VERSION}/{}\n\ndepmod -b /build/usr ${KERNEL_VERSION}\nEOF\n\nFROM scratch AS modules-arm64\nCOPY --from=depmod-arm64 /build/usr/lib/modules /usr/lib/modules\n\n# The rootfs target provides the Talos rootfs.\nFROM build AS rootfs-base-amd64\nCOPY --link --from=pkg-fhs / /rootfs\nCOPY --link --from=pkg-apparmor-amd64 / /rootfs\nCOPY --link --from=pkg-cni-stripped-amd64 / /rootfs\nCOPY --link --from=pkg-flannel-cni-amd64 / /rootfs\nCOPY --link --from=pkg-cryptsetup-amd64 / /rootfs\nCOPY --link --exclude=usr/bin/ctr --from=pkg-containerd-amd64 / /rootfs\nCOPY --link --from=pkg-dosfstools-amd64 / /rootfs\nCOPY --link --from=pkg-e2fsprogs-amd64 / /rootfs\nCOPY --link --exclude=usr/share --from=pkg-systemd-udevd-amd64 / /rootfs\nCOPY --link --from=pkg-systemd-udevd-amd64 /usr/share/spdx/systemd.spdx.json /rootfs/usr/share/spdx/systemd.spdx.json\nCOPY --link --from=pkg-libcap-amd64 / /rootfs\nCOPY --link --exclude=usr/share --from=pkg-iptables-amd64 / /rootfs\nCOPY --link --from=pkg-iptables-amd64 /usr/share/spdx/iptables.spdx.json /rootfs/usr/share/spdx/iptables.spdx.json\nCOPY --link --from=pkg-libarchive-amd64 / /rootfs\nCOPY --link --from=pkg-libattr-amd64 / /rootfs\nCOPY --link --from=pkg-libinih-amd64 / /rootfs\nCOPY --link --exclude=usr/include --from=pkg-libjansson-amd64 / /rootfs\nCOPY --link --from=pkg-libjson-c-amd64 / /rootfs\nCOPY --link --from=pkg-libmnl-amd64 / /rootfs\nCOPY --link --from=pkg-libnftnl-amd64 / /rootfs\nCOPY --link --from=pkg-libpopt-amd64 / /rootfs\nCOPY --link --from=pkg-liburcu-amd64 / /rootfs\nCOPY --link --from=pkg-libsepol-amd64 / /rootfs\nCOPY --link --from=pkg-libselinux-amd64 / /rootfs\n# NOTE: amd64 ships igzip, but arm64 ships pigz (see https://github.com/siderolabs/extensions/discussions/931)\nCOPY --link --exclude=usr/lib/pkgconfig --exclude=usr/include --from=pkg-igzip-amd64 / /rootfs\nCOPY --link --from=pkg-pcre2-amd64 / /rootfs\nCOPY --link --from=pkg-openssl-amd64 / /rootfs\nCOPY --link --from=pkg-lvm2-amd64 / /rootfs\nCOPY --link --from=pkg-libaio-amd64 / /rootfs\nCOPY --link --from=pkg-musl-amd64 / /rootfs\nCOPY --link --from=pkg-nftables-amd64 / /rootfs\nCOPY --link --from=pkg-runc-amd64 / /rootfs\nCOPY --link --from=pkg-xfsprogs-amd64 / /rootfs\nCOPY --link --from=pkg-util-linux-amd64 /usr/lib/libblkid.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-amd64 /usr/lib/libuuid.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-amd64 /usr/lib/libmount.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-amd64 /usr/share/spdx/util-linux.spdx.json /rootfs/usr/share/spdx/util-linux.spdx.json\nCOPY --link --from=pkg-kmod-amd64 /usr/lib/libkmod.* /rootfs/usr/lib/\nCOPY --link --from=pkg-kmod-amd64 /usr/bin/kmod /rootfs/usr/bin/modprobe\nCOPY --link --from=pkg-kmod-amd64 usr/share/spdx/kmod.spdx.json /rootfs/usr/share/spdx/kmod.spdx.json\nCOPY --link --from=modules-amd64 /usr/lib/modules /rootfs/usr/lib/modules\nCOPY --link --from=machined-build-amd64 /machined /rootfs/usr/bin/init\n\n# this is a no-op as it copies from a scratch image when WITH_DEBUG_SHELL is not set\nCOPY --link --from=pkg-debug-tools-amd64 * /rootfs/\n\nRUN <<END\n    # the orderly_poweroff call by the kernel will call '/sbin/poweroff'\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/poweroff\n    chmod +x /rootfs/usr/bin/poweroff\n    # some extensions like qemu-guest agent will call '/sbin/shutdown'\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/shutdown\n    chmod +x /rootfs/usr/bin/shutdown\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/dashboard\n    chmod +x /rootfs/usr/bin/dashboard\nEND\n# NB: We run the cleanup step before creating extra directories, files, and\n# symlinks to avoid accidentally cleaning them up.\nCOPY ./hack/cleanup.sh /usr/bin/cleanup.sh\nRUN <<END\n    cleanup.sh /rootfs\n    mkdir -pv /rootfs/{boot/EFI,etc/{iscsi,nvme,cri/conf.d/hosts},usr/lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}\n    mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,etc/ssl/certs,usr/libexec/kubernetes,/usr/local/lib/kubelet/credentialproviders,etc/selinux/targeted/contexts/files}\n    mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib}\nEND\nCOPY --chmod=0644 hack/zoneinfo/Etc/UTC /rootfs/usr/share/zoneinfo/Etc/UTC\nCOPY --chmod=0644 hack/nfsmount.conf /rootfs/etc/nfsmount.conf\nCOPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/config.toml\nCOPY --chmod=0644 hack/cri-containerd.toml /rootfs/etc/cri/containerd.toml\nCOPY --chmod=0644 hack/cri-plugin.part /rootfs/etc/cri/conf.d/00-base.part\nCOPY --chmod=0644 hack/udevd/99-default.link /rootfs/usr/lib/systemd/network/\nCOPY --chmod=0644 hack/udevd/40-vm-hotadd.rules hack/udevd/90-selinux.rules /rootfs/usr/lib/udev/rules.d/\nCOPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf\nCOPY --chmod=0644 --from=base /src/pkg/machinery/version/os-release /rootfs/etc/os-release\nRUN <<END\n    ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime\n    touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates.crt,selinux/targeted/contexts/files/file_contexts,iscsi/initiatorname.iscsi,nvme/{hostid,hostnqn}}\n    ln -s ca-certificates.crt /rootfs/etc/ssl/certs/ca-certificates\n    ln -s /etc/ssl /rootfs/etc/pki\n    ln -s /etc/ssl /rootfs/usr/share/ca-certificates\n    ln -s /etc/ssl /rootfs/usr/local/share/ca-certificates\n    ln -s /etc/ssl /rootfs/etc/ca-certificates\n    ln -s /usr/local/bin/nvidia-smi /rootfs/usr/bin/nvidia-smi\n    ln -s ../usr/local/glibc/etc/ld.so.conf /rootfs/etc/ld.so.conf\n    ln -s ../usr/local/glibc/etc/ld.so.cache /rootfs/etc/ld.so.cache\nEND\n\nFROM build AS rootfs-base-arm64\nCOPY --link --from=pkg-fhs / /rootfs\nCOPY --link --from=pkg-apparmor-arm64 / /rootfs\nCOPY --link --from=pkg-cni-stripped-arm64 / /rootfs\nCOPY --link --from=pkg-flannel-cni-arm64 / /rootfs\nCOPY --link --from=pkg-cryptsetup-arm64 / /rootfs\nCOPY --link --exclude=usr/bin/ctr --from=pkg-containerd-arm64 / /rootfs\nCOPY --link --from=pkg-dosfstools-arm64 / /rootfs\nCOPY --link --from=pkg-e2fsprogs-arm64 / /rootfs\nCOPY --link --exclude=usr/share --from=pkg-systemd-udevd-arm64 / /rootfs\nCOPY --link --from=pkg-systemd-udevd-arm64 /usr/share/spdx/systemd.spdx.json /rootfs/usr/share/spdx/systemd.spdx.json\nCOPY --link --from=pkg-libcap-arm64 / /rootfs\nCOPY --link --exclude=usr/share --from=pkg-iptables-arm64 / /rootfs\nCOPY --link --from=pkg-iptables-arm64 /usr/share/spdx/iptables.spdx.json /rootfs/usr/share/spdx/iptables.spdx.json\nCOPY --link --from=pkg-libarchive-arm64 / /rootfs\nCOPY --link --from=pkg-libattr-arm64 / /rootfs\nCOPY --link --from=pkg-libinih-arm64 / /rootfs\nCOPY --link --exclude=usr/include --from=pkg-libjansson-arm64 / /rootfs\nCOPY --link --from=pkg-libjson-c-arm64 / /rootfs\nCOPY --link --from=pkg-libmnl-arm64 / /rootfs\nCOPY --link --from=pkg-libnftnl-arm64 / /rootfs\nCOPY --link --from=pkg-libpopt-arm64 / /rootfs\nCOPY --link --from=pkg-liburcu-arm64 / /rootfs\nCOPY --link --from=pkg-libsepol-arm64 / /rootfs\nCOPY --link --from=pkg-libselinux-arm64 / /rootfs\nCOPY --link --from=pkg-pcre2-arm64 / /rootfs\nCOPY --link --from=pkg-openssl-arm64 / /rootfs\nCOPY --link --from=pkg-lvm2-arm64 / /rootfs\nCOPY --link --from=pkg-libaio-arm64 / /rootfs\nCOPY --link --from=pkg-musl-arm64 / /rootfs\nCOPY --link --from=pkg-nftables-arm64 / /rootfs\nCOPY --link --from=pkg-runc-arm64 / /rootfs\nCOPY --link --from=pkg-xfsprogs-arm64 / /rootfs\n# NOTE: amd64 ships igzip, but arm64 ships pigz (see https://github.com/siderolabs/extensions/discussions/931)\nCOPY --link --from=pkg-zlib-arm64 / /rootfs\nCOPY --link --from=pkg-pigz-arm64 / /rootfs\nCOPY --link --from=pkg-util-linux-arm64 /usr/lib/libblkid.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-arm64 /usr/lib/libuuid.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-arm64 /usr/lib/libmount.* /rootfs/usr/lib/\nCOPY --link --from=pkg-util-linux-arm64 /usr/share/spdx/util-linux.spdx.json /rootfs/usr/share/spdx/util-linux.spdx.json\nCOPY --link --from=pkg-kmod-arm64 /usr/lib/libkmod.* /rootfs/usr/lib/\nCOPY --link --from=pkg-kmod-arm64 /usr/bin/kmod /rootfs/usr/bin/modprobe\nCOPY --link --from=pkg-kmod-arm64 /usr/share/spdx/kmod.spdx.json /rootfs/usr/share/spdx/kmod.spdx.json\nCOPY --link --from=modules-arm64 /usr/lib/modules /rootfs/usr/lib/modules\nCOPY --link --from=machined-build-arm64 /machined /rootfs/usr/bin/init\n\n# this is a no-op as it copies from a scratch image when WITH_DEBUG_SHELL is not set\nCOPY --link --from=pkg-debug-tools-arm64 * /rootfs/\n\nRUN <<END\n    # the orderly_poweroff call by the kernel will call '/sbin/poweroff'\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/poweroff\n    chmod +x /rootfs/usr/bin/poweroff\n    # some extensions like qemu-guest agent will call '/sbin/shutdown'\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/shutdown\n    chmod +x /rootfs/usr/bin/shutdown\n    ln /rootfs/usr/bin/init /rootfs/usr/bin/dashboard\n    chmod +x /rootfs/usr/bin/dashboard\nEND\n# NB: We run the cleanup step before creating extra directories, files, and\n# symlinks to avoid accidentally cleaning them up.\nCOPY ./hack/cleanup.sh /usr/bin/cleanup.sh\nRUN <<END\n    cleanup.sh /rootfs\n    mkdir -pv /rootfs/{boot/EFI,etc/{iscsi,nvme,cri/conf.d/hosts},usr/lib/firmware,usr/etc,usr/local/share,usr/share/zoneinfo/Etc,mnt,system,opt,.extra}\n    mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,etc/ssl/certs,usr/libexec/kubernetes,/usr/local/lib/kubelet/credentialproviders,etc/selinux/targeted/contexts/files}\n    mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib}\nEND\nCOPY --chmod=0644 hack/zoneinfo/Etc/UTC /rootfs/usr/share/zoneinfo/Etc/UTC\nCOPY --chmod=0644 hack/nfsmount.conf /rootfs/etc/nfsmount.conf\nCOPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/config.toml\nCOPY --chmod=0644 hack/cri-containerd.toml /rootfs/etc/cri/containerd.toml\nCOPY --chmod=0644 hack/cri-plugin.part /rootfs/etc/cri/conf.d/00-base.part\nCOPY --chmod=0644 hack/udevd/99-default.link /rootfs/usr/lib/systemd/network/\nCOPY --chmod=0644 hack/udevd/40-vm-hotadd.rules hack/udevd/90-selinux.rules /rootfs/usr/lib/udev/rules.d/\nCOPY --chmod=0644 hack/lvm.conf /rootfs/etc/lvm/lvm.conf\nCOPY --chmod=0644 --from=base /src/pkg/machinery/version/os-release /rootfs/etc/os-release\nRUN <<END\n    ln -s /usr/share/zoneinfo/Etc/UTC /rootfs/etc/localtime\n    touch /rootfs/etc/{extensions.yaml,resolv.conf,hosts,machine-id,cri/conf.d/cri.toml,cri/conf.d/01-registries.part,cri/conf.d/20-customization.part,cri/conf.d/base-spec.json,ssl/certs/ca-certificates.crt,selinux/targeted/contexts/files/file_contexts,iscsi/initiatorname.iscsi,nvme/{hostid,hostnqn}}\n    ln -s ca-certificates.crt /rootfs/etc/ssl/certs/ca-certificates\n    ln -s /etc/ssl /rootfs/etc/pki\n    ln -s /etc/ssl /rootfs/usr/share/ca-certificates\n    ln -s /etc/ssl /rootfs/usr/local/share/ca-certificates\n    ln -s /etc/ssl /rootfs/etc/ca-certificates\n    ln -s /usr/local/bin/nvidia-smi /rootfs/usr/bin/nvidia-smi\n    ln -s ../usr/local/glibc/etc/ld.so.conf /rootfs/etc/ld.so.conf\n    ln -s ../usr/local/glibc/etc/ld.so.cache /rootfs/etc/ld.so.cache\nEND\n\nFROM build-go AS build-sbom\nARG SOURCE_DATE_EPOCH\nENV SYFT_FORMAT_SPDX_JSON_CREATED_TIME=${SOURCE_DATE_EPOCH}\nARG NAME\nARG TAG\n\nCOPY ./hack/sbom.sh /usr/bin/sbom.sh\n\nRUN mkdir -p /tmp/sbom-src /rootfs/usr/share/spdx\nRUN cp go.mod go.sum /tmp/sbom-src/\n\nFROM build-sbom AS sbom-container-arm64-generate\nCOPY --from=rootfs-base-arm64 /rootfs/usr/share/spdx /tmp/sbom-src/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache sbom.sh /tmp/sbom-src/ talos-container-arm64.spdx.json\n\nFROM scratch AS sbom-container-arm64\nCOPY --from=sbom-container-arm64-generate /rootfs/usr/share/spdx/talos-container-arm64.spdx.json /\n\nFROM build-sbom AS sbom-container-amd64-generate\nCOPY --from=rootfs-base-amd64 /rootfs/usr/share/spdx /tmp/sbom-src/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache sbom.sh /tmp/sbom-src/ talos-container-amd64.spdx.json\n\nFROM scratch AS sbom-container-amd64\nCOPY --from=sbom-container-amd64-generate /rootfs/usr/share/spdx/talos-container-amd64.spdx.json /\n\nFROM build-sbom AS sbom-arm64-generate\nCOPY --from=rootfs-base-arm64 /rootfs/usr/share/spdx /tmp/sbom-src/\nCOPY --from=pkg-kernel-arm64 /usr/share/spdx/kernel.spdx.json /tmp/sbom-src/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache sbom.sh /tmp/sbom-src/ talos-arm64.spdx.json\n\nFROM scratch AS sbom-arm64\nCOPY --from=sbom-arm64-generate /rootfs/usr/share/spdx/talos-arm64.spdx.json /\n\nFROM build-sbom AS sbom-amd64-generate\nCOPY --from=rootfs-base-amd64 /rootfs/usr/share/spdx /tmp/sbom-src/\nCOPY --from=pkg-kernel-amd64 /usr/share/spdx/kernel.spdx.json /tmp/sbom-src/\nRUN --mount=type=cache,target=/.cache,id=talos/.cache sbom.sh /tmp/sbom-src/ talos-amd64.spdx.json\n\nFROM scratch AS sbom-amd64\nCOPY --from=sbom-amd64-generate /rootfs/usr/share/spdx/talos-amd64.spdx.json /\n\nFROM scratch AS sbom\nCOPY --from=sbom-container-arm64 / /\nCOPY --from=sbom-container-amd64 / /\nCOPY --from=sbom-arm64 / /\nCOPY --from=sbom-amd64 / /\n\nFROM sbom-container-${TARGETARCH} AS sbom-container-target\n\n# Use an unpinned latest version, because we want to use the latest advisories\nFROM ${GENERATE_VEX_PREFIX}:${GENERATE_VEX} AS talos-vex\n\nFROM build-go AS vex-generate\nARG TAG\nCOPY --from=talos-vex /generate-vex /generate-vex\nRUN /generate-vex gen --target-version $TAG > /talos.vex.json\n# This config contains IDs of the tracked, but affected vulnerabilities.\n# Once an advisory is made, the CI should go back to passing status.\nRUN /generate-vex grype-config --target-version $TAG > /talos.grype.yaml\n\nFROM scratch AS vex\nCOPY --from=vex-generate /talos.vex.json /talos.vex.json\nCOPY --from=vex-generate /talos.grype.yaml /talos.grype.yaml\n\nFROM build-go AS grype-scan\nCOPY --from=sbom-arm64 /talos-arm64.spdx.json /talos-arm64.spdx.json\nCOPY --from=vex /talos.vex.json /talos.vex.json\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool \\\n    github.com/anchore/grype/cmd/grype sbom:/talos-arm64.spdx.json \\\n    --vex /talos.vex.json -vv 2>&1 | tee /grype-scan.log\n\nFROM scratch AS grype-scan-result\nCOPY --from=grype-scan /grype-scan.log /grype-scan.log\n\nFROM build-go AS grype-validate\nCOPY --from=sbom-arm64 /talos-arm64.spdx.json /talos-arm64.spdx.json\nCOPY --from=vex /talos.vex.json /talos.vex.json\nCOPY --from=vex /talos.grype.yaml /talos.grype.yaml\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool \\\n    github.com/anchore/grype/cmd/grype sbom:/talos-arm64.spdx.json \\\n    --vex /talos.vex.json -vv --fail-on negligible --config /talos.grype.yaml\n\nFROM rootfs-base-${TARGETARCH} AS rootfs-base\nRUN rm -rf /rootfs/usr/share/spdx/*\nCOPY --from=sbom-container-target / /rootfs/usr/share/spdx/\nRUN echo \"true\" > /rootfs/usr/etc/in-container\nRUN rm -rf /rootfs/usr/lib/modules/*\nRUN find /rootfs -print0 \\\n    | xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\n\nFROM rootfs-base-arm64 AS rootfs-squashfs-arm64\nRUN rm -rf /rootfs/usr/share/spdx/*\nCOPY --from=sbom-arm64 / /rootfs/usr/share/spdx/\nARG ZSTD_COMPRESSION_LEVEL\nCOPY --from=selinux-generate /policy/file_contexts /file_contexts\nCOPY ./hack/labeled-squashfs.sh /\nRUN fakeroot /labeled-squashfs.sh /rootfs /rootfs.sqsh /file_contexts ${ZSTD_COMPRESSION_LEVEL}\n\nFROM rootfs-base-amd64 AS rootfs-squashfs-amd64\nRUN rm -rf /rootfs/usr/share/spdx/*\nCOPY --from=sbom-amd64 / /rootfs/usr/share/spdx/\nARG ZSTD_COMPRESSION_LEVEL\nCOPY --from=selinux-generate /policy/file_contexts /file_contexts\nCOPY ./hack/labeled-squashfs.sh /\nRUN fakeroot /labeled-squashfs.sh /rootfs /rootfs.sqsh /file_contexts ${ZSTD_COMPRESSION_LEVEL}\n\nFROM scratch AS squashfs-arm64\nCOPY --from=rootfs-squashfs-arm64 /rootfs.sqsh /\n\nFROM scratch AS squashfs-amd64\nCOPY --from=rootfs-squashfs-amd64 /rootfs.sqsh /\n\nFROM scratch AS rootfs\nCOPY --from=rootfs-base /rootfs /\n\n# The initramfs target provides the Talos initramfs image.\n\nFROM build AS initramfs-archive-arm64\nWORKDIR /initramfs\nARG ZSTD_COMPRESSION_LEVEL\nCOPY --from=squashfs-arm64 /rootfs.sqsh .\nCOPY --from=init-build-arm64 /init .\nRUN find . -print0 \\\n    | xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\nRUN set -o pipefail \\\n    && find . 2>/dev/null \\\n    | LC_ALL=c sort \\\n    | cpio --reproducible -H newc -o \\\n    | zstd -c -T0 -${ZSTD_COMPRESSION_LEVEL} \\\n    > /initramfs.xz\n\nFROM build AS initramfs-archive-amd64\nWORKDIR /initramfs\nARG ZSTD_COMPRESSION_LEVEL\nCOPY --from=squashfs-amd64 /rootfs.sqsh .\nCOPY --from=init-build-amd64 /init .\nRUN find . -print0 \\\n    | xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\nRUN set -o pipefail \\\n    && find . 2>/dev/null \\\n    | LC_ALL=c sort \\\n    | cpio --reproducible -H newc -o \\\n    | zstd -c -T0 -${ZSTD_COMPRESSION_LEVEL} \\\n    > /initramfs.xz\n\nFROM initramfs-archive-${TARGETARCH} AS initramfs-archive\n\nFROM scratch AS initramfs\nARG TARGETARCH\nCOPY --from=initramfs-archive /initramfs.xz /initramfs-${TARGETARCH}.xz\n\n# The talos target generates a docker image that can be used to run Talos\n# in containers.\n\nFROM scratch AS talos\nCOPY --from=rootfs / /\nLABEL org.opencontainers.image.source=https://github.com/siderolabs/talos\nENTRYPOINT [\"/sbin/init\"]\n\n# The installer target generates an image that can be used to install Talos to\n# various environments.\n\n# Make the installer binary.\nFROM base AS installer-build\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nWORKDIR /src/cmd/installer\nARG TARGETARCH\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=${TARGETARCH} go build ${GO_BUILDFLAGS} -ldflags \"${GO_LDFLAGS}\" -o /installer\nRUN chmod +x /installer\n\n# Make the images containing the boot artifacts.\nFROM scratch AS install-artifacts-amd64\nCOPY --from=pkg-kernel-amd64 /boot/vmlinuz /usr/install/amd64/vmlinuz\nCOPY --from=initramfs-archive-amd64 /initramfs.xz /usr/install/amd64/initramfs.xz\nCOPY --from=pkg-sd-boot-amd64 /linuxx64.efi.stub /usr/install/amd64/systemd-stub.efi\nCOPY --from=pkg-sd-boot-amd64 /systemd-bootx64.efi /usr/install/amd64/systemd-boot.efi\nCOPY --from=sbom-amd64 /talos-amd64.spdx.json /usr/install/amd64/talos.spdx.json\n\nFROM scratch AS install-artifacts-arm64\nCOPY --from=pkg-kernel-arm64 /boot/vmlinuz /usr/install/arm64/vmlinuz\nCOPY --from=initramfs-archive-arm64 /initramfs.xz /usr/install/arm64/initramfs.xz\nCOPY --from=pkg-sd-boot-arm64 /linuxaa64.efi.stub /usr/install/arm64/systemd-stub.efi\nCOPY --from=pkg-sd-boot-arm64 /systemd-bootaa64.efi /usr/install/arm64/systemd-boot.efi\nCOPY --from=sbom-arm64 /talos-arm64.spdx.json /usr/install/arm64/talos.spdx.json\n\nFROM scratch AS install-artifacts-all\nCOPY --from=install-artifacts-amd64 / /\nCOPY --from=install-artifacts-arm64 / /\n\nFROM install-artifacts-${TARGETARCH} AS install-artifacts-targetarch\n\nFROM install-artifacts-${INSTALLER_ARCH} AS install-artifacts\n\n# Add the installer with a symlink as 'imager' and a /rootfs dir containing only the installer.\nFROM tools AS installer-image-gen\nCOPY --from=installer-build /installer /rootfs/usr/bin/installer\nRUN ln -s installer /rootfs/usr/bin/imager\n\n# Add the installer binary and the tools needed to run the installer.\nFROM scratch AS installer-base-image\nARG TARGETARCH\nENV TARGETARCH=${TARGETARCH}\nCOPY --link --from=pkg-fhs / /\nCOPY --link --from=pkg-ca-certificates / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la --exclude=usr/include --from=pkg-musl / /\nCOPY --link --from=pkg-dosfstools / /\nCOPY --link --exclude=etc/bash_completion.d --from=pkg-grub / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libattr / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libinih / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-liblzma / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-liburcu / /\nCOPY --link --from=pkg-mtools / /\nCOPY --link --from=pkg-xfsprogs / /\n# Only copy the installer binary and none of the tools used for building it.\nCOPY --link --from=installer-image-gen /rootfs /\n\n# Squash the installer-base-image layers to reduce size.\nFROM scratch AS installer-base-image-squashed\nCOPY --from=installer-base-image / /\n\n# Add metadata.\n# 'installer-base' only contains the installer binary and the tools it uses.\n# 'installer-base' does not contain boot assets or talos itself.\nFROM installer-base-image-squashed AS installer-base\nARG TAG\nENV VERSION=${TAG}\nLABEL \"alpha.talos.dev/version\"=\"${VERSION}\"\nLABEL org.opencontainers.image.source=https://github.com/siderolabs/talos\nENTRYPOINT [\"/bin/installer\"]\n\n# Imager can be thought of as an extended installer.\n# It has the boot artifacts and tools to build any requested talos image with desired modifications and system extensions.\n# Imager is meant to be run outside of talos and the talos installation flow.\nFROM installer-base-image-squashed AS imager-image\nCOPY --link --from=pkg-cpio / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/lib/pkgconfig --from=pkg-e2fsprogs / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-glib / /\nCOPY --link --from=pkg-grub-amd64 /usr/lib/grub /usr/lib/grub\nCOPY --link --from=pkg-grub-arm64 /usr/lib/grub /usr/lib/grub\nCOPY --link --exclude=usr/include --exclude=usr/lib/pkgconfig --exclude=usr/share/pkgconfig --exclude=usr/share/bash-completion --from=pkg-kmod / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libarchive / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libburn / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libisoburn / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-libisofs / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --exclude=usr/lib/cmake --from=pkg-openssl / /\nCOPY --link --from=pkg-open-vmdk / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-pcre2 / /\nCOPY --link --from=pkg-pigz / /\nCOPY --link --from=pkg-qemu-tools / /\nCOPY --link --from=pkg-squashfs-tools / /\nCOPY --link --from=pkg-tar / /\nCOPY --link --exclude=**/*.a --exclude=*.a --from=pkg-util-linux /usr/lib/libblkid.* /usr/lib/\nCOPY --link --exclude=**/*.a --exclude=*.a --from=pkg-util-linux /usr/lib/libuuid.* /usr/lib/\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-xz / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-zlib / /\nCOPY --link --exclude=**/*.a --exclude=**/*.la  --exclude=usr/include --exclude=usr/lib/pkgconfig --from=pkg-zstd / /\nCOPY --chmod=0644 hack/extra-modules.conf /etc/modules.d/10-extra-modules.conf\nCOPY --from=install-artifacts / /\n\nFROM scratch AS imager-image-squashed\nCOPY --from=imager-image / /\n\nFROM imager-image-squashed AS imager\nARG TAG\nENV VERSION=${TAG}\nLABEL \"alpha.talos.dev/version\"=\"${VERSION}\"\nLABEL org.opencontainers.image.source=https://github.com/siderolabs/talos\nENTRYPOINT [\"/bin/imager\"]\n\nFROM imager AS iso-amd64-build\nARG SOURCE_DATE_EPOCH\nENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}\nRUN /bin/installer \\\n    iso \\\n    --arch amd64 \\\n    --output /out\n\nFROM imager AS iso-arm64-build\nARG SOURCE_DATE_EPOCH\nENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}\nRUN /bin/installer \\\n    iso \\\n    --arch arm64 \\\n    --output /out\n\nFROM scratch AS iso-amd64\nCOPY --from=iso-amd64-build /out /\n\nFROM scratch AS iso-arm64\nCOPY --from=iso-arm64-build /out /\n\nFROM --platform=${BUILDPLATFORM} iso-${TARGETARCH} AS iso\n\n# The test target performs tests on the source code.\nFROM base AS unit-tests-runner\nCOPY --from=rootfs / /\nCOPY --from=pkg-ca-certificates / /\nARG TESTPKGS\nENV PLATFORM=container\nARG GO_LDFLAGS\nRUN --security=insecure --mount=type=cache,id=testspace,target=/tmp --mount=type=cache,target=/.cache,id=talos/.cache go test \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -covermode=atomic -coverprofile=coverage.txt -coverpkg=${TESTPKGS} -p 4 ${TESTPKGS}\nFROM scratch AS unit-tests\nCOPY --from=unit-tests-runner /src/coverage.txt /coverage.txt\n\n# The unit-tests-race target performs tests with race detector.\n\nFROM base AS unit-tests-race\nCOPY --from=rootfs / /\nCOPY --from=pkg-ca-certificates / /\nARG TESTPKGS\nENV PLATFORM=container\nENV CGO_ENABLED=1\nARG GO_LDFLAGS\nRUN --security=insecure --mount=type=cache,id=testspace,target=/tmp --mount=type=cache,target=/.cache,id=talos/.cache go test \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -race -p 4 ${TESTPKGS}\n\n# The unit-tests-fips target performs tests with FIPS strict mode.\nFROM base AS unit-tests-fips\nCOPY --from=rootfs / /\nCOPY --from=pkg-ca-certificates / /\nARG TESTPKGS\nENV PLATFORM=container\nENV GOFIPS140=latest\nENV GODEBUG=fips140=only,tlsmlkem=0\nARG GO_LDFLAGS\nRUN --security=insecure --mount=type=cache,id=testspace,target=/tmp --mount=type=cache,target=/.cache,id=talos/.cache go test \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -p 4 ${TESTPKGS}\n\n# The integration-test targets builds integration test binary.\n\nFROM base AS integration-test-linux-amd64-build\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=${GOAMD64} go test -v -c ${GO_BUILDFLAGS} \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -tags integration,integration_api,integration_cli,integration_k8s \\\n    ./internal/integration\n\nFROM scratch AS integration-test-linux-amd64\nCOPY --from=integration-test-linux-amd64-build /src/integration.test /integration-test-linux-amd64\n\nFROM base AS integration-test-linux-arm64-build\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=arm64 go test -v -c ${GO_BUILDFLAGS} \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -tags integration,integration_api,integration_cli,integration_k8s \\\n    ./internal/integration\n\nFROM scratch AS integration-test-linux-arm64\nCOPY --from=integration-test-linux-arm64-build /src/integration.test /integration-test-linux-arm64\n\nFROM base AS integration-test-darwin-arm64-build\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=darwin GOARCH=arm64 go test -v -c ${GO_BUILDFLAGS} \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -tags integration,integration_api,integration_cli,integration_k8s \\\n    ./internal/integration\n\nFROM scratch AS integration-test-darwin-arm64\nCOPY --from=integration-test-darwin-arm64-build /src/integration.test /integration-test-darwin-arm64\n\nFROM --platform=${BUILDPLATFORM} integration-test-${TARGETOS}-${TARGETARCH} AS integration-test-targetarch\n\n# The integration-test-provision target builds integration test binary with provisioning tests.\n\nFROM base AS integration-test-provision-linux-build\nARG GO_BUILDFLAGS\nARG GO_LDFLAGS\nARG GOAMD64\nRUN --mount=type=cache,target=/.cache,id=talos/.cache GOOS=linux GOARCH=amd64 GOAMD64=${GOAMD64} go test -v -c ${GO_BUILDFLAGS} \\\n    -ldflags \"${GO_LDFLAGS}\" \\\n    -tags integration,integration_provision \\\n    ./internal/integration\n\nFROM scratch AS integration-test-provision-linux\nCOPY --from=integration-test-provision-linux-build /src/integration.test /integration-test-provision-linux-amd64\n\n# The lint target performs linting on the source code.\nFROM base AS lint-go\nCOPY .golangci.yml .\nENV GOGC=50\nENV GOLANGCI_LINT_CACHE=/.cache/lint\nRUN --mount=type=cache,target=/.cache,id=talos/.cache,sharing=locked go tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint config verify --config .golangci.yml\nRUN --mount=type=cache,target=/.cache,id=talos/.cache,sharing=locked go tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint run --config .golangci.yml\nWORKDIR /src/pkg/machinery\nRUN --mount=type=cache,target=/.cache,id=talos/.cache,sharing=locked go tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint run --config ../../.golangci.yml\nCOPY ./hack/cloud-image-uploader /src/hack/cloud-image-uploader\nWORKDIR /src/hack/cloud-image-uploader\nRUN --mount=type=cache,target=/.cache,id=talos/.cache,sharing=locked go tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint run --config ../../.golangci.yml\nWORKDIR /src\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/siderolabs/importvet/cmd/importvet github.com/siderolabs/talos/...\n\n# The protolint target performs linting on protobuf files.\n\nFROM base AS lint-protobuf\nWORKDIR /src/api\nCOPY api .\nCOPY --from=api-descriptors /api/lock.binpb ./current.lock.binpb\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf lint\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go tool github.com/bufbuild/buf/cmd/buf breaking current.lock.binpb --against lock.binpb\n\n# The markdownlint target performs linting on Markdown files.\n\nFROM oven/bun:1-alpine AS lint-markdown\nARG MARKDOWNLINTCLI_VERSION\nRUN apk add --no-cache findutils\nRUN bun i -g markdownlint-cli@${MARKDOWNLINTCLI_VERSION}\nWORKDIR /src\nCOPY . .\nRUN bun run --bun markdownlint \\\n    --ignore '**/LICENCE.md' \\\n    --ignore '**/CHANGELOG.md' \\\n    --ignore '**/CODE_OF_CONDUCT.md' \\\n    --ignore '**/node_modules/**' \\\n    --ignore '**/hack/chglog/**' \\\n    --ignore 'website/content/*/reference/*' \\\n    --ignore 'website/themes/**' \\\n    --disable MD045 MD056 -- \\\n    .\n\n# The docs target generates documentation.\n\nFROM base AS docs-build\nARG TARGETOS\nARG TARGETARCH\nWORKDIR /src\nCOPY --from=talosctl-targetarch /talosctl-${TARGETOS}-${TARGETARCH} /bin/talosctl\nRUN env HOME=/home/user TAG=latest /bin/talosctl docs --config /tmp/configuration \\\n    && env HOME=/home/user TAG=latest /bin/talosctl docs --cli /tmp\nCOPY ./pkg/machinery/config/schemas/*.schema.json /tmp/schemas/\n\nFROM scratch AS proto-docs-build\nCOPY --from=generate-build-clean /api/docs/api.md /api.md\n\nFROM scratch AS docs\nCOPY --from=docs-build /tmp/configuration/ /website/content/v1.13/reference/configuration/\nCOPY --from=docs-build /tmp/cli.md /website/content/v1.13/reference/\nCOPY --from=docs-build /tmp/schemas /website/content/v1.13/schemas/\nCOPY --from=proto-docs-build /api.md /website/content/v1.13/reference/\n\n# The talosctl-cni-bundle builds the CNI bundle for talosctl.\n\nFROM scratch AS talosctl-cni-bundle\nARG TARGETARCH\nCOPY --from=pkgs-talosctl-cni-bundle /opt/cni/bin/ /talosctl-cni-bundle-${TARGETARCH}/\n\n# The go-mod-outdated target lists all outdated modules.\n\nFROM base AS go-mod-outdated\nRUN --mount=type=cache,target=/.cache,id=talos/.cache go install github.com/psampaz/go-mod-outdated@latest \\\n    && mv /root/go/bin/go-mod-outdated /usr/bin/go-mod-outdated\nCOPY ./hack/cloud-image-uploader ./hack/cloud-image-uploader\n# fail always to get the output back\nRUN --mount=type=cache,target=/.cache,id=talos/.cache <<EOF\n    for project in pkg/machinery . hack/cloud-image-uploader; do\n        echo -e \"\\n>>>> ${project}:\" && \\\n        (cd \"${project}\" && go list -u -m -json all | go-mod-outdated -update -direct)\n    done\n\n    exit 1\nEOF\n"
  },
  {
    "path": "LICENSE",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "Makefile",
    "content": "REGISTRY ?= ghcr.io\nUSERNAME ?= siderolabs\nSHA ?= $(shell git describe --match=none --always --abbrev=8 --dirty)\nTAG ?= $(shell git describe --tag --always --dirty --match v[0-9]\\*)\nABBREV_TAG ?= $(shell git describe --tag --always --match v[0-9]\\* --abbrev=0 )\nTAG_SUFFIX ?=\nTAG_SUFFIX_IN ?= $(TAG_SUFFIX)\nTAG_SUFFIX_OUT ?= $(TAG_SUFFIX)\nSOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct)\nIMAGE_REGISTRY ?= $(REGISTRY)\nIMAGE_TAG_IN ?= $(TAG)$(TAG_SUFFIX_IN)\nIMAGE_TAG_OUT ?= $(TAG)$(TAG_SUFFIX_OUT)\nBRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)\nREGISTRY_AND_USERNAME := $(IMAGE_REGISTRY)/$(USERNAME)\nNAME = Talos\n\nCLOUD_IMAGES_EXTRA_ARGS ?= \"\"\nZSTD_COMPRESSION_LEVEL ?= 18\n\nCI_RELEASE_TAG := $(shell git log --oneline --format=%B -n 1 HEAD^2 -- 2>/dev/null | head -n 1 | sed -r \"/^release\\(.*\\)/ s/^release\\((.*)\\):.*$$/\\\\1/; t; Q\")\n\nARTIFACTS := _out\n\nDEBUG_TOOLS_SOURCE := scratch\nEMBED_TARGET ?= embed\n\nTOOLS_PREFIX ?= ghcr.io/siderolabs/tools\nTOOLS ?= v1.13.0-beta.0\nPKGS_PREFIX ?= ghcr.io/siderolabs\nPKGS ?= v1.13.0-beta.0\nGENERATE_VEX_PREFIX ?= ghcr.io/siderolabs/generate-vex\nGENERATE_VEX ?= latest\n\nKRES_IMAGE ?= ghcr.io/siderolabs/kres:latest\nCONFORMANCE_IMAGE ?= ghcr.io/siderolabs/conform:latest\nIMAGE_SIGNER_RELEASE ?= v0.2.0\n\nPKG_APPARMOR ?= $(PKGS_PREFIX)/apparmor:$(PKGS)\nPKG_CA_CERTIFICATES ?= $(PKGS_PREFIX)/ca-certificates:$(PKGS)\nPKG_CNI ?= $(PKGS_PREFIX)/cni:$(PKGS)\nPKG_CONTAINERD ?= $(PKGS_PREFIX)/containerd:$(PKGS)\nPKG_CPIO ?= $(PKGS_PREFIX)/cpio:$(PKGS)\nPKG_CRYPTSETUP ?= $(PKGS_PREFIX)/cryptsetup:$(PKGS)\nPKG_DOSFSTOOLS ?= $(PKGS_PREFIX)/dosfstools:$(PKGS)\nPKG_E2FSPROGS ?= $(PKGS_PREFIX)/e2fsprogs:$(PKGS)\nPKG_FHS ?= $(PKGS_PREFIX)/fhs:$(PKGS)\nPKG_FLANNEL_CNI ?= $(PKGS_PREFIX)/flannel-cni:$(PKGS)\nPKG_GLIB ?= $(PKGS_PREFIX)/glib:$(PKGS)\nPKG_GRUB ?= $(PKGS_PREFIX)/grub:$(PKGS)\nPKG_IGZIP ?= $(PKGS_PREFIX)/igzip:$(PKGS)\nPKG_IPTABLES ?= $(PKGS_PREFIX)/iptables:$(PKGS)\nPKG_IPXE ?= $(PKGS_PREFIX)/ipxe:$(PKGS)\nPKG_KERNEL ?= $(PKGS_PREFIX)/kernel:$(PKGS)\nPKG_KMOD ?= $(PKGS_PREFIX)/kmod:$(PKGS)\nPKG_LIBAIO ?= $(PKGS_PREFIX)/libaio:$(PKGS)\nPKG_LIBARCHIVE ?= $(PKGS_PREFIX)/libarchive:$(PKGS)\nPKG_LIBATTR ?= $(PKGS_PREFIX)/libattr:$(PKGS)\nPKG_LIBBURN ?= $(PKGS_PREFIX)/libburn:$(PKGS)\nPKG_LIBCAP ?= $(PKGS_PREFIX)/libcap:$(PKGS)\nPKG_LIBINIH ?= $(PKGS_PREFIX)/libinih:$(PKGS)\nPKG_LIBISOBURN ?= $(PKGS_PREFIX)/libisoburn:$(PKGS)\nPKG_LIBISOFS ?= $(PKGS_PREFIX)/libisofs:$(PKGS)\nPKG_LIBJANSSON ?= $(PKGS_PREFIX)/libjansson:$(PKGS)\nPKG_LIBJSON_C ?= $(PKGS_PREFIX)/libjson-c:$(PKGS)\nPKG_LIBLZMA ?= $(PKGS_PREFIX)/liblzma:$(PKGS)\nPKG_LIBMNL ?= $(PKGS_PREFIX)/libmnl:$(PKGS)\nPKG_LIBNFTNL ?= $(PKGS_PREFIX)/libnftnl:$(PKGS)\nPKG_LIBPOPT ?= $(PKGS_PREFIX)/libpopt:$(PKGS)\nPKG_LIBSELINUX ?= $(PKGS_PREFIX)/libselinux:$(PKGS)\nPKG_LIBSEPOL ?= $(PKGS_PREFIX)/libsepol:$(PKGS)\nPKG_LIBURCU ?= $(PKGS_PREFIX)/liburcu:$(PKGS)\nPKG_LINUX_FIRMWARE ?= $(PKGS_PREFIX)/linux-firmware:$(PKGS)\nPKG_LVM2 ?= $(PKGS_PREFIX)/lvm2:$(PKGS)\nPKG_MTOOLS ?= $(PKGS_PREFIX)/mtools:$(PKGS)\nPKG_MUSL ?= $(PKGS_PREFIX)/musl:$(PKGS)\nPKG_NFTABLES ?= $(PKGS_PREFIX)/nftables:$(PKGS)\nPKG_OPENSSL ?= $(PKGS_PREFIX)/openssl:$(PKGS)\nPKG_OPEN_VMDK ?= $(PKGS_PREFIX)/open-vmdk:$(PKGS)\nPKG_PCRE2 ?= $(PKGS_PREFIX)/pcre2:$(PKGS)\nPKG_PIGZ ?= $(PKGS_PREFIX)/pigz:$(PKGS)\nPKG_QEMU_TOOLS ?= $(PKGS_PREFIX)/qemu-tools:$(PKGS)\nPKG_RUNC ?= $(PKGS_PREFIX)/runc:$(PKGS)\nPKG_SD_BOOT ?= $(PKGS_PREFIX)/sd-boot:$(PKGS)\nPKG_SQUASHFS_TOOLS ?= $(PKGS_PREFIX)/squashfs-tools:$(PKGS)\nPKG_SYSTEMD_UDEVD ?= $(PKGS_PREFIX)/systemd-udevd:$(PKGS)\nPKG_TALOSCTL_CNI_BUNDLE ?= $(PKGS_PREFIX)/talosctl-cni-bundle:$(PKGS)\nPKG_TAR ?= $(PKGS_PREFIX)/tar:$(PKGS)\nPKG_UTIL_LINUX ?= $(PKGS_PREFIX)/util-linux:$(PKGS)\nPKG_XFSPROGS ?= $(PKGS_PREFIX)/xfsprogs:$(PKGS)\nPKG_XZ ?= $(PKGS_PREFIX)/xz:$(PKGS)\nPKG_ZLIB ?= $(PKGS_PREFIX)/zlib:$(PKGS)\nPKG_ZSTD ?= $(PKGS_PREFIX)/zstd:$(PKGS)\n\n# renovate: datasource=github-tags depName=golang/go\nGO_VERSION ?= 1.26\n# renovate: datasource=npm depName=markdownlint-cli\nMARKDOWNLINTCLI_VERSION ?= 0.48.0\nOPERATING_SYSTEM := $(shell uname -s | tr \"[:upper:]\" \"[:lower:]\")\nARCH := $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')\nTALOSCTL_DEFAULT_TARGET := talosctl-$(OPERATING_SYSTEM)\nTALOSCTL_EXECUTABLE := $(PWD)/$(ARTIFACTS)/$(TALOSCTL_DEFAULT_TARGET)-$(ARCH)\nINTEGRATION_TEST := integration-test\nINTEGRATION_TEST_DEFAULT_TARGET := $(INTEGRATION_TEST)-$(OPERATING_SYSTEM)\nINTEGRATION_TEST_PROVISION_DEFAULT_TARGET := integration-test-provision-$(OPERATING_SYSTEM)\n# renovate: datasource=github-releases depName=kubernetes/kubernetes\nKUBECTL_VERSION ?= v1.36.0-alpha.2\n# renovate: datasource=github-releases depName=kastenhq/kubestr\nKUBESTR_VERSION ?= v0.4.49\n# renovate: datasource=github-releases depName=helm/helm\nHELM_VERSION ?= v4.1.3\n# renovate: datasource=github-releases depName=cilium/cilium-cli\nCILIUM_CLI_VERSION ?= v0.19.2\n# renovate: datasource=github-releases depName=microsoft/secureboot_objects\nMICROSOFT_SECUREBOOT_RELEASE ?= v1.1.3\n\nKUBECTL_URL ?= https://dl.k8s.io/release/$(KUBECTL_VERSION)/bin/$(OPERATING_SYSTEM)/amd64/kubectl\nKUBESTR_URL ?= https://github.com/kastenhq/kubestr/releases/download/$(KUBESTR_VERSION)/kubestr_$(subst v,,$(KUBESTR_VERSION))_Linux_amd64.tar.gz\nHELM_URL ?= https://get.helm.sh/helm-$(HELM_VERSION)-linux-amd64.tar.gz\nCILIUM_CLI_URL ?= https://github.com/cilium/cilium-cli/releases/download/$(CILIUM_CLI_VERSION)/cilium-$(OPERATING_SYSTEM)-amd64.tar.gz\nTESTPKGS ?= github.com/siderolabs/talos/...\nRELEASES ?= v1.11.6 v1.12.0\nSHORT_INTEGRATION_TEST ?=\nCUSTOM_CNI_URL ?=\n\nINSTALLER_ARCH ?= all\n\nIMAGER_ARGS ?=\n\nCGO_ENABLED ?= 0\nGO_BUILDFLAGS ?=\nGO_BUILDTAGS ?= tcell_minimal,grpcnotrace\nGO_BUILDTAGS_TALOSCTL ?= grpcnotrace\nGO_LDFLAGS ?=\nGO_MACHINED_LDFLAGS ?= -X golang.zx2c4.com/wireguard/ipc.socketDirectory=/system/wireguard-sock # see https://github.com/siderolabs/talos/issues/8514\nGOAMD64 ?= v2\nGOFIPS140 ?= off\n\nWITH_RACE ?= false\nWITH_DEBUG ?= false\n\nifneq (, $(filter $(WITH_RACE), t true TRUE y yes 1))\nCGO_ENABLED = 1\nGO_BUILDFLAGS += -race\nGO_LDFLAGS += -linkmode=external -extldflags '-static'\nINSTALLER_ARCH = targetarch\nendif\n\nifneq (, $(filter $(WITH_DEBUG), t true TRUE y yes 1))\nGO_BUILDTAGS := $(GO_BUILDTAGS),sidero.debug\nGO_BUILDTAGS_TALOSCTL := $(GO_BUILDTAGS_TALOSCTL),sidero.debug\nelse\nGO_LDFLAGS += -s -w\nendif\n\nifneq (, $(filter $(WITH_DEBUG_SHELL), t true TRUE y yes 1))\n# bash-minimal is a Dockerfile target that copies over the bash from siderolabs tools\nDEBUG_TOOLS_SOURCE := bash-minimal\nendif\n\nGO_BUILDFLAGS_TALOSCTL := $(GO_BUILDFLAGS) -tags \"$(GO_BUILDTAGS_TALOSCTL)\"\nGO_BUILDFLAGS += -tags \"$(GO_BUILDTAGS)\"\n\n, := ,\nspace := $(subst ,, )\nBUILD := docker buildx build\nPLATFORM ?= linux/$(ARCH)\nPROGRESS ?= auto\nPUSH ?= false\nCOMMON_ARGS := --file=Dockerfile\nCOMMON_ARGS += --progress=$(PROGRESS)\nCOMMON_ARGS += --platform=$(PLATFORM)\nCOMMON_ARGS += --push=$(PUSH)\n\nCOMMON_ARGS += --build-arg=ABBREV_TAG=$(ABBREV_TAG)\nCOMMON_ARGS += --build-arg=ARTIFACTS=$(ARTIFACTS)\nCOMMON_ARGS += --build-arg=CGO_ENABLED=$(CGO_ENABLED)\nCOMMON_ARGS += --build-arg=DEBUG_TOOLS_SOURCE=$(DEBUG_TOOLS_SOURCE)\nCOMMON_ARGS += --build-arg=EMBED_TARGET=$(EMBED_TARGET)\nCOMMON_ARGS += --build-arg=GO_BUILDFLAGS_TALOSCTL=\"$(GO_BUILDFLAGS_TALOSCTL)\"\nCOMMON_ARGS += --build-arg=GO_BUILDFLAGS=\"$(GO_BUILDFLAGS)\"\nCOMMON_ARGS += --build-arg=GO_LDFLAGS=\"$(GO_LDFLAGS)\"\nCOMMON_ARGS += --build-arg=GO_MACHINED_LDFLAGS=\"$(GO_MACHINED_LDFLAGS)\"\nCOMMON_ARGS += --build-arg=GOAMD64=\"$(GOAMD64)\"\nCOMMON_ARGS += --build-arg=GOFIPS140=\"$(GOFIPS140)\"\nCOMMON_ARGS += --build-arg=http_proxy=$(http_proxy)\nCOMMON_ARGS += --build-arg=https_proxy=$(https_proxy)\nCOMMON_ARGS += --build-arg=INSTALLER_ARCH=$(INSTALLER_ARCH)\nCOMMON_ARGS += --build-arg=MARKDOWNLINTCLI_VERSION=$(MARKDOWNLINTCLI_VERSION)\nCOMMON_ARGS += --build-arg=MICROSOFT_SECUREBOOT_RELEASE=$(MICROSOFT_SECUREBOOT_RELEASE)\nCOMMON_ARGS += --build-arg=NAME=$(NAME)\nCOMMON_ARGS += --build-arg=PKG_APPARMOR=$(PKG_APPARMOR)\nCOMMON_ARGS += --build-arg=PKG_CA_CERTIFICATES=$(PKG_CA_CERTIFICATES)\nCOMMON_ARGS += --build-arg=PKG_CNI=$(PKG_CNI)\nCOMMON_ARGS += --build-arg=PKG_CONTAINERD=$(PKG_CONTAINERD)\nCOMMON_ARGS += --build-arg=PKG_CPIO=$(PKG_CPIO)\nCOMMON_ARGS += --build-arg=PKG_CRYPTSETUP=$(PKG_CRYPTSETUP)\nCOMMON_ARGS += --build-arg=PKG_DOSFSTOOLS=$(PKG_DOSFSTOOLS)\nCOMMON_ARGS += --build-arg=PKG_E2FSPROGS=$(PKG_E2FSPROGS)\nCOMMON_ARGS += --build-arg=PKG_FHS=$(PKG_FHS)\nCOMMON_ARGS += --build-arg=PKG_FLANNEL_CNI=$(PKG_FLANNEL_CNI)\nCOMMON_ARGS += --build-arg=PKG_GLIB=$(PKG_GLIB)\nCOMMON_ARGS += --build-arg=PKG_GRUB=$(PKG_GRUB)\nCOMMON_ARGS += --build-arg=PKG_IGZIP=$(PKG_IGZIP)\nCOMMON_ARGS += --build-arg=PKG_IPTABLES=$(PKG_IPTABLES)\nCOMMON_ARGS += --build-arg=PKG_IPXE=$(PKG_IPXE)\nCOMMON_ARGS += --build-arg=PKG_KERNEL=$(PKG_KERNEL)\nCOMMON_ARGS += --build-arg=PKG_KMOD=$(PKG_KMOD)\nCOMMON_ARGS += --build-arg=PKG_LIBAIO=$(PKG_LIBAIO)\nCOMMON_ARGS += --build-arg=PKG_LIBARCHIVE=$(PKG_LIBARCHIVE)\nCOMMON_ARGS += --build-arg=PKG_LIBATTR=$(PKG_LIBATTR)\nCOMMON_ARGS += --build-arg=PKG_LIBBURN=$(PKG_LIBBURN)\nCOMMON_ARGS += --build-arg=PKG_LIBCAP=$(PKG_LIBCAP)\nCOMMON_ARGS += --build-arg=PKG_LIBINIH=$(PKG_LIBINIH)\nCOMMON_ARGS += --build-arg=PKG_LIBISOBURN=$(PKG_LIBISOBURN)\nCOMMON_ARGS += --build-arg=PKG_LIBISOFS=$(PKG_LIBISOFS)\nCOMMON_ARGS += --build-arg=PKG_LIBJANSSON=$(PKG_LIBJANSSON)\nCOMMON_ARGS += --build-arg=PKG_LIBJSON_C=$(PKG_LIBJSON_C)\nCOMMON_ARGS += --build-arg=PKG_LIBLZMA=$(PKG_LIBLZMA)\nCOMMON_ARGS += --build-arg=PKG_LIBMNL=$(PKG_LIBMNL)\nCOMMON_ARGS += --build-arg=PKG_LIBNFTNL=$(PKG_LIBNFTNL)\nCOMMON_ARGS += --build-arg=PKG_LIBPOPT=$(PKG_LIBPOPT)\nCOMMON_ARGS += --build-arg=PKG_LIBSELINUX=$(PKG_LIBSELINUX)\nCOMMON_ARGS += --build-arg=PKG_LIBSEPOL=$(PKG_LIBSEPOL)\nCOMMON_ARGS += --build-arg=PKG_LIBURCU=$(PKG_LIBURCU)\nCOMMON_ARGS += --build-arg=PKG_LINUX_FIRMWARE=$(PKG_LINUX_FIRMWARE)\nCOMMON_ARGS += --build-arg=PKG_LVM2=$(PKG_LVM2)\nCOMMON_ARGS += --build-arg=PKG_MTOOLS=$(PKG_MTOOLS)\nCOMMON_ARGS += --build-arg=PKG_NFTABLES=$(PKG_NFTABLES)\nCOMMON_ARGS += --build-arg=PKG_MUSL=$(PKG_MUSL)\nCOMMON_ARGS += --build-arg=PKG_OPENSSL=$(PKG_OPENSSL)\nCOMMON_ARGS += --build-arg=PKG_OPEN_VMDK=$(PKG_OPEN_VMDK)\nCOMMON_ARGS += --build-arg=PKG_PCRE2=$(PKG_PCRE2)\nCOMMON_ARGS += --build-arg=PKG_PIGZ=$(PKG_PIGZ)\nCOMMON_ARGS += --build-arg=PKG_QEMU_TOOLS=$(PKG_QEMU_TOOLS)\nCOMMON_ARGS += --build-arg=PKG_RASPBERYPI_FIRMWARE=$(PKG_RASPBERYPI_FIRMWARE)\nCOMMON_ARGS += --build-arg=PKG_RUNC=$(PKG_RUNC)\nCOMMON_ARGS += --build-arg=PKG_SD_BOOT=$(PKG_SD_BOOT)\nCOMMON_ARGS += --build-arg=PKG_SQUASHFS_TOOLS=$(PKG_SQUASHFS_TOOLS)\nCOMMON_ARGS += --build-arg=PKG_SYSTEMD_UDEVD=$(PKG_SYSTEMD_UDEVD)\nCOMMON_ARGS += --build-arg=PKG_TALOSCTL_CNI_BUNDLE=$(PKG_TALOSCTL_CNI_BUNDLE)\nCOMMON_ARGS += --build-arg=PKG_TAR=$(PKG_TAR)\nCOMMON_ARGS += --build-arg=PKG_U_BOOT=$(PKG_U_BOOT)\nCOMMON_ARGS += --build-arg=PKG_UTIL_LINUX=$(PKG_UTIL_LINUX)\nCOMMON_ARGS += --build-arg=PKG_XFSPROGS=$(PKG_XFSPROGS)\nCOMMON_ARGS += --build-arg=PKG_XZ=$(PKG_XZ)\nCOMMON_ARGS += --build-arg=PKG_ZLIB=$(PKG_ZLIB)\nCOMMON_ARGS += --build-arg=PKG_ZSTD=$(PKG_ZSTD)\nCOMMON_ARGS += --build-arg=PKGS_PREFIX=$(PKGS_PREFIX)\nCOMMON_ARGS += --build-arg=PKGS=$(PKGS)\nCOMMON_ARGS += --build-arg=REGISTRY=$(REGISTRY)\nCOMMON_ARGS += --build-arg=SHA=$(SHA)\nCOMMON_ARGS += --build-arg=SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH)\nCOMMON_ARGS += --build-arg=TAG=$(TAG)\nCOMMON_ARGS += --build-arg=TESTPKGS=$(TESTPKGS)\nCOMMON_ARGS += --build-arg=TOOLS_PREFIX=$(TOOLS_PREFIX)\nCOMMON_ARGS += --build-arg=TOOLS=$(TOOLS)\nCOMMON_ARGS += --build-arg=GENERATE_VEX_PREFIX=$(GENERATE_VEX_PREFIX)\nCOMMON_ARGS += --build-arg=GENERATE_VEX=$(GENERATE_VEX)\nCOMMON_ARGS += --build-arg=USERNAME=$(USERNAME)\nCOMMON_ARGS += --build-arg=ZSTD_COMPRESSION_LEVEL=$(ZSTD_COMPRESSION_LEVEL)\n\nCI_ARGS ?=\n\nEXTENSIONS_FILTER_COMMAND ?= grep -vE 'tailscale|xen-guest-agent|nvidia|vmtoolsd-guest-agent|metal-agent|cloudflared|zerotier|nebula|newt|netbird|multipath-tools|trident-iscsi-tools'\n\nall: initramfs kernel installer imager talosctl talosctl-image talos\n\n# Help Menu\n\ndefine HELP_MENU_HEADER\n# Getting Started\n\nTo build this project, you must have the following installed:\n\n- git\n- make\n- docker (19.03 or higher)\n- buildx (https://github.com/docker/buildx)\n- crane (https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md)\n\n## Creating a Builder Instance\n\nThe build process makes use of features not currently supported by the default\nbuilder instance (docker driver). To create a compatible builder instance, run:\n\n```\ndocker buildx create --driver docker-container --name local --buildkitd-flags '--allow-insecure-entitlement security.insecure' --use\n```\n\nIf you already have a compatible builder instance, you may use that instead.\n\n> Note: The security.insecure entitlement is only required, and used by the unit-tests target.\n\n## Artifacts\n\nAll artifacts will be output to ./$(ARTIFACTS). Images will be tagged with the\nregistry \"$(IMAGE_REGISTRY)\", username \"$(USERNAME)\", and a dynamic tag (e.g. $(REGISTRY_AND_USERNAME)/image:$(IMAGE_TAG)).\nThe registry and username can be overridden by exporting REGISTRY, and USERNAME\nrespectively.\n\n## Race Detector\n\nBuilding with `WITH_RACE=1` enables race detector in the Talos executables. Integration tests are always built with the race detector\nenabled.\n\nendef\n\nexport HELP_MENU_HEADER\n\nhelp: ## This help menu.\n\t@echo \"$$HELP_MENU_HEADER\"\n\t@grep -E '^[a-zA-Z0-9%_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-30s\\033[0m %s\\n\", $$1, $$2}'\n\n# Build Abstractions\n\n$(ARTIFACTS):\n\t@mkdir -p $(ARTIFACTS)\n\n.PHONY: base\ntarget-%: ## Builds the specified target defined in the Dockerfile. The build result will only remain in the build cache.\n\t@$(BUILD) \\\n\t\t--target=$* \\\n\t\t$(COMMON_ARGS) \\\n\t\t$(TARGET_ARGS) \\\n\t\t$(CI_ARGS) .\n\nlocal-%: ## Builds the specified target defined in the Dockerfile using the local output type. The build result will be output to the specified local destination.\n\t@$(MAKE) target-$* TARGET_ARGS=\"--output=type=local,dest=$(DEST) $(TARGET_ARGS)\"\n\t@PLATFORM=$(PLATFORM) \\\n\t\tARTIFACTS=$(ARTIFACTS) \\\n\t\t./hack/fix-artifacts.sh\n\ndocker-%: ## Builds the specified target defined in the Dockerfile using the docker output type. The build result will be output to the specified local destination.\n\t@mkdir -p $(DEST)\n\t@$(MAKE) target-$* TARGET_ARGS=\"--output type=docker,dest=$(DEST)/$*.tar,name=$(REGISTRY_AND_USERNAME)/$*:$(IMAGE_TAG_OUT) $(TARGET_ARGS)\"\n\nregistry-%: ## Builds the specified target defined in the Dockerfile using the image/registry output type. The build result will be pushed to the registry if PUSH=true.\n\t@$(MAKE) target-$* TARGET_ARGS=\"--output type=image,name=$(REGISTRY_AND_USERNAME)/$*:$(IMAGE_TAG_OUT),rewrite-timestamp=true $(TARGET_ARGS)\"\n\nhack-test-%: ## Runs the specified script in ./hack/test with well known environment variables.\n\t@./hack/test/$*.sh\n\n# Generators\n\n.PHONY: generate\ngenerate: ## Generates code from protobuf service definitions and machinery config.\n\t@$(MAKE) local-$@ DEST=./ PLATFORM=linux/$(ARCH) EMBED_TARGET=embed-abbrev\n\n.PHONY: docs\ndocs: ## Generates the documentation for machine config, and talosctl.\n\t@$(MAKE) local-$@ DEST=./ PLATFORM=linux/amd64\n\n# Local Artifacts\n\n.PHONY: kernel\nkernel: ## Outputs the kernel package contents (vmlinuz) to the artifact directory.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS) PUSH=false\n\t@-rm -rf $(ARTIFACTS)/modules\n\n.PHONY: initramfs\ninitramfs: ## Builds the compressed initramfs and outputs it to the artifact directory.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS) PUSH=false\n\n.PHONY: sd-boot\nsd-boot: ## Outputs the systemd-boot to the artifact directory.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS) PUSH=false\n\n.PHONY: sd-stub\nsd-stub: ## Outputs the systemd-stub to the artifact directory.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS) PUSH=false\n\n.PHONY: installer-base\ninstaller-base: ## Builds the container image for the installer-base and outputs it to the registry.\n\t@$(MAKE) registry-$@\n\n.PHONY: imager\nimager: ## Builds the container image for the imager and outputs it to the registry.\n\t@$(MAKE) registry-$@\n\n.PHONY: talos\ntalos: ## Builds the Talos container image and outputs it to the registry.\n\t@$(MAKE) registry-$@\n\n.PHONY: talosctl-image\ntalosctl-image: ## Builds the talosctl container image and outputs it to the registry.\n\t@$(MAKE) registry-talosctl\n\ntalosctl-all-image:\n\t@$(MAKE) registry-talosctl-all\n\ntalosctl-all:\n\t@$(MAKE) local-talosctl-all DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-linux-amd64:\n\t@$(MAKE) local-talosctl-linux-amd64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-linux-arm64:\n\t@$(MAKE) local-talosctl-linux-arm64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-linux-armv7:\n\t@$(MAKE) local-talosctl-linux-armv7 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-linux-riscv64:\n\t@$(MAKE) local-talosctl-linux-riscv64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-darwin-amd64:\n\t@$(MAKE) local-talosctl-darwin-amd64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-darwin-arm64:\n\t@$(MAKE) local-talosctl-darwin-arm64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-freebsd-amd64:\n\t@$(MAKE) local-talosctl-freebsd-amd64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-freebsd-arm64:\n\t@$(MAKE) local-talosctl-freebsd-arm64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-windows-amd64:\n\t@$(MAKE) local-talosctl-windows-amd64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl-windows-arm64:\n\t@$(MAKE) local-talosctl-windows-arm64 DEST=$(ARTIFACTS) PUSH=false\n\ntalosctl: talosctl-$(OPERATING_SYSTEM)-$(ARCH)\n\nsbom:\n\t@$(MAKE) local-sbom DEST=$(ARTIFACTS)\n\nimage-%: ## Builds the specified image. Valid options are aws, azure, digital-ocean, gcp, and vmware etc (e.g. image-aws)\n\t@docker pull $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG_IN)\n\t@for platform in $(subst $(,),$(space),$(PLATFORM)); do \\\n\t\tarch=$$(basename \"$${platform}\") && \\\n\t\tdocker run --rm -t \\\n\t\t\t--network=host \\\n\t\t\t--user $(shell id -u):$(shell id -g) \\\n\t\t\t-v $(PWD)/$(ARTIFACTS):/secureboot:ro \\\n\t\t\t-v $(PWD)/$(ARTIFACTS):/out \\\n\t\t\t-e GITHUB_TOKEN \\\n\t\t\t-e SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) \\\n\t\t\t-e DETERMINISTIC_SEED=1 \\\n\t\t\t$(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG_IN) $* \\\n\t\t\t--arch $$arch \\\n\t\t\t--base-installer-image $(REGISTRY_AND_USERNAME)/installer-base:$(IMAGE_TAG_IN) \\\n\t\t\t$(IMAGER_ARGS) || exit 1 ; \\\n\tdone\n\n.PHONY: images-essential\nimages-essential: image-metal image-metal-uki installer secureboot-installer ## Builds only essential images used in the CI.\n\n# Defines all known images (AWS, Azure, DigitalOcean, Exoscale, Cloudstack, GCP, HCloud, Metal, NoCloud, OpenNebula, OpenStack, Oracle, Scaleway, UpCloud, Vultr and VMware).\nIMAGES := image-akamai image-aws image-azure image-digital-ocean image-exoscale image-cloudstack image-gcp image-hcloud image-iso image-metal image-metal-uki image-nocloud image-opennebula image-openstack image-oracle image-scaleway image-upcloud image-vmware image-vultr\n\n.PHONY: images\nimages: $(IMAGES)\n\n.PHONY: iso\niso: image-iso ## Builds the ISO and outputs it to the artifact directory.\n\n.PHONY: secureboot-iso\nsecureboot-iso: image-secureboot-iso ## Builds UEFI only ISO which uses UKI and outputs it to the artifact directory.\n\nIMAGES_LIST :=\n\n.PHONY: installer\ninstaller: ## Builds the installer and outputs it to the artifact directory.\n\t@$(MAKE) image-installer IMAGER_ARGS=\"--base-installer-image $(REGISTRY_AND_USERNAME)/installer-base:$(IMAGE_TAG_IN) $(IMAGER_ARGS)\"\n\n\t@crane_args=\"\"\n\t@for platform in $(subst $(,),$(space),$(PLATFORM)); do \\\n\t\tarch=$$(basename \"$${platform}\") && \\\n\t\timage=$$(crane push $(ARTIFACTS)/installer-$${arch}.tar $(REGISTRY_AND_USERNAME)/installer:$(IMAGE_TAG_OUT)-$${arch}) && \\\n\t\tcrane_args=\"$${crane_args} -m $${image}\" && \\\n\t\trm -f $(ARTIFACTS)/installer-$${arch}.tar ; \\\n\tdone; \\\n\tcrane index append -t \"${REGISTRY_AND_USERNAME}/installer:${IMAGE_TAG_OUT}\" $${crane_args}\n\t@echo \"${REGISTRY_AND_USERNAME}/installer:${IMAGE_TAG_OUT}\" > $(ARTIFACTS)/installer_image\n\n\n.PHONY: secureboot-installer\nsecureboot-installer: ## Builds UEFI only installer which uses UKI and push it to the registry.\n\t@$(MAKE) image-secureboot-installer IMAGER_ARGS=\"--base-installer-image $(REGISTRY_AND_USERNAME)/installer-base:$(IMAGE_TAG_IN) $(IMAGER_ARGS)\"\n\t@for platform in $(subst $(,),$(space),$(PLATFORM)); do \\\n\t\tarch=$$(basename \"$${platform}\") && \\\n\t\tcrane push $(ARTIFACTS)/installer-$${arch}-secureboot.tar $(REGISTRY_AND_USERNAME)/installer:$(IMAGE_TAG_OUT)-$${arch}-secureboot && \\\n\t\trm -f $(ARTIFACTS)/installer-$${arch}-secureboot.tar ; \\\n\tdone\n\n.PHONY: talosctl-cni-bundle\ntalosctl-cni-bundle: ## Creates a compressed tarball that includes CNI bundle for talosctl.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS)\n\t@for platform in $(subst $(,),$(space),$(PLATFORM)); do \\\n\t\tarch=`basename \"$${platform}\"` ; \\\n\t\ttar  -C $(ARTIFACTS)/talosctl-cni-bundle-$${arch} -czf $(ARTIFACTS)/talosctl-cni-bundle-$${arch}.tar.gz . ; \\\n\tdone\n\t@rm -rf $(ARTIFACTS)/talosctl-cni-bundle-*/\n\n.PHONY: cloud-images\ncloud-images: ## Uploads cloud images (AMIs, etc.) to the cloud registry.\n\t@docker run --rm -v $(PWD):/src -w /src \\\n\t\t-e TAG=$(TAG) -e ARTIFACTS=$(ARTIFACTS) -e ABBREV_TAG=$(ABBREV_TAG) \\\n\t\t-e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY \\\n\t\t-e GOOGLE_PROJECT_ID -e GOOGLE_CREDENTIALS \\\n\t\tgolang:$(GO_VERSION) \\\n\t\t./hack/cloud-image-uploader.sh $(CLOUD_IMAGES_EXTRA_ARGS)\n\n.PHONY: uki-certs\nuki-certs: talosctl ## Generate test certificates for SecureBoot/PCR Signing\n\t@$(TALOSCTL_EXECUTABLE) gen secureboot uki\n\t@$(TALOSCTL_EXECUTABLE) gen secureboot pcr\n\t@$(TALOSCTL_EXECUTABLE) gen secureboot database\n\n.PHONY: integration-images-list\nintegration-images-list: ## Generate list of integration images.\n\t@docker run --entrypoint /usr/local/bin/e2e.test registry.k8s.io/conformance:$(KUBECTL_VERSION) --list-images | \\\n\t\t$(TALOSCTL_EXECUTABLE) images integration --installer-tag=$(IMAGE_TAG_IN) --registry-and-user=$(REGISTRY_AND_USERNAME) \\\n\t\t> $(ARTIFACTS)/integration-images.txt\n\nIGNORE_CACHE_IMAGES ?= registry.k8s.io/e2e-test-images/node-perf/pytorch-wide-deep\n# Convert space-separated list into grep-compatible regex (img1|img2|img3)\nIGNORE_CACHE_IMAGES_RE := $(subst $(space),|,$(strip $(IGNORE_CACHE_IMAGES)))\n\n# space helper\nspace := $(empty) $(empty)\nempty :=\n\n.PHONY: cache-create\ncache-create: installer imager integration-images-list ## Generate image cache.\n\t@grep -vE \"$(IGNORE_CACHE_IMAGES_RE)\" $(ARTIFACTS)/integration-images.txt | \\\n\t\t$(TALOSCTL_EXECUTABLE) images cache-create --image-cache-path=/tmp/cache.tar --images=- --force\n\t@crane push /tmp/cache.tar $(REGISTRY_AND_USERNAME)/image-cache:$(IMAGE_TAG_OUT)\n\t@$(MAKE) image-iso IMAGER_ARGS=\"--image-cache=$(REGISTRY_AND_USERNAME)/image-cache:$(IMAGE_TAG_OUT) --extra-kernel-arg='console=ttyS0'\"\n\n# Code Quality\n\napi-descriptors: ## Generates API descriptors used to detect breaking API changes.\n\t@$(MAKE) local-api-descriptors DEST=./ PLATFORM=linux/$(ARCH)\n\nfmt-protobuf: ## Formats protobuf files.\n\t@$(MAKE) local-fmt-protobuf DEST=./ PLATFORM=linux/$(ARCH)\n\nfmt: ## Formats the source code and protobuf files.\n\t@$(MAKE) fmt-protobuf\n\nlint-%: ## Runs the specified linter. Valid options are go, protobuf, and markdown (e.g. lint-go).\n\t@$(MAKE) target-lint-$* PLATFORM=linux/$(ARCH)\n\nlint: ## Runs linters on go, vulncheck, deadcode, protobuf, and markdown file types.\n\t@$(MAKE) lint-go lint-vulncheck lint-deadcode lint-protobuf lint-markdown\n\ncheck-dirty: ## Verifies that source tree is not dirty\n\t@if test -n \"`git status --porcelain`\"; then echo \"Source tree is dirty\"; git status; git diff; exit 1 ; fi\n\ngo-mod-outdated: ## Runs the go-mod-oudated to show outdated dependencies.\n\t@$(MAKE) target-go-mod-outdated PLATFORM=linux/$(ARCH)\n\n# Tests\n\n.PHONY: unit-tests\nunit-tests: ## Performs unit tests.\n\t@$(MAKE) local-$@ DEST=$(ARTIFACTS) TARGET_ARGS=\"--allow security.insecure\" PLATFORM=linux/$(ARCH)\n\n.PHONY: unit-tests-race\nunit-tests-race: ## Performs unit tests with race detection enabled.\n\t@$(MAKE) target-$@ TARGET_ARGS=\"--allow security.insecure\" PLATFORM=linux/$(ARCH)\n\n.PHONY: unit-tests-fips\nunit-tests-fips: ## Performs unit tests with FIPS strict mode.\n\t@$(MAKE) target-$@ TARGET_ARGS=\"--allow security.insecure\" PLATFORM=linux/$(ARCH)\n\n$(ARTIFACTS)/$(INTEGRATION_TEST_DEFAULT_TARGET)-amd64:\n\t@$(MAKE) local-$(INTEGRATION_TEST_DEFAULT_TARGET)-amd64 DEST=$(ARTIFACTS) PLATFORM=linux/amd64 WITH_RACE=true PUSH=false\n\n$(ARTIFACTS)/$(INTEGRATION_TEST_DEFAULT_TARGET)-arm64:\n\t@$(MAKE) local-$(INTEGRATION_TEST_DEFAULT_TARGET)-arm64 DEST=$(ARTIFACTS) PLATFORM=linux/arm64 WITH_RACE=true PUSH=false\n\n$(ARTIFACTS)/$(INTEGRATION_TEST):\n\t@$(MAKE) local-$(INTEGRATION_TEST)-targetarch DEST=$(ARTIFACTS)\n\n$(ARTIFACTS)/$(INTEGRATION_TEST_PROVISION_DEFAULT_TARGET)-amd64:\n\t@$(MAKE) local-$(INTEGRATION_TEST_PROVISION_DEFAULT_TARGET) DEST=$(ARTIFACTS) PLATFORM=linux/amd64 WITH_RACE=true\n\n$(ARTIFACTS)/kubectl: $(ARTIFACTS)\n\t@curl -L -o $(ARTIFACTS)/kubectl \"$(KUBECTL_URL)\"\n\t@chmod +x $(ARTIFACTS)/kubectl\n\n$(ARTIFACTS)/kubestr: $(ARTIFACTS)\n\t@curl -L \"$(KUBESTR_URL)\" | tar xzf - -C $(ARTIFACTS) kubestr\n\t@chmod +x $(ARTIFACTS)/kubestr\n\n$(ARTIFACTS)/helm: $(ARTIFACTS)\n\t@curl -L \"$(HELM_URL)\" | tar xzf - -C $(ARTIFACTS) --strip-components=1 linux-amd64/helm\n\t@chmod +x $(ARTIFACTS)/helm\n\n$(ARTIFACTS)/cilium: $(ARTIFACTS)\n\t@curl -L \"$(CILIUM_CLI_URL)\" | tar xzf - -C $(ARTIFACTS) cilium\n\t@chmod +x $(ARTIFACTS)/cilium\n\nexternal-artifacts: $(ARTIFACTS)/kubectl $(ARTIFACTS)/kubestr $(ARTIFACTS)/helm $(ARTIFACTS)/cilium\n\ne2e-%: $(ARTIFACTS)/$(INTEGRATION_TEST_DEFAULT_TARGET)-amd64 external-artifacts ## Runs the E2E test for the specified platform (e.g. e2e-docker).\n\t@$(MAKE) hack-test-$@ \\\n\t\tPLATFORM=$* \\\n\t\tTAG=$(TAG) \\\n\t\tSHA=$(SHA) \\\n\t\tREGISTRY=$(IMAGE_REGISTRY) \\\n\t\tIMAGE=$(REGISTRY_AND_USERNAME)/talos:$(IMAGE_TAG_IN) \\\n\t\tINSTALLER_IMAGE=$(REGISTRY_AND_USERNAME)/installer:$(IMAGE_TAG_IN) \\\n\t\tARTIFACTS=$(ARTIFACTS) \\\n\t\tTALOSCTL=$(PWD)/$(ARTIFACTS)/$(TALOSCTL_DEFAULT_TARGET)-amd64 \\\n\t\tINTEGRATION_TEST=$(PWD)/$(ARTIFACTS)/$(INTEGRATION_TEST_DEFAULT_TARGET)-amd64 \\\n\t\tSHORT_INTEGRATION_TEST=$(SHORT_INTEGRATION_TEST) \\\n\t\tCUSTOM_CNI_URL=$(CUSTOM_CNI_URL) \\\n\t\tKUBECTL=$(PWD)/$(ARTIFACTS)/kubectl \\\n\t\tKUBESTR=$(PWD)/$(ARTIFACTS)/kubestr \\\n\t\tHELM=$(PWD)/$(ARTIFACTS)/helm \\\n\t\tCILIUM_CLI=$(PWD)/$(ARTIFACTS)/cilium\n\nprovision-tests-prepare: release-artifacts $(ARTIFACTS)/$(INTEGRATION_TEST_PROVISION_DEFAULT_TARGET)-amd64\n\nprovision-tests: provision-tests-prepare\n\t@$(MAKE) hack-test-$@ \\\n\t\tTAG=$(TAG) \\\n\t\tTALOSCTL=$(PWD)/$(ARTIFACTS)/$(TALOSCTL_DEFAULT_TARGET)-amd64 \\\n\t\tINTEGRATION_TEST=$(PWD)/$(ARTIFACTS)/$(INTEGRATION_TEST_PROVISION_DEFAULT_TARGET)-amd64\n\nprovision-tests-track-%:\n\t@$(MAKE) hack-test-provision-tests \\\n\t\tTAG=$(TAG) \\\n\t\tTALOSCTL=$(PWD)/$(ARTIFACTS)/$(TALOSCTL_DEFAULT_TARGET)-amd64 \\\n\t\tINTEGRATION_TEST=$(PWD)/$(ARTIFACTS)/$(INTEGRATION_TEST_PROVISION_DEFAULT_TARGET)-amd64 \\\n\t\tINTEGRATION_TEST_RUN=\"TestIntegration/.+-TR$*\" \\\n\t\tINTEGRATION_TEST_TRACK=\"$*\" \\\n\t\tCUSTOM_CNI_URL=$(CUSTOM_CNI_URL) \\\n\t\tREGISTRY=$(IMAGE_REGISTRY) \\\n\t\tARTIFACTS=$(ARTIFACTS)\n\ninstaller-with-extensions: $(ARTIFACTS)/extensions/_out/extensions-metadata\n\t$(MAKE) image-installer \\\n\t\tIMAGER_ARGS=\"--base-installer-image=$(REGISTRY_AND_USERNAME)/installer-base:$(IMAGE_TAG_IN) $(shell cat $(ARTIFACTS)/extensions/_out/extensions-metadata | $(EXTENSIONS_FILTER_COMMAND) | xargs -n 1 echo --system-extension-image)\"\n\tcrane push $(ARTIFACTS)/installer-amd64.tar $(REGISTRY_AND_USERNAME)/installer:$(IMAGE_TAG_OUT)-amd64-extensions\n\tINSTALLER_IMAGE_EXTENSIONS=\"$(REGISTRY_AND_USERNAME)/installer:$(IMAGE_TAG_OUT)-amd64-extensions\" yq eval -n '.machine.install.image = strenv(INSTALLER_IMAGE_EXTENSIONS)' > $(ARTIFACTS)/installer-extensions-patch.yaml\n\nkubelet-fat-patch:\n\tK8S_VERSION=$(KUBECTL_VERSION) yq eval -n '.machine.kubelet.image = \"ghcr.io/siderolabs/kubelet:\" + strenv(K8S_VERSION) + \"-fat\"' > $(ARTIFACTS)/kubelet-fat-patch.yaml\n\n# Assets for releases\n\n.PHONY: $(ARTIFACTS)/$(TALOS_RELEASE)\n$(ARTIFACTS)/$(TALOS_RELEASE): $(ARTIFACTS)/$(TALOS_RELEASE)/vmlinuz $(ARTIFACTS)/$(TALOS_RELEASE)/initramfs.xz\n\n# download release artifacts for specific version\n$(ARTIFACTS)/$(TALOS_RELEASE)/%:\n\t@mkdir -p $(ARTIFACTS)/$(TALOS_RELEASE)/\n\t@case \"$*\" in \\\n\t\tvmlinuz) \\\n\t\t\tcurl -L -o \"$(ARTIFACTS)/$(TALOS_RELEASE)/$*\" \"https://github.com/siderolabs/talos/releases/download/$(TALOS_RELEASE)/vmlinuz-amd64\" \\\n\t\t\t;; \\\n\t\tinitramfs.xz) \\\n\t\t\tcurl -L -o \"$(ARTIFACTS)/$(TALOS_RELEASE)/$*\" \"https://github.com/siderolabs/talos/releases/download/$(TALOS_RELEASE)/initramfs-amd64.xz\" \\\n\t\t\t;; \\\n\tesac\n\n.PHONY: release-artifacts\nrelease-artifacts:\n\t@for release in $(RELEASES); do \\\n\t\t$(MAKE) $(ARTIFACTS)/$$release TALOS_RELEASE=$$release; \\\n\tdone\n\n# Utilities\n\n.PHONY: rekres\nrekres:\n\t@docker pull $(KRES_IMAGE)\n\t@docker run --rm --net=host --user $(shell id -u):$(shell id -g) -v $(PWD):/src -w /src -e GITHUB_TOKEN $(KRES_IMAGE)\n\n.PHONY: conformance\nconformance:\n\t@docker pull $(CONFORMANCE_IMAGE)\n\t@docker run --rm -it -v $(PWD):/src -w /src $(CONFORMANCE_IMAGE) enforce\n\n.PHONY: release-notes\nrelease-notes:\n\tARTIFACTS=$(ARTIFACTS) ./hack/release.sh $@ $(ARTIFACTS)/RELEASE_NOTES.md $(TAG)\n\npush: ## Pushes the installer, imager, talos and talosctl images to the configured container registry with the generated tag.\n\t@$(MAKE) installer-base PUSH=true\n\t@$(MAKE) imager PUSH=true\n\t@$(MAKE) installer PUSH=true\n\t@$(MAKE) talos PUSH=true\n\t@$(MAKE) talosctl-image PUSH=true\n\t@$(MAKE) talosctl-all-image PUSH=true\n\npush-%: ## Pushes the installer, imager, talos and talosctl images to the configured container registry with the specified tag (e.g. push-latest).\n\t@$(MAKE) push IMAGE_TAG_OUT=$*\n\n.PHONY: clean\nclean: ## Cleans up all artifacts.\n\t@-rm -rf $(ARTIFACTS)\n\n.PHONY: image-list\nimage-list: ## Prints a list of all images built by this Makefile with digests.\n\t@echo -n installer installer-base talos imager talosctl talosctl-all | xargs -d ' ' -I{} sh -c 'echo $(REGISTRY_AND_USERNAME)/{}:$(IMAGE_TAG_IN)' | xargs -I{} sh -c 'echo {}@$$(crane digest {})'\n\n$(ARTIFACTS)/image-signer: $(ARTIFACTS) ## Downloads image-signer binary\n\t@curl -sSL https://github.com/siderolabs/go-tools/releases/download/$(IMAGE_SIGNER_RELEASE)/image-signer-$(OPERATING_SYSTEM)-$(ARCH) -o $(ARTIFACTS)/image-signer\n\t@chmod +x $(ARTIFACTS)/image-signer\n\n\n.PHONY: sign-images\nsign-images: $(ARTIFACTS)/image-signer ## Run cosign to sign all images built by this Makefile.\n\t@$(ARTIFACTS)/image-signer sign $(shell $(MAKE) --quiet image-list REGISTRY_AND_USERNAME=$(REGISTRY_AND_USERNAME) IMAGE_TAG_IN=$(IMAGE_TAG_IN))\n\n.PHONY: reproducibility-test\nreproducibility-test: $(ARTIFACTS)\n\t@$(MAKE) reproducibility-test-local-initramfs\n\t@$(MAKE) reproducibility-test-docker-installer-base INSTALLER_ARCH=targetarch PLATFORM=linux/$(ARCH)\n\t@$(MAKE) reproducibility-test-docker-talos reproducibility-test-docker-installer-base reproducibility-test-docker-imager reproducibility-test-docker-talosctl PLATFORM=linux/$(ARCH)\n\t@$(MAKE) reproducibility-test-iso\n\nreproducibility-test-docker-%: $(ARTIFACTS)\n\t@rm -rf _out1/ _out2/\n\t@mkdir -p _out1/ _out2/\n\t@$(MAKE) docker-$* DEST=_out1/\n\t@$(MAKE) docker-$* DEST=_out2/ TARGET_ARGS=\"--no-cache\"\n\t@find _out1/ -type f | xargs -IFILE diffoscope FILE `echo FILE | sed 's/_out1/_out2/'`\n\t@rm -rf _out1/ _out2/\n\nreproducibility-test-local-%: $(ARTIFACTS)\n\t@rm -rf _out1/ _out2/\n\t@mkdir -p _out1/ _out2/\n\t@$(MAKE) local-$* DEST=_out1/\n\t@$(MAKE) local-$* DEST=_out2/ TARGET_ARGS=\"--no-cache\"\n\t@find _out1/ -type f | xargs -IFILE diffoscope FILE `echo FILE | sed 's/_out1/_out2/'`\n\t@rm -rf _out1/ _out2/\n\nreproducibility-test-iso: $(ARTIFACTS)\n\t@$(MAKE) iso\n\tmv $(ARTIFACTS)/metal-amd64.iso $(ARTIFACTS)/metal-amd64.iso.orig\n\t@$(MAKE) iso\n\t@diffoscope $(ARTIFACTS)/metal-amd64.iso.orig $(ARTIFACTS)/metal-amd64.iso\n\t@rm -rf $(ARTIFACTS)/metal-amd64.iso.orig\n\nreproducibility-test-images: $(ARTIFACTS)\n\t@rm -rf $(ARTIFACTS)/images-orig $(ARTIFACTS)/images-new\n\t@$(MAKE) $(filter-out image-azure image-vmware,$(IMAGES)) ARTIFACTS=$(ARTIFACTS)/images-orig\n\t@$(MAKE) $(filter-out image-azure image-vmware,$(IMAGES)) ARTIFACTS=$(ARTIFACTS)/images-new\n\t@touch -ch -t $$(date -d @$(SOURCE_DATE_EPOCH) +%Y%m%d0000) $(ARTIFACTS)/images-orig $(ARTIFACTS)/images-new\n\t@find $(ARTIFACTS)/images-orig $(ARTIFACTS)/images-new -type f -exec touch -ch -t $$(date -d @$(SOURCE_DATE_EPOCH) +%Y%m%d0000) {} +\n\t@diffoscope $(ARTIFACTS)/images-orig $(ARTIFACTS)/images-new\n\t@rm -rf $(ARTIFACTS)/images-orig $(ARTIFACTS)/images-new\n\n.PHONY: ci-temp-release-tag\nci-temp-release-tag: ## Generates a temporary release tag for CI run.\n\t@if [ -n \"$(CI_RELEASE_TAG)\" -a -n \"$${GITHUB_ENV}\" ]; then \\\n\t\techo Setting temporary release tag \"$(CI_RELEASE_TAG)\"; \\\n\t\techo \"TAG=$(CI_RELEASE_TAG)\" >> \"$${GITHUB_ENV}\"; \\\n\t\techo \"ABBREV_TAG=$(CI_RELEASE_TAG)\" >> \"$${GITHUB_ENV}\"; \\\n\tfi\n"
  },
  {
    "path": "README.md",
    "content": "<!-- markdownlint-disable MD041 -->\n\n<p align=\"center\">\n  <h1 align=\"center\">Talos Linux</h1>\n  <p align=\"center\">A modern OS for Kubernetes.</p>\n  <p align=\"center\">\n    <a href=\"https://github.com/talos-systems/talos/releases/latest\"><img alt=\"Release\" src=\"https://img.shields.io/github/release/talos-systems/talos.svg?logo=github&logoColor=white\"></a>\n    <a href=\"https://github.com/talos-systems/talos/releases/latest\"><img alt=\"Pre-release\" src=\"https://img.shields.io/github/release-pre/talos-systems/talos.svg?label=pre-release&logo=GitHub&logoColor=white\"></a>\n    <a href=\"https://www.bestpractices.dev/projects/7340\"><img src=\"https://www.bestpractices.dev/projects/7340/badge\" alt=\"OpenSSF badge\"></a>\n  </p>\n</p>\n\n---\n\n**Talos** is a modern OS for running Kubernetes: secure, immutable, and minimal.\nTalos is fully open source, production-ready, and supported by the people at [Sidero Labs](https://www.SideroLabs.com/).\nAll system management is done via an API - there is no shell or interactive console.\nBenefits include:\n\n- **Security**: Talos reduces your attack surface: It's minimal, hardened, and immutable.\n  All API access is secured with mutual TLS (mTLS) authentication.\n- **Predictability**: Talos eliminates configuration drift, reduces unknown factors by employing immutable infrastructure ideology, and delivers atomic updates.\n- **Evolvability**: Talos simplifies your architecture, increases your agility, and always delivers current stable Kubernetes and Linux versions.\n\n## Documentation\n\nFor instructions on deploying and managing Talos, see the [Documentation](https://docs.siderolabs.com/talos).\n\n## Community\n\n- Support: Questions, bugs, feature requests [GitHub Discussions](https://github.com/siderolabs/talos/discussions)\n- Slack: Join our [slack channel](https://taloscommunity.slack.com/). Request access via [inviter.co](https://inviter.co/sidero-labs-community).\n- Forum: [community](https://groups.google.com/a/SideroLabs.com/forum/#!forum/community)\n- Twitter: [@SideroLabs](https://twitter.com/SideroLabs)\n- Email: [info@SideroLabs.com](mailto:info@SideroLabs.com)\n\nIf you're interested in this project and would like to help in engineering efforts or have general usage questions, we are happy to have you!\nWe hold a monthly meeting that all audiences are welcome to attend.\n\nWe would appreciate your feedback so that we can make Talos even better!\nTo do so, you can take our [survey](https://docs.google.com/forms/d/1TUna5YTYGCKot68Y9YN_CLobY6z9JzLVCq1G7DoyNjA/edit).\n\n### Office Hours\n\n- When: Second Monday of every month at 16:30 UTC.\n- Where: [Google Meet](https://meet.google.com/ivb-kjfm-jfc).\n\nYou can subscribe to this meeting by joining the community forum above.\n\n> Note: You can convert the meeting hours to your [local time](https://everytimezone.com/s/599e61d6).\n\n## Contributing\n\nContributions are welcomed and appreciated!\nSee [Contributing](CONTRIBUTING.md) for our guidelines.\n\n## License\n\n<a href=\"https://github.com/siderolabs/talos/blob/master/LICENSE\">\n  <img alt=\"GitHub\" src=\"https://img.shields.io/github/license/siderolabs/talos\">\n</a>\n\nSome software we distribute is under the General Public License family of licenses or other licenses that require we provide you with the source code.\nIf you would like a copy of the source code for this software, please contact us via email: info at SideroLabs.com.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Reporting Security Issues\n\nThe Sidero Labs team and community take security bugs in Talos Linux seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.\n\nTo report a security issue, please use the GitHub Security Advisory [\"Report a Vulnerability\"](https://github.com/siderolabs/talos/security/advisories/new) tab.\n\nThe Sidero Labs team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. The expected response time is within 3 business days, and the fix is expected to be delivered within 30 days.\n\n## Supported Releases\n\nThe Sidero Labs team will only provide security updates for the two latest minor releases of Talos Linux. If you are using an older version of Talos Linux, we recommend upgrading to the latest release.\n\nFor example, if the latest release is `v1.8.3`, the supported releases are `v1.7.x` and `v1.8.x`.\n"
  },
  {
    "path": "api/buf.gen.yaml",
    "content": "version: v2\nplugins:\n  - local: [\"go\", \"tool\", \"google.golang.org/protobuf/cmd/protoc-gen-go\"]\n    out: ./machinery/api\n    opt:\n      - paths=source_relative\n  - local: [\"go\", \"tool\", \"google.golang.org/grpc/cmd/protoc-gen-go-grpc\"]\n    out: ./machinery/api\n    opt:\n      - paths=source_relative\n  - local: [\"go\", \"tool\", \"github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto\"]\n    out: ./machinery/api\n    opt:\n      - paths=source_relative\n      - features=marshal+unmarshal+size\n  - local: [\"go\", \"tool\", \"github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc\"]\n    strategy: all\n    out: ./docs/\n    opt:\n      - docs.markdown.tmpl\n      - api.md\ninputs:\n  - directory: .\n    paths:\n      - cluster/\n      - common/\n      - inspect/\n      - machine/\n      - resource/\n      - security/\n      - storage/\n      - time/\n"
  },
  {
    "path": "api/buf.yaml",
    "content": "version: v2\nmodules:\n  - path: ./\n    excludes:\n      - vendor/\n    breaking:\n      use:\n        - WIRE\n    lint:\n      use:\n        - BASIC\n      ignore_only:\n        PACKAGE_DIRECTORY_MATCH:\n          - resource/definitions/\n          - security/\n        ENUM_NO_ALLOW_ALIAS:\n          - resource/definitions/enums/\n  - path: vendor/\n    lint:\n      ignore:\n        - vendor/\n\nlint:\n  use:\n    - BASIC\n\nbreaking:\n  use:\n    - FILE\n"
  },
  {
    "path": "api/cluster/cluster.proto",
    "content": "syntax = \"proto3\";\n\npackage cluster;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/cluster\";\noption java_package = \"dev.talos.api.cluster\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/duration.proto\";\n\n// The cluster service definition.\nservice ClusterService {\n  rpc HealthCheck(HealthCheckRequest) returns (stream HealthCheckProgress);\n}\n\nmessage HealthCheckRequest {\n  google.protobuf.Duration wait_timeout = 1;\n  ClusterInfo cluster_info = 2;\n}\n\nmessage ClusterInfo {\n  repeated string control_plane_nodes = 1;\n  repeated string worker_nodes = 2;\n  string force_endpoint = 3;\n}\n\nmessage HealthCheckProgress {\n  common.Metadata metadata = 1;\n  string message = 2;\n}\n"
  },
  {
    "path": "api/common/common.proto",
    "content": "syntax = \"proto3\";\n\npackage common;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/common\";\noption java_package = \"dev.talos.api.common\";\n\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/descriptor.proto\";\nimport \"google/rpc/status.proto\";\n\n// An alternative to using options could be extracting versions from comments.\n// Unfortunately, they are not available: https://github.com/golang/protobuf/issues/1134\n// Also, while option numbers can be the same,\n// names should be different: https://github.com/protocolbuffers/protobuf/issues/4861\n\nextend google.protobuf.MessageOptions {\n  // Indicates the Talos version when this deprecated message will be removed from API.\n  string remove_deprecated_message = 93117;\n}\n\nextend google.protobuf.FieldOptions {\n  // Indicates the Talos version when this deprecated filed will be removed from API.\n  string remove_deprecated_field = 93117;\n}\n\nextend google.protobuf.EnumOptions {\n  // Indicates the Talos version when this deprecated enum will be removed from API.\n  string remove_deprecated_enum = 93117;\n}\n\nextend google.protobuf.EnumValueOptions {\n  // Indicates the Talos version when this deprecated enum value will be removed from API.\n  string remove_deprecated_enum_value = 93117;\n}\n\nextend google.protobuf.MethodOptions {\n  // Indicates the Talos version when this deprecated method will be removed from API.\n  string remove_deprecated_method = 93117;\n}\n\nextend google.protobuf.ServiceOptions {\n  // Indicates the Talos version when this deprecated service will be removed from API.\n  string remove_deprecated_service = 93117;\n}\n\nenum Code {\n  FATAL = 0;\n  LOCKED = 1;\n  CANCELED = 2;\n}\n\nmessage Error {\n  Code code = 1;\n  string message = 2;\n  repeated google.protobuf.Any details = 3;\n}\n\n// Common metadata message nested in all reply message types\nmessage Metadata {\n  // hostname of the server response comes from (injected by proxy)\n  string hostname = 1;\n  // error is set if request failed to the upstream (rest of response is\n  // undefined)\n  string error = 2;\n  // error as gRPC Status\n  google.rpc.Status status = 3;\n}\n\nmessage Data {\n  Metadata metadata = 1;\n  bytes bytes = 2;\n}\n\nmessage DataResponse {\n  repeated Data messages = 1;\n}\n\nmessage Empty {\n  Metadata metadata = 1;\n}\n\nmessage EmptyResponse {\n  repeated Empty messages = 1;\n}\n\nenum ContainerDriver {\n  CONTAINERD = 0;\n  CRI = 1;\n}\n\nenum ContainerdNamespace {\n  NS_UNKNOWN = 0;\n  NS_SYSTEM = 1;\n  NS_CRI = 2;\n}\n\nmessage ContainerdInstance {\n  // Containerd instance to use.\n  ContainerDriver driver = 1;\n  // Containerd namespace to use.\n  ContainerdNamespace namespace = 2;\n}\n\nmessage URL {\n  string full_path = 1;\n}\n\nmessage PEMEncodedCertificateAndKey {\n  bytes crt = 1;\n  bytes key = 2;\n}\n\nmessage PEMEncodedKey {\n  bytes key = 1;\n}\n\nmessage PEMEncodedCertificate {\n  bytes crt = 1;\n}\n\nmessage NetIP {\n  bytes ip = 1;\n}\n\nmessage NetIPPort {\n  bytes ip = 1;\n  int32 port = 2;\n}\n\nmessage NetIPPrefix {\n  bytes ip = 1;\n  int32 prefix_length = 2;\n}\n"
  },
  {
    "path": "api/docs.markdown.tmpl",
    "content": "---\ntitle: API\ndescription: Talos gRPC API reference.\n---\n\n## Table of Contents\n{{range .Files}}\n{{$file_name := .Name}}- [{{.Name}}](#{{.Name}})\n  {{- if .Messages }}\n  {{range .Messages}}  - [{{.LongName}}](#{{.FullName}})\n  {{end}}\n  {{- end -}}\n  {{- if .Enums }}\n  {{range .Enums}}  - [{{.LongName}}](#{{.FullName}})\n  {{end}}\n  {{- end -}}\n  {{- if .Extensions }}\n  {{range (list .Extensions | uniq)}}  - [File-level Extensions](#{{$file_name}}-extensions)\n  {{end}}\n  {{- end -}}\n  {{- if .Services }}\n  {{range .Services}}  - [{{.Name}}](#{{.FullName}})\n  {{end}}\n  {{- end -}}\n{{end}}\n- [Scalar Value Types](#scalar-value-types)\n\n{{range .Files}}\n{{$file_name := .Name}}\n<a name=\"{{.Name}}\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## {{.Name}}\n{{.Description}}\n\n{{range .Messages}}\n<a name=\"{{.FullName}}\"></a>\n\n### {{.LongName}}\n{{.Description}}\n\n{{if .HasFields}}\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n{{range .Fields -}}\n  | {{.Name}} | [{{.LongType}}](#{{.FullType}}) | {{.Label}} | {{if (index .Options \"deprecated\"|default false)}}**Deprecated.** {{end}}{{nobr .Description | replace \"\\n\\n\" \"<br><br>\"}}{{if .DefaultValue}} Default: {{.DefaultValue}}{{end}} |\n{{end}}\n{{end}}\n\n{{if .HasExtensions}}\n| Extension | Type | Base | Number | Description |\n| --------- | ---- | ---- | ------ | ----------- |\n{{range .Extensions -}}\n  | {{.Name}} | {{.LongType}} | {{.ContainingLongType}} | {{.Number}} | {{nobr .Description | replace \"\\n\\n\" \"<br><br>\"}}{{if .DefaultValue}} Default: {{.DefaultValue}}{{end}} |\n{{end}}\n{{end}}\n\n{{end}} <!-- end messages -->\n\n{{range .Enums}}\n<a name=\"{{.FullName}}\"></a>\n\n### {{.LongName}}\n{{.Description}}\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n{{range .Values -}}\n  | {{.Name}} | {{.Number}} | {{nobr .Description | replace \"\\n\\n\" \"<br><br>\"}} |\n{{end}}\n\n{{end}} <!-- end enums -->\n\n{{if .HasExtensions}}\n<a name=\"{{$file_name}}-extensions\"></a>\n\n### File-level Extensions\n| Extension | Type | Base | Number | Description |\n| --------- | ---- | ---- | ------ | ----------- |\n{{range .Extensions -}}\n  | {{.Name}} | {{.LongType}} | {{.ContainingLongType}} | {{.Number}} | {{nobr .Description | replace \"\\n\\n\" \"<br><br>\"}}{{if .DefaultValue}} Default: `{{.DefaultValue}}`{{end}} |\n{{end}}\n{{end}} <!-- end HasExtensions -->\n\n{{range .Services}}\n<a name=\"{{.FullName}}\"></a>\n\n### {{.Name}}\n{{.Description}}\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n{{range .Methods -}}\n  | {{.Name}} | [{{.RequestLongType}}](#{{.RequestFullType}}){{if .RequestStreaming}} stream{{end}} | [{{.ResponseLongType}}](#{{.ResponseFullType}}){{if .ResponseStreaming}} stream{{end}} | {{nobr .Description | replace \"\\n\\n\" \"<br><br>\"}} |\n{{end}}\n{{end}} <!-- end services -->\n\n{{end}}\n\n## Scalar Value Types\n\n| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |\n| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |\n{{range .Scalars -}}\n  | <a name=\"{{.ProtoType}}\" /> {{.ProtoType}} | {{.Notes}} | {{.CppType}} | {{.JavaType}} | {{.PythonType}} | {{.GoType}} | {{.CSharp}} | {{.PhpType}} | {{.RubyType}} |\n{{end}}\n"
  },
  {
    "path": "api/inspect/inspect.proto",
    "content": "syntax = \"proto3\";\n\npackage inspect;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/inspect\";\noption java_package = \"dev.talos.api.inspect\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/empty.proto\";\n\n// The inspect service definition.\n//\n// InspectService provides auxiliary API to inspect OS internals.\nservice InspectService {\n  rpc ControllerRuntimeDependencies(google.protobuf.Empty) returns (ControllerRuntimeDependenciesResponse);\n}\n\n// The ControllerRuntimeDependency message contains the graph of controller-resource dependencies.\nmessage ControllerRuntimeDependency {\n  common.Metadata metadata = 1;\n  repeated ControllerDependencyEdge edges = 2;\n}\n\nmessage ControllerRuntimeDependenciesResponse {\n  repeated ControllerRuntimeDependency messages = 1;\n}\n\nenum DependencyEdgeType {\n  OUTPUT_EXCLUSIVE = 0;\n  OUTPUT_SHARED = 3;\n  INPUT_STRONG = 1;\n  INPUT_WEAK = 2;\n  INPUT_DESTROY_READY = 4;\n}\n\nmessage ControllerDependencyEdge {\n  string controller_name = 1;\n  DependencyEdgeType edge_type = 2;\n  string resource_namespace = 3;\n  string resource_type = 4;\n  string resource_id = 5;\n}\n"
  },
  {
    "path": "api/machine/debug.proto",
    "content": "syntax = \"proto3\";\n\npackage machine;\n\nimport \"common/common.proto\";\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/machine\";\noption java_package = \"dev.talos.api.machine\";\n\n// DebugService provides debugging and inspection capabilities for a Talos node.\nservice DebugService {\n  // ContainerRun runs a debug container, attaches to it, and streams I/O.\n  rpc ContainerRun(stream DebugContainerRunRequest) returns (stream DebugContainerRunResponse);\n}\n\nmessage DebugContainerRunRequest {\n  oneof request {\n    // 1. send the container spec\n    DebugContainerRunRequestSpec spec = 1;\n    // 2. send either of the three below to interact with the running container\n    bytes stdin_data = 2;\n    int32 signal = 3;\n    DebugContainerTerminalResize term_resize = 4;\n  }\n}\n\nmessage DebugContainerRunRequestSpec {\n  common.ContainerdInstance containerd = 1;\n  string image_name = 2;\n  repeated string args = 3;\n  map<string, string> env = 4;\n\n  enum Profile {\n    PROFILE_UNSPECIFIED = 0;\n    PROFILE_PRIVILEGED = 1;\n  }\n\n  Profile profile = 5;\n  bool tty = 6;\n}\n\nmessage DebugContainerTerminalResize {\n  int32 width = 1;\n  int32 height = 2;\n}\n\nmessage DebugContainerRunResponse {\n  oneof resp {\n    bytes stdout_data = 2;\n    int32 exit_code = 3;\n  }\n}\n"
  },
  {
    "path": "api/machine/image.proto",
    "content": "syntax = \"proto3\";\n\npackage machine;\n\nimport \"common/common.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/machine\";\noption java_package = \"dev.talos.api.machine\";\n\n// The machine service definition.\nservice ImageService {\n  // List images in the containerd.\n  rpc List(ImageServiceListRequest) returns (stream ImageServiceListResponse);\n  // Pull an image into the containerd.\n  rpc Pull(ImageServicePullRequest) returns (stream ImageServicePullResponse);\n  // Import an image from a stream (tarball).\n  rpc Import(stream ImageServiceImportRequest) returns (ImageServiceImportResponse);\n  // Remove an image from the containerd.\n  rpc Remove(ImageServiceRemoveRequest) returns (google.protobuf.Empty);\n  // Verify an image signature.\n  rpc Verify(ImageServiceVerifyRequest) returns (ImageServiceVerifyResponse);\n}\n\nmessage ImageServiceListRequest {\n  common.ContainerdInstance containerd = 1;\n}\n\nmessage ImageServiceListResponse {\n  string name = 1;\n  string digest = 2;\n  int64 size = 3;\n  google.protobuf.Timestamp created_at = 4;\n  map<string, string> labels = 5;\n}\n\nmessage ImageServicePullRequest {\n  common.ContainerdInstance containerd = 1;\n  // Image reference to pull.\n  string image_ref = 3;\n}\n\nmessage ImageServicePullResponse {\n  oneof response {\n    // Name of the pulled image (when done).\n    string name = 1;\n    // Progress of the image pull (intermediate updates).\n    ImageServicePullProgress pull_progress = 2;\n  }\n}\n\nmessage ImageServiceImportRequest {\n  oneof request {\n    // Containerd instance to use.\n    common.ContainerdInstance containerd = 1;\n    // Chunk of the image tarball.\n    common.Data image_chunk = 2;\n  }\n}\n\nmessage ImageServiceImportResponse {\n  // Name of the imported image.\n  string name = 1;\n}\n\nmessage ImageServicePullLayerProgress {\n  enum Status {\n    // Keep this in sync with ImagePullLayerProgress.Status.\n    DOWNLOADING = 0;\n    DOWNLOAD_COMPLETE = 1;\n    EXTRACTING = 2;\n    EXTRACT_COMPLETE = 3;\n    ALREADY_EXISTS = 4;\n  }\n  Status status = 1;\n  google.protobuf.Duration elapsed = 2;\n  int64 offset = 3;\n  int64 total = 4;\n}\n\nmessage ImageServicePullProgress {\n  string layer_id = 1;\n  ImageServicePullLayerProgress progress = 2;\n}\n\nmessage ImageServiceRemoveRequest {\n  common.ContainerdInstance containerd = 1;\n  // Image reference to remove.\n  string image_ref = 2;\n}\n\nmessage ImageServiceVerifyRequest {\n  // Image reference to verify.\n  //\n  // The image reference could be either in:\n  //  * the digest form (e.g. \"docker.io/library/nginx@sha256:abc123...\") to ensure that the exact image is verified.\n  //  * the tag form (e.g. \"docker.io/library/nginx:latest\") to verify the image currently pointed by the tag, and the resolved\n  //    digested will be returned in the response.\n  //\n  // Any other format will cause the error.\n  string image_ref = 1;\n  // Authentication credentials for the registry (if needed).\n  //\n  // By default Talos will use configured auth, but additional\n  // image pull secret can be submitted here.\n  ImageServiceCredentials credentials = 2;\n}\n\nmessage ImageServiceCredentials {\n  // Host of the registry (e.g. \"docker.io\").\n  string host = 1;\n  // Username for the registry.\n  string username = 2;\n  // Password (token) for the registry.\n  string password = 3;\n}\n\nmessage ImageServiceVerifyResponse {\n  // Was the image verified: if it didn't match any verify rule, false will be returned.\n  // If the image matched the rule, but the verification failed, an error will be returned.\n  bool verified = 1;\n  // Free-form verification result message, e.g. with details about the matched rule and how the image was verified.\n  string message = 2;\n  // The pinned image reference with resolved digest that was verified (e.g. \"docker.io/library/nginx@sha256:abc123...\").\n  //\n  // This is only set if verified=true.\n  string digested_image_ref = 3;\n}\n"
  },
  {
    "path": "api/machine/lifecycle.proto",
    "content": "syntax = \"proto3\";\n\npackage machine;\n\nimport \"common/common.proto\";\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/machine\";\noption java_package = \"dev.talos.api.machine\";\n\n// The LifecycleService handles installation and upgrade operations.\nservice LifecycleService {\n  // Install Talos to disk.\n  // The RPC should fail if the Talos is already installed on the target disk.\n  rpc Install(LifecycleServiceInstallRequest) returns (stream LifecycleServiceInstallResponse);\n  // Upgrade Talos to a new version.\n  // The RPC should fail if Talos is not already installed on the target disk.\n  rpc Upgrade(LifecycleServiceUpgradeRequest) returns (stream LifecycleServiceUpgradeResponse);\n}\n\n// InstallArtifactsSource specifies the source of the installation artifacts.\nmessage InstallArtifactsSource {\n  // The reference name of the image, as returned by `talosctl image pull`.\n  string image_name = 1;\n}\n\n// InstallDestination specifies the target for installation.\nmessage InstallDestination {\n  // The disk to which Talos should be installed, e.g. \"/dev/sda\".\n  string disk = 1;\n}\n\n// LifecycleServiceInstallRequest contains the necessary information to perform an installation.\nmessage LifecycleServiceInstallRequest {\n  // The containerd instance to use for pulling the installation artifacts.\n  common.ContainerdInstance containerd = 1;\n  // The source of the installation artifacts.\n  InstallArtifactsSource source = 2;\n  // The destination for the installation.\n  InstallDestination destination = 3;\n}\n\n// LifecycleServiceInstallProgress represents the progress of the installation or upgrade process.\nmessage LifecycleServiceInstallProgress {\n  oneof response {\n    // A message indicating the current progress of the installation or upgrade.\n    string message = 1;\n    // An exit code indicating the result of the installation or upgrade process.\n    // A non-zero value indicates an error.\n    // Server SHOULD NOT respond with error, even if the value is non-zero.\n    // It's responsibility of the client to handle the exit code appropriately.\n    int32 exit_code = 2;\n  }\n}\n\n// LifecycleServiceInstallResponse is the response message for the Install RPC, containing progress updates.\nmessage LifecycleServiceInstallResponse {\n  // The progress of the installation process.\n  LifecycleServiceInstallProgress progress = 1;\n}\n\n// LifecycleServiceUpgradeRequest contains the necessary information to perform an upgrade.\nmessage LifecycleServiceUpgradeRequest {\n  // The containerd instance to use for pulling the installation artifacts.\n  common.ContainerdInstance containerd = 1;\n  // The source of the installation artifacts for the upgrade.\n  InstallArtifactsSource source = 2;\n}\n\n// LifecycleServiceUpgradeResponse is the response message for the Upgrade RPC, containing progress updates.\nmessage LifecycleServiceUpgradeResponse {\n  // The progress of the upgrade process.\n  LifecycleServiceInstallProgress progress = 1;\n}\n"
  },
  {
    "path": "api/machine/machine.proto",
    "content": "syntax = \"proto3\";\n\npackage machine;\n\nimport \"common/common.proto\";\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/machine\";\noption java_package = \"dev.talos.api.machine\";\n\n// The machine service definition.\nservice MachineService {\n  rpc ApplyConfiguration(ApplyConfigurationRequest) returns (ApplyConfigurationResponse);\n  // Bootstrap method makes control plane node enter etcd bootstrap mode.\n  // Node aborts etcd join sequence and creates single-node etcd cluster.\n  // If recover_etcd argument is specified, etcd is recovered from a snapshot\n  // uploaded with EtcdRecover.\n  rpc Bootstrap(BootstrapRequest) returns (BootstrapResponse);\n  rpc Containers(ContainersRequest) returns (ContainersResponse);\n  rpc Copy(CopyRequest) returns (stream common.Data);\n  rpc CPUFreqStats(google.protobuf.Empty) returns (CPUFreqStatsResponse);\n  rpc CPUInfo(google.protobuf.Empty) returns (CPUInfoResponse);\n  rpc DiskStats(google.protobuf.Empty) returns (DiskStatsResponse);\n  rpc Dmesg(DmesgRequest) returns (stream common.Data);\n  rpc Events(EventsRequest) returns (stream Event);\n  rpc EtcdMemberList(EtcdMemberListRequest) returns (EtcdMemberListResponse);\n  // EtcdRemoveMemberByID removes a member from the etcd cluster identified by member ID.\n  // This API should be used to remove members which don't have an associated Talos node anymore.\n  // To remove a member with a running Talos node, use EtcdLeaveCluster API on the node to be removed.\n  rpc EtcdRemoveMemberByID(EtcdRemoveMemberByIDRequest) returns (EtcdRemoveMemberByIDResponse);\n  rpc EtcdLeaveCluster(EtcdLeaveClusterRequest) returns (EtcdLeaveClusterResponse);\n  rpc EtcdForfeitLeadership(EtcdForfeitLeadershipRequest) returns (EtcdForfeitLeadershipResponse);\n  // EtcdRecover method uploads etcd data snapshot created with EtcdSnapshot\n  // to the node.\n  // Snapshot can be later used to recover the cluster via Bootstrap method.\n  rpc EtcdRecover(stream common.Data) returns (EtcdRecoverResponse);\n  // EtcdSnapshot method creates etcd data snapshot (backup) from the local etcd instance\n  // and streams it back to the client.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdSnapshot(EtcdSnapshotRequest) returns (stream common.Data);\n  // EtcdAlarmList lists etcd alarms for the current node.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdAlarmList(google.protobuf.Empty) returns (EtcdAlarmListResponse);\n  // EtcdAlarmDisarm disarms etcd alarms for the current node.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdAlarmDisarm(google.protobuf.Empty) returns (EtcdAlarmDisarmResponse);\n  // EtcdDefragment defragments etcd data directory for the current node.\n  // Defragmentation is a resource-heavy operation, so it should only run on a specific\n  // node.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdDefragment(google.protobuf.Empty) returns (EtcdDefragmentResponse);\n  // EtcdStatus returns etcd status for the current member.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdStatus(google.protobuf.Empty) returns (EtcdStatusResponse);\n  // EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdDowngradeValidate(EtcdDowngradeValidateRequest) returns (EtcdDowngradeValidateResponse);\n  // EtcdDowngradeEnable enables etcd cluster downgrade to a specific version.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdDowngradeEnable(EtcdDowngradeEnableRequest) returns (EtcdDowngradeEnableResponse);\n  // EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress.\n  // This method is available only on control plane nodes (which run etcd).\n  rpc EtcdDowngradeCancel(google.protobuf.Empty) returns (EtcdDowngradeCancelResponse);\n  rpc Hostname(google.protobuf.Empty) returns (HostnameResponse);\n  rpc Kubeconfig(google.protobuf.Empty) returns (stream common.Data);\n  rpc List(ListRequest) returns (stream FileInfo);\n  rpc DiskUsage(DiskUsageRequest) returns (stream DiskUsageInfo);\n  rpc LoadAvg(google.protobuf.Empty) returns (LoadAvgResponse);\n  rpc Logs(LogsRequest) returns (stream common.Data);\n  rpc LogsContainers(google.protobuf.Empty) returns (LogsContainersResponse);\n  rpc Memory(google.protobuf.Empty) returns (MemoryResponse);\n  rpc Mounts(google.protobuf.Empty) returns (MountsResponse);\n  rpc NetworkDeviceStats(google.protobuf.Empty) returns (NetworkDeviceStatsResponse);\n  rpc Processes(google.protobuf.Empty) returns (ProcessesResponse);\n  rpc Read(ReadRequest) returns (stream common.Data);\n  rpc Reboot(RebootRequest) returns (RebootResponse);\n  rpc Restart(RestartRequest) returns (RestartResponse);\n  rpc Rollback(RollbackRequest) returns (RollbackResponse);\n  rpc Reset(ResetRequest) returns (ResetResponse);\n  rpc ServiceList(google.protobuf.Empty) returns (ServiceListResponse);\n  rpc ServiceRestart(ServiceRestartRequest) returns (ServiceRestartResponse);\n  rpc ServiceStart(ServiceStartRequest) returns (ServiceStartResponse);\n  rpc ServiceStop(ServiceStopRequest) returns (ServiceStopResponse);\n  rpc Shutdown(ShutdownRequest) returns (ShutdownResponse);\n  rpc Stats(StatsRequest) returns (StatsResponse);\n  rpc SystemStat(google.protobuf.Empty) returns (SystemStatResponse);\n  // Upgrade initiates the upgrade of the node to a new version of Talos.\n  //\n  // Use LifecycleService Upgrade RPC instead.\n  rpc Upgrade(UpgradeRequest) returns (UpgradeResponse) {\n    option (common.remove_deprecated_method) = \"v1.18\";\n    option deprecated = true;\n  }\n  rpc Version(google.protobuf.Empty) returns (VersionResponse);\n  // GenerateClientConfiguration generates talosctl client configuration (talosconfig).\n  rpc GenerateClientConfiguration(GenerateClientConfigurationRequest) returns (GenerateClientConfigurationResponse);\n  // PacketCapture performs packet capture and streams back pcap file.\n  rpc PacketCapture(PacketCaptureRequest) returns (stream common.Data);\n  // Netstat provides information about network connections.\n  rpc Netstat(NetstatRequest) returns (NetstatResponse);\n  // MetaWrite writes a META key-value pair.\n  rpc MetaWrite(MetaWriteRequest) returns (MetaWriteResponse);\n  // MetaDelete deletes a META key.\n  rpc MetaDelete(MetaDeleteRequest) returns (MetaDeleteResponse);\n  // ImageList lists images in the CRI.\n  //\n  // Use ImageService List RPC instead.\n  rpc ImageList(ImageListRequest) returns (stream ImageListResponse) {\n    option (common.remove_deprecated_method) = \"v1.18\";\n    option deprecated = true;\n  }\n  // ImagePull pulls an image into the CRI.\n  //\n  // Use ImageService Pull RPC instead.\n  rpc ImagePull(ImagePullRequest) returns (ImagePullResponse) {\n    option (common.remove_deprecated_method) = \"v1.18\";\n    option deprecated = true;\n  }\n}\n\n// rpc applyConfiguration\n// ApplyConfiguration describes a request to assert a new configuration upon a\n// node.\nmessage ApplyConfigurationRequest {\n  enum Mode {\n    REBOOT = 0;\n    AUTO = 1;\n    NO_REBOOT = 2;\n    STAGED = 3;\n    TRY = 4;\n  }\n  bytes data = 1;\n  Mode mode = 4;\n  bool dry_run = 5;\n  google.protobuf.Duration try_mode_timeout = 6;\n}\n\n// ApplyConfigurationResponse describes the response to a configuration request.\nmessage ApplyConfiguration {\n  common.Metadata metadata = 1;\n  // Configuration validation warnings.\n  repeated string warnings = 2;\n  // States which mode was actually chosen.\n  ApplyConfigurationRequest.Mode mode = 3;\n  // Human-readable message explaining the result of the apply configuration call.\n  string mode_details = 4;\n}\n\nmessage ApplyConfigurationResponse {\n  repeated ApplyConfiguration messages = 1;\n}\n\n// rpc reboot\nmessage RebootRequest {\n  enum Mode {\n    DEFAULT = 0;\n    POWERCYCLE = 1;\n    FORCE = 2;\n  }\n  Mode mode = 1;\n}\n\n// The reboot message containing the reboot status.\nmessage Reboot {\n  common.Metadata metadata = 1;\n  string actor_id = 2;\n}\n\nmessage RebootResponse {\n  repeated Reboot messages = 1;\n}\n\n// rpc Bootstrap\nmessage BootstrapRequest {\n  // Enable etcd recovery from the snapshot.\n  // Snapshot should be uploaded before this call via EtcdRecover RPC.\n  bool recover_etcd = 1;\n  // Skip hash check on the snapshot (etcd).\n  // Enable this when recovering from data directory copy to skip integrity check.\n  bool recover_skip_hash_check = 2;\n}\n\n// The bootstrap message containing the bootstrap status.\nmessage Bootstrap {\n  common.Metadata metadata = 1;\n}\n\nmessage BootstrapResponse {\n  repeated Bootstrap messages = 1;\n}\n\n// rpc events\nmessage SequenceEvent {\n  string sequence = 1;\n  enum Action {\n    NOOP = 0;\n    START = 1;\n    STOP = 2;\n  }\n  Action action = 2;\n  common.Error error = 3;\n}\n\nmessage PhaseEvent {\n  string phase = 1;\n  enum Action {\n    START = 0;\n    STOP = 1;\n  }\n  Action action = 2;\n}\n\nmessage TaskEvent {\n  string task = 1;\n  enum Action {\n    START = 0;\n    STOP = 1;\n  }\n  Action action = 2;\n}\n\nmessage ServiceStateEvent {\n  string service = 1;\n  enum Action {\n    INITIALIZED = 0;\n    PREPARING = 1;\n    WAITING = 2;\n    RUNNING = 3;\n    STOPPING = 4;\n    FINISHED = 5;\n    FAILED = 6;\n    SKIPPED = 7;\n    STARTING = 8;\n  }\n  Action action = 2;\n  string message = 3;\n  ServiceHealth health = 4;\n}\n\nmessage RestartEvent {\n  int64 cmd = 1;\n}\n\n// ConfigLoadErrorEvent is reported when the config loading has failed.\nmessage ConfigLoadErrorEvent {\n  string error = 1;\n}\n\n// ConfigValidationErrorEvent is reported when config validation has failed.\nmessage ConfigValidationErrorEvent {\n  string error = 1;\n}\n\n// AddressEvent reports node endpoints aggregated from k8s.Endpoints and network.Hostname.\nmessage AddressEvent {\n  string hostname = 1;\n  repeated string addresses = 2;\n}\n\n// MachineStatusEvent reports changes to the MachineStatus resource.\nmessage MachineStatusEvent {\n  message MachineStatus {\n    message UnmetCondition {\n      string name = 1;\n      string reason = 2;\n    }\n    bool ready = 1;\n    repeated UnmetCondition unmet_conditions = 2;\n  }\n  enum MachineStage {\n    UNKNOWN = 0;\n    BOOTING = 1;\n    INSTALLING = 2;\n    MAINTENANCE = 3;\n    RUNNING = 4;\n    REBOOTING = 5;\n    SHUTTING_DOWN = 6;\n    RESETTING = 7;\n    UPGRADING = 8;\n  }\n  MachineStage stage = 1;\n  MachineStatus status = 2;\n}\n\nmessage EventsRequest {\n  int32 tail_events = 1;\n  string tail_id = 2;\n  int32 tail_seconds = 3;\n  string with_actor_id = 4;\n}\n\nmessage Event {\n  common.Metadata metadata = 1;\n  google.protobuf.Any data = 2;\n  string id = 3;\n  string actor_id = 4;\n}\n\n// rpc reset\nmessage ResetPartitionSpec {\n  string label = 1;\n  bool wipe = 2;\n}\n\nmessage ResetRequest {\n  enum WipeMode {\n    ALL = 0;\n    SYSTEM_DISK = 1;\n    USER_DISKS = 2;\n  }\n  // Graceful indicates whether node should leave etcd before the upgrade, it also\n  // enforces etcd checks before leaving.\n  bool graceful = 1;\n  // Reboot indicates whether node should reboot or halt after resetting.\n  bool reboot = 2;\n  // System_partitions_to_wipe lists specific system disk partitions to be reset (wiped).\n  // If system_partitions_to_wipe is empty, all the partitions are erased.\n  repeated ResetPartitionSpec system_partitions_to_wipe = 3;\n  // UserDisksToWipe lists specific connected block devices to be reset (wiped).\n  repeated string user_disks_to_wipe = 4;\n  // WipeMode defines which devices should be wiped.\n  WipeMode mode = 5;\n}\n\n// The reset message containing the restart status.\nmessage Reset {\n  common.Metadata metadata = 1;\n  string actor_id = 2;\n}\n\nmessage ResetResponse {\n  repeated Reset messages = 1;\n}\n\n// rpc shutdown\n// The messages message containing the shutdown status.\nmessage Shutdown {\n  common.Metadata metadata = 1;\n  string actor_id = 2;\n}\n\nmessage ShutdownRequest {\n  // Force indicates whether node should shutdown without first cordening and draining\n  bool force = 1;\n}\n\nmessage ShutdownResponse {\n  repeated Shutdown messages = 1;\n}\n\n// rpc upgrade\nmessage UpgradeRequest {\n  enum RebootMode {\n    DEFAULT = 0;\n    POWERCYCLE = 1;\n  }\n  string image = 1;\n  bool preserve = 2;\n  bool stage = 3;\n  bool force = 4;\n  RebootMode reboot_mode = 5;\n}\n\nmessage Upgrade {\n  common.Metadata metadata = 1;\n  string ack = 2;\n  string actor_id = 3;\n}\n\nmessage UpgradeResponse {\n  repeated Upgrade messages = 1;\n}\n\n// rpc servicelist\nmessage ServiceList {\n  common.Metadata metadata = 1;\n  repeated ServiceInfo services = 2;\n}\n\nmessage ServiceListResponse {\n  repeated ServiceList messages = 1;\n}\n\nmessage ServiceInfo {\n  string id = 1;\n  string state = 2;\n  ServiceEvents events = 3;\n  ServiceHealth health = 4;\n}\n\nmessage ServiceEvents {\n  repeated ServiceEvent events = 1;\n}\n\nmessage ServiceEvent {\n  string msg = 1;\n  string state = 2;\n  google.protobuf.Timestamp ts = 3;\n}\n\nmessage ServiceHealth {\n  bool unknown = 1;\n  bool healthy = 2;\n  string last_message = 3;\n  google.protobuf.Timestamp last_change = 4;\n}\n\n// rpc servicestart\nmessage ServiceStartRequest {\n  string id = 1;\n}\n\nmessage ServiceStart {\n  common.Metadata metadata = 1;\n  string resp = 2;\n}\n\nmessage ServiceStartResponse {\n  repeated ServiceStart messages = 1;\n}\n\nmessage ServiceStopRequest {\n  string id = 1;\n}\n\nmessage ServiceStop {\n  common.Metadata metadata = 1;\n  string resp = 2;\n}\n\nmessage ServiceStopResponse {\n  repeated ServiceStop messages = 1;\n}\n\nmessage ServiceRestartRequest {\n  string id = 1;\n}\n\nmessage ServiceRestart {\n  common.Metadata metadata = 1;\n  string resp = 2;\n}\n\nmessage ServiceRestartResponse {\n  repeated ServiceRestart messages = 1;\n}\n\n// CopyRequest describes a request to copy data out of Talos node\n//\n// Copy produces .tar.gz archive which is streamed back to the caller\nmessage CopyRequest {\n  // Root path to start copying data out, it might be either a file or directory\n  string root_path = 1;\n}\n\n// ListRequest describes a request to list the contents of a directory.\nmessage ListRequest {\n  // Root indicates the root directory for the list. If not indicated, '/' is\n  // presumed.\n  string root = 1;\n  // Recurse indicates that subdirectories should be recursed.\n  bool recurse = 2;\n  // RecursionDepth indicates how many levels of subdirectories should be\n  // recursed. The default (0) indicates that no limit should be enforced.\n  int32 recursion_depth = 3;\n  // File type.\n  enum Type {\n    // Regular file (not directory, symlink, etc).\n    REGULAR = 0;\n    // Directory.\n    DIRECTORY = 1;\n    // Symbolic link.\n    SYMLINK = 2;\n  }\n  // Types indicates what file type should be returned. If not indicated,\n  // all files will be returned.\n  repeated Type types = 4;\n  // Report xattrs\n  bool report_xattrs = 5;\n}\n\n// DiskUsageRequest describes a request to list disk usage of directories and regular files\nmessage DiskUsageRequest {\n  // RecursionDepth indicates how many levels of subdirectories should be\n  // recursed. The default (0) indicates that no limit should be enforced.\n  int32 recursion_depth = 1;\n  // All write sizes for all files, not just directories.\n  bool all = 2;\n  // Threshold exclude entries smaller than SIZE if positive,\n  // or entries greater than SIZE if negative.\n  int64 threshold = 3;\n  // DiskUsagePaths is the list of directories to calculate disk usage for.\n  repeated string paths = 4;\n}\n\n// FileInfo describes a file or directory's information\nmessage FileInfo {\n  common.Metadata metadata = 1;\n  // Name is the name (including prefixed path) of the file or directory\n  string name = 2;\n  // Size indicates the number of bytes contained within the file\n  int64 size = 3;\n  // Mode is the bitmap of UNIX mode/permission flags of the file\n  uint32 mode = 4;\n  // Modified indicates the UNIX timestamp at which the file was last modified\n  int64 modified = 5;\n  // IsDir indicates that the file is a directory\n  bool is_dir = 6;\n  // Error describes any error encountered while trying to read the file\n  // information.\n  string error = 7;\n  // Link is filled with symlink target\n  string link = 8;\n  // RelativeName is the name of the file or directory relative to the RootPath\n  string relative_name = 9;\n  // Owner uid\n  uint32 uid = 10;\n  // Owner gid\n  uint32 gid = 11;\n  // Extended attributes (if present and requested)\n  repeated Xattr xattrs = 12;\n}\n\nmessage Xattr {\n  string name = 1;\n  bytes data = 2;\n}\n\n// DiskUsageInfo describes a file or directory's information for du command\nmessage DiskUsageInfo {\n  common.Metadata metadata = 1;\n  // Name is the name (including prefixed path) of the file or directory\n  string name = 2;\n  // Size indicates the number of bytes contained within the file\n  int64 size = 3;\n  // Error describes any error encountered while trying to read the file\n  // information.\n  string error = 4;\n  // RelativeName is the name of the file or directory relative to the RootPath\n  string relative_name = 5;\n}\n\n// The messages message containing the requested df stats.\nmessage Mounts {\n  common.Metadata metadata = 1;\n  repeated MountStat stats = 2;\n}\n\nmessage MountsResponse {\n  repeated Mounts messages = 1;\n}\n\n// The messages message containing the requested processes.\nmessage MountStat {\n  string filesystem = 1;\n  uint64 size = 2;\n  uint64 available = 3;\n  string mounted_on = 4;\n}\n\nmessage Version {\n  common.Metadata metadata = 1;\n  VersionInfo version = 2;\n  PlatformInfo platform = 3;\n  // Features describe individual Talos features that can be switched on or off.\n  FeaturesInfo features = 4;\n}\n\nmessage VersionResponse {\n  repeated Version messages = 1;\n}\n\nmessage VersionInfo {\n  string tag = 1;\n  string sha = 2;\n  string built = 3;\n  string go_version = 4;\n  string os = 5;\n  string arch = 6;\n}\n\nmessage PlatformInfo {\n  string name = 1;\n  string mode = 2;\n}\n\n// FeaturesInfo describes individual Talos features that can be switched on or off.\nmessage FeaturesInfo {\n  // RBAC is true if role-based access control is enabled.\n  bool rbac = 1;\n}\n\n// rpc logs\n// The request message containing the process name.\nmessage LogsRequest {\n  string namespace = 1;\n  string id = 2;\n  // driver might be default \"containerd\" or \"cri\"\n  common.ContainerDriver driver = 3;\n  bool follow = 4;\n  int32 tail_lines = 5;\n}\n\nmessage ReadRequest {\n  string path = 1;\n}\n\n// LogsContainer describes all available registered log containers.\nmessage LogsContainer {\n  common.Metadata metadata = 1;\n  repeated string ids = 2;\n}\n\nmessage LogsContainersResponse {\n  repeated LogsContainer messages = 1;\n}\n\n// rpc rollback\nmessage RollbackRequest {}\n\nmessage Rollback {\n  common.Metadata metadata = 1;\n}\n\nmessage RollbackResponse {\n  repeated Rollback messages = 1;\n}\n\n// rpc Containers\n\nmessage ContainersRequest {\n  string namespace = 1;\n  // driver might be default \"containerd\" or \"cri\"\n  common.ContainerDriver driver = 2;\n}\n\n// The messages message containing the requested containers.\nmessage ContainerInfo {\n  string namespace = 1;\n  string id = 2;\n  string uid = 10;\n  string internal_id = 9;\n  string image = 3;\n  uint32 pid = 4;\n  string status = 5;\n  string pod_id = 6;\n  string name = 7;\n  string network_namespace = 8;\n}\n\n// The messages message containing the requested containers.\nmessage Container {\n  common.Metadata metadata = 1;\n  repeated ContainerInfo containers = 2;\n}\n\nmessage ContainersResponse {\n  repeated Container messages = 1;\n}\n\n// dmesg\nmessage DmesgRequest {\n  bool follow = 1;\n  bool tail = 2;\n}\n\n// rpc processes\nmessage ProcessesResponse {\n  repeated Process messages = 1;\n}\n\nmessage Process {\n  common.Metadata metadata = 1;\n  repeated ProcessInfo processes = 2;\n}\n\nmessage ProcessInfo {\n  int32 pid = 1;\n  int32 ppid = 2;\n  string state = 3;\n  int32 threads = 4;\n  double cpu_time = 5;\n  uint64 virtual_memory = 6;\n  uint64 resident_memory = 7;\n  string command = 8;\n  string executable = 9;\n  string args = 10;\n  string label = 11;\n}\n\n// rpc restart\n// The request message containing the process to restart.\nmessage RestartRequest {\n  string namespace = 1;\n  string id = 2;\n  // driver might be default \"containerd\" or \"cri\"\n  common.ContainerDriver driver = 3;\n}\n\nmessage Restart {\n  common.Metadata metadata = 1;\n}\n\n// The messages message containing the restart status.\nmessage RestartResponse {\n  repeated Restart messages = 1;\n}\n\n// rpc stats\n\n// The request message containing the containerd namespace.\nmessage StatsRequest {\n  string namespace = 1;\n  // driver might be default \"containerd\" or \"cri\"\n  common.ContainerDriver driver = 2;\n}\n\n// The messages message containing the requested stats.\nmessage Stats {\n  common.Metadata metadata = 1;\n  repeated Stat stats = 2;\n}\n\nmessage StatsResponse {\n  repeated Stats messages = 1;\n}\n\n// The messages message containing the requested stat.\nmessage Stat {\n  string namespace = 1;\n  string id = 2;\n  uint64 memory_usage = 4;\n  uint64 cpu_usage = 5;\n  string pod_id = 6;\n  string name = 7;\n}\n\nmessage Memory {\n  common.Metadata metadata = 1;\n  MemInfo meminfo = 2;\n}\n\nmessage MemoryResponse {\n  repeated Memory messages = 1;\n}\n\nmessage MemInfo {\n  uint64 memtotal = 1;\n  uint64 memfree = 2;\n  uint64 memavailable = 3;\n  uint64 buffers = 4;\n  uint64 cached = 5;\n  uint64 swapcached = 6;\n  uint64 active = 7;\n  uint64 inactive = 8;\n  uint64 activeanon = 9;\n  uint64 inactiveanon = 10;\n  uint64 activefile = 11;\n  uint64 inactivefile = 12;\n  uint64 unevictable = 13;\n  uint64 mlocked = 14;\n  uint64 swaptotal = 15;\n  uint64 swapfree = 16;\n  uint64 dirty = 17;\n  uint64 writeback = 18;\n  uint64 anonpages = 19;\n  uint64 mapped = 20;\n  uint64 shmem = 21;\n  uint64 slab = 22;\n  uint64 sreclaimable = 23;\n  uint64 sunreclaim = 24;\n  uint64 kernelstack = 25;\n  uint64 pagetables = 26;\n  uint64 nfsunstable = 27;\n  uint64 bounce = 28;\n  uint64 writebacktmp = 29;\n  uint64 commitlimit = 30;\n  uint64 committedas = 31;\n  uint64 vmalloctotal = 32;\n  uint64 vmallocused = 33;\n  uint64 vmallocchunk = 34;\n  uint64 hardwarecorrupted = 35;\n  uint64 anonhugepages = 36;\n  uint64 shmemhugepages = 37;\n  uint64 shmempmdmapped = 38;\n  uint64 cmatotal = 39;\n  uint64 cmafree = 40;\n  uint64 hugepagestotal = 41;\n  uint64 hugepagesfree = 42;\n  uint64 hugepagesrsvd = 43;\n  uint64 hugepagessurp = 44;\n  uint64 hugepagesize = 45;\n  uint64 directmap4k = 46;\n  uint64 directmap2m = 47;\n  uint64 directmap1g = 48;\n}\n\n// rpc Hostname\n\nmessage HostnameResponse {\n  repeated Hostname messages = 1;\n}\n\nmessage Hostname {\n  common.Metadata metadata = 1;\n  string hostname = 2;\n}\n\n// rpc LoadAvg\n\nmessage LoadAvgResponse {\n  repeated LoadAvg messages = 1;\n}\n\nmessage LoadAvg {\n  common.Metadata metadata = 1;\n  double load1 = 2;\n  double load5 = 3;\n  double load15 = 4;\n}\n\n// rpc SystemStat\n\nmessage SystemStatResponse {\n  repeated SystemStat messages = 1;\n}\n\nmessage SystemStat {\n  common.Metadata metadata = 1;\n  uint64 boot_time = 2;\n  CPUStat cpu_total = 3;\n  repeated CPUStat cpu = 4;\n  uint64 irq_total = 5;\n  repeated uint64 irq = 6;\n  uint64 context_switches = 7;\n  uint64 process_created = 8;\n  uint64 process_running = 9;\n  uint64 process_blocked = 10;\n  uint64 soft_irq_total = 11;\n  SoftIRQStat soft_irq = 12;\n}\n\nmessage CPUStat {\n  double user = 1;\n  double nice = 2;\n  double system = 3;\n  double idle = 4;\n  double iowait = 5;\n  double irq = 6;\n  double soft_irq = 7;\n  double steal = 8;\n  double guest = 9;\n  double guest_nice = 10;\n}\n\nmessage SoftIRQStat {\n  uint64 hi = 1;\n  uint64 timer = 2;\n  uint64 net_tx = 3;\n  uint64 net_rx = 4;\n  uint64 block = 5;\n  uint64 block_io_poll = 6;\n  uint64 tasklet = 7;\n  uint64 sched = 8;\n  uint64 hrtimer = 9;\n  uint64 rcu = 10;\n}\n\n// rpc CPUFreqStats\n\nmessage CPUFreqStatsResponse {\n  repeated CPUsFreqStats messages = 1;\n}\n\nmessage CPUsFreqStats {\n  common.Metadata metadata = 1;\n  repeated CPUFreqStats cpu_freq_stats = 2;\n}\n\nmessage CPUFreqStats {\n  uint64 current_frequency = 1;\n  uint64 minimum_frequency = 2;\n  uint64 maximum_frequency = 3;\n  string governor = 4;\n}\n\n// rpc CPUInfo\n\nmessage CPUInfoResponse {\n  repeated CPUsInfo messages = 1;\n}\n\nmessage CPUsInfo {\n  common.Metadata metadata = 1;\n  repeated CPUInfo cpu_info = 2;\n}\n\nmessage CPUInfo {\n  uint32 processor = 1;\n  string vendor_id = 2;\n  string cpu_family = 3;\n  string model = 4;\n  string model_name = 5;\n  string stepping = 6;\n  string microcode = 7;\n  double cpu_mhz = 8;\n  string cache_size = 9;\n  string physical_id = 10;\n  uint32 siblings = 11;\n  string core_id = 12;\n  uint32 cpu_cores = 13;\n  string apic_id = 14;\n  string initial_apic_id = 15;\n  string fpu = 16;\n  string fpu_exception = 17;\n  uint32 cpu_id_level = 18;\n  string wp = 19;\n  repeated string flags = 20;\n  repeated string bugs = 21;\n  double bogo_mips = 22;\n  uint32 cl_flush_size = 23;\n  uint32 cache_alignment = 24;\n  string address_sizes = 25;\n  string power_management = 26;\n}\n\n// rpc NetworkDeviceStats\n\nmessage NetworkDeviceStatsResponse {\n  repeated NetworkDeviceStats messages = 1;\n}\n\nmessage NetworkDeviceStats {\n  common.Metadata metadata = 1;\n  NetDev total = 2;\n  repeated NetDev devices = 3;\n}\n\nmessage NetDev {\n  string name = 1;\n  uint64 rx_bytes = 2;\n  uint64 rx_packets = 3;\n  uint64 rx_errors = 4;\n  uint64 rx_dropped = 5;\n  uint64 rx_fifo = 6;\n  uint64 rx_frame = 7;\n  uint64 rx_compressed = 8;\n  uint64 rx_multicast = 9;\n  uint64 tx_bytes = 10;\n  uint64 tx_packets = 11;\n  uint64 tx_errors = 12;\n  uint64 tx_dropped = 13;\n  uint64 tx_fifo = 14;\n  uint64 tx_collisions = 15;\n  uint64 tx_carrier = 16;\n  uint64 tx_compressed = 17;\n}\n\n// rpc DiskStats\n\nmessage DiskStatsResponse {\n  repeated DiskStats messages = 1;\n}\n\nmessage DiskStats {\n  common.Metadata metadata = 1;\n  DiskStat total = 2;\n  repeated DiskStat devices = 3;\n}\n\nmessage DiskStat {\n  string name = 1;\n  uint64 read_completed = 2;\n  uint64 read_merged = 3;\n  uint64 read_sectors = 4;\n  uint64 read_time_ms = 5;\n  uint64 write_completed = 6;\n  uint64 write_merged = 7;\n  uint64 write_sectors = 8;\n  uint64 write_time_ms = 9;\n  uint64 io_in_progress = 10;\n  uint64 io_time_ms = 11;\n  uint64 io_time_weighted_ms = 12;\n  uint64 discard_completed = 13;\n  uint64 discard_merged = 14;\n  uint64 discard_sectors = 15;\n  uint64 discard_time_ms = 16;\n}\n\nmessage EtcdLeaveClusterRequest {}\n\nmessage EtcdLeaveCluster {\n  common.Metadata metadata = 1;\n}\n\nmessage EtcdLeaveClusterResponse {\n  repeated EtcdLeaveCluster messages = 1;\n}\n\nmessage EtcdRemoveMemberRequest {\n  string member = 1;\n}\n\nmessage EtcdRemoveMember {\n  common.Metadata metadata = 1;\n}\n\nmessage EtcdRemoveMemberResponse {\n  repeated EtcdRemoveMember messages = 1;\n}\n\nmessage EtcdRemoveMemberByIDRequest {\n  uint64 member_id = 1;\n}\n\nmessage EtcdRemoveMemberByID {\n  common.Metadata metadata = 1;\n}\n\nmessage EtcdRemoveMemberByIDResponse {\n  repeated EtcdRemoveMemberByID messages = 1;\n}\n\nmessage EtcdForfeitLeadershipRequest {}\n\nmessage EtcdForfeitLeadership {\n  common.Metadata metadata = 1;\n  string member = 2;\n}\n\nmessage EtcdForfeitLeadershipResponse {\n  repeated EtcdForfeitLeadership messages = 1;\n}\n\nmessage EtcdMemberListRequest {\n  bool query_local = 1;\n}\n\n// EtcdMember describes a single etcd member.\nmessage EtcdMember {\n  // member ID.\n  uint64 id = 2;\n  // human-readable name of the member.\n  string hostname = 3;\n  // the list of URLs the member exposes to clients for communication.\n  repeated string peer_urls = 4;\n  // the list of URLs the member exposes to the cluster for communication.\n  repeated string client_urls = 5;\n  // learner flag\n  bool is_learner = 6;\n}\n\n// EtcdMembers contains the list of members registered on the host.\nmessage EtcdMembers {\n  common.Metadata metadata = 1;\n  // list of member hostnames.\n  repeated string legacy_members = 2;\n  // the list of etcd members registered on the node.\n  repeated EtcdMember members = 3;\n}\n\nmessage EtcdMemberListResponse {\n  repeated EtcdMembers messages = 1;\n}\n\nmessage EtcdSnapshotRequest {}\n\nmessage EtcdRecover {\n  common.Metadata metadata = 1;\n}\n\nmessage EtcdRecoverResponse {\n  repeated EtcdRecover messages = 1;\n}\n\nmessage EtcdAlarmListResponse {\n  repeated EtcdAlarm messages = 1;\n}\n\nmessage EtcdAlarm {\n  common.Metadata metadata = 1;\n  repeated EtcdMemberAlarm member_alarms = 2;\n}\n\nmessage EtcdMemberAlarm {\n  enum AlarmType {\n    NONE = 0;\n    NOSPACE = 1;\n    CORRUPT = 2;\n  }\n  uint64 member_id = 1;\n  AlarmType alarm = 2;\n}\n\nmessage EtcdAlarmDisarmResponse {\n  repeated EtcdAlarmDisarm messages = 1;\n}\n\nmessage EtcdAlarmDisarm {\n  common.Metadata metadata = 1;\n  repeated EtcdMemberAlarm member_alarms = 2;\n}\n\nmessage EtcdDefragmentResponse {\n  repeated EtcdDefragment messages = 1;\n}\n\nmessage EtcdDefragment {\n  common.Metadata metadata = 1;\n}\n\nmessage EtcdStatusResponse {\n  repeated EtcdStatus messages = 1;\n}\n\nmessage EtcdStatus {\n  common.Metadata metadata = 1;\n  EtcdMemberStatus member_status = 2;\n}\n\nmessage EtcdMemberStatus {\n  string storage_version = 11;\n  uint64 member_id = 10;\n  string protocol_version = 1;\n  int64 db_size = 2;\n  int64 db_size_in_use = 3;\n  uint64 leader = 4;\n  uint64 raft_index = 5;\n  uint64 raft_term = 6;\n  uint64 raft_applied_index = 7;\n  repeated string errors = 8;\n  bool is_learner = 9;\n}\n\nmessage EtcdDowngradeValidateRequest {\n  string version = 1;\n}\n\nmessage EtcdDowngradeValidateResponse {\n  repeated EtcdDowngradeValidate messages = 1;\n}\n\nmessage EtcdDowngradeValidate {\n  common.Metadata metadata = 1;\n  EtcdClusterDowngrade cluster_downgrade = 2;\n}\n\nmessage EtcdDowngradeEnableRequest {\n  string version = 1;\n}\n\nmessage EtcdDowngradeEnableResponse {\n  repeated EtcdDowngradeEnable messages = 1;\n}\n\nmessage EtcdDowngradeEnable {\n  common.Metadata metadata = 1;\n  EtcdClusterDowngrade cluster_downgrade = 2;\n}\n\nmessage EtcdDowngradeCancelResponse {\n  repeated EtcdDowngradeCancel messages = 1;\n}\n\nmessage EtcdDowngradeCancel {\n  common.Metadata metadata = 1;\n  EtcdClusterDowngrade cluster_downgrade = 2;\n}\n\nmessage EtcdClusterDowngrade {\n  string cluster_version = 1;\n}\n\n// rpc generateConfiguration\n\nmessage RouteConfig {\n  string network = 1;\n  string gateway = 2;\n  uint32 metric = 3;\n}\n\nmessage DHCPOptionsConfig {\n  uint32 route_metric = 1;\n}\n\nmessage NetworkDeviceConfig {\n  string interface = 1;\n  string cidr = 2;\n  int32 mtu = 3;\n  bool dhcp = 4;\n  bool ignore = 5;\n  DHCPOptionsConfig dhcp_options = 6;\n  repeated RouteConfig routes = 7;\n}\n\nmessage NetworkConfig {\n  string hostname = 1;\n  repeated NetworkDeviceConfig interfaces = 2;\n}\n\nmessage InstallConfig {\n  string install_disk = 1;\n  string install_image = 2;\n}\n\nmessage MachineConfig {\n  enum MachineType {\n    TYPE_UNKNOWN = 0;\n    TYPE_INIT = 1;\n    TYPE_CONTROL_PLANE = 2;\n    TYPE_WORKER = 3;\n  }\n  MachineType type = 1;\n  InstallConfig install_config = 2;\n  NetworkConfig network_config = 3;\n  string kubernetes_version = 4;\n}\n\nmessage ControlPlaneConfig {\n  string endpoint = 1;\n}\n\nmessage CNIConfig {\n  string name = 1;\n  repeated string urls = 2;\n}\n\nmessage ClusterNetworkConfig {\n  string dns_domain = 1;\n  CNIConfig cni_config = 2;\n}\n\nmessage ClusterConfig {\n  string name = 1;\n  ControlPlaneConfig control_plane = 2;\n  ClusterNetworkConfig cluster_network = 3;\n  bool allow_scheduling_on_control_planes = 4;\n}\n\nmessage GenerateClientConfigurationRequest {\n  // Roles in the generated client certificate.\n  repeated string roles = 1;\n  // Client certificate TTL.\n  google.protobuf.Duration crt_ttl = 2;\n}\n\nmessage GenerateClientConfiguration {\n  common.Metadata metadata = 1;\n  // PEM-encoded CA certificate.\n  bytes ca = 2;\n  // PEM-encoded generated client certificate.\n  bytes crt = 3;\n  // PEM-encoded generated client key.\n  bytes key = 4;\n  // Client configuration (talosconfig) file content.\n  bytes talosconfig = 5;\n}\n\nmessage GenerateClientConfigurationResponse {\n  repeated GenerateClientConfiguration messages = 1;\n}\n\nmessage PacketCaptureRequest {\n  // Interface name to perform packet capture on.\n  string interface = 1;\n  // Enable promiscuous mode.\n  bool promiscuous = 2;\n  // Snap length in bytes.\n  uint32 snap_len = 3;\n  // BPF filter.\n  repeated BPFInstruction bpf_filter = 4;\n}\n\nmessage BPFInstruction {\n  uint32 op = 1;\n  uint32 jt = 2;\n  uint32 jf = 3;\n  uint32 k = 4;\n}\n\nmessage NetstatRequest {\n  enum Filter {\n    ALL = 0;\n    CONNECTED = 1;\n    LISTENING = 2;\n  }\n  Filter filter = 1;\n  message Feature {\n    bool pid = 1;\n  }\n  Feature feature = 2;\n  message L4proto {\n    bool tcp = 1;\n    bool tcp6 = 2;\n    bool udp = 3;\n    bool udp6 = 4;\n    bool udplite = 5;\n    bool udplite6 = 6;\n    bool raw = 7;\n    bool raw6 = 8;\n  }\n  L4proto l4proto = 3;\n  message NetNS {\n    bool hostnetwork = 1;\n    repeated string netns = 2;\n    bool allnetns = 3;\n  }\n  NetNS netns = 4;\n}\n\nmessage ConnectRecord {\n  string l4proto = 1;\n  string localip = 2;\n  uint32 localport = 3;\n  string remoteip = 4;\n  uint32 remoteport = 5;\n  enum State {\n    RESERVED = 0;\n    ESTABLISHED = 1;\n    SYN_SENT = 2;\n    SYN_RECV = 3;\n    FIN_WAIT1 = 4;\n    FIN_WAIT2 = 5;\n    TIME_WAIT = 6;\n    CLOSE = 7;\n    CLOSEWAIT = 8;\n    LASTACK = 9;\n    LISTEN = 10;\n    CLOSING = 11;\n  }\n  State state = 6;\n  uint64 txqueue = 7;\n  uint64 rxqueue = 8;\n  enum TimerActive {\n    OFF = 0;\n    ON = 1;\n    KEEPALIVE = 2;\n    TIMEWAIT = 3;\n    PROBE = 4;\n  }\n  TimerActive tr = 9;\n  uint64 timerwhen = 10;\n  uint64 retrnsmt = 11;\n  uint32 uid = 12;\n  uint64 timeout = 13;\n  uint64 inode = 14;\n  uint64 ref = 15;\n  uint64 pointer = 16;\n  message Process {\n    uint32 pid = 1;\n    string name = 2;\n  }\n  Process process = 17;\n  string netns = 18;\n}\n\nmessage Netstat {\n  common.Metadata metadata = 1;\n  repeated ConnectRecord connectrecord = 2;\n}\n\nmessage NetstatResponse {\n  repeated Netstat messages = 1;\n}\n\nmessage MetaWriteRequest {\n  uint32 key = 1;\n  bytes value = 2;\n}\n\nmessage MetaWrite {\n  common.Metadata metadata = 1;\n}\n\nmessage MetaWriteResponse {\n  repeated MetaWrite messages = 1;\n}\n\nmessage MetaDeleteRequest {\n  uint32 key = 1;\n}\n\nmessage MetaDelete {\n  common.Metadata metadata = 1;\n}\n\nmessage MetaDeleteResponse {\n  repeated MetaDelete messages = 1;\n}\n\nmessage ImageListRequest {\n  // Containerd namespace to use.\n  common.ContainerdNamespace namespace = 1;\n}\n\nmessage ImageListResponse {\n  common.Metadata metadata = 1;\n  string name = 2;\n  string digest = 3;\n  int64 size = 4;\n  google.protobuf.Timestamp created_at = 5;\n}\n\nmessage ImagePullRequest {\n  // Containerd namespace to use.\n  common.ContainerdNamespace namespace = 1;\n  // Image reference to pull.\n  string reference = 2;\n}\n\nmessage ImagePull {\n  common.Metadata metadata = 1;\n}\n\nmessage ImagePullResponse {\n  repeated ImagePull messages = 1;\n}\n"
  },
  {
    "path": "api/resource/config/config.proto",
    "content": "syntax = \"proto3\";\n\npackage resource.config;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/config\";\noption java_package = \"dev.talos.api.resource.config\";\n\n// MessageConfigSpec is the spec for the config.MachineConfig resource.\nmessage MachineConfigSpec {\n  // Contains YAML marshalled machine configuration.\n  //\n  // Byte representation is preserved as the machine configuration was submitted to the node.\n  bytes yaml_marshalled = 1;\n}\n\n// MachineType matches machine.Type constants.\nenum MachineType {\n  UNKNOWN = 0;\n  INIT = 1;\n  CONTROL_PLANE = 2;\n  WORKER = 3;\n}\n\n// MachineTypeSpec is the spec for the config.MachineType resource.\nmessage MachineTypeSpec {\n  MachineType machine_type = 1;\n}\n"
  },
  {
    "path": "api/resource/definitions/block/block.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.block;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\";\noption java_package = \"dev.talos.api.resource.definitions.block\";\n\nimport \"google/api/expr/v1alpha1/checked.proto\";\nimport \"resource/definitions/enums/enums.proto\";\n\n// DeviceSpec is the spec for devices status.\nmessage DeviceSpec {\n  string type = 1;\n  int64 major = 2;\n  int64 minor = 3;\n  string partition_name = 4;\n  int64 partition_number = 5;\n  int64 generation = 6;\n  string device_path = 7;\n  string parent = 8;\n  repeated string secondaries = 9;\n}\n\n// DiscoveredVolumeSpec is the spec for DiscoveredVolumes resource.\nmessage DiscoveredVolumeSpec {\n  uint64 size = 1;\n  uint64 sector_size = 2;\n  uint64 io_size = 3;\n  string name = 4;\n  string uuid = 5;\n  string label = 6;\n  uint32 block_size = 7;\n  uint32 filesystem_block_size = 8;\n  uint64 probed_size = 9;\n  string partition_uuid = 10;\n  string partition_type = 11;\n  string partition_label = 12;\n  uint64 partition_index = 13;\n  string type = 14;\n  string device_path = 15;\n  string parent = 16;\n  string dev_path = 17;\n  string parent_dev_path = 18;\n  string pretty_size = 19;\n  uint64 offset = 20;\n}\n\n// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest.\nmessage DiscoveryRefreshRequestSpec {\n  int64 request = 1;\n}\n\n// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status.\nmessage DiscoveryRefreshStatusSpec {\n  int64 request = 1;\n}\n\n// DiskSelector selects a disk for the volume.\nmessage DiskSelector {\n  google.api.expr.v1alpha1.CheckedExpr match = 1;\n  string external = 2;\n}\n\n// DiskSpec is the spec for Disks status.\nmessage DiskSpec {\n  uint64 size = 1;\n  uint64 io_size = 2;\n  uint64 sector_size = 3;\n  bool readonly = 4;\n  string model = 5;\n  string serial = 6;\n  string modalias = 7;\n  string wwid = 8;\n  string bus_path = 9;\n  string sub_system = 10;\n  string transport = 11;\n  bool rotational = 12;\n  bool cdrom = 13;\n  string dev_path = 14;\n  string pretty_size = 15;\n  repeated string secondary_disks = 16;\n  string uuid = 17;\n  repeated string symlinks = 18;\n}\n\n// EncryptionKey is the spec for volume encryption key.\nmessage EncryptionKey {\n  int64 slot = 1;\n  talos.resource.definitions.enums.BlockEncryptionKeyType type = 2;\n  bytes static_passphrase = 3;\n  string kms_endpoint = 4;\n  bool tpm_check_secureboot_status_on_enroll = 5;\n  bool lock_to_state = 6;\n  repeated int64 tpmpc_rs = 7;\n  repeated int64 tpm_pub_key_pc_rs = 8;\n}\n\n// EncryptionSpec is the spec for volume encryption.\nmessage EncryptionSpec {\n  talos.resource.definitions.enums.BlockEncryptionProviderType provider = 1;\n  repeated EncryptionKey keys = 2;\n  string cipher = 3;\n  uint64 key_size = 4;\n  uint64 block_size = 5;\n  repeated string perf_options = 6;\n}\n\n// FilesystemSpec is the spec for volume filesystem.\nmessage FilesystemSpec {\n  talos.resource.definitions.enums.BlockFilesystemType type = 1;\n  string label = 2;\n}\n\n// LocatorSpec is the spec for volume locator.\nmessage LocatorSpec {\n  google.api.expr.v1alpha1.CheckedExpr match = 1;\n  google.api.expr.v1alpha1.CheckedExpr disk_match = 2;\n}\n\n// MountRequestSpec is the spec for MountRequest.\nmessage MountRequestSpec {\n  string volume_id = 1;\n  string parent_mount_id = 2;\n  repeated string requesters = 3;\n  repeated string requester_i_ds = 4;\n  bool read_only = 5;\n  bool detached = 6;\n  bool disable_access_time = 7;\n  bool secure = 8;\n}\n\n// MountSpec is the spec for volume mount.\nmessage MountSpec {\n  string target_path = 1;\n  string selinux_label = 2;\n  bool project_quota_support = 3;\n  string parent_id = 4;\n  uint32 file_mode = 5;\n  int64 uid = 6;\n  int64 gid = 7;\n  bool recursive_relabel = 8;\n  string bind_target = 9;\n  repeated ParameterSpec parameters = 10;\n}\n\n// MountStatusSpec is the spec for MountStatus.\nmessage MountStatusSpec {\n  MountRequestSpec spec = 1;\n  string target = 2;\n  string source = 3;\n  talos.resource.definitions.enums.BlockFilesystemType filesystem = 4;\n  bool read_only = 5;\n  bool project_quota_support = 6;\n  talos.resource.definitions.enums.BlockEncryptionProviderType encryption_provider = 7;\n  bool detached = 8;\n}\n\n// ParameterSpec is a mount parameter.\nmessage ParameterSpec {\n  talos.resource.definitions.enums.BlockFSParameterType type = 1;\n  string name = 2;\n  string string = 3;\n  bytes binary = 5;\n}\n\n// PartitionSpec is the spec for volume partitioning.\nmessage PartitionSpec {\n  uint64 min_size = 1;\n  uint64 max_size = 2;\n  bool grow = 3;\n  string label = 4;\n  string type_uuid = 5;\n  uint64 relative_max_size = 6;\n  bool negative_max_size = 7;\n}\n\n// ProvisioningSpec is the spec for volume provisioning.\nmessage ProvisioningSpec {\n  DiskSelector disk_selector = 1;\n  PartitionSpec partition_spec = 2;\n  int64 wave = 3;\n  FilesystemSpec filesystem_spec = 4;\n}\n\n// SwapStatusSpec is the spec for SwapStatuss resource.\nmessage SwapStatusSpec {\n  string device = 1;\n  uint64 size_bytes = 2;\n  string size_human = 3;\n  uint64 used_bytes = 4;\n  string used_human = 5;\n  int32 priority = 6;\n  string type = 7;\n}\n\n// SymlinkProvisioningSpec is the spec for volume symlink.\nmessage SymlinkProvisioningSpec {\n  string symlink_target_path = 1;\n  bool force = 2;\n}\n\n// SymlinkSpec is the spec for Symlinks resource.\nmessage SymlinkSpec {\n  repeated string paths = 1;\n}\n\n// SystemDiskSpec is the spec for SystemDisks resource.\nmessage SystemDiskSpec {\n  string disk_id = 1;\n  string dev_path = 2;\n}\n\n// TPMEncryptionOptionsInfo is the options for TPM-based encryption.\nmessage TPMEncryptionOptionsInfo {\n  repeated int64 pc_rs = 1;\n  repeated int64 pub_key_pc_rs = 2;\n}\n\n// UserDiskConfigStatusSpec is the spec for UserDiskConfigStatus resource.\nmessage UserDiskConfigStatusSpec {\n  bool ready = 1;\n  bool torn_down = 2;\n}\n\n// VolumeConfigSpec is the spec for VolumeConfig resource.\nmessage VolumeConfigSpec {\n  string parent_id = 1;\n  talos.resource.definitions.enums.BlockVolumeType type = 2;\n  ProvisioningSpec provisioning = 3;\n  LocatorSpec locator = 4;\n  MountSpec mount = 5;\n  EncryptionSpec encryption = 6;\n  SymlinkProvisioningSpec symlink = 7;\n}\n\n// VolumeMountRequestSpec is the spec for VolumeMountRequest.\nmessage VolumeMountRequestSpec {\n  string volume_id = 1;\n  string requester = 2;\n  bool read_only = 3;\n  bool detached = 4;\n  bool disable_access_time = 5;\n  bool secure = 6;\n}\n\n// VolumeMountStatusSpec is the spec for VolumeMountStatus.\nmessage VolumeMountStatusSpec {\n  string volume_id = 1;\n  string requester = 2;\n  string target = 3;\n  bool read_only = 4;\n  bool detached = 5;\n  bool disable_access_time = 6;\n  bool secure = 7;\n}\n\n// VolumeStatusSpec is the spec for VolumeStatus resource.\nmessage VolumeStatusSpec {\n  talos.resource.definitions.enums.BlockVolumePhase phase = 1;\n  string location = 2;\n  string error_message = 3;\n  string uuid = 4;\n  string partition_uuid = 5;\n  talos.resource.definitions.enums.BlockVolumePhase pre_fail_phase = 6;\n  string parent_location = 7;\n  int64 partition_index = 8;\n  uint64 size = 9;\n  talos.resource.definitions.enums.BlockFilesystemType filesystem = 10;\n  string mount_location = 11;\n  talos.resource.definitions.enums.BlockEncryptionProviderType encryption_provider = 12;\n  string pretty_size = 13;\n  repeated string encryption_failed_syncs = 14;\n  MountSpec mount_spec = 15;\n  talos.resource.definitions.enums.BlockVolumeType type = 16;\n  repeated string configured_encryption_keys = 17;\n  SymlinkProvisioningSpec symlink_spec = 18;\n  string parent_id = 19;\n  bool encryption_locked_to_state = 20;\n  int64 encryption_slot = 21;\n  TPMEncryptionOptionsInfo tpm_encryption_options = 22;\n}\n\n// ZswapStatusSpec is the spec for ZswapStatus resource.\nmessage ZswapStatusSpec {\n  uint64 total_size_bytes = 1;\n  string total_size_human = 2;\n  uint64 stored_pages = 3;\n  uint64 pool_limit_hit = 4;\n  uint64 reject_reclaim_fail = 5;\n  uint64 reject_alloc_fail = 6;\n  uint64 reject_kmemcache_fail = 7;\n  uint64 reject_compress_fail = 8;\n  uint64 reject_compress_poor = 9;\n  uint64 written_back_pages = 10;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/cluster/cluster.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.cluster;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cluster\";\noption java_package = \"dev.talos.api.resource.definitions.cluster\";\n\nimport \"common/common.proto\";\nimport \"resource/definitions/enums/enums.proto\";\n\n// AffiliateSpec describes Affiliate state.\nmessage AffiliateSpec {\n  string node_id = 1;\n  repeated common.NetIP addresses = 2;\n  string hostname = 3;\n  string nodename = 4;\n  string operating_system = 5;\n  talos.resource.definitions.enums.MachineType machine_type = 6;\n  KubeSpanAffiliateSpec kube_span = 7;\n  ControlPlane control_plane = 8;\n}\n\n// ConfigSpec describes KubeSpan configuration.\nmessage ConfigSpec {\n  bool discovery_enabled = 1;\n  bool registry_kubernetes_enabled = 2;\n  bool registry_service_enabled = 3;\n  string service_endpoint = 4;\n  bool service_endpoint_insecure = 5;\n  bytes service_encryption_key = 6;\n  string service_cluster_id = 7;\n}\n\n// ControlPlane describes ControlPlane data if any.\nmessage ControlPlane {\n  int64 api_server_port = 1;\n}\n\n// IdentitySpec describes status of rendered secrets.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\nmessage IdentitySpec {\n  string node_id = 1;\n}\n\n// InfoSpec describes cluster information.\nmessage InfoSpec {\n  string cluster_id = 1;\n  string cluster_name = 2;\n}\n\n// KubeSpanAffiliateSpec describes additional information specific for the KubeSpan.\nmessage KubeSpanAffiliateSpec {\n  string public_key = 1;\n  common.NetIP address = 2;\n  repeated common.NetIPPrefix additional_addresses = 3;\n  repeated common.NetIPPort endpoints = 4;\n  repeated common.NetIPPrefix exclude_advertised_networks = 5;\n}\n\n// MemberSpec describes Member state.\nmessage MemberSpec {\n  string node_id = 1;\n  repeated common.NetIP addresses = 2;\n  string hostname = 3;\n  talos.resource.definitions.enums.MachineType machine_type = 4;\n  string operating_system = 5;\n  ControlPlane control_plane = 6;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/cri/cri.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.cri;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cri\";\noption java_package = \"dev.talos.api.resource.definitions.cri\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/struct.proto\";\nimport \"resource/definitions/enums/enums.proto\";\n\n// ImageCacheConfigSpec represents the ImageCacheConfig.\nmessage ImageCacheConfigSpec {\n  talos.resource.definitions.enums.CriImageCacheStatus status = 1;\n  repeated string roots = 2;\n  talos.resource.definitions.enums.CriImageCacheCopyStatus copy_status = 3;\n}\n\n// RegistriesConfigSpec describes status of rendered secrets.\nmessage RegistriesConfigSpec {\n  map<string, RegistryMirrorConfig> registry_mirrors = 1;\n  map<string, RegistryAuthConfig> registry_auths = 2;\n  map<string, RegistryTLSConfig> registry_tl_ss = 3;\n}\n\n// RegistryAuthConfig specifies authentication configuration for a registry.\nmessage RegistryAuthConfig {\n  string registry_username = 1;\n  string registry_password = 2;\n  string registry_auth = 3;\n  string registry_identity_token = 4;\n}\n\n// RegistryEndpointConfig represents a single registry endpoint.\nmessage RegistryEndpointConfig {\n  string endpoint_endpoint = 1;\n  bool endpoint_override_path = 2;\n}\n\n// RegistryMirrorConfig represents mirror configuration for a registry.\nmessage RegistryMirrorConfig {\n  repeated RegistryEndpointConfig mirror_endpoints = 1;\n  bool mirror_skip_fallback = 3;\n}\n\n// RegistryTLSConfig specifies TLS config for HTTPS registries.\nmessage RegistryTLSConfig {\n  common.PEMEncodedCertificateAndKey tls_client_identity = 1;\n  bytes tlsca = 2;\n  bool tls_insecure_skip_verify = 3;\n}\n\n// SeccompProfileSpec represents the SeccompProfile.\nmessage SeccompProfileSpec {\n  string name = 1;\n  google.protobuf.Struct value = 2;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/enums/enums.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.enums;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\";\noption java_package = \"dev.talos.api.resource.definitions.enums\";\n\n// RuntimeMachineStage describes the stage of the machine boot/run process.\nenum RuntimeMachineStage {\n  MACHINE_STAGE_UNKNOWN = 0;\n  MACHINE_STAGE_BOOTING = 1;\n  MACHINE_STAGE_INSTALLING = 2;\n  MACHINE_STAGE_MAINTENANCE = 3;\n  MACHINE_STAGE_RUNNING = 4;\n  MACHINE_STAGE_REBOOTING = 5;\n  MACHINE_STAGE_SHUTTING_DOWN = 6;\n  MACHINE_STAGE_RESETTING = 7;\n  MACHINE_STAGE_UPGRADING = 8;\n}\n\n// RuntimeSELinuxState describes the current SELinux status.\nenum RuntimeSELinuxState {\n  SE_LINUX_STATE_DISABLED = 0;\n  SE_LINUX_STATE_PERMISSIVE = 1;\n  SE_LINUX_STATE_ENFORCING = 2;\n}\n\n// RuntimeFIPSState describes the current FIPS status.\nenum RuntimeFIPSState {\n  FIPS_STATE_DISABLED = 0;\n  FIPS_STATE_ENABLED = 1;\n  FIPS_STATE_STRICT = 2;\n}\n\n// MachineType represents a machine type.\nenum MachineType {\n  // TypeUnknown represents undefined node type, when there is no machine configuration yet.\n  TYPE_UNKNOWN = 0;\n  // TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node.\n  // This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc.\n  TYPE_INIT = 1;\n  // TypeControlPlane designates the node as a control plane member.\n  // This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\n  TYPE_CONTROL_PLANE = 2;\n  // TypeWorker designates the node as a worker node.\n  // This means it will be an available compute node for scheduling workloads.\n  TYPE_WORKER = 3;\n}\n\n// NethelpersAddressFlag wraps IFF_* constants.\nenum NethelpersAddressFlag {\n  NETHELPERS_ADDRESSFLAG_UNSPECIFIED = 0;\n  ADDRESS_TEMPORARY = 1;\n  ADDRESS_NO_DAD = 2;\n  ADDRESS_OPTIMISTIC = 4;\n  ADDRESS_DAD_FAILED = 8;\n  ADDRESS_HOME = 16;\n  ADDRESS_DEPRECATED = 32;\n  ADDRESS_TENTATIVE = 64;\n  ADDRESS_PERMANENT = 128;\n  ADDRESS_MANAGEMENT_TEMP = 256;\n  ADDRESS_NO_PREFIX_ROUTE = 512;\n  ADDRESS_MC_AUTO_JOIN = 1024;\n  ADDRESS_STABLE_PRIVACY = 2048;\n}\n\n// NethelpersAddressSortAlgorithm is an internal address sorting algorithm.\nenum NethelpersAddressSortAlgorithm {\n  ADDRESS_SORT_ALGORITHM_V1 = 0;\n  ADDRESS_SORT_ALGORITHM_V2 = 1;\n}\n\n// NethelpersADLACPActive is ADLACPActive.\nenum NethelpersADLACPActive {\n  ADLACP_ACTIVE_OFF = 0;\n  ADLACP_ACTIVE_ON = 1;\n}\n\n// NethelpersADSelect is ADSelect.\nenum NethelpersADSelect {\n  AD_SELECT_STABLE = 0;\n  AD_SELECT_BANDWIDTH = 1;\n  AD_SELECT_COUNT = 2;\n}\n\n// NethelpersARPAllTargets is an ARP targets mode.\nenum NethelpersARPAllTargets {\n  ARP_ALL_TARGETS_ANY = 0;\n  ARP_ALL_TARGETS_ALL = 1;\n}\n\n// NethelpersARPValidate is an ARP Validation mode.\nenum NethelpersARPValidate {\n  ARP_VALIDATE_NONE = 0;\n  ARP_VALIDATE_ACTIVE = 1;\n  ARP_VALIDATE_BACKUP = 2;\n  ARP_VALIDATE_ALL = 3;\n  ARP_VALIDATE_FILTER = 4;\n  ARP_VALIDATE_FILTER_ACTIVE = 5;\n  ARP_VALIDATE_FILTER_BACKUP = 6;\n}\n\n// NethelpersAutoHostnameKind is a kind of automatically generated hostname.\nenum NethelpersAutoHostnameKind {\n  AUTO_HOSTNAME_KIND_OFF = 0;\n  AUTO_HOSTNAME_KIND_ADDR = 1;\n  AUTO_HOSTNAME_KIND_STABLE = 2;\n}\n\n// NethelpersBondMode is a bond mode.\nenum NethelpersBondMode {\n  BOND_MODE_ROUNDROBIN = 0;\n  BOND_MODE_ACTIVE_BACKUP = 1;\n  BOND_MODE_XOR = 2;\n  BOND_MODE_BROADCAST = 3;\n  BOND_MODE8023_AD = 4;\n  BOND_MODE_TLB = 5;\n  BOND_MODE_ALB = 6;\n}\n\n// NethelpersBondXmitHashPolicy is a bond hash policy.\nenum NethelpersBondXmitHashPolicy {\n  BOND_XMIT_POLICY_LAYER2 = 0;\n  BOND_XMIT_POLICY_LAYER34 = 1;\n  BOND_XMIT_POLICY_LAYER23 = 2;\n  BOND_XMIT_POLICY_ENCAP23 = 3;\n  BOND_XMIT_POLICY_ENCAP34 = 4;\n}\n\n// NethelpersClientIdentifier is a DHCP client identifier.\nenum NethelpersClientIdentifier {\n  CLIENT_IDENTIFIER_NONE = 0;\n  CLIENT_IDENTIFIER_MAC = 1;\n  CLIENT_IDENTIFIER_DUID = 2;\n}\n\n// NethelpersConntrackState is a conntrack state.\nenum NethelpersConntrackState {\n  NETHELPERS_CONNTRACKSTATE_UNSPECIFIED = 0;\n  CONNTRACK_STATE_NEW = 8;\n  CONNTRACK_STATE_RELATED = 4;\n  CONNTRACK_STATE_ESTABLISHED = 2;\n  CONNTRACK_STATE_INVALID = 1;\n}\n\n// NethelpersDuplex wraps ethtool.Duplex for YAML marshaling.\nenum NethelpersDuplex {\n  HALF = 0;\n  FULL = 1;\n  UNKNOWN = 255;\n}\n\n// NethelpersFailOverMAC is a MAC failover mode.\nenum NethelpersFailOverMAC {\n  FAIL_OVER_MAC_NONE = 0;\n  FAIL_OVER_MAC_ACTIVE = 1;\n  FAIL_OVER_MAC_FOLLOW = 2;\n}\n\n// NethelpersFamily is a network family.\nenum NethelpersFamily {\n  NETHELPERS_FAMILY_UNSPECIFIED = 0;\n  FAMILY_INET4 = 2;\n  FAMILY_INET6 = 10;\n}\n\n// NethelpersICMPType is a ICMP packet type.\nenum NethelpersICMPType {\n  NETHELPERS_ICMPTYPE_UNSPECIFIED = 0;\n  ICMP_TYPE_TIMESTAMP_REQUEST = 13;\n  ICMP_TYPE_TIMESTAMP_REPLY = 14;\n  ICMP_TYPE_ADDRESS_MASK_REQUEST = 17;\n  ICMP_TYPE_ADDRESS_MASK_REPLY = 18;\n}\n\n// NethelpersLACPRate is a LACP rate.\nenum NethelpersLACPRate {\n  LACP_RATE_SLOW = 0;\n  LACP_RATE_FAST = 1;\n}\n\n// NethelpersLinkType is a link type.\nenum NethelpersLinkType {\n  option allow_alias = true;\n  LINK_NETROM = 0;\n  LINK_ETHER = 1;\n  LINK_EETHER = 2;\n  LINK_AX25 = 3;\n  LINK_PRONET = 4;\n  LINK_CHAOS = 5;\n  LINK_IEE802 = 6;\n  LINK_ARCNET = 7;\n  LINK_ATALK = 8;\n  LINK_DLCI = 15;\n  LINK_ATM = 19;\n  LINK_METRICOM = 23;\n  LINK_IEEE1394 = 24;\n  LINK_EUI64 = 27;\n  LINK_INFINIBAND = 32;\n  LINK_SLIP = 256;\n  LINK_CSLIP = 257;\n  LINK_SLIP6 = 258;\n  LINK_CSLIP6 = 259;\n  LINK_RSRVD = 260;\n  LINK_ADAPT = 264;\n  LINK_ROSE = 270;\n  LINK_X25 = 271;\n  LINK_HWX25 = 272;\n  LINK_CAN = 280;\n  LINK_PPP = 512;\n  LINK_CISCO = 513;\n  LINK_HDLC = 513;\n  LINK_LAPB = 516;\n  LINK_DDCMP = 517;\n  LINK_RAWHDLC = 518;\n  LINK_TUNNEL = 768;\n  LINK_TUNNEL6 = 769;\n  LINK_FRAD = 770;\n  LINK_SKIP = 771;\n  LINK_LOOPBCK = 772;\n  LINK_LOCALTLK = 773;\n  LINK_FDDI = 774;\n  LINK_BIF = 775;\n  LINK_SIT = 776;\n  LINK_IPDDP = 777;\n  LINK_IPGRE = 778;\n  LINK_PIMREG = 779;\n  LINK_HIPPI = 780;\n  LINK_ASH = 781;\n  LINK_ECONET = 782;\n  LINK_IRDA = 783;\n  LINK_FCPP = 784;\n  LINK_FCAL = 785;\n  LINK_FCPL = 786;\n  LINK_FCFABRIC = 787;\n  LINK_FCFABRIC1 = 788;\n  LINK_FCFABRIC2 = 789;\n  LINK_FCFABRIC3 = 790;\n  LINK_FCFABRIC4 = 791;\n  LINK_FCFABRIC5 = 792;\n  LINK_FCFABRIC6 = 793;\n  LINK_FCFABRIC7 = 794;\n  LINK_FCFABRIC8 = 795;\n  LINK_FCFABRIC9 = 796;\n  LINK_FCFABRIC10 = 797;\n  LINK_FCFABRIC11 = 798;\n  LINK_FCFABRIC12 = 799;\n  LINK_IEE802TR = 800;\n  LINK_IEE80211 = 801;\n  LINK_IEE80211PRISM = 802;\n  LINK_IEE80211_RADIOTAP = 803;\n  LINK_IEE8021154 = 804;\n  LINK_IEE8021154MONITOR = 805;\n  LINK_PHONET = 820;\n  LINK_PHONETPIPE = 821;\n  LINK_CAIF = 822;\n  LINK_IP6GRE = 823;\n  LINK_NETLINK = 824;\n  LINK6_LOWPAN = 825;\n  LINK_VOID = 65535;\n  LINK_NONE = 65534;\n}\n\n// NethelpersMatchOperator is a netfilter match operator.\nenum NethelpersMatchOperator {\n  OPERATOR_EQUAL = 0;\n  OPERATOR_NOT_EQUAL = 1;\n}\n\n// NethelpersNfTablesChainHook wraps nftables.ChainHook for YAML marshaling.\nenum NethelpersNfTablesChainHook {\n  CHAIN_HOOK_PREROUTING = 0;\n  CHAIN_HOOK_INPUT = 1;\n  CHAIN_HOOK_FORWARD = 2;\n  CHAIN_HOOK_OUTPUT = 3;\n  CHAIN_HOOK_POSTROUTING = 4;\n}\n\n// NethelpersNfTablesChainPriority wraps nftables.ChainPriority for YAML marshaling.\nenum NethelpersNfTablesChainPriority {\n  option allow_alias = true;\n  NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED = 0;\n  CHAIN_PRIORITY_FIRST = -2147483648;\n  CHAIN_PRIORITY_CONNTRACK_DEFRAG = -400;\n  CHAIN_PRIORITY_RAW = -300;\n  CHAIN_PRIORITY_SE_LINUX_FIRST = -225;\n  CHAIN_PRIORITY_CONNTRACK = -200;\n  CHAIN_PRIORITY_MANGLE = -150;\n  CHAIN_PRIORITY_NAT_DEST = -100;\n  CHAIN_PRIORITY_FILTER = 0;\n  CHAIN_PRIORITY_SECURITY = 50;\n  CHAIN_PRIORITY_NAT_SOURCE = 100;\n  CHAIN_PRIORITY_SE_LINUX_LAST = 225;\n  CHAIN_PRIORITY_CONNTRACK_HELPER = 300;\n  CHAIN_PRIORITY_LAST = 2147483647;\n}\n\n// NethelpersNfTablesVerdict wraps nftables.Verdict for YAML marshaling.\nenum NethelpersNfTablesVerdict {\n  VERDICT_DROP = 0;\n  VERDICT_ACCEPT = 1;\n}\n\n// NethelpersOperationalState wraps rtnetlink.OperationalState for YAML marshaling.\nenum NethelpersOperationalState {\n  OPER_STATE_UNKNOWN = 0;\n  OPER_STATE_NOT_PRESENT = 1;\n  OPER_STATE_DOWN = 2;\n  OPER_STATE_LOWER_LAYER_DOWN = 3;\n  OPER_STATE_TESTING = 4;\n  OPER_STATE_DORMANT = 5;\n  OPER_STATE_UP = 6;\n}\n\n// NethelpersPort wraps ethtool.Port for YAML marshaling.\nenum NethelpersPort {\n  TWISTED_PAIR = 0;\n  AUI = 1;\n  MII = 2;\n  FIBRE = 3;\n  BNC = 4;\n  DIRECT_ATTACH = 5;\n  NONE = 239;\n  OTHER = 255;\n}\n\n// NethelpersPrimaryReselect is an ARP targets mode.\nenum NethelpersPrimaryReselect {\n  PRIMARY_RESELECT_ALWAYS = 0;\n  PRIMARY_RESELECT_BETTER = 1;\n  PRIMARY_RESELECT_FAILURE = 2;\n}\n\n// NethelpersProtocol is a inet protocol.\nenum NethelpersProtocol {\n  NETHELPERS_PROTOCOL_UNSPECIFIED = 0;\n  PROTOCOL_ICMP = 1;\n  PROTOCOL_TCP = 6;\n  PROTOCOL_UDP = 17;\n  PROTOCOL_ICM_PV6 = 58;\n}\n\n// NethelpersRouteFlag wraps RTM_F_* constants.\nenum NethelpersRouteFlag {\n  NETHELPERS_ROUTEFLAG_UNSPECIFIED = 0;\n  ROUTE_NOTIFY = 256;\n  ROUTE_CLONED = 512;\n  ROUTE_EQUALIZE = 1024;\n  ROUTE_PREFIX = 2048;\n  ROUTE_LOOKUP_TABLE = 4096;\n  ROUTE_FIB_MATCH = 8192;\n  ROUTE_OFFLOAD = 16384;\n  ROUTE_TRAP = 32768;\n}\n\n// NethelpersRouteProtocol is a routing protocol.\nenum NethelpersRouteProtocol {\n  PROTOCOL_UNSPEC = 0;\n  PROTOCOL_REDIRECT = 1;\n  PROTOCOL_KERNEL = 2;\n  PROTOCOL_BOOT = 3;\n  PROTOCOL_STATIC = 4;\n  PROTOCOL_RA = 9;\n  PROTOCOL_MRT = 10;\n  PROTOCOL_ZEBRA = 11;\n  PROTOCOL_BIRD = 12;\n  PROTOCOL_DNROUTED = 13;\n  PROTOCOL_XORP = 14;\n  PROTOCOL_NTK = 15;\n  PROTOCOL_DHCP = 16;\n  PROTOCOL_MRTD = 17;\n  PROTOCOL_KEEPALIVED = 18;\n  PROTOCOL_BABEL = 42;\n  PROTOCOL_OPENR = 99;\n  PROTOCOL_BGP = 186;\n  PROTOCOL_ISIS = 187;\n  PROTOCOL_OSPF = 188;\n  PROTOCOL_RIP = 189;\n  PROTOCOL_EIGRP = 192;\n}\n\n// NethelpersRouteType is a route type.\nenum NethelpersRouteType {\n  TYPE_UNSPEC = 0;\n  TYPE_UNICAST = 1;\n  TYPE_LOCAL = 2;\n  TYPE_BROADCAST = 3;\n  TYPE_ANYCAST = 4;\n  TYPE_MULTICAST = 5;\n  TYPE_BLACKHOLE = 6;\n  TYPE_UNREACHABLE = 7;\n  TYPE_PROHIBIT = 8;\n  TYPE_THROW = 9;\n  TYPE_NAT = 10;\n  TYPE_X_RESOLVE = 11;\n}\n\n// NethelpersRoutingRuleAction is a routing rule action.\nenum NethelpersRoutingRuleAction {\n  ROUTING_RULE_ACTION_UNSPEC = 0;\n  ROUTING_RULE_ACTION_UNICAST = 1;\n  ROUTING_RULE_ACTION_BLACKHOLE = 6;\n  ROUTING_RULE_ACTION_UNREACHABLE = 7;\n  ROUTING_RULE_ACTION_PROHIBIT = 8;\n}\n\n// NethelpersRoutingTable is a routing table ID.\nenum NethelpersRoutingTable {\n  TABLE_UNSPEC = 0;\n  TABLE1 = 1;\n  TABLE2 = 2;\n  TABLE3 = 3;\n  TABLE4 = 4;\n  TABLE5 = 5;\n  TABLE6 = 6;\n  TABLE7 = 7;\n  TABLE8 = 8;\n  TABLE9 = 9;\n  TABLE10 = 10;\n  TABLE11 = 11;\n  TABLE12 = 12;\n  TABLE13 = 13;\n  TABLE14 = 14;\n  TABLE15 = 15;\n  TABLE16 = 16;\n  TABLE17 = 17;\n  TABLE18 = 18;\n  TABLE19 = 19;\n  TABLE20 = 20;\n  TABLE21 = 21;\n  TABLE22 = 22;\n  TABLE23 = 23;\n  TABLE24 = 24;\n  TABLE25 = 25;\n  TABLE26 = 26;\n  TABLE27 = 27;\n  TABLE28 = 28;\n  TABLE29 = 29;\n  TABLE30 = 30;\n  TABLE31 = 31;\n  TABLE32 = 32;\n  TABLE33 = 33;\n  TABLE34 = 34;\n  TABLE35 = 35;\n  TABLE36 = 36;\n  TABLE37 = 37;\n  TABLE38 = 38;\n  TABLE39 = 39;\n  TABLE40 = 40;\n  TABLE41 = 41;\n  TABLE42 = 42;\n  TABLE43 = 43;\n  TABLE44 = 44;\n  TABLE45 = 45;\n  TABLE46 = 46;\n  TABLE47 = 47;\n  TABLE48 = 48;\n  TABLE49 = 49;\n  TABLE50 = 50;\n  TABLE51 = 51;\n  TABLE52 = 52;\n  TABLE53 = 53;\n  TABLE54 = 54;\n  TABLE55 = 55;\n  TABLE56 = 56;\n  TABLE57 = 57;\n  TABLE58 = 58;\n  TABLE59 = 59;\n  TABLE60 = 60;\n  TABLE61 = 61;\n  TABLE62 = 62;\n  TABLE63 = 63;\n  TABLE64 = 64;\n  TABLE65 = 65;\n  TABLE66 = 66;\n  TABLE67 = 67;\n  TABLE68 = 68;\n  TABLE69 = 69;\n  TABLE70 = 70;\n  TABLE71 = 71;\n  TABLE72 = 72;\n  TABLE73 = 73;\n  TABLE74 = 74;\n  TABLE75 = 75;\n  TABLE76 = 76;\n  TABLE77 = 77;\n  TABLE78 = 78;\n  TABLE79 = 79;\n  TABLE80 = 80;\n  TABLE81 = 81;\n  TABLE82 = 82;\n  TABLE83 = 83;\n  TABLE84 = 84;\n  TABLE85 = 85;\n  TABLE86 = 86;\n  TABLE87 = 87;\n  TABLE88 = 88;\n  TABLE89 = 89;\n  TABLE90 = 90;\n  TABLE91 = 91;\n  TABLE92 = 92;\n  TABLE93 = 93;\n  TABLE94 = 94;\n  TABLE95 = 95;\n  TABLE96 = 96;\n  TABLE97 = 97;\n  TABLE98 = 98;\n  TABLE99 = 99;\n  TABLE100 = 100;\n  TABLE101 = 101;\n  TABLE102 = 102;\n  TABLE103 = 103;\n  TABLE104 = 104;\n  TABLE105 = 105;\n  TABLE106 = 106;\n  TABLE107 = 107;\n  TABLE108 = 108;\n  TABLE109 = 109;\n  TABLE110 = 110;\n  TABLE111 = 111;\n  TABLE112 = 112;\n  TABLE113 = 113;\n  TABLE114 = 114;\n  TABLE115 = 115;\n  TABLE116 = 116;\n  TABLE117 = 117;\n  TABLE118 = 118;\n  TABLE119 = 119;\n  TABLE120 = 120;\n  TABLE121 = 121;\n  TABLE122 = 122;\n  TABLE123 = 123;\n  TABLE124 = 124;\n  TABLE125 = 125;\n  TABLE126 = 126;\n  TABLE127 = 127;\n  TABLE128 = 128;\n  TABLE129 = 129;\n  TABLE130 = 130;\n  TABLE131 = 131;\n  TABLE132 = 132;\n  TABLE133 = 133;\n  TABLE134 = 134;\n  TABLE135 = 135;\n  TABLE136 = 136;\n  TABLE137 = 137;\n  TABLE138 = 138;\n  TABLE139 = 139;\n  TABLE140 = 140;\n  TABLE141 = 141;\n  TABLE142 = 142;\n  TABLE143 = 143;\n  TABLE144 = 144;\n  TABLE145 = 145;\n  TABLE146 = 146;\n  TABLE147 = 147;\n  TABLE148 = 148;\n  TABLE149 = 149;\n  TABLE150 = 150;\n  TABLE151 = 151;\n  TABLE152 = 152;\n  TABLE153 = 153;\n  TABLE154 = 154;\n  TABLE155 = 155;\n  TABLE156 = 156;\n  TABLE157 = 157;\n  TABLE158 = 158;\n  TABLE159 = 159;\n  TABLE160 = 160;\n  TABLE161 = 161;\n  TABLE162 = 162;\n  TABLE163 = 163;\n  TABLE164 = 164;\n  TABLE165 = 165;\n  TABLE166 = 166;\n  TABLE167 = 167;\n  TABLE168 = 168;\n  TABLE169 = 169;\n  TABLE170 = 170;\n  TABLE171 = 171;\n  TABLE172 = 172;\n  TABLE173 = 173;\n  TABLE174 = 174;\n  TABLE175 = 175;\n  TABLE176 = 176;\n  TABLE177 = 177;\n  TABLE178 = 178;\n  TABLE179 = 179;\n  TABLE180 = 180;\n  TABLE181 = 181;\n  TABLE182 = 182;\n  TABLE183 = 183;\n  TABLE184 = 184;\n  TABLE185 = 185;\n  TABLE186 = 186;\n  TABLE187 = 187;\n  TABLE188 = 188;\n  TABLE189 = 189;\n  TABLE190 = 190;\n  TABLE191 = 191;\n  TABLE192 = 192;\n  TABLE193 = 193;\n  TABLE194 = 194;\n  TABLE195 = 195;\n  TABLE196 = 196;\n  TABLE197 = 197;\n  TABLE198 = 198;\n  TABLE199 = 199;\n  TABLE200 = 200;\n  TABLE201 = 201;\n  TABLE202 = 202;\n  TABLE203 = 203;\n  TABLE204 = 204;\n  TABLE205 = 205;\n  TABLE206 = 206;\n  TABLE207 = 207;\n  TABLE208 = 208;\n  TABLE209 = 209;\n  TABLE210 = 210;\n  TABLE211 = 211;\n  TABLE212 = 212;\n  TABLE213 = 213;\n  TABLE214 = 214;\n  TABLE215 = 215;\n  TABLE216 = 216;\n  TABLE217 = 217;\n  TABLE218 = 218;\n  TABLE219 = 219;\n  TABLE220 = 220;\n  TABLE221 = 221;\n  TABLE222 = 222;\n  TABLE223 = 223;\n  TABLE224 = 224;\n  TABLE225 = 225;\n  TABLE226 = 226;\n  TABLE227 = 227;\n  TABLE228 = 228;\n  TABLE229 = 229;\n  TABLE230 = 230;\n  TABLE231 = 231;\n  TABLE232 = 232;\n  TABLE233 = 233;\n  TABLE234 = 234;\n  TABLE235 = 235;\n  TABLE236 = 236;\n  TABLE237 = 237;\n  TABLE238 = 238;\n  TABLE239 = 239;\n  TABLE240 = 240;\n  TABLE241 = 241;\n  TABLE242 = 242;\n  TABLE243 = 243;\n  TABLE244 = 244;\n  TABLE245 = 245;\n  TABLE246 = 246;\n  TABLE247 = 247;\n  TABLE248 = 248;\n  TABLE249 = 249;\n  TABLE250 = 250;\n  TABLE251 = 251;\n  TABLE252 = 252;\n  TABLE_DEFAULT = 253;\n  TABLE_MAIN = 254;\n  TABLE_LOCAL = 255;\n}\n\n// NethelpersScope is an address scope.\nenum NethelpersScope {\n  SCOPE_GLOBAL = 0;\n  SCOPE_SITE = 200;\n  SCOPE_LINK = 253;\n  SCOPE_HOST = 254;\n  SCOPE_NOWHERE = 255;\n}\n\n// NethelpersVLANProtocol is a VLAN protocol.\nenum NethelpersVLANProtocol {\n  NETHELPERS_VLANPROTOCOL_UNSPECIFIED = 0;\n  VLAN_PROTOCOL8021_Q = 33024;\n  VLAN_PROTOCOL8021_AD = 34984;\n}\n\n// NethelpersWOLMode wraps ethtool.WOLMode for YAML marshaling.\nenum NethelpersWOLMode {\n  NETHELPERS_WOLMODE_UNSPECIFIED = 0;\n  WOL_MODE_PHY = 1;\n  WOL_MODE_UNICAST = 2;\n  WOL_MODE_MULTICAST = 4;\n  WOL_MODE_BROADCAST = 8;\n  WOL_MODE_MAGIC = 32;\n  WOL_MODE_MAGIC_SECURE = 64;\n  WOL_MODE_FILTER = 128;\n}\n\n// BlockEncryptionKeyType describes encryption key type.\nenum BlockEncryptionKeyType {\n  ENCRYPTION_KEY_STATIC = 0;\n  ENCRYPTION_KEY_NODE_ID = 1;\n  ENCRYPTION_KEY_KMS = 2;\n  ENCRYPTION_KEY_TPM = 3;\n}\n\n// BlockEncryptionProviderType describes encryption provider type.\nenum BlockEncryptionProviderType {\n  ENCRYPTION_PROVIDER_NONE = 0;\n  ENCRYPTION_PROVIDER_LUKS2 = 1;\n}\n\n// BlockFilesystemType describes filesystem type.\nenum BlockFilesystemType {\n  FILESYSTEM_TYPE_NONE = 0;\n  FILESYSTEM_TYPE_XFS = 1;\n  FILESYSTEM_TYPE_VFAT = 2;\n  FILESYSTEM_TYPE_EXT4 = 3;\n  FILESYSTEM_TYPE_ISO9660 = 4;\n  FILESYSTEM_TYPE_SWAP = 5;\n  FILESYSTEM_TYPE_VIRTIOFS = 6;\n}\n\n// BlockFSParameterType describes Filesystem Parameter type.\nenum BlockFSParameterType {\n  FS_PARAMETER_TYPE_STRING_VALUE = 0;\n  FS_PARAMETER_TYPE_BOOLEAN_VALUE = 1;\n  FS_PARAMETER_TYPE_BINARY_VALUE = 2;\n}\n\n// BlockVolumePhase describes volume phase.\nenum BlockVolumePhase {\n  VOLUME_PHASE_WAITING = 0;\n  VOLUME_PHASE_FAILED = 1;\n  VOLUME_PHASE_MISSING = 2;\n  VOLUME_PHASE_LOCATED = 3;\n  VOLUME_PHASE_PROVISIONED = 4;\n  VOLUME_PHASE_PREPARED = 5;\n  VOLUME_PHASE_READY = 6;\n  VOLUME_PHASE_CLOSED = 7;\n}\n\n// BlockVolumeType describes volume type.\nenum BlockVolumeType {\n  VOLUME_TYPE_PARTITION = 0;\n  VOLUME_TYPE_DISK = 1;\n  VOLUME_TYPE_TMPFS = 2;\n  VOLUME_TYPE_DIRECTORY = 3;\n  VOLUME_TYPE_SYMLINK = 4;\n  VOLUME_TYPE_OVERLAY = 5;\n  VOLUME_TYPE_EXTERNAL = 6;\n}\n\n// CriImageCacheStatus describes image cache status type.\nenum CriImageCacheStatus {\n  IMAGE_CACHE_STATUS_UNKNOWN = 0;\n  IMAGE_CACHE_STATUS_DISABLED = 1;\n  IMAGE_CACHE_STATUS_PREPARING = 2;\n  IMAGE_CACHE_STATUS_READY = 3;\n}\n\n// CriImageCacheCopyStatus describes image cache copy status type.\nenum CriImageCacheCopyStatus {\n  IMAGE_CACHE_COPY_STATUS_UNKNOWN = 0;\n  IMAGE_CACHE_COPY_STATUS_SKIPPED = 1;\n  IMAGE_CACHE_COPY_STATUS_PENDING = 2;\n  IMAGE_CACHE_COPY_STATUS_READY = 3;\n}\n\n// KubespanPeerState is KubeSpan peer current state.\nenum KubespanPeerState {\n  PEER_STATE_UNKNOWN = 0;\n  PEER_STATE_UP = 1;\n  PEER_STATE_DOWN = 2;\n}\n\n// NetworkConfigLayer describes network configuration layers, with lowest priority first.\nenum NetworkConfigLayer {\n  CONFIG_DEFAULT = 0;\n  CONFIG_CMDLINE = 1;\n  CONFIG_PLATFORM = 2;\n  CONFIG_OPERATOR = 3;\n  CONFIG_MACHINE_CONFIGURATION = 4;\n}\n\n// NetworkOperator enumerates Talos network operators.\nenum NetworkOperator {\n  OPERATOR_DHCP4 = 0;\n  OPERATOR_DHCP6 = 1;\n  OPERATOR_VIP = 2;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/etcd/etcd.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.etcd;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/etcd\";\noption java_package = \"dev.talos.api.resource.definitions.etcd\";\n\nimport \"common/common.proto\";\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\nmessage ArgValues {\n  repeated string values = 1;\n}\n\n// ConfigSpec describes (some) configuration settings of etcd.\nmessage ConfigSpec {\n  repeated string advertise_valid_subnets = 1;\n  repeated string advertise_exclude_subnets = 2;\n  string image = 3;\n  map<string, ArgValues> extra_args = 4;\n  repeated string listen_valid_subnets = 5;\n  repeated string listen_exclude_subnets = 6;\n}\n\n// MemberSpec holds information about an etcd member.\nmessage MemberSpec {\n  string member_id = 1;\n}\n\n// PKIStatusSpec describes status of rendered secrets.\nmessage PKIStatusSpec {\n  bool ready = 1;\n  string version = 2;\n}\n\n// SpecSpec describes (some) Specuration settings of etcd.\nmessage SpecSpec {\n  string name = 1;\n  repeated common.NetIP advertised_addresses = 2;\n  string image = 3;\n  map<string, ArgValues> extra_args = 4;\n  repeated common.NetIP listen_peer_addresses = 5;\n  repeated common.NetIP listen_client_addresses = 6;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/extensions/extensions.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.extensions;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/extensions\";\noption java_package = \"dev.talos.api.resource.definitions.extensions\";\n\n// Compatibility describes extension compatibility.\nmessage Compatibility {\n  Constraint talos = 1;\n}\n\n// Constraint describes compatibility constraint.\nmessage Constraint {\n  string version = 1;\n}\n\n// Layer defines overlay mount layer.\nmessage Layer {\n  string image = 1;\n  Metadata metadata = 2;\n}\n\n// Metadata describes base extension metadata.\nmessage Metadata {\n  string name = 1;\n  string version = 2;\n  string author = 3;\n  string description = 4;\n  Compatibility compatibility = 5;\n  string extra_info = 6;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/files/files.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.files;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/files\";\noption java_package = \"dev.talos.api.resource.definitions.files\";\n\n// EtcFileSpecSpec describes status of rendered secrets.\nmessage EtcFileSpecSpec {\n  bytes contents = 1;\n  uint32 mode = 2;\n  string selinux_label = 3;\n}\n\n// EtcFileStatusSpec describes status of rendered secrets.\nmessage EtcFileStatusSpec {\n  string spec_version = 1;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/hardware/hardware.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.hardware;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/hardware\";\noption java_package = \"dev.talos.api.resource.definitions.hardware\";\n\n// MemoryModuleSpec represents a single Memory.\nmessage MemoryModuleSpec {\n  uint32 size = 1;\n  string device_locator = 2;\n  string bank_locator = 3;\n  uint32 speed = 4;\n  string manufacturer = 5;\n  string serial_number = 6;\n  string asset_tag = 7;\n  string product_name = 8;\n}\n\n// PCIDeviceSpec represents a single processor.\nmessage PCIDeviceSpec {\n  string class = 1;\n  string subclass = 2;\n  string vendor = 3;\n  string product = 4;\n  string class_id = 5;\n  string subclass_id = 6;\n  string vendor_id = 7;\n  string product_id = 8;\n  string driver = 9;\n}\n\n// PCIDriverRebindConfigSpec describes PCI rebind configuration.\nmessage PCIDriverRebindConfigSpec {\n  string pciid = 1;\n  string target_driver = 2;\n}\n\n// PCIDriverRebindStatusSpec describes status of rebinded drivers.\nmessage PCIDriverRebindStatusSpec {\n  string pciid = 1;\n  string target_driver = 2;\n}\n\n// ProcessorSpec represents a single processor.\nmessage ProcessorSpec {\n  string socket = 1;\n  string manufacturer = 2;\n  string product_name = 3;\n  uint32 max_speed = 4;\n  uint32 boot_speed = 5;\n  uint32 status = 6;\n  string serial_number = 7;\n  string asset_tag = 8;\n  string part_number = 9;\n  uint32 core_count = 10;\n  uint32 core_enabled = 11;\n  uint32 thread_count = 12;\n}\n\n// SystemInformationSpec represents the system information obtained from smbios.\nmessage SystemInformationSpec {\n  string manufacturer = 1;\n  string product_name = 2;\n  string version = 3;\n  string serial_number = 4;\n  string uuid = 5;\n  string wake_up_type = 6;\n  string sku_number = 7;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/k8s/k8s.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.k8s;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/k8s\";\noption java_package = \"dev.talos.api.resource.definitions.k8s\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/struct.proto\";\nimport \"resource/definitions/proto/proto.proto\";\n\n// APIServerConfigSpec is configuration for kube-apiserver.\nmessage APIServerConfigSpec {\n  string image = 1;\n  string cloud_provider = 2;\n  string control_plane_endpoint = 3;\n  repeated string etcd_servers = 4;\n  int64 local_port = 5;\n  repeated string service_cid_rs = 6;\n  map<string, ArgValues> extra_args = 7;\n  repeated ExtraVolume extra_volumes = 8;\n  map<string, string> environment_variables = 9;\n  string advertised_address = 11;\n  Resources resources = 12;\n}\n\n// AdmissionControlConfigSpec is configuration for kube-apiserver.\nmessage AdmissionControlConfigSpec {\n  repeated AdmissionPluginSpec config = 1;\n}\n\n// AdmissionPluginSpec is a single admission plugin configuration Admission Control plugins.\nmessage AdmissionPluginSpec {\n  string name = 1;\n  google.protobuf.Struct configuration = 2;\n}\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\nmessage ArgValues {\n  repeated string values = 1;\n}\n\n// AuditPolicyConfigSpec is audit policy configuration for kube-apiserver.\nmessage AuditPolicyConfigSpec {\n  google.protobuf.Struct config = 1;\n}\n\n// AuthorizationAuthorizersSpec is a configuration of authorization authorizers.\nmessage AuthorizationAuthorizersSpec {\n  string type = 1;\n  string name = 2;\n  google.protobuf.Struct webhook = 3;\n}\n\n// AuthorizationConfigSpec is authorization configuration for kube-apiserver.\nmessage AuthorizationConfigSpec {\n  string image = 1;\n  repeated AuthorizationAuthorizersSpec config = 2;\n}\n\n// BootstrapManifestsConfigSpec is configuration for bootstrap manifests.\nmessage BootstrapManifestsConfigSpec {\n  string server = 1;\n  string cluster_domain = 2;\n  repeated string pod_cid_rs = 3;\n  bool proxy_enabled = 4;\n  string proxy_image = 5;\n  repeated string proxy_args = 6;\n  bool core_dns_enabled = 7;\n  string core_dns_image = 8;\n  string dns_service_ip = 9;\n  string dns_service_i_pv6 = 10;\n  bool flannel_enabled = 11;\n  string flannel_image = 12;\n  bool pod_security_policy_enabled = 14;\n  bool talos_api_service_enabled = 15;\n  repeated string flannel_extra_args = 16;\n  string flannel_kube_service_host = 17;\n  string flannel_kube_service_port = 18;\n  bool flannel_kube_network_policies_enabled = 19;\n  string flannel_kube_network_policies_image = 20;\n  string cni_name = 21;\n}\n\n// ConfigStatusSpec describes status of rendered secrets.\nmessage ConfigStatusSpec {\n  bool ready = 1;\n  string version = 2;\n}\n\n// ControllerManagerConfigSpec is configuration for kube-controller-manager.\nmessage ControllerManagerConfigSpec {\n  bool enabled = 1;\n  string image = 2;\n  string cloud_provider = 3;\n  repeated string pod_cid_rs = 4;\n  repeated string service_cid_rs = 5;\n  map<string, ArgValues> extra_args = 6;\n  repeated ExtraVolume extra_volumes = 7;\n  map<string, string> environment_variables = 8;\n  Resources resources = 9;\n}\n\n// EndpointSpec describes a list of endpoints to connect to.\nmessage EndpointSpec {\n  repeated common.NetIP addresses = 1;\n  repeated string hosts = 2;\n}\n\n// ExtraManifest defines a single extra manifest to download.\nmessage ExtraManifest {\n  string name = 1;\n  string url = 2;\n  string priority = 3;\n  map<string, string> extra_headers = 4;\n  string inline_manifest = 5;\n}\n\n// ExtraManifestsConfigSpec is configuration for extra bootstrap manifests.\nmessage ExtraManifestsConfigSpec {\n  repeated ExtraManifest extra_manifests = 1;\n}\n\n// ExtraVolume is a configuration of extra volume.\nmessage ExtraVolume {\n  string name = 1;\n  string host_path = 2;\n  string mount_path = 3;\n  bool read_only = 4;\n}\n\n// KubePrismConfigSpec describes KubePrismConfig data.\nmessage KubePrismConfigSpec {\n  string host = 1;\n  int64 port = 2;\n  repeated KubePrismEndpoint endpoints = 3;\n}\n\n// KubePrismEndpoint holds data for control plane endpoint.\nmessage KubePrismEndpoint {\n  string host = 1;\n  uint32 port = 2;\n}\n\n// KubePrismEndpointsSpec describes KubePrismEndpoints configuration.\nmessage KubePrismEndpointsSpec {\n  repeated KubePrismEndpoint endpoints = 1;\n}\n\n// KubePrismStatusesSpec describes KubePrismStatuses data.\nmessage KubePrismStatusesSpec {\n  string host = 1;\n  bool healthy = 2;\n}\n\n// KubeletConfigSpec holds the source of kubelet configuration.\nmessage KubeletConfigSpec {\n  string image = 1;\n  repeated string cluster_dns = 2;\n  string cluster_domain = 3;\n  map<string, ArgValues> extra_args = 4;\n  repeated talos.resource.definitions.proto.Mount extra_mounts = 5;\n  google.protobuf.Struct extra_config = 6;\n  bool cloud_provider_external = 7;\n  bool default_runtime_seccomp_enabled = 8;\n  bool skip_node_registration = 9;\n  string static_pod_list_url = 10;\n  bool disable_manifests_directory = 11;\n  bool enable_fs_quota_monitoring = 12;\n  google.protobuf.Struct credential_provider_config = 13;\n  bool allow_scheduling_on_control_plane = 14;\n}\n\n// KubeletSpecSpec holds the source of kubelet configuration.\nmessage KubeletSpecSpec {\n  string image = 1;\n  repeated string args = 2;\n  repeated talos.resource.definitions.proto.Mount extra_mounts = 3;\n  string expected_nodename = 4;\n  google.protobuf.Struct config = 5;\n  google.protobuf.Struct credential_provider_config = 6;\n}\n\n// ManifestSpec holds the Kubernetes resources spec.\nmessage ManifestSpec {\n  repeated SingleManifest items = 1;\n}\n\n// ManifestStatusSpec describes manifest application status.\nmessage ManifestStatusSpec {\n  repeated string manifests_applied = 1;\n}\n\n// NodeAnnotationSpecSpec represents an annoation that's attached to a Talos node.\nmessage NodeAnnotationSpecSpec {\n  string key = 1;\n  string value = 2;\n}\n\n// NodeIPConfigSpec holds the Node IP specification.\nmessage NodeIPConfigSpec {\n  repeated string valid_subnets = 1;\n  repeated string exclude_subnets = 2;\n}\n\n// NodeIPSpec holds the Node IP specification.\nmessage NodeIPSpec {\n  repeated common.NetIP addresses = 1;\n}\n\n// NodeLabelSpecSpec represents a label that's attached to a Talos node.\nmessage NodeLabelSpecSpec {\n  string key = 1;\n  string value = 2;\n}\n\n// NodeStatusSpec describes Kubernetes NodeStatus.\nmessage NodeStatusSpec {\n  string nodename = 1;\n  bool node_ready = 2;\n  bool unschedulable = 3;\n  map<string, string> labels = 4;\n  map<string, string> annotations = 5;\n  repeated common.NetIPPrefix pod_cid_rs = 6;\n}\n\n// NodeTaintSpecSpec represents a label that's attached to a Talos node.\nmessage NodeTaintSpecSpec {\n  string key = 1;\n  string effect = 2;\n  string value = 3;\n}\n\n// NodenameSpec describes Kubernetes nodename.\nmessage NodenameSpec {\n  string nodename = 1;\n  string hostname_version = 2;\n  bool skip_node_registration = 3;\n}\n\n// Resources is a configuration of cpu and memory resources.\nmessage Resources {\n  map<string, string> requests = 1;\n  map<string, string> limits = 2;\n}\n\n// SchedulerConfigSpec is configuration for kube-scheduler.\nmessage SchedulerConfigSpec {\n  bool enabled = 1;\n  string image = 2;\n  map<string, ArgValues> extra_args = 3;\n  repeated ExtraVolume extra_volumes = 4;\n  map<string, string> environment_variables = 5;\n  Resources resources = 6;\n  google.protobuf.Struct config = 7;\n}\n\n// SecretsStatusSpec describes status of rendered secrets.\nmessage SecretsStatusSpec {\n  bool ready = 1;\n  string version = 2;\n}\n\n// SingleManifest is a single manifest.\nmessage SingleManifest {\n  google.protobuf.Struct object = 1;\n}\n\n// StaticPodServerStatusSpec describes static pod spec, it contains marshaled *v1.Pod spec.\nmessage StaticPodServerStatusSpec {\n  string url = 1;\n}\n\n// StaticPodSpec describes static pod spec, it contains marshaled *v1.Pod spec.\nmessage StaticPodSpec {\n  google.protobuf.Struct pod = 1;\n}\n\n// StaticPodStatusSpec describes kubelet static pod status.\nmessage StaticPodStatusSpec {\n  google.protobuf.Struct pod_status = 1;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/kubeaccess/kubeaccess.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.kubeaccess;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/kubeaccess\";\noption java_package = \"dev.talos.api.resource.definitions.kubeaccess\";\n\n// ConfigSpec describes KubeSpan configuration..\nmessage ConfigSpec {\n  bool enabled = 1;\n  repeated string allowed_api_roles = 2;\n  repeated string allowed_kubernetes_namespaces = 3;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/kubespan/kubespan.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.kubespan;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/kubespan\";\noption java_package = \"dev.talos.api.resource.definitions.kubespan\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/timestamp.proto\";\nimport \"resource/definitions/enums/enums.proto\";\n\n// ConfigSpec describes KubeSpan configuration..\nmessage ConfigSpec {\n  bool enabled = 1;\n  string cluster_id = 2;\n  string shared_secret = 3;\n  bool force_routing = 4;\n  bool advertise_kubernetes_networks = 5;\n  uint32 mtu = 6;\n  repeated string endpoint_filters = 7;\n  bool harvest_extra_endpoints = 8;\n  repeated common.NetIPPort extra_endpoints = 9;\n  repeated common.NetIPPrefix exclude_advertised_networks = 10;\n}\n\n// EndpointSpec describes Endpoint state.\nmessage EndpointSpec {\n  string affiliate_id = 1;\n  common.NetIPPort endpoint = 2;\n}\n\n// IdentitySpec describes KubeSpan keys and address.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\nmessage IdentitySpec {\n  common.NetIPPrefix address = 1;\n  common.NetIPPrefix subnet = 2;\n  string private_key = 3;\n  string public_key = 4;\n}\n\n// PeerSpecSpec describes PeerSpec state.\nmessage PeerSpecSpec {\n  common.NetIP address = 1;\n  repeated common.NetIPPrefix allowed_ips = 2;\n  repeated common.NetIPPort endpoints = 3;\n  string label = 4;\n}\n\n// PeerStatusSpec describes PeerStatus state.\nmessage PeerStatusSpec {\n  common.NetIPPort endpoint = 1;\n  string label = 2;\n  talos.resource.definitions.enums.KubespanPeerState state = 3;\n  int64 receive_bytes = 4;\n  int64 transmit_bytes = 5;\n  google.protobuf.Timestamp last_handshake_time = 6;\n  common.NetIPPort last_used_endpoint = 7;\n  google.protobuf.Timestamp last_endpoint_change = 8;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/network/network.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.network;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network\";\noption java_package = \"dev.talos.api.resource.definitions.network\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"resource/definitions/enums/enums.proto\";\nimport \"resource/definitions/runtime/runtime.proto\";\n\n// AddressSpecSpec describes status of rendered secrets.\nmessage AddressSpecSpec {\n  common.NetIPPrefix address = 1;\n  string link_name = 2;\n  talos.resource.definitions.enums.NethelpersFamily family = 3;\n  talos.resource.definitions.enums.NethelpersScope scope = 4;\n  uint32 flags = 5;\n  bool announce_with_arp = 6;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 7;\n  uint32 priority = 8;\n}\n\n// AddressStatusSpec describes status of rendered secrets.\nmessage AddressStatusSpec {\n  common.NetIPPrefix address = 1;\n  common.NetIP local = 2;\n  common.NetIP broadcast = 3;\n  common.NetIP anycast = 4;\n  common.NetIP multicast = 5;\n  uint32 link_index = 6;\n  string link_name = 7;\n  talos.resource.definitions.enums.NethelpersFamily family = 8;\n  talos.resource.definitions.enums.NethelpersScope scope = 9;\n  uint32 flags = 10;\n  uint32 priority = 11;\n}\n\n// BondMasterSpec describes bond settings if Kind == \"bond\".\nmessage BondMasterSpec {\n  talos.resource.definitions.enums.NethelpersBondMode mode = 1;\n  talos.resource.definitions.enums.NethelpersBondXmitHashPolicy hash_policy = 2;\n  talos.resource.definitions.enums.NethelpersLACPRate lacp_rate = 3;\n  talos.resource.definitions.enums.NethelpersARPValidate arp_validate = 4;\n  talos.resource.definitions.enums.NethelpersARPAllTargets arp_all_targets = 5;\n  uint32 primary_index = 6;\n  talos.resource.definitions.enums.NethelpersPrimaryReselect primary_reselect = 7;\n  talos.resource.definitions.enums.NethelpersFailOverMAC fail_over_mac = 8;\n  talos.resource.definitions.enums.NethelpersADSelect ad_select = 9;\n  uint32 mii_mon = 10;\n  uint32 up_delay = 11;\n  uint32 down_delay = 12;\n  uint32 arp_interval = 13;\n  uint32 resend_igmp = 14;\n  uint32 min_links = 15;\n  uint32 lp_interval = 16;\n  uint32 packets_per_slave = 17;\n  uint32 num_peer_notif = 18;\n  uint32 tlb_dynamic_lb = 19;\n  uint32 all_slaves_active = 20;\n  bool use_carrier = 21;\n  uint32 ad_actor_sys_prio = 22;\n  uint32 ad_user_port_key = 23;\n  uint32 peer_notify_delay = 24;\n  repeated common.NetIP arpip_targets = 25;\n  repeated common.NetIP nsip6_targets = 26;\n  talos.resource.definitions.enums.NethelpersADLACPActive adlacp_active = 27;\n  uint32 missed_max = 28;\n}\n\n// BondSlave contains a bond's master name and slave index.\nmessage BondSlave {\n  string master_name = 1;\n  int64 slave_index = 2;\n}\n\n// BridgeMasterSpec describes bridge settings if Kind == \"bridge\".\nmessage BridgeMasterSpec {\n  STPSpec stp = 1;\n  BridgeVLANSpec vlan = 2;\n}\n\n// BridgeSlave contains the name of the master bridge of a bridged interface\nmessage BridgeSlave {\n  string master_name = 1;\n}\n\n// BridgeVLANSpec describes VLAN settings of a bridge.\nmessage BridgeVLANSpec {\n  bool filtering_enabled = 1;\n}\n\n// ClientIdentifierSpec is a shared DHCP4/DHCP6 client identifier spec.\nmessage ClientIdentifierSpec {\n  talos.resource.definitions.enums.NethelpersClientIdentifier client_identifier = 1;\n  string duid_raw_hex = 2;\n}\n\n// DHCP4OperatorSpec describes DHCP4 operator options.\nmessage DHCP4OperatorSpec {\n  uint32 route_metric = 1;\n  bool skip_hostname_request = 2;\n  ClientIdentifierSpec client_identifier = 3;\n}\n\n// DHCP6OperatorSpec describes DHCP6 operator options.\nmessage DHCP6OperatorSpec {\n  uint32 route_metric = 2;\n  bool skip_hostname_request = 3;\n  ClientIdentifierSpec client_identifier = 4;\n}\n\n// DNSResolveCacheSpec describes DNS servers status.\nmessage DNSResolveCacheSpec {\n  string status = 1;\n}\n\n// EthernetChannelsSpec describes config of Ethernet channels.\nmessage EthernetChannelsSpec {\n  uint32 rx = 1;\n  uint32 tx = 2;\n  uint32 other = 3;\n  uint32 combined = 4;\n}\n\n// EthernetChannelsStatus describes status of Ethernet channels.\nmessage EthernetChannelsStatus {\n  uint32 rx_max = 1;\n  uint32 tx_max = 2;\n  uint32 other_max = 3;\n  uint32 combined_max = 4;\n  uint32 rx = 5;\n  uint32 tx = 6;\n  uint32 other = 7;\n  uint32 combined = 8;\n}\n\n// EthernetFeatureStatus describes status of Ethernet features.\nmessage EthernetFeatureStatus {\n  string name = 1;\n  string status = 2;\n}\n\n// EthernetRingsSpec describes config of Ethernet rings.\nmessage EthernetRingsSpec {\n  uint32 rx = 1;\n  uint32 rx_mini = 2;\n  uint32 rx_jumbo = 3;\n  uint32 tx = 4;\n  uint32 rx_buf_len = 5;\n  uint32 cqe_size = 6;\n  bool tx_push = 7;\n  bool rx_push = 8;\n  uint32 tx_push_buf_len = 9;\n  bool tcp_data_split = 10;\n}\n\n// EthernetRingsStatus describes status of Ethernet rings.\nmessage EthernetRingsStatus {\n  uint32 rx_max = 1;\n  uint32 rx_mini_max = 2;\n  uint32 rx_jumbo_max = 3;\n  uint32 tx_max = 4;\n  uint32 tx_push_buf_len_max = 5;\n  uint32 rx = 6;\n  uint32 rx_mini = 7;\n  uint32 rx_jumbo = 8;\n  uint32 tx = 9;\n  uint32 rx_buf_len = 10;\n  uint32 cqe_size = 11;\n  bool tx_push = 12;\n  bool rx_push = 13;\n  uint32 tx_push_buf_len = 14;\n  bool tcp_data_split = 15;\n}\n\n// EthernetSpecSpec describes config of Ethernet link.\nmessage EthernetSpecSpec {\n  EthernetRingsSpec rings = 1;\n  map<string, bool> features = 2;\n  EthernetChannelsSpec channels = 3;\n  repeated talos.resource.definitions.enums.NethelpersWOLMode wake_on_lan = 4;\n}\n\n// EthernetStatusSpec describes status of rendered secrets.\nmessage EthernetStatusSpec {\n  bool link_state = 1;\n  int64 speed_megabits = 2;\n  talos.resource.definitions.enums.NethelpersPort port = 3;\n  talos.resource.definitions.enums.NethelpersDuplex duplex = 4;\n  repeated string our_modes = 5;\n  repeated string peer_modes = 6;\n  EthernetRingsStatus rings = 7;\n  repeated EthernetFeatureStatus features = 8;\n  EthernetChannelsStatus channels = 9;\n  repeated talos.resource.definitions.enums.NethelpersWOLMode wake_on_lan = 10;\n}\n\n// HardwareAddrSpec describes spec for the link.\nmessage HardwareAddrSpec {\n  string name = 1;\n  bytes hardware_addr = 2;\n}\n\n// HostDNSConfigSpec describes host DNS config.\nmessage HostDNSConfigSpec {\n  bool enabled = 1;\n  repeated common.NetIPPort listen_addresses = 2;\n  common.NetIP service_host_dns_address = 3;\n  bool resolve_member_names = 4;\n}\n\n// HostnameSpecSpec describes node hostname.\nmessage HostnameSpecSpec {\n  string hostname = 1;\n  string domainname = 2;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 3;\n}\n\n// HostnameStatusSpec describes node hostname.\nmessage HostnameStatusSpec {\n  string hostname = 1;\n  string domainname = 2;\n}\n\n// LinkAliasSpecSpec describes status of rendered secrets.\nmessage LinkAliasSpecSpec {\n  string alias = 1;\n}\n\n// LinkRefreshSpec describes status of rendered secrets.\nmessage LinkRefreshSpec {\n  int64 generation = 1;\n}\n\n// LinkSpecSpec describes spec for the link.\nmessage LinkSpecSpec {\n  string name = 1;\n  bool logical = 2;\n  bool up = 3;\n  uint32 mtu = 4;\n  string kind = 5;\n  talos.resource.definitions.enums.NethelpersLinkType type = 6;\n  string parent_name = 7;\n  BondSlave bond_slave = 8;\n  BridgeSlave bridge_slave = 9;\n  VLANSpec vlan = 10;\n  BondMasterSpec bond_master = 11;\n  BridgeMasterSpec bridge_master = 12;\n  WireguardSpec wireguard = 13;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 14;\n  bytes hardware_address = 15;\n  bool multicast = 16;\n  VRFMasterSpec vrf_master = 17;\n  VRFSlave vrf_slave = 18;\n}\n\n// LinkStatusSpec describes status of rendered secrets.\nmessage LinkStatusSpec {\n  uint32 index = 1;\n  talos.resource.definitions.enums.NethelpersLinkType type = 2;\n  uint32 link_index = 3;\n  uint32 flags = 4;\n  bytes hardware_addr = 5;\n  bytes broadcast_addr = 6;\n  uint32 mtu = 7;\n  string queue_disc = 8;\n  uint32 master_index = 9;\n  talos.resource.definitions.enums.NethelpersOperationalState operational_state = 10;\n  string kind = 11;\n  string slave_kind = 12;\n  string bus_path = 13;\n  string pciid = 14;\n  string driver = 15;\n  string driver_version = 16;\n  string firmware_version = 17;\n  string product_id = 18;\n  string vendor_id = 19;\n  string product = 20;\n  string vendor = 21;\n  bool link_state = 22;\n  int64 speed_megabits = 23;\n  talos.resource.definitions.enums.NethelpersPort port = 24;\n  talos.resource.definitions.enums.NethelpersDuplex duplex = 25;\n  VLANSpec vlan = 26;\n  BridgeMasterSpec bridge_master = 27;\n  BondMasterSpec bond_master = 28;\n  WireguardSpec wireguard = 29;\n  bytes permanent_addr = 30;\n  string alias = 31;\n  repeated string alt_names = 32;\n  VRFMasterSpec vrf_master = 33;\n}\n\n// NfTablesAddressMatch describes the match on the IP address.\nmessage NfTablesAddressMatch {\n  repeated common.NetIPPrefix include_subnets = 1;\n  repeated common.NetIPPrefix exclude_subnets = 2;\n  bool invert = 3;\n}\n\n// NfTablesChainSpec describes status of rendered secrets.\nmessage NfTablesChainSpec {\n  string type = 1;\n  talos.resource.definitions.enums.NethelpersNfTablesChainHook hook = 2;\n  talos.resource.definitions.enums.NethelpersNfTablesChainPriority priority = 3;\n  repeated NfTablesRule rules = 4;\n  talos.resource.definitions.enums.NethelpersNfTablesVerdict policy = 5;\n}\n\n// NfTablesClampMSS describes the TCP MSS clamping operation.\n//\n// MSS is limited by the `MaxMTU` so that:\n// - IPv4: MSS = MaxMTU - 40\n// - IPv6: MSS = MaxMTU - 60.\nmessage NfTablesClampMSS {\n  uint32 mtu = 1;\n}\n\n// NfTablesConntrackStateMatch describes the match on the connection tracking state.\nmessage NfTablesConntrackStateMatch {\n  repeated talos.resource.definitions.enums.NethelpersConntrackState states = 1;\n}\n\n// NfTablesICMPTypeMatch describes the match on the ICMP type.\nmessage NfTablesICMPTypeMatch {\n  repeated talos.resource.definitions.enums.NethelpersICMPType types = 1;\n}\n\n// NfTablesIfNameMatch describes the match on the interface name.\nmessage NfTablesIfNameMatch {\n  talos.resource.definitions.enums.NethelpersMatchOperator operator = 2;\n  repeated string interface_names = 3;\n}\n\n// NfTablesLayer4Match describes the match on the transport layer protocol.\nmessage NfTablesLayer4Match {\n  talos.resource.definitions.enums.NethelpersProtocol protocol = 1;\n  NfTablesPortMatch match_source_port = 2;\n  NfTablesPortMatch match_destination_port = 3;\n  NfTablesICMPTypeMatch match_icmp_type = 4;\n}\n\n// NfTablesLimitMatch describes the match on the packet rate.\nmessage NfTablesLimitMatch {\n  uint64 packet_rate_per_second = 1;\n}\n\n// NfTablesMark encodes packet mark match/update operation.\n//\n// When used as a match computes the following condition:\n// (mark & mask) ^ xor == value\n//\n// When used as an update computes the following operation:\n// mark = (mark & mask) ^ xor.\nmessage NfTablesMark {\n  uint32 mask = 1;\n  uint32 xor = 2;\n  uint32 value = 3;\n}\n\n// NfTablesPortMatch describes the match on the transport layer port.\nmessage NfTablesPortMatch {\n  repeated PortRange ranges = 1;\n}\n\n// NfTablesRule describes a single rule in the nftables chain.\nmessage NfTablesRule {\n  NfTablesIfNameMatch match_o_if_name = 1;\n  talos.resource.definitions.enums.NethelpersNfTablesVerdict verdict = 2;\n  NfTablesMark match_mark = 3;\n  NfTablesMark set_mark = 4;\n  NfTablesAddressMatch match_source_address = 5;\n  NfTablesAddressMatch match_destination_address = 6;\n  NfTablesLayer4Match match_layer4 = 7;\n  NfTablesIfNameMatch match_i_if_name = 8;\n  NfTablesClampMSS clamp_mss = 9;\n  NfTablesLimitMatch match_limit = 10;\n  NfTablesConntrackStateMatch match_conntrack_state = 11;\n  bool anon_counter = 12;\n}\n\n// NodeAddressFilterSpec describes a filter for NodeAddresses.\nmessage NodeAddressFilterSpec {\n  repeated common.NetIPPrefix include_subnets = 1;\n  repeated common.NetIPPrefix exclude_subnets = 2;\n}\n\n// NodeAddressSortAlgorithmSpec describes a filter for NodeAddresses.\nmessage NodeAddressSortAlgorithmSpec {\n  talos.resource.definitions.enums.NethelpersAddressSortAlgorithm algorithm = 1;\n}\n\n// NodeAddressSpec describes a set of node addresses.\nmessage NodeAddressSpec {\n  repeated common.NetIPPrefix addresses = 1;\n  talos.resource.definitions.enums.NethelpersAddressSortAlgorithm sort_algorithm = 2;\n}\n\n// OperatorSpecSpec describes operator specification.\nmessage OperatorSpecSpec {\n  talos.resource.definitions.enums.NetworkOperator operator = 1;\n  string link_name = 2;\n  bool require_up = 3;\n  DHCP4OperatorSpec dhcp4 = 4;\n  DHCP6OperatorSpec dhcp6 = 5;\n  VIPOperatorSpec vip = 6;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 7;\n}\n\n// PlatformConfigSpec describes platform network configuration.\n//\n// This structure is marshaled to STATE partition to persist cached network configuration across\n// reboots.\nmessage PlatformConfigSpec {\n  repeated AddressSpecSpec addresses = 1;\n  repeated LinkSpecSpec links = 2;\n  repeated RouteSpecSpec routes = 3;\n  repeated HostnameSpecSpec hostnames = 4;\n  repeated ResolverSpecSpec resolvers = 5;\n  repeated TimeServerSpecSpec time_servers = 6;\n  repeated OperatorSpecSpec operators = 7;\n  repeated common.NetIP external_ips = 8;\n  repeated ProbeSpecSpec probes = 9;\n  talos.resource.definitions.runtime.PlatformMetadataSpec metadata = 10;\n}\n\n// PortRange describes a range of ports.\n//\n// Range is [lo, hi].\nmessage PortRange {\n  uint32 lo = 1;\n  uint32 hi = 2;\n}\n\n// ProbeSpecSpec describes the Probe.\nmessage ProbeSpecSpec {\n  google.protobuf.Duration interval = 1;\n  int64 failure_threshold = 2;\n  TCPProbeSpec tcp = 3;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 4;\n}\n\n// ProbeStatusSpec describes the Probe.\nmessage ProbeStatusSpec {\n  bool success = 1;\n  string last_error = 2;\n}\n\n// ResolverSpecSpec describes DNS resolvers.\nmessage ResolverSpecSpec {\n  repeated common.NetIP dns_servers = 1;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 2;\n  repeated string search_domains = 3;\n}\n\n// ResolverStatusSpec describes DNS resolvers.\nmessage ResolverStatusSpec {\n  repeated common.NetIP dns_servers = 1;\n  repeated string search_domains = 2;\n}\n\n// RouteSpecSpec describes the route.\nmessage RouteSpecSpec {\n  talos.resource.definitions.enums.NethelpersFamily family = 1;\n  common.NetIPPrefix destination = 2;\n  common.NetIP source = 3;\n  common.NetIP gateway = 4;\n  string out_link_name = 5;\n  talos.resource.definitions.enums.NethelpersRoutingTable table = 6;\n  uint32 priority = 7;\n  talos.resource.definitions.enums.NethelpersScope scope = 8;\n  talos.resource.definitions.enums.NethelpersRouteType type = 9;\n  uint32 flags = 10;\n  talos.resource.definitions.enums.NethelpersRouteProtocol protocol = 11;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 12;\n  uint32 mtu = 13;\n}\n\n// RouteStatusSpec describes status of rendered secrets.\nmessage RouteStatusSpec {\n  talos.resource.definitions.enums.NethelpersFamily family = 1;\n  common.NetIPPrefix destination = 2;\n  common.NetIP source = 3;\n  common.NetIP gateway = 4;\n  uint32 out_link_index = 5;\n  string out_link_name = 6;\n  talos.resource.definitions.enums.NethelpersRoutingTable table = 7;\n  uint32 priority = 8;\n  talos.resource.definitions.enums.NethelpersScope scope = 9;\n  talos.resource.definitions.enums.NethelpersRouteType type = 10;\n  uint32 flags = 11;\n  talos.resource.definitions.enums.NethelpersRouteProtocol protocol = 12;\n  uint32 mtu = 13;\n}\n\n// RoutingRuleSpecSpec describes the routing rule.\nmessage RoutingRuleSpecSpec {\n  talos.resource.definitions.enums.NethelpersFamily family = 1;\n  common.NetIPPrefix src = 2;\n  common.NetIPPrefix dst = 3;\n  talos.resource.definitions.enums.NethelpersRoutingTable table = 4;\n  uint32 priority = 5;\n  talos.resource.definitions.enums.NethelpersRoutingRuleAction action = 6;\n  string iif_name = 7;\n  string oif_name = 8;\n  uint32 fw_mark = 9;\n  uint32 fw_mask = 10;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 11;\n}\n\n// RoutingRuleStatusSpec describes the observed routing rule state.\nmessage RoutingRuleStatusSpec {\n  talos.resource.definitions.enums.NethelpersFamily family = 1;\n  common.NetIPPrefix src = 2;\n  common.NetIPPrefix dst = 3;\n  talos.resource.definitions.enums.NethelpersRoutingTable table = 4;\n  uint32 priority = 5;\n  talos.resource.definitions.enums.NethelpersRoutingRuleAction action = 6;\n  string iif_name = 7;\n  string oif_name = 8;\n  uint32 fw_mark = 9;\n  uint32 fw_mask = 10;\n}\n\n// STPSpec describes Spanning Tree Protocol (STP) settings of a bridge.\nmessage STPSpec {\n  bool enabled = 1;\n}\n\n// StatusSpec describes network state.\nmessage StatusSpec {\n  bool address_ready = 1;\n  bool connectivity_ready = 2;\n  bool hostname_ready = 3;\n  bool etc_files_ready = 4;\n}\n\n// TCPProbeSpec describes the TCP Probe.\nmessage TCPProbeSpec {\n  string endpoint = 1;\n  google.protobuf.Duration timeout = 2;\n}\n\n// TimeServerSpecSpec describes NTP servers.\nmessage TimeServerSpecSpec {\n  repeated string ntp_servers = 1;\n  talos.resource.definitions.enums.NetworkConfigLayer config_layer = 2;\n}\n\n// TimeServerStatusSpec describes NTP servers.\nmessage TimeServerStatusSpec {\n  repeated string ntp_servers = 1;\n}\n\n// VIPEquinixMetalSpec describes virtual (elastic) IP settings for Equinix Metal.\nmessage VIPEquinixMetalSpec {\n  string project_id = 1;\n  string device_id = 2;\n  string api_token = 3;\n}\n\n// VIPHCloudSpec describes virtual (elastic) IP settings for Hetzner Cloud.\nmessage VIPHCloudSpec {\n  int64 device_id = 1;\n  int64 network_id = 2;\n  string api_token = 3;\n}\n\n// VIPOperatorSpec describes virtual IP operator options.\nmessage VIPOperatorSpec {\n  common.NetIP ip = 1;\n  bool gratuitous_arp = 2;\n  VIPEquinixMetalSpec equinix_metal = 3;\n  VIPHCloudSpec h_cloud = 4;\n}\n\n// VLANSpec describes VLAN settings if Kind == \"vlan\".\nmessage VLANSpec {\n  uint32 vid = 1;\n  talos.resource.definitions.enums.NethelpersVLANProtocol protocol = 2;\n}\n\n// VRFMasterSpec describes vrf settings if Kind == \"vrf\".\nmessage VRFMasterSpec {\n  talos.resource.definitions.enums.NethelpersRoutingTable table = 1;\n}\n\n// VRFSlave contains the name of the master vrf for an interface\nmessage VRFSlave {\n  string master_name = 1;\n}\n\n// WireguardPeer describes a single peer.\nmessage WireguardPeer {\n  string public_key = 1;\n  string preshared_key = 2;\n  string endpoint = 3;\n  google.protobuf.Duration persistent_keepalive_interval = 4;\n  repeated common.NetIPPrefix allowed_ips = 5;\n}\n\n// WireguardSpec describes Wireguard settings if Kind == \"wireguard\".\nmessage WireguardSpec {\n  string private_key = 1;\n  string public_key = 2;\n  int64 listen_port = 3;\n  int64 firewall_mark = 4;\n  repeated WireguardPeer peers = 5;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/perf/perf.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.perf;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/perf\";\noption java_package = \"dev.talos.api.resource.definitions.perf\";\n\n// CPUSpec represents the last CPU stats snapshot.\nmessage CPUSpec {\n  repeated CPUStat cpu = 1;\n  CPUStat cpu_total = 2;\n  uint64 irq_total = 3;\n  uint64 context_switches = 4;\n  uint64 process_created = 5;\n  uint64 process_running = 6;\n  uint64 process_blocked = 7;\n  uint64 soft_irq_total = 8;\n}\n\n// CPUStat represents a single cpu stat.\nmessage CPUStat {\n  double user = 1;\n  double nice = 2;\n  double system = 3;\n  double idle = 4;\n  double iowait = 5;\n  double irq = 6;\n  double soft_irq = 7;\n  double steal = 8;\n  double guest = 9;\n  double guest_nice = 10;\n}\n\n// MemorySpec represents the last Memory stats snapshot.\nmessage MemorySpec {\n  uint64 mem_total = 1;\n  uint64 mem_used = 2;\n  uint64 mem_available = 3;\n  uint64 buffers = 4;\n  uint64 cached = 5;\n  uint64 swap_cached = 6;\n  uint64 active = 7;\n  uint64 inactive = 8;\n  uint64 active_anon = 9;\n  uint64 inactive_anon = 10;\n  uint64 active_file = 11;\n  uint64 inactive_file = 12;\n  uint64 unevictable = 13;\n  uint64 mlocked = 14;\n  uint64 swap_total = 15;\n  uint64 swap_free = 16;\n  uint64 dirty = 17;\n  uint64 writeback = 18;\n  uint64 anon_pages = 19;\n  uint64 mapped = 20;\n  uint64 shmem = 21;\n  uint64 slab = 22;\n  uint64 s_reclaimable = 23;\n  uint64 s_unreclaim = 24;\n  uint64 kernel_stack = 25;\n  uint64 page_tables = 26;\n  uint64 nf_sunstable = 27;\n  uint64 bounce = 28;\n  uint64 writeback_tmp = 29;\n  uint64 commit_limit = 30;\n  uint64 committed_as = 31;\n  uint64 vmalloc_total = 32;\n  uint64 vmalloc_used = 33;\n  uint64 vmalloc_chunk = 34;\n  uint64 hardware_corrupted = 35;\n  uint64 anon_huge_pages = 36;\n  uint64 shmem_huge_pages = 37;\n  uint64 shmem_pmd_mapped = 38;\n  uint64 cma_total = 39;\n  uint64 cma_free = 40;\n  uint64 huge_pages_total = 41;\n  uint64 huge_pages_free = 42;\n  uint64 huge_pages_rsvd = 43;\n  uint64 huge_pages_surp = 44;\n  uint64 hugepagesize = 45;\n  uint64 direct_map4k = 46;\n  uint64 direct_map2m = 47;\n  uint64 direct_map1g = 48;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/proto/proto.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.proto;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/proto\";\noption java_package = \"dev.talos.api.resource.definitions.proto\";\n\n// LinuxIDMapping specifies UID/GID mappings.\nmessage LinuxIDMapping {\n  uint32 container_id = 1;\n  uint32 host_id = 2;\n  uint32 size = 3;\n}\n\n// Mount specifies a mount for a container.\nmessage Mount {\n  string destination = 1;\n  string type = 2;\n  string source = 3;\n  repeated string options = 4;\n  repeated LinuxIDMapping uid_mappings = 5;\n  repeated LinuxIDMapping gid_mappings = 6;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/runtime/runtime.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.runtime;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/runtime\";\noption java_package = \"dev.talos.api.resource.definitions.runtime\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/duration.proto\";\nimport \"resource/definitions/enums/enums.proto\";\n\n// APIServiceConfigSpec describes configuration for Talos API service (apid).\nmessage APIServiceConfigSpec {\n  string listen_address = 1;\n  bool node_routing_disabled = 2;\n  bool readonly_role_mode = 3;\n  bool skip_verifying_client_cert = 4;\n}\n\n// BootedEntrySpec describes the booted entry resource properties.\nmessage BootedEntrySpec {\n  string booted_entry = 1;\n}\n\n// DevicesStatusSpec is the spec for devices status.\nmessage DevicesStatusSpec {\n  bool ready = 1;\n}\n\n// DiagnosticSpec is the spec for devices status.\nmessage DiagnosticSpec {\n  string message = 1;\n  repeated string details = 2;\n}\n\n// EnvironmentSpec describes the specification of Environment resource.\nmessage EnvironmentSpec {\n  repeated string variables = 1;\n}\n\n// EventSinkConfigSpec describes configuration of Talos event log streaming.\nmessage EventSinkConfigSpec {\n  string endpoint = 1;\n}\n\n// ExtensionServiceConfigFile describes extensions service config files.\nmessage ExtensionServiceConfigFile {\n  string content = 1;\n  string mount_path = 2;\n}\n\n// ExtensionServiceConfigSpec describes status of rendered extensions service config files.\nmessage ExtensionServiceConfigSpec {\n  repeated ExtensionServiceConfigFile files = 1;\n  repeated string environment = 2;\n}\n\n// ExtensionServiceConfigStatusSpec describes status of rendered extensions service config files.\nmessage ExtensionServiceConfigStatusSpec {\n  string spec_version = 1;\n}\n\n// KernelCmdlineSpec presents kernel command line (contents of /proc/cmdline).\nmessage KernelCmdlineSpec {\n  string cmdline = 1;\n}\n\n// KernelModuleSpecSpec describes Linux kernel module to load.\nmessage KernelModuleSpecSpec {\n  string name = 1;\n  repeated string parameters = 2;\n}\n\n// KernelParamSpecSpec describes status of the defined sysctls.\nmessage KernelParamSpecSpec {\n  string value = 1;\n  bool ignore_errors = 2;\n}\n\n// KernelParamStatusSpec describes status of the defined sysctls.\nmessage KernelParamStatusSpec {\n  string current = 1;\n  string default = 2;\n  bool unsupported = 3;\n}\n\n// KmsgLogConfigSpec describes configuration for kmsg log streaming.\nmessage KmsgLogConfigSpec {\n  repeated common.URL destinations = 1;\n}\n\n// LoadedKernelModuleSpec describes Linux kernel module to load.\nmessage LoadedKernelModuleSpec {\n  int64 size = 1;\n  int64 reference_count = 2;\n  repeated string dependencies = 3;\n  string state = 4;\n  string address = 5;\n}\n\n// MachineStatusSpec describes status of the defined sysctls.\nmessage MachineStatusSpec {\n  talos.resource.definitions.enums.RuntimeMachineStage stage = 1;\n  MachineStatusStatus status = 2;\n}\n\n// MachineStatusStatus describes machine current status at the stage.\nmessage MachineStatusStatus {\n  bool ready = 1;\n  repeated UnmetCondition unmet_conditions = 2;\n}\n\n// MaintenanceServiceConfigSpec describes configuration for maintenance service API.\nmessage MaintenanceServiceConfigSpec {\n  string listen_address = 1;\n  repeated common.NetIP reachable_addresses = 2;\n}\n\n// MetaKeySpec describes status of the defined sysctls.\nmessage MetaKeySpec {\n  string value = 1;\n}\n\n// MetaLoadedSpec is the spec for meta loaded. The Done field is always true when resource exists.\nmessage MetaLoadedSpec {\n  bool done = 1;\n}\n\n// MountStatusSpec describes status of the defined sysctls.\nmessage MountStatusSpec {\n  string source = 1;\n  string target = 2;\n  string filesystem_type = 3;\n  repeated string options = 4;\n  bool encrypted = 5;\n  repeated string encryption_providers = 6;\n}\n\n// OOMActionSpec describes the OOM action record resource properties.\nmessage OOMActionSpec {\n  string trigger_context = 1;\n  double score = 2;\n  repeated string processes = 3;\n}\n\n// PlatformMetadataSpec describes platform metadata properties.\nmessage PlatformMetadataSpec {\n  string platform = 1;\n  string hostname = 2;\n  string region = 3;\n  string zone = 4;\n  string instance_type = 5;\n  string instance_id = 6;\n  string provider_id = 7;\n  bool spot = 8;\n  string internal_dns = 9;\n  string external_dns = 10;\n  map<string, string> tags = 11;\n}\n\n// SBOMItemSpec describes the SBOM item resource properties.\nmessage SBOMItemSpec {\n  string name = 1;\n  string version = 2;\n  string license = 3;\n  repeated string cp_es = 4;\n  repeated string pur_ls = 5;\n  bool extension = 6;\n}\n\n// SecurityStateSpec describes the security state resource properties.\nmessage SecurityStateSpec {\n  bool secure_boot = 1;\n  string uki_signing_key_fingerprint = 2;\n  string pcr_signing_key_fingerprint = 3;\n  talos.resource.definitions.enums.RuntimeSELinuxState se_linux_state = 4;\n  bool booted_with_uki = 5;\n  talos.resource.definitions.enums.RuntimeFIPSState fips_state = 6;\n  bool module_signature_enforced = 7;\n}\n\n// UniqueMachineTokenSpec is the spec for the machine unique token. Token can be empty if machine wasn't assigned any.\nmessage UniqueMachineTokenSpec {\n  string token = 1;\n}\n\n// UnmetCondition is a failure which prevents machine from being ready at the stage.\nmessage UnmetCondition {\n  string name = 1;\n  string reason = 2;\n}\n\n// WatchdogTimerConfigSpec describes configuration of watchdog timer.\nmessage WatchdogTimerConfigSpec {\n  string device = 1;\n  google.protobuf.Duration timeout = 2;\n}\n\n// WatchdogTimerStatusSpec describes configuration of watchdog timer.\nmessage WatchdogTimerStatusSpec {\n  string device = 1;\n  google.protobuf.Duration timeout = 2;\n  google.protobuf.Duration feed_interval = 3;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/secrets/secrets.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.secrets;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/secrets\";\noption java_package = \"dev.talos.api.resource.definitions.secrets\";\n\nimport \"common/common.proto\";\n\n// APICertsSpec describes etcd certs secrets.\nmessage APICertsSpec {\n  common.PEMEncodedCertificateAndKey client = 2;\n  common.PEMEncodedCertificateAndKey server = 3;\n  repeated common.PEMEncodedCertificate accepted_c_as = 4;\n  bool skip_verifying_client_cert = 5;\n}\n\n// CertSANSpec describes fields of the cert SANs.\nmessage CertSANSpec {\n  repeated common.NetIP i_ps = 1;\n  repeated string dns_names = 2;\n  string fqdn = 3;\n}\n\n// EncryptionSaltSpec describes the salt.\nmessage EncryptionSaltSpec {\n  bytes disk_salt = 1;\n}\n\n// EtcdCertsSpec describes etcd certs secrets.\nmessage EtcdCertsSpec {\n  common.PEMEncodedCertificateAndKey etcd = 1;\n  common.PEMEncodedCertificateAndKey etcd_peer = 2;\n  common.PEMEncodedCertificateAndKey etcd_admin = 3;\n  common.PEMEncodedCertificateAndKey etcd_api_server = 4;\n}\n\n// EtcdRootSpec describes etcd CA secrets.\nmessage EtcdRootSpec {\n  common.PEMEncodedCertificateAndKey etcd_ca = 1;\n}\n\n// KubeletSpec describes root Kubernetes secrets.\nmessage KubeletSpec {\n  common.URL endpoint = 1;\n  string bootstrap_token_id = 3;\n  string bootstrap_token_secret = 4;\n  repeated common.PEMEncodedCertificate accepted_c_as = 5;\n}\n\n// KubernetesCertsSpec describes generated Kubernetes certificates.\nmessage KubernetesCertsSpec {\n  string scheduler_kubeconfig = 4;\n  string controller_manager_kubeconfig = 5;\n  string localhost_admin_kubeconfig = 6;\n  string admin_kubeconfig = 7;\n}\n\n// KubernetesDynamicCertsSpec describes generated KubernetesCerts certificates.\nmessage KubernetesDynamicCertsSpec {\n  common.PEMEncodedCertificateAndKey api_server = 1;\n  common.PEMEncodedCertificateAndKey api_server_kubelet_client = 2;\n  common.PEMEncodedCertificateAndKey front_proxy = 3;\n}\n\n// KubernetesRootSpec describes root Kubernetes secrets.\nmessage KubernetesRootSpec {\n  string name = 1;\n  common.URL endpoint = 2;\n  common.URL local_endpoint = 3;\n  repeated string cert_sa_ns = 4;\n  string dns_domain = 6;\n  common.PEMEncodedCertificateAndKey issuing_ca = 7;\n  common.PEMEncodedKey service_account = 8;\n  common.PEMEncodedCertificateAndKey aggregator_ca = 9;\n  string aescbc_encryption_secret = 10;\n  string bootstrap_token_id = 11;\n  string bootstrap_token_secret = 12;\n  string secretbox_encryption_secret = 13;\n  repeated common.NetIP api_server_ips = 14;\n  repeated common.PEMEncodedCertificate accepted_c_as = 15;\n}\n\n// MaintenanceRootSpec describes maintenance service CA.\nmessage MaintenanceRootSpec {\n  common.PEMEncodedCertificateAndKey ca = 1;\n}\n\n// OSRootSpec describes operating system CA.\nmessage OSRootSpec {\n  common.PEMEncodedCertificateAndKey issuing_ca = 1;\n  repeated common.NetIP cert_sani_ps = 2;\n  repeated string cert_sandns_names = 3;\n  string token = 4;\n  repeated common.PEMEncodedCertificate accepted_c_as = 5;\n}\n\n// TrustdCertsSpec describes etcd certs secrets.\nmessage TrustdCertsSpec {\n  common.PEMEncodedCertificateAndKey server = 2;\n  repeated common.PEMEncodedCertificate accepted_c_as = 3;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/security/security.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.security;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/security\";\noption java_package = \"dev.talos.api.resource.definitions.security\";\n\nimport \"google/protobuf/timestamp.proto\";\n\n// ImageKeylessVerifierSpec represents a signature verification provider.\nmessage ImageKeylessVerifierSpec {\n  string issuer = 1;\n  string subject = 2;\n  string subject_regex = 3;\n}\n\n// ImagePublicKeyVerifierSpec represents a signature verification provider with static public key.\nmessage ImagePublicKeyVerifierSpec {\n  string certificate = 1;\n}\n\n// ImageVerificationRuleSpec represents a verification rule.\nmessage ImageVerificationRuleSpec {\n  string image_pattern = 2;\n  bool skip = 3;\n  bool deny = 4;\n  ImageKeylessVerifierSpec keyless_verifier = 5;\n  ImagePublicKeyVerifierSpec public_key_verifier = 6;\n}\n\n// TUFTrustedRootSpec represents a sigstore's TUF trusted root information.\nmessage TUFTrustedRootSpec {\n  google.protobuf.Timestamp last_refresh_time = 1;\n  string json_data = 2;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/siderolink/siderolink.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.siderolink;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/siderolink\";\noption java_package = \"dev.talos.api.resource.definitions.siderolink\";\n\nimport \"common/common.proto\";\n\n// ConfigSpec describes Siderolink configuration.\nmessage ConfigSpec {\n  string api_endpoint = 1;\n  string host = 2;\n  string join_token = 3;\n  bool insecure = 4;\n  bool tunnel = 5;\n}\n\n// StatusSpec describes Siderolink status.\nmessage StatusSpec {\n  string host = 1;\n  bool connected = 2;\n  string link_name = 3;\n  bool grpc_tunnel = 4;\n}\n\n// TunnelSpec describes Siderolink GRPC Tunnel configuration.\nmessage TunnelSpec {\n  string api_endpoint = 1;\n  string link_name = 2;\n  int64 mtu = 3;\n  common.NetIPPort node_address = 4;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/time/time.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.time;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/time\";\noption java_package = \"dev.talos.api.resource.definitions.time\";\n\nimport \"google/protobuf/duration.proto\";\n\n// AdjtimeStatusSpec describes Linux internal adjtime state.\nmessage AdjtimeStatusSpec {\n  google.protobuf.Duration offset = 1;\n  double frequency_adjustment_ratio = 2;\n  google.protobuf.Duration max_error = 3;\n  google.protobuf.Duration est_error = 4;\n  string status = 5;\n  int64 constant = 6;\n  bool sync_status = 7;\n  string state = 8;\n}\n\n// StatusSpec describes time sync state.\nmessage StatusSpec {\n  bool synced = 1;\n  int64 epoch = 2;\n  bool sync_disabled = 3;\n}\n\n"
  },
  {
    "path": "api/resource/definitions/v1alpha1/v1alpha1.proto",
    "content": "syntax = \"proto3\";\n\npackage talos.resource.definitions.v1alpha1;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/v1alpha1\";\noption java_package = \"dev.talos.api.resource.definitions.v1alpha1\";\n\n// ServiceSpec describe service state.\nmessage ServiceSpec {\n  bool running = 1;\n  bool healthy = 2;\n  bool unknown = 3;\n}\n\n"
  },
  {
    "path": "api/resource/network/device_config.proto",
    "content": "syntax = \"proto3\";\n\npackage resource.network;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/network\";\noption java_package = \"dev.talos.api.resource.network\";\n\n// DeviceConfigSpecSpec is the spec for the network.DeviceConfigSpec resource.\nmessage DeviceConfigSpecSpec {\n  // Contains YAML marshalled device config (as part of the machine config).\n  bytes yaml_marshalled = 1;\n}\n"
  },
  {
    "path": "api/security/security.proto",
    "content": "syntax = \"proto3\";\n\npackage securityapi;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/security\";\noption java_package = \"dev.talos.api.security\";\n\n// The security service definition.\nservice SecurityService {\n  rpc Certificate(CertificateRequest) returns (CertificateResponse);\n}\n\n// The request message containing the certificate signing request.\nmessage CertificateRequest {\n  // Certificate Signing Request in PEM format.\n  bytes csr = 1;\n}\n\n// The response message containing signed certificate.\nmessage CertificateResponse {\n  // Certificate of the CA that signed the requested certificate in PEM format.\n  bytes ca = 1;\n  // Signed X.509 requested certificate in PEM format.\n  bytes crt = 2;\n}\n"
  },
  {
    "path": "api/storage/storage.proto",
    "content": "syntax = \"proto3\";\n\npackage storage;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/storage\";\noption java_package = \"dev.talos.api.storage\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/empty.proto\";\n\n// StorageService represents the storage service.\nservice StorageService {\n  rpc Disks(google.protobuf.Empty) returns (DisksResponse);\n  // BlockDeviceWipe performs a wipe of the blockdevice (partition or disk).\n  //\n  // The method doesn't require a reboot, and it can only wipe blockdevices which are not\n  // being used as volumes at the moment.\n  // Wiping of volumes requires a different API.\n  rpc BlockDeviceWipe(BlockDeviceWipeRequest) returns (BlockDeviceWipeResponse);\n}\n\n// Disk represents a disk.\nmessage Disk {\n  // Size indicates the disk size in bytes.\n  uint64 size = 1;\n  // Model idicates the disk model.\n  string model = 2;\n  // DeviceName indicates the disk name (e.g. `sda`).\n  string device_name = 3;\n  // Name as in `/sys/block/<dev>/device/name`.\n  string name = 4;\n  // Serial as in `/sys/block/<dev>/device/serial`.\n  string serial = 5;\n  // Modalias as in `/sys/block/<dev>/device/modalias`.\n  string modalias = 6;\n  // Uuid as in `/sys/block/<dev>/device/uuid`.\n  string uuid = 7;\n  // Wwid as in `/sys/block/<dev>/device/wwid`.\n  string wwid = 8;\n  enum DiskType {\n    UNKNOWN = 0;\n    SSD = 1;\n    HDD = 2;\n    NVME = 3;\n    SD = 4;\n    CD = 5;\n  }\n  // Type is a type of the disk: nvme, ssd, hdd, sd card.\n  DiskType type = 9;\n  // BusPath is the bus path of the disk.\n  string bus_path = 10;\n  // SystemDisk indicates that the disk is used as Talos system disk.\n  bool system_disk = 11;\n  // Subsystem is the symlink path in the `/sys/block/<dev>/subsystem`.\n  string subsystem = 12;\n  // Readonly specifies if the disk is read only.\n  bool readonly = 13;\n}\n\n// DisksResponse represents the response of the `Disks` RPC.\nmessage Disks {\n  common.Metadata metadata = 1;\n  repeated Disk disks = 2;\n}\n\nmessage DisksResponse {\n  repeated Disks messages = 1;\n}\n\n// rpc BlockDeviceWipe\n\nmessage BlockDeviceWipeRequest {\n  repeated BlockDeviceWipeDescriptor devices = 1;\n}\n\n// BlockDeviceWipeDescriptor represents a single block device to be wiped.\n//\n// The device can be either a full disk (e.g. vda) or a partition (vda5).\n// The device should not be used in any of active volumes.\n// The device should not be used as a secondary (e.g. part of LVM).\nmessage BlockDeviceWipeDescriptor {\n  enum Method {\n    // Fast wipe - wipe only filesystem signatures.\n    FAST = 0;\n    // Zeroes wipe - wipe by overwriting with zeroes (might be slow depending on the disk size and available hardware features).\n    ZEROES = 1;\n  }\n  // Device name to wipe (e.g. sda or sda5).\n  //\n  // The name should be submitted without `/dev/` prefix.\n  string device = 1;\n  // Wipe method to use.\n  Method method = 2;\n  // Skip the volume in use check.\n  bool skip_volume_check = 3;\n  // Skip the secondary disk check (e.g. underlying disk for RAID or LVM).\n  bool skip_secondary_check = 5;\n  // Drop the partition (only applies if the device is a partition).\n  bool drop_partition = 4;\n}\n\nmessage BlockDeviceWipeResponse {\n  repeated BlockDeviceWipe messages = 1;\n}\n\nmessage BlockDeviceWipe {\n  common.Metadata metadata = 1;\n}\n"
  },
  {
    "path": "api/time/time.proto",
    "content": "syntax = \"proto3\";\n\npackage time;\n\noption go_package = \"github.com/siderolabs/talos/pkg/machinery/api/time\";\noption java_package = \"dev.talos.api.time\";\n\nimport \"common/common.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\n// The time service definition.\nservice TimeService {\n  rpc Time(google.protobuf.Empty) returns (TimeResponse);\n  rpc TimeCheck(TimeRequest) returns (TimeResponse);\n}\n\n// The response message containing the ntp server\nmessage TimeRequest {\n  string server = 1;\n}\n\nmessage Time {\n  common.Metadata metadata = 1;\n  string server = 2;\n  google.protobuf.Timestamp localtime = 3;\n  google.protobuf.Timestamp remotetime = 4;\n}\n\n// The response message containing the ntp server, time, and offset\nmessage TimeResponse {\n  repeated Time messages = 1;\n}\n"
  },
  {
    "path": "api/vendor/google/api/expr/v1alpha1/checked.proto",
    "content": "// Copyright 2024 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api.expr.v1alpha1;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr\";\noption java_multiple_files = true;\noption java_outer_classname = \"DeclProto\";\noption java_package = \"com.google.api.expr.v1alpha1\";\n\nimport \"google/api/expr/v1alpha1/syntax.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/struct.proto\";\n\n// Protos for representing CEL declarations and typed checked expressions.\n\n// A CEL expression which has been successfully type checked.\nmessage CheckedExpr {\n  // A map from expression ids to resolved references.\n  //\n  // The following entries are in this table:\n  //\n  // - An Ident or Select expression is represented here if it resolves to a\n  //   declaration. For instance, if `a.b.c` is represented by\n  //   `select(select(id(a), b), c)`, and `a.b` resolves to a declaration,\n  //   while `c` is a field selection, then the reference is attached to the\n  //   nested select expression (but not to the id or or the outer select).\n  //   In turn, if `a` resolves to a declaration and `b.c` are field selections,\n  //   the reference is attached to the ident expression.\n  // - Every Call expression has an entry here, identifying the function being\n  //   called.\n  // - Every CreateStruct expression for a message has an entry, identifying\n  //   the message.\n  map<int64, Reference> reference_map = 2;\n  // A map from expression ids to types.\n  //\n  // Every expression node which has a type different than DYN has a mapping\n  // here. If an expression has type DYN, it is omitted from this map to save\n  // space.\n  map<int64, Type> type_map = 3;\n  // The source info derived from input that generated the parsed `expr` and\n  // any optimizations made during the type-checking pass.\n  SourceInfo source_info = 5;\n  // The expr version indicates the major / minor version number of the `expr`\n  // representation.\n  //\n  // The most common reason for a version change will be to indicate to the CEL\n  // runtimes that transformations have been performed on the expr during static\n  // analysis. In some cases, this will save the runtime the work of applying\n  // the same or similar transformations prior to evaluation.\n  string expr_version = 6;\n  // The checked expression. Semantically equivalent to the parsed `expr`, but\n  // may have structural differences.\n  Expr expr = 4;\n}\n\n// Represents a CEL type.\nmessage Type {\n  // List type with typed elements, e.g. `list<example.proto.MyMessage>`.\n  message ListType {\n    // The element type.\n    Type elem_type = 1;\n  }\n  // Map type with parameterized key and value types, e.g. `map<string, int>`.\n  message MapType {\n    // The type of the key.\n    Type key_type = 1;\n    // The type of the value.\n    Type value_type = 2;\n  }\n  // Function type with result and arg types.\n  message FunctionType {\n    // Result type of the function.\n    Type result_type = 1;\n    // Argument types of the function.\n    repeated Type arg_types = 2;\n  }\n  // Application defined abstract type.\n  message AbstractType {\n    // The fully qualified name of this abstract type.\n    string name = 1;\n    // Parameter types for this abstract type.\n    repeated Type parameter_types = 2;\n  }\n  // CEL primitive types.\n  enum PrimitiveType {\n    // Unspecified type.\n    PRIMITIVE_TYPE_UNSPECIFIED = 0;\n    // Boolean type.\n    BOOL = 1;\n    // Int64 type.\n    //\n    // Proto-based integer values are widened to int64.\n    INT64 = 2;\n    // Uint64 type.\n    //\n    // Proto-based unsigned integer values are widened to uint64.\n    UINT64 = 3;\n    // Double type.\n    //\n    // Proto-based float values are widened to double values.\n    DOUBLE = 4;\n    // String type.\n    STRING = 5;\n    // Bytes type.\n    BYTES = 6;\n  }\n  // Well-known protobuf types treated with first-class support in CEL.\n  enum WellKnownType {\n    // Unspecified type.\n    WELL_KNOWN_TYPE_UNSPECIFIED = 0;\n    // Well-known protobuf.Any type.\n    //\n    // Any types are a polymorphic message type. During type-checking they are\n    // treated like `DYN` types, but at runtime they are resolved to a specific\n    // message type specified at evaluation time.\n    ANY = 1;\n    // Well-known protobuf.Timestamp type, internally referenced as `timestamp`.\n    TIMESTAMP = 2;\n    // Well-known protobuf.Duration type, internally referenced as `duration`.\n    DURATION = 3;\n  }\n  // The kind of type.\n  oneof type_kind {\n    // Dynamic type.\n    google.protobuf.Empty dyn = 1;\n    // Null value.\n    google.protobuf.NullValue null = 2;\n    // Primitive types: `true`, `1u`, `-2.0`, `'string'`, `b'bytes'`.\n    PrimitiveType primitive = 3;\n    // Wrapper of a primitive type, e.g. `google.protobuf.Int64Value`.\n    PrimitiveType wrapper = 4;\n    // Well-known protobuf type such as `google.protobuf.Timestamp`.\n    WellKnownType well_known = 5;\n    // Parameterized list with elements of `list_type`, e.g. `list<timestamp>`.\n    ListType list_type = 6;\n    // Parameterized map with typed keys and values.\n    MapType map_type = 7;\n    // Function type.\n    FunctionType function = 8;\n    // Protocol buffer message type.\n    //\n    // The `message_type` string specifies the qualified message type name. For\n    // example, `google.plus.Profile`.\n    string message_type = 9;\n    // Type param type.\n    //\n    // The `type_param` string specifies the type parameter name, e.g. `list<E>`\n    // would be a `list_type` whose element type was a `type_param` type\n    // named `E`.\n    string type_param = 10;\n    // Type type.\n    //\n    // The `type` value specifies the target type. e.g. int is type with a\n    // target type of `Primitive.INT`.\n    Type type = 11;\n    // Error type.\n    //\n    // During type-checking if an expression is an error, its type is propagated\n    // as the `ERROR` type. This permits the type-checker to discover other\n    // errors present in the expression.\n    google.protobuf.Empty error = 12;\n    // Abstract, application defined type.\n    AbstractType abstract_type = 14;\n  }\n}\n\n// Represents a declaration of a named value or function.\n//\n// A declaration is part of the contract between the expression, the agent\n// evaluating that expression, and the caller requesting evaluation.\nmessage Decl {\n  // Identifier declaration which specifies its type and optional `Expr` value.\n  //\n  // An identifier without a value is a declaration that must be provided at\n  // evaluation time. An identifier with a value should resolve to a constant,\n  // but may be used in conjunction with other identifiers bound at evaluation\n  // time.\n  message IdentDecl {\n    // Required. The type of the identifier.\n    Type type = 1;\n    // The constant value of the identifier. If not specified, the identifier\n    // must be supplied at evaluation time.\n    Constant value = 2;\n    // Documentation string for the identifier.\n    string doc = 3;\n  }\n  // Function declaration specifies one or more overloads which indicate the\n  // function's parameter types and return type.\n  //\n  // Functions have no observable side-effects (there may be side-effects like\n  // logging which are not observable from CEL).\n  message FunctionDecl {\n    // An overload indicates a function's parameter types and return type, and\n    // may optionally include a function body described in terms of\n    // [Expr][google.api.expr.v1alpha1.Expr] values.\n    //\n    // Functions overloads are declared in either a function or method\n    // call-style. For methods, the `params[0]` is the expected type of the\n    // target receiver.\n    //\n    // Overloads must have non-overlapping argument types after erasure of all\n    // parameterized type variables (similar as type erasure in Java).\n    message Overload {\n      // Required. Globally unique overload name of the function which reflects\n      // the function name and argument types.\n      //\n      // This will be used by a [Reference][google.api.expr.v1alpha1.Reference]\n      // to indicate the `overload_id` that was resolved for the function\n      // `name`.\n      string overload_id = 1;\n      // List of function parameter [Type][google.api.expr.v1alpha1.Type]\n      // values.\n      //\n      // Param types are disjoint after generic type parameters have been\n      // replaced with the type `DYN`. Since the `DYN` type is compatible with\n      // any other type, this means that if `A` is a type parameter, the\n      // function types `int<A>` and `int<int>` are not disjoint. Likewise,\n      // `map<string, string>` is not disjoint from `map<K, V>`.\n      //\n      // When the `result_type` of a function is a generic type param, the\n      // type param name also appears as the `type` of on at least one params.\n      repeated Type params = 2;\n      // The type param names associated with the function declaration.\n      //\n      // For example, `function ex<K,V>(K key, map<K, V> map) : V` would yield\n      // the type params of `K, V`.\n      repeated string type_params = 3;\n      // Required. The result type of the function. For example, the operator\n      // `string.isEmpty()` would have `result_type` of `kind: BOOL`.\n      Type result_type = 4;\n      // Whether the function is to be used in a method call-style `x.f(...)`\n      // or a function call-style `f(x, ...)`.\n      //\n      // For methods, the first parameter declaration, `params[0]` is the\n      // expected type of the target receiver.\n      bool is_instance_function = 5;\n      // Documentation string for the overload.\n      string doc = 6;\n    }\n    // Required. List of function overloads, must contain at least one overload.\n    repeated Overload overloads = 1;\n  }\n  // The fully qualified name of the declaration.\n  //\n  // Declarations are organized in containers and this represents the full path\n  // to the declaration in its container, as in `google.api.expr.Decl`.\n  //\n  // Declarations used as\n  // [FunctionDecl.Overload][google.api.expr.v1alpha1.Decl.FunctionDecl.Overload]\n  // parameters may or may not have a name depending on whether the overload is\n  // function declaration or a function definition containing a result\n  // [Expr][google.api.expr.v1alpha1.Expr].\n  string name = 1;\n  // Required. The declaration kind.\n  oneof decl_kind {\n    // Identifier declaration.\n    IdentDecl ident = 2;\n    // Function declaration.\n    FunctionDecl function = 3;\n  }\n}\n\n// Describes a resolved reference to a declaration.\nmessage Reference {\n  // The fully qualified name of the declaration.\n  string name = 1;\n  // For references to functions, this is a list of `Overload.overload_id`\n  // values which match according to typing rules.\n  //\n  // If the list has more than one element, overload resolution among the\n  // presented candidates must happen at runtime because of dynamic types. The\n  // type checker attempts to narrow down this list as much as possible.\n  //\n  // Empty if this is not a reference to a\n  // [Decl.FunctionDecl][google.api.expr.v1alpha1.Decl.FunctionDecl].\n  repeated string overload_id = 3;\n  // For references to constants, this may contain the value of the\n  // constant if known at compile time.\n  Constant value = 4;\n}\n"
  },
  {
    "path": "api/vendor/google/api/expr/v1alpha1/eval.proto",
    "content": "// Copyright 2024 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api.expr.v1alpha1;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr\";\noption java_multiple_files = true;\noption java_outer_classname = \"EvalProto\";\noption java_package = \"com.google.api.expr.v1alpha1\";\n\nimport \"google/api/expr/v1alpha1/value.proto\";\nimport \"google/rpc/status.proto\";\n\n// The state of an evaluation.\n//\n// Can represent an initial, partial, or completed state of evaluation.\nmessage EvalState {\n  // A single evalution result.\n  message Result {\n    // The id of the expression this result if for.\n    int64 expr = 1;\n    // The index in `values` of the resulting value.\n    int64 value = 2;\n  }\n  // The unique values referenced in this message.\n  repeated ExprValue values = 1;\n  // An ordered list of results.\n  //\n  // Tracks the flow of evaluation through the expression.\n  // May be sparse.\n  repeated Result results = 3;\n}\n\n// The value of an evaluated expression.\nmessage ExprValue {\n  // An expression can resolve to a value, error or unknown.\n  oneof kind {\n    // A concrete value.\n    Value value = 1;\n    // The set of errors in the critical path of evalution.\n    //\n    // Only errors in the critical path are included. For example,\n    // `(<error1> || true) && <error2>` will only result in `<error2>`,\n    // while `<error1> || <error2>` will result in both `<error1>` and\n    // `<error2>`.\n    //\n    // Errors cause by the presence of other errors are not included in the\n    // set. For example `<error1>.foo`, `foo(<error1>)`, and `<error1> + 1` will\n    // only result in `<error1>`.\n    //\n    // Multiple errors *might* be included when evaluation could result\n    // in different errors. For example `<error1> + <error2>` and\n    // `foo(<error1>, <error2>)` may result in `<error1>`, `<error2>` or both.\n    // The exact subset of errors included for this case is unspecified and\n    // depends on the implementation details of the evaluator.\n    ErrorSet error = 2;\n    // The set of unknowns in the critical path of evaluation.\n    //\n    // Unknown behaves identically to Error with regards to propagation.\n    // Specifically, only unknowns in the critical path are included, unknowns\n    // caused by the presence of other unknowns are not included, and multiple\n    // unknowns *might* be included included when evaluation could result in\n    // different unknowns. For example:\n    //\n    //     (<unknown[1]> || true) && <unknown[2]> -> <unknown[2]>\n    //     <unknown[1]> || <unknown[2]> -> <unknown[1,2]>\n    //     <unknown[1]>.foo -> <unknown[1]>\n    //     foo(<unknown[1]>) -> <unknown[1]>\n    //     <unknown[1]> + <unknown[2]> -> <unknown[1]> or <unknown[2[>\n    //\n    // Unknown takes precidence over Error in cases where a `Value` can short\n    // circuit the result:\n    //\n    //     <error> || <unknown> -> <unknown>\n    //     <error> && <unknown> -> <unknown>\n    //\n    // Errors take precidence in all other cases:\n    //\n    //     <unknown> + <error> -> <error>\n    //     foo(<unknown>, <error>) -> <error>\n    UnknownSet unknown = 3;\n  }\n}\n\n// A set of errors.\n//\n// The errors included depend on the context. See `ExprValue.error`.\nmessage ErrorSet {\n  // The errors in the set.\n  repeated google.rpc.Status errors = 1;\n}\n\n// A set of expressions for which the value is unknown.\n//\n// The unknowns included depend on the context. See `ExprValue.unknown`.\nmessage UnknownSet {\n  // The ids of the expressions with unknown values.\n  repeated int64 exprs = 1;\n}\n"
  },
  {
    "path": "api/vendor/google/api/expr/v1alpha1/explain.proto",
    "content": "// Copyright 2024 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api.expr.v1alpha1;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr\";\noption java_multiple_files = true;\noption java_outer_classname = \"ExplainProto\";\noption java_package = \"com.google.api.expr.v1alpha1\";\n\nimport \"google/api/expr/v1alpha1/value.proto\";\n\n// Values of intermediate expressions produced when evaluating expression.\n// Deprecated, use `EvalState` instead.\nmessage Explain {\n  option deprecated = true;\n  // ID and value index of one step.\n  message ExprStep {\n    // ID of corresponding Expr node.\n    int64 id = 1;\n    // Index of the value in the values list.\n    int32 value_index = 2;\n  }\n  // All of the observed values.\n  //\n  // The field value_index is an index in the values list.\n  // Separating values from steps is needed to remove redundant values.\n  repeated Value values = 1;\n  // List of steps.\n  //\n  // Repeated evaluations of the same expression generate new ExprStep\n  // instances. The order of such ExprStep instances matches the order of\n  // elements returned by Comprehension.iter_range.\n  repeated ExprStep expr_steps = 2;\n}\n"
  },
  {
    "path": "api/vendor/google/api/expr/v1alpha1/syntax.proto",
    "content": "// Copyright 2024 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api.expr.v1alpha1;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr\";\noption java_multiple_files = true;\noption java_outer_classname = \"SyntaxProto\";\noption java_package = \"com.google.api.expr.v1alpha1\";\n\nimport \"google/protobuf/duration.proto\";\nimport \"google/protobuf/struct.proto\";\nimport \"google/protobuf/timestamp.proto\";\n\n// A representation of the abstract syntax of the Common Expression Language.\n\n// An expression together with source information as returned by the parser.\nmessage ParsedExpr {\n  // The parsed expression.\n  Expr expr = 2;\n  // The source info derived from input that generated the parsed `expr`.\n  SourceInfo source_info = 3;\n}\n\n// An abstract representation of a common expression.\n//\n// Expressions are abstractly represented as a collection of identifiers,\n// select statements, function calls, literals, and comprehensions. All\n// operators with the exception of the '.' operator are modelled as function\n// calls. This makes it easy to represent new operators into the existing AST.\n//\n// All references within expressions must resolve to a\n// [Decl][google.api.expr.v1alpha1.Decl] provided at type-check for an\n// expression to be valid. A reference may either be a bare identifier `name` or\n// a qualified identifier `google.api.name`. References may either refer to a\n// value or a function declaration.\n//\n// For example, the expression `google.api.name.startsWith('expr')` references\n// the declaration `google.api.name` within a\n// [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression, and the\n// function declaration `startsWith`.\nmessage Expr {\n  // An identifier expression. e.g. `request`.\n  message Ident {\n    // Required. Holds a single, unqualified identifier, possibly preceded by a\n    // '.'.\n    //\n    // Qualified names are represented by the\n    // [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression.\n    string name = 1;\n  }\n  // A field selection expression. e.g. `request.auth`.\n  message Select {\n    // Required. The target of the selection expression.\n    //\n    // For example, in the select expression `request.auth`, the `request`\n    // portion of the expression is the `operand`.\n    Expr operand = 1;\n    // Required. The name of the field to select.\n    //\n    // For example, in the select expression `request.auth`, the `auth` portion\n    // of the expression would be the `field`.\n    string field = 2;\n    // Whether the select is to be interpreted as a field presence test.\n    //\n    // This results from the macro `has(request.auth)`.\n    bool test_only = 3;\n  }\n  // A call expression, including calls to predefined functions and operators.\n  //\n  // For example, `value == 10`, `size(map_value)`.\n  message Call {\n    // The target of an method call-style expression. For example, `x` in\n    // `x.f()`.\n    Expr target = 1;\n    // Required. The name of the function or method being called.\n    string function = 2;\n    // The arguments.\n    repeated Expr args = 3;\n  }\n  // A list creation expression.\n  //\n  // Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g.\n  // `dyn([1, 'hello', 2.0])`\n  message CreateList {\n    // The elements part of the list.\n    repeated Expr elements = 1;\n    // The indices within the elements list which are marked as optional\n    // elements.\n    //\n    // When an optional-typed value is present, the value it contains\n    // is included in the list. If the optional-typed value is absent, the list\n    // element is omitted from the CreateList result.\n    repeated int32 optional_indices = 2;\n  }\n  // A map or message creation expression.\n  //\n  // Maps are constructed as `{'key_name': 'value'}`. Message construction is\n  // similar, but prefixed with a type name and composed of field ids:\n  // `types.MyType{field_id: 'value'}`.\n  message CreateStruct {\n    // Represents an entry.\n    message Entry {\n      // Required. An id assigned to this node by the parser which is unique\n      // in a given expression tree. This is used to associate type\n      // information and other attributes to the node.\n      int64 id = 1;\n      // The `Entry` key kinds.\n      oneof key_kind {\n        // The field key for a message creator statement.\n        string field_key = 2;\n        // The key expression for a map creation statement.\n        Expr map_key = 3;\n      }\n      // Required. The value assigned to the key.\n      //\n      // If the optional_entry field is true, the expression must resolve to an\n      // optional-typed value. If the optional value is present, the key will be\n      // set; however, if the optional value is absent, the key will be unset.\n      Expr value = 4;\n      // Whether the key-value pair is optional.\n      bool optional_entry = 5;\n    }\n    // The type name of the message to be created, empty when creating map\n    // literals.\n    string message_name = 1;\n    // The entries in the creation expression.\n    repeated Entry entries = 2;\n  }\n  // A comprehension expression applied to a list or map.\n  //\n  // Comprehensions are not part of the core syntax, but enabled with macros.\n  // A macro matches a specific call signature within a parsed AST and replaces\n  // the call with an alternate AST block. Macro expansion happens at parse\n  // time.\n  //\n  // The following macros are supported within CEL:\n  //\n  // Aggregate type macros may be applied to all elements in a list or all keys\n  // in a map:\n  //\n  // *  `all`, `exists`, `exists_one` -  test a predicate expression against\n  //    the inputs and return `true` if the predicate is satisfied for all,\n  //    any, or only one value `list.all(x, x < 10)`.\n  // *  `filter` - test a predicate expression against the inputs and return\n  //    the subset of elements which satisfy the predicate:\n  //    `payments.filter(p, p > 1000)`.\n  // *  `map` - apply an expression to all elements in the input and return the\n  //    output aggregate type: `[1, 2, 3].map(i, i * i)`.\n  //\n  // The `has(m.x)` macro tests whether the property `x` is present in struct\n  // `m`. The semantics of this macro depend on the type of `m`. For proto2\n  // messages `has(m.x)` is defined as 'defined, but not set`. For proto3, the\n  // macro tests whether the property is set to its default. For map and struct\n  // types, the macro tests whether the property `x` is defined on `m`.\n  message Comprehension {\n    // The name of the iteration variable.\n    string iter_var = 1;\n    // The range over which var iterates.\n    Expr iter_range = 2;\n    // The name of the variable used for accumulation of the result.\n    string accu_var = 3;\n    // The initial value of the accumulator.\n    Expr accu_init = 4;\n    // An expression which can contain iter_var and accu_var.\n    //\n    // Returns false when the result has been computed and may be used as\n    // a hint to short-circuit the remainder of the comprehension.\n    Expr loop_condition = 5;\n    // An expression which can contain iter_var and accu_var.\n    //\n    // Computes the next value of accu_var.\n    Expr loop_step = 6;\n    // An expression which can contain accu_var.\n    //\n    // Computes the result.\n    Expr result = 7;\n  }\n  // Required. An id assigned to this node by the parser which is unique in a\n  // given expression tree. This is used to associate type information and other\n  // attributes to a node in the parse tree.\n  int64 id = 2;\n  // Required. Variants of expressions.\n  oneof expr_kind {\n    // A literal expression.\n    Constant const_expr = 3;\n    // An identifier expression.\n    Ident ident_expr = 4;\n    // A field selection expression, e.g. `request.auth`.\n    Select select_expr = 5;\n    // A call expression, including calls to predefined functions and operators.\n    Call call_expr = 6;\n    // A list creation expression.\n    CreateList list_expr = 7;\n    // A map or message creation expression.\n    CreateStruct struct_expr = 8;\n    // A comprehension expression.\n    Comprehension comprehension_expr = 9;\n  }\n}\n\n// Represents a primitive literal.\n//\n// Named 'Constant' here for backwards compatibility.\n//\n// This is similar as the primitives supported in the well-known type\n// `google.protobuf.Value`, but richer so it can represent CEL's full range of\n// primitives.\n//\n// Lists and structs are not included as constants as these aggregate types may\n// contain [Expr][google.api.expr.v1alpha1.Expr] elements which require\n// evaluation and are thus not constant.\n//\n// Examples of literals include: `\"hello\"`, `b'bytes'`, `1u`, `4.2`, `-2`,\n// `true`, `null`.\nmessage Constant {\n  // Required. The valid constant kinds.\n  oneof constant_kind {\n    // null value.\n    google.protobuf.NullValue null_value = 1;\n    // boolean value.\n    bool bool_value = 2;\n    // int64 value.\n    int64 int64_value = 3;\n    // uint64 value.\n    uint64 uint64_value = 4;\n    // double value.\n    double double_value = 5;\n    // string value.\n    string string_value = 6;\n    // bytes value.\n    bytes bytes_value = 7;\n    // protobuf.Duration value.\n    //\n    // Deprecated: duration is no longer considered a builtin cel type.\n    google.protobuf.Duration duration_value = 8 [deprecated = true];\n    // protobuf.Timestamp value.\n    //\n    // Deprecated: timestamp is no longer considered a builtin cel type.\n    google.protobuf.Timestamp timestamp_value = 9 [deprecated = true];\n  }\n}\n\n// Source information collected at parse time.\nmessage SourceInfo {\n  // An extension that was requested for the source expression.\n  message Extension {\n    // Version\n    message Version {\n      // Major version changes indicate different required support level from\n      // the required components.\n      int64 major = 1;\n      // Minor version changes must not change the observed behavior from\n      // existing implementations, but may be provided informationally.\n      int64 minor = 2;\n    }\n    // CEL component specifier.\n    enum Component {\n      // Unspecified, default.\n      COMPONENT_UNSPECIFIED = 0;\n      // Parser. Converts a CEL string to an AST.\n      COMPONENT_PARSER = 1;\n      // Type checker. Checks that references in an AST are defined and types\n      // agree.\n      COMPONENT_TYPE_CHECKER = 2;\n      // Runtime. Evaluates a parsed and optionally checked CEL AST against a\n      // context.\n      COMPONENT_RUNTIME = 3;\n    }\n    // Identifier for the extension. Example: constant_folding\n    string id = 1;\n    // If set, the listed components must understand the extension for the\n    // expression to evaluate correctly.\n    //\n    // This field has set semantics, repeated values should be deduplicated.\n    repeated Component affected_components = 2;\n    // Version info. May be skipped if it isn't meaningful for the extension.\n    // (for example constant_folding might always be v0.0).\n    Version version = 3;\n  }\n  // The syntax version of the source, e.g. `cel1`.\n  string syntax_version = 1;\n  // The location name. All position information attached to an expression is\n  // relative to this location.\n  //\n  // The location could be a file, UI element, or similar. For example,\n  // `acme/app/AnvilPolicy.cel`.\n  string location = 2;\n  // Monotonically increasing list of code point offsets where newlines\n  // `\\n` appear.\n  //\n  // The line number of a given position is the index `i` where for a given\n  // `id` the `line_offsets[i] < id_positions[id] < line_offsets[i+1]`. The\n  // column may be derivd from `id_positions[id] - line_offsets[i]`.\n  repeated int32 line_offsets = 3;\n  // A map from the parse node id (e.g. `Expr.id`) to the code point offset\n  // within the source.\n  map<int64, int32> positions = 4;\n  // A map from the parse node id where a macro replacement was made to the\n  // call `Expr` that resulted in a macro expansion.\n  //\n  // For example, `has(value.field)` is a function call that is replaced by a\n  // `test_only` field selection in the AST. Likewise, the call\n  // `list.exists(e, e > 10)` translates to a comprehension expression. The key\n  // in the map corresponds to the expression id of the expanded macro, and the\n  // value is the call `Expr` that was replaced.\n  map<int64, Expr> macro_calls = 5;\n  // A list of tags for extensions that were used while parsing or type checking\n  // the source expression. For example, optimizations that require special\n  // runtime support may be specified.\n  //\n  // These are used to check feature support between components in separate\n  // implementations. This can be used to either skip redundant work or\n  // report an error if the extension is unsupported.\n  repeated Extension extensions = 6;\n}\n\n// A specific position in source.\nmessage SourcePosition {\n  // The soucre location name (e.g. file name).\n  string location = 1;\n  // The UTF-8 code unit offset.\n  int32 offset = 2;\n  // The 1-based index of the starting line in the source text\n  // where the issue occurs, or 0 if unknown.\n  int32 line = 3;\n  // The 0-based index of the starting position within the line of source text\n  // where the issue occurs.  Only meaningful if line is nonzero.\n  int32 column = 4;\n}\n"
  },
  {
    "path": "api/vendor/google/api/expr/v1alpha1/value.proto",
    "content": "// Copyright 2024 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.api.expr.v1alpha1;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr\";\noption java_multiple_files = true;\noption java_outer_classname = \"ValueProto\";\noption java_package = \"com.google.api.expr.v1alpha1\";\n\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/struct.proto\";\n\n// Contains representations for CEL runtime values.\n\n// Represents a CEL value.\n//\n// This is similar to `google.protobuf.Value`, but can represent CEL's full\n// range of values.\nmessage Value {\n  // Required. The valid kinds of values.\n  oneof kind {\n    // Null value.\n    google.protobuf.NullValue null_value = 1;\n    // Boolean value.\n    bool bool_value = 2;\n    // Signed integer value.\n    int64 int64_value = 3;\n    // Unsigned integer value.\n    uint64 uint64_value = 4;\n    // Floating point value.\n    double double_value = 5;\n    // UTF-8 string value.\n    string string_value = 6;\n    // Byte string value.\n    bytes bytes_value = 7;\n    // An enum value.\n    EnumValue enum_value = 9;\n    // The proto message backing an object value.\n    google.protobuf.Any object_value = 10;\n    // Map value.\n    MapValue map_value = 11;\n    // List value.\n    ListValue list_value = 12;\n    // Type value.\n    string type_value = 15;\n  }\n}\n\n// An enum value.\nmessage EnumValue {\n  // The fully qualified name of the enum type.\n  string type = 1;\n  // The value of the enum.\n  int32 value = 2;\n}\n\n// A list.\n//\n// Wrapped in a message so 'not set' and empty can be differentiated, which is\n// required for use in a 'oneof'.\nmessage ListValue {\n  // The ordered values in the list.\n  repeated Value values = 1;\n}\n\n// A map.\n//\n// Wrapped in a message so 'not set' and empty can be differentiated, which is\n// required for use in a 'oneof'.\nmessage MapValue {\n  // An entry in the map.\n  message Entry {\n    // The key.\n    //\n    // Must be unique with in the map.\n    // Currently only boolean, int, uint, and string values can be keys.\n    Value key = 1;\n    // The value.\n    Value value = 2;\n  }\n  // The set of map entries.\n  //\n  // CEL has fewer restrictions on keys, so a protobuf map representation\n  // cannot be used.\n  repeated Entry entries = 1;\n}\n"
  },
  {
    "path": "api/vendor/google/rpc/status.proto",
    "content": "// Copyright 2020 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage google.rpc;\n\noption cc_enable_arenas = true;\noption go_package = \"google.golang.org/genproto/googleapis/rpc/status;status\";\noption java_multiple_files = true;\noption java_outer_classname = \"StatusProto\";\noption java_package = \"com.google.rpc\";\noption objc_class_prefix = \"RPC\";\n\nimport \"google/protobuf/any.proto\";\n\n// The `Status` type defines a logical error model that is suitable for\n// different programming environments, including REST APIs and RPC APIs. It is\n// used by [gRPC](https://github.com/grpc). Each `Status` message contains\n// three pieces of data: error code, error message, and error details.\n//\n// You can find out more about this error model and how to work with it in the\n// [API Design Guide](https://cloud.google.com/apis/design/errors).\nmessage Status {\n  // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code].\n  int32 code = 1;\n  // A developer-facing error message, which should be in English. Any\n  // user-facing error message should be localized and sent in the\n  // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client.\n  string message = 2;\n  // A list of messages that carry the error details.  There is a common set of\n  // message types for APIs to use.\n  repeated google.protobuf.Any details = 3;\n}\n"
  },
  {
    "path": "cmd/installer/cmd/imager/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package imager implements the imager command.\npackage imager\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/pkg/install\"\n\t\"github.com/siderolabs/talos/pkg/archiver\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/imager\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nvar cmdFlags struct {\n\tPlatform string\n\tArch     string\n\t// Insecure can be set to true to force pull from insecure registry.\n\tInsecure              bool\n\tExtraKernelArgs       []string\n\tMetaValues            install.MetaValues\n\tSystemExtensionImages []string\n\tBaseInstallerImage    string\n\tImageCache            string\n\tEmbeddedConfigPath    string\n\tOutputPath            string\n\tOutputKind            string\n\tTarToStdout           bool\n\tOverlayName           string\n\tOverlayImage          string\n\tOverlayOptions        []string\n\t// Only used when generating a secure boot iso without also providing a secure boot database.\n\tSecurebootIncludeWellKnownCerts bool\n}\n\n// rootCmd represents the base command when called without any subcommands.\nvar rootCmd = &cobra.Command{\n\tUse:          \"imager <profile>|-\",\n\tShort:        \"Generate various boot assets and images.\",\n\tLong:         ``,\n\tArgs:         cobra.ExactArgs(1),\n\tSilenceUsage: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn cli.WithContext(context.Background(), func(ctx context.Context) error {\n\t\t\treport := reporter.New()\n\t\t\treport.Report(reporter.Update{\n\t\t\t\tMessage: \"assembling the finalized profile...\",\n\t\t\t\tStatus:  reporter.StatusRunning,\n\t\t\t})\n\n\t\t\tbaseProfile := args[0]\n\n\t\t\tvar prof profile.Profile\n\n\t\t\tif baseProfile == \"-\" {\n\t\t\t\tif err := yaml.NewDecoder(os.Stdin).Decode(&prof); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tprof = profile.Profile{\n\t\t\t\t\tBaseProfileName: baseProfile,\n\t\t\t\t\tArch:            cmdFlags.Arch,\n\t\t\t\t\tPlatform:        cmdFlags.Platform,\n\t\t\t\t\tCustomization: profile.CustomizationProfile{\n\t\t\t\t\t\tExtraKernelArgs: cmdFlags.ExtraKernelArgs,\n\t\t\t\t\t\tMetaContents:    cmdFlags.MetaValues.GetMetaValues(),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\textraOverlayOptions := overlay.ExtraOptions{}\n\n\t\t\t\tfor _, option := range cmdFlags.OverlayOptions {\n\t\t\t\t\tif strings.HasPrefix(option, \"@\") {\n\t\t\t\t\t\tdata, err := os.ReadFile(option[1:])\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdecoder := yaml.NewDecoder(bytes.NewReader(data))\n\t\t\t\t\t\tdecoder.KnownFields(true)\n\n\t\t\t\t\t\tif err := decoder.Decode(&extraOverlayOptions); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tk, v, _ := strings.Cut(option, \"=\")\n\n\t\t\t\t\tif strings.HasPrefix(v, \"@\") {\n\t\t\t\t\t\tdata, err := os.ReadFile(v[1:])\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tv = string(data)\n\t\t\t\t\t}\n\n\t\t\t\t\textraOverlayOptions[k] = v\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.OverlayName != \"\" || cmdFlags.OverlayImage != \"\" {\n\t\t\t\t\tprof.Overlay = &profile.OverlayOptions{\n\t\t\t\t\t\tName: cmdFlags.OverlayName,\n\t\t\t\t\t\tImage: profile.ContainerAsset{\n\t\t\t\t\t\t\tImageRef: cmdFlags.OverlayImage,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExtraOptions: extraOverlayOptions,\n\t\t\t\t\t}\n\n\t\t\t\t\tprof.Input.OverlayInstaller.ImageRef = cmdFlags.OverlayImage\n\t\t\t\t}\n\n\t\t\t\tprof.Input.SystemExtensions = xslices.Map(\n\t\t\t\t\tcmdFlags.SystemExtensionImages,\n\t\t\t\t\tfunc(imageRef string) profile.ContainerAsset {\n\t\t\t\t\t\treturn profile.ContainerAsset{\n\t\t\t\t\t\t\tImageRef:      imageRef,\n\t\t\t\t\t\t\tForceInsecure: cmdFlags.Insecure,\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\tif cmdFlags.OutputKind != \"\" {\n\t\t\t\t\toutKind, err := profile.OutputKindString(cmdFlags.OutputKind)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tprof.Output.Kind = outKind\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.BaseInstallerImage != \"\" {\n\t\t\t\t\tprof.Input.BaseInstaller = profile.ContainerAsset{\n\t\t\t\t\t\tImageRef: cmdFlags.BaseInstallerImage,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.ImageCache != \"\" {\n\t\t\t\t\tparseOpts := []name.Option{name.StrictValidation}\n\n\t\t\t\t\tif cmdFlags.Insecure {\n\t\t\t\t\t\tparseOpts = append(parseOpts, name.Insecure)\n\t\t\t\t\t}\n\n\t\t\t\t\tif _, err := name.ParseReference(cmdFlags.ImageCache, parseOpts...); err == nil {\n\t\t\t\t\t\tprof.Input.ImageCache = profile.ContainerAsset{\n\t\t\t\t\t\t\tImageRef: cmdFlags.ImageCache,\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprof.Input.ImageCache = profile.ContainerAsset{\n\t\t\t\t\t\t\tOCIPath: cmdFlags.ImageCache,\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.Insecure {\n\t\t\t\t\tprof.Input.BaseInstaller.ForceInsecure = cmdFlags.Insecure\n\t\t\t\t\tprof.Input.ImageCache.ForceInsecure = cmdFlags.Insecure\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.SecurebootIncludeWellKnownCerts {\n\t\t\t\t\tif prof.Input.SecureBoot == nil {\n\t\t\t\t\t\tprof.Input.SecureBoot = &profile.SecureBootAssets{}\n\t\t\t\t\t}\n\n\t\t\t\t\tprof.Input.SecureBoot.IncludeWellKnownCerts = true\n\t\t\t\t}\n\n\t\t\t\tif cmdFlags.EmbeddedConfigPath != \"\" {\n\t\t\t\t\tdata, err := os.ReadFile(cmdFlags.EmbeddedConfigPath)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error reading embedded config file: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tprof.Customization.EmbeddedMachineConfiguration = string(data)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := os.MkdirAll(cmdFlags.OutputPath, 0o755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\timager, err := imager.New(prof)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif _, err = imager.Execute(ctx, cmdFlags.OutputPath, report); err != nil {\n\t\t\t\treport.Report(reporter.Update{\n\t\t\t\t\tMessage: err.Error(),\n\t\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\t})\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif cmdFlags.TarToStdout {\n\t\t\t\treturn archiver.TarGz(ctx, cmdFlags.OutputPath, os.Stdout)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\n// Execute adds all child commands to the root command and sets flags appropriately.\n// This is called by main.main(). It only needs to happen once to the rootCmd.\nfunc Execute() {\n\tif err := rootCmd.Execute(); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n\nfunc init() {\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.Platform, \"platform\", \"\", \"The value of \"+constants.KernelParamPlatform)\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.Arch, \"arch\", runtime.GOARCH, \"The target architecture\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.BaseInstallerImage, \"base-installer-image\", \"\", \"Base installer image to use\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.ImageCache, \"image-cache\", \"\", \"Image cache container image or oci path\")\n\trootCmd.PersistentFlags().BoolVar(&cmdFlags.Insecure, \"insecure\", false, \"Pull assets from insecure registry\")\n\trootCmd.PersistentFlags().StringArrayVar(&cmdFlags.ExtraKernelArgs, \"extra-kernel-arg\", []string{}, \"Extra argument to pass to the kernel\")\n\trootCmd.PersistentFlags().Var(&cmdFlags.MetaValues, \"meta\", \"A key/value pair for META\")\n\trootCmd.PersistentFlags().StringArrayVar(&cmdFlags.SystemExtensionImages, \"system-extension-image\", []string{}, \"The image reference to the system extension to install\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.OutputPath, \"output\", \"/out\", \"The output directory path\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.OutputKind, \"output-kind\", \"\", \"Override output kind\")\n\trootCmd.PersistentFlags().BoolVar(&cmdFlags.TarToStdout, \"tar-to-stdout\", false, \"Tar output and send to stdout\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.OverlayName, \"overlay-name\", \"\", \"The name of the overlay to use\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.OverlayImage, \"overlay-image\", \"\", \"The image reference to the overlay\")\n\trootCmd.PersistentFlags().StringArrayVar(&cmdFlags.OverlayOptions, \"overlay-option\", []string{}, \"Extra options to pass to the overlay\")\n\trootCmd.PersistentFlags().StringVar(&cmdFlags.EmbeddedConfigPath, \"embedded-config-path\", \"\", \"Path to a file containing the machine configuration to embed into the image\")\n\trootCmd.PersistentFlags().BoolVar(\n\t\t&cmdFlags.SecurebootIncludeWellKnownCerts, \"secureboot-include-well-known-certs\", false, \"Include well-known (Microsoft) UEFI certificates when generating a secure boot database\")\n}\n"
  },
  {
    "path": "cmd/installer/cmd/installer/install.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage installer\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/pkg/install\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// installCmd represents the installation command.\nvar installCmd = &cobra.Command{\n\tUse:   \"install\",\n\tShort: \"\",\n\tLong:  ``,\n\tRunE: func(cmd *cobra.Command, args []string) (err error) {\n\t\treturn runInstallCmd(cmd.Context())\n\t},\n}\n\nfunc init() {\n\trootCmd.AddCommand(installCmd)\n}\n\n//nolint:gocyclo\nfunc runInstallCmd(ctx context.Context) (err error) {\n\tlog.Printf(\"running Talos installer %s\", version.NewVersion().Tag)\n\n\tmode := install.ModeInstall\n\n\tif options.Upgrade {\n\t\tmode = install.ModeUpgrade\n\t}\n\n\tp, err := platform.NewPlatform(options.Platform)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconfig, err := configloader.NewFromStdin()\n\tif err != nil {\n\t\tif errors.Is(err, configloader.ErrNoConfig) {\n\t\t\tlog.Printf(\"machine configuration missing, skipping validation\")\n\n\t\t\t// machine configuration can be only missing while running an upgrade in maintenance mode, assume that we should follow GrubUseUKICmdline\n\t\t\toptions.GrubUseUKICmdline = true\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"error loading machine configuration: %w\", err)\n\t\t}\n\t} else {\n\t\tvar warnings []string\n\n\t\twarnings, err = config.Validate(p.Mode())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"machine configuration is invalid: %w\", err)\n\t\t}\n\n\t\tif len(warnings) > 0 {\n\t\t\tlog.Printf(\"WARNING: config validation:\")\n\n\t\t\tfor _, warning := range warnings {\n\t\t\t\tlog.Printf(\"  %s\", warning)\n\t\t\t}\n\t\t}\n\n\t\tif config.Machine() != nil && config.Machine().Install().LegacyBIOSSupport() {\n\t\t\toptions.LegacyBIOSSupport = true\n\t\t}\n\n\t\t// if we don't have v1alpha1 config (we are in maintenance mode),\n\t\t// or if we have v1alpha1 config, and GrubUseUKICmdline is set to true,\n\t\t// then we should set the option to true\n\t\tif config.Machine() == nil || config.Machine().Install().GrubUseUKICmdline() {\n\t\t\toptions.GrubUseUKICmdline = true\n\t\t}\n\t}\n\n\treturn install.Install(ctx, p, mode, options)\n}\n"
  },
  {
    "path": "cmd/installer/cmd/installer/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package installer implements the installer command.\npackage installer\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/pkg/install\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// rootCmd represents the base command when called without any subcommands.\nvar rootCmd = &cobra.Command{\n\tUse:   \"installer\",\n\tShort: \"\",\n\tLong:  ``,\n}\n\nfunc setFlagsFromEnvironment() error {\n\tif metaEnvBase64 := os.Getenv(constants.MetaValuesEnvVar); metaEnvBase64 != \"\" {\n\t\tif err := options.MetaValues.Decode(metaEnvBase64); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Execute adds all child commands to the root command and sets flags appropriately.\n// This is called by main.main(). It only needs to happen once to the rootCmd.\nfunc Execute() {\n\t// Set defaults for flags from the environment variables.\n\tif err := setFlagsFromEnvironment(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\n\tif err := rootCmd.Execute(); err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n}\n\nvar options = &install.Options{}\n\nfunc init() {\n\trootCmd.PersistentFlags().StringVar(&options.ConfigSource, \"config\", \"\", \"The value of \"+constants.KernelParamConfig)\n\trootCmd.PersistentFlags().StringVar(&options.DiskPath, \"disk\", \"\", \"The path to the disk to install to\")\n\trootCmd.PersistentFlags().StringVar(&options.Platform, \"platform\", \"\", \"The value of \"+constants.KernelParamPlatform)\n\trootCmd.PersistentFlags().StringVar(&options.Arch, \"arch\", runtime.GOARCH, \"The target architecture\")\n\trootCmd.PersistentFlags().StringArrayVar(&options.ExtraKernelArgs, \"extra-kernel-arg\", []string{}, \"Extra argument to pass to the kernel\")\n\trootCmd.PersistentFlags().BoolVar(&options.Upgrade, \"upgrade\", false, \"Indicates that the install is being performed by an upgrade\")\n\trootCmd.PersistentFlags().BoolVar(&options.Force, \"force\", false, \"Indicates that the install should forcefully format the partition\")\n\trootCmd.PersistentFlags().BoolVar(&options.Zero, \"zero\", false, \"Indicates that the install should write zeros to the disk before installing\")\n\trootCmd.PersistentFlags().Var(&options.MetaValues, \"meta\", \"A key/value pair for META\")\n}\n"
  },
  {
    "path": "cmd/installer/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package installer provides the installer implementation.\npackage main\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/cmd/imager\"\n\t\"github.com/siderolabs/talos/cmd/installer/cmd/installer\"\n)\n\nfunc main() {\n\tswitch filepath.Base(os.Args[0]) {\n\tcase \"imager\":\n\t\timager.Execute()\n\tdefault:\n\t\tinstaller.Execute()\n\t}\n}\n"
  },
  {
    "path": "cmd/installer/pkg/install/errata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// errataNetIfnames appends the `net.ifnames=0` kernel parameter to the kernel command line if upgrading\n// from an old enough version of Talos.\nfunc (i *Installer) errataNetIfnames(talosVersion *compatibility.TalosVersion) {\n\tif i.cmdline.Get(constants.KernelParamNetIfnames).First() != nil {\n\t\t// net.ifnames is already set, nothing to do\n\t\treturn\n\t}\n\n\toldTalos := upgradeFromPreIfnamesTalos(talosVersion)\n\n\tif oldTalos {\n\t\tlog.Printf(\"appending net.ifnames=0 to the kernel command line\")\n\n\t\ti.cmdline.Append(constants.KernelParamNetIfnames, \"0\")\n\t}\n}\n\nfunc readHostTalosVersion() (*compatibility.TalosVersion, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Minute)\n\tdefer cancel()\n\n\tif _, err := os.Stat(constants.MachineSocketPath); err != nil {\n\t\t// can't read Talos version\n\t\treturn nil, nil\n\t}\n\n\tc, err := client.New(ctx,\n\t\tclient.WithUnixSocket(constants.MachineSocketPath),\n\t\tclient.WithGRPCDialOptions(\n\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error connecting to the machine service: %w\", err)\n\t}\n\n\tdefer c.Close() //nolint:errcheck\n\n\t// inject \"fake\" authorization\n\tctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(constants.APIAuthzRoleMetadataKey, string(role.Admin)))\n\n\tresp, err := c.Version(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting Talos version: %w\", err)\n\t}\n\n\thostVersion := unpack(resp.Messages)\n\n\ttalosVersion, err := compatibility.ParseTalosVersion(hostVersion.Version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing Talos version: %w\", err)\n\t}\n\n\treturn talosVersion, nil\n}\n\nfunc upgradeFromPreIfnamesTalos(talosVersion *compatibility.TalosVersion) bool {\n\tif talosVersion == nil {\n\t\t// old Talos version, include fallback\n\t\treturn true\n\t}\n\n\treturn talosVersion.DisablePredictableNetworkInterfaces()\n}\n"
  },
  {
    "path": "cmd/installer/pkg/install/install.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package install provides the installation routine.\npackage install\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tbootloaderpkg \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n\tbootloaderoptions \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/imager/overlay/executor\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\tmetaconsts \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\n// Options represents the set of options available for an install.\ntype Options struct {\n\tConfigSource string\n\t// Can be an actual disk path or a file representing a disk image.\n\tDiskPath            string\n\tPlatform            string\n\tArch                string\n\tExtraKernelArgs     []string\n\tUpgrade             bool\n\tForce               bool\n\tZero                bool\n\tLegacyBIOSSupport   bool\n\tGrubUseUKICmdline   bool\n\tMetaValues          MetaValues\n\tOverlayInstaller    overlay.Installer[overlay.ExtraOptions]\n\tOverlayName         string\n\tOverlayExtractedDir string\n\tExtraOptions        overlay.ExtraOptions\n\n\tImageCachePath string\n\tImageCacheSize int64\n\n\t// Options specific for the image creation mode.\n\tImageSecureboot     bool\n\tDiskImageBootloader string\n\tVersion             string\n\tBootAssets          bootloaderoptions.BootAssets\n\tPrintf              func(string, ...any)\n\tMountPrefix         string\n}\n\n// Mode is the install mode.\ntype Mode int\n\nconst (\n\t// ModeInstall is the install mode.\n\tModeInstall Mode = iota\n\t// ModeUpgrade is the upgrade mode.\n\tModeUpgrade\n\t// ModeImage is the image creation mode.\n\tModeImage\n)\n\n// IsImage returns true if the mode is image creation.\nfunc (m Mode) IsImage() bool {\n\treturn m == ModeImage\n}\n\nconst typeGPT = \"gpt\"\n\n// diskImageLabel is used as a label to generate a deterministic GPT UUID for disk images.\nconst diskImageLabel = \"talos-image-disk\"\n\n// Install installs Talos.\n//\n//nolint:gocyclo\nfunc Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options) error {\n\tif overlayPresent() {\n\t\textraOptionsBytes, err := os.ReadFile(constants.ImagerOverlayExtraOptionsPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar extraOptions overlay.ExtraOptions\n\n\t\tdecoder := yaml.NewDecoder(bytes.NewReader(extraOptionsBytes))\n\t\tdecoder.KnownFields(true)\n\n\t\tif err := decoder.Decode(&extraOptions); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decode extra options: %w\", err)\n\t\t}\n\n\t\topts.OverlayInstaller = executor.New(constants.ImagerOverlayInstallerDefaultPath)\n\t\topts.ExtraOptions = extraOptions\n\t}\n\n\t// NOTE: this is legacy code which is only used when running in GRUB mode with GrubUseUKICmdline set to false.\n\tcmdline := procfs.NewCmdline(\"\")\n\tcmdline.Append(constants.KernelParamPlatform, p.Name())\n\n\tif opts.ConfigSource != \"\" {\n\t\tcmdline.Append(constants.KernelParamConfig, opts.ConfigSource)\n\t}\n\n\tcmdline.SetAll(p.KernelArgs(opts.Arch, quirks.Quirks{}).Strings())\n\n\t// first defaults, then extra kernel args to allow extra kernel args to override defaults\n\tif err := cmdline.AppendAll(kernel.DefaultArgs(quirks.Quirks{})); err != nil {\n\t\treturn err\n\t}\n\n\tif opts.OverlayInstaller != nil {\n\t\toverlayOpts, getOptsErr := opts.OverlayInstaller.GetOptions(ctx, opts.ExtraOptions)\n\t\tif getOptsErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to get overlay installer options: %w\", getOptsErr)\n\t\t}\n\n\t\topts.OverlayName = overlayOpts.Name\n\n\t\tcmdline.SetAll(overlayOpts.KernelArgs)\n\t}\n\n\t// preserve console=ttyS0 if it was already present in cmdline for metal platform\n\texistingCmdline := procfs.ProcCmdline()\n\n\tif *existingCmdline.Get(constants.KernelParamPlatform).First() == constants.PlatformMetal && existingCmdline.Get(\"console\").Contains(\"ttyS0\") {\n\t\tif !slices.Contains(opts.ExtraKernelArgs, \"console=ttyS0\") {\n\t\t\tcmdline.Append(\"console\", \"ttyS0\")\n\t\t}\n\t}\n\n\tif err := cmdline.AppendAll(\n\t\topts.ExtraKernelArgs,\n\t\tprocfs.WithOverwriteArgs(\"console\"),\n\t\tprocfs.WithOverwriteArgs(constants.KernelParamPlatform),\n\t\tprocfs.WithDeleteNegatedArgs(),\n\t); err != nil {\n\t\treturn err\n\t}\n\n\ti, err := NewInstaller(ctx, cmdline, mode, opts)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = i.Install(ctx, mode); err != nil {\n\t\treturn err\n\t}\n\n\ti.options.Printf(\"installation of %s complete\", version.Tag)\n\n\treturn nil\n}\n\n// Installer represents the installer logic. It serves as the entrypoint to all\n// installation methods.\ntype Installer struct {\n\tcmdline *procfs.Cmdline\n\toptions *Options\n}\n\n// NewInstaller initializes and returns an Installer.\nfunc NewInstaller(ctx context.Context, cmdline *procfs.Cmdline, mode Mode, opts *Options) (i *Installer, err error) {\n\ti = &Installer{\n\t\tcmdline: cmdline,\n\t\toptions: opts,\n\t}\n\n\tif i.options.Version == \"\" {\n\t\ti.options.Version = version.Tag\n\t}\n\n\tif i.options.Printf == nil {\n\t\ti.options.Printf = log.Printf\n\t}\n\n\tif mode == ModeUpgrade && i.options.Force {\n\t\ti.options.Printf(\"system disk wipe on upgrade is not supported anymore, option ignored\")\n\t}\n\n\tif i.options.Zero && mode != ModeInstall {\n\t\ti.options.Printf(\"zeroing of the disk is only supported for the initial installation, option ignored\")\n\t}\n\n\ti.options.BootAssets.FillDefaults(opts.Arch)\n\n\treturn i, nil\n}\n\n// detectBootloader detects the bootloader to use based on the mode.\nfunc (i *Installer) detectBootloader(mode Mode) (bootloaderpkg.Bootloader, error) {\n\tswitch mode {\n\tcase ModeInstall:\n\t\treturn bootloaderpkg.NewAuto(), nil\n\tcase ModeUpgrade:\n\t\treturn bootloaderpkg.Probe(i.options.DiskPath, bootloaderoptions.ProbeOptions{\n\t\t\t// the disk is already locked\n\t\t\tBlockProbeOptions: []blkid.ProbeOption{\n\t\t\t\tblkid.WithSkipLocking(true),\n\t\t\t},\n\t\t\tLogger: log.Printf,\n\t\t})\n\tcase ModeImage:\n\t\treturn bootloaderpkg.New(i.options.DiskImageBootloader, i.options.Version, i.options.Arch)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\n// diskOperations performs any disk operations required before installation.\n//\n//nolint:gocyclo\nfunc (i *Installer) diskOperations(mode Mode, bd *block.Device, info *blkid.Info) error {\n\tswitch mode {\n\tcase ModeInstall:\n\t\tif !i.options.Zero && !i.options.Force {\n\t\t\t// verify that the disk is either empty or has an empty GPT partition table, otherwise fail the install\n\t\t\tswitch {\n\t\t\tcase info.Name == \"\":\n\t\t\t\t// empty, ok\n\t\t\tcase info.Name == typeGPT && len(info.Parts) == 0:\n\t\t\t\t// GPT, no partitions, ok\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"disk %s is not empty, skipping install, detected %q\", i.options.DiskPath, info.Name)\n\t\t\t}\n\t\t} else {\n\t\t\t// zero the disk\n\t\t\tif err := bd.FastWipe(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to zero blockdevice %s: %w\", i.options.DiskPath, err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\tcase ModeUpgrade:\n\t\t// on upgrade, we don't touch the disk partitions, but we need to verify that the disk has the expected GPT partition table\n\t\tif info.Name != typeGPT {\n\t\t\treturn fmt.Errorf(\"disk %s has an unexpected format %q\", i.options.DiskPath, info.Name)\n\t\t}\n\n\t\treturn nil\n\tcase ModeImage:\n\t\t// no disk operations required for image creation\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\n// blockDeviceData opens and locks the block device and probes it.\n// the caller is responsible for unlocking and closing the block device.\nfunc (i *Installer) blockDeviceData(mode Mode) (*block.Device, *blkid.Info, error) {\n\t// open and lock the blockdevice for the installation disk for the whole duration of the installer\n\tbd, err := block.NewFromPath(i.options.DiskPath, block.OpenForWrite())\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to open blockdevice %s: %w\", i.options.DiskPath, err)\n\t}\n\n\tif err = bd.Lock(true); err != nil {\n\t\tbd.Close() //nolint:errcheck\n\n\t\treturn nil, nil, fmt.Errorf(\"failed to lock blockdevice %s: %w\", i.options.DiskPath, err)\n\t}\n\n\tswitch mode {\n\tcase ModeInstall, ModeUpgrade:\n\t\tinfo, err := blkid.Probe(bd.File(), blkid.WithSkipLocking(true))\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to probe blockdevice %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\treturn bd, info, nil\n\tcase ModeImage:\n\t\tinfo, err := blkid.ProbePath(i.options.DiskPath, blkid.WithSkipLocking(true))\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to probe blockdevice %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\treturn bd, info, nil\n\tdefault:\n\t\treturn nil, nil, fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\n// Install fetches the necessary data locations and copies or extracts\n// to the target locations.\n//\n//nolint:gocyclo,cyclop\nfunc (i *Installer) Install(ctx context.Context, mode Mode) (err error) {\n\t// pre-flight checks, erratas\n\thostTalosVersion, err := readHostTalosVersion()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif mode == ModeUpgrade {\n\t\ti.errataNetIfnames(hostTalosVersion)\n\t}\n\n\tif err = i.runPreflightChecks(mode); err != nil {\n\t\treturn err\n\t}\n\n\tbootlder, err := i.detectBootloader(mode)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to detect bootloader: %w\", err)\n\t}\n\n\tbootPartitions, err := i.getBootPartitions(ctx, mode, bootlder)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get bootloader partitions: %w\", err)\n\t}\n\n\t// create an exclusive lock on the disk and perform necessary disk operations\n\t// this lock will be held for the whole duration of the installation\n\t// this is necessary to prevent other processes from interfering with the installation like udevd\n\t// otherwise udevd might remove and re-add partition device nodes while we are using them\n\tbd, info, err := i.blockDeviceData(mode)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get blockdevice data: %w\", err)\n\t}\n\n\tdefer bd.Unlock() //nolint:errcheck\n\tdefer bd.Close()  //nolint:errcheck\n\n\tif err = i.diskOperations(mode, bd, info); err != nil {\n\t\treturn fmt.Errorf(\"failed to perform disk operations: %w\", err)\n\t}\n\n\t// create partitions and re-probe the device\n\tpartitionOptions, err := i.createPartitions(ctx, mode, bd, hostTalosVersion, bootPartitions)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create partitions: %w\", err)\n\t}\n\n\tif err := i.formatPartitions(ctx, mode, partitionOptions); err != nil {\n\t\treturn fmt.Errorf(\"failed to format partitions: %w\", err)\n\t}\n\n\t// re-probe the device to get updated partition information\n\tinfo, err = blkid.ProbePath(i.options.DiskPath, blkid.WithSkipLocking(true))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to probe blockdevice %s: %w\", i.options.DiskPath, err)\n\t}\n\n\tbootInstallResult, err := i.installBootloader(ctx, mode, bootlder, info)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to install bootloader: %w\", err)\n\t}\n\n\tif err = i.handleMeta(ctx, mode, bootInstallResult.PreviousLabel, info); err != nil {\n\t\treturn fmt.Errorf(\"failed to handle META partition: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *Installer) handleMeta(ctx context.Context, mode Mode, previousLabel string, info *blkid.Info) error {\n\tswitch mode {\n\tcase ModeInstall, ModeUpgrade:\n\t\tvar metaPartitionName string\n\n\t\tfor _, partition := range info.Parts {\n\t\t\tif pointer.SafeDeref(partition.PartitionLabel) == constants.MetaPartitionLabel {\n\t\t\t\tmetaPartitionName = partitioning.DevName(i.options.DiskPath, partition.PartitionIndex)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif metaPartitionName == \"\" {\n\t\t\treturn errors.New(\"failed to detect META partition\")\n\t\t}\n\n\t\tmetaState, err := meta.New(ctx, nil, meta.WithPrinter(i.options.Printf), meta.WithFixedPath(metaPartitionName))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open META: %w\", err)\n\t\t}\n\n\t\tif mode == ModeUpgrade {\n\t\t\tif ok, err := metaState.SetTag(ctx, metaconsts.Upgrade, previousLabel); !ok || err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to set upgrade tag: %q\", previousLabel)\n\t\t\t}\n\t\t}\n\n\t\tfor _, v := range i.options.MetaValues.values {\n\t\t\tif ok, err := metaState.SetTag(ctx, v.Key, v.Value); !ok || err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to set meta tag: %q -> %q\", v.Key, v.Value)\n\t\t\t}\n\t\t}\n\n\t\tif err := metaState.Flush(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to flush META: %w\", err)\n\t\t}\n\n\t\treturn nil\n\tcase ModeImage:\n\t\tif i.options.MetaValues.values == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tf, err := os.OpenFile(i.options.DiskPath, os.O_RDWR, 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tgptdev, err := gpt.DeviceFromFile(f)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize GPT device from image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tpt, err := gpt.Read(gptdev)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read GPT from image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tmetaPartitionInfo := xslices.Filter(info.Parts, func(pr blkid.NestedProbeResult) bool {\n\t\t\treturn pointer.SafeDeref(pr.PartitionLabel) == constants.MetaPartitionLabel\n\t\t})\n\n\t\tif len(metaPartitionInfo) == 0 {\n\t\t\treturn errors.New(\"failed to detect META partition\")\n\t\t}\n\n\t\tmetaPartitionIndex := int(metaPartitionInfo[0].PartitionIndex) - 1\n\n\t\tmetaFilePath := filepath.Join(i.options.MountPrefix, \"meta.img\")\n\n\t\tif err := utils.CreateRawDisk(i.options.Printf, metaFilePath, int64(metaPartitionInfo[0].PartitionSize), true); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create meta image file: %w\", err)\n\t\t}\n\n\t\tmetaState, err := meta.New(ctx, nil, meta.WithPrinter(i.options.Printf), meta.WithFixedPath(metaFilePath))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open META: %w\", err)\n\t\t}\n\n\t\tfor _, v := range i.options.MetaValues.values {\n\t\t\tif ok, err := metaState.SetTag(ctx, v.Key, v.Value); !ok || err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to set meta tag: %q -> %q\", v.Key, v.Value)\n\t\t\t}\n\t\t}\n\n\t\tif err := metaState.Flush(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to flush META: %w\", err)\n\t\t}\n\n\t\tmetaFile, err := os.Open(metaFilePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open meta image file: %w\", err)\n\t\t}\n\n\t\tdefer metaFile.Close() //nolint:errcheck\n\n\t\tpw, pSize, err := pt.PartitionWriter(metaPartitionIndex)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get partition writer for META partition: %w\", err)\n\t\t}\n\n\t\tmetaFileInfo, err := metaFile.Stat()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to stat meta image file: %w\", err)\n\t\t}\n\n\t\tif metaFileInfo.Size() != int64(pSize) {\n\t\t\treturn fmt.Errorf(\"META partition size mismatch: image size %d, partition size %d\", metaFileInfo.Size(), pSize)\n\t\t}\n\n\t\tif _, err := io.Copy(pw, metaFile); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write back META partition data: %w\", err)\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\nfunc (i *Installer) generateBootloaderOptions(ctx context.Context, mode Mode, info *blkid.Info) bootloaderoptions.InstallOptions {\n\treturn bootloaderoptions.InstallOptions{\n\t\tBootDisk:          i.options.DiskPath,\n\t\tArch:              i.options.Arch,\n\t\tCmdline:           i.cmdline.String(),\n\t\tGrubUseUKICmdline: i.options.GrubUseUKICmdline,\n\t\tVersion:           i.options.Version,\n\t\tImageMode:         mode.IsImage(),\n\t\tBootAssets:        i.options.BootAssets,\n\t\tPrintf:            i.options.Printf,\n\t\tMountPrefix:       i.options.MountPrefix,\n\t\tBlkidInfo:         info,\n\n\t\tExtraInstallStep: func() error {\n\t\t\tif i.options.OverlayInstaller != nil {\n\t\t\t\ti.options.Printf(\"running overlay installer %q\", i.options.OverlayName)\n\n\t\t\t\tif err := i.options.OverlayInstaller.Install(ctx, overlay.InstallOptions[overlay.ExtraOptions]{\n\t\t\t\t\tInstallDisk:   i.options.DiskPath,\n\t\t\t\t\tMountPrefix:   i.options.MountPrefix,\n\t\t\t\t\tArtifactsPath: filepath.Join(i.options.OverlayExtractedDir, constants.ImagerOverlayArtifactsPath),\n\t\t\t\t\tExtraOptions:  i.options.ExtraOptions,\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to run overlay installer: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n}\n\nfunc (i *Installer) getBootPartitions(ctx context.Context, mode Mode, bootloader bootloaderpkg.Bootloader) ([]partition.Options, error) {\n\tif mode == ModeUpgrade {\n\t\treturn nil, nil // no need to generate boot partitions on upgrade\n\t}\n\n\tbootloaderOptions := i.generateBootloaderOptions(ctx, mode, nil)\n\n\tpartitionOptions, err := bootloader.GenerateAssets(bootloaderOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate bootloader assets: %w\", err)\n\t}\n\n\tefiPartitionPresent := slices.ContainsFunc(partitionOptions, func(p partition.Options) bool {\n\t\treturn p.Label == constants.EFIPartitionLabel && p.SourceDirectory != \"\"\n\t})\n\n\t// We need to move out bootloaderOptions.MountPrefix+/boot/EFI to bootloaderOptions.MountPrefix+/EFI otherwise\n\t// BOOT partition will be populated with EFI directory inside boot directory.\n\tif efiPartitionPresent {\n\t\tif err := os.Rename(filepath.Join(bootloaderOptions.MountPrefix, constants.EFIMountPoint), filepath.Join(bootloaderOptions.MountPrefix, \"EFI\")); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to move EFI directory: %w\", err)\n\t\t}\n\t}\n\n\treturn partitionOptions, nil\n}\n\nfunc (i *Installer) installBootloader(ctx context.Context, mode Mode, bootloader bootloaderpkg.Bootloader, info *blkid.Info) (*bootloaderoptions.InstallResult, error) {\n\tinstallOptions := i.generateBootloaderOptions(ctx, mode, info)\n\n\tswitch mode {\n\tcase ModeInstall:\n\t\treturn bootloader.Install(installOptions)\n\tcase ModeUpgrade:\n\t\treturn bootloader.Upgrade(installOptions)\n\tcase ModeImage:\n\t\treturn &bootloaderoptions.InstallResult{}, nil // bootloader already installed in image mode during partition creation\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *Installer) createPartitions(ctx context.Context, mode Mode, bd *block.Device, hostTalosVersion *compatibility.TalosVersion, bootPartitions []partition.Options) ([]partition.Options, error) {\n\tvar (\n\t\tgptdev gpt.Device\n\t\terr    error\n\t)\n\n\tswitch mode {\n\tcase ModeInstall:\n\t\tgptdev, err = gpt.DeviceFromBlockDevice(bd)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to initialize GPT device from blockdevice %s: %w\", i.options.DiskPath, err)\n\t\t}\n\tcase ModeUpgrade:\n\t\treturn nil, nil // no partitioning on upgrade\n\tcase ModeImage:\n\t\tf, err := os.OpenFile(i.options.DiskPath, os.O_RDWR, 0)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to open image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tgptdev, err = gpt.DeviceFromFile(f)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to initialize GPT device from image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n\n\tpartitions, gptOptions, err := i.getPartitionOptions(ctx, mode, hostTalosVersion, bootPartitions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get partition options: %w\", err)\n\t}\n\n\tpt, err := gpt.New(gptdev, gptOptions...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize GPT: %w\", err)\n\t}\n\n\tfor _, p := range partitions {\n\t\tsize := p.Size\n\n\t\tif size == 0 {\n\t\t\tsize = pt.LargestContiguousAllocatable()\n\t\t}\n\n\t\tpartitionTyp := uuid.MustParse(p.PartitionType)\n\n\t\t_, _, err = pt.AllocatePartition(size, p.PartitionLabel, partitionTyp, p.PartitionOpts...)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to allocate partition %s: %w\", p.PartitionLabel, err)\n\t\t}\n\n\t\ti.options.Printf(\"created %s (%s) size %d bytes\", p.PartitionLabel, p.PartitionType, size)\n\t}\n\n\tif err = pt.Write(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write GPT: %w\", err)\n\t}\n\n\tif err := gptdev.Sync(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to sync GPT device: %w\", err)\n\t}\n\n\treturn partitions, nil\n}\n\n// formatPartitions formats the created partitions populating them with filesystems and data as required.\n//\n//nolint:gocyclo\nfunc (i *Installer) formatPartitions(ctx context.Context, mode Mode, parts []partition.Options) error {\n\tswitch mode {\n\tcase ModeInstall:\n\t\t// format also populates partitions, so we need to make sure source directories are set\n\t\tfor idx, p := range parts {\n\t\t\tdevName := partitioning.DevName(i.options.DiskPath, uint(idx+1))\n\n\t\t\tif err := partition.Format(ctx, devName, &p.FormatOptions, i.options.Version, i.options.Printf); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to format partition %s: %w\", devName, err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\tcase ModeUpgrade:\n\t\t// no formatting on upgrade\n\t\treturn nil\n\tcase ModeImage:\n\t\t// format also populates partitions, so we need to make sure source directories are set\n\t\tf, err := os.OpenFile(i.options.DiskPath, os.O_RDWR, 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tgptdev, err := gpt.DeviceFromFile(f)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize GPT device from image file %s: %w\", i.options.DiskPath, err)\n\t\t}\n\n\t\tpt, err := gpt.Read(gptdev)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize GPT: %w\", err)\n\t\t}\n\n\t\tfor idx, p := range parts {\n\t\t\tif err := i.handlePartitionDataPopulation(ctx, idx, p, pt); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to handle partition data population for partition %s: %w\", p.Label, err)\n\t\t\t}\n\t\t}\n\n\t\tif err := i.handleGrubBlocklist(gptdev, pt); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to handle GRUB blocklist: %w\", err)\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown image mode: %d\", mode)\n\t}\n}\n\n//nolint:gocyclo\nfunc (i *Installer) handlePartitionDataPopulation(ctx context.Context, idx int, p partition.Options, pt *gpt.Table) error {\n\t// skip data population for partitions without filesystem ie. partition.FilesystemTypeNone\n\t// or zeroed partitions ie. partition.FilesystemTypeZeroes\n\tif p.FileSystemType == partition.FilesystemTypeNone || p.FileSystemType == partition.FilesystemTypeZeroes {\n\t\t// no data population required\n\t\treturn nil\n\t}\n\n\tpartitionImageFile := filepath.Join(i.options.MountPrefix, p.Label+\".img\")\n\n\tif err := utils.CreateRawDisk(i.options.Printf, partitionImageFile, int64(p.Size), true); err != nil {\n\t\treturn fmt.Errorf(\"failed to create raw disk for partition %s: %w\", p.Label, err)\n\t}\n\n\tif p.SourceDirectory == \"\" {\n\t\treturn fmt.Errorf(\"missing source directory for partition %s\", p.Label)\n\t}\n\n\t// this ensures that the images are reproducible\n\tif err := utils.TouchFiles(i.options.Printf, p.SourceDirectory); err != nil {\n\t\treturn fmt.Errorf(\"failed to touch files in source directory %s for partition %s: %w\", p.SourceDirectory, p.Label, err)\n\t}\n\n\tif err := partition.Format(ctx, partitionImageFile, &p.FormatOptions, i.options.Version, i.options.Printf); err != nil {\n\t\treturn fmt.Errorf(\"failed to format partition %s: %w\", partitionImageFile, err)\n\t}\n\n\tpartitionData, err := os.Open(partitionImageFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open partition image file %s: %w\", partitionImageFile, err)\n\t}\n\n\tdefer partitionData.Close() //nolint:errcheck\n\n\tw, size, err := pt.PartitionWriter(idx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get partition writer for partition %s: %w\", p.Label, err)\n\t}\n\n\tif size != int(p.Size) {\n\t\treturn fmt.Errorf(\"partition size mismatch for partition %s: expected %d, got %d\", p.Label, p.Size, size)\n\t}\n\n\twritten, err := io.Copy(w, partitionData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to copy partition data for partition %s: %w\", p.Label, err)\n\t}\n\n\tif written != int64(size) {\n\t\treturn fmt.Errorf(\"partition data size mismatch for partition %s: expected %d, got %d\", p.Label, size, written)\n\t}\n\n\ti.options.Printf(\"updated partition %s with %d bytes of data\", p.Label, written)\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *Installer) handleGrubBlocklist(gptdev gpt.Device, pt *gpt.Table) error {\n\tif i.options.Arch != \"amd64\" {\n\t\treturn nil\n\t}\n\n\tif i.options.DiskImageBootloader != profile.BootLoaderKindGrub.String() && i.options.DiskImageBootloader != profile.BootLoaderKindDualBoot.String() {\n\t\treturn nil\n\t}\n\n\tsectorSize := gptdev.GetSectorSize()\n\n\t// Find the BIOS GRUB partition where the `core.img` is going to be written to.\n\tvar (\n\t\tbiosPartitionIndex int\n\t\tbiosPartition      *gpt.Partition\n\t)\n\n\tfor idx, p := range pt.Partitions() {\n\t\tif p.Name == constants.BIOSGrubPartitionLabel {\n\t\t\tbiosPartition = p\n\t\t\tbiosPartitionIndex = idx\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif biosPartition == nil {\n\t\treturn fmt.Errorf(\"failed to find BOOT partition for GRUB blocklist handling\")\n\t}\n\n\t// Patch boot.img and core.img with blocklist information.\n\tif err := grub.PatchBlocklistsForDiskImage(sectorSize, biosPartition.FirstLBA, i.options.MountPrefix); err != nil {\n\t\treturn fmt.Errorf(\"failed to patch GRUB blocklists: %w\", err)\n\t}\n\n\tcoreImgData, err := os.ReadFile(filepath.Join(i.options.MountPrefix, \"core.img\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read core.img: %w\", err)\n\t}\n\n\tw, size, err := pt.PartitionWriter(biosPartitionIndex)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get partition writer for partition %s: %w\", biosPartition.Name, err)\n\t}\n\n\tif len(coreImgData) > size {\n\t\treturn fmt.Errorf(\"core.img size (%d bytes) exceeds BIOS partition size (%d bytes)\", len(coreImgData), size)\n\t}\n\n\twrittenSize, err := w.Write(coreImgData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to copy partition data for partition %s: %w\", biosPartition.Name, err)\n\t}\n\n\tif writtenSize != len(coreImgData) {\n\t\treturn fmt.Errorf(\"partition data size mismatch for partition %s: expected %d, got %d\", biosPartition.Name, len(coreImgData), writtenSize)\n\t}\n\n\ti.options.Printf(\"embedded GRUB core.img into BIOS partition image (%d bytes)\", len(coreImgData))\n\n\tbootImg, err := os.Open(filepath.Join(i.options.MountPrefix, \"boot.img\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open boot.img for MBR write: %w\", err)\n\t}\n\n\tdefer bootImg.Close() //nolint:errcheck\n\n\tmbr := make([]byte, 446)\n\n\tif _, err := io.ReadFull(bootImg, mbr); err != nil {\n\t\treturn fmt.Errorf(\"failed to read MBR from boot.img: %w\", err)\n\t}\n\n\twritten, err := gptdev.WriteAt(mbr, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to write MBR to image file %s: %w\", i.options.DiskPath, err)\n\t}\n\n\tif written != len(mbr) {\n\t\treturn fmt.Errorf(\"failed to write full MBR to image file %s: wrote %d bytes, expected %d bytes\", i.options.DiskPath, written, len(mbr))\n\t}\n\n\ti.options.Printf(\"wrote GRUB MBR to image file %s\", i.options.DiskPath)\n\n\treturn nil\n}\n\n// getPartitionOptions builds the complete list of partition options for an installation.\n// It combines the bootloader-specific partitions passed in via bootPartitions with the\n// system partitions defined by Talos and handling META and IMAGE cache.\n// It also generates GPT options required to create\n// the final partition layout. Mode-specific behavior is handled,\n// including configuration required for reproducible GUIDs when running in image mode.\n//\n//nolint:gocyclo\nfunc (i *Installer) getPartitionOptions(ctx context.Context, mode Mode, hostTalosVersion *compatibility.TalosVersion, bootPartitions []partition.Options) ([]partition.Options, []gpt.Option, error) {\n\tvar partitionOffset uint64\n\n\tif i.options.OverlayInstaller != nil {\n\t\toverlayOpts, getOptsErr := i.options.OverlayInstaller.GetOptions(ctx, i.options.ExtraOptions)\n\t\tif getOptsErr != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to get overlay installer options: %w\", getOptsErr)\n\t\t}\n\n\t\tif overlayOpts.PartitionOptions.Offset != 0 {\n\t\t\tpartitionOffset = overlayOpts.PartitionOptions.Offset\n\t\t}\n\t}\n\n\tvar gptOptions []gpt.Option\n\n\tif partitionOffset != 0 {\n\t\tgptOptions = append(gptOptions, gpt.WithSkipLBAs(uint(partitionOffset)))\n\t}\n\n\tif i.options.LegacyBIOSSupport {\n\t\tgptOptions = append(gptOptions, gpt.WithMarkPMBRBootable())\n\t}\n\n\tif mode == ModeImage {\n\t\tgptOptions = append(gptOptions, gpt.WithDiskGUID(makefs.GUIDFromLabel(diskImageLabel)))\n\t}\n\n\tquirk := quirks.New(i.options.Version)\n\n\t// boot partitions\n\tpartitions := slices.Clone(bootPartitions)\n\n\t// META partition\n\tpartitions = append(partitions,\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.MetaPartitionLabel)),\n\t)\n\n\tlegacyImage := mode == ModeImage && !quirks.New(i.options.Version).SkipDataPartitions()\n\n\t// compatibility when installing on Talos < 1.8\n\tif legacyImage || (hostTalosVersion != nil && hostTalosVersion.PrecreateStatePartition()) {\n\t\tpartitions = append(partitions,\n\t\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.StatePartitionLabel)),\n\t\t)\n\t}\n\n\tif legacyImage {\n\t\tpartitions = append(partitions,\n\t\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.EphemeralPartitionLabel)),\n\t\t)\n\t}\n\n\tif i.options.ImageCachePath != \"\" {\n\t\timageCachePartitionFormatOptions := []partition.FormatOption{\n\t\t\tpartition.WithLabel(constants.ImageCachePartitionLabel),\n\t\t\tpartition.WithSourceDirectory(i.options.ImageCachePath),\n\t\t}\n\n\t\tif mode == ModeImage {\n\t\t\timageCachePartitionFormatOptions = append(imageCachePartitionFormatOptions,\n\t\t\t\tpartition.WithReproducible(),\n\t\t\t)\n\t\t}\n\n\t\timageCachePartition := partition.NewPartitionOptions(\n\t\t\tfalse,\n\t\t\tquirk,\n\t\t\timageCachePartitionFormatOptions...,\n\t\t)\n\n\t\timageCachePartition.Size = uint64(i.options.ImageCacheSize)\n\n\t\tpartitions = append(partitions, imageCachePartition)\n\t}\n\n\tif mode == ModeImage {\n\t\tpartitions = xslices.Map(partitions, func(p partition.Options) partition.Options {\n\t\t\tpartitionGUID := makefs.GUIDFromLabel(p.PartitionLabel)\n\n\t\t\t// Generate deterministic partition GUID from label for reproducible images\n\t\t\tp.PartitionOpts = append(p.PartitionOpts, gpt.WithUniqueGUID(partitionGUID))\n\n\t\t\treturn p\n\t\t})\n\t}\n\n\treturn partitions, gptOptions, nil\n}\n\nfunc (i *Installer) runPreflightChecks(mode Mode) error {\n\tif mode != ModeUpgrade {\n\t\t// pre-flight checks only apply to upgrades\n\t\treturn nil\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tchecks, err := NewPreflightChecks(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing pre-flight checks: %w\", err)\n\t}\n\n\tdefer checks.Close() //nolint:errcheck\n\n\treturn checks.Run(ctx)\n}\n\nfunc overlayPresent() bool {\n\t_, err := os.Stat(constants.ImagerOverlayInstallerDefaultPath)\n\n\treturn err == nil\n}\n"
  },
  {
    "path": "cmd/installer/pkg/install/meta_value.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install\n\nimport (\n\t\"strings\"\n\n\t\"github.com/spf13/pflag\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n)\n\n// MetaValues is a list of MetaValue.\ntype MetaValues struct {\n\tvalues  meta.Values\n\tchanged bool\n}\n\n// Interface check.\nvar (\n\t_ pflag.Value      = &MetaValues{}\n\t_ pflag.SliceValue = &MetaValues{}\n)\n\n// FromMeta returns a new MetaValues from a meta.Values.\nfunc FromMeta(values meta.Values) MetaValues {\n\treturn MetaValues{values: values}\n}\n\n// Set implements pflag.Value.\nfunc (s *MetaValues) Set(val string) error {\n\tvar v meta.Value\n\n\tif err := v.Parse(val); err != nil {\n\t\treturn err\n\t}\n\n\tif !s.changed {\n\t\ts.values = meta.Values{v}\n\t} else {\n\t\ts.values = append(s.values, v)\n\t}\n\n\ts.changed = true\n\n\treturn nil\n}\n\n// Type implements pflag.Value.\nfunc (s *MetaValues) Type() string {\n\treturn \"metaValueSlice\"\n}\n\n// String implements pflag.Value.\nfunc (s *MetaValues) String() string {\n\treturn \"[\" + strings.Join(s.GetSlice(), \",\") + \"]\"\n}\n\n// Append implements pflag.SliceValue.\nfunc (s *MetaValues) Append(val string) error {\n\tvar v meta.Value\n\n\tif err := v.Parse(val); err != nil {\n\t\treturn err\n\t}\n\n\ts.values = append(s.values, v)\n\n\treturn nil\n}\n\n// Replace implements pflag.SliceValue.\nfunc (s *MetaValues) Replace(val []string) error {\n\tout := make(meta.Values, len(val))\n\n\tfor i, pair := range val {\n\t\tvar v meta.Value\n\n\t\tif err := v.Parse(pair); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tout[i] = v\n\t}\n\n\ts.values = out\n\n\treturn nil\n}\n\n// GetSlice implements pflag.SliceValue.\nfunc (s *MetaValues) GetSlice() []string {\n\tout := make([]string, len(s.values))\n\n\tfor i, v := range s.values {\n\t\tout[i] = v.String()\n\t}\n\n\treturn out\n}\n\n// Encode returns the encoded values.\nfunc (s *MetaValues) Encode() string {\n\treturn s.values.Encode(false)\n}\n\n// Decode the values from the given string.\nfunc (s *MetaValues) Decode(val string) error {\n\tvalues, err := meta.DecodeValues(val)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ts.values = values\n\n\treturn nil\n}\n\n// GetMetaValues returns the wrapped meta.Values.\nfunc (s *MetaValues) GetMetaValues() meta.Values {\n\treturn s.values\n}\n"
  },
  {
    "path": "cmd/installer/pkg/install/meta_value_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/pkg/install\"\n)\n\nfunc TestMetaValues(t *testing.T) {\n\tt.Parallel()\n\n\tvar s install.MetaValues\n\n\trequire.NoError(t, s.Set(\"10=foo\"))\n\trequire.NoError(t, s.Append(\"20=bar\"))\n\n\tassert.Equal(t, \"[0xa=foo,0x14=bar]\", s.String())\n\n\tencoded := s.Encode()\n\n\tvar s2 install.MetaValues\n\n\trequire.NoError(t, s2.Decode(encoded))\n\tassert.Equal(t, s.String(), s2.String())\n}\n"
  },
  {
    "path": "cmd/installer/pkg/install/preflight.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// PreflightChecks runs the preflight checks.\ntype PreflightChecks struct {\n\tdisabled bool\n\tclient   *client.Client\n\n\tinstallerTalosVersion *compatibility.TalosVersion\n\thostTalosVersion      *compatibility.TalosVersion\n}\n\n// NewPreflightChecks initializes and returns the installation PreflightChecks.\nfunc NewPreflightChecks(ctx context.Context) (*PreflightChecks, error) {\n\tif _, err := os.Stat(constants.MachineSocketPath); err != nil {\n\t\tlog.Printf(\"pre-flight checks disabled, as host Talos version is too old\")\n\n\t\treturn &PreflightChecks{disabled: true}, nil //nolint:nilerr\n\t}\n\n\tc, err := client.New(ctx,\n\t\tclient.WithUnixSocket(constants.MachineSocketPath),\n\t\tclient.WithGRPCDialOptions(\n\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error connecting to the machine service: %w\", err)\n\t}\n\n\treturn &PreflightChecks{\n\t\tclient: c,\n\t}, nil\n}\n\n// Close closes the client.\nfunc (checks *PreflightChecks) Close() error {\n\tif checks.disabled {\n\t\treturn nil\n\t}\n\n\treturn checks.client.Close()\n}\n\n// Run the checks, return the error if the check fails.\nfunc (checks *PreflightChecks) Run(ctx context.Context) error {\n\tif checks.disabled {\n\t\treturn nil\n\t}\n\n\tlog.Printf(\"running pre-flight checks\")\n\n\t// inject \"fake\" authorization\n\tctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(constants.APIAuthzRoleMetadataKey, string(role.Admin)))\n\n\tfor _, check := range []func(context.Context) error{\n\t\tchecks.talosVersion,\n\t} {\n\t\tif err := check(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"pre-flight checks failed: %w\", err)\n\t\t}\n\t}\n\n\tlog.Printf(\"all pre-flight checks successful\")\n\n\treturn nil\n}\n\nfunc (checks *PreflightChecks) talosVersion(ctx context.Context) error {\n\tresp, err := checks.client.Version(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting Talos version: %w\", err)\n\t}\n\n\thostVersion := unpack(resp.Messages)\n\n\tlog.Printf(\"host Talos version: %s\", hostVersion.Version.Tag)\n\n\tchecks.hostTalosVersion, err = compatibility.ParseTalosVersion(hostVersion.Version)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing host Talos version: %w\", err)\n\t}\n\n\tchecks.installerTalosVersion, err = compatibility.ParseTalosVersion(version.NewVersion())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing installer Talos version: %w\", err)\n\t}\n\n\treturn checks.installerTalosVersion.UpgradeableFrom(checks.hostTalosVersion)\n}\n\nfunc unpack[T any](s []T) T {\n\tif len(s) != 1 {\n\t\tpanic(\"unpack: slice length is not 1\")\n\t}\n\n\treturn s[0]\n}\n"
  },
  {
    "path": "cmd/talosctl/acompat/acompat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package acompat provides compatibility with gRPC 1.67.0 and later.\npackage acompat\n\nimport \"os\"\n\nfunc init() {\n\tif err := os.Setenv(\"GRPC_ENFORCE_ALPN_ENABLED\", \"false\"); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/common/common.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package common provides common functionality for talosctl commands.\n//\n//nolint:revive\npackage common\n\n// SuppressErrors is a flag to suppress printing errors after the command was run.\nvar SuppressErrors = false\n"
  },
  {
    "path": "cmd/talosctl/cmd/completion.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n)\n\n// completionCmd represents the completion command.\nvar completionCmd = &cobra.Command{\n\tUse:   \"completion SHELL\",\n\tShort: \"Output shell completion code for the specified shell (bash, fish or zsh)\",\n\tLong: `Output shell completion code for the specified shell (bash, fish or zsh).\nThe shell code must be evaluated to provide interactive\ncompletion of talosctl commands.  This can be done by sourcing it from\nthe .bash_profile.\n\nNote for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2`,\n\tExample: `# Installing bash completion on macOS using homebrew\n## If running Bash 3.2 included with macOS\n\tbrew install bash-completion\n## or, if running Bash 4.1+\n\tbrew install bash-completion@2\n## If talosctl is installed via homebrew, this should start working immediately.\n## If you've installed via other means, you may need add the completion to your completion directory\n\ttalosctl completion bash > $(brew --prefix)/etc/bash_completion.d/talosctl\n\n# Installing bash completion on Linux\n## If bash-completion is not installed on Linux, please install the 'bash-completion' package\n## via your distribution's package manager.\n## Load the talosctl completion code for bash into the current shell\n\tsource <(talosctl completion bash)\n## Write bash completion code to a file and source if from .bash_profile\n\ttalosctl completion bash > \"${TALOS_HOME:-$HOME/.talos}/completion.bash.inc\"\n\tprintf '\n\t\t# talosctl shell completion\n\t\tsource \"${TALOS_HOME:-$HOME/.talos}/completion.bash.inc\"\n\t\t' >> $HOME/.bash_profile\n\tsource $HOME/.bash_profile\n# Load the talosctl completion code for fish[1] into the current shell\n\ttalosctl completion fish | source\n# Set the talosctl completion code for fish[1] to autoload on startup\n    talosctl completion fish > ~/.config/fish/completions/talosctl.fish\n# Load the talosctl completion code for zsh[1] into the current shell\n\tsource <(talosctl completion zsh)\n# Set the talosctl completion code for zsh[1] to autoload on startup\n    talosctl completion zsh > \"${fpath[1]}/_talosctl\"`,\n\tValidArgs: []string{\"bash\", \"fish\", \"zsh\"},\n\tArgs:      cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif len(args) != 1 {\n\t\t\tcli.Should(cmd.Usage())\n\t\t\tos.Exit(1)\n\t\t}\n\n\t\tswitch args[0] {\n\t\tcase \"bash\":\n\t\t\treturn rootCmd.GenBashCompletion(os.Stdout)\n\t\tcase \"fish\":\n\t\t\treturn rootCmd.GenFishCompletion(os.Stdout, true)\n\t\tcase \"zsh\":\n\t\t\terr := rootCmd.GenZshCompletion(os.Stdout)\n\t\t\t// cobra does not hook the completion, so let's do it manually\n\t\t\tfmt.Printf(\"compdef _talosctl talosctl\")\n\n\t\t\treturn err\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported shell %q\", args[0])\n\t\t}\n\t},\n}\n\nfunc init() {\n\trootCmd.AddCommand(completionCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/constants/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage constants\n\nconst (\n\t// ImageFactoryEmptySchematicID is the ID of an empty image factory schematic.\n\tImageFactoryEmptySchematicID = \"376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba\"\n\n\t// ImageFactoryURL is the url of the Sidero hosted image factory.\n\tImageFactoryURL = \"https://factory.talos.dev/\"\n)\n"
  },
  {
    "path": "cmd/talosctl/cmd/docs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cmd provides the talosctl command implementation.\npackage cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/cobra/doc\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc frontmatter(title, description string) string {\n\tvar buf bytes.Buffer\n\n\tbuf.WriteString(\"---\\n\")\n\n\tif err := yaml.NewEncoder(&buf).Encode(map[string]string{\n\t\t\"title\":       title,\n\t\t\"description\": description,\n\t}); err != nil {\n\t\tpanic(err)\n\t}\n\n\tbuf.WriteString(\"---\\n\")\n\tbuf.WriteString(\"\\n\")\n\tbuf.WriteString(\"<!-- markdownlint-disable -->\\n\\n\")\n\n\treturn buf.String()\n}\n\nfunc linkHandler(name string) string {\n\tbase := strings.TrimSuffix(name, path.Ext(name))\n\n\tbase = strings.ReplaceAll(base, \"_\", \"-\")\n\n\treturn \"#\" + strings.ToLower(base)\n}\n\nconst cliDescription = \"Talosctl CLI tool reference.\"\n\nvar (\n\tcliDocs    bool\n\tconfigDocs bool\n)\n\n// docsCmd represents the docs command.\nvar docsCmd = &cobra.Command{\n\tUse:    \"docs <output> [flags]\",\n\tShort:  \"Generate documentation for the CLI or config\",\n\tLong:   ``,\n\tArgs:   cobra.ExactArgs(1),\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tdir := args[0]\n\n\t\tif err := os.MkdirAll(dir, 0o777); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create output directory %q\", dir)\n\t\t}\n\n\t\tall := !cliDocs && !configDocs\n\n\t\tif cliDocs || all {\n\t\t\tw := &bytes.Buffer{}\n\n\t\t\tif err := GenMarkdownReference(rootCmd, w, linkHandler); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to generate docs: %w\", err)\n\t\t\t}\n\n\t\t\tfilename := filepath.Join(dir, \"cli.md\")\n\n\t\t\tf, err := os.Create(filename)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t//nolint:errcheck\n\t\t\tdefer f.Close()\n\n\t\t\tif _, err := io.WriteString(f, frontmatter(\"CLI\", cliDescription)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif _, err := io.WriteString(f, w.String()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif configDocs || all {\n\t\t\tfor _, pkg := range []struct {\n\t\t\t\tname    string\n\t\t\t\tfileDoc *encoder.FileDoc\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tname:    \"network\",\n\t\t\t\t\tfileDoc: network.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"runtime\",\n\t\t\t\t\tfileDoc: runtime.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"siderolink\",\n\t\t\t\t\tfileDoc: siderolink.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"v1alpha1\",\n\t\t\t\t\tfileDoc: v1alpha1.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"extensions\",\n\t\t\t\t\tfileDoc: extensions.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"security\",\n\t\t\t\t\tfileDoc: security.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"block\",\n\t\t\t\t\tfileDoc: block.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"hardware\",\n\t\t\t\t\tfileDoc: hardware.GetFileDoc(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:    \"cri\",\n\t\t\t\t\tfileDoc: cri.GetFileDoc(),\n\t\t\t\t},\n\t\t\t} {\n\t\t\t\tpath := filepath.Join(dir, pkg.name)\n\n\t\t\t\tif err := os.MkdirAll(path, 0o777); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create output directory %q\", path)\n\t\t\t\t}\n\n\t\t\t\tif err := pkg.fileDoc.Write(path, frontmatter); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to generate docs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\n// GenMarkdownReference is the same as GenMarkdownTree, but\n// with custom filePrepender and linkHandler.\n//\n//nolint:gocyclo\nfunc GenMarkdownReference(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error {\n\tfor _, c := range cmd.Commands() {\n\t\t// Generate docs for children of the cluster create command although the command itself is hidden.\n\t\tif cmd.Name() == \"cluster\" && c.Name() == \"create\" {\n\t\t\tif err := GenMarkdownReference(c, w, linkHandler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := GenMarkdownReference(c, w, linkHandler); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Skip generating docs for the cluster create command itself and only generate docs for children.\n\t// TODO: remove once \"cluster create\" is completely migrated to \"cluster create dev\".\n\tif cmd.Name() == \"create\" && cmd.Parent() != nil && cmd.Parent().Name() == \"cluster\" {\n\t\treturn nil\n\t}\n\n\treturn doc.GenMarkdownCustom(cmd, w, linkHandler)\n}\n\nfunc init() {\n\tdocsCmd.Flags().BoolVar(&configDocs, \"config\", false, \"generate documentation for the default configuration schema\")\n\tdocsCmd.Flags().BoolVar(&cliDocs, \"cli\", false, \"generate documentation for the CLI\")\n\trootCmd.AddCommand(docsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cluster implements \"cluster\" subcommands.\npackage cluster\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/spf13/cobra\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\nconst (\n\t// ProvisionerFlagName is the flag with which the provisioner is configured.\n\tProvisionerFlagName = \"provisioner\"\n)\n\n// Cmd represents the cluster command.\nvar Cmd = &cobra.Command{\n\tUse:   \"cluster\",\n\tShort: \"A collection of commands for managing local docker-based or QEMU-based clusters\",\n}\n\n// CmdOps are the options for the cluster command.\ntype CmdOps struct {\n\tStateDir    string\n\tClusterName string\n}\n\n// PersistentFlags are the persistent flags of the cluster command.\nvar PersistentFlags CmdOps\n\nvar provisionerName string\n\nvar (\n\t// DefaultStateDir is the default location of the cluster related file state.\n\tDefaultStateDir string\n\t// DefaultCNIDir is the default location of the CNI binaries.\n\tDefaultCNIDir string\n)\n\nfunc init() {\n\ttalosDir, err := clientconfig.GetTalosDirectory()\n\tif err == nil {\n\t\tDefaultStateDir = filepath.Join(talosDir, \"clusters\")\n\t\tDefaultCNIDir = filepath.Join(talosDir, \"cni\")\n\t}\n\n\tCmd.PersistentFlags().StringVar(&PersistentFlags.StateDir, \"state\", DefaultStateDir, \"directory path to store cluster state\")\n\tCmd.PersistentFlags().StringVar(&PersistentFlags.ClusterName, \"name\", \"talos-default\", \"the name of the cluster\")\n}\n\n// AddProvisionerFlag adds the provisioner flag to a command.\nfunc AddProvisionerFlag(cmd *cobra.Command) {\n\tcmd.Flags().StringVar(&provisionerName, ProvisionerFlagName, providers.DockerProviderName, \"Talos cluster provisioner to use\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/config_maker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configmaker\n\nimport (\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers\"\n)\n\n// DockerOptions are the options for provisioning a docker based Talos cluster.\ntype DockerOptions makers.MakerOptions[clusterops.Docker]\n\n// GetDockerConfigs returns the cluster configs for docker.\nfunc GetDockerConfigs(options DockerOptions) (clusterops.ClusterConfigs, error) {\n\tmaker, err := makers.NewDocker(options)\n\tif err != nil {\n\t\treturn clusterops.ClusterConfigs{}, err\n\t}\n\n\treturn maker.GetClusterConfigs()\n}\n\n// QemuOptions are the options for provisioning a qemu based Talos cluster.\ntype QemuOptions makers.MakerOptions[clusterops.Qemu]\n\n// GetQemuConfigs returns the cluster configs for qemu.\nfunc GetQemuConfigs(options QemuOptions) (clusterops.ClusterConfigs, error) {\n\tmaker, err := makers.NewQemu(options)\n\tif err != nil {\n\t\treturn clusterops.ClusterConfigs{}, err\n\t}\n\n\treturn maker.GetClusterConfigs()\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/common.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"os\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tsideronet \"github.com/siderolabs/net\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\t// gatewayOffset is the offset from the network address of the IP address of the network gateway.\n\tgatewayOffset = 1 + iota\n\n\t// nodesOffset is the offset from the network address of the beginning of the IP addresses to be used for nodes.\n\tnodesOffset\n)\n\n// MakerOptions are the options needed to initialize a maker.\ntype MakerOptions[ExtraOps any] = struct {\n\tExtraOps    ExtraOps\n\tCommonOps   clusterops.Common\n\tProvisioner provision.Provisioner\n}\n\n// New creates a new maker.\nfunc New[ExtraOps any](options MakerOptions[ExtraOps]) (Maker[ExtraOps], error) {\n\tm := Maker[ExtraOps]{}\n\tm.Ops = options.CommonOps\n\tm.EOps = options.ExtraOps\n\tm.Provisioner = options.Provisioner\n\n\treturn m, nil\n}\n\n// Maker contains config making logic shared between provisioners.\ntype Maker[ExtraOps any] struct {\n\tOps clusterops.Common\n\n\tClusterRequest    provision.ClusterRequest\n\tProvisioner       provision.Provisioner\n\tIPs               [][]netip.Addr\n\tVersionContract   *config.VersionContract\n\tGatewayIPs        []netip.Addr\n\tCidrs             []netip.Prefix\n\tInClusterEndpoint string\n\tEndpoints         []string\n\tWithOmni          bool\n\n\tProvisionOps    []provision.Option\n\tGenOps          []generate.Option\n\tConfigBundleOps []bundle.Option\n\n\tEOps ExtraOps\n\n\textraOptionsProvider ExtraOptionsProvider\n}\n\n// SetExtraOptionsProvider sets extra options provider containing the provider specific logic.\nfunc (m *Maker[T]) SetExtraOptionsProvider(hooks ExtraOptionsProvider) {\n\tm.extraOptionsProvider = hooks\n}\n\n// Init initializes the common struct fields.\nfunc (m *Maker[T]) Init() error {\n\tif err := m.InitCommon(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.InitExtra(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// InitExtra calls the init functions set by the individual implementation of the maker.\nfunc (m *Maker[T]) InitExtra() error {\n\tif err := m.extraOptionsProvider.InitExtra(); err != nil {\n\t\treturn err\n\t}\n\n\t// skip generating machine config if nodes are to be used with omni\n\tif !m.WithOmni {\n\t\tif err := m.extraOptionsProvider.AddExtraGenOps(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := m.extraOptionsProvider.AddExtraConfigBundleOpts(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := m.extraOptionsProvider.AddExtraProvisionOpts(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.extraOptionsProvider.ModifyClusterRequest(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.extraOptionsProvider.ModifyNodes(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// InitCommon initializes the common fields.\n//\n//nolint:gocyclo\nfunc (m *Maker[T]) InitCommon() error {\n\tif m.Ops.OmniAPIEndpoint != \"\" {\n\t\tm.WithOmni = true\n\t}\n\n\tif err := m.initVersionContract(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.initCIDRs(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.initIPs(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.initGatewayIPs(); err != nil {\n\t\treturn err\n\t}\n\n\tm.initClusterRequest()\n\n\tif err := m.initEndpoints(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := m.initNodeRequests(); err != nil {\n\t\treturn err\n\t}\n\n\t// skip generating machine config if nodes are to be used with omni\n\tif !m.WithOmni {\n\t\tif err := m.initGenOps(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := m.initConfigBundleOps(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := m.initProvisionOps(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) initProvisionOps() error {\n\tm.ProvisionOps = []provision.Option{\n\t\tprovision.WithKubernetesEndpoint(m.Provisioner.GetExternalKubernetesControlPlaneEndpoint(m.ClusterRequest.Network, m.Ops.ControlPlanePort)),\n\t}\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) initConfigBundleOps() error {\n\tconfigPatchBundleOps, err := getConfigPatchBundleOps(m.Ops)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tm.ConfigBundleOps = slices.Clone(configPatchBundleOps)\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) initVersionContract() error {\n\tif m.Ops.TalosVersion == \"latest\" {\n\t\tm.VersionContract = nil\n\n\t\treturn nil\n\t}\n\n\tversionContract, err := config.ParseContractFromVersion(m.Ops.TalosVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing Talos version %q: %w\", m.Ops.TalosVersion, err)\n\t}\n\n\tm.VersionContract = versionContract\n\n\treturn nil\n}\n\n// GetClusterConfigs prepares and returns the cluster create request data. This method is ment to be called after the implemeting maker\n// logic has been run.\nfunc (m *Maker[T]) GetClusterConfigs() (clusterops.ClusterConfigs, error) {\n\tvar configBundle *bundle.Bundle\n\n\tif !m.WithOmni {\n\t\tcfgBundle, err := m.finalizeMachineConfigs()\n\t\tif err != nil {\n\t\t\treturn clusterops.ClusterConfigs{}, err\n\t\t}\n\n\t\tconfigBundle = cfgBundle\n\t} else {\n\t\terr := m.applyOmniConfigs()\n\t\tif err != nil {\n\t\t\treturn clusterops.ClusterConfigs{}, err\n\t\t}\n\t}\n\n\treturn clusterops.ClusterConfigs{\n\t\tClusterRequest:   m.ClusterRequest,\n\t\tProvisionOptions: m.ProvisionOps,\n\t\tConfigBundle:     configBundle,\n\t}, nil\n}\n\nfunc (m *Maker[T]) applyOmniConfigs() error {\n\tcfg := siderolink.NewConfigV1Alpha1()\n\n\tparsedURL, err := url.Parse(m.Ops.OmniAPIEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing omni api url: %w\", err)\n\t}\n\n\tcfg.APIUrlConfig.URL = parsedURL\n\n\t_, err = cfg.Validate(runtime.ModeMetal)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tctr, err := container.New(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tm.ForEachNode(func(i int, node *provision.NodeRequest) {\n\t\tnode.Config = ctr\n\t\tnode.Name = m.Ops.RootOps.ClusterName + \"-machine-\" + strconv.Itoa(i+1)\n\t})\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) finalizeMachineConfigs() (*bundle.Bundle, error) {\n\t// These options needs to be generated after the implementing maker has made changes to the cluster request.\n\tprovisionGenOps, provisionBundleOps := m.Provisioner.GenOptions(m.ClusterRequest.Network, m.VersionContract)\n\tm.GenOps = slices.Concat(m.GenOps, provisionGenOps)\n\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps, provisionBundleOps)\n\tm.GenOps = slices.Concat(m.GenOps, []generate.Option{generate.WithEndpointList(m.Endpoints)})\n\n\tm.ConfigBundleOps = append(m.ConfigBundleOps,\n\t\tbundle.WithInputOptions(\n\t\t\t&bundle.InputOptions{\n\t\t\t\tClusterName: m.Ops.RootOps.ClusterName,\n\t\t\t\tEndpoint:    m.InClusterEndpoint,\n\t\t\t\tKubeVersion: strings.TrimPrefix(m.Ops.KubernetesVersion, \"v\"),\n\t\t\t\tGenOptions:  m.GenOps,\n\t\t\t}),\n\t)\n\n\tconfigBundle, err := bundle.NewBundle(m.ConfigBundleOps...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif m.ClusterRequest.Nodes[0].Type == machine.TypeInit {\n\t\tm.ClusterRequest.Nodes[0].Config = configBundle.Init()\n\t}\n\n\tm.ForEachControlplaneNode(func(i, controlplaneIndex int, node *provision.NodeRequest) {\n\t\tnode.Config = configBundle.ControlPlane()\n\t})\n\tm.ForEachWorkerNode(func(i, workerI int, node *provision.NodeRequest) {\n\t\tnode.Config = configBundle.Worker()\n\t})\n\n\tif m.Ops.WireguardCIDR != \"\" {\n\t\twireguardConfigBundle, err := helpers.NewWireguardConfigBundle(m.IPs[0], m.Ops.WireguardCIDR, 51111, m.Ops.Controlplanes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor i := range m.ClusterRequest.Nodes {\n\t\t\tnode := &m.ClusterRequest.Nodes[i]\n\n\t\t\tpatch, err := wireguardConfigBundle.PatchNode(node.IPs[0])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tout, err := configpatcher.Apply(configpatcher.WithConfig(node.Config), []configpatcher.Patch{patch})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tnode.Config, err = out.Config()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\tm.ProvisionOps = append(m.ProvisionOps, provision.WithTalosConfig(configBundle.TalosConfig()))\n\n\treturn configBundle, nil\n}\n\n// ForEachNode iterates over all nodes allowing modification of each node.\nfunc (m *Maker[T]) ForEachNode(fn func(i int, node *provision.NodeRequest)) {\n\tfor i := range m.ClusterRequest.Nodes {\n\t\tfn(i, &m.ClusterRequest.Nodes[i])\n\t}\n}\n\n// ForEachWorkerNode iterates over all worker nodes allowing modification of each worker node.\nfunc (m *Maker[T]) ForEachWorkerNode(fn func(i, workerI int, node *provision.NodeRequest)) {\n\tworkerIndex := 0\n\n\tfor i := range m.ClusterRequest.Nodes {\n\t\tif m.ClusterRequest.Nodes[i].Type != machine.TypeWorker {\n\t\t\tcontinue\n\t\t}\n\n\t\tfn(i, workerIndex, &m.ClusterRequest.Nodes[i])\n\t\tworkerIndex++\n\t}\n}\n\n// ForEachControlplaneNode iterates over all controlplane nodes allowing modification of each controlplane node.\nfunc (m *Maker[T]) ForEachControlplaneNode(fn func(i, controlplaneIndex int, node *provision.NodeRequest)) {\n\tcontrolplaneIndex := 0\n\n\tfor i := range m.ClusterRequest.Nodes {\n\t\tif m.ClusterRequest.Nodes[i].Type != machine.TypeControlPlane {\n\t\t\tcontinue\n\t\t}\n\n\t\tfn(i, controlplaneIndex, &m.ClusterRequest.Nodes[i])\n\t\tcontrolplaneIndex++\n\t}\n}\n\nfunc (m *Maker[T]) initCIDRs() error {\n\tcidr4, err := netip.ParsePrefix(m.Ops.NetworkCIDR)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error validating cidr block: %w\", err)\n\t}\n\n\tif !cidr4.Addr().Is4() {\n\t\treturn errors.New(\"IPV4 CIDR expected, got IPV6 CIDR\")\n\t}\n\n\t// use ULA IPv6 network fd00::/8, add 'TAL' in hex to build /32 network, add IPv4 CIDR to build /64 unique network\n\tcidr6, err := netip.ParsePrefix(\n\t\tfmt.Sprintf(\n\t\t\t\"fd74:616c:%02x%02x:%02x%02x::/64\",\n\t\t\tcidr4.Addr().As4()[0], cidr4.Addr().As4()[1], cidr4.Addr().As4()[2], cidr4.Addr().As4()[3],\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error validating cidr IPv6 block: %w\", err)\n\t}\n\n\tvar cidrs []netip.Prefix\n\n\tif m.Ops.NetworkIPv4 {\n\t\tcidrs = append(cidrs, cidr4)\n\t}\n\n\tif m.Ops.NetworkIPv6 {\n\t\tcidrs = append(cidrs, cidr6)\n\t}\n\n\tif len(cidrs) == 0 {\n\t\treturn errors.New(\"neither IPv4 nor IPv6 network was enabled\")\n\t}\n\n\tm.Cidrs = cidrs\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) initGenOps() error {\n\tgenOptions := []generate.Option{\n\t\tgenerate.WithDNSDomain(m.Ops.DNSDomain),\n\t\tgenerate.WithClusterDiscovery(m.Ops.EnableClusterDiscovery),\n\t\tgenerate.WithDebug(m.Ops.ConfigDebug),\n\t}\n\n\tregistryMirrorOps, err := getRegistryMirrorGenOps(m.Ops)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, registryHost := range m.Ops.RegistryInsecure {\n\t\tgenOptions = append(genOptions, generate.WithRegistryInsecureSkipVerify(registryHost))\n\t}\n\n\tgenOptions = append(genOptions, registryMirrorOps...)\n\n\tgenOptions = append(genOptions, generate.WithVersionContract(m.VersionContract))\n\n\tif m.Ops.ControlPlanePort != constants.DefaultControlPlanePort {\n\t\tgenOptions = slices.Concat(genOptions, []generate.Option{\n\t\t\tgenerate.WithLocalAPIServerPort(m.Ops.ControlPlanePort),\n\t\t})\n\t}\n\n\tif m.Ops.KubePrismPort != constants.DefaultKubePrismPort {\n\t\tgenOptions = slices.Concat(genOptions, []generate.Option{\n\t\t\tgenerate.WithKubePrismPort(m.Ops.KubePrismPort),\n\t\t})\n\t}\n\n\tif m.Ops.EnableKubeSpan {\n\t\tgenOptions = slices.Concat(genOptions,\n\t\t\t[]generate.Option{\n\t\t\t\tgenerate.WithKubeSpanEnabled(m.Ops.EnableKubeSpan),\n\t\t\t},\n\t\t)\n\t}\n\n\tm.GenOps = genOptions\n\n\treturn nil\n}\n\nfunc getConfigPatchBundleOps(cOps clusterops.Common) ([]bundle.Option, error) {\n\tconfigBundleOpts := []bundle.Option{}\n\n\taddConfigPatch := func(configPatches []string, configOpt func([]configpatcher.Patch) bundle.Option) error {\n\t\tvar patches []configpatcher.Patch\n\n\t\tpatches, err := configpatcher.LoadPatches(configPatches)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing config patch: %w\", err)\n\t\t}\n\n\t\tconfigBundleOpts = append(configBundleOpts, configOpt(patches))\n\n\t\treturn nil\n\t}\n\tif err := addConfigPatch(cOps.ConfigPatch, bundle.WithPatch); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := addConfigPatch(cOps.ConfigPatchControlPlane, bundle.WithPatchControlPlane); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := addConfigPatch(cOps.ConfigPatchWorker, bundle.WithPatchWorker); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn configBundleOpts, nil\n}\n\nfunc (m *Maker[T]) initIPs() error {\n\tnodes := m.Ops.Controlplanes + m.Ops.Workers\n\tips := make([][]netip.Addr, len(m.Cidrs))\n\n\tfor cidrIndex, cidr := range m.Cidrs {\n\t\tfor nodeIndex := range nodes {\n\t\t\tip, err := sideronet.NthIPInNetwork(cidr, nodesOffset+nodeIndex)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tips[cidrIndex] = append(ips[cidrIndex], ip)\n\t\t}\n\t}\n\n\tm.IPs = ips\n\n\treturn nil\n}\n\nfunc parseCPUShare(cpus string) (int64, error) {\n\tcpu, ok := new(big.Rat).SetString(cpus)\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"failed to parsing as a rational number: %s\", cpus)\n\t}\n\n\tnano := cpu.Mul(cpu, big.NewRat(1e9, 1))\n\tif !nano.IsInt() {\n\t\treturn 0, errors.New(\"value is too precise\")\n\t}\n\n\treturn nano.Num().Int64(), nil\n}\n\nfunc getRegistryMirrorGenOps(cOps clusterops.Common) ([]generate.Option, error) {\n\tops := make([]generate.Option, 0, len(cOps.RegistryMirrors))\n\n\tfor _, registryMirror := range cOps.RegistryMirrors {\n\t\tleft, right, ok := strings.Cut(registryMirror, \"=\")\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid registry mirror spec: %q\", registryMirror)\n\t\t}\n\n\t\tops = append(ops, generate.WithRegistryMirror(left, right))\n\t}\n\n\treturn ops, nil\n}\n\nfunc (m *Maker[T]) initClusterRequest() {\n\tm.ClusterRequest = provision.ClusterRequest{\n\t\tName:           m.Ops.RootOps.ClusterName,\n\t\tSelfExecutable: os.Args[0],\n\t\tStateDirectory: m.Ops.RootOps.StateDir,\n\n\t\tNetwork: provision.NetworkRequest{\n\t\t\tName:              m.Ops.RootOps.ClusterName,\n\t\t\tCIDRs:             m.Cidrs,\n\t\t\tGatewayAddrs:      m.GatewayIPs,\n\t\t\tMTU:               m.Ops.NetworkMTU,\n\t\t\tLoadBalancerPorts: []int{m.Ops.ControlPlanePort},\n\t\t},\n\t}\n}\n\nfunc (m *Maker[T]) initGatewayIPs() error {\n\tgatewayIPs := make([]netip.Addr, len(m.Cidrs))\n\n\tfor j := range gatewayIPs {\n\t\tip, err := sideronet.NthIPInNetwork(m.Cidrs[j], gatewayOffset)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tgatewayIPs[j] = ip\n\t}\n\n\tm.GatewayIPs = gatewayIPs\n\n\treturn nil\n}\n\nfunc (m *Maker[T]) initEndpoints() error {\n\tm.InClusterEndpoint = m.Provisioner.GetInClusterKubernetesControlPlaneEndpoint(m.ClusterRequest.Network, m.Ops.ControlPlanePort)\n\tm.Endpoints = m.Provisioner.GetTalosAPIEndpoints(m.ClusterRequest.Network)\n\n\treturn nil\n}\n\nfunc parseResources(res clusterops.NodeResources) (clusterops.ParsedNodeResources, error) {\n\tnanoCPUs, err := parseCPUShare(res.CPU)\n\tif err != nil {\n\t\treturn clusterops.ParsedNodeResources{}, err\n\t}\n\n\treturn clusterops.ParsedNodeResources{\n\t\tNanoCPUs: nanoCPUs,\n\t\tMemory:   res.Memory,\n\t}, nil\n}\n\nfunc (m *Maker[T]) initNodeRequests() error {\n\tcontrolplaneResources, err := parseResources(m.Ops.ControlplaneResources)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing controlplane resources: %s\", err)\n\t}\n\n\tworkerResources, err := parseResources(m.Ops.WorkerResources)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing worker resources: %s\", err)\n\t}\n\n\tif m.Ops.Controlplanes < 1 {\n\t\treturn errors.New(\"number of controlplanes can't be less than 1\")\n\t}\n\n\tnodes := []provision.NodeRequest{}\n\n\tfor i := range m.Ops.Controlplanes {\n\t\tnodeUUID := uuid.New()\n\t\tmachineName := fmt.Sprintf(\"%s-%s-%d\", m.Ops.RootOps.ClusterName, \"controlplane\", i+1)\n\n\t\tif m.Ops.WithUUIDHostnames {\n\t\t\tmachineName = fmt.Sprintf(\"%s-%s\", \"machine\", nodeUUID)\n\t\t}\n\n\t\tmachineType := machine.TypeControlPlane\n\n\t\tif m.Ops.WithInitNode && i == 0 {\n\t\t\tmachineType = machine.TypeInit\n\t\t}\n\n\t\tips := getNodeIPs(m.IPs, i)\n\t\tnodes = append(nodes, provision.NodeRequest{\n\t\t\tName:                machineName,\n\t\t\tIPs:                 ips,\n\t\t\tType:                machineType,\n\t\t\tMemory:              int64(controlplaneResources.Memory.Bytes()),\n\t\t\tNanoCPUs:            controlplaneResources.NanoCPUs,\n\t\t\tUUID:                new(nodeUUID),\n\t\t\tSkipInjectingConfig: m.Ops.SkipInjectingConfig,\n\t\t})\n\t}\n\n\tfor workerIndex := range m.Ops.Workers {\n\t\tnodeUUID := uuid.New()\n\t\tmachineName := fmt.Sprintf(\"%s-%s-%d\", m.Ops.RootOps.ClusterName, \"worker\", workerIndex+1)\n\n\t\tif m.Ops.WithUUIDHostnames {\n\t\t\tmachineName = fmt.Sprintf(\"%s-%s\", \"machine\", nodeUUID)\n\t\t}\n\n\t\tnodeIndex := m.Ops.Controlplanes + workerIndex\n\t\tips := getNodeIPs(m.IPs, nodeIndex)\n\t\tnodes = append(nodes, provision.NodeRequest{\n\t\t\tName:                machineName,\n\t\t\tIPs:                 ips,\n\t\t\tType:                machine.TypeWorker,\n\t\t\tMemory:              int64(workerResources.Memory.Bytes()),\n\t\t\tNanoCPUs:            workerResources.NanoCPUs,\n\t\t\tUUID:                new(nodeUUID),\n\t\t\tSkipInjectingConfig: m.Ops.SkipInjectingConfig,\n\t\t})\n\t}\n\n\tm.ClusterRequest.Nodes = nodes\n\n\treturn nil\n}\n\nfunc getNodeIPs(ips [][]netip.Addr, nodeIndex int) []netip.Addr {\n\treturn xslices.Map(ips, func(ips []netip.Addr) netip.Addr {\n\t\treturn ips[nodeIndex]\n\t})\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/common_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers_test\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\ntype testProvisioner struct {\n\tprovision.Provisioner\n}\n\nfunc (p testProvisioner) GenOptions(r provision.NetworkRequest, _ *config.VersionContract) ([]generate.Option, []bundle.Option) {\n\treturn []generate.Option{func(o *generate.Options) error { return nil }}, nil\n}\n\nfunc (p testProvisioner) GetTalosAPIEndpoints(provision.NetworkRequest) []string {\n\treturn []string{\"talos-api-endpoint.test\"}\n}\n\nfunc (p testProvisioner) GetInClusterKubernetesControlPlaneEndpoint(networkReq provision.NetworkRequest, controlPlanePort int) string {\n\treturn \"controlplane-endpoint.test\"\n}\n\nfunc (p testProvisioner) GetExternalKubernetesControlPlaneEndpoint(networkReq provision.NetworkRequest, controlPlanePort int) string {\n\treturn \"external-kubernetes-controlplane-endpoint.test\"\n}\n\ntype nothingProvider struct{}\n\nfunc (*nothingProvider) InitExtra() error                { return nil }\nfunc (*nothingProvider) AddExtraGenOps() error           { return nil }\nfunc (*nothingProvider) AddExtraProvisionOpts() error    { return nil }\nfunc (*nothingProvider) AddExtraConfigBundleOpts() error { return nil }\nfunc (*nothingProvider) ModifyClusterRequest() error     { return nil }\nfunc (*nothingProvider) ModifyNodes() error              { return nil }\n\nfunc getInitializedTestMaker(t *testing.T, cOps clusterops.Common) makers.Maker[any] {\n\tm, err := makers.New(makers.MakerOptions[any]{CommonOps: cOps, Provisioner: testProvisioner{}})\n\trequire.NoError(t, err)\n\n\tm.SetExtraOptionsProvider(&nothingProvider{})\n\n\terr = m.Init()\n\trequire.NoError(t, err)\n\n\treturn m\n}\n\nvar nodeUUIDHostnameRegex = regexp.MustCompile(\"^machine-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$\")\n\nfunc TestCommonMaker(t *testing.T) {\n\tcOps := clusterops.GetCommon()\n\tcOps.Controlplanes = 2\n\tcOps.Workers = 2\n\tcOps.NetworkIPv6 = true\n\tcOps.RootOps.ClusterName = \"test-cluster\"\n\n\tm := getInitializedTestMaker(t, cOps)\n\n\tcontrolplanes := m.ClusterRequest.Nodes.ControlPlaneNodes()\n\tworkers := m.ClusterRequest.Nodes.WorkerNodes()\n\n\tassert.Equal(t, 2, len(controlplanes))\n\tassert.Equal(t, 2, len(workers))\n\n\tassert.Equal(t, \"test-cluster\", m.ClusterRequest.Name)\n\tassert.Equal(t, \"test-cluster\", m.ClusterRequest.Network.Name)\n\tassert.Equal(t, 2, len(m.Cidrs))\n\tassert.Equal(t, \"10.5.0.0/24\", m.Cidrs[0].String())\n\tassert.Equal(t, \"fd74:616c:a05::/64\", m.Cidrs[1].String())\n\tassert.Equal(t, []string{\"talos-api-endpoint.test\"}, m.Endpoints)\n\n\tassert.Equal(t, \"test-cluster-controlplane-1\", controlplanes[0].Name)\n\tassert.Equal(t, \"test-cluster-controlplane-2\", controlplanes[1].Name)\n\tassert.Equal(t, \"test-cluster-worker-1\", workers[0].Name)\n\tassert.Equal(t, \"test-cluster-worker-2\", workers[1].Name)\n\n\tfor _, node := range append(controlplanes, workers...) {\n\t\tassert.Equal(t, 2, len(node.IPs))\n\t}\n\n\tassert.Equal(t, \"10.5.0.2\", controlplanes[0].IPs[0].String())\n\tassert.Equal(t, \"fd74:616c:a05::2\", controlplanes[0].IPs[1].String())\n\tassert.Equal(t, \"10.5.0.3\", controlplanes[1].IPs[0].String())\n\tassert.Equal(t, \"fd74:616c:a05::3\", controlplanes[1].IPs[1].String())\n\tassert.Equal(t, \"10.5.0.4\", workers[0].IPs[0].String())\n\tassert.Equal(t, \"fd74:616c:a05::4\", workers[0].IPs[1].String())\n\tassert.Equal(t, \"10.5.0.5\", workers[1].IPs[0].String())\n\tassert.Equal(t, \"fd74:616c:a05::5\", workers[1].IPs[1].String())\n\n\tassert.Equal(t, \"controlplane-endpoint.test\", m.InClusterEndpoint)\n\n\tm.Ops.WithUUIDHostnames = true\n\terr := m.Init()\n\tassert.NoError(t, err)\n\n\tcontrolplanes = m.ClusterRequest.Nodes.ControlPlaneNodes()\n\tworkers = m.ClusterRequest.Nodes.WorkerNodes()\n\n\tassert.Regexp(t, nodeUUIDHostnameRegex, controlplanes[0].Name)\n\tassert.Regexp(t, nodeUUIDHostnameRegex, controlplanes[1].Name)\n\tassert.Regexp(t, nodeUUIDHostnameRegex, workers[0].Name)\n\tassert.Regexp(t, nodeUUIDHostnameRegex, workers[1].Name)\n\n\t_, err = m.GetClusterConfigs()\n\tassert.NoError(t, err)\n\n\tm.Ops.OmniAPIEndpoint = \"grpc://10.5.0.1:8090?jointoken=my-token\"\n\terr = m.Init()\n\tassert.NoError(t, err)\n\n\tclusterCfgs, err := m.GetClusterConfigs()\n\tassert.NoError(t, err)\n\n\treq := clusterCfgs.ClusterRequest\n\tassert.Equal(t, \"test-cluster-machine-1\", req.Nodes[0].Name)\n\tassert.Equal(t, \"test-cluster-machine-2\", req.Nodes[1].Name)\n\n\tcfgBytes, err := req.Nodes[0].Config.Bytes()\n\tassert.NoError(t, err)\n\n\tassert.Contains(t, string(cfgBytes), \"apiVersion: v1alpha1\")\n\tassert.Contains(t, string(cfgBytes), \"kind: SideroLinkConfig\")\n\tassert.Contains(t, string(cfgBytes), \"apiUrl: grpc://10.5.0.1:8090?jointoken=my-token\")\n}\n\nfunc TestCommonMaker_MachineConfig(t *testing.T) {\n\tcOps := clusterops.GetCommon()\n\tm := getInitializedTestMaker(t, cOps)\n\n\tassertConfigDefaultness(t, cOps, m)\n}\n\n// assertConfigDefaultness makes sure the maker-generated machine configs are not different from default talos machine configs.\nfunc assertConfigDefaultness[ExtraOps any](t *testing.T, cOps clusterops.Common, m makers.Maker[ExtraOps], desiredExtraGenOps ...generate.Option) {\n\tvar versionContract *config.VersionContract\n\n\tsecretsBundle, err := secrets.NewBundle(secrets.NewClock(), versionContract)\n\trequire.NoError(t, err)\n\n\t// The only allowed differences from the default machine config.\n\tdesiredExtraGenOps = append(desiredExtraGenOps,\n\t\tgenerate.WithSecretsBundle(secretsBundle),\n\t\tgenerate.WithVersionContract(versionContract),\n\t)\n\n\tin, err := generate.NewInput(cOps.RootOps.ClusterName, \"controlplane-endpoint.test\", cOps.KubernetesVersion,\n\t\tdesiredExtraGenOps...,\n\t)\n\trequire.NoError(t, err)\n\n\tm.GenOps = append(m.GenOps, generate.WithSecretsBundle(secretsBundle))\n\n\tclusterCfgs, err := m.GetClusterConfigs()\n\trequire.NoError(t, err)\n\n\tfor _, node := range clusterCfgs.ClusterRequest.Nodes {\n\t\tassertMachineConfig(t, in, node)\n\t}\n}\n\nfunc assertMachineConfig(t *testing.T, in *generate.Input, node provision.NodeRequest) {\n\tcfgExpected, err := in.Config(node.Type)\n\trequire.NoError(t, err)\n\n\tcfgGot := node.Config\n\n\tcfgGot = cfgGot.RedactSecrets(\"secret\")\n\tcfgExpected = cfgExpected.RedactSecrets(\"secret\")\n\n\tcfgExpectedBytes, err := cfgExpected.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\trequire.NoError(t, err)\n\tcfgGotBytes, err := cfgGot.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, string(cfgExpectedBytes), string(cfgGotBytes))\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/docker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers\n\nimport (\n\t\"net\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nvar _ ConfigMaker = &(Docker{})\n\n// Docker is the maker for docker.\ntype Docker struct {\n\t*Maker[clusterops.Docker]\n}\n\n// NewDocker returns a new initialized Docker Maker.\nfunc NewDocker(ops MakerOptions[clusterops.Docker]) (Docker, error) {\n\tmaker, err := New(ops)\n\tif err != nil {\n\t\treturn Docker{}, err\n\t}\n\n\tm := Docker{Maker: &maker}\n\n\tm.SetExtraOptionsProvider(&m)\n\n\tif err := m.Init(); err != nil {\n\t\treturn Docker{}, err\n\t}\n\n\treturn m, nil\n}\n\n// InitExtra implements ExtraOptionsProvider.\nfunc (m *Docker) InitExtra() error { return nil }\n\n// AddExtraConfigBundleOpts implements ExtraOptionsProvider.\nfunc (m *Docker) AddExtraConfigBundleOpts() error { return nil }\n\n// AddExtraGenOps implements ExtraOptionsProvider.\nfunc (m *Docker) AddExtraGenOps() error {\n\tm.GenOps = slices.Concat(m.GenOps, getWithAdditionalSubjectAltNamesGenOps(m.Endpoints))\n\n\treturn nil\n}\n\n// AddExtraProvisionOpts implements ExtraOptionsProvider.\nfunc (m *Docker) AddExtraProvisionOpts() error {\n\tif m.EOps.Ports != \"\" {\n\t\tportList := strings.Split(m.EOps.Ports, \",\")\n\t\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{provision.WithDockerPorts(portList)})\n\t}\n\n\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{provision.WithDockerPortsHostIP(m.EOps.HostIP)})\n\n\treturn nil\n}\n\n// ModifyClusterRequest implements ExtraOptionsProvider.\nfunc (m *Docker) ModifyClusterRequest() error {\n\tm.ClusterRequest.Network.DockerDisableIPv6 = m.EOps.DisableIPv6\n\tm.ClusterRequest.Image = m.EOps.TalosImage\n\n\treturn nil\n}\n\n// ModifyNodes implements ExtraOptionsProvider.\nfunc (m *Docker) ModifyNodes() error {\n\tm.ForEachNode(func(i int, node *provision.NodeRequest) {\n\t\tnode.Mounts = m.EOps.MountOpts.Value()\n\t})\n\n\treturn nil\n}\n\nfunc getWithAdditionalSubjectAltNamesGenOps(endpointList []string) []generate.Option {\n\treturn xslices.Map(endpointList, func(endpointHostPort string) generate.Option {\n\t\tendpointHost, _, err := net.SplitHostPort(endpointHostPort)\n\t\tif err != nil {\n\t\t\tendpointHost = endpointHostPort\n\t\t}\n\n\t\treturn generate.WithAdditionalSubjectAltNames([]string{endpointHost})\n\t})\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/docker_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n)\n\nfunc TestDockerMaker_MachineConfig(t *testing.T) {\n\tcOps := clusterops.GetCommon()\n\tdOps := clusterops.GetDocker()\n\n\tm, err := makers.NewDocker(makers.MakerOptions[clusterops.Docker]{\n\t\tExtraOps:    dOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: testProvisioner{}, // use test provisioner to simplify the test case.\n\t})\n\trequire.NoError(t, err)\n\n\tdesiredExtraGenOps := []generate.Option{\n\t\tgenerate.WithAdditionalSubjectAltNames([]string{\"talos-api-endpoint.test\"}),\n\t}\n\n\tassertConfigDefaultness(t, cOps, *m.Maker, desiredExtraGenOps...)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/maker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers\n\nimport \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\n// ConfigMaker helps creating cluster and provision configuration.\ntype ConfigMaker interface {\n\tGetClusterConfigs() (clusterops.ClusterConfigs, error)\n}\n\n// ExtraOptionsProvider are used to implement provider specific logic.\ntype ExtraOptionsProvider interface {\n\tInitExtra() error\n\tAddExtraGenOps() error\n\tAddExtraProvisionOpts() error\n\tAddExtraConfigBundleOpts() error\n\tModifyClusterRequest() error\n\tModifyNodes() error\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\tsideronet \"github.com/siderolabs/net\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/siderolinkbuilder\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/internal/firewallpatch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\tconfigbase \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\t// vipOffset is the offset from the network address of the CIDR to use for allocating the Virtual (shared) IP address, if enabled.\n\tvipOffset = 50\n)\n\nvar _ ConfigMaker = &(Qemu{})\n\n// Qemu is the maker for qemu.\ntype Qemu struct {\n\t*Maker[clusterops.Qemu]\n\n\tVIP               netip.Addr\n\tSideroLinkBuilder *siderolinkbuilder.SiderolinkBuilder\n}\n\n// NewQemu returns a new qemu Maker.\nfunc NewQemu(ops MakerOptions[clusterops.Qemu]) (Qemu, error) {\n\tmaker, err := New(ops)\n\tif err != nil {\n\t\treturn Qemu{}, err\n\t}\n\n\tm := Qemu{Maker: &maker}\n\n\tm.SetExtraOptionsProvider(&m)\n\n\tif err := m.Init(); err != nil {\n\t\treturn Qemu{}, err\n\t}\n\n\treturn m, nil\n}\n\n// InitExtra implements ExtraOptionsProvider.\nfunc (m *Qemu) InitExtra() error {\n\tif m.EOps.UseVIP {\n\t\tvip, err := sideronet.NthIPInNetwork(m.Cidrs[0], vipOffset)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tm.VIP = vip\n\n\t\tm.InClusterEndpoint = \"https://\" + nethelpers.JoinHostPort(vip.String(), m.Ops.ControlPlanePort)\n\t}\n\n\tif err := m.initDisks(); err != nil {\n\t\treturn err\n\t}\n\n\tif m.EOps.WithSiderolinkAgent.IsEnabled() {\n\t\tslb, err := siderolinkbuilder.New(context.Background(), m.GatewayIPs[0].String(), m.EOps.WithSiderolinkAgent.IsTLS())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tm.SideroLinkBuilder = slb\n\t}\n\n\tm.initEndpoints()\n\n\tif m.Ops.WithJSONLogs {\n\t\tm.initJSONLogs()\n\t}\n\n\treturn nil\n}\n\nfunc (m *Qemu) initEndpoints() {\n\tswitch {\n\tcase m.Ops.ForceEndpoint != \"\":\n\t\t// using non-default endpoints, provision additional cert SANs and fix endpoint list\n\t\tm.Endpoints = []string{m.Ops.ForceEndpoint}\n\tcase m.Ops.ForceInitNodeAsEndpoint:\n\t\tm.Endpoints = []string{m.IPs[0][0].String()}\n\tcase m.Endpoints == nil:\n\t\t// use control plane nodes as endpoints, client-side load-balancing\n\t\tfor i := range m.Ops.Controlplanes {\n\t\t\tm.Endpoints = slices.Concat(m.Endpoints, []string{m.IPs[0][i].String()})\n\t\t}\n\t}\n}\n\n// AddExtraGenOps implements ExtraOptionsProvider.\nfunc (m *Qemu) AddExtraGenOps() error {\n\tm.GenOps = slices.Concat(m.GenOps, []generate.Option{generate.WithInstallImage(m.EOps.NodeInstallImage)})\n\n\tif m.Ops.CustomCNIUrl != \"\" {\n\t\tm.GenOps = slices.Concat(m.GenOps, []generate.Option{generate.WithClusterCNIConfig(&v1alpha1.CNIConfig{\n\t\t\tCNIName: constants.CustomCNI,\n\t\t\tCNIUrls: []string{m.Ops.CustomCNIUrl},\n\t\t})})\n\t}\n\n\tif m.EOps.UseVIP {\n\t\tif m.VersionContract.MultidocNetworkConfigSupported() {\n\t\t\tvipCfg := networkcfg.NewLayer2VIPConfigV1Alpha1(m.VIP.String())\n\t\t\tvipCfg.LinkName = m.Provisioner.GetFirstInterfaceName()\n\n\t\t\tctr, err := container.New(vipCfg)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tm.ConfigBundleOps = append(m.ConfigBundleOps,\n\t\t\t\tbundle.WithPatchControlPlane([]configpatcher.Patch{configpatcher.NewStrategicMergePatch(ctr)}),\n\t\t\t)\n\t\t} else {\n\t\t\tm.GenOps = slices.Concat(m.GenOps,\n\t\t\t\t[]generate.Option{generate.WithNetworkOptions(\n\t\t\t\t\tv1alpha1.WithNetworkInterfaceVirtualIP(m.Provisioner.GetFirstInterface(), m.VIP.String()),\n\t\t\t\t)},\n\t\t\t)\n\t\t}\n\t}\n\n\t// disable kexec, if bootloader is disabled, and\n\t// also disable kexec on arm64 due to https://github.com/siderolabs/talos/issues/12393\n\tif !m.EOps.BootloaderEnabled || m.EOps.TargetArch == \"arm64\" {\n\t\tm.GenOps = slices.Concat(m.GenOps, []generate.Option{\n\t\t\tgenerate.WithSysctls(map[string]string{\n\t\t\t\t\"kernel.kexec_load_disabled\": \"1\",\n\t\t\t}),\n\t\t})\n\t}\n\n\tif m.Ops.ForceEndpoint != \"\" {\n\t\tm.GenOps = slices.Concat(m.GenOps, []generate.Option{generate.WithAdditionalSubjectAltNames(m.Endpoints)})\n\t}\n\n\treturn nil\n}\n\n// AddExtraProvisionOpts implements ExtraOptionsProvider.\nfunc (m *Qemu) AddExtraProvisionOpts() error {\n\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{\n\t\tprovision.WithBootlader(m.EOps.BootloaderEnabled),\n\t\tprovision.WithSkipInjectingExtraCmdline(m.EOps.SkipInjectingExtraCmdline),\n\t\tprovision.WithUEFI(m.EOps.UefiEnabled),\n\t\tprovision.WithTPM1_2(m.EOps.Tpm1_2Enabled),\n\t\tprovision.WithTPM2(m.EOps.Tpm2Enabled),\n\t\tprovision.WithDebugShell(m.EOps.DebugShellEnabled),\n\t\tprovision.WithIOMMU(m.EOps.WithIOMMU),\n\t\tprovision.WithExtraUEFISearchPaths(m.EOps.ExtraUEFISearchPaths),\n\t\tprovision.WithTargetArch(m.EOps.TargetArch),\n\t\tprovision.WithSiderolinkAgent(m.EOps.WithSiderolinkAgent.IsEnabled()),\n\t})\n\n\texternalKubernetesEndpoint := m.Provisioner.GetExternalKubernetesControlPlaneEndpoint(m.ClusterRequest.Network, m.Ops.ControlPlanePort)\n\n\tif m.EOps.UseVIP {\n\t\texternalKubernetesEndpoint = \"https://\" + nethelpers.JoinHostPort(m.VIP.String(), m.Ops.ControlPlanePort)\n\t}\n\n\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{provision.WithKubernetesEndpoint(externalKubernetesEndpoint)})\n\n\treturn nil\n}\n\n// AddExtraConfigBundleOpts implements ExtraOptionsProvider.\nfunc (m *Qemu) AddExtraConfigBundleOpts() error {\n\tif m.EOps.WithFirewall != \"\" {\n\t\tvar defaultAction nethelpers.DefaultAction\n\n\t\tdefaultAction, err := nethelpers.DefaultActionString(m.EOps.WithFirewall)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar controlplaneIPs []netip.Addr\n\n\t\tfor i := range m.IPs {\n\t\t\tcontrolplaneIPs = slices.Concat(controlplaneIPs, m.IPs[i][:m.Ops.Controlplanes])\n\t\t}\n\n\t\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps,\n\t\t\t[]bundle.Option{\n\t\t\t\tbundle.WithPatchControlPlane([]configpatcher.Patch{firewallpatch.ControlPlane(defaultAction, m.Cidrs, m.GatewayIPs, controlplaneIPs)}),\n\t\t\t\tbundle.WithPatchWorker([]configpatcher.Patch{firewallpatch.Worker(defaultAction, m.Cidrs, m.GatewayIPs)}),\n\t\t\t})\n\t}\n\n\tif err := m.addDiskEncryptionPatches(); err != nil {\n\t\treturn err\n\t}\n\n\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps, []bundle.Option{\n\t\tbundle.WithPatch(m.SideroLinkBuilder.ConfigPatches(m.EOps.WithSiderolinkAgent.IsTunnel())),\n\t})\n\n\treturn nil\n}\n\n// ModifyClusterRequest implements ExtraOptionsProvider.\nfunc (m *Qemu) ModifyClusterRequest() error {\n\tnameserverIPs, err := getNameserverIPs(m.EOps.Nameservers, m.GatewayIPs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnoMasqueradeCIDRs := make([]netip.Prefix, 0, len(m.EOps.NetworkNoMasqueradeCIDRs))\n\n\tfor _, cidr := range m.EOps.NetworkNoMasqueradeCIDRs {\n\t\tvar parsedCIDR netip.Prefix\n\n\t\tparsedCIDR, err = netip.ParsePrefix(cidr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing non-masquerade CIDR %q: %w\", cidr, err)\n\t\t}\n\n\t\tnoMasqueradeCIDRs = append(noMasqueradeCIDRs, parsedCIDR)\n\t}\n\n\terr = m.validateNetworkChaosParams()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tm.ClusterRequest.Network.CNI = provision.CNIConfig{\n\t\tBinPath:  m.EOps.CniBinPath,\n\t\tConfDir:  m.EOps.CniConfDir,\n\t\tCacheDir: m.EOps.CniCacheDir,\n\n\t\tBundleURL: m.EOps.CniBundleURL,\n\t}\n\tm.ClusterRequest.Network.Nameservers = nameserverIPs\n\tm.ClusterRequest.Network.NoMasqueradeCIDRs = noMasqueradeCIDRs\n\tm.ClusterRequest.Network.DHCPSkipHostname = m.EOps.DHCPSkipHostname\n\tm.ClusterRequest.Network.NetworkChaos = m.EOps.NetworkChaos\n\tm.ClusterRequest.Network.Jitter = m.EOps.Jjitter\n\tm.ClusterRequest.Network.Latency = m.EOps.Latency\n\tm.ClusterRequest.Network.PacketLoss = m.EOps.PacketLoss\n\tm.ClusterRequest.Network.PacketReorder = m.EOps.PacketReorder\n\tm.ClusterRequest.Network.PacketCorrupt = m.EOps.PacketCorrupt\n\tm.ClusterRequest.Network.Bandwidth = m.EOps.Bandwidth\n\tm.ClusterRequest.Network.Airgapped = m.EOps.Airgapped\n\tm.ClusterRequest.Network.ImageCachePath = m.EOps.ImageCachePath\n\tm.ClusterRequest.Network.ImageCacheTLSCertFile = m.EOps.ImageCacheTLSCertFile\n\tm.ClusterRequest.Network.ImageCacheTLSKeyFile = m.EOps.ImageCacheTLSKeyFile\n\tm.ClusterRequest.Network.ImageCachePort = m.EOps.ImageCachePort\n\n\tm.ClusterRequest.KernelPath = m.EOps.NodeVmlinuzPath\n\tm.ClusterRequest.InitramfsPath = m.EOps.NodeInitramfsPath\n\tm.ClusterRequest.ISOPath = m.EOps.NodeISOPath\n\tm.ClusterRequest.USBPath = m.EOps.NodeUSBPath\n\tm.ClusterRequest.UKIPath = m.EOps.NodeUKIPath\n\tm.ClusterRequest.IPXEBootScript = m.EOps.NodeIPXEBootScript\n\tm.ClusterRequest.DiskImagePath = m.EOps.NodeDiskImagePath\n\n\treturn nil\n}\n\nfunc (m *Qemu) validateNetworkChaosParams() error {\n\tif !m.EOps.NetworkChaos {\n\t\tif m.EOps.Jjitter != 0 || m.EOps.Latency != 0 || m.EOps.PacketLoss != 0 || m.EOps.PacketReorder != 0 || m.EOps.PacketCorrupt != 0 || m.EOps.Bandwidth != 0 {\n\t\t\treturn errors.New(\"network chaos flags can only be used with network-chaos option enabled\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ModifyNodes implements ExtraOptionsProvider.\nfunc (m *Qemu) ModifyNodes() error {\n\tvar configInjectionMethod provision.ConfigInjectionMethod\n\n\tswitch m.EOps.ConfigInjectionMethod {\n\tcase \"\", \"default\", \"http\":\n\t\tconfigInjectionMethod = provision.ConfigInjectionMethodHTTP\n\tcase \"metal-iso\":\n\t\tconfigInjectionMethod = provision.ConfigInjectionMethodMetalISO\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown config injection method %d\", configInjectionMethod)\n\t}\n\n\tvar extraKernelArgs *procfs.Cmdline\n\n\tif m.EOps.ExtraBootKernelArgs != \"\" || m.EOps.WithSiderolinkAgent.IsEnabled() {\n\t\textraKernelArgs = procfs.NewCmdline(m.EOps.ExtraBootKernelArgs)\n\t}\n\n\terr := m.SideroLinkBuilder.SetKernelArgs(extraKernelArgs, m.EOps.WithSiderolinkAgent.IsTunnel())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i := range m.ClusterRequest.Nodes {\n\t\tnode := &m.ClusterRequest.Nodes[i]\n\n\t\terr := m.SideroLinkBuilder.DefineIPv6ForUUID(*node.UUID)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnode.ConfigInjectionMethod = configInjectionMethod\n\t\tnode.Quirks = quirks.New(m.Ops.TalosVersion)\n\t\tnode.SkipInjectingConfig = m.Ops.SkipInjectingConfig\n\t\tnode.BadRTC = m.EOps.BadRTC\n\t\tnode.ExtraKernelArgs = extraKernelArgs\n\t}\n\n\tm.ClusterRequest.SiderolinkRequest = m.SideroLinkBuilder.SiderolinkRequest()\n\n\treturn nil\n}\n\nfunc (m *Qemu) addDiskEncryptionPatches() error {\n\tvar diskEncryptionPatches []configpatcher.Patch\n\n\tif m.EOps.EncryptStatePartition || m.EOps.EncryptEphemeralPartition {\n\t\tkeys, err := m.getEncryptionKeys(m.EOps.DiskEncryptionKeyTypes)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !m.VersionContract.VolumeConfigEncryptionSupported() {\n\t\t\t// legacy v1alpha1 flow to support booting old Talos versions\n\t\t\tpatch, err := m.getLegacyDiskEncryptionPatch(keys)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdiskEncryptionPatches = append(diskEncryptionPatches, patch)\n\t\t} else {\n\t\t\tfor _, spec := range []struct {\n\t\t\t\tlabel   string\n\t\t\t\tenabled bool\n\t\t\t}{\n\t\t\t\t{label: constants.StatePartitionLabel, enabled: m.EOps.EncryptStatePartition},\n\t\t\t\t{label: constants.EphemeralPartitionLabel, enabled: m.EOps.EncryptEphemeralPartition},\n\t\t\t} {\n\t\t\t\tif !spec.enabled {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tpatch, err := m.getDiskEncryptionPatch(spec, keys)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tdiskEncryptionPatches = append(diskEncryptionPatches, patch)\n\t\t\t}\n\t\t}\n\t}\n\n\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps,\n\t\t[]bundle.Option{bundle.WithPatch(diskEncryptionPatches)},\n\t)\n\n\treturn nil\n}\n\nfunc (*Qemu) getDiskEncryptionPatch(spec struct {\n\tlabel   string\n\tenabled bool\n}, keys []*v1alpha1.EncryptionKey,\n) (configpatcher.StrategicMergePatch, error) {\n\tblockCfg := block.NewVolumeConfigV1Alpha1()\n\tblockCfg.MetaName = spec.label\n\tblockCfg.EncryptionSpec = block.EncryptionSpec{\n\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\tEncryptionKeys:     convertEncryptionKeys(keys),\n\t}\n\n\tif spec.label != constants.StatePartitionLabel {\n\t\tfor idx := range blockCfg.EncryptionSpec.EncryptionKeys {\n\t\t\tblockCfg.EncryptionSpec.EncryptionKeys[idx].KeyLockToSTATE = new(true)\n\t\t}\n\t}\n\n\tctr, err := container.New(blockCfg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating container for %q volume: %w\", spec.label, err)\n\t}\n\n\tpatch := configpatcher.NewStrategicMergePatch(ctr)\n\n\treturn patch, nil\n}\n\nfunc (m *Qemu) getLegacyDiskEncryptionPatch(keys []*v1alpha1.EncryptionKey) (configpatcher.Patch, error) {\n\tdiskEncryptionConfig := &v1alpha1.SystemDiskEncryptionConfig{}\n\n\tif m.EOps.EncryptStatePartition {\n\t\tdiskEncryptionConfig.StatePartition = &v1alpha1.EncryptionConfig{\n\t\t\tEncryptionProvider: encryption.LUKS2,\n\t\t\tEncryptionKeys:     keys,\n\t\t}\n\t}\n\n\tif m.EOps.EncryptEphemeralPartition {\n\t\tdiskEncryptionConfig.EphemeralPartition = &v1alpha1.EncryptionConfig{\n\t\t\tEncryptionProvider: encryption.LUKS2,\n\t\t\tEncryptionKeys:     keys,\n\t\t}\n\t}\n\n\tpatchRaw := map[string]any{\n\t\t\"machine\": map[string]any{\n\t\t\t\"systemDiskEncryption\": diskEncryptionConfig,\n\t\t},\n\t}\n\n\tpatchData, err := yaml.Marshal(patchRaw)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error marshaling patch: %w\", err)\n\t}\n\n\tpatch, err := configpatcher.LoadPatch(patchData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error loading patch: %w\", err)\n\t}\n\n\treturn patch, nil\n}\n\nfunc (m *Qemu) initDisks() error {\n\tworkerExtraDisks := make([]*provision.Disk, 0, len(m.EOps.Disks.Requests())-1)\n\n\tprimaryDisks := []*provision.Disk{\n\t\t{\n\t\t\tSize:            m.EOps.Disks.Requests()[0].Size.Bytes(),\n\t\t\tSkipPreallocate: !m.EOps.PreallocateDisks,\n\t\t\tDriver:          m.EOps.Disks.Requests()[0].Driver,\n\t\t\tBlockSize:       m.EOps.DiskBlockSize,\n\t\t\tSerial:          m.EOps.Disks.Requests()[0].Serial,\n\t\t},\n\t}\n\t// get worker extra disks\n\tfor _, d := range m.EOps.Disks.Requests()[1:] {\n\t\tworkerExtraDisks = append(workerExtraDisks, &provision.Disk{\n\t\t\tSize:            d.Size.Bytes(),\n\t\t\tSkipPreallocate: !m.EOps.PreallocateDisks,\n\t\t\tDriver:          d.Driver,\n\t\t\tBlockSize:       m.EOps.DiskBlockSize,\n\t\t\tTag:             d.Tag,\n\t\t\tSerial:          d.Serial,\n\t\t})\n\t}\n\n\tm.ForEachNode(func(i int, node *provision.NodeRequest) {\n\t\tnode.Disks = slices.Concat(node.Disks, primaryDisks)\n\t})\n\n\tif err := m.initExtraDisks(); err != nil {\n\t\treturn err\n\t}\n\n\tm.ForEachNode(func(i int, node *provision.NodeRequest) {\n\t\tif node.Type == machine.TypeWorker {\n\t\t\tnode.Disks = slices.Concat(node.Disks, workerExtraDisks)\n\t\t}\n\t})\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (m *Qemu) initExtraDisks() error {\n\tconst GPTAlignment = 2 * 1024 * 1024 // 2 MB\n\n\tvar (\n\t\tuserVolumes    []*block.UserVolumeConfigV1Alpha1\n\t\tencryptionSpec block.EncryptionSpec\n\t)\n\n\tif m.EOps.EncryptUserVolumes {\n\t\tencryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\n\t\tkeys, err := m.getEncryptionKeys(m.EOps.DiskEncryptionKeyTypes)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tencryptionSpec.EncryptionKeys = convertEncryptionKeys(keys)\n\t}\n\n\tdisks := make([]*provision.Disk, 0, len(m.EOps.ClusterUserVolumes))\n\n\tfor diskID, disk := range m.EOps.ClusterUserVolumes {\n\t\tvar (\n\t\t\tvolumes  = strings.Split(disk, \":\")\n\t\t\tdiskSize uint64\n\t\t)\n\n\t\tif len(volumes)%2 != 0 {\n\t\t\treturn errors.New(\"failed to parse malformed volume definitions\")\n\t\t}\n\n\t\tfor j := 0; j < len(volumes); j += 2 {\n\t\t\tvolumeName := volumes[j]\n\t\t\tvolumeSize := volumes[j+1]\n\n\t\t\tuserVolume := block.NewUserVolumeConfigV1Alpha1()\n\t\t\tuserVolume.MetaName = volumeName\n\t\t\tuserVolume.ProvisioningSpec = block.ProvisioningSpec{\n\t\t\t\tDiskSelectorSpec: block.DiskSelector{\n\t\t\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", m.Provisioner.UserDiskName(diskID+1)), celenv.DiskLocator())),\n\t\t\t\t},\n\t\t\t\tProvisioningMinSize: block.MustByteSize(volumeSize),\n\t\t\t\tProvisioningMaxSize: block.MustSize(volumeSize),\n\t\t\t}\n\t\t\tuserVolume.EncryptionSpec = encryptionSpec\n\n\t\t\tuserVolumes = append(userVolumes, userVolume)\n\t\t\tdiskSize += userVolume.ProvisioningSpec.ProvisioningMaxSize.Value()\n\t\t}\n\n\t\tdisks = append(disks, &provision.Disk{\n\t\t\t// add 2 MB per partition to make extra room for GPT and alignment\n\t\t\tSize:            diskSize + GPTAlignment*uint64(len(volumes)/2+1),\n\t\t\tSkipPreallocate: !m.EOps.PreallocateDisks,\n\t\t\tDriver:          \"ide\",\n\t\t\tBlockSize:       m.EOps.DiskBlockSize,\n\t\t})\n\t}\n\n\tif len(userVolumes) > 0 {\n\t\tctr, err := container.New(xslices.Map(userVolumes, func(u *block.UserVolumeConfigV1Alpha1) configbase.Document { return u })...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create user volumes container: %w\", err)\n\t\t}\n\n\t\tuserVolumePatches := []configpatcher.Patch{configpatcher.NewStrategicMergePatch(ctr)}\n\t\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps, []bundle.Option{bundle.WithPatch(userVolumePatches)})\n\t}\n\n\tm.ForEachNode(func(i int, node *provision.NodeRequest) {\n\t\tnode.Disks = slices.Concat(node.Disks, disks)\n\t})\n\n\treturn nil\n}\n\nfunc (m *Qemu) getEncryptionKeys(diskEncryptionKeyTypes []string) ([]*v1alpha1.EncryptionKey, error) {\n\tvar keys []*v1alpha1.EncryptionKey\n\n\tfor i, key := range diskEncryptionKeyTypes {\n\t\tswitch key {\n\t\tcase \"uuid\":\n\t\t\tkeys = append(keys, &v1alpha1.EncryptionKey{\n\t\t\t\tKeyNodeID: &v1alpha1.EncryptionKeyNodeID{},\n\t\t\t\tKeySlot:   i,\n\t\t\t})\n\t\tcase \"kms\":\n\t\t\tvar ip netip.Addr\n\n\t\t\t// get bridge IP\n\t\t\tip, err := sideronet.NthIPInNetwork(m.Cidrs[0], 1)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tconst port = 4050\n\n\t\t\tkeys = append(keys, &v1alpha1.EncryptionKey{\n\t\t\t\tKeyKMS: &v1alpha1.EncryptionKeyKMS{\n\t\t\t\t\tKMSEndpoint: \"grpc://\" + nethelpers.JoinHostPort(ip.String(), port),\n\t\t\t\t},\n\t\t\t\tKeySlot: i,\n\t\t\t})\n\n\t\t\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{provision.WithKMS(nethelpers.JoinHostPort(\"0.0.0.0\", port))})\n\t\tcase \"tpm\":\n\t\t\tkeyTPM := &v1alpha1.EncryptionKeyTPM{}\n\n\t\t\tif m.VersionContract.SecureBootEnrollEnforcementSupported() {\n\t\t\t\tkeyTPM.TPMCheckSecurebootStatusOnEnroll = new(true)\n\t\t\t}\n\n\t\t\tkeys = append(keys, &v1alpha1.EncryptionKey{\n\t\t\t\tKeyTPM:  keyTPM,\n\t\t\t\tKeySlot: i,\n\t\t\t})\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown key type %q\", key)\n\t\t}\n\t}\n\n\tif len(keys) == 0 {\n\t\treturn nil, errors.New(\"no disk encryption key types enabled\")\n\t}\n\n\treturn keys, nil\n}\n\nfunc convertEncryptionKeys(keys []*v1alpha1.EncryptionKey) []block.EncryptionKey {\n\treturn xslices.Map(keys, func(k *v1alpha1.EncryptionKey) block.EncryptionKey {\n\t\tr := block.EncryptionKey{\n\t\t\tKeySlot: k.KeySlot,\n\t\t}\n\n\t\tif k.KeyKMS != nil {\n\t\t\tr.KeyKMS = new(block.EncryptionKeyKMS(*k.KeyKMS))\n\t\t}\n\n\t\tif k.KeyTPM != nil {\n\t\t\tencryptionKeyTPM := block.EncryptionKeyTPM{\n\t\t\t\tTPMCheckSecurebootStatusOnEnroll: k.KeyTPM.TPMCheckSecurebootStatusOnEnroll,\n\t\t\t}\n\n\t\t\tr.KeyTPM = new(encryptionKeyTPM)\n\t\t}\n\n\t\tif k.KeyNodeID != nil {\n\t\t\tr.KeyNodeID = new(block.EncryptionKeyNodeID(*k.KeyNodeID))\n\t\t}\n\n\t\tif k.KeyStatic != nil {\n\t\t\tr.KeyStatic = new(block.EncryptionKeyStatic(*k.KeyStatic))\n\t\t}\n\n\t\treturn r\n\t})\n}\n\nfunc (m *Qemu) initJSONLogs() {\n\tconst port = 4003\n\n\tm.ProvisionOps = slices.Concat(m.ProvisionOps, []provision.Option{provision.WithJSONLogs(nethelpers.JoinHostPort(m.GatewayIPs[0].String(), port))})\n\n\tcfg := container.NewV1Alpha1(\n\t\t&v1alpha1.Config{\n\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineLogging: &v1alpha1.LoggingConfig{\n\t\t\t\t\tLoggingDestinations: []v1alpha1.LoggingDestination{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLoggingEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\t\tURL: &url.URL{\n\t\t\t\t\t\t\t\t\tScheme: \"tcp\",\n\t\t\t\t\t\t\t\t\tHost:   nethelpers.JoinHostPort(m.GatewayIPs[0].String(), port),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLoggingFormat: \"json_lines\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\n\tm.ConfigBundleOps = slices.Concat(m.ConfigBundleOps, []bundle.Option{bundle.WithPatch([]configpatcher.Patch{configpatcher.NewStrategicMergePatch(cfg)})})\n}\n\nfunc getNameserverIPs(nameservers []string, gatewayIPs []netip.Addr) ([]netip.Addr, error) {\n\tnameserverIPs := make([]netip.Addr, len(nameservers))\n\n\tif len(nameservers) == 0 {\n\t\treturn gatewayIPs, nil\n\t}\n\n\tfor i := range nameserverIPs {\n\t\tip, err := netip.ParseAddr(nameservers[i])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed parsing nameserver IP %q: %w\", nameservers[i], err)\n\t\t}\n\n\t\tnameserverIPs[i] = ip\n\t}\n\n\treturn nameserverIPs, nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/qemu_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makers_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc TestQemuMaker_MachineConfig(t *testing.T) {\n\tcOps := clusterops.GetCommon()\n\tqOps := clusterops.GetQemu()\n\n\tm, err := makers.NewQemu(makers.MakerOptions[clusterops.Qemu]{\n\t\tExtraOps:    qOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: testProvisioner{}, // use test provisioner to simplify the test case.\n\t})\n\trequire.NoError(t, err)\n\n\tdesiredExtraGenOps := []generate.Option{}\n\n\tassertConfigDefaultness(t, cOps, *m.Maker, desiredExtraGenOps...)\n}\n\nfunc TestQemuMaker_Disks(t *testing.T) {\n\tcOps := clusterops.GetCommon()\n\tqOps := clusterops.GetQemu()\n\n\tdisks := flags.Disks{}\n\terr := disks.Set(\"virtio:10GiB,nvme:20GiB,virtio:30GiB\")\n\trequire.NoError(t, err)\n\n\tqOps.Disks = disks\n\tcOps.Controlplanes = 1\n\tcOps.Workers = 1\n\n\tm, err := makers.NewQemu(makers.MakerOptions[clusterops.Qemu]{\n\t\tExtraOps:    qOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: testProvisioner{}, // use test provisioner to simplify the test case.\n\t})\n\trequire.NoError(t, err)\n\n\treq, err := m.GetClusterConfigs()\n\trequire.NoError(t, err)\n\n\tcontrolplaneDisks := req.ClusterRequest.Nodes[0].Disks\n\tworkerDisks := req.ClusterRequest.Nodes[1].Disks\n\n\tassert.Equal(t, 1, len(controlplaneDisks))\n\tassert.Equal(t, 3, len(workerDisks))\n\n\tassert.Equal(t, []*provision.Disk{\n\t\t{\n\t\t\tSize:            disks.Requests()[0].Size.Bytes(),\n\t\t\tSkipPreallocate: !qOps.PreallocateDisks,\n\t\t\tDriver:          \"virtio\",\n\t\t\tBlockSize:       qOps.DiskBlockSize,\n\t\t\tSerial:          \"\",\n\t\t},\n\t}, controlplaneDisks)\n\n\tassert.Equal(t, []*provision.Disk{\n\t\t{\n\t\t\tSize:            disks.Requests()[0].Size.Bytes(),\n\t\t\tSkipPreallocate: !qOps.PreallocateDisks,\n\t\t\tDriver:          \"virtio\",\n\t\t\tBlockSize:       qOps.DiskBlockSize,\n\t\t\tSerial:          \"\",\n\t\t},\n\t\t{\n\t\t\tSize:            disks.Requests()[1].Size.Bytes(),\n\t\t\tSkipPreallocate: !qOps.PreallocateDisks,\n\t\t\tDriver:          \"nvme\",\n\t\t\tBlockSize:       qOps.DiskBlockSize,\n\t\t\tSerial:          \"\",\n\t\t},\n\t\t{\n\t\t\tSize:            disks.Requests()[2].Size.Bytes(),\n\t\t\tSkipPreallocate: !qOps.PreallocateDisks,\n\t\t\tDriver:          \"virtio\",\n\t\t\tBlockSize:       qOps.DiskBlockSize,\n\t\t\tSerial:          \"\",\n\t\t},\n\t}, workerDisks)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/siderolinkbuilder/builder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolinkbuilder\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tconfigbase \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// New creates a new SiderolinkBuilder.\nfunc New(ctx context.Context, wgHost string, useTLS bool) (*SiderolinkBuilder, error) {\n\tprefix, err := networkPrefix(\"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := &SiderolinkBuilder{\n\t\twgHost:       wgHost,\n\t\tbinds:        map[uuid.UUID]netip.Addr{},\n\t\tprefix:       prefix,\n\t\tnodeIPv6Addr: prefix.Addr().Next().String(),\n\t}\n\n\tif useTLS {\n\t\tca, err := x509.NewSelfSignedCertificateAuthority(x509.ECDSA(true), x509.IPAddresses([]net.IP{net.ParseIP(wgHost)}))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult.apiCert = ca.CrtPEM\n\t\tresult.apiKey = ca.KeyPEM\n\t}\n\n\tvar resultErr error\n\n\tfor range 10 {\n\t\tfor _, d := range []struct {\n\t\t\tfield *int\n\t\t\tnet   string\n\t\t\twhat  string\n\t\t}{\n\t\t\t{&result.wgPort, \"udp\", \"WireGuard\"},\n\t\t\t{&result.apiPort, \"tcp\", \"gRPC API\"},\n\t\t\t{&result.sinkPort, \"tcp\", \"Event Sink\"},\n\t\t\t{&result.logPort, \"tcp\", \"Log Receiver\"},\n\t\t} {\n\t\t\tvar err error\n\n\t\t\t*d.field, err = getDynamicPort(ctx, d.net)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get dynamic port for %s: %w\", d.what, err)\n\t\t\t}\n\t\t}\n\n\t\tresultErr = checkPortsDontOverlap(result.wgPort, result.apiPort, result.sinkPort, result.logPort)\n\t\tif resultErr == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif resultErr != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get non-overlapping dynamic ports in 10 attempts: %w\", resultErr)\n\t}\n\n\treturn result, nil\n}\n\n// SiderolinkBuilder is responsible for building Siderolink configurations.\ntype SiderolinkBuilder struct {\n\twgHost string\n\n\tbinds        map[uuid.UUID]netip.Addr\n\tprefix       netip.Prefix\n\tnodeIPv6Addr string\n\twgPort       int\n\tapiPort      int\n\tsinkPort     int\n\tlogPort      int\n\n\tapiCert []byte\n\tapiKey  []byte\n}\n\n// DefineIPv6ForUUID defines an IPv6 address for a given UUID. It is safe to call this method on a nil pointer.\nfunc (slb *SiderolinkBuilder) DefineIPv6ForUUID(id uuid.UUID) error {\n\tif slb == nil {\n\t\treturn nil\n\t}\n\n\tresult, err := generateRandomNodeAddr(slb.prefix)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tslb.binds[id] = result.Addr()\n\n\treturn nil\n}\n\n// SiderolinkRequest returns a SiderolinkRequest based on the current state of the builder.\n// It is safe to call this method on a nil pointer.\nfunc (slb *SiderolinkBuilder) SiderolinkRequest() provision.SiderolinkRequest {\n\tif slb == nil {\n\t\treturn provision.SiderolinkRequest{}\n\t}\n\n\treturn provision.SiderolinkRequest{\n\t\tWireguardEndpoint: net.JoinHostPort(slb.wgHost, strconv.Itoa(slb.wgPort)),\n\t\tAPIEndpoint:       \":\" + strconv.Itoa(slb.apiPort),\n\t\tAPICertificate:    slb.apiCert,\n\t\tAPIKey:            slb.apiKey,\n\t\tSinkEndpoint:      \":\" + strconv.Itoa(slb.sinkPort),\n\t\tLogEndpoint:       \":\" + strconv.Itoa(slb.logPort),\n\t\tSiderolinkBind: maps.ToSlice(slb.binds, func(k uuid.UUID, v netip.Addr) provision.SiderolinkBind {\n\t\t\treturn provision.SiderolinkBind{\n\t\t\t\tUUID: k,\n\t\t\t\tAddr: v,\n\t\t\t}\n\t\t}),\n\t}\n}\n\n// ConfigPatches returns the config patches for the current builder.\nfunc (slb *SiderolinkBuilder) ConfigPatches(tunnel bool) []configpatcher.Patch {\n\tcfg := slb.ConfigDocument(tunnel)\n\tif cfg == nil {\n\t\treturn nil\n\t}\n\n\treturn []configpatcher.Patch{configpatcher.NewStrategicMergePatch(cfg)}\n}\n\n// ConfigDocument returns the config document for the current builder.\nfunc (slb *SiderolinkBuilder) ConfigDocument(tunnel bool) config.Provider {\n\tif slb == nil {\n\t\treturn nil\n\t}\n\n\tscheme := \"grpc://\"\n\n\tif slb.apiCert != nil {\n\t\tscheme = \"https://\"\n\t}\n\n\tapiLink := scheme + net.JoinHostPort(slb.wgHost, strconv.Itoa(slb.apiPort)) + \"?jointoken=foo\"\n\n\tif tunnel {\n\t\tapiLink += \"&grpc_tunnel=true\"\n\t}\n\n\tapiURL, err := url.Parse(apiLink)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"failed to parse API URL: %s\", err))\n\t}\n\n\tsdlConfig := siderolink.NewConfigV1Alpha1()\n\tsdlConfig.APIUrlConfig.URL = apiURL\n\n\teventsConfig := runtime.NewEventSinkV1Alpha1()\n\teventsConfig.Endpoint = net.JoinHostPort(slb.nodeIPv6Addr, strconv.Itoa(slb.sinkPort))\n\n\tlogURL, err := url.Parse(\"tcp://\" + net.JoinHostPort(slb.nodeIPv6Addr, strconv.Itoa(slb.logPort)))\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"failed to parse log URL: %s\", err))\n\t}\n\n\tlogConfig := runtime.NewKmsgLogV1Alpha1()\n\tlogConfig.MetaName = \"siderolink\"\n\tlogConfig.KmsgLogURL.URL = logURL\n\n\tdocuments := []configbase.Document{\n\t\tsdlConfig,\n\t\teventsConfig,\n\t\tlogConfig,\n\t}\n\n\tif slb.apiCert != nil {\n\t\ttrustedRootsConfig := security.NewTrustedRootsConfigV1Alpha1()\n\t\ttrustedRootsConfig.MetaName = \"siderolink-ca\"\n\t\ttrustedRootsConfig.Certificates = string(slb.apiCert)\n\n\t\tdocuments = append(documents, trustedRootsConfig)\n\t}\n\n\tctr, err := container.New(documents...)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"failed to create container for Siderolink config: %s\", err))\n\t}\n\n\treturn ctr\n}\n\n// SetKernelArgs sets the kernel arguments for the current builder. It is safe to call this method on a nil pointer.\nfunc (slb *SiderolinkBuilder) SetKernelArgs(extraKernelArgs *procfs.Cmdline, tunnel bool) error {\n\tswitch {\n\tcase slb == nil:\n\t\treturn nil\n\tcase extraKernelArgs.Get(\"siderolink.api\") != nil,\n\t\textraKernelArgs.Get(\"talos.events.sink\") != nil,\n\t\textraKernelArgs.Get(\"talos.logging.kernel\") != nil:\n\t\treturn errors.New(\"siderolink kernel arguments are already set, cannot run with --with-siderolink\")\n\tdefault:\n\t\tmarshaled, err := slb.ConfigDocument(tunnel).EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"failed to marshal trusted roots config: %s\", err))\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\n\t\tzencoder, err := zstd.NewWriter(&buf)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create zstd encoder: %w\", err)\n\t\t}\n\n\t\t_, err = zencoder.Write(marshaled)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write zstd data: %w\", err)\n\t\t}\n\n\t\tif err = zencoder.Close(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to close zstd encoder: %w\", err)\n\t\t}\n\n\t\textraKernelArgs.Append(constants.KernelParamConfigEarly, base64.StdEncoding.EncodeToString(buf.Bytes()))\n\n\t\treturn nil\n\t}\n}\n\nfunc getDynamicPort(ctx context.Context, network string) (int, error) {\n\tvar (\n\t\tcloseFn func() error\n\t\taddrFn  func() net.Addr\n\t)\n\n\tswitch network {\n\tcase \"tcp\", \"tcp4\", \"tcp6\":\n\t\tl, err := (&net.ListenConfig{}).Listen(ctx, network, \"127.0.0.1:0\")\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\taddrFn, closeFn = l.Addr, l.Close\n\tcase \"udp\", \"udp4\", \"udp6\":\n\t\tl, err := (&net.ListenConfig{}).ListenPacket(ctx, network, \"127.0.0.1:0\")\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\taddrFn, closeFn = l.LocalAddr, l.Close\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"unsupported network: %s\", network)\n\t}\n\n\t_, portStr, err := net.SplitHostPort(addrFn().String())\n\tif err != nil {\n\t\treturn 0, handleCloseErr(err, closeFn())\n\t}\n\n\tport, err := strconv.Atoi(portStr)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn port, handleCloseErr(nil, closeFn())\n}\n\nfunc handleCloseErr(err error, closeErr error) error {\n\tswitch {\n\tcase err != nil && closeErr != nil:\n\t\treturn fmt.Errorf(\"error: %w, close error: %w\", err, closeErr)\n\tcase err == nil && closeErr != nil:\n\t\treturn closeErr\n\tcase err != nil && closeErr == nil:\n\t\treturn err\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc checkPortsDontOverlap(ports ...int) error {\n\tslices.Sort(ports)\n\n\tif len(ports) != len(slices.Compact(ports)) {\n\t\treturn errors.New(\"generated ports overlap\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/siderolinkbuilder/helpers_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux && !darwin\n\npackage siderolinkbuilder\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n)\n\nfunc generateRandomNodeAddr(prefix netip.Prefix) (netip.Prefix, error) {\n\treturn netip.Prefix{}, nil\n}\n\nfunc networkPrefix(prefix string) (netip.Prefix, error) {\n\treturn netip.Prefix{}, errors.New(\"unsupported platform\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/siderolinkbuilder/helpers_supported.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage siderolinkbuilder\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/siderolink/pkg/wireguard\"\n)\n\nfunc generateRandomNodeAddr(prefix netip.Prefix) (netip.Prefix, error) {\n\treturn wireguard.GenerateRandomNodeAddr(prefix)\n}\n\nfunc networkPrefix(prefix string) (netip.Prefix, error) {\n\treturn wireguard.NetworkPrefix(prefix), nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/disk_image_preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/machinery/platforms\"\n)\n\n// DiskImage configures Talos to boot from a disk image from the Image Factory.\ntype DiskImage struct{}\n\n// Name implements the Preset interface.\nfunc (DiskImage) Name() string { return \"disk-image\" }\n\n// Description implements the Preset interface.\nfunc (DiskImage) Description() string {\n\treturn \"Configure Talos to boot from a disk image from the Image Factory.\"\n}\n\n// ModifyOptions implements the Preset interface.\nfunc (DiskImage) ModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tdiskImageURL, err := url.JoinPath(presetOps.ImageFactoryURL.String(), \"image\", presetOps.SchematicID, cOps.TalosVersion,\n\t\tplatforms.MetalPlatform().DiskImageDefaultPath(qOps.TargetArch))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build an Image Factory disk-image url: %w\", err)\n\t}\n\n\tqOps.NodeDiskImagePath = diskImageURL\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/iso_preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport (\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/machinery/platforms\"\n)\n\n// ISO configures Talos to boot from an iso from the Image Factory.\ntype ISO struct{}\n\n// Name implements the Preset interface.\nfunc (ISO) Name() string { return \"iso\" }\n\n// Description implements the Preset interface.\nfunc (ISO) Description() string {\n\treturn \"Configure Talos to boot from an ISO from the Image Factory.\"\n}\n\n// ModifyOptions implements the Preset interface.\nfunc (ISO) ModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tisoURL, err := getISOURL(presetOps, cOps, qOps)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tqOps.NodeISOPath = isoURL\n\n\treturn nil\n}\n\nfunc getISOURL(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) (string, error) {\n\tisoPath := platforms.MetalPlatform().ISOPath(qOps.TargetArch)\n\tif presetOps.secureBoot {\n\t\tisoPath = platforms.MetalPlatform().SecureBootISOPath(qOps.TargetArch)\n\t}\n\n\treturn url.JoinPath(presetOps.ImageFactoryURL.String(), \"image\", presetOps.SchematicID, cOps.TalosVersion, isoPath)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/iso_secureboot_preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\n// ISOSecureBoot configures Talos to boot from a disk image from the Image Factory.\ntype ISOSecureBoot struct{}\n\n// Name implements the Preset interface.\nfunc (ISOSecureBoot) Name() string { return \"iso-secureboot\" }\n\n// Description implements the Preset interface.\nfunc (ISOSecureBoot) Description() string {\n\treturn \"Configure Talos for Secureboot via ISO. Only available on Linux hosts.\"\n}\n\n// ModifyOptions implements the Preset interface.\nfunc (ISOSecureBoot) ModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tisoURL, err := getISOURL(presetOps, cOps, qOps)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tqOps.NodeISOPath = isoURL\n\tqOps.Tpm2Enabled = true\n\tqOps.DiskEncryptionKeyTypes = []string{\"tpm\"}\n\tqOps.EncryptEphemeralPartition = true\n\tqOps.EncryptStatePartition = true\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/maintenance_preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\n// Maintenance configures Talos to boot from a disk image from the Image Factory.\ntype Maintenance struct{}\n\n// Name implements the Preset interface.\nfunc (Maintenance) Name() string { return \"maintenance\" }\n\n// Description implements the Preset interface.\nfunc (Maintenance) Description() string {\n\treturn \"Skip applying machine configuration and leave the machines in maintenance mode. The machine configuration files are written to the working directory.\"\n}\n\n// ModifyOptions implements the Preset interface.\nfunc (Maintenance) ModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tcOps.SkipInjectingConfig = true\n\tcOps.ApplyConfigEnabled = false\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"runtime\"\n\n\t\"gopkg.in/typ.v4/slices\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n)\n\nconst secureBootSuffix = \"-secureboot\"\n\n// Preset modifies cluster create options to achieve certain behavior.\ntype Preset interface {\n\tName() string\n\tDescription() string\n\n\t// ModifyOptions modifies configs to achieve the desired behavior\n\tModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error\n}\n\n// Options are the options required for presets to function.\ntype Options struct {\n\tSchematicID     string\n\tImageFactoryURL *url.URL\n\n\t// secureBoot preset also affects other presets so this option needs to be shared.\n\tsecureBoot bool\n}\n\n// Presets is a list of all available presets.\nvar Presets = [...]Preset{\n\tISO{},\n\tISOSecureBoot{},\n\tPXE{},\n\tDiskImage{},\n\tMaintenance{},\n}\n\n// Apply validates and applies a set of multiple presets.\nfunc Apply(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu, presetNames []string) error {\n\tpresets, err := slices.MapErr(presetNames, func(name string) (Preset, error) {\n\t\tif name == (ISOSecureBoot{}).Name() {\n\t\t\tpresetOps.secureBoot = true\n\t\t}\n\n\t\tfor _, p := range Presets {\n\t\t\tif p.Name() == name {\n\t\t\t\treturn p, nil\n\t\t\t}\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error: unknown preset: %q\", name)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = Validate(presetNames, presetOps)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := applyDefaultSettings(presetOps, cOps, qOps); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, p := range presets {\n\t\terr = p.ModifyOptions(presetOps, cOps, qOps)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to apply %q preset: %w\", p.Name(), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Validate checks if the provided presets are valid and compatible.\n//\n//nolint:gocyclo\nfunc Validate(presetNames []string, presetOps Options) error {\n\tbootMethodPresets := []string{ISO{}.Name(), PXE{}.Name(), DiskImage{}.Name(), ISOSecureBoot{}.Name()}\n\n\t// check if at least one boot method preset is selected, but no more than one\n\tbootMethodPresetCount := 0\n\n\tfor _, name := range presetNames {\n\t\tfor _, bm := range bootMethodPresets {\n\t\t\tif name == bm {\n\t\t\t\tbootMethodPresetCount++\n\t\t\t}\n\t\t}\n\t}\n\n\tif bootMethodPresetCount == 0 {\n\t\treturn fmt.Errorf(\"error: at least one boot method preset must be specified (one of %v)\", bootMethodPresets)\n\t}\n\n\tif bootMethodPresetCount > 1 {\n\t\treturn fmt.Errorf(\"error: multiple boot method presets specified, please select only one (one of %v)\", bootMethodPresets)\n\t}\n\n\tif presetOps.secureBoot && runtime.GOOS == \"darwin\" {\n\t\t// skip the check if it's a unit test environment\n\t\tif flag.Lookup(\"test.v\") == nil {\n\t\t\treturn errors.New(\"error: 'secureboot' preset is currently not supported on darwin\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc applyDefaultSettings(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tinstallerName := \"metal-installer\"\n\tif presetOps.secureBoot {\n\t\tinstallerName += secureBootSuffix\n\t}\n\n\tinstallerURL, err := url.JoinPath(presetOps.ImageFactoryURL.Host, installerName, presetOps.SchematicID+\":\"+cOps.TalosVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build installer image URL: %w\", err)\n\t}\n\n\tqOps.NodeInstallImage = installerURL\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/preset_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/constants\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset\"\n)\n\nfunc TestValidatePresets(t *testing.T) {\n\timageFactoryURL, err := url.Parse(constants.ImageFactoryURL)\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname       string\n\t\tpresets    []string\n\t\tshouldFail bool\n\t}{\n\t\t{\n\t\t\tname:       \"no presets\",\n\t\t\tpresets:    []string{},\n\t\t\tshouldFail: true,\n\t\t},\n\t\t{\n\t\t\tname:       \"multiple boot method presets\",\n\t\t\tpresets:    []string{preset.ISO{}.Name(), preset.PXE{}.Name()},\n\t\t\tshouldFail: true,\n\t\t},\n\t\t{\n\t\t\tname:       \"valid single boot method preset - iso\",\n\t\t\tpresets:    []string{preset.ISO{}.Name()},\n\t\t\tshouldFail: false,\n\t\t},\n\t\t{\n\t\t\tname:       \"valid single boot method preset - pxe\",\n\t\t\tpresets:    []string{preset.PXE{}.Name()},\n\t\t\tshouldFail: false,\n\t\t},\n\t\t{\n\t\t\tname:       \"valid single boot method preset - disk-image\",\n\t\t\tpresets:    []string{preset.DiskImage{}.Name()},\n\t\t\tshouldFail: false,\n\t\t},\n\t\t{\n\t\t\tname:       \"valid boot method preset with maintenance\",\n\t\t\tpresets:    []string{preset.ISO{}.Name(), preset.Maintenance{}.Name()},\n\t\t\tshouldFail: false,\n\t\t},\n\t\t{\n\t\t\tname:       \"iso-secureboot\",\n\t\t\tpresets:    []string{preset.ISOSecureBoot{}.Name()},\n\t\t\tshouldFail: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := preset.Validate(tt.presets, preset.Options{\n\t\t\t\tSchematicID:     constants.ImageFactoryEmptySchematicID,\n\t\t\t\tImageFactoryURL: imageFactoryURL,\n\t\t\t})\n\n\t\t\tif tt.shouldFail {\n\t\t\t\trequire.Error(t, err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc applyPreset(t *testing.T, presets ...string) (clusterops.Common, clusterops.Qemu) {\n\timageFactoryURL, err := url.Parse(constants.ImageFactoryURL)\n\trequire.NoError(t, err)\n\n\tcOps := clusterops.GetCommon()\n\tqOps := clusterops.GetQemu()\n\tqOps.TargetArch = \"arm64\"\n\tcOps.TalosVersion = \"v9.9.9\"\n\n\terr = preset.Apply(preset.Options{\n\t\tSchematicID:     \"123schematic123\",\n\t\tImageFactoryURL: imageFactoryURL,\n\t}, &cOps, &qOps, presets)\n\trequire.NoError(t, err)\n\n\treturn cOps, qOps\n}\n\nfunc TestPXE(t *testing.T) {\n\t_, qOps := applyPreset(t, preset.PXE{}.Name())\n\n\trequire.Equal(t, \"factory.talos.dev/metal-installer/123schematic123:v9.9.9\", qOps.NodeInstallImage)\n\trequire.Equal(t, \"https://factory.talos.dev/pxe/123schematic123/v9.9.9/metal-arm64\", qOps.NodeIPXEBootScript)\n\trequire.False(t, qOps.Tpm2Enabled)\n\trequire.Empty(t, qOps.NodeISOPath)\n}\n\nfunc TestSecureboot(t *testing.T) {\n\t_, qOps := applyPreset(t, preset.ISOSecureBoot{}.Name())\n\n\trequire.Equal(t, \"https://factory.talos.dev/image/123schematic123/v9.9.9/metal-arm64-secureboot.iso\", qOps.NodeISOPath)\n\trequire.True(t, qOps.Tpm2Enabled)\n\trequire.Contains(t, qOps.DiskEncryptionKeyTypes, \"tpm\")\n\trequire.True(t, qOps.EncryptEphemeralPartition)\n\trequire.True(t, qOps.EncryptStatePartition)\n\n\trequire.Equal(t, \"factory.talos.dev/metal-installer-secureboot/123schematic123:v9.9.9\", qOps.NodeInstallImage)\n}\n\nfunc TestDiskImage(t *testing.T) {\n\t_, qOps := applyPreset(t, preset.DiskImage{}.Name())\n\n\trequire.Equal(t, \"https://factory.talos.dev/image/123schematic123/v9.9.9/metal-arm64.raw.zst\", qOps.NodeDiskImagePath)\n}\n\nfunc TestMaintenance(t *testing.T) {\n\tcOps, _ := applyPreset(t, preset.Maintenance{}.Name(), preset.ISO{}.Name())\n\n\trequire.True(t, cOps.SkipInjectingConfig)\n\trequire.False(t, cOps.ApplyConfigEnabled)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset/pxe_preset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage preset\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/machinery/platforms\"\n)\n\n// PXE configures Talos to boot from via pxe from the Image Factory.\ntype PXE struct{}\n\n// Name implements the Preset interface.\nfunc (PXE) Name() string { return \"pxe\" }\n\n// Description implements the Preset interface.\nfunc (PXE) Description() string {\n\treturn \"Configure Talos to boot via PXE from the Image Factory.\"\n}\n\n// ModifyOptions implements the Preset interface.\nfunc (PXE) ModifyOptions(presetOps Options, cOps *clusterops.Common, qOps *clusterops.Qemu) error {\n\tpxeURL, err := url.JoinPath(presetOps.ImageFactoryURL.String(), \"pxe\", presetOps.SchematicID, cOps.TalosVersion,\n\t\tplatforms.MetalPlatform().PXEScriptPath(qOps.TargetArch))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build an Image Factory pxe url: %w\", err)\n\t}\n\n\tqOps.NodeIPXEBootScript = pxeURL\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage clusterops\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/docker/cli/opts\"\n\n\tclustercmd \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/bytesize\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// ClusterConfigs is the configuration needed to create a talos cluster via the provisioner interface.\ntype ClusterConfigs struct {\n\tClusterRequest   provision.ClusterRequest\n\tProvisionOptions []provision.Option\n\tConfigBundle     *bundle.Bundle\n}\n\n// NodeResources represents CPU and Memory resources for a node.\ntype NodeResources struct {\n\tCPU    string\n\tMemory bytesize.ByteSize\n}\n\n// ParsedNodeResources represents parsed CPU and Memory resources for a node.\ntype ParsedNodeResources struct {\n\tNanoCPUs int64\n\tMemory   bytesize.ByteSize\n}\n\n// Common are the options that are not specific to a single provider.\ntype Common struct {\n\t// rootOps are the options from the root cluster command\n\tRootOps                   *clustercmd.CmdOps\n\tTalosconfigDestination    string\n\tRegistryMirrors           []string\n\tRegistryInsecure          []string\n\tKubernetesVersion         string\n\tApplyConfigEnabled        bool\n\tConfigDebug               bool\n\tNetworkCIDR               string\n\tNetworkMTU                int\n\tNetworkIPv4               bool\n\tDNSDomain                 string\n\tWorkers                   int\n\tControlplanes             int\n\tControlplaneResources     NodeResources\n\tWorkerResources           NodeResources\n\tClusterWait               bool\n\tClusterWaitTimeout        time.Duration\n\tForceInitNodeAsEndpoint   bool\n\tForceEndpoint             string\n\tControlPlanePort          int\n\tWithInitNode              bool\n\tCustomCNIUrl              string\n\tSkipKubeconfig            bool\n\tSkipInjectingConfig       bool\n\tTalosVersion              string\n\tEnableKubeSpan            bool\n\tEnableClusterDiscovery    bool\n\tConfigPatch               []string\n\tConfigPatchControlPlane   []string\n\tConfigPatchWorker         []string\n\tKubePrismPort             int\n\tSkipK8sNodeReadinessCheck bool\n\tWithJSONLogs              bool\n\tWireguardCIDR             string\n\tWithUUIDHostnames         bool\n\tNetworkIPv6               bool\n\tOmniAPIEndpoint           string\n}\n\n// Docker are options specific to docker provisioner.\ntype Docker struct {\n\tHostIP      string\n\tDisableIPv6 bool\n\tMountOpts   opts.MountOpt\n\tPorts       string\n\tTalosImage  string\n}\n\n// Qemu are options specific to qemu provisioner.\ntype Qemu struct {\n\tNodeInstallImage          string\n\tNodeVmlinuzPath           string\n\tNodeInitramfsPath         string\n\tNodeISOPath               string\n\tNodeUSBPath               string\n\tNodeUKIPath               string\n\tNodeDiskImagePath         string\n\tNodeIPXEBootScript        string\n\tBootloaderEnabled         bool\n\tSkipInjectingExtraCmdline bool\n\tUefiEnabled               bool\n\tTpm1_2Enabled             bool\n\tTpm2Enabled               bool\n\tExtraUEFISearchPaths      []string\n\tNetworkNoMasqueradeCIDRs  []string\n\tNameservers               []string\n\tDisks                     flags.Disks\n\tDiskBlockSize             uint\n\tPreallocateDisks          bool\n\tClusterUserVolumes        []string\n\tTargetArch                string\n\tCniBinPath                []string\n\tCniConfDir                string\n\tCniCacheDir               string\n\tCniBundleURL              string\n\tEncryptStatePartition     bool\n\tEncryptEphemeralPartition bool\n\tEncryptUserVolumes        bool\n\tUseVIP                    bool\n\tBadRTC                    bool\n\tExtraBootKernelArgs       string\n\tDHCPSkipHostname          bool\n\tNetworkChaos              bool\n\tJjitter                   time.Duration\n\tLatency                   time.Duration\n\tPacketLoss                float64\n\tPacketReorder             float64\n\tPacketCorrupt             float64\n\tBandwidth                 int\n\tDiskEncryptionKeyTypes    []string\n\tWithFirewall              string\n\tWithSiderolinkAgent       flags.Agent\n\tDebugShellEnabled         bool\n\tWithIOMMU                 bool\n\tConfigInjectionMethod     string\n\tAirgapped                 bool\n\tImageCachePath            string\n\tImageCacheTLSCertFile     string\n\tImageCacheTLSKeyFile      string\n\tImageCachePort            uint16\n}\n\n// GetCommon returns the default common options.\nfunc GetCommon() Common {\n\tmemory2GB := bytesize.WithDefaultUnit(\"MiB\")\n\tcli.Should(memory2GB.Set(\"2.0GiB\"))\n\tdefaultResources := NodeResources{\n\t\tCPU:    \"2.0\",\n\t\tMemory: *memory2GB,\n\t}\n\n\treturn Common{\n\t\tControlplanes:         1,\n\t\tControlplaneResources: defaultResources,\n\t\tWorkers:               1,\n\t\tWorkerResources:       defaultResources,\n\n\t\tNetworkCIDR:            \"10.5.0.0/24\",\n\t\tKubernetesVersion:      constants.DefaultKubernetesVersion,\n\t\tNetworkMTU:             1500,\n\t\tClusterWaitTimeout:     20 * time.Minute,\n\t\tClusterWait:            true,\n\t\tDNSDomain:              \"cluster.local\",\n\t\tControlPlanePort:       constants.DefaultControlPlanePort,\n\t\tRootOps:                &clustercmd.PersistentFlags, // TODO: move this elsewhere\n\t\tNetworkIPv4:            true,\n\t\tKubePrismPort:          constants.DefaultKubePrismPort,\n\t\tEnableClusterDiscovery: true,\n\t\tTalosVersion:           helpers.GetTag(),\n\t}\n}\n\n// GetQemu returns default QEMU options.\nfunc GetQemu() Qemu {\n\tdisks := flags.Disks{}\n\tcli.Should(disks.Set(\"virtio:10GiB,virtio:6GiB\"))\n\n\treturn Qemu{\n\t\tPreallocateDisks:  false,\n\t\tBootloaderEnabled: true,\n\t\tUefiEnabled:       true,\n\t\tNameservers:       defaultNameservers,\n\t\tDiskBlockSize:     512,\n\t\tTargetArch:        runtime.GOARCH,\n\t\tCniBinPath:        []string{filepath.Join(clustercmd.DefaultCNIDir, \"bin\")},\n\t\tCniConfDir:        filepath.Join(clustercmd.DefaultCNIDir, \"conf.d\"),\n\t\tCniCacheDir:       filepath.Join(clustercmd.DefaultCNIDir, \"cache\"),\n\t\tCniBundleURL: fmt.Sprintf(\"https://github.com/%s/talos/releases/download/%s/talosctl-cni-bundle-%s.tar.gz\",\n\t\t\timages.Username, version.Trim(version.Tag), constants.ArchVariable),\n\t\tDisks:          disks,\n\t\tImageCachePort: 5000,\n\t}\n}\n\n// GetDocker returns default Docker options.\nfunc GetDocker() Docker {\n\treturn Docker{\n\t\tHostIP:     \"0.0.0.0\",\n\t\tTalosImage: helpers.DefaultImage(images.DefaultTalosImageRepository),\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/options_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage clusterops\n\nvar defaultNameservers = []string{}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/clusterops/options_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\npackage clusterops\n\nvar defaultNameservers = []string{\"8.8.8.8\", \"1.1.1.1\", \"2001:4860:4860::8888\", \"2606:4700:4700::1111\"}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/cmd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package create provides way to create talos clusters\npackage create\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/pkg/bytesize\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar (\n\tworkersFlagName           = \"workers\"\n\tcontrolplanesFlagName     = \"controlplanes\"\n\tkubernetesVersionFlagName = \"kubernetes-version\"\n\tregistryMirrorFlagName    = \"registry-mirror\"\n\tnetworkMTUFlagName        = \"mtu\"\n\tnetworkCIDRFlagName       = \"cidr\"\n\ttalosVersionFlagName      = \"talos-version\"\n\n\t// Flags that have been renamed in the user-facing commands.\n\tcontrolPlaneCpusFlagName        = \"cpus-controlplanes\"\n\tcontrolPlaneMemoryFlagName      = \"memory-controlplanes\"\n\tworkersCpusFlagName             = \"cpus-workers\"\n\tworkersMemoryFlagName           = \"memory-workers\"\n\tconfigPatchFlagName             = \"config-patch\"\n\tconfigPatchControlPlaneFlagName = \"config-patch-controlplanes\"\n\tconfigPatchWorkerFlagName       = \"config-patch-workers\"\n\ttalosconfigDestinationFlagName  = \"talosconfig-destination\"\n\n\t// Qemu flags.\n\tdisksFlagName           = \"disks\"\n\tomniAPIEndpointFlagName = \"omni-api-endpoint\"\n)\n\nfunc getCommonUserFacingFlags(pointer *clusterops.Common) *pflag.FlagSet {\n\tcommon := pflag.NewFlagSet(\"common\", pflag.PanicOnError)\n\n\taddWorkersFlag(common, &pointer.Workers)\n\taddKubernetesVersionFlag(common, &pointer.KubernetesVersion)\n\taddTalosconfigDestinationFlag(common, &pointer.TalosconfigDestination, talosconfigDestinationFlagName)\n\taddConfigPatchFlag(common, &pointer.ConfigPatch, configPatchFlagName)\n\taddConfigPatchControlPlaneFlag(common, &pointer.ConfigPatchControlPlane, configPatchControlPlaneFlagName)\n\taddConfigPatchWorkerFlag(common, &pointer.ConfigPatchWorker, configPatchWorkerFlagName)\n\n\taddControlplaneCpusFlag(common, &pointer.ControlplaneResources.CPU, controlPlaneCpusFlagName)\n\taddWorkersCpusFlag(common, &pointer.WorkerResources.CPU, workersCpusFlagName)\n\taddControlPlaneMemoryFlag(common, &pointer.ControlplaneResources.Memory, controlPlaneMemoryFlagName)\n\taddWorkersMemoryFlag(common, &pointer.WorkerResources.Memory, workersMemoryFlagName)\n\n\t// The following flags are used in tests and development\n\taddNetworkMTUFlag(common, &pointer.NetworkMTU)\n\tcli.Should(common.MarkHidden(networkMTUFlagName))\n\taddRegistryMirrorFlag(common, &pointer.RegistryMirrors)\n\tcli.Should(common.MarkHidden(registryMirrorFlagName))\n\n\treturn common\n}\n\n// Common flags\n\nfunc addTalosconfigDestinationFlag(flagset *pflag.FlagSet, bind *string, flagName string) {\n\tflagset.StringVar(bind, flagName, \"\",\n\t\tfmt.Sprintf(\"The location to save the generated Talos configuration file to. Defaults to '%s' env variable if set, otherwise '%s' and '%s' in order.\",\n\t\t\tconstants.TalosConfigEnvVar,\n\t\t\tfilepath.Join(\"$HOME\", constants.TalosDir, constants.TalosconfigFilename),\n\t\t\tfilepath.Join(constants.ServiceAccountMountPath, constants.TalosconfigFilename),\n\t\t),\n\t)\n}\n\nfunc addControlplaneCpusFlag(flagset *pflag.FlagSet, bind *string, flagName string) {\n\tflagset.StringVar(bind, flagName, *bind, \"the share of CPUs as fraction for each control plane/VM\")\n}\n\nfunc addWorkersCpusFlag(flagset *pflag.FlagSet, bind *string, flagName string) {\n\tflagset.StringVar(bind, flagName, *bind, \"the share of CPUs as fraction for each worker/VM\")\n}\n\nfunc addControlPlaneMemoryFlag(flagset *pflag.FlagSet, bind *bytesize.ByteSize, flagName string) {\n\tflagset.Var(bind, flagName, \"the limit on memory usage for each control plane/VM\")\n}\n\nfunc addWorkersMemoryFlag(flagset *pflag.FlagSet, bind *bytesize.ByteSize, flagName string) {\n\tflagset.Var(bind, flagName, \"the limit on memory usage for each worker/VM\")\n}\n\nfunc addConfigPatchFlag(flagset *pflag.FlagSet, bind *[]string, flagName string) {\n\tflagset.StringArrayVar(bind, flagName, nil, \"patch generated machineconfigs (applied to all node types), use @file to read a patch from file\")\n}\n\nfunc addConfigPatchControlPlaneFlag(flagset *pflag.FlagSet, bind *[]string, flagName string) {\n\tflagset.StringArrayVar(bind, flagName, nil, \"patch generated machineconfigs (applied to 'controlplane' type)\")\n}\n\nfunc addConfigPatchWorkerFlag(flagset *pflag.FlagSet, bind *[]string, flagName string) {\n\tflagset.StringArrayVar(bind, flagName, nil, \"patch generated machineconfigs (applied to 'worker' type)\")\n}\n\nfunc addWorkersFlag(flagset *pflag.FlagSet, bind *int) {\n\tflagset.IntVar(bind, workersFlagName, *bind, \"the number of workers to create\")\n}\n\nfunc addControlplanesFlag(flagset *pflag.FlagSet, bind *int) {\n\tflagset.IntVar(bind, controlplanesFlagName, *bind, \"the number of controlplanes to create\")\n}\n\nfunc addKubernetesVersionFlag(flagset *pflag.FlagSet, bind *string) {\n\tflagset.StringVar(bind, kubernetesVersionFlagName, *bind, \"desired kubernetes version to run\")\n}\n\nfunc addRegistryMirrorFlag(flagset *pflag.FlagSet, bind *[]string) {\n\tflagset.StringSliceVar(bind, registryMirrorFlagName, []string{}, \"list of registry mirrors to use in format: <registry host>=<mirror URL>\")\n}\n\nfunc addNetworkMTUFlag(flagset *pflag.FlagSet, bind *int) {\n\tflagset.IntVar(bind, networkMTUFlagName, *bind, \"MTU of the cluster network\")\n}\n\nfunc addTalosVersionFlag(flagset *pflag.FlagSet, bind *string, description string) {\n\tflagset.StringVar(bind, talosVersionFlagName, *bind, description)\n}\n\n// qemu flags\n\nfunc addDisksFlag(flagset *pflag.FlagSet, bind *flags.Disks) {\n\tflagset.Var(bind, disksFlagName,\n\t\t`list of disks to create in format \"<driver1>:<size1>\" (disks after the first one are added only to worker machines)`)\n}\n\nfunc addOmniJoinTokenFlag(cmd *cobra.Command, bindAPIEndpoint *string, cfgPatchAllFlagName, cfgPatchWorkersFlagName, cfgPatchCPsFlagName string) {\n\tcmd.Flags().StringVar(bindAPIEndpoint, omniAPIEndpointFlagName, *bindAPIEndpoint,\n\t\t\"the Omni API endpoint (must include a scheme, a hostname and a join token, e.g. 'https://siderolink.omni.example?jointoken=foobar')\")\n\n\tcmd.MarkFlagsMutuallyExclusive(omniAPIEndpointFlagName, cfgPatchAllFlagName)\n\tcmd.MarkFlagsMutuallyExclusive(omniAPIEndpointFlagName, cfgPatchWorkersFlagName)\n\tcmd.MarkFlagsMutuallyExclusive(omniAPIEndpointFlagName, cfgPatchCPsFlagName)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/cmd_dev.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tclustercmd \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\ntype legacyOps struct {\n\tclusterDiskSize   int\n\textraDisks        int\n\textraDiskSize     int\n\textraDisksDrivers []string\n\textraDisksTags    []string\n\textraDisksSerials []string\n}\n\nvar (\n\tcreateCmd    = getCreateCmd(\"create\", true)\n\tcreateDevCmd = getCreateCmd(\"dev\", false)\n)\n\n//nolint:gocyclo\nfunc getCreateCmd(cmdName string, hidden bool) *cobra.Command {\n\tconst (\n\t\tnetworkIPv4Flag               = \"ipv4\"\n\t\tnetworkIPv6Flag               = \"ipv6\"\n\t\tnetworkNoMasqueradeCIDRsFlag  = \"no-masquerade-cidrs\"\n\t\tnameserversFlag               = \"nameservers\"\n\t\tpreallocateDisksFlag          = \"disk-preallocate\"\n\t\tclusterUserVolumesFlag        = \"user-volumes\"\n\t\tclusterDiskSizeFlag           = \"disk\"\n\t\tdiskBlockSizeFlag             = \"disk-block-size\"\n\t\tuseVIPFlag                    = \"use-vip\"\n\t\tbootloaderEnabledFlag         = \"with-bootloader\"\n\t\tskipInjectingExtraCmdlineFlag = \"skip-injecting-extra-cmdline\"\n\t\tcontrolPlanePortFlag          = \"control-plane-port\"\n\t\tfirewallFlag                  = \"with-firewall\"\n\t\ttpmEnabledFlag                = \"with-tpm1_2\"\n\t\ttpm2EnabledFlag               = \"with-tpm2\"\n\t\twithDebugShellFlag            = \"with-debug-shell\"\n\t\twithIOMMUFlag                 = \"with-iommu\"\n\t\ttalosconfigFlag               = \"talosconfig\"\n\t\tapplyConfigEnabledFlag        = \"with-apply-config\"\n\t\twireguardCIDRFlag             = \"wireguard-cidr\"\n\t\tcontrolPlaneCpusFlag          = \"cpus\"\n\t\tworkersCpusFlag               = \"cpus-workers\"\n\t\tcontrolPlaneMemoryFlag        = \"memory\"\n\t\tworkersMemoryFlag             = \"memory-workers\"\n\t\tclusterWaitFlag               = \"wait\"\n\t\tclusterWaitTimeoutFlag        = \"wait-timeout\"\n\t\tforceInitNodeAsEndpointFlag   = \"init-node-as-endpoint\"\n\t\twithInitNodeFlag              = \"with-init-node\"\n\t\tskipKubeconfigFlag            = \"skip-kubeconfig\"\n\t\tskipInjectingConfigFlag       = \"skip-injecting-config\"\n\t\tconfigPatchFlag               = \"config-patch\"\n\t\tconfigPatchControlPlaneFlag   = \"config-patch-control-plane\"\n\t\tconfigPatchWorkerFlag         = \"config-patch-worker\"\n\t\tskipK8sNodeReadinessCheckFlag = \"skip-k8s-node-readiness-check\"\n\t\twithJSONLogsFlag              = \"with-json-logs\"\n\t\tnodeVmlinuzPathFlag           = \"vmlinuz-path\"\n\t\tnodeISOPathFlag               = \"iso-path\"\n\t\tnodeUSBPathFlag               = \"usb-path\"\n\t\tnodeUKIPathFlag               = \"uki-path\"\n\t\tnodeInitramfsPathFlag         = \"initrd-path\"\n\t\tnodeDiskImagePathFlag         = \"disk-image-path\"\n\t\tnodeIPXEBootScriptFlag        = \"ipxe-boot-script\"\n\t\tuefiEnabledFlag               = \"with-uefi\"\n\t\textraUEFISearchPathsFlag      = \"extra-uefi-search-paths\"\n\t\textraDisksFlag                = \"extra-disks\"\n\t\textraDisksDriversFlag         = \"extra-disks-drivers\"\n\t\textraDisksTagsFlag            = \"extra-disks-tags\"\n\t\textraDisksSerialsFlag         = \"extra-disks-serials\"\n\t\textraDiskSizeFlag             = \"extra-disks-size\"\n\t\ttargetArchFlag                = \"arch\"\n\t\tcniBinPathFlag                = \"cni-bin-path\"\n\t\tcniConfDirFlag                = \"cni-conf-dir\"\n\t\tcniCacheDirFlag               = \"cni-cache-dir\"\n\t\tcniBundleURLFlag              = \"cni-bundle-url\"\n\t\tbadRTCFlag                    = \"bad-rtc\"\n\t\textraBootKernelArgsFlag       = \"extra-boot-kernel-args\"\n\t\tdhcpSkipHostnameFlag          = \"disable-dhcp-hostname\"\n\t\tnetworkChaosFlag              = \"with-network-chaos\"\n\t\tjitterFlag                    = \"with-network-jitter\"\n\t\tlatencyFlag                   = \"with-network-latency\"\n\t\tpacketLossFlag                = \"with-network-packet-loss\"\n\t\tpacketReorderFlag             = \"with-network-packet-reorder\"\n\t\tpacketCorruptFlag             = \"with-network-packet-corrupt\"\n\t\tbandwidthFlag                 = \"with-network-bandwidth\"\n\t\twithUUIDHostnamesFlag         = \"with-uuid-hostnames\"\n\t\twithSiderolinkAgentFlag       = \"with-siderolink\"\n\t\tconfigInjectionMethodFlag     = \"config-injection-method\"\n\t\tairgappedFlag                 = \"airgapped\"\n\t\timageCachePathFlag            = \"image-cache-path\"\n\t\timageCacheTLSCertFileFlag     = \"image-cache-tls-cert-file\"\n\t\timageCacheTLSKeyFileFlag      = \"image-cache-tls-key-file\"\n\t\timageCachePortFlag            = \"image-cache-port\"\n\n\t\t// The following flags are the gen options - the options that are only used in machine configuration (i.e., not during the qemu/docker provisioning).\n\t\t// They are not applicable when no machine configuration is generated, hence mutually exclusive with the --input-dir flag.\n\n\t\tnodeInstallImageFlag          = \"install-image\"\n\t\tconfigDebugFlag               = \"with-debug\"\n\t\tdnsDomainFlag                 = \"dns-domain\"\n\t\twithClusterDiscoveryFlag      = \"with-cluster-discovery\"\n\t\tregistryInsecureFlag          = \"registry-insecure-skip-verify\"\n\t\tcustomCNIUrlFlag              = \"custom-cni-url\"\n\t\tencryptStatePartitionFlag     = \"encrypt-state\"\n\t\tencryptEphemeralPartitionFlag = \"encrypt-ephemeral\"\n\t\tencryptUserVolumeFlag         = \"encrypt-user-volumes\"\n\t\tenableKubeSpanFlag            = \"with-kubespan\"\n\t\tforceEndpointFlag             = \"endpoint\"\n\t\tkubePrismFlag                 = \"kubeprism-port\"\n\t\tdiskEncryptionKeyTypesFlag    = \"disk-encryption-key-types\"\n\t)\n\n\tunImplementedFlagsDarwin := []string{\n\t\tnetworkNoMasqueradeCIDRsFlag,\n\t\tcniBinPathFlag,\n\t\tcniConfDirFlag,\n\t\tcniCacheDirFlag,\n\t\tcniBundleURLFlag,\n\t\tbadRTCFlag,\n\t\tnetworkChaosFlag,\n\t\tjitterFlag,\n\t\tlatencyFlag,\n\t\tpacketLossFlag,\n\t\tpacketReorderFlag,\n\t\tpacketCorruptFlag,\n\t\tbandwidthFlag,\n\t\tairgappedFlag,\n\n\t\t// The following might work but need testing first.\n\t\tconfigInjectionMethodFlag,\n\t}\n\n\tqOps := clusterops.GetQemu()\n\tcOps := clusterops.GetCommon()\n\tlegacyOps := legacyOps{}\n\n\tgetCommonFlags := func() *pflag.FlagSet {\n\t\tcommon := pflag.NewFlagSet(\"common\", pflag.PanicOnError)\n\n\t\taddControlplaneCpusFlag(common, &cOps.ControlplaneResources.CPU, controlPlaneCpusFlag)\n\t\taddWorkersCpusFlag(common, &cOps.WorkerResources.CPU, workersCpusFlag)\n\t\taddControlPlaneMemoryFlag(common, &cOps.ControlplaneResources.Memory, controlPlaneMemoryFlag)\n\t\taddWorkersMemoryFlag(common, &cOps.WorkerResources.Memory, workersMemoryFlag)\n\n\t\taddWorkersFlag(common, &cOps.Workers)\n\t\taddControlplanesFlag(common, &cOps.Controlplanes)\n\t\taddKubernetesVersionFlag(common, &cOps.KubernetesVersion)\n\t\taddTalosconfigDestinationFlag(common, &cOps.TalosconfigDestination, talosconfigFlag)\n\t\taddConfigPatchFlag(common, &cOps.ConfigPatch, configPatchFlag)\n\t\taddConfigPatchControlPlaneFlag(common, &cOps.ConfigPatchControlPlane, configPatchControlPlaneFlag)\n\t\taddConfigPatchWorkerFlag(common, &cOps.ConfigPatchWorker, configPatchWorkerFlag)\n\t\taddRegistryMirrorFlag(common, &cOps.RegistryMirrors)\n\t\taddNetworkMTUFlag(common, &cOps.NetworkMTU)\n\t\taddTalosVersionFlag(common, &cOps.TalosVersion, \"the desired Talos version to generate config for\")\n\n\t\tcommon.StringVar(&cOps.NetworkCIDR, networkCIDRFlagName, cOps.NetworkCIDR, \"CIDR of the cluster network (IPv4, ULA network for IPv6 is derived in automated way)\")\n\t\tcommon.StringVar(&cOps.WireguardCIDR, wireguardCIDRFlag, cOps.WireguardCIDR, \"CIDR of the wireguard network\")\n\t\tcommon.BoolVar(&cOps.ApplyConfigEnabled, applyConfigEnabledFlag, cOps.ApplyConfigEnabled, \"enable apply config when the VM is starting in maintenance mode\")\n\t\tcommon.StringSliceVar(&cOps.RegistryInsecure, registryInsecureFlag, cOps.RegistryInsecure, \"list of registry hostnames to skip TLS verification for\")\n\t\tcommon.IntVar(&cOps.ControlPlanePort, controlPlanePortFlag, cOps.ControlPlanePort, \"control plane port (load balancer and local API port)\")\n\t\tcommon.BoolVar(&cOps.ConfigDebug, configDebugFlag, cOps.ConfigDebug, \"enable debug in Talos config to send service logs to the console\")\n\t\tcommon.BoolVar(&cOps.NetworkIPv4, networkIPv4Flag, cOps.NetworkIPv4, \"enable IPv4 network in the cluster\")\n\t\tcommon.BoolVar(&cOps.ClusterWait, clusterWaitFlag, cOps.ClusterWait, \"wait for the cluster to be ready before returning\")\n\t\tcommon.DurationVar(&cOps.ClusterWaitTimeout, clusterWaitTimeoutFlag, cOps.ClusterWaitTimeout, \"timeout to wait for the cluster to be ready\")\n\t\tcommon.BoolVar(&cOps.ForceInitNodeAsEndpoint, forceInitNodeAsEndpointFlag, cOps.ForceInitNodeAsEndpoint, \"use init node as endpoint instead of any load balancer endpoint\")\n\t\tcommon.StringVar(&cOps.ForceEndpoint, forceEndpointFlag, cOps.ForceEndpoint, \"use endpoint instead of provider defaults\")\n\t\tcommon.BoolVar(&cOps.WithInitNode, withInitNodeFlag, cOps.WithInitNode, \"create the cluster with an init node\")\n\t\tcommon.StringVar(&cOps.CustomCNIUrl, customCNIUrlFlag, cOps.CustomCNIUrl, \"install custom CNI from the URL (Talos cluster)\")\n\t\tcommon.StringVar(&cOps.DNSDomain, dnsDomainFlag, cOps.DNSDomain, \"the dns domain to use for cluster\")\n\t\tcommon.BoolVar(&cOps.SkipKubeconfig, skipKubeconfigFlag, cOps.SkipKubeconfig, \"skip merging kubeconfig from the created cluster\")\n\t\tcommon.BoolVar(&cOps.SkipInjectingConfig, skipInjectingConfigFlag, cOps.SkipInjectingConfig,\n\t\t\t\"skip injecting config from embedded metadata server, write config files to current directory\")\n\t\tcommon.BoolVar(&cOps.EnableClusterDiscovery, withClusterDiscoveryFlag, cOps.EnableClusterDiscovery, \"enable cluster discovery\")\n\t\tcommon.BoolVar(&cOps.EnableKubeSpan, enableKubeSpanFlag, cOps.EnableKubeSpan, \"enable KubeSpan system\")\n\t\tcommon.IntVar(&cOps.KubePrismPort, kubePrismFlag, cOps.KubePrismPort, \"KubePrism port (set to 0 to disable)\")\n\t\tcommon.BoolVar(&cOps.SkipK8sNodeReadinessCheck, skipK8sNodeReadinessCheckFlag, cOps.SkipK8sNodeReadinessCheck, \"skip k8s node readiness checks\")\n\t\tcommon.BoolVar(&cOps.WithJSONLogs, withJSONLogsFlag, cOps.WithJSONLogs, \"enable JSON logs receiver and configure Talos to send logs there\")\n\t\tcommon.BoolVar(&cOps.WithUUIDHostnames, withUUIDHostnamesFlag, cOps.WithUUIDHostnames, \"use machine UUIDs as default hostnames\")\n\t\tcommon.BoolVar(&cOps.NetworkIPv6, networkIPv6Flag, cOps.NetworkIPv6, \"enable IPv6 network in the cluster\")\n\n\t\treturn common\n\t}\n\n\tgetQemuFlags := func() *pflag.FlagSet {\n\t\tqemu := pflag.NewFlagSet(\"qemu\", pflag.PanicOnError)\n\n\t\tqemu.BoolVar(&qOps.PreallocateDisks, preallocateDisksFlag, true, \"whether disk space should be preallocated\")\n\t\tqemu.StringSliceVar(&qOps.ClusterUserVolumes, clusterUserVolumesFlag, qOps.ClusterUserVolumes, \"list of user volumes to create for each VM in format: <name1>:<size1>:<name2>:<size2>\")\n\t\tqemu.StringVar(&qOps.NodeInstallImage, nodeInstallImageFlag, helpers.DefaultImage(images.DefaultInstallerImageRepository), \"the installer image to use\")\n\t\tqemu.StringVar(&qOps.NodeVmlinuzPath, nodeVmlinuzPathFlag, helpers.ArtifactPath(constants.KernelAssetWithArch), \"the compressed kernel image to use\")\n\t\tqemu.StringVar(&qOps.NodeISOPath, nodeISOPathFlag, qOps.NodeISOPath, \"the ISO path to use for the initial boot\")\n\t\tqemu.StringVar(&qOps.NodeUSBPath, nodeUSBPathFlag, qOps.NodeUSBPath, \"the USB stick image path to use for the initial boot\")\n\t\tqemu.StringVar(&qOps.NodeUKIPath, nodeUKIPathFlag, qOps.NodeUKIPath, \"the UKI image path to use for the initial boot\")\n\t\tqemu.StringVar(&qOps.NodeInitramfsPath, nodeInitramfsPathFlag, helpers.ArtifactPath(constants.InitramfsAssetWithArch), \"initramfs image to use\")\n\t\tqemu.StringVar(&qOps.NodeDiskImagePath, nodeDiskImagePathFlag, qOps.NodeDiskImagePath, \"disk image to use\")\n\t\tqemu.StringVar(&qOps.NodeIPXEBootScript, nodeIPXEBootScriptFlag, qOps.NodeIPXEBootScript, \"iPXE boot script (URL) to use\")\n\t\tqemu.BoolVar(&qOps.BootloaderEnabled, bootloaderEnabledFlag, qOps.BootloaderEnabled, \"enable bootloader to load kernel and initramfs from disk image after install\")\n\t\tqemu.BoolVar(&qOps.SkipInjectingExtraCmdline, skipInjectingExtraCmdlineFlag, qOps.SkipInjectingExtraCmdline,\n\t\t\t\"skip injecting extra kernel cmdline parameters via EFI vars through bootloader\")\n\t\tqemu.BoolVar(&qOps.UefiEnabled, uefiEnabledFlag, qOps.UefiEnabled, \"enable UEFI on x86_64 architecture\")\n\t\tqemu.BoolVar(&qOps.Tpm1_2Enabled, tpmEnabledFlag, qOps.Tpm1_2Enabled, \"enable TPM 1.2 emulation support using swtpm\")\n\t\tqemu.BoolVar(&qOps.Tpm2Enabled, tpm2EnabledFlag, qOps.Tpm2Enabled, \"enable TPM 2.0 emulation support using swtpm\")\n\t\tqemu.BoolVar(&qOps.DebugShellEnabled, withDebugShellFlag, qOps.DebugShellEnabled, \"drop talos into a maintenance shell on boot, this is for advanced debugging for developers only\")\n\t\tqemu.BoolVar(&qOps.WithIOMMU, withIOMMUFlag, qOps.WithIOMMU, \"enable IOMMU support, this also add a new PCI root port and an interface attached to it\")\n\t\tqemu.MarkHidden(\"with-debug-shell\") //nolint:errcheck\n\t\tqemu.StringSliceVar(&qOps.ExtraUEFISearchPaths, extraUEFISearchPathsFlag, qOps.ExtraUEFISearchPaths, \"additional search paths for UEFI firmware (only applies when UEFI is enabled)\")\n\t\tqemu.StringSliceVar(&qOps.NetworkNoMasqueradeCIDRs, networkNoMasqueradeCIDRsFlag, qOps.NetworkNoMasqueradeCIDRs, \"list of CIDRs to exclude from NAT\")\n\t\tqemu.StringSliceVar(&qOps.Nameservers, nameserversFlag, qOps.Nameservers, \"list of nameservers to use\")\n\t\tqemu.UintVar(&qOps.DiskBlockSize, diskBlockSizeFlag, qOps.DiskBlockSize, \"disk block size\")\n\t\tqemu.StringVar(&qOps.TargetArch, targetArchFlag, qOps.TargetArch, \"cluster architecture\")\n\t\tqemu.StringSliceVar(&qOps.CniBinPath, cniBinPathFlag, qOps.CniBinPath, \"search path for CNI binaries\")\n\t\tqemu.StringVar(&qOps.CniConfDir, cniConfDirFlag, qOps.CniConfDir, \"CNI config directory path\")\n\t\tqemu.StringVar(&qOps.CniCacheDir, cniCacheDirFlag, qOps.CniCacheDir, \"CNI cache directory path\")\n\t\tqemu.StringVar(&qOps.CniBundleURL, cniBundleURLFlag, qOps.CniBundleURL, \"URL to download CNI bundle from\")\n\t\tqemu.BoolVar(&qOps.EncryptStatePartition, encryptStatePartitionFlag, qOps.EncryptStatePartition, \"enable state partition encryption\")\n\t\tqemu.BoolVar(&qOps.EncryptEphemeralPartition, encryptEphemeralPartitionFlag, qOps.EncryptEphemeralPartition, \"enable ephemeral partition encryption\")\n\t\tqemu.BoolVar(&qOps.EncryptUserVolumes, encryptUserVolumeFlag, qOps.EncryptUserVolumes, \"enable ephemeral partition encryption\")\n\t\tqemu.StringArrayVar(&qOps.DiskEncryptionKeyTypes, diskEncryptionKeyTypesFlag, []string{\"uuid\"}, \"encryption key types to use for disk encryption (uuid, kms)\")\n\t\tqemu.BoolVar(&qOps.UseVIP, useVIPFlag, qOps.UseVIP, \"use a virtual IP for the controlplane endpoint instead of the loadbalancer\")\n\t\tqemu.BoolVar(&qOps.BadRTC, badRTCFlag, qOps.BadRTC, \"launch VM with bad RTC state\")\n\t\tqemu.StringVar(&qOps.ExtraBootKernelArgs, extraBootKernelArgsFlag, qOps.ExtraBootKernelArgs, \"add extra kernel args to the initial boot from vmlinuz and initramfs\")\n\t\tqemu.BoolVar(&qOps.DHCPSkipHostname, dhcpSkipHostnameFlag, qOps.DHCPSkipHostname, \"skip announcing hostname via DHCP\")\n\t\tqemu.BoolVar(&qOps.NetworkChaos, networkChaosFlag, qOps.NetworkChaos, \"enable to use network chaos parameters\")\n\t\tqemu.DurationVar(&qOps.Jjitter, jitterFlag, qOps.Jjitter, \"specify jitter on the bridge interface\")\n\t\tqemu.DurationVar(&qOps.Latency, latencyFlag, qOps.Latency, \"specify latency on the bridge interface\")\n\t\tqemu.Float64Var(&qOps.PacketLoss, packetLossFlag, qOps.PacketLoss,\n\t\t\t\"specify percent of packet loss on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\")\n\t\tqemu.Float64Var(&qOps.PacketReorder, packetReorderFlag, qOps.PacketReorder,\n\t\t\t\"specify percent of reordered packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\")\n\t\tqemu.Float64Var(&qOps.PacketCorrupt, packetCorruptFlag, qOps.PacketCorrupt,\n\t\t\t\"specify percent of corrupt packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\")\n\t\tqemu.IntVar(&qOps.Bandwidth, bandwidthFlag, qOps.Bandwidth, \"specify bandwidth restriction (in kbps) on the bridge interface\")\n\t\tqemu.StringVar(&qOps.WithFirewall, firewallFlag, qOps.WithFirewall, \"inject firewall rules into the cluster, value is default policy - accept/block\")\n\t\tqemu.Var(&qOps.WithSiderolinkAgent, withSiderolinkAgentFlag,\n\t\t\t\"enables the use of siderolink agent as configuration apply mechanism. `true` or `wireguard` enables the agent, `tunnel` enables the agent with grpc tunneling\")\n\t\tqemu.StringVar(&qOps.ConfigInjectionMethod,\n\t\t\tconfigInjectionMethodFlag, qOps.ConfigInjectionMethod, \"a method to inject machine config: default is HTTP server, 'metal-iso' to mount an ISO\")\n\t\tqemu.BoolVar(&qOps.Airgapped, airgappedFlag, qOps.Airgapped, \"limit VM network access to the provisioning network only\")\n\t\tqemu.StringVar(&qOps.ImageCachePath, imageCachePathFlag, qOps.ImageCachePath, \"path to image cache\")\n\t\tqemu.StringVar(&qOps.ImageCacheTLSCertFile, imageCacheTLSCertFileFlag, qOps.ImageCacheTLSCertFile, \"path to image cache TLS cert\")\n\t\tqemu.StringVar(&qOps.ImageCacheTLSKeyFile, imageCacheTLSKeyFileFlag, qOps.ImageCacheTLSKeyFile, \"path to image cache TLS key\")\n\t\tqemu.Uint16Var(&qOps.ImageCachePort, imageCachePortFlag, qOps.ImageCachePort, \"port on which to serve image cache\")\n\n\t\treturn qemu\n\t}\n\n\t// createCmd is the developer oriented create command.\n\tcreateCmd := &cobra.Command{\n\t\tUse:   cmdName,\n\t\tShort: \"Creates a local QEMU-based cluster for Talos development.\",\n\t\tArgs:  cobra.NoArgs,\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\treturn cli.WithContext(context.Background(), func(ctx context.Context) error {\n\t\t\t\tif cmdName == \"create\" {\n\t\t\t\t\tcli.Warning(\"the developer oriented 'cluster create' command has been moved to 'cluster create dev'\")\n\t\t\t\t}\n\n\t\t\t\tif err := validateQemuFlags(cmd.Flags(), unImplementedFlagsDarwin); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tvar disks strings.Builder\n\t\t\t\tfmt.Fprintf(&disks, \"virtio:%d\", legacyOps.clusterDiskSize)\n\n\t\t\t\tfor i := range legacyOps.extraDisks {\n\t\t\t\t\tdriver := \"ide\"\n\t\t\t\t\ttag := \"\"\n\t\t\t\t\tserial := \"\"\n\n\t\t\t\t\t// ide driver is not supported on arm64\n\t\t\t\t\tif qOps.TargetArch == \"arm64\" {\n\t\t\t\t\t\tdriver = \"virtio\"\n\t\t\t\t\t}\n\n\t\t\t\t\tif i < len(legacyOps.extraDisksDrivers) {\n\t\t\t\t\t\tdriver = legacyOps.extraDisksDrivers[i]\n\t\t\t\t\t}\n\n\t\t\t\t\tif i < len(legacyOps.extraDisksTags) {\n\t\t\t\t\t\tif legacyOps.extraDisksTags[i] != \"\" {\n\t\t\t\t\t\t\ttag = fmt.Sprintf(\":tag=%s\", legacyOps.extraDisksTags[i])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif i < len(legacyOps.extraDisksSerials) {\n\t\t\t\t\t\tif legacyOps.extraDisksSerials[i] != \"\" {\n\t\t\t\t\t\t\tserial = fmt.Sprintf(\":serial=%s\", legacyOps.extraDisksSerials[i])\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintf(&disks, \",%s:%d%s%s\", driver, legacyOps.extraDiskSize, tag, serial)\n\t\t\t\t}\n\n\t\t\t\tqOps.Disks = flags.Disks{}\n\n\t\t\t\tif err := qOps.Disks.Set(disks.String()); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn createDevCluster(ctx, cOps, qOps)\n\t\t\t})\n\t\t},\n\t}\n\tcreateCmd.Flags().IntVar(&legacyOps.clusterDiskSize, clusterDiskSizeFlag, 6*1024, \"default limit on disk size in MB (each VM)\")\n\tcreateCmd.Flags().IntVar(&legacyOps.extraDisks, extraDisksFlag, 0, \"number of extra disks to create for each worker VM\")\n\tcreateCmd.Flags().StringSliceVar(&legacyOps.extraDisksDrivers, extraDisksDriversFlag, nil, \"driver for each extra disk (virtio, ide, ahci, scsi, nvme, megaraid)\")\n\tcreateCmd.Flags().StringSliceVar(&legacyOps.extraDisksTags, extraDisksTagsFlag, nil, \"tags for each extra disk (only used by virtiofs)\")\n\tcreateCmd.Flags().StringSliceVar(&legacyOps.extraDisksSerials, extraDisksSerialsFlag, nil, \"serials for each extra disk\")\n\tcreateCmd.Flags().IntVar(&legacyOps.extraDiskSize, extraDiskSizeFlag, 5*1024, \"default limit on disk size in MB (each VM)\")\n\n\tclustercmd.AddProvisionerFlag(createCmd)\n\tcli.Should(createCmd.Flags().MarkHidden(clustercmd.ProvisionerFlagName))\n\n\tcreateCmd.Flags().AddFlagSet(getCommonFlags())\n\tcreateCmd.Flags().AddFlagSet(getQemuFlags())\n\taddOmniJoinTokenFlag(createCmd, &cOps.OmniAPIEndpoint, configPatchFlag, configPatchWorkerFlag, configPatchControlPlaneFlag)\n\n\tcreateCmd.MarkFlagsMutuallyExclusive(tpmEnabledFlag, tpm2EnabledFlag)\n\n\thideUnimplementedQemuFlags(createCmd, unImplementedFlagsDarwin)\n\n\tif hidden {\n\t\tcreateCmd.Flags().VisitAll(func(f *pflag.Flag) {\n\t\t\tf.Hidden = true\n\t\t})\n\n\t\tcreateCmd.Short = \"Create a local Talos cluster.\"\n\t\tcreateCmd.DisableFlagsInUseLine = true\n\t}\n\n\treturn createCmd\n}\n\nfunc init() {\n\tcreateCmd.AddCommand(createDevCmd)\n\tclustercmd.Cmd.AddCommand(createCmd)\n}\n\nfunc validateQemuFlags(allCmdFlags *pflag.FlagSet, unImplementedQemuFlagsDarwin []string) error {\n\terrMsg := \"\"\n\n\tallCmdFlags.VisitAll(func(f *pflag.Flag) {\n\t\tif f.Changed {\n\t\t\tif runtime.GOOS == \"darwin\" && slices.Contains(unImplementedQemuFlagsDarwin, f.Name) {\n\t\t\t\terrMsg += fmt.Sprintf(\"the \\\"%s\\\" flag is not supported on macos\\n\", f.Name)\n\t\t\t}\n\t\t}\n\t})\n\n\tif errMsg != \"\" {\n\t\treturn fmt.Errorf(\"%sinvalid flags found\", errMsg)\n\t}\n\n\treturn nil\n}\n\nfunc hideUnimplementedQemuFlags(cmd *cobra.Command, unImplementedQemuFlagsDarwin []string) {\n\tcmd.Flags().VisitAll(func(f *pflag.Flag) {\n\t\tif runtime.GOOS != \"darwin\" {\n\t\t\treturn\n\t\t}\n\n\t\tfor _, unimplemented := range unImplementedQemuFlagsDarwin {\n\t\t\tif f.Name == unimplemented {\n\t\t\t\tf.Hidden = true\n\t\t\t}\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/cmd_docker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tclustercmd \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\nfunc init() {\n\tdOps := clusterops.GetDocker()\n\tcOps := clusterops.GetCommon()\n\n\tconst (\n\t\tportsFlag             = \"exposed-ports\"\n\t\tdockerDisableIPv6Flag = \"disable-ipv6\"\n\t\tdockerHostIPFlag      = \"host-ip\"\n\t\tmountOptsFlag         = \"mount\"\n\t\tsubnetFlag            = \"subnet\"\n\t)\n\n\tgetDockerFlags := func() *pflag.FlagSet {\n\t\tdocker := pflag.NewFlagSet(\"docker\", pflag.PanicOnError)\n\n\t\tdocker.StringVarP(&dOps.Ports, portsFlag, \"p\", dOps.Ports,\n\t\t\t\"comma-separated list of ports/protocols to expose on init node. Ex -p <hostPort>:<containerPort>/<protocol (tcp or udp)>\")\n\t\tdocker.StringVar(&dOps.HostIP, dockerHostIPFlag, dOps.HostIP, \"Host IP to forward exposed ports to\")\n\t\tdocker.BoolVar(&dOps.DisableIPv6, dockerDisableIPv6Flag, dOps.DisableIPv6, \"skip enabling IPv6 in containers\")\n\t\tcli.Should(docker.MarkHidden(dockerDisableIPv6Flag))\n\t\tdocker.Var(&dOps.MountOpts, mountOptsFlag, \"attach a mount to the container (docker --mount syntax)\")\n\t\tdocker.StringVar(&dOps.TalosImage, \"image\", dOps.TalosImage, \"the talos image to run\")\n\n\t\treturn docker\n\t}\n\n\tcommonFlags := getCommonUserFacingFlags(&cOps)\n\tcommonFlags.StringVar(&cOps.NetworkCIDR, subnetFlag, cOps.NetworkCIDR, \"Docker network subnet CIDR\")\n\n\tcreateDockerCmd := &cobra.Command{\n\t\tUse:   \"docker\",\n\t\tShort: \"Create a local Docker based kubernetes cluster\",\n\t\tArgs:  cobra.NoArgs,\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\treturn cli.WithContext(context.Background(), func(ctx context.Context) error {\n\t\t\t\tprovisioner, err := providers.Factory(ctx, providers.DockerProviderName)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tclusterConfigs, err := getDockerClusterRequest(cOps, dOps, provisioner)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tcluster, err := provisioner.Create(ctx, clusterConfigs.ClusterRequest, clusterConfigs.ProvisionOptions...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\terr = postCreate(ctx, cOps, cluster, clusterConfigs)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn clustercmd.ShowCluster(cluster)\n\t\t\t})\n\t\t},\n\t}\n\n\tcreateDockerCmd.Flags().AddFlagSet(getDockerFlags())\n\tcreateDockerCmd.Flags().AddFlagSet(commonFlags)\n\n\tcreateCmd.AddCommand(createDockerCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/cmd_qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/constants\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\ntype presetOptions struct {\n\tschematicID     string\n\timageFactoryURL string\n\tpresets         []string\n}\n\nfunc init() {\n\tpresetOptions := presetOptions{}\n\tqOps := clusterops.GetQemu()\n\tcOps := clusterops.GetCommon()\n\tcOps.SkipInjectingConfig = true\n\tcOps.ApplyConfigEnabled = true\n\n\tcommonFlags := getCommonUserFacingFlags(&cOps)\n\taddControlplanesFlag(commonFlags, &cOps.Controlplanes)\n\taddTalosVersionFlag(commonFlags, &cOps.TalosVersion, \"the desired talos version\")\n\tcommonFlags.StringVar(&cOps.NetworkCIDR, networkCIDRFlagName, \"10.5.0.0/24\", \"CIDR of the cluster network\")\n\n\tgetQemuFlags := func() *pflag.FlagSet {\n\t\tqemu := pflag.NewFlagSet(\"qemu\", pflag.PanicOnError)\n\n\t\taddDisksFlag(qemu, &qOps.Disks)\n\t\tqemu.StringVar(&presetOptions.schematicID, \"schematic-id\", \"\", \"image factory schematic id (defaults to an empty schematic)\")\n\t\tqemu.StringVar(&presetOptions.imageFactoryURL, \"image-factory-url\", constants.ImageFactoryURL, \"image factory url\")\n\t\tqemu.StringSliceVar(&presetOptions.presets, \"presets\", []string{preset.ISO{}.Name()}, \"list of presets to apply\")\n\n\t\treturn qemu\n\t}\n\n\tvar cmdDescription strings.Builder\n\tcmdDescription.WriteString(\"Create a local QEMU based Talos cluster.\\n\\n\")\n\n\tcmdDescription.WriteString(\"Available presets:\\n\")\n\n\tfor _, p := range preset.Presets {\n\t\tcmdDescription.WriteString(\"  - \" + p.Name() + \": \" + p.Description() + \"\\n\")\n\t}\n\n\tcmdDescription.WriteString(\"\\n\")\n\tcmdDescription.WriteString(\"Note: exactly one of 'iso', 'iso-secureboot', 'pxe' or 'disk-image' presets must be specified.\\n\")\n\n\tcreateQemuCmd := &cobra.Command{\n\t\tUse:   providers.QemuProviderName,\n\t\tShort: \"Create a local QEMU based Talos cluster.\",\n\t\tLong:  cmdDescription.String(),\n\t\tArgs:  cobra.NoArgs,\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\treturn cli.WithContext(context.Background(), func(ctx context.Context) error {\n\t\t\t\tprovisioner, err := providers.Factory(ctx, providers.QemuProviderName)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn createQemuCluster(ctx, qOps, cOps, presetOptions, provisioner)\n\t\t\t})\n\t\t},\n\t}\n\n\tcreateQemuCmd.Flags().AddFlagSet(commonFlags)\n\tcreateQemuCmd.Flags().AddFlagSet(getQemuFlags())\n\taddOmniJoinTokenFlag(createQemuCmd, &cOps.OmniAPIEndpoint, configPatchFlagName, configPatchWorkerFlagName, configPatchControlPlaneFlagName)\n\n\tcreateCmd.AddCommand(createQemuCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/create.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-getter/v2\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n)\n\n// downloadBootAssets downloads the boot assets in the given qemuOps if they are URLs, and replaces their URL paths with the downloaded paths on the filesystem.\n//\n// As it modifies the qemuOps struct, it needs to be passed by reference.\n//\n//nolint:gocyclo\nfunc downloadBootAssets(ctx context.Context, qOps *clusterops.Qemu) error {\n\t// download & cache images if provides as URLs\n\tfor _, downloadableImage := range []struct {\n\t\tpath           *string\n\t\tdisableArchive bool\n\t}{\n\t\t{\n\t\t\tpath: &qOps.NodeVmlinuzPath,\n\t\t},\n\t\t{\n\t\t\tpath:           &qOps.NodeInitramfsPath,\n\t\t\tdisableArchive: true,\n\t\t},\n\t\t{\n\t\t\tpath: &qOps.NodeISOPath,\n\t\t},\n\t\t{\n\t\t\tpath: &qOps.NodeUSBPath,\n\t\t},\n\t\t{\n\t\t\tpath: &qOps.NodeUKIPath,\n\t\t},\n\t\t{\n\t\t\tpath: &qOps.NodeDiskImagePath,\n\t\t\t// we disable extracting the compressed image since we handle zstd for disk images\n\t\t\tdisableArchive: true,\n\t\t},\n\t} {\n\t\tif *downloadableImage.path == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tu, err := url.Parse(*downloadableImage.path)\n\t\tif err != nil || !(u.Scheme == \"http\" || u.Scheme == \"https\") {\n\t\t\t// not a URL\n\t\t\tcontinue\n\t\t}\n\n\t\tdefaultStateDir, err := clientconfig.GetTalosDirectory()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcacheDir := filepath.Join(defaultStateDir, \"cache\")\n\n\t\tif err = os.MkdirAll(cacheDir, 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdestPath := strings.ReplaceAll(\n\t\t\tstrings.ReplaceAll(u.String(), \"/\", \"-\"),\n\t\t\t\":\", \"-\")\n\n\t\t_, err = os.Stat(filepath.Join(cacheDir, destPath))\n\t\tif err == nil {\n\t\t\t*downloadableImage.path = filepath.Join(cacheDir, destPath)\n\n\t\t\t// already cached\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"downloading asset from %q to %q\\n\", u.String(), filepath.Join(cacheDir, destPath))\n\n\t\tclient := getter.Client{\n\t\t\tGetters: []getter.Getter{\n\t\t\t\t&getter.HttpGetter{\n\t\t\t\t\tHeadFirstTimeout: 30 * time.Minute,\n\t\t\t\t\tReadTimeout:      30 * time.Minute,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tif downloadableImage.disableArchive {\n\t\t\tq := u.Query()\n\n\t\t\tq.Set(\"archive\", \"false\")\n\n\t\t\tu.RawQuery = q.Encode()\n\t\t}\n\n\t\t_, err = client.Get(ctx, &getter.Request{\n\t\t\tSrc:     u.String(),\n\t\t\tDst:     filepath.Join(cacheDir, destPath),\n\t\t\tGetMode: getter.ModeFile,\n\t\t})\n\t\tif err != nil {\n\t\t\t// clean up the destination on failure\n\t\t\tos.Remove(filepath.Join(cacheDir, destPath)) //nolint:errcheck\n\n\t\t\treturn err\n\t\t}\n\n\t\t*downloadableImage.path = filepath.Join(cacheDir, destPath)\n\t}\n\n\treturn nil\n}\n\nfunc postCreate(\n\tctx context.Context,\n\tcOps clusterops.Common,\n\tcluster provision.Cluster,\n\tclusterConfigs clusterops.ClusterConfigs,\n) error {\n\tif clusterConfigs.ConfigBundle != nil {\n\t\tbundleTalosconfig := clusterConfigs.ConfigBundle.TalosConfig()\n\n\t\tif err := saveConfig(bundleTalosconfig, cOps.TalosconfigDestination); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tclusterAccess := access.NewAdapter(cluster, clusterConfigs.ProvisionOptions...)\n\tdefer clusterAccess.Close() //nolint:errcheck\n\n\tif cOps.ApplyConfigEnabled {\n\t\tfmt.Println(\"applying configuration to the cluster nodes\")\n\n\t\terr := clusterAccess.ApplyConfig(ctx, clusterConfigs.ClusterRequest.Nodes, clusterConfigs.ClusterRequest.SiderolinkRequest, os.Stdout)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif cOps.OmniAPIEndpoint != \"\" || (cOps.SkipInjectingConfig && !cOps.ApplyConfigEnabled) {\n\t\treturn nil\n\t}\n\n\treturn bootstrapCluster(ctx, clusterAccess, cOps)\n}\n\nfunc bootstrapCluster(ctx context.Context, clusterAccess *access.Adapter, cOps clusterops.Common) error {\n\tif !cOps.WithInitNode {\n\t\tif err := clusterAccess.Bootstrap(ctx, os.Stdout); err != nil {\n\t\t\treturn fmt.Errorf(\"bootstrap error: %w\", err)\n\t\t}\n\t}\n\n\tif !cOps.ClusterWait {\n\t\treturn nil\n\t}\n\n\t// Run cluster readiness checks\n\tcheckCtx, checkCtxCancel := context.WithTimeout(ctx, cOps.ClusterWaitTimeout)\n\tdefer checkCtxCancel()\n\n\tchecks := check.DefaultClusterChecks()\n\n\tif cOps.SkipK8sNodeReadinessCheck {\n\t\tchecks = slices.Concat(check.PreBootSequenceChecks(), check.K8sComponentsReadinessChecks())\n\t}\n\n\tchecks = slices.Concat(checks, check.ExtraClusterChecks())\n\n\tif err := check.Wait(checkCtx, clusterAccess, checks, check.StderrReporter()); err != nil {\n\t\treturn err\n\t}\n\n\tif cOps.SkipKubeconfig {\n\t\treturn nil\n\t}\n\n\treturn mergeKubeconfig(ctx, clusterAccess)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/create_dev.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-kubeconfig\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\tclustercmd \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\n//nolint:gocyclo,cyclop\nfunc createDevCluster(ctx context.Context, cOps clusterops.Common, qOps clusterops.Qemu) error {\n\tif err := downloadBootAssets(ctx, &qOps); err != nil {\n\t\treturn err\n\t}\n\n\tif cOps.TalosVersion == \"\" {\n\t\tparts := strings.Split(qOps.NodeInstallImage, \":\")\n\t\tcOps.TalosVersion = parts[len(parts)-1]\n\t}\n\n\tprovisioner, err := providers.Factory(ctx, providers.QemuProviderName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tclusterConfigs, err := configmaker.GetQemuConfigs(configmaker.QemuOptions{\n\t\tExtraOps:    qOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: provisioner,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = preCreate(cOps, clusterConfigs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcluster, err := provisioner.Create(ctx, clusterConfigs.ClusterRequest, clusterConfigs.ProvisionOptions...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif qOps.DebugShellEnabled {\n\t\tfmt.Println(\"You can now connect to debug shell on any node using these commands:\")\n\n\t\tfor _, node := range clusterConfigs.ClusterRequest.Nodes {\n\t\t\ttalosDir, err := clientconfig.GetTalosDirectory()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Printf(\"socat - UNIX-CONNECT:%s\\n\", filepath.Join(talosDir, \"clusters\", cOps.RootOps.ClusterName, node.Name+\".serial\"))\n\t\t}\n\n\t\treturn nil\n\t}\n\n\t// Create and save the talosctl configuration file.\n\terr = postCreate(ctx, cOps, cluster, clusterConfigs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn clustercmd.ShowCluster(cluster)\n}\n\nfunc saveConfig(talosConfigObj *clientconfig.Config, talosconfigPath string) (err error) {\n\tc, err := clientconfig.Open(talosconfigPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening talos config: %w\", err)\n\t}\n\n\trenames := c.Merge(talosConfigObj)\n\tfor _, rename := range renames {\n\t\tfmt.Fprintf(os.Stderr, \"renamed talosconfig context %s\\n\", rename.String())\n\t}\n\n\treturn c.Save(talosconfigPath)\n}\n\nfunc mergeKubeconfig(ctx context.Context, clusterAccess *access.Adapter) error {\n\tkubeconfigPath, err := kubeconfig.SinglePath()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"\\nmerging kubeconfig into %q\\n\", kubeconfigPath)\n\n\tk8sconfig, err := clusterAccess.Kubeconfig(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching kubeconfig: %w\", err)\n\t}\n\n\tkubeConfig, err := clientcmd.Load(k8sconfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing kubeconfig: %w\", err)\n\t}\n\n\tif clusterAccess.ForceEndpoint != \"\" {\n\t\tfor name := range kubeConfig.Clusters {\n\t\t\tkubeConfig.Clusters[name].Server = clusterAccess.ForceEndpoint\n\t\t}\n\t}\n\n\t_, err = os.Stat(kubeconfigPath)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\treturn clientcmd.WriteToFile(*kubeConfig, kubeconfigPath)\n\t}\n\n\tmerger, err := kubeconfig.Load(kubeconfigPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error loading existing kubeconfig: %w\", err)\n\t}\n\n\terr = merger.Merge(kubeConfig, kubeconfig.MergeOptions{\n\t\tActivateContext: true,\n\t\tOutputWriter:    os.Stdout,\n\t\tConflictHandler: func(component kubeconfig.ConfigComponent, name string) (kubeconfig.ConflictDecision, error) {\n\t\t\treturn kubeconfig.RenameDecision, nil\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error merging kubeconfig: %w\", err)\n\t}\n\n\treturn merger.Write(kubeconfigPath)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/create_docker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n//nolint:gocyclo,cyclop\nfunc getDockerClusterRequest(cOps clusterops.Common, dOps clusterops.Docker, provisioner provision.Provisioner) (clusterops.ClusterConfigs, error) {\n\tparts := strings.Split(dOps.TalosImage, \":\")\n\tcOps.TalosVersion = parts[len(parts)-1]\n\n\t_, err := config.ParseContractFromVersion(cOps.TalosVersion)\n\tif err != nil {\n\t\tcurrentVersion := helpers.GetTag()\n\t\tfmt.Printf(\"failed to derrive Talos version from the docker image, defaulting to %s\\n\", currentVersion)\n\t\tcOps.TalosVersion = currentVersion\n\t}\n\n\treturn configmaker.GetDockerConfigs(configmaker.DockerOptions{\n\t\tExtraOps:    dOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: provisioner,\n\t})\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/create_qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage create\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/constants\"\n\tclustercmd \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/preset\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n//nolint:gocyclo,cyclop\nfunc createQemuCluster(\n\tctx context.Context,\n\tqOps clusterops.Qemu,\n\tcOps clusterops.Common,\n\tpresetOptions presetOptions,\n\tprovisioner provision.Provisioner,\n) error {\n\tif cOps.TalosVersion == \"\" || cOps.TalosVersion[0] != 'v' {\n\t\treturn fmt.Errorf(\"failed to parse talos version: version string must start with a 'v'\")\n\t}\n\n\t_, err := config.ParseContractFromVersion(cOps.TalosVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse talos version: %s\", err)\n\t}\n\n\tif presetOptions.schematicID == \"\" {\n\t\tpresetOptions.schematicID = constants.ImageFactoryEmptySchematicID\n\t}\n\n\tfactoryURL, err := url.Parse(presetOptions.imageFactoryURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"malformed Image Factory URL: %q: %w\", presetOptions.imageFactoryURL, err)\n\t}\n\n\tif factoryURL.Scheme == \"\" || factoryURL.Host == \"\" {\n\t\treturn fmt.Errorf(\"image Factory URL must include scheme and host: %q\", presetOptions.imageFactoryURL)\n\t}\n\n\tif slices.Contains(presetOptions.presets, preset.Maintenance{}.Name()) && cOps.OmniAPIEndpoint != \"\" {\n\t\tfmt.Println(\"omni-api-endpoint specified along with the 'maintenance' preset\")\n\t\tfmt.Println(\"machine configuration containing 'SideroLinkConfig' will be written to the working path but will not be applied to the nodes\")\n\t}\n\n\terr = preset.Apply(\n\t\tpreset.Options{\n\t\t\tSchematicID:     presetOptions.schematicID,\n\t\t\tImageFactoryURL: factoryURL,\n\t\t}, &cOps, &qOps, presetOptions.presets)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := downloadBootAssets(ctx, &qOps); err != nil {\n\t\treturn err\n\t}\n\n\tclusterConfigs, err := configmaker.GetQemuConfigs(configmaker.QemuOptions{\n\t\tExtraOps:    qOps,\n\t\tCommonOps:   cOps,\n\t\tProvisioner: provisioner,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = preCreate(cOps, clusterConfigs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcluster, err := provisioner.Create(ctx, clusterConfigs.ClusterRequest, clusterConfigs.ProvisionOptions...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = postCreate(ctx, cOps, cluster, clusterConfigs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn clustercmd.ShowCluster(cluster)\n}\n\nfunc preCreate(cOps clusterops.Common, clusterConfigs clusterops.ClusterConfigs) error {\n\t// write machine config\n\tif cOps.SkipInjectingConfig {\n\t\tif err := writeMachineconfig(clusterConfigs, cOps); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeMachineconfig(clusterConfigs clusterops.ClusterConfigs, cOps clusterops.Common) error {\n\tif clusterConfigs.ConfigBundle != nil {\n\t\ttypes := []machine.Type{machine.TypeControlPlane, machine.TypeWorker}\n\n\t\tif cOps.WithInitNode {\n\t\t\ttypes = slices.Insert(types, 0, machine.TypeInit)\n\t\t}\n\n\t\treturn clusterConfigs.ConfigBundle.Write(\".\", encoder.CommentsAll, types...)\n\t}\n\n\t// no configbundle, just write the machine config as-is\n\tcfgBytes, err := clusterConfigs.ClusterRequest.Nodes[0].Config.Bytes()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfullFilePath := filepath.Join(\".\", \"machineconfig.yaml\")\n\tif err = os.WriteFile(fullFilePath, cfgBytes, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"created %s\\n\", fullFilePath)\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/flags/agent.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage flags\n\nimport \"fmt\"\n\n// Agent represents the type of the agent to use for cluster management.\ntype Agent uint8\n\nfunc (a *Agent) String() string {\n\tswitch *a {\n\tcase 1:\n\t\treturn \"wireguard\"\n\tcase 2:\n\t\treturn \"grpc-tunnel\"\n\tcase 3:\n\t\treturn \"wireguard+tls\"\n\tcase 4:\n\t\treturn \"grpc-tunnel+tls\"\n\tdefault:\n\t\treturn \"none\"\n\t}\n}\n\n// Set implements pflag.Value interface.\nfunc (a *Agent) Set(s string) error {\n\tswitch s {\n\tcase \"true\", \"wireguard\":\n\t\t*a = 1\n\tcase \"tunnel\":\n\t\t*a = 2\n\tcase \"wireguard+tls\":\n\t\t*a = 3\n\tcase \"grpc-tunnel+tls\":\n\t\t*a = 4\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown type: %s, possible values: 'true', 'wireguard' for the usual WG; 'tunnel' for WG over GRPC, add '+tls' to enable TLS for API\", s)\n\t}\n\n\treturn nil\n}\n\n// Type implements pflag.Value interface.\nfunc (a *Agent) Type() string { return \"agent\" }\n\n// IsEnabled returns true if the agent is enabled.\nfunc (a *Agent) IsEnabled() bool { return *a != 0 }\n\n// IsTunnel returns true if the agent is a tunnel.\nfunc (a *Agent) IsTunnel() bool { return *a == 2 || *a == 4 }\n\n// IsTLS returns true if the agent is using TLS.\nfunc (a *Agent) IsTLS() bool { return *a == 3 || *a == 4 }\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/flags/disks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage flags\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/bytesize\"\n)\n\n// DiskRequest is the configuration required for disk creation.\ntype DiskRequest struct {\n\tDriver string\n\tSize   bytesize.ByteSize\n\tTag    string\n\tSerial string\n}\n\n// Drivers that support tag option.\nvar tagDrivers = []string{\"virtiofs\"}\n\n// Drivers that support serial option.\nvar serialDrivers = []string{\"virtio\"}\n\n// ParseDisksFlag parses the disks flag into a slice of DiskRequests.\nfunc ParseDisksFlag(disks []string) ([]DiskRequest, error) {\n\tresult := []DiskRequest{}\n\n\tif len(disks) == 0 {\n\t\treturn nil, errors.New(\"at least one disk has to be specified\")\n\t}\n\n\tfor _, d := range disks {\n\t\tparts := strings.Split(d, \":\")\n\t\tif len(parts) < 2 {\n\t\t\treturn nil, fmt.Errorf(\"invalid disk format: %q\", d)\n\t\t}\n\n\t\tsize := bytesize.WithDefaultUnit(\"MiB\")\n\n\t\terr := size.Set(parts[1])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid size in disk spec: %q\", d)\n\t\t}\n\n\t\treq := DiskRequest{\n\t\t\tDriver: parts[0],\n\t\t\tSize:   *size,\n\t\t}\n\n\t\tif len(parts) > 2 {\n\t\t\tfor _, part := range parts[2:] {\n\t\t\t\tif err := parseKVParams(&req, part); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%w: %q\", err, d)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tresult = append(result, req)\n\t}\n\n\treturn result, nil\n}\n\nfunc parseKVParams(req *DiskRequest, part string) error {\n\tkv := strings.SplitN(part, \"=\", 2)\n\tif len(kv) != 2 {\n\t\treturn fmt.Errorf(\"invalid disk option in spec: %q\", part)\n\t}\n\n\tswitch kv[0] {\n\tcase \"tag\":\n\t\tif !slices.Contains(tagDrivers, req.Driver) {\n\t\t\treturn fmt.Errorf(\"tag option is only supported for %v drivers in spec\", tagDrivers)\n\t\t}\n\n\t\treq.Tag = kv[1]\n\tcase \"serial\":\n\t\tif !slices.Contains(serialDrivers, req.Driver) {\n\t\t\treturn fmt.Errorf(\"serial option is only supported for %v drivers in spec\", serialDrivers)\n\t\t}\n\n\t\treq.Serial = kv[1]\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown disk option %q in spec\", kv[0])\n\t}\n\n\treturn nil\n}\n\n// Disks implements pflag.Value for accumulating multiple DiskRequest entries.\n// It accepts repeated uses of the flag (e.g., --disks a:1GiB --disks b:10GiB)\n// and comma-separated lists (e.g., --disks a:1GiB,b:10GiB).\ntype Disks struct {\n\trequests []DiskRequest\n}\n\n// String returns a string representation suitable for flag printing.\nfunc (f *Disks) String() string {\n\tif f == nil || len(f.requests) == 0 {\n\t\treturn \"\"\n\t}\n\n\tparts := make([]string, 0, len(f.requests))\n\tfor _, r := range f.requests {\n\t\tsb := strings.Builder{}\n\n\t\tsb.WriteString(r.Driver)\n\t\tsb.WriteString(\":\")\n\t\tsb.WriteString(r.Size.String())\n\n\t\tif r.Tag != \"\" {\n\t\t\tsb.WriteString(\":tag=\")\n\t\t\tsb.WriteString(r.Tag)\n\t\t}\n\n\t\tif r.Serial != \"\" {\n\t\t\tsb.WriteString(\":serial=\")\n\t\t\tsb.WriteString(r.Serial)\n\t\t}\n\n\t\tparts = append(parts, sb.String())\n\t}\n\n\treturn strings.Join(parts, \",\")\n}\n\n// Set parses and appends one or more disk specifications to the flag value.\n// The input may contain a single spec (\"driver:size\") or a comma-separated list.\nfunc (f *Disks) Set(value string) error {\n\tif strings.TrimSpace(value) == \"\" {\n\t\treturn errors.New(\"disk value must not be empty\")\n\t}\n\t// Support comma-separated values in a single Set call.\n\traw := strings.Split(value, \",\")\n\n\treqs, err := ParseDisksFlag(raw)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tf.requests = reqs\n\n\treturn nil\n}\n\n// Type returns the flag's value type name.\nfunc (f *Disks) Type() string { return \"disks\" }\n\n// Requests returns a defensive copy of the accumulated disk requests.\nfunc (f *Disks) Requests() []DiskRequest {\n\tout := make([]DiskRequest, len(f.requests))\n\tcopy(out, f.requests)\n\n\treturn out\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/flags/disks_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage flags_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/spf13/pflag\"\n\t\"github.com/stretchr/testify/assert\"\n\n\tflags \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/pkg/bytesize\"\n)\n\nfunc TestDisksFlag_ExtraOpts(t *testing.T) {\n\tt.Parallel()\n\n\tvar d flags.Disks\n\n\tfs := pflag.NewFlagSet(\"test\", pflag.ContinueOnError)\n\tfs.Var(&d, \"disks\", \"\")\n\n\targs := []string{\n\t\t\"--disks\", \"virtio:1GiB:serial=test-1,virtiofs:1GiB:tag=foo,virtiofs:1GiB:tag=bar\",\n\t}\n\n\terr := fs.Parse(args)\n\tassert.NoError(t, err)\n\n\treqs := d.Requests()\n\tassert.Len(t, reqs, 3)\n\n\ttoBytes := func(s string) uint64 {\n\t\tbs := bytesize.WithDefaultUnit(\"MiB\")\n\t\tassert.NoError(t, bs.Set(s))\n\n\t\treturn bs.Bytes()\n\t}\n\n\tassert.Equal(t, \"virtio\", reqs[0].Driver)\n\tassert.Equal(t, toBytes(\"1GiB\"), reqs[0].Size.Bytes())\n\tassert.Equal(t, \"test-1\", reqs[0].Serial)\n\tassert.Equal(t, \"\", reqs[0].Tag)\n\n\tassert.Equal(t, \"virtiofs\", reqs[1].Driver)\n\tassert.Equal(t, toBytes(\"1GiB\"), reqs[1].Size.Bytes())\n\tassert.Equal(t, \"\", reqs[1].Serial)\n\tassert.Equal(t, \"foo\", reqs[1].Tag)\n\n\tassert.Equal(t, \"virtiofs\", reqs[2].Driver)\n\tassert.Equal(t, toBytes(\"1GiB\"), reqs[2].Size.Bytes())\n\tassert.Equal(t, \"\", reqs[2].Serial)\n\tassert.Equal(t, \"bar\", reqs[2].Tag)\n\n\t// Type should be stable\n\tassert.Equal(t, \"disks\", d.Type())\n\n\tassert.Equal(t, \"virtio:1GiB:serial=test-1,virtiofs:1GiB:tag=foo,virtiofs:1GiB:tag=bar\", d.String())\n}\n\nfunc TestDisksFlag_AccumulatesAndRequests(t *testing.T) {\n\tt.Parallel()\n\n\tvar d flags.Disks\n\n\tfs := pflag.NewFlagSet(\"test\", pflag.ContinueOnError)\n\tfs.Var(&d, \"disks\", \"\")\n\n\targs := []string{\n\t\t\"--disks\", \"virtio:1GiB,nvme:10GiB,sata:512MiB\",\n\t}\n\n\terr := fs.Parse(args)\n\tassert.NoError(t, err)\n\n\treqs := d.Requests()\n\tassert.Len(t, reqs, 3)\n\n\ttoBytes := func(s string) uint64 {\n\t\tbs := bytesize.WithDefaultUnit(\"MiB\")\n\t\tassert.NoError(t, bs.Set(s))\n\n\t\treturn bs.Bytes()\n\t}\n\n\tassert.Equal(t, \"virtio\", reqs[0].Driver)\n\tassert.Equal(t, toBytes(\"1GiB\"), reqs[0].Size.Bytes())\n\n\tassert.Equal(t, \"nvme\", reqs[1].Driver)\n\tassert.Equal(t, toBytes(\"10GiB\"), reqs[1].Size.Bytes())\n\n\tassert.Equal(t, \"sata\", reqs[2].Driver)\n\tassert.Equal(t, toBytes(\"512MiB\"), reqs[2].Size.Bytes())\n\n\t// Type should be stable\n\tassert.Equal(t, \"disks\", d.Type())\n\n\tassert.Equal(t, \"virtio:1GiB,nvme:10GiB,sata:512MiB\", d.String())\n}\n\nfunc TestDisksFlag_Set(t *testing.T) {\n\tt.Parallel()\n\n\tvar d flags.Disks\n\n\terr := d.Set(\"virtio:6gb\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"virtio:6gb\", d.String())\n\n\terr = d.Set(\"nvme:12mb,sata:2gb\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"nvme:12mb,sata:2gb\", d.String())\n\n\terr = d.Set(\"invalid-no-colon\")\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/flags/virtiofs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage flags\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// VirtiofsRequest is the configuration required for virtiofs share creation.\ntype VirtiofsRequest struct {\n\tSharedDir  string\n\tSocketPath string\n}\n\n// ParseVirtiofsFlag parses the virtiofs flag into a slice of VirtiofsRequest.\nfunc ParseVirtiofsFlag(disks []string) ([]VirtiofsRequest, error) {\n\tresult := []VirtiofsRequest{}\n\n\tif len(disks) == 0 {\n\t\treturn nil, errors.New(\"at least one disk has to be specified\")\n\t}\n\n\tfor _, d := range disks {\n\t\tparts := strings.SplitN(d, \":\", 2)\n\t\tif len(parts) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"invalid disk format: %q\", d)\n\t\t}\n\n\t\tresult = append(result, VirtiofsRequest{\n\t\t\tSharedDir:  parts[0],\n\t\t\tSocketPath: parts[1],\n\t\t})\n\t}\n\n\treturn result, nil\n}\n\n// Virtiofs implements pflag.Value for accumulating multiple VirtiofsRequest entries.\ntype Virtiofs struct {\n\trequests []VirtiofsRequest\n}\n\n// String returns a string representation suitable for flag printing.\nfunc (f *Virtiofs) String() string {\n\tif f == nil || len(f.requests) == 0 {\n\t\treturn \"\"\n\t}\n\n\tparts := make([]string, 0, len(f.requests))\n\tfor _, r := range f.requests {\n\t\tparts = append(parts, fmt.Sprintf(\"%s:%s\", r.SharedDir, r.SocketPath))\n\t}\n\n\treturn strings.Join(parts, \",\")\n}\n\n// Set parses and appends one or more disk specifications to the flag value.\n// The input may contain a single spec (\"sharedDir:socketPath\") or a comma-separated list.\nfunc (f *Virtiofs) Set(value string) error {\n\tif strings.TrimSpace(value) == \"\" {\n\t\treturn errors.New(\"virtiofs value must not be empty\")\n\t}\n\t// Support comma-separated values in a single Set call.\n\traw := strings.Split(value, \",\")\n\n\treqs, err := ParseVirtiofsFlag(raw)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tf.requests = reqs\n\n\treturn nil\n}\n\n// Type returns the flag's value type name.\nfunc (f *Virtiofs) Type() string { return \"virtiofs\" }\n\n// Requests returns a defensive copy of the accumulated virtiofs share requests.\nfunc (f *Virtiofs) Requests() []VirtiofsRequest {\n\tout := make([]VirtiofsRequest, len(f.requests))\n\tcopy(out, f.requests)\n\n\treturn out\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/create/flags/virtiofs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage flags_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/spf13/pflag\"\n\t\"github.com/stretchr/testify/assert\"\n\n\tflags \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n)\n\nfunc TestVirtiofsFlag_AccumulatesAndRequests(t *testing.T) {\n\tt.Parallel()\n\n\tvar d flags.Virtiofs\n\n\tfs := pflag.NewFlagSet(\"test\", pflag.ContinueOnError)\n\tfs.Var(&d, \"virtiofs\", \"\")\n\n\targs := []string{\n\t\t\"--virtiofs\", \"/mnt/shared/1:/tmp/mnt-shared-1.sock,/mnt/shared/2:/tmp/mnt-shared-2.sock,/mnt/shared/3:/tmp/mnt-shared-3.sock\",\n\t}\n\n\terr := fs.Parse(args)\n\tassert.NoError(t, err)\n\n\treqs := d.Requests()\n\tassert.Len(t, reqs, 3)\n\n\tassert.Equal(t, \"/mnt/shared/1\", reqs[0].SharedDir)\n\tassert.Equal(t, \"/tmp/mnt-shared-1.sock\", reqs[0].SocketPath)\n\n\tassert.Equal(t, \"/mnt/shared/2\", reqs[1].SharedDir)\n\tassert.Equal(t, \"/tmp/mnt-shared-2.sock\", reqs[1].SocketPath)\n\n\tassert.Equal(t, \"/mnt/shared/3\", reqs[2].SharedDir)\n\tassert.Equal(t, \"/tmp/mnt-shared-3.sock\", reqs[2].SocketPath)\n\n\t// Type should be stable\n\tassert.Equal(t, \"virtiofs\", d.Type())\n\n\tassert.Equal(t, \"/mnt/shared/1:/tmp/mnt-shared-1.sock,/mnt/shared/2:/tmp/mnt-shared-2.sock,/mnt/shared/3:/tmp/mnt-shared-3.sock\", d.String())\n}\n\nfunc TestVirtiofsFlag_SetInvalid(t *testing.T) {\n\tt.Parallel()\n\n\tvar f flags.Virtiofs\n\n\terr := f.Set(\"/mnt/shared/1:/tmp/mnt-shared-1.sock\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"/mnt/shared/1:/tmp/mnt-shared-1.sock\", f.String())\n\n\terr = f.Set(\"/mnt/shared/1:/tmp/mnt-shared-1.sock,/mnt/shared/2:/tmp/mnt-shared-2.sock\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"/mnt/shared/1:/tmp/mnt-shared-1.sock,/mnt/shared/2:/tmp/mnt-shared-2.sock\", f.String())\n\n\terr = f.Set(\"invalid-no-colon\")\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/destroy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\nvar destroyCmdFlags struct {\n\tforceDelete                bool\n\tsaveSupportArchivePath     string\n\tsaveClusterLogsArchivePath string\n}\n\n// destroyCmd represents the cluster destroy command.\nvar destroyCmd = &cobra.Command{\n\tUse:   \"destroy\",\n\tShort: \"Destroys a local Talos kubernetes cluster\",\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn cli.WithContext(context.Background(), destroy)\n\t},\n}\n\nfunc destroy(ctx context.Context) error {\n\tstate, err := provision.ReadState(ctx, PersistentFlags.ClusterName, PersistentFlags.StateDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read cluster state: %w\", err)\n\t}\n\n\tprovisioner, err := providers.Factory(ctx, state.ProvisionerName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer provisioner.Close() //nolint:errcheck\n\n\tcluster, err := provisioner.Reflect(ctx, PersistentFlags.ClusterName, PersistentFlags.StateDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn provisioner.Destroy(\n\t\tctx,\n\t\tcluster,\n\t\tprovision.WithDeleteOnErr(destroyCmdFlags.forceDelete),\n\t\tprovision.WithSaveSupportArchivePath(destroyCmdFlags.saveSupportArchivePath),\n\t\tprovision.WithSaveClusterLogsArchivePath(destroyCmdFlags.saveClusterLogsArchivePath),\n\t)\n}\n\nfunc init() {\n\tdestroyCmd.PersistentFlags().BoolVarP(&destroyCmdFlags.forceDelete, \"force\", \"f\", false, \"force deletion of cluster directory if there were errors\")\n\tdestroyCmd.PersistentFlags().StringVarP(&destroyCmdFlags.saveSupportArchivePath, \"save-support-archive-path\", \"\", \"\", \"save support archive to the specified file on destroy\")\n\tdestroyCmd.PersistentFlags().StringVarP(&destroyCmdFlags.saveClusterLogsArchivePath, \"save-cluster-logs-archive-path\", \"\", \"\", \"save cluster logs archive to the specified file on destroy\")\n\tAddProvisionerFlag(destroyCmd)\n\tcli.Should(destroyCmd.Flags().MarkDeprecated(ProvisionerFlagName, \"the provisioner is inferred automatically\"))\n\n\tCmd.AddCommand(destroyCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/internal/firewallpatch/firewallpatch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package firewallpatch provides a set of default config patches to enable firewall.\npackage firewallpatch\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\nfunc ingressRuleWithinCluster(cidrs []netip.Prefix, gateways []netip.Addr) []network.IngressRule {\n\trules := make([]network.IngressRule, 0, len(cidrs))\n\n\tfor i := range cidrs {\n\t\trules = append(rules,\n\t\t\tnetwork.IngressRule{\n\t\t\t\tSubnet: cidrs[i],\n\t\t\t\tExcept: network.Prefix{Prefix: netip.PrefixFrom(gateways[i], gateways[i].BitLen())},\n\t\t\t},\n\t\t)\n\t}\n\n\treturn rules\n}\n\nfunc ingressRuleWideOpen() []network.IngressRule {\n\treturn []network.IngressRule{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t},\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"::/0\"),\n\t\t},\n\t}\n}\n\nfunc ingressOnly(ips []netip.Addr) []network.IngressRule {\n\treturn xslices.Map(ips, func(ip netip.Addr) network.IngressRule {\n\t\treturn network.IngressRule{\n\t\t\tSubnet: netip.PrefixFrom(ip, ip.BitLen()),\n\t\t}\n\t})\n}\n\n// ControlPlane generates a default firewall for a controlplane node.\n//\n// Kubelet and Trustd are only available within the cluster.\n// Apid & Kubernetes API is wide open.\n// Etcd is only available within the controlplanes.\nfunc ControlPlane(defaultAction nethelpers.DefaultAction, cidrs []netip.Prefix, gateways []netip.Addr, controlplanes []netip.Addr) configpatcher.Patch {\n\tdef := network.NewDefaultActionConfigV1Alpha1()\n\tdef.Ingress = defaultAction\n\n\tkubeletRule := network.NewRuleConfigV1Alpha1()\n\tkubeletRule.MetaName = \"kubelet-ingress\"\n\tkubeletRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.KubeletPort,\n\t\t\tHi: constants.KubeletPort,\n\t\t},\n\t}\n\tkubeletRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tkubeletRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tapidRule := network.NewRuleConfigV1Alpha1()\n\tapidRule.MetaName = \"apid-ingress\"\n\tapidRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.ApidPort,\n\t\t\tHi: constants.ApidPort,\n\t\t},\n\t}\n\tapidRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tapidRule.Ingress = ingressRuleWideOpen()\n\n\ttrustdRule := network.NewRuleConfigV1Alpha1()\n\ttrustdRule.MetaName = \"trustd-ingress\"\n\ttrustdRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.TrustdPort,\n\t\t\tHi: constants.TrustdPort,\n\t\t},\n\t}\n\ttrustdRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\ttrustdRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tkubeAPIRule := network.NewRuleConfigV1Alpha1()\n\tkubeAPIRule.MetaName = \"kubernetes-api-ingress\"\n\tkubeAPIRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.DefaultControlPlanePort,\n\t\t\tHi: constants.DefaultControlPlanePort,\n\t\t},\n\t}\n\tkubeAPIRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tkubeAPIRule.Ingress = ingressRuleWideOpen()\n\n\tetcdRule := network.NewRuleConfigV1Alpha1()\n\tetcdRule.MetaName = \"etcd-ingress\"\n\tetcdRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.EtcdClientPort,\n\t\t\tHi: constants.EtcdPeerPort,\n\t\t},\n\t}\n\tetcdRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tetcdRule.Ingress = ingressOnly(controlplanes)\n\n\tvxlanRule := network.NewRuleConfigV1Alpha1()\n\tvxlanRule.MetaName = \"cni-vxlan\"\n\tvxlanRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: 4789, // Flannel, Calico VXLAN\n\t\t\tHi: 4789,\n\t\t},\n\t\t{\n\t\t\tLo: 8472, // Cilium VXLAN\n\t\t\tHi: 8472,\n\t\t},\n\t}\n\tvxlanRule.PortSelector.Protocol = nethelpers.ProtocolUDP\n\tvxlanRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tprovider, err := container.New(def, kubeletRule, apidRule, trustdRule, kubeAPIRule, etcdRule, vxlanRule)\n\tif err != nil { // should not fail\n\t\tpanic(err)\n\t}\n\n\treturn configpatcher.NewStrategicMergePatch(provider)\n}\n\n// Worker generates a default firewall for a worker node.\n//\n// Kubelet & apid are only available within the cluster.\nfunc Worker(defaultAction nethelpers.DefaultAction, cidrs []netip.Prefix, gateways []netip.Addr) configpatcher.Patch {\n\tdef := network.NewDefaultActionConfigV1Alpha1()\n\tdef.Ingress = defaultAction\n\n\tkubeletRule := network.NewRuleConfigV1Alpha1()\n\tkubeletRule.MetaName = \"kubelet-ingress\"\n\tkubeletRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.KubeletPort,\n\t\t\tHi: constants.KubeletPort,\n\t\t},\n\t}\n\tkubeletRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tkubeletRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tapidRule := network.NewRuleConfigV1Alpha1()\n\tapidRule.MetaName = \"apid-ingress\"\n\tapidRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: constants.ApidPort,\n\t\t\tHi: constants.ApidPort,\n\t\t},\n\t}\n\tapidRule.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tapidRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tvxlanRule := network.NewRuleConfigV1Alpha1()\n\tvxlanRule.MetaName = \"cni-vxlan\"\n\tvxlanRule.PortSelector.Ports = []network.PortRange{\n\t\t{\n\t\t\tLo: 4789, // Flannel, Calico VXLAN\n\t\t\tHi: 4789,\n\t\t},\n\t\t{\n\t\t\tLo: 8472, // Cilium VXLAN\n\t\t\tHi: 8472,\n\t\t},\n\t}\n\tvxlanRule.PortSelector.Protocol = nethelpers.ProtocolUDP\n\tvxlanRule.Ingress = ingressRuleWithinCluster(cidrs, gateways)\n\n\tprovider, err := container.New(def, kubeletRule, apidRule, vxlanRule)\n\tif err != nil { // should not fail\n\t\tpanic(err)\n\t}\n\n\treturn configpatcher.NewStrategicMergePatch(provider)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/cluster/show.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\n// showCmd represents the cluster show command.\nvar showCmd = &cobra.Command{\n\tUse:   \"show\",\n\tShort: \"Shows info about a local provisioned kubernetes cluster\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn cli.WithContext(context.Background(), show)\n\t},\n}\n\nfunc show(ctx context.Context) error {\n\tprovisioner, err := providers.Factory(ctx, provisionerName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer provisioner.Close() //nolint:errcheck\n\n\tcluster, err := provisioner.Reflect(ctx, PersistentFlags.ClusterName, PersistentFlags.StateDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn ShowCluster(cluster)\n}\n\n// ShowCluster prints the details about the cluster to the terminal.\nfunc ShowCluster(cluster provision.Cluster) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintf(w, \"PROVISIONER\\t%s\\n\", cluster.Provisioner())\n\tfmt.Fprintf(w, \"NAME\\t%s\\n\", cluster.Info().ClusterName)\n\tfmt.Fprintf(w, \"NETWORK NAME\\t%s\\n\", cluster.Info().Network.Name)\n\n\tcidrs := xslices.Map(cluster.Info().Network.CIDRs, netip.Prefix.String)\n\n\tfmt.Fprintf(w, \"NETWORK CIDR\\t%s\\n\", strings.Join(cidrs, \",\"))\n\n\tgateways := xslices.Map(cluster.Info().Network.GatewayAddrs, netip.Addr.String)\n\n\tfmt.Fprintf(w, \"NETWORK GATEWAY\\t%s\\n\", strings.Join(gateways, \",\"))\n\tfmt.Fprintf(w, \"NETWORK MTU\\t%d\\n\", cluster.Info().Network.MTU)\n\tfmt.Fprintf(w, \"KUBERNETES ENDPOINT\\t%s\\n\", cluster.Info().KubernetesEndpoint)\n\n\tif err := w.Flush(); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprint(os.Stdout, \"\\nNODES:\\n\\n\")\n\n\tw = tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\n\tfmt.Fprintf(w, \"NAME\\tTYPE\\tIP\\tCPU\\tRAM\\tDISK\\n\")\n\n\tnodes := cluster.Info().Nodes\n\tslices.SortFunc(nodes, func(a, b provision.NodeInfo) int { return cmp.Compare(a.Name, b.Name) })\n\n\tfor _, node := range nodes {\n\t\tcpus := \"-\"\n\t\tif node.NanoCPUs > 0 {\n\t\t\tcpus = fmt.Sprintf(\"%.2f\", float64(node.NanoCPUs)/1000.0/1000.0/1000.0)\n\t\t}\n\n\t\tmem := \"-\"\n\t\tif node.Memory > 0 {\n\t\t\tmem = humanize.Bytes(uint64(node.Memory))\n\t\t}\n\n\t\tdisk := \"-\"\n\t\tif node.DiskSize > 0 {\n\t\t\tdisk = humanize.Bytes(node.DiskSize)\n\t\t}\n\n\t\tips := xslices.Map(node.IPs, netip.Addr.String)\n\n\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n\",\n\t\t\tnode.Name,\n\t\t\tnode.Type,\n\t\t\tstrings.Join(ips, \",\"),\n\t\t\tcpus,\n\t\t\tmem,\n\t\t\tdisk,\n\t\t)\n\t}\n\n\treturn w.Flush()\n}\n\nfunc init() {\n\tAddProvisionerFlag(showCmd)\n\n\tCmd.AddCommand(showCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/debug/air-gapped.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage debug\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n//go:embed httproot/*\nvar httpFs embed.FS\n\nvar airgappedFlags struct {\n\tadvertisedAddress       net.IP\n\tproxyPort               int\n\thttpsProxyPort          int\n\thttpsPort               int\n\tuseSecureProxy          bool\n\tinjectHTTPProxy         bool\n\thttpsReverseProxyPort   int\n\thttpsReverseProxyTarget string\n}\n\n// airgappedCmd represents the `gen ca` command.\nvar airgappedCmd = &cobra.Command{\n\tUse:   \"air-gapped\",\n\tShort: \"Starts a local HTTP proxy and HTTPS server serving a test manifest.\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn cli.WithContext(\n\t\t\tcontext.Background(), func(ctx context.Context) error {\n\t\t\t\tcaPEM, certPEM, keyPEM, err := helpers.GenerateSelfSignedCert([]net.IP{airgappedFlags.advertisedAddress}, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif err = generateConfigPatch(caPEM); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\teg, ctx := errgroup.WithContext(ctx)\n\n\t\t\t\teg.Go(func() error { return runHTTPServer(ctx, certPEM, keyPEM) })\n\t\t\t\teg.Go(func() error { return runHTTPProxy(ctx) })\n\t\t\t\teg.Go(func() error { return runHTTPSProxy(ctx, certPEM, keyPEM) })\n\t\t\t\teg.Go(func() error { return runHTTPSReverseProxy(ctx, certPEM, keyPEM) })\n\n\t\t\t\treturn eg.Wait()\n\t\t\t},\n\t\t)\n\t},\n}\n\nfunc generateConfigPatch(caPEM []byte) error {\n\tpatch1 := &v1alpha1.Config{\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tExtraManifests: []string{\n\t\t\t\tfmt.Sprintf(\"https://%s/debug.yaml\", net.JoinHostPort(airgappedFlags.advertisedAddress.String(), strconv.Itoa(airgappedFlags.httpsPort))),\n\t\t\t},\n\t\t},\n\t}\n\n\tpatch2 := runtime.NewEnvironmentV1Alpha1()\n\n\tif airgappedFlags.injectHTTPProxy {\n\t\tproxyURL := fmt.Sprintf(\"http://%s\", net.JoinHostPort(airgappedFlags.advertisedAddress.String(), strconv.Itoa(airgappedFlags.proxyPort)))\n\n\t\tif airgappedFlags.useSecureProxy {\n\t\t\tproxyURL = fmt.Sprintf(\"https://%s\", net.JoinHostPort(airgappedFlags.advertisedAddress.String(), strconv.Itoa(airgappedFlags.httpsProxyPort)))\n\t\t}\n\n\t\tpatch2.EnvironmentVariables = map[string]string{\n\t\t\t\"http_proxy\":  proxyURL,\n\t\t\t\"https_proxy\": proxyURL,\n\t\t\t\"no_proxy\":    fmt.Sprintf(\"%s/24\", airgappedFlags.advertisedAddress.String()),\n\t\t}\n\t}\n\n\tpatch3 := security.NewTrustedRootsConfigV1Alpha1()\n\tpatch3.MetaName = \"air-gapped-ca\"\n\tpatch3.Certificates = string(caPEM)\n\n\tctr, err := container.New(patch1, patch2, patch3)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpatchBytes, err := ctr.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconst patchFile = \"air-gapped-patch.yaml\"\n\n\tlog.Printf(\"writing config patch to %s\", patchFile)\n\n\treturn os.WriteFile(patchFile, patchBytes, 0o644)\n}\n\nfunc runHTTPServer(ctx context.Context, certPEM, keyPEM []byte) error {\n\tcertificate, err := tls.X509KeyPair(certPEM, keyPEM)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tCertificates: []tls.Certificate{certificate},\n\t}\n\n\tsubFs, err := fs.Sub(httpFs, \"httproot\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsrv := &http.Server{\n\t\tAddr:      net.JoinHostPort(\"\", strconv.Itoa(airgappedFlags.httpsPort)),\n\t\tHandler:   loggingMiddleware(http.FileServer(http.FS(subFs))),\n\t\tTLSConfig: tlsConfig,\n\t}\n\n\tlog.Printf(\"starting HTTPS server with self-signed cert on %s\", srv.Addr)\n\n\tgo srv.ListenAndServeTLS(\"\", \"\") //nolint:errcheck\n\n\t<-ctx.Done()\n\n\treturn srv.Close()\n}\n\nfunc handleTunneling(ctx context.Context, w http.ResponseWriter, r *http.Request) {\n\taddr := r.URL.Host\n\n\tdstConn, err := (&net.Dialer{Timeout: 10 * time.Second}).DialContext(ctx, \"tcp\", addr)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusServiceUnavailable)\n\n\t\treturn\n\t}\n\n\tdst := dstConn.(*net.TCPConn)\n\n\thijacker, ok := w.(http.Hijacker)\n\tif !ok {\n\t\thttp.Error(w, \"Hijacking not supported\", http.StatusInternalServerError)\n\n\t\treturn\n\t}\n\n\tclientConn, _, err := hijacker.Hijack()\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusServiceUnavailable)\n\n\t\treturn\n\t}\n\n\tvar src conn\n\n\tif src, ok = clientConn.(conn); !ok {\n\t\tif tlsConn, ok := clientConn.(*tls.Conn); ok {\n\t\t\tsrc = &tlsConnWrapper{\n\t\t\t\tConn:           tlsConn,\n\t\t\t\tcloseReadWrite: tlsConn.NetConn().(*net.TCPConn),\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\"HTTP CONNECT: tunneling to %s: failed: connection is not a net.Conn: %T\", addr, clientConn)\n\t\t\thttp.Error(w, \"Connection is not a net.Conn\", http.StatusInternalServerError)\n\n\t\t\treturn\n\t\t}\n\t}\n\n\tsrc.Write([]byte(\"HTTP/1.0 200 Connection established\\r\\n\\r\\n\")) //nolint:errcheck\n\n\tlog.Printf(\"HTTP CONNECT: tunneling to %s\", addr)\n\n\tdefer dst.Close() //nolint:errcheck\n\tdefer src.Close() //nolint:errcheck\n\n\tvar eg errgroup.Group\n\n\teg.Go(func() error { return transfer(dst, src, \"src -> dst: \"+addr) })\n\teg.Go(func() error { return transfer(src, dst, \"dst -> src: \"+addr) })\n\n\tif err = eg.Wait(); err != nil {\n\t\tlog.Printf(\"HTTP CONNECT: tunneling to %s: failed %v\", addr, err)\n\t}\n}\n\ntype conn interface {\n\tio.Reader\n\tio.Writer\n\tio.Closer\n\tCloseRead() error\n\tCloseWrite() error\n}\n\ntype tlsConnWrapper struct {\n\tnet.Conn\n\n\tcloseReadWrite *net.TCPConn\n}\n\nfunc (t *tlsConnWrapper) CloseRead() error {\n\treturn t.closeReadWrite.CloseRead()\n}\n\nfunc (t *tlsConnWrapper) CloseWrite() error {\n\treturn t.closeReadWrite.CloseWrite()\n}\n\nfunc transfer(destination conn, source conn, label string) error {\n\tdefer destination.CloseWrite() //nolint:errcheck\n\tdefer source.CloseRead()       //nolint:errcheck\n\n\tn, err := io.Copy(destination, source)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"transfer failed %s (%d bytes copied): %w\", label, n, err)\n\t}\n\n\treturn nil\n}\n\nfunc handleHTTP(w http.ResponseWriter, req *http.Request) {\n\tresp, err := http.DefaultTransport.RoundTrip(req)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusServiceUnavailable)\n\n\t\treturn\n\t}\n\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tcopyHeaders(w.Header(), resp.Header)\n\n\tw.WriteHeader(resp.StatusCode)\n\tio.Copy(w, resp.Body) //nolint:errcheck\n}\n\nfunc copyHeaders(dst, src http.Header) {\n\tfor k, vv := range src {\n\t\tfor _, v := range vv {\n\t\t\tdst.Add(k, v)\n\t\t}\n\t}\n}\n\nfunc loggingMiddleware(h http.Handler) http.Handler {\n\tlogFn := func(rw http.ResponseWriter, r *http.Request) {\n\t\th.ServeHTTP(rw, r) // serve the original request\n\n\t\tlog.Printf(\"%s %s\", r.Method, r.RequestURI)\n\t}\n\n\treturn http.HandlerFunc(logFn)\n}\n\nfunc runHTTPProxy(ctx context.Context) error {\n\tsrv := &http.Server{\n\t\tAddr: net.JoinHostPort(\"\", strconv.Itoa(airgappedFlags.proxyPort)),\n\t\tHandler: loggingMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tif r.Method == http.MethodConnect {\n\t\t\t\thandleTunneling(ctx, w, r)\n\t\t\t} else {\n\t\t\t\thandleHTTP(w, r)\n\t\t\t}\n\t\t})),\n\t\t// Disable HTTP/2.\n\t\tTLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),\n\t}\n\n\tlog.Printf(\"starting HTTP proxy on %s\", srv.Addr)\n\n\tgo srv.ListenAndServe() //nolint:errcheck\n\n\t<-ctx.Done()\n\n\treturn srv.Close()\n}\n\nfunc runHTTPSProxy(ctx context.Context, certPEM, keyPEM []byte) error {\n\tcertificate, err := tls.X509KeyPair(certPEM, keyPEM)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tCertificates: []tls.Certificate{certificate},\n\t}\n\n\tsrv := &http.Server{\n\t\tAddr: net.JoinHostPort(\"\", strconv.Itoa(airgappedFlags.httpsProxyPort)),\n\t\tHandler: loggingMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tif r.Method == http.MethodConnect {\n\t\t\t\thandleTunneling(ctx, w, r)\n\t\t\t} else {\n\t\t\t\thandleHTTP(w, r)\n\t\t\t}\n\t\t})),\n\t\t// Disable HTTP/2.\n\t\tTLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),\n\t\t// Secure\n\t\tTLSConfig: tlsConfig,\n\t}\n\n\tlog.Printf(\"starting HTTPS proxy on %s\", srv.Addr)\n\n\tgo srv.ListenAndServeTLS(\"\", \"\") //nolint:errcheck\n\n\t<-ctx.Done()\n\n\treturn srv.Close()\n}\n\nfunc runHTTPSReverseProxy(ctx context.Context, certPEM, keyPEM []byte) error {\n\tcertificate, err := tls.X509KeyPair(certPEM, keyPEM)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tCertificates: []tls.Certificate{certificate},\n\t}\n\n\ttarget, err := url.Parse(airgappedFlags.httpsReverseProxyTarget)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing reverse proxy target %q: %w\", airgappedFlags.httpsReverseProxyTarget, err)\n\t}\n\n\treverseProxy := httputil.NewSingleHostReverseProxy(target)\n\n\tsrv := &http.Server{\n\t\tAddr:    net.JoinHostPort(\"\", strconv.Itoa(airgappedFlags.httpsReverseProxyPort)),\n\t\tHandler: loggingMiddleware(reverseProxy),\n\t\t// Secure\n\t\tTLSConfig: tlsConfig,\n\t}\n\n\tlog.Printf(\"starting HTTPS reverse proxy on %s to %s\", srv.Addr, target.String())\n\n\tgo srv.ListenAndServeTLS(\"\", \"\") //nolint:errcheck\n\n\t<-ctx.Done()\n\n\treturn srv.Close()\n}\n\nfunc init() {\n\tairgappedCmd.Flags().IPVar(&airgappedFlags.advertisedAddress, \"advertised-address\", net.IPv4(10, 5, 0, 2), \"The address to advertise to the cluster.\")\n\tairgappedCmd.Flags().IntVar(&airgappedFlags.httpsPort, \"https-port\", 8001, \"The HTTPS server port.\")\n\tairgappedCmd.Flags().IntVar(&airgappedFlags.proxyPort, \"proxy-port\", 8002, \"The HTTP proxy port.\")\n\tairgappedCmd.Flags().IntVar(&airgappedFlags.httpsProxyPort, \"https-proxy-port\", 8003, \"The HTTPS proxy port.\")\n\tairgappedCmd.Flags().BoolVar(&airgappedFlags.useSecureProxy, \"use-secure-proxy\", false, \"Whether to use HTTPS proxy.\")\n\tairgappedCmd.Flags().BoolVar(&airgappedFlags.injectHTTPProxy, \"inject-http-proxy\", true, \"Whether to inject HTTP proxy configuration.\")\n\tairgappedCmd.Flags().IntVar(&airgappedFlags.httpsReverseProxyPort, \"https-reverse-proxy-port\", 8004, \"The HTTPS reverse proxy port.\")\n\tairgappedCmd.Flags().StringVar(&airgappedFlags.httpsReverseProxyTarget, \"https-reverse-proxy-target\", \"http://localhost/\", \"The HTTPS reverse proxy target (URL).\")\n\n\tCmd.AddCommand(airgappedCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/debug/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package debug implements \"debug\" subcommands.\npackage debug\n\nimport (\n\t\"github.com/spf13/cobra\"\n)\n\n// Cmd represents the debug command.\nvar Cmd = &cobra.Command{\n\tUse:    \"debug-tool\",\n\tShort:  \"A collection of commands to facilitate debugging of Talos.\",\n\tHidden: true,\n\tLong:   ``,\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/debug/httproot/debug.yaml",
    "content": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    app: debug-container\n  name: debug-container\n  namespace: default\nspec:\n  selector:\n    matchLabels:\n      app: debug-container\n  template:\n    metadata:\n      labels:\n        app: debug-container\n    spec:\n      containers:\n      - args:\n        - \"inf\"\n        command:\n        - /bin/sleep\n        image: alpine:latest\n        imagePullPolicy: IfNotPresent\n        name: debug-container\n        resources: {}\n      terminationGracePeriodSeconds: 30\n  updateStrategy:\n    rollingUpdate:\n      maxSurge: 0\n      maxUnavailable: 1\n    type: RollingUpdate\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/dhcpd_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage mgmt\n\nimport (\n\t\"net\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\nvar dhcpdLaunchCmdFlags struct {\n\taddr            string\n\tifName          string\n\tstatePath       string\n\tipxeNextHandler string\n}\n\n// dhcpdLaunchCmd represents the dhcpd-launch command.\nvar dhcpdLaunchCmd = &cobra.Command{\n\tUse:    \"dhcpd-launch\",\n\tShort:  \"Internal command used by VM provisioners\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tips := xslices.Map(slices.Collect(strings.SplitSeq(dhcpdLaunchCmdFlags.addr, \",\")), net.ParseIP)\n\n\t\tvar eg errgroup.Group\n\n\t\teg.Go(func() error {\n\t\t\treturn vm.DHCPd(dhcpdLaunchCmdFlags.ifName, ips, dhcpdLaunchCmdFlags.statePath)\n\t\t})\n\n\t\tif dhcpdLaunchCmdFlags.ipxeNextHandler != \"\" {\n\t\t\teg.Go(func() error {\n\t\t\t\treturn vm.TFTPd(ips, dhcpdLaunchCmdFlags.ipxeNextHandler)\n\t\t\t})\n\t\t}\n\n\t\treturn eg.Wait()\n\t},\n}\n\nfunc init() {\n\tdhcpdLaunchCmd.Flags().StringVar(&dhcpdLaunchCmdFlags.addr, \"addr\", \"localhost\", \"IP addresses to listen on\")\n\tdhcpdLaunchCmd.Flags().StringVar(&dhcpdLaunchCmdFlags.ifName, \"interface\", \"\", \"interface to listen on\")\n\tdhcpdLaunchCmd.Flags().StringVar(&dhcpdLaunchCmdFlags.statePath, \"state-path\", \"\", \"path to state directory\")\n\tdhcpdLaunchCmd.Flags().StringVar(&dhcpdLaunchCmdFlags.ipxeNextHandler, \"ipxe-next-handler\", \"\", \"iPXE script to chain load\")\n\taddCommand(dhcpdLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/dnsd_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage mgmt\n\nimport (\n\t\"net\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\nvar dnsdLaunchCmdFlags struct {\n\taddr       string\n\tresolvConf string\n}\n\n// dnsdLaunchCmd represents the dnsd-launch command.\nvar dnsdLaunchCmd = &cobra.Command{\n\tUse:    \"dnsd-launch\",\n\tShort:  \"Internal command used by VM provisioners\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tips := xslices.Map(slices.Collect(strings.SplitSeq(dnsdLaunchCmdFlags.addr, \",\")), net.ParseIP)\n\n\t\tvar eg errgroup.Group\n\n\t\teg.Go(func() error {\n\t\t\treturn vm.DNSd(ips, dnsdLaunchCmdFlags.resolvConf)\n\t\t})\n\n\t\treturn eg.Wait()\n\t},\n}\n\nfunc init() {\n\tdnsdLaunchCmd.Flags().StringVar(&dnsdLaunchCmdFlags.addr, \"addr\", \"localhost:53\", \"IP addresses to listen on\")\n\tdnsdLaunchCmd.Flags().StringVar(&dnsdLaunchCmdFlags.resolvConf, \"resolv-conf\", \"/etc/resolv.conf\", \"path to resolv file\")\n\taddCommand(dnsdLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/ca.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package gen implements the genration of various artifacts.\npackage gen\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n)\n\nvar genCACmdFlags struct {\n\torganization string\n\thours        int\n\trsa          bool\n}\n\n// genCACmd represents the `gen ca` command.\nvar genCACmd = &cobra.Command{\n\tUse:   \"ca\",\n\tShort: \"Generates a self-signed X.509 certificate authority\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\topts := []x509.Option{x509.RSA(genCACmdFlags.rsa)}\n\t\tif genCACmdFlags.organization != \"\" {\n\t\t\topts = append(opts, x509.Organization(genCACmdFlags.organization))\n\t\t}\n\n\t\topts = append(opts, x509.NotAfter(time.Now().Add(time.Duration(genCACmdFlags.hours)*time.Hour)))\n\n\t\tca, err := x509.NewSelfSignedCertificateAuthority(opts...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating CA: %w\", err)\n\t\t}\n\n\t\tcaCertFile := genCACmdFlags.organization + crtExt\n\t\tcaHashFile := genCACmdFlags.organization + \".sha256\"\n\t\tcaKeyFile := genCACmdFlags.organization + keyExt\n\n\t\tif err := validateFilesExists([]string{caCertFile, caHashFile, caKeyFile}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(caCertFile, ca.CrtPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing CA certificate: %w\", err)\n\t\t}\n\n\t\tif err := os.WriteFile(caHashFile, []byte(x509.Hash(ca.Crt)), 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing certificate hash: %w\", err)\n\t\t}\n\n\t\tif err := os.WriteFile(caKeyFile, ca.KeyPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing key: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tgenCACmd.Flags().StringVar(&genCACmdFlags.organization, \"organization\", \"\", \"X.509 distinguished name for the Organization\")\n\tcli.Should(cobra.MarkFlagRequired(genCACmd.Flags(), \"organization\"))\n\tgenCACmd.Flags().IntVar(&genCACmdFlags.hours, \"hours\", 87600, \"the hours from now on which the certificate validity period ends\")\n\tgenCACmd.Flags().BoolVar(&genCACmdFlags.rsa, \"rsa\", false, \"generate in RSA format\")\n\n\tCmd.AddCommand(genCACmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tsideronet \"github.com/siderolabs/net\"\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tcontrolPlaneOutputType = \"controlplane\"\n\tworkerOutputType       = \"worker\"\n\ttalosconfigOutputType  = \"talosconfig\"\n\n\tstdoutOutput = \"-\"\n\n\tyamlExt = \".yaml\"\n)\n\nvar allOutputTypes = []string{\n\tcontrolPlaneOutputType,\n\tworkerOutputType,\n\ttalosconfigOutputType,\n}\n\ntype configOutputPaths struct {\n\tcontrolPlane, worker, talosconfig string\n}\n\nvar genConfigCmdFlags struct {\n\tadditionalSANs    []string\n\tconfigVersion     string\n\tdnsDomain         string\n\tkubernetesVersion string\n\ttalosVersion      string\n\tinstallDisk       string\n\tinstallImage      string\n\n\t// outputDir is a hidden flag kept for backwards compatibility\n\toutputDir string\n\n\toutput                  string\n\toutputTypes             []string\n\tconfigPatch             []string\n\tconfigPatchControlPlane []string\n\tconfigPatchWorker       []string\n\tregistryMirrors         []string\n\twithExamples            bool\n\twithDocs                bool\n\twithClusterDiscovery    bool\n\twithKubeSpan            bool\n\twithSecrets             string\n}\n\n// NewConfigCmd builds the config generation subcommand with the given name.\nfunc NewConfigCmd(name string) *cobra.Command {\n\treturn &cobra.Command{\n\t\tUse:   fmt.Sprintf(\"%s <cluster name> <cluster endpoint>\", name),\n\t\tShort: \"Generates a set of configuration files for Talos cluster\",\n\t\tLong: `The cluster endpoint is the URL for the Kubernetes API. If you decide to use\na control plane node, common in a single node control plane setup, use port 6443 as\nthis is the port that the API server binds to on every control plane node. For an HA\nsetup, usually involving a load balancer, use the IP and port of the load balancer.`,\n\t\tArgs: cobra.ExactArgs(2),\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\terr := validateClusterEndpoint(args[1])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tswitch genConfigCmdFlags.configVersion {\n\t\t\tcase \"v1alpha1\":\n\t\t\t\treturn writeConfig(args)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown config version: %q\", genConfigCmdFlags.configVersion)\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunc fixControlPlaneEndpoint(u *url.URL) *url.URL {\n\t// handle the case when the hostname/IP is given without the port, it parses as URL Path\n\tif u.Scheme == \"\" && u.Host == \"\" && u.Path != \"\" {\n\t\tu.Host = u.Path\n\t\tu.Path = \"\"\n\t}\n\n\tu.Scheme = \"https\"\n\n\tif u.Port() == \"\" {\n\t\tu.Host = fmt.Sprintf(\"%s:%d\", u.Host, constants.DefaultControlPlanePort)\n\t}\n\n\treturn u\n}\n\n// GenerateConfigBundle generates the Talos config bundle\n//\n// GenerateConfigBundle is useful for integration with external tooling options.\nfunc GenerateConfigBundle(genOptions []generate.Option,\n\tclusterName string,\n\tendpoint string,\n\tkubernetesVersion string,\n\tconfigPatch []string,\n\tconfigPatchControlPlane []string,\n\tconfigPatchWorker []string,\n) (*bundle.Bundle, error) {\n\tconfigBundleOpts := []bundle.Option{\n\t\tbundle.WithInputOptions(\n\t\t\t&bundle.InputOptions{\n\t\t\t\tClusterName: clusterName,\n\t\t\t\tEndpoint:    endpoint,\n\t\t\t\tKubeVersion: strings.TrimPrefix(kubernetesVersion, \"v\"),\n\t\t\t\tGenOptions:  genOptions,\n\t\t\t},\n\t\t),\n\t}\n\n\taddConfigPatch := func(configPatches []string, configOpt func([]configpatcher.Patch) bundle.Option) error {\n\t\tpatches, err := configpatcher.LoadPatches(configPatches)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing config JSON patch: %w\", err)\n\t\t}\n\n\t\tconfigBundleOpts = append(configBundleOpts, configOpt(patches))\n\n\t\treturn nil\n\t}\n\tif err := addConfigPatch(configPatch, bundle.WithPatch); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := addConfigPatch(configPatchControlPlane, bundle.WithPatchControlPlane); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := addConfigPatch(configPatchWorker, bundle.WithPatchWorker); err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfigBundle, err := bundle.NewBundle(configBundleOpts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate config bundle: %w\", err)\n\t}\n\n\treturn configBundle, nil\n}\n\n//nolint:gocyclo\nfunc writeConfig(args []string) error {\n\tif err := validateFlags(); err != nil {\n\t\treturn err\n\t}\n\n\tpaths, err := outputPaths()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar genOptions []generate.Option //nolint:prealloc\n\n\tfor _, registryMirror := range genConfigCmdFlags.registryMirrors {\n\t\tleft, right, ok := strings.Cut(registryMirror, \"=\")\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"invalid registry mirror spec: %q\", registryMirror)\n\t\t}\n\n\t\tgenOptions = append(genOptions, generate.WithRegistryMirror(left, right))\n\t}\n\n\tif genConfigCmdFlags.talosVersion != \"\" {\n\t\tvar versionContract *config.VersionContract\n\n\t\tversionContract, err = config.ParseContractFromVersion(genConfigCmdFlags.talosVersion)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid talos-version: %w\", err)\n\t\t}\n\n\t\tgenOptions = append(genOptions, generate.WithVersionContract(versionContract))\n\t}\n\n\t// Add KubeSpan configuration based on version\n\tif genConfigCmdFlags.withKubeSpan {\n\t\tgenOptions = append(genOptions,\n\t\t\tgenerate.WithKubeSpanEnabled(genConfigCmdFlags.withKubeSpan),\n\t\t)\n\t}\n\n\tif genConfigCmdFlags.withSecrets != \"\" {\n\t\tvar secretsBundle *secrets.Bundle\n\n\t\tsecretsBundle, err = secrets.LoadBundle(genConfigCmdFlags.withSecrets)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load secrets bundle: %w\", err)\n\t\t}\n\n\t\tif err = secretsBundle.Validate(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to validate secrets bundle: %w\", err)\n\t\t}\n\n\t\tgenOptions = append(genOptions, generate.WithSecretsBundle(secretsBundle))\n\t}\n\n\tgenOptions = append(genOptions,\n\t\tgenerate.WithInstallDisk(genConfigCmdFlags.installDisk),\n\t\tgenerate.WithInstallImage(genConfigCmdFlags.installImage),\n\t\tgenerate.WithAdditionalSubjectAltNames(genConfigCmdFlags.additionalSANs),\n\t\tgenerate.WithDNSDomain(genConfigCmdFlags.dnsDomain),\n\t\tgenerate.WithClusterDiscovery(genConfigCmdFlags.withClusterDiscovery),\n\t)\n\n\tcommentsFlags := encoder.CommentsDisabled\n\tif genConfigCmdFlags.withDocs {\n\t\tcommentsFlags |= encoder.CommentsDocs\n\t}\n\n\tif genConfigCmdFlags.withExamples {\n\t\tcommentsFlags |= encoder.CommentsExamples\n\t}\n\n\tconfigBundle, err := GenerateConfigBundle(\n\t\tgenOptions,\n\t\targs[0],\n\t\targs[1],\n\t\tgenConfigCmdFlags.kubernetesVersion,\n\t\tgenConfigCmdFlags.configPatch,\n\t\tgenConfigCmdFlags.configPatchControlPlane,\n\t\tgenConfigCmdFlags.configPatchWorker)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn writeConfigBundle(configBundle, paths, commentsFlags)\n}\n\nfunc validateFlags() error {\n\tif len(genConfigCmdFlags.outputTypes) == 0 {\n\t\treturn errors.New(\"at least one output type must be specified\")\n\t}\n\n\tif len(genConfigCmdFlags.outputTypes) > 1 && genConfigCmdFlags.output == stdoutOutput {\n\t\treturn errors.New(\"can't use multiple output types with stdout\")\n\t}\n\n\tif genConfigCmdFlags.outputDir != \"\" && genConfigCmdFlags.output != \"\" {\n\t\treturn errors.New(\"can't use both output-dir and output\")\n\t}\n\n\tif genConfigCmdFlags.outputDir != \"\" {\n\t\tgenConfigCmdFlags.output = genConfigCmdFlags.outputDir\n\t}\n\n\tvar err error\n\n\tfor _, outputType := range genConfigCmdFlags.outputTypes {\n\t\tif !slices.ContainsFunc(allOutputTypes, func(t string) bool {\n\t\t\treturn t == outputType\n\t\t}) {\n\t\t\terr = multierror.Append(err, fmt.Errorf(\"invalid output type: %q\", outputType))\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc writeConfigBundle(configBundle *bundle.Bundle, outputPaths configOutputPaths, commentsFlags encoder.CommentsFlags) error {\n\toutputTypesSet := xslices.ToSet(genConfigCmdFlags.outputTypes)\n\n\tif _, ok := outputTypesSet[controlPlaneOutputType]; ok {\n\t\tdata, err := configBundle.Serialize(commentsFlags, machine.TypeControlPlane)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = writeToDestination(data, outputPaths.controlPlane, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif _, ok := outputTypesSet[workerOutputType]; ok {\n\t\tdata, err := configBundle.Serialize(commentsFlags, machine.TypeWorker)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = writeToDestination(data, outputPaths.worker, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif _, ok := outputTypesSet[talosconfigOutputType]; ok {\n\t\tdata, err := yaml.Marshal(configBundle.TalosConfig())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to marshal config: %+v\", err)\n\t\t}\n\n\t\tif err = writeToDestination(data, outputPaths.talosconfig, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc writeToDestination(data []byte, destination string, permissions os.FileMode) error {\n\tif destination == stdoutOutput {\n\t\t_, err := os.Stdout.Write(data)\n\n\t\treturn err\n\t}\n\n\tif err := validateFileExists(destination); err != nil {\n\t\treturn err\n\t}\n\n\tparentDir := filepath.Dir(destination)\n\n\t// Create dir path, ignoring \"already exists\" messages\n\tif err := os.MkdirAll(parentDir, os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"failed to create output dir: %w\", err)\n\t}\n\n\terr := os.WriteFile(destination, data, permissions)\n\n\tfmt.Fprintf(os.Stderr, \"Created %s\\n\", destination)\n\n\treturn err\n}\n\nfunc outputPaths() (configOutputPaths, error) {\n\t// output to stdout\n\tif genConfigCmdFlags.output == stdoutOutput {\n\t\treturn configOutputPaths{controlPlane: stdoutOutput, worker: stdoutOutput, talosconfig: stdoutOutput}, nil\n\t}\n\n\t// output is not specified - use current working directory as the default\n\tif genConfigCmdFlags.output == \"\" {\n\t\tcwd, err := os.Getwd()\n\t\tif err != nil {\n\t\t\treturn configOutputPaths{}, err\n\t\t}\n\n\t\tcontrolPlane := filepath.Join(cwd, machine.TypeControlPlane.String()+yamlExt)\n\t\tworker := filepath.Join(cwd, machine.TypeWorker.String()+yamlExt)\n\t\ttalosconfig := filepath.Join(cwd, \"talosconfig\")\n\n\t\treturn configOutputPaths{controlPlane: controlPlane, worker: worker, talosconfig: talosconfig}, nil\n\t}\n\n\t// output is specified\n\n\t// if a single output type is specified, treat --output as a file path and not a directory\n\t// except when the deprecated flag of --output-dir is specified - it is always treated as a directory\n\tif len(genConfigCmdFlags.outputTypes) == 1 && genConfigCmdFlags.outputDir == \"\" { // specified output is a file\n\t\treturn configOutputPaths{\n\t\t\tcontrolPlane: genConfigCmdFlags.output,\n\t\t\tworker:       genConfigCmdFlags.output,\n\t\t\ttalosconfig:  genConfigCmdFlags.output,\n\t\t}, nil\n\t}\n\n\t// treat --output as a directory\n\tcontrolPlane := filepath.Join(genConfigCmdFlags.output, machine.TypeControlPlane.String()+yamlExt)\n\tworker := filepath.Join(genConfigCmdFlags.output, machine.TypeWorker.String()+yamlExt)\n\ttalosconfig := filepath.Join(genConfigCmdFlags.output, \"talosconfig\")\n\n\treturn configOutputPaths{controlPlane: controlPlane, worker: worker, talosconfig: talosconfig}, nil\n}\n\nfunc validateClusterEndpoint(endpoint string) error {\n\t// Validate url input to ensure it has https:// scheme before we attempt to gen\n\tu, err := url.Parse(endpoint)\n\tif err != nil {\n\t\tif !strings.Contains(endpoint, \"/\") {\n\t\t\t// not a URL, could be just host:port\n\t\t\tu = &url.URL{\n\t\t\t\tHost: endpoint,\n\t\t\t}\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"failed to parse the cluster endpoint URL: %w\", err)\n\t\t}\n\t}\n\n\tif u.Scheme == \"\" {\n\t\tif u.Port() == \"\" {\n\t\t\treturn fmt.Errorf(\"no scheme and port specified for the cluster endpoint URL\\ntry: %q\", fixControlPlaneEndpoint(u))\n\t\t}\n\n\t\treturn fmt.Errorf(\"no scheme specified for the cluster endpoint URL\\ntry: %q\", fixControlPlaneEndpoint(u))\n\t}\n\n\tif u.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"the control plane endpoint URL should have scheme https://\\ntry: %q\", fixControlPlaneEndpoint(u))\n\t}\n\n\tif err = sideronet.ValidateEndpointURI(endpoint); err != nil {\n\t\treturn fmt.Errorf(\"error validating the cluster endpoint URL: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tgenConfigCmd := NewConfigCmd(\"config\")\n\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.installDisk, \"install-disk\", \"/dev/sda\", \"the disk to install to\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.installImage, \"install-image\", helpers.DefaultImage(images.DefaultInstallerImageRepository), \"the image used to perform an installation\")\n\tgenConfigCmd.Flags().StringSliceVar(&genConfigCmdFlags.additionalSANs, \"additional-sans\", []string{}, \"additional Subject-Alt-Names for the APIServer certificate\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.dnsDomain, \"dns-domain\", \"cluster.local\", \"the dns domain to use for cluster\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.configVersion, \"version\", \"v1alpha1\", \"the desired machine config version to generate\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.talosVersion, \"talos-version\", \"\", \"the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.kubernetesVersion, \"kubernetes-version\", constants.DefaultKubernetesVersion, \"desired kubernetes version to run\")\n\tgenConfigCmd.Flags().StringArrayVar(&genConfigCmdFlags.configPatch, \"config-patch\", nil, \"patch generated machineconfigs (applied to all node types), use @file to read a patch from file\")\n\tgenConfigCmd.Flags().StringArrayVar(&genConfigCmdFlags.configPatchControlPlane, \"config-patch-control-plane\", nil, \"patch generated machineconfigs (applied to 'init' and 'controlplane' types)\")\n\tgenConfigCmd.Flags().StringArrayVar(&genConfigCmdFlags.configPatchWorker, \"config-patch-worker\", nil, \"patch generated machineconfigs (applied to 'worker' type)\")\n\tgenConfigCmd.Flags().StringSliceVar(&genConfigCmdFlags.registryMirrors, \"registry-mirror\", []string{}, \"list of registry mirrors to use in format: <registry host>=<mirror URL>\")\n\tgenConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withExamples, \"with-examples\", \"\", true, \"renders all machine configs with the commented examples\")\n\tgenConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withDocs, \"with-docs\", \"\", true, \"renders all machine configs adding the documentation for each field\")\n\tgenConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withClusterDiscovery, \"with-cluster-discovery\", \"\", true, \"enable cluster discovery feature\")\n\tgenConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withKubeSpan, \"with-kubespan\", \"\", false, \"enable KubeSpan feature\")\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.withSecrets, \"with-secrets\", \"\", \"use a secrets file generated using 'gen secrets'\")\n\n\tgenConfigCmd.Flags().StringSliceVarP(&genConfigCmdFlags.outputTypes, \"output-types\", \"t\", allOutputTypes, fmt.Sprintf(\"types of outputs to be generated. valid types are: %q\", allOutputTypes))\n\tgenConfigCmd.Flags().StringVarP(&genConfigCmdFlags.output, \"output\", \"o\", \"\",\n\t\t`destination to output generated files. when multiple output types are specified, it must be a directory. for a single output type, it must either be a file path, or \"-\" for stdout`)\n\tgenConfigCmd.Flags().StringVar(&genConfigCmdFlags.outputDir, \"output-dir\", \"\", \"destination to output generated files\") // kept for backwards compatibility\n\tgenConfigCmd.Flags().MarkHidden(\"output-dir\")                                                                           //nolint:errcheck\n\n\tCmd.AddCommand(genConfigCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/crt.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n)\n\nvar genCrtCmdFlags struct {\n\tname  string\n\tca    string\n\tcsr   string\n\thours int\n}\n\n// genCrtCmd represents the `gen crt` command.\nvar genCrtCmd = &cobra.Command{\n\tUse:   \"crt\",\n\tShort: \"Generates an X.509 Ed25519 certificate\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tcaBytes, err := os.ReadFile(genCrtCmdFlags.ca + crtExt)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading CA cert: %s\", err)\n\t\t}\n\n\t\tcaPemBlock, _ := pem.Decode(caBytes)\n\t\tif caPemBlock == nil {\n\t\t\treturn errors.New(\"error decoding cert PEM\")\n\t\t}\n\n\t\tcaCrt, err := stdlibx509.ParseCertificate(caPemBlock.Bytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing cert: %s\", err)\n\t\t}\n\n\t\tkeyBytes, err := os.ReadFile(genCrtCmdFlags.ca + keyExt)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading key file: %s\", err)\n\t\t}\n\n\t\tkeyPemBlock, _ := pem.Decode(keyBytes)\n\t\tif keyPemBlock == nil {\n\t\t\treturn errors.New(\"error decoding key PEM\")\n\t\t}\n\n\t\tcaKey, err := stdlibx509.ParsePKCS8PrivateKey(keyPemBlock.Bytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing EC key: %s\", err)\n\t\t}\n\n\t\tcsrBytes, err := os.ReadFile(genCrtCmdFlags.csr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading CSR: %s\", err)\n\t\t}\n\n\t\tcsrPemBlock, _ := pem.Decode(csrBytes)\n\t\tif csrPemBlock == nil {\n\t\t\treturn errors.New(\"error parsing CSR PEM\")\n\t\t}\n\n\t\tccsr, err := stdlibx509.ParseCertificateRequest(csrPemBlock.Bytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing CSR: %s\", err)\n\t\t}\n\n\t\tsignedCrt, err := x509.NewCertificateFromCSR(caCrt, caKey, ccsr,\n\t\t\tx509.NotAfter(time.Now().Add(time.Duration(genCrtCmdFlags.hours)*time.Hour)),\n\t\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature),\n\t\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error signing certificate: %s\", err)\n\t\t}\n\n\t\tcertFile := genCrtCmdFlags.name + crtExt\n\n\t\tif err = validateFileExists(certFile); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = os.WriteFile(certFile, signedCrt.X509CertificatePEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing certificate: %s\", err)\n\t\t}\n\n\t\treturn err\n\t},\n}\n\nfunc init() {\n\tgenCrtCmd.Flags().StringVar(&genCrtCmdFlags.name, \"name\", \"\", \"the basename of the generated file\")\n\tcli.Should(cobra.MarkFlagRequired(genCrtCmd.Flags(), \"name\"))\n\tgenCrtCmd.Flags().StringVar(&genCrtCmdFlags.ca, \"ca\", \"\", \"path to the PEM encoded CERTIFICATE\")\n\tcli.Should(cobra.MarkFlagRequired(genCrtCmd.Flags(), \"ca\"))\n\tgenCrtCmd.Flags().StringVar(&genCrtCmdFlags.csr, \"csr\", \"\", \"path to the PEM encoded CERTIFICATE REQUEST\")\n\tcli.Should(cobra.MarkFlagRequired(genCrtCmd.Flags(), \"csr\"))\n\tgenCrtCmd.Flags().IntVar(&genCrtCmdFlags.hours, \"hours\", 24, \"the hours from now on which the certificate validity period ends\")\n\n\tCmd.AddCommand(genCrtCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/csr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nvar genCSRCmdFlags struct {\n\tkey   string\n\tip    string\n\troles []string\n}\n\n// genCSRCmd represents the `gen csr` command.\nvar genCSRCmd = &cobra.Command{\n\tUse:   \"csr\",\n\tShort: \"Generates a CSR using an Ed25519 private key\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tkeyBytes, err := os.ReadFile(genCSRCmdFlags.key)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading key: %s\", err)\n\t\t}\n\n\t\tpemBlock, _ := pem.Decode(keyBytes)\n\t\tif pemBlock == nil {\n\t\t\treturn errors.New(\"error decoding PEM\")\n\t\t}\n\n\t\tkeyEC, err := stdlibx509.ParsePKCS8PrivateKey(pemBlock.Bytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing ECDSA key: %s\", err)\n\t\t}\n\n\t\tvar opts []x509.Option //nolint:prealloc // dynamic\n\n\t\tparsed := net.ParseIP(genCSRCmdFlags.ip)\n\t\tif parsed == nil {\n\t\t\treturn fmt.Errorf(\"invalid IP: %s\", genCSRCmdFlags.ip)\n\t\t}\n\n\t\troles, unknownRoles := role.Parse(genCSRCmdFlags.roles)\n\t\tif len(unknownRoles) != 0 {\n\t\t\treturn fmt.Errorf(\"unknown roles: %s\", strings.Join(unknownRoles, \", \"))\n\t\t}\n\n\t\tips := []net.IP{parsed}\n\n\t\topts = append(opts, x509.Organization(roles.Strings()...))\n\t\topts = append(opts, x509.IPAddresses(ips))\n\n\t\tcsr, err := x509.NewCertificateSigningRequest(keyEC, opts...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating CSR: %s\", err)\n\t\t}\n\n\t\tcsrFile := strings.TrimSuffix(genCSRCmdFlags.key, path.Ext(genCSRCmdFlags.key)) + \".csr\"\n\n\t\tif err := validateFileExists(csrFile); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(csrFile, csr.X509CertificateRequestPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing CSR: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tgenCSRCmd.Flags().StringVar(&genCSRCmdFlags.key, \"key\", \"\", \"path to the PEM encoded EC or RSA PRIVATE KEY\")\n\tcli.Should(cobra.MarkFlagRequired(genCSRCmd.Flags(), \"key\"))\n\tgenCSRCmd.Flags().StringVar(&genCSRCmdFlags.ip, \"ip\", \"\", \"generate the certificate for this IP address\")\n\tcli.Should(cobra.MarkFlagRequired(genCSRCmd.Flags(), \"ip\"))\n\tgenCSRCmd.Flags().StringSliceVar(&genCSRCmdFlags.roles, \"roles\", role.MakeSet(role.Admin).Strings(), \"roles\")\n\n\tCmd.AddCommand(genCSRCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/gen.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/spf13/cobra\"\n)\n\nconst (\n\tcrtExt = \".crt\"\n\tkeyExt = \".key\"\n)\n\nvar genCmdFlags struct {\n\tforce bool\n}\n\n// Cmd represents the `gen` command.\nvar Cmd = &cobra.Command{\n\tUse:   \"gen\",\n\tShort: \"Generate CAs, certificates, and private keys\",\n\tLong:  ``,\n}\n\nfunc init() {\n\tCmd.PersistentFlags().BoolVarP(&genCmdFlags.force, \"force\", \"f\", false, \"will overwrite existing files\")\n}\n\nfunc validateFileExists(file string) error {\n\tif !genCmdFlags.force {\n\t\tif _, err := os.Stat(file); err == nil {\n\t\t\treturn fmt.Errorf(\"file %q already exists, use --force to overwrite\", file)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc validateFilesExists(files []string) error {\n\tvar combinedErr multierror.Error\n\n\tfor _, file := range files {\n\t\tif err := validateFileExists(file); err != nil {\n\t\t\tcombinedErr.Errors = append(combinedErr.Errors, err)\n\t\t}\n\t}\n\n\treturn combinedErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/key.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n)\n\nvar genKeyCmdFlags struct {\n\tname string\n}\n\n// genKeyCmd represents the `gen key` command.\nvar genKeyCmd = &cobra.Command{\n\tUse:   \"key\",\n\tShort: \"Generates an Ed25519 private key\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tkey, err := x509.NewEd25519Key()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating key: %w\", err)\n\t\t}\n\n\t\tkeyFile := genKeyCmdFlags.name + keyExt\n\n\t\tif err = validateFileExists(keyFile); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(keyFile, key.PrivateKeyPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing key: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tgenKeyCmd.Flags().StringVar(&genKeyCmdFlags.name, \"name\", \"\", \"the basename of the generated file\")\n\tcli.Should(cobra.MarkFlagRequired(genKeyCmd.Flags(), \"name\"))\n\n\tCmd.AddCommand(genKeyCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/keypair.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n)\n\nvar genKeypairCmdFlags struct {\n\tip           string\n\torganization string\n}\n\nvar genKeypairCmd = &cobra.Command{\n\tUse:   \"keypair\",\n\tShort: \"Generates an X.509 Ed25519 key pair\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tvar opts []x509.Option\n\n\t\tif genKeypairCmdFlags.ip != \"\" {\n\t\t\tparsed := net.ParseIP(genKeypairCmdFlags.ip)\n\t\t\tif parsed == nil {\n\t\t\t\treturn fmt.Errorf(\"invalid IP: %s\", genKeypairCmdFlags.ip)\n\t\t\t}\n\n\t\t\tips := []net.IP{parsed}\n\t\t\topts = append(opts, x509.IPAddresses(ips))\n\t\t}\n\n\t\tif genKeypairCmdFlags.organization != \"\" {\n\t\t\topts = append(opts, x509.Organization(genKeypairCmdFlags.organization))\n\t\t}\n\n\t\tca, err := x509.NewSelfSignedCertificateAuthority(opts...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating CA: %s\", err)\n\t\t}\n\n\t\tcertFile := genKeypairCmdFlags.organization + crtExt\n\t\tkeyFile := genKeypairCmdFlags.organization + keyExt\n\n\t\tif err = validateFilesExists([]string{certFile, keyFile}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(certFile, ca.CrtPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing certificate: %s\", err)\n\t\t}\n\n\t\tif err := os.WriteFile(keyFile, ca.KeyPEM, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing key: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tgenKeypairCmd.Flags().StringVar(&genKeypairCmdFlags.ip, \"ip\", \"\", \"generate the certificate for this IP address\")\n\tgenKeypairCmd.Flags().StringVar(&genKeypairCmdFlags.organization, \"organization\", \"\", \"X.509 distinguished name for the Organization\")\n\tcli.Should(cobra.MarkFlagRequired(genKeypairCmd.Flags(), \"organization\"))\n\n\tCmd.AddCommand(genKeypairCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/secrets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n)\n\nvar genSecretsCmdFlags struct {\n\toutputFile               string\n\ttalosVersion             string\n\tfromKubernetesPki        string\n\tfromControlplaneConfig   string\n\tkubernetesBootstrapToken string\n}\n\n// genSecretsCmd represents the `gen secrets` command.\nvar genSecretsCmd = &cobra.Command{\n\tUse:   \"secrets\",\n\tShort: \"Generates a secrets bundle file which can later be used to generate a config\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tvar (\n\t\t\tsecretsBundle   *secrets.Bundle\n\t\t\tversionContract *config.VersionContract\n\t\t\terr             error\n\t\t)\n\n\t\tif genSecretsCmdFlags.talosVersion != \"\" {\n\t\t\tversionContract, err = config.ParseContractFromVersion(genSecretsCmdFlags.talosVersion)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid talos-version: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase genSecretsCmdFlags.fromKubernetesPki != \"\":\n\t\t\tsecretsBundle, err = secrets.NewBundleFromKubernetesPKI(genSecretsCmdFlags.fromKubernetesPki,\n\t\t\t\tgenSecretsCmdFlags.kubernetesBootstrapToken, versionContract)\n\t\tcase genSecretsCmdFlags.fromControlplaneConfig != \"\":\n\t\t\tvar cfg config.Provider\n\n\t\t\tcfg, err = configloader.NewFromFile(genSecretsCmdFlags.fromControlplaneConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to load controlplane config: %w\", err)\n\t\t\t}\n\n\t\t\tsecretsBundle = secrets.NewBundleFromConfig(secrets.NewFixedClock(time.Now()), cfg)\n\t\tdefault:\n\t\t\tsecretsBundle, err = secrets.NewBundle(secrets.NewFixedClock(time.Now()),\n\t\t\t\tversionContract,\n\t\t\t)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create secrets bundle: %w\", err)\n\t\t}\n\n\t\treturn writeSecretsBundleToFile(secretsBundle)\n\t},\n}\n\nfunc writeSecretsBundleToFile(bundle *secrets.Bundle) error {\n\tbundleBytes, err := yaml.Marshal(bundle)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif genSecretsCmdFlags.outputFile == stdoutOutput {\n\t\t_, err = os.Stdout.Write(bundleBytes)\n\n\t\treturn err\n\t}\n\n\tif err = validateFileExists(genSecretsCmdFlags.outputFile); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(genSecretsCmdFlags.outputFile, bundleBytes, 0o600)\n}\n\nfunc init() {\n\tgenSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.outputFile, \"output-file\", \"o\", \"secrets.yaml\", `path of the output file, or \"-\" for stdout`)\n\tgenSecretsCmd.Flags().StringVar(&genSecretsCmdFlags.talosVersion, \"talos-version\", \"\", \"the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)\")\n\tgenSecretsCmd.Flags().StringVar(&genSecretsCmdFlags.fromControlplaneConfig, \"from-controlplane-config\", \"\", \"use the provided controlplane Talos machine configuration as input\")\n\tgenSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.fromKubernetesPki, \"from-kubernetes-pki\", \"p\", \"\", \"use a Kubernetes PKI directory (e.g. /etc/kubernetes/pki) as input\")\n\tgenSecretsCmd.Flags().StringVarP(&genSecretsCmdFlags.kubernetesBootstrapToken, \"kubernetes-bootstrap-token\", \"t\", \"\", \"use the provided bootstrap token as input\")\n\n\tCmd.AddCommand(genSecretsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/gen/secureboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"context\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/database\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar genSecurebootCmdFlags struct {\n\toutputDirectory string\n}\n\n// genSecurebootCmd represents the `gen secureboot` command.\nvar genSecurebootCmd = &cobra.Command{\n\tUse:   \"secureboot\",\n\tShort: \"Generates secrets for the SecureBoot process\",\n\tLong:  ``,\n}\n\nvar genSecurebootUKICmdFlags struct {\n\tcommonName string\n}\n\n// genSecurebootUKICmd represents the `gen secureboot uki` command.\nvar genSecurebootUKICmd = &cobra.Command{\n\tUse:   \"uki\",\n\tShort: \"Generates a certificate which is used to sign boot assets (UKI)\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn generateSigningCerts(genSecurebootCmdFlags.outputDirectory, \"uki\", genSecurebootUKICmdFlags.commonName, 4096, true)\n\t},\n}\n\n// genSecurebootPCRCmd represents the `gen secureboot pcr` command.\nvar genSecurebootPCRCmd = &cobra.Command{\n\tUse:   \"pcr\",\n\tShort: \"Generates a key which is used to sign TPM PCR values\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn generateSigningCerts(genSecurebootCmdFlags.outputDirectory, \"pcr\", \"dummy\", 2048, false)\n\t},\n}\n\nvar genSecurebootDatabaseCmdFlags struct {\n\tenrolledCertificatePath                string\n\tsigningCertificatePath, signingKeyPath string\n\tincludeWellKnownCerts                  bool\n}\n\n// genSecurebootDatabaseCmd represents the `gen secureboot database` command.\nvar genSecurebootDatabaseCmd = &cobra.Command{\n\tUse:   \"database\",\n\tShort: \"Generates a UEFI database to enroll the signing certificate\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn generateSecureBootDatabase(\n\t\t\tgenSecurebootCmdFlags.outputDirectory,\n\t\t\tgenSecurebootDatabaseCmdFlags.enrolledCertificatePath,\n\t\t\tgenSecurebootDatabaseCmdFlags.signingKeyPath,\n\t\t\tgenSecurebootDatabaseCmdFlags.signingCertificatePath,\n\t\t\tgenSecurebootDatabaseCmdFlags.includeWellKnownCerts,\n\t\t)\n\t},\n}\n\nfunc checkedWrite(path string, data []byte, perm fs.FileMode) error { //nolint:unparam\n\tif err := validateFileExists(path); err != nil {\n\t\treturn err\n\t}\n\n\tif dirname := filepath.Dir(path); dirname != \".\" {\n\t\tif err := os.MkdirAll(dirname, 0o700); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"writing %s\\n\", path)\n\n\treturn os.WriteFile(path, data, perm)\n}\n\nfunc generateSigningCerts(path, prefix, commonName string, rsaBits int, outputCert bool) error {\n\tcurrentTime := time.Now()\n\n\topts := []x509.Option{\n\t\tx509.RSA(true),\n\t\tx509.Bits(rsaBits),\n\t\tx509.CommonName(commonName),\n\t\tx509.NotAfter(currentTime.Add(secrets.CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.Organization(commonName),\n\t}\n\n\tsigningKey, err := x509.NewSelfSignedCertificateAuthority(opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif outputCert {\n\t\tif err = checkedWrite(filepath.Join(path, prefix+\"-signing-cert.pem\"), signingKey.CrtPEM, 0o600); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = saveAsDER(filepath.Join(path, prefix+\"-signing-cert.der\"), signingKey.CrtPEM); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn checkedWrite(filepath.Join(path, prefix+\"-signing-key.pem\"), signingKey.KeyPEM, 0o600)\n}\n\nfunc saveAsDER(file string, pem []byte) error {\n\tpublicKeyDER, err := convertPEMToDER(pem)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn checkedWrite(file, publicKeyDER, 0o600)\n}\n\n// generateSecureBootDatabase generates a UEFI database to enroll the signing certificate.\n//\n// ref: https://blog.hansenpartnership.com/the-meaning-of-all-the-uefi-keys/\nfunc generateSecureBootDatabase(path, enrolledCertificatePath, signingKeyPath, signingCertificatePath string, includeWellKnownCerts bool) error {\n\tin := profile.SigningKeyAndCertificate{\n\t\tKeyPath:  signingKeyPath,\n\t\tCertPath: signingCertificatePath,\n\t}\n\n\tsigner, err := in.GetSigner(context.Background()) // context not used\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create signer: %w\", err)\n\t}\n\n\tenrolledPEM, err := os.ReadFile(enrolledCertificatePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdb, err := database.Generate(enrolledPEM, signer, database.IncludeWellKnownCertificates(includeWellKnownCerts))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate database: %w\", err)\n\t}\n\n\t// output all files with sd-boot conventional names for auto-enrolment\n\tfor _, entry := range db {\n\t\tif err = checkedWrite(filepath.Join(path, entry.Name), entry.Contents, 0o600); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tgenSecurebootCmd.PersistentFlags().StringVarP(&genSecurebootCmdFlags.outputDirectory, \"output\", \"o\", helpers.ArtifactsPath, \"path to the directory storing the generated files\")\n\tCmd.AddCommand(genSecurebootCmd)\n\n\tgenSecurebootUKICmd.Flags().StringVar(&genSecurebootUKICmdFlags.commonName, \"common-name\", \"Test UKI Signing Key\", \"common name for the certificate\")\n\tgenSecurebootCmd.AddCommand(genSecurebootUKICmd)\n\n\tgenSecurebootCmd.AddCommand(genSecurebootPCRCmd)\n\n\tgenSecurebootDatabaseCmd.Flags().StringVar(\n\t\t&genSecurebootDatabaseCmdFlags.enrolledCertificatePath, \"enrolled-certificate\", helpers.ArtifactPath(constants.SecureBootSigningCertAsset), \"path to the certificate to enroll\")\n\tgenSecurebootDatabaseCmd.Flags().StringVar(\n\t\t&genSecurebootDatabaseCmdFlags.signingCertificatePath, \"signing-certificate\", helpers.ArtifactPath(constants.SecureBootSigningCertAsset), \"path to the certificate used to sign the database\")\n\tgenSecurebootDatabaseCmd.Flags().StringVar(\n\t\t&genSecurebootDatabaseCmdFlags.signingKeyPath, \"signing-key\", helpers.ArtifactPath(constants.SecureBootSigningKeyAsset), \"path to the key used to sign the database\")\n\tgenSecurebootDatabaseCmd.Flags().BoolVar(\n\t\t&genSecurebootDatabaseCmdFlags.includeWellKnownCerts, \"include-well-known-uefi-certs\", false, \"include well-known UEFI (Microsoft) certificates in the database\")\n\tgenSecurebootCmd.AddCommand(genSecurebootDatabaseCmd)\n}\n\nfunc convertPEMToDER(data []byte) ([]byte, error) {\n\tblock, rest := pem.Decode(data)\n\tif block == nil {\n\t\treturn nil, errors.New(\"failed to decode PEM data\")\n\t}\n\n\tif len(rest) > 0 {\n\t\treturn nil, errors.New(\"more than one PEM block found in PEM data\")\n\t}\n\n\treturn block.Bytes, nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/inject/inject.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage inject\n\nimport \"github.com/spf13/cobra\"\n\n// Cmd represents the debug command.\nvar Cmd = &cobra.Command{\n\tUse:   \"inject\",\n\tShort: \"Inject Talos API resources into Kubernetes manifests\",\n\tLong:  ``,\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/inject/serviceaccount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage inject\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes/inject\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nvar serviceAccountCmdFlags struct {\n\tfile  string\n\troles []string\n}\n\nvar serviceAccountCmd = &cobra.Command{\n\tUse:     fmt.Sprintf(\"%s [--roles='<ROLE_1>,<ROLE_2>'] -f <manifest.yaml>\", constants.ServiceAccountResourceSingular),\n\tAliases: []string{constants.ServiceAccountResourceShortName},\n\tShort:   \"Inject Talos API ServiceAccount into Kubernetes manifests\",\n\tExample: fmt.Sprintf(\n\t\t`talosctl inject %[1]s --roles=\"os:admin\" -f deployment.yaml > deployment-injected.yaml\n\nAlternatively, stdin can be piped to the command:\ncat deployment.yaml | talosctl inject %[1]s --roles=\"os:admin\" -f - > deployment-injected.yaml\n`,\n\t\tconstants.ServiceAccountResourceSingular,\n\t),\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, _ []string) error {\n\t\tvar err error\n\n\t\tif serviceAccountCmdFlags.file == \"\" {\n\t\t\treturn cmd.Help()\n\t\t}\n\n\t\treader := os.Stdin\n\n\t\tif serviceAccountCmdFlags.file != \"-\" {\n\t\t\treader, err = os.Open(serviceAccountCmdFlags.file)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tinjectedYaml, err := inject.ServiceAccount(reader, serviceAccountCmdFlags.roles)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfmt.Println(string(injectedYaml))\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tserviceAccountCmd.Flags().StringVarP(&serviceAccountCmdFlags.file, \"file\", \"f\", \"\",\n\t\tfmt.Sprintf(\"file with Kubernetes manifests to be injected with %s\", constants.ServiceAccountResourceKind))\n\tserviceAccountCmd.Flags().StringSliceVarP(&serviceAccountCmdFlags.roles, \"roles\", \"r\", []string{string(role.Reader)},\n\t\tfmt.Sprintf(\"roles to add to the generated %s manifests\", constants.ServiceAccountResourceKind))\n\tCmd.AddCommand(serviceAccountCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/json_logs_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mgmt\n\nimport (\n\t\"bufio\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n)\n\nvar jsonLogsLaunchCmdFlags struct {\n\taddr string\n}\n\n// jsonLogsLaunchCmd represents the kms-launch command.\nvar jsonLogsLaunchCmd = &cobra.Command{\n\tUse:    \"json-logs-launch\",\n\tShort:  \"Internal command used by QEMU provisioner\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tlis, err := net.Listen(\"tcp\", jsonLogsLaunchCmdFlags.addr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlog.Printf(\"starting JSON logs server on %s\", jsonLogsLaunchCmdFlags.addr)\n\n\t\teg, ctx := errgroup.WithContext(cmd.Context())\n\n\t\teg.Go(func() error {\n\t\t\tfor {\n\t\t\t\tconn, err := lis.Accept()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tgo func() {\n\t\t\t\t\tdefer conn.Close() //nolint:errcheck\n\n\t\t\t\t\tremoteAddr := conn.RemoteAddr().String()\n\n\t\t\t\t\tif addr, err := netip.ParseAddrPort(remoteAddr); err == nil {\n\t\t\t\t\t\tremoteAddr = addr.Addr().String()\n\t\t\t\t\t}\n\n\t\t\t\t\tscanner := bufio.NewScanner(conn)\n\n\t\t\t\t\tfor scanner.Scan() {\n\t\t\t\t\t\tlog.Printf(\"%s: %s\", remoteAddr, scanner.Text())\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\t\t})\n\n\t\teg.Go(func() error {\n\t\t\t<-ctx.Done()\n\n\t\t\treturn lis.Close()\n\t\t})\n\n\t\treturn eg.Wait()\n\t},\n}\n\nfunc init() {\n\tjsonLogsLaunchCmd.Flags().StringVar(&jsonLogsLaunchCmdFlags.addr, \"addr\", \"localhost:3000\", \"JSON logs listen address\")\n\taddCommand(jsonLogsLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/kms_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mgmt\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"log\"\n\t\"net\"\n\n\t\"github.com/siderolabs/kms-client/api/kms\"\n\t\"github.com/siderolabs/kms-client/pkg/server\"\n\t\"github.com/spf13/cobra\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc\"\n\n\tgrpclog \"github.com/siderolabs/talos/pkg/grpc/middleware/log\"\n)\n\nvar kmsLaunchCmdFlags struct {\n\taddr string\n\tkey  []byte\n}\n\n// kmsLaunchCmd represents the kms-launch command.\nvar kmsLaunchCmd = &cobra.Command{\n\tUse:    \"kms-launch\",\n\tShort:  \"Internal command used by QEMU provisioner\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif kmsLaunchCmdFlags.key == nil {\n\t\t\treturn errors.New(\"no key provided to the KMS server\")\n\t\t}\n\n\t\tlogger, err := zap.NewDevelopment()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer logger.Sync() //nolint:errcheck\n\n\t\tundo := zap.RedirectStdLog(logger)\n\t\tdefer undo()\n\n\t\tsrv := server.NewServer(logger, func(_ context.Context, nodeUUID string) ([]byte, error) {\n\t\t\treturn kmsLaunchCmdFlags.key, nil\n\t\t})\n\n\t\tlis, err := net.Listen(\"tcp\", kmsLaunchCmdFlags.addr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Info(\"starting KMS server\", zap.String(\"address\", kmsLaunchCmdFlags.addr))\n\n\t\tlogMiddleware := grpclog.NewMiddleware(log.New(log.Writer(), \"\", log.Flags()))\n\n\t\ts := grpc.NewServer(\n\t\t\tgrpc.UnaryInterceptor(logMiddleware.UnaryInterceptor()),\n\t\t\tgrpc.StreamInterceptor(logMiddleware.StreamInterceptor()),\n\t\t)\n\t\tkms.RegisterKMSServiceServer(s, srv)\n\n\t\teg, ctx := errgroup.WithContext(cmd.Context())\n\n\t\teg.Go(func() error {\n\t\t\terr := s.Serve(lis)\n\t\t\tif errors.Is(err, context.Canceled) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t})\n\n\t\teg.Go(func() error {\n\t\t\t<-ctx.Done()\n\n\t\t\ts.Stop()\n\n\t\t\treturn nil\n\t\t})\n\n\t\treturn eg.Wait()\n\t},\n}\n\nfunc init() {\n\tkmsLaunchCmd.Flags().StringVar(&kmsLaunchCmdFlags.addr, \"kms-addr\", \"localhost\", \"KMS listen address (IP or host)\")\n\tkmsLaunchCmd.Flags().BytesBase64Var(&kmsLaunchCmdFlags.key, \"kms-key\", nil, \"KMS key to use\")\n\taddCommand(kmsLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/loadbalancer_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mgmt\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/siderolabs/go-loadbalancer/loadbalancer\"\n\t\"github.com/spf13/cobra\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar loadbalancerLaunchCmdFlags struct {\n\taddr             string\n\tports            []int\n\tupstreams        []string\n\tapidOnlyInitNode bool\n}\n\nvar loadbalancerLaunchCmd = &cobra.Command{\n\tUse:    \"loadbalancer-launch\",\n\tShort:  \"Internal command used by QEMU provisioner\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tlb := loadbalancer.TCP{Logger: makeLogger()}\n\n\t\tfor _, port := range loadbalancerLaunchCmdFlags.ports {\n\t\t\tif err := lb.AddRoute(\n\t\t\t\tfmt.Sprintf(\"%s:%d\", loadbalancerLaunchCmdFlags.addr, port),\n\t\t\t\txiter.Map(\n\t\t\t\t\tfunc(upstream string) string {\n\t\t\t\t\t\treturn fmt.Sprintf(\"%s:%d\", upstream, port)\n\t\t\t\t\t},\n\t\t\t\t\tslices.Values(loadbalancerLaunchCmdFlags.upstreams),\n\t\t\t\t),\n\t\t\t); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn lb.Run()\n\t},\n}\n\nfunc makeLogger() *zap.Logger {\n\tconfig := zap.NewProductionConfig()\n\tconfig.Encoding = \"console\"\n\tconfig.DisableStacktrace = true\n\n\treturn zap.Must(config.Build())\n}\n\nfunc init() {\n\tloadbalancerLaunchCmd.Flags().StringVar(&loadbalancerLaunchCmdFlags.addr, \"loadbalancer-addr\", \"localhost\", \"load balancer listen address (IP or host)\")\n\tloadbalancerLaunchCmd.Flags().IntSliceVar(&loadbalancerLaunchCmdFlags.ports, \"loadbalancer-ports\", []int{constants.DefaultControlPlanePort}, \"load balancer ports\")\n\tloadbalancerLaunchCmd.Flags().StringSliceVar(&loadbalancerLaunchCmdFlags.upstreams, \"loadbalancer-upstreams\", []string{}, \"load balancer upstreams (nodes to proxy to)\")\n\taddCommand(loadbalancerLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/machineconfig/gen.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage machineconfig\n\nimport \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/gen\"\n\nfunc init() {\n\t// alias for `talosctl gen config`\n\tCmd.AddCommand(gen.NewConfigCmd(\"gen\"))\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/machineconfig/machineconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage machineconfig\n\nimport \"github.com/spf13/cobra\"\n\n// Cmd represents the `machineconfig` command.\nvar Cmd = &cobra.Command{\n\tUse:     \"machineconfig\",\n\tShort:   \"Machine config related commands\",\n\tAliases: []string{\"mc\"},\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/machineconfig/patch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage machineconfig\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n)\n\nvar patchCmdFlags struct {\n\tpatches []string\n\toutput  string\n}\n\n// patchCmd represents the `machineconfig patch` command.\nvar patchCmd = &cobra.Command{\n\tUse:   \"patch <machineconfig-file>\",\n\tShort: \"Patch a machine config\",\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tdata, err := os.ReadFile(args[0])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpatches, err := configpatcher.LoadPatches(patchCmdFlags.patches)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpatched, err := configpatcher.Apply(configpatcher.WithBytes(data), patches)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpatchedData, err := patched.Bytes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif patchCmdFlags.output == \"\" { // write to stdout\n\t\t\tfmt.Printf(\"%s\\n\", patchedData)\n\n\t\t\treturn nil\n\t\t}\n\n\t\t// write to file\n\n\t\tparentDir := filepath.Dir(patchCmdFlags.output)\n\n\t\t// Create dir path, ignoring \"already exists\" messages\n\t\tif err := os.MkdirAll(parentDir, os.ModePerm); err != nil && !os.IsExist(err) {\n\t\t\treturn fmt.Errorf(\"failed to create output dir: %w\", err)\n\t\t}\n\n\t\treturn os.WriteFile(patchCmdFlags.output, patchedData, 0o644)\n\t},\n}\n\nfunc init() {\n\t// use StringArrayVarP instead of StringSliceVarP to prevent cobra from splitting the patch string on commas\n\tpatchCmd.Flags().StringArrayVarP(&patchCmdFlags.patches, \"patch\", \"p\", nil, \"patch generated machineconfigs (applied to all node types), use @file to read a patch from file\")\n\tpatchCmd.Flags().StringVarP(&patchCmdFlags.output, \"output\", \"o\", \"\", \"output destination. if not specified, output will be printed to stdout\")\n\n\tCmd.AddCommand(patchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/qemu_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage mgmt\n\nimport (\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/qemu\"\n)\n\n// qemuLaunchCmd represents the qemu-launch command.\nvar qemuLaunchCmd = &cobra.Command{\n\tUse:    \"qemu-launch\",\n\tShort:  \"Internal command used by QEMU provisioner\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn qemu.Launch()\n\t},\n}\n\nfunc init() {\n\taddCommand(qemuLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mgmt\n\nimport (\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/debug\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/gen\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/inject\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/machineconfig\"\n)\n\n// Commands is a list of commands published by the package.\nvar Commands []*cobra.Command\n\n// GenV1Alpha1Config generates the Talos config bundle\n//\n// Kept with this name in this package for backwards-compatibility.\nvar GenV1Alpha1Config = gen.GenerateConfigBundle\n\nfunc addCommand(cmd *cobra.Command) {\n\tCommands = append(Commands, cmd)\n}\n\nfunc init() {\n\taddCommand(cluster.Cmd)\n\taddCommand(gen.Cmd)\n\taddCommand(debug.Cmd)\n\taddCommand(inject.Cmd)\n\taddCommand(machineconfig.Cmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/siderolink_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage mgmt\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\n\t\"github.com/siderolabs/siderolink/pkg/agent\"\n\t\"github.com/siderolabs/siderolink/pkg/wireguard\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"go.uber.org/zap\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n)\n\nvar siderolinkFlags struct {\n\tjoinToken         string\n\twireguardEndpoint string\n\tsinkEndpoint      string\n\tapiEndpoint       string\n\tapiCertPath       string\n\tapiKeyPath        string\n\tlogEndpoint       string\n\tpredefinedPairs   []string\n}\n\nvar siderolinkCmd = &cobra.Command{\n\tUse:    \"siderolink-launch\",\n\tShort:  \"Internal command used by cluster create to launch siderolink agent\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tctx, cancel := signal.NotifyContext(cmd.Context(), os.Interrupt)\n\t\tdefer cancel()\n\n\t\treturn run(ctx)\n\t},\n}\n\nfunc init() {\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.joinToken, \"sidero-link-join-token\", \"\", \"join token for the cluster\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.wireguardEndpoint, \"sidero-link-wireguard-endpoint\", \"\", \"advertised Wireguard endpoint\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.sinkEndpoint, \"event-sink-endpoint\", \"\", \"gRPC API endpoint for the Event Sink\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.apiEndpoint, \"sidero-link-api-endpoint\", \"\", \"gRPC API endpoint for the SideroLink\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.apiCertPath, \"sidero-link-api-cert\", \"\", \"path to the API server certificate (optional)\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.apiKeyPath, \"sidero-link-api-key\", \"\", \"path to the API server key (optional)\")\n\tsiderolinkCmd.PersistentFlags().StringVar(&siderolinkFlags.logEndpoint, \"log-receiver-endpoint\", \"\", \"TCP log receiver endpoint\")\n\tsiderolinkCmd.PersistentFlags().StringArrayVar(&siderolinkFlags.predefinedPairs, \"predefined-pair\", nil, \"predefined pairs of UUID=IPv6 addrs for the nodes\")\n\n\tsiderolinkCmd.PersistentFlags().VisitAll(func(flag *pflag.Flag) {\n\t\terr := siderolinkCmd.PersistentFlags().MarkHidden(flag.Name)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t})\n\n\taddCommand(siderolinkCmd)\n}\n\nfunc run(ctx context.Context) error {\n\tlogger, err := zap.NewDevelopment()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlogger.Info(\"starting embedded siderolink agent\")\n\tdefer logger.Info(\"stopping embedded siderolink agent\")\n\n\tvar apiTLSConfig *tls.Config\n\n\tif siderolinkFlags.apiCertPath != \"\" && siderolinkFlags.apiKeyPath != \"\" {\n\t\tapiCert, err := tls.LoadX509KeyPair(siderolinkFlags.apiCertPath, siderolinkFlags.apiKeyPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load API server certificate: %w\", err)\n\t\t}\n\n\t\tapiTLSConfig = &tls.Config{\n\t\t\tCertificates: []tls.Certificate{apiCert},\n\t\t}\n\t}\n\n\terr = agent.Run(\n\t\tctx,\n\t\tagent.Config{\n\t\t\tWireguardEndpoint: siderolinkFlags.wireguardEndpoint,\n\t\t\tAPIEndpoint:       siderolinkFlags.apiEndpoint,\n\t\t\tAPITLSConfig:      apiTLSConfig,\n\t\t\tJoinToken:         siderolinkFlags.joinToken,\n\t\t\tSinkEndpoint:      siderolinkFlags.sinkEndpoint,\n\t\t\tLogEndpoint:       siderolinkFlags.logEndpoint,\n\t\t\tUUIDIPv6Pairs:     siderolinkFlags.predefinedPairs,\n\t\t\tForceUserspace:    true,\n\t\t},\n\t\t&handler{l: logger},\n\t\tlogger,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to run siderolink agent: %w\", err)\n\t}\n\n\treturn nil\n}\n\ntype handler struct {\n\tl *zap.Logger\n}\n\nfunc (h *handler) HandlePeerAdded(event wireguard.PeerEvent) error {\n\th.l.Info(\"talos agent sees peer added\", zap.String(\"address\", event.Address.String()))\n\n\treturn nil\n}\n\nfunc (h *handler) HandlePeerRemoved(wgtypes.Key) error {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/validate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mgmt\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\nvar (\n\tvalidateConfigArg string\n\tvalidateModeArg   string\n\tvalidateStrictArg bool\n)\n\n// validateCmd reads in a userData file and attempts to parse it.\nvar validateCmd = &cobra.Command{\n\tUse:   \"validate\",\n\tShort: \"Validate config\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tcfg, err := configloader.NewFromFile(validateConfigArg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tmode, err := runtime.ParseMode(validateModeArg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\topts := []validation.Option{validation.WithLocal()}\n\t\tif validateStrictArg {\n\t\t\topts = append(opts, validation.WithStrict())\n\t\t}\n\n\t\twarnings, err := cfg.Validate(mode, opts...)\n\t\tfor _, w := range warnings {\n\t\t\tcli.Warning(\"%s\", w)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfmt.Printf(\"%s is valid for %s mode\\n\", validateConfigArg, validateModeArg)\n\n\t\treturn nil\n\t},\n}\n\nfunc init() {\n\tvalidateCmd.Flags().StringVarP(&validateConfigArg, \"config\", \"c\", \"\", \"the path of the config file\")\n\tvalidateCmd.Flags().StringVarP(\n\t\t&validateModeArg,\n\t\t\"mode\",\n\t\t\"m\",\n\t\t\"\",\n\t\tfmt.Sprintf(\"the mode to validate the config for (valid values are %s, %s, and %s)\", runtime.ModeMetal.String(), runtime.ModeCloud.String(), runtime.ModeContainer.String()),\n\t)\n\tcli.Should(validateCmd.MarkFlagRequired(\"mode\"))\n\tvalidateCmd.Flags().BoolVarP(&validateStrictArg, \"strict\", \"\", false, \"treat validation warnings as errors\")\n\taddCommand(validateCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/mgmt/virtiofsd_launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage mgmt\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create/flags\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\nvar virtiofsdLaunchCmdFlags struct {\n\tvirtiofsdBin string\n\tvirtiofs     flags.Virtiofs\n}\n\n// virtiofsdLaunchCmd represents the virtiofsd-launch command.\nvar virtiofsdLaunchCmd = &cobra.Command{\n\tUse:    \"virtiofsd-launch\",\n\tShort:  \"Internal command used by VM provisioners\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\teg, ctx := errgroup.WithContext(cmd.Context())\n\n\t\tfor _, vfs := range virtiofsdLaunchCmdFlags.virtiofs.Requests() {\n\t\t\teg.Go(func() error {\n\t\t\t\treturn vm.Virtiofsd(ctx, virtiofsdLaunchCmdFlags.virtiofsdBin, vfs.SharedDir, vfs.SocketPath)\n\t\t\t})\n\t\t}\n\n\t\treturn eg.Wait()\n\t},\n}\n\nfunc init() {\n\tvirtiofsdLaunchCmd.Flags().StringVar(&virtiofsdLaunchCmdFlags.virtiofsdBin, \"bin\",\n\t\t\"/usr/libexec/virtiofsd\", `path to the virtiofsd binary`)\n\tvirtiofsdLaunchCmd.Flags().Var(&virtiofsdLaunchCmdFlags.virtiofs, \"virtiofs\",\n\t\t`list of virtiofs shares to create in format \"<share>:<socket>\"`)\n\taddCommand(virtiofsdLaunchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/common\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster\"\n\t_ \"github.com/siderolabs/talos/cmd/talosctl/cmd/mgmt/cluster/create\" // import to get the command registered via the init() function.\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos\"\n)\n\n// rootCmd represents the base command when called without any subcommands.\nvar rootCmd = &cobra.Command{\n\tUse:               \"talosctl\",\n\tShort:             \"A CLI for out-of-band management of Kubernetes nodes created by Talos\",\n\tLong:              ``,\n\tSilenceErrors:     true,\n\tSilenceUsage:      true,\n\tDisableAutoGenTag: true,\n}\n\n// Execute adds all child commands to the root command and sets flags appropriately.\n// This is called by main.main(). It only needs to happen once to the rootCmd.\nfunc Execute() error {\n\tcmd, err := rootCmd.ExecuteContextC(context.Background())\n\tif err != nil && !common.SuppressErrors {\n\t\tfmt.Fprintln(os.Stderr, err.Error())\n\n\t\terrorString := err.Error()\n\t\t// TODO: this is a nightmare, but arg-flag related validation returns simple `fmt.Errorf`, no way to distinguish\n\t\t//       these errors\n\t\tif strings.Contains(errorString, \"arg(s)\") || strings.Contains(errorString, \"flag\") || strings.Contains(errorString, \"command\") {\n\t\t\tfmt.Fprintln(os.Stderr)\n\t\t\tfmt.Fprintln(os.Stderr, cmd.UsageString())\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc init() {\n\tconst (\n\t\ttalosGroup   = \"talos\"\n\t\tmgmtGroup    = \"mgmt\"\n\t\tclusterGroup = \"cluster\"\n\t)\n\n\trootCmd.AddGroup(&cobra.Group{ID: talosGroup, Title: \"Manage running Talos clusters:\"})\n\trootCmd.AddGroup(&cobra.Group{ID: mgmtGroup, Title: \"Commands to generate and manage machine configuration offline:\"})\n\trootCmd.AddGroup(&cobra.Group{ID: clusterGroup, Title: \"Local Talos cluster commands:\"})\n\n\tfor _, cmd := range mgmt.Commands {\n\t\tcmd.GroupID = mgmtGroup\n\t\tif cmd == cluster.Cmd {\n\t\t\tcmd.GroupID = clusterGroup\n\t\t}\n\n\t\trootCmd.AddCommand(cmd)\n\t}\n\n\tfor _, cmd := range talos.Commands {\n\t\tcmd.GroupID = talosGroup\n\t\trootCmd.AddCommand(cmd)\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/apply-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar applyConfigCmdFlags struct {\n\thelpers.Mode\n\n\tcertFingerprints []string\n\tpatches          []string\n\tfilename         string\n\tinsecure         bool\n\tdryRun           bool\n\tconfigTryTimeout time.Duration\n}\n\n// applyConfigCmd represents the applyConfiguration command.\nvar applyConfigCmd = &cobra.Command{\n\tUse:     \"apply-config\",\n\tAliases: []string{\"apply\"},\n\tShort:   \"Apply a new configuration to a node\",\n\tLong:    ``,\n\tArgs:    cobra.MaximumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tvar (\n\t\t\tcfgBytes []byte\n\t\t\terr      error\n\t\t)\n\n\t\tif len(args) > 0 {\n\t\t\tif args[0] != \"config\" && !strings.EqualFold(args[0], \"machineconfig\") {\n\t\t\t\tcmd.Help() //nolint:errcheck\n\n\t\t\t\treturn fmt.Errorf(\"unknown positional argument %s\", args[0])\n\t\t\t} else if cmd.CalledAs() == \"apply-config\" {\n\t\t\t\tcmd.Help() //nolint:errcheck\n\n\t\t\t\treturn errors.New(\"expected no positional arguments\")\n\t\t\t}\n\t\t}\n\n\t\tif applyConfigCmdFlags.filename == \"\" {\n\t\t\treturn errors.New(\"no filename supplied for configuration\")\n\t\t}\n\n\t\tcfgBytes, err = os.ReadFile(applyConfigCmdFlags.filename)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read configuration from %q: %w\", applyConfigCmdFlags.filename, err)\n\t\t}\n\n\t\tif len(cfgBytes) < 1 {\n\t\t\treturn errors.New(\"no configuration data read\")\n\t\t}\n\n\t\tif len(applyConfigCmdFlags.patches) != 0 {\n\t\t\tvar (\n\t\t\t\tcfg     configpatcher.Input\n\t\t\t\tpatches []configpatcher.Patch\n\t\t\t)\n\n\t\t\tpatches, err = configpatcher.LoadPatches(applyConfigCmdFlags.patches)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcfg, err = configpatcher.Apply(configpatcher.WithBytes(cfgBytes), patches)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcfgBytes, err = cfg.Bytes()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\twithClient := func(f func(context.Context, *client.Client) error) error {\n\t\t\tif applyConfigCmdFlags.insecure {\n\t\t\t\treturn WithClientMaintenance(applyConfigCmdFlags.certFingerprints, f)\n\t\t\t}\n\n\t\t\treturn WithClient(f)\n\t\t}\n\n\t\treturn withClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tresp, err := c.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\tData:           cfgBytes,\n\t\t\t\tMode:           applyConfigCmdFlags.Mode.Mode,\n\t\t\t\tDryRun:         applyConfigCmdFlags.dryRun,\n\t\t\t\tTryModeTimeout: durationpb.New(applyConfigCmdFlags.configTryTimeout),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying new configuration: %s\", err)\n\t\t\t}\n\n\t\t\thelpers.PrintApplyResults(resp)\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\tapplyConfigCmd.Flags().StringVarP(&applyConfigCmdFlags.filename, \"file\", \"f\", \"\", \"the filename of the updated configuration\")\n\tapplyConfigCmd.Flags().BoolVarP(&applyConfigCmdFlags.insecure, \"insecure\", \"i\", false, \"apply the config using the insecure (encrypted with no auth) maintenance service\")\n\tapplyConfigCmd.Flags().BoolVar(&applyConfigCmdFlags.dryRun, \"dry-run\", false, \"check how the config change will be applied in dry-run mode\")\n\tapplyConfigCmd.Flags().StringSliceVar(&applyConfigCmdFlags.certFingerprints, \"cert-fingerprint\", nil, \"list of server certificate fingeprints to accept (defaults to no check)\")\n\tapplyConfigCmd.Flags().StringArrayVarP(&applyConfigCmdFlags.patches, \"config-patch\", \"p\", nil, \"the list of config patches to apply to the local config file before sending it to the node\")\n\tapplyConfigCmd.Flags().DurationVar(&applyConfigCmdFlags.configTryTimeout, \"timeout\", constants.ConfigTryTimeout, \"the config will be rolled back after specified timeout (if try mode is selected)\")\n\thelpers.AddModeFlags(&applyConfigCmdFlags.Mode, applyConfigCmd)\n\taddCommand(applyConfigCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/bootstrap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\tsnapshot \"go.etcd.io/etcd/etcdutl/v3/snapshot\"\n\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar bootstrapCmdFlags struct {\n\trecoverFrom          string\n\trecoverSkipHashCheck bool\n}\n\n// bootstrapCmd represents the bootstrap command.\nvar bootstrapCmd = &cobra.Command{\n\tUse:   \"bootstrap\",\n\tShort: \"Bootstrap the etcd cluster on the specified node.\",\n\tLong: `When Talos cluster is created etcd service on control plane nodes enter the join loop waiting\nto join etcd peers from other control plane nodes. One node should be picked as the bootstrap node.\nWhen bootstrap command is issued, the node aborts join process and bootstraps etcd cluster as a single node cluster.\nOther control plane nodes will join etcd cluster once Kubernetes is bootstrapped on the bootstrap node.\n\nThis command should not be used when \"init\" type node are used.\n\nTalos etcd cluster can be recovered from a known snapshot with '--recover-from=' flag.`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif len(GlobalArgs.Nodes) > 1 {\n\t\t\t\treturn errors.New(\"command \\\"bootstrap\\\" is not supported with multiple nodes\")\n\t\t\t}\n\n\t\t\tif bootstrapCmdFlags.recoverFrom != \"\" {\n\t\t\t\tmanager := snapshot.NewV3(logging.Wrap(os.Stderr))\n\n\t\t\t\tstatus, err := manager.Status(bootstrapCmdFlags.recoverFrom)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tfmt.Printf(\"recovering from snapshot %q: hash %08x, revision %d, total keys %d, total size %d\\n\",\n\t\t\t\t\tbootstrapCmdFlags.recoverFrom, status.Hash, status.Revision, status.TotalKey, status.TotalSize)\n\n\t\t\t\tsnapshot, err := os.Open(bootstrapCmdFlags.recoverFrom)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error opening snapshot file: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tdefer snapshot.Close() //nolint:errcheck\n\n\t\t\t\t_, err = c.EtcdRecover(ctx, snapshot)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error uploading snapshot: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := c.Bootstrap(ctx, &machineapi.BootstrapRequest{\n\t\t\t\tRecoverEtcd:          bootstrapCmdFlags.recoverFrom != \"\",\n\t\t\t\tRecoverSkipHashCheck: bootstrapCmdFlags.recoverSkipHashCheck,\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error executing bootstrap: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\tbootstrapCmd.Flags().StringVar(&bootstrapCmdFlags.recoverFrom, \"recover-from\", \"\", \"recover etcd cluster from the snapshot\")\n\tbootstrapCmd.Flags().BoolVar(&bootstrapCmdFlags.recoverSkipHashCheck, \"recover-skip-hash-check\", false, \"skip integrity check when recovering etcd (use when recovering from data directory copy)\")\n\taddCommand(bootstrapCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroups.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"archive/tar\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/cgroupsprinter\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar cgroupsCmdFlags struct {\n\tschemaFile     string\n\tpresetName     string\n\tskipCRIResolve bool\n}\n\n// cgroupsCmd represents the cgroups command.\nvar cgroupsCmd = &cobra.Command{\n\tUse:     \"cgroups\",\n\tAliases: []string{\"cg\"},\n\tShort:   \"Retrieve cgroups usage information\",\n\tLong: `The cgroups command fetches control group v2 (cgroupv2) usage details from the machine.\nSeveral presets are available to focus on specific cgroup subsystems:\n\n* cpu\n* cpuset\n* io\n* memory\n* process\n* swap\n\nYou can specify the preset using the --preset flag.\n\nAlternatively, a custom schema can be provided using the --schema-file flag.\nTo see schema examples, refer to https://github.com/siderolabs/talos/tree/main/cmd/talosctl/cmd/talos/cgroupsprinter/schemas.\n`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"cgroups\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tvar schema cgroupsprinter.Schema\n\n\t\t\tswitch {\n\t\t\tcase cgroupsCmdFlags.schemaFile != \"\":\n\t\t\t\tin, err := os.Open(cgroupsCmdFlags.schemaFile)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error opening schema file: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tdefer in.Close() //nolint:errcheck\n\n\t\t\t\tif err = yaml.NewDecoder(in).Decode(&schema); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error decoding schema file: %w\", err)\n\t\t\t\t}\n\t\t\tcase cgroupsCmdFlags.presetName != \"\":\n\t\t\t\tpresetNames := cgroupsprinter.GetPresetNames()\n\n\t\t\t\tif slices.Index(presetNames, cgroupsCmdFlags.presetName) == -1 {\n\t\t\t\t\treturn fmt.Errorf(\"invalid preset name: %s (valid %v)\", cgroupsCmdFlags.presetName, presetNames)\n\t\t\t\t}\n\n\t\t\t\tschema = cgroupsprinter.GetPreset(cgroupsCmdFlags.presetName)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"either schema file or preset must be specified\")\n\t\t\t}\n\n\t\t\tif err := schema.Compile(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error compiling schema: %w\", err)\n\t\t\t}\n\n\t\t\tprocessResolveMap := buildProcessResolveMap(ctx, c)\n\t\t\tdevicesResolveMap := buildDevicesResolveMap(ctx, c)\n\n\t\t\tr, err := c.Copy(ctx, constants.CgroupMountPath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying: %w\", err)\n\t\t\t}\n\n\t\t\tdefer r.Close() //nolint:errcheck\n\n\t\t\ttree, err := cgroups.TreeFromTarGz(r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading cgroups: %w\", err)\n\t\t\t}\n\n\t\t\tif !cgroupsCmdFlags.skipCRIResolve {\n\t\t\t\tcgroupNameResolveMap := buildCgroupResolveMap(ctx, c)\n\t\t\t\ttree.ResolveNames(cgroupNameResolveMap)\n\t\t\t}\n\n\t\t\ttree.Walk(func(node *cgroups.Node) {\n\t\t\t\tnode.CgroupProcsResolved = xslices.Map(node.CgroupProcs, func(pid cgroups.Value) cgroups.RawValue {\n\t\t\t\t\tif name, ok := processResolveMap[pid.String()]; ok {\n\t\t\t\t\t\treturn cgroups.RawValue(name)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn cgroups.RawValue(pid.String())\n\t\t\t\t})\n\n\t\t\t\tfor dev := range node.IOStat {\n\t\t\t\t\tif name, ok := devicesResolveMap[dev]; ok {\n\t\t\t\t\t\tnode.IOStat[name] = node.IOStat[dev]\n\t\t\t\t\t\tdelete(node.IOStat, dev)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\n\t\t\tdefer w.Flush() //nolint:errcheck\n\n\t\t\theaderLine := \"NAME\\t\" + schema.HeaderLine() + \"\\n\"\n\n\t\t\t_, err = w.Write([]byte(headerLine))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error writing header line: %w\", err)\n\t\t\t}\n\n\t\t\treturn cgroupsprinter.PrintNode(\".\", w, &schema, tree.Root, nil, 0, nil, false, true)\n\t\t})\n\t},\n}\n\nfunc completeCgroupPresetArg(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\treturn cgroupsprinter.GetPresetNames(), cobra.ShellCompDirectiveNoFileComp\n}\n\nfunc buildCgroupResolveMap(ctx context.Context, c *client.Client) map[string]string {\n\tcgroupNameResolveMap := map[string]string{}\n\n\tcontainersResp, err := c.Containers(ctx, constants.K8sContainerdNamespace, common.ContainerDriver_CRI)\n\tif err != nil {\n\t\tcli.Warning(\"error getting containers: %s\", err)\n\t} else {\n\t\tfor _, ctr := range containersResp.Messages[0].Containers {\n\t\t\tif ctr.Uid != \"\" && ctr.PodId != \"\" {\n\t\t\t\tcgroupNameResolveMap[\"pod\"+ctr.Uid] = ctr.PodId\n\t\t\t}\n\n\t\t\tif ctr.InternalId != \"\" {\n\t\t\t\tif ctr.PodId == ctr.Name {\n\t\t\t\t\tcgroupNameResolveMap[ctr.InternalId] = \"sandbox\"\n\t\t\t\t} else {\n\t\t\t\t\tcgroupNameResolveMap[ctr.InternalId] = ctr.Name\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn cgroupNameResolveMap\n}\n\nfunc buildProcessResolveMap(ctx context.Context, c *client.Client) map[string]string {\n\tprocessResolveMap := map[string]string{}\n\n\tprocessesResp, err := c.Processes(ctx)\n\tif err != nil {\n\t\tcli.Warning(\"error getting processes: %s\", err)\n\n\t\treturn processResolveMap\n\t}\n\n\tfor _, proc := range processesResp.Messages[0].Processes {\n\t\tname := proc.Executable\n\n\t\tif name == \"\" {\n\t\t\tname = proc.Command\n\t\t}\n\n\t\tif name == \"\" {\n\t\t\targs := strings.Fields(proc.Args)\n\n\t\t\tif len(args) > 0 {\n\t\t\t\tname = args[0]\n\t\t\t}\n\t\t}\n\n\t\tname = filepath.Base(name)\n\n\t\tprocessResolveMap[strconv.FormatInt(int64(proc.Pid), 10)] = name\n\t}\n\n\treturn processResolveMap\n}\n\nfunc buildDevicesResolveMap(ctx context.Context, c *client.Client) map[string]string {\n\tdevicesResolveMap := map[string]string{}\n\n\tr, err := c.Copy(ctx, \"/sys/dev/block\")\n\tif err != nil {\n\t\tcli.Warning(\"error copying devices: %s\", err)\n\n\t\treturn devicesResolveMap\n\t}\n\n\tdefer r.Close() //nolint:errcheck\n\n\tgzR, err := gzip.NewReader(r)\n\tif err != nil {\n\t\tcli.Warning(\"error reading devices: %s\", err)\n\n\t\treturn devicesResolveMap\n\t}\n\n\tdefer gzR.Close() //nolint:errcheck\n\n\ttarR := tar.NewReader(gzR)\n\n\tfor {\n\t\theader, err := tarR.Next()\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tif header.Typeflag != tar.TypeSymlink {\n\t\t\tcontinue\n\t\t}\n\n\t\tdevicesResolveMap[header.Name] = filepath.Base(header.Linkname)\n\t}\n\n\treturn devicesResolveMap\n}\n\nfunc init() {\n\tpresetNames := cgroupsprinter.GetPresetNames()\n\n\tcgroupsCmd.Flags().StringVar(&cgroupsCmdFlags.schemaFile, \"schema-file\", \"\", \"path to the columns schema file\")\n\tcgroupsCmd.Flags().StringVar(&cgroupsCmdFlags.presetName, \"preset\", \"\", fmt.Sprintf(\"preset name (one of: %v)\", presetNames))\n\tcgroupsCmd.Flags().BoolVar(&cgroupsCmdFlags.skipCRIResolve, \"skip-cri-resolve\", false, \"do not resolve cgroup names via a request to CRI\")\n\tcgroupsCmd.MarkFlagsMutuallyExclusive(\"schema-file\", \"preset\")\n\tcgroupsCmd.RegisterFlagCompletionFunc(\"preset\", completeCgroupPresetArg) //nolint:errcheck\n\n\taddCommand(cgroupsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/cpu.yaml",
    "content": "# Basic CPU metrics\ncolumns:\n  - name: CpuWeight\n    template: '{{ .CPUWeight | printf \"%6s\" }}'\n  - name: CpuNice\n    template: '{{ .CPUWeightNice | printf \"%6s\" }}'\n  - name: CpuMax\n    template: '{{ .CPUMax | printf \"%6s\" }}'\n  - name: CpuUser\n    template: '{{ .CPUStat.user_usec.UsecToDuration | printf \"%12s\" }}'\n  - name: User/%\n    template: '{{ if .Parent }}{{ .CPUStat.user_usec.DivideBy .Parent.CPUStat.user_usec | printf \"%6s\" }}%{{ else }}-{{ end }}'\n  - name: CpuSystem\n    template: '{{ .CPUStat.system_usec.UsecToDuration | printf \"%12s\" }}'\n  - name: System/%\n    template: '{{ if .Parent }}{{ .CPUStat.system_usec.DivideBy .Parent.CPUStat.system_usec | printf \"%6s\" }}%{{ else }}-{{ end }}'\n  - name: Throttled\n    template: '{{ .CPUStat.throttled_usec.UsecToDuration | printf \"%12s\" }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/cpuset.yaml",
    "content": "columns:\n  - name: CpuSet\n    template: '{{ .CPUSetCPUs | printf \"%12s\" }}'\n  - name: CpuSet(Eff)\n    template: '{{ .CPUSetCPUsEffective | printf \"%12s\" }}'\n  - name: Mems\n    template: '{{ .CPUSetMems | printf \"%12s\" }}'\n  - name: Mems(Eff)\n    template: '{{ .CPUSetMemsEffective | printf \"%12s\" }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/io.yaml",
    "content": "columns:\n  - name: Bytes Read/Written\n    template: '{{ range $disk, $v := .IOStat }}{{ if $v }}{{ $disk }}: {{ $v.rbytes.HumanizeIBytes }}/{{ $v.wbytes.HumanizeIBytes }} {{ end }}{{ end }}'\n  - name: ios Read/Write\n    template: '{{ if .Parent }}{{ range $disk, $v := .IOStat }}{{ $disk }}: {{ $v.rios }}/{{ $v.wios }} {{ end }}{{ end }}'\n  - name: PressAvg10\n    template: '{{ .IOPressure.some.avg10 | printf \"%6s\" }}'\n  - name: PressAvg60\n    template: '{{ .IOPressure.some.avg60 | printf \"%6s\" }}'\n  - name: PressTotal\n    template: '{{ .IOPressure.some.total.UsecToDuration | printf \"%12s\" }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/memory.yaml",
    "content": "# Memory-related cgroup metrics\ncolumns:\n  - name: MemCurrent\n    template: '{{ .MemoryCurrent.HumanizeIBytes | printf \"%8s\" }}'\n  - name: MemPeak\n    template: '{{ .MemoryPeak.HumanizeIBytes | printf \"%8s\" }}'\n  - name: MemLow\n    template: '{{ .MemoryLow.HumanizeIBytes | printf \"%8s\" }}'\n  - name: Peak/Low\n    template: '{{ .MemoryPeak.DivideBy .MemoryLow | printf \"%6s%%\" }}'\n  - name: MemHigh\n    template: '{{ .MemoryHigh.HumanizeIBytes | printf \"%8s\" }}'\n  - name: MemMin\n    template: '{{ .MemoryMin.HumanizeIBytes | printf \"%8s\" }}'\n  - name: Current/Min\n    template: '{{ .MemoryCurrent.DivideBy .MemoryMin | printf \"%6s%%\" }}'\n  - name: MemMax\n    template: '{{ .MemoryMax.HumanizeIBytes | printf \"%8s\" }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/process.yaml",
    "content": "columns:\n  - name: PidsCurrent\n    template: '{{ .PidsCurrent | printf \"%8s\" }}'\n  - name: PidsPeak\n    template: '{{ .PidsPeak | printf \"%8s\" }}'\n  - name: PidsMax\n    template: '{{ .PidsMax | printf \"%8s\" }}'\n  - name: Procs\n    template: '{{ .CgroupProcs | len | printf \"%7d\" }}'\n  - name: Threads\n    template: '{{ .CgroupThreads | len | printf \"%7d\" }}'\n  - name: Processes\n    template: '{{ if .Parent }}{{ .CgroupProcsResolved | printf \"%s\" | printf \"%.50s\"  }}{{ end }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/psi.yaml",
    "content": "# PSI-related cgroup metrics\ncolumns:\n  - name: MemCurrent\n    template: '{{ .MemoryCurrent.HumanizeIBytes | printf \"%8s\" }}'\n  - name: MemPsiSome10\n    template: '{{ .MemoryPressure.some.avg10 | printf \"%6s\" }}'\n  - name: MemPsi10\n    template: '{{ .MemoryPressure.full.avg10 | printf \"%6s\" }}'\n  - name: CpuPsi10\n    template: '{{ .CPUPressure.full.avg10 | printf \"%6s\" }}'\n  - name: IoPsi10\n    template: '{{ .IOPressure.full.avg10 | printf \"%6s\" }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets/swap.yaml",
    "content": "columns:\n  - name: SwapCurrent\n    template: '{{ .MemorySwapCurrent.HumanizeIBytes | printf \"%8s\" }}'\n  - name: SwapPeak\n    template: '{{ .MemorySwapPeak.HumanizeIBytes | printf \"%8s\" }}'\n  - name: SwapHigh\n    template: '{{ .MemorySwapHigh.HumanizeIBytes | printf \"%8s\" }}'\n  - name: SwapMax\n    template: '{{ .MemorySwapMax.HumanizeIBytes | printf \"%8s\" }}'\n  - name: ZswapCurrent\n    template: '{{ .MemoryZswapCurrent.HumanizeIBytes | printf \"%8s\" }}'\n  - name: ZswapMax\n    template: '{{ .MemoryZswapMax.HumanizeIBytes | printf \"%8s\" }}'\n  - name: ZswapWriteback\n    template: '{{ .MemoryZswapWriteback }}'\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroupsprinter\n\nimport (\n\t\"embed\"\n\t\"io/fs\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.yaml.in/yaml/v4\"\n)\n\n//go:embed presets/*.yaml\nvar presetsFS embed.FS\n\n// GetPresetNames returns the list of preset names.\nfunc GetPresetNames() []string {\n\tlist, err := presetsFS.ReadDir(\"presets\")\n\tif err != nil {\n\t\tpanic(err) // should not fail\n\t}\n\n\tpresets := xslices.Map(list, func(dirEntry fs.DirEntry) string {\n\t\t// cut extension\n\t\treturn strings.TrimSuffix(dirEntry.Name(), filepath.Ext(dirEntry.Name()))\n\t})\n\n\tslices.Sort(presets)\n\n\treturn presets\n}\n\n// GetPreset returns the preset by name.\nfunc GetPreset(name string) Schema {\n\t// embed.FS always uses / as separator, even on Windows, we need OS-agnostic path joining here\n\tf, err := presetsFS.Open(path.Join(\"presets\", name+\".yaml\"))\n\tif err != nil {\n\t\tpanic(err) // should not fail\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tvar schema Schema\n\n\tif err := yaml.NewDecoder(f).Decode(&schema); err != nil {\n\t\tpanic(err) // should not fail\n\t}\n\n\tif err := schema.Compile(); err != nil {\n\t\tpanic(err) // should not fail\n\t}\n\n\treturn schema\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/presets_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroupsprinter_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/cgroupsprinter\"\n)\n\nfunc TestGetPresetNames(t *testing.T) {\n\tassert.Equal(t, []string{\"cpu\", \"cpuset\", \"io\", \"memory\", \"process\", \"psi\", \"swap\"}, cgroupsprinter.GetPresetNames())\n}\n\nfunc TestGetPreset(t *testing.T) {\n\tfor _, name := range cgroupsprinter.GetPresetNames() {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tassert.NotEmpty(t, cgroupsprinter.GetPreset(name))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/schema.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroupsprinter\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"text/template\"\n)\n\n// Schema defines columns for cgroups printer.\ntype Schema struct {\n\tColumns []*Column `yaml:\"columns\"`\n}\n\n// Compile compiles the templates.\nfunc (s *Schema) Compile() error {\n\tfor _, c := range s.Columns {\n\t\ttmpl, err := template.New(c.Name).Parse(c.Template)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tc.tmpl = tmpl\n\t}\n\n\treturn nil\n}\n\n// HeaderLine returns the header line.\nfunc (s *Schema) HeaderLine() string {\n\tvar headerLine strings.Builder\n\n\tfor i, c := range s.Columns {\n\t\tif i > 0 {\n\t\t\theaderLine.WriteString(\"\\t\")\n\t\t}\n\n\t\theaderLine.WriteString(c.Name)\n\t}\n\n\treturn headerLine.String()\n}\n\n// Render returns the row line.\nfunc (s *Schema) Render(data any) (string, error) {\n\tvar rowLine strings.Builder\n\n\tfor i, c := range s.Columns {\n\t\tif i > 0 {\n\t\t\trowLine.WriteString(\"\\t\")\n\t\t}\n\n\t\tif err := c.Render(&rowLine, data); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\treturn rowLine.String(), nil\n}\n\n// Column defines a column for cgroups printer.\ntype Column struct {\n\tName string `yaml:\"name\"`\n\n\tTemplate string `yaml:\"template\"` // Template is a Go template string.\n\n\ttmpl *template.Template\n}\n\n// Render the template with the data.\nfunc (c *Column) Render(out io.Writer, data any) error {\n\tif c.tmpl == nil {\n\t\tpanic(\"template is not compiled\")\n\t}\n\n\treturn c.tmpl.Execute(out, data)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/cgroupsprinter/tree.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cgroupsprinter provides functions to print cgroup information.\npackage cgroupsprinter\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n)\n\ntype edgeType string\n\nconst (\n\tedgeTypeNone edgeType = \"\"\n\tedgeTypeLink edgeType = \"│\"\n\tedgeTypeMid  edgeType = \"├──\"\n\tedgeTypeEnd  edgeType = \"└──\"\n\n\tindentSize = 3\n)\n\n// PrintNode prints the cgroup node recursively.\n//\n//nolint:gocyclo\nfunc PrintNode(name string, w io.Writer, schema *Schema, node, parent *cgroups.Node, level int, levelsEnded []int, lastNode, treeRoot bool) error {\n\tvar prefix strings.Builder\n\n\tfor i := range level {\n\t\tif slices.Index(levelsEnded, i) != -1 {\n\t\t\tprefix.WriteString(strings.Repeat(\" \", indentSize+1))\n\t\t} else {\n\t\t\tprefix.WriteString(string(edgeTypeLink) + strings.Repeat(\" \", indentSize))\n\t\t}\n\t}\n\n\tvar edge edgeType\n\n\tswitch {\n\tcase treeRoot:\n\t\tedge = edgeTypeNone\n\tcase lastNode:\n\t\tedge = edgeTypeEnd\n\tdefault:\n\t\tedge = edgeTypeMid\n\t}\n\n\trowData, err := schema.Render(struct {\n\t\t*cgroups.Node\n\n\t\tParent *cgroups.Node\n\t}{\n\t\tNode:   node,\n\t\tParent: parent,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = fmt.Fprintf(w, \"%s%s%s\\t%s\\n\", prefix.String(), edge, name, rowData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tchildren := node.SortedChildren()\n\n\tif lastNode {\n\t\tlevelsEnded = append(levelsEnded, level)\n\t}\n\n\tif !treeRoot {\n\t\tlevel++\n\t}\n\n\tfor i, child := range children {\n\t\tlast := i == len(children)-1\n\n\t\tif err = PrintNode(child, w, schema, node.Children[child], node, level, levelsEnded, last, false); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/ryanuber/go-glob\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// configCmd represents the config command.\nvar configCmd = &cobra.Command{\n\tUse:   \"config\",\n\tShort: \"Manage the client configuration file (talosconfig)\",\n\tLong:  ``,\n}\n\nfunc openConfigAndContext(context string) (*clientconfig.Config, error) {\n\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading config: %w\", err)\n\t}\n\n\tif context == \"\" {\n\t\tcontext = c.Context\n\t}\n\n\tif context == \"\" {\n\t\treturn nil, errors.New(\"no context is set\")\n\t}\n\n\tif _, ok := c.Contexts[context]; !ok {\n\t\treturn nil, fmt.Errorf(\"context %q is not defined\", context)\n\t}\n\n\treturn c, nil\n}\n\n// configEndpointCmd represents the `config endpoint` command.\nvar configEndpointCmd = &cobra.Command{\n\tUse:     \"endpoint <endpoint>...\",\n\tAliases: []string{\"endpoints\"},\n\tShort:   \"Set the endpoint(s) for the current context\",\n\tLong:    ``,\n\tArgs:    cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tc, err := openConfigAndContext(\"\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor i := range args {\n\t\t\targs[i] = strings.TrimSpace(args[i])\n\t\t}\n\n\t\tctxData, err := getContextData(c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctxData.Endpoints = args\n\n\t\tif err := c.Save(GlobalArgs.Talosconfig); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\n// configNodeCmd represents the `config node` command.\nvar configNodeCmd = &cobra.Command{\n\tUse:     \"node <endpoint>...\",\n\tAliases: []string{\"nodes\"},\n\tShort:   \"Set the node(s) for the current context\",\n\tLong:    ``,\n\tArgs:    cobra.ArbitraryArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tc, err := openConfigAndContext(\"\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor i := range args {\n\t\t\targs[i] = strings.TrimSpace(args[i])\n\t\t}\n\n\t\tctxData, err := getContextData(c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctxData.Nodes = args\n\n\t\tif err := c.Save(GlobalArgs.Talosconfig); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\n// configContextCmd represents the `config context` command.\nvar configContextCmd = &cobra.Command{\n\tUse:     \"context <context>\",\n\tShort:   \"Set the current context\",\n\tAliases: []string{\"use-context\"},\n\tLong:    ``,\n\tArgs:    cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tcontext := args[0]\n\n\t\tc, err := openConfigAndContext(context)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tc.Context = context\n\n\t\tif err := c.Save(GlobalArgs.Talosconfig); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n\tValidArgsFunction: CompleteConfigContext,\n}\n\n// configAddCmdFlags represents the `config add` command flags.\nvar configAddCmdFlags struct {\n\tca  string\n\tcrt string\n\tkey string\n}\n\n// configAddCmd represents the `config add` command.\nvar configAddCmd = &cobra.Command{\n\tUse:   \"add <context>\",\n\tShort: \"Add a new context\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tcontext := args[0]\n\n\t\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config: %w\", err)\n\t\t}\n\n\t\tnewContext := &clientconfig.Context{}\n\n\t\tif configAddCmdFlags.ca != \"\" {\n\t\t\tvar caBytes []byte\n\n\t\t\tcaBytes, err = os.ReadFile(configAddCmdFlags.ca)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading CA: %w\", err)\n\t\t\t}\n\n\t\t\tnewContext.CA = base64.StdEncoding.EncodeToString(caBytes)\n\t\t}\n\n\t\terr = checkAndSetCrtAndKey(newContext)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif c.Contexts == nil {\n\t\t\tc.Contexts = map[string]*clientconfig.Context{}\n\t\t}\n\n\t\tc.Contexts[context] = newContext\n\t\tif err := c.Save(GlobalArgs.Talosconfig); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\n// configRemoveCmdFlags represents the `config remove` command flags.\nvar configRemoveCmdFlags struct {\n\tnoconfirm bool\n\tdry       bool\n}\n\n// configRemoveCmd represents the `config remove` command.\nvar configRemoveCmd = &cobra.Command{\n\tUse:   \"remove <context>\",\n\tShort: \"Remove contexts\",\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tpattern := args[0]\n\t\tif pattern == \"\" {\n\t\t\treturn errors.New(\"no context specified\")\n\t\t}\n\n\t\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config: %w\", err)\n\t\t}\n\n\t\tif len(c.Contexts) == 0 {\n\t\t\treturn errors.New(\"no contexts defined\")\n\t\t}\n\n\t\tmatches := sortInPlace(maps.Keys(\n\t\t\tmaps.Filter(c.Contexts, func(context string, _ *clientconfig.Context) bool {\n\t\t\t\treturn glob.Glob(pattern, context)\n\t\t\t}),\n\t\t))\n\t\tif len(matches) == 0 {\n\t\t\treturn fmt.Errorf(\"no contexts matched %q\", pattern)\n\t\t}\n\n\t\t// we want to prevent file updates in case there were no changes\n\t\tnoChanges := true\n\n\t\tfor _, match := range matches {\n\t\t\tif match == c.Context {\n\t\t\t\tfmt.Fprintf(\n\t\t\t\t\tos.Stderr,\n\t\t\t\t\t\"skipping removal of current context %q, please change it to another before removing\\n\",\n\t\t\t\t\tmatch,\n\t\t\t\t)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !configRemoveCmdFlags.noconfirm {\n\t\t\t\tprompt := fmt.Sprintf(\"remove context %q\", match)\n\n\t\t\t\tif !helpers.Confirm(prompt + \"?\") {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"removing context %q\\n\", match)\n\t\t\t}\n\n\t\t\tnoChanges = false\n\n\t\t\tdelete(c.Contexts, match)\n\t\t}\n\n\t\tif configRemoveCmdFlags.dry || noChanges {\n\t\t\treturn nil\n\t\t}\n\n\t\terr = c.Save(GlobalArgs.Talosconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n\tValidArgsFunction: CompleteConfigContext,\n}\n\nfunc sortInPlace(slc []string) []string {\n\tslices.Sort(slc)\n\n\treturn slc\n}\n\nfunc checkAndSetCrtAndKey(configContext *clientconfig.Context) error {\n\tcrt := configAddCmdFlags.crt\n\tkey := configAddCmdFlags.key\n\n\tif crt == \"\" && key == \"\" {\n\t\treturn nil\n\t}\n\n\tif crt == \"\" || key == \"\" {\n\t\treturn errors.New(\"if either the 'crt' or 'key' flag is specified, both are required\")\n\t}\n\n\tcrtBytes, err := os.ReadFile(crt)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading certificate: %w\", err)\n\t}\n\n\tconfigContext.Crt = base64.StdEncoding.EncodeToString(crtBytes)\n\n\tkeyBytes, err := os.ReadFile(key)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading key: %w\", err)\n\t}\n\n\tconfigContext.Key = base64.StdEncoding.EncodeToString(keyBytes)\n\n\treturn nil\n}\n\n// configGetContextsCmd represents the `config contexts` command.\nvar configGetContextsCmd = &cobra.Command{\n\tUse:     \"contexts\",\n\tShort:   \"List defined contexts\",\n\tAliases: []string{\"get-contexts\"},\n\tLong:    ``,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config: %w\", err)\n\t\t}\n\n\t\tkeys := maps.Keys(c.Contexts)\n\t\tslices.Sort(keys)\n\n\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\tfmt.Fprintln(w, \"CURRENT\\tNAME\\tENDPOINTS\\tNODES\")\n\n\t\tfor _, name := range keys {\n\t\t\tcontext := c.Contexts[name]\n\n\t\t\tvar (\n\t\t\t\tcurrent   string\n\t\t\t\tendpoints string\n\t\t\t\tnodes     string\n\t\t\t)\n\n\t\t\tif name == c.Context {\n\t\t\t\tcurrent = \"*\"\n\t\t\t}\n\n\t\t\tendpoints = strings.Join(context.Endpoints, \",\")\n\t\t\tif len(context.Nodes) > 3 {\n\t\t\t\tnodes = strings.Join(context.Nodes[:3], \",\")\n\t\t\t\tnodes += \"...\"\n\t\t\t} else {\n\t\t\t\tnodes = strings.Join(context.Nodes, \",\")\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\n\", current, name, endpoints, nodes)\n\t\t}\n\n\t\treturn w.Flush()\n\t},\n}\n\n// configMergeCmd represents the `config merge` command.\nvar configMergeCmd = &cobra.Command{\n\tUse:   \"merge <from>\",\n\tShort: \"Merge additional contexts from another client configuration file\",\n\tLong:  \"Contexts with the same name are renamed while merging configs.\",\n\tArgs:  cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tfrom := args[0]\n\n\t\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config: %w\", err)\n\t\t}\n\n\t\tsecondConfig, err := clientconfig.Open(from)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading config: %w\", err)\n\t\t}\n\n\t\trenames := c.Merge(secondConfig)\n\t\tfor _, rename := range renames {\n\t\t\tfmt.Fprintf(os.Stderr, \"renamed talosconfig context %s\\n\", rename.String())\n\t\t}\n\n\t\tif err := c.Save(GlobalArgs.Talosconfig); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\n// configNewCmdFlags represents the `config new` command flags.\nvar configNewCmdFlags struct {\n\troles  []string\n\tcrtTTL time.Duration\n}\n\n// configNewCmd represents the `config new` command.\nvar configNewCmd = &cobra.Command{\n\tUse:   \"new [<path>]\",\n\tShort: \"Generate a new client configuration file\",\n\tArgs:  cobra.RangeArgs(0, 1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif len(args) == 0 {\n\t\t\targs = []string{\"talosconfig\"}\n\t\t}\n\n\t\tpath := args[0]\n\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"talosconfig\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\troles, unknownRoles := role.Parse(configNewCmdFlags.roles)\n\t\t\tif len(unknownRoles) != 0 {\n\t\t\t\treturn fmt.Errorf(\"unknown roles: %s\", strings.Join(unknownRoles, \", \"))\n\t\t\t}\n\n\t\t\tif _, err := os.Stat(path); err == nil {\n\t\t\t\treturn fmt.Errorf(\"talosconfig file already exists: %q\", path)\n\t\t\t}\n\n\t\t\tresp, err := c.GenerateClientConfiguration(ctx, &machineapi.GenerateClientConfigurationRequest{\n\t\t\t\tRoles:  roles.Strings(),\n\t\t\t\tCrtTtl: durationpb.New(configNewCmdFlags.crtTTL),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif l := len(resp.Messages); l != 1 {\n\t\t\t\tpanic(fmt.Sprintf(\"expected 1 message, got %d\", l))\n\t\t\t}\n\n\t\t\tconfig, err := clientconfig.FromBytes(resp.Messages[0].Talosconfig)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// make the new config immediately useful\n\t\t\tconfig.Contexts[config.Context].Endpoints = c.GetEndpoints()\n\n\t\t\treturn config.Save(path)\n\t\t})\n\t},\n}\n\n// configNewCmd represents the `config info` command output template.\nvar configInfoCmdTemplate = template.Must(template.New(\"configInfoCmdTemplate\").\n\tFuncs(template.FuncMap{\"join\": strings.Join}).\n\tOption(\"missingkey=error\").\n\tParse(strings.TrimSpace(`\nCurrent context:     {{ .Context }}\nNodes:               {{ if .Nodes }}{{ join .Nodes \", \" }}{{ else }}not defined{{ end }}\nEndpoints:           {{ if .Endpoints }}{{ join .Endpoints \", \" }}{{ else }}not defined{{ end }}\n{{- if .Roles }}\nRoles:               {{ join .Roles \", \" }}{{ end }}\n{{- if .CertTTL }}\nCertificate expires: {{ .CertTTL }} ({{ .CertNotAfter }}){{ end }}\n`)))\n\ntype talosconfigInfo struct {\n\tContext      string   `json:\"context\" yaml:\"context\"`\n\tNodes        []string `json:\"nodes\" yaml:\"nodes\"`\n\tEndpoints    []string `json:\"endpoints\" yaml:\"endpoints\"`\n\tRoles        []string `json:\"roles\" yaml:\"roles\"`\n\tCertTTL      string   `json:\"certTTL\" yaml:\"certTTL\"`\n\tCertNotAfter string   `json:\"certNotAfter\" yaml:\"certNotAfter\"`\n}\n\n// configInfo returns talosct config info.\nfunc configInfo(config *clientconfig.Config, now time.Time) (talosconfigInfo, error) {\n\tcfgContext, err := getContextData(config)\n\tif err != nil {\n\t\treturn talosconfigInfo{}, err\n\t}\n\n\tvar (\n\t\tcertTTL, certNotAfter string\n\t\troles                 role.Set\n\t)\n\n\tif cfgContext.Crt != \"\" {\n\t\tvar b []byte\n\n\t\tb, err = base64.StdEncoding.DecodeString(cfgContext.Crt)\n\t\tif err != nil {\n\t\t\treturn talosconfigInfo{}, err\n\t\t}\n\n\t\tblock, _ := pem.Decode(b)\n\t\tif block == nil {\n\t\t\treturn talosconfigInfo{}, errors.New(\"error decoding PEM\")\n\t\t}\n\n\t\tvar crt *x509.Certificate\n\n\t\tcrt, err = x509.ParseCertificate(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn talosconfigInfo{}, err\n\t\t}\n\n\t\troles, _ = role.Parse(crt.Subject.Organization)\n\n\t\tcertTTL = humanize.RelTime(crt.NotAfter, now, \"ago\", \"from now\")\n\t\tcertNotAfter = crt.NotAfter.UTC().Format(\"2006-01-02\")\n\t}\n\n\treturn talosconfigInfo{\n\t\tContext:      config.Context,\n\t\tNodes:        cfgContext.Nodes,\n\t\tEndpoints:    cfgContext.Endpoints,\n\t\tRoles:        roles.Strings(),\n\t\tCertTTL:      certTTL,\n\t\tCertNotAfter: certNotAfter,\n\t}, nil\n}\n\n// configInfoCommand implements `config info` command logic.\nfunc configInfoCommand(config *clientconfig.Config, now time.Time) (string, error) {\n\tinfo, err := configInfo(config, now)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvar res bytes.Buffer\n\n\terr = configInfoCmdTemplate.Execute(&res, info)\n\n\treturn res.String() + \"\\n\", err\n}\n\nvar configInfoCmdFlags struct {\n\toutput string\n}\n\n// configInfoCmd represents the `config info` command.\nvar configInfoCmd = &cobra.Command{\n\tUse:   \"info\",\n\tShort: \"Show information about the current context\",\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tc, err := openConfigAndContext(\"\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch configInfoCmdFlags.output {\n\t\tcase \"text\":\n\t\t\tres, err := configInfoCommand(c, time.Now())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Print(res)\n\n\t\t\treturn nil\n\t\tcase \"json\":\n\t\t\tinfo, err := configInfo(c, time.Now())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tenc := json.NewEncoder(os.Stdout)\n\t\t\tenc.SetIndent(\"\", \"  \")\n\n\t\t\treturn enc.Encode(&info)\n\t\tcase \"yaml\":\n\t\t\tinfo, err := configInfo(c, time.Now())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn yaml.NewEncoder(os.Stdout).Encode(&info)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown output format: %q\", configInfoCmdFlags.output)\n\t\t}\n\t},\n}\n\n// CompleteConfigContext represents tab completion for `--context`\n// argument and `config [context|remove]` command.\nfunc CompleteConfigContext(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {\n\tc, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\tif err != nil {\n\t\treturn nil, cobra.ShellCompDirectiveError\n\t}\n\n\tcontextnames := maps.Keys(c.Contexts)\n\tslices.Sort(contextnames)\n\n\treturn contextnames, cobra.ShellCompDirectiveNoFileComp\n}\n\nfunc init() {\n\tconfigCmd.AddCommand(\n\t\tconfigEndpointCmd,\n\t\tconfigNodeCmd,\n\t\tconfigContextCmd,\n\t\tconfigAddCmd,\n\t\tconfigRemoveCmd,\n\t\tconfigGetContextsCmd,\n\t\tconfigMergeCmd,\n\t\tconfigNewCmd,\n\t\tconfigInfoCmd,\n\t)\n\n\tconfigAddCmd.Flags().StringVar(&configAddCmdFlags.ca, \"ca\", \"\", \"the path to the CA certificate\")\n\tconfigAddCmd.Flags().StringVar(&configAddCmdFlags.crt, \"crt\", \"\", \"the path to the certificate\")\n\tconfigAddCmd.Flags().StringVar(&configAddCmdFlags.key, \"key\", \"\", \"the path to the key\")\n\n\tconfigRemoveCmd.Flags().BoolVarP(\n\t\t&configRemoveCmdFlags.noconfirm, \"noconfirm\", \"y\", false,\n\t\t\"do not ask for confirmation\",\n\t)\n\tconfigRemoveCmd.Flags().BoolVar(\n\t\t&configRemoveCmdFlags.dry, \"dry-run\", false, \"dry run\",\n\t)\n\n\tconfigNewCmd.Flags().StringSliceVar(&configNewCmdFlags.roles, \"roles\", role.MakeSet(role.Admin).Strings(), \"roles\")\n\tconfigNewCmd.Flags().DurationVar(&configNewCmdFlags.crtTTL, \"crt-ttl\", constants.TalosAPIDefaultCertificateValidityDuration, \"certificate TTL\")\n\n\tconfigInfoCmd.Flags().StringVarP(&configInfoCmdFlags.output, \"output\", \"o\", \"text\", \"output format (json|yaml|text). Default text.\")\n\n\taddCommand(configCmd)\n}\n\nfunc getContextData(c *clientconfig.Config) (*clientconfig.Context, error) {\n\tcontextName := c.Context\n\n\tif GlobalArgs.CmdContext != \"\" {\n\t\tcontextName = GlobalArgs.CmdContext\n\t}\n\n\tctxData, ok := c.Contexts[contextName]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"context %q is not defined\", contextName)\n\t}\n\n\treturn ctxData, nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos //nolint:testpackage // to test unexported function\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\nfunc TestConfigInfoCommand(t *testing.T) {\n\tt.Parallel()\n\n\tnow := time.Date(2021, 7, 5, 22, 6, 42, 0, time.UTC)\n\n\t//nolint:lll\n\ttestCases := []struct {\n\t\tname     string\n\t\tconfig   string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"Default\",\n\t\t\tconfig: `\ncontext: no-roles\ncontexts:\n    no-roles:\n        endpoints:\n            - 172.20.1.2\n            - 172.20.1.3\n            - 172.20.1.4\n        nodes:\n            - 172.20.1.2\n        ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBblpENTFNNW0zUmNMNUZwWXVYUkRWVEFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qRXdOekExTVRFeE9ETXpXaGNOTXpFd056QXpNVEV4T0RNeldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUFPYU93TVBaaDNHaE9kd2ZtSjYxcUhheUxDakFzdGcrWlNJCmpLbVV0WXR2bzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkhLNzFyajVOTmxad1J1VgpXcFc4bkNabit2YWxNQVVHQXl0bGNBTkJBTjlMQ2d2RzltSDdka3RSRTVQTFJJT25VcTNORnZaMTl1SHF5bWttCjJwQVR2SU02cXpMS0x0NXUyWEtBVFUzcDZDQWFGVVpOMkJhVjV0amVTeXZSWkFzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJNakNCNWFBREFnRUNBaEFyalRDdnc3TElYZVRPTjFSTnhqeFNNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1UQTNNRFV4TVRFNE16TmFGdzB6TVRBM01ETXhNVEU0TXpOYU1CTXhFVEFQQmdOVgpCQW9UQ0c5ek9tRmtiV2x1TUNvd0JRWURLMlZ3QXlFQTI2bDQ0eU1ZRTAvZUVUVEtsQXBTZGhlMEgzOEhGRDBnClh1Q2VFdWZ0YnZpalVqQlFNQTRHQTFVZER3RUIvd1FFQXdJSGdEQWRCZ05WSFNVRUZqQVVCZ2dyQmdFRkJRY0QKQVFZSUt3WUJCUVVIQXdJd0h3WURWUjBqQkJnd0ZvQVVjcnZXdVBrMDJWbkJHNVZhbGJ5Y0ptZjY5cVV3QlFZRApLMlZ3QTBFQXhlN3Qrb2tZUURoNlZOQ0ZLenlqTmVuWkhmQ1MrRTdFdUYyVC9kcjRkU3JXcko2eXYvaE5ZalJqCnhNb0grU3dLak5kU2trNnJhWHdWb0ZwY3JraWRBdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJQWhmdzFISzBKVFgzVjh2K09wZ2J5dXQ2VzN0OWhVaGczQW5pK043WTFTNAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n`,\n\t\t\texpected: strings.TrimSpace(`\nCurrent context:     no-roles\nNodes:               172.20.1.2\nEndpoints:           172.20.1.2, 172.20.1.3, 172.20.1.4\nRoles:               os:admin\nCertificate expires: 10 years from now (2031-07-03)\n`) + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"NoRoles\",\n\t\t\tconfig: `\ncontext: no-roles\ncontexts:\n    no-roles:\n        endpoints:\n            - 172.20.1.2\n        ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBblpENTFNNW0zUmNMNUZwWXVYUkRWVEFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qRXdOekExTVRFeE9ETXpXaGNOTXpFd056QXpNVEV4T0RNeldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUFPYU93TVBaaDNHaE9kd2ZtSjYxcUhheUxDakFzdGcrWlNJCmpLbVV0WXR2bzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkhLNzFyajVOTmxad1J1VgpXcFc4bkNabit2YWxNQVVHQXl0bGNBTkJBTjlMQ2d2RzltSDdka3RSRTVQTFJJT25VcTNORnZaMTl1SHF5bWttCjJwQVR2SU02cXpMS0x0NXUyWEtBVFUzcDZDQWFGVVpOMkJhVjV0amVTeXZSWkFzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJIekNCMHFBREFnRUNBaEFpcVA1MjN0NkJWNWZmNTVhUlBOWW1NQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1UQTNNRFV4TVRNeE5UWmFGdzB6TVRBM01ETXhNVE14TlRaYU1BQXdLakFGQmdNcgpaWEFESVFCNTlmL2h0MG1tOUJqL3I4b0VsdjFUU3VVcG5kazlwang3Mm10MUpxZGEyNk5TTUZBd0RnWURWUjBQCkFRSC9CQVFEQWdlQU1CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFmQmdOVkhTTUUKR0RBV2dCUnl1OWE0K1RUWldjRWJsVnFWdkp3bVovcjJwVEFGQmdNclpYQURRUUNXUnAzcHB6YkM5ZzlmWC9RRgp0ZGg1eFY2YVYvdTVVdTFkU05TNmQ5VFFlUE00c1NXL1U5UGViNEpvK3Uzd1lPblBlb3huSWoxNzJOdTBQTm81CldPa0MKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJREJybmN1UEV2RHFPRjhqWWJMNUxvNWhSUkZ2cXBPVWZud2RMOHRPdzdFRgotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n`,\n\t\t\texpected: strings.TrimSpace(`\nCurrent context:     no-roles\nNodes:               not defined\nEndpoints:           172.20.1.2\nCertificate expires: 10 years from now (2031-07-03)\n`) + \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"FutureRole\",\n\t\t\tconfig: `\ncontext: future-role\ncontexts:\n    future-role:\n        ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBblpENTFNNW0zUmNMNUZwWXVYUkRWVEFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qRXdOekExTVRFeE9ETXpXaGNOTXpFd056QXpNVEV4T0RNeldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUFPYU93TVBaaDNHaE9kd2ZtSjYxcUhheUxDakFzdGcrWlNJCmpLbVV0WXR2bzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkhLNzFyajVOTmxad1J1VgpXcFc4bkNabit2YWxNQVVHQXl0bGNBTkJBTjlMQ2d2RzltSDdka3RSRTVQTFJJT25VcTNORnZaMTl1SHF5bWttCjJwQVR2SU02cXpMS0x0NXUyWEtBVFUzcDZDQWFGVVpOMkJhVjV0amVTeXZSWkFzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJNekNCNXFBREFnRUNBaEFQL1MrVGx0WTBHdGk5Q1g0UDNVZStNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1UQTNNRFV4TVRRek1qRmFGdzB6TVRBM01ETXhNVFF6TWpGYU1CUXhFakFRQmdOVgpCQW9UQ1c5ek9tWjFkSFZ5WlRBcU1BVUdBeXRsY0FNaEFLck04NmtPYm1MdGw5OVdpdzFFL29pdnl2YXVqVmNkCmlQTk82TVhQNGxEMm8xSXdVREFPQmdOVkhROEJBZjhFQkFNQ0I0QXdIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUgKQXdFR0NDc0dBUVVGQndNQ01COEdBMVVkSXdRWU1CYUFGSEs3MXJqNU5ObFp3UnVWV3BXOG5DWm4rdmFsTUFVRwpBeXRsY0FOQkFDSno3NTlGeVFJMXlIWTJNRG9vZDNrZjdZeG9HRG1Hem1nNllqRHJueXAxWGpaQ3o1Q1RQbm9jCjhxWlAyTXE5MDJnOXZSSUh1dm84N0NIZjJacTNGZ1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJS1RCRDIyZDBLVnNTek5iSkNBdjNObUVnL1VWOTk4SHZvY2NGb1lDOEJ1bAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n`,\n\t\t\texpected: strings.TrimSpace(`\nCurrent context:     future-role\nNodes:               not defined\nEndpoints:           not defined\nRoles:               os:future\nCertificate expires: 10 years from now (2031-07-03)\n`) + \"\\n\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tconfig, err := clientconfig.FromString(tc.config)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tactual, err := configInfoCommand(config, now)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/conformance.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/cluster/hydrophone\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// conformanceCmd represents the conformance command.\nvar conformanceCmd = &cobra.Command{\n\tUse:   \"conformance\",\n\tShort: \"Run conformance tests\",\n\tLong:  ``,\n}\n\nvar conformanceKubernetesCmdFlags struct {\n\tmode string\n}\n\nvar conformanceKubernetesCmd = &cobra.Command{\n\tUse:     \"kubernetes\",\n\tAliases: []string{\"k8s\"},\n\tShort:   \"Run Kubernetes conformance tests\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tclientProvider := &cluster.ConfigClientProvider{\n\t\t\t\tDefaultClient: c,\n\t\t\t}\n\t\t\tdefer clientProvider.Close() //nolint:errcheck\n\n\t\t\tstate := struct {\n\t\t\t\tcluster.K8sProvider\n\t\t\t}{\n\t\t\t\tK8sProvider: &cluster.KubernetesClient{\n\t\t\t\t\tClientProvider: clientProvider,\n\t\t\t\t\tForceEndpoint:  healthCmdFlags.forceEndpoint,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tswitch conformanceKubernetesCmdFlags.mode {\n\t\t\tcase \"fast\":\n\t\t\t\treturn hydrophone.FastConformance(ctx, &state)\n\t\t\tcase \"certified\":\n\t\t\t\treturn hydrophone.CertifiedConformance(ctx, &state)\n\t\t\tcase \"network-policy\":\n\t\t\t\treturn hydrophone.NetworkPolicies(ctx, &state)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unsupported conformance mode %v\", conformanceKubernetesCmdFlags.mode)\n\t\t\t}\n\t\t})\n\t},\n}\n\nfunc init() {\n\tconformanceKubernetesCmd.Flags().StringVar(&conformanceKubernetesCmdFlags.mode, \"mode\", \"fast\", \"conformance test mode: [fast, certified, network-policy]\")\n\tconformanceCmd.AddCommand(conformanceKubernetesCmd)\n\taddCommand(conformanceCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/containers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// containersCmd represents the processes command.\nvar containersCmd = &cobra.Command{\n\tUse:     \"containers\",\n\tAliases: []string{\"c\"},\n\tShort:   \"List containers\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tnamespace string\n\t\t\t\tdriver    common.ContainerDriver\n\t\t\t)\n\n\t\t\tif kubernetesFlag {\n\t\t\t\tnamespace = constants.K8sContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CRI\n\t\t\t} else {\n\t\t\t\tnamespace = constants.SystemContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CONTAINERD\n\t\t\t}\n\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.Containers(ctx, namespace, driver, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting container list: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn containerRender(&remotePeer, resp)\n\t\t})\n\t},\n}\n\nfunc containerRender(remotePeer *peer.Peer, resp *machineapi.ContainersResponse) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tNAMESPACE\\tID\\tIMAGE\\tPID\\tSTATUS\")\n\n\tdefaultNode := client.AddrFromPeer(remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tslices.SortFunc(msg.Containers, func(a, b *machineapi.ContainerInfo) int { return strings.Compare(a.Id, b.Id) })\n\n\t\tfor _, p := range msg.Containers {\n\t\t\tdisplay := p.Id\n\t\t\tif p.Id != p.PodId {\n\t\t\t\t// container in a sandbox\n\t\t\t\tdisplay = \"└─ \" + display\n\t\t\t}\n\n\t\t\tnode := defaultNode\n\n\t\t\tif msg.Metadata != nil {\n\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\t%d\\t%s\\n\", node, p.Namespace, display, p.Image, p.Pid, p.Status)\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\nfunc init() {\n\tcontainersCmd.Flags().BoolVarP(&kubernetesFlag, \"kubernetes\", \"k\", false, \"use the k8s.io containerd namespace\")\n\n\tcontainersCmd.Flags().Bool(\"use-cri\", false, \"use the CRI driver\")\n\tcontainersCmd.Flags().MarkHidden(\"use-cri\") //nolint:errcheck\n\n\taddCommand(containersCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/copy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// cpCmd represents the cp command.\nvar cpCmd = &cobra.Command{\n\tUse:     \"copy <src-path> -|<local-path>\",\n\tAliases: []string{\"cp\"},\n\tShort:   \"Copy data out from the node\",\n\tLong: `Creates an .tar.gz archive at the node starting at <src-path> and\nstreams it back to the client.\n\nIf '-' is given for <local-path>, archive is written to stdout.\nOtherwise archive is extracted to <local-path> which should be an empty directory or\ntalosctl creates a directory if <local-path> doesn't exist. Command doesn't preserve\nownership and access mode for the files in extract mode, while  streamed .tar archive\ncaptures ownership and permission bits.`,\n\tArgs: cobra.ExactArgs(2),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tswitch len(args) {\n\t\tcase 0:\n\t\t\treturn completePathFromNode(toComplete), cobra.ShellCompDirectiveNoFileComp\n\t\tcase 1:\n\t\t\treturn nil, cobra.ShellCompDirectiveDefault\n\t\t}\n\n\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"copy\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr, err := c.Copy(ctx, args[0])\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying: %w\", err)\n\t\t\t}\n\n\t\t\tlocalPath := args[1]\n\n\t\t\tif localPath == \"-\" {\n\t\t\t\t_, err = io.Copy(os.Stdout, r)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlocalPath = filepath.Clean(localPath)\n\n\t\t\tfi, err := os.Stat(localPath)\n\t\t\tif err == nil && !fi.IsDir() {\n\t\t\t\treturn fmt.Errorf(\"local path %q should be a directory\", args[1])\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\treturn fmt.Errorf(\"failed to stat local path: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = os.MkdirAll(localPath, 0o777); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error creating local path %q: %w\", localPath, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn helpers.ExtractTarGz(localPath, r)\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(cpCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/crashdump.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar crashdumpCmdFlags struct {\n\tclusterState clusterNodes\n}\n\n// crashdumpCmd represents the crashdump command.\nvar crashdumpCmd = &cobra.Command{\n\tUse:    \"crashdump\",\n\tShort:  \"Dump debug information about the cluster\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\treturn errors.New(\"`talosctl crashdump` is deprecated, please use `talosctl support` instead\")\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(crashdumpCmd)\n\tcrashdumpCmd.Flags().StringVar(&crashdumpCmdFlags.clusterState.InitNode, \"init-node\", \"\", \"specify IPs of init node\")\n\tcrashdumpCmd.Flags().StringSliceVar(&crashdumpCmdFlags.clusterState.ControlPlaneNodes, \"control-plane-nodes\", nil, \"specify IPs of control plane nodes\")\n\tcrashdumpCmd.Flags().StringSliceVar(&crashdumpCmdFlags.clusterState.WorkerNodes, \"worker-nodes\", nil, \"specify IPs of worker nodes\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/dashboard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar dashboardCmdFlags struct {\n\tinterval time.Duration\n}\n\n// dashboardCmd represents the monitor command.\nvar dashboardCmd = &cobra.Command{\n\tUse:   \"dashboard\",\n\tShort: \"Cluster dashboard with node overview, logs and real-time metrics\",\n\tLong: `Provide a text-based UI to navigate node overview, logs and real-time metrics.\n\nKeyboard shortcuts:\n\n - h, <Left> - switch one node to the left\n - l, <Right> - switch one node to the right\n - j, <Down> - scroll logs/process list down\n - k, <Up> - scroll logs/process list up\n - <C-d> - scroll logs/process list half page down\n - <C-u> - scroll logs/process list half page up\n - <C-f> - scroll logs/process list one page down\n - <C-b> - scroll logs/process list one page up\n`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\treturn dashboard.Run(ctx, c,\n\t\t\t\tdashboard.WithInterval(dashboardCmdFlags.interval),\n\t\t\t\tdashboard.WithScreens(dashboard.ScreenSummary, dashboard.ScreenMonitor),\n\t\t\t\tdashboard.WithAllowExitKeys(true),\n\t\t\t)\n\t\t})\n\t},\n}\n\nfunc init() {\n\tdashboardCmd.Flags().DurationVarP(&dashboardCmdFlags.interval, \"update-interval\", \"d\", 3*time.Second, \"interval between updates\")\n\taddCommand(dashboardCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !windows\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/term\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nvar debugCmdFlags struct {\n\timageCmdFlagsType\n\n\targs []string\n}\n\nfunc init() {\n\tdebugCmd.Flags().StringSliceVar(&debugCmdFlags.args, \"args\", nil, \"arguments to pass to the container\")\n\tdebugCmd.Flags().StringVar(&debugCmdFlags.namespace, \"namespace\", \"inmem\", \"namespace to use: `system` (CRI containerd) or `inmem` for in-memory containerd instance\")\n\n\taddCommand(debugCmd)\n}\n\n// debugCmd represents the debug command.\nvar debugCmd = &cobra.Command{\n\tUse:   \"debug <image-tar-path|image ref> [args]\",\n\tShort: \"Run a debug container from an image archive or reference\",\n\tExample: `  # Run a debug container from a local tar archive (image will be loaded into Talos from the archive)\n    talosctl debug ./debug-tools.tar --args /bin/sh\n\n  # Run a debug container from an image reference (Talos will pull the image if not present)\n    talosctl debug docker.io/library/alpine:latest --args /bin/sh`,\n\n\tArgs: cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClientAndNodes(func(ctx context.Context, c *client.Client, nodes []string) error {\n\t\t\tif len(nodes) != 1 {\n\t\t\t\treturn fmt.Errorf(\"expected exactly one node, got %v\", nodes)\n\t\t\t}\n\n\t\t\tctx = client.WithNode(ctx, nodes[0])\n\n\t\t\trep := reporter.New()\n\n\t\t\tctrdInstance, err := debugCmdFlags.containerdInstance()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// verify if we are sending a tarball or pulling an image\n\t\t\t_, err = os.Stat(args[0])\n\t\t\tif err != nil && !os.IsNotExist(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to stat image argument: %w\", err)\n\t\t\t}\n\n\t\t\tvar imgName string\n\n\t\t\tif err == nil {\n\t\t\t\timgName, err = imageImportInternal(ctx, c, ctrdInstance, nodes[0], args[0], rep)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to import image: %w\", err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpullResult, err := imagePullInternal(ctx, c, ctrdInstance, nodes, args[0], rep)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to pull image: %w\", err)\n\t\t\t\t}\n\n\t\t\t\timgName = pullResult[nodes[0]]\n\t\t\t}\n\n\t\t\t// no easy way to disable hooking up signal handling to the command context,\n\t\t\t// so instead save this context and use a new one from here on out.\n\t\t\t//\n\t\t\t// new context so that SIGINT/similar won't immediately cancel streaming\n\t\t\t// and instead allow us to forward the signal to the container\n\t\t\tctx = context.WithoutCancel(ctx)\n\n\t\t\tctx, cancel := context.WithCancel(ctx)\n\t\t\tdefer cancel()\n\n\t\t\trunStream, err := c.DebugClient.ContainerRun(ctx,\n\t\t\t\tgrpc.MaxCallRecvMsgSize(4*1024*1024), // 4 MiB\n\t\t\t\tgrpc.MaxCallSendMsgSize(4*1024*1024),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create debug container stream: %w\", err)\n\t\t\t}\n\n\t\t\treturn runContainer(ctx, rep, runStream, imgName, debugCmdFlags.args, ctrdInstance)\n\t\t})\n\t},\n}\n\n//nolint:gocyclo,cyclop\nfunc runContainer(\n\tctx context.Context,\n\trep *reporter.Reporter,\n\tstream grpc.BidiStreamingClient[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse],\n\timageName string,\n\targs []string,\n\tctrdInstance *common.ContainerdInstance,\n) error { //nolint:gocyclo,cyclop\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tisTTY := term.IsTerminal(int(os.Stdin.Fd()))\n\n\terr := stream.Send(&machine.DebugContainerRunRequest{\n\t\tRequest: &machine.DebugContainerRunRequest_Spec{\n\t\t\tSpec: &machine.DebugContainerRunRequestSpec{\n\t\t\t\tContainerd: ctrdInstance,\n\t\t\t\tImageName:  imageName,\n\t\t\t\tArgs:       args,\n\t\t\t\tProfile:    machine.DebugContainerRunRequestSpec_PROFILE_PRIVILEGED,\n\t\t\t\tTty:        isTTY,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to send container spec: %w\", err)\n\t}\n\n\tif isTTY {\n\t\toldState, err := term.MakeRaw(int(os.Stdin.Fd()))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to set terminal to raw mode: %w\", err)\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif oldState != nil {\n\t\t\t\tterm.Restore(int(os.Stdin.Fd()), oldState) //nolint:errcheck\n\t\t\t}\n\t\t}()\n\t}\n\n\tvar (\n\t\tsendC    = make(chan *machine.DebugContainerRunRequest, 100)\n\t\tsendDone chan error\n\t\trecvDone = make(chan error, 1)\n\n\t\tstdinDone chan error\n\n\t\texitCode int32 = -1\n\t)\n\n\tsigHandler(ctx, sendC)\n\n\tstdinDone = stdinReader(ctx, sendC)\n\tsendDone = sendLoop(stream, sendC)\n\n\tgo func() {\n\t\tfor {\n\t\t\tmsg, err := stream.Recv()\n\t\t\tif err != nil {\n\t\t\t\tif status.Code(err) == codes.Canceled {\n\t\t\t\t\trecvDone <- context.Canceled\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\trecvDone <- err\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch msg.Resp.(type) {\n\t\t\tcase *machine.DebugContainerRunResponse_StdoutData:\n\t\t\t\tif stdoutData := msg.GetStdoutData(); stdoutData != nil {\n\t\t\t\t\tos.Stdout.Write(stdoutData) //nolint:errcheck\n\t\t\t\t}\n\n\t\t\tcase *machine.DebugContainerRunResponse_ExitCode:\n\t\t\t\texitCode = msg.GetExitCode()\n\n\t\t\t\trecvDone <- io.EOF\n\n\t\t\t\treturn\n\n\t\t\tdefault:\n\t\t\t\tfmt.Fprintf(os.Stderr, \"unknown message type %T\\n\", msg.Resp)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// either stdin closes first, and we cancel goroutines and CloseSend this end of the stream\n\t// or recvLoop exits first (container exit or error), and we cancel goroutines and wait\n\t// for stdinReader to finish\n\tselect {\n\tcase err := <-stdinDone:\n\t\tif err != nil && err != io.EOF {\n\t\t\tfmt.Fprintf(os.Stderr, \"%s\\n\", err.Error())\n\t\t}\n\n\t\tcancel() // cancels sigHandler, stdinReader goroutines\n\n\t\tclose(sendC)\n\n\t\tif sendDone != nil {\n\t\t\t<-sendDone\n\t\t}\n\n\t\t// close send stream and wait for the server to exit\n\t\t// which will cause recvLoop to return\n\t\tif err := stream.CloseSend(); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"Warning: failed to close send stream: %v\\n\", err)\n\t\t}\n\n\t\tif recvErr := <-recvDone; recvErr != nil && recvErr != io.EOF {\n\t\t\treturn recvErr\n\t\t}\n\n\tcase err := <-recvDone:\n\t\tif err != nil {\n\t\t\tif err == context.Canceled {\n\t\t\t\trep.Report(reporter.Update{\n\t\t\t\t\tMessage: \"context canceled\",\n\t\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\t})\n\n\t\t\t\treturn nil\n\t\t\t} else if err != io.EOF {\n\t\t\t\trep.Report(reporter.Update{\n\t\t\t\t\tMessage: fmt.Sprintf(\"error: %s\", err.Error()),\n\t\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\t})\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tcancel() // sigHandler, stdinReader goroutines\n\n\t\tif stdinDone != nil {\n\t\t\t<-stdinDone\n\t\t}\n\n\t\tclose(sendC)\n\n\t\tif sendDone != nil {\n\t\t\t<-sendDone\n\t\t}\n\t}\n\n\tif exitCode != -1 && exitCode != 0 {\n\t\treturn fmt.Errorf(\"container exited with code %d\", exitCode)\n\t}\n\n\treturn nil\n}\n\nvar forwardedSignals = []os.Signal{\n\tsyscall.SIGINT,\n\tsyscall.SIGTERM,\n\tsyscall.SIGQUIT,\n\tsyscall.SIGHUP,\n\tsyscall.SIGWINCH,\n}\n\n// sigHandler registers signal handlers for the signals in `forwardedSignals`,\n// and sends them to `msgC`.\n//\n// In case the signal received is `SIGWINCH`, the size of the user's terminal\n// is queried and sent as a `DebugContainerTerminalResize` message, in order\n// to resize the container's terminal.\nfunc sigHandler(ctx context.Context, msgC chan<- *machine.DebugContainerRunRequest) {\n\tsigC := make(chan os.Signal, 1)\n\tsignal.Notify(sigC, forwardedSignals...)\n\n\tgo func() {\n\t\tdefer func() {\n\t\t\tdefer signal.Stop(sigC)\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\n\t\t\tcase sig := <-sigC:\n\t\t\t\tif sig.(syscall.Signal) == syscall.SIGWINCH {\n\t\t\t\t\tif term.IsTerminal(int(os.Stdin.Fd())) {\n\t\t\t\t\t\twidth, height, err := term.GetSize(int(os.Stdin.Fd()))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif !channel.SendWithContext(ctx, msgC,\n\t\t\t\t\t\t\t&machine.DebugContainerRunRequest{\n\t\t\t\t\t\t\t\tRequest: &machine.DebugContainerRunRequest_TermResize{\n\t\t\t\t\t\t\t\t\tTermResize: &machine.DebugContainerTerminalResize{\n\t\t\t\t\t\t\t\t\t\tWidth:  int32(width),\n\t\t\t\t\t\t\t\t\t\tHeight: int32(height),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif !channel.SendWithContext(ctx, msgC, &machine.DebugContainerRunRequest{\n\t\t\t\t\tRequest: &machine.DebugContainerRunRequest_Signal{\n\t\t\t\t\t\tSignal: int32(sig.(syscall.Signal)),\n\t\t\t\t\t},\n\t\t\t\t}) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\tsigC <- syscall.SIGWINCH // trigger an initial resize\n}\n\n// stdinReader reads from stdin and sends data to msgC.\n//\n// This implementation is unfortunately a bit complex. This is due to the fact\n// that reading from stdin is a blocking syscall, which means if we just do\n// `os.Stdin.Read` and send it's output to `msgC`, canceling `ctx` won't cause\n// this goroutine to end (that will only happen when there's something to read\n// from stdin, and the goroutine will loop around and check `ctx.Done()`.\n// To address this, wrap `os.Stdin` in a `io.Pipe()` we can cancel, and launch a\n// separate goroutine to close the pipe when `ctx` is canceled.\n// This way, as soon as `ctx` is canceled, the pipe is closed and the main\n// goroutine will get an `io.EOF` and exit.\nfunc stdinReader(ctx context.Context, msgC chan<- *machine.DebugContainerRunRequest) chan error {\n\tr, w := io.Pipe()\n\tdone := make(chan error)\n\n\tgo func() {\n\t\tio.Copy(w, os.Stdin) //nolint:errcheck\n\t\tw.Close()            //nolint:errcheck\n\t}()\n\n\tgo func() {\n\t\t<-ctx.Done()\n\t\tw.Close() //nolint:errcheck\n\t}()\n\n\tgo func() {\n\t\tbuf := make([]byte, 1024)\n\n\t\tfor {\n\t\t\tn, err := r.Read(buf)\n\t\t\tif err != nil {\n\t\t\t\tdone <- err\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif n == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !channel.SendWithContext(ctx, msgC, &machine.DebugContainerRunRequest{\n\t\t\t\tRequest: &machine.DebugContainerRunRequest_StdinData{\n\t\t\t\t\tStdinData: buf[:n],\n\t\t\t\t},\n\t\t\t}) {\n\t\t\t\tdone <- ctx.Err()\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn done\n}\n\n// sendLoop launches a goroutine that reads messages from msgC and sends them to\n// the gRPC stream.\n// The launched goroutine exits if ctx is canceled, or an error is returned while\n// sending a message to the gRPC stream.\n//\n// sendLoop returns a channel that will receive the error (or nil) when the\n// goroutine exits.\nfunc sendLoop(\n\tstream grpc.BidiStreamingClient[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse],\n\tmsgC chan *machine.DebugContainerRunRequest,\n) chan error {\n\tdone := make(chan error)\n\n\tgo func() {\n\t\tfor msg := range msgC {\n\t\t\terr := stream.Send(msg)\n\t\t\tif err != nil {\n\t\t\t\tdone <- err\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tdone <- nil\n\t}()\n\n\treturn done\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/disks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"errors\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar disksCmd = &cobra.Command{\n\tUse:    \"disks\",\n\tShort:  \"Get the list of disks from /sys/block on the machine\",\n\tLong:   ``,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn errors.New(\"`talosctl disks` is deprecated, please use `talosctl get disks`, `talosctl get systemdisk`, `talosctl get discoveredvolumes` instead\")\n\t},\n}\n\nfunc init() {\n\taddCommand(disksCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/diskusage.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strconv\"\n\t\"text/tabwriter\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar (\n\tall       bool\n\tthreshold int64\n)\n\n// duCmd represents the du command.\nvar duCmd = &cobra.Command{\n\tUse:     \"usage [path1] [path2] ... [pathN]\",\n\tAliases: []string{\"du\"},\n\tShort:   \"Retrieve a disk usage\",\n\tLong:    ``,\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) != 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\tvar completeOnlyPaths []string\n\n\t\tfor _, path := range completePathFromNode(toComplete) {\n\t\t\tif path[len(path)-1:] == \"/\" {\n\t\t\t\tcompleteOnlyPaths = append(completeOnlyPaths, path)\n\t\t\t}\n\t\t}\n\n\t\treturn completeOnlyPaths, cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar paths []string\n\n\t\t\tif len(args) == 0 {\n\t\t\t\tpaths = []string{\"/\"}\n\t\t\t} else {\n\t\t\t\tpaths = args\n\t\t\t}\n\n\t\t\tstream, err := c.DiskUsage(ctx, &machineapi.DiskUsageRequest{\n\t\t\t\tRecursionDepth: recursionDepth + 1,\n\t\t\t\tAll:            all,\n\t\t\t\tThreshold:      threshold,\n\t\t\t\tPaths:          paths,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error fetching disk usage: %s\", err)\n\t\t\t}\n\n\t\t\taddedHeader := false\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\n\t\t\tstringifySize := func(s int64) string {\n\t\t\t\tif humanizeFlag {\n\t\t\t\t\treturn humanize.Bytes(uint64(s))\n\t\t\t\t}\n\n\t\t\t\treturn strconv.FormatInt(s, 10)\n\t\t\t}\n\n\t\t\tdefer w.Flush() //nolint:errcheck\n\n\t\t\treturn helpers.ReadGRPCStream(stream, func(info *machineapi.DiskUsageInfo, node string, multipleNodes bool) error {\n\t\t\t\tif info.Error != \"\" {\n\t\t\t\t\treturn helpers.NonFatalError(errors.New(info.Error))\n\t\t\t\t}\n\n\t\t\t\tpattern := \"%s\\t%s\\n\"\n\n\t\t\t\tsize := stringifySize(info.Size)\n\n\t\t\t\targs := []any{\n\t\t\t\t\tsize, info.RelativeName,\n\t\t\t\t}\n\n\t\t\t\tif info.Metadata != nil && info.Metadata.Hostname != \"\" {\n\t\t\t\t\tmultipleNodes = true\n\t\t\t\t\tnode = info.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif !addedHeader {\n\t\t\t\t\tif multipleNodes {\n\t\t\t\t\t\tfmt.Fprintln(w, \"NODE\\tSIZE\\tNAME\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfmt.Fprintln(w, \"SIZE\\tNAME\")\n\t\t\t\t\t}\n\n\t\t\t\t\taddedHeader = true\n\t\t\t\t}\n\n\t\t\t\tif multipleNodes {\n\t\t\t\t\tpattern = \"%s\\t%s\\t%s\\n\"\n\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t},\n}\n\nfunc init() {\n\tduCmd.Flags().BoolVarP(&humanizeFlag, \"humanize\", \"H\", false, \"humanize size and time in the output\")\n\tduCmd.Flags().BoolVarP(&all, \"all\", \"a\", false, \"write counts for all files, not just directories\")\n\tduCmd.Flags().Int64VarP(&threshold, \"threshold\", \"t\", 0, \"threshold exclude entries smaller than SIZE if positive, or entries greater than SIZE if negative\")\n\tduCmd.Flags().Int32VarP(&recursionDepth, \"depth\", \"d\", 0, \"maximum recursion depth\")\n\taddCommand(duCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/dmesg.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar dmesgTail bool\n\n// dmesgCmd represents the dmesg command.\nvar dmesgCmd = &cobra.Command{\n\tUse:   \"dmesg\",\n\tShort: \"Retrieve kernel logs\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tstream, err := c.Dmesg(ctx, follow, dmesgTail)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting dmesg: %w\", err)\n\t\t\t}\n\n\t\t\treturn helpers.ReadGRPCStream(stream, func(data *common.Data, node string, multipleNodes bool) error {\n\t\t\t\tif data.Bytes != nil {\n\t\t\t\t\tfmt.Printf(\"%s: %s\", node, data.Bytes)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(dmesgCmd)\n\tdmesgCmd.Flags().BoolVarP(&follow, \"follow\", \"f\", false, \"specify if the kernel log should be streamed\")\n\tdmesgCmd.Flags().BoolVarP(&dmesgTail, \"tail\", \"\", false, \"specify if only new messages should be sent (makes sense only when combined with --follow)\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/edit.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\t\"k8s.io/kubectl/pkg/cmd/util/editor\"\n\t\"k8s.io/kubectl/pkg/cmd/util/editor/crlf\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/yamlstrip\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\nvar editCmdFlags struct {\n\thelpers.Mode\n\n\tnamespace        string\n\tdryRun           bool\n\tconfigTryTimeout time.Duration\n}\n\n//nolint:gocyclo\nfunc editFn(c *client.Client) func(context.Context, string, resource.Resource, error) error {\n\tvar (\n\t\tpath      string\n\t\tlastError string\n\t)\n\n\tedit := editor.NewDefaultEditor([]string{\n\t\t\"TALOS_EDITOR\",\n\t\t\"EDITOR\",\n\t})\n\n\treturn func(ctx context.Context, node string, mc resource.Resource, callError error) error {\n\t\tif callError != nil {\n\t\t\treturn fmt.Errorf(\"%s: %w\", node, callError)\n\t\t}\n\n\t\tif mc.Metadata().Type() != config.MachineConfigType {\n\t\t\treturn errors.New(\"only the machineconfig resource can be edited\")\n\t\t}\n\n\t\tid := mc.Metadata().ID()\n\n\t\tif id != config.ActiveID {\n\t\t\treturn nil\n\t\t}\n\n\t\tbody, err := extractMachineConfigBody(mc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tedited := body\n\n\t\tfor {\n\t\t\tvar (\n\t\t\t\tbuf bytes.Buffer\n\t\t\t\tw   io.Writer = &buf\n\t\t\t)\n\n\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\tw = crlf.NewCRLFWriter(w)\n\t\t\t}\n\n\t\t\t_, err := fmt.Fprintf(w,\n\t\t\t\t\"# Editing %s/%s at node %s\\n\", mc.Metadata().Type(), id, node,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif lastError != \"\" {\n\t\t\t\t_, err = w.Write([]byte(addEditingComment(lastError)))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_, err = w.Write(edited)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\teditedDiff := edited\n\n\t\t\tedited, path, err = edit.LaunchTempFile(fmt.Sprintf(\"%s-%s-edit-\", mc.Metadata().Type(), id), \".yaml\", &buf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer os.Remove(path) //nolint:errcheck\n\n\t\t\tedited = stripEditingComment(edited)\n\n\t\t\t// If we're retrying the loop because of an error, and no change was made in the file, short-circuit\n\t\t\tif lastError != \"\" && bytes.Equal(yamlstrip.Comments(editedDiff), yamlstrip.Comments(edited)) {\n\t\t\t\tif _, err = os.Stat(path); !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\tmessage := addEditingComment(lastError)\n\t\t\t\t\tmessage += fmt.Sprintf(\"A copy of your changes has been stored to %q\\nEdit canceled, no valid changes were saved.\\n\", path)\n\n\t\t\t\t\treturn errors.New(message)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(bytes.TrimSpace(bytes.TrimSpace(yamlstrip.Comments(edited)))) == 0 {\n\t\t\t\tfmt.Fprintln(os.Stderr, \"Apply was skipped: empty file.\")\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif bytes.Equal(edited, body) {\n\t\t\t\tfmt.Fprintln(os.Stderr, \"Apply was skipped: no changes detected.\")\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tresp, err := c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{\n\t\t\t\tData:           edited,\n\t\t\t\tMode:           editCmdFlags.Mode.Mode,\n\t\t\t\tDryRun:         editCmdFlags.dryRun,\n\t\t\t\tTryModeTimeout: durationpb.New(editCmdFlags.configTryTimeout),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tlastError = err.Error()\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\thelpers.PrintApplyResults(resp)\n\n\t\t\tbreak\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\nfunc stripEditingComment(in []byte) []byte {\n\t// Note: on Windows, we use crlf.NewCRLFWriter which converts LF to CRLF before opening the editor.\n\t// So this code block below undoes that conversion back to LF for consistent processing.\n\tif runtime.GOOS == \"windows\" {\n\t\t// revert back CRLF to LF for processing\n\t\tin = bytes.ReplaceAll(in, []byte(\"\\r\\n\"), []byte(\"\\n\"))\n\t}\n\n\tfor {\n\t\tidx := bytes.Index(in, []byte{'\\n'})\n\t\tif idx == -1 {\n\t\t\treturn in\n\t\t}\n\n\t\tif !bytes.HasPrefix(in, []byte(\"# \")) {\n\t\t\treturn in\n\t\t}\n\n\t\tin = in[idx+1:]\n\t}\n}\n\nfunc addEditingComment(in string) string {\n\tlines := strings.Split(in, \"\\n\")\n\n\treturn fmt.Sprintf(\"# \\n# %s\\n\", strings.Join(lines, \"\\n# \"))\n}\n\n// editCmd represents the edit command.\nvar editCmd = &cobra.Command{\n\tUse:   \"edit machineconfig\",\n\tShort: \"Edit Talos node machine configuration with the default editor.\",\n\tArgs:  cobra.RangeArgs(1, 2),\n\tLong: `The edit command allows you to directly edit the machine configuration\nof a Talos node using your preferred text editor.\n\nIt will open the editor defined by your TALOS_EDITOR,\nor EDITOR environment variables, or fall back to 'vi' for Linux\nor 'notepad' for Windows.`,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, node := range GlobalArgs.Nodes {\n\t\t\t\tnodeCtx := client.WithNodes(ctx, node)\n\t\t\t\tif err := helpers.ForEachResource(nodeCtx, c, nil, editFn(c), editCmdFlags.namespace, args...); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\teditCmd.Flags().StringVar(&editCmdFlags.namespace, \"namespace\", \"\", \"resource namespace (default is to use default namespace per resource)\")\n\thelpers.AddModeFlags(&editCmdFlags.Mode, editCmd)\n\teditCmd.Flags().BoolVar(&editCmdFlags.dryRun, \"dry-run\", false, \"do not apply the change after editing and print the change summary instead\")\n\teditCmd.Flags().DurationVar(&editCmdFlags.configTryTimeout, \"timeout\", constants.ConfigTryTimeout, \"the config will be rolled back after specified timeout (if try mode is selected)\")\n\taddCommand(editCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\tsnapshot \"go.etcd.io/etcd/etcdutl/v3/snapshot\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tetcdresource \"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\n// etcdCmd represents the etcd command.\nvar etcdCmd = &cobra.Command{\n\tUse:   \"etcd\",\n\tShort: \"Manage etcd\",\n\tLong:  ``,\n}\n\n// etcdAlarmCmd represents the etcd alarm command.\nvar etcdAlarmCmd = &cobra.Command{\n\tUse:   \"alarm\",\n\tShort: \"Manage etcd alarms\",\n\tLong:  ``,\n}\n\ntype alarmMessage interface {\n\tGetMetadata() *common.Metadata\n\tGetMemberAlarms() []*machine.EtcdMemberAlarm\n}\n\nfunc displayAlarms(messages []alarmMessage) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tnode := \"\"\n\tpattern := \"%s\\t%s\\n\"\n\theader := \"MEMBER\\tALARM\"\n\n\tfor i, message := range messages {\n\t\tif message.GetMetadata() != nil && message.GetMetadata().GetHostname() != \"\" {\n\t\t\tnode = message.GetMetadata().GetHostname()\n\t\t}\n\n\t\tfor j, alarm := range message.GetMemberAlarms() {\n\t\t\tif i == 0 && j == 0 {\n\t\t\t\tif node != \"\" {\n\t\t\t\t\theader = \"NODE\\t\" + header\n\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintln(w, header)\n\t\t\t}\n\n\t\t\targs := []any{\n\t\t\t\tetcdresource.FormatMemberID(alarm.GetMemberId()),\n\t\t\t\talarm.GetAlarm().String(),\n\t\t\t}\n\t\t\tif node != \"\" {\n\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\n// etcdAlarmListCmd represents the etcd alarm list command.\nvar etcdAlarmListCmd = &cobra.Command{\n\tUse:   \"list\",\n\tShort: \"List the etcd alarms for the node.\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tresponse, err := c.EtcdAlarmList(ctx)\n\t\t\tif err != nil {\n\t\t\t\tif response == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting alarms: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn displayAlarms(xslices.Map(response.Messages, func(v *machine.EtcdAlarm) alarmMessage {\n\t\t\t\treturn v\n\t\t\t}))\n\t\t})\n\t},\n}\n\n// etcdAlarmDisarmCmd represents the etcd alarm disarm command.\nvar etcdAlarmDisarmCmd = &cobra.Command{\n\tUse:   \"disarm\",\n\tShort: \"Disarm the etcd alarms for the node.\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tresponse, err := c.EtcdAlarmDisarm(ctx)\n\t\t\tif err != nil {\n\t\t\t\tif response == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error disarming alarms: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn displayAlarms(xslices.Map(response.Messages, func(v *machine.EtcdAlarmDisarm) alarmMessage {\n\t\t\t\treturn v\n\t\t\t}))\n\t\t})\n\t},\n}\n\n// etcdDefragCmd represents the etcd defrag command.\nvar etcdDefragCmd = &cobra.Command{\n\tUse:   \"defrag\",\n\tShort: \"Defragment etcd database on the node\",\n\tLong: `Defragmentation is a maintenance operation that releases unused space from the etcd database file.\nDefragmentation is a resource heavy operation and should be performed only when necessary on a single node at a time.`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd defrag\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t_, err := c.EtcdDefragment(ctx)\n\n\t\t\treturn err\n\t\t})\n\t},\n}\n\nvar etcdLeaveCmd = &cobra.Command{\n\tUse:   \"leave\",\n\tShort: \"Tell nodes to leave etcd cluster\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd leave\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn c.EtcdLeaveCluster(ctx, &machine.EtcdLeaveClusterRequest{})\n\t\t})\n\t},\n}\n\nvar etcdMemberRemoveCmd = &cobra.Command{\n\tUse:   \"remove-member <member ID>\",\n\tShort: \"Remove the node from etcd cluster\",\n\tLong: `Use this command only if you want to remove a member which is in broken state.\nIf there is no access to the node, or the node can't access etcd to call etcd leave.\nAlways prefer etcd leave over this command.`,\n\tArgs: cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tmemberID, err := etcdresource.ParseMemberID(args[0])\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error parsing member ID: %w\", err)\n\t\t\t}\n\n\t\t\treturn c.EtcdRemoveMemberByID(ctx, &machine.EtcdRemoveMemberByIDRequest{\n\t\t\t\tMemberId: memberID,\n\t\t\t})\n\t\t})\n\t},\n}\n\nvar etcdForfeitLeadershipCmd = &cobra.Command{\n\tUse:   \"forfeit-leadership\",\n\tShort: \"Tell node to forfeit etcd cluster leadership\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\t_, err := c.EtcdForfeitLeadership(ctx, &machine.EtcdForfeitLeadershipRequest{})\n\n\t\t\treturn err\n\t\t})\n\t},\n}\n\nvar etcdMemberListCmd = &cobra.Command{\n\tUse:   \"members\",\n\tShort: \"Get the list of etcd cluster members\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tresponse, err := c.EtcdMemberList(ctx, &machine.EtcdMemberListRequest{\n\t\t\t\tQueryLocal: true,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tif response == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting members: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tnode := \"\"\n\t\t\tpattern := \"%s\\t%s\\t%s\\t%s\\t%v\\n\"\n\n\t\t\tfor i, message := range response.Messages {\n\t\t\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = message.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif len(message.Members) == 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfor j, member := range message.Members {\n\t\t\t\t\tif i == 0 && j == 0 {\n\t\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\t\tfmt.Fprintln(w, \"NODE\\tID\\tHOSTNAME\\tPEER URLS\\tCLIENT URLS\\tLEARNER\")\n\n\t\t\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfmt.Fprintln(w, \"ID\\tHOSTNAME\\tPEER URLS\\tCLIENT URLS\\tLEARNER\")\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\targs := []any{\n\t\t\t\t\t\tetcdresource.FormatMemberID(member.Id),\n\t\t\t\t\t\tmember.Hostname,\n\t\t\t\t\t\tstrings.Join(member.PeerUrls, \",\"),\n\t\t\t\t\t\tstrings.Join(member.ClientUrls, \",\"),\n\t\t\t\t\t\tmember.IsLearner,\n\t\t\t\t\t}\n\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nvar etcdStatusCmd = &cobra.Command{\n\tUse:   \"status\",\n\tShort: \"Get the status of etcd cluster member\",\n\tLong:  `Returns the status of etcd member on the node, use multiple nodes to get status of all members.`,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tresponse, err := c.EtcdStatus(ctx)\n\t\t\tif err != nil {\n\t\t\t\tif response == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tnode := \"\"\n\t\t\tpattern := \"%s\\t%s\\t%s (%.2f%%)\\t%s\\t%d\\t%d\\t%d\\t%v\\t%s\\t%s\\t%s\\n\"\n\t\t\theader := \"MEMBER\\tDB SIZE\\tIN USE\\tLEADER\\tRAFT INDEX\\tRAFT TERM\\tRAFT APPLIED INDEX\\tLEARNER\\tPROTOCOL\\tSTORAGE\\tERRORS\"\n\n\t\t\tfor i, message := range response.Messages {\n\t\t\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = message.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif i == 0 {\n\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\theader = \"NODE\\t\" + header\n\t\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintln(w, header)\n\t\t\t\t}\n\n\t\t\t\tvar ratio float64\n\n\t\t\t\tif message.GetMemberStatus().GetDbSize() > 0 {\n\t\t\t\t\tratio = float64(message.GetMemberStatus().GetDbSizeInUse()) / float64(message.GetMemberStatus().GetDbSize()) * 100.0\n\t\t\t\t}\n\n\t\t\t\targs := []any{\n\t\t\t\t\tetcdresource.FormatMemberID(message.GetMemberStatus().GetMemberId()),\n\t\t\t\t\thumanize.Bytes(uint64(message.GetMemberStatus().GetDbSize())),\n\t\t\t\t\thumanize.Bytes(uint64(message.GetMemberStatus().GetDbSizeInUse())),\n\t\t\t\t\tratio,\n\t\t\t\t\tetcdresource.FormatMemberID(message.GetMemberStatus().GetLeader()),\n\t\t\t\t\tmessage.GetMemberStatus().GetRaftIndex(),\n\t\t\t\t\tmessage.GetMemberStatus().GetRaftTerm(),\n\t\t\t\t\tmessage.GetMemberStatus().GetRaftAppliedIndex(),\n\t\t\t\t\tmessage.GetMemberStatus().GetIsLearner(),\n\t\t\t\t\tmessage.GetMemberStatus().GetProtocolVersion(),\n\t\t\t\t\tmessage.GetMemberStatus().GetStorageVersion(),\n\t\t\t\t\tstrings.Join(message.GetMemberStatus().GetErrors(), \", \"),\n\t\t\t\t}\n\t\t\t\tif node != \"\" {\n\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nvar etcdSnapshotCmd = &cobra.Command{\n\tUse:   \"snapshot <path>\",\n\tShort: \"Stream snapshot of the etcd node to the path.\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd snapshot\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdbPath := args[0]\n\t\t\tpartPath := dbPath + \".part\"\n\n\t\t\tdefer os.RemoveAll(partPath) //nolint:errcheck\n\n\t\t\tdest, err := os.OpenFile(partPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating temporary file: %w\", err)\n\t\t\t}\n\n\t\t\tdefer dest.Close() //nolint:errcheck\n\n\t\t\tr, err := c.EtcdSnapshot(ctx, &machine.EtcdSnapshotRequest{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading file: %w\", err)\n\t\t\t}\n\n\t\t\tdefer r.Close() //nolint:errcheck\n\n\t\t\tsize, err := io.Copy(dest, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading: %w\", err)\n\t\t\t}\n\n\t\t\tif err = dest.Sync(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to fsync: %w\", err)\n\t\t\t}\n\n\t\t\t// this check is from https://github.com/etcd-io/etcd/blob/client/v3.5.0-alpha.0/client/v3/snapshot/v3_snapshot.go#L46\n\t\t\tif (size % 512) != sha256.Size {\n\t\t\t\treturn fmt.Errorf(\"sha256 checksum not found (size %d)\", size)\n\t\t\t}\n\n\t\t\tif err = dest.Close(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to close: %w\", err)\n\t\t\t}\n\n\t\t\tif err = os.Rename(partPath, dbPath); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error renaming to final location: %w\", err)\n\t\t\t}\n\n\t\t\tfmt.Printf(\"etcd snapshot saved to %q (%d bytes)\\n\", dbPath, size)\n\n\t\t\tmanager := snapshot.NewV3(logging.Wrap(os.Stderr))\n\n\t\t\tstatus, err := manager.Status(dbPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Printf(\"snapshot info: hash %08x, revision %d, total keys %d, total size %d\\n\",\n\t\t\t\tstatus.Hash, status.Revision, status.TotalKey, status.TotalSize)\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nvar etcdDowngradeCmd = &cobra.Command{\n\tUse:   \"downgrade\",\n\tShort: \"Manage etcd storage system downgrades\",\n\tLong:  ``,\n}\n\nconst (\n\tetcdDowngradePattern = \"%s\\n\"\n\tetcdDowngradeHeader  = \"MESSAGE\"\n)\n\nvar etcdDowngradeValidateCmd = &cobra.Command{\n\tUse:   \"validate <version>\",\n\tShort: \"Validate if the etcd storage system can be downgraded to the specified version.\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd downgrade validate\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tversion := args[0]\n\n\t\t\tr, err := c.EtcdDowngradeValidate(ctx, &machine.EtcdDowngradeValidateRequest{Version: version})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tnode := \"\"\n\t\t\tpattern := etcdDowngradePattern\n\t\t\theader := etcdDowngradeHeader\n\n\t\t\tfor i, message := range r.Messages {\n\t\t\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = message.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif i == 0 {\n\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\theader = \"NODE\\t\" + header\n\t\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintln(w, header)\n\t\t\t\t}\n\n\t\t\t\targs := []any{\n\t\t\t\t\tfmt.Sprintf(\"downgrade validate success, cluster version %s\",\n\t\t\t\t\t\tmessage.GetClusterDowngrade().GetClusterVersion(),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t\tif node != \"\" {\n\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nvar etcdDowngradeEnableCmd = &cobra.Command{\n\tUse:   \"enable <version>\",\n\tShort: \"Enable etcd storage system downgrade to the specified version.\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd downgrade enable\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tversion := args[0]\n\n\t\t\tr, err := c.EtcdDowngradeEnable(ctx, &machine.EtcdDowngradeEnableRequest{Version: version})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tnode := \"\"\n\t\t\tpattern := etcdDowngradePattern\n\t\t\theader := etcdDowngradeHeader\n\n\t\t\tfor i, message := range r.Messages {\n\t\t\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = message.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif i == 0 {\n\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\theader = \"NODE\\t\" + header\n\t\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintln(w, header)\n\t\t\t\t}\n\n\t\t\t\targs := []any{\n\t\t\t\t\tfmt.Sprintf(\"downgrade enable success, cluster version %s\",\n\t\t\t\t\t\tmessage.GetClusterDowngrade().GetClusterVersion(),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t\tif node != \"\" {\n\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nvar etcdDowngradeCancelCmd = &cobra.Command{\n\tUse:   \"cancel\",\n\tShort: \"Cancel etcd storage system downgrade.\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"etcd downgrade cancel\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr, err := c.EtcdDowngradeCancel(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tnode := \"\"\n\t\t\tpattern := etcdDowngradePattern\n\t\t\theader := etcdDowngradeHeader\n\n\t\t\tfor i, message := range r.Messages {\n\t\t\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = message.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif i == 0 {\n\t\t\t\t\tif node != \"\" {\n\t\t\t\t\t\theader = \"NODE\\t\" + header\n\t\t\t\t\t\tpattern = \"%s\\t\" + pattern\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Fprintln(w, header)\n\t\t\t\t}\n\n\t\t\t\targs := []any{\n\t\t\t\t\tfmt.Sprintf(\"downgrade cancel success, cluster version %s\",\n\t\t\t\t\t\tmessage.GetClusterDowngrade().GetClusterVersion(),\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t\tif node != \"\" {\n\t\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nfunc init() {\n\tetcdAlarmCmd.AddCommand(\n\t\tetcdAlarmListCmd,\n\t\tetcdAlarmDisarmCmd,\n\t)\n\n\tetcdDowngradeCmd.AddCommand(\n\t\tetcdDowngradeValidateCmd,\n\t\tetcdDowngradeEnableCmd,\n\t\tetcdDowngradeCancelCmd,\n\t)\n\n\tetcdCmd.AddCommand(\n\t\tetcdAlarmCmd,\n\t\tetcdDefragCmd,\n\t\tetcdForfeitLeadershipCmd,\n\t\tetcdLeaveCmd,\n\t\tetcdMemberListCmd,\n\t\tetcdMemberRemoveCmd,\n\t\tetcdSnapshotCmd,\n\t\tetcdStatusCmd,\n\t\tetcdDowngradeCmd,\n\t)\n\n\taddCommand(etcdCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar eventsCmdFlags struct {\n\ttailEvents   int32\n\ttailDuration time.Duration\n\ttailID       string\n\tactorID      string\n}\n\n// eventsCmd represents the events command.\nvar eventsCmd = &cobra.Command{\n\tUse:   \"events\",\n\tShort: \"Stream runtime events\",\n\tLong:  ``,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tfmt.Fprintln(w, \"NODE\\tID\\tEVENT\\tACTOR\\tSOURCE\\tMESSAGE\")\n\n\t\t\tvar opts []client.EventsOptionFunc\n\n\t\t\tif eventsCmdFlags.tailEvents != 0 {\n\t\t\t\topts = append(opts, client.WithTailEvents(eventsCmdFlags.tailEvents))\n\t\t\t}\n\n\t\t\tif eventsCmdFlags.tailDuration != 0 {\n\t\t\t\topts = append(opts, client.WithTailDuration(eventsCmdFlags.tailDuration))\n\t\t\t}\n\n\t\t\tif eventsCmdFlags.tailID != \"\" {\n\t\t\t\topts = append(opts, client.WithTailID(eventsCmdFlags.tailID))\n\t\t\t}\n\n\t\t\tif eventsCmdFlags.actorID != \"\" {\n\t\t\t\topts = append(opts, client.WithActorID(eventsCmdFlags.actorID))\n\t\t\t}\n\n\t\t\tevents, err := c.Events(ctx, opts...)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn helpers.ReadGRPCStream(events, func(ev *machine.Event, node string, multipleNodes bool) error {\n\t\t\t\tformat := \"%s\\t%s\\t%s\\n%s\\t%s\\t%s\\n\"\n\n\t\t\t\tevent, err := client.UnmarshalEvent(ev)\n\t\t\t\tif err != nil {\n\t\t\t\t\tvar errBadEvent client.EventNotSupportedError\n\t\t\t\t\tif errors.As(err, &errBadEvent) {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tvar args []any\n\n\t\t\t\tswitch msg := event.Payload.(type) {\n\t\t\t\tcase *machine.SequenceEvent:\n\t\t\t\t\targs = []any{msg.GetSequence()}\n\t\t\t\t\tif msg.Error != nil {\n\t\t\t\t\t\targs = append(args, \"error:\"+\" \"+msg.GetError().GetMessage())\n\t\t\t\t\t} else {\n\t\t\t\t\t\targs = append(args, msg.GetAction().String())\n\t\t\t\t\t}\n\t\t\t\tcase *machine.PhaseEvent:\n\t\t\t\t\targs = []any{msg.GetPhase(), msg.GetAction().String()}\n\t\t\t\tcase *machine.TaskEvent:\n\t\t\t\t\targs = []any{msg.GetTask(), msg.GetAction().String()}\n\t\t\t\tcase *machine.ServiceStateEvent:\n\t\t\t\t\targs = []any{msg.GetService(), fmt.Sprintf(\"%s: %s\", msg.GetAction(), msg.GetMessage())}\n\t\t\t\tcase *machine.ConfigLoadErrorEvent:\n\t\t\t\t\targs = []any{\"error\", msg.GetError()}\n\t\t\t\tcase *machine.ConfigValidationErrorEvent:\n\t\t\t\t\targs = []any{\"error\", msg.GetError()}\n\t\t\t\tcase *machine.AddressEvent:\n\t\t\t\t\targs = []any{msg.GetHostname(), fmt.Sprintf(\"ADDRESSES: %s\", strings.Join(msg.GetAddresses(), \",\"))}\n\t\t\t\tcase *machine.MachineStatusEvent:\n\t\t\t\t\targs = []any{\n\t\t\t\t\t\tmsg.GetStage().String(),\n\t\t\t\t\t\tfmt.Sprintf(\"ready: %v, unmet conditions: %v\",\n\t\t\t\t\t\t\tmsg.GetStatus().Ready,\n\t\t\t\t\t\t\txslices.Map(msg.GetStatus().GetUnmetConditions(),\n\t\t\t\t\t\t\t\tfunc(c *machine.MachineStatusEvent_MachineStatus_UnmetCondition) string {\n\t\t\t\t\t\t\t\t\treturn c.Name\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\targs = append([]any{event.Node, event.ID, event.TypeURL, event.ActorID}, args...)\n\t\t\t\tfmt.Fprintf(w, format, args...)\n\n\t\t\t\treturn w.Flush()\n\t\t\t})\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(eventsCmd)\n\teventsCmd.Flags().Int32Var(&eventsCmdFlags.tailEvents, \"tail\", 0, \"show specified number of past events (use -1 to show full history, default is to show no history)\")\n\teventsCmd.Flags().DurationVar(&eventsCmdFlags.tailDuration, \"duration\", 0, \"show events for the past duration interval (one second resolution, default is to show no history)\")\n\teventsCmd.Flags().StringVar(&eventsCmdFlags.tailID, \"since\", \"\", \"show events after the specified event ID (default is to show no history)\")\n\teventsCmd.Flags().StringVar(&eventsCmdFlags.actorID, \"actor-id\", \"\", \"filter events by the specified actor ID (default is no filter)\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/get.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/output\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nvar getCmdFlags struct {\n\tinsecure bool\n\n\tnamespace string\n\toutput    string\n\twatch     bool\n}\n\n// getCmd represents the get (resources) command.\nvar getCmd = &cobra.Command{\n\tUse:        \"get <type> [<id>]\",\n\tAliases:    []string{\"g\"},\n\tSuggestFor: []string{},\n\tShort:      \"Get a specific resource or list of resources (use 'talosctl get rd' to see all available resource types).\",\n\tLong: `Similar to 'kubectl get', 'talosctl get' returns a set of resources from the OS.\nTo get a list of all available resource definitions, issue 'talosctl get rd'`,\n\tExample: \"\",\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tswitch len(args) {\n\t\tcase 0:\n\t\t\treturn completeResourceDefinition(toComplete != \"\")\n\t\tcase 1:\n\t\t\treturn completeResourceID(args[0], getCmdFlags.namespace)\n\t\t}\n\n\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t},\n\tArgs: cobra.RangeArgs(1, 2),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif getCmdFlags.insecure {\n\t\t\treturn WithClientMaintenance(nil, getResources(args))\n\t\t}\n\n\t\treturn WithClient(getResources(args))\n\t},\n}\n\n//nolint:gocyclo,cyclop\nfunc getResources(args []string) func(ctx context.Context, c *client.Client) error {\n\treturn func(ctx context.Context, c *client.Client) error {\n\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tout, err := output.NewWriter(getCmdFlags.output)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresourceType := args[0]\n\n\t\tvar resourceID string\n\n\t\tif len(args) == 2 {\n\t\t\tresourceID = args[1]\n\t\t}\n\n\t\tdefer out.Flush() //nolint:errcheck\n\n\t\tif getCmdFlags.watch { // get -w <type> OR get -w <type> <id>\n\t\t\tmd, _ := metadata.FromOutgoingContext(ctx)\n\t\t\tnodes := md.Get(\"nodes\")\n\n\t\t\tif len(nodes) == 0 {\n\t\t\t\t// use \"current\" node\n\t\t\t\tnodes = []string{\"\"}\n\t\t\t}\n\n\t\t\t// fetch the RD from the first node (it doesn't matter which one to use, so we'll use the first one)\n\t\t\trd, err := c.ResolveResourceKind(client.WithNode(ctx, nodes[0]), &getCmdFlags.namespace, resourceType)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresourceType = rd.TypedSpec().Type\n\n\t\t\tif err = out.WriteHeader(rd, true); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\taggregatedCh := make(chan nodeAndEvent)\n\n\t\t\tfor _, node := range nodes {\n\t\t\t\tvar nodeCtx context.Context\n\n\t\t\t\tif node == \"\" {\n\t\t\t\t\tnodeCtx = ctx\n\t\t\t\t} else {\n\t\t\t\t\tnodeCtx = client.WithNode(ctx, node)\n\t\t\t\t}\n\n\t\t\t\twatchCh := make(chan state.Event)\n\n\t\t\t\tif resourceID == \"\" {\n\t\t\t\t\terr = c.COSI.WatchKind(\n\t\t\t\t\t\tnodeCtx,\n\t\t\t\t\t\tresource.NewMetadata(getCmdFlags.namespace, resourceType, \"\", resource.VersionUndefined),\n\t\t\t\t\t\twatchCh,\n\t\t\t\t\t\tstate.WithBootstrapContents(true),\n\t\t\t\t\t\tstate.WithWatchKindUnmarshalOptions(state.WithSkipProtobufUnmarshal()),\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\terr = c.COSI.Watch(\n\t\t\t\t\t\tnodeCtx,\n\t\t\t\t\t\tresource.NewMetadata(getCmdFlags.namespace, resourceType, resourceID, resource.VersionUndefined),\n\t\t\t\t\t\twatchCh,\n\t\t\t\t\t\tstate.WithWatchUnmarshalOptions(state.WithSkipProtobufUnmarshal()),\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error setting up watch on node %s: %w\", node, err)\n\t\t\t\t}\n\n\t\t\t\tgo aggregateEvents(ctx, aggregatedCh, watchCh, node)\n\t\t\t}\n\n\t\t\tvar bootstrapped bool\n\n\t\t\tfor {\n\t\t\t\tvar nev nodeAndEvent\n\n\t\t\t\tselect {\n\t\t\t\tcase nev = <-aggregatedCh:\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif nev.ev.Type == state.Errored {\n\t\t\t\t\treturn fmt.Errorf(\"error watching resource: %w\", nev.ev.Error)\n\t\t\t\t}\n\n\t\t\t\tif nev.ev.Type == state.Bootstrapped {\n\t\t\t\t\tbootstrapped = true\n\n\t\t\t\t\tif err = out.Flush(); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif nev.ev.Resource == nil {\n\t\t\t\t\t// new event type without resource, skip it\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err = out.WriteResource(nev.node, nev.ev.Resource, nev.ev.Type); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif bootstrapped {\n\t\t\t\t\tif err = out.Flush(); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar multiErr *multierror.Error\n\n\t\t// get <type>\n\t\t// get <type> <id>\n\t\tcallbackResource := func(parentCtx context.Context, hostname string, r resource.Resource, callError error) error {\n\t\t\tif callError != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, callError)\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn out.WriteResource(hostname, r, 0)\n\t\t}\n\n\t\tcallbackRD := func(definition *meta.ResourceDefinition) error {\n\t\t\treturn out.WriteHeader(definition, false)\n\t\t}\n\n\t\thelperErr := helpers.ForEachResource(ctx, c, callbackRD, callbackResource, getCmdFlags.namespace, args...)\n\t\tif helperErr != nil {\n\t\t\treturn helperErr\n\t\t}\n\n\t\treturn multiErr.ErrorOrNil()\n\t}\n}\n\ntype nodeAndEvent struct {\n\tnode string\n\tev   state.Event\n}\n\nfunc aggregateEvents(ctx context.Context, outCh chan<- nodeAndEvent, watchCh <-chan state.Event, node string) {\n\tfor {\n\t\tselect {\n\t\tcase ev := <-watchCh:\n\t\t\tselect {\n\t\t\tcase outCh <- nodeAndEvent{node, ev}:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// completeResourceDefinition represents tab complete options for `get` and `get *` commands.\nfunc completeResourceDefinition(withAliases bool) ([]string, cobra.ShellCompDirective) {\n\tvar result []string\n\n\tif WithClientNoNodes(func(ctx context.Context, c *client.Client) error {\n\t\titems, err := safe.StateListAll[*meta.ResourceDefinition](ctx, c.COSI)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor res := range items.All() {\n\t\t\tif withAliases {\n\t\t\t\tresult = append(result, res.TypedSpec().Aliases...)\n\t\t\t}\n\n\t\t\tresult = append(result, res.Metadata().ID())\n\t\t}\n\n\t\treturn nil\n\t}) != nil {\n\t\treturn nil, cobra.ShellCompDirectiveError\n\t}\n\n\treturn result, cobra.ShellCompDirectiveNoFileComp\n}\n\n// completeResourceID represents tab complete options for `get` and `get *` commands.\nfunc completeResourceID(resourceType, namespace string) ([]string, cobra.ShellCompDirective) {\n\tvar result []string\n\n\tif WithClientNoNodes(func(ctx context.Context, c *client.Client) error {\n\t\tif len(GlobalArgs.Nodes) > 0 {\n\t\t\tctx = client.WithNode(ctx, GlobalArgs.Nodes[0])\n\t\t}\n\n\t\trd, err := c.ResolveResourceKind(ctx, &namespace, resourceType)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\titems, err := c.COSI.List(ctx, resource.NewMetadata(namespace, rd.TypedSpec().Type, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, item := range items.Items {\n\t\t\tresult = append(result, item.Metadata().ID())\n\t\t}\n\n\t\treturn nil\n\t}) != nil {\n\t\treturn nil, cobra.ShellCompDirectiveError\n\t}\n\n\treturn result, cobra.ShellCompDirectiveNoFileComp\n}\n\n// CompleteNodes represents tab completion for `--nodes` argument.\nfunc CompleteNodes(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {\n\tvar nodes []string\n\n\tif WithClientNoNodes(func(ctx context.Context, c *client.Client) error {\n\t\titems, err := safe.StateListAll[*cluster.Member](ctx, c.COSI)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor res := range items.All() {\n\t\t\tif hostname := res.TypedSpec().Hostname; hostname != \"\" {\n\t\t\t\tnodes = append(nodes, hostname)\n\t\t\t}\n\n\t\t\tfor _, address := range res.TypedSpec().Addresses {\n\t\t\t\tnodes = append(nodes, address.String())\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}) != nil {\n\t\treturn nil, cobra.ShellCompDirectiveError\n\t}\n\n\treturn nodes, cobra.ShellCompDirectiveNoFileComp\n}\n\nfunc init() {\n\tgetCmd.Flags().StringVar(&getCmdFlags.namespace, \"namespace\", \"\", \"resource namespace (default is to use default namespace per resource)\")\n\tgetCmd.Flags().StringVarP(&getCmdFlags.output, \"output\", \"o\", \"table\", \"output mode (json, table, yaml, jsonpath)\")\n\tgetCmd.Flags().BoolVarP(&getCmdFlags.watch, \"watch\", \"w\", false, \"watch resource changes\")\n\tgetCmd.Flags().BoolVarP(&getCmdFlags.insecure, \"insecure\", \"i\", false, \"get resources using the insecure (encrypted with no auth) maintenance service\")\n\tcli.Should(getCmd.RegisterFlagCompletionFunc(\"output\", output.CompleteOutputArg))\n\taddCommand(getCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/health.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\t\"github.com/siderolabs/talos/pkg/cluster/hydrophone\"\n\tclusterapi \"github.com/siderolabs/talos/pkg/machinery/api/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tclusterres \"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\ntype clusterNodes struct {\n\tInitNode          string\n\tControlPlaneNodes []string\n\tWorkerNodes       []string\n\n\tnodes       []cluster.NodeInfo\n\tnodesByType map[machine.Type][]cluster.NodeInfo\n}\n\nfunc (cl *clusterNodes) InitNodeInfos() error {\n\tvar initNodes []string\n\n\tif cl.InitNode != \"\" {\n\t\tinitNodes = []string{cl.InitNode}\n\t}\n\n\tinitNodeInfos, err := cluster.IPsToNodeInfos(initNodes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontrolPlaneNodeInfos, err := cluster.IPsToNodeInfos(cl.ControlPlaneNodes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tworkerNodeInfos, err := cluster.IPsToNodeInfos(cl.WorkerNodes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodesByType := make(map[machine.Type][]cluster.NodeInfo)\n\tnodesByType[machine.TypeInit] = initNodeInfos\n\tnodesByType[machine.TypeControlPlane] = controlPlaneNodeInfos\n\tnodesByType[machine.TypeWorker] = workerNodeInfos\n\tcl.nodesByType = nodesByType\n\n\tcl.nodes = slices.Concat(initNodeInfos, controlPlaneNodeInfos, workerNodeInfos)\n\n\treturn nil\n}\n\nfunc (cl *clusterNodes) Nodes() []cluster.NodeInfo {\n\treturn cl.nodes\n}\n\nfunc (cl *clusterNodes) NodesByType(t machine.Type) []cluster.NodeInfo {\n\treturn cl.nodesByType[t]\n}\n\nvar healthCmdFlags struct {\n\tclusterState       clusterNodes\n\tclusterWaitTimeout time.Duration\n\tforceEndpoint      string\n\trunOnServer        bool\n\trunE2E             bool\n}\n\n// healthCmd represents the health command.\nvar healthCmd = &cobra.Command{\n\tUse:   \"health\",\n\tShort: \"Check cluster health\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\terr := healthCmdFlags.clusterState.InitNodeInfos()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := runHealth(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif healthCmdFlags.runE2E {\n\t\t\treturn runE2E()\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc runHealth() error {\n\tif healthCmdFlags.runOnServer {\n\t\treturn WithClient(healthOnServer)\n\t}\n\n\treturn WithClientNoNodes(healthOnClient)\n}\n\nfunc healthOnClient(ctx context.Context, c *client.Client) error {\n\tclientProvider := &cluster.ConfigClientProvider{\n\t\tDefaultClient: c,\n\t}\n\tdefer clientProvider.Close() //nolint:errcheck\n\n\tclusterInfo, err := buildClusterInfo(healthCmdFlags.clusterState)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate := struct {\n\t\tcluster.ClientProvider\n\t\tcluster.K8sProvider\n\t\tcluster.Info\n\t}{\n\t\tClientProvider: clientProvider,\n\t\tK8sProvider: &cluster.KubernetesClient{\n\t\t\tClientProvider: clientProvider,\n\t\t\tForceEndpoint:  healthCmdFlags.forceEndpoint,\n\t\t},\n\t\tInfo: clusterInfo,\n\t}\n\n\t// Run cluster readiness checks\n\tcheckCtx, checkCtxCancel := context.WithTimeout(ctx, healthCmdFlags.clusterWaitTimeout)\n\tdefer checkCtxCancel()\n\n\treturn check.Wait(checkCtx, &state, append(check.DefaultClusterChecks(), check.ExtraClusterChecks()...), check.StderrReporter())\n}\n\nfunc healthOnServer(ctx context.Context, c *client.Client) error {\n\tif err := helpers.FailIfMultiNodes(ctx, \"health\"); err != nil {\n\t\treturn err\n\t}\n\n\tcontrolPlaneNodes := healthCmdFlags.clusterState.ControlPlaneNodes\n\tif healthCmdFlags.clusterState.InitNode != \"\" {\n\t\tcontrolPlaneNodes = append(controlPlaneNodes, healthCmdFlags.clusterState.InitNode)\n\t}\n\n\thealthCheckClient, err := c.ClusterHealthCheck(ctx, healthCmdFlags.clusterWaitTimeout, &clusterapi.ClusterInfo{\n\t\tControlPlaneNodes: controlPlaneNodes,\n\t\tWorkerNodes:       healthCmdFlags.clusterState.WorkerNodes,\n\t\tForceEndpoint:     healthCmdFlags.forceEndpoint,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := healthCheckClient.CloseSend(); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tmsg, err := healthCheckClient.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif msg.GetMetadata().GetError() != \"\" {\n\t\t\treturn fmt.Errorf(\"healthcheck error: %s\", msg.GetMetadata().GetError())\n\t\t}\n\n\t\tfmt.Fprintln(os.Stderr, msg.GetMessage())\n\t}\n}\n\nfunc runE2E() error {\n\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\tclientProvider := &cluster.ConfigClientProvider{\n\t\t\tDefaultClient: c,\n\t\t}\n\t\tdefer clientProvider.Close() //nolint:errcheck\n\n\t\tstate := &cluster.KubernetesClient{\n\t\t\tClientProvider: clientProvider,\n\t\t\tForceEndpoint:  healthCmdFlags.forceEndpoint,\n\t\t}\n\n\t\t// Run cluster readiness checks\n\t\tcheckCtx, checkCtxCancel := context.WithTimeout(ctx, healthCmdFlags.clusterWaitTimeout)\n\t\tdefer checkCtxCancel()\n\n\t\toptions := hydrophone.DefaultOptions()\n\t\toptions.UseSpinner = true\n\n\t\treturn hydrophone.Run(checkCtx, state, options)\n\t})\n}\n\nfunc init() {\n\taddCommand(healthCmd)\n\thealthCmd.Flags().StringVar(&healthCmdFlags.clusterState.InitNode, \"init-node\", \"\", \"specify IPs of init node\")\n\thealthCmd.Flags().StringSliceVar(&healthCmdFlags.clusterState.ControlPlaneNodes, \"control-plane-nodes\", nil, \"specify IPs of control plane nodes\")\n\thealthCmd.Flags().StringSliceVar(&healthCmdFlags.clusterState.WorkerNodes, \"worker-nodes\", nil, \"specify IPs of worker nodes\")\n\thealthCmd.Flags().DurationVar(&healthCmdFlags.clusterWaitTimeout, \"wait-timeout\", 20*time.Minute, \"timeout to wait for the cluster to be ready\")\n\thealthCmd.Flags().StringVar(&healthCmdFlags.forceEndpoint, \"k8s-endpoint\", \"\", \"use endpoint instead of kubeconfig default\")\n\thealthCmd.Flags().BoolVar(&healthCmdFlags.runOnServer, \"server\", true, \"run server-side check\")\n\thealthCmd.Flags().BoolVar(&healthCmdFlags.runE2E, \"run-e2e\", false, \"run Kubernetes e2e test\")\n}\n\nfunc buildClusterInfo(clusterState clusterNodes) (cluster.Info, error) {\n\t// if nodes are set explicitly via command line args, use them\n\tif len(clusterState.ControlPlaneNodes) > 0 || len(clusterState.WorkerNodes) > 0 {\n\t\treturn &clusterState, nil\n\t}\n\n\t// read members from the Talos API\n\n\tvar members []*clusterres.Member\n\n\terr := WithClientNoNodes(func(ctx context.Context, c *client.Client) error {\n\t\titems, err := safe.StateListAll[*clusterres.Member](ctx, c.COSI)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\titems.ForEach(func(item *clusterres.Member) { members = append(members, item) })\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn check.NewDiscoveredClusterInfo(members)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/signal\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/multiplex\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/pull\"\n\tmgmthelpers \"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/artifacts\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services/registry\"\n\t\"github.com/siderolabs/talos/pkg/flags\"\n\t\"github.com/siderolabs/talos/pkg/imager/cache\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\ntype imageCmdFlagsType struct {\n\tnamespace string\n}\n\nvar imageCmdFlags imageCmdFlagsType\n\nfunc (flags imageCmdFlagsType) apiNamespace() (common.ContainerdNamespace, error) {\n\tswitch flags.namespace {\n\tcase \"cri\":\n\t\treturn common.ContainerdNamespace_NS_CRI, nil\n\tcase \"system\":\n\t\treturn common.ContainerdNamespace_NS_SYSTEM, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"unsupported namespace %q\", flags.namespace)\n\t}\n}\n\nfunc (flags imageCmdFlagsType) containerdInstance() (*common.ContainerdInstance, error) {\n\tswitch flags.namespace {\n\tcase \"cri\":\n\t\treturn &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t}, nil\n\tcase \"system\":\n\t\treturn &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t}, nil\n\tcase \"inmem\":\n\t\treturn &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CONTAINERD,\n\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported namespace %q\", flags.namespace)\n\t}\n}\n\n// imagesCmd represents the image command.\nvar imageCmd = &cobra.Command{\n\tUse:     \"image\",\n\tAliases: []string{\"images\"},\n\tShort:   \"Manage container images\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n}\n\n// imageListCmd represents the image list command.\nvar imageListCmd = &cobra.Command{\n\tUse:     \"list\",\n\tAliases: []string{\"l\", \"ls\"},\n\tShort:   \"List images in the machine's container runtime\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn imageList()\n\t},\n}\n\nfunc imageList() error {\n\treturn WithClientAndNodes(func(ctx context.Context, c *client.Client, nodes []string) error {\n\t\tctx, cancel := context.WithCancel(ctx)\n\t\tdefer cancel()\n\n\t\tcontainerdInstance, err := imageCmdFlags.containerdInstance()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresponseChan := multiplex.Streaming(ctx, nodes,\n\t\t\tfunc(ctx context.Context) (grpc.ServerStreamingClient[machine.ImageServiceListResponse], error) {\n\t\t\t\treturn c.ImageClient.List(ctx, &machine.ImageServiceListRequest{\n\t\t\t\t\tContainerd: containerdInstance,\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\n\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\theaderWritten := false\n\n\t\tvar errs error\n\n\t\tfor resp := range responseChan {\n\t\t\tif resp.Err != nil {\n\t\t\t\tif status.Code(resp.Err) == codes.Unimplemented {\n\t\t\t\t\t// fallback to legacy API for older Talos\n\t\t\t\t\treturn imageListLegacy()\n\t\t\t\t}\n\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !headerWritten {\n\t\t\t\theaderWritten = true\n\n\t\t\t\tfmt.Fprintln(w, \"NODE\\tIMAGE\\tDIGEST\\tSIZE\\tLABELS\\tCREATED\")\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\t%s\\t%s\\n\",\n\t\t\t\tresp.Node,\n\t\t\t\tresp.Payload.GetName(),\n\t\t\t\tresp.Payload.GetDigest(),\n\t\t\t\thumanize.Bytes(uint64(resp.Payload.GetSize())),\n\t\t\t\thelpers.FormatLabels(resp.Payload.GetLabels()),\n\t\t\t\tresp.Payload.GetCreatedAt().AsTime().Format(time.RFC3339),\n\t\t\t)\n\t\t}\n\n\t\treturn errors.Join(errs, w.Flush())\n\t})\n}\n\n// imageListLegacy lists images using the legacy ImageList API.\n//\n// Note: remove me in Talos 1.15.\nfunc imageListLegacy() error {\n\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\tns, err := imageCmdFlags.apiNamespace()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trcv, err := c.ImageList(ctx, ns) //nolint:staticcheck // legacy talosctl methods, to be removed in Talos 1.15\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing images: %w\", err)\n\t\t}\n\n\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\tfmt.Fprintln(w, \"NODE\\tIMAGE\\tDIGEST\\tSIZE\\tCREATED\")\n\n\t\tif err = helpers.ReadGRPCStream(rcv, func(msg *machine.ImageListResponse, node string, multipleNodes bool) error {\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\t%s\\n\",\n\t\t\t\tnode,\n\t\t\t\tmsg.Name,\n\t\t\t\tmsg.Digest,\n\t\t\t\thumanize.Bytes(uint64(msg.Size)),\n\t\t\t\tmsg.CreatedAt.AsTime().Format(time.RFC3339),\n\t\t\t)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn w.Flush()\n\t})\n}\n\n// imagePullCmd represents the image pull command.\nvar imagePullCmd = &cobra.Command{\n\tUse:     \"pull <image>\",\n\tAliases: []string{\"p\"},\n\tShort:   \"Pull an image into the machine's container runtime\",\n\tLong:    ``,\n\tArgs:    cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn imagePull(args[0])\n\t},\n}\n\n// imagePull pulls an image using modern API and showing progress.\nfunc imagePull(imageRef string) error {\n\treturn WithClientAndNodes(func(ctx context.Context, c *client.Client, nodes []string) error {\n\t\trep := reporter.New()\n\n\t\tcontainerdInstance, err := imageCmdFlags.containerdInstance()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = imagePullInternal(ctx, c, containerdInstance, nodes, imageRef, rep)\n\n\t\treturn err\n\t})\n}\n\nfunc imagePullInternal(\n\tctx context.Context,\n\tc *client.Client,\n\tcontainerdInstance *common.ContainerdInstance,\n\tnodes []string,\n\timageRef string,\n\trep *reporter.Reporter,\n) (map[string]string, error) {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tresponseChan := multiplex.Streaming(ctx, nodes,\n\t\tfunc(ctx context.Context) (grpc.ServerStreamingClient[machine.ImageServicePullResponse], error) {\n\t\t\treturn c.ImageClient.Pull(ctx, &machine.ImageServicePullRequest{\n\t\t\t\tContainerd: containerdInstance,\n\t\t\t\tImageRef:   imageRef,\n\t\t\t})\n\t\t},\n\t)\n\n\tfinishedPulls := map[string]string{}\n\n\tvar (\n\t\tw    pull.ProgressWriter\n\t\terrs error\n\t)\n\n\tfor resp := range responseChan {\n\t\tif resp.Err != nil {\n\t\t\tif status.Code(resp.Err) == codes.Unimplemented {\n\t\t\t\tcancel()\n\n\t\t\t\t// fallback to legacy API for older Talos\n\t\t\t\treturn nil, imagePullLegacy(imageRef)\n\t\t\t}\n\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch payload := resp.Payload.Response.(type) {\n\t\tcase *machine.ImageServicePullResponse_PullProgress:\n\t\t\tif !rep.IsColorized() {\n\t\t\t\t// don't show progress if not colorized/terminal\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tw.UpdateJob(resp.Node, payload.PullProgress.GetLayerId(), payload.PullProgress.GetProgress())\n\n\t\t\tw.PrintLayerProgress(rep)\n\t\tcase *machine.ImageServicePullResponse_Name:\n\t\t\tfinishedPulls[resp.Node] = payload.Name\n\t\t}\n\t}\n\n\tif len(finishedPulls) > 0 {\n\t\tvar sb strings.Builder\n\n\t\tfor node, imageName := range finishedPulls {\n\t\t\tfmt.Fprintf(&sb, \"%s: pulled image %s\\n\", node, imageName)\n\t\t}\n\n\t\trep.Report(reporter.Update{\n\t\t\tMessage: sb.String(),\n\t\t\tStatus:  reporter.StatusSucceeded,\n\t\t})\n\t}\n\n\treturn finishedPulls, errs\n}\n\n// imagePullLegacy pulls an image using the legacy ImagePull API.\n//\n// Note: remove me in Talos 1.15.\nfunc imagePullLegacy(imageRef string) error {\n\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\tns, err := imageCmdFlags.apiNamespace()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = c.ImagePull(ctx, ns, imageRef) //nolint:staticcheck // legacy talosctl methods, to be removed in Talos 1.15\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error pulling image: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// imageImportInternal imports an image from a tarball.\n//\n// Note: this is not exposed as a command, but used in talosctl debug flow.\n//\n//nolint:gocyclo\nfunc imageImportInternal(\n\tctx context.Context,\n\tc *client.Client,\n\tcontainerdInstance *common.ContainerdInstance,\n\tnode string,\n\timageTarballPath string,\n\trep *reporter.Reporter,\n) (string, error) {\n\tin, err := os.Open(imageTarballPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to open image tarball: %w\", err)\n\t}\n\n\tdefer in.Close() //nolint:errcheck\n\n\tctx = client.WithNode(ctx, node)\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\trcv, err := c.ImageClient.Import(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = rcv.Send(&machine.ImageServiceImportRequest{\n\t\tRequest: &machine.ImageServiceImportRequest_Containerd{\n\t\t\tContainerd: containerdInstance,\n\t\t},\n\t}); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tconst chunkSize = 32 * 1024\n\n\tbuf := make([]byte, chunkSize)\n\n\tvar bytesImported uint64\n\n\tfor {\n\t\tn, err := in.Read(buf)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn \"\", fmt.Errorf(\"error reading image tarball: %w\", err)\n\t\t}\n\n\t\tif n > 0 {\n\t\t\tif err = rcv.Send(&machine.ImageServiceImportRequest{\n\t\t\t\tRequest: &machine.ImageServiceImportRequest_ImageChunk{\n\t\t\t\t\tImageChunk: &common.Data{\n\t\t\t\t\t\tBytes: buf[:n],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"error sending image chunk: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tbytesImported += uint64(n)\n\n\t\tif rep.IsColorized() {\n\t\t\trep.Report(reporter.Update{\n\t\t\t\tMessage: fmt.Sprintf(\"%s: %s imported\", node, humanize.IBytes(bytesImported)),\n\t\t\t\tStatus:  reporter.StatusRunning,\n\t\t\t})\n\t\t}\n\t}\n\n\tresp, err := rcv.CloseAndRecv()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error closing send stream: %w\", err)\n\t}\n\n\trep.Report(reporter.Update{\n\t\tMessage: fmt.Sprintf(\"%s: image imported %s from %s\", node, resp.GetName(), imageTarballPath),\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\treturn resp.GetName(), nil\n}\n\n// imageRemoveCmd represents the image remove command.\nvar imageRemoveCmd = &cobra.Command{\n\tUse:     \"remove <image>\",\n\tAliases: []string{\"rm\"},\n\tShort:   \"Remove an image from the machine's container runtime\",\n\tLong:    ``,\n\tArgs:    cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn imageRemove(args[0])\n\t},\n}\n\n// imageRemove removes an image using modern API.\nfunc imageRemove(imageRef string) error {\n\treturn WithClientAndNodes(func(ctx context.Context, c *client.Client, nodes []string) error {\n\t\tctx, cancel := context.WithCancel(ctx)\n\t\tdefer cancel()\n\n\t\tcontainerdInstance, err := imageCmdFlags.containerdInstance()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresponseChan := multiplex.Unary(ctx, nodes,\n\t\t\tfunc(ctx context.Context) (*emptypb.Empty, error) {\n\t\t\t\treturn c.ImageClient.Remove(ctx, &machine.ImageServiceRemoveRequest{\n\t\t\t\t\tContainerd: containerdInstance,\n\t\t\t\t\tImageRef:   imageRef,\n\t\t\t\t})\n\t\t\t},\n\t\t)\n\n\t\tvar errs error\n\n\t\tfor resp := range responseChan {\n\t\t\tif resp.Err != nil {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\t\t\t}\n\t\t}\n\n\t\treturn errs\n\t})\n}\n\nvar imageK8sBundleCmdFlags = struct {\n\tk8sVersion                 pflag.Value\n\tflannelVersion             pflag.Value\n\tcorednsVersion             pflag.Value\n\tetcdVersion                pflag.Value\n\tkubeNetworkPoliciesVersion pflag.Value\n}{\n\tk8sVersion:                 flags.Semver(constants.DefaultKubernetesVersion),\n\tflannelVersion:             flags.Semver(constants.FlannelVersion),\n\tcorednsVersion:             flags.Semver(constants.DefaultCoreDNSVersion),\n\tetcdVersion:                flags.Semver(constants.DefaultEtcdVersion),\n\tkubeNetworkPoliciesVersion: flags.Semver(constants.KubeNetworkPoliciesVersion),\n}\n\n// imageK8sBundleCmd represents the image k8s-bundle command.\nvar imageK8sBundleCmd = &cobra.Command{\n\tUse:     \"k8s-bundle\",\n\tAliases: []string{\"default\"},\n\tShort:   \"List the default Kubernetes images used by Talos\",\n\tLong:    ``,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\timages := images.ListWithOptions(container.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tEtcdConfig:              &v1alpha1.EtcdConfig{},\n\t\t\t\t\tAPIServerConfig:         &v1alpha1.APIServerConfig{},\n\t\t\t\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{},\n\t\t\t\t\tSchedulerConfig:         &v1alpha1.SchedulerConfig{},\n\t\t\t\t\tCoreDNSConfig:           &v1alpha1.CoreDNS{},\n\t\t\t\t\tProxyConfig:             &v1alpha1.ProxyConfig{},\n\t\t\t\t},\n\t\t\t}),\n\t\t\timages.VersionsListOptions{\n\t\t\t\tKubernetesVersion:          imageK8sBundleCmdFlags.k8sVersion.String(),\n\t\t\t\tEtcdVersion:                imageK8sBundleCmdFlags.etcdVersion.String(),\n\t\t\t\tFlannelVersion:             imageK8sBundleCmdFlags.flannelVersion.String(),\n\t\t\t\tCoreDNSVersion:             imageK8sBundleCmdFlags.corednsVersion.String(),\n\t\t\t\tKubeNetworkPoliciesVersion: imageK8sBundleCmdFlags.kubeNetworkPoliciesVersion.String(),\n\t\t\t},\n\t\t)\n\n\t\tfmt.Printf(\"%s\\n\", images.Flannel)\n\t\tfmt.Printf(\"%s\\n\", images.CoreDNS)\n\t\tfmt.Printf(\"%s\\n\", images.Etcd)\n\t\tfmt.Printf(\"%s\\n\", images.Pause)\n\t\tfmt.Printf(\"%s\\n\", images.KubeAPIServer)\n\t\tfmt.Printf(\"%s\\n\", images.KubeControllerManager)\n\t\tfmt.Printf(\"%s\\n\", images.KubeScheduler)\n\t\tfmt.Printf(\"%s\\n\", images.KubeProxy)\n\t\tfmt.Printf(\"%s\\n\", images.Kubelet)\n\t\tfmt.Printf(\"%s\\n\", images.KubeNetworkPolicies)\n\n\t\treturn nil\n\t},\n}\n\nvar imageTalosBundleCmdFlags = struct {\n\textensions bool\n\toverlays   bool\n}{}\n\n// imageTalosBundleCmd represents the image talos-bundle command.\nvar imageTalosBundleCmd = &cobra.Command{\n\tUse:   \"talos-bundle [talos-version]\",\n\tShort: \"List the default system images and extensions used for Talos\",\n\tLong:  ``,\n\tArgs: cobra.MatchAll(\n\t\tcobra.RangeArgs(0, 1),\n\t\tfunc(cmd *cobra.Command, args []string) error {\n\t\t\tmaximumVersion, err := semver.ParseTolerant(version.Tag)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err) // panic, this should never happen\n\t\t\t}\n\n\t\t\tmaximumVersion.Patch = 0\n\n\t\t\tmaximumVersion.Pre = nil\n\t\t\tif err := maximumVersion.IncrementMinor(); err != nil {\n\t\t\t\tpanic(err) // panic, this should never happen\n\t\t\t}\n\n\t\t\t// If no version specified, use current version\n\t\t\tif len(args) == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\ttag := args[0]\n\n\t\t\tif !strings.HasPrefix(tag, \"v\") {\n\t\t\t\treturn fmt.Errorf(\"invalid tag %q: must have \\\"v\\\" prefix\", tag)\n\t\t\t}\n\n\t\t\tver, err := semver.ParseTolerant(tag)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid argument %q: tag must be a valid semver\", tag)\n\t\t\t}\n\n\t\t\tif !ver.GTE(talosBundleMinimumVersion) || !ver.LT(maximumVersion) {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"invalid tag %q: must be between v%s (inclusive) and v%s (exclusive)\", tag, talosBundleMinimumVersion, maximumVersion,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tvar (\n\t\t\ttag        string\n\t\t\terr        error\n\t\t\textensions []artifacts.ExtensionRef\n\t\t\toverlays   []artifacts.OverlayRef\n\t\t)\n\n\t\t// Default to current version if not specified\n\t\tif len(args) == 0 {\n\t\t\ttag = version.Tag\n\t\t} else {\n\t\t\ttag = args[0]\n\t\t}\n\n\t\tsources := images.ListSourcesFor(tag)\n\n\t\tfmt.Printf(\"%s\\n\", sources.Installer)\n\t\tfmt.Printf(\"%s\\n\", sources.InstallerBase)\n\t\tfmt.Printf(\"%s\\n\", sources.Imager)\n\t\tfmt.Printf(\"%s\\n\", sources.Talos)\n\t\tfmt.Printf(\"%s\\n\", sources.TalosctlAll)\n\t\tfmt.Printf(\"%s\\n\", sources.Overlays)\n\t\tfmt.Printf(\"%s\\n\", sources.Extensions)\n\n\t\tdigestedReferences := []string{}\n\n\t\tif imageTalosBundleCmdFlags.extensions {\n\t\t\textensions, err = artifacts.FetchOfficialExtensions(tag)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error fetching official extensions for %s: %w\", tag, err)\n\t\t\t}\n\n\t\t\tfor _, extension := range extensions {\n\t\t\t\tdigestedReferences = append(digestedReferences, fmt.Sprintf(\"%s@%s\", extension.TaggedReference.String(), extension.Digest))\n\t\t\t}\n\t\t}\n\n\t\tif imageTalosBundleCmdFlags.overlays {\n\t\t\toverlays, err = artifacts.FetchOfficialOverlays(tag)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error fetching official overlays for %s: %w\", tag, err)\n\t\t\t}\n\n\t\t\tfor _, overlay := range overlays {\n\t\t\t\tdigestedReferences = append(digestedReferences, fmt.Sprintf(\"%s@%s\", overlay.TaggedReference.String(), overlay.Digest))\n\t\t\t}\n\t\t}\n\n\t\tslices.Sort(digestedReferences)\n\n\t\tfor _, ref := range slices.Compact(digestedReferences) {\n\t\t\tfmt.Printf(\"%s\\n\", ref)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nvar talosBundleMinimumVersion = semver.MustParse(\"1.11.0-alpha.0\")\n\n// imageIntegrationCmd represents the integration image command.\nvar imageIntegrationCmd = &cobra.Command{\n\tUse:    \"integration\",\n\tShort:  \"List the integration images used by k8s in Talos\",\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(*cobra.Command, []string) error {\n\t\tif stat, _ := os.Stdin.Stat(); (stat.Mode() & os.ModeCharDevice) != 0 { //nolint:errcheck\n\t\t\treturn errors.New(\"input must be piped\")\n\t\t}\n\n\t\tif imageIntegrationCmdFlags.installerTag == \"\" {\n\t\t\treturn errors.New(\"installer tag is required\")\n\t\t}\n\n\t\tif imageIntegrationCmdFlags.registryAndUser == \"\" {\n\t\t\treturn errors.New(\"registry and user string is required\")\n\t\t}\n\n\t\timgs := images.List(container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{},\n\t\t\t},\n\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\tEtcdConfig:              &v1alpha1.EtcdConfig{},\n\t\t\t\tAPIServerConfig:         &v1alpha1.APIServerConfig{},\n\t\t\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{},\n\t\t\t\tSchedulerConfig:         &v1alpha1.SchedulerConfig{},\n\t\t\t\tCoreDNSConfig:           &v1alpha1.CoreDNS{},\n\t\t\t\tProxyConfig:             &v1alpha1.ProxyConfig{},\n\t\t\t},\n\t\t}))\n\n\t\timageNames := []string{\n\t\t\timgs.Flannel.String(),\n\t\t\timgs.CoreDNS.String(),\n\t\t\timgs.Etcd.String(),\n\t\t\timgs.KubeAPIServer.String(),\n\t\t\timgs.KubeControllerManager.String(),\n\t\t\timgs.KubeScheduler.String(),\n\t\t\timgs.KubeProxy.String(),\n\t\t\timgs.Kubelet.String(),\n\t\t\timgs.Pause.String(),\n\t\t\timgs.KubeNetworkPolicies.String(),\n\t\t\t\"registry.k8s.io/conformance:v\" + constants.DefaultKubernetesVersion,\n\t\t\t\"docker.io/library/alpine:latest\",\n\t\t\t\"ghcr.io/siderolabs/talosctl:v1.12.4\",\n\t\t\t\"registry.k8s.io/kube-apiserver:v1.27.0\",\n\t\t\t\"registry.k8s.io/kube-apiserver:v1.27.1\",\n\t\t\t\"docker.io/library/alpine:3.23\",\n\t\t\timageIntegrationCmdFlags.registryAndUser + \"/installer:\" +\n\t\t\t\timageIntegrationCmdFlags.installerTag,\n\t\t\timageIntegrationCmdFlags.registryAndUser + \"/talos:\" +\n\t\t\t\timageIntegrationCmdFlags.talosTag,\n\t\t}\n\n\t\tsc := bufio.NewScanner(os.Stdin)\n\n\t\tfor sc.Scan() {\n\t\t\tswitch sc := sc.Text(); {\n\t\t\tcase strings.Contains(sc, \"authenticated-\"):\n\t\t\t// skip authenticated images\n\t\t\tcase strings.HasPrefix(sc, \"invalid.registry.k8s.io\"):\n\t\t\t// skip invalid images\n\t\t\tdefault:\n\t\t\t\timageNames = append(imageNames, sc)\n\t\t\t}\n\t\t}\n\n\t\tif err := sc.Err(); err != nil {\n\t\t\treturn fmt.Errorf(\"error reading from stdin: %w\", err)\n\t\t}\n\n\t\tslices.Sort(imageNames)\n\n\t\timageNames = slices.Compact(imageNames)\n\n\t\tfor _, img := range imageNames {\n\t\t\tfmt.Println(img)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nvar imageIntegrationCmdFlags struct {\n\tinstallerTag    string\n\ttalosTag        string\n\tregistryAndUser string\n}\n\n// imageCacheCreate represents the image cache create command.\nvar imageCacheCreateCmd = &cobra.Command{\n\tUse:   \"cache-create\",\n\tShort: \"Create a cache of images in OCI format into a directory\",\n\tLong:  `Create a cache of images in OCI format into a directory`,\n\tExample: fmt.Sprintf(\n\t\t`talosctl images cache-create --images=ghcr.io/siderolabs/kubelet:v%s --image-cache-path=/tmp/talos-image-cache\n\nAlternatively, stdin can be piped to the command:\ntalosctl images default | talosctl images cache-create --image-cache-path=/tmp/talos-image-cache --images=-\n`,\n\t\tconstants.DefaultKubernetesVersion,\n\t),\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif len(imageCacheCreateCmdFlags.images) == 0 {\n\t\t\treturn fmt.Errorf(\"no images specified\")\n\t\t}\n\n\t\tif imageCacheCreateCmdFlags.force {\n\t\t\tif err := os.RemoveAll(imageCacheCreateCmdFlags.imageCachePath); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing existing image cache path %s: %w\", imageCacheCreateCmdFlags.imageCachePath, err)\n\t\t\t}\n\t\t}\n\n\t\tif _, err := os.Stat(imageCacheCreateCmdFlags.imageCachePath); err == nil {\n\t\t\treturn fmt.Errorf(\"image cache path %s already exists, use --force to remove and use the path\", imageCacheCreateCmdFlags.imageCachePath)\n\t\t}\n\n\t\tif imageCacheCreateCmdFlags.images[0] == \"-\" {\n\t\t\tvar imagesListData strings.Builder\n\n\t\t\tif _, err := io.Copy(&imagesListData, os.Stdin); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading from stdin: %w\", err)\n\t\t\t}\n\n\t\t\timageCacheCreateCmdFlags.images = strings.Split(strings.Trim(imagesListData.String(), \"\\n\"), \"\\n\")\n\t\t}\n\n\t\terr := cache.Generate(\n\t\t\timageCacheCreateCmdFlags.images,\n\t\t\timageCacheCreateCmdFlags.platform,\n\t\t\timageCacheCreateCmdFlags.insecure,\n\t\t\timageCacheCreateCmdFlags.imageLayerCachePath,\n\t\t\timageCacheCreateCmdFlags.imageCachePath,\n\t\t\timageCacheCreateCmdFlags.layout.String() == layoutFlat,\n\t\t\timageCacheCreateCmdFlags.cosignSignatures,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating cache: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nconst (\n\tlayoutOCI  = \"oci\"\n\tlayoutFlat = \"flat\"\n)\n\nvar imageCacheCreateCmdFlags = struct {\n\timageCachePath      string\n\timageLayerCachePath string\n\tlayout              pflag.Value\n\tplatform            []string\n\n\timages []string\n\n\tinsecure         bool\n\tforce            bool\n\tcosignSignatures bool\n}{\n\tlayout: flags.StringChoice(layoutOCI, layoutFlat),\n}\n\n// imageCacheServeCmd represents the image cache serve command.\nvar imageCacheServeCmd = &cobra.Command{\n\tUse:     \"cache-serve\",\n\tShort:   \"Serve an OCI image cache directory over HTTP(S) as a container registry\",\n\tLong:    `Serve an OCI image cache directory over HTTP(S) as a container registry`,\n\tExample: ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tctx, cancel := signal.NotifyContext(cmd.Context(), os.Interrupt)\n\t\tdefer cancel()\n\n\t\tdevelopment, err := zap.NewDevelopment()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create development logger: %w\", err)\n\t\t}\n\n\t\tif err = generateMirrorsConfigPatch(\n\t\t\timageCacheServeCmdFlags.address,\n\t\t\timageCacheServeCmdFlags.mirrors,\n\t\t\timageCacheServeCmdFlags.tlsCertFile != \"\" && imageCacheServeCmdFlags.tlsKeyFile != \"\",\n\t\t); err != nil {\n\t\t\tdevelopment.Error(\"failed to generate Talos config patch for registry mirrors\", zap.Error(err))\n\t\t}\n\n\t\tit := func(yield func(string) bool) {\n\t\t\tfor _, root := range []string{imageCacheServeCmdFlags.imageCachePath} {\n\t\t\t\tif !yield(root) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn registry.NewService(registry.NewMultiPathFS(it), development).Run(\n\t\t\tctx,\n\t\t\tregistry.WithTLS(\n\t\t\t\timageCacheServeCmdFlags.tlsCertFile,\n\t\t\t\timageCacheServeCmdFlags.tlsKeyFile,\n\t\t\t),\n\t\t\tregistry.WithAddress(imageCacheServeCmdFlags.address),\n\t\t)\n\t},\n}\n\n//nolint:gocyclo\nfunc generateMirrorsConfigPatch(addr string, mirrors []string, secure bool) error {\n\taddresses := []string{}\n\n\thost, port, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif host == \"\" || host == \"0.0.0.0\" || host == \"[::]\" {\n\t\t// list all IPs for the host\n\t\tips, err := net.InterfaceAddrs()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, addr := range ips {\n\t\t\tif ipnet, ok := addr.(*net.IPNet); ok {\n\t\t\t\tif ipnet.IP.IsLoopback() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taddresses = append(addresses, net.JoinHostPort(ipnet.IP.String(), port))\n\t\t\t}\n\n\t\t\tif ipa, ok := addr.(*net.IPAddr); ok {\n\t\t\t\tif ipa.IP.IsLoopback() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taddresses = append(addresses, net.JoinHostPort(ipa.IP.String(), port))\n\t\t\t}\n\t\t}\n\t} else {\n\t\taddresses = []string{net.JoinHostPort(host, port)}\n\t}\n\n\tif port == \"0\" {\n\t\treturn nil // we do not generate patch for dynamic ports\n\t}\n\n\tpatches := make([]config.Document, 0, len(mirrors))\n\n\tprefix := \"http://\"\n\tif secure {\n\t\tprefix = \"https://\"\n\t}\n\n\tfor _, mirror := range mirrors {\n\t\tpatch := cri.NewRegistryMirrorConfigV1Alpha1(mirror)\n\t\tpatch.RegistryEndpoints = []cri.RegistryEndpoint{}\n\n\t\tfor _, endpoint := range addresses {\n\t\t\tpatch.RegistryEndpoints = append(patch.RegistryEndpoints, cri.RegistryEndpoint{\n\t\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(prefix + endpoint))},\n\t\t\t})\n\t\t}\n\n\t\tpatches = append(patches, patch)\n\t}\n\n\tctr, err := container.New(patches...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpatchBytes, err := ctr.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconst patchFile = \"image-cache-mirrors-patch.yaml\"\n\n\tlog.Printf(\"writing config patch to %s\", patchFile)\n\n\treturn os.WriteFile(patchFile, patchBytes, 0o644)\n}\n\nvar imageCacheServeCmdFlags struct {\n\timageCachePath string\n\taddress        string\n\tmirrors        []string\n\ttlsCertFile    string\n\ttlsKeyFile     string\n}\n\n// imageCacheCertGenCmd represents the image cache tls certificate generation command.\nvar imageCacheCertGenCmd = &cobra.Command{\n\tUse:     \"cache-cert-gen\",\n\tShort:   \"Generate TLS certificates and CA patch required for securing image cache to Talos communication\",\n\tLong:    `Generate TLS certificates and CA patch required for securing image cache to Talos communication`,\n\tExample: ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tcaPEM, certPEM, keyPEM, err := mgmthelpers.GenerateSelfSignedCert(\n\t\t\timageCacheCertGenCmdFlags.advertisedAddresses,\n\t\t\timageCacheCertGenCmdFlags.advertisedNames,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tif err = generateCAConfigPatch(caPEM); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(imageCacheCertGenCmdFlags.tlsCaFile, caPEM, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(imageCacheCertGenCmdFlags.tlsCertFile, certPEM, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(imageCacheCertGenCmdFlags.tlsKeyFile, keyPEM, 0o600); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t},\n}\n\nfunc generateCAConfigPatch(caPEM []byte) error {\n\tpatch := security.NewTrustedRootsConfigV1Alpha1()\n\tpatch.MetaName = \"image-cache-ca\"\n\tpatch.Certificates = string(caPEM)\n\n\tctr, err := container.New(patch)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpatchBytes, err := ctr.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconst patchFile = \"image-cache-patch.yaml\"\n\n\tlog.Printf(\"writing config patch to %s\", patchFile)\n\n\treturn os.WriteFile(patchFile, patchBytes, 0o644)\n}\n\nvar imageCacheCertGenCmdFlags struct {\n\tadvertisedAddresses []net.IP\n\tadvertisedNames     []string\n\ttlsCaFile           string\n\ttlsCertFile         string\n\ttlsKeyFile          string\n}\n\nfunc init() {\n\timageCmd.PersistentFlags().StringVar(&imageCmdFlags.namespace, \"namespace\", \"cri\",\n\t\t\"namespace to use: \\\"system\\\" (etcd and kubelet images), \\\"cri\\\" for all Kubernetes workloads, \\\"inmem\\\" for in-memory containerd instance\",\n\t)\n\taddCommand(imageCmd)\n\n\timageCmd.AddCommand(imageListCmd)\n\timageCmd.AddCommand(imagePullCmd)\n\timageCmd.AddCommand(imageRemoveCmd)\n\n\timageCmd.AddCommand(imageTalosBundleCmd)\n\timageTalosBundleCmd.PersistentFlags().BoolVar(&imageTalosBundleCmdFlags.overlays, \"overlays\", true, \"Include images that belong to Talos overlays\")\n\timageTalosBundleCmd.PersistentFlags().BoolVar(&imageTalosBundleCmdFlags.extensions, \"extensions\", true, \"Include images that belong to Talos extensions\")\n\n\timageCmd.AddCommand(imageK8sBundleCmd)\n\timageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.k8sVersion, \"k8s-version\", \"Kubernetes semantic version\")\n\timageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.etcdVersion, \"etcd-version\", \"ETCD semantic version\")\n\timageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.flannelVersion, \"flannel-version\", \"Flannel CNI semantic version\")\n\timageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.corednsVersion, \"coredns-version\", \"CoreDNS semantic version\")\n\timageK8sBundleCmd.PersistentFlags().Var(imageK8sBundleCmdFlags.kubeNetworkPoliciesVersion, \"kube-network-policies-version\", \"kube-network-policies semantic version\")\n\n\timageCmd.AddCommand(imageCacheCreateCmd)\n\timageCacheCreateCmd.PersistentFlags().StringVar(&imageCacheCreateCmdFlags.imageCachePath, \"image-cache-path\", \"\", \"directory to save the image cache in OCI format\")\n\timageCacheCreateCmd.MarkPersistentFlagRequired(\"image-cache-path\") //nolint:errcheck\n\timageCacheCreateCmd.PersistentFlags().StringVar(&imageCacheCreateCmdFlags.imageLayerCachePath, \"image-layer-cache-path\", \"\", \"directory to save the image layer cache\")\n\timageCacheCreateCmd.PersistentFlags().Var(imageCacheCreateCmdFlags.layout, \"layout\",\n\t\t\"Specifies the cache layout format: \\\"oci\\\" for an OCI image layout directory, or \\\"flat\\\" for a registry-like flat file structure\")\n\timageCacheCreateCmd.PersistentFlags().StringSliceVar(&imageCacheCreateCmdFlags.platform, \"platform\", []string{\"linux/amd64\"}, \"platform to use for the cache\")\n\timageCacheCreateCmd.PersistentFlags().StringSliceVar(&imageCacheCreateCmdFlags.images, \"images\", nil, \"images to cache\")\n\timageCacheCreateCmd.MarkPersistentFlagRequired(\"images\") //nolint:errcheck\n\timageCacheCreateCmd.PersistentFlags().BoolVar(&imageCacheCreateCmdFlags.insecure, \"insecure\", false, \"allow insecure registries\")\n\timageCacheCreateCmd.PersistentFlags().BoolVar(&imageCacheCreateCmdFlags.force, \"force\", false, \"force overwrite of existing image cache\")\n\timageCacheCreateCmd.PersistentFlags().BoolVar(&imageCacheCreateCmdFlags.cosignSignatures, \"cosign-signatures\", true, \"pull and cache cosign signatures for images\")\n\n\timageCmd.AddCommand(imageCacheServeCmd)\n\timageCacheServeCmd.PersistentFlags().StringVar(&imageCacheServeCmdFlags.imageCachePath, \"image-cache-path\", \"\", \"directory to save the image cache in flat format\")\n\timageCacheServeCmd.MarkPersistentFlagRequired(\"image-cache-path\") //nolint:errcheck\n\timageCacheServeCmd.PersistentFlags().StringVar(&imageCacheServeCmdFlags.address, \"address\", constants.RegistrydListenAddress, \"address to serve the registry on\")\n\timageCacheServeCmd.PersistentFlags().StringSliceVar(&imageCacheServeCmdFlags.mirrors, \"mirror\", []string{\"docker.io\", \"ghcr.io\", \"registry.k8s.io\"},\n\t\t\"list of registry mirrors to add to the Talos config patch\")\n\timageCacheServeCmd.PersistentFlags().StringVar(&imageCacheServeCmdFlags.tlsCertFile, \"tls-cert-file\", \"\", \"TLS certificate file to use for serving\")\n\timageCacheServeCmd.PersistentFlags().StringVar(&imageCacheServeCmdFlags.tlsKeyFile, \"tls-key-file\", \"\", \"TLS key file to use for serving\")\n\n\timageCmd.AddCommand(imageCacheCertGenCmd)\n\timageCacheCertGenCmd.PersistentFlags().StringVar(&imageCacheCertGenCmdFlags.tlsCaFile, \"tls-ca-file\", \"ca.crt\", \"TLS certificate authority file\")\n\timageCacheCertGenCmd.PersistentFlags().StringVar(&imageCacheCertGenCmdFlags.tlsCertFile, \"tls-cert-file\", \"tls.crt\", \"TLS certificate file to use for serving\")\n\timageCacheCertGenCmd.PersistentFlags().StringVar(&imageCacheCertGenCmdFlags.tlsKeyFile, \"tls-key-file\", \"tls.key\", \"TLS key file to use for serving\")\n\timageCacheCertGenCmd.PersistentFlags().IPSliceVar(&imageCacheCertGenCmdFlags.advertisedAddresses, \"advertised-address\", []net.IP{}, \"The addresses to advertise.\")\n\timageCacheCertGenCmd.PersistentFlags().StringSliceVar(&imageCacheCertGenCmdFlags.advertisedNames, \"advertised-name\", []string{}, \"The DNS names to advertise.\")\n\timageIntegrationCmd.MarkPersistentFlagRequired(\"advertised-address\") //nolint:errcheck\n\n\timageCmd.AddCommand(imageIntegrationCmd)\n\timageIntegrationCmd.PersistentFlags().StringVar(&imageIntegrationCmdFlags.installerTag, \"installer-tag\", \"\", \"tag of the installer image to use\")\n\timageIntegrationCmd.MarkPersistentFlagRequired(\"installer-tag\") //nolint:errcheck\n\timageIntegrationCmd.PersistentFlags().StringVar(&imageIntegrationCmdFlags.talosTag, \"talos-tag\", version.Tag, \"tag of the installer image to use\")\n\timageIntegrationCmd.PersistentFlags().StringVar(&imageIntegrationCmdFlags.registryAndUser, \"registry-and-user\", \"\", \"registry and user to use for the images\")\n\timageIntegrationCmd.MarkPersistentFlagRequired(\"registry-and-user\") //nolint:errcheck\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/inspect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/formatters\"\n)\n\n// inspectCmd represents the inspect command.\nvar inspectCmd = &cobra.Command{\n\tUse:   \"inspect\",\n\tShort: \"Inspect internals of Talos\",\n\tLong:  ``,\n}\n\nvar inspectDependenciesCmdFlags struct {\n\twithResources bool\n}\n\n// inspectDependenciesCmd represents the inspect dependencies command.\nvar inspectDependenciesCmd = &cobra.Command{\n\tUse:   \"dependencies\",\n\tShort: \"Inspect controller-resource dependencies as graphviz graph.\",\n\tLong: `Inspect controller-resource dependencies as graphviz graph.\n\nPipe the output of the command through the \"dot\" program (part of graphviz package)\nto render the graph:\n\n    talosctl inspect dependencies | dot -Tpng > graph.png\n`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"inspect dependencies\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresp, err := c.Inspect.ControllerRuntimeDependencies(ctx)\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting controller runtime dependencies: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn formatters.RenderGraph(ctx, c, resp, os.Stdout, inspectDependenciesCmdFlags.withResources)\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(inspectCmd)\n\n\tinspectCmd.AddCommand(inspectDependenciesCmd)\n\tinspectDependenciesCmd.Flags().BoolVar(&inspectDependenciesCmdFlags.withResources, \"with-resources\", false, \"display live resource information with dependencies\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/install.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nvar installCmdFlags struct {\n\timageCmdFlagsType\n\n\tinstallerImage string\n}\n\nvar installCmd = &cobra.Command{\n\tUse:   \"install <disk>\",\n\tShort: \"Install Talos to disk on the target node\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\t// TODO: This API is not available in maintenance mode, and once the system is fully running, installation is not relevant.\n\t// Requires https://github.com/siderolabs/talos/issues/12702\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClientMaintenance(nil, func(ctx context.Context, c *client.Client) error {\n\t\t\treturn installInternal(ctx, c, args[0])\n\t\t})\n\t},\n}\n\n//nolint:gocyclo\nfunc installInternal(ctx context.Context, c *client.Client, disk string) error {\n\tcontainerdInstance, err := installCmdFlags.containerdInstance()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstream, err := c.LifecycleClient.Install(ctx, &machine.LifecycleServiceInstallRequest{\n\t\tContainerd: containerdInstance,\n\t\tSource: &machine.InstallArtifactsSource{\n\t\t\tImageName: installCmdFlags.installerImage,\n\t\t},\n\t\tDestination: &machine.InstallDestination{\n\t\t\tDisk: disk,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error starting install: %w\", err)\n\t}\n\n\trep := reporter.New()\n\n\texited := false\n\n\tfor {\n\t\tresp, err := stream.Recv()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error during install: %w\", err)\n\t\t}\n\n\t\tswitch payload := resp.GetProgress().GetResponse().(type) {\n\t\tcase *machine.LifecycleServiceInstallProgress_Message:\n\t\t\tif rep.IsColorized() {\n\t\t\t\trep.Report(reporter.Update{\n\t\t\t\t\tMessage: payload.Message,\n\t\t\t\t\tStatus:  reporter.StatusRunning,\n\t\t\t\t})\n\t\t\t}\n\t\tcase *machine.LifecycleServiceInstallProgress_ExitCode:\n\t\t\texited = true\n\n\t\t\tif payload.ExitCode != 0 {\n\t\t\t\trep.Report(reporter.Update{\n\t\t\t\t\tMessage: fmt.Sprintf(\"install failed with exit code %d\", payload.ExitCode),\n\t\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\t})\n\n\t\t\t\treturn fmt.Errorf(\"install failed with exit code %d\", payload.ExitCode)\n\t\t\t}\n\n\t\t\trep.Report(reporter.Update{\n\t\t\t\tMessage: \"install completed successfully\",\n\t\t\t\tStatus:  reporter.StatusSucceeded,\n\t\t\t})\n\t\t}\n\t}\n\n\tif !exited {\n\t\trep.Report(reporter.Update{\n\t\t\tMessage: \"install stream closed without exit code\",\n\t\t\tStatus:  reporter.StatusError,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tinstallCmd.Flags().StringVar(&installCmdFlags.namespace, \"namespace\", \"system\",\n\t\t\"namespace to use: \\\"system\\\" (etcd and kubelet images), \\\"cri\\\" for all Kubernetes workloads, \\\"inmem\\\" for in-memory containerd instance\",\n\t)\n\tinstallCmd.Flags().StringVarP(&installCmdFlags.installerImage, \"image\", \"i\",\n\t\tfmt.Sprintf(\"%s/%s/installer:%s\", images.Registry, images.Username, version.Trim(version.Tag)),\n\t\t\"the container image to use for performing the install\")\n\n\taddCommand(installCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/interfaces.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// interfacesCmd represents the net interfaces command.\nvar interfacesCmd = &cobra.Command{\n\tUse:    \"interfaces\",\n\tShort:  \"List network interfaces\",\n\tLong:   ``,\n\tArgs:   cobra.NoArgs,\n\tHidden: true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\treturn errors.New(\"`talosctl interfaces` is deprecated, please use `talosctl get addresses` and `talosctl get links` instead\")\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(interfacesCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/kubeconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/mattn/go-isatty\"\n\t\"github.com/siderolabs/go-kubeconfig\"\n\t\"github.com/spf13/cobra\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nconst stdoutOutput = \"-\"\n\nvar kubeconfigFlags struct {\n\tforce            bool\n\tforceContextName string\n\tmerge            bool\n}\n\n// kubeconfigCmd represents the kubeconfig command.\nvar kubeconfigCmd = &cobra.Command{\n\tUse:   \"kubeconfig [local-path]\",\n\tShort: \"Download the admin kubeconfig from the node\",\n\tLong: `Download the admin kubeconfig from the node.\nIf merge flag is true, config will be merged with ~/.kube/config or [local-path] if specified.\nOtherwise, kubeconfig will be written to PWD or [local-path] if specified.\n\nIf merge flag is false and [local-path] is \"-\", config will be written to stdout.`,\n\tArgs: cobra.MaximumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"kubeconfig\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tvar localPath string\n\n\t\t\tif len(args) == 0 {\n\t\t\t\t// no path given, use defaults\n\t\t\t\tvar err error\n\n\t\t\t\tif kubeconfigFlags.merge {\n\t\t\t\t\tlocalPath, err = kubeconfig.SinglePath()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlocalPath, err = os.Getwd()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error getting current working directory: %s\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlocalPath = args[0]\n\t\t\t}\n\n\t\t\tlocalPath = filepath.Clean(localPath)\n\n\t\t\tst, err := os.Stat(localPath)\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\treturn fmt.Errorf(\"error checking path %q: %w\", localPath, err)\n\t\t\t\t}\n\n\t\t\t\terr = os.MkdirAll(filepath.Dir(localPath), 0o755)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else if st.IsDir() {\n\t\t\t\t// only dir name was given, append `kubeconfig` by default\n\t\t\t\tlocalPath = filepath.Join(localPath, \"kubeconfig\")\n\t\t\t}\n\n\t\t\t_, err = os.Stat(localPath)\n\t\t\tif err == nil && !(kubeconfigFlags.force || kubeconfigFlags.merge) {\n\t\t\t\treturn fmt.Errorf(\"kubeconfig file already exists, use --force to overwrite: %q\", localPath)\n\t\t\t} else if err != nil {\n\t\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\t// merge doesn't make sense if target path doesn't exist\n\t\t\t\t\tkubeconfigFlags.merge = false\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"error checking path %q: %w\", localPath, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tr, err := c.KubeconfigRaw(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying: %w\", err)\n\t\t\t}\n\n\t\t\tdefer r.Close() //nolint:errcheck\n\n\t\t\tdata, err := helpers.ExtractFileFromTarGz(\"kubeconfig\", r)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif kubeconfigFlags.merge {\n\t\t\t\treturn extractAndMerge(data, localPath)\n\t\t\t}\n\n\t\t\tif localPath == stdoutOutput {\n\t\t\t\t_, err = os.Stdout.Write(data)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn os.WriteFile(localPath, data, 0o600)\n\t\t})\n\t},\n}\n\nfunc extractAndMerge(data []byte, localPath string) error {\n\tconfig, err := clientcmd.Load(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmerger, err := kubeconfig.Load(localPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinteractive := isatty.IsTerminal(os.Stdout.Fd())\n\n\terr = merger.Merge(config, kubeconfig.MergeOptions{\n\t\tActivateContext:  true,\n\t\tForceContextName: kubeconfigFlags.forceContextName,\n\t\tOutputWriter:     os.Stdout,\n\t\tConflictHandler: func(component kubeconfig.ConfigComponent, name string) (kubeconfig.ConflictDecision, error) {\n\t\t\tif kubeconfigFlags.force {\n\t\t\t\treturn kubeconfig.OverwriteDecision, nil\n\t\t\t}\n\n\t\t\tif !interactive {\n\t\t\t\treturn kubeconfig.RenameDecision, nil\n\t\t\t}\n\n\t\t\treturn askOverwriteOrRename(fmt.Sprintf(\"%s %q already exists\", component, name))\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn merger.Write(localPath)\n}\n\nfunc askOverwriteOrRename(prompt string) (kubeconfig.ConflictDecision, error) {\n\treader := bufio.NewReader(os.Stdin)\n\n\tfor {\n\t\tfmt.Printf(\"%s [(r)ename/(o)verwrite]: \", prompt)\n\n\t\tresponse, err := reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tswitch strings.ToLower(strings.TrimSpace(response)) {\n\t\tcase \"overwrite\", \"o\":\n\t\t\treturn kubeconfig.OverwriteDecision, nil\n\t\tcase \"rename\", \"r\":\n\t\t\treturn kubeconfig.RenameDecision, nil\n\t\t}\n\t}\n}\n\nfunc init() {\n\tkubeconfigCmd.Flags().BoolVarP(&kubeconfigFlags.force, \"force\", \"f\", false, \"Force overwrite of kubeconfig if already present, force overwrite on kubeconfig merge\")\n\tkubeconfigCmd.Flags().StringVar(&kubeconfigFlags.forceContextName, \"force-context-name\", \"\", \"Force context name for kubeconfig merge\")\n\tkubeconfigCmd.Flags().BoolVarP(&kubeconfigFlags.merge, \"merge\", \"m\", true, \"Merge with existing kubeconfig\")\n\taddCommand(kubeconfigCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/lifecycle/lifecycle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package lifecycle implements image install progress reporting.\npackage lifecycle\n\nimport (\n\t\"fmt\"\n\t\"maps\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// ProgressWriter writes install progress updates to a reporter.\ntype ProgressWriter struct {\n\t// ongoingInstalls keeps track of ongoing install jobs per node.\n\tongoingInstalls map[string]installJob\n}\n\n// UpdateJob updates the progress of a pull job for a given node and layer ID.\n//\n// It is supposed to be called whenever there is a progress update for a layer pull.\nfunc (w *ProgressWriter) UpdateJob(node string, status *machine.LifecycleServiceInstallProgress) {\n\tif w.ongoingInstalls == nil {\n\t\tw.ongoingInstalls = make(map[string]installJob)\n\t}\n\n\tw.ongoingInstalls[node] = installJob{Status: status}\n}\n\n// PrintLayerProgress prints the current layer pull progress to the reporter.\nfunc (w *ProgressWriter) PrintLayerProgress(rep *reporter.Reporter) {\n\tnodes := slices.Collect(maps.Keys(w.ongoingInstalls))\n\tsort.Strings(nodes)\n\n\tsb := strings.Builder{}\n\n\tfor _, node := range nodes {\n\t\tsb.WriteString(node + \": \")\n\n\t\tfmt.Fprintf(&sb, \"%s\\n\", w.ongoingInstalls[node].Status.Fmt())\n\t}\n\n\trep.Report(reporter.Update{\n\t\tMessage: sb.String(),\n\t\tStatus:  reporter.StatusRunning,\n\t})\n}\n\ntype installJob struct {\n\tStatus *machine.LifecycleServiceInstallProgress\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/list.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\thumanize \"github.com/dustin/go-humanize\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nconst sixMonths = 6 * time.Hour * 24 * 30\n\nvar (\n\tlong           bool\n\trecurse        bool\n\trecursionDepth int32\n\thumanizeFlag   bool\n\ttypes          []string\n)\n\n// lsCmd represents the ls command.\nvar lsCmd = &cobra.Command{\n\tUse:     \"list [path]\",\n\tAliases: []string{\"ls\"},\n\tShort:   \"Retrieve a directory listing\",\n\tLong:    ``,\n\tArgs:    cobra.MaximumNArgs(1),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) != 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn completePathFromNode(toComplete), cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif recurse && recursionDepth != 1 {\n\t\t\treturn errors.New(\"only one of flags --recurse and --depth can be specified at the same time\")\n\t\t}\n\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\trootDir := \"/\"\n\n\t\t\tif len(args) > 0 {\n\t\t\t\trootDir = args[0]\n\t\t\t}\n\n\t\t\t// handle all variants: --type=f,l; -tfl; etc\n\t\t\tvar reqTypes []machineapi.ListRequest_Type\n\n\t\t\tfor _, typ := range types {\n\t\t\t\tfor _, t := range typ {\n\t\t\t\t\t// handle both `find -type X` and os.FileMode.String() designations\n\t\t\t\t\tswitch t {\n\t\t\t\t\tcase 'f':\n\t\t\t\t\t\treqTypes = append(reqTypes, machineapi.ListRequest_REGULAR)\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\treqTypes = append(reqTypes, machineapi.ListRequest_DIRECTORY)\n\t\t\t\t\tcase 'l', 'L':\n\t\t\t\t\t\treqTypes = append(reqTypes, machineapi.ListRequest_SYMLINK)\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid file type: %s\", string(t))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif recurse {\n\t\t\t\trecursionDepth = -1\n\t\t\t}\n\n\t\t\tstream, err := c.LS(ctx, &machineapi.ListRequest{\n\t\t\t\tRoot:           rootDir,\n\t\t\t\tRecurse:        recursionDepth > 1 || recurse,\n\t\t\t\tRecursionDepth: recursionDepth,\n\t\t\t\tTypes:          reqTypes,\n\t\t\t\tReportXattrs:   long,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error fetching logs: %s\", err)\n\t\t\t}\n\n\t\t\tif !long {\n\t\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\t\tfmt.Fprintln(w, \"NODE\\tNAME\")\n\n\t\t\t\tdefer w.Flush() //nolint:errcheck\n\n\t\t\t\treturn helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\t\t\t\tif info.Error != \"\" {\n\t\t\t\t\t\treturn helpers.NonFatalError(fmt.Errorf(\"%s: error reading file %s: %s\", node, info.Name, info.Error))\n\t\t\t\t\t}\n\n\t\t\t\t\tif !multipleNodes {\n\t\t\t\t\t\tfmt.Println(info.RelativeName)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfmt.Fprintf(w, \"%s\\t%s\\n\",\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tinfo.RelativeName,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tdefer w.Flush() //nolint:errcheck\n\n\t\t\tfmt.Fprintln(w, \"NODE\\tMODE\\tUID\\tGID\\tSIZE(B)\\tLASTMOD\\tLABEL\\tNAME\")\n\n\t\t\treturn helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\t\t\tif info.Error != \"\" {\n\t\t\t\t\treturn helpers.NonFatalError(fmt.Errorf(\"%s: error reading file %s: %s\", node, info.Name, info.Error))\n\t\t\t\t}\n\n\t\t\t\tdisplay := info.RelativeName\n\t\t\t\tif info.Link != \"\" {\n\t\t\t\t\tdisplay += \" -> \" + info.Link\n\t\t\t\t}\n\n\t\t\t\tsize := strconv.FormatInt(info.Size, 10)\n\n\t\t\t\tif humanizeFlag {\n\t\t\t\t\tsize = humanize.Bytes(uint64(info.Size))\n\t\t\t\t}\n\n\t\t\t\ttimestamp := time.Unix(info.Modified, 0)\n\t\t\t\ttimestampFormatted := \"\"\n\n\t\t\t\tif humanizeFlag {\n\t\t\t\t\ttimestampFormatted = humanize.Time(timestamp)\n\t\t\t\t} else {\n\t\t\t\t\tif time.Since(timestamp) < sixMonths {\n\t\t\t\t\t\ttimestampFormatted = timestamp.Format(\"Jan _2 15:04:05\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttimestampFormatted = timestamp.Format(\"Jan _2 2006 15:04\")\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlabel := \"\"\n\n\t\t\t\tif info.Xattrs != nil {\n\t\t\t\t\tfor _, l := range info.Xattrs {\n\t\t\t\t\t\tif l.Name == \"security.selinux\" {\n\t\t\t\t\t\t\tlabel = string(bytes.Trim(l.Data, \"\\x00\\n\"))\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%d\\t%d\\t%s\\t%s\\t%s\\t%s\\n\",\n\t\t\t\t\tnode,\n\t\t\t\t\tos.FileMode(info.Mode).String(),\n\t\t\t\t\tinfo.Uid,\n\t\t\t\t\tinfo.Gid,\n\t\t\t\t\tsize,\n\t\t\t\t\ttimestampFormatted,\n\t\t\t\t\tlabel,\n\t\t\t\t\tdisplay,\n\t\t\t\t)\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t},\n}\n\nfunc init() {\n\ttypesHelp := strings.Join([]string{\n\t\t\"filter by specified types:\",\n\t\t\"f\" + \"\\t\" + \"regular file\",\n\t\t\"d\" + \"\\t\" + \"directory\",\n\t\t\"l, L\" + \"\\t\" + \"symbolic link\",\n\t}, \"\\n\")\n\n\tlsCmd.Flags().BoolVarP(&long, \"long\", \"l\", false, \"display additional file details\")\n\tlsCmd.Flags().BoolVarP(&recurse, \"recurse\", \"r\", false, \"recurse into subdirectories\")\n\tlsCmd.Flags().BoolVarP(&humanizeFlag, \"humanize\", \"H\", false, \"humanize size and time in the output\")\n\tlsCmd.Flags().Int32VarP(&recursionDepth, \"depth\", \"d\", 1, \"maximum recursion depth\")\n\tlsCmd.Flags().StringSliceVarP(&types, \"type\", \"t\", nil, typesHelp)\n\taddCommand(lsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/logs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar (\n\tfollow    bool\n\ttailLines int32\n)\n\nvar logsCmd = &cobra.Command{\n\tUse:   \"logs <service name>\",\n\tShort: \"Retrieve logs for a service\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) != 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\tif kubernetesFlag {\n\t\t\treturn getContainersFromNode(kubernetesFlag), cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn mergeSuggestions(getServiceFromNode(), getContainersFromNode(kubernetesFlag), getLogsContainers()), cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tnamespace string\n\t\t\t\tdriver    common.ContainerDriver\n\t\t\t)\n\n\t\t\tif kubernetesFlag {\n\t\t\t\tnamespace = constants.K8sContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CRI\n\t\t\t} else {\n\t\t\t\tnamespace = constants.SystemContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CONTAINERD\n\t\t\t}\n\n\t\t\tstream, err := c.Logs(ctx, namespace, driver, args[0], follow, tailLines)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error fetching logs: %s\", err)\n\t\t\t}\n\n\t\t\tdefaultNode := client.RemotePeer(stream.Context())\n\n\t\t\trespCh, errCh := newLineSlicer(stream)\n\n\t\t\tvar gotErrors bool\n\n\t\t\tfor data := range respCh {\n\t\t\t\tif data.Metadata != nil && data.Metadata.Error != \"\" {\n\t\t\t\t\t_, err = fmt.Fprintf(os.Stderr, \"ERROR: %s\\n\", data.Metadata.Error)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tgotErrors = true\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tnode := defaultNode\n\t\t\t\tif data.Metadata != nil && data.Metadata.Hostname != \"\" {\n\t\t\t\t\tnode = data.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\t_, err = fmt.Printf(\"%s: %s\\n\", node, data.Bytes)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err = <-errCh; err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting logs: %v\", err)\n\t\t\t}\n\n\t\t\tif gotErrors {\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\n// lineSlicer splits random chunks of bytes coming from nodes into a stream\n// of lines aggregated per node.\ntype lineSlicer struct {\n\trespCh chan *common.Data\n\terrCh  chan error\n\tpipes  map[string]*io.PipeWriter\n\twg     sync.WaitGroup\n}\n\nfunc newLineSlicer(stream machine.MachineService_LogsClient) (chan *common.Data, chan error) {\n\tslicer := &lineSlicer{\n\t\trespCh: make(chan *common.Data),\n\t\terrCh:  make(chan error, 1),\n\t\tpipes:  map[string]*io.PipeWriter{},\n\t}\n\n\tgo slicer.run(stream)\n\n\treturn slicer.respCh, slicer.errCh\n}\n\nfunc (slicer *lineSlicer) chopper(r io.Reader, hostname string) {\n\tdefer slicer.wg.Done()\n\n\tscanner := bufio.NewScanner(r)\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Bytes()\n\t\tline = xslices.CopyN(line, len(line))\n\n\t\tslicer.respCh <- &common.Data{\n\t\t\tMetadata: &common.Metadata{\n\t\t\t\tHostname: hostname,\n\t\t\t},\n\t\t\tBytes: line,\n\t\t}\n\t}\n}\n\nfunc (slicer *lineSlicer) getPipe(node string) *io.PipeWriter {\n\tpipe, ok := slicer.pipes[node]\n\tif !ok {\n\t\tvar piper *io.PipeReader\n\n\t\tpiper, pipe = io.Pipe()\n\n\t\tslicer.wg.Add(1)\n\n\t\tgo slicer.chopper(piper, node)\n\n\t\tslicer.pipes[node] = pipe\n\t}\n\n\treturn pipe\n}\n\nfunc (slicer *lineSlicer) cleanupChoppers() {\n\tfor _, p := range slicer.pipes {\n\t\t_ = p.Close() //nolint:errcheck\n\t}\n\n\tslicer.wg.Wait()\n}\n\nfunc (slicer *lineSlicer) run(stream machine.MachineService_LogsClient) {\n\tdefer close(slicer.errCh)\n\tdefer close(slicer.respCh)\n\n\tdefer slicer.cleanupChoppers()\n\n\tfor {\n\t\tdata, err := stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tslicer.errCh <- err\n\n\t\t\treturn\n\t\t}\n\n\t\tif data.Metadata != nil && data.Metadata.Error != \"\" {\n\t\t\t// errors are delivered OOB\n\t\t\tslicer.respCh <- data\n\n\t\t\tcontinue\n\t\t}\n\n\t\tnode := \"\"\n\n\t\tif data.Metadata != nil {\n\t\t\tnode = data.Metadata.Hostname\n\t\t}\n\n\t\t_, err = slicer.getPipe(node).Write(data.Bytes)\n\t\tcli.Should(err)\n\t}\n}\n\nfunc getLogsContainers() []string {\n\tvar result []string\n\n\t//nolint:errcheck\n\tWithClient(\n\t\tfunc(ctx context.Context, c *client.Client) error {\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.LogsContainers(ctx, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresult = xslices.FlatMap(resp.Messages, func(lc *machine.LogsContainer) []string { return lc.Ids })\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\treturn result\n}\n\nfunc init() {\n\tlogsCmd.Flags().BoolVarP(&kubernetesFlag, \"kubernetes\", \"k\", false, \"use the k8s.io containerd namespace\")\n\tlogsCmd.Flags().BoolVarP(&follow, \"follow\", \"f\", false, \"specify if the logs should be streamed\")\n\tlogsCmd.Flags().Int32VarP(&tailLines, \"tail\", \"\", -1, \"lines of log file to display (default is to show from the beginning)\")\n\n\tlogsCmd.Flags().Bool(\"use-cri\", false, \"use the CRI driver\")\n\tlogsCmd.Flags().MarkHidden(\"use-cri\") //nolint:errcheck\n\n\taddCommand(logsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/memory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"text/tabwriter\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar verbose bool\n\n// memoryCmd represents the processes command.\nvar memoryCmd = &cobra.Command{\n\tUse:     \"memory\",\n\tAliases: []string{\"m\", \"free\"},\n\tShort:   \"Show memory usage\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.Memory(ctx, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting memory stats: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\tif verbose {\n\t\t\t\tverboseRender(&remotePeer, resp)\n\t\t\t} else {\n\t\t\t\terr = briefRender(&remotePeer, resp)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn helpers.CheckErrors(resp.Messages...)\n\t\t})\n\t},\n}\n\nfunc briefRender(remotePeer *peer.Peer, resp *machineapi.MemoryResponse) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tTOTAL\\tUSED\\tFREE\\tSHARED\\tBUFFERS\\tCACHE\\tAVAILABLE\")\n\n\tdefaultNode := client.AddrFromPeer(remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\t// Default to displaying output as MB\n\t\tfmt.Fprintf(w, \"%s\\t%d\\t%d\\t%d\\t%d\\t%d\\t%d\\t%d\\n\",\n\t\t\tnode,\n\t\t\tmsg.Meminfo.Memtotal/1024,\n\t\t\t(msg.Meminfo.Memtotal-msg.Meminfo.Memfree-msg.Meminfo.Cached-msg.Meminfo.Buffers)/1024,\n\t\t\tmsg.Meminfo.Memfree/1024,\n\t\t\tmsg.Meminfo.Shmem/1024,\n\t\t\tmsg.Meminfo.Buffers/1024,\n\t\t\tmsg.Meminfo.Cached/1024,\n\t\t\tmsg.Meminfo.Memavailable/1024,\n\t\t)\n\t}\n\n\treturn w.Flush()\n}\n\nfunc verboseRender(remotePeer *peer.Peer, resp *machineapi.MemoryResponse) {\n\tdefaultNode := client.AddrFromPeer(remotePeer)\n\n\t// Dump as /proc/meminfo\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tfmt.Printf(\"%s: %s\\n\", \"NODE\", node)\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"MemTotal\", msg.Meminfo.Memtotal, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"MemFree\", msg.Meminfo.Memfree, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"MemAvailable\", msg.Meminfo.Memavailable, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Buffers\", msg.Meminfo.Buffers, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Cached\", msg.Meminfo.Cached, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"SwapCached\", msg.Meminfo.Swapcached, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Active\", msg.Meminfo.Active, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Inactive\", msg.Meminfo.Inactive, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"ActiveAnon\", msg.Meminfo.Activeanon, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"InactiveAnon\", msg.Meminfo.Inactiveanon, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"ActiveFile\", msg.Meminfo.Activefile, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"InactiveFile\", msg.Meminfo.Inactivefile, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Unevictable\", msg.Meminfo.Unevictable, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Mlocked\", msg.Meminfo.Mlocked, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"SwapTotal\", msg.Meminfo.Swaptotal, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"SwapFree\", msg.Meminfo.Swapfree, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Dirty\", msg.Meminfo.Dirty, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Writeback\", msg.Meminfo.Writeback, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"AnonPages\", msg.Meminfo.Anonpages, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Mapped\", msg.Meminfo.Mapped, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Shmem\", msg.Meminfo.Shmem, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Slab\", msg.Meminfo.Slab, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"SReclaimable\", msg.Meminfo.Sreclaimable, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"SUnreclaim\", msg.Meminfo.Sunreclaim, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"KernelStack\", msg.Meminfo.Kernelstack, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"PageTables\", msg.Meminfo.Pagetables, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"NFSUnstable\", msg.Meminfo.Nfsunstable, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Bounce\", msg.Meminfo.Bounce, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"WritebackTmp\", msg.Meminfo.Writebacktmp, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"CommitLimit\", msg.Meminfo.Commitlimit, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"CommittedAS\", msg.Meminfo.Committedas, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"VmallocTotal\", msg.Meminfo.Vmalloctotal, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"VmallocUsed\", msg.Meminfo.Vmallocused, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"VmallocChunk\", msg.Meminfo.Vmallocchunk, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"HardwareCorrupted\", msg.Meminfo.Hardwarecorrupted, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"AnonHugePages\", msg.Meminfo.Anonhugepages, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"ShmemHugePages\", msg.Meminfo.Shmemhugepages, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"ShmemPmdMapped\", msg.Meminfo.Shmempmdmapped, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"CmaTotal\", msg.Meminfo.Cmatotal, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"CmaFree\", msg.Meminfo.Cmafree, \"kB\")\n\t\tfmt.Printf(\"%s: %d\\n\", \"HugePagesTotal\", msg.Meminfo.Hugepagestotal)\n\t\tfmt.Printf(\"%s: %d\\n\", \"HugePagesFree\", msg.Meminfo.Hugepagesfree)\n\t\tfmt.Printf(\"%s: %d\\n\", \"HugePagesRsvd\", msg.Meminfo.Hugepagesrsvd)\n\t\tfmt.Printf(\"%s: %d\\n\", \"HugePagesSurp\", msg.Meminfo.Hugepagessurp)\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"Hugepagesize\", msg.Meminfo.Hugepagesize, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"DirectMap4k\", msg.Meminfo.Directmap4K, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"DirectMap2M\", msg.Meminfo.Directmap2M, \"kB\")\n\t\tfmt.Printf(\"%s: %d %s\\n\", \"DirectMap1G\", msg.Meminfo.Directmap1G, \"kB\")\n\t}\n}\n\nfunc init() {\n\tmemoryCmd.Flags().BoolVarP(&verbose, \"verbose\", \"v\", false, \"display extended memory statistics\")\n\taddCommand(memoryCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar metaCmdFlags struct {\n\tinsecure bool\n}\n\nvar metaCmd = &cobra.Command{\n\tUse:   \"meta\",\n\tShort: \"Write and delete keys in the META partition\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n}\n\nvar metaWriteCmd = &cobra.Command{\n\tUse:   \"write key value\",\n\tShort: \"Write a key-value pair to the META partition.\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(2),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tfn := func(ctx context.Context, c *client.Client) error {\n\t\t\tkey, err := strconv.ParseUint(args[0], 0, 8)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn c.MetaWrite(ctx, uint8(key), []byte(args[1]))\n\t\t}\n\n\t\tif metaCmdFlags.insecure {\n\t\t\treturn WithClientMaintenance(nil, fn)\n\t\t}\n\n\t\treturn WithClient(fn)\n\t},\n}\n\nvar metaDeleteCmd = &cobra.Command{\n\tUse:   \"delete key\",\n\tShort: \"Delete a key from the META partition.\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tfn := func(ctx context.Context, c *client.Client) error {\n\t\t\tkey, err := strconv.ParseUint(args[0], 0, 8)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn c.MetaDelete(ctx, uint8(key))\n\t\t}\n\n\t\tif metaCmdFlags.insecure {\n\t\t\treturn WithClientMaintenance(nil, fn)\n\t\t}\n\n\t\treturn WithClient(fn)\n\t},\n}\n\nfunc init() {\n\tmetaCmd.PersistentFlags().BoolVarP(&metaCmdFlags.insecure, \"insecure\", \"i\", false, \"write|delete meta using the insecure (encrypted with no auth) maintenance service\")\n\n\tmetaCmd.AddCommand(metaWriteCmd)\n\tmetaCmd.AddCommand(metaDeleteCmd)\n\taddCommand(metaCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/mounts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/formatters\"\n)\n\n// mountsCmd represents the mounts command.\nvar mountsCmd = &cobra.Command{\n\tUse:     \"mounts\",\n\tAliases: []string{\"mount\"},\n\tShort:   \"List mounts\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.Mounts(ctx, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting mount information: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn formatters.RenderMounts(resp, os.Stdout, &remotePeer)\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(mountsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/multiplex/multiplex.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package multiplex implements client-side multiplexing helpers.\npackage multiplex\n\n// Response represents a multiplexed response from a specific node.\ntype Response[ResponseT any] struct {\n\tNode    string\n\tPayload ResponseT\n\tErr     error\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/multiplex/stream.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage multiplex\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// Streaming initiates a multiplexed streaming gRPC client call to multiple nodes.\nfunc Streaming[ResponseT any](ctx context.Context, nodes []string, initiate func(context.Context) (grpc.ServerStreamingClient[ResponseT], error)) <-chan Response[*ResponseT] {\n\tresponseCh := make(chan Response[*ResponseT])\n\n\tvar wg sync.WaitGroup\n\n\tfor _, node := range nodes {\n\t\twg.Go(func() {\n\t\t\tstream, err := initiate(client.WithNode(ctx, node))\n\t\t\tif err != nil {\n\t\t\t\tchannel.SendWithContext(ctx, responseCh,\n\t\t\t\t\tResponse[*ResponseT]{\n\t\t\t\t\t\tNode: node,\n\t\t\t\t\t\tErr:  err,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tpayload, err := stream.Recv()\n\t\t\t\tif err != nil {\n\t\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tchannel.SendWithContext(ctx, responseCh,\n\t\t\t\t\t\tResponse[*ResponseT]{\n\t\t\t\t\t\t\tNode: node,\n\t\t\t\t\t\t\tErr:  err,\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif !channel.SendWithContext(ctx, responseCh,\n\t\t\t\t\tResponse[*ResponseT]{\n\t\t\t\t\t\tNode:    node,\n\t\t\t\t\t\tPayload: payload,\n\t\t\t\t\t},\n\t\t\t\t) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(responseCh)\n\t}()\n\n\treturn responseCh\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/multiplex/unary.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage multiplex\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// Unary initiates a multiplexed unary gRPC client call to multiple nodes.\nfunc Unary[ResponseT any](ctx context.Context, nodes []string, initiate func(context.Context) (*ResponseT, error)) <-chan Response[*ResponseT] {\n\tresponseCh := make(chan Response[*ResponseT])\n\n\tvar wg sync.WaitGroup\n\n\tfor _, node := range nodes {\n\t\twg.Go(func() {\n\t\t\tresponse, err := initiate(client.WithNode(ctx, node))\n\t\t\tif err != nil {\n\t\t\t\tchannel.SendWithContext(ctx, responseCh,\n\t\t\t\t\tResponse[*ResponseT]{\n\t\t\t\t\t\tNode: node,\n\t\t\t\t\t\tErr:  err,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tchannel.SendWithContext(ctx, responseCh,\n\t\t\t\tResponse[*ResponseT]{\n\t\t\t\t\tNode:    node,\n\t\t\t\t\tPayload: response,\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t}\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(responseCh)\n\t}()\n\n\treturn responseCh\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/netstat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar netstatCmdFlags struct {\n\tverbose   bool\n\textend    bool\n\tpid       bool\n\ttimers    bool\n\tlistening bool\n\tall       bool\n\tpods      bool\n\ttcp       bool\n\tudp       bool\n\tudplite   bool\n\traw       bool\n\tipv4      bool\n\tipv6      bool\n}\n\ntype netstat struct {\n\tclient        *client.Client\n\tNodeNetNSPods map[string]map[string]string\n}\n\n// netstatCmd represents the netstat command.\nvar netstatCmd = &cobra.Command{\n\tUse:     \"netstat\",\n\tAliases: []string{\"ss\"},\n\tShort:   \"Show network connections and sockets\",\n\tLong: `Show network connections and sockets.\n\nYou can pass an optional argument to view a specific pod's connections.\nTo do this, format the argument as \"namespace/pod\".\nNote that only pods with a pod network namespace are allowed.\nIf you don't pass an argument, the command will show host connections.`,\n\tArgs: cobra.MaximumNArgs(1),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) > 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\tvar podList []string\n\n\t\tif WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tn := netstat{\n\t\t\t\tNodeNetNSPods: make(map[string]map[string]string),\n\t\t\t\tclient:        c,\n\t\t\t}\n\n\t\t\terr := n.getPodNetNsFromNode(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, netNsPods := range n.NodeNetNSPods {\n\t\t\t\tfor _, podName := range netNsPods {\n\t\t\t\t\tpodList = append(podList, podName)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}) != nil {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn podList, cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treq := netstatFlagsToRequest()\n\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) (err error) {\n\t\t\tif netstatCmdFlags.pods && len(args) > 0 {\n\t\t\t\treturn errors.New(\"cannot use --pods and specify a pod\")\n\t\t\t}\n\n\t\t\tfindThePod := len(args) > 0\n\n\t\t\tn := netstat{\n\t\t\t\tclient: c,\n\t\t\t}\n\n\t\t\tn.NodeNetNSPods = make(map[string]map[string]string)\n\n\t\t\tif findThePod || netstatCmdFlags.pods {\n\t\t\t\terr = n.getPodNetNsFromNode(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif findThePod {\n\t\t\t\tvar foundNode, foundNetNs string\n\n\t\t\t\tfoundNode, foundNetNs = n.findPodNetNs(args[0])\n\n\t\t\t\tif foundNetNs == \"\" {\n\t\t\t\t\tcli.Fatalf(\"pod %s not found\", args[0])\n\t\t\t\t}\n\n\t\t\t\tctx = client.WithNode(ctx, foundNode)\n\n\t\t\t\treq.Netns.Netns = []string{foundNetNs}\n\t\t\t\treq.Netns.Hostnetwork = false\n\t\t\t}\n\n\t\t\tresponse, err := c.Netstat(ctx, req)\n\t\t\tif err != nil {\n\t\t\t\tif response == nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\terr = n.printNetstat(response)\n\n\t\t\treturn err\n\t\t})\n\t},\n}\n\n//nolint:gocyclo\nfunc netstatFlagsToRequest() *machine.NetstatRequest {\n\treq := machine.NetstatRequest{\n\t\tFeature: &machine.NetstatRequest_Feature{\n\t\t\tPid: netstatCmdFlags.pid,\n\t\t},\n\t\tL4Proto: &machine.NetstatRequest_L4Proto{\n\t\t\tTcp:      netstatCmdFlags.tcp,\n\t\t\tTcp6:     netstatCmdFlags.tcp,\n\t\t\tUdp:      netstatCmdFlags.udp,\n\t\t\tUdp6:     netstatCmdFlags.udp,\n\t\t\tUdplite:  netstatCmdFlags.udplite,\n\t\t\tUdplite6: netstatCmdFlags.udplite,\n\t\t\tRaw:      netstatCmdFlags.raw,\n\t\t\tRaw6:     netstatCmdFlags.raw,\n\t\t},\n\t\tNetns: &machine.NetstatRequest_NetNS{\n\t\t\tAllnetns:    netstatCmdFlags.pods,\n\t\t\tHostnetwork: true,\n\t\t},\n\t}\n\n\tswitch {\n\tcase netstatCmdFlags.all:\n\t\treq.Filter = machine.NetstatRequest_ALL\n\tcase netstatCmdFlags.listening:\n\t\treq.Filter = machine.NetstatRequest_LISTENING\n\tdefault:\n\t\treq.Filter = machine.NetstatRequest_CONNECTED\n\t}\n\n\tif netstatCmdFlags.verbose {\n\t\treq.L4Proto.Tcp = true\n\t\treq.L4Proto.Tcp6 = true\n\t\treq.L4Proto.Udp = true\n\t\treq.L4Proto.Udp6 = true\n\t\treq.L4Proto.Udplite = true\n\t\treq.L4Proto.Udplite6 = true\n\t\treq.L4Proto.Raw = true\n\t\treq.L4Proto.Raw6 = true\n\t}\n\n\tif !req.L4Proto.Tcp && !req.L4Proto.Tcp6 && !req.L4Proto.Udp && !req.L4Proto.Udp6 && !req.L4Proto.Udplite && !req.L4Proto.Udplite6 && !req.L4Proto.Raw && !req.L4Proto.Raw6 {\n\t\treq.L4Proto.Tcp = true\n\t\treq.L4Proto.Tcp6 = true\n\t\treq.L4Proto.Udp = true\n\t\treq.L4Proto.Udp6 = true\n\t}\n\n\tif netstatCmdFlags.ipv4 && !netstatCmdFlags.ipv6 {\n\t\treq.L4Proto.Tcp6 = false\n\t\treq.L4Proto.Udp6 = false\n\t\treq.L4Proto.Udplite6 = false\n\t\treq.L4Proto.Raw6 = false\n\t}\n\n\tif netstatCmdFlags.ipv6 && !netstatCmdFlags.ipv4 {\n\t\treq.L4Proto.Tcp = false\n\t\treq.L4Proto.Udp = false\n\t\treq.L4Proto.Udplite = false\n\t\treq.L4Proto.Raw = false\n\t}\n\n\treturn &req\n}\n\nfunc (n *netstat) getPodNetNsFromNode(ctx context.Context) (err error) {\n\tresp, err := n.client.Containers(ctx, constants.K8sContainerdNamespace, common.ContainerDriver_CRI)\n\tif err != nil {\n\t\tcli.Warning(\"error getting containers: %v\", err)\n\n\t\treturn err\n\t}\n\n\tfor _, msg := range resp.Messages {\n\t\tfor _, p := range msg.Containers {\n\t\t\tif p.NetworkNamespace == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif p.Pid == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif p.Id != p.PodId {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif n.NodeNetNSPods[msg.Metadata.Hostname] == nil {\n\t\t\t\tn.NodeNetNSPods[msg.Metadata.Hostname] = make(map[string]string)\n\t\t\t}\n\n\t\t\tn.NodeNetNSPods[msg.Metadata.Hostname][p.NetworkNamespace] = p.Id\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (n *netstat) findPodNetNs(findNamespaceAndPod string) (string, string) {\n\tvar foundNetNs, foundNode string\n\n\tfor node, netNSPods := range n.NodeNetNSPods {\n\t\tfor NetNs, podName := range netNSPods {\n\t\t\tif podName == strings.ToLower(findNamespaceAndPod) {\n\t\t\t\tfoundNetNs = NetNs\n\t\t\t\tfoundNode = node\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn foundNode, foundNetNs\n}\n\n//nolint:gocyclo\nfunc (n *netstat) printNetstat(response *machine.NetstatResponse) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tnode := \"\"\n\n\tfor i, message := range response.Messages {\n\t\tif message.Metadata != nil && message.Metadata.Hostname != \"\" {\n\t\t\tnode = message.Metadata.Hostname\n\t\t}\n\n\t\tif len(message.Connectrecord) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor j, record := range message.Connectrecord {\n\t\t\tif i == 0 && j == 0 {\n\t\t\t\tlabels := netstatSummaryLabels()\n\n\t\t\t\tif node != \"\" {\n\t\t\t\t\tfmt.Fprintln(w, \"NODE\\t\"+labels)\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Fprintln(w, labels)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar args []any\n\n\t\t\tif node != \"\" {\n\t\t\t\targs = append(args, node)\n\t\t\t}\n\n\t\t\tstate := \"\"\n\t\t\tif record.State != 7 {\n\t\t\t\tstate = record.State.String()\n\t\t\t}\n\n\t\t\targs = append(args, []any{\n\t\t\t\trecord.L4Proto,\n\t\t\t\tstrconv.FormatUint(record.Rxqueue, 10),\n\t\t\t\tstrconv.FormatUint(record.Txqueue, 10),\n\t\t\t\tfmt.Sprintf(\"%s:%d\", record.Localip, record.Localport),\n\t\t\t\tfmt.Sprintf(\"%s:%s\", record.Remoteip, wildcardIfZero(record.Remoteport)),\n\t\t\t\tstate,\n\t\t\t}...)\n\n\t\t\tif netstatCmdFlags.extend {\n\t\t\t\targs = append(args, []any{\n\t\t\t\t\tstrconv.FormatUint(uint64(record.Uid), 10),\n\t\t\t\t\tstrconv.FormatUint(record.Inode, 10),\n\t\t\t\t}...)\n\t\t\t}\n\n\t\t\tif netstatCmdFlags.pid {\n\t\t\t\tif record.Process.Pid != 0 {\n\t\t\t\t\targs = append(args, []any{\n\t\t\t\t\t\tfmt.Sprintf(\"%d/%s\", record.Process.Pid, record.Process.Name),\n\t\t\t\t\t}...)\n\t\t\t\t} else {\n\t\t\t\t\targs = append(args, []any{\n\t\t\t\t\t\t\"-\",\n\t\t\t\t\t}...)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif netstatCmdFlags.pods {\n\t\t\t\tif record.Netns == \"\" || node == \"\" || n.NodeNetNSPods[node] == nil {\n\t\t\t\t\targs = append(args, []any{\n\t\t\t\t\t\t\"-\",\n\t\t\t\t\t}...)\n\t\t\t\t} else {\n\t\t\t\t\targs = append(args, []any{\n\t\t\t\t\t\tn.NodeNetNSPods[node][record.Netns],\n\t\t\t\t\t}...)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif netstatCmdFlags.timers {\n\t\t\t\ttimerwhen := strconv.FormatFloat(float64(record.Timerwhen)/100, 'f', 2, 64)\n\n\t\t\t\targs = append(args, []any{\n\t\t\t\t\tfmt.Sprintf(\"%s (%s/%d/%d)\", strings.ToLower(record.Tr.String()), timerwhen, record.Retrnsmt, record.Timeout),\n\t\t\t\t}...)\n\t\t\t}\n\n\t\t\tpattern := strings.Repeat(\"%s\\t\", len(args))\n\t\t\tpattern = strings.TrimSpace(pattern) + \"\\n\"\n\n\t\t\tfmt.Fprintf(w, pattern, args...)\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\nfunc netstatSummaryLabels() (labels string) {\n\tlabels = strings.Join(\n\t\t[]string{\n\t\t\t\"Proto\",\n\t\t\t\"Recv-Q\",\n\t\t\t\"Send-Q\",\n\t\t\t\"Local Address\",\n\t\t\t\"Foreign Address\",\n\t\t\t\"State\",\n\t\t}, \"\\t\")\n\n\tif netstatCmdFlags.extend {\n\t\tlabels += \"\\t\" + strings.Join(\n\t\t\t[]string{\n\t\t\t\t\"Uid\",\n\t\t\t\t\"Inode\",\n\t\t\t}, \"\\t\")\n\t}\n\n\tif netstatCmdFlags.pid {\n\t\tlabels += \"\\t\" + \"PID/Program name\"\n\t}\n\n\tif netstatCmdFlags.pods {\n\t\tlabels += \"\\t\" + \"Pod\"\n\t}\n\n\tif netstatCmdFlags.timers {\n\t\tlabels += \"\\t\" + \"Timer\"\n\t}\n\n\treturn labels\n}\n\nfunc wildcardIfZero(num uint32) string {\n\tif num == 0 {\n\t\treturn \"*\"\n\t}\n\n\treturn strconv.FormatUint(uint64(num), 10)\n}\n\nfunc init() {\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.verbose, \"verbose\", \"v\", false, \"display sockets of all supported transport protocols\")\n\t// extend is normally -e but cannot be used as this is endpoint in talosctl\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.extend, \"extend\", \"x\", false, \"show detailed socket information\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.pid, \"programs\", \"p\", false, \"show process using socket\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.timers, \"timers\", \"o\", false, \"display timers\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.listening, \"listening\", \"l\", false, \"display listening server sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.all, \"all\", \"a\", false, \"display all sockets states (default: connected)\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.pods, \"pods\", \"k\", false, \"show sockets used by Kubernetes pods\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.tcp, \"tcp\", \"t\", false, \"display only TCP sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.udp, \"udp\", \"u\", false, \"display only UDP sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.udplite, \"udplite\", \"U\", false, \"display only UDPLite sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.raw, \"raw\", \"w\", false, \"display only RAW sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.ipv4, \"ipv4\", \"4\", false, \"display only ipv4 sockets\")\n\tnetstatCmd.Flags().BoolVarP(&netstatCmdFlags.ipv6, \"ipv6\", \"6\", false, \"display only ipv6 sockets\")\n\n\taddCommand(netstatCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/json.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage output\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// JSON outputs resources in JSON format.\ntype JSON struct {\n\twithEvents bool\n\twriter     io.Writer\n}\n\n// NewJSON initializes JSON resource output.\nfunc NewJSON(writer io.Writer) *JSON {\n\treturn &JSON{\n\t\twriter: writer,\n\t}\n}\n\n// WriteHeader implements output.Writer interface.\nfunc (j *JSON) WriteHeader(definition *meta.ResourceDefinition, withEvents bool) error {\n\tj.withEvents = withEvents\n\n\treturn nil\n}\n\n// prepareEncodableData prepares the data of a resource to be encoded as JSON and populates it with some extra information.\nfunc (j *JSON) prepareEncodableData(node string, r resource.Resource, event state.EventType) (map[string]any, error) {\n\tif r.Metadata().Type() == config.MachineConfigType && r.Metadata().Annotations().Empty() {\n\t\t// use a temporary wrapper to adjust YAML marshaling\n\t\t// for backwards compatibility with versions of Talos\n\t\t// which incorrectly marshal MachineConfig spec as YAML document\n\t\t// directly\n\t\tr = &mcYamlRepr{r}\n\t}\n\n\tout, err := resource.MarshalYAML(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tyamlBytes, err := yaml.Marshal(out)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar data map[string]any\n\n\terr = yaml.Unmarshal(yamlBytes, &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata[\"node\"] = node\n\n\tif j.withEvents {\n\t\tdata[\"event\"] = strings.ToLower(event.String())\n\t}\n\n\treturn data, nil\n}\n\nfunc writeAsIndentedJSON(wr io.Writer, data any) error {\n\tenc := json.NewEncoder(wr)\n\tenc.SetIndent(\"\", \"    \")\n\n\treturn enc.Encode(data)\n}\n\n// WriteResource implements output.Writer interface.\nfunc (j *JSON) WriteResource(node string, r resource.Resource, event state.EventType) error {\n\tdata, err := j.prepareEncodableData(node, r, event)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn writeAsIndentedJSON(j.writer, data)\n}\n\n// Flush implements output.Writer interface.\nfunc (j *JSON) Flush() error {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/jsonpath.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage output\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"k8s.io/client-go/third_party/forked/golang/template\"\n\t\"k8s.io/client-go/util/jsonpath\"\n)\n\n// JSONPath outputs resources in JSONPath format.\ntype JSONPath struct {\n\tjsonPath *jsonpath.JSONPath\n\tjson     *JSON\n\twriter   io.Writer\n}\n\n// NewJSONPath initializes JSONPath resource output.\nfunc NewJSONPath(writer io.Writer, jsonPath *jsonpath.JSONPath) *JSONPath {\n\treturn &JSONPath{\n\t\tjsonPath: jsonPath,\n\t\tjson:     NewJSON(writer),\n\t\twriter:   writer,\n\t}\n}\n\n// WriteHeader implements output.Writer interface.\nfunc (j *JSONPath) WriteHeader(definition *meta.ResourceDefinition, withEvents bool) error {\n\treturn j.json.WriteHeader(definition, withEvents)\n}\n\n// printResult prints a reflect.Value as JSON if it's a map, array, slice or struct.\n// But if it's just a 'scalar' type it prints it as a mere string.\nfunc printResult(wr io.Writer, result reflect.Value) error {\n\tkind := result.Kind()\n\tif kind == reflect.Interface {\n\t\tkind = result.Elem().Kind()\n\t}\n\n\toutputJSON := kind == reflect.Map ||\n\t\tkind == reflect.Array ||\n\t\tkind == reflect.Slice ||\n\t\tkind == reflect.Struct\n\n\tvar text []byte //nolint:prealloc // dynamic\n\n\tvar err error\n\n\tif outputJSON {\n\t\ttext, err = json.MarshalIndent(result.Interface(), \"\", \"    \")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\ttext, err = valueToText(result)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttext = append(text, '\\n')\n\n\tif _, err = wr.Write(text); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// valueToText translates reflect value to corresponding text.\nfunc valueToText(v reflect.Value) ([]byte, error) {\n\tiface, ok := template.PrintableValue(v)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"can't translate type %s to text\", v.Type())\n\t}\n\n\tvar buffer bytes.Buffer\n\n\tfmt.Fprint(&buffer, iface)\n\n\treturn buffer.Bytes(), nil\n}\n\n// WriteResource implements output.Writer interface.\nfunc (j *JSONPath) WriteResource(node string, r resource.Resource, event state.EventType) error {\n\tdata, err := j.json.prepareEncodableData(node, r, event)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresults, err := j.jsonPath.FindResults(data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error finding result for jsonpath: %w\", err)\n\t}\n\n\tj.jsonPath.EnableJSONOutput(true)\n\n\tfor _, resultGroup := range results {\n\t\tfor _, result := range resultGroup {\n\t\t\terr = printResult(j.writer, result)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error generating jsonpath results: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Flush implements output.Writer interface.\nfunc (j *JSONPath) Flush() error {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/jsonpath_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage output_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"k8s.io/client-go/util/jsonpath\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/output\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\nfunc TestWriteResource(t *testing.T) {\n\tnode := \"123.123.123.123\"\n\tevent := state.Created\n\n\tt.Run(\"prints scalar values on one line\", func(tt *testing.T) {\n\t\tvar buf bytes.Buffer\n\n\t\t// given\n\t\texpectedID := \"myCPU\"\n\t\tprocessorResource := hardware.NewProcessorInfo(expectedID)\n\t\tjsonPath := jsonpath.New(\"talos\")\n\t\tassert.Nil(t, jsonPath.Parse(\"{.metadata.id}\"))\n\n\t\t// when\n\t\ttestObj := output.NewJSONPath(&buf, jsonPath)\n\t\terr := testObj.WriteResource(node, processorResource, event)\n\n\t\t// then\n\t\tassert.Nil(t, err)\n\n\t\tassert.Equal(t, expectedID+\"\\n\", buf.String())\n\t})\n\n\tt.Run(\"prints complex values as JSON\", func(tt *testing.T) {\n\t\tvar buf bytes.Buffer\n\n\t\t// given\n\t\texpectedMetadata := `{\n    \"coreCount\": 2\n}\n`\n\t\tprocessorResource := hardware.NewProcessorInfo(\"myCPU\")\n\t\tprocessorResource.TypedSpec().CoreCount = 2\n\t\tjsonPath := jsonpath.New(\"talos\")\n\t\tassert.Nil(t, jsonPath.Parse(\"{.spec}\"))\n\n\t\t// when\n\t\ttestObj := output.NewJSONPath(&buf, jsonPath)\n\t\terr := testObj.WriteResource(node, processorResource, event)\n\n\t\t// then\n\t\tassert.Nil(t, err)\n\n\t\tassert.Equal(t, expectedMetadata, buf.String())\n\t})\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/output.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package output provides writers in different formats.\npackage output\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/spf13/cobra\"\n\t\"k8s.io/client-go/util/jsonpath\"\n)\n\n// Writer interface.\ntype Writer interface {\n\tWriteHeader(definition *meta.ResourceDefinition, withEvents bool) error\n\tWriteResource(node string, r resource.Resource, event state.EventType) error\n\tFlush() error\n}\n\n// NewWriter builds writer from type.\nfunc NewWriter(format string) (Writer, error) {\n\twriter := os.Stdout\n\n\tswitch {\n\tcase format == \"table\":\n\t\treturn NewTable(writer), nil\n\tcase format == \"yaml\":\n\t\treturn NewYAML(writer), nil\n\tcase format == \"json\":\n\t\treturn NewJSON(writer), nil\n\tcase strings.HasPrefix(format, \"jsonpath=\"):\n\t\tpath := format[len(\"jsonpath=\"):]\n\n\t\tjp := jsonpath.New(\"talos\")\n\n\t\tif err := jp.Parse(path); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing jsonpath: %w\", err)\n\t\t}\n\n\t\treturn NewJSONPath(writer, jp), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"output format %q is not supported\", format)\n\t}\n}\n\n// CompleteOutputArg represents tab completion for `--output` argument.\nfunc CompleteOutputArg(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\treturn []string{\"json\", \"table\", \"yaml\", \"jsonpath\"}, cobra.ShellCompDirectiveNoFileComp\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/table.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage output\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"k8s.io/client-go/util/jsonpath\"\n)\n\n// Table outputs resources in Table view.\ntype Table struct {\n\tw              tabwriter.Writer\n\twithEvents     bool\n\tdisplayType    string\n\tdynamicColumns []dynamicColumn\n}\n\ntype dynamicColumn func(value any) (string, error)\n\n// NewTable initializes table resource output.\nfunc NewTable(writer io.Writer) *Table {\n\toutput := &Table{}\n\toutput.w.Init(writer, 0, 0, 3, ' ', 0)\n\n\treturn output\n}\n\n// WriteHeader implements output.Writer interface.\nfunc (table *Table) WriteHeader(definition *meta.ResourceDefinition, withEvents bool) error {\n\ttable.withEvents = withEvents\n\tfields := []string{\"NAMESPACE\", \"TYPE\", \"ID\", \"VERSION\"}\n\n\tif withEvents {\n\t\tfields = slices.Insert(fields, 0, \"*\")\n\t}\n\n\ttable.displayType = definition.TypedSpec().DisplayType\n\n\tfor _, column := range definition.TypedSpec().PrintColumns {\n\t\tname := column.Name\n\n\t\tfields = append(fields, strings.ToUpper(name))\n\n\t\texpr := jsonpath.New(name)\n\t\tif err := expr.Parse(column.JSONPath); err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing column %q jsonpath: %w\", name, err)\n\t\t}\n\n\t\texpr = expr.AllowMissingKeys(true)\n\n\t\ttable.dynamicColumns = append(table.dynamicColumns, func(val any) (string, error) {\n\t\t\tvar buf bytes.Buffer\n\n\t\t\tif e := expr.Execute(&buf, val); e != nil {\n\t\t\t\treturn \"\", e\n\t\t\t}\n\n\t\t\treturn buf.String(), nil\n\t\t})\n\t}\n\n\tfields = slices.Insert(fields, 0, \"NODE\")\n\n\t_, err := fmt.Fprintln(&table.w, strings.Join(fields, \"\\t\"))\n\n\treturn err\n}\n\n// WriteResource implements output.Writer interface.\nfunc (table *Table) WriteResource(node string, r resource.Resource, event state.EventType) error {\n\tvalues := []string{r.Metadata().Namespace(), table.displayType, r.Metadata().ID(), r.Metadata().Version().String()}\n\n\tif table.withEvents {\n\t\tvar label string\n\n\t\tswitch event {\n\t\tcase state.Created:\n\t\t\tlabel = \"+\"\n\t\tcase state.Destroyed:\n\t\t\tlabel = \"-\"\n\t\tcase state.Updated:\n\t\t\tlabel = \" \"\n\t\tcase state.Bootstrapped, state.Errored, state.Noop:\n\t\t\treturn nil\n\t\t}\n\n\t\tvalues = slices.Insert(values, 0, label)\n\t}\n\n\tyml, err := yaml.Marshal(r.Spec())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar unstructured any\n\n\tif err = yaml.Unmarshal(yml, &unstructured); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, dynamicColumn := range table.dynamicColumns {\n\t\tvar value string\n\n\t\tvalue, err = dynamicColumn(unstructured)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvalues = append(values, value)\n\t}\n\n\tvalues = slices.Insert(values, 0, node)\n\n\t_, err = fmt.Fprintln(&table.w, strings.Join(values, \"\\t\"))\n\n\treturn err\n}\n\n// Flush implements output.Writer interface.\nfunc (table *Table) Flush() error {\n\treturn table.w.Flush()\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/output/yaml.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage output\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// YAML outputs resources in YAML format.\ntype YAML struct {\n\tneedDashes bool\n\twithEvents bool\n\twriter     io.Writer\n}\n\n// NewYAML initializes YAML resource output.\nfunc NewYAML(writer io.Writer) *YAML {\n\treturn &YAML{\n\t\twriter: writer,\n\t}\n}\n\n// WriteHeader implements output.Writer interface.\nfunc (y *YAML) WriteHeader(definition *meta.ResourceDefinition, withEvents bool) error {\n\ty.withEvents = withEvents\n\n\treturn nil\n}\n\n// WriteResource implements output.Writer interface.\nfunc (y *YAML) WriteResource(node string, r resource.Resource, event state.EventType) error {\n\tif r.Metadata().Type() == config.MachineConfigType && r.Metadata().Annotations().Empty() {\n\t\t// use a temporary wrapper to adjust YAML marshaling\n\t\t// for backwards compatibility with versions of Talos\n\t\t// which incorrectly marshal MachineConfig spec as YAML document\n\t\t// directly\n\t\tr = &mcYamlRepr{r}\n\t}\n\n\tout, err := resource.MarshalYAML(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif y.needDashes {\n\t\tfmt.Fprintln(y.writer, \"---\")\n\t}\n\n\ty.needDashes = true\n\n\tfmt.Fprintf(y.writer, \"node: %s\\n\", node)\n\n\tif y.withEvents {\n\t\tfmt.Fprintf(y.writer, \"event: %s\\n\", strings.ToLower(event.String()))\n\t}\n\n\treturn yaml.NewEncoder(y.writer).Encode(out)\n}\n\n// Flush implements output.Writer interface.\nfunc (y *YAML) Flush() error {\n\treturn nil\n}\n\ntype mcYamlRepr struct{ resource.Resource }\n\nfunc (m *mcYamlRepr) Spec() any { return &mcYamlSpec{res: m.Resource} }\n\ntype mcYamlSpec struct{ res resource.Resource }\n\nfunc (m *mcYamlSpec) MarshalYAML() (any, error) {\n\t// this is backwards compatibility for versions of Talos which marshaled the MachineConfig spec as a YAML document\n\t// instead of putting it as string\n\t//\n\t// if try to go via yaml.Marshal path, it will cut off all documents after the first one (as there is no way to return\n\t// multiple documents from MarshalYAML), so we need to extract the original body from the resource\n\tif pb, ok := m.res.(*protobuf.Resource); ok {\n\t\tp, err := pb.Marshal()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"marshal protobuf resource: %w\", err)\n\t\t}\n\n\t\treturn p.GetSpec().GetYamlSpec(), nil\n\t}\n\n\tout, err := yaml.Marshal(m.res.Spec())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn string(out), err\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/patch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/yamlstrip\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\nvar patchCmdFlags struct {\n\thelpers.Mode\n\n\tnamespace        string\n\tpatch            []string\n\tpatchFile        string\n\tdryRun           bool\n\tconfigTryTimeout time.Duration\n}\n\nfunc extractMachineConfigBody(mc resource.Resource) ([]byte, error) {\n\tif mc.Metadata().Annotations().Empty() {\n\t\t// this is backwards compatibility for versions of Talos which marshaled the MachineConfig spec as a YAML document\n\t\t// instead of putting it as string\n\t\t//\n\t\t// if try to go via yaml.Marshal path, it will cut off all documents after the first one (as there is no way to return\n\t\t// multiple documents from MarshalYAML), so we need to extract the original body from the resource\n\t\tif pb, ok := mc.(*protobuf.Resource); ok {\n\t\t\tp, err := pb.Marshal()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"marshal protobuf resource: %w\", err)\n\t\t\t}\n\n\t\t\treturn []byte(p.GetSpec().GetYamlSpec()), nil\n\t\t}\n\n\t\treturn yaml.Marshal(mc.Spec())\n\t}\n\n\tspec, err := yaml.Marshal(mc.Spec())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar bodyStr string\n\n\tif err = yaml.Unmarshal(spec, &bodyStr); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn []byte(bodyStr), nil\n}\n\nfunc patchFn(c *client.Client, patches []configpatcher.Patch) func(context.Context, string, resource.Resource, error) error {\n\treturn func(ctx context.Context, node string, mc resource.Resource, callError error) error {\n\t\tif callError != nil {\n\t\t\treturn fmt.Errorf(\"%s: %w\", node, callError)\n\t\t}\n\n\t\tif mc.Metadata().Type() != config.MachineConfigType {\n\t\t\treturn fmt.Errorf(\"%s: unsupported resource type: %s\", node, mc.Metadata().Type())\n\t\t}\n\n\t\tif mc.Metadata().ID() != config.ActiveID {\n\t\t\treturn nil\n\t\t}\n\n\t\tbody, err := extractMachineConfigBody(mc)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcfg, err := configpatcher.Apply(configpatcher.WithBytes(body), patches)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tpatched, err := cfg.Bytes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresp, err := c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{\n\t\t\tData:           patched,\n\t\t\tMode:           patchCmdFlags.Mode.Mode,\n\t\t\tDryRun:         patchCmdFlags.dryRun,\n\t\t\tTryModeTimeout: durationpb.New(patchCmdFlags.configTryTimeout),\n\t\t})\n\n\t\tif bytes.Equal(\n\t\t\tbytes.TrimSpace(yamlstrip.Comments(patched)),\n\t\t\tbytes.TrimSpace(yamlstrip.Comments(body)),\n\t\t) {\n\t\t\tfmt.Fprintln(os.Stderr, \"Apply was skipped: no changes detected.\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"patched %s/%s at the node %s\\n\",\n\t\t\tmc.Metadata().Type(),\n\t\t\tmc.Metadata().ID(),\n\t\t\tnode,\n\t\t)\n\n\t\thelpers.PrintApplyResults(resp)\n\n\t\treturn err\n\t}\n}\n\n// patchCmd represents the edit command.\nvar patchCmd = &cobra.Command{\n\tUse:   \"patch machineconfig\",\n\tShort: \"Patch machine configuration of a Talos node with a local patch.\",\n\tArgs:  cobra.RangeArgs(1, 2),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif patchCmdFlags.patchFile != \"\" {\n\t\t\t\tpatchCmdFlags.patch = append(patchCmdFlags.patch, \"@\"+patchCmdFlags.patchFile)\n\t\t\t}\n\n\t\t\tif len(patchCmdFlags.patch) == 0 {\n\t\t\t\treturn errors.New(\"either --patch or --patch-file should be defined\")\n\t\t\t}\n\n\t\t\tpatches, err := configpatcher.LoadPatches(patchCmdFlags.patch)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, node := range GlobalArgs.Nodes {\n\t\t\t\tnodeCtx := client.WithNodes(ctx, node)\n\t\t\t\tif err := helpers.ForEachResource(nodeCtx, c, nil, patchFn(c, patches), patchCmdFlags.namespace, args...); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\tpatchCmd.Flags().StringVar(&patchCmdFlags.namespace, \"namespace\", \"\", \"resource namespace (default is to use default namespace per resource)\")\n\tpatchCmd.Flags().StringVar(&patchCmdFlags.patchFile, \"patch-file\", \"\", \"a file containing a patch to be applied to the resource.\")\n\tpatchCmd.Flags().StringArrayVarP(&patchCmdFlags.patch, \"patch\", \"p\", nil, \"the patch to be applied to the resource file, use @file to read a patch from file.\")\n\tpatchCmd.Flags().BoolVar(&patchCmdFlags.dryRun, \"dry-run\", false, \"print the change summary and patch preview without applying the changes\")\n\tpatchCmd.Flags().DurationVar(&patchCmdFlags.configTryTimeout, \"timeout\", constants.ConfigTryTimeout, \"the config will be rolled back after specified timeout (if try mode is selected)\")\n\thelpers.AddModeFlags(&patchCmdFlags.Mode, patchCmd)\n\taddCommand(patchCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/pcap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/gopacket/gopacket\"\n\t\"github.com/gopacket/gopacket/pcapgo\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar pcapCmdFlags struct {\n\tiface     string\n\tpromisc   bool\n\tsnaplen   int\n\toutput    string\n\tbpfFilter string\n\tduration  time.Duration\n}\n\n// pcapCmd represents the pcap command.\nvar pcapCmd = &cobra.Command{\n\tUse:     \"pcap\",\n\tAliases: []string{\"tcpdump\"},\n\tShort:   \"Capture the network packets from the node.\",\n\tLong:    `The command launches packet capture on the node and streams back the packets as raw pcap file.`,\n\tExample: `Default behavior is to decode the packets with internal decoder to stdout:\n\n    talosctl pcap -i eth0\n\nRaw pcap file can be saved with ` + \"`--output`\" + ` flag:\n\n    talosctl pcap -i eth0 --output eth0.pcap\n\nOutput can be piped to tcpdump:\n\n    talosctl pcap -i eth0 -o - | tcpdump -vvv -r -\n\nBPF filter can be applied, but it has to compiled to BPF instructions first using tcpdump.\nCorrect link type should be specified for the tcpdump: EN10MB for Ethernet links and RAW\nfor e.g. Wireguard tunnels:\n\n    talosctl pcap -i eth0 --bpf-filter \"$(tcpdump -dd -y EN10MB 'tcp and dst port 80')\"\n\n    talosctl pcap -i kubespan --bpf-filter \"$(tcpdump -dd -y RAW 'port 50000')\"\n\nAs packet capture is transmitted over the network, it is recommended to filter out the Talos API traffic,\ne.g. by excluding packets with the port 50000.\n   `,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"pcap\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif pcapCmdFlags.duration > 0 {\n\t\t\t\tvar cancel context.CancelFunc\n\n\t\t\t\tctx, cancel = context.WithTimeout(ctx, pcapCmdFlags.duration)\n\t\t\t\tdefer cancel()\n\t\t\t}\n\n\t\t\treq := machine.PacketCaptureRequest{\n\t\t\t\tInterface:   pcapCmdFlags.iface,\n\t\t\t\tPromiscuous: pcapCmdFlags.promisc,\n\t\t\t}\n\n\t\t\tvar err error\n\n\t\t\treq.BpfFilter, err = parseBPFInstructions(pcapCmdFlags.bpfFilter)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr, err := c.PacketCapture(ctx, &req)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying: %w\", err)\n\t\t\t}\n\n\t\t\tif pcapCmdFlags.output == \"\" {\n\t\t\t\treturn dumpPackets(ctx, r)\n\t\t\t}\n\n\t\t\tvar out io.Writer\n\n\t\t\tif pcapCmdFlags.output == \"-\" {\n\t\t\t\tout = os.Stdout\n\t\t\t} else {\n\t\t\t\tout, err = os.Create(pcapCmdFlags.output)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_, err = io.Copy(out, r)\n\n\t\t\tif errors.Is(err, io.EOF) || client.StatusCode(err) == codes.DeadlineExceeded {\n\t\t\t\terr = nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t})\n\t},\n}\n\n// snapLength defines a snap length for the packet reading. For some reason\n// TF_PACKET captures more than the snap length. Tools like tcpdump ignore snaplen entirely and set their own\n// (https://github.com/the-tcpdump-group/tcpdump/blob/9fad826b0e487e8939325d62b7a461619b2722eb/netdissect.h#L342)\n// so it makes sense to do the same.\nconst snapLength = 262144\n\nfunc dumpPackets(ctx context.Context, r io.Reader) error {\n\tsrc, err := pcapgo.NewReader(r)\n\tif err != nil {\n\t\tif errors.Is(err, io.EOF) {\n\t\t\t// nothing in the capture at all\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error opening pcap reader: %w\", err)\n\t}\n\n\tsrc.SetSnaplen(snapLength)\n\n\tforEachPacket(\n\t\tctx,\n\t\tgopacket.NewZeroCopyPacketSource(src, src.LinkType(), gopacket.WithPool(true)),\n\t\tfunc(packet gopacket.Packet, err error) {\n\t\t\tswitch err {\n\t\t\tcase nil:\n\t\t\t\tfmt.Println(packet)\n\t\t\tdefault:\n\t\t\t\tfmt.Println(\"packet capture error:\", err)\n\t\t\t}\n\t\t},\n\t)\n\n\treturn nil\n}\n\n// parseBPFInstructions parses the BPF raw instructions in 'tcpdump -dd' format.\n//\n// Example:\n//\n//\t{ 0x30, 0, 0, 0x00000000 },\n//\t{ 0x54, 0, 0, 0x000000f0 },\n//\t{ 0x15, 0, 8, 0x00000060 },\n//\n//nolint:dupword\nfunc parseBPFInstructions(in string) ([]*machine.BPFInstruction, error) {\n\tin = strings.TrimSpace(in)\n\n\tif in == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tvar result []*machine.BPFInstruction //nolint:prealloc\n\n\tfor line := range strings.SplitSeq(in, \"\\n\") {\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tins := &machine.BPFInstruction{}\n\n\t\tn, err := fmt.Sscanf(line, \"{ 0x%x, %d, %d, 0x%x },\", &ins.Op, &ins.Jt, &ins.Jf, &ins.K)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing bpf instruction %q: %w\", line, err)\n\t\t}\n\n\t\tif n != 4 {\n\t\t\treturn nil, fmt.Errorf(\"error parsing bpf instruction %q: expected 4 fields, got %d\", line, n)\n\t\t}\n\n\t\tresult = append(result, ins)\n\t}\n\n\treturn result, nil\n}\n\nfunc init() {\n\tpcapCmd.Flags().StringVarP(&pcapCmdFlags.iface, \"interface\", \"i\", \"eth0\", \"interface name to capture packets on\")\n\tpcapCmd.Flags().BoolVar(&pcapCmdFlags.promisc, \"promiscuous\", false, \"put interface into promiscuous mode\")\n\tpcapCmd.Flags().IntVarP(&pcapCmdFlags.snaplen, \"snaplen\", \"s\", 4096, \"maximum packet size to capture\")\n\tpcapCmd.Flags().StringVarP(&pcapCmdFlags.output, \"output\", \"o\", \"\", \"if not set, decode packets to stdout; if set write raw pcap data to a file, use '-' for stdout\")\n\tpcapCmd.Flags().StringVar(&pcapCmdFlags.bpfFilter, \"bpf-filter\", \"\", \"bpf filter to apply, tcpdump -dd format\")\n\tpcapCmd.Flags().DurationVar(&pcapCmdFlags.duration, \"duration\", 0, \"duration of the capture\")\n\tpcapCmd.Flags().MarkDeprecated(\"snaplen\", \"support of snap length is removed\") //nolint:errcheck\n\n\taddCommand(pcapCmd)\n}\n\n// forEachPacket reads packets from the packet source and calls the provided function for each packet. fn should not\n// store the packet as it will be reused for the next packet. It will also call fn with nil packet and non nill\n// error if the error is not known. If the context is canceled, the function will return as soon as\n// [gopacket.PacketSource.NextPacket] returns.\n//\n// This function is more or less direct copy of [gopacket.PacketSource.PacketsCtx] minus the sleeps.\n//\n//nolint:gocyclo\nfunc forEachPacket(ctx context.Context, p *gopacket.PacketSource, fn func(gopacket.Packet, error)) {\n\tfor ctx.Err() == nil {\n\t\tpacket, err := p.NextPacket()\n\t\tif err == nil {\n\t\t\tfn(packet, nil)\n\n\t\t\tif ctx.Err() != nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// If we use pooled packets, we need to send them back to the pool\n\t\t\tif pooled, ok := packet.(gopacket.PooledPacket); ok {\n\t\t\t\tpooled.Dispose()\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// if timeout error -> retry\n\t\tvar netErr net.Error\n\t\tif ok := errors.As(err, &netErr); ok && netErr.Timeout() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Immediately break for known unrecoverable errors\n\t\tif errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) ||\n\t\t\terrors.Is(err, io.ErrNoProgress) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, io.ErrShortBuffer) ||\n\t\t\terrors.Is(err, syscall.EBADF) ||\n\t\t\tstrings.Contains(err.Error(), \"use of closed file\") {\n\t\t\tbreak\n\t\t}\n\n\t\t// Otherwise, send error to the caller\n\t\tfn(nil, err)\n\n\t\t// and try again if context is not canceled\n\t\tif ctx.Err() != nil {\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/processes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/ryanuber/columnize\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar sortMethod string\n\n// processesCmd represents the processes command.\nvar processesCmd = &cobra.Command{\n\tUse:     \"processes\",\n\tAliases: []string{\"p\", \"ps\"},\n\tShort:   \"List running processes\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\toutput, err := processesOutput(ctx, c)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(output)\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\tprocessesCmd.Flags().StringVarP(&sortMethod, \"sort\", \"s\", \"rss\", \"Column to sort output by. [rss|cpu]\")\n\taddCommand(processesCmd)\n}\n\ntype by func(p1, p2 *machineapi.ProcessInfo) bool\n\nfunc (b by) sort(procs []*machineapi.ProcessInfo) {\n\tps := &procSorter{\n\t\tprocs: procs,\n\t\tby:    b, // The Sort method's receiver is the function (closure) that defines the sort order.\n\t}\n\tsort.Sort(ps)\n}\n\ntype procSorter struct {\n\tprocs []*machineapi.ProcessInfo\n\tby    func(p1, p2 *machineapi.ProcessInfo) bool // Closure used in the Less method.\n}\n\n// Len is part of sort.Interface.\nfunc (s *procSorter) Len() int {\n\treturn len(s.procs)\n}\n\n// Swap is part of sort.Interface.\nfunc (s *procSorter) Swap(i, j int) {\n\ts.procs[i], s.procs[j] = s.procs[j], s.procs[i]\n}\n\n// Less is part of sort.Interface. It is implemented by calling the \"by\" closure in the sorter.\nfunc (s *procSorter) Less(i, j int) bool {\n\treturn s.by(s.procs[i], s.procs[j])\n}\n\n// Sort Methods.\nvar rss = func(p1, p2 *machineapi.ProcessInfo) bool {\n\t// Reverse sort ( Descending )\n\treturn p1.ResidentMemory > p2.ResidentMemory\n}\n\nvar cpu = func(p1, p2 *machineapi.ProcessInfo) bool {\n\t// Reverse sort ( Descending )\n\treturn p1.CpuTime > p2.CpuTime\n}\n\n//nolint:gocyclo\nfunc processesOutput(ctx context.Context, c *client.Client) (output string, err error) {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.Processes(ctx, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\treturn output, err\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tvar s []string\n\n\ts = append(s, \"NODE | PID | STATE | THREADS | CPU-TIME | VIRTMEM | RESMEM | LABEL | COMMAND\")\n\n\tfor _, msg := range resp.Messages {\n\t\tprocs := msg.Processes\n\n\t\tswitch sortMethod {\n\t\tcase \"cpu\":\n\t\t\tby(cpu).sort(procs)\n\t\tdefault:\n\t\t\tby(rss).sort(procs)\n\t\t}\n\n\t\tvar args string\n\n\t\tfor _, p := range procs {\n\t\t\tswitch {\n\t\t\tcase p.Executable == \"\":\n\t\t\t\targs = p.Command\n\t\t\tcase p.Args != \"\" && strings.Fields(p.Args)[0] == filepath.Base(strings.Fields(p.Executable)[0]):\n\t\t\t\targs = strings.Replace(p.Args, strings.Fields(p.Args)[0], p.Executable, 1)\n\t\t\tdefault:\n\t\t\t\targs = p.Args\n\t\t\t}\n\n\t\t\t// filter out non-printable characters\n\t\t\targs = strings.Map(func(r rune) rune {\n\t\t\t\tif r < 32 || r > 126 {\n\t\t\t\t\treturn ' '\n\t\t\t\t}\n\n\t\t\t\treturn r\n\t\t\t}, args)\n\n\t\t\tnode := defaultNode\n\n\t\t\tif msg.Metadata != nil {\n\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t}\n\n\t\t\ts = append(s,\n\t\t\t\tfmt.Sprintf(\"%12s | %6d | %1s | %4d | %8.2f | %7s | %7s | %64s | %s\",\n\t\t\t\t\tnode, p.Pid, p.State, p.Threads, p.CpuTime, humanize.Bytes(p.VirtualMemory), humanize.Bytes(p.ResidentMemory), p.Label, args))\n\t\t}\n\t}\n\n\tres := columnize.SimpleFormat(s)\n\n\treturn res, helpers.CheckErrors(resp.Messages...)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/pull/pull.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pull implements image pull progress reporting.\npackage pull\n\nimport (\n\t\"fmt\"\n\t\"maps\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// ProgressWriter writes pull progress updates to a reporter.\ntype ProgressWriter struct {\n\t// ongoingPulls keeps track of ongoing pull jobs per node.\n\tongoingPulls map[string]pullJobs\n}\n\n// UpdateJob updates the progress of a pull job for a given node and layer ID.\n//\n// It is supposed to be called whenever there is a progress update for a layer pull.\nfunc (w *ProgressWriter) UpdateJob(node, layerID string, progress *machine.ImageServicePullLayerProgress) {\n\tif w.ongoingPulls == nil {\n\t\tw.ongoingPulls = make(map[string]pullJobs)\n\t}\n\n\tongoingPulls, ok := w.ongoingPulls[node]\n\tif !ok {\n\t\tongoingPulls = pullJobs{}\n\t}\n\n\tfor _, job := range ongoingPulls {\n\t\tif job.LayerID == layerID {\n\t\t\tjob.Status = progress\n\n\t\t\treturn\n\t\t}\n\t}\n\n\tongoingPulls = append(ongoingPulls, &pullJob{\n\t\tLayerID: layerID,\n\t\tStatus:  progress,\n\t})\n\n\tw.ongoingPulls[node] = ongoingPulls\n}\n\n// PrintLayerProgress prints the current layer pull progress to the reporter.\nfunc (w *ProgressWriter) PrintLayerProgress(rep *reporter.Reporter) {\n\tnodes := slices.Collect(maps.Keys(w.ongoingPulls))\n\tsort.Strings(nodes)\n\n\tsb := strings.Builder{}\n\n\tfor _, node := range nodes {\n\t\tsb.WriteString(node + \":\\n\")\n\n\t\tongoingPulls := w.ongoingPulls[node]\n\n\t\tslices.SortFunc(ongoingPulls, func(a, b *pullJob) int {\n\t\t\treturn strings.Compare(a.LayerID, b.LayerID)\n\t\t})\n\n\t\tfor _, job := range ongoingPulls {\n\t\t\tfmt.Fprintf(&sb, \"  %s\\n\", job.Status.Fmt())\n\t\t}\n\t}\n\n\trep.Report(reporter.Update{\n\t\tMessage: sb.String(),\n\t\tStatus:  reporter.StatusRunning,\n\t})\n}\n\ntype pullJob struct {\n\tLayerID string\n\tStatus  *machine.ImageServicePullLayerProgress\n}\n\ntype pullJobs []*pullJob\n\nfunc (p pullJobs) Len() int {\n\treturn len(p)\n}\n\nfunc (p pullJobs) Swap(i, j int) {\n\tp[i], p[j] = p[j], p[i]\n}\n\nfunc (p pullJobs) Less(i, j int) bool {\n\treturn p[i].LayerID < p[j].LayerID\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/read.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// readCmd represents the read command.\nvar readCmd = &cobra.Command{\n\tUse:     \"read <path>\",\n\tShort:   \"Read a file on the machine\",\n\tLong:    ``,\n\tArgs:    cobra.ExactArgs(1),\n\tAliases: []string{\"cat\"},\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) != 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn completePathFromNode(toComplete), cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.FailIfMultiNodes(ctx, \"read\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr, err := c.Read(ctx, args[0])\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading file: %w\", err)\n\t\t\t}\n\n\t\t\tdefer r.Close() //nolint:errcheck\n\n\t\t\t_, err = io.Copy(os.Stdout, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading: %w\", err)\n\t\t\t}\n\n\t\t\treturn r.Close()\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(readCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/reboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/action\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nvar rebootCmdFlags struct {\n\ttrackableActionCmdFlags\n\n\tmode string\n}\n\n// rebootCmd represents the reboot command.\nvar rebootCmd = &cobra.Command{\n\tUse:   \"reboot\",\n\tShort: \"Reboot a node\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif rebootCmdFlags.debug {\n\t\t\trebootCmdFlags.wait = true\n\t\t}\n\n\t\tvar opts []client.RebootMode\n\n\t\tswitch rebootCmdFlags.mode {\n\t\t// skips kexec and reboots with power cycle\n\t\tcase \"powercycle\":\n\t\t\topts = append(opts, client.WithPowerCycle)\n\t\tcase \"force\":\n\t\t\topts = append(opts, client.WithForce)\n\t\tcase \"default\":\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid reboot mode: %q\", rebootCmdFlags.mode)\n\t\t}\n\n\t\treturn rebootInternal(rebootCmdFlags.debug, rebootCmdFlags.debug, rebootCmdFlags.timeout, nil, opts...)\n\t},\n}\n\nfunc rebootInternal(wait, debug bool, timeout time.Duration, rep *reporter.Reporter, opts ...client.RebootMode) error {\n\tif !wait {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := c.Reboot(ctx, opts...); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error executing reboot: %s\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn action.NewTracker(\n\t\t&GlobalArgs,\n\t\taction.MachineReadyEventFn,\n\t\trebootGetActorID(opts...),\n\t\taction.WithPostCheck(action.BootIDChangedPostCheckFn),\n\t\taction.WithDebug(debug),\n\t\taction.WithTimeout(timeout),\n\t\taction.WithReporter(rep),\n\t).Run()\n}\n\nfunc rebootGetActorID(opts ...client.RebootMode) func(ctx context.Context, c *client.Client) (string, error) {\n\treturn func(ctx context.Context, c *client.Client) (string, error) {\n\t\tresp, err := c.RebootWithResponse(ctx, opts...)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif len(resp.GetMessages()) == 0 {\n\t\t\treturn \"\", errors.New(\"no messages returned from action run\")\n\t\t}\n\n\t\treturn resp.GetMessages()[0].GetActorId(), nil\n\t}\n}\n\nfunc init() {\n\trebootCmd.Flags().StringVarP(&rebootCmdFlags.mode, \"mode\", \"m\", \"default\", \"select the reboot mode: \\\"default\\\", \\\"powercycle\\\" (skips kexec), \\\"force\\\" (skips graceful teardown)\")\n\trebootCmdFlags.addTrackActionFlags(rebootCmd)\n\taddCommand(rebootCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/reset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/action\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar wipeOptions = map[string]machineapi.ResetRequest_WipeMode{\n\twipeModeAll:        machineapi.ResetRequest_ALL,\n\twipeModeSystemDisk: machineapi.ResetRequest_SYSTEM_DISK,\n\twipeModeUserDisks:  machineapi.ResetRequest_USER_DISKS,\n}\n\n// WipeMode apply, patch, edit config update mode.\ntype WipeMode machineapi.ResetRequest_WipeMode\n\nconst (\n\twipeModeAll        = \"all\"\n\twipeModeSystemDisk = \"system-disk\"\n\twipeModeUserDisks  = \"user-disks\"\n)\n\nfunc (m WipeMode) String() string {\n\tswitch machineapi.ResetRequest_WipeMode(m) {\n\tcase machineapi.ResetRequest_ALL:\n\t\treturn wipeModeAll\n\tcase machineapi.ResetRequest_SYSTEM_DISK:\n\t\treturn wipeModeSystemDisk\n\tcase machineapi.ResetRequest_USER_DISKS:\n\t\treturn wipeModeUserDisks\n\t}\n\n\treturn wipeModeAll\n}\n\n// Set implements Flag interface.\nfunc (m *WipeMode) Set(value string) error {\n\tmode, ok := wipeOptions[value]\n\tif !ok {\n\t\treturn fmt.Errorf(\"possible options are: %s\", m.Type())\n\t}\n\n\t*m = WipeMode(mode)\n\n\treturn nil\n}\n\n// Type implements Flag interface.\nfunc (m *WipeMode) Type() string {\n\toptions := maps.Keys(wipeOptions)\n\tslices.Sort(options)\n\n\treturn strings.Join(options, \", \")\n}\n\nvar resetCmdFlags struct {\n\ttrackableActionCmdFlags\n\n\tgraceful           bool\n\treboot             bool\n\tinsecure           bool\n\twipeMode           WipeMode\n\tuserDisksToWipe    []string\n\tsystemLabelsToWipe []string\n}\n\n// resetCmd represents the reset command.\nvar resetCmd = &cobra.Command{\n\tUse:   \"reset\",\n\tShort: \"Reset a node\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif resetCmdFlags.debug {\n\t\t\tresetCmdFlags.wait = true\n\t\t}\n\n\t\tresetRequest := buildResetRequest()\n\n\t\tif resetCmdFlags.wait && resetCmdFlags.insecure {\n\t\t\treturn errors.New(\"cannot use --wait and --insecure together\")\n\t\t}\n\n\t\tif !resetCmdFlags.wait {\n\t\t\tresetNoWait := func(ctx context.Context, c *client.Client) error {\n\t\t\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif err := c.ResetGeneric(ctx, resetRequest); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error executing reset: %s\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif resetCmdFlags.insecure {\n\t\t\t\treturn WithClientMaintenance(nil, resetNoWait)\n\t\t\t}\n\n\t\t\treturn WithClient(resetNoWait)\n\t\t}\n\n\t\tactionFn := func(ctx context.Context, c *client.Client) (string, error) {\n\t\t\treturn resetGetActorID(ctx, c, resetRequest)\n\t\t}\n\n\t\tvar postCheckFn func(context.Context, *client.Client, string) error\n\n\t\tif resetCmdFlags.reboot {\n\t\t\tpostCheckFn = func(ctx context.Context, c *client.Client, preActionBootID string) error {\n\t\t\t\terr := WithClientMaintenance(nil,\n\t\t\t\t\tfunc(ctx context.Context, cli *client.Client) error {\n\t\t\t\t\t\t_, err := cli.Disks(ctx)\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t})\n\n\t\t\t\t// if we can get into maintenance mode, reset has succeeded\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// try to get the boot ID in the normal mode to see if the node has rebooted\n\t\t\t\treturn action.BootIDChangedPostCheckFn(ctx, c, preActionBootID)\n\t\t\t}\n\t\t}\n\n\t\treturn action.NewTracker(\n\t\t\t&GlobalArgs,\n\t\t\taction.StopAllServicesEventFn,\n\t\t\tactionFn,\n\t\t\taction.WithPostCheck(postCheckFn),\n\t\t\taction.WithDebug(resetCmdFlags.debug),\n\t\t\taction.WithTimeout(resetCmdFlags.timeout),\n\t\t).Run()\n\t},\n}\n\nfunc buildResetRequest() *machineapi.ResetRequest {\n\tsystemPartitionsToWipe := make([]*machineapi.ResetPartitionSpec, 0, len(resetCmdFlags.systemLabelsToWipe))\n\n\tfor _, label := range resetCmdFlags.systemLabelsToWipe {\n\t\tsystemPartitionsToWipe = append(systemPartitionsToWipe, &machineapi.ResetPartitionSpec{\n\t\t\tLabel: label,\n\t\t\tWipe:  true,\n\t\t})\n\t}\n\n\treturn &machineapi.ResetRequest{\n\t\tGraceful:               resetCmdFlags.graceful,\n\t\tReboot:                 resetCmdFlags.reboot,\n\t\tUserDisksToWipe:        resetCmdFlags.userDisksToWipe,\n\t\tMode:                   machineapi.ResetRequest_WipeMode(resetCmdFlags.wipeMode),\n\t\tSystemPartitionsToWipe: systemPartitionsToWipe,\n\t}\n}\n\nfunc resetGetActorID(ctx context.Context, c *client.Client, req *machineapi.ResetRequest) (string, error) {\n\tresp, err := c.ResetGenericWithResponse(ctx, req)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif len(resp.GetMessages()) == 0 {\n\t\treturn \"\", errors.New(\"no messages returned from action run\")\n\t}\n\n\treturn resp.GetMessages()[0].GetActorId(), nil\n}\n\nfunc init() {\n\tresetCmd.Flags().BoolVar(&resetCmdFlags.graceful, \"graceful\", true, \"if true, attempt to cordon/drain node and leave etcd (if applicable)\")\n\tresetCmd.Flags().BoolVar(&resetCmdFlags.reboot, \"reboot\", false, \"if true, reboot the node after resetting instead of shutting down\")\n\tresetCmd.Flags().BoolVar(&resetCmdFlags.insecure, \"insecure\", false, \"reset using the insecure (encrypted with no auth) maintenance service\")\n\tresetCmd.Flags().Var(&resetCmdFlags.wipeMode, \"wipe-mode\", \"disk reset mode\")\n\tresetCmd.Flags().StringSliceVar(&resetCmdFlags.userDisksToWipe, \"user-disks-to-wipe\", nil, \"if set, wipes defined devices in the list\")\n\tresetCmd.Flags().StringSliceVar(&resetCmdFlags.systemLabelsToWipe, \"system-labels-to-wipe\", nil, \"if set, just wipe selected system disk partitions by label but keep other partitions intact\")\n\tresetCmdFlags.addTrackActionFlags(resetCmd)\n\taddCommand(resetCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/restart.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// restartCmd represents the restart command.\nvar restartCmd = &cobra.Command{\n\tUse:   \"restart <id>\",\n\tShort: \"Restart a process\",\n\tLong:  ``,\n\tArgs:  cobra.ExactArgs(1),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tif len(args) != 0 {\n\t\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn getContainersFromNode(kubernetesFlag), cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tnamespace string\n\t\t\t\tdriver    common.ContainerDriver\n\t\t\t)\n\n\t\t\tif kubernetesFlag {\n\t\t\t\tnamespace = constants.K8sContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CRI\n\t\t\t} else {\n\t\t\t\tnamespace = constants.SystemContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CONTAINERD\n\t\t\t}\n\n\t\t\tif err := c.Restart(ctx, namespace, driver, args[0]); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error restarting process: %s\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\trestartCmd.Flags().BoolVarP(&kubernetesFlag, \"kubernetes\", \"k\", false, \"use the k8s.io containerd namespace\")\n\n\trestartCmd.Flags().Bool(\"use-cri\", false, \"use the CRI driver\")\n\trestartCmd.Flags().MarkHidden(\"use-cri\") //nolint:errcheck\n\n\taddCommand(restartCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/rollback.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// rollbackCmd represents the rollback command.\nvar rollbackCmd = &cobra.Command{\n\tUse:   \"rollback\",\n\tShort: \"Rollback a node to the previous installation\",\n\tLong:  ``,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tif err := c.Rollback(ctx); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error executing rollback: %s\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(rollbackCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t_ \"github.com/siderolabs/proto-codec/codec\" // register codec v2\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/global\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/formatters\"\n)\n\nvar kubernetesFlag bool\n\n// GlobalArgs is the common arguments for the root command.\nvar GlobalArgs global.Args\n\nconst pathAutoCompleteLimit = 500\n\n// WithClientNoNodes wraps common code to initialize Talos client and provide cancellable context.\n//\n// WithClientNoNodes doesn't set any node information on the request context.\nfunc WithClientNoNodes(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error {\n\treturn GlobalArgs.WithClientNoNodes(action, dialOptions...)\n}\n\n// WithClient builds upon WithClientNoNodes to provide set of nodes on request context based on config & flags.\nfunc WithClient(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error {\n\treturn GlobalArgs.WithClient(action, dialOptions...)\n}\n\n// WithClientAndNodes builds upon WithClientNoNodes to pass a list of nodes via command function.\nfunc WithClientAndNodes(action func(context.Context, *client.Client, []string) error, dialOptions ...grpc.DialOption) error {\n\treturn GlobalArgs.WithClientAndNodes(action, dialOptions...)\n}\n\n// WithClientMaintenance wraps common code to initialize Talos client in maintenance (insecure mode).\nfunc WithClientMaintenance(enforceFingerprints []string, action func(context.Context, *client.Client) error) error {\n\treturn GlobalArgs.WithClientMaintenance(enforceFingerprints, action)\n}\n\n// Commands is a list of commands published by the package.\nvar Commands []*cobra.Command\n\nfunc addCommand(cmd *cobra.Command) {\n\tcmd.PersistentFlags().StringVar(\n\t\t&GlobalArgs.Talosconfig,\n\t\t\"talosconfig\",\n\t\t\"\",\n\t\tfmt.Sprintf(\"The path to the Talos configuration file. Defaults to '%s' env variable if set, otherwise '%s' and '%s' in order.\",\n\t\t\tconstants.TalosConfigEnvVar,\n\t\t\tfilepath.Join(\"$HOME\", constants.TalosDir, constants.TalosconfigFilename),\n\t\t\tfilepath.Join(constants.ServiceAccountMountPath, constants.TalosconfigFilename),\n\t\t),\n\t)\n\tcmd.PersistentFlags().StringSliceVarP(&GlobalArgs.Nodes, \"nodes\", \"n\", []string{}, \"target the specified nodes\")\n\tcmd.PersistentFlags().StringSliceVarP(&GlobalArgs.Endpoints, \"endpoints\", \"e\", []string{}, \"override default endpoints in Talos configuration\")\n\tcli.Should(cmd.RegisterFlagCompletionFunc(\"nodes\", CompleteNodes))\n\tcmd.PersistentFlags().StringVarP(&GlobalArgs.Cluster, \"cluster\", \"c\", \"\", \"Cluster to connect to if a proxy endpoint is used.\")\n\tcmd.PersistentFlags().StringVar(&GlobalArgs.CmdContext, \"context\", \"\", \"Context to be used in command\")\n\tcmd.PersistentFlags().StringVar(\n\t\t&GlobalArgs.SideroV1KeysDir,\n\t\t\"siderov1-keys-dir\",\n\t\t\"\",\n\t\tfmt.Sprintf(\"The path to the SideroV1 auth PGP keys directory. Defaults to '%s' env variable if set, otherwise '%s'. Only valid for Contexts that use SideroV1 auth.\",\n\t\t\tconstants.SideroV1KeysDirEnvVar,\n\t\t\tfilepath.Join(\"$HOME\", constants.TalosDir, constants.SideroV1KeysDir),\n\t\t),\n\t)\n\tcli.Should(cmd.RegisterFlagCompletionFunc(\"context\", CompleteConfigContext))\n\n\tCommands = append(Commands, cmd)\n}\n\n// completePathFromNode represents tab complete options for `ls` and `ls *` commands.\nfunc completePathFromNode(inputPath string) []string {\n\tpathToSearch := inputPath\n\n\t// If the pathToSearch is empty, use root '/'\n\tif pathToSearch == \"\" {\n\t\tpathToSearch = \"/\"\n\t}\n\n\tvar paths map[string]struct{}\n\n\t// search up one level to find possible completions\n\tif pathToSearch != \"/\" && !strings.HasSuffix(pathToSearch, \"/\") {\n\t\tindex := strings.LastIndex(pathToSearch, \"/\")\n\t\t// we need a trailing slash to search for items in a directory\n\t\tpathToSearch = pathToSearch[:index] + \"/\"\n\t}\n\n\tpaths = getPathFromNode(pathToSearch, inputPath)\n\n\treturn maps.Keys(paths)\n}\n\n//nolint:gocyclo\nfunc getPathFromNode(path, filter string) map[string]struct{} {\n\tpaths := make(map[string]struct{})\n\n\t//nolint:errcheck\n\tGlobalArgs.WithClient(\n\t\tfunc(ctx context.Context, c *client.Client) error {\n\t\t\tctx, cancel := context.WithCancel(ctx)\n\t\t\tdefer cancel()\n\n\t\t\tstream, err := c.LS(\n\t\t\t\tctx, &machineapi.ListRequest{\n\t\t\t\t\tRoot: path,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tresp, err := stream.Recv()\n\t\t\t\tif err != nil {\n\t\t\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fmt.Errorf(\"error streaming results: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tif resp.Metadata != nil && resp.Metadata.Error != \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif resp.Error != \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// skip reference to the same directory\n\t\t\t\tif resp.RelativeName == \".\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// limit the results to a reasonable amount\n\t\t\t\tif len(paths) > pathAutoCompleteLimit {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// directories have a trailing slash\n\t\t\t\tif resp.IsDir {\n\t\t\t\t\tfullPath := path + resp.RelativeName + \"/\"\n\n\t\t\t\t\tif relativeTo(fullPath, filter) {\n\t\t\t\t\t\tpaths[fullPath] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfullPath := path + resp.RelativeName\n\n\t\t\t\t\tif relativeTo(fullPath, filter) {\n\t\t\t\t\t\tpaths[fullPath] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t)\n\n\treturn paths\n}\n\nfunc getServiceFromNode() []string {\n\tvar svcIDs []string\n\n\t//nolint:errcheck\n\tGlobalArgs.WithClient(\n\t\tfunc(ctx context.Context, c *client.Client) error {\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.ServiceList(ctx, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, msg := range resp.Messages {\n\t\t\t\tfor _, s := range msg.Services {\n\t\t\t\t\tsvc := formatters.ServiceInfoWrapper{ServiceInfo: s}\n\t\t\t\t\tsvcIDs = append(svcIDs, svc.Id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\treturn svcIDs\n}\n\nfunc getContainersFromNode(kubernetes bool) []string {\n\tvar containerIDs []string\n\n\t//nolint:errcheck\n\tGlobalArgs.WithClient(\n\t\tfunc(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tnamespace string\n\t\t\t\tdriver    common.ContainerDriver\n\t\t\t)\n\n\t\t\tif kubernetes {\n\t\t\t\tnamespace = constants.K8sContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CRI\n\t\t\t} else {\n\t\t\t\tnamespace = constants.SystemContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CONTAINERD\n\t\t\t}\n\n\t\t\tresp, err := c.Containers(ctx, namespace, driver)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, msg := range resp.Messages {\n\t\t\t\tfor _, p := range msg.Containers {\n\t\t\t\t\tif p.Pid == 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif kubernetes && p.Id == p.PodId {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tcontainerIDs = append(containerIDs, p.Id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\treturn containerIDs\n}\n\nfunc mergeSuggestions(s ...[]string) []string {\n\tmerged := slices.Concat(s...)\n\n\tslices.Sort(merged)\n\n\treturn slices.Compact(merged)\n}\n\nfunc relativeTo(fullPath string, filter string) bool {\n\treturn strings.HasPrefix(fullPath, filter)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/rotate-ca.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/talos\"\n)\n\nvar rotateCACmdFlags struct {\n\tclusterState     clusterNodes\n\tforceEndpoint    string\n\toutput           string\n\twithExamples     bool\n\twithDocs         bool\n\tdryRun           bool\n\trotateTalos      bool\n\trotateKubernetes bool\n}\n\n// rotateCACmd represents the rotate-ca command.\nvar rotateCACmd = &cobra.Command{\n\tUse:   \"rotate-ca\",\n\tShort: \"Rotate cluster CAs (Talos and Kubernetes APIs).\",\n\tLong: `The command can rotate both Talos and Kubernetes root CAs (for the API).\nBy default both CAs are rotated, but you can choose to rotate just one or another.\nThe command starts by generating new CAs, and gracefully applying it to the cluster.\n\nFor Kubernetes, the command only rotates the API server issuing CA, and other Kubernetes\nPKI can be rotated by applying machine config changes to the controlplane nodes.`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\terr := rotateCACmdFlags.clusterState.InitNodeInfos()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn WithClient(rotateCA)\n\t},\n}\n\nfunc rotateCA(ctx context.Context, c *client.Client) error {\n\tcommentsFlags := encoder.CommentsDisabled\n\tif rotateCACmdFlags.withDocs {\n\t\tcommentsFlags |= encoder.CommentsDocs\n\t}\n\n\tif rotateCACmdFlags.withExamples {\n\t\tcommentsFlags |= encoder.CommentsExamples\n\t}\n\n\tencoderOpt := encoder.WithComments(commentsFlags)\n\n\tclusterInfo, err := buildClusterInfo(rotateCACmdFlags.clusterState)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewBundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating new Talos CA: %w\", err)\n\t}\n\n\tif rotateCACmdFlags.rotateTalos {\n\t\tvar newTalosconfig *clientconfig.Config\n\n\t\tnewTalosconfig, err = rotateTalosCA(ctx, c, encoderOpt, clusterInfo, newBundle)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error rotating Talos CA: %w\", err)\n\t\t}\n\n\t\t// re-create client with new Talos PKI\n\t\tc, err = client.New(ctx, client.WithConfig(newTalosconfig))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create new client with rotated Talos CA: %w\", err)\n\t\t}\n\t}\n\n\tif rotateCACmdFlags.rotateKubernetes {\n\t\tif err = rotateKubernetesCA(ctx, c, encoderOpt, clusterInfo, newBundle); err != nil {\n\t\t\treturn fmt.Errorf(\"error rotating Kubernetes CA: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc rotateTalosCA(ctx context.Context, oldClient *client.Client, encoderOpt encoder.Option, clusterInfo cluster.Info, newBundle *secrets.Bundle) (*clientconfig.Config, error) {\n\toldTalosconfig, err := clientconfig.Open(GlobalArgs.Talosconfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open config file %q: %w\", GlobalArgs.Talosconfig, err)\n\t}\n\n\tconfigContext := oldTalosconfig.Context\n\n\tif GlobalArgs.CmdContext != \"\" {\n\t\tconfigContext = GlobalArgs.CmdContext\n\t}\n\n\toptions := talos.Options{\n\t\tDryRun: rotateCACmdFlags.dryRun,\n\n\t\tCurrentClient: oldClient,\n\t\tClusterInfo:   clusterInfo,\n\n\t\tContextName: configContext,\n\t\tEndpoints:   oldClient.GetEndpoints(),\n\n\t\tNewTalosCA: newBundle.Certs.OS,\n\n\t\tEncoderOption: encoderOpt,\n\n\t\tPrintf: func(format string, args ...any) { fmt.Printf(format, args...) },\n\t}\n\n\tnewTalosconfig, err := talos.Rotate(ctx, options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif rotateCACmdFlags.dryRun {\n\t\tfmt.Println(\"> Dry-run mode enabled, no changes were made to the cluster, re-run with `--dry-run=false` to apply the changes.\")\n\n\t\treturn nil, nil\n\t}\n\n\tfmt.Printf(\"> Writing new talosconfig to %q\\n\", rotateCACmdFlags.output)\n\n\treturn newTalosconfig, newTalosconfig.Save(rotateCACmdFlags.output)\n}\n\nfunc rotateKubernetesCA(ctx context.Context, c *client.Client, encoderOpt encoder.Option, clusterInfo cluster.Info, newBundle *secrets.Bundle) error {\n\toptions := kubernetes.Options{\n\t\tDryRun: rotateCACmdFlags.dryRun,\n\n\t\tTalosClient: c,\n\t\tClusterInfo: clusterInfo,\n\n\t\tKubernetesEndpoint: rotateCACmdFlags.forceEndpoint,\n\n\t\tNewKubernetesCA: newBundle.Certs.K8s,\n\n\t\tEncoderOption: encoderOpt,\n\n\t\tPrintf: func(format string, args ...any) { fmt.Printf(format, args...) },\n\t}\n\n\tif err := kubernetes.Rotate(ctx, options); err != nil {\n\t\treturn err\n\t}\n\n\tif rotateCACmdFlags.dryRun {\n\t\tfmt.Println(\"> Dry-run mode enabled, no changes were made to the cluster, re-run with `--dry-run=false` to apply the changes.\")\n\n\t\treturn nil\n\t}\n\n\tfmt.Printf(\"> Kubernetes CA rotation done, new 'kubeconfig' can be fetched with `talosctl kubeconfig`.\\n\")\n\n\treturn nil\n}\n\nfunc init() {\n\taddCommand(rotateCACmd)\n\trotateCACmd.Flags().StringVar(&rotateCACmdFlags.clusterState.InitNode, \"init-node\", \"\", \"specify IPs of init node\")\n\trotateCACmd.Flags().StringSliceVar(&rotateCACmdFlags.clusterState.ControlPlaneNodes, \"control-plane-nodes\", nil, \"specify IPs of control plane nodes\")\n\trotateCACmd.Flags().StringSliceVar(&rotateCACmdFlags.clusterState.WorkerNodes, \"worker-nodes\", nil, \"specify IPs of worker nodes\")\n\trotateCACmd.Flags().StringVar(&rotateCACmdFlags.forceEndpoint, \"k8s-endpoint\", \"\", \"use endpoint instead of kubeconfig default\")\n\trotateCACmd.Flags().BoolVarP(&rotateCACmdFlags.withExamples, \"with-examples\", \"\", true, \"patch all machine configs with the commented examples\")\n\trotateCACmd.Flags().BoolVarP(&rotateCACmdFlags.withDocs, \"with-docs\", \"\", true, \"patch all machine configs adding the documentation for each field\")\n\trotateCACmd.Flags().StringVarP(&rotateCACmdFlags.output, \"output\", \"o\", \"talosconfig\", \"path to the output new `talosconfig`\")\n\trotateCACmd.Flags().BoolVarP(&rotateCACmdFlags.dryRun, \"dry-run\", \"\", true, \"dry-run mode (no changes to the cluster)\")\n\trotateCACmd.Flags().BoolVarP(&rotateCACmdFlags.rotateTalos, \"talos\", \"\", true, \"rotate Talos API CA\")\n\trotateCACmd.Flags().BoolVarP(&rotateCACmdFlags.rotateKubernetes, \"kubernetes\", \"\", true, \"rotate Kubernetes API CA\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/routes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// routesCmd represents the net routes command.\nvar routesCmd = &cobra.Command{\n\tUse:     \"routes\",\n\tAliases: []string{\"route\"},\n\tShort:   \"List network routes\",\n\tLong:    ``,\n\tArgs:    cobra.NoArgs,\n\tHidden:  true,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\treturn errors.New(\"`talosctl routes` is deprecated, please use `talosctl get routes` instead\")\n\t\t})\n\t},\n}\n\nfunc init() {\n\taddCommand(routesCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"text/tabwriter\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/formatters\"\n)\n\n// serviceCmd represents the service command.\nvar serviceCmd = &cobra.Command{\n\tUse:     \"service [<id> [start|stop|restart|status]]\",\n\tAliases: []string{\"services\"},\n\tShort:   \"Retrieve the state of a service (or all services), control service state\",\n\tLong: `Service control command. If run without arguments, lists all the services and their state.\nIf service ID is specified, default action 'status' is executed which shows status of a single list service.\nWith actions 'start', 'stop', 'restart', service state is updated respectively.`,\n\tArgs: cobra.MaximumNArgs(2),\n\tValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {\n\t\tswitch len(args) {\n\t\tcase 0:\n\t\t\treturn getServiceFromNode(), cobra.ShellCompDirectiveNoFileComp\n\t\tcase 1:\n\t\t\treturn []string{\"start\", \"stop\", \"restart\", \"status\"}, cobra.ShellCompDirectiveNoFileComp\n\t\t}\n\n\t\treturn nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp\n\t},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\taction := \"status\"\n\t\tserviceID := \"\"\n\n\t\tif len(args) >= 1 {\n\t\t\tserviceID = args[0]\n\t\t}\n\n\t\tif len(args) == 2 {\n\t\t\taction = args[1]\n\t\t}\n\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tswitch action {\n\t\t\tcase \"status\":\n\t\t\t\tif serviceID == \"\" {\n\t\t\t\t\treturn serviceList(ctx, c)\n\t\t\t\t}\n\n\t\t\t\treturn serviceInfo(ctx, c, serviceID)\n\t\t\tcase \"start\":\n\t\t\t\treturn serviceStart(ctx, c, serviceID)\n\t\t\tcase \"stop\":\n\t\t\t\treturn serviceStop(ctx, c, serviceID)\n\t\t\tcase \"restart\":\n\t\t\t\treturn serviceRestart(ctx, c, serviceID)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unsupported service action: %q\", action)\n\t\t\t}\n\t\t})\n\t},\n}\n\nfunc serviceList(ctx context.Context, c *client.Client) error {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.ServiceList(ctx, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error listing services: %w\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tSERVICE\\tSTATE\\tHEALTH\\tLAST CHANGE\\tLAST EVENT\")\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tfor _, s := range msg.Services {\n\t\t\tsvc := formatters.ServiceInfoWrapper{ServiceInfo: s}\n\n\t\t\tnode := defaultNode\n\n\t\t\tif msg.Metadata != nil {\n\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\t%s ago\\t%s\\n\", node, svc.Id, svc.State, svc.HealthStatus(), svc.LastUpdated(), svc.LastEvent())\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\nfunc serviceInfo(ctx context.Context, c *client.Client, id string) error {\n\tvar remotePeer peer.Peer\n\n\tservices, err := c.ServiceInfo(ctx, id, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif services == nil {\n\t\t\treturn fmt.Errorf(\"error listing services: %w\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tif len(services) == 0 {\n\t\treturn fmt.Errorf(\"service %q is not registered on any nodes\", id)\n\t}\n\n\treturn formatters.RenderServicesInfo(services, os.Stdout, defaultNode, true)\n}\n\nfunc serviceStart(ctx context.Context, c *client.Client, id string) error {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.ServiceStart(ctx, id, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error starting service: %w\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tRESPONSE\")\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tfmt.Fprintf(w, \"%s\\t%s\\n\", node, msg.Resp)\n\t}\n\n\treturn w.Flush()\n}\n\nfunc serviceStop(ctx context.Context, c *client.Client, id string) error {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.ServiceStop(ctx, id, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error starting service: %w\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tRESPONSE\")\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tfmt.Fprintf(w, \"%s\\t%s\\n\", node, msg.Resp)\n\t}\n\n\treturn w.Flush()\n}\n\nfunc serviceRestart(ctx context.Context, c *client.Client, id string) error {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.ServiceRestart(ctx, id, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error starting service: %w\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tRESPONSE\")\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tfmt.Fprintf(w, \"%s\\t%s\\n\", node, msg.Resp)\n\t}\n\n\treturn w.Flush()\n}\n\nfunc init() {\n\taddCommand(serviceCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/shutdown.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/action\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar shutdownCmdFlags struct {\n\ttrackableActionCmdFlags\n\n\tforce bool\n}\n\n// shutdownCmd represents the shutdown command.\nvar shutdownCmd = &cobra.Command{\n\tUse:   \"shutdown\",\n\tShort: \"Shutdown a node\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif shutdownCmdFlags.debug {\n\t\t\tshutdownCmdFlags.wait = true\n\t\t}\n\n\t\topts := []client.ShutdownOption{\n\t\t\tclient.WithShutdownForce(shutdownCmdFlags.force),\n\t\t}\n\n\t\tif !shutdownCmdFlags.wait {\n\t\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif err := c.Shutdown(ctx, opts...); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error executing shutdown: %s\", err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\n\t\treturn action.NewTracker(\n\t\t\t&GlobalArgs,\n\t\t\taction.StopAllServicesEventFn,\n\t\t\tshutdownGetActorID,\n\t\t\taction.WithDebug(shutdownCmdFlags.debug),\n\t\t\taction.WithTimeout(shutdownCmdFlags.timeout),\n\t\t).Run()\n\t},\n}\n\nfunc shutdownGetActorID(ctx context.Context, c *client.Client) (string, error) {\n\tresp, err := c.ShutdownWithResponse(ctx, client.WithShutdownForce(shutdownCmdFlags.force))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif len(resp.GetMessages()) == 0 {\n\t\treturn \"\", errors.New(\"no messages returned from action run\")\n\t}\n\n\treturn resp.GetMessages()[0].GetActorId(), nil\n}\n\nfunc init() {\n\tshutdownCmd.Flags().BoolVar(&shutdownCmdFlags.force, \"force\", false, \"if true, force a node to shutdown without a cordon/drain\")\n\tshutdownCmdFlags.addTrackActionFlags(shutdownCmd)\n\taddCommand(shutdownCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/stats.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// statsCmd represents the stats command.\nvar statsCmd = &cobra.Command{\n\tUse:   \"stats\",\n\tShort: \"Get container stats\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tnamespace string\n\t\t\t\tdriver    common.ContainerDriver\n\t\t\t)\n\n\t\t\tif kubernetesFlag {\n\t\t\t\tnamespace = constants.K8sContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CRI\n\t\t\t} else {\n\t\t\t\tnamespace = constants.SystemContainerdNamespace\n\t\t\t\tdriver = common.ContainerDriver_CONTAINERD\n\t\t\t}\n\n\t\t\tvar remotePeer peer.Peer\n\n\t\t\tresp, err := c.Stats(ctx, namespace, driver, grpc.Peer(&remotePeer))\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting stats: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\treturn statsRender(&remotePeer, resp)\n\t\t})\n\t},\n}\n\nfunc statsRender(remotePeer *peer.Peer, resp *machineapi.StatsResponse) error {\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\n\tfmt.Fprintln(w, \"NODE\\tNAMESPACE\\tID\\tMEMORY(MB)\\tCPU\")\n\n\tdefaultNode := client.AddrFromPeer(remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tslices.SortFunc(msg.Stats, func(a, b *machineapi.Stat) int { return strings.Compare(a.Id, b.Id) })\n\n\t\tfor _, s := range msg.Stats {\n\t\t\tdisplay := s.Id\n\t\t\tif s.Id != s.PodId {\n\t\t\t\t// container in a sandbox\n\t\t\t\tdisplay = \"└─ \" + display\n\t\t\t}\n\n\t\t\tnode := defaultNode\n\n\t\t\tif msg.Metadata != nil {\n\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%.2f\\t%d\\n\", node, s.Namespace, display, float64(s.MemoryUsage)*1e-6, s.CpuUsage)\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\nfunc init() {\n\tstatsCmd.Flags().BoolVarP(&kubernetesFlag, \"kubernetes\", \"k\", false, \"use the k8s.io containerd namespace\")\n\n\tstatsCmd.Flags().Bool(\"use-cri\", false, \"use the CRI driver\")\n\tstatsCmd.Flags().MarkHidden(\"use-cri\") //nolint:errcheck\n\n\taddCommand(statsCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/support.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"text/tabwriter\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/fatih/color\"\n\t\"github.com/gosuri/uiprogress\"\n\t\"github.com/siderolabs/go-talos-support/support\"\n\t\"github.com/siderolabs/go-talos-support/support/bundle\"\n\t\"github.com/siderolabs/go-talos-support/support/collectors\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/sync/errgroup\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\tk8s \"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclusterresource \"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nvar supportCmdFlags struct {\n\toutput     string\n\tnumWorkers int\n\tverbose    bool\n}\n\n// supportCmd represents the support command.\nvar supportCmd = &cobra.Command{\n\tUse:   \"support\",\n\tShort: \"Dump debug information about the cluster\",\n\tLong: `Generated bundle contains the following debug information:\n\n- For each node:\n\n\t- Kernel logs.\n\t- All Talos internal services logs.\n\t- All kube-system pods logs.\n\t- Talos COSI resources without secrets.\n\t- COSI runtime state graph.\n\t- Processes snapshot.\n\t- IO pressure snapshot.\n\t- Mounts list.\n\t- PCI devices info.\n\t- Talos version.\n\n- For the cluster:\n\n\t- Kubernetes nodes and kube-system pods manifests.\n`,\n\tArgs: cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif len(GlobalArgs.Nodes) == 0 {\n\t\t\treturn errors.New(\"please provide at least a single node to gather the debug information from\")\n\t\t}\n\n\t\tf, err := openArchive()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tprogress := make(chan bundle.Progress)\n\n\t\tvar (\n\t\t\teg     errgroup.Group\n\t\t\terrors supportBundleErrors\n\t\t)\n\n\t\teg.Go(func() error {\n\t\t\tif supportCmdFlags.verbose {\n\t\t\t\tfor p := range progress {\n\t\t\t\t\terrors.handleProgress(p)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tshowProgress(progress, &errors)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\n\t\tcollectErr := collectData(f, progress)\n\n\t\tclose(progress)\n\n\t\tif e := eg.Wait(); e != nil {\n\t\t\treturn e\n\t\t}\n\n\t\tif err = errors.print(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"Support bundle is written to %s\\n\", supportCmdFlags.output)\n\n\t\treturn collectErr\n\t},\n}\n\nfunc collectData(dest *os.File, progress chan bundle.Progress) error {\n\treturn WithClientNoNodes(func(ctx context.Context, c *client.Client) error {\n\t\tclientset, err := getKubernetesClient(ctx, c)\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"Failed to create kubernetes client %s\\n\", err)\n\t\t}\n\n\t\topts := []bundle.Option{\n\t\t\tbundle.WithArchiveOutput(dest),\n\t\t\tbundle.WithKubernetesClient(clientset),\n\t\t\tbundle.WithTalosClient(c),\n\t\t\tbundle.WithNodes(GlobalArgs.Nodes...),\n\t\t\tbundle.WithNumWorkers(supportCmdFlags.numWorkers),\n\t\t\tbundle.WithProgressChan(progress),\n\t\t}\n\n\t\tif !supportCmdFlags.verbose {\n\t\t\topts = append(opts, bundle.WithLogOutput(io.Discard))\n\t\t}\n\n\t\toptions := bundle.NewOptions(opts...)\n\n\t\tcollectors, err := collectors.GetForOptions(ctx, options)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn support.CreateSupportBundle(ctx, options, collectors...)\n\t})\n}\n\nfunc getKubernetesClient(ctx context.Context, c *client.Client) (*k8s.Clientset, error) {\n\tkubeconfig, err := c.Kubeconfig(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trestconfig, err := config.ClientConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclientset, err := k8s.NewForConfig(restconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// just checking that k8s responds\n\t_, err = clientset.CoreV1().Namespaces().Get(ctx, \"kube-system\", v1.GetOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn clientset, nil\n}\n\nfunc getDiscoveryConfig() (*clusterresource.Config, error) {\n\tvar config *clusterresource.Config\n\n\tif e := WithClient(func(ctx context.Context, c *client.Client) error {\n\t\tvar err error\n\n\t\tconfig, err = safe.StateGet[*clusterresource.Config](\n\t\t\tctx,\n\t\t\tc.COSI,\n\t\t\tresource.NewMetadata(clusterresource.NamespaceName, clusterresource.IdentityType, clusterresource.LocalIdentity, resource.VersionUndefined),\n\t\t)\n\n\t\treturn err\n\t}); e != nil {\n\t\treturn nil, e\n\t}\n\n\treturn config, nil\n}\n\nfunc openArchive() (*os.File, error) {\n\tif supportCmdFlags.output == \"\" {\n\t\tsupportCmdFlags.output = \"support\"\n\n\t\tif config, err := getDiscoveryConfig(); err == nil && config.TypedSpec().DiscoveryEnabled {\n\t\t\tsupportCmdFlags.output += \"-\" + config.TypedSpec().ServiceClusterID\n\t\t}\n\n\t\tsupportCmdFlags.output += \".zip\"\n\t}\n\n\tif _, err := os.Stat(supportCmdFlags.output); err != nil {\n\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tbuf := bufio.NewReader(os.Stdin)\n\n\t\tfmt.Printf(\"%s already exists, overwrite? [y/N]: \", supportCmdFlags.output)\n\n\t\tchoice, err := buf.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif strings.TrimSpace(strings.ToLower(choice)) != \"y\" {\n\t\t\treturn nil, fmt.Errorf(\"operation aborted\")\n\t\t}\n\t}\n\n\treturn os.OpenFile(supportCmdFlags.output, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644)\n}\n\ntype supportBundleError struct {\n\tsource string\n\tvalue  string\n}\n\ntype supportBundleErrors struct {\n\terrors []supportBundleError\n}\n\nfunc (sbe *supportBundleErrors) handleProgress(p bundle.Progress) {\n\tif p.Error != nil {\n\t\tsbe.errors = append(sbe.errors, supportBundleError{\n\t\t\tsource: p.Source,\n\t\t\tvalue:  p.Error.Error(),\n\t\t})\n\t}\n}\n\nfunc (sbe *supportBundleErrors) print() error {\n\tif sbe.errors == nil {\n\t\treturn nil\n\t}\n\n\tvar wroteHeader bool\n\n\tw := tabwriter.NewWriter(os.Stderr, 0, 0, 3, ' ', 0)\n\n\tfor _, err := range sbe.errors {\n\t\tif !wroteHeader {\n\t\t\twroteHeader = true\n\n\t\t\tfmt.Fprintln(os.Stderr, \"Processed with errors:\")\n\t\t\tfmt.Fprintln(w, \"\\tSOURCE\\tERROR\")\n\t\t}\n\n\t\tdetails := strings.Split(err.value, \"\\n\")\n\t\tfor i, d := range details {\n\t\t\tdetails[i] = strings.TrimSpace(d)\n\t\t}\n\n\t\tfmt.Fprintf(w, \"\\t%s\\t%s\\n\", err.source, color.RedString(details[0]))\n\n\t\tif len(details) > 1 {\n\t\t\tfor _, line := range details[1:] {\n\t\t\t\tfmt.Fprintf(w, \"\\t\\t%s\\n\", color.RedString(line))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\nfunc showProgress(progress <-chan bundle.Progress, errors *supportBundleErrors) {\n\tuiprogress.Start()\n\n\ttype nodeProgress struct {\n\t\tmu    sync.Mutex\n\t\tstate string\n\t\tbar   *uiprogress.Bar\n\t}\n\n\tnodes := map[string]*nodeProgress{}\n\n\tfor p := range progress {\n\t\terrors.handleProgress(p)\n\n\t\tvar (\n\t\t\tnp *nodeProgress\n\t\t\tok bool\n\t\t)\n\n\t\tsrc := p.Source\n\n\t\tif _, ok = nodes[p.Source]; !ok {\n\t\t\tbar := uiprogress.AddBar(p.Total)\n\t\t\tbar = bar.AppendCompleted().PrependElapsed()\n\n\t\t\tnp = &nodeProgress{\n\t\t\t\tstate: \"initializing...\",\n\t\t\t\tbar:   bar,\n\t\t\t}\n\n\t\t\tbar.AppendFunc(\n\t\t\t\tfunc(src string, np *nodeProgress) func(b *uiprogress.Bar) string {\n\t\t\t\t\treturn func(b *uiprogress.Bar) string {\n\t\t\t\t\t\tnp.mu.Lock()\n\t\t\t\t\t\tdefer np.mu.Unlock()\n\n\t\t\t\t\t\treturn fmt.Sprintf(\"%s: %s\", src, np.state)\n\t\t\t\t\t}\n\t\t\t\t}(src, np),\n\t\t\t)\n\n\t\t\tbar.Width = 20\n\n\t\t\tnodes[src] = np\n\t\t} else {\n\t\t\tnp = nodes[src]\n\t\t}\n\n\t\tnp.mu.Lock()\n\t\tnp.state = p.State\n\t\tnp.mu.Unlock()\n\n\t\tnp.bar.Incr()\n\t}\n\n\tuiprogress.Stop()\n}\n\nfunc init() {\n\taddCommand(supportCmd)\n\tsupportCmd.Flags().StringVarP(&supportCmdFlags.output, \"output\", \"O\", \"\", \"output file to write support archive to\")\n\tsupportCmd.Flags().IntVarP(&supportCmdFlags.numWorkers, \"num-workers\", \"w\", 1, \"number of workers per node\")\n\tsupportCmd.Flags().BoolVarP(&supportCmdFlags.verbose, \"verbose\", \"v\", false, \"verbose output\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/time.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\ttimeapi \"github.com/siderolabs/talos/pkg/machinery/api/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nvar timeCmdFlags struct {\n\tntpServer string\n}\n\n// timeCmd represents the time command.\nvar timeCmd = &cobra.Command{\n\tUse:   \"time [--check server]\",\n\tShort: \"Gets current server time\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\t\tvar (\n\t\t\t\tresp       *timeapi.TimeResponse\n\t\t\t\tremotePeer peer.Peer\n\t\t\t\terr        error\n\t\t\t)\n\n\t\t\tif timeCmdFlags.ntpServer == \"\" {\n\t\t\t\tresp, err = c.Time(ctx, grpc.Peer(&remotePeer))\n\t\t\t} else {\n\t\t\t\tresp, err = c.TimeCheck(ctx, timeCmdFlags.ntpServer, grpc.Peer(&remotePeer))\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn fmt.Errorf(\"error fetching time: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcli.Warning(\"%s\", err)\n\t\t\t}\n\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\t\t\tfmt.Fprintln(w, \"NODE\\tNTP-SERVER\\tNODE-TIME\\tNTP-SERVER-TIME\")\n\n\t\t\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\t\t\tvar localtime, remotetime time.Time\n\n\t\t\tfor _, msg := range resp.Messages {\n\t\t\t\tnode := defaultNode\n\n\t\t\t\tif msg.Metadata != nil {\n\t\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t\t}\n\n\t\t\t\tif !msg.Localtime.IsValid() {\n\t\t\t\t\treturn errors.New(\"error parsing local time\")\n\t\t\t\t}\n\n\t\t\t\tif !msg.Remotetime.IsValid() {\n\t\t\t\t\treturn errors.New(\"error parsing remote time\")\n\t\t\t\t}\n\n\t\t\t\tlocaltime = msg.Localtime.AsTime()\n\t\t\t\tremotetime = msg.Remotetime.AsTime()\n\n\t\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\n\", node, msg.Server, localtime.String(), remotetime.String())\n\t\t\t}\n\n\t\t\treturn w.Flush()\n\t\t})\n\t},\n}\n\nfunc init() {\n\ttimeCmd.Flags().StringVar(&timeCmdFlags.ntpServer, \"check\", \"\", \"checks server time against specified ntp server\")\n\taddCommand(timeCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/track.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n)\n\ntype trackableActionCmdFlags struct {\n\twait    bool\n\tdebug   bool\n\ttimeout time.Duration\n}\n\nfunc (f *trackableActionCmdFlags) addTrackActionFlags(cmd *cobra.Command) {\n\tcmd.Flags().BoolVar(&f.wait, \"wait\", true, \"wait for the operation to complete, tracking its progress. always set to true when --debug is set\")\n\tcmd.Flags().BoolVar(&f.debug, \"debug\", false, \"debug operation from kernel logs. --wait is set to true when this flag is set\")\n\tcmd.Flags().DurationVar(&f.timeout, \"timeout\", 30*time.Minute, \"time to wait for the operation is complete if --debug or --wait is set\")\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/upgrade-k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/upgrade\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\tk8s \"github.com/siderolabs/talos/pkg/cluster/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// upgradeK8sCmd represents the upgrade-k8s command.\nvar upgradeK8sCmd = &cobra.Command{\n\tUse:   \"upgrade-k8s\",\n\tShort: \"Upgrade Kubernetes control plane in the Talos cluster.\",\n\tLong:  `Command runs upgrade of Kubernetes control plane components between specified versions.`,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn WithClient(upgradeKubernetes)\n\t},\n}\n\nvar upgradeOptions k8s.UpgradeOptions\n\nvar upgradeK8sCmdFlags struct {\n\tFromVersion string\n\tToVersion   string\n\n\twithExamples    bool\n\twithDocs        bool\n\tinventoryPolicy string\n}\n\nfunc init() {\n\tupgradeK8sCmd.Flags().StringVar(&upgradeK8sCmdFlags.FromVersion, \"from\", \"\", \"the Kubernetes control plane version to upgrade from\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeK8sCmdFlags.ToVersion, \"to\", constants.DefaultKubernetesVersion, \"the Kubernetes control plane version to upgrade to\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.ControlPlaneEndpoint, \"endpoint\", \"\", \"the cluster control plane endpoint\")\n\tupgradeK8sCmd.Flags().BoolVarP(&upgradeK8sCmdFlags.withExamples, \"with-examples\", \"\", true, \"patch all machine configs with the commented examples\")\n\tupgradeK8sCmd.Flags().BoolVarP(&upgradeK8sCmdFlags.withDocs, \"with-docs\", \"\", true, \"patch all machine configs adding the documentation for each field\")\n\tupgradeK8sCmd.Flags().BoolVar(&upgradeOptions.PrePullImages, \"pre-pull-images\", true, \"pre-pull images before upgrade\")\n\tupgradeK8sCmd.Flags().BoolVar(&upgradeOptions.UpgradeKubelet, \"upgrade-kubelet\", true, \"upgrade kubelet service\")\n\tupgradeK8sCmd.Flags().BoolVar(&upgradeOptions.DryRun, \"dry-run\", false, \"skip the actual upgrade and show the upgrade plan instead\")\n\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.KubeletImage, \"kubelet-image\", constants.KubeletImage, \"kubelet image to use\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.APIServerImage, \"apiserver-image\", constants.KubernetesAPIServerImage, \"kube-apiserver image to use\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.ControllerManagerImage, \"controller-manager-image\", constants.KubernetesControllerManagerImage, \"kube-controller-manager image to use\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.SchedulerImage, \"scheduler-image\", constants.KubernetesSchedulerImage, \"kube-scheduler image to use\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeOptions.ProxyImage, \"proxy-image\", constants.KubeProxyImage, \"kube-proxy image to use\")\n\n\t// manifest sync related options\n\tupgradeK8sCmd.Flags().BoolVar(&upgradeOptions.ForceManifests, \"manifests-force\", false, \"whether to recreate objects that contain immutable field changes\")\n\tupgradeK8sCmd.Flags().BoolVar(&upgradeOptions.NoPrune, \"manifests-no-prune\", false, \"whether pruning of previously applied objects should happen after apply\")\n\tupgradeK8sCmd.Flags().StringVar(&upgradeK8sCmdFlags.inventoryPolicy, \"manifests-inventory-policy\", \"AdoptIfNoInventory\",\n\t\t\"kubernetes SSA inventory policy (one of 'MustMatch', 'AdoptIfNoInventory' or 'AdoptAll')\")\n\tupgradeK8sCmd.Flags().DurationVar(&upgradeOptions.ReconcileTimeout, \"manifests-reconcile-timeout\", 5*time.Minute,\n\t\t\"how long to wait for resources to be fully reconciled (set to zero to disable waiting)\")\n\n\taddCommand(upgradeK8sCmd)\n}\n\nfunc upgradeKubernetes(ctx context.Context, c *client.Client) error {\n\tif err := helpers.FailIfMultiNodes(ctx, \"upgrade-k8s\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\treturn err\n\t}\n\n\tclientProvider := &cluster.ConfigClientProvider{\n\t\tDefaultClient: c,\n\t}\n\tdefer clientProvider.Close() //nolint:errcheck\n\n\tstate := struct {\n\t\tcluster.ClientProvider\n\t\tcluster.K8sProvider\n\t}{\n\t\tClientProvider: clientProvider,\n\t\tK8sProvider: &cluster.KubernetesClient{\n\t\t\tClientProvider: clientProvider,\n\t\t\tForceEndpoint:  upgradeOptions.ControlPlaneEndpoint,\n\t\t},\n\t}\n\n\tvar err error\n\n\tif upgradeK8sCmdFlags.FromVersion == \"\" {\n\t\tupgradeK8sCmdFlags.FromVersion, err = k8s.DetectLowestVersion(ctx, &state, upgradeOptions)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error detecting the lowest Kubernetes version %w\", err)\n\t\t}\n\n\t\tupgradeOptions.Log(\"automatically detected the lowest Kubernetes version %s\", upgradeK8sCmdFlags.FromVersion)\n\t}\n\n\tupgradeOptions.Path, err = upgrade.NewPath(upgradeK8sCmdFlags.FromVersion, upgradeK8sCmdFlags.ToVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating upgrade path %w\", err)\n\t}\n\n\tcommentsFlags := encoder.CommentsDisabled\n\tif upgradeK8sCmdFlags.withDocs {\n\t\tcommentsFlags |= encoder.CommentsDocs\n\t}\n\n\tif upgradeK8sCmdFlags.withExamples {\n\t\tcommentsFlags |= encoder.CommentsExamples\n\t}\n\n\tpolicy, err := ssa.ParseInventoryPolicy(upgradeK8sCmdFlags.inventoryPolicy)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tupgradeOptions.InventoryPolicy = policy\n\tupgradeOptions.EncoderOpt = encoder.WithComments(commentsFlags)\n\n\tif upgradeOptions.ReconcileTimeout == 0 {\n\t\tupgradeOptions.SkipManifestWait = true\n\t}\n\n\treturn k8s.Upgrade(ctx, &state, upgradeOptions)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/upgrade.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/lifecycle\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/talos/multiplex\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/action\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/flags\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nvar upgradeCmdFlags = struct {\n\ttrackableActionCmdFlags\n\timageCmdFlagsType\n\n\tupgradeImage string\n\trebootMode   flags.PflagExtended[machine.RebootRequest_Mode]\n\tprogress     flags.PflagExtended[reporter.OutputMode]\n\n\tforce    bool // Deprecated: only used for legacy upgrade path, to be removed in Talos 1.18.\n\tinsecure bool // Deprecated: only used for legacy upgrade path, to be removed in Talos 1.18.\n\tpreserve bool // Deprecated: only used for legacy upgrade path, to be removed in Talos 1.18.\n\tstage    bool // Deprecated: only used for legacy upgrade path, to be removed in Talos 1.18.\n}{\n\trebootMode: flags.ProtoEnum(machine.RebootRequest_DEFAULT, machine.RebootRequest_Mode_value, machine.RebootRequest_Mode_name),\n\tprogress:   reporter.NewOutputModeFlag(),\n}\n\n// upgradeCmd represents the processes command.\nvar upgradeCmd = &cobra.Command{\n\tUse:   \"upgrade\",\n\tShort: \"Upgrade Talos on the target node\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif upgradeCmdFlags.debug {\n\t\t\tupgradeCmdFlags.wait = true\n\t\t}\n\n\t\tif upgradeCmdFlags.wait && upgradeCmdFlags.insecure {\n\t\t\treturn errors.New(\"cannot use --wait and --insecure together\")\n\t\t}\n\n\t\treturn upgradeRun()\n\t},\n}\n\nfunc upgradeRun() error {\n\treturn WithClientAndNodes(upgradeViaLifecycleService)\n}\n\nvar talosUpgradeAPIVersionRange = semver.MustParseRange(\">1.13.0-alpha.2 <2.0.0\")\n\n// upgradeViaLifecycleService tries the new LifecycleService.Upgrade streaming API.\n// If the server returns codes.Unimplemented, it falls back to the legacy MachineService.Upgrade.\nfunc upgradeViaLifecycleService(ctx context.Context, c *client.Client, nodes []string) error {\n\tif upgradeCmdFlags.debug {\n\t\tupgradeCmdFlags.wait = true\n\t}\n\n\topts := []client.RebootMode{\n\t\tclient.WithRebootMode(upgradeCmdFlags.rebootMode.Value()),\n\t}\n\n\tcontainerdInstance, err := upgradeCmdFlags.containerdInstance()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trep := reporter.New(\n\t\treporter.WithOutputMode(upgradeCmdFlags.progress.Value()),\n\t)\n\n\terr = WithClient(func(ctx context.Context, c *client.Client) error {\n\t\treturn helpers.TalosVersionCheck(ctx, c, talosUpgradeAPIVersionRange)\n\t})\n\tif err != nil {\n\t\tif xerrors.TagIs[helpers.VersionOutsideRangeError](err) {\n\t\t\trep.Report(reporter.Update{\n\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\tMessage: \"New upgrade API is not available, falling back to legacy\",\n\t\t\t})\n\n\t\t\treturn upgradeLegacy()\n\t\t}\n\n\t\treturn fmt.Errorf(\"error checking Talos version compatibility: %w\", err)\n\t}\n\n\t_, err = imagePullInternal(ctx, c, containerdInstance, nodes, upgradeCmdFlags.upgradeImage, rep)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error pulling upgrade image: %w\", err)\n\t}\n\n\t_, err = upgradeInternal(ctx, c, containerdInstance, nodes, upgradeCmdFlags.upgradeImage, rep)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during upgrade: %w\", err)\n\t}\n\n\terr = rebootInternal(upgradeCmdFlags.wait, upgradeCmdFlags.debug, upgradeCmdFlags.timeout, rep, opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error during upgrade: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc upgradeInternal(ctx context.Context, c *client.Client, containerdInstance *common.ContainerdInstance, nodes []string, imageRef string, rep *reporter.Reporter) (map[string]int32, error) {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tvar (\n\t\terrs error\n\t\tw    lifecycle.ProgressWriter\n\t)\n\n\tfinishedUpgrades := map[string]int32{}\n\n\tresponseChan := multiplex.Streaming(ctx, nodes,\n\t\tfunc(ctx context.Context) (grpc.ServerStreamingClient[machine.LifecycleServiceUpgradeResponse], error) {\n\t\t\treturn c.LifecycleClient.Upgrade(ctx, &machine.LifecycleServiceUpgradeRequest{\n\t\t\t\tContainerd: containerdInstance,\n\t\t\t\tSource: &machine.InstallArtifactsSource{\n\t\t\t\t\tImageName: imageRef,\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t)\n\n\tfor resp := range responseChan {\n\t\tif resp.Err != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch resp.Payload.GetProgress().GetResponse().(type) {\n\t\tcase *machine.LifecycleServiceInstallProgress_Message:\n\t\t\tw.UpdateJob(resp.Node, resp.Payload.GetProgress())\n\n\t\t\tw.PrintLayerProgress(rep)\n\t\tcase *machine.LifecycleServiceInstallProgress_ExitCode:\n\t\t\tfinishedUpgrades[resp.Node] = resp.Payload.GetProgress().GetExitCode()\n\n\t\t\tw.UpdateJob(resp.Node, resp.Payload.GetProgress())\n\n\t\t\tw.PrintLayerProgress(rep)\n\t\t}\n\t}\n\n\tif len(finishedUpgrades) > 0 {\n\t\tvar sb strings.Builder\n\n\t\tstatus := reporter.StatusSucceeded\n\n\t\tfor node, exitCode := range finishedUpgrades {\n\t\t\tif exitCode != 0 {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"node %s: upgrade failed with exit code %d\", node, exitCode))\n\n\t\t\t\tstatus = reporter.StatusError\n\n\t\t\t\tfmt.Fprintf(&sb, \"%s: upgrade failed with exit code %d\\n\", node, exitCode)\n\t\t\t} else {\n\t\t\t\tfmt.Fprintf(&sb, \"%s: upgrade completed\\n\", node)\n\t\t\t}\n\t\t}\n\n\t\trep.Report(reporter.Update{\n\t\t\tMessage: sb.String(),\n\t\t\tStatus:  status,\n\t\t})\n\t}\n\n\treturn finishedUpgrades, errs\n}\n\n// upgradeLegacy dispatches to the legacy upgrade path, respecting --wait.\n//\n// Note: remove me in Talos 1.18.\nfunc upgradeLegacy() error {\n\trebootModeStr := strings.ToUpper(upgradeCmdFlags.rebootMode.String())\n\n\trebootMode, ok := machine.UpgradeRequest_RebootMode_value[rebootModeStr]\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid reboot mode: %s\", upgradeCmdFlags.rebootMode)\n\t}\n\n\topts := []client.UpgradeOption{\n\t\tclient.WithUpgradeImage(upgradeCmdFlags.upgradeImage),\n\t\tclient.WithUpgradeRebootMode(machine.UpgradeRequest_RebootMode(rebootMode)),\n\t\tclient.WithUpgradePreserve(upgradeCmdFlags.preserve),\n\t\tclient.WithUpgradeStage(upgradeCmdFlags.stage),\n\t\tclient.WithUpgradeForce(upgradeCmdFlags.force),\n\t}\n\n\tif !upgradeCmdFlags.wait {\n\t\treturn runUpgradeLegacyNoWaitWithOpts(opts)\n\t}\n\n\treturn action.NewTracker(\n\t\t&GlobalArgs,\n\t\taction.MachineReadyEventFn,\n\t\tfunc(ctx context.Context, c *client.Client) (string, error) {\n\t\t\treturn upgradeGetActorID(ctx, c, opts)\n\t\t},\n\t\taction.WithPostCheck(action.BootIDChangedPostCheckFn),\n\t\taction.WithDebug(upgradeCmdFlags.debug),\n\t\taction.WithTimeout(upgradeCmdFlags.timeout),\n\t).Run()\n}\n\n// runUpgradeLegacyNoWaitWithOpts runs the legacy upgrade without waiting.\n//\n// Note: remove me in Talos 1.18.\nfunc runUpgradeLegacyNoWaitWithOpts(opts []client.UpgradeOption) error {\n\tif upgradeCmdFlags.insecure {\n\t\treturn WithClientMaintenance(nil, func(ctx context.Context, c *client.Client) error {\n\t\t\treturn doUpgradeLegacy(ctx, c, opts)\n\t\t})\n\t}\n\n\treturn WithClient(func(ctx context.Context, c *client.Client) error {\n\t\treturn doUpgradeLegacy(ctx, c, opts)\n\t})\n}\n\n// doUpgradeLegacy performs the legacy MachineService.Upgrade call on an existing client.\n//\n// Note: remove me in Talos 1.18.\nfunc doUpgradeLegacy(ctx context.Context, c *client.Client, opts []client.UpgradeOption) error {\n\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\treturn err\n\t}\n\n\tvar remotePeer peer.Peer\n\n\topts = append(opts, client.WithUpgradeGRPCCallOptions(grpc.Peer(&remotePeer)))\n\n\t// TODO: See if we can validate version and prevent starting upgrades to an unknown version\n\tresp, err := c.UpgradeWithOptions(ctx, opts...) //nolint:staticcheck // legacy talosctl methods, to be removed in Talos 1.18\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error performing upgrade: %s\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)\n\tfmt.Fprintln(w, \"NODE\\tACK\\tSTARTED\")\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t\\n\", node, msg.Ack, time.Now())\n\t}\n\n\treturn w.Flush()\n}\n\n// upgradeGetActorID is used by the legacy action tracker path.\n//\n// Note: remove me in Talos 1.18.\nfunc upgradeGetActorID(ctx context.Context, c *client.Client, opts []client.UpgradeOption) (string, error) {\n\tresp, err := c.UpgradeWithOptions(ctx, opts...) //nolint:staticcheck // legacy talosctl methods, to be removed in Talos 1.18\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif len(resp.GetMessages()) == 0 {\n\t\treturn \"\", errors.New(\"no messages returned from action run\")\n\t}\n\n\treturn resp.GetMessages()[0].GetActorId(), nil\n}\n\nfunc init() {\n\tupgradeCmd.Flags().StringVarP(&upgradeCmdFlags.upgradeImage, \"image\", \"i\",\n\t\tfmt.Sprintf(\"%s/%s/installer:%s\", images.Registry, images.Username, version.Trim(version.Tag)),\n\t\t\"the container image to use for performing the install\")\n\tupgradeCmd.Flags().StringVar(&upgradeCmdFlags.namespace, \"namespace\", \"system\",\n\t\t\"namespace to use: \\\"system\\\" (etcd and kubelet images), \\\"cri\\\" for all Kubernetes workloads, \\\"inmem\\\" for in-memory containerd instance\",\n\t)\n\tupgradeCmd.Flags().VarP(upgradeCmdFlags.rebootMode, \"reboot-mode\", \"m\",\n\t\tfmt.Sprintf(\n\t\t\t\"select the reboot mode during upgrade. Mode %q bypasses kexec. Values: %v\",\n\t\t\tstrings.ToLower(machine.UpgradeRequest_POWERCYCLE.String()),\n\t\t\tupgradeCmdFlags.rebootMode.Options(),\n\t\t),\n\t)\n\tupgradeCmd.Flags().Var(upgradeCmdFlags.progress, \"progress\", fmt.Sprintf(\"output mode for upgrade progress. Values: %v\", upgradeCmdFlags.progress.Options()))\n\n\t// Mark legacy-only flags as deprecated. These are only used when falling back\n\t// to the legacy MachineService.Upgrade unary API for older Talos versions.\n\t//\n\t// Note: remove me in Talos 1.18.\n\tupgradeCmdFlags.addTrackActionFlags(upgradeCmd)\n\tupgradeCmd.Flags().BoolVarP(&upgradeCmdFlags.force, \"force\", \"f\", false, \"force the upgrade (skip checks on etcd health and members, might lead to data loss)\")\n\tupgradeCmd.Flags().BoolVar(&upgradeCmdFlags.insecure, \"insecure\", false, \"upgrade using the insecure (encrypted with no auth) maintenance service\")\n\tupgradeCmd.Flags().BoolVarP(&upgradeCmdFlags.preserve, \"preserve\", \"p\", false, \"preserve data\")\n\tupgradeCmd.Flags().BoolVarP(&upgradeCmdFlags.stage, \"stage\", \"s\", false, \"stage the upgrade to perform it after a reboot\")\n\n\tfor _, flag := range []string{\"force\", \"insecure\", \"preserve\", \"stage\"} {\n\t\tupgradeCmd.Flags().MarkDeprecated(flag, \"legacy flag for MachineService.Upgrade fallback, to be removed in Talos 1.18\") //nolint:errcheck\n\t}\n\n\taddCommand(upgradeCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/peer\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// versionCmdFlags represents the `talosctl version` command's flags.\nvar versionCmdFlags struct {\n\tclientOnly   bool\n\tshortVersion bool\n\tjson         bool\n\tinsecure     bool\n}\n\n// versionCmd represents the `talosctl version` command.\nvar versionCmd = &cobra.Command{\n\tUse:   \"version\",\n\tShort: \"Prints the version\",\n\tLong:  ``,\n\tArgs:  cobra.NoArgs,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif !versionCmdFlags.json {\n\t\t\tfmt.Println(\"Client:\")\n\n\t\t\tif versionCmdFlags.shortVersion {\n\t\t\t\tversion.PrintShortVersion()\n\t\t\t} else {\n\t\t\t\tversion.PrintLongVersion()\n\t\t\t}\n\n\t\t\t// Exit early if we're only looking for client version\n\t\t\tif versionCmdFlags.clientOnly {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tfmt.Println(\"Server:\")\n\t\t}\n\n\t\tif versionCmdFlags.insecure {\n\t\t\treturn WithClientMaintenance(nil, cmdVersion)\n\t\t}\n\n\t\treturn WithClient(cmdVersion)\n\t},\n}\n\nfunc cmdVersion(ctx context.Context, c *client.Client) error {\n\tvar remotePeer peer.Peer\n\n\tresp, err := c.Version(ctx, grpc.Peer(&remotePeer))\n\tif err != nil {\n\t\tif resp == nil {\n\t\t\treturn fmt.Errorf(\"error getting version: %s\", err)\n\t\t}\n\n\t\tcli.Warning(\"%s\", err)\n\t}\n\n\tdefaultNode := client.AddrFromPeer(&remotePeer)\n\n\tfor _, msg := range resp.Messages {\n\t\tnode := defaultNode\n\n\t\tif msg.Metadata != nil {\n\t\t\tnode = msg.Metadata.Hostname\n\t\t}\n\n\t\tif !versionCmdFlags.json {\n\t\t\tfmt.Printf(\"\\t%s:        %s\\n\", \"NODE\", node)\n\n\t\t\tversion.PrintLongVersionFromExisting(msg.Version)\n\n\t\t\tvar enabledFeatures []string\n\t\t\tif msg.Features.GetRbac() {\n\t\t\t\tenabledFeatures = append(enabledFeatures, \"RBAC\")\n\t\t\t}\n\n\t\t\tfmt.Printf(\"\\tEnabled:     %s\\n\", strings.Join(enabledFeatures, \", \"))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tb, err := protojson.Marshal(msg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfmt.Printf(\"%s\\n\", b)\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tversionCmd.Flags().BoolVar(&versionCmdFlags.shortVersion, \"short\", false, \"Print the short version\")\n\tversionCmd.Flags().BoolVar(&versionCmdFlags.clientOnly, \"client\", false, \"Print client version only\")\n\tversionCmd.Flags().BoolVarP(&versionCmdFlags.insecure, \"insecure\", \"i\", false, \"use Talos maintenance mode API\")\n\n\t// TODO remove when https://github.com/siderolabs/talos/issues/907 is implemented\n\tversionCmd.Flags().BoolVar(&versionCmdFlags.json, \"json\", false, \"\")\n\tcli.Should(versionCmd.Flags().MarkHidden(\"json\"))\n\n\taddCommand(versionCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/cmd/talos/wipe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// wipeCmd represents the wipe command.\nvar wipeCmd = &cobra.Command{\n\tUse:   \"wipe\",\n\tShort: \"Wipe block device or volumes\",\n\tArgs:  cobra.NoArgs,\n}\n\nvar wipeDiskCmdFlags struct {\n\twipeMethod         string\n\tskipVolumeCheck    bool\n\tskipSecondaryCheck bool\n\tdropPartition      bool\n\tinsecure           bool\n}\n\n// wipeDiskCmd represents the wipe disk command.\nvar wipeDiskCmd = &cobra.Command{\n\tUse:   \"disk <device names>...\",\n\tShort: \"Wipe a block device (disk or partition) which is not used as a volume\",\n\tLong: `Wipe a block device (disk or partition) which is not used as a volume.\n\nUse device names as arguments, for example: vda or sda5.`,\n\tArgs: cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif wipeDiskCmdFlags.insecure {\n\t\t\treturn WithClientMaintenance(nil, cmdWipe(args))\n\t\t}\n\n\t\treturn WithClient(cmdWipe(args))\n\t},\n}\n\nfunc cmdWipe(args []string) func(ctx context.Context, c *client.Client) error {\n\treturn func(ctx context.Context, c *client.Client) error {\n\t\tmethod, ok := storage.BlockDeviceWipeDescriptor_Method_value[wipeDiskCmdFlags.wipeMethod]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"invalid wipe method %q\", wipeDiskCmdFlags.wipeMethod)\n\t\t}\n\n\t\treturn c.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: xslices.Map(args, func(devName string) *storage.BlockDeviceWipeDescriptor {\n\t\t\t\treturn &storage.BlockDeviceWipeDescriptor{\n\t\t\t\t\tDevice:             devName,\n\t\t\t\t\tMethod:             storage.BlockDeviceWipeDescriptor_Method(method),\n\t\t\t\t\tSkipVolumeCheck:    wipeDiskCmdFlags.skipVolumeCheck,\n\t\t\t\t\tSkipSecondaryCheck: wipeDiskCmdFlags.skipSecondaryCheck,\n\t\t\t\t\tDropPartition:      wipeDiskCmdFlags.dropPartition,\n\t\t\t\t}\n\t\t\t}),\n\t\t})\n\t}\n}\n\nfunc wipeMethodValues() []string {\n\tvar method storage.BlockDeviceWipeDescriptor_Method\n\n\tvalues := make([]string, method.Descriptor().Values().Len())\n\n\tfor idx := range method.Descriptor().Values().Len() {\n\t\tvalues[idx] = storage.BlockDeviceWipeDescriptor_Method_name[int32(idx)]\n\t}\n\n\treturn values\n}\n\nfunc init() {\n\taddCommand(wipeCmd)\n\n\twipeDiskCmd.Flags().StringVar(&wipeDiskCmdFlags.wipeMethod, \"method\", wipeMethodValues()[0], fmt.Sprintf(\"wipe method to use %s\", wipeMethodValues()))\n\twipeDiskCmd.Flags().BoolVar(&wipeDiskCmdFlags.skipVolumeCheck, \"skip-volume-check\", false, \"skip volume check\")\n\twipeDiskCmd.Flags().BoolVar(&wipeDiskCmdFlags.skipSecondaryCheck, \"skip-secondary-check\", false, \"skip secondary disk check (e.g. underlying disk for RAID or LVM), use with caution\")\n\twipeDiskCmd.Flags().BoolVar(&wipeDiskCmdFlags.dropPartition, \"drop-partition\", false, \"drop partition after wipe (if applicable)\")\n\twipeDiskCmd.Flags().MarkHidden(\"skip-volume-check\")    //nolint:errcheck\n\twipeDiskCmd.Flags().MarkHidden(\"skip-secondary-check\") //nolint:errcheck\n\twipeDiskCmd.Flags().BoolVarP(&wipeDiskCmdFlags.insecure, \"insecure\", \"i\", false, \"use Talos maintenance mode API\")\n\n\twipeCmd.AddCommand(wipeDiskCmd)\n}\n"
  },
  {
    "path": "cmd/talosctl/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talosctl provides the talosctl utility implementation.\npackage main\n\nimport (\n\t\"os\"\n\n\t_ \"github.com/siderolabs/talos/cmd/talosctl/acompat\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd\"\n)\n\nfunc main() {\n\tif err := cmd.Execute(); err != nil {\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/mgmt/helpers/airgapped.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\tstdx509 \"crypto/x509\"\n\t\"net\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// GenerateSelfSignedCert generates self-signed certificate.\nfunc GenerateSelfSignedCert(sanIPs []net.IP, sanNames []string) ([]byte, []byte, []byte, error) {\n\tca, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.ECDSA(true),\n\t\tx509.Organization(\"talos.dev\"),\n\t\tx509.CommonName(\"talos.dev Root CA\"),\n\t)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tserverIdentity, err := x509.NewKeyPair(ca,\n\t\tx509.Organization(\"talos.dev\"),\n\t\tx509.CommonName(\"server\"),\n\t\tx509.IPAddresses(sanIPs),\n\t\tx509.DNSNames(sanNames),\n\t\tx509.ExtKeyUsage([]stdx509.ExtKeyUsage{stdx509.ExtKeyUsageServerAuth}),\n\t)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\treturn ca.CrtPEM, serverIdentity.CrtPEM, serverIdentity.KeyPEM, nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/mgmt/helpers/artifacts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package helpers provides helpers for talosctl.\npackage helpers\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/gendata\"\n)\n\n// ArtifactsPath is a path to artifacts output directory (set during the build).\nvar ArtifactsPath = gendata.ArtifactsPath\n\n// ArtifactPath returns path to the artifact by name.\nfunc ArtifactPath(name string) string {\n\treturn filepath.Join(ArtifactsPath, name)\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/mgmt/helpers/helpers_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/mgmt/helpers/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// DefaultImage appends default image version.\nfunc DefaultImage(image string) string {\n\treturn fmt.Sprintf(\"%s:%s\", image, GetTag())\n}\n\n// GetTag retrieves the current tag.\nfunc GetTag() string {\n\treturn getEnv(\"TAG\", version.Tag)\n}\n\nfunc getEnv(key, fallback string) string {\n\tif value, ok := os.LookupEnv(key); ok {\n\t\treturn value\n\t}\n\n\treturn fallback\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/mgmt/helpers/wireguard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\tsideronet \"github.com/siderolabs/net\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n// NewWireguardConfigBundle creates a new Wireguard config bundle.\nfunc NewWireguardConfigBundle(ips []netip.Addr, wireguardCidr string, listenPort, controlplanesCount int) (*WireguardConfigBundle, error) {\n\tconfigs := map[netip.Addr]*network.WireguardConfigV1Alpha1{}\n\tkeys := make([]wgtypes.Key, len(ips))\n\tpeers := make([]network.WireguardPeer, len(ips))\n\n\twgCidr, err := netip.ParsePrefix(wireguardCidr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse wireguard cidr %s: %w\", wireguardCidr, err)\n\t}\n\n\tfor i, ip := range ips {\n\t\tkey, err := wgtypes.GeneratePrivateKey()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\twgAddr, err := sideronet.NthIPInNetwork(wgCidr, i+2)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tkeys[i] = key\n\n\t\tpeers[i] = network.WireguardPeer{\n\t\t\tWireguardAllowedIPs: []network.Prefix{\n\t\t\t\t{\n\t\t\t\t\tPrefix: netip.PrefixFrom(wgAddr, wgAddr.BitLen()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tWireguardPublicKey:                   key.PublicKey().String(),\n\t\t\tWireguardPersistentKeepaliveInterval: time.Second * 5,\n\t\t}\n\n\t\tif i < controlplanesCount {\n\t\t\tpeers[i].WireguardEndpoint = network.AddrPort{AddrPort: netip.AddrPortFrom(ip, uint16(listenPort))}\n\t\t}\n\t}\n\n\tfor i, nodeIP := range ips {\n\t\twgAddr, err := sideronet.NthIPInNetwork(wgCidr, i+2)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tconfig := network.NewWireguardConfigV1Alpha1(\"wg0\")\n\n\t\tconfig.WireguardPeers = xslices.Filter(peers, func(p network.WireguardPeer) bool {\n\t\t\treturn p.WireguardPublicKey != keys[i].PublicKey().String()\n\t\t})\n\t\tconfig.WireguardPrivateKey = keys[i].String()\n\t\tconfig.LinkAddresses = []network.AddressConfig{\n\t\t\t{\n\t\t\t\tAddressAddress: netip.PrefixFrom(wgAddr, wgCidr.Bits()),\n\t\t\t},\n\t\t}\n\t\tconfig.LinkUp = new(true)\n\t\tconfig.LinkMTU = 1500\n\n\t\tif i < controlplanesCount {\n\t\t\tconfig.WireguardListenPort = listenPort\n\t\t}\n\n\t\tconfigs[nodeIP] = config\n\t}\n\n\treturn &WireguardConfigBundle{\n\t\tconfigs: configs,\n\t}, nil\n}\n\n// WireguardConfigBundle allows assembling wireguard network configuration with first controlplane being listen node.\ntype WireguardConfigBundle struct {\n\tconfigs map[netip.Addr]*network.WireguardConfigV1Alpha1\n}\n\n// PatchNode generates config patch for a node.\nfunc (w *WireguardConfigBundle) PatchNode(ip netip.Addr) (configpatcher.Patch, error) {\n\tcfg, ok := w.configs[ip]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no wireguard config for ip %s\", ip.String())\n\t}\n\n\tctr, err := container.New(cfg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create wireguard config container: %w\", err)\n\t}\n\n\treturn configpatcher.NewStrategicMergePatch(ctr), nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/action/node.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage action\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-circular\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// nodeTracker tracks the actions of a single node.\ntype nodeTracker struct {\n\tctx     context.Context //nolint:containedctx\n\tnode    string\n\ttracker *Tracker\n\tdmesg   *circular.Buffer\n\tcli     *client.Client\n}\n\n// tailDebugLogs starts tailing the dmesg of the node.\nfunc (a *nodeTracker) tailDebugLogs() error {\n\treturn retry.Constant(a.tracker.timeout).RetryWithContext(a.ctx, func(ctx context.Context) error {\n\t\terr := func() error {\n\t\t\tstream, err := a.cli.Dmesg(ctx, true, true)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn helpers.ReadGRPCStream(stream, func(data *common.Data, _ string, _ bool) error {\n\t\t\t\t_, err := fmt.Fprintf(a.dmesg, \"%s: %s\", a.node, data.GetBytes())\n\n\t\t\t\treturn err\n\t\t\t})\n\t\t}()\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tif strings.Contains(err.Error(), \"file already closed\") {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tstatusCode := client.StatusCode(err)\n\t\tif errors.Is(err, io.EOF) || statusCode == codes.Unavailable {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t})\n}\n\nfunc (a *nodeTracker) run() error {\n\tvar (\n\t\tactorIDCh                chan string\n\t\tnodeEg                   errgroup.Group\n\t\tactorID, preActionBootID string\n\t\terr                      error\n\t)\n\n\tactorIDCh = make(chan string)\n\n\tnodeEg.Go(func() error {\n\t\treturn a.trackEventsWithRetry(actorIDCh)\n\t})\n\n\tif a.tracker.postCheckFn != nil {\n\t\tpreActionBootID, err = getBootID(a.ctx, a.cli)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tactorID, err = a.tracker.actionFn(a.ctx, a.cli)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase actorIDCh <- actorID:\n\tcase <-a.ctx.Done():\n\t\treturn a.ctx.Err()\n\t}\n\n\terr = nodeEg.Wait()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif a.tracker.postCheckFn == nil {\n\t\treturn nil\n\t}\n\n\treturn a.runPostCheckWithRetry(preActionBootID)\n}\n\nfunc (a *nodeTracker) update(update reporter.Update) {\n\tselect {\n\tcase a.tracker.reportCh <- nodeUpdate{\n\t\tnode:   a.node,\n\t\tupdate: update,\n\t}:\n\tcase <-a.ctx.Done():\n\t}\n}\n\nfunc (a *nodeTracker) trackEventsWithRetry(actorIDCh chan string) error {\n\tvar (\n\t\ttailEvents     int32\n\t\tactorID        string\n\t\twaitForActorID = true\n\t)\n\n\treturn retry.Constant(a.tracker.timeout).RetryWithContext(a.ctx, func(ctx context.Context) error {\n\t\t// retryable function\n\t\terr := func() error {\n\t\t\teventCh := make(chan client.EventResult)\n\n\t\t\terr := a.cli.EventsWatchV2(ctx, eventCh, client.WithTailEvents(tailEvents))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif waitForActorID {\n\t\t\t\ta.update(reporter.Update{\n\t\t\t\t\tMessage: \"waiting for actor ID\",\n\t\t\t\t\tStatus:  reporter.StatusRunning,\n\t\t\t\t})\n\n\t\t\t\tselect {\n\t\t\t\tcase actorID = <-actorIDCh:\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn ctx.Err()\n\t\t\t\t}\n\n\t\t\t\ta.update(reporter.Update{\n\t\t\t\t\tMessage: fmt.Sprintf(\"actor ID: %v\", actorID),\n\t\t\t\t\tStatus:  reporter.StatusRunning,\n\t\t\t\t})\n\n\t\t\t\twaitForActorID = false\n\t\t\t}\n\n\t\t\treturn a.handleEvents(eventCh, actorID)\n\t\t}()\n\n\t\t// handle retryable errors\n\n\t\tstatusCode := client.StatusCode(err)\n\t\tif errors.Is(err, io.EOF) || statusCode == codes.Unavailable {\n\t\t\ta.update(reporter.Update{\n\t\t\t\tMessage: \"unavailable, retrying...\",\n\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t})\n\n\t\t\ttailEvents = -1\n\t\t\tactorID = \"\"\n\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif err != nil {\n\t\t\ta.update(reporter.Update{\n\t\t\t\tMessage: fmt.Sprintf(\"error: %v\", err),\n\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t})\n\t\t}\n\n\t\treturn err\n\t})\n}\n\nfunc (a *nodeTracker) runPostCheckWithRetry(preActionBootID string) error {\n\treturn retry.Constant(a.tracker.timeout).RetryWithContext(a.ctx, func(ctx context.Context) error {\n\t\t// retryable function\n\t\terr := func() error {\n\t\t\terr := a.tracker.postCheckFn(ctx, a.cli, preActionBootID)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ta.update(reporter.Update{\n\t\t\t\tMessage: \"post check passed\",\n\t\t\t\tStatus:  reporter.StatusSucceeded,\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}()\n\n\t\t// handle retryable errors\n\t\tstatusCode := client.StatusCode(err)\n\t\tif errors.Is(err, io.EOF) || statusCode == codes.Unavailable || statusCode == codes.Canceled {\n\t\t\ta.update(reporter.Update{\n\t\t\t\tMessage: \"unavailable, retrying...\",\n\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t})\n\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t})\n}\n\nfunc (a *nodeTracker) handleEvents(eventCh chan client.EventResult, actorID string) error {\n\tfor {\n\t\tvar eventResult client.EventResult\n\n\t\tselect {\n\t\tcase eventResult = <-eventCh:\n\t\tcase <-a.ctx.Done():\n\t\t\treturn a.ctx.Err()\n\t\t}\n\n\t\tif a.tracker.expectedEventFn(eventResult) {\n\t\t\tstatus := reporter.StatusSucceeded\n\t\t\tif a.tracker.postCheckFn != nil {\n\t\t\t\tstatus = reporter.StatusRunning\n\t\t\t}\n\n\t\t\ta.update(reporter.Update{\n\t\t\t\tMessage: \"events check condition met\",\n\t\t\t\tStatus:  status,\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif eventResult.Error != nil {\n\t\t\treturn eventResult.Error\n\t\t}\n\n\t\tif eventResult.Event.ActorID == actorID {\n\t\t\terr := a.handleEvent(eventResult.Event)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (a *nodeTracker) handleEvent(event client.Event) error {\n\tswitch msg := event.Payload.(type) {\n\tcase *machineapi.PhaseEvent:\n\t\ta.update(reporter.Update{\n\t\t\tMessage: fmt.Sprintf(\"phase: %s action: %v\", msg.GetPhase(), msg.GetAction()),\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t})\n\n\tcase *machineapi.TaskEvent:\n\t\ta.update(reporter.Update{\n\t\t\tMessage: fmt.Sprintf(\"task: %s action: %v\", msg.GetTask(), msg.GetAction()),\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t})\n\n\t\tif msg.GetTask() == \"stopAllServices\" {\n\t\t\treturn retry.ExpectedErrorf(\"stopAllServices task completed\")\n\t\t}\n\n\tcase *machineapi.SequenceEvent:\n\t\terrStr := \"\"\n\t\tif msg.GetError().GetMessage() != \"\" {\n\t\t\terrStr = fmt.Sprintf(\n\t\t\t\t\" error: [code: %v message: %v]\",\n\t\t\t\tmsg.GetError().GetMessage(),\n\t\t\t\tmsg.GetError().GetCode(),\n\t\t\t)\n\t\t}\n\n\t\ta.update(reporter.Update{\n\t\t\tMessage: fmt.Sprintf(\"sequence: %s action: %v%v\", msg.GetSequence(), msg.GetAction(), errStr),\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t})\n\n\t\tif msg.GetSequence() == \"reboot\" {\n\t\t\treturn retry.ExpectedErrorf(\"reboot sequence completed\")\n\t\t}\n\n\t\tif errStr != \"\" {\n\t\t\treturn fmt.Errorf(\"sequence error: %s\", msg.GetError().GetMessage())\n\t\t}\n\n\tcase *machineapi.MachineStatusEvent:\n\t\ta.update(reporter.Update{\n\t\t\tMessage: fmt.Sprintf(\"stage: %v ready: %v unmetCond: %v\", msg.GetStage(), msg.GetStatus().GetReady(), msg.GetStatus().GetUnmetConditions()),\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t})\n\n\tcase *machineapi.ServiceStateEvent:\n\t\ta.update(reporter.Update{\n\t\t\tMessage: fmt.Sprintf(\"service: %v message: %v healthy: %v\", msg.GetService(), msg.GetMessage(), msg.GetHealth().GetHealthy()),\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t})\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/action/tracker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage action\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mattn/go-isatty\"\n\t\"github.com/siderolabs/gen/containers\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-circular\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/backoff\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/cmd/common\"\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nconst unauthorizedBootIDFallback = \"(unauthorized)\"\n\nvar (\n\t// MachineReadyEventFn is the predicate function that returns true if the event indicates the machine is ready.\n\tMachineReadyEventFn = func(event client.EventResult) bool {\n\t\tmachineStatusEvent, ok := event.Event.Payload.(*machineapi.MachineStatusEvent)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\treturn machineStatusEvent.GetStage() == machineapi.MachineStatusEvent_RUNNING &&\n\t\t\tmachineStatusEvent.GetStatus().GetReady()\n\t}\n\n\t// StopAllServicesEventFn is the predicate function that returns true if the event indicates that all services are being stopped.\n\tStopAllServicesEventFn = func(event client.EventResult) bool {\n\t\ttaskEvent, ok := event.Event.Payload.(*machineapi.TaskEvent)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\treturn taskEvent.GetTask() == \"stopAllServices\"\n\t}\n\n\t// BootIDChangedPostCheckFn is a post check function that returns nil if the boot ID has changed.\n\tBootIDChangedPostCheckFn = func(ctx context.Context, c *client.Client, preActionBootID string) error {\n\t\tif preActionBootID == unauthorizedBootIDFallback {\n\t\t\treturn nil\n\t\t}\n\n\t\tcurrentBootID, err := getBootID(ctx, c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif preActionBootID == currentBootID {\n\t\t\treturn retry.ExpectedErrorf(\"didn't reboot yet\")\n\t\t}\n\n\t\treturn nil\n\t}\n)\n\ntype nodeUpdate struct {\n\tnode   string\n\tupdate reporter.Update\n}\n\n// Tracker runs the action in the actionFn on the nodes and tracks its progress using the provided expectedEventFn and postCheckFn.\ntype Tracker struct {\n\texpectedEventFn          func(event client.EventResult) bool\n\tactionFn                 func(ctx context.Context, c *client.Client) (string, error)\n\tpostCheckFn              func(ctx context.Context, c *client.Client, preActionBootID string) error\n\treporter                 *reporter.Reporter\n\tnodeToLatestStatusUpdate map[string]reporter.Update\n\treportCh                 chan nodeUpdate\n\ttimeout                  time.Duration\n\tisTerminal               bool\n\tdebug                    bool\n\tclientExecutor           ClientExecutor\n}\n\n// TrackerOption is the functional option for the Tracker.\ntype TrackerOption func(*Tracker)\n\n// WithReporter sets the reporter for the tracker.\nfunc WithReporter(r *reporter.Reporter) TrackerOption {\n\treturn func(t *Tracker) {\n\t\tif r != nil {\n\t\t\tt.reporter = r\n\t\t}\n\t}\n}\n\n// WithTimeout sets the timeout for the tracker.\nfunc WithTimeout(timeout time.Duration) TrackerOption {\n\treturn func(t *Tracker) {\n\t\tt.timeout = timeout\n\t}\n}\n\n// WithPostCheck sets the post check function.\nfunc WithPostCheck(postCheckFn func(ctx context.Context, c *client.Client, preActionBootID string) error) TrackerOption {\n\treturn func(t *Tracker) {\n\t\tt.postCheckFn = postCheckFn\n\t}\n}\n\n// WithDebug enables debug mode.\nfunc WithDebug(debug bool) TrackerOption {\n\treturn func(t *Tracker) {\n\t\tt.debug = debug\n\t}\n}\n\n// WithTerminalOverride sets the terminal override.\nfunc WithTerminalOverride(isTerminal bool) TrackerOption {\n\treturn func(t *Tracker) {\n\t\tt.isTerminal = isTerminal\n\t}\n}\n\n// NewTracker creates a new Tracker.\nfunc NewTracker(\n\tclientExecutor ClientExecutor,\n\texpectedEventFn func(event client.EventResult) bool,\n\tactionFn func(ctx context.Context, c *client.Client) (string, error),\n\topts ...TrackerOption,\n) *Tracker {\n\ttracker := Tracker{\n\t\texpectedEventFn:          expectedEventFn,\n\t\tactionFn:                 actionFn,\n\t\tnodeToLatestStatusUpdate: make(map[string]reporter.Update, len(clientExecutor.NodeList())),\n\t\treporter:                 reporter.New(),\n\t\treportCh:                 make(chan nodeUpdate),\n\t\tisTerminal:               isatty.IsTerminal(os.Stderr.Fd()),\n\t\tclientExecutor:           clientExecutor,\n\t}\n\n\tfor _, option := range opts {\n\t\toption(&tracker)\n\t}\n\n\treturn &tracker\n}\n\n// ClientExecutor is the interface for the client executor.\ntype ClientExecutor interface {\n\tWithClient(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error\n\tNodeList() []string\n}\n\n// Run executes the action on nodes and tracks its progress by watching events with retries.\n// After receiving the expected event, if provided, it tracks the progress by running the post check with retries.\n//\n//nolint:gocyclo\nfunc (a *Tracker) Run() error {\n\tvar failedNodesToDmesgs containers.ConcurrentMap[string, io.Reader]\n\n\tvar eg errgroup.Group\n\n\terr := a.clientExecutor.WithClient(func(ctx context.Context, c *client.Client) error {\n\t\tctx, cancel := context.WithTimeout(ctx, a.timeout)\n\t\tdefer cancel()\n\n\t\tif err := helpers.ClientVersionCheck(ctx, c); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\teg.Go(func() error {\n\t\t\treturn a.runReporter(ctx)\n\t\t})\n\n\t\t// Reporter is started, it will print the errors if there is any.\n\t\t// So from here on we can suppress the command error to be printed to avoid it being printed twice.\n\t\tcommon.SuppressErrors = true\n\n\t\tvar trackEg errgroup.Group\n\n\t\tfor _, node := range a.clientExecutor.NodeList() {\n\t\t\tvar (\n\t\t\t\tdmesg *circular.Buffer\n\t\t\t\terr   error\n\t\t\t)\n\n\t\t\tif a.debug {\n\t\t\t\tdmesg, err = circular.NewBuffer()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttracker := nodeTracker{\n\t\t\t\tctx:     client.WithNode(ctx, node),\n\t\t\t\tnode:    node,\n\t\t\t\ttracker: a,\n\t\t\t\tdmesg:   dmesg,\n\t\t\t\tcli:     c,\n\t\t\t}\n\n\t\t\tif a.debug {\n\t\t\t\teg.Go(tracker.tailDebugLogs)\n\t\t\t}\n\n\t\t\ttrackEg.Go(func() error {\n\t\t\t\ttrackErr := tracker.run()\n\t\t\t\tif trackErr != nil {\n\t\t\t\t\tif a.debug {\n\t\t\t\t\t\tfailedNodesToDmesgs.Set(node, dmesg.GetReader())\n\t\t\t\t\t}\n\n\t\t\t\t\ttracker.update(reporter.Update{\n\t\t\t\t\t\tMessage: trackErr.Error(),\n\t\t\t\t\t\tStatus:  reporter.StatusError,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn trackErr\n\t\t\t})\n\t\t}\n\n\t\treturn trackEg.Wait()\n\t}, grpc.WithConnectParams(grpc.ConnectParams{\n\t\t// disable grpc backoff\n\t\tBackoff:           backoff.Config{},\n\t\tMinConnectTimeout: 20 * time.Second,\n\t}))\n\tif errors.Is(err, context.Canceled) {\n\t\terr = nil\n\t}\n\n\teg.Wait() //nolint:errcheck\n\n\tif !a.debug {\n\t\treturn err\n\t}\n\n\tvar failedNodes []string\n\n\tfailedNodesToDmesgs.ForEach(func(key string, _ io.Reader) {\n\t\tfailedNodes = append(failedNodes, key)\n\t})\n\n\tif len(failedNodes) > 0 {\n\t\tslices.Sort(failedNodes)\n\n\t\tfmt.Fprintf(os.Stderr, \"console logs for nodes %q:\\n\", failedNodes)\n\n\t\tfor _, node := range failedNodes {\n\t\t\tdmesgReader, _ := failedNodesToDmesgs.Get(node)\n\n\t\t\t_, copyErr := io.Copy(os.Stderr, dmesgReader)\n\t\t\tif copyErr != nil {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"%q: failed to print debug logs: %v\\n\", node, copyErr)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn err\n}\n\n// runReporter starts the (colored) stderr reporter.\nfunc (a *Tracker) runReporter(ctx context.Context) error {\n\tvar (\n\t\tupdate       nodeUpdate\n\t\treportUpdate reporter.Update\n\t)\n\n\tticker := time.NewTicker(100 * time.Millisecond)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tif a.isTerminal {\n\t\t\t\ta.reporter.Report(reportUpdate)\n\t\t\t}\n\n\t\t\treturn ctx.Err()\n\n\t\tcase <-ticker.C:\n\t\t\tif a.isTerminal {\n\t\t\t\ta.reporter.Report(reportUpdate)\n\t\t\t}\n\n\t\tcase update = <-a.reportCh:\n\t\t\tif !a.isTerminal {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"%q: %v\\n\", update.node, update.update.Message)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treportUpdate = a.processNodeUpdate(update)\n\t\t}\n\t}\n}\n\nfunc (a *Tracker) processNodeUpdate(update nodeUpdate) reporter.Update {\n\tif update.node != \"\" {\n\t\ta.nodeToLatestStatusUpdate[update.node] = update.update\n\t}\n\n\tnodes := maps.Keys(a.nodeToLatestStatusUpdate)\n\tslices.Sort(nodes)\n\n\tmessages := make([]string, 0, len(nodes)+1)\n\tmessages = append(messages, fmt.Sprintf(\"watching nodes: %v\", nodes))\n\n\tfor _, node := range nodes {\n\t\tnUpdate := a.nodeToLatestStatusUpdate[node]\n\n\t\tmessages = append(messages, fmt.Sprintf(\"    * %s: %s\", node, nUpdate.Message))\n\t}\n\n\tcombinedMessage := strings.Join(messages, \"\\n\")\n\tcombinedStatus := func() reporter.Status {\n\t\tcombined := reporter.StatusSucceeded\n\n\t\tfor _, status := range a.nodeToLatestStatusUpdate {\n\t\t\tif status.Status == reporter.StatusError {\n\t\t\t\treturn reporter.StatusError\n\t\t\t}\n\n\t\t\tif status.Status == reporter.StatusRunning {\n\t\t\t\tcombined = reporter.StatusRunning\n\t\t\t}\n\t\t}\n\n\t\treturn combined\n\t}()\n\n\treturn reporter.Update{\n\t\tMessage: combinedMessage,\n\t\tStatus:  combinedStatus,\n\t}\n}\n\n// getBootID reads the boot ID from the node.\n// It returns the node as the first return value and the boot ID as the second.\nfunc getBootID(ctx context.Context, c *client.Client) (string, error) {\n\treader, err := c.Read(ctx, \"/proc/sys/kernel/random/boot_id\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer reader.Close() //nolint:errcheck\n\n\tbody, err := io.ReadAll(reader)\n\tif err != nil {\n\t\tif status.Code(err) == codes.PermissionDenied { // we are not authorized to read the boot ID, skip the check\n\t\t\treturn unauthorizedBootIDFallback, nil\n\t\t}\n\n\t\treturn \"\", err\n\t}\n\n\tbootID := strings.TrimSpace(string(body))\n\n\treturn bootID, reader.Close()\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/artifacts/arch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage artifacts\n\n// Arch is the artifacts architecture.\ntype Arch string\n\n// Supported architectures.\nconst (\n\tArchAmd64 Arch = \"amd64\"\n\tArchArm64 Arch = \"arm64\"\n)\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/artifacts/fetch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package artifacts handles manifest traversal for Overalys and Extensions.\npackage artifacts\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/google/go-containerregistry/pkg/crane\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/remote\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/images\"\n)\n\ntype imageHandler func(ctx context.Context, img v1.Image) error\n\n// FetchTimeout controls overall timeout for fetching artifacts for a release.\nconst FetchTimeout = 20 * time.Minute\n\ntype fetchManager struct {\n\timageRegistry name.Registry\n\tpuller        *remote.Puller\n}\n\nfunc newManager() (*fetchManager, error) {\n\timageRegistry, err := name.NewRegistry(images.Registry)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create image registry: %w\", err)\n\t}\n\n\tpuller, err := remote.NewPuller(\n\t\tremote.WithPlatform(v1.Platform{\n\t\t\tArchitecture: string(ArchAmd64),\n\t\t\tOS:           \"linux\",\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create puller: %w\", err)\n\t}\n\n\treturn &fetchManager{\n\t\timageRegistry: imageRegistry,\n\t\tpuller:        puller,\n\t}, nil\n}\n\nfunc (m *fetchManager) fetchImageByTag(imageName, tag string, imageHandler imageHandler) error {\n\t// set a timeout for fetching, but don't bind it to any context, as we want fetch operation to finish\n\tctx, cancel := context.WithTimeout(context.Background(), FetchTimeout)\n\tdefer cancel()\n\n\t// light check first - if the image exists, and resolve the digest\n\t// it's important to do further checks by digest exactly\n\trepoRef := m.imageRegistry.Repo(imageName).Tag(tag)\n\n\tdescriptor, err := m.puller.Head(ctx, repoRef)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdigestRef := repoRef.Digest(descriptor.Digest.String())\n\n\treturn m.fetchImageByDigest(digestRef, imageHandler)\n}\n\n// fetchImageByDigest fetches an image by digest, verifies signatures, and exports it to the storage.\nfunc (m *fetchManager) fetchImageByDigest(digestRef name.Digest, imageHandler imageHandler) error {\n\tvar err error\n\n\t// set a timeout for fetching, but don't bind it to any context, as we want fetch operation to finish\n\tctx, cancel := context.WithTimeout(context.Background(), FetchTimeout)\n\tdefer cancel()\n\n\tdesc, err := m.puller.Get(ctx, digestRef)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error pulling image %s: %w\", digestRef, err)\n\t}\n\n\timg, err := desc.Image()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating image from descriptor: %w\", err)\n\t}\n\n\treturn imageHandler(ctx, img)\n}\n\n// imageExportHandler exports the image for further processing.\nfunc imageExportHandler(exportHandler func(r io.Reader) error) imageHandler {\n\treturn func(_ context.Context, img v1.Image) error {\n\t\tr, w := io.Pipe()\n\n\t\tvar eg errgroup.Group\n\n\t\teg.Go(func() error {\n\t\t\tdefer w.Close() //nolint:errcheck\n\n\t\t\treturn crane.Export(img, w)\n\t\t})\n\n\t\teg.Go(func() error {\n\t\t\terr := exportHandler(r)\n\t\t\tif err != nil {\n\t\t\t\tr.CloseWithError(err) // signal the exporter to stop\n\t\t\t}\n\n\t\t\treturn err\n\t\t})\n\n\t\tif err := eg.Wait(); err != nil {\n\t\t\treturn fmt.Errorf(\"error extracting the image: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/artifacts/images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage artifacts\n\nimport (\n\t\"archive/tar\"\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/images\"\n)\n\n// ExtensionRef is a ref to the extension for some Talos version.\ntype ExtensionRef struct {\n\tTaggedReference name.Tag\n\tDigest          string\n\tDescription     string\n\tAuthor          string\n\n\timageDigest string\n}\n\n// OverlayRef is a ref to the overlay for some Talos version.\ntype OverlayRef struct {\n\tName            string\n\tTaggedReference name.Tag\n\tDigest          string\n}\n\n// FetchOfficialExtensions fetches list of extensions for specific Talos version.\nfunc FetchOfficialExtensions(tag string) ([]ExtensionRef, error) {\n\tvar extensions []ExtensionRef\n\n\tm, err := newManager()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := m.fetchImageByTag(images.DefaultExtensionsManifestRepository, tag, imageExportHandler(func(r io.Reader) error {\n\t\tvar extractErr error\n\n\t\textensions, extractErr = extractExtensionList(r)\n\n\t\treturn extractErr\n\t})); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn extensions, nil\n}\n\n// FetchOfficialOverlays fetches list of overlays for specific Talos version.\nfunc FetchOfficialOverlays(tag string) ([]OverlayRef, error) {\n\tvar overlays []OverlayRef\n\n\tm, err := newManager()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := m.fetchImageByTag(images.DefaultOverlaysManifestRepository, tag, imageExportHandler(func(r io.Reader) error {\n\t\tvar extractErr error\n\n\t\toverlays, extractErr = extractOverlayList(r)\n\n\t\treturn extractErr\n\t})); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn overlays, nil\n}\n\ntype extensionsDescriptions map[string]struct {\n\tAuthor      string `yaml:\"author\"`\n\tDescription string `yaml:\"description\"`\n}\n\ntype overlaysDescriptions struct {\n\tOverlays []overlaysDescription `yaml:\"overlays\"`\n}\n\ntype overlaysDescription struct {\n\tName   string `yaml:\"name\"`\n\tImage  string `yaml:\"image\"`\n\tDigest string `yaml:\"digest\"`\n}\n\n//nolint:gocyclo\nfunc extractExtensionList(r io.Reader) ([]ExtensionRef, error) {\n\tvar extensions []ExtensionRef\n\n\ttr := tar.NewReader(r)\n\n\tvar descriptions extensionsDescriptions\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"error reading tar header: %w\", err)\n\t\t}\n\n\t\tif hdr.Name == \"descriptions.yaml\" {\n\t\t\tdecoder := yaml.NewDecoder(tr)\n\n\t\t\tif err = decoder.Decode(&descriptions); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error reading descriptions.yaml file: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif hdr.Name == \"image-digests\" {\n\t\t\tscanner := bufio.NewScanner(tr)\n\n\t\t\tfor scanner.Scan() {\n\t\t\t\tline := strings.TrimSpace(scanner.Text())\n\n\t\t\t\ttagged, digest, ok := strings.Cut(line, \"@\")\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ttaggedRef, err := name.NewTag(tagged)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to parse tagged reference %s: %w\", tagged, err)\n\t\t\t\t}\n\n\t\t\t\textensions = append(extensions, ExtensionRef{\n\t\t\t\t\tTaggedReference: taggedRef,\n\t\t\t\t\tDigest:          digest,\n\n\t\t\t\t\timageDigest: line,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif scanner.Err() != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error reading image-digests: %w\", scanner.Err())\n\t\t\t}\n\t\t}\n\t}\n\n\tif extensions != nil {\n\t\tif descriptions != nil {\n\t\t\tfor i, extension := range extensions {\n\t\t\t\tdesc, ok := descriptions[extension.imageDigest]\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\textensions[i].Author = desc.Author\n\t\t\t\textensions[i].Description = desc.Description\n\t\t\t}\n\t\t}\n\n\t\treturn extensions, nil\n\t}\n\n\treturn nil, errors.New(\"failed to find image-digests file\")\n}\n\nfunc extractOverlayList(r io.Reader) ([]OverlayRef, error) {\n\tvar overlays []OverlayRef\n\n\ttr := tar.NewReader(r)\n\n\tvar overlayInfo overlaysDescriptions\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"error reading tar header: %w\", err)\n\t\t}\n\n\t\tif hdr.Name == \"overlays.yaml\" {\n\t\t\tdecoder := yaml.NewDecoder(tr)\n\n\t\t\tif err = decoder.Decode(&overlayInfo); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error reading overlays.yaml file: %w\", err)\n\t\t\t}\n\n\t\t\tfor _, overlay := range overlayInfo.Overlays {\n\t\t\t\ttaggedRef, err := name.NewTag(overlay.Image)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to parse tagged reference %s: %w\", overlay.Image, err)\n\t\t\t\t}\n\n\t\t\t\toverlays = append(overlays, OverlayRef{\n\t\t\t\t\tName:            overlay.Name,\n\t\t\t\t\tTaggedReference: taggedRef,\n\t\t\t\t\tDigest:          overlay.Digest,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tif overlays != nil {\n\t\treturn overlays, nil\n\t}\n\n\treturn nil, errors.New(\"failed to find overlays.yaml file\")\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/global/client.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package global provides global flags for talosctl.\npackage global\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// Args is a context for the Talos command line client.\ntype Args struct {\n\tTalosconfig     string\n\tCmdContext      string\n\tCluster         string\n\tNodes           []string\n\tEndpoints       []string\n\tSideroV1KeysDir string\n}\n\n// NodeList returns the list of nodes to run the command against.\nfunc (c *Args) NodeList() []string {\n\treturn c.Nodes\n}\n\n// WithClientNoNodes wraps common code to initialize Talos client and provide cancellable context.\n//\n// WithClientNoNodes doesn't set any node information on the request context.\nfunc (c *Args) WithClientNoNodes(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error {\n\treturn cli.WithContext(\n\t\tcontext.Background(), func(ctx context.Context) error {\n\t\t\tcfg, err := clientconfig.Open(c.Talosconfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to open config file %q: %w\", c.Talosconfig, err)\n\t\t\t}\n\n\t\t\topts := []client.OptionFunc{\n\t\t\t\tclient.WithConfig(cfg),\n\t\t\t\tclient.WithDefaultGRPCDialOptions(),\n\t\t\t\tclient.WithGRPCDialOptions(dialOptions...),\n\t\t\t\tclient.WithSideroV1KeysDir(clientconfig.CustomSideroV1KeysDirPath(c.SideroV1KeysDir)),\n\t\t\t}\n\n\t\t\tif c.CmdContext != \"\" {\n\t\t\t\topts = append(opts, client.WithContextName(c.CmdContext))\n\t\t\t}\n\n\t\t\tif len(c.Endpoints) > 0 {\n\t\t\t\t// override endpoints from command-line flags\n\t\t\t\topts = append(opts, client.WithEndpoints(c.Endpoints...))\n\t\t\t}\n\n\t\t\tif c.Cluster != \"\" {\n\t\t\t\topts = append(opts, client.WithCluster(c.Cluster))\n\t\t\t}\n\n\t\t\tc, err := client.New(ctx, opts...)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error constructing client: %w\", err)\n\t\t\t}\n\t\t\t//nolint:errcheck\n\t\t\tdefer c.Close()\n\n\t\t\treturn action(ctx, c)\n\t\t},\n\t)\n}\n\n// ErrConfigContext is returned when config context cannot be resolved.\nvar ErrConfigContext = errors.New(\"failed to resolve config context\")\n\nfunc (c *Args) getNodes(cli *client.Client) ([]string, error) {\n\tif len(c.Nodes) < 1 {\n\t\tconfigContext := cli.GetConfigContext()\n\t\tif configContext == nil {\n\t\t\treturn nil, ErrConfigContext\n\t\t}\n\n\t\tc.Nodes = configContext.Nodes\n\t}\n\n\tif len(c.Nodes) < 1 {\n\t\treturn nil, errors.New(\"nodes are not set for the command: please use `--nodes` flag or configuration file to set the nodes to run the command against\")\n\t}\n\n\treturn c.Nodes, nil\n}\n\n// WithClient builds upon WithClientNoNodes to provide set of nodes on request context based on config & flags.\nfunc (c *Args) WithClient(action func(context.Context, *client.Client) error, dialOptions ...grpc.DialOption) error {\n\treturn c.WithClientNoNodes(\n\t\tfunc(ctx context.Context, cli *client.Client) error {\n\t\t\tnodes, err := c.getNodes(cli)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tctx = client.WithNodes(ctx, nodes...)\n\n\t\t\treturn action(ctx, cli)\n\t\t},\n\t\tdialOptions...,\n\t)\n}\n\n// WithClientAndNodes builds upon WithClientNoNodes to provide a list of nodes to the function.\nfunc (c *Args) WithClientAndNodes(action func(context.Context, *client.Client, []string) error, dialOptions ...grpc.DialOption) error {\n\treturn c.WithClientNoNodes(\n\t\tfunc(ctx context.Context, cli *client.Client) error {\n\t\t\tnodes, err := c.getNodes(cli)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn action(ctx, cli, nodes)\n\t\t},\n\t\tdialOptions...,\n\t)\n}\n\n// WithClientMaintenance wraps common code to initialize Talos client in maintenance (insecure mode).\nfunc (c *Args) WithClientMaintenance(enforceFingerprints []string, action func(context.Context, *client.Client) error) error {\n\treturn cli.WithContext(\n\t\tcontext.Background(), func(ctx context.Context) error {\n\t\t\ttlsConfig := &tls.Config{\n\t\t\t\tInsecureSkipVerify: true,\n\t\t\t}\n\n\t\t\tif len(enforceFingerprints) > 0 {\n\t\t\t\tfingerprints := make([]x509.Fingerprint, len(enforceFingerprints))\n\n\t\t\t\tfor i, stringFingerprint := range enforceFingerprints {\n\t\t\t\t\tvar err error\n\n\t\t\t\t\tfingerprints[i], err = x509.ParseFingerprint(stringFingerprint)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error parsing certificate fingerprint %q: %v\", stringFingerprint, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttlsConfig.VerifyConnection = x509.MatchSPKIFingerprints(fingerprints...)\n\t\t\t}\n\n\t\t\tc, err := client.New(ctx, client.WithTLSConfig(tlsConfig), client.WithEndpoints(c.Nodes...))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t//nolint:errcheck\n\t\t\tdefer c.Close()\n\n\t\t\treturn action(ctx, c)\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/archive.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"archive/tar\"\n\t\"compress/gzip\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/safepath\"\n)\n\n// ExtractFileFromTarGz reads a single file data from an archive.\nfunc ExtractFileFromTarGz(filename string, r io.ReadCloser) ([]byte, error) {\n\tdefer r.Close() //nolint:errcheck\n\n\tzr, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error initializing gzip: %w\", err)\n\t}\n\n\ttr := tar.NewReader(zr)\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\thdrPath := safepath.CleanPath(hdr.Name)\n\t\tif hdrPath == \"\" {\n\t\t\treturn nil, errors.New(\"empty tar header path\")\n\t\t}\n\n\t\tif hdrPath == filename {\n\t\t\tif hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeSymlink {\n\t\t\t\treturn nil, fmt.Errorf(\"%s is not a file\", filename)\n\t\t\t}\n\n\t\t\treturn io.ReadAll(tr)\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"couldn't find file %s in the archive\", filename)\n}\n\n// ExtractTarGz extracts .tar.gz archive from r into filesystem under localPath.\n//\n//nolint:gocyclo\nfunc ExtractTarGz(localPath string, r io.ReadCloser) error {\n\tdefer r.Close() //nolint:errcheck\n\n\tzr, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing gzip: %w\", err)\n\t}\n\n\ttr := tar.NewReader(zr)\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error reading tar header: %s\", err)\n\t\t}\n\n\t\thdrPath := safepath.CleanPath(hdr.Name)\n\t\tif hdrPath == \"\" {\n\t\t\treturn errors.New(\"empty tar header path\")\n\t\t}\n\n\t\tpath := filepath.Join(localPath, hdrPath)\n\t\t// TODO: do we need to clean up any '..' references?\n\n\t\tswitch hdr.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tmode := hdr.FileInfo().Mode()\n\t\t\tmode |= 0o700 // make rwx for the owner\n\n\t\t\tif err = os.Mkdir(path, mode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating directory %q mode %s: %w\", path, mode, err)\n\t\t\t}\n\n\t\t\tif err = os.Chmod(path, mode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating mode %s for %q: %w\", mode, path, err)\n\t\t\t}\n\n\t\tcase tar.TypeSymlink:\n\t\t\tif err = os.Symlink(hdr.Linkname, path); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating symlink %q -> %q: %w\", path, hdr.Linkname, err)\n\t\t\t}\n\n\t\tdefault:\n\t\t\tmode := hdr.FileInfo().Mode()\n\n\t\t\tfp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_EXCL, mode)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating file %q mode %s: %w\", path, mode, err)\n\t\t\t}\n\n\t\t\t_, err = io.Copy(fp, tr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying data to %q: %w\", path, err)\n\t\t\t}\n\n\t\t\tif err = fp.Close(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error closing %q: %w\", path, err)\n\t\t\t}\n\n\t\t\tif err = os.Chmod(path, mode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating mode %s for %q: %w\", mode, path, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/checks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// FailIfMultiNodes checks if ctx contains multi-node request metadata.\nfunc FailIfMultiNodes(ctx context.Context, command string) error {\n\tmd, ok := metadata.FromOutgoingContext(ctx)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif len(md.Get(\"nodes\")) <= 1 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"command %q is not supported with multiple nodes\", command)\n}\n\n// CheckErrors goes through the returned message list and checks if any messages have errors set.\nfunc CheckErrors[T interface{ GetMetadata() *common.Metadata }](messages ...T) error {\n\tvar err error\n\n\tfor _, msg := range messages {\n\t\tmd := msg.GetMetadata()\n\t\tif md != nil && md.Error != \"\" {\n\t\t\terr = AppendErrors(err, errors.New(md.Error))\n\t\t}\n\t}\n\n\treturn err\n}\n\n// VersionOutsideRangeError is returned when a node is running a Talos version that is outside the desired range.\ntype VersionOutsideRangeError struct{}\n\n// TalosVersionCheck verifies that all nodes are running the desired Talos version.\nfunc TalosVersionCheck(ctx context.Context, c *client.Client, desired semver.Range) error {\n\tserverVersions, err := c.Version(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting server versions: %w\", err)\n\t}\n\n\tvar errs error\n\n\tfor _, msg := range serverVersions.GetMessages() {\n\t\tnode := msg.GetMetadata().GetHostname()\n\n\t\tserverVersion, err := semver.ParseTolerant(msg.GetVersion().Tag)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s: error parsing server version: %w\", node, err)\n\t\t}\n\n\t\tif !desired(serverVersion) {\n\t\t\terrs = errors.Join(errs, xerrors.NewTaggedf[VersionOutsideRangeError](\"%s: server version %s is outside the desired range\", node, serverVersion))\n\t\t}\n\t}\n\n\treturn errs\n}\n\n// ClientVersionCheck verifies that client is not outdated vs. Talos version.\nfunc ClientVersionCheck(ctx context.Context, c *client.Client) error {\n\t// ignore the error, as we are only interested in the nodes which respond\n\tserverVersions, _ := c.Version(ctx) //nolint:errcheck\n\n\tclientVersion, err := semver.ParseTolerant(version.NewVersion().Tag)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing client version: %w\", err)\n\t}\n\n\tvar warnings []string\n\n\tfor _, msg := range serverVersions.GetMessages() {\n\t\tnode := msg.GetMetadata().GetHostname()\n\n\t\tserverVersion, err := semver.ParseTolerant(msg.GetVersion().Tag)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s: error parsing server version: %w\", node, err)\n\t\t}\n\n\t\tif serverVersion.Compare(clientVersion) < 0 {\n\t\t\twarnings = append(warnings, fmt.Sprintf(\"%s: server version %s is older than client version %s\", node, serverVersion, clientVersion))\n\t\t}\n\t}\n\n\tif warnings != nil {\n\t\tfmt.Fprintf(os.Stderr, \"WARNING: %s\\n\", strings.Join(warnings, \", \"))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/confirm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar okays = []string{\"y\", \"yes\"}\n\n// Confirm asks the user to confirm their action. Anything other than\n// `y` and `yes` returns false.\nfunc Confirm(prompt string) bool {\n\tvar inp string\n\n\tfmt.Printf(\"%s (y/N): \", prompt)\n\tfmt.Scanf(\"%s\", &inp) //nolint:errcheck\n\tinp = strings.TrimSpace(inp)\n\n\tfor _, ok := range okays {\n\t\tif strings.EqualFold(inp, ok) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/error.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/gertd/go-pluralize\"\n\t\"github.com/hashicorp/go-multierror\"\n)\n\n// AppendErrors adds errors to the multierr wrapper.\nfunc AppendErrors(err error, errs ...error) error {\n\tres := multierror.Append(err, errs...)\n\n\tres.ErrorFormat = func(errs []error) string {\n\t\tlines := make([]string, 0, len(errs))\n\n\t\tfor _, err := range errs {\n\t\t\tlines = append(lines, fmt.Sprintf(\" %s\", err.Error()))\n\t\t}\n\n\t\tcount := pluralize.NewClient().Pluralize(\"error\", len(lines), true)\n\n\t\treturn color.RedString(fmt.Sprintf(\"%s occurred:\\n%s\", count, strings.Join(lines, \"\\n\")))\n\t}\n\n\treturn res\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/helpers_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n)\n\ntype cfg struct {\n\tAPIVersion string `yaml:\"apiVersion\"`\n\tKind       string `yaml:\"kind\"`\n}\n\nfunc TestExtractFileFromTarGz(t *testing.T) {\n\tfile, err := os.Open(\"./testdata/archive.tar.gz\")\n\tassert.NoError(t, err)\n\n\tdata, err := helpers.ExtractFileFromTarGz(\"kubeconfig\", file)\n\tassert.NoError(t, err)\n\n\t// just some primitive sanity check that yaml file inside was not corrupted somehow\n\tvar c cfg\n\n\terr = yaml.Unmarshal(data, &c)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, c.APIVersion, \"v1\")\n\tassert.Equal(t, c.Kind, \"Config\")\n\n\t_, err = helpers.ExtractFileFromTarGz(\"void\", file)\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/labels.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n)\n\n// FormatLabels formats labels as a comma-separated key=value pairs.\nfunc FormatLabels(labels map[string]string) string {\n\tif len(labels) == 0 {\n\t\treturn \"\"\n\t}\n\n\tkeys := maps.Keys(labels)\n\tslices.Sort(keys)\n\n\tvar sb strings.Builder\n\n\tfor i, k := range keys {\n\t\tif i > 0 {\n\t\t\tsb.WriteString(\",\")\n\t\t}\n\n\t\tsb.WriteString(k)\n\t\tsb.WriteString(\"=\")\n\t\tsb.WriteString(labels[k])\n\t}\n\n\treturn sb.String()\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/mode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/pkg/cli\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// Mode apply, patch, edit config update mode.\ntype Mode struct {\n\toptions map[string]machine.ApplyConfigurationRequest_Mode\n\tMode    machine.ApplyConfigurationRequest_Mode\n}\n\nfunc (m Mode) String() string {\n\tswitch m.Mode {\n\tcase machine.ApplyConfigurationRequest_TRY:\n\t\treturn modeTry\n\tcase machine.ApplyConfigurationRequest_AUTO:\n\t\treturn modeAuto\n\tcase machine.ApplyConfigurationRequest_NO_REBOOT:\n\t\treturn modeNoReboot\n\tcase machine.ApplyConfigurationRequest_REBOOT:\n\t\treturn modeReboot\n\tcase machine.ApplyConfigurationRequest_STAGED:\n\t\treturn modeStaged\n\tdefault:\n\t\treturn modeAuto\n\t}\n}\n\n// Set implements Flag interface.\nfunc (m *Mode) Set(value string) error {\n\tmode, ok := m.options[value]\n\tif !ok {\n\t\treturn fmt.Errorf(\"possible options are: %s\", m.Type())\n\t}\n\n\tm.Mode = mode\n\n\treturn nil\n}\n\n// Type implements Flag interface.\nfunc (m *Mode) Type() string {\n\toptions := maps.Keys(m.options)\n\tslices.Sort(options)\n\n\treturn strings.Join(options, \", \")\n}\n\nconst (\n\tmodeAuto     = \"auto\"\n\tmodeNoReboot = \"no-reboot\"\n\tmodeReboot   = \"reboot\"\n\tmodeStaged   = \"staged\"\n\tmodeTry      = \"try\"\n)\n\n// AddModeFlags adds deprecated flags to the command and registers mode flag with it's parser.\nfunc AddModeFlags(mode *Mode, command *cobra.Command) {\n\tmodes := map[string]machine.ApplyConfigurationRequest_Mode{\n\t\tmodeAuto:     machine.ApplyConfigurationRequest_AUTO,\n\t\tmodeNoReboot: machine.ApplyConfigurationRequest_NO_REBOOT,\n\t\tmodeReboot:   machine.ApplyConfigurationRequest_REBOOT,\n\t\tmodeStaged:   machine.ApplyConfigurationRequest_STAGED,\n\t\tmodeTry:      machine.ApplyConfigurationRequest_TRY,\n\t}\n\n\tmode.Mode = machine.ApplyConfigurationRequest_AUTO\n\tmode.options = modes\n\n\tcommand.Flags().VarP(mode, \"mode\", \"m\", \"apply config mode\")\n}\n\n// PrintApplyResults prints out all warnings and auto apply results.\nfunc PrintApplyResults(resp *machine.ApplyConfigurationResponse) {\n\tfor _, m := range resp.GetMessages() {\n\t\tfor _, w := range m.GetWarnings() {\n\t\t\tcli.Warning(\"%s\", w)\n\t\t}\n\n\t\tif m.ModeDetails != \"\" {\n\t\t\tfmt.Fprintln(os.Stderr, m.ModeDetails)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/resources.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// ForEachResource gets resources from the controller runtime and runs a callback for each resource.\n//\n//nolint:gocyclo\nfunc ForEachResource(ctx context.Context,\n\tc *client.Client,\n\tcallbackRD func(rd *meta.ResourceDefinition) error,\n\tcallback func(ctx context.Context, hostname string, r resource.Resource, callError error) error,\n\tnamespace string,\n\targs ...string,\n) error {\n\tif len(args) == 0 {\n\t\treturn errors.New(\"not enough arguments: at least 1 is expected\")\n\t}\n\n\tresourceType := args[0]\n\n\tvar resourceID string\n\n\tif len(args) > 1 {\n\t\tresourceID = args[1]\n\t}\n\n\tmd, _ := metadata.FromOutgoingContext(ctx)\n\tnodes := md.Get(\"nodes\")\n\n\tif len(nodes) == 0 {\n\t\tnodes = []string{\"\"}\n\t}\n\n\t// fetch the RD from the first node (it doesn't matter which one to use, so we'll use the first one)\n\trd, err := c.ResolveResourceKind(client.WithNode(ctx, nodes[0]), &namespace, resourceType)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif callbackRD != nil {\n\t\tif err = callbackRD(rd); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tresourceType = rd.TypedSpec().Type\n\n\tfor _, node := range nodes {\n\t\tvar nodeCtx context.Context\n\n\t\tif node == \"\" {\n\t\t\tnodeCtx = ctx\n\t\t} else {\n\t\t\tnodeCtx = client.WithNode(ctx, node)\n\t\t}\n\n\t\tif resourceID != \"\" {\n\t\t\tr, callErr := c.COSI.Get(\n\t\t\t\tnodeCtx,\n\t\t\t\tresource.NewMetadata(namespace, rd.TypedSpec().Type, resourceID, resource.VersionUndefined),\n\t\t\t\tstate.WithGetUnmarshalOptions(state.WithSkipProtobufUnmarshal()),\n\t\t\t)\n\t\t\tif err = callback(ctx, node, r, callErr); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\titems, callErr := c.COSI.List(\n\t\t\t\tnodeCtx,\n\t\t\t\tresource.NewMetadata(namespace, resourceType, \"\", resource.VersionUndefined),\n\t\t\t\tstate.WithListUnmarshalOptions(state.WithSkipProtobufUnmarshal()),\n\t\t\t)\n\t\t\tif callErr != nil {\n\t\t\t\tif err = callback(ctx, node, nil, callErr); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, r := range items.Items {\n\t\t\t\tif err = callback(ctx, node, r, nil); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/helpers/stream.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage helpers\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// Stream implements the contract for the grpc stream of a specific type.\ntype Stream[T proto.Message] interface {\n\tRecv() (T, error)\n\tgrpc.ClientStream\n}\n\n// Message defines the contract for the grpc message.\ntype Message interface {\n\tGetMetadata() *common.Metadata\n\tproto.Message\n}\n\n// ReadGRPCStream consumes all messages from the gRPC stream, handles errors, calls the passed handler for each message.\nfunc ReadGRPCStream[S Stream[T], T Message](stream S, handler func(T, string, bool) error) error {\n\tvar streamErrs error\n\n\tdefaultNode := client.RemotePeer(stream.Context())\n\n\tmultipleNodes := false\n\n\tfor {\n\t\tinfo, err := stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\treturn streamErrs\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error streaming results: %s\", err)\n\t\t}\n\n\t\tnode := defaultNode\n\n\t\tif info.GetMetadata() != nil {\n\t\t\tif info.GetMetadata().Hostname != \"\" {\n\t\t\t\tmultipleNodes = true\n\t\t\t\tnode = info.GetMetadata().Hostname\n\t\t\t}\n\n\t\t\tif info.GetMetadata().Error != \"\" {\n\t\t\t\tstreamErrs = AppendErrors(streamErrs, errors.New(info.GetMetadata().Error))\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif err = handler(info, node, multipleNodes); err != nil {\n\t\t\tvar errNonFatal *ErrNonFatalError\n\t\t\tif errors.As(err, &errNonFatal) {\n\t\t\t\tstreamErrs = AppendErrors(streamErrs, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// ErrNonFatalError represents the error that can be returned from the handler in the gRPC stream reader\n// which doesn't mean that we should stop iterating over the messages in the stream, but log this error\n// and continue the process.\ntype ErrNonFatalError struct {\n\terr error\n}\n\n// Error implements error interface.\nfunc (e *ErrNonFatalError) Error() string {\n\treturn e.err.Error()\n}\n\n// NonFatalError wraps another error into a ErrNonFatal.\nfunc NonFatalError(err error) error {\n\treturn &ErrNonFatalError{\n\t\terr: err,\n\t}\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/testdata/malformed.in.yaml",
    "content": "data:\n  # This is a comment\n  some:\n    other: a: b: c\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/testdata/malformed.out.yaml",
    "content": "data:\n  some:\n    other: a: b: c\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/testdata/multidoc.in.yaml",
    "content": "# siderolink config\napiVersion: v1alpha1\nkind: SideroLinkConfig # kind of the document\n# apiUrl is the URL of the SideroLink API endpoint\napiUrl: grpc://172.20.0.1:4000/?jointoken=foo\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink # named document\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\noptions: # options are optional\n  # more options\n  foo: bar # this option\n---\napiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: \"[fdae:41e4:649b:9303::1]:8080\"\n# end of document\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/testdata/multidoc.out.yaml",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: grpc://172.20.0.1:4000/?jointoken=foo\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\noptions:\n    foo: bar\n---\napiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: \"[fdae:41e4:649b:9303::1]:8080\"\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/yamlstrip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package yamlstrip provides YAML file manipulation.\npackage yamlstrip\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\n\t\"go.yaml.in/yaml/v4\"\n)\n\n// Comments strips comments from a YAML file.\n//\n// If the YAML file is parseable, it will be accurately stripped. Otherwise, it\n// will be stripped in a best-effort manner.\nfunc Comments(b []byte) []byte {\n\tstripped, err := stripViaDecoding(b)\n\tif err != nil {\n\t\tstripped = stripManual(b)\n\t}\n\n\treturn stripped\n}\n\nfunc stripViaDecoding(b []byte) ([]byte, error) {\n\tvar out bytes.Buffer\n\n\tdecoder := yaml.NewDecoder(bytes.NewReader(b))\n\tencoder := yaml.NewEncoder(&out)\n\n\tfor {\n\t\tvar node yaml.Node\n\n\t\terr := decoder.Decode(&node)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tremoveComments(&node)\n\n\t\tif err = encoder.Encode(&node); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn out.Bytes(), nil\n}\n\nfunc removeComments(node *yaml.Node) {\n\tnode.FootComment = \"\"\n\tnode.HeadComment = \"\"\n\tnode.LineComment = \"\"\n\n\tfor _, child := range node.Content {\n\t\tremoveComments(child)\n\t}\n}\n\nfunc stripManual(b []byte) []byte {\n\tvar stripped []byte\n\n\tlines := bytes.Split(b, []byte(\"\\n\"))\n\n\tfor i, line := range lines {\n\t\ttrimline := bytes.TrimSpace(line)\n\n\t\t// this is not accurate, but best effort\n\t\tif bytes.HasPrefix(trimline, []byte(\"#\")) && !bytes.HasPrefix(trimline, []byte(\"#!\")) {\n\t\t\tcontinue\n\t\t}\n\n\t\tstripped = append(stripped, line...)\n\n\t\tif i < len(lines)-1 {\n\t\t\tstripped = append(stripped, '\\n')\n\t\t}\n\t}\n\n\treturn stripped\n}\n"
  },
  {
    "path": "cmd/talosctl/pkg/talos/yamlstrip/yamlstrip_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage yamlstrip_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/yamlstrip\"\n)\n\nfunc TestComments(t *testing.T) {\n\ttestCases, err := filepath.Glob(filepath.Join(\"testdata\", \"*.in.yaml\"))\n\trequire.NoError(t, err)\n\n\tfor _, path := range testCases {\n\t\tt.Run(filepath.Base(path), func(t *testing.T) {\n\t\t\tin, err := os.ReadFile(path)\n\t\t\trequire.NoError(t, err)\n\n\t\t\texpected, err := os.ReadFile(strings.ReplaceAll(path, \".in.yaml\", \".out.yaml\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tout := yamlstrip.Comments(in)\n\t\t\trequire.Equal(t, string(expected), string(out))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/siderolabs/talos\n\ngo 1.26.1\n\nreplace (\n\t// forked coredns so we don't carry caddy and other stuff into the Talos\n\tgithub.com/coredns/coredns => github.com/siderolabs/coredns v1.14.53\n\n\t// see https://github.com/jsimonetti/rtnetlink/pull/306\n\tgithub.com/jsimonetti/rtnetlink/v2 => github.com/shanduur/rtnetlink/v2 v2.0.0-20260313131132-118a2ded4751\n\n\t// forked ethtool introduces missing APIs\n\tgithub.com/mdlayher/ethtool => github.com/siderolabs/ethtool v0.4.0-sidero\n\n\t// see https://github.com/mdlayher/kobject/pull/5\n\tgithub.com/mdlayher/kobject => github.com/smira/kobject v0.0.0-20240304111826-49c8d4613389\n\n\t// Use nested module.\n\tgithub.com/siderolabs/talos/pkg/machinery => ./pkg/machinery\n\n\t// fork to add Talos-specific userspace socket location: https://github.com/siderolabs/talos/issues/8514\n\tgolang.zx2c4.com/wireguard/wgctrl => github.com/siderolabs/wgctrl-go v0.0.0-20251029173431-c4fd5f6a4e72\n)\n\n// deadcode elimination fix replacement: https://github.com/siderolabs/talos/issues/11296\n// upstream PR: https://github.com/containerd/containerd/pull/12175\n// this a fork with containerd 2.2 branch + the commit from the PR above\nreplace github.com/containerd/containerd/v2 => github.com/smira/containerd/v2 v2.2.3-0.20260311174942-e5fa687ba763\n\n// Kubernetes dependencies sharing the same version.\nrequire (\n\tk8s.io/api v0.35.2\n\tk8s.io/apiextensions-apiserver v0.35.2\n\tk8s.io/apimachinery v0.35.2\n\tk8s.io/apiserver v0.35.2\n\tk8s.io/client-go v0.35.2\n\tk8s.io/component-base v0.35.2\n\tk8s.io/cri-api v0.35.2\n\tk8s.io/kube-scheduler v0.35.2\n\tk8s.io/kubectl v0.35.2\n\tk8s.io/kubelet v0.35.2\n\tk8s.io/pod-security-admission v0.35.2\n)\n\nrequire (\n\tcloud.google.com/go/compute/metadata v0.9.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1\n\tgithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.4.0\n\tgithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0\n\tgithub.com/alexflint/go-filemutex v1.3.0\n\tgithub.com/aws/aws-sdk-go-v2/config v1.32.12\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20\n\tgithub.com/aws/aws-sdk-go-v2/service/acm v1.37.22\n\tgithub.com/aws/aws-sdk-go-v2/service/kms v1.50.3\n\tgithub.com/aws/smithy-go v1.24.2\n\tgithub.com/beevik/ntp v1.5.0\n\tgithub.com/blang/semver/v4 v4.0.0\n\tgithub.com/cenkalti/backoff/v4 v4.3.0\n\tgithub.com/containerd/cgroups/v3 v3.1.3\n\tgithub.com/containerd/containerd/api v1.10.0\n\tgithub.com/containerd/containerd/v2 v2.2.2\n\tgithub.com/containerd/errdefs v1.0.0\n\tgithub.com/containerd/log v0.1.0\n\tgithub.com/containerd/platforms v1.0.0-rc.2\n\tgithub.com/containerd/typeurl/v2 v2.2.3\n\tgithub.com/containernetworking/cni v1.3.0\n\tgithub.com/containernetworking/plugins v1.9.0\n\tgithub.com/coredns/coredns v1.14.2\n\tgithub.com/coreos/go-iptables v0.8.0\n\tgithub.com/cosi-project/runtime v1.14.0\n\tgithub.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e\n\tgithub.com/distribution/reference v0.6.0\n\tgithub.com/docker/cli v29.3.0+incompatible\n\tgithub.com/dustin/go-humanize v1.0.1\n\tgithub.com/elastic/go-libaudit/v2 v2.6.2\n\tgithub.com/equinix-ms/go-vmw-guestrpc v1.0.0\n\tgithub.com/fatih/color v1.18.0\n\tgithub.com/florianl/go-tc v0.4.7\n\tgithub.com/foxboron/go-uefi v0.0.0-20251010190908-d29549a44f29\n\tgithub.com/freddierice/go-losetup/v2 v2.0.1\n\tgithub.com/fsnotify/fsnotify v1.9.0\n\tgithub.com/g0rbe/go-chattr v1.0.1\n\tgithub.com/gdamore/tcell/v2 v2.13.8\n\tgithub.com/gertd/go-pluralize v0.2.1\n\tgithub.com/godbus/dbus/v5 v5.2.2\n\tgithub.com/golang/mock v1.7.0-rc.1\n\tgithub.com/google/cadvisor v0.56.2\n\tgithub.com/google/cel-go v0.27.0\n\tgithub.com/google/go-containerregistry v0.21.2\n\tgithub.com/google/go-tpm v0.9.8\n\tgithub.com/google/nftables v0.3.0\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/gopacket/gopacket v1.5.0\n\tgithub.com/gosuri/uiprogress v0.0.1\n\tgithub.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2\n\tgithub.com/hashicorp/go-envparse v0.1.0\n\tgithub.com/hashicorp/go-getter/v2 v2.2.3\n\tgithub.com/hashicorp/go-multierror v1.1.1\n\tgithub.com/hetznercloud/hcloud-go/v2 v2.36.0\n\tgithub.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91\n\tgithub.com/jeromer/syslogparser v1.1.0\n\tgithub.com/jsimonetti/rtnetlink/v2 v2.2.0\n\tgithub.com/jxskiss/base62 v1.1.0\n\tgithub.com/klauspost/compress v1.18.4\n\tgithub.com/klauspost/cpuid/v2 v2.3.0\n\tgithub.com/linode/go-metadata v0.2.4\n\tgithub.com/martinlindhe/base36 v1.1.1\n\tgithub.com/mattn/go-isatty v0.0.20\n\tgithub.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875\n\tgithub.com/mdlayher/ethtool v0.5.1\n\tgithub.com/mdlayher/genetlink v1.3.2\n\tgithub.com/mdlayher/kobject v0.0.0-20200520190114-19ca17470d7d\n\tgithub.com/mdlayher/netlink v1.9.0\n\tgithub.com/mdlayher/netx v0.0.0-20230430222610-7e21880baee8\n\tgithub.com/mdp/qrterminal/v3 v3.2.1\n\tgithub.com/miekg/dns v1.1.72\n\tgithub.com/moby/moby/api v1.54.0\n\tgithub.com/moby/moby/client v0.3.0\n\tgithub.com/navidys/tvxwidgets v0.13.0\n\tgithub.com/nberlee/go-netstat v0.1.2\n\tgithub.com/opencontainers/go-digest v1.0.0\n\tgithub.com/opencontainers/image-spec v1.1.1\n\tgithub.com/opencontainers/runtime-spec v1.3.0\n\tgithub.com/packethost/packngo v0.31.0\n\tgithub.com/pelletier/go-toml/v2 v2.2.4\n\tgithub.com/pin/tftp/v3 v3.2.0\n\tgithub.com/pkg/xattr v0.4.12\n\tgithub.com/pmorjan/kmod v1.1.1\n\tgithub.com/prometheus/procfs v0.20.1\n\tgithub.com/rivo/tview v0.42.0\n\tgithub.com/rs/xid v1.6.0\n\tgithub.com/ryanuber/columnize v2.1.2+incompatible\n\tgithub.com/ryanuber/go-glob v1.0.0\n\tgithub.com/safchain/ethtool v0.7.0\n\tgithub.com/scaleway/scaleway-sdk-go v1.0.0-beta.36\n\tgithub.com/siderolabs/crypto v0.6.4\n\tgithub.com/siderolabs/discovery-api v0.1.8\n\tgithub.com/siderolabs/discovery-client v0.1.15\n\tgithub.com/siderolabs/gen v0.8.6\n\tgithub.com/siderolabs/go-api-signature v0.3.12\n\tgithub.com/siderolabs/go-blockdevice/v2 v2.0.26\n\tgithub.com/siderolabs/go-circular v0.2.3\n\tgithub.com/siderolabs/go-cmd v0.2.0\n\tgithub.com/siderolabs/go-copy v0.1.0\n\tgithub.com/siderolabs/go-debug v0.6.2\n\tgithub.com/siderolabs/go-kmsg v0.1.5\n\tgithub.com/siderolabs/go-kubeconfig v0.1.1\n\tgithub.com/siderolabs/go-kubernetes v0.2.33\n\tgithub.com/siderolabs/go-loadbalancer v0.5.0\n\tgithub.com/siderolabs/go-pcidb v0.3.3\n\tgithub.com/siderolabs/go-pointer v1.0.1\n\tgithub.com/siderolabs/go-procfs v0.1.2\n\tgithub.com/siderolabs/go-retry v0.3.3\n\tgithub.com/siderolabs/go-smbios v0.3.3\n\tgithub.com/siderolabs/go-tail v0.1.1\n\tgithub.com/siderolabs/go-talos-support v0.1.4\n\tgithub.com/siderolabs/grpc-proxy v0.5.1\n\tgithub.com/siderolabs/kms-client v0.2.0\n\tgithub.com/siderolabs/net v0.4.0\n\tgithub.com/siderolabs/proto-codec v0.1.3\n\tgithub.com/siderolabs/siderolink v0.3.15\n\tgithub.com/siderolabs/talos/pkg/machinery v1.13.0-alpha.2\n\tgithub.com/sigstore/cosign/v3 v3.0.5\n\tgithub.com/sigstore/sigstore v1.10.5-0.20260304232115-b56c8664d026\n\tgithub.com/sigstore/sigstore-go v1.1.4\n\tgithub.com/sirupsen/logrus v1.9.4\n\tgithub.com/spf13/cobra v1.10.2\n\tgithub.com/spf13/pflag v1.0.10\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/thejerf/suture/v4 v4.0.6\n\tgithub.com/theupdateframework/go-tuf/v2 v2.4.1\n\tgithub.com/u-root/u-root v0.16.0\n\tgithub.com/ulikunitz/xz v0.5.15\n\tgithub.com/vultr/metadata v1.1.0\n\tgo.etcd.io/etcd/api/v3 v3.6.8\n\tgo.etcd.io/etcd/client/pkg/v3 v3.6.8\n\tgo.etcd.io/etcd/client/v3 v3.6.8\n\tgo.etcd.io/etcd/etcdutl/v3 v3.6.8\n\tgo.uber.org/goleak v1.3.0\n\tgo.uber.org/zap v1.27.1\n\tgo.yaml.in/yaml/v4 v4.0.0-rc.4\n\tgo4.org/netipx v0.0.0-20231129151722-fdeea329fbba\n\tgolang.org/x/net v0.52.0\n\tgolang.org/x/oauth2 v0.36.0\n\tgolang.org/x/sync v0.20.0\n\tgolang.org/x/sys v0.42.0\n\tgolang.org/x/term v0.41.0\n\tgolang.org/x/text v0.35.0\n\tgolang.org/x/time v0.15.0\n\tgolang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10\n\tgoogle.golang.org/grpc v1.79.3\n\tgoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af\n\tgopkg.in/typ.v4 v4.4.0\n\tk8s.io/klog/v2 v2.140.0\n\tkernel.org/pub/linux/libs/security/libcap/cap v1.2.77\n\tsigs.k8s.io/hydrophone v0.7.0\n)\n\nrequire (\n\tal.essio.dev/pkg/shellescape v1.6.0 // indirect\n\tcel.dev/expr v0.25.1 // indirect\n\tcyphar.com/go-pathrs v0.2.1 // indirect\n\tgithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect\n\tgithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect\n\tgithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect\n\tgithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect\n\tgithub.com/MakeNowJust/heredoc v1.0.0 // indirect\n\tgithub.com/Microsoft/go-winio v0.6.2 // indirect\n\tgithub.com/Microsoft/hcsshim v0.14.0-rc.1 // indirect\n\tgithub.com/ProtonMail/go-crypto v1.3.0 // indirect\n\tgithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect\n\tgithub.com/ProtonMail/gopenpgp/v2 v2.9.0 // indirect\n\tgithub.com/adrg/xdg v0.5.3 // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.1 // indirect\n\tgithub.com/apparentlymart/go-cidr v1.1.0 // indirect\n\tgithub.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect\n\tgithub.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect\n\tgithub.com/aws/aws-sdk-go-v2 v1.41.4 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect\n\tgithub.com/blang/semver v3.5.1+incompatible // indirect\n\tgithub.com/cenkalti/backoff/v5 v5.0.3 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/chai2010/gettext-go v1.0.2 // indirect\n\tgithub.com/cilium/ebpf v0.21.0 // indirect\n\tgithub.com/cloudflare/circl v1.6.3 // indirect\n\tgithub.com/containerd/continuity v0.4.5 // indirect\n\tgithub.com/containerd/errdefs/pkg v0.3.0 // indirect\n\tgithub.com/containerd/fifo v1.1.0 // indirect\n\tgithub.com/containerd/go-cni v1.1.13 // indirect\n\tgithub.com/containerd/plugin v1.0.0 // indirect\n\tgithub.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect\n\tgithub.com/containerd/ttrpc v1.2.7 // indirect\n\tgithub.com/coreos/go-oidc/v3 v3.17.0 // indirect\n\tgithub.com/coreos/go-semver v0.3.1 // indirect\n\tgithub.com/coreos/go-systemd/v22 v22.6.0 // indirect\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect\n\tgithub.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect\n\tgithub.com/cyphar/filepath-securejoin v0.6.1 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect\n\tgithub.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect\n\tgithub.com/docker/distribution v2.8.3+incompatible // indirect\n\tgithub.com/docker/docker-credential-helpers v0.9.4 // indirect\n\tgithub.com/docker/go-connections v0.6.0 // indirect\n\tgithub.com/docker/go-units v0.5.0 // indirect\n\tgithub.com/emicklei/dot v1.11.0 // indirect\n\tgithub.com/emicklei/go-restful/v3 v3.13.0 // indirect\n\tgithub.com/evanphx/json-patch v5.9.11+incompatible // indirect\n\tgithub.com/evanphx/json-patch/v5 v5.9.11 // indirect\n\tgithub.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/fluxcd/cli-utils v0.36.0-flux.15 // indirect\n\tgithub.com/fluxcd/pkg/ssa v0.60.0 // indirect\n\tgithub.com/fxamacker/cbor/v2 v2.9.0 // indirect\n\tgithub.com/gdamore/encoding v1.0.1 // indirect\n\tgithub.com/ghodss/yaml v1.0.0 // indirect\n\tgithub.com/go-chi/chi/v5 v5.2.4 // indirect\n\tgithub.com/go-errors/errors v1.5.1 // indirect\n\tgithub.com/go-jose/go-jose/v4 v4.1.3 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/analysis v0.24.1 // indirect\n\tgithub.com/go-openapi/errors v0.22.7 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.22.4 // indirect\n\tgithub.com/go-openapi/jsonreference v0.21.4 // indirect\n\tgithub.com/go-openapi/loads v0.23.2 // indirect\n\tgithub.com/go-openapi/runtime v0.29.2 // indirect\n\tgithub.com/go-openapi/spec v0.22.3 // indirect\n\tgithub.com/go-openapi/strfmt v0.26.0 // indirect\n\tgithub.com/go-openapi/swag v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/cmdutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/conv v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/fileutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/jsonname v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/jsonutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/loading v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/mangling v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/netutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/stringutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/typeutils v0.25.5 // indirect\n\tgithub.com/go-openapi/swag/yamlutils v0.25.5 // indirect\n\tgithub.com/go-openapi/validate v0.25.1 // indirect\n\tgithub.com/go-resty/resty/v2 v2.17.1 // indirect\n\tgithub.com/go-viper/mapstructure/v2 v2.5.0 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/golang-jwt/jwt/v5 v5.3.0 // indirect\n\tgithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/golang/snappy v0.0.4 // indirect\n\tgithub.com/google/btree v1.1.3 // indirect\n\tgithub.com/google/certificate-transparency-go v1.3.2 // indirect\n\tgithub.com/google/gnostic-models v0.7.0 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect\n\tgithub.com/gosuri/uilive v0.0.4 // indirect\n\tgithub.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-retryablehttp v0.7.8 // indirect\n\tgithub.com/hashicorp/go-safetemp v1.0.0 // indirect\n\tgithub.com/hashicorp/go-version v1.7.0 // indirect\n\tgithub.com/in-toto/attestation v1.1.2 // indirect\n\tgithub.com/in-toto/in-toto-golang v0.9.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect\n\tgithub.com/jonboulle/clockwork v0.5.0 // indirect\n\tgithub.com/josharian/native v1.1.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/kylelemons/godebug v1.1.0 // indirect\n\tgithub.com/letsencrypt/boulder v0.20260223.0 // indirect\n\tgithub.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect\n\tgithub.com/lmittmann/tint v1.0.4 // indirect\n\tgithub.com/lucasb-eyer/go-colorful v1.3.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect\n\tgithub.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect\n\tgithub.com/mdlayher/packet v1.1.2 // indirect\n\tgithub.com/mdlayher/socket v0.5.1 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/go-testing-interface v1.14.1 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/moby/docker-image-spec v1.3.1 // indirect\n\tgithub.com/moby/locker v1.0.1 // indirect\n\tgithub.com/moby/spdystream v0.5.0 // indirect\n\tgithub.com/moby/sys/mountinfo v0.7.2 // indirect\n\tgithub.com/moby/sys/sequential v0.6.0 // indirect\n\tgithub.com/moby/sys/signal v0.7.1 // indirect\n\tgithub.com/moby/sys/user v0.4.0 // indirect\n\tgithub.com/moby/sys/userns v0.1.0 // indirect\n\tgithub.com/moby/term v0.5.2 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect\n\tgithub.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect\n\tgithub.com/neticdk/go-stdlib v1.0.1 // indirect\n\tgithub.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect\n\tgithub.com/oklog/ulid/v2 v2.1.1 // indirect\n\tgithub.com/opencontainers/selinux v1.13.1 // indirect\n\tgithub.com/opentracing/opentracing-go v1.2.0 // indirect\n\tgithub.com/peterbourgon/diskv v2.0.1+incompatible // indirect\n\tgithub.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.22 // indirect\n\tgithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect\n\tgithub.com/prometheus/client_golang v1.23.2 // indirect\n\tgithub.com/prometheus/client_model v0.6.2 // indirect\n\tgithub.com/prometheus/common v0.67.5 // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/russross/blackfriday/v2 v2.1.0 // indirect\n\tgithub.com/sasha-s/go-deadlock v0.3.6 // indirect\n\tgithub.com/sassoftware/relic v7.2.1+incompatible // indirect\n\tgithub.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect\n\tgithub.com/shibumi/go-pathspec v1.3.0 // indirect\n\tgithub.com/siderolabs/protoenc v0.2.4 // indirect\n\tgithub.com/siderolabs/tcpproxy v0.1.0 // indirect\n\tgithub.com/sigstore/protobuf-specs v0.5.0 // indirect\n\tgithub.com/sigstore/rekor v1.5.0 // indirect\n\tgithub.com/sigstore/rekor-tiles/v2 v2.2.0 // indirect\n\tgithub.com/sigstore/timestamp-authority/v2 v2.0.4 // indirect\n\tgithub.com/spf13/afero v1.15.0 // indirect\n\tgithub.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect\n\tgithub.com/theupdateframework/go-tuf v0.7.0 // indirect\n\tgithub.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect\n\tgithub.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c // indirect\n\tgithub.com/transparency-dev/merkle v0.0.2 // indirect\n\tgithub.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect\n\tgithub.com/vbatts/tar-split v0.12.2 // indirect\n\tgithub.com/vishvananda/netlink v1.3.1 // indirect\n\tgithub.com/vishvananda/netns v0.0.5 // indirect\n\tgithub.com/x448/float16 v0.8.4 // indirect\n\tgithub.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect\n\tgithub.com/xlab/treeprint v1.2.0 // indirect\n\tgithub.com/zalando/go-keyring v0.2.6 // indirect\n\tgo.etcd.io/bbolt v1.4.3 // indirect\n\tgo.etcd.io/etcd/pkg/v3 v3.6.8 // indirect\n\tgo.etcd.io/etcd/server/v3 v3.6.8 // indirect\n\tgo.etcd.io/raft/v3 v3.6.0 // indirect\n\tgo.opencensus.io v0.24.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect\n\tgo.opentelemetry.io/otel v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.40.0 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.3 // indirect\n\tgo.yaml.in/yaml/v3 v3.0.4 // indirect\n\tgolang.org/x/crypto v0.49.0 // indirect\n\tgolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect\n\tgolang.org/x/mod v0.33.0 // indirect\n\tgolang.org/x/tools v0.42.0 // indirect\n\tgolang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect\n\tgolang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c // indirect\n\tgopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect\n\tgopkg.in/inf.v0 v0.9.1 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tk8s.io/cli-runtime v0.35.2 // indirect\n\tk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect\n\tk8s.io/utils v0.0.0-20260108192941-914a6e750570 // indirect\n\tkernel.org/pub/linux/libs/security/libcap/psx v1.2.77 // indirect\n\trsc.io/qr v0.2.0 // indirect\n\tsigs.k8s.io/controller-runtime v0.22.2 // indirect\n\tsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect\n\tsigs.k8s.io/knftables v0.0.18 // indirect\n\tsigs.k8s.io/kustomize/api v0.20.1 // indirect\n\tsigs.k8s.io/kustomize/kyaml v0.20.1 // indirect\n\tsigs.k8s.io/randfill v1.0.0 // indirect\n\tsigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect\n\tsigs.k8s.io/yaml v1.6.0 // indirect\n)\n\nexclude github.com/containerd/containerd v1.7.0\n"
  },
  {
    "path": "go.sum",
    "content": "al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA=\nal.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=\ncel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=\ncloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=\ncloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs=\ncloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=\ncloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=\ncloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=\ncloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=\ncloud.google.com/go/kms v1.25.0 h1:gVqvGGUmz0nYCmtoxWmdc1wli2L1apgP8U4fghPGSbQ=\ncloud.google.com/go/kms v1.25.0/go.mod h1:XIdHkzfj0bUO3E+LvwPg+oc7s58/Ns8Nd8Sdtljihbk=\ncloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8=\ncloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk=\ncyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=\ncyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=\nfilippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw=\nfilippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=\ngithub.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg=\ngithub.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM=\ngithub.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=\ngithub.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=\ngithub.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=\ngithub.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.4.0 h1:mtvR5ZXH5Ew6PSONd5lO5OXovWP1E3oAlgC8fpxor2Q=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates v1.4.0/go.mod h1:u560+RFVfG0CBPzkXlDW43slESbBAQjgDGi3r6z+wk8=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLBGeVB5f2MdcIVD3ELVAWpr+WD6MUe1i+tM/PA=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4=\ngithub.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=\ngithub.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=\ngithub.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=\ngithub.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=\ngithub.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/Microsoft/hcsshim v0.14.0-rc.1 h1:qAPXKwGOkVn8LlqgBN8GS0bxZ83hOJpcjxzmlQKxKsQ=\ngithub.com/Microsoft/hcsshim v0.14.0-rc.1/go.mod h1:hTKFGbnDtQb1wHiOWv4v0eN+7boSWAHyK/tNAaYZL0c=\ngithub.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=\ngithub.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=\ngithub.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=\ngithub.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=\ngithub.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=\ngithub.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=\ngithub.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM=\ngithub.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A=\ngithub.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=\ngithub.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=\ngithub.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=\ngithub.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs=\ngithub.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=\ngithub.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=\ngithub.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=\ngithub.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ=\ngithub.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk=\ngithub.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=\ngithub.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=\ngithub.com/aws/aws-sdk-go-v2/service/acm v1.37.22 h1:gc1fzEkQZXff6e6rF6BpsHqYEhBtpL5ckBdiSXzWySk=\ngithub.com/aws/aws-sdk-go-v2/service/acm v1.37.22/go.mod h1:YUf/0QA0wySPQ3TJC5cHWHLwWw9nV3EXgTPkzcjnoq0=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk=\ngithub.com/aws/aws-sdk-go-v2/service/kms v1.50.3 h1:s/zDSG/a/Su9aX+v0Ld9cimUCdkr5FWPmBV8owaEbZY=\ngithub.com/aws/aws-sdk-go-v2/service/kms v1.50.3/go.mod h1:/iSgiUor15ZuxFGQSTf3lA2FmKxFsQoc2tADOarQBSw=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk=\ngithub.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=\ngithub.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=\ngithub.com/beevik/ntp v1.5.0 h1:y+uj/JjNwlY2JahivxYvtmv4ehfi3h74fAuABB9ZSM4=\ngithub.com/beevik/ntp v1.5.0/go.mod h1:mJEhBrwT76w9D+IfOEGvuzyuudiW9E52U2BaTrMOYow=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=\ngithub.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=\ngithub.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=\ngithub.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=\ngithub.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=\ngithub.com/brianvoe/gofakeit/v7 v7.7.3 h1:RWOATEGpJ5EVg2nN8nlaEyaV/aB4d6c3GqYrbqQekss=\ngithub.com/brianvoe/gofakeit/v7 v7.7.3/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=\ngithub.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=\ngithub.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=\ngithub.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=\ngithub.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=\ngithub.com/cilium/ebpf v0.21.0 h1:4dpx1J/B/1apeTmWBH5BkVLayHTkFrMovVPnHEk+l3k=\ngithub.com/cilium/ebpf v0.21.0/go.mod h1:1kHKv6Kvh5a6TePP5vvvoMa1bclRyzUXELSs272fmIQ=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=\ngithub.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=\ngithub.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=\ngithub.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=\ngithub.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=\ngithub.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=\ngithub.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=\ngithub.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=\ngithub.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=\ngithub.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=\ngithub.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=\ngithub.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=\ngithub.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=\ngithub.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=\ngithub.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=\ngithub.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=\ngithub.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=\ngithub.com/containerd/go-cni v1.1.13 h1:eFSGOKlhoYNxpJ51KRIMHZNlg5UgocXEIEBGkY7Hnis=\ngithub.com/containerd/go-cni v1.1.13/go.mod h1:nTieub0XDRmvCZ9VI/SBG6PyqT95N4FIhxsauF1vSBI=\ngithub.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=\ngithub.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=\ngithub.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=\ngithub.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=\ngithub.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=\ngithub.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8=\ngithub.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=\ngithub.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=\ngithub.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=\ngithub.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=\ngithub.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=\ngithub.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=\ngithub.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEmnuFjskwo=\ngithub.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4=\ngithub.com/containernetworking/plugins v1.9.0 h1:Mg3SXBdRGkdXyFC4lcwr6u2ZB2SDeL6LC3U+QrEANuQ=\ngithub.com/containernetworking/plugins v1.9.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c=\ngithub.com/coredns/caddy v1.1.4-0.20250930002214-15135a999495 h1:JFeOmbjLnVRhvmLHyuO3M1pfXWlPWpwkdM8UqXZRtBg=\ngithub.com/coredns/caddy v1.1.4-0.20250930002214-15135a999495/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=\ngithub.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc=\ngithub.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=\ngithub.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=\ngithub.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=\ngithub.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=\ngithub.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=\ngithub.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=\ngithub.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU=\ngithub.com/cosi-project/runtime v1.14.0 h1:puGI7sssk1h2KScC4ETjC+M7nyN+0ur44bAuSLdY91A=\ngithub.com/cosi-project/runtime v1.14.0/go.mod h1:sd2+E6DjC/QjrnlEEglINDZ4FUW7cVDMB5aG98Dl3LA=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=\ngithub.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=\ngithub.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=\ngithub.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=\ngithub.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=\ngithub.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=\ngithub.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=\ngithub.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=\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/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU=\ngithub.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk=\ngithub.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc=\ngithub.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE=\ngithub.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc=\ngithub.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I=\ngithub.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y=\ngithub.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=\ngithub.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=\ngithub.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=\ngithub.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=\ngithub.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk=\ngithub.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=\ngithub.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=\ngithub.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=\ngithub.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI=\ngithub.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=\ngithub.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=\ngithub.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=\ngithub.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=\ngithub.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/elastic/go-libaudit/v2 v2.6.2 h1:1PM6wVBTJHJQYsKl8jfA9/Aw9pFty5uUezPiUfKtOI4=\ngithub.com/elastic/go-libaudit/v2 v2.6.2/go.mod h1:8205nkf2oSrXFlO4H5j8/cyVMoSF3Y7jt+FjgS4ubQU=\ngithub.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4=\ngithub.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU=\ngithub.com/emicklei/dot v1.11.0 h1:zsrhCuFHAJge/aZIC4N4LdHy5tqYu4tWEaUzIwdYj4Y=\ngithub.com/emicklei/dot v1.11.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=\ngithub.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=\ngithub.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/equinix-ms/go-vmw-guestrpc v1.0.0 h1:O1+zDPdtli9NDWFyYe9ChaaROr3MJusEP0b89UTZDTI=\ngithub.com/equinix-ms/go-vmw-guestrpc v1.0.0/go.mod h1:YB8EWh3S7z7T2BmHYc95pGynNqjMLJCFnt0X57B0+p4=\ngithub.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=\ngithub.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=\ngithub.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=\ngithub.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=\ngithub.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=\ngithub.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/florianl/go-tc v0.4.7 h1:Ysai5TIx4PgOzqI/1cse/pquOFCEkWofKtc/EPumfrg=\ngithub.com/florianl/go-tc v0.4.7/go.mod h1:Fdz6eHitQZwylSvpAW3y9R9cUrnS/zinuAdjJpD7XqY=\ngithub.com/fluxcd/cli-utils v0.36.0-flux.15 h1:Et5QLnIpRjj+oZtM9gEybkAaoNsjysHq0y1253Ai94Y=\ngithub.com/fluxcd/cli-utils v0.36.0-flux.15/go.mod h1:AqRUmWIfNE7cdL6NWSGF0bAlypGs+9x5UQ2qOtlEzv4=\ngithub.com/fluxcd/pkg/ssa v0.60.0 h1:ikA78TWSLDmIc8I/goGAU/buYF6jto/gswE5hnOfWGk=\ngithub.com/fluxcd/pkg/ssa v0.60.0/go.mod h1:3k9t4B4UjOF0536RQssQ4r9BXLSCq6FSTnUNKseFVHQ=\ngithub.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=\ngithub.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=\ngithub.com/foxboron/go-uefi v0.0.0-20251010190908-d29549a44f29 h1:2XQY2y+CZCLpFjK5p2EEMwDdP99c7AWP29WhCTkiQm8=\ngithub.com/foxboron/go-uefi v0.0.0-20251010190908-d29549a44f29/go.mod h1:sqQZKX1X86EAN4C07n6DcbGC/DCN36BNaX/uNvjzmfk=\ngithub.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=\ngithub.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=\ngithub.com/freddierice/go-losetup/v2 v2.0.1 h1:wPDx/Elu9nDV8y/CvIbEDz5Xi5Zo80y4h7MKbi3XaAI=\ngithub.com/freddierice/go-losetup/v2 v2.0.1/go.mod h1:TEyBrvlOelsPEhfWD5rutNXDmUszBXuFnwT1kIQF4J8=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=\ngithub.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=\ngithub.com/g0rbe/go-chattr v1.0.1 h1:CHwYB+WKB46hkzt6Jxyvkyrz7u9njghUOFvmx2gir84=\ngithub.com/g0rbe/go-chattr v1.0.1/go.mod h1:yQc6VPJfpDDC1g+W2t47+yYmzBNioax/GLiyJ25/IOs=\ngithub.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=\ngithub.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo=\ngithub.com/gdamore/tcell/v2 v2.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU=\ngithub.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo=\ngithub.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA=\ngithub.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk=\ngithub.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=\ngithub.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=\ngithub.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=\ngithub.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=\ngithub.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=\ngithub.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=\ngithub.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=\ngithub.com/go-openapi/analysis v0.24.1 h1:Xp+7Yn/KOnVWYG8d+hPksOYnCYImE3TieBa7rBOesYM=\ngithub.com/go-openapi/analysis v0.24.1/go.mod h1:dU+qxX7QGU1rl7IYhBC8bIfmWQdX4Buoea4TGtxXY84=\ngithub.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA=\ngithub.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w=\ngithub.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4=\ngithub.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80=\ngithub.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8=\ngithub.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4=\ngithub.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4=\ngithub.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY=\ngithub.com/go-openapi/runtime v0.29.2 h1:UmwSGWNmWQqKm1c2MGgXVpC2FTGwPDQeUsBMufc5Yj0=\ngithub.com/go-openapi/runtime v0.29.2/go.mod h1:biq5kJXRJKBJxTDJXAa00DOTa/anflQPhT0/wmjuy+0=\ngithub.com/go-openapi/spec v0.22.3 h1:qRSmj6Smz2rEBxMnLRBMeBWxbbOvuOoElvSvObIgwQc=\ngithub.com/go-openapi/spec v0.22.3/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs=\ngithub.com/go-openapi/strfmt v0.26.0 h1:SDdQLyOEqu8W96rO1FRG1fuCtVyzmukky0zcD6gMGLU=\ngithub.com/go-openapi/strfmt v0.26.0/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=\ngithub.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU=\ngithub.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA=\ngithub.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c=\ngithub.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0=\ngithub.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=\ngithub.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=\ngithub.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk=\ngithub.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc=\ngithub.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=\ngithub.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU=\ngithub.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo=\ngithub.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U=\ngithub.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo=\ngithub.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU=\ngithub.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g=\ngithub.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw=\ngithub.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY=\ngithub.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU=\ngithub.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14=\ngithub.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M=\ngithub.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII=\ngithub.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E=\ngithub.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc=\ngithub.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=\ngithub.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag=\ngithub.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM=\ngithub.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw=\ngithub.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=\ngithub.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw=\ngithub.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc=\ngithub.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s=\ngithub.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=\ngithub.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4=\ngithub.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA=\ngithub.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA=\ngithub.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg=\ngithub.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=\ngithub.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=\ngithub.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=\ngithub.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=\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/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=\ngithub.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=\ngithub.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=\ngithub.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=\ngithub.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=\ngithub.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=\ngithub.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=\ngithub.com/google/cadvisor v0.56.2 h1:ra6p4Nxc4zT8VLbZscWUxhvjsqy+1AzMvuSdEM90o1w=\ngithub.com/google/cadvisor v0.56.2/go.mod h1:CWidr4DqGbkN4aKuOEjLB7Bab3gl01Xxm3co38C3xRU=\ngithub.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo=\ngithub.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw=\ngithub.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A=\ngithub.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs=\ngithub.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=\ngithub.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-containerregistry v0.21.2 h1:vYaMU4nU55JJGFC9JR/s8NZcTjbE9DBBbvusTW9NeS0=\ngithub.com/google/go-containerregistry v0.21.2/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=\ngithub.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=\ngithub.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=\ngithub.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc=\ngithub.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc=\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/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg=\ngithub.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM=\ngithub.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=\ngithub.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\ngithub.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js=\ngithub.com/google/trillian v1.7.2/go.mod h1:mfQJW4qRH6/ilABtPYNBerVJAJ/upxHLX81zxNQw05s=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\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/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8=\ngithub.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=\ngithub.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=\ngithub.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M=\ngithub.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=\ngithub.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=\ngithub.com/gosuri/uilive v0.0.4 h1:hUEBpQDj8D8jXgtCdBu7sWsy5sbW/5GhuO8KBwJ2jyY=\ngithub.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI=\ngithub.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJSxw=\ngithub.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=\ngithub.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=\ngithub.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=\ngithub.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o=\ngithub.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20=\ngithub.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns=\ngithub.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=\ngithub.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=\ngithub.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk=\ngithub.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=\ngithub.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=\ngithub.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=\ngithub.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM=\ngithub.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=\ngithub.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=\ngithub.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=\ngithub.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=\ngithub.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=\ngithub.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=\ngithub.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=\ngithub.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0=\ngithub.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM=\ngithub.com/hetznercloud/hcloud-go/v2 v2.36.0 h1:HlLL/aaVXUulqe+rsjoJmrxKhPi1MflL5O9iq5QEtvo=\ngithub.com/hetznercloud/hcloud-go/v2 v2.36.0/go.mod h1:MnN/QJEa/RYNQiiVoJjNHPntM7Z1wlYPgJ2HA40/cDE=\ngithub.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM=\ngithub.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8=\ngithub.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=\ngithub.com/hugelgupf/vmtest v0.0.0-20240307030256-5d9f3d34a58d h1:nP8SfQJqruIVSWYJTuYc37jLHEY1Z0fF+zKSrs3K/C8=\ngithub.com/hugelgupf/vmtest v0.0.0-20240307030256-5d9f3d34a58d/go.mod h1:B63hDJMhTupLWCHwopAyEo7wRFowx9kOc8m8j1sfOqE=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E=\ngithub.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM=\ngithub.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=\ngithub.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 h1:u9i04mGE3iliBh0EFuWaKsmcwrLacqGmq1G3XoaM7gY=\ngithub.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=\ngithub.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=\ngithub.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=\ngithub.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=\ngithub.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=\ngithub.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=\ngithub.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=\ngithub.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=\ngithub.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=\ngithub.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A=\ngithub.com/jarcoal/httpmock v1.4.1/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=\ngithub.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY=\ngithub.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=\ngithub.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=\ngithub.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=\ngithub.com/jeromer/syslogparser v1.1.0 h1:HES0EviO9iPvCu56LjVFVhbM3o0BckDlIbQfkkaRJAw=\ngithub.com/jeromer/syslogparser v1.1.0/go.mod h1:zfowyus/j2SEgW31bIntTvEBE2zCSndtFsCC6NcW4S4=\ngithub.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=\ngithub.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=\ngithub.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=\ngithub.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=\ngithub.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=\ngithub.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=\ngithub.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo=\ngithub.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs=\ngithub.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA=\ngithub.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00=\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/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw=\ngithub.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=\ngithub.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=\ngithub.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=\ngithub.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=\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/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/letsencrypt/boulder v0.20260223.0 h1:xdS2OnJNUasR6TgVIOpqqcvdkOu47+PQQMBk9ThuWBw=\ngithub.com/letsencrypt/boulder v0.20260223.0/go.mod h1:r3aTSA7UZ7dbDfiGK+HLHJz0bWNbHk6YSPiXgzl23sA=\ngithub.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=\ngithub.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=\ngithub.com/linode/go-metadata v0.2.4 h1:iif+14PN5T0u/wRnu6i/UlLQrlaFlWvDJzm0Wl9Rn0I=\ngithub.com/linode/go-metadata v0.2.4/go.mod h1:h6yHiRupdKvyPkydU9g8kUA3QKdAgj3WX2wrF+mUv1c=\ngithub.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=\ngithub.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=\ngithub.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=\ngithub.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=\ngithub.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=\ngithub.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=\ngithub.com/martinlindhe/base36 v1.1.1 h1:1F1MZ5MGghBXDZ2KJ3QfxmiydlWOGB8HCEtkap5NkVg=\ngithub.com/martinlindhe/base36 v1.1.1/go.mod h1:vMS8PaZ5e/jV9LwFKlm0YLnXl/hpOihiBxKkIoc3g08=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=\ngithub.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 h1:ql8x//rJsHMjS+qqEag8n3i4azw1QneKh5PieH9UEbY=\ngithub.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875/go.mod h1:kfOoFJuHWp76v1RgZCb9/gVUc7XdY877S2uVYbNliGc=\ngithub.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=\ngithub.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=\ngithub.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=\ngithub.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=\ngithub.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=\ngithub.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=\ngithub.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=\ngithub.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=\ngithub.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=\ngithub.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=\ngithub.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=\ngithub.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=\ngithub.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q=\ngithub.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=\ngithub.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=\ngithub.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco=\ngithub.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg=\ngithub.com/mdlayher/netx v0.0.0-20230430222610-7e21880baee8 h1:HMgSn3c16SXca3M+n6fLK2hXJLd4mhKAsZZh7lQfYmQ=\ngithub.com/mdlayher/netx v0.0.0-20230430222610-7e21880baee8/go.mod h1:qhZhwMDNWwZglKfwuWm0U9pCr/YKX1QAEwwJk9qfiTQ=\ngithub.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=\ngithub.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=\ngithub.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=\ngithub.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc=\ngithub.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=\ngithub.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=\ngithub.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=\ngithub.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=\ngithub.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=\ngithub.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFet4=\ngithub.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU=\ngithub.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=\ngithub.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=\ngithub.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=\ngithub.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=\ngithub.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE=\ngithub.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=\ngithub.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=\ngithub.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=\ngithub.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=\ngithub.com/moby/moby/api v1.54.0 h1:7kbUgyiKcoBhm0UrWbdrMs7RX8dnwzURKVbZGy2GnL0=\ngithub.com/moby/moby/api v1.54.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=\ngithub.com/moby/moby/client v0.3.0 h1:UUGL5okry+Aomj3WhGt9Aigl3ZOxZGqR7XPo+RLPlKs=\ngithub.com/moby/moby/client v0.3.0/go.mod h1:HJgFbJRvogDQjbM8fqc1MCEm4mIAGMLjXbgwoZp6jCQ=\ngithub.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=\ngithub.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=\ngithub.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=\ngithub.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=\ngithub.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=\ngithub.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=\ngithub.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=\ngithub.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=\ngithub.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=\ngithub.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=\ngithub.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=\ngithub.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=\ngithub.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=\ngithub.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=\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/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=\ngithub.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=\ngithub.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=\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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=\ngithub.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=\ngithub.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=\ngithub.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=\ngithub.com/navidys/tvxwidgets v0.13.0 h1:ccGODowWhHQH7zh43lwdeML+qpZS0cMHByjS3CPcRJY=\ngithub.com/navidys/tvxwidgets v0.13.0/go.mod h1:C+hTUXTFCOaYQkKlwqqn9K54RT0zrNqfqhI/RWwt+g4=\ngithub.com/nberlee/go-netstat v0.1.2 h1:wgPV1YOUo+kDFypqiKgfxMtnSs1Wb42c7ahI4qyEUJc=\ngithub.com/nberlee/go-netstat v0.1.2/go.mod h1:GvDCRLsUKMRN1wULkt7tpnDmjSIE6YGf5zeVq+mBO64=\ngithub.com/neticdk/go-stdlib v1.0.1 h1:3P6tJIICo8kvMMEFWSZCk+iRh+HoN8P/51WwMO+Ka2k=\ngithub.com/neticdk/go-stdlib v1.0.1/go.mod h1:KP9nLuDoanLbM8Wturn+hage2FtcrJaF1+1Znu+MKEw=\ngithub.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=\ngithub.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=\ngithub.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=\ngithub.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=\ngithub.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=\ngithub.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=\ngithub.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=\ngithub.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=\ngithub.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=\ngithub.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE=\ngithub.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=\ngithub.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=\ngithub.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=\ngithub.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=\ngithub.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=\ngithub.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=\ngithub.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=\ngithub.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=\ngithub.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=\ngithub.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=\ngithub.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE=\ngithub.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg=\ngithub.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=\ngithub.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=\ngithub.com/packethost/packngo v0.31.0 h1:LLH90ardhULWbagBIc3I3nl2uU75io0a7AwY6hyi0S4=\ngithub.com/packethost/packngo v0.31.0/go.mod h1:Io6VJqzkiqmIEQbpOjeIw9v8q9PfcTEq8TEY/tMQsfw=\ngithub.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=\ngithub.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=\ngithub.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=\ngithub.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=\ngithub.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=\ngithub.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=\ngithub.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14=\ngithub.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=\ngithub.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=\ngithub.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=\ngithub.com/pin/tftp/v3 v3.2.0 h1:q6K5G6T0TA7e3wDJsB/7VpD3iaWwVEJD/nEuh3q9Sk0=\ngithub.com/pin/tftp/v3 v3.2.0/go.mod h1:qc5ySXB5aOS1H6ULneqB4g5nshqV1CgeV/l/M6rEDms=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=\ngithub.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 h1:S1hI5JiKP7883xBzZAr1ydcxrKNSVNm7+3+JwjxZEsg=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25/go.mod h1:ZQntvDG8TkPgljxtA0R9frDoND4QORU1VXz015N5Ks4=\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/pmorjan/kmod v1.1.1 h1:Vfw6bMaOg/sYSBCqJPT9TbqHHf5zK00GbaL5JQLO4r0=\ngithub.com/pmorjan/kmod v1.1.1/go.mod h1:jR4fVosEpQ6b5U0rpxaqoShTDPvCjLIP8vEESZyvnqQ=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=\ngithub.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=\ngithub.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c=\ngithub.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=\ngithub.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=\ngithub.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=\ngithub.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=\ngithub.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=\ngithub.com/safchain/ethtool v0.7.0 h1:rlJzfDetsVvT61uz8x1YIcFn12akMfuPulHtZjtb7Is=\ngithub.com/safchain/ethtool v0.7.0/go.mod h1:MenQKEjXdfkjD3mp2QdCk8B/hwvkrlOTm/FD4gTpFxQ=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=\ngithub.com/sasha-s/go-deadlock v0.3.6 h1:TR7sfOnZ7x00tWPfD397Peodt57KzMDo+9Ae9rMiUmw=\ngithub.com/sasha-s/go-deadlock v0.3.6/go.mod h1:CUqNyyvMxTyjFqDT7MRg9mb4Dv/btmGTqSR+rky/UXo=\ngithub.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A=\ngithub.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk=\ngithub.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4=\ngithub.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k=\ngithub.com/scaleway/scaleway-sdk-go v1.0.0-beta.36 h1:ObX9hZmK+VmijreZO/8x9pQ8/P/ToHD/bdSb4Eg4tUo=\ngithub.com/scaleway/scaleway-sdk-go v1.0.0-beta.36/go.mod h1:LEsDu4BubxK7/cWhtlQWfuxwL4rf/2UEpxXz1o1EMtM=\ngithub.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14=\ngithub.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk=\ngithub.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=\ngithub.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=\ngithub.com/shanduur/rtnetlink/v2 v2.0.0-20260313131132-118a2ded4751 h1:rUMfGoS7VczaiZIGnG33ERqRnwgrcXiUoq+WgAFMSJo=\ngithub.com/shanduur/rtnetlink/v2 v2.0.0-20260313131132-118a2ded4751/go.mod h1:A/gqt1BEMJcvzGQJXQ3SnsDOQL7QRNhxTiC3eb++608=\ngithub.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=\ngithub.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=\ngithub.com/siderolabs/coredns v1.14.53 h1:rwWyicwWFcu+i8OV0WT1u2W46J/iIReqzm+pSvEPPWs=\ngithub.com/siderolabs/coredns v1.14.53/go.mod h1:KAGRTpTbhrScGMhiLsgnzo30OgiBBut1Y5XTuG1V+BQ=\ngithub.com/siderolabs/crypto v0.6.4 h1:uMoe/X/mABOv6yOgvKcjmjIMdv6U8JegBXlPKtyjn3g=\ngithub.com/siderolabs/crypto v0.6.4/go.mod h1:39B7Mdrd8qTfEYOjsWPQOk7gLTWrEI30isAW+YYj9nk=\ngithub.com/siderolabs/discovery-api v0.1.8 h1:Hq/Si0fFQICvdT+P/I81fRf9t5I+J6vaJNBvgehv8GE=\ngithub.com/siderolabs/discovery-api v0.1.8/go.mod h1:JN8aBpnsArIeLNLbqt3HIYHyFR14Qfwr4etAB2ZfygA=\ngithub.com/siderolabs/discovery-client v0.1.15 h1:XN2nm2U/RUtevZtKZnwYAOE+Z68VpW32Me1K19zXtHU=\ngithub.com/siderolabs/discovery-client v0.1.15/go.mod h1:iUpFYp40CNTnqshG7d2r9zjMruLEaT0sb49rZzVSXVA=\ngithub.com/siderolabs/ethtool v0.4.0-sidero h1:Ls/M4bFUjfcB1RDVviPZlL3kWcXaEVVSbKke+EZ2A9U=\ngithub.com/siderolabs/ethtool v0.4.0-sidero/go.mod h1:nOIR88fiFTdBfakYLEUAhxdy75Ih/fgnSlsSKAHRpfc=\ngithub.com/siderolabs/gen v0.8.0/go.mod h1:an3a2Y53O7kUjnnK8Bfu3gewtvnIOu5RTU6HalFtXQQ=\ngithub.com/siderolabs/gen v0.8.6 h1:pE6shuqov3L+5rEcAUJ/kY6iJofimljQw5G95P8a5c4=\ngithub.com/siderolabs/gen v0.8.6/go.mod h1:J9IbusbES2W6QWjtSHpDV9iPGZHc978h1+KJ4oQRspQ=\ngithub.com/siderolabs/go-api-signature v0.3.12 h1:i1X+kPh9fzo+lEjtEplZSbtq1p21vKv4FCWJcB/ozvk=\ngithub.com/siderolabs/go-api-signature v0.3.12/go.mod h1:dPLiXohup4qHX7KUgF/wwOE3lRU5uAr3ssEomNxiyxY=\ngithub.com/siderolabs/go-blockdevice/v2 v2.0.26 h1:t7faVJft7OrC/INPpODKg79O4qVpeKlkbs3amk/DIdQ=\ngithub.com/siderolabs/go-blockdevice/v2 v2.0.26/go.mod h1:a6KUjzyU8Joo7y9cW9BdmORCFJwVNweHYRpKiuDfMU8=\ngithub.com/siderolabs/go-circular v0.2.3 h1:GKkA1Tw79kEFGtWdl7WTxEUTbwtklITeiRT0V1McHrA=\ngithub.com/siderolabs/go-circular v0.2.3/go.mod h1:YBN/q9YpQphUYnBtBgPsngauSHj1TEZfgQZWZVjk1WE=\ngithub.com/siderolabs/go-cmd v0.2.0 h1:fZ0jbQzZg4bFLmJzNEDZM/RlebZsfHOo2k+PCJ6g7y4=\ngithub.com/siderolabs/go-cmd v0.2.0/go.mod h1:YA/UEDh8Av84RlI4LfQw7HN9+vgxUrQw/Byef1dgptY=\ngithub.com/siderolabs/go-copy v0.1.0 h1:OIWCtSg+rhOtnIZTpT31Gfpn17rv5kwJqQHG+QUEgC8=\ngithub.com/siderolabs/go-copy v0.1.0/go.mod h1:4bF2rZOZAR/ags/U4AVSpjFE5RPGdEeSkOq6yR9YOkU=\ngithub.com/siderolabs/go-debug v0.6.2 h1:zWWMTcrYDVyiNTotSxEVg++hj9mb2ctuTNVnOeCWtO8=\ngithub.com/siderolabs/go-debug v0.6.2/go.mod h1:tcHnBjzOfEC/Stfc+cpP8J9Y6y5Pp89XNBN0n3dsWD4=\ngithub.com/siderolabs/go-kmsg v0.1.5 h1:bdaultamVoM6f2ZmhwFL+LAh2A1c2sdCno5cEubv3rs=\ngithub.com/siderolabs/go-kmsg v0.1.5/go.mod h1:fryspKc1f6nMIOK5YbUPutz2v2rdBTBeLqW/ci9BDfk=\ngithub.com/siderolabs/go-kubeconfig v0.1.1 h1:tZlgpelj/OqrcHVUwISPN0NRgObcflpH9WtE41mtQZ0=\ngithub.com/siderolabs/go-kubeconfig v0.1.1/go.mod h1:QaGp4i9L95oDbcU7jDn30aw4gnREkb3O5otgxw8imOk=\ngithub.com/siderolabs/go-kubernetes v0.2.33 h1:I5J1EW6McjQeTzQCaZ7Vc0ZTbwypsCburRshTkb6HS0=\ngithub.com/siderolabs/go-kubernetes v0.2.33/go.mod h1:Ow/1iR+kJmMvKno9whL8WTRBoCPKPrHqxy1a/7SYacs=\ngithub.com/siderolabs/go-loadbalancer v0.5.0 h1:0v7E6GrxoONyqwcmHiA+J0vIDPWbkTmevHGCFb4tjdc=\ngithub.com/siderolabs/go-loadbalancer v0.5.0/go.mod h1:tRVouZ9i2R/TRbNUF9MqyBlV2wsjX0cxkYTjPXcI9P0=\ngithub.com/siderolabs/go-pcidb v0.3.3 h1:Cxng3j6gUrWCh1tHlt524A4cC+dyRU+3j1AWQM6ULPc=\ngithub.com/siderolabs/go-pcidb v0.3.3/go.mod h1:FHHkNSBdcdxba/UKFH8936pPFKAvjqqTsq182X0ulcY=\ngithub.com/siderolabs/go-pointer v1.0.1 h1:f7Yi4IK1jptS8yrT9GEbwhmGcVxvPQgBUG/weH3V3DM=\ngithub.com/siderolabs/go-pointer v1.0.1/go.mod h1:C8Q/3pNHT4RE9e4rYR9PHeS6KPMlStRBgYrJQJNy/vA=\ngithub.com/siderolabs/go-procfs v0.1.2 h1:bDs9hHyYGE2HO1frpmUsD60yg80VIEDrx31fkbi4C8M=\ngithub.com/siderolabs/go-procfs v0.1.2/go.mod h1:dBzQXobsM7+TWRRI3DS9X7vAuj8Nkfgu3Z/U9iY3ZTY=\ngithub.com/siderolabs/go-retry v0.3.3 h1:zKV+S1vumtO72E6sYsLlmIdV/G/GcYSBLiEx/c9oCEg=\ngithub.com/siderolabs/go-retry v0.3.3/go.mod h1:Ff/VGc7v7un4uQg3DybgrmOWHEmJ8BzZds/XNn/BqMI=\ngithub.com/siderolabs/go-smbios v0.3.3 h1:rM3UKHQ8in1mqNRkpV75Ls3Wnk6rAhQJVYKUsKkQS20=\ngithub.com/siderolabs/go-smbios v0.3.3/go.mod h1:kScnr0XSyzLfkRo/ChjITgI0rPRQnIi6PdgbxVCwA9U=\ngithub.com/siderolabs/go-tail v0.1.1 h1:3XeJgd97OHyFAIE7nQEMcRhOfnv7DvXbu0BRKbtT6u8=\ngithub.com/siderolabs/go-tail v0.1.1/go.mod h1:IihAL39acadXHfb5fEAOKK2DaDFIrG2+VD3b2H/ziZ0=\ngithub.com/siderolabs/go-talos-support v0.1.4 h1:vFYI7tcuyH4PoSkSOZtFMX8OKjvrkktzXWztbsCDh6Q=\ngithub.com/siderolabs/go-talos-support v0.1.4/go.mod h1:1DX20fTINVjMaW2zBmmqDBmQ4Be/6a6HwyqI1DR1ijM=\ngithub.com/siderolabs/grpc-proxy v0.5.1 h1:WTZYLMPTZPt43BzEJ02LT9kYA9qAfquWwCezc6NPPYE=\ngithub.com/siderolabs/grpc-proxy v0.5.1/go.mod h1:EQwE87LiWxhiIUPBeWmpjJb9DIWxWID8R6ARtdTC+8A=\ngithub.com/siderolabs/kms-client v0.2.0 h1:8RniCStUI75RTZO8qkhHOSVOnEU1AvvsKqJ7FqW/8NA=\ngithub.com/siderolabs/kms-client v0.2.0/go.mod h1:qq6dwcLPO0gaUyfkrhWi/37g/ZyZJzOHzvHrilLz48E=\ngithub.com/siderolabs/net v0.4.0 h1:1bOgVay/ijPkJz4qct98nHsiB/ysLQU0KLoBC4qLm7I=\ngithub.com/siderolabs/net v0.4.0/go.mod h1:/ibG+Hm9HU27agp5r9Q3eZicEfjquzNzQNux5uEk0kM=\ngithub.com/siderolabs/proto-codec v0.1.3 h1:tRzt2Rlc84Uv+Lx6vV2VmFpgHSV1fUNq/7nTXU892dM=\ngithub.com/siderolabs/proto-codec v0.1.3/go.mod h1:k6Sn8r+0473+xHL4t1rxD51lWm05rDqFpXecSUg3UE8=\ngithub.com/siderolabs/protoenc v0.2.4 h1:D3Fpn2nQSQOhl8ZlAxijZAf7K6F8CM1uZq0afIGsr8Q=\ngithub.com/siderolabs/protoenc v0.2.4/go.mod h1:i5XLHjfv5vyi7LhQrSEo19HCA+lYtDd7CWxsoWp9XE8=\ngithub.com/siderolabs/siderolink v0.3.15 h1:WSsgKQGJY/ObIKjTcYYGEaGfRMyox+r/Ft+9lIgJqOI=\ngithub.com/siderolabs/siderolink v0.3.15/go.mod h1:iWdlsHji90zotgDg4+a2zJL2ZMNJckQ8/VwqR39ThBM=\ngithub.com/siderolabs/tcpproxy v0.1.0 h1:IbkS9vRhjMOscc1US3M5P1RnsGKFgB6U5IzUk+4WkKA=\ngithub.com/siderolabs/tcpproxy v0.1.0/go.mod h1:onn6CPPj/w1UNqQ0U97oRPF0CqbrgEApYCw4P9IiCW8=\ngithub.com/siderolabs/wgctrl-go v0.0.0-20251029173431-c4fd5f6a4e72 h1:Boabco/vhoFVTUlPcLr4B27NnYUq1QMZVgMtPvyaDzk=\ngithub.com/siderolabs/wgctrl-go v0.0.0-20251029173431-c4fd5f6a4e72/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=\ngithub.com/sigstore/cosign/v3 v3.0.5 h1:c1zPqjU+H4wmirgysC+AkWMg7a7fykyOYF/m+F1150I=\ngithub.com/sigstore/cosign/v3 v3.0.5/go.mod h1:ble1vMvJagCFyTIDkibCq6MIHiWDw00JNYl0f9rB4T4=\ngithub.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY=\ngithub.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc=\ngithub.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ=\ngithub.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ=\ngithub.com/sigstore/rekor-tiles/v2 v2.2.0 h1:QwJNwxT+k5A3id+Hrg+8vYcNsTaB0Sj51xjfW2rKyAs=\ngithub.com/sigstore/rekor-tiles/v2 v2.2.0/go.mod h1:/WNRYctHKdxcjgXydYwO5OclW72Zqh6fNHSyGE8zQOE=\ngithub.com/sigstore/sigstore v1.10.5-0.20260304232115-b56c8664d026 h1:s+iQW///NgIyhJenrynY/joaLTbo91hFL+vytjDaKck=\ngithub.com/sigstore/sigstore v1.10.5-0.20260304232115-b56c8664d026/go.mod h1:k/mcVVXw3I87dYG/iCVTSW2xTrW7vPzxxGic4KqsqXs=\ngithub.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg=\ngithub.com/sigstore/sigstore-go v1.1.4/go.mod h1:2U/mQOT9cjjxrtIUeKDVhL+sHBKsnWddn8URlswdBsg=\ngithub.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4 h1:VZ+L6SKVWbLPHznIF0tBuO7qKMFdJiJMVwFKu9DlY5o=\ngithub.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4/go.mod h1:Rstj47WpJym25il8j4jTL0BfikzP/9AhVD+DsBcYzZc=\ngithub.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4 h1:G7yOv8bxk3zIEEZyVCixPxtePIAm+t3ZWSaKRPzVw+o=\ngithub.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4/go.mod h1:hxJelB/bRItMYOzi6qD9xEKjse2QZcikh4TbysfdDHc=\ngithub.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4 h1:Qxt6dE4IwhJ6gIXmg2q4S/SeqEDSZ29nmfsv7Zb6LL4=\ngithub.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4/go.mod h1:hJVeNOwarqfyALjOwsf0OR8YA/A96NABucEaQumPr30=\ngithub.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4 h1:KVavYMPfSf5NryOl6VrZ9nRG3fXOOJOPp7Czk/YCPkM=\ngithub.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4/go.mod h1:J7CA1AaBkyK8dYq6EdQANhj+8oEcsA7PrIp088qgPiY=\ngithub.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU=\ngithub.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM=\ngithub.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=\ngithub.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=\ngithub.com/smira/containerd/v2 v2.2.3-0.20260311174942-e5fa687ba763 h1:l0WOZNJ5VG2EYm4Tnj2Pm0m1v5Tlw9W7TwhWAn/k/Sk=\ngithub.com/smira/containerd/v2 v2.2.3-0.20260311174942-e5fa687ba763/go.mod h1:5Jhevmv6/2J+Iu/A2xXAdUIdI5Ah/hfyO7okJ4AFIdY=\ngithub.com/smira/kobject v0.0.0-20240304111826-49c8d4613389 h1:f/5NRv5IGZxbjBhc5MnlbNmyuXBPxvekhBAUzyKWyLY=\ngithub.com/smira/kobject v0.0.0-20240304111826-49c8d4613389/go.mod h1:+SexPO1ZvdbbWUdUnyXEWv3+4NwHZjKhxOmQqHY4Pqc=\ngithub.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=\ngithub.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=\ngithub.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=\ngithub.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=\ngithub.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=\ngithub.com/thejerf/suture/v4 v4.0.6 h1:QsuCEsCqb03xF9tPAsWAj8QOAJBgQI1c0VqJNaingg8=\ngithub.com/thejerf/suture/v4 v4.0.6/go.mod h1:gu9Y4dXNUWFrByqRt30Rm9/UZ0wzRSt9AJS6xu/ZGxU=\ngithub.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI=\ngithub.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug=\ngithub.com/theupdateframework/go-tuf/v2 v2.4.1 h1:K6ewW064rKZCPkRo1W/CTbTtm/+IB4+coG1iNURAGCw=\ngithub.com/theupdateframework/go-tuf/v2 v2.4.1/go.mod h1:Nex2enPVYDFCklrnbTzl3OVwD7fgIAj0J5++z/rvCj8=\ngithub.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI=\ngithub.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis=\ngithub.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0=\ngithub.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw=\ngithub.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4=\ngithub.com/tink-crypto/tink-go-hcvault/v2 v2.4.0/go.mod h1:OCKJIujnTzDq7f+73NhVs99oA2c1TR6nsOpuasYM6Yo=\ngithub.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4=\ngithub.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8=\ngithub.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=\ngithub.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=\ngithub.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c h1:5a2XDQ2LiAUV+/RjckMyq9sXudfrPSuCY4FuPC1NyAw=\ngithub.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c/go.mod h1:g85IafeFJZLxlzZCDRu4JLpfS7HKzR+Hw9qRh3bVzDI=\ngithub.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4=\ngithub.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A=\ngithub.com/u-root/u-root v0.16.0 h1:wY40O83MBVks97+Is0WlFlOPSwKQMIrWP9R1IsrExg8=\ngithub.com/u-root/u-root v0.16.0/go.mod h1:yL/XdSSW27PdGLgUh4MNRBy54mKM+TBLzpwiB4nwj90=\ngithub.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=\ngithub.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=\ngithub.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=\ngithub.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=\ngithub.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=\ngithub.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=\ngithub.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=\ngithub.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=\ngithub.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=\ngithub.com/vultr/metadata v1.1.0 h1:RUjCnH5Mdlz7uuyfb1jOZNkU72zl/HwK76jLzVFdiOo=\ngithub.com/vultr/metadata v1.1.0/go.mod h1:4yocaI6h2EFJzwN0m1KnnC/vDCx2axIqnyxmtF/LWoQ=\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/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=\ngithub.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=\ngithub.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=\ngithub.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=\ngithub.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=\ngithub.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=\ngithub.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=\ngithub.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=\ngithub.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q=\ngithub.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg=\ngithub.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=\ngithub.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=\ngithub.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU=\ngithub.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s=\ngithub.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI=\ngo.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=\ngo.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=\ngo.etcd.io/etcd/api/v3 v3.6.8 h1:gqb1VN92TAI6G2FiBvWcqKtHiIjr4SU2GdXxTwyexbM=\ngo.etcd.io/etcd/api/v3 v3.6.8/go.mod h1:qyQj1HZPUV3B5cbAL8scG62+fyz5dSxxu0w8pn28N6Q=\ngo.etcd.io/etcd/client/pkg/v3 v3.6.8 h1:Qs/5C0LNFiqXxYf2GU8MVjYUEXJ6sZaYOz0zEqQgy50=\ngo.etcd.io/etcd/client/pkg/v3 v3.6.8/go.mod h1:GsiTRUZE2318PggZkAo6sWb6l8JLVrnckTNfbG8PWtw=\ngo.etcd.io/etcd/client/v3 v3.6.8 h1:B3G76t1UykqAOrbio7s/EPatixQDkQBevN8/mwiplrY=\ngo.etcd.io/etcd/client/v3 v3.6.8/go.mod h1:MVG4BpSIuumPi+ELF7wYtySETmoTWBHVcDoHdVupwt8=\ngo.etcd.io/etcd/etcdutl/v3 v3.6.8 h1:5YolVcLplhVwSR7IXemN7kBpx/L4qHAmyNc+iW+PL/k=\ngo.etcd.io/etcd/etcdutl/v3 v3.6.8/go.mod h1:HGfpMG6Sjo9S6KWeXctiYcN8LjLbbUBdAjCYb8V977w=\ngo.etcd.io/etcd/pkg/v3 v3.6.8 h1:Xe+LIL974spy8b4nEx3H0KMr1ofq3r0kh6FbU3aw4es=\ngo.etcd.io/etcd/pkg/v3 v3.6.8/go.mod h1:TRibVNe+FqJIe1abOAA1PsuQ4wqO87ZaOoprg09Tn8c=\ngo.etcd.io/etcd/server/v3 v3.6.8 h1:U2strdSEy1U8qcSzRIdkYpvOPtBy/9i/IfaaCI9flZ4=\ngo.etcd.io/etcd/server/v3 v3.6.8/go.mod h1:88dCtwUnSirkUoJbflQxxWXqtBSZa6lSG0Kuej+dois=\ngo.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=\ngo.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=\ngo.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=\ngo.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg=\ngo.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=\ngo.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=\ngo.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=\ngo.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=\ngo.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=\ngo.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=\ngo.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=\ngo.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=\ngo.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=\ngo.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=\ngo.step.sm/crypto v0.76.0 h1:K23BSaeoiY7Y5dvvijTeYC9EduDBetNwQYMBwMhi1aA=\ngo.step.sm/crypto v0.76.0/go.mod h1:PXYJdKkK8s+GHLwLguFaLxHNAFsFL3tL1vSBrYfey5k=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=\ngo.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=\ngo4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=\ngo4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=\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-20200420201142-3c4aac89819a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\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/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=\ngolang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=\ngolang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=\ngolang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\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/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=\ngolang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=\ngolang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=\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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=\ngolang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=\ngolang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=\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=\ngolang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngolang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=\ngolang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=\ngolang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=\ngolang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/api v0.267.0 h1:w+vfWPMPYeRs8qH1aYYsFX68jMls5acWl/jocfLomwE=\ngoogle.golang.org/api v0.267.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=\ngoogle.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c h1:OyQPd6I3pN/9gDxz6L13kYGJgqkpdrAohJRBeXyxlgI=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c/go.mod h1:X2gu9Qwng7Nn009s/r3RUxqkzQNqOrAy79bluY7ojIg=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=\ngoogle.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=\ngoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/dnaeon/go-vcr.v4 v4.0.6 h1:PiJkrakkmzc5s7EfBnZOnyiLwi7o7A9fwPzN0X2uwe0=\ngopkg.in/dnaeon/go-vcr.v4 v4.0.6/go.mod h1:sbq5oMEcM4PXngbcNbHhzfCP9OdZodLhrbRYoyg09HY=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=\ngopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=\ngopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/typ.v4 v4.4.0 h1:O9vTueEmZd0iA9DF+g2wXeNCeloN2TOpxu6FXKl3AqM=\ngopkg.in/typ.v4 v4.4.0/go.mod h1:wolXe8DlewxRCjA7SOiT3zjrZ0eQJZcr8cmV6bQWJUM=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=\ngotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=\ngvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=\ngvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nk8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=\nk8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=\nk8s.io/apiextensions-apiserver v0.35.2 h1:iyStXHoJZsUXPh/nFAsjC29rjJWdSgUmG1XpApE29c0=\nk8s.io/apiextensions-apiserver v0.35.2/go.mod h1:OdyGvcO1FtMDWQ+rRh/Ei3b6X3g2+ZDHd0MSRGeS8rU=\nk8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=\nk8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=\nk8s.io/apiserver v0.35.2 h1:rb52v0CZGEL0FkhjS+I6jHflAp7fZ4MIaKcEHX7wmDk=\nk8s.io/apiserver v0.35.2/go.mod h1:CROJUAu0tfjZLyYgSeBsBan2T7LUJGh0ucWwTCSSk7g=\nk8s.io/cli-runtime v0.35.2 h1:3DNctzpPNXavqyrm/FFiT60TLk4UjUxuUMYbKOE970E=\nk8s.io/cli-runtime v0.35.2/go.mod h1:G2Ieu0JidLm5m1z9b0OkFhnykvJ1w+vjbz1tR5OFKL0=\nk8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=\nk8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=\nk8s.io/component-base v0.35.2 h1:btgR+qNrpWuRSuvWSnQYsZy88yf5gVwemvz0yw79pGc=\nk8s.io/component-base v0.35.2/go.mod h1:B1iBJjooe6xIJYUucAxb26RwhAjzx0gHnqO9htWIX+0=\nk8s.io/cri-api v0.35.2 h1:Lfg8KG0XFPph2KM+yWA+/mfv71v7UOkGt+uuqKMSWCU=\nk8s.io/cri-api v0.35.2/go.mod h1:Cnt29u/tYl1Se1cBRL30uSZ/oJ5TaIp4sZm1xDLvcMc=\nk8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=\nk8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=\nk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=\nk8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=\nk8s.io/kube-scheduler v0.35.2 h1:VMH5AxwoFp4k30uaYSTchDr6MPmURmGpuwldS2R3Opw=\nk8s.io/kube-scheduler v0.35.2/go.mod h1:D0Fqh5wr/ECi22MVfn4n8aywz/Vh0pfD59VGbYkQfA4=\nk8s.io/kubectl v0.35.2 h1:aSmqhSOfsoG9NR5oR8OD5eMKpLN9x8oncxfqLHbJJII=\nk8s.io/kubectl v0.35.2/go.mod h1:+OJC779UsDJGxNPbHxCwvb4e4w9Eh62v/DNYU2TlsyM=\nk8s.io/kubelet v0.35.2 h1:qF9jOe1j6vT4bVQZ6nnTTA5uu5NCnyR10o9IkW8Z0JQ=\nk8s.io/kubelet v0.35.2/go.mod h1:2pyCVLDfm7ErNwWZw2mutCloAXX76gfOToIMCHCq/8s=\nk8s.io/pod-security-admission v0.35.2 h1:vzEfL/TpdwwIE25xQiamiRfmWD+FIcNXJYzoMI50AUY=\nk8s.io/pod-security-admission v0.35.2/go.mod h1:zrNF0GSYasCR8SHiAD67q2iUTHitVoFQRvTOy/UijyU=\nk8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=\nk8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=\nkernel.org/pub/linux/libs/security/libcap/cap v1.2.77 h1:iQtQTjFUOcTT19fI8sTCzYXsjeVs56et3D8AbKS2Uks=\nkernel.org/pub/linux/libs/security/libcap/cap v1.2.77/go.mod h1:oV+IO8kGh0B7TxErbydDe2+BRmi9g/W0CkpVV+QBTJU=\nkernel.org/pub/linux/libs/security/libcap/psx v1.2.77 h1:Z06sMOzc0GNCwp6efaVrIrz4ywGJ1v+DP0pjVkOfDuA=\nkernel.org/pub/linux/libs/security/libcap/psx v1.2.77/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=\npgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=\npgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=\nrsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=\nrsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=\nsigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4=\nsigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=\nsigs.k8s.io/hydrophone v0.7.0 h1:BKEb8m6mcVL6kFEZ4jUCk5VD81bqm2XPtNxFT52ifxc=\nsigs.k8s.io/hydrophone v0.7.0/go.mod h1:w22N+PiIfL6XrIAxEqnZ7HnoER3F447WvdDlQhURiro=\nsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=\nsigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=\nsigs.k8s.io/knftables v0.0.18 h1:6Duvmu0s/HwGifKrtl6G3AyAPYlWiZqTgS8bkVMiyaE=\nsigs.k8s.io/knftables v0.0.18/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk=\nsigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I=\nsigs.k8s.io/kustomize/api v0.20.1/go.mod h1:t6hUFxO+Ph0VxIk1sKp1WS0dOjbPCtLJ4p8aADLwqjM=\nsigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A78=\nsigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po=\nsigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=\nsigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=\nsigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=\nsigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=\nsigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=\nsigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=\nsoftware.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=\nsoftware.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=\n"
  },
  {
    "path": "go.work",
    "content": "go 1.26.1\n\nuse (\n\t.\n\t./hack/cloud-image-uploader\n\t./pkg/machinery\n\t./tools\n\t./tools/docgen\n\t./tools/gotagsrewrite\n\t./tools/structprotogen\n)\n"
  },
  {
    "path": "hack/boilerplate.txt",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n"
  },
  {
    "path": "hack/cleanup.sh",
    "content": "#!/bin/bash\nPREFIX=\"${1}\"\n\n# Remove any archives as we do not need them since everything is dynamically linked.\nfind ${PREFIX} -type f -name \\*.a -delete\nfind ${PREFIX} -type f -name \\*.la -delete\n# Remove static binaries.\nfind ${PREFIX} -type f \\( -name \\*.static -o -name \\*.o \\) -delete\n# Strip debug symbols from all libraries and binaries.\nfind ${PREFIX}/{lib,usr/lib} -type f \\( -name \\*.so* -a ! -name \\*dbg \\) -exec strip --strip-unneeded {} ';' || true\nfind ${PREFIX}/usr/bin -type f -exec strip --strip-all {} ';' || true\n\n# Remove header files, man files, and any other non-runtime dependencies.\nrm -rf ${PREFIX}/usr/lib/pkgconfig/ \\\n       ${PREFIX}/{include,usr/include}/* \\\n       ${PREFIX}/share/* \\\n       ${PREFIX}/usr/lib/cmake \\\n       ${PREFIX}/usr/lib/gconv/ \\\n       ${PREFIX}/usr/libexec/getconf \\\n       ${PREFIX}/var/db\n\n# Drop broken symlinks.\nfind ${PREFIX} -xtype l -print -delete\n"
  },
  {
    "path": "hack/cloud-image-uploader/README.md",
    "content": "# cloud-image-uploader\n\n## vmimport role\n\nRole should be pre-created before running this command.\n\n    aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json\n    aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document file://role-policy.json\n\n## Google Cloud Pre-requisites\n\n- `GOOGLE_PROJECT_ID` - Google Cloud Project ID\n- `GOOGLE_CREDENTIALS_JSON` - Google Cloud Service Account JSON\n"
  },
  {
    "path": "hack/cloud-image-uploader/aws.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/feature/s3/manager\"\n\t\"github.com/aws/aws-sdk-go-v2/service/ec2\"\n\t\"github.com/aws/aws-sdk-go-v2/service/ec2/types\"\n\t\"github.com/aws/aws-sdk-go-v2/service/s3\"\n\ts3types \"github.com/aws/aws-sdk-go-v2/service/s3/types\"\n\t\"github.com/google/uuid\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n)\n\nvar denyInsecurePolicyTemplate = `{\n  \"Id\": \"ExamplePolicy\",\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Sid\": \"AllowSSLRequestsOnly\",\n      \"Action\": \"s3:*\",\n      \"Effect\": \"Deny\",\n      \"Resource\": [\n        \"arn:aws:s3:::%s\",\n        \"arn:aws:s3:::%s/*\"\n      ],\n      \"Condition\": {\n        \"Bool\": {\n          \"aws:SecureTransport\": \"false\"\n        }\n      },\n      \"Principal\": \"*\"\n    }\n  ]\n}`\n\n// GetAWSDefaultRegions returns a list of regions which are enabled for this account.\nfunc GetAWSDefaultRegions(ctx context.Context) ([]string, error) {\n\tcfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(\"us-east-1\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed loading AWS config: %w\", err)\n\t}\n\n\tsvc := ec2.NewFromConfig(cfg)\n\n\tresp, err := svc.DescribeRegions(ctx, &ec2.DescribeRegionsInput{\n\t\tFilters: []types.Filter{\n\t\t\t{\n\t\t\t\tName:   new(\"opt-in-status\"),\n\t\t\t\tValues: []string{\"opt-in-not-required\", \"opted-in\"},\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed describing regions: %w\", err)\n\t}\n\n\treturn xslices.Map(resp.Regions, func(r types.Region) string {\n\t\treturn pointer.SafeDeref(r.RegionName)\n\t}), nil\n}\n\n// AWSUploader registers AMI in the AWS.\ntype AWSUploader struct {\n\tOptions Options\n\n\tcfg     aws.Config\n\tec2svcs map[string]*ec2.Client\n}\n\nvar awsArchitectures = map[string]types.ArchitectureValues{\n\t\"amd64\": types.ArchitectureValuesX8664,\n\t\"arm64\": types.ArchitectureValuesArm64,\n}\n\n// Upload image and register with AWS.\nfunc (au *AWSUploader) Upload(ctx context.Context) error {\n\tvar err error\n\n\tau.cfg, err = config.LoadDefaultConfig(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed loading AWS config: %w\", err)\n\t}\n\n\tau.ec2svcs = make(map[string]*ec2.Client)\n\n\tfor _, region := range au.Options.AWSRegions {\n\t\tau.ec2svcs[region] = ec2.NewFromConfig(au.cfg, func(o *ec2.Options) {\n\t\t\to.Region = region\n\t\t})\n\t}\n\n\treturn au.RegisterAMIs(ctx)\n}\n\n// RegisterAMIs in every region.\nfunc (au *AWSUploader) RegisterAMIs(ctx context.Context) error {\n\tvar g *errgroup.Group\n\n\tg, ctx = errgroup.WithContext(ctx)\n\n\tfor region, svc := range au.ec2svcs {\n\t\tg.Go(func() error {\n\t\t\terr := au.registerAMI(ctx, region, svc)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error registering AMI in %s: %w\", region, err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn g.Wait()\n}\n\nfunc cleanupBucket(s3Svc *s3.Client, bucketName string) {\n\t// create a detached context, as context might be canceled\n\tctx, cancel := context.WithTimeout(context.Background(), time.Minute)\n\tdefer cancel()\n\n\tmpuPaginator := s3.NewListMultipartUploadsPaginator(s3Svc, &s3.ListMultipartUploadsInput{\n\t\tBucket: new(bucketName),\n\t})\n\n\tfor mpuPaginator.HasMorePages() {\n\t\tpage, err := mpuPaginator.NextPage(ctx)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed listing multipart uploads: %s\", err)\n\n\t\t\tbreak\n\t\t}\n\n\t\tfor _, upload := range page.Uploads {\n\t\t\t_, err = s3Svc.AbortMultipartUpload(ctx, &s3.AbortMultipartUploadInput{\n\t\t\t\tBucket:   new(bucketName),\n\t\t\t\tKey:      upload.Key,\n\t\t\t\tUploadId: upload.UploadId,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"failed aborting multipart upload: %s\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tobjectsPaginator := s3.NewListObjectsV2Paginator(s3Svc, &s3.ListObjectsV2Input{\n\t\tBucket: new(bucketName),\n\t})\n\n\tfor objectsPaginator.HasMorePages() {\n\t\tpage, err := objectsPaginator.NextPage(ctx)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed listing objects: %s\", err)\n\n\t\t\tbreak\n\t\t}\n\n\t\tif len(page.Contents) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\t_, err = s3Svc.DeleteObjects(ctx, &s3.DeleteObjectsInput{\n\t\t\tBucket: new(bucketName),\n\t\t\tDelete: &s3types.Delete{\n\t\t\t\tObjects: xslices.Map(page.Contents, func(obj s3types.Object) s3types.ObjectIdentifier {\n\t\t\t\t\treturn s3types.ObjectIdentifier{\n\t\t\t\t\t\tKey: obj.Key,\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed deleting objects: %s\", err)\n\t\t}\n\t}\n\n\t_, err := s3Svc.DeleteBucket(ctx, &s3.DeleteBucketInput{\n\t\tBucket: aws.String(bucketName),\n\t})\n\tif err != nil {\n\t\tlog.Printf(\"failed deleting bucket: %s\", err)\n\t}\n\n\tlog.Printf(\"aws: deleted bucket %q\", bucketName)\n}\n\nfunc (au *AWSUploader) registerAMI(ctx context.Context, region string, svc *ec2.Client) error {\n\ts3Svc := s3.NewFromConfig(au.cfg, func(o *s3.Options) {\n\t\to.Region = region\n\t})\n\tbucketName := fmt.Sprintf(\"talos-image-upload-%s\", uuid.New())\n\n\tvar createBucketConfiguration *s3types.CreateBucketConfiguration\n\n\tif region != \"us-east-1\" {\n\t\tcreateBucketConfiguration = &s3types.CreateBucketConfiguration{\n\t\t\tLocationConstraint: s3types.BucketLocationConstraint(region),\n\t\t}\n\t}\n\n\t_, err := s3Svc.CreateBucket(ctx, &s3.CreateBucketInput{\n\t\tBucket:                    new(bucketName),\n\t\tCreateBucketConfiguration: createBucketConfiguration,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed creating S3 bucket: %w\", err)\n\t}\n\n\tif err = s3.NewBucketExistsWaiter(s3Svc).Wait(ctx, &s3.HeadBucketInput{\n\t\tBucket: new(bucketName),\n\t}, time.Minute); err != nil {\n\t\treturn fmt.Errorf(\"failed waiting for S3 bucket: %w\", err)\n\t}\n\n\tlog.Printf(\"aws: created bucket %q for %s\", bucketName, region)\n\n\tdefer func() {\n\t\tcleanupBucket(s3Svc, bucketName)\n\t}()\n\n\t_, err = s3Svc.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{\n\t\tBucket: new(bucketName),\n\t\tPolicy: new(fmt.Sprintf(denyInsecurePolicyTemplate, bucketName, bucketName)),\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed applying S3 bucket policy: %w\", err)\n\t}\n\n\tlog.Printf(\"aws: applied policy to bucket %q\", bucketName)\n\n\tuploader := manager.NewUploader(s3Svc) //nolint:staticcheck\n\n\tvar g errgroup.Group\n\n\tfor _, arch := range au.Options.Architectures {\n\t\tg.Go(func() error {\n\t\t\terr = au.registerAMIArch(ctx, region, svc, arch, bucketName, uploader)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"WARNING: aws: ignoring failure to upload AMI into %s/%s: %s\", region, arch, err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn g.Wait()\n}\n\n//nolint:gocyclo\nfunc (au *AWSUploader) tagSnapshot(ctx context.Context, svc *ec2.Client, snapshotID, imageName string) {\n\tif snapshotID == \"\" {\n\t\treturn\n\t}\n\n\t_, tagErr := svc.CreateTags(ctx, &ec2.CreateTagsInput{\n\t\tResources: []string{snapshotID},\n\t\tTags: []types.Tag{{\n\t\t\tKey:   new(\"Name\"),\n\t\t\tValue: new(imageName),\n\t\t}},\n\t})\n\tif tagErr != nil {\n\t\tlog.Printf(\"WARNING: failed to tag snapshot %s: %v\", snapshotID, tagErr)\n\t}\n}\n\n//nolint:gocyclo\nfunc (au *AWSUploader) registerAMIArch(ctx context.Context, region string, svc *ec2.Client, arch, bucketName string, uploader *manager.Uploader) error { //nolint:staticcheck\n\terr := retry.Constant(30*time.Minute, retry.WithUnits(time.Second), retry.WithErrorLogging(true)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tsource, err := os.Open(au.Options.AWSImage(arch))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer source.Close() //nolint:errcheck\n\n\t\timage, err := zstd.NewReader(source)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer image.Close()\n\n\t\t_, err = uploader.Upload(ctx, &s3.PutObjectInput{ //nolint:staticcheck\n\t\t\tBucket: new(bucketName),\n\t\t\tKey:    new(fmt.Sprintf(\"disk-%s.raw\", arch)),\n\t\t\tBody:   image,\n\t\t})\n\n\t\treturn retry.ExpectedError(err)\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to upload image to the bucket: %w\", err)\n\t}\n\n\tlog.Printf(\"aws: import into %s/%s, image uploaded to S3\", region, arch)\n\n\tresp, err := svc.ImportSnapshot(ctx, &ec2.ImportSnapshotInput{\n\t\tDescription: new(fmt.Sprintf(\"Talos Image %s %s %s\", au.Options.Tag, arch, region)),\n\t\tDiskContainer: &types.SnapshotDiskContainer{\n\t\t\tDescription: new(fmt.Sprintf(\"Talos Image %s %s %s\", au.Options.Tag, arch, region)),\n\t\t\tFormat:      new(\"raw\"),\n\t\t\tUserBucket: &types.UserBucket{\n\t\t\t\tS3Bucket: new(bucketName),\n\t\t\t\tS3Key:    new(fmt.Sprintf(\"disk-%s.raw\", arch)),\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to import snapshot: %w\", err)\n\t}\n\n\ttaskID := *resp.ImportTaskId\n\n\tvar snapshotID string\n\n\tlog.Printf(\"aws: import into %s/%s, task ID %q\", region, arch, taskID)\n\n\tprogress := \"0\"\n\n\terr = retry.Constant(30*time.Minute, retry.WithUnits(30*time.Second)).Retry(func() error {\n\t\tvar status *ec2.DescribeImportSnapshotTasksOutput\n\n\t\tstatus, err = svc.DescribeImportSnapshotTasks(ctx, &ec2.DescribeImportSnapshotTasksInput{\n\t\t\tImportTaskIds: []string{taskID},\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, task := range status.ImportSnapshotTasks {\n\t\t\tif pointer.SafeDeref(task.ImportTaskId) == taskID {\n\t\t\t\tif task.SnapshotTaskDetail == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif pointer.SafeDeref(task.SnapshotTaskDetail.Status) == \"completed\" {\n\t\t\t\t\tsnapshotID = pointer.SafeDeref(task.SnapshotTaskDetail.SnapshotId)\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif pointer.SafeDeref(task.SnapshotTaskDetail.Progress) != progress {\n\t\t\t\t\tprogress = pointer.SafeDeref(task.SnapshotTaskDetail.Progress)\n\n\t\t\t\t\tlog.Printf(\"aws: import into %s/%s, import snapshot %s%%\", region, arch, progress)\n\t\t\t\t}\n\n\t\t\t\treturn retry.ExpectedErrorf(\"task status is %s\", *task.SnapshotTaskDetail.Status)\n\t\t\t}\n\t\t}\n\n\t\treturn retry.ExpectedErrorf(\"task status not found\")\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to wait for import task: %w\", err)\n\t}\n\n\tlog.Printf(\"aws: import into %s/%s, snapshot ID %q\", region, arch, snapshotID)\n\n\timageName := fmt.Sprintf(\"talos-%s-%s-%s\", au.Options.Tag, region, arch)\n\n\tif au.Options.NamePrefix != \"\" {\n\t\timageName = fmt.Sprintf(\"%s-%s-%s-%s\", au.Options.NamePrefix, au.Options.Tag, region, arch)\n\t}\n\n\tau.tagSnapshot(ctx, svc, snapshotID, imageName)\n\n\timageResp, err := svc.DescribeImages(ctx, &ec2.DescribeImagesInput{\n\t\tFilters: []types.Filter{\n\t\t\t{\n\t\t\t\tName:   aws.String(\"name\"),\n\t\t\t\tValues: []string{imageName},\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to describe images: %w\", err)\n\t}\n\n\tfor _, image := range imageResp.Images {\n\t\t_, err = svc.DeregisterImage(ctx, &ec2.DeregisterImageInput{\n\t\t\tImageId: image.ImageId,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to deregister image: %w\", err)\n\t\t}\n\n\t\tlog.Printf(\"aws: import into %s/%s, deregistered image ID %q\", region, arch, *image.ImageId)\n\t}\n\n\tregisterReq := &ec2.RegisterImageInput{\n\t\tName: aws.String(imageName),\n\t\tBlockDeviceMappings: []types.BlockDeviceMapping{\n\t\t\t{\n\t\t\t\tDeviceName:  new(\"/dev/xvda\"),\n\t\t\t\tVirtualName: new(\"talos\"),\n\t\t\t\tEbs: &types.EbsBlockDevice{\n\t\t\t\t\tDeleteOnTermination: new(true),\n\t\t\t\t\tSnapshotId:          new(snapshotID),\n\t\t\t\t\tVolumeSize:          new(int32(20)),\n\t\t\t\t\tVolumeType:          types.VolumeTypeGp2,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tRootDeviceName:     new(\"/dev/xvda\"),\n\t\tVirtualizationType: new(\"hvm\"),\n\t\tEnaSupport:         new(true),\n\t\tDescription:        new(fmt.Sprintf(\"Talos AMI %s %s %s\", au.Options.Tag, arch, region)),\n\t\tArchitecture:       awsArchitectures[arch],\n\t\tImdsSupport:        types.ImdsSupportValuesV20,\n\t}\n\n\tif !au.Options.AWSForceBIOS {\n\t\tregisterReq.BootMode = types.BootModeValuesUefiPreferred\n\t}\n\n\tregisterResp, err := svc.RegisterImage(ctx, registerReq)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register image: %w\", err)\n\t}\n\n\timageID := *registerResp.ImageId\n\n\tlog.Printf(\"aws: import into %s/%s, registered image ID %q\", region, arch, imageID)\n\n\t_, err = svc.ModifyImageAttribute(ctx, &ec2.ModifyImageAttributeInput{\n\t\tImageId: aws.String(imageID),\n\t\tLaunchPermission: &types.LaunchPermissionModifications{\n\t\t\tAdd: []types.LaunchPermission{\n\t\t\t\t{\n\t\t\t\t\tGroup: types.PermissionGroupAll,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAttribute: aws.String(\"launchPermission\"),\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to modify image attribute: %w\", err)\n\t}\n\n\tpushResult(CloudImage{\n\t\tCloud:  \"aws\",\n\t\tTag:    au.Options.Tag,\n\t\tRegion: region,\n\t\tArch:   arch,\n\t\tType:   \"hvm\",\n\t\tID:     imageID,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/factory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"golang.org/x/sync/errgroup\"\n)\n\nvar extensions = map[string]string{\n\t\"aws\": \".raw.zst\",\n\t\"gcp\": \".raw.tar.gz\",\n}\n\n// FactoryDownloader is helper for downloading images from Image Factory.\ntype FactoryDownloader struct {\n\tTarget  string\n\tOptions Options\n}\n\nfunc (f *FactoryDownloader) Download(ctx context.Context) error {\n\tg, ctx := errgroup.WithContext(ctx)\n\n\tfor _, arch := range f.Options.Architectures {\n\t\tg.Go(func() error {\n\t\t\tartifact := fmt.Sprintf(\"%s-%s%s\", f.Target, arch, extensions[f.Target])\n\n\t\t\tr, err := f.getArtifact(ctx, artifact)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer r.Close() //nolint:errcheck\n\n\t\t\treturn f.saveArtifact(artifact, r)\n\t\t})\n\t}\n\n\treturn g.Wait()\n}\n\nfunc (f *FactoryDownloader) getArtifact(ctx context.Context, name string) (io.ReadCloser, error) {\n\turl, err := url.JoinPath(\n\t\tf.Options.FactoryHost,\n\t\t\"image\",\n\t\tf.Options.SchematicFor(f.Target),\n\t\tf.Options.Tag,\n\t\tname,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to construct URL: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create request: %w\", err)\n\t}\n\n\tlog.Printf(\"requesting artifact: %s\", url)\n\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to download image from %q: %w\", url, err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"unexpected status code %d when fetching %q\", resp.StatusCode, url)\n\t}\n\n\treturn resp.Body, nil\n}\n\nfunc (f *FactoryDownloader) saveArtifact(name string, r io.Reader) error {\n\tartifact := filepath.Join(f.Options.ArtifactsPath, name)\n\n\terr := os.MkdirAll(f.Options.ArtifactsPath, 0o755)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create artifacts directory %q: %w\", f.Options.ArtifactsPath, err)\n\t}\n\n\tof, err := os.OpenFile(artifact, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create file %q: %w\", artifact, err)\n\t}\n\tdefer of.Close() //nolint:errcheck\n\n\tlog.Printf(\"saving artifact: %s\", artifact)\n\n\t_, err = io.Copy(of, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to write image to file %q: %w\", artifact, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/gcp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"cloud.google.com/go/storage\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/api/compute/v1\"\n\t\"google.golang.org/api/googleapi\"\n\t\"google.golang.org/api/iterator\"\n\t\"google.golang.org/api/option\"\n)\n\n// GCPUploder registers the image in GCP.\ntype GCPUploder struct {\n\tOptions Options\n\n\tstorageClient  *storage.Client\n\tcomputeService *compute.Service\n\tprojectID      string\n\n\timagePath string\n}\n\n// NewGCPUploder creates a new GCPUploder.\nfunc NewGCPUploder(options Options) (*GCPUploder, error) {\n\tprojectID := os.Getenv(\"GOOGLE_PROJECT_ID\")\n\tcredentials := os.Getenv(\"GOOGLE_CREDENTIALS\")\n\n\tif projectID == \"\" {\n\t\treturn nil, fmt.Errorf(\"gcp: GOOGLE_PROJECT_ID is not set\")\n\t}\n\n\tif credentials == \"\" {\n\t\treturn nil, fmt.Errorf(\"gcp: GOOGLE_CREDENTIALS is not set\")\n\t}\n\n\tgcpUploader := &GCPUploder{\n\t\tOptions: options,\n\t}\n\n\tgcpUploader.projectID = projectID\n\n\tvar err error\n\n\tgcpUploader.storageClient, err = storage.NewClient(context.Background(), option.WithCredentialsJSON([]byte(credentials))) //nolint:staticcheck\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"gcp: failed to create google storage client: %w\", err)\n\t}\n\n\tgcpUploader.computeService, err = compute.NewService(context.Background(), option.WithCredentialsJSON([]byte(credentials))) //nolint:staticcheck\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"gcp: failed to create google compute service: %w\", err)\n\t}\n\n\treturn gcpUploader, nil\n}\n\n// Upload uploads the image to GCP.\nfunc (u *GCPUploder) Upload(ctx context.Context) error {\n\tbucketName := fmt.Sprintf(\"talos-image-upload-%s\", uuid.New())\n\n\tbucketHandle := u.storageClient.Bucket(bucketName)\n\n\tif err := bucketHandle.Create(ctx, u.projectID, &storage.BucketAttrs{\n\t\tPublicAccessPrevention: storage.PublicAccessPreventionEnforced,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to create bucket %s: %w\", bucketName, err)\n\t}\n\n\tlog.Println(\"gcp: created bucket\", bucketName)\n\n\tdefer func() {\n\t\tobjects := bucketHandle.Objects(ctx, nil)\n\n\t\tfor {\n\t\t\tobjAttr, err := objects.Next()\n\t\t\tif errors.Is(err, iterator.Done) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"gcp: failed to list objects: %v\", err)\n\t\t\t}\n\n\t\t\tif err := bucketHandle.Object(objAttr.Name).Delete(ctx); err != nil {\n\t\t\t\tlog.Printf(\"gcp: failed to delete object %s: %v\", objAttr.Name, err)\n\t\t\t}\n\t\t}\n\n\t\tif err := bucketHandle.Delete(ctx); err != nil {\n\t\t\tlog.Printf(\"gcp: failed to delete bucket %s: %v\", bucketName, err)\n\t\t}\n\t}()\n\n\tvar g errgroup.Group\n\n\tfor _, arch := range u.Options.Architectures {\n\t\tg.Go(func() error {\n\t\t\treturn u.uploadImage(ctx, arch, bucketName)\n\t\t})\n\t}\n\n\tif err := g.Wait(); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to upload images: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (u *GCPUploder) uploadImage(ctx context.Context, arch, bucketName string) error {\n\tobjectPath := u.Options.GCPImage(arch)\n\n\tobjectName := filepath.Base(objectPath)\n\n\tobjectReader, err := os.Open(objectPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to open object data file %s: %w\", objectPath, err)\n\t}\n\n\tobjectHandle := u.storageClient.Bucket(bucketName).Object(objectName)\n\n\tobjectWriter := objectHandle.NewWriter(ctx)\n\n\tdefer objectWriter.Close() //nolint:errcheck\n\n\tif _, err := io.Copy(objectWriter, objectReader); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to write object data: %w\", err)\n\t}\n\n\tif err := objectWriter.Close(); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to close object writer: %w\", err)\n\t}\n\n\tu.imagePath = fmt.Sprintf(\"https://storage.googleapis.com/%s/%s\", bucketName, objectName)\n\n\tlog.Println(\"gcp: uploaded image\", u.imagePath)\n\n\treturn u.registerImage(arch)\n}\n\n//nolint:gocyclo\nfunc (u *GCPUploder) registerImage(arch string) error {\n\timageName := fmt.Sprintf(\"talos-%s-%s\", strings.ReplaceAll(u.Options.Tag, \".\", \"-\"), arch)\n\n\tif u.Options.NamePrefix != \"\" {\n\t\timageName = fmt.Sprintf(\"%s-talos-%s-%s\", u.Options.NamePrefix, strings.ReplaceAll(u.Options.Tag, \".\", \"-\"), arch)\n\t}\n\n\texists, err := u.checkImageExists(imageName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif exists {\n\t\tlog.Printf(\"gcp: image %s already exists, deleting\", imageName)\n\n\t\tif deleteErr := u.deleteImage(imageName); deleteErr != nil {\n\t\t\treturn deleteErr\n\t\t}\n\t}\n\n\toperationID, link, err := u.insertImage(imageName, arch)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := retry.Constant(15*time.Minute, retry.WithUnits(30*time.Second)).Retry(func() error {\n\t\top, err := u.computeService.GlobalOperations.Get(u.projectID, operationID).Do()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"gcp: failed to get operation: %w\", err)\n\t\t}\n\n\t\tif op.HTTPStatusCode != http.StatusOK {\n\t\t\treturn fmt.Errorf(\"gcp: operation failed with http error message: %s\", op.HttpErrorMessage)\n\t\t}\n\n\t\tif op.Error != nil {\n\t\t\treturn fmt.Errorf(\"gcp: operation faild with error message: %s\", op.Error.Errors[0].Message)\n\t\t}\n\n\t\tif op.Status == \"DONE\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tlog.Printf(\"gcp: image creation progress: %d\", op.Progress)\n\n\t\treturn retry.ExpectedError(fmt.Errorf(\"gcp: image status is %s\", op.Status))\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"gcp: image creation is taking longer than expected: %w\", err)\n\t}\n\n\tpushResult(CloudImage{\n\t\tCloud:  \"gcp\",\n\t\tTag:    u.Options.Tag,\n\t\tRegion: \"us\",\n\t\tArch:   arch,\n\t\tType:   \"compute#image\",\n\t\tID:     link,\n\t})\n\n\treturn nil\n}\n\nfunc (u *GCPUploder) checkImageExists(imageName string) (bool, error) {\n\t_, err := u.computeService.Images.Get(u.projectID, imageName).Do()\n\tif err != nil {\n\t\tvar googleErr *googleapi.Error\n\t\tif errors.As(err, &googleErr) {\n\t\t\tif googleErr.Code == http.StatusNotFound {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}\n\n\t\treturn false, fmt.Errorf(\"gcp: failed to get image %s: %w\", imageName, err)\n\t}\n\n\treturn true, nil\n}\n\nfunc (u *GCPUploder) insertImage(imageName, arch string) (operationID, imageLink string, err error) {\n\tvar archImage string\n\n\tswitch arch {\n\tcase \"amd64\":\n\t\tarchImage = \"x86_64\"\n\tcase \"arm64\":\n\t\tarchImage = \"ARM64\"\n\tdefault:\n\t\treturn \"\", \"\", fmt.Errorf(\"gcp: unknown architecture %s\", arch)\n\t}\n\n\top, err := u.computeService.Images.Insert(u.projectID, &compute.Image{\n\t\tArchitecture: archImage,\n\t\tDescription:  fmt.Sprintf(\"Talos %s %s\", u.Options.Tag, arch),\n\t\tGuestOsFeatures: []*compute.GuestOsFeature{\n\t\t\t{\n\t\t\t\tType: \"VIRTIO_SCSI_MULTIQUEUE\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tType: \"UEFI_COMPATIBLE\",\n\t\t\t},\n\t\t},\n\t\tName: imageName,\n\t\tRawDisk: &compute.ImageRawDisk{\n\t\t\tSource: u.imagePath,\n\t\t},\n\t\tShieldedInstanceInitialState: &compute.InitialStateConfig{},\n\t}).Do()\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"gcp: failed to insert image: %w\", err)\n\t}\n\n\tif op.HTTPStatusCode != http.StatusOK {\n\t\treturn \"\", \"\", fmt.Errorf(\"gcp: insert image failed with http error message: %s\", op.HttpErrorMessage)\n\t}\n\n\tif op.Error != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"gcp: insert image failed with error message: %s\", op.Error.Errors[0].Message)\n\t}\n\n\tlog.Printf(\"gcp: image %s is being created with operation %s\", imageName, op.Name)\n\n\treturn op.Name, op.TargetLink, nil\n}\n\nfunc (u *GCPUploder) deleteImage(imageName string) error {\n\tif _, err := u.computeService.Images.Delete(u.projectID, imageName).Do(); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to delete image %s: %w\", imageName, err)\n\t}\n\n\tif err := retry.Constant(5*time.Minute, retry.WithUnits(30*time.Second)).Retry(func() error {\n\t\t_, err := u.computeService.Images.Get(u.projectID, imageName).Do()\n\t\tif err != nil {\n\t\t\tvar googleErr *googleapi.Error\n\n\t\t\tif errors.As(err, &googleErr) {\n\t\t\t\tif googleErr.Code == http.StatusNotFound {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn retry.ExpectedError(fmt.Errorf(\"gcp: image %s still exists\", imageName))\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"gcp: failed to delete image %s: %w\", imageName, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/go.mod",
    "content": "module github.com/siderolabs/cloud-image-uploader\n\ngo 1.26.0\n\nrequire (\n\tcloud.google.com/go/storage v1.61.3\n\tgithub.com/aws/aws-sdk-go-v2 v1.41.4\n\tgithub.com/aws/aws-sdk-go-v2/config v1.32.12\n\tgithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.8\n\tgithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.1\n\tgithub.com/aws/aws-sdk-go-v2/service/s3 v1.97.1\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/klauspost/compress v1.18.4\n\tgithub.com/siderolabs/gen v0.8.6\n\tgithub.com/siderolabs/go-pointer v1.0.1\n\tgithub.com/siderolabs/go-retry v0.3.3\n\tgithub.com/spf13/pflag v1.0.10\n\tgolang.org/x/sync v0.20.0\n\tgoogle.golang.org/api v0.271.0\n)\n\nrequire (\n\tcel.dev/expr v0.25.1 // indirect\n\tcloud.google.com/go v0.123.0 // indirect\n\tcloud.google.com/go/auth v0.18.2 // indirect\n\tcloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect\n\tcloud.google.com/go/compute/metadata v0.9.0 // indirect\n\tcloud.google.com/go/iam v1.5.3 // indirect\n\tcloud.google.com/go/monitoring v1.24.3 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.19.12 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9 // indirect\n\tgithub.com/aws/smithy-go v1.24.2 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect\n\tgithub.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect\n\tgithub.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/go-jose/go-jose/v4 v4.1.3 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/s2a-go v0.1.9 // indirect\n\tgithub.com/googleapis/enterprise-certificate-proxy v0.3.14 // indirect\n\tgithub.com/googleapis/gax-go/v2 v2.17.0 // indirect\n\tgithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect\n\tgithub.com/spiffe/go-spiffe/v2 v2.6.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect\n\tgo.opentelemetry.io/otel v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.40.0 // indirect\n\tgolang.org/x/crypto v0.48.0 // indirect\n\tgolang.org/x/net v0.51.0 // indirect\n\tgolang.org/x/oauth2 v0.36.0 // indirect\n\tgolang.org/x/sys v0.42.0 // indirect\n\tgolang.org/x/text v0.34.0 // indirect\n\tgolang.org/x/time v0.15.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect\n\tgoogle.golang.org/grpc v1.79.2 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n)\n"
  },
  {
    "path": "hack/cloud-image-uploader/go.sum",
    "content": "cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=\ncloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=\ncloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=\ncloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=\ncloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=\ncloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=\ncloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=\ncloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=\ncloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY=\ncloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw=\ncloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8=\ncloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk=\ncloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=\ncloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=\ncloud.google.com/go/storage v1.61.3 h1:VS//ZfBuPGDvakfD9xyPW1RGF1Vy3BWUoVZXgW1KMOg=\ncloud.google.com/go/storage v1.61.3/go.mod h1:JtqK8BBB7TWv0HVGHubtUdzYYrakOQIsMLffZ2Z/HWk=\ncloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=\ncloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=\ngithub.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=\ngithub.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7 h1:3kGOqnh1pPeddVa/E37XNTaWJ8W6vrbYV9lJEkCnhuY=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE=\ngithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.8 h1:nuc44j+otOY0d1e+CWwB6zul57d2YEGlgCyiq3SL0lI=\ngithub.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.8/go.mod h1:qSFgGCN8fjdhvlLhTPZdWRWXbwfeZZWF2FEaIplYPhE=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21 h1:SwGMTMLIlvDNyhMteQ6r8IJSBPlRdXX5d4idhIGbkXA=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21/go.mod h1:UUxgWxofmOdAMuqEsSppbDtGKLfR04HGsD0HXzvhI1k=\ngithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.1 h1:c2BbWVkQ0hVqls6SruYCRxfN5W46qvL+hIg7VLhXpg8=\ngithub.com/aws/aws-sdk-go-v2/service/ec2 v1.294.1/go.mod h1:T6ndRfdhnXLIY5oKBHjYZDVj706los2zGdpThppquvA=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12 h1:qtJZ70afD3ISKWnoX3xB0J2otEqu3LqicRcDBqsj0hQ=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12/go.mod h1:v2pNpJbRNl4vEUWEh5ytQok0zACAKfdmKS51Hotc3pQ=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20 h1:siU1A6xjUZ2N8zjTHSXFhB9L/2OY8Dqs0xXiLjF30jA=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20/go.mod h1:4TLZCmVJDM3FOu5P5TJP0zOlu9zWgDWU7aUxWbr+rcw=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.97.1 h1:csi9NLpFZXb9fxY7rS1xVzgPRGMt7MSNWeQ6eo247kE=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.97.1/go.mod h1:qXVal5H0ChqXP63t6jze5LmFalc7+ZE7wOdLtZ0LCP0=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk=\ngithub.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=\ngithub.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=\ngithub.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=\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/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=\ngithub.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=\ngithub.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=\ngithub.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=\ngithub.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=\ngithub.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\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/googleapis/enterprise-certificate-proxy v0.3.14 h1:yh8ncqsbUY4shRD5dA6RlzjJaT4hi3kII+zYw8wmLb8=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.14/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=\ngithub.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=\ngithub.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=\ngithub.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=\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/siderolabs/gen v0.8.6 h1:pE6shuqov3L+5rEcAUJ/kY6iJofimljQw5G95P8a5c4=\ngithub.com/siderolabs/gen v0.8.6/go.mod h1:J9IbusbES2W6QWjtSHpDV9iPGZHc978h1+KJ4oQRspQ=\ngithub.com/siderolabs/go-pointer v1.0.1 h1:f7Yi4IK1jptS8yrT9GEbwhmGcVxvPQgBUG/weH3V3DM=\ngithub.com/siderolabs/go-pointer v1.0.1/go.mod h1:C8Q/3pNHT4RE9e4rYR9PHeS6KPMlStRBgYrJQJNy/vA=\ngithub.com/siderolabs/go-retry v0.3.3 h1:zKV+S1vumtO72E6sYsLlmIdV/G/GcYSBLiEx/c9oCEg=\ngithub.com/siderolabs/go-retry v0.3.3/go.mod h1:Ff/VGc7v7un4uQg3DybgrmOWHEmJ8BzZds/XNn/BqMI=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE=\ngo.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=\ngo.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=\ngo.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk=\ngo.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=\ngo.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=\ngo.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=\ngo.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=\ngo.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=\ngo.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=\ngo.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=\ngo.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=\ngolang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=\ngolang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=\ngolang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=\ngolang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=\ngolang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=\ngolang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=\ngolang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=\ngolang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=\ngolang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/api v0.271.0 h1:cIPN4qcUc61jlh7oXu6pwOQqbJW2GqYh5PS6rB2C/JY=\ngoogle.golang.org/api v0.271.0/go.mod h1:CGT29bhwkbF+i11qkRUJb2KMKqcJ1hdFceEIRd9u64Q=\ngoogle.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=\ngoogle.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 h1:7ei4lp52gK1uSejlA8AZl5AJjeLUOHBQscRQZUgAcu0=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20/go.mod h1:ZdbssH/1SOVnjnDlXzxDHK2MCidiqXtbYccJNzNYPEE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=\ngoogle.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "hack/cloud-image-uploader/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package main implements Talos cloud image uploader.\npackage main\n\nimport (\n\t\"context\"\n\tcryptorand \"crypto/rand\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"syscall\"\n\n\t\"github.com/spf13/pflag\"\n\t\"golang.org/x/sync/errgroup\"\n)\n\n// Result of the upload process.\ntype Result []CloudImage\n\n// CloudImage is the record official cloud image.\ntype CloudImage struct {\n\tCloud  string `json:\"cloud\"`\n\tTag    string `json:\"version\"`\n\tRegion string `json:\"region\"`\n\tArch   string `json:\"arch\"`\n\tType   string `json:\"type\"`\n\tID     string `json:\"id\"`\n}\n\nvar (\n\tresult   Result\n\tresultMu sync.Mutex\n)\n\nfunc pushResult(image CloudImage) {\n\tresultMu.Lock()\n\tdefer resultMu.Unlock()\n\n\tresult = append(result, image)\n}\n\nfunc main() {\n\tif err := run(); err != nil {\n\t\tlog.Fatalf(\"%s\", err)\n\t}\n}\n\n//nolint:gocyclo\nfunc run() error {\n\tvar err error\n\n\tpflag.StringSliceVar(&DefaultOptions.TargetClouds, \"target-clouds\", DefaultOptions.TargetClouds, \"cloud targets to upload to\")\n\tpflag.StringSliceVar(&DefaultOptions.Architectures, \"architectures\", DefaultOptions.Architectures, \"list of architectures to process\")\n\tpflag.StringVar(&DefaultOptions.ArtifactsPath, \"artifacts-path\", DefaultOptions.ArtifactsPath, \"artifacts path\")\n\tpflag.StringVar(&DefaultOptions.Tag, \"tag\", DefaultOptions.Tag, \"tag (version) of the uploaded image\")\n\tpflag.StringVar(&DefaultOptions.NamePrefix, \"name-prefix\", DefaultOptions.NamePrefix, \"prefix for the name of the uploaded image\")\n\n\tpflag.BoolVar(&DefaultOptions.UseFactory, \"use-factory\", DefaultOptions.UseFactory, \"whether to use factory to fetch images\")\n\tpflag.StringVar(&DefaultOptions.FactoryHost, \"factory-host\", DefaultOptions.FactoryHost, \"factory host to fetch images from\")\n\tpflag.StringArrayVar(&DefaultOptions.FactorySchematics, \"factory-schematics\", DefaultOptions.FactorySchematics, \"list of schematics to fetch from factory\")\n\n\tpflag.StringSliceVar(&DefaultOptions.AWSRegions, \"aws-regions\", DefaultOptions.AWSRegions, \"list of AWS regions to upload to\")\n\tpflag.BoolVar(&DefaultOptions.AWSForceBIOS, \"aws-force-bios\", DefaultOptions.AWSForceBIOS, \"force BIOS boot mode for AWS images\")\n\n\tpflag.Parse()\n\n\tseed := make([]byte, 8)\n\tif _, err = cryptorand.Read(seed); err != nil {\n\t\tlog.Fatalf(\"error seeding rand: %s\", err)\n\t}\n\n\tctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)\n\tdefer cancel()\n\n\tvar g *errgroup.Group\n\n\tg, ctx = errgroup.WithContext(ctx)\n\n\tfor _, target := range DefaultOptions.TargetClouds {\n\t\tswitch target {\n\t\tcase \"aws\":\n\t\t\tg.Go(func() error {\n\t\t\t\tif DefaultOptions.UseFactory {\n\t\t\t\t\tdownloader := FactoryDownloader{\n\t\t\t\t\t\tTarget:  target,\n\t\t\t\t\t\tOptions: DefaultOptions,\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := downloader.Download(ctx); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to download image: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif len(DefaultOptions.AWSRegions) == 0 {\n\t\t\t\t\tDefaultOptions.AWSRegions, err = GetAWSDefaultRegions(ctx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Printf(\"failed to get a list of enabled AWS regions: %s, ignored\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\taws := AWSUploader{\n\t\t\t\t\tOptions: DefaultOptions,\n\t\t\t\t}\n\n\t\t\t\treturn aws.Upload(ctx)\n\t\t\t})\n\t\tcase \"gcp\":\n\t\t\tg.Go(func() error {\n\t\t\t\tif DefaultOptions.UseFactory {\n\t\t\t\t\tdownloader := FactoryDownloader{\n\t\t\t\t\t\tTarget:  target,\n\t\t\t\t\t\tOptions: DefaultOptions,\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := downloader.Download(ctx); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to download image: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tgcp, err := NewGCPUploder(DefaultOptions)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create GCP uploader: %w\", err)\n\t\t\t\t}\n\n\t\t\t\treturn gcp.Upload(ctx)\n\t\t\t})\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown target: %s\", target)\n\t\t}\n\t}\n\n\tif err = g.Wait(); err != nil {\n\t\treturn fmt.Errorf(\"failed: %w\", err)\n\t}\n\n\tf, err := os.Create(filepath.Join(DefaultOptions.ArtifactsPath, \"cloud-images.json\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed: %w\", err)\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\te := json.NewEncoder(io.MultiWriter(os.Stdout, f))\n\te.SetIndent(\"\", \"  \")\n\n\treturn e.Encode(&result)\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// Options for the cli.\ntype Options struct {\n\tTag           string\n\tArtifactsPath string\n\tNamePrefix    string\n\tArchitectures []string\n\tTargetClouds  []string\n\n\t// ImageFactory options.\n\tUseFactory        bool\n\tFactoryHost       string\n\tFactorySchematics []string\n\n\t// AWS options.\n\tAWSRegions   []string\n\tAWSForceBIOS bool\n}\n\n// DefaultOptions used throughout the cli.\nvar DefaultOptions = Options{\n\tArtifactsPath: \"_out/\",\n\tArchitectures: []string{\"amd64\", \"arm64\"},\n\tTargetClouds:  []string{\"aws\"},\n\tFactoryHost:   \"https://factory.talos.dev\",\n\tFactorySchematics: []string{\n\t\t\"aws:10e276a06c1f86b182757a962258ac00655d3425e5957f617bdc82f06894e39b\",\n\t},\n}\n\n// AWSImage returns path to AWS pre-built image.\nfunc (o *Options) AWSImage(architecture string) string {\n\treturn filepath.Join(o.ArtifactsPath, fmt.Sprintf(\"aws-%s.raw.zst\", architecture))\n}\n\n// GCPImage returns path to GCP pre-built image.\nfunc (o *Options) GCPImage(architecture string) string {\n\treturn filepath.Join(o.ArtifactsPath, fmt.Sprintf(\"gcp-%s.raw.tar.gz\", architecture))\n}\n\n// SchematicFor returns the schematic for the given cloud.\nfunc (o *Options) SchematicFor(cloud string) string {\n\tfor _, schematic := range o.FactorySchematics {\n\t\tparts := strings.Split(schematic, \":\")\n\t\tif len(parts) != 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tcloudPart := parts[0]\n\t\tschematicPart := parts[1]\n\n\t\tif cloudPart == cloud {\n\t\t\treturn schematicPart\n\t\t}\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/role-policy.json",
    "content": "{\n   \"Version\":\"2012-10-17\",\n   \"Statement\":[\n      {\n         \"Effect\":\"Allow\",\n         \"Action\":[\n            \"s3:ListBucket\",\n            \"s3:GetBucketLocation\"\n         ],\n         \"Resource\":[\n            \"arn:aws:s3:::*\"\n         ]\n      },\n      {\n         \"Effect\":\"Allow\",\n         \"Action\":[\n            \"s3:GetObject\"\n         ],\n         \"Resource\":[\n            \"arn:aws:s3:::*/*\"\n         ]\n      },\n      {\n         \"Effect\":\"Allow\",\n         \"Action\":[\n            \"ec2:ModifySnapshotAttribute\",\n            \"ec2:CopySnapshot\",\n            \"ec2:RegisterImage\",\n            \"ec2:Describe*\"\n         ],\n         \"Resource\":\"*\"\n      }\n   ]\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader/trust-policy.json",
    "content": "{\n   \"Version\":\"2012-10-17\",\n   \"Statement\":[\n      {\n         \"Sid\":\"\",\n         \"Effect\":\"Allow\",\n         \"Principal\":{\n            \"Service\":\"vmie.amazonaws.com\"\n         },\n         \"Action\":\"sts:AssumeRole\",\n         \"Condition\":{\n            \"StringEquals\":{\n               \"sts:ExternalId\":\"vmimport\"\n            }\n         }\n      }\n   ]\n}\n"
  },
  {
    "path": "hack/cloud-image-uploader.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\ncd hack/cloud-image-uploader\n\ngo run . --artifacts-path=\"../../${ARTIFACTS}\" --tag=\"${TAG}\" \"$@\"\n"
  },
  {
    "path": "hack/containerd.toml",
    "content": "version = 3\n\ndisabled_plugins = [\n    \"io.containerd.cri.v1.images\",\n    \"io.containerd.cri.v1.runtime\",\n    \"io.containerd.differ.v1.erofs\",\n    \"io.containerd.grpc.v1.cri\",\n    \"io.containerd.grpc.v1.sandbox-controllers\",\n    \"io.containerd.grpc.v1.sandboxes\",\n    \"io.containerd.internal.v1.opt\",\n    \"io.containerd.internal.v1.tracing\",\n    \"io.containerd.monitor.container.v1.restart\",\n    \"io.containerd.nri.v1.nri\",\n    \"io.containerd.podsandbox.controller.v1.podsandbox\",\n    \"io.containerd.sandbox.controller.v1.podsandbox\",\n    \"io.containerd.sandbox.controller.v1.shim\",\n    \"io.containerd.sandbox.controller.v1\",\n    \"io.containerd.sandbox.store.v1.local\",\n    \"io.containerd.sandbox.store.v1\",\n    \"io.containerd.snapshotter.v1.blockfile\",\n    \"io.containerd.snapshotter.v1.erofs\",\n    \"io.containerd.ttrpc.v1.otelttrpc\",\n    \"io.containerd.tracing.processor.v1.otlp\",\n]\n\n[debug]\nlevel = \"info\"\nformat = \"json\"\n"
  },
  {
    "path": "hack/cri-containerd.toml",
    "content": "version = 3\n\ndisabled_plugins = [\n    \"io.containerd.differ.v1.erofs\",\n    \"io.containerd.internal.v1.tracing\",\n    \"io.containerd.snapshotter.v1.blockfile\",\n    \"io.containerd.snapshotter.v1.erofs\",\n    \"io.containerd.ttrpc.v1.otelttrpc\",\n    \"io.containerd.tracing.processor.v1.otlp\",\n]\n\nimports = [\n    \"/etc/cri/conf.d/cri.toml\",\n]\n\n[debug]\nlevel = \"info\"\nformat = \"json\"\n"
  },
  {
    "path": "hack/cri-plugin.part",
    "content": "version = 3\n\n[plugins.\"io.containerd.cri.v1.images\"]\n  discard_unpacked_layers = true\n  use_local_image_pull = true\n\n[plugins.\"io.containerd.cri.v1.runtime\"]\n  enable_cdi = true\n  cdi_spec_dirs = [\"/run/cdi\"]\n\n[plugins.\"io.containerd.cri.v1.runtime\".containerd.runtimes.runc]\n  base_runtime_spec = \"/etc/cri/conf.d/base-spec.json\"\n\n[plugins.\"io.containerd.nri.v1.nri\"]\n  disable = true\n"
  },
  {
    "path": "hack/extra-modules.conf",
    "content": "search extras built-in\n"
  },
  {
    "path": "hack/fix-artifacts.sh",
    "content": "#!/usr/bin/env bash\n\nfor platform in $(tr \",\" \"\\n\" <<< \"${PLATFORM}\"); do\n    echo ${platform}\n    directory=\"${platform//\\//_}\"\n\n    if [[ -d \"${ARTIFACTS}/${directory}\" ]]; then\n        mv \"${ARTIFACTS}/${directory}/\"* ${ARTIFACTS}\n\n        rmdir \"${ARTIFACTS}/${directory}/\"\n    fi\ndone\n"
  },
  {
    "path": "hack/labeled-squashfs.sh",
    "content": "#!/bin/bash\nset -eufx\n\nif [ $# -ne 4 ]; then\n  printf 'Usage: %s <root_dir> <output_image> <file_contexts> <compression_level>\\n' \"${0##*/}\"\n  exit 2\nfi\n\nroot_dir=$1;shift\noutput_image=$1;shift\nfile_contexts=$1;shift\ncompression_level=$1;shift\n\nif [ -n \"${file_contexts:-}\" ]; then\n  # set SELinux labels for files according to file_contexts supplied\n  setfiles -r \"${root_dir}\" -F -vv \"${file_contexts}\" \"${root_dir}\"\nfi\n\nmksquashfs \"${root_dir}\" \"${output_image}\" \\\n  -all-root -noappend \\\n  -comp zstd -Xcompression-level \"${compression_level}\" \\\n  -no-progress\n"
  },
  {
    "path": "hack/lvm.conf",
    "content": "# Disable LVM backups as Talos rootfs is read-only, and ephemeral partition is not a safe place to store\n# metadata backups.\n#\n# See https://github.com/siderolabs/talos/issues/3129\nbackup {\n    backup = 0\n    archive = 0\n}\n"
  },
  {
    "path": "hack/modules-amd64.txt",
    "content": "kernel/crypto/async_tx/async_memcpy.ko\nkernel/crypto/async_tx/async_pq.ko\nkernel/crypto/async_tx/async_raid6_recov.ko\nkernel/crypto/async_tx/async_tx.ko\nkernel/crypto/async_tx/async_xor.ko\nkernel/crypto/hkdf.ko\nkernel/crypto/xor.ko\nkernel/drivers/ata/ahci.ko\nkernel/drivers/ata/libahci.ko\nkernel/drivers/ata/pata_amd.ko\nkernel/drivers/ata/pata_marvell.ko\nkernel/drivers/ata/pata_oldpiix.ko\nkernel/drivers/ata/pata_sch.ko\nkernel/drivers/block/nbd.ko\nkernel/drivers/block/ublk_drv.ko\nkernel/drivers/char/hw_random/amd-rng.ko\nkernel/drivers/char/hw_random/ba431-rng.ko\nkernel/drivers/char/hw_random/intel-rng.ko\nkernel/drivers/char/hw_random/via-rng.ko\nkernel/drivers/char/hw_random/virtio-rng.ko\nkernel/drivers/char/hw_random/xiphera-trng.ko\nkernel/drivers/char/ipmi/ipmi_watchdog.ko\nkernel/drivers/edac/amd64_edac.ko\nkernel/drivers/edac/e752x_edac.ko\nkernel/drivers/edac/i3000_edac.ko\nkernel/drivers/edac/i3200_edac.ko\nkernel/drivers/edac/i5100_edac.ko\nkernel/drivers/edac/i5400_edac.ko\nkernel/drivers/edac/i7300_edac.ko\nkernel/drivers/edac/i7core_edac.ko\nkernel/drivers/edac/i82975x_edac.ko\nkernel/drivers/edac/ie31200_edac.ko\nkernel/drivers/edac/igen6_edac.ko\nkernel/drivers/edac/sb_edac.ko\nkernel/drivers/edac/skx_edac.ko\nkernel/drivers/edac/x38_edac.ko\nkernel/drivers/gpu/drm/display/drm_display_helper.ko\nkernel/drivers/gpu/drm/drm_buddy.ko\nkernel/drivers/gpu/drm/drm_exec.ko\nkernel/drivers/gpu/drm/drm_gpusvm_helper.ko\nkernel/drivers/gpu/drm/drm_gpuvm.ko\nkernel/drivers/gpu/drm/drm_panel_backlight_quirks.ko\nkernel/drivers/gpu/drm/drm_suballoc_helper.ko\nkernel/drivers/gpu/drm/drm_ttm_helper.ko\nkernel/drivers/gpu/drm/scheduler/gpu-sched.ko\nkernel/drivers/gpu/drm/ttm/ttm.ko\nkernel/drivers/hid/hid-a4tech.ko\nkernel/drivers/hid/hid-apple.ko\nkernel/drivers/hid/hid-belkin.ko\nkernel/drivers/hid/hid-cherry.ko\nkernel/drivers/hid/hid-chicony.ko\nkernel/drivers/hid/hid-cypress.ko\nkernel/drivers/hid/hid-ezkey.ko\nkernel/drivers/hid/hid-gyration.ko\nkernel/drivers/hid/hid-ite.ko\nkernel/drivers/hid/hid-kensington.ko\nkernel/drivers/hid/hid-lg-g15.ko\nkernel/drivers/hid/hid-logitech.ko\nkernel/drivers/hid/hid-microsoft.ko\nkernel/drivers/hid/hid-monterey.ko\nkernel/drivers/hid/hid-multitouch.ko\nkernel/drivers/hid/hid-petalynx.ko\nkernel/drivers/hid/hid-pl.ko\nkernel/drivers/hid/hid-samsung.ko\nkernel/drivers/hid/hid-sunplus.ko\nkernel/drivers/hid/hid-topseed.ko\nkernel/drivers/hwmon/fam15h_power.ko\nkernel/drivers/hwmon/i5500_temp.ko\nkernel/drivers/hwmon/i5k_amb.ko\nkernel/drivers/hwmon/it87.ko\nkernel/drivers/hwmon/k10temp.ko\nkernel/drivers/hwmon/k8temp.ko\nkernel/drivers/i2c/algos/i2c-algo-bit.ko\nkernel/drivers/i2c/busses/i2c-i801.ko\nkernel/drivers/i2c/i2c-smbus.ko\nkernel/drivers/infiniband/core/ib_umad.ko\nkernel/drivers/infiniband/core/ib_uverbs.ko\nkernel/drivers/infiniband/core/rdma_ucm.ko\nkernel/drivers/infiniband/hw/irdma/irdma.ko\nkernel/drivers/infiniband/hw/mlx4/mlx4_ib.ko\nkernel/drivers/infiniband/hw/mlx5/mlx5_ib.ko\nkernel/drivers/infiniband/sw/rxe/rdma_rxe.ko\nkernel/drivers/leds/led-class-multicolor.ko\nkernel/drivers/md/bcache/bcache.ko\nkernel/drivers/md/dm-bio-prison.ko\nkernel/drivers/md/dm-cache-smq.ko\nkernel/drivers/md/dm-cache.ko\nkernel/drivers/md/dm-integrity.ko\nkernel/drivers/md/dm-multipath.ko\nkernel/drivers/md/dm-raid.ko\nkernel/drivers/md/dm-round-robin.ko\nkernel/drivers/md/dm-thin-pool.ko\nkernel/drivers/md/persistent-data/dm-persistent-data.ko\nkernel/drivers/md/raid456.ko\nkernel/drivers/media/cec/core/cec.ko\nkernel/drivers/message/fusion/mptbase.ko\nkernel/drivers/message/fusion/mptsas.ko\nkernel/drivers/message/fusion/mptscsih.ko\nkernel/drivers/message/fusion/mptspi.ko\nkernel/drivers/mfd/lpc_ich.ko\nkernel/drivers/mfd/mfd-core.ko\nkernel/drivers/misc/hpilo.ko\nkernel/drivers/mmc/host/sdhci_f_sdh30.ko\nkernel/drivers/mmc/host/sdhci-acpi.ko\nkernel/drivers/mmc/host/sdhci-pci.ko\nkernel/drivers/mmc/host/sdhci-pltfm.ko\nkernel/drivers/mmc/host/sdhci-uhs2.ko\nkernel/drivers/mmc/host/sdhci-xenon-driver.ko\nkernel/drivers/net/ethernet/amazon/ena/ena.ko\nkernel/drivers/net/ethernet/aquantia/atlantic/atlantic.ko\nkernel/drivers/net/ethernet/atheros/alx/alx.ko\nkernel/drivers/net/ethernet/broadcom/bnx2.ko\nkernel/drivers/net/ethernet/broadcom/bnx2x/bnx2x.ko\nkernel/drivers/net/ethernet/broadcom/bnxt/bnxt_en.ko\nkernel/drivers/net/ethernet/broadcom/tg3.ko\nkernel/drivers/net/ethernet/cavium/common/cavium_ptp.ko\nkernel/drivers/net/ethernet/cisco/enic/enic.ko\nkernel/drivers/net/ethernet/emulex/benet/be2net.ko\nkernel/drivers/net/ethernet/google/gve/gve.ko\nkernel/drivers/net/ethernet/intel/e100.ko\nkernel/drivers/net/ethernet/intel/e1000/e1000.ko\nkernel/drivers/net/ethernet/intel/e1000e/e1000e.ko\nkernel/drivers/net/ethernet/intel/i40e/i40e.ko\nkernel/drivers/net/ethernet/intel/iavf/iavf.ko\nkernel/drivers/net/ethernet/intel/ice/ice.ko\nkernel/drivers/net/ethernet/intel/idpf/idpf.ko\nkernel/drivers/net/ethernet/intel/igb/igb.ko\nkernel/drivers/net/ethernet/intel/igbvf/igbvf.ko\nkernel/drivers/net/ethernet/intel/igc/igc.ko\nkernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko\nkernel/drivers/net/ethernet/intel/ixgbevf/ixgbevf.ko\nkernel/drivers/net/ethernet/intel/libeth/libeth_xdp.ko\nkernel/drivers/net/ethernet/intel/libeth/libeth.ko\nkernel/drivers/net/ethernet/intel/libie/libie_adminq.ko\nkernel/drivers/net/ethernet/intel/libie/libie_fwlog.ko\nkernel/drivers/net/ethernet/intel/libie/libie.ko\nkernel/drivers/net/ethernet/marvell/sky2.ko\nkernel/drivers/net/ethernet/mellanox/mlx4/mlx4_core.ko\nkernel/drivers/net/ethernet/mellanox/mlx4/mlx4_en.ko\nkernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko\nkernel/drivers/net/ethernet/mellanox/mlxfw/mlxfw.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_core.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_i2c.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_minimal.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_pci.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_spectrum.ko\nkernel/drivers/net/ethernet/qlogic/netxen/netxen_nic.ko\nkernel/drivers/net/ethernet/qlogic/qed/qed.ko\nkernel/drivers/net/ethernet/qlogic/qede/qede.ko\nkernel/drivers/net/ethernet/qlogic/qlcnic/qlcnic.ko\nkernel/drivers/net/ethernet/realtek/8139too.ko\nkernel/drivers/net/ethernet/realtek/r8169.ko\nkernel/drivers/net/ethernet/sfc/sfc.ko\nkernel/drivers/net/ethernet/sfc/siena/sfc-siena.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac-pci.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac-platform.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac.ko\nkernel/drivers/net/mdio.ko\nkernel/drivers/net/mii.ko\nkernel/drivers/net/pcs/pcs_xpcs.ko\nkernel/drivers/net/usb/r8152.ko\nkernel/drivers/net/vmxnet3/vmxnet3.ko\nkernel/drivers/net/vrf.ko\nkernel/drivers/nvme/common/nvme-auth.ko\nkernel/drivers/nvme/host/nvme-rdma.ko\nkernel/drivers/nvme/host/nvme.ko\nkernel/drivers/nvme/target/nvme-loop.ko\nkernel/drivers/nvme/target/nvmet-fc.ko\nkernel/drivers/nvme/target/nvmet-rdma.ko\nkernel/drivers/nvme/target/nvmet-tcp.ko\nkernel/drivers/nvme/target/nvmet.ko\nkernel/drivers/platform/x86/intel/intel-vsec.ko\nkernel/drivers/platform/x86/intel/pmc/intel_pmc_core_pltdrv.ko\nkernel/drivers/platform/x86/intel/pmc/intel_pmc_core.ko\nkernel/drivers/platform/x86/intel/pmc/intel_pmc_ssram_telemetry.ko\nkernel/drivers/platform/x86/intel/pmt/pmt_class.ko\nkernel/drivers/platform/x86/intel/pmt/pmt_discovery.ko\nkernel/drivers/platform/x86/intel/pmt/pmt_telemetry.ko\nkernel/drivers/powercap/intel_rapl_common.ko\nkernel/drivers/powercap/intel_rapl_msr.ko\nkernel/drivers/scsi/aacraid/aacraid.ko\nkernel/drivers/scsi/fcoe/libfcoe.ko\nkernel/drivers/scsi/fnic/fnic.ko\nkernel/drivers/scsi/hpsa.ko\nkernel/drivers/scsi/isci/isci.ko\nkernel/drivers/scsi/libfc/libfc.ko\nkernel/drivers/scsi/lpfc/lpfc.ko\nkernel/drivers/scsi/megaraid/megaraid_sas.ko\nkernel/drivers/scsi/mpi3mr/mpi3mr.ko\nkernel/drivers/scsi/mpt3sas/mpt3sas.ko\nkernel/drivers/scsi/qedf/qedf.ko\nkernel/drivers/scsi/qla2xxx/qla2xxx.ko\nkernel/drivers/scsi/smartpqi/smartpqi.ko\nkernel/drivers/scsi/vmw_pvscsi.ko\nkernel/drivers/uio/uio_pci_generic.ko\nkernel/drivers/uio/uio.ko\nkernel/drivers/usb/serial/ch341.ko\nkernel/drivers/usb/serial/cp210x.ko\nkernel/drivers/usb/serial/ftdi_sio.ko\nkernel/drivers/usb/serial/pl2303.ko\nkernel/drivers/vdpa/alibaba/eni_vdpa.ko\nkernel/drivers/vdpa/mlx5/mlx5_vdpa.ko\nkernel/drivers/vdpa/octeon_ep/octep_vdpa.ko\nkernel/drivers/vdpa/solidrun/snet_vdpa.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim_blk.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim_net.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim.ko\nkernel/drivers/vdpa/vdpa_user/vduse.ko\nkernel/drivers/vdpa/vdpa.ko\nkernel/drivers/vdpa/virtio_pci/vp_vdpa.ko\nkernel/drivers/vfio/pci/vfio-pci-core.ko\nkernel/drivers/vfio/pci/vfio-pci.ko\nkernel/drivers/vfio/vfio_iommu_type1.ko\nkernel/drivers/vfio/vfio.ko\nkernel/drivers/vhost/vhost_vdpa.ko\nkernel/drivers/vhost/vringh.ko\nkernel/drivers/virt/coco/guest/tsm_report.ko\nkernel/drivers/virt/coco/sev-guest/sev-guest.ko\nkernel/drivers/virtio/virtio_balloon.ko\nkernel/drivers/virtio/virtio_mem.ko\nkernel/drivers/virtio/virtio_pci_legacy_dev.ko\nkernel/drivers/virtio/virtio_pci_modern_dev.ko\nkernel/drivers/virtio/virtio_pci.ko\nkernel/drivers/virtio/virtio_vdpa.ko\nkernel/drivers/watchdog/f71808e_wdt.ko\nkernel/drivers/watchdog/i6300esb.ko\nkernel/drivers/watchdog/iTCO_vendor_support.ko\nkernel/drivers/watchdog/iTCO_wdt.ko\nkernel/drivers/watchdog/sp5100_tco.ko\nkernel/drivers/watchdog/watchdog.ko\nkernel/drivers/watchdog/wdat_wdt.ko\nkernel/drivers/watchdog/xen_wdt.ko\nkernel/lib/crc/crc8.ko\nkernel/lib/objagg.ko\nkernel/lib/parman.ko\nkernel/lib/raid6/raid6_pq.ko\nkernel/net/ipv4/ip_gre.ko\nkernel/net/ipv6/ip6_gre.ko\nkernel/net/openvswitch/vport-gre.ko\nkernel/net/tls/tls.ko\nmodules.builtin\nmodules.builtin.modinfo\nmodules.order\n"
  },
  {
    "path": "hack/modules-arm64.txt",
    "content": "kernel/arch/arm64/lib/xor-neon.ko\nkernel/crypto/async_tx/async_memcpy.ko\nkernel/crypto/async_tx/async_pq.ko\nkernel/crypto/async_tx/async_raid6_recov.ko\nkernel/crypto/async_tx/async_tx.ko\nkernel/crypto/async_tx/async_xor.ko\nkernel/crypto/hkdf.ko\nkernel/crypto/xor.ko\nkernel/drivers/acpi/video.ko\nkernel/drivers/ata/ahci.ko\nkernel/drivers/ata/pata_amd.ko\nkernel/drivers/ata/pata_marvell.ko\nkernel/drivers/ata/pata_oldpiix.ko\nkernel/drivers/ata/pata_sch.ko\nkernel/drivers/block/nbd.ko\nkernel/drivers/block/ublk_drv.ko\nkernel/drivers/crypto/tegra/tegra-se.ko\nkernel/drivers/gpu/drm/drm_buddy.ko\nkernel/drivers/gpu/drm/drm_exec.ko\nkernel/drivers/gpu/drm/drm_gpuvm.ko\nkernel/drivers/gpu/drm/drm_panel_backlight_quirks.ko\nkernel/drivers/gpu/drm/drm_suballoc_helper.ko\nkernel/drivers/gpu/drm/drm_ttm_helper.ko\nkernel/drivers/gpu/drm/drm_vram_helper.ko\nkernel/drivers/gpu/drm/hisilicon/hibmc/hibmc-drm.ko\nkernel/drivers/gpu/drm/scheduler/gpu-sched.ko\nkernel/drivers/gpu/drm/tegra/tegra-drm.ko\nkernel/drivers/gpu/drm/ttm/ttm.ko\nkernel/drivers/gpu/host1x/host1x.ko\nkernel/drivers/hid/hid-a4tech.ko\nkernel/drivers/hid/hid-apple.ko\nkernel/drivers/hid/hid-belkin.ko\nkernel/drivers/hid/hid-cherry.ko\nkernel/drivers/hid/hid-chicony.ko\nkernel/drivers/hid/hid-cypress.ko\nkernel/drivers/hid/hid-ezkey.ko\nkernel/drivers/hid/hid-gyration.ko\nkernel/drivers/hid/hid-ite.ko\nkernel/drivers/hid/hid-kensington.ko\nkernel/drivers/hid/hid-lg-g15.ko\nkernel/drivers/hid/hid-logitech.ko\nkernel/drivers/hid/hid-microsoft.ko\nkernel/drivers/hid/hid-monterey.ko\nkernel/drivers/hid/hid-multitouch.ko\nkernel/drivers/hid/hid-petalynx.ko\nkernel/drivers/hid/hid-pl.ko\nkernel/drivers/hid/hid-samsung.ko\nkernel/drivers/hid/hid-sunplus.ko\nkernel/drivers/hid/hid-topseed.ko\nkernel/drivers/hwmon/i5k_amb.ko\nkernel/drivers/i2c/algos/i2c-algo-bit.ko\nkernel/drivers/i2c/busses/i2c-i801.ko\nkernel/drivers/i2c/i2c-mux.ko\nkernel/drivers/infiniband/core/ib_umad.ko\nkernel/drivers/infiniband/core/ib_uverbs.ko\nkernel/drivers/infiniband/core/rdma_ucm.ko\nkernel/drivers/infiniband/hw/hns/hns-roce-hw-v2.ko\nkernel/drivers/infiniband/hw/irdma/irdma.ko\nkernel/drivers/infiniband/hw/mlx4/mlx4_ib.ko\nkernel/drivers/infiniband/hw/mlx5/mlx5_ib.ko\nkernel/drivers/infiniband/sw/rxe/rdma_rxe.ko\nkernel/drivers/irqchip/irq-bcm2712-mip.ko\nkernel/drivers/irqchip/irq-imx-mu-msi.ko\nkernel/drivers/leds/led-class-multicolor.ko\nkernel/drivers/mailbox/bcm-flexrm-mailbox.ko\nkernel/drivers/md/bcache/bcache.ko\nkernel/drivers/md/dm-bio-prison.ko\nkernel/drivers/md/dm-cache-smq.ko\nkernel/drivers/md/dm-cache.ko\nkernel/drivers/md/dm-integrity.ko\nkernel/drivers/md/dm-multipath.ko\nkernel/drivers/md/dm-raid.ko\nkernel/drivers/md/dm-round-robin.ko\nkernel/drivers/md/dm-thin-pool.ko\nkernel/drivers/md/persistent-data/dm-persistent-data.ko\nkernel/drivers/md/raid456.ko\nkernel/drivers/misc/hpilo.ko\nkernel/drivers/mmc/host/sdhci_f_sdh30.ko\nkernel/drivers/mmc/host/sdhci-acpi.ko\nkernel/drivers/mmc/host/sdhci-brcmstb.ko\nkernel/drivers/mmc/host/sdhci-cadence.ko\nkernel/drivers/mmc/host/sdhci-iproc.ko\nkernel/drivers/mmc/host/sdhci-msm.ko\nkernel/drivers/mmc/host/sdhci-of-arasan.ko\nkernel/drivers/mmc/host/sdhci-of-dwcmshc.ko\nkernel/drivers/mmc/host/sdhci-of-esdhc.ko\nkernel/drivers/mmc/host/sdhci-pci.ko\nkernel/drivers/mmc/host/sdhci-pltfm.ko\nkernel/drivers/mmc/host/sdhci-tegra.ko\nkernel/drivers/mmc/host/sdhci-uhs2.ko\nkernel/drivers/mmc/host/sdhci-xenon-driver.ko\nkernel/drivers/net/ethernet/amazon/ena/ena.ko\nkernel/drivers/net/ethernet/aquantia/atlantic/atlantic.ko\nkernel/drivers/net/ethernet/atheros/alx/alx.ko\nkernel/drivers/net/ethernet/broadcom/bnx2.ko\nkernel/drivers/net/ethernet/broadcom/bnx2x/bnx2x.ko\nkernel/drivers/net/ethernet/broadcom/bnxt/bnxt_en.ko\nkernel/drivers/net/ethernet/broadcom/tg3.ko\nkernel/drivers/net/ethernet/cavium/common/cavium_ptp.ko\nkernel/drivers/net/ethernet/cisco/enic/enic.ko\nkernel/drivers/net/ethernet/google/gve/gve.ko\nkernel/drivers/net/ethernet/hisilicon/hip04_eth.ko\nkernel/drivers/net/ethernet/hisilicon/hisi_femac.ko\nkernel/drivers/net/ethernet/hisilicon/hix5hd2_gmac.ko\nkernel/drivers/net/ethernet/hisilicon/hns_mdio.ko\nkernel/drivers/net/ethernet/hisilicon/hns/hnae.ko\nkernel/drivers/net/ethernet/hisilicon/hns/hns_dsaf.ko\nkernel/drivers/net/ethernet/hisilicon/hns/hns_enet_drv.ko\nkernel/drivers/net/ethernet/hisilicon/hns3/hclge-common.ko\nkernel/drivers/net/ethernet/hisilicon/hns3/hclge.ko\nkernel/drivers/net/ethernet/hisilicon/hns3/hclgevf.ko\nkernel/drivers/net/ethernet/hisilicon/hns3/hnae3.ko\nkernel/drivers/net/ethernet/hisilicon/hns3/hns3.ko\nkernel/drivers/net/ethernet/intel/e100.ko\nkernel/drivers/net/ethernet/intel/e1000/e1000.ko\nkernel/drivers/net/ethernet/intel/e1000e/e1000e.ko\nkernel/drivers/net/ethernet/intel/i40e/i40e.ko\nkernel/drivers/net/ethernet/intel/iavf/iavf.ko\nkernel/drivers/net/ethernet/intel/ice/ice.ko\nkernel/drivers/net/ethernet/intel/idpf/idpf.ko\nkernel/drivers/net/ethernet/intel/igb/igb.ko\nkernel/drivers/net/ethernet/intel/igbvf/igbvf.ko\nkernel/drivers/net/ethernet/intel/igc/igc.ko\nkernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko\nkernel/drivers/net/ethernet/intel/ixgbevf/ixgbevf.ko\nkernel/drivers/net/ethernet/intel/libeth/libeth_xdp.ko\nkernel/drivers/net/ethernet/intel/libeth/libeth.ko\nkernel/drivers/net/ethernet/intel/libie/libie_adminq.ko\nkernel/drivers/net/ethernet/intel/libie/libie_fwlog.ko\nkernel/drivers/net/ethernet/intel/libie/libie.ko\nkernel/drivers/net/ethernet/marvell/sky2.ko\nkernel/drivers/net/ethernet/mellanox/mlx4/mlx4_core.ko\nkernel/drivers/net/ethernet/mellanox/mlx4/mlx4_en.ko\nkernel/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.ko\nkernel/drivers/net/ethernet/mellanox/mlxfw/mlxfw.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_core.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_i2c.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_minimal.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_pci.ko\nkernel/drivers/net/ethernet/mellanox/mlxsw/mlxsw_spectrum.ko\nkernel/drivers/net/ethernet/qlogic/qed/qed.ko\nkernel/drivers/net/ethernet/qlogic/qede/qede.ko\nkernel/drivers/net/ethernet/qlogic/qlcnic/qlcnic.ko\nkernel/drivers/net/ethernet/realtek/8139too.ko\nkernel/drivers/net/ethernet/realtek/r8169.ko\nkernel/drivers/net/ethernet/sfc/sfc.ko\nkernel/drivers/net/ethernet/sfc/siena/sfc-siena.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac-pci.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac-platform.ko\nkernel/drivers/net/ethernet/stmicro/stmmac/stmmac.ko\nkernel/drivers/net/mdio.ko\nkernel/drivers/net/pcs/pcs_xpcs.ko\nkernel/drivers/net/phy/dp83867.ko\nkernel/drivers/net/usb/r8152.ko\nkernel/drivers/net/vmxnet3/vmxnet3.ko\nkernel/drivers/net/vrf.ko\nkernel/drivers/nvme/common/nvme-auth.ko\nkernel/drivers/nvme/host/nvme-rdma.ko\nkernel/drivers/nvme/host/nvme.ko\nkernel/drivers/nvme/target/nvme-loop.ko\nkernel/drivers/nvme/target/nvmet-fc.ko\nkernel/drivers/nvme/target/nvmet-rdma.ko\nkernel/drivers/nvme/target/nvmet-tcp.ko\nkernel/drivers/nvme/target/nvmet.ko\nkernel/drivers/perf/hisilicon/hisi_pcie_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_hha_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_pa_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.ko\nkernel/drivers/perf/hisilicon/hisi_uncore_uc_pmu.ko\nkernel/drivers/perf/hisilicon/hns3_pmu.ko\nkernel/drivers/scsi/fcoe/libfcoe.ko\nkernel/drivers/scsi/hisi_sas/hisi_sas_main.ko\nkernel/drivers/scsi/hisi_sas/hisi_sas_v1_hw.ko\nkernel/drivers/scsi/hisi_sas/hisi_sas_v2_hw.ko\nkernel/drivers/scsi/hisi_sas/hisi_sas_v3_hw.ko\nkernel/drivers/scsi/hpsa.ko\nkernel/drivers/scsi/libfc/libfc.ko\nkernel/drivers/scsi/lpfc/lpfc.ko\nkernel/drivers/scsi/megaraid/megaraid_sas.ko\nkernel/drivers/scsi/mpi3mr/mpi3mr.ko\nkernel/drivers/scsi/mpt3sas/mpt3sas.ko\nkernel/drivers/scsi/qedf/qedf.ko\nkernel/drivers/scsi/qla2xxx/qla2xxx.ko\nkernel/drivers/scsi/smartpqi/smartpqi.ko\nkernel/drivers/uio/uio_pci_generic.ko\nkernel/drivers/uio/uio.ko\nkernel/drivers/usb/serial/ch341.ko\nkernel/drivers/usb/serial/cp210x.ko\nkernel/drivers/usb/serial/ftdi_sio.ko\nkernel/drivers/usb/serial/pl2303.ko\nkernel/drivers/vdpa/mlx5/mlx5_vdpa.ko\nkernel/drivers/vdpa/octeon_ep/octep_vdpa.ko\nkernel/drivers/vdpa/solidrun/snet_vdpa.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim_blk.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim_net.ko\nkernel/drivers/vdpa/vdpa_sim/vdpa_sim.ko\nkernel/drivers/vdpa/vdpa_user/vduse.ko\nkernel/drivers/vdpa/vdpa.ko\nkernel/drivers/vdpa/virtio_pci/vp_vdpa.ko\nkernel/drivers/vfio/pci/vfio-pci-core.ko\nkernel/drivers/vfio/pci/vfio-pci.ko\nkernel/drivers/vfio/vfio_iommu_type1.ko\nkernel/drivers/vfio/vfio.ko\nkernel/drivers/vhost/vhost_vdpa.ko\nkernel/drivers/vhost/vringh.ko\nkernel/drivers/virtio/virtio_balloon.ko\nkernel/drivers/virtio/virtio_input.ko\nkernel/drivers/virtio/virtio_mmio.ko\nkernel/drivers/virtio/virtio_pci_legacy_dev.ko\nkernel/drivers/virtio/virtio_pci_modern_dev.ko\nkernel/drivers/virtio/virtio_pci.ko\nkernel/drivers/virtio/virtio_vdpa.ko\nkernel/drivers/watchdog/sbsa_gwdt.ko\nkernel/lib/objagg.ko\nkernel/lib/parman.ko\nkernel/lib/raid6/raid6_pq.ko\nkernel/net/ipv4/ip_gre.ko\nkernel/net/ipv6/ip6_gre.ko\nkernel/net/openvswitch/vport-gre.ko\nkernel/net/tls/tls.ko\nmodules.builtin\nmodules.builtin.modinfo\nmodules.order\n"
  },
  {
    "path": "hack/nfsmount.conf",
    "content": "[ NFSMount_Global_Options ]\n    nolock=true\n"
  },
  {
    "path": "hack/release.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\n\nRELEASE_TOOL_IMAGE=\"ghcr.io/siderolabs/release-tool:latest\"\n\nfunction release-tool {\n  docker pull \"${RELEASE_TOOL_IMAGE}\" >/dev/null\n  docker run --net=host --rm -w /src -v \"${PWD}\":/src:ro \"${RELEASE_TOOL_IMAGE}\" -l -d -n ${2} -t \"${1}\" ./hack/release.toml\n}\n\nfunction changelog {\n  if [ \"$#\" -eq 1 ]; then\n    (release-tool ${1}; echo; cat CHANGELOG.md) > CHANGELOG.md- && mv CHANGELOG.md- CHANGELOG.md\n  else\n    echo 1>&2 \"Usage: $0 changelog [tag]\"\n    exit 1\n  fi\n}\n\nfunction release-notes {\n  release-tool \"${2}\" --gfm > \"${1}\"\n\n  echo -e '\\n## Images\\n\\n```' >> ${1}\n  ${ARTIFACTS}/talosctl-linux-amd64 image k8s-bundle >> ${1}\n  ${ARTIFACTS}/talosctl-linux-amd64 image talos-bundle --overlays=false --extensions=false >> ${1}\n  echo -e '```\\n' >> ${1}\n}\n\nfunction cherry-pick {\n  if [ $# -ne 2 ]; then\n    echo 1>&2 \"Usage: $0 cherry-pick <commit> <branch>\"\n    exit 1\n  fi\n\n  git checkout $2\n  git fetch\n  git rebase upstream/$2\n  git cherry-pick -x $1\n}\n\nfunction commit {\n  if [ $# -ne 1 ]; then\n    echo 1>&2 \"Usage: $0 commit <tag>\"\n    exit 1\n  fi\n\n  git commit -s -m \"release($1): prepare release\" -m \"This is the official $1 release.\"\n}\n\nif declare -f \"$1\" > /dev/null\nthen\n  cmd=\"$1\"\n  shift\n  $cmd \"$@\"\nelse\n  cat <<EOF\nUsage:\n  commit:        Create the official release commit message.\n  cherry-pick:   Cherry-pick a commit into a release branch.\n  changelog:     Update the specified CHANGELOG.\n  release-notes: Create release notes for GitHub release.\nEOF\n\n  exit 1\nfi\n"
  },
  {
    "path": "hack/release.toml",
    "content": "# commit to be tagged for new release\ncommit = \"HEAD\"\n\nproject_name = \"Talos\"\ngithub_repo = \"siderolabs/talos\"\nmatch_deps = \"^github.com/((talos-systems|siderolabs)/[a-zA-Z0-9-]+)$\"\nignore_deps = [\"github.com/coredns/coredns\"]\n\n# previous release\nprevious = \"v1.12.0\"\n\npre_release = true\n\npreface = \"\"\"\n\"\"\"\n\n[notes]\n    [notes.updates]\n        title = \"Component Updates\"\n        description = \"\"\"\\\nLinux: 6.18.18\ncontainerd: 2.2.2\netcd: 3.6.8\nCoreDNS: 1.14.2\nKubernetes: 1.36.0-alpha.2\nFlannel CNI plugin: v1.9.0-flannel1\nFlannel: 0.28.1\nLVM2: 2_03_38\nrunc: 1.4.1\nsystemd: 259.5\ncryptsetup: 2.8.3\nTenstorrent: 2.7.0\niptables: 1.8.12\n\nTalos is built with Go 1.26.1.\n\"\"\"\n\n    [notes.external_volumes]\n        title = \"External Volumes\"\n        description = \"\"\"\\\nTalos now supports virtiofs-based external volumes via the new\n[ExternalVolumeConfig](https://www.talos.dev/v1.13/reference/configuration/block/externalvolumeconfig/)\ndocument.\n\nThese virtiofs external volumes are not supported when SELinux is running\nin enforcing mode.\n\"\"\"\n\n    [notes.procpidmem]\n        title = \"/proc/PID/mem Access Hardening\"\n        description = \"\"\"\\\nA new kernel parameter `proc_mem.force_override=never` has been introduced by default to enhance system security\nby preventing unwanted writes to protected process memory via `/proc/PID/mem`.\nIf the kernel parameter is removed, default behavior is restored, allowing access only if the process is traced.\n\"\"\"\n\n    [notes.pigz]\n        title = \"Container Image Decompression\"\n        description = \"\"\"\\\nTalos now ships with `igzip` (amd64) and `pigz` (arm64) to speed up container image decompression.\n\"\"\"\n\n    [notes.imager]\n        title = \"Talos Imager Enhancements\"\n        description = \"\"\"\\\nTalos imager now supports running rootless. `--privileged` and `-v /dev:/dev` are no longer required.\n\"\"\"\n\n    [notes.reproducible_images]\n        title = \"Reproducible Disk Images\"\n        description = \"\"\"\\\nTalos disk images are now reproducible. Building the same version of Talos multiple times will yield\nidentical disk images.\n\nNote: VHD and VMDK (Azure and VMware) images are not currently reproducible due to limitations in the underlying image creation tools.\nUsers verifying reproducible images should use raw images, verify checksums, and convert them to VHD/VMDK as needed.\n\"\"\"\n\n    [notes.vm]\n        title = \"VM Hot-Add Support\"\n        description = \"\"\"\\\nTalos now includes udev rules to support hot-adding of CPUs in virtualized environments.\n\"\"\"\n\n    [notest.interactive-installer]\n        title = \"Interactive Installer Removal\"\n        description = \"\"\"\\\nThe interactive installer mode has been removed from `talosctl apply-config` (`--mode=interactive`).\nIt has been deprecated since Talos v1.12.0, and now fully removed.\nThe related `GenerateConfiguration` API method has also been removed.\nUsers are encouraged to use other installation methods, such as using pre-generated configuration files, or using Omni.\n\"\"\"\n\n    [notes.k8s_ssa]\n        title = \"Kubernetes server-side apply\"\n        description = \"\"\"\\\nTalos now uses inventory backed server-side apply when applying bootsrap manifests (including `extraManifests` and `inlineManifests`).\nPurging of unneeded manifests is automatically performed.\nThe switch and inventory backfill is automatic and no action is needed from the user.\n\"\"\"\n\n    [notes.talosctl_images_talos_bundle]\n        title = \"`talosctl images talos-bundle` can ignore reaching to the registry\"\n        description = \"\"\"\\\nThe `talosctl images talos-bundle` command now accepts optional `--overlays` and `--extensions` flags.\nIf those are set to `false`, the command will not attempt to reach out to the container registry to fetch the latest versions and digests of the overlays and extensions.\n\"\"\"\n\n    [notes.images_k8s_bundle]\n        title = \"Talosctl images k8s-bundle subcommand accepts version parameter\"\n        description = \"\"\"\\\nThe `talosctl images k8s-bundle` command now accepts an optional version overrides arguments.\n\"\"\"\n\n    [notes.environment_config]\n        title = \"Environment Configuration Document\"\n        description = \"\"\"\\\nA new `EnvironmentConfig` document has been introduced to allow users to specify environment variables for Talos components.\nIt replaces and deprecates the previous method of setting environment variables via the `.machine.env` field.\n\nMultiple values for the same environment variable will replace previous values, with the last one taking precedence.\n\nTo remove an environment variable, remove it from the `EnvironmentConfig` document and restart the node.\n\"\"\"\n\n    [notes.kubespan]\n        title = \"KubeSpan Configuration\"\n        description = \"\"\"\\\nA new `KubeSpanConfig` document has been introduced to configure KubeSpan settings.\nIt replaces and deprecates the previous method of configuring KubeSpan via the `.machine.network.kubespan` field.\n\nThe old configuration field will continue to work for backward compatibility.\n\"\"\"\n\n    [notes.link_alias_config]\n        title = \"LinkAliasConfig Pattern-Based Multi-Alias\"\n        description = \"\"\"\\\n`LinkAliasConfig` now supports pattern-based alias names using `%d` format verb (e.g. `net%d`).\n\nWhen the alias name contains a `%d` format verb, the selector is allowed to match multiple links.\nEach matched link receives a sequential alias (e.g. `net0`, `net1`, ...) based on hardware address order\nof the links. Links already aliased by a previous config are automatically skipped.\n\nThis enables creating stable aliases from any N links using a single config document,\nuseful for `BondConfig` and `BridgeConfig` member interfaces on varying hardware.\n\"\"\"\n\n    [notes.extraArgs]\n        title = \"Extra Arguments accept slices in addition to strings\"\n        description = \"\"\"\\\nSeveral Talos configuration fields that previously accepted single string values for extra arguments have been updated to accept slices of strings as well.\nThis includes fields such as `.cluster.apiServer.extraArgs`.\n\nBREAKING: If you were relying on the resources EtcdConfigs, KubeletConfigs, ControllerManagerConfigs, SchedulerConfigs or APIServerConfigs, the protobuf format has changed from `map<string,string>` to `map<string,message>`.\n\"\"\"\n\n    [notes.serviceAccountIssuer]\n        title = \"Service Account Issuer configuration\"\n        description = \"\"\"\\\nIn API Server, passing extra args with `service-account-issuer` will append them after default value.\nThis allows easy migration, e.g. by changing `.cluster.controlPlane.endpoint` to new value, and keeping the old value in\n`.cluster.apiServer.extraArgs[\"service-account-issuer\"]`.\n\"\"\"\n\n    [notes.negativeMaxVolumeSize]\n    title = \"Negative Max Volume Size\"\n    description = \"\"\"\\\nNegative max size represents the amount of space to be left free on the device, rather than the size the volume should consume.\nFor example:\n    * a max size of \"-10GiB\" means the volume can grow to the available space minus 10GiB.\n    * a max size of \"-25%\" means the volume can grow to the available space minus 25%.\n\"\"\"\n\n    [notes.resolver_config]\n        title = \"ResolverConfig\"\n        description = \"\"\"\\\nThe nameservers configuration in machine configuration now overwrites any previous layers (defaults, platform, etc.) when specified.\nPreviously a smart merge was performed to keep IPv4/IPv6 nameservers from lower layers if the machine configuration specified only one type.\n\"\"\"\n\n    [notes.kernel_preempt]\n        title = \"Dynamic Linux Kernel Preemption Model\"\n        description = \"\"\"\\\nTalos Linux now defaults to dynamic Linux kernel preemption model, the default value `none` matches\nprevious version, but now with kernel argument `preempt=` the preemption model can be changed.\n\nSee [Linux kernel documentation](https://docs.kernel.org/admin-guide/kernel-parameters.html) for more\ninformation on supported values.\n\nThis change only applies to amd64 (x86_64) architecture.\n\"\"\"\n\n    [notes.probe_config]\n        title = \"ProbeConfig\"\n        description = \"\"\"\\\nThe TCPProbeConfig configuration document allows to configure TCP probes for network reachability checks.\nThis allows to define a custom connectivity condition.\n\"\"\"\n\n    [notes.images]\n        title = \"Image APIs Updated\"\n        description = \"\"\"\\\nTalos Linux provides new APIs to manage container images on the node: listing, pulling, importing and removing images.\nThe new pull APIs provides pull progress notifications.\n\nThe CLI commands `talosctl image pull`, `talosctl image list` and `talosctl image remove` have been updated to interact with the new APIs.\n\"\"\"\n\n    [notes.debug]\n        title = \"talosctl debug\"\n        description = \"\"\"\\\nTalos Linux now provides a way to run and attach to the privileged debug container with a user-provided container image.\nThe debug container might be used for troubleshooting and debugging purposes.\n\"\"\"\n\n    [notes.network-policy]\n        title = \"Flannel CNI with Network Policy Support\"\n        description = \"\"\"\\\nTalos Linux now supports optionally deploying Flannel CNI with [network policy support](https://kubernetes.io/docs/concepts/services-networking/network-policies/) enabled.\nThe network policy implementation is [kube-network-policies](https://github.com/kubernetes-sigs/kube-network-policies/).\n\nTo enable Flannel CNI with network policy support, use the following machine configuration patch:\n\n```yaml\ncluster:\n  network:\n    cni:\n      name: flannel\n      flannel:\n        kubeNetworkPoliciesEnabled: true\n```\n\n(If the cluster is already running, sync the bootstrap manifests after applying the patch to deploy the new CNI configuration.)\n\"\"\"\n\n    [notes.kubespan-filters]\n        title = \"KubeSpan Advertised Network Filters\"\n        description = \"\"\"\\\nKubeSpan now supports filtering of advertised networks using the `excludeAdvertisedNetworks` field in the `KubeSpanConfig` document.\nThis allows users to specify a list of CIDRs to exclude from the advertised networks. Please note that routing must be symmetric for any\npair of peers, so if one peer excludes a certain network, the other peer must also exclude it. In other words, for any given pair of peers,\nand any pair of their addresses, the traffic should either go through KubeSpan or not, but not one way or the other.\n\"\"\"\n\n    [notes.clang-thinlto]\n        title = \"Clang built kernel and ThinLTO\"\n        description = \"\"\"\\\nTalos now uses a kernel built using Clang compiler, and optimized using ThinLTO. This should bring a small performance improvement,\nalongside some hardening features, such as BTI on supported ARM systems.\n\"\"\"\n\n    [notes.vrf]\n        title = \"VRF Support\"\n        description = \"\"\"\\\nTalos now supports VRF (Virtual Routing and Forwarding) via the new `VRFConfig` machine config document.\n\"\"\"\n\n    [notes.image_signatures]\n        title = \"Container Image Signature Verification\"\n        description = \"\"\"\\\nTalos now supports machine-wide container image signature verification via the new `ImageVerificationConfig` machine config document.\n\nAny image which gets pulled on the node will be verified against the configured rules, and if no rule matches, it will be pulled without verification.\n\"\"\"\n\n    [notest.blackhole_routes]\n        title = \"Blackhole Route Support\"\n        description = \"\"\"\\\nTalos now supports blackhole routes via the new `BlackholeRouteConfig` machine config document.\n\"\"\"\n\n    [notes.install_upgrade_api]\n        title = \"Install and Upgrade API\"\n        description = \"\"\"\\\nTalos now exposes install and upgrade operations via the `LifecycleService` API, enabling programmatic installs and upgrades through a single, consistent interface.\nThe legacy upgrade API is deprecated; new integrations should migrate to `LifecycleService` for future compatibility.\n\"\"\"\n\n    [notes.talosctl_upgrade_lifecycle]\n        title = \"Lifecycle Upgrade in talosctl\"\n        description = \"\"\"\\\n`talosctl` upgrades now route through `LifecycleService`, aligning CLI behavior with the new install/upgrade API and unifying the upgrade path.\nThis change is transparent to users but standardizes the backend used for upgrades.\n\"\"\"\n\n    [notes.container_device_interface]\n        title = \"Container Device Interface\"\n        description = \"\"\"\\\nTalos now enables [CDI](https://github.com/cncf-tags/container-device-interface) by default and extension/extension services can bring in dynamic\nCDI spec files under `/run/cdi`.\n\"\"\"\n\n    [notes.nvidia]\n        title = \"NVIDIA GPU Support\"\n        description = \"\"\"\\\nTalos switched to using CDI and now supports configuring NVIDIA GPU via the gpu-operator helm chart.\nSee the documentation on [upgrade notes](https://docs.siderolabs.com/talos/v1.13/configure-your-talos-cluster/lifecycle-management/upgrading-talos#after-upgrade-to)\nfor more details on how to configure NVIDIA GPU support in Talos.\n\"\"\"\n\n    [notes.routing_rules]\n        title = \"Routing Rules Support\"\n        description = \"\"\"\\\nTalos now supports routing rules via the new `RoutingRuleConfig` machine config document.\n\"\"\"\n\n[make_deps]\n\n    [make_deps.tools]\n        variable = \"TOOLS\"\n        repository = \"github.com/siderolabs/tools\"\n\n    [make_deps.pkgs]\n        variable = \"PKGS\"\n        repository = \"github.com/siderolabs/pkgs\"\n"
  },
  {
    "path": "hack/sbom.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\nSYFT_FORMAT_PRETTY=1 SYFT_FORMAT_SPDX_JSON_DETERMINISTIC_UUID=1 \\\n\tgo tool \\\n\tgithub.com/anchore/syft/cmd/syft \\\n\tscan --from dir \"$1\" \\\n\t--select-catalogers \"+sbom-cataloger,go\" \\\n\t--source-name \"$NAME\" --source-version \"$TAG\" \\\n\t-o spdx-json > \"/rootfs/usr/share/spdx/$2\"\n"
  },
  {
    "path": "hack/start-registry-proxies.sh",
    "content": "#!/usr/bin/env bash\n\n# Sync changes with configuring-pull-through-cache.md.\n\nset -e\n\ndocker run -d -p 5000:5000 \\\n    -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \\\n    --restart always \\\n    --name registry-docker.io registry:2\n\ndocker run -d -p 5001:5000 \\\n    -e REGISTRY_PROXY_REMOTEURL=https://registry.k8s.io \\\n    --restart always \\\n    --name registry-registry.k8s.io registry:2\n\ndocker run -d -p 5003:5000 \\\n    -e REGISTRY_PROXY_REMOTEURL=https://gcr.io \\\n    --restart always \\\n    --name registry-gcr.io registry:2\n\ndocker run -d -p 5004:5000 \\\n    -e REGISTRY_PROXY_REMOTEURL=https://ghcr.io \\\n    --restart always \\\n    --name registry-ghcr.io registry:2\n\ndocker run -d -p 5006:5000 \\\n    -e REGISTRY_PROXY_REMOTEURL=https://factory.talos.dev \\\n    --restart always \\\n    --name registry-factory.talos.dev registry:2\n"
  },
  {
    "path": "hack/test/cis/kube-bench-master.yaml",
    "content": "apiVersion: batch/v1\nkind: Job\nmetadata:\n  name: kube-bench-master\nspec:\n  template:\n    spec:\n      hostPID: true\n      nodeSelector:\n        node-role.kubernetes.io/master: ''\n      tolerations:\n      - key: node-role.kubernetes.io/master\n        operator: Exists\n        effect: NoSchedule\n      containers:\n      - name: kube-bench\n        image: aquasec/kube-bench:latest\n        args:\n        - master\n        - --version=1.13\n        volumeMounts:\n        - name: etc-kubernetes\n          mountPath: /etc/kubernetes\n      volumes:\n      - name: etc-kubernetes\n        hostPath:\n          path: /etc/kubernetes\n          type: Directory\n      restartPolicy: Never\n  backoffLimit: 0\n"
  },
  {
    "path": "hack/test/cis/kube-bench-node.yaml",
    "content": "apiVersion: batch/v1\nkind: Job\nmetadata:\n  name: kube-bench-node\nspec:\n  template:\n    spec:\n      hostPID: true\n      containers:\n      - name: kube-bench\n        image: aquasec/kube-bench:latest\n        args:\n        - node\n        - --version=1.13\n        volumeMounts:\n        - name: etc-kubernetes\n          mountPath: /etc/kubernetes\n      volumes:\n      - name: etc-kubernetes\n        hostPath:\n          path: /etc/kubernetes\n          type: Directory\n      restartPolicy: Never\n  backoffLimit: 0\n"
  },
  {
    "path": "hack/test/e2e-aws-prepare.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\nREGION=\"us-east-1\"\n\nfunction cloud_image_upload() {\n  RANDOM_SUFFIX=$(openssl rand -hex 4)\n\n  CLOUD_IMAGES_EXTRA_ARGS=(\"--name-prefix=${1}-${RANDOM_SUFFIX}\" \"--target-clouds=aws\" \"--architectures=amd64\" \"--aws-regions=${REGION}\")\n\n  case \"${1}\" in\n    talos-e2e-nvidia-oss-*)\n      CLOUD_IMAGES_EXTRA_ARGS+=(\"--aws-force-bios\")\n      ;;\n  esac\n\n  make cloud-images CLOUD_IMAGES_EXTRA_ARGS=\"${CLOUD_IMAGES_EXTRA_ARGS[*]}\"\n}\n\nfunction get_ami_id() {\n  jq -r \".[] | select(.cloud == \\\"aws\\\") | select(.region == \\\"${REGION}\\\") | select (.arch == \\\"amd64\\\") | .id\" \"${ARTIFACTS}/cloud-images.json\"\n}\n\nfunction cloud_image_upload_with_extensions() {\n  case \"${1}\" in\n    nvidia-oss-lts)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nvidia-open-gpu-kernel-modules-lts\") or contains(\"nvidia-container-toolkit-lts\")) and (contains(\"nvidia-fabricmanager\") or contains(\"nonfree-kmod-nvidia\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    nvidia-oss-production)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nvidia-open-gpu-kernel-modules-production\") or contains(\"nvidia-container-toolkit-production\")) and (contains(\"nvidia-fabricmanager\") or contains(\"nonfree-kmod-nvidia\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    nvidia-oss-fabricmanager)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nvidia-open-gpu-kernel-modules-production\") or contains(\"nvidia-container-toolkit-production\")) and (contains(\"nonfree-kmod-nvidia\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    nvidia-nonfree-lts)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nonfree-kmod-nvidia-lts\") or contains(\"nvidia-container-toolkit-lts\")) and (contains(\"nvidia-fabricmanager\") or contains(\"nvidia-open-gpu-kernel-modules\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    nvidia-nonfree-production)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nonfree-kmod-nvidia-production\") or contains(\"nvidia-container-toolkit-production\")) and (contains(\"nvidia-fabricmanager\") or contains(\"nvidia-open-gpu-kernel-modules\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    nvidia-nonfree-fabricmanager)\n      EXTENSIONS=$(jq -R < \"${EXTENSIONS_METADATA_FILE}\" | jq -rs 'map(select(. | (contains(\"nonfree-kmod-nvidia-lts\") or contains(\"nvidia-container-toolkit-lts\")) and (contains(\"nvidia-open-gpu-kernel-modules\") | not))) | .[] |= \"--system-extension-image=\" + . | join(\" \")')\n      ;;\n    *)\n      ;;\n  esac\n\n  make image-aws IMAGER_ARGS=\"${EXTENSIONS}\" PLATFORM=linux/amd64\n  cloud_image_upload \"talos-e2e-${1}\"\n}\n\ncloud_image_upload \"talos-e2e\"\n\nAMI_ID=$(get_ami_id)\n\nWORKER_GROUP=\nNVIDIA_AMI_ID=\n\ncase \"${E2E_AWS_TARGET:-default}\" in\n  default)\n    ;;\n  *)\n    WORKER_GROUP=\"nvidia\"\n    cloud_image_upload_with_extensions \"${E2E_AWS_TARGET}\"\n    NVIDIA_AMI_ID=$(get_ami_id)\n    # cloud_image_upload_with_extensions \"${E2E_AWS_TARGET}-fabricmanager\"\n    # NVIDIA_FM_AMI_ID=$(get_ami_id)\n    ;;\nesac\n\nmkdir -p \"${ARTIFACTS}/e2e-aws-generated\"\n\nNAME_PREFIX=\"${SHA}-${E2E_AWS_TARGET}\"\n\njq --null-input \\\n  --arg WORKER_GROUP \"${WORKER_GROUP}\" \\\n  --arg AMI_ID \"${AMI_ID}\" \\\n  --arg NVIDIA_AMI_ID \"${NVIDIA_AMI_ID}\" \\\n  --arg CLUSTER_NAME \"${NAME_PREFIX}\" \\\n  --arg TALOS_VERSION_CONTRACT \"${TALOS_VERSION}\" \\\n  --arg KUBERNETES_VERSION \"${KUBERNETES_VERSION}\" \\\n    '{\n        worker_group: $WORKER_GROUP,\n        ami_id: $AMI_ID,\n        nvidia_ami_id: $NVIDIA_AMI_ID,\n        cluster_name: $CLUSTER_NAME,\n        talos_version_contract: $TALOS_VERSION_CONTRACT,\n        kubernetes_version: $KUBERNETES_VERSION\n    }' \\\n  | jq -f hack/test/tfvars/aws.jq > \"${ARTIFACTS}/e2e-aws-generated/vars.json\"\n\ncp hack/test/tfvars/*.yaml \"${ARTIFACTS}/e2e-aws-generated\"\n"
  },
  {
    "path": "hack/test/e2e-aws.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\ncp \"${ARTIFACTS}/e2e-aws-talosconfig\" \"${TALOSCONFIG}\"\ncp \"${ARTIFACTS}/e2e-aws-kubeconfig\" \"${KUBECONFIG}\"\n\n# set the talosconfig to use the first controlplane ip\nCONTROLPLANE0_NODE=$(${TALOSCTL} config info -o json | jq -r '.endpoints[0]')\n${TALOSCTL} config node \"${CONTROLPLANE0_NODE}\"\n\nrun_talos_integration_test\nrun_kubernetes_integration_test\n"
  },
  {
    "path": "hack/test/e2e-azure.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\ncp \"${ARTIFACTS}/e2e-azure-talosconfig\" \"${TALOSCONFIG}\"\ncp \"${ARTIFACTS}/e2e-azure-kubeconfig\" \"${KUBECONFIG}\"\n\n# set the talosconfig to use the first controlplane ip\nCONTROLPLANE0_NODE=$(${TALOSCTL} config info -o json | jq -r '.endpoints[0]')\n${TALOSCTL} config node \"${CONTROLPLANE0_NODE}\"\n\nrun_talos_integration_test\nrun_kubernetes_integration_test\n"
  },
  {
    "path": "hack/test/e2e-cloud-tf.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\n# This script is used to run the end-to-end tests on a cloud provider using Terraform.\n\nBUCKET_NAME=\"talos-ci-e2e\"\nTF_DIR=\"${TF_SCRIPT_DIR}/examples/terraform/${TF_E2E_TEST_TYPE}\"\n\ncp \"${TF_SCRIPT_DIR}/hack/backend-aws.tf\" \"${TF_DIR}/backend.tf\"\n\ncp \"${ARTIFACTS}/e2e-${TF_E2E_TEST_TYPE}-generated\"/* \"${TF_DIR}\"\n\nCLUSTER_NAME=$(jq -e -r '.cluster_name' \"${TF_DIR}/vars.json\")\nBACKEND_CONFIG_KEY=\"cloud-tf/${CLUSTER_NAME}-terraform.tfstate\"\n\nterraform -chdir=\"${TF_DIR}\" \\\n    init \\\n    -backend-config=\"bucket=${BUCKET_NAME}\" \\\n    -backend-config=\"key=${BACKEND_CONFIG_KEY}\"\n\ncase \"${TF_E2E_ACTION}\" in\n    \"apply\")\n        terraform -chdir=\"${TF_DIR}\" \\\n            apply \\\n            -auto-approve \\\n            -var-file=\"vars.json\"\n\n        terraform -chdir=\"${TF_DIR}\" \\\n            output \\\n            -raw \\\n            talosconfig > \"${ARTIFACTS}/e2e-${TF_E2E_TEST_TYPE}-talosconfig\"\n\n        terraform -chdir=\"${TF_DIR}\" \\\n            output \\\n            -raw \\\n            kubeconfig > \"${ARTIFACTS}/e2e-${TF_E2E_TEST_TYPE}-kubeconfig\"\n        ;;\n    \"destroy\")\n        terraform -chdir=\"${TF_DIR}\" \\\n            apply \\\n            -destroy \\\n            -auto-approve \\\n            -var-file=\"vars.json\" \\\n            -refresh=\"${TF_E2E_REFRESH_ON_DESTROY:-true}\"\n\n        aws s3api delete-object --bucket \"${BUCKET_NAME}\" --key \"${BACKEND_CONFIG_KEY}\"\n        ;;\n    *)\n        echo \"Unsupported action: ${TF_E2E_ACTION}\"\n        exit 1\n        ;;\nesac\n"
  },
  {
    "path": "hack/test/e2e-docker.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\nPROVISIONER=docker\nCLUSTER_NAME=e2e-${PROVISIONER}\n\nfunction create_cluster {\n  build_registry_mirrors\n\n  \"${TALOSCTL}\" cluster create docker \\\n    --name=\"${CLUSTER_NAME}\" \\\n    --kubernetes-version=${KUBERNETES_VERSION} \\\n    --image=\"${IMAGE}\" \\\n    --workers=1 \\\n    --mtu=1430 \\\n    --config-patch=hack/test/patches/image-verification.yaml \\\n    \"${REGISTRY_MIRROR_FLAGS[@]}\"\n\n  \"${TALOSCTL}\" config node 10.5.0.2\n}\n\nfunction destroy_cluster() {\n  \"${TALOSCTL}\" cluster destroy --name \"${CLUSTER_NAME}\" --provisioner \"${PROVISIONER}\" --save-support-archive-path=/tmp/support-${CLUSTER_NAME}.zip\n}\n\ntrap destroy_cluster SIGINT EXIT\n\ncreate_cluster\nget_kubeconfig\n${KUBECTL} config set-cluster e2e-docker --server https://10.5.0.2:6443\nrun_talos_integration_test_docker\nrun_kubernetes_integration_test\n"
  },
  {
    "path": "hack/test/e2e-embedded.sh",
    "content": "#!/usr/bin/env bash\n\nset -eoux pipefail\n\nsource ./hack/test/e2e.sh\n\nPROVISIONER=qemu\nCLUSTER_NAME=e2e-embedded\n\nNODE=\"172.20.3.2\"\n\nfunction build_iso_embedded {\n  # build the ISO with embedded config\n  cp hack/test/patches/watchdog.yaml ${ARTIFACTS}/embedded.yaml\n  make image-iso IMAGER_ARGS=\"--embedded-config-path=/out/embedded.yaml\" PLATFORM=linux/amd64\n}\n\nfunction create_cluster {\n  \"${TALOSCTL}\" cluster create \\\n    --provisioner=\"${PROVISIONER}\" \\\n    --name=\"${CLUSTER_NAME}\" \\\n    --iso-path=${ARTIFACTS}/metal-amd64.iso \\\n    --controlplanes=1 \\\n    --workers=0 \\\n    --mtu=1430 \\\n    --memory=2048 \\\n    --cpus=2.0 \\\n    --cidr=172.20.3.0/24 \\\n    --skip-injecting-config \\\n    --wait=false \\\n    --cni-bundle-url=${ARTIFACTS}/talosctl-cni-bundle-'${ARCH}'.tar.gz\n}\n\nfunction destroy_cluster() {\n  \"${TALOSCTL}\" cluster destroy \\\n    --name \"${CLUSTER_NAME}\" \\\n    --provisioner \"${PROVISIONER}\" \\\n    --save-cluster-logs-archive-path=\"/tmp/logs-${CLUSTER_NAME}.tar.gz\" \\\n    --save-support-archive-path=\"/tmp/support-${CLUSTER_NAME}.zip\"\n}\n\ntrap destroy_cluster SIGINT EXIT\n\nbuild_iso_embedded\ncreate_cluster\n\n# wait for the Talos API to be up\nfor i in $(seq 1 30); do\n  if \"${TALOSCTL}\" -n \"${NODE}\" get disks --insecure &>/dev/null; then\n    break\n  fi\n  sleep 1\ndone\n\n# verify that the config is applied\n\"${TALOSCTL}\" -n \"${NODE}\" get watchdogtimerstatus timer --insecure\n"
  },
  {
    "path": "hack/test/e2e-gcp-prepare.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\nREGION=\"us-central1\"\nZONE=\"us-central1-a\"\nPROJECT_ID=\"${GOOGLE_PROJECT_ID}\"\n\nfunction cloud_image_upload() {\n  CLOUD_IMAGES_EXTRA_ARGS=(\"--target-clouds=gcp\" \"--architectures=amd64\")\n\n  make cloud-images CLOUD_IMAGES_EXTRA_ARGS=\"${CLOUD_IMAGES_EXTRA_ARGS[*]}\"\n}\n\nfunction get_image() {\n  jq -r \".[] | select(.cloud == \\\"gcp\\\") | select (.arch == \\\"amd64\\\") | .id\" \"${ARTIFACTS}/cloud-images.json\"\n}\n\ncloud_image_upload\n\nGCP_IMAGE=$(get_image)\n\nmkdir -p \"${ARTIFACTS}/e2e-gcp-generated\"\n\nNAME_PREFIX=\"talos-e2e-${SHA}-gcp\"\n\njq --null-input \\\n  --arg REGION \"${REGION}\" \\\n  --arg ZONE \"${ZONE}\" \\\n  --arg PROJECT_ID \"${PROJECT_ID}\" \\\n  --arg GCP_IMAGE \"${GCP_IMAGE}\" \\\n  --arg CLUSTER_NAME \"${NAME_PREFIX}\" \\\n  --arg TALOS_VERSION_CONTRACT \"${TALOS_VERSION}\" \\\n  --arg KUBERNETES_VERSION \"${KUBERNETES_VERSION}\" \\\n    '{\n        region: $REGION,\n        zone: $ZONE,\n        project_id: $PROJECT_ID,\n        gcp_image: $GCP_IMAGE,\n        cluster_name: $CLUSTER_NAME,\n        talos_version_contract: $TALOS_VERSION_CONTRACT,\n        kubernetes_version: $KUBERNETES_VERSION\n    }' \\\n  | jq -f hack/test/tfvars/gcp.jq > \"${ARTIFACTS}/e2e-gcp-generated/vars.json\"\n\ncp hack/test/tfvars/*.yaml \"${ARTIFACTS}/e2e-gcp-generated\"\n"
  },
  {
    "path": "hack/test/e2e-gcp.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\nsource ./hack/test/e2e.sh\n\ncp \"${ARTIFACTS}/e2e-gcp-talosconfig\" \"${TALOSCONFIG}\"\ncp \"${ARTIFACTS}/e2e-gcp-kubeconfig\" \"${KUBECONFIG}\"\n\n# set the talosconfig to use the first controlplane ip\nCONTROLPLANE0_NODE=$(${TALOSCTL} config info -o json | jq -r '.endpoints[0]')\n${TALOSCTL} config node \"${CONTROLPLANE0_NODE}\"\n\nrun_talos_integration_test\nrun_kubernetes_integration_test\n"
  },
  {
    "path": "hack/test/e2e-image-factory.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\n# shellcheck source=/dev/null\nsource ./hack/test/e2e.sh\n\nPROVISIONER=qemu\nCLUSTER_NAME=\"e2e-${PROVISIONER}\"\nLOG_ARCHIVE_SUFFIX=\"${GITHUB_STEP_NAME:-e2e-${PROVISIONER}}\"\n\nFACTORY_HOSTNAME=${FACTORY_HOSTNAME:-factory.talos.dev}\nif [ \"${FACTORY_BOOT_METHOD}\" = \"ipxe\" ]; then\n    FACTORY_HOSTNAME=${PXE_FACTORY_HOSTNAME:-pxe.${FACTORY_HOSTNAME}}\nfi\nFACTORY_SCHEME=${FACTORY_SCHEME:-https}\nINSTALLER_IMAGE_NAME=${INSTALLER_IMAGE_NAME:-installer}\n\ncase \"${FACTORY_BOOT_METHOD:-iso}\" in\n  iso)\n    QEMU_FLAGS+=(\"--presets=iso\")\n    ;;\n  disk-image)\n    QEMU_FLAGS+=(\"--presets=disk-image\")\n    ;;\n  ipxe)\n    QEMU_FLAGS+=(\"--presets=pxe\")\n    ;;\n  secureboot-iso)\n    QEMU_FLAGS+=(\"--presets=iso-secureboot\")\n    INSTALLER_IMAGE_NAME=installer-secureboot\n    ;;\n  *)\n    echo \"unknown factory boot method: ${FACTORY_BOOT_METHOD}\"\n    exit 1\n    ;;\nesac\n\nfunction assert_secureboot {\n  if [[ \"${FACTORY_BOOT_METHOD:-iso}\" != \"secureboot-iso\" ]]; then\n    return\n  fi\n\n  ${TALOSCTL} get securitystate -o json\n  ${TALOSCTL} get securitystate -o json | jq -e '.spec.secureBoot == true'\n}\n\nfunction create_cluster {\n  build_registry_mirrors\n\n  \"${TALOSCTL}\" cluster create qemu \\\n    --name=\"${CLUSTER_NAME}\" \\\n    --kubernetes-version=\"${KUBERNETES_VERSION}\" \\\n    --controlplanes=3 \\\n    --workers=\"${QEMU_WORKERS:-1}\" \\\n    --mtu=1430 \\\n    --memory-controlplanes=2048 \\\n    --memory-workers=\"${QEMU_MEMORY_WORKERS:-2048}\" \\\n    --cpus-controlplanes=\"${QEMU_CPUS:-2}\" \\\n    --cpus-workers=\"${QEMU_CPUS_WORKERS:-2}\" \\\n    --cidr=172.20.1.0/24 \\\n    --image-factory-url=\"${FACTORY_SCHEME}://${FACTORY_HOSTNAME}/\" \\\n    --talos-version=\"${FACTORY_VERSION}\" \\\n    --schematic-id=\"${FACTORY_SCHEMATIC}\" \\\n    \"${REGISTRY_MIRROR_FLAGS[@]}\" \\\n    \"${QEMU_FLAGS[@]}\"\n\n    ${TALOSCTL} config node 172.20.1.2\n}\n\nfunction destroy_cluster() {\n  \"${TALOSCTL}\" cluster destroy \\\n    --name \"${CLUSTER_NAME}\" \\\n    --provisioner \"${PROVISIONER}\" \\\n    --save-cluster-logs-archive-path=\"/tmp/logs-${LOG_ARCHIVE_SUFFIX}.tar.gz\" \\\n    --save-support-archive-path=\"/tmp/support-${LOG_ARCHIVE_SUFFIX}.zip\"\n}\n\ntrap destroy_cluster SIGINT EXIT\n\ncreate_cluster\n\n${TALOSCTL} health --run-e2e\n${TALOSCTL} version | grep \"${FACTORY_VERSION}\"\n${TALOSCTL} get extensions | grep \"${FACTORY_SCHEMATIC}\"\nassert_secureboot\n\nif [[ \"${FACTORY_UPGRADE:-false}\" == \"true\" ]]; then\n    ${TALOSCTL} upgrade -i \"${FACTORY_HOSTNAME}/${INSTALLER_IMAGE_NAME}/${FACTORY_UPGRADE_SCHEMATIC:-$FACTORY_SCHEMATIC}:${FACTORY_UPGRADE_VERSION:-$FACTORY_VERSION}\"\n    ${TALOSCTL} version | grep \"${FACTORY_UPGRADE_VERSION:-$FACTORY_VERSION}\"\n    ${TALOSCTL} get extensions | grep \"${FACTORY_UPGRADE_SCHEMATIC:-$FACTORY_SCHEMATIC}\"\n    assert_secureboot\nfi\n"
  },
  {
    "path": "hack/test/e2e-iso.sh",
    "content": "#!/usr/bin/env bash\n\nset -eoux pipefail\n\nsource ./hack/test/e2e.sh\n\nPROVISIONER=qemu\nCLUSTER_NAME=e2e-iso\n\nNODE=\"172.20.2.2\"\n\nfunction create_cluster {\n  build_registry_mirrors\n\n  \"${TALOSCTL}\" cluster create \\\n    --provisioner=\"${PROVISIONER}\" \\\n    --name=\"${CLUSTER_NAME}\" \\\n    --kubernetes-version=${KUBERNETES_VERSION} \\\n    --iso-path=${ARTIFACTS}/metal-amd64.iso \\\n    --controlplanes=1 \\\n    --workers=0 \\\n    --mtu=1430 \\\n    --memory=2048 \\\n    --cpus=2.0 \\\n    --cidr=172.20.2.0/24 \\\n    --with-apply-config \\\n    --install-image=\"${INSTALLER_IMAGE}\" \\\n    --cni-bundle-url=${ARTIFACTS}/talosctl-cni-bundle-'${ARCH}'.tar.gz \\\n    \"${REGISTRY_MIRROR_FLAGS[@]}\"\n\n  \"${TALOSCTL}\" config node \"${NODE}\"\n}\n\nfunction destroy_cluster() {\n  \"${TALOSCTL}\" cluster destroy \\\n    --name \"${CLUSTER_NAME}\" \\\n    --provisioner \"${PROVISIONER}\" \\\n    --save-cluster-logs-archive-path=\"/tmp/logs-${CLUSTER_NAME}.tar.gz\" \\\n    --save-support-archive-path=\"/tmp/support-${CLUSTER_NAME}.zip\"\n}\n\ntrap destroy_cluster SIGINT EXIT\n\ncreate_cluster\nsleep 5\n"
  },
  {
    "path": "hack/test/e2e-qemu.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\n# shellcheck source=/dev/null\nsource ./hack/test/e2e.sh\n\nPROVISIONER=qemu\nCLUSTER_NAME=\"e2e-${PROVISIONER}\"\nLOG_ARCHIVE_SUFFIX=\"${GITHUB_STEP_NAME:-e2e-${PROVISIONER}}\"\n\nQEMU_FLAGS=()\n\ncase \"${CI:-false}\" in\n  false)\n    QEMU_FLAGS+=(\"--with-bootloader=false\")\n    ;;\n  *)\n    ;;\nesac\n\ncase \"${CUSTOM_CNI_URL:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--custom-cni-url=${CUSTOM_CNI_URL}\")\n    ;;\nesac\n\ncase \"${WITH_UEFI:-none}\" in\n  none)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-uefi=${WITH_UEFI}\")\n    ;;\nesac\n\ncase \"${WITH_VIRTUAL_IP:-false}\" in\n  true)\n    QEMU_FLAGS+=(\"--use-vip\")\n    ;;\nesac\n\ncase \"${WITH_JSON_LOGS:-true}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-json-logs\")\n    ;;\nesac\n\ncase \"${WITH_CLUSTER_DISCOVERY:-true}\" in\n  false)\n    QEMU_FLAGS+=(\"--with-cluster-discovery=false\" \"--kubeprism-port=0\") # disable both KubePrism and cluster discovery\n    ;;\nesac\n\ncase \"${WITH_KUBESPAN:-false}\" in\n  true)\n    QEMU_FLAGS+=(\"--with-kubespan\")\n    ;;\nesac\n\ncase \"${WITH_CONTROL_PLANE_PORT:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--control-plane-port=${WITH_CONTROL_PLANE_PORT}\")\n    ;;\nesac\n\ncase \"${VIA_MAINTENANCE_MODE:-false}\" in\n  false)\n    ;;\n  *)\n    # apply config via maintenance mode\n    QEMU_FLAGS+=(\"--skip-injecting-config\" \"--with-apply-config\")\n    ;;\nesac\n\ncase \"${DISABLE_DHCP_HOSTNAME:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--disable-dhcp-hostname\")\n    ;;\nesac\n\ncase \"${WITH_NETWORK_CHAOS:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-network-chaos\" \"--with-network-packet-loss=0.01\" \"--with-network-latency=15ms\" \"--with-network-jitter=5ms\")\n    ;;\nesac\n\ncase \"${WITH_FIREWALL:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-firewall=${WITH_FIREWALL}\")\n    ;;\nesac\n\ncase \"${USE_DISK_IMAGE:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--disk-image-path=_out/metal-amd64.raw.zst\")\n    ;;\nesac\n\ncase \"${WITH_DISK_ENCRYPTION:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--encrypt-ephemeral\" \"--encrypt-state\" \"--encrypt-user-volumes\" \"--disk-encryption-key-types=kms\")\n    ;;\nesac\n\ncase \"${WITH_CONFIG_PATCH:-false}\" in\n  false)\n    ;;\n  *)\n    [[ ! ${WITH_CONFIG_PATCH} =~ ^@ ]] && echo \"WITH_CONFIG_PATCH variable should start with @\" && exit 1\n\n    for i in ${WITH_CONFIG_PATCH//:/ }; do\n      QEMU_FLAGS+=(\"--config-patch=${i}\")\n    done\n    ;;\nesac\n\ncase \"${WITH_ISO:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--iso-path=${ARTIFACTS}/metal-amd64.iso\")\n    ;;\nesac\n\ncase \"${WITH_CONFIG_PATCH_CONTROLPLANE:-false}\" in\n  false)\n    ;;\n  *)\n    [[ ! ${WITH_CONFIG_PATCH_CONTROLPLANE} =~ ^@ ]] && echo \"WITH_CONFIG_PATCH_CONTROLPLANE variable should start with @\" && exit 1\n\n    for i in ${WITH_CONFIG_PATCH_CONTROLPLANE//:/ }; do\n      QEMU_FLAGS+=(\"--config-patch-control-plane=${i}\")\n    done\n    ;;\nesac\n\ncase \"${WITH_CONFIG_PATCH_WORKER:-false}\" in\n  false)\n    ;;\n  *)\n    [[ ! ${WITH_CONFIG_PATCH_WORKER} =~ ^@ ]] && echo \"WITH_CONFIG_PATCH_WORKER variable should start with @\" && exit 1\n\n    for i in ${WITH_CONFIG_PATCH_WORKER//:/ }; do\n      QEMU_FLAGS+=(\"--config-patch-worker=${i}\")\n    done\n    ;;\nesac\n\ncase \"${WITH_CUSTOM_CNI:-none}\" in\n  false)\n    ;;\n  cilium)\n    QEMU_FLAGS+=(\"--kubeprism-port=13336\")\n    ;;\nesac\n\ncase \"${WITH_TRUSTED_BOOT_ISO:-false}\" in\n  false)\n    ;;\n  *)\n    INSTALLER_IMAGE=${INSTALLER_IMAGE}-amd64-secureboot\n    QEMU_FLAGS+=(\"--iso-path=_out/metal-amd64-secureboot.iso\" \"--with-tpm2\" \"--encrypt-ephemeral\" \"--encrypt-state\" \"--encrypt-user-volumes\" \"--disk-encryption-key-types=tpm\")\n    ;;\nesac\n\ncase \"${WITH_TPM1_2:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-tpm1_2\")\n    ;;\nesac\n\ncase \"${WITH_SIDEROLINK_AGENT:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-siderolink=${WITH_SIDEROLINK_AGENT}\")\n    ;;\nesac\n\ncase \"${WITH_APPARMOR_LSM_ENABLED:-false}\" in\n  false)\n    ;;\n  *)\n    # build disk image with specific kernel args to enable AppArmor LSM\n    make image-metal PLATFORM=linux/amd64 IMAGER_ARGS=\"--extra-kernel-arg -selinux --extra-kernel-arg lsm=lockdown,capability,yama,apparmor,bpf --extra-kernel-arg apparmor=1\"\n\n    QEMU_FLAGS+=(\"--disk-image-path=_out/metal-amd64.raw.zst\" \"--skip-injecting-config\" \"--with-apply-config\")\n    ;;\nesac\n\ncase \"${WITH_CONFIG_INJECTION_METHOD:-default}\" in\n  default)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--config-injection-method=${WITH_CONFIG_INJECTION_METHOD}\")\n    ;;\nesac\n\ncase \"${WITH_IOMMU:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--with-iommu\")\n    ;;\nesac\n\ncase \"${WITH_4K_DISK:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--disk-block-size=4096\")\n    ;;\nesac\n\ncase \"${WITH_UKI_BOOT:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--uki-path=_out/metal-amd64-uki.efi\")\n    ;;\nesac\n\ncase \"${WITH_USER_DISK:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--user-volumes=extra:350MB\")\n    QEMU_FLAGS+=(\"--user-volumes=p1:350MB:p2:350MB\")\n    ;;\nesac\n\ncase \"${WITH_ENFORCING:-false}\" in\n  false)\n    ;;\n  *)\n    QEMU_FLAGS+=(\"--extra-boot-kernel-args=enforcing=1\")\n    ;;\nesac\n\ncase \"${WITH_AIRGAPPED:-false}\" in\n  no-proxy)\n    INSTALLER_IMAGE=\"${INSTALLER_IMAGE/registry.dev.siderolabs.io/172.20.1.1:5000}\"\n\n    QEMU_FLAGS+=(\"--config-patch=@hack/test/patches/airgapped-timesync.yaml\")\n    QEMU_FLAGS+=(\"--config-patch=@${TMP}/image-cache-patch.yaml\")\n    QEMU_FLAGS+=(\"--airgapped\")\n    QEMU_FLAGS+=(\"--image-cache-path=${TMP}/image-cache\")\n    QEMU_FLAGS+=(\"--image-cache-tls-cert-file=${TMP}/image-cache-tls.crt\")\n    QEMU_FLAGS+=(\"--image-cache-tls-key-file=${TMP}/image-cache-tls.key\")\n    ;;\n  http-proxy)\n    \"${TALOSCTL}\" debug-tool air-gapped --advertised-address 172.20.1.1 > /tmp/airgapped.log 2>&1 &\n    sleep 5 # wait for the air-gapped server to start\n    cat air-gapped-patch.yaml\n    mv air-gapped-patch.yaml \"${TMP}/air-gapped-patch.yaml\"\n\n    QEMU_FLAGS+=(\"--config-patch=@${TMP}/air-gapped-patch.yaml\")\n    ;;\n  secure-http-proxy)\n    \"${TALOSCTL}\" debug-tool air-gapped --advertised-address 172.20.1.1 --use-secure-proxy > /tmp/airgapped-secure.log 2>&1 &\n    sleep 5 # wait for the air-gapped server to start\n    cat air-gapped-patch.yaml\n    mv air-gapped-patch.yaml \"${TMP}/air-gapped-patch.yaml\"\n\n    QEMU_FLAGS+=(\"--config-patch=@${TMP}/air-gapped-patch.yaml\")\n    ;;\n  https-reverse-proxy)\n    \"${TALOSCTL}\" debug-tool air-gapped --advertised-address 172.20.1.1 --inject-http-proxy=false --https-reverse-proxy-target=https://registry.dev.siderolabs.io > /tmp/airgapped-reverse-proxy.log 2>&1 &\n    sleep 5 # wait for the air-gapped server to start\n    cat air-gapped-patch.yaml\n    mv air-gapped-patch.yaml \"${TMP}/air-gapped-patch.yaml\"\n\n    QEMU_FLAGS+=(\"--config-patch=@${TMP}/air-gapped-patch.yaml\")\n    ;;\n  false)\n    ;;\nesac\n\nfunction create_cluster {\n  build_registry_mirrors\n\n  \"${TALOSCTL}\" cluster create \\\n    --provisioner=\"${PROVISIONER}\" \\\n    --name=\"${CLUSTER_NAME}\" \\\n    --kubernetes-version=\"${KUBERNETES_VERSION}\" \\\n    --controlplanes=3 \\\n    --workers=\"${QEMU_WORKERS:-2}\" \\\n    --disk=\"${QEMU_SYSTEM_DISK_SIZE:-15360}\" \\\n    --extra-disks=\"${QEMU_EXTRA_DISKS:-0}\" \\\n    --extra-disks-size=\"${QEMU_EXTRA_DISKS_SIZE:-6144}\" \\\n    --extra-disks-drivers=\"${QEMU_EXTRA_DISKS_DRIVERS:-}\" \\\n    --extra-disks-serials=\"${QEMU_EXTRA_DISKS_SERIALS:-}\" \\\n    --extra-disks-tags=\"${QEMU_EXTRA_DISKS_TAGS:-}\" \\\n    --mtu=1430 \\\n    --memory=\"${QEMU_MEMORY_CONTROLPLANES:-2048}\" \\\n    --memory-workers=\"${QEMU_MEMORY_WORKERS:-2048}\" \\\n    --cpus=\"${QEMU_CPUS:-2}\" \\\n    --cpus-workers=\"${QEMU_CPUS_WORKERS:-2}\" \\\n    --cidr=172.20.1.0/24 \\\n    --install-image=\"${INSTALLER_IMAGE}\" \\\n    --with-init-node=false \\\n    --cni-bundle-url=\"${ARTIFACTS}/talosctl-cni-bundle-\\${ARCH}.tar.gz\" \\\n    \"${REGISTRY_MIRROR_FLAGS[@]}\" \\\n    \"${QEMU_FLAGS[@]}\"\n\n  \"${TALOSCTL}\" config node 172.20.1.2\n}\n\nfunction destroy_cluster() {\n  jobs -p | xargs -r kill\n\n  \"${TALOSCTL}\" cluster destroy \\\n    --name \"${CLUSTER_NAME}\" \\\n    --provisioner \"${PROVISIONER}\" \\\n    --save-cluster-logs-archive-path=\"/tmp/logs-${LOG_ARCHIVE_SUFFIX}.tar.gz\" \\\n    --save-support-archive-path=\"/tmp/support-${LOG_ARCHIVE_SUFFIX}.zip\"\n}\n\ntrap destroy_cluster SIGINT EXIT\n\ncreate_cluster\n\ncase \"${WITH_CUSTOM_CNI:-none}\" in\n  cilium)\n    install_and_run_cilium_cni_tests\n    ;;\n  *)\n    ;;\nesac\n\ncase \"${TEST_MODE:-default}\" in\n  fast-conformance)\n    run_kubernetes_conformance_test fast\n    ;;\n  *)\n    get_kubeconfig\n    run_talos_integration_test\n\n    if [[ ${QEMU_MEMORY_WORKERS:-2048} -gt 1024 ]]; then\n        run_kubernetes_integration_test\n    fi\n\n    if [ \"${TEST_MODE:-default}\" = \"network-policy\" ]; then\n        run_kubernetes_conformance_test network-policy\n    fi\n\n    if [ \"${WITH_TEST:-none}\" != \"none\" ]; then\n      \"${WITH_TEST}\"\n    fi\n    ;;\nesac\n"
  },
  {
    "path": "hack/test/e2e.sh",
    "content": "#!/usr/bin/env bash\n\n# This file contains common environment variables and setup logic for all test\n# scripts. It assumes that the following environment variables are set by the\n# Makefile:\n#  - PLATFORM\n#  - TAG\n#  - SHA\n#  - REGISTRY\n#  - IMAGE\n#  - INSTALLER_IMAGE\n#  - ARTIFACTS\n#  - TALOSCTL\n#  - INTEGRATION_TEST\n#  - SHORT_INTEGRATION_TEST\n#  - CUSTOM_CNI_URL\n#  - KUBECTL\n#  - KUBESTR\n#  - HELM\n#  - CILIUM_CLI\n\nset -eoux pipefail\n\nTMP=\"/tmp/e2e/${PLATFORM}\"\nmkdir -p \"${TMP}\"\n\n# Talos\n\nexport TALOSCONFIG=\"${TMP}/talosconfig\"\nTALOS_VERSION=$(cut -d \".\" -f 1,2 <<< \"${TAG}\")\nexport TALOS_VERSION\n\n# Kubernetes\n\nexport KUBECONFIG=\"${TMP}/kubeconfig\"\nexport KUBERNETES_VERSION=${KUBERNETES_VERSION:-1.36.0-alpha.2}\n\nexport NAME_PREFIX=\"talos-e2e-${SHA}-${PLATFORM}\"\nexport TIMEOUT=1200\n\n# default values, overridden by talosctl cluster create tests\nPROVISIONER=\nCLUSTER_NAME=\n\nTEST_SHORT=()\nTEST_RUN=(\"-test.run\" \".\")\n\nfunction run_talos_integration_test {\n  case \"${SHORT_INTEGRATION_TEST:-no}\" in\n    no)\n      ;;\n    *)\n      TEST_SHORT=(\"-test.short\")\n      ;;\n  esac\n\n  case \"${WITH_AIRGAPPED:-false}\" in\n    no-proxy)\n      TEST_AIRGAPPED=(\"-talos.airgapped\")\n      ;;\n    *)\n      ;;\n  esac\n\n  case \"${INTEGRATION_TEST_RUN:-no}\" in\n    no)\n      ;;\n    *)\n      TEST_RUN=(\"-test.run\" \"${INTEGRATION_TEST_RUN}\")\n      ;;\n  esac\n\n  if [ -n \"${QEMU_EXTRA_DISKS_TAGS:-}\" ]; then\n      TEST_VIRTIOFSD=(\"-talos.virtiofsd\")\n  fi\n\n  \"${INTEGRATION_TEST}\" \\\n    -test.v \\\n    -talos.failfast \\\n    -talos.talosctlpath \"${TALOSCTL}\" \\\n    -talos.kubectlpath \"${KUBECTL}\" \\\n    -talos.helmpath \"${HELM}\" \\\n    -talos.kubestrpath \"${KUBESTR}\" \\\n    -talos.provisioner \"${PROVISIONER}\" \\\n    -talos.name \"${CLUSTER_NAME}\" \\\n    -talos.image \"${REGISTRY}/siderolabs/talos\" \\\n    ${EXTRA_TEST_ARGS:-} \\\n    \"${TEST_RUN[@]}\" \\\n    \"${TEST_SHORT[@]}\" \\\n    \"${TEST_AIRGAPPED[@]}\" \\\n    \"${TEST_VIRTIOFSD[@]}\"\n}\n\nfunction run_talos_integration_test_docker {\n  case \"${SHORT_INTEGRATION_TEST:-no}\" in\n    no)\n      ;;\n    *)\n      TEST_SHORT=(\"-test.short\")\n      ;;\n  esac\n\n  case \"${INTEGRATION_TEST_RUN:-no}\" in\n    no)\n      ;;\n    *)\n      TEST_RUN=(\"-test.run\" \"${INTEGRATION_TEST_RUN}\")\n      ;;\n  esac\n\n  \"${INTEGRATION_TEST}\" \\\n    -test.v \\\n    -talos.failfast \\\n    -talos.talosctlpath \"${TALOSCTL}\" \\\n    -talos.kubectlpath \"${KUBECTL}\" \\\n    -talos.helmpath \"${HELM}\" \\\n    -talos.kubestrpath \"${KUBESTR}\" \\\n    -talos.provisioner \"${PROVISIONER}\" \\\n    -talos.name \"${CLUSTER_NAME}\" \\\n    -talos.image \"${REGISTRY}/siderolabs/talos\" \\\n    ${EXTRA_TEST_ARGS:-} \\\n    \"${TEST_RUN[@]}\" \\\n    \"${TEST_SHORT[@]}\"\n}\n\nfunction run_kubernetes_conformance_test {\n  \"${TALOSCTL}\" conformance kubernetes --mode=\"${1}\"\n}\n\nfunction run_kubernetes_integration_test {\n  \"${TALOSCTL}\" health --run-e2e\n}\n\nfunction run_control_plane_cis_benchmark {\n  ${KUBECTL} apply -f \"${PWD}/hack/test/cis/kube-bench-master.yaml\"\n  ${KUBECTL} wait --timeout=300s --for=condition=complete job/kube-bench-master > /dev/null\n  ${KUBECTL} logs job/kube-bench-master\n}\n\nfunction run_worker_cis_benchmark {\n  ${KUBECTL} apply -f \"${PWD}/hack/test/cis/kube-bench-node.yaml\"\n  ${KUBECTL} wait --timeout=300s --for=condition=complete job/kube-bench-node > /dev/null\n  ${KUBECTL} logs job/kube-bench-node\n}\n\nfunction get_kubeconfig {\n  rm -f \"${TMP}/kubeconfig\"\n  \"${TALOSCTL}\" kubeconfig \"${TMP}\"\n}\n\nfunction dump_cluster_state {\n  nodes=$(${KUBECTL} get nodes -o jsonpath=\"{.items[*].status.addresses[?(@.type == 'InternalIP')].address}\" | tr '[:space:]' ',')\n  \"${TALOSCTL}\" -n \"${nodes}\" services\n  ${KUBECTL} get nodes -o wide\n  ${KUBECTL} get pods --all-namespaces -o wide\n}\n\nfunction build_image_cache {\n  cat _out/integration-images.txt | \"${TALOSCTL}\" image cache-create --images=- --image-cache-path=\"${TMP}/image-cache\" --layout=flat\n\n  \"${TALOSCTL}\" image cache-cert-gen \\\n    --tls-ca-file=\"${TMP}/image-cache-ca.crt\" \\\n    --tls-cert-file=\"${TMP}/image-cache-tls.crt\" \\\n    --tls-key-file=\"${TMP}/image-cache-tls.key\" \\\n    --advertised-address=\"172.20.1.1\"\n\n  cat image-cache-patch.yaml\n  mv image-cache-patch.yaml \"${TMP}/image-cache-patch.yaml\"\n}\n\nfunction build_registry_mirrors {\n  if [[ \"${WITH_AIRGAPPED:-false}\" == \"no-proxy\" ]]; then\n    build_image_cache\n\n    REGISTRY_MIRROR_FLAGS=()\n\n    for registry in docker.io registry.k8s.io quay.io gcr.io ghcr.io; do\n      addr=\"172.20.1.1\"\n      REGISTRY_MIRROR_FLAGS+=(\"--registry-mirror=${registry}=https://${addr}:5000\")\n    done\n\n    return\n  fi\n\n  if [[ \"${REGISTRY_MIRROR_FLAGS:-yes}\" == \"no\" ]]; then\n    REGISTRY_MIRROR_FLAGS=()\n\n    return\n  fi\n\n  if [[ \"${CI:-false}\" == \"true\" ]]; then\n    REGISTRY_MIRROR_FLAGS=()\n\n    for registry in docker.io registry.k8s.io quay.io gcr.io ghcr.io; do\n      local service=\"registry-${registry//./-}.ci.svc\"\n      addr=$(python3 -c \"import socket; print(socket.gethostbyname('${service}'))\")\n\n      REGISTRY_MIRROR_FLAGS+=(\"--registry-mirror=${registry}=http://${addr}:5000\")\n    done\n  fi\n}\n\nfunction install_and_run_cilium_cni_tests {\n  get_kubeconfig\n\n  case \"${WITH_KUBESPAN:-false}\" in\n    true)\n      CILIUM_NODE_ENCRYPTION=false\n      CILIUM_TEST_EXTRA_ARGS=(\"--test=!node-to-node-encryption,!check-log-errors,!pod-to-pod-encryption-v2\")\n      ;;\n    *)\n      CILIUM_NODE_ENCRYPTION=true\n      CILIUM_TEST_EXTRA_ARGS=(\"--test=!check-log-errors\")\n      ;;\n  esac\n\n  case \"${CILIUM_INSTALL_TYPE:-none}\" in\n    strict)\n      ${CILIUM_CLI} install \\\n        --set=ipam.mode=kubernetes \\\n        --set=kubeProxyReplacement=true \\\n        --set=encryption.nodeEncryption=${CILIUM_NODE_ENCRYPTION} \\\n        --set=securityContext.capabilities.ciliumAgent=\"{CHOWN,KILL,NET_ADMIN,NET_RAW,IPC_LOCK,SYS_ADMIN,SYS_RESOURCE,DAC_OVERRIDE,FOWNER,SETGID,SETUID}\" \\\n        --set=securityContext.capabilities.cleanCiliumState=\"{NET_ADMIN,SYS_ADMIN,SYS_RESOURCE}\" \\\n        --set=cgroup.autoMount.enabled=false \\\n        --set=cgroup.hostRoot=/sys/fs/cgroup \\\n        --set=k8sServiceHost=localhost \\\n        --set=k8sServicePort=13336\n      ;;\n    *)\n      # explicitly setting kubeProxyReplacement=disabled since by the time cilium cli runs talos\n      # has not yet applied the kube-proxy manifests\n      ${CILIUM_CLI} install \\\n        --set=ipam.mode=kubernetes \\\n        --set=kubeProxyReplacement=false \\\n        --set=encryption.nodeEncryption=${CILIUM_NODE_ENCRYPTION} \\\n        --set=securityContext.capabilities.ciliumAgent=\"{CHOWN,KILL,NET_ADMIN,NET_RAW,IPC_LOCK,SYS_ADMIN,SYS_RESOURCE,DAC_OVERRIDE,FOWNER,SETGID,SETUID}\" \\\n        --set=securityContext.capabilities.cleanCiliumState=\"{NET_ADMIN,SYS_ADMIN,SYS_RESOURCE}\" \\\n        --set=cgroup.autoMount.enabled=false \\\n        --set=cgroup.hostRoot=/sys/fs/cgroup\n      ;;\n  esac\n\n  ${CILIUM_CLI} status --wait --wait-duration=10m\n\n  # ref: https://github.com/cilium/cilium-cli/releases/tag/v0.16.14\n  ${KUBECTL} delete ns --ignore-not-found cilium-test-1 cilium-test-ccnp1 cilium-test-ccnp2\n\n  ${KUBECTL} create ns cilium-test-1\n  ${KUBECTL} create ns cilium-test-ccnp1\n  ${KUBECTL} create ns cilium-test-ccnp2\n  ${KUBECTL} label ns cilium-test-1 cilium-test-ccnp1 cilium-test-ccnp2 pod-security.kubernetes.io/enforce=privileged\n\n  # --external-target added, as default 'one.one.one.one' is buggy, and CloudFlare status is of course \"all healthy\"\n  ${CILIUM_CLI} connectivity test --test-namespace cilium-test --external-target google.com --timeout=20m \"${CILIUM_TEST_EXTRA_ARGS[@]}\"\n  ${KUBECTL} delete ns cilium-test-1 cilium-test-ccnp1 cilium-test-ccnp2\n}\n"
  },
  {
    "path": "hack/test/patches/airgapped-timesync.yaml",
    "content": "machine:\n  time:\n    servers:\n      - /dev/ptp0\n"
  },
  {
    "path": "hack/test/patches/cilium-kubeproxy.yaml",
    "content": "cluster:\n  network:\n    cni:\n      name: none\n  proxy:\n    disabled: true\n"
  },
  {
    "path": "hack/test/patches/cilium-no-kubeproxy.yaml",
    "content": "cluster:\n  network:\n    cni:\n      name: none\n"
  },
  {
    "path": "hack/test/patches/dm-raid-module.yaml",
    "content": "machine:\n  kernel:\n    modules:\n      - name: dm_raid\n"
  },
  {
    "path": "hack/test/patches/ephemeral-min-max.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\nprovisioning:\n  diskSelector:\n    match: system_disk\n  minSize: 4GB\n  maxSize: 100GB\n"
  },
  {
    "path": "hack/test/patches/ephemeral-nvme.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\nprovisioning:\n  diskSelector:\n    match: disk.transport == 'nvme'\n  minSize: 3GB\n  maxSize: 5GB\n---\napiVersion: v1alpha1\nkind: SwapVolumeConfig\nname: swap1\nprovisioning:\n  diskSelector:\n    match: disk.transport == 'nvme'\n  minSize: 500MB\n  maxSize: 500MB\n---\nmachine:\n  kubelet:\n    extraConfig:\n      memorySwap:\n        swapBehavior: LimitedSwap\n---\napiVersion: v1alpha1\nkind: ZswapConfig\nmaxPoolPercent: 25\nshrinkerEnabled: true\n"
  },
  {
    "path": "hack/test/patches/extensions.yaml",
    "content": "machine:\n  sysctls:\n    user.max_user_namespaces: \"11255\"\n  kernel:\n    modules:\n      - name: asix\n      - name: ax88179_178a\n      - name: ax88796b\n      - name: binfmt_misc\n      - name: btrfs\n      - name: cdc_ether\n      - name: cdc_mbim\n      - name: cdc_ncm\n      - name: cdc_subset\n      - name: cdc_wdm\n      - name: cxgb\n      - name: cxgb3\n      - name: cxgb4\n      - name: cxgb4vf\n      - name: drbd\n      - name: ena\n      - name: gasket\n      - name: net1080\n      - name: option\n      - name: qmi_wwan\n      - name: r8153_ecm\n      - name: thunderbolt\n      - name: thunderbolt_net\n      - name: usb_wwan\n      - name: usbnet\n      - name: usbserial\n      - name: xdma\n      - name: zaurus\n      - name: zfs\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: tailscale\nenvironment:\n  - TS_AUTHKEY=tskey-0000000000000000\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: nut-client\nconfigFiles:\n  - content: |-\n      MONITOR ${upsmonHost} 1 remote ${upsmonPasswd} slave\n      SHUTDOWNCMD \"/sbin/poweroff\"\n    mountPath: /usr/local/etc/nut/upsmon.conf\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: lldpd\nconfigFiles:\n  - content: |\n      configure lldpd portidsubtype ifname\n      unconfigure lldp management-addresses-advertisements\n      unconfigure lldp capabilities-advertisements\n      configure system description \"Talos Node\"\n    mountPath: /usr/local/etc/lldpd/lldpd.conf\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: bird2\nconfigFiles:\n  - mountPath: /usr/local/etc/bird.conf\n    content: |\n      # This is just a minimal NOOP config!\n      log stderr all;\n      router id 6.6.6.6;\n      protocol device {}\n"
  },
  {
    "path": "hack/test/patches/flannel-netpol.yaml",
    "content": "# enable network policies in flannel CNI plugin\n# see PR: https://github.com/siderolabs/talos/pull/12590\ncluster:\n  network:\n    cni:\n      name: flannel\n      flannel:\n        kubeNetworkPoliciesEnabled: true\n"
  },
  {
    "path": "hack/test/patches/image-cache-encrypted.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: IMAGECACHE\nencryption:\n    provider: luks2\n    keys:\n        - slot: 0\n          static:\n            passphrase: imagesecret\n"
  },
  {
    "path": "hack/test/patches/image-cache.yaml",
    "content": "machine:\n  features:\n    imageCache:\n      localEnabled: true\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: '*'\nskipFallback: true\nendpoints:\n  - url: http://172.20.0.251:65000\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: k8s.gcr.io\nskipFallback: true\nendpoints:\n  - url: http://172.20.0.251:65000\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: registry.k8s.io\nskipFallback: true\nendpoints:\n  - url: http://172.20.0.251:65000\n---\napiVersion: v1alpha1\nkind: VolumeConfig\nname: IMAGECACHE\nprovisioning:\n  diskSelector:\n    match: 'system_disk'\n  maxSize: 3GiB\n  grow: true\n"
  },
  {
    "path": "hack/test/patches/image-verification.yaml",
    "content": "apiVersion: v1alpha1\nkind: ImageVerificationConfig\nrules:\n    - image: registry.k8s.io/e2e-test-images/*\n      skip: true # skip verification for e2e test images since they are not signed\n    - image: registry.k8s.io/*\n      keyless:\n        issuer: https://accounts.google.com\n        subject: krel-trust@k8s-releng-prod.iam.gserviceaccount.com\n    - image: ghcr.io/siderolabs/*\n      keyless:\n        issuer: https://accounts.google.com\n        subjectRegex: '(@siderolabs\\.com$|^releasemgr-svc@talos-production\\.iam\\.gserviceaccount\\.com$)'\n"
  },
  {
    "path": "hack/test/patches/longhorn-cp.yaml",
    "content": "---\ncluster:\n  apiServer:\n    admissionControl:\n      - name: PodSecurity\n        configuration:\n          exemptions:\n            namespaces:\n              - longhorn-system\n"
  },
  {
    "path": "hack/test/patches/longhorn.yaml",
    "content": "---\nmachine:\n  sysctls:\n    vm.nr_hugepages: \"1024\"\n  kernel:\n    modules:\n      - name: nvme_tcp\n      - name: vfio_pci\n      - name: uio_pci_generic\n  kubelet:\n    extraMounts:\n      - destination: /var/lib/longhorn\n        type: bind\n        source: /var/lib/longhorn\n        options:\n          - bind\n          - rshared\n          - rw\n"
  },
  {
    "path": "hack/test/patches/node-address-v2.yaml",
    "content": "machine:\n  features:\n    nodeAddressSortAlgorithm: v2\n"
  },
  {
    "path": "hack/test/patches/openebs-cp.yaml",
    "content": "---\ncluster:\n  apiServer:\n    admissionControl:\n      - name: PodSecurity\n        configuration:\n          exemptions:\n            namespaces:\n              - openebs\n"
  },
  {
    "path": "hack/test/patches/openebs.yaml",
    "content": "---\nmachine:\n  sysctls:\n    vm.nr_hugepages: \"1024\"\n  nodeLabels:\n    openebs.io/engine: \"mayastor\"\n  kubelet:\n    extraMounts:\n      - destination: /var/local\n        type: bind\n        source: /var/local\n        options:\n          - bind\n          - rshared\n          - rw\n"
  },
  {
    "path": "hack/test/patches/proxied-registry.yaml",
    "content": "apiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: registry.dev.siderolabs.io\nskipFallback: true\nendpoints:\n  - url: https://172.20.1.1:8004\n"
  },
  {
    "path": "hack/test/patches/rook-ceph.yaml",
    "content": "cluster:\n  apiServer:\n    admissionControl:\n      - name: PodSecurity\n        configuration:\n          exemptions:\n            namespaces:\n              - rook-ceph\n"
  },
  {
    "path": "hack/test/patches/usernamespace.yaml",
    "content": "---\ncluster:\n  apiServer:\n    extraArgs:\n      feature-gates: UserNamespacesSupport=true\nmachine:\n  sysctls:\n    user.max_user_namespaces: \"11255\"\n  kubelet:\n    extraConfig:\n      featureGates:\n        UserNamespacesSupport: true\n"
  },
  {
    "path": "hack/test/patches/watchdog.yaml",
    "content": "apiVersion: v1alpha1\nkind: WatchdogTimerConfig\ndevice: /dev/watchdog0\ntimeout: 2m0s \n"
  },
  {
    "path": "hack/test/provision-tests.sh",
    "content": "#!/usr/bin/env bash\n\nset -eoux pipefail\n\nINTEGRATION_TEST_FLAGS=()\n\ncase \"${CI:-false}\" in\n  true)\n    MIRROR_FLAG=()\n\n    for registry in docker.io k8s.gcr.io registry.k8s.io quay.io gcr.io ghcr.io; do\n      service=\"registry-${registry//./-}.ci.svc\"\n      addr=$(python3 -c \"import socket; print(socket.gethostbyname('${service}'))\")\n\n      MIRROR_FLAG+=(\"${registry}=http://${addr}:5000\")\n    done\n\n    MIRROR_FLAGS=\"${MIRROR_FLAG[*]}\"\n\n    INTEGRATION_TEST_FLAGS+=(\"-talos.provision.target-installer-registry=${REGISTRY}\" \"-talos.provision.registry-mirror=${MIRROR_FLAGS// /,}\")\n    ;;\n  *)\n    ;;\nesac\n\nif [ \"${INTEGRATION_TEST_RUN:-undefined}\" != \"undefined\" ]; then\n  INTEGRATION_TEST_FLAGS+=(\"-test.run=${INTEGRATION_TEST_RUN}\")\nfi\n\nif [ \"${INTEGRATION_TEST_TRACK:-undefined}\" != \"undefined\" ]; then\n  INTEGRATION_TEST_FLAGS+=(\"-talos.provision.cidr=172.$(( INTEGRATION_TEST_TRACK + 21 )).0.0/24\")\nfi\n\ncase \"${CUSTOM_CNI_URL:-false}\" in\n  false)\n    ;;\n  *)\n    INTEGRATION_TEST_FLAGS+=(\"-talos.provision.custom-cni-url=${CUSTOM_CNI_URL}\")\n    ;;\nesac\n\n\"${INTEGRATION_TEST}\" -test.v \\\n  -talos.talosctlpath \"${TALOSCTL}\" \\\n  -talos.provision.mtu 1430  \\\n  -talos.provision.cni-bundle-url \"${ARTIFACTS}/talosctl-cni-bundle-\\${ARCH}.tar.gz\" \\\n  \"${INTEGRATION_TEST_FLAGS[@]}\"\n"
  },
  {
    "path": "hack/test/tfvars/aws.jq",
    "content": "{\n    \"cluster_name\": .cluster_name,\n    \"ccm\": true,\n    \"talos_version_contract\": .talos_version_contract,\n    \"kubernetes_version\": .kubernetes_version,\n    \"control_plane\": {\n        \"ami_id\": .ami_id,\n        \"instance_type\": \"t3.large\"\n    },\n    \"worker_groups\": (if .worker_group == \"nvidia\" then [\n        {\n            \"name\": \"nvidia-t4\",\n            \"ami_id\": .nvidia_ami_id,\n            \"instance_type\": \"g4dn.xlarge\",\n            \"config_patch_files\": [\n                \"nvidia.yaml\"\n            ],\n            \"tags\": {\n                \"Type\": \"nvidia-t4\"\n            }\n        }\n    ] else [\n        {\n            \"name\": \"default\",\n            \"num_instances\": 3,\n            \"ami_id\": .ami_id,\n            \"instance_type\": \"t3.large\"\n        }\n    ] end),\n    \"extra_tags\": {\n        \"ClusterName\": .cluster_name,\n        \"Project\": \"talos-e2e-ci\",\n        \"Environment\": \"ci\"\n    }\n}\n"
  },
  {
    "path": "hack/test/tfvars/azure.jq",
    "content": "{\n    \"cluster_name\": .cluster_name,\n    \"talos_version_contract\": .talos_version_contract,\n    \"kubernetes_version\": .kubernetes_version,\n    \"azure_location\": \"eastus\",\n    \"control_plane\": {\n        \"vm_os_id\": .vm_os_id,\n        \"vm_size\": \"Standard_B2s\"\n    },\n    \"worker_groups\": [\n        {\n            \"name\": \"default\",\n            \"vm_os_id\": .vm_os_id,\n            \"vm_size\": \"Standard_B2s\"\n        }\n    ],\n    \"extra_tags\": {\n        \"Cluster Name\": .cluster_name,\n        \"Project\": \"talos-e2e-ci\",\n        \"Environment\": \"ci\"\n    }\n}\n"
  },
  {
    "path": "hack/test/tfvars/gcp.jq",
    "content": "{\n    \"project\": .project_id,\n    \"region\": .region,\n    \"zone\": .zone,\n    \"cluster_name\": .cluster_name,\n    \"talos_version_contract\": .talos_version_contract,\n    \"kubernetes_version\": .kubernetes_version,\n    \"control_plane\": {\n        \"image\": .gcp_image,\n    }\n}\n"
  },
  {
    "path": "hack/test/tfvars/nvidia.yaml",
    "content": "machine:\n  kernel:\n    modules:\n      - name: nvidia\n      - name: nvidia_uvm\n      - name: nvidia_drm\n      - name: nvidia_modeset\n"
  },
  {
    "path": "hack/udevd/40-vm-hotadd.rules",
    "content": "SUBSYSTEM==\"cpu\", ACTION==\"add\", TEST==\"online\", ATTR{online}!=\"1\", ATTR{online}=\"1\"\n"
  },
  {
    "path": "hack/udevd/90-selinux.rules",
    "content": "SUBSYSTEM==\"rtc\",SECLABEL{selinux}=\"system_u:object_r:rtc_device_t:s0\"\nSUBSYSTEM==\"mtd\",SECLABEL{selinux}=\"system_u:object_r:mtd_device_t:s0\"\nSUBSYSTEM==\"tpm\",SECLABEL{selinux}=\"system_u:object_r:tpm_device_t:s0\"\nSUBSYSTEM==\"tpmrm\",SECLABEL{selinux}=\"system_u:object_r:tpm_device_t:s0\"\n\nKERNEL==\"watchdog\",SECLABEL{selinux}=\"system_u:object_r:wdt_device_t:s0\"\nKERNEL==\"watchdog*\",SECLABEL{selinux}=\"system_u:object_r:wdt_device_t:s0\"\nKERNEL==\"null\",SECLABEL{selinux}=\"system_u:object_r:null_device_t:s0\"\nKERNEL==\"zero\",SECLABEL{selinux}=\"system_u:object_r:null_device_t:s0\"\n"
  },
  {
    "path": "hack/udevd/99-default.link",
    "content": "# SPDX-License-Identifier: MIT-0\n#\n# This config file is installed as part of systemd.\n# It may be freely copied and edited (following the MIT No Attribution license).\n#\n# To make local modifications, use \"networkctl edit\". See networkctl(1) for details.\n# This file should not be edited in place, because it'll be overwritten on upgrades.\n\n[Match]\nOriginalName=*\n\n[Link]\nNamePolicy=keep kernel database onboard slot path mac\nAlternativeNamesPolicy=database onboard slot path mac\nMACAddressPolicy=none\n"
  },
  {
    "path": "internal/app/apid/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage apid\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"github.com/siderolabs/go-debug\"\n)\n\nfunc runDebugServer(ctx context.Context) {\n\tconst debugAddr = \":9981\"\n\n\tdebugLogFunc := func(msg string) {\n\t\tlog.Print(msg)\n\t}\n\n\tif err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {\n\t\tlog.Fatalf(\"failed to start debug server: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "internal/app/apid/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package apid implements apid functionality.\npackage apid\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/client\"\n\t\"github.com/siderolabs/gen/panicsafe\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/startup\"\n)\n\n// Main is the entrypoint of apid.\nfunc Main() {\n\tif err := apidMain(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\n// apidMain is the entrypoint of apid.\n//\n// It fetches service config as a resource and keeps watching it\n// for changes.\n//\n// If the service config changes, it shuts down the listener and starts a new one with the new configuration.\n//\n//nolint:gocyclo\nfunc apidMain() error {\n\tctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)\n\tdefer cancel()\n\n\tlog.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime)\n\n\tflag.Parse()\n\n\tgo runDebugServer(ctx)\n\n\tstartup.LimitMaxProcs(constants.ApidMaxProcs)\n\n\truntimeConn, err := grpc.NewClient(\"unix://\"+constants.APIRuntimeSocketPath,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithNoProxy(),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dial runtime connection: %w\", err)\n\t}\n\n\tstateClient := v1alpha1.NewStateClient(runtimeConn)\n\tresources := state.WrapCore(client.NewAdapter(stateClient))\n\n\tconfigWatchCh := make(chan safe.WrappedStateEvent[*runtime.APIServiceConfig])\n\n\tif err = safe.StateWatch(ctx, resources, runtime.NewAPIServiceConfig().Metadata(), configWatchCh); err != nil {\n\t\treturn fmt.Errorf(\"failed to set up watch for API service config: %w\", err)\n\t}\n\n\tvar (\n\t\tserviceConfig *runtime.APIServiceConfig\n\t\tcancelService context.CancelFunc\n\t)\n\n\tserviceErrCh := make(chan error, 1)\n\nouterLoop:\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tbreak outerLoop\n\t\tcase err = <-serviceErrCh:\n\t\t\tcancelService = nil\n\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"service error: %w\", err)\n\t\t\t}\n\t\tcase event := <-configWatchCh:\n\t\t\tswitch event.Type() {\n\t\t\tcase state.Created, state.Updated:\n\t\t\t\tserviceConfig, err = event.Resource()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to get API service config from watch event: %w\", err) //nolint:govet\n\t\t\t\t}\n\t\t\tcase state.Destroyed:\n\t\t\t\tserviceConfig = nil\n\t\t\tcase state.Errored:\n\t\t\t\treturn fmt.Errorf(\"service config watch error: %w\", event.Error())\n\t\t\tcase state.Bootstrapped, state.Noop:\n\t\t\t\t// ignore\n\t\t\t\tcontinue outerLoop\n\t\t\t}\n\t\t}\n\n\t\t// we got a change in the service config, restart the server with the new config\n\t\tif cancelService != nil {\n\t\t\tcancelService()\n\n\t\t\tcancelService = nil\n\n\t\t\t// wait for the service to shut down\n\t\t\t<-serviceErrCh\n\t\t}\n\n\t\tif serviceConfig != nil {\n\t\t\tvar serviceCtx context.Context\n\n\t\t\tserviceCtx, cancelService = context.WithCancel(ctx) //nolint:govet\n\n\t\t\tgo func() {\n\t\t\t\tserviceErrCh <- panicsafe.RunErr(func() error {\n\t\t\t\t\treturn runService(serviceCtx, resources, serviceConfig)\n\t\t\t\t})\n\t\t\t}()\n\t\t}\n\t}\n\n\tif cancelService != nil {\n\t\tcancelService()\n\n\t\t<-serviceErrCh\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/backend/apid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"github.com/siderolabs/net\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/backoff\"\n\t\"google.golang.org/grpc/connectivity\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/encoding/protowire\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// GracefulShutdownTimeout is the timeout for graceful shutdown of the backend connection.\n//\n// Talos has a few long-running API calls, so we need to give the backend some time to finish them.\n//\n// The connection will enter IDLE time after GracefulShutdownTimeout/2, if no RPC is running.\nconst GracefulShutdownTimeout = 30 * time.Minute\n\nvar _ proxy.Backend = (*APID)(nil)\n\n// APID backend performs proxying to another apid instance.\n//\n// Backend authenticates itself using given grpc credentials.\ntype APID struct {\n\ttarget string\n\n\ttlsConfigProvider func() (*tls.Config, error)\n\n\tmu   sync.Mutex\n\tconn *grpc.ClientConn\n}\n\n// NewAPID creates new instance of APID backend.\nfunc NewAPID(target string, tlsConfigProvider func() (*tls.Config, error)) (*APID, error) {\n\t// perform very basic validation on target, trying to weed out empty addresses or addresses with the port appended\n\tif target == \"\" || net.AddressContainsPort(target) {\n\t\treturn nil, fmt.Errorf(\"invalid target %q\", target)\n\t}\n\n\treturn &APID{\n\t\ttarget:            target,\n\t\ttlsConfigProvider: tlsConfigProvider,\n\t}, nil\n}\n\nfunc (a *APID) String() string {\n\treturn a.target\n}\n\n// GetConnection returns a grpc connection to the backend.\nfunc (a *APID) GetConnection(ctx context.Context, _ string) (context.Context, *grpc.ClientConn, error) {\n\tmd, _ := metadata.FromIncomingContext(ctx)\n\tmd = md.Copy()\n\n\tauthz.SetMetadata(md, authz.GetRoles(ctx))\n\n\tif authority := md[\":authority\"]; len(authority) > 0 {\n\t\tmd.Set(\"proxyfrom\", authority...)\n\t} else {\n\t\tmd.Set(\"proxyfrom\", \"unknown\")\n\t}\n\n\tdelete(md, \":authority\")\n\tdelete(md, \"nodes\")\n\tdelete(md, \"node\")\n\n\toutCtx := metadata.NewOutgoingContext(ctx, md)\n\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\tif a.conn != nil {\n\t\treturn outCtx, a.conn, nil\n\t}\n\n\ttlsConfig, err := a.tlsConfigProvider()\n\tif err != nil {\n\t\treturn outCtx, nil, err\n\t}\n\n\t// override  max delay to avoid excessive backoff when the another node is unavailable (e.g. rebooted),\n\t// and apid used as an endpoint considers another node to be down for longer than expected.\n\t//\n\t// default max delay is 2 minutes, which is too long for our use case.\n\tbackoffConfig := backoff.DefaultConfig\n\tbackoffConfig.MaxDelay = 15 * time.Second\n\n\ta.conn, err = grpc.NewClient(\n\t\tfmt.Sprintf(\"%s:%d\", net.FormatAddress(a.target), constants.ApidPort),\n\t\tgrpc.WithInitialWindowSize(65535*32),\n\t\tgrpc.WithInitialConnWindowSize(65535*16),\n\t\tgrpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),\n\t\tgrpc.WithIdleTimeout(GracefulShutdownTimeout/2), // use half of the shutdown timeout as idle timeout\n\t\tgrpc.WithConnectParams(grpc.ConnectParams{\n\t\t\tBackoff: backoffConfig,\n\t\t\t// not published as a constant in gRPC library\n\t\t\t// see: https://github.com/grpc/grpc-go/blob/d5dee5fdbdeb52f6ea10b37b2cc7ce37814642d7/clientconn.go#L55-L56\n\t\t\tMinConnectTimeout: 20 * time.Second,\n\t\t}),\n\t\tgrpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallRecvMsgSize(constants.GRPCMaxMessageSize),\n\t\t\tgrpc.ForceCodecV2(proxy.Codec()),\n\t\t),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t)\n\n\treturn outCtx, a.conn, err\n}\n\n// AppendInfo is called to enhance response from the backend with additional data.\n//\n// AppendInfo enhances upstream response with node metadata (target).\n//\n// This method depends on grpc protobuf response structure, each response should\n// look like:\n//\n//\t  message SomeResponse {\n//\t    repeated SomeReply messages = 1; // please note field ID == 1\n//\t  }\n//\n//\t  message SomeReply {\n//\t\t   common.Metadata metadata = 1;\n//\t    <other fields go here ...>\n//\t  }\n//\n// As 'SomeReply' is repeated in 'SomeResponse', if we concatenate protobuf representation\n// of several 'SomeResponse' messages, we still get valid 'SomeResponse' representation but with more\n// entries (feature of protobuf binary representation).\n//\n// If we look at binary representation of any unary 'SomeResponse' message, it will always contain one\n// protobuf field with field ID 1 (see above) and type 2 (embedded message SomeReply is encoded\n// as string with length). So if we want to add fields to 'SomeReply', we can simply read field\n// header, adjust length for new 'SomeReply' representation, and prepend new field header.\n//\n// At the same time, we can add 'common.Metadata' structure to 'SomeReply' by simply\n// appending or prepending 'common.Metadata' as a single field. This requires 'metadata'\n// field to be not defined in original response. (This is due to the fact that protobuf message\n// representation is concatenation of each field representation).\n//\n// To build only single field (Metadata) we use helper message which contains exactly this\n// field with same field ID as in every other 'SomeReply':\n//\n//\t  message Empty {\n//\t    common.Metadata metadata = 1;\n//\t\t}\n//\n// As streaming replies are not wrapped into 'SomeResponse' with 'repeated', handling is simpler: we just\n// need to append Empty with details.\n//\n// So AppendInfo does the following: validates that response contains field ID 1 encoded as string,\n// cuts field header, rest is representation of some reply. Marshal 'Empty' as protobuf,\n// which builds 'common.Metadata' field, append it to original response message, build new header\n// for new length of some response, and add back new field header.\nfunc (a *APID) AppendInfo(streaming bool, resp []byte) ([]byte, error) {\n\tpayload, err := proto.Marshal(&common.Empty{\n\t\tMetadata: &common.Metadata{\n\t\t\tHostname: a.target,\n\t\t},\n\t})\n\n\tif streaming {\n\t\treturn append(resp, payload...), err\n\t}\n\n\tconst (\n\t\tmetadataField = 1 // field number in proto definition for repeated response\n\t\tmetadataType  = 2 // \"string\" for embedded messages\n\t)\n\n\t// decode protobuf embedded header\n\n\ttyp, n1 := protowire.ConsumeVarint(resp)\n\tif n1 < 0 {\n\t\treturn nil, protowire.ParseError(n1)\n\t}\n\n\t_, n2 := protowire.ConsumeVarint(resp[n1:]) // length\n\tif n2 < 0 {\n\t\treturn nil, protowire.ParseError(n2)\n\t}\n\n\tif typ != (metadataField<<3)|metadataType {\n\t\treturn nil, fmt.Errorf(\"unexpected message format: %d\", typ)\n\t}\n\n\tif n1+n2 > len(resp) {\n\t\treturn nil, fmt.Errorf(\"unexpected message size: %d\", len(resp))\n\t}\n\n\t// cut off embedded message header\n\tresp = resp[n1+n2:]\n\t// build new embedded message header\n\tprefix := protowire.AppendVarint(\n\t\tprotowire.AppendVarint(nil, (metadataField<<3)|metadataType),\n\t\tuint64(len(resp)+len(payload)),\n\t)\n\n\treturn slices.Concat(prefix, resp, payload), err\n}\n\n// BuildError is called to convert error from upstream into response field.\n//\n// BuildError converts upstream error into message from upstream, so that multiple\n// successful and failure responses might be returned.\n//\n// This simply relies on the fact that any response contains 'Empty' message.\n// So if 'Empty' is unmarshalled into any other reply message, all the fields\n// are undefined but 'Metadata':\n//\n//\t  message Empty {\n//\t   common.Metadata metadata = 1;\n//\t\t}\n//\n//\t message EmptyResponse {\n//\t   repeated Empty messages = 1;\n//\t}\n//\n// Streaming responses are not wrapped into Empty, so we simply marshall EmptyResponse\n// message.\nfunc (a *APID) BuildError(streaming bool, err error) ([]byte, error) {\n\tvar resp proto.Message = &common.Empty{\n\t\tMetadata: &common.Metadata{\n\t\t\tHostname: a.target,\n\t\t\tError:    err.Error(),\n\t\t\tStatus:   status.Convert(err).Proto(),\n\t\t},\n\t}\n\n\tif !streaming {\n\t\tresp = &common.EmptyResponse{\n\t\t\tMessages: []*common.Empty{\n\t\t\t\tresp.(*common.Empty),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn proto.Marshal(resp)\n}\n\n// Close connection.\nfunc (a *APID) Close() {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\n\tif a.conn != nil {\n\t\tgracefulGRPCClose(a.conn, GracefulShutdownTimeout)\n\t\ta.conn = nil\n\t}\n}\n\nfunc gracefulGRPCClose(conn *grpc.ClientConn, timeout time.Duration) {\n\t// close the client connection in the background, tries to avoid closing the connection\n\t// if the connection is in the middle of a call (e.g. streaming API)\n\t//\n\t// see https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md for details on connection states\n\tgo func() {\n\t\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\t\tdefer cancel()\n\n\t\tfor ctx.Err() == nil {\n\t\t\tswitch state := conn.GetState(); state { //nolint:exhaustive\n\t\t\tcase connectivity.Idle,\n\t\t\t\tconnectivity.Shutdown,\n\t\t\t\tconnectivity.TransientFailure:\n\t\t\t\t// close immediately, connection is not used\n\t\t\t\tconn.Close() //nolint:errcheck\n\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t\t// wait for state change of the connection\n\t\t\t\tconn.WaitForStateChange(ctx, state)\n\t\t\t}\n\t\t}\n\n\t\t// close anyways on timeout\n\t\tconn.Close() //nolint:errcheck\n\t}()\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/backend/apid_factory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend\n\nimport (\n\t\"crypto/tls\"\n\n\t\"github.com/siderolabs/gen/concurrent\"\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n)\n\n// APIDFactory caches connection to apid instances by target.\n//\n// TODO: need to clean up idle connections from time to time.\ntype APIDFactory struct {\n\tcache    *concurrent.HashTrieMap[string, *APID]\n\tprovider TLSConfigProvider\n}\n\n// TLSConfigProvider provides tls.Config for client connections.\ntype TLSConfigProvider interface {\n\tClientConfig() (*tls.Config, error)\n}\n\n// NewAPIDFactory creates new APIDFactory with given tls.Config.\n//\n// Client TLS config is used to connect to other apid instances.\nfunc NewAPIDFactory(provider TLSConfigProvider) *APIDFactory {\n\treturn &APIDFactory{\n\t\tcache:    concurrent.NewHashTrieMap[string, *APID](),\n\t\tprovider: provider,\n\t}\n}\n\n// Get backend by target.\n//\n// Get performs caching of backends.\nfunc (factory *APIDFactory) Get(target string) (proxy.Backend, error) {\n\tb, ok := factory.cache.Load(target)\n\tif ok {\n\t\treturn b, nil\n\t}\n\n\tbackend, err := NewAPID(target, factory.provider.ClientConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\texisting, loaded := factory.cache.LoadOrStore(target, backend)\n\tif loaded {\n\t\t// race: another Get() call built different backend\n\t\tbackend.Close()\n\n\t\treturn existing, nil\n\t}\n\n\treturn backend, nil\n}\n\n// Flush all cached backends.\n//\n// This ensures that all connections are closed.\nfunc (factory *APIDFactory) Flush() {\n\tfactory.cache.Range(func(key string, backend *APID) bool {\n\t\tbackend.Close()\n\n\t\treturn true\n\t})\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/backend/apid_factory_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend_test\n\nimport (\n\t\"crypto/tls\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/apid/pkg/backend\"\n)\n\ntype APIDFactorySuite struct {\n\tsuite.Suite\n\n\tf *backend.APIDFactory\n}\n\ntype fakeTLSConfigProvider struct{}\n\nfunc (fakeTLSConfigProvider) ClientConfig() (*tls.Config, error) {\n\treturn &tls.Config{}, nil\n}\n\nfunc (suite *APIDFactorySuite) SetupSuite() {\n\tsuite.f = backend.NewAPIDFactory(fakeTLSConfigProvider{})\n}\n\nfunc (suite *APIDFactorySuite) TestGet() {\n\tb1, err := suite.f.Get(\"127.0.0.1\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotNil(b1)\n\n\tb2, err := suite.f.Get(\"127.0.0.1\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Equal(b1, b2)\n\n\tb3, err := suite.f.Get(\"127.0.0.2\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotEqual(b1, b3)\n\n\t_, err = suite.f.Get(\"127.0.0.2:50000\")\n\tsuite.Require().Error(err)\n}\n\nfunc (suite *APIDFactorySuite) TestGetConcurrent() {\n\t// for race detector\n\tvar wg sync.WaitGroup\n\n\tbackendCh := make(chan proxy.Backend, 10)\n\n\tfor range 10 {\n\t\twg.Go(func() {\n\t\t\tb, _ := suite.f.Get(\"10.0.0.1\") //nolint:errcheck\n\t\t\tbackendCh <- b\n\t\t})\n\t}\n\n\twg.Wait()\n\tclose(backendCh)\n\n\tb := <-backendCh\n\n\tfor anotherB := range backendCh {\n\t\tsuite.Assert().Equal(b, anotherB)\n\t}\n}\n\nfunc TestAPIDFactorySuite(t *testing.T) {\n\tsuite.Run(t, new(APIDFactorySuite))\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/backend/apid_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend_test\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"google.golang.org/grpc/metadata\"\n\tprotobuf \"google.golang.org/protobuf/proto\" //nolint:depguard\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/siderolabs/talos/internal/app/apid/pkg/backend\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\ntype APIDSuite struct {\n\tsuite.Suite\n\n\tb *backend.APID\n}\n\nfunc (suite *APIDSuite) SetupSuite() {\n\ttlsConfigProvider := func() (*tls.Config, error) {\n\t\treturn &tls.Config{}, nil\n\t}\n\n\tvar err error\n\n\tsuite.b, err = backend.NewAPID(\"127.0.0.1\", tlsConfigProvider)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *APIDSuite) TestGetConnection() {\n\tmd1 := metadata.New(nil)\n\tmd1.Set(\":authority\", \"127.0.0.2\")\n\tmd1.Set(\"nodes\", \"127.0.0.1\")\n\tmd1.Set(\"key\", \"value1\", \"value2\")\n\tctx1 := metadata.NewIncomingContext(authz.ContextWithRoles(context.Background(), role.MakeSet(role.Admin)), md1)\n\n\toutCtx1, conn1, err1 := suite.b.GetConnection(ctx1, \"\")\n\tsuite.Require().NoError(err1)\n\tsuite.Assert().NotNil(conn1)\n\tsuite.Assert().Equal(role.MakeSet(role.Admin), authz.GetRoles(outCtx1))\n\n\tmdOut1, ok1 := metadata.FromOutgoingContext(outCtx1)\n\tsuite.Require().True(ok1)\n\tsuite.Assert().Equal([]string{\"value1\", \"value2\"}, mdOut1.Get(\"key\"))\n\tsuite.Assert().Equal([]string{\"127.0.0.2\"}, mdOut1.Get(\"proxyfrom\"))\n\tsuite.Assert().Equal([]string{\"os:admin\"}, mdOut1.Get(\"talos-role\"))\n\n\tsuite.Run(\n\t\t\"Same context\", func() {\n\t\t\tctx2 := ctx1\n\t\t\toutCtx2, conn2, err2 := suite.b.GetConnection(ctx2, \"\")\n\t\t\tsuite.Require().NoError(err2)\n\t\t\tsuite.Assert().Equal(conn1, conn2) // connection is cached\n\t\t\tsuite.Assert().Equal(role.MakeSet(role.Admin), authz.GetRoles(outCtx2))\n\n\t\t\tmdOut2, ok2 := metadata.FromOutgoingContext(outCtx2)\n\t\t\tsuite.Require().True(ok2)\n\t\t\tsuite.Assert().Equal([]string{\"value1\", \"value2\"}, mdOut2.Get(\"key\"))\n\t\t\tsuite.Assert().Equal([]string{\"127.0.0.2\"}, mdOut2.Get(\"proxyfrom\"))\n\t\t\tsuite.Assert().Equal([]string{\"os:admin\"}, mdOut2.Get(\"talos-role\"))\n\t\t},\n\t)\n\n\tsuite.Run(\n\t\t\"Other context\", func() {\n\t\t\tmd3 := metadata.New(nil)\n\t\t\tmd3.Set(\":authority\", \"127.0.0.2\")\n\t\t\tmd3.Set(\"nodes\", \"127.0.0.1\")\n\t\t\tmd3.Set(\"key\", \"value3\", \"value4\")\n\t\t\tctx3 := metadata.NewIncomingContext(\n\t\t\t\tauthz.ContextWithRoles(context.Background(), role.MakeSet(role.Reader)),\n\t\t\t\tmd3,\n\t\t\t)\n\n\t\t\toutCtx3, conn3, err3 := suite.b.GetConnection(ctx3, \"\")\n\t\t\tsuite.Require().NoError(err3)\n\t\t\tsuite.Assert().Equal(conn1, conn3) // connection is cached\n\t\t\tsuite.Assert().Equal(role.MakeSet(role.Reader), authz.GetRoles(outCtx3))\n\n\t\t\tmdOut3, ok3 := metadata.FromOutgoingContext(outCtx3)\n\t\t\tsuite.Require().True(ok3)\n\t\t\tsuite.Assert().Equal([]string{\"value3\", \"value4\"}, mdOut3.Get(\"key\"))\n\t\t\tsuite.Assert().Equal([]string{\"127.0.0.2\"}, mdOut3.Get(\"proxyfrom\"))\n\t\t\tsuite.Assert().Equal([]string{\"os:reader\"}, mdOut3.Get(\"talos-role\"))\n\t\t},\n\t)\n}\n\nfunc (suite *APIDSuite) TestAppendInfoUnary() {\n\treply := &common.DataResponse{\n\t\tMessages: []*common.Data{\n\t\t\t{\n\t\t\t\tBytes: []byte(\"foobar\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tresp, err := proto.Marshal(reply)\n\tsuite.Require().NoError(err)\n\n\tnewResp, err := suite.b.AppendInfo(false, resp)\n\tsuite.Require().NoError(err)\n\n\tvar newReply common.DataResponse\n\n\terr = proto.Unmarshal(newResp, &newReply)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().EqualValues([]byte(\"foobar\"), newReply.Messages[0].Bytes)\n\tsuite.Assert().Equal(suite.b.String(), newReply.Messages[0].Metadata.Hostname)\n\tsuite.Assert().Empty(newReply.Messages[0].Metadata.Error)\n}\n\nfunc (suite *APIDSuite) TestAppendInfoStreaming() {\n\tresponse := &common.Data{\n\t\tBytes: []byte(\"foobar\"),\n\t}\n\n\tresp, err := proto.Marshal(response)\n\tsuite.Require().NoError(err)\n\n\tnewResp, err := suite.b.AppendInfo(true, resp)\n\tsuite.Require().NoError(err)\n\n\tvar newResponse common.Data\n\n\terr = proto.Unmarshal(newResp, &newResponse)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().EqualValues([]byte(\"foobar\"), newResponse.Bytes)\n\tsuite.Assert().Equal(suite.b.String(), newResponse.Metadata.Hostname)\n\tsuite.Assert().Empty(newResponse.Metadata.Error)\n}\n\nfunc (suite *APIDSuite) TestAppendInfoStreamingMetadata() {\n\t// this tests the case when metadata field is appended twice\n\t// to the message, but protobuf merges definitions\n\tresponse := &common.Data{\n\t\tMetadata: &common.Metadata{\n\t\t\tError: \"something went wrong\",\n\t\t},\n\t}\n\n\tresp, err := proto.Marshal(response)\n\tsuite.Require().NoError(err)\n\n\tnewResp, err := suite.b.AppendInfo(true, resp)\n\tsuite.Require().NoError(err)\n\n\tvar newResponse common.Data\n\n\terr = proto.Unmarshal(newResp, &newResponse)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Nil(newResponse.Bytes)\n\tsuite.Assert().Equal(suite.b.String(), newResponse.Metadata.Hostname)\n\tsuite.Assert().Equal(\"something went wrong\", newResponse.Metadata.Error)\n}\n\nfunc (suite *APIDSuite) TestBuildErrorUnary() {\n\tresp, err := suite.b.BuildError(false, errors.New(\"some error\"))\n\tsuite.Require().NoError(err)\n\n\tvar reply common.DataResponse\n\n\terr = proto.Unmarshal(resp, &reply)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Nil(reply.Messages[0].Bytes)\n\tsuite.Assert().Equal(suite.b.String(), reply.Messages[0].Metadata.Hostname)\n\tsuite.Assert().Equal(\"some error\", reply.Messages[0].Metadata.Error)\n}\n\nfunc (suite *APIDSuite) TestBuildErrorStreaming() {\n\tresp, err := suite.b.BuildError(true, errors.New(\"some error\"))\n\tsuite.Require().NoError(err)\n\n\tvar response common.Data\n\n\terr = proto.Unmarshal(resp, &response)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Nil(response.Bytes)\n\tsuite.Assert().Equal(suite.b.String(), response.Metadata.Hostname)\n\tsuite.Assert().Equal(\"some error\", response.Metadata.Error)\n}\n\nfunc TestAPIDSuite(t *testing.T) {\n\tsuite.Run(t, new(APIDSuite))\n}\n\nfunc TestAPIIdiosyncrasies(t *testing.T) {\n\tfor _, services := range xslices.Map(api.TalosAPIdOne2ManyAPIs(),\n\t\tfunc(fd protoreflect.FileDescriptor) protoreflect.ServiceDescriptors {\n\t\t\treturn fd.Services()\n\t\t},\n\t) {\n\t\tfor i := range services.Len() {\n\t\t\tservice := services.Get(i)\n\t\t\tmethods := service.Methods()\n\n\t\t\tfor j := range methods.Len() {\n\t\t\t\tmethod := methods.Get(j)\n\n\t\t\t\tt.Run(\n\t\t\t\t\tstring(method.FullName()), func(t *testing.T) {\n\t\t\t\t\t\tresponse := method.Output()\n\t\t\t\t\t\tresponseFields := response.Fields()\n\n\t\t\t\t\t\tif method.IsStreamingServer() {\n\t\t\t\t\t\t\tmetadata := responseFields.Get(0)\n\t\t\t\t\t\t\tassert.Equal(t, \"metadata\", metadata.TextName())\n\t\t\t\t\t\t\tassert.Equal(t, 1, int(metadata.Number()))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trequire.Equal(t, 1, responseFields.Len(), \"unary responses should have exactly one field\")\n\n\t\t\t\t\t\t\tmessages := responseFields.Get(0)\n\t\t\t\t\t\t\tassert.Equal(t, \"messages\", messages.TextName())\n\t\t\t\t\t\t\tassert.Equal(t, 1, int(messages.Number()))\n\n\t\t\t\t\t\t\treply := messages.Message()\n\t\t\t\t\t\t\treplyFields := reply.Fields()\n\t\t\t\t\t\t\trequire.GreaterOrEqual(\n\t\t\t\t\t\t\t\tt,\n\t\t\t\t\t\t\t\treplyFields.Len(),\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"unary replies should have at least one field\",\n\t\t\t\t\t\t\t)\n\n\t\t\t\t\t\t\tmetadata := replyFields.Get(0)\n\t\t\t\t\t\t\tassert.Equal(t, \"metadata\", metadata.TextName())\n\t\t\t\t\t\t\tassert.Equal(t, 1, int(metadata.Number()))\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n}\n\n//nolint:nakedret,gocyclo,forcetypeassert\nfunc getOptions(t *testing.T, descriptor protoreflect.Descriptor) (deprecated bool, version string) {\n\tswitch opts := descriptor.Options().(type) {\n\tcase *descriptorpb.EnumOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedEnum).(string)\n\t\t}\n\tcase *descriptorpb.EnumValueOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedEnumValue).(string)\n\t\t}\n\tcase *descriptorpb.MessageOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedMessage).(string)\n\t\t}\n\tcase *descriptorpb.FieldOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedField).(string)\n\t\t}\n\tcase *descriptorpb.ServiceOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedService).(string)\n\t\t}\n\tcase *descriptorpb.MethodOptions:\n\t\tif opts != nil {\n\t\t\tdeprecated = pointer.SafeDeref(opts.Deprecated)\n\t\t\tversion = protobuf.GetExtension(opts, common.E_RemoveDeprecatedMethod).(string)\n\t\t}\n\tcase *descriptorpb.OneofOptions:\n\t\t// OneofOptions do not have deprecated option\n\tdefault:\n\t\tt.Fatalf(\"unhandled %T\", opts)\n\t}\n\n\treturn deprecated, version\n}\n\nfunc testDeprecated(t *testing.T, descriptor protoreflect.Descriptor, currentVersion *config.VersionContract) {\n\tdeprecated, version := getOptions(t, descriptor)\n\n\tassert.Equal(\n\t\tt, deprecated, version != \"\",\n\t\t\"%s: `deprecated` and `remove_deprecated_XXX_in` options should be used together\", descriptor.FullName(),\n\t)\n\n\tif !deprecated || version == \"\" {\n\t\treturn\n\t}\n\n\tv, err := config.ParseContractFromVersion(version)\n\trequire.NoError(t, err, \"%s\", descriptor.FullName())\n\n\tassert.True(t, v.Greater(currentVersion), \"%s should be removed in this version\", descriptor.FullName())\n}\n\nfunc testEnum(t *testing.T, enum protoreflect.EnumDescriptor, currentVersion *config.VersionContract) {\n\ttestDeprecated(t, enum, currentVersion)\n\n\tvalues := enum.Values()\n\tfor i := range values.Len() {\n\t\ttestDeprecated(t, values.Get(i), currentVersion)\n\t}\n}\n\nfunc testMessage(t *testing.T, message protoreflect.MessageDescriptor, currentVersion *config.VersionContract) {\n\ttestDeprecated(t, message, currentVersion)\n\n\tfields := message.Fields()\n\tfor i := range fields.Len() {\n\t\ttestDeprecated(t, fields.Get(i), currentVersion)\n\t}\n\n\toneofs := message.Oneofs()\n\tfor i := range oneofs.Len() {\n\t\ttestDeprecated(t, oneofs.Get(i), currentVersion)\n\t}\n\n\tenums := message.Enums()\n\tfor i := range enums.Len() {\n\t\ttestEnum(t, enums.Get(i), currentVersion)\n\t}\n\n\t// test nested messages\n\tmessages := message.Messages()\n\tfor i := range messages.Len() {\n\t\ttestMessage(t, messages.Get(i), currentVersion)\n\t}\n}\n\nfunc TestDeprecatedAPIs(t *testing.T) {\n\tcurrentVersion, err := config.ParseContractFromVersion(version.Tag)\n\trequire.NoError(t, err)\n\n\tfor _, file := range api.AllAPIs() {\n\t\tenums := file.Enums()\n\t\tfor i := range enums.Len() {\n\t\t\ttestEnum(t, enums.Get(i), currentVersion)\n\t\t}\n\n\t\tmessages := file.Messages()\n\t\tfor i := range messages.Len() {\n\t\t\ttestMessage(t, messages.Get(i), currentVersion)\n\t\t}\n\n\t\tservices := file.Services()\n\t\tfor i := range services.Len() {\n\t\t\tservice := services.Get(i)\n\t\t\ttestDeprecated(t, service, currentVersion)\n\n\t\t\tmethods := service.Methods()\n\t\t\tfor j := range methods.Len() {\n\t\t\t\tmethod := methods.Get(j)\n\t\t\t\ttestDeprecated(t, method, currentVersion)\n\n\t\t\t\tmessage := method.Input()\n\t\t\t\ttestMessage(t, message, currentVersion)\n\n\t\t\t\tmessage = method.Output()\n\t\t\t\ttestMessage(t, message, currentVersion)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/backend/backend.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package backend implements backends satisfying proxy.Backend interface\npackage backend\n"
  },
  {
    "path": "internal/app/apid/pkg/director/director.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package director provides proxy call routing facility\npackage director\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// Router wraps grpc-proxy StreamDirector.\ntype Router struct {\n\tlocalBackend         proxy.Backend\n\tremoteBackendFactory RemoteBackendFactory\n\tlocalAddressProvider LocalAddressProvider\n\tstreamedMatchers     []*regexp.Regexp\n\tskipRouting          bool\n}\n\n// RemoteBackendFactory provides backend generation by address (target).\ntype RemoteBackendFactory func(target string) (proxy.Backend, error)\n\n// NewRouter builds new Router.\nfunc NewRouter(backendFactory RemoteBackendFactory, localBackend proxy.Backend, localAddressProvider LocalAddressProvider, skipRouting bool) *Router {\n\treturn &Router{\n\t\tlocalBackend:         localBackend,\n\t\tremoteBackendFactory: backendFactory,\n\t\tlocalAddressProvider: localAddressProvider,\n\t\tskipRouting:          skipRouting,\n\t}\n}\n\n// Register is no-op to implement factory.Registrator interface.\n//\n// Actual proxy handler is installed via grpc.UnknownServiceHandler option.\nfunc (r *Router) Register(srv *grpc.Server) {\n}\n\n// Director implements proxy.StreamDirector function.\n//\n//nolint:gocyclo,cyclop\nfunc (r *Router) Director(ctx context.Context, fullMethodName string) (proxy.Mode, []proxy.Backend, error) {\n\tif r.skipRouting {\n\t\treturn proxy.One2One, []proxy.Backend{r.localBackend}, nil\n\t}\n\n\tmd, ok := metadata.FromIncomingContext(ctx)\n\tif !ok {\n\t\treturn proxy.One2One, []proxy.Backend{r.localBackend}, nil\n\t}\n\n\tif _, exists := md[\"proxyfrom\"]; exists {\n\t\treturn proxy.One2One, []proxy.Backend{r.localBackend}, nil\n\t}\n\n\tnodes, okNodes := md[\"nodes\"]\n\tnode, okNode := md[\"node\"]\n\n\tif okNode && len(node) != 1 {\n\t\treturn proxy.One2One, nil, status.Error(codes.InvalidArgument, \"node metadata must be single-valued\")\n\t}\n\n\t// special handling for cases when a single node is requested, but forwarding is disabled\n\t//\n\t// if there's a single destination, and that destination is local node, skip forwarding and send a request to the same node\n\tif r.remoteBackendFactory == nil {\n\t\tif okNode && r.localAddressProvider.IsLocalTarget(node[0]) {\n\t\t\tokNode = false\n\t\t}\n\n\t\tif okNodes && len(nodes) == 1 && r.localAddressProvider.IsLocalTarget(nodes[0]) {\n\t\t\tokNodes = false\n\t\t}\n\t}\n\n\tswitch {\n\tcase okNodes:\n\t\t// Explicit list of gRPC methods that support one-2-many proxying.\n\t\tswitch {\n\t\tcase strings.HasPrefix(fullMethodName, \"/machine.MachineService/\"):\n\t\tcase strings.HasPrefix(fullMethodName, \"/cluster.ClusterService/\"):\n\t\tcase strings.HasPrefix(fullMethodName, \"/inspect.InspectService/\"):\n\t\tcase strings.HasPrefix(fullMethodName, \"/storage.StorageService/\"):\n\t\tcase strings.HasPrefix(fullMethodName, \"/time.TimeService/\"):\n\t\tdefault:\n\t\t\treturn proxy.One2One, nil, status.Errorf(codes.InvalidArgument, \"one-2-many proxying is not supported for method %s\", fullMethodName)\n\t\t}\n\n\t\treturn r.aggregateDirector(nodes)\n\tcase okNode:\n\t\treturn r.singleDirector(node[0])\n\tdefault:\n\t\t// send directly to local node, skips another layer of proxying\n\t\treturn proxy.One2One, []proxy.Backend{r.localBackend}, nil\n\t}\n}\n\n// singleDirector sends request to a single instance in one-2-one mode.\nfunc (r *Router) singleDirector(target string) (proxy.Mode, []proxy.Backend, error) {\n\tif r.remoteBackendFactory == nil {\n\t\treturn proxy.One2One, nil, status.Error(codes.PermissionDenied, \"no request forwarding\")\n\t}\n\n\tbackend, err := r.remoteBackendFactory(target)\n\tif err != nil {\n\t\treturn proxy.One2One, nil, status.Error(codes.Internal, err.Error())\n\t}\n\n\treturn proxy.One2One, []proxy.Backend{backend}, nil\n}\n\n// aggregateDirector sends request across set of remote instances and aggregates results.\nfunc (r *Router) aggregateDirector(targets []string) (proxy.Mode, []proxy.Backend, error) {\n\tif r.remoteBackendFactory == nil {\n\t\treturn proxy.One2One, nil, status.Error(codes.PermissionDenied, \"no request forwarding\")\n\t}\n\n\tvar err error\n\n\tbackends := make([]proxy.Backend, len(targets))\n\n\tfor i, target := range targets {\n\t\tbackends[i], err = r.remoteBackendFactory(target)\n\t\tif err != nil {\n\t\t\treturn proxy.One2Many, nil, status.Error(codes.Internal, err.Error())\n\t\t}\n\t}\n\n\treturn proxy.One2Many, backends, nil\n}\n\n// StreamedDetector implements proxy.StreamedDetector.\nfunc (r *Router) StreamedDetector(fullMethodName string) bool {\n\treturn slices.ContainsFunc(r.streamedMatchers, func(regex *regexp.Regexp) bool { return regex.MatchString(fullMethodName) })\n}\n\n// RegisterStreamedRegex register regex for streamed method.\n//\n// This could be exact literal match: /^\\/serviceName\\/methodName$/ or any\n// suffix/prefix match.\nfunc (r *Router) RegisterStreamedRegex(regex string) {\n\tr.streamedMatchers = append(r.streamedMatchers, regexp.MustCompile(regex))\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/director/director_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage director_test\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/app/apid/pkg/director\"\n)\n\ntype DirectorSuite struct {\n\tsuite.Suite\n\n\tlocalBackend *mockBackend\n\trouter       *director.Router\n}\n\nfunc (suite *DirectorSuite) SetupSuite() {\n\tsuite.localBackend = &mockBackend{}\n\tsuite.router = director.NewRouter(\n\t\tmockBackendFactory,\n\t\tsuite.localBackend,\n\t\t&mockLocalAddressProvider{\n\t\t\tlocal: map[string]struct{}{\n\t\t\t\t\"localhost\": {},\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t)\n}\n\nfunc (suite *DirectorSuite) TestStreamedDetector() {\n\tsuite.Assert().False(suite.router.StreamedDetector(\"/service.Service/someMethod\"))\n\n\tsuite.router.RegisterStreamedRegex(\"^\" + regexp.QuoteMeta(\"/service.Service/someMethod\") + \"$\")\n\n\tsuite.Assert().True(suite.router.StreamedDetector(\"/service.Service/someMethod\"))\n\tsuite.Assert().False(suite.router.StreamedDetector(\"/service.Service/someMethod2\"))\n\tsuite.Assert().False(suite.router.StreamedDetector(\"/servicexService/someMethod\"))\n\n\tsuite.router.RegisterStreamedRegex(\"Stream$\")\n\n\tsuite.Assert().True(suite.router.StreamedDetector(\"/service.Service/getStream\"))\n\tsuite.Assert().False(suite.router.StreamedDetector(\"/service.Service/getStreamItem\"))\n}\n\nfunc (suite *DirectorSuite) TestDirectorAggregate() {\n\tctx := context.Background()\n\n\tmd := metadata.New(nil)\n\tmd.Set(\"nodes\", \"127.0.0.1\", \"127.0.0.2\")\n\tmode, backends, err := suite.router.Director(metadata.NewIncomingContext(ctx, md), \"/machine.MachineService/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2Many, mode)\n\tsuite.Assert().Len(backends, 2)\n\tsuite.Assert().Equal(\"127.0.0.1\", backends[0].(*mockBackend).target)\n\tsuite.Assert().Equal(\"127.0.0.2\", backends[1].(*mockBackend).target)\n\n\tmd = metadata.New(nil)\n\tmd.Set(\"nodes\", \"127.0.0.1\")\n\tmode, backends, err = suite.router.Director(metadata.NewIncomingContext(ctx, md), \"/machine.MachineService/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2Many, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(\"127.0.0.1\", backends[0].(*mockBackend).target)\n}\n\nfunc (suite *DirectorSuite) TestDirectorSingleNode() {\n\tctx := context.Background()\n\n\tmd := metadata.New(nil)\n\tmd.Set(\"node\", \"127.0.0.1\")\n\tmode, backends, err := suite.router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(\"127.0.0.1\", backends[0].(*mockBackend).target)\n\tsuite.Assert().NoError(err)\n\n\tmd = metadata.New(nil)\n\tmd.Set(\"node\", \"127.0.0.1\", \"127.0.0.2\")\n\t_, _, err = suite.router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Assert().Equal(codes.InvalidArgument, status.Code(err))\n}\n\nfunc (suite *DirectorSuite) TestDirectorLocal() {\n\tctx := context.Background()\n\n\tmd := metadata.New(nil)\n\tmode, backends, err := suite.router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n\tsuite.Assert().NoError(err)\n}\n\nfunc (suite *DirectorSuite) TestDirectorNoRemoteBackend() {\n\t// override the router to have no remote backends\n\trouter := director.NewRouter(\n\t\tnil,\n\t\tsuite.localBackend,\n\t\t&mockLocalAddressProvider{\n\t\t\tlocal: map[string]struct{}{\n\t\t\t\t\"localhost\": {},\n\t\t\t},\n\t\t},\n\t\tfalse,\n\t)\n\n\tctx := context.Background()\n\n\t// request forwarding via node/nodes is disabled\n\tmd := metadata.New(nil)\n\tmd.Set(\"node\", \"127.0.0.1\")\n\t_, _, err := router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.PermissionDenied, status.Code(err))\n\n\tmd = metadata.New(nil)\n\tmd.Set(\"nodes\", \"127.0.0.1\", \"127.0.0.2\")\n\t_, _, err = router.Director(metadata.NewIncomingContext(ctx, md), \"/machine.MachineService/method\")\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.PermissionDenied, status.Code(err))\n\n\t// no request forwarding, allowed\n\tmd = metadata.New(nil)\n\tmode, backends, err := router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n\n\t// request forwarding to local address, allowed\n\tmd = metadata.New(nil)\n\tmd.Set(\"node\", \"localhost\")\n\tmode, backends, err = router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n\n\tmd = metadata.New(nil)\n\tmd.Set(\"nodes\", \"localhost\")\n\tmode, backends, err = router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n}\n\nfunc (suite *DirectorSuite) TestDirectorNoRouting() {\n\trouter := director.NewRouter(\n\t\tnil,\n\t\tsuite.localBackend,\n\t\t&mockLocalAddressProvider{\n\t\t\tlocal: map[string]struct{}{\n\t\t\t\t\"localhost\": {},\n\t\t\t},\n\t\t},\n\t\ttrue,\n\t)\n\n\tctx := context.Background()\n\n\t// request forwarding via node/nodes is ignored\n\tmd := metadata.New(nil)\n\tmd.Set(\"node\", \"127.0.0.1\")\n\tmode, backends, err := router.Director(metadata.NewIncomingContext(ctx, md), \"/machine.MachineService/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n\n\tmd = metadata.New(nil)\n\tmd.Set(\"nodes\", \"127.0.0.1\", \"127.0.0.2\")\n\tmode, backends, err = router.Director(metadata.NewIncomingContext(ctx, md), \"/machine.MachineService/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n\n\t// no request forwarding -- same\n\tmd = metadata.New(nil)\n\tmode, backends, err = router.Director(metadata.NewIncomingContext(ctx, md), \"/service.Service/method\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(proxy.One2One, mode)\n\tsuite.Assert().Len(backends, 1)\n\tsuite.Assert().Equal(suite.localBackend, backends[0])\n}\n\nfunc TestDirectorSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(DirectorSuite))\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/director/local_address.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage director\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LocalAddressProvider provides local address information.\ntype LocalAddressProvider interface {\n\tIsLocalTarget(string) bool\n}\n\n// localAddressProvider watches and keeps track of the local node addresses.\ntype localAddressProvider struct {\n\tmu sync.Mutex\n\n\tlocalAddresses map[string]struct{}\n\tlocalHostnames map[string]struct{}\n}\n\n// NewLocalAddressProvider initializes and returns a new LocalAddressProvider.\nfunc NewLocalAddressProvider(st state.State) (LocalAddressProvider, error) {\n\tp := &localAddressProvider{}\n\n\tevCh := make(chan state.Event)\n\n\tif err := st.Watch(context.Background(), resource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.NodeAddressCurrentID, resource.VersionUndefined), evCh); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := st.Watch(context.Background(), resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined), evCh); err != nil {\n\t\treturn nil, err\n\t}\n\n\tgo p.watch(evCh)\n\n\treturn p, nil\n}\n\nfunc (p *localAddressProvider) watch(evCh <-chan state.Event) {\n\tfor ev := range evCh {\n\t\tswitch ev.Type {\n\t\tcase state.Created, state.Updated:\n\t\t\t// expected\n\t\tcase state.Destroyed, state.Bootstrapped, state.Errored, state.Noop:\n\t\t\t// shouldn't happen, ignore\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch r := ev.Resource.(type) {\n\t\tcase *network.NodeAddress:\n\t\t\tp.mu.Lock()\n\n\t\t\tp.localAddresses = make(map[string]struct{}, len(r.TypedSpec().Addresses))\n\n\t\t\tfor _, addr := range r.TypedSpec().Addresses {\n\t\t\t\tp.localAddresses[addr.Addr().String()] = struct{}{}\n\t\t\t}\n\n\t\t\tp.mu.Unlock()\n\t\tcase *network.HostnameStatus:\n\t\t\tp.mu.Lock()\n\n\t\t\tp.localHostnames = make(map[string]struct{}, 2)\n\n\t\t\tp.localHostnames[r.TypedSpec().Hostname] = struct{}{}\n\t\t\tp.localHostnames[r.TypedSpec().FQDN()] = struct{}{}\n\n\t\t\tp.mu.Unlock()\n\t\t}\n\t}\n}\n\n// IsLocalTarget returns true if the address (hostname) is local.\nfunc (p *localAddressProvider) IsLocalTarget(target string) bool {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\t_, ok1 := p.localAddresses[target]\n\t_, ok2 := p.localHostnames[target]\n\n\treturn ok1 || ok2\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/director/mocks_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage director_test\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"google.golang.org/grpc\"\n)\n\ntype mockBackend struct {\n\ttarget string\n}\n\nfunc (m *mockBackend) String() string {\n\treturn m.target\n}\n\nfunc (m *mockBackend) GetConnection(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error) {\n\treturn ctx, nil, nil\n}\n\nfunc (m *mockBackend) AppendInfo(streaming bool, resp []byte) ([]byte, error) {\n\treturn resp, nil\n}\n\nfunc (m *mockBackend) BuildError(streaming bool, err error) ([]byte, error) {\n\treturn nil, nil\n}\n\nfunc mockBackendFactory(target string) (proxy.Backend, error) {\n\treturn &mockBackend{target: target}, nil\n}\n\ntype mockLocalAddressProvider struct {\n\tlocal map[string]struct{}\n}\n\nfunc (m *mockLocalAddressProvider) IsLocalTarget(t string) bool {\n\t_, ok := m.local[t]\n\n\treturn ok\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/provider/provider.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package provider provides TLS config for client & server.\npackage provider\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tstdlibtls \"crypto/tls\"\n\tstdx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/tls\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// TLSConfig provides client & server TLS configs for apid.\ntype TLSConfig struct {\n\tcertificateProvider  *certificateProvider\n\twatchCh              <-chan state.Event\n\tskipClientCertVerify bool\n}\n\n// NewTLSConfig builds provider from configuration and endpoints.\nfunc NewTLSConfig(ctx context.Context, resources state.State, skipClientCertVerify bool) (*TLSConfig, error) {\n\twatchCh := make(chan state.Event)\n\n\tif err := resources.Watch(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.APIType, secrets.APIID, resource.VersionUndefined), watchCh); err != nil {\n\t\treturn nil, fmt.Errorf(\"error setting up watch: %w\", err)\n\t}\n\n\t// wait for the first event to set up certificate provider\n\tprovider := &certificateProvider{}\n\n\tfor {\n\t\tvar event state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase event = <-watchCh:\n\t\t}\n\n\t\tswitch event.Type {\n\t\tcase state.Created, state.Updated:\n\t\t\t// expected\n\t\tcase state.Destroyed, state.Bootstrapped, state.Noop:\n\t\t\t// ignore, we'll get another event\n\t\t\tcontinue\n\t\tcase state.Errored:\n\t\t\treturn nil, fmt.Errorf(\"error watching for API certificates: %w\", event.Error)\n\t\t}\n\n\t\tapiCerts := event.Resource.(*secrets.API) //nolint:forcetypeassert\n\n\t\tif err := provider.Update(apiCerts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &TLSConfig{\n\t\t\tcertificateProvider:  provider,\n\t\t\twatchCh:              watchCh,\n\t\t\tskipClientCertVerify: skipClientCertVerify,\n\t\t}, nil\n\t}\n}\n\n// Watch for changes in API certificates and updates the TLSConfig.\nfunc (tlsConfig *TLSConfig) Watch(ctx context.Context, onUpdate func()) error {\n\tfor {\n\t\tvar event state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase event = <-tlsConfig.watchCh:\n\t\t}\n\n\t\tswitch event.Type {\n\t\tcase state.Created, state.Updated:\n\t\t\t// expected\n\t\tcase state.Destroyed, state.Bootstrapped, state.Noop:\n\t\t\t// ignore, we'll get another event\n\t\t\tcontinue\n\t\tcase state.Errored:\n\t\t\treturn fmt.Errorf(\"error watching API certificates: %w\", event.Error)\n\t\t}\n\n\t\tapiCerts := event.Resource.(*secrets.API) //nolint:forcetypeassert\n\n\t\tif err := tlsConfig.certificateProvider.Update(apiCerts); err != nil {\n\t\t\treturn fmt.Errorf(\"failed updating cert: %v\", err)\n\t\t}\n\n\t\tif onUpdate != nil {\n\t\t\tonUpdate()\n\t\t}\n\t}\n}\n\n// ServerConfig generates server-side tls.Config.\nfunc (tlsConfig *TLSConfig) ServerConfig() (*stdlibtls.Config, error) {\n\tauthType := tls.Mutual\n\n\tif tlsConfig.skipClientCertVerify {\n\t\tauthType = tls.ServerOnly\n\t}\n\n\treturn tls.New(\n\t\ttls.WithClientAuthType(authType),\n\t\ttls.WithDynamicClientCA(tlsConfig.certificateProvider),\n\t\ttls.WithServerCertificateProvider(tlsConfig.certificateProvider),\n\t)\n}\n\n// ClientConfig generates client-side tls.Config.\nfunc (tlsConfig *TLSConfig) ClientConfig() (*stdlibtls.Config, error) {\n\tif !tlsConfig.certificateProvider.HasClientCertificate() {\n\t\treturn nil, nil\n\t}\n\n\tca, err := tlsConfig.certificateProvider.GetCA()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get root CA: %w\", err)\n\t}\n\n\treturn tls.New(\n\t\ttls.WithClientAuthType(tls.Mutual),\n\t\ttls.WithCACertPEM(ca),\n\t\ttls.WithClientCertificateProvider(tlsConfig.certificateProvider),\n\t)\n}\n\ntype certificateProvider struct {\n\tmu sync.Mutex\n\n\tca                     []byte\n\tcaCertPool             *stdx509.CertPool\n\tclientCert, serverCert *stdlibtls.Certificate\n}\n\nfunc (p *certificateProvider) Update(apiCerts *secrets.API) error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tserverCert, err := stdlibtls.X509KeyPair(apiCerts.TypedSpec().Server.Crt, apiCerts.TypedSpec().Server.Key)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse server cert and key into a TLS Certificate: %w\", err)\n\t}\n\n\tp.serverCert = &serverCert\n\n\tp.ca = bytes.Join(\n\t\txslices.Map(\n\t\t\tapiCerts.TypedSpec().AcceptedCAs,\n\t\t\tfunc(cert *x509.PEMEncodedCertificate) []byte {\n\t\t\t\treturn cert.Crt\n\t\t\t},\n\t\t),\n\t\tnil,\n\t)\n\n\tp.caCertPool = stdx509.NewCertPool()\n\n\tif len(p.ca) > 0 {\n\t\tif !p.caCertPool.AppendCertsFromPEM(p.ca) {\n\t\t\treturn fmt.Errorf(\"failed to parse CA certs into a CertPool\")\n\t\t}\n\t}\n\n\tif apiCerts.TypedSpec().Client != nil {\n\t\tclientCert, err := stdlibtls.X509KeyPair(apiCerts.TypedSpec().Client.Crt, apiCerts.TypedSpec().Client.Key)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse client cert and key into a TLS Certificate: %w\", err)\n\t\t}\n\n\t\tp.clientCert = &clientCert\n\t} else {\n\t\tp.clientCert = nil\n\t}\n\n\treturn nil\n}\n\nfunc (p *certificateProvider) GetCA() ([]byte, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.ca, nil\n}\n\nfunc (p *certificateProvider) GetCACertPool() (*stdx509.CertPool, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.caCertPool, nil\n}\n\nfunc (p *certificateProvider) GetCertificate(*stdlibtls.ClientHelloInfo) (*stdlibtls.Certificate, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.serverCert, nil\n}\n\nfunc (p *certificateProvider) HasClientCertificate() bool {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.clientCert != nil\n}\n\nfunc (p *certificateProvider) GetClientCertificate(*stdlibtls.CertificateRequestInfo) (*stdlibtls.Certificate, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.clientCert, nil\n}\n"
  },
  {
    "path": "internal/app/apid/pkg/provider/provider_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provider_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "internal/app/apid/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage apid\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"regexp\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-debug\"\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\n\tapidbackend \"github.com/siderolabs/talos/internal/app/apid/pkg/backend\"\n\t\"github.com/siderolabs/talos/internal/app/apid/pkg/director\"\n\t\"github.com/siderolabs/talos/internal/app/apid/pkg/provider\"\n\t\"github.com/siderolabs/talos/pkg/grpc/factory\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/grpc/proxy/backend\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc runService(ctx context.Context, resources state.State, config *runtime.APIServiceConfig) error {\n\tlog.Printf(\n\t\t\"starting apid with config: listen address %s, skip client cert verify %v, node routing disabled %v, readonly role mode %v\",\n\t\tconfig.TypedSpec().ListenAddress,\n\t\tconfig.TypedSpec().SkipVerifyingClientCert,\n\t\tconfig.TypedSpec().NodeRoutingDisabled,\n\t\tconfig.TypedSpec().ReadonlyRoleMode,\n\t)\n\n\ttlsConfig, err := provider.NewTLSConfig(ctx, resources, config.TypedSpec().SkipVerifyingClientCert)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create remote certificate provider: %w\", err)\n\t}\n\n\tserverTLSConfig, err := tlsConfig.ServerConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create OS-level TLS configuration: %w\", err)\n\t}\n\n\tserverTLSConfig.VerifyPeerCertificate = verifyExtKeyUsage\n\n\tclientTLSConfig, err := tlsConfig.ClientConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create client TLS config: %w\", err)\n\t}\n\n\tvar (\n\t\tremoteFactory director.RemoteBackendFactory\n\t\tonPKIUpdate   func()\n\t)\n\n\tif clientTLSConfig != nil {\n\t\tbackendFactory := apidbackend.NewAPIDFactory(tlsConfig)\n\t\tremoteFactory = backendFactory.Get\n\t\tonPKIUpdate = backendFactory.Flush\n\n\t\tdefer backendFactory.Flush()\n\t}\n\n\tlocalAddressProvider, err := director.NewLocalAddressProvider(resources)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create local address provider: %w\", err)\n\t}\n\n\tlocalBackend := backend.NewLocal(\"machined\", constants.MachineSocketPath)\n\tdefer localBackend.Close() //nolint:errcheck\n\n\trouter := director.NewRouter(remoteFactory, localBackend, localAddressProvider, config.TypedSpec().NodeRoutingDisabled)\n\n\t// all existing streaming methods\n\tfor _, methodName := range []string{\n\t\t\"/machine.MachineService/Copy\",\n\t\t\"/machine.MachineService/DiskUsage\",\n\t\t\"/machine.MachineService/Dmesg\",\n\t\t\"/machine.MachineService/EtcdSnapshot\",\n\t\t\"/machine.MachineService/Events\",\n\t\t\"/machine.MachineService/ImageList\",\n\t\t\"/machine.MachineService/Kubeconfig\",\n\t\t\"/machine.MachineService/List\",\n\t\t\"/machine.MachineService/DebugContainer\",\n\t\t\"/machine.MachineService/Logs\",\n\t\t\"/machine.MachineService/PacketCapture\",\n\t\t\"/machine.MachineService/Read\",\n\t\t\"/machine.LifecycleService/Install\",\n\t\t\"/machine.LifecycleService/Upgrade\",\n\t\t\"/os.OSService/Dmesg\",\n\t\t\"/cluster.ClusterService/HealthCheck\",\n\t} {\n\t\trouter.RegisterStreamedRegex(\"^\" + regexp.QuoteMeta(methodName) + \"$\")\n\t}\n\n\t// register future pattern: method should have suffix \"Stream\"\n\trouter.RegisterStreamedRegex(\"Stream$\")\n\n\tnetworkListener, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", config.TypedSpec().ListenAddress)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating listner: %w\", err)\n\t}\n\n\tnetworkServer := func() *grpc.Server {\n\t\tinjector := &authz.Injector{\n\t\t\tMode: authz.Enabled,\n\t\t}\n\n\t\tif config.TypedSpec().ReadonlyRoleMode {\n\t\t\tinjector.Mode = authz.ReadOnlyWithAdminOnSiderolink\n\t\t}\n\n\t\tif debug.Enabled {\n\t\t\tinjector.Logger = log.New(log.Writer(), \"apid/authz/injector/http \", log.Flags()).Printf\n\t\t}\n\n\t\treturn factory.NewServer(\n\t\t\trouter,\n\t\t\tfactory.WithDefaultLog(),\n\t\t\tfactory.ServerOptions(\n\t\t\t\tgrpc.Creds(\n\t\t\t\t\tcredentials.NewTLS(serverTLSConfig),\n\t\t\t\t),\n\t\t\t\tgrpc.ForceServerCodecV2(proxy.Codec()),\n\t\t\t\tgrpc.UnknownServiceHandler(\n\t\t\t\t\tproxy.TransparentHandler(\n\t\t\t\t\t\trouter.Director,\n\t\t\t\t\t\tproxy.WithStreamedDetector(router.StreamedDetector),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tgrpc.MaxRecvMsgSize(constants.GRPCMaxMessageSize),\n\t\t\t),\n\t\t\tfactory.WithUnaryInterceptor(injector.UnaryInterceptor()),\n\t\t\tfactory.WithStreamInterceptor(injector.StreamInterceptor()),\n\t\t)\n\t}()\n\n\terrGroup, ctx := errgroup.WithContext(ctx)\n\n\terrGroup.Go(func() error {\n\t\treturn networkServer.Serve(networkListener)\n\t})\n\n\terrGroup.Go(func() error {\n\t\treturn tlsConfig.Watch(ctx, onPKIUpdate)\n\t})\n\n\terrGroup.Go(func() error {\n\t\t<-ctx.Done()\n\n\t\tshutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer shutdownCancel()\n\n\t\tfactory.ServerGracefulStop(networkServer, shutdownCtx)\n\n\t\treturn nil\n\t})\n\n\treturn errGroup.Wait()\n}\n\nfunc verifyExtKeyUsage(_ [][]byte, verifiedChains [][]*x509.Certificate) error {\n\tif len(verifiedChains) == 0 {\n\t\treturn errors.New(\"no verified chains\")\n\t}\n\n\tcerts := verifiedChains[0]\n\n\tfor _, cert := range certs {\n\t\tif cert.IsCA {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !slices.Equal(cert.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}) {\n\t\t\treturn fmt.Errorf(\"certificate %q is missing the client auth extended key usage\", cert.Subject)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/auditd/auditd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package auditd registers auditd service and logs audit events.\npackage auditd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\n\t\"github.com/elastic/go-libaudit/v2\"\n\t\"github.com/elastic/go-libaudit/v2/auparse\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// Main is an entrypoint to the auditd service.\nfunc Main(ctx context.Context, _ runtime.Runtime, logWriter io.Writer) error {\n\treturn Run(ctx, logWriter)\n}\n\n// Run starts the auditd service.\n//\n// based on https://github.com/elastic/go-libaudit/blob/main/cmd/audit/audit.go\nfunc Run(ctx context.Context, logWriter io.Writer) error {\n\tvar wg sync.WaitGroup\n\n\tdefer wg.Wait()\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tclient, err := libaudit.NewAuditClient(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create audit client: %w\", err)\n\t}\n\n\tvar auditDefaultEnabled atomic.Bool\n\n\twg.Add(1)\n\n\tgo func(c *libaudit.AuditClient) {\n\t\tdefer wg.Done()\n\n\t\t<-ctx.Done()\n\n\t\tif !auditDefaultEnabled.Load() {\n\t\t\tc.SetEnabled(false, libaudit.NoWait) //nolint:errcheck\n\t\t}\n\n\t\tc.Close() //nolint:errcheck\n\t}(client)\n\n\tstatus, err := client.GetStatus()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get audit status: %w\", err)\n\t}\n\n\tauditDefaultEnabled.Store(status.Enabled >= 1)\n\n\tif status.Enabled == 0 {\n\t\tif err := client.SetEnabled(true, libaudit.WaitForReply); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to enable audit: %w\", err)\n\t\t}\n\t}\n\n\tif err = client.SetRateLimit(uint32(4096), libaudit.NoWait); err != nil {\n\t\treturn fmt.Errorf(\"failed to set rate limit: %w\", err)\n\t}\n\n\tif err := client.SetBacklogLimit(8192, libaudit.NoWait); err != nil {\n\t\treturn fmt.Errorf(\"failed to set backlog limit: %w\", err)\n\t}\n\n\tif err := client.SetPID(libaudit.NoWait); err != nil {\n\t\treturn fmt.Errorf(\"failed to set audit PID: %w\", err)\n\t}\n\n\treturn receiveEvents(ctx, client, logWriter)\n}\n\nfunc receiveEvents(ctx context.Context, client *libaudit.AuditClient, logWriter io.Writer) error {\n\tfor {\n\t\trawEvent, err := client.Receive(false)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, syscall.EBADF) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif errors.Is(err, syscall.EINTR) && errors.Is(err, syscall.EAGAIN) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to receive audit event: %w\", err)\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\t// Messages from 1100-2999 are valid audit messages.\n\t\tif rawEvent.Type < auparse.AUDIT_USER_AUTH ||\n\t\t\trawEvent.Type > auparse.AUDIT_LAST_USER_MSG2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Fprintf(logWriter, \"type=%s msg=%s\\n\", rawEvent.Type, rawEvent.Data)\n\t}\n}\n"
  },
  {
    "path": "internal/app/dashboard/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package dashboard implements dashboard functionality.\npackage dashboard\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\tmetalurl \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/startup\"\n)\n\n// Main is the entrypoint into dashboard.\nfunc Main() {\n\tif err := dashboardMain(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc dashboardMain() error {\n\tstartup.LimitMaxProcs(constants.DashboardMaxProcs)\n\n\tmd := metadata.Pairs()\n\tauthz.SetMetadata(md, role.MakeSet(role.Admin))\n\n\tctx, cancel := sigtermAwareContext(context.Background())\n\tdefer cancel()\n\n\tctx = metadata.NewOutgoingContext(ctx, md)\n\n\tc, err := client.New(ctx,\n\t\tclient.WithUnixSocket(constants.MachineSocketPath),\n\t\tclient.WithGRPCDialOptions(\n\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error connecting to the machine service: %w\", err)\n\t}\n\n\tscreens := []dashboard.Screen{dashboard.ScreenSummary, dashboard.ScreenMonitor}\n\n\t// activate the network config screen only on metal platform\n\tcurrentPlatform, _ := platform.CurrentPlatform() //nolint:errcheck\n\tif currentPlatform != nil && currentPlatform.Name() == constants.PlatformMetal {\n\t\tscreens = append(screens, dashboard.ScreenNetworkConfig)\n\n\t\tif showConfigURLTab() {\n\t\t\tscreens = append(screens, dashboard.ScreenConfigURL)\n\t\t}\n\t}\n\n\treturn dashboard.Run(ctx, c, dashboard.WithAllowExitKeys(false), dashboard.WithScreens(screens...))\n}\n\nfunc showConfigURLTab() bool {\n\toption := procfs.ProcCmdline().Get(constants.KernelParamConfig).First()\n\tif option == nil {\n\t\treturn false\n\t}\n\n\tparsedURL, err := url.Parse(*option)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tcodeVar := metalurl.AllVariables()[constants.CodeKey]\n\tif codeVar == nil {\n\t\treturn false\n\t}\n\n\treturn codeVar.Matches(parsedURL.Query())\n}\n\nfunc sigtermAwareContext(ctx context.Context) (context.Context, context.CancelFunc) {\n\tctx, cancel := context.WithCancel(ctx)\n\n\tsignalCh := make(chan os.Signal, 1)\n\tsignal.Notify(signalCh, syscall.SIGTERM)\n\n\tgo func() {\n\t\tselect {\n\t\tcase <-signalCh:\n\t\t\tcancel()\n\t\tcase <-ctx.Done():\n\t\t}\n\t}()\n\n\treturn ctx, cancel\n}\n"
  },
  {
    "path": "internal/app/debug/container_streams.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage debug\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"syscall\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/siderolabs/gen/panicsafe\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\nfunc newGrpcStreamWriter(srv grpc.BidiStreamingServer[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse]) (\n\t*grpcStdioStreamer,\n\tio.Reader,\n\tio.Writer,\n) {\n\tstdinR, stdinW := io.Pipe()\n\tstdoutR, stdoutW := io.Pipe()\n\n\treturn &grpcStdioStreamer{\n\t\tsrv:     srv,\n\t\tstdinW:  stdinW,\n\t\tstdoutR: stdoutR,\n\t\tstdoutW: stdoutW,\n\t}, stdinR, stdoutW\n}\n\ntype grpcStdioStreamer struct {\n\tsrv grpc.BidiStreamingServer[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse]\n\n\tstdinW  *io.PipeWriter\n\tstdoutR *io.PipeReader\n\tstdoutW *io.PipeWriter\n}\n\n//nolint:gocyclo\nfunc (g *grpcStdioStreamer) stream(ctx context.Context, statusC <-chan containerdapi.ExitStatus, task containerdapi.Task) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tsendLoopCh, recvLoopCh := make(chan error), make(chan error)\n\n\tgo func(errCh chan<- error) {\n\t\terrCh <- panicsafe.RunErr(g.sendLoop)\n\t}(sendLoopCh)\n\n\tgo func(errCh chan<- error) {\n\t\terrCh <- panicsafe.RunErr(func() error {\n\t\t\treturn g.recvLoop(ctx, task)\n\t\t})\n\t}(recvLoopCh)\n\n\tfor {\n\t\tselect {\n\t\t// task terminated\n\t\tcase ec := <-statusC:\n\t\t\t// closing r.stdoutW causes the sendLoop, which s\n\t\t\t// blocking on r.stdoutR.Read(), to get an EOF and exit\n\t\t\tg.stdoutW.Close() //nolint:errcheck\n\n\t\t\t// close r.stdinW to ensure the container exits if it's still running\n\t\t\tg.stdinW.Close() //nolint:errcheck\n\n\t\t\t// cancel the context to stop loops\n\t\t\tcancel()\n\n\t\t\tif ec.Error() != nil {\n\t\t\t\treturn ec.Error()\n\t\t\t}\n\n\t\t\t// wait for send loop to exit\n\t\t\t//\n\t\t\t// calling srv.Send from multiple goroutines is not safe,\n\t\t\t// so we need to wait for sendLoop to exit\n\t\t\tif sendLoopCh != nil {\n\t\t\t\t<-sendLoopCh\n\t\t\t}\n\n\t\t\t// then, sending the exit code back to the client makes\n\t\t\t// the client disconnect\n\t\t\tif err := g.srv.Send(&machine.DebugContainerRunResponse{\n\t\t\t\tResp: &machine.DebugContainerRunResponse_ExitCode{\n\t\t\t\t\tExitCode: int32(ec.ExitCode()),\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"debug container: failed to send exit code: %w\", err)\n\t\t\t}\n\n\t\t\t// wait for recv loop to exit after client disconnects\n\t\t\tif recvLoopCh != nil {\n\t\t\t\t<-recvLoopCh\n\t\t\t}\n\n\t\t\treturn nil\n\t\t// our send loop terminated\n\t\tcase sendErr := <-sendLoopCh:\n\t\t\tif sendErr == nil { // keep waiting for task to exit\n\t\t\t\tsendLoopCh = nil\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// close r.stdinW to ensure the container exits if it's still running\n\t\t\tg.stdinW.Close() //nolint:errcheck\n\n\t\t\treturn fmt.Errorf(\"debug container: send loop error: %w\", sendErr)\n\t\tcase recvErr := <-recvLoopCh:\n\t\t\tif recvErr == nil { // keep waiting for task to exit\n\t\t\t\trecvLoopCh = nil\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// close r.stdoutW to stop the send loop\n\t\t\tg.stdoutW.Close() //nolint:errcheck\n\n\t\t\treturn fmt.Errorf(\"debug container: receive loop error: %w\", recvErr)\n\t\t// client walked away\n\t\tcase <-ctx.Done():\n\t\t\t// closing r.stdoutW causes the sendLoop, which s\n\t\t\t// blocking on r.stdoutR.Read(), to get an EOF and exit\n\t\t\tg.stdoutW.Close() //nolint:errcheck\n\n\t\t\t// close r.stdinW to ensure the container exits if it's still running\n\t\t\tg.stdinW.Close() //nolint:errcheck\n\n\t\t\t// wait for loops to exit\n\t\t\tif recvLoopCh != nil {\n\t\t\t\t<-recvLoopCh\n\t\t\t}\n\n\t\t\tif sendLoopCh != nil {\n\t\t\t\t<-sendLoopCh\n\t\t\t}\n\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n}\n\nfunc (g *grpcStdioStreamer) recvLoop(ctx context.Context, task containerdapi.Task) error {\n\tdefer g.stdinW.Close() //nolint:errcheck\n\n\tfor {\n\t\tmsg, err := g.srv.Recv()\n\t\tif err != nil {\n\t\t\tif status.Code(err) != codes.Canceled && err != io.EOF {\n\t\t\t\treturn fmt.Errorf(\"error receiving input message: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif err = g.processMessage(ctx, task, msg); err != nil {\n\t\t\treturn fmt.Errorf(\"error processing input message: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (g *grpcStdioStreamer) processMessage(ctx context.Context, task containerdapi.Task, msg *machine.DebugContainerRunRequest) error {\n\tswitch msg.Request.(type) {\n\tcase *machine.DebugContainerRunRequest_StdinData:\n\t\tif stdinData := msg.GetStdinData(); stdinData != nil {\n\t\t\t_, err := g.stdinW.Write(stdinData)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write to stdin: %w\", err)\n\t\t\t}\n\t\t}\n\n\tcase *machine.DebugContainerRunRequest_TermResize:\n\t\tif err := task.Resize(\n\t\t\tctx,\n\t\t\tuint32(msg.GetTermResize().Width),\n\t\t\tuint32(msg.GetTermResize().Height),\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to resize terminal: %w\", err)\n\t\t}\n\n\tcase *machine.DebugContainerRunRequest_Signal:\n\t\tsignalNum := msg.GetSignal()\n\t\tlog.Printf(\"debug container: received signal %d, forwarding to task\", signalNum)\n\n\t\tif err := task.Kill(ctx, syscall.Signal(signalNum)); err != nil {\n\t\t\treturn fmt.Errorf(\"debug container: failed to forward signal to task: %w\", err)\n\t\t}\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown request type: %T\", msg.Request)\n\t}\n\n\treturn nil\n}\n\nfunc (g *grpcStdioStreamer) sendLoop() error {\n\tdefer g.stdoutW.Close() //nolint:errcheck\n\n\tb := make([]byte, 512)\n\n\tfor {\n\t\tn, err := g.stdoutR.Read(b)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to read from stdout: %w\", err)\n\t\t}\n\n\t\terr = g.srv.Send(&machine.DebugContainerRunResponse{\n\t\t\tResp: &machine.DebugContainerRunResponse_StdoutData{\n\t\t\t\tStdoutData: b[:n],\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\tif status.Code(err) != codes.Canceled {\n\t\t\t\treturn fmt.Errorf(\"debug container: failed to send stdout data: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/debug/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package debug implements machine.DebugService.\npackage debug\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"path/filepath\"\n\n\t\"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/core/leases\"\n\t\"github.com/containerd/containerd/v2/pkg/cio\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/app/internal/ctrhelper\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Service implements machine.DebugService.\ntype Service struct {\n\tmachine.UnimplementedDebugServiceServer\n}\n\n// ContainerRun implements machine.DebugService.ContainerRun.\nfunc (s *Service) ContainerRun(srv grpc.BidiStreamingServer[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse]) error { //nolint:gocyclo\n\tctx := srv.Context()\n\n\t// 1. get the debug container spec\n\tspecReq, err := srv.Recv()\n\tif err != nil {\n\t\treturn status.Errorf(codes.InvalidArgument, \"failed to receive spec: %v\", err)\n\t}\n\n\tspec := specReq.GetSpec()\n\tif spec == nil {\n\t\treturn status.Errorf(codes.InvalidArgument, \"expected debug container spec\")\n\t}\n\n\tif spec.GetProfile() != machine.DebugContainerRunRequestSpec_PROFILE_PRIVILEGED {\n\t\treturn status.Errorf(codes.InvalidArgument, \"unsupported debug container profile: %s\", spec.GetProfile())\n\t}\n\n\tlog.Printf(\"debug container request received: image=%s args=%v env=%v profile=%s\", spec.GetImageName(), spec.GetArgs(), spec.GetEnv(), spec.GetProfile())\n\n\t// 2. connect to containerd with a lease\n\tctx, detachedContext, c8dClient, err := ctrhelper.ContainerdInstanceHelper(ctx, spec.GetContainerd())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer c8dClient.Close() //nolint:errcheck\n\n\tl, err := c8dClient.LeasesService().Create(ctx,\n\t\tleases.WithRandomID(),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create lease: %v\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := c8dClient.LeasesService().Delete(detachedContext, l, leases.SynchronousDelete); err != nil {\n\t\t\tlog.Printf(\"failed to delete lease %s: %v\", l.ID, err)\n\t\t}\n\t}()\n\n\tctx = leases.WithLease(ctx, l.ID)\n\n\timg, err := c8dClient.GetImage(ctx, spec.ImageName)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn status.Errorf(codes.NotFound, \"image %s not found: %v\", spec.ImageName, err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\t// 3. create the debug container\n\tcontainerID, err := generateContainerID()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate container ID: %v\", err)\n\t}\n\n\t// create the root cgroup to populate resources as needed\n\t_, err = cgroup.CreateCgroup(constants.CgroupSystemDebug)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create debug cgroup: %v\", err)\n\t}\n\n\tcgroupPath := filepath.Join(constants.CgroupSystemDebug, containerID)\n\n\t// create a cgroup for this container instance, and clean it up afterwards\n\tcg, err := cgroup.CreateCgroup(cgroupPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create cgroup for debug container: %v\", err)\n\t}\n\n\tdefer func() {\n\t\tcg.Delete() // nolint: errcheck\n\t}()\n\n\tctr, err := createDebugContainer(ctx, c8dClient, containerID, img, spec, cgroupPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Printf(\"debug container: container %s created\", ctr.ID())\n\n\tdefer func() {\n\t\tcleanupErr := ctr.Delete(detachedContext, client.WithSnapshotCleanup)\n\t\tif cleanupErr != nil {\n\t\t\tlog.Printf(\"debug container: failed to delete container %s: %s\", ctr.ID(), cleanupErr.Error())\n\t\t}\n\n\t\tlog.Printf(\"debug container: container %s deleted\", ctr.ID())\n\t}()\n\n\t// 4. run and attach to the debug container\n\treturn runAndAttachContainer(ctx, detachedContext, spec, srv, ctr)\n}\n\nfunc createDebugContainer(\n\tctx context.Context,\n\tc8dClient *client.Client,\n\tcontainerID string,\n\timage client.Image,\n\tspec *machine.DebugContainerRunRequestSpec,\n\tcgroupPath string,\n) (client.Container, error) {\n\tociOpts := []oci.SpecOpts{\n\t\toci.WithDefaultSpec(),\n\t\toci.WithDefaultUnixDevices,\n\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\toci.WithHostNamespace(specs.PIDNamespace),\n\t\toci.WithHostNamespace(specs.IPCNamespace),\n\t\toci.WithHostDevices,\n\t\toci.WithAllDevicesAllowed,\n\t\toci.WithHostHostsFile,\n\t\toci.WithWriteableSysfs,\n\t\toci.WithCapabilities(capability.AllGrantableCapabilities()),\n\t\toci.WithHostResolvconf,\n\t\toci.WithMounts([]specs.Mount{\n\t\t\t// mount host / under /host\n\t\t\t{\n\t\t\t\tDestination: \"/host\",\n\t\t\t\tType:        \"bind\",\n\t\t\t\tSource:      \"/\",\n\t\t\t\tOptions:     []string{\"rbind\", \"rw\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tDestination: \"/sys\",\n\t\t\t\tType:        \"bind\",\n\t\t\t\tSource:      \"/sys\",\n\t\t\t\tOptions:     []string{\"rbind\", \"rw\"},\n\t\t\t},\n\t\t}),\n\t\toci.WithSelinuxLabel(\"\"), // SELinux will automatically transition the debug container into the proper context\n\t\toci.WithApparmorProfile(\"\"),\n\t\toci.WithSeccompUnconfined,\n\t\toci.WithImageConfig(image),\n\t\toci.WithCgroup(cgroupPath),\n\t}\n\n\tif spec.GetTty() {\n\t\tociOpts = append(ociOpts, oci.WithTTY)\n\t}\n\n\tif len(spec.Args) > 0 {\n\t\tociOpts = append(ociOpts, oci.WithProcessArgs(spec.Args...))\n\t}\n\n\tif len(spec.Env) > 0 {\n\t\tenvVars := make([]string, 0, len(spec.Env))\n\n\t\tfor k, v := range spec.Env {\n\t\t\tenvVars = append(envVars, fmt.Sprintf(\"%s=%s\", k, v))\n\t\t}\n\n\t\tociOpts = append(ociOpts, oci.WithEnv(envVars))\n\t}\n\n\tcontainer, err := c8dClient.NewContainer(ctx, containerID,\n\t\tclient.WithImage(image),\n\t\tclient.WithNewSnapshot(containerID+\"-snapshot\", image),\n\t\tclient.WithNewSpec(ociOpts...),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create container: %v\", err)\n\t}\n\n\treturn container, nil\n}\n\nfunc runAndAttachContainer(\n\tctx context.Context,\n\tdetachedContext context.Context,\n\tspec *machine.DebugContainerRunRequestSpec,\n\tsrv grpc.BidiStreamingServer[machine.DebugContainerRunRequest, machine.DebugContainerRunResponse],\n\tctr client.Container,\n) error {\n\tgrpcStreamer, stdinR, stdoutW := newGrpcStreamWriter(srv)\n\tstdin := &containerd.StdinCloser{\n\t\tStdin:  stdinR,\n\t\tCloser: make(chan struct{}),\n\t}\n\n\tcIoOpts := []cio.Opt{\n\t\tcio.WithStreams(stdin, stdoutW, stdoutW),\n\t}\n\n\tif spec.GetTty() {\n\t\tcIoOpts = append(cIoOpts, cio.WithTerminal)\n\t}\n\n\tcIo := cio.NewCreator(cIoOpts...)\n\n\ttask, err := ctr.NewTask(ctx, cIo)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create task: %v\", err)\n\t}\n\n\tdefer func() {\n\t\t_, err := task.Delete(detachedContext, client.WithProcessKill)\n\t\tif err != nil && !errdefs.IsNotFound(err) {\n\t\t\tlog.Printf(\"debug container: failed to delete task: %s\", err.Error())\n\t\t}\n\t}()\n\n\tgo stdin.WaitAndClose(ctx, task)\n\n\tif err := task.Start(ctx); err != nil {\n\t\treturn fmt.Errorf(\"failed to start task: %v\", err)\n\t}\n\n\tstatusC, err := task.Wait(detachedContext)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to wait for task: %v\", err)\n\t}\n\n\treturn grpcStreamer.stream(ctx, statusC, task)\n}\n\nfunc generateContainerID() (string, error) {\n\tb := make([]byte, 8)\n\tif _, err := rand.Read(b); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to generate random ID: %w\", err)\n\t}\n\n\treturn fmt.Sprintf(\"debug-%s\", hex.EncodeToString(b)), nil\n}\n"
  },
  {
    "path": "internal/app/images/images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package images implements machine.ImageService.\npackage images\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"maps\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/core/images\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/containerd/platforms\"\n\t\"github.com/distribution/reference\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/siderolabs/talos/internal/app/internal/ctrhelper\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/progress\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// Service implements machine.ImageService.\ntype Service struct {\n\tmachine.UnimplementedImageServiceServer\n\n\tcontroller runtime.Controller\n\tlogger     *zap.Logger\n}\n\n// NewService creates a new ImageService.\nfunc NewService(controller runtime.Controller, logger *zap.Logger) *Service {\n\treturn &Service{\n\t\tcontroller: controller,\n\t\tlogger:     logger,\n\t}\n}\n\n// List images in the containerd.\nfunc (svc *Service) List(req *machine.ImageServiceListRequest, srv grpc.ServerStreamingServer[machine.ImageServiceListResponse]) error {\n\tctx, _, client, err := ctrhelper.ContainerdInstanceHelper(srv.Context(), req.GetContainerd())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\timages, err := client.ImageService().List(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, image := range images {\n\t\titem := &machine.ImageServiceListResponse{\n\t\t\tName:      image.Name,\n\t\t\tDigest:    image.Target.Digest.String(),\n\t\t\tCreatedAt: timestamppb.New(image.CreatedAt),\n\t\t\tLabels:    maps.Clone(image.Labels),\n\t\t}\n\n\t\tsize, err := image.Size(ctx, client.ContentStore(), platforms.Default())\n\t\tif err == nil {\n\t\t\titem.Size = size\n\t\t}\n\n\t\tif err = srv.Send(item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Pull an image into the containerd.\nfunc (svc *Service) Pull(req *machine.ImageServicePullRequest, srv grpc.ServerStreamingServer[machine.ImageServicePullResponse]) error {\n\tctx, _, client, err := ctrhelper.ContainerdInstanceHelper(srv.Context(), req.GetContainerd())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\timg, err := image.Pull(ctx,\n\t\tcri.RegistryBuilder(svc.controller.Runtime().State().V1Alpha2().Resources()),\n\t\tsvc.controller.Runtime().State().V1Alpha2().Resources(),\n\t\tclient,\n\t\treq.GetImageRef(),\n\t\timage.WithSkipIfAlreadyPulled(),\n\t\timage.WithMaxNotFoundRetries(0), // return an error immediately if the image is not found\n\t\timage.WithProgressReporter(image.NewSimpleProgressReporter(func(lpp progress.LayerPullProgress) {\n\t\t\tsrv.Send(&machine.ImageServicePullResponse{ //nolint:errcheck\n\t\t\t\tResponse: &machine.ImageServicePullResponse_PullProgress{\n\t\t\t\t\tPullProgress: &machine.ImageServicePullProgress{\n\t\t\t\t\t\tLayerId: lpp.LayerID,\n\t\t\t\t\t\tProgress: &machine.ImageServicePullLayerProgress{\n\t\t\t\t\t\t\tStatus:  machine.ImageServicePullLayerProgress_Status(lpp.Status),\n\t\t\t\t\t\t\tElapsed: durationpb.New(lpp.Elapsed),\n\t\t\t\t\t\t\tOffset:  lpp.Offset,\n\t\t\t\t\t\t\tTotal:   lpp.Total,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t})),\n\t)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn status.Errorf(codes.NotFound, \"error pulling image: %s\", err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tpulledRef := img.Name()\n\n\tparsedRef, err := reference.ParseDockerRef(pulledRef)\n\tif err != nil {\n\t\treturn status.Errorf(codes.Internal, \"error parsing image reference: %s\", err)\n\t}\n\n\tif _, ok := parsedRef.(reference.Canonical); !ok {\n\t\t// if the reference is not canonical, pin it\n\t\tpulledRef = parsedRef.Name() + \"@\" + img.Target().Digest.String()\n\t}\n\n\treturn srv.Send(&machine.ImageServicePullResponse{\n\t\tResponse: &machine.ImageServicePullResponse_Name{\n\t\t\tName: pulledRef,\n\t\t},\n\t})\n}\n\n// Import an image from a stream (tarball).\n//\n//nolint:gocyclo\nfunc (svc *Service) Import(srv grpc.ClientStreamingServer[machine.ImageServiceImportRequest, machine.ImageServiceImportResponse]) error {\n\tmsg, err := srv.Recv()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq := msg.GetContainerd()\n\tif req == nil {\n\t\treturn status.Errorf(codes.InvalidArgument, \"containerd instance is required\")\n\t}\n\n\tctx, _, client, err := ctrhelper.ContainerdInstanceHelper(srv.Context(), req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tr, w := io.Pipe()\n\n\tgo func() {\n\t\tdefer w.Close() //nolint:errcheck\n\n\t\tfor {\n\t\t\tmsg, err := srv.Recv()\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tw.CloseWithError(err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tchunk := msg.GetImageChunk()\n\t\t\tif chunk == nil {\n\t\t\t\tw.CloseWithError(errors.New(\"no image chunk\"))\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif _, err := w.Write(chunk.GetBytes()); err != nil {\n\t\t\t\tw.CloseWithError(err)\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\timages, err := client.Import(ctx, r)\n\tif err != nil {\n\t\treturn status.Errorf(codes.Internal, \"failed to import image: %v\", err)\n\t}\n\n\tr.Close() //nolint:errcheck\n\n\tif len(images) == 0 {\n\t\treturn status.Errorf(codes.InvalidArgument, \"no images imported from archive\")\n\t}\n\n\timageName := images[0].Name\n\tfor _, img := range images {\n\t\timage := containerdapi.NewImage(client, img)\n\n\t\terr = image.Unpack(ctx, \"\")\n\t\tif err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to unpack image %s: %v\", img.Name, err)\n\t\t}\n\t}\n\n\timg, err := client.GetImage(ctx, imageName)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\tcreated, err := client.ImageService().Create(ctx, images[0])\n\t\t\tif err != nil {\n\t\t\t\treturn status.Errorf(codes.Internal, \"failed to create image: %v\", err)\n\t\t\t}\n\n\t\t\timageName = created.Name\n\n\t\t\timg, err = client.GetImage(ctx, imageName)\n\t\t\tif err != nil {\n\t\t\t\treturn status.Errorf(codes.Internal, \"failed to get image: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn srv.SendAndClose(&machine.ImageServiceImportResponse{\n\t\tName: img.Name(),\n\t})\n}\n\n// Remove an image from the containerd.\nfunc (svc *Service) Remove(ctx context.Context, req *machine.ImageServiceRemoveRequest) (*emptypb.Empty, error) {\n\tctx, _, client, err := ctrhelper.ContainerdInstanceHelper(ctx, req.GetContainerd())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\terr = client.ImageService().Delete(ctx, req.ImageRef, images.SynchronousDelete())\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn nil, status.Errorf(codes.NotFound, \"image %s not found\", req.ImageRef)\n\t\t}\n\n\t\treturn nil, status.Errorf(codes.Internal, \"failed to remove image %s: %v\", req.ImageRef, err)\n\t}\n\n\treturn &emptypb.Empty{}, nil\n}\n"
  },
  {
    "path": "internal/app/images/verify.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage images\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/verify\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// Verify an image signature against the configured verification policy.\n//\n// This endpoint is called by containerd before unpacking an image to ensure\n// the image meets the verification requirements configured in the machine config.\n//\n// If no verification policy is configured, all images are allowed by default.\nfunc (svc *Service) Verify(ctx context.Context, req *machine.ImageServiceVerifyRequest) (*machine.ImageServiceVerifyResponse, error) {\n\t// build resolver with custom auth if credentials are provided in the request\n\tvar opts []func(*cri.RegistriesConfigSpec)\n\n\tif req.Credentials != nil {\n\t\topts = append(opts, func(spec *cri.RegistriesConfigSpec) {\n\t\t\tif spec.RegistryAuths == nil {\n\t\t\t\tspec.RegistryAuths = make(map[string]*cri.RegistryAuthConfig)\n\t\t\t}\n\n\t\t\tspec.RegistryAuths[req.GetCredentials().GetHost()] = &cri.RegistryAuthConfig{\n\t\t\t\tRegistryUsername: req.GetCredentials().Username,\n\t\t\t\tRegistryPassword: req.GetCredentials().Password,\n\t\t\t}\n\t\t})\n\t}\n\n\tregistries, err := cri.RegistryBuilder(svc.controller.Runtime().State().V1Alpha2().Resources(), opts...)(ctx)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Internal, \"failed to build registry configuration: %s\", err)\n\t}\n\n\tresolver := image.NewResolver(registries)\n\n\treturn verify.ImageSignature(ctx, svc.logger, svc.controller.Runtime().State().V1Alpha2().Resources(), resolver, req.GetImageRef())\n}\n"
  },
  {
    "path": "internal/app/init/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package init implements booting process.\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/klauspost/cpuid/v2\"\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/switchroot\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/rng\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nfunc init() {\n\t// Explicitly disable memory profiling to save around 1.4MiB of memory.\n\truntime.MemProfileRate = 0\n}\n\n//nolint:gocyclo\nfunc run() error {\n\t// Mount the pseudo devices.\n\tpseudo := mount.Pseudo(nil)\n\n\tif _, err := pseudo.Mount(); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := mount.PseudoSub(nil).Mount(); err != nil {\n\t\treturn err\n\t}\n\n\t// Setup logging to /dev/kmsg.\n\tif err := kmsg.SetupLogger(nil, \"[talos] [initramfs]\", nil); err != nil {\n\t\treturn err\n\t}\n\n\t// Seed RNG.\n\tif err := rng.TPMSeed(); err != nil {\n\t\t// not making this fatal error\n\t\tlog.Printf(\"failed to seed from the TPM: %s\", err)\n\t}\n\n\t// extend PCR 11 with enter-initrd\n\tif err := tpm2.PCRExtend(constants.UKIPCR, []byte(secureboot.EnterInitrd)); err != nil {\n\t\treturn fmt.Errorf(\"failed to extend PCR %d with enter-initrd: %v\", constants.UKIPCR, err)\n\t}\n\n\tlog.Printf(\"booting Talos %s\", version.Tag)\n\n\tcpuInfo()\n\n\t// Mount the rootfs.\n\tif err := mountRootFS(); err != nil {\n\t\treturn err\n\t}\n\n\t// Bind mount the usr/lib/firmware if needed.\n\tif err := bindMountFirmware(); err != nil {\n\t\treturn err\n\t}\n\n\t// Bind mount /.extra if needed.\n\tif err := bindMountExtra(); err != nil {\n\t\treturn err\n\t}\n\n\t// Switch into the new rootfs.\n\tlog.Println(\"entering the rootfs\")\n\n\treturn switchroot.Switch(constants.NewRoot, pseudo)\n}\n\nfunc recovery() {\n\t// If panic is set in the kernel flags, we'll hang instead of rebooting.\n\t// But we still allow users to hit CTRL+ALT+DEL to try and restart when they're ready.\n\t// Listening for these signals also keep us from deadlocking the goroutine.\n\tif r := recover(); r != nil {\n\t\tlog.Printf(\"recovered from: %+v\\n\", r)\n\n\t\tp := procfs.ProcCmdline().Get(constants.KernelParamPanic).First()\n\t\tif p != nil && *p == \"0\" {\n\t\t\tlog.Printf(\"panic=0 kernel flag found. sleeping forever\")\n\n\t\t\texitSignal := make(chan os.Signal, 1)\n\t\t\tsignal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)\n\t\t\t<-exitSignal\n\t\t}\n\n\t\tfor i := 10; i >= 0; i-- {\n\t\t\tlog.Printf(\"rebooting in %d seconds\\n\", i)\n\t\t\ttime.Sleep(1 * time.Second)\n\t\t}\n\t}\n\n\t//nolint:errcheck\n\tunix.Reboot(unix.LINUX_REBOOT_CMD_RESTART)\n}\n\n//nolint:gocyclo\nfunc mountRootFS() error {\n\tlog.Println(\"mounting the rootfs\")\n\n\tvar extensionsConfig extensions.Config\n\n\tif err := extensionsConfig.Read(constants.ExtensionsConfigFile); err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"failed to read extensions config: %w\", err)\n\t\t}\n\t}\n\n\t// if no extensions found use plain squashfs mount\n\tif len(extensionsConfig.Layers) == 0 {\n\t\tsquashfs, err := mount.Squashfs(constants.NewRoot, \"/\"+constants.RootfsAsset, log.Printf)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize squashfs: %w\", err)\n\t\t}\n\n\t\tif _, err := squashfs.Mount(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to mount squashfs: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\t// otherwise compose overlay mounts\n\ttype layer struct {\n\t\tname  string\n\t\timage string\n\t}\n\n\tvar (\n\t\tlayers   []layer\n\t\tsquashfs mount.Managers\n\t)\n\n\t// going in the inverse order as earlier layers are overlayed on top of the latter ones\n\tfor i := len(extensionsConfig.Layers) - 1; i >= 0; i-- {\n\t\tlayers = append(layers, layer{\n\t\t\tname:  fmt.Sprintf(\"layer%d\", i),\n\t\t\timage: extensionsConfig.Layers[i].Image,\n\t\t})\n\n\t\tlog.Printf(\"enabling system extension %s %s\", extensionsConfig.Layers[i].Metadata.Name, extensionsConfig.Layers[i].Metadata.Version)\n\t}\n\n\tlayers = append(layers, layer{\n\t\tname:  \"root\",\n\t\timage: \"/\" + constants.RootfsAsset,\n\t})\n\n\toverlays := make([]string, 0, len(layers))\n\n\tfor _, layer := range layers {\n\t\ttarget := filepath.Join(constants.ExtensionLayers, layer.name)\n\n\t\tmanager, err := mount.Squashfs(target, layer.image, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsquashfs = append(squashfs, manager)\n\t\toverlays = append(overlays, target)\n\t}\n\n\tsquashfsUnmounter, err := squashfs.Mount()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toverlayPoint := mount.NewReadOnlyOverlay(\n\t\toverlays,\n\t\tconstants.NewRoot,\n\t\tnil,\n\t\tmount.WithShared(),\n\t)\n\n\t_, err = overlayPoint.Mount()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = squashfsUnmounter(); err != nil {\n\t\treturn err\n\t}\n\n\treturn mount.BindReadonly(constants.ExtensionsConfigFile, filepath.Join(constants.NewRoot, constants.ExtensionsRuntimeConfigFile))\n}\n\nfunc bindMountFirmware() error {\n\tfirmwarePath := quirks.New(\"\").FirmwarePath()\n\tif _, err := os.Stat(firmwarePath); err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tlog.Printf(\"bind mounting %s\", firmwarePath)\n\n\treturn mount.BindReadonly(firmwarePath, filepath.Join(constants.NewRoot, firmwarePath))\n}\n\nfunc bindMountExtra() error {\n\tif _, err := os.Stat(constants.SDStubDynamicInitrdPath); err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tlog.Printf(\"bind mounting %s\", constants.SDStubDynamicInitrdPath)\n\n\treturn mount.BindReadonly(constants.SDStubDynamicInitrdPath, filepath.Join(constants.NewRoot, constants.SDStubDynamicInitrdPath))\n}\n\nfunc cpuInfo() {\n\tlog.Printf(\"CPU: %s, %d core(s), %d thread(s) per core\", cpuid.CPU.BrandName, cpuid.CPU.PhysicalCores, cpuid.CPU.ThreadsPerCore)\n\n\tif runtime.GOARCH == \"amd64\" {\n\t\tlog.Printf(\"x86_64 microarchitecture level: %d\", cpuid.CPU.X64Level())\n\n\t\tif cpuid.CPU.X64Level() < constants.MinimumGOAMD64Level {\n\t\t\tif cpuid.CPU.VM() {\n\t\t\t\tlog.Printf(\"it might be that the VM is configured with an older CPU model, please check the VM configuration\")\n\t\t\t}\n\n\t\t\tlog.Printf(\"x86_64 microarchitecture level %d or higher is required, halting\", constants.MinimumGOAMD64Level)\n\n\t\t\ttime.Sleep(365 * 24 * time.Hour)\n\t\t}\n\t}\n}\n\nfunc main() {\n\tdefer recovery()\n\n\tif err := run(); err != nil {\n\t\tpanic(fmt.Errorf(\"early boot failed: %w\", err))\n\t}\n\n\t// We should never reach this point if things are working as intended.\n\tpanic(errors.New(\"unknown error\"))\n}\n"
  },
  {
    "path": "internal/app/internal/ctrhelper/ctrhelper.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ctrhelper provides helpers for container-related APIs.\npackage ctrhelper\n\nimport (\n\t\"context\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ContainerdInstanceHelper helps to create containerd client and context from the given ContainerdInstance.\n//\n// This function returns:\n//   - inbound context annotated with the appropriate containerd namespace\n//   - detached (context.Background()) context with the appropriate containerd namespace\n//   - containerd client\nfunc ContainerdInstanceHelper(ctx context.Context, req *common.ContainerdInstance) (context.Context, context.Context, *containerdapi.Client, error) {\n\tvar (\n\t\tcontainerdAddress   string\n\t\tcontainerdNamespace string\n\t)\n\n\tswitch req.GetDriver() {\n\tcase common.ContainerDriver_CONTAINERD:\n\t\tcontainerdAddress = constants.SystemContainerdAddress\n\tcase common.ContainerDriver_CRI:\n\t\tcontainerdAddress = constants.CRIContainerdAddress\n\tdefault:\n\t\treturn nil, nil, nil, status.Errorf(codes.InvalidArgument, \"invalid containerd driver %s\", req.GetDriver())\n\t}\n\n\tswitch req.GetNamespace() {\n\tcase common.ContainerdNamespace_NS_CRI:\n\t\tcontainerdNamespace = constants.K8sContainerdNamespace\n\tcase common.ContainerdNamespace_NS_SYSTEM:\n\t\tcontainerdNamespace = constants.SystemContainerdNamespace\n\tcase common.ContainerdNamespace_NS_UNKNOWN:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, nil, nil, status.Errorf(codes.InvalidArgument, \"invalid containerd namespace %s\", req.GetNamespace())\n\t}\n\n\tif req.GetDriver() == common.ContainerDriver_CONTAINERD && req.GetNamespace() == common.ContainerdNamespace_NS_CRI {\n\t\treturn nil, nil, nil, status.Errorf(codes.InvalidArgument, \"cannot use CRI namespace with containerd driver\")\n\t}\n\n\tclient, err := containerdapi.New(containerdAddress)\n\tif err != nil {\n\t\treturn ctx, nil, nil, status.Errorf(codes.Unavailable, \"error connecting to containerd: %s\", err)\n\t}\n\n\treturn namespaces.WithNamespace(ctx, containerdNamespace), namespaces.WithNamespace(context.Background(), containerdNamespace), client, nil\n}\n"
  },
  {
    "path": "internal/app/internal/machinehelper/machinehelper.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package machinehelper provides helper functions for machine-related information.\npackage machinehelper\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// CheckControlplane implements the controlplane machine type check.\n//\n// This works for API handlers.\nfunc CheckControlplane(ctx context.Context, resources state.State, apiName string) error {\n\tmachineType, err := safe.StateGetByID[*config.MachineType](ctx, resources, config.MachineTypeID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn status.Errorf(codes.Unimplemented, \"machine type is not set, cannot use %s API\", apiName)\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to get machine type: %w\", err)\n\t}\n\n\tif !machineType.MachineType().IsControlPlane() {\n\t\treturn status.Errorf(codes.Unimplemented, \"%s is only available on control plane nodes\", apiName)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/lifecycle/container.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage lifecycle\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/core/leases\"\n\t\"github.com/containerd/containerd/v2/pkg/cio\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/internal/ctrhelper\"\n\tcontainerdrunner \"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/install\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tconfigcore \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc generateContainerID() (string, error) {\n\tb := make([]byte, 8)\n\tif _, err := rand.Read(b); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to generate random ID: %w\", err)\n\t}\n\n\treturn fmt.Sprintf(\"installer-%s\", hex.EncodeToString(b)), nil\n}\n\n// sendFunc is a callback to stream a message line back to the client.\ntype sendFunc func(msg string) error\n\n// sendExitCodeFunc is a callback to stream the exit code back to the client.\ntype sendExitCodeFunc func(exitCode int32) error\n\n// containerRunConfig holds all parameters needed to create and run the installer container.\ntype containerRunConfig struct {\n\tcontainerdInst *common.ContainerdInstance\n\timageRef       string\n\tdisk           string\n\tplatform       string\n\tcfgContainer   configcore.Container\n\topts           []install.Option\n\n\tsend         sendFunc\n\tsendExitCode sendExitCodeFunc\n}\n\n// runInstallerContainer creates and runs the installer container synchronously,\n// streaming output lines back to the client via the send callback.\n//\n//nolint:gocyclo,cyclop\nfunc runInstallerContainer(ctx context.Context, rc *containerRunConfig) error {\n\toptions := install.Options{Pull: true} //nolint:staticcheck\n\tif err := options.Apply(rc.opts...); err != nil {\n\t\treturn fmt.Errorf(\"failed to apply install options: %w\", err)\n\t}\n\n\t// connect to containerd\n\tctx, detachedCtx, c8dClient, err := ctrhelper.ContainerdInstanceHelper(ctx, rc.containerdInst)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer c8dClient.Close() //nolint:errcheck\n\n\tl, err := c8dClient.LeasesService().Create(ctx, leases.WithRandomID())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create lease: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := c8dClient.LeasesService().Delete(detachedCtx, l, leases.SynchronousDelete); err != nil {\n\t\t\tlog.Printf(\"failed to delete lease %s: %v\", l.ID, err)\n\t\t}\n\t}()\n\n\tctx = leases.WithLease(ctx, l.ID)\n\n\timg, err := c8dClient.GetImage(ctx, rc.imageRef)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"installer image %q not found in containerd store: %w\", rc.imageRef, err)\n\t}\n\n\t// build container spec\n\tmounts := buildMounts()\n\targs := buildInstallerArgs(rc.disk, rc.platform, &options)\n\tspecOpts := buildSpecOpts(img, args, mounts)\n\n\tcontainerID, err := generateContainerID()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate container ID: %v\", err)\n\t}\n\n\t// create container\n\tctr, err := c8dClient.NewContainer(ctx, containerID,\n\t\tclient.WithImage(img),\n\t\tclient.WithNewSnapshot(containerID, img),\n\t\tclient.WithNewSpec(specOpts...),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create container: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif cleanupErr := ctr.Delete(detachedCtx, client.WithSnapshotCleanup); cleanupErr != nil {\n\t\t\tlog.Printf(\"failed to delete container %s: %v\", ctr.ID(), cleanupErr)\n\t\t}\n\t}()\n\n\t// set up I/O: stdout/stderr -> pipe -> stream to client; stdin <- config bytes\n\tstdoutR, stdoutW := io.Pipe()\n\n\tvar stdinReader interface {\n\t\tio.Reader\n\t\tWaitAndClose(context.Context, client.Task)\n\t}\n\n\tif rc.cfgContainer != nil {\n\t\tconfigBytes, cfgErr := rc.cfgContainer.Bytes()\n\t\tif cfgErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to serialize config: %w\", cfgErr)\n\t\t}\n\n\t\tstdinReader = &containerdrunner.StdinCloser{\n\t\t\tStdin:  bytes.NewReader(configBytes),\n\t\t\tCloser: make(chan struct{}),\n\t\t}\n\t}\n\n\tcreator := cio.NewCreator(cio.WithStreams(stdinReader, stdoutW, stdoutW))\n\n\ttask, err := ctr.NewTask(ctx, creator)\n\tif err != nil {\n\t\tstdoutW.Close() //nolint:errcheck\n\n\t\treturn fmt.Errorf(\"failed to create task: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif _, delErr := task.Delete(detachedCtx, client.WithProcessKill); delErr != nil && !errdefs.IsNotFound(delErr) {\n\t\t\tlog.Printf(\"failed to delete task: %v\", delErr)\n\t\t}\n\t}()\n\n\tif stdinReader != nil {\n\t\tgo stdinReader.WaitAndClose(ctx, task)\n\t}\n\n\tif err := task.Start(ctx); err != nil {\n\t\tstdoutW.Close() //nolint:errcheck\n\n\t\treturn fmt.Errorf(\"failed to start task: %w\", err)\n\t}\n\n\tstatusC, err := task.Wait(detachedCtx)\n\tif err != nil {\n\t\tstdoutW.Close() //nolint:errcheck\n\n\t\treturn fmt.Errorf(\"failed to wait for task: %w\", err)\n\t}\n\n\t// stream output in a goroutine\n\tsendDone := make(chan error, 1)\n\n\tgo func() {\n\t\tsendDone <- streamOutput(stdoutR, rc.send)\n\t}()\n\n\t// wait for task to exit\n\texitStatus := <-statusC\n\n\t// close the write end so the reader gets EOF\n\tstdoutW.Close() //nolint:errcheck\n\n\t// wait for send loop to finish\n\tif sendErr := <-sendDone; sendErr != nil {\n\t\tlog.Printf(\"error streaming output: %v\", sendErr)\n\t}\n\n\tif exitStatus.Error() != nil {\n\t\treturn fmt.Errorf(\"task exited with error: %w\", exitStatus.Error())\n\t}\n\n\texitCode := int32(exitStatus.ExitCode())\n\n\t// send exit code to client\n\tif err := rc.sendExitCode(exitCode); err != nil {\n\t\treturn fmt.Errorf(\"failed to send exit code: %w\", err)\n\t}\n\n\tif exitCode != 0 {\n\t\tlog.Printf(\"installer container exited with code %d\", exitCode)\n\t}\n\n\treturn nil\n}\n\n// streamOutput reads from r line by line and sends each line via the send callback.\nfunc streamOutput(r io.Reader, send sendFunc) error {\n\tbuf := make([]byte, 512)\n\n\tfor {\n\t\tn, err := r.Read(buf)\n\t\tif n > 0 {\n\t\t\tif sendErr := send(string(buf[:n])); sendErr != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to send message: %w\", sendErr)\n\t\t\t}\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to read output: %w\", err)\n\t\t}\n\t}\n}\n\n// buildMounts constructs the OCI mounts for the installer container.\nfunc buildMounts() []specs.Mount {\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: \"/dev\", Source: \"/dev\", Options: []string{\"rbind\", \"rshared\", \"rw\"}},\n\t}\n\n\tif _, err := os.Stat(constants.MachineSocketPath); err == nil {\n\t\tmounts = append(mounts, specs.Mount{\n\t\t\tType: \"bind\", Destination: constants.MachineSocketPath,\n\t\t\tSource: constants.MachineSocketPath, Options: []string{\"rbind\", \"rshared\", \"ro\"},\n\t\t})\n\t}\n\n\tif _, err := os.Stat(constants.EFIVarsMountPoint); err == nil {\n\t\tmounts = append(mounts, specs.Mount{\n\t\t\tType: \"efivarfs\", Source: \"efivarfs\",\n\t\t\tDestination: constants.EFIVarsMountPoint,\n\t\t\tOptions:     []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"relatime\"},\n\t\t})\n\t}\n\n\tif _, err := os.Stat(constants.SDStubDynamicInitrdPath); err == nil {\n\t\tmounts = append(mounts, specs.Mount{\n\t\t\tType: \"bind\", Destination: constants.SDStubDynamicInitrdPath,\n\t\t\tSource: constants.SDStubDynamicInitrdPath, Options: []string{\"rbind\", \"rshared\", \"ro\"},\n\t\t})\n\t}\n\n\treturn mounts\n}\n\n// buildInstallerArgs constructs the command-line arguments for the installer binary.\nfunc buildInstallerArgs(disk, platform string, options *install.Options) []string {\n\tconfig := constants.ConfigNone\n\tif c := procfs.ProcCmdline().Get(constants.KernelParamConfig).First(); c != nil {\n\t\tconfig = *c\n\t}\n\n\targs := []string{\n\t\t\"/bin/installer\",\n\t\t\"install\",\n\t\t\"--disk=\" + disk,\n\t\t\"--platform=\" + platform,\n\t\t\"--config=\" + config,\n\t\t\"--upgrade=\" + strconv.FormatBool(options.Upgrade),\n\t\t\"--force=\" + strconv.FormatBool(options.Force),\n\t\t\"--zero=\" + strconv.FormatBool(options.Zero),\n\t}\n\n\tfor _, arg := range options.ExtraKernelArgs {\n\t\targs = append(args, \"--extra-kernel-arg\", arg)\n\t}\n\n\tfor _, preservedArg := range []string{\n\t\tconstants.KernelParamSideroLink,\n\t\tconstants.KernelParamEventsSink,\n\t\tconstants.KernelParamLoggingKernel,\n\t\tconstants.KernelParamEquinixMetalEvents,\n\t\tconstants.KernelParamAuditdDisabled,\n\t\tconstants.KernelParamDashboardDisabled,\n\t\tconstants.KernelParamNetIfnames,\n\t\tconstants.KernelParamEnforceModuleSigVerify,\n\t} {\n\t\tif c := procfs.ProcCmdline().Get(preservedArg).First(); c != nil {\n\t\t\targs = append(args, \"--extra-kernel-arg\", fmt.Sprintf(\"%s=%s\", preservedArg, *c))\n\t\t}\n\t}\n\n\treturn args\n}\n\n// buildSpecOpts constructs the OCI spec options for the installer container.\nfunc buildSpecOpts(img client.Image, args []string, mounts []specs.Mount) []oci.SpecOpts {\n\tspecOpts := []oci.SpecOpts{\n\t\toci.WithImageConfig(img),\n\t\toci.WithProcessArgs(args...),\n\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\toci.WithHostNamespace(specs.PIDNamespace),\n\t\toci.WithMounts(mounts),\n\t\toci.WithHostHostsFile,\n\t\toci.WithHostResolvconf,\n\t\toci.WithParentCgroupDevices,\n\t\toci.WithCapabilities(capability.AllGrantableCapabilities()),\n\t\toci.WithMaskedPaths(nil),\n\t\toci.WithReadonlyPaths(nil),\n\t\toci.WithWriteableSysfs,\n\t\toci.WithWriteableCgroupfs,\n\t\toci.WithApparmorProfile(\"\"),\n\t\toci.WithSeccompUnconfined,\n\t\toci.WithAllDevicesAllowed,\n\t}\n\n\tif selinux.IsEnabled() {\n\t\tspecOpts = append(specOpts, oci.WithSelinuxLabel(constants.SelinuxLabelInstaller))\n\t}\n\n\treturn specOpts\n}\n"
  },
  {
    "path": "internal/app/lifecycle/lifecycle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package lifecycle implements machine.LifecycleService.\npackage lifecycle\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/install\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tcrires \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// Service implements machine.LifecycleService.\ntype Service struct {\n\tmachine.UnimplementedLifecycleServiceServer\n\n\tlock    sync.Mutex\n\truntime runtime.Runtime\n\tlogger  *zap.Logger\n}\n\n// NewService creates a new instance of the lifecycle service.\nfunc NewService(runtime runtime.Runtime, logger *zap.Logger) *Service {\n\treturn &Service{\n\t\tlock:    sync.Mutex{},\n\t\truntime: runtime,\n\t\tlogger:  logger.With(zap.String(\"service\", \"lifecycle\")),\n\t}\n}\n\n// Install handles the installation of the machine.\n// It ensures that only one installation or upgrade can occur at a time by using a mutex lock.\n//\n//nolint:gocyclo\nfunc (s *Service) Install(req *machine.LifecycleServiceInstallRequest, ss grpc.ServerStreamingServer[machine.LifecycleServiceInstallResponse]) error {\n\tif s.runtime.State().Platform().Mode().IsAgent() {\n\t\treturn status.Error(codes.Unimplemented, \"API is not implemented in agent mode\")\n\t}\n\n\tif err := s.checkSupported(runtime.Upgrade); err != nil {\n\t\treturn err\n\t}\n\n\tctx := ss.Context()\n\n\tif !s.lock.TryLock() {\n\t\treturn status.Error(codes.FailedPrecondition, \"another installation/upgrade is already in progress\")\n\t}\n\tdefer s.lock.Unlock()\n\n\tif s.runtime.State().Platform().Mode().InContainer() {\n\t\treturn status.Error(codes.FailedPrecondition, \"installation is not supported in container mode\")\n\t}\n\n\tif s.runtime.State().Machine().Installed() {\n\t\treturn status.Error(codes.AlreadyExists, \"machine is already installed\")\n\t}\n\n\tif err := crires.WaitForImageCache(ctx, s.runtime.State().V1Alpha2().Resources()); err != nil {\n\t\treturn status.Error(codes.Internal, fmt.Sprintf(\"failed to wait for the image cache: %v\", err))\n\t}\n\n\tinstallerImage := req.GetSource().GetImageName()\n\tif installerImage == \"\" {\n\t\treturn status.Error(codes.InvalidArgument, \"installer image name is required\")\n\t}\n\n\tdisk := req.GetDestination().GetDisk()\n\tif disk == \"\" {\n\t\treturn status.Error(codes.InvalidArgument, \"destination disk is required\")\n\t}\n\n\ttargetDisk, err := filepath.EvalSymlinks(disk)\n\tif err != nil {\n\t\treturn status.Error(codes.InvalidArgument, fmt.Sprintf(\"invalid disk path: %v\", err))\n\t}\n\n\ts.logger.Info(\"starting installation\", zap.String(\"installer_image\", installerImage), zap.String(\"disk\", targetDisk))\n\n\t//nolint:dupl\n\terr = runInstallerContainer(ctx, &containerRunConfig{\n\t\tcontainerdInst: req.GetContainerd(),\n\t\timageRef:       installerImage,\n\t\tdisk:           targetDisk,\n\t\tplatform:       s.runtime.State().Platform().Name(),\n\t\tcfgContainer:   s.runtime.ConfigContainer(),\n\t\topts: []install.Option{\n\t\t\tinstall.WithForce(true),\n\t\t\tinstall.WithZero(false),\n\t\t},\n\t\tsend: func(msg string) error {\n\t\t\ts.logger.Info(\"installation progress\", zap.String(\"message\", msg))\n\n\t\t\treturn ss.Send(&machine.LifecycleServiceInstallResponse{\n\t\t\t\tProgress: &machine.LifecycleServiceInstallProgress{\n\t\t\t\t\tResponse: &machine.LifecycleServiceInstallProgress_Message{\n\t\t\t\t\t\tMessage: msg,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t\tsendExitCode: func(exitCode int32) error {\n\t\t\tif exitCode == 0 {\n\t\t\t\ts.logger.Info(\"installation completed successfully\", zap.Int32(\"exit_code\", exitCode))\n\t\t\t} else {\n\t\t\t\ts.logger.Error(\"installation failed\", zap.Int32(\"exit_code\", exitCode))\n\t\t\t}\n\n\t\t\treturn ss.Send(&machine.LifecycleServiceInstallResponse{\n\t\t\t\tProgress: &machine.LifecycleServiceInstallProgress{\n\t\t\t\t\tResponse: &machine.LifecycleServiceInstallProgress_ExitCode{\n\t\t\t\t\t\tExitCode: exitCode,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn status.Error(codes.Internal, fmt.Sprintf(\"installation failed: %v\", err))\n\t}\n\n\treturn nil\n}\n\n// Upgrade handles the upgrade of the machine.\n// It ensures that only one installation or upgrade can occur at a time by using a mutex lock.\n//\n//nolint:gocyclo\nfunc (s *Service) Upgrade(req *machine.LifecycleServiceUpgradeRequest, ss grpc.ServerStreamingServer[machine.LifecycleServiceUpgradeResponse]) error {\n\tif s.runtime.State().Platform().Mode().IsAgent() {\n\t\treturn status.Error(codes.Unimplemented, \"API is not implemented in agent mode\")\n\t}\n\n\tif err := s.checkSupported(runtime.Upgrade); err != nil {\n\t\treturn err\n\t}\n\n\tctx := ss.Context()\n\n\tif !s.lock.TryLock() {\n\t\treturn status.Error(codes.FailedPrecondition, \"another installation/upgrade is already in progress\")\n\t}\n\tdefer s.lock.Unlock()\n\n\tif s.runtime.State().Platform().Mode().InContainer() {\n\t\treturn status.Error(codes.FailedPrecondition, \"upgrade is not supported in container mode\")\n\t}\n\n\tif !s.runtime.State().Machine().Installed() {\n\t\treturn status.Error(codes.FailedPrecondition, \"machine is not installed\")\n\t}\n\n\tinstallerImage := req.GetSource().GetImageName()\n\tif installerImage == \"\" {\n\t\treturn status.Error(codes.InvalidArgument, \"installer image name is required\")\n\t}\n\n\tsystemDisk, err := blockres.GetSystemDisk(ctx, s.runtime.State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn status.Error(codes.Internal, fmt.Sprintf(\"failed to get system disk: %v\", err))\n\t}\n\n\tif systemDisk == nil {\n\t\treturn status.Error(codes.Internal, \"system disk not found\")\n\t}\n\n\tdevname := systemDisk.DevPath\n\n\ts.logger.Info(\"starting upgrade\", zap.String(\"installer_image\", installerImage), zap.String(\"disk\", devname))\n\n\t//nolint:dupl\n\terr = runInstallerContainer(ctx, &containerRunConfig{\n\t\tcontainerdInst: req.GetContainerd(),\n\t\timageRef:       installerImage,\n\t\tdisk:           devname,\n\t\tplatform:       s.runtime.State().Platform().Name(),\n\t\tcfgContainer:   s.runtime.ConfigContainer(),\n\t\topts: []install.Option{\n\t\t\tinstall.WithUpgrade(true),\n\t\t\tinstall.WithForce(false),\n\t\t},\n\t\tsend: func(msg string) error {\n\t\t\ts.logger.Info(\"upgrade progress\", zap.String(\"message\", msg))\n\n\t\t\treturn ss.Send(&machine.LifecycleServiceUpgradeResponse{\n\t\t\t\tProgress: &machine.LifecycleServiceInstallProgress{\n\t\t\t\t\tResponse: &machine.LifecycleServiceInstallProgress_Message{\n\t\t\t\t\t\tMessage: msg,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t\tsendExitCode: func(exitCode int32) error {\n\t\t\tif exitCode == 0 {\n\t\t\t\ts.logger.Info(\"upgrade completed successfully\", zap.Int32(\"exit_code\", exitCode))\n\t\t\t} else {\n\t\t\t\ts.logger.Error(\"upgrade failed\", zap.Int32(\"exit_code\", exitCode))\n\t\t\t}\n\n\t\t\treturn ss.Send(&machine.LifecycleServiceUpgradeResponse{\n\t\t\t\tProgress: &machine.LifecycleServiceInstallProgress{\n\t\t\t\t\tResponse: &machine.LifecycleServiceInstallProgress_ExitCode{\n\t\t\t\t\t\tExitCode: exitCode,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn status.Error(codes.Internal, fmt.Sprintf(\"upgrade failed: %v\", err))\n\t}\n\n\treturn nil\n}\n\nfunc (s *Service) checkSupported(feature runtime.ModeCapability) error {\n\tmode := s.runtime.State().Platform().Mode()\n\n\tif !mode.Supports(feature) {\n\t\treturn status.Errorf(codes.FailedPrecondition, \"method is not supported in %s mode\", mode.String())\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package runtime provides the runtime implementation.\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/internal/machinehelper\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\tclusterapi \"github.com/siderolabs/talos/pkg/machinery/api/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tclusterres \"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// HealthCheck implements the cluster.ClusterServer interface.\nfunc (s *Server) HealthCheck(in *clusterapi.HealthCheckRequest, srv clusterapi.ClusterService_HealthCheckServer) error {\n\tif err := machinehelper.CheckControlplane(srv.Context(), s.Controller.Runtime().State().V1Alpha2().Resources(), \"cluster health check\"); err != nil {\n\t\treturn err\n\t}\n\n\tclientProvider := cluster.NewLocalClientProvider(\n\t\ts.Controller.Runtime().State().V1Alpha2().Resources(),\n\t\t// use talosconfig with same roles as incoming request for local communication\n\t\tauthz.GetRoles(srv.Context()),\n\t)\n\tdefer clientProvider.Close() //nolint:errcheck\n\n\tk8sProvider := &cluster.KubernetesClient{\n\t\tClientProvider: clientProvider,\n\t\tForceEndpoint:  in.GetClusterInfo().GetForceEndpoint(),\n\t}\n\tdefer k8sProvider.K8sClose() //nolint:errcheck\n\n\tcheckCtx, checkCtxCancel := context.WithTimeout(srv.Context(), in.WaitTimeout.AsDuration())\n\tdefer checkCtxCancel()\n\n\tr := s.Controller.Runtime()\n\n\tclusterInfo, err := buildClusterInfo(checkCtx, in, r, *k8sProvider)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate := struct {\n\t\tcluster.ClientProvider\n\t\tcluster.K8sProvider\n\t\tcluster.Info\n\t}{\n\t\tClientProvider: clientProvider,\n\t\tK8sProvider:    k8sProvider,\n\t\tInfo:           clusterInfo,\n\t}\n\n\tnodeInternalIPs := xslices.Map(clusterInfo.Nodes(), func(info cluster.NodeInfo) string {\n\t\treturn info.InternalIP.String()\n\t})\n\n\tif err := srv.Send(&clusterapi.HealthCheckProgress{\n\t\tMessage: fmt.Sprintf(\"discovered nodes: %q\", nodeInternalIPs),\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn check.Wait(checkCtx, &state, append(check.DefaultClusterChecks(), check.ExtraClusterChecks()...), &healthReporter{srv: srv})\n}\n\ntype healthReporter struct {\n\tsrv      clusterapi.ClusterService_HealthCheckServer\n\tlastLine string\n}\n\nfunc (hr *healthReporter) Update(condition conditions.Condition) {\n\tline := fmt.Sprintf(\"waiting for %s\", condition)\n\n\tif line != hr.lastLine {\n\t\thr.srv.Send(&clusterapi.HealthCheckProgress{ //nolint:errcheck\n\t\t\tMessage: strings.TrimSpace(line),\n\t\t})\n\n\t\thr.lastLine = line\n\t}\n}\n\ntype clusterState struct {\n\tnodeInfos       []cluster.NodeInfo\n\tnodeInfosByType map[machine.Type][]cluster.NodeInfo\n}\n\nfunc (cl *clusterState) Nodes() []cluster.NodeInfo {\n\treturn cl.nodeInfos\n}\n\nfunc (cl *clusterState) NodesByType(t machine.Type) []cluster.NodeInfo {\n\treturn cl.nodeInfosByType[t]\n}\n\nfunc (cl *clusterState) String() string {\n\treturn fmt.Sprintf(\"control plane: %q, worker: %q\",\n\t\txslices.Map(cl.nodeInfosByType[machine.TypeControlPlane], func(info cluster.NodeInfo) string {\n\t\t\treturn info.InternalIP.String()\n\t\t}),\n\t\txslices.Map(cl.nodeInfosByType[machine.TypeWorker], func(info cluster.NodeInfo) string {\n\t\t\treturn info.InternalIP.String()\n\t\t}))\n}\n\n//nolint:gocyclo\nfunc buildClusterInfo(ctx context.Context,\n\treq *clusterapi.HealthCheckRequest,\n\tr runtime.Runtime,\n\tcli cluster.KubernetesClient,\n) (cluster.Info, error) {\n\tcontrolPlaneNodes := req.GetClusterInfo().GetControlPlaneNodes()\n\tworkerNodes := req.GetClusterInfo().GetWorkerNodes()\n\n\t// if the node list is explicitly provided, use it\n\tif len(controlPlaneNodes) != 0 || len(workerNodes) != 0 {\n\t\tcontrolPlaneNodeInfos, err := cluster.IPsToNodeInfos(controlPlaneNodes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tworkerNodeInfos, err := cluster.IPsToNodeInfos(workerNodes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &clusterState{\n\t\t\tnodeInfos: slices.Concat(controlPlaneNodeInfos, workerNodeInfos),\n\t\t\tnodeInfosByType: map[machine.Type][]cluster.NodeInfo{\n\t\t\t\tmachine.TypeControlPlane: controlPlaneNodeInfos,\n\t\t\t\tmachine.TypeWorker:       workerNodeInfos,\n\t\t\t},\n\t\t}, nil\n\t}\n\n\t// try to discover nodes using discovery service\n\tdiscoveryMemberList, err := getDiscoveryMemberList(ctx, r)\n\tif err != nil {\n\t\tlog.Printf(\"discovery service returned error: %v\\n\", err)\n\t}\n\n\t// discovery service returned some nodes, use them\n\tif len(discoveryMemberList) > 0 {\n\t\treturn check.NewDiscoveredClusterInfo(discoveryMemberList)\n\t}\n\n\t// as the last resort, get the nodes from the cluster itself\n\tk8sCli, err := cli.K8sClient(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodeList, err := k8sCli.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodeInfos := make([]cluster.NodeInfo, len(nodeList.Items))\n\tnodeInfosByType := map[machine.Type][]cluster.NodeInfo{}\n\n\tfor i, node := range nodeList.Items {\n\t\tnodeInfo, err2 := k8sNodeToNodeInfo(&node)\n\t\tif err2 != nil {\n\t\t\treturn nil, err2\n\t\t}\n\n\t\tif isControlPlaneNode(&node) {\n\t\t\tnodeInfosByType[machine.TypeControlPlane] = append(nodeInfosByType[machine.TypeControlPlane], *nodeInfo)\n\t\t} else {\n\t\t\tnodeInfosByType[machine.TypeWorker] = append(nodeInfosByType[machine.TypeWorker], *nodeInfo)\n\t\t}\n\n\t\tnodeInfos[i] = *nodeInfo\n\t}\n\n\treturn &clusterState{\n\t\tnodeInfos:       nodeInfos,\n\t\tnodeInfosByType: nodeInfosByType,\n\t}, nil\n}\n\nfunc k8sNodeToNodeInfo(node *corev1.Node) (*cluster.NodeInfo, error) {\n\tif node == nil {\n\t\treturn nil, nil\n\t}\n\n\tvar internalIP netip.Addr\n\n\tips := make([]netip.Addr, 0, len(node.Status.Addresses))\n\n\tfor _, address := range node.Status.Addresses {\n\t\tswitch address.Type { //nolint:exhaustive\n\t\tcase corev1.NodeInternalIP:\n\t\t\tip, err := netip.ParseAddr(address.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tinternalIP = ip\n\t\t\tips = append(ips, ip)\n\t\tcase corev1.NodeExternalIP:\n\t\t\tip, err := netip.ParseAddr(address.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tips = append(ips, ip)\n\t\t}\n\t}\n\n\treturn &cluster.NodeInfo{\n\t\tInternalIP: internalIP,\n\t\tIPs:        ips,\n\t}, nil\n}\n\nfunc getDiscoveryMemberList(ctx context.Context, runtime runtime.Runtime) ([]*clusterres.Member, error) {\n\tres := runtime.State().V1Alpha2().Resources()\n\n\tlist, err := safe.StateListAll[*clusterres.Member](ctx, res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn safe.ToSlice(list, func(m *clusterres.Member) *clusterres.Member { return m }), nil\n}\n\nfunc isControlPlaneNode(node *corev1.Node) bool {\n\tfor key := range node.Labels {\n\t\tif key == constants.LabelNodeRoleControlPlane {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/containerd/platforms\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\nfunc containerdNamespaceHelper(ctx context.Context, ns common.ContainerdNamespace) (context.Context, error) {\n\tvar namespaceName string\n\n\tswitch ns {\n\tcase common.ContainerdNamespace_NS_CRI:\n\t\tnamespaceName = constants.K8sContainerdNamespace\n\tcase common.ContainerdNamespace_NS_SYSTEM:\n\t\tnamespaceName = constants.SystemContainerdNamespace\n\tcase common.ContainerdNamespace_NS_UNKNOWN:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"invalid namespace %s\", ns)\n\t}\n\n\treturn namespaces.WithNamespace(ctx, namespaceName), nil\n}\n\n// ImageList lists the images in the CRI.\n//\n// Deprecated: use ImageService.List instead.\nfunc (s *Server) ImageList(req *machine.ImageListRequest, srv machine.MachineService_ImageListServer) error {\n\tclient, err := containerdapi.New(constants.CRIContainerdAddress)\n\tif err != nil {\n\t\treturn status.Errorf(codes.Unavailable, \"error connecting to containerd: %s\", err)\n\t}\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tctx, err := containerdNamespaceHelper(srv.Context(), req.Namespace)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\timages, err := client.ImageService().List(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, image := range images {\n\t\titem := &machine.ImageListResponse{\n\t\t\tName:      image.Name,\n\t\t\tDigest:    image.Target.Digest.String(),\n\t\t\tCreatedAt: timestamppb.New(image.CreatedAt),\n\t\t}\n\n\t\tsize, err := image.Size(ctx, client.ContentStore(), platforms.Default())\n\t\tif err == nil {\n\t\t\titem.Size = size\n\t\t}\n\n\t\tif err = srv.Send(item); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ImagePull pulls an image to the CRI.\n//\n// Deprecated: use ImageService.Pull instead.\nfunc (s *Server) ImagePull(ctx context.Context, req *machine.ImagePullRequest) (*machine.ImagePullResponse, error) {\n\tclient, err := containerdapi.New(constants.CRIContainerdAddress)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Unavailable, \"error connecting to containerd: %s\", err)\n\t}\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tctx, err = containerdNamespaceHelper(ctx, req.Namespace)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, err = image.Pull(ctx,\n\t\tcri.RegistryBuilder(s.Controller.Runtime().State().V1Alpha2().Resources()),\n\t\ts.Controller.Runtime().State().V1Alpha2().Resources(),\n\t\tclient, req.Reference,\n\t\timage.WithSkipIfAlreadyPulled(),\n\t\timage.WithMaxNotFoundRetries(0), // return an error immediately if the image is not found\n\t)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn nil, status.Errorf(codes.NotFound, \"error pulling image: %s\", err)\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn &machine.ImagePullResponse{\n\t\tMessages: []*machine.ImagePull{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_inspect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\tinspectapi \"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n)\n\n// InspectServer implements InspectService API.\ntype InspectServer struct {\n\tinspectapi.UnimplementedInspectServiceServer\n\n\tserver *Server\n}\n\n// ControllerRuntimeDependencies implements inspect.InspectService interface.\nfunc (s *InspectServer) ControllerRuntimeDependencies(ctx context.Context, in *emptypb.Empty) (*inspectapi.ControllerRuntimeDependenciesResponse, error) {\n\tgraph, err := s.server.Controller.V1Alpha2().DependencyGraph()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching dependency graph: %w\", err)\n\t}\n\n\tedges := make([]*inspectapi.ControllerDependencyEdge, 0, len(graph.Edges))\n\n\tfor i := range graph.Edges {\n\t\tvar edgeType inspectapi.DependencyEdgeType\n\n\t\tswitch graph.Edges[i].EdgeType {\n\t\tcase controller.EdgeOutputExclusive:\n\t\t\tedgeType = inspectapi.DependencyEdgeType_OUTPUT_EXCLUSIVE\n\t\tcase controller.EdgeOutputShared:\n\t\t\tedgeType = inspectapi.DependencyEdgeType_OUTPUT_SHARED\n\t\tcase controller.EdgeInputStrong:\n\t\t\tedgeType = inspectapi.DependencyEdgeType_INPUT_STRONG\n\t\tcase controller.EdgeInputWeak:\n\t\t\tedgeType = inspectapi.DependencyEdgeType_INPUT_WEAK\n\t\tcase controller.EdgeInputDestroyReady:\n\t\t\tedgeType = inspectapi.DependencyEdgeType_INPUT_DESTROY_READY\n\t\tcase controller.EdgeInputQPrimary,\n\t\t\tcontroller.EdgeInputQMapped,\n\t\t\tcontroller.EdgeInputQMappedDestroyReady:\n\t\t\treturn nil, fmt.Errorf(\"unexpected edge type: %v\", graph.Edges[i].EdgeType)\n\t\t}\n\n\t\tedges = append(edges, &inspectapi.ControllerDependencyEdge{\n\t\t\tControllerName: graph.Edges[i].ControllerName,\n\n\t\t\tEdgeType: edgeType,\n\n\t\t\tResourceNamespace: graph.Edges[i].ResourceNamespace,\n\t\t\tResourceType:      graph.Edges[i].ResourceType,\n\t\t\tResourceId:        graph.Edges[i].ResourceID,\n\t\t})\n\t}\n\n\treturn &inspectapi.ControllerRuntimeDependenciesResponse{\n\t\tMessages: []*inspectapi.ControllerRuntimeDependency{\n\t\t\t{\n\t\t\t\tEdges: edges,\n\t\t\t},\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io/fs\"\n\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// MetaWrite implements the machine.MachineServer interface.\nfunc (s *Server) MetaWrite(ctx context.Context, req *machine.MetaWriteRequest) (*machine.MetaWriteResponse, error) {\n\tif err := s.checkSupported(runtime.MetaKV); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif uint32(uint8(req.Key)) != req.Key {\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"key must be a uint8\")\n\t}\n\n\tok, err := s.Controller.Runtime().State().Machine().Meta().SetTagBytes(ctx, uint8(req.Key), req.Value)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !ok {\n\t\t// META overflowed\n\t\treturn nil, status.Errorf(codes.ResourceExhausted, \"meta write failed\")\n\t}\n\n\terr = s.Controller.Runtime().State().Machine().Meta().Flush()\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t// ignore not exist error, as it's possible that the meta partition is not created yet\n\t\treturn nil, err\n\t}\n\n\treturn &machine.MetaWriteResponse{\n\t\tMessages: []*machine.MetaWrite{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// MetaDelete implements the machine.MachineServer interface.\nfunc (s *Server) MetaDelete(ctx context.Context, req *machine.MetaDeleteRequest) (*machine.MetaDeleteResponse, error) {\n\tif err := s.checkSupported(runtime.MetaKV); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif uint32(uint8(req.Key)) != req.Key {\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"key must be a uint8\")\n\t}\n\n\tok, err := s.Controller.Runtime().State().Machine().Meta().DeleteTag(ctx, uint8(req.Key))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !ok {\n\t\t// META key not found\n\t\treturn nil, status.Errorf(codes.NotFound, \"meta key not found\")\n\t}\n\n\terr = s.Controller.Runtime().State().Machine().Meta().Flush()\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t// ignore not exist error, as it's possible that the meta partition is not created yet\n\t\treturn nil, err\n\t}\n\n\treturn &machine.MetaDeleteResponse{\n\t\tMessages: []*machine.MetaDelete{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_monitoring.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/prometheus/procfs\"\n\t\"github.com/prometheus/procfs/sysfs\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// Hostname implements the machine.MachineServer interface.\nfunc (s *Server) Hostname(ctx context.Context, in *emptypb.Empty) (*machine.HostnameResponse, error) {\n\thostname, err := os.Hostname()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := &machine.HostnameResponse{\n\t\tMessages: []*machine.Hostname{\n\t\t\t{\n\t\t\t\tHostname: hostname,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// LoadAvg implements the machine.MachineServer interface.\nfunc (s *Server) LoadAvg(ctx context.Context, in *emptypb.Empty) (*machine.LoadAvgResponse, error) {\n\tfs, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tloadAvg, err := fs.LoadAvg()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := &machine.LoadAvgResponse{\n\t\tMessages: []*machine.LoadAvg{\n\t\t\t{\n\t\t\t\tLoad1:  loadAvg.Load1,\n\t\t\t\tLoad5:  loadAvg.Load5,\n\t\t\t\tLoad15: loadAvg.Load15,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// SystemStat implements the machine.MachineServer interface.\nfunc (s *Server) SystemStat(ctx context.Context, in *emptypb.Empty) (*machine.SystemStatResponse, error) {\n\tfs, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tstat, err := fs.Stat()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttranslateCPUStat := func(in procfs.CPUStat) *machine.CPUStat {\n\t\treturn &machine.CPUStat{\n\t\t\tUser:      in.User,\n\t\t\tNice:      in.Nice,\n\t\t\tSystem:    in.System,\n\t\t\tIdle:      in.Idle,\n\t\t\tIowait:    in.Iowait,\n\t\t\tIrq:       in.IRQ,\n\t\t\tSoftIrq:   in.SoftIRQ,\n\t\t\tSteal:     in.Steal,\n\t\t\tGuest:     in.Guest,\n\t\t\tGuestNice: in.GuestNice,\n\t\t}\n\t}\n\n\ttranslateListOfCPUStat := func(in map[int64]procfs.CPUStat) []*machine.CPUStat {\n\t\tmaxCore := int64(-1)\n\n\t\tfor core := range in {\n\t\t\tmaxCore = max(maxCore, core)\n\t\t}\n\n\t\tslc := make([]*machine.CPUStat, maxCore+1)\n\n\t\tfor core, stat := range in {\n\t\t\tslc[core] = translateCPUStat(stat)\n\t\t}\n\n\t\treturn slc\n\t}\n\n\ttranslateSoftIRQ := func(in procfs.SoftIRQStat) *machine.SoftIRQStat {\n\t\treturn &machine.SoftIRQStat{\n\t\t\tHi:          in.Hi,\n\t\t\tTimer:       in.Timer,\n\t\t\tNetTx:       in.NetTx,\n\t\t\tNetRx:       in.NetRx,\n\t\t\tBlock:       in.Block,\n\t\t\tBlockIoPoll: in.BlockIoPoll,\n\t\t\tTasklet:     in.Tasklet,\n\t\t\tSched:       in.Sched,\n\t\t\tHrtimer:     in.Hrtimer,\n\t\t\tRcu:         in.Rcu,\n\t\t}\n\t}\n\n\treply := &machine.SystemStatResponse{\n\t\tMessages: []*machine.SystemStat{\n\t\t\t{\n\t\t\t\tBootTime:        stat.BootTime,\n\t\t\t\tCpuTotal:        translateCPUStat(stat.CPUTotal),\n\t\t\t\tCpu:             translateListOfCPUStat(stat.CPU),\n\t\t\t\tIrqTotal:        stat.IRQTotal,\n\t\t\t\tIrq:             stat.IRQ,\n\t\t\t\tContextSwitches: stat.ContextSwitches,\n\t\t\t\tProcessCreated:  stat.ProcessCreated,\n\t\t\t\tProcessRunning:  stat.ProcessesRunning,\n\t\t\t\tProcessBlocked:  stat.ProcessesBlocked,\n\t\t\t\tSoftIrqTotal:    stat.SoftIRQTotal,\n\t\t\t\tSoftIrq:         translateSoftIRQ(stat.SoftIRQ),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// CPUFreqStats implements the machine.MachineServer interface.\nfunc (s *Server) CPUFreqStats(ctx context.Context, in *emptypb.Empty) (*machine.CPUFreqStatsResponse, error) {\n\tfs, err := sysfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsystemCpufreqStats, err := fs.SystemCpufreq()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttranslateCPUFreqStats := func(in sysfs.SystemCPUCpufreqStats) *machine.CPUFreqStats {\n\t\tif in.CpuinfoCurrentFrequency == nil || in.CpuinfoMinimumFrequency == nil || in.CpuinfoMaximumFrequency == nil {\n\t\t\treturn &machine.CPUFreqStats{}\n\t\t}\n\n\t\treturn &machine.CPUFreqStats{\n\t\t\tCurrentFrequency: *in.CpuinfoCurrentFrequency,\n\t\t\tMinimumFrequency: *in.CpuinfoMinimumFrequency,\n\t\t\tMaximumFrequency: *in.CpuinfoMaximumFrequency,\n\t\t\tGovernor:         in.Governor,\n\t\t}\n\t}\n\n\treply := &machine.CPUFreqStatsResponse{\n\t\tMessages: []*machine.CPUsFreqStats{\n\t\t\t{\n\t\t\t\tCpuFreqStats: xslices.Map(systemCpufreqStats, translateCPUFreqStats),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// CPUInfo implements the machine.MachineServer interface.\nfunc (s *Server) CPUInfo(ctx context.Context, in *emptypb.Empty) (*machine.CPUInfoResponse, error) {\n\tfs, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinfo, err := fs.CPUInfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttranslateCPUInfo := func(in procfs.CPUInfo) *machine.CPUInfo {\n\t\treturn &machine.CPUInfo{\n\t\t\tProcessor:       uint32(in.Processor),\n\t\t\tVendorId:        in.VendorID,\n\t\t\tCpuFamily:       in.CPUFamily,\n\t\t\tModel:           in.Model,\n\t\t\tModelName:       in.ModelName,\n\t\t\tStepping:        in.Stepping,\n\t\t\tMicrocode:       in.Microcode,\n\t\t\tCpuMhz:          in.CPUMHz,\n\t\t\tCacheSize:       in.CacheSize,\n\t\t\tPhysicalId:      in.PhysicalID,\n\t\t\tSiblings:        uint32(in.Siblings),\n\t\t\tCoreId:          in.CoreID,\n\t\t\tApicId:          in.APICID,\n\t\t\tInitialApicId:   in.InitialAPICID,\n\t\t\tFpu:             in.FPU,\n\t\t\tFpuException:    in.FPUException,\n\t\t\tCpuIdLevel:      uint32(in.CPUIDLevel),\n\t\t\tWp:              in.WP,\n\t\t\tFlags:           in.Flags,\n\t\t\tBugs:            in.Bugs,\n\t\t\tBogoMips:        in.BogoMips,\n\t\t\tClFlushSize:     uint32(in.CLFlushSize),\n\t\t\tCacheAlignment:  uint32(in.CacheAlignment),\n\t\t\tAddressSizes:    in.AddressSizes,\n\t\t\tPowerManagement: in.PowerManagement,\n\t\t}\n\t}\n\n\treply := &machine.CPUInfoResponse{\n\t\tMessages: []*machine.CPUsInfo{\n\t\t\t{\n\t\t\t\tCpuInfo: xslices.Map(info, translateCPUInfo),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// NetworkDeviceStats implements the machine.MachineServer interface.\nfunc (s *Server) NetworkDeviceStats(ctx context.Context, in *emptypb.Empty) (*machine.NetworkDeviceStatsResponse, error) {\n\tfs, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinfo, err := fs.NetDev()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttranslateNetDevLine := func(in procfs.NetDevLine) *machine.NetDev {\n\t\treturn &machine.NetDev{\n\t\t\tName:         in.Name,\n\t\t\tRxBytes:      in.RxBytes,\n\t\t\tRxPackets:    in.RxPackets,\n\t\t\tRxErrors:     in.RxErrors,\n\t\t\tRxDropped:    in.RxDropped,\n\t\t\tRxFifo:       in.RxFIFO,\n\t\t\tRxFrame:      in.RxFrame,\n\t\t\tRxCompressed: in.RxCompressed,\n\t\t\tRxMulticast:  in.RxMulticast,\n\t\t\tTxBytes:      in.TxBytes,\n\t\t\tTxPackets:    in.TxPackets,\n\t\t\tTxErrors:     in.TxErrors,\n\t\t\tTxDropped:    in.TxDropped,\n\t\t\tTxFifo:       in.TxFIFO,\n\t\t\tTxCollisions: in.TxCollisions,\n\t\t\tTxCarrier:    in.TxCarrier,\n\t\t\tTxCompressed: in.TxCompressed,\n\t\t}\n\t}\n\n\treply := &machine.NetworkDeviceStatsResponse{\n\t\tMessages: []*machine.NetworkDeviceStats{\n\t\t\t{\n\t\t\t\tDevices: maps.ValuesFunc(info, translateNetDevLine),\n\t\t\t\tTotal:   translateNetDevLine(info.Total()),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// DiskStats implements the machine.MachineServer interface.\nfunc (s *Server) DiskStats(ctx context.Context, in *emptypb.Empty) (*machine.DiskStatsResponse, error) {\n\tf, err := os.Open(\"/proc/diskstats\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tresp := machine.DiskStats{\n\t\tDevices: []*machine.DiskStat{},\n\t\tTotal:   &machine.DiskStat{},\n\t}\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\n\t\tif len(fields) < 18 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvalues := make([]uint64, 15)\n\t\tfor i := range values {\n\t\t\tvalues[i], err = strconv.ParseUint(fields[3+i], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tstat := &machine.DiskStat{\n\t\t\tName:             fields[2],\n\t\t\tReadCompleted:    values[0],\n\t\t\tReadMerged:       values[1],\n\t\t\tReadSectors:      values[2],\n\t\t\tReadTimeMs:       values[3],\n\t\t\tWriteCompleted:   values[4],\n\t\t\tWriteMerged:      values[5],\n\t\t\tWriteSectors:     values[6],\n\t\t\tWriteTimeMs:      values[7],\n\t\t\tIoInProgress:     values[8],\n\t\t\tIoTimeMs:         values[9],\n\t\t\tIoTimeWeightedMs: values[10],\n\t\t\tDiscardCompleted: values[11],\n\t\t\tDiscardMerged:    values[12],\n\t\t\tDiscardSectors:   values[13],\n\t\t\tDiscardTimeMs:    values[14],\n\t\t}\n\n\t\tresp.Devices = append(resp.Devices, stat)\n\n\t\tresp.Total.ReadCompleted += stat.ReadCompleted\n\t\tresp.Total.ReadMerged += stat.ReadMerged\n\t\tresp.Total.ReadSectors += stat.ReadSectors\n\t\tresp.Total.ReadTimeMs += stat.ReadTimeMs\n\t\tresp.Total.WriteCompleted += stat.WriteCompleted\n\t\tresp.Total.WriteMerged += stat.WriteMerged\n\t\tresp.Total.WriteSectors += stat.WriteSectors\n\t\tresp.Total.WriteTimeMs += stat.WriteTimeMs\n\t\tresp.Total.IoInProgress += stat.IoInProgress\n\t\tresp.Total.IoTimeMs += stat.IoTimeMs\n\t\tresp.Total.IoTimeWeightedMs += stat.IoTimeWeightedMs\n\t\tresp.Total.DiscardCompleted += stat.DiscardCompleted\n\t\tresp.Total.DiscardMerged += stat.DiscardMerged\n\t\tresp.Total.DiscardSectors += stat.DiscardSectors\n\t\tresp.Total.DiscardTimeMs += stat.DiscardTimeMs\n\t}\n\n\tif err = scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := &machine.DiskStatsResponse{\n\t\tMessages: []*machine.DiskStats{\n\t\t\t&resp,\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"archive/tar\"\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/blang/semver/v4\"\n\tcosiv1alpha1 \"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/server\"\n\t\"github.com/google/uuid\"\n\t\"github.com/gopacket/gopacket/afpacket\"\n\tmultierror \"github.com/hashicorp/go-multierror\"\n\t\"github.com/nberlee/go-netstat/netstat\"\n\t\"github.com/pkg/xattr\"\n\t\"github.com/prometheus/procfs\"\n\t\"github.com/rs/xid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.etcd.io/etcd/api/v3/etcdserverpb\"\n\t\"go.etcd.io/etcd/api/v3/v3rpc/rpctypes\"\n\tclientv3 \"go.etcd.io/etcd/client/v3\"\n\t\"go.etcd.io/etcd/client/v3/concurrency\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/net/bpf\"\n\t\"golang.org/x/sys/unix\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/internal/app/debug\"\n\t\"github.com/siderolabs/talos/internal/app/images\"\n\t\"github.com/siderolabs/talos/internal/app/internal/machinehelper\"\n\t\"github.com/siderolabs/talos/internal/app/lifecycle\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/resources\"\n\tstoraged \"github.com/siderolabs/talos/internal/app/storaged\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers\"\n\ttaloscontainerd \"github.com/siderolabs/talos/internal/pkg/containers/containerd\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/cri\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/internal/pkg/install\"\n\t\"github.com/siderolabs/talos/internal/pkg/miniprocfs\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/internal/pkg/pcap\"\n\t\"github.com/siderolabs/talos/pkg/archiver\"\n\t\"github.com/siderolabs/talos/pkg/chunker\"\n\t\"github.com/siderolabs/talos/pkg/chunker/stream\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/kubeconfig\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\ttimeapi \"github.com/siderolabs/talos/pkg/machinery/api/time\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configdiff\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\tmachinetype \"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tcrires \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\tetcdresource \"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// MinimumEtcdUpgradeLeaseLockSeconds indicates the minimum number of seconds for which we open a lease lock for upgrading Etcd nodes.\n// This is not intended to lock for the duration of an upgrade.\n// Rather, it is intended to make sure only one node processes the various pre-upgrade checks at a time.\n// Thus, this timeout should be reflective of the expected time for the pre-upgrade checks, NOT the time to perform the upgrade itself.\nconst MinimumEtcdUpgradeLeaseLockSeconds = 60\n\n// OSPathSeparator is the string version of the os.PathSeparator.\nconst OSPathSeparator = string(os.PathSeparator)\n\n// Server implements ClusterService and MachineService APIs\n// and is also responsible for registering ResourceServer and InspectServer.\ntype Server struct {\n\tcluster.UnimplementedClusterServiceServer\n\tmachine.UnimplementedMachineServiceServer\n\n\tController runtime.Controller\n\t// breaking the import loop cycle between services/ package and v1alpha1_server.go\n\tEtcdBootstrapper func(context.Context, runtime.Runtime, *machine.BootstrapRequest) error\n\n\t// ShutdownCtx signals that the server is shutting down.\n\tShutdownCtx context.Context //nolint:containedctx\n\n\t// Zap logger.\n\tLogger *zap.Logger\n\n\tserver *grpc.Server\n}\n\nfunc (s *Server) checkSupported(feature runtime.ModeCapability) error {\n\tmode := s.Controller.Runtime().State().Platform().Mode()\n\n\tif !mode.Supports(feature) {\n\t\treturn status.Errorf(codes.FailedPrecondition, \"method is not supported in %s mode\", mode.String())\n\t}\n\n\treturn nil\n}\n\n// Register implements the factory.Registrator interface.\nfunc (s *Server) Register(obj *grpc.Server) {\n\ts.server = obj\n\n\t// wrap resources with access filter\n\tresourceState := s.Controller.Runtime().State().V1Alpha2().Resources()\n\tresourceState = state.WrapCore(state.Filter(resourceState, resources.AccessPolicy(resourceState)))\n\n\tmachine.RegisterMachineServiceServer(obj, s)\n\tmachine.RegisterImageServiceServer(obj, images.NewService(s.Controller, s.Logger))\n\tmachine.RegisterDebugServiceServer(obj, &debug.Service{})\n\tmachine.RegisterLifecycleServiceServer(obj, lifecycle.NewService(s.Controller.Runtime(), s.Logger))\n\tcluster.RegisterClusterServiceServer(obj, s)\n\tcosiv1alpha1.RegisterStateServer(obj, server.NewState(resourceState))\n\tinspect.RegisterInspectServiceServer(obj, &InspectServer{server: s})\n\tstorage.RegisterStorageServiceServer(obj, &storaged.Server{Controller: s.Controller})\n\ttimeapi.RegisterTimeServiceServer(obj, &TimeServer{ConfigProvider: s.Controller.Runtime()})\n}\n\n// modeWrapper overrides RequiresInstall() based on actual installed status.\ntype modeWrapper struct {\n\truntime.Mode\n\n\tinstalled bool\n}\n\nfunc (m modeWrapper) RequiresInstall() bool {\n\treturn m.Mode.RequiresInstall() && !m.installed\n}\n\n// ApplyConfiguration implements machine.MachineService.\n//\n//nolint:gocyclo,cyclop\nfunc (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfigurationRequest) (*machine.ApplyConfigurationResponse, error) {\n\tif s.Controller.Runtime().State().Platform().Mode().IsAgent() {\n\t\treturn nil, status.Error(codes.Unimplemented, \"API is not implemented in agent mode\")\n\t}\n\n\troles := authz.GetRoles(ctx)\n\tinMaintenance := !s.Controller.Runtime().ConfigCompleteForBoot()\n\n\tif !inMaintenance && !roles.Includes(role.Admin) {\n\t\treturn nil, authz.ErrNotAuthorized\n\t}\n\n\tmode := in.Mode.String()\n\tmodeDetails := \"Applied configuration with a reboot\"\n\tmodeErr := \"\"\n\n\tif in.Mode != machine.ApplyConfigurationRequest_TRY {\n\t\ts.Controller.Runtime().CancelConfigRollbackTimeout()\n\t}\n\n\tcfgProvider, err := configloader.NewFromBytes(in.GetData())\n\tif err != nil {\n\t\treturn nil, status.Error(codes.InvalidArgument, err.Error())\n\t}\n\n\t// as we are not in maintenance mode, the v1alpha1 config should be always present\n\t// in the future we should allow to remove v1alpha1, but for now for better UX we deny\n\t// such requests to avoid confusion\n\tif !inMaintenance && cfgProvider.RawV1Alpha1() == nil {\n\t\treturn nil, status.Error(codes.InvalidArgument, \"the applied machine configuration doesn't contain v1alpha1 config, did you mean to patch the machine config instead?\")\n\t}\n\n\tvalidationMode := modeWrapper{\n\t\tMode:      s.Controller.Runtime().State().Platform().Mode(),\n\t\tinstalled: s.Controller.Runtime().State().Machine().Installed(),\n\t}\n\n\twarnings, err := cfgProvider.Validate(validationMode)\n\tif err != nil {\n\t\treturn nil, status.Error(codes.InvalidArgument, err.Error())\n\t}\n\n\twarningsRuntime, err := cfgProvider.RuntimeValidate(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), validationMode)\n\tif err != nil {\n\t\treturn nil, status.Error(codes.InvalidArgument, err.Error())\n\t}\n\n\twarnings = slices.Concat(warnings, warningsRuntime)\n\n\tif inMaintenance && in.Mode == machine.ApplyConfigurationRequest_REBOOT {\n\t\tin.Mode = machine.ApplyConfigurationRequest_NO_REBOOT\n\t}\n\n\t//nolint:exhaustive\n\tswitch in.Mode {\n\t// --mode=try\n\tcase machine.ApplyConfigurationRequest_TRY:\n\t\tfallthrough\n\t// --mode=no-reboot\n\tcase machine.ApplyConfigurationRequest_NO_REBOOT:\n\t\tif err = s.Controller.Runtime().CanApplyImmediate(cfgProvider); err != nil && !inMaintenance {\n\t\t\treturn nil, status.Error(codes.InvalidArgument, err.Error())\n\t\t}\n\n\t\tmodeDetails = \"Applied configuration without a reboot\"\n\t// --mode=staged\n\tcase machine.ApplyConfigurationRequest_STAGED:\n\t\tmodeDetails = \"Staged configuration to be applied after the next reboot\"\n\t// --mode=auto detect actual update mode\n\tcase machine.ApplyConfigurationRequest_AUTO:\n\t\tif err = s.Controller.Runtime().CanApplyImmediate(cfgProvider); err != nil && !inMaintenance {\n\t\t\tin.Mode = machine.ApplyConfigurationRequest_REBOOT\n\t\t\tmodeDetails = \"Applied configuration with a reboot\"\n\t\t\tmodeErr = \": \" + err.Error()\n\t\t} else {\n\t\t\tin.Mode = machine.ApplyConfigurationRequest_NO_REBOOT\n\t\t\tmodeDetails = \"Applied configuration without a reboot\"\n\t\t}\n\n\t\tmode = fmt.Sprintf(\"%s(%s)\", mode, in.Mode)\n\t}\n\n\tif in.DryRun {\n\t\tdetails, err := generateDiff(s.Controller.Runtime(), cfgProvider)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to generate diff: %w\", err)\n\t\t}\n\n\t\treturn &machine.ApplyConfigurationResponse{\n\t\t\tMessages: []*machine.ApplyConfiguration{\n\t\t\t\t{\n\t\t\t\t\tMode: in.Mode,\n\t\t\t\t\tModeDetails: fmt.Sprintf(`Dry run summary:\n%s (skipped in dry-run).\n%s`, modeDetails, details),\n\t\t\t\t},\n\t\t\t},\n\t\t}, nil\n\t}\n\n\tlog.Printf(\"apply config request: mode %s\", strings.ToLower(mode))\n\n\t//nolint:exhaustive\n\tswitch in.Mode {\n\t// --mode=try\n\tcase machine.ApplyConfigurationRequest_TRY:\n\t\ttimeout := constants.ConfigTryTimeout\n\t\tif in.TryModeTimeout != nil {\n\t\t\ttimeout = in.TryModeTimeout.AsDuration()\n\t\t}\n\n\t\tmodeDetails += fmt.Sprintf(\"\\nThe config is applied in 'try' mode and will be automatically reverted back in %s\", timeout.String())\n\n\t\tif err := s.Controller.Runtime().RollbackToConfigAfter(timeout); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := s.Controller.Runtime().SetConfig(cfgProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t// --mode=no-reboot\n\tcase machine.ApplyConfigurationRequest_NO_REBOOT:\n\t\tif err := s.Controller.Runtime().SetPersistedConfig(cfgProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := s.Controller.Runtime().SetConfig(cfgProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t// --mode=staged\n\tcase machine.ApplyConfigurationRequest_STAGED:\n\t\tif err := s.Controller.Runtime().SetPersistedConfig(cfgProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t// --mode=reboot\n\tcase machine.ApplyConfigurationRequest_REBOOT:\n\t\tif err := s.Controller.Runtime().SetPersistedConfig(cfgProvider); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tgo func() {\n\t\t\tif err := s.Controller.Run(context.Background(), runtime.SequenceReboot, nil, runtime.WithTakeover()); err != nil {\n\t\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\t\tlog.Println(\"apply configuration failed:\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"incorrect mode '%s' specified for the apply config call\", in.Mode.String())\n\t}\n\n\treturn &machine.ApplyConfigurationResponse{\n\t\tMessages: []*machine.ApplyConfiguration{\n\t\t\t{\n\t\t\t\tMode:        in.Mode,\n\t\t\t\tWarnings:    warnings,\n\t\t\t\tModeDetails: modeDetails + modeErr,\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\nfunc generateDiff(r runtime.Runtime, provider config.Provider) (string, error) {\n\tdocumentsDiff, err := configdiff.DiffConfigs(r.ConfigContainer(), provider)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif documentsDiff == \"\" {\n\t\tdocumentsDiff = \"No changes.\"\n\t}\n\n\treturn \"Config diff:\\n\\n\" + documentsDiff, nil\n}\n\n// Reboot implements the machine.MachineServer interface.\nfunc (s *Server) Reboot(ctx context.Context, in *machine.RebootRequest) (reply *machine.RebootResponse, err error) {\n\tactorID := uuid.New().String()\n\n\tlog.Printf(\"reboot via API received. actor id: %s\", actorID)\n\n\tif err := s.checkSupported(runtime.Reboot); err != nil {\n\t\treturn nil, err\n\t}\n\n\trebootCtx := context.WithValue(context.Background(), runtime.ActorIDCtxKey{}, actorID)\n\n\tgo func() {\n\t\tif err := s.Controller.Run(rebootCtx, runtime.SequenceReboot, in); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Println(\"reboot failed:\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\treply = &machine.RebootResponse{\n\t\tMessages: []*machine.Reboot{\n\t\t\t{\n\t\t\t\tActorId: actorID,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Rollback implements the machine.MachineServer interface.\nfunc (s *Server) Rollback(ctx context.Context, in *machine.RollbackRequest) (*machine.RollbackResponse, error) {\n\tlog.Printf(\"rollback via API received\")\n\n\tif err := s.checkSupported(runtime.Rollback); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsystemDisk, err := block.GetSystemDisk(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"system disk lookup failed: %w\", err)\n\t}\n\n\tif systemDisk == nil {\n\t\treturn nil, status.Errorf(codes.FailedPrecondition, \"system disk not found\")\n\t}\n\n\tif err := func() error {\n\t\tconfig, err := bootloader.Probe(systemDisk.DevPath, options.ProbeOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn config.Revert(systemDisk.DevPath)\n\t}(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tgo func() {\n\t\tif err := s.Controller.Run(context.Background(), runtime.SequenceReboot, in, runtime.WithTakeover()); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Println(\"reboot failed:\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn &machine.RollbackResponse{\n\t\tMessages: []*machine.Rollback{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// Bootstrap implements the machine.MachineServer interface.\nfunc (s *Server) Bootstrap(ctx context.Context, in *machine.BootstrapRequest) (reply *machine.BootstrapResponse, err error) {\n\tlog.Printf(\"bootstrap request received\")\n\n\tif !s.Controller.Runtime().IsBootstrapAllowed() {\n\t\treturn nil, status.Error(codes.FailedPrecondition, \"bootstrap is not available yet\")\n\t}\n\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"bootstrap\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttimeCtx, timeCtxCancel := context.WithTimeout(ctx, 5*time.Second)\n\tdefer timeCtxCancel()\n\n\tif err := timeresource.NewSyncCondition(s.Controller.Runtime().State().V1Alpha2().Resources()).Wait(timeCtx); err != nil {\n\t\treturn nil, status.Error(codes.FailedPrecondition, \"time is not in sync yet\")\n\t}\n\n\tif entries, _ := os.ReadDir(constants.EtcdDataPath); len(entries) > 0 { //nolint:errcheck\n\t\treturn nil, status.Error(codes.AlreadyExists, \"etcd data directory is not empty\")\n\t}\n\n\tif err := s.EtcdBootstrapper(ctx, s.Controller.Runtime(), in); err != nil {\n\t\treturn nil, err\n\t}\n\n\treply = &machine.BootstrapResponse{\n\t\tMessages: []*machine.Bootstrap{\n\t\t\t{},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Shutdown implements the machine.MachineServer interface.\nfunc (s *Server) Shutdown(ctx context.Context, in *machine.ShutdownRequest) (reply *machine.ShutdownResponse, err error) {\n\tactorID := uuid.New().String()\n\n\tlog.Printf(\"shutdown via API received. actor id: %s\", actorID)\n\n\tif err = s.checkSupported(runtime.Shutdown); err != nil {\n\t\treturn nil, err\n\t}\n\n\tshutdownCtx := context.WithValue(context.Background(), runtime.ActorIDCtxKey{}, actorID)\n\n\tgo func() {\n\t\tif err := s.Controller.Run(shutdownCtx, runtime.SequenceShutdown, in, runtime.WithTakeover()); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Println(\"shutdown failed:\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\treply = &machine.ShutdownResponse{\n\t\tMessages: []*machine.Shutdown{\n\t\t\t{\n\t\t\t\tActorId: actorID,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Upgrade initiates an upgrade.\n//\n//nolint:gocyclo,cyclop\nfunc (s *Server) Upgrade(ctx context.Context, in *machine.UpgradeRequest) (*machine.UpgradeResponse, error) {\n\tif s.Controller.Runtime().State().Platform().Mode().IsAgent() {\n\t\treturn nil, status.Error(codes.Unimplemented, \"API is not implemented in agent mode\")\n\t}\n\n\tactorID := uuid.New().String()\n\n\tctx = context.WithValue(ctx, runtime.ActorIDCtxKey{}, actorID)\n\n\tif err := s.checkSupported(runtime.Upgrade); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"upgrade request received: staged %v, force %v, reboot mode %v\", in.GetStage(), in.GetForce(), in.GetRebootMode().String())\n\n\tlog.Printf(\"validating %q\", in.GetImage())\n\n\tif err := install.PullAndValidateInstallerImage(\n\t\tctx,\n\t\ts.Controller.Runtime().State().V1Alpha2().Resources(),\n\t\tcrires.RegistryBuilder(s.Controller.Runtime().State().V1Alpha2().Resources()),\n\t\tin.GetImage(),\n\t); err != nil {\n\t\treturn nil, fmt.Errorf(\"error validating installer image %q: %w\", in.GetImage(), err)\n\t}\n\n\tif s.Controller.Runtime().Config().Machine().Type() != machinetype.TypeWorker && !in.GetForce() {\n\t\tetcdClient, err := etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t\t}\n\n\t\t// acquire the upgrade mutex\n\t\tunlocker, err := tryLockUpgradeMutex(ctx, etcdClient)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to acquire upgrade mutex: %w\", err)\n\t\t}\n\n\t\t// unlock the mutex once the API call is done, as it protects only pre-upgrade checks\n\t\tdefer unlocker()\n\n\t\tif err = etcdClient.ValidateForUpgrade(ctx, s.Controller.Runtime().Config()); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error validating etcd for upgrade: %w\", err)\n\t\t}\n\t}\n\n\trunCtx := context.WithValue(context.Background(), runtime.ActorIDCtxKey{}, actorID)\n\n\tif in.GetStage() {\n\t\tif ok, err := s.Controller.Runtime().State().Machine().Meta().SetTag(ctx, meta.StagedUpgradeImageRef, in.GetImage()); !ok || err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error adding staged upgrade image ref tag: %w\", err)\n\t\t}\n\n\t\topts := install.Options{Pull: true} //nolint:staticcheck\n\t\tif err := opts.Apply(install.OptionsFromUpgradeRequest(s.Controller.Runtime(), in)...); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error applying install options: %w\", err)\n\t\t}\n\n\t\tserialized, err := json.Marshal(opts)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error serializing install options: %s\", err)\n\t\t}\n\n\t\tvar ok bool\n\n\t\tif ok, err = s.Controller.Runtime().State().Machine().Meta().SetTag(ctx, meta.StagedUpgradeInstallOptions, string(serialized)); !ok || err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error adding staged upgrade install options tag: %w\", err)\n\t\t}\n\n\t\tif err = s.Controller.Runtime().State().Machine().Meta().Flush(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error writing meta: %w\", err)\n\t\t}\n\n\t\tgo func() {\n\t\t\tif err := s.Controller.Run(runCtx, runtime.SequenceStageUpgrade, in); err != nil {\n\t\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\t\tlog.Println(\"reboot for staged upgrade failed:\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t} else {\n\t\tgo func() {\n\t\t\tif err := s.Controller.Run(runCtx, runtime.SequenceUpgrade, in); err != nil {\n\t\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\t\tlog.Println(\"upgrade failed:\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\treturn &machine.UpgradeResponse{\n\t\tMessages: []*machine.Upgrade{\n\t\t\t{\n\t\t\t\tAck:     \"Upgrade request received\",\n\t\t\t\tActorId: actorID,\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// ResetOptions implements runtime.ResetOptions interface.\ntype ResetOptions struct {\n\t*machine.ResetRequest\n\n\tsystemDiskTargets []*partition.VolumeWipeTarget\n\tsystemDiskPaths   []string\n}\n\n// GetSystemDiskTargets implements runtime.ResetOptions interface.\nfunc (opt *ResetOptions) GetSystemDiskTargets() []runtime.PartitionTarget {\n\tif opt.systemDiskTargets == nil {\n\t\treturn nil\n\t}\n\n\treturn xslices.Map(opt.systemDiskTargets, func(t *partition.VolumeWipeTarget) runtime.PartitionTarget { return t })\n}\n\n// GetSystemDiskPaths implements runtime.ResetOptions interface.\nfunc (opt *ResetOptions) GetSystemDiskPaths() []string {\n\treturn opt.systemDiskPaths\n}\n\n// String implements runtime.ResetOptions interface.\nfunc (opt *ResetOptions) String() string {\n\treturn strings.Join(xslices.Map(opt.systemDiskTargets, func(t *partition.VolumeWipeTarget) string { return t.String() }), \", \")\n}\n\n// Reset resets the node.\n//\n//nolint:gocyclo,cyclop\nfunc (s *Server) Reset(ctx context.Context, in *machine.ResetRequest) (reply *machine.ResetResponse, err error) {\n\tif s.Controller.Runtime().State().Platform().Mode().IsAgent() {\n\t\treturn nil, status.Error(codes.Unimplemented, \"API is not implemented in agent mode\")\n\t}\n\n\tactorID := uuid.New().String()\n\n\tlog.Printf(\"reset request received. actorID: %s\", actorID)\n\n\topts := ResetOptions{\n\t\tResetRequest: in,\n\t}\n\n\tif len(in.GetUserDisksToWipe()) > 0 {\n\t\tif in.Mode == machine.ResetRequest_SYSTEM_DISK {\n\t\t\treturn nil, errors.New(\"reset failed: invalid input, wipe mode SYSTEM_DISK doesn't support UserDisksToWipe parameter\")\n\t\t}\n\n\t\tdiskList, err := safe.StateListAll[*block.Disk](ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"listing disks failed: %w\", err)\n\t\t}\n\n\t\tdisks := xslices.ToMap(\n\t\t\tsafe.ToSlice(diskList, func(d *block.Disk) *block.Disk { return d }),\n\t\t\tfunc(disk *block.Disk) (string, *block.Disk) {\n\t\t\t\treturn disk.TypedSpec().DevPath, disk\n\t\t\t},\n\t\t)\n\n\t\tsystemDisk, err := block.GetSystemDisk(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"system disk lookup failed: %w\", err)\n\t\t}\n\n\t\t// validate input\n\t\tfor _, deviceName := range in.GetUserDisksToWipe() {\n\t\t\tdisk, ok := disks[deviceName]\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"reset user disk failed: device %s wasn't found\", deviceName)\n\t\t\t}\n\n\t\t\tif disk.TypedSpec().Readonly {\n\t\t\t\treturn nil, fmt.Errorf(\"reset user disk failed: device %s is readonly\", deviceName)\n\t\t\t}\n\n\t\t\tif systemDisk != nil && deviceName == systemDisk.DevPath {\n\t\t\t\treturn nil, fmt.Errorf(\"reset user disk failed: device %s is the system disk\", deviceName)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(in.GetSystemPartitionsToWipe()) > 0 {\n\t\tif in.Mode == machine.ResetRequest_USER_DISKS {\n\t\t\treturn nil, errors.New(\"reset failed: invalid input, wipe mode USER_DISKS doesn't support SystemPartitionsToWipe parameter\")\n\t\t}\n\n\t\tfor _, spec := range in.GetSystemPartitionsToWipe() {\n\t\t\tvolumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), spec.Label)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to get volume status with label %q: %w\", spec.Label, err)\n\t\t\t}\n\n\t\t\tif volumeStatus.TypedSpec().Location == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to reset: volume %q is not located\", spec.Label)\n\t\t\t}\n\n\t\t\ttarget := partition.VolumeWipeTargetFromVolumeStatus(volumeStatus)\n\n\t\t\tif spec.Wipe {\n\t\t\t\topts.systemDiskTargets = append(opts.systemDiskTargets, target)\n\t\t\t}\n\t\t}\n\t}\n\n\tif in.Mode != machine.ResetRequest_USER_DISKS && len(in.GetSystemPartitionsToWipe()) == 0 {\n\t\topts.systemDiskPaths, err = block.GetSystemDiskPaths(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"system disk paths lookup failed: %w\", err)\n\t\t}\n\t}\n\n\tresetCtx := context.WithValue(context.Background(), runtime.ActorIDCtxKey{}, actorID)\n\n\tgo func() {\n\t\tif err := s.Controller.Run(resetCtx, runtime.SequenceReset, &opts); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Println(\"reset failed:\", err)\n\t\t\t}\n\t\t}\n\t}()\n\n\treply = &machine.ResetResponse{\n\t\tMessages: []*machine.Reset{\n\t\t\t{\n\t\t\t\tActorId: actorID,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// ServiceList returns list of the registered services and their status.\nfunc (s *Server) ServiceList(ctx context.Context, in *emptypb.Empty) (result *machine.ServiceListResponse, err error) {\n\tservices := system.Services(s.Controller.Runtime()).List()\n\n\tresult = &machine.ServiceListResponse{\n\t\tMessages: []*machine.ServiceList{\n\t\t\t{\n\t\t\t\tServices: xslices.Map(services, (*system.ServiceRunner).AsProto),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn result, nil\n}\n\n// ServiceStart implements the machine.MachineServer interface and starts a\n// service running on Talos.\nfunc (s *Server) ServiceStart(ctx context.Context, in *machine.ServiceStartRequest) (reply *machine.ServiceStartResponse, err error) {\n\tif err = system.Services(s.Controller.Runtime()).APIStart(ctx, in.Id); err != nil {\n\t\treturn &machine.ServiceStartResponse{}, err\n\t}\n\n\treply = &machine.ServiceStartResponse{\n\t\tMessages: []*machine.ServiceStart{\n\t\t\t{\n\t\t\t\tResp: fmt.Sprintf(\"Service %q started\", in.Id),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, err\n}\n\n// ServiceStop implements the machine.MachineServer interface and stops a\n// service running on Talos.\nfunc (s *Server) ServiceStop(ctx context.Context, in *machine.ServiceStopRequest) (reply *machine.ServiceStopResponse, err error) {\n\tif err = system.Services(s.Controller.Runtime()).APIStop(ctx, in.Id); err != nil {\n\t\treturn &machine.ServiceStopResponse{}, err\n\t}\n\n\treply = &machine.ServiceStopResponse{\n\t\tMessages: []*machine.ServiceStop{\n\t\t\t{\n\t\t\t\tResp: fmt.Sprintf(\"Service %q stopped\", in.Id),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, err\n}\n\n// ServiceRestart implements the machine.MachineServer interface and stops a\n// service running on Talos.\nfunc (s *Server) ServiceRestart(ctx context.Context, in *machine.ServiceRestartRequest) (reply *machine.ServiceRestartResponse, err error) {\n\tif err = system.Services(s.Controller.Runtime()).APIRestart(ctx, in.Id); err != nil {\n\t\treturn &machine.ServiceRestartResponse{}, err\n\t}\n\n\treply = &machine.ServiceRestartResponse{\n\t\tMessages: []*machine.ServiceRestart{\n\t\t\t{\n\t\t\t\tResp: fmt.Sprintf(\"Service %q restarted\", in.Id),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, err\n}\n\n// Copy implements the machine.MachineServer interface and copies data out of Talos node.\nfunc (s *Server) Copy(req *machine.CopyRequest, obj machine.MachineService_CopyServer) error {\n\tpath := req.RootPath\n\tpath = filepath.Clean(path)\n\n\tif !filepath.IsAbs(path) {\n\t\treturn fmt.Errorf(\"path is not absolute %v\", path)\n\t}\n\n\tpr, pw := io.Pipe()\n\n\terrCh := make(chan error, 1)\n\n\tctx, ctxCancel := context.WithCancel(obj.Context())\n\tdefer ctxCancel()\n\n\tgo func() {\n\t\t//nolint:errcheck\n\t\tdefer pw.Close()\n\n\t\terrCh <- archiver.TarGz(ctx, path, pw)\n\t}()\n\n\tchunker := stream.NewChunker(ctx, pr)\n\tchunkCh := chunker.Read()\n\n\tfor data := range chunkCh {\n\t\terr := obj.SendMsg(&common.Data{Bytes: data})\n\t\tif err != nil {\n\t\t\tctxCancel()\n\t\t}\n\t}\n\n\tarchiveErr := <-errCh\n\tif archiveErr != nil {\n\t\treturn obj.SendMsg(&common.Data{\n\t\t\tMetadata: &common.Metadata{\n\t\t\t\tError: archiveErr.Error(),\n\t\t\t},\n\t\t})\n\t}\n\n\treturn nil\n}\n\n// List implements the machine.MachineServer interface.\n//\n//nolint:gocyclo,cyclop\nfunc (s *Server) List(req *machine.ListRequest, obj machine.MachineService_ListServer) error {\n\tif req == nil {\n\t\treq = new(machine.ListRequest)\n\t}\n\n\tif !strings.HasPrefix(req.Root, OSPathSeparator) {\n\t\t// Make sure we use complete paths\n\t\treq.Root = OSPathSeparator + req.Root\n\t}\n\n\treq.Root = strings.TrimSuffix(req.Root, OSPathSeparator)\n\tif req.Root == \"\" {\n\t\treq.Root = \"/\"\n\t}\n\n\tvar recursionDepth int\n\n\tif req.Recurse {\n\t\tif req.RecursionDepth == 0 {\n\t\t\trecursionDepth = -1\n\t\t} else {\n\t\t\trecursionDepth = int(req.RecursionDepth)\n\t\t}\n\t}\n\n\topts := []archiver.WalkerOption{\n\t\tarchiver.WithMaxRecurseDepth(recursionDepth),\n\t}\n\n\tif len(req.Types) > 0 {\n\t\ttypes := make([]archiver.FileType, 0, len(req.Types))\n\n\t\tfor _, t := range req.Types {\n\t\t\tswitch t {\n\t\t\tcase machine.ListRequest_REGULAR:\n\t\t\t\ttypes = append(types, archiver.RegularFileType)\n\t\t\tcase machine.ListRequest_DIRECTORY:\n\t\t\t\ttypes = append(types, archiver.DirectoryFileType)\n\t\t\tcase machine.ListRequest_SYMLINK:\n\t\t\t\ttypes = append(types, archiver.SymlinkFileType)\n\t\t\t}\n\t\t}\n\n\t\topts = append(opts, archiver.WithFileTypes(types...))\n\t}\n\n\tfiles, err := archiver.Walker(obj.Context(), req.Root, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor fi := range files {\n\t\txattrs := []*machine.Xattr{}\n\n\t\tif req.ReportXattrs {\n\t\t\t// On filesystems such as devtmpfs and sysfs, xattrs are not supported.\n\t\t\t// However, we can still get the label from the security.selinux xattr for automatic labels.\n\t\t\tfoundSelinux := false\n\n\t\t\tif list, err := xattr.List(fi.FullPath); err == nil {\n\t\t\t\tfor _, attr := range list {\n\t\t\t\t\tif data, err := xattr.Get(fi.FullPath, attr); err == nil {\n\t\t\t\t\t\tif attr == \"security.selinux\" {\n\t\t\t\t\t\t\tfoundSelinux = true\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\txattrs = append(xattrs, &machine.Xattr{Name: attr, Data: data})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !foundSelinux {\n\t\t\t\tif data, err := xattr.Get(fi.FullPath, \"security.selinux\"); err == nil {\n\t\t\t\t\txattrs = append(xattrs, &machine.Xattr{Name: \"security.selinux\", Data: data})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif fi.Error != nil {\n\t\t\terr = obj.Send(&machine.FileInfo{\n\t\t\t\tName:         fi.FullPath,\n\t\t\t\tRelativeName: fi.RelPath,\n\t\t\t\tError:        fi.Error.Error(),\n\t\t\t\tXattrs:       xattrs,\n\t\t\t})\n\t\t} else {\n\t\t\terr = obj.Send(&machine.FileInfo{\n\t\t\t\tName:         fi.FullPath,\n\t\t\t\tRelativeName: fi.RelPath,\n\t\t\t\tSize:         fi.FileInfo.Size(),\n\t\t\t\tMode:         uint32(fi.FileInfo.Mode()),\n\t\t\t\tModified:     fi.FileInfo.ModTime().Unix(),\n\t\t\t\tIsDir:        fi.FileInfo.IsDir(),\n\t\t\t\tLink:         fi.Link,\n\t\t\t\tUid:          fi.FileInfo.Sys().(*syscall.Stat_t).Uid,\n\t\t\t\tGid:          fi.FileInfo.Sys().(*syscall.Stat_t).Gid,\n\t\t\t\tXattrs:       xattrs,\n\t\t\t})\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// DiskUsage implements the machine.MachineServer interface.\n//\n//nolint:cyclop\nfunc (s *Server) DiskUsage(req *machine.DiskUsageRequest, obj machine.MachineService_DiskUsageServer) error { //nolint:gocyclo\n\tif req == nil {\n\t\treq = new(machine.DiskUsageRequest)\n\t}\n\n\tfor _, path := range req.Paths {\n\t\tif !strings.HasPrefix(path, OSPathSeparator) {\n\t\t\t// Make sure we use complete paths\n\t\t\tpath = OSPathSeparator + path\n\t\t}\n\n\t\tpath = strings.TrimSuffix(path, OSPathSeparator)\n\t\tif path == \"\" {\n\t\t\tpath = \"/\"\n\t\t}\n\n\t\t_, err := os.Stat(path)\n\t\tif err == os.ErrNotExist {\n\t\t\terr = obj.Send(\n\t\t\t\t&machine.DiskUsageInfo{\n\t\t\t\t\tName:         path,\n\t\t\t\t\tRelativeName: path,\n\t\t\t\t\tError:        err.Error(),\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tfiles, err := archiver.Walker(obj.Context(), path, archiver.WithMaxRecurseDepth(-1))\n\t\tif err != nil {\n\t\t\terr = obj.Send(\n\t\t\t\t&machine.DiskUsageInfo{\n\t\t\t\t\tName:         path,\n\t\t\t\t\tRelativeName: path,\n\t\t\t\t\tError:        err.Error(),\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tfolders := map[string]*machine.DiskUsageInfo{}\n\n\t\t// send a record back to client if the message shouldn't be skipped\n\t\t// at the same time use record information for folder size estimation\n\t\tsendSize := func(info *machine.DiskUsageInfo, depth int32, isDir bool) error {\n\t\t\tprefix := strings.TrimRight(filepath.Dir(info.Name), \"/\")\n\t\t\tif folder, ok := folders[prefix]; ok {\n\t\t\t\tfolder.Size += info.Size\n\t\t\t}\n\n\t\t\t// recursion depth check\n\t\t\tskip := depth >= req.RecursionDepth && req.RecursionDepth > 0\n\t\t\t// skip files check\n\t\t\tskip = skip || !isDir && !req.All\n\t\t\t// threshold check\n\t\t\tskip = skip || req.Threshold > 0 && info.Size < req.Threshold\n\t\t\tskip = skip || req.Threshold < 0 && info.Size > -req.Threshold\n\n\t\t\tif skip {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn obj.Send(info)\n\t\t}\n\n\t\tvar (\n\t\t\tdepth     int32\n\t\t\tprefix    = path\n\t\t\trootDepth = int32(strings.Count(path, archiver.OSPathSeparator))\n\t\t)\n\n\t\t// flush all folder sizes until we get to the common prefix\n\t\tflushFolders := func(prefix, nextPrefix string) error {\n\t\t\tfor !strings.HasPrefix(nextPrefix, prefix) {\n\t\t\t\tcurrentDepth := int32(strings.Count(prefix, archiver.OSPathSeparator)) - rootDepth\n\n\t\t\t\tif folder, ok := folders[prefix]; ok {\n\t\t\t\t\terr = sendSize(folder, currentDepth, true)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tdelete(folders, prefix)\n\t\t\t\t}\n\n\t\t\t\tprefix = strings.TrimRight(filepath.Dir(prefix), \"/\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tfor fi := range files {\n\t\t\tif fi.Error != nil {\n\t\t\t\terr = obj.Send(\n\t\t\t\t\t&machine.DiskUsageInfo{\n\t\t\t\t\t\tName:         fi.FullPath,\n\t\t\t\t\t\tRelativeName: fi.RelPath,\n\t\t\t\t\t\tError:        fi.Error.Error(),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tcurrentDepth := int32(strings.Count(fi.FullPath, archiver.OSPathSeparator)) - rootDepth\n\n\t\t\t\tsize := max(fi.FileInfo.Size(), 0)\n\n\t\t\t\t// kcore file size gives wrong value, this code should be smarter when it reads it\n\t\t\t\t// TODO: figure out better way to skip such file\n\t\t\t\tif fi.FullPath == \"/proc/kcore\" {\n\t\t\t\t\tsize = 0\n\t\t\t\t}\n\n\t\t\t\tif fi.FileInfo.IsDir() {\n\t\t\t\t\tfolders[strings.TrimRight(fi.FullPath, \"/\")] = &machine.DiskUsageInfo{\n\t\t\t\t\t\tName:         fi.FullPath,\n\t\t\t\t\t\tRelativeName: fi.RelPath,\n\t\t\t\t\t\tSize:         size,\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\terr = sendSize(&machine.DiskUsageInfo{\n\t\t\t\t\t\tName:         fi.FullPath,\n\t\t\t\t\t\tRelativeName: fi.RelPath,\n\t\t\t\t\t\tSize:         size,\n\t\t\t\t\t}, currentDepth, false)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// depth goes down when walker gets to the next sibling folder\n\t\t\t\tif currentDepth < depth {\n\t\t\t\t\tnextPrefix := fi.FullPath\n\n\t\t\t\t\tif err = flushFolders(prefix, nextPrefix); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tprefix = nextPrefix\n\t\t\t\t}\n\n\t\t\t\tif fi.FileInfo.IsDir() {\n\t\t\t\t\tprefix = fi.FullPath\n\t\t\t\t}\n\n\t\t\t\tdepth = currentDepth\n\t\t\t}\n\t\t}\n\n\t\tif path != \"\" {\n\t\t\tp := strings.TrimRight(path, \"/\")\n\t\t\tif folder, ok := folders[p]; ok {\n\t\t\t\terr = flushFolders(prefix, p)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\terr = sendSize(folder, 0, true)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn nil\n}\n\n// Mounts implements the machine.MachineServer interface.\nfunc (s *Server) Mounts(ctx context.Context, in *emptypb.Empty) (reply *machine.MountsResponse, err error) {\n\tfile, err := os.Open(\"/proc/mounts\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t//nolint:errcheck\n\tdefer file.Close()\n\n\tvar (\n\t\tstat     unix.Statfs_t\n\t\tmultiErr *multierror.Error\n\t)\n\n\tvar stats []*machine.MountStat\n\n\tscanner := bufio.NewScanner(file)\n\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilesystem := fields[0]\n\t\tmountpoint := fields[1]\n\n\t\tvar (\n\t\t\ttotalSize  uint64\n\t\t\ttotalAvail uint64\n\t\t)\n\n\t\tif statInfo, err := os.Stat(mountpoint); err == nil && statInfo.Mode().IsDir() {\n\t\t\tif err := unix.Statfs(mountpoint, &stat); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t} else {\n\t\t\t\ttotalSize = uint64(stat.Bsize) * stat.Blocks\n\t\t\t\ttotalAvail = uint64(stat.Bsize) * stat.Bavail\n\t\t\t}\n\t\t}\n\n\t\tstat := &machine.MountStat{\n\t\t\tFilesystem: filesystem,\n\t\t\tSize:       totalSize,\n\t\t\tAvailable:  totalAvail,\n\t\t\tMountedOn:  mountpoint,\n\t\t}\n\n\t\tstats = append(stats, stat)\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\treply = &machine.MountsResponse{\n\t\tMessages: []*machine.Mounts{\n\t\t\t{\n\t\t\t\tStats: stats,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, multiErr.ErrorOrNil()\n}\n\n// Version implements the machine.MachineServer interface.\nfunc (s *Server) Version(ctx context.Context, in *emptypb.Empty) (reply *machine.VersionResponse, err error) {\n\tvar platform *machine.PlatformInfo\n\n\tif s.Controller.Runtime().State().Platform() != nil {\n\t\tplatform = &machine.PlatformInfo{\n\t\t\tName: s.Controller.Runtime().State().Platform().Name(),\n\t\t\tMode: s.Controller.Runtime().State().Platform().Mode().String(),\n\t\t}\n\t}\n\n\tvar features *machine.FeaturesInfo\n\n\tconfig := s.Controller.Runtime().Config()\n\tif config != nil && config.Machine() != nil {\n\t\tfeatures = &machine.FeaturesInfo{\n\t\t\tRbac: true,\n\t\t}\n\t}\n\n\treturn &machine.VersionResponse{\n\t\tMessages: []*machine.Version{\n\t\t\t{\n\t\t\t\tVersion:  version.NewVersion(),\n\t\t\t\tPlatform: platform,\n\t\t\t\tFeatures: features,\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// Kubeconfig implements the machine.MachineServer interface.\nfunc (s *Server) Kubeconfig(empty *emptypb.Empty, obj machine.MachineService_KubeconfigServer) error {\n\tif err := machinehelper.CheckControlplane(obj.Context(), s.Controller.Runtime().State().V1Alpha2().Resources(), \"kubeconfig\"); err != nil {\n\t\treturn err\n\t}\n\n\tvar b bytes.Buffer\n\n\tif err := kubeconfig.GenerateAdmin(s.Controller.Runtime().Config().Cluster(), &b); err != nil {\n\t\treturn err\n\t}\n\n\t// wrap in .tar.gz to match Copy protocol\n\tvar buf bytes.Buffer\n\n\tzw := gzip.NewWriter(&buf)\n\n\ttarW := tar.NewWriter(zw)\n\n\terr := tarW.WriteHeader(&tar.Header{\n\t\tTypeflag: tar.TypeReg,\n\t\tName:     \"kubeconfig\",\n\t\tSize:     int64(b.Len()),\n\t\tModTime:  time.Now(),\n\t\tMode:     0o600,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = io.Copy(tarW, &b)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = zw.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn obj.Send(&common.Data{\n\t\tBytes: buf.Bytes(),\n\t})\n}\n\n// Logs provides a service or container logs can be requested and the contents of the\n// log file are streamed in chunks.\nfunc (s *Server) Logs(req *machine.LogsRequest, l machine.MachineService_LogsServer) (err error) {\n\tvar chunk chunker.Chunker\n\n\tswitch {\n\tcase req.Namespace == constants.SystemContainerdNamespace || req.Id == \"kubelet\":\n\t\tvar options []runtime.LogOption\n\n\t\tif req.Follow {\n\t\t\toptions = append(options, runtime.WithFollow())\n\t\t}\n\n\t\tif req.TailLines >= 0 {\n\t\t\toptions = append(options, runtime.WithTailLines(int(req.TailLines)))\n\t\t}\n\n\t\tvar logR io.ReadCloser\n\n\t\tlogR, err = s.Controller.Runtime().Logging().ServiceLog(req.Id).Reader(options...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t//nolint:errcheck\n\t\tdefer logR.Close()\n\n\t\tchunk = stream.NewChunker(l.Context(), logR)\n\tdefault:\n\t\tvar file io.Closer\n\n\t\tif chunk, file, err = k8slogs(l.Context(), req); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t//nolint:errcheck\n\t\tdefer file.Close()\n\t}\n\n\tfor data := range chunk.Read() {\n\t\tif err = l.Send(&common.Data{Bytes: data}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// LogsContainers provide a list of registered log containers.\nfunc (s *Server) LogsContainers(context.Context, *emptypb.Empty) (*machine.LogsContainersResponse, error) {\n\treturn &machine.LogsContainersResponse{\n\t\tMessages: []*machine.LogsContainer{\n\t\t\t{\n\t\t\t\tIds: s.Controller.Runtime().Logging().RegisteredLogs(),\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\nfunc k8slogs(ctx context.Context, req *machine.LogsRequest) (chunker.Chunker, io.Closer, error) {\n\tinspector, err := getContainerInspector(ctx, req.Namespace, req.Driver)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\t//nolint:errcheck\n\tdefer inspector.Close()\n\n\tcontainer, err := inspector.Container(req.Id)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif container == nil {\n\t\treturn nil, nil, fmt.Errorf(\"container %q not found\", req.Id)\n\t}\n\n\treturn container.GetLogChunker(ctx, req.Follow, int(req.TailLines))\n}\n\nfunc getContainerInspector(ctx context.Context, namespace string, driver common.ContainerDriver) (containers.Inspector, error) {\n\tswitch driver {\n\tcase common.ContainerDriver_CRI:\n\t\tif namespace != constants.K8sContainerdNamespace {\n\t\t\treturn nil, errors.New(\"CRI inspector is supported only for K8s namespace\")\n\t\t}\n\n\t\treturn cri.NewInspector(ctx)\n\tcase common.ContainerDriver_CONTAINERD:\n\t\taddr := constants.CRIContainerdAddress\n\t\tif namespace == constants.SystemContainerdNamespace {\n\t\t\taddr = constants.SystemContainerdAddress\n\t\t}\n\n\t\treturn taloscontainerd.NewInspector(ctx, namespace, taloscontainerd.WithContainerdAddress(addr))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported driver %q\", driver)\n\t}\n}\n\n// Read implements the read API.\nfunc (s *Server) Read(in *machine.ReadRequest, srv machine.MachineService_ReadServer) (err error) {\n\tstat, err := os.Stat(in.Path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn status.Error(codes.NotFound, err.Error())\n\t\t}\n\n\t\treturn err\n\t}\n\n\tswitch mode := stat.Mode(); {\n\tcase mode.IsRegular():\n\t\tf, err := os.OpenFile(in.Path, os.O_RDONLY, 0)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tctx, cancel := context.WithCancel(srv.Context())\n\t\tdefer cancel()\n\n\t\tchunker := stream.NewChunker(ctx, f)\n\t\tchunkCh := chunker.Read()\n\n\t\tfor data := range chunkCh {\n\t\t\terr := srv.SendMsg(&common.Data{Bytes: data})\n\t\t\tif err != nil {\n\t\t\t\tcancel()\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\treturn errors.New(\"path must be a regular file\")\n\t}\n}\n\n// Events streams runtime events.\n//\n//nolint:gocyclo\nfunc (s *Server) Events(req *machine.EventsRequest, l machine.MachineService_EventsServer) error {\n\t// send an empty (hello) event to indicate to client that streaming has started\n\terr := sendEmptyEvent(req, l)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terrCh := make(chan error)\n\n\tvar opts []runtime.WatchOptionFunc\n\n\tif req.TailEvents != 0 {\n\t\topts = append(opts, runtime.WithTailEvents(int(req.TailEvents)))\n\t}\n\n\tif req.TailId != \"\" {\n\t\ttailID, err := xid.FromString(req.TailId)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing tail_id: %w\", err)\n\t\t}\n\n\t\topts = append(opts, runtime.WithTailID(tailID))\n\t}\n\n\tif req.TailSeconds != 0 {\n\t\topts = append(opts, runtime.WithTailDuration(time.Duration(req.TailSeconds)*time.Second))\n\t}\n\n\tif req.WithActorId != \"\" {\n\t\topts = append(opts, runtime.WithActorID(req.WithActorId))\n\t}\n\n\tif err := s.Controller.Runtime().Events().Watch(func(events <-chan runtime.EventInfo) {\n\t\terrCh <- func() error {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-s.ShutdownCtx.Done():\n\t\t\t\t\treturn nil\n\t\t\t\tcase <-l.Context().Done():\n\t\t\t\t\treturn l.Context().Err()\n\t\t\t\tcase event, ok := <-events:\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\tmsg, err := event.ToMachineEvent()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tif err = l.Send(msg); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}, opts...); err != nil {\n\t\treturn err\n\t}\n\n\treturn <-errCh\n}\n\nfunc sendEmptyEvent(req *machine.EventsRequest, l machine.MachineService_EventsServer) error {\n\temptyEvent, err := new(runtime.NewEvent(nil, req.WithActorId)).ToMachineEvent()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn l.Send(emptyEvent)\n}\n\n// Containers implements the machine.MachineServer interface.\nfunc (s *Server) Containers(ctx context.Context, in *machine.ContainersRequest) (reply *machine.ContainersResponse, err error) {\n\tinspector, err := getContainerInspector(ctx, in.Namespace, in.Driver)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t//nolint:errcheck\n\tdefer inspector.Close()\n\n\tpods, err := inspector.Pods()\n\tif err != nil {\n\t\t// fatal error\n\t\tif pods == nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// TODO: only some failed, need to handle it better via client\n\t\tlog.Println(err.Error())\n\t}\n\n\tvar containers []*machine.ContainerInfo\n\n\tfor _, pod := range pods {\n\t\tfor _, container := range pod.Containers {\n\t\t\tcontainer := &machine.ContainerInfo{\n\t\t\t\tNamespace:        in.Namespace,\n\t\t\t\tId:               container.Display,\n\t\t\t\tInternalId:       container.ID,\n\t\t\t\tUid:              container.UID,\n\t\t\t\tPodId:            pod.Name,\n\t\t\t\tName:             container.Name,\n\t\t\t\tImage:            container.Image,\n\t\t\t\tPid:              container.Pid,\n\t\t\t\tStatus:           container.Status,\n\t\t\t\tNetworkNamespace: container.NetworkNamespace,\n\t\t\t}\n\t\t\tcontainers = append(containers, container)\n\t\t}\n\t}\n\n\treply = &machine.ContainersResponse{\n\t\tMessages: []*machine.Container{\n\t\t\t{\n\t\t\t\tContainers: containers,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Stats implements the machine.MachineServer interface.\nfunc (s *Server) Stats(ctx context.Context, in *machine.StatsRequest) (reply *machine.StatsResponse, err error) {\n\tinspector, err := getContainerInspector(ctx, in.Namespace, in.Driver)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t//nolint:errcheck\n\tdefer inspector.Close()\n\n\tpods, err := inspector.Pods()\n\tif err != nil {\n\t\t// fatal error\n\t\tif pods == nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// TODO: only some failed, need to handle it better via client\n\t\tlog.Println(err.Error())\n\t}\n\n\tvar stats []*machine.Stat\n\n\tfor _, pod := range pods {\n\t\tfor _, container := range pod.Containers {\n\t\t\tif container.Metrics == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstat := &machine.Stat{\n\t\t\t\tNamespace:   in.Namespace,\n\t\t\t\tId:          container.Display,\n\t\t\t\tPodId:       pod.Name,\n\t\t\t\tName:        container.Name,\n\t\t\t\tMemoryUsage: container.Metrics.MemoryUsage,\n\t\t\t\tCpuUsage:    container.Metrics.CPUUsage,\n\t\t\t}\n\n\t\t\tstats = append(stats, stat)\n\t\t}\n\t}\n\n\treply = &machine.StatsResponse{\n\t\tMessages: []*machine.Stats{\n\t\t\t{\n\t\t\t\tStats: stats,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Restart implements the machine.MachineServer interface.\nfunc (s *Server) Restart(ctx context.Context, in *machine.RestartRequest) (*machine.RestartResponse, error) {\n\tinspector, err := getContainerInspector(ctx, in.Namespace, in.Driver)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t//nolint:errcheck\n\tdefer inspector.Close()\n\n\tcontainer, err := inspector.Container(in.Id)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif container == nil {\n\t\treturn nil, fmt.Errorf(\"container %q not found\", in.Id)\n\t}\n\n\terr = container.Kill(syscall.SIGTERM)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &machine.RestartResponse{\n\t\tMessages: []*machine.Restart{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// Dmesg implements the machine.MachineServer interface.\n//\n//nolint:gocyclo\nfunc (s *Server) Dmesg(req *machine.DmesgRequest, srv machine.MachineService_DmesgServer) error {\n\tctx := srv.Context()\n\n\tvar options []kmsg.Option\n\n\tif req.Follow {\n\t\toptions = append(options, kmsg.Follow())\n\t}\n\n\tif req.Tail {\n\t\toptions = append(options, kmsg.FromTail())\n\t}\n\n\treader, err := kmsg.NewReader(options...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening /dev/kmsg reader: %w\", err)\n\t}\n\tdefer reader.Close() //nolint:errcheck\n\n\tch := reader.Scan(ctx)\n\n\tfor {\n\t\tselect {\n\t\tcase <-s.ShutdownCtx.Done():\n\t\t\tif err = reader.Close(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\tif err = reader.Close(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase packet, ok := <-ch:\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif packet.Err != nil {\n\t\t\t\terr = srv.Send(&common.Data{\n\t\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\t\tError: packet.Err.Error(),\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tmsg := packet.Message\n\t\t\t\terr = srv.Send(&common.Data{\n\t\t\t\t\tBytes: fmt.Appendf(nil, \"%s: %7s: [%s]: %s\", msg.Facility, msg.Priority, msg.Timestamp.Format(time.RFC3339Nano), msg.Message),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Processes implements the machine.MachineServer interface.\nfunc (s *Server) Processes(ctx context.Context, in *emptypb.Empty) (reply *machine.ProcessesResponse, err error) {\n\tvar processes []*machine.ProcessInfo\n\n\tprocs, err := miniprocfs.NewProcesses()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor {\n\t\tinfo, err := procs.Next()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif info == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tprocesses = append(processes, info)\n\t}\n\n\treply = &machine.ProcessesResponse{\n\t\tMessages: []*machine.Process{\n\t\t\t{\n\t\t\t\tProcesses: processes,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// Memory implements the machine.MachineServer interface.\nfunc (s *Server) Memory(ctx context.Context, in *emptypb.Empty) (reply *machine.MemoryResponse, err error) {\n\tproc, err := procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinfo, err := proc.Meminfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeminfo := &machine.MemInfo{\n\t\tMemtotal:          pointer.SafeDeref(info.MemTotal),\n\t\tMemfree:           pointer.SafeDeref(info.MemFree),\n\t\tMemavailable:      pointer.SafeDeref(info.MemAvailable),\n\t\tBuffers:           pointer.SafeDeref(info.Buffers),\n\t\tCached:            pointer.SafeDeref(info.Cached),\n\t\tSwapcached:        pointer.SafeDeref(info.SwapCached),\n\t\tActive:            pointer.SafeDeref(info.Active),\n\t\tInactive:          pointer.SafeDeref(info.Inactive),\n\t\tActiveanon:        pointer.SafeDeref(info.ActiveAnon),\n\t\tInactiveanon:      pointer.SafeDeref(info.InactiveAnon),\n\t\tActivefile:        pointer.SafeDeref(info.ActiveFile),\n\t\tInactivefile:      pointer.SafeDeref(info.InactiveFile),\n\t\tUnevictable:       pointer.SafeDeref(info.Unevictable),\n\t\tMlocked:           pointer.SafeDeref(info.Mlocked),\n\t\tSwaptotal:         pointer.SafeDeref(info.SwapTotal),\n\t\tSwapfree:          pointer.SafeDeref(info.SwapFree),\n\t\tDirty:             pointer.SafeDeref(info.Dirty),\n\t\tWriteback:         pointer.SafeDeref(info.Writeback),\n\t\tAnonpages:         pointer.SafeDeref(info.AnonPages),\n\t\tMapped:            pointer.SafeDeref(info.Mapped),\n\t\tShmem:             pointer.SafeDeref(info.Shmem),\n\t\tSlab:              pointer.SafeDeref(info.Slab),\n\t\tSreclaimable:      pointer.SafeDeref(info.SReclaimable),\n\t\tSunreclaim:        pointer.SafeDeref(info.SUnreclaim),\n\t\tKernelstack:       pointer.SafeDeref(info.KernelStack),\n\t\tPagetables:        pointer.SafeDeref(info.PageTables),\n\t\tNfsunstable:       pointer.SafeDeref(info.NFSUnstable),\n\t\tBounce:            pointer.SafeDeref(info.Bounce),\n\t\tWritebacktmp:      pointer.SafeDeref(info.WritebackTmp),\n\t\tCommitlimit:       pointer.SafeDeref(info.CommitLimit),\n\t\tCommittedas:       pointer.SafeDeref(info.CommittedAS),\n\t\tVmalloctotal:      pointer.SafeDeref(info.VmallocTotal),\n\t\tVmallocused:       pointer.SafeDeref(info.VmallocUsed),\n\t\tVmallocchunk:      pointer.SafeDeref(info.VmallocChunk),\n\t\tHardwarecorrupted: pointer.SafeDeref(info.HardwareCorrupted),\n\t\tAnonhugepages:     pointer.SafeDeref(info.AnonHugePages),\n\t\tShmemhugepages:    pointer.SafeDeref(info.ShmemHugePages),\n\t\tShmempmdmapped:    pointer.SafeDeref(info.ShmemPmdMapped),\n\t\tCmatotal:          pointer.SafeDeref(info.CmaTotal),\n\t\tCmafree:           pointer.SafeDeref(info.CmaFree),\n\t\tHugepagestotal:    pointer.SafeDeref(info.HugePagesTotal),\n\t\tHugepagesfree:     pointer.SafeDeref(info.HugePagesFree),\n\t\tHugepagesrsvd:     pointer.SafeDeref(info.HugePagesRsvd),\n\t\tHugepagessurp:     pointer.SafeDeref(info.HugePagesSurp),\n\t\tHugepagesize:      pointer.SafeDeref(info.Hugepagesize),\n\t\tDirectmap4K:       pointer.SafeDeref(info.DirectMap4k),\n\t\tDirectmap2M:       pointer.SafeDeref(info.DirectMap2M),\n\t\tDirectmap1G:       pointer.SafeDeref(info.DirectMap1G),\n\t}\n\n\treply = &machine.MemoryResponse{\n\t\tMessages: []*machine.Memory{\n\t\t\t{\n\t\t\t\tMeminfo: meminfo,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, err\n}\n\n// EtcdMemberList implements the machine.MachineServer interface.\nfunc (s *Server) EtcdMemberList(ctx context.Context, in *machine.EtcdMemberListRequest) (*machine.EtcdMemberListResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"member list\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar (\n\t\tclient *etcd.Client\n\t\terr    error\n\t)\n\n\tif in.QueryLocal {\n\t\tclient, err = etcd.NewLocalClient(ctx)\n\t} else {\n\t\tclient, err = etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tctx = clientv3.WithRequireLeader(ctx)\n\n\tresp, err := client.MemberList(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &machine.EtcdMemberListResponse{\n\t\tMessages: []*machine.EtcdMembers{\n\t\t\t{\n\t\t\t\tLegacyMembers: xslices.Map(resp.Members, (*etcdserverpb.Member).GetName),\n\t\t\t\tMembers: xslices.Map(resp.Members, func(member *etcdserverpb.Member) *machine.EtcdMember {\n\t\t\t\t\treturn &machine.EtcdMember{\n\t\t\t\t\t\tId:         member.GetID(),\n\t\t\t\t\t\tHostname:   member.GetName(),\n\t\t\t\t\t\tPeerUrls:   member.GetPeerURLs(),\n\t\t\t\t\t\tClientUrls: member.GetClientURLs(),\n\t\t\t\t\t\tIsLearner:  member.GetIsLearner(),\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdRemoveMemberByID implements the machine.MachineServer interface.\nfunc (s *Server) EtcdRemoveMemberByID(ctx context.Context, in *machine.EtcdRemoveMemberByIDRequest) (*machine.EtcdRemoveMemberByIDResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd remove member\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tctx = clientv3.WithRequireLeader(ctx)\n\n\tif err = client.RemoveMemberByMemberID(ctx, in.MemberId); err != nil {\n\t\tif errors.Is(err, rpctypes.ErrMemberNotFound) {\n\t\t\treturn nil, status.Error(codes.NotFound, err.Error())\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to remove member: %w\", err)\n\t}\n\n\treturn &machine.EtcdRemoveMemberByIDResponse{\n\t\tMessages: []*machine.EtcdRemoveMemberByID{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// EtcdLeaveCluster implements the machine.MachineServer interface.\nfunc (s *Server) EtcdLeaveCluster(ctx context.Context, in *machine.EtcdLeaveClusterRequest) (*machine.EtcdLeaveClusterResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd leave\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tctx = clientv3.WithRequireLeader(ctx)\n\n\tif err = client.LeaveCluster(ctx, s.Controller.Runtime().State().V1Alpha2().Resources()); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to leave cluster: %w\", err)\n\t}\n\n\treturn &machine.EtcdLeaveClusterResponse{\n\t\tMessages: []*machine.EtcdLeaveCluster{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// EtcdForfeitLeadership implements the machine.MachineServer interface.\nfunc (s *Server) EtcdForfeitLeadership(ctx context.Context, in *machine.EtcdForfeitLeadershipRequest) (*machine.EtcdForfeitLeadershipResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd forfeit leadership\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewClientFromControlPlaneIPs(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tctx = clientv3.WithRequireLeader(ctx)\n\n\tmemberID, err := etcd.GetLocalMemberID(ctx, s.Controller.Runtime().State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tleader, err := client.ForfeitLeadership(ctx, etcdresource.FormatMemberID(memberID))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to forfeit leadership: %w\", err)\n\t}\n\n\treturn &machine.EtcdForfeitLeadershipResponse{\n\t\tMessages: []*machine.EtcdForfeitLeadership{\n\t\t\t{\n\t\t\t\tMember: leader,\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdSnapshot implements the machine.MachineServer interface.\nfunc (s *Server) EtcdSnapshot(in *machine.EtcdSnapshotRequest, srv machine.MachineService_EtcdSnapshotServer) error {\n\tif err := machinehelper.CheckControlplane(srv.Context(), s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd snapshot\"); err != nil {\n\t\treturn err\n\t}\n\n\tctx, cancel := context.WithCancel(srv.Context())\n\tdefer cancel()\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\trd, err := client.Snapshot(srv.Context())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed reading etcd snapshot: %w\", err)\n\t}\n\n\tchunker := stream.NewChunker(ctx, rd)\n\tchunkCh := chunker.Read()\n\n\tfor data := range chunkCh {\n\t\terr := srv.SendMsg(&common.Data{Bytes: data})\n\t\tif err != nil {\n\t\t\tcancel()\n\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// EtcdRecover implements the machine.MachineServer interface.\n//\n//nolint:gocyclo\nfunc (s *Server) EtcdRecover(srv machine.MachineService_EtcdRecoverServer) error {\n\tif _, err := os.Stat(filepath.Dir(constants.EtcdRecoverySnapshotPath)); err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn status.Error(codes.FailedPrecondition, \"etcd service is not ready for recovery yet\")\n\t\t}\n\n\t\treturn err\n\t}\n\n\tif err := machinehelper.CheckControlplane(srv.Context(), s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd recover\"); err != nil {\n\t\treturn err\n\t}\n\n\tsnapshot, err := os.OpenFile(constants.EtcdRecoverySnapshotPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o700)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating etcd recovery snapshot: %w\", err)\n\t}\n\n\tdefer snapshot.Close() //nolint:errcheck\n\n\tsuccessfulUpload := false\n\n\tdefer func() {\n\t\tif !successfulUpload {\n\t\t\tos.Remove(snapshot.Name()) //nolint:errcheck\n\t\t}\n\t}()\n\n\tfor {\n\t\tvar msg *common.Data\n\n\t\tmsg, err = srv.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = snapshot.Write(msg.Bytes)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error writing snapshot: %w\", err)\n\t\t}\n\t}\n\n\tif err = snapshot.Sync(); err != nil {\n\t\treturn fmt.Errorf(\"error fsyncing snapshot: %w\", err)\n\t}\n\n\tif err = snapshot.Close(); err != nil {\n\t\treturn fmt.Errorf(\"error closing snapshot: %w\", err)\n\t}\n\n\tsuccessfulUpload = true\n\n\treturn srv.SendAndClose(&machine.EtcdRecoverResponse{\n\t\tMessages: []*machine.EtcdRecover{\n\t\t\t{},\n\t\t},\n\t})\n}\n\nfunc mapAlarms(alarms []*etcdserverpb.AlarmMember) []*machine.EtcdMemberAlarm {\n\tmapAlarmType := func(alarmType etcdserverpb.AlarmType) machine.EtcdMemberAlarm_AlarmType {\n\t\tswitch alarmType {\n\t\tcase etcdserverpb.AlarmType_NOSPACE:\n\t\t\treturn machine.EtcdMemberAlarm_NOSPACE\n\t\tcase etcdserverpb.AlarmType_CORRUPT:\n\t\t\treturn machine.EtcdMemberAlarm_CORRUPT\n\t\tcase etcdserverpb.AlarmType_NONE:\n\t\t\treturn machine.EtcdMemberAlarm_NONE\n\t\tdefault:\n\t\t\treturn machine.EtcdMemberAlarm_NONE\n\t\t}\n\t}\n\n\treturn xslices.Map(alarms, func(alarm *etcdserverpb.AlarmMember) *machine.EtcdMemberAlarm {\n\t\treturn &machine.EtcdMemberAlarm{\n\t\t\tMemberId: alarm.MemberID,\n\t\t\tAlarm:    mapAlarmType(alarm.Alarm),\n\t\t}\n\t})\n}\n\n// EtcdAlarmList lists etcd alarms for the current node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (s *Server) EtcdAlarmList(ctx context.Context, in *emptypb.Empty) (*machine.EtcdAlarmListResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd alarm list\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.AlarmList(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list etcd alarms: %w\", err)\n\t}\n\n\treturn &machine.EtcdAlarmListResponse{\n\t\tMessages: []*machine.EtcdAlarm{\n\t\t\t{\n\t\t\t\tMemberAlarms: mapAlarms(resp.Alarms),\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdAlarmDisarm disarms etcd alarms for the current node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (s *Server) EtcdAlarmDisarm(ctx context.Context, in *emptypb.Empty) (*machine.EtcdAlarmDisarmResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd alarm disarm\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.AlarmDisarm(ctx, &clientv3.AlarmMember{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to disarm etcd alarm: %w\", err)\n\t}\n\n\treturn &machine.EtcdAlarmDisarmResponse{\n\t\tMessages: []*machine.EtcdAlarmDisarm{\n\t\t\t{\n\t\t\t\tMemberAlarms: mapAlarms(resp.Alarms),\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdDefragment defragments etcd data directory for the current node.\n//\n// Defragmentation is a resource-heavy operation, so it should only run on a specific\n// node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (s *Server) EtcdDefragment(ctx context.Context, in *emptypb.Empty) (*machine.EtcdDefragmentResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd defragment\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\t_, err = client.Defragment(ctx, nethelpers.JoinHostPort(\"localhost\", constants.EtcdClientPort))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to defragment etcd: %w\", err)\n\t}\n\n\treturn &machine.EtcdDefragmentResponse{\n\t\tMessages: []*machine.EtcdDefragment{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n// EtcdStatus returns etcd status for the member of the cluster.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (s *Server) EtcdStatus(ctx context.Context, in *emptypb.Empty) (*machine.EtcdStatusResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd status\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.Status(ctx, nethelpers.JoinHostPort(\"localhost\", constants.EtcdClientPort))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query etcd status: %w\", err)\n\t}\n\n\tstorageVersion := resp.StorageVersion\n\t// NOTE: this field is only filled on >3.6.0, thus we need a workaround for previous ETCD versions\n\tif storageVersion == \"\" {\n\t\tif v, err := semver.Parse(resp.Version); err == nil {\n\t\t\tstorageVersion = fmt.Sprintf(\"%d.%d.0\", v.Major, v.Minor)\n\t\t} else {\n\t\t\t// we swallow the error here, as we don't want to fail the request\n\t\t\t// over something that is not critical\n\t\t\tstorageVersion = \"unknown\"\n\t\t}\n\t}\n\n\treturn &machine.EtcdStatusResponse{\n\t\tMessages: []*machine.EtcdStatus{\n\t\t\t{\n\t\t\t\tMemberStatus: &machine.EtcdMemberStatus{\n\t\t\t\t\tMemberId:         resp.Header.MemberId,\n\t\t\t\t\tProtocolVersion:  resp.Version,\n\t\t\t\t\tDbSize:           resp.DbSize,\n\t\t\t\t\tDbSizeInUse:      resp.DbSizeInUse,\n\t\t\t\t\tLeader:           resp.Leader,\n\t\t\t\t\tRaftIndex:        resp.RaftIndex,\n\t\t\t\t\tRaftTerm:         resp.RaftTerm,\n\t\t\t\t\tRaftAppliedIndex: resp.RaftAppliedIndex,\n\t\t\t\t\tStorageVersion:   storageVersion,\n\t\t\t\t\tErrors:           resp.Errors,\n\t\t\t\t\tIsLearner:        resp.IsLearner,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (s *Server) EtcdDowngradeCancel(ctx context.Context, _ *emptypb.Empty) (*machine.EtcdDowngradeCancelResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd downgrade cancel\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.Downgrade(ctx, clientv3.DowngradeCancel, \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query etcd status: %w\", err)\n\t}\n\n\treturn &machine.EtcdDowngradeCancelResponse{\n\t\tMessages: []*machine.EtcdDowngradeCancel{\n\t\t\t{\n\t\t\t\tClusterDowngrade: &machine.EtcdClusterDowngrade{\n\t\t\t\t\tClusterVersion: resp.Version,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdDowngradeEnable enables etcd cluster downgrade to a specific version.\n//\n// This method is available only on control plane nodes (which run etcd).\n//\n//nolint:dupl\nfunc (s *Server) EtcdDowngradeEnable(ctx context.Context, in *machine.EtcdDowngradeEnableRequest) (*machine.EtcdDowngradeEnableResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd downgrade enable\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := validateDowngrade(in.Version); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.Downgrade(ctx, clientv3.DowngradeEnable, in.Version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query etcd status: %w\", err)\n\t}\n\n\treturn &machine.EtcdDowngradeEnableResponse{\n\t\tMessages: []*machine.EtcdDowngradeEnable{\n\t\t\t{\n\t\t\t\tClusterDowngrade: &machine.EtcdClusterDowngrade{\n\t\t\t\t\tClusterVersion: resp.Version,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\n// EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version.\n//\n// This method is available only on control plane nodes (which run etcd).\n//\n//nolint:dupl\nfunc (s *Server) EtcdDowngradeValidate(ctx context.Context, in *machine.EtcdDowngradeValidateRequest) (*machine.EtcdDowngradeValidateResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"etcd downgrade validate\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := validateDowngrade(in.Version); err != nil {\n\t\treturn nil, err\n\t}\n\n\tclient, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tresp, err := client.Downgrade(ctx, clientv3.DowngradeValidate, in.Version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to query etcd status: %w\", err)\n\t}\n\n\treturn &machine.EtcdDowngradeValidateResponse{\n\t\tMessages: []*machine.EtcdDowngradeValidate{\n\t\t\t{\n\t\t\t\tClusterDowngrade: &machine.EtcdClusterDowngrade{\n\t\t\t\t\tClusterVersion: resp.Version,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, nil\n}\n\nvar minEtcdDowngradeVersion = semver.Version{Major: 3, Minor: 5}\n\nfunc validateDowngrade(version string) error {\n\tif version == \"\" {\n\t\treturn status.Error(codes.InvalidArgument, \"version is required for etcd downgrade\")\n\t}\n\n\tparts := strings.Split(version, \".\")\n\tif len(parts) != 2 {\n\t\treturn status.Error(codes.InvalidArgument, \"version should be in MAJOR.MINOR format\")\n\t}\n\n\tmajor, err := strconv.ParseInt(parts[0], 10, 64)\n\tif err != nil {\n\t\treturn status.Error(codes.InvalidArgument, \"major version should be a number\")\n\t}\n\n\tminor, err := strconv.ParseInt(parts[1], 10, 64)\n\tif err != nil {\n\t\treturn status.Error(codes.InvalidArgument, \"minor version should be a number\")\n\t}\n\n\tsemverVersion := semver.Version{Major: uint64(major), Minor: uint64(minor)}\n\tif semverVersion.LT(minEtcdDowngradeVersion) {\n\t\treturn status.Error(codes.InvalidArgument, \"etcd downgrade is only supported to 3.5 and later versions\")\n\t}\n\n\treturn nil\n}\n\n// GenerateClientConfiguration implements the machine.MachineServer interface.\nfunc (s *Server) GenerateClientConfiguration(ctx context.Context, in *machine.GenerateClientConfigurationRequest) (*machine.GenerateClientConfigurationResponse, error) {\n\tif err := machinehelper.CheckControlplane(ctx, s.Controller.Runtime().State().V1Alpha2().Resources(), \"generate client configuration\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tcrtTTL := in.CrtTtl.AsDuration()\n\tif crtTTL <= 0 {\n\t\treturn nil, status.Error(codes.InvalidArgument, \"crt_ttl should be positive\")\n\t}\n\n\troles, _ := role.Parse(in.Roles)\n\n\tsecretsBundle := secrets.NewBundleFromConfig(secrets.NewFixedClock(time.Now()), s.Controller.Runtime().Config())\n\n\tcert, err := secretsBundle.GenerateTalosAPIClientCertificateWithTTL(roles, crtTTL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// make a nice context name\n\tcontextName := s.Controller.Runtime().Config().Cluster().Name()\n\tif r := roles.Strings(); len(r) == 1 {\n\t\tcontextName = strings.TrimPrefix(r[0], role.Prefix) + \"@\" + contextName\n\t}\n\n\ttalosconfig := clientconfig.NewConfig(contextName, nil, secretsBundle.Certs.OS.Crt, cert)\n\n\tb, err := talosconfig.Bytes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treply := &machine.GenerateClientConfigurationResponse{\n\t\tMessages: []*machine.GenerateClientConfiguration{\n\t\t\t{\n\t\t\t\tCa:          secretsBundle.Certs.OS.Crt,\n\t\t\t\tCrt:         cert.Crt,\n\t\t\t\tKey:         cert.Key,\n\t\t\t\tTalosconfig: b,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\ntype packetStreamWriter struct {\n\tstream machine.MachineService_PacketCaptureServer\n}\n\nfunc (w *packetStreamWriter) Write(data []byte) (int, error) {\n\t// copy the data as the stream may not send it immediately\n\tdata = slices.Clone(data)\n\n\terr := w.stream.Send(&common.Data{Bytes: data})\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn len(data), nil\n}\n\n// PacketCapture performs packet capture and streams the pcap file.\n//\n//nolint:gocyclo\nfunc (s *Server) PacketCapture(in *machine.PacketCaptureRequest, srv machine.MachineService_PacketCaptureServer) error {\n\tlinkInfo, err := safe.StateGetResource(srv.Context(), s.Controller.Runtime().State().V1Alpha2().Resources(), network.NewLinkStatus(network.NamespaceName, in.Interface))\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn status.Errorf(codes.NotFound, \"interface %q not found\", in.Interface)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tvar linkType pcap.LinkType\n\n\tswitch linkInfo.TypedSpec().Type { //nolint:exhaustive\n\tcase nethelpers.LinkEther, nethelpers.LinkLoopbck:\n\t\tlinkType = pcap.LinkTypeEthernet\n\tcase nethelpers.LinkNone:\n\t\tlinkType = pcap.LinkTypeRaw\n\tdefault:\n\t\treturn status.Errorf(codes.InvalidArgument, \"unsupported link type %s\", linkInfo.TypedSpec().Type)\n\t}\n\n\tif in.SnapLen == 0 {\n\t\tin.SnapLen = afpacket.DefaultFrameSize\n\t}\n\n\tfilter := make([]bpf.RawInstruction, 0, len(in.BpfFilter))\n\n\tfor _, f := range in.BpfFilter {\n\t\tfilter = append(filter, bpf.RawInstruction{\n\t\t\tOp: uint16(f.Op),\n\t\t\tJt: uint8(f.Jt),\n\t\t\tJf: uint8(f.Jf),\n\t\t\tK:  f.K,\n\t\t})\n\t}\n\n\thandle, err := afpacket.NewTPacket(\n\t\tafpacket.OptInterface(in.Interface),\n\t\tafpacket.OptPollTimeout(100*time.Millisecond),\n\t\tafpacket.OptSocketType(unix.SOCK_RAW|unix.SOCK_CLOEXEC),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating afpacket handle: %w\", err)\n\t}\n\n\tif len(filter) > 0 {\n\t\tif err = handle.SetBPF(filter); err != nil {\n\t\t\thandle.Close()\n\n\t\t\treturn fmt.Errorf(\"error setting BPF filter: %w\", err)\n\t\t}\n\t}\n\n\tif err = handle.SetPromiscuous(in.Promiscuous); err != nil {\n\t\thandle.Close()\n\n\t\treturn fmt.Errorf(\"error setting promiscuous mode %v: %w\", in.Promiscuous, err)\n\t}\n\n\treturn capturePackets(srv.Context(), &packetStreamWriter{srv}, handle, in.SnapLen, linkType)\n}\n\n//nolint:gocyclo,cyclop\nfunc capturePackets(ctx context.Context, w io.Writer, handle *afpacket.TPacket, snapLen uint32, linkType pcap.LinkType) error {\n\tdefer handle.Close()\n\n\tpcapw := pcap.NewWriter(w)\n\n\tif err := pcapw.WriteFileHeader(snapLen, linkType); err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tinfoMessage := \"pcap: \"\n\n\t\tstats, errStats := handle.Stats()\n\t\tif errStats == nil {\n\t\t\tinfoMessage += fmt.Sprintf(\"packets captured %d, polls %d\", stats.Packets, stats.Polls)\n\t\t}\n\n\t\t_, socketStatsV3, socketStatsErr := handle.SocketStats()\n\t\tif socketStatsErr == nil {\n\t\t\tinfoMessage += fmt.Sprintf(\", socket stats: drops %d, packets %d, queue freezes %d\", socketStatsV3.Drops(), socketStatsV3.Packets(), socketStatsV3.QueueFreezes())\n\t\t}\n\n\t\tlog.Print(infoMessage)\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\tdata, captureData, err := handle.ZeroCopyReadPacketData()\n\t\tif err == nil {\n\t\t\tif err = pcapw.WritePacket(captureData, data); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Immediately retry for temporary network errors\n\t\tif nerr, ok := err.(net.Error); ok && nerr.Temporary() { //nolint:staticcheck\n\t\t\tcontinue\n\t\t}\n\n\t\t// Immediately retry for EAGAIN and poll timeout\n\t\tif errors.Is(err, syscall.EAGAIN) || errors.Is(err, afpacket.ErrTimeout) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Immediately break for known unrecoverable errors\n\t\tif errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) ||\n\t\t\terrors.Is(err, io.ErrNoProgress) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, io.ErrShortBuffer) ||\n\t\t\terrors.Is(err, syscall.EBADF) || errors.Is(err, afpacket.ErrPoll) ||\n\t\t\tstrings.Contains(err.Error(), \"use of closed file\") {\n\t\t\treturn err\n\t\t}\n\n\t\ttime.Sleep(5 * time.Millisecond) // short sleep before retrying some errors\n\t}\n}\n\nfunc tryLockUpgradeMutex(ctx context.Context, etcdClient *etcd.Client) (unlock func(), err error) {\n\tsess, err := concurrency.NewSession(etcdClient.Client,\n\t\tconcurrency.WithContext(ctx),\n\t\tconcurrency.WithTTL(MinimumEtcdUpgradeLeaseLockSeconds),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error establishing etcd concurrency session: %w\", err)\n\t}\n\n\tmu := concurrency.NewMutex(sess, constants.EtcdTalosEtcdUpgradeMutex)\n\n\tif err = mu.TryLock(ctx); err != nil {\n\t\treturn nil, fmt.Errorf(\"error trying to lock etcd upgrade mutex: %w\", err)\n\t}\n\n\tlog.Printf(\"etcd upgrade mutex locked with session ID %08x\", sess.Lease())\n\n\treturn func() {\n\t\tunlockCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\tif err := mu.Unlock(unlockCtx); err != nil {\n\t\t\tlog.Printf(\"error unlocking etcd upgrade mutex: %v\", err)\n\t\t}\n\n\t\tif err := sess.Close(); err != nil {\n\t\t\tlog.Printf(\"error closing etcd upgrade mutex session: %v\", err)\n\t\t}\n\n\t\tlog.Printf(\"etcd upgrade mutex unlocked and session closed\")\n\t}, nil\n}\n\n// Netstat implements the machine.MachineServer interface.\nfunc (s *Server) Netstat(ctx context.Context, req *machine.NetstatRequest) (*machine.NetstatResponse, error) {\n\tif req == nil {\n\t\treq = new(machine.NetstatRequest)\n\t}\n\n\tfeatures := netstat.EnableFeatures{\n\t\tTCP:           req.L4Proto.Tcp,\n\t\tTCP6:          req.L4Proto.Tcp6,\n\t\tUDP:           req.L4Proto.Udp,\n\t\tUDP6:          req.L4Proto.Udp6,\n\t\tUDPLite:       req.L4Proto.Udplite,\n\t\tUDPLite6:      req.L4Proto.Udplite6,\n\t\tRaw:           req.L4Proto.Raw,\n\t\tRaw6:          req.L4Proto.Raw6,\n\t\tPID:           req.Feature.Pid,\n\t\tNoHostNetwork: !req.Netns.Hostnetwork,\n\t\tAllNetNs:      req.Netns.Allnetns,\n\t\tNetNsName:     req.Netns.Netns,\n\t}\n\n\tvar fn netstat.AcceptFn\n\n\tswitch req.Filter {\n\tcase machine.NetstatRequest_ALL:\n\t\tfn = func(*netstat.SockTabEntry) bool { return true }\n\tcase machine.NetstatRequest_LISTENING:\n\t\tfn = func(s *netstat.SockTabEntry) bool {\n\t\t\treturn s.RemoteEndpoint.IP.IsUnspecified() && s.RemoteEndpoint.Port == 0\n\t\t}\n\tcase machine.NetstatRequest_CONNECTED:\n\t\tfn = func(s *netstat.SockTabEntry) bool {\n\t\t\treturn !s.RemoteEndpoint.IP.IsUnspecified() && s.RemoteEndpoint.Port != 0\n\t\t}\n\t}\n\n\tnetstatResp, err := netstat.Netstat(ctx, features, fn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trecords := make([]*machine.ConnectRecord, len(netstatResp))\n\n\tfor i, entry := range netstatResp {\n\t\trecords[i] = &machine.ConnectRecord{\n\t\t\tL4Proto:    entry.Transport,\n\t\t\tLocalip:    entry.LocalEndpoint.IP.String(),\n\t\t\tLocalport:  uint32(entry.LocalEndpoint.Port),\n\t\t\tRemoteip:   entry.RemoteEndpoint.IP.String(),\n\t\t\tRemoteport: uint32(entry.RemoteEndpoint.Port),\n\t\t\tState:      machine.ConnectRecord_State(entry.State),\n\t\t\tTxqueue:    entry.TxQueue,\n\t\t\tRxqueue:    entry.RxQueue,\n\t\t\tTr:         machine.ConnectRecord_TimerActive(entry.Tr),\n\t\t\tTimerwhen:  entry.TimerWhen,\n\t\t\tRetrnsmt:   entry.Retrnsmt,\n\t\t\tUid:        entry.UID,\n\t\t\tTimeout:    entry.Timeout,\n\t\t\tInode:      entry.Inode,\n\t\t\tRef:        entry.Ref,\n\t\t\tPointer:    entry.Pointer,\n\t\t\tProcess:    &machine.ConnectRecord_Process{},\n\t\t\tNetns:      entry.NetNS,\n\t\t}\n\t\tif entry.Process != nil {\n\t\t\trecords[i].Process = &machine.ConnectRecord_Process{\n\t\t\t\tPid:  uint32(entry.Process.Pid),\n\t\t\t\tName: entry.Process.Name,\n\t\t\t}\n\t\t}\n\t}\n\n\treply := &machine.NetstatResponse{\n\t\tMessages: []*machine.Netstat{\n\t\t\t{\n\t\t\t\tConnectrecord: records,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, err\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_time.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\tntpclient \"github.com/beevik/ntp\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/ntp\"\n\ttimeapi \"github.com/siderolabs/talos/pkg/machinery/api/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ConfigProvider defines an interface sufficient for the TimeServer.\ntype ConfigProvider interface {\n\tConfig() config.Config\n}\n\n// TimeServer implements TimeService API.\ntype TimeServer struct {\n\ttimeapi.UnimplementedTimeServiceServer\n\n\tConfigProvider ConfigProvider\n}\n\n// Register implements the factory.Registrator interface.\nfunc (r *TimeServer) Register(s *grpc.Server) {\n\ttimeapi.RegisterTimeServiceServer(s, r)\n}\n\n// Time issues a query to the configured ntp server and displays the results.\nfunc (r *TimeServer) Time(ctx context.Context, in *emptypb.Empty) (reply *timeapi.TimeResponse, err error) {\n\tvar timeServers []string\n\n\tif r.ConfigProvider.Config() != nil {\n\t\tif cfg := r.ConfigProvider.Config().NetworkTimeSyncConfig(); cfg != nil {\n\t\t\ttimeServers = cfg.Servers()\n\t\t}\n\t}\n\n\tif len(timeServers) == 0 {\n\t\ttimeServers = []string{constants.DefaultNTPServer}\n\t}\n\n\treturn r.TimeCheck(ctx, &timeapi.TimeRequest{\n\t\tServer: timeServers[0],\n\t})\n}\n\n// TimeCheck issues a query to the specified ntp server and displays the results.\nfunc (r *TimeServer) TimeCheck(ctx context.Context, in *timeapi.TimeRequest) (reply *timeapi.TimeResponse, err error) {\n\tvar t time.Time\n\n\tif ntp.IsPTPDevice(in.Server) {\n\t\tts, err := ntp.QueryPTPDevice(in.Server)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error querying PTP device %q: %w\", in.Server, err)\n\t\t}\n\n\t\tt = time.Unix(ts.Sec, ts.Nsec)\n\t} else {\n\t\trt, err := ntpclient.Query(in.Server)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error querying NTP server %q: %w\", in.Server, err)\n\t\t}\n\n\t\tif err = rt.Validate(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error validating NTP response: %w\", err)\n\t\t}\n\n\t\tt = rt.Time\n\t}\n\n\treturn &timeapi.TimeResponse{\n\t\tMessages: []*timeapi.Time{\n\t\t\t{\n\t\t\t\tServer:     in.Server,\n\t\t\t\tLocaltime:  timestamppb.New(time.Now()),\n\t\t\t\tRemotetime: timestamppb.New(t),\n\t\t\t},\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/internal/server/v1alpha1/v1alpha1_time_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\truntime \"github.com/siderolabs/talos/internal/app/machined/internal/server/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/grpc/factory\"\n\ttimeapi \"github.com/siderolabs/talos/pkg/machinery/api/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\ntype TimedSuite struct {\n\tsuite.Suite\n}\n\nfunc TestTimedSuite(t *testing.T) {\n\t// Hide all our state transition messages\n\t// log.SetOutput(ioutil.Discard)\n\tsuite.Run(t, new(TimedSuite))\n}\n\ntype mockConfigProvider struct {\n\ttimeServer string\n}\n\nfunc (provider *mockConfigProvider) Config() config.Config {\n\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\tTimeServers: []string{provider.timeServer},\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *TimedSuite) TestTime() {\n\ttestServer := \"time.cloudflare.com\"\n\n\t// Create gRPC server\n\tapi := &runtime.TimeServer{\n\t\tConfigProvider: &mockConfigProvider{timeServer: testServer},\n\t}\n\tserver := factory.NewServer(api)\n\tlistener, err := fakeTimedRPC(suite.T())\n\tsuite.Assert().NoError(err)\n\n\tdefer server.Stop()\n\n\t//nolint:errcheck\n\tdefer os.Remove(listener.Addr().String())\n\n\t//nolint:errcheck\n\tgo server.Serve(listener)\n\n\tconn, err := grpc.NewClient(\n\t\tfmt.Sprintf(\"%s://%s\", \"unix\", listener.Addr().String()),\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithContextDialer(dialer.DialUnix()),\n\t)\n\tsuite.Require().NoError(err)\n\tsuite.T().Cleanup(func() { conn.Close() }) //nolint:errcheck\n\n\tnClient := timeapi.NewTimeServiceClient(conn)\n\treply, err := nClient.Time(context.Background(), &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(reply.Messages[0].Server, testServer)\n}\n\nfunc (suite *TimedSuite) TestTimeCheck() {\n\ttestServer := \"time.cloudflare.com\"\n\n\t// Create ntp client with bogus server\n\t// so we can check that we explicitly check the time of the\n\t// specified server ( testserver )\n\n\t// Create gRPC server\n\tapi := &runtime.TimeServer{}\n\tserver := factory.NewServer(api)\n\tlistener, err := fakeTimedRPC(suite.T())\n\tsuite.Assert().NoError(err)\n\n\tdefer server.Stop()\n\n\t//nolint:errcheck\n\tdefer os.Remove(listener.Addr().String())\n\n\t//nolint:errcheck\n\tgo server.Serve(listener)\n\n\tconn, err := grpc.NewClient(\n\t\tfmt.Sprintf(\"%s://%s\", \"unix\", listener.Addr().String()),\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithContextDialer(dialer.DialUnix()),\n\t)\n\tsuite.Require().NoError(err)\n\tsuite.T().Cleanup(func() { conn.Close() }) //nolint:errcheck\n\n\tnClient := timeapi.NewTimeServiceClient(conn)\n\treply, err := nClient.TimeCheck(context.Background(), &timeapi.TimeRequest{Server: testServer})\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(reply.Messages[0].Server, testServer)\n}\n\nfunc fakeTimedRPC(t *testing.T) (net.Listener, error) {\n\tt.Helper()\n\n\ttmpfile, err := os.CreateTemp(t.TempDir(), \"timed\")\n\trequire.NoError(t, err)\n\n\treturn factory.NewListener(\n\t\tt.Context(),\n\t\tfactory.Network(\"unix\"),\n\t\tfactory.SocketPath(tmpfile.Name()),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package machined provides machined implementation.\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd/proc\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd/proc/reaper\"\n\tdebug \"github.com/siderolabs/go-debug\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/apid\"\n\t\"github.com/siderolabs/talos/internal/app/dashboard\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/emergency\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1\"\n\tstartuptasks \"github.com/siderolabs/talos/internal/app/machined/pkg/startup\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/internal/app/poweroff\"\n\t\"github.com/siderolabs/talos/internal/app/trustd\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/startup\"\n)\n\nfunc init() {\n\t// Patch a default HTTP client with updated transport to handle cases when default client is being used.\n\thttp.DefaultClient.Transport = httpdefaults.PatchTransport(cleanhttp.DefaultPooledTransport())\n}\n\nfunc recovery(ctx context.Context) {\n\tif r := recover(); r != nil {\n\t\tvar (\n\t\t\terr error\n\t\t\tok  bool\n\t\t)\n\n\t\terr, ok = r.(error)\n\t\tif ok {\n\t\t\thandle(ctx, err)\n\t\t}\n\t}\n}\n\n// syncNonVolatileStorageBuffers invokes unix.Sync and waits up to 30 seconds\n// for it to finish.\n//\n// See http://man7.org/linux/man-pages/man2/reboot.2.html.\nfunc syncNonVolatileStorageBuffers() {\n\tsyncdone := make(chan struct{})\n\n\tgo func() {\n\t\tdefer close(syncdone)\n\n\t\tunix.Sync()\n\t}()\n\n\tlog.Printf(\"waiting for sync...\")\n\n\tfor i := 29; i >= 0; i-- {\n\t\tselect {\n\t\tcase <-syncdone:\n\t\t\tlog.Printf(\"sync done\")\n\n\t\t\treturn\n\t\tcase <-time.After(time.Second):\n\t\t}\n\n\t\tif i != 0 {\n\t\t\tlog.Printf(\"waiting %d more seconds for sync to finish\", i)\n\t\t}\n\t}\n\n\tlog.Printf(\"sync hasn't completed in time, aborting...\")\n}\n\n//nolint:gocyclo\nfunc handle(ctx context.Context, err error) {\n\trebootCmd := int(emergency.RebootCmd.Load())\n\n\tvar rebootErr runtime.RebootError\n\tif errors.As(err, &rebootErr) {\n\t\t// not a failure, but wrapped reboot command\n\t\trebootCmd = rebootErr.Cmd\n\n\t\terr = nil\n\t}\n\n\tif err != nil {\n\t\tlog.Print(err)\n\t\trevertBootloader(ctx)\n\n\t\tif p := procfs.ProcCmdline().Get(constants.KernelParamPanic).First(); p != nil {\n\t\t\tif *p == \"0\" {\n\t\t\t\tlog.Printf(\"panic=0 kernel flag found, sleeping forever\")\n\n\t\t\t\trebootCmd = 0\n\t\t\t}\n\t\t}\n\n\t\tif rebootCmd == unix.LINUX_REBOOT_CMD_RESTART {\n\t\t\tfor i := 10; i >= 0; i-- {\n\t\t\t\tlog.Printf(\"rebooting in %d seconds\\n\", i)\n\t\t\t\ttime.Sleep(1 * time.Second)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err = proc.KillAll(); err != nil {\n\t\tlog.Printf(\"error killing all procs: %s\", err)\n\t}\n\n\tif err = mount.UnmountAll(); err != nil {\n\t\tlog.Printf(\"error unmounting: %s\", err)\n\t}\n\n\tsyncNonVolatileStorageBuffers()\n\n\tif rebootCmd == 0 {\n\t\texitSignal := make(chan os.Signal, 1)\n\n\t\tsignal.Notify(exitSignal, syscall.SIGINT, syscall.SIGTERM)\n\n\t\t<-exitSignal\n\t} else if unix.Reboot(rebootCmd) == nil {\n\t\t// Wait forever.\n\t\tselect {}\n\t}\n}\n\nfunc runDebugServer(ctx context.Context) {\n\tconst debugAddr = \":9982\"\n\n\tdebugLogFunc := func(msg string) {\n\t\tlog.Print(msg)\n\t}\n\n\tif err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {\n\t\tlog.Fatalf(\"failed to start debug server: %s\", err)\n\t}\n}\n\nfunc run() error {\n\t// Limit GOMAXPROCS.\n\tstartup.LimitMaxProcs(constants.MachinedMaxProcs)\n\n\t// Initialize the controller without a config.\n\tc, err := v1alpha1runtime.NewController()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trevertSetState(c.Runtime().State().V1Alpha2().Resources())\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tlogger, err := c.V1Alpha2().MakeLogger(\"early-startup\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstart := time.Now()\n\n\t// Run startup tasks, and then run the entrypoint.\n\treturn startuptasks.RunTasks(ctx, logger, c.Runtime(), append(\n\t\tstartuptasks.DefaultTasks(),\n\t\tfunc(ctx context.Context, log *zap.Logger, _ runtime.Runtime, _ startuptasks.NextTaskFunc) error {\n\t\t\tlogger.Info(\"early startup done\", zap.Duration(\"duration\", time.Since(start)))\n\n\t\t\treturn runEntrypoint(ctx, c)\n\t\t},\n\t)...)\n}\n\n//nolint:gocyclo\nfunc runEntrypoint(ctx context.Context, c *v1alpha1runtime.Controller) error {\n\terrCh := make(chan error)\n\n\tvar controllerWaitGroup sync.WaitGroup\n\tdefer controllerWaitGroup.Wait() // wait for controller-runtime to finish before rebooting\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tdrainer := runtime.NewDrainer()\n\n\tdefer func() {\n\t\tdrainCtx, drainCtxCancel := context.WithTimeout(context.Background(), time.Second*10)\n\t\tdefer drainCtxCancel()\n\n\t\tif e := drainer.Drain(drainCtx); e != nil {\n\t\t\tlog.Printf(\"WARNING: failed to drain controllers: %s\", e)\n\t\t}\n\t}()\n\n\tgo runDebugServer(ctx)\n\n\t// Schedule service shutdown on any return.\n\tdefer system.Services(c.Runtime()).Shutdown(ctx)\n\n\t// Start signal and ACPI listeners.\n\tgo func() {\n\t\tif e := c.ListenForEvents(ctx); e != nil {\n\t\t\tlog.Printf(\"WARNING: signals and ACPI events will be ignored: %s\", e)\n\t\t}\n\t}()\n\n\tcontrollerWaitGroup.Go(func() {\n\t\tif e := c.V1Alpha2().Run(ctx, drainer); e != nil {\n\t\t\tctrlErr := fmt.Errorf(\"fatal controller runtime error: %s\", e)\n\n\t\t\tlog.Printf(\"controller runtime goroutine error: %s\", ctrlErr)\n\n\t\t\terrCh <- ctrlErr\n\t\t}\n\n\t\tlog.Printf(\"controller runtime finished\")\n\t})\n\n\t// Load machined service.\n\tsystem.Services(c.Runtime()).Load(\n\t\t&services.Machined{Controller: c},\n\t)\n\n\tinitializeCanceled := false\n\n\t// Initialize the machine.\n\tif err := c.Run(ctx, runtime.SequenceInitialize, nil); err != nil {\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tinitializeCanceled = true\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// If Initialize sequence was canceled, don't run any other sequence.\n\tif !initializeCanceled {\n\t\t// Perform an installation if required.\n\t\tif err := c.Run(ctx, runtime.SequenceInstall, nil); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Boot the machine.\n\t\tif err := c.Run(ctx, runtime.SequenceBoot, nil); err != nil && !errors.Is(err, context.Canceled) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Watch and handle runtime events.\n\t//nolint:errcheck\n\t_ = c.Runtime().Events().Watch(\n\t\tfunc(events <-chan runtime.EventInfo) {\n\t\t\tfor {\n\t\t\t\tfor event := range events {\n\t\t\t\t\tswitch msg := event.Payload.(type) {\n\t\t\t\t\tcase *machine.SequenceEvent:\n\t\t\t\t\t\tif msg.Error != nil {\n\t\t\t\t\t\t\tif msg.Error.GetCode() == common.Code_LOCKED ||\n\t\t\t\t\t\t\t\tmsg.Error.GetCode() == common.Code_CANCELED {\n\t\t\t\t\t\t\t\t// ignore sequence lock and canceled errors, they're not fatal\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\terrCh <- fmt.Errorf(\n\t\t\t\t\t\t\t\t\"fatal sequencer error in %q sequence: %v\",\n\t\t\t\t\t\t\t\tmsg.GetSequence(),\n\t\t\t\t\t\t\t\tmsg.GetError().String(),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\tcase *machine.RestartEvent:\n\t\t\t\t\t\terrCh <- runtime.RebootError{Cmd: int(msg.Cmd)}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t)\n\n\treturn <-errCh\n}\n\nfunc main() {\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tswitch filepath.Base(os.Args[0]) {\n\tcase \"apid\":\n\t\tapid.Main()\n\n\t\treturn\n\tcase \"trustd\":\n\t\ttrustd.Main()\n\n\t\treturn\n\t// Azure uses the hv_utils kernel module to shutdown the node in hyper-v by calling perform_shutdown which will call orderly_poweroff which will call /sbin/poweroff.\n\tcase \"poweroff\", \"shutdown\":\n\t\tpoweroff.Main(os.Args)\n\n\t\treturn\n\tcase \"dashboard\":\n\t\tdashboard.Main()\n\n\t\treturn\n\tdefault:\n\t}\n\n\t// Setup panic handler.\n\tdefer recovery(ctx)\n\n\t// Initialize the process reaper.\n\treaper.Run()\n\n\tdefer reaper.Shutdown()\n\n\thandle(ctx, run())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/block/mount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package block implements adapters wrapping resources/block to provide additional functionality.\npackage block\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/block/volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumeConfigSpec adapter provides conversion from MountStatus.\n//\n//nolint:revive,golint\nfunc VolumeConfigSpec(r *block.VolumeConfigSpec) volumeConfigSpec {\n\treturn volumeConfigSpec{\n\t\tvolumeConfigSpec: r,\n\t}\n}\n\ntype volumeConfigSpec struct {\n\tvolumeConfigSpec *block.VolumeConfigSpec\n}\n\n// WithRoot adapts VolumeConfigSpec to xfs.Root and calls the provided callback with it.\nfunc (a volumeConfigSpec) ApplyEncryptionConfig(in config.EncryptionConfig) error {\n\tout := a.volumeConfigSpec\n\n\tif in == nil {\n\t\tout.Encryption = block.EncryptionSpec{}\n\n\t\treturn nil\n\t}\n\n\tout.Encryption.Provider = in.Provider()\n\tout.Encryption.Cipher = in.Cipher()\n\tout.Encryption.KeySize = in.KeySize()\n\tout.Encryption.BlockSize = in.BlockSize()\n\tout.Encryption.PerfOptions = in.Options()\n\n\tout.Encryption.Keys = make([]block.EncryptionKey, len(in.Keys()))\n\n\tfor i, key := range in.Keys() {\n\t\tout.Encryption.Keys[i].Slot = key.Slot()\n\t\tout.Encryption.Keys[i].LockToSTATE = key.LockToSTATE()\n\n\t\tswitch {\n\t\tcase key.Static() != nil:\n\t\t\tout.Encryption.Keys[i].Type = block.EncryptionKeyStatic\n\t\t\tout.Encryption.Keys[i].StaticPassphrase = key.Static().Key()\n\t\tcase key.NodeID() != nil:\n\t\t\tout.Encryption.Keys[i].Type = block.EncryptionKeyNodeID\n\t\tcase key.KMS() != nil:\n\t\t\tout.Encryption.Keys[i].Type = block.EncryptionKeyKMS\n\t\t\tout.Encryption.Keys[i].KMSEndpoint = key.KMS().Endpoint()\n\t\tcase key.TPM() != nil:\n\t\t\tout.Encryption.Keys[i].Type = block.EncryptionKeyTPM\n\t\t\tout.Encryption.Keys[i].TPMCheckSecurebootStatusOnEnroll = key.TPM().CheckSecurebootOnEnroll()\n\t\t\tout.Encryption.Keys[i].TPMPCRs = key.TPM().PCRs()\n\t\t\tout.Encryption.Keys[i].TPMPubKeyPCRs = key.TPM().PubKeyPCRs()\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported encryption key type: slot %d\", key.Slot())\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/block/volume_mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"fmt\"\n\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\n// VolumeMountStatus adapter provides conversion from MountStatus.\n//\n//nolint:revive,golint\nfunc VolumeMountStatus(r *block.VolumeMountStatus) volumeMountStatus {\n\treturn volumeMountStatus{\n\t\tVolumeMountStatus: r,\n\t}\n}\n\ntype volumeMountStatus struct {\n\tVolumeMountStatus *block.VolumeMountStatus\n}\n\n// WithRoot adapts VolumeMountStatus to xfs.Root and calls the provided callback with it.\nfunc (a volumeMountStatus) WithRoot(logger *zap.Logger, callback func(root xfs.Root) error) error {\n\tvar root xfs.Root\n\n\troot, ok := a.VolumeMountStatus.TypedSpec().Root().(xfs.Root)\n\n\tif !ok || root == nil || !a.VolumeMountStatus.TypedSpec().Detached {\n\t\troot = &xfs.UnixRoot{\n\t\t\tFS: opentree.NewFromPath(a.VolumeMountStatus.TypedSpec().Target),\n\t\t}\n\t\tif err := root.OpenFS(); err != nil {\n\t\t\treturn fmt.Errorf(\"error opening filesystem: %w\", err)\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif err := root.Close(); err != nil {\n\t\t\t\tlogger.Error(\"error closing filesystem\", zap.Error(err))\n\t\t\t}\n\t\t}()\n\t}\n\n\treturn callback(root)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/cluster/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cluster implements adapters wrapping resources/cluster to provide additional functionality.\npackage cluster\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/cluster/identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"io\"\n\n\t\"github.com/jxskiss/base62\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// IdentitySpec adapter provides identity generation.\n//\n//nolint:revive,golint\nfunc IdentitySpec(r *cluster.IdentitySpec) identity {\n\treturn identity{\n\t\tIdentitySpec: r,\n\t}\n}\n\ntype identity struct {\n\t*cluster.IdentitySpec\n}\n\n// Generate new identity.\nfunc (a identity) Generate() error {\n\tbuf := make([]byte, constants.DefaultNodeIdentitySize)\n\n\tif _, err := io.ReadFull(rand.Reader, buf); err != nil {\n\t\treturn err\n\t}\n\n\ta.IdentitySpec.NodeID = base62.EncodeToString(buf)\n\n\treturn nil\n}\n\n// ConvertMachineID returns /etc/machine-id compatible representation.\nfunc (a identity) ConvertMachineID() ([]byte, error) {\n\traw, err := base62.DecodeString(a.IdentitySpec.NodeID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbuf := make([]byte, 32)\n\thex.Encode(buf, raw[:16])\n\n\treturn buf, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/cluster/identity_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc TestIdentityGenerate(t *testing.T) {\n\tt.Parallel()\n\n\tvar spec1, spec2 cluster.IdentitySpec\n\n\trequire.NoError(t, clusteradapter.IdentitySpec(&spec1).Generate())\n\trequire.NoError(t, clusteradapter.IdentitySpec(&spec2).Generate())\n\n\tassert.NotEqual(t, spec1, spec2)\n\n\tlength := len(spec1.NodeID)\n\n\tassert.GreaterOrEqual(t, length, 43)\n\tassert.LessOrEqual(t, length, 45)\n}\n\nfunc TestIdentityConvertMachineID(t *testing.T) {\n\tt.Parallel()\n\n\tspec := cluster.IdentitySpec{\n\t\tNodeID: \"sou7yy34ykX3n373Zw1DXKb8zD7UnyKT6HT3QDsGH6L\",\n\t}\n\n\tmachineID, err := clusteradapter.IdentitySpec(&spec).ConvertMachineID()\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"be871ac0d0dd31fa4caca753b0f3f1b2\", string(machineID))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/hardware/hardware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package hardware implements adapters wrapping resources/hardware to provide additional functionality.\npackage hardware\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/hardware/memorymodule.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/siderolabs/go-smbios/smbios\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// MemoryModule adapter provider conversion from smbios.SMBIOS.\n//\n//nolint:revive,golint\nfunc MemoryModule(m *hardware.MemoryModule) memoryModule {\n\treturn memoryModule{\n\t\tMemoryModule: m,\n\t}\n}\n\ntype memoryModule struct {\n\t*hardware.MemoryModule\n}\n\n// Update current processor info.\nfunc (m memoryModule) Update(memory *smbios.MemoryDevice) {\n\ttranslateMemoryModuleInfo := func(in *smbios.MemoryDevice) hardware.MemoryModuleSpec {\n\t\tvar memoryModuleSpec hardware.MemoryModuleSpec\n\n\t\tif in.Size != 0 && in.Size != 0xFFFF {\n\t\t\tvar size uint32\n\n\t\t\tif in.Size == 0x7FFF {\n\t\t\t\tsize = uint32(in.ExtendedSize)\n\t\t\t} else {\n\t\t\t\tsize = uint32(in.Size)\n\t\t\t}\n\n\t\t\tmemoryModuleSpec.AssetTag = in.AssetTag\n\t\t\tmemoryModuleSpec.BankLocator = in.BankLocator\n\t\t\tmemoryModuleSpec.DeviceLocator = in.DeviceLocator\n\t\t\tmemoryModuleSpec.Manufacturer = in.Manufacturer\n\t\t\tmemoryModuleSpec.ProductName = in.PartNumber\n\t\t\tmemoryModuleSpec.SerialNumber = in.SerialNumber\n\t\t\tmemoryModuleSpec.Size = size\n\t\t\tmemoryModuleSpec.Speed = uint32(in.Speed)\n\t\t}\n\n\t\treturn memoryModuleSpec\n\t}\n\n\t*m.MemoryModule.TypedSpec() = translateMemoryModuleInfo(memory)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/hardware/processor.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/siderolabs/go-smbios/smbios\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// Processor adapter provider conversion from smbios.SMBIOS.\n//\n//nolint:revive,golint\nfunc Processor(p *hardware.Processor) processor {\n\treturn processor{\n\t\tProcessor: p,\n\t}\n}\n\ntype processor struct {\n\t*hardware.Processor\n}\n\n// Update current processor info.\nfunc (p processor) Update(processor *smbios.ProcessorInformation) {\n\ttranslateProcessorInfo := func(in *smbios.ProcessorInformation) hardware.ProcessorSpec {\n\t\tvar processorSpec hardware.ProcessorSpec\n\n\t\tif in.Status.SocketPopulated() {\n\t\t\tprocessorSpec.Socket = in.SocketDesignation\n\t\t\tprocessorSpec.Manufacturer = in.ProcessorManufacturer\n\t\t\tprocessorSpec.ProductName = in.ProcessorVersion\n\t\t\tprocessorSpec.MaxSpeed = uint32(in.MaxSpeed)\n\t\t\tprocessorSpec.BootSpeed = uint32(in.CurrentSpeed)\n\t\t\tprocessorSpec.Status = uint32(in.Status)\n\t\t\tprocessorSpec.SerialNumber = in.SerialNumber\n\t\t\tprocessorSpec.AssetTag = in.AssetTag\n\t\t\tprocessorSpec.PartNumber = in.PartNumber\n\t\t\tprocessorSpec.CoreCount = uint32(in.CoreCount)\n\t\t\tprocessorSpec.CoreEnabled = uint32(in.CoreEnabled)\n\t\t\tprocessorSpec.ThreadCount = uint32(in.ThreadCount)\n\t\t}\n\n\t\treturn processorSpec\n\t}\n\n\t*p.Processor.TypedSpec() = translateProcessorInfo(processor)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/hardware/system_information.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/siderolabs/go-smbios/smbios\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// SystemInformation adapter provider conversion from smbios.SMBIOS.\n//\n//nolint:revive,golint\nfunc SystemInformation(p *hardware.SystemInformation) systemInformation {\n\treturn systemInformation{\n\t\tSystemInformation: p,\n\t}\n}\n\ntype systemInformation struct {\n\t*hardware.SystemInformation\n}\n\n// Update current systemInformation info.\nfunc (p systemInformation) Update(systemInformation *smbios.SystemInformation, uuidRewrite string) {\n\tif uuidRewrite == \"\" {\n\t\tuuidRewrite = systemInformation.UUID\n\t}\n\n\t*p.SystemInformation.TypedSpec() = hardware.SystemInformationSpec{\n\t\tManufacturer: systemInformation.Manufacturer,\n\t\tProductName:  systemInformation.ProductName,\n\t\tVersion:      systemInformation.Version,\n\t\tSerialNumber: systemInformation.SerialNumber,\n\t\tUUID:         uuidRewrite,\n\t\tWakeUpType:   systemInformation.WakeUpType.String(),\n\t\tSKUNumber:    systemInformation.SKUNumber,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s implements adapters wrapping resources/k8s to provide additional functionality.\npackage k8s\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/manifest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/util/yaml\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// Manifest adapter provides conversion from procfs.\n//\n//nolint:revive,golint\nfunc Manifest(r *k8s.Manifest) manifest {\n\treturn manifest{\n\t\tManifest: r,\n\t}\n}\n\ntype manifest struct {\n\t*k8s.Manifest\n}\n\n// SetObjects parses manifest from a list of runtime objects.\nfunc (a manifest) SetObjects(objects []runtime.Object) error {\n\ta.Manifest.TypedSpec().Items = make([]k8s.SingleManifest, 0, len(objects))\n\n\tfor _, obj := range objects {\n\t\tunstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error converting object to unstructured: %w\", err)\n\t\t}\n\n\t\tu := unstructured.Unstructured{Object: unstructuredObj}\n\t\tu.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind())\n\t\tdelete(u.Object, \"status\") // remove status field if present\n\n\t\ta.Manifest.TypedSpec().Items = append(a.Manifest.TypedSpec().Items, k8s.SingleManifest{\n\t\t\tObject: u.Object,\n\t\t})\n\t}\n\n\treturn nil\n}\n\n// SetYAML parses manifest from YAML.\n//\n//nolint:gocyclo\nfunc (a manifest) SetYAML(yamlBytes []byte) error {\n\ta.Manifest.TypedSpec().Items = nil\n\treader := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(yamlBytes)))\n\n\tfor {\n\t\tyamlManifest, err := reader.Read()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tyamlManifest = bytes.TrimSpace(yamlManifest)\n\n\t\tif len(yamlManifest) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tjsonManifest, err := yaml.ToJSON(yamlManifest)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error converting manifest to JSON: %w\", err)\n\t\t}\n\n\t\tif bytes.Equal(jsonManifest, []byte(\"null\")) || bytes.Equal(jsonManifest, []byte(\"{}\")) {\n\t\t\t// skip YAML docs which contain only comments\n\t\t\tcontinue\n\t\t}\n\n\t\tvar obj unstructured.Unstructured\n\n\t\tif err = json.Unmarshal(jsonManifest, &obj); err != nil {\n\t\t\treturn fmt.Errorf(\"error loading JSON manifest into unstructured: %w\", err)\n\t\t}\n\n\t\t// if the manifest is a list, we will unwrap it\n\t\tif obj.IsList() {\n\t\t\tif err = obj.EachListItem(func(item runtime.Object) error {\n\t\t\t\tobj, ok := item.(*unstructured.Unstructured)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"list item is not Unstructured: %T\", item)\n\t\t\t\t}\n\n\t\t\t\ta.Manifest.TypedSpec().Items = append(a.Manifest.TypedSpec().Items, k8s.SingleManifest{Object: obj.Object})\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error unwrapping a List: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\ta.Manifest.TypedSpec().Items = append(a.Manifest.TypedSpec().Items, k8s.SingleManifest{Object: obj.Object})\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Objects returns list of unstructured object.\nfunc (a manifest) Objects() []*unstructured.Unstructured {\n\treturn xslices.Map(a.Manifest.TypedSpec().Items, func(item k8s.SingleManifest) *unstructured.Unstructured {\n\t\treturn &unstructured.Unstructured{Object: item.Object}\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/manifest_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t_ \"embed\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\nfunc TestManifestSetYAML(t *testing.T) {\n\tmanifest := k8s.NewManifest(k8s.ControlPlaneNamespaceName, \"test\")\n\tadapter := k8sadapter.Manifest(manifest)\n\n\trequire.NoError(t, adapter.SetYAML([]byte(strings.TrimSpace(`\n---\napiVersion: audit.k8s.io/v1\nkind: Policy\nrules:\n- level: Metadata\n---\n`))))\n\n\tassert.Len(t, adapter.Objects(), 1)\n\tassert.Equal(t, adapter.Objects()[0].GetKind(), \"Policy\")\n}\n\nfunc TestManifestSetYAMLEmptyComments(t *testing.T) {\n\tmanifest := k8s.NewManifest(k8s.ControlPlaneNamespaceName, \"test\")\n\tadapter := k8sadapter.Manifest(manifest)\n\n\trequire.NoError(t, adapter.SetYAML([]byte(strings.TrimSpace(`\n---\napiVersion: audit.k8s.io/v1\nkind: Policy\nrules:\n- level: Metadata\n---\n# Left empty\n---\n`))))\n\n\tassert.Len(t, adapter.Objects(), 1)\n\tassert.Equal(t, adapter.Objects()[0].GetKind(), \"Policy\")\n}\n\n//go:embed testdata/list.yaml\nvar listManifest []byte\n\nfunc TestManifestSetYAMLList(t *testing.T) {\n\tmanifest := k8s.NewManifest(k8s.ControlPlaneNamespaceName, \"test\")\n\tadapter := k8sadapter.Manifest(manifest)\n\n\trequire.NoError(t, adapter.SetYAML(listManifest))\n\n\tassert.Len(t, adapter.Objects(), 2)\n\tassert.Equal(t, \"ClusterRoleBinding\", adapter.Objects()[0].GetKind())\n\tassert.Equal(t, \"system:cloud-node-controller\", adapter.Objects()[0].GetName())\n\tassert.Equal(t, \"ClusterRoleBinding\", adapter.Objects()[1].GetKind())\n\tassert.Equal(t, \"system:cloud-controller-manager\", adapter.Objects()[1].GetName())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/static_pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"encoding/json\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// StaticPod adapter provides conversion from *v1.Pod.\n//\n//nolint:revive,golint\nfunc StaticPod(r *k8s.StaticPod) staticPod {\n\treturn staticPod{\n\t\tStaticPod: r,\n\t}\n}\n\ntype staticPod struct {\n\t*k8s.StaticPod\n}\n\n// Pod returns native Kubernetes resource.\nfunc (a staticPod) Pod() (*v1.Pod, error) {\n\tvar spec v1.Pod\n\n\tjsonSerialized, err := json.Marshal(a.StaticPod.TypedSpec().Pod)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(jsonSerialized, &spec)\n\n\treturn &spec, err\n}\n\n// SetPod sets spec from native Kubernetes resource.\nfunc (a staticPod) SetPod(podSpec *v1.Pod) error {\n\tjsonSerialized, err := json.Marshal(podSpec)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ta.StaticPod.TypedSpec().Pod = map[string]any{}\n\n\treturn json.Unmarshal(jsonSerialized, &a.StaticPod.TypedSpec().Pod)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/static_pod_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"encoding/json\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// StaticPodStatus adapter provides conversion from *v1.PodStatus.\n//\n//nolint:revive,golint\nfunc StaticPodStatus(r *k8s.StaticPodStatus) staticPodStatus {\n\treturn staticPodStatus{\n\t\tStaticPodStatus: r,\n\t}\n}\n\ntype staticPodStatus struct {\n\t*k8s.StaticPodStatus\n}\n\n// SetStatus sets status from native Kubernetes resource.\nfunc (a staticPodStatus) SetStatus(status *v1.PodStatus) error {\n\tjsonSerialized, err := json.Marshal(status)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ta.StaticPodStatus.TypedSpec().PodStatus = map[string]any{}\n\n\treturn json.Unmarshal(jsonSerialized, &a.StaticPodStatus.TypedSpec().PodStatus)\n}\n\n// Status gets status from native Kubernetes resource.\nfunc (a staticPodStatus) Status() (*v1.PodStatus, error) {\n\tvar spec v1.PodStatus\n\n\tjsonSerialized, err := json.Marshal(a.StaticPodStatus.TypedSpec().PodStatus)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(jsonSerialized, &spec)\n\n\treturn &spec, err\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/k8s/testdata/list.yaml",
    "content": "apiVersion: v1\nitems:\n- apiVersion: rbac.authorization.k8s.io/v1\n  kind: ClusterRoleBinding\n  metadata:\n    name: system:cloud-node-controller\n  roleRef:\n    apiGroup: rbac.authorization.k8s.io\n    kind: ClusterRole\n    name: system:cloud-node-controller\n  subjects:\n  - kind: ServiceAccount\n    name: cloud-node-controller\n    namespace: kube-system\n- apiVersion: rbac.authorization.k8s.io/v1\n  kind: ClusterRoleBinding\n  metadata:\n    name: system:cloud-controller-manager\n  roleRef:\n    apiGroup: rbac.authorization.k8s.io\n    kind: ClusterRole\n    name: system:cloud-controller-manager\n  subjects:\n  - kind: ServiceAccount\n    name: cloud-controller-manager\n    namespace: kube-system\nkind: List\nmetadata: {}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/kubespan/identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/mdlayher/netx/eui64\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go4.org/netipx\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// IdentitySpec adapter provides identity generation.\n//\n//nolint:revive,golint\nfunc IdentitySpec(r *kubespan.IdentitySpec) identity {\n\treturn identity{\n\t\tIdentitySpec: r,\n\t}\n}\n\ntype identity struct {\n\t*kubespan.IdentitySpec\n}\n\n// GenerateKey generates new Wireguard key.\nfunc (a identity) GenerateKey() error {\n\tkey, err := wgtypes.GeneratePrivateKey()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ta.IdentitySpec.PrivateKey = key.String()\n\ta.IdentitySpec.PublicKey = key.PublicKey().String()\n\n\treturn nil\n}\n\n// UpdateAddress re-calculates node address based on input data.\nfunc (a identity) UpdateAddress(clusterID string, mac net.HardwareAddr) error {\n\ta.IdentitySpec.Subnet = network.ULAPrefix(clusterID, network.ULAKubeSpan)\n\n\tvar err error\n\n\ta.IdentitySpec.Address, err = wgEUI64(a.IdentitySpec.Subnet, mac)\n\n\treturn err\n}\n\nfunc wgEUI64(prefix netip.Prefix, mac net.HardwareAddr) (out netip.Prefix, err error) {\n\tif value.IsZero(prefix) {\n\t\treturn out, errors.New(\"cannot calculate IP from zero prefix\")\n\t}\n\n\tstdIP, err := eui64.ParseMAC(netipx.PrefixIPNet(prefix).IP, mac)\n\tif err != nil {\n\t\treturn out, fmt.Errorf(\"failed to parse MAC into EUI-64 address: %w\", err)\n\t}\n\n\tip, ok := netipx.FromStdIP(stdIP)\n\tif !ok {\n\t\treturn out, fmt.Errorf(\"failed to parse intermediate standard IP %q: %w\", stdIP.String(), err)\n\t}\n\n\treturn netip.PrefixFrom(ip, ip.BitLen()), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/kubespan/identity_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan_test\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\nfunc TestIdentityGenerateKey(t *testing.T) {\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tvar spec kubespan.IdentitySpec\n\n\tassert.NoError(t, kubespanadapter.IdentitySpec(&spec).GenerateKey())\n}\n\nfunc TestIdentityUpdateAddress(t *testing.T) {\n\tvar spec kubespan.IdentitySpec\n\n\tmac, err := net.ParseMAC(\"2e:1a:b6:53:81:69\")\n\trequire.NoError(t, err)\n\n\tassert.NoError(t, kubespanadapter.IdentitySpec(&spec).UpdateAddress(\"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\", mac))\n\n\tassert.Equal(t, \"fd7f:175a:b97c:5602:2c1a:b6ff:fe53:8169/128\", spec.Address.String())\n\tassert.Equal(t, \"fd7f:175a:b97c:5602::/64\", spec.Subnet.String())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/kubespan/kubespan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubespan implements adapters wrapping resources/kubespan to provide additional functionality.\npackage kubespan\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/kubespan/peer_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/value\"\n\t\"go4.org/netipx\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/wireguard\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\n// PeerStatusSpec adapter provides Wireguard integration and state management.\n//\n//nolint:revive,golint\nfunc PeerStatusSpec(r *kubespan.PeerStatusSpec) peerStatus {\n\treturn peerStatus{\n\t\tPeerStatusSpec: r,\n\t}\n}\n\ntype peerStatus struct {\n\t*kubespan.PeerStatusSpec\n}\n\n// EndpointConnectionTimeout is time to wait for initial handshake when the endpoint is just set.\nconst EndpointConnectionTimeout = 15 * time.Second\n\n// CalculateState updates connection state based on other fields values.\n//\n// Goal: endpoint is ultimately down if we haven't seen handshake for more than peerDownInterval,\n// but as the endpoints get updated we want faster feedback, so we start checking more aggressively\n// that the handshake happened within endpointConnectionTimeout since last endpoint change.\n//\n// Timeline:\n//\n// ---------------------------------------------------------------------->\n// ^            ^                                   ^\n// |            |                                   |\n// T0           T0+endpointConnectionTimeout        T0+peerDownInterval\n//\n// Where T0 = LastEndpointChange\n//\n// The question is where is LastHandshakeTimeout vs. those points above:\n//\n//   - if we're past (T0+peerDownInterval), simply check that time since last handshake < peerDownInterval\n//   - if we're between (T0+endpointConnectionTimeout) and (T0+peerDownInterval), and there's no handshake\n//     after the endpoint change, assume that the endpoint is down\n//   - if we're between (T0) and (T0+endpointConnectionTimeout), and there's no handshake since the endpoint change,\n//     consider the state to be unknown\nfunc (a peerStatus) CalculateState() {\n\tsinceLastHandshake := time.Since(a.PeerStatusSpec.LastHandshakeTime)\n\tsinceEndpointChange := time.Since(a.PeerStatusSpec.LastEndpointChange)\n\n\ta.CalculateStateWithDurations(sinceLastHandshake, sinceEndpointChange)\n}\n\n// CalculateStateWithDurations calculates the state based on the time since events.\nfunc (a peerStatus) CalculateStateWithDurations(sinceLastHandshake, sinceEndpointChange time.Duration) {\n\tswitch {\n\tcase sinceEndpointChange > wireguard.PeerDownInterval: // past T0+peerDownInterval\n\t\t// if we got handshake in the last peerDownInterval, endpoint is up\n\t\tif sinceLastHandshake < wireguard.PeerDownInterval {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateUp\n\t\t} else {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateDown\n\t\t}\n\tcase sinceEndpointChange < EndpointConnectionTimeout: // between (T0) and (T0+endpointConnectionTimeout)\n\t\t// endpoint got recently updated, consider no handshake as 'unknown'\n\t\tif a.PeerStatusSpec.LastHandshakeTime.After(a.PeerStatusSpec.LastEndpointChange) {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateUp\n\t\t} else {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateUnknown\n\t\t}\n\n\tdefault: // otherwise, we're between (T0+endpointConnectionTimeout) and (T0+peerDownInterval)\n\t\t// if we haven't had the handshake yet, consider the endpoint to be down\n\t\tif a.PeerStatusSpec.LastHandshakeTime.After(a.PeerStatusSpec.LastEndpointChange) {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateUp\n\t\t} else {\n\t\t\ta.PeerStatusSpec.State = kubespan.PeerStateDown\n\t\t}\n\t}\n\n\tif a.PeerStatusSpec.State == kubespan.PeerStateDown && value.IsZero(a.PeerStatusSpec.LastUsedEndpoint) {\n\t\t// no endpoint, so unknown\n\t\ta.PeerStatusSpec.State = kubespan.PeerStateUnknown\n\t}\n}\n\n// UpdateFromWireguard updates fields from wgtypes information.\nfunc (a peerStatus) UpdateFromWireguard(peer wgtypes.Peer) {\n\tif peer.Endpoint != nil {\n\t\ta.PeerStatusSpec.Endpoint, _ = netipx.FromStdAddr(peer.Endpoint.IP, peer.Endpoint.Port, \"\")\n\t} else {\n\t\ta.PeerStatusSpec.Endpoint = netip.AddrPort{}\n\t}\n\n\ta.PeerStatusSpec.LastHandshakeTime = peer.LastHandshakeTime\n\ta.PeerStatusSpec.TransmitBytes = peer.TransmitBytes\n\ta.PeerStatusSpec.ReceiveBytes = peer.ReceiveBytes\n}\n\n// UpdateEndpoint updates the endpoint information and last update timestamp.\nfunc (a peerStatus) UpdateEndpoint(endpoint netip.AddrPort) {\n\ta.PeerStatusSpec.Endpoint = endpoint\n\ta.PeerStatusSpec.LastUsedEndpoint = endpoint\n\ta.PeerStatusSpec.LastEndpointChange = time.Now()\n\ta.PeerStatusSpec.State = kubespan.PeerStateUnknown\n}\n\n// ShouldChangeEndpoint tells whether endpoint should be updated.\nfunc (a peerStatus) ShouldChangeEndpoint() bool {\n\treturn a.PeerStatusSpec.State == kubespan.PeerStateDown || value.IsZero(a.PeerStatusSpec.LastUsedEndpoint)\n}\n\n// PickNewEndpoint picks new endpoint given the state and list of available endpoints.\n//\n// If returned newEndpoint is zero value, no new endpoint is available.\nfunc (a peerStatus) PickNewEndpoint(endpoints []netip.AddrPort) (newEndpoint netip.AddrPort) {\n\tif len(endpoints) == 0 {\n\t\treturn newEndpoint\n\t}\n\n\tif value.IsZero(a.PeerStatusSpec.LastUsedEndpoint) {\n\t\t// first time setting the endpoint\n\t\tnewEndpoint = endpoints[0]\n\t} else {\n\t\t// find the next endpoint after LastUsedEndpoint and use it\n\t\tidx := -1\n\n\t\tfor i := range endpoints {\n\t\t\tif endpoints[i] == a.PeerStatusSpec.LastUsedEndpoint {\n\t\t\t\tidx = i\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// special case: if the peer has just a single endpoint, we can't rotate\n\t\tif !(len(endpoints) == 1 && idx == 0 && a.PeerStatusSpec.Endpoint == a.PeerStatusSpec.LastUsedEndpoint) {\n\t\t\tnewEndpoint = endpoints[(idx+1)%len(endpoints)]\n\t\t}\n\t}\n\n\treturn newEndpoint\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/kubespan/peer_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/stretchr/testify/assert\"\n\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/wireguard\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\nfunc TestPeerStatus_PickNewEndpoint(t *testing.T) {\n\t// zero status\n\tpeerStatus := kubespan.PeerStatusSpec{}\n\n\t// no endpoint => no way to pick new one\n\tassert.True(t, value.IsZero(kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(nil)))\n\n\tendpoints := []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"10.3.4.5:10500\"),\n\t\tnetip.MustParseAddrPort(\"192.168.3.8:457\"),\n\t}\n\n\t// initial choice should be the first endpoint\n\tnewEndpoint := kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints)\n\tassert.Equal(t, endpoints[0], newEndpoint)\n\tkubespanadapter.PeerStatusSpec(&peerStatus).UpdateEndpoint(newEndpoint)\n\n\t// next choice should be 2nd endpoint\n\tnewEndpoint = kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints)\n\tassert.Equal(t, endpoints[1], newEndpoint)\n\tkubespanadapter.PeerStatusSpec(&peerStatus).UpdateEndpoint(newEndpoint)\n\n\t// back to the first endpoint\n\tnewEndpoint = kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints)\n\tassert.Equal(t, endpoints[0], newEndpoint)\n\tkubespanadapter.PeerStatusSpec(&peerStatus).UpdateEndpoint(newEndpoint)\n\n\t// can't rotate a single endpoint\n\tassert.True(t, value.IsZero(kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints[:1])))\n\n\t// can rotate if the endpoint is different\n\tnewEndpoint = kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints[1:])\n\tassert.Equal(t, endpoints[1], newEndpoint)\n\tkubespanadapter.PeerStatusSpec(&peerStatus).UpdateEndpoint(newEndpoint)\n\n\t// if totally new list of endpoints is given, pick the first one\n\tendpoints = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"10.3.4.5:10501\"),\n\t\tnetip.MustParseAddrPort(\"192.168.3.8:458\"),\n\t}\n\tnewEndpoint = kubespanadapter.PeerStatusSpec(&peerStatus).PickNewEndpoint(endpoints)\n\tassert.Equal(t, endpoints[0], newEndpoint)\n\tkubespanadapter.PeerStatusSpec(&peerStatus).UpdateEndpoint(newEndpoint)\n}\n\nfunc TestPeerStatus_CalculateState(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname string\n\n\t\tsinceLastHandshake, sinceEndpointChange time.Duration\n\n\t\tlastUsedEndpointZero bool\n\n\t\texpectedState kubespan.PeerState\n\t}{\n\t\t{\n\t\t\tname:                 \"no endpoint set\",\n\t\t\tsinceLastHandshake:   time.Hour,\n\t\t\tsinceEndpointChange:  time.Hour,\n\t\t\tlastUsedEndpointZero: true,\n\t\t\texpectedState:        kubespan.PeerStateUnknown,\n\t\t},\n\t\t{\n\t\t\tname:                \"peer is down\",\n\t\t\tsinceLastHandshake:  2 * wireguard.PeerDownInterval,\n\t\t\tsinceEndpointChange: 2 * wireguard.PeerDownInterval,\n\t\t\texpectedState:       kubespan.PeerStateDown,\n\t\t},\n\t\t{\n\t\t\tname:                \"fresh peer, no handshake\",\n\t\t\tsinceLastHandshake:  2 * wireguard.PeerDownInterval,\n\t\t\tsinceEndpointChange: kubespanadapter.EndpointConnectionTimeout / 2,\n\t\t\texpectedState:       kubespan.PeerStateUnknown,\n\t\t},\n\t\t{\n\t\t\tname:                \"fresh peer, with handshake\",\n\t\t\tsinceLastHandshake:  0,\n\t\t\tsinceEndpointChange: kubespanadapter.EndpointConnectionTimeout / 2,\n\t\t\texpectedState:       kubespan.PeerStateUp,\n\t\t},\n\t\t{\n\t\t\tname:                \"peer after initial timeout, with handshake\",\n\t\t\tsinceLastHandshake:  0,\n\t\t\tsinceEndpointChange: kubespanadapter.EndpointConnectionTimeout + 1,\n\t\t\texpectedState:       kubespan.PeerStateUp,\n\t\t},\n\t\t{\n\t\t\tname:                \"peer after initial timeout, no handshake\",\n\t\t\tsinceLastHandshake:  2 * kubespanadapter.EndpointConnectionTimeout,\n\t\t\tsinceEndpointChange: kubespanadapter.EndpointConnectionTimeout + 1,\n\t\t\texpectedState:       kubespan.PeerStateDown,\n\t\t},\n\t\t{\n\t\t\tname:                \"established peer, up\",\n\t\t\tsinceLastHandshake:  wireguard.PeerDownInterval / 2,\n\t\t\tsinceEndpointChange: wireguard.PeerDownInterval + 1,\n\t\t\texpectedState:       kubespan.PeerStateUp,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tpeerStatus := kubespan.PeerStatusSpec{\n\t\t\t\tLastHandshakeTime:  time.Now().Add(-tt.sinceLastHandshake),\n\t\t\t\tLastEndpointChange: time.Now().Add(-tt.sinceEndpointChange),\n\t\t\t}\n\n\t\t\tif !tt.lastUsedEndpointZero {\n\t\t\t\tpeerStatus.LastUsedEndpoint = netip.MustParseAddrPort(\"192.168.1.1:10000\")\n\t\t\t}\n\n\t\t\tkubespanadapter.PeerStatusSpec(&peerStatus).CalculateStateWithDurations(tt.sinceLastHandshake, tt.sinceEndpointChange)\n\n\t\t\tassert.Equal(t, tt.expectedState, peerStatus.State)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/bond_master_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/mdlayher/netlink\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// BondMasterSpec adapter provides encoding/decoding to netlink structures.\n//\n//nolint:revive,golint\nfunc BondMasterSpec(r *network.BondMasterSpec) bondMaster {\n\treturn bondMaster{\n\t\tBondMasterSpec: r,\n\t}\n}\n\ntype bondMaster struct {\n\t*network.BondMasterSpec\n}\n\n// FillDefaults fills zero values with proper default values.\n//\n//nolint:gocyclo\nfunc (a bondMaster) FillDefaults() {\n\tbond := a.BondMasterSpec\n\n\tbond.UseCarrier = true // Linux 6.18 locks this value to true\n\n\tif bond.ResendIGMP == 0 {\n\t\tbond.ResendIGMP = 1\n\t}\n\n\tif bond.LPInterval == 0 {\n\t\tbond.LPInterval = 1\n\t}\n\n\tif bond.PacketsPerSlave == 0 {\n\t\tbond.PacketsPerSlave = 1\n\t}\n\n\tif bond.NumPeerNotif == 0 {\n\t\tbond.NumPeerNotif = 1\n\t}\n\n\tif bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {\n\t\tbond.TLBDynamicLB = 1\n\t}\n\n\tif bond.Mode == nethelpers.BondMode8023AD && bond.ADActorSysPrio == 0 {\n\t\tbond.ADActorSysPrio = 65535\n\t}\n\n\tif bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {\n\t\tif bond.MissedMax == 0 {\n\t\t\tbond.MissedMax = 2\n\t\t}\n\t}\n\n\tif bond.Mode != nethelpers.BondMode8023AD {\n\t\tbond.ADLACPActive = nethelpers.ADLACPActiveOn\n\t}\n}\n\n// Encode the BondMasterSpec into netlink attributes.\n//\n//nolint:gocyclo,cyclop\nfunc (a bondMaster) Encode() ([]byte, error) {\n\tbond := a.BondMasterSpec\n\n\tencoder := netlink.NewAttributeEncoder()\n\n\tencoder.Uint8(unix.IFLA_BOND_MODE, uint8(bond.Mode))\n\tencoder.Uint8(unix.IFLA_BOND_XMIT_HASH_POLICY, uint8(bond.HashPolicy))\n\n\tif bond.Mode == nethelpers.BondMode8023AD {\n\t\tencoder.Uint8(unix.IFLA_BOND_AD_LACP_RATE, uint8(bond.LACPRate))\n\t\tencoder.Uint8(unix.IFLA_BOND_AD_LACP_ACTIVE, uint8(bond.ADLACPActive))\n\t}\n\n\tif bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {\n\t\tencoder.Uint32(unix.IFLA_BOND_ARP_VALIDATE, uint32(bond.ARPValidate))\n\t}\n\n\tencoder.Uint32(unix.IFLA_BOND_ARP_ALL_TARGETS, uint32(bond.ARPAllTargets))\n\n\tif bond.Mode == nethelpers.BondModeActiveBackup || bond.Mode == nethelpers.BondModeALB || bond.Mode == nethelpers.BondModeTLB {\n\t\tif bond.PrimaryIndex != nil {\n\t\t\tencoder.Uint32(unix.IFLA_BOND_PRIMARY, *bond.PrimaryIndex)\n\t\t}\n\t}\n\n\tencoder.Uint8(unix.IFLA_BOND_PRIMARY_RESELECT, uint8(bond.PrimaryReselect))\n\tencoder.Uint8(unix.IFLA_BOND_FAIL_OVER_MAC, uint8(bond.FailOverMac))\n\tencoder.Uint8(unix.IFLA_BOND_AD_SELECT, uint8(bond.ADSelect))\n\tencoder.Uint32(unix.IFLA_BOND_MIIMON, bond.MIIMon)\n\n\tif bond.MIIMon != 0 {\n\t\tencoder.Uint32(unix.IFLA_BOND_UPDELAY, bond.UpDelay)\n\t\tencoder.Uint32(unix.IFLA_BOND_DOWNDELAY, bond.DownDelay)\n\t}\n\n\tif bond.Mode != nethelpers.BondMode8023AD && bond.Mode != nethelpers.BondModeALB && bond.Mode != nethelpers.BondModeTLB {\n\t\tencoder.Uint32(unix.IFLA_BOND_ARP_INTERVAL, bond.ARPInterval)\n\n\t\tencoder.Nested(unix.IFLA_BOND_ARP_IP_TARGET, func(nae *netlink.AttributeEncoder) error {\n\t\t\tfor i, addr := range bond.ARPIPTargets {\n\t\t\t\tif !addr.Is4() {\n\t\t\t\t\treturn fmt.Errorf(\"%s is not IPV4 address\", addr)\n\t\t\t\t}\n\n\t\t\t\tip := addr.As4()\n\t\t\t\tnae.Bytes(uint16(i), ip[:])\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\n\t\tencoder.Nested(unix.IFLA_BOND_NS_IP6_TARGET, func(nae *netlink.AttributeEncoder) error {\n\t\t\tfor i, addr := range bond.NSIP6Targets {\n\t\t\t\tif !addr.Is6() {\n\t\t\t\t\treturn fmt.Errorf(\"%s is not IPV6 address\", addr)\n\t\t\t\t}\n\n\t\t\t\tip := addr.As16()\n\t\t\t\tnae.Bytes(uint16(i), ip[:])\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tencoder.Uint32(unix.IFLA_BOND_RESEND_IGMP, bond.ResendIGMP)\n\tencoder.Uint32(unix.IFLA_BOND_MIN_LINKS, bond.MinLinks)\n\tencoder.Uint32(unix.IFLA_BOND_LP_INTERVAL, bond.LPInterval)\n\n\tif bond.Mode == nethelpers.BondModeRoundrobin {\n\t\tencoder.Uint32(unix.IFLA_BOND_PACKETS_PER_SLAVE, bond.PacketsPerSlave)\n\t}\n\n\tencoder.Uint8(unix.IFLA_BOND_NUM_PEER_NOTIF, bond.NumPeerNotif)\n\n\tif bond.Mode == nethelpers.BondModeALB || bond.Mode == nethelpers.BondModeTLB {\n\t\tencoder.Uint8(unix.IFLA_BOND_TLB_DYNAMIC_LB, bond.TLBDynamicLB)\n\t}\n\n\tencoder.Uint8(unix.IFLA_BOND_ALL_SLAVES_ACTIVE, bond.AllSlavesActive)\n\n\tvar useCarrier uint8\n\n\tif bond.UseCarrier {\n\t\tuseCarrier = 1\n\t}\n\n\tencoder.Uint8(unix.IFLA_BOND_USE_CARRIER, useCarrier)\n\n\tif bond.Mode == nethelpers.BondMode8023AD {\n\t\tencoder.Uint16(unix.IFLA_BOND_AD_ACTOR_SYS_PRIO, bond.ADActorSysPrio)\n\t\tencoder.Uint16(unix.IFLA_BOND_AD_USER_PORT_KEY, bond.ADUserPortKey)\n\t}\n\n\tif bond.MIIMon != 0 {\n\t\tencoder.Uint32(unix.IFLA_BOND_PEER_NOTIF_DELAY, bond.PeerNotifyDelay)\n\t}\n\n\tif bond.MissedMax != 0 {\n\t\tencoder.Uint8(unix.IFLA_BOND_MISSED_MAX, bond.MissedMax)\n\t}\n\n\treturn encoder.Encode()\n}\n\n// Decode the BondMasterSpec from netlink attributes.\n//\n//nolint:gocyclo,cyclop\nfunc (a bondMaster) Decode(data []byte) error {\n\t*a.BondMasterSpec = network.BondMasterSpec{}\n\tbond := a.BondMasterSpec\n\n\tdecoder, err := netlink.NewAttributeDecoder(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor decoder.Next() {\n\t\tswitch decoder.Type() {\n\t\tcase unix.IFLA_BOND_MODE:\n\t\t\tbond.Mode = nethelpers.BondMode(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_XMIT_HASH_POLICY:\n\t\t\tbond.HashPolicy = nethelpers.BondXmitHashPolicy(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_AD_LACP_RATE:\n\t\t\tbond.LACPRate = nethelpers.LACPRate(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_ARP_VALIDATE:\n\t\t\tbond.ARPValidate = nethelpers.ARPValidate(decoder.Uint32())\n\t\tcase unix.IFLA_BOND_ARP_ALL_TARGETS:\n\t\t\tbond.ARPAllTargets = nethelpers.ARPAllTargets(decoder.Uint32())\n\t\tcase unix.IFLA_BOND_PRIMARY:\n\t\t\tbond.PrimaryIndex = new(decoder.Uint32())\n\t\tcase unix.IFLA_BOND_PRIMARY_RESELECT:\n\t\t\tbond.PrimaryReselect = nethelpers.PrimaryReselect(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_FAIL_OVER_MAC:\n\t\t\tbond.FailOverMac = nethelpers.FailOverMAC(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_AD_SELECT:\n\t\t\tbond.ADSelect = nethelpers.ADSelect(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_MIIMON:\n\t\t\tbond.MIIMon = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_UPDELAY:\n\t\t\tbond.UpDelay = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_DOWNDELAY:\n\t\t\tbond.DownDelay = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_ARP_INTERVAL:\n\t\t\tbond.ARPInterval = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_ARP_IP_TARGET:\n\t\t\tdecoder.Nested(func(nad *netlink.AttributeDecoder) error {\n\t\t\t\tfor nad.Next() {\n\t\t\t\t\taddr, ok := netip.AddrFromSlice(nad.Bytes())\n\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tbond.ARPIPTargets = append(bond.ARPIPTargets, addr)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid ARP IP target\")\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\tcase unix.IFLA_BOND_NS_IP6_TARGET:\n\t\t\tdecoder.Nested(func(nad *netlink.AttributeDecoder) error {\n\t\t\t\tfor nad.Next() {\n\t\t\t\t\taddr, ok := netip.AddrFromSlice(nad.Bytes())\n\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tbond.NSIP6Targets = append(bond.NSIP6Targets, addr)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn fmt.Errorf(\"invalid NS IP6 target\")\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\tcase unix.IFLA_BOND_RESEND_IGMP:\n\t\t\tbond.ResendIGMP = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_MIN_LINKS:\n\t\t\tbond.MinLinks = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_LP_INTERVAL:\n\t\t\tbond.LPInterval = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_PACKETS_PER_SLAVE:\n\t\t\tbond.PacketsPerSlave = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_NUM_PEER_NOTIF:\n\t\t\tbond.NumPeerNotif = decoder.Uint8()\n\t\tcase unix.IFLA_BOND_TLB_DYNAMIC_LB:\n\t\t\tbond.TLBDynamicLB = decoder.Uint8()\n\t\tcase unix.IFLA_BOND_ALL_SLAVES_ACTIVE:\n\t\t\tbond.AllSlavesActive = decoder.Uint8()\n\t\tcase unix.IFLA_BOND_USE_CARRIER:\n\t\t\tbond.UseCarrier = decoder.Uint8() == 1\n\t\tcase unix.IFLA_BOND_AD_ACTOR_SYS_PRIO:\n\t\t\tbond.ADActorSysPrio = decoder.Uint16()\n\t\tcase unix.IFLA_BOND_AD_USER_PORT_KEY:\n\t\t\tbond.ADUserPortKey = decoder.Uint16()\n\t\tcase unix.IFLA_BOND_PEER_NOTIF_DELAY:\n\t\t\tbond.PeerNotifyDelay = decoder.Uint32()\n\t\tcase unix.IFLA_BOND_AD_LACP_ACTIVE:\n\t\t\tbond.ADLACPActive = nethelpers.ADLACPActive(decoder.Uint8())\n\t\tcase unix.IFLA_BOND_MISSED_MAX:\n\t\t\tbond.MissedMax = decoder.Uint8()\n\t\t}\n\t}\n\n\treturn decoder.Err()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/bond_master_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestBondMasterSpec(t *testing.T) {\n\tspec := network.BondMasterSpec{\n\t\tMode:      nethelpers.BondModeActiveBackup,\n\t\tMIIMon:    100,\n\t\tUpDelay:   200,\n\t\tDownDelay: 300,\n\t}\n\n\tb, err := networkadapter.BondMasterSpec(&spec).Encode()\n\trequire.NoError(t, err)\n\n\tvar decodedSpec network.BondMasterSpec\n\n\trequire.NoError(t, networkadapter.BondMasterSpec(&decodedSpec).Decode(b))\n\n\trequire.Equal(t, spec, decodedSpec)\n}\n\nfunc TestBondMasterSpecDecodeClearsTargets(t *testing.T) {\n\tinitial := network.BondMasterSpec{\n\t\tMode:         nethelpers.BondModeActiveBackup,\n\t\tARPIPTargets: []netip.Addr{netip.MustParseAddr(\"198.51.100.254\")},\n\t\tNSIP6Targets: []netip.Addr{netip.MustParseAddr(\"fd00::1\")},\n\t}\n\n\tinitialEncoded, err := networkadapter.BondMasterSpec(&initial).Encode()\n\trequire.NoError(t, err)\n\n\tcleared := network.BondMasterSpec{\n\t\tMode: nethelpers.BondModeActiveBackup,\n\t}\n\n\tclearedEncoded, err := networkadapter.BondMasterSpec(&cleared).Encode()\n\trequire.NoError(t, err)\n\n\tvar decodedSpec network.BondMasterSpec\n\n\trequire.NoError(t, networkadapter.BondMasterSpec(&decodedSpec).Decode(initialEncoded))\n\trequire.Equal(t, initial.ARPIPTargets, decodedSpec.ARPIPTargets)\n\trequire.Equal(t, initial.NSIP6Targets, decodedSpec.NSIP6Targets)\n\n\trequire.NoError(t, networkadapter.BondMasterSpec(&decodedSpec).Decode(clearedEncoded))\n\trequire.Empty(t, decodedSpec.ARPIPTargets)\n\trequire.Empty(t, decodedSpec.NSIP6Targets)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/bridge_master_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/mdlayher/netlink\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// BridgeMasterSpec adapter provides encoding/decoding to netlink structures.\n//\n//nolint:revive\nfunc BridgeMasterSpec(r *network.BridgeMasterSpec) bridgeMaster {\n\treturn bridgeMaster{\n\t\tBridgeMasterSpec: r,\n\t}\n}\n\n// bridgeMaster contains the bridge master spec and provides methods for encoding/decoding it to netlink structures.\ntype bridgeMaster struct {\n\t*network.BridgeMasterSpec\n}\n\n// Encode the BridgeMasterSpec into netlink attributes.\nfunc (a bridgeMaster) Encode() ([]byte, error) {\n\tbridge := a.BridgeMasterSpec\n\n\tencoder := netlink.NewAttributeEncoder()\n\n\tstpEnabled := 0\n\tif bridge.STP.Enabled {\n\t\tstpEnabled = 1\n\t}\n\n\tvlanFiltering := 0\n\tif bridge.VLAN.FilteringEnabled {\n\t\tvlanFiltering = 1\n\t}\n\n\tencoder.Uint32(unix.IFLA_BR_STP_STATE, uint32(stpEnabled))\n\tencoder.Uint8(unix.IFLA_BR_VLAN_FILTERING, uint8(vlanFiltering))\n\n\treturn encoder.Encode()\n}\n\n// Decode the BridgeMasterSpec from netlink attributes.\nfunc (a bridgeMaster) Decode(data []byte) error {\n\tbridge := a.BridgeMasterSpec\n\n\tdecoder, err := netlink.NewAttributeDecoder(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor decoder.Next() {\n\t\tswitch decoder.Type() {\n\t\tcase unix.IFLA_BR_STP_STATE:\n\t\t\tbridge.STP.Enabled = decoder.Uint32() == 1\n\t\tcase unix.IFLA_BR_VLAN_FILTERING:\n\t\t\tbridge.VLAN.FilteringEnabled = decoder.Uint8() == 1\n\t\t}\n\t}\n\n\treturn decoder.Err()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/bridge_master_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestBridgeMasterSpec(t *testing.T) {\n\tspec := network.BridgeMasterSpec{\n\t\tSTP: network.STPSpec{\n\t\t\tEnabled: true,\n\t\t},\n\t\tVLAN: network.BridgeVLANSpec{\n\t\t\tFilteringEnabled: true,\n\t\t},\n\t}\n\n\tb, err := networkadapter.BridgeMasterSpec(&spec).Encode()\n\trequire.NoError(t, err)\n\n\tvar decodedSpec network.BridgeMasterSpec\n\n\trequire.NoError(t, networkadapter.BridgeMasterSpec(&decodedSpec).Decode(b))\n\n\trequire.Equal(t, spec, decodedSpec)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/ipset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"go4.org/netipx\"\n)\n\n// BuildIPSet builds an IPSet from the given include and exclude prefixes.\nfunc BuildIPSet(include, exclude []netip.Prefix) (*netipx.IPSet, error) {\n\tvar builder netipx.IPSetBuilder\n\n\tfor _, pfx := range include {\n\t\tbuilder.AddPrefix(pfx)\n\t}\n\n\tfor _, pfx := range exclude {\n\t\tbuilder.RemovePrefix(pfx)\n\t}\n\n\treturn builder.IPSet()\n}\n\n// SplitIPSet splits the given IPSet into IPv4 and IPv6 ranges.\nfunc SplitIPSet(set *netipx.IPSet) (ipv4, ipv6 []netipx.IPRange) {\n\tfor _, rng := range set.Ranges() {\n\t\tif rng.From().Is4() {\n\t\t\tipv4 = append(ipv4, rng)\n\t\t} else {\n\t\t\tipv6 = append(ipv6, rng)\n\t\t}\n\t}\n\n\treturn ipv4, ipv6\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/ipset_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go4.org/netipx\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n)\n\nfunc TestBuildIPSet(t *testing.T) {\n\tipset, err := network.BuildIPSet(\n\t\t[]netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\tnetip.MustParsePrefix(\"2001:db8::/32\"),\n\t\t},\n\t\t[]netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.4.0.0/16\"),\n\t\t})\n\trequire.NoError(t, err)\n\n\tassert.Equal(t,\n\t\t[]string{\"10.0.0.0-10.3.255.255\", \"10.5.0.0-10.255.255.255\", \"2001:db8::-2001:db8:ffff:ffff:ffff:ffff:ffff:ffff\"},\n\t\txslices.Map(ipset.Ranges(), netipx.IPRange.String),\n\t)\n}\n\nfunc TestSplitIPSet(t *testing.T) {\n\tipset, err := network.BuildIPSet(\n\t\t[]netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\tnetip.MustParsePrefix(\"2001:db8::/32\"),\n\t\t},\n\t\t[]netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.4.0.0/16\"),\n\t\t})\n\trequire.NoError(t, err)\n\n\tv4, v6 := network.SplitIPSet(ipset)\n\n\tassert.Equal(t,\n\t\t[]string{\"10.0.0.0-10.3.255.255\", \"10.5.0.0-10.255.255.255\"},\n\t\txslices.Map(v4, netipx.IPRange.String),\n\t)\n\n\tassert.Equal(t,\n\t\t[]string{\"2001:db8::-2001:db8:ffff:ffff:ffff:ffff:ffff:ffff\"},\n\t\txslices.Map(v6, netipx.IPRange.String),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network implements adapters wrapping resources/network to provide additional functionality.\npackage network\n\n// MSS calculation constants.\nconst (\n\tIPv4HeaderLen = 20 // IPv4 fixed header length\n\tIPv6HeaderLen = 40 // IPv6 fixed header length\n\tTCPHeaderLen  = 20 // fixed TCP header length, without options\n\tTCPOptionsLen = 12 // assuming typical options like SACK, timestamps, etc. used by default in Linux\n)\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/nftables_rule.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\n\t\"github.com/google/nftables\"\n\t\"github.com/google/nftables/binaryutil\"\n\t\"github.com/google/nftables/expr\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go4.org/netipx\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NfTablesRule adapter provides encoding to nftables instructions.\n//\n//nolint:revive,golint\nfunc NfTablesRule(r *network.NfTablesRule) nftablesRule {\n\treturn nftablesRule{\n\t\tNfTablesRule: r,\n\t}\n}\n\ntype nftablesRule struct {\n\t*network.NfTablesRule\n}\n\n// SetKind is the type of the nftables Set.\ntype SetKind uint8\n\n// SetKind constants.\nconst (\n\tSetKindIPv4 SetKind = iota\n\tSetKindIPv6\n\tSetKindPort\n\tSetKindIfName\n\tSetKindConntrackState\n\tSetKindICMPType\n)\n\n// NfTablesSet is a compiled representation of the set.\ntype NfTablesSet struct {\n\tKind            SetKind\n\tAddresses       []netipx.IPRange\n\tPorts           [][2]uint16\n\tStrings         [][]byte\n\tConntrackStates []nethelpers.ConntrackState\n\tICMPTypes       []nethelpers.ICMPType\n}\n\n// IsInterval returns true if the set is an interval set.\nfunc (set NfTablesSet) IsInterval() bool {\n\tswitch set.Kind {\n\tcase SetKindIPv4, SetKindIPv6, SetKindPort:\n\t\treturn true\n\tcase SetKindIfName, SetKindConntrackState, SetKindICMPType:\n\t\treturn false\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown set kind: %d\", set.Kind))\n\t}\n}\n\n// KeyType returns the type of the set.\nfunc (set NfTablesSet) KeyType() nftables.SetDatatype {\n\tswitch set.Kind {\n\tcase SetKindIPv4:\n\t\treturn nftables.TypeIPAddr\n\tcase SetKindIPv6:\n\t\treturn nftables.TypeIP6Addr\n\tcase SetKindPort:\n\t\treturn nftables.TypeInetService\n\tcase SetKindIfName:\n\t\treturn nftables.TypeIFName\n\tcase SetKindConntrackState:\n\t\treturn nftables.TypeCTState\n\tcase SetKindICMPType:\n\t\treturn nftables.TypeICMPType\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown set kind: %d\", set.Kind))\n\t}\n}\n\n// SetElements returns the set elements.\n//\n//nolint:gocyclo\nfunc (set NfTablesSet) SetElements() []nftables.SetElement {\n\tswitch set.Kind {\n\tcase SetKindIPv4, SetKindIPv6:\n\t\telements := make([]nftables.SetElement, 0, len(set.Addresses)*2)\n\n\t\tfor _, r := range set.Addresses {\n\t\t\tfromBin, _ := r.From().MarshalBinary() //nolint:errcheck // doesn't fail\n\n\t\t\telements = append(elements,\n\t\t\t\tnftables.SetElement{\n\t\t\t\t\tKey:         fromBin,\n\t\t\t\t\tIntervalEnd: false,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\t// r.To().Next() overflows for the max address (255.255.255.255 or ffff:...:ffff),\n\t\t\t// returning the zero Addr whose MarshalBinary() yields nil.\n\t\t\t// In that case, omit the interval-end element — nftables treats the absence\n\t\t\t// of an end boundary as extending to the maximum value.\n\t\t\tnext := r.To().Next()\n\t\t\tif next.IsValid() {\n\t\t\t\ttoBin, _ := next.MarshalBinary() //nolint:errcheck // doesn't fail\n\n\t\t\t\telements = append(elements, nftables.SetElement{\n\t\t\t\t\tKey:         toBin,\n\t\t\t\t\tIntervalEnd: true,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn elements\n\tcase SetKindPort:\n\t\tports := mergeAdjacentPorts(set.Ports)\n\n\t\telements := make([]nftables.SetElement, 0, len(ports))\n\n\t\tfor _, p := range ports {\n\t\t\tfrom := binaryutil.BigEndian.PutUint16(p[0])\n\n\t\t\telements = append(elements,\n\t\t\t\tnftables.SetElement{\n\t\t\t\t\tKey:         from,\n\t\t\t\t\tIntervalEnd: false,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\t// handle overflow of p[1]+1 for the max port 65535, as binaryutil.BigEndian.PutUint16(65536) returns 0\n\t\t\tif p[1] != 65535 {\n\t\t\t\tto := binaryutil.BigEndian.PutUint16(p[1] + 1)\n\n\t\t\t\telements = append(elements,\n\t\t\t\t\tnftables.SetElement{\n\t\t\t\t\t\tKey:         to,\n\t\t\t\t\t\tIntervalEnd: true,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\treturn elements\n\tcase SetKindIfName:\n\t\telements := make([]nftables.SetElement, 0, len(set.Strings))\n\n\t\tfor _, s := range set.Strings {\n\t\t\telements = append(elements,\n\t\t\t\tnftables.SetElement{\n\t\t\t\t\tKey: s,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn elements\n\tcase SetKindConntrackState:\n\t\telements := make([]nftables.SetElement, 0, len(set.ConntrackStates))\n\n\t\tfor _, s := range set.ConntrackStates {\n\t\t\telements = append(elements,\n\t\t\t\tnftables.SetElement{\n\t\t\t\t\tKey: binaryutil.NativeEndian.PutUint32(uint32(s)),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn elements\n\tcase SetKindICMPType:\n\t\treturn xslices.Map(set.ICMPTypes, func(t nethelpers.ICMPType) nftables.SetElement {\n\t\t\treturn nftables.SetElement{\n\t\t\t\tKey: []byte{byte(t)},\n\t\t\t}\n\t\t})\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown set kind: %d\", set.Kind))\n\t}\n}\n\nfunc mergeAdjacentPorts(in [][2]uint16) [][2]uint16 {\n\tports := slices.Clone(in)\n\n\tslices.SortFunc(ports, func(a, b [2]uint16) int {\n\t\t// sort by the lower bound of the range, assume no overlap\n\t\treturn cmp.Compare(a[0], b[0])\n\t})\n\n\tfor i := 0; i < len(ports)-1; {\n\t\tif ports[i][1]+1 >= ports[i+1][0] {\n\t\t\tports[i][1] = ports[i+1][1]\n\t\t\tports = append(ports[:i+1], ports[i+2:]...)\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn ports\n}\n\n// NfTablesCompiled is a compiled representation of the rule.\ntype NfTablesCompiled struct {\n\tRules [][]expr.Any\n\tSets  []NfTablesSet\n}\n\nvar (\n\tmatchV4 = []expr.Any{\n\t\t// Store protocol type to register 1\n\t\t&expr.Meta{\n\t\t\tKey:      expr.MetaKeyNFPROTO,\n\t\t\tRegister: 1,\n\t\t},\n\t\t// Match IP Family\n\t\t&expr.Cmp{\n\t\t\tOp:       expr.CmpOpEq,\n\t\t\tRegister: 1,\n\t\t\tData:     []byte{byte(nftables.TableFamilyIPv4)},\n\t\t},\n\t}\n\n\tmatchV6 = []expr.Any{\n\t\t// Store protocol type to register 1\n\t\t&expr.Meta{\n\t\t\tKey:      expr.MetaKeyNFPROTO,\n\t\t\tRegister: 1,\n\t\t},\n\t\t// Match IP Family\n\t\t&expr.Cmp{\n\t\t\tOp:       expr.CmpOpEq,\n\t\t\tRegister: 1,\n\t\t\tData:     []byte{byte(nftables.TableFamilyIPv6)},\n\t\t},\n\t}\n\n\tfirstIPv4 = netip.MustParseAddr(\"0.0.0.0\")\n\tlastIPv4  = netip.MustParseAddr(\"255.255.255.255\")\n\n\tfirstIPv6 = netip.MustParseAddr(\"::\")\n\tlastIPv6  = netip.MustParseAddr(\"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff\")\n)\n\n// Compile translates the rule into the set of nftables instructions.\n//\n//nolint:gocyclo,cyclop\nfunc (a nftablesRule) Compile() (*NfTablesCompiled, error) {\n\tvar (\n\t\t// common for ipv4 & ipv6 expression, pre & post\n\t\trulePre  []expr.Any\n\t\trulePost []expr.Any\n\t\t// speficic for ipv4 & ipv6 expression\n\t\trule4, rule6 []expr.Any\n\n\t\tresult NfTablesCompiled\n\t)\n\n\tmatchIfNames := func(operator nethelpers.MatchOperator, ifnames []string) {\n\t\tif len(ifnames) == 1 {\n\t\t\trulePre = append(rulePre,\n\t\t\t\t// [ cmp eq/neq reg 1 <ifname> ]\n\t\t\t\t&expr.Cmp{\n\t\t\t\t\tOp:       expr.CmpOp(operator),\n\t\t\t\t\tRegister: 1,\n\t\t\t\t\tData:     ifname(ifnames[0]),\n\t\t\t\t},\n\t\t\t)\n\t\t} else {\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:    SetKindIfName,\n\t\t\t\t\tStrings: xslices.Map(ifnames, ifname),\n\t\t\t\t})\n\n\t\t\trulePre = append(rulePre,\n\t\t\t\t// Match from target set\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t\tInvert:         operator == nethelpers.OperatorNotEqual,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\tif a.NfTablesRule.MatchIIfName != nil {\n\t\tmatch := a.NfTablesRule.MatchIIfName\n\n\t\trulePre = append(rulePre,\n\t\t\t// [ meta load iifname => reg 1 ]\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyIIFNAME,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t)\n\n\t\tmatchIfNames(match.Operator, match.InterfaceNames)\n\t}\n\n\tif a.NfTablesRule.MatchOIfName != nil {\n\t\tmatch := a.NfTablesRule.MatchOIfName\n\n\t\trulePre = append(rulePre,\n\t\t\t// [ meta load oifname => reg 1 ]\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyOIFNAME,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t)\n\n\t\tmatchIfNames(match.Operator, match.InterfaceNames)\n\t}\n\n\tif a.NfTablesRule.MatchMark != nil {\n\t\tmatch := a.NfTablesRule.MatchMark\n\n\t\trulePre = append(rulePre,\n\t\t\t// [ meta load mark => reg 1 ]\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyMARK,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t\t// Mask the mark with the configured mask:\n\t\t\t//  R1 = R1 & mask ^ xor\n\t\t\t&expr.Bitwise{\n\t\t\t\tSourceRegister: 1,\n\t\t\t\tDestRegister:   1,\n\t\t\t\tLen:            4,\n\t\t\t\tXor:            binaryutil.NativeEndian.PutUint32(match.Xor),\n\t\t\t\tMask:           binaryutil.NativeEndian.PutUint32(match.Mask),\n\t\t\t},\n\t\t\t// Compare the masked firewall mark with expected value\n\t\t\t&expr.Cmp{\n\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     binaryutil.NativeEndian.PutUint32(match.Value),\n\t\t\t},\n\t\t)\n\t}\n\n\tif a.NfTablesRule.MatchConntrackState != nil {\n\t\tmatch := a.NfTablesRule.MatchConntrackState\n\n\t\tif len(match.States) == 1 {\n\t\t\trulePre = append(rulePre,\n\t\t\t\t// [ ct load state => reg 1 ]\n\t\t\t\t&expr.Ct{\n\t\t\t\t\tKey:      expr.CtKeySTATE,\n\t\t\t\t\tRegister: 1,\n\t\t\t\t},\n\t\t\t\t// [ bitwise reg 1 = ( reg 1 & state ) ^ 0x00000000 ]\n\t\t\t\t&expr.Bitwise{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\tLen:            4,\n\t\t\t\t\tMask:           binaryutil.NativeEndian.PutUint32(uint32(match.States[0])),\n\t\t\t\t\tXor:            []byte{0x0, 0x0, 0x0, 0x0},\n\t\t\t\t},\n\t\t\t\t// [ cmp neq reg 1 0x00000000 ]\n\t\t\t\t&expr.Cmp{\n\t\t\t\t\tOp:       expr.CmpOpNeq,\n\t\t\t\t\tRegister: 1,\n\t\t\t\t\tData:     []byte{0x0, 0x0, 0x0, 0x0},\n\t\t\t\t},\n\t\t\t)\n\t\t} else {\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:            SetKindConntrackState,\n\t\t\t\t\tConntrackStates: match.States,\n\t\t\t\t})\n\n\t\t\trulePre = append(rulePre,\n\t\t\t\t// [ ct load state => reg 1 ]\n\t\t\t\t&expr.Ct{\n\t\t\t\t\tKey:      expr.CtKeySTATE,\n\t\t\t\t\tRegister: 1,\n\t\t\t\t},\n\t\t\t\t// [ lookup reg 1 set <set> ]\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\taddressMatchExpression := func(match *network.NfTablesAddressMatch, label string, offV4, offV6 uint32) error {\n\t\tipSet, err := BuildIPSet(match.IncludeSubnets, match.ExcludeSubnets)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to build IPSet for %s address match: %w\", label, err)\n\t\t}\n\n\t\tv4Set, v6Set := SplitIPSet(ipSet)\n\n\t\tif v4Set == nil && v6Set == nil && !match.Invert {\n\t\t\t// this rule doesn't match anything\n\t\t\treturn os.ErrNotExist\n\t\t}\n\n\t\tv4SetCoversAll := len(v4Set) == 1 && v4Set[0].From() == firstIPv4 && v4Set[0].To() == lastIPv4\n\t\tv6SetCoversAll := len(v6Set) == 1 && v6Set[0].From() == firstIPv6 && v6Set[0].To() == lastIPv6\n\n\t\tif v4SetCoversAll && v6SetCoversAll && match.Invert {\n\t\t\t// this rule doesn't match anything\n\t\t\treturn os.ErrNotExist\n\t\t}\n\n\t\tswitch { //nolint:dupl\n\t\tcase v4SetCoversAll && !match.Invert, match.Invert && v4Set == nil:\n\t\t\t// match any v4 IP\n\t\t\tif rule4 == nil {\n\t\t\t\trule4 = []expr.Any{}\n\t\t\t}\n\t\tcase !v4SetCoversAll && match.Invert, !match.Invert && v4Set != nil:\n\t\t\t// match specific v4 IPs\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:      SetKindIPv4,\n\t\t\t\t\tAddresses: v4Set,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\trule4 = append(rule4,\n\t\t\t\t// Store the destination IP address to register 1\n\t\t\t\t&expr.Payload{\n\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\tOffset:       offV4,\n\t\t\t\t\tLen:          4,\n\t\t\t\t},\n\t\t\t\t// Match from target set\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t\tInvert:         match.Invert,\n\t\t\t\t},\n\t\t\t)\n\t\tdefault: // otherwise skip generating v4 rule, as it doesn't match anything\n\t\t}\n\n\t\tswitch { //nolint:dupl\n\t\tcase v6SetCoversAll && !match.Invert, match.Invert && v6Set == nil:\n\t\t\t// match any v6 IP\n\t\t\tif rule6 == nil {\n\t\t\t\trule6 = []expr.Any{}\n\t\t\t}\n\t\tcase !v6SetCoversAll && match.Invert, !match.Invert && v6Set != nil:\n\t\t\t// match specific v6 IPs\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:      SetKindIPv6,\n\t\t\t\t\tAddresses: v6Set,\n\t\t\t\t})\n\n\t\t\trule6 = append(rule6,\n\t\t\t\t// Store the destination IP address to register 1\n\t\t\t\t&expr.Payload{\n\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\tOffset:       offV6,\n\t\t\t\t\tLen:          16,\n\t\t\t\t},\n\t\t\t\t// Match from target set\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t\tInvert:         match.Invert,\n\t\t\t\t},\n\t\t\t)\n\t\tdefault: // otherwise skip generating v6 rule, as it doesn't match anything\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif a.NfTablesRule.MatchSourceAddress != nil {\n\t\tmatch := a.NfTablesRule.MatchSourceAddress\n\n\t\tif err := addressMatchExpression(match, \"source\", 12, 8); err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn &NfTablesCompiled{}, nil\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif a.NfTablesRule.MatchDestinationAddress != nil {\n\t\tmatch := a.NfTablesRule.MatchDestinationAddress\n\n\t\tif err := addressMatchExpression(match, \"destination\", 16, 24); err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn &NfTablesCompiled{}, nil\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif a.NfTablesRule.MatchLayer4 != nil {\n\t\tmatch := a.NfTablesRule.MatchLayer4\n\n\t\trulePre = append(rulePre,\n\t\t\t// [ meta load l4proto => reg 1 ]\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyL4PROTO,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t\t// [ cmp eq reg 1 <protocol> ]\n\t\t\t&expr.Cmp{\n\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     []byte{byte(match.Protocol)},\n\t\t\t},\n\t\t)\n\n\t\tportMatch := func(off uint32, ports []network.PortRange) {\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:  SetKindPort,\n\t\t\t\t\tPorts: xslices.Map(ports, func(r network.PortRange) [2]uint16 { return [2]uint16{r.Lo, r.Hi} }),\n\t\t\t\t},\n\t\t\t)\n\n\t\t\trulePost = append(rulePost,\n\t\t\t\t// [ payload load 2b @ transport header + <offset> => reg 1 ]\n\t\t\t\t&expr.Payload{\n\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\tOffset:       off,\n\t\t\t\t\tLen:          2,\n\t\t\t\t},\n\t\t\t\t// [ lookup reg 1 set <set> ]\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\tif match.MatchSourcePort != nil {\n\t\t\tportMatch(0, match.MatchSourcePort.Ranges)\n\t\t}\n\n\t\tif match.MatchDestinationPort != nil {\n\t\t\tportMatch(2, match.MatchDestinationPort.Ranges)\n\t\t}\n\n\t\tif match.MatchICMPType != nil {\n\t\t\tresult.Sets = append(result.Sets,\n\t\t\t\tNfTablesSet{\n\t\t\t\t\tKind:      SetKindICMPType,\n\t\t\t\t\tICMPTypes: match.MatchICMPType.Types,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\trulePost = append(rulePost,\n\t\t\t\t// [ payload load 1b @ transport header + 0 => reg 1 ]\n\t\t\t\t&expr.Payload{\n\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\tOffset:       0,\n\t\t\t\t\tLen:          1,\n\t\t\t\t},\n\t\t\t\t// [ lookup reg 1 set <set> ]\n\t\t\t\t&expr.Lookup{\n\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\tSetID:          uint32(len(result.Sets) - 1), // reference will be fixed up by the controller\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\tif a.NfTablesRule.MatchLimit != nil {\n\t\tmatch := a.NfTablesRule.MatchLimit\n\n\t\trulePost = append(rulePost,\n\t\t\t// [ limit rate <rate> ]\n\t\t\t&expr.Limit{\n\t\t\t\tType:  expr.LimitTypePkts,\n\t\t\t\tRate:  match.PacketRatePerSecond,\n\t\t\t\tBurst: uint32(match.PacketRatePerSecond),\n\t\t\t\tUnit:  expr.LimitTimeSecond,\n\t\t\t},\n\t\t)\n\t}\n\n\tclampMSS := func(family nftables.TableFamily, mtu uint16) []expr.Any {\n\t\tvar mss uint16\n\n\t\tswitch family { //nolint:exhaustive\n\t\tcase nftables.TableFamilyIPv4:\n\t\t\tmss = mtu - (IPv4HeaderLen + TCPHeaderLen + TCPOptionsLen) // TCP + IPv4 overhead\n\t\tcase nftables.TableFamilyIPv6:\n\t\t\tmss = mtu - (IPv6HeaderLen + TCPHeaderLen + TCPOptionsLen) // TCP + IPv6 overhead\n\t\tdefault:\n\t\t\tpanic(\"unexpected IP family\")\n\t\t}\n\n\t\treturn []expr.Any{\n\t\t\t// Load the L4 protocol into register 1\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyL4PROTO,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t\t// Match TCP Family\n\t\t\t&expr.Cmp{\n\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     []byte{unix.IPPROTO_TCP},\n\t\t\t},\n\t\t\t// [ payload load 1b @ transport header + 13 => reg 1 ]\n\t\t\t&expr.Payload{\n\t\t\t\tDestRegister: 1,\n\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\tOffset:       13,\n\t\t\t\tLen:          1,\n\t\t\t},\n\t\t\t// [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]\n\t\t\t&expr.Bitwise{\n\t\t\t\tDestRegister:   1,\n\t\t\t\tSourceRegister: 1,\n\t\t\t\tLen:            1,\n\t\t\t\tMask:           []byte{0x02 | 0x04},\n\t\t\t\tXor:            []byte{0x00},\n\t\t\t},\n\t\t\t// [ cmp eq reg 1 0x00000002 ]\n\t\t\t&expr.Cmp{\n\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     []byte{0x02},\n\t\t\t},\n\t\t\t// [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]\n\t\t\t&expr.Exthdr{\n\t\t\t\tDestRegister: 1,\n\t\t\t\tType:         2,\n\t\t\t\tOffset:       2,\n\t\t\t\tLen:          2,\n\t\t\t\tOp:           expr.ExthdrOpTcpopt,\n\t\t\t},\n\t\t\t// [ cmp gte reg 1 MTU ]\n\t\t\t&expr.Cmp{\n\t\t\t\tOp:       expr.CmpOpGt,\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     binaryutil.BigEndian.PutUint16(mss),\n\t\t\t},\n\t\t\t// [ immediate reg 1 MTU ]\n\t\t\t&expr.Immediate{\n\t\t\t\tRegister: 1,\n\t\t\t\tData:     binaryutil.BigEndian.PutUint16(mss),\n\t\t\t},\n\t\t\t// [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]\n\t\t\t&expr.Exthdr{\n\t\t\t\tSourceRegister: 1,\n\t\t\t\tType:           2,\n\t\t\t\tOffset:         2,\n\t\t\t\tLen:            2,\n\t\t\t\tOp:             expr.ExthdrOpTcpopt,\n\t\t\t},\n\t\t}\n\t}\n\n\tif a.NfTablesRule.ClampMSS != nil {\n\t\tif rule4 != nil {\n\t\t\trule4 = append(rule4, clampMSS(nftables.TableFamilyIPv4, a.NfTablesRule.ClampMSS.MTU)...)\n\t\t}\n\n\t\tif rule6 != nil {\n\t\t\trule6 = append(rule6, clampMSS(nftables.TableFamilyIPv6, a.NfTablesRule.ClampMSS.MTU)...)\n\t\t}\n\t}\n\n\tif a.NfTablesRule.SetMark != nil {\n\t\tset := a.NfTablesRule.SetMark\n\n\t\trulePost = append(rulePost,\n\t\t\t// Load the current packet mark into register 1\n\t\t\t&expr.Meta{\n\t\t\t\tKey:      expr.MetaKeyMARK,\n\t\t\t\tRegister: 1,\n\t\t\t},\n\t\t\t// Calculate the new mark value in register 1\n\t\t\t&expr.Bitwise{\n\t\t\t\tSourceRegister: 1,\n\t\t\t\tDestRegister:   1,\n\t\t\t\tLen:            4,\n\t\t\t\tXor:            binaryutil.NativeEndian.PutUint32(set.Xor),\n\t\t\t\tMask:           binaryutil.NativeEndian.PutUint32(set.Mask),\n\t\t\t},\n\t\t\t// Set firewall mark to the value computed in register 1\n\t\t\t&expr.Meta{\n\t\t\t\tKey:            expr.MetaKeyMARK,\n\t\t\t\tSourceRegister: true,\n\t\t\t\tRegister:       1,\n\t\t\t},\n\t\t)\n\t}\n\n\tif a.NfTablesRule.AnonCounter {\n\t\trulePost = append(rulePost,\n\t\t\t// [ counter ]\n\t\t\t&expr.Counter{},\n\t\t)\n\t}\n\n\tif a.NfTablesRule.Verdict != nil {\n\t\trulePost = append(rulePost,\n\t\t\t// [ verdict accept|drop ]\n\t\t\t&expr.Verdict{\n\t\t\t\tKind: expr.VerdictKind(*a.NfTablesRule.Verdict),\n\t\t\t},\n\t\t)\n\t}\n\n\t// Build v4/v6 rules as requested.\n\t//\n\t// If there's no IPv4/IPv6 part, generate a single rule.\n\t// If there's a specific IPv4/IPv6 part, generate a rule per IP version.\n\tswitch {\n\tcase rule4 == nil && rule6 == nil && rulePre == nil && rulePost == nil:\n\t\t// nothing\n\tcase rule4 == nil && rule6 == nil:\n\t\tresult.Rules = [][]expr.Any{append(rulePre, rulePost...)}\n\tcase rule4 != nil && rule6 == nil:\n\t\tresult.Rules = [][]expr.Any{\n\t\t\tslices.Concat(rulePre, matchV4, rule4, rulePost),\n\t\t}\n\tcase rule4 == nil && rule6 != nil:\n\t\tresult.Rules = [][]expr.Any{\n\t\t\tslices.Concat(rulePre, matchV6, rule6, rulePost),\n\t\t}\n\tcase rule4 != nil && rule6 != nil:\n\t\tresult.Rules = [][]expr.Any{\n\t\t\tslices.Concat(rulePre, matchV4, rule4, rulePost),\n\t\t\tslices.Concat(rulePre, matchV6, rule6, rulePost),\n\t\t}\n\t}\n\n\treturn &result, nil\n}\n\nfunc ifname(name string) []byte {\n\tb := make([]byte, 16)\n\tcopy(b, []byte(name))\n\n\treturn b\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/nftables_rule_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/google/nftables\"\n\t\"github.com/google/nftables/expr\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go4.org/netipx\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\tnetworkres \"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestNfTablesRuleCompile(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tspec networkres.NfTablesRule\n\n\t\texpectedRules [][]expr.Any\n\t\texpectedSets  []network.NfTablesSet\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"match oifname\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchOIfName: &networkres.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\"eth0\"},\n\t\t\t\t\tOperator:       nethelpers.OperatorEqual,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte(\"eth0\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match iifname\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchIIfName: &networkres.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\"lo\"},\n\t\t\t\t\tOperator:       nethelpers.OperatorNotEqual,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpNeq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte(\"lo\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match multiple iifname\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchIIfName: &networkres.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\"siderolink\", \"kubespan\"},\n\t\t\t\t\tOperator:       nethelpers.OperatorEqual,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind: network.SetKindIfName,\n\t\t\t\t\tStrings: [][]byte{\n\t\t\t\t\t\t[]byte(\"siderolink\\000\\000\\000\\000\\000\\000\"),\n\t\t\t\t\t\t[]byte(\"kubespan\\000\\000\\000\\000\\000\\000\\000\\000\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"verdict accept\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchOIfName: &networkres.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\"eth0\"},\n\t\t\t\t\tOperator:       nethelpers.OperatorNotEqual,\n\t\t\t\t},\n\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpNeq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte(\"eth0\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\"),\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{Kind: expr.VerdictAccept},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match and set mark\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchMark: &networkres.NfTablesMark{\n\t\t\t\t\tMask:  0xff00ffff,\n\t\t\t\t\tXor:   0x00ff0000,\n\t\t\t\t\tValue: 0x00ee0000,\n\t\t\t\t},\n\t\t\t\tSetMark: &networkres.NfTablesMark{\n\t\t\t\t\tMask: 0x0000ffff,\n\t\t\t\t\tXor:  0xffff0000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyMARK, Register: 1},\n\t\t\t\t\t&expr.Bitwise{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\t\tLen:            4,\n\t\t\t\t\t\tXor:            []byte{0x00, 0x00, 0xff, 0x00},\n\t\t\t\t\t\tMask:           []byte{0xff, 0xff, 0x00, 0xff},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x00, 0x00, 0xee, 0x00},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyMARK, Register: 1},\n\t\t\t\t\t&expr.Bitwise{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\t\tLen:            4,\n\t\t\t\t\t\tXor:            []byte{0x00, 0x00, 0xff, 0xff},\n\t\t\t\t\t\tMask:           []byte{0xff, 0xff, 0x00, 0x00},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyMARK, SourceRegister: true, Register: 1},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match on empty source address\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchSourceAddress: &networkres.NfTablesAddressMatch{},\n\t\t\t\tVerdict:            new(nethelpers.VerdictDrop),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match on v4 source address\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchSourceAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t},\n\t\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.4.0/24\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv4)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\t\tOffset:       12,\n\t\t\t\t\t\tLen:          4,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind:      network.SetKindIPv4,\n\t\t\t\t\tAddresses: []netipx.IPRange{netipx.MustParseIPRange(\"192.168.0.0-192.168.3.255\"), netipx.MustParseIPRange(\"192.168.5.0-192.168.255.255\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match on v6 source and destination addresses\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchSourceAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"2001::/16\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMatchDestinationAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"20fe::/16\"),\n\t\t\t\t\t},\n\t\t\t\t\tInvert: true,\n\t\t\t\t},\n\t\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv4)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv6)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\t\tOffset:       8,\n\t\t\t\t\t\tLen:          16,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\t\tOffset:       24,\n\t\t\t\t\t\tLen:          16,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          1,\n\t\t\t\t\t\tInvert:         true,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind:      network.SetKindIPv6,\n\t\t\t\t\tAddresses: []netipx.IPRange{netipx.MustParseIPRange(\"2001::-2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKind:      network.SetKindIPv6,\n\t\t\t\t\tAddresses: []netipx.IPRange{netipx.MustParseIPRange(\"20fe::-20fe:ffff:ffff:ffff:ffff:ffff:ffff:ffff\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match on v6 destination addresses\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchDestinationAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"20fe::/16\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv6)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\t\tOffset:       24,\n\t\t\t\t\t\tLen:          16,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind:      network.SetKindIPv6,\n\t\t\t\t\tAddresses: []netipx.IPRange{netipx.MustParseIPRange(\"20fe::-20fe:ffff:ffff:ffff:ffff:ffff:ffff:ffff\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match on any v6 address\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchSourceAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.37.45/32\"),\n\t\t\t\t\t},\n\t\t\t\t\tInvert: true,\n\t\t\t\t},\n\t\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv4)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseNetworkHeader,\n\t\t\t\t\t\tOffset:       12,\n\t\t\t\t\t\tLen:          4,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t\tInvert:         true,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv6)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Verdict{\n\t\t\t\t\t\tKind: expr.VerdictDrop,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind:      network.SetKindIPv4,\n\t\t\t\t\tAddresses: []netipx.IPRange{netipx.MustParseIPRange(\"192.168.37.45-192.168.37.45\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{ //nolint:dupl\n\t\t\tname: \"clamp MSS v4\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchDestinationAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClampMSS: &networkres.NfTablesClampMSS{\n\t\t\t\t\tMTU: 1280,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv4)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Meta{\n\t\t\t\t\t\tKey:      expr.MetaKeyL4PROTO,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{6},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\t\tOffset:       13,\n\t\t\t\t\t\tLen:          1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Bitwise{\n\t\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tLen:            1,\n\t\t\t\t\t\tMask:           []byte{0x02 | 0x04},\n\t\t\t\t\t\tXor:            []byte{0x00},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x02},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Exthdr{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tType:         2,\n\t\t\t\t\t\tOffset:       2,\n\t\t\t\t\t\tLen:          2,\n\t\t\t\t\t\tOp:           expr.ExthdrOpTcpopt,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpGt,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x04, 0xcc},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Immediate{\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x04, 0xcc},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Exthdr{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tType:           2,\n\t\t\t\t\t\tOffset:         2,\n\t\t\t\t\t\tLen:            2,\n\t\t\t\t\t\tOp:             expr.ExthdrOpTcpopt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{ //nolint:dupl\n\t\t\tname: \"clamp MSS v6\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchDestinationAddress: &networkres.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"::/0\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClampMSS: &networkres.NfTablesClampMSS{\n\t\t\t\t\tMTU: 1280,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyNFPROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{byte(nftables.TableFamilyIPv6)},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Meta{\n\t\t\t\t\t\tKey:      expr.MetaKeyL4PROTO,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{6},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\t\tOffset:       13,\n\t\t\t\t\t\tLen:          1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Bitwise{\n\t\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tLen:            1,\n\t\t\t\t\t\tMask:           []byte{0x02 | 0x04},\n\t\t\t\t\t\tXor:            []byte{0x00},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x02},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Exthdr{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tType:         2,\n\t\t\t\t\t\tOffset:       2,\n\t\t\t\t\t\tLen:          2,\n\t\t\t\t\t\tOp:           expr.ExthdrOpTcpopt,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpGt,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x04, 0xb8},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Immediate{\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x04, 0xb8},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Exthdr{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tType:           2,\n\t\t\t\t\t\tOffset:         2,\n\t\t\t\t\t\tLen:            2,\n\t\t\t\t\t\tOp:             expr.ExthdrOpTcpopt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match L4 proto\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchLayer4: &networkres.NfTablesLayer4Match{\n\t\t\t\t\tProtocol: nethelpers.ProtocolUDP,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x11},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match L4 proto and src port\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchLayer4: &networkres.NfTablesLayer4Match{\n\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\tMatchSourcePort: &networkres.NfTablesPortMatch{\n\t\t\t\t\t\tRanges: []networkres.PortRange{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tLo: 2000,\n\t\t\t\t\t\t\t\tHi: 2000,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tLo: 1000,\n\t\t\t\t\t\t\t\tHi: 1025,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x6},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\t\tOffset:       0,\n\t\t\t\t\t\tLen:          2,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind: network.SetKindPort,\n\t\t\t\t\tPorts: [][2]uint16{\n\t\t\t\t\t\t{2000, 2000},\n\t\t\t\t\t\t{1000, 1025},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"match L4 proto and dst port\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchLayer4: &networkres.NfTablesLayer4Match{\n\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\tMatchDestinationPort: &networkres.NfTablesPortMatch{\n\t\t\t\t\t\tRanges: []networkres.PortRange{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tLo: 2000,\n\t\t\t\t\t\t\t\tHi: 2000,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x6},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\t\tOffset:       2,\n\t\t\t\t\t\tLen:          2,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind: network.SetKindPort,\n\t\t\t\t\tPorts: [][2]uint16{\n\t\t\t\t\t\t{2000, 2000},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"limit\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchLimit: &networkres.NfTablesLimitMatch{\n\t\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Limit{\n\t\t\t\t\t\tType:  expr.LimitTypePkts,\n\t\t\t\t\t\tRate:  5,\n\t\t\t\t\t\tBurst: 5,\n\t\t\t\t\t\tUnit:  expr.LimitTimeSecond,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"counter\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tAnonCounter: true,\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Counter{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ct state\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchConntrackState: &networkres.NfTablesConntrackStateMatch{\n\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\tnethelpers.ConntrackStateInvalid,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Ct{\n\t\t\t\t\t\tKey:      expr.CtKeySTATE,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Bitwise{\n\t\t\t\t\t\tDestRegister:   1,\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tLen:            4,\n\t\t\t\t\t\tMask:           []byte{0x01, 0x00, 0x00, 0x00},\n\t\t\t\t\t\tXor:            []byte{0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpNeq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ct states\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchConntrackState: &networkres.NfTablesConntrackStateMatch{\n\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\tnethelpers.ConntrackStateRelated,\n\t\t\t\t\t\tnethelpers.ConntrackStateEstablished,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Ct{\n\t\t\t\t\t\tKey:      expr.CtKeySTATE,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind: network.SetKindConntrackState,\n\t\t\t\t\tConntrackStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\tnethelpers.ConntrackStateRelated,\n\t\t\t\t\t\tnethelpers.ConntrackStateEstablished,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"icmp packet type\",\n\t\t\tspec: networkres.NfTablesRule{\n\t\t\t\tMatchLayer4: &networkres.NfTablesLayer4Match{\n\t\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\t\tMatchICMPType: &networkres.NfTablesICMPTypeMatch{\n\t\t\t\t\t\tTypes: []nethelpers.ICMPType{\n\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampRequest,\n\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampReply,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedRules: [][]expr.Any{\n\t\t\t\t{\n\t\t\t\t\t&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},\n\t\t\t\t\t&expr.Cmp{\n\t\t\t\t\t\tOp:       expr.CmpOpEq,\n\t\t\t\t\t\tRegister: 1,\n\t\t\t\t\t\tData:     []byte{0x1},\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Payload{\n\t\t\t\t\t\tDestRegister: 1,\n\t\t\t\t\t\tBase:         expr.PayloadBaseTransportHeader,\n\t\t\t\t\t\tOffset:       0,\n\t\t\t\t\t\tLen:          1,\n\t\t\t\t\t},\n\t\t\t\t\t&expr.Lookup{\n\t\t\t\t\t\tSourceRegister: 1,\n\t\t\t\t\t\tSetID:          0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedSets: []network.NfTablesSet{\n\t\t\t\t{\n\t\t\t\t\tKind: network.SetKindICMPType,\n\t\t\t\t\tICMPTypes: []nethelpers.ICMPType{\n\t\t\t\t\t\tnethelpers.ICMPTypeTimestampRequest,\n\t\t\t\t\t\tnethelpers.ICMPTypeTimestampReply,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tresult, err := network.NfTablesRule(&test.spec).Compile()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expectedRules, result.Rules)\n\t\t\tassert.Equal(t, test.expectedSets, result.Sets)\n\t\t})\n\t}\n}\n\nfunc TestNftablesSet(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tset network.NfTablesSet\n\n\t\texpectedKeyType  nftables.SetDatatype\n\t\texpectedInterval bool\n\t\texpectedData     []nftables.SetElement\n\t}{\n\t\t{\n\t\t\tname: \"ports\",\n\n\t\t\tset: network.NfTablesSet{\n\t\t\t\tKind: network.SetKindPort,\n\t\t\t\tPorts: [][2]uint16{\n\t\t\t\t\t{443, 443},\n\t\t\t\t\t{80, 81},\n\t\t\t\t\t{5000, 5000},\n\t\t\t\t\t{5001, 5001},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedKeyType:  nftables.TypeInetService,\n\t\t\texpectedInterval: true,\n\t\t\texpectedData: []nftables.SetElement{ // network byte order\n\t\t\t\t{Key: []uint8{0x0, 80}, IntervalEnd: false}, // 80 - 81\n\t\t\t\t{Key: []uint8{0x0, 82}, IntervalEnd: true},\n\t\t\t\t{Key: []uint8{0x1, 0xbb}, IntervalEnd: false}, // 443-443\n\t\t\t\t{Key: []uint8{0x1, 0xbc}, IntervalEnd: true},\n\t\t\t\t{Key: []uint8{0x13, 0x88}, IntervalEnd: false}, // 5000-5001\n\t\t\t\t{Key: []uint8{0x13, 0x8a}, IntervalEnd: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ports with overflow\",\n\n\t\t\tset: network.NfTablesSet{\n\t\t\t\tKind: network.SetKindPort,\n\t\t\t\tPorts: [][2]uint16{\n\t\t\t\t\t{65530, 65535},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedKeyType:  nftables.TypeInetService,\n\t\t\texpectedInterval: true,\n\t\t\texpectedData: []nftables.SetElement{ // network byte order\n\t\t\t\t{Key: []uint8{0xff, 0xfa}, IntervalEnd: false}, // 65530-inf\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"regular ip range\",\n\n\t\t\tset: network.NfTablesSet{\n\t\t\t\tKind: network.SetKindIPv4,\n\t\t\t\tAddresses: []netipx.IPRange{\n\t\t\t\t\tnetipx.MustParseIPRange(\"10.0.0.0-10.0.0.255\"),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedKeyType:  nftables.TypeIPAddr,\n\t\t\texpectedInterval: true,\n\t\t\texpectedData: []nftables.SetElement{ // network byte order\n\t\t\t\t{Key: []uint8{10, 0, 0, 0}, IntervalEnd: false},\n\t\t\t\t{Key: []uint8{10, 0, 1, 0}, IntervalEnd: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ip range with overflow\",\n\n\t\t\tset: network.NfTablesSet{\n\t\t\t\tKind: network.SetKindIPv4,\n\t\t\t\tAddresses: []netipx.IPRange{\n\t\t\t\t\tnetipx.MustParseIPRange(\"10.0.0.0-255.255.255.255\"),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedKeyType:  nftables.TypeIPAddr,\n\t\t\texpectedInterval: true,\n\t\t\texpectedData: []nftables.SetElement{ // network byte order\n\t\t\t\t{Key: []uint8{10, 0, 0, 0}, IntervalEnd: false}, // 10.0.0.0-inf\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expectedKeyType, test.set.KeyType())\n\t\t\tassert.Equal(t, test.expectedInterval, test.set.IsInterval())\n\t\t\tassert.Equal(t, test.expectedData, test.set.SetElements())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/vlan_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"encoding/binary\"\n\n\t\"github.com/mdlayher/netlink\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// VLANSpec adapter provides encoding/decoding to netlink structures.\n//\n//nolint:revive,golint\nfunc VLANSpec(r *network.VLANSpec) vlanSpec {\n\treturn vlanSpec{\n\t\tVLANSpec: r,\n\t}\n}\n\ntype vlanSpec struct {\n\t*network.VLANSpec\n}\n\n// Encode the VLANSpec into netlink attributes.\nfunc (a vlanSpec) Encode() ([]byte, error) {\n\tvlan := a.VLANSpec\n\n\tencoder := netlink.NewAttributeEncoder()\n\n\tencoder.Uint16(unix.IFLA_VLAN_ID, vlan.VID)\n\n\tbuf := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(buf, uint16(vlan.Protocol))\n\tencoder.Bytes(unix.IFLA_VLAN_PROTOCOL, buf)\n\n\treturn encoder.Encode()\n}\n\n// Decode the VLANSpec from netlink attributes.\nfunc (a vlanSpec) Decode(data []byte) error {\n\tvlan := a.VLANSpec\n\n\tdecoder, err := netlink.NewAttributeDecoder(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor decoder.Next() {\n\t\tswitch decoder.Type() {\n\t\tcase unix.IFLA_VLAN_ID:\n\t\t\tvlan.VID = decoder.Uint16()\n\t\tcase unix.IFLA_VLAN_PROTOCOL:\n\t\t\tvlan.Protocol = nethelpers.VLANProtocol(binary.BigEndian.Uint16(decoder.Bytes()))\n\t\t}\n\t}\n\n\treturn decoder.Err()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/vlan_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestVLANSpec(t *testing.T) {\n\tspec := network.VLANSpec{\n\t\tVID:      25,\n\t\tProtocol: nethelpers.VLANProtocol8021AD,\n\t}\n\n\tb, err := networkadapter.VLANSpec(&spec).Encode()\n\trequire.NoError(t, err)\n\n\tvar decodedSpec network.VLANSpec\n\n\trequire.NoError(t, networkadapter.VLANSpec(&decodedSpec).Decode(b))\n\n\trequire.Equal(t, spec, decodedSpec)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/vrf_master_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/mdlayher/netlink\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// VRFMasterSpec adapter provides encoding/decoding to netlink structures.\n//\n//nolint:revive\nfunc VRFMasterSpec(r *network.VRFMasterSpec) vrfMaster {\n\treturn vrfMaster{\n\t\tVRFMasterSpec: r,\n\t}\n}\n\n// vrfMaster contains the vrf master spec and provides methods for encoding/decoding it to netlink structures.\ntype vrfMaster struct {\n\t*network.VRFMasterSpec\n}\n\n// Encode the VRFMasterSpec into netlink attributes.\nfunc (a vrfMaster) Encode() ([]byte, error) {\n\tvrf := a.VRFMasterSpec\n\n\tencoder := netlink.NewAttributeEncoder()\n\n\tencoder.Uint32(unix.IFLA_VRF_TABLE, uint32(vrf.Table))\n\n\treturn encoder.Encode()\n}\n\n// Decode the VRFMasterSpec from netlink attributes.\nfunc (a vrfMaster) Decode(data []byte) error {\n\tvrf := a.VRFMasterSpec\n\n\tdecoder, err := netlink.NewAttributeDecoder(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor decoder.Next() {\n\t\tif decoder.Type() == unix.IFLA_VRF_TABLE {\n\t\t\tvrf.Table = nethelpers.RoutingTable(decoder.Uint32())\n\t\t}\n\t}\n\n\treturn decoder.Err()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/vrf_master_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestVRFMasterSpec(t *testing.T) {\n\tspec := network.VRFMasterSpec{\n\t\tTable: 4294967295,\n\t}\n\n\tb, err := networkadapter.VRFMasterSpec(&spec).Encode()\n\trequire.NoError(t, err)\n\n\tvar decodedSpec network.VRFMasterSpec\n\n\trequire.NoError(t, networkadapter.VRFMasterSpec(&decodedSpec).Decode(b))\n\n\trequire.Equal(t, spec, decodedSpec)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/wireguard_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go4.org/netipx\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// WireguardSpec adapter provides encoding/decoding to netlink structures.\n//\n//nolint:revive,golint\nfunc WireguardSpec(r *network.WireguardSpec) wireguardSpec {\n\treturn wireguardSpec{\n\t\tWireguardSpec: r,\n\t}\n}\n\ntype wireguardSpec struct {\n\t*network.WireguardSpec\n}\n\n// Encode converts WireguardSpec to wgctrl.Config \"patch\" to adjust the config to match the spec.\n//\n// Both specs should be sorted.\n//\n// Encode produces a \"diff\" as *wgtypes.Config which when applied transitions `existing` configuration into\n// configuration `spec`.\n//\n//nolint:gocyclo,cyclop\nfunc (a wireguardSpec) Encode(existing *network.WireguardSpec) (*wgtypes.Config, error) {\n\tspec := a.WireguardSpec\n\n\tcfg := &wgtypes.Config{}\n\n\tif existing.PrivateKey != spec.PrivateKey {\n\t\tkey, err := wgtypes.ParseKey(spec.PrivateKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcfg.PrivateKey = &key\n\t}\n\n\tif existing.ListenPort != spec.ListenPort {\n\t\tcfg.ListenPort = &spec.ListenPort\n\t}\n\n\tif existing.FirewallMark != spec.FirewallMark {\n\t\tcfg.FirewallMark = &spec.FirewallMark\n\t}\n\n\t// perform a merge of two sorted list of peers producing diff\n\tl, r := 0, 0\n\n\tfor l < len(existing.Peers) || r < len(spec.Peers) {\n\t\taddPeer := func(peer *network.WireguardPeer) error {\n\t\t\tpubKey, err := wgtypes.ParseKey(peer.PublicKey)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tvar presharedKey *wgtypes.Key\n\n\t\t\tif peer.PresharedKey != \"\" {\n\t\t\t\tvar parsedKey wgtypes.Key\n\n\t\t\t\tparsedKey, err = wgtypes.ParseKey(peer.PresharedKey)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tpresharedKey = &parsedKey\n\t\t\t}\n\n\t\t\tvar endpoint *net.UDPAddr\n\n\t\t\tif peer.Endpoint != \"\" {\n\t\t\t\tendpoint, err = net.ResolveUDPAddr(\"\", peer.Endpoint)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcfg.Peers = append(cfg.Peers, wgtypes.PeerConfig{\n\t\t\t\tPublicKey:                   pubKey,\n\t\t\t\tEndpoint:                    endpoint,\n\t\t\t\tPresharedKey:                presharedKey,\n\t\t\t\tPersistentKeepaliveInterval: &peer.PersistentKeepaliveInterval,\n\t\t\t\tReplaceAllowedIPs:           true,\n\t\t\t\tAllowedIPs: xslices.Map(peer.AllowedIPs, func(peerIP netip.Prefix) net.IPNet {\n\t\t\t\t\treturn *netipx.PrefixIPNet(peerIP)\n\t\t\t\t}),\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}\n\n\t\tdeletePeer := func(peer *network.WireguardPeer) error {\n\t\t\tpubKey, err := wgtypes.ParseKey(peer.PublicKey)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcfg.Peers = append(cfg.Peers, wgtypes.PeerConfig{\n\t\t\t\tPublicKey: pubKey,\n\t\t\t\tRemove:    true,\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}\n\n\t\tvar left, right *network.WireguardPeer\n\n\t\tif l < len(existing.Peers) {\n\t\t\tleft = &existing.Peers[l]\n\t\t}\n\n\t\tif r < len(spec.Peers) {\n\t\t\tright = &spec.Peers[r]\n\t\t}\n\n\t\tswitch {\n\t\t// peer from the \"right\" (new spec) is missing in \"existing\" (left), add it\n\t\tcase left == nil || (right != nil && left.PublicKey > right.PublicKey):\n\t\t\tif err := addPeer(right); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tr++\n\t\t// peer from the \"left\" (existing) is missing in new spec (right), so it should be removed\n\t\tcase right == nil || (left != nil && left.PublicKey < right.PublicKey):\n\t\t\t// deleting peers from the existing\n\t\t\tif err := deletePeer(left); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tl++\n\t\t// peer public keys are equal, so either they are identical or peer should be replaced\n\t\tcase left.PublicKey == right.PublicKey:\n\t\t\tif !left.Equal(right) {\n\t\t\t\t// replace peer\n\t\t\t\tif err := addPeer(right); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tl++\n\t\t\tr++\n\t\t}\n\t}\n\n\treturn cfg, nil\n}\n\n// Decode spec from the device state.\nfunc (a wireguardSpec) Decode(dev *wgtypes.Device, isStatus bool) {\n\tspec := a.WireguardSpec\n\n\tif isStatus {\n\t\tspec.PublicKey = dev.PublicKey.String()\n\t} else {\n\t\tspec.PrivateKey = dev.PrivateKey.String()\n\t}\n\n\tspec.ListenPort = dev.ListenPort\n\tspec.FirewallMark = dev.FirewallMark\n\n\tspec.Peers = make([]network.WireguardPeer, len(dev.Peers))\n\n\tfor i := range spec.Peers {\n\t\tspec.Peers[i].PublicKey = dev.Peers[i].PublicKey.String()\n\n\t\tif dev.Peers[i].Endpoint != nil {\n\t\t\tspec.Peers[i].Endpoint = dev.Peers[i].Endpoint.String()\n\t\t}\n\n\t\tvar zeroKey wgtypes.Key\n\n\t\tif dev.Peers[i].PresharedKey != zeroKey {\n\t\t\tspec.Peers[i].PresharedKey = dev.Peers[i].PresharedKey.String()\n\t\t}\n\n\t\tspec.Peers[i].PersistentKeepaliveInterval = dev.Peers[i].PersistentKeepaliveInterval\n\t\tspec.Peers[i].AllowedIPs = xslices.Map(dev.Peers[i].AllowedIPs, func(peerIP net.IPNet) netip.Prefix {\n\t\t\tres, _ := netipx.FromStdIPNet(&peerIP)\n\n\t\t\treturn res\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/network/wireguard_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestWireguardSpecDecode(t *testing.T) {\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tpriv, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tpub1, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tpub2, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tvar spec network.WireguardSpec\n\n\t// decode in spec mode\n\tnetworkadapter.WireguardSpec(&spec).Decode(&wgtypes.Device{\n\t\tPrivateKey:   priv,\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t\tPeers: []wgtypes.Peer{\n\t\t\t{\n\t\t\t\tPublicKey:    pub1.PublicKey(),\n\t\t\t\tPresharedKey: priv,\n\t\t\t\tEndpoint: &net.UDPAddr{\n\t\t\t\t\tIP:   net.ParseIP(\"10.2.0.3\"),\n\t\t\t\t\tPort: 20000,\n\t\t\t\t},\n\t\t\t\tAllowedIPs: []net.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIP:   net.ParseIP(\"172.24.0.0\"),\n\t\t\t\t\t\tMask: net.IPv4Mask(255, 255, 0, 0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPublicKey: pub2.PublicKey(),\n\t\t\t\tAllowedIPs: []net.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIP:   net.ParseIP(\"172.25.0.0\"),\n\t\t\t\t\t\tMask: net.IPv4Mask(255, 255, 255, 0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, false)\n\n\texpected := network.WireguardSpec{\n\t\tPrivateKey:   priv.String(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t\tPeers: []network.WireguardPeer{\n\t\t\t{\n\t\t\t\tPublicKey:    pub1.PublicKey().String(),\n\t\t\t\tPresharedKey: priv.String(),\n\t\t\t\tEndpoint:     \"10.2.0.3:20000\",\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.24.0.0/16\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPublicKey: pub2.PublicKey().String(),\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.25.0.0/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tassert.Equal(t, expected, spec)\n\tassert.True(t, expected.Equal(&spec))\n\n\t// zeroed out listen port is still acceptable on the right side\n\tspec.ListenPort = 0\n\tassert.True(t, expected.Equal(&spec))\n\n\t// ... but not on the left side\n\texpected.ListenPort = 0\n\tspec.ListenPort = 30000\n\tassert.False(t, expected.Equal(&spec))\n\n\tvar zeroSpec network.WireguardSpec\n\n\tassert.False(t, zeroSpec.Equal(&spec))\n}\n\nfunc TestWireguardSpecDecodeStatus(t *testing.T) {\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tpriv, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tvar spec network.WireguardSpec\n\n\t// decode in status mode\n\tnetworkadapter.WireguardSpec(&spec).Decode(&wgtypes.Device{\n\t\tPrivateKey:   priv,\n\t\tPublicKey:    priv.PublicKey(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t}, true)\n\n\texpected := network.WireguardSpec{\n\t\tPublicKey:    priv.PublicKey().String(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t\tPeers:        []network.WireguardPeer{},\n\t}\n\n\tassert.Equal(t, expected, spec)\n}\n\nfunc TestWireguardSpecEncode(t *testing.T) {\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tpriv, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tpub1, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\tpub2, err := wgtypes.GeneratePrivateKey()\n\trequire.NoError(t, err)\n\n\t// make sure pub1 < pub2\n\tif pub1.PublicKey().String() > pub2.PublicKey().String() {\n\t\tpub1, pub2 = pub2, pub1\n\t}\n\n\tspecV1 := network.WireguardSpec{\n\t\tPrivateKey:   priv.String(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t\tPeers: []network.WireguardPeer{\n\t\t\t{\n\t\t\t\tPublicKey: pub1.PublicKey().String(),\n\t\t\t\tEndpoint:  \"10.2.0.3:20000\",\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.24.0.0/16\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPublicKey: pub2.PublicKey().String(),\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.25.0.0/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tspecV1.Sort()\n\n\tvar zero network.WireguardSpec\n\n\tnetworkadapter.WireguardSpec(&zero).Decode(&wgtypes.Device{}, false)\n\tzero.Sort()\n\n\t// from zero (empty) config to config with two peers\n\tdelta, err := networkadapter.WireguardSpec(&specV1).Encode(&zero)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &wgtypes.Config{\n\t\tPrivateKey:   &priv,\n\t\tListenPort:   new(30000),\n\t\tFirewallMark: new(1),\n\t\tPeers: []wgtypes.PeerConfig{\n\t\t\t{\n\t\t\t\tPublicKey: pub1.PublicKey(),\n\t\t\t\tEndpoint: &net.UDPAddr{\n\t\t\t\t\tIP:   net.ParseIP(\"10.2.0.3\"),\n\t\t\t\t\tPort: 20000,\n\t\t\t\t},\n\t\t\t\tPersistentKeepaliveInterval: new(time.Duration(0)),\n\t\t\t\tReplaceAllowedIPs:           true,\n\t\t\t\tAllowedIPs: []net.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIP:   net.ParseIP(\"172.24.0.0\").To4(),\n\t\t\t\t\t\tMask: net.IPv4Mask(255, 255, 0, 0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tPublicKey:                   pub2.PublicKey(),\n\t\t\t\tPersistentKeepaliveInterval: new(time.Duration(0)),\n\t\t\t\tReplaceAllowedIPs:           true,\n\t\t\t\tAllowedIPs: []net.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIP:   net.ParseIP(\"172.25.0.0\").To4(),\n\t\t\t\t\t\tMask: net.IPv4Mask(255, 255, 255, 0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, delta)\n\n\t// noop\n\tdelta, err = networkadapter.WireguardSpec(&specV1).Encode(&specV1)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &wgtypes.Config{}, delta)\n\n\t// delete peer2\n\tspecV2 := network.WireguardSpec{\n\t\tPrivateKey:   priv.String(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 1,\n\t\tPeers: []network.WireguardPeer{\n\t\t\t{\n\t\t\t\tPublicKey: pub1.PublicKey().String(),\n\t\t\t\tEndpoint:  \"10.2.0.3:20000\",\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.24.0.0/16\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdelta, err = networkadapter.WireguardSpec(&specV2).Encode(&specV1)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &wgtypes.Config{\n\t\tPeers: []wgtypes.PeerConfig{\n\t\t\t{\n\t\t\t\tPublicKey: pub2.PublicKey(),\n\t\t\t\tRemove:    true,\n\t\t\t},\n\t\t},\n\t}, delta)\n\n\t// update peer1, firewallMark\n\tspecV3 := network.WireguardSpec{\n\t\tPrivateKey:   priv.String(),\n\t\tListenPort:   30000,\n\t\tFirewallMark: 2,\n\t\tPeers: []network.WireguardPeer{\n\t\t\t{\n\t\t\t\tPublicKey:    pub1.PublicKey().String(),\n\t\t\t\tPresharedKey: priv.String(),\n\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"172.24.0.0/16\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdelta, err = networkadapter.WireguardSpec(&specV3).Encode(&specV2)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &wgtypes.Config{\n\t\tFirewallMark: new(2),\n\t\tPeers: []wgtypes.PeerConfig{\n\t\t\t{\n\t\t\t\tPublicKey:                   pub1.PublicKey(),\n\t\t\t\tPresharedKey:                &priv,\n\t\t\t\tPersistentKeepaliveInterval: new(time.Duration(0)),\n\t\t\t\tReplaceAllowedIPs:           true,\n\t\t\t\tAllowedIPs: []net.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIP:   net.ParseIP(\"172.24.0.0\").To4(),\n\t\t\t\t\t\tMask: net.IPv4Mask(255, 255, 0, 0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, delta)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/perf/cpu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport (\n\t\"github.com/prometheus/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n)\n\n// CPU adapter provides conversion from procfs.\n//\n//nolint:revive,golint\nfunc CPU(r *perf.CPU) cpu {\n\treturn cpu{\n\t\tCPU: r,\n\t}\n}\n\ntype cpu struct {\n\t*perf.CPU\n}\n\n// Update current CPU snapshot.\nfunc (a cpu) Update(stat *procfs.Stat) {\n\ttranslateCPUStat := func(in procfs.CPUStat) perf.CPUStat {\n\t\treturn perf.CPUStat{\n\t\t\tUser:      in.User,\n\t\t\tNice:      in.Nice,\n\t\t\tSystem:    in.System,\n\t\t\tIdle:      in.Idle,\n\t\t\tIowait:    in.Iowait,\n\t\t\tIrq:       in.IRQ,\n\t\t\tSoftIrq:   in.SoftIRQ,\n\t\t\tSteal:     in.Steal,\n\t\t\tGuest:     in.Guest,\n\t\t\tGuestNice: in.GuestNice,\n\t\t}\n\t}\n\n\ttranslateListOfCPUStat := func(in map[int64]procfs.CPUStat) []perf.CPUStat {\n\t\tmaxCore := int64(-1)\n\n\t\tfor core := range in {\n\t\t\tmaxCore = max(maxCore, core)\n\t\t}\n\n\t\tslc := make([]perf.CPUStat, maxCore+1)\n\n\t\tfor core, stat := range in {\n\t\t\tslc[core] = translateCPUStat(stat)\n\t\t}\n\n\t\treturn slc\n\t}\n\n\t*a.CPU.TypedSpec() = perf.CPUSpec{\n\t\tCPUTotal:        translateCPUStat(stat.CPUTotal),\n\t\tCPU:             translateListOfCPUStat(stat.CPU),\n\t\tIRQTotal:        stat.IRQTotal,\n\t\tContextSwitches: stat.ContextSwitches,\n\t\tProcessCreated:  stat.ProcessCreated,\n\t\tProcessRunning:  stat.ProcessesRunning,\n\t\tProcessBlocked:  stat.ProcessesBlocked,\n\t\tSoftIrqTotal:    stat.SoftIRQTotal,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/perf/mem.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport (\n\t\"github.com/prometheus/procfs\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n)\n\n// Memory adapter provides conversion from procfs.\n//\n//nolint:revive,golint\nfunc Memory(r *perf.Memory) memory {\n\treturn memory{\n\t\tMemory: r,\n\t}\n}\n\ntype memory struct {\n\t*perf.Memory\n}\n\n// Update current Mem snapshot.\nfunc (a memory) Update(info *procfs.Meminfo) {\n\t*a.Memory.TypedSpec() = perf.MemorySpec{\n\t\tMemTotal:          pointer.SafeDeref(info.MemTotal),\n\t\tMemUsed:           pointer.SafeDeref(info.MemTotal) - pointer.SafeDeref(info.MemFree),\n\t\tMemAvailable:      pointer.SafeDeref(info.MemAvailable),\n\t\tBuffers:           pointer.SafeDeref(info.Buffers),\n\t\tCached:            pointer.SafeDeref(info.Cached),\n\t\tSwapCached:        pointer.SafeDeref(info.SwapCached),\n\t\tActive:            pointer.SafeDeref(info.Active),\n\t\tInactive:          pointer.SafeDeref(info.Inactive),\n\t\tActiveAnon:        pointer.SafeDeref(info.ActiveAnon),\n\t\tInactiveAnon:      pointer.SafeDeref(info.InactiveAnon),\n\t\tActiveFile:        pointer.SafeDeref(info.ActiveFile),\n\t\tInactiveFile:      pointer.SafeDeref(info.InactiveFile),\n\t\tUnevictable:       pointer.SafeDeref(info.Unevictable),\n\t\tMlocked:           pointer.SafeDeref(info.Mlocked),\n\t\tSwapTotal:         pointer.SafeDeref(info.SwapTotal),\n\t\tSwapFree:          pointer.SafeDeref(info.SwapFree),\n\t\tDirty:             pointer.SafeDeref(info.Dirty),\n\t\tWriteback:         pointer.SafeDeref(info.Writeback),\n\t\tAnonPages:         pointer.SafeDeref(info.AnonPages),\n\t\tMapped:            pointer.SafeDeref(info.Mapped),\n\t\tShmem:             pointer.SafeDeref(info.Shmem),\n\t\tSlab:              pointer.SafeDeref(info.Slab),\n\t\tSReclaimable:      pointer.SafeDeref(info.SReclaimable),\n\t\tSUnreclaim:        pointer.SafeDeref(info.SUnreclaim),\n\t\tKernelStack:       pointer.SafeDeref(info.KernelStack),\n\t\tPageTables:        pointer.SafeDeref(info.PageTables),\n\t\tNFSunstable:       pointer.SafeDeref(info.NFSUnstable),\n\t\tBounce:            pointer.SafeDeref(info.Bounce),\n\t\tWritebackTmp:      pointer.SafeDeref(info.WritebackTmp),\n\t\tCommitLimit:       pointer.SafeDeref(info.CommitLimit),\n\t\tCommittedAS:       pointer.SafeDeref(info.CommittedAS),\n\t\tVmallocTotal:      pointer.SafeDeref(info.VmallocTotal),\n\t\tVmallocUsed:       pointer.SafeDeref(info.VmallocUsed),\n\t\tVmallocChunk:      pointer.SafeDeref(info.VmallocChunk),\n\t\tHardwareCorrupted: pointer.SafeDeref(info.HardwareCorrupted),\n\t\tAnonHugePages:     pointer.SafeDeref(info.AnonHugePages),\n\t\tShmemHugePages:    pointer.SafeDeref(info.ShmemHugePages),\n\t\tShmemPmdMapped:    pointer.SafeDeref(info.ShmemPmdMapped),\n\t\tCmaTotal:          pointer.SafeDeref(info.CmaTotal),\n\t\tCmaFree:           pointer.SafeDeref(info.CmaFree),\n\t\tHugePagesTotal:    pointer.SafeDeref(info.HugePagesTotal),\n\t\tHugePagesFree:     pointer.SafeDeref(info.HugePagesFree),\n\t\tHugePagesRsvd:     pointer.SafeDeref(info.HugePagesRsvd),\n\t\tHugePagesSurp:     pointer.SafeDeref(info.HugePagesSurp),\n\t\tHugepagesize:      pointer.SafeDeref(info.Hugepagesize),\n\t\tDirectMap4k:       pointer.SafeDeref(info.DirectMap4k),\n\t\tDirectMap2m:       pointer.SafeDeref(info.DirectMap2M),\n\t\tDirectMap1g:       pointer.SafeDeref(info.DirectMap1G),\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/perf/perf.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package perf implements adapters wrapping resources/perf to provide additional functionality.\npackage perf\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/secrets/encryption_salt.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"crypto/rand\"\n\t\"io\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// EncryptionSalt adapter provides encryption salt generation.\n//\n//nolint:revive,golint\nfunc EncryptionSalt(r *secrets.EncryptionSaltSpec) encryptionSalt {\n\treturn encryptionSalt{\n\t\tEncryptionSaltSpec: r,\n\t}\n}\n\ntype encryptionSalt struct {\n\t*secrets.EncryptionSaltSpec\n}\n\n// Generate new encryption salt.\nfunc (a encryptionSalt) Generate() error {\n\tbuf := make([]byte, constants.DiskEncryptionSaltSize)\n\n\tif _, err := io.ReadFull(rand.Reader, buf); err != nil {\n\t\treturn err\n\t}\n\n\ta.EncryptionSaltSpec.DiskSalt = buf\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/secrets/encryption_salt_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tsecretsadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestEncryptionSaltGenerate(t *testing.T) {\n\tt.Parallel()\n\n\tvar spec1, spec2 secrets.EncryptionSaltSpec\n\n\trequire.NoError(t, secretsadapter.EncryptionSalt(&spec1).Generate())\n\trequire.NoError(t, secretsadapter.EncryptionSalt(&spec2).Generate())\n\n\tassert.NotEqual(t, spec1, spec2)\n\n\tassert.Len(t, spec1.DiskSalt, constants.DiskEncryptionSaltSize)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/secrets/secrets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package secrets implements adapters wrapping resources to provide additional functionality.\npackage secrets\n"
  },
  {
    "path": "internal/app/machined/pkg/adapters/wireguard/wireguard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package wireguard implements common wireguard functionality.\npackage wireguard\n\nimport \"time\"\n\n// PeerDownInterval is the time since last handshake when established peer is considered to be down.\n//\n// WG whitepaper defines a downed peer as being:\n// Handshake Timeout (180s) + Rekey Timeout (5s) + Rekey Attempt Timeout (90s)\n//\n// This interval is applied when the link is already established.\nconst PeerDownInterval = (180 + 5 + 90) * time.Second\n"
  },
  {
    "path": "internal/app/machined/pkg/automaton/blockautomaton/blockmachine.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package blockautomaton implements the controller-specific state automaton for block resources.\npackage blockautomaton\n"
  },
  {
    "path": "internal/app/machined/pkg/automaton/blockautomaton/volume_mount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage blockautomaton\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumeMountCallbackFunc is a callback function that is called when a volume is mounted.\ntype VolumeMountCallbackFunc func(context.Context, controller.ReaderWriter, *zap.Logger, *block.VolumeMountStatus) error\n\n// volumeMountContext is the internal context for the volume mounter controller state machine.\ntype volumeMountContext struct {\n\tmountID   string\n\tvolumeID  string\n\trequester string\n\tcallback  VolumeMountCallbackFunc\n\toptions   VolumeMounterOptions\n}\n\n// VolumeMounterAutomaton is the type of the volume mounter controller state machine.\ntype VolumeMounterAutomaton = *automaton.ControllerAutomaton[volumeMountContext]\n\n// VolumeMounterOptions is the options for the volume mounter controller state machine.\ntype VolumeMounterOptions struct {\n\tReadOnly bool\n\tDetached bool\n}\n\n// VolumeMounterOption is a function that configures the volume mounter controller state machine.\ntype VolumeMounterOption func(*VolumeMounterOptions)\n\n// WithReadOnly sets the volume mounter controller state machine to read-only mode.\nfunc WithReadOnly(readOnly bool) VolumeMounterOption {\n\treturn func(options *VolumeMounterOptions) {\n\t\toptions.ReadOnly = readOnly\n\t}\n}\n\n// WithDetached sets the volume mounter controller state machine to detached mode.\nfunc WithDetached(detached bool) VolumeMounterOption {\n\treturn func(options *VolumeMounterOptions) {\n\t\toptions.Detached = detached\n\t}\n}\n\n// NewVolumeMounter creates a new volume mounter controller state machine.\n//\n// It ensures that the volume is mounted, and calls the callback function when the volume is mounted,\n// unmounting the volume before terminating the state machine.\nfunc NewVolumeMounter(requester, volumeID string, callback VolumeMountCallbackFunc, options ...VolumeMounterOption) VolumeMounterAutomaton {\n\topts := VolumeMounterOptions{}\n\tfor _, option := range options {\n\t\toption(&opts)\n\t}\n\n\treturn automaton.NewControllerAutomaton(createVolumeMountRequest,\n\t\tvolumeMountContext{\n\t\t\tmountID:   requester + \"-\" + volumeID,\n\t\t\tvolumeID:  volumeID,\n\t\t\trequester: requester,\n\t\t\tcallback:  callback,\n\t\t\toptions:   opts,\n\t\t},\n\t)\n}\n\n// createVolumeMountRequest is the initial state of the volume mounter controller state machine.\n//\n// Transitions to: waitForMountStatus.\nfunc createVolumeMountRequest(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\tif err := safe.WriterModify(ctx, r, block.NewVolumeMountRequest(block.NamespaceName, mountContext.mountID), func(req *block.VolumeMountRequest) error {\n\t\treq.TypedSpec().VolumeID = mountContext.volumeID\n\t\treq.TypedSpec().Requester = mountContext.requester\n\t\treq.TypedSpec().ReadOnly = mountContext.options.ReadOnly\n\t\treq.TypedSpec().Detached = mountContext.options.Detached\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating volume mount request: %w\", err)\n\t}\n\n\treturn waitForMountStatus, nil\n}\n\n// waitForMountStatus is the state of the volume mounter controller state machine that waits for the mount status to be established.\n//\n// Transitions to: callbackWithMountStatus.\nfunc waitForMountStatus(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\tmountStatus, err := safe.ReaderGetByID[*block.VolumeMountStatus](ctx, r, mountContext.mountID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, fmt.Errorf(\"error reading volume mount status: %w\", err)\n\t}\n\n\tif mountStatus == nil {\n\t\t// wait for the mount status to be established\n\t\treturn nil, xerrors.NewTaggedf[automaton.Continue](\"waiting for mount status to be established\")\n\t}\n\n\tif mountStatus.TypedSpec().ReadOnly && !mountContext.options.ReadOnly {\n\t\treturn nil, xerrors.NewTaggedf[automaton.Continue](\"volume is mounted read-only, but read-write was requested\")\n\t}\n\n\tif !mountStatus.Metadata().Finalizers().Has(mountContext.requester) {\n\t\tif err = r.AddFinalizer(ctx, mountStatus.Metadata(), mountContext.requester); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t}\n\t}\n\n\treturn callbackWithMountStatus(mountStatus), nil\n}\n\n// callbackWithMountStatus is the state of the volume mounter controller state machine that calls the callback with the mount status.\n//\n// Transitions to: removeMountStatusFinalizer.\nfunc callbackWithMountStatus(mountStatus *block.VolumeMountStatus) func(\n\tctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext,\n) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\treturn func(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\t\tif err := mountContext.callback(ctx, r, logger, mountStatus); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn removeMountStatusFinalizer, nil\n\t}\n}\n\n// removeMountStatusFinalizer is the state of the volume mounter controller state machine that removes the mount status finalizer.\n//\n// Transitions to: removeMountRequest.\nfunc removeMountStatusFinalizer(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\tif err := r.RemoveFinalizer(ctx, block.NewVolumeMountStatus(block.NamespaceName, mountContext.mountID).Metadata(), mountContext.requester); err != nil {\n\t\treturn nil, fmt.Errorf(\"error removing finalizer: %w\", err)\n\t}\n\n\treturn removeMountRequest, nil\n}\n\n// removeMountRequest is the state of the volume mounter controller state machine that removes the mount request.\n//\n// Transitions to: nil.\nfunc removeMountRequest(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\tmountRequest := block.NewVolumeMountRequest(block.NamespaceName, mountContext.mountID)\n\n\tokToDestroy, err := r.Teardown(ctx, mountRequest.Metadata())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error tearing down mount request: %w\", err)\n\t}\n\n\tif !okToDestroy {\n\t\treturn nil, xerrors.NewTaggedf[automaton.Continue](\"mount request is not ready to be destroyed\")\n\t}\n\n\tif err = r.Destroy(ctx, mountRequest.Metadata()); err != nil {\n\t\treturn nil, fmt.Errorf(\"error destroying mount request: %w\", err)\n\t}\n\n\treturn waitForVolumeMountStatusRemoved, nil\n}\n\n// waitForVolumeMountStatusRemoved is the state of the volume mounter controller state machine that waits for the volume mount status to be removed.\nfunc waitForVolumeMountStatusRemoved(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountContext volumeMountContext) (automaton.ControllerStateFunc[volumeMountContext], error) {\n\tmountStatus, err := safe.ReaderGetByID[*block.VolumeMountStatus](ctx, r, mountContext.mountID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, fmt.Errorf(\"error reading volume mount status: %w\", err)\n\t}\n\n\tif mountStatus == nil {\n\t\t// removed\n\t\treturn nil, nil\n\t}\n\n\treturn nil, xerrors.NewTaggedf[automaton.Continue](\"waiting for mount status to be removed\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/automaton/blockautomaton/volume_mount_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage blockautomaton_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/owned\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestVolumeMounter(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := zaptest.NewLogger(t)\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\tctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)\n\tt.Cleanup(cancel)\n\n\tmountedCh := make(chan struct{})\n\n\tvolumeMounter := blockautomaton.NewVolumeMounter(\"requester\", \"volumeID\", func(ctx context.Context, rw controller.ReaderWriter, l *zap.Logger, vms *block.VolumeMountStatus) error {\n\t\tselect {\n\t\tcase <-mountedCh:\n\t\t\t// already closed\n\t\t\treturn nil\n\t\tdefault:\n\t\t\tclose(mountedCh)\n\n\t\t\treturn errors.New(\"mount status callback\")\n\t\t}\n\t})\n\n\tconst mountID = \"requester-volumeID\"\n\n\tadapter := owned.New(st, \"automaton\")\n\n\t// 1st run, should create the volume mount request\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\trtestutils.AssertResource(ctx, t, st, mountID, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"requester\", vmr.TypedSpec().Requester)\n\t\tasrt.Equal(\"volumeID\", vmr.TypedSpec().VolumeID)\n\t})\n\n\trequire.NoError(t, st.AddFinalizer(ctx, block.NewVolumeMountRequest(block.NamespaceName, mountID).Metadata(), \"test\"))\n\n\t// no-op run, as the volume mount status doesn't exist\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\tvms := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\trequire.NoError(t, st.Create(ctx, vms))\n\n\t// 2nd run, should put a finalizer on the volume mount status and call the callback 1st time\n\terr := volumeMounter.Run(ctx, adapter, logger)\n\n\tselect {\n\tcase <-mountedCh:\n\tcase <-ctx.Done():\n\t\tt.Fatal(\"timed out waiting for mount status callback\")\n\t}\n\n\trequire.ErrorContains(t, err, \"mount status callback\")\n\n\t// should put a finalizer on the volume mount status\n\trtestutils.AssertResource(ctx, t, st, mountID, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Has(\"requester\"))\n\t})\n\n\t// 3rd run, now the mount callback should be called again, return nil,\n\t// and volume mount status finalizer should be removed\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\t// should remove a finalizer on the volume mount status\n\trtestutils.AssertResource(ctx, t, st, mountID, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.False(vms.Metadata().Finalizers().Has(\"requester\"))\n\t})\n\n\t// the mount request now should be torn down by the automaton\n\trtestutils.AssertResource(ctx, t, st, mountID, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(resource.PhaseTearingDown, vmr.Metadata().Phase())\n\t})\n\n\t// remove our finalizer from the mount request\n\trequire.NoError(t, st.RemoveFinalizer(ctx, block.NewVolumeMountRequest(block.NamespaceName, mountID).Metadata(), \"test\"))\n\n\t// 4th run, now the mount request should be destroyed\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\trtestutils.AssertNoResource[*block.VolumeMountRequest](ctx, t, st, mountID)\n\n\t// destroy the volume mount status\n\trequire.NoError(t, st.Destroy(ctx, vms.Metadata()))\n\n\tvar finished bool\n\n\t// 5th run, now the automaton should have finished\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger, automaton.WithAfterFunc(func() error {\n\t\tfinished = true\n\n\t\treturn nil\n\t})))\n\n\tassert.True(t, finished)\n}\n\nfunc TestVolumeMounterReadWrite(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := zaptest.NewLogger(t)\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\tctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)\n\tt.Cleanup(cancel)\n\n\tmountedCh := make(chan struct{})\n\n\tvolumeMounter := blockautomaton.NewVolumeMounter(\"rw\", \"volumeID\", func(ctx context.Context, rw controller.ReaderWriter, l *zap.Logger, vms *block.VolumeMountStatus) error {\n\t\tclose(mountedCh)\n\n\t\treturn nil\n\t})\n\n\tconst mountID = \"rw-volumeID\"\n\n\tadapter := owned.New(st, \"automaton\")\n\n\t// 1st run, should create the volume mount request\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\trtestutils.AssertResource(ctx, t, st, mountID, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"rw\", vmr.TypedSpec().Requester)\n\t\tasrt.Equal(\"volumeID\", vmr.TypedSpec().VolumeID)\n\t\tasrt.False(vmr.TypedSpec().ReadOnly)\n\t})\n\n\trequire.NoError(t, st.AddFinalizer(ctx, block.NewVolumeMountRequest(block.NamespaceName, mountID).Metadata(), \"test\"))\n\n\tvms := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvms.TypedSpec().ReadOnly = true // volume is mounted read-only (from some other request)\n\trequire.NoError(t, st.Create(ctx, vms))\n\n\t// no-op run, as the volume mount status is read-only\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\tvms.TypedSpec().ReadOnly = false // volume is now mounted read-write\n\trequire.NoError(t, st.Update(ctx, vms))\n\n\t// 2nd run, should put a finalizer on the volume mount status and call the callback 1st time, finishing the whole sequence\n\trequire.NoError(t, volumeMounter.Run(ctx, adapter, logger))\n\n\tselect {\n\tcase <-mountedCh:\n\tcase <-ctx.Done():\n\t\tt.Fatal(\"timed out waiting for mount status callback\")\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/automaton/machine.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package automaton implements the controller-specific state automaton (state machine).\npackage automaton\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"go.uber.org/zap\"\n)\n\n// ControllerStateFunc is a function that implements a state in the controller state automaton.\n//\n// Each state in the automaton is implemented by a function which returns the next state and an error.\n// If the error returned is tagged with Continue, the state automaton returns nil error keeping the state,\n// this should be used to keep progressing on next controller reconcile loop.\n// If the state returns an error, the state automaton returns the error and pauses the automaton.ControllerStateFunc\n// If the returned next state is nil, the state automaton terminates and always returns nil.\ntype ControllerStateFunc[T any] func(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, v T) (ControllerStateFunc[T], error)\n\n// ControllerAutomaton is a state automaton that is used in a controller context.\n//\n// Type T holds a context value that is passed to each state function.\ntype ControllerAutomaton[T any] struct {\n\tstate ControllerStateFunc[T]\n\tvalue T\n}\n\n// NewControllerAutomaton creates a new controller automaton with the specified initialState and value.\nfunc NewControllerAutomaton[T any](initialState ControllerStateFunc[T], v T) *ControllerAutomaton[T] {\n\treturn &ControllerAutomaton[T]{\n\t\tstate: initialState,\n\t\tvalue: v,\n\t}\n}\n\n// Continue is an error tag that indicates that the state automaton should return to the controller with nil error and keep the state.\ntype Continue struct{}\n\n// RunOptions is a struct that holds options for the Run function.\ntype RunOptions struct {\n\tAfterFunc func() error\n}\n\n// RunOption is a function that configures the RunOptions.\ntype RunOption func(*RunOptions)\n\n// WithAfterFunc sets the AfterFunc option.\nfunc WithAfterFunc(afterFunc func() error) RunOption {\n\treturn func(options *RunOptions) {\n\t\toptions.AfterFunc = afterFunc\n\t}\n}\n\n// Run is the entrypoint to the state automaton.\n//\n// Run is supposed to be called from the controller's reconcile loop.\n//\n// If Run returns an error, the controller should propagate the error back, and on nil error,\n// the controller should wait for the next event.\nfunc (automaton *ControllerAutomaton[T]) Run(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, options ...RunOption) error {\n\topts := &RunOptions{}\n\tfor _, opt := range options {\n\t\topt(opts)\n\t}\n\n\tfor {\n\t\tif automaton.state == nil {\n\t\t\tif opts.AfterFunc != nil {\n\t\t\t\treturn opts.AfterFunc()\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tnextState, err := automaton.state(ctx, r, logger, automaton.value)\n\t\tif err != nil {\n\t\t\tif xerrors.TagIs[Continue](err) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tautomaton.state = nextState\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/block.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package block provides the controllers related to blockdevices, mounts, etc.\npackage block\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/devices.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/inotify\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/kobject\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/sysblock\"\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// DevicesController provides a view of available block devices with information about pending updates.\ntype DevicesController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DevicesController) Name() string {\n\treturn \"block.DevicesController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DevicesController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DevicesController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.DeviceType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DevicesController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// in container mode, no devices\n\tif ctrl.V1Alpha1Mode == machineruntime.ModeContainer {\n\t\treturn nil\n\t}\n\n\t// start the watcher first\n\twatcher, err := kobject.NewWatcher()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create kobject watcher: %w\", err)\n\t}\n\n\tdefer watcher.Close() //nolint:errcheck\n\n\twatchCh := watcher.Run(logger)\n\n\t// start the inotify watcher\n\tinotifyWatcher, err := inotify.NewWatcher()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create inotify watcher: %w\", err)\n\t}\n\n\tdefer inotifyWatcher.Close() //nolint:errcheck\n\n\tinotifyCh, inotifyErrCh := inotifyWatcher.Run()\n\n\t// reconcile the initial list of devices while the watcher is running\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tif err = ctrl.resync(ctx, r, logger, inotifyWatcher); err != nil {\n\t\treturn fmt.Errorf(\"failed to resync: %w\", err)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase ev := <-watchCh:\n\t\t\tif ev.Subsystem != \"block\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tev.DevicePath = filepath.Join(\"/sys\", ev.DevicePath)\n\n\t\t\tif err = ctrl.processEvent(ctx, r, logger, inotifyWatcher, ev); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase err = <-inotifyErrCh:\n\t\t\treturn fmt.Errorf(\"inotify watcher failed: %w\", err)\n\t\tcase updatedPath := <-inotifyCh:\n\t\t\tid := filepath.Base(updatedPath)\n\n\t\t\tif err = ctrl.bumpGeneration(ctx, r, logger, id); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (ctrl *DevicesController) bumpGeneration(ctx context.Context, r controller.Runtime, logger *zap.Logger, id string) error {\n\t_, err := safe.ReaderGetByID[*block.Device](ctx, r, id)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// skip it\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tlogger.Debug(\"bumping generation for device, inotify update\", zap.String(\"id\", id))\n\n\treturn safe.WriterModify(ctx, r, block.NewDevice(block.NamespaceName, id), func(dev *block.Device) error {\n\t\tdev.TypedSpec().Generation++\n\n\t\treturn nil\n\t})\n}\n\nfunc (ctrl *DevicesController) resync(ctx context.Context, r controller.Runtime, logger *zap.Logger, inotifyWatcher *inotify.Watcher) error {\n\tevents, err := sysblock.Walk(\"/sys/block\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to walk /sys/block: %w\", err)\n\t}\n\n\ttouchedIDs := make(map[string]struct{}, len(events))\n\n\tfor _, ev := range events {\n\t\tif err = ctrl.processEvent(ctx, r, logger, inotifyWatcher, ev); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttouchedIDs[ev.Values[\"DEVNAME\"]] = struct{}{}\n\t}\n\n\t// remove devices that were not touched\n\tdevices, err := safe.ReaderListAll[*block.Device](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to list devices: %w\", err)\n\t}\n\n\tfor dev := range devices.All() {\n\t\tif _, ok := touchedIDs[dev.Metadata().ID()]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = r.Destroy(ctx, dev.Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to remove device: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *DevicesController) processEvent(ctx context.Context, r controller.Runtime, logger *zap.Logger, inotifyWatcher *inotify.Watcher, ev *kobject.Event) error {\n\tlogger = logger.With(\n\t\tzap.String(\"action\", string(ev.Action)),\n\t\tzap.String(\"path\", ev.DevicePath),\n\t\tzap.String(\"id\", ev.Values[\"DEVNAME\"]),\n\t)\n\n\tlogger.Debug(\"processing event\")\n\n\tid := ev.Values[\"DEVNAME\"]\n\tdevPath := filepath.Join(\"/dev\", id)\n\n\t// re-stat the sysfs entry to make sure we are not out of sync with events\n\t_, reStatErr := os.Stat(ev.DevicePath)\n\n\tswitch ev.Action {\n\tcase kobject.ActionAdd, kobject.ActionBind, kobject.ActionOnline, kobject.ActionChange, kobject.ActionMove, kobject.ActionUnbind, kobject.ActionOffline:\n\t\tif reStatErr != nil {\n\t\t\tlogger.Debug(\"skipped, as device path doesn't exist\")\n\n\t\t\treturn nil //nolint:nilerr // entry doesn't exist now, so skip the event\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, block.NewDevice(block.NamespaceName, id), func(dev *block.Device) error {\n\t\t\tdev.TypedSpec().Type = ev.Values[\"DEVTYPE\"]\n\t\t\tdev.TypedSpec().Major = atoiOrZero(ev.Values[\"MAJOR\"])\n\t\t\tdev.TypedSpec().Minor = atoiOrZero(ev.Values[\"MINOR\"])\n\t\t\tdev.TypedSpec().PartitionName = ev.Values[\"PARTNAME\"]\n\t\t\tdev.TypedSpec().PartitionNumber = atoiOrZero(ev.Values[\"PARTN\"])\n\n\t\t\tdev.TypedSpec().DevicePath = ev.DevicePath\n\n\t\t\tif dev.TypedSpec().Type == \"partition\" {\n\t\t\t\tdev.TypedSpec().Parent = filepath.Base(filepath.Dir(dev.TypedSpec().DevicePath))\n\t\t\t\tdev.TypedSpec().Secondaries = nil\n\t\t\t} else {\n\t\t\t\tdev.TypedSpec().Parent = \"\"\n\t\t\t\tdev.TypedSpec().Secondaries = sysblock.ReadSecondaries(ev.DevicePath)\n\t\t\t}\n\n\t\t\tdev.TypedSpec().Generation++\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to modify device %q: %w\", id, err)\n\t\t}\n\n\t\tif err := inotifyWatcher.Add(devPath, unix.IN_CLOSE_WRITE); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to add inotify watch for %q: %w\", devPath, err)\n\t\t}\n\tcase kobject.ActionRemove:\n\t\tif reStatErr == nil { // entry still exists, skip removing\n\t\t\tlogger.Debug(\"skipped, as device path still exists\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif err := r.Destroy(ctx, block.NewDevice(block.NamespaceName, id).Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to remove device %q: %w\", id, err)\n\t\t}\n\n\t\tif err := inotifyWatcher.Remove(devPath); err != nil {\n\t\t\tlogger.Debug(\"failed to remove inotify watch\", zap.String(\"device\", devPath), zap.Error(err))\n\t\t}\n\tdefault:\n\t\tlogger.Debug(\"skipped, as action is not supported\")\n\t}\n\n\treturn nil\n}\n\nfunc atoiOrZero(s string) int {\n\ti, _ := strconv.Atoi(s) //nolint:errcheck\n\n\treturn i\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/devices_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype DevicesSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestDevicesSuite(t *testing.T) {\n\tsuite.Run(t, new(DevicesSuite))\n}\n\nfunc (suite *DevicesSuite) TestDiscover() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test; must be root to use inotify\")\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.DevicesController{}))\n\n\t// these devices should always exist on Linux\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"loop0\", \"loop1\"}, func(r *block.Device, assertions *assert.Assertions) {\n\t\tassertions.Equal(\"disk\", r.TypedSpec().Type)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/discovery.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// DiscoveryController provides a filesystem/partition discovery for blockdevices.\ntype DiscoveryController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DiscoveryController) Name() string {\n\treturn \"block.DiscoveryController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DiscoveryController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DeviceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiscoveryRefreshRequestType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DiscoveryController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.DiscoveredVolumeType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: block.DiscoveryRefreshStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *DiscoveryController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// lastObservedGenerations holds the last observed generation of each device.\n\t//\n\t// when the generation of a device changes, the device might have changed and might need to be re-probed.\n\tlastObservedGenerations := map[string]int{}\n\n\t// whenever new DiscoveryRefresh requests are received, the devices are re-probed.\n\tvar lastObservedDiscoveryRefreshRequest int\n\n\t// nextRescan holds the pool of devices to be rescanned in the next batch.\n\tnextRescan := map[string]int{}\n\n\trescanTicker := time.NewTicker(100 * time.Millisecond)\n\tdefer rescanTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-rescanTicker.C:\n\t\t\tif len(nextRescan) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlogger.Debug(\"rescanning devices\", zap.Strings(\"devices\", maps.Keys(nextRescan)))\n\n\t\t\tif nextRescanBatch, err := ctrl.rescan(ctx, r, logger, maps.Keys(nextRescan)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to rescan devices: %w\", err)\n\t\t\t} else {\n\t\t\t\tnextRescan = map[string]int{}\n\n\t\t\t\tfor id := range nextRescanBatch {\n\t\t\t\t\tnextRescan[id] = lastObservedGenerations[id]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := safe.WriterModify(ctx, r, block.NewDiscoveryRefreshStatus(block.NamespaceName, block.RefreshID), func(status *block.DiscoveryRefreshStatus) error {\n\t\t\t\tstatus.TypedSpec().Request = lastObservedDiscoveryRefreshRequest\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write discovery refresh status: %w\", err)\n\t\t\t}\n\t\tcase <-r.EventCh():\n\t\t\trefreshRequest, err := safe.ReaderGetByID[*block.DiscoveryRefreshRequest](ctx, r, block.RefreshID)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to get refresh request: %w\", err)\n\t\t\t}\n\n\t\t\tif refreshRequest != nil && refreshRequest.TypedSpec().Request != lastObservedDiscoveryRefreshRequest {\n\t\t\t\tlastObservedDiscoveryRefreshRequest = refreshRequest.TypedSpec().Request\n\n\t\t\t\t// force re-probe all devices\n\t\t\t\tclear(lastObservedGenerations)\n\t\t\t}\n\n\t\t\tdevices, err := safe.ReaderListAll[*block.Device](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to list devices: %w\", err)\n\t\t\t}\n\n\t\t\tparents := map[string]string{}\n\t\t\tallDevices := map[string]struct{}{}\n\n\t\t\tfor device := range devices.All() {\n\t\t\t\tif device.TypedSpec().Major == 1 {\n\t\t\t\t\t// ignore ram disks (/dev/ramX), major number is 1\n\t\t\t\t\t// ref: https://www.kernel.org/doc/Documentation/admin-guide/devices.txt\n\t\t\t\t\t// ref: https://github.com/util-linux/util-linux/blob/c0207d354ee47fb56acfa64b03b5b559bb301280/misc-utils/lsblk.c#L2697-L2699\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tallDevices[device.Metadata().ID()] = struct{}{}\n\n\t\t\t\tif device.TypedSpec().Parent != \"\" {\n\t\t\t\t\tparents[device.Metadata().ID()] = device.TypedSpec().Parent\n\t\t\t\t}\n\n\t\t\t\tif device.TypedSpec().Generation == lastObservedGenerations[device.Metadata().ID()] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tnextRescan[device.Metadata().ID()] = device.TypedSpec().Generation\n\t\t\t\tlastObservedGenerations[device.Metadata().ID()] = device.TypedSpec().Generation\n\t\t\t}\n\n\t\t\t// remove child devices if the parent is marked for rescan\n\t\t\tfor id := range nextRescan {\n\t\t\t\tif parent, ok := parents[id]; ok {\n\t\t\t\t\tif _, ok := nextRescan[parent]; ok {\n\t\t\t\t\t\tdelete(nextRescan, id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if the device is removed, add it to the nextRescan, and remove from lastObservedGenerations\n\t\t\tfor id := range lastObservedGenerations {\n\t\t\t\tif _, ok := allDevices[id]; !ok {\n\t\t\t\t\tnextRescan[id] = lastObservedGenerations[id]\n\t\t\t\t\tdelete(lastObservedGenerations, id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *DiscoveryController) rescan(ctx context.Context, r controller.Runtime, logger *zap.Logger, ids []string) (map[string]struct{}, error) {\n\tfailedIDs := map[string]struct{}{}\n\ttouchedIDs := map[string]struct{}{}\n\tnextRescan := map[string]struct{}{}\n\n\tfor _, id := range ids {\n\t\tdevice, err := safe.ReaderGetByID[*block.Device](ctx, r, id)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tfailedIDs[id] = struct{}{}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"failed to get device: %w\", err)\n\t\t}\n\n\t\tinfo, err := blkid.ProbePath(filepath.Join(\"/dev\", id), blkid.WithProbeLogger(logger.With(zap.String(\"device\", id))))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, blkid.ErrFailedLock) {\n\t\t\t\t// failed to lock the blockdevice, retry later\n\t\t\t\tlogger.Debug(\"failed to lock device, retrying later\", zap.String(\"id\", id))\n\n\t\t\t\tnextRescan[id] = struct{}{}\n\t\t\t} else {\n\t\t\t\tlogger.Debug(\"failed to probe device\", zap.String(\"id\", id), zap.Error(err))\n\n\t\t\t\tfailedIDs[id] = struct{}{}\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.Debug(\"probed device\", zap.String(\"id\", id), zap.Any(\"info\", info))\n\n\t\tif err = safe.WriterModify(ctx, r, block.NewDiscoveredVolume(block.NamespaceName, id), func(dv *block.DiscoveredVolume) error {\n\t\t\tdv.TypedSpec().DevPath = filepath.Join(\"/dev\", id)\n\t\t\tdv.TypedSpec().Type = device.TypedSpec().Type\n\t\t\tdv.TypedSpec().DevicePath = device.TypedSpec().DevicePath\n\t\t\tdv.TypedSpec().Parent = device.TypedSpec().Parent\n\n\t\t\tif device.TypedSpec().Parent != \"\" {\n\t\t\t\tdv.TypedSpec().ParentDevPath = filepath.Join(\"/dev\", device.TypedSpec().Parent)\n\t\t\t}\n\n\t\t\tdv.TypedSpec().Offset = 0\n\t\t\tdv.TypedSpec().SetSize(info.Size)\n\t\t\tdv.TypedSpec().SectorSize = info.SectorSize\n\t\t\tdv.TypedSpec().IOSize = info.IOSize\n\n\t\t\tctrl.fillDiscoveredVolumeFromInfo(dv, info.ProbeResult)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to write discovered volume: %w\", err)\n\t\t}\n\n\t\ttouchedIDs[id] = struct{}{}\n\n\t\tfor _, nested := range info.Parts {\n\t\t\tpartID := partitioning.DevName(id, nested.PartitionIndex)\n\n\t\t\tif err = safe.WriterModify(ctx, r, block.NewDiscoveredVolume(block.NamespaceName, partID), func(dv *block.DiscoveredVolume) error {\n\t\t\t\tdv.TypedSpec().Type = \"partition\"\n\t\t\t\tdv.TypedSpec().DevPath = filepath.Join(\"/dev\", partID)\n\t\t\t\tdv.TypedSpec().DevicePath = filepath.Join(device.TypedSpec().DevicePath, partID)\n\t\t\t\tdv.TypedSpec().Parent = id\n\t\t\t\tdv.TypedSpec().ParentDevPath = filepath.Join(\"/dev\", id)\n\n\t\t\t\tdv.TypedSpec().Offset = nested.PartitionOffset\n\t\t\t\tdv.TypedSpec().SetSize(nested.PartitionSize)\n\n\t\t\t\tdv.TypedSpec().SectorSize = info.SectorSize\n\t\t\t\tdv.TypedSpec().IOSize = info.IOSize\n\n\t\t\t\tctrl.fillDiscoveredVolumeFromInfo(dv, nested.ProbeResult)\n\n\t\t\t\tif nested.PartitionUUID != nil {\n\t\t\t\t\tdv.TypedSpec().PartitionUUID = nested.PartitionUUID.String()\n\t\t\t\t} else {\n\t\t\t\t\tdv.TypedSpec().PartitionUUID = \"\"\n\t\t\t\t}\n\n\t\t\t\tif nested.PartitionType != nil {\n\t\t\t\t\tdv.TypedSpec().PartitionType = nested.PartitionType.String()\n\t\t\t\t} else {\n\t\t\t\t\tdv.TypedSpec().PartitionType = \"\"\n\t\t\t\t}\n\n\t\t\t\tif nested.PartitionLabel != nil {\n\t\t\t\t\tdv.TypedSpec().PartitionLabel = *nested.PartitionLabel\n\t\t\t\t} else {\n\t\t\t\t\tdv.TypedSpec().PartitionLabel = \"\"\n\t\t\t\t}\n\n\t\t\t\tdv.TypedSpec().PartitionIndex = nested.PartitionIndex\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to write discovered volume: %w\", err)\n\t\t\t}\n\n\t\t\ttouchedIDs[partID] = struct{}{}\n\t\t}\n\t}\n\n\t// clean up discovered volumes\n\tdiscoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list discovered volumes: %w\", err)\n\t}\n\n\tfor dv := range discoveredVolumes.All() {\n\t\tif _, ok := touchedIDs[dv.Metadata().ID()]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t_, isFailed := failedIDs[dv.Metadata().ID()]\n\n\t\tparentTouched := false\n\n\t\tif dv.TypedSpec().Parent != \"\" {\n\t\t\tif _, ok := touchedIDs[dv.TypedSpec().Parent]; ok {\n\t\t\t\tparentTouched = true\n\t\t\t}\n\t\t}\n\n\t\tif isFailed || parentTouched {\n\t\t\t// if the probe failed, or if the parent was touched, while this device was not, remove it\n\t\t\tif err = r.Destroy(ctx, dv.Metadata()); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to destroy discovered volume: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nextRescan, nil\n}\n\nfunc (ctrl *DiscoveryController) fillDiscoveredVolumeFromInfo(dv *block.DiscoveredVolume, info blkid.ProbeResult) {\n\tdv.TypedSpec().Name = info.Name\n\n\tif info.UUID != nil {\n\t\tdv.TypedSpec().UUID = info.UUID.String()\n\t} else {\n\t\tdv.TypedSpec().UUID = \"\"\n\t}\n\n\tif info.Label != nil {\n\t\tdv.TypedSpec().Label = *info.Label\n\t} else {\n\t\tdv.TypedSpec().Label = \"\"\n\t}\n\n\tdv.TypedSpec().BlockSize = info.BlockSize\n\tdv.TypedSpec().FilesystemBlockSize = info.FilesystemBlockSize\n\tdv.TypedSpec().ProbedSize = info.ProbedSize\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/disks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bufio\"\n\t\"cmp\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tblkdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// DisksController provides a detailed view of blockdevices of type 'disk'.\ntype DisksController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DisksController) Name() string {\n\treturn \"block.DisksController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DisksController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DeviceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.SymlinkType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DisksController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.DiskType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DisksController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// lastObservedGenerations holds the last observed generation of each device.\n\t//\n\t// when the generation of a device changes, the device might have changed and might need to be re-probed.\n\tlastObservedGenerations := map[string]int{}\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tblockdevices, err := safe.ReaderListAll[*block.Device](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to list block devices: %w\", err)\n\t\t}\n\n\t\ttouchedDisks := map[string]struct{}{}\n\n\t\tfor device := range blockdevices.All() {\n\t\t\tif device.TypedSpec().Type != block.DeviceTypeDisk {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif device.TypedSpec().Major == 1 {\n\t\t\t\t// ignore ram disks (/dev/ramX), major number is 1\n\t\t\t\t// ref: https://www.kernel.org/doc/Documentation/admin-guide/devices.txt\n\t\t\t\t// ref: https://github.com/util-linux/util-linux/blob/c0207d354ee47fb56acfa64b03b5b559bb301280/misc-utils/lsblk.c#L2697-L2699\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// always update symlinks, but skip if the disk hasn't been created yet\n\t\t\tif err = ctrl.updateSymlinks(ctx, r, device); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif lastObserved, ok := lastObservedGenerations[device.Metadata().ID()]; ok && device.TypedSpec().Generation == lastObserved {\n\t\t\t\t// ignore disks which have same generation as before (don't query them once again)\n\t\t\t\ttouchedDisks[device.Metadata().ID()] = struct{}{}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlastObservedGenerations[device.Metadata().ID()] = device.TypedSpec().Generation\n\n\t\t\tif err = ctrl.analyzeBlockDevice(ctx, r, logger.With(zap.String(\"device\", device.Metadata().ID())), device, touchedDisks, blockdevices); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to analyze block device: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tdisks, err := safe.ReaderListAll[*block.Disk](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to list disks: %w\", err)\n\t\t}\n\n\t\tfor disk := range disks.All() {\n\t\t\tif _, ok := touchedDisks[disk.Metadata().ID()]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.Destroy(ctx, disk.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to remove disk: %w\", err)\n\t\t\t}\n\n\t\t\tdelete(lastObservedGenerations, disk.Metadata().ID())\n\t\t}\n\t}\n}\n\nfunc (ctrl *DisksController) updateSymlinks(ctx context.Context, r controller.Runtime, device *block.Device) error {\n\tsymlinks, err := safe.ReaderGetByID[*block.Symlink](ctx, r, device.Metadata().ID())\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\t_, err = safe.ReaderGetByID[*block.Disk](ctx, r, device.Metadata().ID())\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// don't create disk entries even if we have symlinks, let analyze handle it\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn safe.WriterModify(ctx, r, block.NewDisk(block.NamespaceName, device.Metadata().ID()), func(d *block.Disk) error {\n\t\td.TypedSpec().Symlinks = symlinks.TypedSpec().Paths\n\n\t\treturn nil\n\t})\n}\n\n//nolint:gocyclo\nfunc (ctrl *DisksController) analyzeBlockDevice(\n\tctx context.Context, r controller.Runtime, logger *zap.Logger, device *block.Device, touchedDisks map[string]struct{}, allBlockdevices safe.List[*block.Device],\n) error {\n\tbd, err := blkdev.NewFromPath(filepath.Join(\"/dev\", device.Metadata().ID()))\n\tif err != nil {\n\t\tlogger.Debug(\"failed to open blockdevice\", zap.Error(err))\n\n\t\treturn nil\n\t}\n\n\tdefer bd.Close() //nolint:errcheck\n\n\tsize, err := bd.GetSize()\n\tif err != nil || size == 0 {\n\t\treturn nil\n\t}\n\n\tif privateDM, _ := bd.IsPrivateDeviceMapper(); privateDM { //nolint:errcheck\n\t\treturn nil\n\t}\n\n\tisCD := bd.IsCD()\n\tif isCD && bd.IsCDNoMedia() {\n\t\t// Linux reports non-zero size for CD-ROMs even when there is no media.\n\t\tsize = 0\n\t}\n\n\tioSize, err := bd.GetIOSize()\n\tif err != nil {\n\t\tlogger.Debug(\"failed to get io size\", zap.Error(err))\n\t}\n\n\tsectorSize := bd.GetSectorSize()\n\n\treadOnly, err := bd.IsReadOnly()\n\tif err != nil {\n\t\tlogger.Debug(\"failed to get read only\", zap.Error(err))\n\t}\n\n\tprops, err := bd.GetProperties()\n\tif err != nil {\n\t\tlogger.Debug(\"failed to get properties\", zap.Error(err))\n\t}\n\n\tsecondaryDisks := xslices.Map(device.TypedSpec().Secondaries, func(devID string) string {\n\t\tif secondary, ok := allBlockdevices.Find(func(dev *block.Device) bool {\n\t\t\treturn dev.Metadata().ID() == devID\n\t\t}); ok {\n\t\t\tif secondary.TypedSpec().Parent != \"\" {\n\t\t\t\treturn secondary.TypedSpec().Parent\n\t\t\t}\n\t\t}\n\n\t\treturn devID\n\t})\n\n\tsymlinks, err := safe.ReaderGetByID[*block.Symlink](ctx, r, device.Metadata().ID())\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn err\n\t}\n\n\ttouchedDisks[device.Metadata().ID()] = struct{}{}\n\n\tserial := props.Serial\n\tif serial == \"\" {\n\t\t// try to get serial from udevd helpers\n\t\tserial = serialFromUdevdHelpers(ctx, device.Metadata().ID(), props.Transport)\n\t\tif serial == \"\" {\n\t\t\tlogger.Debug(\"failed to get serial from udevd helpers, using empty value\", zap.String(\"device\", device.Metadata().ID()), zap.String(\"transport\", props.Transport))\n\t\t}\n\t}\n\n\treturn safe.WriterModify(ctx, r, block.NewDisk(block.NamespaceName, device.Metadata().ID()), func(d *block.Disk) error {\n\t\td.TypedSpec().SetSize(size)\n\n\t\td.TypedSpec().DevPath = filepath.Join(\"/dev\", device.Metadata().ID())\n\t\td.TypedSpec().IOSize = ioSize\n\t\td.TypedSpec().SectorSize = sectorSize\n\t\td.TypedSpec().Readonly = readOnly\n\t\td.TypedSpec().CDROM = isCD\n\n\t\td.TypedSpec().Model = props.Model\n\t\td.TypedSpec().Serial = serial\n\t\td.TypedSpec().Modalias = props.Modalias\n\t\td.TypedSpec().WWID = props.WWID\n\t\td.TypedSpec().UUID = props.UUID\n\t\td.TypedSpec().BusPath = props.BusPath\n\t\td.TypedSpec().SubSystem = props.SubSystem\n\t\td.TypedSpec().Transport = props.Transport\n\t\td.TypedSpec().Rotational = props.Rotational\n\n\t\td.TypedSpec().SecondaryDisks = secondaryDisks\n\n\t\tif symlinks != nil {\n\t\t\td.TypedSpec().Symlinks = symlinks.TypedSpec().Paths\n\t\t} else {\n\t\t\td.TypedSpec().Symlinks = nil\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc serialFromUdevdHelpers(ctx context.Context, id, transport string) string {\n\tswitch strings.ToLower(transport) {\n\tcase \"ata\":\n\t\treturn runUdevdHelper(\n\t\t\tctx,\n\t\t\t\"/usr/lib/udev/ata_id\",\n\t\t\t\"--export\", filepath.Join(\"/dev\", id),\n\t\t)\n\n\tcase \"scsi\":\n\t\treturn runUdevdHelper(\n\t\t\tctx,\n\t\t\t\"/usr/lib/udev/scsi_id\",\n\t\t\t\"--export\", \"--allowlisted\", \"--device\", filepath.Join(\"/dev\", id),\n\t\t)\n\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc runUdevdHelper(ctx context.Context, helper string, args ...string) string {\n\tout, err := cmd.RunWithOptions(ctx, helper, args)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tenv := parseEnv(strings.NewReader(out))\n\n\treturn cmp.Or(\n\t\tenv[\"ID_SERIAL\"],\n\t\tenv[\"ID_SERIAL_SHORT\"],\n\t)\n}\n\nfunc parseEnv(r io.Reader) map[string]string {\n\tenv := map[string]string{}\n\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif line == \"\" || strings.HasPrefix(line, \"#\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey, value, ok := strings.Cut(line, \"=\")\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tenv[strings.TrimSpace(key)] = strings.TrimSpace(value)\n\t}\n\n\treturn env\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/inotify/inotify.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package inotify implements a specialized inotify watcher for block devices.\npackage inotify\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\ntype (\n\twatches struct {\n\t\tmu   sync.RWMutex\n\t\twd   map[uint32]*watch // wd → watch\n\t\tpath map[string]uint32 // pathname → wd\n\t}\n\twatch struct {\n\t\twd    uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)\n\t\tflags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)\n\t\tpath  string // Watch path.\n\t}\n)\n\nfunc newWatches() *watches {\n\treturn &watches{\n\t\twd:   make(map[uint32]*watch),\n\t\tpath: make(map[string]uint32),\n\t}\n}\n\nfunc (w *watches) remove(wd uint32) {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\tif _, ok := w.wd[wd]; ok {\n\t\tdelete(w.path, w.wd[wd].path)\n\t}\n\n\tdelete(w.wd, wd)\n}\n\nfunc (w *watches) removePath(path string) (uint32, bool) {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\twd, ok := w.path[path]\n\tif !ok {\n\t\treturn 0, false\n\t}\n\n\tdelete(w.path, path)\n\tdelete(w.wd, wd)\n\n\treturn wd, true\n}\n\nfunc (w *watches) byWd(wd uint32) *watch {\n\tw.mu.RLock()\n\tdefer w.mu.RUnlock()\n\n\treturn w.wd[wd]\n}\n\nfunc (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\tvar existing *watch\n\n\twd, ok := w.path[path]\n\tif ok {\n\t\texisting = w.wd[wd]\n\t}\n\n\tupd, err := f(existing)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif upd != nil {\n\t\tw.wd[upd.wd] = upd\n\t\tw.path[upd.path] = upd.wd\n\n\t\tif upd.wd != wd {\n\t\t\tdelete(w.wd, wd)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Watcher implements inotify-based file watching.\ntype Watcher struct {\n\twg          sync.WaitGroup\n\tfd          int\n\tinotifyFile *os.File\n\twatches     *watches\n}\n\n// NewWatcher creates a new inotify Watcher.\nfunc NewWatcher() (*Watcher, error) {\n\t// Need to set nonblocking mode for SetDeadline to work, otherwise blocking\n\t// I/O operations won't terminate on close.\n\tfd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)\n\tif fd == -1 {\n\t\treturn nil, errno\n\t}\n\n\treturn &Watcher{\n\t\tfd:          fd,\n\t\tinotifyFile: os.NewFile(uintptr(fd), \"\"),\n\t\twatches:     newWatches(),\n\t}, nil\n}\n\n// Close the inotify watcher.\nfunc (w *Watcher) Close() error {\n\t// Causes any blocking reads to return with an error, provided the file\n\t// still supports deadline operations.\n\terr := w.inotifyFile.Close()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Wait for goroutine to close\n\tw.wg.Wait()\n\n\treturn nil\n}\n\n// Run the watcher, returns two channels for errors and events (paths changed).\n//\n//nolint:gocyclo\nfunc (w *Watcher) Run() (<-chan string, <-chan error) {\n\terrCh := make(chan error, 1)\n\teventCh := make(chan string, 128)\n\n\tw.wg.Add(1)\n\n\tvar buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events\n\n\tgo func() {\n\t\tdefer w.wg.Done()\n\n\t\tfor {\n\t\t\tn, err := w.inotifyFile.Read(buf[:])\n\n\t\t\tswitch {\n\t\t\tcase errors.Is(err, os.ErrClosed):\n\t\t\t\treturn\n\t\t\tcase err != nil:\n\t\t\t\terrCh <- err\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif n < unix.SizeofInotifyEvent {\n\t\t\t\terrCh <- errors.New(\"short read from inotify\")\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar offset uint32\n\n\t\t\t// We don't know how many events we just read into the buffer\n\t\t\t// While the offset points to at least one whole event...\n\t\t\tfor offset <= uint32(n-unix.SizeofInotifyEvent) {\n\t\t\t\tvar (\n\t\t\t\t\t// Point \"raw\" to the event in the buffer\n\t\t\t\t\traw     = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))\n\t\t\t\t\tmask    = raw.Mask\n\t\t\t\t\tnameLen = raw.Len\n\t\t\t\t)\n\n\t\t\t\tif mask&unix.IN_Q_OVERFLOW != 0 {\n\t\t\t\t\terrCh <- errors.New(\"inotify queue overflow\")\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// If the event happened to the watched directory or the watched file, the kernel\n\t\t\t\t// doesn't append the filename to the event, but we would like to always fill the\n\t\t\t\t// the \"Name\" field with a valid filename. We retrieve the path of the watch from\n\t\t\t\t// the \"paths\" map.\n\t\t\t\twatch := w.watches.byWd(uint32(raw.Wd))\n\n\t\t\t\t// inotify will automatically remove the watch on deletes; just need\n\t\t\t\t// to clean our state here.\n\t\t\t\tif watch != nil && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {\n\t\t\t\t\tw.watches.remove(watch.wd)\n\t\t\t\t}\n\n\t\t\t\tvar name string\n\t\t\t\tif watch != nil {\n\t\t\t\t\tname = watch.path\n\t\t\t\t}\n\n\t\t\t\tif nameLen > 0 {\n\t\t\t\t\t// Point \"bytes\" at the first byte of the filename\n\t\t\t\t\tbytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]\n\t\t\t\t\t// The filename is padded with NULL bytes. TrimRight() gets rid of those.\n\t\t\t\t\tname += \"/\" + strings.TrimRight(string(bytes[0:nameLen]), \"\\000\")\n\t\t\t\t}\n\n\t\t\t\t// Send the events that are not ignored on the events channel\n\t\t\t\tif mask&unix.IN_IGNORED == 0 && mask&^uint32(unix.IN_DELETE_SELF) != 0 {\n\t\t\t\t\teventCh <- name\n\t\t\t\t}\n\n\t\t\t\t// Move to the next event in the buffer\n\t\t\t\toffset += unix.SizeofInotifyEvent + nameLen\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn eventCh, errCh\n}\n\n// Add a watch to the inotify watcher.\nfunc (w *Watcher) Add(name string, flags uint32) error {\n\tflags |= unix.IN_DELETE_SELF\n\n\treturn w.watches.updatePath(name, func(existing *watch) (*watch, error) {\n\t\tif existing != nil {\n\t\t\tflags |= existing.flags | unix.IN_MASK_ADD\n\t\t}\n\n\t\twd, err := unix.InotifyAddWatch(w.fd, name, flags)\n\t\tif wd == -1 {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif existing == nil {\n\t\t\treturn &watch{\n\t\t\t\twd:    uint32(wd),\n\t\t\t\tpath:  name,\n\t\t\t\tflags: flags,\n\t\t\t}, nil\n\t\t}\n\n\t\texisting.wd = uint32(wd)\n\t\texisting.flags = flags\n\n\t\treturn existing, nil\n\t})\n}\n\n// Remove a watch from the inotify watcher.\nfunc (w *Watcher) Remove(name string) error {\n\twd, ok := w.watches.removePath(name)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tsuccess, errno := unix.InotifyRmWatch(w.fd, wd)\n\tif success == -1 {\n\t\t// TODO: Perhaps it's not helpful to return an error here in every case;\n\t\t//       The only two possible errors are:\n\t\t//\n\t\t//       - EBADF, which happens when w.fd is not a valid file descriptor\n\t\t//         of any kind.\n\t\t//       - EINVAL, which is when fd is not an inotify descriptor or wd\n\t\t//         is not a valid watch descriptor. Watch descriptors are\n\t\t//         invalidated when they are removed explicitly or implicitly;\n\t\t//         explicitly by inotify_rm_watch, implicitly when the file they\n\t\t//         are watching is deleted.\n\t\treturn errno\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/inotify/inotify_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage inotify_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/inotify\"\n)\n\nfunc assertEvent(t *testing.T, watchCh <-chan string, errCh <-chan error, expected string) {\n\tt.Helper()\n\n\tselect {\n\tcase path := <-watchCh:\n\t\trequire.Equal(t, expected, path)\n\tcase err := <-errCh:\n\t\trequire.FailNow(t, \"unexpected error\", \"%s\", err)\n\tcase <-time.After(time.Second):\n\t\trequire.FailNow(t, \"timeout\")\n\t}\n}\n\nfunc assertNoEvent(t *testing.T, watchCh <-chan string, errCh <-chan error) {\n\tt.Helper()\n\n\tselect {\n\tcase path := <-watchCh:\n\t\trequire.FailNow(t, \"unexpected path\", \"%s\", path)\n\tcase err := <-errCh:\n\t\trequire.FailNow(t, \"unexpected error\", \"%s\", err)\n\tcase <-time.After(100 * time.Millisecond):\n\t}\n}\n\nfunc TestWatcherCloseWrite(t *testing.T) {\n\twatcher, err := inotify.NewWatcher()\n\trequire.NoError(t, err)\n\n\td := t.TempDir()\n\n\trequire.NoError(t, os.WriteFile(filepath.Join(d, \"file1\"), []byte(\"test1\"), 0o644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(d, \"file2\"), []byte(\"test2\"), 0o644))\n\n\trequire.NoError(t, watcher.Add(filepath.Join(d, \"file1\"), unix.IN_CLOSE_WRITE))\n\n\twatchCh, errCh := watcher.Run()\n\n\trequire.NoError(t, watcher.Add(filepath.Join(d, \"file2\"), unix.IN_CLOSE_WRITE))\n\n\tassertNoEvent(t, watchCh, errCh)\n\n\t// open file1 for writing, should get inotify event\n\tf1, err := os.OpenFile(filepath.Join(d, \"file1\"), os.O_WRONLY, 0)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f1.Close())\n\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"file1\"))\n\n\t// open file2 for reading, should not get inotify event\n\tf2, err := os.OpenFile(filepath.Join(d, \"file2\"), os.O_RDONLY, 0)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f2.Close())\n\n\tassertNoEvent(t, watchCh, errCh)\n\n\t// remove file2\n\trequire.NoError(t, os.Remove(filepath.Join(d, \"file2\")))\n\n\tassertNoEvent(t, watchCh, errCh)\n\n\trequire.NoError(t, watcher.Remove(filepath.Join(d, \"file2\")))\n\n\trequire.NoError(t, watcher.Close())\n}\n\nfunc TestWatcherDirectory(t *testing.T) {\n\twatcher, err := inotify.NewWatcher()\n\trequire.NoError(t, err)\n\n\td := t.TempDir()\n\n\trequire.NoError(t, os.Mkdir(filepath.Join(d, \"dir1\"), 0o755))\n\n\trequire.NoError(t, os.Symlink(\"a1\", filepath.Join(d, \"dir1\", \"link1\")))\n\trequire.NoError(t, os.Symlink(\"a2\", filepath.Join(d, \"dir1\", \"link2\")))\n\n\trequire.NoError(t, watcher.Add(d, unix.IN_CREATE|unix.IN_DELETE|unix.IN_MOVE))\n\trequire.NoError(t, watcher.Add(filepath.Join(d, \"dir1\"), unix.IN_CREATE|unix.IN_DELETE|unix.IN_MOVE))\n\n\twatchCh, errCh := watcher.Run()\n\n\tassertNoEvent(t, watchCh, errCh)\n\n\trequire.NoError(t, os.Remove(filepath.Join(d, \"dir1\", \"link1\")))\n\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"dir1\", \"link1\"))\n\n\trequire.NoError(t, os.Mkdir(filepath.Join(d, \"dir2\"), 0o755))\n\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"dir2\"))\n\n\trequire.NoError(t, os.Symlink(\"a3\", filepath.Join(d, \"dir1\", \"#.link3\")))\n\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"dir1\", \"#.link3\"))\n\n\trequire.NoError(t, os.Rename(filepath.Join(d, \"dir1\", \"#.link3\"), filepath.Join(d, \"dir1\", \"link3\")))\n\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"dir1\", \"#.link3\"))\n\tassertEvent(t, watchCh, errCh, filepath.Join(d, \"dir1\", \"link3\"))\n\n\t// no more events\n\tassertNoEvent(t, watchCh, errCh)\n\n\trequire.NoError(t, watcher.Remove(d))\n\n\trequire.NoError(t, watcher.Close())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/kobject/kobject.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kobject implements Linux kernel kobject uvent watcher.\npackage kobject\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/mdlayher/kobject\"\n\t\"go.uber.org/zap\"\n)\n\nconst readBufferSize = 64 * 1024 * 1024\n\n// Event is exported.\ntype Event = kobject.Event\n\n// Re-export action constants.\nconst (\n\tActionAdd     = kobject.Add\n\tActionRemove  = kobject.Remove\n\tActionChange  = kobject.Change\n\tActionMove    = kobject.Move\n\tActionOnline  = kobject.Online\n\tActionOffline = kobject.Offline\n\tActionBind    = kobject.Bind\n\tActionUnbind  = kobject.Unbind\n)\n\n// Watcher is a kobject uvent watcher.\ntype Watcher struct {\n\twg sync.WaitGroup\n\n\tcli *kobject.Client\n}\n\n// NewWatcher creates a new kobject watcher.\nfunc NewWatcher() (*Watcher, error) {\n\tcli, err := kobject.New()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create kobject client: %w\", err)\n\t}\n\n\tif err = cli.SetReadBuffer(readBufferSize); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Watcher{\n\t\tcli: cli,\n\t}, nil\n}\n\n// Close the watcher.\nfunc (w *Watcher) Close() error {\n\tif err := w.cli.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tw.wg.Wait()\n\n\treturn nil\n}\n\n// Run the watcher, returns the channel of events.\nfunc (w *Watcher) Run(logger *zap.Logger) <-chan *Event {\n\tch := make(chan *kobject.Event, 128)\n\n\tw.wg.Go(func() {\n\t\tdefer close(ch)\n\n\t\tfor {\n\t\t\tev, err := w.cli.Receive()\n\t\t\tif err != nil {\n\t\t\t\tif err.Error() != \"use of closed file\" { // unfortunately not an exported error, just errors.New()\n\t\t\t\t\tlogger.Error(\"failed to receive kobject event\", zap.Error(err))\n\t\t\t\t}\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tch <- ev\n\t\t}\n\t})\n\n\treturn ch\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/kobject/kobject_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kobject_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/kobject\"\n)\n\nfunc TestWatcher(t *testing.T) {\n\twatcher, err := kobject.NewWatcher()\n\trequire.NoError(t, err)\n\n\tevCh := watcher.Run(zaptest.NewLogger(t))\n\n\trequire.NoError(t, watcher.Close())\n\n\t// the evCh should be closed\n\tfor range evCh { //nolint:revive\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/sysblock/sysblock.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package sysblock implements gathering block device information from /sys/block filesystem.\npackage sysblock\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/mdlayher/kobject\"\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\n// Walk the /sys/block filesystem and gather block device information.\n//\n//nolint:gocyclo\nfunc Walk(root string) ([]*kobject.Event, error) {\n\tentries, err := os.ReadDir(root)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read %q: %w\", root, err)\n\t}\n\n\tresult := make([]*kobject.Event, 0, len(entries))\n\n\tfor _, entry := range entries {\n\t\tfi, err := entry.Info()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"failed to stat %s: %w\", entry.Name(), err)\n\t\t}\n\n\t\tif fi.Mode()&os.ModeSymlink == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tpath, err := filepath.EvalSymlinks(filepath.Join(root, entry.Name()))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"failed to resolve symlink %s: %w\", entry.Name(), err)\n\t\t}\n\n\t\tuevent, err := readUevent(path)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, &kobject.Event{\n\t\t\tAction:     kobject.Add,\n\t\t\tDevicePath: path,\n\t\t\tSubsystem:  \"block\",\n\t\t\tValues:     uevent,\n\t\t})\n\n\t\tpartitions, err := readPartitions(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, partitions...)\n\t}\n\n\treturn result, nil\n}\n\n// readUevent reads the /sys/block/<device>/uevent file and returns the content.\nfunc readUevent(path string) (map[string]string, error) {\n\tpath = filepath.Join(path, \"uevent\")\n\n\tcontent, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read %q: %w\", path, err)\n\t}\n\n\tresult := map[string]string{}\n\n\tfor kv := range bytes.SplitSeq(content, []byte(\"\\n\")) {\n\t\tkey, value, ok := bytes.Cut(kv, []byte(\"=\"))\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult[string(key)] = string(value)\n\t}\n\n\treturn result, nil\n}\n\n// readPartitions reads partitions for a given device and returns the list of events.\nfunc readPartitions(path string) ([]*kobject.Event, error) {\n\tentries, err := os.ReadDir(path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to read %s: %w\", path, err)\n\t}\n\n\tvar result []*kobject.Event //nolint:prealloc\n\n\tfor _, entry := range entries {\n\t\tif !entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tpartitionPath := filepath.Join(path, entry.Name())\n\n\t\t_, err = os.Stat(filepath.Join(partitionPath, \"partition\"))\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tuevent, err := readUevent(partitionPath)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, &kobject.Event{\n\t\t\tAction:     kobject.Add,\n\t\t\tDevicePath: partitionPath,\n\t\t\tSubsystem:  \"block\",\n\t\t\tValues:     uevent,\n\t\t})\n\t}\n\n\treturn result, nil\n}\n\n// ReadSecondaries reads secondary devices for a given device and returns the list.\nfunc ReadSecondaries(devPath string) []string {\n\tentries, err := os.ReadDir(filepath.Join(devPath, \"slaves\"))\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\treturn xslices.Map(entries, func(entry os.DirEntry) string {\n\t\treturn entry.Name()\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/sysblock/sysblock_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage sysblock_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mdlayher/kobject\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/sysblock\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestWalk(t *testing.T) {\n\tevents, err := sysblock.Walk(\"/sys/block\")\n\trequire.NoError(t, err)\n\n\trequire.NotEmpty(t, events)\n\n\t// there should be at least a single blockdevice and a partition\n\tpartitions, disks := 0, 0\n\n\tfor _, event := range events {\n\t\trequire.Equal(t, \"block\", event.Subsystem)\n\t\trequire.EqualValues(t, kobject.Add, event.Action)\n\n\t\trequire.NotEmpty(t, event.DevicePath)\n\t\trequire.NotEmpty(t, event.Action)\n\n\t\tswitch event.Values[\"DEVTYPE\"] {\n\t\tcase block.DeviceTypePartition:\n\t\t\tpartitions++\n\t\tcase block.DeviceTypeDisk:\n\t\t\tdisks++\n\t\t}\n\t}\n\n\trequire.Greater(t, partitions, 0)\n\trequire.Greater(t, disks, 0)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/close.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Close the encrypted volumes.\nfunc Close(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {\n\tswitch volumeContext.Cfg.TypedSpec().Type {\n\tcase block.VolumeTypeTmpfs, block.VolumeTypeDirectory, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal:\n\t\t// volume types can be always closed\n\t\tvolumeContext.Status.Phase = block.VolumePhaseClosed\n\n\t\treturn nil\n\tcase block.VolumeTypeDisk, block.VolumeTypePartition:\n\t}\n\n\tswitch volumeContext.Cfg.TypedSpec().Encryption.Provider {\n\tcase block.EncryptionProviderNone:\n\t\t// nothing to do\n\t\tvolumeContext.Status.Phase = block.VolumePhaseClosed\n\n\t\treturn nil\n\tcase block.EncryptionProviderLUKS2:\n\t\tencryptionConfig := volumeContext.Cfg.TypedSpec().Encryption\n\n\t\thandler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.EncryptionHelpers)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create encryption handler: %w\", err)\n\t\t}\n\n\t\treturn CloseWithHandler(ctx, logger, volumeContext, handler)\n\tdefault:\n\t\treturn fmt.Errorf(\"provider %s not implemented yet\", volumeContext.Cfg.TypedSpec().Encryption.Provider)\n\t}\n}\n\n// CloseWithHandler closes the encrypted volumes.\nfunc CloseWithHandler(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext, handler *encryption.Handler) error {\n\tctx, cancel := context.WithTimeout(ctx, encryptionTimeout)\n\tdefer cancel()\n\n\tmappedName := handler.Name() + \"-\" + volumeContext.Cfg.Metadata().ID()\n\n\tif err := handler.Close(ctx, mappedName); err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error closing encrypted volume mapped to %q: %w\", mappedName, err)\n\t}\n\n\tvolumeContext.Status.Phase = block.VolumePhaseClosed\n\n\tlogger.Info(\"encrypted volume closed\", zap.String(\"name\", mappedName))\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// DiskRejectedReason is the reason why a disk cannot be used for provisioning.\ntype DiskRejectedReason int\n\n// Possible reasons why a disk cannot be used for provisioning.\nconst (\n\tGeneralError DiskRejectedReason = iota\n\tNotEnoughSpace\n\tWrongFormat\n)\n\n// CheckDiskResult is the result of checking a disk for provisioning.\ntype CheckDiskResult struct {\n\t// CanProvision indicates if the disk can be used for provisioning.\n\tCanProvision bool\n\t// HasGPT indicates if the disk has a GPT partition table.\n\tHasGPT bool\n\t// DiskSize is the size of the disk.\n\tDiskSize uint64\n\t// RejectedReason is the reason why the disk cannot be used for provisioning (if CanProvision is false).\n\tRejectedReason DiskRejectedReason\n}\n\n// CheckDiskForProvisioning checks if the disk can be used for provisioning for the given volume configuration.\nfunc CheckDiskForProvisioning(logger *zap.Logger, diskPath string, volumeCfg *block.VolumeConfig) CheckDiskResult {\n\tinfo, err := blkid.ProbePath(diskPath)\n\tif err != nil {\n\t\tlogger.Error(\"error probing disk\", zap.String(\"disk\", diskPath), zap.Error(err))\n\n\t\treturn CheckDiskResult{}\n\t}\n\n\tswitch volumeCfg.TypedSpec().Type { //nolint:exhaustive\n\tcase block.VolumeTypeDisk:\n\t\treturn CheckDiskResult{\n\t\t\tCanProvision:   info.Name == \"\",\n\t\t\tDiskSize:       info.Size,\n\t\t\tRejectedReason: WrongFormat,\n\t\t}\n\tcase block.VolumeTypePartition:\n\t\tif info.Name == \"\" {\n\t\t\t// if the disk is not partitioned, it can be used for partitioning, but we need to check the size\n\t\t\toverhead := uint64(info.SectorSize) * 67 // GPT + MBR\n\n\t\t\treturn CheckDiskResult{\n\t\t\t\tCanProvision:   info.Size >= volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize+overhead,\n\t\t\t\tDiskSize:       info.Size,\n\t\t\t\tRejectedReason: NotEnoughSpace,\n\t\t\t}\n\t\t}\n\n\t\tif info.Name != \"gpt\" {\n\t\t\t// not empty, and not gpt => can't be used for partitioning\n\t\t\treturn CheckDiskResult{\n\t\t\t\tRejectedReason: WrongFormat,\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tpanic(\"unexpected volume type\")\n\t}\n\n\t// the rest for partition type volumes with existing GPT partition table\n\t// find the amount of space available\n\tdev, err := blockdev.NewFromPath(diskPath)\n\tif err != nil {\n\t\tlogger.Error(\"error opening disk\", zap.String(\"disk\", diskPath), zap.Error(err))\n\n\t\treturn CheckDiskResult{}\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err = dev.TryLock(false); err != nil {\n\t\tlogger.Error(\"error locking disk\", zap.String(\"disk\", diskPath), zap.Error(err))\n\n\t\treturn CheckDiskResult{}\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tgptdev, err := gpt.DeviceFromBlockDevice(dev)\n\tif err != nil {\n\t\tlogger.Error(\"error getting GPT device\", zap.String(\"disk\", diskPath), zap.Error(err))\n\n\t\treturn CheckDiskResult{}\n\t}\n\n\tpt, err := gpt.Read(gptdev)\n\tif err != nil {\n\t\tlogger.Error(\"error reading GPT\", zap.String(\"disk\", diskPath), zap.Error(err))\n\n\t\treturn CheckDiskResult{}\n\t}\n\n\tavailable := pt.LargestContiguousAllocatable()\n\n\tlogger.Debug(\"checking disk for provisioning\", zap.String(\"disk\", diskPath), zap.Uint64(\"available\", available))\n\n\treturn CheckDiskResult{\n\t\tCanProvision:   available >= volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize,\n\t\tHasGPT:         true,\n\t\tDiskSize:       info.Size,\n\t\tRejectedReason: NotEnoughSpace,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/disk_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestCheckDiskForProvisioning(t *testing.T) {\n\tcheckRequirements(t)\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tdiskSetup    func(t *testing.T) string\n\t\tvolumeConfig block.VolumeConfigSpec\n\n\t\texpected volumes.CheckDiskResult\n\t}{\n\t\t{\n\t\t\tname: \"small empty disk\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\treturn prepareRawImage(t, 1<<20)\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 20,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: volumes.CheckDiskResult{\n\t\t\t\tDiskSize: 1 << 20,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"big enough empty disk\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\treturn prepareRawImage(t, 1<<20)\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 18,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: volumes.CheckDiskResult{\n\t\t\t\tCanProvision: true,\n\t\t\t\tDiskSize:     1 << 20,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"big enough formatted disk\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdisk := prepareRawImage(t, 1<<21)\n\n\t\t\t\tformatExt4(t, disk)\n\n\t\t\t\treturn disk\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 18,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: volumes.CheckDiskResult{\n\t\t\t\tCanProvision: false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"big enough empty GPT disk\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdisk := prepareRawImage(t, 1<<24)\n\n\t\t\t\tprepareGPT(t, disk)\n\n\t\t\t\treturn disk\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 20,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: volumes.CheckDiskResult{\n\t\t\t\tCanProvision: true,\n\t\t\t\tHasGPT:       true,\n\t\t\t\tDiskSize:     1 << 24,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tdiskPath := test.diskSetup(t)\n\t\t\tlogger := zaptest.NewLogger(t)\n\n\t\t\tvolumeCfg := block.NewVolumeConfig(block.NamespaceName, \"TEST\")\n\t\t\t*volumeCfg.TypedSpec() = test.volumeConfig\n\n\t\t\tassert.Equal(t, test.expected, volumes.CheckDiskForProvisioning(logger, diskPath, volumeCfg))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/encrypt.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// HandleEncryption makes sure the encryption for the volumes is handled appropriately.\nfunc HandleEncryption(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {\n\tswitch volumeContext.Cfg.TypedSpec().Encryption.Provider {\n\tcase block.EncryptionProviderNone:\n\t\t// nothing to do\n\t\tvolumeContext.Status.Phase = block.VolumePhasePrepared\n\t\tvolumeContext.Status.MountLocation = volumeContext.Status.Location\n\t\tvolumeContext.Status.EncryptionProvider = block.EncryptionProviderNone\n\t\tvolumeContext.Status.EncryptionFailedSyncs = nil\n\t\tvolumeContext.Status.ConfiguredEncryptionKeys = nil\n\n\t\treturn nil\n\tcase block.EncryptionProviderLUKS2:\n\t\tencryptionConfig := volumeContext.Cfg.TypedSpec().Encryption\n\n\t\thandler, err := encryption.NewHandler(encryptionConfig, volumeContext.Cfg.Metadata().ID(), volumeContext.EncryptionHelpers)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create encryption handler: %w\", err)\n\t\t}\n\n\t\treturn HandleEncryptionWithHandler(ctx, logger, volumeContext, handler)\n\tdefault:\n\t\treturn fmt.Errorf(\"provider %s not implemented yet\", volumeContext.Cfg.TypedSpec().Encryption.Provider)\n\t}\n}\n\nconst encryptionTimeout = time.Minute\n\n// HandleEncryptionWithHandler makes sure the encryption for the volumes is handled appropriately.\n//\n//nolint:gocyclo\nfunc HandleEncryptionWithHandler(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext, handler *encryption.Handler) error {\n\tctx, cancel := context.WithTimeout(ctx, encryptionTimeout)\n\tdefer cancel()\n\n\t// lock either the parent device or the device itself\n\tdevPath := volumeContext.Status.ParentLocation\n\tif devPath == \"\" {\n\t\tdevPath = volumeContext.Status.Location\n\t}\n\n\tdev, err := blockdev.NewFromPath(devPath, blockdev.OpenForWrite())\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error opening disk: %w\", err)\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err = dev.RetryLockWithTimeout(ctx, true, 10*time.Second); err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error locking disk: %w\", err)\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tinfo, err := blkid.ProbePath(volumeContext.Status.Location, blkid.WithSkipLocking(true))\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error probing disk: %w\", err)\n\t}\n\n\tswitch info.Name {\n\tcase \"\":\n\t\t// no filesystem, encrypt\n\t\tlogger.Info(\"formatting and encrypting volume\")\n\n\t\tif err = handler.FormatAndEncrypt(ctx, logger, volumeContext.Status.Location); err != nil {\n\t\t\treturn xerrors.NewTaggedf[Retryable](\"error formatting and encrypting volume: %w\", err)\n\t\t}\n\tcase \"luks\":\n\t\t// already encrypted\n\tdefault:\n\t\t// mismatch\n\t\treturn fmt.Errorf(\"block dev type mismatch: %s != %s\", info.Name, \"luks\")\n\t}\n\n\tlogger.Info(\"opening encrypted volume\")\n\n\tmappedName := handler.Name() + \"-\" + volumeContext.Cfg.Metadata().ID()\n\n\tmappedPath, usedSlot, failedSyncs, err := handler.Open(ctx, logger, volumeContext.Status.Location, mappedName)\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error opening encrypted volume: %w\", err)\n\t}\n\n\tresolvedPath, err := filepath.EvalSymlinks(mappedPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error resolving symlink: %w\", err)\n\t}\n\n\tvolumeContext.Status.Phase = block.VolumePhasePrepared\n\tvolumeContext.Status.MountLocation = resolvedPath\n\tvolumeContext.Status.EncryptionProvider = volumeContext.Cfg.TypedSpec().Encryption.Provider\n\tvolumeContext.Status.EncryptionFailedSyncs = failedSyncs\n\n\tvolumeContext.Status.ConfiguredEncryptionKeys = nil\n\tvolumeContext.Status.EncryptionSlot = &usedSlot\n\n\tfor _, key := range volumeContext.Cfg.TypedSpec().Encryption.Keys {\n\t\tprovider := key.Type.String()\n\n\t\tif key.Slot == usedSlot {\n\t\t\tvolumeContext.Status.EncryptionLockedToState = key.LockToSTATE\n\n\t\t\tif provider == \"tpm\" {\n\t\t\t\tvolumeContext.Status.TPMEncryptionOptions = block.TPMEncryptionOptionsInfo{\n\t\t\t\t\tPCRs:       key.TPMPCRs,\n\t\t\t\t\tPubKeyPCRs: key.TPMPubKeyPCRs,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif slices.Index(volumeContext.Status.ConfiguredEncryptionKeys, provider) == -1 {\n\t\t\tvolumeContext.Status.ConfiguredEncryptionKeys = append(volumeContext.Status.ConfiguredEncryptionKeys, provider)\n\t\t}\n\t}\n\n\tslices.Sort(volumeContext.Status.ConfiguredEncryptionKeys)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/encryption_meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\tblocktype \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// MarshalEncryptionMeta is a function to persist encryption config to the META value.\nfunc MarshalEncryptionMeta(cfg config.EncryptionConfig) ([]byte, error) {\n\treturn json.Marshal(cfg)\n}\n\n// UnmarshalEncryptionMeta is a function to load encryption config from the META value.\nfunc UnmarshalEncryptionMeta(data []byte) (config.EncryptionConfig, error) {\n\tvar encryptionFromMeta blocktype.EncryptionSpec\n\n\tif err := json.Unmarshal(data, &encryptionFromMeta); err != nil {\n\t\tvar legacyEncryption v1alpha1.EncryptionConfig\n\n\t\tif legacyErr := json.Unmarshal(data, &legacyEncryption); legacyErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"error unmarshalling state encryption meta key: %w\", err)\n\t\t}\n\n\t\treturn &legacyEncryption, nil\n\t}\n\n\treturn &encryptionFromMeta, nil\n}\n\n// ConvertEncryptionConfiguration converts a `config.EncryptionConfig` into a\n// `block.EncryptionSpec`, and writes it into `out`.\nfunc ConvertEncryptionConfiguration(in config.EncryptionConfig, out *block.VolumeConfigSpec) error {\n\treturn blockadapter.VolumeConfigSpec(out).ApplyEncryptionConfig(in)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/encryption_meta_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc legacyEncryptionConfig() config.EncryptionConfig {\n\treturn &v1alpha1.EncryptionConfig{\n\t\tEncryptionCipher: \"aes-xts-plain64\",\n\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeyStatic: &v1alpha1.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"secret\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeyNodeID: &v1alpha1.EncryptionKeyNodeID{},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc modernEncryptionConfig() config.EncryptionConfig {\n\treturn blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\tEncryptionCipher:   \"aes-xts-plain64\",\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"secret\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeyNodeID: &blockcfg.EncryptionKeyNodeID{},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc assertEqualEncryptionConfigs(t *testing.T, a, b config.EncryptionConfig) {\n\tt.Helper()\n\n\trequire.NotNil(t, a)\n\trequire.NotNil(t, b)\n\n\tassert.Equal(t, a.Provider(), b.Provider())\n\tassert.Equal(t, a.Cipher(), b.Cipher())\n\tassert.Equal(t, a.KeySize(), b.KeySize())\n\tassert.Equal(t, a.BlockSize(), b.BlockSize())\n\tassert.ElementsMatch(t, a.Options(), b.Options())\n\n\trequire.Equal(t, len(a.Keys()), len(b.Keys()))\n\n\tfor i := range a.Keys() {\n\t\tassert.Equal(t, a.Keys()[i].Slot(), b.Keys()[i].Slot())\n\t\tassert.Equal(t, a.Keys()[i].Static(), b.Keys()[i].Static())\n\t\tassert.Equal(t, a.Keys()[i].NodeID(), b.Keys()[i].NodeID())\n\t\tassert.Equal(t, a.Keys()[i].KMS(), b.Keys()[i].KMS())\n\t\tassert.Equal(t, a.Keys()[i].TPM(), b.Keys()[i].TPM())\n\t\tassert.Equal(t, a.Keys()[i].LockToSTATE(), b.Keys()[i].LockToSTATE())\n\t}\n}\n\n//nolint:lll\nconst (\n\tlegacyMarshalled = `{\"EncryptionProvider\":\"\",\"EncryptionKeys\":[{\"KeyStatic\":{\"KeyData\":\"secret\"},\"KeyNodeID\":null,\"KeyKMS\":null,\"KeySlot\":0,\"KeyTPM\":null},{\"KeyStatic\":null,\"KeyNodeID\":{},\"KeyKMS\":null,\"KeySlot\":0,\"KeyTPM\":null}],\"EncryptionCipher\":\"aes-xts-plain64\",\"EncryptionKeySize\":0,\"EncryptionBlockSize\":0,\"EncryptionPerfOptions\":null}`\n\tmodernMarshalled = `{\"EncryptionProvider\":\"luks2\",\"EncryptionKeys\":[{\"KeySlot\":0,\"KeyStatic\":{\"KeyData\":\"secret\"},\"KeyNodeID\":null,\"KeyKMS\":null,\"KeyTPM\":null,\"KeyLockToSTATE\":null},{\"KeySlot\":0,\"KeyStatic\":null,\"KeyNodeID\":{},\"KeyKMS\":null,\"KeyTPM\":null,\"KeyLockToSTATE\":null}],\"EncryptionCipher\":\"aes-xts-plain64\",\"EncryptionKeySize\":0,\"EncryptionBlockSize\":0,\"EncryptionPerfOptions\":null}`\n)\n\nfunc TestMarshalEncryptionMeta(t *testing.T) {\n\tt.Parallel()\n\n\tdata, err := volumes.MarshalEncryptionMeta(legacyEncryptionConfig())\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, legacyMarshalled, string(data))\n\n\tdata, err = volumes.MarshalEncryptionMeta(modernEncryptionConfig())\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, modernMarshalled, string(data))\n}\n\nfunc TestUnmarshalEncryptionMeta(t *testing.T) {\n\tt.Parallel()\n\n\tcfg, err := volumes.UnmarshalEncryptionMeta([]byte(legacyMarshalled))\n\trequire.NoError(t, err)\n\n\tassertEqualEncryptionConfigs(t, cfg, legacyEncryptionConfig())\n\n\tcfg, err = volumes.UnmarshalEncryptionMeta([]byte(modernMarshalled))\n\trequire.NoError(t, err)\n\n\tassertEqualEncryptionConfigs(t, cfg, modernEncryptionConfig())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/format.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/swap\"\n\t\"go.uber.org/zap\"\n\n\tmountv3 \"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\n// Format establishes a filesystem on a block device.\n//\n//nolint:gocyclo,cyclop\nfunc Format(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {\n\t// lock either the parent device or the device itself\n\tdevPath := volumeContext.Status.ParentLocation\n\tif devPath == \"\" {\n\t\tdevPath = volumeContext.Status.Location\n\t}\n\n\tdev, err := blockdev.NewFromPath(devPath)\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error opening disk: %w\", err)\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err = dev.RetryLockWithTimeout(ctx, true, 10*time.Second); err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error locking disk: %w\", err)\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tinfo, err := blkid.ProbePath(volumeContext.Status.MountLocation, blkid.WithSkipLocking(true))\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error probing disk: %w\", err)\n\t}\n\n\tswitch {\n\tcase volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type == block.FilesystemTypeNone:\n\t\tvolumeContext.Status.Filesystem, _ = block.FilesystemTypeString(info.Name) //nolint:errcheck\n\n\t\t// this is mountable\n\t\tif volumeContext.Cfg.TypedSpec().Mount.TargetPath != \"\" {\n\t\t\tswitch info.Name {\n\t\t\tcase \"\":\n\t\t\t\treturn fmt.Errorf(\"filesystem not found on %s\", volumeContext.Status.MountLocation)\n\t\t\tcase \"luks\":\n\t\t\t\t// this volume is actually encrypted, but we got here without encryption config, move phase back\n\t\t\t\tvolumeContext.Status.Phase = block.VolumePhaseProvisioned\n\n\t\t\t\treturn fmt.Errorf(\"volume is encrypted, but no encryption config provided\")\n\t\t\t}\n\t\t}\n\n\t\tvolumeContext.Status.Phase = block.VolumePhaseReady\n\n\t\treturn nil\n\tcase info.Name == \"\":\n\t\t// no filesystem, format\n\tcase info.Name == \"swap\":\n\t\t// swap volume, format always\n\tcase info.Name == volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type.String():\n\t\t// filesystem already exists and matches the requested type\n\t\tif volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.Grow {\n\t\t\t// if the partition is set to grow, we need to grow the filesystem\n\t\t\tif err = GrowFilesystem(ctx, logger, volumeContext); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error growing filesystem: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvolumeContext.Status.Phase = block.VolumePhaseReady\n\t\tvolumeContext.Status.Filesystem = volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type\n\n\t\treturn nil\n\tdefault:\n\t\t// mismatch\n\t\treturn fmt.Errorf(\"filesystem type mismatch: %s != %s\", info.Name, volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t}\n\n\tlogger.Info(\"formatting filesystem\",\n\t\tzap.String(\"device\", volumeContext.Status.MountLocation),\n\t\tzap.Stringer(\"filesystem\", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type),\n\t)\n\n\tswitch volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type { //nolint:exhaustive\n\tcase block.FilesystemTypeXFS:\n\t\tvar makefsOptions []makefs.Option\n\n\t\t// xfs doesn't support by default filesystems < 300 MiB\n\t\tif volumeContext.Status.Size <= 300*1024*1024 {\n\t\t\tmakefsOptions = append(makefsOptions, makefs.WithUnsupportedFSOption(true))\n\t\t}\n\n\t\tif volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label != \"\" {\n\t\t\tmakefsOptions = append(makefsOptions, makefs.WithLabel(volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label))\n\t\t}\n\n\t\tmakefsOptions = append(makefsOptions, makefs.WithConfigFile(quirks.New(\"\").XFSMkfsConfig()))\n\n\t\tif err = makefs.XFS(ctx, volumeContext.Status.MountLocation, makefsOptions...); err != nil {\n\t\t\treturn xerrors.NewTaggedf[Retryable](\"error formatting XFS: %w\", err)\n\t\t}\n\tcase block.FilesystemTypeEXT4:\n\t\tvar makefsOptions []makefs.Option\n\n\t\tif volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label != \"\" {\n\t\t\tmakefsOptions = append(makefsOptions, makefs.WithLabel(volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label))\n\t\t}\n\n\t\tif err = makefs.Ext4(ctx, volumeContext.Status.MountLocation, makefsOptions...); err != nil {\n\t\t\treturn xerrors.NewTaggedf[Retryable](\"error formatting ext4: %w\", err)\n\t\t}\n\tcase block.FilesystemTypeSwap:\n\t\tif err = swap.Format(volumeContext.Status.MountLocation, swap.FormatOptions{\n\t\t\tLabel: volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Label,\n\t\t\tUUID:  uuid.New(),\n\t\t}); err != nil {\n\t\t\treturn xerrors.NewTaggedf[Retryable](\"error formatting swap: %w\", err)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported filesystem type: %s\", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t}\n\n\tvolumeContext.Status.Phase = block.VolumePhaseReady\n\tvolumeContext.Status.Filesystem = volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type\n\n\treturn nil\n}\n\n// GrowFilesystem grows the filesystem on the block device.\nfunc GrowFilesystem(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {\n\tswitch volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type { //nolint:exhaustive\n\tcase block.FilesystemTypeXFS:\n\t\t// XFS requires partition to be mounted to grow\n\t\ttmpDir, err := os.MkdirTemp(\"\", \"talos-growfs-\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating temporary directory: %w\", err)\n\t\t}\n\n\t\tdefer os.Remove(tmpDir) //nolint:errcheck\n\n\t\tmanager := mountv3.NewManager(\n\t\t\tmountv3.WithPrinter(logger.Sugar().Infof),\n\t\t\tmountv3.WithTarget(tmpDir),\n\t\t\tmountv3.WithFsopen(\n\t\t\t\tvolumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type.String(),\n\t\t\t\tfsopen.WithSource(volumeContext.Status.MountLocation),\n\t\t\t),\n\t\t)\n\n\t\tif _, err := manager.Mount(); err != nil {\n\t\t\treturn fmt.Errorf(\"error mounting partition: %w\", err)\n\t\t}\n\n\t\tdefer manager.Unmount() //nolint:errcheck\n\n\t\tlogger.Info(\"growing XFS filesystem\", zap.String(\"device\", volumeContext.Status.MountLocation))\n\n\t\tif err = makefs.XFSGrow(ctx, tmpDir); err != nil {\n\t\t\treturn fmt.Errorf(\"error growing XFS: %w\", err)\n\t\t}\n\n\t\treturn nil\n\tcase block.FilesystemTypeEXT4:\n\t\tlogger.Info(\"growing ext4 filesystem\", zap.String(\"device\", volumeContext.Status.MountLocation))\n\n\t\tif err := makefs.Ext4Resize(ctx, volumeContext.Status.MountLocation); err != nil {\n\t\t\treturn fmt.Errorf(\"error growing ext4: %w\", err)\n\t\t}\n\n\t\treturn nil\n\tcase block.FilesystemTypeSwap:\n\t\t// swap is always reformatted, so we don't need to grow it\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported filesystem type to grow: %s\", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/grow.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Grow grows a volume.\n//\n//nolint:gocyclo\nfunc Grow(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {\n\tif !(volumeContext.Cfg.TypedSpec().Type == block.VolumeTypePartition && volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.Grow) {\n\t\t// nothing to do\n\t\tvolumeContext.Status.Phase = block.VolumePhaseProvisioned\n\n\t\treturn nil\n\t}\n\n\tif volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize > 0 && volumeContext.Status.Size >= volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize {\n\t\t// nowhere to grow\n\t\tvolumeContext.Status.Phase = block.VolumePhaseProvisioned\n\n\t\treturn nil\n\t}\n\n\tdev, err := blockdev.NewFromPath(volumeContext.Status.ParentLocation, blockdev.OpenForWrite())\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error opening disk: %w\", err)\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err = dev.RetryLockWithTimeout(ctx, true, 10*time.Second); err != nil {\n\t\treturn xerrors.NewTaggedf[Retryable](\"error locking disk: %w\", err)\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tgptdev, err := gpt.DeviceFromBlockDevice(dev)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting GPT device: %w\", err)\n\t}\n\n\tpt, err := gpt.Read(gptdev)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing GPT: %w\", err)\n\t}\n\n\tavailableGrowth, err := pt.AvailablePartitionGrowth(volumeContext.Status.PartitionIndex - 1)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting available partition growth: %w\", err)\n\t}\n\n\tif availableGrowth <= 1024*1024 { // don't grow by less than 1MiB\n\t\tvolumeContext.Status.Phase = block.VolumePhaseProvisioned\n\n\t\treturn nil\n\t}\n\n\tif volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize > 0 && availableGrowth > volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize-volumeContext.Status.Size {\n\t\tavailableGrowth = volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize - volumeContext.Status.Size\n\t}\n\n\tlogger.Debug(\"growing partition\", zap.String(\"disk\", volumeContext.Status.ParentLocation), zap.Int(\"partition\", volumeContext.Status.PartitionIndex), zap.Uint64(\"size\", availableGrowth))\n\n\tif err = pt.GrowPartition(volumeContext.Status.PartitionIndex-1, availableGrowth); err != nil {\n\t\treturn fmt.Errorf(\"error growing partition: %w\", err)\n\t}\n\n\tif err = pt.Write(); err != nil {\n\t\treturn fmt.Errorf(\"error writing GPT: %w\", err)\n\t}\n\n\tvolumeContext.Status.Phase = block.VolumePhaseProvisioned\n\tvolumeContext.Status.SetSize(volumeContext.Status.Size + availableGrowth)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/grow_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n//nolint:dupl\nfunc TestGrow(t *testing.T) {\n\tcheckRequirements(t)\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tdiskSetup    func(t *testing.T) string\n\t\tvolumeConfig block.VolumeConfigSpec\n\t\tvolumeStatus block.VolumeStatusSpec\n\n\t\texpectedSize uint64\n\t}{\n\t\t{\n\t\t\tname: \"grow at the end of the disk\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdiskPath := prepareRawImage(t, 1<<23)\n\n\t\t\t\tprepareGPT(t, diskPath,\n\t\t\t\t\tfunc(pt *gpt.Table) {\n\t\t\t\t\t\t_, _, err := pt.AllocatePartition(1<<20, \"GROWS\", uuid.MustParse(\"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\"))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn diskPath\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 20,\n\t\t\t\t\t\tGrow:    true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tvolumeStatus: block.VolumeStatusSpec{\n\t\t\t\tSize:           1 << 20,\n\t\t\t\tPartitionIndex: 1,\n\t\t\t},\n\n\t\t\texpectedSize: 1<<23 - 2*(1<<20),\n\t\t},\n\t\t{\n\t\t\tname: \"grow to max size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdiskPath := prepareRawImage(t, 1<<23)\n\n\t\t\t\tprepareGPT(t, diskPath,\n\t\t\t\t\tfunc(pt *gpt.Table) {\n\t\t\t\t\t\t_, _, err := pt.AllocatePartition(1<<20, \"GROWS\", uuid.MustParse(\"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\"))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn diskPath\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 20,\n\t\t\t\t\t\tMaxSize: 1 << 22,\n\t\t\t\t\t\tGrow:    true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tvolumeStatus: block.VolumeStatusSpec{\n\t\t\t\tSize:           1 << 20,\n\t\t\t\tPartitionIndex: 1,\n\t\t\t},\n\n\t\t\texpectedSize: 1 << 22,\n\t\t},\n\t\t{\n\t\t\tname: \"doesn't grow at max size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdiskPath := prepareRawImage(t, 1<<23)\n\n\t\t\t\tprepareGPT(t, diskPath,\n\t\t\t\t\tfunc(pt *gpt.Table) {\n\t\t\t\t\t\t_, _, err := pt.AllocatePartition(1<<21, \"BIG\", uuid.MustParse(\"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\"))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn diskPath\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize: 1 << 20,\n\t\t\t\t\t\tMaxSize: 1 << 21,\n\t\t\t\t\t\tGrow:    true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tvolumeStatus: block.VolumeStatusSpec{\n\t\t\t\tSize:           1 << 21,\n\t\t\t\tPartitionIndex: 1,\n\t\t\t},\n\n\t\t\texpectedSize: 1 << 21,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 30*time.Second)\n\t\t\tt.Cleanup(cancel)\n\n\t\t\tlogger := zaptest.NewLogger(t)\n\n\t\t\tvolumeCfg := block.NewVolumeConfig(block.NamespaceName, \"TEST\")\n\t\t\t*volumeCfg.TypedSpec() = test.volumeConfig\n\n\t\t\tvolumeStatus := test.volumeStatus\n\t\t\tvolumeStatus.ParentLocation = test.diskSetup(t)\n\n\t\t\tmanagerContext := volumes.ManagerContext{\n\t\t\t\tCfg:    volumeCfg,\n\t\t\t\tStatus: &volumeStatus,\n\t\t\t}\n\n\t\t\tvar err error\n\n\t\t\tfor range 10 {\n\t\t\t\terr = volumes.Grow(ctx, logger, managerContext)\n\t\t\t\tif err != nil && xerrors.TagIs[volumes.Retryable](err) {\n\t\t\t\t\t// retry various disk locked and other retryable errors\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, block.VolumePhaseProvisioned, volumeStatus.Phase)\n\t\t\tassert.Equal(t, test.expectedSize, volumeStatus.Size)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/helpers_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"errors\"\n\trandv2 \"math/rand/v2\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/freddierice/go-losetup/v2\"\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc checkRequirements(t *testing.T) {\n\tt.Helper()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"test requires root privileges\")\n\t}\n\n\tif hostname, _ := os.Hostname(); hostname == \"buildkitsandbox\" { //nolint: errcheck\n\t\tt.Skip(\"test not supported under buildkit as partition devices are not propagated from /dev\")\n\t}\n}\n\nfunc losetupAttachHelper(t *testing.T, rawImage string, readonly bool) losetup.Device {\n\tt.Helper()\n\n\tfor range 10 {\n\t\tloDev, err := losetup.Attach(rawImage, 0, readonly)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, unix.EBUSY) {\n\t\t\t\tspraySleep := max(randv2.ExpFloat64(), 2.0)\n\n\t\t\t\tt.Logf(\"retrying after %v seconds\", spraySleep)\n\n\t\t\t\ttime.Sleep(time.Duration(spraySleep * float64(time.Second)))\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\trequire.NoError(t, err)\n\n\t\treturn loDev\n\t}\n\n\tt.Fatal(\"failed to attach loop device\") //nolint:revive\n\n\tpanic(\"unreachable\")\n}\n\nfunc prepareRawImage(t *testing.T, size int64) string {\n\tt.Helper()\n\n\ttmpDir := t.TempDir()\n\n\trawImage := filepath.Join(tmpDir, \"image.raw\")\n\n\tf, err := os.Create(rawImage)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f.Truncate(size))\n\trequire.NoError(t, f.Close())\n\n\tloDev := losetupAttachHelper(t, rawImage, false)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, loDev.Detach())\n\t})\n\n\treturn loDev.Path()\n}\n\nfunc formatExt4(t *testing.T, path string) {\n\tt.Helper()\n\n\tcmd := exec.CommandContext(t.Context(), \"mkfs.ext4\", \"-L\", \"extlabel\", path)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\trequire.NoError(t, cmd.Run())\n}\n\nfunc prepareGPT(t *testing.T, path string, funcs ...func(*gpt.Table)) {\n\tt.Helper()\n\n\tblkdev, err := block.NewFromPath(path, block.OpenForWrite())\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, blkdev.Close())\n\t})\n\n\tgptdev, err := gpt.DeviceFromBlockDevice(blkdev)\n\trequire.NoError(t, err)\n\n\tpt, err := gpt.New(gptdev)\n\trequire.NoError(t, err)\n\n\tfor _, f := range funcs {\n\t\tf(pt)\n\t}\n\n\trequire.NoError(t, pt.Write())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/locate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning\"\n\t\"go.uber.org/zap\"\n\n\tblockpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// LocateAndProvision locates and provisions a volume.\nfunc LocateAndProvision(ctx context.Context, logger *zap.Logger, vc ManagerContext) error {\n\t// 1. Setup common status fields\n\tvc.Status.MountSpec = vc.Cfg.TypedSpec().Mount\n\tvc.Status.SymlinkSpec = vc.Cfg.TypedSpec().Symlink\n\n\t// 2. Handle simple types (Tmpfs, Overlay, External, etc.)\n\t// If handled, we return early.\n\tif done := handleSimpleVolumeTypes(vc); done {\n\t\treturn nil\n\t}\n\n\t// 3. Validation for Disk/Partition types\n\tif value.IsZero(vc.Cfg.TypedSpec().Locator) {\n\t\treturn fmt.Errorf(\"volume locator is not set\")\n\t}\n\n\t// 4. Attempt to locate an existing volume\n\tlocated, err := locateExistingVolume(vc)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif located {\n\t\treturn nil\n\t}\n\n\t// 5. Handle Waiting State\n\t// If not found and devices aren't ready, we must wait.\n\tif !vc.DevicesReady {\n\t\tvc.Status.Phase = block.VolumePhaseWaiting\n\n\t\treturn nil\n\t}\n\n\t// 6. Provision new volume\n\treturn provisionNewVolume(ctx, logger, vc)\n}\n\n// handleSimpleVolumeTypes handles non-provisionable types.\n// Returns true if the volume type was handled.\nfunc handleSimpleVolumeTypes(vc ManagerContext) bool {\n\tspec := vc.Cfg.TypedSpec()\n\n\tswitch spec.Type {\n\tcase block.VolumeTypeTmpfs, block.VolumeTypeDirectory, block.VolumeTypeSymlink, block.VolumeTypeOverlay:\n\t\tvc.Status.Phase = block.VolumePhaseReady\n\n\t\treturn true\n\n\tcase block.VolumeTypeExternal:\n\t\tvc.Status.Phase = block.VolumePhaseReady\n\t\tvc.Status.Filesystem = spec.Provisioning.FilesystemSpec.Type\n\t\tvc.Status.Location = spec.Provisioning.DiskSelector.External\n\t\tvc.Status.MountLocation = spec.Provisioning.DiskSelector.External\n\n\t\treturn true\n\n\tcase block.VolumeTypeDisk, block.VolumeTypePartition:\n\t\tfallthrough\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// locateExistingVolume iterates through discovered volumes or disks to find a match.\n//\n// For disk volumes with a DiskMatch locator the function iterates over disks\n// (each disk is evaluated exactly once) and then picks the best discovered\n// volume for the matched disk.  For all other volume types it iterates over\n// discovered volumes and returns on the first match.\nfunc locateExistingVolume(vc ManagerContext) (bool, error) {\n\tspec := vc.Cfg.TypedSpec()\n\n\tswitch {\n\tcase !spec.Locator.DiskMatch.IsZero():\n\t\tif spec.Type != block.VolumeTypeDisk {\n\t\t\treturn false, fmt.Errorf(\"DiskMatch locator is only valid for disk volumes\")\n\t\t}\n\n\t\treturn locateDiskByDiskMatch(vc)\n\tcase !spec.Locator.Match.IsZero():\n\t\treturn locateVolumeByMatch(vc)\n\tdefault:\n\t\treturn false, fmt.Errorf(\"no locator expression set for volume\")\n\t}\n}\n\n// locateDiskByDiskMatch handles VolumeTypeDisk with Locator.DiskMatch.\n//\n// It iterates over disks (not discovered volumes), so each physical disk is\n// evaluated exactly once. If more than one disk matches, an error is returned.\n// The best discovered volume for the matched disk is then selected, preferring\n// whole-disk entries over partition entries.\n//\n//nolint:gocyclo\nfunc locateDiskByDiskMatch(vc ManagerContext) (bool, error) {\n\tspec := vc.Cfg.TypedSpec()\n\tenv := celenv.DiskLocator()\n\n\tvar matchedDisks []string\n\n\tfor _, diskCtx := range vc.Disks {\n\t\tmatches, err := spec.Locator.DiskMatch.EvalBool(env, map[string]any{\"disk\": diskCtx.Disk})\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error evaluating disk locator: %w\", err)\n\t\t}\n\n\t\tif matches {\n\t\t\tmatchedDisks = append(matchedDisks, diskCtx.Disk.DevPath)\n\t\t}\n\t}\n\n\tif len(matchedDisks) > 1 {\n\t\treturn false, fmt.Errorf(\"multiple disks matched locator for disk volume; matched disks: %v\", matchedDisks)\n\t}\n\n\tif len(matchedDisks) == 0 {\n\t\treturn false, nil\n\t}\n\n\tdiskDev := matchedDisks[0]\n\n\t// Find the best discovered volume for this disk, preferring whole-disk\n\t// entries (ParentDevPath == \"\") over partition entries.\n\tvar matchedVol *blockpb.DiscoveredVolumeSpec\n\n\tfor _, dv := range vc.DiscoveredVolumes {\n\t\tif dv.DevPath != diskDev && dv.ParentDevPath != diskDev {\n\t\t\tcontinue\n\t\t}\n\n\t\tif matchedVol == nil || (matchedVol.ParentDevPath != \"\" && dv.ParentDevPath == \"\") {\n\t\t\tmatchedVol = dv\n\t\t}\n\t}\n\n\tif matchedVol != nil {\n\t\tapplyLocatedStatus(vc, matchedVol)\n\n\t\treturn true, nil\n\t}\n\n\treturn false, nil\n}\n\n// locateVolumeByMatch handles volumes with Locator.Match (a CEL expression\n// evaluated against each discovered volume).\nfunc locateVolumeByMatch(vc ManagerContext) (bool, error) {\n\tspec := vc.Cfg.TypedSpec()\n\tenv := celenv.VolumeLocator()\n\n\tfor _, dv := range vc.DiscoveredVolumes {\n\t\tmatchContext := map[string]any{\"volume\": dv}\n\n\t\t// Resolve the parent disk for CEL context\n\t\tfor _, diskCtx := range vc.Disks {\n\t\t\tif (dv.ParentDevPath != \"\" && diskCtx.Disk.DevPath == dv.ParentDevPath) ||\n\t\t\t\t(dv.ParentDevPath == \"\" && diskCtx.Disk.DevPath == dv.DevPath) {\n\t\t\t\tmatchContext[\"disk\"] = diskCtx.Disk\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tmatches, err := spec.Locator.Match.EvalBool(env, matchContext)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error evaluating volume locator: %w\", err)\n\t\t}\n\n\t\tif matches {\n\t\t\tapplyLocatedStatus(vc, dv)\n\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\n// applyLocatedStatus updates the status when a volume is found.\nfunc applyLocatedStatus(vc ManagerContext, vol *blockpb.DiscoveredVolumeSpec) {\n\tvc.Status.Phase = block.VolumePhaseLocated\n\tvc.Status.Location = vol.DevPath\n\tvc.Status.PartitionIndex = int(vol.PartitionIndex)\n\tvc.Status.ParentLocation = vol.ParentDevPath\n\tvc.Status.UUID = vol.Uuid\n\tvc.Status.PartitionUUID = vol.PartitionUuid\n\tvc.Status.SetSize(vol.Size)\n}\n\n// provisionNewVolume handles the creation/provisioning of missing volumes.\nfunc provisionNewVolume(ctx context.Context, logger *zap.Logger, vc ManagerContext) error {\n\tspec := vc.Cfg.TypedSpec()\n\n\t// Pre-checks\n\tif value.IsZero(spec.Provisioning) {\n\t\tvc.Status.Phase = block.VolumePhaseMissing\n\n\t\treturn nil\n\t}\n\n\tif !vc.PreviousWaveProvisioned {\n\t\tvc.Status.Phase = block.VolumePhaseWaiting\n\n\t\treturn nil\n\t}\n\n\t// 1. Find candidate disks\n\tcandidates, err := findCandidateDisks(vc)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlogger.Debug(\"matched disks\", zap.Strings(\"disks\", candidates))\n\n\t// 2. Select the best fit\n\tpickedDisk, diskRes, err := selectBestDisk(logger, candidates, vc.Cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlogger.Debug(\"picked disk\", zap.String(\"disk\", pickedDisk))\n\n\t// 3. Apply Provisioning (Update status or Create Partition)\n\treturn applyProvisioning(ctx, logger, vc, pickedDisk, diskRes)\n}\n\n// findCandidateDisks filters available disks based on the selector.\nfunc findCandidateDisks(vc ManagerContext) ([]string, error) {\n\tvar matchedDisks []string\n\n\tspec := vc.Cfg.TypedSpec()\n\n\tfor _, diskCtx := range vc.Disks {\n\t\tif diskCtx.Disk.Readonly {\n\t\t\tcontinue\n\t\t}\n\n\t\tmatches, err := spec.Provisioning.DiskSelector.Match.EvalBool(celenv.DiskLocator(), diskCtx.ToCELContext())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error evaluating disk locator: %w\", err)\n\t\t}\n\n\t\tif matches {\n\t\t\tmatchedDisks = append(matchedDisks, diskCtx.Disk.DevPath)\n\t\t}\n\t}\n\n\tif len(matchedDisks) == 0 {\n\t\treturn nil, fmt.Errorf(\"no disks matched selector for volume\")\n\t}\n\n\tif spec.Type == block.VolumeTypeDisk && len(matchedDisks) > 1 {\n\t\treturn nil, fmt.Errorf(\"multiple disks matched locator for disk volume; matched disks: %v\", matchedDisks)\n\t}\n\n\treturn matchedDisks, nil\n}\n\n// selectBestDisk analyzes candidates and picks the one that satisfies constraints.\nfunc selectBestDisk(logger *zap.Logger, candidates []string, cfg *block.VolumeConfig) (string, CheckDiskResult, error) {\n\tvar (\n\t\tpickedDisk      string\n\t\tfinalResult     CheckDiskResult\n\t\trejectedReasons = map[DiskRejectedReason]int{}\n\t)\n\n\tfor _, disk := range candidates {\n\t\tres := CheckDiskForProvisioning(logger, disk, cfg)\n\t\tif res.CanProvision {\n\t\t\tpickedDisk = disk\n\t\t\tfinalResult = res\n\n\t\t\tbreak\n\t\t}\n\n\t\trejectedReasons[res.RejectedReason]++\n\t}\n\n\tif pickedDisk == \"\" {\n\t\terr := xerrors.NewTaggedf[Retryable](\n\t\t\t\"no disks matched for volume (%d matched selector): %d have not enough space, %d have wrong format, %d have other issues\",\n\t\t\tlen(candidates),\n\t\t\trejectedReasons[NotEnoughSpace],\n\t\t\trejectedReasons[WrongFormat],\n\t\t\trejectedReasons[GeneralError],\n\t\t)\n\n\t\treturn \"\", CheckDiskResult{}, err\n\t}\n\n\treturn pickedDisk, finalResult, nil\n}\n\n// applyProvisioning performs the final provisioning step.\nfunc applyProvisioning(ctx context.Context, logger *zap.Logger, vc ManagerContext, disk string, res CheckDiskResult) error {\n\tswitch vc.Cfg.TypedSpec().Type {\n\tcase block.VolumeTypeDisk:\n\t\tvc.Status.Phase = block.VolumePhaseProvisioned\n\t\tvc.Status.Location = disk\n\t\tvc.Status.ParentLocation = \"\"\n\t\tvc.Status.SetSize(res.DiskSize)\n\n\tcase block.VolumeTypePartition:\n\t\tpartRes, err := CreatePartition(ctx, logger, disk, vc.Cfg, res.HasGPT)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating partition: %w\", err)\n\t\t}\n\n\t\tvc.Status.Phase = block.VolumePhaseProvisioned\n\t\tvc.Status.Location = partitioning.DevName(disk, uint(partRes.PartitionIdx))\n\t\tvc.Status.PartitionIndex = partRes.PartitionIdx\n\t\tvc.Status.ParentLocation = disk\n\t\tvc.Status.PartitionUUID = partRes.Partition.PartGUID.String()\n\t\tvc.Status.SetSize(partRes.Size)\n\n\tcase block.VolumeTypeTmpfs, block.VolumeTypeDirectory, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal:\n\t\tfallthrough\n\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected volume type: %s\", vc.Cfg.TypedSpec().Type))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/locate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\tblockpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\ttaloscel \"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestLocateAndProvision(t *testing.T) {\n\t// Helpers to reduce boilerplate in test table\n\tmkCEL := func(expr string, env *cel.Env) taloscel.Expression {\n\t\treturn taloscel.MustExpression(taloscel.ParseBooleanExpression(expr, env))\n\t}\n\n\tmkDisk := func(dev string, size uint64, opts ...func(*blockpb.DiskSpec)) volumes.DiskContext {\n\t\td := &blockpb.DiskSpec{DevPath: dev, Size: size}\n\t\tfor _, opt := range opts {\n\t\t\topt(d)\n\t\t}\n\n\t\treturn volumes.DiskContext{Disk: d}\n\t}\n\n\tmkVol := func(dev string, parent string, size uint64, opts ...func(*blockpb.DiscoveredVolumeSpec)) *blockpb.DiscoveredVolumeSpec {\n\t\tv := &blockpb.DiscoveredVolumeSpec{DevPath: dev, ParentDevPath: parent, Size: size}\n\t\tfor _, opt := range opts {\n\t\t\topt(v)\n\t\t}\n\n\t\treturn v\n\t}\n\n\t// Option helpers\n\twithLabel := func(l string) func(*blockpb.DiscoveredVolumeSpec) {\n\t\treturn func(v *blockpb.DiscoveredVolumeSpec) { v.PartitionLabel = l }\n\t}\n\twithName := func(n string) func(*blockpb.DiscoveredVolumeSpec) {\n\t\treturn func(v *blockpb.DiscoveredVolumeSpec) { v.Name = n }\n\t}\n\twithUUID := func(u string) func(*blockpb.DiscoveredVolumeSpec) {\n\t\treturn func(v *blockpb.DiscoveredVolumeSpec) { v.Uuid = u }\n\t}\n\twithSerial := func(s string) func(*blockpb.DiskSpec) { return func(d *blockpb.DiskSpec) { d.Serial = s } }\n\treadOnly := func(d *blockpb.DiskSpec) { d.Readonly = true }\n\n\t// Constants\n\tconst gb = 1 << 30\n\n\t//nolint:dupl\n\ttests := []struct {\n\t\tname                string\n\t\tvolumeConfig        block.VolumeConfigSpec\n\t\tdiscoveredVolumes   []*blockpb.DiscoveredVolumeSpec\n\t\tdisks               []volumes.DiskContext\n\t\tdevicesReady        bool\n\t\tprevWaveProvisioned bool\n\t\texpectedPhase       block.VolumePhase\n\t\texpectedError       string\n\t\tassertStatus        func(*testing.T, block.VolumeStatusSpec)\n\t}{\n\t\t// --- Simple Volume Types ---\n\t\t{\n\t\t\tname:          \"tmpfs volume is always ready\",\n\t\t\tvolumeConfig:  block.VolumeConfigSpec{Type: block.VolumeTypeTmpfs},\n\t\t\texpectedPhase: block.VolumePhaseReady,\n\t\t},\n\t\t{\n\t\t\tname: \"external volume is ready with location\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypeExternal,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tDiskSelector:   block.DiskSelector{External: \"/dev/ext0\"},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{Type: block.FilesystemTypeXFS},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedPhase: block.VolumePhaseReady,\n\t\t\tassertStatus: func(t *testing.T, s block.VolumeStatusSpec) {\n\t\t\t\tassert.Equal(t, block.FilesystemTypeXFS, s.Filesystem)\n\t\t\t\tassert.Equal(t, \"/dev/ext0\", s.Location)\n\t\t\t},\n\t\t},\n\n\t\t// --- Validation ---\n\t\t{\n\t\t\tname:          \"partition with zero locator fails\",\n\t\t\tvolumeConfig:  block.VolumeConfigSpec{Type: block.VolumeTypePartition},\n\t\t\texpectedError: \"volume locator is not set\",\n\t\t},\n\n\t\t// --- Locator Logic ---\n\t\t{\n\t\t\tname: \"located via Match expression (Partition)\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tMatch: mkCEL(`volume.partition_label == \"STATE\"`, celenv.VolumeLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdiscoveredVolumes: []*blockpb.DiscoveredVolumeSpec{\n\t\t\t\tmkVol(\"/dev/sda1\", \"/dev/sda\", 1*gb, withLabel(\"STATE\"), withUUID(\"uuid-123\")),\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{mkDisk(\"/dev/sda\", 10*gb)},\n\n\t\t\texpectedPhase: block.VolumePhaseLocated,\n\t\t\tassertStatus: func(t *testing.T, s block.VolumeStatusSpec) {\n\t\t\t\tassert.Equal(t, \"/dev/sda1\", s.Location)\n\t\t\t\tassert.Equal(t, \"uuid-123\", s.UUID)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"located via Match expression (Disk without parent)\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypeDisk,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tMatch: mkCEL(`volume.name == \"xfs\"`, celenv.VolumeLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdiscoveredVolumes: []*blockpb.DiscoveredVolumeSpec{\n\t\t\t\tmkVol(\"/dev/sdb\", \"\", 5*gb, withName(\"xfs\"), withUUID(\"uuid-disk\")),\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{mkDisk(\"/dev/sdb\", 5*gb)},\n\n\t\t\texpectedPhase: block.VolumePhaseLocated,\n\t\t\tassertStatus: func(t *testing.T, s block.VolumeStatusSpec) {\n\t\t\t\tassert.Equal(t, \"/dev/sdb\", s.Location)\n\t\t\t\tassert.Equal(t, \"\", s.ParentLocation)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"partition with DiskMatch locator fails\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tDiskMatch: mkCEL(`disk.serial == \"SERIAL001\"`, celenv.DiskLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdiscoveredVolumes: []*blockpb.DiscoveredVolumeSpec{\n\t\t\t\tmkVol(\"/dev/sda1\", \"/dev/sda\", 2*gb, withLabel(\"DATA\")),\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{\n\t\t\t\tmkDisk(\"/dev/sda\", 10*gb, withSerial(\"SERIAL001\")),\n\t\t\t},\n\t\t\texpectedError: \"DiskMatch locator is only valid for disk volumes\",\n\t\t},\n\n\t\t// --- Waiting / Missing States ---\n\t\t{\n\t\t\tname: \"volume not located, devices NOT ready -> Waiting\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tMatch: mkCEL(`volume.partition_label == \"MISSING\"`, celenv.VolumeLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdevicesReady:  false,\n\t\t\texpectedPhase: block.VolumePhaseWaiting,\n\t\t},\n\t\t{\n\t\t\tname: \"volume not located, devices ready, NO provisioning spec -> Missing\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tMatch: mkCEL(`volume.partition_label == \"MISSING\"`, celenv.VolumeLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdevicesReady:  true,\n\t\t\texpectedPhase: block.VolumePhaseMissing,\n\t\t},\n\t\t{\n\t\t\tname: \"volume not located, previous wave NOT provisioned -> Waiting\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tMatch: mkCEL(`volume.partition_label == \"MISSING\"`, celenv.VolumeLocator()),\n\t\t\t\t},\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: mkCEL(`!disk.readonly`, celenv.DiskLocator()),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdevicesReady:        true,\n\t\t\tprevWaveProvisioned: false,\n\t\t\texpectedPhase:       block.VolumePhaseWaiting,\n\t\t},\n\n\t\t// --- Provisioning Logic Errors ---\n\t\t{\n\t\t\tname: \"provisioning: no disks matched selector\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType:    block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{Match: mkCEL(`false`, celenv.VolumeLocator())}, // Force miss\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: mkCEL(`disk.serial == \"NONEXISTENT\"`, celenv.DiskLocator()),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdisks:               []volumes.DiskContext{mkDisk(\"/dev/sda\", 10*gb, withSerial(\"ACTUAL\"))},\n\t\t\tdevicesReady:        true,\n\t\t\tprevWaveProvisioned: true,\n\t\t\texpectedError:       \"no disks matched selector for volume\",\n\t\t},\n\t\t{\n\t\t\tname: \"provisioning: match fail due to readonly\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType:    block.VolumeTypePartition,\n\t\t\t\tLocator: block.LocatorSpec{Match: mkCEL(`false`, celenv.VolumeLocator())},\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: mkCEL(`!disk.readonly`, celenv.DiskLocator()),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdisks:               []volumes.DiskContext{mkDisk(\"/dev/sda\", 10*gb, readOnly)},\n\t\t\tdevicesReady:        true,\n\t\t\tprevWaveProvisioned: true,\n\t\t\texpectedError:       \"no disks matched selector for volume\",\n\t\t},\n\t\t{\n\t\t\tname: \"provisioning: multiple disks matched for Disk Volume\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType:    block.VolumeTypeDisk,\n\t\t\t\tLocator: block.LocatorSpec{Match: mkCEL(`false`, celenv.VolumeLocator())},\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: mkCEL(`!disk.readonly`, celenv.DiskLocator()),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{\n\t\t\t\tmkDisk(\"/dev/sda\", 10*gb),\n\t\t\t\tmkDisk(\"/dev/sdb\", 20*gb),\n\t\t\t},\n\t\t\tdevicesReady:        true,\n\t\t\tprevWaveProvisioned: true,\n\t\t\texpectedError:       \"multiple disks matched locator for disk volume\",\n\t\t},\n\t\t{\n\t\t\tname: \"disk volume with DiskMatch locates disk device, not partition\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypeDisk,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tDiskMatch: mkCEL(`disk.serial == \"SN100\"`, celenv.DiskLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdiscoveredVolumes: []*blockpb.DiscoveredVolumeSpec{\n\t\t\t\t// partition entry appears first\n\t\t\t\tmkVol(\"/dev/sda1\", \"/dev/sda\", 1*gb, withLabel(\"EFI\")),\n\t\t\t\t// whole-disk entry appears second\n\t\t\t\tmkVol(\"/dev/sda\", \"\", 10*gb),\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{\n\t\t\t\tmkDisk(\"/dev/sda\", 10*gb, withSerial(\"SN100\")),\n\t\t\t},\n\t\t\texpectedPhase: block.VolumePhaseLocated,\n\t\t\tassertStatus: func(t *testing.T, s block.VolumeStatusSpec) {\n\t\t\t\tassert.Equal(t, \"/dev/sda\", s.Location, \"disk volume should locate the disk device, not a partition\")\n\t\t\t\tassert.Equal(t, \"\", s.ParentLocation, \"disk volume should have no parent location\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"disk volume with DiskMatch errors on multiple disks during locate\",\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypeDisk,\n\t\t\t\tLocator: block.LocatorSpec{\n\t\t\t\t\tDiskMatch: mkCEL(`!disk.readonly`, celenv.DiskLocator()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdiscoveredVolumes: []*blockpb.DiscoveredVolumeSpec{\n\t\t\t\tmkVol(\"/dev/sda\", \"\", 10*gb),\n\t\t\t\tmkVol(\"/dev/sdb1\", \"/dev/sdb\", 4*gb, withLabel(\"DATA\")),\n\t\t\t},\n\t\t\tdisks: []volumes.DiskContext{\n\t\t\t\tmkDisk(\"/dev/sda\", 10*gb, withSerial(\"SN-A\")),\n\t\t\t\tmkDisk(\"/dev/sdb\", 20*gb, withSerial(\"SN-B\")),\n\t\t\t},\n\t\t\texpectedError: \"multiple disks matched locator for disk volume\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tlogger := zaptest.NewLogger(t)\n\n\t\t\t// Setup Config\n\t\t\tvolumeCfg := block.NewVolumeConfig(block.NamespaceName, \"TEST\")\n\t\t\t*volumeCfg.TypedSpec() = test.volumeConfig\n\n\t\t\tstatus := block.VolumeStatusSpec{}\n\n\t\t\t// Build Context\n\t\t\tctx := volumes.ManagerContext{\n\t\t\t\tCfg:                     volumeCfg,\n\t\t\t\tStatus:                  &status,\n\t\t\t\tDiscoveredVolumes:       test.discoveredVolumes,\n\t\t\t\tDisks:                   test.disks,\n\t\t\t\tDevicesReady:            test.devicesReady,\n\t\t\t\tPreviousWaveProvisioned: test.prevWaveProvisioned,\n\t\t\t}\n\n\t\t\t// Execute\n\t\t\terr := volumes.LocateAndProvision(t.Context(), logger, ctx)\n\n\t\t\t// Assertions\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, test.expectedPhase, status.Phase)\n\t\t\t}\n\n\t\t\tif test.assertStatus != nil {\n\t\t\t\ttest.assertStatus(t, status)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/partition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// CreatePartitionResult is the result of creating a partition.\ntype CreatePartitionResult struct {\n\tPartitionIdx int\n\tPartition    gpt.Partition\n\tSize         uint64\n}\n\n// CreatePartition creates a partition on a disk.\n//\n//nolint:gocyclo\nfunc CreatePartition(ctx context.Context, logger *zap.Logger, diskPath string, volumeCfg *block.VolumeConfig, hasPT bool) (CreatePartitionResult, error) {\n\tdev, err := blockdev.NewFromPath(diskPath, blockdev.OpenForWrite())\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, xerrors.NewTaggedf[Retryable](\"error opening disk: %w\", err)\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err = dev.RetryLockWithTimeout(ctx, true, 10*time.Second); err != nil {\n\t\treturn CreatePartitionResult{}, xerrors.NewTaggedf[Retryable](\"error locking disk: %w\", err)\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tgptdev, err := gpt.DeviceFromBlockDevice(dev)\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error getting GPT device: %w\", err)\n\t}\n\n\tvar pt *gpt.Table\n\n\tif hasPT {\n\t\tpt, err = gpt.Read(gptdev)\n\t} else {\n\t\tpt, err = gpt.New(gptdev)\n\t}\n\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error initializing GPT: %w\", err)\n\t}\n\n\tavailable := pt.LargestContiguousAllocatable()\n\n\tsize := volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize\n\n\tmaxSize, err := volumeCfg.TypedSpec().Provisioning.PartitionSpec.ResolveMaxSize(available)\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error resolving max size: %w\", err)\n\t}\n\n\tif available < size {\n\t\t// should never happen\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"not enough space on disk\")\n\t}\n\n\tif maxSize == 0 || maxSize >= available {\n\t\tsize = available\n\t} else {\n\t\tsize = maxSize\n\t}\n\n\ttypeUUID, err := uuid.Parse(volumeCfg.TypedSpec().Provisioning.PartitionSpec.TypeUUID)\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error parsing type UUID: %w\", err)\n\t}\n\n\tpartitionIdx, partitionEntry, err := pt.AllocatePartition(size, volumeCfg.TypedSpec().Provisioning.PartitionSpec.Label, typeUUID)\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error allocating partition: %w\", err)\n\t}\n\n\tif err = pt.Write(); err != nil {\n\t\treturn CreatePartitionResult{}, fmt.Errorf(\"error writing GPT: %w\", err)\n\t}\n\n\t// wipe the newly created partition, as it might contain old data\n\tpartitionDevName := partitioning.DevName(diskPath, uint(partitionIdx))\n\n\tpartitionDev, err := blockdev.NewFromPath(partitionDevName, blockdev.OpenForWrite())\n\tif err != nil {\n\t\treturn CreatePartitionResult{}, xerrors.NewTaggedf[Retryable](\"error opening partition: %w\", err)\n\t}\n\n\tdefer partitionDev.Close() //nolint:errcheck\n\n\tif err = partition.WipeWithSignatures(partitionDev, partitionDevName, logger.Sugar().Debugf); err != nil {\n\t\treturn CreatePartitionResult{}, xerrors.NewTaggedf[Retryable](\"error wiping partition: %w\", err)\n\t}\n\n\tlogger.Info(\"partition created\",\n\t\tzap.String(\"disk\", diskPath), zap.Int(\"partition\", partitionIdx),\n\t\tzap.String(\"label\", volumeCfg.TypedSpec().Provisioning.PartitionSpec.Label),\n\t\tzap.String(\"size\", humanize.IBytes(size)),\n\t)\n\n\treturn CreatePartitionResult{\n\t\tPartitionIdx: partitionIdx,\n\t\tPartition:    partitionEntry,\n\t\tSize:         size,\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/partition_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestCreatePartition(t *testing.T) {\n\tcheckRequirements(t)\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tdiskSetup    func(t *testing.T) string\n\t\tvolumeConfig block.VolumeConfigSpec\n\t\thasPT        bool\n\n\t\texpectedPartitionIdx int\n\t\texpectedSize         uint64\n\t}{\n\t\t{\n\t\t\tname: \"empty disk, fixed partition size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\treturn prepareRawImage(t, 1<<22)\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:  1 << 20,\n\t\t\t\t\t\tMaxSize:  1 << 20,\n\t\t\t\t\t\tLabel:    \"TEST1\",\n\t\t\t\t\t\tTypeUUID: \"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasPT: false,\n\n\t\t\texpectedPartitionIdx: 1,\n\t\t\texpectedSize:         1 << 20,\n\t\t},\n\t\t{\n\t\t\tname: \"empty disk, with max size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\treturn prepareRawImage(t, 1<<22)\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:  1 << 20,\n\t\t\t\t\t\tMaxSize:  1 << 21,\n\t\t\t\t\t\tLabel:    \"TEST2\",\n\t\t\t\t\t\tTypeUUID: \"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasPT: false,\n\n\t\t\texpectedPartitionIdx: 1,\n\t\t\texpectedSize:         1 << 21,\n\t\t},\n\t\t{\n\t\t\tname: \"empty disk, no max size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\treturn prepareRawImage(t, 1<<23)\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:  1 << 20,\n\t\t\t\t\t\tLabel:    \"TEST3\",\n\t\t\t\t\t\tTypeUUID: \"c12a7328-f81f-11d2-ba4b-00a0c93ec93c\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasPT: false,\n\n\t\t\texpectedPartitionIdx: 1,\n\t\t\texpectedSize:         1<<23 - 1<<21, // partition grows to max available size minus GPT overhead/alignment\n\t\t},\n\t\t{\n\t\t\tname: \"empty GPT, fixed partition size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdiskPath := prepareRawImage(t, 1<<22)\n\n\t\t\t\tprepareGPT(t, diskPath)\n\n\t\t\t\treturn diskPath\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:  1 << 20,\n\t\t\t\t\t\tMaxSize:  1 << 20,\n\t\t\t\t\t\tLabel:    \"TEST4\",\n\t\t\t\t\t\tTypeUUID: \"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasPT: true,\n\n\t\t\texpectedPartitionIdx: 1,\n\t\t\texpectedSize:         1 << 20,\n\t\t},\n\t\t{\n\t\t\tname: \"non-empty GPT, with max size\",\n\n\t\t\tdiskSetup: func(t *testing.T) string {\n\t\t\t\tdiskPath := prepareRawImage(t, 1<<23)\n\n\t\t\t\tprepareGPT(t, diskPath,\n\t\t\t\t\tfunc(pt *gpt.Table) {\n\t\t\t\t\t\t_, _, err := pt.AllocatePartition(1<<20, \"FIXED\", uuid.MustParse(\"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\"))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn diskPath\n\t\t\t},\n\t\t\tvolumeConfig: block.VolumeConfigSpec{\n\t\t\t\tType: block.VolumeTypePartition,\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:  1 << 20,\n\t\t\t\t\t\tMaxSize:  1 << 24,\n\t\t\t\t\t\tLabel:    \"TEST4\",\n\t\t\t\t\t\tTypeUUID: \"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\thasPT: true,\n\n\t\t\texpectedPartitionIdx: 2,\n\t\t\texpectedSize:         1<<23 - 3*(1<<20), // partition grows to max available size minus GPT overhead/alignment\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 30*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tdiskPath := test.diskSetup(t)\n\t\t\tlogger := zaptest.NewLogger(t)\n\n\t\t\tvolumeCfg := block.NewVolumeConfig(block.NamespaceName, \"TEST\")\n\t\t\t*volumeCfg.TypedSpec() = test.volumeConfig\n\n\t\t\tvar (\n\t\t\t\tresult volumes.CreatePartitionResult\n\t\t\t\terr    error\n\t\t\t)\n\n\t\t\tfor range 10 {\n\t\t\t\tresult, err = volumes.CreatePartition(ctx, logger, diskPath, volumeCfg, test.hasPT)\n\t\t\t\tif err != nil && xerrors.TagIs[volumes.Retryable](err) {\n\t\t\t\t\t// retry various disk locked and other retryable errors\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expectedPartitionIdx, result.PartitionIdx)\n\t\t\tassert.Equal(t, test.expectedSize, result.Size)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage volumeconfig\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// GetSystemVolumeTransformers returns the transformers for system volumes.\nfunc GetSystemVolumeTransformers(ctx context.Context,\n\tencryptionMeta *runtime.MetaKey,\n\tinContainer, isAgent bool,\n) []volumeConfigTransformer { //nolint:gocyclo\n\tmetaVolumeTransformer := func(_ configconfig.Config) ([]VolumeResource, error) {\n\t\treturn []VolumeResource{\n\t\t\t{\n\t\t\t\tVolumeID: constants.MetaPartitionLabel,\n\t\t\t\tLabel:    block.SystemVolumeLabel,\n\t\t\t\tTransformFunc: NewBuilder().\n\t\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\t\tWithLocator(metaMatch()).\n\t\t\t\t\tWriterFunc(),\n\t\t\t},\n\t\t}, nil\n\t}\n\n\treturn []volumeConfigTransformer{\n\t\tmetaVolumeTransformer,\n\t\tGetStateVolumeTransformer(encryptionMeta, inContainer, isAgent),\n\t\tGetEphemeralVolumeTransformer(inContainer),\n\t\tStandardDirectoryVolumesTransformer,\n\t\tGetOverlayVolumesTransformer(inContainer),\n\t}\n}\n\n// GetStateVolumeTransformer returns the transformer for the STATE volume.\nfunc GetStateVolumeTransformer(encryptionMeta *runtime.MetaKey, inContainer, isAgent bool) volumeConfigTransformer {\n\treturn func(cfg configconfig.Config) ([]VolumeResource, error) {\n\t\tvar volumeConfigurator func(*block.VolumeConfig) error\n\n\t\tif inContainer {\n\t\t\tvolumeConfigurator = NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeDirectory).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:   constants.StateMountPoint,\n\t\t\t\t\tSelinuxLabel: constants.StateSelinuxLabel,\n\t\t\t\t\tFileMode:     0o700,\n\t\t\t\t\tUID:          0,\n\t\t\t\t\tGID:          0,\n\t\t\t\t}).WriterFunc()\n\t\t} else {\n\t\t\t// STATE configuration should be always created, but it depends on the configuration presence\n\t\t\tif cfg != nil && cfg.Machine() != nil {\n\t\t\t\tvolumeConfigurator = manageStateConfigPresent(cfg)\n\t\t\t} else {\n\t\t\t\tvolumeConfigurator = manageStateNoConfig(encryptionMeta, isAgent)\n\t\t\t}\n\t\t}\n\n\t\treturn []VolumeResource{\n\t\t\t{\n\t\t\t\tVolumeID:      constants.StatePartitionLabel,\n\t\t\t\tLabel:         block.SystemVolumeLabel,\n\t\t\t\tTransformFunc: volumeConfigurator,\n\t\t\t},\n\t\t}, nil\n\t}\n}\n\n// GetEphemeralVolumeTransformer returns the transformer for the EPHEMERAL volume.\nfunc GetEphemeralVolumeTransformer(inContainer bool) volumeConfigTransformer {\n\treturn func(cfg configconfig.Config) ([]VolumeResource, error) {\n\t\t// skip if no config\n\t\tif cfg == nil || cfg.Machine() == nil {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tvar volumeConfigurator func(*block.VolumeConfig) error\n\n\t\tif inContainer {\n\t\t\tvolumeConfigurator = NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeDirectory).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:   constants.EphemeralMountPoint,\n\t\t\t\t\tSelinuxLabel: constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:     0o755,\n\t\t\t\t\tUID:          0,\n\t\t\t\t\tGID:          0,\n\t\t\t\t}).WriterFunc()\n\t\t} else {\n\t\t\tvolumeConfigurator = func(vc *block.VolumeConfig) error {\n\t\t\t\textraVolumeConfig, _ := cfg.Volumes().ByName(constants.EphemeralPartitionLabel)\n\n\t\t\t\treturn NewBuilder().\n\t\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\t\tMatch: extraVolumeConfig.Provisioning().DiskSelector().ValueOr(systemDiskMatch()),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\t\tMinSize:         extraVolumeConfig.Provisioning().MinSize().ValueOr(quirks.New(\"\").PartitionSizes().EphemeralMinSize()),\n\t\t\t\t\t\t\tMaxSize:         extraVolumeConfig.Provisioning().MaxSize().ValueOrZero(),\n\t\t\t\t\t\t\tRelativeMaxSize: extraVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),\n\t\t\t\t\t\t\tNegativeMaxSize: extraVolumeConfig.Provisioning().MaxSizeNegative(),\n\t\t\t\t\t\t\tGrow:            extraVolumeConfig.Provisioning().Grow().ValueOr(true),\n\t\t\t\t\t\t\tLabel:           constants.EphemeralPartitionLabel,\n\t\t\t\t\t\t\tTypeUUID:        partition.LinuxFilesystemData,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\t\tType:  block.FilesystemTypeXFS,\n\t\t\t\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\t\t\t},\n\t\t\t\t\t}).\n\t\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\t\tTargetPath:          constants.EphemeralMountPoint,\n\t\t\t\t\t\tSelinuxLabel:        constants.EphemeralSelinuxLabel,\n\t\t\t\t\t\tFileMode:            0o755,\n\t\t\t\t\t\tUID:                 0,\n\t\t\t\t\t\tGID:                 0,\n\t\t\t\t\t\tProjectQuotaSupport: cfg.Machine().Features().DiskQuotaSupportEnabled(),\n\t\t\t\t\t}).\n\t\t\t\t\tWithLocator(labelVolumeMatch(constants.EphemeralPartitionLabel)).\n\t\t\t\t\tWithFunc(func(vcs *block.VolumeConfigSpec) error {\n\t\t\t\t\t\tencryptionConfig := extraVolumeConfig.Encryption()\n\t\t\t\t\t\tif encryptionConfig == nil {\n\t\t\t\t\t\t\t// fall back to v1alpha1 encryption config\n\t\t\t\t\t\t\tencryptionConfig = cfg.Machine().SystemDiskEncryption().Get(constants.EphemeralPartitionLabel)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif err := volumes.ConvertEncryptionConfiguration(\n\t\t\t\t\t\t\tencryptionConfig,\n\t\t\t\t\t\t\tvc.TypedSpec(),\n\t\t\t\t\t\t); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error converting encryption for %s: %w\", constants.EphemeralPartitionLabel, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}).\n\t\t\t\t\tApply(vc.TypedSpec())\n\t\t\t}\n\t\t}\n\n\t\treturn []VolumeResource{{\n\t\t\tVolumeID:      constants.EphemeralPartitionLabel,\n\t\t\tLabel:         block.SystemVolumeLabel,\n\t\t\tTransformFunc: volumeConfigurator,\n\t\t}}, nil\n\t}\n}\n\n// GetOverlayVolumesTransformer returns the transformer for overlay volumes.\nfunc GetOverlayVolumesTransformer(inContainer bool) func(configconfig.Config) ([]VolumeResource, error) {\n\treturn func(cfg configconfig.Config) ([]VolumeResource, error) {\n\t\t// skip if no config or in container\n\t\tif cfg == nil || cfg.Machine() == nil || inContainer {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tvar resources []VolumeResource\n\t\tfor _, overlay := range constants.Overlays {\n\t\t\tresources = append(resources, VolumeResource{\n\t\t\t\tVolumeID: overlay.Path,\n\t\t\t\tLabel:    block.SystemVolumeLabel,\n\t\t\t\tTransformFunc: NewBuilder().\n\t\t\t\t\tWithType(block.VolumeTypeOverlay).\n\t\t\t\t\tWithParentID(constants.EphemeralPartitionLabel).\n\t\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\t\tTargetPath:   overlay.Path,\n\t\t\t\t\t\tSelinuxLabel: overlay.Label,\n\t\t\t\t\t\tFileMode:     0o755,\n\t\t\t\t\t\tUID:          0,\n\t\t\t\t\t\tGID:          0,\n\t\t\t\t\t}).WriterFunc(),\n\t\t\t})\n\t\t}\n\n\t\treturn resources, nil\n\t}\n}\n\nfunc manageStateNoConfig(encryptionMeta *runtime.MetaKey, isAgent bool) func(vc *block.VolumeConfig) error {\n\tmatch := labelVolumeMatchAndNonEmpty(constants.StatePartitionLabel)\n\tif isAgent { // mark as missing\n\t\tmatch = noMatch\n\t}\n\n\treturn NewBuilder().\n\t\tWithType(block.VolumeTypePartition).\n\t\tWithMount(block.MountSpec{\n\t\t\tTargetPath:   constants.StateMountPoint,\n\t\t\tSelinuxLabel: constants.StateSelinuxLabel,\n\t\t\tFileMode:     0o700,\n\t\t\tUID:          0,\n\t\t\tGID:          0,\n\t\t}).WithLocator(match).\n\t\tWithFunc(func(spec *block.VolumeConfigSpec) error {\n\t\t\tif encryptionMeta != nil {\n\t\t\t\tencryptionFromMeta, err := volumes.UnmarshalEncryptionMeta([]byte(encryptionMeta.TypedSpec().Value))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif err := volumes.ConvertEncryptionConfiguration(\n\t\t\t\t\tencryptionFromMeta,\n\t\t\t\t\tspec,\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error converting encryption for %s: %w\", constants.StatePartitionLabel, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tspec.Encryption = block.EncryptionSpec{}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}).\n\t\tWriterFunc()\n}\n\nfunc manageStateConfigPresent(cfg configconfig.Config) func(vc *block.VolumeConfig) error {\n\treturn func(vc *block.VolumeConfig) error {\n\t\textraVolumeConfig, _ := cfg.Volumes().ByName(constants.StatePartitionLabel)\n\n\t\tencryptionConfig := extraVolumeConfig.Encryption()\n\t\tif encryptionConfig == nil {\n\t\t\t// fall back to v1alpha1 encryption config\n\t\t\tencryptionConfig = cfg.Machine().SystemDiskEncryption().Get(constants.StatePartitionLabel)\n\t\t}\n\n\t\treturn NewBuilder().\n\t\t\tWithType(block.VolumeTypePartition).\n\t\t\tWithMount(block.MountSpec{\n\t\t\t\tTargetPath:   constants.StateMountPoint,\n\t\t\t\tSelinuxLabel: constants.StateSelinuxLabel,\n\t\t\t\tFileMode:     0o700,\n\t\t\t\tUID:          0,\n\t\t\t\tGID:          0,\n\t\t\t}).\n\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\tMatch: systemDiskMatch(),\n\t\t\t\t},\n\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\tMinSize:  quirks.New(\"\").PartitionSizes().StateSize(),\n\t\t\t\t\tMaxSize:  quirks.New(\"\").PartitionSizes().StateSize(),\n\t\t\t\t\tLabel:    constants.StatePartitionLabel,\n\t\t\t\t\tTypeUUID: partition.LinuxFilesystemData,\n\t\t\t\t},\n\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\tType:  block.FilesystemTypeXFS,\n\t\t\t\t\tLabel: constants.StatePartitionLabel,\n\t\t\t\t},\n\t\t\t}).\n\t\t\tWithLocator(labelVolumeMatch(constants.StatePartitionLabel)).\n\t\t\tWithConvertEncryptionConfiguration(encryptionConfig).\n\t\t\tApply(vc.TypedSpec())\n\t}\n}\n\nvar standardVolumeDefinitions = []struct {\n\tID           string\n\tPath         string\n\tMode         os.FileMode\n\tUID          int\n\tGID          int\n\tRecursive    bool\n\tSELinuxLabel string\n}{\n\t// /var/log\n\t{\n\t\tPath:         \"/var/log\",\n\t\tMode:         0o755,\n\t\tSELinuxLabel: \"system_u:object_r:var_log_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/log/audit\",\n\t\tMode:         0o700,\n\t\tSELinuxLabel: \"system_u:object_r:audit_log_t:s0\",\n\t},\n\t{\n\t\tPath:         constants.KubernetesAuditLogDir,\n\t\tMode:         0o700,\n\t\tUID:          constants.KubernetesAPIServerRunUser,\n\t\tGID:          constants.KubernetesAPIServerRunGroup,\n\t\tRecursive:    true,\n\t\tSELinuxLabel: \"system_u:object_r:kube_log_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/log/containers\",\n\t\tMode:         0o755,\n\t\tSELinuxLabel: \"system_u:object_r:containers_log_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/log/pods\",\n\t\tMode:         0o755,\n\t\tSELinuxLabel: \"system_u:object_r:pods_log_t:s0\",\n\t},\n\t// /var/lib\n\t{\n\t\tPath:         \"/var/lib\",\n\t\tMode:         0o700,\n\t\tSELinuxLabel: constants.EphemeralSelinuxLabel,\n\t},\n\t{\n\t\tID:           constants.EtcdDataVolumeID,\n\t\tPath:         constants.EtcdDataPath,\n\t\tSELinuxLabel: constants.EtcdDataSELinuxLabel,\n\t\tMode:         0o700,\n\t\tUID:          constants.EtcdUserID,\n\t\tGID:          constants.EtcdUserID,\n\t\tRecursive:    true,\n\t},\n\t{\n\t\tPath:         \"/var/lib/containerd\",\n\t\tMode:         0o000,\n\t\tSELinuxLabel: \"system_u:object_r:containerd_state_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/lib/kubelet\",\n\t\tMode:         0o700,\n\t\tSELinuxLabel: \"system_u:object_r:kubelet_state_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/lib/cni\",\n\t\tMode:         0o700,\n\t\tRecursive:    true,\n\t\tSELinuxLabel: \"system_u:object_r:cni_state_t:s0\",\n\t},\n\t{\n\t\tPath:         \"/var/lib/kubelet/seccomp\",\n\t\tMode:         0o700,\n\t\tSELinuxLabel: \"system_u:object_r:seccomp_profile_t:s0\",\n\t},\n\t{\n\t\tPath:         constants.SeccompProfilesDirectory,\n\t\tMode:         0o700,\n\t\tRecursive:    true,\n\t\tSELinuxLabel: \"system_u:object_r:seccomp_profile_t:s0\",\n\t},\n\t// /var/mnt\n\t{\n\t\tPath:         constants.UserVolumeMountPoint,\n\t\tMode:         0o755,\n\t\tSELinuxLabel: constants.EphemeralSelinuxLabel,\n\t},\n\t// /var/run\n\t{\n\t\tPath:         \"/var/run/lock\",\n\t\tMode:         0o755,\n\t\tSELinuxLabel: \"system_u:object_r:var_lock_t:s0\",\n\t},\n}\n\n// StandardDirectoryVolumesTransformer is the transformer for standard directory volumes,\n// including the /var/run symlink.\nfunc StandardDirectoryVolumesTransformer(cfg configconfig.Config) ([]VolumeResource, error) {\n\t// skip if no config\n\tif cfg == nil || cfg.Machine() == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := []VolumeResource{\n\t\t// /var/run symlink\n\t\t{\n\t\t\tVolumeID: \"/var/run\",\n\t\t\tLabel:    block.SystemVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeSymlink).\n\t\t\t\tWithSymlink(block.SymlinkProvisioningSpec{\n\t\t\t\t\tSymlinkTargetPath: \"/run\",\n\t\t\t\t\tForce:             true,\n\t\t\t\t}).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath: \"/var/run\",\n\t\t\t\t}).\n\t\t\t\tWriterFunc(),\n\t\t},\n\t}\n\n\tparentIDs := map[string]string{\n\t\t\"/var\":     constants.EphemeralPartitionLabel,\n\t\t\"/var/run\": \"/var/run\",\n\t}\n\n\tfor _, volume := range standardVolumeDefinitions {\n\t\tparentDir := filepath.Dir(volume.Path)\n\t\ttargetDir := filepath.Base(volume.Path)\n\n\t\tparentID, ok := parentIDs[parentDir]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unknown parent directory volume %q for %q\", parentDir, volume.Path)\n\t\t}\n\n\t\tvolumeID := volume.Path\n\t\tif volume.ID != \"\" {\n\t\t\tvolumeID = volume.ID\n\t\t}\n\n\t\tresources = append(resources, VolumeResource{\n\t\t\tVolumeID: volumeID,\n\t\t\tLabel:    block.SystemVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeDirectory).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:       targetDir,\n\t\t\t\t\tParentID:         parentID,\n\t\t\t\t\tSelinuxLabel:     volume.SELinuxLabel,\n\t\t\t\t\tFileMode:         volume.Mode,\n\t\t\t\t\tUID:              volume.UID,\n\t\t\t\t\tGID:              volume.GID,\n\t\t\t\t\tRecursiveRelabel: volume.Recursive,\n\t\t\t\t}).WriterFunc(),\n\t\t})\n\n\t\tparentIDs[volume.Path] = volumeID\n\t}\n\n\treturn resources, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/system_volumes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig_test\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nvar baseCfg v1alpha1.Config\n\nfunc init() {\n\tu, _ := url.Parse(\"https://foo:6443\") //nolint:errcheck\n\n\tbaseCfg = v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{URL: u},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc TestGetSystemVolumeTransformers(t *testing.T) {\n\tt.Parallel()\n\n\tctx := context.Background()\n\tencryptionMeta := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.StateEncryptionConfig))\n\n\ttransformers := volumeconfig.GetSystemVolumeTransformers(ctx, encryptionMeta, false, false)\n\trequire.Len(t, transformers, 5, \"should return 5 transformers\")\n\n\tvar allResources []volumeconfig.VolumeResource //nolint:prealloc // this is a test\n\n\tfor _, transformer := range transformers {\n\t\tresources, err := transformer(container.NewV1Alpha1(&baseCfg))\n\t\trequire.NoError(t, err)\n\n\t\tallResources = append(allResources, resources...)\n\t}\n\n\tfor _, volumeID := range []string{\n\t\tconstants.MetaPartitionLabel,\n\t\tconstants.StatePartitionLabel,\n\t\tconstants.EphemeralPartitionLabel,\n\t\t\"/var/run\",\n\t\t\"/var/log\",\n\t\t\"/etc/cni\",\n\t} {\n\t\tassert.Condition(t, func() bool {\n\t\t\tfor _, r := range allResources {\n\t\t\t\tif r.VolumeID == volumeID {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t}, \"should have volume config resource for %s\", volumeID)\n\t}\n}\n\nfunc TestGetStateVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname string\n\n\t\tencryptionMeta *runtime.MetaKey\n\t\tinContainer    bool\n\t\tisAgent        bool\n\t\tcfg            *v1alpha1.Config\n\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname:           \"in container\",\n\t\t\tinContainer:    true,\n\t\t\tisAgent:        false,\n\t\t\tencryptionMeta: nil,\n\t\t\tcfg:            &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, constants.StateMountPoint, vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:           \"W/ config\",\n\t\t\tinContainer:    false,\n\t\t\tisAgent:        false,\n\t\t\tencryptionMeta: nil,\n\t\t\tcfg:            &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) { //nolint:dupl\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, constants.StateMountPoint, vc.TypedSpec().Mount.TargetPath)\n\n\t\t\t\t\tassert.NotEmpty(t, vc.TypedSpec().Provisioning)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:           \"NO config\",\n\t\t\tinContainer:    false,\n\t\t\tisAgent:        false,\n\t\t\tencryptionMeta: nil,\n\t\t\tcfg:            nil,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, constants.StateMountPoint, vc.TypedSpec().Mount.TargetPath)\n\n\t\t\t\t\tlocator, err := vc.TypedSpec().Locator.Match.MarshalText()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, `volume.partition_label == \"STATE\" && volume.name != \"\"`, string(locator))\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:           \"agent w/ NO config = no match locator\",\n\t\t\tinContainer:    false,\n\t\t\tisAgent:        true,\n\t\t\tencryptionMeta: nil,\n\t\t\tcfg:            nil,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tlocator, err := vc.TypedSpec().Locator.Match.MarshalText()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, \"false\", string(locator))\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttransformer := volumeconfig.GetStateVolumeTransformer(tc.encryptionMeta, tc.inContainer, tc.isAgent)\n\t\t\tresources, err := transformer(container.NewV1Alpha1(tc.cfg))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, constants.StatePartitionLabel, resources[0].VolumeID)\n\t\t\tassert.Equal(t, block.SystemVolumeLabel, resources[0].Label)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\nfunc TestGetEphemeralVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname string\n\n\t\tinContainer bool\n\t\tcfg         *v1alpha1.Config\n\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname:        \"NO config\",\n\t\t\tinContainer: false,\n\t\t\tcfg:         nil,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"container W/ config\",\n\t\t\tinContainer: true,\n\t\t\tcfg:         &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) { //nolint:dupl\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, constants.EphemeralMountPoint, vc.TypedSpec().Mount.TargetPath)\n\n\t\t\t\t\tassert.Empty(t, vc.TypedSpec().Provisioning)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"W/ config\",\n\t\t\tinContainer: false,\n\t\t\tcfg:         &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, constants.EphemeralPartitionLabel, resources[0].VolumeID)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, constants.EphemeralMountPoint, vc.TypedSpec().Mount.TargetPath)\n\n\t\t\t\t\tassert.NotEmpty(t, vc.TypedSpec().Provisioning)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttransformer := volumeconfig.GetEphemeralVolumeTransformer(tc.inContainer)\n\t\t\tresources, err := transformer(container.NewV1Alpha1(tc.cfg))\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\nfunc TestStandardDirectoryVolumesTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname string\n\n\t\tcfg *v1alpha1.Config\n\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname: \"NO config\",\n\t\t\tcfg:  nil,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"W/ config\",\n\t\t\tcfg:  &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1+14) // +1 for /var/run symlink, +14 for standard directories\n\n\t\t\t\tvar varRunSymlinkResource *volumeconfig.VolumeResource\n\n\t\t\t\tfor i := range resources {\n\t\t\t\t\tif resources[i].VolumeID == \"/var/run\" {\n\t\t\t\t\t\tvarRunSymlinkResource = &resources[i]\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trequire.NotNil(t, varRunSymlinkResource, \"should have /var/run symlink resource\")\n\t\t\t\tassert.Equal(t, block.SystemVolumeLabel, varRunSymlinkResource.Label)\n\t\t\t\ttestTransformFunc(t, varRunSymlinkResource.TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeSymlink, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, \"/run\", vc.TypedSpec().Symlink.SymlinkTargetPath)\n\t\t\t\t})\n\n\t\t\t\t// Check some standard directories\n\t\t\t\texpectedPaths := []string{\"/var/log\", \"/var/lib\", constants.EtcdDataVolumeID}\n\t\t\t\tfor _, expectedPath := range expectedPaths {\n\t\t\t\t\tvar found bool\n\n\t\t\t\t\tfor i := range resources {\n\t\t\t\t\t\tif resources[i].VolumeID == expectedPath {\n\t\t\t\t\t\t\tfound = true\n\n\t\t\t\t\t\t\tassert.Equal(t, block.SystemVolumeLabel, resources[i].Label)\n\t\t\t\t\t\t\ttestTransformFunc(t, resources[i].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\t\tassert.Equal(t, block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\t\t\t\t\t\t\t})\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tassert.True(t, found, \"should have resource for %s\", expectedPath)\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tresources, err := volumeconfig.StandardDirectoryVolumesTransformer(container.NewV1Alpha1(tc.cfg))\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\nfunc TestGetOverlayVolumesTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname string\n\n\t\tinContainer bool\n\t\tcfg         *v1alpha1.Config\n\t\tcheckFunc   func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname:        \"NO config\",\n\t\t\tinContainer: false,\n\t\t\tcfg:         nil,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"in container\",\n\t\t\tinContainer: true,\n\t\t\tcfg:         &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"W/ config\",\n\t\t\tinContainer: false,\n\t\t\tcfg:         &baseCfg,\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, len(constants.Overlays))\n\n\t\t\t\tfor _, resource := range resources {\n\t\t\t\t\tassert.Equal(t, block.SystemVolumeLabel, resource.Label)\n\n\t\t\t\t\ttestTransformFunc(t, resource.TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\tassert.Equal(t, block.VolumeTypeOverlay, vc.TypedSpec().Type)\n\t\t\t\t\t\tassert.Equal(t, constants.EphemeralPartitionLabel, vc.TypedSpec().ParentID)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tresources, err := volumeconfig.GetOverlayVolumesTransformer(tc.inContainer)(container.NewV1Alpha1(tc.cfg))\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\nfunc TestStateVolumeTransformerWithEncryptionMeta(t *testing.T) {\n\tt.Parallel()\n\n\t// Create encryption meta\n\tencryptionConfig := &v1alpha1.EncryptionConfig{\n\t\tEncryptionProvider: \"luks2\",\n\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 1,\n\t\t\t\tKeyStatic: &v1alpha1.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"test-secret\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tencryptionMetaMarshalled, err := json.Marshal(encryptionConfig)\n\trequire.NoError(t, err)\n\n\tencryptionMeta := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.StateEncryptionConfig))\n\tencryptionMeta.TypedSpec().Value = string(encryptionMetaMarshalled)\n\n\ttransformer := volumeconfig.GetStateVolumeTransformer(encryptionMeta, false, false)\n\n\tresources, err := transformer(nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, resources, 1)\n\n\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\trequire.NoError(t, err)\n\n\t\t// Encryption should be set from meta\n\t\tassert.NotEmpty(t, vc.TypedSpec().Encryption)\n\t})\n}\n\nfunc TestEphemeralVolumeTransformerWithExtraConfig(t *testing.T) {\n\tt.Parallel()\n\n\tephemeralConfig := blockcfg.NewVolumeConfigV1Alpha1()\n\tephemeralConfig.MetaName = constants.EphemeralPartitionLabel\n\tephemeralConfig.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"10GiB\")\n\tephemeralConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"100GiB\")\n\n\tcfg, err := container.New(\n\t\tbaseCfg.DeepCopy(),\n\t\tephemeralConfig,\n\t)\n\trequire.NoError(t, err)\n\n\ttransformer := volumeconfig.GetEphemeralVolumeTransformer(false)\n\tresources, err := transformer(cfg)\n\trequire.NoError(t, err)\n\n\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\trequire.NoError(t, err)\n\n\t\trequire.Len(t, resources, 1)\n\n\t\tassert.EqualValues(t, 10*1024*1024*1024, vc.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\tassert.EqualValues(t, 100*1024*1024*1024, vc.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t})\n}\n\nfunc testTransformFunc(t *testing.T,\n\ttransformer func(vc *block.VolumeConfig) error,\n\tcheckFunc func(t *testing.T, vc *block.VolumeConfig, err error),\n) {\n\tt.Helper()\n\n\tvc := block.NewVolumeConfig(block.NamespaceName, \"test\")\n\terr := transformer(vc)\n\n\tcheckFunc(t, vc, err)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/types.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig\n\nimport (\n\t\"fmt\"\n\n\tmachinedruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumeResource is an internal type containing the information required by\n// VolumeConfigController to create a VolumeConfig (and optionally\n// VolumeMountRequest) resource.\n//\n// Transformers (System and User) transform the config into VolumeResources, which are\n// later created by VolumeConfigController.\ntype VolumeResource struct {\n\tVolumeID           string                                  // ID of the volume to create.\n\tLabel              string                                  // label of the volume to create.\n\tTransformFunc      func(vc *block.VolumeConfig) error      // func that applies the changes to the provided VolumeConfig.\n\tMountTransformFunc func(m *block.VolumeMountRequest) error // func that applies the changes to the provided VolumeMountRequest.\n}\n\ntype volumeConfigTransformer func(c configconfig.Config) ([]VolumeResource, error)\n\n// SkipUserVolumeMountRequest is used to skip creating a VolumeMountRequest for a user volume.\ntype SkipUserVolumeMountRequest struct{}\n\nvar noMatch = cel.MustExpression(cel.ParseBooleanExpression(\"false\", celenv.Empty()))\n\nfunc labelVolumeMatch(label string) cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"volume.partition_label == '%s'\", label), celenv.VolumeLocator()))\n}\n\nfunc labelVolumeMatchAndNonEmpty(label string) cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"volume.partition_label == '%s' && volume.name != ''\", label), celenv.VolumeLocator()))\n}\n\nfunc metaMatch() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"volume.partition_label == '%s' && volume.name in ['', 'talosmeta'] && volume.size == 1048576u\", constants.MetaPartitionLabel), celenv.VolumeLocator())) //nolint:lll\n}\n\nfunc systemDiskMatch() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(\"system_disk\", celenv.DiskLocator()))\n}\n\n// MetaProvider wraps acquiring meta.\ntype MetaProvider interface {\n\tMeta() machinedruntime.Meta\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig\n\nimport (\n\t\"cmp\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Size constants.\nconst (\n\tMiB               = 1024 * 1024\n\tMinUserVolumeSize = 100 * MiB\n)\n\n// UserVolumeTransformers contains all the user volume config transformers.\nvar UserVolumeTransformers = []volumeConfigTransformer{\n\tUserVolumeTransformer,\n\tRawVolumeTransformer,\n\tExistingVolumeTransformer,\n\tExternalVolumeTransformer,\n\tSwapVolumeTransformer,\n}\n\n// UserVolumeTransformer is the transformer for user volume configs.\nfunc UserVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {\n\tif c == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := make([]VolumeResource, 0, len(c.UserVolumeConfigs()))\n\n\tfor _, userVolumeConfig := range c.UserVolumeConfigs() {\n\t\tvolumeID := constants.UserVolumePrefix + userVolumeConfig.Name()\n\t\tuserVolumeResource := VolumeResource{\n\t\t\tVolumeID:           volumeID,\n\t\t\tLabel:              block.UserVolumeLabel,\n\t\t\tMountTransformFunc: HandleUserVolumeMountRequest(userVolumeConfig), // This is overridden for Directory type below.\n\t\t}\n\n\t\tswitch userVolumeConfig.Type().ValueOr(block.VolumeTypePartition) {\n\t\tcase block.VolumeTypeDirectory:\n\t\t\tuserVolumeResource.MountTransformFunc = DefaultMountTransform\n\t\t\tuserVolumeResource.TransformFunc = NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeDirectory).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:   userVolumeConfig.Name(),\n\t\t\t\t\tParentID:     constants.UserVolumeMountPoint,\n\t\t\t\t\tSelinuxLabel: constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:     0o755,\n\t\t\t\t\tUID:          0,\n\t\t\t\t\tGID:          0,\n\t\t\t\t\tBindTarget:   new(userVolumeConfig.Name()),\n\t\t\t\t}).\n\t\t\t\tWriterFunc()\n\n\t\tcase block.VolumeTypeDisk:\n\t\t\tuserVolumeResource.TransformFunc = NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeDisk).\n\t\t\t\tWithDiskLocator(userVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch)).\n\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: userVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),\n\t\t\t\t\t},\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tTypeUUID: partition.LinuxFilesystemData,\n\t\t\t\t\t},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: userVolumeConfig.Filesystem().Type(),\n\t\t\t\t\t},\n\t\t\t\t}).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:          userVolumeConfig.Name(),\n\t\t\t\t\tParentID:            constants.UserVolumeMountPoint,\n\t\t\t\t\tSelinuxLabel:        constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:            0o755,\n\t\t\t\t\tUID:                 0,\n\t\t\t\t\tGID:                 0,\n\t\t\t\t\tProjectQuotaSupport: userVolumeConfig.Filesystem().ProjectQuotaSupport(),\n\t\t\t\t}).\n\t\t\t\tWithConvertEncryptionConfiguration(userVolumeConfig.Encryption()).\n\t\t\t\tWriterFunc()\n\n\t\tcase block.VolumeTypePartition:\n\t\t\tuserVolumeResource.TransformFunc = NewBuilder().\n\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\tWithLocator(labelVolumeMatch(volumeID)).\n\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: userVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),\n\t\t\t\t\t},\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:         cmp.Or(userVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),\n\t\t\t\t\t\tMaxSize:         userVolumeConfig.Provisioning().MaxSize().ValueOrZero(),\n\t\t\t\t\t\tRelativeMaxSize: userVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),\n\t\t\t\t\t\tNegativeMaxSize: userVolumeConfig.Provisioning().MaxSizeNegative(),\n\t\t\t\t\t\tGrow:            userVolumeConfig.Provisioning().Grow().ValueOrZero(),\n\t\t\t\t\t\tLabel:           volumeID,\n\t\t\t\t\t\tTypeUUID:        partition.LinuxFilesystemData,\n\t\t\t\t\t},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: userVolumeConfig.Filesystem().Type(),\n\t\t\t\t\t},\n\t\t\t\t}).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:          userVolumeConfig.Name(),\n\t\t\t\t\tParentID:            constants.UserVolumeMountPoint,\n\t\t\t\t\tSelinuxLabel:        constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:            0o755,\n\t\t\t\t\tUID:                 0,\n\t\t\t\t\tGID:                 0,\n\t\t\t\t\tProjectQuotaSupport: userVolumeConfig.Filesystem().ProjectQuotaSupport(),\n\t\t\t\t}).\n\t\t\t\tWithConvertEncryptionConfiguration(userVolumeConfig.Encryption()).\n\t\t\t\tWriterFunc()\n\n\t\tcase block.VolumeTypeTmpfs, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal:\n\t\t\tfallthrough\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unsupported volume type %q\", userVolumeConfig.Type().ValueOr(block.VolumeTypePartition).String())\n\t\t}\n\n\t\tresources = append(resources, userVolumeResource)\n\t}\n\n\treturn resources, nil\n}\n\n// RawVolumeTransformer is the transformer for raw volume configs.\nfunc RawVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {\n\tif c == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := make([]VolumeResource, 0, len(c.RawVolumeConfigs()))\n\n\tfor _, rawVolumeConfig := range c.RawVolumeConfigs() {\n\t\tvolumeID := constants.RawVolumePrefix + rawVolumeConfig.Name()\n\t\tresources = append(resources, VolumeResource{\n\t\t\tVolumeID: volumeID,\n\t\t\tLabel:    block.RawVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\tWithLocator(labelVolumeMatch(volumeID)).\n\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: rawVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),\n\t\t\t\t\t},\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:         cmp.Or(rawVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),\n\t\t\t\t\t\tMaxSize:         rawVolumeConfig.Provisioning().MaxSize().ValueOrZero(),\n\t\t\t\t\t\tRelativeMaxSize: rawVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),\n\t\t\t\t\t\tGrow:            rawVolumeConfig.Provisioning().Grow().ValueOrZero(),\n\t\t\t\t\t\tLabel:           volumeID,\n\t\t\t\t\t\tTypeUUID:        partition.LinuxFilesystemData,\n\t\t\t\t\t},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: block.FilesystemTypeNone,\n\t\t\t\t\t},\n\t\t\t\t}).\n\t\t\t\tWithConvertEncryptionConfiguration(rawVolumeConfig.Encryption()).\n\t\t\t\tWriterFunc(),\n\t\t\tMountTransformFunc: SkipMountTransform,\n\t\t})\n\t}\n\n\treturn resources, nil\n}\n\n// ExistingVolumeTransformer is the transformer for existing user volume configs.\nfunc ExistingVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {\n\tif c == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := make([]VolumeResource, 0, len(c.ExistingVolumeConfigs()))\n\n\tfor _, existingVolumeConfig := range c.ExistingVolumeConfigs() {\n\t\tvolumeID := constants.ExistingVolumePrefix + existingVolumeConfig.Name()\n\n\t\tresources = append(resources, VolumeResource{\n\t\t\tVolumeID: volumeID,\n\t\t\tLabel:    block.ExistingVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\tWithLocator(existingVolumeConfig.VolumeDiscovery().VolumeSelector()).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:   existingVolumeConfig.Name(),\n\t\t\t\t\tParentID:     constants.UserVolumeMountPoint,\n\t\t\t\t\tSelinuxLabel: constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:     0o755,\n\t\t\t\t\tUID:          0,\n\t\t\t\t\tGID:          0,\n\t\t\t\t}).\n\t\t\t\tWriterFunc(),\n\t\t\tMountTransformFunc: HandleExistingVolumeMountRequest(existingVolumeConfig),\n\t\t})\n\t}\n\n\treturn resources, nil\n}\n\n// ExternalVolumeTransformer is the transformer for external user volume configs.\nfunc ExternalVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {\n\tif c == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := make([]VolumeResource, 0, len(c.ExternalVolumeConfigs()))\n\n\tfor _, externalVolumeConfig := range c.ExternalVolumeConfigs() {\n\t\tvolumeID := constants.ExternalVolumePrefix + externalVolumeConfig.Name()\n\n\t\tparams, err := externalVolumeParameters(externalVolumeConfig)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get external volume parameters for volume %q: %w\", externalVolumeConfig.Name(), err)\n\t\t}\n\n\t\tresources = append(resources, VolumeResource{\n\t\t\tVolumeID: volumeID,\n\t\t\tLabel:    block.ExternalVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypeExternal).\n\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tExternal: externalVolumeSource(externalVolumeConfig),\n\t\t\t\t\t},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: externalVolumeConfig.Type(),\n\t\t\t\t\t},\n\t\t\t\t}).\n\t\t\t\tWithMount(block.MountSpec{\n\t\t\t\t\tTargetPath:   externalVolumeConfig.Name(),\n\t\t\t\t\tParentID:     constants.UserVolumeMountPoint,\n\t\t\t\t\tSelinuxLabel: constants.EphemeralSelinuxLabel,\n\t\t\t\t\tFileMode:     0o755,\n\t\t\t\t\tUID:          0,\n\t\t\t\t\tGID:          0,\n\t\t\t\t\tParameters:   params,\n\t\t\t\t}).\n\t\t\t\tWriterFunc(),\n\t\t\tMountTransformFunc: HandleExternalVolumeMountRequest(externalVolumeConfig),\n\t\t})\n\t}\n\n\treturn resources, nil\n}\n\nfunc externalVolumeSource(ext configconfig.ExternalVolumeConfig) string {\n\tswitch ext.Type() {\n\tcase block.FilesystemTypeVirtiofs:\n\t\tif ext.Mount().Virtiofs().IsPresent() {\n\t\t\treturn ext.Mount().Virtiofs().ValueOrZero().Source()\n\t\t}\n\n\tcase block.FilesystemTypeNone, block.FilesystemTypeXFS, block.FilesystemTypeVFAT, block.FilesystemTypeEXT4, block.FilesystemTypeISO9660, block.FilesystemTypeSwap:\n\t\tfallthrough\n\n\tdefault:\n\t\treturn \"\"\n\t}\n\n\treturn \"\"\n}\n\nfunc externalVolumeParameters(ext configconfig.ExternalVolumeConfig) ([]block.ParameterSpec, error) {\n\tswitch ext.Type() {\n\tcase block.FilesystemTypeVirtiofs:\n\t\tif ext.Mount().Virtiofs().IsPresent() {\n\t\t\treturn ext.Mount().Virtiofs().ValueOrZero().Parameters()\n\t\t}\n\n\t\treturn nil, errors.New(\"virtiofs mount specification is required for Virtiofs external volume\")\n\n\tcase block.FilesystemTypeNone, block.FilesystemTypeXFS, block.FilesystemTypeVFAT, block.FilesystemTypeEXT4, block.FilesystemTypeISO9660, block.FilesystemTypeSwap:\n\t\tfallthrough\n\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported external volume type %q\", ext.Type().String())\n\t}\n}\n\n// SwapVolumeTransformer is the transformer for swap volume configs.\nfunc SwapVolumeTransformer(c configconfig.Config) ([]VolumeResource, error) {\n\tif c == nil {\n\t\treturn nil, nil\n\t}\n\n\tresources := make([]VolumeResource, 0, len(c.SwapVolumeConfigs()))\n\n\tfor _, swapVolumeConfig := range c.SwapVolumeConfigs() {\n\t\tvolumeID := constants.SwapVolumePrefix + swapVolumeConfig.Name()\n\t\tresources = append(resources, VolumeResource{\n\t\t\tVolumeID: volumeID,\n\t\t\tLabel:    block.SwapVolumeLabel,\n\t\t\tTransformFunc: NewBuilder().\n\t\t\t\tWithType(block.VolumeTypePartition).\n\t\t\t\tWithLocator(labelVolumeMatch(volumeID)).\n\t\t\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\t\tMatch: swapVolumeConfig.Provisioning().DiskSelector().ValueOr(noMatch),\n\t\t\t\t\t},\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tMinSize:         cmp.Or(swapVolumeConfig.Provisioning().MinSize().ValueOrZero(), MinUserVolumeSize),\n\t\t\t\t\t\tMaxSize:         swapVolumeConfig.Provisioning().MaxSize().ValueOrZero(),\n\t\t\t\t\t\tRelativeMaxSize: swapVolumeConfig.Provisioning().RelativeMaxSize().ValueOrZero(),\n\t\t\t\t\t\tNegativeMaxSize: swapVolumeConfig.Provisioning().MaxSizeNegative(),\n\t\t\t\t\t\tGrow:            swapVolumeConfig.Provisioning().Grow().ValueOrZero(),\n\t\t\t\t\t\tLabel:           volumeID,\n\t\t\t\t\t\tTypeUUID:        partition.LinkSwap,\n\t\t\t\t\t},\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: block.FilesystemTypeSwap,\n\t\t\t\t\t},\n\t\t\t\t}).\n\t\t\t\tWithConvertEncryptionConfiguration(swapVolumeConfig.Encryption()).\n\t\t\t\tWriterFunc(),\n\t\t\tMountTransformFunc: DefaultMountTransform,\n\t\t})\n\t}\n\n\treturn resources, nil\n}\n\n// HandleUserVolumeMountRequest returns a MountTransformFunc for user volumes.\nfunc HandleUserVolumeMountRequest(userVolumeConfig configconfig.UserVolumeConfig) func(m *block.VolumeMountRequest) error {\n\treturn func(m *block.VolumeMountRequest) error {\n\t\tm.TypedSpec().DisableAccessTime = userVolumeConfig.Mount().DisableAccessTime()\n\t\tm.TypedSpec().Secure = userVolumeConfig.Mount().Secure()\n\n\t\treturn nil\n\t}\n}\n\n// HandleExistingVolumeMountRequest returns a MountTransformFunc for existing volumes.\n// It sets `VolumeMountRequestSpec.ReadOnly` based on the existing configuration.\nfunc HandleExistingVolumeMountRequest(existingVolumeConfig configconfig.ExistingVolumeConfig) func(m *block.VolumeMountRequest) error {\n\treturn func(m *block.VolumeMountRequest) error {\n\t\tm.TypedSpec().ReadOnly = existingVolumeConfig.Mount().ReadOnly()\n\t\tm.TypedSpec().DisableAccessTime = existingVolumeConfig.Mount().DisableAccessTime()\n\t\tm.TypedSpec().Secure = existingVolumeConfig.Mount().Secure()\n\n\t\treturn nil\n\t}\n}\n\n// HandleExternalVolumeMountRequest returns a MountTransformFunc for external volumes.\nfunc HandleExternalVolumeMountRequest(externalVolumeConfig configconfig.ExternalVolumeConfig) func(m *block.VolumeMountRequest) error {\n\treturn func(m *block.VolumeMountRequest) error {\n\t\tm.TypedSpec().ReadOnly = externalVolumeConfig.Mount().ReadOnly()\n\t\tm.TypedSpec().DisableAccessTime = externalVolumeConfig.Mount().DisableAccessTime()\n\t\tm.TypedSpec().Secure = externalVolumeConfig.Mount().Secure()\n\n\t\treturn nil\n\t}\n}\n\n// DefaultMountTransform is a no-op.\nfunc DefaultMountTransform(_ *block.VolumeMountRequest) error {\n\treturn nil\n}\n\n// SkipMountTransform is a MountTransformFunc which skips creating a MountRequest.\n// It returns a tagged error, which is handled by the VolumeConfigController.\nfunc SkipMountTransform(_ *block.VolumeMountRequest) error {\n\treturn xerrors.NewTaggedf[SkipUserVolumeMountRequest](\"skip\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/user_volumes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig_test\n\nimport (\n\t\"io/fs\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n//nolint:dupl\nfunc TestUserVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname      string\n\t\tcfg       []*blockcfg.UserVolumeConfigV1Alpha1\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource, err error)\n\t}{\n\t\t{\n\t\t\tname: \"no config\",\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource, err error) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"partition volume\",\n\t\t\tcfg: []*blockcfg.UserVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.UserVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName:   \"foo\",\n\t\t\t\t\tVolumeType: new(block.VolumeTypePartition),\n\t\t\t\t\tFilesystemSpec: blockcfg.FilesystemSpec{\n\t\t\t\t\t\tFilesystemType: block.FilesystemTypeXFS,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource, err error) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, constants.UserVolumePrefix+\"foo\", resources[0].VolumeID)\n\t\t\t\tassert.Equal(t, block.UserVolumeLabel, resources[0].Label)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, block.FilesystemTypeXFS, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\n\t\t\t\t\tassert.Equal(t, \"foo\", vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t\tassert.Equal(t, constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\t\t\t\t\tassert.Equal(t, fs.FileMode(0o755), vc.TypedSpec().Mount.FileMode)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\t// default mount transform is noop\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"directory volume\",\n\t\t\tcfg: []*blockcfg.UserVolumeConfigV1Alpha1{{\n\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\tMetaKind:       blockcfg.UserVolumeConfigKind,\n\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t},\n\t\t\t\tMetaName:   \"bar\",\n\t\t\t\tVolumeType: new(block.VolumeTypeDirectory),\n\t\t\t\tFilesystemSpec: blockcfg.FilesystemSpec{\n\t\t\t\t\tFilesystemType: block.FilesystemTypeXFS,\n\t\t\t\t},\n\t\t\t}},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource, err error) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, constants.UserVolumePrefix+\"bar\", resources[0].VolumeID)\n\t\t\t\tassert.Equal(t, block.UserVolumeLabel, resources[0].Label)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\n\t\t\t\t\trequire.Empty(t, vc.TypedSpec().Provisioning)\n\n\t\t\t\t\tassert.Equal(t, \"bar\", vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t\tassert.Equal(t, constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\t\t\t\t\tassert.Equal(t, new(\"bar\"), vc.TypedSpec().Mount.BindTarget)\n\t\t\t\t\tassert.Equal(t, fs.FileMode(0o755), vc.TypedSpec().Mount.FileMode)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\t// default mount transform is noop\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported volume type\",\n\t\t\tcfg: []*blockcfg.UserVolumeConfigV1Alpha1{{\n\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\tMetaKind:       blockcfg.UserVolumeConfigKind,\n\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t},\n\t\t\t\tVolumeType: new(block.VolumeTypeTmpfs),\n\t\t\t}},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource, err error) {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Equal(t, \"unsupported volume type \\\"tmpfs\\\"\", err.Error())\n\n\t\t\t\trequire.Empty(t, resources)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple configs\",\n\t\t\tcfg: []*blockcfg.UserVolumeConfigV1Alpha1{{\n\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\tMetaKind:       blockcfg.UserVolumeConfigKind,\n\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t},\n\t\t\t\tMetaName:   \"foo\",\n\t\t\t\tVolumeType: new(block.VolumeTypePartition),\n\t\t\t\tFilesystemSpec: blockcfg.FilesystemSpec{\n\t\t\t\t\tFilesystemType: block.FilesystemTypeXFS,\n\t\t\t\t},\n\t\t\t}, {\n\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\tMetaKind:       blockcfg.UserVolumeConfigKind,\n\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t},\n\t\t\t\tMetaName:   \"bar\",\n\t\t\t\tVolumeType: new(block.VolumeTypeDirectory),\n\t\t\t\tFilesystemSpec: blockcfg.FilesystemSpec{\n\t\t\t\t\tFilesystemType: block.FilesystemTypeXFS,\n\t\t\t\t},\n\t\t\t}},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource, err error) {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, resources, 2)\n\n\t\t\t\tassert.Equal(t, constants.UserVolumePrefix+\"foo\", resources[0].VolumeID)\n\t\t\t\tassert.Equal(t, block.UserVolumeLabel, resources[0].Label)\n\n\t\t\t\tassert.Equal(t, constants.UserVolumePrefix+\"bar\", resources[1].VolumeID)\n\t\t\t\tassert.Equal(t, block.UserVolumeLabel, resources[1].Label)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\t\t\t\tassert.Equal(t, block.FilesystemTypeXFS, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t\t\t\t})\n\n\t\t\t\ttestTransformFunc(t, resources[1].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmergedCfg, err := container.New(xslices.Map(tc.cfg,\n\t\t\t\tfunc(cfg *blockcfg.UserVolumeConfigV1Alpha1) configconfig.Document {\n\t\t\t\t\treturn cfg\n\t\t\t\t})...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresources, err := volumeconfig.UserVolumeTransformer(mergedCfg)\n\n\t\t\ttc.checkFunc(t, resources, err)\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc TestRawVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tvolumeCfg := &blockcfg.RawVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       blockcfg.RawVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: \"raw-data\",\n\t}\n\n\tcfg, err := container.New(volumeCfg)\n\trequire.NoError(t, err)\n\n\tresources, err := volumeconfig.RawVolumeTransformer(cfg)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, block.RawVolumeLabel, resources[0].Label)\n\trequire.Len(t, resources, 1)\n\n\tassert.Equal(t, constants.RawVolumePrefix+\"raw-data\", resources[0].VolumeID)\n\tassert.Equal(t, block.RawVolumeLabel, resources[0].Label)\n\n\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\tassert.Equal(t, block.WaveUserVolumes, vc.TypedSpec().Provisioning.Wave)\n\t\tassert.Equal(t, block.FilesystemTypeNone, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t\tassert.Equal(t, constants.RawVolumePrefix+\"raw-data\", vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\t\tassert.Equal(t, partition.LinuxFilesystemData, vc.TypedSpec().Provisioning.PartitionSpec.TypeUUID)\n\t\tassert.Equal(t, block.FilesystemTypeNone, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t})\n\n\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t// SkipMountTransform should return an error tagged with SkipUserVolumeMountRequest\n\t\trequire.Error(t, err)\n\t\tassert.Equal(t, \"skip\", err.Error())\n\t})\n}\n\n//nolint:dupl\nfunc TestExistingVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname      string\n\t\tcfg       []*blockcfg.ExistingVolumeConfigV1Alpha1\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname: \"no config\",\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing volume RW\",\n\t\t\tcfg: []*blockcfg.ExistingVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.ExistingVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName: \"existing-data\",\n\t\t\t\t\tVolumeDiscoverySpec: blockcfg.VolumeDiscoverySpec{\n\t\t\t\t\t\tVolumeSelectorConfig: blockcfg.VolumeSelector{\n\t\t\t\t\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`volume.partition_label == \"MY-DATA\"`, celenv.VolumeLocator())),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMountSpec: blockcfg.ExistingMountSpec{\n\t\t\t\t\t\tMountReadOnly: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, block.ExistingVolumeLabel, resources[0].Label)\n\t\t\t\tassert.Equal(t, constants.ExistingVolumePrefix+\"existing-data\", resources[0].VolumeID)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, \"existing-data\", vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t\tassert.Equal(t, constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\t\t\t\t\tassert.Equal(t, fs.FileMode(0o755), vc.TypedSpec().Mount.FileMode)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.False(t, m.TypedSpec().ReadOnly, \"expected read-write mount\")\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing volume RO\",\n\t\t\tcfg: []*blockcfg.ExistingVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.ExistingVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName: \"readonly-data\",\n\t\t\t\t\tVolumeDiscoverySpec: blockcfg.VolumeDiscoverySpec{\n\t\t\t\t\t\tVolumeSelectorConfig: blockcfg.VolumeSelector{\n\t\t\t\t\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`volume.partition_label == \"READONLY-DATA\"`, celenv.VolumeLocator())),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMountSpec: blockcfg.ExistingMountSpec{\n\t\t\t\t\t\tMountReadOnly: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.True(t, m.TypedSpec().ReadOnly, \"expected read-only mount\")\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmergedCfg, err := container.New(xslices.Map(tc.cfg,\n\t\t\t\tfunc(cfg *blockcfg.ExistingVolumeConfigV1Alpha1) configconfig.Document {\n\t\t\t\t\treturn cfg\n\t\t\t\t})...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresources, err := volumeconfig.ExistingVolumeTransformer(mergedCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc TestExternalVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname      string\n\t\tcfg       []*blockcfg.ExternalVolumeConfigV1Alpha1\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname: \"no config\",\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"external volume RW\",\n\t\t\tcfg: []*blockcfg.ExternalVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.ExternalVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName:       \"external-data\",\n\t\t\t\t\tFilesystemType: block.FilesystemTypeVirtiofs,\n\t\t\t\t\tMountSpec: blockcfg.ExternalMountSpec{\n\t\t\t\t\t\tMountReadOnly: new(false),\n\t\t\t\t\t\tMountVirtiofs: &blockcfg.VirtiofsMountSpec{\n\t\t\t\t\t\t\tVirtiofsTag: \"data\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, block.ExternalVolumeLabel, resources[0].Label)\n\t\t\t\tassert.Equal(t, constants.ExternalVolumePrefix+\"external-data\", resources[0].VolumeID)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeExternal, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, \"external-data\", vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t\tassert.Equal(t, constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\t\t\t\t\tassert.Equal(t, fs.FileMode(0o755), vc.TypedSpec().Mount.FileMode)\n\t\t\t\t\tassert.Equal(t, \"data\", vc.TypedSpec().Provisioning.DiskSelector.External)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.False(t, m.TypedSpec().ReadOnly, \"expected read-write mount\")\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"external volume RW\",\n\t\t\tcfg: []*blockcfg.ExternalVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.ExternalVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName:       \"external-data\",\n\t\t\t\t\tFilesystemType: block.FilesystemTypeVirtiofs,\n\t\t\t\t\tMountSpec: blockcfg.ExternalMountSpec{\n\t\t\t\t\t\tMountReadOnly: new(true),\n\t\t\t\t\t\tMountVirtiofs: &blockcfg.VirtiofsMountSpec{\n\t\t\t\t\t\t\tVirtiofsTag: \"data\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, block.ExternalVolumeLabel, resources[0].Label)\n\t\t\t\tassert.Equal(t, constants.ExternalVolumePrefix+\"external-data\", resources[0].VolumeID)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypeExternal, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, \"external-data\", vc.TypedSpec().Mount.TargetPath)\n\t\t\t\t\tassert.Equal(t, constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\t\t\t\t\tassert.Equal(t, fs.FileMode(0o755), vc.TypedSpec().Mount.FileMode)\n\t\t\t\t\tassert.Equal(t, \"data\", vc.TypedSpec().Provisioning.DiskSelector.External)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.True(t, m.TypedSpec().ReadOnly, \"expected read-write mount\")\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmergedCfg, err := container.New(xslices.Map(tc.cfg,\n\t\t\t\tfunc(cfg *blockcfg.ExternalVolumeConfigV1Alpha1) configconfig.Document {\n\t\t\t\t\treturn cfg\n\t\t\t\t})...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresources, err := volumeconfig.ExternalVolumeTransformer(mergedCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc TestSwapVolumeTransformer(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname      string\n\t\tcfg       []*blockcfg.SwapVolumeConfigV1Alpha1\n\t\tcheckFunc func(t *testing.T, resources []volumeconfig.VolumeResource)\n\t}{\n\t\t{\n\t\t\tname: \"no config\",\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"swap volume\",\n\t\t\tcfg: []*blockcfg.SwapVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.SwapVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName: \"swap1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, constants.SwapVolumePrefix+\"swap1\", resources[0].VolumeID)\n\t\t\t\tassert.Equal(t, block.SwapVolumeLabel, resources[0].Label)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, block.FilesystemTypeSwap, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t\t\t\t\tassert.Equal(t, constants.SwapVolumePrefix+\"swap1\", vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\t\t\t\t\tassert.Equal(t, block.WaveUserVolumes, vc.TypedSpec().Provisioning.Wave)\n\n\t\t\t\t\tassert.EqualValues(t, volumeconfig.MinUserVolumeSize, vc.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\t\t\t\tassert.EqualValues(t, 0, vc.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\t// default mount transform is noop\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"swap volume with sizes\",\n\t\t\tcfg: []*blockcfg.SwapVolumeConfigV1Alpha1{\n\t\t\t\t{\n\t\t\t\t\tMeta: meta.Meta{\n\t\t\t\t\t\tMetaKind:       blockcfg.SwapVolumeConfigKind,\n\t\t\t\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\t\t\t},\n\t\t\t\t\tMetaName: \"swap1\",\n\t\t\t\t\tProvisioningSpec: blockcfg.ProvisioningSpec{\n\t\t\t\t\t\tProvisioningMinSize: blockcfg.MustByteSize(\"1GB\"),\n\t\t\t\t\t\tProvisioningMaxSize: blockcfg.MustSize(\"2GB\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheckFunc: func(t *testing.T, resources []volumeconfig.VolumeResource) {\n\t\t\t\trequire.Len(t, resources, 1)\n\n\t\t\t\tassert.Equal(t, constants.SwapVolumePrefix+\"swap1\", resources[0].VolumeID)\n\t\t\t\tassert.Equal(t, block.SwapVolumeLabel, resources[0].Label)\n\n\t\t\t\ttestTransformFunc(t, resources[0].TransformFunc, func(t *testing.T, vc *block.VolumeConfig, err error) {\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\t\t\t\tassert.Equal(t, block.FilesystemTypeSwap, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t\t\t\t\tassert.Equal(t, constants.SwapVolumePrefix+\"swap1\", vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\t\t\t\t\tassert.Equal(t, block.WaveUserVolumes, vc.TypedSpec().Provisioning.Wave)\n\n\t\t\t\t\tassert.EqualValues(t, 1*1000*1000*1000, vc.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\t\t\t\tassert.EqualValues(t, 2*1000*1000*1000, vc.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t\t\t\t})\n\n\t\t\t\ttestMountTransformFunc(t, resources[0].MountTransformFunc, func(t *testing.T, m *block.VolumeMountRequest, err error) {\n\t\t\t\t\t// default mount transform is noop\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmergedCfg, err := container.New(xslices.Map(tc.cfg,\n\t\t\t\tfunc(cfg *blockcfg.SwapVolumeConfigV1Alpha1) configconfig.Document {\n\t\t\t\t\treturn cfg\n\t\t\t\t})...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresources, err := volumeconfig.SwapVolumeTransformer(mergedCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttc.checkFunc(t, resources)\n\t\t})\n\t}\n}\n\nfunc testMountTransformFunc(t *testing.T,\n\ttransformer func(*block.VolumeMountRequest) error,\n\tcheckFunc func(t *testing.T, m *block.VolumeMountRequest, err error),\n) {\n\tt.Helper()\n\n\tm := block.NewVolumeMountRequest(block.NamespaceName, \"test\")\n\terr := transformer(m)\n\n\tcheckFunc(t, m, err)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/volume_config_builder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig\n\nimport (\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Builder is a small utility to build spec-modifying functions\n// that can be applied (inside `safe.WriterModify`) to a VolumeConfigSpec.\n//\n// The builder is just a wrapper around a slice `func(*VolumeConfigSpec) error`, and the\n// `.WithXXX` methods only append to the slice. No modifications are made to the spec until\n// `Apply()` is called, or the function returned by `WriterFunc()` is called.\n//\n// Errors that occur during application are collected into a multierror and returned\n// by `Apply`/`WriterFunc`.\ntype Builder struct {\n\topts []func(*block.VolumeConfigSpec) error\n}\n\n// NewBuilder creates a new VolumeConfigBuilder.\nfunc NewBuilder() *Builder {\n\treturn &Builder{\n\t\topts: nil,\n\t}\n}\n\n// WithType sets VolumeConfigSpec.Type.\nfunc (b *Builder) WithType(volumeType block.VolumeType) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Type = volumeType\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithLocator sets VolumeConfigSpec.Locator.Match.\nfunc (b *Builder) WithLocator(match cel.Expression) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Locator = block.LocatorSpec{Match: match}\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithDiskLocator sets VolumeConfigSpec.Locator.DiskMatch.\nfunc (b *Builder) WithDiskLocator(diskMatch cel.Expression) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Locator = block.LocatorSpec{DiskMatch: diskMatch}\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithProvisioning sets VolumeConfigSpec.Provisioning.\nfunc (b *Builder) WithProvisioning(provisioning block.ProvisioningSpec) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Provisioning = provisioning\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithMount sets VolumeConfigSpec.Mount.\nfunc (b *Builder) WithMount(mount block.MountSpec) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Mount = mount\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithSymlink sets VolumeConfigSpec.Symlink.\nfunc (b *Builder) WithSymlink(symlink block.SymlinkProvisioningSpec) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Symlink = symlink\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithParentID sets VolumeConfigSpec.ParentID.\nfunc (b *Builder) WithParentID(parentID string) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.ParentID = parentID\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithEncryption sets VolumeConfigSpec.Encryption.\nfunc (b *Builder) WithEncryption(encryption block.EncryptionSpec) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\tspec.Encryption = encryption\n\n\t\treturn nil\n\t})\n\n\treturn b\n}\n\n// WithConvertEncryptionConfiguration sets VolumeConfigSpec.Encryption, converting the provided\n// encryption config.\nfunc (b *Builder) WithConvertEncryptionConfiguration(encryption configconfig.EncryptionConfig) *Builder {\n\tb.opts = append(b.opts, func(spec *block.VolumeConfigSpec) error {\n\t\treturn volumes.ConvertEncryptionConfiguration(encryption, spec)\n\t})\n\n\treturn b\n}\n\n// WithFunc adds an arbitraty spec-modifying `func(*block.VolumeConfigSpec) error` to the builder.\n// Errors returned by the function are collected and returned by Apply/WriterFunc.\nfunc (b *Builder) WithFunc(fn func(*block.VolumeConfigSpec) error) *Builder {\n\tb.opts = append(b.opts, fn)\n\n\treturn b\n}\n\n// Apply applies all the changes to the provided VolumeConfigSpec.\n// Returns a multierror containing all errors that occurred during application.\nfunc (b *Builder) Apply(spec *block.VolumeConfigSpec) error {\n\tvar errors *multierror.Error\n\n\tfor _, opt := range b.opts {\n\t\tif err := opt(spec); err != nil {\n\t\t\terrors = multierror.Append(errors, err)\n\t\t}\n\t}\n\n\treturn errors.ErrorOrNil()\n}\n\n// WriterFunc returns a function that applies all the changes to the provided VolumeConfig.\n// The function returned is suitable for use in `safe.WriterModify`, and returns a multierror\n// containing all errors that occurred during application.\nfunc (b *Builder) WriterFunc() func(*block.VolumeConfig) error {\n\treturn func(vc *block.VolumeConfig) error {\n\t\treturn b.Apply(vc.TypedSpec())\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig/volume_config_builder_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumeconfig_test\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestNewVolumeConfigBuilder(t *testing.T) {\n\tt.Parallel()\n\n\tbuilder := volumeconfig.NewBuilder()\n\trequire.NotNil(t, builder)\n\n\tspec := &block.VolumeConfigSpec{}\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n}\n\nfunc TestVolumeConfigBuilder_EmptyBuilder(t *testing.T) {\n\tt.Parallel()\n\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder()\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\t// spec should remain empty/default\n\tassert.Equal(t, block.VolumeType(0), spec.Type)\n\tassert.Empty(t, spec.ParentID)\n\tassert.Empty(t, spec.Mount)\n\tassert.Empty(t, spec.Provisioning)\n}\n\nfunc TestVolumeConfigBuilder_WithType(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname       string\n\t\tvolumeType block.VolumeType\n\t}{\n\t\t{\n\t\t\tname:       \"partition\",\n\t\t\tvolumeType: block.VolumeTypePartition,\n\t\t},\n\t\t{\n\t\t\tname:       \"directory\",\n\t\t\tvolumeType: block.VolumeTypeDirectory,\n\t\t},\n\t\t{\n\t\t\tname:       \"overlay\",\n\t\t\tvolumeType: block.VolumeTypeOverlay,\n\t\t},\n\t\t{\n\t\t\tname:       \"symlink\",\n\t\t\tvolumeType: block.VolumeTypeSymlink,\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tspec := &block.VolumeConfigSpec{}\n\t\t\tbuilder := volumeconfig.NewBuilder().WithType(tc.volumeType)\n\n\t\t\terr := builder.Apply(spec)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tc.volumeType, spec.Type)\n\t\t})\n\t}\n}\n\nfunc TestVolumeConfigBuilder_WithLocator(t *testing.T) {\n\tt.Parallel()\n\n\tmatch := cel.MustExpression(cel.ParseBooleanExpression(`volume.partition_label == \"TEST\"`, celenv.VolumeLocator()))\n\tspec := &block.VolumeConfigSpec{}\n\n\tbuilder := volumeconfig.NewBuilder().WithLocator(match)\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, match, spec.Locator.Match)\n}\n\nfunc TestVolumeConfigBuilder_WithProvisioning(t *testing.T) {\n\tt.Parallel()\n\n\tprovisioning := block.ProvisioningSpec{\n\t\tWave: block.WaveUserVolumes,\n\t\tDiskSelector: block.DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`system_disk`, celenv.DiskLocator())),\n\t\t},\n\t\tPartitionSpec: block.PartitionSpec{\n\t\t\tMinSize:  100 * 1024 * 1024,\n\t\t\tMaxSize:  200 * 1024 * 1024,\n\t\t\tGrow:     true,\n\t\t\tLabel:    \"test-label\",\n\t\t\tTypeUUID: partition.LinuxFilesystemData,\n\t\t},\n\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\tType: block.FilesystemTypeXFS,\n\t\t},\n\t}\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().WithProvisioning(provisioning)\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, provisioning, spec.Provisioning)\n}\n\nfunc TestVolumeConfigBuilder_WithMount(t *testing.T) {\n\tt.Parallel()\n\n\tmount := block.MountSpec{\n\t\tTargetPath:   \"/test/path\",\n\t\tParentID:     \"parent-id\",\n\t\tSelinuxLabel: \"test_label\",\n\t\tFileMode:     0o755,\n\t\tUID:          1000,\n\t\tGID:          2000,\n\t}\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().WithMount(mount)\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, mount, spec.Mount)\n}\n\nfunc TestVolumeConfigBuilder_WithEncryption(t *testing.T) {\n\tt.Parallel()\n\n\tencryption := block.EncryptionSpec{\n\t\tProvider: block.EncryptionProviderLUKS2,\n\t\tKeys: []block.EncryptionKey{\n\t\t\t{\n\t\t\t\tSlot: 0,\n\t\t\t\tType: block.EncryptionKeyTPM,\n\t\t\t},\n\t\t},\n\t}\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().WithEncryption(encryption)\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, encryption, spec.Encryption)\n}\n\nfunc TestVolumeConfigBuilder_WithSymlink(t *testing.T) {\n\tt.Parallel()\n\n\tsymlink := block.SymlinkProvisioningSpec{\n\t\tSymlinkTargetPath: \"/target/path\",\n\t\tForce:             true,\n\t}\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().WithSymlink(symlink)\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, symlink, spec.Symlink)\n}\n\nfunc TestVolumeConfigBuilder_WithParentID(t *testing.T) {\n\tt.Parallel()\n\n\tparentID := \"parent-volume-id\"\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().WithParentID(parentID)\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, parentID, spec.ParentID)\n}\n\nfunc TestVolumeConfigBuilder_WithFunc(t *testing.T) {\n\tt.Parallel()\n\n\tcustomValue := \"custom-value\"\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\ts.ParentID = customValue\n\n\t\t\treturn nil\n\t\t})\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, customValue, spec.ParentID)\n}\n\nfunc TestVolumeConfigBuilder_WithFunc_Error(t *testing.T) {\n\tt.Parallel()\n\n\ttestErr := errors.New(\"test error\")\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\treturn testErr\n\t\t})\n\n\terr := builder.Apply(spec)\n\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"test error\")\n}\n\nfunc TestVolumeConfigBuilder_WithFunc_MultipleErrors(t *testing.T) {\n\tt.Parallel()\n\n\terr1 := errors.New(\"error 1\")\n\terr2 := errors.New(\"error 2\")\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\treturn err1\n\t\t}).\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\treturn err2\n\t\t})\n\n\terr := builder.Apply(spec)\n\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"error 1\")\n\tassert.Contains(t, err.Error(), \"error 2\")\n}\n\nfunc TestVolumeConfigBuilder_Chaining(t *testing.T) {\n\tt.Parallel()\n\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithType(block.VolumeTypePartition).\n\t\tWithParentID(\"parent-id\").\n\t\tWithMount(block.MountSpec{\n\t\t\tTargetPath: \"/test/path\",\n\t\t\tFileMode:   0o755,\n\t\t}).\n\t\tWithProvisioning(block.ProvisioningSpec{\n\t\t\tWave: block.WaveUserVolumes,\n\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\tLabel: \"test-label\",\n\t\t\t},\n\t\t})\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, block.VolumeTypePartition, spec.Type)\n\tassert.Equal(t, \"parent-id\", spec.ParentID)\n\tassert.Equal(t, \"/test/path\", spec.Mount.TargetPath)\n\tassert.Equal(t, fs.FileMode(0o755), spec.Mount.FileMode)\n\tassert.Equal(t, block.WaveUserVolumes, spec.Provisioning.Wave)\n\tassert.Equal(t, \"test-label\", spec.Provisioning.PartitionSpec.Label)\n}\n\nfunc TestVolumeConfigBuilder_Chaining_Overwrite(t *testing.T) {\n\tt.Parallel()\n\n\tspec := &block.VolumeConfigSpec{}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithType(block.VolumeTypePartition).\n\t\tWithType(block.VolumeTypeDirectory).\n\t\tWithParentID(\"parent-1\").\n\t\tWithParentID(\"parent-2\")\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\t// Last call should win\n\tassert.Equal(t, block.VolumeTypeDirectory, spec.Type)\n\tassert.Equal(t, \"parent-2\", spec.ParentID)\n}\n\nfunc TestVolumeConfigBuilder_WriterFunc(t *testing.T) {\n\tt.Parallel()\n\n\tvc := block.NewVolumeConfig(block.NamespaceName, \"test\")\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithType(block.VolumeTypePartition).\n\t\tWithParentID(\"parent-id\")\n\n\twriterFunc := builder.WriterFunc()\n\trequire.NotNil(t, writerFunc)\n\n\terr := writerFunc(vc)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, block.VolumeTypePartition, vc.TypedSpec().Type)\n\tassert.Equal(t, \"parent-id\", vc.TypedSpec().ParentID)\n}\n\nfunc TestVolumeConfigBuilder_MultipleWithFunc(t *testing.T) {\n\tt.Parallel()\n\n\tspec := &block.VolumeConfigSpec{}\n\tcounter := 0\n\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\tcounter++\n\t\t\ts.ParentID = \"func1\"\n\n\t\t\treturn nil\n\t\t}).\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\tcounter++\n\t\t\ts.ParentID = \"func2\"\n\n\t\t\treturn nil\n\t\t}).\n\t\tWithFunc(func(s *block.VolumeConfigSpec) error {\n\t\t\tcounter++\n\n\t\t\treturn nil\n\t\t})\n\n\terr := builder.Apply(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 3, counter)\n\tassert.Equal(t, \"func2\", spec.ParentID)\n}\n\nfunc TestVolumeConfigBuilder_WithConvertEncryptionConfiguration_Nil(t *testing.T) {\n\tt.Parallel()\n\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithConvertEncryptionConfiguration(nil)\n\n\tvc := block.NewVolumeConfig(block.NamespaceName, \"test\")\n\terr := builder.Apply(vc.TypedSpec())\n\trequire.NoError(t, err)\n\n\tassert.Empty(t, vc.TypedSpec().Encryption)\n}\n\nfunc TestVolumeConfigBuilder_WithConvertEncryptionConfiguration_WithConfig(t *testing.T) {\n\tt.Parallel()\n\n\tencryptionConfig := blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &blockcfg.EncryptionKeyTPM{},\n\t\t\t},\n\t\t},\n\t}\n\tbuilder := volumeconfig.NewBuilder().\n\t\tWithConvertEncryptionConfiguration(encryptionConfig)\n\n\tvc := block.NewVolumeConfig(block.NamespaceName, \"test\")\n\terr := builder.Apply(vc.TypedSpec())\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, block.EncryptionProviderLUKS2, vc.TypedSpec().Encryption.Provider)\n\tassert.Len(t, vc.TypedSpec().Encryption.Keys, 1)\n\tassert.Equal(t, 0, vc.TypedSpec().Encryption.Keys[0].Slot)\n\tassert.Equal(t, block.EncryptionKeyTPM, vc.TypedSpec().Encryption.Keys[0].Type)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package volumes provides utilities and extra functions for the volume manager.\npackage volumes\n\nimport (\n\t\"cmp\"\n\t\"math\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption\"\n\tblockpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// CompareVolumeConfigs compares two volume configs in the proposed order of provisioning.\nfunc CompareVolumeConfigs(a, b *block.VolumeConfig) int {\n\t// first, sort volumes without provisioning instructions first, as they don't block provisioning of other volumes\n\tif c := cmpBool(!value.IsZero(a.TypedSpec().Provisioning), !value.IsZero(b.TypedSpec().Provisioning)); c != 0 {\n\t\treturn c\n\t}\n\n\t// second, sort by wave, smaller wave first\n\tif c := cmp.Compare(a.TypedSpec().Provisioning.Wave, b.TypedSpec().Provisioning.Wave); c != 0 {\n\t\treturn c\n\t}\n\n\t// prefer partitions which do not grow, as growing partitions may consume space needed by other partitions\n\tif c := cmpBool(a.TypedSpec().Provisioning.PartitionSpec.Grow, b.TypedSpec().Provisioning.PartitionSpec.Grow); c != 0 {\n\t\treturn c\n\t}\n\n\t// prefer partitions with smaller sizes first\n\t// e.g.: for a disk of size 1GiB, and following config with min-max requested sizes:\n\t// 1. 100MiB - 200MiB\n\t// 2. 300MiB - 2GiB\n\t//\n\t// if the order is 2-1, the second partition will grow to full disk size and will leave no space for the first partition,\n\t// but if the order is 1-2, partition sizes will 200MiB and 800MiB respectively.\n\t//\n\t// we compare only max size, as it affects the resulting size of the partition\n\tdesiredSizeA := cmp.Or(a.TypedSpec().Provisioning.PartitionSpec.MaxSize, math.MaxUint64)\n\tdesiredSizeB := cmp.Or(b.TypedSpec().Provisioning.PartitionSpec.MaxSize, math.MaxUint64)\n\n\treturn cmp.Compare(desiredSizeA, desiredSizeB)\n}\n\nfunc cmpBool(a, b bool) int {\n\tif a == b {\n\t\treturn 0\n\t}\n\n\tif a {\n\t\treturn 1\n\t}\n\n\treturn -1\n}\n\n// Retryable is an error tag.\ntype Retryable struct{}\n\n// DiskContext captures the context of a disk.\ntype DiskContext struct {\n\tDisk       *blockpb.DiskSpec\n\tSystemDisk optional.Optional[bool]\n}\n\n// ToCELContext converts the disk context to CEL contexts.\nfunc (d *DiskContext) ToCELContext() map[string]any {\n\tresult := map[string]any{\n\t\t\"disk\": d.Disk,\n\t}\n\n\tif val, ok := d.SystemDisk.Get(); ok {\n\t\tresult[\"system_disk\"] = val\n\t}\n\n\treturn result\n}\n\n// ManagerContext captures the context of the volume manager.\ntype ManagerContext struct {\n\tCfg               *block.VolumeConfig\n\tStatus            *block.VolumeStatusSpec\n\tParentStatus      *block.VolumeStatus\n\tParentFinalizer   string\n\tDiscoveredVolumes []*blockpb.DiscoveredVolumeSpec\n\tDisks             []DiskContext\n\n\tDevicesReady            bool\n\tPreviousWaveProvisioned bool\n\tEncryptionHelpers       encryption.Helpers\n\tShouldCloseVolume       bool\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/internal/volumes/volumes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage volumes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestCompareVolumeConfigs(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\ta *block.VolumeConfigSpec\n\t\tb *block.VolumeConfigSpec\n\n\t\texpected int\n\t}{\n\t\t{\n\t\t\tname: \"no provisioning instructions\",\n\n\t\t\ta: &block.VolumeConfigSpec{},\n\t\t\tb: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: -1,\n\t\t},\n\t\t{\n\t\t\tname: \"different wave\",\n\n\t\t\ta: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t},\n\t\t\t},\n\t\t\tb: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveUserVolumes,\n\t\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\t\tType: block.FilesystemTypeEXT4,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: -1,\n\t\t},\n\t\t{\n\t\t\tname: \"prefer grow\",\n\n\t\t\ta: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tb: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow: false,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname: \"prefer smaller size\",\n\n\t\t\ta: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow:    false,\n\t\t\t\t\t\tMinSize: 100,\n\t\t\t\t\t\tMaxSize: 200,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tb: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow:    false,\n\t\t\t\t\t\tMinSize: 150,\n\t\t\t\t\t\tMaxSize: 1000,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: -1,\n\t\t},\n\t\t{\n\t\t\tname: \"prefer max size\",\n\n\t\t\ta: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow:    false,\n\t\t\t\t\t\tMinSize: 100,\n\t\t\t\t\t\tMaxSize: 200,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tb: &block.VolumeConfigSpec{\n\t\t\t\tProvisioning: block.ProvisioningSpec{\n\t\t\t\t\tWave: block.WaveSystemDisk,\n\t\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\t\tGrow:    false,\n\t\t\t\t\t\tMinSize: 50,\n\t\t\t\t\t\tMaxSize: 0, // no limit\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: -1,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tresA := block.NewVolumeConfig(block.NamespaceName, \"A\")\n\t\t\t*resA.TypedSpec() = *test.a\n\n\t\t\tresB := block.NewVolumeConfig(block.NamespaceName, \"B\")\n\t\t\t*resB.TypedSpec() = *test.b\n\n\t\t\tactual := volumes.CompareVolumeConfigs(resA, resB)\n\n\t\t\tassert.Equal(t, test.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/lvm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// LVMActivationController activates LVM volumes when they are discovered by the block.DiscoveryController.\ntype LVMActivationController struct {\n\tV1Alpha1Mode machineruntime.Mode\n\n\tseenVolumes  map[string]struct{}\n\tactivatedVGs map[string]struct{}\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LVMActivationController) Name() string {\n\treturn \"block.LVMActivationController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LVMActivationController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiscoveredVolumeType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tID:        optional.Some(constants.MetaPartitionLabel),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"udevd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LVMActivationController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LVMActivationController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.seenVolumes == nil {\n\t\tctrl.seenVolumes = map[string]struct{}{}\n\t}\n\n\tif ctrl.activatedVGs == nil {\n\t\tctrl.activatedVGs = map[string]struct{}{}\n\t}\n\n\tif ctrl.V1Alpha1Mode.IsAgent() {\n\t\t// in agent mode, we don't want to activate LVMs\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tudevdService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"udevd\")\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get udevd service: %w\", err)\n\t\t}\n\n\t\tif udevdService == nil {\n\t\t\tlogger.Debug(\"udevd service not registered yet\")\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !udevdService.TypedSpec().Running || !udevdService.TypedSpec().Healthy {\n\t\t\tlogger.Debug(\"waiting for udevd service to be running and healthy\")\n\n\t\t\tcontinue\n\t\t}\n\n\t\tmeta, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, constants.MetaPartitionLabel)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get meta partition info: %w\", err)\n\t\t}\n\n\t\tif meta == nil {\n\t\t\tlogger.Debug(\"meta partition not registered yet\")\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif meta.TypedSpec().Phase != block.VolumePhaseReady {\n\t\t\tlogger.Debug(\"meta partition not ready yet\")\n\n\t\t\tcontinue\n\t\t}\n\n\t\tdiscoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to list discovered volumes: %w\", err)\n\t\t}\n\n\t\tvar multiErr error\n\n\t\tfor dv := range discoveredVolumes.All() {\n\t\t\tif dv.TypedSpec().Name != \"lvm2-pv\" {\n\t\t\t\t// if the volume is not an LVM volume the moment we saw it, we can skip it\n\t\t\t\t// we need to activate the volumes only on reboot, not when they are first formatted\n\t\t\t\tctrl.seenVolumes[dv.Metadata().ID()] = struct{}{}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := ctrl.seenVolumes[dv.Metadata().ID()]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlogger.Debug(\"checking device for LVM volume activation\", zap.String(\"device\", dv.TypedSpec().DevPath))\n\n\t\t\tvgName, err := ctrl.checkVGNeedsActivation(ctx, dv.TypedSpec().DevPath)\n\t\t\tif err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif vgName == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := ctrl.activatedVGs[vgName]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlogger.Info(\"activating LVM volume\", zap.String(\"name\", vgName))\n\n\t\t\t// activate the volume group\n\t\t\tif _, err = cmd.RunWithOptions(ctx,\n\t\t\t\t\"/sbin/lvm\",\n\t\t\t\t[]string{\n\t\t\t\t\t\"vgchange\",\n\t\t\t\t\t\"-aay\",\n\t\t\t\t\t\"--autoactivation\",\n\t\t\t\t\t\"event\",\n\t\t\t\t\tvgName,\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"failed to activate LVM volume %s: %w\", vgName, err))\n\t\t\t} else {\n\t\t\t\tctrl.activatedVGs[vgName] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\tif multiErr != nil {\n\t\t\treturn multiErr\n\t\t}\n\t}\n}\n\n// checkVGNeedsActivation checks if the device is part of a volume group and returns the volume group name\n// if it needs to be activated, otherwise it returns an empty string.\nfunc (ctrl *LVMActivationController) checkVGNeedsActivation(ctx context.Context, devicePath string) (string, error) {\n\t// first we check if all associated volumes are available\n\t// https://man7.org/linux/man-pages/man7/lvmautoactivation.7.html\n\tstdOut, err := cmd.RunWithOptions(ctx,\n\t\t\"/sbin/lvm\",\n\t\t[]string{\n\t\t\t\"pvscan\",\n\t\t\t\"--cache\",\n\t\t\t\"--listvg\",\n\t\t\t\"--checkcomplete\",\n\t\t\t\"--vgonline\",\n\t\t\t\"--autoactivation\",\n\t\t\t\"event\",\n\t\t\t\"--udevoutput\",\n\t\t\tdevicePath,\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to check if LVM volume backed by device %s needs activation: %w\", devicePath, err)\n\t}\n\n\t// parse the key-value pairs from the udev output\n\tfor line := range strings.SplitSeq(stdOut, \"\\n\") {\n\t\tkey, value, ok := strings.Cut(line, \"=\")\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tvalue = strings.Trim(value, \"'\\\"\")\n\n\t\tif key == \"LVM_VG_NAME_COMPLETE\" {\n\t\t\treturn value, nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"syscall\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/swap\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/filetree\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\ntype mountContext struct {\n\tpoint             *mount.Point\n\treadOnly          bool\n\tdisableAccessTime bool\n\tsecure            bool\n\tunmounter         func() error\n}\n\n// MountController performs actual mount/unmount operations based on the MountRequests.\ntype MountController struct {\n\tactiveMounts map[string]*mountContext\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MountController) Name() string {\n\treturn \"block.MountController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MountController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountRequestType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MountController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.MountStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *MountController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.activeMounts == nil {\n\t\tctrl.activeMounts = map[string]*mountContext{}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tvolumeStatuses, err := safe.ReaderListAll[*block.VolumeStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read volume statuses: %w\", err)\n\t\t}\n\n\t\tvolumeStatusMap := xslices.ToMap(\n\t\t\tsafe.ToSlice(\n\t\t\t\tvolumeStatuses,\n\t\t\t\tidentity,\n\t\t\t),\n\t\t\tfunc(v *block.VolumeStatus) (string, *block.VolumeStatus) {\n\t\t\t\treturn v.Metadata().ID(), v\n\t\t\t},\n\t\t)\n\n\t\tmountStatuses, err := safe.ReaderListAll[*block.MountStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read mount statuses: %w\", err)\n\t\t}\n\n\t\tmountStatusMap := xslices.ToMap(\n\t\t\tsafe.ToSlice(\n\t\t\t\tmountStatuses,\n\t\t\t\tidentity,\n\t\t\t),\n\t\t\tfunc(v *block.MountStatus) (string, *block.MountStatus) {\n\t\t\t\treturn v.Metadata().ID(), v\n\t\t\t},\n\t\t)\n\n\t\tmountRequests, err := safe.ReaderListAll[*block.MountRequest](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read mount requests: %w\", err)\n\t\t}\n\n\t\tfor mountRequest := range mountRequests.All() {\n\t\t\tvolumeStatus := volumeStatusMap[mountRequest.TypedSpec().VolumeID]\n\t\t\tvolumeNotReady := volumeStatus == nil || volumeStatus.TypedSpec().Phase != block.VolumePhaseReady || volumeStatus.Metadata().Phase() != resource.PhaseRunning\n\n\t\t\tmountRequestTearingDown := mountRequest.Metadata().Phase() == resource.PhaseTearingDown\n\n\t\t\tmountStatus := mountStatusMap[mountRequest.Metadata().ID()]\n\t\t\tmountStatusTearingDown := mountStatus != nil && mountStatus.Metadata().Phase() == resource.PhaseTearingDown\n\n\t\t\tmountHasParent := mountRequest.TypedSpec().ParentMountID != \"\"\n\t\t\tmountParentStatus := mountStatusMap[mountRequest.TypedSpec().ParentMountID] // this might be nil\n\t\t\tmountParentReady := !mountHasParent || (mountParentStatus != nil && mountParentStatus.Metadata().Phase() == resource.PhaseRunning)\n\t\t\tmountParentTearingDown := mountHasParent && mountParentStatus != nil && mountParentStatus.Metadata().Phase() == resource.PhaseTearingDown\n\n\t\t\tparentFinalizerName := ctrl.Name() + \"-\" + mountRequest.Metadata().ID()\n\n\t\t\tif volumeNotReady || mountRequestTearingDown || mountStatusTearingDown || mountParentTearingDown {\n\t\t\t\t// we should tear down the mount in the following sequence:\n\t\t\t\t// 1. tear down & destroy MountStatus\n\t\t\t\t// 2. perform actual unmount\n\t\t\t\t// 3. remove finalizer from VolumeStatus\n\t\t\t\t// 4. remove finalizer from parent MountStatus (if any)\n\t\t\t\t// 5. remove finalizer from MountRequest\n\t\t\t\tmountStatusTornDown, err := ctrl.tearDownMountStatus(ctx, r, logger, mountRequest)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down mount status %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t}\n\n\t\t\t\tif !mountStatusTornDown {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif volumeStatus != nil {\n\t\t\t\t\tif err = ctrl.handleUnmountOperation(logger, mountRequest, volumeStatus); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif volumeStatus != nil && volumeStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\tif err = r.RemoveFinalizer(ctx, volumeStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer from volume status %q: %w\", volumeStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif mountParentStatus != nil && mountParentStatus.Metadata().Finalizers().Has(parentFinalizerName) {\n\t\t\t\t\tif err = r.RemoveFinalizer(ctx, mountParentStatus.Metadata(), parentFinalizerName); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer from parent mount status %q: %w\", mountParentStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif mountRequest.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\tif err = r.RemoveFinalizer(ctx, mountRequest.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer from mount request %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !(volumeNotReady || mountRequestTearingDown) && mountParentReady {\n\t\t\t\t// we should perform mount operation in the following sequence:\n\t\t\t\t// 1. add finalizer on MountRequest\n\t\t\t\t// 2. add finalizer on parent MountStatus (if any)\n\t\t\t\t// 3. add finalizer on VolumeStatus\n\t\t\t\t// 4. perform actual mount\n\t\t\t\t// 5. create MountStatus\n\t\t\t\tif !mountRequest.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\tif err = r.AddFinalizer(ctx, mountRequest.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to add finalizer to mount request %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif mountHasParent && !mountParentStatus.Metadata().Finalizers().Has(parentFinalizerName) && mountParentStatus.Metadata().Phase() == resource.PhaseRunning {\n\t\t\t\t\tif err = r.AddFinalizer(ctx, mountParentStatus.Metadata(), parentFinalizerName); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to add finalizer to parent mount status %q: %w\", mountParentStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif !volumeStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\tif err = r.AddFinalizer(ctx, volumeStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to add finalizer to volume status %q: %w\", volumeStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmountSource := volumeStatus.TypedSpec().MountLocation\n\t\t\t\tmountTarget := volumeStatus.TypedSpec().MountSpec.TargetPath\n\t\t\t\tmountFilesystem := volumeStatus.TypedSpec().Filesystem\n\n\t\t\t\trootPath := \"/\"\n\n\t\t\t\tif mountHasParent {\n\t\t\t\t\trootPath = mountParentStatus.TypedSpec().Target\n\t\t\t\t}\n\n\t\t\t\tif err = ctrl.handleMountOperation(logger, rootPath, mountSource, mountTarget, mountFilesystem, mountRequest, volumeStatus); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif err = safe.WriterModify(\n\t\t\t\t\tctx, r, block.NewMountStatus(block.NamespaceName, mountRequest.Metadata().ID()),\n\t\t\t\t\tfunc(mountStatus *block.MountStatus) error {\n\t\t\t\t\t\tmountStatus.TypedSpec().Spec = *mountRequest.TypedSpec()\n\t\t\t\t\t\tmountStatus.TypedSpec().Source = mountSource\n\t\t\t\t\t\tmountStatus.TypedSpec().Target = filepath.Join(rootPath, mountTarget)\n\t\t\t\t\t\tmountStatus.TypedSpec().Filesystem = mountFilesystem\n\t\t\t\t\t\tmountStatus.TypedSpec().EncryptionProvider = volumeStatus.TypedSpec().EncryptionProvider\n\t\t\t\t\t\tmountStatus.TypedSpec().ReadOnly = mountRequest.TypedSpec().ReadOnly\n\t\t\t\t\t\tmountStatus.TypedSpec().ProjectQuotaSupport = volumeStatus.TypedSpec().MountSpec.ProjectQuotaSupport\n\t\t\t\t\t\tmountStatus.TypedSpec().Detached = mountRequest.TypedSpec().Detached\n\n\t\t\t\t\t\t// This needs to be set through accessor, and is not guaranteed to resolve to a valid root.\n\t\t\t\t\t\tmount, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\t\t\t\t\t\tif ok && mount.point != nil {\n\t\t\t\t\t\t\tmountStatus.TypedSpec().SetRoot(mount.point.Root())\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmountStatus.TypedSpec().SetRoot(&xfs.OSRoot{Shadow: filepath.Join(rootPath, mountTarget)})\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create mount status %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *MountController) tearDownMountStatus(ctx context.Context, r controller.Runtime, logger *zap.Logger, mountRequest *block.MountRequest) (bool, error) {\n\tlogger = logger.With(zap.String(\"mount_request\", mountRequest.Metadata().ID()))\n\n\tokToDestroy, err := r.Teardown(ctx, block.NewMountStatus(block.NamespaceName, mountRequest.Metadata().ID()).Metadata())\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// no mount status, we are done\n\t\t\treturn true, nil\n\t\t}\n\n\t\treturn false, fmt.Errorf(\"failed to teardown mount status %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\tif !okToDestroy {\n\t\tlogger.Debug(\"waiting for mount status to be torn down\")\n\n\t\treturn false, nil\n\t}\n\n\terr = r.Destroy(ctx, block.NewMountStatus(block.NamespaceName, mountRequest.Metadata().ID()).Metadata())\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"failed to destroy mount status %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\treturn true, nil\n}\n\nfunc (ctrl *MountController) handleMountOperation(\n\tlogger *zap.Logger,\n\trootPath string,\n\tmountSource, mountTarget string,\n\tmountFilesystem block.FilesystemType,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\tswitch volumeStatus.TypedSpec().Type {\n\tcase block.VolumeTypeDirectory:\n\t\treturn ctrl.handleDirectoryMountOperation(logger, rootPath, mountTarget, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeOverlay:\n\t\treturn ctrl.handleOverlayMountOperation(logger, filepath.Join(rootPath, mountTarget), mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeSymlink:\n\t\treturn ctrl.handleSymlinkMountOperation(logger, rootPath, mountTarget, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeTmpfs:\n\t\treturn fmt.Errorf(\"not implemented yet\")\n\n\tcase block.VolumeTypeExternal:\n\t\treturn ctrl.handleDiskMountOperation(logger, mountSource, filepath.Join(rootPath, mountTarget), mountFilesystem, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeDisk, block.VolumeTypePartition:\n\t\tif mountFilesystem == block.FilesystemTypeSwap {\n\t\t\treturn ctrl.handleSwapMountOperation(logger, mountSource, mountRequest, volumeStatus)\n\t\t}\n\n\t\treturn ctrl.handleDiskMountOperation(logger, mountSource, filepath.Join(rootPath, mountTarget), mountFilesystem, mountRequest, volumeStatus)\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported volume type %q\", volumeStatus.TypedSpec().Type)\n\t}\n}\n\nfunc (ctrl *MountController) handleDirectoryMountOperation(\n\tlogger *zap.Logger,\n\trootPath string,\n\ttarget string,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\ttargetPath := filepath.Join(rootPath, target)\n\n\tif err := os.Mkdir(targetPath, volumeStatus.TypedSpec().MountSpec.FileMode); err != nil {\n\t\tif !os.IsExist(err) {\n\t\t\treturn fmt.Errorf(\"failed to create target path: %w\", err)\n\t\t}\n\n\t\tst, err := os.Stat(targetPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to stat target path: %w\", err)\n\t\t}\n\n\t\tif !st.IsDir() {\n\t\t\treturn fmt.Errorf(\"target path %q is not a directory\", targetPath)\n\t\t}\n\t}\n\n\tif volumeStatus.TypedSpec().MountSpec.BindTarget != nil {\n\t\tif err := ctrl.handleBindMountOperation(\n\t\t\tlogger,\n\t\t\trootPath, target, *volumeStatus.TypedSpec().MountSpec.BindTarget,\n\t\t\tmountRequest, volumeStatus,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"target path %q is not a directory\", targetPath)\n\t\t}\n\t}\n\n\treturn ctrl.updateTargetSettings(targetPath, volumeStatus.TypedSpec().Filesystem, volumeStatus.TypedSpec().MountSpec)\n}\n\nfunc (ctrl *MountController) handleBindMountOperation(\n\tlogger *zap.Logger,\n\trootPath string,\n\tsource string,\n\tbindTarget string,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\t_, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\n\t// mount hasn't been done yet\n\tif !ok {\n\t\tmountSource := filepath.Join(rootPath, source)\n\t\tmountTarget := filepath.Join(rootPath, bindTarget)\n\n\t\tif err := os.Mkdir(mountTarget, volumeStatus.TypedSpec().MountSpec.FileMode); err != nil {\n\t\t\tif !os.IsExist(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to create target path: %w\", err)\n\t\t\t}\n\n\t\t\tst, err := os.Stat(mountTarget)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to stat target path: %w\", err)\n\t\t\t}\n\n\t\t\tif !st.IsDir() {\n\t\t\t\treturn fmt.Errorf(\"target path %q is not a directory\", mountTarget)\n\t\t\t}\n\t\t}\n\n\t\topts := []mount.ManagerOption{\n\t\t\tmount.WithSelinuxLabel(volumeStatus.TypedSpec().MountSpec.SelinuxLabel),\n\t\t}\n\n\t\tmanager := mount.NewManager(slices.Concat(\n\t\t\t[]mount.ManagerOption{\n\t\t\t\tmount.WithTarget(mountTarget),\n\t\t\t\tmount.WithOpentreeFromPath(mountSource),\n\t\t\t\tmount.WithPrinter(logger.Sugar().Infof),\n\t\t\t},\n\t\t\topts,\n\t\t)...)\n\n\t\tmountpoint, err := manager.Mount()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to mount %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tif !mountRequest.TypedSpec().ReadOnly && !mountRequest.TypedSpec().Detached {\n\t\t\tif err = ctrl.updateTargetSettings(mountTarget, volumeStatus.TypedSpec().Filesystem, volumeStatus.TypedSpec().MountSpec); err != nil {\n\t\t\t\tmanager.Unmount() //nolint:errcheck\n\n\t\t\t\treturn fmt.Errorf(\"failed to update target settings %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t}\n\t\t}\n\n\t\tlogger.Info(\"bind mount\",\n\t\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\t\tzap.String(\"source\", mountSource),\n\t\t\tzap.String(\"target\", mountTarget),\n\t\t)\n\n\t\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{\n\t\t\tpoint:     mountpoint,\n\t\t\treadOnly:  mountRequest.TypedSpec().ReadOnly,\n\t\t\tunmounter: manager.Unmount,\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *MountController) handleSymlinkMountOperation(\n\tlogger *zap.Logger,\n\trootPath string,\n\ttarget string,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\t_, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\tif ok {\n\t\treturn nil\n\t}\n\n\ttargetPath := filepath.Join(rootPath, target)\n\n\tst, err := os.Lstat(targetPath)\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"failed to stat target path: %w\", err)\n\t}\n\n\tif st == nil {\n\t\t// create the symlink\n\t\tif err := os.Symlink(volumeStatus.TypedSpec().SymlinkSpec.SymlinkTargetPath, targetPath); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create symlink %q: %w\", targetPath, err)\n\t\t}\n\n\t\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{}\n\n\t\treturn nil\n\t}\n\n\tif st.Mode()&os.ModeSymlink != 0 {\n\t\t// if it's already a symlink, check if it points to the right target\n\t\tsymlinkTarget, err := os.Readlink(targetPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read symlink target: %w\", err)\n\t\t}\n\n\t\tif symlinkTarget == volumeStatus.TypedSpec().SymlinkSpec.SymlinkTargetPath {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif !volumeStatus.TypedSpec().SymlinkSpec.Force {\n\t\treturn fmt.Errorf(\"target path %q is not a symlink to %q\", targetPath, volumeStatus.TypedSpec().SymlinkSpec.SymlinkTargetPath)\n\t}\n\n\t// try to remove forcefully\n\tif err := os.RemoveAll(targetPath); err != nil {\n\t\tif !st.Mode().IsDir() {\n\t\t\treturn fmt.Errorf(\"failed to remove target path, and target is not a directory %s: %w\", st.Mode(), err)\n\t\t}\n\n\t\t// try to remove all entries if it's a directory\n\t\tentries, err := os.ReadDir(targetPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read target path: %w\", err)\n\t\t}\n\n\t\tfor _, entry := range entries {\n\t\t\tif err := os.RemoveAll(filepath.Join(targetPath, entry.Name())); err != nil {\n\t\t\t\tlogger.Warn(\"failed to remove target path entry\", zap.String(\"entry\", entry.Name()), zap.Error(err))\n\t\t\t}\n\t\t}\n\n\t\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{}\n\n\t\t// return early, i.e. keep this as a directory\n\t\treturn nil\n\t}\n\n\tif err := os.Symlink(volumeStatus.TypedSpec().SymlinkSpec.SymlinkTargetPath, targetPath); err != nil {\n\t\treturn fmt.Errorf(\"failed to create symlink %q: %w\", targetPath, err)\n\t}\n\n\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *MountController) updateTargetSettings(\n\ttargetPath string,\n\tfstype block.FilesystemType,\n\tmountSpec block.MountSpec,\n) error {\n\tif err := os.Chmod(targetPath, mountSpec.FileMode); err != nil {\n\t\treturn fmt.Errorf(\"failed to chmod %q: %w\", targetPath, err)\n\t}\n\n\tst, err := os.Stat(targetPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to stat %q: %w\", targetPath, err)\n\t}\n\n\tsysStat := st.Sys().(*syscall.Stat_t)\n\n\tif sysStat.Uid != uint32(mountSpec.UID) || sysStat.Gid != uint32(mountSpec.GID) {\n\t\tif mountSpec.RecursiveRelabel {\n\t\t\terr = filetree.ChownRecursive(targetPath, uint32(mountSpec.UID), uint32(mountSpec.GID))\n\t\t} else {\n\t\t\terr = os.Chown(targetPath, mountSpec.UID, mountSpec.GID)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to chown %q: %w\", targetPath, err)\n\t\t}\n\t}\n\n\tcurrentLabel, err := selinux.GetLabel(targetPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get current label %q: %w\", targetPath, err)\n\t}\n\n\tif currentLabel == mountSpec.SelinuxLabel {\n\t\t// nothing to do\n\t\treturn nil\n\t}\n\n\tif mountSpec.RecursiveRelabel {\n\t\terr = selinux.SetLabelRecursive(targetPath, mountSpec.SelinuxLabel)\n\t} else {\n\t\terr = selinux.SetLabel(targetPath, mountSpec.SelinuxLabel)\n\t}\n\n\treturn mount.FilterSelinuxLabelErrors(targetPath, fstype.String(), err)\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *MountController) handleDiskMountOperation(\n\tlogger *zap.Logger,\n\tmountSource, mountTarget string,\n\tmountFilesystem block.FilesystemType,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\tmountCtx, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\n\tlogger = logger.With(zap.String(\"mount_request.id\", mountRequest.Metadata().ID()))\n\n\t// mount hasn't been done yet\n\tif !ok {\n\t\tvar (\n\t\t\topts   []mount.ManagerOption\n\t\t\tfsOpts []fsopen.Option\n\t\t)\n\n\t\tfsOpts = append(fsOpts,\n\t\t\tfsopen.WithSource(mountSource),\n\t\t\tfsopen.WithProjectQuota(volumeStatus.TypedSpec().MountSpec.ProjectQuotaSupport),\n\t\t)\n\n\t\tfor _, param := range volumeStatus.TypedSpec().MountSpec.Parameters {\n\t\t\tlogger.Info(\"adding new parameter\",\n\t\t\t\tzap.String(\"parameter\", param.Name),\n\t\t\t\tzap.String(\"parameter.type\", param.Type.String()),\n\t\t\t\tzap.String(\"parameter.string\", pointer.SafeDeref(param.String)),\n\t\t\t\tzap.Binary(\"parameter.bytes\", param.Binary),\n\t\t\t)\n\n\t\t\tswitch param.Type {\n\t\t\tcase block.FSParameterTypeBinaryValue:\n\t\t\t\tif param.Binary == nil {\n\t\t\t\t\tlogger.Warn(\"skipping nil binary parameter\", zap.String(\"parameter\", param.Name))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfsOpts = append(fsOpts, fsopen.WithBinaryParameters(param.Name, param.Binary))\n\t\t\tcase block.FSParameterTypeStringValue:\n\t\t\t\tif param.String == nil {\n\t\t\t\t\tlogger.Warn(\"skipping nil string parameter\", zap.String(\"parameter\", param.Name))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfsOpts = append(fsOpts, fsopen.WithStringParameter(param.Name, *param.String))\n\t\t\tcase block.FSParameterTypeBooleanValue:\n\t\t\t\tfsOpts = append(fsOpts, fsopen.WithBoolParameter(param.Name))\n\t\t\t}\n\t\t}\n\n\t\topts = append(opts,\n\t\t\tmount.WithSelinuxLabel(volumeStatus.TypedSpec().MountSpec.SelinuxLabel),\n\t\t)\n\n\t\tif mountRequest.TypedSpec().DisableAccessTime {\n\t\t\topts = append(opts, mount.WithDisableAccessTime())\n\t\t}\n\n\t\tif mountRequest.TypedSpec().Secure {\n\t\t\topts = append(opts, mount.WithSecure())\n\t\t}\n\n\t\tif mountRequest.TypedSpec().ReadOnly {\n\t\t\topts = append(opts, mount.WithReadOnly())\n\t\t}\n\n\t\tif mountRequest.TypedSpec().Detached {\n\t\t\topts = append(opts, mount.WithDetached())\n\t\t}\n\n\t\tmanager := mount.NewManager(slices.Concat(\n\t\t\t[]mount.ManagerOption{\n\t\t\t\tmount.WithTarget(mountTarget),\n\t\t\t\tmount.WithFsopen(\n\t\t\t\t\tmountFilesystem.String(),\n\t\t\t\t\tfsOpts...,\n\t\t\t\t),\n\t\t\t\tmount.WithPrinter(logger.Sugar().Infof),\n\t\t\t},\n\t\t\topts,\n\t\t)...)\n\n\t\tmountpoint, err := manager.Mount()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to mount %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tif !mountRequest.TypedSpec().ReadOnly && !mountRequest.TypedSpec().Detached {\n\t\t\tif err = ctrl.updateTargetSettings(mountTarget, volumeStatus.TypedSpec().Filesystem, volumeStatus.TypedSpec().MountSpec); err != nil {\n\t\t\t\tmanager.Unmount() //nolint:errcheck\n\n\t\t\t\treturn fmt.Errorf(\"failed to update target settings %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t}\n\t\t}\n\n\t\tlogger.Info(\"volume mount\",\n\t\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\t\tzap.String(\"source\", mountSource),\n\t\t\tzap.String(\"target\", mountTarget),\n\t\t\tzap.Stringer(\"filesystem\", mountFilesystem),\n\t\t\tzap.Bool(\"read_only\", mountRequest.TypedSpec().ReadOnly),\n\t\t\tzap.Bool(\"secure\", mountRequest.TypedSpec().Secure),\n\t\t\tzap.Bool(\"disable_access_time\", mountRequest.TypedSpec().DisableAccessTime),\n\t\t\tzap.Bool(\"detached\", mountRequest.TypedSpec().Detached),\n\t\t)\n\n\t\tmountCtx = &mountContext{\n\t\t\tpoint:             mountpoint,\n\t\t\treadOnly:          mountRequest.TypedSpec().ReadOnly,\n\t\t\tdisableAccessTime: mountRequest.TypedSpec().DisableAccessTime,\n\t\t\tsecure:            mountRequest.TypedSpec().Secure,\n\t\t\tunmounter:         manager.Unmount,\n\t\t}\n\t\tctrl.activeMounts[mountRequest.Metadata().ID()] = mountCtx\n\t}\n\n\tif mountCtx.readOnly != mountRequest.TypedSpec().ReadOnly { // remount if needed\n\t\tvar err error\n\n\t\tswitch mountRequest.TypedSpec().ReadOnly {\n\t\tcase true:\n\t\t\terr = mountCtx.point.RemountReadOnly()\n\t\tcase false:\n\t\t\terr = mountCtx.point.RemountReadWrite()\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to remount %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tlogger.Info(\"volume remounted\",\n\t\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\t\tzap.String(\"read_only\", fmt.Sprintf(\"%v -> %v\", mountCtx.readOnly, mountRequest.TypedSpec().ReadOnly)),\n\t\t)\n\n\t\tmountCtx.readOnly = mountRequest.TypedSpec().ReadOnly\n\t}\n\n\t//nolint:dupl\n\tif mountCtx.disableAccessTime != mountRequest.TypedSpec().DisableAccessTime {\n\t\terr := mountCtx.point.SetDisableAccessTime(mountRequest.TypedSpec().DisableAccessTime)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update disableAccessTime for %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tlogger.Info(\"volume mount attributes updated\",\n\t\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\t\tzap.String(\"disable_access_time\", fmt.Sprintf(\"%v -> %v\", mountCtx.disableAccessTime, mountRequest.TypedSpec().DisableAccessTime)),\n\t\t)\n\n\t\tmountCtx.disableAccessTime = mountRequest.TypedSpec().DisableAccessTime\n\t}\n\n\t//nolint:dupl\n\tif mountCtx.secure != mountRequest.TypedSpec().Secure {\n\t\terr := mountCtx.point.SetSecure(mountRequest.TypedSpec().Secure)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update secure for %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tlogger.Info(\"volume mount attributes updated\",\n\t\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\t\tzap.String(\"secure\", fmt.Sprintf(\"%v -> %v\", mountCtx.secure, mountRequest.TypedSpec().Secure)),\n\t\t)\n\n\t\tmountCtx.secure = mountRequest.TypedSpec().Secure\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleOverlayMountOperation(\n\tlogger *zap.Logger,\n\tmountTarget string,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\tif _, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]; ok {\n\t\treturn nil\n\t}\n\n\tif volumeStatus.TypedSpec().ParentID != constants.EphemeralPartitionLabel {\n\t\treturn fmt.Errorf(\"overlay mount is not supported for %q\", volumeStatus.TypedSpec().ParentID)\n\t}\n\n\tmanager := mount.NewVarOverlay(\n\t\t[]string{mountTarget},\n\t\tmountTarget,\n\t\tlogger.Sugar().Infof,\n\t\tmount.WithSelinuxLabel(volumeStatus.TypedSpec().MountSpec.SelinuxLabel),\n\t)\n\n\tmountpoint, err := manager.Mount()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to mount %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\tif err = ctrl.updateTargetSettings(mountTarget, volumeStatus.TypedSpec().Filesystem, volumeStatus.TypedSpec().MountSpec); err != nil {\n\t\tmanager.Unmount() //nolint:errcheck\n\n\t\treturn fmt.Errorf(\"failed to update target settings %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\tlogger.Info(\"overlay mount\",\n\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\tzap.String(\"target\", mountTarget),\n\t\tzap.String(\"parent\", volumeStatus.TypedSpec().ParentID),\n\t)\n\n\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{\n\t\tpoint:     mountpoint,\n\t\tunmounter: manager.Unmount,\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleSwapMountOperation(\n\tlogger *zap.Logger,\n\tmountSource string,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\t_, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\tif ok {\n\t\treturn nil\n\t}\n\n\tif err := swap.On(mountSource, swap.FLAG_DISCARD_ONCE); err != nil {\n\t\treturn fmt.Errorf(\"failed to enable swap on %q: %w\", mountSource, err)\n\t}\n\n\tctrl.activeMounts[mountRequest.Metadata().ID()] = &mountContext{\n\t\tpoint: mount.NewPoint(mountSource, 0, \"\", 0, \"swap\"),\n\t}\n\n\tlogger.Info(\"swap enabled\",\n\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\tzap.String(\"source\", mountSource),\n\t)\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleUnmountOperation(\n\tlogger *zap.Logger,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\tswitch volumeStatus.TypedSpec().Type {\n\tcase block.VolumeTypeDirectory:\n\t\treturn ctrl.handleDirectoryUnmountOperation(logger, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeTmpfs:\n\t\treturn fmt.Errorf(\"not implemented yet\")\n\n\tcase block.VolumeTypeExternal:\n\t\treturn ctrl.handleDiskUnmountOperation(logger, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeDisk, block.VolumeTypePartition, block.VolumeTypeOverlay:\n\t\tif volumeStatus.TypedSpec().Filesystem == block.FilesystemTypeSwap {\n\t\t\treturn ctrl.handleSwapUmountOperation(logger, mountRequest, volumeStatus)\n\t\t}\n\n\t\treturn ctrl.handleDiskUnmountOperation(logger, mountRequest, volumeStatus)\n\n\tcase block.VolumeTypeSymlink:\n\t\treturn ctrl.handleSymlinkUmountOperation(mountRequest)\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported volume type %q\", volumeStatus.TypedSpec().Type)\n\t}\n}\n\nfunc (ctrl *MountController) handleDiskUnmountOperation(\n\tlogger *zap.Logger,\n\tmountRequest *block.MountRequest,\n\t_ *block.VolumeStatus,\n) error {\n\tmountCtx, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif err := mountCtx.unmounter(); err != nil {\n\t\treturn fmt.Errorf(\"failed to unmount %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\tdelete(ctrl.activeMounts, mountRequest.Metadata().ID())\n\n\tlogger.Info(\"volume unmount\",\n\t\tzap.String(\"volume\", mountRequest.Metadata().ID()),\n\t\tzap.String(\"source\", mountCtx.point.Source()),\n\t\tzap.String(\"target\", mountCtx.point.Target()),\n\t\tzap.String(\"filesystem\", mountCtx.point.FSType()),\n\t)\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleDirectoryUnmountOperation(\n\tlogger *zap.Logger,\n\tmountRequest *block.MountRequest,\n\t_ *block.VolumeStatus,\n) error {\n\tmountCtx, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif err := mountCtx.unmounter(); err != nil {\n\t\treturn fmt.Errorf(\"failed to unmount %q: %w\", mountRequest.Metadata().ID(), err)\n\t}\n\n\tdelete(ctrl.activeMounts, mountRequest.Metadata().ID())\n\n\tlogger.Info(\"volume unmount\",\n\t\tzap.String(\"volume\", mountRequest.Metadata().ID()),\n\t\tzap.String(\"source\", mountCtx.point.Source()),\n\t\tzap.String(\"target\", mountCtx.point.Target()),\n\t)\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleSymlinkUmountOperation(\n\tmountRequest *block.MountRequest,\n) error {\n\tdelete(ctrl.activeMounts, mountRequest.Metadata().ID())\n\n\treturn nil\n}\n\nfunc (ctrl *MountController) handleSwapUmountOperation(\n\tlogger *zap.Logger,\n\tmountRequest *block.MountRequest,\n\tvolumeStatus *block.VolumeStatus,\n) error {\n\tmountCtx, ok := ctrl.activeMounts[mountRequest.Metadata().ID()]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif err := swap.Off(mountCtx.point.Source()); err != nil {\n\t\treturn fmt.Errorf(\"failed to disable swap on %q: %w\", mountCtx.point.Source(), err)\n\t}\n\n\tdelete(ctrl.activeMounts, mountRequest.Metadata().ID())\n\n\tlogger.Info(\"swap disabled\",\n\t\tzap.String(\"volume\", volumeStatus.Metadata().ID()),\n\t\tzap.String(\"source\", mountCtx.point.Source()),\n\t)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount_request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// MountRequestController provides mount requests based on VolumeMountRequests and VolumeStatuses.\ntype MountRequestController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MountRequestController) Name() string {\n\treturn \"block.MountRequestController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MountRequestController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MountRequestController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.MountRequestType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nfunc identity[T any](v T) T {\n\treturn v\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *MountRequestController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tvolumeStatuses, err := safe.ReaderListAll[*block.VolumeStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read volume statuses: %w\", err)\n\t\t}\n\n\t\tvolumeStatusMap := xslices.ToMap(\n\t\t\tsafe.ToSlice(\n\t\t\t\tvolumeStatuses,\n\t\t\t\tidentity,\n\t\t\t),\n\t\t\tfunc(v *block.VolumeStatus) (string, *block.VolumeStatus) {\n\t\t\t\treturn v.Metadata().ID(), v\n\t\t\t},\n\t\t)\n\n\t\tvolumeMountRequests, err := safe.ReaderListAll[*block.VolumeMountRequest](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read volume mount requests: %w\", err)\n\t\t}\n\n\t\tdesiredMountRequests := map[string]*block.MountRequestSpec{}\n\n\t\tfor volumeMountRequest := range volumeMountRequests.All() {\n\t\t\tvolumeID := volumeMountRequest.TypedSpec().VolumeID\n\n\t\t\tvolumeStatus, ok := volumeStatusMap[volumeID]\n\t\t\tif !ok || volumeStatus.TypedSpec().Phase != block.VolumePhaseReady || volumeStatus.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, exists := desiredMountRequests[volumeID]; !exists {\n\t\t\t\tdesiredMountRequests[volumeID] = &block.MountRequestSpec{\n\t\t\t\t\tVolumeID:          volumeID,\n\t\t\t\t\tReadOnly:          volumeMountRequest.TypedSpec().ReadOnly,\n\t\t\t\t\tDetached:          volumeMountRequest.TypedSpec().Detached,\n\t\t\t\t\tDisableAccessTime: volumeMountRequest.TypedSpec().DisableAccessTime,\n\t\t\t\t\tSecure:            volumeMountRequest.TypedSpec().Secure,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdesiredMountRequest := desiredMountRequests[volumeID]\n\t\t\tdesiredMountRequest.Requesters = append(desiredMountRequest.Requesters, volumeMountRequest.TypedSpec().Requester)\n\t\t\tdesiredMountRequest.RequesterIDs = append(desiredMountRequest.RequesterIDs, volumeMountRequest.Metadata().ID())\n\n\t\t\t// read-only if all requesters are read-only\n\t\t\tdesiredMountRequest.ReadOnly = desiredMountRequest.ReadOnly && volumeMountRequest.TypedSpec().ReadOnly\n\t\t\t// detached if all requesters are detached\n\t\t\tdesiredMountRequest.Detached = desiredMountRequest.Detached && volumeMountRequest.TypedSpec().Detached\n\t\t\t// disable access time if any requester wants it disabled\n\t\t\tdesiredMountRequest.DisableAccessTime = desiredMountRequest.DisableAccessTime || volumeMountRequest.TypedSpec().DisableAccessTime\n\t\t\t// secure if any requester wants it secure\n\t\t\tdesiredMountRequest.Secure = desiredMountRequest.Secure || volumeMountRequest.TypedSpec().Secure\n\t\t\tdesiredMountRequest.ParentMountID = volumeStatus.TypedSpec().MountSpec.ParentID\n\t\t}\n\n\t\t// list and figure out what to do with existing mount requests\n\t\tmountRequests, err := safe.ReaderListAll[*block.MountRequest](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read mount requests: %w\", err)\n\t\t}\n\n\t\t// perform cleanup of mount requests which should be cleaned up\n\t\tfor mountRequest := range mountRequests.All() {\n\t\t\ttearingDown := mountRequest.Metadata().Phase() == resource.PhaseTearingDown\n\t\t\tshouldBeDestroyed := desiredMountRequests[mountRequest.Metadata().ID()] == nil\n\n\t\t\tif tearingDown || shouldBeDestroyed {\n\t\t\t\tokToDestroy, err := r.Teardown(ctx, mountRequest.Metadata())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to teardown mount request %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t}\n\n\t\t\t\tif okToDestroy {\n\t\t\t\t\tif err = r.Destroy(ctx, mountRequest.Metadata()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to destroy mount request %q: %w\", mountRequest.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t} else if !shouldBeDestroyed {\n\t\t\t\t\t// previous mount request version is still being torn down\n\t\t\t\t\tdelete(desiredMountRequests, mountRequest.Metadata().ID())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// create/update mount requests\n\t\tfor id, desiredMountRequest := range desiredMountRequests {\n\t\t\tif err = safe.WriterModify(\n\t\t\t\tctx, r, block.NewMountRequest(block.NamespaceName, id),\n\t\t\t\tfunc(mr *block.MountRequest) error {\n\t\t\t\t\t*mr.TypedSpec() = *desiredMountRequest\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create/update mount request %q: %w\", id, err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount_request_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype MountRequestSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestMountRequestSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &MountRequestSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.MountRequestController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *MountRequestSuite) TestReconcile() {\n\tmountRequest1 := block.NewVolumeMountRequest(block.NamespaceName, \"mountRequest1\")\n\tmountRequest1.TypedSpec().Requester = \"requester1\"\n\tmountRequest1.TypedSpec().VolumeID = \"volume1\"\n\tmountRequest1.TypedSpec().ReadOnly = true\n\tsuite.Create(mountRequest1)\n\n\t// mount request is not created as the volume is not ready\n\tctest.AssertNoResource[*block.MountRequest](suite, \"volume1\")\n\n\tvolumeStatus1 := block.NewVolumeStatus(block.NamespaceName, \"volume1\")\n\tvolumeStatus1.TypedSpec().Phase = block.VolumePhaseWaiting\n\tsuite.Create(volumeStatus1)\n\n\t// mount request is not created as the volume status is not ready\n\tctest.AssertNoResource[*block.MountRequest](suite, \"volume1\")\n\n\tvolumeStatus1.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Update(volumeStatus1)\n\n\tctest.AssertResource(suite, \"volume1\", func(mr *block.MountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"volume1\", mr.TypedSpec().VolumeID)\n\t\tasrt.True(mr.TypedSpec().ReadOnly)\n\t\tasrt.ElementsMatch([]string{\"requester1\"}, mr.TypedSpec().Requesters)\n\t\tasrt.ElementsMatch([]string{\"mountRequest1\"}, mr.TypedSpec().RequesterIDs)\n\t})\n\n\t// add another mount request for the same volume\n\tmountRequest2 := block.NewVolumeMountRequest(block.NamespaceName, \"mountRequest2\")\n\tmountRequest2.TypedSpec().Requester = \"requester2\"\n\tmountRequest2.TypedSpec().VolumeID = \"volume1\"\n\tmountRequest2.TypedSpec().ReadOnly = false\n\tsuite.Create(mountRequest2)\n\n\tctest.AssertResource(suite, \"volume1\", func(mr *block.MountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"volume1\", mr.TypedSpec().VolumeID)\n\t\tasrt.False(mr.TypedSpec().ReadOnly)\n\t\tasrt.ElementsMatch([]string{\"requester1\", \"requester2\"}, mr.TypedSpec().Requesters)\n\t\tasrt.ElementsMatch([]string{\"mountRequest1\", \"mountRequest2\"}, mr.TypedSpec().RequesterIDs)\n\t})\n\n\t// if the mount request is fulfilled, a finalizer should be added\n\tsuite.AddFinalizer(block.NewMountRequest(block.NamespaceName, \"volume1\").Metadata(), \"mounted\")\n\n\t// try to remove one mount requests now\n\tsuite.Destroy(mountRequest2)\n\n\tctest.AssertResource(suite, \"volume1\", func(mr *block.MountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"volume1\", mr.TypedSpec().VolumeID)\n\t\tasrt.True(mr.TypedSpec().ReadOnly)\n\t\tasrt.ElementsMatch([]string{\"requester1\"}, mr.TypedSpec().Requesters)\n\t\tasrt.ElementsMatch([]string{\"mountRequest1\"}, mr.TypedSpec().RequesterIDs)\n\t})\n\n\t// try to remove another mount request now\n\tsuite.Destroy(mountRequest1)\n\n\tctest.AssertResource(suite, \"volume1\", func(mr *block.MountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"volume1\", mr.TypedSpec().VolumeID)\n\t\tasrt.True(mr.TypedSpec().ReadOnly)\n\t\tasrt.Equal([]string{\"requester1\"}, mr.TypedSpec().Requesters)\n\t\tasrt.ElementsMatch([]string{\"mountRequest1\"}, mr.TypedSpec().RequesterIDs)\n\t\tasrt.Equal(resource.PhaseTearingDown, mr.Metadata().Phase())\n\t})\n\n\t// remove the finalizer, allowing the mount request to be destroyed\n\tsuite.RemoveFinalizer(block.NewMountRequest(block.NamespaceName, \"volume1\").Metadata(), \"mounted\")\n\n\tctest.AssertNoResource[*block.MountRequest](suite, \"volume1\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// MountStatusController provides mount requests based on VolumeMountRequests and VolumeStatuses.\ntype MountStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Name() string {\n\treturn \"block.MountStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeMountStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *MountStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tmountStatuses, err := safe.ReaderListAll[*block.MountStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read volume mount requests: %w\", err)\n\t\t}\n\n\t\tfor mountStatus := range mountStatuses.All() {\n\t\t\tswitch mountStatus.Metadata().Phase() {\n\t\t\tcase resource.PhaseRunning:\n\t\t\t\t// always put our own finalizer\n\t\t\t\tif !mountStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\tif err = r.AddFinalizer(ctx, mountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to add finalizer to mount status %q: %w\", mountStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// now \"explode\" the mount status into volume mount statuses per requester\n\t\t\t\tfor i, requester := range mountStatus.TypedSpec().Spec.Requesters {\n\t\t\t\t\trequestID := mountStatus.TypedSpec().Spec.RequesterIDs[i]\n\n\t\t\t\t\tif err = safe.WriterModify(\n\t\t\t\t\t\tctx, r, block.NewVolumeMountStatus(block.NamespaceName, requestID),\n\t\t\t\t\t\tfunc(vms *block.VolumeMountStatus) error {\n\t\t\t\t\t\t\tvms.Metadata().Labels().Set(\"mount-status-id\", mountStatus.Metadata().ID())\n\t\t\t\t\t\t\tvms.TypedSpec().Requester = requester\n\t\t\t\t\t\t\tvms.TypedSpec().Target = mountStatus.TypedSpec().Target\n\t\t\t\t\t\t\tvms.TypedSpec().VolumeID = mountStatus.TypedSpec().Spec.VolumeID\n\t\t\t\t\t\t\tvms.TypedSpec().ReadOnly = mountStatus.TypedSpec().Spec.ReadOnly\n\t\t\t\t\t\t\tvms.TypedSpec().Detached = mountStatus.TypedSpec().Detached\n\t\t\t\t\t\t\tvms.TypedSpec().DisableAccessTime = mountStatus.TypedSpec().Spec.DisableAccessTime\n\t\t\t\t\t\t\tvms.TypedSpec().Secure = mountStatus.TypedSpec().Spec.Secure\n\n\t\t\t\t\t\t\t// This needs to be set through accessor, and is not guaranteed to resolve to a valid root.\n\t\t\t\t\t\t\tvms.TypedSpec().SetRoot(mountStatus.TypedSpec().Root())\n\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to create volume mount status %q: %w\", requestID, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// now clean up volume mount statuses that do match any existing requesters\n\t\t\t\tvolumeMountStatuses, err := safe.ReaderListAll[*block.VolumeMountStatus](ctx, r, state.WithLabelQuery(resource.LabelEqual(\"mount-status-id\", mountStatus.Metadata().ID())))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to read volume mount statuses for mount status %q: %w\", mountStatus.Metadata().ID(), err)\n\t\t\t\t}\n\n\t\t\t\tfor volumeMountStatus := range volumeMountStatuses.All() {\n\t\t\t\t\tif slices.Contains(mountStatus.TypedSpec().Spec.RequesterIDs, volumeMountStatus.Metadata().ID()) {\n\t\t\t\t\t\t// still active\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tokToDestroy, err := r.Teardown(ctx, volumeMountStatus.Metadata())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to teardown volume mount status %q: %w\", volumeMountStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif okToDestroy {\n\t\t\t\t\t\tif err = r.Destroy(ctx, volumeMountStatus.Metadata()); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to destroy volume mount status %q: %w\", volumeMountStatus.Metadata().ID(), err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase resource.PhaseTearingDown:\n\t\t\t\t// we need to ensure that all volume mount statuses are torn down and destroyed\n\t\t\t\tvolumeMountStatus, err := safe.ReaderListAll[*block.VolumeMountStatus](ctx, r, state.WithLabelQuery(resource.LabelEqual(\"mount-status-id\", mountStatus.Metadata().ID())))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to read volume mount statuses for mount status %q: %w\", mountStatus.Metadata().ID(), err)\n\t\t\t\t}\n\n\t\t\t\tallDestroyed := true\n\n\t\t\t\tfor volumeMountStatus := range volumeMountStatus.All() {\n\t\t\t\t\tokToDestroy, err := r.Teardown(ctx, volumeMountStatus.Metadata())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to teardown volume mount status %q: %w\", volumeMountStatus.Metadata().ID(), err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif okToDestroy {\n\t\t\t\t\t\tif err = r.Destroy(ctx, volumeMountStatus.Metadata()); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to destroy volume mount status %q: %w\", volumeMountStatus.Metadata().ID(), err)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tallDestroyed = false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif allDestroyed {\n\t\t\t\t\t// remove our finalizer now\n\t\t\t\t\tif mountStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\t\tif err = r.RemoveFinalizer(ctx, mountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer from mount status %q: %w\", mountStatus.Metadata().ID(), err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype MountStatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestMountStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &MountStatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.MountStatusController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *MountStatusSuite) TestReconcile() {\n\tmountStatus1 := block.NewMountStatus(block.NamespaceName, \"volume1\")\n\tmountStatus1.TypedSpec().Spec = block.MountRequestSpec{\n\t\tVolumeID:     \"volume1\",\n\t\tRequesters:   []string{\"requester1\", \"requester2\"},\n\t\tRequesterIDs: []string{\"requester1/volume1\", \"requester2/volume1\"},\n\t}\n\tmountStatus1.TypedSpec().Target = \"/target\"\n\tsuite.Create(mountStatus1)\n\n\t// mount status is exploded into volume mount statuses\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"requester1/volume1\", \"requester2/volume1\"},\n\t\tfunc(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"volume1\", vms.Metadata().Labels().Raw()[\"mount-status-id\"])\n\t\t\tasrt.Equal(\"volume1\", vms.TypedSpec().VolumeID)\n\t\t\tasrt.Equal(\"/target\", vms.TypedSpec().Target)\n\t\t},\n\t)\n\n\t// mount status should now have a finalizer\n\tctest.AssertResource(suite, \"volume1\", func(ms *block.MountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(ms.Metadata().Finalizers().Has((&blockctrls.MountStatusController{}).Name()))\n\t})\n\n\t// add a finalizer for volume mount status\n\tsuite.AddFinalizer(block.NewVolumeMountStatus(block.NamespaceName, \"requester1/volume1\").Metadata(), \"test-finalizer\")\n\n\t// now, teardown the mount status\n\tready, err := suite.State().Teardown(suite.Ctx(), mountStatus1.Metadata())\n\tsuite.Require().NoError(err)\n\tsuite.Assert().False(ready)\n\n\t// volume mount status without finalizer should be removed\n\tctest.AssertNoResource[*block.VolumeMountStatus](suite, \"requester2/volume1\")\n\n\t// volume mount status with finalizer should be tearing down\n\tctest.AssertResource(suite, \"requester1/volume1\", func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(resource.PhaseTearingDown, vms.Metadata().Phase())\n\t})\n\n\t// remove finalizer from volume mount status\n\tsuite.RemoveFinalizer(block.NewVolumeMountStatus(block.NamespaceName, \"requester1/volume1\").Metadata(), \"test-finalizer\")\n\n\t// volume mount status should be destroyed\n\tctest.AssertNoResource[*block.VolumeMountStatus](suite, \"requester1/volume1\")\n\n\t// now the mount status finalizers should be empty as well\n\tctest.AssertResource(suite, \"volume1\", func(ms *block.MountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(ms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(mountStatus1)\n}\n\nfunc (suite *MountStatusSuite) TestReconcileRequesterGoingOut() {\n\tmountStatus1 := block.NewMountStatus(block.NamespaceName, \"volume1\")\n\tmountStatus1.TypedSpec().Spec = block.MountRequestSpec{\n\t\tVolumeID:     \"volume1\",\n\t\tRequesters:   []string{\"requester1\", \"requester2\"},\n\t\tRequesterIDs: []string{\"requester1/volume1\", \"requester2/volume1\"},\n\t}\n\tmountStatus1.TypedSpec().Target = \"/target\"\n\tsuite.Create(mountStatus1)\n\n\t// mount status is exploded into volume mount statuses\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"requester1/volume1\", \"requester2/volume1\"},\n\t\tfunc(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"volume1\", vms.Metadata().Labels().Raw()[\"mount-status-id\"])\n\t\t\tasrt.Equal(\"volume1\", vms.TypedSpec().VolumeID)\n\t\t\tasrt.Equal(\"/target\", vms.TypedSpec().Target)\n\t\t},\n\t)\n\n\t// put a finalizer on volume mount status\n\tsuite.AddFinalizer(block.NewVolumeMountStatus(block.NamespaceName, \"requester1/volume1\").Metadata(), \"test-finalizer\")\n\n\t// update the mount status, as if requester1 is no longer mounting it\n\tmountStatus1, err := safe.StateGetByID[*block.MountStatus](suite.Ctx(), suite.State(), mountStatus1.Metadata().ID())\n\tsuite.Require().NoError(err)\n\n\tmountStatus1.TypedSpec().Spec.Requesters = []string{\"requester2\"}\n\tmountStatus1.TypedSpec().Spec.RequesterIDs = []string{\"requester2/volume1\"}\n\tsuite.Update(mountStatus1)\n\n\t// volume mount status with finalizer should be tearing down\n\tctest.AssertResource(suite, \"requester1/volume1\", func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(resource.PhaseTearingDown, vms.Metadata().Phase())\n\t})\n\n\t// remove finalizer from volume mount status\n\tsuite.RemoveFinalizer(block.NewVolumeMountStatus(block.NamespaceName, \"requester1/volume1\").Metadata(), \"test-finalizer\")\n\n\t// volume mount status should be destroyed\n\tctest.AssertNoResource[*block.VolumeMountStatus](suite, \"requester1/volume1\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/mount_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype MountSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestMountSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &MountSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.MountController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *MountSuite) mountVolume(volumeID string) { //nolint:unparam\n\tmountRequest := block.NewMountRequest(block.NamespaceName, volumeID)\n\tmountRequest.TypedSpec().RequesterIDs = []string{\"requester1/\" + volumeID}\n\tmountRequest.TypedSpec().Requesters = []string{\"requester1\"}\n\tmountRequest.TypedSpec().VolumeID = volumeID\n\tsuite.Create(mountRequest)\n\n\t// wait for the mount status to be created\n\tctest.AssertResource(suite, volumeID, func(*block.MountStatus, *assert.Assertions) {})\n}\n\nfunc (suite *MountSuite) TestSymlinkNew() {\n\tdir := suite.T().TempDir()\n\ttargetPath := filepath.Join(dir, \"target\")\n\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, \"volume1\")\n\tvolumeStatus.TypedSpec().Type = block.VolumeTypeSymlink\n\tvolumeStatus.TypedSpec().SymlinkSpec = block.SymlinkProvisioningSpec{\n\t\tSymlinkTargetPath: \"/run\",\n\t\tForce:             true,\n\t}\n\tvolumeStatus.TypedSpec().MountSpec = block.MountSpec{\n\t\tTargetPath: targetPath,\n\t}\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Create(volumeStatus)\n\n\tsuite.mountVolume(\"volume1\")\n\n\t// verify symlink\n\tpath, err := os.Readlink(targetPath)\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(\"/run\", path)\n}\n\nfunc (suite *MountSuite) TestSymlinkExists() {\n\tdir := suite.T().TempDir()\n\ttargetPath := filepath.Join(dir, \"target\")\n\n\t// symlink already exists\n\tsuite.Require().NoError(os.Symlink(\"/run\", targetPath))\n\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, \"volume1\")\n\tvolumeStatus.TypedSpec().Type = block.VolumeTypeSymlink\n\tvolumeStatus.TypedSpec().SymlinkSpec = block.SymlinkProvisioningSpec{\n\t\tSymlinkTargetPath: \"/run\",\n\t}\n\tvolumeStatus.TypedSpec().MountSpec = block.MountSpec{\n\t\tTargetPath: targetPath,\n\t}\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Create(volumeStatus)\n\n\tsuite.mountVolume(\"volume1\")\n\n\t// verify symlink\n\tpath, err := os.Readlink(targetPath)\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(\"/run\", path)\n}\n\nfunc (suite *MountSuite) TestSymlinkWrong() {\n\tdir := suite.T().TempDir()\n\ttargetPath := filepath.Join(dir, \"target\")\n\n\t// wrong symlink target\n\tsuite.Require().NoError(os.Symlink(\"/foo\", targetPath))\n\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, \"volume1\")\n\tvolumeStatus.TypedSpec().Type = block.VolumeTypeSymlink\n\tvolumeStatus.TypedSpec().SymlinkSpec = block.SymlinkProvisioningSpec{\n\t\tSymlinkTargetPath: \"/run\",\n\t\tForce:             true,\n\t}\n\tvolumeStatus.TypedSpec().MountSpec = block.MountSpec{\n\t\tTargetPath: targetPath,\n\t}\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Create(volumeStatus)\n\n\tsuite.mountVolume(\"volume1\")\n\n\t// verify symlink\n\tpath, err := os.Readlink(targetPath)\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(\"/run\", path)\n}\n\nfunc (suite *MountSuite) TestSymlinkDirectory() {\n\tdir := suite.T().TempDir()\n\ttargetPath := filepath.Join(dir, \"target\")\n\n\t// non-empty directory structure\n\tsuite.Require().NoError(os.Mkdir(targetPath, 0o755))\n\tsuite.Require().NoError(os.Mkdir(filepath.Join(targetPath, \"foo\"), 0o755))\n\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, \"volume1\")\n\tvolumeStatus.TypedSpec().Type = block.VolumeTypeSymlink\n\tvolumeStatus.TypedSpec().SymlinkSpec = block.SymlinkProvisioningSpec{\n\t\tSymlinkTargetPath: \"/run\",\n\t\tForce:             true,\n\t}\n\tvolumeStatus.TypedSpec().MountSpec = block.MountSpec{\n\t\tTargetPath: targetPath,\n\t}\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Create(volumeStatus)\n\n\tsuite.mountVolume(\"volume1\")\n\n\t// verify symlink\n\tpath, err := os.Readlink(targetPath)\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Equal(\"/run\", path)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/swap_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/dustin/go-humanize\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// SwapStatusController provides a view of active swap devices.\ntype SwapStatusController struct {\n\tV1Alpha1Mode  machineruntime.Mode\n\tProcSwapsPath string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SwapStatusController) Name() string {\n\treturn \"block.SwapStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SwapStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\t// not really a dependency, but we refresh swap status on mount status change\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SwapStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.SwapStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *SwapStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// in container mode, no swap applies\n\tif ctrl.V1Alpha1Mode == machineruntime.ModeContainer {\n\t\treturn nil\n\t}\n\n\tif ctrl.ProcSwapsPath == \"\" {\n\t\tctrl.ProcSwapsPath = \"/proc/swaps\"\n\t}\n\n\t// there is no way to watch for swap devices, so we are going to poll every minute\n\tticker := time.NewTicker(time.Minute)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif err := ctrl.parseSwaps(ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse swaps: %w\", err)\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*block.SwapStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *SwapStatusController) parseSwaps(ctx context.Context, r controller.ReaderWriter) error {\n\tswapsContent, err := os.ReadFile(ctrl.ProcSwapsPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read %q: %w\", ctrl.ProcSwapsPath, err)\n\t}\n\n\tscanner := bufio.NewScanner(bytes.NewReader(swapsContent))\n\n\t// skip the first line, it contains headers\n\tif !scanner.Scan() {\n\t\treturn fmt.Errorf(\"failed to read header line from %q: %w\", ctrl.ProcSwapsPath, scanner.Err())\n\t}\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tfields := strings.Fields(line)\n\t\tif len(fields) < 5 {\n\t\t\treturn fmt.Errorf(\"invalid swap line in %q: %q\", ctrl.ProcSwapsPath, line)\n\t\t}\n\n\t\tswapDevice := fields[0]\n\n\t\tif err = safe.WriterModify(ctx, r, block.NewSwapStatus(block.NamespaceName, swapDevice),\n\t\t\tfunc(swapStatus *block.SwapStatus) error {\n\t\t\t\tswapStatus.TypedSpec().Device = swapDevice\n\t\t\t\tswapStatus.TypedSpec().Type = fields[1]\n\n\t\t\t\tsize, err := strconv.ParseUint(fields[2], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse size from %q: %w\", fields[2], err)\n\t\t\t\t}\n\n\t\t\t\tswapStatus.TypedSpec().SizeBytes = size * 1024 // convert from KiB to bytes\n\n\t\t\t\tused, err := strconv.ParseUint(fields[3], 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse used from %q: %w\", fields[3], err)\n\t\t\t\t}\n\n\t\t\t\tswapStatus.TypedSpec().UsedBytes = used * 1024 // convert from KiB to bytes\n\n\t\t\t\tswapStatus.TypedSpec().SizeHuman = humanize.IBytes(swapStatus.TypedSpec().SizeBytes)\n\t\t\t\tswapStatus.TypedSpec().UsedHuman = humanize.IBytes(swapStatus.TypedSpec().UsedBytes)\n\n\t\t\t\tpriority, err := strconv.ParseInt(fields[4], 10, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to parse priority from %q: %w\", fields[4], err)\n\t\t\t\t}\n\n\t\t\t\tswapStatus.TypedSpec().Priority = int32(priority)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to modify swap status for %q: %w\", swapDevice, err)\n\t\t}\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn fmt.Errorf(\"failed to read swaps from %q: %w\", ctrl.ProcSwapsPath, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/swap_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t_ \"embed\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype SwapStatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestSwapStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &SwapStatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout:    3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {},\n\t\t},\n\t})\n}\n\n//go:embed \"testdata/procswaps.txt\"\nvar procSwapsData []byte\n\nfunc (suite *SwapStatusSuite) TestReconcile() {\n\ttmpDir := suite.T().TempDir()\n\tpath := filepath.Join(tmpDir, \"procswaps.txt\")\n\n\tsuite.Require().NoError(os.WriteFile(path, procSwapsData, 0o644))\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.SwapStatusController{\n\t\tProcSwapsPath: path,\n\t}))\n\n\tctest.AssertResources(suite, []string{\"/dev/vda1\", \"/dev/vda2\"}, func(s *block.SwapStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"partition\", s.TypedSpec().Type)\n\n\t\tswitch s.Metadata().ID() {\n\t\tcase \"/dev/vda1\":\n\t\t\tasrt.Equal(\"/dev/vda1\", s.TypedSpec().Device)\n\t\t\tasrt.EqualValues(524280*1024, s.TypedSpec().SizeBytes)\n\t\t\tasrt.Equal(\"512 MiB\", s.TypedSpec().SizeHuman)\n\t\t\tasrt.EqualValues(1024*1024, s.TypedSpec().UsedBytes)\n\t\t\tasrt.Equal(\"1.0 MiB\", s.TypedSpec().UsedHuman)\n\t\t\tasrt.EqualValues(-1, s.TypedSpec().Priority)\n\t\tcase \"/dev/vda2\":\n\t\t\tasrt.Equal(\"/dev/vda2\", s.TypedSpec().Device)\n\t\t\tasrt.EqualValues(2*1024*1024, s.TypedSpec().SizeBytes)\n\t\t\tasrt.Equal(\"2.0 MiB\", s.TypedSpec().SizeHuman)\n\t\t\tasrt.EqualValues(0, s.TypedSpec().UsedBytes)\n\t\t\tasrt.Equal(\"0 B\", s.TypedSpec().UsedHuman)\n\t\t\tasrt.EqualValues(-2, s.TypedSpec().Priority)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/symlinks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/inotify\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// SymlinksController provides a view of symlinks created by udevd to the blockdevices.\ntype SymlinksController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SymlinksController) Name() string {\n\treturn \"block.SymlinksController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SymlinksController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"udevd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SymlinksController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.SymlinkType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nconst (\n\tbaseDevDiskPath   = \"/dev/disk\"\n\ttempSymlinkPrefix = \".#\"\n)\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *SymlinksController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy & running\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tudevdService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"udevd\")\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get udevd service: %w\", err)\n\t\t}\n\n\t\tif udevdService.TypedSpec().Healthy && udevdService.TypedSpec().Running {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// start the inotify watcher\n\tinotifyWatcher, err := inotify.NewWatcher()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create inotify watcher: %w\", err)\n\t}\n\n\tdefer inotifyWatcher.Close() //nolint:errcheck\n\n\tinotifyCh, inotifyErrCh := inotifyWatcher.Run()\n\n\t// build initial list of symlinks\n\t//\n\t// map of path -> destination\n\tdetectedSymlinks := map[string]string{}\n\n\t// get list of subpaths under /dev/disk\n\tif err = ctrl.handleDir(logger, inotifyWatcher, detectedSymlinks, baseDevDiskPath); err != nil {\n\t\treturn err\n\t}\n\n\tif err = ctrl.updateOutputs(ctx, r, detectedSymlinks); err != nil {\n\t\treturn err\n\t}\n\n\t// now wait for inotify events\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase updatedPath := <-inotifyCh:\n\t\t\tlogger.Debug(\"inotify event\", zap.String(\"path\", updatedPath))\n\n\t\t\tst, err := os.Stat(updatedPath)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\tdelete(detectedSymlinks, updatedPath)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"failed to stat %q: %w\", updatedPath, err)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif st.IsDir() {\n\t\t\t\t\tif err = ctrl.handleDir(logger, inotifyWatcher, detectedSymlinks, updatedPath); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdest, err := os.Readlink(updatedPath)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif errors.Is(err, fs.ErrNotExist) || errors.Is(err, unix.EINVAL) {\n\t\t\t\t\t\t\tdelete(detectedSymlinks, updatedPath)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to readlink %q: %w\", updatedPath, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if !strings.HasPrefix(filepath.Base(updatedPath), tempSymlinkPrefix) {\n\t\t\t\t\t\tdetectedSymlinks[updatedPath] = dest\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase watchErr := <-inotifyErrCh:\n\t\t\treturn fmt.Errorf(\"inotify watcher failed: %w\", watchErr)\n\t\t}\n\n\t\tif err = ctrl.updateOutputs(ctx, r, detectedSymlinks); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (ctrl *SymlinksController) updateOutputs(ctx context.Context, r controller.Runtime, detectedSymlinks map[string]string) error {\n\tr.StartTrackingOutputs()\n\n\tdeviceToSymlinks := map[string][]string{}\n\n\tfor path, dest := range detectedSymlinks {\n\t\tdevicePath := filepath.Base(dest)\n\n\t\tdeviceToSymlinks[devicePath] = append(deviceToSymlinks[devicePath], path)\n\t}\n\n\tfor devicePath := range deviceToSymlinks {\n\t\tslices.Sort(deviceToSymlinks[devicePath])\n\t}\n\n\tfor devicePath, symlinks := range deviceToSymlinks {\n\t\tif err := safe.WriterModify(ctx, r, block.NewSymlink(block.NamespaceName, devicePath), func(symlink *block.Symlink) error {\n\t\t\tsymlink.TypedSpec().Paths = symlinks\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update symlink %q: %w\", devicePath, err)\n\t\t}\n\t}\n\n\treturn safe.CleanupOutputs[*block.Symlink](ctx, r)\n}\n\n//nolint:gocyclo\nfunc (ctrl *SymlinksController) handleDir(logger *zap.Logger, inotifyWatcher *inotify.Watcher, detectedSymlinks map[string]string, path string) error {\n\tif err := inotifyWatcher.Add(path, unix.IN_CREATE|unix.IN_DELETE|unix.IN_MOVE); err != nil {\n\t\tlogger.Debug(\"failed to add inotify watch\", zap.String(\"path\", path), zap.Error(err))\n\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"failed to add inotify watch for %q: %w\", path, err)\n\t\t}\n\t}\n\n\tlogger.Debug(\"processing directory\", zap.String(\"path\", path))\n\n\tentries, err := os.ReadDir(path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to read directory %q: %w\", path, err)\n\t}\n\n\tfor _, entry := range entries {\n\t\tfullPath := filepath.Join(path, entry.Name())\n\n\t\tst, err := os.Stat(fullPath)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to stat %q: %w\", fullPath, err)\n\t\t}\n\n\t\tif st.IsDir() {\n\t\t\tif err = ctrl.handleDir(logger, inotifyWatcher, detectedSymlinks, fullPath); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tdest, err := os.Readlink(fullPath)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, fs.ErrNotExist) || errors.Is(err, unix.EINVAL) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn fmt.Errorf(\"failed to readlink %q: %w\", fullPath, err)\n\t\t\t}\n\n\t\t\tif !strings.HasPrefix(entry.Name(), tempSymlinkPrefix) {\n\t\t\t\tdetectedSymlinks[fullPath] = dest\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/system_disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// SystemDiskController provides a detailed view of blockdevices of type 'disk'.\ntype SystemDiskController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SystemDiskController) Name() string {\n\treturn \"block.SystemDiskController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SystemDiskController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiscoveredVolumeType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SystemDiskController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.SystemDiskType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *SystemDiskController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tdiscoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to list discovered volumes: %w\", err)\n\t\t}\n\n\t\tvar (\n\t\t\tsystemDiskID   string\n\t\t\tsystemDiskPath string\n\t\t)\n\n\t\tfor volume := range discoveredVolumes.All() {\n\t\t\tif volume.TypedSpec().PartitionLabel == constants.MetaPartitionLabel {\n\t\t\t\tsystemDiskID = volume.TypedSpec().Parent\n\t\t\t\tsystemDiskPath = volume.TypedSpec().ParentDevPath\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif systemDiskID != \"\" {\n\t\t\tif err = safe.WriterModify(ctx, r, block.NewSystemDisk(block.NamespaceName, block.SystemDiskID), func(d *block.SystemDisk) error {\n\t\t\t\td.TypedSpec().DiskID = systemDiskID\n\t\t\t\td.TypedSpec().DevPath = systemDiskPath\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write system disk: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err = r.Destroy(ctx, block.NewSystemDisk(block.NamespaceName, block.SystemDiskID).Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to destroy system disk: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/system_disk_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\ntype SystemDiskSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestSystemDiskSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &SystemDiskSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.SystemDiskController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *SystemDiskSuite) TestReconcile() {\n\tctest.AssertNoResource[*block.SystemDisk](suite, block.SystemDiskID)\n\n\tdiscoveredVolume := block.NewDiscoveredVolume(block.NamespaceName, \"vda4\")\n\tdiscoveredVolume.TypedSpec().PartitionLabel = constants.MetaPartitionLabel\n\tdiscoveredVolume.TypedSpec().Parent = \"vda\"\n\tdiscoveredVolume.TypedSpec().ParentDevPath = \"/dev/vda\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), discoveredVolume))\n\n\tctest.AssertResource(suite, block.SystemDiskID, func(r *block.SystemDisk, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"vda\", r.TypedSpec().DiskID)\n\t\tasrt.Equal(\"/dev/vda\", r.TypedSpec().DevPath)\n\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), discoveredVolume.Metadata()))\n\n\tctest.AssertNoResource[*block.SystemDisk](suite, block.SystemDiskID)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/testdata/procswaps.txt",
    "content": "Filename                          Type        Size     Used    Priority\n/dev/vda1                         partition   524280   1024      -1\n/dev/vda2                         partition   2048     0         -2\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/user_disk_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tmachineconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// UserDiskConfigController provides volume configuration based on Talos v1alpha1 user disks.\ntype UserDiskConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *UserDiskConfigController) Name() string {\n\treturn \"block.UserDiskConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *UserDiskConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *UserDiskConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeConfigType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.UserDiskConfigStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nfunc diskPathMatch(devicePath string) cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"disk.dev_path == '%s'\", devicePath), celenv.DiskLocator()))\n}\n\nfunc partitionIdxMatch(devicePath string, partitionIdx int) cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf(\"volume.parent_dev_path == '%s' && volume.partition_index == %du\", devicePath, partitionIdx), celenv.VolumeLocator()))\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *UserDiskConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching machine configuration\")\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tconfigurationPresent := cfg != nil && cfg.Config().Machine() != nil\n\n\t\tstatus := block.NewUserDiskConfigStatus(block.NamespaceName, block.UserDiskConfigStatusID)\n\t\tstatus.TypedSpec().Ready = configurationPresent\n\t\tstatus.TypedSpec().TornDown = true\n\n\t\tif configurationPresent {\n\t\t\t// user disks\n\t\t\tfor _, disk := range cfg.Config().Machine().Disks() {\n\t\t\t\tresult, err := ctrl.processUserDisk(ctx, r, disk)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error processing user disk %s: %w\", disk.Device(), err)\n\t\t\t\t}\n\n\t\t\t\tstatus.TypedSpec().Ready = status.TypedSpec().Ready && result.ready\n\t\t\t\tstatus.TypedSpec().TornDown = status.TypedSpec().TornDown && result.tornDown\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*block.VolumeConfig](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up volume configuration: %w\", err)\n\t\t}\n\n\t\tif configurationPresent {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\tblock.NewUserDiskConfigStatus(block.NamespaceName, block.UserDiskConfigStatusID),\n\t\t\t\tfunc(udcs *block.UserDiskConfigStatus) error {\n\t\t\t\t\t*udcs.TypedSpec() = *status.TypedSpec()\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating user disk configuration status: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n\ntype userDiskResult struct {\n\tready    bool\n\ttornDown bool\n}\n\nfunc (ctrl *UserDiskConfigController) processUserDisk(ctx context.Context, r controller.ReaderWriter, disk machineconfig.Disk) (*userDiskResult, error) {\n\tdevice := disk.Device()\n\n\tresolvedDevicePath, err := filepath.EvalSymlinks(device)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error resolving device path: %w\", err)\n\t}\n\n\toverallResult := &userDiskResult{\n\t\tready:    true,\n\t\ttornDown: true,\n\t}\n\n\tfor idx, part := range disk.Partitions() {\n\t\tresult, err := ctrl.processUserDiskPartition(ctx, r, device, idx, part, resolvedDevicePath)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error processing user disk partition %s: %w\", part.MountPoint(), err)\n\t\t}\n\n\t\toverallResult.ready = overallResult.ready && result.ready\n\t\toverallResult.tornDown = overallResult.tornDown && result.tornDown\n\t}\n\n\treturn overallResult, nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *UserDiskConfigController) processUserDiskPartition(\n\tctx context.Context, r controller.ReaderWriter, device string, idx int, part machineconfig.Partition, resolvedDevicePath string,\n) (*userDiskResult, error) {\n\tid := fmt.Sprintf(\"%s-%d\", device, idx+1)\n\n\t// volume configuration\n\tif err := safe.WriterModify(ctx, r,\n\t\tblock.NewVolumeConfig(block.NamespaceName, id),\n\t\tfunc(vc *block.VolumeConfig) error {\n\t\t\tvc.Metadata().Labels().Set(block.UserDiskLabel, \"\")\n\n\t\t\tvc.TypedSpec().Type = block.VolumeTypePartition\n\n\t\t\tvc.TypedSpec().Provisioning = block.ProvisioningSpec{\n\t\t\t\t// it's crucial to keep the order of provisioning locked within each disk, otherwise\n\t\t\t\t// provisioning might order them different way, and create partitions in wrong order\n\t\t\t\t// the matcher on partition idx would then discover partitions in wrong order, and mount them\n\t\t\t\t// in wrong order\n\t\t\t\tWave: block.WaveLegacyUserDisks + idx,\n\t\t\t\tDiskSelector: block.DiskSelector{\n\t\t\t\t\tMatch: diskPathMatch(resolvedDevicePath),\n\t\t\t\t},\n\t\t\t\tPartitionSpec: block.PartitionSpec{\n\t\t\t\t\tMinSize:  part.Size(),\n\t\t\t\t\tMaxSize:  part.Size(),\n\t\t\t\t\tTypeUUID: partition.LinuxFilesystemData,\n\t\t\t\t},\n\t\t\t\tFilesystemSpec: block.FilesystemSpec{\n\t\t\t\t\tType: block.FilesystemTypeXFS,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tvc.TypedSpec().Locator = block.LocatorSpec{\n\t\t\t\tMatch: partitionIdxMatch(resolvedDevicePath, idx+1),\n\t\t\t}\n\n\t\t\ttargetPath := part.MountPoint()\n\t\t\tparentID := \"\"\n\n\t\t\t// machine configuration doesn't enforce any specific mount point for user disks,\n\t\t\t// so we don't do any more thorough validation here\n\t\t\tif strings.HasPrefix(targetPath, \"/var/\") {\n\t\t\t\tparentID = constants.EphemeralPartitionLabel\n\t\t\t\ttargetPath = strings.TrimPrefix(targetPath, \"/var/\")\n\t\t\t}\n\n\t\t\tvc.TypedSpec().Mount = block.MountSpec{\n\t\t\t\tTargetPath:   targetPath,\n\t\t\t\tParentID:     parentID,\n\t\t\t\tSelinuxLabel: constants.EphemeralSelinuxLabel,\n\t\t\t\tFileMode:     0o755,\n\t\t\t\tUID:          0,\n\t\t\t\tGID:          0,\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating user disk volume configuration: %w\", err)\n\t}\n\n\t// figure out if we want to create the mount of to tear it down\n\tvolumeMountStatus, err := safe.ReaderGetByID[*block.VolumeMountStatus](ctx, r, id)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, fmt.Errorf(\"error fetching volume mount status: %w\", err)\n\t}\n\n\tvolumeMountRequest, err := safe.ReaderGetByID[*block.VolumeMountRequest](ctx, r, id)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, fmt.Errorf(\"error fetching volume mount request: %w\", err)\n\t}\n\n\tshouldTearDown := (volumeMountStatus != nil && volumeMountStatus.Metadata().Phase() == resource.PhaseTearingDown) ||\n\t\t(volumeMountRequest != nil && volumeMountRequest.Metadata().Phase() == resource.PhaseTearingDown)\n\n\tif !shouldTearDown {\n\t\t// create volume mount request\n\t\tif err = safe.WriterModify(ctx, r,\n\t\t\tblock.NewVolumeMountRequest(block.NamespaceName, id),\n\t\t\tfunc(vmr *block.VolumeMountRequest) error {\n\t\t\t\tvmr.TypedSpec().Requester = ctrl.Name()\n\t\t\t\tvmr.TypedSpec().VolumeID = id\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating volume mount request: %w\", err)\n\t\t}\n\n\t\tif volumeMountStatus == nil {\n\t\t\t// not mounted yet\n\t\t\treturn &userDiskResult{}, nil\n\t\t}\n\n\t\tif !volumeMountStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\tif err = r.AddFinalizer(ctx, volumeMountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error adding finalizer to volume mount status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// ready\n\t\treturn &userDiskResult{\n\t\t\tready: true,\n\t\t}, nil\n\t}\n\n\t// tear down volume mount request\n\tif volumeMountStatus != nil && volumeMountStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\tif err = r.RemoveFinalizer(ctx, volumeMountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error removing finalizer from volume mount status: %w\", err)\n\t\t}\n\t}\n\n\tif volumeMountRequest == nil {\n\t\t// already torn down\n\t\treturn &userDiskResult{\n\t\t\ttornDown: true,\n\t\t}, nil\n\t}\n\n\tokToDestroy, err := r.Teardown(ctx, volumeMountRequest.Metadata())\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn &userDiskResult{\n\t\t\t\ttornDown: true,\n\t\t\t}, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error tearing down volume mount request: %w\", err)\n\t}\n\n\tif !okToDestroy {\n\t\treturn &userDiskResult{}, nil\n\t}\n\n\tif err = r.Destroy(ctx, volumeMountRequest.Metadata()); err != nil {\n\t\treturn nil, fmt.Errorf(\"error destroying volume mount request: %w\", err)\n\t}\n\n\treturn &userDiskResult{\n\t\ttornDown: true,\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/user_disk_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\ntype UserDiskConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestUserDiskConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &UserDiskConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&blockctrls.UserDiskConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *UserDiskConfigSuite) TestReconcileDefaults() {\n\tctest.AssertNoResource[*block.UserDiskConfigStatus](suite, block.UserDiskConfigStatusID)\n\n\t// create a dummy machine config\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// now the volume config should be created\n\tctest.AssertResource(suite, block.UserDiskConfigStatusID, func(r *block.UserDiskConfigStatus, asrt *assert.Assertions) {\n\t\tasrt.True(r.TypedSpec().Ready)\n\t})\n}\n\nfunc (suite *UserDiskConfigSuite) TestReconcileUserDisk() {\n\tctest.AssertNoResource[*block.UserDiskConfigStatus](suite, block.UserDiskConfigStatusID)\n\n\tdir := suite.T().TempDir()\n\n\tdisk1, disk2 := filepath.Join(dir, \"disk1\"), filepath.Join(dir, \"disk2\")\n\n\tsuite.Require().NoError(os.WriteFile(disk1, nil, 0o644))\n\tsuite.Require().NoError(os.WriteFile(disk2, nil, 0o644))\n\n\t// create a machine config with user disks\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineDisks: []*v1alpha1.MachineDisk{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDeviceName: disk1,\n\t\t\t\t\t\t\tDiskPartitions: []*v1alpha1.DiskPartition{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tDiskSize:       1024 * 1024,\n\t\t\t\t\t\t\t\t\tDiskMountPoint: \"/var/1-1\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tDiskSize:       1024 * 1024,\n\t\t\t\t\t\t\t\t\tDiskMountPoint: \"/var/1-2\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDeviceName: disk2,\n\t\t\t\t\t\t\tDiskPartitions: []*v1alpha1.DiskPartition{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tDiskSize:       1024 * 1024,\n\t\t\t\t\t\t\t\t\tDiskMountPoint: \"/var/2-1\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// now the volume config should be created\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tctest.AssertResource(suite, id, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\t\t\tasrt.Contains(r.Metadata().Labels().Raw(), block.UserDiskLabel)\n\t\t\tasrt.GreaterOrEqual(r.TypedSpec().Provisioning.Wave, block.WaveLegacyUserDisks)\n\t\t\tasrt.Equal(constants.EphemeralPartitionLabel, r.TypedSpec().Mount.ParentID)\n\t\t\tasrt.NotContains(r.TypedSpec().Mount.TargetPath, \"/\") // path should become relative\n\t\t})\n\t}\n\n\t// .. and a volume mount request\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tctest.AssertResource(suite, id, func(r *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(id, r.TypedSpec().VolumeID)\n\t\t})\n\t}\n\n\t// the status should not be ready (yet)\n\tctest.AssertResource(suite, block.UserDiskConfigStatusID, func(r *block.UserDiskConfigStatus, asrt *assert.Assertions) {\n\t\tasrt.False(r.TypedSpec().Ready)\n\t})\n\n\t// now emulate that the mount requests are fulfilled\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, id)\n\t\tsuite.Create(volumeMountStatus)\n\n\t\tsuite.AddFinalizer(block.NewVolumeMountRequest(block.NamespaceName, id).Metadata(), \"test\")\n\t}\n\n\t// the controller should put a finalizer on the mount status\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tctest.AssertResource(suite, id, func(r *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.Metadata().Finalizers().Has((&blockctrls.UserDiskConfigController{}).Name()))\n\t\t})\n\t}\n\n\t// now everything should be ready\n\tctest.AssertResource(suite, block.UserDiskConfigStatusID, func(r *block.UserDiskConfigStatus, asrt *assert.Assertions) {\n\t\tasrt.True(r.TypedSpec().Ready)\n\t\tasrt.False(r.TypedSpec().TornDown)\n\t})\n\n\t// start tearing down volume mount status\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\t_, err := suite.State().Teardown(suite.Ctx(), block.NewVolumeMountStatus(block.NamespaceName, id).Metadata())\n\t\tsuite.Require().NoError(err)\n\t}\n\n\t// back to not ready\n\tctest.AssertResource(suite, block.UserDiskConfigStatusID, func(r *block.UserDiskConfigStatus, asrt *assert.Assertions) {\n\t\tasrt.False(r.TypedSpec().Ready)\n\t\tasrt.False(r.TypedSpec().TornDown)\n\t})\n\n\t// the finalizers on mount statuses should be removed\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tctest.AssertResource(suite, id, func(r *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.Metadata().Finalizers().Empty())\n\t\t})\n\t}\n\n\t// remove the finalizer from the mount request\n\tfor _, id := range []string{disk1 + \"-1\", disk1 + \"-2\", disk2 + \"-1\"} {\n\t\tsuite.RemoveFinalizer(block.NewVolumeMountRequest(block.NamespaceName, id).Metadata(), \"test\")\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes/volumeconfig\"\n\tmachinedruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// VolumeConfigController provides volume configuration based on Talos defaults and machine configuration.\ntype VolumeConfigController struct {\n\tV1Alpha1Mode machinedruntime.Mode\n\tMetaProvider volumeconfig.MetaProvider\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *VolumeConfigController) Name() string {\n\treturn \"block.VolumeConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *VolumeConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MetaKeyType,\n\t\t\tID:        optional.Some(runtime.MetaKeyTagToID(meta.StateEncryptionConfig)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeConfigType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *VolumeConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeConfigType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *VolumeConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { //nolint:gocyclo\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\t// create a volume mount request for the root user volume mount point\n\t\t// to keep it alive and prevent it from being torn down\n\t\tif err := safe.WriterModify(ctx, r,\n\t\t\tblock.NewVolumeMountRequest(block.NamespaceName, constants.UserVolumeMountPoint),\n\t\t\tfunc(v *block.VolumeMountRequest) error {\n\t\t\t\tv.TypedSpec().Requester = ctrl.Name()\n\t\t\t\tv.TypedSpec().VolumeID = constants.UserVolumeMountPoint\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating volume mount request for user volume mount point: %w\", err)\n\t\t}\n\n\t\tmachineCfg, encryptionMeta, err := ctrl.loadConfiguration(ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar cfg configconfig.Config\n\t\tif machineCfg != nil {\n\t\t\tcfg = machineCfg.Config()\n\t\t}\n\n\t\tif err := ctrl.setupStateEncryption(ctx, logger, cfg); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttransformers := append(volumeconfig.GetSystemVolumeTransformers(ctx, encryptionMeta,\n\t\t\tctrl.V1Alpha1Mode.InContainer(), ctrl.V1Alpha1Mode.IsAgent()), volumeconfig.UserVolumeTransformers...)\n\n\t\tvar resources []volumeconfig.VolumeResource\n\n\t\tfor _, transformer := range transformers {\n\t\t\tr, err := transformer(cfg)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresources = append(resources, r...)\n\t\t}\n\n\t\tvolumeConfigsByID, volumeMountRequestsByID, err := ctrl.getExistingVolumes(ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting existing user volumes: %w\", err)\n\t\t}\n\n\t\tfor _, resource := range resources {\n\t\t\tif err := ctrl.createVolume(ctx, r, resource, volumeConfigsByID, volumeMountRequestsByID); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating volumes: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := ctrl.cleanupUnusedVolumes(ctx, r, volumeConfigsByID, volumeMountRequestsByID); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up unused volumes: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *VolumeConfigController) setupStateEncryption(ctx context.Context, l *zap.Logger, cfg configconfig.Config) error { //nolint:gocyclo\n\tif cfg == nil || cfg.Machine() == nil || ctrl.V1Alpha1Mode.InContainer() {\n\t\treturn nil\n\t}\n\n\textraVolumeConfig, _ := cfg.Volumes().ByName(constants.StatePartitionLabel)\n\n\tencryptionConfig := extraVolumeConfig.Encryption()\n\tif encryptionConfig == nil {\n\t\t// fall back to v1alpha1 encryption config\n\t\tencryptionConfig = cfg.Machine().SystemDiskEncryption().Get(constants.StatePartitionLabel)\n\t}\n\n\tmetaEncryptionConfig, err := volumes.MarshalEncryptionMeta(encryptionConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling encryption config for %s: %w\", constants.StatePartitionLabel, err)\n\t}\n\n\tprevious, ok := ctrl.MetaProvider.Meta().ReadTagBytes(meta.StateEncryptionConfig)\n\tif ok && bytes.Equal(previous, metaEncryptionConfig) {\n\t\treturn nil\n\t}\n\n\tok, err = ctrl.MetaProvider.Meta().SetTagBytes(ctx, meta.StateEncryptionConfig, metaEncryptionConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error setting meta tag %d: %w\", meta.StateEncryptionConfig, err)\n\t}\n\n\tif !ok {\n\t\treturn errors.New(\"failed to save state encryption config to meta\")\n\t}\n\n\tif err = ctrl.MetaProvider.Meta().Flush(); err != nil {\n\t\treturn fmt.Errorf(\"error flushing meta: %w\", err)\n\t}\n\n\tl.Info(\"saved state encryption config to META\")\n\n\treturn nil\n}\n\nfunc (ctrl *VolumeConfigController) loadConfiguration(ctx context.Context, r controller.Runtime) (*config.MachineConfig, *runtime.MetaKey, error) {\n\t// load config if present\n\tmachineCfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, nil, fmt.Errorf(\"error fetching machine configuration: %w\", err)\n\t}\n\n\t// load STATE encryption meta key\n\tencryptionMeta, err := safe.ReaderGetByID[*runtime.MetaKey](ctx, r, runtime.MetaKeyTagToID(meta.StateEncryptionConfig))\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, nil, fmt.Errorf(\"error fetching state encryption meta key: %w\", err)\n\t}\n\n\treturn machineCfg, encryptionMeta, nil\n}\n\nfunc (ctrl *VolumeConfigController) createVolume(\n\tctx context.Context, r controller.ReaderWriter, rsrc volumeconfig.VolumeResource,\n\tvolumeConfigsByID map[string]*block.VolumeConfig,\n\tvolumeMountRequestsByID map[string]*block.VolumeMountRequest,\n) error {\n\tvolumeConfig := volumeConfigsByID[rsrc.VolumeID]\n\tvolumeMountRequest := volumeMountRequestsByID[rsrc.VolumeID]\n\n\ttearingDown := (volumeConfig != nil && volumeConfig.Metadata().Phase() == resource.PhaseTearingDown) ||\n\t\t(volumeMountRequest != nil && volumeMountRequest.Metadata().Phase() == resource.PhaseTearingDown)\n\n\t// if the volume is being torn down, do the tear down (in the next loop)\n\tif tearingDown {\n\t\treturn nil\n\t}\n\n\tdelete(volumeConfigsByID, rsrc.VolumeID)\n\tdelete(volumeMountRequestsByID, rsrc.VolumeID)\n\n\tif err := safe.WriterModify(ctx, r, block.NewVolumeConfig(block.NamespaceName, rsrc.VolumeID), func(vc *block.VolumeConfig) error {\n\t\tif rsrc.Label != \"\" {\n\t\t\tvc.Metadata().Labels().Set(rsrc.Label, \"\")\n\t\t}\n\n\t\treturn rsrc.TransformFunc(vc)\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error creating volume %s: %w\", rsrc.VolumeID, err)\n\t}\n\n\tif rsrc.MountTransformFunc != nil {\n\t\tif err := safe.WriterModify(ctx, r, block.NewVolumeMountRequest(block.NamespaceName, rsrc.VolumeID), func(v *block.VolumeMountRequest) error {\n\t\t\tv.Metadata().Labels().Set(block.UserVolumeLabel, \"\")\n\t\t\tv.TypedSpec().Requester = ctrl.Name()\n\t\t\tv.TypedSpec().VolumeID = rsrc.VolumeID\n\n\t\t\treturn rsrc.MountTransformFunc(v)\n\t\t}); err != nil && !xerrors.TagIs[volumeconfig.SkipUserVolumeMountRequest](err) {\n\t\t\treturn fmt.Errorf(\"error creating volume mount request: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// getExistingVolumes retrieves existing volume configurations and mount requests.\nfunc (ctrl *VolumeConfigController) getExistingVolumes(ctx context.Context, r controller.Runtime) (map[string]*block.VolumeConfig, map[string]*block.VolumeMountRequest, error) {\n\tlabelQuery := []state.ListOption{\n\t\tstate.WithLabelQuery(resource.LabelExists(block.SystemVolumeLabel)),\n\t\tstate.WithLabelQuery(resource.LabelExists(block.UserVolumeLabel)),\n\t\tstate.WithLabelQuery(resource.LabelExists(block.RawVolumeLabel)),\n\t\tstate.WithLabelQuery(resource.LabelExists(block.ExistingVolumeLabel)),\n\t\tstate.WithLabelQuery(resource.LabelExists(block.ExternalVolumeLabel)),\n\t\tstate.WithLabelQuery(resource.LabelExists(block.SwapVolumeLabel)),\n\t}\n\n\tvolumeConfigs, err := safe.ReaderListAll[*block.VolumeConfig](ctx, r, labelQuery...)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error fetching volume configs: %w\", err)\n\t}\n\n\tvolumeMountRequests, err := safe.ReaderListAll[*block.VolumeMountRequest](ctx, r, labelQuery...)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error fetching volume mount requests: %w\", err)\n\t}\n\n\tvolumeConfigsByID := xslices.ToMap(\n\t\tsafe.ToSlice(volumeConfigs, identity),\n\t\tfunc(v *block.VolumeConfig) (resource.ID, *block.VolumeConfig) {\n\t\t\treturn v.Metadata().ID(), v\n\t\t},\n\t)\n\n\tvolumeMountRequestsByID := xslices.ToMap(\n\t\tsafe.ToSlice(volumeMountRequests, identity),\n\t\tfunc(v *block.VolumeMountRequest) (resource.ID, *block.VolumeMountRequest) {\n\t\t\treturn v.Metadata().ID(), v\n\t\t},\n\t)\n\n\treturn volumeConfigsByID, volumeMountRequestsByID, nil\n}\n\n// cleanupUnusedVolumes removes volumes that are no longer needed.\nfunc (ctrl *VolumeConfigController) cleanupUnusedVolumes(\n\tctx context.Context,\n\tr controller.Runtime,\n\tvolumeConfigsByID map[string]*block.VolumeConfig,\n\tvolumeMountRequestsByID map[string]*block.VolumeMountRequest,\n) error {\n\tfor _, volumeConfig := range volumeConfigsByID {\n\t\tokToDestroy, err := r.Teardown(ctx, volumeConfig.Metadata())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error tearing down volume config %q: %w\", volumeConfig.Metadata().ID(), err)\n\t\t}\n\n\t\tif okToDestroy {\n\t\t\tif err = r.Destroy(ctx, volumeConfig.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error destroying volume config %q: %w\", volumeConfig.Metadata().ID(), err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Clean up unused volume mount requests\n\tfor _, volumeMountRequest := range volumeMountRequestsByID {\n\t\tokToDestroy, err := r.Teardown(ctx, volumeMountRequest.Metadata())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error tearing down volume mount request %q: %w\", volumeMountRequest.Metadata().ID(), err)\n\t\t}\n\n\t\tif okToDestroy {\n\t\t\tif err = r.Destroy(ctx, volumeMountRequest.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error destroying volume mount request %q: %w\", volumeMountRequest.Metadata().ID(), err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"encoding/json\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tblockctrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tintmeta \"github.com/siderolabs/talos/internal/pkg/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/yamlutils\"\n)\n\ntype VolumeConfigSuite struct {\n\tctest.DefaultSuite\n}\n\ntype metaProvider struct {\n\tmeta *intmeta.Meta\n}\n\nfunc (m metaProvider) Meta() machineruntime.Meta {\n\treturn m.meta\n}\n\nfunc TestVolumeConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &VolumeConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\ttmpDir := suite.T().TempDir()\n\t\t\t\tpath := filepath.Join(tmpDir, \"meta\")\n\n\t\t\t\tf, err := os.Create(path)\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t\tsuite.Require().NoError(f.Truncate(1024 * 1024))\n\t\t\t\tsuite.Require().NoError(f.Close())\n\n\t\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\t\tm, err := intmeta.New(t.Context(), st, intmeta.WithFixedPath(path))\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(\n\t\t\t\t\t&blockctrls.VolumeConfigController{\n\t\t\t\t\t\tMetaProvider: metaProvider{meta: m},\n\t\t\t\t\t},\n\t\t\t\t))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *VolumeConfigSuite) TestReconcileDefaults() {\n\t// user volume mount point should be hold mounted all the time to prevent cascading unmounts on kubelet restart\n\tctest.AssertResource(suite, constants.UserVolumeMountPoint, func(*block.VolumeMountRequest, *assert.Assertions) {})\n\n\t// no machine config, default config which only searches for\n\tctest.AssertResource(suite, constants.MetaPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\t})\n\tctest.AssertResource(suite, constants.StatePartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\n\t\tlocator, err := r.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\t\tasrt.Equal(`volume.partition_label == \"STATE\" && volume.name != \"\"`, string(locator))\n\n\t\tasrt.Equal(constants.StateMountPoint, r.TypedSpec().Mount.TargetPath)\n\t})\n\tctest.AssertNoResource[*block.VolumeConfig](suite, constants.EphemeralPartitionLabel)\n\n\t// create a dummy machine config\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// now the volume config should be created\n\tctest.AssertResource(suite, constants.MetaPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\t\tasrt.Empty(r.TypedSpec().Mount)\n\n\t\tlocator, err := r.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\n\t\tasrt.Equal(`volume.partition_label == \"META\" && volume.name in [\"\", \"talosmeta\"] && volume.size == 1048576u`, string(locator))\n\t})\n\tctest.AssertResource(suite, constants.StatePartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\n\t\tlocator, err := r.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\t\tasrt.Equal(`volume.partition_label == \"STATE\"`, string(locator))\n\n\t\tasrt.Equal(constants.StateMountPoint, r.TypedSpec().Mount.TargetPath)\n\t})\n\tctest.AssertResource(suite, constants.EphemeralPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\n\t\tlocator, err := r.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\t\tasrt.Equal(`volume.partition_label == \"EPHEMERAL\"`, string(locator))\n\n\t\tlocator, err = r.TypedSpec().Provisioning.DiskSelector.Match.MarshalText()\n\t\tasrt.NoError(err)\n\t\tasrt.Equal(`system_disk`, string(locator))\n\n\t\tasrt.True(r.TypedSpec().Provisioning.PartitionSpec.Grow)\n\t\tasrt.EqualValues(0, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t\tasrt.EqualValues(quirks.New(\"\").PartitionSizes().EphemeralMinSize(), r.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\n\t\tasrt.Equal(constants.EphemeralMountPoint, r.TypedSpec().Mount.TargetPath)\n\t})\n\tctest.AssertResource(suite, \"/var/run\", func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(r.TypedSpec().Type, block.VolumeTypeSymlink)\n\t\tasrt.Equal(r.TypedSpec().Symlink.SymlinkTargetPath, \"/run\")\n\t\tasrt.Equal(r.TypedSpec().Mount.TargetPath, \"/var/run\")\n\t})\n\n\tctest.AssertResources(suite, []resource.ID{\n\t\tconstants.LogMountPoint,\n\t\t\"/var/log/audit\",\n\t\t\"/var/log/containers\",\n\t\t\"/var/log/pods\",\n\t\tconstants.EtcdDataVolumeID,\n\t\t\"/var/lib/containerd\",\n\t\t\"/var/lib/kubelet\",\n\t\t\"/var/lib/cni\",\n\t\tconstants.SeccompProfilesDirectory,\n\t\tconstants.KubernetesAuditLogDir,\n\t\t\"/var/run/lock\",\n\t}, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(block.VolumeTypeDirectory, r.TypedSpec().Type)\n\t})\n\n\tctest.AssertResources(suite,\n\t\txslices.Map(constants.Overlays, func(target constants.SELinuxLabeledPath) resource.ID {\n\t\t\treturn target.Path\n\t\t}),\n\t\tfunc(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(block.VolumeTypeOverlay, r.TypedSpec().Type)\n\t\t})\n}\n\nfunc (suite *VolumeConfigSuite) TestReconcileEncryptedSTATE() {\n\tstateEncryption := &v1alpha1.EncryptionConfig{\n\t\tEncryptionProvider: \"luks2\",\n\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 1,\n\t\t\t\tKeyStatic: &v1alpha1.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"supersecret\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot: 2,\n\t\t\t\tKeyTPM:  &v1alpha1.EncryptionKeyTPM{},\n\t\t\t},\n\t\t},\n\t}\n\n\tstateEncryptionMarshalled, err := json.Marshal(stateEncryption)\n\tsuite.Require().NoError(err)\n\n\tstateMetaKey := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.StateEncryptionConfig))\n\tstateMetaKey.TypedSpec().Value = string(stateEncryptionMarshalled)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), stateMetaKey))\n\n\t// no machine config, default config which only searches for\n\tctest.AssertResource(suite, constants.MetaPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\t})\n\tctest.AssertResource(suite, constants.StatePartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\n\t\tasrt.NotEmpty(r.TypedSpec().Encryption)\n\n\t\tasrt.Equal(block.EncryptionProviderLUKS2, r.TypedSpec().Encryption.Provider)\n\t\tasrt.Len(r.TypedSpec().Encryption.Keys, 2)\n\n\t\tif len(r.TypedSpec().Encryption.Keys) != 2 {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal(1, r.TypedSpec().Encryption.Keys[0].Slot)\n\n\t\tasrt.Equal(block.EncryptionKeyStatic, r.TypedSpec().Encryption.Keys[0].Type)\n\t\tasrt.Equal(yamlutils.StringBytes([]byte(\"supersecret\")), r.TypedSpec().Encryption.Keys[0].StaticPassphrase)\n\n\t\tasrt.Equal(2, r.TypedSpec().Encryption.Keys[1].Slot)\n\t\tasrt.Equal(block.EncryptionKeyTPM, r.TypedSpec().Encryption.Keys[1].Type)\n\t})\n\tctest.AssertNoResource[*block.VolumeConfig](suite, constants.EphemeralPartitionLabel)\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineSystemDiskEncryption: &v1alpha1.SystemDiskEncryptionConfig{\n\t\t\t\t\t\tStatePartition: stateEncryption,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// now the volume config should be created\n\tctest.AssertResource(suite, constants.MetaPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Provisioning)\n\t})\n\tctest.AssertResource(suite, constants.StatePartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\t\tasrt.NotEmpty(r.TypedSpec().Encryption)\n\t})\n\tctest.AssertResource(suite, constants.EphemeralPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\t\tasrt.Empty(r.TypedSpec().Encryption)\n\t})\n}\n\nfunc (suite *VolumeConfigSuite) TestReconcileExtraEPHEMERALConfig() {\n\tctest.AssertNoResource[*block.VolumeConfig](suite, constants.EphemeralPartitionLabel)\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tctr, err := container.New(\n\t\t&v1alpha1.Config{\n\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\tURL: u,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t&blockcfg.VolumeConfigV1Alpha1{\n\t\t\tMetaName: constants.EphemeralPartitionLabel,\n\t\t\tProvisioningSpec: blockcfg.ProvisioningSpec{\n\t\t\t\tDiskSelectorSpec: blockcfg.DiskSelector{\n\t\t\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t\t\t},\n\t\t\t\tProvisioningGrow:    new(false),\n\t\t\t\tProvisioningMaxSize: blockcfg.MustSize(\"2.5TiB\"),\n\t\t\t},\n\t\t\tEncryptionSpec: blockcfg.EncryptionSpec{\n\t\t\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\t\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &blockcfg.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// now the volume config should be created\n\tctest.AssertResource(suite, constants.EphemeralPartitionLabel, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(r.TypedSpec().Provisioning)\n\t\tasrt.NotEmpty(r.TypedSpec().Encryption)\n\n\t\tlocator, err := r.TypedSpec().Provisioning.DiskSelector.Match.MarshalText()\n\t\tasrt.NoError(err)\n\t\tasrt.Equal(`disk.transport == \"nvme\"`, string(locator))\n\n\t\tasrt.False(r.TypedSpec().Provisioning.PartitionSpec.Grow)\n\t\tasrt.EqualValues(2.5*1024*1024*1024*1024, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t\tasrt.EqualValues(quirks.New(\"\").PartitionSizes().EphemeralMinSize(), r.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\n\t\tasrt.Equal(block.EncryptionProviderLUKS2, r.TypedSpec().Encryption.Provider)\n\t})\n}\n\nfunc (suite *VolumeConfigSuite) TestReconcileUserRawVolumes() {\n\trv1 := blockcfg.NewRawVolumeConfigV1Alpha1()\n\trv1.MetaName = \"data1\"\n\tsuite.Require().NoError(rv1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\trv1.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"10GiB\")\n\trv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"100GiB\")\n\n\trv2 := blockcfg.NewRawVolumeConfigV1Alpha1()\n\trv2.MetaName = \"data2\"\n\tsuite.Require().NoError(rv2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\trv2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"1TiB\")\n\trv2.EncryptionSpec = blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &blockcfg.EncryptionKeyTPM{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot:   1,\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{KeyData: \"secret\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tctr, err := container.New(rv1, rv2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\trawVolumes := []string{\n\t\tconstants.RawVolumePrefix + \"data1\",\n\t\tconstants.RawVolumePrefix + \"data2\",\n\t}\n\n\tctest.AssertResources(suite, rawVolumes, func(vc *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Contains(vc.Metadata().Labels().Raw(), block.RawVolumeLabel)\n\n\t\tasrt.Equal(block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\tasrt.Contains(rawVolumes, vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\n\t\tlocator, err := vc.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\n\t\tasrt.Contains(string(locator), vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\t\tasrt.Equal(block.FilesystemTypeNone, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\n\t\tasrt.Empty(vc.TypedSpec().Mount)\n\t})\n\n\tfor _, volumeID := range rawVolumes {\n\t\tctest.AssertNoResource[*block.VolumeMountRequest](suite, volumeID)\n\t}\n\n\t// drop the first volume\n\tctr, err = container.New(rv2)\n\tsuite.Require().NoError(err)\n\n\tnewCfg := config.NewMachineConfig(ctr)\n\tnewCfg.Metadata().SetVersion(cfg.Metadata().Version())\n\tsuite.Update(newCfg)\n\n\t// now the resources should be removed\n\tctest.AssertNoResource[*block.VolumeConfig](suite, rawVolumes[0])\n}\n\nfunc (suite *VolumeConfigSuite) TestReconcileUserSwapVolumes() {\n\tuserVolumeNames := []string{\n\t\t\"data-part1\",\n\t\t\"data-part2\",\n\t\t\"data-dir1\",\n\t\t\"data-disk1\",\n\t}\n\n\tuvPart1 := blockcfg.NewUserVolumeConfigV1Alpha1()\n\tuvPart1.MetaName = userVolumeNames[0]\n\tsuite.Require().NoError(uvPart1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\tuvPart1.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"10GiB\")\n\tuvPart1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"100GiB\")\n\tuvPart1.FilesystemSpec.FilesystemType = block.FilesystemTypeXFS\n\n\tuvPart2 := blockcfg.NewUserVolumeConfigV1Alpha1()\n\tuvPart2.MetaName = userVolumeNames[1]\n\tuvPart2.VolumeType = new(block.VolumeTypePartition)\n\tsuite.Require().NoError(uvPart2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\tuvPart2.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"1TiB\")\n\tuvPart2.EncryptionSpec = blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &blockcfg.EncryptionKeyTPM{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot:   1,\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{KeyData: \"secret\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tuvDir1 := blockcfg.NewUserVolumeConfigV1Alpha1()\n\tuvDir1.MetaName = userVolumeNames[2]\n\tuvDir1.VolumeType = new(block.VolumeTypeDirectory)\n\n\tuvDisk1 := blockcfg.NewUserVolumeConfigV1Alpha1()\n\tuvDisk1.MetaName = userVolumeNames[3]\n\tsuite.Require().NoError(uvDisk1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\tuvDisk1.EncryptionSpec = blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &blockcfg.EncryptionKeyTPM{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot:   1,\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{KeyData: \"secret\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tsv1 := blockcfg.NewSwapVolumeConfigV1Alpha1()\n\tsv1.MetaName = \"swap\"\n\tsuite.Require().NoError(sv1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == \"nvme\"`)))\n\tsv1.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"2GiB\")\n\n\tctr, err := container.New(uvPart1, uvPart2, uvDir1, uvDisk1, sv1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tuserVolumes := xslices.Map(userVolumeNames, func(in string) string { return constants.UserVolumePrefix + in })\n\n\tctest.AssertResources(suite, userVolumes, func(vc *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Contains(vc.Metadata().Labels().Raw(), block.UserVolumeLabel)\n\n\t\tswitch vc.Metadata().ID() {\n\t\tcase userVolumes[0], userVolumes[1], userVolumes[3]:\n\t\t\tasrt.Equal(block.VolumeTypePartition, vc.TypedSpec().Type)\n\n\t\t\tasrt.Contains(userVolumes, vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\n\t\t\tlocator, err := vc.TypedSpec().Locator.Match.MarshalText()\n\t\t\tasrt.NoError(err)\n\n\t\t\tasrt.Contains(string(locator), vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\n\t\tcase userVolumes[2]:\n\t\t\tasrt.Equal(block.VolumeTypeDirectory, vc.TypedSpec().Type)\n\t\t}\n\n\t\tasrt.Contains(userVolumeNames, vc.TypedSpec().Mount.TargetPath)\n\t\tasrt.Equal(constants.UserVolumeMountPoint, vc.TypedSpec().Mount.ParentID)\n\n\t\tswitch vc.Metadata().ID() {\n\t\tcase userVolumes[0]:\n\t\t\tasrt.EqualValues(10*1024*1024*1024, vc.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\tcase userVolumes[1]:\n\t\t\tasrt.EqualValues(100*1024*1024, vc.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\t}\n\t})\n\n\tctest.AssertResources(suite, userVolumes, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Contains(vmr.Metadata().Labels().Raw(), block.UserVolumeLabel)\n\t})\n\n\tswapVolumes := []string{\n\t\tconstants.SwapVolumePrefix + \"swap\",\n\t}\n\n\tctest.AssertResources(suite, swapVolumes, func(vc *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Contains(vc.Metadata().Labels().Raw(), block.SwapVolumeLabel)\n\n\t\tasrt.Equal(block.VolumeTypePartition, vc.TypedSpec().Type)\n\t\tasrt.Contains(swapVolumes, vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\n\t\tlocator, err := vc.TypedSpec().Locator.Match.MarshalText()\n\t\tasrt.NoError(err)\n\n\t\tasrt.Contains(string(locator), vc.TypedSpec().Provisioning.PartitionSpec.Label)\n\n\t\tasrt.Equal(block.FilesystemTypeSwap, vc.TypedSpec().Provisioning.FilesystemSpec.Type)\n\t})\n\n\t// simulate other controllers working - add finalizers for volume config & mount request\n\tfor _, volumeID := range userVolumes {\n\t\tsuite.AddFinalizer(block.NewVolumeConfig(block.NamespaceName, volumeID).Metadata(), \"test\")\n\t\tsuite.AddFinalizer(block.NewVolumeMountRequest(block.NamespaceName, volumeID).Metadata(), \"test\")\n\t}\n\n\t// keep only the first volume\n\tctr, err = container.New(uvPart1)\n\tsuite.Require().NoError(err)\n\n\tnewCfg := config.NewMachineConfig(ctr)\n\tnewCfg.Metadata().SetVersion(cfg.Metadata().Version())\n\tsuite.Update(newCfg)\n\n\t// controller should tear down removed resources\n\tctest.AssertResources(suite, userVolumes, func(vc *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tif vc.Metadata().ID() == userVolumes[0] {\n\t\t\tasrt.Equal(resource.PhaseRunning, vc.Metadata().Phase())\n\t\t} else {\n\t\t\tasrt.Equal(resource.PhaseTearingDown, vc.Metadata().Phase())\n\t\t}\n\t})\n\n\tctest.AssertResources(suite, userVolumes, func(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tif vmr.Metadata().ID() == userVolumes[0] {\n\t\t\tasrt.Equal(resource.PhaseRunning, vmr.Metadata().Phase())\n\t\t} else {\n\t\t\tasrt.Equal(resource.PhaseTearingDown, vmr.Metadata().Phase())\n\t\t}\n\t})\n\n\t// remove finalizers\n\tfor _, userVolume := range userVolumes[1:] {\n\t\tsuite.RemoveFinalizer(block.NewVolumeConfig(block.NamespaceName, userVolume).Metadata(), \"test\")\n\t\tsuite.RemoveFinalizer(block.NewVolumeMountRequest(block.NamespaceName, userVolume).Metadata(), \"test\")\n\t}\n\n\t// now the resources should be removed\n\tfor _, userVolume := range userVolumes[1:] {\n\t\tctest.AssertNoResource[*block.VolumeConfig](suite, userVolume)\n\t\tctest.AssertNoResource[*block.VolumeMountRequest](suite, userVolume)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/volume_manager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/kvutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes\"\n\t\"github.com/siderolabs/talos/internal/pkg/encryption\"\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n\tblockpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// VolumeManagerController manages volumes in the system, converting VolumeConfig resources to VolumeStatuses.\ntype VolumeManagerController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *VolumeManagerController) Name() string {\n\treturn \"block.VolumeManagerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *VolumeManagerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeConfigType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiscoveredVolumeType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiskType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.SystemDiskType,\n\t\t\tID:        optional.Some(block.SystemDiskID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.DevicesStatusType,\n\t\t\tID:        optional.Some(runtime.DevicesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.DiscoveryRefreshStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: hardware.NamespaceName,\n\t\t\tType:      hardware.SystemInformationType,\n\t\t\tID:        optional.Some(hardware.SystemInformationID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeLifecycleType,\n\t\t\tID:        optional.Some(block.VolumeLifecycleID),\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: hardware.NamespaceName,\n\t\t\tType:      hardware.PCRStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EncryptionSaltType,\n\t\t\tID:        optional.Some(secrets.EncryptionSaltID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *VolumeManagerController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: block.DiscoveryRefreshRequestType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *VolumeManagerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tdeviceReadyObserved bool\n\t\tdeviceReadyRequest  int\n\t)\n\n\tretryTicker := time.NewTicker(30 * time.Second)\n\tdefer retryTicker.Stop()\n\n\tshouldRetry := false\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-retryTicker.C:\n\t\t\tif !shouldRetry {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tshouldRetry = false\n\t\t}\n\n\t\t// if devices are not ready, we can't provision and locate most volumes\n\t\tdevicesStatus, err := safe.ReaderGetByID[*runtime.DevicesStatus](ctx, r, runtime.DevicesID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching devices status: %w\", err)\n\t\t}\n\n\t\tdevicesReady := devicesStatus != nil && devicesStatus.TypedSpec().Ready\n\n\t\tif devicesReady && !deviceReadyObserved {\n\t\t\tdeviceReadyObserved = true\n\n\t\t\t// udevd reports that devices are ready, now it's time to refresh the discovery volumes\n\t\t\tif err = safe.WriterModify(ctx, r, block.NewDiscoveryRefreshRequest(block.NamespaceName, block.RefreshID), func(drr *block.DiscoveryRefreshRequest) error {\n\t\t\t\tdrr.TypedSpec().Request++\n\t\t\t\tdeviceReadyRequest = drr.TypedSpec().Request\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating discovery refresh request: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\trefreshStatus, err := safe.ReaderGetByID[*block.DiscoveryRefreshStatus](ctx, r, block.RefreshID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching discovery refresh status: %w\", err)\n\t\t}\n\n\t\t// now devicesReady is only true if the refresh status is up to date\n\t\tdevicesReady = devicesReady && refreshStatus != nil && refreshStatus.TypedSpec().Request == deviceReadyRequest\n\n\t\tdiscoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching discovered volumes: %w\", err)\n\t\t}\n\n\t\tdiscoveredVolumesSpecs, err := safe.Map(discoveredVolumes, func(dv *block.DiscoveredVolume) (*blockpb.DiscoveredVolumeSpec, error) {\n\t\t\tspec := &blockpb.DiscoveredVolumeSpec{}\n\n\t\t\treturn spec, proto.ResourceSpecToProto(dv, spec)\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error mapping discovered volumes: %w\", err)\n\t\t}\n\n\t\tdisks, err := safe.ReaderListAll[*block.Disk](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching disks: %w\", err)\n\t\t}\n\n\t\tsystemDisk, err := safe.ReaderGetByID[*block.SystemDisk](ctx, r, block.SystemDiskID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching system disk: %w\", err)\n\t\t}\n\n\t\tvolumeLifecycle, err := safe.ReaderGetByID[*block.VolumeLifecycle](ctx, r, block.VolumeLifecycleID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching volume lifecycle: %w\", err)\n\t\t}\n\n\t\tif volumeLifecycle == nil {\n\t\t\t// no volume lifecycle, cease all operations\n\t\t\tcontinue\n\t\t}\n\n\t\tif volumeLifecycle.Metadata().Phase() == resource.PhaseRunning {\n\t\t\tif err = r.AddFinalizer(ctx, volumeLifecycle.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer to volume lifecycle: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tdiskSpecs, err := safe.Map(disks, func(d *block.Disk) (volumes.DiskContext, error) {\n\t\t\tspec := &blockpb.DiskSpec{}\n\n\t\t\tif err := proto.ResourceSpecToProto(d, spec); err != nil {\n\t\t\t\treturn volumes.DiskContext{}, err\n\t\t\t}\n\n\t\t\tvar optionalSystemDisk optional.Optional[bool]\n\n\t\t\tif systemDisk != nil {\n\t\t\t\toptionalSystemDisk = optional.Some(d.Metadata().ID() == systemDisk.TypedSpec().DiskID)\n\t\t\t}\n\n\t\t\treturn volumes.DiskContext{\n\t\t\t\tDisk:       spec,\n\t\t\t\tSystemDisk: optionalSystemDisk,\n\t\t\t}, nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error mapping disks: %w\", err)\n\t\t}\n\n\t\tvolumeConfigList, err := safe.ReaderListAll[*block.VolumeConfig](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching volume configurations: %w\", err)\n\t\t}\n\n\t\tvolumeStatusList, err := safe.ReaderListAll[*block.VolumeStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching volume statuses: %w\", err)\n\t\t}\n\n\t\tvolumeStatuses := xslices.ToMap(\n\t\t\tsafe.ToSlice(volumeStatusList, func(vs *block.VolumeStatus) *block.VolumeStatus { return vs }),\n\t\t\tfunc(vs *block.VolumeStatus) (resource.ID, *block.VolumeStatus) {\n\t\t\t\treturn vs.Metadata().ID(), vs\n\t\t\t},\n\t\t)\n\n\t\tif volumeStatuses == nil {\n\t\t\tvolumeStatuses = map[resource.ID]*block.VolumeStatus{}\n\t\t}\n\n\t\t// ensure all volume configs have our finalizers\n\t\tfor vc := range volumeConfigList.All() {\n\t\t\tif vc.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !vc.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\tif err = r.AddFinalizer(ctx, vc.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error adding finalizer to volume configuration: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvolumeLifecycleTearingDown := volumeLifecycle.Metadata().Phase() == resource.PhaseTearingDown\n\n\t\tif volumeLifecycleTearingDown {\n\t\t\tfor _, fin := range *volumeLifecycle.Metadata().Finalizers() {\n\t\t\t\tif fin == ctrl.Name() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// if there are finalizers other than us, we don't start global teardown\n\t\t\t\tvolumeLifecycleTearingDown = false\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tvolumeConfigs := safe.ToSlice(volumeConfigList, identity)\n\n\t\t// re-sort volume configs by provisioning wave\n\t\tslices.SortStableFunc(volumeConfigs, volumes.CompareVolumeConfigs)\n\n\t\tfullyProvisionedWave := math.MaxInt\n\t\tallClosed := true\n\n\t\tfor _, vc := range volumeConfigs {\n\t\t\t// abort on context cancel, as each volume processing might take a while\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil\n\t\t\tdefault:\n\t\t\t}\n\n\t\t\tvolumeStatus := volumeStatuses[vc.Metadata().ID()]\n\t\t\tvolumeLogger := logger.With(zap.String(\"volume\", vc.Metadata().ID()))\n\n\t\t\tvar volumeParentStatus *block.VolumeStatus\n\n\t\t\tif vc.TypedSpec().ParentID != \"\" {\n\t\t\t\tvolumeParentStatus = volumeStatuses[vc.TypedSpec().ParentID]\n\t\t\t}\n\n\t\t\tparentFinalizer := ctrl.Name() + \"-\" + vc.Metadata().ID()\n\n\t\t\t// figure out if we are tearing down this volume or building it\n\t\t\ttearingDown := (volumeStatus != nil && volumeStatus.Metadata().Phase() == resource.PhaseTearingDown) || // we started tearing down the volume, so finish doing so\n\t\t\t\tvc.Metadata().Phase() == resource.PhaseTearingDown || // volume config is being torn down\n\t\t\t\tvolumeParentStatus != nil && volumeParentStatus.Metadata().Phase() == resource.PhaseTearingDown || // parent volume is being torn down\n\t\t\t\tvolumeLifecycleTearingDown // global volume lifecycle requires all volumes to be torn down\n\n\t\t\t// volume status doesn't exist yet, figure out what to do\n\t\t\tif volumeStatus == nil {\n\t\t\t\tif tearingDown {\n\t\t\t\t\tif volumeParentStatus != nil {\n\t\t\t\t\t\tif volumeParentStatus.Metadata().Finalizers().Has(parentFinalizer) {\n\t\t\t\t\t\t\tif err = r.RemoveFinalizer(ctx, volumeParentStatus.Metadata(), parentFinalizer); err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer from parent volume configuration: %w\", err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// happy case, we don't need to progress this volume\n\t\t\t\t\tif vc.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\t\t\tif err = r.RemoveFinalizer(ctx, vc.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer from volume configuration: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// create a stub volume status\n\t\t\t\tvolumeStatus = block.NewVolumeStatus(block.NamespaceName, vc.Metadata().ID())\n\n\t\t\t\tfor k, v := range vc.Metadata().Labels().Raw() {\n\t\t\t\t\tvolumeStatus.Metadata().Labels().Set(k, v)\n\t\t\t\t}\n\n\t\t\t\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseWaiting\n\t\t\t\tvolumeStatus.TypedSpec().Type = vc.TypedSpec().Type\n\t\t\t\tvolumeStatus.TypedSpec().ParentID = vc.TypedSpec().ParentID\n\n\t\t\t\tvolumeStatuses[vc.Metadata().ID()] = volumeStatus\n\t\t\t}\n\n\t\t\tif tearingDown && volumeStatus.Metadata().Phase() != resource.PhaseTearingDown {\n\t\t\t\t// volume status is not yet in the tearing down phase, so move it there\n\t\t\t\t_, err = r.Teardown(ctx, volumeStatus.Metadata())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down volume status: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tshouldCloseVolume := tearingDown && volumeStatus.Metadata().Finalizers().Empty() // we can start closing volume as soon as all finalizers are gone, so the volume is not e.g. mounted\n\n\t\t\tprevPhase := volumeStatus.TypedSpec().Phase\n\n\t\t\tif err = ctrl.progressVolumeConfig(\n\t\t\t\tctx,\n\t\t\t\tvolumeLogger,\n\t\t\t\tr,\n\t\t\t\tvolumes.ManagerContext{\n\t\t\t\t\tCfg:                     vc,\n\t\t\t\t\tStatus:                  volumeStatus.TypedSpec(),\n\t\t\t\t\tParentStatus:            volumeParentStatus,\n\t\t\t\t\tParentFinalizer:         parentFinalizer,\n\t\t\t\t\tDiscoveredVolumes:       discoveredVolumesSpecs,\n\t\t\t\t\tDisks:                   diskSpecs,\n\t\t\t\t\tDevicesReady:            devicesReady,\n\t\t\t\t\tPreviousWaveProvisioned: vc.TypedSpec().Provisioning.Wave <= fullyProvisionedWave,\n\t\t\t\t\tEncryptionHelpers: encryption.Helpers{\n\t\t\t\t\t\tGetSystemInformation: ctrl.getSystemInformation(r),\n\t\t\t\t\t\tTPMLocker:            hardware.LockPCRStatus(r, constants.UKIPCR, vc.Metadata().ID()),\n\t\t\t\t\t\tSaltGetter:           ctrl.getSaltGetter(r),\n\t\t\t\t\t},\n\t\t\t\t\tShouldCloseVolume: shouldCloseVolume,\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\tvolumeStatus.TypedSpec().PreFailPhase = volumeStatus.TypedSpec().Phase\n\t\t\t\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseFailed\n\n\t\t\t\tvolumeStatus.TypedSpec().ErrorMessage = err.Error()\n\t\t\t\tif xerrors.TagIs[volumes.Retryable](err) {\n\t\t\t\t\tshouldRetry = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvolumeStatus.TypedSpec().ErrorMessage = \"\"\n\t\t\t\tvolumeStatus.TypedSpec().PreFailPhase = block.VolumePhase(0)\n\t\t\t}\n\n\t\t\t// if the volume is not ready yet, we can consider the wave not fully provisioned, so the next wave can't start provisioning either\n\t\t\t// but if the volume doesn't have provisioning instructions, we don't block on it being ready\n\t\t\tif volumeStatus.TypedSpec().Phase != block.VolumePhaseReady && !value.IsZero(vc.TypedSpec().Provisioning) {\n\t\t\t\tfullyProvisionedWave = vc.TypedSpec().Provisioning.Wave - 1\n\t\t\t}\n\n\t\t\tif prevPhase != volumeStatus.TypedSpec().Phase || err != nil {\n\t\t\t\tsuppressVolumeLogs := slices.Contains(\n\t\t\t\t\t[]block.VolumeType{\n\t\t\t\t\t\tblock.VolumeTypeDirectory,\n\t\t\t\t\t\tblock.VolumeTypeOverlay,\n\t\t\t\t\t\tblock.VolumeTypeSymlink,\n\t\t\t\t\t},\n\t\t\t\t\tvolumeStatus.TypedSpec().Type,\n\t\t\t\t)\n\n\t\t\t\tif !suppressVolumeLogs {\n\t\t\t\t\tfields := []zap.Field{\n\t\t\t\t\t\tzap.String(\"phase\", fmt.Sprintf(\"%s -> %s\", prevPhase, volumeStatus.TypedSpec().Phase)),\n\t\t\t\t\t\tzap.Error(err),\n\t\t\t\t\t}\n\n\t\t\t\t\tif volumeStatus.TypedSpec().Location != \"\" {\n\t\t\t\t\t\tfields = append(fields, zap.String(\"location\", volumeStatus.TypedSpec().Location))\n\t\t\t\t\t}\n\n\t\t\t\t\tif volumeStatus.TypedSpec().MountLocation != \"\" && volumeStatus.TypedSpec().MountLocation != volumeStatus.TypedSpec().Location {\n\t\t\t\t\t\tfields = append(fields, zap.String(\"mountLocation\", volumeStatus.TypedSpec().MountLocation))\n\t\t\t\t\t}\n\n\t\t\t\t\tif volumeStatus.TypedSpec().ParentLocation != \"\" {\n\t\t\t\t\t\tfields = append(fields, zap.String(\"parentLocation\", volumeStatus.TypedSpec().ParentLocation))\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(volumeStatus.TypedSpec().EncryptionFailedSyncs) > 0 {\n\t\t\t\t\t\tfields = append(fields, zap.Strings(\"encryptionFailedSyncs\", volumeStatus.TypedSpec().EncryptionFailedSyncs))\n\t\t\t\t\t}\n\n\t\t\t\t\tvolumeLogger.Info(\"volume status\", fields...)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// when closing, ignore META volume, we want it to stay longer, so no problem if is not closed yet\n\t\t\tallClosed = allClosed && (volumeStatus.TypedSpec().Phase == block.VolumePhaseClosed || vc.Metadata().ID() == constants.MetaPartitionLabel)\n\n\t\t\tif shouldCloseVolume && volumeStatus.TypedSpec().Phase == block.VolumePhaseClosed {\n\t\t\t\tif volumeParentStatus != nil {\n\t\t\t\t\tif volumeParentStatus.Metadata().Finalizers().Has(parentFinalizer) {\n\t\t\t\t\t\tif err = r.RemoveFinalizer(ctx, volumeParentStatus.Metadata(), parentFinalizer); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer from parent volume configuration: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// we can destroy the volume status now\n\t\t\t\tif err = r.Destroy(ctx, volumeStatus.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying volume status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tdelete(volumeStatuses, volumeStatus.Metadata().ID())\n\t\t\t}\n\t\t}\n\n\t\t// update statuses\n\t\tfor id, newVs := range volumeStatuses {\n\t\t\tif err = safe.WriterModify(ctx, r, block.NewVolumeStatus(block.NamespaceName, id), func(vs *block.VolumeStatus) error {\n\t\t\t\tvs.Metadata().Labels().Do(func(temp kvutils.TempKV) {\n\t\t\t\t\tfor k, v := range newVs.Metadata().Labels().Raw() {\n\t\t\t\t\t\ttemp.Set(k, v)\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\t*vs.TypedSpec() = *newVs.TypedSpec()\n\n\t\t\t\treturn nil\n\t\t\t}, controller.WithExpectedPhaseAny()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating volume status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// remove our finalizer if all volumes are closed\n\t\tif volumeLifecycle.Metadata().Phase() == resource.PhaseTearingDown && allClosed {\n\t\t\tif err = r.RemoveFinalizer(ctx, volumeLifecycle.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing finalizer from volume lifecycle: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ctrl *VolumeManagerController) progressVolumeConfig(ctx context.Context, logger *zap.Logger, r controller.Runtime, volumeContext volumes.ManagerContext) error {\n\tif !volumeContext.ShouldCloseVolume {\n\t\tif volumeContext.Cfg.TypedSpec().ParentID != \"\" {\n\t\t\tif volumeContext.ParentStatus == nil {\n\t\t\t\t// not ready yet\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif !volumeContext.ParentStatus.Metadata().Finalizers().Has(volumeContext.ParentFinalizer) {\n\t\t\t\tif err := r.AddFinalizer(ctx, volumeContext.ParentStatus.Metadata(), volumeContext.ParentFinalizer); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error adding finalizer to parent volume configuration: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ctrl.processVolumeConfig(ctx, logger, volumeContext)\n}\n\n// processVolumeConfig implements the volume configuration automata.\n//\n//\tInitial -> { Waiting }  ----> { Missing } // volume is not found (by locator)\n//\t\t\t    |                  |\n//\t\t\t    v                  v\n//\t\t\t{ Located }  ---->  { Provisioned } // partition is ready, grown as needed\n//\t                              |\n//\t\t\t\t\t\t\t      v\n//\t                            { Prepared } // decrypted (if needed)\n//\t                              |\n//\t                              v\n//\t                            { Ready } // can be mounted\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *VolumeManagerController) processVolumeConfig(ctx context.Context, logger *zap.Logger, volumeContext volumes.ManagerContext) error {\n\tprevPhase := volumeContext.Status.Phase\n\n\tfor {\n\t\tif !volumeContext.ShouldCloseVolume {\n\t\t\t// normal state machine\n\t\t\tswitch volumeContext.Status.Phase {\n\t\t\tcase block.VolumePhaseReady:\n\t\t\t\t// nothing to do, ready\n\t\t\t\treturn nil\n\t\t\tcase block.VolumePhaseWaiting, block.VolumePhaseMissing:\n\t\t\t\tif err := volumes.LocateAndProvision(ctx, logger, volumeContext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase block.VolumePhaseLocated:\n\t\t\t\t// grow the partition if needed\n\t\t\t\tif err := volumes.Grow(ctx, logger, volumeContext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase block.VolumePhaseProvisioned:\n\t\t\t\t// decrypt/encrypt the volume\n\t\t\t\tif err := volumes.HandleEncryption(ctx, logger, volumeContext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase block.VolumePhasePrepared:\n\t\t\t\t// format the volume\n\t\t\t\tif err := volumes.Format(ctx, logger, volumeContext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase block.VolumePhaseFailed:\n\t\t\t\t// recover from the failure by restoring the pre-failure phase\n\t\t\t\tvolumeContext.Status.Phase = volumeContext.Status.PreFailPhase\n\t\t\tcase block.VolumePhaseClosed:\n\t\t\t\t// no progress, stop the loop\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else {\n\t\t\t// closing state machine\n\t\t\tswitch volumeContext.Status.Phase {\n\t\t\tcase block.VolumePhaseReady, block.VolumePhasePrepared:\n\t\t\t\tif err := volumes.Close(ctx, logger, volumeContext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase block.VolumePhaseWaiting, block.VolumePhaseMissing, block.VolumePhaseLocated, block.VolumePhaseProvisioned:\n\t\t\t\tvolumeContext.Status.Phase = block.VolumePhaseClosed\n\t\t\tcase block.VolumePhaseClosed:\n\t\t\t\t// done\n\t\t\t\treturn nil\n\t\t\tcase block.VolumePhaseFailed:\n\t\t\t\t// recover from the failure by restoring the pre-failure phase\n\t\t\t\tvolumeContext.Status.Phase = volumeContext.Status.PreFailPhase\n\t\t\t}\n\t\t}\n\n\t\tif volumeContext.Status.Phase == prevPhase {\n\t\t\t// doesn't progress, stop the loop\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\t// abort\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\tprevPhase = volumeContext.Status.Phase\n\t}\n}\n\nfunc (ctrl *VolumeManagerController) getSystemInformation(r controller.Reader) helpers.SystemInformationGetter {\n\treturn func(ctx context.Context) (*hardware.SystemInformation, error) {\n\t\tsystemInfo, err := safe.ReaderGetByID[*hardware.SystemInformation](ctx, r, hardware.SystemInformationID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn nil, fmt.Errorf(\"error fetching system information: %w\", err)\n\t\t}\n\n\t\tif systemInfo == nil {\n\t\t\treturn nil, errors.New(\"system information not available\")\n\t\t}\n\n\t\treturn systemInfo, nil\n\t}\n}\n\nfunc (ctrl *VolumeManagerController) getSaltGetter(r controller.Reader) helpers.SaltGetter {\n\treturn func(ctx context.Context) ([]byte, error) {\n\t\tsalt, err := safe.ReaderGetByID[*secrets.EncryptionSalt](ctx, r, secrets.EncryptionSaltID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn nil, fmt.Errorf(\"error fetching encryption salt: %w\", err)\n\t\t}\n\n\t\tif salt == nil {\n\t\t\treturn nil, errors.New(\"encryption salt not available\")\n\t\t}\n\n\t\treturn salt.TypedSpec().DiskSalt, nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/zswap_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ZswapConfigController provides zswap configuration based machine configuration.\ntype ZswapConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ZswapConfigController) Name() string {\n\treturn \"block.ZswapConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ZswapConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ZswapConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelParamSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ZswapConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\t// load config if present\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching machine configuration\")\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tvar zswapCfg configconfig.ZswapConfig\n\n\t\tif cfg != nil {\n\t\t\tzswapCfg = cfg.Config().ZswapConfig()\n\t\t}\n\n\t\tif zswapCfg != nil { // enabled\n\t\t\tif err := safe.WriterModify(ctx, r, runtime.NewKernelParamSpec(runtime.NamespaceName, \"sys.module.zswap.parameters.enabled\"),\n\t\t\t\tfunc(p *runtime.KernelParamSpec) error {\n\t\t\t\t\tp.TypedSpec().Value = \"Y\"\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting zswap config: %w\", err)\n\t\t\t}\n\n\t\t\tif err := safe.WriterModify(ctx, r, runtime.NewKernelParamSpec(runtime.NamespaceName, \"sys.module.zswap.parameters.max_pool_percent\"),\n\t\t\t\tfunc(p *runtime.KernelParamSpec) error {\n\t\t\t\t\tp.TypedSpec().Value = strconv.Itoa(zswapCfg.MaxPoolPercent())\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting zswap config: %w\", err)\n\t\t\t}\n\n\t\t\tif err := safe.WriterModify(ctx, r, runtime.NewKernelParamSpec(runtime.NamespaceName, \"sys.module.zswap.parameters.shrinker_enabled\"),\n\t\t\t\tfunc(p *runtime.KernelParamSpec) error {\n\t\t\t\t\tif zswapCfg.ShrinkerEnabled() {\n\t\t\t\t\t\tp.TypedSpec().Value = \"Y\"\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.TypedSpec().Value = \"N\"\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting zswap config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.KernelParamSpec](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up volume configuration: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/block/zswap_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/dustin/go-humanize\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ZswapStatusController provides a view of active swap devices.\ntype ZswapStatusController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ZswapStatusController) Name() string {\n\treturn \"block.ZswapStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ZswapStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\t// not really a dependency, but we refresh zswap status kernel param change\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.KernelParamStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ZswapStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.ZswapStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ZswapStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// in container mode, no zswap applies\n\tif ctrl.V1Alpha1Mode == machineruntime.ModeContainer {\n\t\treturn nil\n\t}\n\n\t// there is no way to watch for zswap status, so we are going to poll every minute\n\tticker := time.NewTicker(time.Minute)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\t// try to read a single status file to see if zswap is enabled\n\t\tif _, err := os.ReadFile(\"/sys/kernel/debug/zswap/pool_total_size\"); err == nil {\n\t\t\tif err = safe.WriterModify(ctx, r, block.NewZswapStatus(block.NamespaceName, block.ZswapStatusID),\n\t\t\t\tfunc(zs *block.ZswapStatus) error {\n\t\t\t\t\tfor _, p := range []struct {\n\t\t\t\t\t\tname string\n\t\t\t\t\t\tout  *uint64\n\t\t\t\t\t}{\n\t\t\t\t\t\t{\"pool_total_size\", &zs.TypedSpec().TotalSizeBytes},\n\t\t\t\t\t\t{\"stored_pages\", &zs.TypedSpec().StoredPages},\n\t\t\t\t\t\t{\"pool_limit_hit\", &zs.TypedSpec().PoolLimitHit},\n\t\t\t\t\t\t{\"reject_reclaim_fail\", &zs.TypedSpec().RejectReclaimFail},\n\t\t\t\t\t\t{\"reject_alloc_fail\", &zs.TypedSpec().RejectAllocFail},\n\t\t\t\t\t\t{\"reject_kmemcache_fail\", &zs.TypedSpec().RejectKmemcacheFail},\n\t\t\t\t\t\t{\"reject_compress_fail\", &zs.TypedSpec().RejectCompressFail},\n\t\t\t\t\t\t{\"reject_compress_poor\", &zs.TypedSpec().RejectCompressPoor},\n\t\t\t\t\t\t{\"written_back_pages\", &zs.TypedSpec().WrittenBackPages},\n\t\t\t\t\t} {\n\t\t\t\t\t\tif err := ctrl.readZswapParam(p.name, p.out); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tzs.TypedSpec().TotalSizeHuman = humanize.IBytes(zs.TypedSpec().TotalSizeBytes)\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create zswap status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*block.ZswapStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *ZswapStatusController) readZswapParam(name string, out *uint64) error {\n\tcontent, err := os.ReadFile(filepath.Join(\"/sys/kernel/debug/zswap\", name))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read zswap parameter %q: %w\", name, err)\n\t}\n\n\t*out, err = strconv.ParseUint(string(bytes.TrimSpace(content)), 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse zswap parameter %q: %w\", name, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/affiliate_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// AffiliateMergeController merges raw Affiliates from the RawNamespaceName into final representation in the NamespaceName.\ntype AffiliateMergeController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AffiliateMergeController) Name() string {\n\treturn \"cluster.AffiliateMergeController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AffiliateMergeController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cluster.RawNamespaceName,\n\t\t\tType:      cluster.AffiliateType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AffiliateMergeController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.AffiliateType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *AffiliateMergeController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\trawAffiliates, err := safe.ReaderList[*cluster.Affiliate](ctx, r, resource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn errors.New(\"error listing affiliates\")\n\t\t}\n\n\t\tmergedAffiliates := make(map[resource.ID]*cluster.AffiliateSpec, rawAffiliates.Len())\n\n\t\tfor rawAffiliate := range rawAffiliates.All() {\n\t\t\taffiliateSpec := rawAffiliate.TypedSpec()\n\t\t\tid := affiliateSpec.NodeID\n\n\t\t\tif affiliate, ok := mergedAffiliates[id]; ok {\n\t\t\t\taffiliate.Merge(affiliateSpec)\n\t\t\t} else {\n\t\t\t\tmergedAffiliates[id] = affiliateSpec\n\t\t\t}\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{}, len(mergedAffiliates))\n\n\t\tfor id, affiliateSpec := range mergedAffiliates {\n\t\t\tif err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.NamespaceName, id), func(res *cluster.Affiliate) error {\n\t\t\t\t*res.TypedSpec() = *affiliateSpec\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\t// list keys for cleanup\n\t\tlist, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/affiliate_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\ntype AffiliateMergeSuite struct {\n\tClusterSuite\n}\n\nfunc (suite *AffiliateMergeSuite) TestReconcileDefault() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.AffiliateMergeController{}))\n\n\taffiliate1 := cluster.NewAffiliate(cluster.RawNamespaceName, \"k8s/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate1.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t},\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t}\n\n\taffiliate2 := cluster.NewAffiliate(cluster.RawNamespaceName, \"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate2.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\"), netip.MustParseAddr(\"10.5.0.2\")},\n\t}\n\n\taffiliate3 := cluster.NewAffiliate(cluster.RawNamespaceName, \"service/9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\")\n\t*affiliate3.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tHostname:    \"worker-1\",\n\t\tNodename:    \"worker-1\",\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.5\")},\n\t}\n\n\tfor _, r := range []resource.Resource{affiliate1, affiliate2, affiliate3} {\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, r))\n\t}\n\n\t// there should be two merged affiliates: one from affiliate1+affiliate2, and another from affiliate3\n\tctest.AssertResource(\n\t\tsuite,\n\t\taffiliate1.TypedSpec().NodeID,\n\t\tfunc(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tasrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"192.168.3.4\"), netip.MustParseAddr(\"10.5.0.2\")}, spec.Addresses)\n\t\t\tasrt.Equal(\"foo.com\", spec.Hostname)\n\t\t\tasrt.Equal(\"bar\", spec.Nodename)\n\t\t\tasrt.Equal(machine.TypeControlPlane, spec.MachineType)\n\t\t\tasrt.Equal(netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"), spec.KubeSpan.Address)\n\t\t\tasrt.Equal(\"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\", spec.KubeSpan.PublicKey)\n\t\t\tasrt.Equal([]netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")}, spec.KubeSpan.AdditionalAddresses)\n\t\t\tasrt.Equal([]netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")}, spec.KubeSpan.Endpoints)\n\t\t\tasrt.Equal(&cluster.ControlPlane{APIServerPort: 6443}, spec.ControlPlane)\n\t\t},\n\t)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\taffiliate3.TypedSpec().NodeID,\n\t\tfunc(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tasrt.Equal(affiliate3.TypedSpec().NodeID, spec.NodeID)\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"192.168.3.5\")}, spec.Addresses)\n\t\t\tasrt.Equal(\"worker-1\", spec.Hostname)\n\t\t\tasrt.Equal(\"worker-1\", spec.Nodename)\n\t\t\tasrt.Equal(machine.TypeWorker, spec.MachineType)\n\t\t\tasrt.Zero(spec.KubeSpan.PublicKey)\n\t\t\tasrt.Nil(spec.ControlPlane)\n\t\t},\n\t)\n\n\t// remove affiliate2, KubeSpan information should eventually go away\n\tsuite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate1.Metadata()))\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\taffiliate1.TypedSpec().NodeID,\n\t\tfunc(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tasrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)\n\t\t\tasrt.Zero(spec.KubeSpan.Address)\n\t\t\tasrt.Zero(spec.KubeSpan.PublicKey)\n\t\t\tasrt.Zero(spec.KubeSpan.AdditionalAddresses)\n\t\t\tasrt.Zero(spec.KubeSpan.Endpoints)\n\t\t\tasrt.Nil(spec.ControlPlane)\n\t\t},\n\t)\n\n\t// remove affiliate3, merged affiliate should be removed\n\tsuite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate3.Metadata()))\n\n\tctest.AssertNoResource[*cluster.Affiliate](suite, affiliate3.TypedSpec().NodeID)\n}\n\nfunc TestAffiliateMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(AffiliateMergeSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cluster provides controllers which manage Talos cluster resources.\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc cleanupAffiliates(ctx context.Context, ctrl controller.Controller, r controller.Runtime, touchedIDs map[resource.ID]struct{}) error {\n\t// list keys for cleanup\n\tlist, err := safe.ReaderList[*cluster.Affiliate](\n\t\tctx,\n\t\tr,\n\t\tresource.NewMetadata(cluster.RawNamespaceName, cluster.AffiliateType, \"\", resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t}\n\n\tfor res := range list.All() {\n\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/cluster_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n)\n\ntype ClusterSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *ClusterSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *ClusterSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *ClusterSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc (suite *ClusterSuite) State() state.State { return suite.state }\n\nfunc (suite *ClusterSuite) Ctx() context.Context { return suite.ctx }\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"net\"\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// ConfigController watches v1alpha1.Config, updates discovery config.\ntype ConfigController = transform.Controller[*config.MachineConfig, *cluster.Config]\n\n// NewConfigController instanciates the config controller.\nfunc NewConfigController() *ConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *cluster.Config]{\n\t\t\tName: \"cluster.ConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*cluster.Config] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*cluster.Config]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Cluster() == nil {\n\t\t\t\t\treturn optional.None[*cluster.Config]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(cluster.NewConfig(config.NamespaceName, cluster.ConfigID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *cluster.Config) error {\n\t\t\t\tc := cfg.Config()\n\n\t\t\t\tres.TypedSpec().DiscoveryEnabled = c.Cluster().Discovery().Enabled()\n\n\t\t\t\tif c.Cluster().Discovery().Enabled() {\n\t\t\t\t\tres.TypedSpec().RegistryKubernetesEnabled = c.Cluster().Discovery().Registries().Kubernetes().Enabled()\n\t\t\t\t\tres.TypedSpec().RegistryServiceEnabled = c.Cluster().Discovery().Registries().Service().Enabled()\n\n\t\t\t\t\tif c.Cluster().Discovery().Registries().Service().Enabled() {\n\t\t\t\t\t\tvar u *url.URL\n\n\t\t\t\t\t\tu, err := url.ParseRequestURI(c.Cluster().Discovery().Registries().Service().Endpoint())\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thost := u.Hostname()\n\t\t\t\t\t\tport := u.Port()\n\n\t\t\t\t\t\tif port == \"\" {\n\t\t\t\t\t\t\tif u.Scheme == \"http\" {\n\t\t\t\t\t\t\t\tport = \"80\"\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tport = \"443\" // use default https port for everything else\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tres.TypedSpec().ServiceEndpoint = net.JoinHostPort(host, port)\n\t\t\t\t\t\tres.TypedSpec().ServiceEndpointInsecure = u.Scheme == \"http\"\n\n\t\t\t\t\t\tres.TypedSpec().ServiceEncryptionKey, err = base64.StdEncoding.DecodeString(c.Cluster().Secret())\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tres.TypedSpec().ServiceClusterID = c.Cluster().ID()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tres.TypedSpec().ServiceEndpoint = \"\"\n\t\t\t\t\t\tres.TypedSpec().ServiceEndpointInsecure = false\n\t\t\t\t\t\tres.TypedSpec().ServiceEncryptionKey = nil\n\t\t\t\t\t\tres.TypedSpec().ServiceClusterID = \"\"\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tres.TypedSpec().RegistryKubernetesEnabled = false\n\t\t\t\t\tres.TypedSpec().RegistryServiceEnabled = false\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage cluster_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ConfigSuite) TestReconcileConfig() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tClusterID:     \"cluster1\",\n\t\t\tClusterSecret: \"kCQsKr4B28VUl7qw1sVkTDNF9fFH++ViIuKsss+C6kc=\",\n\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.ConfigID},\n\t\tfunc(res *cluster.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.True(spec.DiscoveryEnabled)\n\t\t\tasrt.True(spec.RegistryKubernetesEnabled)\n\t\t\tasrt.True(spec.RegistryServiceEnabled)\n\t\t\tasrt.Equal(\"discovery.talos.dev:443\", spec.ServiceEndpoint)\n\t\t\tasrt.False(spec.ServiceEndpointInsecure)\n\t\t\tasrt.Equal(\"cluster1\", spec.ServiceClusterID)\n\t\t\tasrt.Equal(\n\t\t\t\t[]byte(\"\\x90\\x24\\x2c\\x2a\\xbe\\x01\\xdb\\xc5\\x54\\x97\\xba\\xb0\\xd6\\xc5\\x64\\x4c\\x33\\x45\\xf5\\xf1\\x47\\xfb\\xe5\\x62\\x22\\xe2\\xac\\xb2\\xcf\\x82\\xea\\x47\"),\n\t\t\t\tspec.ServiceEncryptionKey,\n\t\t\t)\n\t\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), cfg.Metadata()))\n\n\trtestutils.AssertNoResource[*cluster.Config](suite.Ctx(), suite.T(), suite.State(), cluster.ConfigID)\n}\n\nfunc (suite *ConfigSuite) TestReconcileConfigCustom() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tClusterID:     \"cluster1\",\n\t\t\tClusterSecret: \"kCQsKr4B28VUl7qw1sVkTDNF9fFH++ViIuKsss+C6kc=\",\n\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\tDiscoveryRegistries: v1alpha1.DiscoveryRegistriesConfig{\n\t\t\t\t\tRegistryKubernetes: v1alpha1.RegistryKubernetesConfig{\n\t\t\t\t\t\tRegistryDisabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tRegistryService: v1alpha1.RegistryServiceConfig{\n\t\t\t\t\t\tRegistryEndpoint: \"https://[2001:470:6d:30e:565d:e162:e2a0:cf5a]:3456/\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.ConfigID},\n\t\tfunc(res *cluster.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.True(spec.DiscoveryEnabled)\n\t\t\tasrt.False(spec.RegistryKubernetesEnabled)\n\t\t\tasrt.True(spec.RegistryServiceEnabled)\n\t\t\tasrt.Equal(\"[2001:470:6d:30e:565d:e162:e2a0:cf5a]:3456\", spec.ServiceEndpoint)\n\t\t\tasrt.False(spec.ServiceEndpointInsecure)\n\t\t},\n\t)\n}\n\nfunc (suite *ConfigSuite) TestReconcileConfigCustomInsecure() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tClusterID:     \"cluster1\",\n\t\t\tClusterSecret: \"kCQsKr4B28VUl7qw1sVkTDNF9fFH++ViIuKsss+C6kc=\",\n\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\tDiscoveryRegistries: v1alpha1.DiscoveryRegistriesConfig{\n\t\t\t\t\tRegistryKubernetes: v1alpha1.RegistryKubernetesConfig{\n\t\t\t\t\t\tRegistryDisabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tRegistryService: v1alpha1.RegistryServiceConfig{\n\t\t\t\t\t\tRegistryEndpoint: \"http://localhost:3000\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.ConfigID},\n\t\tfunc(res *cluster.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.True(spec.DiscoveryEnabled)\n\t\t\tasrt.False(spec.RegistryKubernetesEnabled)\n\t\t\tasrt.True(spec.RegistryServiceEnabled)\n\t\t\tasrt.Equal(\"localhost:3000\", spec.ServiceEndpoint)\n\t\t\tasrt.True(spec.ServiceEndpointInsecure)\n\t\t},\n\t)\n}\n\nfunc (suite *ConfigSuite) TestReconcileDisabled() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.ConfigID},\n\t\tfunc(res *cluster.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.False(spec.DiscoveryEnabled)\n\t\t\tasrt.False(spec.RegistryKubernetesEnabled)\n\t\t},\n\t)\n}\n\nfunc (suite *ConfigSuite) TestReconcilePartial() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.ConfigID},\n\t\tfunc(res *cluster.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.False(spec.DiscoveryEnabled)\n\t\t\tasrt.False(spec.RegistryKubernetesEnabled)\n\t\t},\n\t)\n\n\tnewCfg := config.NewMachineConfig(must(container.New()))\n\tnewCfg.Metadata().SetVersion(cfg.Metadata().Version())\n\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), newCfg))\n\n\trtestutils.AssertNoResource[*cluster.Config](suite.Ctx(), suite.T(), suite.State(), cluster.ConfigID)\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(clusterctrl.NewConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc must[T any](t T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn t\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/discovery_service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/discovery-api/api/v1alpha1/client/pb\"\n\tdiscoveryclient \"github.com/siderolabs/discovery-client/pkg/client\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nconst defaultDiscoveryTTL = 30 * time.Minute\n\n// DiscoveryServiceController pushes Affiliate resource to the Kubernetes registry.\ntype DiscoveryServiceController struct {\n\tlocalAffiliateID       resource.ID\n\tdiscoveryConfigVersion resource.Version\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DiscoveryServiceController) Name() string {\n\treturn \"cluster.DiscoveryServiceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DiscoveryServiceController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      cluster.ConfigType,\n\t\t\tID:        optional.Some(cluster.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: kubespan.NamespaceName,\n\t\t\tType:      kubespan.EndpointType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MachineResetSignalType,\n\t\t\tID:        optional.Some(runtime.MachineResetSignalID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DiscoveryServiceController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.AffiliateType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.AddressStatusType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *DiscoveryServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tclient          *discoveryclient.Client\n\t\tclientCtxCancel context.CancelFunc\n\t)\n\n\tclientErrCh := make(chan error, 1)\n\n\tdefer func() {\n\t\tif clientCtxCancel != nil {\n\t\t\tclientCtxCancel()\n\n\t\t\t<-clientErrCh\n\t\t}\n\t}()\n\n\tnotifyCh := make(chan struct{}, 1)\n\n\tvar (\n\t\tprevLocalData      *pb.Affiliate\n\t\tprevLocalEndpoints []*pb.Endpoint\n\t\tprevOtherEndpoints []discoveryclient.Endpoint\n\t)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-notifyCh:\n\t\tcase err := <-clientErrCh:\n\t\t\tif clientCtxCancel != nil {\n\t\t\t\tclientCtxCancel()\n\t\t\t}\n\n\t\t\tclientCtxCancel = nil\n\n\t\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\treturn fmt.Errorf(\"error from discovery client: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tcleanupClient := func() {\n\t\t\tif clientCtxCancel != nil {\n\t\t\t\tclientCtxCancel()\n\n\t\t\t\t<-clientErrCh\n\n\t\t\t\tclientCtxCancel = nil\n\t\t\t\tclient = nil\n\n\t\t\t\tprevLocalData = nil\n\t\t\t\tprevLocalEndpoints = nil\n\t\t\t\tprevOtherEndpoints = nil\n\t\t\t}\n\t\t}\n\n\t\tdiscoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting discovery config: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !discoveryConfig.TypedSpec().RegistryServiceEnabled {\n\t\t\t// if discovery is disabled cleanup existing resources\n\t\t\tif err = cleanupAffiliates(ctx, ctrl, r, nil); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcleanupClient()\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !discoveryConfig.Metadata().Version().Equal(ctrl.discoveryConfigVersion) {\n\t\t\t// force reconnect on config change\n\t\t\tcleanupClient()\n\t\t}\n\n\t\tidentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting local identity: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlocalAffiliateID := identity.TypedSpec().NodeID\n\n\t\tif ctrl.localAffiliateID != localAffiliateID {\n\t\t\tctrl.localAffiliateID = localAffiliateID\n\n\t\t\tif err = r.UpdateInputs(append(ctrl.Inputs(),\n\t\t\t\tcontroller.Input{\n\t\t\t\t\tNamespace: cluster.NamespaceName,\n\t\t\t\t\tType:      cluster.AffiliateType,\n\t\t\t\t\tID:        optional.Some(ctrl.localAffiliateID),\n\t\t\t\t\tKind:      controller.InputWeak,\n\t\t\t\t},\n\t\t\t)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcleanupClient()\n\t\t}\n\n\t\taffiliate, err := safe.ReaderGetByID[*cluster.Affiliate](ctx, r, ctrl.localAffiliateID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting local affiliate: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\taffiliateSpec := affiliate.TypedSpec()\n\n\t\totherEndpointsList, err := safe.ReaderListAll[*kubespan.Endpoint](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing endpoints: %w\", err)\n\t\t}\n\n\t\tmachineResetSginal, err := safe.ReaderGetByID[*runtime.MachineResetSignal](ctx, r, runtime.MachineResetSignalID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine reset signal: %w\", err)\n\t\t}\n\n\t\tif client == nil {\n\t\t\tvar cipherBlock cipher.Block\n\n\t\t\tcipherBlock, err = aes.NewCipher(discoveryConfig.TypedSpec().ServiceEncryptionKey)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error initializing AES cipher: %w\", err)\n\t\t\t}\n\n\t\t\ttlsConfigFunc := func() *tls.Config {\n\t\t\t\treturn &tls.Config{\n\t\t\t\t\tRootCAs: httpdefaults.RootCAs(),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tclient, err = discoveryclient.NewClient(discoveryclient.Options{\n\t\t\t\tCipher:        cipherBlock,\n\t\t\t\tEndpoint:      discoveryConfig.TypedSpec().ServiceEndpoint,\n\t\t\t\tClusterID:     discoveryConfig.TypedSpec().ServiceClusterID,\n\t\t\t\tAffiliateID:   localAffiliateID,\n\t\t\t\tTTL:           defaultDiscoveryTTL,\n\t\t\t\tInsecure:      discoveryConfig.TypedSpec().ServiceEndpointInsecure,\n\t\t\t\tClientVersion: version.Tag,\n\t\t\t\tTLSConfig:     tlsConfigFunc,\n\t\t\t\tDialOptions: []grpc.DialOption{\n\t\t\t\t\tgrpc.WithContextDialer(dialer.DynamicProxyDialerWithTLSConfig(tlsConfigFunc)),\n\t\t\t\t},\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error initializing discovery client: %w\", err)\n\t\t\t}\n\n\t\t\tvar clientCtx context.Context\n\n\t\t\tclientCtx, clientCtxCancel = context.WithCancel(ctx) //nolint:govet\n\n\t\t\tctrl.discoveryConfigVersion = discoveryConfig.Metadata().Version()\n\n\t\t\tgo func() {\n\t\t\t\tclientErrCh <- client.Run(clientCtx, logger, notifyCh)\n\t\t\t}()\n\t\t}\n\n\t\t// delete/update local affiliate\n\t\t//\n\t\t// if the node enters final resetting stage, cleanup the local affiliate\n\t\t// otherwise, update local affiliate data\n\t\tif machineResetSginal != nil {\n\t\t\tclient.DeleteLocalAffiliate()\n\t\t} else {\n\t\t\tlocalData := pbAffiliate(affiliateSpec)\n\t\t\tlocalEndpoints := pbEndpoints(affiliateSpec)\n\t\t\totherEndpoints := pbOtherEndpoints(otherEndpointsList)\n\n\t\t\t// don't send updates on localData if it hasn't changed: this introduces positive feedback loop,\n\t\t\t// as the watch loop will notify on self update\n\t\t\tif !proto.Equal(localData, prevLocalData) || !equalEndpoints(localEndpoints, prevLocalEndpoints) || !equalOtherEndpoints(otherEndpoints, prevOtherEndpoints) {\n\t\t\t\tif err = client.SetLocalData(&discoveryclient.Affiliate{\n\t\t\t\t\tAffiliate: localData,\n\t\t\t\t\tEndpoints: localEndpoints,\n\t\t\t\t}, otherEndpoints); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error setting local affiliate data: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tprevLocalData = localData\n\t\t\t\tprevLocalEndpoints = localEndpoints\n\t\t\t\tprevOtherEndpoints = otherEndpoints\n\t\t\t}\n\t\t}\n\n\t\t// discover public IP\n\t\tif publicIP := client.GetPublicIP(); len(publicIP) > 0 {\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewAddressStatus(cluster.NamespaceName, \"service\"), func(address *network.AddressStatus) error {\n\t\t\t\tvar addr netip.Addr\n\n\t\t\t\tif err = addr.UnmarshalBinary(publicIP); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error unmarshaling public IP: %w\", err)\n\t\t\t\t}\n\n\t\t\t\taddress.TypedSpec().Address = netip.PrefixFrom(addr, addr.BitLen())\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err //nolint:govet\n\t\t\t}\n\t\t}\n\n\t\t// discover other nodes (affiliates)\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tfor _, discoveredAffiliate := range client.GetAffiliates() {\n\t\t\tid := fmt.Sprintf(\"service/%s\", discoveredAffiliate.Affiliate.NodeId)\n\n\t\t\tif err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res *cluster.Affiliate) error {\n\t\t\t\t*res.TypedSpec() = specAffiliate(discoveredAffiliate.Affiliate, discoveredAffiliate.Endpoints)\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\tif err := cleanupAffiliates(ctx, ctrl, r, touchedIDs); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc pbAffiliate(affiliate *cluster.AffiliateSpec) *pb.Affiliate {\n\taddresses := xslices.Map(affiliate.Addresses, func(address netip.Addr) []byte {\n\t\treturn takeResult(address.MarshalBinary())\n\t})\n\n\tvar kubeSpan *pb.KubeSpan\n\n\tif affiliate.KubeSpan.PublicKey != \"\" {\n\t\tkubeSpan = &pb.KubeSpan{\n\t\t\tPublicKey: affiliate.KubeSpan.PublicKey,\n\t\t\tAddress:   takeResult(affiliate.KubeSpan.Address.MarshalBinary()),\n\t\t\tAdditionalAddresses: xslices.Map(affiliate.KubeSpan.AdditionalAddresses, func(address netip.Prefix) *pb.IPPrefix {\n\t\t\t\treturn &pb.IPPrefix{\n\t\t\t\t\tBits: uint32(address.Bits()),\n\t\t\t\t\tIp:   takeResult(address.Addr().MarshalBinary()),\n\t\t\t\t}\n\t\t\t}),\n\t\t\tExcludeAdvertisedAddresses: xslices.Map(affiliate.KubeSpan.ExcludeAdvertisedNetworks, func(address netip.Prefix) *pb.IPPrefix {\n\t\t\t\treturn &pb.IPPrefix{\n\t\t\t\t\tBits: uint32(address.Bits()),\n\t\t\t\t\tIp:   takeResult(address.Addr().MarshalBinary()),\n\t\t\t\t}\n\t\t\t}),\n\t\t}\n\t}\n\n\treturn &pb.Affiliate{\n\t\tNodeId:          affiliate.NodeID,\n\t\tAddresses:       addresses,\n\t\tHostname:        affiliate.Hostname,\n\t\tNodename:        affiliate.Nodename,\n\t\tMachineType:     affiliate.MachineType.String(),\n\t\tOperatingSystem: affiliate.OperatingSystem,\n\t\tKubespan:        kubeSpan,\n\t\tControlPlane:    toPlane(affiliate.ControlPlane),\n\t}\n}\n\nfunc toPlane(data *cluster.ControlPlane) *pb.ControlPlane {\n\tif data == nil {\n\t\treturn nil\n\t}\n\n\treturn &pb.ControlPlane{ApiServerPort: uint32(data.APIServerPort)}\n}\n\nfunc pbEndpoints(affiliate *cluster.AffiliateSpec) []*pb.Endpoint {\n\tif affiliate.KubeSpan.PublicKey == \"\" || len(affiliate.KubeSpan.Endpoints) == 0 {\n\t\treturn nil\n\t}\n\n\treturn xslices.Map(affiliate.KubeSpan.Endpoints, func(endpoint netip.AddrPort) *pb.Endpoint {\n\t\treturn &pb.Endpoint{\n\t\t\tPort: uint32(endpoint.Port()),\n\t\t\tIp:   takeResult(endpoint.Addr().MarshalBinary()),\n\t\t}\n\t})\n}\n\nfunc pbOtherEndpoints(otherEndpointsList safe.List[*kubespan.Endpoint]) []discoveryclient.Endpoint {\n\tif otherEndpointsList.Len() == 0 {\n\t\treturn nil\n\t}\n\n\tresult := make([]discoveryclient.Endpoint, 0, otherEndpointsList.Len())\n\n\tfor endpoint := range otherEndpointsList.All() {\n\t\tendpointSpec := endpoint.TypedSpec()\n\n\t\tresult = append(result, discoveryclient.Endpoint{\n\t\t\tAffiliateID: endpointSpec.AffiliateID,\n\t\t\tEndpoints: []*pb.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tPort: uint32(endpointSpec.Endpoint.Port()),\n\t\t\t\t\tIp:   takeResult(endpointSpec.Endpoint.Addr().MarshalBinary()),\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn result\n}\n\nfunc equalEndpoints(a, b []*pb.Endpoint) bool {\n\tif a == nil || b == nil {\n\t\treturn a == nil && b == nil\n\t}\n\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\tfor i := range a {\n\t\tif !proto.Equal(a[i], b[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc equalOtherEndpoints(a, b []discoveryclient.Endpoint) bool {\n\tif a == nil || b == nil {\n\t\treturn a == nil && b == nil\n\t}\n\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\n\tfor i := range a {\n\t\tif a[i].AffiliateID != b[i].AffiliateID {\n\t\t\treturn false\n\t\t}\n\n\t\tif !equalEndpoints(a[i].Endpoints, b[i].Endpoints) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc specAffiliate(affiliate *pb.Affiliate, endpoints []*pb.Endpoint) cluster.AffiliateSpec {\n\tresult := cluster.AffiliateSpec{\n\t\tNodeID:          affiliate.NodeId,\n\t\tHostname:        affiliate.Hostname,\n\t\tNodename:        affiliate.Nodename,\n\t\tOperatingSystem: affiliate.OperatingSystem,\n\t\tMachineType:     takeResult(machine.ParseType(affiliate.MachineType)), // ignore parse error (machine.TypeUnknown)\n\t\tControlPlane:    fromControlPlane(affiliate.ControlPlane),\n\t}\n\n\tresult.Addresses = make([]netip.Addr, 0, len(affiliate.Addresses))\n\n\tfor i := range affiliate.Addresses {\n\t\tvar ip netip.Addr\n\n\t\tif err := ip.UnmarshalBinary(affiliate.Addresses[i]); err == nil {\n\t\t\tresult.Addresses = append(result.Addresses, ip)\n\t\t}\n\t}\n\n\tif affiliate.Kubespan != nil {\n\t\tresult.KubeSpan.PublicKey = affiliate.Kubespan.PublicKey\n\t\tresult.KubeSpan.Address.UnmarshalBinary(affiliate.Kubespan.Address) //nolint:errcheck // ignore error, address will be zero\n\n\t\tresult.KubeSpan.AdditionalAddresses = make([]netip.Prefix, 0, len(affiliate.Kubespan.AdditionalAddresses))\n\n\t\tfor i := range affiliate.Kubespan.AdditionalAddresses {\n\t\t\tvar ip netip.Addr\n\n\t\t\tif err := ip.UnmarshalBinary(affiliate.Kubespan.AdditionalAddresses[i].Ip); err == nil {\n\t\t\t\tresult.KubeSpan.AdditionalAddresses = append(result.KubeSpan.AdditionalAddresses, netip.PrefixFrom(ip, int(affiliate.Kubespan.AdditionalAddresses[i].Bits)))\n\t\t\t}\n\t\t}\n\n\t\tresult.KubeSpan.Endpoints = make([]netip.AddrPort, 0, len(endpoints))\n\n\t\tfor i := range endpoints {\n\t\t\tvar ip netip.Addr\n\n\t\t\tif err := ip.UnmarshalBinary(endpoints[i].Ip); err == nil {\n\t\t\t\tresult.KubeSpan.Endpoints = append(result.KubeSpan.Endpoints, netip.AddrPortFrom(ip, uint16(endpoints[i].Port)))\n\t\t\t}\n\t\t}\n\n\t\tresult.KubeSpan.ExcludeAdvertisedNetworks = make([]netip.Prefix, 0, len(affiliate.Kubespan.ExcludeAdvertisedAddresses))\n\n\t\tfor i := range affiliate.Kubespan.ExcludeAdvertisedAddresses {\n\t\t\tvar ip netip.Addr\n\n\t\t\tif err := ip.UnmarshalBinary(affiliate.Kubespan.ExcludeAdvertisedAddresses[i].Ip); err == nil {\n\t\t\t\tresult.KubeSpan.ExcludeAdvertisedNetworks = append(result.KubeSpan.ExcludeAdvertisedNetworks, netip.PrefixFrom(ip, int(affiliate.Kubespan.ExcludeAdvertisedAddresses[i].Bits)))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc fromControlPlane(plane *pb.ControlPlane) *cluster.ControlPlane {\n\tif plane == nil {\n\t\treturn nil\n\t}\n\n\treturn &cluster.ControlPlane{APIServerPort: int(plane.ApiServerPort)}\n}\n\nfunc takeResult[T any](arg1 T, _ error) T {\n\treturn arg1\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/discovery_service_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"context\"\n\t\"crypto/aes\"\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"io\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/discovery-api/api/v1alpha1/client/pb\"\n\t\"github.com/siderolabs/discovery-client/pkg/client\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype DiscoveryServiceSuite struct {\n\tClusterSuite\n}\n\nfunc (suite *DiscoveryServiceSuite) TestReconcile() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.DiscoveryServiceController{}))\n\n\tserviceEndpoint, err := url.Parse(constants.DefaultDiscoveryServiceEndpoint)\n\tsuite.Require().NoError(err)\n\n\tif serviceEndpoint.Port() == \"\" {\n\t\tserviceEndpoint.Host += \":443\"\n\t}\n\n\tclusterIDRaw := make([]byte, constants.DefaultClusterIDSize)\n\t_, err = io.ReadFull(rand.Reader, clusterIDRaw)\n\tsuite.Require().NoError(err)\n\n\tclusterID := base64.StdEncoding.EncodeToString(clusterIDRaw)\n\n\tencryptionKey := make([]byte, constants.DefaultClusterSecretSize)\n\t_, err = io.ReadFull(rand.Reader, encryptionKey)\n\tsuite.Require().NoError(err)\n\n\t// regular discovery affiliate\n\tdiscoveryConfig := cluster.NewConfig(config.NamespaceName, cluster.ConfigID)\n\tdiscoveryConfig.TypedSpec().DiscoveryEnabled = true\n\tdiscoveryConfig.TypedSpec().RegistryServiceEnabled = true\n\tdiscoveryConfig.TypedSpec().ServiceEndpoint = serviceEndpoint.Host\n\tdiscoveryConfig.TypedSpec().ServiceClusterID = clusterID\n\tdiscoveryConfig.TypedSpec().ServiceEncryptionKey = encryptionKey\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, discoveryConfig))\n\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity))\n\n\tlocalAffiliate := cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID)\n\t*localAffiliate.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      nodeIdentity.TypedSpec().NodeID,\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\")},\n\t\t},\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, localAffiliate))\n\n\t// create a test client connected to the same cluster but under different affiliate ID\n\tcipher, err := aes.NewCipher(discoveryConfig.TypedSpec().ServiceEncryptionKey)\n\tsuite.Require().NoError(err)\n\n\tcli, err := client.NewClient(client.Options{\n\t\tCipher:      cipher,\n\t\tEndpoint:    serviceEndpoint.Host,\n\t\tClusterID:   discoveryConfig.TypedSpec().ServiceClusterID,\n\t\tAffiliateID: \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tTTL:         5 * time.Minute,\n\t})\n\tsuite.Require().NoError(err)\n\n\terrCh := make(chan error, 1)\n\tnotifyCh := make(chan struct{}, 1)\n\n\tcliCtx, cliCtxCancel := context.WithCancel(suite.ctx)\n\tdefer cliCtxCancel()\n\n\tgo func() {\n\t\terrCh <- cli.Run(cliCtx, zaptest.NewLogger(suite.T()), notifyCh)\n\t}()\n\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\t// controller should register its local affiliate, and we should see it being discovered\n\t\t\taffiliates := cli.GetAffiliates()\n\n\t\t\tif len(affiliates) != 1 {\n\t\t\t\treturn retry.ExpectedErrorf(\"affiliates len %d != 1\", len(affiliates))\n\t\t\t}\n\n\t\t\tsuite.Require().Len(affiliates[0].Endpoints, 2)\n\t\t\tsuite.Assert().True(proto.Equal(&pb.Affiliate{\n\t\t\t\tNodeId:          nodeIdentity.TypedSpec().NodeID,\n\t\t\t\tAddresses:       [][]byte{[]byte(\"\\xc0\\xa8\\x03\\x04\")},\n\t\t\t\tHostname:        \"foo.com\",\n\t\t\t\tNodename:        \"bar\",\n\t\t\t\tMachineType:     \"controlplane\",\n\t\t\t\tOperatingSystem: \"\",\n\t\t\t\tKubespan: &pb.KubeSpan{\n\t\t\t\t\tPublicKey: \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:   []byte(\"\\xfd\\x50\\x8d\\x60\\x42\\x38\\x63\\x02\\xf8\\x57\\x23\\xff\\xfe\\x21\\xd1\\xe0\"),\n\t\t\t\t\tAdditionalAddresses: []*pb.IPPrefix{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIp:   []byte(\"\\x0a\\xf4\\x03\\x01\"),\n\t\t\t\t\t\t\tBits: 24,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExcludeAdvertisedAddresses: []*pb.IPPrefix{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIp:   []byte(\"\\x00\\x00\\x00\\x00\"),\n\t\t\t\t\t\t\tBits: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tControlPlane: &pb.ControlPlane{ApiServerPort: 6443},\n\t\t\t}, affiliates[0].Affiliate))\n\t\t\tsuite.Assert().True(proto.Equal(\n\t\t\t\t&pb.Endpoint{\n\t\t\t\t\tIp:   []byte(\"\\n\\x00\\x00\\x02\"),\n\t\t\t\t\tPort: 51820,\n\t\t\t\t},\n\t\t\t\taffiliates[0].Endpoints[0]), \"expected %v\", affiliates[0].Endpoints[0])\n\t\t\tsuite.Assert().True(proto.Equal(\n\t\t\t\t&pb.Endpoint{\n\t\t\t\t\tIp:   []byte(\"\\xc0\\xa8\\x03\\x04\"),\n\t\t\t\t\tPort: 51820,\n\t\t\t\t},\n\t\t\t\taffiliates[0].Endpoints[1]), \"expected %v\", affiliates[0].Endpoints[1])\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\t// inject some affiliate via our client, controller should publish it as an affiliate\n\tsuite.Require().NoError(cli.SetLocalData(&client.Affiliate{\n\t\tAffiliate: &pb.Affiliate{\n\t\t\tNodeId:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\t\tAddresses:       [][]byte{[]byte(\"\\xc0\\xa8\\x03\\x05\")},\n\t\t\tHostname:        \"some.com\",\n\t\t\tNodename:        \"some\",\n\t\t\tMachineType:     \"worker\",\n\t\t\tOperatingSystem: \"test OS\",\n\t\t\tKubespan: &pb.KubeSpan{\n\t\t\t\tPublicKey: \"1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=\",\n\t\t\t\tAddress:   []byte(\"\\xfd\\x50\\x8d\\x60\\x42\\x38\\x63\\x02\\xf8\\x57\\x23\\xff\\xfe\\x21\\xd1\\xe1\"),\n\t\t\t\tAdditionalAddresses: []*pb.IPPrefix{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:   []byte(\"\\x0a\\xf4\\x04\\x01\"),\n\t\t\t\t\t\tBits: 24,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tExcludeAdvertisedAddresses: []*pb.IPPrefix{\n\t\t\t\t\t{\n\t\t\t\t\t\tIp:   []byte(\"\\x01\\x01\\x01\\x01\"),\n\t\t\t\t\t\tBits: 32,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tEndpoints: []*pb.Endpoint{\n\t\t\t{\n\t\t\t\tIp:   []byte(\"\\xc0\\xa8\\x03\\x05\"),\n\t\t\t\tPort: 51820,\n\t\t\t},\n\t\t},\n\t}, nil))\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tfunc(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tsuite.Assert().Equal(\"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\", spec.NodeID)\n\t\t\tsuite.Assert().Equal([]netip.Addr{netip.MustParseAddr(\"192.168.3.5\")}, spec.Addresses)\n\t\t\tsuite.Assert().Equal(\"some.com\", spec.Hostname)\n\t\t\tsuite.Assert().Equal(\"some\", spec.Nodename)\n\t\t\tsuite.Assert().Equal(machine.TypeWorker, spec.MachineType)\n\t\t\tsuite.Assert().Equal(\"test OS\", spec.OperatingSystem)\n\t\t\tsuite.Assert().Equal(netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1\"), spec.KubeSpan.Address)\n\t\t\tsuite.Assert().Equal(\"1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=\", spec.KubeSpan.PublicKey)\n\t\t\tsuite.Assert().Equal([]netip.Prefix{netip.MustParsePrefix(\"10.244.4.1/24\")}, spec.KubeSpan.AdditionalAddresses)\n\t\t\tsuite.Assert().Equal([]netip.Prefix{netip.MustParsePrefix(\"1.1.1.1/32\")}, spec.KubeSpan.ExcludeAdvertisedNetworks)\n\t\t\tsuite.Assert().Equal([]netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.5:51820\")}, spec.KubeSpan.Endpoints)\n\t\t\tsuite.Assert().Zero(spec.ControlPlane)\n\t\t},\n\t\trtestutils.WithNamespace(cluster.RawNamespaceName),\n\t)\n\n\t// controller should publish public IP\n\tctest.AssertResource(suite, \"service\", func(r *network.AddressStatus, assertions *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tassertions.True(spec.Address.IsValid())\n\t\tassertions.True(spec.Address.IsSingleIP())\n\t}, rtestutils.WithNamespace(cluster.NamespaceName))\n\n\t// make controller inject additional endpoint via kubespan.Endpoint\n\tendpoint := kubespan.NewEndpoint(kubespan.NamespaceName, \"1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=\")\n\t*endpoint.TypedSpec() = kubespan.EndpointSpec{\n\t\tAffiliateID: \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tEndpoint:    netip.MustParseAddrPort(\"1.1.1.1:343\"),\n\t}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, endpoint))\n\n\tctest.AssertResource(suite,\n\t\t\"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tfunc(r *cluster.Affiliate, assertions *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tassertions.Len(spec.KubeSpan.Endpoints, 2)\n\t\t\tassertions.Equal([]netip.AddrPort{\n\t\t\t\tnetip.MustParseAddrPort(\"192.168.3.5:51820\"),\n\t\t\t\tnetip.MustParseAddrPort(\"1.1.1.1:343\"),\n\t\t\t}, spec.KubeSpan.Endpoints)\n\t\t},\n\t\trtestutils.WithNamespace(cluster.RawNamespaceName),\n\t)\n\n\t// pretend that machine is being reset\n\tmachineResetSignal := runtime.NewMachineResetSignal()\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, machineResetSignal))\n\n\t// client should see the affiliate being deleted\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\t// controller should delete its local affiliate\n\t\t\taffiliates := cli.GetAffiliates()\n\n\t\t\tif len(affiliates) != 0 {\n\t\t\t\treturn retry.ExpectedErrorf(\"affiliates len %d != 0\", len(affiliates))\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\tcliCtxCancel()\n\tsuite.Assert().NoError(<-errCh)\n}\n\nfunc (suite *DiscoveryServiceSuite) TestDisable() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.DiscoveryServiceController{}))\n\n\tserviceEndpoint, err := url.Parse(constants.DefaultDiscoveryServiceEndpoint)\n\tsuite.Require().NoError(err)\n\n\tif serviceEndpoint.Port() == \"\" {\n\t\tserviceEndpoint.Host += \":443\"\n\t}\n\n\tclusterIDRaw := make([]byte, constants.DefaultClusterIDSize)\n\t_, err = io.ReadFull(rand.Reader, clusterIDRaw)\n\tsuite.Require().NoError(err)\n\n\tclusterID := base64.StdEncoding.EncodeToString(clusterIDRaw)\n\n\tencryptionKey := make([]byte, constants.DefaultClusterSecretSize)\n\t_, err = io.ReadFull(rand.Reader, encryptionKey)\n\tsuite.Require().NoError(err)\n\n\t// regular discovery affiliate\n\tdiscoveryConfig := cluster.NewConfig(config.NamespaceName, cluster.ConfigID)\n\tdiscoveryConfig.TypedSpec().DiscoveryEnabled = true\n\tdiscoveryConfig.TypedSpec().RegistryServiceEnabled = true\n\tdiscoveryConfig.TypedSpec().ServiceEndpoint = serviceEndpoint.Host\n\tdiscoveryConfig.TypedSpec().ServiceClusterID = clusterID\n\tdiscoveryConfig.TypedSpec().ServiceEncryptionKey = encryptionKey\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, discoveryConfig))\n\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity))\n\n\tlocalAffiliate := cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID)\n\t*localAffiliate.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      nodeIdentity.TypedSpec().NodeID,\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, localAffiliate))\n\n\t// create a test client connected to the same cluster but under different affiliate ID\n\tcipher, err := aes.NewCipher(discoveryConfig.TypedSpec().ServiceEncryptionKey)\n\tsuite.Require().NoError(err)\n\n\tcli, err := client.NewClient(client.Options{\n\t\tCipher:      cipher,\n\t\tEndpoint:    serviceEndpoint.Host,\n\t\tClusterID:   discoveryConfig.TypedSpec().ServiceClusterID,\n\t\tAffiliateID: \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tTTL:         5 * time.Minute,\n\t})\n\tsuite.Require().NoError(err)\n\n\terrCh := make(chan error, 1)\n\tnotifyCh := make(chan struct{}, 1)\n\n\tcliCtx, cliCtxCancel := context.WithCancel(suite.ctx)\n\tdefer cliCtxCancel()\n\n\tgo func() {\n\t\terrCh <- cli.Run(cliCtx, zaptest.NewLogger(suite.T()), notifyCh)\n\t}()\n\n\t// inject some affiliate via our client, controller should publish it as an affiliate\n\tsuite.Require().NoError(cli.SetLocalData(&client.Affiliate{\n\t\tAffiliate: &pb.Affiliate{\n\t\t\tNodeId: \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\t},\n\t}, nil))\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tfunc(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\t\tsuite.Assert().Equal(\"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\", r.TypedSpec().NodeID)\n\t\t},\n\t\trtestutils.WithNamespace(cluster.RawNamespaceName),\n\t)\n\n\t// now disable the service registry\n\tctest.UpdateWithConflicts(suite, discoveryConfig, func(r *cluster.Config) error {\n\t\tr.TypedSpec().RegistryServiceEnabled = false\n\n\t\treturn nil\n\t})\n\n\tctest.AssertNoResource[*cluster.Affiliate](\n\t\tsuite,\n\t\t\"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\trtestutils.WithNamespace(cluster.RawNamespaceName),\n\t)\n\n\tcliCtxCancel()\n\tsuite.Assert().NoError(<-errCh)\n}\n\nfunc TestDiscoveryServiceSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(DiscoveryServiceSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// EndpointController looks up control plane endpoints.\ntype EndpointController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EndpointController) Name() string {\n\treturn \"cluster.EndpointController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.MemberType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.EndpointType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmemberList, err := safe.ReaderListAll[*cluster.Member](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing members: %w\", err)\n\t\t}\n\n\t\tvar endpoints []netip.Addr\n\n\t\tfor member := range memberList.All() {\n\t\t\tmemberSpec := member.TypedSpec()\n\n\t\t\tif !(memberSpec.MachineType == machine.TypeControlPlane || memberSpec.MachineType == machine.TypeInit) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tendpoints = append(endpoints, memberSpec.Addresses...)\n\t\t}\n\n\t\tslices.SortFunc(endpoints, func(a, b netip.Addr) int { return a.Compare(b) })\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tk8s.NewEndpoint(k8s.ControlPlaneNamespaceName, k8s.ControlPlaneDiscoveredEndpointsID),\n\t\t\tfunc(r *k8s.Endpoint) error {\n\t\t\t\tif !slices.Equal(r.TypedSpec().Addresses, endpoints) {\n\t\t\t\t\tlogger.Debug(\"updated controlplane endpoints\", zap.Any(\"endpoints\", endpoints))\n\t\t\t\t}\n\n\t\t\t\tr.TypedSpec().Addresses = endpoints\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating endpoints: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype EndpointSuite struct {\n\tClusterSuite\n}\n\nfunc (suite *EndpointSuite) TestReconcileDefault() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.EndpointController{}))\n\n\tmember1 := cluster.NewMember(cluster.NamespaceName, \"talos-default-controlplane-1\")\n\t*member1.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"172.20.0.2\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\")},\n\t\tHostname:        \"talos-default-controlplane-1\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tmember2 := cluster.NewMember(cluster.NamespaceName, \"talos-default-controlplane-2\")\n\t*member2.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:          \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"172.20.0.3\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1\")},\n\t\tHostname:        \"talos-default-controlplane-2\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tmember3 := cluster.NewMember(cluster.NamespaceName, \"talos-default-worker-1\")\n\t*member3.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:          \"xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\",\n\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"172.20.0.4\")},\n\t\tHostname:        \"talos-default-worker-1\",\n\t\tMachineType:     machine.TypeWorker,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tfor _, r := range []resource.Resource{member1, member2, member3} {\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, r))\n\t}\n\n\t// control plane members should be translated to Endpoints\n\tctest.AssertResource(suite, k8s.ControlPlaneDiscoveredEndpointsID, func(r *k8s.Endpoint, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(\n\t\t\t[]string{\n\t\t\t\t\"172.20.0.2\",\n\t\t\t\t\"172.20.0.3\",\n\t\t\t\t\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\",\n\t\t\t\t\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1\",\n\t\t\t},\n\t\t\txslices.Map(spec.Addresses, netip.Addr.String),\n\t\t)\n\t})\n}\n\nfunc TestEndpointSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(EndpointSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/info.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// InfoController looks up control plane infos.\ntype InfoController = transform.Controller[*config.MachineConfig, *cluster.Info]\n\n// NewInfoController instanciates the cluster info controller.\nfunc NewInfoController() *InfoController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *cluster.Info]{\n\t\t\tName: \"cluster.InfoController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*cluster.Info] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*cluster.Info]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Cluster() == nil {\n\t\t\t\t\treturn optional.None[*cluster.Info]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(cluster.NewInfo())\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, info *cluster.Info) error {\n\t\t\t\tinfo.TypedSpec().ClusterID = cfg.Config().Cluster().ID()\n\t\t\t\tinfo.TypedSpec().ClusterName = cfg.Config().Cluster().Name()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/info_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\ntype InfoSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *InfoSuite) TestReconcile() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tClusterID:   \"cluster1\",\n\t\t\tClusterName: \"foo\",\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{cluster.InfoID},\n\t\tfunc(res *cluster.Info, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(\"cluster1\", spec.ClusterID)\n\t\t\tasrt.Equal(\"foo\", spec.ClusterName)\n\t\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), cfg.Metadata()))\n\n\trtestutils.AssertNoResource[*cluster.Config](suite.Ctx(), suite.T(), suite.State(), cluster.ConfigID)\n}\n\nfunc TestInfoSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &InfoSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(clusterctrl.NewInfoController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/kubernetes_pull.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/discovery/registry\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubernetesPullController pulls list of Affiliate resource from the Kubernetes registry.\ntype KubernetesPullController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubernetesPullController) Name() string {\n\treturn \"cluster.KubernetesPullController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubernetesPullController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      cluster.ConfigType,\n\t\t\tID:        optional.Some(cluster.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubernetesPullController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.AffiliateType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KubernetesPullController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tkubernetesClient   *kubernetes.Client\n\t\tkubernetesRegistry *registry.Kubernetes\n\t\twatchCtxCancel     context.CancelFunc\n\t\tnotifyCh           <-chan struct{}\n\t\tnotifyCloser       func()\n\t)\n\n\tdefer func() {\n\t\tif watchCtxCancel != nil {\n\t\t\twatchCtxCancel()\n\t\t}\n\n\t\tif notifyCloser != nil {\n\t\t\tnotifyCloser()\n\t\t}\n\n\t\tif kubernetesClient != nil {\n\t\t\tkubernetesClient.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-notifyCh:\n\t\t}\n\n\t\tdiscoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting discovery config: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !discoveryConfig.TypedSpec().RegistryKubernetesEnabled {\n\t\t\t// if discovery is disabled cleanup existing resources\n\t\t\tif err = cleanupAffiliates(ctx, ctrl, r, nil); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif kubernetesClient == nil {\n\t\t\tkubernetesClient, err = kubernetes.NewClientFromKubeletKubeconfig()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif kubernetesRegistry == nil {\n\t\t\tkubernetesRegistry = registry.NewKubernetes(kubernetesClient)\n\t\t}\n\n\t\tif notifyCh == nil {\n\t\t\tvar watchCtx context.Context\n\n\t\t\twatchCtx, watchCtxCancel = context.WithCancel(ctx) //nolint:govet\n\n\t\t\tnotifyCh, notifyCloser, err = kubernetesRegistry.Watch(watchCtx, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting up registry watcher: %w\", err) //nolint:govet\n\t\t\t}\n\t\t}\n\n\t\taffiliateSpecs, err := kubernetesRegistry.List(nodename.TypedSpec().Nodename)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing affiliates: %w\", err)\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tfor _, affilateSpec := range affiliateSpecs {\n\t\t\tid := fmt.Sprintf(\"k8s/%s\", affilateSpec.NodeID)\n\n\t\t\tif err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.RawNamespaceName, id), func(res *cluster.Affiliate) error {\n\t\t\t\t*res.TypedSpec() = *affilateSpec\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\tif err := cleanupAffiliates(ctx, ctrl, r, touchedIDs); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/kubernetes_push.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/discovery/registry\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// KubernetesPushController pushes Affiliate resource to the Kubernetes registry.\ntype KubernetesPushController struct {\n\tlocalAffiliateID resource.ID\n\tkubernetesClient *kubernetes.Client\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubernetesPushController) Name() string {\n\treturn \"cluster.KubernetesPushController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubernetesPushController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      cluster.ConfigType,\n\t\t\tID:        optional.Some(cluster.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubernetesPushController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KubernetesPushController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tdefer func() {\n\t\tif ctrl.kubernetesClient != nil {\n\t\t\tctrl.kubernetesClient.Close() //nolint:errcheck\n\t\t}\n\n\t\tctrl.kubernetesClient = nil\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tdiscoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)\n\t\t\tif err != nil {\n\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting discovery config: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !discoveryConfig.TypedSpec().RegistryKubernetesEnabled {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tidentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\t\tif err != nil {\n\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting local identity: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlocalAffiliateID := identity.TypedSpec().NodeID\n\n\t\t\tif ctrl.localAffiliateID != localAffiliateID {\n\t\t\t\tctrl.localAffiliateID = localAffiliateID\n\n\t\t\t\tif err = r.UpdateInputs(append(ctrl.Inputs(),\n\t\t\t\t\tcontroller.Input{\n\t\t\t\t\t\tNamespace: cluster.NamespaceName,\n\t\t\t\t\t\tType:      cluster.AffiliateType,\n\t\t\t\t\t\tID:        optional.Some(ctrl.localAffiliateID),\n\t\t\t\t\t\tKind:      controller.InputWeak,\n\t\t\t\t\t},\n\t\t\t\t)); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\taffiliate, err := safe.ReaderGetByID[*cluster.Affiliate](ctx, r, ctrl.localAffiliateID)\n\t\t\tif err != nil {\n\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting local affiliate: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif ctrl.kubernetesClient == nil {\n\t\t\t\tctrl.kubernetesClient, err = kubernetes.NewClientFromKubeletKubeconfig()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err = registry.NewKubernetes(ctrl.kubernetesClient).Push(ctx, affiliate); err != nil {\n\t\t\t\t// reset client connection\n\t\t\t\tctrl.kubernetesClient.Close() //nolint:errcheck\n\t\t\t\tctrl.kubernetesClient = nil\n\n\t\t\t\treturn fmt.Errorf(\"error pushing to Kubernetes registry: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/local_affiliate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/net\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// LocalAffiliateController builds Affiliate resource for the local node.\ntype LocalAffiliateController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LocalAffiliateController) Name() string {\n\treturn \"cluster.LocalAffiliateController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LocalAffiliateController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      cluster.ConfigType,\n\t\t\tID:        optional.Some(cluster.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: kubespan.NamespaceName,\n\t\t\tType:      kubespan.IdentityType,\n\t\t\tID:        optional.Some(kubespan.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubespan.ConfigType,\n\t\t\tID:        optional.Some(kubespan.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      network.AddressStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.APIServerConfigType,\n\t\t\tID:        optional.Some(k8s.APIServerConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LocalAffiliateController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.AffiliateType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LocalAffiliateController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// mandatory resources to be fetched\n\t\tdiscoveryConfig, err := safe.ReaderGetByID[*cluster.Config](ctx, r, cluster.ConfigID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting discovery config: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tidentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting local identity: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\thostname, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting hostname: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tnodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\troutedAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcurrentAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tmachineType, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// optional resources (kubespan)\n\t\tkubespanIdentity, err := safe.ReaderGetByID[*kubespan.Identity](ctx, r, kubespan.LocalIdentity)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan identity: %w\", err)\n\t\t}\n\n\t\tkubespanConfig, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan config: %w\", err)\n\t\t}\n\n\t\tnodeStatus, err := safe.ReaderGetByID[*k8s.NodeStatus](ctx, r, nodename.TypedSpec().Nodename)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting node status: %w\", err)\n\t\t}\n\n\t\tdiscoveredPublicIPs, err := safe.ReaderList[*network.AddressStatus](ctx, r, resource.NewMetadata(cluster.NamespaceName, network.AddressStatusType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting discovered public IP: %w\", err)\n\t\t}\n\n\t\t// optional resources (kubernetes)\n\t\tapiServerConfig, err := safe.ReaderGetByID[*k8s.APIServerConfig](ctx, r, k8s.APIServerConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting API server config: %w\", err)\n\t\t}\n\n\t\tlocalID := identity.TypedSpec().NodeID\n\n\t\ttouchedIDs := map[resource.ID]struct{}{}\n\n\t\tif discoveryConfig.TypedSpec().DiscoveryEnabled {\n\t\t\tif err = safe.WriterModify(ctx, r, cluster.NewAffiliate(cluster.NamespaceName, localID), func(res *cluster.Affiliate) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tspec.NodeID = localID\n\t\t\t\tspec.Hostname = hostname.TypedSpec().FQDN()\n\t\t\t\tspec.Nodename = nodename.TypedSpec().Nodename\n\t\t\t\tspec.MachineType = machineType.MachineType()\n\t\t\t\tspec.OperatingSystem = fmt.Sprintf(\"%s (%s)\", version.Name, version.Tag)\n\n\t\t\t\tif machineType.MachineType().IsControlPlane() && apiServerConfig != nil {\n\t\t\t\t\tspec.ControlPlane = &cluster.ControlPlane{\n\t\t\t\t\t\tAPIServerPort: apiServerConfig.TypedSpec().LocalPort,\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tspec.ControlPlane = nil\n\t\t\t\t}\n\n\t\t\t\troutedNodeIPs := routedAddresses.TypedSpec().IPs()\n\t\t\t\tcurrentNodeIPs := currentAddresses.TypedSpec().IPs()\n\n\t\t\t\tspec.Addresses = routedNodeIPs\n\n\t\t\t\tspec.KubeSpan = cluster.KubeSpanAffiliateSpec{}\n\n\t\t\t\tif kubespanIdentity != nil && kubespanConfig != nil {\n\t\t\t\t\tspec.KubeSpan.Address = kubespanIdentity.TypedSpec().Address.Addr()\n\t\t\t\t\tspec.KubeSpan.PublicKey = kubespanIdentity.TypedSpec().PublicKey\n\n\t\t\t\t\tif kubespanConfig.TypedSpec().AdvertiseKubernetesNetworks && nodeStatus != nil {\n\t\t\t\t\t\tspec.KubeSpan.AdditionalAddresses = slices.Clone(nodeStatus.TypedSpec().PodCIDRs)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspec.KubeSpan.AdditionalAddresses = nil\n\t\t\t\t\t}\n\n\t\t\t\t\tspec.KubeSpan.ExcludeAdvertisedNetworks = kubespanConfig.TypedSpec().ExcludeAdvertisedNetworks\n\n\t\t\t\t\tendpointIPs := xslices.Filter(currentNodeIPs, func(ip netip.Addr) bool {\n\t\t\t\t\t\tif ip == spec.KubeSpan.Address {\n\t\t\t\t\t\t\t// skip kubespan local address\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif network.IsULA(ip, network.ULASideroLink) {\n\t\t\t\t\t\t\t// ignore SideroLink addresses, as they are point-to-point addresses\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn true\n\t\t\t\t\t})\n\n\t\t\t\t\t// mix in discovered public IPs\n\t\t\t\t\tfor res := range discoveredPublicIPs.All() {\n\t\t\t\t\t\taddr := res.TypedSpec().Address.Addr()\n\n\t\t\t\t\t\tif slices.ContainsFunc(endpointIPs, func(a netip.Addr) bool { return addr == a }) {\n\t\t\t\t\t\t\t// this address is already published\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tendpointIPs = append(endpointIPs, addr)\n\t\t\t\t\t}\n\n\t\t\t\t\t// filter endpoints if configured\n\t\t\t\t\tif kubespanConfig.TypedSpec().EndpointFilters != nil {\n\t\t\t\t\t\tendpointIPs, err = net.FilterIPs(endpointIPs, kubespanConfig.TypedSpec().EndpointFilters)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error filtering KubeSpan endpoints: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tspec.KubeSpan.Endpoints = xslices.Map(endpointIPs, func(addr netip.Addr) netip.AddrPort {\n\t\t\t\t\t\treturn netip.AddrPortFrom(addr, constants.KubeSpanDefaultPort)\n\t\t\t\t\t})\n\n\t\t\t\t\t// add extra announced endpoints, deduplicating on the way\n\t\t\t\t\tfor _, addr := range kubespanConfig.TypedSpec().ExtraEndpoints {\n\t\t\t\t\t\tif !slices.Contains(spec.KubeSpan.Endpoints, addr) {\n\t\t\t\t\t\t\tspec.KubeSpan.Endpoints = append(spec.KubeSpan.Endpoints, addr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[localID] = struct{}{}\n\t\t}\n\n\t\t// list keys for cleanup\n\t\tlist, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/local_affiliate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\ntype LocalAffiliateSuite struct {\n\tClusterSuite\n}\n\nfunc (suite *LocalAffiliateSuite) TestGeneration() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.LocalAffiliateController{}))\n\n\tnodeIdentity, nonK8sRoutedAddresses, nodeName, discoveryConfig := suite.createResources()\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, machineType))\n\n\tctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal([]string{\n\t\t\t\"172.20.0.2\",\n\t\t\t\"10.5.0.1\",\n\t\t\t\"192.168.192.168\",\n\t\t\t\"2001:123:4567::1\",\n\t\t}, xslices.Map(spec.Addresses, netip.Addr.String))\n\t\tasrt.Equal(\"example1\", spec.Hostname)\n\t\tasrt.Equal(\"example1.com\", spec.Nodename)\n\t\tasrt.Equal(machine.TypeWorker, spec.MachineType)\n\t\tasrt.Equal(\"Talos (\"+version.Tag+\")\", spec.OperatingSystem)\n\t\tasrt.Equal(cluster.KubeSpanAffiliateSpec{}, spec.KubeSpan)\n\t})\n\n\tif fipsmode.Strict() {\n\t\tsuite.T().Skip(\"skipping test in strict FIPS mode (Wireguard/KubeSpan)\")\n\t}\n\n\t// enable kubespan\n\tmac, err := net.ParseMAC(\"ea:71:1b:b2:cc:ee\")\n\tsuite.Require().NoError(err)\n\n\tksIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity)\n\tsuite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).GenerateKey())\n\tsuite.Require().NoError(kubespanadapter.IdentitySpec(ksIdentity.TypedSpec()).UpdateAddress(\"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\", mac))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, ksIdentity))\n\n\tksConfig := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tksConfig.TypedSpec().EndpointFilters = []string{\"0.0.0.0/0\", \"!192.168.0.0/16\", \"2001::/16\"}\n\tksConfig.TypedSpec().AdvertiseKubernetesNetworks = true\n\tksConfig.TypedSpec().ExtraEndpoints = []netip.AddrPort{netip.MustParseAddrPort(\"10.5.0.1:51820\"), netip.MustParseAddrPort(\"1.2.3.4:5678\")}\n\tksConfig.TypedSpec().ExcludeAdvertisedNetworks = []netip.Prefix{netip.MustParsePrefix(\"2001:123:4567::/64\")}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, ksConfig))\n\n\t// add KS address to the list of node addresses, it should be ignored in the endpoints\n\tnonK8sRoutedAddresses.TypedSpec().Addresses = append(nonK8sRoutedAddresses.TypedSpec().Addresses, ksIdentity.TypedSpec().Address)\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, nonK8sRoutedAddresses))\n\n\tnodeStatus := k8s.NewNodeStatus(k8s.NamespaceName, nodeName.TypedSpec().Nodename)\n\tnodeStatus.TypedSpec().PodCIDRs = []netip.Prefix{netip.MustParsePrefix(\"10.244.1.0/24\")}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodeStatus))\n\n\t// add discovered public IPs\n\tfor _, addr := range []netip.Addr{\n\t\tnetip.MustParseAddr(\"1.1.1.1\"),\n\t\tnetip.MustParseAddr(\"2001:123:4567::1\"), // duplicate, will be ignored\n\t} {\n\t\tdiscoveredAddr := network.NewAddressStatus(cluster.NamespaceName, addr.String())\n\t\tdiscoveredAddr.TypedSpec().Address = netip.PrefixFrom(addr, addr.BitLen())\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, discoveredAddr))\n\t}\n\n\tctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.False(len(spec.Addresses) < 5)\n\n\t\tasrt.Equal([]netip.Addr{\n\t\t\tnetip.MustParseAddr(\"172.20.0.2\"),\n\t\t\tnetip.MustParseAddr(\"10.5.0.1\"),\n\t\t\tnetip.MustParseAddr(\"192.168.192.168\"),\n\t\t\tnetip.MustParseAddr(\"2001:123:4567::1\"),\n\t\t\tksIdentity.TypedSpec().Address.Addr(),\n\t\t}, spec.Addresses)\n\n\t\tasrt.Equal(\"example1\", spec.Hostname)\n\t\tasrt.Equal(\"example1.com\", spec.Nodename)\n\t\tasrt.Equal(machine.TypeWorker, spec.MachineType)\n\n\t\tasrt.NotZero(spec.KubeSpan.PublicKey)\n\t\tasrt.NotZero(spec.KubeSpan.AdditionalAddresses)\n\t\tasrt.Len(spec.KubeSpan.ExcludeAdvertisedNetworks, 1)\n\n\t\tasrt.Equal(ksIdentity.TypedSpec().Address.Addr(), spec.KubeSpan.Address)\n\t\tasrt.Equal(ksIdentity.TypedSpec().PublicKey, spec.KubeSpan.PublicKey)\n\t\tasrt.Equal([]netip.Prefix{netip.MustParsePrefix(\"10.244.1.0/24\")}, spec.KubeSpan.AdditionalAddresses)\n\t\tasrt.Equal(\n\t\t\t[]string{\n\t\t\t\t\"172.20.0.2:51820\",\n\t\t\t\t\"10.5.0.1:51820\",\n\t\t\t\t\"1.1.1.1:51820\",\n\t\t\t\t\"[2001:123:4567::1]:51820\",\n\t\t\t\t\"1.2.3.4:5678\",\n\t\t\t},\n\t\t\txslices.Map(spec.KubeSpan.Endpoints, netip.AddrPort.String),\n\t\t)\n\t})\n\n\t// disable advertising K8s addresses\n\tksConfig.TypedSpec().AdvertiseKubernetesNetworks = false\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, ksConfig))\n\n\tctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().KubeSpan.AdditionalAddresses)\n\t})\n\n\t// disable discovery, local affiliate should be removed\n\tdiscoveryConfig.TypedSpec().DiscoveryEnabled = false\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, discoveryConfig))\n\n\tctest.AssertNoResource[*cluster.Affiliate](suite, nodeIdentity.TypedSpec().NodeID)\n}\n\nfunc (suite *LocalAffiliateSuite) TestCPGeneration() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.LocalAffiliateController{}))\n\n\tnodeIdentity, _, _, discoveryConfig := suite.createResources()\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, machineType))\n\n\tapiServerConfig := k8s.NewAPIServerConfig()\n\tapiServerConfig.TypedSpec().LocalPort = 6445\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, apiServerConfig))\n\n\tctest.AssertResource(suite, nodeIdentity.TypedSpec().NodeID, func(r *cluster.Affiliate, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal([]string{\n\t\t\t\"172.20.0.2\",\n\t\t\t\"10.5.0.1\",\n\t\t\t\"192.168.192.168\",\n\t\t\t\"2001:123:4567::1\",\n\t\t}, xslices.Map(spec.Addresses, netip.Addr.String))\n\t\tasrt.Equal(\"example1\", spec.Hostname)\n\t\tasrt.Equal(\"example1.com\", spec.Nodename)\n\t\tasrt.Equal(machine.TypeControlPlane, spec.MachineType)\n\t\tasrt.Equal(\"Talos (\"+version.Tag+\")\", spec.OperatingSystem)\n\t\tasrt.Equal(cluster.KubeSpanAffiliateSpec{}, spec.KubeSpan)\n\t\tasrt.NotNil(spec.ControlPlane)\n\t\tasrt.Equal(6445, pointer.SafeDeref(spec.ControlPlane).APIServerPort)\n\t})\n\n\tdiscoveryConfig.TypedSpec().DiscoveryEnabled = false\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, discoveryConfig))\n\n\tctest.AssertNoResource[*cluster.Affiliate](suite, nodeIdentity.TypedSpec().NodeID)\n}\n\nfunc (suite *LocalAffiliateSuite) createResources() (*cluster.Identity, *network.NodeAddress, *k8s.Nodename, *cluster.Config) {\n\t// regular discovery affiliate\n\tdiscoveryConfig := cluster.NewConfig(config.NamespaceName, cluster.ConfigID)\n\tdiscoveryConfig.TypedSpec().DiscoveryEnabled = true\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, discoveryConfig))\n\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodeIdentity))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"example1\"\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"example1.com\"\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodename))\n\n\tnonK8sCurrentAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s))\n\tnonK8sCurrentAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\tnetip.MustParsePrefix(\"10.5.0.1/32\"),\n\t\tnetip.MustParsePrefix(\"192.168.192.168/24\"),\n\t\tnetip.MustParsePrefix(\"2001:123:4567::1/64\"),\n\t\tnetip.MustParsePrefix(\"2001:123:4567::1/128\"),\n\t\tnetip.MustParsePrefix(\"fdae:41e4:649b:9303:60be:7e36:c270:3238/128\"), // SideroLink, should be ignored\n\t}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nonK8sCurrentAddresses))\n\n\tnonK8sRoutedAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\tnonK8sRoutedAddresses.TypedSpec().Addresses = []netip.Prefix{ // routed node addresses don't contain SideroLink addresses\n\t\tnetip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\tnetip.MustParsePrefix(\"10.5.0.1/32\"),\n\t\tnetip.MustParsePrefix(\"192.168.192.168/24\"),\n\t\tnetip.MustParsePrefix(\"2001:123:4567::1/64\"),\n\t\tnetip.MustParsePrefix(\"2001:123:4567::1/128\"),\n\t}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nonK8sRoutedAddresses))\n\n\treturn nodeIdentity, nonK8sRoutedAddresses, nodename, discoveryConfig\n}\n\nfunc TestLocalAffiliateSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(LocalAffiliateSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/member.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// MemberController converts Affiliates which have Nodename set into Members.\ntype MemberController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MemberController) Name() string {\n\treturn \"cluster.MemberController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MemberController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.AffiliateType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MemberController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.MemberType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *MemberController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\taffiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)\n\t\tif err != nil {\n\t\t\treturn errors.New(\"error listing affiliates\")\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tfor affiliate := range affiliates.All() {\n\t\t\taffiliateSpec := affiliate.TypedSpec()\n\t\t\tif affiliateSpec.Nodename == \"\" {\n\t\t\t\t// not a cluster member\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, cluster.NewMember(cluster.NamespaceName, affiliateSpec.Nodename), func(res *cluster.Member) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tspec.Addresses = slices.Clone(affiliateSpec.Addresses)\n\t\t\t\tspec.Hostname = affiliateSpec.Hostname\n\t\t\t\tspec.MachineType = affiliateSpec.MachineType\n\t\t\t\tspec.OperatingSystem = affiliateSpec.OperatingSystem\n\t\t\t\tspec.NodeID = affiliateSpec.NodeID\n\t\t\t\tspec.ControlPlane = affiliateSpec.ControlPlane\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[affiliateSpec.Nodename] = struct{}{}\n\t\t}\n\n\t\t// list keys for cleanup\n\t\tlist, err := safe.ReaderListAll[*cluster.Member](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/member_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\ntype MemberSuite struct {\n\tClusterSuite\n}\n\nfunc (suite *MemberSuite) TestReconcileDefault() {\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&clusterctrl.MemberController{}))\n\n\taffiliate1 := cluster.NewAffiliate(cluster.NamespaceName, \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate1.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:        \"foo.com\",\n\t\tNodename:        \"bar\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t},\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t}\n\n\taffiliate2 := cluster.NewAffiliate(cluster.NamespaceName, \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\")\n\t*affiliate2.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tHostname:    \"worker-1\",\n\t\tNodename:    \"worker-1\",\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.5\")},\n\t}\n\n\taffiliate3 := cluster.NewAffiliate(cluster.NamespaceName, \"xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\")\n\t*affiliate3.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\",\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.6\")},\n\t}\n\n\tfor _, r := range []resource.Resource{affiliate1, affiliate2, affiliate3} {\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, r))\n\t}\n\n\t// affiliates with non-empty Nodename should be translated to Members\n\tctest.AssertResource(\n\t\tsuite,\n\t\taffiliate1.TypedSpec().Nodename,\n\t\tfunc(r *cluster.Member, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tasrt.Equal(affiliate1.TypedSpec().NodeID, spec.NodeID)\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"192.168.3.4\")}, spec.Addresses)\n\t\t\tasrt.Equal(\"foo.com\", spec.Hostname)\n\t\t\tasrt.Equal(machine.TypeControlPlane, spec.MachineType)\n\t\t\tasrt.Equal(\"Talos (v1.0.0)\", spec.OperatingSystem)\n\t\t\tasrt.Equal(6443, spec.ControlPlane.APIServerPort)\n\t\t},\n\t)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\taffiliate2.TypedSpec().Nodename,\n\t\tfunc(r *cluster.Member, asrt *assert.Assertions) {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tasrt.Equal(affiliate2.TypedSpec().NodeID, spec.NodeID)\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"192.168.3.5\")}, spec.Addresses)\n\t\t\tasrt.Equal(\"worker-1\", spec.Hostname)\n\t\t\tasrt.Equal(machine.TypeWorker, spec.MachineType)\n\t\t},\n\t)\n\n\t// remove affiliate2, member information should eventually go away\n\tsuite.Require().NoError(suite.state.Destroy(suite.ctx, affiliate2.Metadata()))\n\n\tctest.AssertNoResource[*cluster.Member](suite, affiliate2.TypedSpec().Nodename)\n}\n\nfunc TestMemberSuite(t *testing.T) {\n\tsuite.Run(t, new(MemberSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/node_identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// NodeIdentityController manages runtime.Identity caching identity in the STATE.\ntype NodeIdentityController struct {\n\tstateMachine blockautomaton.VolumeMounterAutomaton\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeIdentityController) Name() string {\n\treturn \"cluster.NodeIdentityController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeIdentityController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeIdentityController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cluster.IdentityType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeIdentityController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif ctrl.stateMachine == nil {\n\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\tctrl.Name(),\n\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\tctrl.establishNodeIdentity,\n\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t)\n\t\t}\n\n\t\tif err := ctrl.stateMachine.Run(ctx, r, logger); err != nil {\n\t\t\treturn fmt.Errorf(\"error running volume mounter machine: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *NodeIdentityController) establishNodeIdentity(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\tvar localIdentity cluster.IdentitySpec\n\n\t\tif err := controllers.LoadOrNewFromFile(root, constants.NodeIdentityFilename, &localIdentity, func(v *cluster.IdentitySpec) error {\n\t\t\treturn clusteradapter.IdentitySpec(v).Generate()\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error caching node identity: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity), func(r *cluster.Identity) error {\n\t\t\t*r.TypedSpec() = localIdentity\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\t// generate `/etc/machine-id` from node identity\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"machine-id\"),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tvar err error\n\n\t\t\t\tr.TypedSpec().Contents, err = clusteradapter.IdentitySpec(&localIdentity).ConvertMachineID()\n\t\t\t\tr.TypedSpec().Mode = 0o444\n\t\t\t\tr.TypedSpec().SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn err\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying machine-id: %w\", err)\n\t\t}\n\n\t\tlogger.Info(\"node identity established\", zap.String(\"node_id\", localIdentity.NodeID))\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cluster/node_identity_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\ntype NodeIdentitySuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NodeIdentitySuite) TestDefault() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&clusterctrl.NodeIdentityController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tctest.AssertNoResource[*cluster.Identity](suite, cluster.LocalIdentity)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, cluster.LocalIdentity, func(*cluster.Identity, *assert.Assertions) {})\n\tctest.AssertResource(suite, \"machine-id\", func(*files.EtcFileSpec, *assert.Assertions) {})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n}\n\nfunc (suite *NodeIdentitySuite) TestLoad() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&clusterctrl.NodeIdentityController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\t// using verbatim data here to make sure nodeId representation is supported in future version fo Talos\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(statePath, constants.NodeIdentityFilename), []byte(\"nodeId: gvqfS27LxD58lPlASmpaueeRVzuof16iXoieRgEvBWaE\\n\"), 0o600))\n\n\tctest.AssertNoResource[*cluster.Identity](suite, cluster.LocalIdentity)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, cluster.LocalIdentity, func(identity *cluster.Identity, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"gvqfS27LxD58lPlASmpaueeRVzuof16iXoieRgEvBWaE\", identity.TypedSpec().NodeID)\n\t})\n\tctest.AssertResource(suite, \"machine-id\", func(f *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"8d2c0de2408fa2a178bad7f45d9aa8fb\", string(f.TypedSpec().Contents))\n\t})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n}\n\nfunc TestNodeIdentitySuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.Run(t, &NodeIdentitySuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&clusterctrl.NodeIdentityController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/acquire.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\ttalosruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\tplatformerrors \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tconfigresource \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// PlatformConfigurator is a reduced interface of runtime.Platform.\ntype PlatformConfigurator interface {\n\tName() string\n\tConfiguration(context.Context) ([]byte, error)\n}\n\n// PlatformEventer sends events based on the config process via platform-specific interface.\ntype PlatformEventer interface {\n\tFireEvent(context.Context, platform.Event)\n}\n\n// Setter sets the current machine config.\ntype Setter interface {\n\tSetConfig(config.Provider) error\n\tSetPersistedConfig(config.Provider) error\n}\n\n// ModeGetter gets the current runtime mode.\ntype ModeGetter interface {\n\tInContainer() bool\n}\n\n// AcquireController loads the machine configuration from multiple sources.\ntype AcquireController struct {\n\tPlatformConfiguration PlatformConfigurator\n\tPlatformEvent         PlatformEventer\n\tMode                  ModeGetter\n\tCmdlineGetter         func() *procfs.Cmdline\n\tConfigSetter          Setter\n\tEventPublisher        talosruntime.Publisher\n\tValidationMode        validation.RuntimeMode\n\tResourceState         state.State\n\tEmbeddedDirectory     string\n\n\tconfigSourcesUsed         []string\n\tstateMachine              blockautomaton.VolumeMounterAutomaton\n\tdiskConfig                config.Provider\n\tstoredEmbeddedConfig      []byte\n\tskipMaskingEmbeddedConfig bool\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AcquireController) Name() string {\n\treturn \"config.AcquireController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AcquireController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.AcquireConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: configresource.NamespaceName,\n\t\t\tType:      configresource.MachineConfigType,\n\t\t\tID:        optional.Some(configresource.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MaintenanceServiceRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tID:        optional.Some(constants.StatePartitionLabel),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AcquireController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: v1alpha1.AcquireConfigStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: runtime.MaintenanceServiceRequestType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// stateMachineFunc represents the state machine of config.AcquireController.\ntype stateMachineFunc func(context.Context, controller.Runtime, *zap.Logger) (stateMachineFunc, config.Provider, error)\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *AcquireController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.EmbeddedDirectory == \"\" {\n\t\tctrl.EmbeddedDirectory = constants.EmbeddedConfigDirectory\n\t} else {\n\t\t// if the embedded directory is overridden, we skip masking the embedded config\n\t\t// as we are in the test mode\n\t\tctrl.skipMaskingEmbeddedConfig = true\n\t}\n\n\t// early on, load the embedded config, and store it in the controller struct\n\t// this way we can \"mask\" the config directory with an empty mount to prevent it from being read from the tree\n\t// by malicious workloads\n\tif err := ctrl.processEmbeddedConfig(logger); err != nil {\n\t\treturn fmt.Errorf(\"failed to process embedded config: %w\", err)\n\t}\n\n\t// start always with loading config from disk\n\tvar currentState stateMachineFunc = ctrl.stateDisk\n\n\t// initialize with empty sources\n\tctrl.configSourcesUsed = []string{}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// check the spec first\n\t\t_, err := safe.ReaderGet[*v1alpha1.AcquireConfigSpec](ctx, r, v1alpha1.NewAcquireConfigSpec().Metadata())\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// spec is not found, wait for it\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get spec: %w\", err)\n\t\t}\n\n\t\t// run the state machine\n\t\tfor {\n\t\t\tnewState, cfg, err := currentState(ctx, r, logger)\n\t\t\tif err != nil {\n\t\t\t\tctrl.EventPublisher.Publish(ctx, &machineapi.ConfigLoadErrorEvent{\n\t\t\t\t\tError: err.Error(),\n\t\t\t\t})\n\n\t\t\t\tctrl.PlatformEvent.FireEvent(\n\t\t\t\t\tctx,\n\t\t\t\t\tplatform.Event{\n\t\t\t\t\t\tType:    platform.EventTypeFailure,\n\t\t\t\t\t\tMessage: \"Error loading and validating Talos machine config.\",\n\t\t\t\t\t\tError:   err,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif cfg != nil {\n\t\t\t\t// apply config\n\t\t\t\tif err = ctrl.ConfigSetter.SetConfig(cfg); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to set config: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif !(len(ctrl.configSourcesUsed) == 1 && ctrl.configSourcesUsed[0] == \"state\") {\n\t\t\t\t\t// if the only source is state, we do not need to persist it\n\t\t\t\t\tif err = ctrl.ConfigSetter.SetPersistedConfig(cfg); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to set persisted config: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif newState == nil {\n\t\t\t\t// wait for reconcile event, keep running in the same state\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcurrentState = newState\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// stateDisk acquires machine configuration from disk (STATE partition).\n//\n// Transitions:\n//\n//\t--> embedded: no config found on disk, proceed to embedded\n//\t--> maintenanceEnter: config found on disk, but it's incomplete, proceed to maintenance\n//\t--> done: config found on disk, and it's complete\n//\n//nolint:gocyclo\nfunc (ctrl *AcquireController) stateDisk(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\t// check if the STATE is missing/available first, if it's missing, we skip the step\n\tstateVolumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, constants.StatePartitionLabel)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, nil, fmt.Errorf(\"failed observing STATE volume status: %w\", err)\n\t}\n\n\tswitch {\n\tcase stateVolumeStatus == nil:\n\t\t// wait for the status to be available\n\t\treturn nil, nil, nil\n\tcase stateVolumeStatus.TypedSpec().Phase == block.VolumePhaseMissing:\n\t\t// STATE is missing, proceed to stateEmbedded\n\t\treturn ctrl.stateEmbedded, nil, nil\n\tcase stateVolumeStatus.TypedSpec().Phase == block.VolumePhaseReady:\n\t\t// STATE is ready, proceed to to the action\n\tdefault:\n\t\t// wait for the definitive status\n\t\treturn nil, nil, nil\n\t}\n\n\tcfg, done, err := ctrl.loadFromDisk(ctx, r, logger)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif !done {\n\t\t// wait for the state machine to finish\n\t\treturn nil, nil, nil\n\t}\n\n\tif cfg != nil {\n\t\tctrl.configSourcesUsed = append(ctrl.configSourcesUsed, \"state\")\n\t}\n\n\tswitch {\n\tcase cfg == nil:\n\t\t// no config loaded, proceed to cmdlineEarly\n\t\treturn ctrl.stateEmbedded, nil, nil\n\tcase cfg.CompleteForBoot():\n\t\t// complete config, we are done\n\t\treturn ctrl.stateDone, cfg, nil\n\tdefault:\n\t\t// incomplete config, proceed to maintenance\n\t\treturn ctrl.stateMaintenanceEnter, cfg, nil\n\t}\n}\n\n// validationModeDiskConfig is a \"fake\" validation mode for config loaded from disk.\ntype validationModeDiskConfig struct{}\n\n// RequiresInstall implements validation.RuntimeMode interface.\nfunc (validationModeDiskConfig) RequiresInstall() bool {\n\treturn false\n}\n\n// InContainer implements validation.RuntimeMode interface.\nfunc (validationModeDiskConfig) InContainer() bool {\n\t// containers don't persist config to disk\n\treturn false\n}\n\n// String implements validation.RuntimeMode interface.\nfunc (validationModeDiskConfig) String() string {\n\treturn \"diskConfig\"\n}\n\n// loadFromDisk is a helper function for stateDisk.\nfunc (ctrl *AcquireController) loadFromDisk(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger) (config.Provider, bool, error) {\n\tif ctrl.stateMachine == nil {\n\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\tctrl.Name(),\n\t\t\tconstants.StatePartitionLabel,\n\t\t\tctrl.loadConfigFromDisk,\n\t\t\tblockautomaton.WithReadOnly(true),\n\t\t\tblockautomaton.WithDetached(true),\n\t\t)\n\t}\n\n\tif err := ctrl.stateMachine.Run(ctx, r, logger,\n\t\tautomaton.WithAfterFunc(func() error {\n\t\t\tctrl.stateMachine = nil\n\n\t\t\treturn nil\n\t\t}),\n\t); err != nil {\n\t\treturn nil, false, err\n\t}\n\n\tif ctrl.stateMachine == nil {\n\t\t// state machine finished\n\t\treturn ctrl.diskConfig, true, nil\n\t}\n\n\treturn nil, false, nil\n}\n\nfunc (ctrl *AcquireController) loadConfigFromDisk(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\tconfigPath := constants.ConfigFilename\n\n\t\tlogger.Debug(\"loading config from STATE\", zap.String(\"path\", configPath))\n\n\t\t_, err := xfs.Stat(root, configPath)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t// no saved machine config\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to stat %s: %w\", configPath, err)\n\t\t}\n\n\t\tcfg, err := loadConfig(root, configPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// if the STATE partition is present & contains machine config, Talos is already installed\n\t\twarnings, err := cfg.Validate(validationModeDiskConfig{})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to validate on-disk config: %w\", err)\n\t\t}\n\n\t\tfor _, warning := range warnings {\n\t\t\tlogger.Warn(\"config validation warning\", zap.String(\"warning\", warning))\n\t\t}\n\n\t\t// we can't return the value directly\n\t\tctrl.diskConfig = cfg\n\n\t\treturn nil\n\t})\n}\n\n// stateEmbedded acquires machine configuration from the embedded file path.\n//\n// It is called before the cmdlineEarly source.\n//\n// Transitions:\n//\n//\t--> cmdlineEarly: config loaded from embedded, but it's incomplete, or no config: proceed to cmdlineEarly\n//\t--> done: config loaded from cmdline, and it's complete\nfunc (ctrl *AcquireController) stateEmbedded(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\tcfg, err := ctrl.loadConfigFromEmbedded(logger)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif cfg != nil {\n\t\tctrl.configSourcesUsed = append(ctrl.configSourcesUsed, \"embedded\")\n\t}\n\n\tswitch {\n\tcase cfg == nil:\n\t\tfallthrough\n\tcase !cfg.CompleteForBoot():\n\t\t// incomplete or missing config, proceed to cmdlineEarly\n\t\treturn ctrl.stateCmdlineEarly, cfg, nil\n\tdefault:\n\t\t// complete config, we are done\n\t\treturn ctrl.stateDone, cfg, nil\n\t}\n}\n\nfunc (ctrl *AcquireController) processEmbeddedConfig(logger *zap.Logger) error {\n\tconfigPath := filepath.Join(ctrl.EmbeddedDirectory, constants.ConfigFilename)\n\n\t_, err := os.Stat(configPath)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\t// no saved machine config\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to stat %s: %w\", configPath, err)\n\t}\n\n\tcfgBytes, err := os.ReadFile(configPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read embedded config: %w\", err)\n\t}\n\n\tlogger.Info(\"initialized embedded config processing\", zap.String(\"path\", configPath))\n\n\tctrl.storedEmbeddedConfig = cfgBytes\n\n\tif ctrl.skipMaskingEmbeddedConfig {\n\t\treturn nil\n\t}\n\n\t// we are not going to unmount this, so we don't store the point\n\t_, err = mount.NewManager(\n\t\tmount.WithTarget(ctrl.EmbeddedDirectory),\n\t\tmount.WithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_RELATIME|unix.MOUNT_ATTR_RDONLY),\n\t\tmount.WithFsopen(\n\t\t\t\"tmpfs\",\n\t\t),\n\t).Mount()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to mask embedded config directory %q: %w\", ctrl.EmbeddedDirectory, err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *AcquireController) loadConfigFromEmbedded(logger *zap.Logger) (config.Provider, error) {\n\tif ctrl.storedEmbeddedConfig == nil {\n\t\t// no embedded config\n\t\treturn nil, nil\n\t}\n\n\tlogger.Info(\"loading embedded config\")\n\n\tcfg, err := configloader.NewFromBytes(ctrl.storedEmbeddedConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load config from embedded: %w\", err)\n\t}\n\n\t// if the STATE partition is present & contains machine config, Talos is already installed\n\twarnings, err := cfg.Validate(validationModeDiskConfig{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate embedded config: %w\", err)\n\t}\n\n\tfor _, warning := range warnings {\n\t\tlogger.Warn(\"config validation warning\", zap.String(\"warning\", warning))\n\t}\n\n\treturn cfg, nil\n}\n\n// stateCmdlineEarly acquires machine configuration from the kernel cmdline source (talos.config.early).\n//\n// It is called before the platform source.\n//\n// Transitions:\n//\n//\t--> platform: config loaded from cmdline, but it's incomplete, or no config: proceed to platform\n//\t--> done: config loaded from cmdline, and it's complete\nfunc (ctrl *AcquireController) stateCmdlineEarly(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\treturn ctrl.stateCmdlineGeneric(constants.KernelParamConfigEarly, \"cmdline-early\", ctrl.statePlatform)(ctx, r, logger)\n}\n\n// statePlatform acquires machine configuration from the platform source.\n//\n// Transitions:\n//\n//\t--> cmdlineLate: config loaded from platform, but it's incomplete, or no config from platform: proceed to cmdline\n//\t--> done: config loaded from platform, and it's complete\nfunc (ctrl *AcquireController) statePlatform(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\tcfg, err := ctrl.loadFromPlatform(ctx, logger)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif cfg != nil {\n\t\tctrl.configSourcesUsed = append(ctrl.configSourcesUsed, ctrl.PlatformConfiguration.Name())\n\t}\n\n\tswitch {\n\tcase cfg == nil:\n\t\tfallthrough\n\tcase !cfg.CompleteForBoot():\n\t\t// incomplete or missing config, proceed to maintenance\n\t\treturn ctrl.stateCmdlineLate, cfg, nil\n\tdefault:\n\t\t// complete config, we are done\n\t\treturn ctrl.stateDone, cfg, nil\n\t}\n}\n\n// loadFromPlatform is a helper function for statePlatform.\nfunc (ctrl *AcquireController) loadFromPlatform(ctx context.Context, logger *zap.Logger) (config.Provider, error) {\n\tplatformName := ctrl.PlatformConfiguration.Name()\n\n\tlogger.Info(\"downloading config\", zap.String(\"platform\", platformName))\n\n\tcfgBytes, err := ctrl.PlatformConfiguration.Configuration(ctx)\n\tif err != nil {\n\t\tif errors.Is(err, platformerrors.ErrNoConfigSource) {\n\t\t\t// no config in the platform\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error acquiring via platform %s: %w\", platformName, err)\n\t}\n\n\t// Detect if config is a gzip archive and unzip it if so\n\tcontentType := http.DetectContentType(cfgBytes)\n\tif contentType == \"application/x-gzip\" {\n\t\tvar gzipReader *gzip.Reader\n\n\t\tgzipReader, err = gzip.NewReader(bytes.NewReader(cfgBytes))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating gzip reader: %w\", err)\n\t\t}\n\n\t\t//nolint:errcheck\n\t\tdefer gzipReader.Close()\n\n\t\tvar unzippedData []byte\n\n\t\tunzippedData, err = io.ReadAll(gzipReader)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error unzipping machine config: %w\", err)\n\t\t}\n\n\t\tcfgBytes = unzippedData\n\t}\n\n\tcfg, err := configloader.NewFromBytes(cfgBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load config via platform %s: %w\", platformName, err)\n\t}\n\n\twarnings, err := cfg.Validate(ctrl.ValidationMode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate config acquired via platform %s: %w\", platformName, err)\n\t}\n\n\twarningsRuntime, err := cfg.RuntimeValidate(ctx, ctrl.ResourceState, ctrl.ValidationMode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to runtime validate config acquired via platform %s: %w\", platformName, err)\n\t}\n\n\tfor _, warning := range slices.Concat(warnings, warningsRuntime) {\n\t\tlogger.Warn(\"config validation warning\", zap.String(\"platform\", platformName), zap.String(\"warning\", warning))\n\t}\n\n\treturn cfg, nil\n}\n\n// stateCmdlineLate acquires machine configuration from the kernel cmdline source (talos.config.inline).\n//\n// It is called after the platform source.\n//\n// Transitions:\n//\n//\t--> maintenanceEnter: config loaded from cmdline, but it's incomplete, or no config from cmdline: proceed to maintenance\n//\t--> done: config loaded from cmdline, and it's complete\nfunc (ctrl *AcquireController) stateCmdlineLate(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\treturn ctrl.stateCmdlineGeneric(constants.KernelParamConfigInline, \"cmdline-late\", ctrl.stateMaintenanceEnter)(ctx, r, logger)\n}\n\n// stateCmdlineGeneric is a generic function to load config from cmdline given a parameter name and source name, and the next state in the state machine.\nfunc (ctrl *AcquireController) stateCmdlineGeneric(\n\tparamName, sourceName string, next stateMachineFunc,\n) func(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\treturn func(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\t\tif ctrl.Mode.InContainer() {\n\t\t\t// no cmdline in containers\n\t\t\treturn next, nil, nil\n\t\t}\n\n\t\tcfg, err := ctrl.loadFromCmdline(ctx, logger, paramName)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif cfg != nil {\n\t\t\tctrl.configSourcesUsed = append(ctrl.configSourcesUsed, sourceName)\n\t\t}\n\n\t\tswitch {\n\t\tcase cfg == nil:\n\t\t\tfallthrough\n\t\tcase !cfg.CompleteForBoot():\n\t\t\t// incomplete or missing config, proceed to maintenance\n\t\t\treturn next, cfg, nil\n\t\tdefault:\n\t\t\t// complete config, we are done\n\t\t\treturn ctrl.stateDone, cfg, nil\n\t\t}\n\t}\n}\n\n// loadFromCmdline is a helper function for stateCmdline.\n//\n//nolint:gocyclo\nfunc (ctrl *AcquireController) loadFromCmdline(ctx context.Context, logger *zap.Logger, paramName string) (config.Provider, error) {\n\tcmdline := ctrl.CmdlineGetter()\n\n\tparam := cmdline.Get(paramName)\n\n\tif param == nil {\n\t\treturn nil, nil\n\t}\n\n\tlogger.Info(\"getting config from cmdline\", zap.String(\"param\", paramName))\n\n\tvar cfgEncoded strings.Builder\n\n\tfor i := 0; ; i++ {\n\t\tv := param.Get(i)\n\t\tif v == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcfgEncoded.WriteString(*v)\n\t}\n\n\tcfgDecoded, err := base64.StdEncoding.DecodeString(cfgEncoded.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode base64 config from cmdline %s: %w\", paramName, err)\n\t}\n\n\tzr, err := zstd.NewReader(bytes.NewReader(cfgDecoded))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create zstd reader: %w\", err)\n\t}\n\n\tdefer zr.Close()\n\n\tcfgBytes, err := io.ReadAll(zr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read zstd compressed config from cmdline %s: %w\", paramName, err)\n\t}\n\n\tcfg, err := configloader.NewFromBytes(cfgBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load config via cmdline %s: %w\", paramName, err)\n\t}\n\n\twarnings, err := cfg.Validate(ctrl.ValidationMode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate config acquired via cmdline %s: %w\", paramName, err)\n\t}\n\n\twarningsRuntime, err := cfg.RuntimeValidate(ctx, ctrl.ResourceState, ctrl.ValidationMode)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate config acquired via cmdline %s: %w\", paramName, err)\n\t}\n\n\tfor _, warning := range slices.Concat(warnings, warningsRuntime) {\n\t\tlogger.Warn(\"config validation warning\", zap.String(\"cmdline\", paramName), zap.String(\"warning\", warning))\n\t}\n\n\treturn cfg, nil\n}\n\n// stateMaintenanceEnter initializes maintenance service.\n//\n// Transitions:\n//\n//\t--> stateMaintenance: run the maintenance service\nfunc (ctrl *AcquireController) stateMaintenanceEnter(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\tlogger.Info(\"entering maintenance service\")\n\n\t// nb: we treat maintenance mode as an \"activate\"\n\t// event b/c the user is expected to be able to\n\t// interact with the system at this point.\n\tctrl.PlatformEvent.FireEvent(\n\t\tctx,\n\t\tplatform.Event{\n\t\t\tType:    platform.EventTypeActivate,\n\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t},\n\t)\n\n\t// add \"fake\" events to signal when Talos enters and leaves maintenance mode\n\tctrl.EventPublisher.Publish(ctx, &machineapi.TaskEvent{\n\t\tAction: machineapi.TaskEvent_START,\n\t\tTask:   \"runningMaintenance\",\n\t})\n\n\treturn ctrl.stateMaintenance, nil, nil\n}\n\n// stateMaintenance acquires machine configuration from the maintenance service.\n//\n// Transitions:\n//\n//\t--> maintenanceLeave: config loaded from maintenance service, and it's complete\nfunc (ctrl *AcquireController) stateMaintenance(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\t// init maintenance\n\tif err := safe.WriterModify(ctx, r, runtime.NewMaintenanceServiceRequest(), func(*runtime.MaintenanceServiceRequest) error {\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed creating maintenance service request: %w\", err)\n\t}\n\n\t// check current config\n\tcfgResource, err := safe.ReaderGetByID[*configresource.MachineConfig](ctx, r, configresource.ActiveID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// no config loaded, wait for it\n\t\t\treturn nil, nil, nil\n\t\t}\n\n\t\treturn nil, nil, fmt.Errorf(\"failed to get maintenance config: %w\", err)\n\t}\n\n\tcfg := cfgResource.Provider()\n\n\tif cfg.CompleteForBoot() {\n\t\t// complete config, we are done\n\t\tctrl.configSourcesUsed = append(ctrl.configSourcesUsed, \"maintenance\")\n\n\t\treturn ctrl.stateMaintenanceLeave, nil, nil\n\t}\n\n\t// incomplete config, keep waiting\n\treturn nil, nil, nil\n}\n\n// stateMaintenanceLeave leaves the maintenance service.\n//\n// Transitions:\n//\n//\t--> done: proceed to done state\nfunc (ctrl *AcquireController) stateMaintenanceLeave(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\t// stop the maintenance service\n\tready, err := r.Teardown(ctx, runtime.NewMaintenanceServiceRequest().Metadata())\n\n\tswitch {\n\tcase err != nil && !state.IsNotFoundError(err):\n\t\treturn nil, nil, fmt.Errorf(\"failed to tear down maintenance service: %w\", err)\n\tcase err == nil && !ready:\n\t\t// wait for the maintenance service to be torn down\n\t\treturn nil, nil, nil\n\tcase err == nil && ready:\n\t\tif err = r.Destroy(ctx, runtime.NewMaintenanceServiceRequest().Metadata()); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed cleaning up maintenance service request: %w\", err)\n\t\t}\n\t}\n\n\tctrl.EventPublisher.Publish(ctx, &machineapi.TaskEvent{\n\t\tAction: machineapi.TaskEvent_STOP,\n\t\tTask:   \"runningMaintenance\",\n\t})\n\n\tlogger.Info(\"leaving maintenance service\")\n\n\treturn ctrl.stateDone, nil, nil\n}\n\n// stateDone is the final state of the controller.\nfunc (ctrl *AcquireController) stateDone(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\tif err := safe.WriterModify(ctx, r, v1alpha1.NewAcquireConfigStatus(), func(_ *v1alpha1.AcquireConfigStatus) error {\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to write status: %w\", err)\n\t}\n\n\tctrl.PlatformEvent.FireEvent(\n\t\tctx,\n\t\tplatform.Event{\n\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t},\n\t)\n\n\tlogger.Info(\"machine config loaded successfully\", zap.Strings(\"sources\", ctrl.configSourcesUsed))\n\n\t// fall through to the controller loop\n\treturn ctrl.stateFinal, nil, nil\n}\n\n// stateFinal just makes the controller do nothing.\nfunc (ctrl *AcquireController) stateFinal(ctx context.Context, r controller.Runtime, logger *zap.Logger) (stateMachineFunc, config.Provider, error) {\n\treturn nil, nil, nil\n}\n\nfunc loadConfig(root xfs.Root, configPath string) (config.Provider, error) {\n\tf, err := xfs.Open(root, configPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open %q from STATE: %w\", configPath, err)\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tcfg, err := configloader.NewFromReader(f)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load %q from STATE: %w\", configPath, err)\n\t}\n\n\treturn cfg, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/acquire_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"encoding/base64\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tconfigctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tconfigresource \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\ntype AcquireSuite struct {\n\tctest.DefaultSuite\n\n\tplatformConfig *platformConfigMock\n\tplatformEvent  *platformEventMock\n\tconfigSetter   *configSetterMock\n\teventPublisher *eventPublisherMock\n\tcmdline        *cmdlineGetterMock\n\tembeddedPath   string\n\n\tclusterName           string\n\tcompleteMachineConfig []byte\n\tpartialMachineConfig  []byte\n}\n\ntype platformConfigMock struct {\n\tconfiguration []byte\n\terr           error\n}\n\nfunc (p *platformConfigMock) Configuration(context.Context) ([]byte, error) {\n\treturn p.configuration, p.err\n}\n\nfunc (p *platformConfigMock) Name() string {\n\treturn \"mock\"\n}\n\ntype platformEventMock struct {\n\tmu     sync.Mutex\n\tevents []platform.Event\n}\n\nfunc (p *platformEventMock) FireEvent(_ context.Context, ev platform.Event) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tp.events = append(p.events, ev)\n}\n\nfunc (p *platformEventMock) getEvents() []platform.Event {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn slices.Clone(p.events)\n}\n\ntype configSetterMock struct {\n\tcfgCh          chan config.Provider\n\tpersistedCfgCh chan config.Provider\n}\n\nfunc (c *configSetterMock) SetConfig(cfg config.Provider) error {\n\tc.cfgCh <- cfg\n\n\treturn nil\n}\n\nfunc (c *configSetterMock) SetPersistedConfig(cfg config.Provider) error {\n\tc.persistedCfgCh <- cfg\n\n\treturn nil\n}\n\ntype eventPublisherMock struct {\n\tmu     sync.Mutex\n\tevents []proto.Message\n}\n\nfunc (e *eventPublisherMock) Publish(_ context.Context, ev proto.Message) {\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\n\te.events = append(e.events, ev)\n}\n\nfunc (e *eventPublisherMock) getEvents() []proto.Message {\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\n\treturn slices.Clone(e.events)\n}\n\ntype cmdlineGetterMock struct {\n\tcmdline *procfs.Cmdline\n}\n\nfunc (c *cmdlineGetterMock) Getter() func() *procfs.Cmdline {\n\treturn func() *procfs.Cmdline {\n\t\treturn c.cmdline\n\t}\n}\n\ntype validationModeMock struct{}\n\nfunc (v validationModeMock) String() string {\n\treturn \"mock\"\n}\n\nfunc (v validationModeMock) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (v validationModeMock) InContainer() bool {\n\treturn false\n}\n\nfunc TestAcquireSuite(t *testing.T) {\n\tt.Parallel()\n\n\ts := &AcquireSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 15 * time.Second,\n\t\t},\n\t}\n\n\ts.DefaultSuite.AfterSetup = func(*ctest.DefaultSuite) {\n\t\ts.platformConfig = &platformConfigMock{\n\t\t\terr: errors.ErrNoConfigSource,\n\t\t}\n\t\ts.platformEvent = &platformEventMock{}\n\t\ts.configSetter = &configSetterMock{\n\t\t\tcfgCh:          make(chan config.Provider, 1),\n\t\t\tpersistedCfgCh: make(chan config.Provider, 1),\n\t\t}\n\t\ts.eventPublisher = &eventPublisherMock{}\n\t\ts.cmdline = &cmdlineGetterMock{\n\t\t\tprocfs.NewCmdline(\"\"),\n\t\t}\n\n\t\ts.clusterName = fmt.Sprintf(\"cluster-%d\", rand.Int32())\n\t\tinput, err := generate.NewInput(s.clusterName, \"https://localhost:6443\", \"\")\n\t\ts.Require().NoError(err)\n\n\t\tcfg, err := input.Config(machine.TypeControlPlane)\n\t\ts.Require().NoError(err)\n\n\t\ts.completeMachineConfig, err = cfg.Bytes()\n\t\ts.Require().NoError(err)\n\n\t\tsideroLinkCfg := siderolink.NewConfigV1Alpha1()\n\t\tsideroLinkCfg.APIUrlConfig.URL = must(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))\n\n\t\tpCfg, err := container.New(sideroLinkCfg)\n\t\ts.Require().NoError(err)\n\n\t\ts.partialMachineConfig, err = pCfg.Bytes()\n\t\ts.Require().NoError(err)\n\n\t\ts.embeddedPath = t.TempDir()\n\n\t\ts.Require().NoError(s.Runtime().RegisterController(&configctrl.AcquireController{\n\t\t\tPlatformConfiguration: s.platformConfig,\n\t\t\tPlatformEvent:         s.platformEvent,\n\t\t\tConfigSetter:          s.configSetter,\n\t\t\tMode:                  validationModeMock{},\n\t\t\tCmdlineGetter:         s.cmdline.Getter(),\n\t\t\tEventPublisher:        s.eventPublisher,\n\t\t\tValidationMode:        validationModeMock{},\n\t\t\tResourceState:         s.State(),\n\t\t\tEmbeddedDirectory:     s.embeddedPath,\n\t\t}))\n\t}\n\n\tsuite.Run(t, s)\n}\n\nfunc (suite *AcquireSuite) triggerAcquire() {\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), v1alpha1.NewAcquireConfigSpec()))\n}\n\nfunc (suite *AcquireSuite) waitForConfig(shouldPersist bool) config.Provider {\n\tvar (\n\t\tappliedConfig   config.Provider\n\t\tpersistedConfig config.Provider\n\t)\n\n\tfor {\n\t\tselect {\n\t\tcase cfg := <-suite.configSetter.cfgCh:\n\t\t\tsuite.Require().Nil(appliedConfig)\n\n\t\t\tappliedConfig = cfg\n\t\tcase cfg := <-suite.configSetter.persistedCfgCh:\n\t\t\tsuite.Require().Nil(persistedConfig)\n\t\t\tsuite.Require().True(shouldPersist)\n\n\t\t\tpersistedConfig = cfg\n\t\tcase <-suite.Ctx().Done():\n\t\t\tsuite.Require().Fail(\"timed out waiting for config: applied %v persisted %v\", appliedConfig, persistedConfig)\n\t\t}\n\n\t\tif appliedConfig != nil && (persistedConfig != nil || !shouldPersist) {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif persistedConfig != nil {\n\t\tsuite.Assert().Same(persistedConfig, appliedConfig)\n\t}\n\n\tstatus := v1alpha1.NewAcquireConfigStatus()\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{status.Metadata().ID()}, func(*v1alpha1.AcquireConfigStatus, *assert.Assertions) {})\n\n\treturn appliedConfig\n}\n\nfunc (suite *AcquireSuite) injectViaMaintenance(cfg []byte) {\n\t_, err := suite.State().WatchFor(suite.Ctx(), runtime.NewMaintenanceServiceRequest().Metadata(), state.WithEventTypes(state.Created))\n\tsuite.Require().NoError(err)\n\n\tmCfg, err := configloader.NewFromBytes(cfg)\n\tsuite.Require().NoError(err)\n\n\texistingCfg, err := safe.StateGetByID[*configresource.MachineConfig](suite.Ctx(), suite.State(), configresource.ActiveID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tnewCfg := configresource.NewMachineConfigWithID(mCfg, configresource.ActiveID)\n\n\tif existingCfg == nil {\n\t\tsuite.Create(newCfg)\n\t} else {\n\t\tnewCfg.Metadata().SetVersion(existingCfg.Metadata().Version())\n\t\tsuite.Update(newCfg)\n\t}\n\n\t_, err = suite.State().WatchFor(suite.Ctx(), runtime.NewMaintenanceServiceRequest().Metadata(), state.WithEventTypes(state.Destroyed))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *AcquireSuite) noStateVolume() {\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, constants.StatePartitionLabel)\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseMissing\n\tsuite.Create(volumeStatus)\n}\n\nfunc (suite *AcquireSuite) presentStateVolume() {\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, constants.StatePartitionLabel)\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Create(volumeStatus)\n}\n\nfunc (suite *AcquireSuite) injectViaDisk(cfg []byte, wait bool) {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&configctrl.AcquireController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(statePath, constants.ConfigFilename), cfg, 0o644))\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tif wait {\n\t\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\t\tsuite.Destroy(volumeMountStatus)\n\t}\n}\n\nfunc (suite *AcquireSuite) TestFromDisk() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.presentStateVolume()\n\n\tsuite.triggerAcquire()\n\n\tsuite.injectViaDisk(suite.completeMachineConfig, true)\n\n\tcfg := suite.waitForConfig(false)\n\tsuite.Require().Equal(cfg.Cluster().Name(), suite.clusterName)\n\n\tsuite.Assert().Empty(suite.eventPublisher.getEvents())\n\tsuite.Assert().Equal(\n\t\t[]platform.Event{\n\t\t\t{\n\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t},\n\t\t},\n\t\tsuite.platformEvent.getEvents(),\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromDiskFailure() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.presentStateVolume()\n\n\tsuite.triggerAcquire()\n\n\tsuite.injectViaDisk(slices.Concat([]byte(\"aaa\"), suite.completeMachineConfig), false)\n\n\tsuite.AssertWithin(time.Second, 10*time.Millisecond, func() error {\n\t\tif len(suite.platformEvent.getEvents()) == 0 || len(suite.eventPublisher.getEvents()) == 0 {\n\t\t\treturn retry.ExpectedErrorf(\"no events received\")\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tev := suite.platformEvent.getEvents()[0]\n\tsuite.Assert().Equal(platform.EventTypeFailure, ev.Type)\n\tsuite.Assert().Equal(\"Error loading and validating Talos machine config.\", ev.Message)\n\tsuite.Assert().Equal(\n\t\t\"failed to load \\\"config.yaml\\\" from STATE: error decoding document /v1alpha1/ (line 1): unknown keys found during decoding:\\n\"+\n\t\t\t\"aaaversion: v1alpha1 # Indicates the schema used to decode the contents.\\n\",\n\t\tev.Error.Error(),\n\t)\n\n\tsuite.Assert().Equal(&machineapi.ConfigLoadErrorEvent{\n\t\tError: \"failed to load \\\"config.yaml\\\" from STATE: error decoding document /v1alpha1/ (line 1): unknown keys found during decoding:\\n\" +\n\t\t\t\"aaaversion: v1alpha1 # Indicates the schema used to decode the contents.\\n\",\n\t}, suite.eventPublisher.getEvents()[0])\n}\n\nfunc (suite *AcquireSuite) TestFromDiskToMaintenance() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.presentStateVolume()\n\n\tsuite.triggerAcquire()\n\n\tsuite.injectViaDisk(suite.partialMachineConfig, true)\n\n\tvar cfg config.Provider\n\n\tselect {\n\tcase cfg = <-suite.configSetter.cfgCh:\n\tcase <-suite.configSetter.persistedCfgCh:\n\t\tsuite.Require().Fail(\"should not persist\")\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for config\")\n\t}\n\n\tsuite.Require().Equal(cfg.SideroLink().APIUrl().Host, \"siderolink.api\")\n\n\t// no asserts here, as maintenance injects the config bypassing the controller\n\tsuite.injectViaMaintenance(suite.completeMachineConfig)\n\n\tsuite.Assert().Equal(\n\t\t[]proto.Message{\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_START,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_STOP,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t},\n\t\tsuite.eventPublisher.getEvents(),\n\t)\n\n\tsuite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tassert.New(collect).Equal(\n\t\t\t\t[]platform.Event{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsuite.platformEvent.getEvents(),\n\t\t\t)\n\t\t},\n\t\t2*time.Second,\n\t\t10*time.Millisecond,\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromPlatform() {\n\tsuite.noStateVolume()\n\tsuite.platformConfig.configuration = suite.completeMachineConfig\n\tsuite.platformConfig.err = nil\n\n\tsuite.triggerAcquire()\n\n\tcfg := suite.waitForConfig(true)\n\tsuite.Require().Equal(cfg.Cluster().Name(), suite.clusterName)\n\n\tsuite.Assert().Empty(suite.eventPublisher.getEvents())\n\tsuite.Assert().Equal(\n\t\t[]platform.Event{\n\t\t\t{\n\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t},\n\t\t},\n\t\tsuite.platformEvent.getEvents(),\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromPlatformFailure() {\n\tsuite.noStateVolume()\n\tsuite.platformConfig.err = stderrors.New(\"mock error\")\n\n\tsuite.triggerAcquire()\n\n\tsuite.AssertWithin(time.Second, 10*time.Millisecond, func() error {\n\t\tif len(suite.platformEvent.getEvents()) == 0 || len(suite.eventPublisher.getEvents()) == 0 {\n\t\t\treturn retry.ExpectedErrorf(\"no events received\")\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tev := suite.platformEvent.getEvents()[0]\n\tsuite.Assert().Equal(platform.EventTypeFailure, ev.Type)\n\tsuite.Assert().Equal(\"Error loading and validating Talos machine config.\", ev.Message)\n\tsuite.Assert().Equal(\"error acquiring via platform mock: mock error\", ev.Error.Error())\n\n\tsuite.Assert().Equal(&machineapi.ConfigLoadErrorEvent{\n\t\tError: \"error acquiring via platform mock: mock error\",\n\t}, suite.eventPublisher.getEvents()[0])\n}\n\nfunc (suite *AcquireSuite) TestFromPlatformNotValid() {\n\tsuite.noStateVolume()\n\n\tpatchCfg, err := configloader.NewFromBytes([]byte(`{\"machine\": {\"nodeLabels\": {\"/1\": \"2\"}}}`))\n\tsuite.Require().NoError(err)\n\n\tout, err := configpatcher.Apply(configpatcher.WithBytes(suite.completeMachineConfig), []configpatcher.Patch{\n\t\tconfigpatcher.NewStrategicMergePatch(patchCfg),\n\t})\n\tsuite.Require().NoError(err)\n\n\toutCfg, err := out.Bytes()\n\tsuite.Require().NoError(err)\n\n\tsuite.platformConfig.configuration = outCfg\n\tsuite.platformConfig.err = nil\n\n\tsuite.triggerAcquire()\n\n\tsuite.AssertWithin(time.Second, 10*time.Millisecond, func() error {\n\t\tif len(suite.platformEvent.getEvents()) == 0 || len(suite.eventPublisher.getEvents()) == 0 {\n\t\t\treturn retry.ExpectedErrorf(\"no events received\")\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tev := suite.platformEvent.getEvents()[0]\n\tsuite.Assert().Equal(platform.EventTypeFailure, ev.Type)\n\tsuite.Assert().Equal(\"Error loading and validating Talos machine config.\", ev.Message)\n\tsuite.Assert().Equal(\n\t\t\"failed to validate config acquired via platform mock: 1 error occurred:\\n\"+\n\t\t\t\"\\t* v1alpha1.Config: 1 error occurred:\\n\\t* invalid machine node labels: 1 error occurred:\\n\\t* prefix cannot be empty: \\\"/1\\\"\\n\\n\\n\\n\\n\\n\",\n\t\tev.Error.Error(),\n\t)\n\n\tsuite.Assert().Equal(&machineapi.ConfigLoadErrorEvent{\n\t\tError: \"failed to validate config acquired via platform mock: 1 error occurred:\" +\n\t\t\t\"\\n\\t* v1alpha1.Config: 1 error occurred:\\n\\t* invalid machine node labels: 1 error occurred:\\n\\t* prefix cannot be empty: \\\"/1\\\"\\n\\n\\n\\n\\n\\n\",\n\t}, suite.eventPublisher.getEvents()[0])\n}\n\nfunc (suite *AcquireSuite) TestFromPlatformGzip() {\n\tvar buf bytes.Buffer\n\n\tgz := gzip.NewWriter(&buf)\n\t_, err := gz.Write(suite.completeMachineConfig)\n\tsuite.Require().NoError(err)\n\tsuite.Require().NoError(gz.Close())\n\n\tsuite.platformConfig.configuration = buf.Bytes()\n\tsuite.platformConfig.err = nil\n\n\tsuite.noStateVolume()\n\tsuite.triggerAcquire()\n\n\tcfg := suite.waitForConfig(true)\n\tsuite.Require().Equal(cfg.Cluster().Name(), suite.clusterName)\n\n\tsuite.Assert().Empty(suite.eventPublisher.getEvents())\n\tsuite.Assert().Equal(\n\t\t[]platform.Event{\n\t\t\t{\n\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t},\n\t\t},\n\t\tsuite.platformEvent.getEvents(),\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromPlatformToMaintenance() {\n\tsuite.platformConfig.configuration = suite.partialMachineConfig\n\tsuite.platformConfig.err = nil\n\n\tsuite.noStateVolume()\n\tsuite.triggerAcquire()\n\n\tvar cfg config.Provider\n\n\tselect {\n\tcase cfg = <-suite.configSetter.cfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for config\")\n\t}\n\n\tselect {\n\tcase <-suite.configSetter.persistedCfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for persisted config\")\n\t}\n\n\tsuite.Require().Equal(cfg.SideroLink().APIUrl().Host, \"siderolink.api\")\n\n\t// no asserts here, as maintenance injects the config bypassing the controller\n\tsuite.injectViaMaintenance(suite.completeMachineConfig)\n\n\tsuite.Assert().Equal(\n\t\t[]proto.Message{\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_START,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_STOP,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t},\n\t\tsuite.eventPublisher.getEvents(),\n\t)\n\n\tsuite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tassert.New(collect).Equal(\n\t\t\t\t[]platform.Event{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsuite.platformEvent.getEvents(),\n\t\t\t)\n\t\t},\n\t\t2*time.Second,\n\t\t10*time.Millisecond,\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromCmdlineLateToMaintenance() {\n\tvar cfgCompressed bytes.Buffer\n\n\tzw, err := zstd.NewWriter(&cfgCompressed)\n\tsuite.Require().NoError(err)\n\n\t_, err = zw.Write(suite.partialMachineConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(zw.Close())\n\n\tcfgEncoded := base64.StdEncoding.EncodeToString(cfgCompressed.Bytes())\n\n\tsuite.cmdline.cmdline = procfs.NewCmdline(fmt.Sprintf(\"%s=%s\", constants.KernelParamConfigInline, cfgEncoded))\n\n\tsuite.noStateVolume()\n\tsuite.triggerAcquire()\n\n\tvar cfg config.Provider\n\n\tselect {\n\tcase cfg = <-suite.configSetter.cfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for config\")\n\t}\n\n\tselect {\n\tcase <-suite.configSetter.persistedCfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for persisted config\")\n\t}\n\n\tsuite.Require().Equal(cfg.SideroLink().APIUrl().Host, \"siderolink.api\")\n\n\t// no asserts here, as maintenance injects the config bypassing the controller\n\tsuite.injectViaMaintenance(suite.completeMachineConfig)\n\n\tsuite.Assert().Equal(\n\t\t[]proto.Message{\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_START,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_STOP,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t},\n\t\tsuite.eventPublisher.getEvents(),\n\t)\n\n\tsuite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tassert.New(collect).Equal(\n\t\t\t\t[]platform.Event{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsuite.platformEvent.getEvents(),\n\t\t\t)\n\t\t},\n\t\t2*time.Second,\n\t\t10*time.Millisecond,\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromCmdlineEarlyToPlatform() {\n\tvar cfgCompressed bytes.Buffer\n\n\tzw, err := zstd.NewWriter(&cfgCompressed)\n\tsuite.Require().NoError(err)\n\n\t_, err = zw.Write(suite.partialMachineConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(zw.Close())\n\n\tcfgEncoded := base64.StdEncoding.EncodeToString(cfgCompressed.Bytes())\n\n\tsuite.cmdline.cmdline = procfs.NewCmdline(fmt.Sprintf(\"%s=%s\", constants.KernelParamConfigEarly, cfgEncoded))\n\n\tsuite.noStateVolume()\n\tsuite.platformConfig.configuration = suite.completeMachineConfig\n\tsuite.platformConfig.err = nil\n\tsuite.triggerAcquire()\n\n\tvar cfg config.Provider\n\n\tselect {\n\tcase cfg = <-suite.configSetter.cfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for config\")\n\t}\n\n\tselect {\n\tcase <-suite.configSetter.persistedCfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for persisted config\")\n\t}\n\n\tsuite.Require().Equal(cfg.SideroLink().APIUrl().Host, \"siderolink.api\")\n\n\tcfg = suite.waitForConfig(true)\n\tsuite.Require().Equal(cfg.Cluster().Name(), suite.clusterName)\n\n\tsuite.Assert().Empty(suite.eventPublisher.getEvents())\n\tsuite.Assert().Equal(\n\t\t[]platform.Event{\n\t\t\t{\n\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t},\n\t\t},\n\t\tsuite.platformEvent.getEvents(),\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromMaintenance() {\n\tsuite.noStateVolume()\n\tsuite.triggerAcquire()\n\n\t// no asserts here, as maintenance injects the config bypassing the controller\n\tsuite.injectViaMaintenance(suite.completeMachineConfig)\n\n\tsuite.Assert().Equal(\n\t\t[]proto.Message{\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_START,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_STOP,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t},\n\t\tsuite.eventPublisher.getEvents(),\n\t)\n\n\tsuite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tassert.New(collect).Equal(\n\t\t\t\t[]platform.Event{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsuite.platformEvent.getEvents(),\n\t\t\t)\n\t\t},\n\t\t2*time.Second,\n\t\t10*time.Millisecond,\n\t)\n}\n\nfunc (suite *AcquireSuite) TestFromEmbeddedToMaintenance() {\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(suite.embeddedPath, constants.ConfigFilename), suite.partialMachineConfig, 0o644))\n\n\tsuite.noStateVolume()\n\tsuite.triggerAcquire()\n\n\tvar cfg config.Provider\n\n\tselect {\n\tcase cfg = <-suite.configSetter.cfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for config\")\n\t}\n\n\tselect {\n\tcase <-suite.configSetter.persistedCfgCh:\n\tcase <-suite.Ctx().Done():\n\t\tsuite.Require().Fail(\"timed out waiting for persisted config\")\n\t}\n\n\tsuite.Require().Equal(cfg.SideroLink().APIUrl().Host, \"siderolink.api\")\n\n\t// no asserts here, as maintenance injects the config bypassing the controller\n\tsuite.injectViaMaintenance(suite.completeMachineConfig)\n\n\tsuite.Assert().Equal(\n\t\t[]proto.Message{\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_START,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t\t&machineapi.TaskEvent{\n\t\t\t\tAction: machineapi.TaskEvent_STOP,\n\t\t\t\tTask:   \"runningMaintenance\",\n\t\t\t},\n\t\t},\n\t\tsuite.eventPublisher.getEvents(),\n\t)\n\n\tsuite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tassert.New(collect).Equal(\n\t\t\t\t[]platform.Event{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\t\t\tMessage: \"Talos booted into maintenance mode. Ready for user interaction.\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:    platform.EventTypeConfigLoaded,\n\t\t\t\t\t\tMessage: \"Talos machine config loaded successfully.\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsuite.platformEvent.getEvents(),\n\t\t\t)\n\t\t},\n\t\t2*time.Second,\n\t\t10*time.Millisecond,\n\t)\n}\n\nfunc must[T any](t T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn t\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package config provides controllers which manage config resources.\npackage config\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/machine_type.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// MachineTypeController manages config.MachineType based on configuration.\ntype MachineTypeController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MachineTypeController) Name() string {\n\treturn \"config.MachineTypeController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MachineTypeController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MachineTypeController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: config.MachineTypeType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *MachineTypeController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar machineType machine.Type\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else if cfg.Config().Machine() != nil {\n\t\t\tmachineType = cfg.Config().Machine().Type()\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, config.NewMachineType(), func(r *config.MachineType) error {\n\t\t\tr.SetMachineType(machineType)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating objects: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/persistence.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// PersistenceController ensures that the machine configuration is persisted in STATE partition.\ntype PersistenceController struct {\n\tlastPersistedVersion resource.Version\n\tconfigToPersist      *config.MachineConfig\n\tstateMachine         blockautomaton.VolumeMounterAutomaton\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PersistenceController) Name() string {\n\treturn \"config.PersistenceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PersistenceController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.PersistentID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tID:        optional.Some(constants.StatePartitionLabel),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeLifecycleType,\n\t\t\tID:        optional.Some(block.VolumeLifecycleID),\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PersistenceController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *PersistenceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvolumeLifecycle, err := safe.ReaderGetByID[*block.VolumeLifecycle](ctx, r, block.VolumeLifecycleID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching volume lifecycle: %w\", err)\n\t\t}\n\n\t\tif volumeLifecycle == nil {\n\t\t\t// no volume lifecycle, cease all operations\n\t\t\tcontinue\n\t\t}\n\n\t\tif volumeLifecycle.Metadata().Phase() == resource.PhaseRunning {\n\t\t\tif err = r.AddFinalizer(ctx, volumeLifecycle.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer to volume lifecycle: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tstateStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, constants.StatePartitionLabel)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error fetching STATE volume status: %w\", err)\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.PersistentID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tif cfg != nil && !ctrl.lastPersistedVersion.Equal(cfg.Metadata().Version()) {\n\t\t\t// if the version is newer than the last persisted version\n\t\t\tctrl.configToPersist = cfg\n\t\t}\n\n\t\tif ctrl.stateMachine == nil && ctrl.configToPersist != nil {\n\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\tctrl.Name(),\n\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\tctrl.persistMachineConfig,\n\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t)\n\t\t}\n\n\t\tif ctrl.stateMachine != nil {\n\t\t\terr := ctrl.stateMachine.Run(ctx, r, logger,\n\t\t\t\tautomaton.WithAfterFunc(func() error {\n\t\t\t\t\tctrl.stateMachine = nil\n\n\t\t\t\t\tr.QueueReconcile()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error running state machine: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif volumeLifecycle.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t\tif ctrl.configToPersist == nil || (stateStatus != nil && stateStatus.TypedSpec().Phase == block.VolumePhaseMissing) {\n\t\t\t\tif err = r.RemoveFinalizer(ctx, volumeLifecycle.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *PersistenceController) persistMachineConfig(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\ttempName := constants.ConfigFilename + \"-tmp\"\n\n\t\tconfigContents, err := ctrl.configToPersist.Provider().Bytes()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting config bytes: %w\", err)\n\t\t}\n\n\t\tif err = xfs.WriteFile(root, tempName, configContents, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing config to file: %w\", err)\n\t\t}\n\n\t\tif err = xfs.Rename(root, tempName, constants.ConfigFilename); err != nil {\n\t\t\treturn fmt.Errorf(\"error renaming config file: %w\", err)\n\t\t}\n\n\t\tlogger.Info(\"machine configuration persisted to STATE\")\n\n\t\tctrl.lastPersistedVersion = ctrl.configToPersist.Metadata().Version()\n\t\tctrl.configToPersist = nil\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/config/persistence_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tconfigctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\ntype PersistenceSuite struct {\n\tctest.DefaultSuite\n\n\tcfg1, cfg2 talosconfig.Provider\n}\n\nfunc (suite *PersistenceSuite) TestPersist() {\n\tvolumeLifecycle := block.NewVolumeLifecycle(block.NamespaceName, block.VolumeLifecycleID)\n\tsuite.Create(volumeLifecycle)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.False(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tstatePath := suite.T().TempDir()\n\tmountID := (&configctrl.PersistenceController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\tc1 := config.NewMachineConfigWithID(suite.cfg1, config.PersistentID)\n\tsuite.Create(c1)\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.FileExists(filepath.Join(statePath, constants.ConfigFilename))\n\t}, time.Second, 10*time.Millisecond)\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\tc2 := config.NewMachineConfigWithID(suite.cfg2, config.PersistentID)\n\tc2.Metadata().SetVersion(c1.Metadata().Version())\n\tsuite.Update(c2)\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\t// teardown the volume lifecycle, but finalizer should not be removed yet\n\t_, err := suite.State().Teardown(suite.Ctx(), volumeLifecycle.Metadata())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.False(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tvolumeMountStatus = block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tcontents, err := os.ReadFile(filepath.Join(statePath, constants.ConfigFilename))\n\t\tasrt.NoError(err)\n\n\t\tasrt.Contains(string(contents), \"jointoken=none\")\n\t}, time.Second, 10*time.Millisecond)\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.True(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeLifecycle)\n}\n\nfunc (suite *PersistenceSuite) TestConfig() {\n\tvolumeLifecycle := block.NewVolumeLifecycle(block.NamespaceName, block.VolumeLifecycleID)\n\tsuite.Create(volumeLifecycle)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.False(vl.Metadata().Finalizers().Empty())\n\t})\n\n\t_, err := suite.State().Teardown(suite.Ctx(), volumeLifecycle.Metadata())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.True(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeLifecycle)\n}\n\nfunc (suite *PersistenceSuite) TestNoPersistenceWithMissingState() {\n\tvolumeLifecycle := block.NewVolumeLifecycle(block.NamespaceName, block.VolumeLifecycleID)\n\tsuite.Create(volumeLifecycle)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.False(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tc1 := config.NewMachineConfigWithID(suite.cfg1, config.PersistentID)\n\tsuite.Create(c1)\n\n\t_, err := suite.State().Teardown(suite.Ctx(), volumeLifecycle.Metadata())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.False(vl.Metadata().Finalizers().Empty())\n\t})\n\n\t// simulate STATE missing\n\tvolumeStatus := block.NewVolumeStatus(block.NamespaceName, constants.StatePartitionLabel)\n\tvolumeStatus.TypedSpec().Phase = block.VolumePhaseMissing\n\tsuite.Create(volumeStatus)\n\n\tctest.AssertResource(suite, block.VolumeLifecycleID, func(vl *block.VolumeLifecycle, asrt *assert.Assertions) {\n\t\tasrt.True(vl.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeLifecycle)\n}\n\nfunc TestPersistenceSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsideroLinkCfg1 := siderolink.NewConfigV1Alpha1()\n\tsideroLinkCfg1.APIUrlConfig.URL = must(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))\n\n\tcfg1, err := container.New(sideroLinkCfg1)\n\trequire.NoError(t, err)\n\n\tsideroLinkCfg2 := siderolink.NewConfigV1Alpha1()\n\tsideroLinkCfg2.APIUrlConfig.URL = must(url.Parse(\"https://siderolink.api/?jointoken=none&user=bob\"))\n\n\tcfg2, err := container.New(sideroLinkCfg2)\n\trequire.NoError(t, err)\n\n\tsuite.Run(t, &PersistenceSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&configctrl.PersistenceController{}))\n\t\t\t},\n\t\t},\n\n\t\tcfg1: cfg1,\n\t\tcfg2: cfg2,\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cri provides CRI related controllers.\npackage cri\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/cri_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\n// BuildExpectedDigests is exported for testing.\nvar BuildExpectedDigests = buildExpectedDigests\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/image_cache_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/google/cel-go/common/ast\"\n\t\"github.com/google/cel-go/common/operators\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tcfg \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// ServiceManager is the interface to the v1alpha1 services subsystems.\ntype ServiceManager interface {\n\tIsRunning(id string) (system.Service, bool, error)\n\tLoad(services ...system.Service) []string\n\tStart(serviceIDs ...string) error\n}\n\n// ImageCacheConfigController manages configures Image Cache.\ntype ImageCacheConfigController struct {\n\tV1Alpha1ServiceManager ServiceManager\n\n\tDisableCacheCopy bool // used for testing\n\n\tcacheCopyDone bool\n}\n\n// Name implements controller.StatsController interface.\nfunc (ctrl *ImageCacheConfigController) Name() string {\n\treturn \"cri.ImageCacheConfigController\"\n}\n\n// Inputs implements controller.StatsController interface.\nfunc (ctrl *ImageCacheConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(RegistrydServiceID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.StatsController interface.\nfunc (ctrl *ImageCacheConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cri.ImageCacheConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeConfigType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Volume configuration constants.\nconst (\n\tVolumeImageCacheISO  = \"IMAGECACHE-ISO\"\n\tVolumeImageCacheDISK = constants.ImageCachePartitionLabel\n\n\tMinImageCacheSize = 500 * 1024 * 1024      // 500MB\n\tMaxImageCacheSize = 1 * 1024 * 1024 * 1024 // 1GB\n\n\tRegistrydServiceID = services.RegistryID\n)\n\n// Run implements controller.StatsController interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ImageCacheConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tregistryDService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, RegistrydServiceID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting service: %w\", err)\n\t\t}\n\n\t\t// image cache is disabled\n\t\timageCacheDisabled := cfg == nil || cfg.Config().Machine() == nil || !cfg.Config().Machine().Features().ImageCache().LocalEnabled()\n\n\t\tvar (\n\t\t\tstatus     cri.ImageCacheStatus\n\t\t\tcopyStatus cri.ImageCacheCopyStatus\n\t\t\troots      []string\n\t\t\tallReady   bool\n\t\t)\n\n\t\tif imageCacheDisabled {\n\t\t\tstatus = cri.ImageCacheStatusDisabled\n\t\t\tcopyStatus = cri.ImageCacheCopyStatusSkipped\n\t\t} else {\n\t\t\tstatus = cri.ImageCacheStatusPreparing\n\n\t\t\t// image cache is enabled, so create the volume config resources to find the image cache roots\n\t\t\tif err = ctrl.createVolumeConfigISO(ctx, r); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating volume config: %w\", err)\n\t\t\t}\n\n\t\t\tif err = ctrl.createVolumeConfigDisk(ctx, r, cfg.Config()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating volume config: %w\", err)\n\t\t\t}\n\n\t\t\tcacheVolumeStatus, err := ctrl.analyzeImageCacheVolumes(ctx, logger, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error analyzing image cache volumes: %w\", err)\n\t\t\t}\n\n\t\t\tallReady = cacheVolumeStatus.allReady\n\t\t\troots = cacheVolumeStatus.roots\n\t\t\tcopyStatus = cacheVolumeStatus.copyStatus\n\n\t\t\tif allReady && len(roots) == 0 {\n\t\t\t\t// all volumes identified, but no roots found\n\t\t\t\tstatus = cri.ImageCacheStatusDisabled\n\t\t\t}\n\t\t}\n\n\t\tif status == cri.ImageCacheStatusPreparing && len(roots) > 0 {\n\t\t\t_, running, err := ctrl.V1Alpha1ServiceManager.IsRunning(RegistrydServiceID)\n\t\t\tif err != nil {\n\t\t\t\tctrl.V1Alpha1ServiceManager.Load(services.NewRegistryD())\n\t\t\t}\n\n\t\t\tif !running {\n\t\t\t\tif err = ctrl.V1Alpha1ServiceManager.Start(RegistrydServiceID); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error starting service: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif registryDService != nil && registryDService.TypedSpec().Running && registryDService.TypedSpec().Healthy {\n\t\t\t\tstatus = cri.ImageCacheStatusReady\n\t\t\t}\n\t\t}\n\n\t\tlogger.Debug(\"image cache status\", zap.String(\"status\", status.String()), zap.String(\"copy_status\", copyStatus.String()))\n\n\t\tif err = safe.WriterModify(ctx, r, cri.NewImageCacheConfig(), func(cfg *cri.ImageCacheConfig) error {\n\t\t\tcfg.TypedSpec().Status = status\n\t\t\tcfg.TypedSpec().CopyStatus = copyStatus\n\t\t\tcfg.TypedSpec().Roots = roots\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing ImageCacheConfig: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *ImageCacheConfigController) createVolumeConfigISO(ctx context.Context, r controller.ReaderWriter) error {\n\tbuilder := cel.NewBuilder(celenv.VolumeLocator())\n\n\t// volume.name in [\"iso9660\", \"vfat\"] && volume.label.startsWith(\"TALOS_\")\n\texpr := builder.NewCall(\n\t\tbuilder.NextID(),\n\t\toperators.LogicalAnd,\n\t\tbuilder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.In,\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\t\"name\",\n\t\t\t),\n\t\t\tbuilder.NewList(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\t[]ast.Expr{\n\t\t\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(\"iso9660\")),\n\t\t\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(\"vfat\")),\n\t\t\t\t},\n\t\t\t\tnil,\n\t\t\t),\n\t\t),\n\t\tbuilder.NewMemberCall(\n\t\t\tbuilder.NextID(),\n\t\t\t\"startsWith\",\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\t\"label\",\n\t\t\t),\n\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(\"TALOS_\")),\n\t\t),\n\t)\n\n\tboolExpr, err := builder.ToBooleanExpression(expr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating boolean expression: %w\", err)\n\t}\n\n\treturn safe.WriterModify(ctx, r, block.NewVolumeConfig(block.NamespaceName, VolumeImageCacheISO), func(volumeCfg *block.VolumeConfig) error {\n\t\tvolumeCfg.TypedSpec().Type = block.VolumeTypeDisk\n\t\tvolumeCfg.TypedSpec().Locator = block.LocatorSpec{\n\t\t\tMatch: *boolExpr,\n\t\t}\n\t\tvolumeCfg.TypedSpec().Mount = block.MountSpec{\n\t\t\tTargetPath: constants.ImageCacheISOMountPoint,\n\t\t\tFileMode:   0o700,\n\t\t\tUID:        0,\n\t\t\tGID:        0,\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (ctrl *ImageCacheConfigController) createVolumeConfigDisk(ctx context.Context, r controller.ReaderWriter, cfg cfg.Config) error {\n\tbuilder := cel.NewBuilder(celenv.VolumeLocator())\n\n\t// volume.partition_label == \"IMAGECACHE\"\n\texpr := builder.NewCall(\n\t\tbuilder.NextID(),\n\t\toperators.Equals,\n\t\tbuilder.NewSelect(\n\t\t\tbuilder.NextID(),\n\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\"partition_label\",\n\t\t),\n\t\tbuilder.NewLiteral(builder.NextID(), types.String(constants.ImageCachePartitionLabel)),\n\t)\n\n\tlocatorExpr, err := builder.ToBooleanExpression(expr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating boolean expression: %w\", err)\n\t}\n\n\t// system_disk\n\tbuilder = cel.NewBuilder(celenv.DiskLocator())\n\n\texpr = builder.NewIdent(builder.NextID(), \"system_disk\")\n\n\tdiskExpr, err := builder.ToBooleanExpression(expr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating boolean expression: %w\", err)\n\t}\n\n\treturn safe.WriterModify(ctx, r, block.NewVolumeConfig(block.NamespaceName, VolumeImageCacheDISK), func(volumeCfg *block.VolumeConfig) error {\n\t\tvolumeCfg.TypedSpec().Type = block.VolumeTypePartition\n\t\tvolumeCfg.TypedSpec().Locator = block.LocatorSpec{\n\t\t\tMatch: *locatorExpr,\n\t\t}\n\n\t\tif extraCfg, ok := cfg.Volumes().ByName(constants.ImageCachePartitionLabel); ok {\n\t\t\tvolumeCfg.TypedSpec().Provisioning.Wave = block.WaveSystemDisk\n\t\t\tvolumeCfg.TypedSpec().Provisioning.DiskSelector.Match = extraCfg.Provisioning().DiskSelector().ValueOr(*diskExpr)\n\t\t\tvolumeCfg.TypedSpec().Provisioning.PartitionSpec.Grow = extraCfg.Provisioning().Grow().ValueOr(false)\n\t\t\tvolumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize = extraCfg.Provisioning().MinSize().ValueOr(MinImageCacheSize)\n\t\t\tvolumeCfg.TypedSpec().Provisioning.PartitionSpec.MaxSize = extraCfg.Provisioning().MaxSize().ValueOr(MaxImageCacheSize)\n\t\t\tvolumeCfg.TypedSpec().Provisioning.PartitionSpec.Label = constants.ImageCachePartitionLabel\n\t\t\tvolumeCfg.TypedSpec().Provisioning.PartitionSpec.TypeUUID = partition.LinuxFilesystemData\n\t\t\tvolumeCfg.TypedSpec().Provisioning.FilesystemSpec.Type = block.FilesystemTypeEXT4\n\n\t\t\tif err := blockadapter.VolumeConfigSpec(volumeCfg.TypedSpec()).ApplyEncryptionConfig(extraCfg.Encryption()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying encryption config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvolumeCfg.TypedSpec().Mount = block.MountSpec{\n\t\t\tTargetPath: constants.ImageCacheDiskMountPoint,\n\t\t\tFileMode:   0o700,\n\t\t\tUID:        0,\n\t\t\tGID:        0,\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\ntype imageCacheVolumeStatus struct {\n\troots      []string\n\tallReady   bool\n\tcopyStatus cri.ImageCacheCopyStatus\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *ImageCacheConfigController) analyzeImageCacheVolumes(ctx context.Context, logger *zap.Logger, r controller.ReaderWriter) (*imageCacheVolumeStatus, error) {\n\tvolumeIDs := []string{VolumeImageCacheDISK, VolumeImageCacheISO} // prefer disk cache over ISO cache\n\tvolumeStatuses := make([]*block.VolumeStatus, 0, len(volumeIDs))\n\n\tfor _, volumeID := range volumeIDs {\n\t\tvolumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, volumeID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// wait for volume statuses to be present\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"error getting volume status: %w\", err)\n\t\t}\n\n\t\tvolumeStatuses = append(volumeStatuses, volumeStatus)\n\t}\n\n\t// we need to ensure that we first wait for the ISO to be either missing or ready,\n\t// so that we can make a decision on copying the image cache from an ISO to the disk volume\n\tvar isoStatus, diskStatus block.VolumePhase\n\n\tfor _, volumeStatus := range volumeStatuses {\n\t\tswitch volumeStatus.Metadata().ID() {\n\t\tcase VolumeImageCacheISO:\n\t\t\tisoStatus = volumeStatus.TypedSpec().Phase\n\t\tcase VolumeImageCacheDISK:\n\t\t\tdiskStatus = volumeStatus.TypedSpec().Phase\n\t\t}\n\t}\n\n\tisoPresent := isoStatus == block.VolumePhaseReady\n\tdiskMissing := diskStatus == block.VolumePhaseMissing\n\n\tfor _, volumeStatus := range volumeStatuses {\n\t\tvolumeID := volumeStatus.Metadata().ID()\n\n\t\t// create a mount request for the volume, it doesn't matter if the volume is ready or not,\n\t\t// but we want them to be mounted whenever they are ready\n\t\tmountID := ctrl.Name() + \"-\" + volumeID\n\n\t\tif err := safe.WriterModify(ctx, r, block.NewVolumeMountRequest(block.NamespaceName, mountID),\n\t\t\tfunc(mountRequest *block.VolumeMountRequest) error {\n\t\t\t\tmountRequest.TypedSpec().Requester = ctrl.Name()\n\t\t\t\tmountRequest.TypedSpec().VolumeID = volumeID\n\t\t\t\tmountRequest.TypedSpec().ReadOnly = !(volumeStatus.Metadata().ID() == VolumeImageCacheDISK && isoPresent)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating volume mount request: %w\", err)\n\t\t}\n\t}\n\n\troots := make([]string, 0, len(volumeIDs))\n\n\tvar (\n\t\tisoReady, diskReady    bool\n\t\tcopySource, copyTarget string\n\t)\n\n\tallReady := true\n\n\t// analyze volume statuses, and build the roots\n\tfor _, volumeStatus := range volumeStatuses {\n\t\t// mount as rw only disk cache if the ISO cache is present\n\t\troot, ready, err := ctrl.getImageCacheRoot(ctx, r, volumeStatus)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error getting image cache root: %w\", err)\n\t\t}\n\n\t\tif ready {\n\t\t\tswitch volumeStatus.Metadata().ID() {\n\t\t\tcase VolumeImageCacheISO:\n\t\t\t\tisoReady = true\n\t\t\t\tcopySource = root.ValueOr(\"\")\n\t\t\t\tlogger = logger.With(zap.String(\"iso_size\", volumeStatus.TypedSpec().PrettySize))\n\t\t\tcase VolumeImageCacheDISK:\n\t\t\t\tdiskReady = true\n\t\t\t\tcopyTarget = root.ValueOr(\"\")\n\t\t\t\tlogger = logger.With(zap.String(\"disk_size\", volumeStatus.TypedSpec().PrettySize))\n\t\t\t}\n\t\t}\n\n\t\tallReady = allReady && ready\n\n\t\tif rootPath, ok := root.Get(); ok {\n\t\t\troots = append(roots, rootPath)\n\t\t}\n\t}\n\n\tlogger = logger.With(zap.Bool(\"all_ready\", allReady))\n\n\tvar copyStatus cri.ImageCacheCopyStatus\n\n\tswitch {\n\tcase !isoPresent:\n\t\t// if there's no ISO, we don't need to copy anything\n\t\tcopyStatus = cri.ImageCacheCopyStatusSkipped\n\tcase diskMissing:\n\t\t// if the disk volume is not configured, we can't copy the image cache\n\t\tcopyStatus = cri.ImageCacheCopyStatusSkipped\n\tcase ctrl.cacheCopyDone:\n\t\t// if the copy has already been done, we don't need to do it again\n\t\tcopyStatus = cri.ImageCacheCopyStatusReady\n\tcase isoReady && diskReady && copySource != \"\" && copyTarget != \"\":\n\t\t// ready to copy\n\t\tif err := ctrl.copyImageCache(ctx, logger, copySource, copyTarget); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error copying image cache: %w\", err)\n\t\t}\n\n\t\tcopyStatus = cri.ImageCacheCopyStatusReady\n\tdefault:\n\t\t// waiting for copy preconditions\n\t\tcopyStatus = cri.ImageCacheCopyStatusPending\n\t}\n\n\treturn &imageCacheVolumeStatus{\n\t\troots:      roots,\n\t\tallReady:   allReady,\n\t\tcopyStatus: copyStatus,\n\t}, nil\n}\n\nfunc (ctrl *ImageCacheConfigController) getImageCacheRoot(\n\tctx context.Context, r controller.ReaderWriter, volumeStatus *block.VolumeStatus,\n) (optional.Optional[string], bool, error) {\n\tswitch volumeStatus.TypedSpec().Phase { //nolint:exhaustive\n\tcase block.VolumePhaseMissing, block.VolumePhaseFailed, block.VolumePhaseWaiting:\n\t\t// image cache is missing\n\t\treturn optional.None[string](), true, nil\n\tcase block.VolumePhaseReady:\n\t\t// fall through to below\n\tdefault:\n\t\t// undetermined status\n\t\treturn optional.None[string](), false, nil\n\t}\n\n\tvolumeID := volumeStatus.Metadata().ID()\n\n\tmountID := ctrl.Name() + \"-\" + volumeID\n\n\tmountStatus, err := safe.ReaderGetByID[*block.VolumeMountStatus](ctx, r, mountID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn optional.None[string](), false, nil\n\t\t}\n\n\t\treturn optional.None[string](), false, fmt.Errorf(\"error fetching volume mount status: %w\", err)\n\t}\n\n\tif mountStatus.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t// the mount status is being torn down, so we should stop using it\n\t\tif err = r.RemoveFinalizer(ctx, mountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn optional.None[string](), false, fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t}\n\n\t\treturn optional.None[string](), true, nil\n\t}\n\n\t// put a finalizer on the mount status, meaning that we are using it\n\tif !mountStatus.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\tif err = r.AddFinalizer(ctx, mountStatus.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn optional.None[string](), false, fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t}\n\t}\n\n\ttargetPath := mountStatus.TypedSpec().Target\n\n\tif volumeID == VolumeImageCacheISO {\n\t\t// the ISO volume has a subdirectory with the actual image cache\n\t\ttargetPath = filepath.Join(targetPath, \"imagecache\")\n\t}\n\n\treturn optional.Some(targetPath), true, nil\n}\n\nfunc (ctrl *ImageCacheConfigController) copyImageCache(ctx context.Context, logger *zap.Logger, source, target string) error {\n\tlogger.Info(\"copying image cache\", zap.String(\"source\", source), zap.String(\"target\", target))\n\n\tif ctrl.DisableCacheCopy {\n\t\t// used for testing\n\t\treturn nil\n\t}\n\n\tvar bytesCopied int64\n\n\tif err := filepath.WalkDir(source, func(path string, d fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error walking source directory: %w\", err)\n\t\t} else if err = ctx.Err(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trelPath, err := filepath.Rel(source, path)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting relative path: %w\", err)\n\t\t}\n\n\t\ttargetPath := filepath.Join(target, relPath)\n\n\t\tinfo, err := d.Info()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting file info: %w\", err)\n\t\t}\n\n\t\t// we only support directories and files\n\t\tswitch {\n\t\tcase info.Mode().IsDir():\n\t\t\tif err := os.MkdirAll(targetPath, 0o755); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating directory: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\tcase info.Mode().IsRegular():\n\t\t\tbytesCopied += info.Size()\n\n\t\t\treturn copyFileSafe(path, targetPath)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported file type %s: %s\", info.Mode(), path)\n\t\t}\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error copying image cache: %w\", err)\n\t}\n\n\tlogger.Info(\"image cache copied\", zap.String(\"size\", humanize.IBytes(uint64(bytesCopied))))\n\n\tctrl.cacheCopyDone = true\n\n\treturn nil\n}\n\nfunc copyFileSafe(src, dst string) error {\n\tsrcStat, err := os.Stat(src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting source file info: %w\", err)\n\t}\n\n\tdstStat, err := os.Stat(dst)\n\tif err == nil && srcStat.Size() == dstStat.Size() {\n\t\t// skipping copy\n\t\treturn nil\n\t}\n\n\tsrcFile, err := os.Open(src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening source file: %w\", err)\n\t}\n\n\tdefer srcFile.Close() //nolint:errcheck\n\n\ttempPath := dst + \".tmp\"\n\n\tdstFile, err := os.Create(tempPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating destination file: %w\", err)\n\t}\n\n\tdefer dstFile.Close() //nolint:errcheck\n\n\tif _, err = io.Copy(dstFile, srcFile); err != nil {\n\t\treturn fmt.Errorf(\"error copying file: %w, source size is %d\", err, srcStat.Size())\n\t}\n\n\tif err = dstFile.Close(); err != nil {\n\t\treturn fmt.Errorf(\"error closing destination file: %w\", err)\n\t}\n\n\tif err = os.Rename(tempPath, dst); err != nil {\n\t\treturn fmt.Errorf(\"error renaming file: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/image_cache_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tcrictrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\tv1alpha1res \"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileNoConfig() {\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t})\n}\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileFeatureNotEnabled() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t})\n}\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileFeatureEnabled() {\n\tctrlName := (&crictrl.ImageCacheConfigController{}).Name()\n\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tImageCacheSupport: &v1alpha1.ImageCacheConfig{\n\t\t\t\t\tCacheLocalEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crictrl.VolumeImageCacheISO, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(`volume.name in [\"iso9660\", \"vfat\"] && volume.label.startsWith(\"TALOS_\")`, r.TypedSpec().Locator.Match.String())\n\t})\n\tctest.AssertResource(suite, crictrl.VolumeImageCacheDISK, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(`volume.partition_label == \"IMAGECACHE\"`, r.TypedSpec().Locator.Match.String())\n\t})\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t})\n\n\t// create volume statuses to simulate the volume being ready\n\tvs1 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheISO)\n\tvs1.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs1))\n\n\tvs2 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheDISK)\n\tvs2.TypedSpec().Phase = block.VolumePhaseWaiting\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs2))\n\n\t// controller should create mount requests\n\tctest.AssertResources(suite,\n\t\t[]string{\n\t\t\tctrlName + \"-\" + crictrl.VolumeImageCacheISO,\n\t\t\tctrlName + \"-\" + crictrl.VolumeImageCacheDISK,\n\t\t},\n\t\tfunc(vmr *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(vmr.TypedSpec().VolumeID == crictrl.VolumeImageCacheISO, vmr.TypedSpec().ReadOnly)\n\t\t},\n\t)\n\n\t// simulate ISO being mounted\n\tvms1 := block.NewVolumeMountStatus(block.NamespaceName, ctrlName+\"-\"+crictrl.VolumeImageCacheISO)\n\tvms1.TypedSpec().ReadOnly = true\n\tvms1.TypedSpec().Target = constants.ImageCacheISOMountPoint\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vms1))\n\n\t// one volume is ready, but second one is not (yet)\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusPending, r.TypedSpec().CopyStatus)\n\t\tasrt.Equal([]string{filepath.Join(constants.ImageCacheISOMountPoint, \"imagecache\")}, r.TypedSpec().Roots)\n\t})\n\n\t// mark second as ready\n\tvs2.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), vs2))\n\n\t// simulate disk being mounted\n\tvms2 := block.NewVolumeMountStatus(block.NamespaceName, ctrlName+\"-\"+crictrl.VolumeImageCacheDISK)\n\tvms2.TypedSpec().ReadOnly = false\n\tvms2.TypedSpec().Target = constants.ImageCacheDiskMountPoint\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vms2))\n\n\t// now both volumes are ready, but service hasn't started yet\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status)\n\t\tasrt.Equal([]string{constants.ImageCacheDiskMountPoint, filepath.Join(constants.ImageCacheISOMountPoint, \"imagecache\")}, r.TypedSpec().Roots)\n\t})\n\n\t// simulate registryd being ready\n\tservice := v1alpha1res.NewService(crictrl.RegistrydServiceID)\n\tservice.TypedSpec().Healthy = true\n\tservice.TypedSpec().Running = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), service))\n\n\t// now both volumes are ready, and service is ready, should be ready\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusReady, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusReady, r.TypedSpec().CopyStatus)\n\t\tasrt.Equal([]string{constants.ImageCacheDiskMountPoint, filepath.Join(constants.ImageCacheISOMountPoint, \"imagecache\")}, r.TypedSpec().Roots)\n\t})\n}\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileJustDiskVolume() {\n\tctrlName := (&crictrl.ImageCacheConfigController{}).Name()\n\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tImageCacheSupport: &v1alpha1.ImageCacheConfig{\n\t\t\t\t\tCacheLocalEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t})\n\n\t// create volume statuses to simulate the volume being ready/not\n\tvs1 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheISO)\n\tvs1.TypedSpec().Phase = block.VolumePhaseMissing\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs1))\n\n\tvs2 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheDISK)\n\tvs2.TypedSpec().Phase = block.VolumePhaseWaiting\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs2))\n\n\t// ISO is missing, but disk volume is not ready yet\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t\tasrt.Empty(r.TypedSpec().Roots)\n\t})\n\n\t// make disk image cache ready\n\tvs2.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Update(vs2)\n\n\t// simulate disk being mounted\n\tvms2 := block.NewVolumeMountStatus(block.NamespaceName, ctrlName+\"-\"+crictrl.VolumeImageCacheDISK)\n\tvms2.TypedSpec().ReadOnly = false\n\tvms2.TypedSpec().Target = constants.ImageCacheDiskMountPoint\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vms2))\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusPreparing, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t\tasrt.Equal([]string{constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots)\n\t})\n\n\t// simulate registryd being ready\n\tservice := v1alpha1res.NewService(crictrl.RegistrydServiceID)\n\tservice.TypedSpec().Healthy = true\n\tservice.TypedSpec().Running = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), service))\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusReady, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t\tasrt.Equal([]string{constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots)\n\t})\n\n\t// volume mount status should have a finalizer\n\tctest.AssertResource(suite,\n\t\tctrlName+\"-\"+crictrl.VolumeImageCacheDISK,\n\t\tfunc(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vms.Metadata().Finalizers().Has(ctrlName))\n\t\t},\n\t)\n\n\t// now, simulate reboot sequence:\n\t// * missing ISO volume is destroyed\n\t// * volume mount status is being torn down\n\tsuite.Destroy(vs1)\n\n\t_, err := suite.State().Teardown(suite.Ctx(), block.NewVolumeMountStatus(block.NamespaceName, ctrlName+\"-\"+crictrl.VolumeImageCacheDISK).Metadata())\n\tsuite.Require().NoError(err)\n\n\t// controller should remove its finalizer\n\tctest.AssertResource(suite,\n\t\tctrlName+\"-\"+crictrl.VolumeImageCacheDISK,\n\t\tfunc(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t\t},\n\t)\n}\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileWithImageCacheVolume() {\n\tctrlName := (&crictrl.ImageCacheConfigController{}).Name()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tImageCacheSupport: &v1alpha1.ImageCacheConfig{\n\t\t\t\t\tCacheLocalEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tvolumeConfig := blockcfg.NewVolumeConfigV1Alpha1()\n\tvolumeConfig.MetaName = constants.ImageCachePartitionLabel\n\tvolumeConfig.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"10GiB\")\n\n\tcontainer, err := container.New(v1alpha1Cfg, volumeConfig)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(container)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crictrl.VolumeImageCacheDISK, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(`volume.partition_label == \"IMAGECACHE\"`, r.TypedSpec().Locator.Match.String())\n\t\tasrt.Equal(`system_disk`, r.TypedSpec().Provisioning.DiskSelector.Match.String())\n\t\tasrt.False(r.TypedSpec().Provisioning.PartitionSpec.Grow)\n\t\tasrt.EqualValues(crictrl.MinImageCacheSize, r.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\tasrt.EqualValues(10*1024*1024*1024, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t})\n\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusDisabled, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t})\n\n\t// create volume statuses to simulate the volume being ready & missing\n\tvs1 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheISO)\n\tvs1.TypedSpec().Phase = block.VolumePhaseMissing\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs1))\n\n\tvs2 := block.NewVolumeStatus(block.NamespaceName, crictrl.VolumeImageCacheDISK)\n\tvs2.TypedSpec().Phase = block.VolumePhaseReady\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vs2))\n\n\t// simulate disk being mounted\n\tvms := block.NewVolumeMountStatus(block.NamespaceName, ctrlName+\"-\"+crictrl.VolumeImageCacheDISK)\n\tvms.TypedSpec().ReadOnly = false\n\tvms.TypedSpec().Target = constants.ImageCacheDiskMountPoint\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), vms))\n\n\t// simulate registryd being ready\n\tservice := v1alpha1res.NewService(crictrl.RegistrydServiceID)\n\tservice.TypedSpec().Healthy = true\n\tservice.TypedSpec().Running = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), service))\n\n\t// now both volumes are ready, and service is ready, should be ready\n\tctest.AssertResource(suite, cri.ImageCacheConfigID, func(r *cri.ImageCacheConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(cri.ImageCacheStatusReady, r.TypedSpec().Status)\n\t\tasrt.Equal(cri.ImageCacheCopyStatusSkipped, r.TypedSpec().CopyStatus)\n\t\tasrt.Equal([]string{constants.ImageCacheDiskMountPoint}, r.TypedSpec().Roots)\n\t})\n}\n\nfunc (suite *ImageCacheConfigSuite) TestReconcileWithEncryptionConfig() {\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tImageCacheSupport: &v1alpha1.ImageCacheConfig{\n\t\t\t\t\tCacheLocalEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tvolumeConfig := blockcfg.NewVolumeConfigV1Alpha1()\n\tvolumeConfig.MetaName = constants.ImageCachePartitionLabel\n\tvolumeConfig.EncryptionSpec = blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"allsecret\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tcontainer, err := container.New(v1alpha1Cfg, volumeConfig)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(container)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crictrl.VolumeImageCacheDISK, func(r *block.VolumeConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(`volume.partition_label == \"IMAGECACHE\"`, r.TypedSpec().Locator.Match.String())\n\t\tasrt.Equal(`system_disk`, r.TypedSpec().Provisioning.DiskSelector.Match.String())\n\t\tasrt.False(r.TypedSpec().Provisioning.PartitionSpec.Grow)\n\t\tasrt.EqualValues(crictrl.MinImageCacheSize, r.TypedSpec().Provisioning.PartitionSpec.MinSize)\n\t\tasrt.EqualValues(crictrl.MaxImageCacheSize, r.TypedSpec().Provisioning.PartitionSpec.MaxSize)\n\t\tasrt.Equal(block.EncryptionProviderLUKS2, r.TypedSpec().Encryption.Provider)\n\t\tasrt.Len(r.TypedSpec().Encryption.Keys, 1)\n\t})\n}\n\nfunc TestImageCacheConfigSuite(t *testing.T) {\n\ts := &ImageCacheConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t}\n\n\ts.AfterSetup = func(suite *ctest.DefaultSuite) {\n\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&crictrl.ImageCacheConfigController{\n\t\t\tV1Alpha1ServiceManager: &mockServiceRunner{},\n\t\t\tDisableCacheCopy:       true,\n\t\t}))\n\t}\n\n\tsuite.Run(t, s)\n}\n\ntype ImageCacheConfigSuite struct {\n\tctest.DefaultSuite\n}\n\ntype mockServiceRunner struct{}\n\nfunc (mock *mockServiceRunner) IsRunning(id string) (system.Service, bool, error) {\n\treturn nil, true, nil\n}\n\nfunc (mock *mockServiceRunner) Load(services ...system.Service) []string {\n\treturn nil\n}\n\nfunc (mock *mockServiceRunner) Start(serviceIDs ...string) error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/image_gc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/core/images\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/distribution/reference\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// ImageCleanupInterval is the interval at which the image GC controller runs.\nconst ImageCleanupInterval = 15 * time.Minute\n\n// ImageGCGracePeriod is the minimum age of an image before it can be deleted.\nconst ImageGCGracePeriod = 4 * ImageCleanupInterval\n\n// NewImageGCController creates a new ImageGCController.\nfunc NewImageGCController(containerdName string, buildExpectedImages bool) *ImageGCController {\n\tcontrollerName := \"cri.\" + containerdName + \"ImageGCController\"\n\n\treturn &ImageGCController{\n\t\tcontainerdName:      containerdName,\n\t\tcontrollerName:      controllerName,\n\t\tbuildExpectedImages: buildExpectedImages,\n\t}\n}\n\n// ImageGCController performs garbage collection of unused container images.\ntype ImageGCController struct {\n\tImageServiceProvider func() (ImageServiceProvider, error)\n\n\tcontainerdName             string\n\tcontrollerName             string\n\tbuildExpectedImages        bool\n\timageFirstSeenUnreferenced map[string]time.Time\n}\n\n// ImageServiceProvider wraps the containerd image service.\ntype ImageServiceProvider interface {\n\tImageService() images.Store\n\tClose() error\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ImageGCController) Name() string {\n\treturn ctrl.controllerName\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ImageGCController) Inputs() []controller.Input {\n\tinputs := []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(ctrl.containerdName),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n\n\tif ctrl.buildExpectedImages {\n\t\tinputs = append(inputs,\n\t\t\tcontroller.Input{\n\t\t\t\tNamespace: k8s.NamespaceName,\n\t\t\t\tType:      k8s.KubeletSpecType,\n\t\t\t\tID:        optional.Some(k8s.KubeletID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t\tcontroller.Input{\n\t\t\t\tNamespace: etcd.NamespaceName,\n\t\t\t\tType:      etcd.SpecType,\n\t\t\t\tID:        optional.Some(etcd.SpecID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t)\n\t}\n\n\treturn inputs\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ImageGCController) Outputs() []controller.Output {\n\treturn nil\n}\n\nfunc defaultImageServiceProvider(containerdName string) func() (ImageServiceProvider, error) {\n\treturn func() (ImageServiceProvider, error) {\n\t\tvar addr string\n\n\t\tswitch containerdName {\n\t\tcase \"cri\":\n\t\t\taddr = constants.CRIContainerdAddress\n\t\tcase \"containerd\":\n\t\t\taddr = constants.SystemContainerdAddress\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown containerd name: %s\", containerdName)\n\t\t}\n\n\t\tcriClient, err := containerd.New(addr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating containerd client: %w\", err)\n\t\t}\n\n\t\treturn &containerdImageServiceProvider{\n\t\t\tcriClient: criClient,\n\t\t}, nil\n\t}\n}\n\ntype containerdImageServiceProvider struct {\n\tcriClient *containerd.Client\n}\n\nfunc (s *containerdImageServiceProvider) ImageService() images.Store {\n\treturn s.criClient.ImageService()\n}\n\nfunc (s *containerdImageServiceProvider) Close() error {\n\treturn s.criClient.Close()\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ImageGCController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.ImageServiceProvider == nil {\n\t\tctrl.ImageServiceProvider = defaultImageServiceProvider(ctrl.containerdName)\n\t}\n\n\tif ctrl.imageFirstSeenUnreferenced == nil {\n\t\tctrl.imageFirstSeenUnreferenced = map[string]time.Time{}\n\t}\n\n\tvar (\n\t\tcontainerdIsUp       bool\n\t\texpectedImages       []string\n\t\timageServiceProvider ImageServiceProvider\n\t)\n\n\tticker := time.NewTicker(ImageCleanupInterval)\n\tdefer ticker.Stop()\n\n\tdefer func() {\n\t\tif imageServiceProvider != nil {\n\t\t\timageServiceProvider.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\t\tif !containerdIsUp || (ctrl.buildExpectedImages && len(expectedImages) == 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif imageServiceProvider == nil {\n\t\t\t\tvar err error\n\n\t\t\t\timageServiceProvider, err = ctrl.ImageServiceProvider()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error creating image service provider: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := ctrl.cleanup(ctx, logger, imageServiceProvider.ImageService(), expectedImages); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error running image cleanup: %w\", err)\n\t\t\t}\n\t\tcase <-r.EventCh():\n\t\t\tcontainerdService, err := safe.ReaderGet[*v1alpha1.Service](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, ctrl.containerdName, resource.VersionUndefined))\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting container service: %w\", err)\n\t\t\t}\n\n\t\t\tcontainerdIsUp = containerdService != nil && containerdService.TypedSpec().Running && containerdService.TypedSpec().Healthy\n\n\t\t\texpectedImages = nil\n\n\t\t\tif ctrl.buildExpectedImages {\n\t\t\t\tetcdSpec, err := safe.ReaderGet[*etcd.Spec](ctx, r, resource.NewMetadata(etcd.NamespaceName, etcd.SpecType, etcd.SpecID, resource.VersionUndefined))\n\t\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting etcd spec: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif etcdSpec != nil {\n\t\t\t\t\texpectedImages = append(expectedImages, etcdSpec.TypedSpec().Image)\n\t\t\t\t}\n\n\t\t\t\tkubeletSpec, err := safe.ReaderGet[*k8s.KubeletSpec](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined))\n\t\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting kubelet spec: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif kubeletSpec != nil {\n\t\t\t\t\texpectedImages = append(expectedImages, kubeletSpec.TypedSpec().Image)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc buildExpectedDigests(logger *zap.Logger, actualImages []images.Image, expectedImages []string) (map[string]struct{}, error) {\n\tvar parseErrors error\n\n\texpectedReferences := xslices.Map(expectedImages, func(ref string) reference.Named {\n\t\tres, parseErr := reference.ParseNamed(ref)\n\n\t\tparseErrors = errors.Join(parseErrors, parseErr)\n\n\t\treturn res\n\t})\n\n\tif parseErrors != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing expected images: %w\", parseErrors)\n\t}\n\n\texpectedDigests := map[string]struct{}{}\n\n\tfor _, expectedRef := range expectedReferences {\n\t\t// easy case: image ref has digest, record it\n\t\tif expectedDigested, ok := expectedRef.(reference.Digested); ok {\n\t\t\texpectedDigests[expectedDigested.Digest().String()] = struct{}{}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// hard case: iterate over actual images to find the digest for the tag\n\t\tfor _, image := range actualImages {\n\t\t\timageRef, err := reference.ParseAnyReference(image.Name)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Debug(\"failed to parse image reference\", zap.Error(err), zap.String(\"image\", image.Name))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdigest := image.Target.Digest.String()\n\n\t\t\tif ref, ok := imageRef.(reference.NamedTagged); ok {\n\t\t\t\tif expectedRef.Name() != ref.Name() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif expectedTagged, ok := expectedRef.(reference.Tagged); ok && ref.Tag() == expectedTagged.Tag() {\n\t\t\t\t\t// this is expected image by tag, inject digest\n\t\t\t\t\texpectedDigests[digest] = struct{}{}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn expectedDigests, nil\n}\n\nfunc (ctrl *ImageGCController) cleanup(ctx context.Context, logger *zap.Logger, imageService images.Store, expectedImages []string) error {\n\tlogger.Debug(\"running image cleanup\")\n\n\tctx = namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)\n\n\tactualImages, err := imageService.List(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing images: %w\", err)\n\t}\n\n\t// first pass: scan actualImages and expand expectedImages from tags to digests\n\texpectedDigests, err := buildExpectedDigests(logger, actualImages, expectedImages)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// second pass, drop whatever is not expected\n\tfor _, image := range actualImages {\n\t\t_, shouldKeep := expectedDigests[image.Target.Digest.String()]\n\n\t\tif shouldKeep {\n\t\t\tlogger.Debug(\"image is referenced, skipping garbage collection\", zap.String(\"image\", image.Name))\n\n\t\t\tdelete(ctrl.imageFirstSeenUnreferenced, image.Name)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := ctrl.imageFirstSeenUnreferenced[image.Name]; !ok {\n\t\t\tctrl.imageFirstSeenUnreferenced[image.Name] = time.Now()\n\t\t}\n\n\t\t// calculate image age two ways, and pick the minimum:\n\t\t//  * as CRI reports it, which is the time image got pulled\n\t\t//  * as we see it, this means the image won't be deleted until it reaches the age of ImageGCGracePeriod from the moment it became unreferenced\n\t\timageAgeCRI := time.Since(image.CreatedAt)\n\t\timageAgeInternal := time.Since(ctrl.imageFirstSeenUnreferenced[image.Name])\n\n\t\timageAge := min(imageAgeCRI, imageAgeInternal)\n\n\t\tif imageAge < ImageGCGracePeriod {\n\t\t\tlogger.Debug(\"skipping image cleanup, as it's below minimum age\", zap.String(\"image\", image.Name), zap.Duration(\"age\", imageAge))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = imageService.Delete(ctx, image.Name); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to delete an image %s: %w\", image.Name, err)\n\t\t}\n\n\t\tdelete(ctrl.imageFirstSeenUnreferenced, image.Name)\n\t\tlogger.Info(\"deleted an image\", zap.String(\"image\", image.Name))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/image_gc_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"testing/synctest\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/core/images\"\n\t\"github.com/opencontainers/go-digest\"\n\tv1 \"github.com/opencontainers/image-spec/specs-go/v1\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tcrictrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nfunc TestImageGC(t *testing.T) {\n\tsynctest.Test(t, func(t *testing.T) {\n\t\tmockImageService := &mockImageService{}\n\n\t\t// Create the controller inside synctest time function so it uses the controlled time\n\t\tcontroller := crictrl.NewImageGCController(\"cri\", true)\n\t\tcontroller.ImageServiceProvider = func() (crictrl.ImageServiceProvider, error) {\n\t\t\treturn mockImageService, nil\n\t\t}\n\n\t\t// Set up the test environment manually\n\t\tsuite := &ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\t// Register the controller\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(controller))\n\t\t\t},\n\t\t\t// We need a long timeout here because we advance time manually in the test and we want the controller\n\t\t\t// to have enough time to run its cleanup cycles.\n\t\t\tTimeout: 2 * time.Hour,\n\t\t}\n\n\t\tsuite.SetT(t) // we need to explicitly set to the t from the synctest.Test\n\n\t\tsuite.SetupTest()\n\t\tdefer suite.TearDownTest()\n\n\t\t// Use synctest controlled time as the base time\n\t\tnow := time.Now()\n\n\t\tstoredImages := []images.Image{\n\t\t\t{\n\t\t\t\tName:      \"registry.io/org/image1:v1.3.5@sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\",\n\t\t\t\tCreatedAt: now.Add(-2 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\")),\n\t\t\t\t},\n\t\t\t}, // ok to be gc'd\n\t\t\t{\n\t\t\t\tName: \"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\",\n\t\t\t\t// the image age is more than the grace period, but the controller won't remove due to the check on the last seen unreferenced timestamp\n\t\t\t\tCreatedAt: now.Add(-4 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\")),\n\t\t\t\t},\n\t\t\t}, // ok to be gc'd, same as above, another ref\n\t\t\t{\n\t\t\t\tName:      \"registry.io/org/image1:v1.3.7\",\n\t\t\t\tCreatedAt: now.Add(-2 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t\t},\n\t\t\t}, // current image\n\t\t\t{\n\t\t\t\tName:      \"registry.io/org/image1@sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t\tCreatedAt: now.Add(-2 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t\t},\n\t\t\t}, // current image, canonical ref\n\t\t\t{\n\t\t\t\tName:      \"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t\tCreatedAt: now.Add(-2 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t\t},\n\t\t\t}, // current image, digest ref\n\t\t\t{\n\t\t\t\tName:      \"registry.io/org/image1:v1.3.8\",\n\t\t\t\tCreatedAt: now.Add(crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:fd03335dd2e7163e5e36e933a0c735d7fec6f42b33ddafad0bc54f333e4a23c0\")),\n\t\t\t\t},\n\t\t\t}, // not ok to clean up, too new\n\t\t\t{\n\t\t\t\tName:      \"registry.io/org/image2@sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\",\n\t\t\t\tCreatedAt: now.Add(-2 * crictrl.ImageGCGracePeriod),\n\t\t\t\tTarget: v1.Descriptor{\n\t\t\t\t\tDigest: must(digest.Parse(\"sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\")),\n\t\t\t\t},\n\t\t\t}, // current image\n\t\t}\n\n\t\tmockImageService.images = storedImages\n\n\t\tcriService := v1alpha1.NewService(\"cri\")\n\t\tcriService.TypedSpec().Healthy = true\n\t\tcriService.TypedSpec().Running = true\n\n\t\trequire.NoError(t, suite.State().Create(suite.Ctx(), criService))\n\n\t\tkubelet := k8s.NewKubeletSpec(k8s.NamespaceName, k8s.KubeletID)\n\t\tkubelet.TypedSpec().Image = \"registry.io/org/image1:v1.3.7\"\n\t\trequire.NoError(t, suite.State().Create(suite.Ctx(), kubelet))\n\n\t\tetcd := etcd.NewSpec(etcd.NamespaceName, etcd.SpecID)\n\t\tetcd.TypedSpec().Image = \"registry.io/org/image2:v3.5.9@sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\"\n\t\trequire.NoError(t, suite.State().Create(suite.Ctx(), etcd))\n\n\t\t// // Wait for the controller to process all events and set up state\n\t\t// synctest.Wait()\n\n\t\t// Advance time past the grace period to make old images eligible for cleanup\n\t\t// Grace period is 60 minutes, so advance by 65 minutes to ensure cleanup\n\t\ttime.Sleep(crictrl.ImageGCGracePeriod + 5*time.Minute)\n\t\tsynctest.Wait()\n\n\t\t// Advance time to trigger the cleanup cycle (15 minutes)\n\t\ttime.Sleep(crictrl.ImageCleanupInterval)\n\t\tsynctest.Wait() // Wait for cleanup to complete\n\n\t\t// Images that should remain after cleanup:\n\t\t// - All referenced images (from kubelet and etcd specs)\n\t\t// - The \"new\" image that hasn't aged enough yet\n\t\texpectedImages := []string{\n\t\t\t\"registry.io/org/image1:v1.3.7\", // kubelet image\n\t\t\t\"registry.io/org/image1@sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\", // kubelet image canonical ref\n\t\t\t\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",                        // kubelet image digest ref\n\t\t\t\"registry.io/org/image1:v1.3.8\", // new image, not old enough to clean\n\t\t\t\"registry.io/org/image2@sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\", // etcd image\n\t\t}\n\n\t\timageList, err := mockImageService.List(suite.Ctx())\n\t\trequire.NoError(t, err)\n\n\t\tactualImages := xslices.Map(imageList, func(i images.Image) string { return i.Name })\n\n\t\tsuite.Assert().Equal(expectedImages, actualImages, \"images after first GC run do not match expected\")\n\t})\n}\n\ntype mockImageService struct {\n\tmu sync.Mutex\n\n\timages []images.Image\n}\n\nfunc (m *mockImageService) ImageService() images.Store {\n\treturn m\n}\n\nfunc (m *mockImageService) Close() error {\n\treturn nil\n}\n\nfunc (m *mockImageService) Get(ctx context.Context, name string) (images.Image, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (m *mockImageService) List(ctx context.Context, filters ...string) ([]images.Image, error) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\treturn slices.Clone(m.images), nil\n}\n\nfunc (m *mockImageService) Create(ctx context.Context, image images.Image) (images.Image, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (m *mockImageService) Update(ctx context.Context, image images.Image, fieldpaths ...string) (images.Image, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (m *mockImageService) Delete(ctx context.Context, name string, opts ...images.DeleteOpt) error {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tm.images = xslices.FilterInPlace(m.images, func(i images.Image) bool { return i.Name != name })\n\n\treturn nil\n}\n\nfunc TestBuildExpectedImageDigests(t *testing.T) {\n\tactualImages := []images.Image{\n\t\t{\n\t\t\tName: \"registry.io/org/image1:v1.3.5@sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:6b094bd0b063a1172eec7da249eccbb48cc48333800569363d67c747960cfa0a\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"registry.io/org/image1:v1.3.7\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"registry.io/org/image1@sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"registry.io/org/image1:v1.3.8\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:fd03335dd2e7163e5e36e933a0c735d7fec6f42b33ddafad0bc54f333e4a23c0\")),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"registry.io/org/image2@sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\",\n\t\t\tTarget: v1.Descriptor{\n\t\t\t\tDigest: must(digest.Parse(\"sha256:2f794176e9bd8a28501fa185693dc1073013a048c51585022ebce4f84b469db8\")),\n\t\t\t},\n\t\t},\n\t}\n\n\tlogger := zaptest.NewLogger(t)\n\n\tfor _, test := range []struct {\n\t\tname           string\n\t\texpectedImages []string\n\n\t\texpectedDigests []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"by tag\",\n\t\t\texpectedImages: []string{\n\t\t\t\t\"registry.io/org/image1:v1.3.7\",\n\t\t\t},\n\t\t\texpectedDigests: []string{\n\t\t\t\t\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"by digest\",\n\t\t\texpectedImages: []string{\n\t\t\t\t\"registry.io/org/image1@sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t},\n\t\t\texpectedDigests: []string{\n\t\t\t\t\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"by digest and tag\",\n\t\t\texpectedImages: []string{\n\t\t\t\t\"registry.io/org/image1:v1.3.7@sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t},\n\t\t\texpectedDigests: []string{\n\t\t\t\t\"sha256:7051a34bcd2522e58a2291d1aa065667f225fd07e4445590b091e86c6799b135\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"not found\",\n\t\t\texpectedImages: []string{\n\t\t\t\t\"registry.io/org/image1:v1.3.9\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\texpectedDigests, err := crictrl.BuildExpectedDigests(logger, actualImages, test.expectedImages)\n\t\t\trequire.NoError(t, err)\n\n\t\t\texpectedDigestKeys := maps.Keys(expectedDigests)\n\n\t\t\tslices.Sort(test.expectedDigests)\n\t\t\tslices.Sort(expectedDigestKeys)\n\n\t\t\tassert.Equal(t, test.expectedDigests, expectedDigestKeys)\n\t\t})\n\t}\n}\n\nfunc must[T any](t T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn t\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/registries_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\tconfig2 \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// RegistriesConfigController watches v1alpha1.Config, updates registry.RegistriesConfig.\ntype RegistriesConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RegistriesConfigController) Name() string {\n\treturn \"cri.RegistriesConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RegistriesConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cri.NamespaceName,\n\t\t\tType:      cri.ImageCacheConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RegistriesConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cri.RegistriesConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *RegistriesConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get machine config: %w\", err)\n\t\t}\n\n\t\timageCacheConfig, err := safe.ReaderGetByID[*cri.ImageCacheConfig](ctx, r, cri.ImageCacheConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get image cache config: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, cri.NewRegistriesConfig(), func(res *cri.RegistriesConfig) error {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tspec.RegistryAuths = clearInit(spec.RegistryAuths)\n\t\t\tspec.RegistryMirrors = clearInit(spec.RegistryMirrors)\n\t\t\tspec.RegistryTLSs = clearInit(spec.RegistryTLSs)\n\n\t\t\tif cfg != nil {\n\t\t\t\tfor k, v := range cfg.Config().RegistryMirrorConfigs() {\n\t\t\t\t\tspec.RegistryMirrors[k] = &cri.RegistryMirrorConfig{\n\t\t\t\t\t\tMirrorEndpoints: xslices.Map(\n\t\t\t\t\t\t\tv.Endpoints(),\n\t\t\t\t\t\t\tfunc(endpoint config2.RegistryEndpointConfig) cri.RegistryEndpointConfig {\n\t\t\t\t\t\t\t\treturn cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t\t\tEndpointEndpoint:     endpoint.Endpoint(),\n\t\t\t\t\t\t\t\t\tEndpointOverridePath: endpoint.OverridePath(),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t\tMirrorSkipFallback: v.SkipFallback(),\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor k, v := range cfg.Config().RegistryAuthConfigs() {\n\t\t\t\t\tspec.RegistryAuths[k] = &cri.RegistryAuthConfig{\n\t\t\t\t\t\tRegistryUsername:      v.Username(),\n\t\t\t\t\t\tRegistryPassword:      v.Password(),\n\t\t\t\t\t\tRegistryAuth:          v.Auth(),\n\t\t\t\t\t\tRegistryIdentityToken: v.IdentityToken(),\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor k, v := range cfg.Config().RegistryTLSConfigs() {\n\t\t\t\t\tspec.RegistryTLSs[k] = &cri.RegistryTLSConfig{\n\t\t\t\t\t\tTLSCA:                 v.CA(),\n\t\t\t\t\t\tTLSInsecureSkipVerify: v.InsecureSkipVerify(),\n\t\t\t\t\t\tTLSClientIdentity:     v.ClientIdentity(),\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif imageCacheConfig != nil && imageCacheConfig.TypedSpec().Status == cri.ImageCacheStatusReady {\n\t\t\t\t// if the '*' was configured, we just use it, otherwise create it so that we can inject the registryd\n\t\t\t\tif _, hasStar := spec.RegistryMirrors[\"*\"]; !hasStar {\n\t\t\t\t\tspec.RegistryMirrors[\"*\"] = &cri.RegistryMirrorConfig{}\n\t\t\t\t}\n\n\t\t\t\t// inject the registryd mirror endpoint as the first one for all registries\n\t\t\t\tfor registry := range spec.RegistryMirrors {\n\t\t\t\t\tspec.RegistryMirrors[registry].MirrorEndpoints = append(\n\t\t\t\t\t\t[]cri.RegistryEndpointConfig{{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress}},\n\t\t\t\t\t\tspec.RegistryMirrors[registry].MirrorEndpoints...,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write registries config: %w\", err)\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*cri.RegistriesConfig](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to clean up outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc clearInit[M ~map[K]V, K comparable, V any](m M) M {\n\tif m == nil {\n\t\treturn make(M)\n\t}\n\n\tclear(m)\n\n\treturn m\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/registries_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tcriconfig \"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\tcrires \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ConfigSuite) TestRegistry() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t\tMachineRegistries: v1alpha1.RegistriesConfig{\n\t\t\t\tRegistryMirrors: map[string]*v1alpha1.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tMirrorEndpoints:    []string{\"https://mirror.io\"},\n\t\t\t\t\t\tMirrorOverridePath: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tMirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint:     \"https://mirror.io\",\n\t\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\t})\n\n\tic := crires.NewImageCacheConfig()\n\tic.TypedSpec().Roots = []string{\"/imagecache\"}\n\tic.TypedSpec().Status = crires.ImageCacheStatusReady\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ic))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"*\": {\n\t\t\t\t\tMirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint: \"http://\" + constants.RegistrydListenAddress,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tMirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint: \"http://\" + constants.RegistrydListenAddress,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint:     \"https://mirror.io\",\n\t\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestRegistryAuth() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t\tMachineRegistries: v1alpha1.RegistriesConfig{\n\t\t\t\tRegistryMirrors: map[string]*v1alpha1.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {MirrorEndpoints: []string{\"https://mirror.io\"}},\n\t\t\t\t},\n\t\t\t\tRegistryConfig: map[string]*v1alpha1.RegistryConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tRegistryAuth: &v1alpha1.RegistryAuthConfig{\n\t\t\t\t\t\t\tRegistryUsername:      \"example\",\n\t\t\t\t\t\t\tRegistryPassword:      \"pass\",\n\t\t\t\t\t\t\tRegistryAuth:          \"someauth\",\n\t\t\t\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"docker.io\": {MirrorEndpoints: []crires.RegistryEndpointConfig{{EndpointEndpoint: \"https://mirror.io\"}}},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryAuthConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tRegistryUsername:      \"example\",\n\t\t\t\t\tRegistryPassword:      \"pass\",\n\t\t\t\t\tRegistryAuth:          \"someauth\",\n\t\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryAuths,\n\t\t)\n\n\t\ta.Empty(spec.RegistryTLSs)\n\t})\n\n\tic := crires.NewImageCacheConfig()\n\tic.TypedSpec().Roots = []string{\"/imagecache\"}\n\tic.TypedSpec().Status = crires.ImageCacheStatusReady\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ic))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"*\": {MirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress},\n\t\t\t\t}},\n\t\t\t\t\"docker.io\": {MirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress},\n\t\t\t\t\t{EndpointEndpoint: \"https://mirror.io\"},\n\t\t\t\t}},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryAuthConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tRegistryUsername:      \"example\",\n\t\t\t\t\tRegistryPassword:      \"pass\",\n\t\t\t\t\tRegistryAuth:          \"someauth\",\n\t\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryAuths,\n\t\t)\n\n\t\ta.Empty(spec.RegistryTLSs)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestRegistryTLS() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t\tMachineRegistries: v1alpha1.RegistriesConfig{\n\t\t\t\tRegistryMirrors: map[string]*v1alpha1.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {MirrorEndpoints: []string{\"https://mirror.io\"}},\n\t\t\t\t},\n\t\t\t\tRegistryConfig: map[string]*v1alpha1.RegistryConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tRegistryTLS: &v1alpha1.RegistryTLSConfig{\n\t\t\t\t\t\t\tTLSInsecureSkipVerify: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"docker.io\": {MirrorEndpoints: []crires.RegistryEndpointConfig{{EndpointEndpoint: \"https://mirror.io\"}}},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\n\t\ta.Empty(spec.RegistryAuths)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryTLSConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryTLSs,\n\t\t)\n\t})\n\n\tic := crires.NewImageCacheConfig()\n\tic.TypedSpec().Roots = []string{\"/imagecache\"}\n\tic.TypedSpec().Status = crires.ImageCacheStatusReady\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ic))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"*\": {MirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress},\n\t\t\t\t}},\n\t\t\t\t\"docker.io\": {MirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress},\n\t\t\t\t\t{EndpointEndpoint: \"https://mirror.io\"},\n\t\t\t\t}},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\n\t\ta.Empty(spec.RegistryAuths)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryTLSConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryTLSs,\n\t\t)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestRegistryImageCacheNoConfig() {\n\tic := crires.NewImageCacheConfig()\n\tic.TypedSpec().Roots = []string{\"/imagecache\"}\n\tic.TypedSpec().Status = crires.ImageCacheStatusReady\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ic))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"*\": {MirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://\" + constants.RegistrydListenAddress},\n\t\t\t\t}},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestRegistryNoConfig() {\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Empty(\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestRegistryNewStyle() {\n\tmr1 := criconfig.NewRegistryMirrorConfigV1Alpha1(\"docker.io\")\n\tmr1.RegistryEndpoints = []criconfig.RegistryEndpoint{\n\t\t{\n\t\t\tEndpointURL:          meta.URL{URL: ensure.Value(url.Parse(\"https://mirror1.io\"))},\n\t\t\tEndpointOverridePath: new(true),\n\t\t},\n\t\t{\n\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"https://mirror2.io\"))},\n\t\t},\n\t}\n\n\tar1 := criconfig.NewRegistryAuthConfigV1Alpha1(\"registry-1.docker.io\")\n\tar1.RegistryUsername = \"docker-example\"\n\tar1.RegistryPassword = \"docker-pass\"\n\n\ttr1 := criconfig.NewRegistryTLSConfigV1Alpha1(\"private-registry:3000\")\n\ttr1.TLSInsecureSkipVerify = new(true)\n\ttr1.TLSClientIdentity = &meta.CertificateAndKey{\n\t\tCert: \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\",\n\t\tKey:  \"-----BEGIN PRIVATE KEY-----\\nMIIE...AB\\n-----END PRIVATE KEY-----\",\n\t}\n\ttr1.TLSCA = \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\"\n\n\ttr2 := criconfig.NewRegistryTLSConfigV1Alpha1(\"another-registry\")\n\ttr2.TLSInsecureSkipVerify = new(true)\n\n\tctr, err := container.New(mr1, ar1, tr1, tr2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, crires.RegistriesConfigID, func(r *crires.RegistriesConfig, a *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryMirrorConfig{\n\t\t\t\t\"docker.io\": {\n\t\t\t\t\tMirrorEndpoints: []crires.RegistryEndpointConfig{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint:     \"https://mirror1.io\",\n\t\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpointEndpoint: \"https://mirror2.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryMirrors,\n\t\t)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryAuthConfig{\n\t\t\t\t\"registry-1.docker.io\": {\n\t\t\t\t\tRegistryUsername: \"docker-example\",\n\t\t\t\t\tRegistryPassword: \"docker-pass\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryAuths,\n\t\t)\n\n\t\ta.Equal(\n\t\t\tmap[string]*crires.RegistryTLSConfig{\n\t\t\t\t\"private-registry:3000\": {\n\t\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\t\tTLSClientIdentity: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\"),\n\t\t\t\t\t\tKey: []byte(\"-----BEGIN PRIVATE KEY-----\\nMIIE...AB\\n-----END PRIVATE KEY-----\"),\n\t\t\t\t\t},\n\t\t\t\t\tTLSCA: []byte(\"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\"),\n\t\t\t\t},\n\t\t\t\t\"another-registry\": {\n\t\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.RegistryTLSs,\n\t\t)\n\t})\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&cri.RegistriesConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/seccomp_profile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// SeccompProfileController manages SeccompProfiles.\ntype SeccompProfileController struct{}\n\n// Name implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileController) Name() string {\n\treturn \"cri.SeccompProfileController\"\n}\n\n// Inputs implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: cri.SeccompProfileType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg.Config().Machine() != nil {\n\t\t\tfor _, profile := range cfg.Config().Machine().SeccompProfiles() {\n\t\t\t\tif err = safe.WriterModify(ctx, r, cri.NewSeccompProfile(profile.Name()), func(cri *cri.SeccompProfile) error {\n\t\t\t\t\tcri.TypedSpec().Name = profile.Name()\n\t\t\t\t\tcri.TypedSpec().Value = profile.Value()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*cri.SeccompProfile](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/seccomp_profile_file.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// SeccompProfileFileController manages the Seccomp Profiles on the host.\ntype SeccompProfileFileController struct {\n\tV1Alpha1Mode             runtimetalos.Mode\n\tSeccompProfilesDirectory string\n}\n\n// Name implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileFileController) Name() string {\n\treturn \"cri.SeccompProfileFileController\"\n}\n\n// Inputs implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileFileController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.StatsController interface.\nfunc (ctrl *SeccompProfileFileController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.StatsController interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *SeccompProfileFileController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// initially, wait for /var to be mounted\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: runtimeres.NamespaceName,\n\t\t\tType:      runtimeres.MountStatusType,\n\t\t\tID:        optional.Some(constants.EphemeralPartitionLabel),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t_, err := safe.ReaderGet[*runtimeres.MountStatus](ctx, r, resource.NewMetadata(runtimeres.NamespaceName, runtimeres.MountStatusType, constants.EphemeralPartitionLabel, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// in container mode EPHEMERAL is always mounted\n\t\t\t\tif ctrl.V1Alpha1Mode != runtimetalos.ModeContainer {\n\t\t\t\t\t// wait for the EPHEMERAL to be mounted\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"error getting ephemeral mount status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tbreak\n\t}\n\n\t// normal reconcile loop\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: cri.NamespaceName,\n\t\t\tType:      cri.SeccompProfileType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tr.QueueReconcile()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tlist, err := safe.ReaderListAll[*cri.SeccompProfile](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing seccomp profiles: %w\", err)\n\t\t}\n\n\t\ttouchedIDs := make(map[string]struct{}, list.Len())\n\n\t\tfor profile := range list.All() {\n\t\t\tprofileName := profile.TypedSpec().Name\n\t\t\tprofilePath := filepath.Join(ctrl.SeccompProfilesDirectory, profileName)\n\n\t\t\tprofileContent, err := json.Marshal(profile.TypedSpec().Value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error marshaling seccomp profile: %w\", err)\n\t\t\t}\n\n\t\t\texistingProfileContent, err := os.ReadFile(profilePath)\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\treturn fmt.Errorf(\"error reading existing seccomp profile at %s: %w\", profilePath, err)\n\t\t\t\t}\n\n\t\t\t\tif err := writeSeccompFile(profilePath, profileContent); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif val := bytes.Compare(existingProfileContent, profileContent); val != 0 {\n\t\t\t\t\tif err := writeSeccompFile(profilePath, profileContent); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttouchedIDs[profileName] = struct{}{}\n\t\t}\n\n\t\t// cleanup\n\t\tif err := filepath.WalkDir(ctrl.SeccompProfilesDirectory, func(path string, d fs.DirEntry, err error) error {\n\t\t\tfileName, errRel := filepath.Rel(ctrl.SeccompProfilesDirectory, path)\n\t\t\tif errRel != nil {\n\t\t\t\treturn errRel\n\t\t\t}\n\n\t\t\t// ignore current folder\n\t\t\tif fileName != \".\" {\n\t\t\t\tif _, ok := touchedIDs[fileName]; !ok {\n\t\t\t\t\tif err := os.RemoveAll(path); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc writeSeccompFile(path string, content []byte) error {\n\tif err := os.WriteFile(path, content, 0o644); err != nil {\n\t\treturn fmt.Errorf(\"error writing seccomp profile at %s: %w\", path, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/seccomp_profile_file_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tcriseccompresource \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc (suite *CRISeccompProfileFileSuite) TestReconcileSeccompProfileFile() {\n\t// need to mock mountStatus so that the controller moves ahead with the actual code\n\tmountStatus := runtimeres.NewMountStatus(runtimeres.NamespaceName, \"EPHEMERAL\")\n\tsuite.Create(mountStatus)\n\n\tfor _, tt := range []struct {\n\t\tseccompProfileName  string\n\t\tseccompProfileValue map[string]any\n\t}{\n\t\t{\n\t\t\tseccompProfileName: \"audit.json\",\n\t\t\tseccompProfileValue: map[string]any{\n\t\t\t\t\"defaultAction\": \"SCMP_ACT_LOG\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseccompProfileName: \"deny.json\",\n\t\t\tseccompProfileValue: map[string]any{\n\t\t\t\t\"defaultAction\": \"SCMP_ACT_ERRNO\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tseccompProfiles := criseccompresource.NewSeccompProfile(tt.seccompProfileName)\n\t\tseccompProfiles.TypedSpec().Name = tt.seccompProfileName\n\t\tseccompProfiles.TypedSpec().Value = tt.seccompProfileValue\n\t\tsuite.Create(seccompProfiles)\n\n\t\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\tif !asrt.FileExists(suite.seccompProfilesDirectory + \"/\" + tt.seccompProfileName) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tseccompProfileContent, err := os.ReadFile(suite.seccompProfilesDirectory + \"/\" + tt.seccompProfileName)\n\t\t\tasrt.NoError(err)\n\n\t\t\texpectedSeccompProfileContent, err := json.Marshal(tt.seccompProfileValue)\n\t\t\tasrt.NoError(err)\n\n\t\t\tasrt.Equal(seccompProfileContent, expectedSeccompProfileContent)\n\t\t}, time.Second, 100*time.Millisecond)\n\t}\n\n\t// create a directory and file manually in the seccomp profile directory\n\t// ensure that the controller deletes the manually created directory/file\n\t// also ensure that an update doesn't update existing files timestamp\n\tsuite.Require().NoError(os.Mkdir(suite.seccompProfilesDirectory+\"/test\", 0o755))\n\tsuite.Require().NoError(os.WriteFile(suite.seccompProfilesDirectory+\"/test.json\", []byte(\"{}\"), 0o644))\n\n\tauditJSONSeccompProfile, err := os.Stat(suite.seccompProfilesDirectory + \"/audit.json\")\n\tsuite.Require().NoError(err)\n\n\t// delete deny.json resource\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), resource.NewMetadata(criseccompresource.NamespaceName, criseccompresource.SeccompProfileType, \"deny.json\", resource.VersionUndefined)))\n\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tauditJSONSeccompProfileAfterUpdate, err := os.Stat(suite.seccompProfilesDirectory + \"/audit.json\")\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal(auditJSONSeccompProfile.ModTime(), auditJSONSeccompProfileAfterUpdate.ModTime())\n\t}, 1*time.Second, 100*time.Millisecond)\n\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoFileExists(suite.seccompProfilesDirectory + \"/deny.json\")\n\t\tasrt.NoFileExists(suite.seccompProfilesDirectory + \"/test.json\")\n\t\tasrt.NoDirExists(suite.seccompProfilesDirectory + \"/test\")\n\t}, 1*time.Second, 100*time.Millisecond)\n}\n\nfunc TestSeccompProfileFileSuite(t *testing.T) {\n\tseccompProfiesDirectory := t.TempDir()\n\n\tsuite.Run(t, &CRISeccompProfileFileSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&cri.SeccompProfileFileController{\n\t\t\t\t\tSeccompProfilesDirectory: seccompProfiesDirectory,\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t\tseccompProfilesDirectory: seccompProfiesDirectory,\n\t})\n}\n\ntype CRISeccompProfileFileSuite struct {\n\tctest.DefaultSuite\n\n\tseccompProfilesDirectory string\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/cri/seccomp_profile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\tcriseccompresource \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\nfunc (suite *CRISeccompProfileSuite) TestReconcileSeccompProfile() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineSeccompProfiles: []*v1alpha1.MachineSeccompProfile{\n\t\t\t\t{\n\t\t\t\t\tMachineSeccompProfileName: \"audit.json\",\n\t\t\t\t\tMachineSeccompProfileValue: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"defaultAction\": \"SCMP_ACT_LOG\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMachineSeccompProfileName: \"deny.json\",\n\t\t\t\t\tMachineSeccompProfileValue: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"defaultAction\": \"SCMP_ACT_ERRNO\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tvalue map[string]any\n\t}{\n\t\t{\n\t\t\tname: \"audit.json\",\n\t\t\tvalue: map[string]any{\n\t\t\t\t\"defaultAction\": \"SCMP_ACT_LOG\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"deny.json\",\n\t\t\tvalue: map[string]any{\n\t\t\t\t\"defaultAction\": \"SCMP_ACT_ERRNO\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.AssertWithin(1*time.Second, 100*time.Millisecond, func() error {\n\t\t\tseccompProfile, err := ctest.Get[*criseccompresource.SeccompProfile](\n\t\t\t\tsuite,\n\t\t\t\tcriseccompresource.NewSeccompProfile(tt.name).Metadata(),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tspec := seccompProfile.TypedSpec()\n\n\t\t\tsuite.Assert().Equal(tt.name, spec.Name)\n\t\t\tsuite.Assert().Equal(tt.value, spec.Value)\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\t// test deletion\n\tcfg = config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineSeccompProfiles: []*v1alpha1.MachineSeccompProfile{\n\t\t\t\t{\n\t\t\t\t\tMachineSeccompProfileName: \"audit.json\",\n\t\t\t\t\tMachineSeccompProfileValue: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"defaultAction\": \"SCMP_ACT_LOG\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tctest.UpdateWithConflicts(suite, cfg, func(mc *config.MachineConfig) error { return nil })\n\n\tsuite.AssertWithin(1*time.Second, 100*time.Millisecond, func() error {\n\t\t_, err := ctest.Get[*criseccompresource.SeccompProfile](\n\t\t\tsuite,\n\t\t\tcriseccompresource.NewSeccompProfile(\"deny.json\").Metadata(),\n\t\t)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc TestSeccompProfileSuite(t *testing.T) {\n\tsuite.Run(t, &CRISeccompProfileSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&cri.SeccompProfileController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype CRISeccompProfileSuite struct {\n\tctest.DefaultSuite\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/ctest/assert.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage ctest\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype assertionAggregator struct {\n\terrors    map[string]struct{}\n\tfailNow   bool\n\thadErrors bool\n}\n\nfunc (agg *assertionAggregator) Errorf(format string, args ...any) {\n\terrorString := fmt.Sprintf(format, args...)\n\n\tif agg.errors == nil {\n\t\tagg.errors = make(map[string]struct{})\n\t}\n\n\tagg.errors[errorString] = struct{}{}\n\tagg.hadErrors = true\n}\n\nfunc (agg *assertionAggregator) FailNow() {\n\tagg.failNow = true\n}\n\nfunc (agg *assertionAggregator) Error() error {\n\tif !agg.hadErrors {\n\t\treturn nil\n\t}\n\n\tlines := make([]string, 0, len(agg.errors))\n\n\tfor errorString := range agg.errors {\n\t\tlines = append(lines, \" * \"+errorString)\n\t}\n\n\tslices.Sort(lines)\n\n\treturn fmt.Errorf(\"%s\", strings.Join(lines, \"\\n\"))\n}\n\n// WrapRetry wraps the function with assertions and requires to return retry-compatible errors.\nfunc WrapRetry(f func(*assert.Assertions, *require.Assertions)) func() error {\n\treturn func() error {\n\t\tvar errs assertionAggregator\n\n\t\tf(assert.New(&errs), require.New(&errs))\n\n\t\tif errs.failNow {\n\t\t\treturn errs.Error()\n\t\t}\n\n\t\treturn retry.ExpectedError(errs.Error())\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/ctest/ctest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ctest provides basic types and functions for controller testing.\npackage ctest\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n)\n\n// DefaultSuite is a base suite for controller testing.\ntype DefaultSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tAfterSetup    func(suite *DefaultSuite)\n\tAfterTearDown func(suite *DefaultSuite)\n\tTimeout       time.Duration\n}\n\n// SetupTest is a function for setting up a test.\nfunc (suite *DefaultSuite) SetupTest() {\n\tif suite.Timeout == 0 {\n\t\tsuite.Timeout = 3 * time.Minute\n\t}\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), suite.Timeout)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.startRuntime()\n\n\tif suite.AfterSetup != nil {\n\t\tsuite.AfterSetup(suite)\n\t}\n}\n\nfunc (suite *DefaultSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\n// Runtime returns the runtime of the suite.\nfunc (suite *DefaultSuite) Runtime() *runtime.Runtime {\n\treturn suite.runtime\n}\n\n// State returns the state of the suite.\nfunc (suite *DefaultSuite) State() state.State {\n\treturn suite.state\n}\n\n// Ctx returns the context of the suite.\nfunc (suite *DefaultSuite) Ctx() context.Context {\n\treturn suite.ctx\n}\n\n// AssertWithin asserts that fn returns within the given duration without an error.\nfunc (suite *DefaultSuite) AssertWithin(d time.Duration, rate time.Duration, fn func() error) {\n\tretryer := retry.Constant(d, retry.WithUnits(rate))\n\tsuite.Assert().NoError(retryer.Retry(fn))\n}\n\n// TearDownTest is a function for tearing down a test.\nfunc (suite *DefaultSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n\n\tif suite.AfterTearDown != nil {\n\t\tsuite.AfterTearDown(suite)\n\t}\n}\n\n// Create creates a new resource in the state of the suite.\nfunc (suite *DefaultSuite) Create(res resource.Resource, opts ...state.CreateOption) {\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), res, opts...))\n}\n\n// Update updates a resource in the state of the suite.\nfunc (suite *DefaultSuite) Update(res resource.Resource, opts ...state.UpdateOption) {\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), res, opts...))\n}\n\n// AddFinalizer adds a finalizer to a resource in the state of the suite.\nfunc (suite *DefaultSuite) AddFinalizer(resourcePointer resource.Pointer, finalizer string) {\n\tsuite.Require().NoError(suite.State().AddFinalizer(suite.Ctx(), resourcePointer, finalizer))\n}\n\n// RemoveFinalizer removes a finalizer from a resource in the state of the suite.\nfunc (suite *DefaultSuite) RemoveFinalizer(resourcePointer resource.Pointer, finalizer string) {\n\tsuite.Require().NoError(suite.State().RemoveFinalizer(suite.Ctx(), resourcePointer, finalizer))\n}\n\n// Destroy destroys a resource in the state of the suite.\nfunc (suite *DefaultSuite) Destroy(res resource.Resource, opts ...state.DestroyOption) {\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), res.Metadata(), opts...))\n}\n\n// Suite is a type which describes the suite type.\ntype Suite interface {\n\tT() *testing.T\n\tRequire() *require.Assertions\n\tState() state.State\n\tCtx() context.Context\n}\n\n// UpdateWithConflicts is a type safe wrapper around state.UpdateWithConflicts which uses the provided suite.\nfunc UpdateWithConflicts[T resource.Resource](suite Suite, res T, updateFn func(T) error, options ...state.UpdateOption) T { //nolint:ireturn\n\tsuite.T().Helper()\n\tresult, err := safe.StateUpdateWithConflicts(suite.Ctx(), suite.State(), res.Metadata(), updateFn, options...)\n\tsuite.Require().NoError(err)\n\n\treturn result\n}\n\n// GetUsingResource is a type safe wrapper around state.StateGetResource which uses the provided suite.\nfunc GetUsingResource[T resource.Resource](suite Suite, res T, options ...state.GetOption) (T, error) { //nolint:ireturn\n\treturn safe.StateGetResource(suite.Ctx(), suite.State(), res, options...)\n}\n\n// Get is a type safe wrapper around state.Get which uses the provided suite.\nfunc Get[T resource.Resource](suite Suite, ptr resource.Pointer, options ...state.GetOption) (T, error) { //nolint:ireturn\n\treturn safe.StateGet[T](suite.Ctx(), suite.State(), ptr, options...)\n}\n\n// Suiter is like Suite but do not require Require() method.\ntype Suiter interface {\n\tT() *testing.T\n\tState() state.State\n\tCtx() context.Context\n}\n\n// AssertResources asserts on a resource list.\nfunc AssertResources[R rtestutils.ResourceWithRD](\n\tsuiter Suiter,\n\trequiredIDs []resource.ID,\n\tcheck func(R, *assert.Assertions),\n\topts ...rtestutils.Option,\n) {\n\tctx, cancel := context.WithTimeout(suiter.Ctx(), 10*time.Second)\n\tdefer cancel()\n\n\trtestutils.AssertResources(ctx, suiter.T(), suiter.State(), requiredIDs, check, opts...)\n}\n\n// AssertResource asserts on a single resource.\nfunc AssertResource[R rtestutils.ResourceWithRD](\n\tsuiter Suiter,\n\trequiredIDs resource.ID,\n\tcheck func(R, *assert.Assertions),\n\topts ...rtestutils.Option,\n) {\n\tAssertResources(suiter, []resource.ID{requiredIDs}, check, opts...)\n}\n\n// AssertNoResource asserts that a resource no longer exists.\nfunc AssertNoResource[R rtestutils.ResourceWithRD](\n\tsuiter Suiter,\n\tid string,\n\topts ...rtestutils.Option,\n) {\n\tctx, cancel := context.WithTimeout(suiter.Ctx(), 10*time.Second)\n\tdefer cancel()\n\n\trtestutils.AssertNoResource[R](\n\t\tctx,\n\t\tsuiter.T(),\n\t\tsuiter.State(),\n\t\tid,\n\t\topts...,\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/advertised_peer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.etcd.io/etcd/api/v3/etcdserverpb\"\n\t\"go.uber.org/zap\"\n\n\tetcdcli \"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// AdvertisedPeerController updates advertised peer list for this instance of etcd.\ntype AdvertisedPeerController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AdvertisedPeerController) Name() string {\n\treturn \"etcd.AdvertisedPeerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AdvertisedPeerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: etcd.NamespaceName,\n\t\t\tType:      etcd.SpecType,\n\t\t\tID:        optional.Some(etcd.SpecID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: etcd.NamespaceName,\n\t\t\tType:      etcd.PKIStatusType,\n\t\t\tID:        optional.Some(etcd.PKIID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"etcd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AdvertisedPeerController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *AdvertisedPeerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tetcdService, err := safe.ReaderGet[*v1alpha1.Service](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, \"etcd\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd service: %w\", err)\n\t\t}\n\n\t\tif !(etcdService.TypedSpec().Healthy && etcdService.TypedSpec().Running) {\n\t\t\tcontinue\n\t\t}\n\n\t\tetcdSpec, err := safe.ReaderGet[*etcd.Spec](ctx, r, resource.NewMetadata(etcd.NamespaceName, etcd.SpecType, etcd.SpecID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd spec: %w\", err)\n\t\t}\n\n\t\t_, err = safe.ReaderGet[*etcd.PKIStatus](ctx, r, resource.NewMetadata(etcd.NamespaceName, etcd.PKIStatusType, etcd.PKIID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd PKI status: %w\", err)\n\t\t}\n\n\t\tif err = ctrl.updateAdvertisedPeers(ctx, logger, etcdSpec.TypedSpec().AdvertisedAddresses); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating advertised peers: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *AdvertisedPeerController) updateAdvertisedPeers(ctx context.Context, logger *zap.Logger, advertisedAddresses []netip.Addr) error {\n\tctx, cancel := context.WithTimeout(ctx, 30*time.Second)\n\tdefer cancel()\n\n\tclient, err := etcdcli.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating etcd client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\t// figure out local member ID\n\tresp, err := client.MemberList(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting member list: %w\", err)\n\t}\n\n\tlocalMemberID := resp.Header.MemberId\n\n\tvar localMember *etcdserverpb.Member\n\n\tfor _, member := range resp.Members {\n\t\tif member.ID == localMemberID {\n\t\t\tlocalMember = member\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif localMember == nil {\n\t\treturn errors.New(\"local member not found in member list\")\n\t}\n\n\tnewPeerURLs := xslices.Map(advertisedAddresses, func(addr netip.Addr) string {\n\t\treturn fmt.Sprintf(\"https://%s\", nethelpers.JoinHostPort(addr.String(), constants.EtcdPeerPort))\n\t})\n\tcurrentPeerURLs := localMember.PeerURLs\n\n\tif slices.Equal(newPeerURLs, currentPeerURLs) {\n\t\treturn nil\n\t}\n\n\tlogger.Debug(\"updating etcd peer URLs\",\n\t\tzap.Strings(\"current_peer_urls\", currentPeerURLs),\n\t\tzap.Strings(\"new_peer_urls\", newPeerURLs),\n\t\tzap.Uint64(\"member_id\", localMemberID),\n\t)\n\n\t_, err = client.MemberUpdate(ctx, localMemberID, newPeerURLs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error updating member: %w\", err)\n\t}\n\n\tlogger.Info(\"updated etcd peer URLs\",\n\t\tzap.Strings(\"new_peer_urls\", newPeerURLs),\n\t\tzap.Uint64(\"member_id\", localMemberID),\n\t)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\n// ConfigController watches v1alpha1.Config, updates etcd config.\ntype ConfigController = transform.Controller[*config.MachineConfig, *etcd.Config]\n\n// NewConfigController instanciates the config controller.\n//\n//nolint:gocyclo\nfunc NewConfigController() *ConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *etcd.Config]{\n\t\t\tName: \"etcd.ConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*etcd.Config] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*etcd.Config]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Machine() == nil || cfg.Config().Cluster() == nil {\n\t\t\t\t\treturn optional.None[*etcd.Config]()\n\t\t\t\t}\n\n\t\t\t\tif !cfg.Config().Machine().Type().IsControlPlane() {\n\t\t\t\t\t// etcd only runs on controlplane nodes\n\t\t\t\t\treturn optional.None[*etcd.Config]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(etcd.NewConfig(etcd.NamespaceName, etcd.ConfigID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, cfg *etcd.Config) error {\n\t\t\t\tcfg.TypedSpec().AdvertiseValidSubnets = machineConfig.Config().Cluster().Etcd().AdvertisedSubnets()\n\t\t\t\tcfg.TypedSpec().AdvertiseExcludeSubnets = nil\n\t\t\t\tcfg.TypedSpec().ListenValidSubnets = machineConfig.Config().Cluster().Etcd().ListenSubnets()\n\t\t\t\tcfg.TypedSpec().ListenExcludeSubnets = nil\n\n\t\t\t\t// filter out any virtual IPs, they can't be node IPs either\n\t\t\t\tfor _, device := range machineConfig.Config().Machine().Network().Devices() {\n\t\t\t\t\tif device.VIPConfig() != nil {\n\t\t\t\t\t\tcfg.TypedSpec().AdvertiseExcludeSubnets = append(cfg.TypedSpec().AdvertiseExcludeSubnets, device.VIPConfig().IP())\n\t\t\t\t\t}\n\n\t\t\t\t\tfor _, vlan := range device.Vlans() {\n\t\t\t\t\t\tif vlan.VIPConfig() != nil {\n\t\t\t\t\t\t\tcfg.TypedSpec().AdvertiseExcludeSubnets = append(cfg.TypedSpec().AdvertiseExcludeSubnets, vlan.VIPConfig().IP())\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor _, doc := range machineConfig.Config().NetworkVirtualIPConfigs() {\n\t\t\t\t\tcfg.TypedSpec().AdvertiseExcludeSubnets = append(cfg.TypedSpec().AdvertiseExcludeSubnets, doc.VIP().String())\n\t\t\t\t}\n\n\t\t\t\tcfg.TypedSpec().Image = machineConfig.Config().Cluster().Etcd().Image()\n\n\t\t\t\textraArgs := make(map[string]etcd.ArgValues, len(machineConfig.Config().Cluster().Etcd().ExtraArgs()))\n\n\t\t\t\tfor k, v := range machineConfig.Config().Cluster().Etcd().ExtraArgs() {\n\t\t\t\t\textraArgs[k] = etcd.ArgValues{Values: v}\n\t\t\t\t}\n\n\t\t\t\tcfg.TypedSpec().ExtraArgs = extraArgs\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd_test\n\nimport (\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tetcdctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/etcd\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(etcdctrl.NewConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ConfigSuite) TestReconcile() {\n\tfor _, tt := range []struct {\n\t\tname           string\n\t\tetcdConfig     *v1alpha1.EtcdConfig\n\t\tnetworkConfig  v1alpha1.NetworkDeviceList\n\t\texpectedConfig etcd.ConfigSpec\n\t\textraConfig    func(*testing.T) []configconfig.Document\n\t}{\n\t\t{\n\t\t\tname: \"default config\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage: \"foo/bar:v1.0.0\",\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                 \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:             map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets: nil,\n\t\t\t\tListenValidSubnets:    nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"extra args config\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage: \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdExtraArgs: v1alpha1.Args{\n\t\t\t\t\t\"foo\": v1alpha1.NewArgValue(\"\", []string{\"bar\", \"baz\"}),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs: map[string]etcd.ArgValues{\n\t\t\t\t\t\"foo\": {Values: []string{\"bar\", \"baz\"}},\n\t\t\t\t},\n\t\t\t\tAdvertiseValidSubnets: nil,\n\t\t\t\tListenValidSubnets:    nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"legacy subnet\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage: \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdExtraArgs: v1alpha1.Args{\n\t\t\t\t\t\"arg\": v1alpha1.NewArgValue(\"value\", nil),\n\t\t\t\t},\n\t\t\t\tEtcdSubnet: \"10.0.0.0/8\",\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs: map[string]etcd.ArgValues{\n\t\t\t\t\t\"arg\": {Values: []string{\"value\"}},\n\t\t\t\t},\n\t\t\t\tAdvertiseValidSubnets: []string{\"10.0.0.0/8\"},\n\t\t\t\tListenValidSubnets:    nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"advertised subnets\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage:        \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdAdvertisedSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                 \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:             map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t\tListenValidSubnets:    []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"advertised and listen subnets\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage:        \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdAdvertisedSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t\tEtcdListenSubnets:     []string{\"10.0.0.0/8\"},\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                 \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:             map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t\tListenValidSubnets:    []string{\"10.0.0.0/8\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"default with legacy vip\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage: \"foo/bar:v1.0.0\",\n\t\t\t},\n\t\t\tnetworkConfig: v1alpha1.NetworkDeviceList{\n\t\t\t\t{\n\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\tSharedIP: \"10.0.0.4\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                   \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:               map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets:   nil,\n\t\t\t\tAdvertiseExcludeSubnets: []string{\"10.0.0.4\"},\n\t\t\t\tListenValidSubnets:      nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"default with new vip\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage: \"foo/bar:v1.0.0\",\n\t\t\t},\n\t\t\textraConfig: func(*testing.T) []configconfig.Document {\n\t\t\t\tvipCfg := network.NewLayer2VIPConfigV1Alpha1(\"10.0.0.4\")\n\t\t\t\tvipCfg.LinkName = \"eth0\"\n\n\t\t\t\treturn []configconfig.Document{vipCfg}\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                   \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:               map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets:   nil,\n\t\t\t\tAdvertiseExcludeSubnets: []string{\"10.0.0.4\"},\n\t\t\t\tListenValidSubnets:      nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"advertised with legacy vip\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage:        \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdAdvertisedSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t\tnetworkConfig: v1alpha1.NetworkDeviceList{\n\t\t\t\t{\n\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\tSharedIP: \"10.0.0.4\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                   \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:               map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets:   []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t\tAdvertiseExcludeSubnets: []string{\"10.0.0.4\"},\n\t\t\t\tListenValidSubnets:      []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"advertised with new vip\",\n\t\t\tetcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\tContainerImage:        \"foo/bar:v1.0.0\",\n\t\t\t\tEtcdAdvertisedSubnets: []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t\textraConfig: func(*testing.T) []configconfig.Document {\n\t\t\t\tvipCfg := network.NewLayer2VIPConfigV1Alpha1(\"10.0.0.4\")\n\t\t\t\tvipCfg.LinkName = \"eth0\"\n\n\t\t\t\treturn []configconfig.Document{vipCfg}\n\t\t\t},\n\t\t\texpectedConfig: etcd.ConfigSpec{\n\t\t\t\tImage:                   \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs:               map[string]etcd.ArgValues{},\n\t\t\t\tAdvertiseValidSubnets:   []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t\tAdvertiseExcludeSubnets: []string{\"10.0.0.4\"},\n\t\t\t\tListenValidSubnets:      []string{\"10.0.0.0/8\", \"192.168.0.0/24\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.Run(tt.name, func() {\n\t\t\tcfgV1Alpha1 := &v1alpha1.Config{\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tEtcdConfig: tt.etcdConfig,\n\t\t\t\t},\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: tt.networkConfig,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tdocuments := []configconfig.Document{cfgV1Alpha1}\n\n\t\t\tif tt.extraConfig != nil {\n\t\t\t\tdocuments = slices.Concat(documents, tt.extraConfig(suite.T()))\n\t\t\t}\n\n\t\t\tctr, err := container.New(documents...)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tmachineConfig := config.NewMachineConfig(ctr)\n\t\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineConfig))\n\n\t\t\tsuite.AssertWithin(3*time.Second, 100*time.Millisecond, ctest.WrapRetry(func(assert *assert.Assertions, require *require.Assertions) {\n\t\t\t\tetcdConfig, err := safe.StateGet[*etcd.Config](suite.Ctx(), suite.State(), etcd.NewConfig(etcd.NamespaceName, etcd.ConfigID).Metadata())\n\t\t\t\tif err != nil {\n\t\t\t\t\tassert.NoError(err)\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(tt.expectedConfig, *etcdConfig.TypedSpec())\n\t\t\t}))\n\n\t\t\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), machineConfig.Metadata()))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package etcd provides controllers which manage etcd resources.\npackage etcd\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/member.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tpkgetcd \"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// MemberController updates information about the local etcd member.\ntype MemberController struct {\n\tGetLocalMemberIDFunc func(ctx context.Context) (uint64, error)\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MemberController) Name() string {\n\treturn \"etcd.MemberController\"\n}\n\nconst etcdServiceID = \"etcd\"\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MemberController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(etcdServiceID),\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MemberController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: etcd.MemberType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *MemberController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tm := etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID)\n\n\t\tetcdService, err := safe.ReaderGet[*v1alpha1.Service](ctx, r, v1alpha1.NewService(etcdServiceID).Metadata())\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting etcd service resource: %w\", err)\n\t\t}\n\n\t\tupdateMemberID := etcdService != nil && etcdService.Metadata().Phase() == resource.PhaseRunning && etcdService.TypedSpec().Healthy\n\n\t\tif updateMemberID {\n\t\t\tvar memberID uint64\n\n\t\t\tmemberID, err = ctrl.getLocalMemberID(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting etcd local member ID: %w\", err)\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, m, func(status *etcd.Member) error {\n\t\t\t\tstatus.TypedSpec().MemberID = etcd.FormatMemberID(memberID)\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating etcd member resource: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err = r.Destroy(ctx, m.Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error destroying etcd member resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// getLocalMemberID gets the etcd member ID of the local node.\nfunc (ctrl *MemberController) getLocalMemberID(ctx context.Context) (uint64, error) {\n\tif ctrl.GetLocalMemberIDFunc != nil {\n\t\treturn ctrl.GetLocalMemberIDFunc(ctx)\n\t}\n\n\tclient, err := pkgetcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\treturn client.GetMemberID(ctx)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/member_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tetcdctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nfunc TestMemberSuite(t *testing.T) {\n\tt.Parallel()\n\n\tctrl := &etcdctrl.MemberController{}\n\n\tsuite.Run(t, &MemberSuite{\n\t\tctrl: ctrl,\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(ctrl))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype MemberSuite struct {\n\tctest.DefaultSuite\n\n\tctrl *etcdctrl.MemberController\n}\n\nfunc (suite *MemberSuite) assertEtcdMember(member *etcd.Member) func() error {\n\treturn func() error {\n\t\tr, err := ctest.Get[*etcd.Member](suite, member.Metadata())\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tspec := r.TypedSpec()\n\t\texpectedSpec := member.TypedSpec()\n\n\t\tsuite.Require().Equal(expectedSpec.MemberID, spec.MemberID)\n\n\t\treturn nil\n\t}\n}\n\nfunc (suite *MemberSuite) assertInexistentEtcdMember(member *etcd.Member) func() error {\n\treturn func() error {\n\t\t_, err := suite.State().Get(suite.Ctx(), member.Metadata())\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn retry.ExpectedErrorf(\"should not exist\")\n\t}\n}\n\nfunc (suite *MemberSuite) TestEtcdRunning() {\n\t// given\n\tsuite.ctrl.GetLocalMemberIDFunc = func(ctx context.Context) (uint64, error) {\n\t\treturn 123, nil\n\t}\n\tetcdService := v1alpha1.NewService(\"etcd\")\n\tetcdService.TypedSpec().Running = true\n\tetcdService.TypedSpec().Healthy = true\n\n\t// when\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), etcdService))\n\n\t// then\n\texpectedMember := etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID)\n\texpectedMember.TypedSpec().MemberID = \"000000000000007b\"\n\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertEtcdMember(expectedMember),\n\t),\n\t)\n}\n\nfunc (suite *MemberSuite) TestEtcdNotRunning() {\n\t// given\n\tsuite.ctrl.GetLocalMemberIDFunc = func(ctx context.Context) (uint64, error) {\n\t\treturn 123, nil\n\t}\n\tetcdService := v1alpha1.NewService(\"etcd\")\n\tetcdService.TypedSpec().Running = false\n\n\t// when\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), etcdService))\n\n\t// then\n\texpectedMember := etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID)\n\texpectedMember.TypedSpec().MemberID = \"\"\n\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertInexistentEtcdMember(expectedMember),\n\t),\n\t)\n}\n\nfunc (suite *MemberSuite) TestCleanup() {\n\t// given\n\tsuite.ctrl.GetLocalMemberIDFunc = func(ctx context.Context) (uint64, error) {\n\t\treturn 123, nil\n\t}\n\tetcdService := v1alpha1.NewService(\"etcd\")\n\tetcdService.TypedSpec().Running = true\n\tetcdService.TypedSpec().Healthy = true\n\n\texpectedMember := etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID)\n\texpectedMember.TypedSpec().MemberID = \"000000000000007b\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), etcdService))\n\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertEtcdMember(expectedMember),\n\t),\n\t)\n\n\t// when\n\tokToDestroy, err := suite.State().Teardown(suite.Ctx(), etcdService.Metadata())\n\tsuite.Require().NoError(err)\n\tsuite.Require().True(okToDestroy)\n\n\t// then\n\tsuite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertInexistentEtcdMember(expectedMember),\n\t))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/pki.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/filetree\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// PKIController renders manifests based on templates and config/secrets.\ntype PKIController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PKIController) Name() string {\n\treturn \"etcd.PKIController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PKIController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EtcdRootType,\n\t\t\tID:        optional.Some(secrets.EtcdRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EtcdType,\n\t\t\tID:        optional.Some(secrets.EtcdID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PKIController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: etcd.PKIStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *PKIController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\trootScrts, err := safe.ReaderGet[*secrets.EtcdRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdRootType, secrets.EtcdRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting root secrets: %w\", err)\n\t\t}\n\n\t\tscrts, err := safe.ReaderGet[*secrets.Etcd](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdType, secrets.EtcdID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets: %w\", err)\n\t\t}\n\n\t\tif err = os.MkdirAll(constants.EtcdPKIPath, 0o700); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = selinux.SetLabel(constants.EtcdPKIPath, constants.EtcdPKISELinuxLabel); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = os.WriteFile(constants.EtcdCACert, rootScrts.TypedSpec().EtcdCA.Crt, 0o400); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write CA certificate: %w\", err)\n\t\t}\n\n\t\tif err = os.WriteFile(constants.EtcdCAKey, rootScrts.TypedSpec().EtcdCA.Key, 0o400); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write CA key: %w\", err)\n\t\t}\n\n\t\tetcdCerts := scrts.TypedSpec()\n\n\t\tfor _, keypair := range []struct {\n\t\t\tgetter   func() *x509.PEMEncodedCertificateAndKey\n\t\t\tkeyPath  string\n\t\t\tcertPath string\n\t\t}{\n\t\t\t{\n\t\t\t\tgetter:   func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.Etcd },\n\t\t\t\tkeyPath:  constants.EtcdKey,\n\t\t\t\tcertPath: constants.EtcdCert,\n\t\t\t},\n\t\t\t{\n\t\t\t\tgetter:   func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdPeer },\n\t\t\t\tkeyPath:  constants.EtcdPeerKey,\n\t\t\t\tcertPath: constants.EtcdPeerCert,\n\t\t\t},\n\t\t\t{\n\t\t\t\tgetter:   func() *x509.PEMEncodedCertificateAndKey { return etcdCerts.EtcdAdmin },\n\t\t\t\tkeyPath:  constants.EtcdAdminKey,\n\t\t\t\tcertPath: constants.EtcdAdminCert,\n\t\t\t},\n\t\t} {\n\t\t\tif err = os.WriteFile(keypair.keyPath, keypair.getter().Key, 0o400); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err = os.WriteFile(keypair.certPath, keypair.getter().Crt, 0o400); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = filetree.ChownRecursive(constants.EtcdPKIPath, constants.EtcdUserID, constants.EtcdUserID); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, etcd.NewPKIStatus(etcd.NamespaceName, etcd.PKIID), func(status *etcd.PKIStatus) error {\n\t\t\tstatus.TypedSpec().Ready = true\n\t\t\tstatus.TypedSpec().Version = scrts.Metadata().Version().String()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating PKI status: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/net\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// SpecController renders manifests based on templates and Spec/secrets.\ntype SpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SpecController) Name() string {\n\treturn \"etcd.SpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: etcd.NamespaceName,\n\t\t\tType:      etcd.ConfigType,\n\t\t\tID:        optional.Some(etcd.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: etcd.SpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *SpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tetcdConfig, err := safe.ReaderGet[*etcd.Config](ctx, r, resource.NewMetadata(etcd.NamespaceName, etcd.ConfigType, etcd.ConfigID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd config: %w\", err)\n\t\t}\n\n\t\thostnameStatus, err := safe.ReaderGet[*network.HostnameStatus](ctx, r, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting hostname status: %w\", err)\n\t\t}\n\n\t\tnodeRoutedAddrs, err := safe.ReaderGet[*network.NodeAddress](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.NodeAddressType,\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t}\n\n\t\tnodeCurrentAddrs, err := safe.ReaderGet[*network.NodeAddress](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.NodeAddressType,\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s),\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t}\n\n\t\troutedAddrs := nodeRoutedAddrs.TypedSpec().IPs()\n\t\tcurrentAddrs := nodeCurrentAddrs.TypedSpec().IPs()\n\n\t\t// need at least a single address\n\t\tif len(routedAddrs) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tadvertiseValidSubnets := etcdConfig.TypedSpec().AdvertiseValidSubnets\n\n\t\tif len(advertiseValidSubnets) == 0 {\n\t\t\t// not specified, advertise all addresses\n\t\t\tadvertiseValidSubnets = []string{\"0.0.0.0/0\", \"::/0\"}\n\t\t}\n\n\t\tadvertisedCIDRs := slices.Concat(\n\t\t\tadvertiseValidSubnets,\n\t\t\txslices.Map(etcdConfig.TypedSpec().AdvertiseExcludeSubnets, func(cidr string) string { return \"!\" + cidr }),\n\t\t)\n\n\t\tlistenCIDRs := slices.Concat(\n\t\t\tetcdConfig.TypedSpec().ListenValidSubnets,\n\t\t\txslices.Map(etcdConfig.TypedSpec().ListenExcludeSubnets, func(cidr string) string { return \"!\" + cidr }),\n\t\t)\n\n\t\tdefaultListenAddress := netip.IPv4Unspecified()\n\t\tloopbackAddress := netip.AddrFrom4([4]byte{127, 0, 0, 1})\n\n\t\tvar (\n\t\t\tadvertisedIPs   []netip.Addr\n\t\t\tlistenPeerIPs   []netip.Addr\n\t\t\tlistenClientIPs []netip.Addr\n\t\t)\n\n\t\tif len(etcdConfig.TypedSpec().AdvertiseValidSubnets) == 0 {\n\t\t\tadvertisedIPs, err = net.FilterIPs(routedAddrs, advertisedCIDRs)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error filtering IPs: %w\", err)\n\t\t\t}\n\n\t\t\t// if advertise subnet is not set, advertise the first address\n\t\t\tif len(advertisedIPs) > 0 {\n\t\t\t\tadvertisedIPs = advertisedIPs[:1]\n\t\t\t}\n\t\t} else {\n\t\t\tadvertisedIPs, err = net.FilterIPs(currentAddrs, advertisedCIDRs)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error filtering IPs: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif len(listenCIDRs) > 0 {\n\t\t\tlistenPeerIPs, err = net.FilterIPs(routedAddrs, listenCIDRs)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error filtering IPs: %w\", err)\n\t\t\t}\n\n\t\t\tlistenClientIPs = append([]netip.Addr{loopbackAddress}, listenPeerIPs...)\n\t\t} else {\n\t\t\tlistenPeerIPs = []netip.Addr{defaultListenAddress}\n\t\t\tlistenClientIPs = []netip.Addr{defaultListenAddress}\n\t\t}\n\n\t\tif len(advertisedIPs) == 0 || len(listenPeerIPs) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, etcd.NewSpec(etcd.NamespaceName, etcd.SpecID), func(status *etcd.Spec) error {\n\t\t\tstatus.TypedSpec().AdvertisedAddresses = advertisedIPs\n\t\t\tstatus.TypedSpec().ListenClientAddresses = listenClientIPs\n\t\t\tstatus.TypedSpec().ListenPeerAddresses = listenPeerIPs\n\t\t\tstatus.TypedSpec().Name = hostnameStatus.TypedSpec().Hostname\n\t\t\tstatus.TypedSpec().Image = etcdConfig.TypedSpec().Image\n\t\t\tstatus.TypedSpec().ExtraArgs = etcdConfig.TypedSpec().ExtraArgs\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating Spec status: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/etcd/spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tetcdctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &SpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&etcdctrl.SpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype SpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *SpecSuite) TestReconcile() {\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"worker1\"\n\thostnameStatus.TypedSpec().Domainname = \"some.domain\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\troutedAddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t)\n\n\troutedAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.0.0.5/24\"),\n\t\tnetip.MustParsePrefix(\"192.168.1.1/24\"),\n\t\tnetip.MustParsePrefix(\"192.168.1.50/32\"),\n\t\tnetip.MustParsePrefix(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334/64\"),\n\t\tnetip.MustParsePrefix(\"2002:0db8:85a3:0000:0000:8a2e:0370:7335/64\"),\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), routedAddresses))\n\n\tcurrentAddrs := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s),\n\t)\n\n\tcurrentAddrs.TypedSpec().Addresses = append(\n\t\t[]netip.Prefix{netip.MustParsePrefix(\"1.3.5.7/32\")},\n\t\troutedAddresses.TypedSpec().Addresses...,\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), currentAddrs))\n\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tcfg      etcd.ConfigSpec\n\t\texpected etcd.SpecSpec\n\t}{\n\t\t{\n\t\t\tname: \"defaults\",\n\t\t\tcfg: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs: map[string]etcd.ArgValues{\n\t\t\t\t\t\"arg\": {Values: []string{\"value\"}},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: etcd.SpecSpec{\n\t\t\t\tName:  \"worker1\",\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tExtraArgs: map[string]etcd.ArgValues{\n\t\t\t\t\t\"arg\": {Values: []string{\"value\"}},\n\t\t\t\t},\n\t\t\t\tAdvertisedAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"10.0.0.5\"),\n\t\t\t\t},\n\t\t\t\tListenPeerAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t\tListenClientAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"defaults with exclude\",\n\t\t\tcfg: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertiseExcludeSubnets: []string{\n\t\t\t\t\t\"10.0.0.5\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: etcd.SpecSpec{\n\t\t\t\tName:  \"worker1\",\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertisedAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t},\n\t\t\t\tListenPeerAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t\tListenClientAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"only advertised\",\n\t\t\tcfg: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertiseValidSubnets: []string{\n\t\t\t\t\t\"192.168.0.0/16\",\n\t\t\t\t\t\"1.3.5.7/32\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: etcd.SpecSpec{\n\t\t\t\tName:  \"worker1\",\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertisedAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.50\"),\n\t\t\t\t\tnetip.MustParseAddr(\"1.3.5.7\"),\n\t\t\t\t},\n\t\t\t\tListenPeerAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t\tListenClientAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"only advertised with exclude\",\n\t\t\tcfg: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertiseValidSubnets: []string{\n\t\t\t\t\t\"192.168.0.0/16\",\n\t\t\t\t},\n\t\t\t\tAdvertiseExcludeSubnets: []string{\n\t\t\t\t\t\"10.0.0.5\",\n\t\t\t\t\t\"192.168.1.50\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: etcd.SpecSpec{\n\t\t\t\tName:  \"worker1\",\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertisedAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t},\n\t\t\t\tListenPeerAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t\tListenClientAddresses: []netip.Addr{\n\t\t\t\t\tnetip.IPv4Unspecified(),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"advertised and listen\",\n\t\t\tcfg: etcd.ConfigSpec{\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertiseValidSubnets: []string{\n\t\t\t\t\t\"192.168.0.0/16\",\n\t\t\t\t\t\"2001::/16\",\n\t\t\t\t},\n\t\t\t\tListenValidSubnets: []string{\n\t\t\t\t\t\"192.168.0.0/16\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: etcd.SpecSpec{\n\t\t\t\tName:  \"worker1\",\n\t\t\t\tImage: \"foo/bar:v1.0.0\",\n\t\t\t\tAdvertisedAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.50\"),\n\t\t\t\t\tnetip.MustParseAddr(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\"),\n\t\t\t\t},\n\t\t\t\tListenPeerAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.50\"),\n\t\t\t\t},\n\t\t\t\tListenClientAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"127.0.0.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.50\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.Run(tt.name, func() {\n\t\t\tetcdConfig := etcd.NewConfig(etcd.NamespaceName, etcd.ConfigID)\n\t\t\t*etcdConfig.TypedSpec() = tt.cfg\n\n\t\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), etcdConfig))\n\n\t\t\tctest.AssertResource(suite, etcd.SpecID, func(etcdSpec *etcd.Spec, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(tt.expected, *etcdSpec.TypedSpec(), \"spec %v\", *etcdSpec.TypedSpec())\n\t\t\t})\n\n\t\t\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), etcdConfig.Metadata()))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/cri_base_runtime_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/containerd/containerd/v2/core/containers\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/platforms\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\n// CRIBaseRuntimeSpecController generates parts of the CRI config for base OCI runtime configuration.\ntype CRIBaseRuntimeSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *CRIBaseRuntimeSpecController) Name() string {\n\treturn \"files.CRIBaseRuntimeSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *CRIBaseRuntimeSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *CRIBaseRuntimeSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *CRIBaseRuntimeSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// wait for machine config to be available\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tif cfg.Config().Machine() == nil {\n\t\t\t// wait for machine config to be available\n\t\t\tcontinue\n\t\t}\n\n\t\tplatform := platforms.DefaultString()\n\n\t\tdefaultSpec, err := oci.GenerateSpecWithPlatform(\n\t\t\tnamespaces.WithNamespace(ctx, constants.K8sContainerdNamespace),\n\t\t\tnil,\n\t\t\tplatform,\n\t\t\t&containers.Container{},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating default spec: %w\", err)\n\t\t}\n\n\t\t// compatibility with CRI defaults:\n\t\t// * remove default rlimits (See https://github.com/containerd/cri/issues/515)\n\t\tdefaultSpec.Process.Rlimits = nil\n\n\t\tif len(cfg.Config().Machine().BaseRuntimeSpecOverrides()) > 0 {\n\t\t\tvar overrides oci.Spec\n\n\t\t\tjsonOverrides, err := json.Marshal(cfg.Config().Machine().BaseRuntimeSpecOverrides())\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error marshaling runtime spec overrides: %w\", err)\n\t\t\t}\n\n\t\t\tif err := json.Unmarshal(jsonOverrides, &overrides); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error unmarshaling runtime spec overrides: %w\", err)\n\t\t\t}\n\n\t\t\tif err := merge.Merge(defaultSpec, &overrides); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error merging runtime spec overrides: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tcontents, err := json.Marshal(defaultSpec)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error marshaling runtime spec: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, constants.CRIBaseRuntimeSpec),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Contents = contents\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/cri_base_runtime_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files_test\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tfilesctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\ntype CRIBaseRuntimeSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *CRIBaseRuntimeSpecSuite) TestDefaults() {\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, constants.CRIBaseRuntimeSpec, func(etcFile *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\tcontents := etcFile.TypedSpec().Contents\n\n\t\tvar ociSpec oci.Spec\n\n\t\tasrt.NoError(json.Unmarshal(contents, &ociSpec))\n\n\t\tasrt.Empty(ociSpec.Process.Rlimits)\n\t})\n}\n\nfunc (suite *CRIBaseRuntimeSpecSuite) TestOverrides() {\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineBaseRuntimeSpecOverrides: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"process\": map[string]any{\n\t\t\t\t\t\t\t\t\"rlimits\": []map[string]any{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"type\": \"RLIMIT_NOFILE\",\n\t\t\t\t\t\t\t\t\t\t\"hard\": 1024,\n\t\t\t\t\t\t\t\t\t\t\"soft\": 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite, constants.CRIBaseRuntimeSpec, func(etcFile *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\tcontents := etcFile.TypedSpec().Contents\n\n\t\tvar ociSpec oci.Spec\n\n\t\tasrt.NoError(json.Unmarshal(contents, &ociSpec))\n\n\t\tasrt.NotEmpty(ociSpec.Process.Rlimits)\n\t\tasrt.Equal(\"RLIMIT_NOFILE\", ociSpec.Process.Rlimits[0].Type)\n\t\tasrt.Equal(uint64(1024), ociSpec.Process.Rlimits[0].Hard)\n\t\tasrt.Equal(uint64(1024), ociSpec.Process.Rlimits[0].Soft)\n\t})\n}\n\nfunc TestCRIBaseRuntimeSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &CRIBaseRuntimeSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&filesctrl.CRIBaseRuntimeSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/cri_config_parts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/toml\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\n// CRIConfigPartsController merges parts of the CRI config from /etc/cri/conf.d/*.part into final /etc/cri/conf.d/cri.toml.\ntype CRIConfigPartsController struct {\n\t// Path to /etc/cri/conf.d directory.\n\tCRIConfdPath string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *CRIConfigPartsController) Name() string {\n\treturn \"files.CRIConfigPartsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *CRIConfigPartsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: files.NamespaceName,\n\t\t\tType:      files.EtcFileStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *CRIConfigPartsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *CRIConfigPartsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.CRIConfdPath == \"\" {\n\t\tctrl.CRIConfdPath = constants.EtcCRIConfdPath\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// scan conf.d directory for config parts and merge them together into final configuration\n\t\tparts, err := filepath.Glob(filepath.Join(ctrl.CRIConfdPath, \"*.part\"))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tslices.Sort(parts)\n\n\t\tout, checksums, err := toml.Merge(parts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, constants.CRIConfig),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tfor _, key := range r.Metadata().Annotations().Raw() {\n\t\t\t\t\tr.Metadata().Annotations().Delete(key)\n\t\t\t\t}\n\n\t\t\t\tfor path, checksum := range checksums {\n\t\t\t\t\tr.Metadata().Annotations().Set(files.SourceFileAnnotation+\":\"+path, hex.EncodeToString(checksum))\n\t\t\t\t}\n\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Contents = out\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/cri_registry_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/cri/containerd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// CRIRegistryConfigController generates parts of the CRI config for registry configuration.\ntype CRIRegistryConfigController struct {\n\t// Path to /etc directory, read-only filesystem.\n\tEtcPath string\n\t// EtcRoot is the root for /etc filesystem operations.\n\tEtcRoot xfs.Root\n\n\tbindMountCreated bool\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *CRIRegistryConfigController) Name() string {\n\treturn \"files.CRIRegistryConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *CRIRegistryConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cri.NamespaceName,\n\t\t\tType:      cri.RegistriesConfigType,\n\t\t\tID:        optional.Some(cri.RegistriesConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *CRIRegistryConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *CRIRegistryConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tsrc := filepath.Join(constants.CRIConfdPath, \"hosts\")\n\tdest := filepath.Join(ctrl.EtcPath, src)\n\n\tif !ctrl.bindMountCreated {\n\t\tif ctrl.EtcRoot.FSType() == \"os\" {\n\t\t\tshadowPath := filepath.Join(ctrl.EtcRoot.Source(), src)\n\n\t\t\tif err := createBindMountDir(shadowPath, dest); err != nil {\n\t\t\t\treturn fmt.Errorf(\"bind mount failed for %q -> %q: %w\", shadowPath, dest, err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err := createBindMountDirFd(ctrl.EtcRoot, src, dest); err != nil {\n\t\t\t\treturn fmt.Errorf(\"bind mount failed for %q: %w\", dest, err)\n\t\t\t}\n\t\t}\n\n\t\tctrl.bindMountCreated = true\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*cri.RegistriesConfig](ctx, r, cri.RegistriesConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting registries config: %w\", err)\n\t\t}\n\n\t\tvar (\n\t\t\tcriRegistryContents []byte\n\t\t\tcriHosts            *containerd.HostsConfig\n\t\t)\n\n\t\tif cfg != nil {\n\t\t\tcriRegistryContents, err = containerd.GenerateCRIConfig(cfg.TypedSpec())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcriHosts, err = containerd.GenerateHosts(cfg.TypedSpec(), dest)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tcriHosts = &containerd.HostsConfig{}\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, constants.CRIRegistryConfigPart),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Contents = criRegistryContents\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tif err := ctrl.syncHosts(src, criHosts, logger); err != nil {\n\t\t\treturn fmt.Errorf(\"error syncing hosts: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *CRIRegistryConfigController) syncHosts(basePath string, criHosts *containerd.HostsConfig, _ *zap.Logger) error {\n\t// 1. create/update all files and directories\n\tfor dirName, directory := range criHosts.Directories {\n\t\tpath := filepath.Join(basePath, dirName)\n\n\t\tif err := xfs.MkdirAll(ctrl.EtcRoot, path, 0o700); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, file := range directory.Files {\n\t\t\t// match contents to see if the update can be skipped\n\t\t\tcontents, err := xfs.ReadFile(ctrl.EtcRoot, filepath.Join(path, file.Name))\n\t\t\tif err == nil && bytes.Equal(contents, file.Contents) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// write file\n\t\t\tif err = xfs.WriteFile(\n\t\t\t\tctrl.EtcRoot,\n\t\t\t\tfilepath.Join(path, file.Name),\n\t\t\t\tfile.Contents,\n\t\t\t\tfile.Mode,\n\t\t\t); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// remove any files which shouldn't be present\n\t\tfileList, err := xfs.ReadDir(ctrl.EtcRoot, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfileListMap := xslices.ToSetFunc(fileList, fs.DirEntry.Name)\n\n\t\tfor _, file := range directory.Files {\n\t\t\tdelete(fileListMap, file.Name)\n\t\t}\n\n\t\tfor file := range fileListMap {\n\t\t\tif err = xfs.Remove(ctrl.EtcRoot, filepath.Join(path, file)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. remove any directories which shouldn't be present\n\tdirectoryList, err := xfs.ReadDir(ctrl.EtcRoot, basePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdirectoryListMap := make(map[string]struct{}, len(directoryList))\n\n\tfor _, dir := range directoryList {\n\t\tdirectoryListMap[dir.Name()] = struct{}{}\n\t}\n\n\tfor dirName := range criHosts.Directories {\n\t\tdelete(directoryListMap, dirName)\n\t}\n\n\tfor dirName := range directoryListMap {\n\t\tif err = xfs.RemoveAll(ctrl.EtcRoot, filepath.Join(basePath, dirName)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/etcfile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// EtcFileController watches EtcFileSpecs, creates/updates files.\ntype EtcFileController struct {\n\t// Path to /etc directory, read-only filesystem.\n\tEtcPath string\n\t// EtcRoot is the root for /etc filesystem operations.\n\tEtcRoot xfs.Root\n\n\t// Cache of bind mounts created.\n\tbindMounts map[string]any\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Name() string {\n\treturn \"files.EtcFileController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: files.NamespaceName,\n\t\t\tType:      files.EtcFileSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.bindMounts == nil {\n\t\tctrl.bindMounts = make(map[string]any)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tlist, err := safe.ReaderList[*files.EtcFileSpec](ctx, r, resource.NewMetadata(files.NamespaceName, files.EtcFileSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing specs: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tfor spec := range list.All() {\n\t\t\tfilename := spec.Metadata().ID()\n\t\t\t_, mountExists := ctrl.bindMounts[filename]\n\n\t\t\tdst := filepath.Join(ctrl.EtcPath, filename)\n\t\t\tsrc := filename\n\n\t\t\tswitch spec.Metadata().Phase() {\n\t\t\tcase resource.PhaseTearingDown:\n\t\t\t\tif mountExists {\n\t\t\t\t\tlogger.Debug(\"removing bind mount\", zap.String(\"src\", src), zap.String(\"dst\", dst))\n\n\t\t\t\t\tif err = unix.Unmount(dst, 0); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to unmount bind mount %q: %w\", dst, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tdelete(ctrl.bindMounts, filename)\n\t\t\t\t}\n\n\t\t\t\tlogger.Debug(\"removing file\", zap.String(\"src\", src))\n\n\t\t\t\tif err = xfs.Remove(ctrl.EtcRoot, src); err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\treturn fmt.Errorf(\"failed to remove %q: %w\", src, err)\n\t\t\t\t}\n\n\t\t\t\t// now remove finalizer as the link was deleted\n\t\t\t\tif err = r.RemoveFinalizer(ctx, spec.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t\t}\n\t\t\tcase resource.PhaseRunning:\n\t\t\t\tif !mountExists {\n\t\t\t\t\tlogger.Debug(\"creating bind mount\", zap.String(\"src\", src), zap.String(\"dst\", dst))\n\n\t\t\t\t\tif ctrl.EtcRoot.FSType() == \"os\" {\n\t\t\t\t\t\tshadow := filepath.Join(ctrl.EtcRoot.Source(), src)\n\n\t\t\t\t\t\tif err = createBindMountFile(shadow, dst, spec.TypedSpec().Mode); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to create shadow bind mount %q -> %q (mode: os): %w\", shadow, dst, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif err = createBindMountFileFd(ctrl.EtcRoot, src, dst, spec.TypedSpec().Mode); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to create shadow bind mount %q -> %q (mode: fd): %w\", src, dst, err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tctrl.bindMounts[filename] = struct{}{}\n\t\t\t\t}\n\n\t\t\t\tlogger.Debug(\"writing file contents\", zap.String(\"src\", src), zap.Stringer(\"version\", spec.Metadata().Version()))\n\n\t\t\t\tif err = UpdateFile(ctrl.EtcRoot, src, spec.TypedSpec().Contents, spec.TypedSpec().Mode, spec.TypedSpec().SelinuxLabel); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating %q: %w\", src, err)\n\t\t\t\t}\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, files.NewEtcFileStatus(files.NamespaceName, filename), func(r *files.EtcFileStatus) error {\n\t\t\t\t\tr.TypedSpec().SpecVersion = spec.Metadata().Version().String()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\ttouchedIDs[filename] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\t// list statuses for cleanup\n\t\tstatuses, err := safe.ReaderList[*files.EtcFileStatus](ctx, r, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor res := range statuses.All() {\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// createBindMountFile creates a common way to create a writable source file with a\n// bind mounted destination. This is most commonly used for well known files\n// under /etc that need to be adjusted during startup.\nfunc createBindMountFile(src, dst string, mode os.FileMode) (err error) {\n\tif err = os.MkdirAll(filepath.Dir(src), 0o755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir all failed: %w\", err)\n\t}\n\n\tvar f *os.File\n\n\tif f, err = os.OpenFile(src, os.O_WRONLY|os.O_CREATE, mode); err != nil {\n\t\treturn fmt.Errorf(\"open file failed: %w\", err)\n\t}\n\n\tif err = f.Close(); err != nil {\n\t\treturn fmt.Errorf(\"close file failed: %w\", err)\n\t}\n\n\treturn mount.BindReadonly(src, dst)\n}\n\n// createBindMountDir creates a common way to create a writable source dir with a\n// bind mounted destination. This is most commonly used for well known directories\n// under /etc that need to be adjusted during startup.\nfunc createBindMountDir(src, dst string) (err error) {\n\tif err = os.MkdirAll(src, 0o755); err != nil {\n\t\treturn err\n\t}\n\n\treturn mount.BindReadonly(src, dst)\n}\n\n// createBindMountFileFd creates a common way to create a writable source file with a\n// bind mounted destination. This is most commonly used for well known files\n// under /etc that need to be adjusted during startup.\nfunc createBindMountFileFd(root xfs.Root, src, dst string, mode os.FileMode) (err error) {\n\tif err = xfs.MkdirAll(root, filepath.Dir(src), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tfsrc, err := xfs.OpenFile(root, src, os.O_WRONLY|os.O_CREATE, mode)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer fsrc.Close() //nolint:errcheck\n\n\treturn mount.BindReadonlyFd(int(fsrc.Fd()), dst)\n}\n\n// createBindMountDirFd creates a common way to create a writable source dir with a\n// bind mounted destination. This is most commonly used for well known directories\n// under /etc that need to be adjusted during startup.\nfunc createBindMountDirFd(root xfs.Root, src, dst string) (err error) {\n\tif err = xfs.MkdirAll(root, src, 0o755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir all failed: %w\", err)\n\t}\n\n\tf, err := xfs.OpenFile(root, src, os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open file failed: %w\", err)\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\treturn mount.BindReadonlyFd(int(f.Fd()), dst)\n}\n\n// UpdateFile is like `os.WriteFile`, but it will only update the file if the\n// contents have changed.\nfunc UpdateFile(root xfs.Root, filename string, contents []byte, mode os.FileMode, selinuxLabel string) error {\n\toldContents, err := xfs.ReadFile(root, filename)\n\tif err == nil && bytes.Equal(oldContents, contents) {\n\t\treturn selinux.FSetLabel(root, filename, selinuxLabel)\n\t}\n\n\tif err = xfs.MkdirAll(root, filepath.Dir(filename), 0o755); err != nil {\n\t\treturn fmt.Errorf(\"mkdir all failed: %w\", err)\n\t}\n\n\tif err := xfs.WriteFile(root, filename, contents, mode); err != nil {\n\t\treturn fmt.Errorf(\"write file failed: %w\", err)\n\t}\n\n\treturn selinux.FSetLabel(root, filename, selinuxLabel)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/etcfile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\tosruntime \"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tfilesctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/files\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\ntype EtcFileSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *osruntime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tetcPath string\n\tetcRoot xfs.Root\n}\n\nfunc (suite *EtcFileSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = osruntime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.startRuntime()\n\n\tok, err := runtime.KernelCapabilities().OpentreeOnAnonymousFS()\n\tsuite.Require().NoError(err)\n\n\tsuite.etcPath = suite.T().TempDir()\n\n\tif ok {\n\t\tsuite.etcRoot = &xfs.UnixRoot{FS: opentree.NewFromPath(suite.T().TempDir())}\n\t} else {\n\t\tsuite.etcRoot = &xfs.OSRoot{Shadow: suite.T().TempDir()}\n\t}\n\n\tsuite.Require().NoError(suite.etcRoot.OpenFS())\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&filesctrl.EtcFileController{\n\t\t\t\tEtcPath: suite.etcPath,\n\t\t\t\tEtcRoot: suite.etcRoot,\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *EtcFileSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *EtcFileSuite) assertFileContents(root xfs.Root, filename, contents string) error {\n\trwb, err := xfs.ReadFile(root, filename)\n\tif err != nil {\n\t\treturn retry.ExpectedError(err)\n\t}\n\n\tif string(rwb) != contents {\n\t\treturn retry.ExpectedErrorf(\"contents for RW file %q don't match %q != %q\", filename, string(rwb), contents)\n\t}\n\n\trob, err := os.ReadFile(filepath.Join(suite.etcPath, filename))\n\tif err != nil {\n\t\treturn retry.ExpectedError(err)\n\t}\n\n\tif string(rob) != contents {\n\t\treturn retry.ExpectedErrorf(\"contents for RO file %q don't match %q != %q\", filepath.Join(suite.etcPath, filename), string(rob), contents)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *EtcFileSuite) assertEtcFile(filename, contents string, expectedVersion resource.Version) error {\n\tif err := suite.assertFileContents(suite.etcRoot, filename, contents); err != nil {\n\t\treturn err // Already wrapped in the retry.ExpectedError\n\t}\n\n\tr, err := safe.ReaderGet[*files.EtcFileStatus](suite.ctx, suite.state, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, filename, resource.VersionUndefined))\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tversion := r.TypedSpec().SpecVersion\n\n\texpected, err := strconv.Atoi(expectedVersion.String())\n\tsuite.Require().NoError(err)\n\n\tver, err := strconv.Atoi(version)\n\tsuite.Require().NoError(err)\n\n\tif ver < expected {\n\t\treturn retry.ExpectedErrorf(\"version mismatch %s > %s\", expectedVersion, version)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *EtcFileSuite) TestFiles() {\n\tetcFileSpec := files.NewEtcFileSpec(files.NamespaceName, \"test1\")\n\tetcFileSpec.TypedSpec().Contents = []byte(\"foo\")\n\tetcFileSpec.TypedSpec().Mode = 0o644\n\n\t// create \"read-only\" mock (in Talos it's part of rootfs)\n\tsuite.T().Logf(\"mock created %q\", filepath.Join(suite.etcPath, etcFileSpec.Metadata().ID()))\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(suite.etcPath, etcFileSpec.Metadata().ID()), nil, 0o644))\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, etcFileSpec))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertEtcFile(\"test1\", \"foo\", etcFileSpec.Metadata().Version())\n\t\t\t},\n\t\t),\n\t)\n\n\tfor _, r := range []resource.Resource{etcFileSpec} {\n\t\tfor {\n\t\t\tready, err := suite.state.Teardown(suite.ctx, r.Metadata())\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tif ready {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}\n}\n\nfunc (suite *EtcFileSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n\n\tsuite.etcRoot.Close() //nolint:errcheck\n}\n\nfunc TestEtcFileSuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, new(EtcFileSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/files.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package files provides controllers which manage file resources.\npackage files\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/iqn.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\n// IQNController creates an EtcFileSpec for the iSCSI Qualified Name (IQN) file.\ntype IQNController struct {\n\tV1Alpha1Mode runtimetalos.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *IQNController) Name() string {\n\treturn \"files.IQNController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *IQNController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *IQNController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *IQNController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// Skip the controller if we're running in a container.\n\tif ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// get the local node identity\n\t\tlocalIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get machine-id etcfile status: %w\", err)\n\t\t}\n\n\t\tmachineID, err := clusteradapter.IdentitySpec(localIdentity.TypedSpec()).ConvertMachineID()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to convert identity to machine ID: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"iscsi/initiatorname.iscsi\"),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\t// Fri Nov 3 16:19:12 2017 -0700 is the date of the first commit in the talos repository.\n\t\t\t\tspec.Contents = fmt.Appendf([]byte{}, \"InitiatorName=iqn.2017-11.dev.talos:%s\\n\", machineID)\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/files/nqn.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\n// NQNController creates an EtcFileSpec for the NVMe Qualified Name (NQN) and HostID file.\ntype NQNController struct {\n\tV1Alpha1Mode runtimetalos.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NQNController) Name() string {\n\treturn \"files.NQNController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NQNController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NQNController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NQNController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// Skip the controller if we're running in a container.\n\tif ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// get the local node identity\n\t\tlocalIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get machine-id etcfile status: %w\", err)\n\t\t}\n\n\t\tmachineID, err := clusteradapter.IdentitySpec(localIdentity.TypedSpec()).ConvertMachineID()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to convert identity to machine ID: %w\", err)\n\t\t}\n\n\t\thostID, err := uuid.FromBytes(machineID[:16])\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to convert machine-id to UUID: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"nvme/hostid\"),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Contents = []byte(hostID.String())\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"nvme/hostnqn\"),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\t// Fri Nov 3 16:19:12 2017 -0700 is the date of the first commit in the talos repository.\n\t\t\t\tspec.Contents = fmt.Appendf([]byte{}, \"nqn.2017-11.dev.talos:uuid:%s\", hostID.String())\n\t\t\t\tspec.Mode = 0o600\n\t\t\t\tspec.SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/hardware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package hardware provides the hardware controller implementation.\npackage hardware\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/hardware_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n)\n\ntype HardwareSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *HardwareSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *HardwareSuite) assertNoResource(md resource.Metadata) func() error {\n\treturn func() error {\n\t\t_, err := suite.state.Get(suite.ctx, md)\n\t\tif err == nil {\n\t\t\treturn retry.ExpectedErrorf(\"resource %s still exists\", md)\n\t\t}\n\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n}\n\nfunc (suite *HardwareSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc (suite *HardwareSuite) State() state.State {\n\treturn suite.state\n}\n\nfunc (suite *HardwareSuite) Ctx() context.Context {\n\treturn suite.ctx\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/pci_driver_rebind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\nconst (\n\ttargetDeviceSYSFSPath = \"/sys/bus/pci/devices/%s\"\n\tdriverOverridePath    = targetDeviceSYSFSPath + \"/driver_override\"\n\tdriverUnbindPath      = targetDeviceSYSFSPath + \"/driver/unbind\"\n\tdriverPath            = targetDeviceSYSFSPath + \"/driver\"\n\tdriverProbePath       = \"/sys/bus/pci/drivers_probe\"\n)\n\n// PCIDriverRebindController binds PCI devices to a specific driver and unbinds them from the host driver.\ntype PCIDriverRebindController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n\n\tboundDevices map[string]struct{}\n}\n\n// Name implements controller.Controller interface.\nfunc (c *PCIDriverRebindController) Name() string {\n\treturn \"hardware.PCIDriverRebindController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (c *PCIDriverRebindController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (c *PCIDriverRebindController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: hardware.PCIDriverRebindStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (c *PCIDriverRebindController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) (err error) {\n\t// Skip PCI rebind handling if running in a container or agent mode.\n\tif c.V1Alpha1Mode.InContainer() || c.V1Alpha1Mode.IsAgent() {\n\t\treturn nil\n\t}\n\n\tif c.boundDevices == nil {\n\t\tc.boundDevices = map[string]struct{}{}\n\t}\n\n\t// wait for udevd to be healthy, this is to ensure that host drivers if any are loaded.\n\tif err := runtimectrl.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: hardware.NamespaceName,\n\t\t\t\tType:      hardware.PCIDriverRebindConfigType,\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for devices to be ready: %w\", err)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tpciDriverRebindConfigs, err := safe.ReaderListAll[*hardware.PCIDriverRebindConfig](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing all PCI rebind configs: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\ttouchedIDs := map[string]struct{}{}\n\n\t\tfor cfg := range pciDriverRebindConfigs.All() {\n\t\t\tif err := c.handlePCIDriverReBind(cfg.TypedSpec().PCIID, cfg.TypedSpec().TargetDriver); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tboundDriver, err := checkDeviceBoundDriver(cfg.TypedSpec().PCIID)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error checking bound driver for device with id: %s, %w\", cfg.TypedSpec().PCIID, err)\n\t\t\t}\n\n\t\t\tif boundDriver != cfg.TypedSpec().TargetDriver {\n\t\t\t\tlogger.Info(\n\t\t\t\t\t\"cannot validate if device is bound to target driver, ensure target driver module is loaded\",\n\t\t\t\t\tzap.String(\"id\", cfg.TypedSpec().PCIID),\n\t\t\t\t\tzap.String(\"targetDriver\", cfg.TypedSpec().TargetDriver),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tlogger.Info(\"PCI device bound to target driver\", zap.String(\"id\", cfg.TypedSpec().PCIID), zap.String(\"targetDriver\", cfg.TypedSpec().TargetDriver))\n\n\t\t\tif err := safe.WriterModify[*hardware.PCIDriverRebindStatus](ctx, r, hardware.NewPCIDriverRebindStatus(cfg.TypedSpec().PCIID), func(res *hardware.PCIDriverRebindStatus) error {\n\t\t\t\tres.TypedSpec().PCIID = cfg.TypedSpec().PCIID\n\t\t\t\tres.TypedSpec().TargetDriver = cfg.TypedSpec().TargetDriver\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating PCI rebind status: %w\", err)\n\t\t\t}\n\n\t\t\ttouchedIDs[cfg.TypedSpec().PCIID] = struct{}{}\n\t\t\tc.boundDevices[cfg.TypedSpec().PCIID] = struct{}{}\n\t\t}\n\n\t\t// cleanup any PCI devices that were not touched in the current run.\n\t\tfor pciID := range c.boundDevices {\n\t\t\tif _, ok := touchedIDs[pciID]; !ok {\n\t\t\t\t// writing a newline to driver_override file will set the device to default driver based on pci device id.\n\t\t\t\tif err := c.handlePCIDriverReBind(pciID, \"\\n\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"PCI device set to default\", zap.String(\"id\", pciID))\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*hardware.PCIDriverRebindStatus](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// handlePCIBindToTarget binds PCI device to a target driver and unbinds it from the host driver.\nfunc (c *PCIDriverRebindController) handlePCIDriverReBind(pciID, targetDriver string) error {\n\tif err := os.WriteFile(fmt.Sprintf(driverOverridePath, pciID), []byte(targetDriver), 0o200); err != nil {\n\t\treturn fmt.Errorf(\"error writing driver override for device with id: %s, target driver: %s, %w\", pciID, targetDriver, err)\n\t}\n\n\t// Unbind device from the host driver.\n\t// in some cases, the device may not be bound to any driver, so we ignore the error.\n\tif err := os.WriteFile(fmt.Sprintf(driverUnbindPath, pciID), []byte(pciID), 0o200); err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"error unbinding device with id: %s, %w\", pciID, err)\n\t}\n\n\tif err := os.WriteFile(driverProbePath, []byte(pciID), 0o200); err != nil {\n\t\treturn fmt.Errorf(\"error probing driver for device with id: %s, %w\", pciID, err)\n\t}\n\n\treturn nil\n}\n\n// checkDeviceBoundDriver checks if the device is bound to a driver or not bound at all.\nfunc checkDeviceBoundDriver(pciID string) (string, error) {\n\tdriverPath := fmt.Sprintf(driverPath, pciID)\n\n\tdriver, err := os.Readlink(driverPath)\n\tif err == nil {\n\t\treturn filepath.Base(driver), nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"error reading path: %s, %w\", driverPath, err)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/pci_driver_rebind_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// PCIDriverRebindConfigController generates configuration for PCI rebind.\ntype PCIDriverRebindConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PCIDriverRebindConfigController) Name() string {\n\treturn \"hardware.PCIDriverRebindConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PCIDriverRebindConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PCIDriverRebindConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: hardware.PCIDriverRebindConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *PCIDriverRebindConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) (err error) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil {\n\t\t\tfor _, pciDriverRebindConfig := range cfg.Config().PCIDriverRebindConfig().PCIDriverRebindConfigs() {\n\t\t\t\tif err := safe.WriterModify(ctx, r, hardware.NewPCIDriverRebindConfig(pciDriverRebindConfig.PCIID()), func(res *hardware.PCIDriverRebindConfig) error {\n\t\t\t\t\tres.TypedSpec().PCIID = pciDriverRebindConfig.PCIID()\n\t\t\t\t\tres.TypedSpec().TargetDriver = pciDriverRebindConfig.TargetDriver()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating PCI rebind config: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*hardware.PCIDriverRebindConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/pci_driver_rebind_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\thardwareconfigtype \"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\thardwareres \"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\ntype PCIDriverRebindConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestPCIDriverRebindConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(PCIDriverRebindConfigSuite))\n}\n\nfunc (suite *PCIDriverRebindConfigSuite) TestPCIDriverRebindConfig() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&hardware.PCIDriverRebindConfigController{}))\n\n\tpciDriverRebindConfig := &hardwareconfigtype.PCIDriverRebindConfigV1Alpha1{\n\t\tMetaName:        \"0000:04:00.00\",\n\t\tPCITargetDriver: \"vfio-pci\",\n\t}\n\n\tcfg, err := container.New(pciDriverRebindConfig)\n\tsuite.Require().NoError(err)\n\n\tnCfg := config.NewMachineConfig(cfg)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nCfg))\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), pciDriverRebindConfig.MetaName, func(cfg *hardwareres.PCIDriverRebindConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t\"0000:04:00.00\",\n\t\t\tcfg.TypedSpec().PCIID,\n\t\t)\n\t\tasrt.Equal(\n\t\t\t\"vfio-pci\",\n\t\t\tcfg.TypedSpec().TargetDriver,\n\t\t)\n\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), nCfg.Metadata()))\n\n\trtestutils.AssertNoResource[*hardwareres.PCIDriverRebindConfig](suite.Ctx(), suite.T(), suite.State(), pciDriverRebindConfig.MetaName)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/pcidevices.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pcidb/pkg/pcidb\"\n\t\"go.uber.org/zap\"\n\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// PCIDevicesController populates PCI device information.\ntype PCIDevicesController struct {\n\tV1Alpha1Mode runtimetalos.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PCIDevicesController) Name() string {\n\treturn \"hardware.PCIDevicesController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PCIDevicesController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"udevd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PCIDevicesController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: hardware.PCIDeviceType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *PCIDevicesController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// PCI device info doesn't make sense inside a container, so skip the controller\n\tif ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {\n\t\treturn nil\n\t}\n\n\t// [TODO]: a single run for now, need to figure out how to trigger rescan\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// we need to wait for udevd to be healthy & running so that we get the driver information too\n\t\tudevdService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"udevd\")\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get udevd service: %w\", err)\n\t\t}\n\n\t\tif udevdService.TypedSpec().Healthy && udevdService.TypedSpec().Running {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tdeviceIDs, err := os.ReadDir(\"/sys/bus/pci/devices\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error scanning devices: %w\", err)\n\t}\n\n\tlogger.Debug(\"found PCI devices\", zap.Int(\"count\", len(deviceIDs)))\n\n\tr.StartTrackingOutputs()\n\n\tfor _, deviceID := range deviceIDs {\n\t\tclass, err := readHexPCIInfo(deviceID.Name(), \"class\")\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error parsing device %s class: %w\", deviceID.Name(), err)\n\t\t}\n\n\t\tvendor, err := readHexPCIInfo(deviceID.Name(), \"vendor\")\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error parsing device %s vendor: %w\", deviceID.Name(), err)\n\t\t}\n\n\t\tproduct, err := readHexPCIInfo(deviceID.Name(), \"device\")\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error parsing device %s product: %w\", deviceID.Name(), err)\n\t\t}\n\n\t\tdriver, err := readDriverInfo(deviceID.Name())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing device %s driver: %w\", deviceID.Name(), err)\n\t\t}\n\n\t\tlogger.Debug(\"found PCI device\", zap.String(\"deviceID\", deviceID.Name()), zap.String(\"driver\", driver))\n\n\t\tclassID := pcidb.Class((class >> 16) & 0xff)\n\t\tsubclassID := pcidb.Subclass((class >> 8) & 0xff)\n\t\tvendorID := pcidb.Vendor(vendor)\n\t\tproductID := pcidb.Product(product)\n\n\t\tif err := safe.WriterModify(ctx, r, hardware.NewPCIDeviceInfo(deviceID.Name()), func(r *hardware.PCIDevice) error {\n\t\t\tr.TypedSpec().ClassID = fmt.Sprintf(\"0x%02x\", classID)\n\t\t\tr.TypedSpec().SubclassID = fmt.Sprintf(\"0x%02x\", subclassID)\n\t\t\tr.TypedSpec().VendorID = fmt.Sprintf(\"0x%04x\", vendorID)\n\t\t\tr.TypedSpec().ProductID = fmt.Sprintf(\"0x%04x\", productID)\n\n\t\t\tr.TypedSpec().Class, _ = pcidb.LookupClass(classID)\n\t\t\tr.TypedSpec().Subclass, _ = pcidb.LookupSubclass(classID, subclassID)\n\t\t\tr.TypedSpec().Vendor, _ = pcidb.LookupVendor(vendorID)\n\t\t\tr.TypedSpec().Product, _ = pcidb.LookupProduct(vendorID, productID)\n\t\t\tr.TypedSpec().Driver = driver\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying output resource: %w\", err)\n\t\t}\n\t}\n\n\tif err = safe.CleanupOutputs[*hardware.PCIDevice](ctx, r); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc readHexPCIInfo(deviceID, info string) (uint64, error) {\n\tcontents, err := os.ReadFile(filepath.Join(\"/sys/bus/pci/devices\", deviceID, info))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn strconv.ParseUint(string(bytes.TrimSpace(contents)), 0, 64)\n}\n\nfunc readDriverInfo(deviceID string) (string, error) {\n\tlink, err := os.Readlink(filepath.Join(\"/sys/bus/pci/devices\", deviceID, \"driver\"))\n\tif err != nil {\n\t\t// ignore if the driver doesn't exist\n\t\t// this can happen if the device is not bound to a driver or a pci root port\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn \"\", nil\n\t\t}\n\n\t\treturn \"\", err\n\t}\n\n\treturn filepath.Base(link), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/pcr_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"maps\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// PCRStatusController manages TPM PCR extension.\ntype PCRStatusController struct {\n\tV1Alpha1Mode runtimetalos.Mode\n\n\tnumberOfExtensions int\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PCRStatusController) Name() string {\n\treturn \"hardware.PCRStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PCRStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PCRStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: hardware.PCRStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *PCRStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// PCR status doesn't make sense inside a container, so skip the controller\n\tif ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tswitch ctrl.numberOfExtensions {\n\t\tcase 0:\n\t\t\t// extend the PCR for the first time\n\t\t\t// this unlock initial PCR extension\n\t\t\tif err := tpm2.PCRExtend(constants.UKIPCR, []byte(secureboot.EnterMachined)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error performing initial PCR extension: %w\", err)\n\t\t\t}\n\n\t\t\tif err := r.Create(ctx, hardware.NewPCCRStatus(constants.UKIPCR)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating PCRStatus resource: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"TPM is ready for disk encryption operations (if available)\")\n\n\t\t\tctrl.numberOfExtensions++\n\t\tcase 1:\n\t\t\t// as long as Volumes were provisioned, we extend the PCR once again locking further access to the TPM\n\t\t\tvolumeStatuses, err := safe.ReaderListAll[*block.VolumeStatus](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error listing volume statuses: %w\", err)\n\t\t\t}\n\n\t\t\tvolumesReady := map[string]struct{}{}\n\t\t\tvolumesPending := map[string]struct{}{}\n\n\t\t\tfor volumeStatus := range volumeStatuses.All() {\n\t\t\t\tswitch volumeStatus.TypedSpec().Type {\n\t\t\t\tcase block.VolumeTypeDisk, block.VolumeTypePartition:\n\t\t\t\t\t// can be encrypted\n\t\t\t\tcase block.VolumeTypeDirectory, block.VolumeTypeOverlay, block.VolumeTypeSymlink, block.VolumeTypeTmpfs, block.VolumeTypeExternal:\n\t\t\t\t\t// skip it, not encryptable\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tswitch volumeStatus.TypedSpec().Phase {\n\t\t\t\tcase block.VolumePhaseMissing:\n\t\t\t\t\t// skip it, missing\n\t\t\t\tcase block.VolumePhaseReady:\n\t\t\t\t\tvolumesReady[volumeStatus.Metadata().ID()] = struct{}{}\n\t\t\t\tcase block.VolumePhaseClosed:\n\t\t\t\t\t// skip it, closed\n\t\t\t\tcase block.VolumePhaseLocated, block.VolumePhaseWaiting, block.VolumePhaseFailed,\n\t\t\t\t\tblock.VolumePhaseProvisioned, block.VolumePhasePrepared:\n\t\t\t\t\tvolumesPending[volumeStatus.Metadata().ID()] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnotReady := false\n\n\t\t\tfor _, requiredVolumeID := range []string{constants.StatePartitionLabel, constants.EphemeralPartitionLabel} {\n\t\t\t\tif _, ready := volumesReady[requiredVolumeID]; !ready {\n\t\t\t\t\tlogger.Debug(\"skipping PCR extension, volume not ready\", zap.String(\"volume\", requiredVolumeID))\n\n\t\t\t\t\tnotReady = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif notReady {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif len(volumesPending) > 0 {\n\t\t\t\tpendingVolumes := slices.Sorted(maps.Keys(volumesPending))\n\n\t\t\t\tlogger.Debug(\"skipping PCR extension, volumes not ready\", zap.Strings(\"volumes\", pendingVolumes))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// ready to extend\n\t\t\treadyToDestroy, err := r.Teardown(ctx, hardware.NewPCCRStatus(constants.UKIPCR).Metadata())\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error tearing down PCRStatus resource: %w\", err)\n\t\t\t}\n\n\t\t\tif !readyToDestroy {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.Destroy(ctx, hardware.NewPCCRStatus(constants.UKIPCR).Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error destroying PCRStatus resource: %w\", err)\n\t\t\t}\n\n\t\t\tif err := tpm2.PCRExtend(constants.UKIPCR, []byte(secureboot.StartTheWorld)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error performing PCR extension: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"TPM is locked to block any disk encryption operation (if available)\")\n\n\t\t\tctrl.numberOfExtensions++\n\t\tcase 2: // nothing to do, we are done\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/system.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/prometheus/procfs\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-smbios/smbios\"\n\t\"go.uber.org/zap\"\n\n\thwadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/hardware\"\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tpkgSMBIOS \"github.com/siderolabs/talos/internal/pkg/smbios\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// SystemInfoController populates CPU information of the underlying hardware.\ntype SystemInfoController struct {\n\tV1Alpha1Mode runtimetalos.Mode\n\tSMBIOS       *smbios.SMBIOS\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SystemInfoController) Name() string {\n\treturn \"hardware.SystemInfoController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SystemInfoController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MetaKeyType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MetaLoadedType,\n\t\t\tID:        optional.Some(runtime.MetaLoadedID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SystemInfoController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: hardware.ProcessorType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: hardware.MemoryModuleType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: hardware.SystemInformationType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nconst memoryModuleUnknown = \"UNKNOWN\"\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *SystemInfoController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// smbios info is not available inside container, so skip the controller\n\tif ctrl.V1Alpha1Mode == runtimetalos.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t_, err := safe.ReaderGetByID[*runtime.MetaLoaded](ctx, r, runtime.MetaLoadedID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting meta loaded resource: %w\", err)\n\t\t}\n\n\t\tif ctrl.SMBIOS == nil {\n\t\t\tvar s *smbios.SMBIOS\n\n\t\t\ts, err = pkgSMBIOS.GetSMBIOSInfo()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tctrl.SMBIOS = s\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif err := ctrl.reconcileSystemInformation(ctx, r, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := ctrl.reconcileProcessors(ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := ctrl.reconcileMemoryModules(ctx, r, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := r.CleanupOutputs(ctx,\n\t\t\tresource.NewMetadata(hardware.NamespaceName, hardware.SystemInformationType, hardware.SystemInformationID, resource.VersionUndefined),\n\t\t\tresource.NewMetadata(hardware.NamespaceName, hardware.ProcessorType, \"\", resource.VersionUndefined),\n\t\t\tresource.NewMetadata(hardware.NamespaceName, hardware.MemoryModuleType, \"\", resource.VersionUndefined),\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *SystemInfoController) reconcileSystemInformation(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tuuidRewriteRes, err := safe.ReaderGetByID[*runtime.MetaKey](ctx, r, runtime.MetaKeyTagToID(meta.UUIDOverride))\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn fmt.Errorf(\"error getting meta key resource: %w\", err)\n\t}\n\n\tvar uuidRewrite string\n\n\tif uuidRewriteRes != nil && uuidRewriteRes.TypedSpec().Value != \"\" {\n\t\tuuidRewrite = uuidRewriteRes.TypedSpec().Value\n\n\t\tlogger.Info(\"using UUID rewrite\", zap.String(\"uuid\", uuidRewrite))\n\t}\n\n\tif err := safe.WriterModify(ctx, r, hardware.NewSystemInformation(hardware.SystemInformationID), func(res *hardware.SystemInformation) error {\n\t\thwadapter.SystemInformation(res).Update(&ctrl.SMBIOS.SystemInformation, uuidRewrite)\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating objects: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *SystemInfoController) reconcileProcessors(ctx context.Context, r controller.Runtime) error {\n\tfor _, p := range ctrl.SMBIOS.ProcessorInformation {\n\t\t// replaces `CPU 0` with `CPU-0`\n\t\tid := strings.ReplaceAll(p.SocketDesignation, \" \", \"-\")\n\n\t\tif err := safe.WriterModify(ctx, r, hardware.NewProcessorInfo(id), func(res *hardware.Processor) error {\n\t\t\thwadapter.Processor(res).Update(&p)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating objects: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *SystemInfoController) reconcileMemoryModules(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor _, m := range ctrl.SMBIOS.MemoryDevices {\n\t\t// replaces `SIMM 0` with `SIMM-0`\n\t\tid := strings.ReplaceAll(m.DeviceLocator, \" \", \"-\")\n\n\t\tif err := safe.WriterModify(ctx, r, hardware.NewMemoryModuleInfo(id), func(res *hardware.MemoryModule) error {\n\t\t\thwadapter.MemoryModule(res).Update(&m)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating objects: %w\", err)\n\t\t}\n\t}\n\n\tif len(ctrl.SMBIOS.MemoryDevices) == 0 {\n\t\tlogger.Debug(\"no memory devices found, attempting to retrieve memory information from procfs\")\n\n\t\tproc, err := procfs.NewDefaultFS()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tinfo, err := proc.Meminfo()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, hardware.NewMemoryModuleInfo(memoryModuleUnknown), func(res *hardware.MemoryModule) error {\n\t\t\tif info.MemTotalBytes != nil {\n\t\t\t\thwadapter.MemoryModule(res).TypedSpec().Size = uint32(*info.MemTotal / 1024)\n\t\t\t}\n\n\t\t\thwadapter.MemoryModule(res).TypedSpec().Manufacturer = memoryModuleUnknown\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating objects: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/hardware/system_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware_test\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/siderolabs/go-smbios/smbios\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\thardwarectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/hardware\"\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype SystemInfoSuite struct {\n\tHardwareSuite\n}\n\nfunc (suite *SystemInfoSuite) TestPopulateSystemInformation() {\n\tstream, err := os.Open(\"testdata/SuperMicro-Dual-Xeon.dmi\")\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Cleanup(func() { suite.NoError(stream.Close()) })\n\n\tversion := smbios.Version{Major: 3, Minor: 3, Revision: 0} // dummy version\n\ts, err := smbios.Decode(stream, version)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&hardwarectrl.SystemInfoController{\n\t\t\t\tSMBIOS: s,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, runtime.NewMetaLoaded()))\n\n\tsystemInformation := hardware.SystemInformationSpec{\n\t\tManufacturer: \"Supermicro\",\n\t\tProductName:  \"SYS-1027R-WRF\",\n\t\tVersion:      \"0123456789\",\n\t\tSerialNumber: \"E09626824801435\",\n\t\tUUID:         \"00000000-0000-0000-0000-002590eb9628\",\n\t\tWakeUpType:   \"Power Switch\",\n\t\tSKUNumber:    \"\",\n\t}\n\n\tcpuSpecs := map[string]hardware.ProcessorSpec{\n\t\t\"CPU-1\": {\n\t\t\tSocket:       \"CPU 1\",\n\t\t\tManufacturer: \"Intel\",\n\t\t\tProductName:  \"Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz\",\n\t\t\tMaxSpeed:     4000,\n\t\t\tBootSpeed:    2600,\n\t\t\tStatus:       65,\n\t\t\tAssetTag:     \"3A65E8E29D76BF8D\",\n\t\t\tCoreCount:    8,\n\t\t\tCoreEnabled:  8,\n\t\t\tThreadCount:  16,\n\t\t},\n\t\t\"CPU-2\": {\n\t\t\tSocket:       \"CPU 2\",\n\t\t\tManufacturer: \"Intel\",\n\t\t\tProductName:  \"Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz\",\n\t\t\tMaxSpeed:     4000,\n\t\t\tBootSpeed:    2600,\n\t\t\tStatus:       65,\n\t\t\tCoreCount:    8,\n\t\t\tCoreEnabled:  8,\n\t\t\tThreadCount:  16,\n\t\t},\n\t}\n\n\tmemorySpecs := map[string]hardware.MemoryModuleSpec{\n\t\t\"P1-DIMMA1\": {\n\t\t\tSize:          4096,\n\t\t\tDeviceLocator: \"P1-DIMMA1\",\n\t\t\tBankLocator:   \"P0_Node0_Channel0_Dimm0\",\n\t\t\tSpeed:         1333,\n\t\t\tManufacturer:  \"Micron\",\n\t\t\tSerialNumber:  \"346C4A12\",\n\t\t\tAssetTag:      \"Dimm0_AssetTag\",\n\t\t\tProductName:   \"18KSF51272PZ-1G4K\",\n\t\t},\n\t\t\"P1-DIMMA2\": {\n\t\t\tSize:          4096,\n\t\t\tDeviceLocator: \"P1-DIMMA2\",\n\t\t\tBankLocator:   \"P0_Node0_Channel0_Dimm1\",\n\t\t\tSpeed:         1333,\n\t\t\tManufacturer:  \"Kingston\",\n\t\t\tSerialNumber:  \"D2166C8B\",\n\t\t\tAssetTag:      \"Dimm1_AssetTag\",\n\t\t\tProductName:   \"HP647647-071-HYE\",\n\t\t},\n\t}\n\n\tctest.AssertResource(suite, hardware.SystemInformationID, func(r *hardware.SystemInformation, assertions *assert.Assertions) {\n\t\tassertions.Equal(systemInformation, *r.TypedSpec())\n\t})\n\n\tfor k, v := range cpuSpecs {\n\t\tctest.AssertResource(suite, k, func(r *hardware.Processor, assertions *assert.Assertions) {\n\t\t\tassertions.Equal(v, *r.TypedSpec())\n\t\t})\n\t}\n\n\tfor k, v := range memorySpecs {\n\t\tctest.AssertResource(suite, k, func(r *hardware.MemoryModule, assertions *assert.Assertions) {\n\t\t\tassertions.Equal(v, *r.TypedSpec())\n\t\t})\n\t}\n}\n\nfunc (suite *SystemInfoSuite) TestPopulateSystemInformationEmpty() {\n\tversion := smbios.Version{Major: 3, Minor: 3, Revision: 0} // dummy version\n\ts, err := smbios.Decode(io.NewSectionReader(nil, 0, 0), version)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&hardwarectrl.SystemInfoController{\n\t\t\t\tSMBIOS: s,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, runtime.NewMetaLoaded()))\n\n\tmemorySpecs := map[string]hardware.MemoryModuleSpec{\n\t\t\"UNKNOWN\": {\n\t\t\tManufacturer: \"UNKNOWN\",\n\t\t},\n\t}\n\n\tfor k, v := range memorySpecs {\n\t\tctest.AssertResource(suite, k, func(r *hardware.MemoryModule, assertions *assert.Assertions) {\n\t\t\tassertions.Equal(v.DeviceLocator, r.TypedSpec().DeviceLocator)\n\t\t\tassertions.NotZero(r.TypedSpec().Size)\n\t\t})\n\t}\n}\n\nfunc (suite *SystemInfoSuite) TestUUIDOverwrite() {\n\tstream, err := os.Open(\"testdata/SuperMicro-Dual-Xeon.dmi\")\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Cleanup(func() { suite.NoError(stream.Close()) })\n\n\tversion := smbios.Version{Major: 3, Minor: 3, Revision: 0} // dummy version\n\ts, err := smbios.Decode(stream, version)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&hardwarectrl.SystemInfoController{\n\t\t\t\tSMBIOS: s,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, runtime.NewMetaLoaded()))\n\n\tkey := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.UUIDOverride))\n\tkey.TypedSpec().Value = \"00000000-0000-0000-0000-000000000001\"\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, key))\n\n\tctest.AssertResource(suite, hardware.SystemInformationID, func(r *hardware.SystemInformation, assertions *assert.Assertions) {\n\t\tassertions.Equal(\"00000000-0000-0000-0000-000000000001\", r.TypedSpec().UUID)\n\t})\n}\n\nfunc (suite *SystemInfoSuite) TestPopulateSystemInformationIsDisabledInContainerMode() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&hardwarectrl.SystemInfoController{\n\t\t\t\tV1Alpha1Mode: runtimetalos.ModeContainer,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, runtime.NewMetaLoaded()))\n\n\tsuite.Assert().NoError(retry.Constant(1*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(suite.assertNoResource(*hardware.NewSystemInformation(\"systeminformation\").Metadata())))\n}\n\nfunc TestSystemInfoSyncSuite(t *testing.T) {\n\tsuite.Run(t, new(SystemInfoSuite))\n}\n\nfunc (suite *SystemInfoSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/address_filter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// AddressFilterController creates NodeAddressFilters based on machine configuration.\ntype AddressFilterController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AddressFilterController) Name() string {\n\treturn \"k8s.AddressFilterController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AddressFilterController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AddressFilterController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.NodeAddressFilterType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *AddressFilterController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tnodeName, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t}\n\n\t\tvar nodeStatus *k8s.NodeStatus\n\n\t\tif nodeName != nil {\n\t\t\tnodeStatus, err = safe.ReaderGetByID[*k8s.NodeStatus](ctx, r, nodeName.TypedSpec().Nodename)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config().Cluster() != nil {\n\t\t\tcfgProvider := cfg.Config()\n\n\t\t\tvar podCIDRs, serviceCIDRs []netip.Prefix\n\n\t\t\tfor _, cidr := range cfgProvider.Cluster().Network().PodCIDRs() {\n\t\t\t\tvar ipPrefix netip.Prefix\n\n\t\t\t\tipPrefix, err = netip.ParsePrefix(cidr)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error parsing podCIDR: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tpodCIDRs = append(podCIDRs, ipPrefix)\n\t\t\t}\n\n\t\t\tif nodeStatus != nil {\n\t\t\t\tpodCIDRs = append(podCIDRs, nodeStatus.TypedSpec().PodCIDRs...)\n\t\t\t}\n\n\t\t\tfor _, cidr := range cfgProvider.Cluster().Network().ServiceCIDRs() {\n\t\t\t\tvar ipPrefix netip.Prefix\n\n\t\t\t\tipPrefix, err = netip.ParsePrefix(cidr)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error parsing serviceCIDR: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tserviceCIDRs = append(serviceCIDRs, ipPrefix)\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewNodeAddressFilter(network.NamespaceName, k8s.NodeAddressFilterNoK8s), func(r *network.NodeAddressFilter) error {\n\t\t\t\tr.TypedSpec().ExcludeSubnets = slices.Concat(podCIDRs, serviceCIDRs)\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating output resource: %w\", err)\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewNodeAddressFilter(network.NamespaceName, k8s.NodeAddressFilterOnlyK8s), func(r *network.NodeAddressFilter) error {\n\t\t\t\tr.TypedSpec().IncludeSubnets = slices.Concat(podCIDRs, serviceCIDRs)\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating output resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.NodeAddressFilter](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/address_filter_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype K8sAddressFilterSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *K8sAddressFilterSuite) TestReconcile() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tServiceSubnet: []string{\n\t\t\t\t\t\t\t\"10.200.0.0/22\",\n\t\t\t\t\t\t\t\"fd40:10:200::/112\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPodSubnet: []string{\n\t\t\t\t\t\t\t\"10.32.0.0/12\",\n\t\t\t\t\t\t\t\"fd00:10:32::/102\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, k8s.NodeAddressFilterOnlyK8s, func(res *network.NodeAddressFilter, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.Equal(\n\t\t\t\"[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]\",\n\t\t\tfmt.Sprintf(\"%s\", spec.IncludeSubnets),\n\t\t)\n\t\tasrt.Empty(spec.ExcludeSubnets)\n\t})\n\n\tctest.AssertResource(suite, k8s.NodeAddressFilterNoK8s, func(res *network.NodeAddressFilter, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.Empty(spec.IncludeSubnets)\n\t\tasrt.Equal(\n\t\t\t\"[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]\",\n\t\t\tfmt.Sprintf(\"%s\", spec.ExcludeSubnets),\n\t\t)\n\t})\n\n\t// create NodeStatus with PodCIDRs\n\tnodeName := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodeName.TypedSpec().Nodename = \"test-node\"\n\tsuite.Create(nodeName)\n\n\tnodeStatus := k8s.NewNodeStatus(k8s.NamespaceName, \"test-node\")\n\tnodeStatus.TypedSpec().PodCIDRs = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"192.168.0.0/24\"),\n\t}\n\tsuite.Create(nodeStatus)\n\n\tctest.AssertResource(suite, k8s.NodeAddressFilterOnlyK8s, func(res *network.NodeAddressFilter, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.Equal(\n\t\t\t\"[10.32.0.0/12 fd00:10:32::/102 192.168.0.0/24 10.200.0.0/22 fd40:10:200::/112]\",\n\t\t\tfmt.Sprintf(\"%s\", spec.IncludeSubnets),\n\t\t)\n\t\tasrt.Empty(spec.ExcludeSubnets)\n\t})\n\n\tctest.AssertResource(suite, k8s.NodeAddressFilterNoK8s, func(res *network.NodeAddressFilter, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.Empty(spec.IncludeSubnets)\n\t\tasrt.Equal(\n\t\t\t\"[10.32.0.0/12 fd00:10:32::/102 192.168.0.0/24 10.200.0.0/22 fd40:10:200::/112]\",\n\t\t\tfmt.Sprintf(\"%s\", spec.ExcludeSubnets),\n\t\t)\n\t})\n}\n\nfunc TestK8sAddressFilterSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &K8sAddressFilterSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&k8sctrl.AddressFilterController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/control_plane.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/compatibility\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/argsbuilder\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// controlplaneMapFunc is a shared \"map\" func for transform controller which guards on:\n// * machine config is there\n// * it has cluster & machine parts\n// * machine is controlplane one.\nfunc controlplaneMapFunc[Output generic.ResourceWithRD](output Output) func(cfg *config.MachineConfig) optional.Optional[Output] {\n\treturn func(cfg *config.MachineConfig) optional.Optional[Output] {\n\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\tif cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\tif !cfg.Config().Machine().Type().IsControlPlane() {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\treturn optional.Some(output)\n\t}\n}\n\n// ControlPlaneAdmissionControlController manages k8s.AdmissionControlConfig based on configuration.\ntype ControlPlaneAdmissionControlController = transform.Controller[*config.MachineConfig, *k8s.AdmissionControlConfig]\n\n// NewControlPlaneAdmissionControlController instanciates the controller.\nfunc NewControlPlaneAdmissionControlController() *ControlPlaneAdmissionControlController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.AdmissionControlConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneAdmissionControlController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewAdmissionControlConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.AdmissionControlConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tres.TypedSpec().Config = nil\n\n\t\t\t\tfor _, cfg := range cfgProvider.Cluster().APIServer().AdmissionControl() {\n\t\t\t\t\tres.TypedSpec().Config = append(res.TypedSpec().Config,\n\t\t\t\t\t\tk8s.AdmissionPluginSpec{\n\t\t\t\t\t\t\tName:          cfg.Name(),\n\t\t\t\t\t\t\tConfiguration: cfg.Configuration(),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneAuditPolicyController manages k8s.AuditPolicyConfig based on configuration.\ntype ControlPlaneAuditPolicyController = transform.Controller[*config.MachineConfig, *k8s.AuditPolicyConfig]\n\n// NewControlPlaneAuditPolicyController instanciates the controller.\nfunc NewControlPlaneAuditPolicyController() *ControlPlaneAuditPolicyController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.AuditPolicyConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneAuditPolicyController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewAuditPolicyConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.AuditPolicyConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tres.TypedSpec().Config = cfgProvider.Cluster().APIServer().AuditPolicy()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneAuthorizationController manages k8s.AuthorizationConfig based on configuration.\ntype ControlPlaneAuthorizationController = transform.Controller[*config.MachineConfig, *k8s.AuthorizationConfig]\n\n// NewControlPlaneAuthorizationController instanciates the controller.\nfunc NewControlPlaneAuthorizationController() *ControlPlaneAuthorizationController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.AuthorizationConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneAuthorizationPolicyController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewAuthorizationConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.AuthorizationConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tres.TypedSpec().Image = cfgProvider.Cluster().APIServer().Image()\n\n\t\t\t\tif !compatibility.VersionFromImageRef(cfgProvider.Cluster().APIServer().Image()).KubeAPIServerSupportsAuthorizationConfigFile() {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif cfgProvider.Cluster().APIServer().AuthorizationConfig() == nil {\n\t\t\t\t\tres.TypedSpec().Config = v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tvar authorizers []k8s.AuthorizationAuthorizersSpec\n\n\t\t\t\tfor _, authorizer := range cfgProvider.Cluster().APIServer().AuthorizationConfig() {\n\t\t\t\t\tauthorizers = slices.Concat(authorizers, []k8s.AuthorizationAuthorizersSpec{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tType:    authorizer.Type(),\n\t\t\t\t\t\t\tName:    authorizer.Name(),\n\t\t\t\t\t\t\tWebhook: authorizer.Webhook(),\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool {\n\t\t\t\t\treturn a.Type == \"Node\"\n\t\t\t\t}) {\n\t\t\t\t\tauthorizers = slices.Insert(authorizers, 0, k8s.AuthorizationAuthorizersSpec{\n\t\t\t\t\t\tType: \"Node\",\n\t\t\t\t\t\tName: \"node\",\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif !slices.ContainsFunc(authorizers, func(a k8s.AuthorizationAuthorizersSpec) bool {\n\t\t\t\t\treturn a.Type == \"RBAC\"\n\t\t\t\t}) {\n\t\t\t\t\tauthorizers = slices.Insert(authorizers, 1, k8s.AuthorizationAuthorizersSpec{\n\t\t\t\t\t\tType: \"RBAC\",\n\t\t\t\t\t\tName: \"rbac\",\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tres.TypedSpec().Config = authorizers\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneAPIServerController manages k8s.APIServerConfig based on configuration.\ntype ControlPlaneAPIServerController = transform.Controller[*config.MachineConfig, *k8s.APIServerConfig]\n\n// NewControlPlaneAPIServerController instanciates the controller.\nfunc NewControlPlaneAPIServerController() *ControlPlaneAPIServerController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.APIServerConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneAPIServerController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewAPIServerConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.APIServerConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tvar cloudProvider string\n\t\t\t\tif cfgProvider.Cluster().ExternalCloudProvider().Enabled() {\n\t\t\t\t\tcloudProvider = CloudProviderExternal\n\t\t\t\t}\n\n\t\t\t\tadvertisedAddress := \"$(POD_IP)\"\n\t\t\t\tif cfgProvider.Machine().Kubelet().SkipNodeRegistration() {\n\t\t\t\t\tadvertisedAddress = \"\"\n\t\t\t\t}\n\n\t\t\t\textraArgs := make(map[string]k8s.ArgValues, len(cfgProvider.Cluster().APIServer().ExtraArgs()))\n\t\t\t\tfor k, v := range cfgProvider.Cluster().APIServer().ExtraArgs() {\n\t\t\t\t\textraArgs[k] = k8s.ArgValues{Values: v}\n\t\t\t\t}\n\n\t\t\t\t*res.TypedSpec() = k8s.APIServerConfigSpec{\n\t\t\t\t\tImage:                cfgProvider.Cluster().APIServer().Image(),\n\t\t\t\t\tCloudProvider:        cloudProvider,\n\t\t\t\t\tControlPlaneEndpoint: cfgProvider.Cluster().Endpoint().String(),\n\t\t\t\t\tEtcdServers:          []string{fmt.Sprintf(\"https://%s\", nethelpers.JoinHostPort(\"127.0.0.1\", constants.EtcdClientPort))},\n\t\t\t\t\tLocalPort:            cfgProvider.Cluster().LocalAPIServerPort(),\n\t\t\t\t\tServiceCIDRs:         cfgProvider.Cluster().Network().ServiceCIDRs(),\n\t\t\t\t\tExtraArgs:            extraArgs,\n\t\t\t\t\tExtraVolumes:         convertVolumes(cfgProvider.Cluster().APIServer().ExtraVolumes()),\n\t\t\t\t\tEnvironmentVariables: cfgProvider.Cluster().APIServer().Env(),\n\t\t\t\t\tAdvertisedAddress:    advertisedAddress,\n\t\t\t\t\tResources:            convertResources(cfgProvider.Cluster().APIServer().Resources()),\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneControllerManagerController manages k8s.ControllerManagerConfig based on configuration.\ntype ControlPlaneControllerManagerController = transform.Controller[*config.MachineConfig, *k8s.ControllerManagerConfig]\n\n// NewControlPlaneControllerManagerController instanciates the controller.\nfunc NewControlPlaneControllerManagerController() *ControlPlaneControllerManagerController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.ControllerManagerConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneControllerManagerController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewControllerManagerConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.ControllerManagerConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tvar cloudProvider string\n\n\t\t\t\tif cfgProvider.Cluster().ExternalCloudProvider().Enabled() {\n\t\t\t\t\tcloudProvider = CloudProviderExternal\n\t\t\t\t}\n\n\t\t\t\textraArgs := make(map[string]k8s.ArgValues, len(cfgProvider.Cluster().ControllerManager().ExtraArgs()))\n\t\t\t\tfor k, v := range cfgProvider.Cluster().ControllerManager().ExtraArgs() {\n\t\t\t\t\textraArgs[k] = k8s.ArgValues{Values: v}\n\t\t\t\t}\n\n\t\t\t\t*res.TypedSpec() = k8s.ControllerManagerConfigSpec{\n\t\t\t\t\tEnabled:              !cfgProvider.Machine().Controlplane().ControllerManager().Disabled(),\n\t\t\t\t\tImage:                cfgProvider.Cluster().ControllerManager().Image(),\n\t\t\t\t\tCloudProvider:        cloudProvider,\n\t\t\t\t\tPodCIDRs:             cfgProvider.Cluster().Network().PodCIDRs(),\n\t\t\t\t\tServiceCIDRs:         cfgProvider.Cluster().Network().ServiceCIDRs(),\n\t\t\t\t\tExtraArgs:            extraArgs,\n\t\t\t\t\tExtraVolumes:         convertVolumes(cfgProvider.Cluster().ControllerManager().ExtraVolumes()),\n\t\t\t\t\tEnvironmentVariables: cfgProvider.Cluster().ControllerManager().Env(),\n\t\t\t\t\tResources:            convertResources(cfgProvider.Cluster().ControllerManager().Resources()),\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneSchedulerController manages k8s.SchedulerConfig based on configuration.\ntype ControlPlaneSchedulerController = transform.Controller[*config.MachineConfig, *k8s.SchedulerConfig]\n\n// NewControlPlaneSchedulerController instanciates the controller.\nfunc NewControlPlaneSchedulerController() *ControlPlaneSchedulerController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.SchedulerConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneSchedulerController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewSchedulerConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.SchedulerConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\textraArgs := make(map[string]k8s.ArgValues, len(cfgProvider.Cluster().Scheduler().ExtraArgs()))\n\t\t\t\tfor k, v := range cfgProvider.Cluster().Scheduler().ExtraArgs() {\n\t\t\t\t\textraArgs[k] = k8s.ArgValues{Values: v}\n\t\t\t\t}\n\n\t\t\t\t*res.TypedSpec() = k8s.SchedulerConfigSpec{\n\t\t\t\t\tEnabled:              !cfgProvider.Machine().Controlplane().Scheduler().Disabled(),\n\t\t\t\t\tImage:                cfgProvider.Cluster().Scheduler().Image(),\n\t\t\t\t\tExtraArgs:            extraArgs,\n\t\t\t\t\tExtraVolumes:         convertVolumes(cfgProvider.Cluster().Scheduler().ExtraVolumes()),\n\t\t\t\t\tEnvironmentVariables: cfgProvider.Cluster().Scheduler().Env(),\n\t\t\t\t\tResources:            convertResources(cfgProvider.Cluster().Scheduler().Resources()),\n\t\t\t\t\tConfig:               cfgProvider.Cluster().Scheduler().Config(),\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// ControlPlaneBootstrapManifestsController manages k8s.BootstrapManifestsConfig based on configuration.\ntype ControlPlaneBootstrapManifestsController = transform.Controller[*config.MachineConfig, *k8s.BootstrapManifestsConfig]\n\n// NewControlPlaneBootstrapManifestsController instanciates the controller.\nfunc NewControlPlaneBootstrapManifestsController() *ControlPlaneBootstrapManifestsController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.BootstrapManifestsConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneBootstrapManifestsController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewBootstrapManifestsConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.BootstrapManifestsConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tdnsServiceIPs, err := cfgProvider.Cluster().Network().DNSServiceIPs()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error calculating DNS service IPs: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tdnsServiceIP := \"\"\n\t\t\t\tdnsServiceIPv6 := \"\"\n\n\t\t\t\tfor _, ip := range dnsServiceIPs {\n\t\t\t\t\tif dnsServiceIP == \"\" && ip.Is4() {\n\t\t\t\t\t\tdnsServiceIP = ip.String()\n\t\t\t\t\t}\n\n\t\t\t\t\tif dnsServiceIPv6 == \"\" && ip.Is6() {\n\t\t\t\t\t\tdnsServiceIPv6 = ip.String()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\timages := images.List(cfgProvider)\n\n\t\t\t\tproxyArgs, err := getProxyArgs(cfgProvider)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tvar (\n\t\t\t\t\tserver                                         string\n\t\t\t\t\tflannelKubeServiceHost, flannelKubeServicePort string\n\t\t\t\t)\n\n\t\t\t\tif cfgProvider.Machine().Features().KubePrism().Enabled() {\n\t\t\t\t\tserver = fmt.Sprintf(\"https://127.0.0.1:%d\", cfgProvider.Machine().Features().KubePrism().Port())\n\t\t\t\t\tflannelKubeServiceHost = \"127.0.0.1\"\n\t\t\t\t\tflannelKubeServicePort = strconv.Itoa(cfgProvider.Machine().Features().KubePrism().Port())\n\t\t\t\t} else {\n\t\t\t\t\tserver = cfgProvider.Cluster().Endpoint().String()\n\t\t\t\t}\n\n\t\t\t\t*res.TypedSpec() = k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tServer:        server,\n\t\t\t\t\tClusterDomain: cfgProvider.Cluster().Network().DNSDomain(),\n\n\t\t\t\t\tPodCIDRs: cfgProvider.Cluster().Network().PodCIDRs(),\n\n\t\t\t\t\tProxyEnabled: cfgProvider.Cluster().Proxy().Enabled(),\n\t\t\t\t\tProxyImage:   cfgProvider.Cluster().Proxy().Image(),\n\t\t\t\t\tProxyArgs:    proxyArgs,\n\n\t\t\t\t\tCoreDNSEnabled: cfgProvider.Cluster().CoreDNS().Enabled(),\n\t\t\t\t\tCoreDNSImage:   cfgProvider.Cluster().CoreDNS().Image(),\n\n\t\t\t\t\tDNSServiceIP:   dnsServiceIP,\n\t\t\t\t\tDNSServiceIPv6: dnsServiceIPv6,\n\n\t\t\t\t\tFlannelEnabled:                    cfgProvider.Cluster().Network().CNI().Name() == constants.FlannelCNI,\n\t\t\t\t\tFlannelImage:                      images.Flannel.String(),\n\t\t\t\t\tFlannelExtraArgs:                  cfgProvider.Cluster().Network().CNI().Flannel().ExtraArgs(),\n\t\t\t\t\tFlannelKubeServiceHost:            flannelKubeServiceHost,\n\t\t\t\t\tFlannelKubeServicePort:            flannelKubeServicePort,\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: cfgProvider.Cluster().Network().CNI().Flannel().KubeNetworkPoliciesEnabled(),\n\t\t\t\t\tFlannelKubeNetworkPoliciesImage:   images.KubeNetworkPolicies.String(),\n\n\t\t\t\t\tTalosAPIServiceEnabled: cfgProvider.Machine().Features().KubernetesTalosAPIAccess().Enabled(),\n\n\t\t\t\t\tCNIName: cfgProvider.Cluster().Network().CNI().Name(),\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\ttransform.WithExtraInputs(\n\t\t\tcontroller.Input{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.HostDNSConfigType,\n\t\t\t\tID:        optional.Some(network.HostDNSConfigID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t),\n\t)\n}\n\n// ControlPlaneExtraManifestsController manages k8s.ExtraManifestsConfig based on configuration.\ntype ControlPlaneExtraManifestsController = transform.Controller[*config.MachineConfig, *k8s.ExtraManifestsConfig]\n\n// NewControlPlaneExtraManifestsController instanciates the controller.\nfunc NewControlPlaneExtraManifestsController() *ControlPlaneExtraManifestsController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.ExtraManifestsConfig]{\n\t\t\tName:                    \"k8s.ControlPlaneExtraManifestsController\",\n\t\t\tMapMetadataOptionalFunc: controlplaneMapFunc(k8s.NewExtraManifestsConfig()),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.ExtraManifestsConfig) error {\n\t\t\t\tcfgProvider := machineConfig.Config()\n\n\t\t\t\tspec := k8s.ExtraManifestsConfigSpec{}\n\n\t\t\t\tfor _, url := range cfgProvider.Cluster().Network().CNI().URLs() {\n\t\t\t\t\tspec.ExtraManifests = append(spec.ExtraManifests, k8s.ExtraManifest{\n\t\t\t\t\t\tName:     url,\n\t\t\t\t\t\tURL:      url,\n\t\t\t\t\t\tPriority: \"05\", // push CNI to the top\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tfor _, url := range cfgProvider.Cluster().ExternalCloudProvider().ManifestURLs() {\n\t\t\t\t\tspec.ExtraManifests = append(spec.ExtraManifests, k8s.ExtraManifest{\n\t\t\t\t\t\tName:     url,\n\t\t\t\t\t\tURL:      url,\n\t\t\t\t\t\tPriority: \"30\", // after default manifests\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tfor _, url := range cfgProvider.Cluster().ExtraManifestURLs() {\n\t\t\t\t\tspec.ExtraManifests = append(spec.ExtraManifests, k8s.ExtraManifest{\n\t\t\t\t\t\tName:         url,\n\t\t\t\t\t\tURL:          url,\n\t\t\t\t\t\tPriority:     \"99\", // make sure extra manifests come last, when PSP is already created\n\t\t\t\t\t\tExtraHeaders: cfgProvider.Cluster().ExtraManifestHeaderMap(),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tfor _, manifest := range cfgProvider.Cluster().InlineManifests() {\n\t\t\t\t\tspec.ExtraManifests = append(spec.ExtraManifests, k8s.ExtraManifest{\n\t\t\t\t\t\tName:           manifest.Name(),\n\t\t\t\t\t\tPriority:       \"99\", // make sure extra manifests come last, when PSP is already created\n\t\t\t\t\t\tInlineManifest: manifest.Contents(),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\t*res.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\nfunc convertVolumes(volumes []talosconfig.VolumeMount) []k8s.ExtraVolume {\n\treturn xslices.Map(volumes, func(v talosconfig.VolumeMount) k8s.ExtraVolume {\n\t\treturn k8s.ExtraVolume{\n\t\t\tName:      v.Name(),\n\t\t\tHostPath:  v.HostPath(),\n\t\t\tMountPath: v.MountPath(),\n\t\t\tReadOnly:  v.ReadOnly(),\n\t\t}\n\t})\n}\n\nfunc convertResources(resources talosconfig.Resources) k8s.Resources {\n\tvar convertedLimits map[string]string\n\n\tcpuLimits := resources.CPULimits()\n\tmemoryLimits := resources.MemoryLimits()\n\n\tif cpuLimits != \"\" || memoryLimits != \"\" {\n\t\tconvertedLimits = map[string]string{}\n\n\t\tif cpuLimits != \"\" {\n\t\t\tconvertedLimits[string(v1.ResourceCPU)] = cpuLimits\n\t\t}\n\n\t\tif memoryLimits != \"\" {\n\t\t\tconvertedLimits[string(v1.ResourceMemory)] = memoryLimits\n\t\t}\n\t}\n\n\treturn k8s.Resources{\n\t\tRequests: map[string]string{\n\t\t\tstring(v1.ResourceCPU):    resources.CPURequests(),\n\t\t\tstring(v1.ResourceMemory): resources.MemoryRequests(),\n\t\t},\n\t\tLimits: convertedLimits,\n\t}\n}\n\nfunc getProxyArgs(cfgProvider talosconfig.Config) ([]string, error) {\n\tclusterCidr := strings.Join(cfgProvider.Cluster().Network().PodCIDRs(), \",\")\n\n\tproxyMode := cfgProvider.Cluster().Proxy().Mode()\n\n\tif proxyMode == \"\" {\n\t\t// determine proxy mode based on kube-proxy version via the image, use 'nftables' for Kubernetes >= 1.31\n\t\tif kubernetes.VersionGTE(cfgProvider.Cluster().Proxy().Image(), semver.MustParse(\"1.31.0\")) {\n\t\t\tproxyMode = \"nftables\"\n\t\t} else {\n\t\t\tproxyMode = \"iptables\"\n\t\t}\n\t}\n\n\tbuilder := argsbuilder.Args{\n\t\t\"cluster-cidr\":           {clusterCidr},\n\t\t\"hostname-override\":      {\"$(NODE_NAME)\"},\n\t\t\"kubeconfig\":             {\"/etc/kubernetes/kubeconfig\"},\n\t\t\"proxy-mode\":             {proxyMode},\n\t\t\"conntrack-max-per-core\": {\"0\"},\n\t}\n\n\tpolicies := argsbuilder.MergePolicies{\n\t\t\"kubeconfig\": argsbuilder.MergeDenied,\n\t}\n\n\tif err := builder.Merge(cfgProvider.Cluster().Proxy().ExtraArgs(), argsbuilder.WithMergePolicies(policies)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn builder.Args(), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/control_plane_static_pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/compatibility\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\tapiresource \"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/pkg/argsbuilder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// systemCriticalPriority is copied from scheduling.SystemCriticalPriority in Kubernetes internals.\nconst systemCriticalPriority int32 = 2000000000\n\n// GoGCMemLimitPercentage set the percentage of memorylimit to use for the golang garbage collection target limit.\nconst GoGCMemLimitPercentage = 95\n\n// ControlPlaneStaticPodController manages k8s.StaticPod based on control plane configuration.\ntype ControlPlaneStaticPodController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ControlPlaneStaticPodController) Name() string {\n\treturn \"k8s.ControlPlaneStaticPodController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ControlPlaneStaticPodController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.APIServerConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.ControllerManagerConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.SchedulerConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.SecretsStatusType,\n\t\t\tID:        optional.Some(k8s.StaticPodSecretsStaticPodID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.ConfigStatusType,\n\t\t\tID:        optional.Some(k8s.ConfigStatusStaticPodID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"etcd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ControlPlaneStaticPodController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.StaticPodType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ControlPlaneStaticPodController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// wait for etcd to be healthy as kube-apiserver is using local etcd instance\n\t\tetcdResource, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"etcd\")\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !etcdResource.TypedSpec().Healthy {\n\t\t\tcontinue\n\t\t}\n\n\t\tsecretsStatusResource, err := safe.ReaderGetByID[*k8s.SecretsStatus](ctx, r, k8s.StaticPodSecretsStaticPodID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tsecretsVersion := secretsStatusResource.TypedSpec().Version\n\n\t\tconfigStatusResource, err := safe.ReaderGetByID[*k8s.ConfigStatus](ctx, r, k8s.ConfigStatusStaticPodID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tconfigVersion := configStatusResource.TypedSpec().Version\n\n\t\ttouchedIDs := map[string]struct{}{}\n\n\t\tfor _, pod := range []struct {\n\t\t\tf  func(context.Context, controller.Runtime, *zap.Logger, resource.Resource, string, string) (string, error)\n\t\t\tmd *resource.Metadata\n\t\t}{\n\t\t\t{\n\t\t\t\tf:  ctrl.manageAPIServer,\n\t\t\t\tmd: k8s.NewAPIServerConfig().Metadata(),\n\t\t\t},\n\t\t\t{\n\t\t\t\tf:  ctrl.manageControllerManager,\n\t\t\t\tmd: k8s.NewControllerManagerConfig().Metadata(),\n\t\t\t},\n\t\t\t{\n\t\t\t\tf:  ctrl.manageScheduler,\n\t\t\t\tmd: k8s.NewSchedulerConfig().Metadata(),\n\t\t\t},\n\t\t} {\n\t\t\tres, err := r.Get(ctx, pod.md)\n\t\t\tif err != nil {\n\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn fmt.Errorf(\"error getting control plane config: %w\", err)\n\t\t\t}\n\n\t\t\tvar podID string\n\n\t\t\tif podID, err = pod.f(ctx, r, logger, res, secretsVersion, configVersion); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating static pod for %q: %w\", pod.md.Type(), err)\n\t\t\t}\n\n\t\t\tif podID != \"\" {\n\t\t\t\ttouchedIDs[podID] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\t// clean up static pods which haven't been touched\n\t\t{\n\t\t\tlist, err := r.List(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, \"\", resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, res := range list.Items {\n\t\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *ControlPlaneStaticPodController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range list.Items {\n\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc volumeMounts(volumes []k8s.ExtraVolume) []v1.VolumeMount {\n\treturn xslices.Map(volumes, func(vol k8s.ExtraVolume) v1.VolumeMount {\n\t\treturn v1.VolumeMount{\n\t\t\tName:      vol.Name,\n\t\t\tMountPath: vol.MountPath,\n\t\t\tReadOnly:  vol.ReadOnly,\n\t\t}\n\t})\n}\n\nfunc volumes(volumes []k8s.ExtraVolume) []v1.Volume {\n\treturn xslices.Map(volumes, func(vol k8s.ExtraVolume) v1.Volume {\n\t\treturn v1.Volume{\n\t\t\tName: vol.Name,\n\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\tPath: vol.HostPath,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t})\n}\n\nfunc envVars(environment map[string]string) []v1.EnvVar {\n\tif len(environment) == 0 {\n\t\treturn nil\n\t}\n\n\tkeys := maps.Keys(environment)\n\tslices.Sort(keys)\n\n\treturn xslices.Map(keys, func(key string) v1.EnvVar {\n\t\t// Kubernetes supports variable references in variable values, so escape '$' to prevent that.\n\t\treturn v1.EnvVar{\n\t\t\tName:  key,\n\t\t\tValue: strings.ReplaceAll(environment[key], \"$\", \"$$\"),\n\t\t}\n\t})\n}\n\nfunc resources(resourcesConfig k8s.Resources, defaultCPU, defaultMemory string) (v1.ResourceRequirements, error) {\n\tresources := v1.ResourceRequirements{\n\t\tRequests: v1.ResourceList{\n\t\t\tv1.ResourceCPU:    apiresource.MustParse(defaultCPU),\n\t\t\tv1.ResourceMemory: apiresource.MustParse(defaultMemory),\n\t\t},\n\t\tLimits: v1.ResourceList{},\n\t}\n\n\tif cpu := resourcesConfig.Requests[string(v1.ResourceCPU)]; cpu != \"\" {\n\t\tparsedCPU, err := apiresource.ParseQuantity(cpu)\n\t\tif err != nil {\n\t\t\treturn v1.ResourceRequirements{}, fmt.Errorf(\"error parsing CPU request: %w\", err)\n\t\t}\n\n\t\tresources.Requests[v1.ResourceCPU] = parsedCPU\n\t}\n\n\tif memory := resourcesConfig.Requests[string(v1.ResourceMemory)]; memory != \"\" {\n\t\tparsedMemory, err := apiresource.ParseQuantity(memory)\n\t\tif err != nil {\n\t\t\treturn v1.ResourceRequirements{}, fmt.Errorf(\"error parsing memory request: %w\", err)\n\t\t}\n\n\t\tresources.Requests[v1.ResourceMemory] = parsedMemory\n\t}\n\n\tif cpu := resourcesConfig.Limits[string(v1.ResourceCPU)]; cpu != \"\" {\n\t\tparsedCPU, err := apiresource.ParseQuantity(cpu)\n\t\tif err != nil {\n\t\t\treturn v1.ResourceRequirements{}, fmt.Errorf(\"error parsing CPU limit: %w\", err)\n\t\t}\n\n\t\tresources.Limits[v1.ResourceCPU] = parsedCPU\n\t}\n\n\tif memory := resourcesConfig.Limits[string(v1.ResourceMemory)]; memory != \"\" {\n\t\tparsedMemory, err := apiresource.ParseQuantity(memory)\n\t\tif err != nil {\n\t\t\treturn v1.ResourceRequirements{}, fmt.Errorf(\"error parsing memory limit: %w\", err)\n\t\t}\n\n\t\tresources.Limits[v1.ResourceMemory] = parsedMemory\n\t}\n\n\treturn resources, nil\n}\n\nfunc goGCEnvFromResources(resources v1.ResourceRequirements) (envVar v1.EnvVar) {\n\tmemoryLimit := resources.Limits[v1.ResourceMemory]\n\tif memoryLimit.Value() > 0 {\n\t\tgcMemLimit := memoryLimit.Value() * GoGCMemLimitPercentage / 100\n\t\tenvVar = v1.EnvVar{\n\t\t\tName:  \"GOMEMLIMIT\",\n\t\t\tValue: strconv.FormatInt(gcMemLimit, 10),\n\t\t}\n\t}\n\n\treturn envVar\n}\n\nfunc (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context, r controller.Runtime, _ *zap.Logger,\n\tconfigResource resource.Resource, secretsVersion, configVersion string,\n) (string, error) {\n\tcfg := configResource.(*k8s.APIServerConfig).TypedSpec()\n\n\tenabledAdmissionPlugins := []string{\"NodeRestriction\"}\n\n\targs := []string{ //nolint:prealloc // very dynamic length\n\t\t\"/usr/local/bin/kube-apiserver\",\n\t}\n\n\tbuilder := argsbuilder.Args{\n\t\t\"admission-control-config-file\": {filepath.Join(constants.KubernetesAPIServerConfigDir, \"admission-control-config.yaml\")},\n\t\t\"allow-privileged\":              {\"true\"},\n\t\t// Do not accept anonymous requests by default. Otherwise the kube-apiserver will set the request's group to system:unauthenticated exposing endpoints like /version etc.\n\t\t\"anonymous-auth\":                     {\"false\"},\n\t\t\"api-audiences\":                      {cfg.ControlPlaneEndpoint},\n\t\t\"bind-address\":                       {\"0.0.0.0\"},\n\t\t\"client-ca-file\":                     {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"ca.crt\")},\n\t\t\"enable-admission-plugins\":           {strings.Join(enabledAdmissionPlugins, \",\")},\n\t\t\"requestheader-client-ca-file\":       {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"aggregator-ca.crt\")},\n\t\t\"requestheader-allowed-names\":        {\"front-proxy-client\"},\n\t\t\"requestheader-extra-headers-prefix\": {\"X-Remote-Extra-\"},\n\t\t\"requestheader-group-headers\":        {\"X-Remote-Group\"},\n\t\t\"requestheader-username-headers\":     {\"X-Remote-User\"},\n\t\t\"proxy-client-cert-file\":             {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"front-proxy-client.crt\")},\n\t\t\"proxy-client-key-file\":              {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"front-proxy-client.key\")},\n\t\t\"enable-bootstrap-token-auth\":        {\"true\"},\n\t\t// NB: using TLS 1.2 instead of 1.3 here for interoperability, since this is an externally-facing service.\n\t\t\"tls-min-version\":                  {\"VersionTLS12\"},\n\t\t\"tls-cipher-suites\":                {\"TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\"}, //nolint:lll\n\t\t\"encryption-provider-config\":       {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"encryptionconfig.yaml\")},\n\t\t\"audit-policy-file\":                {filepath.Join(constants.KubernetesAPIServerConfigDir, \"auditpolicy.yaml\")},\n\t\t\"audit-log-path\":                   {filepath.Join(constants.KubernetesAuditLogDir, \"kube-apiserver.log\")},\n\t\t\"audit-log-maxage\":                 {\"30\"},\n\t\t\"audit-log-maxbackup\":              {\"10\"},\n\t\t\"audit-log-maxsize\":                {\"100\"},\n\t\t\"profiling\":                        {\"false\"},\n\t\t\"etcd-cafile\":                      {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"etcd-client-ca.crt\")},\n\t\t\"etcd-certfile\":                    {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"etcd-client.crt\")},\n\t\t\"etcd-keyfile\":                     {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"etcd-client.key\")},\n\t\t\"etcd-servers\":                     {strings.Join(cfg.EtcdServers, \",\")},\n\t\t\"kubelet-client-certificate\":       {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"apiserver-kubelet-client.crt\")},\n\t\t\"kubelet-client-key\":               {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"apiserver-kubelet-client.key\")},\n\t\t\"secure-port\":                      {strconv.FormatInt(int64(cfg.LocalPort), 10)},\n\t\t\"service-account-issuer\":           {cfg.ControlPlaneEndpoint},\n\t\t\"service-account-key-file\":         {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"service-account.pub\")},\n\t\t\"service-account-signing-key-file\": {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"service-account.key\")},\n\t\t\"service-cluster-ip-range\":         {strings.Join(cfg.ServiceCIDRs, \",\")},\n\t\t\"tls-cert-file\":                    {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"apiserver.crt\")},\n\t\t\"tls-private-key-file\":             {filepath.Join(constants.KubernetesAPIServerSecretsDir, \"apiserver.key\")},\n\t\t\"kubelet-preferred-address-types\":  {\"InternalIP,ExternalIP,Hostname\"},\n\t}\n\n\tif cfg.AdvertisedAddress != \"\" {\n\t\tbuilder.Set(\"advertise-address\", argsbuilder.Value{cfg.AdvertisedAddress})\n\t}\n\n\tk8sVersion := compatibility.VersionFromImageRef(cfg.Image)\n\n\tif cfg.CloudProvider != \"\" && !k8sVersion.CloudProviderFlagRemoved() {\n\t\tbuilder.Set(\"cloud-provider\", argsbuilder.Value{cfg.CloudProvider})\n\t}\n\n\textraArgs := make(argsbuilder.Args, len(cfg.ExtraArgs))\n\tfor k, v := range cfg.ExtraArgs {\n\t\textraArgs[k] = v.Values\n\t}\n\n\thandleKubeAPIServerAuthorizationFlags(k8sVersion, builder, extraArgs)\n\n\tmergePolicies := argsbuilder.MergePolicies{\n\t\t\"enable-admission-plugins\": argsbuilder.MergeAdditive,\n\t\t\"feature-gates\":            argsbuilder.MergeAdditive,\n\t\t\"authorization-mode\":       argsbuilder.MergeAdditive,\n\t\t\"tls-cipher-suites\":        argsbuilder.MergeAdditive,\n\n\t\t\"etcd-servers\":                     argsbuilder.MergeDenied,\n\t\t\"client-ca-file\":                   argsbuilder.MergeDenied,\n\t\t\"requestheader-client-ca-file\":     argsbuilder.MergeDenied,\n\t\t\"proxy-client-cert-file\":           argsbuilder.MergeDenied,\n\t\t\"proxy-client-key-file\":            argsbuilder.MergeDenied,\n\t\t\"encryption-provider-config\":       argsbuilder.MergeDenied,\n\t\t\"etcd-cafile\":                      argsbuilder.MergeDenied,\n\t\t\"etcd-certfile\":                    argsbuilder.MergeDenied,\n\t\t\"etcd-keyfile\":                     argsbuilder.MergeDenied,\n\t\t\"kubelet-client-certificate\":       argsbuilder.MergeDenied,\n\t\t\"kubelet-client-key\":               argsbuilder.MergeDenied,\n\t\t\"service-account-issuer\":           argsbuilder.MergeAppend,\n\t\t\"service-account-key-file\":         argsbuilder.MergeDenied,\n\t\t\"service-account-signing-key-file\": argsbuilder.MergeDenied,\n\t\t\"tls-cert-file\":                    argsbuilder.MergeDenied,\n\t\t\"tls-private-key-file\":             argsbuilder.MergeDenied,\n\t\t\"authorization-config\":             argsbuilder.MergeDenied,\n\t}\n\n\tif err := builder.Merge(extraArgs, argsbuilder.WithMergePolicies(mergePolicies)); err != nil {\n\t\treturn \"\", err\n\t}\n\n\targs = append(args, builder.Args()...)\n\n\tresources, err := resources(cfg.Resources, \"200m\", \"512Mi\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tenv := envVars(cfg.EnvironmentVariables)\n\tif goGCEnv := goGCEnvFromResources(resources); goGCEnv.Name != \"\" {\n\t\tenv = append(env, goGCEnv)\n\t}\n\n\treturn k8s.APIServerID, safe.WriterModify(ctx, r, k8s.NewStaticPod(k8s.NamespaceName, k8s.APIServerID), func(r *k8s.StaticPod) error {\n\t\treturn k8sadapter.StaticPod(r).SetPod(&v1.Pod{\n\t\t\tTypeMeta: metav1.TypeMeta{\n\t\t\t\tAPIVersion: \"v1\",\n\t\t\t\tKind:       \"Pod\",\n\t\t\t},\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName:      k8s.APIServerID,\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\tconstants.AnnotationStaticPodSecretsVersion:    secretsVersion,\n\t\t\t\t\tconstants.AnnotationStaticPodConfigFileVersion: configVersion,\n\t\t\t\t\tconstants.AnnotationStaticPodConfigVersion:     configResource.Metadata().Version().String(),\n\t\t\t\t},\n\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\"tier\":                         \"control-plane\",\n\t\t\t\t\t\"k8s-app\":                      k8s.APIServerID,\n\t\t\t\t\t\"component\":                    k8s.APIServerID,\n\t\t\t\t\t\"app.kubernetes.io/name\":       k8s.APIServerID,\n\t\t\t\t\t\"app.kubernetes.io/version\":    k8sVersion.String(),\n\t\t\t\t\t\"app.kubernetes.io/component\":  \"control-plane\",\n\t\t\t\t\t\"app.kubernetes.io/managed-by\": \"Talos\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSpec: v1.PodSpec{\n\t\t\t\tPriority:          new(systemCriticalPriority),\n\t\t\t\tPriorityClassName: \"system-cluster-critical\",\n\t\t\t\tContainers: []v1.Container{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    k8s.APIServerID,\n\t\t\t\t\t\tImage:   cfg.Image,\n\t\t\t\t\t\tCommand: args,\n\t\t\t\t\t\tEnv: append(\n\t\t\t\t\t\t\t[]v1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\t\t\t\t\tValueFrom: &v1.EnvVarSource{\n\t\t\t\t\t\t\t\t\t\tFieldRef: &v1.ObjectFieldSelector{\n\t\t\t\t\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tenv...),\n\t\t\t\t\t\tVolumeMounts: append([]v1.VolumeMount{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"secrets\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesAPIServerSecretsDir,\n\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"config\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesAPIServerConfigDir,\n\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"audit\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesAuditLogDir,\n\t\t\t\t\t\t\t\tReadOnly:  false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}, volumeMounts(cfg.ExtraVolumes)...),\n\t\t\t\t\t\tResources: resources,\n\t\t\t\t\t\tSecurityContext: &v1.SecurityContext{\n\t\t\t\t\t\t\tAllowPrivilegeEscalation: new(false),\n\t\t\t\t\t\t\tCapabilities: &v1.Capabilities{\n\t\t\t\t\t\t\t\tDrop: []v1.Capability{\"ALL\"},\n\t\t\t\t\t\t\t\t// kube-apiserver binary has cap_net_bind_service=+ep set.\n\t\t\t\t\t\t\t\t// It does not matter if ports < 1024 are configured, the setcap flag causes a capability dependency.\n\t\t\t\t\t\t\t\t// https://github.com/kubernetes/kubernetes/blob/5b92e46b2238b4d84358451013e634361084ff7d/build/server-image/kube-apiserver/Dockerfile#L26\n\t\t\t\t\t\t\t\tAdd: []v1.Capability{\"NET_BIND_SERVICE\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tSeccompProfile: &v1.SeccompProfile{\n\t\t\t\t\t\t\t\tType: v1.SeccompProfileTypeRuntimeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostNetwork: true,\n\t\t\t\tSecurityContext: &v1.PodSecurityContext{\n\t\t\t\t\tRunAsNonRoot: new(true),\n\t\t\t\t\tRunAsUser:    new(int64(constants.KubernetesAPIServerRunUser)),\n\t\t\t\t\tRunAsGroup:   new(int64(constants.KubernetesAPIServerRunGroup)),\n\t\t\t\t},\n\t\t\t\tVolumes: append([]v1.Volume{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"secrets\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesAPIServerSecretsDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"config\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesAPIServerConfigDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"audit\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesAuditLogDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, volumes(cfg.ExtraVolumes)...),\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context.Context, r controller.Runtime,\n\t_ *zap.Logger, configResource resource.Resource, secretsVersion, _ string,\n) (string, error) {\n\tcfg := configResource.(*k8s.ControllerManagerConfig).TypedSpec()\n\n\tif !cfg.Enabled {\n\t\treturn \"\", nil\n\t}\n\n\targs := []string{ //nolint:prealloc // very dynamic length\n\t\t\"/usr/local/bin/kube-controller-manager\",\n\t\t\"--use-service-account-credentials\",\n\t}\n\n\tbuilder := argsbuilder.Args{\n\t\t\"allocate-node-cidrs\":              {\"true\"},\n\t\t\"bind-address\":                     {\"127.0.0.1\"},\n\t\t\"cluster-cidr\":                     {strings.Join(cfg.PodCIDRs, \",\")},\n\t\t\"service-cluster-ip-range\":         {strings.Join(cfg.ServiceCIDRs, \",\")},\n\t\t\"cluster-signing-cert-file\":        {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"ca.crt\")},\n\t\t\"cluster-signing-key-file\":         {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"ca.key\")},\n\t\t\"controllers\":                      {\"*,tokencleaner\"},\n\t\t\"configure-cloud-routes\":           {\"false\"},\n\t\t\"kubeconfig\":                       {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"kubeconfig\")},\n\t\t\"authentication-kubeconfig\":        {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"kubeconfig\")},\n\t\t\"authorization-kubeconfig\":         {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"kubeconfig\")},\n\t\t\"leader-elect\":                     {\"true\"},\n\t\t\"root-ca-file\":                     {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"ca.crt\")},\n\t\t\"service-account-private-key-file\": {filepath.Join(constants.KubernetesControllerManagerSecretsDir, \"service-account.key\")},\n\t\t\"profiling\":                        {\"false\"},\n\t\t\"tls-min-version\":                  {\"VersionTLS13\"},\n\t}\n\n\tk8sVersion := compatibility.VersionFromImageRef(cfg.Image)\n\n\tif cfg.CloudProvider != \"\" && !k8sVersion.CloudProviderFlagRemoved() {\n\t\tbuilder.Set(\"cloud-provider\", argsbuilder.Value{cfg.CloudProvider})\n\t}\n\n\tmergePolicies := argsbuilder.MergePolicies{\n\t\t\"service-cluster-ip-range\": argsbuilder.MergeAdditive,\n\t\t\"controllers\":              argsbuilder.MergeAdditive,\n\n\t\t\"cluster-signing-cert-file\":        argsbuilder.MergeDenied,\n\t\t\"cluster-signing-key-file\":         argsbuilder.MergeDenied,\n\t\t\"authentication-kubeconfig\":        argsbuilder.MergeDenied,\n\t\t\"authorization-kubeconfig\":         argsbuilder.MergeDenied,\n\t\t\"root-ca-file\":                     argsbuilder.MergeDenied,\n\t\t\"service-account-private-key-file\": argsbuilder.MergeDenied,\n\t}\n\n\textraArgs := make(argsbuilder.Args, len(cfg.ExtraArgs))\n\tfor k, v := range cfg.ExtraArgs {\n\t\textraArgs[k] = v.Values\n\t}\n\n\tif err := builder.Merge(extraArgs, argsbuilder.WithMergePolicies(mergePolicies)); err != nil {\n\t\treturn \"\", err\n\t}\n\n\targs = append(args, builder.Args()...)\n\n\tresources, err := resources(cfg.Resources, \"50m\", \"256Mi\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tenv := envVars(cfg.EnvironmentVariables)\n\tif goGCEnv := goGCEnvFromResources(resources); goGCEnv.Name != \"\" {\n\t\tenv = append(env, goGCEnv)\n\t}\n\n\treturn k8s.ControllerManagerID, safe.WriterModify(ctx, r, k8s.NewStaticPod(k8s.NamespaceName, k8s.ControllerManagerID), func(r *k8s.StaticPod) error {\n\t\treturn k8sadapter.StaticPod(r).SetPod(&v1.Pod{\n\t\t\tTypeMeta: metav1.TypeMeta{\n\t\t\t\tAPIVersion: \"v1\",\n\t\t\t\tKind:       \"Pod\",\n\t\t\t},\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName:      k8s.ControllerManagerID,\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\tconstants.AnnotationStaticPodSecretsVersion: secretsVersion,\n\t\t\t\t\tconstants.AnnotationStaticPodConfigVersion:  configResource.Metadata().Version().String(),\n\t\t\t\t},\n\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\"tier\":                         \"control-plane\",\n\t\t\t\t\t\"k8s-app\":                      k8s.ControllerManagerID,\n\t\t\t\t\t\"component\":                    k8s.ControllerManagerID,\n\t\t\t\t\t\"app.kubernetes.io/name\":       k8s.ControllerManagerID,\n\t\t\t\t\t\"app.kubernetes.io/version\":    compatibility.VersionFromImageRef(cfg.Image).String(),\n\t\t\t\t\t\"app.kubernetes.io/component\":  \"control-plane\",\n\t\t\t\t\t\"app.kubernetes.io/managed-by\": \"Talos\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSpec: v1.PodSpec{\n\t\t\t\tPriority:          new(systemCriticalPriority),\n\t\t\t\tPriorityClassName: \"system-cluster-critical\",\n\t\t\t\tContainers: []v1.Container{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    k8s.ControllerManagerID,\n\t\t\t\t\t\tImage:   cfg.Image,\n\t\t\t\t\t\tCommand: args,\n\t\t\t\t\t\tEnv: append(\n\t\t\t\t\t\t\t[]v1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\t\t\t\t\tValueFrom: &v1.EnvVarSource{\n\t\t\t\t\t\t\t\t\t\tFieldRef: &v1.ObjectFieldSelector{\n\t\t\t\t\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tenv...),\n\t\t\t\t\t\tVolumeMounts: append([]v1.VolumeMount{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"secrets\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesControllerManagerSecretsDir,\n\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}, volumeMounts(cfg.ExtraVolumes)...),\n\t\t\t\t\t\tStartupProbe: &v1.Probe{\n\t\t\t\t\t\t\tProbeHandler: v1.ProbeHandler{\n\t\t\t\t\t\t\t\tHTTPGet: &v1.HTTPGetAction{\n\t\t\t\t\t\t\t\t\tPath:   \"/healthz\",\n\t\t\t\t\t\t\t\t\tHost:   \"localhost\",\n\t\t\t\t\t\t\t\t\tPort:   intstr.FromInt(10257),\n\t\t\t\t\t\t\t\t\tScheme: v1.URISchemeHTTPS,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Give 60 seconds for the container to start up\n\t\t\t\t\t\t\tPeriodSeconds:                 5,\n\t\t\t\t\t\t\tFailureThreshold:              12,\n\t\t\t\t\t\t\tTerminationGracePeriodSeconds: nil,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tLivenessProbe: &v1.Probe{\n\t\t\t\t\t\t\tProbeHandler: v1.ProbeHandler{\n\t\t\t\t\t\t\t\tHTTPGet: &v1.HTTPGetAction{\n\t\t\t\t\t\t\t\t\tPath:   \"/healthz\",\n\t\t\t\t\t\t\t\t\tHost:   \"localhost\",\n\t\t\t\t\t\t\t\t\tPort:   intstr.FromInt(10257),\n\t\t\t\t\t\t\t\t\tScheme: v1.URISchemeHTTPS,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tTimeoutSeconds: 15,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tResources: resources,\n\t\t\t\t\t\tSecurityContext: &v1.SecurityContext{\n\t\t\t\t\t\t\tAllowPrivilegeEscalation: new(false),\n\t\t\t\t\t\t\tCapabilities: &v1.Capabilities{\n\t\t\t\t\t\t\t\tDrop: []v1.Capability{\"ALL\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tSeccompProfile: &v1.SeccompProfile{\n\t\t\t\t\t\t\t\tType: v1.SeccompProfileTypeRuntimeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostNetwork: true,\n\t\t\t\tSecurityContext: &v1.PodSecurityContext{\n\t\t\t\t\tRunAsNonRoot: new(true),\n\t\t\t\t\tRunAsUser:    new(int64(constants.KubernetesControllerManagerRunUser)),\n\t\t\t\t\tRunAsGroup:   new(int64(constants.KubernetesControllerManagerRunGroup)),\n\t\t\t\t},\n\t\t\t\tVolumes: append([]v1.Volume{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"secrets\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesControllerManagerSecretsDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, volumes(cfg.ExtraVolumes)...),\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context, r controller.Runtime,\n\t_ *zap.Logger, configResource resource.Resource, secretsVersion, _ string,\n) (string, error) {\n\tcfg := configResource.(*k8s.SchedulerConfig).TypedSpec()\n\n\tif !cfg.Enabled {\n\t\treturn \"\", nil\n\t}\n\n\targs := []string{ //nolint:prealloc // very dynamic length\n\t\t\"/usr/local/bin/kube-scheduler\",\n\t}\n\n\tbuilder := argsbuilder.Args{\n\t\t\"config\":                                 {filepath.Join(constants.KubernetesSchedulerConfigDir, \"scheduler-config.yaml\")},\n\t\t\"authentication-tolerate-lookup-failure\": {\"false\"},\n\t\t\"authentication-kubeconfig\":              {filepath.Join(constants.KubernetesSchedulerSecretsDir, \"kubeconfig\")},\n\t\t\"authorization-kubeconfig\":               {filepath.Join(constants.KubernetesSchedulerSecretsDir, \"kubeconfig\")},\n\t\t\"bind-address\":                           {\"127.0.0.1\"},\n\t\t\"leader-elect\":                           {\"true\"},\n\t\t\"profiling\":                              {\"false\"},\n\t\t\"tls-min-version\":                        {\"VersionTLS13\"},\n\t}\n\n\tmergePolicies := argsbuilder.MergePolicies{\n\t\t\"kubeconfig\":                argsbuilder.MergeDenied,\n\t\t\"authentication-kubeconfig\": argsbuilder.MergeDenied,\n\t\t\"authorization-kubeconfig\":  argsbuilder.MergeDenied,\n\t\t\"config\":                    argsbuilder.MergeDenied,\n\t}\n\n\textraArgs := make(argsbuilder.Args, len(cfg.ExtraArgs))\n\tfor k, v := range cfg.ExtraArgs {\n\t\textraArgs[k] = v.Values\n\t}\n\n\tif err := builder.Merge(extraArgs, argsbuilder.WithMergePolicies(mergePolicies)); err != nil {\n\t\treturn \"\", err\n\t}\n\n\targs = append(args, builder.Args()...)\n\n\tresources, err := resources(cfg.Resources, \"10m\", \"64Mi\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tenv := envVars(cfg.EnvironmentVariables)\n\tif goGCEnv := goGCEnvFromResources(resources); goGCEnv.Name != \"\" {\n\t\tenv = append(env, goGCEnv)\n\t}\n\n\tkubeSchedulerVersion := compatibility.VersionFromImageRef(cfg.Image)\n\n\tlivenessProbe := &v1.Probe{\n\t\tProbeHandler: v1.ProbeHandler{\n\t\t\tHTTPGet: &v1.HTTPGetAction{\n\t\t\t\tPath:   kubeSchedulerVersion.KubeSchedulerHealthLivenessEndpoint(),\n\t\t\t\tHost:   \"localhost\",\n\t\t\t\tPort:   intstr.FromInt(10259),\n\t\t\t\tScheme: v1.URISchemeHTTPS,\n\t\t\t},\n\t\t},\n\t}\n\n\treadinessProbe := &v1.Probe{\n\t\tProbeHandler: v1.ProbeHandler{\n\t\t\tHTTPGet: &v1.HTTPGetAction{\n\t\t\t\tPath:   kubeSchedulerVersion.KubeSchedulerHealthReadinessEndpoint(),\n\t\t\t\tHost:   \"localhost\",\n\t\t\t\tPort:   intstr.FromInt(10259),\n\t\t\t\tScheme: v1.URISchemeHTTPS,\n\t\t\t},\n\t\t},\n\t}\n\n\tstartupProbe := &v1.Probe{\n\t\tProbeHandler: v1.ProbeHandler{\n\t\t\tHTTPGet: &v1.HTTPGetAction{\n\t\t\t\tPath:   kubeSchedulerVersion.KubeSchedulerHealthStartupEndpoint(),\n\t\t\t\tHost:   \"localhost\",\n\t\t\t\tPort:   intstr.FromInt(10259),\n\t\t\t\tScheme: v1.URISchemeHTTPS,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn k8s.SchedulerID, safe.WriterModify(ctx, r, k8s.NewStaticPod(k8s.NamespaceName, k8s.SchedulerID), func(r *k8s.StaticPod) error {\n\t\treturn k8sadapter.StaticPod(r).SetPod(&v1.Pod{\n\t\t\tTypeMeta: metav1.TypeMeta{\n\t\t\t\tAPIVersion: \"v1\",\n\t\t\t\tKind:       \"Pod\",\n\t\t\t},\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName:      k8s.SchedulerID,\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\tconstants.AnnotationStaticPodSecretsVersion: secretsVersion,\n\t\t\t\t\tconstants.AnnotationStaticPodConfigVersion:  configResource.Metadata().Version().String(),\n\t\t\t\t},\n\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\"tier\":                         \"control-plane\",\n\t\t\t\t\t\"k8s-app\":                      k8s.SchedulerID,\n\t\t\t\t\t\"component\":                    k8s.SchedulerID,\n\t\t\t\t\t\"app.kubernetes.io/name\":       k8s.SchedulerID,\n\t\t\t\t\t\"app.kubernetes.io/version\":    compatibility.VersionFromImageRef(cfg.Image).String(),\n\t\t\t\t\t\"app.kubernetes.io/component\":  \"control-plane\",\n\t\t\t\t\t\"app.kubernetes.io/managed-by\": \"Talos\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSpec: v1.PodSpec{\n\t\t\t\tPriority:          new(systemCriticalPriority),\n\t\t\t\tPriorityClassName: \"system-cluster-critical\",\n\t\t\t\tContainers: []v1.Container{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    k8s.SchedulerID,\n\t\t\t\t\t\tImage:   cfg.Image,\n\t\t\t\t\t\tCommand: args,\n\t\t\t\t\t\tEnv: append(\n\t\t\t\t\t\t\t[]v1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\t\t\t\t\tValueFrom: &v1.EnvVarSource{\n\t\t\t\t\t\t\t\t\t\tFieldRef: &v1.ObjectFieldSelector{\n\t\t\t\t\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tenv...),\n\t\t\t\t\t\tVolumeMounts: append([]v1.VolumeMount{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"secrets\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesSchedulerSecretsDir,\n\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"config\",\n\t\t\t\t\t\t\t\tMountPath: constants.KubernetesSchedulerConfigDir,\n\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}, volumeMounts(cfg.ExtraVolumes)...),\n\t\t\t\t\t\tStartupProbe:   startupProbe,\n\t\t\t\t\t\tLivenessProbe:  livenessProbe,\n\t\t\t\t\t\tReadinessProbe: readinessProbe,\n\t\t\t\t\t\tResources:      resources,\n\t\t\t\t\t\tSecurityContext: &v1.SecurityContext{\n\t\t\t\t\t\t\tAllowPrivilegeEscalation: new(false),\n\t\t\t\t\t\t\tCapabilities: &v1.Capabilities{\n\t\t\t\t\t\t\t\tDrop: []v1.Capability{\"ALL\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tSeccompProfile: &v1.SeccompProfile{\n\t\t\t\t\t\t\t\tType: v1.SeccompProfileTypeRuntimeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostNetwork: true,\n\t\t\t\tSecurityContext: &v1.PodSecurityContext{\n\t\t\t\t\tRunAsNonRoot: new(true),\n\t\t\t\t\tRunAsUser:    new(int64(constants.KubernetesSchedulerRunUser)),\n\t\t\t\t\tRunAsGroup:   new(int64(constants.KubernetesSchedulerRunGroup)),\n\t\t\t\t},\n\t\t\t\tVolumes: append([]v1.Volume{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"secrets\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesSchedulerSecretsDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"config\",\n\t\t\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: constants.KubernetesSchedulerConfigDir,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, volumes(cfg.ExtraVolumes)...),\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc kubeAPIServerExtraArgsHasAuthorizationWebhooFlags(extraArgs map[string][]string) bool {\n\treturn slices.ContainsFunc(maps.Keys(extraArgs), func(arg string) bool {\n\t\treturn strings.HasPrefix(arg, \"authorization-webhook-\")\n\t})\n}\n\nfunc kubeAPIServerExtraArgsHasAuthorizationModeFlag(extraArgs map[string][]string) bool {\n\t_, ok := extraArgs[\"authorization-mode\"]\n\n\treturn ok\n}\n\nfunc handleKubeAPIServerAuthorizationFlags(kubeVersion compatibility.Version, argBuilder argsbuilder.Args, extraArgs map[string][]string) {\n\t// this handle multiple cases:\n\t// 1. user already has set `authorization-mode` flag, we'll just merge our default `authorization-mode` flag\n\tif kubeAPIServerExtraArgsHasAuthorizationModeFlag(extraArgs) {\n\t\targBuilder.Set(\"authorization-mode\", argsbuilder.Value{\"Node,RBAC\"})\n\n\t\treturn\n\t}\n\n\t// 2. user has set `authorization-webhook-*` flags, we'll just merge our default `authorization-mode` flag\n\tif kubeAPIServerExtraArgsHasAuthorizationWebhooFlags(extraArgs) {\n\t\targBuilder.Set(\"authorization-mode\", argsbuilder.Value{\"Node,RBAC\"})\n\n\t\treturn\n\t}\n\n\t// 3. user has not set `authorization-mode` flag and the kube-apiserver version doesn't support `authorization-config` flag\n\t// machine config validation should handle the case where either of `authorization-mode` or `authorization-webhook-*` flags are set\n\t// along with `authorizationConfig`\n\tif !kubeVersion.KubeAPIServerSupportsAuthorizationConfigFile() {\n\t\targBuilder.Set(\"authorization-mode\", argsbuilder.Value{\"Node,RBAC\"})\n\n\t\treturn\n\t}\n\n\tif !kubeVersion.FeatureFlagStructuredAuthorizationConfigurationEnabledByDefault() {\n\t\t// feature-gates flag can be set multiple times, since it has merge addictive policy\n\t\targBuilder.Set(\"feature-gates\", argsbuilder.Value{\"StructuredAuthorizationConfiguration=true\"})\n\t}\n\n\targBuilder.Set(\"authorization-config\", argsbuilder.Value{filepath.Join(constants.KubernetesAPIServerConfigDir, \"authorization-config.yaml\")})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/control_plane_static_pod_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\tv1 \"k8s.io/api/core/v1\"\n\tapiresource \"k8s.io/apimachinery/pkg/api/resource\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\ntype ControlPlaneStaticPodSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileDefaults() {\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\tconfigControllerManager := k8s.NewControllerManagerConfig()\n\tconfigControllerManager.TypedSpec().Enabled = true\n\tconfigScheduler := k8s.NewSchedulerConfig()\n\tconfigScheduler.TypedSpec().Enabled = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configControllerManager))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configScheduler))\n\n\trtestutils.AssertResources(\n\t\tsuite.Ctx(),\n\t\tsuite.T(),\n\t\tsuite.State(),\n\t\t[]resource.ID{\n\t\t\tk8s.APIServerID,\n\t\t\tk8s.ControllerManagerID,\n\t\t\tk8s.SchedulerID,\n\t\t},\n\t\tfunc(*k8s.StaticPod, *assert.Assertions) {},\n\t)\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() {\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\t*configAPIServer.TypedSpec() = k8s.APIServerConfigSpec{\n\t\tExtraVolumes: []k8s.ExtraVolume{\n\t\t\t{\n\t\t\t\tName:      \"foo\",\n\t\t\t\tHostPath:  \"/var/lib\",\n\t\t\t\tMountPath: \"/var/foo\",\n\t\t\t\tReadOnly:  true,\n\t\t\t},\n\t\t},\n\t}\n\n\tconfigControllerManager := k8s.NewControllerManagerConfig()\n\tconfigControllerManager.TypedSpec().Enabled = true\n\tconfigScheduler := k8s.NewSchedulerConfig()\n\tconfigScheduler.TypedSpec().Enabled = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configControllerManager))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configScheduler))\n\n\trtestutils.AssertResources(\n\t\tsuite.Ctx(),\n\t\tsuite.T(),\n\t\tsuite.State(),\n\t\t[]resource.ID{\n\t\t\tk8s.APIServerID,\n\t\t\tk8s.ControllerManagerID,\n\t\t\tk8s.SchedulerID,\n\t\t},\n\t\tfunc(*k8s.StaticPod, *assert.Assertions) {},\n\t)\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\tapiServerPod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Assert().Len(apiServerPod.Spec.Volumes, 4)\n\t\tsuite.Assert().Len(apiServerPod.Spec.Containers[0].VolumeMounts, 4)\n\n\t\tsuite.Assert().Equal([]v1.Volume{\n\t\t\t{\n\t\t\t\tName: \"secrets\",\n\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\tPath: constants.KubernetesAPIServerSecretsDir,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"config\",\n\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\tPath: constants.KubernetesAPIServerConfigDir,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"audit\",\n\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\tPath: constants.KubernetesAuditLogDir,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"foo\",\n\t\t\t\tVolumeSource: v1.VolumeSource{\n\t\t\t\t\tHostPath: &v1.HostPathVolumeSource{\n\t\t\t\t\t\tPath: \"/var/lib\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\tapiServerPod.Spec.Volumes,\n\t\t)\n\n\t\tsuite.Assert().Equal([]v1.VolumeMount{\n\t\t\t{\n\t\t\t\tName:      \"secrets\",\n\t\t\t\tMountPath: constants.KubernetesAPIServerSecretsDir,\n\t\t\t\tReadOnly:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"config\",\n\t\t\t\tMountPath: constants.KubernetesAPIServerConfigDir,\n\t\t\t\tReadOnly:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"audit\",\n\t\t\t\tMountPath: constants.KubernetesAuditLogDir,\n\t\t\t\tReadOnly:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:      \"foo\",\n\t\t\t\tMountPath: \"/var/foo\",\n\t\t\t\tReadOnly:  true,\n\t\t\t},\n\t\t},\n\t\t\tapiServerPod.Spec.Containers[0].VolumeMounts,\n\t\t)\n\t})\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgsK8s() {\n\ttests := []struct {\n\t\tk8sVersion  string\n\t\targs        map[string]k8s.ArgValues\n\t\texpected    map[string][]string\n\t\texpectError bool\n\t}{\n\t\t{\n\t\t\tk8sVersion: \"v1.28.0\", // authorization-config not supported and `authorization-mode` is not set\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\": {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"bind-address\":             {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\": {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":            {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\": {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"authorization-mode\":       {\"Node,RBAC\"},\n\t\t\t\t\"bind-address\":             {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\": {\"2\"},\n\t\t\t\t\"feature-gates\":            {\"PodNodeSelector=true\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk8sVersion: \"v1.28.0\", // authorization-config not supported\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\": {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"authorization-mode\":       {Values: []string{\"Webhook\"}},\n\t\t\t\t\"bind-address\":             {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\": {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":            {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\": {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"authorization-mode\":       {\"Node,RBAC,Webhook\"},\n\t\t\t\t\"bind-address\":             {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\": {\"2\"},\n\t\t\t\t\"feature-gates\":            {\"PodNodeSelector=true\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk8sVersion: \"v1.29.0\", // authorization-config supported, but feature-gates is alpha\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\": {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"bind-address\":             {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\": {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":            {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\": {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"bind-address\":             {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\": {\"2\"},\n\t\t\t\t\"feature-gates\":            {\"StructuredAuthorizationConfiguration=true,PodNodeSelector=true\"},\n\t\t\t\t\"authorization-config\":     {filepath.Join(constants.KubernetesAPIServerConfigDir, \"authorization-config.yaml\")},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk8sVersion: \"v1.29.0\", // authorization-config supported, but feature-gates is alpha, upgrade scenario where `authorization-mode` is already set\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\": {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"bind-address\":             {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\": {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":            {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t\t\"authorization-mode\":       {Values: []string{\"Webhook,Node\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\": {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"bind-address\":             {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\": {\"2\"},\n\t\t\t\t\"feature-gates\":            {\"PodNodeSelector=true\"},\n\t\t\t\t\"authorization-mode\":       {\"Node,RBAC,Webhook\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk8sVersion: \"v1.30.0\", // authorization-config supported, feature-gates is beta (enabled by default), upgrade scenario where `authorization-webhook-*` is already set\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\":      {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"bind-address\":                  {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\":      {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":                 {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t\t\"authorization-webhook-version\": {Values: []string{\"v1\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\":      {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"bind-address\":                  {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\":      {\"2\"},\n\t\t\t\t\"feature-gates\":                 {\"PodNodeSelector=true\"},\n\t\t\t\t\"authorization-mode\":            {\"Node,RBAC\"},\n\t\t\t\t\"authorization-webhook-version\": {\"v1\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tk8sVersion: \"v1.30.0\", // authorization-config supported, feature-gates is beta (enabled by default)\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"enable-admission-plugins\": {Values: []string{\"NodeRestriction,PodNodeSelector\"}},\n\t\t\t\t\"bind-address\":             {Values: []string{\"127.0.0.1\"}},\n\t\t\t\t\"audit-log-batch-max-size\": {Values: []string{\"2\"}},\n\t\t\t\t\"feature-gates\":            {Values: []string{\"PodNodeSelector=true\"}},\n\t\t\t},\n\t\t\texpected: map[string][]string{\n\t\t\t\t\"enable-admission-plugins\": {\"NodeRestriction,PodNodeSelector\"},\n\t\t\t\t\"bind-address\":             {\"127.0.0.1\"},\n\t\t\t\t\"audit-log-batch-max-size\": {\"2\"},\n\t\t\t\t\"feature-gates\":            {\"PodNodeSelector=true\"},\n\t\t\t\t\"authorization-config\":     {filepath.Join(constants.KubernetesAPIServerConfigDir, \"authorization-config.yaml\")},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\targs: map[string]k8s.ArgValues{\n\t\t\t\t\"proxy-client-key-file\": {Values: []string{\"front-proxy-client.key\"}},\n\t\t\t},\n\t\t\texpectError: true,\n\t\t},\n\t}\n\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {})\n\n\tfor _, test := range tests {\n\t\tconfigAPIServer.TypedSpec().ExtraArgs = test.args\n\n\t\tif test.k8sVersion != \"\" {\n\t\t\tconfigAPIServer.TypedSpec().Image = fmt.Sprintf(\"k8s.gcr.io/kube-apiserver:%s\", test.k8sVersion)\n\t\t}\n\n\t\toldData := configAPIServer.TypedSpec().ExtraArgs\n\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configAPIServer))\n\n\t\tif test.expectError {\n\t\t\t// wait for some time to ensure that controller has picked the input\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\t\t// if the test expects an error, we should not have updated the extra args\n\t\t\tsuite.Assert().Equal(oldData, configAPIServer.TypedSpec().ExtraArgs)\n\n\t\t\tcontinue\n\t\t}\n\n\t\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\t\tapiServerPod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tassert.NotEmpty(apiServerPod.Spec.Containers)\n\n\t\t\tassertArg := func(arg string, equals []string) {\n\t\t\t\tactual := make([]string, 0, len(equals))\n\n\t\t\t\tfor _, param := range apiServerPod.Spec.Containers[0].Command {\n\t\t\t\t\tif strings.HasPrefix(param, fmt.Sprintf(\"--%s\", arg)) {\n\t\t\t\t\t\tkey, value, ok := strings.Cut(param, \"=\")\n\t\t\t\t\t\tassert.True(ok, \"expected '=' in %s\", param)\n\n\t\t\t\t\t\tassert.Equal(\"--\"+arg, key)\n\n\t\t\t\t\t\tactual = append(actual, value)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(len(equals), len(actual))\n\t\t\t\tassert.ElementsMatch(equals, actual)\n\t\t\t}\n\n\t\t\tfor k, v := range test.expected {\n\t\t\t\tassertArg(k, v)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileEnvironmentVariables() {\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\n\ttests := []struct {\n\t\tenv      map[string]string\n\t\texpected []v1.EnvVar\n\t}{\n\t\t{\n\t\t\tenv: nil,\n\t\t\texpected: []v1.EnvVar{\n\t\t\t\t{\n\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\tValueFrom: &v1.EnvVarSource{\n\t\t\t\t\t\tFieldRef: &v1.ObjectFieldSelector{\n\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tenv: map[string]string{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t\t\"baz\": \"$(foo)\",\n\t\t\t},\n\t\t\texpected: []v1.EnvVar{\n\t\t\t\t{\n\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\tValueFrom: &v1.EnvVarSource{\n\t\t\t\t\t\tFieldRef: &v1.ObjectFieldSelector{\n\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"baz\",\n\t\t\t\t\tValue: \"$$(foo)\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:  \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {})\n\n\tfor _, test := range tests {\n\t\tconfigAPIServer.TypedSpec().EnvironmentVariables = test.env\n\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configAPIServer))\n\n\t\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\t\tapiServerPod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tassert.ElementsMatch(test.expected, apiServerPod.Spec.Containers[0].Env)\n\t\t})\n\t}\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileAdvertisedAddressArg() {\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\n\tconfigAPIServer.TypedSpec().AdvertisedAddress = \"$(POD_IP)\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\tapiServerPod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\tsuite.Require().NoError(err)\n\n\t\tassert.NotEmpty(apiServerPod.Spec.Containers)\n\n\t\tassert.Contains(apiServerPod.Spec.Containers[0].Command, \"--advertise-address=$(POD_IP)\")\n\t})\n\n\tconfigAPIServer.TypedSpec().AdvertisedAddress = \"\"\n\n\tsuite.Assert().NoError(suite.State().Update(suite.Ctx(), configAPIServer))\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), k8s.APIServerID, func(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\tapiServerPod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\tsuite.Require().NoError(err)\n\n\t\tassert.NotEmpty(apiServerPod.Spec.Containers)\n\n\t\tassert.NotContains(apiServerPod.Spec.Containers[0].Command, \"--advertise-address\")\n\t})\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestControlPlaneStaticPodsExceptScheduler() {\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\tconfigControllerManager := k8s.NewControllerManagerConfig()\n\tconfigControllerManager.TypedSpec().Enabled = true\n\tconfigScheduler := k8s.NewSchedulerConfig()\n\tconfigScheduler.TypedSpec().Enabled = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configControllerManager))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configScheduler))\n\n\trtestutils.AssertResources(\n\t\tsuite.Ctx(),\n\t\tsuite.T(),\n\t\tsuite.State(),\n\t\t[]resource.ID{\n\t\t\tk8s.APIServerID,\n\t\t\tk8s.ControllerManagerID,\n\t\t\tk8s.SchedulerID,\n\t\t},\n\t\tfunc(*k8s.StaticPod, *assert.Assertions) {},\n\t)\n\n\tconfigScheduler.TypedSpec().Enabled = false\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configScheduler))\n\n\trtestutils.AssertResources(\n\t\tsuite.Ctx(),\n\t\tsuite.T(),\n\t\tsuite.State(),\n\t\t[]resource.ID{\n\t\t\tk8s.APIServerID,\n\t\t\tk8s.ControllerManagerID,\n\t\t},\n\t\tfunc(*k8s.StaticPod, *assert.Assertions) {},\n\t)\n}\n\nfunc (suite *ControlPlaneStaticPodSuite) TestReconcileStaticPodResources() {\n\tconfigStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)\n\tsecretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)\n\n\tconfigAPIServer := k8s.NewAPIServerConfig()\n\tconfigControllerManager := k8s.NewControllerManagerConfig()\n\tconfigControllerManager.TypedSpec().Enabled = true\n\tconfigScheduler := k8s.NewSchedulerConfig()\n\tconfigScheduler.TypedSpec().Enabled = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), secretStatus))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configAPIServer))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configControllerManager))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), configScheduler))\n\n\ttests := []struct {\n\t\tresources   k8s.Resources\n\t\texpected    v1.ResourceRequirements\n\t\texpectedEnv v1.EnvVar\n\t}{\n\t\t{\n\t\t\tresources: k8s.Resources{\n\t\t\t\tRequests: map[string]string{\n\t\t\t\t\tstring(v1.ResourceCPU):    \"100m\",\n\t\t\t\t\tstring(v1.ResourceMemory): \"256Mi\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: v1.ResourceRequirements{\n\t\t\t\tRequests: map[v1.ResourceName]apiresource.Quantity{\n\t\t\t\t\tv1.ResourceCPU:    apiresource.MustParse(\"100m\"),\n\t\t\t\t\tv1.ResourceMemory: apiresource.MustParse(\"256Mi\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tresources: k8s.Resources{\n\t\t\t\tRequests: map[string]string{\n\t\t\t\t\tstring(v1.ResourceCPU):    \"100m\",\n\t\t\t\t\tstring(v1.ResourceMemory): \"256Mi\",\n\t\t\t\t},\n\t\t\t\tLimits: map[string]string{\n\t\t\t\t\tstring(v1.ResourceCPU):    \"1\",\n\t\t\t\t\tstring(v1.ResourceMemory): \"1Gi\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: v1.ResourceRequirements{\n\t\t\t\tRequests: map[v1.ResourceName]apiresource.Quantity{\n\t\t\t\t\tv1.ResourceCPU:    apiresource.MustParse(\"100m\"),\n\t\t\t\t\tv1.ResourceMemory: apiresource.MustParse(\"256Mi\"),\n\t\t\t\t},\n\t\t\t\tLimits: map[v1.ResourceName]apiresource.Quantity{\n\t\t\t\t\tv1.ResourceCPU:    apiresource.MustParse(\"1\"),\n\t\t\t\t\tv1.ResourceMemory: apiresource.MustParse(\"1Gi\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEnv: v1.EnvVar{\n\t\t\t\tName:  \"GOMEMLIMIT\",\n\t\t\t\tValue: strconv.FormatInt(1024*1024*1024*k8sctrl.GoGCMemLimitPercentage/100, 10),\n\t\t\t},\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tconfigAPIServer.TypedSpec().Resources = test.resources\n\t\tconfigControllerManager.TypedSpec().Resources = test.resources\n\t\tconfigScheduler.TypedSpec().Resources = test.resources\n\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configAPIServer))\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configControllerManager))\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), configScheduler))\n\n\t\trtestutils.AssertResources(\n\t\t\tsuite.Ctx(),\n\t\t\tsuite.T(),\n\t\t\tsuite.State(),\n\t\t\t[]resource.ID{\n\t\t\t\tk8s.APIServerID,\n\t\t\t\tk8s.ControllerManagerID,\n\t\t\t\tk8s.SchedulerID,\n\t\t\t},\n\t\t\tfunc(staticPod *k8s.StaticPod, assert *assert.Assertions) {\n\t\t\t\tpod, err := k8sadapter.StaticPod(staticPod).Pod()\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tassert.NotEmpty(pod.Spec.Containers)\n\n\t\t\t\tassert.Equal(test.expected, pod.Spec.Containers[0].Resources)\n\n\t\t\t\tif test.expectedEnv.Name != \"\" {\n\t\t\t\t\tassert.Contains(pod.Spec.Containers[0].Env, test.expectedEnv)\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t}\n}\n\nfunc TestControlPlaneStaticPodSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ControlPlaneStaticPodSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&k8sctrl.ControlPlaneStaticPodController{}))\n\n\t\t\t\tetcdService := v1alpha1.NewService(\"etcd\")\n\t\t\t\tetcdService.TypedSpec().Running = true\n\t\t\t\tetcdService.TypedSpec().Healthy = true\n\n\t\t\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), etcdService))\n\t\t\t},\n\t\t\tAfterTearDown: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), v1alpha1.NewService(\"etcd\").Metadata()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/control_plane_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype K8sControlPlaneSuite struct {\n\tctest.DefaultSuite\n}\n\n// setupMachine creates a machine with given configuration, waits for it to become ready,\n// and returns API server's spec.\nfunc (suite *K8sControlPlaneSuite) setupMachine(cfg *config.MachineConfig) {\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AdmissionControlConfigID}, func(*k8s.AdmissionControlConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuditPolicyConfigID}, func(*k8s.AuditPolicyConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID}, func(*k8s.AuthorizationConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID}, func(*k8s.APIServerConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControllerManagerConfigID}, func(*k8s.ControllerManagerConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.SchedulerConfigID}, func(*k8s.SchedulerConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID}, func(*k8s.BootstrapManifestsConfig, *assert.Assertions) {})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ExtraManifestsConfigID}, func(*k8s.ExtraManifestsConfig, *assert.Assertions) {})\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileDefaults() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID},\n\t\tfunc(apiServer *k8s.APIServerConfig, assert *assert.Assertions) {\n\t\t\tapiServerCfg := apiServer.TypedSpec()\n\n\t\t\tassert.Empty(apiServerCfg.CloudProvider)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControllerManagerConfigID},\n\t\tfunc(controllerManager *k8s.ControllerManagerConfig, assert *assert.Assertions) {\n\t\t\tassert.Empty(controllerManager.TypedSpec().CloudProvider)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID},\n\t\tfunc(bootstrapConfig *k8s.BootstrapManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"10.96.0.10\", bootstrapConfig.TypedSpec().DNSServiceIP)\n\t\t\tassert.Equal(\"\", bootstrapConfig.TypedSpec().DNSServiceIPv6)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},\n\t\tfunc(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, authorizationConfig.TypedSpec().Config)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileEmptyAuthorizationConfigForK8sLessThanv128() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tContainerImage:            \"k8s.gcr.io/kube-apiserver:v1.28.0\",\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResource[*k8s.AuthorizationConfig](suite.Ctx(), suite.T(), suite.State(), k8s.AuthorizationConfigID, func(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\tassert.Equal(&k8s.AuthorizationConfigSpec{\n\t\t\tImage: \"k8s.gcr.io/kube-apiserver:v1.28.0\",\n\t\t}, authorizationConfig.TypedSpec())\n\t})\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileEmptyAuthorizationConfigAuthorizers() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},\n\t\tfunc(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, authorizationConfig.TypedSpec().Config)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAuthorizers() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"Webhook\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"webhook\",\n\t\t\t\t\t\t\t\tAuthorizerWebhook: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\t\t\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\t\t\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\texpectedAuthorizers := slices.Concat(v1alpha1.APIServerDefaultAuthorizationConfigAuthorizers, []k8s.AuthorizationAuthorizersSpec{\n\t\t{\n\t\t\tType: \"Webhook\",\n\t\t\tName: \"webhook\",\n\t\t\tWebhook: map[string]any{\n\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},\n\t\tfunc(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(expectedAuthorizers, authorizationConfig.TypedSpec().Config)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAuthorizersWithDefaultsSet() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"RBAC\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"foo\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"Webhook\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"webhook\",\n\t\t\t\t\t\t\t\tAuthorizerWebhook: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\t\t\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\t\t\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"Node\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"bar\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\texpectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{\n\t\t{\n\t\t\tType: \"RBAC\",\n\t\t\tName: \"foo\",\n\t\t},\n\t\t{\n\t\t\tType: \"Webhook\",\n\t\t\tName: \"webhook\",\n\t\t\tWebhook: map[string]any{\n\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tType: \"Node\",\n\t\t\tName: \"bar\",\n\t\t},\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},\n\t\tfunc(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(expectedAuthorizers, authorizationConfig.TypedSpec().Config)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileAdditionalAuthorizationConfigAuthorizersWithOnlyNodeSet() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"Node\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"foo\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerType: \"Webhook\",\n\t\t\t\t\t\t\t\tAuthorizerName: \"webhook\",\n\t\t\t\t\t\t\t\tAuthorizerWebhook: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\t\t\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\t\t\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\texpectedAuthorizers := []k8s.AuthorizationAuthorizersSpec{\n\t\t{\n\t\t\tType: \"Node\",\n\t\t\tName: \"foo\",\n\t\t},\n\t\t{\n\t\t\tType: \"RBAC\",\n\t\t\tName: \"rbac\",\n\t\t},\n\t\t{\n\t\t\tType: \"Webhook\",\n\t\t\tName: \"webhook\",\n\t\t\tWebhook: map[string]any{\n\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.AuthorizationConfigID},\n\t\tfunc(authorizationConfig *k8s.AuthorizationConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(expectedAuthorizers, authorizationConfig.TypedSpec().Config)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileTransitionWorker() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\tcfg.Container().RawV1Alpha1().MachineConfig.MachineType = \"worker\"\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\trtestutils.AssertNoResource[*k8s.AdmissionControlConfig](suite.Ctx(), suite.T(), suite.State(), k8s.AdmissionControlConfigID)\n\trtestutils.AssertNoResource[*k8s.AuditPolicyConfig](suite.Ctx(), suite.T(), suite.State(), k8s.AuditPolicyConfigID)\n\trtestutils.AssertNoResource[*k8s.AuthorizationConfig](suite.Ctx(), suite.T(), suite.State(), k8s.AuthorizationConfigID)\n\trtestutils.AssertNoResource[*k8s.APIServerConfig](suite.Ctx(), suite.T(), suite.State(), k8s.APIServerConfigID)\n\trtestutils.AssertNoResource[*k8s.ControllerManagerConfig](suite.Ctx(), suite.T(), suite.State(), k8s.ControllerManagerConfigID)\n\trtestutils.AssertNoResource[*k8s.SchedulerConfig](suite.Ctx(), suite.T(), suite.State(), k8s.SchedulerConfigID)\n\trtestutils.AssertNoResource[*k8s.BootstrapManifestsConfig](suite.Ctx(), suite.T(), suite.State(), k8s.BootstrapManifestsConfigID)\n\trtestutils.AssertNoResource[*k8s.ExtraManifestsConfig](suite.Ctx(), suite.T(), suite.State(), k8s.ExtraManifestsConfigID)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileIPv6() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tPodSubnet:     []string{constants.DefaultIPv6PodNet},\n\t\t\t\t\t\tServiceSubnet: []string{constants.DefaultIPv6ServiceNet},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID},\n\t\tfunc(bootstrapConfig *k8s.BootstrapManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"\", bootstrapConfig.TypedSpec().DNSServiceIP)\n\t\t\tassert.Equal(\"fc00:db8:20::a\", bootstrapConfig.TypedSpec().DNSServiceIPv6)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileDualStack() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tPodSubnet:     []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet},\n\t\t\t\t\t\tServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID},\n\t\tfunc(bootstrapConfig *k8s.BootstrapManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"10.96.0.10\", bootstrapConfig.TypedSpec().DNSServiceIP)\n\t\t\tassert.Equal(\"fc00:db8:20::a\", bootstrapConfig.TypedSpec().DNSServiceIPv6)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileExtraVolumes() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tExtraVolumesConfig: []v1alpha1.VolumeMountConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tVolumeHostPath:  \"/var/lib\",\n\t\t\t\t\t\t\t\tVolumeMountPath: \"/var/foo/\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tVolumeHostPath:  \"/var/lib/a.foo\",\n\t\t\t\t\t\t\t\tVolumeMountPath: \"/var/foo/b.foo\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID},\n\t\tfunc(apiServer *k8s.APIServerConfig, assert *assert.Assertions) {\n\t\t\tapiServerCfg := apiServer.TypedSpec()\n\n\t\t\tassert.Equal(\n\t\t\t\t[]k8s.ExtraVolume{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      \"var-foo\",\n\t\t\t\t\t\tHostPath:  \"/var/lib\",\n\t\t\t\t\t\tMountPath: \"/var/foo/\",\n\t\t\t\t\t\tReadOnly:  false,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:      \"var-foo-b-foo\",\n\t\t\t\t\t\tHostPath:  \"/var/lib/a.foo\",\n\t\t\t\t\t\tMountPath: \"/var/foo/b.foo\",\n\t\t\t\t\t\tReadOnly:  false,\n\t\t\t\t\t},\n\t\t\t\t}, apiServerCfg.ExtraVolumes,\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileEnvironment() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tEnvConfig: v1alpha1.Env{\n\t\t\t\t\t\t\t\"HTTP_PROXY\": \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID},\n\t\tfunc(apiServer *k8s.APIServerConfig, assert *assert.Assertions) {\n\t\t\tapiServerCfg := apiServer.TypedSpec()\n\n\t\t\tassert.Equal(\n\t\t\t\tmap[string]string{\n\t\t\t\t\t\"HTTP_PROXY\": \"foo\",\n\t\t\t\t}, apiServerCfg.EnvironmentVariables,\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileResources() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tRequests: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    \"100m\",\n\t\t\t\t\t\t\t\t\t\"memory\": \"1Gi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLimits: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    2,\n\t\t\t\t\t\t\t\t\t\"memory\": \"1500Mi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tRequests: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    \"50m\",\n\t\t\t\t\t\t\t\t\t\"memory\": \"500Mi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLimits: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    1,\n\t\t\t\t\t\t\t\t\t\"memory\": \"1000Mi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSchedulerConfig: &v1alpha1.SchedulerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tRequests: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    \"150m\",\n\t\t\t\t\t\t\t\t\t\"memory\": \"2Gi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLimits: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":    3,\n\t\t\t\t\t\t\t\t\t\"memory\": \"2000Mi\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID},\n\t\tfunc(apiServer *k8s.APIServerConfig, assert *assert.Assertions) {\n\t\t\tapiServerCfg := apiServer.TypedSpec()\n\n\t\t\tassert.Equal(\n\t\t\t\tk8s.Resources{\n\t\t\t\t\tRequests: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"100m\",\n\t\t\t\t\t\t\"memory\": \"1Gi\",\n\t\t\t\t\t},\n\t\t\t\t\tLimits: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"2\",\n\t\t\t\t\t\t\"memory\": \"1500Mi\",\n\t\t\t\t\t},\n\t\t\t\t}, apiServerCfg.Resources,\n\t\t\t)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControllerManagerConfigID},\n\t\tfunc(controllerManager *k8s.ControllerManagerConfig, assert *assert.Assertions) {\n\t\t\tcontrollerManagerCfg := controllerManager.TypedSpec()\n\n\t\t\tassert.Equal(\n\t\t\t\tk8s.Resources{\n\t\t\t\t\tRequests: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"50m\",\n\t\t\t\t\t\t\"memory\": \"500Mi\",\n\t\t\t\t\t},\n\t\t\t\t\tLimits: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"1\",\n\t\t\t\t\t\t\"memory\": \"1000Mi\",\n\t\t\t\t\t},\n\t\t\t\t}, controllerManagerCfg.Resources,\n\t\t\t)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.SchedulerConfigID},\n\t\tfunc(scheduler *k8s.SchedulerConfig, assert *assert.Assertions) {\n\t\t\tschedulerCfg := scheduler.TypedSpec()\n\n\t\t\tassert.Equal(\n\t\t\t\tk8s.Resources{\n\t\t\t\t\tRequests: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"150m\",\n\t\t\t\t\t\t\"memory\": \"2Gi\",\n\t\t\t\t\t},\n\t\t\t\t\tLimits: map[string]string{\n\t\t\t\t\t\t\"cpu\":    \"3\",\n\t\t\t\t\t\t\"memory\": \"2000Mi\",\n\t\t\t\t\t},\n\t\t\t\t}, schedulerCfg.Resources,\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileExternalCloudProvider() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalEnabled: new(true),\n\t\t\t\t\t\tExternalManifests: []string{\n\t\t\t\t\t\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t\t\t\t\t\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.APIServerConfigID},\n\t\tfunc(apiServer *k8s.APIServerConfig, assert *assert.Assertions) {\n\t\t\tapiServerCfg := apiServer.TypedSpec()\n\n\t\t\tassert.Equal(k8sctrl.CloudProviderExternal, apiServerCfg.CloudProvider)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControllerManagerConfigID},\n\t\tfunc(controllerManager *k8s.ControllerManagerConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(k8sctrl.CloudProviderExternal, controllerManager.TypedSpec().CloudProvider)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ExtraManifestsConfigID},\n\t\tfunc(extraManifests *k8s.ExtraManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(\n\t\t\t\t&k8s.ExtraManifestsConfigSpec{\n\t\t\t\t\tExtraManifests: []k8s.ExtraManifest{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t\t\t\t\t\t\tURL:      \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t\t\t\t\t\t\tPriority: \"30\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t\t\t\t\t\t\tURL:      \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t\t\t\t\t\t\tPriority: \"30\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, extraManifests.TypedSpec())\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileInlineManifests() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterInlineManifests: v1alpha1.ClusterInlineManifests{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInlineManifestName: \"namespace-ci\",\n\t\t\t\t\t\t\tInlineManifestContents: strings.TrimSpace(\n\t\t\t\t\t\t\t\t`\napiVersion: v1\nkind: Namespace\nmetadata:\n\tname: ci\n`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ExtraManifestsConfigID},\n\t\tfunc(extraManifests *k8s.ExtraManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Equal(\n\t\t\t\t&k8s.ExtraManifestsConfigSpec{\n\t\t\t\t\tExtraManifests: []k8s.ExtraManifest{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:           \"namespace-ci\",\n\t\t\t\t\t\t\tPriority:       \"99\",\n\t\t\t\t\t\t\tInlineManifest: \"apiVersion: v1\\nkind: Namespace\\nmetadata:\\n\\tname: ci\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\textraManifests.TypedSpec())\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileKubeProxyMode() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID},\n\t\tfunc(cfg *k8s.BootstrapManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Contains(\n\t\t\t\tcfg.TypedSpec().ProxyArgs,\n\t\t\t\t\"--proxy-mode=nftables\",\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *K8sControlPlaneSuite) TestReconcileKubeProxyModeLegacy() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tProxyConfig: &v1alpha1.ProxyConfig{\n\t\t\t\t\t\tContainerImage: constants.KubeProxyImage + \":v1.30.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.setupMachine(cfg)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.BootstrapManifestsConfigID},\n\t\tfunc(cfg *k8s.BootstrapManifestsConfig, assert *assert.Assertions) {\n\t\t\tassert.Contains(\n\t\t\t\tcfg.TypedSpec().ProxyArgs,\n\t\t\t\t\"--proxy-mode=iptables\",\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc TestK8sControlPlaneSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &K8sControlPlaneSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneAPIServerController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneAdmissionControlController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneAuditPolicyController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneAuthorizationController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneBootstrapManifestsController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneControllerManagerController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneExtraManifestsController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewControlPlaneSchedulerController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/tools/cache\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// EndpointController looks up control plane endpoints.\ntype EndpointController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EndpointController) Name() string {\n\treturn \"k8s.EndpointController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.EndpointType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tmachineType := machineTypeRes.MachineType()\n\n\t\tswitch machineType { //nolint:exhaustive\n\t\tcase machine.TypeWorker:\n\t\t\tif err = ctrl.watchEndpointsOnWorker(ctx, r, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase machine.TypeControlPlane, machine.TypeInit:\n\t\t\tif err = ctrl.watchEndpointsOnControlPlane(ctx, r, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *EndpointController) watchEndpointsOnWorker(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tlogger.Debug(\"waiting for kubelet client config\", zap.String(\"file\", constants.KubeletKubeconfig))\n\n\tif err := conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tclient, err := kubernetes.NewClientFromKubeletKubeconfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Kubernetes client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tr.QueueReconcile()\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tif err = ctrl.watchKubernetesEndpointSlices(ctx, r, logger, client); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *EndpointController) watchEndpointsOnControlPlane(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesType,\n\t\t\tID:        optional.Some(secrets.KubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tr.QueueReconcile()\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tsecretsResources, err := safe.ReaderGetByID[*secrets.Kubernetes](ctx, r, secrets.KubernetesID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tsecrets := secretsResources.TypedSpec()\n\n\t\tkubeconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\t\t// using here kubeconfig with cluster control plane endpoint, as endpoint discovery should work before local API server is ready\n\t\t\treturn clientcmd.Load([]byte(secrets.AdminKubeconfig))\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error loading kubeconfig: %w\", err)\n\t\t}\n\n\t\t// closure to capture the deferred close on client\n\t\twatch := func() error {\n\t\t\tclient, err := kubernetes.NewForConfig(kubeconfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error building Kubernetes client: %w\", err)\n\t\t\t}\n\n\t\t\tdefer client.Close() //nolint:errcheck\n\n\t\t\tif err = ctrl.watchKubernetesEndpointSlices(ctx, r, logger, client); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t\tif err = watch(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *EndpointController) updateEndpointsResource(\n\tctx context.Context,\n\tr controller.Runtime,\n\tlogger *zap.Logger,\n\tobject *discoveryv1.EndpointSlice,\n) error {\n\tvar addrs []netip.Addr\n\n\tfor _, endpoint := range object.Endpoints {\n\t\tfor _, addr := range endpoint.Addresses {\n\t\t\tip, err := netip.ParseAddr(addr)\n\t\t\tif err == nil {\n\t\t\t\taddrs = append(addrs, ip)\n\t\t\t}\n\t\t}\n\t}\n\n\tslices.SortFunc(addrs, func(a, b netip.Addr) int { return a.Compare(b) })\n\n\tif err := safe.WriterModify(ctx,\n\t\tr,\n\t\tk8s.NewEndpoint(k8s.ControlPlaneNamespaceName, k8s.ControlPlaneAPIServerEndpointsID),\n\t\tfunc(r *k8s.Endpoint) error {\n\t\t\tif !slices.Equal(r.TypedSpec().Addresses, addrs) {\n\t\t\t\tlogger.Debug(\"updated controlplane endpoints\", zap.Any(\"endpoints\", addrs))\n\t\t\t}\n\n\t\t\tvar addrIPv4, addrIPv6 []netip.Addr\n\n\t\t\tfor _, addr := range r.TypedSpec().Addresses {\n\t\t\t\tswitch {\n\t\t\t\tcase addr.Is4():\n\t\t\t\t\taddrIPv4 = append(addrIPv4, addr)\n\n\t\t\t\tcase addr.Is6():\n\t\t\t\t\taddrIPv6 = append(addrIPv6, addr)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch object.AddressType {\n\t\t\tcase discoveryv1.AddressTypeIPv4:\n\t\t\t\taddrIPv4 = addrs\n\n\t\t\tcase discoveryv1.AddressTypeIPv6:\n\t\t\t\taddrIPv6 = addrs\n\n\t\t\tcase discoveryv1.AddressTypeFQDN:\n\t\t\t\tfallthrough\n\n\t\t\tdefault:\n\t\t\t\t// ignore all other cases\n\t\t\t}\n\n\t\t\tr.TypedSpec().Addresses = slices.Concat(addrIPv4, addrIPv6)\n\n\t\t\treturn nil\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error updating endpoints: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *EndpointController) watchKubernetesEndpointSlices(ctx context.Context, r controller.Runtime, logger *zap.Logger, client *kubernetes.Client) error {\n\t// abort the watch on any return from this function\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tnotifyCh, watchCloser, err := kubernetesEndpointSliceWatcher(ctx, logger, client)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error watching Kubernetes endpoint slice: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tcancel() // cancel the context before stopping the watcher\n\n\t\twatchCloser()\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase endpoints := <-notifyCh:\n\t\t\tif err = ctrl.updateEndpointsResource(ctx, r, logger, endpoints); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\t// something got updated, probably kubeconfig, restart the watch\n\t\t\tr.QueueReconcile()\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc kubernetesEndpointSliceWatcher(ctx context.Context, logger *zap.Logger, client *kubernetes.Client) (chan *discoveryv1.EndpointSlice, func(), error) {\n\tinformerFactory := informers.NewSharedInformerFactoryWithOptions(\n\t\tclient.Clientset, constants.KubernetesInformerDefaultResyncPeriod,\n\t\tinformers.WithNamespace(corev1.NamespaceDefault),\n\t\tinformers.WithTweakListOptions(func(options *v1.ListOptions) {\n\t\t\toptions.FieldSelector = fields.OneTermEqualSelector(\"metadata.name\", \"kubernetes\").String()\n\t\t}),\n\t)\n\n\tnotifyCh := make(chan *discoveryv1.EndpointSlice, 1)\n\n\tinformer := informerFactory.Discovery().V1().EndpointSlices().Informer()\n\n\tif err := informer.SetWatchErrorHandler(func(r *cache.Reflector, err error) {\n\t\tlogger.Error(\"kubernetes endpoint watch error\", zap.Error(err))\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error setting watch error handler: %w\", err)\n\t}\n\n\tif _, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc:    func(obj any) { notifyCh <- obj.(*discoveryv1.EndpointSlice) },\n\t\tDeleteFunc: func(_ any) { notifyCh <- &discoveryv1.EndpointSlice{} },\n\t\tUpdateFunc: func(_, obj any) { notifyCh <- obj.(*discoveryv1.EndpointSlice) },\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error adding watch event handler: %w\", err)\n\t}\n\n\tinformerFactory.Start(ctx.Done())\n\n\treturn notifyCh, informerFactory.Shutdown, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/extra_manifest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/hashicorp/go-getter/v2\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ExtraManifestController renders manifests based on templates and config/secrets.\ntype ExtraManifestController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ExtraManifestController) Name() string {\n\treturn \"k8s.ExtraManifestController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ExtraManifestController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.ExtraManifestsConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ExtraManifestController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.ManifestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ExtraManifestController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// wait for network to be ready as networking is required to download extra manifests\n\t\tnetworkResource, err := safe.ReaderGetByID[*network.Status](ctx, r, network.StatusID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkStatus := networkResource.TypedSpec()\n\n\t\tif !(networkStatus.AddressReady && networkStatus.ConnectivityReady) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconfigResource, err := safe.ReaderGetByID[*k8s.ExtraManifestsConfig](ctx, r, k8s.ExtraManifestsConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tconfig := *configResource.TypedSpec()\n\n\t\tvar multiErr *multierror.Error\n\n\t\tpresentManifests := map[resource.ID]struct{}{}\n\n\t\tfor _, manifest := range config.ExtraManifests {\n\t\t\tvar id resource.ID\n\n\t\t\tid, err = ctrl.process(ctx, r, logger, manifest)\n\t\t\tif err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t}\n\n\t\t\tpresentManifests[id] = struct{}{}\n\t\t}\n\n\t\tif multiErr.ErrorOrNil() != nil {\n\t\t\treturn multiErr.ErrorOrNil()\n\t\t}\n\n\t\tallManifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing extra manifests: %w\", err)\n\t\t}\n\n\t\tfor _, manifest := range allManifests.Items {\n\t\t\tif manifest.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, exists := presentManifests[manifest.Metadata().ID()]; !exists {\n\t\t\t\tif err = r.Destroy(ctx, manifest.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up extra manifest: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *ExtraManifestController) process(ctx context.Context, r controller.Runtime, logger *zap.Logger, manifest k8s.ExtraManifest) (id resource.ID, err error) {\n\tid = fmt.Sprintf(\"%s-%s\", manifest.Priority, manifest.Name)\n\n\t// inline manifests don't require download\n\tif manifest.InlineManifest != \"\" {\n\t\treturn id, ctrl.processInline(ctx, r, manifest, id)\n\t}\n\n\treturn id, ctrl.processURL(ctx, r, logger, manifest, id)\n}\n\nfunc (ctrl *ExtraManifestController) processURL(ctx context.Context, r controller.Runtime, logger *zap.Logger, manifest k8s.ExtraManifest, id resource.ID) (err error) {\n\tvar tmpDir string\n\n\ttmpDir, err = os.MkdirTemp(\"\", \"talos\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer os.RemoveAll(tmpDir) //nolint:errcheck\n\n\t// I wish we never used go-getter package, as it doesn't allow downloading into memory.\n\t// But there's not much we can do about it right now, as it supports lots of magic\n\t// users might rely upon.\n\n\t// Disable netrc since we don't have getent installed, and most likely\n\t// never will.\n\thttpGetter := &getter.HttpGetter{\n\t\tNetrc: false,\n\t\tClient: &http.Client{\n\t\t\tTransport: httpdefaults.PatchTransport(cleanhttp.DefaultTransport()),\n\t\t},\n\t}\n\n\thttpGetter.Header = make(http.Header)\n\n\tfor k, v := range manifest.ExtraHeaders {\n\t\thttpGetter.Header.Add(k, v)\n\t}\n\n\tclient := &getter.Client{\n\t\tGetters: []getter.Getter{\n\t\t\thttpGetter,\n\t\t},\n\t}\n\n\tdst := filepath.Join(tmpDir, \"manifest.yaml\")\n\n\tif _, err = client.Get(ctx, &getter.Request{\n\t\tSrc:     manifest.URL,\n\t\tDst:     dst,\n\t\tPwd:     tmpDir,\n\t\tGetMode: getter.ModeFile,\n\t}); err != nil {\n\t\terr = fmt.Errorf(\"error downloading %q: %w\", manifest.URL, err)\n\n\t\treturn err\n\t}\n\n\tlogger.Sugar().Infof(\"downloaded manifest %q\", manifest.URL)\n\n\tvar contents []byte\n\n\tcontents, err = os.ReadFile(dst)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = safe.WriterModify(ctx, r, k8s.NewManifest(k8s.ControlPlaneNamespaceName, id),\n\t\tfunc(r *k8s.Manifest) error {\n\t\t\treturn k8sadapter.Manifest(r).SetYAML(contents)\n\t\t}); err != nil {\n\t\terr = fmt.Errorf(\"error updating manifests: %w\", err)\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *ExtraManifestController) processInline(ctx context.Context, r controller.Runtime, manifest k8s.ExtraManifest, id resource.ID) error {\n\terr := safe.WriterModify(\n\t\tctx,\n\t\tr,\n\t\tk8s.NewManifest(k8s.ControlPlaneNamespaceName, id),\n\t\tfunc(r *k8s.Manifest) error {\n\t\t\treturn k8sadapter.Manifest(r).SetYAML([]byte(manifest.InlineManifest))\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error updating manifests: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:dupl\nfunc (ctrl *ExtraManifestController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tmanifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing extra manifests: %w\", err)\n\t}\n\n\tfor _, manifest := range manifests.Items {\n\t\tif manifest.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = r.Destroy(ctx, manifest.Metadata()); err != nil {\n\t\t\treturn fmt.Errorf(\"error destroying extra manifest: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/extra_manifest_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ExtraManifestSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *ExtraManifestSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.ExtraManifestController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *ExtraManifestSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\n//nolint:dupl\nfunc (suite *ExtraManifestSuite) assertExtraManifests(manifests []string) error {\n\tresources, err := suite.state.List(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tids := xslices.Map(resources.Items, func(r resource.Resource) string { return r.Metadata().ID() })\n\n\tif !slices.Equal(manifests, ids) {\n\t\treturn retry.ExpectedErrorf(\"expected %q, got %q\", manifests, ids)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *ExtraManifestSuite) TestReconcileInlineManifests() {\n\tconfigExtraManifests := k8s.NewExtraManifestsConfig()\n\t*configExtraManifests.TypedSpec() = k8s.ExtraManifestsConfigSpec{\n\t\tExtraManifests: []k8s.ExtraManifest{\n\t\t\t{\n\t\t\t\tName:     \"namespaces\",\n\t\t\t\tPriority: \"99\",\n\t\t\t\tInlineManifest: strings.TrimSpace(\n\t\t\t\t\t`\napiVersion: v1\nkind: Namespace\nmetadata:\n    name: ci\n---\napiVersion: v1\nkind: Namespace\nmetadata:\n    name: build\n`,\n\t\t\t\t),\n\t\t\t},\n\t\t},\n\t}\n\n\tstatusNetwork := network.NewStatus(network.NamespaceName, network.StatusID)\n\tstatusNetwork.TypedSpec().AddressReady = true\n\tstatusNetwork.TypedSpec().ConnectivityReady = true\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, configExtraManifests))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, statusNetwork))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertExtraManifests(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\t\"99-namespaces\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(\n\t\t\tk8s.ControlPlaneNamespaceName,\n\t\t\tk8s.ManifestType,\n\t\t\t\"99-namespaces\",\n\t\t\tresource.VersionUndefined,\n\t\t),\n\t)\n\tsuite.Require().NoError(err)\n\n\tmanifest := r.(*k8s.Manifest) //nolint:forcetypeassert\n\n\tsuite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 2)\n\tsuite.Assert().Equal(\"ci\", k8sadapter.Manifest(manifest).Objects()[0].GetName())\n\tsuite.Assert().Equal(\"build\", k8sadapter.Manifest(manifest).Objects()[1].GetName())\n}\n\nfunc (suite *ExtraManifestSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestExtraManifestSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(ExtraManifestSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/apiserver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tapiserverv1 \"k8s.io/apiserver/pkg/apis/apiserver/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// APIServerEncryptionConfig returns the encryption configuration for the API server.\nfunc APIServerEncryptionConfig(rootK8sSecrets *secrets.KubernetesRootSpec) runtime.Object {\n\tobj := apiserverv1.EncryptionConfiguration{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"EncryptionConfig\",\n\t\t\tAPIVersion: apiserverv1.SchemeGroupVersion.Version,\n\t\t},\n\t\tResources: []apiserverv1.ResourceConfiguration{\n\t\t\t{\n\t\t\t\tResources: []string{\"secrets\"},\n\t\t\t\tProviders: []apiserverv1.ProviderConfiguration{},\n\t\t\t},\n\t\t},\n\t}\n\n\tif rootK8sSecrets.SecretboxEncryptionSecret != \"\" {\n\t\tobj.Resources[0].Providers = append(obj.Resources[0].Providers, apiserverv1.ProviderConfiguration{\n\t\t\tSecretbox: &apiserverv1.SecretboxConfiguration{\n\t\t\t\tKeys: []apiserverv1.Key{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"key2\",\n\t\t\t\t\t\tSecret: rootK8sSecrets.SecretboxEncryptionSecret,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tif rootK8sSecrets.AESCBCEncryptionSecret != \"\" {\n\t\tobj.Resources[0].Providers = append(obj.Resources[0].Providers, apiserverv1.ProviderConfiguration{\n\t\t\tAESCBC: &apiserverv1.AESConfiguration{\n\t\t\t\tKeys: []apiserverv1.Key{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"key1\",\n\t\t\t\t\t\tSecret: rootK8sSecrets.AESCBCEncryptionSecret,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tobj.Resources[0].Providers = append(obj.Resources[0].Providers, apiserverv1.ProviderConfiguration{\n\t\tIdentity: &apiserverv1.IdentityConfiguration{},\n\t})\n\n\treturn &obj\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/coredns.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\trbacv1 \"k8s.io/api/rbac/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// CoreDNSService returns the CoreDNS service object.\nfunc CoreDNSService(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\tobj := &corev1.Service{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"Service\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.Version,\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kube-dns\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tAnnotations: map[string]string{\n\t\t\t\t\"prometheus.io/scrape\": \"true\",\n\t\t\t\t\"prometheus.io/port\":   \"9153\",\n\t\t\t},\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\":                       \"kube-dns\",\n\t\t\t\t\"kubernetes.io/cluster-service\": \"true\",\n\t\t\t\t\"kubernetes.io/name\":            \"CoreDNS\",\n\t\t\t},\n\t\t},\n\t\tSpec: corev1.ServiceSpec{\n\t\t\tSelector: map[string]string{\n\t\t\t\t\"k8s-app\": \"kube-dns\",\n\t\t\t},\n\t\t\tClusterIP: cmp.Or(spec.DNSServiceIP, spec.DNSServiceIPv6),\n\t\t\tPorts: []corev1.ServicePort{\n\t\t\t\t{\n\t\t\t\t\tName:       \"dns\",\n\t\t\t\t\tPort:       53,\n\t\t\t\t\tProtocol:   corev1.ProtocolUDP,\n\t\t\t\t\tTargetPort: intstr.FromInt(53),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:       \"dns-tcp\",\n\t\t\t\t\tPort:       53,\n\t\t\t\t\tProtocol:   corev1.ProtocolTCP,\n\t\t\t\t\tTargetPort: intstr.FromInt(53),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:       \"metrics\",\n\t\t\t\t\tPort:       9153,\n\t\t\t\t\tProtocol:   corev1.ProtocolTCP,\n\t\t\t\t\tTargetPort: intstr.FromInt(9153),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif spec.DNSServiceIP != \"\" {\n\t\tobj.Spec.ClusterIPs = append(obj.Spec.ClusterIPs, spec.DNSServiceIP)\n\t\tobj.Spec.IPFamilies = append(obj.Spec.IPFamilies, corev1.IPv4Protocol)\n\t}\n\n\tif spec.DNSServiceIPv6 != \"\" {\n\t\tobj.Spec.ClusterIPs = append(obj.Spec.ClusterIPs, spec.DNSServiceIPv6)\n\t\tobj.Spec.IPFamilies = append(obj.Spec.IPFamilies, corev1.IPv6Protocol)\n\t}\n\n\tif spec.DNSServiceIP != \"\" && spec.DNSServiceIPv6 != \"\" {\n\t\tobj.Spec.IPFamilyPolicy = new(corev1.IPFamilyPolicyRequireDualStack)\n\t} else {\n\t\tobj.Spec.IPFamilyPolicy = new(corev1.IPFamilyPolicySingleStack)\n\t}\n\n\treturn obj\n}\n\n// CoreDNSServiceAccount returns the CoreDNS service account object.\nfunc CoreDNSServiceAccount() runtime.Object {\n\treturn &corev1.ServiceAccount{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ServiceAccount\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.Version,\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"coredns\",\n\t\t\tNamespace: \"kube-system\",\n\t\t},\n\t}\n}\n\n// CoreDNSClusterRoleBinding returns the CoreDNS ClusterRoleBinding object.\nfunc CoreDNSClusterRoleBinding() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system:coredns\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"kubernetes.io/bootstrapping\": \"rbac-defaults\",\n\t\t\t},\n\t\t\tAnnotations: map[string]string{\n\t\t\t\t\"rbac.authorization.kubernetes.io/autoupdate\": \"true\",\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:coredns\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:      \"ServiceAccount\",\n\t\t\t\tName:      \"coredns\",\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// CoreDNSClusterRole returns the CoreDNS ClusterRole object.\nfunc CoreDNSClusterRole() runtime.Object {\n\treturn &rbacv1.ClusterRole{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRole\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system:coredns\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"kubernetes.io/bootstrapping\": \"rbac-defaults\",\n\t\t\t},\n\t\t},\n\t\tRules: []rbacv1.PolicyRule{\n\t\t\t{\n\t\t\t\tAPIGroups: []string{\"\"},\n\t\t\t\tResources: []string{\"endpoints\", \"services\", \"pods\", \"namespaces\"},\n\t\t\t\tVerbs:     []string{\"list\", \"watch\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tAPIGroups: []string{\"discovery.k8s.io\"},\n\t\t\t\tResources: []string{\"endpointslices\"},\n\t\t\t\tVerbs:     []string{\"list\", \"watch\"},\n\t\t\t},\n\t\t},\n\t}\n}\n\n// CoreDNSConfigMap returns the CoreDNS ConfigMap object.\nfunc CoreDNSConfigMap(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\tcoreDNSConfig := fmt.Sprintf(`.:53 {\n    errors\n    health {\n        lameduck 5s\n    }\n    ready\n    log . {\n        class error\n    }\n    prometheus :9153\n\n    kubernetes %s in-addr.arpa ip6.arpa {\n        pods insecure\n        fallthrough in-addr.arpa ip6.arpa\n        ttl 30\n    }\n    forward . /etc/resolv.conf {\n       max_concurrent 1000\n    }\n    cache 30`, spec.ClusterDomain)\n\n\tif spec.ClusterDomain != \"\" {\n\t\tcoreDNSConfig += fmt.Sprintf(` {\n       disable success %s\n       disable denial %s\n    }\n`, spec.ClusterDomain, spec.ClusterDomain)\n\t} else {\n\t\tcoreDNSConfig += \"\\n\"\n\t}\n\n\tcoreDNSConfig += `    loop\n    reload\n    loadbalance\n}\n`\n\n\treturn &corev1.ConfigMap{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ConfigMap\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.Version,\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"coredns\",\n\t\t\tNamespace: \"kube-system\",\n\t\t},\n\t\tData: map[string]string{\n\t\t\t\"Corefile\": coreDNSConfig,\n\t\t},\n\t}\n}\n\n// CoreDNSDeployment returns the CoreDNS Deployment object.\nfunc CoreDNSDeployment(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\treturn &appsv1.Deployment{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"Deployment\",\n\t\t\tAPIVersion: appsv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"coredns\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\":            \"kube-dns\",\n\t\t\t\t\"kubernetes.io/name\": \"CoreDNS\",\n\t\t\t},\n\t\t},\n\t\tSpec: appsv1.DeploymentSpec{\n\t\t\tReplicas: new(int32(2)),\n\t\t\tStrategy: appsv1.DeploymentStrategy{\n\t\t\t\tType: appsv1.RollingUpdateDeploymentStrategyType,\n\t\t\t\tRollingUpdate: &appsv1.RollingUpdateDeployment{\n\t\t\t\t\tMaxUnavailable: new(intstr.FromInt(1)),\n\t\t\t\t},\n\t\t\t},\n\t\t\tSelector: &v1.LabelSelector{\n\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\"k8s-app\": \"kube-dns\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: v1.ObjectMeta{\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\"k8s-app\": \"kube-dns\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tNodeSelector: map[string]string{\n\t\t\t\t\t\t\"kubernetes.io/os\": \"linux\",\n\t\t\t\t\t},\n\t\t\t\t\tAffinity: &corev1.Affinity{\n\t\t\t\t\t\tPodAntiAffinity: &corev1.PodAntiAffinity{\n\t\t\t\t\t\t\tPreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tWeight: 100,\n\t\t\t\t\t\t\t\t\tPodAffinityTerm: corev1.PodAffinityTerm{\n\t\t\t\t\t\t\t\t\t\tLabelSelector: &v1.LabelSelector{\n\t\t\t\t\t\t\t\t\t\t\tMatchExpressions: []v1.LabelSelectorRequirement{\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tKey:      \"k8s-app\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tOperator: v1.LabelSelectorOpIn,\n\t\t\t\t\t\t\t\t\t\t\t\t\tValues:   []string{\"kube-dns\"},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tTopologyKey: \"kubernetes.io/hostname\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tServiceAccountName: \"coredns\",\n\t\t\t\t\tPriorityClassName:  \"system-cluster-critical\",\n\t\t\t\t\tTolerations: []corev1.Toleration{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKey:      \"node-role.kubernetes.io/control-plane\",\n\t\t\t\t\t\t\tOperator: corev1.TolerationOpExists,\n\t\t\t\t\t\t\tEffect:   corev1.TaintEffectNoSchedule,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKey:      \"node.cloudprovider.kubernetes.io/uninitialized\",\n\t\t\t\t\t\t\tOperator: corev1.TolerationOpExists,\n\t\t\t\t\t\t\tEffect:   corev1.TaintEffectNoSchedule,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:            \"coredns\",\n\t\t\t\t\t\t\tImage:           spec.CoreDNSImage,\n\t\t\t\t\t\t\tImagePullPolicy: corev1.PullIfNotPresent,\n\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\tLimits: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\tcorev1.ResourceMemory: resource.MustParse(\"170Mi\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\tcorev1.ResourceCPU:    resource.MustParse(\"100m\"),\n\t\t\t\t\t\t\t\t\tcorev1.ResourceMemory: resource.MustParse(\"70Mi\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEnv: []corev1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:  \"GOMEMLIMIT\",\n\t\t\t\t\t\t\t\t\tValue: \"161MiB\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tArgs: []string{\"-conf\", \"/etc/coredns/Corefile\"},\n\t\t\t\t\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:      \"config-volume\",\n\t\t\t\t\t\t\t\t\tMountPath: \"/etc/coredns\",\n\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:          \"dns\",\n\t\t\t\t\t\t\t\t\tProtocol:      corev1.ProtocolUDP,\n\t\t\t\t\t\t\t\t\tContainerPort: 53,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:          \"dns-tcp\",\n\t\t\t\t\t\t\t\t\tProtocol:      corev1.ProtocolTCP,\n\t\t\t\t\t\t\t\t\tContainerPort: 53,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:          \"metrics\",\n\t\t\t\t\t\t\t\t\tProtocol:      corev1.ProtocolTCP,\n\t\t\t\t\t\t\t\t\tContainerPort: 9153,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLivenessProbe: &corev1.Probe{\n\t\t\t\t\t\t\t\tProbeHandler: corev1.ProbeHandler{\n\t\t\t\t\t\t\t\t\tHTTPGet: &corev1.HTTPGetAction{\n\t\t\t\t\t\t\t\t\t\tPath:   \"/health\",\n\t\t\t\t\t\t\t\t\t\tPort:   intstr.FromInt(8080),\n\t\t\t\t\t\t\t\t\t\tScheme: corev1.URISchemeHTTP,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tInitialDelaySeconds: 60,\n\t\t\t\t\t\t\t\tTimeoutSeconds:      5,\n\t\t\t\t\t\t\t\tSuccessThreshold:    1,\n\t\t\t\t\t\t\t\tFailureThreshold:    5,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tReadinessProbe: &corev1.Probe{\n\t\t\t\t\t\t\t\tProbeHandler: corev1.ProbeHandler{\n\t\t\t\t\t\t\t\t\tHTTPGet: &corev1.HTTPGetAction{\n\t\t\t\t\t\t\t\t\t\tPath:   \"/ready\",\n\t\t\t\t\t\t\t\t\t\tPort:   intstr.FromInt(8181),\n\t\t\t\t\t\t\t\t\t\tScheme: corev1.URISchemeHTTP,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\t\t\t\t\tAllowPrivilegeEscalation: new(false),\n\t\t\t\t\t\t\t\tCapabilities: &corev1.Capabilities{\n\t\t\t\t\t\t\t\t\tAdd:  []corev1.Capability{\"NET_BIND_SERVICE\"},\n\t\t\t\t\t\t\t\t\tDrop: []corev1.Capability{\"ALL\"},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tReadOnlyRootFilesystem: new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tDNSPolicy: corev1.DNSDefault,\n\t\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"config-volume\",\n\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\tConfigMap: &corev1.ConfigMapVolumeSource{\n\t\t\t\t\t\t\t\t\tLocalObjectReference: corev1.LocalObjectReference{\n\t\t\t\t\t\t\t\t\t\tName: \"coredns\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tItems: []corev1.KeyToPath{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tKey:  \"Corefile\",\n\t\t\t\t\t\t\t\t\t\t\tPath: \"Corefile\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/crds.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\tapiextensions \"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// TalosServiceAccountCRDTemplate returns the template of the CRD which\n// allows injecting Talos API credentials for Kubernetes pods.\nfunc TalosServiceAccountCRDTemplate() runtime.Object {\n\treturn &apiextensions.CustomResourceDefinition{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: apiextensions.SchemeGroupVersion.String(),\n\t\t\tKind:       \"CustomResourceDefinition\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: constants.ServiceAccountResourcePlural + \".\" + constants.ServiceAccountResourceGroup,\n\t\t},\n\t\tSpec: apiextensions.CustomResourceDefinitionSpec{\n\t\t\tConversion: &apiextensions.CustomResourceConversion{\n\t\t\t\tStrategy: apiextensions.NoneConverter,\n\t\t\t},\n\t\t\tGroup: constants.ServiceAccountResourceGroup,\n\t\t\tNames: apiextensions.CustomResourceDefinitionNames{\n\t\t\t\tKind:       constants.ServiceAccountResourceKind,\n\t\t\t\tListKind:   constants.ServiceAccountResourceKind + \"List\",\n\t\t\t\tPlural:     constants.ServiceAccountResourcePlural,\n\t\t\t\tSingular:   constants.ServiceAccountResourceSingular,\n\t\t\t\tShortNames: []string{constants.ServiceAccountResourceShortName},\n\t\t\t},\n\t\t\tScope: apiextensions.NamespaceScoped,\n\t\t\tVersions: []apiextensions.CustomResourceDefinitionVersion{\n\t\t\t\t{\n\t\t\t\t\tName:    constants.ServiceAccountResourceVersion,\n\t\t\t\t\tServed:  true,\n\t\t\t\t\tStorage: true,\n\t\t\t\t\tSchema: &apiextensions.CustomResourceValidation{\n\t\t\t\t\t\tOpenAPIV3Schema: &apiextensions.JSONSchemaProps{\n\t\t\t\t\t\t\tType: \"object\",\n\t\t\t\t\t\t\tProperties: map[string]apiextensions.JSONSchemaProps{\n\t\t\t\t\t\t\t\t\"spec\": {\n\t\t\t\t\t\t\t\t\tType: \"object\",\n\t\t\t\t\t\t\t\t\tProperties: map[string]apiextensions.JSONSchemaProps{\n\t\t\t\t\t\t\t\t\t\t\"roles\": {\n\t\t\t\t\t\t\t\t\t\t\tType: \"array\",\n\t\t\t\t\t\t\t\t\t\t\tItems: &apiextensions.JSONSchemaPropsOrArray{\n\t\t\t\t\t\t\t\t\t\t\t\tSchema: &apiextensions.JSONSchemaProps{\n\t\t\t\t\t\t\t\t\t\t\t\t\tType: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\t\t\tType: \"object\",\n\t\t\t\t\t\t\t\t\tProperties: map[string]apiextensions.JSONSchemaProps{\n\t\t\t\t\t\t\t\t\t\t\"failureReason\": {\n\t\t\t\t\t\t\t\t\t\t\tType: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/csr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\trbacv1 \"k8s.io/api/rbac/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n)\n\n// CSRNodeBootstrapTemplate returns the CSR node bootstrap template.\nfunc CSRNodeBootstrapTemplate() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system-bootstrap-node-bootstrapper\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:     \"Group\",\n\t\t\t\tName:     \"system:bootstrappers:nodes\",\n\t\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\t},\n\t\t\t{\n\t\t\t\tKind:     \"Group\",\n\t\t\t\tName:     \"system:nodes\",\n\t\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:node-bootstrapper\",\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t},\n\t}\n}\n\n// CSRApproverRoleBindingTemplate returns the CSR approver role binding template.\nfunc CSRApproverRoleBindingTemplate() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system-bootstrap-approve-node-client-csr\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:     \"Group\",\n\t\t\t\tName:     \"system:bootstrappers:nodes\",\n\t\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:certificates.k8s.io:certificatesigningrequests:nodeclient\",\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t},\n\t}\n}\n\n// CSRRenewalRoleBindingTemplate returns the CSR renewal role binding template.\nfunc CSRRenewalRoleBindingTemplate() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system-bootstrap-node-renewal\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:     \"Group\",\n\t\t\t\tName:     \"system:nodes\",\n\t\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:certificates.k8s.io:certificatesigningrequests:selfnodeclient\",\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/flannel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\trbacv1 \"k8s.io/api/rbac/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// FlannelClusterRoleTemplate returns the template of the ClusterRole\n// for the flannel CNI plugin.\nfunc FlannelClusterRoleTemplate(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\trules := []rbacv1.PolicyRule{\n\t\t{\n\t\t\tAPIGroups: []string{\"\"},\n\t\t\tResources: []string{\"pods\", \"nodes\", \"namespaces\"},\n\t\t\tVerbs:     []string{\"get\", \"list\", \"watch\"},\n\t\t},\n\t\t{\n\t\t\tAPIGroups: []string{\"\"},\n\t\t\tResources: []string{\"nodes/status\"},\n\t\t\tVerbs:     []string{\"patch\"},\n\t\t},\n\t}\n\n\tif spec.FlannelKubeNetworkPoliciesEnabled {\n\t\trules = append(rules, []rbacv1.PolicyRule{\n\t\t\t{\n\t\t\t\tAPIGroups: []string{\"networking.k8s.io\"},\n\t\t\t\tResources: []string{\"networkpolicies\"},\n\t\t\t\tVerbs:     []string{\"list\", \"watch\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tAPIGroups: []string{\"policy.networking.k8s.io\"},\n\t\t\t\tResources: []string{\"adminnetworkpolicies\", \"baselineadminnetworkpolicies\"},\n\t\t\t\tVerbs:     []string{\"list\", \"watch\"},\n\t\t\t},\n\t\t}...)\n\t}\n\n\treturn &rbacv1.ClusterRole{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t\tKind:       \"ClusterRole\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"flannel\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t},\n\t\t},\n\t\tRules: rules,\n\t}\n}\n\n// FlannelClusterRoleBindingTemplate returns the template of the\n// ClusterRoleBinding for the flannel CNI plugin.\nfunc FlannelClusterRoleBindingTemplate() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"flannel\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tAPIGroup: rbacv1.SchemeGroupVersion.Group,\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"flannel\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:      \"ServiceAccount\",\n\t\t\t\tName:      \"flannel\",\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// FlannelServiceAccountTemplate returns the template of the\n// ServiceAccount for the flannel CNI plugin.\nfunc FlannelServiceAccountTemplate() runtime.Object {\n\treturn &corev1.ServiceAccount{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.String(),\n\t\t\tKind:       \"ServiceAccount\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"flannel\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// FlannelConfigMapTemplate returns the template of the ConfigMap\n// for the flannel CNI plugin.\nfunc FlannelConfigMapTemplate(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\tdata := map[string]string{\n\t\t\"cni-conf.json\": `{\n  \"name\": \"cbr0\",\n  \"cniVersion\": \"1.0.0\",\n  \"plugins\": [\n    {\n      \"type\": \"flannel\",\n      \"delegate\": {\n        \"hairpinMode\": true,\n        \"isDefaultGateway\": true\n      }\n    },\n    {\n      \"type\": \"portmap\",\n      \"capabilities\": {\n        \"portMappings\": true\n      }\n    }\n  ]\n}`,\n\t}\n\n\tvar netConf struct {\n\t\tNetwork     string `json:\"Network,omitempty\"`\n\t\tIPv6Network string `json:\"IPv6Network,omitempty\"`\n\t\tEnableIPv6  *bool  `json:\"EnableIPv6,omitempty\"`\n\t\tEnableIPv4  *bool  `json:\"EnableIPv4,omitempty\"`\n\t\tBackend     struct {\n\t\t\tType string `json:\"Type\"`\n\t\t\tPort int    `json:\"Port\"`\n\t\t} `json:\"Backend\"`\n\t}\n\n\tnetConf.Backend.Type = \"vxlan\"\n\tnetConf.Backend.Port = 4789\n\n\thasIPv4 := false\n\n\tfor _, cidr := range spec.PodCIDRs {\n\t\tif strings.Contains(cidr, \".\") {\n\t\t\tnetConf.Network = cidr\n\t\t\thasIPv4 = true\n\t\t} else {\n\t\t\tnetConf.IPv6Network = cidr\n\t\t\tnetConf.EnableIPv6 = new(true)\n\t\t}\n\t}\n\n\tif !hasIPv4 {\n\t\tnetConf.EnableIPv4 = new(false)\n\t}\n\n\tnetConfJSON, err := json.MarshalIndent(netConf, \"\", \"  \")\n\tif err != nil {\n\t\t// should never happen\n\t\tpanic(fmt.Sprintf(\"failed to marshal net-conf.json: %s\", err))\n\t}\n\n\tdata[\"net-conf.json\"] = string(netConfJSON)\n\n\treturn &corev1.ConfigMap{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.String(),\n\t\t\tKind:       \"ConfigMap\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kube-flannel-cfg\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t\t\"tier\":    \"node\",\n\t\t\t},\n\t\t},\n\t\tData: data,\n\t}\n}\n\n// FlannelDaemonSetTemplate returns the template of the DaemonSet\n// for the flannel CNI plugin.\nfunc FlannelDaemonSetTemplate(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\tenvVars := []corev1.EnvVar{\n\t\t{\n\t\t\tName: \"POD_NAME\",\n\t\t\tValueFrom: &corev1.EnvVarSource{\n\t\t\t\tFieldRef: &corev1.ObjectFieldSelector{\n\t\t\t\t\tFieldPath: \"metadata.name\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"POD_NAMESPACE\",\n\t\t\tValueFrom: &corev1.EnvVarSource{\n\t\t\t\tFieldRef: &corev1.ObjectFieldSelector{\n\t\t\t\t\tFieldPath: \"metadata.namespace\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:  \"EVENT_QUEUE_DEPTH\",\n\t\t\tValue: \"5000\",\n\t\t},\n\t\t{\n\t\t\tName:  \"CONT_WHEN_CACHE_NOT_READY\",\n\t\t\tValue: \"false\",\n\t\t},\n\t}\n\n\tif spec.FlannelKubeServiceHost != \"\" {\n\t\tenvVars = append(envVars, corev1.EnvVar{\n\t\t\tName:  \"KUBERNETES_SERVICE_HOST\",\n\t\t\tValue: spec.FlannelKubeServiceHost,\n\t\t})\n\t}\n\n\tif spec.FlannelKubeServicePort != \"\" {\n\t\tenvVars = append(envVars, corev1.EnvVar{\n\t\t\tName:  \"KUBERNETES_SERVICE_PORT\",\n\t\t\tValue: spec.FlannelKubeServicePort,\n\t\t})\n\t}\n\n\tvolumes := []corev1.Volume{\n\t\t{Name: \"run\", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: \"/run/flannel\"}}},\n\t\t{Name: \"cni\", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: \"/etc/cni/net.d\"}}},\n\t\t{Name: \"flannel-cfg\", VolumeSource: corev1.VolumeSource{\n\t\t\tConfigMap: &corev1.ConfigMapVolumeSource{\n\t\t\t\tLocalObjectReference: corev1.LocalObjectReference{Name: \"kube-flannel-cfg\"},\n\t\t\t},\n\t\t}},\n\t}\n\n\tif spec.FlannelKubeNetworkPoliciesEnabled {\n\t\tvolumes = append(volumes, corev1.Volume{\n\t\t\tName:         \"lib-modules\",\n\t\t\tVolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: \"/usr/lib/modules\"}},\n\t\t})\n\t}\n\n\tcontainers := []corev1.Container{\n\t\t{\n\t\t\tName:    \"kube-flannel\",\n\t\t\tImage:   spec.FlannelImage,\n\t\t\tCommand: []string{\"/opt/bin/flanneld\"},\n\t\t\tArgs: slices.Concat(\n\t\t\t\t[]string{\n\t\t\t\t\t\"--ip-masq\",\n\t\t\t\t\t\"--kube-subnet-mgr\",\n\t\t\t\t},\n\t\t\t\tspec.FlannelExtraArgs,\n\t\t\t),\n\t\t\tEnv: envVars,\n\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\tcorev1.ResourceCPU:    resource.MustParse(\"100m\"),\n\t\t\t\t\tcorev1.ResourceMemory: resource.MustParse(\"50Mi\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\tCapabilities: &corev1.Capabilities{\n\t\t\t\t\tAdd: []corev1.Capability{\"NET_ADMIN\", \"NET_RAW\"},\n\t\t\t\t},\n\t\t\t\tPrivileged: new(false),\n\t\t\t},\n\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t{\n\t\t\t\t\tName:      \"run\",\n\t\t\t\t\tMountPath: \"/run/flannel\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:      \"flannel-cfg\",\n\t\t\t\t\tMountPath: \"/etc/kube-flannel/\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif spec.FlannelKubeNetworkPoliciesEnabled {\n\t\tcontainers = append(containers, corev1.Container{\n\t\t\tName:  \"kube-network-policies\",\n\t\t\tImage: spec.FlannelKubeNetworkPoliciesImage,\n\t\t\tCommand: []string{\n\t\t\t\t\"/bin/netpol\",\n\t\t\t\t\"--hostname-override=$(MY_NODE_NAME)\",\n\t\t\t\t\"--v=2\",\n\t\t\t},\n\t\t\tEnv: []corev1.EnvVar{\n\t\t\t\t{\n\t\t\t\t\tName: \"MY_NODE_NAME\",\n\t\t\t\t\tValueFrom: &corev1.EnvVarSource{\n\t\t\t\t\t\tFieldRef: &corev1.ObjectFieldSelector{\n\t\t\t\t\t\t\tFieldPath: \"spec.nodeName\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\tcorev1.ResourceCPU:    resource.MustParse(\"100m\"),\n\t\t\t\t\tcorev1.ResourceMemory: resource.MustParse(\"50Mi\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\tCapabilities: &corev1.Capabilities{\n\t\t\t\t\tAdd: []corev1.Capability{\"NET_ADMIN\"},\n\t\t\t\t},\n\t\t\t\tPrivileged: new(true),\n\t\t\t},\n\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t{\n\t\t\t\t\tName:      \"lib-modules\",\n\t\t\t\t\tMountPath: \"/lib/modules\",\n\t\t\t\t\tReadOnly:  true,\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\treturn &appsv1.DaemonSet{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tAPIVersion: appsv1.SchemeGroupVersion.String(),\n\t\t\tKind:       \"DaemonSet\",\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kube-flannel\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t\t\"tier\":    \"node\",\n\t\t\t},\n\t\t},\n\t\tSpec: appsv1.DaemonSetSpec{\n\t\t\tSelector: &v1.LabelSelector{\n\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t\t\t\"tier\":    \"node\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: v1.ObjectMeta{\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\"k8s-app\": \"flannel\",\n\t\t\t\t\t\t\"tier\":    \"node\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tAffinity: &corev1.Affinity{\n\t\t\t\t\t\tNodeAffinity: &corev1.NodeAffinity{\n\t\t\t\t\t\t\tRequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{\n\t\t\t\t\t\t\t\tNodeSelectorTerms: []corev1.NodeSelectorTerm{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tMatchExpressions: []corev1.NodeSelectorRequirement{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tKey:      \"kubernetes.io/os\",\n\t\t\t\t\t\t\t\t\t\t\t\tOperator: corev1.NodeSelectorOpIn,\n\t\t\t\t\t\t\t\t\t\t\t\tValues:   []string{\"linux\"},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tContainers: containers,\n\t\t\t\t\tInitContainers: []corev1.Container{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"install-config\",\n\t\t\t\t\t\t\tImage:   spec.FlannelImage,\n\t\t\t\t\t\t\tCommand: []string{\"cp\"},\n\t\t\t\t\t\t\tArgs:    []string{\"-f\", \"/etc/kube-flannel/cni-conf.json\", \"/etc/cni/net.d/10-flannel.conflist\"},\n\t\t\t\t\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t\t\t\t\t{Name: \"cni\", MountPath: \"/etc/cni/net.d\"},\n\t\t\t\t\t\t\t\t{Name: \"flannel-cfg\", MountPath: \"/etc/kube-flannel/\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tHostNetwork:        true,\n\t\t\t\t\tPriorityClassName:  \"system-node-critical\",\n\t\t\t\t\tServiceAccountName: \"flannel\",\n\t\t\t\t\tTolerations: []corev1.Toleration{\n\t\t\t\t\t\t{Effect: corev1.TaintEffectNoSchedule, Operator: corev1.TolerationOpExists},\n\t\t\t\t\t\t{Effect: corev1.TaintEffectNoExecute, Operator: corev1.TolerationOpExists},\n\t\t\t\t\t},\n\t\t\t\t\tVolumes: volumes,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/k8stemplates.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8stemplates contains templates for Kubernetes resources.\npackage k8stemplates\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync\"\n\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tk8sjson \"k8s.io/apimachinery/pkg/runtime/serializer/json\"\n)\n\nvar serializer = sync.OnceValue(func() *k8sjson.Serializer {\n\treturn k8sjson.NewSerializerWithOptions(\n\t\tk8sjson.DefaultMetaFactory, nil, nil,\n\t\tk8sjson.SerializerOptions{\n\t\t\tYaml:   true,\n\t\t\tPretty: true,\n\t\t\tStrict: true,\n\t\t},\n\t)\n})\n\n// Marshal serializes the given object into YAML format.\nfunc Marshal(obj runtime.Object) ([]byte, error) {\n\tvar buf bytes.Buffer\n\n\tif err := MarshalTo(obj, &buf); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\n// MarshalTo serializes the given object into YAML format and writes it to the provided buffer.\nfunc MarshalTo(obj runtime.Object, w io.Writer) error {\n\tif err := serializer().Encode(obj, w); err != nil {\n\t\treturn fmt.Errorf(\"error marshaling object %s: %w\", obj.GetObjectKind().GroupVersionKind().String(), err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/k8stemplates_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/k8stemplates\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestTemplates(t *testing.T) {\n\tt.Parallel()\n\n\tconst recordResults = false\n\n\tif recordResults {\n\t\tt.Log(\"recording test is enabled, failing the test\")\n\t\tt.Fail()\n\t}\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tobj  func() runtime.Object\n\t}{\n\t\t{\n\t\t\tname: \"apiserver-encryption-secretbox\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.APIServerEncryptionConfig(&secrets.KubernetesRootSpec{\n\t\t\t\t\tSecretboxEncryptionSecret: \"/FYehPLp5F8POCNQRVDEUb7Hmt+KkV44e+fQL4HMexs=\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"apiserver-encryption-aescbc\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.APIServerEncryptionConfig(&secrets.KubernetesRootSpec{\n\t\t\t\t\tAESCBCEncryptionSecret: \"/sFYehPLp5F8POCNQRVDEUb7Hmt+KkV44e+fQL4HMexs=\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-service-ipv4\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSService(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tDNSServiceIP: \"10.96.0.10\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-service-ipv6\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSService(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tDNSServiceIPv6: \"fd00::10\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-service-dual\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSService(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tDNSServiceIP:   \"10.96.0.10\",\n\t\t\t\t\tDNSServiceIPv6: \"fd00::10\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-service-account\",\n\t\t\tobj:  k8stemplates.CoreDNSServiceAccount,\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-cluster-role-binding\",\n\t\t\tobj:  k8stemplates.CoreDNSClusterRoleBinding,\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-cluster-role\",\n\t\t\tobj:  k8stemplates.CoreDNSClusterRole,\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-configmap-cluster-domain\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSConfigMap(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tClusterDomain: \"cluster.local\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-configmap-no-cluster-domain\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSConfigMap(&k8s.BootstrapManifestsConfigSpec{})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"coredns-deployment\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.CoreDNSDeployment(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tCoreDNSImage: \"coredns/coredns:1.9.3\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"kubelet-bootstrapping-token\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.KubeletBootstrapTokenSecret(&secrets.KubernetesRootSpec{\n\t\t\t\t\tBootstrapTokenID:     \"25p8ak\",\n\t\t\t\t\tBootstrapTokenSecret: \"vshybadgp2mhtvm7\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"csr-node-bootstrap\",\n\t\t\tobj:  k8stemplates.CSRNodeBootstrapTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"csr-approver-role-binding\",\n\t\t\tobj:  k8stemplates.CSRApproverRoleBindingTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"csr-renewal-role-binding\",\n\t\t\tobj:  k8stemplates.CSRRenewalRoleBindingTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"kubeconfig-in-cluster\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.KubeconfigInClusterTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tServer: \"https://localhost:6443\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"talos-nodes-rbac-cluster-role-binding\",\n\t\t\tobj:  k8stemplates.TalosNodesRBACClusterRoleBinding,\n\t\t},\n\t\t{\n\t\t\tname: \"talos-nodes-rbac-cluster-role\",\n\t\t\tobj:  k8stemplates.TalosNodesRBACClusterRole,\n\t\t},\n\t\t{\n\t\t\tname: \"kube-proxy-daemonset\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.KubeProxyDaemonSetTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tProxyImage: \"k8s.gcr.io/kube-proxy:v1.27.0\",\n\t\t\t\t\tProxyArgs:  []string{\"--proxy-mode=iptables\"},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"kube-proxy-service-account\",\n\t\t\tobj:  k8stemplates.KubeProxyServiceAccount,\n\t\t},\n\t\t{\n\t\t\tname: \"kube-proxy-cluster-role-binding\",\n\t\t\tobj:  k8stemplates.KubeProxyClusterRoleBinding,\n\t\t},\n\t\t{\n\t\t\tname: \"talos-service-account-crd\",\n\t\t\tobj:  k8stemplates.TalosServiceAccountCRDTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-cluster-role\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelClusterRoleTemplate(&k8s.BootstrapManifestsConfigSpec{})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-cluster-role-with-network-policies\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelClusterRoleTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: true,\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-cluster-role-binding\",\n\t\t\tobj:  k8stemplates.FlannelClusterRoleBindingTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-service-account\",\n\t\t\tobj:  k8stemplates.FlannelServiceAccountTemplate,\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-configmap-v4\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelConfigMapTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tPodCIDRs: []string{\"10.96.0.0/12\"},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-configmap-v6\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelConfigMapTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tPodCIDRs: []string{\"fd00::/112\"},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-configmap-dual\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelConfigMapTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tPodCIDRs: []string{\"10.96.0.0/12\", \"fd00::/112\"},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-daemonset\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelDaemonSetTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tFlannelImage:     \"quay.io/coreos/flannel:v0.14.0\",\n\t\t\t\t\tFlannelExtraArgs: []string{\"--foo=bar\"},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flannel-daemonset-with-network-policies\",\n\t\t\tobj: func() runtime.Object {\n\t\t\t\treturn k8stemplates.FlannelDaemonSetTemplate(&k8s.BootstrapManifestsConfigSpec{\n\t\t\t\t\tFlannelImage:                      \"quay.io/coreos/flannel:v0.14.0\",\n\t\t\t\t\tFlannelExtraArgs:                  []string{\"--foo=bar\"},\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: true,\n\t\t\t\t\tFlannelKubeNetworkPoliciesImage:   \"registry.k8s.io/networking/kube-network-policies:v0.7.0\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tobj := test.obj()\n\n\t\t\tout, err := k8stemplates.Marshal(obj)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgoldenPath := filepath.Join(\"testdata\", test.name+\".yaml\")\n\n\t\t\tif recordResults {\n\t\t\t\trequire.NoError(t, os.WriteFile(goldenPath, out, 0o644), \"failed to write golden file %s\", goldenPath)\n\t\t\t} else {\n\t\t\t\tgolden, err := os.ReadFile(goldenPath)\n\t\t\t\trequire.NoError(t, err, \"failed to read golden file %s\", goldenPath)\n\n\t\t\t\trequire.Equal(t, string(golden), string(out), \"output does not match golden file %s\", goldenPath)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/kube-proxy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\t\"slices\"\n\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\trbacv1 \"k8s.io/api/rbac/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubeProxyDaemonSetTemplate generates a DaemonSet for kube-proxy.\nfunc KubeProxyDaemonSetTemplate(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\treturn &appsv1.DaemonSet{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"DaemonSet\",\n\t\t\tAPIVersion: appsv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kube-proxy\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"tier\":    \"node\",\n\t\t\t\t\"k8s-app\": \"kube-proxy\",\n\t\t\t},\n\t\t},\n\t\tSpec: appsv1.DaemonSetSpec{\n\t\t\tSelector: &v1.LabelSelector{\n\t\t\t\tMatchLabels: map[string]string{\n\t\t\t\t\t\"tier\":    \"node\",\n\t\t\t\t\t\"k8s-app\": \"kube-proxy\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tUpdateStrategy: appsv1.DaemonSetUpdateStrategy{\n\t\t\t\tType: appsv1.RollingUpdateDaemonSetStrategyType,\n\t\t\t\tRollingUpdate: &appsv1.RollingUpdateDaemonSet{\n\t\t\t\t\tMaxUnavailable: new(intstr.FromInt(1)),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: v1.ObjectMeta{\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\"tier\":    \"node\",\n\t\t\t\t\t\t\"k8s-app\": \"kube-proxy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:  \"kube-proxy\",\n\t\t\t\t\t\t\tImage: spec.ProxyImage,\n\t\t\t\t\t\t\tCommand: slices.Concat(\n\t\t\t\t\t\t\t\t[]string{\"/usr/local/bin/kube-proxy\"},\n\t\t\t\t\t\t\t\tspec.ProxyArgs,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tEnv: []corev1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: \"NODE_NAME\",\n\t\t\t\t\t\t\t\t\tValueFrom: &corev1.EnvVarSource{\n\t\t\t\t\t\t\t\t\t\tFieldRef: &corev1.ObjectFieldSelector{\n\t\t\t\t\t\t\t\t\t\t\tFieldPath: \"spec.nodeName\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName: \"POD_IP\",\n\t\t\t\t\t\t\t\t\tValueFrom: &corev1.EnvVarSource{\n\t\t\t\t\t\t\t\t\t\tFieldRef: &corev1.ObjectFieldSelector{\n\t\t\t\t\t\t\t\t\t\t\tFieldPath: \"status.podIP\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\t\t\t\t\tPrivileged: new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:      \"lib-modules\",\n\t\t\t\t\t\t\t\t\tMountPath: \"/lib/modules\",\n\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:      \"ssl-certs-host\",\n\t\t\t\t\t\t\t\t\tMountPath: \"/etc/ssl/certs\",\n\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:      \"kubeconfig\",\n\t\t\t\t\t\t\t\t\tMountPath: \"/etc/kubernetes\",\n\t\t\t\t\t\t\t\t\tReadOnly:  true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tHostNetwork:        true,\n\t\t\t\t\tPriorityClassName:  \"system-cluster-critical\",\n\t\t\t\t\tServiceAccountName: \"kube-proxy\",\n\t\t\t\t\tTolerations: []corev1.Toleration{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEffect:   corev1.TaintEffectNoSchedule,\n\t\t\t\t\t\t\tOperator: corev1.TolerationOpExists,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEffect:   corev1.TaintEffectNoExecute,\n\t\t\t\t\t\t\tOperator: corev1.TolerationOpExists,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"lib-modules\",\n\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\tHostPath: &corev1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\t\tPath: \"/usr/lib/modules\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"ssl-certs-host\",\n\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\tHostPath: &corev1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\t\tPath: \"/etc/ssl/certs\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: \"kubeconfig\",\n\t\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\t\tConfigMap: &corev1.ConfigMapVolumeSource{\n\t\t\t\t\t\t\t\t\tLocalObjectReference: corev1.LocalObjectReference{\n\t\t\t\t\t\t\t\t\t\tName: \"kubeconfig-in-cluster\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\n// KubeProxyServiceAccount returns the ServiceAccount for kube-proxy.\nfunc KubeProxyServiceAccount() runtime.Object {\n\treturn &corev1.ServiceAccount{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ServiceAccount\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kube-proxy\",\n\t\t\tNamespace: \"kube-system\",\n\t\t},\n\t}\n}\n\n// KubeProxyClusterRoleBinding returns the ClusterRoleBinding for kube-proxy.\nfunc KubeProxyClusterRoleBinding() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"kube-proxy\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:      \"ServiceAccount\",\n\t\t\t\tName:      \"kube-proxy\",\n\t\t\t\tNamespace: \"kube-system\",\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:node-proxier\",\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/kubeconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\tcorev1 \"k8s.io/api/core/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubeconfigInClusterTemplate generates a ConfigMap containing the kubeconfig for in-cluster access.\nfunc KubeconfigInClusterTemplate(spec *k8s.BootstrapManifestsConfigSpec) runtime.Object {\n\tcfg := clientcmdapi.Config{\n\t\tAPIVersion: \"v1\",\n\t\tClusters: map[string]*clientcmdapi.Cluster{\n\t\t\t\"local\": {\n\t\t\t\tServer:               spec.Server,\n\t\t\t\tCertificateAuthority: \"/var/run/secrets/kubernetes.io/serviceaccount/ca.crt\",\n\t\t\t},\n\t\t},\n\t\tAuthInfos: map[string]*clientcmdapi.AuthInfo{\n\t\t\t\"service-account\": {\n\t\t\t\tTokenFile: \"/var/run/secrets/kubernetes.io/serviceaccount/token\",\n\t\t\t},\n\t\t},\n\t\tContexts: map[string]*clientcmdapi.Context{\n\t\t\t\"local\": {\n\t\t\t\tCluster:  \"local\",\n\t\t\t\tAuthInfo: \"service-account\",\n\t\t\t},\n\t\t},\n\t\tCurrentContext: \"local\",\n\t}\n\n\tkubeconfig, err := clientcmd.Write(cfg)\n\tif err != nil {\n\t\tpanic(err) // This should never happen, as the config is valid.\n\t}\n\n\treturn &corev1.ConfigMap{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ConfigMap\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"kubeconfig-in-cluster\",\n\t\t\tNamespace: \"kube-system\",\n\t\t},\n\t\tData: map[string]string{\n\t\t\t\"kubeconfig\": string(kubeconfig),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\tcorev1 \"k8s.io/api/core/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// KubeletBootstrapTokenSecret returns the kubelet bootstrap token secret.\nfunc KubeletBootstrapTokenSecret(secrets *secrets.KubernetesRootSpec) runtime.Object {\n\treturn &corev1.Secret{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"Secret\",\n\t\t\tAPIVersion: corev1.SchemeGroupVersion.Version,\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName:      \"bootstrap-token-\" + secrets.BootstrapTokenID,\n\t\t\tNamespace: \"kube-system\",\n\t\t},\n\t\tType: corev1.SecretType(\"bootstrap.kubernetes.io/token\"),\n\t\tStringData: map[string]string{\n\t\t\t\"token-id\":                       secrets.BootstrapTokenID,\n\t\t\t\"token-secret\":                   secrets.BootstrapTokenSecret,\n\t\t\t\"usage-bootstrap-authentication\": \"true\",\n\t\t\t\"auth-extra-groups\":              \"system:bootstrappers:nodes\",\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/talos.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8stemplates\n\nimport (\n\trbacv1 \"k8s.io/api/rbac/v1\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n)\n\n// TalosNodesRBACClusterRoleBinding is the template of the RBAC rules which allow\n// Talos to discover the nodes in the Kubernetes cluster and assign\n// endpoints for the internal discovery.\nfunc TalosNodesRBACClusterRoleBinding() runtime.Object {\n\treturn &rbacv1.ClusterRoleBinding{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRoleBinding\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system:talos-nodes\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"kubernetes.io/bootstrapping\": \"rbac-defaults\",\n\t\t\t},\n\t\t\tAnnotations: map[string]string{\n\t\t\t\t\"rbac.authorization.kubernetes.io/autoupdate\": \"true\",\n\t\t\t},\n\t\t},\n\t\tRoleRef: rbacv1.RoleRef{\n\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\tKind:     \"ClusterRole\",\n\t\t\tName:     \"system:talos-nodes\",\n\t\t},\n\t\tSubjects: []rbacv1.Subject{\n\t\t\t{\n\t\t\t\tKind:     \"Group\",\n\t\t\t\tName:     \"system:nodes\",\n\t\t\t\tAPIGroup: rbacv1.GroupName,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// TalosNodesRBACClusterRole is the template of the RBAC rules which allow\n// Talos to discover the nodes in the Kubernetes cluster and assign\n// endpoints for the internal discovery.\nfunc TalosNodesRBACClusterRole() runtime.Object {\n\treturn &rbacv1.ClusterRole{\n\t\tTypeMeta: v1.TypeMeta{\n\t\t\tKind:       \"ClusterRole\",\n\t\t\tAPIVersion: rbacv1.SchemeGroupVersion.String(),\n\t\t},\n\t\tObjectMeta: v1.ObjectMeta{\n\t\t\tName: \"system:talos-nodes\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"kubernetes.io/bootstrapping\": \"rbac-defaults\",\n\t\t\t},\n\t\t},\n\t\tRules: []rbacv1.PolicyRule{\n\t\t\t{\n\t\t\t\tAPIGroups: []string{\"discovery.k8s.io\"},\n\t\t\t\tResources: []string{\"endpointslices\"},\n\t\t\t\tVerbs:     []string{\"get\", \"list\", \"watch\"},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/apiserver-encryption-aescbc.yaml",
    "content": "apiVersion: v1\nkind: EncryptionConfig\nresources:\n- providers:\n  - aescbc:\n      keys:\n      - name: key1\n        secret: /sFYehPLp5F8POCNQRVDEUb7Hmt+KkV44e+fQL4HMexs=\n  - identity: {}\n  resources:\n  - secrets\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/apiserver-encryption-secretbox.yaml",
    "content": "apiVersion: v1\nkind: EncryptionConfig\nresources:\n- providers:\n  - secretbox:\n      keys:\n      - name: key2\n        secret: /FYehPLp5F8POCNQRVDEUb7Hmt+KkV44e+fQL4HMexs=\n  - identity: {}\n  resources:\n  - secrets\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-cluster-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  annotations:\n    rbac.authorization.kubernetes.io/autoupdate: \"true\"\n  labels:\n    kubernetes.io/bootstrapping: rbac-defaults\n  name: system:coredns\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:coredns\nsubjects:\n- kind: ServiceAccount\n  name: coredns\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-cluster-role.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    kubernetes.io/bootstrapping: rbac-defaults\n  name: system:coredns\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - endpoints\n  - services\n  - pods\n  - namespaces\n  verbs:\n  - list\n  - watch\n- apiGroups:\n  - discovery.k8s.io\n  resources:\n  - endpointslices\n  verbs:\n  - list\n  - watch\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-configmap-cluster-domain.yaml",
    "content": "apiVersion: v1\ndata:\n  Corefile: |\n    .:53 {\n        errors\n        health {\n            lameduck 5s\n        }\n        ready\n        log . {\n            class error\n        }\n        prometheus :9153\n\n        kubernetes cluster.local in-addr.arpa ip6.arpa {\n            pods insecure\n            fallthrough in-addr.arpa ip6.arpa\n            ttl 30\n        }\n        forward . /etc/resolv.conf {\n           max_concurrent 1000\n        }\n        cache 30 {\n           disable success cluster.local\n           disable denial cluster.local\n        }\n        loop\n        reload\n        loadbalance\n    }\nkind: ConfigMap\nmetadata:\n  name: coredns\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-configmap-no-cluster-domain.yaml",
    "content": "apiVersion: v1\ndata:\n  Corefile: |\n    .:53 {\n        errors\n        health {\n            lameduck 5s\n        }\n        ready\n        log . {\n            class error\n        }\n        prometheus :9153\n\n        kubernetes  in-addr.arpa ip6.arpa {\n            pods insecure\n            fallthrough in-addr.arpa ip6.arpa\n            ttl 30\n        }\n        forward . /etc/resolv.conf {\n           max_concurrent 1000\n        }\n        cache 30\n        loop\n        reload\n        loadbalance\n    }\nkind: ConfigMap\nmetadata:\n  name: coredns\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    k8s-app: kube-dns\n    kubernetes.io/name: CoreDNS\n  name: coredns\n  namespace: kube-system\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      k8s-app: kube-dns\n  strategy:\n    rollingUpdate:\n      maxUnavailable: 1\n    type: RollingUpdate\n  template:\n    metadata:\n      labels:\n        k8s-app: kube-dns\n    spec:\n      affinity:\n        podAntiAffinity:\n          preferredDuringSchedulingIgnoredDuringExecution:\n          - podAffinityTerm:\n              labelSelector:\n                matchExpressions:\n                - key: k8s-app\n                  operator: In\n                  values:\n                  - kube-dns\n              topologyKey: kubernetes.io/hostname\n            weight: 100\n      containers:\n      - args:\n        - -conf\n        - /etc/coredns/Corefile\n        env:\n        - name: GOMEMLIMIT\n          value: 161MiB\n        image: coredns/coredns:1.9.3\n        imagePullPolicy: IfNotPresent\n        livenessProbe:\n          failureThreshold: 5\n          httpGet:\n            path: /health\n            port: 8080\n            scheme: HTTP\n          initialDelaySeconds: 60\n          successThreshold: 1\n          timeoutSeconds: 5\n        name: coredns\n        ports:\n        - containerPort: 53\n          name: dns\n          protocol: UDP\n        - containerPort: 53\n          name: dns-tcp\n          protocol: TCP\n        - containerPort: 9153\n          name: metrics\n          protocol: TCP\n        readinessProbe:\n          httpGet:\n            path: /ready\n            port: 8181\n            scheme: HTTP\n        resources:\n          limits:\n            memory: 170Mi\n          requests:\n            cpu: 100m\n            memory: 70Mi\n        securityContext:\n          allowPrivilegeEscalation: false\n          capabilities:\n            add:\n            - NET_BIND_SERVICE\n            drop:\n            - ALL\n          readOnlyRootFilesystem: true\n        volumeMounts:\n        - mountPath: /etc/coredns\n          name: config-volume\n          readOnly: true\n      dnsPolicy: Default\n      nodeSelector:\n        kubernetes.io/os: linux\n      priorityClassName: system-cluster-critical\n      serviceAccountName: coredns\n      tolerations:\n      - effect: NoSchedule\n        key: node-role.kubernetes.io/control-plane\n        operator: Exists\n      - effect: NoSchedule\n        key: node.cloudprovider.kubernetes.io/uninitialized\n        operator: Exists\n      volumes:\n      - configMap:\n          items:\n          - key: Corefile\n            path: Corefile\n          name: coredns\n        name: config-volume\nstatus: {}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-service-account.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: coredns\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-service-dual.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    prometheus.io/port: \"9153\"\n    prometheus.io/scrape: \"true\"\n  labels:\n    k8s-app: kube-dns\n    kubernetes.io/cluster-service: \"true\"\n    kubernetes.io/name: CoreDNS\n  name: kube-dns\n  namespace: kube-system\nspec:\n  clusterIP: 10.96.0.10\n  clusterIPs:\n  - 10.96.0.10\n  - fd00::10\n  ipFamilies:\n  - IPv4\n  - IPv6\n  ipFamilyPolicy: RequireDualStack\n  ports:\n  - name: dns\n    port: 53\n    protocol: UDP\n    targetPort: 53\n  - name: dns-tcp\n    port: 53\n    protocol: TCP\n    targetPort: 53\n  - name: metrics\n    port: 9153\n    protocol: TCP\n    targetPort: 9153\n  selector:\n    k8s-app: kube-dns\nstatus:\n  loadBalancer: {}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-service-ipv4.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    prometheus.io/port: \"9153\"\n    prometheus.io/scrape: \"true\"\n  labels:\n    k8s-app: kube-dns\n    kubernetes.io/cluster-service: \"true\"\n    kubernetes.io/name: CoreDNS\n  name: kube-dns\n  namespace: kube-system\nspec:\n  clusterIP: 10.96.0.10\n  clusterIPs:\n  - 10.96.0.10\n  ipFamilies:\n  - IPv4\n  ipFamilyPolicy: SingleStack\n  ports:\n  - name: dns\n    port: 53\n    protocol: UDP\n    targetPort: 53\n  - name: dns-tcp\n    port: 53\n    protocol: TCP\n    targetPort: 53\n  - name: metrics\n    port: 9153\n    protocol: TCP\n    targetPort: 9153\n  selector:\n    k8s-app: kube-dns\nstatus:\n  loadBalancer: {}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/coredns-service-ipv6.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  annotations:\n    prometheus.io/port: \"9153\"\n    prometheus.io/scrape: \"true\"\n  labels:\n    k8s-app: kube-dns\n    kubernetes.io/cluster-service: \"true\"\n    kubernetes.io/name: CoreDNS\n  name: kube-dns\n  namespace: kube-system\nspec:\n  clusterIP: fd00::10\n  clusterIPs:\n  - fd00::10\n  ipFamilies:\n  - IPv6\n  ipFamilyPolicy: SingleStack\n  ports:\n  - name: dns\n    port: 53\n    protocol: UDP\n    targetPort: 53\n  - name: dns-tcp\n    port: 53\n    protocol: TCP\n    targetPort: 53\n  - name: metrics\n    port: 9153\n    protocol: TCP\n    targetPort: 9153\n  selector:\n    k8s-app: kube-dns\nstatus:\n  loadBalancer: {}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/csr-approver-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: system-bootstrap-approve-node-client-csr\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:certificates.k8s.io:certificatesigningrequests:nodeclient\nsubjects:\n- apiGroup: rbac.authorization.k8s.io\n  kind: Group\n  name: system:bootstrappers:nodes\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/csr-node-bootstrap.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: system-bootstrap-node-bootstrapper\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:node-bootstrapper\nsubjects:\n- apiGroup: rbac.authorization.k8s.io\n  kind: Group\n  name: system:bootstrappers:nodes\n- apiGroup: rbac.authorization.k8s.io\n  kind: Group\n  name: system:nodes\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/csr-renewal-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: system-bootstrap-node-renewal\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient\nsubjects:\n- apiGroup: rbac.authorization.k8s.io\n  kind: Group\n  name: system:nodes\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-cluster-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    k8s-app: flannel\n  name: flannel\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: flannel\nsubjects:\n- kind: ServiceAccount\n  name: flannel\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-cluster-role-with-network-policies.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    k8s-app: flannel\n  name: flannel\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - pods\n  - nodes\n  - namespaces\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - nodes/status\n  verbs:\n  - patch\n- apiGroups:\n  - networking.k8s.io\n  resources:\n  - networkpolicies\n  verbs:\n  - list\n  - watch\n- apiGroups:\n  - policy.networking.k8s.io\n  resources:\n  - adminnetworkpolicies\n  - baselineadminnetworkpolicies\n  verbs:\n  - list\n  - watch\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-cluster-role.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    k8s-app: flannel\n  name: flannel\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - pods\n  - nodes\n  - namespaces\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - nodes/status\n  verbs:\n  - patch\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-configmap-dual.yaml",
    "content": "apiVersion: v1\ndata:\n  cni-conf.json: |-\n    {\n      \"name\": \"cbr0\",\n      \"cniVersion\": \"1.0.0\",\n      \"plugins\": [\n        {\n          \"type\": \"flannel\",\n          \"delegate\": {\n            \"hairpinMode\": true,\n            \"isDefaultGateway\": true\n          }\n        },\n        {\n          \"type\": \"portmap\",\n          \"capabilities\": {\n            \"portMappings\": true\n          }\n        }\n      ]\n    }\n  net-conf.json: |-\n    {\n      \"Network\": \"10.96.0.0/12\",\n      \"IPv6Network\": \"fd00::/112\",\n      \"EnableIPv6\": true,\n      \"Backend\": {\n        \"Type\": \"vxlan\",\n        \"Port\": 4789\n      }\n    }\nkind: ConfigMap\nmetadata:\n  labels:\n    k8s-app: flannel\n    tier: node\n  name: kube-flannel-cfg\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-configmap-v4.yaml",
    "content": "apiVersion: v1\ndata:\n  cni-conf.json: |-\n    {\n      \"name\": \"cbr0\",\n      \"cniVersion\": \"1.0.0\",\n      \"plugins\": [\n        {\n          \"type\": \"flannel\",\n          \"delegate\": {\n            \"hairpinMode\": true,\n            \"isDefaultGateway\": true\n          }\n        },\n        {\n          \"type\": \"portmap\",\n          \"capabilities\": {\n            \"portMappings\": true\n          }\n        }\n      ]\n    }\n  net-conf.json: |-\n    {\n      \"Network\": \"10.96.0.0/12\",\n      \"Backend\": {\n        \"Type\": \"vxlan\",\n        \"Port\": 4789\n      }\n    }\nkind: ConfigMap\nmetadata:\n  labels:\n    k8s-app: flannel\n    tier: node\n  name: kube-flannel-cfg\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-configmap-v6.yaml",
    "content": "apiVersion: v1\ndata:\n  cni-conf.json: |-\n    {\n      \"name\": \"cbr0\",\n      \"cniVersion\": \"1.0.0\",\n      \"plugins\": [\n        {\n          \"type\": \"flannel\",\n          \"delegate\": {\n            \"hairpinMode\": true,\n            \"isDefaultGateway\": true\n          }\n        },\n        {\n          \"type\": \"portmap\",\n          \"capabilities\": {\n            \"portMappings\": true\n          }\n        }\n      ]\n    }\n  net-conf.json: |-\n    {\n      \"IPv6Network\": \"fd00::/112\",\n      \"EnableIPv6\": true,\n      \"EnableIPv4\": false,\n      \"Backend\": {\n        \"Type\": \"vxlan\",\n        \"Port\": 4789\n      }\n    }\nkind: ConfigMap\nmetadata:\n  labels:\n    k8s-app: flannel\n    tier: node\n  name: kube-flannel-cfg\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-daemonset-with-network-policies.yaml",
    "content": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    k8s-app: flannel\n    tier: node\n  name: kube-flannel\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      k8s-app: flannel\n      tier: node\n  template:\n    metadata:\n      labels:\n        k8s-app: flannel\n        tier: node\n    spec:\n      affinity:\n        nodeAffinity:\n          requiredDuringSchedulingIgnoredDuringExecution:\n            nodeSelectorTerms:\n            - matchExpressions:\n              - key: kubernetes.io/os\n                operator: In\n                values:\n                - linux\n      containers:\n      - args:\n        - --ip-masq\n        - --kube-subnet-mgr\n        - --foo=bar\n        command:\n        - /opt/bin/flanneld\n        env:\n        - name: POD_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.name\n        - name: POD_NAMESPACE\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.namespace\n        - name: EVENT_QUEUE_DEPTH\n          value: \"5000\"\n        - name: CONT_WHEN_CACHE_NOT_READY\n          value: \"false\"\n        image: quay.io/coreos/flannel:v0.14.0\n        name: kube-flannel\n        resources:\n          requests:\n            cpu: 100m\n            memory: 50Mi\n        securityContext:\n          capabilities:\n            add:\n            - NET_ADMIN\n            - NET_RAW\n          privileged: false\n        volumeMounts:\n        - mountPath: /run/flannel\n          name: run\n        - mountPath: /etc/kube-flannel/\n          name: flannel-cfg\n      - command:\n        - /bin/netpol\n        - --hostname-override=$(MY_NODE_NAME)\n        - --v=2\n        env:\n        - name: MY_NODE_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: spec.nodeName\n        image: registry.k8s.io/networking/kube-network-policies:v0.7.0\n        name: kube-network-policies\n        resources:\n          requests:\n            cpu: 100m\n            memory: 50Mi\n        securityContext:\n          capabilities:\n            add:\n            - NET_ADMIN\n          privileged: true\n        volumeMounts:\n        - mountPath: /lib/modules\n          name: lib-modules\n          readOnly: true\n      hostNetwork: true\n      initContainers:\n      - args:\n        - -f\n        - /etc/kube-flannel/cni-conf.json\n        - /etc/cni/net.d/10-flannel.conflist\n        command:\n        - cp\n        image: quay.io/coreos/flannel:v0.14.0\n        name: install-config\n        resources: {}\n        volumeMounts:\n        - mountPath: /etc/cni/net.d\n          name: cni\n        - mountPath: /etc/kube-flannel/\n          name: flannel-cfg\n      priorityClassName: system-node-critical\n      serviceAccountName: flannel\n      tolerations:\n      - effect: NoSchedule\n        operator: Exists\n      - effect: NoExecute\n        operator: Exists\n      volumes:\n      - hostPath:\n          path: /run/flannel\n        name: run\n      - hostPath:\n          path: /etc/cni/net.d\n        name: cni\n      - configMap:\n          name: kube-flannel-cfg\n        name: flannel-cfg\n      - hostPath:\n          path: /usr/lib/modules\n        name: lib-modules\n  updateStrategy: {}\nstatus:\n  currentNumberScheduled: 0\n  desiredNumberScheduled: 0\n  numberMisscheduled: 0\n  numberReady: 0\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-daemonset.yaml",
    "content": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    k8s-app: flannel\n    tier: node\n  name: kube-flannel\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      k8s-app: flannel\n      tier: node\n  template:\n    metadata:\n      labels:\n        k8s-app: flannel\n        tier: node\n    spec:\n      affinity:\n        nodeAffinity:\n          requiredDuringSchedulingIgnoredDuringExecution:\n            nodeSelectorTerms:\n            - matchExpressions:\n              - key: kubernetes.io/os\n                operator: In\n                values:\n                - linux\n      containers:\n      - args:\n        - --ip-masq\n        - --kube-subnet-mgr\n        - --foo=bar\n        command:\n        - /opt/bin/flanneld\n        env:\n        - name: POD_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.name\n        - name: POD_NAMESPACE\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.namespace\n        - name: EVENT_QUEUE_DEPTH\n          value: \"5000\"\n        - name: CONT_WHEN_CACHE_NOT_READY\n          value: \"false\"\n        image: quay.io/coreos/flannel:v0.14.0\n        name: kube-flannel\n        resources:\n          requests:\n            cpu: 100m\n            memory: 50Mi\n        securityContext:\n          capabilities:\n            add:\n            - NET_ADMIN\n            - NET_RAW\n          privileged: false\n        volumeMounts:\n        - mountPath: /run/flannel\n          name: run\n        - mountPath: /etc/kube-flannel/\n          name: flannel-cfg\n      hostNetwork: true\n      initContainers:\n      - args:\n        - -f\n        - /etc/kube-flannel/cni-conf.json\n        - /etc/cni/net.d/10-flannel.conflist\n        command:\n        - cp\n        image: quay.io/coreos/flannel:v0.14.0\n        name: install-config\n        resources: {}\n        volumeMounts:\n        - mountPath: /etc/cni/net.d\n          name: cni\n        - mountPath: /etc/kube-flannel/\n          name: flannel-cfg\n      priorityClassName: system-node-critical\n      serviceAccountName: flannel\n      tolerations:\n      - effect: NoSchedule\n        operator: Exists\n      - effect: NoExecute\n        operator: Exists\n      volumes:\n      - hostPath:\n          path: /run/flannel\n        name: run\n      - hostPath:\n          path: /etc/cni/net.d\n        name: cni\n      - configMap:\n          name: kube-flannel-cfg\n        name: flannel-cfg\n  updateStrategy: {}\nstatus:\n  currentNumberScheduled: 0\n  desiredNumberScheduled: 0\n  numberMisscheduled: 0\n  numberReady: 0\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/flannel-service-account.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  labels:\n    k8s-app: flannel\n  name: flannel\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/kube-proxy-cluster-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: kube-proxy\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:node-proxier\nsubjects:\n- kind: ServiceAccount\n  name: kube-proxy\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/kube-proxy-daemonset.yaml",
    "content": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    k8s-app: kube-proxy\n    tier: node\n  name: kube-proxy\n  namespace: kube-system\nspec:\n  selector:\n    matchLabels:\n      k8s-app: kube-proxy\n      tier: node\n  template:\n    metadata:\n      labels:\n        k8s-app: kube-proxy\n        tier: node\n    spec:\n      containers:\n      - command:\n        - /usr/local/bin/kube-proxy\n        - --proxy-mode=iptables\n        env:\n        - name: NODE_NAME\n          valueFrom:\n            fieldRef:\n              fieldPath: spec.nodeName\n        - name: POD_IP\n          valueFrom:\n            fieldRef:\n              fieldPath: status.podIP\n        image: k8s.gcr.io/kube-proxy:v1.27.0\n        name: kube-proxy\n        resources: {}\n        securityContext:\n          privileged: true\n        volumeMounts:\n        - mountPath: /lib/modules\n          name: lib-modules\n          readOnly: true\n        - mountPath: /etc/ssl/certs\n          name: ssl-certs-host\n          readOnly: true\n        - mountPath: /etc/kubernetes\n          name: kubeconfig\n          readOnly: true\n      hostNetwork: true\n      priorityClassName: system-cluster-critical\n      serviceAccountName: kube-proxy\n      tolerations:\n      - effect: NoSchedule\n        operator: Exists\n      - effect: NoExecute\n        operator: Exists\n      volumes:\n      - hostPath:\n          path: /usr/lib/modules\n        name: lib-modules\n      - hostPath:\n          path: /etc/ssl/certs\n        name: ssl-certs-host\n      - configMap:\n          name: kubeconfig-in-cluster\n        name: kubeconfig\n  updateStrategy:\n    rollingUpdate:\n      maxUnavailable: 1\n    type: RollingUpdate\nstatus:\n  currentNumberScheduled: 0\n  desiredNumberScheduled: 0\n  numberMisscheduled: 0\n  numberReady: 0\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/kube-proxy-service-account.yaml",
    "content": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: kube-proxy\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/kubeconfig-in-cluster.yaml",
    "content": "apiVersion: v1\ndata:\n  kubeconfig: |\n    apiVersion: v1\n    clusters:\n    - cluster:\n        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt\n        server: https://localhost:6443\n      name: local\n    contexts:\n    - context:\n        cluster: local\n        user: service-account\n      name: local\n    current-context: local\n    kind: Config\n    users:\n    - name: service-account\n      user:\n        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token\nkind: ConfigMap\nmetadata:\n  name: kubeconfig-in-cluster\n  namespace: kube-system\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/kubelet-bootstrapping-token.yaml",
    "content": "apiVersion: v1\nkind: Secret\nmetadata:\n  name: bootstrap-token-25p8ak\n  namespace: kube-system\nstringData:\n  auth-extra-groups: system:bootstrappers:nodes\n  token-id: 25p8ak\n  token-secret: vshybadgp2mhtvm7\n  usage-bootstrap-authentication: \"true\"\ntype: bootstrap.kubernetes.io/token\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/talos-nodes-rbac-cluster-role-binding.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  annotations:\n    rbac.authorization.kubernetes.io/autoupdate: \"true\"\n  labels:\n    kubernetes.io/bootstrapping: rbac-defaults\n  name: system:talos-nodes\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: system:talos-nodes\nsubjects:\n- apiGroup: rbac.authorization.k8s.io\n  kind: Group\n  name: system:nodes\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/talos-nodes-rbac-cluster-role.yaml",
    "content": "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  labels:\n    kubernetes.io/bootstrapping: rbac-defaults\n  name: system:talos-nodes\nrules:\n- apiGroups:\n  - discovery.k8s.io\n  resources:\n  - endpointslices\n  verbs:\n  - get\n  - list\n  - watch\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/k8stemplates/testdata/talos-service-account-crd.yaml",
    "content": "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  name: serviceaccounts.talos.dev\nspec:\n  conversion:\n    strategy: None\n  group: talos.dev\n  names:\n    kind: ServiceAccount\n    listKind: ServiceAccountList\n    plural: serviceaccounts\n    shortNames:\n    - tsa\n    singular: serviceaccount\n  scope: Namespaced\n  versions:\n  - name: v1alpha1\n    schema:\n      openAPIV3Schema:\n        properties:\n          spec:\n            properties:\n              roles:\n                items:\n                  type: string\n                type: array\n            type: object\n          status:\n            properties:\n              failureReason:\n                type: string\n            type: object\n        type: object\n    served: true\n    storage: true\nstatus:\n  acceptedNames:\n    kind: \"\"\n    plural: \"\"\n  conditions: null\n  storedVersions: null\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/nodename/nodename.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package nodename provides utility functions to generate nodenames.\npackage nodename\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// FromHostname converts a hostname to Kubernetes Node name.\n//\n// UNIX hostname has almost no restrictions, but Kubernetes Node name has\n// to be RFC 1123 compliant. This function converts a hostname to a valid\n// Kubernetes Node name (if possible).\n//\n// The allowed format is:\n//\n//\t[a-z0-9]([-a-z0-9]*[a-z0-9])?\n//\n//nolint:gocyclo\nfunc FromHostname(hostname string) (string, error) {\n\tnodename := strings.Map(func(r rune) rune {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\t// allow lowercase\n\t\t\treturn r\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\t// lowercase uppercase letters\n\t\t\treturn r - 'A' + 'a'\n\t\tcase r >= '0' && r <= '9':\n\t\t\t// allow digits\n\t\t\treturn r\n\t\tcase r == '-' || r == '_':\n\t\t\t// allow dash, convert underscore to dash\n\t\t\treturn '-'\n\t\tcase r == '.':\n\t\t\t// allow dot\n\t\t\treturn '.'\n\t\tdefault:\n\t\t\t// drop anything else\n\t\t\treturn -1\n\t\t}\n\t}, hostname)\n\n\t// now drop any dashes/dots at the beginning or end\n\tnodename = strings.Trim(nodename, \"-.\")\n\n\tif len(nodename) == 0 {\n\t\treturn \"\", fmt.Errorf(\"could not convert hostname %q to a valid Kubernetes Node name\", hostname)\n\t}\n\n\treturn nodename, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/nodename/nodename_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nodename_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/nodename\"\n)\n\nfunc TestFromHostname(t *testing.T) {\n\tfor _, test := range []struct {\n\t\thostname string\n\n\t\texpectedNodeName string\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\thostname: \"foo\",\n\n\t\t\texpectedNodeName: \"foo\",\n\t\t},\n\t\t{\n\t\t\thostname: \"foo_ია\",\n\n\t\t\texpectedNodeName: \"foo\",\n\t\t},\n\t\t{\n\t\t\thostname: \"Node1\",\n\n\t\t\texpectedNodeName: \"node1\",\n\t\t},\n\t\t{\n\t\t\thostname: \"MY_test_server_\",\n\n\t\t\texpectedNodeName: \"my-test-server\",\n\t\t},\n\t\t{\n\t\t\thostname: \"123\",\n\n\t\t\texpectedNodeName: \"123\",\n\t\t},\n\t\t{\n\t\t\thostname: \"-my-server-\",\n\n\t\t\texpectedNodeName: \"my-server\",\n\t\t},\n\t\t{\n\t\t\thostname: \"კომპიუტერი\",\n\n\t\t\texpectedError: \"could not convert hostname \\\"კომპიუტერი\\\" to a valid Kubernetes Node name\",\n\t\t},\n\t\t{\n\t\t\thostname: \"foo.bar.tld.\",\n\n\t\t\texpectedNodeName: \"foo.bar.tld\",\n\t\t},\n\t} {\n\t\tt.Run(test.hostname, func(t *testing.T) {\n\t\t\tnodename, err := nodename.FromHostname(test.hostname)\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\trequire.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, test.expectedNodeName, nodename)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/internal/nodewatch/nodewatch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package nodewatch implements Kubernetes node watcher.\npackage nodewatch\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/client-go/informers\"\n\tinformersv1 \"k8s.io/client-go/informers/core/v1\"\n\t\"k8s.io/client-go/tools/cache\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// NodeWatcher defines a NodeWatcher-based node watcher.\ntype NodeWatcher struct {\n\tclient *kubernetes.Client\n\n\tnodename string\n\tnodes    informersv1.NodeInformer\n}\n\n// NewNodeWatcher creates new Kubernetes node watcher.\nfunc NewNodeWatcher(client *kubernetes.Client, nodename string) *NodeWatcher {\n\treturn &NodeWatcher{\n\t\tnodename: nodename,\n\t\tclient:   client,\n\t}\n}\n\n// Nodename returns the watched nodename.\nfunc (r *NodeWatcher) Nodename() string {\n\treturn r.nodename\n}\n\n// Get returns the Node resource.\nfunc (r *NodeWatcher) Get() (*corev1.Node, error) {\n\treturn r.nodes.Lister().Get(r.nodename)\n}\n\n// Watch starts watching Node state and notifies on updates via notify channel.\nfunc (r *NodeWatcher) Watch(ctx context.Context, logger *zap.Logger) (<-chan struct{}, <-chan error, func(), error) {\n\tlogger.Debug(\"starting node watcher\", zap.String(\"nodename\", r.nodename))\n\n\tinformerFactory := informers.NewSharedInformerFactoryWithOptions(\n\t\tr.client.Clientset,\n\t\tconstants.KubernetesInformerDefaultResyncPeriod,\n\t\tinformers.WithTweakListOptions(\n\t\t\tfunc(opts *metav1.ListOptions) {\n\t\t\t\topts.FieldSelector = fields.OneTermEqualSelector(metav1.ObjectNameField, r.nodename).String()\n\t\t\t},\n\t\t),\n\t)\n\n\tnotifyCh := make(chan struct{}, 1)\n\twatchErrCh := make(chan error, 1)\n\n\tnotify := func(_ any) {\n\t\tselect {\n\t\tcase notifyCh <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n\n\tr.nodes = informerFactory.Core().V1().Nodes()\n\n\tif err := r.nodes.Informer().SetWatchErrorHandler(func(r *cache.Reflector, err error) {\n\t\tselect {\n\t\tcase watchErrCh <- err:\n\t\tdefault:\n\t\t}\n\t}); err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"failed to set watch error handler: %w\", err)\n\t}\n\n\tif _, err := r.nodes.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc:    notify,\n\t\tDeleteFunc: notify,\n\t\tUpdateFunc: func(_, _ any) { notify(nil) },\n\t}); err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"failed to add event handler: %w\", err)\n\t}\n\n\tinformerFactory.Start(ctx.Done())\n\n\tgo func() {\n\t\tlogger.Debug(\"waiting for node cache sync\")\n\n\t\tresult := informerFactory.WaitForCacheSync(ctx.Done())\n\n\t\tvar synced bool\n\n\t\t// result should contain a single entry\n\t\tfor _, v := range result {\n\t\t\tsynced = v\n\t\t}\n\n\t\tlogger.Debug(\"node cache sync done\", zap.Bool(\"synced\", synced))\n\n\t\tselect {\n\t\tcase notifyCh <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}()\n\n\treturn notifyCh, watchErrCh, informerFactory.Shutdown, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides controllers which manage Kubernetes resources.\npackage k8s\n\nimport (\n\tutilruntime \"k8s.io/apimachinery/pkg/util/runtime\"\n)\n\n// CloudProviderExternal is a constant for the external cloud provider.\nconst CloudProviderExternal = \"external\"\n\nfunc init() {\n\t// ugly hack, but it doesn't look like there's better API\n\t// cut out error handler which logs error to standard logger\n\tutilruntime.ErrorHandlers = utilruntime.ErrorHandlers[len(utilruntime.ErrorHandlers)-1:] //nolint:reassign\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubeletConfigController renders kubelet configuration based on machine config.\ntype KubeletConfigController = transform.Controller[*config.MachineConfig, *k8s.KubeletConfig]\n\n// NewKubeletConfigController instanciates the config controller.\nfunc NewKubeletConfigController() *KubeletConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.KubeletConfig]{\n\t\t\tName: \"k8s.KubeletConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*k8s.KubeletConfig] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*k8s.KubeletConfig]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {\n\t\t\t\t\treturn optional.None[*k8s.KubeletConfig]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *k8s.KubeletConfig) error {\n\t\t\t\tstaticPodURL, err := safe.ReaderGetByID[*k8s.StaticPodServerStatus](ctx, r, k8s.StaticPodServerStatusResourceID)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn xerrors.NewTaggedf[transform.SkipReconcileTag](\"static pod server status resource not found; not creating kubelet config\")\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tkubeletConfig := res.TypedSpec()\n\t\t\t\tcfgProvider := cfg.Config()\n\n\t\t\t\tkubeletConfig.Image = cfgProvider.Machine().Kubelet().Image()\n\n\t\t\t\tkubeletConfig.ClusterDNS = cfgProvider.Machine().Kubelet().ClusterDNS()\n\n\t\t\t\tif len(kubeletConfig.ClusterDNS) == 0 {\n\t\t\t\t\taddrs, err := cfgProvider.Cluster().Network().DNSServiceIPs()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error building DNS service IPs: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tkubeletConfig.ClusterDNS = xslices.Map(addrs, netip.Addr.String)\n\t\t\t\t}\n\n\t\t\t\textraArgs := make(map[string]k8s.ArgValues, len(cfgProvider.Machine().Kubelet().ExtraArgs()))\n\t\t\t\tfor k, v := range cfgProvider.Machine().Kubelet().ExtraArgs() {\n\t\t\t\t\textraArgs[k] = k8s.ArgValues{Values: v}\n\t\t\t\t}\n\n\t\t\t\tkubeletConfig.ClusterDomain = cfgProvider.Cluster().Network().DNSDomain()\n\t\t\t\tkubeletConfig.ExtraArgs = extraArgs\n\t\t\t\tkubeletConfig.ExtraMounts = cfgProvider.Machine().Kubelet().ExtraMounts()\n\t\t\t\tkubeletConfig.ExtraConfig = cfgProvider.Machine().Kubelet().ExtraConfig()\n\t\t\t\tkubeletConfig.CloudProviderExternal = cfgProvider.Cluster().ExternalCloudProvider().Enabled()\n\t\t\t\tkubeletConfig.DefaultRuntimeSeccompEnabled = cfgProvider.Machine().Kubelet().DefaultRuntimeSeccompProfileEnabled()\n\t\t\t\tkubeletConfig.SkipNodeRegistration = cfgProvider.Machine().Kubelet().SkipNodeRegistration()\n\t\t\t\tkubeletConfig.StaticPodListURL = staticPodURL.TypedSpec().URL\n\t\t\t\tkubeletConfig.DisableManifestsDirectory = cfgProvider.Machine().Kubelet().DisableManifestsDirectory()\n\t\t\t\tkubeletConfig.EnableFSQuotaMonitoring = cfgProvider.Machine().Features().DiskQuotaSupportEnabled()\n\t\t\t\tkubeletConfig.CredentialProviderConfig = cfgProvider.Machine().Kubelet().CredentialProviderConfig()\n\t\t\t\tkubeletConfig.AllowSchedulingOnControlPlane = cfgProvider.Cluster().ScheduleOnControlPlanes()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\ttransform.WithExtraInputs(\n\t\t\tcontroller.Input{\n\t\t\t\tNamespace: k8s.NamespaceName,\n\t\t\t\tType:      k8s.StaticPodServerStatusType,\n\t\t\t\tID:        optional.Some(k8s.StaticPodServerStatusResourceID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype KubeletConfigSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *KubeletConfigSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(k8sctrl.NewKubeletConfigController()))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *KubeletConfigSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *KubeletConfigSuite) createStaticPodServerStatus() {\n\tstaticPodServerStatus := k8s.NewStaticPodServerStatus(k8s.NamespaceName, k8s.StaticPodServerStatusResourceID)\n\n\tstaticPodServerStatus.TypedSpec().URL = \"http://127.0.0.1:12345\"\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, staticPodServerStatus))\n}\n\nfunc (suite *KubeletConfigSuite) TestReconcile() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tsuite.createStaticPodServerStatus()\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletImage:      \"kubelet\",\n\t\t\t\t\t\tKubeletClusterDNS: []string{\"10.0.0.1\"},\n\t\t\t\t\t\tKubeletExtraArgs: v1alpha1.Args{\n\t\t\t\t\t\t\t\"enable-feature\": v1alpha1.NewArgValue(\"foo\", nil),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tKubeletExtraMounts: []v1alpha1.ExtraMount{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDestination: \"/tmp\",\n\t\t\t\t\t\t\t\tSource:      \"/var\",\n\t\t\t\t\t\t\t\tType:        \"tmpfs\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tKubeletExtraConfig: v1alpha1.Unstructured{\n\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\"serverTLSBootstrap\": true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tKubeletDefaultRuntimeSeccompProfileEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tDNSDomain: \"service.svc\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tkubeletConfig, err := suite.state.Get(\n\t\t\t\t\tsuite.ctx,\n\t\t\t\t\tresource.NewMetadata(\n\t\t\t\t\t\tk8s.NamespaceName,\n\t\t\t\t\t\tk8s.KubeletConfigType,\n\t\t\t\t\t\tk8s.KubeletID,\n\t\t\t\t\t\tresource.VersionUndefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tspec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec()\n\n\t\t\t\tsuite.Assert().Equal(\"kubelet\", spec.Image)\n\t\t\t\tsuite.Assert().Equal([]string{\"10.0.0.1\"}, spec.ClusterDNS)\n\t\t\t\tsuite.Assert().Equal(\"service.svc\", spec.ClusterDomain)\n\t\t\t\tsuite.Assert().Equal(\n\t\t\t\t\tmap[string]k8s.ArgValues{\n\t\t\t\t\t\t\"enable-feature\": {Values: []string{\"foo\"}},\n\t\t\t\t\t},\n\t\t\t\t\tspec.ExtraArgs,\n\t\t\t\t)\n\t\t\t\tsuite.Assert().Equal(\n\t\t\t\t\t[]specs.Mount{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDestination: \"/tmp\",\n\t\t\t\t\t\t\tSource:      \"/var\",\n\t\t\t\t\t\t\tType:        \"tmpfs\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tspec.ExtraMounts,\n\t\t\t\t)\n\t\t\t\tsuite.Assert().Equal(\n\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\"serverTLSBootstrap\": true,\n\t\t\t\t\t},\n\t\t\t\t\tspec.ExtraConfig,\n\t\t\t\t)\n\t\t\t\tsuite.Assert().True(spec.CloudProviderExternal)\n\t\t\t\tsuite.Assert().True(spec.DefaultRuntimeSeccompEnabled)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *KubeletConfigSuite) TestReconcileDefaults() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tsuite.createStaticPodServerStatus()\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletImage: \"kubelet\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tServiceSubnet: []string{constants.DefaultIPv4ServiceNet},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tkubeletConfig, err := suite.state.Get(\n\t\t\t\t\tsuite.ctx,\n\t\t\t\t\tresource.NewMetadata(\n\t\t\t\t\t\tk8s.NamespaceName,\n\t\t\t\t\t\tk8s.KubeletConfigType,\n\t\t\t\t\t\tk8s.KubeletID,\n\t\t\t\t\t\tresource.VersionUndefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tspec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec()\n\n\t\t\t\tsuite.Assert().Equal(\"kubelet\", spec.Image)\n\t\t\t\tsuite.Assert().Equal([]string{\"10.96.0.10\"}, spec.ClusterDNS)\n\t\t\t\tsuite.Assert().Equal(constants.DefaultDNSDomain, spec.ClusterDomain)\n\t\t\t\tsuite.Assert().Empty(spec.ExtraArgs)\n\t\t\t\tsuite.Assert().Empty(spec.ExtraMounts)\n\t\t\t\tsuite.Assert().False(spec.CloudProviderExternal)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *KubeletConfigSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestKubeletConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(KubeletConfigSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/x509\"\n\tstdjson \"encoding/json\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\ttalosx509 \"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/runtime/serializer/json\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\tkubeletv1config \"k8s.io/kubelet/config/v1\"\n\tkubeletconfig \"k8s.io/kubelet/config/v1beta1\"\n\n\truntimetalos \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// ServiceManager is the interface to the v1alpha1 services subsystems.\ntype ServiceManager interface {\n\tIsRunning(id string) (system.Service, bool, error)\n\tLoad(services ...system.Service) []string\n\tStop(ctx context.Context, serviceIDs ...string) (err error)\n\tStart(serviceIDs ...string) error\n}\n\n// KubeletServiceController renders kubelet configuration files and controls kubelet service lifecycle.\ntype KubeletServiceController struct {\n\tV1Alpha1Services ServiceManager\n\tV1Alpha1Mode     runtimetalos.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubeletServiceController) Name() string {\n\treturn \"k8s.KubeletServiceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubeletServiceController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubeletServiceController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KubeletServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// initially, wait for the machine-id to be generated and /var to be mounted\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: files.NamespaceName,\n\t\t\tType:      files.EtcFileStatusType,\n\t\t\tID:        optional.Some(\"machine-id\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtimeres.NamespaceName,\n\t\t\tType:      runtimeres.MountStatusType,\n\t\t\tID:        optional.Some(constants.EphemeralPartitionLabel),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t_, err := r.Get(ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, \"machine-id\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etc file status: %w\", err)\n\t\t}\n\n\t\t_, err = r.Get(ctx, resource.NewMetadata(runtimeres.NamespaceName, runtimeres.MountStatusType, constants.EphemeralPartitionLabel, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// in container mode EPHEMERAL is always mounted\n\t\t\t\tif ctrl.V1Alpha1Mode != runtimetalos.ModeContainer {\n\t\t\t\t\t// wait for the EPHEMERAL to be mounted\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"error getting ephemeral mount status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tbreak\n\t}\n\n\t// normal reconcile loop\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.KubeletSpecType,\n\t\t\tID:        optional.Some(k8s.KubeletID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubeletType,\n\t\t\tID:        optional.Some(secrets.KubeletID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tr.QueueReconcile()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*k8s.KubeletSpec](ctx, r, k8s.KubeletID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tcfgSpec := cfg.TypedSpec()\n\n\t\tsecret, err := safe.ReaderGetByID[*secrets.Kubelet](ctx, r, secrets.KubeletID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets: %w\", err)\n\t\t}\n\n\t\tsecretSpec := secret.TypedSpec()\n\n\t\tif err = ctrl.writePKI(secretSpec); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing kubelet PKI: %w\", err)\n\t\t}\n\n\t\tif err = ctrl.writeConfig(cfgSpec); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing kubelet configuration: %w\", err)\n\t\t}\n\n\t\tif err = ctrl.writeKubeletCredentialProviderConfig(cfgSpec); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing kubelet credential provider configuration: %w\", err)\n\t\t}\n\n\t\t_, running, err := ctrl.V1Alpha1Services.IsRunning(\"kubelet\")\n\t\tif err != nil {\n\t\t\tctrl.V1Alpha1Services.Load(&services.Kubelet{})\n\t\t}\n\n\t\tif running {\n\t\t\tif err = ctrl.V1Alpha1Services.Stop(ctx, \"kubelet\"); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error stopping kubelet service: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = ctrl.refreshKubeletCerts(cfgSpec.ExpectedNodename, secretSpec.AcceptedCAs, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = ctrl.handlePolicyChange(cfgSpec, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = ctrl.refreshSelfServingCert(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = ctrl.updateKubeconfig(secretSpec.Endpoint, secretSpec.AcceptedCAs, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = ctrl.V1Alpha1Services.Start(\"kubelet\"); err != nil {\n\t\t\treturn fmt.Errorf(\"error starting kubelet service: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// handlePolicyChange handles the cpuManagerPolicy change.\nfunc (ctrl *KubeletServiceController) handlePolicyChange(cfgSpec *k8s.KubeletSpecSpec, logger *zap.Logger) error {\n\tconst managerFilename = \"/var/lib/kubelet/cpu_manager_state\"\n\n\toldPolicy, err := loadPolicyFromFile(managerFilename)\n\n\tswitch {\n\tcase errors.Is(err, os.ErrNotExist):\n\t\treturn nil // no cpu_manager_state file, nothing to do\n\tcase err != nil:\n\t\treturn fmt.Errorf(\"error loading cpu_manager_state file: %w\", err)\n\t}\n\n\tpolicy, err := getFromMap[string](cfgSpec.Config, \"cpuManagerPolicy\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnewPolicy := policy.ValueOrZero()\n\tif equalPolicy(oldPolicy, newPolicy) {\n\t\treturn nil\n\t}\n\n\tlogger.Info(\"cpuManagerPolicy changed\", zap.String(\"old\", oldPolicy), zap.String(\"new\", newPolicy))\n\n\terr = os.Remove(managerFilename)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error removing cpu_manager_state file: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc loadPolicyFromFile(filename string) (string, error) {\n\traw, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tcpuManagerState := struct {\n\t\tPolicy string `json:\"policyName\"`\n\t}{}\n\n\tif err = stdjson.Unmarshal(raw, &cpuManagerState); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn cpuManagerState.Policy, nil\n}\n\nfunc equalPolicy(current, newOne string) bool {\n\tif current == \"none\" {\n\t\tcurrent = \"\"\n\t}\n\n\tif newOne == \"none\" {\n\t\tnewOne = \"\"\n\t}\n\n\treturn current == newOne\n}\n\nfunc getFromMap[T any](m map[string]any, key string) (optional.Optional[T], error) {\n\tvar zero optional.Optional[T]\n\n\tres, ok := m[key]\n\tif !ok {\n\t\treturn zero, nil\n\t}\n\n\tif res, ok := res.(T); ok {\n\t\treturn optional.Some(res), nil\n\t}\n\n\treturn zero, fmt.Errorf(\"unexpected type for key %q: found %T, expected %T\", key, res, *new(T))\n}\n\nfunc (ctrl *KubeletServiceController) writePKI(secretSpec *secrets.KubeletSpec) error {\n\tacceptedCAs := bytes.Join(xslices.Map(secretSpec.AcceptedCAs, func(ca *talosx509.PEMEncodedCertificate) []byte { return ca.Crt }), nil)\n\n\tbootstrapKubeconfig := clientcmdapi.Config{\n\t\tAPIVersion: \"v1\",\n\t\tKind:       \"Config\",\n\t\tClusters: map[string]*clientcmdapi.Cluster{\n\t\t\t\"local\": {\n\t\t\t\tServer:                   secretSpec.Endpoint.String(),\n\t\t\t\tCertificateAuthorityData: acceptedCAs,\n\t\t\t},\n\t\t},\n\t\tAuthInfos: map[string]*clientcmdapi.AuthInfo{\n\t\t\t\"kubelet@local\": {\n\t\t\t\tToken: fmt.Sprintf(\"%s.%s\", secretSpec.BootstrapTokenID, secretSpec.BootstrapTokenSecret),\n\t\t\t},\n\t\t},\n\t\tContexts: map[string]*clientcmdapi.Context{\n\t\t\t\"kubelet@local\": {\n\t\t\t\tCluster:  \"local\",\n\t\t\t\tAuthInfo: \"kubelet@local\",\n\t\t\t},\n\t\t},\n\t\tCurrentContext: \"kubelet@local\",\n\t}\n\n\tmarshaledKubeConfig, err := clientcmd.Write(bootstrapKubeconfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling kubeconfig: %w\", err)\n\t}\n\n\tif err := os.WriteFile(constants.KubeletBootstrapKubeconfig, marshaledKubeConfig, 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.MkdirAll(filepath.Dir(constants.KubernetesCACert), 0o700); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(constants.KubernetesCACert, acceptedCAs, 0o400)\n}\n\nfunc (ctrl *KubeletServiceController) writeConfig(cfgSpec *k8s.KubeletSpecSpec) error {\n\tvar kubeletConfiguration kubeletconfig.KubeletConfiguration\n\n\tif err := runtime.DefaultUnstructuredConverter.FromUnstructured(cfgSpec.Config, &kubeletConfiguration); err != nil {\n\t\treturn fmt.Errorf(\"error converting kubelet configuration from unstructured: %w\", err)\n\t}\n\n\tserializer := json.NewSerializerWithOptions(\n\t\tjson.DefaultMetaFactory,\n\t\tnil,\n\t\tnil,\n\t\tjson.SerializerOptions{\n\t\t\tYaml: true,\n\t\t},\n\t)\n\n\tvar buf bytes.Buffer\n\n\tif err := serializer.Encode(&kubeletConfiguration, &buf); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(\"/etc/kubernetes/kubelet.yaml\", buf.Bytes(), 0o600)\n}\n\nfunc (ctrl *KubeletServiceController) writeKubeletCredentialProviderConfig(cfgSpec *k8s.KubeletSpecSpec) error {\n\tif cfgSpec.CredentialProviderConfig == nil {\n\t\treturn os.RemoveAll(constants.KubeletCredentialProviderConfig)\n\t}\n\n\tvar kubeletCredentialProviderConfig kubeletv1config.CredentialProviderConfig\n\n\tif err := runtime.DefaultUnstructuredConverter.FromUnstructured(cfgSpec.CredentialProviderConfig, &kubeletCredentialProviderConfig); err != nil {\n\t\treturn fmt.Errorf(\"error converting kubelet credentialprovider configuration from unstructured: %w\", err)\n\t}\n\n\tserializer := json.NewSerializerWithOptions(\n\t\tjson.DefaultMetaFactory,\n\t\tnil,\n\t\tnil,\n\t\tjson.SerializerOptions{\n\t\t\tYaml: true,\n\t\t},\n\t)\n\n\tvar buf bytes.Buffer\n\n\tif err := serializer.Encode(&kubeletCredentialProviderConfig, &buf); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(constants.KubeletCredentialProviderConfig, buf.Bytes(), 0o600)\n}\n\n// updateKubeconfig updates the kubeconfig of kubelet with the given endpoint if it exists.\nfunc (ctrl *KubeletServiceController) updateKubeconfig(newEndpoint *url.URL, acceptedCAs []*talosx509.PEMEncodedCertificate, logger *zap.Logger) error {\n\tconfig, err := clientcmd.LoadFromFile(constants.KubeletKubeconfig)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn nil\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontext := config.Contexts[config.CurrentContext]\n\tif context == nil {\n\t\t// this should never happen, but we can't fix kubeconfig if it is malformed\n\t\tlogger.Error(\"kubeconfig is missing current context\", zap.String(\"context\", config.CurrentContext))\n\n\t\treturn nil\n\t}\n\n\tcluster := config.Clusters[context.Cluster]\n\n\tif cluster == nil {\n\t\t// this should never happen, but we can't fix kubeconfig if it is malformed\n\t\tlogger.Error(\"kubeconfig is missing cluster\", zap.String(\"context\", config.CurrentContext), zap.String(\"cluster\", context.Cluster))\n\n\t\treturn nil\n\t}\n\n\tcluster.Server = newEndpoint.String()\n\tcluster.CertificateAuthorityData = bytes.Join(xslices.Map(acceptedCAs, func(ca *talosx509.PEMEncodedCertificate) []byte { return ca.Crt }), nil)\n\n\treturn clientcmd.WriteToFile(*config, constants.KubeletKubeconfig)\n}\n\n// refreshKubeletCerts checks if the existing kubelet certificates match the node hostname and expected CA.\n// If they don't match, it clears the certificate directory and the removes kubelet's kubeconfig so that\n// they can be regenerated next time kubelet is started.\n//\n//nolint:gocyclo\nfunc (ctrl *KubeletServiceController) refreshKubeletCerts(expectedNodename string, acceptedCAs []*talosx509.PEMEncodedCertificate, logger *zap.Logger) error {\n\tcert, err := ctrl.readKubeletClientCertificate()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif cert == nil {\n\t\treturn nil\n\t}\n\n\tvalid := true\n\n\t// refresh certs only if we are managing the node name (not overridden by the user)\n\tif expectedNodename != \"\" {\n\t\texpectedCommonName := fmt.Sprintf(\"system:node:%s\", expectedNodename)\n\n\t\tvalid = valid && expectedCommonName == cert.Subject.CommonName\n\n\t\tif !valid {\n\t\t\tlogger.Info(\"kubelet client certificate does not match expected nodename, removing\",\n\t\t\t\tzap.String(\"expected\", expectedCommonName),\n\t\t\t\tzap.String(\"actual\", cert.Subject.CommonName),\n\t\t\t)\n\t\t}\n\t}\n\n\t// check against CAs\n\tif valid {\n\t\trootCAs := x509.NewCertPool()\n\n\t\tfor _, ca := range acceptedCAs {\n\t\t\tif !rootCAs.AppendCertsFromPEM(ca.Crt) {\n\t\t\t\treturn fmt.Errorf(\"error adding CA to root pool: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t_, verifyErr := cert.Verify(x509.VerifyOptions{\n\t\t\tRoots:     rootCAs,\n\t\t\tKeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},\n\t\t})\n\n\t\tvalid = valid && verifyErr == nil\n\n\t\tif !valid {\n\t\t\tlogger.Info(\"kubelet client certificate does not match any accepted CAs, removing\", zap.NamedError(\"verify_error\", verifyErr))\n\t\t}\n\t}\n\n\tif valid {\n\t\t// certificate looks good, no need to refresh\n\t\treturn nil\n\t}\n\n\t// remove the pki directory\n\terr = os.RemoveAll(constants.KubeletPKIDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// clear the kubelet kubeconfig\n\terr = os.Remove(constants.KubeletKubeconfig)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn nil\n\t}\n\n\treturn err\n}\n\n// refreshSelfServingCert removes the self-signed serving certificate (if exists) to force the kubelet to renew it.\nfunc (ctrl *KubeletServiceController) refreshSelfServingCert() error {\n\tfor _, filename := range []string{\n\t\t\"kubelet.crt\",\n\t\t\"kubelet.key\",\n\t} {\n\t\tpath := filepath.Join(constants.KubeletPKIDir, filename)\n\n\t\t_, err := os.Stat(path)\n\t\tif err == nil {\n\t\t\terr = os.Remove(path)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing self-signed certificate: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *KubeletServiceController) readKubeletClientCertificate() (*x509.Certificate, error) {\n\traw, err := os.ReadFile(filepath.Join(constants.KubeletPKIDir, \"kubelet-client-current.pem\"))\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn nil, nil\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor {\n\t\tblock, rest := pem.Decode(raw)\n\t\tif block == nil {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\traw = rest\n\n\t\tif block.Type != \"CERTIFICATE\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar cert *x509.Certificate\n\n\t\tcert, err = x509.ParseCertificate(block.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif !cert.IsCA {\n\t\t\treturn cert, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/compatibility\"\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tkubeletconfig \"k8s.io/kubelet/config/v1beta1\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n\t\"github.com/siderolabs/talos/pkg/argsbuilder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kubelet\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubeletSpecController renders manifests based on templates and config/secrets.\ntype KubeletSpecController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubeletSpecController) Name() string {\n\treturn \"k8s.KubeletSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubeletSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.KubeletConfigType,\n\t\t\tID:        optional.Some(k8s.KubeletID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeIPType,\n\t\t\tID:        optional.Some(k8s.KubeletID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubeletSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.KubeletSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KubeletSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*k8s.KubeletConfig](ctx, r, k8s.KubeletID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tcfgSpec := cfg.TypedSpec()\n\n\t\tkubeletVersion := compatibility.VersionFromImageRef(cfgSpec.Image)\n\n\t\tmachineType, err := safe.ReaderGetByID[*config.MachineType](ctx, r, config.MachineTypeID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tnodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t}\n\n\t\texpectedNodename := nodename.TypedSpec().Nodename\n\n\t\targs := argsbuilder.Args{\n\t\t\t\"config\":            argsbuilder.Value{\"/etc/kubernetes/kubelet.yaml\"},\n\t\t\t\"cert-dir\":          argsbuilder.Value{constants.KubeletPKIDir},\n\t\t\t\"hostname-override\": argsbuilder.Value{expectedNodename},\n\t\t}\n\n\t\tif !cfgSpec.SkipNodeRegistration {\n\t\t\targs[\"bootstrap-kubeconfig\"] = argsbuilder.Value{constants.KubeletBootstrapKubeconfig}\n\t\t\targs[\"kubeconfig\"] = argsbuilder.Value{constants.KubeletKubeconfig}\n\t\t}\n\n\t\tif cfgSpec.CloudProviderExternal {\n\t\t\t// we still need to specify `--cloud-provider=external` for the kubelet\n\t\t\t// to get the node properly tainted so that it gets picked up by the external CCM\n\t\t\targs[\"cloud-provider\"] = argsbuilder.Value{CloudProviderExternal}\n\t\t}\n\n\t\tif !kubeletVersion.SupportsKubeletConfigContainerRuntimeEndpoint() {\n\t\t\targs[\"container-runtime-endpoint\"] = argsbuilder.Value{constants.CRIContainerdAddress}\n\t\t}\n\n\t\textraArgs := make(argsbuilder.Args, len(cfgSpec.ExtraArgs))\n\t\tfor k, v := range cfgSpec.ExtraArgs {\n\t\t\textraArgs[k] = v.Values\n\t\t}\n\n\t\t// if the user supplied a hostname override, we do not manage it anymore\n\t\tif extraArgs.Contains(\"hostname-override\") {\n\t\t\texpectedNodename = \"\"\n\t\t}\n\n\t\t// if the user supplied node-ip via extra args, no need to pick automatically\n\t\tif !extraArgs.Contains(\"node-ip\") {\n\t\t\tnodeIP, nodeErr := safe.ReaderGetByID[*k8s.NodeIP](ctx, r, k8s.KubeletID)\n\t\t\tif nodeErr != nil {\n\t\t\t\tif state.IsNotFoundError(nodeErr) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn fmt.Errorf(\"error getting node IPs: %w\", nodeErr)\n\t\t\t}\n\n\t\t\tnodeIPsString := xslices.Map(nodeIP.TypedSpec().Addresses, netip.Addr.String)\n\t\t\targs[\"node-ip\"] = argsbuilder.Value{strings.Join(nodeIPsString, \",\")} // NOTE: flag has string type, cannot be multiple\n\t\t}\n\n\t\tif err = args.Merge(extraArgs, argsbuilder.WithMergePolicies(\n\t\t\targsbuilder.MergePolicies{\n\t\t\t\t\"bootstrap-kubeconfig\":       argsbuilder.MergeDenied,\n\t\t\t\t\"kubeconfig\":                 argsbuilder.MergeDenied,\n\t\t\t\t\"container-runtime\":          argsbuilder.MergeDenied,\n\t\t\t\t\"container-runtime-endpoint\": argsbuilder.MergeDenied,\n\t\t\t\t\"config\":                     argsbuilder.MergeDenied,\n\t\t\t\t\"cert-dir\":                   argsbuilder.MergeDenied,\n\t\t\t},\n\t\t)); err != nil {\n\t\t\treturn fmt.Errorf(\"error merging arguments: %w\", err)\n\t\t}\n\n\t\t// these flags are present from v1.24\n\t\tif cfgSpec.CredentialProviderConfig != nil {\n\t\t\targs[\"image-credential-provider-bin-dir\"] = argsbuilder.Value{constants.KubeletCredentialProviderBinDir}\n\t\t\targs[\"image-credential-provider-config\"] = argsbuilder.Value{constants.KubeletCredentialProviderConfig}\n\t\t}\n\n\t\tkubeletConfig, err := NewKubeletConfiguration(cfgSpec, kubeletVersion, machineType.MachineType())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating kubelet configuration: %w\", err)\n\t\t}\n\n\t\t// If our platform is container, we cannot rely on the ability to change kernel parameters.\n\t\t// Therefore, we need to NOT attempt to enforce the kernel parameter checking done by the kubelet\n\t\t// when the `ProtectKernelDefaults` setting is enabled.\n\t\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\t\tkubeletConfig.ProtectKernelDefaults = false\n\t\t}\n\n\t\tunstructuredConfig, err := runtime.DefaultUnstructuredConverter.ToUnstructured(kubeletConfig)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error converting to unstructured: %w\", err)\n\t\t}\n\n\t\tif err = safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tk8s.NewKubeletSpec(k8s.NamespaceName, k8s.KubeletID),\n\t\t\tfunc(r *k8s.KubeletSpec) error {\n\t\t\t\tkubeletSpec := r.TypedSpec()\n\n\t\t\t\tkubeletSpec.Image = cfgSpec.Image\n\t\t\t\tkubeletSpec.ExtraMounts = cfgSpec.ExtraMounts\n\t\t\t\tkubeletSpec.Args = args.Args()\n\t\t\t\tkubeletSpec.Config = unstructuredConfig\n\t\t\t\tkubeletSpec.ExpectedNodename = expectedNodename\n\t\t\t\tkubeletSpec.CredentialProviderConfig = cfgSpec.CredentialProviderConfig\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying KubeletSpec resource: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc prepareExtraConfig(extraConfig map[string]any) (*kubeletconfig.KubeletConfiguration, error) {\n\t// check for fields that can't be overridden via extraConfig\n\tvar multiErr *multierror.Error\n\n\tfor _, field := range kubelet.ProtectedConfigurationFields {\n\t\tif _, exists := extraConfig[field]; exists {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"field %q can't be overridden\", field))\n\t\t}\n\t}\n\n\tif err := multiErr.ErrorOrNil(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar config kubeletconfig.KubeletConfiguration\n\n\t// unmarshal extra config into the config structure\n\t// as unmarshalling zeroes the missing fields, we can't do that after setting the defaults\n\tif err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(extraConfig, &config, true); err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling extra kubelet configuration: %w\", err)\n\t}\n\n\treturn &config, nil\n}\n\n// NewKubeletConfiguration builds kubelet configuration with defaults and overrides from extraConfig.\n//\n//nolint:gocyclo,cyclop\nfunc NewKubeletConfiguration(cfgSpec *k8s.KubeletConfigSpec, kubeletVersion compatibility.Version, machineType machine.Type) (*kubeletconfig.KubeletConfiguration, error) {\n\tconfig, err := prepareExtraConfig(cfgSpec.ExtraConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// required fields (always set)\n\tconfig.TypeMeta = metav1.TypeMeta{\n\t\tAPIVersion: kubeletconfig.SchemeGroupVersion.String(),\n\t\tKind:       \"KubeletConfiguration\",\n\t}\n\n\tif cfgSpec.DisableManifestsDirectory {\n\t\tconfig.StaticPodPath = \"\"\n\t} else {\n\t\tconfig.StaticPodPath = constants.ManifestsDirectory\n\t}\n\n\tconfig.StaticPodURL = cfgSpec.StaticPodListURL\n\tconfig.Port = constants.KubeletPort\n\tconfig.Authentication = kubeletconfig.KubeletAuthentication{\n\t\tX509: kubeletconfig.KubeletX509Authentication{\n\t\t\tClientCAFile: constants.KubernetesCACert,\n\t\t},\n\t\tWebhook: kubeletconfig.KubeletWebhookAuthentication{\n\t\t\tEnabled: new(true),\n\t\t},\n\t\tAnonymous: kubeletconfig.KubeletAnonymousAuthentication{\n\t\t\tEnabled: new(false),\n\t\t},\n\t}\n\tconfig.Authorization = kubeletconfig.KubeletAuthorization{\n\t\tMode: kubeletconfig.KubeletAuthorizationModeWebhook,\n\t}\n\tconfig.CgroupRoot = cgroup.Root()\n\tconfig.SystemCgroups = cgroup.Path(constants.CgroupSystem)\n\tconfig.KubeletCgroups = cgroup.Path(constants.CgroupKubelet)\n\tconfig.RotateCertificates = true\n\tconfig.ProtectKernelDefaults = true\n\n\tif kubeletVersion.SupportsKubeletConfigContainerRuntimeEndpoint() {\n\t\tconfig.ContainerRuntimeEndpoint = \"unix://\" + constants.CRIContainerdAddress\n\t}\n\n\tif cfgSpec.DefaultRuntimeSeccompEnabled {\n\t\tconfig.SeccompDefault = new(true)\n\t}\n\n\tif cfgSpec.EnableFSQuotaMonitoring {\n\t\tif _, overridden := config.FeatureGates[\"LocalStorageCapacityIsolationFSQuotaMonitoring\"]; !overridden {\n\t\t\tif config.FeatureGates == nil {\n\t\t\t\tconfig.FeatureGates = map[string]bool{}\n\t\t\t}\n\n\t\t\tconfig.FeatureGates[\"LocalStorageCapacityIsolationFSQuotaMonitoring\"] = true\n\t\t}\n\t}\n\n\tif cfgSpec.SkipNodeRegistration {\n\t\tconfig.Authentication.Webhook.Enabled = new(false)\n\t\tconfig.Authorization.Mode = kubeletconfig.KubeletAuthorizationModeAlwaysAllow\n\t} else if machineType.IsControlPlane() && !cfgSpec.AllowSchedulingOnControlPlane {\n\t\t// register with taint to prevent scheduling on control plane nodes race with NodeApplyController applying the initial taint\n\t\t// NodeApplyController will take ownership of the taint after the first successful apply\n\t\tif slices.IndexFunc(config.RegisterWithTaints, func(t corev1.Taint) bool {\n\t\t\treturn t.Key == constants.LabelNodeRoleControlPlane\n\t\t}) == -1 { // don't add the taint if it's already in the config\n\t\t\tif cfgSpec.ExtraArgs[\"register-with-taints\"].Values == nil { // don't clash with taints provided via extraArgs, it is deprecated on kubelet side\n\t\t\t\tconfig.RegisterWithTaints = append(config.RegisterWithTaints,\n\t\t\t\t\tcorev1.Taint{\n\t\t\t\t\t\tKey:    constants.LabelNodeRoleControlPlane,\n\t\t\t\t\t\tEffect: corev1.TaintEffectNoSchedule,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// fields which can be overridden\n\tif config.Address == \"\" {\n\t\tconfig.Address = \"0.0.0.0\"\n\t}\n\n\tif config.OOMScoreAdj == nil {\n\t\tconfig.OOMScoreAdj = new(int32(constants.KubeletOOMScoreAdj))\n\t}\n\n\tif config.ClusterDomain == \"\" {\n\t\tconfig.ClusterDomain = cfgSpec.ClusterDomain\n\t}\n\n\tif len(config.ClusterDNS) == 0 {\n\t\tconfig.ClusterDNS = cfgSpec.ClusterDNS\n\t}\n\n\tif config.SerializeImagePulls == nil {\n\t\tconfig.SerializeImagePulls = new(false)\n\t}\n\n\tif config.FailSwapOn == nil {\n\t\tconfig.FailSwapOn = new(false)\n\t}\n\n\tif len(config.SystemReserved) == 0 {\n\t\tconfig.SystemReserved = map[string]string{\n\t\t\t\"cpu\":               constants.KubeletSystemReservedCPU,\n\t\t\t\"pid\":               constants.KubeletSystemReservedPid,\n\t\t\t\"ephemeral-storage\": constants.KubeletSystemReservedEphemeralStorage,\n\t\t}\n\n\t\tif machineType.IsControlPlane() {\n\t\t\tconfig.SystemReserved[\"memory\"] = constants.KubeletSystemReservedMemoryControlPlane\n\t\t} else {\n\t\t\tconfig.SystemReserved[\"memory\"] = constants.KubeletSystemReservedMemoryWorker\n\t\t}\n\t}\n\n\tif config.Logging.Format == \"\" {\n\t\tconfig.Logging.Format = \"json\"\n\t}\n\n\textraConfig := cfgSpec.ExtraConfig\n\n\tif _, overridden := extraConfig[\"shutdownGracePeriod\"]; !overridden && config.ShutdownGracePeriod.Duration == 0 {\n\t\tconfig.ShutdownGracePeriod = metav1.Duration{Duration: constants.KubeletShutdownGracePeriod}\n\t}\n\n\tif _, overridden := extraConfig[\"shutdownGracePeriodCriticalPods\"]; !overridden && config.ShutdownGracePeriodCriticalPods.Duration == 0 {\n\t\tconfig.ShutdownGracePeriodCriticalPods = metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods}\n\t}\n\n\tif config.StreamingConnectionIdleTimeout.Duration == 0 {\n\t\tconfig.StreamingConnectionIdleTimeout = metav1.Duration{Duration: 5 * time.Minute}\n\t}\n\n\tif config.TLSMinVersion == \"\" {\n\t\tconfig.TLSMinVersion = \"VersionTLS13\"\n\t}\n\n\tconfig.ResolverConfig = new(constants.PodResolvConfPath)\n\n\treturn config, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:goconst\npackage k8s_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/compatibility\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\tk8sruntime \"k8s.io/apimachinery/pkg/runtime\"\n\tv1 \"k8s.io/component-base/logs/api/v1\"\n\tkubeletconfig \"k8s.io/kubelet/config/v1beta1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype KubeletSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubeletSpecSuite) TestReconcileDefault() {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v1.29.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.10\"}\n\tcfg.TypedSpec().ClusterDomain = \"cluster.local\"\n\tcfg.TypedSpec().ExtraArgs = map[string]k8s.ArgValues{\"foo\": {Values: []string{\"bar\"}}}\n\tcfg.TypedSpec().ExtraMounts = []specs.Mount{\n\t\t{\n\t\t\tDestination: \"/tmp\",\n\t\t\tSource:      \"/var\",\n\t\t\tType:        \"tmpfs\",\n\t\t},\n\t}\n\tcfg.TypedSpec().CloudProviderExternal = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tnodeIP := k8s.NewNodeIP(k8s.NamespaceName, k8s.KubeletID)\n\tnodeIP.TypedSpec().Addresses = []netip.Addr{netip.MustParseAddr(\"172.20.0.2\")}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeIP))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"example.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(kubeletSpec *k8s.KubeletSpec, asrt *assert.Assertions) {\n\t\tspec := kubeletSpec.TypedSpec()\n\n\t\tasrt.Equal(cfg.TypedSpec().Image, spec.Image)\n\t\tasrt.Equal(\n\t\t\t[]string{\n\t\t\t\t\"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig\",\n\t\t\t\t\"--cert-dir=/var/lib/kubelet/pki\",\n\t\t\t\t\"--cloud-provider=external\",\n\t\t\t\t\"--config=/etc/kubernetes/kubelet.yaml\",\n\t\t\t\t\"--foo=bar\",\n\t\t\t\t\"--hostname-override=example.com\",\n\t\t\t\t\"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet\",\n\t\t\t\t\"--node-ip=172.20.0.2\",\n\t\t\t}, spec.Args,\n\t\t)\n\t\tasrt.Equal(cfg.TypedSpec().ExtraMounts, spec.ExtraMounts)\n\n\t\tasrt.Equal([]any{\"10.96.0.10\"}, spec.Config[\"clusterDNS\"])\n\t\tasrt.Equal(\"cluster.local\", spec.Config[\"clusterDomain\"])\n\t})\n}\n\nfunc (suite *KubeletSpecSuite) TestReconcileWithExplicitNodeIP() {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v1.29.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.10\"}\n\tcfg.TypedSpec().ClusterDomain = \"cluster.local\"\n\tcfg.TypedSpec().ExtraArgs = map[string]k8s.ArgValues{\"node-ip\": {Values: []string{\"10.0.0.1\"}}}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"example.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(kubeletSpec *k8s.KubeletSpec, asrt *assert.Assertions) {\n\t\tspec := kubeletSpec.TypedSpec()\n\n\t\tasrt.Equal(cfg.TypedSpec().Image, spec.Image)\n\t\tasrt.Equal(\n\t\t\t[]string{\n\t\t\t\t\"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig\",\n\t\t\t\t\"--cert-dir=/var/lib/kubelet/pki\",\n\t\t\t\t\"--config=/etc/kubernetes/kubelet.yaml\",\n\t\t\t\t\"--hostname-override=example.com\",\n\t\t\t\t\"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet\",\n\t\t\t\t\"--node-ip=10.0.0.1\",\n\t\t\t}, spec.Args,\n\t\t)\n\t})\n}\n\nfunc (suite *KubeletSpecSuite) TestReconcileWithContainerRuntimeEndpointFlag() {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v1.25.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.10\"}\n\tcfg.TypedSpec().ClusterDomain = \"cluster.local\"\n\tcfg.TypedSpec().ExtraArgs = map[string]k8s.ArgValues{\"node-ip\": {Values: []string{\"10.0.0.1\"}}}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"example.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(kubeletSpec *k8s.KubeletSpec, asrt *assert.Assertions) {\n\t\tspec := kubeletSpec.TypedSpec()\n\n\t\tasrt.Equal(cfg.TypedSpec().Image, spec.Image)\n\t\tasrt.Equal(\n\t\t\t[]string{\n\t\t\t\t\"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig\",\n\t\t\t\t\"--cert-dir=/var/lib/kubelet/pki\",\n\t\t\t\t\"--config=/etc/kubernetes/kubelet.yaml\",\n\t\t\t\t\"--container-runtime-endpoint=/run/containerd/containerd.sock\",\n\t\t\t\t\"--hostname-override=example.com\",\n\t\t\t\t\"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet\",\n\t\t\t\t\"--node-ip=10.0.0.1\",\n\t\t\t}, spec.Args,\n\t\t)\n\n\t\tvar kubeletConfiguration kubeletconfig.KubeletConfiguration\n\n\t\tif err := k8sruntime.DefaultUnstructuredConverter.FromUnstructured(\n\t\t\tspec.Config,\n\t\t\t&kubeletConfiguration,\n\t\t); err != nil {\n\t\t\tasrt.NoError(err)\n\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Empty(kubeletConfiguration.ContainerRuntimeEndpoint)\n\t})\n}\n\nfunc (suite *KubeletSpecSuite) TestReconcileWithExtraConfig() {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v2.0.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.11\"}\n\tcfg.TypedSpec().ClusterDomain = \"some.local\"\n\tcfg.TypedSpec().ExtraConfig = map[string]any{\n\t\t\"serverTLSBootstrap\": true,\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"foo.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tnodeIP := k8s.NewNodeIP(k8s.NamespaceName, k8s.KubeletID)\n\tnodeIP.TypedSpec().Addresses = []netip.Addr{netip.MustParseAddr(\"172.20.0.3\")}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeIP))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(kubeletSpec *k8s.KubeletSpec, asrt *assert.Assertions) {\n\t\tspec := kubeletSpec.TypedSpec()\n\n\t\tvar kubeletConfiguration kubeletconfig.KubeletConfiguration\n\n\t\tif err := k8sruntime.DefaultUnstructuredConverter.FromUnstructured(\n\t\t\tspec.Config,\n\t\t\t&kubeletConfiguration,\n\t\t); err != nil {\n\t\t\tasrt.NoError(err)\n\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal(\"/\", kubeletConfiguration.CgroupRoot)\n\t\tasrt.Equal(cfg.TypedSpec().ClusterDomain, kubeletConfiguration.ClusterDomain)\n\t\tasrt.True(kubeletConfiguration.ServerTLSBootstrap)\n\t})\n}\n\nfunc (suite *KubeletSpecSuite) TestReconcileWithSkipNodeRegistration() {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v2.0.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.11\"}\n\tcfg.TypedSpec().ClusterDomain = \"some.local\"\n\tcfg.TypedSpec().SkipNodeRegistration = true\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"foo.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tnodeIP := k8s.NewNodeIP(k8s.NamespaceName, k8s.KubeletID)\n\tnodeIP.TypedSpec().Addresses = []netip.Addr{netip.MustParseAddr(\"172.20.0.3\")}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeIP))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeWorker)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(kubeletSpec *k8s.KubeletSpec, asrt *assert.Assertions) {\n\t\tspec := kubeletSpec.TypedSpec()\n\n\t\tvar kubeletConfiguration kubeletconfig.KubeletConfiguration\n\n\t\tif err := k8sruntime.DefaultUnstructuredConverter.FromUnstructured(\n\t\t\tspec.Config,\n\t\t\t&kubeletConfiguration,\n\t\t); err != nil {\n\t\t\tasrt.NoError(err)\n\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal(\"/\", kubeletConfiguration.CgroupRoot)\n\t\tasrt.Equal(cfg.TypedSpec().ClusterDomain, kubeletConfiguration.ClusterDomain)\n\t\tasrt.Equal([]string{\n\t\t\t\"--cert-dir=/var/lib/kubelet/pki\",\n\t\t\t\"--config=/etc/kubernetes/kubelet.yaml\",\n\t\t\t\"--hostname-override=foo.com\",\n\t\t\t\"--node-ip=172.20.0.3\",\n\t\t}, spec.Args)\n\t})\n}\n\nfunc TestKubeletSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &KubeletSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&k8sctrl.KubeletSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestNewKubeletConfigurationFail(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tcfgSpec     *k8s.KubeletConfigSpec\n\t\texpectedErr string\n\t}{\n\t\t{\n\t\t\tname: \"wrong fields\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.96.0.10\"},\n\t\t\t\tClusterDomain: \"cluster.svc\",\n\t\t\t\tExtraConfig: map[string]any{\n\t\t\t\t\t\"API\":  \"v1\",\n\t\t\t\t\t\"foo\":  \"bar\",\n\t\t\t\t\t\"Port\": \"xyz\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"error unmarshalling extra kubelet configuration: strict decoding error: unknown field \\\"API\\\", unknown field \\\"Port\\\", unknown field \\\"foo\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"wrong field type\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.96.0.10\"},\n\t\t\t\tClusterDomain: \"cluster.svc\",\n\t\t\t\tExtraConfig: map[string]any{\n\t\t\t\t\t\"oomScoreAdj\": \"v1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"error unmarshalling extra kubelet configuration: unrecognized type: int32\",\n\t\t},\n\t\t{\n\t\t\tname: \"not overridable\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.96.0.10\"},\n\t\t\t\tClusterDomain: \"cluster.svc\",\n\t\t\t\tExtraConfig: map[string]any{\n\t\t\t\t\t\"oomScoreAdj\":    -300,\n\t\t\t\t\t\"port\":           81,\n\t\t\t\t\t\"authentication\": nil,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"2 errors occurred:\\n\\t* field \\\"authentication\\\" can't be overridden\\n\\t* field \\\"port\\\" can't be overridden\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(\n\t\t\ttt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\t_, err := k8sctrl.NewKubeletConfiguration(tt.cfgSpec, compatibility.VersionFromImageRef(\"\"), machine.TypeWorker)\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, tt.expectedErr)\n\t\t\t},\n\t\t)\n\t}\n}\n\nfunc TestNewKubeletConfigurationMerge(t *testing.T) {\n\tt.Parallel()\n\n\tdefaultKubeletConfig := kubeletconfig.KubeletConfiguration{\n\t\tTypeMeta: metav1.TypeMeta{\n\t\t\tAPIVersion: kubeletconfig.SchemeGroupVersion.String(),\n\t\t\tKind:       \"KubeletConfiguration\",\n\t\t},\n\t\tPort: constants.KubeletPort,\n\t\tAuthentication: kubeletconfig.KubeletAuthentication{\n\t\t\tX509: kubeletconfig.KubeletX509Authentication{\n\t\t\t\tClientCAFile: constants.KubernetesCACert,\n\t\t\t},\n\t\t\tWebhook: kubeletconfig.KubeletWebhookAuthentication{\n\t\t\t\tEnabled: new(true),\n\t\t\t},\n\t\t\tAnonymous: kubeletconfig.KubeletAnonymousAuthentication{\n\t\t\t\tEnabled: new(false),\n\t\t\t},\n\t\t},\n\t\tAuthorization: kubeletconfig.KubeletAuthorization{\n\t\t\tMode: kubeletconfig.KubeletAuthorizationModeWebhook,\n\t\t},\n\t\tCgroupRoot:            \"/\",\n\t\tSystemCgroups:         constants.CgroupSystem,\n\t\tKubeletCgroups:        constants.CgroupKubelet,\n\t\tRotateCertificates:    true,\n\t\tProtectKernelDefaults: true,\n\t\tAddress:               \"0.0.0.0\",\n\t\tOOMScoreAdj:           new(int32(constants.KubeletOOMScoreAdj)),\n\t\tClusterDomain:         \"cluster.local\",\n\t\tClusterDNS:            []string{\"10.0.0.5\"},\n\t\tSerializeImagePulls:   new(false),\n\t\tFailSwapOn:            new(false),\n\t\tSystemReserved: map[string]string{\n\t\t\t\"cpu\":               constants.KubeletSystemReservedCPU,\n\t\t\t\"memory\":            constants.KubeletSystemReservedMemoryWorker,\n\t\t\t\"pid\":               constants.KubeletSystemReservedPid,\n\t\t\t\"ephemeral-storage\": constants.KubeletSystemReservedEphemeralStorage,\n\t\t},\n\t\tLogging: v1.LoggingConfiguration{\n\t\t\tFormat: \"json\",\n\t\t},\n\t\tShutdownGracePeriod:             metav1.Duration{Duration: constants.KubeletShutdownGracePeriod},\n\t\tShutdownGracePeriodCriticalPods: metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods},\n\t\tStreamingConnectionIdleTimeout:  metav1.Duration{Duration: 5 * time.Minute},\n\t\tTLSMinVersion:                   \"VersionTLS13\",\n\t\tStaticPodPath:                   constants.ManifestsDirectory,\n\t\tContainerRuntimeEndpoint:        \"unix://\" + constants.CRIContainerdAddress,\n\t\tResolverConfig:                  new(constants.PodResolvConfPath),\n\t}\n\n\tfor _, tt := range []struct {\n\t\tname              string\n\t\tcfgSpec           *k8s.KubeletConfigSpec\n\t\tkubeletVersion    compatibility.Version\n\t\texpectedOverrides func(*kubeletconfig.KubeletConfiguration)\n\t\tmachineType       machine.Type\n\t}{\n\t\t{\n\t\t\tname: \"override some\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain: \"cluster.local\",\n\t\t\t\tExtraConfig: map[string]any{\n\t\t\t\t\t\"oomScoreAdj\":             -300,\n\t\t\t\t\t\"enableDebuggingHandlers\": true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.OOMScoreAdj = new(int32(-300))\n\t\t\t\tkc.EnableDebuggingHandlers = new(true)\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t\t{\n\t\t\tname: \"controlplane\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain: \"cluster.local\",\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.SystemReserved[\"memory\"] = constants.KubeletSystemReservedMemoryControlPlane\n\t\t\t\tkc.RegisterWithTaints = []corev1.Taint{\n\t\t\t\t\t{\n\t\t\t\t\t\tKey:    constants.LabelNodeRoleControlPlane,\n\t\t\t\t\t\tEffect: corev1.TaintEffectNoSchedule,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\tmachineType: machine.TypeControlPlane,\n\t\t},\n\t\t{\n\t\t\tname: \"disable graceful shutdown\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:    []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain: \"cluster.local\",\n\t\t\t\tExtraConfig: map[string]any{\n\t\t\t\t\t\"shutdownGracePeriod\":             \"0s\",\n\t\t\t\t\t\"shutdownGracePeriodCriticalPods\": \"0s\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.ShutdownGracePeriod = metav1.Duration{}\n\t\t\t\tkc.ShutdownGracePeriodCriticalPods = metav1.Duration{}\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t\t{\n\t\t\tname: \"enable seccomp default\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:                   []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain:                \"cluster.local\",\n\t\t\t\tDefaultRuntimeSeccompEnabled: true,\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.SeccompDefault = new(true)\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t\t{\n\t\t\tname: \"enable skipNodeRegistration\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:           []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain:        \"cluster.local\",\n\t\t\t\tSkipNodeRegistration: true,\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.Authentication.Webhook.Enabled = new(false)\n\t\t\t\tkc.Authorization.Mode = kubeletconfig.KubeletAuthorizationModeAlwaysAllow\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t\t{\n\t\t\tname: \"disable manifests directory\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:                []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain:             \"cluster.local\",\n\t\t\t\tDisableManifestsDirectory: true,\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.StaticPodPath = \"\"\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t\t{\n\t\t\tname: \"enable local FS quota monitoring\",\n\t\t\tcfgSpec: &k8s.KubeletConfigSpec{\n\t\t\t\tClusterDNS:              []string{\"10.0.0.5\"},\n\t\t\t\tClusterDomain:           \"cluster.local\",\n\t\t\t\tEnableFSQuotaMonitoring: true,\n\t\t\t},\n\t\t\tkubeletVersion: compatibility.VersionFromImageRef(\"ghcr.io/siderolabs/kubelet:v1.29.0\"),\n\t\t\texpectedOverrides: func(kc *kubeletconfig.KubeletConfiguration) {\n\t\t\t\tkc.FeatureGates = map[string]bool{\n\t\t\t\t\t\"LocalStorageCapacityIsolationFSQuotaMonitoring\": true,\n\t\t\t\t}\n\t\t\t},\n\t\t\tmachineType: machine.TypeWorker,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\texpected := defaultKubeletConfig.DeepCopy()\n\t\t\ttt.expectedOverrides(expected)\n\n\t\t\tconfig, err := k8sctrl.NewKubeletConfiguration(tt.cfgSpec, tt.kubeletVersion, tt.machineType)\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, expected, config)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubelet_static_pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes/kubelet\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// KubeletStaticPodController renders static pod definitions and manages k8s.StaticPodStatus.\ntype KubeletStaticPodController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubeletStaticPodController) Name() string {\n\treturn \"k8s.KubeletStaticPodController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubeletStaticPodController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"kubelet\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesDynamicCertsType,\n\t\t\tID:        optional.Some(secrets.KubernetesDynamicCertsID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubeletStaticPodController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.StaticPodStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KubeletStaticPodController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tvar kubeletClient *kubelet.Client\n\n\trefreshTicker := time.NewTicker(15 * time.Second) // refresh kubelet pods status every 15 seconds\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-refreshTicker.C:\n\t\t\tif kubeletClient != nil {\n\t\t\t\tif err := ctrl.refreshPodStatus(ctx, r, kubeletClient); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error refreshing pod status: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontinue\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tkubeletService, err := safe.ReaderGet[*v1alpha1.Service](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, \"kubelet\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tkubeletClient = nil\n\n\t\t\t\tif err = ctrl.teardownStatuses(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !kubeletService.TypedSpec().Running {\n\t\t\tkubeletClient = nil\n\n\t\t\tif err = ctrl.teardownStatuses(ctx, r); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// on worker nodes, there's no way to connect to the kubelet to fetch the pod status (only API server can do that)\n\t\t// on control plane nodes, use API servers' client kubelet certificate to fetch statuses\n\t\trootSecrets, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tkubeletClient = nil\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tcertsResource, err := safe.ReaderGet[*secrets.KubernetesDynamicCerts](\n\t\t\tctx, r,\n\t\t\tresource.NewMetadata(secrets.NamespaceName, secrets.KubernetesDynamicCertsType, secrets.KubernetesDynamicCertsID, resource.VersionUndefined),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tkubeletClient = nil\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tcerts := certsResource.TypedSpec()\n\n\t\tnodename, err := safe.ReaderGet[*k8s.Nodename](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, k8s.NodenameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\t// nodename should exist if the kubelet is running\n\t\t\treturn err\n\t\t}\n\n\t\tkubeletClient, err = kubelet.NewClient(\n\t\t\tnodename.TypedSpec().Nodename,\n\t\t\tcerts.APIServerKubeletClient.Crt,\n\t\t\tcerts.APIServerKubeletClient.Key,\n\t\t\trootSecrets.TypedSpec().IssuingCA.Crt,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error building kubelet client: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *KubeletStaticPodController) teardownStatuses(ctx context.Context, r controller.Runtime) error {\n\tstatuses, err := r.List(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodStatusType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing pod statuses: %w\", err)\n\t}\n\n\tfor _, status := range statuses.Items {\n\t\t// TODO: proper teardown sequence?\n\t\tif err = r.Destroy(ctx, status.Metadata()); err != nil {\n\t\t\treturn fmt.Errorf(\"error destroying stale pod status: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *KubeletStaticPodController) refreshPodStatus(ctx context.Context, r controller.Runtime, kubeletClient *kubelet.Client) error {\n\tpodList, err := kubeletClient.Pods(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching pod status: %w\", err)\n\t}\n\n\tpodsSeen := map[string]struct{}{}\n\n\tfor _, pod := range podList.Items {\n\t\tswitch pod.Metadata.Annotations.ConfigSource {\n\t\tcase \"file\":\n\t\t\t// static pod from a file source\n\t\tcase \"http\":\n\t\t\t// static pod from an HTTP source\n\t\tdefault:\n\t\t\t// anything else is not a static pod, skip it\n\t\t\tcontinue\n\t\t}\n\n\t\tstatusID := fmt.Sprintf(\"%s/%s\", pod.Metadata.Namespace, pod.Metadata.Name)\n\n\t\tpodsSeen[statusID] = struct{}{}\n\n\t\tif err = safe.WriterModify(ctx, r, k8s.NewStaticPodStatus(k8s.NamespaceName, statusID), func(r *k8s.StaticPodStatus) error {\n\t\t\treturn k8sadapter.StaticPodStatus(r).SetStatus(&pod.Status)\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating pod status: %w\", err)\n\t\t}\n\t}\n\n\tstatuses, err := r.List(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodStatusType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing pod statuses: %w\", err)\n\t}\n\n\tfor _, status := range statuses.Items {\n\t\tif _, exists := podsSeen[status.Metadata().ID()]; !exists {\n\t\t\t// TODO: proper teardown sequence?\n\t\t\tif err = r.Destroy(ctx, status.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error destroying stale pod status: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubeprism.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-loadbalancer/controlplane\"\n\t\"github.com/siderolabs/go-loadbalancer/upstream\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubePrismController creates KubePrism load balancer based on KubePrismEndpointsType resource.\ntype KubePrismController struct {\n\tbalancerHost string\n\tbalancerPort int\n\tlb           *controlplane.LoadBalancer\n\tticker       *time.Ticker\n\tupstreamCh   chan []string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubePrismController) Name() string {\n\treturn \"k8s.KubePrismController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubePrismController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.KubePrismConfigType,\n\t\t\tID:        optional.Some(k8s.KubePrismConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubePrismController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.KubePrismStatusesType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KubePrismController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tlogger = logger.Named(\"kubeprism\")\n\n\tdefer func() {\n\t\tif ctrl.lb == nil {\n\t\t\treturn\n\t\t}\n\n\t\tctrl.stopKubePrism(logger) //nolint:errcheck\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ctrl.takeTickerC():\n\t\t\terr := ctrl.writeKubePrismStatus(ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tlbCfg, err := safe.ReaderGetByID[*k8s.KubePrismConfig](ctx, r, k8s.KubePrismConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch {\n\t\tcase ctrl.lb == nil && lbCfg != nil:\n\t\t\terr = ctrl.startKubePrism(lbCfg, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase ctrl.lb != nil && lbCfg == nil:\n\t\t\terr = ctrl.stopKubePrism(logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase ctrl.lb != nil && lbCfg != nil:\n\t\t\tif lbCfg.TypedSpec().Host != ctrl.balancerHost || lbCfg.TypedSpec().Port != ctrl.balancerPort {\n\t\t\t\terr = ctrl.stopKubePrism(logger)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\terr = ctrl.startKubePrism(lbCfg, logger)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tctrl.upstreamChan() <- makeEndpoints(lbCfg.TypedSpec())\n\t\t\t}\n\t\t}\n\n\t\terr = ctrl.writeKubePrismStatus(ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *KubePrismController) writeKubePrismStatus(\n\tctx context.Context,\n\tr controller.Runtime,\n) error {\n\tif ctrl.lb != nil && ctrl.endpoint() != \"\" {\n\t\thealthy, err := ctrl.lb.Healthy()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to check KubePrism health: %w\", err)\n\t\t}\n\n\t\tgot, err := safe.ReaderGetByID[*k8s.KubePrismStatuses](ctx, r, k8s.KubePrismStatusesID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get KubePrism status: %w\", err)\n\t\t}\n\n\t\tif got != nil && got.TypedSpec().Healthy == healthy {\n\t\t\treturn nil\n\t\t}\n\n\t\terr = safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tk8s.NewKubePrismStatuses(k8s.NamespaceName, k8s.KubePrismStatusesID),\n\t\t\tfunc(res *k8s.KubePrismStatuses) error {\n\t\t\t\tres.TypedSpec().Host = ctrl.endpoint()\n\t\t\t\tres.TypedSpec().Healthy = healthy\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write KubePrism status: %w\", err)\n\t\t}\n\t}\n\n\t// list keys for cleanup\n\tlist, err := safe.ReaderListAll[*k8s.KubePrismStatuses](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing KubePrism resources: %w\", err)\n\t}\n\n\tfor res := range list.All() {\n\t\tif ctrl.lb == nil || res.Metadata().ID() != k8s.KubePrismStatusesID {\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error cleaning up KubePrism specs: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *KubePrismController) startKubePrism(lbCfg *k8s.KubePrismConfig, logger *zap.Logger) error {\n\tspec := lbCfg.TypedSpec()\n\tctrl.balancerHost = spec.Host\n\tctrl.balancerPort = spec.Port\n\n\tlb, err := controlplane.NewLoadBalancer(ctrl.balancerHost, ctrl.balancerPort,\n\t\tlogger.WithOptions(zap.IncreaseLevel(zap.ErrorLevel)), // silence the load balancer logs\n\t\tcontrolplane.WithDialTimeout(constants.KubePrismDialTimeout),\n\t\tcontrolplane.WithKeepAlivePeriod(constants.KubePrismKeepAlivePeriod),\n\t\tcontrolplane.WithTCPUserTimeout(constants.KubePrismTCPUserTimeout),\n\t\tcontrolplane.WithHealthCheckOptions(\n\t\t\tupstream.WithHealthcheckInterval(constants.KubePrismHealthCheckInterval),\n\t\t\tupstream.WithHealthcheckTimeout(constants.KubePrismHealthCheckTimeout),\n\t\t),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create KubePrism: %w\", err)\n\t}\n\n\terr = lb.Start(ctrl.upstreamChan())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start KubePrism: %w\", err)\n\t}\n\n\tlogger.Info(\"KubePrism is enabled\", zap.String(\"endpoint\", ctrl.endpoint()))\n\n\tctrl.upstreamChan() <- makeEndpoints(spec)\n\n\tctrl.lb = lb\n\n\treturn nil\n}\n\nfunc makeEndpoints(spec *k8s.KubePrismConfigSpec) []string {\n\treturn xslices.Map(spec.Endpoints, func(e k8s.KubePrismEndpoint) string {\n\t\treturn net.JoinHostPort(e.Host, strconv.FormatUint(uint64(e.Port), 10))\n\t})\n}\n\nfunc (ctrl *KubePrismController) takeTickerC() <-chan time.Time {\n\tswitch {\n\tcase ctrl.lb == nil && ctrl.ticker == nil:\n\t\treturn nil\n\tcase ctrl.lb != nil && ctrl.ticker == nil:\n\t\tctrl.ticker = time.NewTicker(5 * time.Second)\n\n\t\treturn ctrl.ticker.C\n\tcase ctrl.lb == nil:\n\t\tticker := replaceWithZero(&ctrl.ticker)\n\t\tif ticker != nil {\n\t\t\tticker.Stop()\n\t\t}\n\n\t\treturn nil\n\tdefault:\n\t\treturn ctrl.ticker.C\n\t}\n}\n\nfunc (ctrl *KubePrismController) endpoint() string {\n\treturn net.JoinHostPort(ctrl.balancerHost, strconv.FormatUint(uint64(ctrl.balancerPort), 10))\n}\n\nfunc (ctrl *KubePrismController) upstreamChan() chan []string {\n\tif ctrl.upstreamCh == nil {\n\t\tctrl.upstreamCh = make(chan []string)\n\t}\n\n\treturn ctrl.upstreamCh\n}\n\nfunc (ctrl *KubePrismController) stopKubePrism(logger *zap.Logger) error {\n\treplaceWithZero(&ctrl.upstreamCh)\n\n\tlb := replaceWithZero(&ctrl.lb)\n\n\terr := lb.Shutdown()\n\tif err != nil {\n\t\tlogger.Error(\"failed to shutdown KubePrism\", zap.Error(err))\n\n\t\treturn err\n\t}\n\n\tlogger.Info(\"KubePrism is disabled\")\n\n\treturn nil\n}\n\nfunc replaceWithZero[T any](v *T) T {\n\tvar zero T\n\n\tresult := *v\n\n\t*v = zero\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubeprism_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubePrismConfigController creates config for KubePrism.\ntype KubePrismConfigController = transform.Controller[*config.MachineConfig, *k8s.KubePrismConfig]\n\n// NewKubePrismConfigController instanciates the controller.\nfunc NewKubePrismConfigController() *KubePrismConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.KubePrismConfig]{\n\t\t\tName: \"k8s.KubePrismConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*k8s.KubePrismConfig] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*k8s.KubePrismConfig]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Machine() == nil {\n\t\t\t\t\treturn optional.None[*k8s.KubePrismConfig]()\n\t\t\t\t}\n\n\t\t\t\tif !cfg.Config().Machine().Features().KubePrism().Enabled() {\n\t\t\t\t\treturn optional.None[*k8s.KubePrismConfig]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(k8s.NewKubePrismConfig(k8s.NamespaceName, k8s.KubePrismConfigID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *k8s.KubePrismConfig) error {\n\t\t\t\tendpt, err := safe.ReaderGetByID[*k8s.KubePrismEndpoints](ctx, r, k8s.KubePrismEndpointsID)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn xerrors.NewTaggedf[transform.SkipReconcileTag](\"KubePrism endpoints resource not found; not creating KubePrism config\")\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tspec := res.TypedSpec()\n\t\t\t\tspec.Endpoints = endpt.TypedSpec().Endpoints\n\t\t\t\tspec.Host = \"127.0.0.1\"\n\t\t\t\tspec.Port = cfg.Config().Machine().Features().KubePrism().Port()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\ttransform.WithExtraInputs(\n\t\t\tsafe.Input[*k8s.KubePrismEndpoints](controller.InputWeak),\n\t\t),\n\t)\n}\n\nfunc toPort(port string) uint32 {\n\tif port == \"\" {\n\t\treturn 443\n\t}\n\n\tp, err := strconv.ParseUint(port, 10, 32)\n\tif err != nil {\n\t\treturn 443\n\t}\n\n\treturn uint32(p)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubeprism_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype KubePrismConfigControllerSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubePrismConfigControllerSuite) TestGeneration() {\n\tcfg := &v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tKubePrismSupport: &v1alpha1.KubePrism{\n\t\t\t\t\tServerEnabled: new(true),\n\t\t\t\t\tServerPort:    7445,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\tURL: must(url.Parse(\"https://example.com\"))(suite.Require()),\n\t\t\t\t},\n\t\t\t\tLocalAPIServerPort: 6445,\n\t\t\t},\n\t\t},\n\t}\n\n\tmc := config.NewMachineConfig(container.NewV1Alpha1(cfg))\n\tsuite.Create(mc)\n\n\tendpoints := k8s.NewKubePrismEndpoints(k8s.NamespaceName, k8s.KubePrismEndpointsID)\n\tendpoints.TypedSpec().Endpoints = []k8s.KubePrismEndpoint{\n\t\t{Host: \"example.com\", Port: 443},\n\t\t{Host: \"localhost\", Port: 6445},\n\t\t{Host: \"192.168.3.4\", Port: 6446},\n\t\t{Host: \"192.168.3.6\", Port: 6443},\n\t}\n\n\tsuite.Create(endpoints)\n\n\tctest.AssertResource(suite, k8s.KubePrismConfigID, func(e *k8s.KubePrismConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t&k8s.KubePrismConfigSpec{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: 7445,\n\t\t\t\tEndpoints: []k8s.KubePrismEndpoint{\n\t\t\t\t\t{Host: \"example.com\", Port: 443},\n\t\t\t\t\t{Host: \"localhost\", Port: 6445},\n\t\t\t\t\t{Host: \"192.168.3.4\", Port: 6446},\n\t\t\t\t\t{Host: \"192.168.3.6\", Port: 6443},\n\t\t\t\t},\n\t\t\t},\n\t\t\te.TypedSpec(),\n\t\t)\n\t})\n\n\tctest.UpdateWithConflicts(suite, mc, func(cfg *config.MachineConfig) error {\n\t\tbalancer := cfg.Config().Machine().Features().KubePrism().(*v1alpha1.KubePrism)\n\t\tbalancer.ServerEnabled = new(false)\n\n\t\treturn nil\n\t})\n\n\tctest.AssertNoResource[*k8s.KubePrismConfig](suite, k8s.KubePrismConfigID)\n\n\tctest.UpdateWithConflicts(suite, mc, func(cfg *config.MachineConfig) error {\n\t\tbalancer := cfg.Config().Machine().Features().KubePrism().(*v1alpha1.KubePrism)\n\t\tbalancer.ServerEnabled = new(true)\n\t\tbalancer.ServerPort = 7446\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, k8s.KubePrismConfigID, func(e *k8s.KubePrismConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t&k8s.KubePrismConfigSpec{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: 7446,\n\t\t\t\tEndpoints: []k8s.KubePrismEndpoint{\n\t\t\t\t\t{Host: \"example.com\", Port: 443},\n\t\t\t\t\t{Host: \"localhost\", Port: 6445},\n\t\t\t\t\t{Host: \"192.168.3.4\", Port: 6446},\n\t\t\t\t\t{Host: \"192.168.3.6\", Port: 6443},\n\t\t\t\t},\n\t\t\t},\n\t\t\te.TypedSpec(),\n\t\t)\n\t})\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), mc.Metadata()))\n\n\tctest.AssertNoResource[*k8s.KubePrismConfig](suite, k8s.KubePrismConfigID)\n\n\tsuite.Create(mc)\n\n\tctest.AssertResource(suite, k8s.KubePrismConfigID, func(e *k8s.KubePrismConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t&k8s.KubePrismConfigSpec{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t\tPort: 7445,\n\t\t\t\tEndpoints: []k8s.KubePrismEndpoint{\n\t\t\t\t\t{Host: \"example.com\", Port: 443},\n\t\t\t\t\t{Host: \"localhost\", Port: 6445},\n\t\t\t\t\t{Host: \"192.168.3.4\", Port: 6446},\n\t\t\t\t\t{Host: \"192.168.3.6\", Port: 6443},\n\t\t\t\t},\n\t\t\t},\n\t\t\te.TypedSpec(),\n\t\t)\n\t})\n}\n\nfunc TestEndpointsBalancerConfigControllerSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &KubePrismConfigControllerSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(clusterctrl.NewKubePrismConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubeprism_endpoints.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// KubePrismEndpointsController creates a list of API server endpoints.\ntype KubePrismEndpointsController = transform.Controller[*config.MachineConfig, *k8s.KubePrismEndpoints]\n\n// NewKubePrismEndpointsController instanciates the controller.\n//\n//nolint:gocyclo\nfunc NewKubePrismEndpointsController() *KubePrismEndpointsController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.KubePrismEndpoints]{\n\t\t\tName: \"k8s.KubePrismEndpointsController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*k8s.KubePrismEndpoints] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*k8s.KubePrismEndpoints]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {\n\t\t\t\t\treturn optional.None[*k8s.KubePrismEndpoints]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(k8s.NewKubePrismEndpoints(k8s.NamespaceName, k8s.KubePrismEndpointsID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, machineConfig *config.MachineConfig, res *k8s.KubePrismEndpoints) error {\n\t\t\t\tmembers, err := safe.ReaderListAll[*cluster.Member](ctx, r)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error listing affiliates: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tvar endpoints []k8s.KubePrismEndpoint\n\n\t\t\t\tce := machineConfig.Config().Cluster().Endpoint()\n\t\t\t\tif ce != nil {\n\t\t\t\t\tendpoints = append(endpoints, k8s.KubePrismEndpoint{\n\t\t\t\t\t\tHost: ce.Hostname(),\n\t\t\t\t\t\tPort: toPort(ce.Port()),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif machineConfig.Config().Machine().Type().IsControlPlane() {\n\t\t\t\t\tendpoints = append(endpoints, k8s.KubePrismEndpoint{\n\t\t\t\t\t\tHost: \"localhost\",\n\t\t\t\t\t\tPort: uint32(machineConfig.Config().Cluster().LocalAPIServerPort()),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tfor member := range members.All() {\n\t\t\t\t\tmemberSpec := member.TypedSpec()\n\n\t\t\t\t\tif len(memberSpec.Addresses) > 0 && memberSpec.ControlPlane != nil {\n\t\t\t\t\t\tfor _, addr := range memberSpec.Addresses {\n\t\t\t\t\t\t\tendpoints = append(endpoints, k8s.KubePrismEndpoint{\n\t\t\t\t\t\t\t\tHost: addr.String(),\n\t\t\t\t\t\t\t\tPort: uint32(memberSpec.ControlPlane.APIServerPort),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tres.TypedSpec().Endpoints = endpoints\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t\ttransform.WithExtraInputs(\n\t\t\tsafe.Input[*cluster.Member](controller.InputWeak),\n\t\t),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/kubeprism_endpoints_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tclusterctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype KubePrismControllerSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubePrismControllerSuite) TestGeneration() {\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Create(nodeIdentity)\n\n\tmc := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\tURL: must(url.Parse(\"https://example.com\"))(suite.Require()),\n\t\t\t\t},\n\t\t\t\tLocalAPIServerPort: 6445,\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Create(mc)\n\n\tmember1 := cluster.NewMember(cluster.NamespaceName, \"service/7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*member1.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:       \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:     \"foo.com\",\n\t\tMachineType:  machine.TypeControlPlane,\n\t\tAddresses:    []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6446},\n\t}\n\n\tsuite.Create(member1)\n\n\tmember2 := cluster.NewMember(cluster.NamespaceName, \"service/xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\")\n\t*member2.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:       nodeIdentity.TypedSpec().NodeID,\n\t\tHostname:     \"foo2.com\",\n\t\tMachineType:  machine.TypeControlPlane,\n\t\tAddresses:    []netip.Addr{netip.MustParseAddr(\"192.168.3.6\")},\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t}\n\n\tsuite.Create(member2)\n\n\tmember3 := cluster.NewMember(cluster.NamespaceName, \"service/9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\")\n\t*member3.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID:      \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tHostname:    \"worker-1\",\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.5\")},\n\t}\n\n\tsuite.Create(member3)\n\n\tctest.AssertResource(suite, k8s.KubePrismEndpointsID, func(e *k8s.KubePrismEndpoints, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t&k8s.KubePrismEndpointsSpec{\n\t\t\t\tEndpoints: []k8s.KubePrismEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tHost: \"example.com\",\n\t\t\t\t\t\tPort: 443,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tHost: \"localhost\",\n\t\t\t\t\t\tPort: 6445,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tHost: \"192.168.3.4\",\n\t\t\t\t\t\tPort: 6446,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tHost: \"192.168.3.6\",\n\t\t\t\t\t\tPort: 6443,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\te.TypedSpec(),\n\t\t)\n\t})\n}\n\nfunc must[T any](res T, err error) func(t *require.Assertions) T {\n\treturn func(t *require.Assertions) T {\n\t\tt.NoError(err)\n\n\t\treturn res\n\t}\n}\n\nfunc TestEndpointsBalancerControllerSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &KubePrismControllerSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(clusterctrl.NewKubePrismEndpointsController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/manifest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/k8stemplates\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// ManifestController renders manifests based on templates and config/secrets.\ntype ManifestController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ManifestController) Name() string {\n\treturn \"k8s.ManifestController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ManifestController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.BootstrapManifestsConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ManifestController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.ManifestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ManifestController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tconfigResource, err := safe.ReaderGetByID[*k8s.BootstrapManifestsConfig](ctx, r, k8s.BootstrapManifestsConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tconfig := *configResource.TypedSpec()\n\n\t\tsecretsResources, err := safe.ReaderGetByID[*secrets.KubernetesRoot](ctx, r, secrets.KubernetesRootID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error tearing down: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tsecrets := secretsResources.TypedSpec()\n\n\t\trenderedManifests, err := ctrl.render(config, secrets)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, renderedManifest := range renderedManifests {\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewManifest(k8s.ControlPlaneNamespaceName, renderedManifest.name),\n\t\t\t\tfunc(r *k8s.Manifest) error {\n\t\t\t\t\treturn k8sadapter.Manifest(r).SetObjects(renderedManifest.objs)\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating manifest %q: %w\", renderedManifest.name, err)\n\t\t\t}\n\t\t}\n\n\t\t// remove any manifests which weren't rendered\n\t\tmanifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing manifests: %w\", err)\n\t\t}\n\n\t\tmanifestsToDelete := make(map[string]struct{}, len(manifests.Items))\n\n\t\tfor _, manifest := range manifests.Items {\n\t\t\tif manifest.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmanifestsToDelete[manifest.Metadata().ID()] = struct{}{}\n\t\t}\n\n\t\tfor _, renderedManifest := range renderedManifests {\n\t\t\tdelete(manifestsToDelete, renderedManifest.name)\n\t\t}\n\n\t\tfor id := range manifestsToDelete {\n\t\t\tif err = r.Destroy(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, id, resource.VersionUndefined)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error cleaning up manifests: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\ntype renderedManifest struct {\n\tname string\n\tobjs []runtime.Object\n}\n\nfunc (ctrl *ManifestController) render(cfg k8s.BootstrapManifestsConfigSpec, scrt *secrets.KubernetesRootSpec) ([]renderedManifest, error) {\n\tmanifests := []renderedManifest{\n\t\t{\n\t\t\t\"00-kubelet-bootstrapping-token\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.KubeletBootstrapTokenSecret(scrt),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"01-csr-node-bootstrap\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.CSRNodeBootstrapTemplate(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"01-csr-approver-role-binding\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.CSRApproverRoleBindingTemplate(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"01-csr-renewal-role-binding\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.CSRRenewalRoleBindingTemplate(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"11-kube-config-in-cluster\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.KubeconfigInClusterTemplate(&cfg),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"11-talos-node-rbac-template\",\n\t\t\t[]runtime.Object{\n\t\t\t\tk8stemplates.TalosNodesRBACClusterRoleBinding(),\n\t\t\t\tk8stemplates.TalosNodesRBACClusterRole(),\n\t\t\t},\n\t\t},\n\t}\n\n\tif cfg.CoreDNSEnabled {\n\t\tmanifests = append(manifests,\n\t\t\trenderedManifest{\n\t\t\t\t\"11-core-dns\",\n\t\t\t\t[]runtime.Object{\n\t\t\t\t\tk8stemplates.CoreDNSServiceAccount(),\n\t\t\t\t\tk8stemplates.CoreDNSClusterRole(),\n\t\t\t\t\tk8stemplates.CoreDNSClusterRoleBinding(),\n\t\t\t\t\tk8stemplates.CoreDNSConfigMap(&cfg),\n\t\t\t\t\tk8stemplates.CoreDNSDeployment(&cfg),\n\t\t\t\t},\n\t\t\t},\n\t\t\trenderedManifest{\n\t\t\t\t\"11-core-dns-svc\",\n\t\t\t\t[]runtime.Object{\n\t\t\t\t\tk8stemplates.CoreDNSService(&cfg),\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\tif cfg.FlannelEnabled {\n\t\tmanifests = append(manifests,\n\t\t\trenderedManifest{\n\t\t\t\t\"05-flannel\",\n\t\t\t\t[]runtime.Object{\n\t\t\t\t\tk8stemplates.FlannelClusterRoleTemplate(&cfg),\n\t\t\t\t\tk8stemplates.FlannelClusterRoleBindingTemplate(),\n\t\t\t\t\tk8stemplates.FlannelServiceAccountTemplate(),\n\t\t\t\t\tk8stemplates.FlannelConfigMapTemplate(&cfg),\n\t\t\t\t\tk8stemplates.FlannelDaemonSetTemplate(&cfg),\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\tif cfg.ProxyEnabled {\n\t\tmanifests = append(manifests,\n\t\t\trenderedManifest{\n\t\t\t\t\"10-kube-proxy\",\n\t\t\t\t[]runtime.Object{\n\t\t\t\t\tk8stemplates.KubeProxyDaemonSetTemplate(&cfg),\n\t\t\t\t\tk8stemplates.KubeProxyServiceAccount(),\n\t\t\t\t\tk8stemplates.KubeProxyClusterRoleBinding(),\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\tif cfg.PodSecurityPolicyEnabled {\n\t\treturn nil, fmt.Errorf(\"pod security policies are not supported anymore, please remove the flag from the configuration\")\n\t}\n\n\tif cfg.TalosAPIServiceEnabled {\n\t\tmanifests = append(manifests,\n\t\t\trenderedManifest{\n\t\t\t\t\"13-talos-service-account-crd\",\n\t\t\t\t[]runtime.Object{\n\t\t\t\t\tk8stemplates.TalosServiceAccountCRDTemplate(),\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\treturn manifests, nil\n}\n\n//nolint:dupl\nfunc (ctrl *ManifestController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tmanifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing manifests: %w\", err)\n\t}\n\n\tfor _, manifest := range manifests.Items {\n\t\tif manifest.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = r.Destroy(ctx, manifest.Metadata()); err != nil {\n\t\t\treturn fmt.Errorf(\"error destroying manifest: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// TalosServiceAccount is a struct used by the template engine which contains the needed variables to\n// be able to construct the Talos Service Account CRD.\ntype TalosServiceAccount struct {\n\tGroup            string\n\tVersion          string\n\tKind             string\n\tResourceSingular string\n\tResourcePlural   string\n\tShortName        string\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/manifest_apply.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"sort\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa/object\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\t\"k8s.io/apimachinery/pkg/api/meta\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime/schema\"\n\t\"k8s.io/client-go/discovery\"\n\t\"k8s.io/client-go/discovery/cached/memory\"\n\t\"k8s.io/client-go/dynamic\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/restmapper\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// ManifestApplyController applies manifests via control plane endpoint.\ntype ManifestApplyController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ManifestApplyController) Name() string {\n\treturn \"k8s.ManifestApplyController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ManifestApplyController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesType,\n\t\t\tID:        optional.Some(secrets.KubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.ManifestType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(\"etcd\"),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ManifestApplyController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.ManifestStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ManifestApplyController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tsecretsResources, err := safe.ReaderGetByID[*secrets.Kubernetes](ctx, r, secrets.KubernetesID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tsecrets := secretsResources.TypedSpec()\n\n\t\t// wait for etcd to be healthy as controller relies on etcd for locking\n\t\tetcdResource, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"etcd\")\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !etcdResource.TypedSpec().Healthy {\n\t\t\tcontinue\n\t\t}\n\n\t\tmanifests, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing manifests: %w\", err)\n\t\t}\n\n\t\tslices.SortFunc(manifests.Items, func(a, b resource.Resource) int {\n\t\t\treturn cmp.Compare(a.Metadata().ID(), b.Metadata().ID())\n\t\t})\n\n\t\tif len(manifests.Items) > 0 {\n\t\t\tif err = ctrl.applyManifests(ctx, logger, manifests, secrets); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, k8s.NewManifestStatus(k8s.ControlPlaneNamespaceName), func(r *k8s.ManifestStatus) error {\n\t\t\tstatus := r.TypedSpec()\n\n\t\t\tstatus.ManifestsApplied = xslices.Map(manifests.Items, func(m resource.Resource) string {\n\t\t\t\treturn m.Metadata().ID()\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating manifest status: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *ManifestApplyController) applyManifests(\n\tctx context.Context,\n\tlogger *zap.Logger,\n\tmanifests resource.List,\n\tsecrets *secrets.KubernetesCertsSpec,\n) error {\n\tkubeconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\treturn clientcmd.Load([]byte(secrets.LocalhostAdminKubeconfig))\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error loading kubeconfig: %w\", err)\n\t}\n\n\tkubeconfig.WarningHandler = rest.NewWarningWriter(logging.NewWriter(logger, zapcore.WarnLevel), rest.WarningWriterOptions{\n\t\tDeduplicate: true,\n\t})\n\n\thttpClient, err := rest.HTTPClientFor(kubeconfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building HTTP client for kubeconfig: %w\", err)\n\t}\n\n\tdefer httpClient.CloseIdleConnections()\n\n\tdiscoveryClient, err := discovery.NewDiscoveryClientForConfigAndClient(kubeconfig, httpClient)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building discovery client: %w\", err)\n\t}\n\n\tdyn, err := dynamic.NewForConfigAndClient(kubeconfig, httpClient)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building dynamic client: %w\", err)\n\t}\n\n\tdc := memory.NewMemCacheClient(discoveryClient)\n\tmapper := restmapper.NewDeferredDiscoveryRESTMapper(dc)\n\n\tk8sClient, err := kubernetes.NewForConfigAndClient(kubeconfig, httpClient)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = etcd.WithLock(ctx, constants.EtcdTalosManifestApplyMutex, logger, func() error {\n\t\tinv, err := ssa.GetInventory(ctx, k8sClient, constants.KubernetesInventoryNamespace, constants.KubernetesBootstrapManifestsInventoryName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting inventory: %w\", err)\n\t\t}\n\n\t\tinventoryContents := inv.Get()\n\n\t\tinventoryContents, applyErr := ctrl.apply(ctx, logger, mapper, dyn, manifests, inventoryContents)\n\n\t\tinv.Update(inventoryContents)\n\n\t\t// update inventory even if the apply process failed half way through\n\t\terr = inv.Write(ctx)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"updating inventory failed: %w\", err)\n\t\t}\n\n\t\treturn errors.Join(applyErr, err)\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *ManifestApplyController) apply(\n\tctx context.Context,\n\tlogger *zap.Logger,\n\tmapper *restmapper.DeferredDiscoveryRESTMapper,\n\tdyn dynamic.Interface,\n\tmanifests resource.List,\n\tinv object.ObjMetadataSet,\n) (object.ObjMetadataSet, error) {\n\t// flatten list of objects to be applied\n\tobjects := xslices.FlatMap(manifests.Items, func(m resource.Resource) []*unstructured.Unstructured {\n\t\treturn k8sadapter.Manifest(m.(*k8s.Manifest)).Objects()\n\t})\n\n\t// sort the list so that namespaces come first, followed by CRDs and everything else after that\n\tsort.SliceStable(objects, func(i, j int) bool {\n\t\tobjL := objects[i]\n\t\tobjR := objects[j]\n\n\t\tgvkL := objL.GroupVersionKind()\n\t\tgvkR := objR.GroupVersionKind()\n\n\t\tif isNamespace(gvkL) {\n\t\t\tif !isNamespace(gvkR) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\treturn objL.GetName() < objR.GetName()\n\t\t}\n\n\t\tif isNamespace(gvkR) {\n\t\t\treturn false\n\t\t}\n\n\t\tif isCRD(gvkL) {\n\t\t\tif !isCRD(gvkR) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\treturn objL.GetName() < objR.GetName()\n\t\t}\n\n\t\tif isCRD(gvkR) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn false\n\t})\n\n\tvar multiErr *multierror.Error\n\n\tfor _, obj := range objects {\n\t\tgvk := obj.GroupVersionKind()\n\t\tobjName := fmt.Sprintf(\"%s/%s/%s/%s\", gvk.Group, gvk.Version, gvk.Kind, obj.GetName())\n\n\t\tobjMeta, err := object.RuntimeToObjMeta(obj)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to retrieve object metadata of %q: %w\", objName, err)\n\t\t}\n\n\t\t// check if the resource is already in the inventory, if so, skip applying it\n\t\tif inv.Contains(objMeta) {\n\t\t\tcontinue\n\t\t}\n\n\t\tmapping, err := mapper.RESTMapping(obj.GroupVersionKind().GroupKind(), obj.GroupVersionKind().Version)\n\t\tif err != nil {\n\t\t\tswitch {\n\t\t\tcase apierrors.IsNotFound(err):\n\t\t\t\tfallthrough\n\t\t\tcase apierrors.IsInvalid(err):\n\t\t\t\tfallthrough\n\t\t\tcase meta.IsNoMatchError(err):\n\t\t\t\t// most probably a problem with the manifest, so we should continue with other manifests\n\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"error creating mapping for object %s: %w\", objName, err))\n\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\t// connection errors, etc.; it makes no sense to continue with other manifests\n\t\t\t\treturn nil, fmt.Errorf(\"error creating mapping for object %s: %w\", objName, err)\n\t\t\t}\n\t\t}\n\n\t\tvar dr dynamic.ResourceInterface\n\n\t\tif mapping.Scope.Name() == meta.RESTScopeNameNamespace {\n\t\t\t// default the namespace if it's not set in the manifest\n\t\t\tif obj.GetNamespace() == \"\" {\n\t\t\t\tobj.SetNamespace(corev1.NamespaceDefault)\n\t\t\t}\n\n\t\t\t// namespaced resources should specify the namespace\n\t\t\tdr = dyn.Resource(mapping.Resource).Namespace(obj.GetNamespace())\n\t\t} else {\n\t\t\t// for cluster-wide resources\n\t\t\tdr = dyn.Resource(mapping.Resource)\n\t\t}\n\n\t\t_, err = dr.Get(ctx, obj.GetName(), metav1.GetOptions{})\n\t\tif err == nil {\n\t\t\t// already exists,\n\t\t\t// backfill the inventory if the resource is missing (to migrate to inventory-based apply)\n\t\t\tinv = inv.Union(object.ObjMetadataSet{objMeta})\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !apierrors.IsNotFound(err) {\n\t\t\treturn nil, fmt.Errorf(\"error checking resource existence: %w\", err)\n\t\t}\n\n\t\t// Set inventory annotation.\n\t\tannotations := obj.GetAnnotations()\n\t\tif annotations == nil {\n\t\t\tannotations = make(map[string]string)\n\t\t}\n\n\t\tinventoryAnnotation, inventoryAnnotationSet := annotations[ssa.InventoryAnnotationKey]\n\n\t\tif inventoryAnnotationSet && inventoryAnnotation != constants.KubernetesBootstrapManifestsInventoryName {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"unexpected foreign inventory annotation on %s \", objName))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tannotations[ssa.InventoryAnnotationKey] = constants.KubernetesBootstrapManifestsInventoryName\n\t\tobj.SetAnnotations(annotations)\n\n\t\t_, err = dr.Apply(ctx, obj.GetName(), obj, metav1.ApplyOptions{\n\t\t\tFieldManager: constants.KubernetesFieldManagerName,\n\t\t})\n\t\tif err != nil {\n\t\t\tswitch {\n\t\t\tcase apierrors.IsMethodNotSupported(err):\n\t\t\t\tfallthrough\n\t\t\tcase apierrors.IsBadRequest(err):\n\t\t\t\tfallthrough\n\t\t\tcase apierrors.IsInvalid(err):\n\t\t\t\t// resource is malformed, continue with other manifests\n\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"error creating %s: %w\", objName, err))\n\t\t\tdefault:\n\t\t\t\t// connection errors, etc.; it makes no sense to continue with other manifests\n\t\t\t\treturn nil, fmt.Errorf(\"error creating %s: %w\", objName, err)\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.Sugar().Infof(\"created %s\", objName)\n\n\t\t\tinv = inv.Union(object.ObjMetadataSet{objMeta})\n\t\t}\n\t}\n\n\treturn inv, multiErr.ErrorOrNil()\n}\n\nfunc isNamespace(gvk schema.GroupVersionKind) bool {\n\treturn gvk.Kind == \"Namespace\" && gvk.Version == \"v1\"\n}\n\nfunc isCRD(gvk schema.GroupVersionKind) bool {\n\treturn gvk.Kind == \"CustomResourceDefinition\" && gvk.Group == \"apiextensions.k8s.io\"\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/manifest_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\ntype ManifestSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *ManifestSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.ManifestController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *ManifestSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\n//nolint:dupl\nfunc (suite *ManifestSuite) assertManifests(manifests []string) error {\n\tresources, err := suite.state.List(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, \"\", resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tids := xslices.Map(resources.Items, func(r resource.Resource) string { return r.Metadata().ID() })\n\n\tif !slices.Equal(manifests, ids) {\n\t\treturn retry.ExpectedErrorf(\"expected %q, got %q\", manifests, ids)\n\t}\n\n\treturn nil\n}\n\nvar defaultManifestSpec = k8s.BootstrapManifestsConfigSpec{\n\tServer:        \"127.0.0.1\",\n\tClusterDomain: \"cluster.\",\n\n\tPodCIDRs: []string{constants.DefaultIPv4PodNet},\n\n\tProxyEnabled: true,\n\tProxyImage:   \"foo/bar\",\n\tProxyArgs: []string{\n\t\tfmt.Sprintf(\"--cluster-cidr=%s\", constants.DefaultIPv4PodNet),\n\t\t\"--hostname-override=$(NODE_NAME)\",\n\t\t\"--kubeconfig=/etc/kubernetes/kubeconfig\",\n\t\t\"--proxy-mode=iptables\",\n\t\t\"--conntrack-max-per-core=0\",\n\t},\n\n\tCoreDNSEnabled: true,\n\tCoreDNSImage:   \"foo/bar\",\n\n\tDNSServiceIP: \"192.168.0.1\",\n\n\tFlannelEnabled: true,\n\tFlannelImage:   \"foo/bar\",\n\n\tPodSecurityPolicyEnabled: false,\n}\n\nfunc (suite *ManifestSuite) TestReconcileDefaults() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\tmanifestConfig := k8s.NewBootstrapManifestsConfig()\n\t*manifestConfig.TypedSpec() = defaultManifestSpec\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertManifests(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\t\"00-kubelet-bootstrapping-token\",\n\t\t\t\t\t\t\"01-csr-approver-role-binding\",\n\t\t\t\t\t\t\"01-csr-node-bootstrap\",\n\t\t\t\t\t\t\"01-csr-renewal-role-binding\",\n\t\t\t\t\t\t\"05-flannel\",\n\t\t\t\t\t\t\"10-kube-proxy\",\n\t\t\t\t\t\t\"11-core-dns\",\n\t\t\t\t\t\t\"11-core-dns-svc\",\n\t\t\t\t\t\t\"11-kube-config-in-cluster\",\n\t\t\t\t\t\t\"11-talos-node-rbac-template\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *ManifestSuite) TestReconcileDisableKubeProxy() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\tmanifestConfig := k8s.NewBootstrapManifestsConfig()\n\tspec := defaultManifestSpec\n\tspec.ProxyEnabled = false\n\t*manifestConfig.TypedSpec() = spec\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertManifests(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\t\"00-kubelet-bootstrapping-token\",\n\t\t\t\t\t\t\"01-csr-approver-role-binding\",\n\t\t\t\t\t\t\"01-csr-node-bootstrap\",\n\t\t\t\t\t\t\"01-csr-renewal-role-binding\",\n\t\t\t\t\t\t\"05-flannel\",\n\t\t\t\t\t\t\"11-core-dns\",\n\t\t\t\t\t\t\"11-core-dns-svc\",\n\t\t\t\t\t\t\"11-kube-config-in-cluster\",\n\t\t\t\t\t\t\"11-talos-node-rbac-template\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *ManifestSuite) TestReconcileKubeProxyExtraArgs() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\tmanifestConfig := k8s.NewBootstrapManifestsConfig()\n\tspec := defaultManifestSpec\n\tspec.ProxyArgs = append(spec.ProxyArgs, \"--bind-address=\\\"::\\\"\")\n\t*manifestConfig.TypedSpec() = spec\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertManifests(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\t\"00-kubelet-bootstrapping-token\",\n\t\t\t\t\t\t\"01-csr-approver-role-binding\",\n\t\t\t\t\t\t\"01-csr-node-bootstrap\",\n\t\t\t\t\t\t\"01-csr-renewal-role-binding\",\n\t\t\t\t\t\t\"05-flannel\",\n\t\t\t\t\t\t\"10-kube-proxy\",\n\t\t\t\t\t\t\"11-core-dns\",\n\t\t\t\t\t\t\"11-core-dns-svc\",\n\t\t\t\t\t\t\"11-kube-config-in-cluster\",\n\t\t\t\t\t\t\"11-talos-node-rbac-template\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(\n\t\t\tk8s.ControlPlaneNamespaceName,\n\t\t\tk8s.ManifestType,\n\t\t\t\"10-kube-proxy\",\n\t\t\tresource.VersionUndefined,\n\t\t),\n\t)\n\tsuite.Require().NoError(err)\n\n\tmanifest := r.(*k8s.Manifest) //nolint:forcetypeassert\n\tsuite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 3)\n\n\tsuite.Assert().Equal(\"DaemonSet\", k8sadapter.Manifest(manifest).Objects()[0].GetKind())\n\n\tds := k8sadapter.Manifest(manifest).Objects()[0].Object\n\tcontainerSpec := ds[\"spec\"].(map[string]any)[\"template\"].(map[string]any)[\"spec\"].(map[string]any)[\"containers\"].([]any)[0]\n\targs := containerSpec.(map[string]any)[\"command\"].([]any) //nolint:forcetypeassert\n\n\tsuite.Assert().Equal(\"--bind-address=\\\"::\\\"\", args[len(args)-1])\n}\n\nfunc (suite *ManifestSuite) TestReconcileIPv6() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\tmanifestConfig := k8s.NewBootstrapManifestsConfig()\n\tspec := defaultManifestSpec\n\tspec.PodCIDRs = []string{constants.DefaultIPv6PodNet}\n\tspec.DNSServiceIP = \"\"\n\tspec.DNSServiceIPv6 = \"fc00:db8:10::10\"\n\t*manifestConfig.TypedSpec() = spec\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertManifests(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\t\"00-kubelet-bootstrapping-token\",\n\t\t\t\t\t\t\"01-csr-approver-role-binding\",\n\t\t\t\t\t\t\"01-csr-node-bootstrap\",\n\t\t\t\t\t\t\"01-csr-renewal-role-binding\",\n\t\t\t\t\t\t\"05-flannel\",\n\t\t\t\t\t\t\"10-kube-proxy\",\n\t\t\t\t\t\t\"11-core-dns\",\n\t\t\t\t\t\t\"11-core-dns-svc\",\n\t\t\t\t\t\t\"11-kube-config-in-cluster\",\n\t\t\t\t\t\t\"11-talos-node-rbac-template\",\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(\n\t\t\tk8s.ControlPlaneNamespaceName,\n\t\t\tk8s.ManifestType,\n\t\t\t\"11-core-dns-svc\",\n\t\t\tresource.VersionUndefined,\n\t\t),\n\t)\n\tsuite.Require().NoError(err)\n\n\tmanifest := r.(*k8s.Manifest) //nolint:forcetypeassert\n\tsuite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 1)\n\n\tservice := k8sadapter.Manifest(manifest).Objects()[0]\n\tsuite.Assert().Equal(\"Service\", service.GetKind())\n\n\tv, _, _ := unstructured.NestedString(service.Object, \"spec\", \"clusterIP\") //nolint:errcheck\n\tsuite.Assert().Equal(spec.DNSServiceIPv6, v)\n\n\tvv, _, _ := unstructured.NestedStringSlice(service.Object, \"spec\", \"clusterIPs\") //nolint:errcheck\n\tsuite.Assert().Equal([]string{spec.DNSServiceIPv6}, vv)\n\n\tvv, _, _ = unstructured.NestedStringSlice(service.Object, \"spec\", \"ipFamilies\") //nolint:errcheck\n\tsuite.Assert().Equal([]string{\"IPv6\"}, vv)\n\n\tv, _, _ = unstructured.NestedString(service.Object, \"spec\", \"ipFamilyPolicy\") //nolint:errcheck\n\tsuite.Assert().Equal(\"SingleStack\", v)\n\n\tr, err = suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(\n\t\t\tk8s.ControlPlaneNamespaceName,\n\t\t\tk8s.ManifestType,\n\t\t\t\"05-flannel\",\n\t\t\tresource.VersionUndefined,\n\t\t),\n\t)\n\tsuite.Require().NoError(err)\n\n\tmanifest = r.(*k8s.Manifest) //nolint:forcetypeassert\n\tsuite.Assert().Len(k8sadapter.Manifest(manifest).Objects(), 5)\n\n\tconfigmap := k8sadapter.Manifest(manifest).Objects()[3]\n\tsuite.Assert().Equal(\"ConfigMap\", configmap.GetKind())\n\n\tv, _, _ = unstructured.NestedString(configmap.Object, \"data\", \"net-conf.json\") //nolint:errcheck\n\tsuite.Assert().Contains(v, `\"EnableIPv4\": false`)\n\tsuite.Assert().Contains(v, `\"EnableIPv6\": true`)\n\tsuite.Assert().Contains(v, fmt.Sprintf(`\"IPv6Network\": \"%s\"`, constants.DefaultIPv6PodNet))\n}\n\nfunc (suite *ManifestSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestManifestSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(ManifestSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_annotation_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"maps\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/labels\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NodeAnnotationSpecController manages k8s.NodeAnnotationsConfig based on configuration.\ntype NodeAnnotationSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeAnnotationSpecController) Name() string {\n\treturn \"k8s.NodeAnnotationSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeAnnotationSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.ExtensionStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeAnnotationSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeAnnotationSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeAnnotationSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tnodeAnnotations := map[string]string{}\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tmaps.Copy(nodeAnnotations, cfg.Config().Machine().NodeAnnotations())\n\t\t}\n\n\t\tif err = extensionsToNodeKV(\n\t\t\tctx, r, nodeAnnotations,\n\t\t\tfunc(annotationValue string) bool {\n\t\t\t\treturn labels.ValidateLabelValue(annotationValue) != nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error converting extensions to node annotations: %w\", err)\n\t\t}\n\n\t\tfor key, value := range nodeAnnotations {\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewNodeAnnotationSpec(key), func(k *k8s.NodeAnnotationSpec) error {\n\t\t\t\tk.TypedSpec().Key = key\n\t\t\t\tk.TypedSpec().Value = value\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating node label spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*k8s.NodeAnnotationSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_annotation_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype NodeAnnotationsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestNodeAnnotationsSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeAnnotationsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodeAnnotationSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *NodeAnnotationsSuite) updateMachineConfig(annotations map[string]string) {\n\tcfg, err := safe.StateGetByID[*config.MachineConfig](suite.Ctx(), suite.State(), config.ActiveID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tif cfg == nil {\n\t\tcfg = config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineType:            \"controlplane\",\n\t\t\t\tMachineNodeAnnotations: annotations,\n\t\t\t},\n\t\t}))\n\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\t} else {\n\t\tcfg.Container().RawV1Alpha1().MachineConfig.MachineNodeAnnotations = annotations\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\t}\n}\n\nfunc (suite *NodeAnnotationsSuite) TestChangeLabel() {\n\t// given\n\texpectedAnnotation := \"some/annotation\"\n\toldValue := \"oldValue\"\n\texpectedValue := \"newValue\"\n\n\t// when\n\tsuite.updateMachineConfig(map[string]string{\n\t\texpectedAnnotation: oldValue,\n\t})\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedAnnotation},\n\t\tfunc(labelSpec *k8s.NodeAnnotationSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(oldValue, labelSpec.TypedSpec().Value)\n\t\t})\n\n\tsuite.updateMachineConfig(map[string]string{\n\t\texpectedAnnotation: expectedValue,\n\t})\n\n\t// then\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedAnnotation},\n\t\tfunc(labelSpec *k8s.NodeAnnotationSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(expectedValue, labelSpec.TypedSpec().Value)\n\t\t})\n}\n\nfunc (suite *NodeAnnotationsSuite) TestExtensionAnnotations() {\n\text1 := runtime.NewExtensionStatus(runtime.NamespaceName, \"0\")\n\text1.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"zfs\",\n\t\tVersion: \"2.2.4\",\n\t}\n\n\text2 := runtime.NewExtensionStatus(runtime.NamespaceName, \"1\")\n\text2.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"drbd\",\n\t\tVersion: \"9.2.8-v1.7.5\",\n\t}\n\n\text3 := runtime.NewExtensionStatus(runtime.NamespaceName, \"2\")\n\text3.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"schematic\",\n\t\tVersion: \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext1))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext2))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext3))\n\n\trtestutils.AssertNoResource[*k8s.NodeAnnotationSpec](suite.Ctx(), suite.T(), suite.State(), \"extensions.talos.dev/zfs\")\n\trtestutils.AssertNoResource[*k8s.NodeAnnotationSpec](suite.Ctx(), suite.T(), suite.State(), \"extensions.talos.dev/drbd\")\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"extensions.talos.dev/schematic\"},\n\t\tfunc(labelSpec *k8s.NodeAnnotationSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\", labelSpec.TypedSpec().Value)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_apply.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// NodeApplyController watches k8s.NodeLabelSpecs, k8s.NodeTaintSpecs and applies them to the k8s Node object.\ntype NodeApplyController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeApplyController) Name() string {\n\treturn \"k8s.NodeApplyController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeApplyController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeAnnotationSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeLabelSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeTaintSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeCordonedSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\t// NodeStatus is used to trigger the controller on node status updates.\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeApplyController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *NodeApplyController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif err := ctrl.reconcileWithK8s(ctx, r, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *NodeApplyController) getNodeLabelSpecs(ctx context.Context, r controller.Runtime) (map[string]string, error) {\n\titems, err := safe.ReaderListAll[*k8s.NodeLabelSpec](ctx, r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing node label spec resources: %w\", err)\n\t}\n\n\tresult := make(map[string]string, items.Len())\n\n\tfor res := range items.All() {\n\t\tresult[res.TypedSpec().Key] = res.TypedSpec().Value\n\t}\n\n\treturn result, nil\n}\n\nfunc (ctrl *NodeApplyController) getNodeAnnotationSpecs(ctx context.Context, r controller.Runtime) (map[string]string, error) {\n\titems, err := safe.ReaderListAll[*k8s.NodeAnnotationSpec](ctx, r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing node annotation spec resources: %w\", err)\n\t}\n\n\tresult := make(map[string]string, items.Len())\n\n\tfor res := range items.All() {\n\t\tresult[res.TypedSpec().Key] = res.TypedSpec().Value\n\t}\n\n\treturn result, nil\n}\n\nfunc (ctrl *NodeApplyController) getNodeTaintSpecs(ctx context.Context, r controller.Runtime) ([]k8s.NodeTaintSpecSpec, error) {\n\titems, err := safe.ReaderListAll[*k8s.NodeTaintSpec](ctx, r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing node taint spec resources: %w\", err)\n\t}\n\n\tresult := make([]k8s.NodeTaintSpecSpec, 0, items.Len())\n\n\tfor res := range items.All() {\n\t\tresult = append(result, *res.TypedSpec())\n\t}\n\n\treturn result, nil\n}\n\nfunc (ctrl *NodeApplyController) getNodeCordoned(ctx context.Context, r controller.Runtime) (bool, error) {\n\titems, err := safe.ReaderListAll[*k8s.NodeCordonedSpec](ctx, r)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"error listing node cordoned spec resources: %w\", err)\n\t}\n\n\treturn items.Len() > 0, nil\n}\n\nfunc (ctrl *NodeApplyController) getK8sClient(ctx context.Context, r controller.Runtime, logger *zap.Logger) (*kubernetes.Client, error) {\n\tmachineType, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting machine type: %w\", err)\n\t}\n\n\tif machineType.MachineType().IsControlPlane() {\n\t\treturn kubernetes.NewTemporaryClientControlPlane(ctx, r)\n\t}\n\n\tlogger.Debug(\"waiting for kubelet client config\", zap.String(\"file\", constants.KubeletKubeconfig))\n\n\tif err := conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kubernetes.NewClientFromKubeletKubeconfig()\n}\n\nfunc (ctrl *NodeApplyController) reconcileWithK8s(\n\tctx context.Context,\n\tr controller.Runtime,\n\tlogger *zap.Logger,\n) error {\n\tnodenameResource, err := safe.ReaderGet[*k8s.Nodename](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, k8s.NodenameID, resource.VersionUndefined))\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tif nodenameResource.TypedSpec().SkipNodeRegistration {\n\t\t// if the node registration is skipped, we don't need to do anything\n\t\treturn nil\n\t}\n\n\tnodename := nodenameResource.TypedSpec().Nodename\n\n\tk8sClient, err := ctrl.getK8sClient(ctx, r, logger)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t}\n\n\tif k8sClient == nil {\n\t\t// not ready yet\n\t\treturn nil\n\t}\n\n\tdefer k8sClient.Close() //nolint:errcheck\n\n\tnodeLabelSpecs, err := ctrl.getNodeLabelSpecs(ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodeAnnotationSpecs, err := ctrl.getNodeAnnotationSpecs(ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodeTaintSpecs, err := ctrl.getNodeTaintSpecs(ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodeShouldCordon, err := ctrl.getNodeCordoned(ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn ctrl.sync(ctx, logger, k8sClient, nodename, nodeLabelSpecs, nodeAnnotationSpecs, nodeTaintSpecs, nodeShouldCordon)\n}\n\nfunc (ctrl *NodeApplyController) sync(\n\tctx context.Context,\n\tlogger *zap.Logger,\n\tk8sClient *kubernetes.Client,\n\tnodeName string,\n\tnodeLabelSpecs, nodeAnnotationSpecs map[string]string,\n\tnodeTaintSpecs []k8s.NodeTaintSpecSpec,\n\tnodeShouldCordon bool,\n) error {\n\t// run several attempts retrying conflict errors\n\treturn retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\terr := ctrl.syncOnce(ctx, logger, k8sClient, nodeName, nodeLabelSpecs, nodeAnnotationSpecs, nodeTaintSpecs, nodeShouldCordon)\n\t\tif err != nil && (apierrors.IsConflict(err) || apierrors.IsForbidden(err)) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t})\n}\n\nfunc umarshalOwnedAnnotation(node *v1.Node, annotation string) (map[string]struct{}, error) {\n\townedJSON := []byte(node.Annotations[annotation])\n\n\tvar owned []string\n\n\tif len(ownedJSON) > 0 {\n\t\tif err := json.Unmarshal(ownedJSON, &owned); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\townedMap := xslices.ToSet(owned)\n\tif ownedMap == nil {\n\t\townedMap = map[string]struct{}{}\n\t}\n\n\treturn ownedMap, nil\n}\n\nfunc marshalOwnedAnnotation(node *v1.Node, annotation string, ownedMap map[string]struct{}) error {\n\towned := maps.Keys(ownedMap)\n\tslices.Sort(owned)\n\n\tif len(owned) > 0 {\n\t\townedJSON, err := json.Marshal(owned)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnode.Annotations[annotation] = string(ownedJSON)\n\t} else {\n\t\tdelete(node.Annotations, annotation)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *NodeApplyController) syncOnce(\n\tctx context.Context,\n\tlogger *zap.Logger,\n\tk8sClient *kubernetes.Client,\n\tnodeName string,\n\tnodeLabelSpecs, nodeAnnotationSpecs map[string]string,\n\tnodeTaintSpecs []k8s.NodeTaintSpecSpec,\n\tnodeShouldCordon bool,\n) error {\n\tnode, err := k8sClient.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting node: %w\", err)\n\t}\n\n\tif node.Labels == nil {\n\t\tnode.Labels = make(map[string]string)\n\t}\n\n\townedLabelsMap, err := umarshalOwnedAnnotation(node, constants.AnnotationOwnedLabels)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling owned labels: %w\", err)\n\t}\n\n\townedAnnotationsMap, err := umarshalOwnedAnnotation(node, constants.AnnotationOwnedAnnotations)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling owned annotations: %w\", err)\n\t}\n\n\townedTaintsMap, err := umarshalOwnedAnnotation(node, constants.AnnotationOwnedTaints)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling owned taints: %w\", err)\n\t}\n\n\tctrl.ApplyLabels(logger, node, ownedLabelsMap, nodeLabelSpecs)\n\tctrl.ApplyAnnotations(logger, node, ownedAnnotationsMap, nodeAnnotationSpecs)\n\tctrl.ApplyTaints(logger, node, ownedTaintsMap, nodeTaintSpecs)\n\tctrl.ApplyCordoned(logger, node, nodeShouldCordon)\n\n\tif err = marshalOwnedAnnotation(node, constants.AnnotationOwnedLabels, ownedLabelsMap); err != nil {\n\t\treturn fmt.Errorf(\"error marshaling owned labels: %w\", err)\n\t}\n\n\tif err = marshalOwnedAnnotation(node, constants.AnnotationOwnedAnnotations, ownedAnnotationsMap); err != nil {\n\t\treturn fmt.Errorf(\"error marshaling owned annotations: %w\", err)\n\t}\n\n\tif err = marshalOwnedAnnotation(node, constants.AnnotationOwnedTaints, ownedTaintsMap); err != nil {\n\t\treturn fmt.Errorf(\"error marshaling owned taints: %w\", err)\n\t}\n\n\t_, err = k8sClient.CoreV1().Nodes().Update(ctx, node, metav1.UpdateOptions{})\n\n\treturn err\n}\n\nfunc (ctrl *NodeApplyController) applyNodeKV(logger *zap.Logger, nodeKV map[string]string, owned map[string]struct{}, spec map[string]string) {\n\t// set labels from the spec\n\tfor key, value := range spec {\n\t\tcurrentValue, exists := nodeKV[key]\n\n\t\t// label is not set on the node yet, so take it over\n\t\tif !exists {\n\t\t\tnodeKV[key] = value\n\t\t\towned[key] = struct{}{}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// no change to the label, skip it\n\t\tif currentValue == value {\n\t\t\towned[key] = struct{}{}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, owned := owned[key]; !owned {\n\t\t\tlogger.Debug(\"skipping label update, label is not owned\", zap.String(\"key\", key), zap.String(\"value\", value))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tnodeKV[key] = value\n\t}\n\n\t// remove labels which are owned but are not in the spec\n\tfor key := range owned {\n\t\tif _, exists := spec[key]; !exists {\n\t\t\tdelete(nodeKV, key)\n\t\t\tdelete(owned, key)\n\t\t}\n\t}\n}\n\n// ApplyLabels performs the inner loop of the node label reconciliation.\n//\n// This method is exported for testing purposes.\nfunc (ctrl *NodeApplyController) ApplyLabels(logger *zap.Logger, node *v1.Node, ownedLabels map[string]struct{}, nodeLabelSpecs map[string]string) {\n\tctrl.applyNodeKV(logger, node.Labels, ownedLabels, nodeLabelSpecs)\n}\n\n// ApplyAnnotations performs the inner loop of the node annotation reconciliation.\n//\n// This method is exported for testing purposes.\nfunc (ctrl *NodeApplyController) ApplyAnnotations(logger *zap.Logger, node *v1.Node, ownedAnnotations map[string]struct{}, nodeAnnotationSpecs map[string]string) {\n\tctrl.applyNodeKV(logger, node.Annotations, ownedAnnotations, nodeAnnotationSpecs)\n}\n\n// ApplyTaints performs the inner loop of the node taints reconciliation.\n//\n// This method is exported for testing purposes.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeApplyController) ApplyTaints(logger *zap.Logger, node *v1.Node, ownedTaints map[string]struct{}, nodeTaints []k8s.NodeTaintSpecSpec) {\n\t// set taints from the spec\n\tfor _, taint := range nodeTaints {\n\t\tvar currentValue *v1.Taint\n\n\t\tfor i, nodeTaint := range node.Spec.Taints {\n\t\t\tif nodeTaint.Key == taint.Key {\n\t\t\t\tcurrentValue = &node.Spec.Taints[i]\n\t\t\t}\n\t\t}\n\n\t\tif currentValue == nil {\n\t\t\t// taint is not set on the node yet, so take it over\n\t\t\tnode.Spec.Taints = append(node.Spec.Taints, v1.Taint{\n\t\t\t\tKey:    taint.Key,\n\t\t\t\tValue:  taint.Value,\n\t\t\t\tEffect: v1.TaintEffect(taint.Effect),\n\t\t\t})\n\t\t\townedTaints[taint.Key] = struct{}{}\n\t\t} else {\n\t\t\t// taint with the same key exists, check if it is owned\n\t\t\tif _, owned := ownedTaints[taint.Key]; owned {\n\t\t\t\t// taint is owned, so update it\n\t\t\t\tcurrentValue.Value = taint.Value\n\t\t\t\tcurrentValue.Effect = v1.TaintEffect(taint.Effect)\n\t\t\t} else if currentValue.Value == taint.Value && currentValue.Effect == v1.TaintEffect(taint.Effect) {\n\t\t\t\t// no change to the taint, skip it, but mark it as owned\n\t\t\t\townedTaints[taint.Key] = struct{}{}\n\t\t\t} else {\n\t\t\t\tlogger.Debug(\"skipping taint update, taint is not owned\", zap.String(\"key\", taint.Key), zap.String(\"value\", taint.Value), zap.String(\"effect\", taint.Effect))\n\t\t\t}\n\t\t}\n\t}\n\n\t// remove taints which are owned but are not in the spec\n\tnode.Spec.Taints = xslices.FilterInPlace(node.Spec.Taints,\n\t\tfunc(nodeTaint v1.Taint) bool {\n\t\t\tif _, owned := ownedTaints[nodeTaint.Key]; !owned {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tfor _, taint := range nodeTaints {\n\t\t\t\tif nodeTaint.Key == taint.Key {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdelete(ownedTaints, nodeTaint.Key)\n\n\t\t\treturn false\n\t\t})\n}\n\n// ApplyCordoned marks the node as unschedulable if it is cordoned.\n//\n// This method is exported for testing purposes.\nfunc (ctrl *NodeApplyController) ApplyCordoned(logger *zap.Logger, node *v1.Node, shouldCordon bool) {\n\tswitch {\n\tcase shouldCordon && !node.Spec.Unschedulable:\n\t\tnode.Spec.Unschedulable = true\n\n\t\tif node.Annotations == nil {\n\t\t\tnode.Annotations = map[string]string{}\n\t\t}\n\n\t\tnode.Annotations[constants.AnnotationCordonedKey] = constants.AnnotationCordonedValue\n\tcase !shouldCordon && node.Spec.Unschedulable:\n\t\tif _, exists := node.Annotations[constants.AnnotationCordonedKey]; !exists {\n\t\t\t// not cordoned by Talos, skip\n\t\t\treturn\n\t\t}\n\n\t\tnode.Spec.Unschedulable = false\n\t\tdelete(node.Annotations, constants.AnnotationCordonedKey)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_apply_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.uber.org/zap/zaptest\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\nfunc TestApplyLabels(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tctrl := &k8sctrl.NodeApplyController{}\n\tlogger := zaptest.NewLogger(t)\n\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tinputLabels map[string]string\n\t\townedLabels []string\n\t\tlabelSpec   map[string]string\n\n\t\texpectedLabels      map[string]string\n\t\texpectedOwnedLabels []string\n\t}{\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tinputLabels: map[string]string{},\n\t\t\townedLabels: []string{},\n\t\t\tlabelSpec:   map[string]string{},\n\n\t\t\texpectedLabels:      map[string]string{},\n\t\t\texpectedOwnedLabels: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"initial set labels\",\n\t\t\tinputLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t},\n\t\t\townedLabels: []string{},\n\t\t\tlabelSpec: map[string]string{\n\t\t\t\t\"label1\": \"value1\",\n\t\t\t\t\"label2\": \"value2\",\n\t\t\t},\n\n\t\t\texpectedLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value1\",\n\t\t\t\t\"label2\":   \"value2\",\n\t\t\t},\n\t\t\texpectedOwnedLabels: []string{\n\t\t\t\t\"label1\",\n\t\t\t\t\"label2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"update owned labels\",\n\t\t\tinputLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value1\",\n\t\t\t\t\"label2\":   \"value2\",\n\t\t\t},\n\t\t\townedLabels: []string{\n\t\t\t\t\"label1\",\n\t\t\t\t\"label2\",\n\t\t\t},\n\t\t\tlabelSpec: map[string]string{\n\t\t\t\t\"label1\": \"value3\",\n\t\t\t},\n\n\t\t\texpectedLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value3\",\n\t\t\t},\n\t\t\texpectedOwnedLabels: []string{\n\t\t\t\t\"label1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ignore not owned labels\",\n\t\t\tinputLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value1\",\n\t\t\t\t\"label2\":   \"value2\",\n\t\t\t\t\"label3\":   \"value3\",\n\t\t\t},\n\t\t\townedLabels: []string{},\n\t\t\tlabelSpec: map[string]string{\n\t\t\t\t\"label1\": \"value3\",\n\t\t\t\t\"label2\": \"value2\",\n\t\t\t},\n\n\t\t\texpectedLabels: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value1\",\n\t\t\t\t\"label2\":   \"value2\",\n\t\t\t\t\"label3\":   \"value3\",\n\t\t\t},\n\t\t\texpectedOwnedLabels: []string{\n\t\t\t\t\"label2\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnode := &v1.Node{}\n\t\t\tnode.Labels = tt.inputLabels\n\n\t\t\townedLabels := xslices.ToSet(tt.ownedLabels)\n\t\t\tif ownedLabels == nil {\n\t\t\t\townedLabels = map[string]struct{}{}\n\t\t\t}\n\n\t\t\tctrl.ApplyLabels(logger, node, ownedLabels, tt.labelSpec)\n\n\t\t\tnewOwnedLabels := maps.Keys(ownedLabels)\n\t\t\tif newOwnedLabels == nil {\n\t\t\t\tnewOwnedLabels = []string{}\n\t\t\t}\n\n\t\t\tslices.Sort(newOwnedLabels)\n\n\t\t\tassert.Equal(t, tt.expectedLabels, node.Labels)\n\t\t\tassert.Equal(t, tt.expectedOwnedLabels, newOwnedLabels)\n\t\t})\n\t}\n}\n\nfunc TestApplyAnnotations(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tctrl := &k8sctrl.NodeApplyController{}\n\tlogger := zaptest.NewLogger(t)\n\n\tfor _, tt := range []struct {\n\t\tname             string\n\t\tinputAnnotations map[string]string\n\t\townedAnnotations []string\n\t\tannotationSpec   map[string]string\n\n\t\texpectedAnnotations      map[string]string\n\t\texpectedOwnedAnnotations []string\n\t}{\n\t\t{\n\t\t\tname:             \"empty\",\n\t\t\tinputAnnotations: map[string]string{},\n\t\t\townedAnnotations: []string{},\n\t\t\tannotationSpec:   map[string]string{},\n\n\t\t\texpectedAnnotations:      map[string]string{},\n\t\t\texpectedOwnedAnnotations: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"initial annotations\",\n\t\t\tinputAnnotations: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t},\n\t\t\townedAnnotations: []string{},\n\t\t\tannotationSpec: map[string]string{\n\t\t\t\t\"talos/foo\": \"value1\",\n\t\t\t\t\"talos/bar\": \"value2\",\n\t\t\t},\n\n\t\t\texpectedAnnotations: map[string]string{\n\t\t\t\t\"hostname\":  \"foo\",\n\t\t\t\t\"talos/foo\": \"value1\",\n\t\t\t\t\"talos/bar\": \"value2\",\n\t\t\t},\n\t\t\texpectedOwnedAnnotations: []string{\n\t\t\t\t\"talos/bar\",\n\t\t\t\t\"talos/foo\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"update owned annotations\",\n\t\t\tinputAnnotations: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value1\",\n\t\t\t\t\"label2\":   \"value2\",\n\t\t\t},\n\t\t\townedAnnotations: []string{\n\t\t\t\t\"label1\",\n\t\t\t\t\"label2\",\n\t\t\t},\n\t\t\tannotationSpec: map[string]string{\n\t\t\t\t\"label1\": \"value3\",\n\t\t\t},\n\n\t\t\texpectedAnnotations: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"label1\":   \"value3\",\n\t\t\t},\n\t\t\texpectedOwnedAnnotations: []string{\n\t\t\t\t\"label1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ignore not owned annotations\",\n\t\t\tinputAnnotations: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"ann1\":     \"value1\",\n\t\t\t\t\"ann2\":     \"value2\",\n\t\t\t\t\"ann3\":     \"value3\",\n\t\t\t},\n\t\t\townedAnnotations: []string{},\n\t\t\tannotationSpec: map[string]string{\n\t\t\t\t\"ann1\": \"value3\",\n\t\t\t\t\"ann2\": \"value2\",\n\t\t\t},\n\n\t\t\texpectedAnnotations: map[string]string{\n\t\t\t\t\"hostname\": \"foo\",\n\t\t\t\t\"ann1\":     \"value1\",\n\t\t\t\t\"ann2\":     \"value2\",\n\t\t\t\t\"ann3\":     \"value3\",\n\t\t\t},\n\t\t\texpectedOwnedAnnotations: []string{\n\t\t\t\t\"ann2\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnode := &v1.Node{}\n\t\t\tnode.Annotations = tt.inputAnnotations\n\n\t\t\townedAnnotations := xslices.ToSet(tt.ownedAnnotations)\n\t\t\tif ownedAnnotations == nil {\n\t\t\t\townedAnnotations = map[string]struct{}{}\n\t\t\t}\n\n\t\t\tctrl.ApplyAnnotations(logger, node, ownedAnnotations, tt.annotationSpec)\n\n\t\t\tnewOwnedAnnotations := maps.Keys(ownedAnnotations)\n\t\t\tif newOwnedAnnotations == nil {\n\t\t\t\tnewOwnedAnnotations = []string{}\n\t\t\t}\n\n\t\t\tslices.Sort(newOwnedAnnotations)\n\n\t\t\tassert.Equal(t, tt.expectedAnnotations, node.Annotations)\n\t\t\tassert.Equal(t, tt.expectedOwnedAnnotations, newOwnedAnnotations)\n\t\t})\n\t}\n}\n\nfunc TestApplyTaints(t *testing.T) {\n\tt.Parallel()\n\n\tctrl := &k8sctrl.NodeApplyController{}\n\tlogger := zaptest.NewLogger(t)\n\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tinputTaints []v1.Taint\n\t\townedTaints []string\n\t\ttaintSpec   []k8s.NodeTaintSpecSpec\n\n\t\texpectedTaints      []v1.Taint\n\t\texpectedOwnedTaints []string\n\t}{\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tinputTaints: nil,\n\t\t\townedTaints: []string{},\n\t\t\ttaintSpec:   nil,\n\n\t\t\texpectedTaints:      nil,\n\t\t\texpectedOwnedTaints: []string{},\n\t\t},\n\t\t{\n\t\t\tname: \"initial set taints\",\n\t\t\tinputTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t},\n\t\t\townedTaints: []string{},\n\t\t\ttaintSpec: []k8s.NodeTaintSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value2\",\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedOwnedTaints: []string{\n\t\t\t\t\"taint1\",\n\t\t\t\t\"taint2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"update owned taints\",\n\t\t\tinputTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\townedTaints: []string{\n\t\t\t\t\"taint1\",\n\t\t\t\t\"taint2\",\n\t\t\t},\n\t\t\ttaintSpec: []k8s.NodeTaintSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint1\",\n\t\t\t\t\tValue: \"value3\",\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint1\",\n\t\t\t\t\tValue: \"value3\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedOwnedTaints: []string{\n\t\t\t\t\"taint1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ignore not owned taints\",\n\t\t\tinputTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\townedTaints: []string{},\n\t\t\ttaintSpec: []k8s.NodeTaintSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value3\",\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedTaints: []v1.Taint{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"foo\",\n\t\t\t\t\tValue: \"bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:    \"taint1\",\n\t\t\t\t\tValue:  \"value1\",\n\t\t\t\t\tEffect: \"NoSchedule\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"taint2\",\n\t\t\t\t\tValue: \"value2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedOwnedTaints: []string{\n\t\t\t\t\"taint1\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnode := &v1.Node{}\n\t\t\tnode.Spec.Taints = tt.inputTaints\n\n\t\t\townedTaints := xslices.ToSet(tt.ownedTaints)\n\t\t\tif ownedTaints == nil {\n\t\t\t\townedTaints = map[string]struct{}{}\n\t\t\t}\n\n\t\t\tctrl.ApplyTaints(logger, node, ownedTaints, tt.taintSpec)\n\n\t\t\tnewOwnedTaints := maps.Keys(ownedTaints)\n\t\t\tif newOwnedTaints == nil {\n\t\t\t\tnewOwnedTaints = []string{}\n\t\t\t}\n\n\t\t\tslices.Sort(newOwnedTaints)\n\n\t\t\tassert.Equal(t, tt.expectedTaints, node.Spec.Taints)\n\t\t\tassert.Equal(t, tt.expectedOwnedTaints, newOwnedTaints)\n\t\t})\n\t}\n}\n\nfunc TestApplyCordoned(t *testing.T) {\n\tt.Parallel()\n\n\tctrl := &k8sctrl.NodeApplyController{}\n\tlogger := zaptest.NewLogger(t)\n\n\tfor _, tt := range []struct {\n\t\tname               string\n\t\tinputAnnotations   map[string]string\n\t\tinputUnschedulable bool\n\t\tshouldCordon       bool\n\n\t\texpectedUnschedulable bool\n\t\texpectedAnnotations   map[string]string\n\t}{\n\t\t{\n\t\t\tname:               \"not cordoned - uncordon\",\n\t\t\tinputAnnotations:   nil,\n\t\t\tinputUnschedulable: false,\n\t\t\tshouldCordon:       false,\n\n\t\t\texpectedUnschedulable: false,\n\t\t\texpectedAnnotations:   nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"not cordoned - cordon\",\n\t\t\tinputAnnotations:   nil,\n\t\t\tinputUnschedulable: false,\n\t\t\tshouldCordon:       true,\n\n\t\t\texpectedUnschedulable: true,\n\t\t\texpectedAnnotations:   map[string]string{constants.AnnotationCordonedKey: constants.AnnotationCordonedValue},\n\t\t},\n\t\t{\n\t\t\tname:               \"cordoned - no annotation - cordon\",\n\t\t\tinputAnnotations:   nil,\n\t\t\tinputUnschedulable: true,\n\t\t\tshouldCordon:       true,\n\n\t\t\texpectedUnschedulable: true,\n\t\t\texpectedAnnotations:   nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"cordoned - with annotation - cordon\",\n\t\t\tinputAnnotations:   map[string]string{constants.AnnotationCordonedKey: constants.AnnotationCordonedValue},\n\t\t\tinputUnschedulable: true,\n\t\t\tshouldCordon:       true,\n\n\t\t\texpectedUnschedulable: true,\n\t\t\texpectedAnnotations:   map[string]string{constants.AnnotationCordonedKey: constants.AnnotationCordonedValue},\n\t\t},\n\t\t{\n\t\t\tname:               \"cordoned - with annotation - uncordon\",\n\t\t\tinputAnnotations:   map[string]string{constants.AnnotationCordonedKey: constants.AnnotationCordonedValue},\n\t\t\tinputUnschedulable: true,\n\t\t\tshouldCordon:       false,\n\n\t\t\texpectedUnschedulable: false,\n\t\t\texpectedAnnotations:   map[string]string{},\n\t\t},\n\t\t{\n\t\t\tname:               \"cordoned - no annotation - uncordon\",\n\t\t\tinputAnnotations:   map[string]string{\"foo\": \"bar\"},\n\t\t\tinputUnschedulable: true,\n\t\t\tshouldCordon:       false,\n\n\t\t\texpectedUnschedulable: true,\n\t\t\texpectedAnnotations:   map[string]string{\"foo\": \"bar\"},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnode := &v1.Node{}\n\t\t\tnode.Annotations = tt.inputAnnotations\n\t\t\tnode.Spec.Unschedulable = tt.inputUnschedulable\n\n\t\t\tctrl.ApplyCordoned(logger, node, tt.shouldCordon)\n\n\t\t\tassert.Equal(t, tt.expectedUnschedulable, node.Spec.Unschedulable)\n\t\t\tassert.Equal(t, tt.expectedAnnotations, node.Annotations)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_cordoned_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NodeCordonedSpecController manages node cordoned status based on configuration.\ntype NodeCordonedSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeCordonedSpecController) Name() string {\n\treturn \"k8s.NodeCordonedSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeCordonedSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MachineStatusType,\n\t\t\tID:        optional.Some(runtime.MachineStatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeCordonedSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeCordonedSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeCordonedSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tstatus, err := safe.ReaderGetByID[*runtime.MachineStatus](ctx, r, runtime.MachineStatusID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tvar shouldCordon bool\n\n\t\tswitch status.TypedSpec().Stage { //nolint:exhaustive\n\t\tcase runtime.MachineStageShuttingDown, runtime.MachineStageUpgrading, runtime.MachineStageResetting:\n\t\t\tshouldCordon = true\n\t\tcase runtime.MachineStageBooting, runtime.MachineStageRunning:\n\t\t\tshouldCordon = false\n\t\tdefault:\n\t\t\t// don't change cordoned status\n\t\t\tcontinue\n\t\t}\n\n\t\tif shouldCordon {\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewNodeCordonedSpec(k8s.NodeCordonedID),\n\t\t\t\tfunc(k *k8s.NodeCordonedSpec) error {\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating node cordoned spec: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tnodeCordoned, err := safe.ReaderListAll[*k8s.NodeCordonedSpec](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting node cordoned specs: %w\", err)\n\t\t\t}\n\n\t\t\tfor res := range nodeCordoned.All() {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying node cordoned spec: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_cordoned_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype NodeCordonedSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestNodeCordonedSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeCordonedSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodeCordonedSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *NodeCordonedSuite) updateMachineStage(stage runtime.MachineStage) {\n\tstatus, err := safe.StateGetByID[*runtime.MachineStatus](suite.Ctx(), suite.State(), runtime.MachineStatusID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tif status == nil {\n\t\tstatus = runtime.NewMachineStatus()\n\t\tstatus.TypedSpec().Stage = stage\n\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), status))\n\t} else {\n\t\tstatus.TypedSpec().Stage = stage\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), status))\n\t}\n}\n\nfunc (suite *NodeCordonedSuite) TestBootingRunning() {\n\tsuite.updateMachineStage(runtime.MachineStageBooting)\n\n\trtestutils.AssertNoResource[*k8s.NodeCordonedSpec](suite.Ctx(), suite.T(), suite.State(), k8s.NodeCordonedID)\n\n\tsuite.updateMachineStage(runtime.MachineStageRunning)\n\n\trtestutils.AssertNoResource[*k8s.NodeCordonedSpec](suite.Ctx(), suite.T(), suite.State(), k8s.NodeCordonedID)\n}\n\nfunc (suite *NodeCordonedSuite) TestResetting() {\n\tsuite.updateMachineStage(runtime.MachineStageRunning)\n\n\trtestutils.AssertNoResource[*k8s.NodeCordonedSpec](suite.Ctx(), suite.T(), suite.State(), k8s.NodeCordonedID)\n\n\tsuite.updateMachineStage(runtime.MachineStageResetting)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{k8s.NodeCordonedID},\n\t\tfunc(*k8s.NodeCordonedSpec, *assert.Assertions) {})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_label_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"maps\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/labels\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NodeLabelSpecController manages k8s.NodeLabelsConfig based on configuration.\ntype NodeLabelSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeLabelSpecController) Name() string {\n\treturn \"k8s.NodeLabelSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeLabelSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.ExtensionStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeLabelSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeLabelSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeLabelSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tnodeLabels := map[string]string{}\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tmaps.Copy(nodeLabels, cfg.Config().Machine().NodeLabels())\n\n\t\t\tif cfg.Config().Machine().Type().IsControlPlane() {\n\t\t\t\tnodeLabels[constants.LabelNodeRoleControlPlane] = \"\"\n\t\t\t}\n\t\t}\n\n\t\tif err = extensionsToNodeKV(\n\t\t\tctx, r, nodeLabels,\n\t\t\tfunc(labelValue string) bool {\n\t\t\t\treturn labels.ValidateLabelValue(labelValue) == nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error converting extensions to node labels: %w\", err)\n\t\t}\n\n\t\tfor key, value := range nodeLabels {\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewNodeLabelSpec(key), func(k *k8s.NodeLabelSpec) error {\n\t\t\t\tk.TypedSpec().Key = key\n\t\t\t\tk.TypedSpec().Value = value\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating node label spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*k8s.NodeLabelSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc extensionsToNodeKV(ctx context.Context, r controller.Reader, spec map[string]string, valueFilter func(string) bool) error {\n\textensionStatuses, err := safe.ReaderListAll[*runtime.ExtensionStatus](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing extension statuses: %w\", err)\n\t}\n\n\tfor extensionStatus := range extensionStatuses.All() {\n\t\tif extensionStatus.TypedSpec().Metadata.Name == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := constants.K8sExtensionPrefix + extensionStatus.TypedSpec().Metadata.Name\n\t\tvalue := extensionStatus.TypedSpec().Metadata.Version\n\n\t\tif labels.ValidateQualifiedName(name) == nil && valueFilter(value) {\n\t\t\tspec[name] = value\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_label_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype NodeLabelsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestNodeLabelsSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeLabelsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodeLabelSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *NodeLabelsSuite) updateMachineConfig(machineType machine.Type, labels map[string]string) {\n\tcfg, err := safe.StateGetByID[*config.MachineConfig](suite.Ctx(), suite.State(), config.ActiveID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tif cfg == nil {\n\t\tcfg = config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineType:       machineType.String(),\n\t\t\t\tMachineNodeLabels: labels,\n\t\t\t},\n\t\t}))\n\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\t} else {\n\t\tcfg.Container().RawV1Alpha1().MachineConfig.MachineNodeLabels = labels\n\t\tcfg.Container().RawV1Alpha1().MachineConfig.MachineType = machineType.String()\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\t}\n}\n\nfunc (suite *NodeLabelsSuite) TestAddLabel() {\n\t// given\n\texpectedLabel := \"expectedLabel\"\n\texpectedValue := \"expectedValue\"\n\n\t// when\n\tsuite.updateMachineConfig(machine.TypeWorker, map[string]string{\n\t\texpectedLabel: expectedValue,\n\t})\n\n\t// then\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedLabel},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(expectedValue, labelSpec.TypedSpec().Value)\n\t\t})\n\trtestutils.AssertNoResource[*k8s.NodeLabelSpec](suite.Ctx(), suite.T(), suite.State(), constants.LabelNodeRoleControlPlane)\n}\n\nfunc (suite *NodeLabelsSuite) TestChangeLabel() {\n\t// given\n\texpectedLabel := \"someLabel\"\n\toldValue := \"oldValue\"\n\texpectedValue := \"newValue\"\n\n\t// when\n\tsuite.updateMachineConfig(machine.TypeControlPlane, map[string]string{\n\t\texpectedLabel: oldValue,\n\t})\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedLabel},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(oldValue, labelSpec.TypedSpec().Value)\n\t\t})\n\n\tsuite.updateMachineConfig(machine.TypeControlPlane, map[string]string{\n\t\texpectedLabel: expectedValue,\n\t})\n\n\t// then\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedLabel},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(expectedValue, labelSpec.TypedSpec().Value)\n\t\t})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{constants.LabelNodeRoleControlPlane},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(labelSpec.TypedSpec().Value)\n\t\t})\n}\n\nfunc (suite *NodeLabelsSuite) TestDeleteLabel() {\n\t// given\n\texpectedLabel := \"label\"\n\texpectedValue := \"labelValue\"\n\n\t// when\n\tsuite.updateMachineConfig(machine.TypeWorker, map[string]string{\n\t\texpectedLabel: expectedValue,\n\t})\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{expectedLabel},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(expectedValue, labelSpec.TypedSpec().Value)\n\t\t})\n\n\tsuite.updateMachineConfig(machine.TypeWorker, map[string]string{})\n\n\t// then\n\trtestutils.AssertNoResource[*k8s.NodeLabelSpec](suite.Ctx(), suite.T(), suite.State(), expectedLabel)\n\trtestutils.AssertNoResource[*k8s.NodeLabelSpec](suite.Ctx(), suite.T(), suite.State(), constants.LabelNodeRoleControlPlane)\n}\n\nfunc (suite *NodeLabelsSuite) TestExtensionLabels() {\n\text1 := runtime.NewExtensionStatus(runtime.NamespaceName, \"0\")\n\text1.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"zfs\",\n\t\tVersion: \"2.2.4\",\n\t}\n\n\text2 := runtime.NewExtensionStatus(runtime.NamespaceName, \"1\")\n\text2.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"drbd\",\n\t\tVersion: \"9.2.8-v1.7.5\",\n\t}\n\n\text3 := runtime.NewExtensionStatus(runtime.NamespaceName, \"2\")\n\text3.TypedSpec().Metadata = extensions.Metadata{\n\t\tName:    \"schematic\",\n\t\tVersion: \"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext1))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext2))\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), ext3))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"extensions.talos.dev/zfs\"},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"2.2.4\", labelSpec.TypedSpec().Value)\n\t\t})\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"extensions.talos.dev/drbd\"},\n\t\tfunc(labelSpec *k8s.NodeLabelSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"9.2.8-v1.7.5\", labelSpec.TypedSpec().Value)\n\t\t})\n\n\trtestutils.AssertNoResource[*k8s.NodeLabelSpec](suite.Ctx(), suite.T(), suite.State(), \"extensions.talos.dev/schematic\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/nodewatch\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// watchErrorsThreshold is the number of consecutive watch errors before the controller stops watching.\nconst watchErrorsThreshold = 5\n\n// NodeStatusController pulls list of Affiliate resource from the Kubernetes registry.\ntype NodeStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeStatusController) Name() string {\n\treturn \"k8s.NodeStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *NodeStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tkubernetesClient *kubernetes.Client\n\t\tnodewatcher      *nodewatch.NodeWatcher\n\t\twatchCtxCancel   context.CancelFunc\n\t\tnotifyCh         <-chan struct{}\n\t\twatchErrCh       <-chan error\n\t\tnotifyCloser     func()\n\t\twatchErrors      int\n\t\twatchReady       bool\n\t)\n\n\tcloseWatcher := func() {\n\t\tif watchCtxCancel != nil {\n\t\t\twatchCtxCancel()\n\t\t\twatchCtxCancel = nil\n\t\t}\n\n\t\tif notifyCloser != nil {\n\t\t\tnotifyCloser()\n\t\t\tnotifyCloser = nil\n\t\t\tnotifyCh = nil\n\t\t\twatchErrCh = nil\n\t\t}\n\n\t\tif kubernetesClient != nil {\n\t\t\tkubernetesClient.Close() //nolint:errcheck\n\n\t\t\tkubernetesClient = nil\n\t\t}\n\n\t\twatchErrors = 0\n\t\twatchReady = false\n\t\tnodewatcher = nil\n\t}\n\n\tdefer closeWatcher()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-notifyCh:\n\t\t\twatchErrors = 0\n\t\t\twatchReady = true\n\t\tcase watchErr := <-watchErrCh:\n\t\t\tlogger.Error(\"node watch error\", zap.Error(watchErr), zap.Int(\"error_count\", watchErrors))\n\n\t\t\twatchErrors++\n\n\t\t\tif watchErrors >= watchErrorsThreshold {\n\t\t\t\tcloseWatcher()\n\t\t\t} else {\n\t\t\t\t// keep waiting\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tnodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting nodename: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif nodename.TypedSpec().SkipNodeRegistration {\n\t\t\t// node is not registered with Kubernetes, so we can't pull the status\n\t\t\tcloseWatcher()\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = conditions.WaitForKubeconfigReady(constants.KubeletKubeconfig).Wait(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif nodewatcher != nil && nodewatcher.Nodename() != nodename.TypedSpec().Nodename {\n\t\t\t// nodename changed, so we need to reinitialize the watcher\n\t\t\tcloseWatcher()\n\t\t}\n\n\t\tif kubernetesClient == nil {\n\t\t\tkubernetesClient, err = kubernetes.NewClientFromKubeletKubeconfig()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif nodewatcher == nil {\n\t\t\tnodewatcher = nodewatch.NewNodeWatcher(kubernetesClient, nodename.TypedSpec().Nodename)\n\t\t}\n\n\t\tif notifyCh == nil {\n\t\t\tvar watchCtx context.Context\n\n\t\t\twatchCtx, watchCtxCancel = context.WithCancel(ctx) //nolint:govet\n\n\t\t\tnotifyCh, watchErrCh, notifyCloser, err = nodewatcher.Watch(watchCtx, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting up node watcher: %w\", err) //nolint:govet\n\t\t\t}\n\t\t}\n\n\t\tif !watchReady {\n\t\t\t// node watcher is not ready yet, skip updating output resource\n\t\t\tcontinue\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tnode, err := nodewatcher.Get()\n\t\tif err != nil && !apierrors.IsNotFound(err) {\n\t\t\treturn fmt.Errorf(\"error getting node: %w\", err)\n\t\t}\n\n\t\tif node != nil {\n\t\t\tpodCIDRs := make([]netip.Prefix, 0, len(node.Spec.PodCIDRs))\n\t\t\tfor _, cidr := range node.Spec.PodCIDRs {\n\t\t\t\tprefix, err := netip.ParsePrefix(cidr)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Warn(\"error parsing pod CIDR\", zap.String(\"cidr\", cidr), zap.Error(err))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tpodCIDRs = append(podCIDRs, prefix)\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewNodeStatus(k8s.NamespaceName, node.Name),\n\t\t\t\tfunc(res *k8s.NodeStatus) error {\n\t\t\t\t\tres.TypedSpec().Nodename = node.Name\n\t\t\t\t\tres.TypedSpec().Unschedulable = node.Spec.Unschedulable\n\t\t\t\t\tres.TypedSpec().Labels = node.Labels\n\t\t\t\t\tres.TypedSpec().Annotations = node.Annotations\n\t\t\t\t\tres.TypedSpec().NodeReady = false\n\t\t\t\t\tres.TypedSpec().PodCIDRs = podCIDRs\n\n\t\t\t\t\tfor _, condition := range node.Status.Conditions {\n\t\t\t\t\t\tif condition.Type == v1.NodeReady {\n\t\t\t\t\t\t\tres.TypedSpec().NodeReady = condition.Status == v1.ConditionTrue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[node.Name] = struct{}{}\n\t\t}\n\n\t\titems, err := safe.ReaderListAll[*k8s.NodeStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing node statuses: %w\", err)\n\t\t}\n\n\t\tfor res := range items.All() {\n\t\t\tif _, touched := touchedIDs[res.Metadata().ID()]; touched {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error destroying node status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_taint_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// NodeTaintSpecController manages k8s.NodeTaintSpec based on configuration.\ntype NodeTaintSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeTaintSpecController) Name() string {\n\treturn \"k8s.NodeTaintSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeTaintSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeTaintSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeTaintSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeTaintSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tif cfg.Config().Cluster() != nil {\n\t\t\t\tif cfg.Config().Machine().Type().IsControlPlane() && !cfg.Config().Cluster().ScheduleOnControlPlanes() {\n\t\t\t\t\tif err = createTaint(ctx, r, constants.LabelNodeRoleControlPlane, \"\", string(v1.TaintEffectNoSchedule)); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor key, val := range cfg.Config().Machine().NodeTaints() {\n\t\t\t\tvalue, effect, found := strings.Cut(val, \":\")\n\t\t\t\tif !found {\n\t\t\t\t\teffect = value\n\t\t\t\t\tvalue = \"\"\n\t\t\t\t}\n\n\t\t\t\tif err = createTaint(ctx, r, key, value, effect); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*k8s.NodeTaintSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc createTaint(ctx context.Context, r controller.Runtime, key string, val string, effect string) error {\n\tif err := safe.WriterModify(ctx, r, k8s.NewNodeTaintSpec(key), func(k *k8s.NodeTaintSpec) error {\n\t\tk.TypedSpec().Key = key\n\t\tk.TypedSpec().Value = val\n\t\tk.TypedSpec().Effect = effect\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating node taint spec: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/node_taint_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype NodeTaintsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestNodeTaintsSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeTaintsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodeTaintSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *NodeTaintsSuite) updateMachineConfig(machineType machine.Type, allowScheduling bool, taints ...customTaint) {\n\tcfg, err := safe.StateGetByID[*config.MachineConfig](suite.Ctx(), suite.State(), config.ActiveID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tnodeTaints := xslices.ToMap(taints, func(t customTaint) (string, string) { return t.key, t.value })\n\n\tif cfg == nil {\n\t\tcfg = config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineType:       machineType.String(),\n\t\t\t\tMachineNodeTaints: nodeTaints,\n\t\t\t},\n\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\tAllowSchedulingOnControlPlanes: new(allowScheduling),\n\t\t\t},\n\t\t}))\n\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\t} else {\n\t\tcfg.Container().RawV1Alpha1().ClusterConfig.AllowSchedulingOnControlPlanes = new(allowScheduling)\n\t\tcfg.Container().RawV1Alpha1().MachineConfig.MachineType = machineType.String()\n\t\tcfg.Container().RawV1Alpha1().MachineConfig.MachineNodeTaints = nodeTaints\n\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\t}\n}\n\nfunc (suite *NodeTaintsSuite) TestWorker() {\n\tsuite.updateMachineConfig(machine.TypeWorker, false)\n\n\trtestutils.AssertNoResource[*k8s.NodeTaintSpec](suite.Ctx(), suite.T(), suite.State(), constants.LabelNodeRoleControlPlane)\n}\n\nfunc (suite *NodeTaintsSuite) TestControlplane() {\n\tsuite.updateMachineConfig(machine.TypeControlPlane, false)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{constants.LabelNodeRoleControlPlane},\n\t\tfunc(labelSpec *k8s.NodeTaintSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(labelSpec.TypedSpec().Value)\n\t\t\tasrt.Equal(string(v1.TaintEffectNoSchedule), labelSpec.TypedSpec().Effect)\n\t\t})\n\n\tsuite.updateMachineConfig(machine.TypeControlPlane, true)\n\n\trtestutils.AssertNoResource[*k8s.NodeTaintSpec](suite.Ctx(), suite.T(), suite.State(), constants.LabelNodeRoleControlPlane)\n}\n\nfunc (suite *NodeTaintsSuite) TestCustomTaints() {\n\tconst customTaintKey = \"key1\"\n\n\tsuite.updateMachineConfig(machine.TypeControlPlane, false, customTaint{\n\t\tkey:   customTaintKey,\n\t\tvalue: \"value1:NoSchedule\",\n\t})\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{customTaintKey},\n\t\tfunc(labelSpec *k8s.NodeTaintSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(customTaintKey, labelSpec.TypedSpec().Key)\n\t\t\tasrt.Equal(\"value1\", labelSpec.TypedSpec().Value)\n\t\t\tasrt.Equal(string(v1.TaintEffectNoSchedule), labelSpec.TypedSpec().Effect)\n\t\t})\n\n\tsuite.updateMachineConfig(machine.TypeControlPlane, false)\n\n\trtestutils.AssertNoResource[*k8s.NodeTaintSpec](suite.Ctx(), suite.T(), suite.State(), customTaintKey)\n}\n\ntype customTaint struct {\n\tkey   string\n\tvalue string\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodeip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/net\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NodeIPController renders manifests based on templates and config/secrets.\ntype NodeIPController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeIPController) Name() string {\n\treturn \"k8s.NodeIPController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeIPController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeIPConfigType,\n\t\t\tID:        optional.Some(k8s.KubeletID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeIPController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodeIPType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodeIPController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGet[*k8s.NodeIPConfig](ctx, r, resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPConfigType, k8s.KubeletID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tcfgSpec := cfg.TypedSpec()\n\n\t\tnodeAddrs, err := safe.ReaderGet[*network.NodeAddress](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.NodeAddressType,\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t}\n\n\t\taddrs := nodeAddrs.TypedSpec().IPs()\n\t\tcidrs := slices.Concat(\n\t\t\tcfgSpec.ValidSubnets,\n\t\t\txslices.Map(cfgSpec.ExcludeSubnets, func(cidr string) string { return \"!\" + cidr }),\n\t\t)\n\n\t\tips, err := net.FilterIPs(addrs, cidrs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error filtering IPs: %w\", err)\n\t\t}\n\n\t\tif len(ips) == 0 {\n\t\t\tlogger.Warn(\"no suitable node IP found, please make sure .machine.kubelet.nodeIP filters and pod/service subnets are set up correctly\")\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// filter down to make sure only one IPv4 and one IPv6 address stays\n\t\tvar hasIPv4, hasIPv6 bool\n\n\t\tnodeIPs := make([]netip.Addr, 0, 2)\n\n\t\tfor _, ip := range ips {\n\t\t\tswitch {\n\t\t\tcase ip.Is4():\n\t\t\t\tif !hasIPv4 {\n\t\t\t\t\tnodeIPs = append(nodeIPs, ip)\n\t\t\t\t\thasIPv4 = true\n\t\t\t\t} else {\n\t\t\t\t\tlogger.Warn(\"node IP skipped, please use .machine.kubelet.nodeIP to provide explicit subnet for the node IP\", zap.Stringer(\"address\", ip))\n\t\t\t\t}\n\t\t\tcase ip.Is6():\n\t\t\t\tif !hasIPv6 {\n\t\t\t\t\tnodeIPs = append(nodeIPs, ip)\n\t\t\t\t\thasIPv6 = true\n\t\t\t\t} else {\n\t\t\t\t\tlogger.Warn(\"node IP skipped, please use .machine.kubelet.nodeIP to provide explicit subnet for the node IP\", zap.Stringer(\"address\", ip))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tk8s.NewNodeIP(k8s.NamespaceName, k8s.KubeletID),\n\t\t\tfunc(r *k8s.NodeIP) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Addresses = nodeIPs\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying NodeIP resource: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodeip_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// NodeIPConfigController configures k8s.NodeIP based on machine config.\ntype NodeIPConfigController = transform.Controller[*config.MachineConfig, *k8s.NodeIPConfig]\n\n// NewNodeIPConfigController instanciates the controller.\n//\n//nolint:gocyclo\nfunc NewNodeIPConfigController() *NodeIPConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *k8s.NodeIPConfig]{\n\t\t\tName: \"k8s.NodeIPConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*k8s.NodeIPConfig] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*k8s.NodeIPConfig]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Machine() == nil || cfg.Config().Cluster() == nil {\n\t\t\t\t\treturn optional.None[*k8s.NodeIPConfig]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(k8s.NewNodeIPConfig(k8s.NamespaceName, k8s.KubeletID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *k8s.NodeIPConfig) error {\n\t\t\t\tspec := res.TypedSpec()\n\t\t\t\tcfgProvider := cfg.Config()\n\n\t\t\t\tspec.ValidSubnets = cfgProvider.Machine().Kubelet().NodeIP().ValidSubnets()\n\n\t\t\t\tif len(spec.ValidSubnets) == 0 {\n\t\t\t\t\t// automatically deduce validsubnets from ServiceCIDRs\n\t\t\t\t\tvar err error\n\n\t\t\t\t\tspec.ValidSubnets, err = ipSubnetsFromServiceCIDRs(cfgProvider.Cluster().Network().ServiceCIDRs())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error building valid subnets: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tspec.ExcludeSubnets = nil\n\n\t\t\t\t// filter out Pod & Service CIDRs, they can't be kubelet IPs\n\t\t\t\tspec.ExcludeSubnets = append(\n\t\t\t\t\tappend(\n\t\t\t\t\t\tspec.ExcludeSubnets,\n\t\t\t\t\t\tcfgProvider.Cluster().Network().PodCIDRs()...,\n\t\t\t\t\t),\n\t\t\t\t\tcfgProvider.Cluster().Network().ServiceCIDRs()...,\n\t\t\t\t)\n\n\t\t\t\t// filter out any virtual IPs, they can't be node IPs either\n\t\t\t\tfor _, device := range cfgProvider.Machine().Network().Devices() {\n\t\t\t\t\tif device.VIPConfig() != nil {\n\t\t\t\t\t\tspec.ExcludeSubnets = append(spec.ExcludeSubnets, device.VIPConfig().IP())\n\t\t\t\t\t}\n\n\t\t\t\t\tfor _, vlan := range device.Vlans() {\n\t\t\t\t\t\tif vlan.VIPConfig() != nil {\n\t\t\t\t\t\t\tspec.ExcludeSubnets = append(spec.ExcludeSubnets, vlan.VIPConfig().IP())\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor _, doc := range cfgProvider.NetworkVirtualIPConfigs() {\n\t\t\t\t\tspec.ExcludeSubnets = append(spec.ExcludeSubnets, doc.VIP().String())\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\nfunc ipSubnetsFromServiceCIDRs(serviceCIDRs []string) ([]string, error) {\n\t// automatically configure valid IP subnets based on service CIDRs\n\t// if the primary service CIDR is IPv4, primary kubelet node IP should be IPv4 as well, and so on\n\tresult := make([]string, 0, len(serviceCIDRs))\n\n\tfor _, cidr := range serviceCIDRs {\n\t\tnetwork, err := netip.ParsePrefix(cidr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse subnet: %w\", err)\n\t\t}\n\n\t\tif network.Addr().Is6() {\n\t\t\tresult = append(result, \"::/0\")\n\t\t} else {\n\t\t\tresult = append(result, \"0.0.0.0/0\")\n\t\t}\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodeip_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype NodeIPConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NodeIPConfigSuite) TestReconcileWithSubnets() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletNodeIP: &v1alpha1.KubeletNodeIPConfig{\n\t\t\t\t\t\t\tKubeletNodeIPValidSubnets: []string{\"10.0.0.0/24\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy controller\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\tSharedIP: \"1.2.3.4\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 100,\n\t\t\t\t\t\t\t\t\t\tVlanVIP: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\t\t\tSharedIP: \"5.6.7.8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tServiceSubnet: []string{constants.DefaultIPv4ServiceNet},\n\t\t\t\t\t\tPodSubnet:     []string{constants.DefaultIPv4PodNet},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, k8s.KubeletID, func(cfg *k8s.NodeIPConfig, asrt *assert.Assertions) {\n\t\tspec := cfg.TypedSpec()\n\n\t\tasrt.Equal([]string{\"10.0.0.0/24\"}, spec.ValidSubnets)\n\t\tasrt.Equal(\n\t\t\t[]string{\"10.244.0.0/16\", \"10.96.0.0/12\", \"1.2.3.4\", \"5.6.7.8\"},\n\t\t\tspec.ExcludeSubnets,\n\t\t)\n\t})\n}\n\nfunc (suite *NodeIPConfigSuite) TestReconcileWithNewVIPs() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfgV1Alpha1 := &v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\tURL: u,\n\t\t\t\t},\n\t\t\t},\n\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\tServiceSubnet: []string{constants.DefaultIPv4ServiceNet},\n\t\t\t\tPodSubnet:     []string{constants.DefaultIPv4PodNet},\n\t\t\t},\n\t\t},\n\t}\n\n\tcfgVIP := network.NewLayer2VIPConfigV1Alpha1(\"5.6.7.8\")\n\tcfgVIP.LinkName = \"eth0\"\n\n\tctr, err := container.New(cfgV1Alpha1, cfgVIP)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, k8s.KubeletID, func(cfg *k8s.NodeIPConfig, asrt *assert.Assertions) {\n\t\tspec := cfg.TypedSpec()\n\n\t\tasrt.Equal([]string{\"0.0.0.0/0\"}, spec.ValidSubnets)\n\t\tasrt.Equal(\n\t\t\t[]string{\"10.244.0.0/16\", \"10.96.0.0/12\", \"5.6.7.8\"},\n\t\t\tspec.ExcludeSubnets,\n\t\t)\n\t})\n}\n\nfunc (suite *NodeIPConfigSuite) TestReconcileDefaults() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\t\tServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet},\n\t\t\t\t\t\tPodSubnet:     []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, k8s.KubeletID, func(cfg *k8s.NodeIPConfig, asrt *assert.Assertions) {\n\t\tspec := cfg.TypedSpec()\n\n\t\tasrt.Equal([]string{\"0.0.0.0/0\", \"::/0\"}, spec.ValidSubnets)\n\t\tasrt.Equal(\n\t\t\t[]string{\"10.244.0.0/16\", \"fc00:db8:10::/56\", \"10.96.0.0/12\", \"fc00:db8:20::/112\"},\n\t\t\tspec.ExcludeSubnets,\n\t\t)\n\t})\n}\n\nfunc TestNodeIPConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeIPConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(k8sctrl.NewNodeIPConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodeip_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype NodeIPSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NodeIPSuite) TestReconcileIPv4() {\n\tcfg := k8s.NewNodeIPConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().ValidSubnets = []string{\"10.0.0.0/24\", \"::/0\"}\n\tcfg.TypedSpec().ExcludeSubnets = []string{\"10.0.0.2\"}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\taddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t)\n\n\taddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.0.0.2/32\"), // excluded explicitly\n\t\tnetip.MustParsePrefix(\"10.0.0.5/24\"),\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), addresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(nodeIP *k8s.NodeIP, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"[10.0.0.5]\", fmt.Sprintf(\"%s\", nodeIP.TypedSpec().Addresses))\n\t})\n}\n\nfunc (suite *NodeIPSuite) TestReconcileDefaultSubnets() {\n\tcfg := k8s.NewNodeIPConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().ValidSubnets = []string{\"0.0.0.0/0\", \"::/0\"}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\taddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t)\n\taddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.0.0.5/24\"),\n\t\tnetip.MustParsePrefix(\"192.168.1.1/24\"),\n\t\tnetip.MustParsePrefix(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334/64\"),\n\t\tnetip.MustParsePrefix(\"2001:0db8:85a3:0000:0000:8a2e:0370:7335/64\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), addresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(nodeIP *k8s.NodeIP, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"[10.0.0.5 2001:db8:85a3::8a2e:370:7334]\", fmt.Sprintf(\"%s\", nodeIP.TypedSpec().Addresses))\n\t})\n}\n\nfunc (suite *NodeIPSuite) TestReconcileNoMatch() {\n\tcfg := k8s.NewNodeIPConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().ValidSubnets = []string{\"0.0.0.0/0\"}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\taddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t)\n\taddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.0.0.2/32\"),\n\t\tnetip.MustParsePrefix(\"10.0.0.5/24\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), addresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(nodeIP *k8s.NodeIP, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"[10.0.0.2]\", fmt.Sprintf(\"%s\", nodeIP.TypedSpec().Addresses))\n\t})\n\n\tcfg.TypedSpec().ValidSubnets = nil\n\tcfg.TypedSpec().ExcludeSubnets = []string{\"10.0.0.2\"}\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\t// the node IP doesn't change, as there's no match for the filter\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(nodeIP *k8s.NodeIP, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"[10.0.0.2]\", fmt.Sprintf(\"%s\", nodeIP.TypedSpec().Addresses))\n\t})\n}\n\nfunc (suite *NodeIPSuite) TestReconcileIPv6Denies() {\n\tcfg := k8s.NewNodeIPConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().ValidSubnets = []string{\"::/0\", \"!fd01:cafe::f14c:9fa1:8496:557f/128\"}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\taddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s),\n\t)\n\n\taddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"fd01:cafe::f14c:9fa1:8496:557f/128\"),\n\t\tnetip.MustParsePrefix(\"fd01:cafe::5054:ff:fe1f:c7bd/64\"),\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), addresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.KubeletID}, func(nodeIP *k8s.NodeIP, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"[fd01:cafe::5054:ff:fe1f:c7bd]\", fmt.Sprintf(\"%s\", nodeIP.TypedSpec().Addresses))\n\t})\n}\n\nfunc TestNodeIPSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeIPSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodeIPController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodename.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/nodename\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NodenameController renders manifests based on templates and config/secrets.\ntype NodenameController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodenameController) Name() string {\n\treturn \"k8s.NodenameController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodenameController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodenameController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.NodenameType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NodenameController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tcfgProvider := cfg.Config()\n\n\t\tif cfgProvider.Machine() == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\thostnameStatus, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tk8s.NewNodename(k8s.NamespaceName, k8s.NodenameID),\n\t\t\tfunc(res *k8s.Nodename) error {\n\t\t\t\tvar hostname string\n\n\t\t\t\tif cfgProvider.Machine().Kubelet().RegisterWithFQDN() {\n\t\t\t\t\thostname = hostnameStatus.TypedSpec().FQDN()\n\t\t\t\t} else {\n\t\t\t\t\thostname = hostnameStatus.TypedSpec().Hostname\n\t\t\t\t}\n\n\t\t\t\tres.TypedSpec().Nodename, err = nodename.FromHostname(hostname)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tres.TypedSpec().HostnameVersion = hostnameStatus.Metadata().Version().String()\n\t\t\t\tres.TypedSpec().SkipNodeRegistration = cfgProvider.Machine().Kubelet().SkipNodeRegistration()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying nodename resource: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/nodename_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype NodenameSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NodenameSuite) assertNodename(expected string) {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.NodenameID}, func(nodename *k8s.Nodename, asrt *assert.Assertions) {\n\t\tasrt.Equal(expected, nodename.TypedSpec().Nodename)\n\t})\n}\n\nfunc (suite *NodenameSuite) TestDefault() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"Foo-\"\n\thostnameStatus.TypedSpec().Domainname = \"bar.ltd\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\tsuite.assertNodename(\"foo\")\n}\n\nfunc (suite *NodenameSuite) TestFQDN() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletRegisterWithFQDN: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"foo\"\n\thostnameStatus.TypedSpec().Domainname = \"bar.ltd\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\tsuite.assertNodename(\"foo.bar.ltd\")\n}\n\nfunc TestNodenameSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodenameSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&k8sctrl.NodenameController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/render_config_static_pods.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/compatibility\"\n\t\"go.uber.org/zap\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\tk8sjson \"k8s.io/apimachinery/pkg/runtime/serializer/json\"\n\tapiserverv1 \"k8s.io/apiserver/pkg/apis/apiserver/v1\"\n\tauditv1 \"k8s.io/apiserver/pkg/apis/audit/v1\"\n\tschedulerv1 \"k8s.io/kube-scheduler/config/v1\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// RenderConfigsStaticPodController manages k8s.ConfigsReady and renders configs for the control plane.\ntype RenderConfigsStaticPodController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RenderConfigsStaticPodController) Name() string {\n\treturn \"k8s.RenderConfigsStaticPodController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RenderConfigsStaticPodController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.AdmissionControlConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.AuditPolicyConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.AuthorizationConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.SchedulerConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RenderConfigsStaticPodController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.ConfigStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *RenderConfigsStaticPodController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tadmissionRes, err := safe.ReaderGetByID[*k8s.AdmissionControlConfig](ctx, r, k8s.AdmissionControlConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting admission config resource: %w\", err)\n\t\t}\n\n\t\tadmissionConfig := admissionRes.TypedSpec()\n\n\t\tauditRes, err := safe.ReaderGetByID[*k8s.AuditPolicyConfig](ctx, r, k8s.AuditPolicyConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting audit config resource: %w\", err)\n\t\t}\n\n\t\tauditConfig := auditRes.TypedSpec()\n\n\t\tauthorizerConfigRes, err := safe.ReaderGetByID[*k8s.AuthorizationConfig](ctx, r, k8s.AuthorizationConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting authorization config resource: %w\", err)\n\t\t}\n\n\t\tauthorizerConfig := authorizerConfigRes.TypedSpec()\n\n\t\tkubeAPIServerVersion := compatibility.VersionFromImageRef(authorizerConfig.Image)\n\n\t\tkubeSchedulerRes, err := safe.ReaderGetByID[*k8s.SchedulerConfig](ctx, r, k8s.SchedulerConfigID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting scheduler config resource: %w\", err)\n\t\t}\n\n\t\tkubeSchedulerConfig := kubeSchedulerRes.TypedSpec()\n\n\t\ttype configFile struct {\n\t\t\tfilename string\n\t\t\tf        func() (runtime.Object, error)\n\t\t}\n\n\t\tserializer := k8sjson.NewSerializerWithOptions(\n\t\t\tk8sjson.DefaultMetaFactory, nil, nil,\n\t\t\tk8sjson.SerializerOptions{\n\t\t\t\tYaml:   true,\n\t\t\t\tPretty: true,\n\t\t\t\tStrict: true,\n\t\t\t},\n\t\t)\n\n\t\tfor _, pod := range []struct {\n\t\t\tname         string\n\t\t\tdirectory    string\n\t\t\tselinuxLabel string\n\t\t\tuid          int\n\t\t\tgid          int\n\t\t\tconfigs      []configFile\n\t\t}{\n\t\t\t{\n\t\t\t\tname:         \"kube-apiserver\",\n\t\t\t\tdirectory:    constants.KubernetesAPIServerConfigDir,\n\t\t\t\tselinuxLabel: constants.KubernetesAPIServerConfigDirSELinuxLabel,\n\t\t\t\tuid:          constants.KubernetesAPIServerRunUser,\n\t\t\t\tgid:          constants.KubernetesAPIServerRunGroup,\n\t\t\t\tconfigs: []configFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: \"admission-control-config.yaml\",\n\t\t\t\t\t\tf:        admissionControlConfig(admissionConfig),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: \"auditpolicy.yaml\",\n\t\t\t\t\t\tf:        auditPolicyConfig(auditConfig),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: \"authorization-config.yaml\",\n\t\t\t\t\t\tf:        authorizationConfig(authorizerConfig, kubeAPIServerVersion),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:         \"kube-scheduler\",\n\t\t\t\tdirectory:    constants.KubernetesSchedulerConfigDir,\n\t\t\t\tselinuxLabel: constants.KubernetesSchedulerConfigDirSELinuxLabel,\n\t\t\t\tuid:          constants.KubernetesSchedulerRunUser,\n\t\t\t\tgid:          constants.KubernetesSchedulerRunGroup,\n\t\t\t\tconfigs: []configFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: \"scheduler-config.yaml\",\n\t\t\t\t\t\tf:        schedulerConfig(kubeSchedulerConfig),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t} {\n\t\t\tif err = os.MkdirAll(pod.directory, 0o755); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating config directory for %q: %w\", pod.name, err)\n\t\t\t}\n\n\t\t\tif err = selinux.SetLabel(pod.directory, pod.selinuxLabel); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, configFile := range pod.configs {\n\t\t\t\tvar obj runtime.Object\n\n\t\t\t\tobj, err = configFile.f()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error generating configuration %q for %q: %w\", configFile.filename, pod.name, err)\n\t\t\t\t}\n\n\t\t\t\tvar buf bytes.Buffer\n\n\t\t\t\tif err = serializer.Encode(obj, &buf); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error marshaling configuration %q for %q: %w\", configFile.filename, pod.name, err)\n\t\t\t\t}\n\n\t\t\t\tif err = os.WriteFile(filepath.Join(pod.directory, configFile.filename), buf.Bytes(), 0o400); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error writing configuration %q for %q: %w\", configFile.filename, pod.name, err)\n\t\t\t\t}\n\n\t\t\t\tif err = os.Chown(filepath.Join(pod.directory, configFile.filename), pod.uid, pod.gid); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error chowning %q for %q: %w\", configFile.filename, pod.name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID), func(r *k8s.ConfigStatus) error {\n\t\t\tr.TypedSpec().Ready = true\n\t\t\tr.TypedSpec().Version = admissionRes.Metadata().Version().String() +\n\t\t\t\tauditRes.Metadata().Version().String() +\n\t\t\t\tauthorizerConfigRes.Metadata().Version().String() +\n\t\t\t\tkubeSchedulerRes.Metadata().Version().String()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc admissionControlConfig(spec *k8s.AdmissionControlConfigSpec) func() (runtime.Object, error) {\n\treturn func() (runtime.Object, error) {\n\t\tvar cfg apiserverv1.AdmissionConfiguration\n\n\t\tcfg.APIVersion = apiserverv1.SchemeGroupVersion.String()\n\t\tcfg.Kind = \"AdmissionConfiguration\"\n\t\tcfg.Plugins = []apiserverv1.AdmissionPluginConfiguration{}\n\n\t\tfor _, plugin := range spec.Config {\n\t\t\traw, err := json.Marshal(plugin.Configuration)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error marshaling configuration for plugin %q: %w\", plugin.Name, err)\n\t\t\t}\n\n\t\t\tcfg.Plugins = append(cfg.Plugins,\n\t\t\t\tapiserverv1.AdmissionPluginConfiguration{\n\t\t\t\t\tName: plugin.Name,\n\t\t\t\t\tConfiguration: &runtime.Unknown{\n\t\t\t\t\t\tRaw: raw,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn &cfg, nil\n\t}\n}\n\nfunc auditPolicyConfig(spec *k8s.AuditPolicyConfigSpec) func() (runtime.Object, error) {\n\treturn func() (runtime.Object, error) {\n\t\tvar cfg auditv1.Policy\n\n\t\tif err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(spec.Config, &cfg, true); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error unmarshaling audit policy configuration: %w\", err)\n\t\t}\n\n\t\treturn &cfg, nil\n\t}\n}\n\nfunc schedulerConfig(spec *k8s.SchedulerConfigSpec) func() (runtime.Object, error) {\n\treturn func() (runtime.Object, error) {\n\t\tvar cfg schedulerv1.KubeSchedulerConfiguration\n\n\t\tif err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(spec.Config, &cfg, false); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error unmarshaling scheduler configuration: %w\", err)\n\t\t}\n\n\t\tcfg.APIVersion = \"kubescheduler.config.k8s.io/v1\"\n\t\tcfg.Kind = \"KubeSchedulerConfiguration\"\n\t\tcfg.ClientConnection.Kubeconfig = filepath.Join(constants.KubernetesSchedulerSecretsDir, \"kubeconfig\")\n\n\t\treturn &cfg, nil\n\t}\n}\n\nfunc authorizationConfig(spec *k8s.AuthorizationConfigSpec, kubeAPIServerVersion compatibility.Version) func() (runtime.Object, error) {\n\treturn func() (runtime.Object, error) {\n\t\tvar cfg apiserverv1.AuthorizationConfiguration\n\n\t\tcfg.APIVersion = kubeAPIServerVersion.KubeAPIServerAuthorizationConfigAPIVersion()\n\t\tcfg.Kind = \"AuthorizationConfiguration\"\n\t\tcfg.Authorizers = []apiserverv1.AuthorizerConfiguration{}\n\n\t\tfor _, authorizer := range spec.Config {\n\t\t\tauthorizerConfig := apiserverv1.AuthorizerConfiguration{\n\t\t\t\tName: authorizer.Name,\n\t\t\t\tType: authorizer.Type,\n\t\t\t}\n\n\t\t\tif authorizer.Webhook != nil {\n\t\t\t\tvar webhookCfg apiserverv1.WebhookConfiguration\n\n\t\t\t\tif err := runtime.DefaultUnstructuredConverter.FromUnstructured(authorizer.Webhook, &webhookCfg); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"error unmarshaling authorizer webhook configuration: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tauthorizerConfig.Webhook = &webhookCfg\n\t\t\t}\n\n\t\t\tcfg.Authorizers = append(cfg.Authorizers, authorizerConfig)\n\t\t}\n\n\t\treturn &cfg, nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/render_secrets_static_pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s/internal/k8stemplates\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// RenderSecretsStaticPodController manages k8s.SecretsReady and renders secrets from secrets.Kubernetes.\ntype RenderSecretsStaticPodController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RenderSecretsStaticPodController) Name() string {\n\treturn \"k8s.RenderSecretsStaticPodController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RenderSecretsStaticPodController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EtcdRootType,\n\t\t\tID:        optional.Some(secrets.EtcdRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesType,\n\t\t\tID:        optional.Some(secrets.KubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesDynamicCertsType,\n\t\t\tID:        optional.Some(secrets.KubernetesDynamicCertsID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EtcdType,\n\t\t\tID:        optional.Some(secrets.EtcdID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RenderSecretsStaticPodController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.SecretsStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *RenderSecretsStaticPodController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tsecretsRes, err := safe.ReaderGet[*secrets.Kubernetes](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets resource: %w\", err)\n\t\t}\n\n\t\tcertsRes, err := safe.ReaderGet[*secrets.KubernetesDynamicCerts](\n\t\t\tctx, r,\n\t\t\tresource.NewMetadata(secrets.NamespaceName, secrets.KubernetesDynamicCertsType, secrets.KubernetesDynamicCertsID, resource.VersionUndefined),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting certificates resource: %w\", err)\n\t\t}\n\n\t\tetcdRes, err := safe.ReaderGet[*secrets.Etcd](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdType, secrets.EtcdID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets resource: %w\", err)\n\t\t}\n\n\t\trootEtcdRes, err := safe.ReaderGet[*secrets.EtcdRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdRootType, secrets.EtcdRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets resource: %w\", err)\n\t\t}\n\n\t\trootK8sRes, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting secrets resource: %w\", err)\n\t\t}\n\n\t\trootEtcdSecrets := rootEtcdRes.TypedSpec()\n\t\trootK8sSecrets := rootK8sRes.TypedSpec()\n\t\tetcdSecrets := etcdRes.TypedSpec()\n\t\tk8sSecrets := secretsRes.TypedSpec()\n\t\tk8sCerts := certsRes.TypedSpec()\n\n\t\tserviceAccountKey, err := rootK8sSecrets.ServiceAccount.GetKey()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing service account key: %w\", err)\n\t\t}\n\n\t\ttype secret struct {\n\t\t\tgetter       func() *x509.PEMEncodedCertificateAndKey\n\t\t\tcertFilename string\n\t\t\tkeyFilename  string\n\t\t}\n\n\t\ttype file struct {\n\t\t\tfilename    string\n\t\t\tcontentFunc func() ([]byte, error)\n\t\t}\n\n\t\tfor _, pod := range []struct {\n\t\t\tname         string\n\t\t\tdirectory    string\n\t\t\tselinuxLabel string\n\t\t\tuid          int\n\t\t\tgid          int\n\t\t\tsecrets      []secret\n\t\t\tfiles        []file\n\t\t}{\n\t\t\t{\n\t\t\t\tname:         \"kube-apiserver\",\n\t\t\t\tdirectory:    constants.KubernetesAPIServerSecretsDir,\n\t\t\t\tselinuxLabel: constants.KubernetesAPIServerSecretsDirSELinuxLabel,\n\t\t\t\tuid:          constants.KubernetesAPIServerRunUser,\n\t\t\t\tgid:          constants.KubernetesAPIServerRunGroup,\n\t\t\t\tsecrets: []secret{\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return rootEtcdSecrets.EtcdCA },\n\t\t\t\t\t\tcertFilename: \"etcd-client-ca.crt\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return etcdSecrets.EtcdAPIServer },\n\t\t\t\t\t\tcertFilename: \"etcd-client.crt\",\n\t\t\t\t\t\tkeyFilename:  \"etcd-client.key\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter: func() *x509.PEMEncodedCertificateAndKey {\n\t\t\t\t\t\t\treturn &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\t\t\tCrt: bytes.Join(xslices.Map(rootK8sSecrets.AcceptedCAs, func(ca *x509.PEMEncodedCertificate) []byte { return ca.Crt }), nil),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcertFilename: \"ca.crt\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return k8sCerts.APIServer },\n\t\t\t\t\t\tcertFilename: \"apiserver.crt\",\n\t\t\t\t\t\tkeyFilename:  \"apiserver.key\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return k8sCerts.APIServerKubeletClient },\n\t\t\t\t\t\tcertFilename: \"apiserver-kubelet-client.crt\",\n\t\t\t\t\t\tkeyFilename:  \"apiserver-kubelet-client.key\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter: func() *x509.PEMEncodedCertificateAndKey {\n\t\t\t\t\t\t\treturn &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\t\t\tCrt: serviceAccountKey.GetPublicKeyPEM(),\n\t\t\t\t\t\t\t\tKey: serviceAccountKey.GetPrivateKeyPEM(),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcertFilename: \"service-account.pub\",\n\t\t\t\t\t\tkeyFilename:  \"service-account.key\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return rootK8sSecrets.AggregatorCA },\n\t\t\t\t\t\tcertFilename: \"aggregator-ca.crt\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return k8sCerts.FrontProxy },\n\t\t\t\t\t\tcertFilename: \"front-proxy-client.crt\",\n\t\t\t\t\t\tkeyFilename:  \"front-proxy-client.key\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tfiles: []file{\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename: \"encryptionconfig.yaml\",\n\t\t\t\t\t\tcontentFunc: func() ([]byte, error) {\n\t\t\t\t\t\t\treturn k8stemplates.Marshal(k8stemplates.APIServerEncryptionConfig(rootK8sSecrets))\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:         \"kube-controller-manager\",\n\t\t\t\tdirectory:    constants.KubernetesControllerManagerSecretsDir,\n\t\t\t\tselinuxLabel: constants.KubernetesControllerManagerSecretsDirSELinuxLabel,\n\t\t\t\tuid:          constants.KubernetesControllerManagerRunUser,\n\t\t\t\tgid:          constants.KubernetesControllerManagerRunGroup,\n\t\t\t\tsecrets: []secret{\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter:       func() *x509.PEMEncodedCertificateAndKey { return rootK8sSecrets.IssuingCA },\n\t\t\t\t\t\tcertFilename: \"ca.crt\",\n\t\t\t\t\t\tkeyFilename:  \"ca.key\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tgetter: func() *x509.PEMEncodedCertificateAndKey {\n\t\t\t\t\t\t\treturn &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\t\t\tCrt: serviceAccountKey.GetPublicKeyPEM(),\n\t\t\t\t\t\t\t\tKey: serviceAccountKey.GetPrivateKeyPEM(),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\tkeyFilename: \"service-account.key\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tfiles: []file{\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename:    \"kubeconfig\",\n\t\t\t\t\t\tcontentFunc: func() ([]byte, error) { return []byte(k8sSecrets.ControllerManagerKubeconfig), nil },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:         \"kube-scheduler\",\n\t\t\t\tdirectory:    constants.KubernetesSchedulerSecretsDir,\n\t\t\t\tselinuxLabel: constants.KubernetesSchedulerSecretsDirSELinuxLabel,\n\t\t\t\tuid:          constants.KubernetesSchedulerRunUser,\n\t\t\t\tgid:          constants.KubernetesSchedulerRunGroup,\n\t\t\t\tfiles: []file{\n\t\t\t\t\t{\n\t\t\t\t\t\tfilename:    \"kubeconfig\",\n\t\t\t\t\t\tcontentFunc: func() ([]byte, error) { return []byte(k8sSecrets.SchedulerKubeconfig), nil },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t} {\n\t\t\tif err = os.MkdirAll(pod.directory, 0o755); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating secrets directory for %q: %w\", pod.name, err)\n\t\t\t}\n\n\t\t\tif err = selinux.SetLabel(pod.directory, pod.selinuxLabel); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor _, secret := range pod.secrets {\n\t\t\t\tcertAndKey := secret.getter()\n\n\t\t\t\tif secret.certFilename != \"\" {\n\t\t\t\t\tif err = os.WriteFile(filepath.Join(pod.directory, secret.certFilename), certAndKey.Crt, 0o400); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error writing certificate %q for %q: %w\", secret.certFilename, pod.name, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err = os.Chown(filepath.Join(pod.directory, secret.certFilename), pod.uid, pod.gid); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error chowning %q for %q: %w\", secret.certFilename, pod.name, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif secret.keyFilename != \"\" {\n\t\t\t\t\tif err = os.WriteFile(filepath.Join(pod.directory, secret.keyFilename), certAndKey.Key, 0o400); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error writing key %q for %q: %w\", secret.keyFilename, pod.name, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err = os.Chown(filepath.Join(pod.directory, secret.keyFilename), pod.uid, pod.gid); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error chowning %q for %q: %w\", secret.keyFilename, pod.name, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, file := range pod.files {\n\t\t\t\tfileContent, err := file.contentFunc()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting content for file %q for %q: %w\", file.filename, pod.name, err)\n\t\t\t\t}\n\n\t\t\t\tif err = os.WriteFile(filepath.Join(pod.directory, file.filename), fileContent, 0o400); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error writing file %q for %q: %w\", file.filename, pod.name, err)\n\t\t\t\t}\n\n\t\t\t\tif err = os.Chown(filepath.Join(pod.directory, file.filename), pod.uid, pod.gid); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error chowning %q for %q: %w\", file.filename, pod.name, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID), func(r *k8s.SecretsStatus) error {\n\t\t\tr.TypedSpec().Ready = true\n\t\t\tr.TypedSpec().Version = secretsRes.Metadata().Version().String()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// StaticEndpointController injects endpoints based on machine configuration.\ntype StaticEndpointController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *StaticEndpointController) Name() string {\n\treturn \"k8s.StaticEndpointController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *StaticEndpointController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *StaticEndpointController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.EndpointType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *StaticEndpointController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmachineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif machineConfig != nil && machineConfig.Config().Cluster() != nil {\n\t\t\tcpHostname := machineConfig.Config().Cluster().Endpoint().Hostname()\n\n\t\t\tvar (\n\t\t\t\tresolver net.Resolver\n\t\t\t\taddrs    []netip.Addr\n\t\t\t\thosts    []string\n\t\t\t)\n\n\t\t\taddrs, err = resolver.LookupNetIP(ctx, \"ip\", cpHostname)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error resolving %q: %w\", cpHostname, err)\n\t\t\t}\n\n\t\t\taddrs = xslices.Map(addrs, netip.Addr.Unmap)\n\n\t\t\tif len(addrs) != 1 || addrs[0].String() != cpHostname {\n\t\t\t\thosts = []string{cpHostname}\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, k8s.ControlPlaneKubernetesEndpointsID), func(endpoint *k8s.Endpoint) error {\n\t\t\t\tendpoint.TypedSpec().Addresses = addrs\n\t\t\t\tendpoint.TypedSpec().Hosts = hosts\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying endpoint: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*k8s.Endpoint](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype StaticEndpointControllerSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *StaticEndpointControllerSuite) TestReconcile() {\n\tu, err := url.Parse(\"https://[2001:db8::1]:6443/\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControlPlaneKubernetesEndpointsID},\n\t\tfunc(endpoint *k8s.Endpoint, assert *assert.Assertions) {\n\t\t\tassert.Equal([]netip.Addr{netip.MustParseAddr(\"2001:db8::1\")}, endpoint.TypedSpec().Addresses)\n\t\t\tassert.Empty(endpoint.TypedSpec().Hosts)\n\t\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), cfg.Metadata()))\n\n\trtestutils.AssertNoResource[*k8s.Endpoint](suite.Ctx(), suite.T(), suite.State(), k8s.ControlPlaneKubernetesEndpointsID)\n}\n\nfunc (suite *StaticEndpointControllerSuite) TestReconcileHostname() {\n\tu, err := url.Parse(\"https://localhost:6443/\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{k8s.ControlPlaneKubernetesEndpointsID},\n\t\tfunc(endpoint *k8s.Endpoint, assert *assert.Assertions) {\n\t\t\t// localhost might resolve to ::1 as well, check only for 127.0.0.1\n\t\t\tassert.Contains(endpoint.TypedSpec().Addresses, netip.MustParseAddr(\"127.0.0.1\"))\n\t\t\tassert.Equal([]string{\"localhost\"}, endpoint.TypedSpec().Hosts)\n\t\t})\n}\n\nfunc TestStaticEndpointControllerSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &StaticEndpointControllerSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&k8sctrl.StaticEndpointController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_pod_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// StaticPodConfigController manages k8s.StaticPod based on machine configuration.\ntype StaticPodConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *StaticPodConfigController) Name() string {\n\treturn \"k8s.StaticPodConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *StaticPodConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *StaticPodConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.StaticPodType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *StaticPodConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tcfgProvider := cfg.Config()\n\n\t\t\tfor _, pod := range cfgProvider.Machine().Pods() {\n\t\t\t\tvar (\n\t\t\t\t\tname, namespace string\n\t\t\t\t\tok              bool\n\t\t\t\t)\n\n\t\t\t\tname, ok, err = unstructured.NestedString(pod, \"metadata\", \"name\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting name from static pod: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif !ok {\n\t\t\t\t\treturn errors.New(\"name is missing in static pod metadata\")\n\t\t\t\t}\n\n\t\t\t\tnamespace, ok, err = unstructured.NestedString(pod, \"metadata\", \"namespace\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error getting namespace from static pod: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif !ok {\n\t\t\t\t\tnamespace = corev1.NamespaceDefault\n\t\t\t\t}\n\n\t\t\t\tid := fmt.Sprintf(\"%s-%s\", namespace, name)\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, k8s.NewStaticPod(k8s.NamespaceName, id), func(r *k8s.StaticPod) error {\n\t\t\t\t\tr.TypedSpec().Pod = pod\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// clean up static pods which haven't been touched\n\t\tif err = safe.CleanupOutputs[*k8s.StaticPod](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_pod_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype StaticPodConfigSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *StaticPodConfigSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.StaticPodConfigController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *StaticPodConfigSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *StaticPodConfigSuite) assertResource(\n\tmd resource.Metadata,\n\tcheck func(res resource.Resource) error,\n) func() error {\n\treturn func() error {\n\t\tr, err := suite.state.Get(suite.ctx, md)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn check(r)\n\t}\n}\n\nfunc (suite *StaticPodConfigSuite) assertNoResource(md resource.Metadata) func() error {\n\treturn func() error {\n\t\t_, err := suite.state.Get(suite.ctx, md)\n\t\tif err == nil {\n\t\t\treturn retry.ExpectedErrorf(\"resource %s still exists\", md)\n\t\t}\n\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n}\n\nfunc (suite *StaticPodConfigSuite) TestReconcile() {\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachinePods: []v1alpha1.Unstructured{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\"apiVersion\": \"v1\",\n\t\t\t\t\t\t\t\t\"kind\":       \"pod\",\n\t\t\t\t\t\t\t\t\"metadata\": map[string]any{\n\t\t\t\t\t\t\t\t\t\"name\": \"nginx\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"spec\": map[string]any{\n\t\t\t\t\t\t\t\t\t\"containers\": []any{\n\t\t\t\t\t\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\t\t\t\t\t\"name\":  \"nginx\",\n\t\t\t\t\t\t\t\t\t\t\t\"image\": \"nginx\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t))\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tsuite.assertResource(\n\t\t\t\t*k8s.NewStaticPod(k8s.NamespaceName, \"default-nginx\").Metadata(),\n\t\t\t\tfunc(res resource.Resource) error {\n\t\t\t\t\tv, ok, err := unstructured.NestedString(res.(*k8s.StaticPod).TypedSpec().Pod, \"kind\")\n\t\t\t\t\tsuite.Require().NoError(err)\n\t\t\t\t\tsuite.Assert().True(ok)\n\t\t\t\t\tsuite.Assert().Equal(\"pod\", v)\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t),\n\t\t),\n\t)\n\n\t// update the pod changing the namespace\n\tcfg.Container().RawV1Alpha1().MachineConfig.MachinePods[0].Object[\"metadata\"].(map[string]any)[\"namespace\"] = \"custom\"\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tsuite.assertNoResource(\n\t\t\t\t*k8s.NewStaticPod(k8s.NamespaceName, \"default-nginx\").Metadata(),\n\t\t\t),\n\t\t),\n\t)\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tsuite.assertResource(\n\t\t\t\t*k8s.NewStaticPod(k8s.NamespaceName, \"custom-nginx\").Metadata(),\n\t\t\t\tfunc(res resource.Resource) error {\n\t\t\t\t\tv, ok, err := unstructured.NestedString(\n\t\t\t\t\t\tres.(*k8s.StaticPod).TypedSpec().Pod,\n\t\t\t\t\t\t\"metadata\",\n\t\t\t\t\t\t\"namespace\",\n\t\t\t\t\t)\n\t\t\t\t\tsuite.Require().NoError(err)\n\t\t\t\t\tsuite.Assert().True(ok)\n\t\t\t\t\tsuite.Assert().Equal(\"custom\", v)\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t),\n\t\t),\n\t)\n\n\t// remove all pods\n\tcfg.Container().RawV1Alpha1().MachineConfig.MachinePods = nil\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tsuite.assertNoResource(\n\t\t\t\t*k8s.NewStaticPod(k8s.NamespaceName, \"custom-nginx\").Metadata(),\n\t\t\t),\n\t\t),\n\t)\n}\n\nfunc (suite *StaticPodConfigSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestStaticPodConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(StaticPodConfigSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_pod_server.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// StaticPodServerController renders all static pod definitions as a PodList and serves it as YAML via HTTP.\ntype StaticPodServerController struct {\n\tpodList   []byte\n\tpodListMu sync.Mutex\n\n\tstaticPodVersions map[string]string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *StaticPodServerController) Name() string {\n\treturn \"k8s.StaticPodServerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *StaticPodServerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.StaticPodType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *StaticPodServerController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: k8s.StaticPodServerStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\ntype pod map[string]any\n\ntype podList struct {\n\tKind string `json:\"kind,omitempty\" protobuf:\"bytes,1,opt,name=kind\"`\n\n\tItems []pod `json:\"items\" protobuf:\"bytes,2,rep,name=items\"`\n\n\tAPIVersion string `json:\"apiVersion,omitempty\" protobuf:\"bytes,3,opt,name=apiVersion\"`\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *StaticPodServerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tctrl.staticPodVersions = map[string]string{}\n\n\tshutdownServer, serverError, err := ctrl.createServer(ctx, r, logger)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to start http server to serve static pod list: %w\", err)\n\t}\n\n\tdefer shutdownServer()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase err := <-serverError:\n\t\t\treturn fmt.Errorf(\"http server closed unexpectedly: %w\", err)\n\t\tcase <-r.EventCh():\n\t\t\tstaticPodList, err := ctrl.buildPodList(ctx, r, logger)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error(\"error building static pod list\", zap.Error(err))\n\t\t\t}\n\n\t\t\tctrl.podListMu.Lock()\n\t\t\tctrl.podList = staticPodList\n\t\t\tctrl.podListMu.Unlock()\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *StaticPodServerController) buildPodList(ctx context.Context, r controller.Runtime, logger *zap.Logger) ([]byte, error) {\n\tstaticPods, err := safe.ReaderListAll[*k8s.StaticPod](ctx, r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing static pods: %w\", err)\n\t}\n\n\tpl := podList{\n\t\tKind:       \"PodList\",\n\t\tAPIVersion: \"v1\",\n\t}\n\n\ttouchedPodIDs := map[string]struct{}{}\n\n\tfor staticPod := range staticPods.All() {\n\t\tid := staticPod.Metadata().ID()\n\t\tversion := staticPod.Metadata().Version().String()\n\n\t\tif oldVersion, exists := ctrl.staticPodVersions[id]; !exists || oldVersion != version {\n\t\t\tctrl.staticPodVersions[id] = version\n\n\t\t\tif !exists {\n\t\t\t\tlogger.Info(\"rendered new static pod\", zap.String(\"id\", id))\n\t\t\t} else {\n\t\t\t\tlogger.Info(\"rendered updated static pod\", zap.String(\"id\", id), zap.String(\"old_version\", oldVersion), zap.String(\"new_version\", version))\n\t\t\t}\n\t\t}\n\n\t\tstaticPodSpec := staticPod.TypedSpec()\n\n\t\tpl.Items = append(pl.Items, staticPodSpec.Pod)\n\n\t\ttouchedPodIDs[id] = struct{}{}\n\t}\n\n\tfor id := range ctrl.staticPodVersions {\n\t\tif _, exists := touchedPodIDs[id]; exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.Info(\"removed static pod\", zap.String(\"id\", id))\n\n\t\tdelete(ctrl.staticPodVersions, id)\n\t}\n\n\tmanifestContent, err := yaml.Marshal(pl)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error rendering list of static pods as yaml: %w\", err)\n\t}\n\n\treturn manifestContent, nil\n}\n\nfunc (ctrl *StaticPodServerController) createServer(ctx context.Context, r controller.Runtime, logger *zap.Logger) (func(), <-chan error, error) {\n\tmux := http.NewServeMux()\n\n\tmux.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tctrl.podListMu.Lock()\n\t\tstaticPodList := ctrl.podList\n\t\tctrl.podListMu.Unlock()\n\n\t\tlogger.Debug(\"serving static pod manifests\", zap.Int(\"size\", len(staticPodList)))\n\n\t\tif staticPodList == nil {\n\t\t\thttp.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)\n\n\t\t\treturn\n\t\t}\n\n\t\t_, err := w.Write(staticPodList)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to serve static pod manifests\", zap.Error(err))\n\t\t}\n\t})\n\n\tlistener, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to create listener for serving static pod manifests: %w\", err)\n\t}\n\n\thttpServer := &http.Server{\n\t\tHandler: mux,\n\t}\n\n\tshutdownServer := func() {\n\t\tif err := httpServer.Shutdown(ctx); err != nil {\n\t\t\tlogger.Error(\"failed to shut down HTTP server, serving static pod manifests\", zap.Error(err))\n\t\t}\n\t}\n\n\tgo func() {\n\t\t<-ctx.Done()\n\n\t\tshutdownServer()\n\t}()\n\n\tif err := safe.WriterModify(ctx, r, k8s.NewStaticPodServerStatus(k8s.NamespaceName, k8s.StaticPodServerStatusResourceID), func(r *k8s.StaticPodServerStatus) error {\n\t\turl := fmt.Sprintf(\"http://%s\", listener.Addr().String())\n\n\t\tr.TypedSpec().URL = url\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error modifying StaticPodListURL resource: %w\", err)\n\t}\n\n\tserverError := make(chan error, 1)\n\n\tgo func() {\n\t\tserverError <- httpServer.Serve(listener)\n\t}()\n\n\treturn shutdownServer, serverError, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/k8s/static_pod_server_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage k8s_test\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tk8sctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype StaticPodListSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *StaticPodListSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&k8sctrl.StaticPodServerController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *StaticPodListSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *StaticPodListSuite) assertResource(\n\tmd resource.Metadata,\n\tcheck func(res resource.Resource) error,\n) func() error {\n\treturn func() error {\n\t\tr, err := suite.state.Get(suite.ctx, md)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn check(r)\n\t}\n}\n\nfunc (suite *StaticPodListSuite) getResource(\n\tmd resource.Metadata,\n) resource.Resource {\n\tvar ret resource.Resource\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tr, err := suite.state.Get(suite.ctx, md)\n\t\t\tif err != nil {\n\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tret = r\n\n\t\t\treturn nil\n\t\t}))\n\n\treturn ret\n}\n\nfunc newTestPod(name string) *k8s.StaticPod {\n\ttestPod := k8s.NewStaticPod(k8s.NamespaceName, name)\n\n\ttestPod.TypedSpec().Pod = map[string]any{\n\t\t\"metadata\": name,\n\t\t\"spec\":     \"testSpec\",\n\t}\n\n\treturn testPod\n}\n\nfunc (suite *StaticPodListSuite) TestCreatesStaticPodServerStatus() {\n\t// given\n\ttestPod := newTestPod(\"testPod\")\n\n\t// when\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, testPod))\n\n\t// then\n\texpectedPodListURL := k8s.NewStaticPodServerStatus(k8s.NamespaceName, k8s.StaticPodServerStatusResourceID)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tsuite.assertResource(*expectedPodListURL.Metadata(), func(res resource.Resource) error {\n\t\t\t\tsuite.Require().True(strings.HasPrefix(\n\t\t\t\t\tres.(*k8s.StaticPodServerStatus).TypedSpec().URL,\n\t\t\t\t\t\"http://127.0.0.1:\",\n\t\t\t\t),\n\t\t\t\t)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\t),\n\t\t),\n\t)\n}\n\nfunc (suite *StaticPodListSuite) TestServesStaticPodList() {\n\t// given\n\ttestPod1 := newTestPod(\"testPod1\")\n\ttestPod2 := newTestPod(\"testPod2\")\n\n\t// when\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, testPod1))\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, testPod2))\n\n\t// then\n\texpectedPodListURL := k8s.NewStaticPodServerStatus(k8s.NamespaceName, k8s.StaticPodServerStatusResourceID)\n\n\tpodListURL := suite.getResource(*expectedPodListURL.Metadata())\n\n\tsuite.Require().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tresp, err := http.Get(podListURL.(*k8s.StaticPodServerStatus).TypedSpec().URL) //nolint:noctx\n\t\t\tif err != nil {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\tdefer resp.Body.Close() //nolint:errcheck\n\n\t\t\tcontent, err := io.ReadAll(resp.Body)\n\t\t\tsuite.Assert().NoError(err)\n\n\t\t\tsuite.Require().Equal(\"kind: PodList\\nitems:\\n    - metadata: testPod1\\n      spec: testSpec\\n    - metadata: testPod2\\n      spec: testSpec\\napiversion: v1\\n\", string(content))\n\n\t\t\treturn nil\n\t\t}),\n\t)\n}\n\nfunc (suite *StaticPodListSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestStaticPodListSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(StaticPodListSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n)\n\n// ConfigController watches v1alpha1.Config, updates Talos API access config.\ntype ConfigController = transform.Controller[*config.MachineConfig, *kubeaccess.Config]\n\n// NewConfigController instanciates the config controller.\nfunc NewConfigController() *ConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *kubeaccess.Config]{\n\t\t\tName: \"kubeaccess.ConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*kubeaccess.Config] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*kubeaccess.Config]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Machine() == nil {\n\t\t\t\t\treturn optional.None[*kubeaccess.Config]()\n\t\t\t\t}\n\n\t\t\t\tif !cfg.Config().Machine().Type().IsControlPlane() {\n\t\t\t\t\treturn optional.None[*kubeaccess.Config]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(kubeaccess.NewConfig(config.NamespaceName, kubeaccess.ConfigID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *kubeaccess.Config) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\t*spec = kubeaccess.ConfigSpec{}\n\n\t\t\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\t\t\tc := cfg.Config()\n\n\t\t\t\t\tspec.Enabled = c.Machine().Features().KubernetesTalosAPIAccess().Enabled()\n\t\t\t\t\tspec.AllowedAPIRoles = c.Machine().Features().KubernetesTalosAPIAccess().AllowedRoles()\n\t\t\t\t\tspec.AllowedKubernetesNamespaces = c.Machine().Features().KubernetesTalosAPIAccess().AllowedKubernetesNamespaces()\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubeaccessctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubeaccess\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n)\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ConfigSuite) TestReconcileConfig() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tKubernetesTalosAPIAccessConfig: &v1alpha1.KubernetesTalosAPIAccessConfig{\n\t\t\t\t\tAccessEnabled:                     new(true),\n\t\t\t\t\tAccessAllowedRoles:                []string{\"os:admin\"},\n\t\t\t\t\tAccessAllowedKubernetesNamespaces: []string{\"kube-system\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{kubeaccess.ConfigID}, func(r *kubeaccess.Config, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.True(spec.Enabled)\n\t\tasrt.Equal([]string{\"os:admin\"}, spec.AllowedAPIRoles)\n\t\tasrt.Equal([]string{\"kube-system\"}, spec.AllowedKubernetesNamespaces)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestReconcileDisabled() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"init\",\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{kubeaccess.ConfigID}, func(r *kubeaccess.Config, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.False(spec.Enabled)\n\t\tasrt.Empty(spec.AllowedAPIRoles)\n\t\tasrt.Empty(spec.AllowedKubernetesNamespaces)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestReconcileWorker() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"worker\",\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tKubernetesTalosAPIAccessConfig: &v1alpha1.KubernetesTalosAPIAccessConfig{\n\t\t\t\t\tAccessEnabled:                     new(true),\n\t\t\t\t\tAccessAllowedRoles:                []string{\"os:admin\"},\n\t\t\t\t\tAccessAllowedKubernetesNamespaces: []string{\"kube-system\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}))\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\t// worker should have feature disabled even if it is enabled in the config\n\trtestutils.AssertNoResource[*kubeaccess.Config](suite.Ctx(), suite.T(), suite.State(), kubeaccess.ConfigID)\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(kubeaccessctrl.NewConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// EndpointController manages Kubernetes endpoints resource for Talos API endpoints.\ntype EndpointController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EndpointController) Name() string {\n\treturn \"kubeaccess.EndpointController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubeaccess.ConfigType,\n\t\t\tID:        optional.Some(kubeaccess.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesType,\n\t\t\tID:        optional.Some(secrets.KubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.EndpointType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tkubeaccessConfig, err := safe.ReaderGet[*kubeaccess.Config](ctx, r, kubeaccess.NewConfig(config.NamespaceName, kubeaccess.ConfigID).Metadata())\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error fetching kubeaccess config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif kubeaccessConfig == nil || !kubeaccessConfig.TypedSpec().Enabled {\n\t\t\t// disabled, do not do anything\n\t\t\tcontinue\n\t\t}\n\n\t\t// use only api-server endpoints to leave only kubelet node IPs\n\t\tendpointResource, err := safe.ReaderGet[*k8s.Endpoint](ctx, r, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.EndpointType, k8s.ControlPlaneAPIServerEndpointsID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting endpoints resources: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar endpointAddrs k8s.EndpointList\n\n\t\tif endpointResource != nil {\n\t\t\tendpointAddrs = endpointAddrs.Merge(endpointResource)\n\t\t}\n\n\t\tif endpointAddrs.IsEmpty() {\n\t\t\tcontinue\n\t\t}\n\n\t\tsecretsResources, err := safe.ReaderGet[*secrets.Kubernetes](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tsecrets := secretsResources.TypedSpec()\n\n\t\tkubeconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\t\treturn clientcmd.Load([]byte(secrets.LocalhostAdminKubeconfig))\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error loading kubeconfig: %w\", err)\n\t\t}\n\n\t\tif err = ctrl.manageEndpoints(ctx, logger, kubeconfig, endpointAddrs); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *EndpointController) manageEndpoints(ctx context.Context, logger *zap.Logger, kubeconfig *rest.Config, endpointAddrs k8s.EndpointList) error {\n\tclient, err := kubernetes.NewForConfig(kubeconfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Kubernetes client: %w\", err)\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\t// create the Service before creating the Endpoints, as Kubernetes EndpointController will clean up orphaned Endpoints\n\tif err = ctrl.ensureTalosService(ctx, client); err != nil {\n\t\treturn fmt.Errorf(\"error ensuring Talos API service: %w\", err)\n\t}\n\n\t// now create or update the EndpointSlices resource\n\tif err = ctrl.ensureTalosEndpointSlices(ctx, logger, client, endpointAddrs); err != nil {\n\t\treturn fmt.Errorf(\"error ensuring Talos API endpoint slices: %w\", err)\n\t}\n\n\t// clean-up deprecated endpoints\n\tif err = ctrl.cleanupTalosEndpoints(ctx, logger, client); err != nil {\n\t\treturn fmt.Errorf(\"error cleaning up dangling Talos API endpoints: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *EndpointController) ensureTalosService(ctx context.Context, client *kubernetes.Client) error {\n\t_, err := client.CoreV1().Services(constants.KubernetesTalosAPIServiceNamespace).Get(ctx, constants.KubernetesTalosAPIServiceName, metav1.GetOptions{})\n\tif err == nil {\n\t\t// service already exists, nothing to do\n\t\treturn nil\n\t}\n\n\tif !apierrors.IsNotFound(err) {\n\t\treturn fmt.Errorf(\"error getting Talos API service: %w\", err)\n\t}\n\n\t// create the service if it does not exist\n\tnewService := &corev1.Service{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName:      constants.KubernetesTalosAPIServiceName,\n\t\t\tNamespace: constants.KubernetesTalosAPIServiceNamespace,\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"provider\":  constants.KubernetesTalosProvider,\n\t\t\t\t\"component\": \"apid\",\n\t\t\t},\n\t\t},\n\t\tSpec: corev1.ServiceSpec{\n\t\t\tPorts: []corev1.ServicePort{\n\t\t\t\t{\n\t\t\t\t\tName:       \"apid\",\n\t\t\t\t\tPort:       constants.ApidPort,\n\t\t\t\t\tProtocol:   corev1.ProtocolTCP,\n\t\t\t\t\tTargetPort: intstr.FromInt(constants.ApidPort),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t_, err = client.CoreV1().Services(constants.KubernetesTalosAPIServiceNamespace).Create(ctx, newService, metav1.CreateOptions{})\n\tif err != nil && !apierrors.IsAlreadyExists(err) {\n\t\treturn fmt.Errorf(\"error creating Talos API service: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *EndpointController) ensureTalosEndpointSlices(ctx context.Context, logger *zap.Logger, client *kubernetes.Client, endpointAddrs k8s.EndpointList) error {\n\tvar (\n\t\taddrsIPv4 k8s.EndpointList\n\t\taddrsIPv6 k8s.EndpointList\n\t)\n\n\tfor _, addr := range endpointAddrs.Addresses {\n\t\tswitch {\n\t\tcase addr.Is4():\n\t\t\taddrsIPv4.Addresses = append(addrsIPv4.Addresses, addr)\n\n\t\tcase addr.Is6():\n\t\t\taddrsIPv6.Addresses = append(addrsIPv6.Addresses, addr)\n\n\t\tdefault:\n\t\t\t// ignore other address types\n\t\t}\n\t}\n\n\tif len(addrsIPv4.Addresses) == 0 {\n\t\tif err := ctrl.deleteTalosEndpointSlicesTyped(ctx, logger, client, discoveryv1.AddressTypeIPv4); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting Talos API endpoint slices for IPv4: %w\", err)\n\t\t}\n\t} else {\n\t\tif err := ctrl.ensureTalosEndpointSlicesTyped(ctx, logger, client, addrsIPv4, discoveryv1.AddressTypeIPv4); err != nil {\n\t\t\treturn fmt.Errorf(\"error ensuring Talos API endpoint slices for IPv4: %w\", err)\n\t\t}\n\t}\n\n\tif len(addrsIPv6.Addresses) == 0 {\n\t\tif err := ctrl.deleteTalosEndpointSlicesTyped(ctx, logger, client, discoveryv1.AddressTypeIPv6); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting Talos API endpoint slices for IPv6: %w\", err)\n\t\t}\n\t} else {\n\t\tif err := ctrl.ensureTalosEndpointSlicesTyped(ctx, logger, client, addrsIPv6, discoveryv1.AddressTypeIPv6); err != nil {\n\t\t\treturn fmt.Errorf(\"error ensuring Talos API endpoint slices for IPv6: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *EndpointController) deleteTalosEndpointSlicesTyped(ctx context.Context, logger *zap.Logger, client *kubernetes.Client, addressType discoveryv1.AddressType) error {\n\tendpointSliceName := constants.KubernetesTalosAPIServiceName + \"-\" + strings.ToLower(string(addressType))\n\n\terr := client.DiscoveryV1().EndpointSlices(constants.KubernetesTalosAPIServiceNamespace).Delete(ctx, endpointSliceName, metav1.DeleteOptions{})\n\tif err != nil && !apierrors.IsNotFound(err) {\n\t\treturn fmt.Errorf(\"error deleting Talos API endpoint slices: %w\", err)\n\t}\n\n\tlogger.Info(\"deleted Talos API endpoint slices in Kubernetes\", zap.String(\"addressType\", string(addressType)))\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *EndpointController) ensureTalosEndpointSlicesTyped(\n\tctx context.Context,\n\tlogger *zap.Logger,\n\tclient *kubernetes.Client,\n\tendpointAddrs k8s.EndpointList,\n\taddressType discoveryv1.AddressType,\n) error {\n\tfor {\n\t\tesc := client.DiscoveryV1().EndpointSlices(constants.KubernetesTalosAPIServiceNamespace)\n\t\tname := constants.KubernetesTalosAPIServiceName + \"-\" + strings.ToLower(string(addressType))\n\n\t\toldEndpointSlice, err := esc.Get(ctx, name, metav1.GetOptions{})\n\t\tif err != nil && !apierrors.IsNotFound(err) {\n\t\t\treturn fmt.Errorf(\"error getting endpoints: %w\", err)\n\t\t}\n\n\t\tvar newEndpointSlice *discoveryv1.EndpointSlice\n\n\t\tif apierrors.IsNotFound(err) {\n\t\t\tnewEndpointSlice = &discoveryv1.EndpointSlice{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName:      name,\n\t\t\t\t\tNamespace: constants.KubernetesTalosAPIServiceNamespace,\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\"kubernetes.io/service-name\": constants.KubernetesTalosAPIServiceName,\n\t\t\t\t\t\t\"provider\":                   constants.KubernetesTalosProvider,\n\t\t\t\t\t\t\"component\":                  \"apid\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAddressType: addressType,\n\t\t\t}\n\t\t\toldEndpointSlice = nil\n\t\t} else {\n\t\t\tnewEndpointSlice = oldEndpointSlice.DeepCopy()\n\t\t}\n\n\t\tPopulateEndpointSlice(newEndpointSlice, endpointAddrs)\n\n\t\tif oldEndpointSlice != nil &&\n\t\t\t(reflect.DeepEqual(oldEndpointSlice.Endpoints, newEndpointSlice.Endpoints) &&\n\t\t\t\treflect.DeepEqual(oldEndpointSlice.Ports, newEndpointSlice.Ports)) {\n\t\t\t// no change, bail out\n\t\t\treturn nil\n\t\t}\n\n\t\tif oldEndpointSlice == nil {\n\t\t\t_, err = client.DiscoveryV1().EndpointSlices(constants.KubernetesTalosAPIServiceNamespace).Create(ctx, newEndpointSlice, metav1.CreateOptions{})\n\t\t} else {\n\t\t\t_, err = client.DiscoveryV1().EndpointSlices(constants.KubernetesTalosAPIServiceNamespace).Update(ctx, newEndpointSlice, metav1.UpdateOptions{})\n\t\t}\n\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tlogger.Info(\"updated Talos API endpoint slices in Kubernetes\", zap.Strings(\"endpoints\", endpointAddrs.Strings()))\n\n\t\t\treturn nil\n\t\tcase apierrors.IsConflict(err) || apierrors.IsAlreadyExists(err):\n\t\t\t// retry\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"error updating Kubernetes Talos API endpoint slices: %w\", err)\n\t\t}\n\t}\n}\n\n// PopulateEndpointSlice populates the given EndpointSlice with ports and endpoints from the given endpoint addresses.\n//\n// The EndpointSlice's existing Endpoints and Ports fields are overwritten.\nfunc PopulateEndpointSlice(endpointSlice *discoveryv1.EndpointSlice, endpointAddrs k8s.EndpointList) {\n\tendpointSlice.Ports = []discoveryv1.EndpointPort{\n\t\t{\n\t\t\tName:     new(\"apid\"),\n\t\t\tPort:     new(int32(constants.ApidPort)),\n\t\t\tProtocol: new(corev1.ProtocolTCP),\n\t\t},\n\t}\n\n\tendpointSlice.Endpoints = nil\n\n\tfor _, addr := range endpointAddrs.Addresses {\n\t\tendpointSlice.Endpoints = append(\n\t\t\tendpointSlice.Endpoints,\n\t\t\tdiscoveryv1.Endpoint{\n\t\t\t\tAddresses: []string{addr.String()},\n\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\tReady:       new(true),\n\t\t\t\t\tServing:     new(true),\n\t\t\t\t\tTerminating: new(false),\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\tendpointSlice.Endpoints = xslices.Deduplicate(endpointSlice.Endpoints, func(e discoveryv1.Endpoint) string {\n\t\treturn e.Addresses[0]\n\t})\n}\n\n//nolint:gocyclo\nfunc (ctrl *EndpointController) cleanupTalosEndpoints(ctx context.Context, logger *zap.Logger, client *kubernetes.Client) error {\n\tfor {\n\t\terr := client.CoreV1().Endpoints(constants.KubernetesTalosAPIServiceNamespace).Delete(ctx, constants.KubernetesTalosAPIServiceName, metav1.DeleteOptions{})\n\t\tif err != nil && !apierrors.IsNotFound(err) {\n\t\t\treturn fmt.Errorf(\"error getting endpoints: %w\", err)\n\t\t}\n\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tlogger.Info(\"deleted dangling Talos API endpoints in Kubernetes\")\n\n\t\t\treturn nil\n\t\tcase apierrors.IsNotFound(err):\n\t\t\tlogger.Info(\"no dangling Talos API endpoints in Kubernetes\")\n\n\t\t\treturn nil\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"error deleting dangling Kubernetes Talos API endpoints: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tdiscoveryv1 \"k8s.io/api/discovery/v1\"\n\n\tkubeaccessctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubeaccess\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\nfunc TestPopulateEndpointSlice(t *testing.T) {\n\tt.Parallel()\n\n\t//nolint:dupl\n\tfor _, tt := range []struct {\n\t\tname             string\n\t\texistingSlice    *discoveryv1.EndpointSlice\n\t\tendpointAddrs    k8s.EndpointList\n\t\texpectedEndpoint []discoveryv1.Endpoint\n\t}{\n\t\t{\n\t\t\tname:          \"empty endpoint slice, single address\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"empty endpoint slice, multiple addresses\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.2\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.3\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.2\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.3\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"stale endpoints are removed\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{\n\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.1\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.2\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.3\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"10.0.0.1\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"10.0.0.1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"all stale endpoints replaced with new ones\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{\n\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.1\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.2\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.2\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.2\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate addresses are deduplicated\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{\n\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.1\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"192.168.1.2\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"192.168.1.2\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty address list clears endpoints\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{\n\t\t\t\tEndpoints: []discoveryv1.Endpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddresses: []string{\"10.0.0.1\"},\n\t\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tendpointAddrs:    k8s.EndpointList{},\n\t\t\texpectedEndpoint: nil,\n\t\t},\n\t\t{\n\t\t\tname:          \"IPv6 addresses\",\n\t\t\texistingSlice: &discoveryv1.EndpointSlice{},\n\t\t\tendpointAddrs: k8s.EndpointList{\n\t\t\t\tAddresses: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"fd00::1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"fd00::2\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedEndpoint: []discoveryv1.Endpoint{\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"fd00::1\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddresses: []string{\"fd00::2\"},\n\t\t\t\t\tConditions: discoveryv1.EndpointConditions{\n\t\t\t\t\t\tReady:       new(true),\n\t\t\t\t\t\tServing:     new(true),\n\t\t\t\t\t\tTerminating: new(false),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tkubeaccessctrl.PopulateEndpointSlice(tt.existingSlice, tt.endpointAddrs)\n\n\t\t\tassert.Equal(t, tt.expectedEndpoint, tt.existingSlice.Endpoints)\n\n\t\t\t// verify ports are always set correctly\n\t\t\trequire.Len(t, tt.existingSlice.Ports, 1)\n\t\t\tassert.Equal(t, \"apid\", *tt.existingSlice.Ports[0].Name)\n\t\t\tassert.Equal(t, int32(constants.ApidPort), *tt.existingSlice.Ports[0].Port)\n\t\t\tassert.Equal(t, corev1.ProtocolTCP, *tt.existingSlice.Ports[0].Protocol)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/kubeaccess.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubeaccess provides controllers which manage Talos API access from Kubernetes workloads.\npackage kubeaccess\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/serviceaccount/crd_controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage serviceaccount\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tstdlibx509 \"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tkubeerrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime/schema\"\n\tutilruntime \"k8s.io/apimachinery/pkg/util/runtime\"\n\t\"k8s.io/apimachinery/pkg/util/wait\"\n\t\"k8s.io/client-go/dynamic\"\n\t\"k8s.io/client-go/dynamic/dynamicinformer\"\n\t\"k8s.io/client-go/dynamic/dynamiclister\"\n\tkubeinformers \"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/kubernetes/scheme\"\n\ttypedcorev1 \"k8s.io/client-go/kubernetes/typed/core/v1\"\n\tcorelisters \"k8s.io/client-go/listers/core/v1\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/cache\"\n\t\"k8s.io/client-go/tools/record\"\n\t\"k8s.io/client-go/util/workqueue\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nconst (\n\tcertTTL            = time.Hour * 6\n\tcertRenewThreshold = time.Hour * 1\n\n\tsuccessResourceSynced = \"Synced\"\n\tmessageResourceSynced = \"Synced successfully\"\n\n\terrResourceExists     = \"ErrResourceExists\"\n\tmessageResourceExists = \"%s already exists and is not managed by controller: %s\"\n\n\terrRolesNotFound     = \"ErrRolesNotFound\"\n\tmessageRolesNotFound = \"Roles not found\"\n\n\terrNamespaceNotAllowed     = \"ErrNamespaceNotAllowed\"\n\tmessageNamespaceNotAllowed = \"Namespace is not allowed: %s\"\n\n\terrRolesNotAllowed     = \"ErrRolesNotAllowed\"\n\tmessageRolesNotAllowed = \"Roles not allowed: %v\"\n\n\tcontrollerAgentName  = \"talos-sa-controller\"\n\tinformerResyncPeriod = time.Minute * 1\n\n\ttalosconfigContextName = \"default\"\n\tendpoint               = constants.KubernetesTalosAPIServiceName + \".\" + constants.KubernetesTalosAPIServiceNamespace\n\n\tkindSecret = \"Secret\"\n)\n\nvar (\n\ttalosSAGV = schema.GroupVersion{\n\t\tGroup:   constants.ServiceAccountResourceGroup,\n\t\tVersion: constants.ServiceAccountResourceVersion,\n\t}\n\n\ttalosSAGVR = talosSAGV.WithResource(constants.ServiceAccountResourcePlural)\n\ttalosSAGVK = talosSAGV.WithKind(constants.ServiceAccountResourceKind)\n)\n\n// CRDController is the controller implementation for TalosServiceAccount resources.\ntype CRDController struct {\n\ttalosCA *x509.PEMEncodedCertificateAndKey\n\n\tallowedNamespaces []string\n\tallowedRoles      map[string]struct{}\n\n\tqueue workqueue.TypedRateLimitingInterface[string]\n\n\tkubeInformerFactory    kubeinformers.SharedInformerFactory\n\tdynamicInformerFactory dynamicinformer.DynamicSharedInformerFactory\n\n\tkubeClient    kubernetes.Interface\n\tdynamicClient dynamic.Interface\n\thttpClient    *http.Client\n\n\tsecretsSynced  cache.InformerSynced\n\ttalosSAsSynced cache.InformerSynced\n\n\tsecretsLister corelisters.SecretLister\n\tdynamicLister dynamiclister.Lister\n\n\teventRecorder record.EventRecorder\n\n\tlogger *zap.Logger\n}\n\n// NewCRDController creates a new CRD controller.\nfunc NewCRDController(\n\ttalosCA *x509.PEMEncodedCertificateAndKey,\n\tkubeconfig *rest.Config,\n\tallowedNamespaces []string,\n\tallowedRoles []string,\n\tlogger *zap.Logger,\n) (*CRDController, error) {\n\thttpClient, err := rest.HTTPClientFor(kubeconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkubeCli, err := kubernetes.NewForConfigAndClient(kubeconfig, httpClient)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdynCli, err := dynamic.NewForConfigAndClient(kubeconfig, httpClient)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdynamicInformerFactory := dynamicinformer.NewDynamicSharedInformerFactory(dynCli, informerResyncPeriod)\n\tresourceInformer := dynamicInformerFactory.ForResource(talosSAGVR)\n\tinformer := resourceInformer.Informer()\n\n\tindexer := informer.GetIndexer()\n\tlister := dynamiclister.New(indexer, talosSAGVR)\n\n\tkubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeCli, informerResyncPeriod)\n\tsecrets := kubeInformerFactory.Core().V1().Secrets()\n\n\tlogger.Debug(\"creating event broadcaster\")\n\n\teventBroadcaster := record.NewBroadcaster()\n\teventBroadcaster.StartStructuredLogging(0)\n\teventBroadcaster.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: kubeCli.CoreV1().Events(\"\")})\n\n\trecorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName})\n\n\tcontroller := CRDController{\n\t\ttalosCA:                talosCA,\n\t\tallowedNamespaces:      allowedNamespaces,\n\t\tallowedRoles:           xslices.ToSet(allowedRoles),\n\t\tdynamicInformerFactory: dynamicInformerFactory,\n\t\tkubeInformerFactory:    kubeInformerFactory,\n\t\tkubeClient:             kubeCli,\n\t\tdynamicClient:          dynCli,\n\t\thttpClient:             httpClient,\n\t\tdynamicLister:          lister,\n\t\tqueue: workqueue.NewTypedRateLimitingQueue(\n\t\t\tworkqueue.DefaultTypedControllerRateLimiter[string](),\n\t\t),\n\t\tlogger:         logger,\n\t\tsecretsSynced:  secrets.Informer().HasSynced,\n\t\ttalosSAsSynced: informer.HasSynced,\n\t\teventRecorder:  recorder,\n\t\tsecretsLister:  secrets.Lister(),\n\t}\n\n\tif _, err = informer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc: controller.enqueueTalosSA,\n\t\tUpdateFunc: func(oldTalosSA, newTalosSA any) {\n\t\t\tcontroller.enqueueTalosSA(newTalosSA)\n\t\t},\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif _, err = secrets.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc: controller.handleSecret,\n\t\tUpdateFunc: func(oldSec, newSec any) {\n\t\t\tnewSecret := newSec.(*corev1.Secret)\n\t\t\toldSecret := oldSec.(*corev1.Secret)\n\n\t\t\tif newSecret.ResourceVersion == oldSecret.ResourceVersion {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcontroller.handleSecret(newSec)\n\t\t},\n\t\tDeleteFunc: controller.handleSecret,\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &controller, nil\n}\n\n// Run starts the CRD controller.\nfunc (t *CRDController) Run(ctx context.Context, workers int) error {\n\tvar wg sync.WaitGroup\n\n\tdefer func() {\n\t\tt.queue.ShutDown()\n\t\tt.httpClient.CloseIdleConnections()\n\n\t\twg.Wait()\n\t\tt.logger.Debug(\"all workers have shut down\")\n\t}()\n\n\tt.kubeInformerFactory.Start(ctx.Done())\n\tt.dynamicInformerFactory.Start(ctx.Done())\n\n\tt.logger.Sugar().Debugf(\"starting %s controller\", constants.ServiceAccountResourceKind)\n\n\tt.logger.Debug(\"waiting for informer caches to sync\")\n\n\tif ok := cache.WaitForCacheSync(ctx.Done(), t.secretsSynced, t.talosSAsSynced); !ok {\n\t\treturn errors.New(\"failed to wait for caches to sync\")\n\t}\n\n\tt.logger.Debug(\"starting workers\")\n\n\twg.Add(workers)\n\n\tfor range workers {\n\t\tgo func() {\n\t\t\twait.Until(func() { t.runWorker(ctx) }, time.Second, ctx.Done())\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\tt.logger.Debug(\"started workers\")\n\n\t<-ctx.Done()\n\n\tt.logger.Debug(\"shutting down workers\")\n\n\tt.kubeInformerFactory.Shutdown()\n\n\treturn nil\n}\n\nfunc (t *CRDController) runWorker(ctx context.Context) {\n\tfor t.processNextWorkItem(ctx) {\n\t}\n}\n\nfunc (t *CRDController) processNextWorkItem(ctx context.Context) bool {\n\tobj, shutdown := t.queue.Get()\n\n\tif shutdown {\n\t\treturn false\n\t}\n\n\terr := func(obj string) error {\n\t\tdefer t.queue.Done(obj)\n\n\t\tif err := t.syncHandler(ctx, obj); err != nil {\n\t\t\tt.queue.AddRateLimited(obj)\n\n\t\t\treturn fmt.Errorf(\"error syncing '%s': %s, requeuing\", obj, err.Error())\n\t\t}\n\n\t\tt.queue.Forget(obj)\n\t\tt.logger.Sugar().Debugf(\"successfully synced '%s'\", obj)\n\n\t\treturn nil\n\t}(obj)\n\tif err != nil {\n\t\tutilruntime.HandleError(err)\n\n\t\treturn true\n\t}\n\n\treturn true\n}\n\n//nolint:gocyclo,cyclop\nfunc (t *CRDController) syncHandler(ctx context.Context, key string) error {\n\tnamespace, name, err := cache.SplitMetaNamespaceKey(key)\n\tif err != nil {\n\t\tutilruntime.HandleError(fmt.Errorf(\"invalid resource key: %s\", key))\n\n\t\treturn nil //nolint:nilerr\n\t}\n\n\ttalosSA, err := t.dynamicLister.Namespace(namespace).Get(name)\n\tif err != nil {\n\t\tif kubeerrors.IsNotFound(err) {\n\t\t\tutilruntime.HandleError(fmt.Errorf(\"talosSA '%s' in work queue no longer exists\", key))\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tsecret, err := t.secretsLister.Secrets(namespace).Get(name)\n\n\tsecretNotFound := kubeerrors.IsNotFound(err)\n\tif err != nil && !secretNotFound {\n\t\treturn err\n\t}\n\n\tif !secretNotFound && !metav1.IsControlledBy(secret, talosSA) {\n\t\tmsg := fmt.Sprintf(messageResourceExists, kindSecret, key)\n\n\t\terr = t.updateTalosSAStatus(ctx, talosSA, msg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tt.eventRecorder.Event(talosSA, corev1.EventTypeWarning, errResourceExists, msg)\n\n\t\treturn errors.New(msg)\n\t}\n\n\tdesiredRoles, found, err := unstructured.NestedStringSlice(talosSA.UnstructuredContent(), \"spec\", \"roles\")\n\tif err != nil || !found {\n\t\tmsg := messageRolesNotFound\n\n\t\tupdateErr := t.updateTalosSAStatus(ctx, talosSA, msg)\n\t\tif updateErr != nil {\n\t\t\treturn updateErr\n\t\t}\n\n\t\tt.eventRecorder.Event(talosSA, corev1.EventTypeWarning, errRolesNotFound, messageRolesNotFound)\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%s: %w\", msg, err)\n\t\t}\n\n\t\treturn errors.New(msg)\n\t}\n\n\tdesiredRoleSet, _ := role.Parse(desiredRoles)\n\n\tif !slices.ContainsFunc(t.allowedNamespaces, func(allowedNS string) bool {\n\t\treturn allowedNS == namespace\n\t}) {\n\t\tmsg := fmt.Sprintf(messageNamespaceNotAllowed, namespace)\n\n\t\terr = t.updateTalosSAStatus(ctx, talosSA, msg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tt.eventRecorder.Event(talosSA, corev1.EventTypeWarning, errNamespaceNotAllowed, msg)\n\n\t\treturn nil\n\t}\n\n\tvar unallowedRoles []string\n\n\tfor _, desiredRole := range desiredRoles {\n\t\t_, allowed := t.allowedRoles[desiredRole]\n\t\tif !allowed {\n\t\t\tunallowedRoles = append(unallowedRoles, desiredRole)\n\t\t}\n\t}\n\n\tif len(unallowedRoles) > 0 {\n\t\tmsg := fmt.Sprintf(messageRolesNotAllowed, unallowedRoles)\n\n\t\terr = t.updateTalosSAStatus(ctx, talosSA, msg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tt.eventRecorder.Event(talosSA, corev1.EventTypeWarning, errRolesNotAllowed, msg)\n\n\t\treturn nil\n\t}\n\n\tif secretNotFound {\n\t\tvar newSecret *corev1.Secret\n\n\t\tnewSecret, err = t.newSecret(talosSA, desiredRoleSet)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = t.kubeClient.CoreV1().Secrets(namespace).Create(ctx, newSecret, metav1.CreateOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if t.needsUpdate(secret, desiredRoleSet.Strings()) {\n\t\tvar newTalosconfigBytes []byte\n\n\t\tnewTalosconfigBytes, err = t.generateTalosconfig(desiredRoleSet)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsecret.Data[constants.TalosconfigFilename] = newTalosconfigBytes\n\n\t\t_, err = t.kubeClient.CoreV1().Secrets(namespace).Update(ctx, secret, metav1.UpdateOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr = t.updateTalosSAStatus(ctx, talosSA, \"\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tt.eventRecorder.Event(talosSA, corev1.EventTypeNormal, successResourceSynced, messageResourceSynced)\n\n\treturn nil\n}\n\nfunc (t *CRDController) enqueueTalosSA(obj any) {\n\tkey, err := cache.MetaNamespaceKeyFunc(obj)\n\tif err != nil {\n\t\tutilruntime.HandleError(err)\n\n\t\treturn\n\t}\n\n\tt.queue.Add(key)\n}\n\nfunc (t *CRDController) handleSecret(obj any) {\n\tvar object metav1.Object\n\n\tvar ok bool\n\n\tif object, ok = obj.(metav1.Object); !ok {\n\t\ttombstone, tombstoneOK := obj.(cache.DeletedFinalStateUnknown)\n\t\tif !tombstoneOK {\n\t\t\tutilruntime.HandleError(errors.New(\"error decoding object, invalid type\"))\n\n\t\t\treturn\n\t\t}\n\n\t\tobject, tombstoneOK = tombstone.Obj.(metav1.Object)\n\t\tif !tombstoneOK {\n\t\t\tutilruntime.HandleError(errors.New(\"error decoding object tombstone, invalid type\"))\n\n\t\t\treturn\n\t\t}\n\n\t\tt.logger.Sugar().Debugf(\"recovered deleted object '%s' from tombstone\", object.GetName())\n\t}\n\n\tt.logger.Sugar().Debugf(\"processing object: %s\", object.GetName())\n\n\tif ownerRef := metav1.GetControllerOf(object); ownerRef != nil {\n\t\tif ownerRef.Kind != constants.ServiceAccountResourceKind {\n\t\t\treturn\n\t\t}\n\n\t\ttalosSA, err := t.dynamicLister.Namespace(object.GetNamespace()).Get(ownerRef.Name)\n\t\tif err != nil {\n\t\t\tt.logger.Sugar().Debugf(\"ignoring orphaned object '%s/%s' of %s '%s'\",\n\t\t\t\tobject.GetNamespace(), object.GetName(), constants.ServiceAccountResourceKind, ownerRef.Name)\n\n\t\t\treturn\n\t\t}\n\n\t\tt.enqueueTalosSA(talosSA)\n\n\t\treturn\n\t}\n}\n\nfunc (t *CRDController) updateTalosSAStatus(\n\tctx context.Context,\n\ttalosSA *unstructured.Unstructured,\n\tfailureReason string,\n) error {\n\tvar err error\n\n\ttalosSACopy := talosSA.DeepCopy()\n\n\tif failureReason == \"\" {\n\t\tunstructured.RemoveNestedField(talosSACopy.UnstructuredContent(), \"status\", \"failureReason\")\n\t} else {\n\t\terr = unstructured.SetNestedField(talosSACopy.UnstructuredContent(), failureReason, \"status\", \"failureReason\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t_, err = t.dynamicClient.Resource(talosSAGVR).\n\t\tNamespace(talosSACopy.GetNamespace()).\n\t\tUpdate(ctx, talosSACopy, metav1.UpdateOptions{})\n\n\treturn err\n}\n\n//nolint:gocyclo\nfunc (t *CRDController) needsUpdate(secret *corev1.Secret, desiredRoles []string) bool {\n\ttalosconfigInSecret, ok := secret.Data[constants.TalosconfigFilename]\n\tif !ok {\n\t\tt.logger.Debug(\"talosconfig not found in secret\", zap.String(\"key\", constants.TalosconfigFilename))\n\n\t\treturn true\n\t}\n\n\tparsedTalosconfigInSecret, err := clientconfig.ReadFrom(bytes.NewReader(talosconfigInSecret))\n\tif err != nil {\n\t\tt.logger.Debug(\"error parsing talosconfig in secret\", zap.Error(err))\n\n\t\treturn true\n\t}\n\n\ttalosconfigCtx := parsedTalosconfigInSecret.Contexts[parsedTalosconfigInSecret.Context]\n\n\ttalosconfigCA, err := base64.StdEncoding.DecodeString(talosconfigCtx.CA)\n\tif err != nil {\n\t\tt.logger.Debug(\"error decoding talosconfig CA\", zap.Error(err))\n\n\t\treturn true\n\t}\n\n\tif !bytes.Equal(t.talosCA.Crt, talosconfigCA) {\n\t\tt.logger.Debug(\"ca mismatch detected\")\n\n\t\treturn true\n\t}\n\n\tif len(talosconfigCtx.Endpoints) != 1 || talosconfigCtx.Endpoints[0] != endpoint {\n\t\tt.logger.Debug(\n\t\t\t\"endpoint mismatch detected\",\n\t\t\tzap.Strings(\"actual\", talosconfigCtx.Endpoints),\n\t\t\tzap.Strings(\"expected\", []string{endpoint}),\n\t\t)\n\n\t\treturn true\n\t}\n\n\ttalosconfigCRT, err := base64.StdEncoding.DecodeString(talosconfigCtx.Crt)\n\tif err != nil {\n\t\tt.logger.Debug(\"error decoding talosconfig CRT\", zap.Error(err))\n\n\t\treturn true\n\t}\n\n\tblock, _ := pem.Decode(talosconfigCRT)\n\tif block == nil {\n\t\tt.logger.Debug(\"could not decode talosconfig CRT\")\n\n\t\treturn true\n\t}\n\n\tcertificate, err := stdlibx509.ParseCertificate(block.Bytes)\n\tif err != nil {\n\t\tt.logger.Debug(\"error parsing certificate in talosconfig of secret\", zap.Error(err))\n\n\t\treturn true\n\t}\n\n\tif certificate.NotAfter.IsZero() {\n\t\tt.logger.Debug(\"certificate in talosconfig of secret has no expiration date\", zap.Error(err))\n\n\t\treturn true\n\t}\n\n\tif time.Now().Add(certTTL).Before(certificate.NotAfter) {\n\t\tt.logger.Debug(\n\t\t\t\"certificate in talosconfig has expiration date too far in the future\",\n\t\t\tzap.Time(\"expiration\", certificate.NotAfter),\n\t\t)\n\n\t\treturn true\n\t}\n\n\tif time.Now().Add(certRenewThreshold).After(certificate.NotAfter) {\n\t\tt.logger.Debug(\n\t\t\t\"certificate in talosconfig needs renewal\",\n\t\t\tzap.Time(\"expiration\", certificate.NotAfter),\n\t\t)\n\n\t\treturn true\n\t}\n\n\tactualRoles := certificate.Subject.Organization\n\n\tslices.Sort(actualRoles)\n\tslices.Sort(desiredRoles)\n\n\tif !slices.Equal(actualRoles, desiredRoles) {\n\t\tt.logger.Debug(\"roles in certificate do not match desired roles\",\n\t\t\tzap.Strings(\"actual\", actualRoles), zap.Strings(\"desired\", desiredRoles))\n\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (t *CRDController) newSecret(talosSA *unstructured.Unstructured, roles role.Set) (*corev1.Secret, error) {\n\tconfig, err := t.generateTalosconfig(roles)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &corev1.Secret{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: talosSA.GetName(),\n\t\t\tOwnerReferences: []metav1.OwnerReference{\n\t\t\t\t*metav1.NewControllerRef(talosSA, talosSAGVK),\n\t\t\t},\n\t\t},\n\t\tData: map[string][]byte{\n\t\t\tconstants.TalosconfigFilename: config,\n\t\t},\n\t}, nil\n}\n\nfunc (t *CRDController) generateTalosconfig(roles role.Set) ([]byte, error) {\n\tvar newCert *x509.PEMEncodedCertificateAndKey\n\n\tnewCert, err := secrets.NewAdminCertificateAndKey(time.Now(), t.talosCA, roles, certTTL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewTalosconfig := clientconfig.NewConfig(talosconfigContextName, []string{endpoint}, t.talosCA.Crt, newCert)\n\n\treturn newTalosconfig.Bytes()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubeaccess/serviceaccount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubeaccess/serviceaccount\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// CRDController manages Kubernetes endpoints resource for Talos API endpoints.\ntype CRDController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *CRDController) Name() string {\n\treturn \"kubeaccess.CRDController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *CRDController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubeaccess.ConfigType,\n\t\t\tID:        optional.Some(kubeaccess.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesType,\n\t\t\tID:        optional.Some(secrets.KubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.OSRootType,\n\t\t\tID:        optional.Some(secrets.OSRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *CRDController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *CRDController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar crdControllerCtxCancel context.CancelFunc\n\n\tcrdControllerErrCh := make(chan error, 1)\n\n\tstopCRDController := func() {\n\t\tif crdControllerCtxCancel != nil {\n\t\t\tcrdControllerCtxCancel()\n\n\t\t\t<-crdControllerErrCh\n\n\t\t\tcrdControllerCtxCancel = nil\n\t\t}\n\t}\n\n\tdefer stopCRDController()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil //nolint:govet\n\t\tcase <-r.EventCh():\n\t\tcase err := <-crdControllerErrCh:\n\t\t\tif crdControllerCtxCancel != nil {\n\t\t\t\tcrdControllerCtxCancel()\n\t\t\t}\n\n\t\t\tcrdControllerCtxCancel = nil\n\n\t\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\treturn fmt.Errorf(\"error from crd controller: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tkubeaccessConfig, err := safe.ReaderGet[*kubeaccess.Config](ctx, r, kubeaccess.NewConfig(config.NamespaceName, kubeaccess.ConfigID).Metadata())\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error fetching kubeaccess config: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tvar kubeaccessConfigSpec *kubeaccess.ConfigSpec\n\n\t\tif kubeaccessConfig != nil {\n\t\t\tkubeaccessConfigSpec = kubeaccessConfig.TypedSpec()\n\t\t}\n\n\t\tif kubeaccessConfig == nil || kubeaccessConfigSpec == nil || !kubeaccessConfigSpec.Enabled {\n\t\t\tstopCRDController()\n\n\t\t\tcontinue\n\t\t}\n\n\t\tkubeSecretsResources, err := safe.ReaderGet[*secrets.Kubernetes](ctx, r, resource.NewMetadata(\n\t\t\tsecrets.NamespaceName,\n\t\t\tsecrets.KubernetesType,\n\t\t\tsecrets.KubernetesID,\n\t\t\tresource.VersionUndefined,\n\t\t))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error fetching kubernetes secrets: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tkubeSecretsSpec := kubeSecretsResources.TypedSpec()\n\n\t\tosSecretsResource, err := safe.ReaderGet[*secrets.OSRoot](ctx, r, resource.NewMetadata(\n\t\t\tsecrets.NamespaceName,\n\t\t\tsecrets.OSRootType,\n\t\t\tsecrets.OSRootID,\n\t\t\tresource.VersionUndefined,\n\t\t))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error fetching os secrets: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tosSecretsSpec := osSecretsResource.TypedSpec()\n\n\t\tkubeconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\t\treturn clientcmd.Load([]byte(kubeSecretsSpec.LocalhostAdminKubeconfig))\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error loading kubeconfig: %w\", err)\n\t\t}\n\n\t\tstopCRDController()\n\n\t\tvar crdControllerCtx context.Context\n\n\t\tcrdControllerCtx, crdControllerCtxCancel = context.WithCancel(ctx) //nolint:govet\n\n\t\tgo func() {\n\t\t\tcrdControllerErrCh <- ctrl.runCRDController(\n\t\t\t\tcrdControllerCtx,\n\t\t\t\tosSecretsSpec.IssuingCA,\n\t\t\t\tkubeconfig,\n\t\t\t\tkubeaccessConfigSpec,\n\t\t\t\tlogger,\n\t\t\t)\n\t\t}()\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *CRDController) runCRDController(\n\tctx context.Context,\n\ttalosCA *x509.PEMEncodedCertificateAndKey,\n\tkubeconfig *rest.Config,\n\tkubeaccessCfgSpec *kubeaccess.ConfigSpec,\n\tlogger *zap.Logger,\n) error {\n\treturn etcd.WithLock(ctx, constants.EtcdTalosServiceAccountCRDControllerMutex, logger, func() error {\n\t\tcrdCtrl, err := serviceaccount.NewCRDController(\n\t\t\ttalosCA,\n\t\t\tkubeconfig,\n\t\t\tkubeaccessCfgSpec.AllowedKubernetesNamespaces,\n\t\t\tkubeaccessCfgSpec.AllowedAPIRoles,\n\t\t\tlogger,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn crdCtrl.Run(ctx, 1)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\n// ConfigController watches v1alpha1.Config, updates KubeSpan config.\ntype ConfigController = transform.Controller[*config.MachineConfig, *kubespan.Config]\n\n// NewConfigController instanciates the config controller.\nfunc NewConfigController() *ConfigController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *kubespan.Config]{\n\t\t\tName: \"kubespan.ConfigController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*kubespan.Config] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*kubespan.Config]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Machine() == nil || cfg.Config().Cluster() == nil {\n\t\t\t\t\treturn optional.None[*kubespan.Config]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *kubespan.Config) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\t*spec = kubespan.ConfigSpec{}\n\n\t\t\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\t\t\tc := cfg.Config()\n\n\t\t\t\t\tif c.NetworkKubeSpanConfig() != nil {\n\t\t\t\t\t\tres.TypedSpec().Enabled = c.NetworkKubeSpanConfig().Enabled()\n\t\t\t\t\t\tres.TypedSpec().ForceRouting = c.NetworkKubeSpanConfig().ForceRouting()\n\t\t\t\t\t\tres.TypedSpec().AdvertiseKubernetesNetworks = c.NetworkKubeSpanConfig().AdvertiseKubernetesNetworks()\n\t\t\t\t\t\tres.TypedSpec().HarvestExtraEndpoints = c.NetworkKubeSpanConfig().HarvestExtraEndpoints()\n\t\t\t\t\t\tres.TypedSpec().MTU = c.NetworkKubeSpanConfig().MTU()\n\n\t\t\t\t\t\tif c.NetworkKubeSpanConfig().Filters() != nil {\n\t\t\t\t\t\t\tres.TypedSpec().EndpointFilters = c.NetworkKubeSpanConfig().Filters().Endpoints()\n\t\t\t\t\t\t\tres.TypedSpec().ExcludeAdvertisedNetworks = c.NetworkKubeSpanConfig().Filters().ExcludeAdvertisedNetworks()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tres.TypedSpec().ClusterID = c.Cluster().ID()\n\t\t\t\t\tres.TypedSpec().SharedSecret = c.Cluster().Secret()\n\t\t\t\t\tres.TypedSpec().ExtraEndpoints = c.KubespanConfig().ExtraAnnouncedEndpoints()\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage kubespan_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubespanctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ConfigSuite) TestReconcileConfig() {\n\tctr, err := container.New(\n\t\t&v1alpha1.Config{\n\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\tKubeSpanFilters: &v1alpha1.KubeSpanFilters{\n\t\t\t\t\t\t\tKubeSpanFiltersExcludeAdvertisedNetworks: []string{\"10.0.0.0/8\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\tClusterID:     \"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\",\n\t\t\t\tClusterSecret: \"I+1In7fLnpcRIjUmEoeugZnSyFoTF6MztLxICL5Yu0s=\",\n\t\t\t},\n\t\t},\n\t\t&network.KubespanEndpointsConfigV1Alpha1{\n\t\t\tExtraAnnouncedEndpointsConfig: []netip.AddrPort{\n\t\t\t\tnetip.MustParseAddrPort(\"192.168.33.11:1001\"),\n\t\t\t},\n\t\t},\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResource(suite, kubespan.ConfigID, func(res *kubespan.Config, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.True(spec.Enabled)\n\t\tasrt.Equal(\"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\", spec.ClusterID)\n\t\tasrt.Equal(\"I+1In7fLnpcRIjUmEoeugZnSyFoTF6MztLxICL5Yu0s=\", spec.SharedSecret)\n\t\tasrt.True(spec.ForceRouting)\n\t\tasrt.False(spec.AdvertiseKubernetesNetworks)\n\t\tasrt.False(spec.HarvestExtraEndpoints)\n\t\tasrt.Equal(\"[\\\"192.168.33.11:1001\\\"]\", fmt.Sprintf(\"%q\", spec.ExtraEndpoints))\n\t\tasrt.Equal([]netip.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}, spec.ExcludeAdvertisedNetworks)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestReconcileDisabled() {\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t}))\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, kubespan.ConfigID, func(res *kubespan.Config, asrt *assert.Assertions) {\n\t\tspec := res.TypedSpec()\n\n\t\tasrt.False(spec.Enabled)\n\t})\n}\n\nfunc (suite *ConfigSuite) TestReconcileMultiDoc() {\n\tkubeSpanCfg := network.NewKubeSpanV1Alpha1()\n\tkubeSpanCfg.ConfigEnabled = new(true)\n\tkubeSpanCfg.ConfigMTU = new(uint32(1380))\n\tkubeSpanCfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\tConfigEndpoints:                 []string{\"0.0.0.0/0\", \"::/0\"},\n\t\tConfigExcludeAdvertisedNetworks: []network.Prefix{{Prefix: netip.MustParsePrefix(\"10.0.0.0/8\")}},\n\t}\n\n\tctr, err := container.New(\n\t\t&v1alpha1.Config{\n\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\tClusterID:     \"test-cluster-id-multi-doc\",\n\t\t\t\tClusterSecret: \"test-cluster-secret-multi-doc\",\n\t\t\t},\n\t\t},\n\t\tkubeSpanCfg,\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResource(suite, kubespan.ConfigID,\n\t\tfunc(res *kubespan.Config, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.True(spec.Enabled)\n\t\t\tasrt.Equal(\"test-cluster-id-multi-doc\", spec.ClusterID)\n\t\t\tasrt.Equal(\"test-cluster-secret-multi-doc\", spec.SharedSecret)\n\t\t\tasrt.Equal(uint32(1380), spec.MTU)\n\t\t\tasrt.Equal([]string{\"0.0.0.0/0\", \"::/0\"}, spec.EndpointFilters)\n\t\t\tasrt.Equal([]netip.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}, spec.ExcludeAdvertisedNetworks)\n\t\t},\n\t)\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(kubespanctrl.NewConfigController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\n// EndpointController watches KubeSpanPeerStatuses, Affiliates and harvests additional endpoints for the peers.\ntype EndpointController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EndpointController) Name() string {\n\treturn \"kubespan.EndpointController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubespan.ConfigType,\n\t\t\tID:        optional.Some(kubespan.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.AffiliateType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: kubespan.NamespaceName,\n\t\t\tType:      kubespan.PeerStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EndpointController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: kubespan.EndpointType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EndpointController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan configuration: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg == nil || !cfg.TypedSpec().HarvestExtraEndpoints {\n\t\t\t// not enabled, short-circuit early\n\t\t\tif err = safe.CleanupOutputs[*kubespan.Endpoint](ctx, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// for every kubespan peer, if it's up and has endpoint, harvest that endpoint\n\t\tpeerStatuses, err := safe.ReaderListAll[*kubespan.PeerStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing cluster affiliates: %w\", err)\n\t\t}\n\n\t\taffiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing cluster affiliates: %w\", err)\n\t\t}\n\n\t\t// build lookup table of affiliate's kubespan public key back to affiliate ID\n\t\taffiliateLookup := make(map[string]string)\n\n\t\tfor affiliate := range affiliates.All() {\n\t\t\taffiliateSpec := affiliate.TypedSpec()\n\n\t\t\tif affiliateSpec.KubeSpan.PublicKey != \"\" {\n\t\t\t\taffiliateLookup[affiliateSpec.KubeSpan.PublicKey] = affiliateSpec.NodeID\n\t\t\t}\n\t\t}\n\n\t\tfor res := range peerStatuses.All() {\n\t\t\tpeerStatus := res.TypedSpec()\n\n\t\t\tif peerStatus.State != kubespan.PeerStateUp {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif value.IsZero(peerStatus.Endpoint) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\taffiliateID, ok := affiliateLookup[res.Metadata().ID()]\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, kubespan.NewEndpoint(kubespan.NamespaceName, res.Metadata().ID()), func(res *kubespan.Endpoint) error {\n\t\t\t\t*res.TypedSpec() = kubespan.EndpointSpec{\n\t\t\t\t\tAffiliateID: affiliateID,\n\t\t\t\t\tEndpoint:    peerStatus.Endpoint,\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*kubespan.Endpoint](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage kubespan_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubespanctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\ntype EndpointSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *EndpointSuite) TestReconcile() {\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().HarvestExtraEndpoints = true\n\tsuite.Create(cfg)\n\n\t// create some affiliates and peer statuses\n\taffiliate1 := cluster.NewAffiliate(cluster.NamespaceName, \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate1.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t},\n\t}\n\n\taffiliate2 := cluster.NewAffiliate(cluster.NamespaceName, \"roLng5hmP0Gv9S5Pbfzaa93JSZjsdpXNAn7vzuCfsc8\")\n\t*affiliate2.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"roLng5hmP0Gv9S5Pbfzaa93JSZjsdpXNAn7vzuCfsc8\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.5\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey: \"1CXkdhWBm58c36kTpchR8iGlXHG1ruHa5W8gsFqD8Qs=\",\n\t\t\tAddress:   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1\"),\n\t\t},\n\t}\n\n\tsuite.Create(affiliate1)\n\tsuite.Create(affiliate2)\n\n\tpeerStatus1 := kubespan.NewPeerStatus(kubespan.NamespaceName, affiliate1.TypedSpec().KubeSpan.PublicKey)\n\t*peerStatus1.TypedSpec() = kubespan.PeerStatusSpec{\n\t\tEndpoint: netip.MustParseAddrPort(\"10.3.4.8:278\"),\n\t\tState:    kubespan.PeerStateUp,\n\t}\n\n\tpeerStatus2 := kubespan.NewPeerStatus(kubespan.NamespaceName, affiliate2.TypedSpec().KubeSpan.PublicKey)\n\t*peerStatus2.TypedSpec() = kubespan.PeerStatusSpec{\n\t\tEndpoint: netip.MustParseAddrPort(\"10.3.4.9:279\"),\n\t\tState:    kubespan.PeerStateUnknown,\n\t}\n\n\tpeerStatus3 := kubespan.NewPeerStatus(kubespan.NamespaceName, \"LoXPyyYh3kZwyKyWfCcf9VvgVv588cKhSKXavuUZqDg=\")\n\t*peerStatus3.TypedSpec() = kubespan.PeerStatusSpec{\n\t\tEndpoint: netip.MustParseAddrPort(\"10.3.4.10:270\"),\n\t\tState:    kubespan.PeerStateUp,\n\t}\n\n\tsuite.Create(peerStatus1)\n\tsuite.Create(peerStatus2)\n\tsuite.Create(peerStatus3)\n\n\t// peer1 is up and has matching affiliate\n\tctest.AssertResource(suite, peerStatus1.Metadata().ID(),\n\t\tfunc(res *kubespan.Endpoint, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(peerStatus1.TypedSpec().Endpoint, spec.Endpoint)\n\t\t\tasrt.Equal(affiliate1.TypedSpec().NodeID, spec.AffiliateID)\n\t\t},\n\t)\n\n\t// peer2 is not up, it shouldn't be published as an endpoint\n\tctest.AssertNoResource[*kubespan.Endpoint](suite, peerStatus2.Metadata().ID())\n\n\t// peer3 is up, but has not matching affiliate\n\tctest.AssertNoResource[*kubespan.Endpoint](suite, peerStatus3.Metadata().ID())\n}\n\nfunc TestEndpointSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &EndpointSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&kubespanctrl.EndpointController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// IdentityController watches KubeSpan configuration, updates KubeSpan Identity.\ntype IdentityController struct {\n\tstateMachine blockautomaton.VolumeMounterAutomaton\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *IdentityController) Name() string {\n\treturn \"kubespan.IdentityController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *IdentityController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubespan.ConfigType,\n\t\t\tID:        optional.Some(kubespan.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HardwareAddrType,\n\t\t\tID:        optional.Some(network.FirstHardwareAddr),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *IdentityController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: kubespan.IdentityType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *IdentityController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan configuration: %w\", err)\n\t\t}\n\n\t\tfirstMAC, err := safe.ReaderGetByID[*network.HardwareAddr](ctx, r, network.FirstHardwareAddr)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting first MAC address: %w\", err)\n\t\t}\n\n\t\t_, err = safe.ReaderGetByID[*kubespan.Identity](ctx, r, kubespan.LocalIdentity)\n\t\talreadyHasIdentity := err == nil\n\n\t\tif cfg != nil && firstMAC != nil && cfg.TypedSpec().Enabled {\n\t\t\tif fipsmode.Strict() {\n\t\t\t\treturn fmt.Errorf(\"KubeSpan is not supported in strict FIPS mode\")\n\t\t\t}\n\n\t\t\tif ctrl.stateMachine == nil && !alreadyHasIdentity {\n\t\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\t\tctrl.Name(),\n\t\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\t\tctrl.establishIdentity(cfg, firstMAC),\n\t\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t\t)\n\t\t\t}\n\t\t} else if alreadyHasIdentity {\n\t\t\tif err = r.Destroy(ctx, kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity).Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error cleaning up identity: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif ctrl.stateMachine != nil {\n\t\t\tif err := ctrl.stateMachine.Run(ctx, r, logger,\n\t\t\t\tautomaton.WithAfterFunc(func() error {\n\t\t\t\t\tctrl.stateMachine = nil\n\n\t\t\t\t\treturn nil\n\t\t\t\t}),\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error running volume mounter machine: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *IdentityController) establishIdentity(\n\tcfg *kubespan.Config, firstMAC *network.HardwareAddr,\n) func(\n\tctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus,\n) error {\n\treturn func(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\t\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\t\tvar localIdentity kubespan.IdentitySpec\n\n\t\t\tif err := controllers.LoadOrNewFromFile(root, constants.KubeSpanIdentityFilename, &localIdentity, func(v *kubespan.IdentitySpec) error {\n\t\t\t\treturn kubespanadapter.IdentitySpec(v).GenerateKey()\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error caching kubespan identity: %w\", err)\n\t\t\t}\n\n\t\t\tkubespanCfg := cfg.TypedSpec()\n\t\t\tmac := firstMAC.TypedSpec()\n\n\t\t\tif err := kubespanadapter.IdentitySpec(&localIdentity).UpdateAddress(kubespanCfg.ClusterID, net.HardwareAddr(mac.HardwareAddr)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating KubeSpan address: %w\", err)\n\t\t\t}\n\n\t\t\treturn safe.WriterModify(ctx, r, kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity), func(res *kubespan.Identity) error {\n\t\t\t\t*res.TypedSpec() = localIdentity\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/identity_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage kubespan_test\n\nimport (\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubespanctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype IdentitySuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *IdentitySuite) TestGenerate() {\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ClusterID = \"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\"\n\n\tsuite.Create(cfg)\n\n\tfirstMac := network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr)\n\tmac, err := net.ParseMAC(\"ea:71:1b:b2:cc:ee\")\n\tsuite.Require().NoError(err)\n\n\tfirstMac.TypedSpec().HardwareAddr = nethelpers.HardwareAddr(mac)\n\tsuite.Create(firstMac)\n\n\tstatePath := suite.T().TempDir()\n\tmountID := (&kubespanctrl.IdentityController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tctest.AssertNoResource[*kubespan.Identity](suite, kubespan.LocalIdentity)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, kubespan.LocalIdentity, func(identity *kubespan.Identity, asrt *assert.Assertions) {\n\t\tspec := identity.TypedSpec()\n\n\t\t_, err := wgtypes.ParseKey(spec.PrivateKey)\n\t\tasrt.NoError(err)\n\n\t\t_, err = wgtypes.ParseKey(spec.PublicKey)\n\t\tasrt.NoError(err)\n\n\t\tasrt.Equal(\"fd7f:175a:b97c:5602:e871:1bff:feb2:ccee/128\", spec.Address.String())\n\t\tasrt.Equal(\"fd7f:175a:b97c:5602::/64\", spec.Subnet.String())\n\t})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n}\n\nfunc (suite *IdentitySuite) TestLoad() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&kubespanctrl.IdentityController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\t// using verbatim data here to make sure nodeId representation is supported in future version of Talos\n\tconst identityYaml = `address: \"\"\nsubnet: \"\"\nprivateKey: sF45u5ePau58WeeCUY3T8D9foEKaQ8Opx4cGC8g4XE4=\npublicKey: Oak2fBEWngBhwslBxDVgnRNHXs88OAp4kjroSX0uqUE=\n`\n\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(statePath, constants.KubeSpanIdentityFilename), []byte(identityYaml), 0o600))\n\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ClusterID = \"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\"\n\n\tsuite.Create(cfg)\n\n\tfirstMac := network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr)\n\tmac, err := net.ParseMAC(\"ea:71:1b:b2:cc:ee\")\n\tsuite.Require().NoError(err)\n\n\tfirstMac.TypedSpec().HardwareAddr = nethelpers.HardwareAddr(mac)\n\tsuite.Create(firstMac)\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tctest.AssertNoResource[*kubespan.Identity](suite, kubespan.LocalIdentity)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, kubespan.LocalIdentity, func(identity *kubespan.Identity, asrt *assert.Assertions) {\n\t\tspec := identity.TypedSpec()\n\n\t\tasrt.Equal(\"sF45u5ePau58WeeCUY3T8D9foEKaQ8Opx4cGC8g4XE4=\", spec.PrivateKey)\n\t\tasrt.Equal(\"Oak2fBEWngBhwslBxDVgnRNHXs88OAp4kjroSX0uqUE=\", spec.PublicKey)\n\t\tasrt.Equal(\"fd7f:175a:b97c:5602:e871:1bff:feb2:ccee/128\", spec.Address.String())\n\t\tasrt.Equal(\"fd7f:175a:b97c:5602::/64\", spec.Subnet.String())\n\t})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n}\n\nfunc TestIdentitySuite(t *testing.T) {\n\tt.Parallel()\n\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in FIPS mode\")\n\t}\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.Run(t, &IdentitySuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&kubespanctrl.IdentityController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/kubespan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubespan provides controllers which manage Talos KubeSpan feature.\npackage kubespan\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/manager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go.uber.org/zap\"\n\t\"go4.org/netipx\"\n\t\"golang.zx2c4.com/wireguard/wgctrl\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DefaultPeerReconcileInterval is interval between peer status reconciliation on timer.\n//\n// Peers might be reconciled more often e.g. when peerSpecs are updated.\nconst DefaultPeerReconcileInterval = 30 * time.Second\n\n// ManagerController sets up Wireguard networking based on KubeSpan configuration, watches and updates peer statuses.\ntype ManagerController struct {\n\tWireguardClientFactory WireguardClientFactory\n\tPeerReconcileInterval  time.Duration\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ManagerController) Name() string {\n\treturn \"kubespan.ManagerController\"\n}\n\n// WireguardClientFactory allows mocking Wireguard client.\ntype WireguardClientFactory func() (WireguardClient, error)\n\n// WireguardClient allows mocking Wireguard client.\ntype WireguardClient interface {\n\tDevice(string) (*wgtypes.Device, error)\n\tClose() error\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ManagerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubespan.ConfigType,\n\t\t\tID:        optional.Some(kubespan.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: kubespan.NamespaceName,\n\t\t\tType:      kubespan.PeerSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: kubespan.NamespaceName,\n\t\t\tType:      kubespan.IdentityType,\n\t\t\tID:        optional.Some(kubespan.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ManagerController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.LinkSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.RouteSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.NfTablesChainType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.RoutingRuleSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: kubespan.PeerStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\ttickerC <-chan time.Time\n\t\tticker  *time.Ticker\n\t)\n\n\tif ctrl.WireguardClientFactory == nil {\n\t\tctrl.WireguardClientFactory = func() (WireguardClient, error) {\n\t\t\treturn wgctrl.New()\n\t\t}\n\t}\n\n\tif ctrl.PeerReconcileInterval == 0 {\n\t\tctrl.PeerReconcileInterval = DefaultPeerReconcileInterval\n\t}\n\n\tvar wgClient WireguardClient\n\n\tdefer func() {\n\t\tif wgClient != nil {\n\t\t\twgClient.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\tfor {\n\t\tvar updateSpecs bool\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tupdateSpecs = true\n\t\tcase <-tickerC:\n\t\t}\n\n\t\tcfg, err := safe.ReaderGet[*kubespan.Config](ctx, r, resource.NewMetadata(config.NamespaceName, kubespan.ConfigType, kubespan.ConfigID, resource.VersionUndefined))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan configuration: %w\", err)\n\t\t}\n\n\t\tif cfg == nil || !cfg.TypedSpec().Enabled {\n\t\t\tif ticker != nil {\n\t\t\t\tticker.Stop()\n\n\t\t\t\ttickerC = nil\n\t\t\t}\n\n\t\t\t// KubeSpan is not enabled, cleanup everything\n\t\t\tif err = ctrl.cleanup(ctx, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif wgClient == nil {\n\t\t\twgClient, err = ctrl.WireguardClientFactory()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating wireguard client: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif ticker == nil {\n\t\t\tticker = time.NewTicker(ctrl.PeerReconcileInterval)\n\t\t\ttickerC = ticker.C\n\t\t}\n\n\t\tcfgSpec := cfg.TypedSpec()\n\n\t\tlocalIdentity, err := safe.ReaderGet[*kubespan.Identity](ctx, r, resource.NewMetadata(kubespan.NamespaceName, kubespan.IdentityType, kubespan.LocalIdentity, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting local KubeSpan identity: %w\", err)\n\t\t}\n\n\t\tlocalSpec := localIdentity.TypedSpec()\n\n\t\t// fetch PeerSpecs and PeerStatuses and sync them\n\t\tpeerSpecList, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing peer specs: %w\", err)\n\t\t}\n\n\t\tpeerSpecs := make(map[string]*kubespan.PeerSpecSpec, len(peerSpecList.Items))\n\n\t\tfor _, res := range peerSpecList.Items {\n\t\t\tpeerSpecs[res.Metadata().ID()] = res.(*kubespan.PeerSpec).TypedSpec()\n\t\t}\n\n\t\tpeerStatusList, err := r.List(ctx, resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing peer status: %w\", err)\n\t\t}\n\n\t\tpeerStatuses := make(map[string]*kubespan.PeerStatusSpec, len(peerStatusList.Items))\n\n\t\tfor _, res := range peerStatusList.Items {\n\t\t\t// drop any peer statuses which are not in the peer specs\n\t\t\tif _, ok := peerSpecs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying peer status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tpeerStatuses[res.Metadata().ID()] = res.(*kubespan.PeerStatus).TypedSpec()\n\t\t}\n\n\t\t// create missing peer statuses\n\t\tfor pubKey, peerSpec := range peerSpecs {\n\t\t\tif _, ok := peerStatuses[pubKey]; !ok {\n\t\t\t\tpeerStatuses[pubKey] = &kubespan.PeerStatusSpec{\n\t\t\t\t\tLabel: peerSpec.Label,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// update peer status from Wireguard data\n\t\twgDevice, err := wgClient.Device(constants.KubeSpanLinkName)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn fmt.Errorf(\"error fetching wireguard link status: %w\", err)\n\t\t}\n\n\t\tif wgDevice != nil { // wgDevice might be nil if the link is not created yet\n\t\t\tfor _, peerInfo := range wgDevice.Peers {\n\t\t\t\tif peerStatus, ok := peerStatuses[peerInfo.PublicKey.String()]; ok {\n\t\t\t\t\tkubespanadapter.PeerStatusSpec(peerStatus).UpdateFromWireguard(peerInfo)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// calculate peer status connection state\n\t\tfor _, peerStatus := range peerStatuses {\n\t\t\tkubespanadapter.PeerStatusSpec(peerStatus).CalculateState()\n\t\t}\n\n\t\t// build wireguard peer configuration\n\t\twgPeers := make([]network.WireguardPeer, 0, len(peerSpecs))\n\n\t\tfor pubKey, peerSpec := range peerSpecs {\n\t\t\t// list of statuses and specs should be in sync at this point\n\t\t\tpeerStatus := peerStatuses[pubKey]\n\n\t\t\tvar endpoint string\n\n\t\t\t// check if the endpoint should be updated\n\t\t\tif kubespanadapter.PeerStatusSpec(peerStatus).ShouldChangeEndpoint() {\n\t\t\t\tnewEndpoint := kubespanadapter.PeerStatusSpec(peerStatus).PickNewEndpoint(peerSpec.Endpoints)\n\n\t\t\t\tif !value.IsZero(newEndpoint) {\n\t\t\t\t\tlogger.Debug(\"updating endpoint for the peer\", zap.String(\"peer\", pubKey), zap.String(\"label\", peerSpec.Label), zap.Stringer(\"endpoint\", newEndpoint))\n\n\t\t\t\t\tendpoint = newEndpoint.String()\n\t\t\t\t\tkubespanadapter.PeerStatusSpec(peerStatus).UpdateEndpoint(newEndpoint)\n\n\t\t\t\t\tupdateSpecs = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// re-establish the endpoint if it wasn't applied to the Wireguard config completely\n\t\t\tif !value.IsZero(peerStatus.LastUsedEndpoint) && (value.IsZero(peerStatus.Endpoint) || peerStatus.Endpoint == peerStatus.LastUsedEndpoint) {\n\t\t\t\tendpoint = peerStatus.LastUsedEndpoint.String()\n\t\t\t\tpeerStatus.Endpoint = peerStatus.LastUsedEndpoint\n\n\t\t\t\tupdateSpecs = true\n\t\t\t}\n\n\t\t\twgPeers = append(wgPeers, network.WireguardPeer{\n\t\t\t\tPublicKey:                   pubKey,\n\t\t\t\tPresharedKey:                cfgSpec.SharedSecret,\n\t\t\t\tEndpoint:                    endpoint,\n\t\t\t\tPersistentKeepaliveInterval: constants.KubeSpanDefaultPeerKeepalive,\n\t\t\t\tAllowedIPs:                  slices.Clone(peerSpec.AllowedIPs),\n\t\t\t})\n\t\t}\n\n\t\t// build a full set of routed over KubeSpan IPs,\n\t\t// note this doesn't include KubeSpan ULA addresses\n\t\tvar routedIPsBuilder netipx.IPSetBuilder\n\n\t\tfor pubKey, peerSpec := range peerSpecs {\n\t\t\t// list of statuses and specs should be in sync at this point\n\t\t\tpeerStatus := peerStatuses[pubKey]\n\n\t\t\t// add allowedIPs to the nftables set if either routing is forced (for any peer state)\n\t\t\t// or if the peer connection state is up.\n\t\t\tif cfgSpec.ForceRouting || peerStatus.State == kubespan.PeerStateUp {\n\t\t\t\tfor _, prefix := range peerSpec.AllowedIPs {\n\t\t\t\t\tif !network.IsULA(prefix.Addr(), network.ULAKubeSpan) {\n\t\t\t\t\t\troutedIPsBuilder.AddPrefix(prefix)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\troutedIPsSet, err := routedIPsBuilder.IPSet()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed building allowed IPs set: %w\", err)\n\t\t}\n\n\t\t// update peer statuses\n\t\tfor pubKey, peerStatus := range peerStatuses {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\tkubespan.NewPeerStatus(\n\t\t\t\t\tkubespan.NamespaceName,\n\t\t\t\t\tpubKey,\n\t\t\t\t),\n\t\t\t\tfunc(r *kubespan.PeerStatus) error {\n\t\t\t\t\t*r.TypedSpec() = *peerStatus\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying peer status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tmtu := cfgSpec.MTU\n\n\t\t// always update the firewall rules, as allowedIPsSet might change at any moment due to peer up/down events\n\t\tif err = safe.WriterModify(ctx, r,\n\t\t\tnetwork.NewNfTablesChain(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\t\"kubespan_prerouting\",\n\t\t\t),\n\t\t\tfunc(r *network.NfTablesChain) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Type = nethelpers.ChainTypeFilter\n\t\t\t\tspec.Hook = nethelpers.ChainHookPrerouting\n\t\t\t\tspec.Priority = nethelpers.ChainPriorityFilter\n\t\t\t\tspec.Policy = nethelpers.VerdictAccept\n\n\t\t\t\tspec.Rules = []network.NfTablesRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchMark: &network.NfTablesMark{\n\t\t\t\t\t\t\tMask:  constants.KubeSpanDefaultFirewallMask,\n\t\t\t\t\t\t\tValue: constants.KubeSpanDefaultFirewallMark,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\tIncludeSubnets: routedIPsSet.Prefixes(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\t\t\t\tXor:  constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying nftables chain: %w\", err)\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r,\n\t\t\tnetwork.NewNfTablesChain(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\t\"kubespan_outgoing\",\n\t\t\t),\n\t\t\tfunc(r *network.NfTablesChain) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Type = nethelpers.ChainTypeRoute\n\t\t\t\tspec.Hook = nethelpers.ChainHookOutput\n\t\t\t\tspec.Priority = nethelpers.ChainPriorityFilter\n\t\t\t\tspec.Policy = nethelpers.VerdictAccept\n\n\t\t\t\tspec.Rules = []network.NfTablesRule{\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchMark: &network.NfTablesMark{\n\t\t\t\t\t\t\tMask:  constants.KubeSpanDefaultFirewallMask,\n\t\t\t\t\t\t\tValue: constants.KubeSpanDefaultFirewallMark,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchOIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\t\t\tInterfaceNames: []string{\"lo\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\tIncludeSubnets: routedIPsSet.Prefixes(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tClampMSS: &network.NfTablesClampMSS{\n\t\t\t\t\t\t\tMTU: uint16(mtu),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\tIncludeSubnets: routedIPsSet.Prefixes(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\t\t\t\tXor:  constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying nftables chain: %w\", err)\n\t\t}\n\n\t\tif !updateSpecs {\n\t\t\t// micro-optimization: skip updating specs if there are no changes to the incoming resources and no endpoint changes\n\t\t\tr.ResetRestartBackoff()\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r,\n\t\t\tnetwork.NewAddressSpec(\n\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\tnetwork.LayeredID(network.ConfigOperator, network.AddressID(constants.KubeSpanLinkName, localSpec.Address)),\n\t\t\t),\n\t\t\tfunc(r *network.AddressSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.Address = netip.PrefixFrom(localSpec.Address.Addr(), localSpec.Subnet.Bits())\n\t\t\t\tspec.ConfigLayer = network.ConfigOperator\n\t\t\t\tspec.Family = nethelpers.FamilyInet6\n\t\t\t\tspec.Flags = nethelpers.AddressFlags(nethelpers.AddressPermanent)\n\t\t\t\tspec.LinkName = constants.KubeSpanLinkName\n\t\t\t\tspec.Scope = nethelpers.ScopeGlobal\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying address: %w\", err)\n\t\t}\n\n\t\tfor _, spec := range []network.RouteSpecSpec{\n\t\t\t{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tDestination: netip.Prefix{},\n\t\t\t\tSource:      netip.Addr{},\n\t\t\t\tGateway:     netip.Addr{},\n\t\t\t\tMTU:         mtu,\n\t\t\t\tOutLinkName: constants.KubeSpanLinkName,\n\t\t\t\tTable:       nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable),\n\t\t\t\tPriority:    1,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFlags:       0,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t\t{\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tDestination: netip.Prefix{},\n\t\t\t\tSource:      netip.Addr{},\n\t\t\t\tGateway:     netip.Addr{},\n\t\t\t\tMTU:         mtu,\n\t\t\t\tOutLinkName: constants.KubeSpanLinkName,\n\t\t\t\tTable:       nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable),\n\t\t\t\tPriority:    1,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFlags:       0,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t} {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\tnetwork.NewRouteSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tnetwork.LayeredID(network.ConfigOperator, network.RouteID(spec.Table, spec.Family, spec.Destination, spec.Gateway, spec.Priority, spec.OutLinkName)),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.RouteSpec) error {\n\t\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying route spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r,\n\t\t\tnetwork.NewLinkSpec(\n\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),\n\t\t\t),\n\t\t\tfunc(r *network.LinkSpec) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.ConfigLayer = network.ConfigOperator\n\t\t\t\tspec.Name = constants.KubeSpanLinkName\n\t\t\t\tspec.Type = nethelpers.LinkNone\n\t\t\t\tspec.Kind = \"wireguard\"\n\t\t\t\tspec.Up = true\n\t\t\t\tspec.Logical = true\n\t\t\t\tspec.MTU = mtu\n\n\t\t\t\tspec.Wireguard = network.WireguardSpec{\n\t\t\t\t\tPrivateKey:   localSpec.PrivateKey,\n\t\t\t\t\tListenPort:   constants.KubeSpanDefaultPort,\n\t\t\t\t\tFirewallMark: constants.KubeSpanDefaultFirewallMark,\n\t\t\t\t\tPeers:        wgPeers,\n\t\t\t\t}\n\t\t\t\tspec.Wireguard.Sort()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying link spec: %w\", err)\n\t\t}\n\n\t\tfor _, ruleSpec := range []network.RoutingRuleSpecSpec{\n\t\t\t{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tTable:       nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable),\n\t\t\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\t\t\tFwMark:      constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\tFwMask:      constants.KubeSpanDefaultFirewallMask,\n\t\t\t\tPriority:    constants.KubeSpanDefaultRulePriority,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t\t{\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tTable:       nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable),\n\t\t\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\t\t\tFwMark:      constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\tFwMask:      constants.KubeSpanDefaultFirewallMask,\n\t\t\t\tPriority:    constants.KubeSpanDefaultRulePriority,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t} {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\tnetwork.NewRoutingRuleSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tnetwork.LayeredID(network.ConfigOperator, network.RoutingRuleID(ruleSpec.Family, ruleSpec.Priority)),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.RoutingRuleSpec) error {\n\t\t\t\t\t*r.TypedSpec() = ruleSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying routing rule spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *ManagerController) cleanup(ctx context.Context, r controller.Runtime) error {\n\tfor _, item := range []struct {\n\t\tnamespace resource.Namespace\n\t\ttyp       resource.Type\n\t}{\n\t\t{\n\t\t\tnamespace: network.ConfigNamespaceName,\n\t\t\ttyp:       network.LinkSpecType,\n\t\t},\n\t\t{\n\t\t\tnamespace: network.ConfigNamespaceName,\n\t\t\ttyp:       network.AddressSpecType,\n\t\t},\n\t\t{\n\t\t\tnamespace: network.ConfigNamespaceName,\n\t\t\ttyp:       network.RouteSpecType,\n\t\t},\n\t\t{\n\t\t\tnamespace: network.ConfigNamespaceName,\n\t\t\ttyp:       network.RoutingRuleSpecType,\n\t\t},\n\t\t{\n\t\t\tnamespace: network.NamespaceName,\n\t\t\ttyp:       network.NfTablesChainType,\n\t\t},\n\t\t{\n\t\t\tnamespace: kubespan.NamespaceName,\n\t\t\ttyp:       kubespan.PeerStatusType,\n\t\t},\n\t} {\n\t\t// list keys for cleanup\n\t\tlist, err := r.List(ctx, resource.NewMetadata(item.namespace, item.typ, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error cleaning up resource %s: %w\", res, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/manager_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage kubespan_test\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\tkubespanadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/kubespan\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubespanctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ManagerSuite struct {\n\tctest.DefaultSuite\n\n\tmockWireguard *mockWireguardClient\n}\n\nfunc (suite *ManagerSuite) TestDisabled() {\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = false\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tctest.AssertNoResource[*network.NfTablesChain](suite, \"kubespan_outgoing\")\n}\n\ntype mockWireguardClient struct {\n\tdeviceStateMu sync.Mutex\n\tdeviceState   *wgtypes.Device\n}\n\nfunc (mock *mockWireguardClient) update(newState *wgtypes.Device) {\n\tmock.deviceStateMu.Lock()\n\tdefer mock.deviceStateMu.Unlock()\n\n\tmock.deviceState = newState\n}\n\nfunc (mock *mockWireguardClient) Device(name string) (*wgtypes.Device, error) {\n\tmock.deviceStateMu.Lock()\n\tdefer mock.deviceStateMu.Unlock()\n\n\tif mock.deviceState != nil {\n\t\treturn mock.deviceState, nil\n\t}\n\n\treturn nil, os.ErrNotExist\n}\n\nfunc (mock *mockWireguardClient) Close() error {\n\treturn nil\n}\n\n//nolint:dupl\nfunc (suite *ManagerSuite) TestReconcile() {\n\tif fipsmode.Strict() {\n\t\tsuite.T().Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().SharedSecret = \"TPbGXrYlvuXgAl8dERpwjlA5tnEMoihPDPxlovcLtVg=\"\n\tcfg.TypedSpec().ForceRouting = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tmac, err := net.ParseMAC(\"ea:71:1b:b2:cc:ee\")\n\tsuite.Require().NoError(err)\n\n\tlocalIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity)\n\tsuite.Require().NoError(kubespanadapter.IdentitySpec(localIdentity.TypedSpec()).GenerateKey())\n\tsuite.Require().NoError(\n\t\tkubespanadapter.IdentitySpec(localIdentity.TypedSpec()).UpdateAddress(\n\t\t\t\"v16UCWpO2iOm82n6F8dGCJ41ZXXBvDrjRDs2su7C_zs=\",\n\t\t\tmac,\n\t\t),\n\t)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), localIdentity))\n\n\t// initial setup: link should be created without any peers\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),\n\t\tfunc(res *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(network.ConfigOperator, spec.ConfigLayer)\n\t\t\tasrt.Equal(constants.KubeSpanLinkName, spec.Name)\n\t\t\tasrt.Equal(nethelpers.LinkNone, spec.Type)\n\t\t\tasrt.Equal(\"wireguard\", spec.Kind)\n\t\t\tasrt.True(spec.Up)\n\t\t\tasrt.True(spec.Logical)\n\n\t\t\tasrt.Equal(localIdentity.TypedSpec().PrivateKey, spec.Wireguard.PrivateKey)\n\t\t\tasrt.Equal(constants.KubeSpanDefaultPort, spec.Wireguard.ListenPort)\n\t\t\tasrt.Equal(constants.KubeSpanDefaultFirewallMark, spec.Wireguard.FirewallMark)\n\t\t\tasrt.Len(spec.Wireguard.Peers, 0)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.AddressID(constants.KubeSpanLinkName, localIdentity.TypedSpec().Address),\n\t\t), func(res *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(localIdentity.TypedSpec().Address.Addr(), spec.Address.Addr())\n\t\t\tasrt.Equal(localIdentity.TypedSpec().Subnet.Bits(), spec.Address.Bits())\n\t\t\tasrt.Equal(network.ConfigOperator, spec.ConfigLayer)\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, spec.Family)\n\t\t\tasrt.Equal(nethelpers.AddressFlags(nethelpers.AddressPermanent), spec.Flags)\n\t\t\tasrt.Equal(constants.KubeSpanLinkName, spec.LinkName)\n\t\t\tasrt.Equal(nethelpers.ScopeGlobal, spec.Scope)\n\t\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RouteID(\n\t\t\t\tconstants.KubeSpanDefaultRoutingTable,\n\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\tnetip.Prefix{},\n\t\t\t\tnetip.Addr{},\n\t\t\t\t1,\n\t\t\t\t\"kubespan\",\n\t\t\t),\n\t\t),\n\t\tfunc(res *network.RouteSpec, asrt *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RouteID(\n\t\t\t\tconstants.KubeSpanDefaultRoutingTable,\n\t\t\t\tnethelpers.FamilyInet6,\n\t\t\t\tnetip.Prefix{},\n\t\t\t\tnetip.Addr{},\n\t\t\t\t1,\n\t\t\t\t\"kubespan\",\n\t\t\t),\n\t\t),\n\t\tfunc(res *network.RouteSpec, asrt *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// check routing rules (IPv4 + IPv6)\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RoutingRuleID(\n\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\tconstants.KubeSpanDefaultRulePriority,\n\t\t\t),\n\t\t),\n\t\tfunc(res *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, spec.Family)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable), spec.Table)\n\t\t\tasrt.Equal(nethelpers.RoutingRuleActionUnicast, spec.Action)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultForceFirewallMark), spec.FwMark)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultFirewallMask), spec.FwMask)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultRulePriority), spec.Priority)\n\t\t\tasrt.Equal(network.ConfigOperator, spec.ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RoutingRuleID(\n\t\t\t\tnethelpers.FamilyInet6,\n\t\t\t\tconstants.KubeSpanDefaultRulePriority,\n\t\t\t),\n\t\t),\n\t\tfunc(res *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, spec.Family)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(constants.KubeSpanDefaultRoutingTable), spec.Table)\n\t\t\tasrt.Equal(nethelpers.RoutingRuleActionUnicast, spec.Action)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultForceFirewallMark), spec.FwMark)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultFirewallMask), spec.FwMask)\n\t\t\tasrt.Equal(uint32(constants.KubeSpanDefaultRulePriority), spec.Priority)\n\t\t\tasrt.Equal(network.ConfigOperator, spec.ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// add two peers, they should be added to the wireguard link spec and should be tracked in peer statuses\n\tpeer1 := kubespan.NewPeerSpec(kubespan.NamespaceName, \"3FxU7UuwektMjbyuJBs7i1hDj2rQA6tHnbNB6WrQxww=\")\n\tpeer1.TypedSpec().Address = netip.MustParseAddr(\"fd8a:4396:731e:e702:145e:c4ff:fe41:1ef9\")\n\tpeer1.TypedSpec().Label = \"worker-1\"\n\tpeer1.TypedSpec().AllowedIPs = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.244.1.0/24\"),\n\t}\n\tpeer1.TypedSpec().Endpoints = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"172.20.0.3:51280\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), peer1))\n\n\tkey1, err := wgtypes.ParseKey(peer1.Metadata().ID())\n\tsuite.Require().NoError(err)\n\n\tpeer2 := kubespan.NewPeerSpec(kubespan.NamespaceName, \"tQuicRD0tqCu48M+zrySTe4slT15JxWhWIboZOB4tWs=\")\n\tpeer2.TypedSpec().Address = netip.MustParseAddr(\"fd8a:4396:731e:e702:9c83:cbff:fed0:f94b\")\n\tpeer2.TypedSpec().Label = \"worker-2\"\n\tpeer2.TypedSpec().AllowedIPs = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.244.2.0/24\"),\n\t}\n\tpeer2.TypedSpec().Endpoints = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"172.20.0.4:51280\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), peer2))\n\n\tkey2, err := wgtypes.ParseKey(peer2.Metadata().ID())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),\n\t\tfunc(res *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Len(spec.Wireguard.Peers, 2)\n\n\t\t\tif len(spec.Wireguard.Peers) != 2 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor i, peer := range []*kubespan.PeerSpec{peer1, peer2} {\n\t\t\t\tasrt.Equal(peer.Metadata().ID(), spec.Wireguard.Peers[i].PublicKey)\n\t\t\t\tasrt.Equal(cfg.TypedSpec().SharedSecret, spec.Wireguard.Peers[i].PresharedKey)\n\t\t\t\tasrt.Equal(peer.TypedSpec().AllowedIPs, spec.Wireguard.Peers[i].AllowedIPs)\n\t\t\t\tasrt.Equal(peer.TypedSpec().Endpoints[0].String(), spec.Wireguard.Peers[i].Endpoint)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tfor _, peer := range []*kubespan.PeerSpec{peer1, peer2} {\n\t\tctest.AssertResource(suite,\n\t\t\tpeer.Metadata().ID(),\n\t\t\tfunc(res *kubespan.PeerStatus, asrt *assert.Assertions) {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tasrt.Equal(peer.TypedSpec().Label, spec.Label)\n\t\t\t\tasrt.Equal(kubespan.PeerStateUnknown, spec.State)\n\t\t\t\tasrt.Equal(peer.TypedSpec().Endpoints[0], spec.Endpoint)\n\t\t\t\tasrt.Equal(peer.TypedSpec().Endpoints[0], spec.LastUsedEndpoint)\n\t\t\t\tasrt.WithinDuration(time.Now(), spec.LastEndpointChange, 3*time.Second)\n\t\t\t},\n\t\t)\n\t}\n\n\t// check firewall rules\n\tctest.AssertResource(suite,\n\t\t\"kubespan_prerouting\",\n\t\tfunc(res *network.NfTablesChain, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(nethelpers.ChainTypeFilter, spec.Type)\n\t\t\tasrt.Equal(nethelpers.ChainHookPrerouting, spec.Hook)\n\t\t\tasrt.Equal(nethelpers.ChainPriorityFilter, spec.Priority)\n\t\t\tasrt.Equal(nethelpers.VerdictAccept, spec.Policy)\n\n\t\t\tasrt.Len(spec.Rules, 2)\n\n\t\t\tif len(spec.Rules) != 2 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchMark: &network.NfTablesMark{\n\t\t\t\t\t\tMask:  constants.KubeSpanDefaultFirewallMask,\n\t\t\t\t\t\tValue: constants.KubeSpanDefaultFirewallMark,\n\t\t\t\t\t},\n\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tspec.Rules[0],\n\t\t\t)\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.244.1.0/24\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.244.2.0/24\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\t\t\tXor:  constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\t\t},\n\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tspec.Rules[1],\n\t\t\t)\n\t\t},\n\t)\n\n\t// update config and disable force routing, nothing should be routed\n\tcfg.TypedSpec().ForceRouting = false\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\tctest.AssertResource(suite,\n\t\t\"kubespan_prerouting\",\n\t\tfunc(res *network.NfTablesChain, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{},\n\t\t\t\t\t},\n\t\t\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\t\t\tXor:  constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\t\t},\n\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tspec.Rules[1],\n\t\t\t)\n\t\t},\n\t)\n\n\t// report up status via wireguard mock\n\tsuite.mockWireguard.update(\n\t\t&wgtypes.Device{\n\t\t\tPeers: []wgtypes.Peer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey:         key1,\n\t\t\t\t\tEndpoint:          asUDP(peer1.TypedSpec().Endpoints[0]),\n\t\t\t\t\tLastHandshakeTime: time.Now(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPublicKey:         key2,\n\t\t\t\t\tEndpoint:          asUDP(peer2.TypedSpec().Endpoints[0]),\n\t\t\t\t\tLastHandshakeTime: time.Now(),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\n\tfor _, peer := range []*kubespan.PeerSpec{peer1, peer2} {\n\t\tctest.AssertResource(suite,\n\t\t\tpeer.Metadata().ID(),\n\t\t\tfunc(res *kubespan.PeerStatus, asrt *assert.Assertions) {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tasrt.Equal(kubespan.PeerStateUp, spec.State)\n\t\t\t},\n\t\t)\n\t}\n\n\tctest.AssertResource(suite,\n\t\t\"kubespan_prerouting\",\n\t\tfunc(res *network.NfTablesChain, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.244.1.0/24\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.244.2.0/24\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\t\t\tXor:  constants.KubeSpanDefaultForceFirewallMark,\n\t\t\t\t\t},\n\t\t\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tspec.Rules[1],\n\t\t\t)\n\t\t},\n\t)\n\n\t// update config and disable wireguard, everything should be cleaned up\n\tcfg.TypedSpec().Enabled = false\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\tctest.AssertNoResource[*network.LinkSpec](\n\t\tsuite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\tctest.AssertNoResource[*network.NfTablesChain](\n\t\tsuite,\n\t\t\"kubespan_prerouting\",\n\t)\n\tctest.AssertNoResource[*network.RoutingRuleSpec](\n\t\tsuite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RoutingRuleID(\n\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\tconstants.KubeSpanDefaultRulePriority,\n\t\t\t),\n\t\t),\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\tctest.AssertNoResource[*network.RoutingRuleSpec](\n\t\tsuite,\n\t\tnetwork.LayeredID(\n\t\t\tnetwork.ConfigOperator,\n\t\t\tnetwork.RoutingRuleID(\n\t\t\t\tnethelpers.FamilyInet6,\n\t\t\t\tconstants.KubeSpanDefaultRulePriority,\n\t\t\t),\n\t\t),\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc asUDP(addr netip.AddrPort) *net.UDPAddr {\n\treturn &net.UDPAddr{\n\t\tIP:   addr.Addr().AsSlice(),\n\t\tPort: int(addr.Port()),\n\t\tZone: addr.Addr().Zone(),\n\t}\n}\n\nfunc TestManagerSuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tmockWireguard := &mockWireguardClient{}\n\n\tsuite.Run(t, &ManagerSuite{\n\t\tmockWireguard: mockWireguard,\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&kubespanctrl.ManagerController{\n\t\t\t\t\tWireguardClientFactory: func() (kubespanctrl.WireguardClient, error) {\n\t\t\t\t\t\treturn mockWireguard, nil\n\t\t\t\t\t},\n\t\t\t\t\tPeerReconcileInterval: time.Second,\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/peer_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\t\"go4.org/netipx\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\n// PeerSpecController watches cluster.Affiliates updates PeerSpec.\ntype PeerSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PeerSpecController) Name() string {\n\treturn \"kubespan.PeerSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PeerSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      kubespan.ConfigType,\n\t\t\tID:        optional.Some(kubespan.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.AffiliateType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PeerSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: kubespan.PeerSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *PeerSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*kubespan.Config](ctx, r, kubespan.ConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting kubespan configuration: %w\", err)\n\t\t}\n\n\t\tlocalIdentity, err := safe.ReaderGetByID[*cluster.Identity](ctx, r, cluster.LocalIdentity)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting first MAC address: %w\", err)\n\t\t}\n\n\t\taffiliates, err := safe.ReaderListAll[*cluster.Affiliate](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing cluster affiliates: %w\", err)\n\t\t}\n\n\t\ttouchedIDs := map[resource.ID]struct{}{}\n\n\t\tif cfg != nil && localIdentity != nil && cfg.TypedSpec().Enabled {\n\t\t\tlocalAffiliateID := localIdentity.TypedSpec().NodeID\n\n\t\t\tpeerIPSets := make(map[string]*netipx.IPSet, affiliates.Len())\n\n\t\taffiliateLoop:\n\t\t\tfor affiliate := range affiliates.All() {\n\t\t\t\tif affiliate.Metadata().ID() == localAffiliateID {\n\t\t\t\t\t// skip local affiliate, it's not a peer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tspec := affiliate.TypedSpec()\n\n\t\t\t\tif spec.KubeSpan.PublicKey == \"\" {\n\t\t\t\t\t// no kubespan information, skip it\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar builder netipx.IPSetBuilder\n\n\t\t\t\tfor _, ipPrefix := range spec.KubeSpan.AdditionalAddresses {\n\t\t\t\t\tbuilder.AddPrefix(ipPrefix)\n\t\t\t\t}\n\n\t\t\t\tfor _, ip := range spec.Addresses {\n\t\t\t\t\tbuilder.Add(ip)\n\t\t\t\t}\n\n\t\t\t\tfor _, ipPrefix := range spec.KubeSpan.ExcludeAdvertisedNetworks {\n\t\t\t\t\tbuilder.RemovePrefix(ipPrefix)\n\t\t\t\t}\n\n\t\t\t\tbuilder.Add(spec.KubeSpan.Address)\n\n\t\t\t\tvar ipSet *netipx.IPSet\n\n\t\t\t\tipSet, err = builder.IPSet()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Warn(\"failed building list of IP ranges for the peer\", zap.String(\"ignored_peer\", spec.KubeSpan.PublicKey), zap.String(\"label\", spec.Nodename), zap.Error(err))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfor otherPublicKey, otherIPSet := range peerIPSets {\n\t\t\t\t\tif otherIPSet.Overlaps(ipSet) {\n\t\t\t\t\t\tlogger.Warn(\"peer address overlap\", zap.String(\"this_peer\", spec.KubeSpan.PublicKey), zap.String(\"other_peer\", otherPublicKey),\n\t\t\t\t\t\t\tzap.Strings(\"this_ips\", dumpSet(ipSet)), zap.Strings(\"other_ips\", dumpSet(otherIPSet)))\n\n\t\t\t\t\t\t// exclude overlapping IPs from the ipSet\n\t\t\t\t\t\tvar bldr netipx.IPSetBuilder\n\n\t\t\t\t\t\t// ipSet = ipSet & ~otherIPSet\n\t\t\t\t\t\tbldr.AddSet(otherIPSet)\n\t\t\t\t\t\tbldr.Complement()\n\t\t\t\t\t\tbldr.Intersect(ipSet)\n\n\t\t\t\t\t\tipSet, err = bldr.IPSet()\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tlogger.Warn(\"failed building list of IP ranges for the peer\", zap.String(\"ignored_peer\", spec.KubeSpan.PublicKey), zap.String(\"label\", spec.Nodename), zap.Error(err))\n\n\t\t\t\t\t\t\tcontinue affiliateLoop\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif len(ipSet.Ranges()) == 0 {\n\t\t\t\t\t\t\tlogger.Warn(\"conflict resolution removed all ranges\", zap.String(\"this_peer\", spec.KubeSpan.PublicKey), zap.String(\"other_peer\", otherPublicKey))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tpeerIPSets[spec.KubeSpan.PublicKey] = ipSet\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, kubespan.NewPeerSpec(kubespan.NamespaceName, spec.KubeSpan.PublicKey), func(res *kubespan.PeerSpec) error {\n\t\t\t\t\t*res.TypedSpec() = kubespan.PeerSpecSpec{\n\t\t\t\t\t\tAddress:    spec.KubeSpan.Address,\n\t\t\t\t\t\tAllowedIPs: ipSet.Prefixes(),\n\t\t\t\t\t\tEndpoints:  slices.Clone(spec.KubeSpan.Endpoints),\n\t\t\t\t\t\tLabel:      spec.Nodename,\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\ttouchedIDs[spec.KubeSpan.PublicKey] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\t// list keys for cleanup\n\t\tlist, err := safe.ReaderListAll[*kubespan.PeerSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// dumpSet converts IPSet to a form suitable for logging.\nfunc dumpSet(set *netipx.IPSet) []string {\n\treturn xslices.Map(set.Ranges(), netipx.IPRange.String)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/kubespan/peer_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage kubespan_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\tclusteradapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tkubespanctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\ntype PeerSpecSuite struct {\n\tctest.DefaultSuite\n\n\tstatePath string\n}\n\nfunc (suite *PeerSpecSuite) TestReconcile() {\n\tsuite.statePath = suite.T().TempDir()\n\n\tstateMount := runtimeres.NewMountStatus(v1alpha1.NamespaceName, constants.StatePartitionLabel)\n\tsuite.Create(stateMount)\n\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tsuite.Create(cfg)\n\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Create(nodeIdentity)\n\n\taffiliate1 := cluster.NewAffiliate(cluster.NamespaceName, \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate1.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tHostname:    \"foo.com\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\"), netip.MustParsePrefix(\"10.244.3.0/32\")},\n\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"10.244.3.128/25\")},\n\t\t},\n\t}\n\n\taffiliate2 := cluster.NewAffiliate(cluster.NamespaceName, \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\")\n\t*affiliate2.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tHostname:    \"worker-1\",\n\t\tNodename:    \"worker-1\",\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.5\")},\n\t}\n\n\taffiliate3 := cluster.NewAffiliate(cluster.NamespaceName, \"xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\")\n\t*affiliate3.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"xCnFFfxylOf9i5ynhAkt6ZbfcqaLDGKfIa3gwpuaxe7F\",\n\t\tMachineType: machine.TypeWorker,\n\t\tNodename:    \"worker-2\",\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.6\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"mB6WlFOR66Jx5rtPMIpxJ3s4XHyer9NCzqWPP7idGRo\",\n\t\t\tAddress:             netip.MustParseAddr(\"fdc8:8aee:4e2d:1202:f073:9cff:fe6c:4d67\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.4.1/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.6:51820\")},\n\t\t},\n\t}\n\n\t// local node affiliate, should be skipped as a peer\n\taffiliate4 := cluster.NewAffiliate(cluster.NamespaceName, nodeIdentity.TypedSpec().NodeID)\n\t*affiliate4.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      nodeIdentity.TypedSpec().NodeID,\n\t\tMachineType: machine.TypeWorker,\n\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.7\")},\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"27E8I+ekrqT21cq2iW6+fDe+H7WBw6q9J7vqLCeswiM=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fdc8:8aee:4e2d:1202:f073:9cff:fe6c:4d67\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.5.1/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.7:51820\")},\n\t\t},\n\t}\n\n\tfor _, r := range []resource.Resource{affiliate1, affiliate2, affiliate3, affiliate4} {\n\t\tsuite.Create(r)\n\t}\n\n\t// affiliate2 shouldn't be rendered as a peer, as it doesn't have kubespan data\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\n\t\t\taffiliate1.TypedSpec().KubeSpan.PublicKey,\n\t\t\taffiliate3.TypedSpec().KubeSpan.PublicKey,\n\t\t},\n\t\tfunc(*kubespan.PeerSpec, *assert.Assertions) {},\n\t)\n\tctest.AssertNoResource[*kubespan.PeerSpec](suite, affiliate2.TypedSpec().KubeSpan.PublicKey)\n\n\tctest.AssertResource(suite,\n\t\taffiliate1.TypedSpec().KubeSpan.PublicKey,\n\t\tfunc(res *kubespan.PeerSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\", spec.Address.String())\n\t\t\tasrt.Equal(\"[10.244.3.0/25 192.168.3.4/32 fd50:8d60:4238:6302:f857:23ff:fe21:d1e0/128]\", fmt.Sprintf(\"%v\", spec.AllowedIPs))\n\t\t\tasrt.Equal([]netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")}, spec.Endpoints)\n\t\t\tasrt.Equal(\"bar\", spec.Label)\n\t\t},\n\t)\n\n\tctest.AssertResource(suite,\n\t\taffiliate3.TypedSpec().KubeSpan.PublicKey,\n\t\tfunc(res *kubespan.PeerSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(\"fdc8:8aee:4e2d:1202:f073:9cff:fe6c:4d67\", spec.Address.String())\n\t\t\tasrt.Equal(\"[10.244.4.0/24 192.168.3.6/32 fdc8:8aee:4e2d:1202:f073:9cff:fe6c:4d67/128]\", fmt.Sprintf(\"%v\", spec.AllowedIPs))\n\t\t\tasrt.Equal([]netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.6:51820\")}, spec.Endpoints)\n\t\t\tasrt.Equal(\"worker-2\", spec.Label)\n\t\t},\n\t)\n\n\t// disabling kubespan should remove all peers\n\tcfg.TypedSpec().Enabled = false\n\tsuite.Update(cfg)\n\n\tctest.AssertNoResource[*kubespan.PeerSpec](suite, affiliate1.TypedSpec().KubeSpan.PublicKey)\n\tctest.AssertNoResource[*kubespan.PeerSpec](suite, affiliate2.TypedSpec().KubeSpan.PublicKey)\n}\n\nfunc (suite *PeerSpecSuite) TestIPOverlap() {\n\tsuite.statePath = suite.T().TempDir()\n\n\tstateMount := runtimeres.NewMountStatus(v1alpha1.NamespaceName, constants.StatePartitionLabel)\n\tsuite.Create(stateMount)\n\n\tcfg := kubespan.NewConfig(config.NamespaceName, kubespan.ConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tsuite.Create(cfg)\n\n\tnodeIdentity := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tsuite.Require().NoError(clusteradapter.IdentitySpec(nodeIdentity.TypedSpec()).Generate())\n\tsuite.Create(nodeIdentity)\n\n\taffiliate1 := cluster.NewAffiliate(cluster.NamespaceName, \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\")\n\t*affiliate1.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tNodename:    \"bar\",\n\t\tMachineType: machine.TypeControlPlane,\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\"), netip.MustParsePrefix(\"10.244.3.0/32\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t},\n\t}\n\n\taffiliate2 := cluster.NewAffiliate(cluster.NamespaceName, \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\")\n\t*affiliate2.TypedSpec() = cluster.AffiliateSpec{\n\t\tNodeID:      \"9dwHNUViZlPlIervqX9Qo256RUhrfhgO0xBBnKcKl4F\",\n\t\tHostname:    \"worker-1\",\n\t\tNodename:    \"worker-1\",\n\t\tMachineType: machine.TypeWorker,\n\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\tPublicKey:           \"Zr5ewpUm2Ywo1c+/59WFKIBjZ3c/nVbIWsT5elbjwCU=\",\n\t\t\tAddress:             netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1\"),\n\t\t\tAdditionalAddresses: []netip.Prefix{netip.MustParsePrefix(\"10.244.2.0/23\"), netip.MustParsePrefix(\"192.168.3.0/24\")},\n\t\t\tEndpoints:           []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t},\n\t}\n\n\tfor _, r := range []resource.Resource{affiliate1, affiliate2} {\n\t\tsuite.Create(r)\n\t}\n\n\t// affiliate2 should be rendered as a peer, but with reduced address as its AdditionalAddresses overlap with affiliate1 addresses\n\tctest.AssertResource(suite,\n\t\taffiliate1.TypedSpec().KubeSpan.PublicKey,\n\t\tfunc(res *kubespan.PeerSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(`[\"10.244.3.0/24\" \"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0/128\"]`, fmt.Sprintf(\"%q\", spec.AllowedIPs))\n\t\t},\n\t)\n\n\tctest.AssertResource(suite,\n\t\taffiliate2.TypedSpec().KubeSpan.PublicKey,\n\t\tfunc(res *kubespan.PeerSpec, asrt *assert.Assertions) {\n\t\t\tspec := res.TypedSpec()\n\n\t\t\tasrt.Equal(`[\"10.244.2.0/24\" \"192.168.3.0/24\" \"fd50:8d60:4238:6302:f857:23ff:fe21:d1e1/128\"]`, fmt.Sprintf(\"%q\", spec.AllowedIPs))\n\t\t},\n\t)\n}\n\nfunc TestPeerSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &PeerSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&kubespanctrl.PeerSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tcfg \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// AddressConfigController manages network.AddressSpec based on machine configuration, kernel cmdline and some built-in defaults.\ntype AddressConfigController struct {\n\tCmdline      *procfs.Cmdline\n\tV1Alpha1Mode runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AddressConfigController) Name() string {\n\treturn \"network.AddressConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AddressConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.DeviceConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AddressConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *AddressConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\t// apply defaults for the loopback interface\n\t\tif err := ctrl.apply(ctx, r, ctrl.loopbackDefaults()); err != nil {\n\t\t\treturn fmt.Errorf(\"error generating loopback interface defaults: %w\", err)\n\t\t}\n\n\t\tdevices, err := safe.ReaderListAll[*network.DeviceConfigSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tignoredInterfaces := map[string]struct{}{}\n\n\t\tfor device := range devices.All() {\n\t\t\tif device.TypedSpec().Device.Ignore() {\n\t\t\t\tignoredInterfaces[device.TypedSpec().Device.Interface()] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\t// parse kernel cmdline for the address\n\t\tcmdlineAddresses := ctrl.parseCmdline(logger)\n\t\tfor _, cmdlineAddress := range cmdlineAddresses {\n\t\t\tif _, ignored := ignoredInterfaces[cmdlineAddress.LinkName]; !ignored {\n\t\t\t\tif err = ctrl.apply(ctx, r, []network.AddressSpecSpec{cmdlineAddress}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error applying cmdline address: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse machine configuration for static addresses (legacy first)\n\t\tif devices.Len() > 0 {\n\t\t\taddresses := ctrl.processDevicesConfiguration(logger, devices)\n\n\t\t\tif err = ctrl.apply(ctx, r, addresses); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying machine configuration address: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error reading machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif cfg != nil {\n\t\t\tif err = ctrl.apply(ctx, r, ctrl.processMachineConfig(cfg.Config().NetworkCommonLinkConfigs())); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying machine configuration addresses: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.AddressSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error during cleanup: %w\", err)\n\t\t}\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *AddressConfigController) apply(ctx context.Context, r controller.Runtime, addresses []network.AddressSpecSpec) error {\n\tfor _, address := range addresses {\n\t\tid := network.LayeredID(address.ConfigLayer, network.AddressID(address.LinkName, address.Address))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewAddressSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.AddressSpec) error {\n\t\t\t\t*r.TypedSpec() = address\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *AddressConfigController) loopbackDefaults() []network.AddressSpecSpec {\n\tif ctrl.V1Alpha1Mode == runtime.ModeContainer {\n\t\t// skip configuring lo addresses in container mode\n\t\treturn nil\n\t}\n\n\treturn []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:     netip.PrefixFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 8),\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tScope:       nethelpers.ScopeHost,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tLinkName:    \"lo\",\n\t\t\tConfigLayer: network.ConfigDefault,\n\t\t},\n\t}\n}\n\nfunc (ctrl *AddressConfigController) parseCmdline(logger *zap.Logger) (addresses []network.AddressSpecSpec) {\n\tif ctrl.Cmdline == nil {\n\t\treturn addresses\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, network.NewEmptyLinkResolver())\n\tif err != nil {\n\t\tlogger.Info(\"ignoring cmdline parse failure\", zap.Error(err))\n\n\t\treturn addresses\n\t}\n\n\tfor _, linkConfig := range settings.LinkConfigs {\n\t\tif value.IsZero(linkConfig.Address) {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar address network.AddressSpecSpec\n\n\t\taddress.Address = linkConfig.Address\n\t\tif address.Address.Addr().Is6() {\n\t\t\taddress.Family = nethelpers.FamilyInet6\n\t\t} else {\n\t\t\taddress.Family = nethelpers.FamilyInet4\n\t\t}\n\n\t\taddress.Scope = nethelpers.ScopeGlobal\n\t\taddress.Flags = nethelpers.AddressFlags(nethelpers.AddressPermanent)\n\t\taddress.ConfigLayer = network.ConfigCmdline\n\t\taddress.LinkName = linkConfig.LinkName\n\n\t\taddresses = append(addresses, address)\n\t}\n\n\treturn addresses\n}\n\nfunc parseIPOrIPPrefix(address string) (netip.Prefix, error) {\n\tif strings.IndexByte(address, '/') >= 0 {\n\t\treturn netip.ParsePrefix(address)\n\t}\n\n\t// parse as IP address and assume netmask of all ones\n\tip, err := netip.ParseAddr(address)\n\tif err != nil {\n\t\treturn netip.Prefix{}, err\n\t}\n\n\treturn netip.PrefixFrom(ip, ip.BitLen()), nil\n}\n\nfunc (ctrl *AddressConfigController) processDevicesConfiguration(logger *zap.Logger, devices safe.List[*network.DeviceConfigSpec]) (addresses []network.AddressSpecSpec) {\n\tfor item := range devices.All() {\n\t\tdevice := item.TypedSpec().Device\n\n\t\tif device.Ignore() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, cidr := range device.Addresses() {\n\t\t\tipPrefix, err := parseIPOrIPPrefix(cidr)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Info(fmt.Sprintf(\"skipping address %q on interface %q\", cidr, device.Interface()), zap.Error(err))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\taddress := network.AddressSpecSpec{\n\t\t\t\tAddress:     ipPrefix,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tLinkName:    device.Interface(),\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t}\n\n\t\t\tif address.Address.Addr().Is6() {\n\t\t\t\taddress.Family = nethelpers.FamilyInet6\n\t\t\t} else {\n\t\t\t\taddress.Family = nethelpers.FamilyInet4\n\t\t\t}\n\n\t\t\taddresses = append(addresses, address)\n\t\t}\n\n\t\tfor _, vlan := range device.Vlans() {\n\t\t\tfor _, cidr := range vlan.Addresses() {\n\t\t\t\tipPrefix, err := netip.ParsePrefix(cidr)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Info(fmt.Sprintf(\"skipping address %q on interface %q vlan %d\", cidr, device.Interface(), vlan.ID()), zap.Error(err))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taddress := network.AddressSpecSpec{\n\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tLinkName:    nethelpers.VLANLinkName(device.Interface(), vlan.ID()),\n\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t}\n\n\t\t\t\tif address.Address.Addr().Is6() {\n\t\t\t\t\taddress.Family = nethelpers.FamilyInet6\n\t\t\t\t} else {\n\t\t\t\t\taddress.Family = nethelpers.FamilyInet4\n\t\t\t\t}\n\n\t\t\t\taddresses = append(addresses, address)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn addresses\n}\n\nfunc (ctrl *AddressConfigController) processMachineConfig(linkConfigs []cfg.NetworkCommonLinkConfig) (addresses []network.AddressSpecSpec) {\n\tfor _, linkConfig := range linkConfigs {\n\t\tfor _, addr := range linkConfig.Addresses() {\n\t\t\taddress := network.AddressSpecSpec{\n\t\t\t\tAddress:     addr.Address(),\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tLinkName:    linkConfig.Name(),\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\tPriority:    addr.RoutePriority().ValueOrZero(),\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t}\n\n\t\t\tif address.Address.Addr().Is6() {\n\t\t\t\taddress.Family = nethelpers.FamilyInet6\n\t\t\t} else {\n\t\t\t\taddress.Family = nethelpers.FamilyInet4\n\t\t\t}\n\n\t\t\taddresses = append(addresses, address)\n\t\t}\n\t}\n\n\treturn addresses\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype AddressConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *AddressConfigSuite) TestLoopback() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressConfigController{}))\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"default/lo/127.0.0.1/8\",\n\t\tfunc(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"lo\", r.TypedSpec().LinkName)\n\t\t\tasrt.Equal(nethelpers.ScopeHost, r.TypedSpec().Scope)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *AddressConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.AddressConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1::::: ip=eth3:dhcp ip=10.3.5.7::10.3.5.1:255.255.255.0::eth4\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"cmdline/eth1/172.20.0.2/24\",\n\t\t\t\"cmdline/eth4/10.3.5.7/24\",\n\t\t}, func(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"cmdline/eth1/172.20.0.2/24\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().LinkName)\n\t\t\tcase \"cmdline/eth4/10.3.5.7/24\":\n\t\t\t\tasrt.Equal(\"eth4\", r.TypedSpec().LinkName)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *AddressConfigSuite) TestCmdlineNoNetmask() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.AddressConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tifaces, _ := net.Interfaces() //nolint:errcheck // ignoring error here as ifaces will be empty\n\n\tslices.SortFunc(ifaces, func(a, b net.Interface) int { return cmp.Compare(a.Name, b.Name) })\n\n\tifaceName := \"\"\n\n\tfor _, iface := range ifaces {\n\t\tif iface.Flags&net.FlagLoopback != 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tifaceName = iface.Name\n\n\t\tbreak\n\t}\n\n\tsuite.Assert().NotEmpty(ifaceName)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\tfmt.Sprintf(\"cmdline/%s/172.20.0.2/32\", ifaceName),\n\t\tfunc(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(ifaceName, r.TypedSpec().LinkName)\n\t\t\tasrt.Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *AddressConfigSuite) TestMachineConfigurationLegacy() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressConfigController{}))\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth3\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"192.168.0.24/28\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth4\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"192.168.0.24/28\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth5\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"10.5.0.7\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth6\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\n\t\t\t\t\t\t\t\t\t\"10.5.0.8\",\n\t\t\t\t\t\t\t\t\t\"2001:470:6d:30e:8ed2:b60c:9d2f:803b/64\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:   24,\n\t\t\t\t\t\t\t\t\t\tVlanCIDR: \"10.0.0.1/8\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 25,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"11.0.0.1/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/eth2/2001:470:6d:30e:8ed2:b60c:9d2f:803a/64\",\n\t\t\t\"configuration/eth3/192.168.0.24/28\",\n\t\t\t\"configuration/eth5/10.5.0.7/32\",\n\t\t\t\"configuration/eth6/10.5.0.8/32\",\n\t\t\t\"configuration/eth6/2001:470:6d:30e:8ed2:b60c:9d2f:803b/64\",\n\t\t\t\"configuration/eth0.24/10.0.0.1/8\",\n\t\t\t\"configuration/eth0.25/11.0.0.1/8\",\n\t\t},\n\t\tfunc(r *network.AddressSpec, asrt *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *AddressConfigSuite) TestMachineConfiguration() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressConfigController{}))\n\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkAddresses = []networkcfg.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"10.12.3.4/24\"),\n\t\t},\n\t}\n\n\tlc2 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s3\")\n\tlc2.LinkAddresses = []networkcfg.AddressConfig{\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"172.20.0.1/20\"),\n\t\t\tAddressPriority: new(uint32(100)),\n\t\t},\n\t}\n\n\tctr, err := container.New(lc1, lc2)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/enp0s2/10.12.3.4/24\",\n\t\t\t\"configuration/enp0s3/172.20.0.1/20\",\n\t\t},\n\t\tfunc(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tif r.Metadata().ID() == \"configuration/enp0s3/172.20.0.1/20\" {\n\t\t\t\tasrt.Equal(uint32(100), r.TypedSpec().Priority)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc TestAddressConfigSuite(t *testing.T) {\n\tsuite.Run(t, &AddressConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_event.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// AddressEventController reports aggregated enpoints state from hostname statuses and k8s endpoints\n// to the events stream.\ntype AddressEventController struct {\n\tV1Alpha1Events runtime.Publisher\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AddressEventController) Name() string {\n\treturn \"network.AddressEventController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AddressEventController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tKind:      controller.InputWeak,\n\t\t\tID: optional.Some(network.FilteredNodeAddressID(\n\t\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\t\tk8s.NodeAddressFilterNoK8s)),\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AddressEventController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *AddressEventController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tticker := time.NewTicker(time.Minute * 10)\n\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar addresses []string\n\n\t\tnodeAddr, err := safe.ReaderGet[*network.NodeAddress](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.NodeAddressType,\n\t\t\t\tnetwork.FilteredNodeAddressID(\n\t\t\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\t\t\tk8s.NodeAddressFilterNoK8s),\n\t\t\t\tresource.VersionUndefined),\n\t\t)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tfor _, addr := range nodeAddr.TypedSpec().Addresses {\n\t\t\t\taddresses = append(\n\t\t\t\t\taddresses,\n\t\t\t\t\taddr.Addr().String(),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tvar hostname string\n\n\t\thostnameStatus, err := safe.ReaderGet[*network.HostnameStatus](ctx, r, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\thostname = hostnameStatus.TypedSpec().Hostname\n\t\t}\n\n\t\tctrl.V1Alpha1Events.Publish(ctx, &machine.AddressEvent{\n\t\t\tHostname:  hostname,\n\t\t\tAddresses: addresses,\n\t\t})\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_event_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/netip\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\tnetworkresource \"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype mockEventsStream struct {\n\tmessagesMu sync.Mutex\n\tmessages   []proto.Message\n}\n\nfunc (s *mockEventsStream) Publish(_ context.Context, m proto.Message) {\n\ts.messagesMu.Lock()\n\tdefer s.messagesMu.Unlock()\n\n\ts.messages = append(s.messages, m)\n}\n\ntype AddressEventsSuite struct {\n\tsuite.Suite\n\n\tevents *mockEventsStream\n\tstate  state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *AddressEventsSuite) SetupTest() {\n\tsuite.events = &mockEventsStream{\n\t\tmessages: []proto.Message{},\n\t}\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&network.AddressEventController{\n\t\t\t\tV1Alpha1Events: suite.events,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *AddressEventsSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *AddressEventsSuite) TestReconcile() {\n\thostname := networkresource.NewHostnameStatus(networkresource.NamespaceName, networkresource.HostnameID)\n\thostname.TypedSpec().Hostname = \"localhost\"\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, hostname))\n\n\tvar event *machine.AddressEvent\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tsuite.events.messagesMu.Lock()\n\t\t\t\tdefer suite.events.messagesMu.Unlock()\n\n\t\t\t\tif len(suite.events.messages) == 0 {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"no events created\")\n\t\t\t\t}\n\n\t\t\t\tm := suite.events.messages[len(suite.events.messages)-1]\n\n\t\t\t\tvar ok bool\n\n\t\t\t\tevent, ok = m.(*machine.AddressEvent)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn errors.New(\"not an endpoint event\")\n\t\t\t\t}\n\n\t\t\t\tif event.Hostname == \"\" {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"expected hostname to be set\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().Equal(hostname.TypedSpec().Hostname, event.Hostname)\n\tsuite.Require().Empty(event.Addresses)\n\n\tnodeAddress := networkresource.NewNodeAddress(\n\t\tnetworkresource.NamespaceName, networkresource.FilteredNodeAddressID(\n\t\t\tnetworkresource.NodeAddressCurrentID,\n\t\t\tk8s.NodeAddressFilterNoK8s,\n\t\t),\n\t)\n\n\taddrs := []string{\n\t\t\"10.5.0.2\",\n\t\t\"127.0.0.2\",\n\t}\n\n\tnodeAddress.TypedSpec().Addresses = append(\n\t\tnodeAddress.TypedSpec().Addresses,\n\t\tnetip.PrefixFrom(netip.MustParseAddr(addrs[0]), 32),\n\t\tnetip.PrefixFrom(netip.MustParseAddr(addrs[1]), 32),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, nodeAddress))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tsuite.events.messagesMu.Lock()\n\t\t\t\tdefer suite.events.messagesMu.Unlock()\n\n\t\t\t\tif len(suite.events.messages) == 0 {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"no events created\")\n\t\t\t\t}\n\n\t\t\t\tm := suite.events.messages[len(suite.events.messages)-1]\n\n\t\t\t\tvar ok bool\n\n\t\t\t\tevent, ok = m.(*machine.AddressEvent)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn errors.New(\"not an address event\")\n\t\t\t\t}\n\n\t\t\t\tif len(event.Addresses) == 0 {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"expected addresses to be set\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().Equal(addrs, event.Addresses)\n}\n\nfunc (suite *AddressEventsSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestAddressEventsSuite(t *testing.T) {\n\tsuite.Run(t, new(AddressEventsSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewAddressMergeController initializes a AddressMergeController.\n//\n// AddressMergeController merges network.AddressSpec in network.ConfigNamespace and produces final network.AddressSpec in network.Namespace.\nfunc NewAddressMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.AddressSpec]) map[resource.ID]*network.AddressSpecSpec {\n\t\t\t// address is allowed as long as it's not duplicate, for duplicate higher layer takes precedence\n\t\t\taddresses := map[resource.ID]*network.AddressSpecSpec{}\n\n\t\t\tfor address := range list.All() {\n\t\t\t\tid := network.AddressID(address.TypedSpec().LinkName, address.TypedSpec().Address)\n\n\t\t\t\texisting, ok := addresses[id]\n\t\t\t\tif ok && existing.ConfigLayer > address.TypedSpec().ConfigLayer {\n\t\t\t\t\t// skip this address, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\taddresses[id] = address.TypedSpec()\n\t\t\t}\n\n\t\t\treturn addresses\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype AddressMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *AddressMergeSuite) assertAddresses(requiredIDs []string, check func(*network.AddressSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *AddressMergeSuite) assertNoAddress(id string) {\n\tctest.AssertNoResource[*network.AddressSpec](suite, id)\n}\n\nfunc (suite *AddressMergeSuite) TestMerge() {\n\tloopback := network.NewAddressSpec(network.ConfigNamespaceName, \"default/lo/127.0.0.1/8\")\n\t*loopback.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"127.0.0.1/8\"),\n\t\tLinkName:    \"lo\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeHost,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp := network.NewAddressSpec(network.ConfigNamespaceName, \"dhcp/eth0/10.0.0.1/8\")\n\t*dhcp.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.1/8\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewAddressSpec(network.ConfigNamespaceName, \"configuration/eth0/10.0.0.35/32\")\n\t*static.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.35/32\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\toverride := network.NewAddressSpec(network.ConfigNamespaceName, \"configuration/eth0/10.0.0.1/8\")\n\t*override.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.1/8\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeHost,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{loopback, dhcp, static, override} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertAddresses(\n\t\t[]string{\n\t\t\t\"lo/127.0.0.1/8\",\n\t\t\t\"eth0/10.0.0.1/8\",\n\t\t\t\"eth0/10.0.0.35/32\",\n\t\t}, func(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"lo/127.0.0.1/8\":\n\t\t\t\tasrt.Equal(*loopback.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"eth0/10.0.0.1/8\":\n\t\t\t\tasrt.Equal(*override.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"eth0/10.0.0.35/32\":\n\t\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertAddresses(\n\t\t[]string{\n\t\t\t\"lo/127.0.0.1/8\",\n\t\t\t\"eth0/10.0.0.1/8\",\n\t\t}, func(*network.AddressSpec, *assert.Assertions) {},\n\t)\n\n\tsuite.assertNoAddress(\"eth0/10.0.0.35/32\")\n}\n\nfunc (suite *AddressMergeSuite) TestMergeFlapping() {\n\t// simulate two conflicting address definitions which are getting removed/added constantly\n\tdhcp := network.NewAddressSpec(network.ConfigNamespaceName, \"dhcp/eth0/10.0.0.1/8\")\n\t*dhcp.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.1/8\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\toverride := network.NewAddressSpec(network.ConfigNamespaceName, \"configuration/eth0/10.0.0.1/8\")\n\t*override.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.1/8\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeHost,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\ttestMergeFlapping(&suite.DefaultSuite, []*network.AddressSpec{dhcp, override}, \"eth0/10.0.0.1/8\", override)\n}\n\nfunc TestAddressMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &AddressMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewAddressMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/mdlayher/arp\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// AddressSpecController applies network.AddressSpec to the actual interfaces.\ntype AddressSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AddressSpecController) Name() string {\n\treturn \"network.AddressSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AddressSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.AddressSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AddressSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *AddressSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// watch link changes as some address might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := safe.ReaderList[*network.AddressSpec](ctx, r, resource.NewMetadata(network.NamespaceName, network.AddressSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network addresses: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// list rtnetlink links (interfaces)\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\t// list rtnetlink addresses\n\t\taddrs, err := conn.Address.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing addresses: %w\", err)\n\t\t}\n\n\t\t// loop over addresses and make reconcile decision\n\t\tfor address := range list.All() {\n\t\t\tif err = ctrl.syncAddress(ctx, r, logger, conn, links, addrs, address); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc resolveLinkName(links []rtnetlink.LinkMessage, linkName string) uint32 {\n\tif linkName == \"\" {\n\t\treturn 0 // should never match\n\t}\n\n\t// first, lookup by name\n\tfor _, link := range links {\n\t\tif link.Attributes.Name == linkName {\n\t\t\treturn link.Index\n\t\t}\n\t}\n\n\t// then, lookup by alias/altname\n\tfor _, link := range links {\n\t\tif pointer.SafeDeref(link.Attributes.Alias) == linkName {\n\t\t\treturn link.Index\n\t\t}\n\n\t\tif slices.Index(link.Attributes.AltNames, linkName) != -1 {\n\t\t\treturn link.Index\n\t\t}\n\t}\n\n\treturn 0\n}\n\nfunc findAddress(addrs []rtnetlink.AddressMessage, linkIndex uint32, ipPrefix netip.Prefix) *rtnetlink.AddressMessage {\n\tfor i, addr := range addrs {\n\t\tif addr.Index != linkIndex {\n\t\t\tcontinue\n\t\t}\n\n\t\tif int(addr.PrefixLength) != ipPrefix.Bits() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !addr.Attributes.Address.Equal(ipPrefix.Addr().AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn &addrs[i]\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn,\n\tlinks []rtnetlink.LinkMessage, addrs []rtnetlink.AddressMessage, address *network.AddressSpec,\n) error {\n\tlinkIndex := resolveLinkName(links, address.TypedSpec().LinkName)\n\n\tswitch address.Metadata().Phase() {\n\tcase resource.PhaseTearingDown:\n\t\tif linkIndex == 0 {\n\t\t\t// address should be deleted, but link is gone, so assume address is gone\n\t\t\tif err := r.RemoveFinalizer(ctx, address.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif existing := findAddress(addrs, linkIndex, address.TypedSpec().Address); existing != nil {\n\t\t\t// delete address\n\t\t\tif err := conn.Address.Delete(existing); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing address: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Sugar().Infof(\"removed address %s from %q\", address.TypedSpec().Address, address.TypedSpec().LinkName)\n\t\t}\n\n\t\t// now remove finalizer as address was deleted\n\t\tif err := r.RemoveFinalizer(ctx, address.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t}\n\tcase resource.PhaseRunning:\n\t\tif linkIndex == 0 {\n\t\t\t// address can't be assigned as link doesn't exist (yet), skip it\n\t\t\treturn nil\n\t\t}\n\n\t\tif existing := findAddress(addrs, linkIndex, address.TypedSpec().Address); existing != nil {\n\t\t\t// clear out tentative flag, it is set by the kernel, we shouldn't try to enforce it\n\t\t\texisting.Flags &= ^uint8(nethelpers.AddressTentative)\n\t\t\texisting.Attributes.Flags &= ^uint32(nethelpers.AddressTentative)\n\n\t\t\t// check if existing matches the spec: if it does, skip update\n\t\t\tif existing.Scope == uint8(address.TypedSpec().Scope) && existing.Flags == uint8(address.TypedSpec().Flags) &&\n\t\t\t\texisting.Attributes.Flags == uint32(address.TypedSpec().Flags) && existing.Attributes.Priority == address.TypedSpec().Priority {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tlogger.Debug(\"replacing address\",\n\t\t\t\tzap.Stringer(\"address\", address.TypedSpec().Address),\n\t\t\t\tzap.String(\"link\", address.TypedSpec().LinkName),\n\t\t\t\tzap.Stringer(\"old_scope\", nethelpers.Scope(existing.Scope)),\n\t\t\t\tzap.Stringer(\"new_scope\", address.TypedSpec().Scope),\n\t\t\t\tzap.Stringer(\"old_flags\", nethelpers.AddressFlags(existing.Attributes.Flags)),\n\t\t\t\tzap.Stringer(\"new_flags\", address.TypedSpec().Flags),\n\t\t\t\tzap.Uint32(\"old_priority\", existing.Attributes.Priority),\n\t\t\t\tzap.Uint32(\"new_priority\", address.TypedSpec().Priority),\n\t\t\t)\n\n\t\t\t// delete address to get new one assigned below\n\t\t\tif err := conn.Address.Delete(existing); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing address: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"removed address\", zap.Stringer(\"address\", address.TypedSpec().Address), zap.String(\"link\", address.TypedSpec().LinkName))\n\t\t}\n\n\t\t// add address\n\t\tif err := conn.Address.New(&rtnetlink.AddressMessage{\n\t\t\tFamily:       uint8(address.TypedSpec().Family),\n\t\t\tPrefixLength: uint8(address.TypedSpec().Address.Bits()),\n\t\t\tFlags:        uint8(address.TypedSpec().Flags),\n\t\t\tScope:        uint8(address.TypedSpec().Scope),\n\t\t\tIndex:        linkIndex,\n\t\t\tAttributes: &rtnetlink.AddressAttributes{\n\t\t\t\tAddress:   address.TypedSpec().Address.Addr().AsSlice(),\n\t\t\t\tLocal:     address.TypedSpec().Address.Addr().AsSlice(),\n\t\t\t\tBroadcast: addressutil.BroadcastAddr(address.TypedSpec().Address),\n\t\t\t\tFlags:     uint32(address.TypedSpec().Flags),\n\t\t\t\tPriority:  address.TypedSpec().Priority,\n\t\t\t},\n\t\t}); err != nil {\n\t\t\t// ignore EEXIST error\n\t\t\tif !errors.Is(err, os.ErrExist) {\n\t\t\t\treturn fmt.Errorf(\"error adding address %s to %q: %w\", address.TypedSpec().Address, address.TypedSpec().LinkName, err)\n\t\t\t}\n\t\t}\n\n\t\tlogger.Info(\"assigned address\", zap.Stringer(\"address\", address.TypedSpec().Address), zap.String(\"link\", address.TypedSpec().LinkName))\n\n\t\tif address.TypedSpec().AnnounceWithARP {\n\t\t\tif err := ctrl.gratuitousARP(logger, linkIndex, address.TypedSpec().Address.Addr()); err != nil {\n\t\t\t\tlogger.Warn(\"failure sending gratuitous ARP\", zap.Stringer(\"address\", address.TypedSpec().Address), zap.String(\"link\", address.TypedSpec().LinkName), zap.Error(err))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *AddressSpecController) gratuitousARP(logger *zap.Logger, linkIndex uint32, ip netip.Addr) error {\n\tetherBroadcast := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}\n\n\tif !ip.Is4() {\n\t\treturn nil\n\t}\n\n\tiface, err := net.InterfaceByIndex(int(linkIndex))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(iface.HardwareAddr) != 6 {\n\t\t// not ethernet\n\t\treturn nil\n\t}\n\n\tcli, err := arp.Dial(iface)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating arp client: %w\", err)\n\t}\n\n\tdefer cli.Close() //nolint:errcheck\n\n\tpacket, err := arp.NewPacket(arp.OperationRequest, cli.HardwareAddr(), ip, cli.HardwareAddr(), ip)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building packet: %w\", err)\n\t}\n\n\tif err = cli.WriteTo(packet, etherBroadcast); err != nil {\n\t\treturn fmt.Errorf(\"error sending gratuitous ARP: %w\", err)\n\t}\n\n\tlogger.Info(\"sent gratuitous ARP\", zap.Stringer(\"address\", ip), zap.String(\"link\", iface.Name))\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype AddressSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *AddressSpecSuite) uniqueDummyInterface() string {\n\treturn fmt.Sprintf(\"dummy%02x%02x%02x\", rand.Int32()&0xff, rand.Int32()&0xff, rand.Int32()&0xff)\n}\n\nfunc assertLinkAddress(asrt *assert.Assertions, linkName, address string) {\n\taddr := netip.MustParsePrefix(address)\n\n\tiface, err := net.InterfaceByName(linkName)\n\tasrt.NoError(err)\n\n\tconn, err := rtnetlink.Dial(nil)\n\tasrt.NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tlinkAddresses, err := conn.Address.List()\n\tasrt.NoError(err)\n\n\tfor _, linkAddress := range linkAddresses {\n\t\tif linkAddress.Index != uint32(iface.Index) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif int(linkAddress.PrefixLength) != addr.Bits() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !linkAddress.Attributes.Address.Equal(addr.Addr().AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn\n\t}\n\n\tasrt.Failf(\"address not found\", \"address %s not found on %q\", addr, linkName)\n}\n\nfunc assertNoLinkAddress(asrt *assert.Assertions, linkName, address string) {\n\taddr := netip.MustParsePrefix(address)\n\n\tiface, err := net.InterfaceByName(linkName)\n\tasrt.NoError(err)\n\n\tconn, err := rtnetlink.Dial(nil)\n\tasrt.NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tlinkAddresses, err := conn.Address.List()\n\tasrt.NoError(err)\n\n\tfor _, linkAddress := range linkAddresses {\n\t\tif linkAddress.Index == uint32(iface.Index) && int(linkAddress.PrefixLength) == addr.Bits() && linkAddress.Attributes.Address.Equal(addr.Addr().AsSlice()) {\n\t\t\tasrt.Failf(\"address is still there\", \"address %s is assigned to %q\", addr, linkName)\n\t\t}\n\t}\n}\n\nfunc (suite *AddressSpecSuite) TestLoopback() {\n\tloopback := network.NewAddressSpec(network.NamespaceName, \"lo/127.0.0.1/8\")\n\t*loopback.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"127.11.0.1/32\"),\n\t\tLinkName:    \"lo\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeHost,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t}\n\n\tfor _, res := range []resource.Resource{loopback} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().EventuallyWithT(func(collect *assert.CollectT) {\n\t\tassertLinkAddress(assert.New(collect), \"lo\", \"127.11.0.1/32\")\n\t}, 3*time.Second, 10*time.Millisecond)\n\n\t// teardown the address\n\t_, err := suite.State().Teardown(suite.Ctx(), loopback.Metadata())\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.State().WatchFor(suite.Ctx(), loopback.Metadata(), state.WithFinalizerEmpty())\n\tsuite.Require().NoError(err)\n\n\t// torn down address should be removed immediately\n\tsuite.Assert().EventuallyWithT(func(collect *assert.CollectT) {\n\t\tassertNoLinkAddress(assert.New(collect), \"lo\", \"127.11.0.1/32\")\n\t}, 3*time.Second, 10*time.Millisecond)\n\n\tsuite.Destroy(loopback)\n}\n\nfunc (suite *AddressSpecSuite) TestDummy() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tdummy := network.NewAddressSpec(network.NamespaceName, \"dummy/10.0.0.1/8\")\n\t*dummy.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.1/8\"),\n\t\tLinkName:    dummyInterface,\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t}\n\n\t// it's fine to create the address before the interface is actually created\n\tfor _, res := range []resource.Resource{dummy} {\n\t\tsuite.Create(res)\n\t}\n\n\t// create dummy interface\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType: unix.ARPHRD_ETHER,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1400,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tsuite.Assert().EventuallyWithT(func(collect *assert.CollectT) {\n\t\tassertLinkAddress(assert.New(collect), dummyInterface, \"10.0.0.1/8\")\n\t}, 3*time.Second, 10*time.Millisecond)\n\n\t// delete dummy interface, address should be unassigned automatically\n\tsuite.Require().NoError(conn.Link.Delete(uint32(iface.Index)))\n\n\t// teardown the address\n\t_, err = suite.State().Teardown(suite.Ctx(), dummy.Metadata())\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.State().WatchFor(suite.Ctx(), dummy.Metadata(), state.WithFinalizerEmpty())\n\tsuite.Require().NoError(err)\n\n\tsuite.Destroy(dummy)\n}\n\nfunc (suite *AddressSpecSuite) TestDummyAlias() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\tdummyAlias := suite.uniqueDummyInterface()\n\n\tsuite.T().Logf(\"dummyInterface: %s, dummyAlias: %s\", dummyInterface, dummyAlias)\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tdummy := network.NewAddressSpec(network.NamespaceName, \"dummy/10.0.0.5/8\")\n\t*dummy.TypedSpec() = network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"10.0.0.5/8\"),\n\t\tLinkName:    dummyAlias, // use alias name instead of the actual interface name\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t}\n\n\t// it's fine to create the address before the interface is actually created\n\tfor _, res := range []resource.Resource{dummy} {\n\t\tsuite.Create(res)\n\t}\n\n\t// create dummy interface\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType: unix.ARPHRD_ETHER,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1400,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\t// set alias name\n\tsuite.Require().NoError(\n\t\tconn.Link.Set(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tIndex: uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tAlias: &dummyAlias,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tsuite.Assert().EventuallyWithT(func(collect *assert.CollectT) {\n\t\tassertLinkAddress(assert.New(collect), dummyInterface, \"10.0.0.5/8\")\n\t}, 3*time.Second, 10*time.Millisecond)\n}\n\nfunc TestAddressSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, &AddressSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// AddressStatusController manages secrets.Etcd based on configuration.\ntype AddressStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AddressStatusController) Name() string {\n\treturn \"network.AddressStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AddressStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AddressStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.AddressStatusType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *AddressStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK|unix.RTMGRP_IPV4_IFADDR|unix.RTMGRP_IPV6_IFADDR)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\t// build links lookup table\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\tlinkLookup := make(map[uint32]string, len(links))\n\n\t\tfor _, link := range links {\n\t\t\tlinkLookup[link.Index] = link.Attributes.Name\n\t\t}\n\n\t\taddrs, err := conn.Address.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing addresses: %w\", err)\n\t\t}\n\n\t\tfor _, addr := range addrs {\n\t\t\t// TODO: should we use local address actually?\n\t\t\t// from if_addr.h:\n\t\t\t// IFA_ADDRESS is prefix address, rather than local interface address.\n\t\t\t// * It makes no difference for normally configured broadcast interfaces,\n\t\t\t// * but for point-to-point IFA_ADDRESS is DESTINATION address,\n\t\t\t// * local address is supplied in IFA_LOCAL attribute.\n\t\t\tipAddr, _ := netip.AddrFromSlice(addr.Attributes.Address)\n\t\t\tipPrefix := netip.PrefixFrom(ipAddr, int(addr.PrefixLength))\n\t\t\tid := network.AddressID(linkLookup[addr.Index], ipPrefix)\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewAddressStatus(network.NamespaceName, id), func(r *network.AddressStatus) error {\n\t\t\t\tstatus := r.TypedSpec()\n\n\t\t\t\tstatus.Address = ipPrefix\n\t\t\t\tstatus.Local, _ = netip.AddrFromSlice(addr.Attributes.Local)\n\t\t\t\tstatus.Broadcast, _ = netip.AddrFromSlice(addr.Attributes.Broadcast)\n\t\t\t\tstatus.Anycast, _ = netip.AddrFromSlice(addr.Attributes.Anycast)\n\t\t\t\tstatus.Multicast, _ = netip.AddrFromSlice(addr.Attributes.Multicast)\n\t\t\t\tstatus.LinkIndex = addr.Index\n\t\t\t\tstatus.LinkName = linkLookup[addr.Index]\n\t\t\t\tstatus.Family = nethelpers.Family(addr.Family)\n\t\t\t\tstatus.Scope = nethelpers.Scope(addr.Scope)\n\t\t\t\tstatus.Flags = nethelpers.AddressFlags(addr.Attributes.Flags)\n\t\t\t\tstatus.Priority = addr.Attributes.Priority\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*network.AddressStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error doing cleanup: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/address_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype AddressStatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *AddressStatusSuite) TestLoopback() {\n\tctest.AssertResource(suite, \"lo/127.0.0.1/8\", func(r *network.AddressStatus, asrt *assert.Assertions) {})\n}\n\nfunc TestAddressStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &AddressStatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressStatusController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/cmdline.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// CmdlineNetworking contains parsed cmdline networking settings.\ntype CmdlineNetworking struct {\n\tLinkConfigs      []CmdlineLinkConfig\n\tHostname         string\n\tDNSAddresses     []netip.Addr\n\tNTPAddresses     []netip.Addr\n\tIgnoreInterfaces []string\n\tNetworkLinkSpecs []network.LinkSpecSpec\n}\n\n// CmdlineLinkConfig contains parsed cmdline networking settings for a single link.\ntype CmdlineLinkConfig struct {\n\tLinkName string\n\tAddress  netip.Prefix\n\tGateway  netip.Addr\n\tDHCP     bool\n}\n\n// splitIPArgument splits the `ip=` kernel argument honoring the IPv6 addresses in square brackets.\nfunc splitIPArgument(val string) []string {\n\tvar (\n\t\tsquared, prev int\n\t\tparts         []string\n\t)\n\n\tfor i, c := range val {\n\t\tswitch c {\n\t\tcase '[':\n\t\t\tsquared++\n\t\tcase ']':\n\t\t\tsquared--\n\t\tcase ':':\n\t\t\tif squared != 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tparts = append(parts, strings.Trim(val[prev:i], \"[]\"))\n\t\t\tprev = i + 1\n\t\t}\n\t}\n\n\tparts = append(parts, strings.Trim(val[prev:], \"[]\"))\n\n\treturn parts\n}\n\nconst autoconfDHCP = \"dhcp\"\n\n// ParseCmdlineNetwork parses `ip=` and Talos specific kernel cmdline argument producing all the available configuration options.\n//\n//nolint:gocyclo,cyclop\nfunc ParseCmdlineNetwork(cmdline *procfs.Cmdline, linkNameResolver *network.LinkResolver) (CmdlineNetworking, error) {\n\tvar (\n\t\tsettings      CmdlineNetworking\n\t\terr           error\n\t\tlinkSpecSpecs []network.LinkSpecSpec\n\t)\n\n\t// process Talos specific kernel params\n\tcmdlineHostname := cmdline.Get(constants.KernelParamHostname).First()\n\tif cmdlineHostname != nil {\n\t\tsettings.Hostname = *cmdlineHostname\n\t}\n\n\tignoreInterfaces := cmdline.Get(constants.KernelParamNetworkInterfaceIgnore)\n\tfor i := 0; ignoreInterfaces.Get(i) != nil; i++ {\n\t\tsettings.IgnoreInterfaces = append(settings.IgnoreInterfaces, linkNameResolver.Resolve(*ignoreInterfaces.Get(i)))\n\t}\n\n\t// standard ip=\n\tipSettings := cmdline.Get(\"ip\")\n\n\tfor idx := 0; ipSettings.Get(idx) != nil; idx++ {\n\t\t// https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt\n\t\t// https://man7.org/linux/man-pages/man7/dracut.cmdline.7.html\n\t\t//\n\t\t// supported formats:\n\t\t//   ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>:<ntp0-ip>\n\t\t//   ip=dhcp (ignored)\n\t\t//   ip=<device>:dhcp\n\t\tfields := splitIPArgument(*ipSettings.Get(idx))\n\n\t\tswitch {\n\t\tcase len(fields) == 1 && fields[0] == autoconfDHCP:\n\t\t\t// ignore\n\t\tcase len(fields) == 2 && fields[1] == autoconfDHCP:\n\t\t\t// ip=<device>:dhcp\n\t\t\tlinkConfig := CmdlineLinkConfig{\n\t\t\t\tLinkName: linkNameResolver.Resolve(fields[0]),\n\t\t\t\tDHCP:     true,\n\t\t\t}\n\n\t\t\tlinkSpecSpecs = append(linkSpecSpecs, network.LinkSpecSpec{\n\t\t\t\tName:        linkConfig.LinkName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t})\n\n\t\t\tsettings.LinkConfigs = append(settings.LinkConfigs, linkConfig)\n\t\tdefault:\n\t\t\tlinkConfig := CmdlineLinkConfig{}\n\n\t\t\tfor i := range fields {\n\t\t\t\tif fields[i] == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tswitch i {\n\t\t\t\tcase 0:\n\t\t\t\t\tvar ip netip.Addr\n\n\t\t\t\t\tip, err = netip.ParseAddr(fields[0])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn settings, fmt.Errorf(\"cmdline address parse failure: %s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// default is to have complete address masked\n\t\t\t\t\tlinkConfig.Address = netip.PrefixFrom(ip, ip.BitLen())\n\t\t\t\tcase 2:\n\t\t\t\t\tlinkConfig.Gateway, err = netip.ParseAddr(fields[2])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn settings, fmt.Errorf(\"cmdline gateway parse failure: %s\", err)\n\t\t\t\t\t}\n\t\t\t\tcase 3:\n\t\t\t\t\tvar (\n\t\t\t\t\t\tnetmask netip.Addr\n\t\t\t\t\t\tones    int\n\t\t\t\t\t)\n\n\t\t\t\t\tones, err = strconv.Atoi(fields[3])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tnetmask, err = netip.ParseAddr(fields[3])\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn settings, fmt.Errorf(\"cmdline netmask parse failure: %s\", err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tones, _ = net.IPMask(netmask.AsSlice()).Size()\n\t\t\t\t\t}\n\n\t\t\t\t\tlinkConfig.Address = netip.PrefixFrom(linkConfig.Address.Addr(), ones)\n\t\t\t\tcase 4:\n\t\t\t\t\tif settings.Hostname == \"\" {\n\t\t\t\t\t\tsettings.Hostname = fields[4]\n\t\t\t\t\t}\n\t\t\t\tcase 5:\n\t\t\t\t\tlinkConfig.LinkName = linkNameResolver.Resolve(fields[5])\n\t\t\t\tcase 6:\n\t\t\t\t\tif fields[6] == autoconfDHCP {\n\t\t\t\t\t\tlinkConfig.DHCP = true\n\t\t\t\t\t}\n\t\t\t\tcase 7, 8:\n\t\t\t\t\tvar dnsIP netip.Addr\n\n\t\t\t\t\tdnsIP, err = netip.ParseAddr(fields[i])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn settings, fmt.Errorf(\"error parsing DNS IP: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tsettings.DNSAddresses = append(settings.DNSAddresses, dnsIP)\n\t\t\t\tcase 9:\n\t\t\t\t\tvar ntpIP netip.Addr\n\n\t\t\t\t\tntpIP, err = netip.ParseAddr(fields[i])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn settings, fmt.Errorf(\"error parsing NTP IP: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tsettings.NTPAddresses = append(settings.NTPAddresses, ntpIP)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if interface name is not set, pick the first non-loopback interface\n\t\t\tif linkConfig.LinkName == \"\" {\n\t\t\t\tifaces, _ := net.Interfaces() //nolint:errcheck // ignoring error here as ifaces will be empty\n\n\t\t\t\tslices.SortFunc(ifaces, func(a, b net.Interface) int { return cmp.Compare(a.Name, b.Name) })\n\n\t\t\t\tfor _, iface := range ifaces {\n\t\t\t\t\tif iface.Flags&net.FlagLoopback != 0 {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tlinkConfig.LinkName = iface.Name\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlinkSpecSpecs = append(linkSpecSpecs, network.LinkSpecSpec{\n\t\t\t\tName:        linkConfig.LinkName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t})\n\n\t\t\tsettings.LinkConfigs = append(settings.LinkConfigs, linkConfig)\n\t\t}\n\t}\n\n\t// dracut bond=\n\t// ref: https://man7.org/linux/man-pages/man7/dracut.cmdline.7.html\n\tbondSettings := cmdline.Get(constants.KernelParamBonding).First()\n\n\tif bondSettings != nil {\n\t\tvar (\n\t\t\tbondName, bondMTU string\n\t\t\tbondSlaves        []string\n\t\t\tbondOptions       v1alpha1.Bond\n\t\t)\n\n\t\t// bond=<bondname>[:<bondslaves>:[:<options>[:<mtu>]]]\n\t\tfields := strings.Split(*bondSettings, \":\")\n\n\t\tfor i := range fields {\n\t\t\tif fields[i] == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch i {\n\t\t\tcase 0:\n\t\t\t\tbondName = fields[0]\n\t\t\tcase 1:\n\t\t\t\tbondSlaves = strings.Split(fields[1], \",\")\n\t\t\tcase 2:\n\t\t\t\tbondOptions, err = parseBondOptions(fields[2])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn settings, err\n\t\t\t\t}\n\t\t\tcase 3:\n\t\t\t\tbondMTU = fields[3]\n\t\t\t}\n\t\t}\n\n\t\t// set defaults as per https://man7.org/linux/man-pages/man7/dracut.cmdline.7.html\n\t\t// Talos by default sets bond mode to balance-rr\n\t\tif bondSlaves == nil {\n\t\t\tbondSlaves = []string{\n\t\t\t\t\"eth0\",\n\t\t\t\t\"eth1\",\n\t\t\t}\n\t\t}\n\n\t\t// resolve bond slave names via aliases as needed\n\t\tbondSlaves = xslices.Map(bondSlaves, linkNameResolver.Resolve)\n\n\t\tbondLinkSpec := network.LinkSpecSpec{\n\t\t\tName:        bondName,\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t}\n\n\t\tif bondMTU != \"\" {\n\t\t\tmtu, err := strconv.Atoi(bondMTU)\n\t\t\tif err != nil {\n\t\t\t\treturn settings, fmt.Errorf(\"error parsing bond MTU: %w\", err)\n\t\t\t}\n\n\t\t\tbondLinkSpec.MTU = uint32(mtu)\n\t\t}\n\n\t\tif err := SetBondMasterLegacy(&bondLinkSpec, &bondOptions); err != nil {\n\t\t\treturn settings, fmt.Errorf(\"error setting bond master: %w\", err)\n\t\t}\n\n\t\tlinkSpecSpecs = append(linkSpecSpecs, bondLinkSpec)\n\n\t\tfor idx, slave := range bondSlaves {\n\t\t\tslaveLinkSpec := network.LinkSpecSpec{\n\t\t\t\tName:        slave,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t}\n\t\t\tSetBondSlave(&slaveLinkSpec, ordered.MakePair(bondName, idx))\n\t\t\tlinkSpecSpecs = append(linkSpecSpecs, slaveLinkSpec)\n\t\t}\n\t}\n\n\t// dracut vlan=<vlanname>:<phydevice>\n\tvlanSettings := cmdline.Get(constants.KernelParamVlan).First()\n\tif vlanSettings != nil {\n\t\tvlanName, phyDevice, ok := strings.Cut(*vlanSettings, \":\")\n\t\tif !ok {\n\t\t\treturn settings, fmt.Errorf(\"malformed vlan commandline argument: %s\", *vlanSettings)\n\t\t}\n\n\t\t_, vlanNumberString, ok := strings.Cut(vlanName, \".\")\n\t\tif !ok {\n\t\t\tvlanNumberString, ok = strings.CutPrefix(vlanName, \"vlan\")\n\t\t\tif !ok {\n\t\t\t\treturn settings, fmt.Errorf(\"malformed vlan commandline argument: %s\", *vlanSettings)\n\t\t\t}\n\t\t}\n\n\t\tvlanID, err := strconv.Atoi(vlanNumberString)\n\n\t\tif vlanID < 1 || 4095 < vlanID {\n\t\t\treturn settings, fmt.Errorf(\"invalid vlanID=%d, must be in the range 1..4095: %s\", vlanID, *vlanSettings)\n\t\t}\n\n\t\tif err != nil || vlanNumberString == \"\" {\n\t\t\treturn settings, errors.New(\"unable to parse vlan\")\n\t\t}\n\n\t\tvlanSpec := network.VLANSpec{\n\t\t\tVID:      uint16(vlanID),\n\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t}\n\n\t\tvlanName = nethelpers.VLANLinkName(phyDevice, uint16(vlanID))\n\n\t\tphyDevice = linkNameResolver.Resolve(phyDevice)\n\n\t\tlinkSpecUpdated := false\n\n\t\tfor i, linkSpec := range linkSpecSpecs {\n\t\t\tif linkSpec.Name == vlanName {\n\t\t\t\tvlanLink(&linkSpecSpecs[i], vlanName, phyDevice, vlanSpec)\n\n\t\t\t\tlinkSpecUpdated = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !linkSpecUpdated {\n\t\t\tlinkSpec := network.LinkSpecSpec{\n\t\t\t\tName:        vlanName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t}\n\n\t\t\tvlanLink(&linkSpec, vlanName, phyDevice, vlanSpec)\n\n\t\t\tlinkSpecSpecs = append(linkSpecSpecs, linkSpec)\n\t\t}\n\t}\n\n\tsettings.NetworkLinkSpecs = linkSpecSpecs\n\n\treturn settings, nil\n}\n\n// parseBondOptions parses the options string into v1alpha1.Bond\n// v1alpha1.Bond was chosen to re-use the `SetBondMaster` and `SetBondSlave` functions\n// ref: modinfo bonding\n//\n//nolint:gocyclo,cyclop,dupword\nfunc parseBondOptions(options string) (v1alpha1.Bond, error) {\n\tvar bond v1alpha1.Bond\n\n\tfor opt := range strings.SplitSeq(options, \",\") {\n\t\toptionPair := strings.Split(opt, \"=\")\n\n\t\tswitch optionPair[0] {\n\t\tcase \"arp_ip_target\":\n\t\t\tbond.BondARPIPTarget = strings.Split(optionPair[1], \";\")\n\t\tcase \"mode\":\n\t\t\tbond.BondMode = optionPair[1]\n\t\tcase \"xmit_hash_policy\":\n\t\t\tbond.BondHashPolicy = optionPair[1]\n\t\tcase \"lacp_rate\":\n\t\t\tbond.BondLACPRate = optionPair[1]\n\t\tcase \"arp_validate\":\n\t\t\tbond.BondARPValidate = optionPair[1]\n\t\tcase \"arp_all_targets\":\n\t\t\tbond.BondARPAllTargets = optionPair[1]\n\t\tcase \"primary\":\n\t\t\tbond.BondPrimary = optionPair[1]\n\t\tcase \"primary_reselect\":\n\t\t\tbond.BondPrimaryReselect = optionPair[1]\n\t\tcase \"fail_over_mac\":\n\t\t\tbond.BondFailOverMac = optionPair[1]\n\t\tcase \"ad_select\":\n\t\t\tbond.BondADSelect = optionPair[1]\n\t\tcase \"miimon\":\n\t\t\tmiimon, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option miimon: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondMIIMon = uint32(miimon)\n\t\tcase \"updelay\":\n\t\t\tupdelay, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option updelay: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondUpDelay = uint32(updelay)\n\t\tcase \"downdelay\":\n\t\t\tdowndelay, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option downdelay: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondDownDelay = uint32(downdelay)\n\t\tcase \"arp_interval\":\n\t\t\tarpInterval, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option arp_interval: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondARPInterval = uint32(arpInterval)\n\t\tcase \"resend_igmp\":\n\t\t\tresendIGMP, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option resend_igmp: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondResendIGMP = uint32(resendIGMP)\n\t\tcase \"min_links\":\n\t\t\tminLinks, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option min_links: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondMinLinks = uint32(minLinks)\n\t\tcase \"lp_interval\":\n\t\t\tlpInterval, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option lp_interval: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondLPInterval = uint32(lpInterval)\n\t\tcase \"packets_per_slave\":\n\t\t\tpacketsPerSlave, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option packets_per_slave: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondPacketsPerSlave = uint32(packetsPerSlave)\n\t\tcase \"num_grat_arp\":\n\t\t\tnumGratArp, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option num_grat_arp: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondNumPeerNotif = uint8(numGratArp)\n\t\tcase \"num_unsol_na\":\n\t\t\tnumGratArp, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option num_unsol_na: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondNumPeerNotif = uint8(numGratArp)\n\t\tcase \"all_slaves_active\":\n\t\t\tallSlavesActive, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option all_slaves_active: %w\", err)\n\t\t\t}\n\n\t\t\tbond.BondAllSlavesActive = uint8(allSlavesActive)\n\t\tcase \"use_carrier\":\n\t\t\tuseCarrier, err := strconv.Atoi(optionPair[1])\n\t\t\tif err != nil {\n\t\t\t\treturn bond, fmt.Errorf(\"error parsing bond option use_carrier: %w\", err)\n\t\t\t}\n\n\t\t\tif useCarrier == 1 {\n\t\t\t\tbond.BondUseCarrier = new(true)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn bond, fmt.Errorf(\"unknown bond option: %s\", optionPair[0])\n\t\t}\n\t}\n\n\treturn bond, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/cmdline_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"iter\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\tnetconfig \"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestCmdlineParse(t *testing.T) {\n\t// [NOTE]: this test is not safe to run in parallel, as defaultIfaceName might flip if some interface is created concurrently\n\tifaces, _ := net.Interfaces() //nolint:errcheck // ignoring error here as ifaces will be empty\n\n\tslices.SortFunc(ifaces, func(a, b net.Interface) int { return cmp.Compare(a.Name, b.Name) })\n\n\tdefaultIfaceName := \"\"\n\n\tfor _, iface := range ifaces {\n\t\tif iface.Flags&net.FlagLoopback != 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tdefaultIfaceName = iface.Name\n\n\t\tbreak\n\t}\n\n\tdefaultBondSettings := network.CmdlineNetworking{\n\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName:        \"bond1\",\n\t\t\t\tKind:        \"bond\",\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tLogical:     true,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\tBondMaster: netconfig.BondMasterSpec{\n\t\t\t\t\tMode:            nethelpers.BondModeRoundrobin,\n\t\t\t\t\tResendIGMP:      1,\n\t\t\t\t\tLPInterval:      1,\n\t\t\t\t\tPacketsPerSlave: 1,\n\t\t\t\t\tNumPeerNotif:    1,\n\t\t\t\t\tTLBDynamicLB:    1,\n\t\t\t\t\tUseCarrier:      true,\n\t\t\t\t\tPrimaryIndex:    new(uint32(0)),\n\t\t\t\t\tADLACPActive:    nethelpers.ADLACPActiveOn,\n\t\t\t\t\tMissedMax:       2,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"eth0\",\n\t\t\t\tUp:          true,\n\t\t\t\tLogical:     false,\n\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\tSlaveIndex: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"eth1\",\n\t\t\t\tUp:          true,\n\t\t\t\tLogical:     false,\n\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\tSlaveIndex: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range []struct {\n\t\tname    string\n\t\tcmdline string\n\n\t\texpectedSettings network.CmdlineNetworking\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\tname:    \"zero\",\n\t\t\tcmdline: \"\",\n\t\t},\n\t\t{\n\t\t\tname:    \"static IP\",\n\t\t\tcmdline: \"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: \"eth1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"no iface\",\n\t\t\tcmdline: \"ip=172.20.0.2::172.20.0.1\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/32\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: defaultIfaceName,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        defaultIfaceName,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"no iface by mac address\",\n\t\t\tcmdline: \"ip=172.20.0.2::172.20.0.1:255.255.255.0::enx001122aabbcc\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: \"enx001122aabbcc\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"enx001122aabbcc\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"complete\",\n\t\t\tcmdline: \"ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: \"eth1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname:     \"master1\",\n\t\t\t\tDNSAddresses: []netip.Addr{netip.MustParseAddr(\"10.0.0.1\"), netip.MustParseAddr(\"10.0.0.2\")},\n\t\t\t\tNTPAddresses: []netip.Addr{netip.MustParseAddr(\"10.0.0.1\")},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"another config\",\n\t\t\tcmdline: \"ip=10.105.155.21::10.105.155.30:255.255.255.240:pve1:eth0:off\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tLinkName: \"eth0\",\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"10.105.155.21/28\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"10.105.155.30\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname: \"pve1\",\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth0\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"ipv6\",\n\t\t\tcmdline: \"ip=[2001:db8::a]:[2001:db8::b]:[fe80::1]::master1:eth1::[2001:4860:4860::6464]:[2001:4860:4860::64]:[2001:4860:4806::]\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"2001:db8::a/128\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"fe80::1\"),\n\t\t\t\t\t\tLinkName: \"eth1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname:     \"master1\",\n\t\t\t\tDNSAddresses: []netip.Addr{netip.MustParseAddr(\"2001:4860:4860::6464\"), netip.MustParseAddr(\"2001:4860:4860::64\")},\n\t\t\t\tNTPAddresses: []netip.Addr{netip.MustParseAddr(\"2001:4860:4806::\")},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"ipv6-mask\",\n\t\t\tcmdline: \"ip=[2a03:1:2::12]::[2a03:1:2::11]:[ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8]:master:eth0:off:[2001:4860:4860::8888]:[2606:4700::1111]:[2606:4700:f1::1]\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"2a03:1:2::12/125\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"2a03:1:2::11\"),\n\t\t\t\t\t\tLinkName: \"eth0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname:     \"master\",\n\t\t\t\tDNSAddresses: []netip.Addr{netip.MustParseAddr(\"2001:4860:4860::8888\"), netip.MustParseAddr(\"2606:4700::1111\")},\n\t\t\t\tNTPAddresses: []netip.Addr{netip.MustParseAddr(\"2606:4700:f1::1\")},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth0\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"ipv6-mask-number\",\n\t\t\tcmdline: \"ip=[2a03:1:2::12]::[2a03:1:2::11]:125:master:eth0:off:[2001:4860:4860::8888]:[2606:4700::1111]:[2606:4700:f1::1]\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"2a03:1:2::12/125\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"2a03:1:2::11\"),\n\t\t\t\t\t\tLinkName: \"eth0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname:     \"master\",\n\t\t\t\tDNSAddresses: []netip.Addr{netip.MustParseAddr(\"2001:4860:4860::8888\"), netip.MustParseAddr(\"2606:4700::1111\")},\n\t\t\t\tNTPAddresses: []netip.Addr{netip.MustParseAddr(\"2606:4700:f1::1\")},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth0\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"unparseable IP\",\n\t\t\tcmdline: \"ip=xyz:\",\n\n\t\t\texpectedError: \"cmdline address parse failure: ParseAddr(\\\"xyz\\\"): unable to parse IP\",\n\t\t},\n\t\t{\n\t\t\tname:    \"hostname override\",\n\t\t\tcmdline: \"ip=::::master1:eth1 talos.hostname=master2\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tLinkName: \"eth1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostname: \"master2\",\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"only hostname\",\n\t\t\tcmdline: \"talos.hostname=master2\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tHostname: \"master2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"ignore interfaces\",\n\t\t\tcmdline: \"talos.network.interface.ignore=eth2 talos.network.interface.ignore=eth3 talos.network.interface.ignore=enxa\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tIgnoreInterfaces: []string{\"eth2\", \"eth3\", \"eth31\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:             \"bond with no interfaces and no options set\",\n\t\t\tcmdline:          \"bond=bond1\",\n\t\t\texpectedSettings: defaultBondSettings,\n\t\t},\n\t\t{\n\t\t\tname:             \"bond with no interfaces and empty options set\",\n\t\t\tcmdline:          \"bond=bond1:::\",\n\t\t\texpectedSettings: defaultBondSettings,\n\t\t},\n\t\t{\n\t\t\tname:    \"bond with interfaces and no options set\",\n\t\t\tcmdline: \"bond=bond1:eth3,eth4\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\tdefaultBondSettings.NetworkLinkSpecs[0],\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth3\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth4\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"bond with aliased interfaces\",\n\t\t\tcmdline: \"bond=bond1:enxa,enxb\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\tdefaultBondSettings.NetworkLinkSpecs[0],\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth31\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth32\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"bond with interfaces, options and mtu set\",\n\t\t\tcmdline: \"bond=bond1:eth3,eth4:mode=802.3ad,xmit_hash_policy=layer2+3:1450\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"bond1\",\n\t\t\t\t\t\tKind:        \"bond\",\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tMTU:         1450,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondMaster: netconfig.BondMasterSpec{\n\t\t\t\t\t\t\tMode:            nethelpers.BondMode8023AD,\n\t\t\t\t\t\t\tHashPolicy:      nethelpers.BondXmitPolicyLayer23,\n\t\t\t\t\t\t\tADActorSysPrio:  65535,\n\t\t\t\t\t\t\tResendIGMP:      1,\n\t\t\t\t\t\t\tLPInterval:      1,\n\t\t\t\t\t\t\tPacketsPerSlave: 1,\n\t\t\t\t\t\t\tNumPeerNotif:    1,\n\t\t\t\t\t\t\tTLBDynamicLB:    1,\n\t\t\t\t\t\t\tUseCarrier:      true,\n\t\t\t\t\t\t\tPrimaryIndex:    new(uint32(0)),\n\t\t\t\t\t\t\tADLACPActive:    nethelpers.ADLACPActiveOn,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth3\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth4\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tLogical:     false,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tBondSlave: netconfig.BondSlave{\n\t\t\t\t\t\t\tMasterName: \"bond1\",\n\t\t\t\t\t\t\tSlaveIndex: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"unparseable bond options\",\n\t\t\tcmdline: \"bond=bond0:eth1,eth2:mod=balance-rr\",\n\n\t\t\texpectedError: \"unknown bond option: mod\",\n\t\t},\n\t\t{\n\t\t\tname:    \"vlan configuration\",\n\t\t\tcmdline: \"vlan=eth1.169:eth1 ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1.169:::::\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: \"eth1.169\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1.169\",\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tKind:        netconfig.LinkKindVLAN,\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tParentName:  \"eth1\",\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tVLAN: netconfig.VLANSpec{\n\t\t\t\t\t\t\tVID:      169,\n\t\t\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"vlan configuration without ip configuration\",\n\t\t\tcmdline: \"vlan=eth1.5:eth1\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1.5\",\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tKind:        netconfig.LinkKindVLAN,\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tParentName:  \"eth1\",\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tVLAN: netconfig.VLANSpec{\n\t\t\t\t\t\t\tVID:      5,\n\t\t\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"vlan configuration with alternative link name vlan0008\",\n\t\t\tcmdline: \"vlan=vlan0008:eth1\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1.8\",\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tKind:        netconfig.LinkKindVLAN,\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tParentName:  \"eth1\",\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tVLAN: netconfig.VLANSpec{\n\t\t\t\t\t\t\tVID:      8,\n\t\t\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"vlan configuration with alternative link name vlan1\",\n\t\t\tcmdline: \"vlan=vlan4095:eth1\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1.4095\",\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tKind:        netconfig.LinkKindVLAN,\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tParentName:  \"eth1\",\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tVLAN: netconfig.VLANSpec{\n\t\t\t\t\t\t\tVID:      4095,\n\t\t\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"vlan configuration with alias link name\",\n\t\t\tcmdline: \"vlan=vlan4095:enxa\",\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"enxa.4095\",\n\t\t\t\t\t\tLogical:     true,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tKind:        netconfig.LinkKindVLAN,\n\t\t\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\t\t\tParentName:  \"eth31\",\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t\tVLAN: netconfig.VLANSpec{\n\t\t\t\t\t\t\tVID:      4095,\n\t\t\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"vlan configuration with invalid vlan ID 4096\",\n\t\t\tcmdline:       \"vlan=eth1.4096:eth1\",\n\t\t\texpectedError: fmt.Sprintf(\"invalid vlanID=%d, must be in the range 1..4095: %s\", 4096, \"eth1.4096:eth1\"),\n\t\t},\n\t\t{\n\t\t\tname:          \"vlan configuration with invalid vlan ID 0\",\n\t\t\tcmdline:       \"vlan=eth1.0:eth1\",\n\t\t\texpectedError: fmt.Sprintf(\"invalid vlanID=%d, must be in the range 1..4095: %s\", 0, \"eth1.0:eth1\"),\n\t\t},\n\t\t{\n\t\t\tname:    \"multiple ip configurations\",\n\t\t\tcmdline: \"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1::::: ip=eth3:dhcp ip=:::::eth4:dhcp::::\",\n\n\t\t\texpectedSettings: network.CmdlineNetworking{\n\t\t\t\tLinkConfigs: []network.CmdlineLinkConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress:  netip.MustParsePrefix(\"172.20.0.2/24\"),\n\t\t\t\t\t\tGateway:  netip.MustParseAddr(\"172.20.0.1\"),\n\t\t\t\t\t\tLinkName: \"eth1\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tLinkName: \"eth3\",\n\t\t\t\t\t\tDHCP:     true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tLinkName: \"eth4\",\n\t\t\t\t\t\tDHCP:     true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tNetworkLinkSpecs: []netconfig.LinkSpecSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth1\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth3\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:        \"eth4\",\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: netconfig.ConfigCmdline,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcmdline := procfs.NewCmdline(test.cmdline)\n\n\t\t\tlink1 := netconfig.NewLinkStatus(netconfig.NamespaceName, \"eth31\")\n\t\t\tlink1.TypedSpec().Alias = \"enxa\"\n\t\t\tlink2 := netconfig.NewLinkStatus(netconfig.NamespaceName, \"eth32\")\n\t\t\tlink2.TypedSpec().Alias = \"enxb\"\n\n\t\t\tsettings, err := network.ParseCmdlineNetwork(\n\t\t\t\tcmdline,\n\t\t\t\tnetconfig.NewLinkResolver(\n\t\t\t\t\tfunc() iter.Seq[*netconfig.LinkStatus] {\n\t\t\t\t\t\treturn slices.Values([]*netconfig.LinkStatus{link1, link2})\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, test.expectedSettings, settings)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/device_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\tglob \"github.com/ryanuber/go-glob\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DeviceConfigController manages network.DeviceConfig based on configuration.\ntype DeviceConfigController struct {\n\tdevices map[string]networkDevice\n}\n\n//nolint:unused\ntype networkDevice struct {\n\thardwareAddress string\n\tbusPrefix       string\n\tdriver          string\n\tpciID           string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DeviceConfigController) Name() string {\n\treturn \"network.DeviceConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DeviceConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DeviceConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.DeviceConfigSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DeviceConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tctrl.devices = map[string]networkDevice{}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tlinks, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfgProvider != nil && cfgProvider.Machine() != nil {\n\t\t\tfor index, device := range cfgProvider.Machine().Network().Devices() {\n\t\t\t\tout := []talosconfig.Device{device}\n\n\t\t\t\tif device.Selector() != nil {\n\t\t\t\t\tvar matched []*v1alpha1.Device\n\n\t\t\t\t\tmatched, err = ctrl.getDevicesBySelector(device, links)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlogger.Warn(\"failed to select an interface for a device\", zap.Error(err))\n\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tout = xslices.Map(matched, func(device *v1alpha1.Device) talosconfig.Device { return device })\n\t\t\t\t} else if device.Bond() != nil && len(device.Bond().Selectors()) > 0 {\n\t\t\t\t\tdev := device.(*v1alpha1.Device).DeepCopy()\n\t\t\t\t\tdevice = dev\n\n\t\t\t\t\terr = ctrl.expandBondSelector(dev, links)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlogger.Warn(\"failed to select interfaces for a bond device\", zap.Error(err))\n\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tout = []talosconfig.Device{device}\n\t\t\t\t}\n\n\t\t\t\tfor j, outDevice := range out {\n\t\t\t\t\tid := fmt.Sprintf(\"%s/%03d\", outDevice.Interface(), index)\n\n\t\t\t\t\tif len(out) > 1 {\n\t\t\t\t\t\tid = fmt.Sprintf(\"%s/%03d\", id, j)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err = safe.WriterModify(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\tr,\n\t\t\t\t\t\tnetwork.NewDeviceConfig(id, outDevice),\n\t\t\t\t\t\tfunc(r *network.DeviceConfigSpec) error {\n\t\t\t\t\t\t\tr.TypedSpec().Device = outDevice\n\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.DeviceConfigSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (ctrl *DeviceConfigController) getDevicesBySelector(device talosconfig.Device, links safe.List[*network.LinkStatus]) ([]*v1alpha1.Device, error) {\n\tselector := device.Selector()\n\n\tmatches := ctrl.selectDevices(selector, links)\n\tif len(matches) == 0 {\n\t\treturn nil, fmt.Errorf(\"no matching network device for defined selector: %+v\", selector)\n\t}\n\n\tout := make([]*v1alpha1.Device, len(matches))\n\n\tfor i, link := range matches {\n\t\tout[i] = device.(*v1alpha1.Device).DeepCopy()\n\t\tout[i].DeviceInterface = link.Metadata().ID()\n\t}\n\n\treturn out, nil\n}\n\nfunc (ctrl *DeviceConfigController) expandBondSelector(device *v1alpha1.Device, links safe.List[*network.LinkStatus]) error {\n\tmatches := make([]*network.LinkStatus, 0, len(device.Bond().Selectors()))\n\n\tfor _, selector := range device.Bond().Selectors() {\n\t\tmatches = append(matches,\n\t\t\t// filter out bond device itself, as it will inherit the MAC address of the first link\n\t\t\txslices.Filter(\n\t\t\t\tctrl.selectDevices(selector, links),\n\t\t\t\tfunc(link *network.LinkStatus) bool {\n\t\t\t\t\treturn link.Metadata().ID() != device.Interface()\n\t\t\t\t})...)\n\t}\n\n\tdevice.DeviceBond.BondInterfaces = xslices.Map(matches, func(link *network.LinkStatus) string { return link.Metadata().ID() })\n\n\tif len(device.DeviceBond.BondInterfaces) == 0 {\n\t\treturn fmt.Errorf(\"no matching network device for defined bond selectors: %v\",\n\t\t\txslices.Map(device.Bond().Selectors(),\n\t\t\t\tfunc(selector talosconfig.NetworkDeviceSelector) string {\n\t\t\t\t\treturn fmt.Sprintf(\"%+v\", selector)\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t}\n\n\tdevice.DeviceBond.BondDeviceSelectors = nil\n\n\treturn nil\n}\n\nfunc (ctrl *DeviceConfigController) selectDevices(selector talosconfig.NetworkDeviceSelector, links safe.List[*network.LinkStatus]) []*network.LinkStatus {\n\tvar result []*network.LinkStatus\n\n\tfor linkStatus := range links.All() {\n\t\tlinkStatusSpec := linkStatus.TypedSpec()\n\n\t\tvar match optional.Optional[bool]\n\n\t\tfor _, pair := range [][]string{\n\t\t\t{selector.HardwareAddress(), linkStatusSpec.HardwareAddr.String()},\n\t\t\t{selector.PermanentAddress(), linkStatusSpec.PermanentAddr.String()},\n\t\t\t{selector.PCIID(), linkStatusSpec.PCIID},\n\t\t\t{selector.KernelDriver(), linkStatusSpec.Driver},\n\t\t\t{selector.Bus(), linkStatusSpec.BusPath},\n\t\t} {\n\t\t\tif pair[0] == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !glob.Glob(pair[0], pair[1]) {\n\t\t\t\tmatch = optional.Some(false)\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tmatch = optional.Some(true)\n\t\t}\n\n\t\tif selector.Physical() != nil && match.ValueOr(true) {\n\t\t\tmatch = optional.Some(*selector.Physical() == linkStatusSpec.Physical())\n\t\t}\n\n\t\tif match.ValueOrZero() {\n\t\t\tresult = append(result, linkStatus)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/device_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\tconfigs \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype DeviceConfigSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *DeviceConfigSpecSuite) TestDeviceConfigs() {\n\tcfgProvider := container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy controller\n\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.2.0/24\"},\n\t\t\t\t\t\tDeviceMTU:       1500,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.2.0/24\"},\n\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\tBondMode:       \"balance-rr\",\n\t\t\t\t\t\t\tBondInterfaces: []string{\"eth1\", \"eth2\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.3.0/24\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\n\tcfg := config.NewMachineConfig(cfgProvider)\n\n\tdevices := map[string]configs.Device{}\n\tfor index, item := range cfgProvider.Machine().Network().Devices() {\n\t\tdevices[fmt.Sprintf(\"%s/%03d\", item.Interface(), index)] = item\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), maps.Keys(devices),\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal(r.TypedSpec().Device, devices[r.Metadata().ID()])\n\t\t},\n\t)\n}\n\nfunc (suite *DeviceConfigSpecSuite) TestSelectors() {\n\tkernelDriver := \"thedriver\"\n\n\tcfgProvider := container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy controller\n\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t// device selector selecing a single interface\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\tNetworkDeviceKernelDriver: kernelDriver,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.2.0/24\"},\n\t\t\t\t\t\tDeviceMTU:       1500,\n\t\t\t\t\t},\n\t\t\t\t\t// no device selector (explicit name)\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.3.0/24\"},\n\t\t\t\t\t},\n\t\t\t\t\t// device selector which doesn't match anything\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\tNetworkDeviceKernelDriver: \"no-match\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.4.0/24\"},\n\t\t\t\t\t},\n\t\t\t\t\t// device selector which matches multiple interfaces\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\tNetworkDeviceBus: \"0000:01*\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.5.0/24\"},\n\t\t\t\t\t},\n\t\t\t\t\t// device selector which matches physical interfaces\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\tNetworkDevicePhysical: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.6.0/24\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\n\tcfg := config.NewMachineConfig(cfgProvider)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tstatus := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tstatus.TypedSpec().Driver = kernelDriver\n\tstatus.TypedSpec().BusPath = \"0000:01:00.0\"\n\tstatus.TypedSpec().Type = nethelpers.LinkEther // physical\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), status))\n\n\tstatus = network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\tstatus.TypedSpec().BusPath = \"0000:01:01.0\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), status))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"eth0/000\"},\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal(1500, r.TypedSpec().Device.MTU())\n\t\t\tassert.Equal([]string{\"192.168.2.0/24\"}, r.TypedSpec().Device.Addresses())\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"eth0/001\"},\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal([]string{\"192.168.3.0/24\"}, r.TypedSpec().Device.Addresses())\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"eth0/003/000\", \"eth1/003/001\"},\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal([]string{\"192.168.5.0/24\"}, r.TypedSpec().Device.Addresses())\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"eth0/004\"},\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal([]string{\"192.168.6.0/24\"}, r.TypedSpec().Device.Addresses())\n\t\t},\n\t)\n}\n\nfunc (suite *DeviceConfigSpecSuite) TestBondSelectors() {\n\tcfgProvider := container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy controller\n\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t{\n\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.2.0/24\"},\n\t\t\t\t\t\tDeviceMTU:       1500,\n\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\tBondMode: \"balance-rr\",\n\t\t\t\t\t\t\tBondDeviceSelectors: []v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tNetworkDevicePermanentAddress: \"00:*\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tNetworkDevicePermanentAddress: \"01:*\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\n\tcfg := config.NewMachineConfig(cfgProvider)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tfor _, link := range []string{\"eth0\", \"eth1\"} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), status))\n\t}\n\n\trtestutils.AssertNoResource[*network.DeviceConfigSpec](suite.Ctx(), suite.T(), suite.State(), \"bond0/000\")\n\n\tfor _, link := range []struct {\n\t\tname   string\n\t\thwaddr string\n\t}{\n\t\t{\n\t\t\tname:   \"bond0\",\n\t\t\thwaddr: \"00:11:22:33:44:55\", // bond0 will inherit MAC of the first link\n\t\t},\n\t\t{\n\t\t\tname:   \"eth3\",\n\t\t\thwaddr: \"00:11:22:33:44:55\",\n\t\t},\n\t\t{\n\t\t\tname:   \"eth4\",\n\t\t\thwaddr: \"01:11:22:33:44:55\",\n\t\t},\n\t\t{\n\t\t\tname:   \"eth5\",\n\t\t\thwaddr: \"01:11:22:33:44:ef\",\n\t\t},\n\t\t{\n\t\t\tname:   \"eth6\",\n\t\t\thwaddr: \"02:11:22:33:44:55\",\n\t\t},\n\t} {\n\t\thwaddr, err := net.ParseMAC(link.hwaddr)\n\t\tsuite.Require().NoError(err)\n\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(hwaddr)\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), status))\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{\"bond0/000\"},\n\t\tfunc(r *network.DeviceConfigSpec, assert *assert.Assertions) {\n\t\t\tassert.Equal(1500, r.TypedSpec().Device.MTU())\n\t\t\tassert.Equal([]string{\"192.168.2.0/24\"}, r.TypedSpec().Device.Addresses())\n\t\t\tassert.Equal([]string{\"eth3\", \"eth4\", \"eth5\"}, r.TypedSpec().Device.Bond().Interfaces())\n\t\t},\n\t)\n}\n\nfunc TestDeviceConfigSpecSuite(t *testing.T) {\n\tsuite.Run(t, &DeviceConfigSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/dns_resolve_cache.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"fmt\"\n\t\"iter\"\n\t\"net/netip\"\n\t\"sync\"\n\n\t\"github.com/coredns/coredns/plugin/pkg/proxy\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/thejerf/suture/v4\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dns\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DNSResolveCacheController starts dns server on both udp and tcp ports based on finalized network configuration.\ntype DNSResolveCacheController struct {\n\tState  state.State\n\tLogger *zap.Logger\n\n\tmx        sync.Mutex\n\tmanager   *dns.Manager\n\treconcile chan struct{}\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DNSResolveCacheController) Name() string {\n\treturn \"network.DNSResolveCacheController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DNSResolveCacheController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\tsafe.Input[*network.DNSUpstream](controller.InputWeak),\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostDNSConfigType,\n\t\t\tID:        optional.Some(network.HostDNSConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DNSResolveCacheController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.DNSResolveCacheType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *DNSResolveCacheController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tctrl.init(ctx)\n\n\tctrl.mx.Lock()\n\tdefer ctrl.mx.Unlock()\n\n\tdefer func() {\n\t\tif err := ctrl.manager.ClearAll(ctx.Err() == nil); err != nil {\n\t\t\tctrl.Logger.Error(\"error stopping dns runners\", zap.Error(err))\n\t\t}\n\n\t\tif ctx.Err() != nil {\n\t\t\tctrl.Logger.Info(\"manager finished\", zap.Error(<-ctrl.manager.Done()))\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ctrl.reconcile:\n\t\t}\n\n\t\tif err := ctrl.run(ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *DNSResolveCacheController) run(ctx context.Context, r controller.Runtime) (resErr error) {\n\tr.StartTrackingOutputs()\n\tdefer cleanupOutputs(ctx, r, &resErr)\n\n\tcfg, err := safe.ReaderGetByID[*network.HostDNSConfig](ctx, r, network.HostDNSConfigID)\n\n\tswitch {\n\tcase state.IsNotFoundError(err):\n\t\treturn nil\n\tcase err != nil:\n\t\treturn fmt.Errorf(\"error getting host dns config: %w\", err)\n\t}\n\n\tctrl.manager.AllowNodeResolving(cfg.TypedSpec().ResolveMemberNames)\n\n\tif !cfg.TypedSpec().Enabled {\n\t\treturn ctrl.manager.ClearAll(false)\n\t}\n\n\tpairs := allAddressPairs(cfg.TypedSpec().ListenAddresses)\n\tforwardKubeDNSToHost := cfg.TypedSpec().ServiceHostDNSAddress.IsValid()\n\n\tfor runCfg, runErr := range ctrl.manager.RunAll(pairs, forwardKubeDNSToHost) {\n\t\tswitch {\n\t\tcase runErr != nil && (runCfg.Network == \"tcp6\" || runCfg.Network == \"udp6\"):\n\t\t\t// Ignore ipv6 errors\n\t\t\tctrl.Logger.Warn(\"ignoring ipv6 dns runner error\", zap.Error(runErr))\n\t\tcase runErr != nil:\n\t\t\treturn fmt.Errorf(\"error updating dns runner '%v': %w\", runCfg, runErr)\n\t\tcase runCfg.Status == dns.StatusRemoved:\n\t\t\t// Removed runned, no reason to update status\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = ctrl.writeDNSStatus(ctx, r, runCfg.AddressPair); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing dns status: %w\", err)\n\t\t}\n\t}\n\n\tupstreams, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting resolver status: %w\", err)\n\t}\n\n\tprxs := xiter.Map(\n\t\t// We are using iterator here to preserve finalizer on\n\t\tfunc(upstream *network.DNSUpstream) *proxy.Proxy {\n\t\t\treturn upstream.TypedSpec().Value.Conn.Proxy().(*proxy.Proxy)\n\t\t},\n\t\tupstreams.All(),\n\t)\n\n\tif ctrl.manager.SetUpstreams(prxs) {\n\t\tctrl.Logger.Info(\"updated dns server nameservers\", zap.Array(\"addrs\", addrsArr(upstreams)))\n\t}\n\n\treturn nil\n}\n\nfunc cleanupOutputs(ctx context.Context, r controller.Runtime, resErr *error) {\n\tif err := safe.CleanupOutputs[*network.DNSResolveCache](ctx, r); err != nil {\n\t\t*resErr = cmp.Or(*resErr, fmt.Errorf(\"error cleaning up dns resolve cache: %w\", err))\n\t}\n}\n\nfunc (ctrl *DNSResolveCacheController) writeDNSStatus(ctx context.Context, r controller.Runtime, config dns.AddressPair) error {\n\tres := network.NewDNSResolveCache(fmt.Sprintf(\"%s-%s\", config.Network, config.Addr))\n\n\treturn safe.WriterModify(ctx, r, res, func(drc *network.DNSResolveCache) error {\n\t\tdrc.TypedSpec().Status = \"running\"\n\n\t\treturn nil\n\t})\n}\n\nfunc (ctrl *DNSResolveCacheController) init(ctx context.Context) {\n\tif ctrl.manager == nil {\n\t\tctrl.manager = dns.NewManager(&memberReader{st: ctrl.State}, ctrl.eventHook, ctrl.Logger)\n\n\t\t// Ensure we stop all runners when the context is canceled, no matter where we are currently.\n\t\t// For example if we are in Controller runtime sleeping after error and ctx is canceled, we should stop all runners\n\t\t// but, we will never call Run method again, so we need to ensure this happens regardless of the current state.\n\t\tcontext.AfterFunc(ctx, func() {\n\t\t\tctrl.mx.Lock()\n\t\t\tdefer ctrl.mx.Unlock()\n\n\t\t\tif err := ctrl.manager.ClearAll(false); err != nil {\n\t\t\t\tctrl.Logger.Error(\"error ctx stopping dns runners\", zap.Error(err))\n\t\t\t}\n\t\t})\n\t}\n\n\tctrl.manager.ServeBackground(ctx)\n}\n\nfunc (ctrl *DNSResolveCacheController) eventHook(event suture.Event) {\n\tctrl.Logger.Info(\"dns-resolve-cache-runners event\", zap.String(\"event\", event.String()))\n\n\tselect {\n\tcase ctrl.reconcile <- struct{}{}:\n\tdefault:\n\t}\n}\n\ntype memberReader struct{ st state.State }\n\nfunc (m *memberReader) ReadMembers(ctx context.Context) (iter.Seq[*cluster.Member], error) {\n\tlist, err := safe.ReaderListAll[*cluster.Member](ctx, m.st)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn list.All(), nil\n}\n\ntype addrsArr safe.List[*network.DNSUpstream]\n\nfunc (a addrsArr) MarshalLogArray(encoder zapcore.ArrayEncoder) error {\n\tlist := safe.List[*network.DNSUpstream](a)\n\n\tfor u := range list.All() {\n\t\tencoder.AppendString(u.TypedSpec().Value.Conn.Addr())\n\t}\n\n\treturn nil\n}\n\nfunc allAddressPairs(addresses []netip.AddrPort) iter.Seq[dns.AddressPair] {\n\treturn func(yield func(dns.AddressPair) bool) {\n\t\tfor _, addr := range addresses {\n\t\t\tnetworks := [...]string{\"udp\", \"tcp\"}\n\t\t\tif addr.Addr().Is6() {\n\t\t\t\tnetworks = [...]string{\"udp6\", \"tcp6\"}\n\t\t\t}\n\n\t\t\tfor _, netwk := range networks {\n\t\t\t\tif !yield(dns.AddressPair{\n\t\t\t\t\tNetwork: netwk,\n\t\t\t\t\tAddr:    addr,\n\t\t\t\t}) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/dns_resolve_cache_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/miekg/dns\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype DNSServer struct {\n\tctest.DefaultSuite\n}\n\nfunc expectedDNSRunners(port string) []resource.ID {\n\treturn []resource.ID{\n\t\t\"tcp-127.0.0.53:\" + port,\n\t\t\"udp-127.0.0.53:\" + port,\n\t\t// our dns server makes no promises about actually starting on IPv6, so we don't check it here either\n\t}\n}\n\nfunc (suite *DNSServer) TestResolving() {\n\tdnsSlice := []string{\"8.8.8.8\", \"1.1.1.1\"}\n\tport := getDynamicPort(suite.T())\n\n\tcfg := network.NewHostDNSConfig(network.HostDNSConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ListenAddresses = makeAddrs(port)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tresolverSpec := network.NewResolverStatus(network.NamespaceName, network.ResolverID)\n\tresolverSpec.TypedSpec().DNSServers = xslices.Map(dnsSlice, netip.MustParseAddr)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), resolverSpec))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\texpectedDNSRunners(port),\n\t\tfunc(r *network.DNSResolveCache, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"running\", r.TypedSpec().Status)\n\t\t},\n\t)\n\n\trtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))\n\n\tmsg := &dns.Msg{\n\t\tMsgHdr: dns.MsgHdr{\n\t\t\tId:               dns.Id(),\n\t\t\tRecursionDesired: true,\n\t\t},\n\t\tQuestion: []dns.Question{\n\t\t\t{\n\t\t\t\tName:   dns.Fqdn(\"google.com\"),\n\t\t\t\tQtype:  dns.TypeA,\n\t\t\t\tQclass: dns.ClassINET,\n\t\t\t},\n\t\t},\n\t}\n\n\tvar res *dns.Msg\n\n\terr := retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\tr, err := dns.Exchange(msg, \"127.0.0.53:\"+port)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif r.Rcode != dns.RcodeSuccess {\n\t\t\treturn retry.ExpectedErrorf(\"expected rcode %d, got %d\", dns.RcodeSuccess, r.Rcode)\n\t\t}\n\n\t\tres = r\n\n\t\treturn nil\n\t})\n\tsuite.Require().NoError(err)\n\tsuite.Require().Equal(dns.RcodeSuccess, res.Rcode, res)\n}\n\nfunc (suite *DNSServer) TestSetupStartStop() {\n\tdnsSlice := []string{\"8.8.8.8\", \"1.1.1.1\"}\n\tport := getDynamicPort(suite.T())\n\n\tresolverSpec := network.NewResolverStatus(network.NamespaceName, network.ResolverID)\n\tresolverSpec.TypedSpec().DNSServers = xslices.Map(dnsSlice, netip.MustParseAddr)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), resolverSpec))\n\n\tcfg := network.NewHostDNSConfig(network.HostDNSConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ListenAddresses = makeAddrs(port)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\texpectedDNSRunners(port),\n\t\tfunc(r *network.DNSResolveCache, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"running\", r.TypedSpec().Status)\n\t\t})\n\n\trtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))\n\t// stop dns resolver\n\n\tcfg.TypedSpec().Enabled = false\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\tfor _, runner := range expectedDNSRunners(port) {\n\t\tctest.AssertNoResource[*network.DNSResolveCache](suite, runner)\n\t}\n\n\tfor _, d := range dnsSlice {\n\t\tctest.AssertNoResource[*network.DNSUpstream](suite, d)\n\t}\n\n\t// start dns resolver again\n\tcfg.TypedSpec().Enabled = true\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), expectedDNSRunners(port), func(r *network.DNSResolveCache, assert *assert.Assertions) {\n\t\tassert.Equal(\"running\", r.TypedSpec().Status)\n\t})\n\n\trtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(dnsSlice))\n}\n\nfunc (suite *DNSServer) TestResolveMembers() {\n\tport := getDynamicPort(suite.T())\n\n\tconst (\n\t\tid  = \"talos-default-controlplane-1\"\n\t\tid2 = \"foo.example.com.\"\n\t)\n\n\tmember := cluster.NewMember(cluster.NamespaceName, id)\n\t*member.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID: id,\n\t\tAddresses: []netip.Addr{\n\t\t\tnetip.MustParseAddr(\"172.20.0.2\"),\n\t\t},\n\t\tHostname:        id,\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos dev\",\n\t\tControlPlane:    nil,\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), member))\n\n\tmember = cluster.NewMember(cluster.NamespaceName, id2)\n\t*member.TypedSpec() = cluster.MemberSpec{\n\t\tNodeID: id2,\n\t\tAddresses: []netip.Addr{\n\t\t\tnetip.MustParseAddr(\"172.20.0.3\"),\n\t\t},\n\t\tHostname:        id2,\n\t\tMachineType:     machine.TypeWorker,\n\t\tOperatingSystem: \"Talos dev\",\n\t\tControlPlane:    nil,\n\t}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), member))\n\n\tcfg := network.NewHostDNSConfig(network.HostDNSConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ListenAddresses = makeAddrs(port)\n\tcfg.TypedSpec().ResolveMemberNames = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\texpectedDNSRunners(port),\n\t\tfunc(r *network.DNSResolveCache, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"running\", r.TypedSpec().Status)\n\t\t},\n\t)\n\n\tsuite.Require().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\texchange, err := dns.Exchange(\n\t\t\t&dns.Msg{\n\t\t\t\tMsgHdr: dns.MsgHdr{Id: dns.Id(), RecursionDesired: true},\n\t\t\t\tQuestion: []dns.Question{\n\t\t\t\t\t{Name: dns.Fqdn(id), Qtype: dns.TypeA, Qclass: dns.ClassINET},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"127.0.0.53:\"+port,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif exchange.Rcode != dns.RcodeSuccess {\n\t\t\treturn retry.ExpectedErrorf(\"expected rcode %d, got %d for %q\", dns.RcodeSuccess, exchange.Rcode, id)\n\t\t}\n\n\t\tproper := dns.Fqdn(id)\n\n\t\tif exchange.Answer[0].Header().Name != proper {\n\t\t\treturn retry.ExpectedErrorf(\"expected answer name %q, got %q\", proper, exchange.Answer[0].Header().Name)\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tsuite.Require().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\texchange, err := dns.Exchange(\n\t\t\t&dns.Msg{\n\t\t\t\tMsgHdr: dns.MsgHdr{Id: dns.Id(), RecursionDesired: true},\n\t\t\t\tQuestion: []dns.Question{\n\t\t\t\t\t{Name: dns.Fqdn(\"foo\"), Qtype: dns.TypeA, Qclass: dns.ClassINET},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"127.0.0.53:\"+port,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif exchange.Rcode != dns.RcodeSuccess {\n\t\t\treturn retry.ExpectedErrorf(\"expected rcode %d, got %d for %q\", dns.RcodeSuccess, exchange.Rcode, id2)\n\t\t}\n\n\t\tif !exchange.Answer[0].(*dns.A).A.Equal(net.ParseIP(\"172.20.0.3\")) {\n\t\t\treturn retry.ExpectedError(errors.New(\"unexpected ip\"))\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\nfunc TestDNSServer(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &DNSServer{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DNSUpstreamController{}))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DNSResolveCacheController{\n\t\t\t\t\tLogger: zaptest.NewLogger(t),\n\t\t\t\t\tState:  suite.State(),\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc getDynamicPort(t *testing.T) string {\n\tt.Helper()\n\n\tl, err := (&net.ListenConfig{}).Listen(t.Context(), \"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\taddr := l.Addr().String()\n\n\trequire.NoError(t, l.Close())\n\n\t_, port, err := net.SplitHostPort(addr)\n\trequire.NoError(t, err)\n\n\treturn port\n}\n\nfunc makeAddrs(port string) []netip.AddrPort {\n\treturn []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"127.0.0.53:\" + port),\n\t}\n}\n\ntype DNSUpstreams struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *DNSUpstreams) TestOrder() {\n\tport := getDynamicPort(suite.T())\n\n\tcfg := network.NewHostDNSConfig(network.HostDNSConfigID)\n\tcfg.TypedSpec().Enabled = true\n\tcfg.TypedSpec().ListenAddresses = makeAddrs(port)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tresolverSpec := network.NewResolverStatus(network.NamespaceName, network.ResolverID)\n\n\tfor i, addrs := range [][]string{\n\t\t{\"1.0.0.1\", \"8.8.8.8\", \"1.1.1.1\"},\n\t\t{\"1.1.1.1\", \"8.8.8.8\", \"1.0.0.1\", \"8.0.0.8\"},\n\t\t{\"192.168.0.1\"},\n\t} {\n\t\tif !suite.Run(strings.Join(addrs, \",\"), func() {\n\t\t\tresolverSpec.TypedSpec().DNSServers = xslices.Map(addrs, netip.MustParseAddr)\n\n\t\t\tswitch i {\n\t\t\tcase 0:\n\t\t\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), resolverSpec))\n\t\t\tdefault:\n\t\t\t\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), resolverSpec))\n\t\t\t}\n\n\t\t\texpected := xslices.Map(addrs, func(t string) string { return t + \":53\" })\n\n\t\t\trtestutils.AssertLength[*network.DNSUpstream](suite.Ctx(), suite.T(), suite.State(), len(addrs))\n\n\t\t\tvar actual []string\n\n\t\t\tdefer func() { suite.Require().Equal(expected, actual) }()\n\n\t\t\tfor suite.Ctx().Err() == nil {\n\t\t\t\tupstreams, err := safe.ReaderListAll[*network.DNSUpstream](suite.Ctx(), suite.State())\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tactual = safe.ToSlice(upstreams, func(u *network.DNSUpstream) string { return u.TypedSpec().Value.Conn.Addr() })\n\n\t\t\t\tif slices.Equal(expected, actual) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}) {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc TestDNSUpstreams(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &DNSUpstreams{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DNSUpstreamController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/dns_upstream.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/coredns/coredns/plugin/pkg/proxy\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DNSUpstreamController is a controller that manages DNS upstreams.\ntype DNSUpstreamController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DNSUpstreamController) Name() string {\n\treturn \"network.DNSUpstreamController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DNSUpstreamController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostDNSConfigType,\n\t\t\tID:        optional.Some(network.HostDNSConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.ResolverStatusType,\n\t\t\tID:        optional.Some(network.ResolverID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DNSUpstreamController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.DNSUpstreamType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *DNSUpstreamController) Run(ctx context.Context, r controller.Runtime, l *zap.Logger) error {\n\tdefer cleanupUpstream(context.Background(), r, nil, l)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif err := ctrl.run(ctx, r, l); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *DNSUpstreamController) run(ctx context.Context, r controller.Runtime, l *zap.Logger) error {\n\ttouchedIDs := map[resource.ID]struct{}{}\n\n\tdefer cleanupUpstream(ctx, r, touchedIDs, l)\n\n\tcfg, err := safe.ReaderGetByID[*network.HostDNSConfig](ctx, r, network.HostDNSConfigID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tif !cfg.TypedSpec().Enabled {\n\t\t// host DNS is disabled, cleanup all upstreams\n\t\treturn nil\n\t}\n\n\trs, err := safe.ReaderGetByID[*network.ResolverStatus](ctx, r, network.ResolverID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tinitConn, err := existingConnections(ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i, srv := range rs.TypedSpec().DNSServers {\n\t\tremoteHost := srv.String()\n\n\t\tif err = safe.WriterModify[*network.DNSUpstream](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewDNSUpstream(fmt.Sprintf(\"#%03d %s\", i, remoteHost)),\n\t\t\tfunc(u *network.DNSUpstream) error {\n\t\t\t\ttouchedIDs[u.Metadata().ID()] = struct{}{}\n\n\t\t\t\tinitConn(&u.TypedSpec().Value, remoteHost, l)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc existingConnections(ctx context.Context, r controller.Runtime) (func(*network.DNSUpstreamSpecSpec, string, *zap.Logger), error) {\n\tupstream, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\texistingConn := make(map[string]*network.DNSConn, upstream.Len())\n\n\tfor u := range upstream.All() {\n\t\texistingConn[u.TypedSpec().Value.Conn.Addr()] = u.TypedSpec().Value.Conn\n\t}\n\n\treturn func(spec *network.DNSUpstreamSpecSpec, remoteHost string, l *zap.Logger) {\n\t\tremoteAddr := net.JoinHostPort(remoteHost, \"53\")\n\t\tif spec.Conn != nil && spec.Conn.Addr() == remoteAddr {\n\t\t\tl.Debug(\"reusing existing upstream spec\", zap.String(\"addr\", remoteAddr))\n\n\t\t\treturn\n\t\t}\n\n\t\tdefer func(c *network.DNSConn) {\n\t\t\tif c != nil {\n\t\t\t\tc.Close()\n\t\t\t}\n\t\t}(spec.Conn)\n\n\t\tif conn, ok := existingConn[remoteAddr]; ok {\n\t\t\tspec.Conn = conn.NewRef()\n\n\t\t\tl.Debug(\"reusing existing upstream connection\", zap.String(\"addr\", remoteAddr))\n\n\t\t\treturn\n\t\t}\n\n\t\tspec.Conn = network.NewDNSConn(proxy.NewProxy(remoteHost, remoteAddr, \"dns\"))\n\n\t\tl.Debug(\"created new upstream connection\", zap.String(\"addr\", remoteAddr))\n\n\t\texistingConn[remoteAddr] = spec.Conn\n\t}, nil\n}\n\nfunc cleanupUpstream(ctx context.Context, r controller.Runtime, touchedIDs map[resource.ID]struct{}, l *zap.Logger) {\n\tlist, err := safe.ReaderListAll[*network.DNSUpstream](ctx, r)\n\tif err != nil {\n\t\tl.Error(\"error listing upstreams\", zap.Error(err))\n\n\t\treturn\n\t}\n\n\tfor val := range list.All() {\n\t\tmd := val.Metadata()\n\n\t\tif _, ok := touchedIDs[md.ID()]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif conn := val.TypedSpec().Value.Conn; conn != nil {\n\t\t\tconn.Close()\n\t\t}\n\n\t\tif err = r.Destroy(ctx, md); err != nil {\n\t\t\tl.Error(\"error destroying upstream\", zap.Error(err), zap.String(\"id\", md.ID()))\n\n\t\t\treturn\n\t\t}\n\n\t\tl.Debug(\"destroyed dns upstream\", zap.String(\"addr\", md.ID()))\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/etcfile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"iter\"\n\t\"maps\"\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\tefiles \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/files\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// EtcFileController creates /etc/hostname and /etc/resolv.conf files based on finalized network configuration.\ntype EtcFileController struct {\n\tV1Alpha1Mode runtime.Mode\n\n\tEtcRoot          xfs.Root\n\tBindMountTarget  string\n\tbindMountCreated bool\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Name() string {\n\treturn \"network.EtcFileController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.ResolverStatusType,\n\t\t\tID:        optional.Some(network.ResolverID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.NodeAddressDefaultID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostDNSConfigType,\n\t\t\tID:        optional.Some(network.HostDNSConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EtcFileController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\thostnameStatus, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting hostname status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tnodeAddressStatus, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressDefaultID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting network address status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tresolverStatus, err := safe.ReaderGetByID[*network.ResolverStatus](ctx, r, network.ResolverID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error resolver status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\thostDNSCfg, err := safe.ReaderGetByID[*network.HostDNSConfig](ctx, r, network.HostDNSConfigID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting host dns config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif resolverStatus != nil && hostDNSCfg != nil && !ctrl.V1Alpha1Mode.InContainer() {\n\t\t\t// in container mode, keep the original resolv.conf to use the resolvers supplied by the container runtime\n\t\t\tif err = safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"resolv.conf\"),\n\t\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\t\tr.TypedSpec().Contents = renderResolvConf(\n\t\t\t\t\t\tpickNameservers(hostDNSCfg, resolverStatus),\n\t\t\t\t\t\tresolverStatus.TypedSpec().SearchDomains,\n\t\t\t\t\t)\n\t\t\t\t\tr.TypedSpec().Mode = 0o644\n\t\t\t\t\tr.TypedSpec().SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resolv.conf: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif resolverStatus != nil && hostDNSCfg != nil {\n\t\t\tdnsServers := xslices.FilterInPlace(\n\t\t\t\t[]netip.Addr{hostDNSCfg.TypedSpec().ServiceHostDNSAddress},\n\t\t\t\tnetip.Addr.IsValid,\n\t\t\t)\n\n\t\t\tif len(dnsServers) == 0 {\n\t\t\t\tdnsServers = resolverStatus.TypedSpec().DNSServers\n\t\t\t}\n\n\t\t\tsrc := \"resolv.conf\"\n\t\t\tdst := filepath.Join(ctrl.BindMountTarget, src)\n\n\t\t\tconf := renderResolvConf(slices.All(dnsServers), resolverStatus.TypedSpec().SearchDomains)\n\n\t\t\tif err := efiles.UpdateFile(ctrl.EtcRoot, src, conf, 0o644, constants.EtcSelinuxLabel); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error writing pod resolv.conf: %w\", err)\n\t\t\t}\n\n\t\t\tif ctrl.EtcRoot.FSType() != \"os\" {\n\t\t\t\tif !ctrl.bindMountCreated {\n\t\t\t\t\tif err := createBindMountFileFd(ctrl.EtcRoot, src, dst, 0o644); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to create shadow bind mount %q -> %q: %w\", src, dst, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tctrl.bindMountCreated = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, \"hosts\"),\n\t\t\tfunc(r *files.EtcFileSpec) error {\n\t\t\t\tr.TypedSpec().Contents, err = ctrl.renderHosts(hostnameStatus, nodeAddressStatus, cfgProvider)\n\t\t\t\tr.TypedSpec().Mode = 0o644\n\t\t\t\tr.TypedSpec().SelinuxLabel = constants.EtcSelinuxLabel\n\n\t\t\t\treturn err\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying hosts: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nvar localDNS = xiter.Single2(0, netip.MustParseAddr(\"127.0.0.53\"))\n\nfunc pickNameservers(hostDNSCfg *network.HostDNSConfig, resolverStatus *network.ResolverStatus) iter.Seq2[int, netip.Addr] {\n\tif hostDNSCfg.TypedSpec().Enabled {\n\t\t// local dns resolve cache enabled, route host dns requests to 127.0.0.1\n\t\treturn localDNS\n\t}\n\n\treturn slices.All(resolverStatus.TypedSpec().DNSServers)\n}\n\nfunc renderResolvConf(nameservers iter.Seq2[int, netip.Addr], searchDomains []string) []byte {\n\tvar buf bytes.Buffer\n\n\tfor i, ns := range nameservers {\n\t\tif i >= 3 {\n\t\t\t// only use first 3 nameservers, see MAXNS in https://linux.die.net/man/5/resolv.conf\n\t\t\tbreak\n\t\t}\n\n\t\tfmt.Fprintf(&buf, \"nameserver %s\\n\", ns)\n\t}\n\n\tif len(searchDomains) > 0 {\n\t\tfmt.Fprintf(&buf, \"\\nsearch %s\\n\", strings.Join(searchDomains, \" \"))\n\t}\n\n\treturn buf.Bytes()\n}\n\nfunc (ctrl *EtcFileController) renderHosts(hostnameStatus *network.HostnameStatus, nodeAddressStatus *network.NodeAddress, cfgProvider talosconfig.Config) ([]byte, error) {\n\tvar buf bytes.Buffer\n\n\ttabW := tabwriter.NewWriter(&buf, 0, 0, 1, ' ', 0)\n\n\twrite := func(s string) { tabW.Write([]byte(s)) } //nolint:errcheck\n\n\twrite(\"127.0.0.1\\tlocalhost\\n\")\n\n\tif nodeAddressStatus != nil && hostnameStatus != nil {\n\t\twrite(fmt.Sprintf(\"%s\\t%s\", nodeAddressStatus.TypedSpec().Addresses[0].Addr(), hostnameStatus.TypedSpec().FQDN()))\n\n\t\tif hostnameStatus.TypedSpec().Hostname != hostnameStatus.TypedSpec().FQDN() {\n\t\t\twrite(\" \" + hostnameStatus.TypedSpec().Hostname)\n\t\t}\n\n\t\twrite(\"\\n\")\n\t}\n\n\twrite(\"::1\\tlocalhost ip6-localhost ip6-loopback\\n\")\n\twrite(\"ff02::1\\tip6-allnodes\\n\")\n\twrite(\"ff02::2\\tip6-allrouters\\n\")\n\n\thostMap := map[string][]string{}\n\n\tif cfgProvider != nil {\n\t\tfor _, extraHost := range cfgProvider.NetworkStaticHostConfig() {\n\t\t\thostMap[extraHost.IP()] = append(hostMap[extraHost.IP()], extraHost.Aliases()...)\n\t\t}\n\t}\n\n\tfor _, addr := range slices.Sorted(maps.Keys(hostMap)) {\n\t\twrite(fmt.Sprintf(\"%s\\t%s\\n\", addr, strings.Join(hostMap[addr], \" \")))\n\t}\n\n\tif err := tabW.Flush(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\n// createBindMountFileFd creates a common way to create a writable source file with a\n// bind mounted destination.\nfunc createBindMountFileFd(root xfs.Root, src, dst string, mode os.FileMode) (err error) {\n\tif err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {\n\t\treturn fmt.Errorf(\"error creating bind mount dir for resolv.conf: %w\", err)\n\t}\n\n\tf, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating bind mount target %q for resolv.conf: %w\", dst, err)\n\t}\n\n\tif err := f.Close(); err != nil {\n\t\treturn fmt.Errorf(\"error closing bind mount target %q for resolv.conf: %w\", dst, err)\n\t}\n\n\tif err = xfs.MkdirAll(root, filepath.Dir(src), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tfsrc, err := xfs.OpenFile(root, src, os.O_WRONLY|os.O_CREATE, mode)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer fsrc.Close() //nolint:errcheck\n\n\treturn mount.BindReadonlyFd(int(fsrc.Fd()), dst)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/etcfile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\ntype EtcFileConfigSuite struct {\n\tctest.DefaultSuite\n\n\tcfg            *config.MachineConfig\n\tdefaultAddress *network.NodeAddress\n\thostnameStatus *network.HostnameStatus\n\tresolverStatus *network.ResolverStatus\n\thostDNSConfig  *network.HostDNSConfig\n\n\tbindMountTarget   string\n\tpodResolvConfPath string\n\tetcRoot           xfs.Root\n}\n\nfunc (suite *EtcFileConfigSuite) ExtraSetup() {\n\tok, err := v1alpha1runtime.KernelCapabilities().OpentreeOnAnonymousFS()\n\tsuite.Require().NoError(err)\n\n\tif ok {\n\t\tsuite.etcRoot = &xfs.UnixRoot{FS: opentree.NewFromPath(suite.T().TempDir())}\n\t\tsuite.bindMountTarget = suite.T().TempDir()\n\t\tsuite.podResolvConfPath = filepath.Join(suite.bindMountTarget, \"resolv.conf\")\n\t} else {\n\t\tsuite.etcRoot = &xfs.OSRoot{Shadow: suite.T().TempDir()}\n\t\tsuite.podResolvConfPath = filepath.Join(suite.etcRoot.Source(), \"resolv.conf\")\n\t}\n\n\tsuite.Require().NoError(suite.etcRoot.OpenFS())\n\tsuite.Assert().NoFileExists(suite.podResolvConfPath)\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.EtcFileController{\n\t\tV1Alpha1Mode:    v1alpha1runtime.ModeMetal,\n\t\tEtcRoot:         suite.etcRoot,\n\t\tBindMountTarget: suite.bindMountTarget,\n\t}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tsuite.cfg = config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tExtraHostEntries: []*v1alpha1.ExtraHost{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tHostIP:      \"10.0.0.1\",\n\t\t\t\t\t\t\t\tHostAliases: []string{\"a\", \"b\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tHostIP:      \"10.0.0.2\",\n\t\t\t\t\t\t\t\tHostAliases: []string{\"c\", \"d\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.defaultAddress = network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID)\n\tsuite.defaultAddress.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"33.11.22.44/32\")}\n\n\tsuite.hostnameStatus = network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\tsuite.hostnameStatus.TypedSpec().Hostname = \"foo\"\n\tsuite.hostnameStatus.TypedSpec().Domainname = \"example.com\"\n\n\tsuite.resolverStatus = network.NewResolverStatus(network.NamespaceName, network.ResolverID)\n\tsuite.resolverStatus.TypedSpec().DNSServers = []netip.Addr{\n\t\tnetip.MustParseAddr(\"1.1.1.1\"),\n\t\tnetip.MustParseAddr(\"2.2.2.2\"),\n\t\tnetip.MustParseAddr(\"3.3.3.3\"),\n\t\tnetip.MustParseAddr(\"4.4.4.4\"),\n\t}\n\n\tsuite.hostDNSConfig = network.NewHostDNSConfig(network.HostDNSConfigID)\n\tsuite.hostDNSConfig.TypedSpec().Enabled = true\n\tsuite.hostDNSConfig.TypedSpec().ListenAddresses = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"127.0.0.53:53\"),\n\t\tnetip.MustParseAddrPort(\"169.254.116.108:53\"),\n\t}\n\tsuite.hostDNSConfig.TypedSpec().ServiceHostDNSAddress = netip.MustParseAddr(\"169.254.116.108\")\n}\n\ntype etcFileContents struct {\n\thosts            string\n\tresolvConf       string\n\tresolvGlobalConf string\n}\n\n//nolint:gocyclo\nfunc (suite *EtcFileConfigSuite) testFiles(resources []resource.Resource, contents etcFileContents) {\n\tfor _, r := range resources {\n\t\tsuite.Create(r)\n\t}\n\n\tvar (\n\t\texpectedIDs   []string\n\t\tunexpectedIDs []string\n\t)\n\n\tif contents.resolvConf != \"\" {\n\t\texpectedIDs = append(expectedIDs, \"resolv.conf\")\n\t} else {\n\t\tunexpectedIDs = append(unexpectedIDs, \"resolv.conf\")\n\t}\n\n\tif contents.hosts != \"\" {\n\t\texpectedIDs = append(expectedIDs, \"hosts\")\n\t} else {\n\t\tunexpectedIDs = append(unexpectedIDs, \"hosts\")\n\t}\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\texpectedIDs,\n\t\tfunc(r *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"hosts\":\n\t\t\t\tasrt.Equal(contents.hosts, string(r.TypedSpec().Contents))\n\t\t\tcase \"resolv.conf\":\n\t\t\t\tasrt.Equal(contents.resolvConf, string(r.TypedSpec().Contents))\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tif contents.resolvGlobalConf == \"\" {\n\t\t\t\t_, err := os.Lstat(suite.podResolvConfPath)\n\n\t\t\t\tswitch {\n\t\t\t\tcase err == nil:\n\t\t\t\t\treturn retry.ExpectedErrorf(\"unexpected pod %s\", suite.podResolvConfPath)\n\t\t\t\tcase errors.Is(err, os.ErrNotExist):\n\t\t\t\t\treturn nil\n\t\t\t\tdefault:\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfile, err := os.ReadFile(suite.podResolvConfPath)\n\n\t\t\tswitch {\n\t\t\tcase errors.Is(err, os.ErrNotExist):\n\t\t\t\treturn retry.ExpectedErrorf(\"missing pod %s\", suite.podResolvConfPath)\n\t\t\tcase err != nil:\n\t\t\t\treturn err\n\t\t\tcase len(file) == 0:\n\t\t\t\treturn retry.ExpectedErrorf(\"empty pod %s\", suite.podResolvConfPath)\n\t\t\tdefault:\n\t\t\t\tsuite.Assert().Equal(contents.resolvGlobalConf, string(file))\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}),\n\t)\n\n\tfor _, id := range unexpectedIDs {\n\t\tctest.AssertNoResource[*files.EtcFileSpec](suite, id)\n\t}\n}\n\nfunc (suite *EtcFileConfigSuite) TestComplete() {\n\tsuite.resolverStatus.TypedSpec().SearchDomains = []string{\"foo.example.com\"}\n\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo.example.com foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n10.0.0.1    a b\\n10.0.0.2    c d\\n\", //nolint:lll\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\\nsearch foo.example.com\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\\nsearch foo.example.com\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestExtraHostsNoHostname() {\n\tsuite.resolverStatus.TypedSpec().SearchDomains = []string{\"foo.example.com\"}\n\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.cfg, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1 localhost\\n::1       localhost ip6-localhost ip6-loopback\\nff02::1   ip6-allnodes\\nff02::2   ip6-allrouters\\n10.0.0.1  a b\\n10.0.0.2  c d\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\\nsearch foo.example.com\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\\nsearch foo.example.com\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestNoExtraHosts() {\n\tsuite.resolverStatus.TypedSpec().SearchDomains = []string{\"foo.example.com\"}\n\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo.example.com foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\\nsearch foo.example.com\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\\nsearch foo.example.com\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestNoSearchDomainLegacy() {\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkDisableSearchDomain: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\tsuite.testFiles(\n\t\t[]resource.Resource{cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo.example.com foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestNoSearchDomainNewStyle() {\n\thc := networkcfg.NewResolverConfigV1Alpha1()\n\thc.ResolverSearchDomains = networkcfg.SearchDomainsConfig{\n\t\tSearchDisableDefault: new(true),\n\t}\n\n\tctr, err := container.New(hc)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\n\tsuite.testFiles(\n\t\t[]resource.Resource{cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo.example.com foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestNoDomainname() {\n\tsuite.hostnameStatus.TypedSpec().Domainname = \"\"\n\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestOnlyResolvers() {\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.resolverStatus, suite.hostDNSConfig},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1 localhost\\n::1       localhost ip6-localhost ip6-loopback\\nff02::1   ip6-allnodes\\nff02::2   ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"nameserver 127.0.0.53\\n\",\n\t\t\tresolvGlobalConf: \"nameserver 169.254.116.108\\n\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) TestOnlyHostname() {\n\tsuite.testFiles(\n\t\t[]resource.Resource{suite.defaultAddress, suite.hostnameStatus},\n\t\tetcFileContents{\n\t\t\thosts:            \"127.0.0.1   localhost\\n33.11.22.44 foo.example.com foo\\n::1         localhost ip6-localhost ip6-loopback\\nff02::1     ip6-allnodes\\nff02::2     ip6-allrouters\\n\",\n\t\t\tresolvConf:       \"\",\n\t\t\tresolvGlobalConf: \"\",\n\t\t},\n\t)\n}\n\nfunc (suite *EtcFileConfigSuite) ExtraTearDown() {\n\tif _, err := os.Lstat(suite.podResolvConfPath); err == nil {\n\t\tif suite.etcRoot.FSType() == \"os\" {\n\t\t\tsuite.Require().NoError(os.Remove(suite.podResolvConfPath))\n\t\t} else {\n\t\t\tsuite.Require().NoError(mount.SafeUnmount(context.Background(), nil, suite.podResolvConfPath, false))\n\t\t}\n\t}\n\n\tif suite.etcRoot != nil {\n\t\tsuite.Require().NoError(os.RemoveAll(suite.bindMountTarget))\n\n\t\tsuite.etcRoot.Close() //nolint:errcheck\n\t}\n}\n\nfunc TestEtcFileConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\ts := &EtcFileConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t},\n\t}\n\n\ts.AfterSetup = func(*ctest.DefaultSuite) {\n\t\ts.ExtraSetup()\n\t}\n\n\ts.AfterTearDown = func(*ctest.DefaultSuite) {\n\t\ts.ExtraTearDown()\n\t}\n\n\tsuite.Run(t, s)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/ethernet_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tconfigtypes \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EthernetConfigController manages network.EthernetSpec based on machine configuration.\ntype EthernetConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EthernetConfigController) Name() string {\n\treturn \"network.EthernetConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EthernetConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EthernetConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.EthernetSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *EthernetConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error reading machine configuration: %w\", err)\n\t\t}\n\n\t\tif cfg != nil {\n\t\t\tif err = ctrl.apply(ctx, r, cfg.Config().EthernetConfigs()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying EthernetSpec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.EthernetSpec](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up EthernetSpec: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *EthernetConfigController) apply(ctx context.Context, r controller.Runtime, configs []configtypes.EthernetConfig) error {\n\tfor _, cfg := range configs {\n\t\tif err := safe.WriterModify(ctx, r, network.NewEthernetSpec(network.NamespaceName, cfg.Name()), func(spec *network.EthernetSpec) error {\n\t\t\tspec.TypedSpec().Rings = network.EthernetRingsSpec(cfg.Rings())\n\t\t\tspec.TypedSpec().Channels = network.EthernetChannelsSpec(cfg.Channels())\n\t\t\tspec.TypedSpec().Features = cfg.Features()\n\t\t\tspec.TypedSpec().WakeOnLAN = cfg.WakeOnLAN()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing EthernetSpec: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/ethernet_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype EthernetConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *EthernetConfigSuite) TestReconcile() {\n\tcfg1 := networkcfg.NewEthernetConfigV1Alpha1(\"enp0s1\")\n\tcfg1.ChannelsConfig = &networkcfg.EthernetChannelsConfig{\n\t\tRX: new(uint32(4)),\n\t}\n\n\tctr, err := container.New(cfg1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, \"enp0s1\", func(spec *network.EthernetSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(uint32(4), pointer.SafeDeref(spec.TypedSpec().Channels.RX))\n\t})\n\n\tcfg2 := networkcfg.NewEthernetConfigV1Alpha1(\"enp0s2\")\n\tcfg2.FeaturesConfig = map[string]bool{\n\t\t\"tx-checksum-ipv4\": true,\n\t}\n\tcfg2.RingsConfig = &networkcfg.EthernetRingsConfig{\n\t\tRX: new(uint32(16)),\n\t}\n\n\tctr, err = container.New(cfg1, cfg2)\n\tsuite.Require().NoError(err)\n\n\tcfgNew := config.NewMachineConfig(ctr)\n\tcfgNew.Metadata().SetVersion(cfg.Metadata().Version())\n\tsuite.Update(cfgNew)\n\n\tctest.AssertResource(suite, \"enp0s1\", func(spec *network.EthernetSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(uint32(4), pointer.SafeDeref(spec.TypedSpec().Channels.RX))\n\t})\n\tctest.AssertResource(suite, \"enp0s2\", func(spec *network.EthernetSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(uint32(16), pointer.SafeDeref(spec.TypedSpec().Rings.RX))\n\t\tasrt.Equal(true, spec.TypedSpec().Features[\"tx-checksum-ipv4\"])\n\t})\n\n\tsuite.Destroy(cfgNew)\n\n\tctest.AssertNoResource[*network.EthernetSpec](suite, \"enp0s1\")\n\tctest.AssertNoResource[*network.EthernetSpec](suite, \"enp0s2\")\n}\n\nfunc TestEthernetConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &EthernetConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.EthernetConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/ethernet_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/mdlayher/ethtool\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EthernetSpecController reports Ethernet link statuses.\ntype EthernetSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EthernetSpecController) Name() string {\n\treturn \"network.EthernetSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EthernetSpecController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EthernetSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *EthernetSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy, which implies that all link renames are done\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.EthernetSpecType,\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\tethClient, err := ethtool.New()\n\tif err != nil {\n\t\tlogger.Warn(\"error dialing ethtool socket\", zap.Error(err))\n\n\t\treturn nil\n\t}\n\n\tdefer ethClient.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tspecs, err := safe.ReaderListAll[*network.EthernetSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading EthernetSpec resources: %w\", err)\n\t\t}\n\n\t\tvar errs error\n\n\t\tfor spec := range specs.All() {\n\t\t\tif err = ctrl.apply(ethClient, spec); err != nil {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error configuring %q: %w\", spec.Metadata().ID(), err))\n\t\t\t}\n\t\t}\n\n\t\tif errs != nil {\n\t\t\treturn fmt.Errorf(\"failed to reconcile Ethernet specs: %w\", errs)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc optionalFromPtr[T any](ptr *T) optional.Optional[T] {\n\tif ptr == nil {\n\t\treturn optional.None[T]()\n\t}\n\n\treturn optional.Some(*ptr)\n}\n\nfunc (ctrl *EthernetSpecController) apply(\n\tethClient *ethtool.Client,\n\tspec *network.EthernetSpec,\n) error {\n\tringSpec := spec.TypedSpec().Rings\n\n\tif !value.IsZero(ringSpec) {\n\t\tif err := ethClient.SetRings(ethtool.Rings{\n\t\t\tInterface: ethtool.Interface{\n\t\t\t\tName: spec.Metadata().ID(),\n\t\t\t},\n\t\t\tRX:           optionalFromPtr(ringSpec.RX),\n\t\t\tRXMini:       optionalFromPtr(ringSpec.RXMini),\n\t\t\tRXJumbo:      optionalFromPtr(ringSpec.RXJumbo),\n\t\t\tTX:           optionalFromPtr(ringSpec.TX),\n\t\t\tRXBufLen:     optionalFromPtr(ringSpec.RXBufLen),\n\t\t\tCQESize:      optionalFromPtr(ringSpec.CQESize),\n\t\t\tTXPush:       optionalFromPtr(ringSpec.TXPush),\n\t\t\tRXPush:       optionalFromPtr(ringSpec.RXPush),\n\t\t\tTXPushBufLen: optionalFromPtr(ringSpec.TXPushBufLen),\n\t\t\tTCPDataSplit: optionalFromPtr(ringSpec.TCPDataSplit),\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating rings: %w\", err)\n\t\t}\n\t}\n\n\tfeatureSpec := spec.TypedSpec().Features\n\n\tif len(featureSpec) > 0 {\n\t\tif err := ethClient.SetFeatures(\n\t\t\tethtool.Interface{\n\t\t\t\tName: spec.Metadata().ID(),\n\t\t\t},\n\t\t\tfeatureSpec,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating features: %w\", err)\n\t\t}\n\t}\n\n\tchannelsSpec := spec.TypedSpec().Channels\n\n\tif !value.IsZero(channelsSpec) {\n\t\tif err := ethClient.SetChannels(ethtool.Channels{\n\t\t\tInterface: ethtool.Interface{\n\t\t\t\tName: spec.Metadata().ID(),\n\t\t\t},\n\t\t\tRXCount:       optionalFromPtr(channelsSpec.RX),\n\t\t\tTXCount:       optionalFromPtr(channelsSpec.TX),\n\t\t\tOtherCount:    optionalFromPtr(channelsSpec.Other),\n\t\t\tCombinedCount: optionalFromPtr(channelsSpec.Combined),\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating channels: %w\", err)\n\t\t}\n\t}\n\n\tif spec.TypedSpec().WakeOnLAN != nil {\n\t\tvar wolModes nethelpers.WOLMode\n\n\t\tfor _, mode := range spec.TypedSpec().WakeOnLAN {\n\t\t\twolModes |= mode\n\t\t}\n\n\t\tif err := ethClient.SetWakeOnLAN(ethtool.WakeOnLAN{\n\t\t\tInterface: ethtool.Interface{\n\t\t\t\tName: spec.Metadata().ID(),\n\t\t\t},\n\t\t\tModes: ethtool.WOLMode(wolModes),\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating wake-on-lan: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/ethernet_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/mdlayher/ethtool\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EthernetStatusController reports Ethernet link statuses.\ntype EthernetStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EthernetStatusController) Name() string {\n\treturn \"network.EthernetStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EthernetStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EthernetStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.EthernetStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *EthernetStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy, which implies that all link renames are done\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.LinkSpecType,\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\t// create watch connections to ethtool via genetlink\n\t// these connections are used only to join multicast groups and receive notifications on changes\n\t// other connections are used to send requests and receive responses, as we can't mix the notifications and request/responses\n\tethtoolWatcher, err := watch.NewEthtool(watch.NewDefaultRateLimitedTrigger(ctx, r))\n\tif err != nil {\n\t\tlogger.Warn(\"ethtool watcher failed to start\", zap.Error(err))\n\n\t\treturn nil\n\t}\n\n\tdefer ethtoolWatcher.Done()\n\n\tethClient, err := ethtool.New()\n\tif err != nil {\n\t\tlogger.Warn(\"error dialing ethtool socket\", zap.Error(err))\n\n\t\treturn nil\n\t}\n\n\tdefer ethClient.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif err = ctrl.reconcile(ctx, r, logger, ethClient); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.EthernetStatus](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// reconcile function runs for every reconciliation loop querying the ethtool state and updating resources.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *EthernetStatusController) reconcile(\n\tctx context.Context,\n\tr controller.Runtime,\n\tlogger *zap.Logger,\n\tethClient *ethtool.Client,\n) error {\n\tlinkInfos, err := ethClient.LinkInfos()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t}\n\n\tfor _, linkInfo := range linkInfos {\n\t\tiface := linkInfo.Interface\n\n\t\tlgger := logger.With(zap.String(\"interface\", iface.Name))\n\n\t\tlinkState, err := ethClient.LinkState(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting link state\", zap.Error(err))\n\t\t}\n\n\t\tlinkMode, err := ethClient.LinkMode(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting link mode\", zap.Error(err))\n\t\t}\n\n\t\trings, err := ethClient.Rings(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting rings\", zap.Error(err))\n\t\t}\n\n\t\tfeatures, err := ethClient.Features(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting features\", zap.Error(err))\n\t\t}\n\n\t\tchannels, err := ethClient.Channels(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting channels\", zap.Error(err))\n\t\t}\n\n\t\twolMode, err := ethClient.WakeOnLAN(iface)\n\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\tlgger.Warn(\"error getting Wake-on-LAN\", zap.Error(err))\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, network.NewEthernetStatus(network.NamespaceName, iface.Name), func(res *network.EthernetStatus) error {\n\t\t\tres.TypedSpec().Port = nethelpers.Port(linkInfo.Port)\n\n\t\t\tif linkMode != nil {\n\t\t\t\tres.TypedSpec().Duplex = nethelpers.Duplex(linkMode.Duplex)\n\t\t\t\tres.TypedSpec().OurModes = xslices.Map(linkMode.Ours, func(m ethtool.AdvertisedLinkMode) string { return m.Name })\n\t\t\t\tres.TypedSpec().PeerModes = xslices.Map(linkMode.Peer, func(m ethtool.AdvertisedLinkMode) string { return m.Name })\n\t\t\t} else {\n\t\t\t\tres.TypedSpec().Duplex = nethelpers.Duplex(0)\n\t\t\t}\n\n\t\t\tif linkState == nil {\n\t\t\t\tres.TypedSpec().LinkState = nil\n\t\t\t} else {\n\t\t\t\tres.TypedSpec().LinkState = new(linkState.Link)\n\t\t\t}\n\n\t\t\tif rings == nil {\n\t\t\t\tres.TypedSpec().Rings = nil\n\t\t\t} else {\n\t\t\t\tres.TypedSpec().Rings = &network.EthernetRingsStatus{\n\t\t\t\t\tRXMax:           rings.RXMax.Ptr(),\n\t\t\t\t\tRXMiniMax:       rings.RXMiniMax.Ptr(),\n\t\t\t\t\tRXJumboMax:      rings.RXJumboMax.Ptr(),\n\t\t\t\t\tTXMax:           rings.TXMax.Ptr(),\n\t\t\t\t\tTXPushBufLenMax: rings.TXPushBufLenMax.Ptr(),\n\t\t\t\t\tRX:              rings.RX.Ptr(),\n\t\t\t\t\tRXMini:          rings.RXMini.Ptr(),\n\t\t\t\t\tRXJumbo:         rings.RXJumbo.Ptr(),\n\t\t\t\t\tTX:              rings.TX.Ptr(),\n\t\t\t\t\tRXBufLen:        rings.RXBufLen.Ptr(),\n\t\t\t\t\tCQESize:         rings.CQESize.Ptr(),\n\t\t\t\t\tTXPush:          rings.TXPush.Ptr(),\n\t\t\t\t\tRXPush:          rings.RXPush.Ptr(),\n\t\t\t\t\tTXPushBufLen:    rings.TXPushBufLen.Ptr(),\n\t\t\t\t\tTCPDataSplit:    rings.TCPDataSplit.Ptr(),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif features == nil {\n\t\t\t\tres.TypedSpec().Features = nil\n\t\t\t} else {\n\t\t\t\tres.TypedSpec().Features = xslices.Map(features, func(f ethtool.FeatureInfo) network.EthernetFeatureStatus {\n\t\t\t\t\treturn network.EthernetFeatureStatus{\n\t\t\t\t\t\tName:   f.Name,\n\t\t\t\t\t\tStatus: f.State() + f.Suffix(),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif channels == nil {\n\t\t\t\tres.TypedSpec().Channels = nil\n\t\t\t} else {\n\t\t\t\tres.TypedSpec().Channels = &network.EthernetChannelsStatus{\n\t\t\t\t\tRXMax:       channels.RXMax.Ptr(),\n\t\t\t\t\tTXMax:       channels.TXMax.Ptr(),\n\t\t\t\t\tOtherMax:    channels.OtherMax.Ptr(),\n\t\t\t\t\tCombinedMax: channels.CombinedMax.Ptr(),\n\n\t\t\t\t\tRX:       channels.RXCount.Ptr(),\n\t\t\t\t\tTX:       channels.TXCount.Ptr(),\n\t\t\t\t\tOther:    channels.OtherCount.Ptr(),\n\t\t\t\t\tCombined: channels.CombinedCount.Ptr(),\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tres.TypedSpec().WakeOnLAN = nil\n\n\t\t\tif wolMode != nil {\n\t\t\t\tfor mode := nethelpers.WOLModeMin; mode <= nethelpers.WOLModeMax; mode <<= 1 {\n\t\t\t\t\tif (nethelpers.WOLMode(wolMode.Modes) & mode) == mode {\n\t\t\t\t\t\tres.TypedSpec().WakeOnLAN = append(res.TypedSpec().WakeOnLAN, mode)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating EthernetStatus resource: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/generic_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n)\n\ntype genericMergeFunc[T typed.DeepCopyable[T], E typed.Extension] func(logger *zap.Logger, in safe.List[*typed.Resource[T, E]]) map[resource.ID]*T\n\n// GenericMergeController initializes a generic merge controller for network resources.\nfunc GenericMergeController[T typed.DeepCopyable[T], E typed.Extension](namespaceIn, namespaceOut resource.Namespace, mergeFunc genericMergeFunc[T, E]) controller.Controller {\n\tvar zeroE E\n\n\tcontrollerName := strings.ReplaceAll(zeroE.ResourceDefinition().Type, \"Spec\", \"MergeController\")\n\n\treturn &genericMergeController[T, E]{\n\t\tcontrollerName: controllerName,\n\t\tresourceType:   zeroE.ResourceDefinition().Type,\n\t\tnamespaceIn:    namespaceIn,\n\t\tnamespaceOut:   namespaceOut,\n\t\tmergeFunc:      mergeFunc,\n\t}\n}\n\ntype genericMergeController[T typed.DeepCopyable[T], E typed.Extension] struct {\n\tcontrollerName string\n\tresourceType   resource.Type\n\tnamespaceIn    resource.Namespace\n\tnamespaceOut   resource.Namespace\n\tmergeFunc      genericMergeFunc[T, E]\n}\n\nfunc (ctrl *genericMergeController[T, E]) Name() string {\n\treturn ctrl.controllerName\n}\n\nfunc (ctrl *genericMergeController[T, E]) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: ctrl.namespaceIn,\n\t\t\tType:      ctrl.resourceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: ctrl.namespaceOut,\n\t\t\tType:      ctrl.resourceType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\nfunc (ctrl *genericMergeController[T, E]) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: ctrl.resourceType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *genericMergeController[T, E]) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\ttype R = typed.Resource[T, E]\n\n\t\t// list source network configuration resources\n\t\tin, err := safe.ReaderList[*R](ctx, r, resource.NewMetadata(ctrl.namespaceIn, ctrl.resourceType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network resources: %w\", err)\n\t\t}\n\n\t\tmerged := ctrl.mergeFunc(logger, in)\n\n\t\t// cleanup resources, detecting conflicts on the way\n\t\tout, err := safe.ReaderList[*R](ctx, r, resource.NewMetadata(ctrl.namespaceOut, ctrl.resourceType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing output resources: %w\", err)\n\t\t}\n\n\t\tfor res := range out.All() {\n\t\t\tshouldBeDestroyed := false\n\t\t\tif _, ok := merged[res.Metadata().ID()]; !ok {\n\t\t\t\tshouldBeDestroyed = true\n\t\t\t}\n\n\t\t\tisTearingDown := res.Metadata().Phase() == resource.PhaseTearingDown\n\n\t\t\tif shouldBeDestroyed || isTearingDown {\n\t\t\t\tvar okToDestroy bool\n\n\t\t\t\tokToDestroy, err = r.Teardown(ctx, res.Metadata())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up addresses: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif okToDestroy {\n\t\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error cleaning up addresses: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t} else if !shouldBeDestroyed {\n\t\t\t\t\t// resource is not ready to be destroyed yet, skip it\n\t\t\t\t\tdelete(merged, res.Metadata().ID())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvar zeroT T\n\n\t\tfor id, spec := range merged {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\ttyped.NewResource[T, E](resource.NewMetadata(ctrl.namespaceOut, ctrl.resourceType, id, resource.VersionUndefined), zeroT),\n\t\t\t\tfunc(r *R) error {\n\t\t\t\t\t*r.TypedSpec() = *spec\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating resource: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Debug(\"merged spec\", zap.String(\"id\", id), zap.Any(\"spec\", spec))\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hardware_addr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// HardwareAddrController manages secrets.Etcd based on configuration.\ntype HardwareAddrController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *HardwareAddrController) Name() string {\n\treturn \"network.HardwareAddrController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *HardwareAddrController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *HardwareAddrController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.HardwareAddrType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *HardwareAddrController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list the existing HardwareAddr resources and mark them all to be deleted, as the actual link is discovered via netlink, resource ID is removed from the list\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\titemsToDelete := map[resource.ID]struct{}{}\n\n\t\tfor _, r := range list.Items {\n\t\t\titemsToDelete[r.Metadata().ID()] = struct{}{}\n\t\t}\n\n\t\t// list links and find the first physical link\n\t\tlinks, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range links.Items {\n\t\t\tlink := res.(*network.LinkStatus) //nolint:forcetypeassert\n\n\t\t\tif !link.TypedSpec().Physical() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr), func(r *network.HardwareAddr) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\tspec.HardwareAddr = link.TypedSpec().HardwareAddr\n\t\t\t\tspec.Name = link.Metadata().ID()\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t\t}\n\n\t\t\tdelete(itemsToDelete, network.FirstHardwareAddr)\n\n\t\t\t// as link status are listed in sorted order, first physical link in the list is the one we need\n\t\t\tbreak\n\t\t}\n\n\t\tfor id := range itemsToDelete {\n\t\t\tif err = r.Destroy(ctx, resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, id, resource.VersionUndefined)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting resource %q: %w\", id, err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hardware_addr_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype HardwareAddrSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *HardwareAddrSuite) TestFirst() {\n\tmustParseMAC := func(addr string) nethelpers.HardwareAddr {\n\t\tmac, err := net.ParseMAC(addr)\n\t\tsuite.Require().NoError(err)\n\n\t\treturn nethelpers.HardwareAddr(mac)\n\t}\n\n\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\teth0.TypedSpec().Type = nethelpers.LinkEther\n\teth0.TypedSpec().HardwareAddr = mustParseMAC(\"56:a0:a0:87:1c:fa\")\n\n\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\teth1.TypedSpec().Type = nethelpers.LinkEther\n\teth1.TypedSpec().HardwareAddr = mustParseMAC(\"6a:2b:bd:b2:fc:e0\")\n\n\tbond0 := network.NewLinkStatus(network.NamespaceName, \"bond0\")\n\tbond0.TypedSpec().Type = nethelpers.LinkEther\n\tbond0.TypedSpec().Kind = \"bond\"\n\tbond0.TypedSpec().HardwareAddr = mustParseMAC(\"56:a0:a0:87:1c:fb\")\n\n\tsuite.Create(bond0)\n\tsuite.Create(eth1)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\tnetwork.FirstHardwareAddr,\n\t\tfunc(r *network.HardwareAddr, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(eth1.Metadata().ID(), r.TypedSpec().Name)\n\t\t\tasrt.Equal(\"6a:2b:bd:b2:fc:e0\", net.HardwareAddr(r.TypedSpec().HardwareAddr).String())\n\t\t},\n\t)\n\n\tsuite.Create(eth0)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\tnetwork.FirstHardwareAddr,\n\t\tfunc(r *network.HardwareAddr, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(eth0.Metadata().ID(), r.TypedSpec().Name)\n\t\t\tasrt.Equal(\"56:a0:a0:87:1c:fa\", net.HardwareAddr(r.TypedSpec().HardwareAddr).String())\n\t\t},\n\t)\n\n\tsuite.Destroy(eth0)\n\tsuite.Destroy(eth1)\n\n\tctest.AssertNoResource[*network.HardwareAddr](suite, network.FirstHardwareAddr)\n}\n\nfunc TestHardwareAddrSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &HardwareAddrSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HardwareAddrController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostdns_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// HostDNSConfigController manages network.HostDNSConfig based on machine configuration.\ntype HostDNSConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *HostDNSConfigController) Name() string {\n\treturn \"network.HostDNSConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *HostDNSConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *HostDNSConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.HostDNSConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *HostDNSConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else if cfg.Config().Machine() != nil {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\tnewServiceAddrs := make([]netip.Addr, 0, 2)\n\n\t\tif err := safe.WriterModify(ctx, r, network.NewHostDNSConfig(network.HostDNSConfigID), func(res *network.HostDNSConfig) error {\n\t\t\tres.TypedSpec().ListenAddresses = []netip.AddrPort{\n\t\t\t\tnetip.MustParseAddrPort(\"127.0.0.53:53\"),\n\t\t\t}\n\n\t\t\tres.TypedSpec().ServiceHostDNSAddress = netip.Addr{}\n\n\t\t\tif cfgProvider == nil {\n\t\t\t\tres.TypedSpec().Enabled = false\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tres.TypedSpec().Enabled = cfgProvider.Machine().Features().HostDNS().Enabled()\n\t\t\tres.TypedSpec().ResolveMemberNames = cfgProvider.Machine().Features().HostDNS().ResolveMemberNames()\n\n\t\t\tif !cfgProvider.Machine().Features().HostDNS().ForwardKubeDNSToHost() {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif slices.ContainsFunc(\n\t\t\t\tcfgProvider.Cluster().Network().PodCIDRs(),\n\t\t\t\tfunc(cidr string) bool { return netip.MustParsePrefix(cidr).Addr().Is4() },\n\t\t\t) {\n\t\t\t\tparsed := netip.MustParseAddr(constants.HostDNSAddress)\n\t\t\t\tnewServiceAddrs = append(newServiceAddrs, parsed)\n\n\t\t\t\tres.TypedSpec().ListenAddresses = append(res.TypedSpec().ListenAddresses, netip.AddrPortFrom(parsed, 53))\n\t\t\t\tres.TypedSpec().ServiceHostDNSAddress = parsed\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing host dns config: %w\", err)\n\t\t}\n\n\t\tfor _, newServiceAddr := range newServiceAddrs {\n\t\t\terr := updateSpec(ctx, r, newServiceAddr, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.HostDNSConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc updateSpec(ctx context.Context, r controller.Runtime, newServiceAddr netip.Addr, logger *zap.Logger) error {\n\tnewDNSAddrPrefix := netip.PrefixFrom(newServiceAddr, newServiceAddr.BitLen())\n\n\tlogger.Debug(\"creating new host dns address spec\", zap.String(\"address\", newServiceAddr.String()))\n\n\terr := safe.WriterModify(\n\t\tctx,\n\t\tr,\n\t\tnetwork.NewAddressSpec(\n\t\t\tnetwork.ConfigNamespaceName,\n\t\t\tnetwork.LayeredID(network.ConfigOperator, network.AddressID(\"lo\", newDNSAddrPrefix)),\n\t\t),\n\t\tfunc(r *network.AddressSpec) error {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tspec.Address = newDNSAddrPrefix\n\t\t\tspec.ConfigLayer = network.ConfigOperator\n\n\t\t\tif newServiceAddr.Is4() {\n\t\t\t\tspec.Family = nethelpers.FamilyInet4\n\t\t\t} else {\n\t\t\t\tspec.Family = nethelpers.FamilyInet6\n\t\t\t}\n\n\t\t\tspec.Flags = nethelpers.AddressFlags(nethelpers.AddressPermanent)\n\t\t\tspec.LinkName = \"lo\"\n\n\t\t\tif newServiceAddr.Is6() && newServiceAddr.IsPrivate() {\n\t\t\t\tspec.Scope = nethelpers.ScopeGlobal\n\t\t\t} else {\n\t\t\t\tspec.Scope = nethelpers.ScopeHost\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error modifying address: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/martinlindhe/base36\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// HostnameConfigController manages network.HostnameSpec based on machine configuration, kernel cmdline.\ntype HostnameConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *HostnameConfigController) Name() string {\n\treturn \"network.HostnameConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *HostnameConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.NodeAddressDefaultID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: cluster.NamespaceName,\n\t\t\tType:      cluster.IdentityType,\n\t\t\tID:        optional.Some(cluster.LocalIdentity),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *HostnameConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.HostnameSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *HostnameConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\tvar specs []network.HostnameSpecSpec\n\n\t\t// parse kernel cmdline for the default gateway\n\t\tcmdlineHostname := ctrl.parseCmdline(logger)\n\t\tif cmdlineHostname.Hostname != \"\" {\n\t\t\tspecs = append(specs, cmdlineHostname)\n\t\t}\n\n\t\t// parse machine configuration for specs\n\t\tif cfgProvider != nil {\n\t\t\tconfigHostname := ctrl.parseMachineConfiguration(logger, cfgProvider)\n\n\t\t\tif configHostname.Hostname != \"\" {\n\t\t\t\tspecs = append(specs, configHostname)\n\t\t\t}\n\n\t\t\tif cfgProvider.NetworkHostnameConfig() != nil {\n\t\t\t\tswitch cfgProvider.NetworkHostnameConfig().AutoHostname() {\n\t\t\t\tcase nethelpers.AutoHostnameKindOff:\n\t\t\t\tcase nethelpers.AutoHostnameKindAddr:\n\t\t\t\t\tdefaultAddr, err := safe.ReaderGet[*network.NodeAddress](ctx, r, resource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.NodeAddressDefaultID, resource.VersionUndefined))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspecs = append(specs, ctrl.getDefault(defaultAddr))\n\t\t\t\t\t}\n\t\t\t\tcase nethelpers.AutoHostnameKindStable:\n\t\t\t\t\tvar identity *cluster.Identity\n\n\t\t\t\t\tidentity, err = safe.ReaderGet[*cluster.Identity](ctx, r, resource.NewMetadata(cluster.NamespaceName, cluster.IdentityType, cluster.LocalIdentity, resource.VersionUndefined))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error getting local identity: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnodeID := identity.TypedSpec().NodeID\n\n\t\t\t\t\t\tstableHostname := ctrl.getStableDefault(nodeID)\n\t\t\t\t\t\tspecs = append(specs, *stableHostname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = ctrl.apply(ctx, r, specs); err != nil {\n\t\t\treturn fmt.Errorf(\"error applying specs: %w\", err)\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up outputs: %w\", err)\n\t\t}\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *HostnameConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.HostnameSpecSpec) error {\n\tfor _, spec := range specs {\n\t\tid := network.LayeredID(spec.ConfigLayer, network.HostnameID)\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewHostnameSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.HostnameSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *HostnameConfigController) getStableDefault(nodeID string) *network.HostnameSpecSpec {\n\thashBytes := sha256.Sum256([]byte(nodeID))\n\tb36 := strings.ToLower(base36.EncodeBytes(hashBytes[:8]))\n\n\thostname := fmt.Sprintf(\"talos-%s-%s\", b36[1:4], b36[4:7])\n\n\treturn &network.HostnameSpecSpec{\n\t\tHostname:    hostname,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n}\n\nfunc (ctrl *HostnameConfigController) getDefault(defaultAddr *network.NodeAddress) (spec network.HostnameSpecSpec) {\n\tif defaultAddr == nil || len(defaultAddr.TypedSpec().Addresses) != 1 {\n\t\treturn spec\n\t}\n\n\tspec.Hostname = fmt.Sprintf(\"talos-%s\", strings.ReplaceAll(strings.ReplaceAll(defaultAddr.TypedSpec().Addresses[0].Addr().String(), \":\", \"\"), \".\", \"-\"))\n\tspec.ConfigLayer = network.ConfigDefault\n\n\treturn spec\n}\n\nfunc (ctrl *HostnameConfigController) parseCmdline(logger *zap.Logger) (spec network.HostnameSpecSpec) {\n\tif ctrl.Cmdline == nil {\n\t\treturn spec\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, network.NewEmptyLinkResolver())\n\tif err != nil {\n\t\tlogger.Warn(\"ignoring error\", zap.Error(err))\n\n\t\treturn spec\n\t}\n\n\tif settings.Hostname == \"\" {\n\t\treturn spec\n\t}\n\n\tif err = spec.ParseFQDN(settings.Hostname); err != nil {\n\t\tlogger.Warn(\"ignoring error\", zap.Error(err))\n\n\t\treturn network.HostnameSpecSpec{}\n\t}\n\n\tspec.ConfigLayer = network.ConfigCmdline\n\n\treturn spec\n}\n\nfunc (ctrl *HostnameConfigController) parseMachineConfiguration(logger *zap.Logger, cfgProvider talosconfig.Config) (spec network.HostnameSpecSpec) {\n\tvar hostname string\n\n\tif cfgProvider.NetworkHostnameConfig() != nil {\n\t\thostname = cfgProvider.NetworkHostnameConfig().Hostname()\n\t}\n\n\tif hostname == \"\" {\n\t\treturn spec\n\t}\n\n\tif err := spec.ParseFQDN(hostname); err != nil {\n\t\tlogger.Warn(\"ignoring error\", zap.Error(err))\n\n\t\treturn network.HostnameSpecSpec{}\n\t}\n\n\tspec.ConfigLayer = network.ConfigMachineConfiguration\n\n\treturn spec\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype HostnameConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *HostnameConfigSuite) TestNoDefaultWithoutMachineConfig() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\tdefaultAddress := network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID)\n\tdefaultAddress.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"33.11.22.44/32\")}\n\n\tsuite.Create(defaultAddress)\n\n\tctest.AssertNoResource[*network.HostnameSpec](suite, \"default/hostname\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestDefaultIPBasedHostname() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\tsuite.Create(config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{ConfigVersion: \"v1alpha1\"})))\n\n\tdefaultAddress := network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID)\n\tdefaultAddress.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"33.11.22.44/32\")}\n\tsuite.Create(defaultAddress)\n\n\tctest.AssertResource(suite, \"default/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"talos-33-11-22-44\", r.TypedSpec().Hostname)\n\t\tasrt.Equal(\"\", r.TypedSpec().Domainname)\n\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestDefaultStableHostname() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\tsuite.Create(config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\tStableHostname: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t))\n\n\tid := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tid.TypedSpec().NodeID = \"fGdOI05hVrx3YMagLo0Bwxa2Nm9BAswWm8XLeEj0aS4\"\n\tsuite.Create(id)\n\n\tctest.AssertResource(suite, \"default/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"talos-hwz-sw5\", r.TypedSpec().Hostname)\n\t\tasrt.Equal(\"\", r.TypedSpec().Domainname)\n\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.HostnameConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1.domain.tld:eth1::10.0.0.1:10.0.0.2:10.0.0.1\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResource(suite, \"cmdline/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"master1\", r.TypedSpec().Hostname)\n\t\tasrt.Equal(\"domain.tld\", r.TypedSpec().Domainname)\n\t\tasrt.Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestLegacyMachineConfiguration() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkHostname: \"foo\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(\n\t\tsuite, \"configuration/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"foo\", r.TypedSpec().Hostname)\n\t\t\tasrt.Equal(\"\", r.TypedSpec().Domainname)\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t}, rtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error {\n\t\tr.Container().RawV1Alpha1().MachineConfig.MachineNetwork.NetworkHostname = strings.Repeat(\"a\", 128) //nolint:staticcheck // using legacy field in the test\n\n\t\treturn nil\n\t})\n\tsuite.Require().NoError(err)\n\n\tctest.AssertNoResource[*network.HostnameSpec](suite, \"configuration/hostname\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestMachineConfigurationStaticHostname() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\thostnameCfg := networkcfg.NewHostnameConfigV1Alpha1()\n\thostnameCfg.ConfigAuto = new(nethelpers.AutoHostnameKindOff)\n\thostnameCfg.ConfigHostname = \"my-hostname\"\n\n\tctr, err := container.New(hostnameCfg)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(\n\t\tsuite, \"configuration/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"my-hostname\", r.TypedSpec().Hostname)\n\t\t\tasrt.Equal(\"\", r.TypedSpec().Domainname)\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t}, rtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertNoResource[*network.HostnameSpec](suite, \"default/hostname\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n\n\tsuite.Destroy(cfg)\n\n\tctest.AssertNoResource[*network.HostnameSpec](suite, \"configuration/hostname\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n\tctest.AssertNoResource[*network.HostnameSpec](suite, \"default/hostname\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *HostnameConfigSuite) TestMachineConfigurationDefaultStable() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.HostnameConfigController{}))\n\n\thostnameCfg := networkcfg.NewHostnameConfigV1Alpha1()\n\thostnameCfg.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\tctr, err := container.New(hostnameCfg)\n\tsuite.Require().NoError(err)\n\n\tid := cluster.NewIdentity(cluster.NamespaceName, cluster.LocalIdentity)\n\tid.TypedSpec().NodeID = \"fGdOI05hVrx3YMagLo0Bwxa2Nm9BAswWm8XLeEj0aS4\"\n\tsuite.Create(id)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, \"default/hostname\", func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"talos-hwz-sw5\", r.TypedSpec().Hostname)\n\t\tasrt.Equal(\"\", r.TypedSpec().Domainname)\n\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc TestHostnameConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &HostnameConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewHostnameMergeController initializes a HostnameMergeController.\n//\n// HostnameMergeController merges network.HostnameSpec in network.ConfigNamespace and produces final network.HostnameSpec in network.Namespace.\nfunc NewHostnameMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.HostnameSpec]) map[resource.ID]*network.HostnameSpecSpec {\n\t\t\t// simply merge by layers, overriding with the next configuration layer\n\t\t\tvar final network.HostnameSpecSpec\n\n\t\t\tfor spec := range list.All() {\n\t\t\t\tif final.Hostname != \"\" && spec.TypedSpec().ConfigLayer <= final.ConfigLayer {\n\t\t\t\t\t// skip this spec, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfinal = *spec.TypedSpec()\n\t\t\t}\n\n\t\t\tif final.Hostname != \"\" {\n\t\t\t\treturn map[resource.ID]*network.HostnameSpecSpec{\n\t\t\t\t\tnetwork.HostnameID: &final,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype HostnameMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *HostnameMergeSuite) assertHostnames(requiredIDs []string, check func(*network.HostnameSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *HostnameMergeSuite) TestMerge() {\n\tdef := network.NewHostnameSpec(network.ConfigNamespaceName, \"default/hostname\")\n\t*def.TypedSpec() = network.HostnameSpecSpec{\n\t\tHostname:    \"foo\",\n\t\tDomainname:  \"tld\",\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp1 := network.NewHostnameSpec(network.ConfigNamespaceName, \"dhcp/eth0\")\n\t*dhcp1.TypedSpec() = network.HostnameSpecSpec{\n\t\tHostname:    \"eth-0\",\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tdhcp2 := network.NewHostnameSpec(network.ConfigNamespaceName, \"dhcp/eth1\")\n\t*dhcp2.TypedSpec() = network.HostnameSpecSpec{\n\t\tHostname:    \"eth-1\",\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewHostnameSpec(network.ConfigNamespaceName, \"configuration/hostname\")\n\t*static.TypedSpec() = network.HostnameSpecSpec{\n\t\tHostname:    \"bar\",\n\t\tDomainname:  \"com\",\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{def, dhcp1, dhcp2, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertHostnames(\n\t\t[]string{\n\t\t\t\"hostname\",\n\t\t}, func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"bar.com\", r.TypedSpec().FQDN())\n\t\t\tasrt.Equal(\"bar\", r.TypedSpec().Hostname)\n\t\t\tasrt.Equal(\"com\", r.TypedSpec().Domainname)\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertHostnames(\n\t\t[]string{\n\t\t\t\"hostname\",\n\t\t}, func(r *network.HostnameSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"eth-0\", r.TypedSpec().FQDN())\n\t\t},\n\t)\n}\n\nfunc TestHostnameMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &HostnameMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewHostnameMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// HostnameSpecController applies network.HostnameSpec to the actual interfaces.\ntype HostnameSpecController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *HostnameSpecController) Name() string {\n\treturn \"network.HostnameSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *HostnameSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *HostnameSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.HostnameStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *HostnameSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.HostnameSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network addresses: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// loop over specs and sync to statuses\n\t\tfor _, res := range list.Items {\n\t\t\tspec := res.(*network.HostnameSpec) //nolint:forcetypeassert\n\n\t\t\tswitch spec.Metadata().Phase() {\n\t\t\tcase resource.PhaseTearingDown:\n\t\t\t\tif err = r.Destroy(ctx, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, spec.Metadata().ID(), resource.VersionUndefined)); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = r.RemoveFinalizer(ctx, spec.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t\t}\n\t\t\tcase resource.PhaseRunning:\n\t\t\t\tif err = safe.WriterModify(ctx, r, network.NewHostnameStatus(network.NamespaceName, spec.Metadata().ID()), func(status *network.HostnameStatus) error {\n\t\t\t\t\tstatus.TypedSpec().Hostname = spec.TypedSpec().Hostname\n\t\t\t\t\tstatus.TypedSpec().Domainname = spec.TypedSpec().Domainname\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error modifying status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\t// apply hostname unless running in container mode\n\t\t\t\tif ctrl.V1Alpha1Mode != v1alpha1runtime.ModeContainer {\n\t\t\t\t\tlogger.Info(\"setting hostname\", zap.String(\"hostname\", spec.TypedSpec().Hostname), zap.String(\"domainname\", spec.TypedSpec().Domainname))\n\n\t\t\t\t\tif err = unix.Sethostname([]byte(spec.TypedSpec().Hostname)); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error setting hostname: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif err = unix.Setdomainname([]byte(spec.TypedSpec().Domainname)); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error setting domainname: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/hostname_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype HostnameSpecSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *HostnameSpecSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&netctrl.HostnameSpecController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeContainer, // run in container mode to skip _actually_ setting hostname\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *HostnameSpecSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *HostnameSpecSuite) assertStatus(id string, fqdn string) error {\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(network.NamespaceName, network.HostnameStatusType, id, resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tstatus := r.(*network.HostnameStatus) //nolint:forcetypeassert\n\n\tif status.TypedSpec().FQDN() != fqdn {\n\t\treturn retry.ExpectedErrorf(\"fqdn mismatch: %q != %q\", status.TypedSpec().FQDN(), fqdn)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *HostnameSpecSuite) TestSpec() {\n\tspec := network.NewHostnameSpec(network.NamespaceName, \"hostname\")\n\t*spec.TypedSpec() = network.HostnameSpecSpec{\n\t\tHostname:    \"foo\",\n\t\tDomainname:  \"bar\",\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{spec} {\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, res), \"%v\", res.Spec())\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertStatus(\"hostname\", \"foo.bar\")\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *HostnameSpecSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestHostnameSpecSuite(t *testing.T) {\n\tsuite.Run(t, new(HostnameSpecSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/addressutil.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package addressutil contains helpers working with addresses.\npackage addressutil\n\nimport \"net/netip\"\n\n// DeduplicateIPPrefixes removes duplicates from the given list of prefixes.\n//\n// The input list must be sorted.\n// DeduplicateIPPrefixes performs in-place deduplication.\nfunc DeduplicateIPPrefixes(in []netip.Prefix) []netip.Prefix {\n\t// assumes that current is sorted\n\tn := 0\n\n\tvar prev netip.Prefix\n\n\tfor _, x := range in {\n\t\tif prev != x {\n\t\t\tin[n] = x\n\t\t\tn++\n\t\t}\n\n\t\tprev = x\n\t}\n\n\treturn in[:n]\n}\n\n// FilterIPs filters the given list of IP prefixes based on the given include and exclude subnets.\n//\n// If includeSubnets is not empty, only IPs that are in one of the subnets are included.\n// If excludeSubnets is not empty, IPs that are in one of the subnets are excluded.\nfunc FilterIPs(addrs []netip.Prefix, includeSubnets, excludeSubnets []netip.Prefix) []netip.Prefix {\n\tresult := make([]netip.Prefix, 0, len(addrs))\n\nouter:\n\tfor _, ip := range addrs {\n\t\tif len(includeSubnets) > 0 {\n\t\t\tmatchesAny := false\n\n\t\t\tfor _, subnet := range includeSubnets {\n\t\t\t\tif subnet.Contains(ip.Addr()) {\n\t\t\t\t\tmatchesAny = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !matchesAny {\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t}\n\n\t\tfor _, subnet := range excludeSubnets {\n\t\t\tif subnet.Contains(ip.Addr()) {\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t}\n\n\t\tresult = append(result, ip)\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/addressutil_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage addressutil_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n)\n\nfunc TestDeduplicateIPPrefixes(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tin   []netip.Prefix\n\n\t\tout []netip.Prefix\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"single\",\n\t\t\tin:   []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"1.2.3.4/32\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\")},\n\t\t},\n\t\t{\n\t\t\tname: \"many\",\n\t\t\tin:   []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"1.2.3.4/24\"), netip.MustParsePrefix(\"2000::aebc/64\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"1.2.3.4/24\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := addressutil.DeduplicateIPPrefixes(test.in)\n\n\t\t\tassert.Equal(t, test.out, got)\n\t\t})\n\t}\n}\n\n// TestFilterIPs tests the FilterIPs function.\nfunc TestFilterIPs(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tin      []netip.Prefix\n\t\tinclude []netip.Prefix\n\t\texclude []netip.Prefix\n\n\t\tout []netip.Prefix\n\t}{\n\t\t{\n\t\t\tname: \"empty filters\",\n\n\t\t\tin: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t},\n\t\t{\n\t\t\tname: \"v4 only\",\n\n\t\t\tin:      []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t\tinclude: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\")},\n\t\t},\n\t\t{\n\t\t\tname: \"v6 only\",\n\n\t\t\tin:      []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t\texclude: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t},\n\t\t{\n\t\t\tname: \"include and exclude\",\n\n\t\t\tin:      []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\"), netip.MustParsePrefix(\"3.4.5.6/24\"), netip.MustParsePrefix(\"2000::aebc/64\")},\n\t\t\tinclude: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\")},\n\t\t\texclude: []netip.Prefix{netip.MustParsePrefix(\"3.0.0.0/8\")},\n\n\t\t\tout: []netip.Prefix{netip.MustParsePrefix(\"1.2.3.4/32\")},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := addressutil.FilterIPs(test.in, test.include, test.exclude)\n\n\t\t\tassert.Equal(t, test.out, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/broadcast.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage addressutil\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\n\t\"go4.org/netipx\"\n)\n\n// BroadcastAddr calculates the broadcast address for the given IPv4 prefix.\n//\n// If the address is not IPv4 or the prefix length is 31 or 32, nil is returned.\nfunc BroadcastAddr(addr netip.Prefix) net.IP {\n\tif !addr.Addr().Is4() {\n\t\treturn nil\n\t}\n\n\tif addr.Bits() >= 31 {\n\t\treturn nil\n\t}\n\n\tipnet := netipx.PrefixIPNet(addr)\n\n\tip := ipnet.IP.To4()\n\tif ip == nil {\n\t\treturn nil\n\t}\n\n\tmask := net.IP(ipnet.Mask).To4()\n\n\tn := len(ip)\n\tif n != len(mask) {\n\t\treturn nil\n\t}\n\n\tout := make(net.IP, n)\n\n\tfor i := range n {\n\t\tout[i] = ip[i] | ^mask[i]\n\t}\n\n\treturn out\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/broadcast_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage addressutil_test\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n)\n\nfunc TestBroadcastAddr(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tprefix  string\n\t\twant    string\n\t\twantNil bool\n\t}{\n\t\t{\n\t\t\tname:   \"IPv4 /24 network\",\n\t\t\tprefix: \"10.255.255.231/24\",\n\t\t\twant:   \"10.255.255.255\",\n\t\t},\n\t\t{\n\t\t\tname:   \"IPv4 /16 network\",\n\t\t\tprefix: \"192.168.0.1/16\",\n\t\t\twant:   \"192.168.255.255\",\n\t\t},\n\t\t{\n\t\t\tname:    \"IPv4 /32 host route (VIP case)\",\n\t\t\tprefix:  \"10.255.255.230/32\",\n\t\t\twantNil: true, // Should return nil, not set broadcast\n\t\t},\n\t\t{\n\t\t\tname:    \"Another /32 host route\",\n\t\t\tprefix:  \"192.168.1.100/32\",\n\t\t\twantNil: true, // Should return nil, not set broadcast\n\t\t},\n\t\t{\n\t\t\tname:    \"IPv4 /31 point-to-point\",\n\t\t\tprefix:  \"10.0.0.1/31\",\n\t\t\twantNil: true, // RFC 3021 - /31 is point-to-point, no broadcast\n\t\t},\n\t\t{\n\t\t\tname:   \"IPv4 /8 network\",\n\t\t\tprefix: \"10.0.0.1/8\",\n\t\t\twant:   \"10.255.255.255\",\n\t\t},\n\t\t{\n\t\t\tname:    \"IPv6 address (no broadcast)\",\n\t\t\tprefix:  \"2001:db8::1/64\",\n\t\t\twantNil: true, // IPv6 doesn't have broadcast\n\t\t},\n\t\t{\n\t\t\tname:    \"IPv6 /128 address\",\n\t\t\tprefix:  \"2001:db8::1/128\",\n\t\t\twantNil: true, // IPv6 doesn't have broadcast\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tprefix, err := netip.ParsePrefix(tt.prefix)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgot := addressutil.BroadcastAddr(prefix)\n\n\t\t\tif tt.wantNil {\n\t\t\t\tassert.Nil(t, got, \"expected nil broadcast for %s\", tt.prefix)\n\t\t\t} else {\n\t\t\t\tassert.NotNil(t, got, \"expected broadcast address for %s\", tt.prefix)\n\n\t\t\t\twant := net.ParseIP(tt.want)\n\t\t\t\tassert.True(t, got.Equal(want), \"expected %v, got %v for %s\", want, got, tt.prefix)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/compare.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage addressutil\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// CompareByAlgorithm returns a comparison function based on the given algorithm.\nfunc CompareByAlgorithm(algorithm nethelpers.AddressSortAlgorithm) func(a, b netip.Prefix) int {\n\tswitch algorithm {\n\tcase nethelpers.AddressSortAlgorithmV1:\n\t\treturn ComparePrefixesLegacy\n\tcase nethelpers.AddressSortAlgorithmV2:\n\t\treturn ComparePrefixNew\n\t}\n\n\tpanic(fmt.Sprintf(\"unknown address sort algorithm: %s\", algorithm))\n}\n\n// ComparePrefixesLegacy is the old way to sort prefixes.\n//\n// It only compares addresses and does not take prefix length into account.\nfunc ComparePrefixesLegacy(a, b netip.Prefix) int {\n\tif c := a.Addr().Compare(b.Addr()); c != 0 {\n\t\treturn c\n\t}\n\n\t// note: this was missing in the previous implementation, but this makes sorting stable\n\treturn cmp.Compare(a.Bits(), b.Bits())\n}\n\nfunc family(a netip.Prefix) int {\n\tif a.Addr().Is4() {\n\t\treturn 4\n\t}\n\n\treturn 6\n}\n\n// ComparePrefixNew compares two prefixes by address family, address, and prefix length.\n//\n// It prefers more specific prefixes.\nfunc ComparePrefixNew(a, b netip.Prefix) int {\n\t// (1): first, compare address families\n\tif c := cmp.Compare(family(a), family(b)); c != 0 {\n\t\treturn c\n\t}\n\n\t// (2): if addresses are equal, Contains will report that one prefix contains the other, so compare prefix lengths\n\tif a.Addr() == b.Addr() {\n\t\treturn -cmp.Compare(a.Bits(), b.Bits())\n\t}\n\n\t// (3): if one prefix contains another, the more specific one should come first\n\t// but if both prefixes contain each other, proceed to compare addresses\n\taContainsB := a.Contains(b.Addr())\n\tbContainsA := b.Contains(a.Addr())\n\n\tswitch {\n\tcase aContainsB && !bContainsA:\n\t\treturn 1\n\tcase !aContainsB && bContainsA:\n\t\treturn -1\n\t}\n\n\t// (4): compare addresses, they are not equal at this point (see (2))\n\treturn a.Addr().Compare(b.Addr())\n}\n\n// CompareAddressStatuses compares two address statuses with the prefix comparison func.\n//\n// The comparison of AddressStatuses sorts by link name and then by address.\nfunc CompareAddressStatuses(comparePrefixes func(a, b netip.Prefix) int) func(a, b *network.AddressStatus) int {\n\treturn func(a, b *network.AddressStatus) int {\n\t\tif c := cmp.Compare(a.TypedSpec().LinkName, b.TypedSpec().LinkName); c != 0 {\n\t\t\treturn c\n\t\t}\n\n\t\treturn comparePrefixes(a.TypedSpec().Address, b.TypedSpec().Address)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/addressutil/compare_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage addressutil_test\n\nimport (\n\t\"math/rand/v2\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n)\n\nfunc toNetip(prefixes ...string) []netip.Prefix {\n\treturn xslices.Map(prefixes, netip.MustParsePrefix)\n}\n\nfunc toString(prefixes []netip.Prefix) []string {\n\treturn xslices.Map(prefixes, netip.Prefix.String)\n}\n\nfunc TestCompare(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tin []netip.Prefix\n\n\t\toutLegacy []netip.Prefix\n\t\toutNew    []netip.Prefix\n\t}{\n\t\t{\n\t\t\tname: \"ipv4\",\n\n\t\t\tin: toNetip(\"10.3.4.1/24\", \"10.3.4.5/24\", \"10.3.4.5/32\", \"1.2.3.4/26\", \"192.168.35.11/24\", \"192.168.36.10/24\"),\n\n\t\t\toutLegacy: toNetip(\"1.2.3.4/26\", \"10.3.4.1/24\", \"10.3.4.5/24\", \"10.3.4.5/32\", \"192.168.35.11/24\", \"192.168.36.10/24\"),\n\t\t\toutNew:    toNetip(\"1.2.3.4/26\", \"10.3.4.5/32\", \"10.3.4.1/24\", \"10.3.4.5/24\", \"192.168.35.11/24\", \"192.168.36.10/24\"),\n\t\t},\n\t\t{\n\t\t\tname: \"ipv6\",\n\n\t\t\tin: toNetip(\"2001:db8::1/64\", \"2001:db8::1/128\", \"2001:db8::2/64\", \"2001:db8::2/128\", \"2001:db8::3/64\", \"2001:db8::3/128\"),\n\n\t\t\toutLegacy: toNetip(\"2001:db8::1/64\", \"2001:db8::1/128\", \"2001:db8::2/64\", \"2001:db8::2/128\", \"2001:db8::3/64\", \"2001:db8::3/128\"),\n\t\t\toutNew:    toNetip(\"2001:db8::1/128\", \"2001:db8::2/128\", \"2001:db8::3/128\", \"2001:db8::1/64\", \"2001:db8::2/64\", \"2001:db8::3/64\"),\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\n\t\t\tin: toNetip(\"fd01:cafe::5054:ff:fe1f:c7bd/64\", \"fd01:cafe::f14c:9fa1:8496:557f/128\", \"192.168.3.4/24\", \"10.5.0.0/16\"),\n\n\t\t\toutLegacy: toNetip(\"10.5.0.0/16\", \"192.168.3.4/24\", \"fd01:cafe::5054:ff:fe1f:c7bd/64\", \"fd01:cafe::f14c:9fa1:8496:557f/128\"),\n\t\t\toutNew:    toNetip(\"10.5.0.0/16\", \"192.168.3.4/24\", \"fd01:cafe::f14c:9fa1:8496:557f/128\", \"fd01:cafe::5054:ff:fe1f:c7bd/64\"),\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// add more randomness to ensure the sorting is stable\n\t\t\tin := slices.Clone(test.in)\n\t\t\trand.Shuffle(len(in), func(i, j int) { in[i], in[j] = in[j], in[i] })\n\n\t\t\tlegacy := slices.Clone(in)\n\t\t\tslices.SortFunc(legacy, addressutil.ComparePrefixesLegacy)\n\n\t\t\tassert.Equal(t, test.outLegacy, legacy, \"expected %q but got %q\", toString(test.outLegacy), toString(legacy))\n\n\t\t\tnewer := slices.Clone(in)\n\t\t\tslices.SortFunc(newer, addressutil.ComparePrefixNew)\n\n\t\t\tassert.Equal(t, test.outNew, newer, \"expected %q but got %q\", toString(test.outNew), toString(newer))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/probe/probe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package probe contains implementation of the network probe runners.\npackage probe\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// Runner describes a state of running probe.\ntype Runner struct {\n\tID   string\n\tSpec network.ProbeSpecSpec\n\n\tcancel context.CancelFunc\n\twg     sync.WaitGroup\n}\n\n// Notification of a runner status.\ntype Notification struct {\n\tID     string\n\tStatus network.ProbeStatusSpec\n}\n\n// Start a runner with a given context.\nfunc (runner *Runner) Start(ctx context.Context, notifyCh chan<- Notification, logger *zap.Logger) {\n\trunner.wg.Add(1)\n\n\tctx, runner.cancel = context.WithCancel(ctx)\n\n\tgo func() {\n\t\tdefer runner.wg.Done()\n\n\t\trunner.run(ctx, notifyCh, logger)\n\t}()\n}\n\n// Stop a runner.\nfunc (runner *Runner) Stop() {\n\trunner.cancel()\n\n\trunner.wg.Wait()\n}\n\n// run a probe.\n//\n//nolint:gocyclo\nfunc (runner *Runner) run(ctx context.Context, notifyCh chan<- Notification, logger *zap.Logger) {\n\tlogger = logger.With(zap.String(\"probe\", runner.ID))\n\n\tticker := time.NewTicker(runner.Spec.Interval)\n\tdefer ticker.Stop()\n\n\tconsecutiveFailures := 0\n\tfirstIteration := true\n\n\tfor {\n\t\tif !firstIteration {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t}\n\t\t} else {\n\t\t\tfirstIteration = false\n\t\t}\n\n\t\terr := runner.probe(ctx)\n\t\tif err == nil {\n\t\t\tif consecutiveFailures > 0 {\n\t\t\t\tlogger.Info(\"probe succeeded\")\n\t\t\t}\n\n\t\t\tconsecutiveFailures = 0\n\n\t\t\tif !channel.SendWithContext(ctx, notifyCh, Notification{\n\t\t\t\tID: runner.ID,\n\t\t\t\tStatus: network.ProbeStatusSpec{\n\t\t\t\t\tSuccess: true,\n\t\t\t\t},\n\t\t\t}) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif consecutiveFailures == runner.Spec.FailureThreshold {\n\t\t\tlogger.Error(\"probe failed\", zap.Error(err))\n\t\t}\n\n\t\tconsecutiveFailures++\n\n\t\tif consecutiveFailures < runner.Spec.FailureThreshold {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !channel.SendWithContext(ctx, notifyCh, Notification{\n\t\t\tID: runner.ID,\n\t\t\tStatus: network.ProbeStatusSpec{\n\t\t\t\tSuccess:   false,\n\t\t\t\tLastError: err.Error(),\n\t\t\t},\n\t\t}) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// probe runs a probe.\nfunc (runner *Runner) probe(ctx context.Context) error {\n\tvar zeroTCP network.TCPProbeSpec\n\n\tswitch {\n\tcase runner.Spec.TCP != zeroTCP:\n\t\treturn runner.probeTCP(ctx)\n\tdefault:\n\t\treturn errors.New(\"no probe type specified\")\n\t}\n}\n\n// probeTCP runs a TCP probe.\nfunc (runner *Runner) probeTCP(ctx context.Context) error {\n\tdialer := &net.Dialer{\n\t\t// The dialer reduces the TIME-WAIT period to 1 seconds instead of the OS default of 60 seconds.\n\t\tControl: func(network, address string, c syscall.RawConn) error {\n\t\t\treturn c.Control(func(fd uintptr) {\n\t\t\t\tsyscall.SetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, &syscall.Linger{Onoff: 1, Linger: 1}) //nolint: errcheck\n\t\t\t})\n\t\t},\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, runner.Spec.TCP.Timeout)\n\tdefer cancel()\n\n\tconn, err := dialer.DialContext(ctx, \"tcp\", runner.Spec.TCP.Endpoint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn conn.Close()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/internal/probe/probe_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage probe_test\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"testing/synctest\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/probe\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestProbeHTTP(t *testing.T) {\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tt.Cleanup(server.Close)\n\n\tu, err := url.Parse(server.URL)\n\trequire.NoError(t, err)\n\n\tp := probe.Runner{\n\t\tID: \"test\",\n\t\tSpec: network.ProbeSpecSpec{\n\t\t\tInterval: 10 * time.Millisecond,\n\t\t\tTCP: network.TCPProbeSpec{\n\t\t\t\tEndpoint: u.Host,\n\t\t\t\tTimeout:  time.Second,\n\t\t\t},\n\t\t},\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\tt.Cleanup(cancel)\n\n\tnotifyCh := make(chan probe.Notification)\n\n\tp.Start(ctx, notifyCh, zaptest.NewLogger(t))\n\tt.Cleanup(p.Stop)\n\n\t// probe should always succeed\n\tfor range 3 {\n\t\tassert.Equal(t, probe.Notification{\n\t\t\tID: \"test\",\n\t\t\tStatus: network.ProbeStatusSpec{\n\t\t\t\tSuccess: true,\n\t\t\t},\n\t\t}, <-notifyCh)\n\t}\n\n\t// stop the test server, probe should fail\n\tserver.Close()\n\n\tfor {\n\t\tnotification := <-notifyCh\n\n\t\tif notification.Status.Success {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, \"test\", notification.ID)\n\t\tassert.False(t, notification.Status.Success)\n\t\tassert.Contains(t, notification.Status.LastError, \"connection refused\")\n\n\t\tbreak\n\t}\n}\n\nfunc TestProbeConsecutiveFailures(t *testing.T) {\n\t// Use synctest.Test to run the test in a controlled time bubble.\n\t// This allows us to test time-dependent behavior without actual delays,\n\t// making the test both faster and more deterministic.\n\tsynctest.Test(t, func(t *testing.T) {\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tu, err := url.Parse(server.URL)\n\t\trequire.NoError(t, err)\n\n\t\tp := probe.Runner{\n\t\t\tID: \"consecutive-failures\",\n\t\t\tSpec: network.ProbeSpecSpec{\n\t\t\t\tInterval:         10 * time.Millisecond,\n\t\t\t\tFailureThreshold: 3,\n\t\t\t\tTCP: network.TCPProbeSpec{\n\t\t\t\t\tEndpoint: u.Host,\n\t\t\t\t\tTimeout:  time.Second,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\t\tdefer cancel()\n\n\t\tnotifyCh := make(chan probe.Notification)\n\n\t\tp.Start(ctx, notifyCh, zaptest.NewLogger(t))\n\t\tdefer p.Stop()\n\n\t\t// first iteration should succeed\n\t\tassert.Equal(t, probe.Notification{\n\t\t\tID: \"consecutive-failures\",\n\t\t\tStatus: network.ProbeStatusSpec{\n\t\t\t\tSuccess: true,\n\t\t\t},\n\t\t}, <-notifyCh)\n\n\t\t// stop the test server, probe should fail\n\t\tserver.Close()\n\n\t\tfor range p.Spec.FailureThreshold - 1 {\n\t\t\t// probe should fail, but no notification should be sent yet (failure threshold not reached)\n\t\t\t// synctest.Wait() waits until all goroutines in the bubble are durably blocked,\n\t\t\t// which happens when the ticker in the probe runner is waiting for the next interval\n\t\t\tsynctest.Wait()\n\n\t\t\tselect {\n\t\t\tcase ev := <-notifyCh:\n\t\t\t\trequire.Fail(t, \"unexpected notification\", \"got: %v\", ev)\n\t\t\tdefault:\n\t\t\t\t// Expected: no notification yet\n\t\t\t}\n\t\t}\n\n\t\t// wait for next interval to trigger failure notification\n\t\tsynctest.Wait()\n\n\t\tnotify := <-notifyCh\n\t\tassert.Equal(t, \"consecutive-failures\", notify.ID)\n\t\tassert.False(t, notify.Status.Success)\n\t\tassert.Contains(t, notify.Status.LastError, \"connection refused\")\n\n\t\t// wait for next interval to trigger another failure notification\n\t\tsynctest.Wait()\n\n\t\tnotify = <-notifyCh\n\t\tassert.Equal(t, \"consecutive-failures\", notify.ID)\n\t\tassert.False(t, notify.Status.Success)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_alias_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\tnetworkpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LinkAliasConfigController manages network.LinkAliasSpec based on machine configuration, list of links, etc.\ntype LinkAliasConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LinkAliasConfigController) Name() string {\n\treturn \"network.LinkAliasConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LinkAliasConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LinkAliasConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.LinkAliasSpecType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkAliasConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tlinkStatuses, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing link statuses: %w\", err)\n\t\t}\n\n\t\t// we are only interested in physical links\n\t\tphysicalLinks := xslices.Filter(slices.Collect(linkStatuses.All()), func(item *network.LinkStatus) bool {\n\t\t\treturn item.TypedSpec().Physical()\n\t\t})\n\n\t\t// sort the links by MAC address to ensure consistent alias assignment for pattern-based configs\n\t\tslices.SortFunc(physicalLinks, func(a, b *network.LinkStatus) int {\n\t\t\taddrA := a.TypedSpec().PermanentAddr\n\t\t\tif len(addrA) == 0 {\n\t\t\t\taddrA = a.TypedSpec().HardwareAddr\n\t\t\t}\n\n\t\t\taddrB := b.TypedSpec().PermanentAddr\n\t\t\tif len(addrB) == 0 {\n\t\t\t\taddrB = b.TypedSpec().HardwareAddr\n\t\t\t}\n\n\t\t\treturn bytes.Compare(addrA, addrB)\n\t\t})\n\n\t\tphysicalLinkSpecs := make([]*networkpb.LinkStatusSpec, 0, len(physicalLinks))\n\n\t\tfor _, link := range physicalLinks {\n\t\t\tvar spec networkpb.LinkStatusSpec\n\n\t\t\tif err = proto.ResourceSpecToProto(link, &spec); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error converting link spec (%s) to proto: %w\", link.Metadata().ID(), err)\n\t\t\t}\n\n\t\t\tphysicalLinkSpecs = append(physicalLinkSpecs, &spec)\n\t\t}\n\n\t\tvar linkAliasConfigs []configconfig.NetworkLinkAliasConfig\n\n\t\tif cfg != nil {\n\t\t\tlinkAliasConfigs = cfg.Config().NetworkLinkAliasConfigs()\n\t\t}\n\n\t\t// sort the link alias configs by name to ensure deterministic processing order\n\t\tslices.SortFunc(linkAliasConfigs, func(a, b configconfig.NetworkLinkAliasConfig) int {\n\t\t\treturn strings.Compare(a.Name(), b.Name())\n\t\t})\n\n\t\tlinkAliases := map[string]string{}\n\n\t\tfor _, lac := range linkAliasConfigs {\n\t\t\tvar matchedLinks []*network.LinkStatus\n\n\t\t\tfor idx, link := range physicalLinkSpecs {\n\t\t\t\tmatches, err := lac.LinkSelector().EvalBool(celenv.LinkLocator(), map[string]any{\n\t\t\t\t\t\"link\": link,\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error evaluating link selector: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif matches {\n\t\t\t\t\tmatchedLinks = append(matchedLinks, physicalLinks[idx])\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fixed name: require exactly one match\n\t\t\tif len(matchedLinks) > 1 && !lac.IsPatternAlias() {\n\t\t\t\tlogger.Warn(\"link selector matched multiple links, skipping\",\n\t\t\t\t\tzap.String(\"selector\", lac.LinkSelector().String()),\n\t\t\t\t\tzap.String(\"alias\", lac.Name()),\n\t\t\t\t\tzap.Strings(\"links\", xslices.Map(matchedLinks, func(item *network.LinkStatus) string {\n\t\t\t\t\t\treturn item.Metadata().ID()\n\t\t\t\t\t})),\n\t\t\t\t)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmatchedLinks = xslices.Filter(matchedLinks, func(matchedLink *network.LinkStatus) bool {\n\t\t\t\t_, alreadyAliased := linkAliases[matchedLink.Metadata().ID()]\n\t\t\t\tif alreadyAliased {\n\t\t\t\t\tlogger.Warn(\"link already has an alias, skipping\",\n\t\t\t\t\t\tzap.String(\"link\", matchedLink.Metadata().ID()),\n\t\t\t\t\t\tzap.String(\"existing_alias\", linkAliases[matchedLink.Metadata().ID()]),\n\t\t\t\t\t\tzap.String(\"new_alias\", lac.Name()),\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\treturn !alreadyAliased\n\t\t\t})\n\n\t\t\tif len(matchedLinks) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif lac.IsPatternAlias() {\n\t\t\t\t// Pattern-based name: create sequential aliases for each matched link in name order\n\t\t\t\tfor counter, matchedLink := range matchedLinks {\n\t\t\t\t\tlinkAliases[matchedLink.Metadata().ID()] = strings.Replace(lac.Name(), \"%d\", strconv.Itoa(counter), 1)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmatchedLink := matchedLinks[0]\n\n\t\t\t\tlinkAliases[matchedLink.Metadata().ID()] = lac.Name()\n\t\t\t}\n\t\t}\n\n\t\tfor linkID, alias := range linkAliases {\n\t\t\tif err = safe.WriterModify(\n\t\t\t\tctx,\n\t\t\t\tr,\n\t\t\t\tnetwork.NewLinkAliasSpec(network.NamespaceName, linkID),\n\t\t\t\tfunc(r *network.LinkAliasSpec) error {\n\t\t\t\t\tr.TypedSpec().Alias = alias\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error writing link alias spec for link %q: %w\", linkID, err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*network.LinkAliasSpec](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up link alias specs: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_alias_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:goconst\npackage network_test\n\nimport (\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype LinkAliasConfigSuite struct {\n\tctest.DefaultSuite\n}\n\ntype testLink struct {\n\tname          string\n\tpermanentAddr string\n}\n\nfunc (suite *LinkAliasConfigSuite) createLinks(links []testLink) {\n\tfor _, link := range links {\n\t\tpAddr, err := net.ParseMAC(link.permanentAddr)\n\t\tsuite.Require().NoError(err)\n\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(pAddr)\n\t\tstatus.TypedSpec().HardwareAddr = nethelpers.HardwareAddr(pAddr)\n\t\tstatus.TypedSpec().Type = nethelpers.LinkEther\n\n\t\tsuite.Create(status)\n\t}\n}\n\nfunc (suite *LinkAliasConfigSuite) TestMachineConfigurationNewStyle() {\n\tlc1 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net0\")\n\tlc1.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`glob(\"00:1a:2b:*\", mac(link.permanent_addr))`, celenv.LinkLocator()))\n\n\tlc2 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net1\")\n\tlc2.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`glob(\"33:44:55:*\", mac(link.permanent_addr))`, celenv.LinkLocator()))\n\n\tctr, err := container.New(lc1, lc2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.createLinks([]testLink{\n\t\t{name: \"enp0s2\", permanentAddr: \"00:1a:2b:33:44:55\"},\n\t\t{name: \"enp1s3\", permanentAddr: \"33:44:55:66:77:88\"},\n\t\t{name: \"enp1s4\", permanentAddr: \"33:44:55:66:77:89\"},\n\t})\n\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertNoResource[*network.LinkAliasSpec](suite.Ctx(), suite.T(), suite.State(), \"enp1s3\")\n\trtestutils.AssertNoResource[*network.LinkAliasSpec](suite.Ctx(), suite.T(), suite.State(), \"enp1s4\")\n\n\tsuite.Destroy(cfg)\n\n\trtestutils.AssertNoResource[*network.LinkAliasSpec](suite.Ctx(), suite.T(), suite.State(), \"enp0s2\")\n}\n\nfunc (suite *LinkAliasConfigSuite) TestMachineConfigurationTwoAliasesSameLink() {\n\tlc1 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net1\")\n\tlc1.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`glob(\"00:1a:2b:*\", mac(link.permanent_addr))`, celenv.LinkLocator()))\n\n\tlc2 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net0\")\n\tlc2.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`glob(\"00:1a:2b:33:*\", mac(link.permanent_addr))`, celenv.LinkLocator()))\n\n\tctr, err := container.New(lc1, lc2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.createLinks([]testLink{\n\t\t{name: \"enp0s2\", permanentAddr: \"00:1a:2b:33:44:55\"},\n\t})\n\n\t// the \"smallest\" alias (net0) should win, net1 should be ignored since it conflicts with net0\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n}\n\nfunc (suite *LinkAliasConfigSuite) TestPatternAliasSortsByMAC() {\n\t// Test that pattern aliases are assigned in alphabetical order, regardless of creation order\n\tlc1 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net%d\")\n\tlc1.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`link.type == 1`, celenv.LinkLocator()))\n\n\tctr, err := container.New(lc1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\t// Create links out of order\n\tsuite.createLinks([]testLink{\n\t\t{name: \"enp1s4\", permanentAddr: \"33:44:55:66:77:88\"},\n\t\t{name: \"enp0s2\", permanentAddr: \"00:1a:2b:33:44:55\"},\n\t\t{name: \"enp1s3\", permanentAddr: \"33:44:55:66:77:89\"},\n\t})\n\n\t// Aliases should follow alphabetical order of link name\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s3\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net2\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s4\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net1\", spec.TypedSpec().Alias)\n\t})\n\n\tsuite.Destroy(cfg)\n}\n\nfunc (suite *LinkAliasConfigSuite) TestPatternSkipsAlreadyAliased() {\n\t// Test that a fixed-name config claims a link, and a subsequent pattern config skips it\n\tlc1 := networkcfg.NewLinkAliasConfigV1Alpha1(\"mgmt0\")\n\tlc1.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`mac(link.permanent_addr) == \"00:1a:2b:33:44:55\"`, celenv.LinkLocator()))\n\n\tlc2 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net%d\")\n\tlc2.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`link.type == 1`, celenv.LinkLocator()))\n\n\tctr, err := container.New(lc1, lc2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.createLinks([]testLink{\n\t\t{name: \"enp0s2\", permanentAddr: \"00:1a:2b:33:44:55\"},\n\t\t{name: \"enp1s3\", permanentAddr: \"33:44:55:66:77:88\"},\n\t\t{name: \"enp1s4\", permanentAddr: \"33:44:55:66:77:89\"},\n\t})\n\n\t// enp0s2 gets mgmt0 from the fixed-name config\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"mgmt0\", spec.TypedSpec().Alias)\n\t})\n\t// enp1s3 and enp1s4 get net0 and net1 from the pattern config (enp0s2 skipped)\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s3\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s4\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net1\", spec.TypedSpec().Alias)\n\t})\n\n\tsuite.Destroy(cfg)\n}\n\nfunc (suite *LinkAliasConfigSuite) TestPatternReconcileOnLinkChange() {\n\t// Test that when links change, pattern aliases are reconciled (re-numbered)\n\tlc1 := networkcfg.NewLinkAliasConfigV1Alpha1(\"net%d\")\n\tlc1.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`link.type == 1`, celenv.LinkLocator()))\n\n\tctr, err := container.New(lc1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.createLinks([]testLink{\n\t\t{name: \"enp0s2\", permanentAddr: \"00:1a:2b:33:44:55\"},\n\t\t{name: \"enp1s3\", permanentAddr: \"33:44:55:66:77:88\"},\n\t\t{name: \"enp1s4\", permanentAddr: \"33:44:55:66:77:89\"},\n\t})\n\n\t// Initial state: net0, net1, net2\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s3\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net1\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s4\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net2\", spec.TypedSpec().Alias)\n\t})\n\n\t// Remove the middle link — aliases should be re-numbered\n\tsuite.Destroy(network.NewLinkStatus(network.NamespaceName, \"enp1s3\"))\n\n\t// enp1s3 alias should be cleaned up, enp1s4 re-numbered to net1\n\trtestutils.AssertNoResource[*network.LinkAliasSpec](suite.Ctx(), suite.T(), suite.State(), \"enp1s3\")\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp0s2\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net0\", spec.TypedSpec().Alias)\n\t})\n\trtestutils.AssertResource(suite.Ctx(), suite.T(), suite.State(), \"enp1s4\", func(spec *network.LinkAliasSpec, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"net1\", spec.TypedSpec().Alias)\n\t})\n\n\tsuite.Destroy(cfg)\n}\n\nfunc TestLinkAliasConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &LinkAliasConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.LinkAliasConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_alias_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LinkAliasSpecController applies network.LinkAliasSpec to the actual interfaces.\ntype LinkAliasSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LinkAliasSpecController) Name() string {\n\treturn \"network.LinkAliasSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LinkAliasSpecController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LinkAliasSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkAliasSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy, which implies that all link renames are done\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.LinkAliasSpecType,\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\t// watch link changes as some routes might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source link alias specs (what should be aliased)\n\t\tlinkAliasSpecs, err := safe.ReaderListAll[*network.LinkAliasSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing link alias specs: %w\", err)\n\t\t}\n\n\t\tlinkAliasSpecLookup := make(map[string]string, linkAliasSpecs.Len())\n\n\t\tfor linkAliasSpec := range linkAliasSpecs.All() {\n\t\t\tlinkAliasSpecLookup[linkAliasSpec.Metadata().ID()] = linkAliasSpec.TypedSpec().Alias\n\t\t}\n\n\t\tlogger.Debug(\"reconciling link aliases\", zap.Any(\"desired\", linkAliasSpecLookup))\n\n\t\t// list rtnetlink links (interfaces)\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\t// loop over links and make reconcile decision\n\t\tvar multiErr *multierror.Error\n\n\t\tfor _, link := range links {\n\t\t\tif link.Attributes == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif link.Attributes.Info != nil || nethelpers.LinkType(link.Type) != nethelpers.LinkEther {\n\t\t\t\t// skip non-physical links\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\texpectedAlias, shouldHaveAlias := linkAliasSpecLookup[link.Attributes.Name]\n\t\t\tcurrentAlias := pointer.SafeDeref(link.Attributes.Alias)\n\n\t\t\tif !shouldHaveAlias && currentAlias != \"\" {\n\t\t\t\t// should not have alias, but has one - remove it\n\t\t\t\tlogger.Info(\"removing link alias\",\n\t\t\t\t\tzap.String(\"link\", link.Attributes.Name),\n\t\t\t\t\tzap.String(\"alias\", currentAlias),\n\t\t\t\t)\n\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tIndex: link.Index,\n\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\tAlias: new(\"\"),\n\t\t\t\t\t},\n\t\t\t\t}); err != nil {\n\t\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"error removing alias %q from link %q: %w\", currentAlias, link.Attributes.Name, err))\n\t\t\t\t}\n\t\t\t} else if shouldHaveAlias && currentAlias != expectedAlias {\n\t\t\t\t// should have alias, but doesn't have it or it's different - set it\n\t\t\t\tlogger.Info(\"setting link alias\",\n\t\t\t\t\tzap.String(\"link\", link.Attributes.Name),\n\t\t\t\t\tzap.String(\"alias\", expectedAlias),\n\t\t\t\t)\n\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tIndex: link.Index,\n\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\tAlias: new(expectedAlias),\n\t\t\t\t\t},\n\t\t\t\t}); err != nil {\n\t\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"error setting alias %q on link %q: %w\", expectedAlias, link.Attributes.Name, err))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = multiErr.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LinkConfigController manages network.LinkSpec based on machine configuration, kernel cmdline.\ntype LinkConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LinkConfigController) Name() string {\n\treturn \"network.LinkConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LinkConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.DeviceConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LinkConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.LinkSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tdevices, err := safe.ReaderListAll[*network.DeviceConfigSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting device config: %w\", err)\n\t\t}\n\n\t\tignoredInterfaces := map[string]struct{}{}\n\n\t\tfor item := range devices.All() {\n\t\t\tdevice := item.TypedSpec().Device\n\n\t\t\tif device.Ignore() {\n\t\t\t\tignoredInterfaces[device.Interface()] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\tlinkStatuses, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing link statuses: %w\", err)\n\t\t}\n\n\t\tlinkNameResolver := network.NewLinkResolver(linkStatuses.All)\n\n\t\t// bring up loopback interface\n\t\t{\n\t\t\tif err = ctrl.apply(ctx, r, []network.LinkSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tName:        \"lo\",\n\t\t\t\t\tUp:          true,\n\t\t\t\t\tConfigLayer: network.ConfigDefault,\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying cmdline route: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// parse kernel cmdline for the interface name\n\t\tcmdlineLinks, cmdlineIgnored := ctrl.parseCmdline(logger, linkNameResolver)\n\t\tfor _, cmdlineLink := range cmdlineLinks {\n\t\t\tif cmdlineLink.Name != \"\" {\n\t\t\t\tif _, ignored := ignoredInterfaces[cmdlineLink.Name]; !ignored {\n\t\t\t\t\tif err = ctrl.apply(ctx, r, []network.LinkSpecSpec{cmdlineLink}); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error applying cmdline route: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse machine configuration for link specs\n\t\tlinks := ctrl.processMachineConfiguration(logger, cfg, devices, linkNameResolver)\n\n\t\tif err = ctrl.apply(ctx, r, links); err != nil {\n\t\t\treturn fmt.Errorf(\"error applying machine configuration address: %w\", err)\n\t\t}\n\n\t\t// bring up any physical link not mentioned explicitly in the machine configuration\n\t\t// only in the mode when we run default DHCP operators\n\t\tshouldRunDefaultDHCPOperators := cfg == nil || cfg.Config().RunDefaultDHCPOperators()\n\n\t\tif shouldRunDefaultDHCPOperators {\n\t\t\tconfiguredLinks := map[string]struct{}{}\n\n\t\t\tfor _, linkName := range cmdlineIgnored {\n\t\t\t\tconfiguredLinks[linkName] = struct{}{}\n\t\t\t}\n\n\t\t\tfor _, cmdlineLink := range cmdlineLinks {\n\t\t\t\tif cmdlineLink.Name != \"\" {\n\t\t\t\t\tconfiguredLinks[cmdlineLink.Name] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif devices.Len() > 0 {\n\t\t\t\tfor item := range devices.All() {\n\t\t\t\t\tdevice := item.TypedSpec().Device\n\n\t\t\t\t\tconfiguredLinks[device.Interface()] = struct{}{}\n\n\t\t\t\t\tif device.Bond() != nil {\n\t\t\t\t\t\tfor _, link := range device.Bond().Interfaces() {\n\t\t\t\t\t\t\tconfiguredLinks[link] = struct{}{}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif device.Bridge() != nil {\n\t\t\t\t\t\tfor _, link := range device.Bridge().Interfaces() {\n\t\t\t\t\t\t\tconfiguredLinks[link] = struct{}{}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we have new-style link config documents, they disable shouldRunDefaultDHCPOperators, so\n\t\t\t// we don't need to add them to configuredLinks here\n\t\touter:\n\t\t\tfor linkStatus := range linkStatuses.All() {\n\t\t\t\tfor linkAlias := range network.AllLinkNames(linkStatus) {\n\t\t\t\t\tif _, configured := configuredLinks[linkAlias]; configured {\n\t\t\t\t\t\tcontinue outer\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif linkStatus.TypedSpec().Physical() {\n\t\t\t\t\tif err = ctrl.apply(ctx, r, []network.LinkSpecSpec{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:        linkStatus.Metadata().ID(),\n\t\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\t\tConfigLayer: network.ConfigDefault,\n\t\t\t\t\t\t},\n\t\t\t\t\t}); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error applying default link up: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up outputs: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *LinkConfigController) apply(ctx context.Context, r controller.Runtime, links []network.LinkSpecSpec) error {\n\tfor _, link := range links {\n\t\tid := network.LayeredID(link.ConfigLayer, network.LinkID(link.Name))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewLinkSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.LinkSpec) error {\n\t\t\t\t*r.TypedSpec() = link\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *LinkConfigController) parseCmdline(logger *zap.Logger, linkNameResolver *network.LinkResolver) ([]network.LinkSpecSpec, []string) {\n\tif ctrl.Cmdline == nil {\n\t\treturn []network.LinkSpecSpec{}, nil\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, linkNameResolver)\n\tif err != nil {\n\t\tlogger.Info(\"ignoring error\", zap.Error(err))\n\n\t\treturn []network.LinkSpecSpec{}, nil\n\t}\n\n\treturn settings.NetworkLinkSpecs, settings.IgnoreInterfaces\n}\n\nfunc (ctrl *LinkConfigController) processMachineConfiguration(\n\tlogger *zap.Logger, cfg *config.MachineConfig, devices safe.List[*network.DeviceConfigSpec], linkNameResolver *network.LinkResolver,\n) []network.LinkSpecSpec {\n\tlinkMap := map[string]*network.LinkSpecSpec{}\n\n\tctrl.processDevicesConfiguration(logger, linkMap, devices, linkNameResolver)\n\tctrl.processLinkConfigs(logger, linkMap, cfg, linkNameResolver)\n\n\treturn maps.ValuesFunc(linkMap, func(link *network.LinkSpecSpec) network.LinkSpecSpec { return *link })\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkConfigController) processDevicesConfiguration(\n\tlogger *zap.Logger, linkMap map[string]*network.LinkSpecSpec, devices safe.List[*network.DeviceConfigSpec], linkNameResolver *network.LinkResolver,\n) {\n\t// scan for the bonds or bridges\n\tbondedLinks := map[string]ordered.Pair[string, int]{} // mapping physical interface -> bond interface\n\tbridgedLinks := map[string]string{}                   // mapping physical interface -> bridge interface\n\n\tfor item := range devices.All() {\n\t\tdevice := item.TypedSpec().Device\n\n\t\tif device.Ignore() {\n\t\t\tcontinue\n\t\t}\n\n\t\tdeviceInterface := linkNameResolver.Resolve(device.Interface())\n\n\t\tif device.Bond() != nil {\n\t\t\tfor idx, linkName := range device.Bond().Interfaces() {\n\t\t\t\tlinkName = linkNameResolver.Resolve(linkName)\n\n\t\t\t\tif bondData, exists := bondedLinks[linkName]; exists && bondData.F1 != deviceInterface {\n\t\t\t\t\tlogger.Sugar().Warnf(\"link %q is included in both bonds %q and %q\", linkName,\n\t\t\t\t\t\tbondData.F1, deviceInterface)\n\t\t\t\t}\n\n\t\t\t\tif bridgeName, exists := bridgedLinks[linkName]; exists {\n\t\t\t\t\tlogger.Sugar().Warnf(\"link %q is included in both bond %q and bridge %q\", linkName,\n\t\t\t\t\t\tbridgeName, deviceInterface)\n\t\t\t\t}\n\n\t\t\t\tbondedLinks[linkName] = ordered.MakePair(deviceInterface, idx)\n\t\t\t}\n\t\t}\n\n\t\tif device.Bridge() != nil {\n\t\t\tfor _, linkName := range device.Bridge().Interfaces() {\n\t\t\t\tlinkName = linkNameResolver.Resolve(linkName)\n\n\t\t\t\tif bridgeName, exists := bridgedLinks[linkName]; exists && bridgeName != deviceInterface {\n\t\t\t\t\tlogger.Sugar().Warnf(\"link %q is included in both bridges %q and %q\", linkName,\n\t\t\t\t\t\tbridgeName, deviceInterface)\n\t\t\t\t}\n\n\t\t\t\tif bondData, exists := bondedLinks[linkName]; exists {\n\t\t\t\t\tlogger.Sugar().Warnf(\"link %q is included in both bond %q and bridge %q\", linkName,\n\t\t\t\t\t\tbondData.F1, deviceInterface)\n\t\t\t\t}\n\n\t\t\t\tbridgedLinks[linkName] = deviceInterface\n\t\t\t}\n\t\t}\n\n\t\tif device.BridgePort() != nil {\n\t\t\tbridgePortMaster := linkNameResolver.Resolve(device.BridgePort().Master())\n\n\t\t\tif bridgeName, exists := bridgedLinks[deviceInterface]; exists && bridgeName != bridgePortMaster {\n\t\t\t\tlogger.Sugar().Warnf(\"link %q is included in both bridges %q and %q\", deviceInterface,\n\t\t\t\t\tbridgeName, bridgePortMaster)\n\t\t\t}\n\n\t\t\tif bondData, exists := bondedLinks[deviceInterface]; exists {\n\t\t\t\tlogger.Sugar().Warnf(\"link %q is included into both bond %q and bridge %q\", deviceInterface,\n\t\t\t\t\tbondData.F1, bridgePortMaster)\n\t\t\t}\n\n\t\t\tbridgedLinks[deviceInterface] = bridgePortMaster\n\t\t}\n\t}\n\n\tfor item := range devices.All() {\n\t\tdevice := item.TypedSpec().Device\n\n\t\tif device.Ignore() {\n\t\t\tcontinue\n\t\t}\n\n\t\tdeviceInterface := linkNameResolver.Resolve(device.Interface())\n\n\t\tif _, exists := linkMap[deviceInterface]; !exists {\n\t\t\tlinkMap[deviceInterface] = &network.LinkSpecSpec{\n\t\t\t\tName:        deviceInterface,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\t\t}\n\n\t\tif device.MTU() != 0 {\n\t\t\tlinkMap[deviceInterface].MTU = uint32(device.MTU())\n\t\t}\n\n\t\tif device.Bond() != nil {\n\t\t\tif err := SetBondMasterLegacy(linkMap[deviceInterface], device.Bond()); err != nil {\n\t\t\t\tlogger.Error(\"error parsing bond config\", zap.Error(err))\n\t\t\t}\n\t\t}\n\n\t\tif device.Bridge() != nil {\n\t\t\tif err := SetBridgeMasterLegacy(linkMap[deviceInterface], device.Bridge()); err != nil {\n\t\t\t\tlogger.Error(\"error parsing bridge config\", zap.Error(err))\n\t\t\t}\n\t\t}\n\n\t\tif device.WireguardConfig() != nil {\n\t\t\tif err := wireguardLinkLegacy(linkMap[deviceInterface], device.WireguardConfig()); err != nil {\n\t\t\t\tlogger.Error(\"error parsing wireguard config\", zap.Error(err))\n\t\t\t}\n\t\t}\n\n\t\tif device.Dummy() {\n\t\t\tdummyLink(linkMap[deviceInterface])\n\t\t}\n\n\t\tfor _, vlan := range device.Vlans() {\n\t\t\tvlanName := nethelpers.VLANLinkName(device.Interface(), vlan.ID()) // [NOTE]: VLAN uses the original interface name (before resolving aliases)\n\n\t\t\tlinkMap[vlanName] = &network.LinkSpecSpec{\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\n\t\t\tvlanLink(linkMap[vlanName], vlanName, deviceInterface, vlan)\n\t\t}\n\t}\n\n\tfor slaveName, bondData := range bondedLinks {\n\t\tif _, exists := linkMap[slaveName]; !exists {\n\t\t\tlinkMap[slaveName] = &network.LinkSpecSpec{\n\t\t\t\tName:        slaveName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\t\t}\n\n\t\tSetBondSlave(linkMap[slaveName], bondData)\n\t}\n\n\tfor slaveName, bridgeIface := range bridgedLinks {\n\t\tif _, exists := linkMap[slaveName]; !exists {\n\t\t\tlinkMap[slaveName] = &network.LinkSpecSpec{\n\t\t\t\tName:        slaveName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\t\t}\n\n\t\tSetBridgeSlave(linkMap[slaveName], bridgeIface)\n\t}\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkConfigController) processLinkConfigs(logger *zap.Logger, linkMap map[string]*network.LinkSpecSpec, cfg *config.MachineConfig, linkNameResolver *network.LinkResolver) {\n\tif cfg == nil {\n\t\treturn\n\t}\n\n\tfor _, linkConfig := range cfg.Config().NetworkCommonLinkConfigs() {\n\t\tlinkName := linkConfig.Name()\n\t\tlinkName = linkNameResolver.Resolve(linkName)\n\n\t\tif _, exists := linkMap[linkName]; !exists {\n\t\t\tlinkMap[linkName] = &network.LinkSpecSpec{\n\t\t\t\tName:        linkName,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\t\t}\n\n\t\tlinkMap[linkName].Up = linkConfig.Up().ValueOr(true)\n\n\t\tif mtu, ok := linkConfig.MTU().Get(); ok {\n\t\t\tlinkMap[linkName].MTU = mtu\n\t\t}\n\n\t\tif hwAddrConfig, ok := linkConfig.(talosconfig.NetworkHardwareAddressConfig); ok {\n\t\t\tif hwAddr, ok := hwAddrConfig.HardwareAddress().Get(); ok {\n\t\t\t\tlinkMap[linkName].HardwareAddress = hwAddr\n\t\t\t}\n\t\t} else {\n\t\t\tlinkMap[linkName].HardwareAddress = nil\n\t\t}\n\n\t\tif multicast, ok := linkConfig.Multicast().Get(); ok {\n\t\t\tlinkMap[linkName].Multicast = new(multicast)\n\t\t}\n\n\t\tswitch specificLinkConfig := linkConfig.(type) {\n\t\tcase talosconfig.NetworkPhysicalLinkConfig:\n\t\t\t// nothing specific for physical links\n\t\tcase talosconfig.NetworkDummyLinkConfig:\n\t\t\tdummyLink(linkMap[linkName])\n\t\tcase talosconfig.NetworkVLANConfig:\n\t\t\tparentLink := linkNameResolver.Resolve(specificLinkConfig.ParentLink())\n\t\t\tvlanLink(linkMap[linkName], linkName, parentLink, networkVLANConfigToVlaner{specificLinkConfig})\n\t\tcase talosconfig.NetworkBondConfig:\n\t\t\tSendBondMaster(linkMap[linkName], specificLinkConfig)\n\n\t\t\tbondedLinks := xslices.Map(specificLinkConfig.Links(), linkNameResolver.Resolve)\n\n\t\t\tfor idx, slaveLinkName := range bondedLinks {\n\t\t\t\tif _, exists := linkMap[slaveLinkName]; !exists {\n\t\t\t\t\tlinkMap[slaveLinkName] = &network.LinkSpecSpec{\n\t\t\t\t\t\tName:        slaveLinkName,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSetBondSlave(linkMap[slaveLinkName], ordered.MakePair(linkName, idx))\n\t\t\t}\n\t\tcase talosconfig.NetworkBridgeConfig:\n\t\t\tSetBridgeMaster(linkMap[linkName], specificLinkConfig)\n\n\t\t\tbridgedLinks := xslices.Map(specificLinkConfig.Links(), linkNameResolver.Resolve)\n\n\t\t\tfor _, slaveLinkName := range bridgedLinks {\n\t\t\t\tif _, exists := linkMap[slaveLinkName]; !exists {\n\t\t\t\t\tlinkMap[slaveLinkName] = &network.LinkSpecSpec{\n\t\t\t\t\t\tName:        slaveLinkName,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSetBridgeSlave(linkMap[slaveLinkName], linkName)\n\t\t\t}\n\t\tcase talosconfig.NetworkVRFConfig:\n\t\t\tSetVRFMaster(linkMap[linkName], specificLinkConfig)\n\n\t\t\tvrfLinks := xslices.Map(specificLinkConfig.Links(), linkNameResolver.Resolve)\n\n\t\t\tfor _, slaveLinkName := range vrfLinks {\n\t\t\t\tif _, exists := linkMap[slaveLinkName]; !exists {\n\t\t\t\t\tlinkMap[slaveLinkName] = &network.LinkSpecSpec{\n\t\t\t\t\t\tName:        slaveLinkName,\n\t\t\t\t\t\tUp:          true,\n\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSetVRFSlave(linkMap[slaveLinkName], linkName)\n\t\t\t}\n\t\tcase talosconfig.NetworkWireguardConfig:\n\t\t\twireguardLink(linkMap[linkName], specificLinkConfig)\n\t\tdefault:\n\t\t\tlogger.Error(\"unknown link config type\", zap.String(\"linkName\", linkName), zap.String(\"type\", fmt.Sprintf(\"%T\", specificLinkConfig)))\n\t\t}\n\t}\n\n\t// if we have DHCP config, bring up the link implicitly if it hasn't been configured yet\n\tfor _, dhcpConfig := range cfg.Config().NetworkDHCPConfigs() {\n\t\tlinkName := dhcpConfig.Name()\n\t\tlinkName = linkNameResolver.Resolve(linkName)\n\n\t\tif _, exists := linkMap[linkName]; !exists {\n\t\t\tlinkMap[linkName] = &network.LinkSpecSpec{\n\t\t\t\tName:        linkName,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t}\n\t\t}\n\t}\n}\n\ntype vlaner interface {\n\tID() uint16\n\tMode() nethelpers.VLANProtocol\n}\n\ntype networkVLANConfigToVlaner struct {\n\ttalosconfig.NetworkVLANConfig\n}\n\nfunc (v networkVLANConfigToVlaner) ID() uint16 {\n\treturn v.VLANID()\n}\n\nfunc (v networkVLANConfigToVlaner) Mode() nethelpers.VLANProtocol {\n\treturn v.VLANMode().ValueOr(nethelpers.VLANProtocol8021Q)\n}\n\nfunc vlanLink(link *network.LinkSpecSpec, vlanName, linkName string, vlan vlaner) {\n\tlink.Name = vlanName\n\tlink.Logical = true\n\tlink.Up = true\n\n\t// only legacy config specifies MTUs on VLANs this way\n\tif mtuConfig, ok := vlan.(interface{ MTU() uint32 }); ok {\n\t\tlink.MTU = mtuConfig.MTU()\n\t}\n\n\tlink.Kind = network.LinkKindVLAN\n\tlink.Type = nethelpers.LinkEther\n\tlink.ParentName = linkName\n\tlink.VLAN = network.VLANSpec{\n\t\tVID:      vlan.ID(),\n\t\tProtocol: vlan.Mode(),\n\t}\n}\n\nfunc wireguardLinkLegacy(link *network.LinkSpecSpec, config talosconfig.WireguardConfig) error {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindWireguard\n\tlink.Type = nethelpers.LinkNone\n\tlink.Wireguard = network.WireguardSpec{\n\t\tPrivateKey:   config.PrivateKey(),\n\t\tListenPort:   config.ListenPort(),\n\t\tFirewallMark: config.FirewallMark(),\n\t}\n\n\tfor _, peer := range config.Peers() {\n\t\tallowedIPs := make([]netip.Prefix, 0, len(peer.AllowedIPs()))\n\n\t\tfor _, allowedIP := range peer.AllowedIPs() {\n\t\t\tip, err := netip.ParsePrefix(allowedIP)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tallowedIPs = append(allowedIPs, ip)\n\t\t}\n\n\t\tlink.Wireguard.Peers = append(link.Wireguard.Peers, network.WireguardPeer{\n\t\t\tPublicKey:                   peer.PublicKey(),\n\t\t\tEndpoint:                    peer.Endpoint(),\n\t\t\tPersistentKeepaliveInterval: peer.PersistentKeepaliveInterval(),\n\t\t\tAllowedIPs:                  allowedIPs,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc wireguardLink(link *network.LinkSpecSpec, config talosconfig.NetworkWireguardConfig) {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindWireguard\n\tlink.Type = nethelpers.LinkNone\n\tlink.Wireguard = network.WireguardSpec{\n\t\tPrivateKey:   config.PrivateKey(),\n\t\tListenPort:   config.ListenPort().ValueOr(0),\n\t\tFirewallMark: config.FirewallMark().ValueOr(0),\n\t}\n\n\tfor _, peer := range config.Peers() {\n\t\tlink.Wireguard.Peers = append(link.Wireguard.Peers, network.WireguardPeer{\n\t\t\tPublicKey:                   peer.PublicKey(),\n\t\t\tPresharedKey:                peer.PresharedKey().ValueOr(\"\"),\n\t\t\tEndpoint:                    peer.Endpoint().ValueOr(\"\"),\n\t\t\tPersistentKeepaliveInterval: peer.PersistentKeepalive().ValueOr(0),\n\t\t\tAllowedIPs:                  peer.AllowedIPs(),\n\t\t})\n\t}\n}\n\nfunc dummyLink(link *network.LinkSpecSpec) {\n\tlink.Logical = true\n\tlink.Kind = \"dummy\"\n\tlink.Type = nethelpers.LinkEther\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:goconst,dupl\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype LinkConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *LinkConfigSuite) assertLinks(requiredIDs []string, check func(*network.LinkSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *LinkConfigSuite) assertNoLinks(unexpectedIDs []string) {\n\tfor _, id := range unexpectedIDs {\n\t\tctest.AssertNoResource[*network.LinkSpec](suite, id, rtestutils.WithNamespace(network.ConfigNamespaceName))\n\t}\n}\n\nfunc (suite *LinkConfigSuite) TestLoopback() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"default/lo\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"lo\", r.TypedSpec().Name)\n\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.LinkConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"cmdline/eth1\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().Name)\n\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\tasrt.Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)\n\t\t},\n\t)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkConfigSuite) TestMachineConfiguration() {\n\tconst kernelDriver = \"somekerneldriver\"\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:  24,\n\t\t\t\t\t\t\t\t\t\tVlanMTU: 1000,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"10.0.0.1/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 48,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"10.0.0.2/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.24/28\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceMTU:       9001,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.24/28\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\"eth2\", \"eth3\"},\n\t\t\t\t\t\t\t\t\tBondMode:       \"balance-xor\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond1\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondDeviceSelectors: []v1alpha1.NetworkDeviceSelector{{\n\t\t\t\t\t\t\t\t\t\tNetworkDeviceKernelDriver: kernelDriver,\n\t\t\t\t\t\t\t\t\t}},\n\t\t\t\t\t\t\t\t\tBondMode: \"balance-xor\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth4\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.42/24\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth5\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.43/24\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth8\",\n\t\t\t\t\t\t\t\tDeviceBridgePort: &v1alpha1.BridgePort{\n\t\t\t\t\t\t\t\t\tBridgePortMaster: \"br1\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\"eth4\", \"eth5\"},\n\t\t\t\t\t\t\t\t\tBridgeSTP: &v1alpha1.STP{\n\t\t\t\t\t\t\t\t\t\tSTPEnabled: new(false),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br1\",\n\t\t\t\t\t\t\t\tDeviceBridge:    &v1alpha1.Bridge{},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgeSTP: &v1alpha1.STP{\n\t\t\t\t\t\t\t\t\t\tSTPEnabled: new(true),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tBridgeVLAN: &v1alpha1.BridgeVLAN{\n\t\t\t\t\t\t\t\t\t\tBridgeVLANFiltering: new(true),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"dummy0\",\n\t\t\t\t\t\t\t\tDeviceDummy:     new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"wireguard0\",\n\t\t\t\t\t\t\t\tDeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{\n\t\t\t\t\t\t\t\t\tWireguardPrivateKey: \"ABC\",\n\t\t\t\t\t\t\t\t\tWireguardPeers: []*v1alpha1.DeviceWireguardPeer{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tWireguardPublicKey: \"DEF\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardEndpoint:  \"10.0.0.1:3000\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardAllowedIPs: []string{\n\t\t\t\t\t\t\t\t\t\t\t\t\"10.2.3.0/24\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"10.2.4.0/24\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tfor _, name := range []string{\"eth6\", \"eth7\"} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, name)\n\t\tstatus.TypedSpec().Driver = kernelDriver\n\n\t\tsuite.Create(status)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/eth0\",\n\t\t\t\"configuration/eth0.24\",\n\t\t\t\"configuration/eth0.48\",\n\t\t\t\"configuration/eth1\",\n\t\t\t\"configuration/eth2\",\n\t\t\t\"configuration/eth3\",\n\t\t\t\"configuration/eth6\",\n\t\t\t\"configuration/eth7\",\n\t\t\t\"configuration/eth8\",\n\t\t\t\"configuration/bond0\",\n\t\t\t\"configuration/bond1\",\n\t\t\t\"configuration/br0\",\n\t\t\t\"configuration/br1\",\n\t\t\t\"configuration/dummy0\",\n\t\t\t\"configuration/wireguard0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tswitch r.TypedSpec().Name {\n\t\t\tcase \"eth0\", \"eth1\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\n\t\t\t\tif r.TypedSpec().Name == \"eth0\" {\n\t\t\t\t\tasrt.EqualValues(0, r.TypedSpec().MTU)\n\t\t\t\t} else {\n\t\t\t\t\tasrt.EqualValues(9001, r.TypedSpec().MTU)\n\t\t\t\t}\n\n\t\t\t\tasrt.Nil(r.TypedSpec().Multicast)\n\t\t\tcase \"eth0.24\", \"eth0.48\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().ParentName)\n\t\t\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)\n\n\t\t\t\tif r.TypedSpec().Name == \"eth0.24\" {\n\t\t\t\t\tasrt.EqualValues(24, r.TypedSpec().VLAN.VID)\n\t\t\t\t\tasrt.EqualValues(1000, r.TypedSpec().MTU)\n\t\t\t\t} else {\n\t\t\t\t\tasrt.EqualValues(48, r.TypedSpec().VLAN.VID)\n\t\t\t\t\tasrt.EqualValues(0, r.TypedSpec().MTU)\n\t\t\t\t}\n\t\t\tcase \"eth2\", \"eth3\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(\"bond0\", r.TypedSpec().BondSlave.MasterName)\n\t\t\tcase \"eth6\", \"eth7\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(\"bond1\", r.TypedSpec().BondSlave.MasterName)\n\t\t\tcase \"bond0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(nethelpers.BondModeXOR, r.TypedSpec().BondMaster.Mode)\n\t\t\t\tasrt.True(r.TypedSpec().BondMaster.UseCarrier)\n\t\t\tcase \"bond1\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(nethelpers.BondModeXOR, r.TypedSpec().BondMaster.Mode)\n\t\t\t\tasrt.True(r.TypedSpec().BondMaster.UseCarrier)\n\t\t\tcase \"eth4\", \"eth5\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(\"br0\", r.TypedSpec().BridgeSlave.MasterName)\n\t\t\tcase \"eth8\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(\"br1\", r.TypedSpec().BridgeSlave.MasterName)\n\t\t\tcase \"br0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBridge, r.TypedSpec().Kind)\n\t\t\t\tasrt.True(r.TypedSpec().BridgeMaster.STP.Enabled)\n\t\t\t\tasrt.True(r.TypedSpec().BridgeMaster.VLAN.FilteringEnabled)\n\t\t\tcase \"br1\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBridge, r.TypedSpec().Kind)\n\t\t\t\tasrt.True(r.TypedSpec().BridgeMaster.STP.Enabled)\n\t\t\t\tasrt.False(r.TypedSpec().BridgeMaster.VLAN.FilteringEnabled)\n\t\t\tcase \"wireguard0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkNone, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindWireguard, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(\n\t\t\t\t\tnetwork.WireguardSpec{\n\t\t\t\t\t\tPrivateKey: \"ABC\",\n\t\t\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tPublicKey: \"DEF\",\n\t\t\t\t\t\t\t\tEndpoint:  \"10.0.0.1:3000\",\n\t\t\t\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.2.3.0/24\"),\n\t\t\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.2.4.0/24\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}, r.TypedSpec().Wireguard,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestMachineConfigurationWithAliases() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enx0123\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:  24,\n\t\t\t\t\t\t\t\t\t\tVlanMTU: 1000,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enx0123\",\n\t\t\t\t\t\t\t\tDeviceMTU:       9001,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"enx0456\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\"enxa\", \"enxb\"},\n\t\t\t\t\t\t\t\t\tBondMode:       \"balance-xor\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth0\",\n\t\t\taliases: []string{\"enx0123\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth1\",\n\t\t\taliases: []string{\"enx0456\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth2\",\n\t\t\taliases: []string{\"enxa\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth3\",\n\t\t\taliases: []string{\"enxb\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\n\t\tsuite.Create(status)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/eth0\",\n\t\t\t\"configuration/enx0123.24\",\n\t\t\t\"configuration/eth2\",\n\t\t\t\"configuration/eth3\",\n\t\t\t\"configuration/bond0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tswitch r.TypedSpec().Name {\n\t\t\tcase \"eth0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.EqualValues(9001, r.TypedSpec().MTU)\n\t\t\tcase \"eth2\", \"eth3\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(\"bond0\", r.TypedSpec().BondSlave.MasterName)\n\t\t\tcase \"eth0.24\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().ParentName)\n\t\t\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)\n\n\t\t\t\tasrt.EqualValues(24, r.TypedSpec().VLAN.VID)\n\t\t\t\tasrt.EqualValues(1000, r.TypedSpec().MTU)\n\t\t\tcase \"bond0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(nethelpers.BondModeXOR, r.TypedSpec().BondMaster.Mode)\n\t\t\t\tasrt.True(r.TypedSpec().BondMaster.UseCarrier)\n\t\t\t\tasrt.Equal(nethelpers.ADLACPActiveOn, r.TypedSpec().BondMaster.ADLACPActive)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestMachineConfigurationNewStyle() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkMTU = 9001\n\n\tdc1 := networkcfg.NewDummyLinkConfigV1Alpha1(\"dummy1\")\n\tdc1.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x42, 0xac, 0x11, 0x00, 0x02}\n\tdc1.LinkUp = new(true)\n\n\tvl1 := networkcfg.NewVLANConfigV1Alpha1(\"dummy1.100\")\n\tvl1.VLANIDConfig = 100\n\tvl1.ParentLinkConfig = \"dummy1\"\n\tvl1.VLANModeConfig = new(nethelpers.VLANProtocol8021AD)\n\tvl1.LinkMTU = 200\n\tvl1.LinkUp = new(true)\n\n\tdc2 := networkcfg.NewDummyLinkConfigV1Alpha1(\"dummy2\")\n\tdc3 := networkcfg.NewDummyLinkConfigV1Alpha1(\"dummy3\")\n\n\tbc1 := networkcfg.NewBondConfigV1Alpha1(\"bond357\")\n\tbc1.BondMode = new(nethelpers.BondModeActiveBackup)\n\tbc1.BondLinks = []string{\"dummy2\", \"dummy3\"}\n\tbc1.BondUpDelay = new(uint32(200))\n\n\tbr1 := networkcfg.NewBridgeConfigV1Alpha1(\"br0\")\n\tbr1.BridgeLinks = []string{\"enp0s2\", \"eth1\"}\n\tbr1.BridgeSTP.BridgeSTPEnabled = new(true)\n\tbr1.BridgeVLAN.BridgeVLANFiltering = new(true)\n\n\tctr, err := container.New(dc1, lc1, vl1, dc2, dc3, bc1, br1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth0\",\n\t\t\taliases: []string{\"enp0s2\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\n\t\tsuite.Create(status)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/eth0\",\n\t\t\t\"configuration/dummy1\",\n\t\t\t\"configuration/dummy2\",\n\t\t\t\"configuration/dummy3\",\n\t\t\t\"configuration/dummy1.100\",\n\t\t\t\"configuration/bond357\",\n\t\t\t\"configuration/br0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tswitch r.TypedSpec().Name {\n\t\t\tcase \"eth0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.EqualValues(9001, r.TypedSpec().MTU)\n\t\t\t\tasrt.Equal(\"br0\", r.TypedSpec().BridgeSlave.MasterName)\n\t\t\tcase \"eth1\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.Equal(\"br0\", r.TypedSpec().BridgeSlave.MasterName)\n\t\t\tcase \"dummy1\", \"dummy2\", \"dummy3\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\n\t\t\t\tif r.TypedSpec().Name == \"dummy2\" || r.TypedSpec().Name == \"dummy3\" {\n\t\t\t\t\tasrt.Equal(\"bond357\", r.TypedSpec().BondSlave.MasterName)\n\t\t\t\t}\n\t\t\tcase \"dummy1.100\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(\"dummy1\", r.TypedSpec().ParentName)\n\t\t\t\tasrt.Equal(nethelpers.VLANProtocol8021AD, r.TypedSpec().VLAN.Protocol)\n\t\t\t\tasrt.EqualValues(100, r.TypedSpec().VLAN.VID)\n\t\t\t\tasrt.EqualValues(200, r.TypedSpec().MTU)\n\t\t\tcase \"bond357\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(nethelpers.BondModeActiveBackup, r.TypedSpec().BondMaster.Mode)\n\t\t\t\tasrt.EqualValues(200, r.TypedSpec().BondMaster.UpDelay)\n\t\t\t\tasrt.Equal(nethelpers.ADLACPActiveOn, r.TypedSpec().BondMaster.ADLACPActive)\n\t\t\tcase \"br0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindBridge, r.TypedSpec().Kind)\n\t\t\t\tasrt.True(r.TypedSpec().BridgeMaster.STP.Enabled)\n\t\t\t\tasrt.True(r.TypedSpec().BridgeMaster.VLAN.FilteringEnabled)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestMachineConfigurationNewStyleVRF() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkMTU = 9001\n\n\tdc1 := networkcfg.NewDummyLinkConfigV1Alpha1(\"dummy1\")\n\tdc1.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x42, 0xac, 0x11, 0x00, 0x02}\n\tdc1.LinkUp = new(true)\n\n\tvrf := networkcfg.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\tvrf.VRFLinks = []string{\"enp0s2\", \"dummy1\"}\n\tvrf.VRFTable = nethelpers.RoutingTable(123)\n\n\tctr, err := container.New(lc1, dc1, vrf)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth0\",\n\t\t\taliases: []string{\"enp0s2\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\n\t\tsuite.Create(status)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/eth0\",\n\t\t\t\"configuration/dummy1\",\n\t\t\t\"configuration/vrf-blue\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tswitch r.TypedSpec().Name {\n\t\t\tcase \"eth0\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.False(r.TypedSpec().Logical)\n\t\t\t\tasrt.EqualValues(9001, r.TypedSpec().MTU)\n\t\t\t\tasrt.Equal(\"vrf-blue\", r.TypedSpec().VRFSlave.MasterName)\n\t\t\tcase \"dummy1\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(\"vrf-blue\", r.TypedSpec().VRFSlave.MasterName)\n\t\t\tcase \"vrf-blue\":\n\t\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\t\tasrt.Equal(nethelpers.LinkEther, r.TypedSpec().Type)\n\t\t\t\tasrt.Equal(network.LinkKindVRF, r.TypedSpec().Kind)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(123), r.TypedSpec().VRFMaster.Table)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestMachineConfigurationNewStyleNotFIPS() {\n\tif fipsmode.Strict() {\n\t\tsuite.T().Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tprivKey, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\tpskKey, err := wgtypes.GenerateKey()\n\tsuite.Require().NoError(err)\n\n\tpeerKey, err := wgtypes.GenerateKey()\n\tsuite.Require().NoError(err)\n\n\twc1 := networkcfg.NewWireguardConfigV1Alpha1(\"wg0\")\n\twc1.LinkUp = new(true)\n\twc1.WireguardPrivateKey = privKey.String()\n\twc1.WireguardListenPort = 12345\n\twc1.WireguardPeers = []networkcfg.WireguardPeer{\n\t\t{\n\t\t\tWireguardPublicKey:    peerKey.PublicKey().String(),\n\t\t\tWireguardPresharedKey: pskKey.String(),\n\t\t\tWireguardAllowedIPs:   []networkcfg.Prefix{{Prefix: netip.MustParsePrefix(\"10.0.0.0/24\")}},\n\t\t},\n\t}\n\n\tctr, err := container.New(wc1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/wg0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\tasrt.Equal(nethelpers.LinkNone, r.TypedSpec().Type)\n\t\t\tasrt.Equal(network.LinkKindWireguard, r.TypedSpec().Kind)\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.WireguardSpec{\n\t\t\t\t\tPrivateKey:   privKey.String(),\n\t\t\t\t\tListenPort:   12345,\n\t\t\t\t\tFirewallMark: 0,\n\t\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tPublicKey:    peerKey.PublicKey().String(),\n\t\t\t\t\t\t\tPresharedKey: pskKey.String(),\n\t\t\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/24\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tr.TypedSpec().Wireguard,\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestDefaultUp() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.LinkConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"talos.network.interface.ignore=eth2\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tfor _, link := range []string{\"eth5\", \"eth1\", \"eth2\", \"eth3\", \"eth4\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tif link == \"eth5\" {\n\t\t\tlinkStatus.TypedSpec().AltNames = []string{\"enp0s2\"}\n\t\t}\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 24,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"10.0.0.1/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 48,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"10.0.0.2/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth3\",\n\t\t\t\t\t\t\t\t\t\t\"eth4\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"default/eth1\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t},\n\t)\n\n\tsuite.assertNoLinks(\n\t\t[]string{\n\t\t\t\"default/eth0\",\n\t\t\t\"default/eth2\",\n\t\t\t\"default/eth3\",\n\t\t\t\"default/eth4\",\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestNoDefaultUp() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tfor _, link := range []string{\"eth5\", \"eth1\", \"eth2\", \"eth3\", \"eth4\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tif link == \"eth5\" {\n\t\t\tlinkStatus.TypedSpec().AltNames = []string{\"eth0\"}\n\t\t}\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\t// default link up\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"default/eth1\",\n\t\t\t\"default/eth2\",\n\t\t\t\"default/eth3\",\n\t\t\t\"default/eth4\",\n\t\t\t\"default/eth5\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.True(r.TypedSpec().Up)\n\t\t},\n\t)\n\n\t// create config\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkMTU = 9001\n\n\tctr, err := container.New(lc1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\t// no default links up since we have config now\n\tsuite.assertNoLinks(\n\t\t[]string{\n\t\t\t\"default/eth0\",\n\t\t\t\"default/eth1\",\n\t\t\t\"default/eth2\",\n\t\t\t\"default/eth3\",\n\t\t\t\"default/eth4\",\n\t\t\t\"default/eth5\",\n\t\t},\n\t)\n}\n\nfunc (suite *LinkConfigSuite) TestMulticast() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkConfigController{}))\n\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp1s1\")\n\tlc1.LinkMulticast = new(false)\n\tlc2 := networkcfg.NewLinkConfigV1Alpha1(\"enp1s2\")\n\tlc2.LinkMulticast = new(true)\n\n\tctr, err := container.New(lc1, lc2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"configuration/enp1s1\",\n\t\t\t\"configuration/enp1s2\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tswitch r.TypedSpec().Name {\n\t\t\tcase \"enp1s1\":\n\t\t\t\tasrt.False(*r.TypedSpec().Multicast)\n\t\t\tcase \"enp1s2\":\n\t\t\t\tasrt.True(*r.TypedSpec().Multicast)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc TestLinkConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &LinkConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"cmp\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewLinkMergeController initializes a LinkMergeController.\n//\n// LinkMergeController merges network.LinkSpec in network.ConfigNamespace and produces final network.AddressSpec in network.Namespace.\nfunc NewLinkMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.LinkSpec]) map[resource.ID]*network.LinkSpecSpec {\n\t\t\t// sort by link name, configuration layer\n\t\t\tlist.SortFunc(func(left, right *network.LinkSpec) int {\n\t\t\t\tif res := cmp.Compare(left.TypedSpec().Name, right.TypedSpec().Name); res != 0 {\n\t\t\t\t\treturn res\n\t\t\t\t}\n\n\t\t\t\treturn cmp.Compare(left.TypedSpec().ConfigLayer, right.TypedSpec().ConfigLayer)\n\t\t\t})\n\n\t\t\t// build final link definition merging multiple layers\n\t\t\tlinks := make(map[string]*network.LinkSpecSpec, list.Len())\n\n\t\t\tfor link := range list.All() {\n\t\t\t\tid := network.LinkID(link.TypedSpec().Name)\n\n\t\t\t\texisting, ok := links[id]\n\t\t\t\tif !ok {\n\t\t\t\t\tlinks[id] = link.TypedSpec()\n\t\t\t\t} else if err := existing.Merge(link.TypedSpec()); err != nil {\n\t\t\t\t\tlogger.Warn(\"error merging links\", zap.Error(err))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn links\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:goconst\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype LinkMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *LinkMergeSuite) assertLinks(requiredIDs []string, check func(*network.LinkSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *LinkMergeSuite) assertNoLinks(id string) {\n\tctest.AssertNoResource[*network.LinkSpec](suite, id)\n}\n\nfunc (suite *LinkMergeSuite) TestMerge() {\n\tloopback := network.NewLinkSpec(network.ConfigNamespaceName, \"default/lo\")\n\t*loopback.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"lo\",\n\t\tUp:          true,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp := network.NewLinkSpec(network.ConfigNamespaceName, \"dhcp/eth0\")\n\t*dhcp.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tMTU:         1450,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewLinkSpec(network.ConfigNamespaceName, \"configuration/eth0\")\n\t*static.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tMTU:         1500,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{loopback, dhcp, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"lo\",\n\t\t\t\"eth0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"lo\":\n\t\t\t\tasrt.Equal(*loopback.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"eth0\":\n\t\t\t\tasrt.EqualValues(1500, r.TypedSpec().MTU) // static should override dhcp\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"lo\",\n\t\t\t\"eth0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"lo\":\n\t\t\t\tasrt.Equal(*loopback.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"eth0\":\n\t\t\t\t// reconcile happens eventually, so give it some time\n\t\t\t\tasrt.EqualValues(1450, r.TypedSpec().MTU)\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(loopback)\n\n\tsuite.assertNoLinks(\"lo\")\n}\n\nfunc (suite *LinkMergeSuite) TestMergeLogicalLink() {\n\tbondPlatform := network.NewLinkSpec(network.ConfigNamespaceName, \"platform/bond0\")\n\t*bondPlatform.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    \"bond0\",\n\t\tLogical: true,\n\t\tUp:      true,\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode: nethelpers.BondMode8023AD,\n\t\t},\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tbondMachineConfig := network.NewLinkSpec(network.ConfigNamespaceName, \"config/bond0\")\n\t*bondMachineConfig.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"bond0\",\n\t\tMTU:         1450,\n\t\tUp:          true,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{bondPlatform, bondMachineConfig} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"bond0\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().Logical)\n\t\t\tasrt.EqualValues(1450, r.TypedSpec().MTU)\n\t\t},\n\t)\n}\n\nfunc (suite *LinkMergeSuite) TestMergeFlapping() {\n\t// simulate two conflicting link definitions which are getting removed/added constantly\n\tdhcp := network.NewLinkSpec(network.ConfigNamespaceName, \"dhcp/eth0\")\n\t*dhcp.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tMTU:         1450,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewLinkSpec(network.ConfigNamespaceName, \"configuration/eth0\")\n\t*static.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tMTU:         1500,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\ttestMergeFlapping(&suite.DefaultSuite, []*network.LinkSpec{dhcp, static}, \"eth0\", static)\n}\n\nfunc (suite *LinkMergeSuite) TestMergeWireguard() {\n\tstatic := network.NewLinkSpec(network.ConfigNamespaceName, \"configuration/kubespan\")\n\t*static.TypedSpec() = network.LinkSpecSpec{\n\t\tName: \"kubespan\",\n\t\tWireguard: network.WireguardSpec{\n\t\t\tListenPort: 1234,\n\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey: \"bGsc2rOpl6JHd/Pm4fYrIkEABL0ZxW7IlaSyh77IMhw=\",\n\t\t\t\t\tEndpoint:  \"127.0.0.1:9999\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tkubespanOperator := network.NewLinkSpec(network.ConfigNamespaceName, \"kubespan/kubespan\")\n\t*kubespanOperator.TypedSpec() = network.LinkSpecSpec{\n\t\tName: \"kubespan\",\n\t\tWireguard: network.WireguardSpec{\n\t\t\tPrivateKey: \"IG9MqCII7z54Ysof1fQ9a7WcMNG+qNJRMyRCQz3JTUY=\",\n\t\t\tListenPort: 3456,\n\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey: \"RXdQkMTD1Jcxd/Wizr9k8syw8ANs57l5jTormDVHAVs=\",\n\t\t\t\t\tEndpoint:  \"127.0.0.1:1234\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tfor _, res := range []resource.Resource{static, kubespanOperator} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertLinks(\n\t\t[]string{\n\t\t\t\"kubespan\",\n\t\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t\"IG9MqCII7z54Ysof1fQ9a7WcMNG+qNJRMyRCQz3JTUY=\",\n\t\t\t\tr.TypedSpec().Wireguard.PrivateKey,\n\t\t\t)\n\t\t\tasrt.Equal(1234, r.TypedSpec().Wireguard.ListenPort)\n\t\t\tasrt.Len(r.TypedSpec().Wireguard.Peers, 2)\n\n\t\t\tif len(r.TypedSpec().Wireguard.Peers) != 2 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.WireguardPeer{\n\t\t\t\t\tPublicKey: \"RXdQkMTD1Jcxd/Wizr9k8syw8ANs57l5jTormDVHAVs=\",\n\t\t\t\t\tEndpoint:  \"127.0.0.1:1234\",\n\t\t\t\t},\n\t\t\t\tr.TypedSpec().Wireguard.Peers[0],\n\t\t\t)\n\n\t\t\tasrt.Equal(\n\t\t\t\tnetwork.WireguardPeer{\n\t\t\t\t\tPublicKey: \"bGsc2rOpl6JHd/Pm4fYrIkEABL0ZxW7IlaSyh77IMhw=\",\n\t\t\t\t\tEndpoint:  \"127.0.0.1:9999\",\n\t\t\t\t},\n\t\t\t\tr.TypedSpec().Wireguard.Peers[1],\n\t\t\t)\n\t\t},\n\t)\n\n\tsuite.Destroy(kubespanOperator)\n\tsuite.Destroy(static)\n\n\tsuite.assertNoLinks(\"kubespan\")\n}\n\nfunc TestLinkMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &LinkMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewLinkMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\t\"golang.zx2c4.com/wireguard/wgctrl\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LinkSpecController applies network.LinkSpec to the actual interfaces.\ntype LinkSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LinkSpecController) Name() string {\n\treturn \"network.LinkSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LinkSpecController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LinkSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.LinkRefreshType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *LinkSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy, which implies that all link renames are done\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.LinkSpecType,\n\t\t\t\tKind:      controller.InputStrong,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\t// watch link changes as some routes might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\twgClient, err := wgctrl.New()\n\tif err != nil {\n\t\tlogger.Warn(\"error creating wireguard client\", zap.Error(err))\n\t} else {\n\t\tdefer wgClient.Close() //nolint:errcheck\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := safe.ReaderList[*network.LinkSpec](ctx, r, resource.NewMetadata(network.NamespaceName, network.LinkSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network addresses: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// list rtnetlink links (interfaces)\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\t// loop over links and make reconcile decision\n\t\tvar multiErr *multierror.Error\n\n\t\tSortBonds(&list)\n\n\t\tfor link := range list.All() {\n\t\t\tif err = ctrl.syncLink(ctx, r, logger, conn, wgClient, &links, link); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t}\n\t\t}\n\n\t\tif err = multiErr.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// SortBonds sort resources in increasing order, except it places slave interfaces right after the bond\n// in proper order.\nfunc SortBonds(items *safe.List[*network.LinkSpec]) {\n\titems.SortFunc(func(ll, rr *network.LinkSpec) int {\n\t\tleft := ll.TypedSpec()\n\t\tright := rr.TypedSpec()\n\n\t\tl := ordered.MakeTriple(left.Name, 0, \"\")\n\t\tif left.BondSlave.MasterName != \"\" {\n\t\t\tl = ordered.MakeTriple(left.BondSlave.MasterName, left.BondSlave.SlaveIndex, left.Name)\n\t\t}\n\n\t\tr := ordered.MakeTriple(right.Name, 0, \"\")\n\t\tif right.BondSlave.MasterName != \"\" {\n\t\t\tr = ordered.MakeTriple(right.BondSlave.MasterName, right.BondSlave.SlaveIndex, right.Name)\n\t\t}\n\n\t\treturn l.Compare(r)\n\t})\n}\n\nfunc findLink(links []rtnetlink.LinkMessage, name string, allowAliases bool) *rtnetlink.LinkMessage {\n\tif name == \"\" {\n\t\treturn nil // should never match\n\t}\n\n\tfor i, link := range links {\n\t\tif link.Attributes.Name == name {\n\t\t\treturn &links[i]\n\t\t}\n\t}\n\n\tif !allowAliases {\n\t\treturn nil\n\t}\n\n\tfor i, link := range links {\n\t\tif pointer.SafeDeref(link.Attributes.Alias) == name {\n\t\t\treturn &links[i]\n\t\t}\n\n\t\tif slices.Index(link.Attributes.AltNames, name) != -1 {\n\t\t\treturn &links[i]\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// syncLink syncs kernel state with the LinkSpec link.\n//\n// This method is really long, but it's hard to break it down in multiple pieces, are those pieces and steps are inter-dependent, so, instead,\n// I'm going to provide high-level flow of the method here to help understand it:\n//\n// First of all, if the spec is being torn down - remove the link from the kernel, done.\n// If the link spec is not being torn down, start the sync process:\n//\n//   - for physical links, there's not much we can sync - only MTU and 'UP' flag\n//   - for logical links, controller handles creation and sync of the settings depending on the interface type\n//\n// If the logical link kind or type got changed (for example, \"link0\" was a bond, and now it's wireguard interface), the link\n// is dropped and replaced with the new one.\n// Same replace flow is used for VLAN links, as VLAN settings can't be changed on the fly.\n//\n// For bonded links, there are two sync steps applied:\n//\n//   - bond slave interfaces are enslaved to be part of the bond (by changing MasterIndex)\n//   - bond master link settings are synced with the spec: some settings can't be applied on UP bond and a bond which has slaves,\n//     so slaves are removed and bond is brought down (these settings are going to be reconciled back in the next sync cycle)\n//\n// For wireguard links, only settings are synced with the diff generated by the WireguardSpec.\n//\n//nolint:gocyclo,cyclop,dupl\nfunc (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, wgClient *wgctrl.Client,\n\tlinks *[]rtnetlink.LinkMessage, link *network.LinkSpec,\n) error {\n\tlogger = logger.With(zap.String(\"link\", link.TypedSpec().Name))\n\n\tswitch link.Metadata().Phase() {\n\tcase resource.PhaseTearingDown:\n\t\t// TODO: should we bring link down if it's physical and the spec was torn down?\n\t\tif link.TypedSpec().Logical {\n\t\t\texisting := findLink(*links, link.TypedSpec().Name, false) // logical links don't have aliases\n\n\t\t\tif existing != nil {\n\t\t\t\tif err := conn.Link.Delete(existing.Index); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error deleting link %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"deleted link\")\n\n\t\t\t\t// refresh links as the link list got changed\n\t\t\t\tvar err error\n\n\t\t\t\t*links, err = conn.Link.List()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// now remove finalizer as link was deleted\n\t\tif err := r.RemoveFinalizer(ctx, link.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t}\n\tcase resource.PhaseRunning:\n\t\texisting := findLink(*links, link.TypedSpec().Name, !link.TypedSpec().Logical) // allow aliases for physical links\n\n\t\tvar existingRawLinkData []byte\n\n\t\tif existing != nil && existing.Attributes != nil && existing.Attributes.Info != nil && existing.Attributes.Info.Data != nil {\n\t\t\tif existingLinkData, ok := existing.Attributes.Info.Data.(*rtnetlink.LinkData); ok {\n\t\t\t\texistingRawLinkData = existingLinkData.Data\n\t\t\t}\n\t\t}\n\n\t\t// check if type/kind matches for the existing logical link\n\t\tif existing != nil && link.TypedSpec().Logical {\n\t\t\treplace := false\n\n\t\t\tif existing.Attributes.Info == nil {\n\t\t\t\tlogger.Warn(\"requested logical link has no info, skipping sync\",\n\t\t\t\t\tzap.String(\"name\", existing.Attributes.Name),\n\t\t\t\t\tzap.Stringer(\"type\", nethelpers.LinkType(existing.Type)),\n\t\t\t\t\tzap.Uint32(\"index\", existing.Index),\n\t\t\t\t)\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// if type/kind doesn't match, recreate the link to change it\n\t\t\tif existing.Type != uint16(link.TypedSpec().Type) || existing.Attributes.Info.Kind != link.TypedSpec().Kind {\n\t\t\t\tlogger.Info(\"replacing logical link\",\n\t\t\t\t\tzap.String(\"old_kind\", existing.Attributes.Info.Kind),\n\t\t\t\t\tzap.String(\"new_kind\", link.TypedSpec().Kind),\n\t\t\t\t\tzap.Stringer(\"old_type\", nethelpers.LinkType(existing.Type)),\n\t\t\t\t\tzap.Stringer(\"new_type\", link.TypedSpec().Type),\n\t\t\t\t)\n\n\t\t\t\treplace = true\n\t\t\t}\n\n\t\t\t// sync VLAN spec, as it can't be modified on the fly\n\t\t\tif !replace && link.TypedSpec().Kind == network.LinkKindVLAN {\n\t\t\t\tvar existingVLAN network.VLANSpec\n\n\t\t\t\tif existingRawLinkData == nil {\n\t\t\t\t\treturn fmt.Errorf(\"existing link %q has no data, can't decode VLAN settings\", link.TypedSpec().Name)\n\t\t\t\t}\n\n\t\t\t\tif err := networkadapter.VLANSpec(&existingVLAN).Decode(existingRawLinkData); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error decoding VLAN properties on %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tif existingVLAN != link.TypedSpec().VLAN {\n\t\t\t\t\tlogger.Info(\"replacing VLAN link\",\n\t\t\t\t\t\tzap.Uint16(\"old_id\", existingVLAN.VID),\n\t\t\t\t\t\tzap.Uint16(\"new_id\", link.TypedSpec().VLAN.VID),\n\t\t\t\t\t\tzap.Stringer(\"old_protocol\", existingVLAN.Protocol),\n\t\t\t\t\t\tzap.Stringer(\"new_protocol\", link.TypedSpec().VLAN.Protocol),\n\t\t\t\t\t)\n\n\t\t\t\t\treplace = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// sync VRF spec, as it can't be modified on the fly\n\t\t\tif !replace && link.TypedSpec().Kind == network.LinkKindVRF {\n\t\t\t\tvar existingVRF network.VRFMasterSpec\n\n\t\t\t\tif existingRawLinkData == nil {\n\t\t\t\t\treturn fmt.Errorf(\"existing link %q has no data, can't decode vrf settings\", link.TypedSpec().Name)\n\t\t\t\t}\n\n\t\t\t\tif err := networkadapter.VRFMasterSpec(&existingVRF).Decode(existingRawLinkData); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error decoding vrf properties on %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tif existingVRF != link.TypedSpec().VRFMaster {\n\t\t\t\t\tlogger.Info(\"replacing vrf link\",\n\t\t\t\t\t\tzap.Stringer(\"old_table\", existingVRF.Table),\n\t\t\t\t\t\tzap.Stringer(\"new_table\", link.TypedSpec().VRFMaster.Table),\n\t\t\t\t\t)\n\n\t\t\t\t\treplace = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif replace {\n\t\t\t\tif err := conn.Link.Delete(existing.Index); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error deleting link %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\t// not refreshing links, as the link is set to be re-created\n\n\t\t\t\texisting = nil\n\t\t\t}\n\t\t}\n\n\t\tif existing == nil {\n\t\t\tif !link.TypedSpec().Logical {\n\t\t\t\t// physical interface doesn't exist yet, nothing to be done\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// create logical interface\n\t\t\tvar (\n\t\t\t\tmasterIndex *uint32\n\t\t\t\tparentIndex uint32\n\t\t\t\tdata        []byte\n\t\t\t\terr         error\n\t\t\t)\n\n\t\t\t// VLAN settings should be set on interface creation (parent + VLAN settings)\n\t\t\tif link.TypedSpec().ParentName != \"\" {\n\t\t\t\tparent := findLink(*links, link.TypedSpec().ParentName, true) // allow aliases for physical links/parents\n\t\t\t\tif parent == nil {\n\t\t\t\t\t// parent doesn't exist yet, skip it\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tparentIndex = parent.Index\n\t\t\t}\n\n\t\t\tif link.TypedSpec().Kind == network.LinkKindVLAN {\n\t\t\t\tdata, err = networkadapter.VLANSpec(&link.TypedSpec().VLAN).Encode()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error encoding VLAN attributes for link %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// vrf settings should be set on interface creation (parent + vrf settings)\n\t\t\tif link.TypedSpec().VRFSlave.MasterName != \"\" {\n\t\t\t\tmaster := findLink(*links, link.TypedSpec().VRFSlave.MasterName, false)\n\t\t\t\tif master == nil {\n\t\t\t\t\t// master doesn't exist yet, skip it\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tmasterIndex = &master.Index\n\t\t\t\tlogger.Info(\"creating vrf slave link\",\n\t\t\t\t\tzap.Uint32p(\"master_index\", masterIndex),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif link.TypedSpec().Kind == network.LinkKindVRF {\n\t\t\t\tdata, err = networkadapter.VRFMasterSpec(&link.TypedSpec().VRFMaster).Encode()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error encoding vrf attributes for link %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err = conn.Link.New(&rtnetlink.LinkMessage{\n\t\t\t\tType: uint16(link.TypedSpec().Type),\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName:    link.TypedSpec().Name,\n\t\t\t\t\tAddress: net.HardwareAddr(link.TypedSpec().HardwareAddress),\n\t\t\t\t\tType:    parentIndex,\n\t\t\t\t\tMaster:  masterIndex,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: link.TypedSpec().Kind,\n\t\t\t\t\t\tData: &rtnetlink.LinkData{\n\t\t\t\t\t\t\tName: link.TypedSpec().Kind,\n\t\t\t\t\t\t\tData: data,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating logical link %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"created new link\", zap.String(\"kind\", link.TypedSpec().Kind))\n\n\t\t\t// refresh links as the link list got changed\n\t\t\t*links, err = conn.Link.List()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t\t}\n\n\t\t\texisting = findLink(*links, link.TypedSpec().Name, false) // link is created by name\n\t\t\tif existing == nil {\n\t\t\t\treturn fmt.Errorf(\"created link %q not found in the link list\", link.TypedSpec().Name)\n\t\t\t}\n\t\t}\n\n\t\t// sync bond settings\n\t\tif link.TypedSpec().Kind == network.LinkKindBond {\n\t\t\tvar existingBond network.BondMasterSpec\n\n\t\t\tif existingRawLinkData == nil {\n\t\t\t\treturn fmt.Errorf(\"existing link %q has no data, can't decode bond settings\", link.TypedSpec().Name)\n\t\t\t}\n\n\t\t\tif err := networkadapter.BondMasterSpec(&existingBond).Decode(existingRawLinkData); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error parsing bond attributes for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\t// primaryIndex might be reported from the kernel, but if it's nil in the spec, we should treat it as equal\n\t\t\tif existingBond.PrimaryIndex != nil && link.TypedSpec().BondMaster.PrimaryIndex == nil {\n\t\t\t\texistingBond.PrimaryIndex = nil\n\t\t\t}\n\n\t\t\tif !existingBond.Equal(&link.TypedSpec().BondMaster) {\n\t\t\t\tlogger.Debug(\"updating bond settings\",\n\t\t\t\t\tzap.String(\"old\", fmt.Sprintf(\"%+v\", existingBond)),\n\t\t\t\t\tzap.String(\"new\", fmt.Sprintf(\"%+v\", link.TypedSpec().BondMaster)),\n\t\t\t\t)\n\n\t\t\t\tdata, err := networkadapter.BondMasterSpec(&link.TypedSpec().BondMaster).Encode()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error encoding bond attributes for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\t// bring bond down\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tFamily: existing.Family,\n\t\t\t\t\tType:   existing.Type,\n\t\t\t\t\tIndex:  existing.Index,\n\t\t\t\t\tFlags:  0,\n\t\t\t\t\tChange: unix.IFF_UP,\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error changing flags for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\t// unslave all slaves\n\t\t\t\tfor i, slave := range *links {\n\t\t\t\t\tif slave.Attributes.Master != nil && *slave.Attributes.Master == existing.Index {\n\t\t\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\t\t\tFamily: slave.Family,\n\t\t\t\t\t\t\tType:   slave.Type,\n\t\t\t\t\t\t\tIndex:  slave.Index,\n\t\t\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\t\t\tMaster: new(uint32(0)),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error unslaving link %q under %q: %w\", slave.Attributes.Name, link.TypedSpec().BondSlave.MasterName, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t(*links)[i].Attributes.Master = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// update settings\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tFamily: existing.Family,\n\t\t\t\t\tType:   existing.Type,\n\t\t\t\t\tIndex:  existing.Index,\n\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\t\tKind: existing.Attributes.Info.Kind,\n\t\t\t\t\t\t\tData: &rtnetlink.LinkData{\n\t\t\t\t\t\t\t\tName: existing.Attributes.Info.Kind,\n\t\t\t\t\t\t\t\tData: data,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating bond settings for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"updated bond settings\")\n\t\t\t}\n\t\t}\n\n\t\t// sync bridge settings\n\t\tif link.TypedSpec().Kind == network.LinkKindBridge {\n\t\t\tvar existingBridge network.BridgeMasterSpec\n\n\t\t\tif existingRawLinkData == nil {\n\t\t\t\treturn fmt.Errorf(\"existing link %q has no data, can't decode bridge settings\", link.TypedSpec().Name)\n\t\t\t}\n\n\t\t\tif err := networkadapter.BridgeMasterSpec(&existingBridge).Decode(existingRawLinkData); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error parsing bridge attributes for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\tif existingBridge != link.TypedSpec().BridgeMaster {\n\t\t\t\tlogger.Debug(\"updating bridge settings\",\n\t\t\t\t\tzap.String(\"old\", fmt.Sprintf(\"%+v\", existingBridge)),\n\t\t\t\t\tzap.String(\"new\", fmt.Sprintf(\"%+v\", link.TypedSpec().BridgeMaster)),\n\t\t\t\t)\n\n\t\t\t\tdata, err := networkadapter.BridgeMasterSpec(&link.TypedSpec().BridgeMaster).Encode()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error encoding bridge attributes for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\t// bring bridge down\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tFamily: existing.Family,\n\t\t\t\t\tType:   existing.Type,\n\t\t\t\t\tIndex:  existing.Index,\n\t\t\t\t\tFlags:  0,\n\t\t\t\t\tChange: unix.IFF_UP,\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error changing flags for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\t// unslave all slaves\n\t\t\t\tfor i, slave := range *links {\n\t\t\t\t\tif slave.Attributes.Master != nil && *slave.Attributes.Master == existing.Index {\n\t\t\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\t\t\tFamily: slave.Family,\n\t\t\t\t\t\t\tType:   slave.Type,\n\t\t\t\t\t\t\tIndex:  slave.Index,\n\t\t\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\t\t\tMaster: new(uint32(0)),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error unslaving link %q under %q: %w\", slave.Attributes.Name, link.TypedSpec().BridgeSlave.MasterName, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t(*links)[i].Attributes.Master = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// update settings\n\t\t\t\tif err = conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\t\tFamily: existing.Family,\n\t\t\t\t\tType:   existing.Type,\n\t\t\t\t\tIndex:  existing.Index,\n\t\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\t\tKind: existing.Attributes.Info.Kind,\n\t\t\t\t\t\t\tData: &rtnetlink.LinkData{\n\t\t\t\t\t\t\t\tName: existing.Attributes.Info.Kind,\n\t\t\t\t\t\t\t\tData: data,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating bridge settings for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"updated bridge settings\")\n\t\t\t}\n\t\t}\n\n\t\t// sync wireguard settings\n\t\tif link.TypedSpec().Kind == network.LinkKindWireguard {\n\t\t\tif wgClient == nil {\n\t\t\t\treturn fmt.Errorf(\"wireguard client not available, cannot configure wireguard link %q\", link.TypedSpec().Name)\n\t\t\t}\n\n\t\t\twgDev, err := wgClient.Device(link.TypedSpec().Name)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting wireguard settings for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\tvar existingSpec network.WireguardSpec\n\n\t\t\tnetworkadapter.WireguardSpec(&existingSpec).Decode(wgDev, false)\n\t\t\texistingSpec.Sort()\n\n\t\t\tlink.TypedSpec().Wireguard.Sort()\n\n\t\t\t// order here is important: we allow listenPort to be zero in the configuration\n\t\t\tif !existingSpec.Equal(&link.TypedSpec().Wireguard) {\n\t\t\t\tconfig, err := networkadapter.WireguardSpec(&link.TypedSpec().Wireguard).Encode(&existingSpec)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error creating wireguard config patch for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tif err = wgClient.ConfigureDevice(link.TypedSpec().Name, *config); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error configuring wireguard device %q: %w\", link.TypedSpec().Name, err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"reconfigured wireguard link\", zap.Int(\"peers\", len(link.TypedSpec().Wireguard.Peers)))\n\n\t\t\t\t// notify link status controller, as wireguard updates can't be watched via netlink API\n\t\t\t\tif err = safe.WriterModify[*network.LinkRefresh](ctx, r, network.NewLinkRefresh(network.NamespaceName, network.LinkKindWireguard), func(r *network.LinkRefresh) error {\n\t\t\t\t\tr.TypedSpec().Bump()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn errors.New(\"error bumping link refresh\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sync UP flag\n\t\texistingUp := existing.Flags&unix.IFF_UP == unix.IFF_UP\n\t\tif existingUp != link.TypedSpec().Up {\n\t\t\tflags := uint32(0)\n\n\t\t\tif link.TypedSpec().Up {\n\t\t\t\tflags = unix.IFF_UP\n\t\t\t}\n\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tFlags:  flags,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error changing flags for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\tlogger.Debug(\"brought link up/down\", zap.Bool(\"up\", link.TypedSpec().Up))\n\t\t}\n\n\t\t// sync MTU if it's set in the spec\n\t\tif link.TypedSpec().MTU != 0 && existing.Attributes.MTU != link.TypedSpec().MTU {\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tMTU: link.TypedSpec().MTU,\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting MTU for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\texisting.Attributes.MTU = link.TypedSpec().MTU\n\n\t\t\tlogger.Info(\"changed MTU for the link\", zap.Uint32(\"mtu\", link.TypedSpec().MTU))\n\t\t}\n\n\t\t// sync hardware address if it's set in the spec\n\t\tif len(link.TypedSpec().HardwareAddress) != 0 && !bytes.Equal(net.HardwareAddr(link.TypedSpec().HardwareAddress), existing.Attributes.Address) {\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tAddress: net.HardwareAddr(link.TypedSpec().HardwareAddress),\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting hardware address for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\texisting.Attributes.Address = net.HardwareAddr(link.TypedSpec().HardwareAddress)\n\n\t\t\tlogger.Info(\"changed hardware address for the link\", zap.String(\"hwaddr\", net.HardwareAddr(link.TypedSpec().HardwareAddress).String()))\n\t\t}\n\n\t\t// sync multicast flag if it's set in the spec\n\t\tif link.TypedSpec().Multicast != nil && ((existing.Flags&unix.IFF_MULTICAST == unix.IFF_MULTICAST) != *link.TypedSpec().Multicast) {\n\t\t\tflags := uint32(0)\n\n\t\t\tif *link.TypedSpec().Multicast {\n\t\t\t\tflags = unix.IFF_MULTICAST\n\t\t\t}\n\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tFlags:  flags,\n\t\t\t\tChange: unix.IFF_MULTICAST,\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error changing multicast flag for %q: %w\", link.TypedSpec().Name, err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"changed multicast flag for the link\", zap.Bool(\"multicast\", *link.TypedSpec().Multicast))\n\t\t}\n\n\t\t// sync master index (for links which are bridge or bond slaves)\n\t\tvar masterIndex uint32\n\n\t\tvar masterName string\n\n\t\tbondMasterName := link.TypedSpec().BondSlave.MasterName\n\t\tif bondMasterName != \"\" {\n\t\t\tif master := findLink(*links, bondMasterName, false); master != nil { // bond master can't be an alias\n\t\t\t\tmasterName = bondMasterName\n\t\t\t\tmasterIndex = master.Index\n\t\t\t}\n\t\t}\n\n\t\tbridgeMasterName := link.TypedSpec().BridgeSlave.MasterName\n\t\tif bridgeMasterName != \"\" {\n\t\t\tif master := findLink(*links, bridgeMasterName, false); master != nil { // bridge master can't be an alias\n\t\t\t\tmasterName = bridgeMasterName\n\t\t\t\tmasterIndex = master.Index\n\t\t\t}\n\t\t}\n\n\t\tvrfMasterName := link.TypedSpec().VRFSlave.MasterName\n\t\tif vrfMasterName != \"\" {\n\t\t\tif master := findLink(*links, vrfMasterName, false); master != nil { // vrf master can't be an alias\n\t\t\t\tmasterName = vrfMasterName\n\t\t\t\tmasterIndex = master.Index\n\t\t\t}\n\t\t}\n\n\t\tif (existing.Attributes.Master == nil && masterIndex != 0) || (existing.Attributes.Master != nil && *existing.Attributes.Master != masterIndex) {\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error bring down link %q before enslaving under %q: %w\", link.TypedSpec().Name, masterName, err)\n\t\t\t}\n\n\t\t\tif err := conn.Link.Set(&rtnetlink.LinkMessage{\n\t\t\t\tFamily: existing.Family,\n\t\t\t\tType:   existing.Type,\n\t\t\t\tIndex:  existing.Index,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tMaster: new(masterIndex),\n\t\t\t\t},\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error enslaving/unslaving link %q under %q: %w\", link.TypedSpec().Name, masterName, err)\n\t\t\t}\n\n\t\t\texisting.Attributes.Master = new(masterIndex)\n\n\t\t\tlogger.Info(\"enslaved/unslaved link\", zap.String(\"parent\", masterName))\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.org/x/sys/unix\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype LinkSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *LinkSpecSuite) uniqueDummyInterface() string {\n\treturn fmt.Sprintf(\"dummy%02x%02x%02x\", rand.Int32()&0xff, rand.Int32()&0xff, rand.Int32()&0xff)\n}\n\nfunc (suite *LinkSpecSuite) TestLoopback() {\n\tloopback := network.NewLinkSpec(network.NamespaceName, \"lo\")\n\t*loopback.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        \"lo\",\n\t\tUp:          true,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{loopback} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResource(suite, \"lo\", func(r *network.LinkStatus, asrt *assert.Assertions) {})\n}\n\nfunc (suite *LinkSpecSuite) TestDummy() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tdummy := network.NewLinkSpec(network.NamespaceName, dummyInterface)\n\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        dummyInterface,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        \"dummy\",\n\t\tMTU:         1400,\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{dummy} {\n\t\tsuite.Create(res)\n\t}\n\n\tnewHardwareAddr := net.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tasrt.EqualValues(1400, r.TypedSpec().MTU)\n\t\tasrt.NotEqual(newHardwareAddr, net.HardwareAddr(r.TypedSpec().HardwareAddr))\n\t})\n\n\t// attempt to change the hardware address\n\tctest.UpdateWithConflicts(suite, dummy, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().HardwareAddress = nethelpers.HardwareAddr(newHardwareAddr)\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(newHardwareAddr, net.HardwareAddr(r.TypedSpec().HardwareAddr))\n\t})\n\n\t// check default multicast behavior (disabled on dummy interfaces)\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(r.TypedSpec().Flags&unix.IFF_MULTICAST == unix.IFF_MULTICAST, false)\n\t})\n\n\t// attempt to change multicast flag\n\tctest.UpdateWithConflicts(suite, dummy, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().Multicast = new(true)\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(r.TypedSpec().Flags&unix.IFF_MULTICAST == unix.IFF_MULTICAST, true)\n\t})\n\n\t// attempt to disable multicast\n\tctest.UpdateWithConflicts(suite, dummy, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().Multicast = new(bool)\n\t\tr.TypedSpec().Multicast = new(false)\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(r.TypedSpec().Flags&unix.IFF_MULTICAST == unix.IFF_MULTICAST, false)\n\t})\n\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), dummy.Metadata()))\n\n\tctest.AssertNoResource[*network.LinkSpec](suite, dummyInterface)\n}\n\nfunc (suite *LinkSpecSuite) TestDummyWithMAC() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tnewHardwareAddr := net.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\n\tdummy := network.NewLinkSpec(network.NamespaceName, dummyInterface)\n\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\tName:            dummyInterface,\n\t\tType:            nethelpers.LinkEther,\n\t\tKind:            \"dummy\",\n\t\tHardwareAddress: nethelpers.HardwareAddr(newHardwareAddr),\n\t\tUp:              true,\n\t\tLogical:         true,\n\t\tConfigLayer:     network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{dummy} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\tasrt.Equal(newHardwareAddr, net.HardwareAddr(r.TypedSpec().HardwareAddr))\n\t})\n\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), dummy.Metadata()))\n\n\tctest.AssertNoResource[*network.LinkSpec](suite, dummyInterface)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestVLAN() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tdummy := network.NewLinkSpec(network.NamespaceName, dummyInterface)\n\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        dummyInterface,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        \"dummy\",\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tvlanName1 := fmt.Sprintf(\"%s.%d\", dummyInterface, 2)\n\tvlan1 := network.NewLinkSpec(network.NamespaceName, vlanName1)\n\t*vlan1.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        vlanName1,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        network.LinkKindVLAN,\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tParentName:  dummyInterface,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      2,\n\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t},\n\t}\n\n\tvlanName2 := fmt.Sprintf(\"%s.%d\", dummyInterface, 4)\n\tvlan2 := network.NewLinkSpec(network.NamespaceName, vlanName2)\n\t*vlan2.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        vlanName2,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        network.LinkKindVLAN,\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tParentName:  dummyInterface,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      4,\n\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t},\n\t}\n\n\tfor _, res := range []resource.Resource{dummy, vlan1, vlan2} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []string{dummyInterface, vlanName1, vlanName2}, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase dummyInterface:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\tcase vlanName1, vlanName2:\n\t\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)\n\n\t\t\tif r.Metadata().ID() == vlanName1 {\n\t\t\t\tasrt.EqualValues(2, r.TypedSpec().VLAN.VID)\n\t\t\t} else {\n\t\t\t\tasrt.EqualValues(4, r.TypedSpec().VLAN.VID)\n\t\t\t}\n\t\t}\n\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t})\n\n\t// attempt to change VLAN ID\n\tctest.UpdateWithConflicts(suite, vlan1, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().VLAN.VID = 42\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, vlanName1, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)\n\t\tasrt.EqualValues(42, r.TypedSpec().VLAN.VID)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{vlan1, vlan2, dummy} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummyInterface)\n\tctest.AssertNoResource[*network.LinkStatus](suite, vlanName1)\n\tctest.AssertNoResource[*network.LinkStatus](suite, vlanName2)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestVLANViaAlias() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tdummy := network.NewLinkSpec(network.NamespaceName, dummyInterface)\n\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        dummyInterface,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        \"dummy\",\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tsuite.Create(dummy)\n\n\t// create dummy interface, and create an alias for it manually\n\tctest.AssertResource(suite, dummyInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t})\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tdummyAlias := suite.uniqueDummyInterface()\n\n\tsuite.Require().NoError(\n\t\tconn.Link.Set(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tIndex: uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tAlias: &dummyAlias,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tvlanName1 := fmt.Sprintf(\"%s.%d\", dummyAlias, 2)\n\tvlan1 := network.NewLinkSpec(network.NamespaceName, vlanName1)\n\t*vlan1.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        vlanName1,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        network.LinkKindVLAN,\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tParentName:  dummyAlias,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      2,\n\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t},\n\t}\n\n\tvlanName2 := fmt.Sprintf(\"%s.%d\", dummyAlias, 4)\n\tvlan2 := network.NewLinkSpec(network.NamespaceName, vlanName2)\n\t*vlan2.TypedSpec() = network.LinkSpecSpec{\n\t\tName:        vlanName2,\n\t\tType:        nethelpers.LinkEther,\n\t\tKind:        network.LinkKindVLAN,\n\t\tUp:          true,\n\t\tLogical:     true,\n\t\tParentName:  dummyAlias,\n\t\tConfigLayer: network.ConfigDefault,\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      4,\n\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t},\n\t}\n\n\tfor _, res := range []resource.Resource{vlan1, vlan2} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []string{dummyInterface, vlanName1, vlanName2}, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase dummyInterface:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\tasrt.Equal(dummyAlias, r.TypedSpec().Alias)\n\t\tcase vlanName1, vlanName2:\n\t\t\tasrt.Equal(network.LinkKindVLAN, r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)\n\n\t\t\tif r.Metadata().ID() == vlanName1 {\n\t\t\t\tasrt.EqualValues(2, r.TypedSpec().VLAN.VID)\n\t\t\t} else {\n\t\t\t\tasrt.EqualValues(4, r.TypedSpec().VLAN.VID)\n\t\t\t}\n\t\t}\n\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{vlan1, vlan2, dummy} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummyInterface)\n\tctest.AssertNoResource[*network.LinkStatus](suite, vlanName1)\n\tctest.AssertNoResource[*network.LinkStatus](suite, vlanName2)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestBond() {\n\tbondName := suite.uniqueDummyInterface()\n\tbond := network.NewLinkSpec(network.NamespaceName, bondName)\n\t*bond.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    bondName,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    network.LinkKindBond,\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode:            nethelpers.BondModeActiveBackup,\n\t\t\tARPAllTargets:   nethelpers.ARPAllTargetsAll,\n\t\t\tPrimaryReselect: nethelpers.PrimaryReselectBetter,\n\t\t\tFailOverMac:     nethelpers.FailOverMACFollow,\n\t\t\tADSelect:        nethelpers.ADSelectBandwidth,\n\t\t\tMIIMon:          100,\n\t\t\tDownDelay:       100,\n\t\t\tResendIGMP:      2,\n\t\t\tUseCarrier:      true,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\tnetworkadapter.BondMasterSpec(&bond.TypedSpec().BondMaster).FillDefaults()\n\n\tdummy0Name := suite.uniqueDummyInterface()\n\tdummy0 := network.NewLinkSpec(network.NamespaceName, dummy0Name)\n\t*dummy0.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy0Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBondSlave: network.BondSlave{\n\t\t\tMasterName: bondName,\n\t\t\tSlaveIndex: 0,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdummy1Name := suite.uniqueDummyInterface()\n\tdummy1 := network.NewLinkSpec(network.NamespaceName, dummy1Name)\n\t*dummy1.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy1Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBondSlave: network.BondSlave{\n\t\t\tMasterName: bondName,\n\t\t\tSlaveIndex: 1,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{dummy0, dummy1, bond} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []string{dummy0Name, dummy1Name, bondName}, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase bondName:\n\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tcase dummy0Name, dummy1Name:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.OperStateUnknown, r.TypedSpec().OperationalState)\n\t\t\tasrt.NotZero(r.TypedSpec().MasterIndex)\n\t\t}\n\t})\n\n\t// attempt to change bond type\n\tctest.UpdateWithConflicts(suite, bond, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().BondMaster.Mode = nethelpers.BondModeRoundrobin\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, bondName, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(nethelpers.BondModeRoundrobin, r.TypedSpec().BondMaster.Mode)\n\t})\n\n\t// unslave one of the interfaces\n\tctest.UpdateWithConflicts(suite, dummy0, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().BondSlave.MasterName = \"\"\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummy0Name, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Zero(r.TypedSpec().MasterIndex)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{dummy0, dummy1, bond} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy0Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy1Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, bondName)\n}\n\nfunc (suite *LinkSpecSuite) TestBondActiveBackup() {\n\tbondName := suite.uniqueDummyInterface()\n\tbond := network.NewLinkSpec(network.NamespaceName, bondName)\n\t*bond.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    bondName,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    network.LinkKindBond,\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode:            nethelpers.BondModeActiveBackup,\n\t\t\tHashPolicy:      nethelpers.BondXmitPolicyLayer2,\n\t\t\tLACPRate:        nethelpers.LACPRateSlow,\n\t\t\tARPValidate:     nethelpers.ARPValidateNone,\n\t\t\tARPAllTargets:   nethelpers.ARPAllTargetsAny,\n\t\t\tPrimaryReselect: nethelpers.PrimaryReselectAlways,\n\t\t\tFailOverMac:     nethelpers.FailOverMACNone,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tnetworkadapter.BondMasterSpec(&bond.TypedSpec().BondMaster).FillDefaults()\n\n\tfor idx := range 2 {\n\t\tdummyName := suite.uniqueDummyInterface()\n\t\tdummy := network.NewLinkSpec(network.NamespaceName, dummyName)\n\t\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\t\tName:    dummyName,\n\t\t\tType:    nethelpers.LinkEther,\n\t\t\tKind:    \"dummy\",\n\t\t\tUp:      true,\n\t\t\tLogical: true,\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: bondName,\n\t\t\t\tSlaveIndex: idx,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigDefault,\n\t\t}\n\t\tsuite.Create(dummy)\n\t}\n\n\tsuite.Create(bond)\n\n\tctest.AssertResource(suite, bondName, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t})\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestBond8023ad() {\n\tbondName := suite.uniqueDummyInterface()\n\tbond := network.NewLinkSpec(network.NamespaceName, bondName)\n\t*bond.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    bondName,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    network.LinkKindBond,\n\t\tMTU:     9000,\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode:       nethelpers.BondMode8023AD,\n\t\t\tLACPRate:   nethelpers.LACPRateFast,\n\t\t\tUseCarrier: true,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\tnetworkadapter.BondMasterSpec(&bond.TypedSpec().BondMaster).FillDefaults()\n\n\t//nolint:prealloc\n\tvar (\n\t\tdummies    []resource.Resource\n\t\tdummyNames []string\n\t)\n\n\tfor range 4 {\n\t\tdummyName := suite.uniqueDummyInterface()\n\t\tdummy := network.NewLinkSpec(network.NamespaceName, dummyName)\n\t\t*dummy.TypedSpec() = network.LinkSpecSpec{\n\t\t\tName:    dummyName,\n\t\t\tType:    nethelpers.LinkEther,\n\t\t\tKind:    \"dummy\",\n\t\t\tUp:      true,\n\t\t\tLogical: true,\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: bondName,\n\t\t\t\tSlaveIndex: 0,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigDefault,\n\t\t}\n\n\t\tdummies = append(dummies, dummy)\n\t\tdummyNames = append(dummyNames, dummyName)\n\t}\n\n\tfor _, res := range append(dummies, bond) {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, slices.Concat(dummyNames, []string{bondName}), func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase bondName:\n\t\t\tasrt.Equal(network.LinkKindBond, r.TypedSpec().Kind)\n\t\t\tasrt.EqualValues(9000, r.TypedSpec().MTU)\n\t\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tdefault:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.OperStateUnknown, r.TypedSpec().OperationalState)\n\t\t\tasrt.NotZero(r.TypedSpec().MasterIndex)\n\t\t}\n\t})\n\n\t// teardown the links\n\tfor _, r := range append(dummies, bond) {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, bondName)\n\n\tfor _, n := range dummyNames {\n\t\tctest.AssertNoResource[*network.LinkStatus](suite, n)\n\t}\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestBridge() {\n\tbridgeName := suite.uniqueDummyInterface()\n\tbridge := network.NewLinkSpec(network.NamespaceName, bridgeName)\n\t*bridge.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    bridgeName,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    network.LinkKindBridge,\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBridgeMaster: network.BridgeMasterSpec{\n\t\t\tSTP: network.STPSpec{\n\t\t\t\tEnabled: false,\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdummy0Name := suite.uniqueDummyInterface()\n\tdummy0 := network.NewLinkSpec(network.NamespaceName, dummy0Name)\n\t*dummy0.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy0Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBridgeSlave: network.BridgeSlave{\n\t\t\tMasterName: bridgeName,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdummy1Name := suite.uniqueDummyInterface()\n\tdummy1 := network.NewLinkSpec(network.NamespaceName, dummy1Name)\n\t*dummy1.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy1Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tBridgeSlave: network.BridgeSlave{\n\t\t\tMasterName: bridgeName,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{dummy0, dummy1, bridge} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []string{dummy0Name, dummy1Name, bridgeName}, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase bridgeName:\n\t\t\tasrt.Equal(network.LinkKindBridge, r.TypedSpec().Kind)\n\t\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tcase dummy0Name, dummy1Name:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.OperStateUnknown, r.TypedSpec().OperationalState)\n\t\t\tasrt.NotZero(r.TypedSpec().MasterIndex)\n\t\t}\n\t})\n\n\t// attempt to enable STP & VLAN filtering\n\tctest.UpdateWithConflicts(suite, bridge, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().BridgeMaster.STP.Enabled = true\n\t\tr.TypedSpec().BridgeMaster.VLAN.FilteringEnabled = true\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, bridgeName, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(network.LinkKindBridge, r.TypedSpec().Kind)\n\t\tasrt.EqualValues(true, r.TypedSpec().BridgeMaster.STP.Enabled)\n\t\tasrt.EqualValues(true, r.TypedSpec().BridgeMaster.VLAN.FilteringEnabled)\n\t})\n\n\t// unslave one of the interfaces\n\tctest.UpdateWithConflicts(suite, dummy0, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().BridgeSlave.MasterName = \"\"\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummy0Name, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Zero(r.TypedSpec().MasterIndex)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{dummy0, dummy1, bridge} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy0Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy1Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, bridgeName)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestVRF() {\n\tvrfName := suite.uniqueDummyInterface()\n\tvrf := network.NewLinkSpec(network.NamespaceName, vrfName)\n\t*vrf.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    vrfName,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    network.LinkKindVRF,\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tVRFMaster: network.VRFMasterSpec{\n\t\t\tTable: 123,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdummy0Name := suite.uniqueDummyInterface()\n\tdummy0 := network.NewLinkSpec(network.NamespaceName, dummy0Name)\n\t*dummy0.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy0Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tVRFSlave: network.VRFSlave{\n\t\t\tMasterName: vrfName,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdummy1Name := suite.uniqueDummyInterface()\n\tdummy1 := network.NewLinkSpec(network.NamespaceName, dummy1Name)\n\t*dummy1.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    dummy1Name,\n\t\tType:    nethelpers.LinkEther,\n\t\tKind:    \"dummy\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tVRFSlave: network.VRFSlave{\n\t\t\tMasterName: vrfName,\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{dummy0, dummy1, vrf} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []string{dummy0Name, dummy1Name, vrfName}, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tswitch r.Metadata().ID() {\n\t\tcase vrfName:\n\t\t\tasrt.Equal(network.LinkKindVRF, r.TypedSpec().Kind)\n\t\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tcase dummy0Name, dummy1Name:\n\t\t\tasrt.Equal(\"dummy\", r.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.OperStateUnknown, r.TypedSpec().OperationalState)\n\t\t\tasrt.NotZero(r.TypedSpec().MasterIndex)\n\t\t}\n\t})\n\n\t// attempt to change the vrf table\n\tctest.UpdateWithConflicts(suite, vrf, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().VRFMaster.Table = nethelpers.RoutingTable(124)\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, vrfName, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(network.LinkKindVRF, r.TypedSpec().Kind)\n\t\tasrt.Equal(nethelpers.RoutingTable(124), r.TypedSpec().VRFMaster.Table)\n\t})\n\n\t// unslave one of the interfaces\n\tctest.UpdateWithConflicts(suite, dummy0, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().VRFSlave.MasterName = \"\"\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, dummy0Name, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Zero(r.TypedSpec().MasterIndex)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{dummy0, dummy1, vrf} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy0Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, dummy1Name)\n\tctest.AssertNoResource[*network.LinkStatus](suite, vrfName)\n}\n\n//nolint:gocyclo\nfunc (suite *LinkSpecSuite) TestWireguard() {\n\tif fipsmode.Strict() {\n\t\tsuite.T().Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tpriv, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\tpub1, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\tpub2, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\twgInterface := suite.uniqueDummyInterface()\n\n\twg := network.NewLinkSpec(network.NamespaceName, wgInterface)\n\t*wg.TypedSpec() = network.LinkSpecSpec{\n\t\tName:    wgInterface,\n\t\tType:    nethelpers.LinkNone,\n\t\tKind:    \"wireguard\",\n\t\tUp:      true,\n\t\tLogical: true,\n\t\tWireguard: network.WireguardSpec{\n\t\t\tPrivateKey:   priv.String(),\n\t\t\tFirewallMark: 1,\n\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey: pub1.PublicKey().String(),\n\t\t\t\t\tEndpoint:  \"10.2.0.3:20000\",\n\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"172.24.0.0/16\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tPublicKey: pub2.PublicKey().String(),\n\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"172.25.0.0/24\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{wg} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResource(suite, wgInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"wireguard\", r.TypedSpec().Kind)\n\t\tasrt.Contains([]nethelpers.OperationalState{nethelpers.OperStateUp, nethelpers.OperStateUnknown}, r.TypedSpec().OperationalState)\n\t\tasrt.Equal(priv.PublicKey().String(), r.TypedSpec().Wireguard.PublicKey)\n\t\tasrt.Len(r.TypedSpec().Wireguard.Peers, 2)\n\t})\n\n\t// attempt to change wireguard private key\n\tpriv2, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\tctest.UpdateWithConflicts(suite, wg, func(r *network.LinkSpec) error {\n\t\tr.TypedSpec().Wireguard.PrivateKey = priv2.String()\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResource(suite, wgInterface, func(r *network.LinkStatus, asrt *assert.Assertions) {\n\t\tasrt.Equal(priv2.PublicKey().String(), r.TypedSpec().Wireguard.PublicKey)\n\t})\n\n\t// teardown the links\n\tfor _, r := range []resource.Resource{wg} {\n\t\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), r.Metadata()))\n\t}\n\n\tctest.AssertNoResource[*network.LinkStatus](suite, wgInterface)\n}\n\nfunc TestLinkSpecSuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, &LinkSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 15 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\t// create fake device ready status\n\t\t\t\tdeviceStatus := runtimeres.NewDevicesStatus(runtimeres.NamespaceName, runtimeres.DevicesID)\n\t\t\t\tdeviceStatus.TypedSpec().Ready = true\n\t\t\t\tsuite.Create(deviceStatus)\n\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkSpecController{}))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkStatusController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc TestSortBonds(t *testing.T) {\n\texpected := toResources([]network.LinkSpecSpec{\n\t\t{\n\t\t\tName: \"A\",\n\t\t}, {\n\t\t\tName: \"G\",\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: \"A\",\n\t\t\t\tSlaveIndex: 0,\n\t\t\t},\n\t\t}, {\n\t\t\tName: \"C\",\n\t\t}, {\n\t\t\tName: \"E\",\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: \"C\",\n\t\t\t\tSlaveIndex: 0,\n\t\t\t},\n\t\t}, {\n\t\t\tName: \"F\",\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: \"C\",\n\t\t\t\tSlaveIndex: 1,\n\t\t\t},\n\t\t}, {\n\t\t\tName: \"B\",\n\t\t\tBondSlave: network.BondSlave{\n\t\t\t\tMasterName: \"C\",\n\t\t\t\tSlaveIndex: 2,\n\t\t\t},\n\t\t},\n\t})\n\n\tseed := time.Now().Unix()\n\n\trnd := rand.New(rand.NewPCG(uint64(time.Now().Unix()), uint64(time.Now().Unix())))\n\n\tfor i := range 100 {\n\t\tres := safe.NewList[*network.LinkSpec](resource.List{\n\t\t\tItems: safe.ToSlice(expected, func(r *network.LinkSpec) resource.Resource { return r }),\n\t\t})\n\n\t\trnd.Shuffle(res.Len(), res.Swap)\n\t\tnetctrl.SortBonds(&res)\n\t\trequire.Equal(t, expected, res, \"failed with seed %d iteration %d\", seed, i)\n\t}\n}\n\nfunc toResources(slice []network.LinkSpecSpec) safe.List[*network.LinkSpec] {\n\treturn safe.NewList[*network.LinkSpec](resource.List{\n\t\tItems: xslices.Map(slice, func(spec network.LinkSpecSpec) resource.Resource {\n\t\t\tlink := network.NewLinkSpec(network.NamespaceName, \"bar\")\n\t\t\t*link.TypedSpec() = spec\n\n\t\t\treturn link\n\t\t}),\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/mdlayher/ethtool\"\n\tethtoolioctl \"github.com/safchain/ethtool\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\t\"golang.zx2c4.com/wireguard/wgctrl\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/pci\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// LinkStatusController manages secrets.Etcd based on configuration.\ntype LinkStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LinkStatusController) Name() string {\n\treturn \"network.LinkStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LinkStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LinkStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.LinkStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *LinkStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for udevd to be healthy, which implies that all link renames are done\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.LinkSpecType,\n\t\t\t\tKind:      controller.InputStrong,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\t// create watch connections to rtnetlink and ethtool via genetlink\n\t// these connections are used only to join multicast groups and receive notifications on changes\n\t// other connections are used to send requests and receive responses, as we can't mix the notifications and request/responses\n\trtnetlinkWatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer rtnetlinkWatcher.Done()\n\n\tethtoolWatcher, err := watch.NewEthtool(watch.NewDefaultRateLimitedTrigger(ctx, r))\n\tif err != nil {\n\t\tlogger.Warn(\"ethtool watcher failed to start\", zap.Error(err))\n\t} else {\n\t\tdefer ethtoolWatcher.Done()\n\t}\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tethClient, err := ethtool.New()\n\tif err != nil {\n\t\tlogger.Warn(\"error dialing ethtool socket\", zap.Error(err))\n\t} else {\n\t\tdefer ethClient.Close() //nolint:errcheck\n\t}\n\n\tethIoctlClient, err := ethtoolioctl.NewEthtool()\n\tif err != nil {\n\t\tlogger.Warn(\"error dialing ethtool ioctl socket\", zap.Error(err))\n\t} else {\n\t\tdefer ethIoctlClient.Close()\n\t}\n\n\twgClient, err := wgctrl.New()\n\tif err != nil {\n\t\tlogger.Warn(\"error creating wireguard client\", zap.Error(err))\n\t} else {\n\t\tdefer wgClient.Close() //nolint:errcheck\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif err = ctrl.reconcile(ctx, r, logger, conn, ethClient, ethIoctlClient, wgClient); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// reconcile function runs for every reconciliation loop querying the netlink state and updating resources.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *LinkStatusController) reconcile(\n\tctx context.Context,\n\tr controller.Runtime,\n\tlogger *zap.Logger,\n\tconn *rtnetlink.Conn,\n\tethClient *ethtool.Client,\n\tethtoolIoctlClient *ethtoolioctl.Ethtool,\n\twgClient *wgctrl.Client,\n) error {\n\t// list the existing LinkStatus resources and mark them all to be deleted, as the actual link is discovered via netlink, resource ID is removed from the list\n\tlist, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t}\n\n\titemsToDelete := map[resource.ID]struct{}{}\n\n\tfor _, r := range list.Items {\n\t\titemsToDelete[r.Metadata().ID()] = struct{}{}\n\t}\n\n\tlinks, err := conn.Link.List()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t}\n\n\t// for every rtnetlink discovered link\n\tfor _, link := range links {\n\t\tvar (\n\t\t\tethState      *ethtool.LinkState\n\t\t\tethInfo       *ethtool.LinkInfo\n\t\t\tethMode       *ethtool.LinkMode\n\t\t\tdriverInfo    ethtoolioctl.DrvInfo\n\t\t\tpermanentAddr net.HardwareAddr\n\t\t)\n\n\t\tif ethClient != nil {\n\t\t\t// query additional information via ethtool (if supported)\n\t\t\tethState, err = ethClient.LinkState(ethtool.Interface{\n\t\t\t\tIndex: int(link.Index),\n\t\t\t})\n\t\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t\tlogger.Warn(\"error querying ethtool link state\", zap.String(\"link\", link.Attributes.Name), zap.Error(err))\n\t\t\t}\n\n\t\t\t// skip if previous call failed (e.g. not supported)\n\t\t\tif err == nil {\n\t\t\t\tethInfo, err = ethClient.LinkInfo(ethtool.Interface{\n\t\t\t\t\tIndex: int(link.Index),\n\t\t\t\t})\n\t\t\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\tlogger.Warn(\"error querying ethtool link info\", zap.String(\"link\", link.Attributes.Name), zap.Error(err))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// skip if previous call failed (e.g. not supported)\n\t\t\tif err == nil {\n\t\t\t\tethMode, err = ethClient.LinkMode(ethtool.Interface{\n\t\t\t\t\tIndex: int(link.Index),\n\t\t\t\t})\n\t\t\t\tif err != nil && !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\tlogger.Warn(\"error querying ethtool link mode\", zap.String(\"link\", link.Attributes.Name), zap.Error(err))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ethtoolIoctlClient != nil {\n\t\t\tdriverInfo, _ = ethtoolIoctlClient.DriverInfo(link.Attributes.Name) //nolint:errcheck\n\n\t\t\tvar permAddr string\n\n\t\t\tpermAddr, err = ethtoolIoctlClient.PermAddr(link.Attributes.Name)\n\t\t\tif err == nil && permAddr != \"\" {\n\t\t\t\tpermanentAddr, _ = net.ParseMAC(permAddr) //nolint:errcheck\n\t\t\t}\n\n\t\t\tif ethState == nil {\n\t\t\t\tstate, err := ethtoolIoctlClient.LinkState(link.Attributes.Name)\n\t\t\t\tif err == nil {\n\t\t\t\t\tethState = &ethtool.LinkState{\n\t\t\t\t\t\tInterface: ethtool.Interface{\n\t\t\t\t\t\t\tIndex: int(link.Index),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tLink: state > 0,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, network.NewLinkStatus(network.NamespaceName, link.Attributes.Name), func(r *network.LinkStatus) error {\n\t\t\tstatus := r.TypedSpec()\n\n\t\t\tstatus.Alias = pointer.SafeDeref(link.Attributes.Alias)\n\t\t\tstatus.AltNames = slices.Clone(link.Attributes.AltNames)\n\t\t\tstatus.Index = link.Index\n\t\t\tstatus.HardwareAddr = nethelpers.HardwareAddr(link.Attributes.Address)\n\t\t\tstatus.PermanentAddr = nethelpers.HardwareAddr(permanentAddr)\n\t\t\tstatus.BroadcastAddr = nethelpers.HardwareAddr(link.Attributes.Broadcast)\n\t\t\tstatus.LinkIndex = link.Attributes.Type\n\t\t\tstatus.Flags = nethelpers.LinkFlags(link.Flags)\n\t\t\tstatus.Type = nethelpers.LinkType(link.Type)\n\t\t\tstatus.QueueDisc = link.Attributes.QueueDisc\n\n\t\t\tstatus.MTU = link.Attributes.MTU\n\t\t\tif link.Attributes.Master != nil {\n\t\t\t\tstatus.MasterIndex = *link.Attributes.Master\n\t\t\t} else {\n\t\t\t\tstatus.MasterIndex = 0\n\t\t\t}\n\n\t\t\tstatus.OperationalState = nethelpers.OperationalState(link.Attributes.OperationalState)\n\t\t\tif link.Attributes.Info != nil {\n\t\t\t\tstatus.Kind = link.Attributes.Info.Kind\n\t\t\t\tstatus.SlaveKind = link.Attributes.Info.SlaveKind\n\t\t\t} else {\n\t\t\t\tstatus.Kind = \"\"\n\t\t\t\tstatus.SlaveKind = \"\"\n\t\t\t}\n\n\t\t\tif ethState != nil {\n\t\t\t\tstatus.LinkState = ethState.Link\n\t\t\t} else {\n\t\t\t\tstatus.LinkState = false\n\t\t\t}\n\n\t\t\tif ethInfo != nil {\n\t\t\t\tstatus.Port = nethelpers.Port(ethInfo.Port)\n\t\t\t} else {\n\t\t\t\tstatus.Port = nethelpers.Port(ethtool.Other)\n\t\t\t}\n\n\t\t\tif ethMode != nil {\n\t\t\t\tstatus.SpeedMegabits = ethMode.SpeedMegabits\n\t\t\t\tstatus.Duplex = nethelpers.Duplex(ethMode.Duplex)\n\t\t\t} else {\n\t\t\t\tstatus.SpeedMegabits = 0\n\t\t\t\tstatus.Duplex = nethelpers.Duplex(ethtool.Unknown)\n\t\t\t}\n\n\t\t\tvar deviceInfo *nethelpers.DeviceInfo\n\n\t\t\tdeviceInfo, err = nethelpers.GetDeviceInfo(link.Attributes.Name)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Warn(\"failure getting device information from /sys/class/net/*\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t}\n\n\t\t\tif deviceInfo != nil {\n\t\t\t\tstatus.BusPath = deviceInfo.BusPath\n\t\t\t\tstatus.Driver = deviceInfo.Driver\n\t\t\t\tstatus.PCIID = deviceInfo.PCIID\n\t\t\t}\n\n\t\t\tif status.Driver == \"\" {\n\t\t\t\tstatus.Driver = driverInfo.Driver\n\t\t\t}\n\n\t\t\tif status.BusPath == \"\" {\n\t\t\t\tstatus.BusPath = driverInfo.BusInfo\n\t\t\t}\n\n\t\t\tvar pciDev *pci.Device\n\n\t\t\tpciDev, err = pci.SysfsDeviceInfo(driverInfo.BusInfo)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Warn(\"failure looking up sysfs PCI info\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t}\n\n\t\t\tif pciDev != nil {\n\t\t\t\tpciDev.LookupDB()\n\n\t\t\t\tstatus.VendorID = fmt.Sprintf(\"0x%04x\", pciDev.VendorID)\n\t\t\t\tstatus.ProductID = fmt.Sprintf(\"0x%04x\", pciDev.ProductID)\n\n\t\t\t\tstatus.Vendor = pciDev.Vendor\n\t\t\t\tstatus.Product = pciDev.Product\n\t\t\t}\n\n\t\t\tstatus.DriverVersion = driverInfo.Version\n\t\t\tstatus.FirmwareVersion = driverInfo.FwVersion\n\n\t\t\t// link.Attributes.Info will be non-nil, because we set status.Kind above using link.Attributes.Info.Kind\n\t\t\tvar rawLinkData []byte\n\n\t\t\tif link.Attributes.Info != nil && link.Attributes.Info.Data != nil {\n\t\t\t\tif linkData, ok := link.Attributes.Info.Data.(*rtnetlink.LinkData); ok {\n\t\t\t\t\trawLinkData = linkData.Data\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tswitch status.Kind {\n\t\t\tcase network.LinkKindVLAN:\n\t\t\t\tif rawLinkData == nil {\n\t\t\t\t\tlogger.Warn(\"VLAN link data is nil\", zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t} else if err = networkadapter.VLANSpec(&status.VLAN).Decode(rawLinkData); err != nil {\n\t\t\t\t\tlogger.Warn(\"failure decoding VLAN attributes\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t}\n\t\t\tcase network.LinkKindBond:\n\t\t\t\tif rawLinkData == nil {\n\t\t\t\t\tlogger.Warn(\"bond link data is nil\", zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t} else if err = networkadapter.BondMasterSpec(&status.BondMaster).Decode(rawLinkData); err != nil {\n\t\t\t\t\tlogger.Warn(\"failure decoding bond attributes\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t}\n\t\t\tcase network.LinkKindBridge:\n\t\t\t\tif rawLinkData == nil {\n\t\t\t\t\tlogger.Warn(\"bridge link data is nil\", zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t} else if err = networkadapter.BridgeMasterSpec(&status.BridgeMaster).Decode(rawLinkData); err != nil {\n\t\t\t\t\tlogger.Warn(\"failure decoding bridge attributes\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t}\n\t\t\tcase network.LinkKindVRF:\n\t\t\t\tif rawLinkData == nil {\n\t\t\t\t\tlogger.Warn(\"vrf link data is nil\", zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t} else if err = networkadapter.VRFMasterSpec(&status.VRFMaster).Decode(rawLinkData); err != nil {\n\t\t\t\t\tlogger.Warn(\"failure decoding vrf attributes\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t}\n\t\t\tcase network.LinkKindWireguard:\n\t\t\t\tif wgClient == nil {\n\t\t\t\t\treturn fmt.Errorf(\"wireguard client not available, but wireguard interface was discovered: %q\", link.Attributes.Name)\n\t\t\t\t}\n\n\t\t\t\tvar wgDev *wgtypes.Device\n\n\t\t\t\twgDev, err = wgClient.Device(link.Attributes.Name)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Warn(\"failure getting wireguard attributes\", zap.Error(err), zap.String(\"link\", link.Attributes.Name))\n\t\t\t\t} else {\n\t\t\t\t\tnetworkadapter.WireguardSpec(&status.Wireguard).Decode(wgDev, true)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tdelete(itemsToDelete, link.Attributes.Name)\n\t}\n\n\tfor id := range itemsToDelete {\n\t\tif err = r.Destroy(ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, id, resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting link status %q: %w\", id, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/link_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/mdlayher/netlink\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\t\"golang.org/x/sys/unix\"\n\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype LinkStatusSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *LinkStatusSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\t// create fake device ready status\n\tdeviceStatus := runtimeres.NewDevicesStatus(runtimeres.NamespaceName, runtimeres.DevicesID)\n\tdeviceStatus.TypedSpec().Ready = true\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, deviceStatus))\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkStatusController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *LinkStatusSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *LinkStatusSuite) uniqueDummyInterface() string {\n\treturn fmt.Sprintf(\"dummy%02x%02x%02x\", rand.Int32()&0xff, rand.Int32()&0xff, rand.Int32()&0xff)\n}\n\nfunc (suite *LinkStatusSuite) assertInterfaces(requiredIDs []string, check func(*network.LinkStatus) error) error {\n\tmissingIDs := make(map[string]struct{}, len(requiredIDs))\n\n\tfor _, id := range requiredIDs {\n\t\tmissingIDs[id] = struct{}{}\n\t}\n\n\tresources, err := suite.state.List(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"\", resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range resources.Items {\n\t\t_, required := missingIDs[res.Metadata().ID()]\n\t\tif !required {\n\t\t\tcontinue\n\t\t}\n\n\t\tdelete(missingIDs, res.Metadata().ID())\n\n\t\tif err = check(res.(*network.LinkStatus)); err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\t}\n\n\tif len(missingIDs) > 0 {\n\t\treturn retry.ExpectedErrorf(\"some resources are missing: %q\", missingIDs)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *LinkStatusSuite) assertNoInterface(id string) error {\n\tresources, err := suite.state.List(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"\", resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range resources.Items {\n\t\tif res.Metadata().ID() == id {\n\t\t\treturn retry.ExpectedErrorf(\"interface %q is still there\", id)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (suite *LinkStatusSuite) TestInterfaceHwInfo() {\n\terrNoInterfaces := errors.New(\"no suitable interfaces found\")\n\n\terr := retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\tresources, err := suite.state.List(\n\t\t\t\tsuite.ctx,\n\t\t\t\tresource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"\", resource.VersionUndefined),\n\t\t\t)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tfor _, res := range resources.Items {\n\t\t\t\tspec := res.(*network.LinkStatus).TypedSpec() //nolint:forcetypeassert\n\n\t\t\t\tif !spec.Physical() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif spec.Type != nethelpers.LinkEther {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar emptyFields []string\n\n\t\t\t\tfor key, value := range map[string]string{\n\t\t\t\t\t\"hw addr\":   spec.HardwareAddr.String(),\n\t\t\t\t\t\"perm addr\": spec.PermanentAddr.String(),\n\t\t\t\t\t\"driver\":    spec.Driver,\n\t\t\t\t\t\"bus path\":  spec.BusPath,\n\t\t\t\t\t\"PCI id\":    spec.PCIID,\n\t\t\t\t} {\n\t\t\t\t\tif value == \"\" {\n\t\t\t\t\t\temptyFields = append(emptyFields, key)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif len(emptyFields) > 0 {\n\t\t\t\t\treturn fmt.Errorf(\"the interface %s has the following fields empty: %s\", res.Metadata().ID(), strings.Join(emptyFields, \", \"))\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn retry.ExpectedError(errNoInterfaces)\n\t\t},\n\t)\n\tif errors.Is(err, errNoInterfaces) {\n\t\tsuite.T().Skip(err.Error())\n\t}\n\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *LinkStatusSuite) TestLoopbackInterface() {\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertInterfaces(\n\t\t\t\t\t[]string{\"lo\"}, func(r *network.LinkStatus) error {\n\t\t\t\t\t\tsuite.Assert().Equal(\"loopback\", r.TypedSpec().Type.String())\n\t\t\t\t\t\tsuite.Assert().EqualValues(65536, r.TypedSpec().MTU)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *LinkStatusSuite) TestDummyInterface() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"requires root\")\n\t}\n\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType: unix.ARPHRD_ETHER,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1400,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertInterfaces(\n\t\t\t\t\t[]string{dummyInterface}, func(r *network.LinkStatus) error {\n\t\t\t\t\t\tsuite.Assert().Equal(\"ether\", r.TypedSpec().Type.String())\n\t\t\t\t\t\tsuite.Assert().EqualValues(1400, r.TypedSpec().MTU)\n\t\t\t\t\t\tsuite.Assert().Equal(nethelpers.OperStateDown, r.TypedSpec().OperationalState)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(\n\t\tconn.Link.Set(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType:   unix.ARPHRD_ETHER,\n\t\t\t\tIndex:  uint32(iface.Index),\n\t\t\t\tFlags:  unix.IFF_UP,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertInterfaces(\n\t\t\t\t\t[]string{dummyInterface}, func(r *network.LinkStatus) error {\n\t\t\t\t\t\tif r.TypedSpec().OperationalState != nethelpers.OperStateUp && r.TypedSpec().OperationalState != nethelpers.OperStateUnknown {\n\t\t\t\t\t\t\treturn retry.ExpectedErrorf(\n\t\t\t\t\t\t\t\t\"operational state is not up: %s\",\n\t\t\t\t\t\t\t\tr.TypedSpec().OperationalState,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(conn.Link.Delete(uint32(iface.Index)))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoInterface(dummyInterface)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *LinkStatusSuite) TestBridgeInterface() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"requires root\")\n\t}\n\n\tbridgeInterface := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tbridgeData, err := encodeBridgeData(true)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType: unix.ARPHRD_ETHER,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: bridgeInterface,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"bridge\",\n\t\t\t\t\t\tData: &rtnetlink.LinkData{\n\t\t\t\t\t\t\tName: \"bridge\",\n\t\t\t\t\t\t\tData: bridgeData,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tbridgeIface, err := net.InterfaceByName(bridgeInterface)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Link.Delete(uint32(bridgeIface.Index)) //nolint:errcheck\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertInterfaces(\n\t\t\t\t\t[]string{bridgeInterface}, func(r *network.LinkStatus) error {\n\t\t\t\t\t\tsuite.Assert().Equal(\"ether\", r.TypedSpec().Type.String())\n\t\t\t\t\t\tsuite.Assert().True(r.TypedSpec().BridgeMaster.STP.Enabled)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc encodeBridgeData(stpEnabled bool) ([]byte, error) {\n\tencoder := netlink.NewAttributeEncoder()\n\n\tvar stpState uint32\n\tif stpEnabled {\n\t\tstpState = 1\n\t}\n\n\tencoder.Uint32(unix.IFLA_BR_STP_STATE, stpState)\n\n\treturn encoder.Encode()\n}\n\nfunc (suite *LinkStatusSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestLinkStatusSuite(t *testing.T) {\n\tsuite.Run(t, new(LinkStatusSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"net\"\n\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// SetBondSlave sets the bond slave spec.\nfunc SetBondSlave(link *network.LinkSpecSpec, bond ordered.Pair[string, int]) {\n\tlink.BondSlave = network.BondSlave{\n\t\tMasterName: bond.F1,\n\t\tSlaveIndex: bond.F2,\n\t}\n}\n\n// SendBondMaster sets the bond master spec.\nfunc SendBondMaster(link *network.LinkSpecSpec, bond talosconfig.NetworkBondConfig) {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindBond\n\tlink.Type = nethelpers.LinkEther\n\tlink.BondMaster.Mode = bond.Mode()\n\tlink.BondMaster.MIIMon = bond.MIIMon().ValueOrZero()\n\tlink.BondMaster.UpDelay = bond.UpDelay().ValueOrZero()\n\tlink.BondMaster.DownDelay = bond.DownDelay().ValueOrZero()\n\tlink.BondMaster.HashPolicy = bond.XmitHashPolicy().ValueOrZero()\n\tlink.BondMaster.ARPInterval = bond.ARPInterval().ValueOrZero()\n\tlink.BondMaster.ARPIPTargets = bond.ARPIPTargets()\n\tlink.BondMaster.NSIP6Targets = bond.NSIP6Targets()\n\tlink.BondMaster.ARPValidate = bond.ARPValidate().ValueOrZero()\n\tlink.BondMaster.ARPAllTargets = bond.ARPAllTargets().ValueOrZero()\n\tlink.BondMaster.LACPRate = bond.LACPRate().ValueOrZero()\n\tlink.BondMaster.FailOverMac = bond.FailOverMAC().ValueOrZero()\n\tlink.BondMaster.ADSelect = bond.ADSelect().ValueOrZero()\n\tlink.BondMaster.ADActorSysPrio = bond.ADActorSysPrio().ValueOrZero()\n\tlink.BondMaster.ADUserPortKey = bond.ADUserPortKey().ValueOrZero()\n\tlink.BondMaster.ADLACPActive = bond.ADLACPActive().ValueOr(nethelpers.ADLACPActiveOn)\n\tlink.BondMaster.PrimaryReselect = bond.PrimaryReselect().ValueOrZero()\n\tlink.BondMaster.ResendIGMP = bond.ResendIGMP().ValueOrZero()\n\tlink.BondMaster.MinLinks = bond.MinLinks().ValueOrZero()\n\tlink.BondMaster.LPInterval = bond.LPInterval().ValueOrZero()\n\tlink.BondMaster.PacketsPerSlave = bond.PacketsPerSlave().ValueOrZero()\n\tlink.BondMaster.NumPeerNotif = bond.NumPeerNotif().ValueOrZero()\n\tlink.BondMaster.TLBDynamicLB = bond.TLBDynamicLB().ValueOrZero()\n\tlink.BondMaster.AllSlavesActive = bond.AllSlavesActive().ValueOrZero()\n\tlink.BondMaster.PeerNotifyDelay = bond.PeerNotifyDelay().ValueOrZero()\n\tlink.BondMaster.MissedMax = bond.MissedMax().ValueOrZero()\n\n\tnetworkadapter.BondMasterSpec(&link.BondMaster).FillDefaults()\n}\n\n// SetBondMasterLegacy sets the bond master spec.\n//\n//nolint:gocyclo\nfunc SetBondMasterLegacy(link *network.LinkSpecSpec, bond talosconfig.Bond) error {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindBond\n\tlink.Type = nethelpers.LinkEther\n\n\tbondMode, err := nethelpers.BondModeByName(bond.Mode())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thashPolicy, err := nethelpers.BondXmitHashPolicyByName(bond.HashPolicy())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlacpRate, err := nethelpers.LACPRateByName(bond.LACPRate())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tarpValidate, err := nethelpers.ARPValidateByName(bond.ARPValidate())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tarpAllTargets, err := nethelpers.ARPAllTargetsByName(bond.ARPAllTargets())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar primary uint32\n\n\tif bond.Primary() != \"\" {\n\t\tvar iface *net.Interface\n\n\t\tiface, err = net.InterfaceByName(bond.Primary())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tprimary = uint32(iface.Index)\n\t}\n\n\tprimaryReselect, err := nethelpers.PrimaryReselectByName(bond.PrimaryReselect())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfailOverMAC, err := nethelpers.FailOverMACByName(bond.FailOverMac())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tadSelect, err := nethelpers.ADSelectByName(bond.ADSelect())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlink.BondMaster = network.BondMasterSpec{\n\t\tMode:            bondMode,\n\t\tHashPolicy:      hashPolicy,\n\t\tLACPRate:        lacpRate,\n\t\tARPValidate:     arpValidate,\n\t\tARPAllTargets:   arpAllTargets,\n\t\tPrimaryIndex:    new(primary),\n\t\tPrimaryReselect: primaryReselect,\n\t\tFailOverMac:     failOverMAC,\n\t\tADSelect:        adSelect,\n\t\tMIIMon:          bond.MIIMon(),\n\t\tUpDelay:         bond.UpDelay(),\n\t\tDownDelay:       bond.DownDelay(),\n\t\tARPInterval:     bond.ARPInterval(),\n\t\tResendIGMP:      bond.ResendIGMP(),\n\t\tMinLinks:        bond.MinLinks(),\n\t\tLPInterval:      bond.LPInterval(),\n\t\tPacketsPerSlave: bond.PacketsPerSlave(),\n\t\tNumPeerNotif:    bond.NumPeerNotif(),\n\t\tTLBDynamicLB:    bond.TLBDynamicLB(),\n\t\tAllSlavesActive: bond.AllSlavesActive(),\n\t\tADActorSysPrio:  bond.ADActorSysPrio(),\n\t\tADUserPortKey:   bond.ADUserPortKey(),\n\t\tPeerNotifyDelay: bond.PeerNotifyDelay(),\n\t\tADLACPActive:    nethelpers.ADLACPActiveOn,\n\t}\n\tnetworkadapter.BondMasterSpec(&link.BondMaster).FillDefaults()\n\n\treturn nil\n}\n\n// SetBridgeSlave sets the bridge slave spec.\nfunc SetBridgeSlave(link *network.LinkSpecSpec, bridge string) {\n\tlink.BridgeSlave = network.BridgeSlave{\n\t\tMasterName: bridge,\n\t}\n}\n\n// SetBridgeMasterLegacy sets the bridge master spec.\nfunc SetBridgeMasterLegacy(link *network.LinkSpecSpec, bridge talosconfig.Bridge) error {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindBridge\n\tlink.Type = nethelpers.LinkEther\n\n\tif bridge != nil {\n\t\tlink.BridgeMaster = network.BridgeMasterSpec{\n\t\t\tSTP: network.STPSpec{\n\t\t\t\tEnabled: bridge.STP().Enabled(),\n\t\t\t},\n\t\t\tVLAN: network.BridgeVLANSpec{\n\t\t\t\tFilteringEnabled: bridge.VLAN().FilteringEnabled(),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// SetBridgeMaster sets the bridge master spec.\nfunc SetBridgeMaster(link *network.LinkSpecSpec, bridge talosconfig.NetworkBridgeConfig) {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindBridge\n\tlink.Type = nethelpers.LinkEther\n\n\tlink.BridgeMaster = network.BridgeMasterSpec{\n\t\tSTP: network.STPSpec{\n\t\t\tEnabled: bridge.STP().Enabled().ValueOrZero(),\n\t\t},\n\t\tVLAN: network.BridgeVLANSpec{\n\t\t\tFilteringEnabled: bridge.VLAN().FilteringEnabled().ValueOrZero(),\n\t\t},\n\t}\n}\n\n// SetVRFSlave sets the vrf slave spec.\nfunc SetVRFSlave(link *network.LinkSpecSpec, vrf string) {\n\tlink.VRFSlave = network.VRFSlave{\n\t\tMasterName: vrf,\n\t}\n}\n\n// SetVRFMaster sets the vrf master spec.\nfunc SetVRFMaster(link *network.LinkSpecSpec, vrf talosconfig.NetworkVRFConfig) {\n\tlink.Logical = true\n\tlink.Kind = network.LinkKindVRF\n\tlink.Type = nethelpers.LinkEther\n\n\tlink.VRFMaster = network.VRFMasterSpec{\n\t\tTable: vrf.Table(),\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/network_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"go.uber.org/goleak\"\n)\n\nfunc TestMain(m *testing.M) {\n\tgoleak.VerifyTestMain(m,\n\t\tgoleak.IgnoreTopFunction(\"github.com/thejerf/suture/v4.(*Supervisor).removeService.func1.1\"),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/nftables_chain.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/google/nftables\"\n\t\"github.com/google/nftables/expr\"\n\t\"go.uber.org/zap\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NfTablesChainController applies network.NfTablesChain to the Linux nftables interface.\ntype NfTablesChainController struct {\n\tTableName string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NfTablesChainController) Name() string {\n\treturn \"network.NfTablesChainController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NfTablesChainController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NfTablesChainType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NfTablesChainController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *NfTablesChainController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.TableName == \"\" {\n\t\tctrl.TableName = constants.DefaultNfTablesTableName\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar conn nftables.Conn\n\n\t\tif err := ctrl.preCreateIptablesNFTable(logger, &conn); err != nil {\n\t\t\treturn fmt.Errorf(\"error pre-creating iptables-nft table: %w\", err)\n\t\t}\n\n\t\tlist, err := safe.ReaderListAll[*network.NfTablesChain](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing nftables chains: %w\", err)\n\t\t}\n\n\t\texistingTables, err := conn.ListTablesOfFamily(nftables.TableFamilyINet)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing existing nftables tables: %w\", err)\n\t\t}\n\n\t\tvar talosTable *nftables.Table\n\n\t\tif idx := slices.IndexFunc(existingTables, func(t *nftables.Table) bool { return t.Name == ctrl.TableName }); idx != -1 {\n\t\t\ttalosTable = existingTables[idx]\n\t\t}\n\n\t\tif talosTable == nil {\n\t\t\ttalosTable = &nftables.Table{\n\t\t\t\tFamily: nftables.TableFamilyINet,\n\t\t\t\tName:   ctrl.TableName,\n\t\t\t}\n\n\t\t\tconn.AddTable(talosTable)\n\t\t}\n\n\t\t// drop all chains, they will be re-created\n\t\texistingChains, err := conn.ListChains()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing existing nftables chains: %w\", err)\n\t\t}\n\n\t\tfor _, chain := range existingChains {\n\t\t\tif chain.Table.Name != ctrl.TableName { // not our chain\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconn.DelChain(chain)\n\t\t}\n\n\t\tsetID := uint32(0)\n\n\t\tfor chain := range list.All() {\n\t\t\tnfChain := conn.AddChain(&nftables.Chain{\n\t\t\t\tName:     chain.Metadata().ID(),\n\t\t\t\tTable:    talosTable,\n\t\t\t\tHooknum:  new(nftables.ChainHook(chain.TypedSpec().Hook)),\n\t\t\t\tPriority: new(nftables.ChainPriority(chain.TypedSpec().Priority)),\n\t\t\t\tType:     nftables.ChainType(chain.TypedSpec().Type),\n\t\t\t\tPolicy:   new(nftables.ChainPolicy(chain.TypedSpec().Policy)),\n\t\t\t})\n\n\t\t\tfor _, rule := range chain.TypedSpec().Rules {\n\t\t\t\tcompiled, err := networkadapter.NfTablesRule(&rule).Compile()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error compiling nftables rule for chain %s: %w\", nfChain.Name, err)\n\t\t\t\t}\n\n\t\t\t\tfor _, compiledRule := range compiled.Rules {\n\t\t\t\t\t// check for lookup rules and add/fix up the set ID if needed\n\t\t\t\t\tfor i := range compiledRule {\n\t\t\t\t\t\tif lookup, ok := compiledRule[i].(*expr.Lookup); ok {\n\t\t\t\t\t\t\tif lookup.SetID >= uint32(len(compiled.Sets)) {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"invalid set ID %d in lookup\", lookup.SetID)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tset := compiled.Sets[lookup.SetID]\n\t\t\t\t\t\t\tsetName := \"__set\" + strconv.Itoa(int(setID))\n\n\t\t\t\t\t\t\tif err = conn.AddSet(&nftables.Set{\n\t\t\t\t\t\t\t\tTable:     talosTable,\n\t\t\t\t\t\t\t\tID:        setID,\n\t\t\t\t\t\t\t\tName:      setName,\n\t\t\t\t\t\t\t\tAnonymous: true,\n\t\t\t\t\t\t\t\tConstant:  true,\n\t\t\t\t\t\t\t\tInterval:  set.IsInterval(),\n\t\t\t\t\t\t\t\tKeyType:   set.KeyType(),\n\t\t\t\t\t\t\t}, set.SetElements()); err != nil {\n\t\t\t\t\t\t\t\treturn fmt.Errorf(\"error adding nftables set for chain %s: %w\", nfChain.Name, err)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlookupOp := *lookup\n\t\t\t\t\t\t\tlookupOp.SetID = setID\n\t\t\t\t\t\t\tlookupOp.SetName = setName\n\n\t\t\t\t\t\t\tcompiledRule[i] = &lookupOp\n\n\t\t\t\t\t\t\tsetID++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconn.AddRule(&nftables.Rule{\n\t\t\t\t\t\tTable: talosTable,\n\t\t\t\t\t\tChain: nfChain,\n\t\t\t\t\t\tExprs: compiledRule,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err := conn.Flush(); err != nil {\n\t\t\treturn fmt.Errorf(\"error flushing nftables: %w\", err)\n\t\t}\n\n\t\tchainNames := safe.ToSlice(list, func(chain *network.NfTablesChain) string { return chain.Metadata().ID() })\n\t\tlogger.Info(\"nftables chains updated\", zap.Strings(\"chains\", chainNames))\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *NfTablesChainController) preCreateIptablesNFTable(logger *zap.Logger, conn *nftables.Conn) error {\n\t// Pre-create the iptables-nft table, if it doesn't exist.\n\t// This is required to ensure that the iptables universal binary prefers iptables-nft over\n\t// iptables-legacy can be used to manage the nftables rules.\n\ttables, err := conn.ListTablesOfFamily(nftables.TableFamilyIPv4)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing existing nftables tables: %w\", err)\n\t}\n\n\tif slices.IndexFunc(tables, func(t *nftables.Table) bool { return t.Name == \"mangle\" }) != -1 {\n\t\treturn nil\n\t}\n\n\ttable := &nftables.Table{\n\t\tFamily: nftables.TableFamilyIPv4,\n\t\tName:   \"mangle\",\n\t}\n\tconn.AddTable(table)\n\n\tchain := &nftables.Chain{\n\t\tName:  \"KUBE-IPTABLES-HINT\",\n\t\tTable: table,\n\t\tType:  nftables.ChainTypeNAT,\n\t}\n\tconn.AddChain(chain)\n\n\tlogger.Info(\"pre-created iptables-nft table 'mangle'/'KUBE-IPTABLES-HINT'\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/nftables_chain_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// Chain names.\nconst (\n\tIngressChainName    = \"ingress\"\n\tPreroutingChainName = \"prerouting\"\n)\n\n// NfTablesChainConfigController generates nftables rules based on machine configuration.\ntype NfTablesChainConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NfTablesChainConfigController) Name() string {\n\treturn \"network.NfTablesChainConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NfTablesChainConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NfTablesChainConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.NfTablesChainType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *NfTablesChainConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) (err error) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\t// try first to get filtered node addresses, if not available, use non-filtered one\n\t\t// this handles case of being part of Kubernetes cluster and not being part of it as well\n\t\tnodeAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting filtered node addresses: %w\", err)\n\t\t}\n\n\t\tif nodeAddresses == nil {\n\t\t\tnodeAddresses, err = safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressRoutedID)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting node addresses: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && !(cfg.Config().NetworkRules().DefaultAction() == nethelpers.DefaultActionAccept && cfg.Config().NetworkRules().Rules() == nil) {\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewNfTablesChain(network.NamespaceName, IngressChainName), ctrl.buildIngressChain(cfg)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif nodeAddresses != nil {\n\t\t\t\tif err = safe.WriterModify(ctx, r, network.NewNfTablesChain(network.NamespaceName, PreroutingChainName), ctrl.buildPreroutingChain(cfg, nodeAddresses)); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*network.NfTablesChain](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (ctrl *NfTablesChainConfigController) buildIngressChain(cfg *config.MachineConfig) func(*network.NfTablesChain) error {\n\treturn func(chain *network.NfTablesChain) error {\n\t\tspec := chain.TypedSpec()\n\n\t\tspec.Type = nethelpers.ChainTypeFilter\n\t\tspec.Hook = nethelpers.ChainHookInput\n\t\tspec.Priority = nethelpers.ChainPriorityMangle + 10\n\t\tspec.Policy = nethelpers.VerdictAccept\n\n\t\t// preamble\n\t\tspec.Rules = []network.NfTablesRule{\n\t\t\t// trusted interfaces: loopback, siderolink and kubespan\n\t\t\t{\n\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t},\n\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t},\n\t\t\t\tAnonCounter: true,\n\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t},\n\t\t}\n\n\t\tdefaultAction := cfg.Config().NetworkRules().DefaultAction()\n\n\t\tif defaultAction == nethelpers.DefaultActionBlock {\n\t\t\tspec.Policy = nethelpers.VerdictDrop\n\n\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\t// conntrack\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateEstablished,\n\t\t\t\t\t\t\tnethelpers.ConntrackStateRelated,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateInvalid,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t// CVE-1999-0524 mitigation: drop timestamp and address mask ICMP requests\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\t\t\tMatchICMPType: &network.NfTablesICMPTypeMatch{\n\t\t\t\t\t\t\tTypes: []nethelpers.ICMPType{\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampRequest,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampReply,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskRequest,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskReply,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t// allow ICMP and ICMPv6 explicitly\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLimit: &network.NfTablesLimitMatch{\n\t\t\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMPv6,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLimit: &network.NfTablesLimitMatch{\n\t\t\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif cfg.Config().Machine() != nil && cfg.Config().Cluster() != nil {\n\t\t\t\tif cfg.Config().Machine().Features().HostDNS().ForwardKubeDNSToHost() {\n\t\t\t\t\thostDNSIP := netip.MustParseAddr(constants.HostDNSAddress)\n\n\t\t\t\t\t// allow traffic to host DNS\n\t\t\t\t\tfor _, protocol := range []nethelpers.Protocol{nethelpers.ProtocolUDP, nethelpers.ProtocolTCP} {\n\t\t\t\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\t\t\tIncludeSubnets: xslices.Map(\n\t\t\t\t\t\t\t\t\t\tslices.Concat(\n\t\t\t\t\t\t\t\t\t\t\tcfg.Config().Cluster().Network().PodCIDRs(),\n\t\t\t\t\t\t\t\t\t\t\tcfg.Config().Cluster().Network().ServiceCIDRs(),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\tnetip.MustParsePrefix,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{netip.PrefixFrom(hostDNSIP, hostDNSIP.BitLen())},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\t\t\t\tProtocol: protocol,\n\t\t\t\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\t\t\t\tRanges: []network.PortRange{{Lo: 53, Hi: 53}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif cfg.Config().Cluster() != nil {\n\t\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\t\t// allow Kubernetes pod/service traffic\n\t\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\tIncludeSubnets: xslices.Map(\n\t\t\t\t\t\t\t\tslices.Concat(cfg.Config().Cluster().Network().PodCIDRs(), cfg.Config().Cluster().Network().ServiceCIDRs()),\n\t\t\t\t\t\t\t\tnetip.MustParsePrefix,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\t\tIncludeSubnets: xslices.Map(\n\t\t\t\t\t\t\t\tslices.Concat(cfg.Config().Cluster().Network().PodCIDRs(), cfg.Config().Cluster().Network().ServiceCIDRs()),\n\t\t\t\t\t\t\t\tnetip.MustParsePrefix,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tfor _, rule := range cfg.Config().NetworkRules().Rules() {\n\t\t\tportRanges := rule.PortRanges()\n\n\t\t\t// sort port ranges, machine config validation ensures that there are no overlaps\n\t\t\tslices.SortFunc(portRanges, func(a, b [2]uint16) int {\n\t\t\t\treturn cmp.Compare(a[0], b[0])\n\t\t\t})\n\n\t\t\t// if default accept, drop anything that doesn't match the rule\n\t\t\tverdict := nethelpers.VerdictDrop\n\n\t\t\tif defaultAction == nethelpers.DefaultActionBlock {\n\t\t\t\tverdict = nethelpers.VerdictAccept\n\t\t\t}\n\n\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: rule.Subnets(),\n\t\t\t\t\t\tExcludeSubnets: rule.ExceptSubnets(),\n\t\t\t\t\t\tInvert:         defaultAction == nethelpers.DefaultActionAccept,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: rule.Protocol(),\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: xslices.Map(portRanges, func(pr [2]uint16) network.PortRange {\n\t\t\t\t\t\t\t\treturn network.PortRange{Lo: pr[0], Hi: pr[1]}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(verdict),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\nfunc (ctrl *NfTablesChainConfigController) buildPreroutingChain(cfg *config.MachineConfig, nodeAddresses *network.NodeAddress) func(*network.NfTablesChain) error {\n\t// convert CIDRs to /32 (/128) prefixes matching only the address itself\n\tmyAddresses := xslices.Map(nodeAddresses.TypedSpec().Addresses,\n\t\tfunc(addr netip.Prefix) netip.Prefix {\n\t\t\treturn netip.PrefixFrom(addr.Addr(), addr.Addr().BitLen())\n\t\t},\n\t)\n\n\treturn func(chain *network.NfTablesChain) error {\n\t\tspec := chain.TypedSpec()\n\n\t\tspec.Type = nethelpers.ChainTypeFilter\n\t\tspec.Hook = nethelpers.ChainHookPrerouting\n\t\tspec.Priority = nethelpers.ChainPriorityNATDest - 10\n\t\tspec.Policy = nethelpers.VerdictAccept\n\n\t\tdefaultAction := cfg.Config().NetworkRules().DefaultAction()\n\n\t\t// preamble\n\t\tspec.Rules = []network.NfTablesRule{\n\t\t\t// trusted interfaces: loopback, siderolink and kubespan\n\t\t\t{\n\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t},\n\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t},\n\t\t\t\tAnonCounter: true,\n\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t},\n\t\t}\n\n\t\t// if the traffic is not addressed to the machine, ignore (accept it)\n\t\tspec.Rules = append(spec.Rules,\n\t\t\tnetwork.NfTablesRule{\n\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\tIncludeSubnets: myAddresses,\n\t\t\t\t\tInvert:         true,\n\t\t\t\t},\n\t\t\t\tAnonCounter: true,\n\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t},\n\t\t)\n\n\t\t// drop any 'new' connections to ports outside of the allowed ranges\n\t\tfor _, rule := range cfg.Config().NetworkRules().Rules() {\n\t\t\tportRanges := rule.PortRanges()\n\n\t\t\t// sort port ranges, machine config validation ensures that there are no overlaps\n\t\t\tslices.SortFunc(portRanges, func(a, b [2]uint16) int {\n\t\t\t\treturn cmp.Compare(a[0], b[0])\n\t\t\t})\n\n\t\t\tverdict := nethelpers.VerdictDrop\n\n\t\t\tif defaultAction == nethelpers.DefaultActionBlock {\n\t\t\t\tverdict = nethelpers.VerdictAccept\n\t\t\t}\n\n\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: rule.Subnets(),\n\t\t\t\t\t\tExcludeSubnets: rule.ExceptSubnets(),\n\t\t\t\t\t\tInvert:         defaultAction == nethelpers.DefaultActionAccept,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: rule.Protocol(),\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: xslices.Map(portRanges, func(pr [2]uint16) network.PortRange {\n\t\t\t\t\t\t\t\treturn network.PortRange{Lo: pr[0], Hi: pr[1]}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(verdict),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\tif defaultAction == nethelpers.DefaultActionBlock {\n\t\t\t// drop any TCP/UDP new connections\n\t\t\tspec.Rules = append(spec.Rules,\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\tnetwork.NfTablesRule{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolUDP,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/nftables_chain_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\tconfigtypes \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype NfTablesChainConfigTestSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NfTablesChainConfigTestSuite) injectConfig(block bool) {\n\tkubeletIngressCfg := networkcfg.NewRuleConfigV1Alpha1()\n\tkubeletIngressCfg.MetaName = \"kubelet-ingress\"\n\tkubeletIngressCfg.PortSelector.Ports = []networkcfg.PortRange{\n\t\t{\n\t\t\tLo: 10250,\n\t\t\tHi: 10250,\n\t\t},\n\t}\n\tkubeletIngressCfg.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tkubeletIngressCfg.Ingress = []networkcfg.IngressRule{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\tExcept: networkcfg.Prefix{Prefix: netip.MustParsePrefix(\"10.3.0.0/16\")},\n\t\t},\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t},\n\t}\n\n\tapidIngressCfg := networkcfg.NewRuleConfigV1Alpha1()\n\tapidIngressCfg.MetaName = \"apid-ingress\"\n\tapidIngressCfg.PortSelector.Ports = []networkcfg.PortRange{\n\t\t{\n\t\t\tLo: 50000,\n\t\t\tHi: 50000,\n\t\t},\n\t}\n\tapidIngressCfg.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tapidIngressCfg.Ingress = []networkcfg.IngressRule{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t},\n\t}\n\n\tconfigs := []configtypes.Document{kubeletIngressCfg, apidIngressCfg}\n\n\tif block {\n\t\tdefaultActionCfg := networkcfg.NewDefaultActionConfigV1Alpha1()\n\t\tdefaultActionCfg.Ingress = nethelpers.DefaultActionBlock\n\n\t\tconfigs = append(configs, defaultActionCfg)\n\t}\n\n\tcfg, err := container.New(configs...)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(cfg))\n\n\tnodeAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressRoutedID)\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"10.3.4.5/24\")}\n\tsuite.Create(nodeAddresses)\n}\n\nfunc (suite *NfTablesChainConfigTestSuite) TestDefaultAccept() {\n\tctest.AssertNoResource[*network.NfTablesChain](suite, netctrl.IngressChainName)\n\n\tsuite.injectConfig(false)\n\n\tctest.AssertResource(suite, netctrl.IngressChainName, func(chain *network.NfTablesChain, asrt *assert.Assertions) {\n\t\tspec := chain.TypedSpec()\n\n\t\tasrt.Equal(nethelpers.ChainTypeFilter, spec.Type)\n\t\tasrt.Equal(nethelpers.ChainPriorityMangle+10, spec.Priority)\n\t\tasrt.Equal(nethelpers.ChainHookInput, spec.Hook)\n\t\tasrt.Equal(nethelpers.VerdictAccept, spec.Policy)\n\n\t\tasrt.Equal(\n\t\t\t[]network.NfTablesRule{\n\t\t\t\t{\n\t\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 10250,\n\t\t\t\t\t\t\t\t\tHi: 10250,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 50000,\n\t\t\t\t\t\t\t\t\tHi: 50000,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.Rules)\n\t})\n\n\tctest.AssertResource(suite, netctrl.PreroutingChainName, func(chain *network.NfTablesChain, asrt *assert.Assertions) {\n\t\tspec := chain.TypedSpec()\n\n\t\tasrt.Equal(nethelpers.ChainTypeFilter, spec.Type)\n\t\tasrt.Equal(nethelpers.ChainPriorityNATDest-10, spec.Priority)\n\t\tasrt.Equal(nethelpers.ChainHookPrerouting, spec.Hook)\n\t\tasrt.Equal(nethelpers.VerdictAccept, spec.Policy)\n\n\t\tasrt.Equal(\n\t\t\t[]network.NfTablesRule{\n\t\t\t\t{\n\t\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.4.5/32\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 10250,\n\t\t\t\t\t\t\t\t\tHi: 10250,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 50000,\n\t\t\t\t\t\t\t\t\tHi: 50000,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.Rules)\n\t})\n}\n\nfunc (suite *NfTablesChainConfigTestSuite) TestDefaultBlock() {\n\tctest.AssertNoResource[*network.NfTablesChain](suite, netctrl.IngressChainName)\n\n\tsuite.injectConfig(true)\n\n\tctest.AssertResource(suite, netctrl.IngressChainName, func(chain *network.NfTablesChain, asrt *assert.Assertions) {\n\t\tspec := chain.TypedSpec()\n\n\t\tasrt.Equal(nethelpers.ChainTypeFilter, spec.Type)\n\t\tasrt.Equal(nethelpers.ChainPriorityMangle+10, spec.Priority)\n\t\tasrt.Equal(nethelpers.ChainHookInput, spec.Hook)\n\t\tasrt.Equal(nethelpers.VerdictDrop, spec.Policy)\n\n\t\tasrt.Equal(\n\t\t\t[]network.NfTablesRule{\n\t\t\t\t{\n\t\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateEstablished,\n\t\t\t\t\t\t\tnethelpers.ConntrackStateRelated,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateInvalid,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\t\t\tMatchICMPType: &network.NfTablesICMPTypeMatch{\n\t\t\t\t\t\t\tTypes: []nethelpers.ICMPType{\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampRequest,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeTimestampReply,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskRequest,\n\t\t\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskReply,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLimit: &network.NfTablesLimitMatch{\n\t\t\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolICMPv6,\n\t\t\t\t\t},\n\t\t\t\t\tMatchLimit: &network.NfTablesLimitMatch{\n\t\t\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 10250,\n\t\t\t\t\t\t\t\t\tHi: 10250,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 50000,\n\t\t\t\t\t\t\t\t\tHi: 50000,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.Rules)\n\t})\n\n\tctest.AssertResource(suite, netctrl.PreroutingChainName, func(chain *network.NfTablesChain, asrt *assert.Assertions) {\n\t\tspec := chain.TypedSpec()\n\n\t\tasrt.Equal(nethelpers.ChainTypeFilter, spec.Type)\n\t\tasrt.Equal(nethelpers.ChainPriorityNATDest-10, spec.Priority)\n\t\tasrt.Equal(nethelpers.ChainHookPrerouting, spec.Hook)\n\t\tasrt.Equal(nethelpers.VerdictAccept, spec.Policy)\n\n\t\tasrt.Equal(\n\t\t\t[]network.NfTablesRule{\n\t\t\t\t{\n\t\t\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\t\t\tInterfaceNames: []string{\n\t\t\t\t\t\t\t\"lo\",\n\t\t\t\t\t\t\tconstants.SideroLinkName,\n\t\t\t\t\t\t\tconstants.KubeSpanLinkName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOperator: nethelpers.OperatorEqual,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.4.5/32\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tInvert: true,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 10250,\n\t\t\t\t\t\t\t\t\tHi: 10250,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tLo: 50000,\n\t\t\t\t\t\t\t\t\tHi: 50000,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictAccept),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\t\t\tnethelpers.ConntrackStateNew,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\t\t\tProtocol: nethelpers.ProtocolUDP,\n\t\t\t\t\t},\n\t\t\t\t\tAnonCounter: true,\n\t\t\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t\t\t},\n\t\t\t},\n\t\t\tspec.Rules)\n\t})\n}\n\nfunc TestNfTablesChainConfig(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NfTablesChainConfigTestSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.NfTablesChainConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/nftables_chain_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"os\"\n\t\"os/exec\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype NfTablesChainSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (s *NfTablesChainSuite) nftOutput() string {\n\tout, err := exec.CommandContext(s.T().Context(), \"nft\", \"list\", \"table\", \"inet\", \"talos-test\").CombinedOutput()\n\tif err != nil {\n\t\tif strings.Contains(string(out), \"No such file or directory\") ||\n\t\t\tstrings.Contains(string(out), \"No such table\") {\n\t\t\treturn \"table inet talos-test {\\n}\"\n\t\t}\n\t}\n\n\ts.Require().NoError(err, \"nft list table inet talos-test failed: %s\", string(out))\n\n\treturn string(out)\n}\n\nfunc (s *NfTablesChainSuite) checkNftOutput(expected ...string) {\n\ts.T().Helper()\n\n\tvar prevOutput string\n\n\ts.Eventually(func() bool {\n\t\toutput := s.nftOutput()\n\t\tmatches := slices.Contains(expected, strings.TrimSpace(output))\n\n\t\tif output != prevOutput {\n\t\t\tif !matches {\n\t\t\t\ts.T().Logf(\"nft list table inet talos-test:\\n%s\", output)\n\t\t\t\ts.T().Logf(\"expected:\\n%s\", strings.Join(expected, \"\\n\"))\n\t\t\t}\n\n\t\t\tprevOutput = output\n\t\t}\n\n\t\treturn matches\n\t}, 5*time.Second, 100*time.Millisecond)\n}\n\nfunc (s *NfTablesChainSuite) TestEmpty() {\n\ts.checkNftOutput(`table inet talos-test {\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestAcceptLo() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPrioritySecurity\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchOIfName: &network.NfTablesIfNameMatch{\n\t\t\t\tInterfaceNames: []string{\"lo\"},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority security; policy accept;\n\t\toifname \"lo\" accept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestAcceptMultipleIfnames() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPrioritySecurity\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchIIfName: &network.NfTablesIfNameMatch{\n\t\t\t\tInterfaceNames: []string{\"eth0\", \"eth1\"},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\t// this seems to be a bug in the nft cli, it doesn't decoded the ifname anonymous set correctly\n\t// it might be that google/nftables doesn't set some magic on the anonymous set for the nft CLI to pick it up (?)\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority security; policy accept;\n\t\tiifname { \"\", \"\" } accept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestPolicyDrop() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPrioritySecurity\n\tchain.TypedSpec().Policy = nethelpers.VerdictDrop\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority security; policy drop;\n\t\taccept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestICMPLimit() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPrioritySecurity\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t},\n\t\t\tMatchLimit: &network.NfTablesLimitMatch{\n\t\t\t\tPacketRatePerSecond: 5,\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority security; policy accept;\n\t\tmeta l4proto icmp limit rate 5/second burst 5 packets accept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestConntrackCounter() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPrioritySecurity\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\tnethelpers.ConntrackStateEstablished,\n\t\t\t\t\tnethelpers.ConntrackStateRelated,\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t\t{\n\t\t\tMatchConntrackState: &network.NfTablesConntrackStateMatch{\n\t\t\t\tStates: []nethelpers.ConntrackState{\n\t\t\t\t\tnethelpers.ConntrackStateEstablished, // this rule should never match, as previous rule matches it\n\t\t\t\t},\n\t\t\t},\n\t\t\tAnonCounter: true,\n\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority security; policy accept;\n\t\tct state { 0x2000000, 0x4000000 } accept\n\t\tct state established counter packets 0 bytes 0 drop\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestMatchMarksSubnets() {\n\tchain1 := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain1.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain1.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain1.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain1.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain1.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchMark: &network.NfTablesMark{\n\t\t\t\tMask:  constants.KubeSpanDefaultFirewallMask,\n\t\t\t\tValue: constants.KubeSpanDefaultFirewallMark,\n\t\t\t},\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tnetip.MustParsePrefix(\"0::/0\"),\n\t\t\t\t},\n\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t},\n\t\t\t\tInvert: true,\n\t\t\t},\n\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain1))\n\n\tchain2 := network.NewNfTablesChain(network.NamespaceName, \"test2\")\n\tchain2.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain2.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain2.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain2.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain2.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"192.168.3.5/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\tXor:  constants.KubeSpanDefaultFirewallMark,\n\t\t\t},\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain2))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tmeta mark & 0x00000060 == 0x00000020 ip saddr != { 10.0.0.0-10.2.255.255, 10.4.0.0-10.255.255.255 } ip daddr { 192.168.0.0/24 } accept\n\t}\n\n\tchain test2 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip daddr { 192.168.3.5 } meta mark set meta mark & 0xffffffbf | 0x00000020\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestUpdateChains() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t},\n\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.3.0.0/16\"),\n\t\t\t\t},\n\t\t\t\tInvert: true,\n\t\t\t},\n\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip saddr != { 10.0.0.0-10.2.255.255, 10.4.0.0-10.255.255.255 } ip daddr { 192.168.0.0/24 } accept\n\t\tmeta nfproto ipv6 accept\n\t}\n}`)\n\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t},\n\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.4.0.0/16\"),\n\t\t\t\t},\n\t\t\t\tInvert: true,\n\t\t\t},\n\t\t\tSetMark: &network.NfTablesMark{\n\t\t\t\tMask: ^uint32(constants.KubeSpanDefaultFirewallMask),\n\t\t\t\tXor:  constants.KubeSpanDefaultFirewallMark,\n\t\t\t},\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Update(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip saddr != { 10.0.0.0/14, 10.5.0.0-10.255.255.255 } meta mark set meta mark & 0xffffffbf | 0x00000020\n\t\tmeta nfproto ipv6 meta mark set meta mark & 0xffffffbf | 0x00000020\n\t}\n}`)\n\n\ts.Require().NoError(s.State().Destroy(s.Ctx(), chain.Metadata()))\n\n\ts.checkNftOutput(`table inet talos-test {\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestClampMSS() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test1\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\tInvert: true, // match all addresses\n\t\t\t},\n\t\t\tClampMSS: &network.NfTablesClampMSS{\n\t\t\t\tMTU: constants.KubeSpanLinkMTU,\n\t\t\t},\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\t// several versions here for different version of `nft` CLI decoding the rules\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tmeta nfproto ipv4 tcp flags syn / syn,rst tcp option maxseg size > 1368 tcp option maxseg size set 1368\n\t\tmeta nfproto ipv6 tcp flags syn / syn,rst tcp option maxseg size > 1348 tcp option maxseg size set 1348\n\t}\n}`, `table inet talos-test {\n\tchain test1 {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tmeta nfproto ipv4 tcp flags & (syn | rst) == syn tcp option maxseg size > 1368 tcp option maxseg size set 1368\n\t\tmeta nfproto ipv6 tcp flags & (syn | rst) == syn tcp option maxseg size > 1348 tcp option maxseg size set 1348\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestL4Match() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchDestinationAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tnetip.MustParsePrefix(\"2001::/16\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1023,\n\t\t\t\t\t\t\tHi: 1025,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1027,\n\t\t\t\t\t\t\tHi: 1029,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip daddr { 10.0.0.0/8 } tcp dport { 1023-1025, 1027-1029 } drop\n\t\tip6 daddr { 2001::/16 } tcp dport { 1023-1025, 1027-1029 } drop\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestL4Match2() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t},\n\t\t\t\tInvert: true,\n\t\t\t},\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1023,\n\t\t\t\t\t\t\tHi: 1023,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1024,\n\t\t\t\t\t\t\tHi: 1024,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip saddr != { 10.0.0.0/8 } tcp dport { 1023-1024 } drop\n\t\tmeta nfproto ipv6 tcp dport { 1023-1024 } drop\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestL4MatchAdjacentPorts() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t},\n\t\t\t\tInvert: true,\n\t\t\t},\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 5000,\n\t\t\t\t\t\t\tHi: 5000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 5001,\n\t\t\t\t\t\t\tHi: 5001,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 10250,\n\t\t\t\t\t\t\tHi: 10250,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 4240,\n\t\t\t\t\t\t\tHi: 4240,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictDrop),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip saddr != { 10.0.0.0/8 } tcp dport { 4240, 5000-5001, 10250 } drop\n\t\tmeta nfproto ipv6 tcp dport { 4240, 5000-5001, 10250 } drop\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestL4MatchAny() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1023,\n\t\t\t\t\t\t\tHi: 1023,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tmeta nfproto ipv4 tcp dport { 1023 } accept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestL4MatchAnyWithHole() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchSourceAddress: &network.NfTablesAddressMatch{\n\t\t\t\tIncludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\tnetip.MustParsePrefix(\"::/0\"),\n\t\t\t\t},\n\t\t\t\tExcludeSubnets: []netip.Prefix{\n\t\t\t\t\tnetip.MustParsePrefix(\"10.1.2.3/32\"),\n\t\t\t\t\tnetip.MustParsePrefix(\"fe80::1/128\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolTCP,\n\t\t\t\tMatchDestinationPort: &network.NfTablesPortMatch{\n\t\t\t\t\tRanges: []network.PortRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLo: 1023,\n\t\t\t\t\t\t\tHi: 1023,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tVerdict: new(nethelpers.VerdictAccept),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\tip saddr { 0.0.0.0-10.1.2.2, 10.1.2.4-255.255.255.255 } tcp dport { 1023 } accept\n\t\tip6 saddr { ::-fe80::, fe80::2-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } tcp dport { 1023 } accept\n\t}\n}`)\n}\n\nfunc (s *NfTablesChainSuite) TestICMPTypeMatch() {\n\tchain := network.NewNfTablesChain(network.NamespaceName, \"test-tcp\")\n\tchain.TypedSpec().Type = nethelpers.ChainTypeFilter\n\tchain.TypedSpec().Hook = nethelpers.ChainHookInput\n\tchain.TypedSpec().Priority = nethelpers.ChainPriorityFilter\n\tchain.TypedSpec().Policy = nethelpers.VerdictAccept\n\tchain.TypedSpec().Rules = []network.NfTablesRule{\n\t\t{\n\t\t\tMatchLayer4: &network.NfTablesLayer4Match{\n\t\t\t\tProtocol: nethelpers.ProtocolICMP,\n\t\t\t\tMatchICMPType: &network.NfTablesICMPTypeMatch{\n\t\t\t\t\tTypes: []nethelpers.ICMPType{\n\t\t\t\t\t\tnethelpers.ICMPTypeTimestampRequest,\n\t\t\t\t\t\tnethelpers.ICMPTypeTimestampReply,\n\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskRequest,\n\t\t\t\t\t\tnethelpers.ICMPTypeAddressMaskReply,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAnonCounter: true,\n\t\t\tVerdict:     new(nethelpers.VerdictDrop),\n\t\t},\n\t}\n\n\ts.Require().NoError(s.State().Create(s.Ctx(), chain))\n\n\ts.checkNftOutput(`table inet talos-test {\n\tchain test-tcp {\n\t\ttype filter hook input priority filter; policy accept;\n\t\ticmp type { timestamp-request, timestamp-reply, address-mask-request, address-mask-reply } counter packets 0 bytes 0 drop\n\t}\n}`)\n}\n\nfunc TestNftablesChainSuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tif exec.CommandContext(t.Context(), \"nft\", \"list\", \"tables\").Run() != nil {\n\t\tt.Skip(\"requires nftables CLI to be installed\")\n\t}\n\n\tsuite.Run(t, &NfTablesChainSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\t// try to see if the table is there\n\t\t\t\tif exec.CommandContext(s.Ctx(), \"nft\", \"list\", \"table\", \"inet\", \"talos-test\").Run() == nil {\n\t\t\t\t\ts.Require().NoError(exec.CommandContext(s.Ctx(), \"nft\", \"delete\", \"table\", \"inet\", \"talos-test\").Run())\n\t\t\t\t}\n\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.NfTablesChainController{TableName: \"talos-test\"}))\n\t\t\t},\n\t\t\tAfterTearDown: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(exec.CommandContext(s.T().Context(), \"nft\", \"delete\", \"table\", \"inet\", \"talos-test\").Run())\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/node_address.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NodeAddressController manages secrets.Etcd based on configuration.\ntype NodeAddressController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeAddressController) Name() string {\n\treturn \"network.NodeAddressController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeAddressController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.AddressStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressFilterType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressSortAlgorithmType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeAddressController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.NodeAddressType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *NodeAddressController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tvar addressStatusController AddressStatusController\n\n\taddressStatusControllerName := addressStatusController.Name()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// get algorithm to use\n\t\talgoRes, err := safe.ReaderGetByID[*network.NodeAddressSortAlgorithm](ctx, r, network.NodeAddressSortAlgorithmID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// wait for the resource to appear\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting sort algorithm: %w\", err)\n\t\t}\n\n\t\talgo := algoRes.TypedSpec().Algorithm\n\n\t\t// fetch link and address status resources\n\t\tlinks, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\t// build \"link up\" lookup table\n\t\tlinksUp := make(map[uint32]struct{})\n\n\t\tfor link := range links.All() {\n\t\t\tif link.TypedSpec().OperationalState == nethelpers.OperStateUp || link.TypedSpec().OperationalState == nethelpers.OperStateUnknown {\n\t\t\t\t// skip physical interfaces without carrier\n\t\t\t\tif !link.TypedSpec().Physical() || link.TypedSpec().LinkState {\n\t\t\t\t\tlinksUp[link.TypedSpec().Index] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// fetch list of filters\n\t\tfilters, err := safe.ReaderListAll[*network.NodeAddressFilter](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing address filters: %w\", err)\n\t\t}\n\n\t\taddressesList, err := safe.ReaderListAll[*network.AddressStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\taddresses := safe.ToSlice(addressesList, func(a *network.AddressStatus) *network.AddressStatus { return a })\n\n\t\tcompareFunc := addressutil.CompareByAlgorithm(algo)\n\n\t\t// filter out addresses which should be ignored\n\t\taddresses = xslices.FilterInPlace(addresses, func(addr *network.AddressStatus) bool {\n\t\t\tif addr.TypedSpec().Scope >= nethelpers.ScopeLink {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tip := addr.TypedSpec().Address\n\n\t\t\tif ip.Addr().IsLoopback() || ip.Addr().IsMulticast() || ip.Addr().IsLinkLocalUnicast() {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t})\n\n\t\tslices.SortFunc(addresses, addressutil.CompareAddressStatuses(compareFunc))\n\n\t\tvar (\n\t\t\tdefaultAddress netip.Prefix\n\t\t\tcurrent        []netip.Prefix\n\t\t\trouted         []netip.Prefix\n\t\t\taccumulative   []netip.Prefix\n\t\t)\n\n\t\tfor _, addr := range addresses {\n\t\t\tip := addr.TypedSpec().Address\n\n\t\t\t// set defaultAddress to the smallest IP from the alphabetically first link\n\t\t\tif addr.Metadata().Owner() == addressStatusControllerName {\n\t\t\t\tif value.IsZero(defaultAddress) {\n\t\t\t\t\tdefaultAddress = ip\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// assume addresses from external IPs to be always up\n\t\t\tif _, up := linksUp[addr.TypedSpec().LinkIndex]; up || addr.TypedSpec().LinkName == externalLink {\n\t\t\t\tcurrent = append(current, ip)\n\t\t\t}\n\n\t\t\t// routed: filter out external addresses and addresses from SideroLink\n\t\t\tif _, up := linksUp[addr.TypedSpec().LinkIndex]; up && addr.TypedSpec().LinkName != externalLink {\n\t\t\t\tif network.NotSideroLinkIP(ip.Addr()) {\n\t\t\t\t\trouted = append(routed, ip)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\taccumulative = append(accumulative, ip)\n\t\t}\n\n\t\t// sort current addresses\n\t\tslices.SortFunc(current, compareFunc)\n\t\tslices.SortFunc(routed, compareFunc)\n\n\t\t// remove duplicates from current addresses\n\t\tcurrent = addressutil.DeduplicateIPPrefixes(current)\n\t\trouted = addressutil.DeduplicateIPPrefixes(routed)\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\t// update output resources\n\t\tif !value.IsZero(defaultAddress) {\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID), func(r *network.NodeAddress) error {\n\t\t\t\tspec := r.TypedSpec()\n\n\t\t\t\t// never overwrite default address if it's already set\n\t\t\t\t// we should start handing default address updates, but for now we're not ready\n\t\t\t\t//\n\t\t\t\t// at the same time check that recorded default address is still on the host, if it's not => replace it\n\t\t\t\t// also replace default address on algorithm change\n\t\t\t\tif spec.SortAlgorithm == algo && len(spec.Addresses) > 0 && slices.ContainsFunc(current, func(addr netip.Prefix) bool { return spec.Addresses[0] == addr }) {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tspec.Addresses = []netip.Prefix{defaultAddress}\n\t\t\t\tspec.SortAlgorithm = algo\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating output resource: %w\", err)\n\t\t\t}\n\n\t\t\ttouchedIDs[network.NodeAddressDefaultID] = struct{}{}\n\t\t}\n\n\t\tif err = ctrl.updateCurrentAddresses(ctx, r, network.NodeAddressCurrentID, current, algo); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttouchedIDs[network.NodeAddressCurrentID] = struct{}{}\n\n\t\tif err = ctrl.updateCurrentAddresses(ctx, r, network.NodeAddressRoutedID, routed, algo); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttouchedIDs[network.NodeAddressRoutedID] = struct{}{}\n\n\t\tif err = ctrl.updateAccumulativeAddresses(ctx, r, network.NodeAddressAccumulativeID, accumulative, algo, compareFunc); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttouchedIDs[network.NodeAddressAccumulativeID] = struct{}{}\n\n\t\t// update filtered resources\n\t\tfor filterRes := range filters.All() {\n\t\t\tfilterID := filterRes.Metadata().ID()\n\t\t\tfilter := filterRes.TypedSpec()\n\n\t\t\tfilteredCurrent := addressutil.FilterIPs(current, filter.IncludeSubnets, filter.ExcludeSubnets)\n\t\t\tfilteredRouted := addressutil.FilterIPs(routed, filter.IncludeSubnets, filter.ExcludeSubnets)\n\t\t\tfilteredAccumulative := addressutil.FilterIPs(accumulative, filter.IncludeSubnets, filter.ExcludeSubnets)\n\n\t\t\tif err = ctrl.updateCurrentAddresses(ctx, r, network.FilteredNodeAddressID(network.NodeAddressCurrentID, filterID), filteredCurrent, algo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err = ctrl.updateCurrentAddresses(ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, filterID), filteredRouted, algo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err = ctrl.updateAccumulativeAddresses(ctx, r, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filterID), filteredAccumulative, algo, compareFunc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttouchedIDs[network.FilteredNodeAddressID(network.NodeAddressCurrentID, filterID)] = struct{}{}\n\t\t\ttouchedIDs[network.FilteredNodeAddressID(network.NodeAddressRoutedID, filterID)] = struct{}{}\n\t\t\ttouchedIDs[network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filterID)] = struct{}{}\n\t\t}\n\n\t\t// list keys for cleanup\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.NodeAddressType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *NodeAddressController) updateCurrentAddresses(ctx context.Context, r controller.Runtime, id resource.ID, current []netip.Prefix, algo nethelpers.AddressSortAlgorithm) error {\n\tif err := safe.WriterModify(ctx, r, network.NewNodeAddress(network.NamespaceName, id), func(r *network.NodeAddress) error {\n\t\tspec := r.TypedSpec()\n\n\t\tspec.Addresses = current\n\t\tspec.SortAlgorithm = algo\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating output resource: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *NodeAddressController) updateAccumulativeAddresses(\n\tctx context.Context, r controller.Runtime, id resource.ID, accumulative []netip.Prefix, algo nethelpers.AddressSortAlgorithm, compare func(a, b netip.Prefix) int,\n) error {\n\tif err := safe.WriterModify(ctx, r, network.NewNodeAddress(network.NamespaceName, id), func(r *network.NodeAddress) error {\n\t\tspec := r.TypedSpec()\n\n\t\tfor _, ip := range accumulative {\n\t\t\t// find insert position using binary search\n\t\t\tpos, _ := slices.BinarySearchFunc(spec.Addresses, ip, compare)\n\n\t\t\tif pos < len(spec.Addresses) && compare(spec.Addresses[pos], ip) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// insert at position i\n\t\t\tspec.Addresses = slices.Insert(spec.Addresses, pos, ip)\n\t\t}\n\n\t\tspec.SortAlgorithm = algo\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating output resource: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/node_address_sort_algorithm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NodeAddressSortAlgorithmController manages NodeAddressSortAlgorithm based on configuration.\ntype NodeAddressSortAlgorithmController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *NodeAddressSortAlgorithmController) Name() string {\n\treturn \"network.NodeAddressSortAlgorithmController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *NodeAddressSortAlgorithmController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *NodeAddressSortAlgorithmController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.NodeAddressSortAlgorithmType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *NodeAddressSortAlgorithmController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get %s: %w\", config.MachineConfigType, err)\n\t\t}\n\n\t\talgorithm := nethelpers.AddressSortAlgorithmV1\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\talgorithm = cfg.Provider().Machine().Features().NodeAddressSortAlgorithm()\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID), func(res *network.NodeAddressSortAlgorithm) error {\n\t\t\tres.TypedSpec().Algorithm = algorithm\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update %s: %w\", network.NodeAddressSortAlgorithmType, err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/node_address_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/addressutil\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype NodeAddressSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *NodeAddressSuite) TestDefaults() {\n\t// create fake device ready status\n\tdeviceStatus := runtimeres.NewDevicesStatus(runtimeres.NamespaceName, runtimeres.DevicesID)\n\tdeviceStatus.TypedSpec().Ready = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), deviceStatus))\n\n\tsortAlgorithm := network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID)\n\tsortAlgorithm.TypedSpec().Algorithm = nethelpers.AddressSortAlgorithmV1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), sortAlgorithm))\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.AddressStatusController{}))\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.LinkStatusController{}))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressRoutedID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t},\n\t\tfunc(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tsuite.T().Logf(\"id %q val %s\", r.Metadata().ID(), addrs)\n\n\t\t\tasrt.True(\n\t\t\t\tslices.IsSortedFunc(\n\t\t\t\t\taddrs,\n\t\t\t\t\taddressutil.ComparePrefixesLegacy,\n\t\t\t\t), \"addresses %s\", addrs,\n\t\t\t)\n\n\t\t\tif r.Metadata().ID() == network.NodeAddressDefaultID {\n\t\t\t\tasrt.Len(addrs, 1)\n\t\t\t} else {\n\t\t\t\tasrt.NotEmpty(addrs)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *NodeAddressSuite) newAddress(addr netip.Prefix, link *network.LinkStatus) {\n\tvar addressStatusController netctrl.AddressStatusController\n\n\taddressStatus := network.NewAddressStatus(network.NamespaceName, network.AddressID(link.Metadata().ID(), addr))\n\taddressStatus.TypedSpec().Address = addr\n\taddressStatus.TypedSpec().LinkName = link.Metadata().ID()\n\taddressStatus.TypedSpec().LinkIndex = link.TypedSpec().Index\n\tsuite.Require().NoError(\n\t\tsuite.State().Create(\n\t\t\tsuite.Ctx(),\n\t\t\taddressStatus,\n\t\t\tstate.WithCreateOwner(addressStatusController.Name()),\n\t\t),\n\t)\n}\n\nfunc (suite *NodeAddressSuite) newExternalAddress(addr netip.Prefix) {\n\tvar platformConfigController netctrl.PlatformConfigApplyController\n\n\taddressStatus := network.NewAddressStatus(network.NamespaceName, network.AddressID(\"external\", addr))\n\taddressStatus.TypedSpec().Address = addr\n\taddressStatus.TypedSpec().LinkName = \"external\"\n\tsuite.Require().NoError(\n\t\tsuite.State().Create(\n\t\t\tsuite.Ctx(),\n\t\t\taddressStatus,\n\t\t\tstate.WithCreateOwner(platformConfigController.Name()),\n\t\t),\n\t)\n}\n\n//nolint:gocyclo\nfunc (suite *NodeAddressSuite) TestFilters() {\n\tlinkUp := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tlinkUp.TypedSpec().Type = nethelpers.LinkEther\n\tlinkUp.TypedSpec().LinkState = true\n\tlinkUp.TypedSpec().Index = 1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkUp))\n\n\tlinkDown := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\tlinkDown.TypedSpec().Type = nethelpers.LinkEther\n\tlinkDown.TypedSpec().LinkState = false\n\tlinkDown.TypedSpec().Index = 2\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkDown))\n\n\tsortAlgorithm := network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID)\n\tsortAlgorithm.TypedSpec().Algorithm = nethelpers.AddressSortAlgorithmV1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), sortAlgorithm))\n\n\tfor _, addr := range []string{\n\t\t\"10.0.0.1/8\",\n\t\t\"25.3.7.9/32\",\n\t\t\"2001:470:6d:30e:4a62:b3ba:180b:b5b8/64\",\n\t\t\"127.0.0.1/8\",\n\t\t\"fdae:41e4:649b:9303:7886:731d:1ce9:4d4/128\",\n\t} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkUp)\n\t}\n\n\tfor _, addr := range []string{\"10.0.0.2/8\", \"192.168.3.7/24\"} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkDown)\n\t}\n\n\tfor _, addr := range []string{\"1.2.3.4/32\", \"25.3.7.9/32\"} { // duplicate with link address: 25.3.7.9\n\t\tsuite.newExternalAddress(netip.MustParsePrefix(addr))\n\t}\n\n\tfilter1 := network.NewNodeAddressFilter(network.NamespaceName, \"no-k8s\")\n\tfilter1.TypedSpec().ExcludeSubnets = []netip.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), filter1))\n\n\tfilter2 := network.NewNodeAddressFilter(network.NamespaceName, \"only-k8s\")\n\tfilter2.TypedSpec().IncludeSubnets = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), filter2))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressRoutedID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter2.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()),\n\t\t},\n\t\tfunc(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressDefaultID:\n\t\t\t\tasrt.Equal(\"10.0.0.1/8\", stringifyIPs(addrs))\n\t\t\tcase network.NodeAddressCurrentID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/32 10.0.0.1/8 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64 fdae:41e4:649b:9303:7886:731d:1ce9:4d4/128\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressRoutedID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.0.0.1/8 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/32 10.0.0.1/8 10.0.0.2/8 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64 fdae:41e4:649b:9303:7886:731d:1ce9:4d4/128\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()):\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/32 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64 fdae:41e4:649b:9303:7886:731d:1ce9:4d4/128\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressRoutedID, filter1.Metadata().ID()):\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()):\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/32 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64 fdae:41e4:649b:9303:7886:731d:1ce9:4d4/128\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()),\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter2.Metadata().ID()):\n\t\t\t\tasrt.Equal(\"10.0.0.1/8\", stringifyIPs(addrs))\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()):\n\t\t\t\tasrt.Equal(\"10.0.0.1/8 10.0.0.2/8 192.168.3.7/24\", stringifyIPs(addrs))\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *NodeAddressSuite) TestSortAlgorithmV2() {\n\tlinkUp := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tlinkUp.TypedSpec().Type = nethelpers.LinkEther\n\tlinkUp.TypedSpec().LinkState = true\n\tlinkUp.TypedSpec().Index = 1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkUp))\n\n\tlinkDown := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\tlinkDown.TypedSpec().Type = nethelpers.LinkEther\n\tlinkDown.TypedSpec().LinkState = false\n\tlinkDown.TypedSpec().Index = 2\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkDown))\n\n\tsortAlgorithm := network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID)\n\tsortAlgorithm.TypedSpec().Algorithm = nethelpers.AddressSortAlgorithmV2\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), sortAlgorithm))\n\n\tfor _, addr := range []string{\n\t\t\"1.2.3.4/26\", // insert default address first, otherwise the test would be flaky, as default address is immutable\n\t\t\"10.3.4.1/24\",\n\t\t\"10.3.4.5/24\",\n\t\t\"10.3.4.5/32\",\n\t\t\"192.168.35.11/24\",\n\t\t\"192.168.36.10/24\",\n\t\t\"127.0.0.1/8\",\n\t\t\"::1/128\",\n\t\t\"fd01:cafe::5054:ff:fe1f:c7bd/64\",\n\t\t\"fd01:cafe::f14c:9fa1:8496:557f/128\",\n\t} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkUp)\n\t}\n\n\tfor _, addr := range []string{\"10.0.0.2/8\", \"192.168.3.7/24\"} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkDown)\n\t}\n\n\tfor _, addr := range []string{\"1.2.3.4/26\"} { // duplicate with link address: 1.2.3.4\n\t\tsuite.newExternalAddress(netip.MustParsePrefix(addr))\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressRoutedID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t},\n\t\tfunc(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressDefaultID:\n\t\t\t\tasrt.Equal(\"1.2.3.4/26\", stringifyIPs(addrs))\n\t\t\tcase network.NodeAddressCurrentID, network.NodeAddressRoutedID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/26 10.3.4.5/32 10.3.4.1/24 10.3.4.5/24 192.168.35.11/24 192.168.36.10/24 fd01:cafe::f14c:9fa1:8496:557f/128 fd01:cafe::5054:ff:fe1f:c7bd/64\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.2.3.4/26 10.3.4.5/32 10.3.4.1/24 10.3.4.5/24 10.0.0.2/8 192.168.3.7/24 192.168.35.11/24 192.168.36.10/24 fd01:cafe::f14c:9fa1:8496:557f/128 fd01:cafe::5054:ff:fe1f:c7bd/64\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *NodeAddressSuite) TestFilterOverlappingSubnets() {\n\tlinkUp := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tlinkUp.TypedSpec().Type = nethelpers.LinkEther\n\tlinkUp.TypedSpec().LinkState = true\n\tlinkUp.TypedSpec().Index = 1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkUp))\n\n\tsortAlgorithm := network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID)\n\tsortAlgorithm.TypedSpec().Algorithm = nethelpers.AddressSortAlgorithmV1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), sortAlgorithm))\n\n\tfor _, addr := range []string{\n\t\t\"10.0.0.1/8\",\n\t\t\"10.96.0.2/32\",\n\t\t\"25.3.7.9/32\",\n\t} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkUp)\n\t}\n\n\tfilter1 := network.NewNodeAddressFilter(network.NamespaceName, \"no-k8s\")\n\tfilter1.TypedSpec().ExcludeSubnets = []netip.Prefix{netip.MustParsePrefix(\"10.96.0.0/12\")}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), filter1))\n\n\tfilter2 := network.NewNodeAddressFilter(network.NamespaceName, \"only-k8s\")\n\tfilter2.TypedSpec().IncludeSubnets = []netip.Prefix{netip.MustParsePrefix(\"10.96.0.0/12\")}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), filter2))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressRoutedID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter2.Metadata().ID()),\n\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()),\n\t\t},\n\t\tfunc(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressCurrentID, network.NodeAddressRoutedID, network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.0.0.1/8 10.96.0.2/32 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()),\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter1.Metadata().ID()),\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()):\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.0.0.1/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()),\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressRoutedID, filter2.Metadata().ID()),\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()):\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.96.0.2/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n}\n\n//nolint:gocyclo\nfunc (suite *NodeAddressSuite) TestDefaultAddressChange() {\n\tvar addressStatusController netctrl.AddressStatusController\n\n\tlinkUp := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tlinkUp.TypedSpec().Type = nethelpers.LinkEther\n\tlinkUp.TypedSpec().LinkState = true\n\tlinkUp.TypedSpec().Index = 1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), linkUp))\n\n\tsortAlgorithm := network.NewNodeAddressSortAlgorithm(network.NamespaceName, network.NodeAddressSortAlgorithmID)\n\tsortAlgorithm.TypedSpec().Algorithm = nethelpers.AddressSortAlgorithmV1\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), sortAlgorithm))\n\n\tfor _, addr := range []string{\n\t\t\"10.0.0.5/8\",\n\t\t\"25.3.7.9/32\",\n\t\t\"127.0.0.1/8\",\n\t} {\n\t\tsuite.newAddress(netip.MustParsePrefix(addr), linkUp)\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t}, func(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressDefaultID:\n\t\t\t\tasrt.Equal(\"10.0.0.5/8\", stringifyIPs(addrs))\n\t\t\tcase network.NodeAddressCurrentID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.0.0.5/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"10.0.0.5/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n\n\t// add another address which is \"smaller\", but default address shouldn't change\n\tsuite.newAddress(netip.MustParsePrefix(\"1.1.1.1/32\"), linkUp)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t}, func(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressDefaultID:\n\t\t\t\tasrt.Equal(\"10.0.0.5/8\", stringifyIPs(addrs))\n\t\t\tcase network.NodeAddressCurrentID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.1.1.1/32 10.0.0.5/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.1.1.1/32 10.0.0.5/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n\n\t// remove the previous default address, now default address should change\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(),\n\t\tnetwork.NewAddressStatus(network.NamespaceName, network.AddressID(linkUp.Metadata().ID(), netip.MustParsePrefix(\"10.0.0.5/8\"))).Metadata(),\n\t\tstate.WithDestroyOwner(addressStatusController.Name()),\n\t))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(),\n\t\t[]resource.ID{\n\t\t\tnetwork.NodeAddressDefaultID,\n\t\t\tnetwork.NodeAddressCurrentID,\n\t\t\tnetwork.NodeAddressAccumulativeID,\n\t\t}, func(r *network.NodeAddress, asrt *assert.Assertions) {\n\t\t\taddrs := r.TypedSpec().Addresses\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase network.NodeAddressDefaultID:\n\t\t\t\tasrt.Equal(\"1.1.1.1/32\", stringifyIPs(addrs))\n\t\t\tcase network.NodeAddressCurrentID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.1.1.1/32 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\tcase network.NodeAddressAccumulativeID:\n\t\t\t\tasrt.Equal(\n\t\t\t\t\t\"1.1.1.1/32 10.0.0.5/8 25.3.7.9/32\",\n\t\t\t\t\tstringifyIPs(addrs),\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc TestNodeAddressSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &NodeAddressSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.NodeAddressController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc stringifyIPs(ips []netip.Prefix) string {\n\treturn strings.Join(xslices.Map(ips, netip.Prefix.String), \" \")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/client_identifier.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage operator\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/insomniacslk/dhcp/dhcpv4\"\n\t\"github.com/insomniacslk/dhcp/dhcpv6\"\n\t\"github.com/insomniacslk/dhcp/iana\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// GetDHCPv6ClientIdentifier returns the DHCPv6 client identifier to use.\nfunc GetDHCPv6ClientIdentifier(ctx context.Context, st state.State, logger *zap.Logger, linkName string, spec network.ClientIdentifierSpec) ([]dhcpv6.Modifier, error) {\n\tswitch spec.ClientIdentifier {\n\tcase nethelpers.ClientIdentifierNone:\n\t\treturn nil, nil //nolint:nilerr\n\tcase nethelpers.ClientIdentifierMAC:\n\t\tlink, err := safe.StateGetByID[*network.LinkStatus](ctx, st, linkName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error getting link %q: %w\", linkName, err)\n\t\t}\n\n\t\tif len(link.TypedSpec().HardwareAddr) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"link %q has no hardware address\", linkName)\n\t\t}\n\n\t\tduid := dhcpv6.DUIDLL{\n\t\t\tHWType:        iana.HWTypeEthernet,\n\t\t\tLinkLayerAddr: net.HardwareAddr(link.TypedSpec().HardwareAddr),\n\t\t}\n\n\t\treturn []dhcpv6.Modifier{dhcpv6.WithClientID(&duid)}, nil\n\tcase nethelpers.ClientIdentifierDUID:\n\t\tif spec.DUIDRawHex == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"duidRawHex must be set when clientIdentifier is DUID\")\n\t\t}\n\n\t\tduidBin, err := hex.DecodeString(spec.DUIDRawHex)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to parse DUID, ignored\", zap.String(\"link\", linkName))\n\n\t\t\treturn nil, nil //nolint:nilerr\n\t\t}\n\n\t\tduid, err := dhcpv6.DUIDFromBytes(duidBin)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to parse DUID, ignored\", zap.String(\"link\", linkName))\n\n\t\t\treturn nil, nil //nolint:nilerr\n\t\t}\n\n\t\treturn []dhcpv6.Modifier{dhcpv6.WithClientID(duid)}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown client identifier %d\", spec.ClientIdentifier)\n\t}\n}\n\n// GetDHCP4ClientIdentifier returns the DHCP client identifier to use.\nfunc GetDHCP4ClientIdentifier(ctx context.Context, st state.State, logger *zap.Logger, linkName string, spec network.ClientIdentifierSpec) ([]dhcpv4.Modifier, error) {\n\tswitch spec.ClientIdentifier {\n\tcase nethelpers.ClientIdentifierNone:\n\t\treturn nil, nil //nolint:nilerr\n\tcase nethelpers.ClientIdentifierMAC:\n\t\tlink, err := safe.StateGetByID[*network.LinkStatus](ctx, st, linkName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error getting link %q: %w\", linkName, err)\n\t\t}\n\n\t\tif len(link.TypedSpec().HardwareAddr) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"link %q has no hardware address\", linkName)\n\t\t}\n\n\t\t// per RFC 2132, section 9.14\n\t\tidentifier := append([]byte{byte(iana.HWTypeEthernet)}, link.TypedSpec().HardwareAddr...)\n\n\t\treturn []dhcpv4.Modifier{dhcpv4.WithOption(dhcpv4.OptClientIdentifier(identifier))}, nil\n\tcase nethelpers.ClientIdentifierDUID:\n\t\tif spec.DUIDRawHex == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"duidRawHex must be set when clientIdentifier is DUID\")\n\t\t}\n\n\t\tduidBin, err := hex.DecodeString(spec.DUIDRawHex)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to parse DUID, ignored\", zap.String(\"link\", linkName))\n\n\t\t\treturn nil, nil //nolint:nilerr\n\t\t}\n\n\t\t_, err = dhcpv6.DUIDFromBytes(duidBin)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to parse DUID, ignored\", zap.String(\"link\", linkName))\n\n\t\t\treturn nil, nil //nolint:nilerr\n\t\t}\n\n\t\treturn []dhcpv4.Modifier{dhcpv4.WithOption(dhcpv4.OptClientIdentifier(duidBin))}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown client identifier %d\", spec.ClientIdentifier)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/dhcp4.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage operator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/insomniacslk/dhcp/dhcpv4\"\n\t\"github.com/insomniacslk/dhcp/dhcpv4/nclient4\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\t\"go4.org/netipx\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DHCP4 implements the DHCPv4 network operator.\ntype DHCP4 struct {\n\tlogger *zap.Logger\n\tstate  state.State\n\n\tlinkName            string\n\trouteMetric         uint32\n\tclientIdentifier    network.ClientIdentifierSpec\n\tskipHostnameRequest bool\n\trequestMTU          bool\n\n\tlease *nclient4.Lease\n\n\tmu          sync.Mutex\n\taddresses   []network.AddressSpecSpec\n\tlinks       []network.LinkSpecSpec\n\troutes      []network.RouteSpecSpec\n\thostname    []network.HostnameSpecSpec\n\tresolvers   []network.ResolverSpecSpec\n\ttimeservers []network.TimeServerSpecSpec\n}\n\n// NewDHCP4 creates DHCPv4 operator.\nfunc NewDHCP4(logger *zap.Logger, linkName string, config network.DHCP4OperatorSpec, platform runtime.Platform, state state.State) *DHCP4 {\n\treturn &DHCP4{\n\t\tlogger:              logger,\n\t\tstate:               state,\n\t\tlinkName:            linkName,\n\t\trouteMetric:         config.RouteMetric,\n\t\tskipHostnameRequest: config.SkipHostnameRequest,\n\t\tclientIdentifier:    config.ClientIdentifier,\n\t\t// <3 azure\n\t\t// When including dhcp.OptionInterfaceMTU we don't get a dhcp offer back on azure.\n\t\t// So we'll need to explicitly exclude adding this option for azure.\n\t\trequestMTU: platform.Name() != \"azure\",\n\t}\n}\n\n// Prefix returns unique operator prefix which gets prepended to each spec.\nfunc (d *DHCP4) Prefix() string {\n\treturn fmt.Sprintf(\"dhcp4/%s\", d.linkName)\n}\n\n// extractHostname extracts a hostname from the given resource if it is a valid network.HostnameStatus.\nfunc extractHostname(res resource.Resource) network.HostnameStatusSpec {\n\tif res, ok := res.(*network.HostnameStatus); ok {\n\t\treturn *res.TypedSpec()\n\t}\n\n\treturn network.HostnameStatusSpec{}\n}\n\n// setupHostnameWatch returns the initial hostname and a channel that outputs all events related to hostname changes.\nfunc (d *DHCP4) setupHostnameWatch(ctx context.Context) (<-chan state.Event, error) {\n\thostnameWatchCh := make(chan state.Event)\n\tif err := d.state.Watch(ctx, resource.NewMetadata(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.HostnameStatusType,\n\t\tnetwork.HostnameID,\n\t\tresource.VersionUndefined,\n\t), hostnameWatchCh); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn hostnameWatchCh, nil\n}\n\n// knownHostname checks if the given hostname has been defined by this operator.\nfunc (d *DHCP4) knownHostname(hostname network.HostnameStatusSpec) bool {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\tfor i := range d.hostname {\n\t\tif d.hostname[i].FQDN() == hostname.FQDN() {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// waitForNetworkReady waits for the network to be ready and the leased address to\n// be assigned to the associated so that unicast operations can bind successfully.\nfunc (d *DHCP4) waitForNetworkReady(ctx context.Context) error {\n\t// If an IP address has been registered, wait for the address association to be ready\n\tif addresses := d.AddressSpecs(); len(addresses) > 0 {\n\t\t_, err := d.state.WatchFor(ctx,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.AddressStatusType,\n\t\t\t\tnetwork.AddressID(d.linkName, addresses[0].Address),\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t\tstate.WithPhases(resource.PhaseRunning),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to wait for the address association to be ready: %w\", err)\n\t\t}\n\t}\n\n\t// Wait for the network (address and connectivity) to be ready\n\tif err := network.NewReadyCondition(d.state, network.AddressReady, network.ConnectivityReady).Wait(ctx); err != nil {\n\t\treturn fmt.Errorf(\"failed to wait for the network address and connectivity to be ready: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Run the operator loop.\n//\n//nolint:gocyclo,cyclop\nfunc (d *DHCP4) Run(ctx context.Context, notifyCh chan<- struct{}) {\n\tconst minRenewDuration = 5 * time.Second // Protect from renewing too often\n\n\tdhcpStartTime := time.Now() // Time when client began address acquisition or renewal process\n\trenewInterval := minRenewDuration\n\n\t// Never send the hostname on the first iteration, to have a chance to query the hostname from the DHCP server.\n\t// If the DHCP server doesn't provide a hostname, or if the hostname is overridden e.g. via machine config.\n\t// we'll restart the sequence and send the hostname.\n\tvar hostname network.HostnameStatusSpec\n\n\thostnameWatchCh, err := d.setupHostnameWatch(ctx)\n\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\td.logger.Warn(\"failed to watch for hostname changes\", zap.Error(err))\n\t}\n\n\tfor {\n\t\t// Track if we need to acquire a new lease\n\t\tnewLease := d.lease == nil\n\n\t\t// Perform a lease request or renewal\n\t\tleaseTime, err := d.requestRenew(ctx, hostname, uint16(time.Since(dhcpStartTime).Seconds()))\n\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\td.logger.Warn(\"DHCP request/renew failed\", zap.Error(err), zap.String(\"link\", d.linkName))\n\t\t}\n\n\t\tif err == nil {\n\t\t\t// Notify the underlying controller about the new lease\n\t\t\tif !channel.SendWithContext(ctx, notifyCh, struct{}{}) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif newLease {\n\t\t\t\t// Wait for networking to be established before transitioning to unicast operations\n\t\t\t\tif err = d.waitForNetworkReady(ctx); err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\t\td.logger.Warn(\"failed to wait for networking to become ready\", zap.Error(err))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif leaseTime > 0 {\n\t\t\trenewInterval = leaseTime / 2\n\t\t} else {\n\t\t\trenewInterval /= 2\n\t\t}\n\n\t\trenewInterval = max(renewInterval, minRenewDuration)\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase <-time.After(renewInterval):\n\t\t\t\tif leaseTime != 0 {\n\t\t\t\t\t// set the dhcpStartTime as the process of renewal has begun.\n\t\t\t\t\tdhcpStartTime = time.Now()\n\t\t\t\t}\n\t\t\tcase event := <-hostnameWatchCh:\n\t\t\t\t// Attempt to drain the hostname watch channel coalescing multiple events into a single\n\t\t\t\t// change to the DHCP.\n\t\t\tdrainLoop:\n\t\t\t\tfor {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase event = <-hostnameWatchCh:\n\t\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\t\treturn\n\t\t\t\t\tcase <-time.After(time.Second):\n\t\t\t\t\t\tbreak drainLoop\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If the hostname resource was deleted entirely, we must still inform the DHCP\n\t\t\t\t// server that the node has no hostname anymore. `extractHostname` will return a\n\t\t\t\t// blank hostname for a Tombstone resource generated by a deletion event.\n\t\t\t\toldHostname := hostname\n\t\t\t\thostname = extractHostname(event.Resource)\n\n\t\t\t\td.logger.Debug(\"detected hostname change\",\n\t\t\t\t\tzap.String(\"old\", oldHostname.FQDN()),\n\t\t\t\t\tzap.String(\"new\", hostname.FQDN()),\n\t\t\t\t)\n\n\t\t\t\t// If, on first invocation, the DHCP server has given a new hostname for the node,\n\t\t\t\t// and the `network.HostnameSpecController` decides to apply it as a preferred\n\t\t\t\t// hostname, this operator would unnecessarily drop the lease and restart DHCP\n\t\t\t\t// discovery. Thus, if the selected hostname has been sourced from this operator,\n\t\t\t\t// we don't need to do anything.\n\t\t\t\tif (oldHostname == network.HostnameStatusSpec{} && d.knownHostname(hostname)) || oldHostname == hostname {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// While updating the hostname together with a RENEW request works with dnsmasq, it\n\t\t\t\t// doesn't work with the Windows Server DHCP + DNS. A hostname update via an\n\t\t\t\t// INIT-REBOOT request also gets ignored. Thus, the only reliable way to update the\n\t\t\t\t// hostname seems to be to forget the old release and initiate a new DISCOVER flow\n\t\t\t\t// with the new hostname. RFC 2131 doesn't define any better way to do this, and,\n\t\t\t\t// as a DISCOVER request cannot be targeted at the previous lessor according to the\n\t\t\t\t// spec, the node may switch DHCP servers on hostname change. However, this is not\n\t\t\t\t// a major concern, since a single network should not host multiple competing DHCP\n\t\t\t\t// servers in the first place.\n\t\t\t\td.lease = nil\n\n\t\t\t\td.logger.Debug(\"restarting DHCP sequence due to hostname change\",\n\t\t\t\t\tzap.Strings(\"dhcp_hostname\", xslices.Map(d.HostnameSpecs(), func(spec network.HostnameSpecSpec) string {\n\t\t\t\t\t\treturn spec.Hostname\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t// set the dhcpStartTime as the DHCP sequence has begun.\n\t\t\t\tdhcpStartTime = time.Now()\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// AddressSpecs implements Operator interface.\nfunc (d *DHCP4) AddressSpecs() []network.AddressSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.addresses\n}\n\n// LinkSpecs implements Operator interface.\nfunc (d *DHCP4) LinkSpecs() []network.LinkSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.links\n}\n\n// RouteSpecs implements Operator interface.\nfunc (d *DHCP4) RouteSpecs() []network.RouteSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.routes\n}\n\n// HostnameSpecs implements Operator interface.\nfunc (d *DHCP4) HostnameSpecs() []network.HostnameSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.hostname\n}\n\n// ResolverSpecs implements Operator interface.\nfunc (d *DHCP4) ResolverSpecs() []network.ResolverSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.resolvers\n}\n\n// TimeServerSpecs implements Operator interface.\nfunc (d *DHCP4) TimeServerSpecs() []network.TimeServerSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.timeservers\n}\n\n//nolint:gocyclo\nfunc (d *DHCP4) parseNetworkConfigFromAck(ack *dhcpv4.DHCPv4, useHostname bool) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\taddr, _ := netipx.FromStdIPNet(&net.IPNet{\n\t\tIP:   ack.YourIPAddr,\n\t\tMask: ack.SubnetMask(),\n\t})\n\n\td.addresses = []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:     addr,\n\t\t\tLinkName:    d.linkName,\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tPriority:    d.routeMetric,\n\t\t\tConfigLayer: network.ConfigOperator,\n\t\t},\n\t}\n\n\tmtu, err := dhcpv4.GetUint16(dhcpv4.OptionInterfaceMTU, ack.Options)\n\tif err == nil {\n\t\td.links = []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName: d.linkName,\n\t\t\t\tMTU:  uint32(mtu),\n\t\t\t\tUp:   true,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.links = nil\n\t}\n\n\t// rfc3442:\n\t//   If the DHCP server returns both a Classless Static Routes option and\n\t//   a Router option, the DHCP client MUST ignore the Router option.\n\td.routes = nil\n\n\tif len(ack.ClasslessStaticRoute()) > 0 {\n\t\tfor _, route := range ack.ClasslessStaticRoute() {\n\t\t\tgw, _ := netipx.FromStdIP(route.Router)\n\t\t\tdst, _ := netipx.FromStdIPNet(route.Dest)\n\n\t\t\td.routes = append(d.routes, network.RouteSpecSpec{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tDestination: dst,\n\t\t\t\tSource:      addr.Addr(),\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: d.linkName,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tPriority:    d.routeMetric,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t})\n\t\t}\n\t} else {\n\t\tfor _, router := range ack.Router() {\n\t\t\tgw, _ := netipx.FromStdIP(router)\n\n\t\t\td.routes = append(d.routes, network.RouteSpecSpec{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tGateway:     gw,\n\t\t\t\tSource:      addr.Addr(),\n\t\t\t\tOutLinkName: d.linkName,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tPriority:    d.routeMetric,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t})\n\n\t\t\tif !addr.Contains(gw) {\n\t\t\t\t// Add an interface route for the gateway if it's not in the same network\n\t\t\t\td.routes = append(d.routes, network.RouteSpecSpec{\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tDestination: netip.PrefixFrom(gw, gw.BitLen()),\n\t\t\t\t\tSource:      addr.Addr(),\n\t\t\t\t\tOutLinkName: d.linkName,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tPriority:    d.routeMetric,\n\t\t\t\t\tScope:       nethelpers.ScopeLink,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tfor i := range d.routes {\n\t\td.routes[i].Normalize()\n\t}\n\n\tif useHostname {\n\t\td.hostname = nil\n\n\t\thostname := strings.TrimRight(ack.HostName(), \"\\x00\")\n\n\t\tif hostname != \"\" {\n\t\t\tspec := network.HostnameSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t}\n\n\t\t\tif err := spec.ParseFQDN(hostname); err == nil {\n\t\t\t\tdomainName := strings.TrimRight(ack.DomainName(), \"\\x00\")\n\n\t\t\t\tif domainName != \"\" {\n\t\t\t\t\tspec.Domainname = domainName\n\t\t\t\t}\n\n\t\t\t\td.hostname = []network.HostnameSpecSpec{\n\t\t\t\t\tspec,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(ack.DNS()) > 0 {\n\t\tconvertIP := func(ip net.IP) netip.Addr {\n\t\t\tresult, _ := netipx.FromStdIP(ip)\n\n\t\t\treturn result\n\t\t}\n\n\t\td.resolvers = []network.ResolverSpecSpec{\n\t\t\t{\n\t\t\t\tDNSServers:  xslices.Map(ack.DNS(), convertIP),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.resolvers = nil\n\t}\n\n\tif len(ack.NTPServers()) > 0 {\n\t\tconvertIP := func(ip net.IP) string {\n\t\t\tresult, _ := netipx.FromStdIP(ip)\n\n\t\t\treturn result.String()\n\t\t}\n\n\t\td.timeservers = []network.TimeServerSpecSpec{\n\t\t\t{\n\t\t\t\tNTPServers:  xslices.Map(ack.NTPServers(), convertIP),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.timeservers = nil\n\t}\n}\n\nfunc (d *DHCP4) newClient() (*nclient4.Client, error) {\n\tvar clientOpts []nclient4.ClientOpt\n\n\t// We have an existing lease, target the server with unicast.\n\tif d.lease != nil && d.lease.ACK.ServerIdentifier() != nil {\n\t\t// RFC 2131, section 4.3.2:\n\t\t//     DHCPREQUEST generated during RENEWING state:\n\t\t//     ... This message will be unicast, so no relay\n\t\t//     agents will be involved in its transmission.\n\t\tclientOpts = append(clientOpts,\n\t\t\tnclient4.WithServerAddr(&net.UDPAddr{\n\t\t\t\tIP:   d.lease.ACK.ServerIdentifier(),\n\t\t\t\tPort: nclient4.ServerPort,\n\t\t\t}),\n\t\t\t// WithUnicast must be specified manually, WithServerAddr is not enough\n\t\t\tnclient4.WithUnicast(&net.UDPAddr{\n\t\t\t\tIP:   d.lease.ACK.YourIPAddr,\n\t\t\t\tPort: nclient4.ClientPort,\n\t\t\t}),\n\t\t)\n\t}\n\n\t// Create a new client, the caller is responsible for closing it\n\treturn nclient4.New(d.linkName, clientOpts...)\n}\n\n//nolint:gocyclo\nfunc (d *DHCP4) requestRenew(ctx context.Context, hostname network.HostnameStatusSpec, secs uint16) (time.Duration, error) {\n\topts := []dhcpv4.OptionCode{\n\t\tdhcpv4.OptionClasslessStaticRoute,\n\t\tdhcpv4.OptionDomainNameServer,\n\t\t// TODO(twelho): This is unused until network.ResolverSpec supports search domains\n\t\tdhcpv4.OptionDNSDomainSearchList,\n\t\tdhcpv4.OptionNTPServers,\n\t}\n\n\tif d.requestMTU {\n\t\topts = append(opts, dhcpv4.OptionInterfaceMTU)\n\t}\n\n\tsendHostnameRequest := !d.skipHostnameRequest\n\tif hostname.Hostname != \"\" && !d.knownHostname(hostname) {\n\t\t// If we are supposed to publish a hostname, don't request one from the DHCP server.\n\t\t//\n\t\t// DHCP hostname parroting protection: if, e.g., `dnsmasq` receives a request that both\n\t\t// sends a hostname and requests one, it will \"parrot\" the sent hostname back if no other\n\t\t// name has been defined for the requesting host. This causes update anomalies, since\n\t\t// removing a hostname defined previously by, e.g., the configuration layer, causes a copy\n\t\t// of that hostname to live on in a spec defined by this operator, even though it isn't\n\t\t// sourced from DHCP.\n\t\t//\n\t\t// To avoid this issue, never send and request a hostname in the same operation. When\n\t\t// negotiating a new lease, first send the current hostname when acquiring the lease, and\n\t\t// then follow up with a dedicated INFORM request asking the server for a DHCP-defined\n\t\t// hostname. When renewing a lease, we're free to always request a hostname with an INFORM\n\t\t// (to detect server-side changes), since any changes to the node hostname will cause a\n\t\t// lease invalidation and re-start the negotiation process. More details below.\n\t\tsendHostnameRequest = false\n\t}\n\n\tif sendHostnameRequest {\n\t\topts = append(opts, dhcpv4.OptionHostName, dhcpv4.OptionDomainName)\n\t}\n\n\tmods := []dhcpv4.Modifier{dhcpv4.WithRequestedOptions(opts...), WithNumSeconds(secs)}\n\n\tif !sendHostnameRequest {\n\t\t// If the node has a hostname, always send it to the DHCP\n\t\t// server with option 12 during lease acquisition and renewal\n\t\tif len(hostname.Hostname) > 0 {\n\t\t\tmods = append(mods, dhcpv4.WithOption(dhcpv4.OptHostName(hostname.Hostname)))\n\t\t}\n\n\t\tif len(hostname.Domainname) > 0 {\n\t\t\tmods = append(mods, dhcpv4.WithOption(dhcpv4.OptDomainName(hostname.Domainname)))\n\t\t}\n\t}\n\n\tclientIdentifierModes, err := GetDHCP4ClientIdentifier(ctx, d.state, d.logger, d.linkName, d.clientIdentifier)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to get client identifier: %w\", err)\n\t}\n\n\tmods = append(mods, clientIdentifierModes...)\n\n\tclient, err := d.newClient()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\taddresses := d.AddressSpecs()\n\n\tswitch {\n\tcase d.lease != nil && d.lease.ACK.ServerIdentifier() != nil:\n\t\td.logger.Debug(\"DHCP RENEW\", zap.String(\"link\", d.linkName))\n\t\td.lease, err = client.Renew(ctx, d.lease, mods...)\n\tcase d.lease != nil && d.lease.Offer != nil:\n\t\td.logger.Debug(\"DHCP REQUEST FROM OFFER\", zap.String(\"link\", d.linkName))\n\t\td.lease, err = client.RequestFromOffer(ctx, d.lease.Offer, mods...)\n\tcase len(addresses) >= 1:\n\t\tpreviousIPAddress := net.IP(addresses[0].Address.Addr().AsSlice())\n\n\t\td.logger.Debug(\"DHCP REQUEST with previous IP\", zap.String(\"link\", d.linkName), zap.Stringer(\"previous_ip\", previousIPAddress))\n\n\t\td.lease, err = client.Request(ctx, dhcpv4.PrependModifiers(mods,\n\t\t\tdhcpv4.WithOption(dhcpv4.OptRequestedIPAddress(previousIPAddress)),\n\t\t)...)\n\tdefault:\n\t\td.logger.Debug(\"DHCP REQUEST\", zap.String(\"link\", d.linkName))\n\t\td.lease, err = client.Request(ctx, mods...)\n\t}\n\n\tif err != nil {\n\t\t// explicitly clear the lease on failure to start with the discovery sequence next time\n\t\td.lease = nil\n\n\t\treturn 0, err\n\t}\n\n\td.logger.Debug(\"DHCP ACK\", zap.String(\"link\", d.linkName), zap.String(\"dhcp\", collapseSummary(d.lease.ACK.Summary())))\n\n\td.parseNetworkConfigFromAck(d.lease.ACK, sendHostnameRequest)\n\n\treturn d.lease.ACK.IPAddressLeaseTime(time.Minute * 30), nil\n}\n\nfunc collapseSummary(summary string) string {\n\tlines := strings.Split(summary, \"\\n\")[1:]\n\n\tfor i := range lines {\n\t\tlines[i] = strings.TrimSpace(lines[i])\n\t}\n\n\tif len(lines) > 0 && lines[len(lines)-1] == \"\" {\n\t\tlines = lines[:len(lines)-1]\n\t}\n\n\treturn strings.Join(lines, \", \")\n}\n\n// WithNumSeconds sets the secs field of a DHCPv4 packet.\nfunc WithNumSeconds(secs uint16) dhcpv4.Modifier {\n\treturn func(d *dhcpv4.DHCPv4) {\n\t\td.NumSeconds = secs\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/dhcp6.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage operator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/insomniacslk/dhcp/dhcpv6\"\n\t\"github.com/insomniacslk/dhcp/dhcpv6/nclient6\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.uber.org/zap\"\n\t\"go4.org/netipx\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// DHCP6 implements the DHCPv6 network operator.\ntype DHCP6 struct {\n\tlogger *zap.Logger\n\tstate  state.State\n\n\tlinkName            string\n\tclientIdentifier    network.ClientIdentifierSpec\n\tskipHostnameRequest bool\n\n\tmu          sync.Mutex\n\taddresses   []network.AddressSpecSpec\n\thostname    []network.HostnameSpecSpec\n\tresolvers   []network.ResolverSpecSpec\n\ttimeservers []network.TimeServerSpecSpec\n}\n\n// NewDHCP6 creates DHCPv6 operator.\nfunc NewDHCP6(logger *zap.Logger, linkName string, config network.DHCP6OperatorSpec, state state.State) *DHCP6 {\n\treturn &DHCP6{\n\t\tlogger:              logger,\n\t\tstate:               state,\n\t\tlinkName:            linkName,\n\t\tclientIdentifier:    config.ClientIdentifier,\n\t\tskipHostnameRequest: config.SkipHostnameRequest,\n\t}\n}\n\n// Prefix returns unique operator prefix which gets prepended to each spec.\nfunc (d *DHCP6) Prefix() string {\n\treturn fmt.Sprintf(\"dhcp6/%s\", d.linkName)\n}\n\n// Run the operator loop.\n//\n//nolint:gocyclo\nfunc (d *DHCP6) Run(ctx context.Context, notifyCh chan<- struct{}) {\n\tiface, err := net.InterfaceByName(d.linkName)\n\tif err != nil {\n\t\td.logger.Warn(\"link not found\", zap.String(\"link\", d.linkName))\n\t} else if err = d.waitIPv6LinkReady(ctx, iface); err != nil {\n\t\td.logger.Warn(\"error waiting for IPv6 ready\", zap.Error(err), zap.String(\"link\", d.linkName))\n\t}\n\n\tconst minRenewDuration = 5 * time.Second // protect from renewing too often\n\n\trenewInterval := minRenewDuration\n\n\tfor {\n\t\tleaseTime, err := d.renew(ctx)\n\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\td.logger.Warn(\"renew failed\", zap.Error(err), zap.String(\"link\", d.linkName))\n\t\t}\n\n\t\tif err == nil {\n\t\t\tselect {\n\t\t\tcase notifyCh <- struct{}{}:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif leaseTime > 0 {\n\t\t\trenewInterval = leaseTime / 2\n\t\t} else {\n\t\t\trenewInterval /= 2\n\t\t}\n\n\t\trenewInterval = max(renewInterval, minRenewDuration)\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-time.After(renewInterval):\n\t\t}\n\t}\n}\n\n// AddressSpecs implements Operator interface.\nfunc (d *DHCP6) AddressSpecs() []network.AddressSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.addresses\n}\n\n// LinkSpecs implements Operator interface.\nfunc (d *DHCP6) LinkSpecs() []network.LinkSpecSpec {\n\treturn nil\n}\n\n// RouteSpecs implements Operator interface.\nfunc (d *DHCP6) RouteSpecs() []network.RouteSpecSpec {\n\treturn nil\n}\n\n// HostnameSpecs implements Operator interface.\nfunc (d *DHCP6) HostnameSpecs() []network.HostnameSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.hostname\n}\n\n// ResolverSpecs implements Operator interface.\nfunc (d *DHCP6) ResolverSpecs() []network.ResolverSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.resolvers\n}\n\n// TimeServerSpecs implements Operator interface.\nfunc (d *DHCP6) TimeServerSpecs() []network.TimeServerSpecSpec {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\treturn d.timeservers\n}\n\nfunc (d *DHCP6) parseReply(reply *dhcpv6.Message) (leaseTime time.Duration) {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\tif reply.Options.OneIANA() != nil && reply.Options.OneIANA().Options.OneAddress() != nil {\n\t\taddr, _ := netipx.FromStdIPNet(&net.IPNet{\n\t\t\tIP:   reply.Options.OneIANA().Options.OneAddress().IPv6Addr,\n\t\t\tMask: net.CIDRMask(128, 128),\n\t\t})\n\n\t\td.addresses = []network.AddressSpecSpec{\n\t\t\t{\n\t\t\t\tAddress:     addr,\n\t\t\t\tLinkName:    d.linkName,\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\n\t\tleaseTime = reply.Options.OneIANA().Options.OneAddress().ValidLifetime\n\t} else {\n\t\td.addresses = nil\n\t}\n\n\tif len(reply.Options.DNS()) > 0 {\n\t\tconvertIP := func(ip net.IP) netip.Addr {\n\t\t\tresult, _ := netipx.FromStdIP(ip)\n\n\t\t\treturn result\n\t\t}\n\n\t\td.resolvers = []network.ResolverSpecSpec{\n\t\t\t{\n\t\t\t\tDNSServers:  xslices.Map(reply.Options.DNS(), convertIP),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.resolvers = nil\n\t}\n\n\tif reply.Options.FQDN() != nil && len(reply.Options.FQDN().DomainName.Labels) > 0 && !d.skipHostnameRequest {\n\t\td.hostname = []network.HostnameSpecSpec{\n\t\t\t{\n\t\t\t\tHostname:    reply.Options.FQDN().DomainName.Labels[0],\n\t\t\t\tDomainname:  strings.Join(reply.Options.FQDN().DomainName.Labels[1:], \".\"),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.hostname = nil\n\t}\n\n\tif len(reply.Options.NTPServers()) > 0 {\n\t\tconvertIP := func(ip net.IP) string {\n\t\t\tresult, _ := netipx.FromStdIP(ip)\n\n\t\t\treturn result.String()\n\t\t}\n\n\t\td.timeservers = []network.TimeServerSpecSpec{\n\t\t\t{\n\t\t\t\tNTPServers:  xslices.Map(reply.Options.NTPServers(), convertIP),\n\t\t\t\tConfigLayer: network.ConfigOperator,\n\t\t\t},\n\t\t}\n\t} else {\n\t\td.timeservers = nil\n\t}\n\n\treturn leaseTime\n}\n\nfunc (d *DHCP6) renew(ctx context.Context) (time.Duration, error) {\n\tcli, err := nclient6.New(d.linkName)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tdefer cli.Close() //nolint:errcheck\n\n\tclientIdentifierModifiers, err := GetDHCPv6ClientIdentifier(ctx, d.state, d.logger, d.linkName, d.clientIdentifier)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"error getting DHCPv6 client identifier: %w\", err)\n\t}\n\n\treply, err := cli.RapidSolicit(ctx, clientIdentifierModifiers...)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\td.logger.Debug(\"DHCP6 REPLY\", zap.String(\"link\", d.linkName), zap.String(\"dhcp\", collapseSummary(reply.Summary())))\n\n\treturn d.parseReply(reply), nil\n}\n\nfunc (d *DHCP6) waitIPv6LinkReady(ctx context.Context, iface *net.Interface) error {\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\treturn retry.Constant(30*time.Second, retry.WithUnits(100*time.Millisecond)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tready, err := d.isIPv6LinkReady(iface, conn)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !ready {\n\t\t\treturn retry.ExpectedErrorf(\"IPv6 address is still tentative\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// isIPv6LinkReady returns true if the interface has a link-local address\n// which is not tentative.\nfunc (d *DHCP6) isIPv6LinkReady(iface *net.Interface, conn *rtnetlink.Conn) (bool, error) {\n\taddrs, err := conn.Address.List()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tfor _, addr := range addrs {\n\t\tif addr.Index != uint32(iface.Index) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif addr.Family != unix.AF_INET6 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif addr.Attributes.Address.IsLinkLocalUnicast() && (addr.Flags&unix.IFA_F_TENTATIVE == 0) {\n\t\t\tif addr.Flags&unix.IFA_F_DADFAILED != 0 {\n\t\t\t\td.logger.Warn(\"DADFAILED for %v, continuing anyhow\", zap.Stringer(\"address\", addr.Attributes.Address), zap.String(\"link\", d.linkName))\n\t\t\t}\n\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/operator.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package operator implements network operators.\npackage operator\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// Operator describes common interface of the operators.\ntype Operator interface {\n\tRun(ctx context.Context, notifyCh chan<- struct{})\n\n\tPrefix() string\n\n\tAddressSpecs() []network.AddressSpecSpec\n\tRouteSpecs() []network.RouteSpecSpec\n\tLinkSpecs() []network.LinkSpecSpec\n\n\tHostnameSpecs() []network.HostnameSpecSpec\n\tResolverSpecs() []network.ResolverSpecSpec\n\tTimeServerSpecs() []network.TimeServerSpecSpec\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip/equinix_metal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vip\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path\"\n\n\t\"github.com/packethost/packngo\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EquinixMetalHandler implements assignment and release of Virtual IPs using API.\ntype EquinixMetalHandler struct {\n\tclient *packngo.Client\n\n\tlogger *zap.Logger\n\n\tvip       string\n\tprojectID string\n\tdeviceID  string\n\n\tassignmentID string\n}\n\n// NewEquinixMetalHandler creates new EquinixMetalHandler.\nfunc NewEquinixMetalHandler(logger *zap.Logger, vip string, spec network.VIPEquinixMetalSpec) *EquinixMetalHandler {\n\treturn &EquinixMetalHandler{\n\t\tclient: packngo.NewClientWithAuth(\"talos\", spec.APIToken, nil),\n\n\t\tlogger: logger,\n\n\t\tvip:       vip,\n\t\tprojectID: spec.ProjectID,\n\t\tdeviceID:  spec.DeviceID,\n\t}\n}\n\n// Acquire implements Handler interface.\nfunc (handler *EquinixMetalHandler) Acquire(ctx context.Context) error {\n\tips, _, err := handler.client.ProjectIPs.List(handler.projectID, &packngo.ListOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing project IPs: %w\", err)\n\t}\n\n\t// look up assignments for the VIP and unassign it\n\tfor _, ip := range ips {\n\t\tif ip.Address != handler.vip {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, assignment := range ip.Assignments {\n\t\t\tassignmentID := path.Base(assignment.Href)\n\n\t\t\tif _, err = handler.client.DeviceIPs.Unassign(assignmentID); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing assignment %s: %w\", assignment.String(), err)\n\t\t\t}\n\n\t\t\thandler.logger.Info(\"cleared previous Equinix Metal IP assignment\", zap.String(\"assignment\", assignmentID), zap.String(\"vip\", handler.vip))\n\t\t}\n\t}\n\n\t// assign the VIP to this device\n\tassignment, _, err := handler.client.DeviceIPs.Assign(handler.deviceID, &packngo.AddressStruct{\n\t\tAddress: handler.vip,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error assigning %q to %q: %w\", handler.vip, handler.deviceID, err)\n\t}\n\n\thandler.logger.Info(\"assigned Equinix Metal IP\", zap.String(\"vip\", handler.vip), zap.String(\"device_id\", handler.deviceID), zap.String(\"assignment\", assignment.ID))\n\thandler.assignmentID = assignment.ID\n\n\treturn nil\n}\n\n// Release implements Handler interface.\nfunc (handler *EquinixMetalHandler) Release(ctx context.Context) error {\n\tif handler.assignmentID == \"\" {\n\t\treturn nil\n\t}\n\n\t_, err := handler.client.DeviceIPs.Unassign(handler.assignmentID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error removing assignment %s: %w\", handler.assignmentID, err)\n\t}\n\n\thandler.logger.Info(\"unassigned Equinix Metal IP\", zap.String(\"assignment\", handler.assignmentID), zap.String(\"vip\", handler.vip))\n\n\treturn nil\n}\n\n// EquinixMetalMetaDataEndpoint is the local endpoint for machine info like networking.\nconst EquinixMetalMetaDataEndpoint = \"https://metadata.platformequinix.com/metadata\"\n\n// GetProjectAndDeviceIDs fills in parts of the spec based on the API token and instance metadata.\nfunc GetProjectAndDeviceIDs(ctx context.Context, spec *network.VIPEquinixMetalSpec) error {\n\tmetadataConfig, err := download.Download(ctx, EquinixMetalMetaDataEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error downloading metadata: %w\", err)\n\t}\n\n\ttype Metadata struct {\n\t\tID string `json:\"id\"`\n\t}\n\n\tvar unmarshalledMetadataConfig Metadata\n\tif err = json.Unmarshal(metadataConfig, &unmarshalledMetadataConfig); err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling metadata: %w\", err)\n\t}\n\n\tspec.DeviceID = unmarshalledMetadataConfig.ID\n\n\tclient := packngo.NewClientWithAuth(\"talos\", spec.APIToken, nil)\n\n\tdevice, _, err := client.Devices.Get(spec.DeviceID, &packngo.GetOptions{\n\t\tIncludes: []string{\"project\"},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting device: %w\", err)\n\t}\n\n\tspec.ProjectID = device.Project.ID\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip/equinix_metal_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vip_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/operator/vip\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestEquinixMetalHandler(t *testing.T) {\n\t// WARNING: this test requires interaction with Equinix Metal API with real device IDs and API token\n\t// it is skipped by default unless following variables are set:\n\t//   TALOS_EM_API_TOKEN\n\t//   TALOS_EM_PROJECT_ID\n\t//   TALOS_EM_DEVICE_ID_1\n\t//   TALOS_EM_DEVICE_ID_2\n\t//   TALOS_EM_VIP\n\tsettings := map[string]string{}\n\n\tfor _, variable := range []string{\n\t\t\"TALOS_EM_API_TOKEN\",\n\t\t\"TALOS_EM_PROJECT_ID\",\n\t\t\"TALOS_EM_DEVICE_ID_1\",\n\t\t\"TALOS_EM_DEVICE_ID_2\",\n\t\t\"TALOS_EM_VIP\",\n\t} {\n\t\tvar ok bool\n\n\t\tsettings[variable], ok = os.LookupEnv(variable)\n\n\t\tif !ok {\n\t\t\tt.Skip(\"skipping the test as the environment variable is not set\", variable)\n\t\t}\n\t}\n\n\tlogger := zaptest.NewLogger(t)\n\n\thandler1 := vip.NewEquinixMetalHandler(logger, settings[\"TALOS_EM_VIP\"], network.VIPEquinixMetalSpec{\n\t\tProjectID: settings[\"TALOS_EM_PROJECT_ID\"],\n\t\tDeviceID:  settings[\"TALOS_EM_DEVICE_ID_1\"],\n\t\tAPIToken:  settings[\"TALOS_EM_API_TOKEN\"],\n\t})\n\n\thandler2 := vip.NewEquinixMetalHandler(logger, settings[\"TALOS_EM_VIP\"], network.VIPEquinixMetalSpec{\n\t\tProjectID: settings[\"TALOS_EM_PROJECT_ID\"],\n\t\tDeviceID:  settings[\"TALOS_EM_DEVICE_ID_2\"],\n\t\tAPIToken:  settings[\"TALOS_EM_API_TOKEN\"],\n\t})\n\n\t// not graceful\n\trequire.NoError(t, handler1.Acquire(t.Context()))\n\trequire.NoError(t, handler2.Acquire(t.Context()))\n\n\t// graceful\n\trequire.NoError(t, handler1.Acquire(t.Context()))\n\trequire.NoError(t, handler1.Release(t.Context()))\n\trequire.NoError(t, handler2.Acquire(t.Context()))\n\trequire.NoError(t, handler2.Release(t.Context()))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip/hcloud.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vip\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\n\t\"github.com/hetznercloud/hcloud-go/v2/hcloud\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// HCloudHandler implements assignment and release of Virtual IPs using API.\ntype HCloudHandler struct {\n\tclient *hcloud.Client\n\n\tlogger *zap.Logger\n\n\tvip        string\n\tdeviceID   int64\n\tfloatingID int64\n\tnetworkID  int64\n}\n\n// NewHCloudHandler creates new NewEHCloudHandler.\nfunc NewHCloudHandler(logger *zap.Logger, vip string, spec network.VIPHCloudSpec) *HCloudHandler {\n\treturn &HCloudHandler{\n\t\tclient: hcloud.NewClient(\n\t\t\thcloud.WithToken(spec.APIToken),\n\t\t\thcloud.WithApplication(version.Name, version.Tag),\n\t\t),\n\n\t\tlogger: logger,\n\n\t\tvip:       vip,\n\t\tdeviceID:  spec.DeviceID,\n\t\tnetworkID: spec.NetworkID,\n\t}\n}\n\n// Acquire implements Handler interface.\nfunc (handler *HCloudHandler) Acquire(ctx context.Context) error {\n\tif handler.networkID > 0 {\n\t\tvar action *hcloud.Action\n\n\t\talias := hcloud.ServerChangeAliasIPsOpts{\n\t\t\tNetwork:  &hcloud.Network{ID: handler.networkID},\n\t\t\tAliasIPs: []net.IP{},\n\t\t}\n\n\t\t// trying to find the old active server\n\t\t// and remove alias IP from it\n\t\tserverList, err := handler.client.Server.All(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting server list: %w\", err)\n\t\t}\n\n\t\toldDeviceID := findServerByAlias(serverList, handler.networkID, handler.vip)\n\t\tif oldDeviceID != 0 {\n\t\t\thandler.logger.Info(\"trying to remove previous Hetzner Cloud IP alias\",\n\t\t\t\tzap.String(\"vip\", handler.vip), zap.Int64(\"device_id\", oldDeviceID),\n\t\t\t\tzap.Int64(\"network_id\", handler.networkID),\n\t\t\t)\n\n\t\t\taction, _, err = handler.client.Server.ChangeAliasIPs(ctx,\n\t\t\t\t&hcloud.Server{ID: oldDeviceID},\n\t\t\t\thcloud.ServerChangeAliasIPsOpts{\n\t\t\t\t\tNetwork:  &hcloud.Network{ID: handler.networkID},\n\t\t\t\t\tAliasIPs: []net.IP{},\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error remove Hetzner Cloud IP alias %q from server %d: %w\", handler.vip, oldDeviceID, err)\n\t\t\t}\n\n\t\t\thandler.logger.Info(\"cleared previous Hetzner Cloud IP alias\", zap.String(\"vip\", handler.vip),\n\t\t\t\tzap.Int64(\"device_id\", oldDeviceID), zap.String(\"status\", string(action.Status)))\n\t\t}\n\n\t\tnetIP := net.ParseIP(handler.vip)\n\t\talias.AliasIPs = []net.IP{netIP}\n\n\t\taction, _, err = handler.client.Server.ChangeAliasIPs(ctx,\n\t\t\t&hcloud.Server{ID: handler.deviceID},\n\t\t\talias)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error change alias IPs %q to server %d: %w\", handler.vip, handler.deviceID, err)\n\t\t}\n\n\t\thandler.logger.Info(\"assigned Hetzner Cloud IP alias\", zap.String(\"vip\", handler.vip), zap.Int64(\"device_id\", handler.deviceID),\n\t\t\tzap.Int64(\"network_id\", handler.networkID), zap.String(\"status\", string(action.Status)))\n\n\t\treturn nil\n\t}\n\n\tfloatips, err := handler.client.FloatingIP.All(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting floatingIPs list: %w\", err)\n\t}\n\n\tfor _, floatip := range floatips {\n\t\tif floatip.IP.String() == handler.vip {\n\t\t\taction, _, err := handler.client.FloatingIP.Assign(ctx, floatip, &hcloud.Server{ID: handler.deviceID})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error assigning %q on server %d: %w\", handler.vip, handler.deviceID, err)\n\t\t\t}\n\n\t\t\thandler.logger.Info(\"assigned Hetzner Cloud floating IP\", zap.String(\"vip\", handler.vip), zap.Int64(\"device_id\", handler.deviceID), zap.String(\"status\", string(action.Status)))\n\t\t\thandler.floatingID = floatip.ID\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"error assigning %q to server %d in network %d: floating IP / alias IP is not found\", handler.vip, handler.deviceID, handler.networkID)\n}\n\n// Release implements Handler interface.\nfunc (handler *HCloudHandler) Release(ctx context.Context) error {\n\tif handler.networkID > 0 {\n\t\talias := hcloud.ServerChangeAliasIPsOpts{\n\t\t\tNetwork:  &hcloud.Network{ID: handler.networkID},\n\t\t\tAliasIPs: []net.IP{},\n\t\t}\n\n\t\taction, _, err := handler.client.Server.ChangeAliasIPs(ctx,\n\t\t\t&hcloud.Server{ID: handler.deviceID},\n\t\t\talias)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error remove alias IPs %q on server %d: %w\", handler.vip, handler.deviceID, err)\n\t\t}\n\n\t\thandler.logger.Info(\"unassigned Hetzner Cloud alias IP\", zap.String(\"vip\", handler.vip), zap.Int64(\"device_id\", handler.deviceID),\n\t\t\tzap.Int64(\"network_id\", handler.networkID), zap.String(\"status\", string(action.Status)))\n\n\t\treturn nil\n\t}\n\n\tif handler.floatingID > 0 {\n\t\tfloatip, _, err := handler.client.FloatingIP.GetByID(ctx, handler.floatingID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting floatingIP info: %w\", err)\n\t\t}\n\n\t\tif floatip.Server == nil || floatip.Server.ID != handler.deviceID {\n\t\t\thandler.logger.Info(\"unassigned Hetzner Cloud floating IP\", zap.String(\"vip\", handler.vip), zap.Int64(\"device_id\", handler.deviceID))\n\t\t}\n\n\t\thandler.floatingID = 0\n\t}\n\n\treturn nil\n}\n\n// HCloudMetaDataEndpoint is the local endpoint for machine info like networking.\nconst HCloudMetaDataEndpoint = \"http://169.254.169.254/hetzner/v1/metadata/instance-id\"\n\n// GetNetworkAndDeviceIDs fills in parts of the spec based on the API token and instance metadata.\nfunc GetNetworkAndDeviceIDs(ctx context.Context, spec *network.VIPHCloudSpec, vip netip.Addr, logger *zap.Logger) error {\n\tmetadataInstanceID, err := download.Download(ctx, HCloudMetaDataEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error downloading instance-id: %w\", err)\n\t}\n\n\tspec.DeviceID, err = strconv.ParseInt(string(metadataInstanceID), 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting instance-id id: %w\", err)\n\t}\n\n\tclient := hcloud.NewClient(\n\t\thcloud.WithToken(spec.APIToken),\n\t\thcloud.WithApplication(version.Name, version.Tag),\n\t)\n\n\tserver, _, err := client.Server.GetByID(ctx, spec.DeviceID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting server info: %w\", err)\n\t}\n\n\tif vip.IsPrivate() {\n\t\t// find private network for private vip (alias IP)\n\t\tassignedPrivateNetworks := server.PrivateNet\n\t\tif len(assignedPrivateNetworks) == 0 {\n\t\t\treturn fmt.Errorf(\"trying to assign private vip (alias IP) %q, but no private network is assigned to the server\", vip.String())\n\t\t}\n\n\t\tfor _, assignedPrivateNetwork := range assignedPrivateNetworks {\n\t\t\tprivateNetwork, _, err := client.Network.GetByID(ctx, assignedPrivateNetwork.Network.ID)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting network info: %w\", err)\n\t\t\t}\n\n\t\t\tif privateNetwork.IPRange.Contains(vip.AsSlice()) {\n\t\t\t\tspec.NetworkID = assignedPrivateNetwork.Network.ID\n\t\t\t\tlogger.Info(\"found private network for private vip (alias IP)\", zap.String(\"vip\", vip.String()), zap.Int64(\"network_id\", spec.NetworkID))\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// the public vip (floating IP) doesn't require a private network\n\t\tspec.NetworkID = 0\n\t}\n\n\treturn nil\n}\n\nfunc findServerByAlias(serverList []*hcloud.Server, networkID int64, vip string) (deviceID int64) {\n\tfor _, server := range serverList {\n\t\tfor _, network := range server.PrivateNet {\n\t\t\tif network.Network.ID == networkID {\n\t\t\t\tfor _, alias := range network.Aliases {\n\t\t\t\t\tif alias.String() == vip {\n\t\t\t\t\t\treturn server.ID\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip/nop.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vip\n\nimport (\n\t\"context\"\n)\n\n// NopHandler does nothing.\ntype NopHandler struct{}\n\n// Acquire implements Handler interface.\nfunc (handler NopHandler) Acquire(ctx context.Context) error {\n\treturn nil\n}\n\n// Release implements Handler interface.\nfunc (handler NopHandler) Release(ctx context.Context) error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip/vip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vip contains implementations of specific methods to acquire/release virtual IPs.\npackage vip\n\nimport \"context\"\n\n// Handler implements custom actions to manage virtual IP assignment.\ntype Handler interface {\n\tAcquire(ctx context.Context) error\n\tRelease(ctx context.Context) error\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator/vip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage operator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.etcd.io/etcd/client/v3/concurrency\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/operator/vip\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nconst campaignRetryInterval = time.Second\n\n// VIP implements the Virtual (Shared) IP network operator.\ntype VIP struct {\n\tlogger *zap.Logger\n\n\tlinkName      string\n\tsharedIP      netip.Addr\n\tgratuitousARP bool\n\n\tstate state.State\n\n\tmu     sync.Mutex\n\tleader bool\n\n\thandler vip.Handler\n}\n\n// NewVIP creates Virtual IP operator.\nfunc NewVIP(logger *zap.Logger, linkName string, spec network.VIPOperatorSpec, state state.State) *VIP {\n\tvar handler vip.Handler\n\n\tswitch {\n\tcase spec.EquinixMetal != network.VIPEquinixMetalSpec{}:\n\t\thandler = vip.NewEquinixMetalHandler(logger, spec.IP.String(), spec.EquinixMetal)\n\tcase spec.HCloud != network.VIPHCloudSpec{}:\n\t\thandler = vip.NewHCloudHandler(logger, spec.IP.String(), spec.HCloud)\n\tdefault:\n\t\thandler = vip.NopHandler{}\n\t}\n\n\treturn &VIP{\n\t\tlogger:        logger,\n\t\tlinkName:      linkName,\n\t\tsharedIP:      spec.IP,\n\t\tgratuitousARP: spec.GratuitousARP,\n\t\tstate:         state,\n\t\thandler:       handler,\n\t}\n}\n\n// Prefix returns unique operator prefix which gets prepended to each spec.\nfunc (vip *VIP) Prefix() string {\n\treturn fmt.Sprintf(\"vip/%s\", vip.linkName)\n}\n\n// Run the operator loop.\nfunc (vip *VIP) Run(ctx context.Context, notifyCh chan<- struct{}) {\n\tfor {\n\t\terr := vip.campaign(ctx, notifyCh)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, context.Canceled) {\n\t\t\t\tvip.logger.Warn(\"campaign failure\", zap.Error(err), zap.String(\"link\", vip.linkName), zap.Stringer(\"ip\", vip.sharedIP))\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-time.After(campaignRetryInterval):\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// AddressSpecs implements Operator interface.\nfunc (vip *VIP) AddressSpecs() []network.AddressSpecSpec {\n\tvip.mu.Lock()\n\tdefer vip.mu.Unlock()\n\n\tif !vip.leader {\n\t\treturn nil\n\t}\n\n\tfamily := nethelpers.FamilyInet6\n\tgratuitousARP := false\n\n\tif vip.sharedIP.Is4() {\n\t\tfamily = nethelpers.FamilyInet4\n\t\tgratuitousARP = vip.gratuitousARP\n\t}\n\n\treturn []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:         netip.PrefixFrom(vip.sharedIP, vip.sharedIP.BitLen()),\n\t\t\tLinkName:        vip.linkName,\n\t\t\tFamily:          family,\n\t\t\tScope:           nethelpers.ScopeGlobal,\n\t\t\tFlags:           nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tAnnounceWithARP: gratuitousARP,\n\t\t\tConfigLayer:     network.ConfigOperator,\n\t\t},\n\t}\n}\n\n// LinkSpecs implements Operator interface.\nfunc (vip *VIP) LinkSpecs() []network.LinkSpecSpec {\n\treturn nil\n}\n\n// RouteSpecs implements Operator interface.\nfunc (vip *VIP) RouteSpecs() []network.RouteSpecSpec {\n\treturn nil\n}\n\n// HostnameSpecs implements Operator interface.\nfunc (vip *VIP) HostnameSpecs() []network.HostnameSpecSpec {\n\treturn nil\n}\n\n// ResolverSpecs implements Operator interface.\nfunc (vip *VIP) ResolverSpecs() []network.ResolverSpecSpec {\n\treturn nil\n}\n\n// TimeServerSpecs implements Operator interface.\nfunc (vip *VIP) TimeServerSpecs() []network.TimeServerSpecSpec {\n\treturn nil\n}\n\nfunc (vip *VIP) etcdElectionKey() string {\n\treturn fmt.Sprintf(\"%s:vip:election:%s\", constants.EtcdRootTalosKey, vip.sharedIP.String())\n}\n\nfunc (vip *VIP) waitForPreconditions(ctx context.Context) error {\n\t//  wait for the etcd to be up\n\t_, err := vip.state.WatchFor(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, \"etcd\", resource.VersionUndefined),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tsvc := r.(*v1alpha1.Service) //nolint:forcetypeassert\n\n\t\t\treturn svc.TypedSpec().Running && svc.TypedSpec().Healthy, nil\n\t\t}))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"etcd health wait failure: %w\", err)\n\t}\n\n\t// wait for the kubelet lifecycle to be up, and not being torn down\n\t_, err = vip.state.WatchFor(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletLifecycleType, k8s.KubeletLifecycleID, resource.VersionUndefined),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tif r.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn true, nil\n\t\t}))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kubelet lifecycle wait failure: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (vip *VIP) campaign(ctx context.Context, notifyCh chan<- struct{}) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tif err := vip.waitForPreconditions(ctx); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for preconditions: %w\", err)\n\t}\n\n\t// put a finalizer on the kubelet lifecycle and remove once the campaign is done\n\tkubeletLifecycle := resource.NewMetadata(k8s.NamespaceName, k8s.KubeletLifecycleType, k8s.KubeletLifecycleID, resource.VersionUndefined)\n\tif err := vip.state.AddFinalizer(ctx, kubeletLifecycle, vip.Prefix()); err != nil {\n\t\treturn fmt.Errorf(\"error adding kubelet lifecycle finalizer: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tvip.state.RemoveFinalizer(ctx, kubeletLifecycle, vip.Prefix()) //nolint:errcheck\n\t}()\n\n\thostname, err := os.Hostname() // TODO: this should be etcd nodename\n\tif err != nil {\n\t\treturn errors.New(\"refusing to join election without a hostname\")\n\t}\n\n\tec, err := etcd.NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create local etcd client: %w\", err)\n\t}\n\n\tdefer ec.Close() //nolint:errcheck\n\n\tsess, err := concurrency.NewSession(ec.Client)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create concurrency session: %w\", err)\n\t}\n\tdefer sess.Close() //nolint:errcheck\n\n\telection := concurrency.NewElection(sess, vip.etcdElectionKey())\n\n\tnode, err := election.Leader(ctx)\n\tif err != nil {\n\t\tif err != concurrency.ErrElectionNoLeader {\n\t\t\treturn fmt.Errorf(\"failed getting current leader: %w\", err)\n\t\t}\n\t} else if string(node.Kvs[0].Value) == hostname {\n\t\tvip.logger.Info(\"resigning from previous election\")\n\n\t\t// we are still leader from the previous election, attempt to resign to force new election\n\t\tresumedElection := concurrency.ResumeElection(sess, vip.etcdElectionKey(), string(node.Kvs[0].Key), node.Kvs[0].CreateRevision)\n\n\t\tif err = resumedElection.Resign(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed resigning from previous elections: %w\", err)\n\t\t}\n\t}\n\n\tcampaignErrCh := make(chan error)\n\n\tgo func() {\n\t\tcampaignErrCh <- election.Campaign(ctx, hostname)\n\t}()\n\n\twatchCh := make(chan state.Event)\n\n\tif err = vip.state.Watch(ctx, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, \"etcd\", resource.VersionUndefined), watchCh); err != nil {\n\t\treturn fmt.Errorf(\"error setting up etcd watch: %w\", err)\n\t}\n\n\tif err = vip.state.Watch(ctx, kubeletLifecycle, watchCh); err != nil {\n\t\treturn fmt.Errorf(\"error setting up etcd watch: %w\", err)\n\t}\n\n\terr = vip.state.WatchKind(ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodStatusType, \"\", resource.VersionUndefined), watchCh)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"kube-apiserver health wait failure: %w\", err)\n\t}\n\n\t// wait for the etcd election campaign to be complete\n\t// while waiting, also observe the kubelet lifecycle object (if the node is shutting down) and etcd status\ncampaignLoop:\n\tfor {\n\t\tselect {\n\t\tcase err = <-campaignErrCh:\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to conduct campaign: %w\", err)\n\t\t\t}\n\n\t\t\t// node won the election campaign!\n\t\t\tbreak campaignLoop\n\t\tcase <-sess.Done():\n\t\t\tvip.logger.Info(\"etcd session closed\")\n\n\t\t\treturn nil\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase event := <-watchCh:\n\t\t\t// note: here we don't wait for kube-apiserver, as it might not be up on cluster bootstrap, but VIP should be still assigned\n\t\t\t// break the loop when etcd is stopped\n\t\t\tif event.Type == state.Destroyed && event.Resource.Metadata().ID() == \"etcd\" {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// break the loop if the kubelet lifecycle is entering teardown phase\n\t\t\tif event.Resource != nil {\n\t\t\t\tif event.Resource.Metadata().Type() == kubeletLifecycle.Type() && event.Resource.Metadata().ID() == kubeletLifecycle.ID() && event.Resource.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdefer func() {\n\t\t// use a new context to resign, as `ctx` might be canceled\n\t\tresignCtx, resignCancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer resignCancel()\n\n\t\telection.Resign(resignCtx) //nolint:errcheck\n\t}()\n\n\tif err = vip.markAsLeader(ctx, notifyCh, true); err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif err = vip.markAsLeader(ctx, notifyCh, false); err != nil && !errors.Is(err, context.Canceled) {\n\t\t\tvip.logger.Info(\"failed disabling shared IP\", zap.String(\"link\", vip.linkName), zap.Stringer(\"ip\", vip.sharedIP), zap.Error(err))\n\t\t}\n\n\t\tvip.logger.Info(\"removing shared IP\", zap.String(\"link\", vip.linkName), zap.Stringer(\"ip\", vip.sharedIP))\n\t}()\n\n\tvip.logger.Info(\"enabled shared IP\", zap.String(\"link\", vip.linkName), zap.Stringer(\"ip\", vip.sharedIP))\n\n\tobserve := election.Observe(ctx)\n\nobserveLoop:\n\tfor {\n\t\tselect {\n\t\tcase <-sess.Done():\n\t\t\tvip.logger.Info(\"etcd session closed\")\n\n\t\t\tbreak observeLoop\n\t\tcase <-ctx.Done():\n\t\t\tbreak observeLoop\n\t\tcase resp, ok := <-observe:\n\t\t\tif !ok {\n\t\t\t\tbreak observeLoop\n\t\t\t}\n\n\t\t\tif string(resp.Kvs[0].Value) != hostname {\n\t\t\t\tvip.logger.Info(\"detected new leader\", zap.ByteString(\"leader\", resp.Kvs[0].Value))\n\n\t\t\t\tbreak observeLoop\n\t\t\t}\n\t\tcase event := <-watchCh:\n\t\t\t// break the loop when etcd is stopped or kube-apiserver is stopped\n\t\t\tif event.Type == state.Destroyed {\n\t\t\t\tif event.Resource.Metadata().ID() == \"etcd\" || strings.HasPrefix(event.Resource.Metadata().ID(), \"kube-system/kube-apiserver-\") {\n\t\t\t\t\tbreak observeLoop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// break the loop if the kubelet lifecycle is entering teardown phase\n\t\t\tif event.Resource != nil {\n\t\t\t\tif event.Resource.Metadata().Type() == kubeletLifecycle.Type() && event.Resource.Metadata().ID() == kubeletLifecycle.ID() && event.Resource.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t\t\t\tbreak observeLoop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (vip *VIP) markAsLeader(ctx context.Context, notifyCh chan<- struct{}, leader bool) error {\n\tvar handlerErr error\n\n\tif leader {\n\t\thandlerErr = vip.handler.Acquire(ctx)\n\t\tif handlerErr != nil {\n\t\t\t// if failed to acquire, we are not a leader, we will resign from the election\n\t\t\t// so don't mark as leader, so that Talos doesn't announce IPs on the host\n\t\t\tleader = false\n\t\t}\n\t} else {\n\t\thandlerErr = vip.handler.Release(ctx)\n\t}\n\n\tfunc() {\n\t\tvip.mu.Lock()\n\t\tdefer vip.mu.Unlock()\n\n\t\tvip.leader = leader\n\t}()\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase notifyCh <- struct{}{}:\n\t\treturn handlerErr\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// OperatorConfigController manages network.OperatorSpec based on machine configuration, kernel cmdline.\ntype OperatorConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *OperatorConfigController) Name() string {\n\treturn \"network.OperatorConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *OperatorConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.DeviceConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.ConfigNamespaceName,\n\t\t\tType:      network.LinkSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *OperatorConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.OperatorSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *OperatorConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tlinkStatuses, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing link statuses: %w\", err)\n\t\t}\n\n\t\tlinkNameResolver := network.NewLinkResolver(linkStatuses.All)\n\n\t\tvar (\n\t\t\tspecs      []network.OperatorSpecSpec\n\t\t\tspecErrors *multierror.Error\n\t\t)\n\n\t\tignoredInterfaces := map[string]struct{}{}\n\n\t\tif ctrl.Cmdline != nil {\n\t\t\tvar settings CmdlineNetworking\n\n\t\t\tsettings, err = ParseCmdlineNetwork(ctrl.Cmdline, linkNameResolver)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Warn(\"ignored cmdline parse failure\", zap.Error(err))\n\t\t\t}\n\n\t\t\tfor _, link := range settings.IgnoreInterfaces {\n\t\t\t\tignoredInterfaces[link] = struct{}{}\n\t\t\t}\n\n\t\t\tfor _, linkConfig := range settings.LinkConfigs {\n\t\t\t\tif !linkConfig.DHCP {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\tLinkName:  linkNameResolver.Resolve(linkConfig.LinkName),\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\titems, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.DeviceConfigSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tdevices := xslices.Map(items.Items, func(item resource.Resource) talosconfig.Device {\n\t\t\treturn item.(*network.DeviceConfigSpec).TypedSpec().Device\n\t\t})\n\n\t\t// operators from the config\n\t\tif len(devices) > 0 {\n\t\t\tfor _, device := range devices {\n\t\t\t\tif device.Ignore() {\n\t\t\t\t\tignoredInterfaces[linkNameResolver.Resolve(device.Interface())] = struct{}{}\n\t\t\t\t}\n\n\t\t\t\tif _, ignore := ignoredInterfaces[linkNameResolver.Resolve(device.Interface())]; ignore {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif device.DHCP() && device.DHCPOptions().IPv4() {\n\t\t\t\t\trouteMetric := device.DHCPOptions().RouteMetric()\n\t\t\t\t\tif routeMetric == 0 {\n\t\t\t\t\t\trouteMetric = network.DefaultRouteMetric\n\t\t\t\t\t}\n\n\t\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\t\tLinkName:  linkNameResolver.Resolve(device.Interface()),\n\t\t\t\t\t\tRequireUp: true,\n\t\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\t\tRouteMetric: routeMetric,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif device.DHCP() && device.DHCPOptions().IPv6() {\n\t\t\t\t\trouteMetric := device.DHCPOptions().RouteMetric()\n\t\t\t\t\tif routeMetric == 0 {\n\t\t\t\t\t\trouteMetric = network.DefaultRouteMetric\n\t\t\t\t\t}\n\n\t\t\t\t\tclientIdentifier := network.ClientIdentifierSpec{}\n\t\t\t\t\tif duid := device.DHCPOptions().DUIDv6(); len(duid) > 0 {\n\t\t\t\t\t\tclientIdentifier = network.ClientIdentifierSpec{\n\t\t\t\t\t\t\tClientIdentifier: nethelpers.ClientIdentifierDUID,\n\t\t\t\t\t\t\tDUIDRawHex:       duid,\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\t\t\tLinkName:  linkNameResolver.Resolve(device.Interface()),\n\t\t\t\t\t\tRequireUp: true,\n\t\t\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\t\t\tRouteMetric:      routeMetric,\n\t\t\t\t\t\t\tClientIdentifier: clientIdentifier,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tfor _, vlan := range device.Vlans() {\n\t\t\t\t\tif vlan.DHCP() && vlan.DHCPOptions().IPv4() {\n\t\t\t\t\t\trouteMetric := vlan.DHCPOptions().RouteMetric()\n\t\t\t\t\t\tif routeMetric == 0 {\n\t\t\t\t\t\t\trouteMetric = network.DefaultRouteMetric\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\t\t\tLinkName:  nethelpers.VLANLinkName(device.Interface(), vlan.ID()),\n\t\t\t\t\t\t\tRequireUp: true,\n\t\t\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\t\t\tRouteMetric: routeMetric,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\n\t\t\t\t\tif vlan.DHCP() && vlan.DHCPOptions().IPv6() {\n\t\t\t\t\t\trouteMetric := vlan.DHCPOptions().RouteMetric()\n\t\t\t\t\t\tif routeMetric == 0 {\n\t\t\t\t\t\t\trouteMetric = network.DefaultRouteMetric\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tclientIdentifier := network.ClientIdentifierSpec{}\n\t\t\t\t\t\tif duid := vlan.DHCPOptions().DUIDv6(); len(duid) > 0 {\n\t\t\t\t\t\t\tclientIdentifier = network.ClientIdentifierSpec{\n\t\t\t\t\t\t\t\tClientIdentifier: nethelpers.ClientIdentifierDUID,\n\t\t\t\t\t\t\t\tDUIDRawHex:       duid,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\t\t\t\tLinkName:  nethelpers.VLANLinkName(device.Interface(), vlan.ID()),\n\t\t\t\t\t\t\tRequireUp: true,\n\t\t\t\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\t\t\t\tRouteMetric:      routeMetric,\n\t\t\t\t\t\t\t\tClientIdentifier: clientIdentifier,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// operator configs from machine config (new-style)\n\t\tif cfg != nil {\n\t\t\tfor _, dhcp4 := range cfg.Config().NetworkDHCPv4Configs() {\n\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\tLinkName:  linkNameResolver.Resolve(dhcp4.Name()),\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric:         dhcp4.RouteMetric().ValueOr(network.DefaultRouteMetric),\n\t\t\t\t\t\tSkipHostnameRequest: dhcp4.IgnoreHostname().ValueOrZero(),\n\t\t\t\t\t\tClientIdentifier: network.ClientIdentifierSpec{\n\t\t\t\t\t\t\tClientIdentifier: dhcp4.ClientIdentifier(),\n\t\t\t\t\t\t\tDUIDRawHex:       hex.EncodeToString(dhcp4.DUIDRaw().ValueOrZero()),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tfor _, dhcp6 := range cfg.Config().NetworkDHCPv6Configs() {\n\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\t\tLinkName:  linkNameResolver.Resolve(dhcp6.Name()),\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\t\tRouteMetric:         dhcp6.RouteMetric().ValueOr(network.DefaultRouteMetric),\n\t\t\t\t\t\tSkipHostnameRequest: dhcp6.IgnoreHostname().ValueOrZero(),\n\t\t\t\t\t\tClientIdentifier: network.ClientIdentifierSpec{\n\t\t\t\t\t\t\tClientIdentifier: dhcp6.ClientIdentifier(),\n\t\t\t\t\t\t\tDUIDRawHex:       hex.EncodeToString(dhcp6.DUIDRaw().ValueOrZero()),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// run default DHCP operators if enabled\n\t\tshouldRunDefaultDHCPOperators := cfg == nil || cfg.Config().RunDefaultDHCPOperators()\n\n\t\tif shouldRunDefaultDHCPOperators {\n\t\t\t// build configuredInterfaces from linkSpecs in `network-config` namespace\n\t\t\t// any link which has any configuration derived from the machine configuration or platform configuration should be ignored\n\t\t\tconfiguredInterfaces := map[string]struct{}{}\n\n\t\t\tlinkSpecs, err := safe.ReaderList[*network.LinkSpec](ctx, r, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, \"\", resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error listing link specs: %w\", err)\n\t\t\t}\n\n\t\t\tfor link := range linkSpecs.All() {\n\t\t\t\tlinkSpec := link.TypedSpec()\n\n\t\t\t\tswitch linkSpec.ConfigLayer {\n\t\t\t\tcase network.ConfigDefault:\n\t\t\t\t\t// ignore default link specs\n\t\t\t\tcase network.ConfigOperator:\n\t\t\t\t\t// specs produced by operators, ignore\n\t\t\t\tcase network.ConfigCmdline, network.ConfigMachineConfiguration, network.ConfigPlatform:\n\t\t\t\t\t// interface is configured explicitly, don't run default dhcp4\n\t\t\t\t\tconfiguredInterfaces[linkNameResolver.Resolve(linkSpec.Name)] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// operators from defaults\n\t\t\tfor linkStatus := range linkStatuses.All() {\n\t\t\t\tif linkStatus.TypedSpec().Physical() {\n\t\t\t\t\tif _, configured := configuredInterfaces[linkStatus.Metadata().ID()]; !configured {\n\t\t\t\t\t\tif _, ignored := ignoredInterfaces[linkStatus.Metadata().ID()]; !ignored {\n\t\t\t\t\t\t\t// enable DHCPv4 operator on physical interfaces which don't have any explicit configuration and are not ignored\n\t\t\t\t\t\t\tspecs = append(specs, network.OperatorSpecSpec{\n\t\t\t\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\t\t\t\tLinkName:  linkStatus.Metadata().ID(),\n\t\t\t\t\t\t\t\tRequireUp: true,\n\t\t\t\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t\t\t\t\t\tClientIdentifier: network.ClientIdentifierSpec{\n\t\t\t\t\t\t\t\t\t\tClientIdentifier: nethelpers.ClientIdentifierMAC,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tConfigLayer: network.ConfigDefault,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = ctrl.apply(ctx, r, specs); err != nil {\n\t\t\treturn fmt.Errorf(\"error applying operator specs: %w\", err)\n\t\t}\n\n\t\t// list specs for cleanup\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up operator specs: %w\", err)\n\t\t}\n\n\t\t// last, check if some specs failed to build; fail last so that other operator specs are applied successfully\n\t\tif err = specErrors.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *OperatorConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.OperatorSpecSpec) error {\n\tfor _, spec := range specs {\n\t\tid := network.LayeredID(spec.ConfigLayer, network.OperatorID(spec))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewOperatorSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.OperatorSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype OperatorConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *OperatorConfigSuite) assertOperators(requiredIDs []string, check func(*network.OperatorSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *OperatorConfigSuite) assertNoOperators(unexpectedIDs []string) {\n\tfor _, id := range unexpectedIDs {\n\t\tctest.AssertNoResource[*network.OperatorSpec](suite, id, rtestutils.WithNamespace(network.ConfigNamespaceName))\n\t}\n}\n\nfunc (suite *OperatorConfigSuite) TestDefaultDHCP() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.OperatorConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"talos.network.interface.ignore=eth2\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tfor _, link := range []string{\"eth0\", \"eth1\", \"eth2\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth1\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"default/dhcp4/eth0\":\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().LinkName)\n\t\t\tcase \"default/dhcp4/eth1\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().LinkName)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestNoDefaultDHCP() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.OperatorConfigController{}))\n\n\tfor _, link := range []string{\"eth0\", \"eth1\", \"eth2\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\t// operators start\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth1\",\n\t\t\t\"default/dhcp4/eth2\",\n\t\t},\n\t\tfunc(r *network.OperatorSpec, asrt *assert.Assertions) {},\n\t)\n\n\t// create config\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkMTU = 9001\n\n\tctr, err := container.New(lc1)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\t// operators stop\n\tsuite.assertNoOperators(\n\t\t[]string{\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth1\",\n\t\t\t\"default/dhcp4/eth2\",\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestDefaultDHCPCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.OperatorConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1::::: ip=eth3:dhcp\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tfor _, link := range []string{\"eth0\", \"eth1\", \"eth2\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth2\",\n\t\t\t\"cmdline/dhcp4/eth3\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"default/dhcp4/eth0\":\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().LinkName)\n\t\t\tcase \"default/dhcp4/eth2\":\n\t\t\t\tasrt.Equal(\"eth2\", r.TypedSpec().LinkName)\n\t\t\tcase \"cmdline/dhcp4/eth3\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().LinkName)\n\t\t\t}\n\t\t},\n\t)\n\n\t// remove link\n\tsuite.Require().NoError(\n\t\tsuite.State().Destroy(\n\t\t\tsuite.Ctx(),\n\t\t\tresource.NewMetadata(network.NamespaceName, network.LinkStatusType, \"eth2\", resource.VersionUndefined),\n\t\t),\n\t)\n\n\tsuite.assertNoOperators(\n\t\t[]string{\n\t\t\t\"default/dhcp4/eth2\",\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestMachineConfigurationDHCP4() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.OperatorConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"talos.network.interface.ignore=eth5\"),\n\t\t\t},\n\t\t),\n\t)\n\t// add LinkConfig controller to produce link specs based on machine configuration\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.LinkConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"talos.network.interface.ignore=eth5\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tfor _, link := range []string{\"eth0\", \"eth1\", \"eth2\"} {\n\t\tlinkStatus := network.NewLinkStatus(network.NamespaceName, link)\n\t\tlinkStatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tlinkStatus.TypedSpec().LinkState = true\n\n\t\tsuite.Create(linkStatus)\n\t}\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth3\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\tDHCPIPv4:        new(true),\n\t\t\t\t\t\t\t\t\tDHCPRouteMetric: 256,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth4\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:   25,\n\t\t\t\t\t\t\t\t\t\tVlanDHCP: new(true),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 26,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 27,\n\t\t\t\t\t\t\t\t\t\tVlanDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\t\t\tDHCPRouteMetric: 256,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth5\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp4/eth1\",\n\t\t\t\"configuration/dhcp4/eth3\",\n\t\t\t\"configuration/dhcp4/eth4.25\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/dhcp4/eth1\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/eth3\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(256, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/eth4.25\":\n\t\t\t\tasrt.Equal(\"eth4.25\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/eth4.26\":\n\t\t\t\tasrt.Equal(\"eth4.26\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/eth4.27\":\n\t\t\t\tasrt.Equal(\"eth4.27\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(256, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.assertNoOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"configuration/dhcp4/eth2\",\n\t\t\t\"default/dhcp4/eth2\",\n\t\t\t\"configuration/dhcp4/eth4.26\",\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestMachineConfigurationDHCP6() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.OperatorConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\tDHCPIPv4: new(true),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\tDHCPIPv6: new(true),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth3\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\tDHCPIPv6:        new(true),\n\t\t\t\t\t\t\t\t\tDHCPRouteMetric: 512,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp6/eth2\",\n\t\t\t\"configuration/dhcp6/eth3\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorDHCP6, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/dhcp6/eth2\":\n\t\t\t\tasrt.Equal(\"eth2\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP6.RouteMetric)\n\t\t\tcase \"configuration/dhcp6/eth3\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(512, r.TypedSpec().DHCP6.RouteMetric)\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.assertNoOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp6/eth1\",\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestMachineConfigurationNewStyle() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.OperatorConfigController{}))\n\n\tdhcp1 := networkcfg.NewDHCPv4ConfigV1Alpha1(\"eth0\")\n\tdhcp1.ConfigRouteMetric = 256\n\tdhcp1.ConfigIgnoreHostname = new(true)\n\n\tdhcp2 := networkcfg.NewDHCPv6ConfigV1Alpha1(\"eth0\")\n\tdhcp2.ConfigRouteMetric = 512\n\tdhcp2.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\tdhcp2.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01}\n\n\tdhcp3 := networkcfg.NewDHCPv4ConfigV1Alpha1(\"eth23\")\n\n\tdhcp4 := networkcfg.NewDHCPv4ConfigV1Alpha1(\"eth4\")\n\n\tctr, err := container.New(dhcp1, dhcp2, dhcp3, dhcp4)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp4/eth0\",\n\t\t\t\"configuration/dhcp4/eth23\",\n\t\t\t\"configuration/dhcp4/eth4\",\n\t\t\t\"configuration/dhcp6/eth0\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/dhcp4/eth0\":\n\t\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(256, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\t\tasrt.True(r.TypedSpec().DHCP4.SkipHostnameRequest)\n\t\t\t\tasrt.Equal(nethelpers.ClientIdentifierMAC, r.TypedSpec().DHCP4.ClientIdentifier.ClientIdentifier)\n\t\t\tcase \"configuration/dhcp4/eth23\":\n\t\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\t\tasrt.Equal(\"eth23\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\t\tasrt.False(r.TypedSpec().DHCP4.SkipHostnameRequest)\n\t\t\t\tasrt.Equal(nethelpers.ClientIdentifierMAC, r.TypedSpec().DHCP4.ClientIdentifier.ClientIdentifier)\n\t\t\tcase \"configuration/dhcp4/eth2\":\n\t\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\t\tasrt.Equal(\"eth2\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\t\tasrt.False(r.TypedSpec().DHCP4.SkipHostnameRequest)\n\t\t\t\tasrt.Equal(nethelpers.ClientIdentifierMAC, r.TypedSpec().DHCP4.ClientIdentifier.ClientIdentifier)\n\t\t\tcase \"configuration/dhcp6/eth0\":\n\t\t\t\tasrt.Equal(network.OperatorDHCP6, r.TypedSpec().Operator)\n\t\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(512, r.TypedSpec().DHCP6.RouteMetric)\n\t\t\t\tasrt.False(r.TypedSpec().DHCP6.SkipHostnameRequest)\n\t\t\t\tasrt.Equal(nethelpers.ClientIdentifierDUID, r.TypedSpec().DHCP6.ClientIdentifier.ClientIdentifier)\n\t\t\t\tasrt.NotEmpty(r.TypedSpec().DHCP6.ClientIdentifier.DUIDRawHex)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorConfigSuite) TestMachineConfigurationWithAliases() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.OperatorConfigController{},\n\t\t),\n\t)\n\t// add LinkConfig controller to produce link specs based on machine configuration\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.LinkConfigController{},\n\t\t),\n\t)\n\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth0\",\n\t\t\taliases: []string{\"enx0123\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth1\",\n\t\t\taliases: []string{\"enx0456\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth2\",\n\t\t\taliases: []string{\"enxa\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth3\",\n\t\t\taliases: []string{\"enxb\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth4\",\n\t\t\taliases: []string{\"enxc\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\t\tstatus.TypedSpec().Type = nethelpers.LinkEther\n\t\tstatus.TypedSpec().LinkState = true\n\n\t\tsuite.Create(status)\n\t}\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enx0123\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enx0456\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"enxa\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enxb\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\tDHCPIPv4:        new(true),\n\t\t\t\t\t\t\t\t\tDHCPRouteMetric: 256,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enxc\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:   25,\n\t\t\t\t\t\t\t\t\t\tVlanDHCP: new(true),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 26,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 27,\n\t\t\t\t\t\t\t\t\t\tVlanDHCPOptions: &v1alpha1.DHCPOptions{\n\t\t\t\t\t\t\t\t\t\t\tDHCPRouteMetric: 256,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enxd\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp4/eth1\",\n\t\t\t\"configuration/dhcp4/eth3\",\n\t\t\t\"configuration/dhcp4/enxc.25\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorDHCP4, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/dhcp4/eth1\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/eth3\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(256, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\tcase \"configuration/dhcp4/enxc.25\":\n\t\t\t\tasrt.Equal(\"enxc.25\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.assertNoOperators(\n\t\t[]string{\n\t\t\t\"configuration/dhcp4/eth0\",\n\t\t\t\"default/dhcp4/eth0\",\n\t\t\t\"configuration/dhcp4/eth2\",\n\t\t\t\"default/dhcp4/eth2\",\n\t\t\t\"configuration/dhcp4/eth4.26\",\n\t\t},\n\t)\n}\n\nfunc TestOperatorConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &OperatorConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewOperatorMergeController initializes a OperatorMergeController.\n//\n// OperatorMergeController merges network.OperatorSpec in network.ConfigNamespace and produces final network.OperatorSpec in network.Namespace.\nfunc NewOperatorMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.OperatorSpec]) map[resource.ID]*network.OperatorSpecSpec {\n\t\t\t// operator is allowed as long as it's not duplicate, for duplicate higher layer takes precedence\n\t\t\toperators := map[string]*network.OperatorSpecSpec{}\n\n\t\t\tfor operator := range list.All() {\n\t\t\t\tid := network.OperatorID(*operator.TypedSpec())\n\n\t\t\t\texisting, ok := operators[id]\n\t\t\t\tif ok && existing.ConfigLayer > operator.TypedSpec().ConfigLayer {\n\t\t\t\t\t// skip this operator, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\toperators[id] = operator.TypedSpec()\n\t\t\t}\n\n\t\t\treturn operators\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype OperatorMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *OperatorMergeSuite) assertOperators(requiredIDs []string, check func(*network.OperatorSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *OperatorMergeSuite) assertNoOperator(id string) {\n\tctest.AssertNoResource[*network.OperatorSpec](suite, id)\n}\n\nfunc (suite *OperatorMergeSuite) TestMerge() {\n\tdhcp1 := network.NewOperatorSpec(network.ConfigNamespaceName, \"default/dhcp4/eth0\")\n\t*dhcp1.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP4,\n\t\tLinkName:    \"eth0\",\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp2 := network.NewOperatorSpec(network.ConfigNamespaceName, \"configuration/dhcp4/eth0\")\n\t*dhcp2.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP4,\n\t\tLinkName:    \"eth0\",\n\t\tRequireUp:   true,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tdhcp6 := network.NewOperatorSpec(network.ConfigNamespaceName, \"configuration/dhcp6/eth0\")\n\t*dhcp6.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP6,\n\t\tLinkName:    \"eth0\",\n\t\tRequireUp:   true,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{dhcp1, dhcp2, dhcp6} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"dhcp4/eth0\",\n\t\t\t\"dhcp6/eth0\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"dhcp4/eth0\":\n\t\t\t\tasrt.Equal(*dhcp2.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"dhcp6/eth0\":\n\t\t\t\tasrt.Equal(*dhcp6.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(dhcp6)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"dhcp4/eth0\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(*dhcp2.TypedSpec(), *r.TypedSpec())\n\t\t},\n\t)\n\tsuite.assertNoOperator(\"dhcp6/eth0\")\n}\n\nfunc (suite *OperatorMergeSuite) TestMergeFlapping() {\n\t// simulate two conflicting operator definitions which are getting removed/added constantly\n\tdhcp := network.NewOperatorSpec(network.ConfigNamespaceName, \"default/dhcp4/eth0\")\n\t*dhcp.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP4,\n\t\tLinkName:    \"eth0\",\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\toverride := network.NewOperatorSpec(network.ConfigNamespaceName, \"configuration/dhcp4/eth0\")\n\t*override.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP4,\n\t\tLinkName:    \"eth0\",\n\t\tRequireUp:   true,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\ttestMergeFlapping(&suite.DefaultSuite, []*network.OperatorSpec{dhcp, override}, \"dhcp4/eth0\", override)\n}\n\nfunc TestOperatorMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &OperatorMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(netctrl.NewOperatorMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cenkalti/backoff/v4\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/operator\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// OperatorSpecController applies network.OperatorSpec to the actual interfaces.\ntype OperatorSpecController struct {\n\tV1alpha1Platform v1alpha1runtime.Platform\n\tState            state.State\n\n\t// Factory can be overridden for unit-testing.\n\tFactory OperatorFactory\n\n\toperators map[string]*operatorRunState\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *OperatorSpecController) Name() string {\n\treturn \"network.OperatorSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *OperatorSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.OperatorSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *OperatorSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.LinkSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.RouteSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.HostnameSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.ResolverSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.TimeServerSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// operatorRunState describes a state of running operator.\ntype operatorRunState struct {\n\tOperator operator.Operator\n\tSpec     network.OperatorSpecSpec\n\n\tcancel context.CancelFunc\n\twg     sync.WaitGroup\n}\n\nfunc (state *operatorRunState) Start(ctx context.Context, notifyCh chan<- struct{}, logger *zap.Logger, id string) {\n\tstate.wg.Add(1)\n\n\tctx, state.cancel = context.WithCancel(ctx)\n\n\tgo func() {\n\t\tdefer state.wg.Done()\n\n\t\tstate.runWithRestarts(ctx, notifyCh, logger, id)\n\t}()\n}\n\nfunc (state *operatorRunState) runWithRestarts(ctx context.Context, notifyCh chan<- struct{}, logger *zap.Logger, id string) {\n\tbackoff := backoff.NewExponentialBackOff()\n\n\t// disable number of retries limit\n\tbackoff.MaxElapsedTime = 0\n\n\tfor ctx.Err() == nil {\n\t\tif err := state.runWithPanicHandler(ctx, notifyCh, logger, id); err == nil {\n\t\t\t// operator finished without an error\n\t\t\treturn\n\t\t}\n\n\t\tinterval := backoff.NextBackOff()\n\n\t\tlogger.Debug(\"restarting operator\", zap.Duration(\"interval\", interval), zap.String(\"operator\", id))\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-time.After(interval):\n\t\t}\n\t}\n}\n\nfunc (state *operatorRunState) runWithPanicHandler(ctx context.Context, notifyCh chan<- struct{}, logger *zap.Logger, id string) (err error) {\n\tdefer func() {\n\t\tif p := recover(); p != nil {\n\t\t\terr = fmt.Errorf(\"panic: %v\", p)\n\n\t\t\tlogger.Error(\"operator panicked\", zap.Stack(\"stack\"), zap.Error(err), zap.String(\"operator\", id))\n\t\t}\n\t}()\n\n\tstate.Operator.Run(ctx, notifyCh)\n\n\treturn nil\n}\n\nfunc (state *operatorRunState) Stop() {\n\tstate.cancel()\n\n\tstate.wg.Wait()\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *OperatorSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tnotifyCh := make(chan struct{})\n\n\tctrl.operators = make(map[string]*operatorRunState)\n\n\tdefer func() {\n\t\tfor _, operator := range ctrl.operators {\n\t\t\toperator.Stop()\n\t\t}\n\t}()\n\n\tif ctrl.Factory == nil {\n\t\tctrl.Factory = ctrl.newOperator\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tif err := ctrl.reconcileOperators(ctx, r, logger, notifyCh); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase <-notifyCh:\n\t\t\tif err := ctrl.reconcileOperatorOutputs(ctx, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *OperatorSpecController) reconcileOperators(ctx context.Context, r controller.Runtime, logger *zap.Logger, notifyCh chan<- struct{}) error {\n\t// build link up statuses\n\tlinkStatuses := make(map[string]bool)\n\n\tlinkStatusList, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing link statuses: %w\", err)\n\t}\n\n\tfor linkStatus := range linkStatusList.All() {\n\t\tlinkStatuses[linkStatus.Metadata().ID()] = linkStatus.TypedSpec().OperationalState == nethelpers.OperStateUnknown || linkStatus.TypedSpec().OperationalState == nethelpers.OperStateUp\n\t}\n\n\t// list operator specs\n\toperatorSpecs, err := safe.ReaderListAll[*network.OperatorSpec](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing operator specs: %w\", err)\n\t}\n\n\t// figure out which operators should run\n\tshouldRun := make(map[string]*network.OperatorSpecSpec)\n\n\tfor operatorSpec := range operatorSpecs.All() {\n\t\tup, exists := linkStatuses[operatorSpec.TypedSpec().LinkName]\n\n\t\t// link doesn't exist, skip operator\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\t// link is down and operator requires link to be up, skip it\n\t\tif operatorSpec.TypedSpec().RequireUp && !up {\n\t\t\tcontinue\n\t\t}\n\n\t\tshouldRun[operatorSpec.Metadata().ID()] = operatorSpec.TypedSpec()\n\t}\n\n\t// stop running operators which shouldn't run\n\tfor id := range ctrl.operators {\n\t\tif _, exists := shouldRun[id]; !exists {\n\t\t\tlogger.Debug(\"stopping operator\", zap.String(\"operator\", id))\n\n\t\t\t// stop operator\n\t\t\tctrl.operators[id].Stop()\n\t\t\tdelete(ctrl.operators, id)\n\t\t} else if !ctrl.operators[id].Spec.Equal(*shouldRun[id]) {\n\t\t\tlogger.Debug(\"replacing operator\", zap.String(\"operator\", id))\n\n\t\t\t// stop operator\n\t\t\tctrl.operators[id].Stop()\n\t\t\tdelete(ctrl.operators, id)\n\t\t}\n\t}\n\n\t// start operators which aren't running\n\tfor id := range shouldRun {\n\t\tif _, exists := ctrl.operators[id]; !exists {\n\t\t\tctrl.operators[id] = &operatorRunState{\n\t\t\t\tOperator: ctrl.Factory(logger, shouldRun[id]),\n\t\t\t\tSpec:     *shouldRun[id],\n\t\t\t}\n\n\t\t\tlogger.Debug(\"starting operator\", zap.String(\"operator\", id))\n\t\t\tctrl.operators[id].Start(ctx, notifyCh, logger, id)\n\t\t}\n\t}\n\n\t// now reconcile outputs as the operators might have changed\n\treturn ctrl.reconcileOperatorOutputs(ctx, r)\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *OperatorSpecController) reconcileOperatorOutputs(ctx context.Context, r controller.Runtime) error {\n\tr.StartTrackingOutputs()\n\n\tfor _, op := range ctrl.operators {\n\t\tfor _, addressSpec := range op.Operator.AddressSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewAddressSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\", op.Operator.Prefix(), network.AddressID(addressSpec.LinkName, addressSpec.Address)),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.AddressSpec) error {\n\t\t\t\t\t*r.TypedSpec() = addressSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, routeSpec := range op.Operator.RouteSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewRouteSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\",\n\t\t\t\t\t\top.Operator.Prefix(),\n\t\t\t\t\t\tnetwork.RouteID(routeSpec.Table, routeSpec.Family, routeSpec.Destination, routeSpec.Gateway, routeSpec.Priority, routeSpec.OutLinkName),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.RouteSpec) error {\n\t\t\t\t\t*r.TypedSpec() = routeSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, linkSpec := range op.Operator.LinkSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewLinkSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\", op.Operator.Prefix(), network.LinkID(linkSpec.Name)),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.LinkSpec) error {\n\t\t\t\t\t*r.TypedSpec() = linkSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, hostnameSpec := range op.Operator.HostnameSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewHostnameSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\", op.Operator.Prefix(), network.HostnameID),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.HostnameSpec) error {\n\t\t\t\t\t*r.TypedSpec() = hostnameSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, resolverSpec := range op.Operator.ResolverSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewResolverSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\", op.Operator.Prefix(), network.ResolverID),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.ResolverSpec) error {\n\t\t\t\t\t*r.TypedSpec() = resolverSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tfor _, timeserverSpec := range op.Operator.TimeServerSpecs() {\n\t\t\tif err := safe.WriterModify(\n\t\t\t\tctx, r,\n\t\t\t\tnetwork.NewTimeServerSpec(\n\t\t\t\t\tnetwork.ConfigNamespaceName,\n\t\t\t\t\tfmt.Sprintf(\"%s/%s\", op.Operator.Prefix(), network.TimeServerID),\n\t\t\t\t),\n\t\t\t\tfunc(r *network.TimeServerSpec) error {\n\t\t\t\t\t*r.TypedSpec() = timeserverSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying spec: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// clean up not touched specs\n\tif err := r.CleanupOutputs(ctx,\n\t\txslices.Map([]resource.Type{\n\t\t\tnetwork.AddressSpecType,\n\t\t\tnetwork.LinkSpecType,\n\t\t\tnetwork.RouteSpecType,\n\t\t\tnetwork.HostnameSpecType,\n\t\t\tnetwork.ResolverSpecType,\n\t\t\tnetwork.TimeServerSpecType,\n\t\t}, func(t resource.Type) resource.Kind {\n\t\t\treturn resource.NewMetadata(network.ConfigNamespaceName, t, \"\", resource.VersionUndefined)\n\t\t})...,\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error during outputs cleanup: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// OperatorFactory creates operator based on the spec.\ntype OperatorFactory func(*zap.Logger, *network.OperatorSpecSpec) operator.Operator\n\nfunc (ctrl *OperatorSpecController) newOperator(logger *zap.Logger, spec *network.OperatorSpecSpec) operator.Operator {\n\tswitch spec.Operator {\n\tcase network.OperatorDHCP4:\n\t\tlogger = logger.With(zap.String(\"operator\", \"dhcp4\"))\n\n\t\treturn operator.NewDHCP4(logger, spec.LinkName, spec.DHCP4, ctrl.V1alpha1Platform, ctrl.State)\n\tcase network.OperatorDHCP6:\n\t\tlogger = logger.With(zap.String(\"operator\", \"dhcp6\"))\n\n\t\treturn operator.NewDHCP6(logger, spec.LinkName, spec.DHCP6, ctrl.State)\n\tcase network.OperatorVIP:\n\t\tlogger = logger.With(zap.String(\"operator\", \"vip\"))\n\n\t\treturn operator.NewVIP(logger, spec.LinkName, spec.VIP, ctrl.State)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected operator %s\", spec.Operator))\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/operator\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype OperatorSpecSuite struct {\n\tctest.DefaultSuite\n}\n\ntype mockOperator struct {\n\tspec     network.OperatorSpecSpec\n\tnotifyCh chan<- struct{}\n\tpanicked bool\n\n\tmu          sync.Mutex\n\taddresses   []network.AddressSpecSpec\n\tlinks       []network.LinkSpecSpec\n\troutes      []network.RouteSpecSpec\n\thostname    []network.HostnameSpecSpec\n\tresolvers   []network.ResolverSpecSpec\n\ttimeservers []network.TimeServerSpecSpec\n}\n\nvar (\n\trunningOperators   = map[string]*mockOperator{}\n\trunningOperatorsMu sync.Mutex\n)\n\nfunc (mock *mockOperator) Prefix() string {\n\treturn fmt.Sprintf(\"%s/%s\", mock.spec.Operator, mock.spec.LinkName)\n}\n\nfunc (mock *mockOperator) Run(ctx context.Context, notifyCh chan<- struct{}) {\n\tmock.notifyCh = notifyCh\n\n\t{\n\t\trunningOperatorsMu.Lock()\n\n\t\trunningOperators[mock.Prefix()] = mock\n\n\t\trunningOperatorsMu.Unlock()\n\t}\n\n\tdefer func() {\n\t\trunningOperatorsMu.Lock()\n\t\tdelete(runningOperators, mock.Prefix())\n\t\trunningOperatorsMu.Unlock()\n\t}()\n\n\tif mock.spec.Operator == network.OperatorDHCP6 {\n\t\t// DHCP6 operator panics on odd run\n\t\tif !mock.panicked {\n\t\t\tmock.panicked = true\n\n\t\t\tpanic(\"oh no, IPv6!!!\")\n\t\t}\n\t}\n\n\t<-ctx.Done()\n}\n\nfunc (mock *mockOperator) notify() {\n\tmock.notifyCh <- struct{}{}\n}\n\nfunc (mock *mockOperator) AddressSpecs() []network.AddressSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.addresses\n}\n\nfunc (mock *mockOperator) LinkSpecs() []network.LinkSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.links\n}\n\nfunc (mock *mockOperator) RouteSpecs() []network.RouteSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.routes\n}\n\nfunc (mock *mockOperator) HostnameSpecs() []network.HostnameSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.hostname\n}\n\nfunc (mock *mockOperator) ResolverSpecs() []network.ResolverSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.resolvers\n}\n\nfunc (mock *mockOperator) TimeServerSpecs() []network.TimeServerSpecSpec {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.timeservers\n}\n\nfunc (suite *OperatorSpecSuite) newOperator(_ *zap.Logger, spec *network.OperatorSpecSpec) operator.Operator {\n\treturn &mockOperator{\n\t\tspec: *spec,\n\t}\n}\n\nfunc (suite *OperatorSpecSuite) assertRunning(runningIDs []string, assertFunc func(*mockOperator) error) error {\n\trunningOperatorsMu.Lock()\n\tdefer runningOperatorsMu.Unlock()\n\n\tfor _, id := range runningIDs {\n\t\top, exists := runningOperators[id]\n\n\t\tif !exists {\n\t\t\treturn retry.ExpectedErrorf(\"operator %q is not running\", id)\n\t\t}\n\n\t\tif err := assertFunc(op); err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\t}\n\n\tfor id := range runningOperators {\n\t\tfound := slices.Contains(runningIDs, id)\n\n\t\tif !found {\n\t\t\treturn retry.ExpectedErrorf(\"operator %s should not be running\", id)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (suite *OperatorSpecSuite) TestScheduling() {\n\tspecDHCP := network.NewOperatorSpec(network.NamespaceName, \"dhcp4/eth0\")\n\t*specDHCP.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorDHCP4,\n\t\tLinkName:  \"eth0\",\n\t\tRequireUp: true,\n\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\tRouteMetric: 1024,\n\t\t},\n\t}\n\n\tspecVIP := network.NewOperatorSpec(network.NamespaceName, \"vip/eth0\")\n\t*specVIP.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorVIP,\n\t\tLinkName:  \"eth0\",\n\t\tRequireUp: false,\n\t\tVIP: network.VIPOperatorSpec{\n\t\t\tIP: netip.MustParseAddr(\"1.2.3.4\"),\n\t\t},\n\t}\n\n\tsuite.Create(specDHCP)\n\tsuite.Create(specVIP)\n\n\t// operators shouldn't be running yet, as link state is not known yet\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\tnil, func(op *mockOperator) error {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tlinkState := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t*linkState.TypedSpec() = network.LinkStatusSpec{\n\t\tOperationalState: nethelpers.OperStateDown,\n\t}\n\n\tsuite.Create(linkState)\n\n\t// vip operator should be scheduled now, as VIP operator doesn't require link to be up\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\t[]string{\"vip/eth0\"}, func(op *mockOperator) error {\n\t\t\t\t\t\tsuite.Assert().Equal(netip.MustParseAddr(\"1.2.3.4\"), op.spec.VIP.IP)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.UpdateWithConflicts(suite, linkState, func(r *network.LinkStatus) error {\n\t\tr.TypedSpec().OperationalState = nethelpers.OperStateUp\n\n\t\treturn nil\n\t})\n\n\t// now all operators should be scheduled\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\t[]string{\"dhcp4/eth0\", \"vip/eth0\"},\n\t\t\t\t\tfunc(op *mockOperator) error {\n\t\t\t\t\t\tswitch op.spec.Operator { //nolint:exhaustive\n\t\t\t\t\t\tcase network.OperatorDHCP4:\n\t\t\t\t\t\t\tsuite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric)\n\t\t\t\t\t\tcase network.OperatorVIP:\n\t\t\t\t\t\t\tsuite.Assert().Equal(netip.MustParseAddr(\"1.2.3.4\"), op.spec.VIP.IP)\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tpanic(\"unreachable\")\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// change the spec, operator should be rescheduled\n\tctest.UpdateWithConflicts(suite, specVIP, func(r *network.OperatorSpec) error {\n\t\tr.TypedSpec().VIP.IP = netip.MustParseAddr(\"3.4.5.6\")\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\t[]string{\"dhcp4/eth0\", \"vip/eth0\"},\n\t\t\t\t\tfunc(op *mockOperator) error {\n\t\t\t\t\t\tswitch op.spec.Operator { //nolint:exhaustive\n\t\t\t\t\t\tcase network.OperatorDHCP4:\n\t\t\t\t\t\t\tsuite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric)\n\t\t\t\t\t\tcase network.OperatorVIP:\n\t\t\t\t\t\t\tif op.spec.VIP.IP.Compare(netip.MustParseAddr(\"3.4.5.6\")) != 0 {\n\t\t\t\t\t\t\t\treturn retry.ExpectedErrorf(\"unexpected vip: %s\", op.spec.VIP.IP)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tpanic(\"unreachable\")\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// bring down the interface, operator should be stopped\n\tctest.UpdateWithConflicts(suite, linkState, func(r *network.LinkStatus) error {\n\t\tr.TypedSpec().OperationalState = nethelpers.OperStateDown\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\t[]string{\"vip/eth0\"}, func(op *mockOperator) error {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *OperatorSpecSuite) TestPanic() {\n\tspecPanic := network.NewOperatorSpec(network.NamespaceName, \"dhcp6/eth0\")\n\t*specPanic.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorDHCP6,\n\t\tLinkName:  \"eth0\",\n\t\tRequireUp: true,\n\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\tRouteMetric: 1024,\n\t\t},\n\t}\n\n\tsuite.Create(specPanic)\n\n\tlinkState := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t*linkState.TypedSpec() = network.LinkStatusSpec{\n\t\tOperationalState: nethelpers.OperStateUp,\n\t}\n\n\tsuite.Create(linkState)\n\n\t// DHCP6 operator should panic and then restart\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning([]string{\"dhcp6/eth0\"}, func(op *mockOperator) error { return nil })\n\t\t\t},\n\t\t),\n\t)\n\n\t// bring down the interface, operator should be stopped\n\tctest.UpdateWithConflicts(suite, linkState, func(r *network.LinkStatus) error {\n\t\tr.TypedSpec().OperationalState = nethelpers.OperStateDown\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\tnil, func(op *mockOperator) error {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *OperatorSpecSuite) TestOperatorOutputs() {\n\tspecDHCP := network.NewOperatorSpec(network.NamespaceName, \"dhcp4/eth0\")\n\t*specDHCP.TypedSpec() = network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorDHCP4,\n\t\tLinkName:  \"eth0\",\n\t\tRequireUp: true,\n\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\tRouteMetric: 1024,\n\t\t},\n\t}\n\n\tsuite.Create(specDHCP)\n\n\tlinkState := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t*linkState.TypedSpec() = network.LinkStatusSpec{\n\t\tOperationalState: nethelpers.OperStateUp,\n\t}\n\n\tsuite.Create(linkState)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRunning(\n\t\t\t\t\t[]string{\"dhcp4/eth0\"}, func(op *mockOperator) error {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// pretend dhcp has some specs ready\n\trunningOperatorsMu.Lock()\n\n\tdhcpMock := runningOperators[\"dhcp4/eth0\"]\n\n\trunningOperatorsMu.Unlock()\n\n\tdhcpMock.mu.Lock()\n\tdhcpMock.addresses = []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:     netip.MustParsePrefix(\"10.5.0.2/24\"),\n\t\t\tLinkName:    \"eth0\",\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigOperator,\n\t\t},\n\t}\n\tdhcpMock.links = []network.LinkSpecSpec{\n\t\t{\n\t\t\tName:        \"eth0\",\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigOperator,\n\t\t},\n\t}\n\tdhcpMock.hostname = []network.HostnameSpecSpec{\n\t\t{\n\t\t\tHostname:    \"foo\",\n\t\t\tConfigLayer: network.ConfigOperator,\n\t\t},\n\t}\n\tdhcpMock.mu.Unlock()\n\n\tdhcpMock.notify()\n\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"dhcp4/eth0/eth0/10.5.0.2/24\"},\n\t\tfunc(*network.AddressSpec, *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"dhcp4/eth0/eth0\"},\n\t\tfunc(*network.LinkSpec, *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"dhcp4/eth0/hostname\"},\n\t\tfunc(*network.HostnameSpec, *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// update specs\n\tdhcpMock.mu.Lock()\n\tdhcpMock.addresses = []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:     netip.MustParsePrefix(\"10.5.0.3/24\"),\n\t\t\tLinkName:    \"eth0\",\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigOperator,\n\t\t},\n\t}\n\tdhcpMock.mu.Unlock()\n\n\tdhcpMock.notify()\n\n\tctest.AssertResources(suite,\n\t\t[]resource.ID{\"dhcp4/eth0/eth0/10.5.0.3/24\"},\n\t\tfunc(*network.AddressSpec, *assert.Assertions) {},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc TestOperatorSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\toperatorSuite := &OperatorSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t}\n\n\toperatorSuite.DefaultSuite.AfterSetup = func(suite *ctest.DefaultSuite) {\n\t\trunningOperators = map[string]*mockOperator{}\n\n\t\tsuite.Require().NoError(\n\t\t\tsuite.Runtime().RegisterController(\n\t\t\t\t&netctrl.OperatorSpecController{\n\t\t\t\t\tFactory: operatorSuite.newOperator,\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t}\n\n\tsuite.Run(t, operatorSuite)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_vip_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/operator/vip\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// OperatorVIPConfigController manages network.OperatorSpec for virtual IPs based on machine configuration.\ntype OperatorVIPConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *OperatorVIPConfigController) Name() string {\n\treturn \"network.OperatorVIPConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *OperatorVIPConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.DeviceConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.LinkStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *OperatorVIPConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.OperatorSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *OperatorVIPConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tdevices, err := safe.ReaderListAll[*network.DeviceConfigSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing device config specs: %w\", err)\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tlinkStatuses, err := safe.ReaderListAll[*network.LinkStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing link statuses: %w\", err)\n\t\t}\n\n\t\tlinkNameResolver := network.NewLinkResolver(linkStatuses.All)\n\n\t\tignoredInterfaces := map[string]struct{}{}\n\n\t\tif ctrl.Cmdline != nil {\n\t\t\tvar settings CmdlineNetworking\n\n\t\t\tsettings, err = ParseCmdlineNetwork(ctrl.Cmdline, linkNameResolver)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Warn(\"ignored cmdline parse failure\", zap.Error(err))\n\t\t\t}\n\n\t\t\tfor _, link := range settings.IgnoreInterfaces {\n\t\t\t\tignoredInterfaces[link] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\tvar (\n\t\t\tspecs      []network.OperatorSpecSpec\n\t\t\tspecErrors *multierror.Error\n\t\t)\n\n\t\t// operators from the legacy config\n\t\tfor dev := range devices.All() {\n\t\t\tdevice := dev.TypedSpec().Device\n\n\t\t\tif device.Ignore() {\n\t\t\t\tignoredInterfaces[linkNameResolver.Resolve(device.Interface())] = struct{}{}\n\t\t\t}\n\n\t\t\tif _, ignore := ignoredInterfaces[linkNameResolver.Resolve(device.Interface())]; ignore {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif device.VIPConfig() != nil {\n\t\t\t\tif spec, specErr := ctrl.handleVIPLegacy(ctx, device.VIPConfig(), linkNameResolver.Resolve(device.Interface()), logger); specErr != nil {\n\t\t\t\t\tspecErrors = multierror.Append(specErrors, specErr)\n\t\t\t\t} else {\n\t\t\t\t\tspecs = append(specs, spec)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, vlan := range device.Vlans() {\n\t\t\t\tif vlan.VIPConfig() != nil {\n\t\t\t\t\tlinkName := nethelpers.VLANLinkName(device.Interface(), vlan.ID())\n\t\t\t\t\tif spec, specErr := ctrl.handleVIPLegacy(ctx, vlan.VIPConfig(), linkName, logger); specErr != nil {\n\t\t\t\t\t\tspecErrors = multierror.Append(specErrors, specErr)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tspecs = append(specs, spec)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// new-style config operators\n\t\tif cfg != nil {\n\t\t\tfor _, doc := range cfg.Config().NetworkVirtualIPConfigs() {\n\t\t\t\tif spec, specErr := ctrl.handleVIPConfigDoc(ctx, doc, linkNameResolver.Resolve(doc.Link()), logger); specErr != nil {\n\t\t\t\t\tspecErrors = multierror.Append(specErrors, specErr)\n\t\t\t\t} else {\n\t\t\t\t\tspecs = append(specs, spec)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif err := ctrl.apply(ctx, r, specs); err != nil {\n\t\t\treturn fmt.Errorf(\"error applying operator specs: %w\", err)\n\t\t}\n\n\t\t// last, check if some specs failed to build; fail last so that other operator specs are applied successfully\n\t\tif err = specErrors.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up operator specs: %w\", err)\n\t\t}\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *OperatorVIPConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.OperatorSpecSpec) error {\n\tfor _, spec := range specs {\n\t\tid := network.LayeredID(spec.ConfigLayer, network.OperatorID(spec))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewOperatorSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.OperatorSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *OperatorVIPConfigController) handleVIPLegacy(ctx context.Context, vipConfig talosconfig.VIPConfig, deviceName string, logger *zap.Logger) (network.OperatorSpecSpec, error) {\n\tvar sharedIP netip.Addr\n\n\tsharedIP, err := netip.ParseAddr(vipConfig.IP())\n\tif err != nil {\n\t\tlogger.Warn(\"ignoring vip parse failure\", zap.Error(err), zap.String(\"link\", deviceName))\n\n\t\treturn network.OperatorSpecSpec{}, err\n\t}\n\n\tspec := network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorVIP,\n\t\tLinkName:  deviceName,\n\t\tRequireUp: true,\n\t\tVIP: network.VIPOperatorSpec{\n\t\t\tIP:            sharedIP,\n\t\t\tGratuitousARP: true,\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tswitch {\n\t// Equinix Metal VIP\n\tcase vipConfig.EquinixMetal() != nil:\n\t\tspec.VIP.GratuitousARP = false\n\t\tspec.VIP.EquinixMetal.APIToken = vipConfig.EquinixMetal().APIToken()\n\n\t\tif err = vip.GetProjectAndDeviceIDs(ctx, &spec.VIP.EquinixMetal); err != nil {\n\t\t\treturn network.OperatorSpecSpec{}, err\n\t\t}\n\t// Hetzner Cloud VIP\n\tcase vipConfig.HCloud() != nil:\n\t\tspec.VIP.GratuitousARP = false\n\t\tspec.VIP.HCloud.APIToken = vipConfig.HCloud().APIToken()\n\n\t\tif err = vip.GetNetworkAndDeviceIDs(ctx, &spec.VIP.HCloud, sharedIP, logger); err != nil {\n\t\t\treturn network.OperatorSpecSpec{}, err\n\t\t}\n\t// Regular layer 2 VIP\n\tdefault:\n\t}\n\n\treturn spec, nil\n}\n\nfunc (ctrl *OperatorVIPConfigController) handleVIPConfigDoc(ctx context.Context, cfg talosconfig.NetworkVirtualIPConfig, deviceName string, logger *zap.Logger) (network.OperatorSpecSpec, error) {\n\tspec := network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorVIP,\n\t\tLinkName:  deviceName,\n\t\tRequireUp: true,\n\t\tVIP: network.VIPOperatorSpec{\n\t\t\tIP:            cfg.VIP(),\n\t\t\tGratuitousARP: true,\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tswitch v := cfg.(type) {\n\tcase talosconfig.NetworkHCloudVIPConfig:\n\t\tspec.VIP.GratuitousARP = false\n\t\tspec.VIP.HCloud.APIToken = v.HCloudAPIToken()\n\n\t\tif err := vip.GetNetworkAndDeviceIDs(ctx, &spec.VIP.HCloud, cfg.VIP(), logger); err != nil {\n\t\t\treturn network.OperatorSpecSpec{}, err\n\t\t}\n\tdefault:\n\t\t// nothing to do\n\t}\n\n\treturn spec, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/operator_vip_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype OperatorVIPConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *OperatorVIPConfigSuite) assertOperators(\n\trequiredIDs []string,\n\tcheck func(*network.OperatorSpec, *assert.Assertions),\n) {\n\tctest.AssertResources(suite, requiredIDs, check, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *OperatorVIPConfigSuite) TestMachineConfigurationLegacyVIP() {\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth5\",\n\t\t\taliases: []string{\"enxa\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth6\",\n\t\t\taliases: []string{\"enxb\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\n\t\tsuite.Create(status)\n\t}\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\tSharedIP: \"2.3.4.5\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\tSharedIP: \"fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth3\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 26,\n\t\t\t\t\t\t\t\t\t\tVlanVIP: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\t\t\tSharedIP: \"5.5.4.4\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"enxa\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t\tDeviceVIPConfig: &v1alpha1.DeviceVIPConfig{\n\t\t\t\t\t\t\t\t\tSharedIP: \"2.3.4.5\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/vip/eth1/2.3.4.5\",\n\t\t\t\"configuration/vip/eth2/fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\",\n\t\t\t\"configuration/vip/eth3.26/5.5.4.4\",\n\t\t\t\"configuration/vip/eth5/2.3.4.5\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorVIP, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/vip/eth1/2.3.4.5\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(netip.MustParseAddr(\"2.3.4.5\"), r.TypedSpec().VIP.IP)\n\t\t\tcase \"configuration/vip/eth5/2.3.4.5\":\n\t\t\t\tasrt.Equal(\"eth5\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(netip.MustParseAddr(\"2.3.4.5\"), r.TypedSpec().VIP.IP)\n\t\t\tcase \"configuration/vip/eth2/fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\":\n\t\t\t\tasrt.Equal(\"eth2\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(\n\t\t\t\t\tnetip.MustParseAddr(\"fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\"),\n\t\t\t\t\tr.TypedSpec().VIP.IP,\n\t\t\t\t)\n\t\t\tcase \"configuration/vip/eth3.26/5.5.4.4\":\n\t\t\t\tasrt.Equal(\"eth3.26\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(netip.MustParseAddr(\"5.5.4.4\"), r.TypedSpec().VIP.IP)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (suite *OperatorVIPConfigSuite) TestMachineConfigurationVIP() {\n\tfor _, link := range []struct {\n\t\tname    string\n\t\taliases []string\n\t}{\n\t\t{\n\t\t\tname:    \"eth5\",\n\t\t\taliases: []string{\"enxa\"},\n\t\t},\n\t\t{\n\t\t\tname:    \"eth6\",\n\t\t\taliases: []string{\"enxb\"},\n\t\t},\n\t} {\n\t\tstatus := network.NewLinkStatus(network.NamespaceName, link.name)\n\t\tstatus.TypedSpec().AltNames = link.aliases\n\n\t\tsuite.Create(status)\n\t}\n\n\tvip1 := networkcfg.NewLayer2VIPConfigV1Alpha1(\"2.3.4.5\")\n\tvip1.LinkName = \"eth33\"\n\n\tvip2 := networkcfg.NewLayer2VIPConfigV1Alpha1(\"fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\")\n\tvip2.LinkName = \"enxa\"\n\n\tctr, err := container.New(vip1, vip2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tsuite.assertOperators(\n\t\t[]string{\n\t\t\t\"configuration/vip/eth33/2.3.4.5\",\n\t\t\t\"configuration/vip/eth5/fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\",\n\t\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.OperatorVIP, r.TypedSpec().Operator)\n\t\t\tasrt.True(r.TypedSpec().RequireUp)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/vip/eth33/2.3.4.5\":\n\t\t\t\tasrt.Equal(\"eth33\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(netip.MustParseAddr(\"2.3.4.5\"), r.TypedSpec().VIP.IP)\n\t\t\tcase \"configuration/vip/eth5/fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\":\n\t\t\t\tasrt.Equal(\"eth5\", r.TypedSpec().LinkName)\n\t\t\t\tasrt.EqualValues(\n\t\t\t\t\tnetip.MustParseAddr(\"fd7a:115c:a1e0:ab12:4843:cd96:6277:2302\"),\n\t\t\t\t\tr.TypedSpec().VIP.IP,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc TestOperatorVIPConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &OperatorVIPConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&netctrl.OperatorVIPConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cenkalti/backoff/v4\"\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// PlatformConfigController runs the platform config acquire code and publishes the result as a resource.\ntype PlatformConfigController struct {\n\tV1alpha1Platform v1alpha1runtime.Platform\n\tPlatformState    state.State\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PlatformConfigController) Name() string {\n\treturn \"network.PlatformConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.PlatformConfigType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *PlatformConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tif ctrl.V1alpha1Platform == nil {\n\t\t// no platform, no work to be done\n\t\treturn nil\n\t}\n\n\tplatformCtx, platformCtxCancel := context.WithCancel(ctx)\n\tdefer platformCtxCancel()\n\n\tplatformCh := make(chan *v1alpha1runtime.PlatformNetworkConfig, 1)\n\n\tvar platformWg sync.WaitGroup\n\n\tplatformWg.Go(func() {\n\t\tctrl.runWithRestarts(platformCtx, logger, func() error {\n\t\t\treturn ctrl.V1alpha1Platform.NetworkConfiguration(platformCtx, ctrl.PlatformState, platformCh)\n\t\t})\n\t})\n\n\tdefer platformWg.Wait()\n\n\tr.QueueReconcile()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase networkConfig := <-platformCh:\n\t\t\tif networkConfig == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := safe.WriterModify(ctx, r,\n\t\t\t\tnetwork.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID),\n\t\t\t\tfunc(out *network.PlatformConfig) error {\n\t\t\t\t\t*out.TypedSpec() = *networkConfig\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying active network config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *PlatformConfigController) runWithRestarts(ctx context.Context, logger *zap.Logger, f func() error) {\n\tbackoff := backoff.NewExponentialBackOff()\n\n\t// disable number of retries limit\n\tbackoff.MaxElapsedTime = 0\n\n\tfor ctx.Err() == nil {\n\t\tvar err error\n\t\tif err = ctrl.runWithPanicHandler(logger, f); err == nil {\n\t\t\t// operator finished without an error\n\t\t\treturn\n\t\t}\n\n\t\t// skip restarting if context is already done\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tinterval := backoff.NextBackOff()\n\n\t\tlogger.Error(\"restarting platform network config\", zap.Duration(\"interval\", interval), zap.Error(err))\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-time.After(interval):\n\t\t}\n\t}\n}\n\nfunc (ctrl *PlatformConfigController) runWithPanicHandler(logger *zap.Logger, f func() error) (err error) {\n\tdefer func() {\n\t\tif p := recover(); p != nil {\n\t\t\terr = fmt.Errorf(\"panic: %v\", p)\n\n\t\t\tlogger.Error(\"platform panicked\", zap.Stack(\"stack\"), zap.Error(err))\n\t\t}\n\t}()\n\n\terr = f()\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_apply.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Virtual link name for external IPs.\nconst externalLink = \"external\"\n\n// PlatformConfigApplyController applies active (or cached) platform network config to the network stack.\ntype PlatformConfigApplyController struct {\n\tV1alpha1Platform v1alpha1runtime.Platform\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PlatformConfigApplyController) Name() string {\n\treturn \"network.PlatformConfigApplyController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigApplyController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.PlatformConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigApplyController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.LinkSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.RouteSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.HostnameSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.ResolverSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.TimeServerSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.AddressStatusType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.OperatorSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.ProbeSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: runtimeres.PlatformMetadataType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *PlatformConfigApplyController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tplatformConfigs, err := safe.ReaderListAll[*network.PlatformConfig](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing platform configs: %w\", err)\n\t\t}\n\n\t\tvar platformConfig *network.PlatformConfig\n\n\t\t// we always prefer \"active\" to \"cached\"\n\t\tfor cfg := range platformConfigs.All() {\n\t\t\tswitch cfg.Metadata().ID() {\n\t\t\tcase network.PlatformConfigActiveID:\n\t\t\t\tplatformConfig = cfg\n\t\t\tcase network.PlatformConfigCachedID:\n\t\t\t\tif platformConfig == nil {\n\t\t\t\t\tplatformConfig = cfg\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we don't have any config yet, populate a minimal one\n\t\t// to ensure that platform name is populated in the resource\n\t\tif platformConfig == nil {\n\t\t\tplatformConfig = network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\t\t\tplatformConfig.TypedSpec().Metadata = &runtimeres.PlatformMetadataSpec{\n\t\t\t\tPlatform: ctrl.V1alpha1Platform.Name(),\n\t\t\t}\n\t\t}\n\n\t\tif err := ctrl.apply(ctx, r, platformConfig); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:dupl,gocyclo\nfunc (ctrl *PlatformConfigApplyController) apply(ctx context.Context, r controller.Runtime, platformConfig *network.PlatformConfig) error {\n\tnetworkConfig := platformConfig.TypedSpec()\n\n\tmetadataLength := 0\n\n\tif networkConfig.Metadata != nil {\n\t\tmetadataLength = 1\n\t}\n\n\t// handle all network specs in a loop as all specs can be handled in a similar way\n\tfor _, specType := range []struct {\n\t\tlength           int\n\t\tgetter           func(i int) any\n\t\tidBuilder        func(spec any) (resource.ID, error)\n\t\tresourceBuilder  func(id string) resource.Resource\n\t\tresourceModifier func(newSpec any) func(r resource.Resource) error\n\t}{\n\t\t// AddressSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Addresses),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Addresses[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\taddressSpec := spec.(network.AddressSpecSpec) //nolint:forcetypeassert\n\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.AddressID(addressSpec.LinkName, addressSpec.Address)), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewAddressSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.AddressSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.AddressSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// LinkSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Links),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Links[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\tlinkSpec := spec.(network.LinkSpecSpec) //nolint:forcetypeassert\n\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.LinkID(linkSpec.Name)), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewLinkSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.LinkSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.LinkSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\tif spec.Kind == network.LinkKindBond {\n\t\t\t\t\t\tnetworkadapter.BondMasterSpec(&spec.BondMaster).FillDefaults()\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// RouteSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Routes),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Routes[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\trouteSpec := spec.(network.RouteSpecSpec) //nolint:forcetypeassert\n\n\t\t\t\treturn network.LayeredID(\n\t\t\t\t\tnetwork.ConfigPlatform,\n\t\t\t\t\tnetwork.RouteID(routeSpec.Table, routeSpec.Family, routeSpec.Destination, routeSpec.Gateway, routeSpec.Priority, routeSpec.OutLinkName),\n\t\t\t\t), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewRouteSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.RouteSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.RouteSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// HostnameSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Hostnames),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Hostnames[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.HostnameID), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewHostnameSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.HostnameSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.HostnameSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// ResolverSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Resolvers),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Resolvers[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.ResolverID), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewResolverSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.ResolverSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.ResolverSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// TimeServerSpec\n\t\t{\n\t\t\tlength: len(networkConfig.TimeServers),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.TimeServers[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.TimeServerID), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewTimeServerSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.TimeServerSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.TimeServerSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// OperatorSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Operators),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Operators[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\toperatorSpec := spec.(network.OperatorSpecSpec) //nolint:forcetypeassert\n\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, network.OperatorID(operatorSpec)), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewOperatorSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.OperatorSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.OperatorSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// ExternalIPs\n\t\t{\n\t\t\tlength: len(networkConfig.ExternalIPs),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.ExternalIPs[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\tipAddr := spec.(netip.Addr) //nolint:forcetypeassert\n\t\t\t\tipPrefix := netip.PrefixFrom(ipAddr, ipAddr.BitLen())\n\n\t\t\t\treturn network.AddressID(externalLink, ipPrefix), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewAddressStatus(network.NamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tipAddr := newSpec.(netip.Addr) //nolint:forcetypeassert\n\t\t\t\t\tipPrefix := netip.PrefixFrom(ipAddr, ipAddr.BitLen())\n\n\t\t\t\t\tstatus := r.(*network.AddressStatus).TypedSpec()\n\n\t\t\t\t\tstatus.Address = ipPrefix\n\t\t\t\t\tstatus.LinkName = externalLink\n\n\t\t\t\t\tif ipAddr.Is4() {\n\t\t\t\t\t\tstatus.Family = nethelpers.FamilyInet4\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstatus.Family = nethelpers.FamilyInet6\n\t\t\t\t\t}\n\n\t\t\t\t\tstatus.Scope = nethelpers.ScopeGlobal\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// ProbeSpec\n\t\t{\n\t\t\tlength: len(networkConfig.Probes),\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Probes[i]\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\tprobeSpec := spec.(network.ProbeSpecSpec) //nolint:forcetypeassert\n\n\t\t\t\tid, err := probeSpec.ID()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\n\t\t\t\treturn network.LayeredID(network.ConfigPlatform, id), nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn network.NewProbeSpec(network.ConfigNamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tspec := r.(*network.ProbeSpec).TypedSpec()\n\n\t\t\t\t\t*spec = newSpec.(network.ProbeSpecSpec) //nolint:forcetypeassert\n\t\t\t\t\tspec.ConfigLayer = network.ConfigPlatform\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// Platform metadata\n\t\t{\n\t\t\tlength: metadataLength,\n\t\t\tgetter: func(i int) any {\n\t\t\t\treturn networkConfig.Metadata\n\t\t\t},\n\t\t\tidBuilder: func(spec any) (resource.ID, error) {\n\t\t\t\treturn runtimeres.PlatformMetadataID, nil\n\t\t\t},\n\t\t\tresourceBuilder: func(id string) resource.Resource {\n\t\t\t\treturn runtimeres.NewPlatformMetadataSpec(runtimeres.NamespaceName, id)\n\t\t\t},\n\t\t\tresourceModifier: func(newSpec any) func(r resource.Resource) error {\n\t\t\t\treturn func(r resource.Resource) error {\n\t\t\t\t\tmetadata := newSpec.(*runtimeres.PlatformMetadataSpec) //nolint:forcetypeassert\n\n\t\t\t\t\t*r.(*runtimeres.PlatformMetadata).TypedSpec() = *metadata\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t} {\n\t\ttouchedIDs := make(map[resource.ID]struct{}, specType.length)\n\n\t\tresourceEmpty := specType.resourceBuilder(\"\")\n\t\tresourceNamespace := resourceEmpty.Metadata().Namespace()\n\t\tresourceType := resourceEmpty.Metadata().Type()\n\n\t\tfor i := range specType.length {\n\t\t\tspec := specType.getter(i)\n\n\t\t\tid, err := specType.idBuilder(spec)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error building resource %s ID: %w\", resourceType, err)\n\t\t\t}\n\n\t\t\tif err = r.Modify(ctx, specType.resourceBuilder(id), specType.resourceModifier(spec)); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resource %s: %w\", resourceType, err)\n\t\t\t}\n\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\tlist, err := r.List(ctx, resource.NewMetadata(resourceNamespace, resourceType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting %s: %w\", res, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_apply_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype PlatformConfigApplySuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *PlatformConfigApplySuite) TestHostname() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigCachedID)\n\tplatformConfig.TypedSpec().Hostnames = []network.HostnameSpecSpec{\n\t\t{\n\t\t\tHostname:    \"talos-e2e-897b4e49-gcp-controlplane-jvcnl\",\n\t\t\tDomainname:  \"c.talos-testbed.internal\",\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResource(suite, \"platform/hostname\", func(hostname *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tspec := hostname.TypedSpec()\n\n\t\tasrt.Equal(\"talos-e2e-897b4e49-gcp-controlplane-jvcnl\", spec.Hostname)\n\t\tasrt.Equal(\"c.talos-testbed.internal\", spec.Domainname)\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestHostnameNoDomain() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Hostnames = []network.HostnameSpecSpec{\n\t\t{\n\t\t\tHostname:    \"talos-e2e-897b4e49-gcp-controlplane-jvcnl\",\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResource(suite, \"platform/hostname\", func(hostname *network.HostnameSpec, asrt *assert.Assertions) {\n\t\tspec := hostname.TypedSpec()\n\n\t\tasrt.Equal(\"talos-e2e-897b4e49-gcp-controlplane-jvcnl\", spec.Hostname)\n\t\tasrt.Equal(\"\", spec.Domainname)\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestAddresses() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Addresses = []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:     netip.MustParsePrefix(\"192.168.1.24/24\"),\n\t\t\tLinkName:    \"eth0\",\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t\t{\n\t\t\tAddress:     netip.MustParsePrefix(\"2001:fd::3/64\"),\n\t\t\tLinkName:    \"eth0\",\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/eth0/192.168.1.24/24\",\n\t\t\"platform/eth0/2001:fd::3/64\",\n\t}, func(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tswitch r.Metadata().ID() {\n\t\tcase \"platform/eth0/192.168.1.24/24\":\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, spec.Family)\n\t\t\tasrt.Equal(\"192.168.1.24/24\", spec.Address.String())\n\t\tcase \"platform/eth0/2001:fd::3/64\":\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, spec.Family)\n\t\t\tasrt.Equal(\"2001:fd::3/64\", spec.Address.String())\n\t\t}\n\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestLinks() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Links = []network.LinkSpecSpec{\n\t\t{\n\t\t\tName:        \"eth0\",\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t\t{\n\t\t\tName:        \"eth1\",\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/eth0\",\n\t\t\"platform/eth1\",\n\t}, func(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.True(spec.Up)\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestRoutes() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Routes = []network.RouteSpecSpec{\n\t\t{\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tGateway:     netip.MustParseAddr(\"10.0.0.1\"),\n\t\t\tOutLinkName: \"eth0\",\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tPriority:    1024,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/inet4/10.0.0.1//1024\",\n\t}, func(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(\"10.0.0.1\", spec.Gateway.String())\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestOperators() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Operators = []network.OperatorSpecSpec{\n\t\t{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tLinkName:    \"eth1\",\n\t\t\tOperator:    network.OperatorDHCP4,\n\t\t\tDHCP4:       network.DHCP4OperatorSpec{},\n\t\t},\n\t\t{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tLinkName:    \"eth2\",\n\t\t\tOperator:    network.OperatorDHCP4,\n\t\t\tDHCP4:       network.DHCP4OperatorSpec{},\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/dhcp4/eth1\",\n\t\t\"platform/dhcp4/eth2\",\n\t}, func(r *network.OperatorSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(network.OperatorDHCP4, spec.Operator)\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestResolvers() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Resolvers = []network.ResolverSpecSpec{\n\t\t{\n\t\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"1.1.1.1\")},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/resolvers\",\n\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(\"[1.1.1.1]\", fmt.Sprintf(\"%s\", spec.DNSServers))\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestTimeServers() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().TimeServers = []network.TimeServerSpecSpec{\n\t\t{\n\t\t\tNTPServers:  []string{\"pool.ntp.org\"},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/timeservers\",\n\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(\"[pool.ntp.org]\", fmt.Sprintf(\"%s\", spec.NTPServers))\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t}, rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *PlatformConfigApplySuite) TestProbes() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Probes = []network.ProbeSpecSpec{\n\t\t{\n\t\t\tInterval: time.Second,\n\t\t\tTCP: network.TCPProbeSpec{\n\t\t\t\tEndpoint: \"example.com:80\",\n\t\t\t\tTimeout:  time.Second,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t\t{\n\t\t\tInterval: time.Second,\n\t\t\tTCP: network.TCPProbeSpec{\n\t\t\t\tEndpoint: \"example.com:443\",\n\t\t\t\tTimeout:  time.Second,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"platform/tcp:example.com:80\",\n\t\t\"platform/tcp:example.com:443\",\n\t}, func(r *network.ProbeSpec, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(time.Second, spec.Interval)\n\t\tasrt.Equal(network.ConfigPlatform, spec.ConfigLayer)\n\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *PlatformConfigApplySuite) TestExternalIPs() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().ExternalIPs = []netip.Addr{\n\t\tnetip.MustParseAddr(\"10.3.4.5\"),\n\t\tnetip.MustParseAddr(\"2001:470:6d:30e:96f4:4219:5733:b860\"),\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResources(suite, []string{\n\t\t\"external/10.3.4.5/32\",\n\t\t\"external/2001:470:6d:30e:96f4:4219:5733:b860/128\",\n\t}, func(r *network.AddressStatus, asrt *assert.Assertions) {\n\t\tspec := r.TypedSpec()\n\n\t\tasrt.Equal(\"external\", spec.LinkName)\n\t\tasrt.Equal(nethelpers.ScopeGlobal, spec.Scope)\n\n\t\tif r.Metadata().ID() == \"external/10.3.4.5/32\" {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, spec.Family)\n\t\t} else {\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, spec.Family)\n\t\t}\n\t})\n}\n\nfunc (suite *PlatformConfigApplySuite) TestMetadata() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform: \"mock\",\n\t\tZone:     \"mock-zone\",\n\t}\n\tsuite.Create(platformConfig)\n\n\tctest.AssertResource(suite, runtimeres.PlatformMetadataID,\n\t\tfunc(r *runtimeres.PlatformMetadata, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"mock\", r.TypedSpec().Platform)\n\t\t\tasrt.Equal(\"mock-zone\", r.TypedSpec().Zone)\n\t\t})\n}\n\nfunc (suite *PlatformConfigApplySuite) TestNoPlatformConfig() {\n\tctest.AssertResource(suite, runtimeres.PlatformMetadataID,\n\t\tfunc(r *runtimeres.PlatformMetadata, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"metal\", r.TypedSpec().Platform)\n\t\t})\n}\n\nfunc TestPlatformConfigApplySuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &PlatformConfigApplySuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(\n\t\t\t\t\tsuite.Runtime().RegisterController(\n\t\t\t\t\t\t&netctrl.PlatformConfigApplyController{\n\t\t\t\t\t\t\tV1alpha1Platform: &metal.Metal{},\n\t\t\t\t\t\t},\n\t\t\t\t\t))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_load.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"go.yaml.in/yaml/v4\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// PlatformConfigLoadController loads cached platform network config from STATE.\ntype PlatformConfigLoadController struct {\n\tstateMachine blockautomaton.VolumeMounterAutomaton\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PlatformConfigLoadController) Name() string {\n\treturn \"network.PlatformConfigLoadController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigLoadController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigLoadController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.PlatformConfigType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *PlatformConfigLoadController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif ctrl.stateMachine == nil {\n\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\tctrl.Name(),\n\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\tctrl.load(),\n\t\t\t\tblockautomaton.WithReadOnly(true),\n\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t)\n\t\t}\n\n\t\tif err := ctrl.stateMachine.Run(ctx, r, logger,\n\t\t\tautomaton.WithAfterFunc(func() error {\n\t\t\t\tctrl.stateMachine = nil\n\n\t\t\t\treturn nil\n\t\t\t}),\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error running volume mounter machine: %w\", err)\n\t\t}\n\n\t\tif ctrl.stateMachine == nil {\n\t\t\t// we read only once, so once read, we should stop\n\t\t\treturn nil\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *PlatformConfigLoadController) load() func(\n\tctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus,\n) error {\n\treturn func(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\t\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\t\tcachedNetworkConfig, err := ctrl.loadConfig(root, constants.PlatformNetworkConfigFilename)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Warn(\"ignored failure loading cached platform network config\", zap.Error(err))\n\t\t\t} else if cachedNetworkConfig != nil {\n\t\t\t\tlogger.Debug(\"loaded cached platform network config\")\n\t\t\t}\n\n\t\t\tif cachedNetworkConfig != nil {\n\t\t\t\tif err := safe.WriterModify(ctx, r,\n\t\t\t\t\tnetwork.NewPlatformConfig(network.NamespaceName, network.PlatformConfigCachedID),\n\t\t\t\t\tfunc(out *network.PlatformConfig) error {\n\t\t\t\t\t\t*out.TypedSpec() = *cachedNetworkConfig\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error modifying cached platform network config: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc (ctrl *PlatformConfigLoadController) loadConfig(root xfs.Root, path string) (*network.PlatformConfigSpec, error) {\n\tmarshaled, err := xfs.ReadFile(root, path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tvar networkConfig network.PlatformConfigSpec\n\n\tif err = yaml.Unmarshal(marshaled, &networkConfig); err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshaling network config: %w\", err)\n\t}\n\n\treturn &networkConfig, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_load_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype PlatformConfigLoadSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *PlatformConfigLoadSuite) TestLoadConfig() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&netctrl.PlatformConfigLoadController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tsuite.Require().NoError(\n\t\tos.WriteFile(\n\t\t\tfilepath.Join(statePath, constants.PlatformNetworkConfigFilename),\n\t\t\t[]byte(sampleStoredConfig),\n\t\t\t0o400,\n\t\t),\n\t)\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertResource(suite, network.PlatformConfigCachedID, func(cachedConfig *network.PlatformConfig, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t[]network.HostnameSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tHostname: \"talos-e2e-897b4e49-gcp-controlplane-jvcnl\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcachedConfig.TypedSpec().Hostnames,\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]netip.Addr{\n\t\t\t\tnetip.MustParseAddr(\"10.3.4.5\"),\n\t\t\t\tnetip.MustParseAddr(\"2001:470:6d:30e:96f4:4219:5733:b860\"),\n\t\t\t},\n\t\t\tcachedConfig.TypedSpec().ExternalIPs,\n\t\t)\n\t})\n}\n\nfunc TestPlatformConfigLoadSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.Run(t, &PlatformConfigLoadSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(\n\t\t\t\t\tsuite.Runtime().RegisterController(&netctrl.PlatformConfigLoadController{}),\n\t\t\t\t)\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_store.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"go.yaml.in/yaml/v4\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// PlatformConfigStoreController stores (caches) active platform network config in STATE.\ntype PlatformConfigStoreController struct {\n\tstateMachine                    blockautomaton.VolumeMounterAutomaton\n\tconfigToStore, lastStoredConfig *network.PlatformConfig\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *PlatformConfigStoreController) Name() string {\n\treturn \"network.PlatformConfigStoreController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigStoreController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.PlatformConfigType,\n\t\t\tID:        optional.Some(network.PlatformConfigActiveID),\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *PlatformConfigStoreController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *PlatformConfigStoreController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tactiveConfig, err := safe.ReaderGetByID[*network.PlatformConfig](ctx, r, network.PlatformConfigActiveID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// no active network config found, wait more\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting active network config: %w\", err)\n\t\t}\n\n\t\t// if we haven't stored any config yet, or the active config has changed\n\t\tif ctrl.lastStoredConfig == nil || !activeConfig.TypedSpec().Equal(ctrl.lastStoredConfig.TypedSpec()) {\n\t\t\tctrl.configToStore = activeConfig\n\t\t}\n\n\t\tif ctrl.stateMachine == nil && ctrl.configToStore != nil {\n\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\tctrl.Name(),\n\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\tctrl.store(),\n\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t)\n\t\t}\n\n\t\tif ctrl.stateMachine != nil {\n\t\t\tif err := ctrl.stateMachine.Run(ctx, r, logger,\n\t\t\t\tautomaton.WithAfterFunc(func() error {\n\t\t\t\t\tctrl.stateMachine = nil\n\n\t\t\t\t\treturn nil\n\t\t\t\t}),\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error running volume mounter machine: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *PlatformConfigStoreController) store() func(\n\tctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus,\n) error {\n\treturn func(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\t\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\t\tif err := ctrl.storeConfig(root, constants.PlatformNetworkConfigFilename, ctrl.configToStore); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error saving platform network config: %w\", err)\n\t\t\t}\n\n\t\t\t// remember last stored config\n\t\t\tctrl.lastStoredConfig, ctrl.configToStore = ctrl.configToStore, nil\n\n\t\t\tlogger.Debug(\"stored active platform network config\")\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc (ctrl *PlatformConfigStoreController) storeConfig(root xfs.Root, path string, networkConfig *network.PlatformConfig) error {\n\tmarshaled, err := yaml.Marshal(networkConfig.TypedSpec())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling network config: %w\", err)\n\t}\n\n\tif _, err := xfs.Stat(root, path); err == nil {\n\t\texisting, err := xfs.ReadFile(root, path)\n\t\tif err == nil && bytes.Equal(marshaled, existing) {\n\t\t\t// existing contents are identical, skip writing to avoid no-op writes\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn xfs.WriteFile(root, path, marshaled, 0o400)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_store_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype PlatformConfigStoreSuite struct {\n\tctest.DefaultSuite\n}\n\nconst sampleStoredConfig = \"addresses: []\\nlinks: []\\nroutes: []\\nhostnames:\\n    - hostname: talos-e2e-897b4e49-gcp-controlplane-jvcnl\\n      domainname: \\\"\\\"\\n      layer: default\\nresolvers: []\\ntimeServers: []\\noperators: []\\nexternalIPs:\\n    - 10.3.4.5\\n    - 2001:470:6d:30e:96f4:4219:5733:b860\\n\" //nolint:lll\n\nfunc (suite *PlatformConfigStoreSuite) TestStoreConfig() {\n\tplatformConfig := network.NewPlatformConfig(network.NamespaceName, network.PlatformConfigActiveID)\n\tplatformConfig.TypedSpec().Hostnames = []network.HostnameSpecSpec{\n\t\t{\n\t\t\tHostname: \"talos-e2e-897b4e49-gcp-controlplane-jvcnl\",\n\t\t},\n\t}\n\tplatformConfig.TypedSpec().ExternalIPs = []netip.Addr{\n\t\tnetip.MustParseAddr(\"10.3.4.5\"),\n\t\tnetip.MustParseAddr(\"2001:470:6d:30e:96f4:4219:5733:b860\"),\n\t}\n\tsuite.Create(platformConfig)\n\n\tstatePath := suite.T().TempDir()\n\tmountID := (&netctrl.PlatformConfigStoreController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tcontents, err := os.ReadFile(filepath.Join(statePath, constants.PlatformNetworkConfigFilename))\n\t\tasrt.NoError(err)\n\n\t\tasrt.Equal(sampleStoredConfig, string(contents))\n\t}, time.Second, 10*time.Millisecond)\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\t// do an update which should not trigger store operation\n\tplatformConfig.Metadata().Labels().Set(\"foo\", \"bar\")\n\tsuite.Update(platformConfig)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\t// now update configuration\n\tplatformConfig.TypedSpec().Hostnames = nil\n\tsuite.Update(platformConfig)\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n}\n\nfunc TestPlatformConfigStoreSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.Run(t, &PlatformConfigStoreSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(\n\t\t\t\t\tsuite.Runtime().RegisterController(&netctrl.PlatformConfigStoreController{}),\n\t\t\t\t)\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/platform_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"context\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype PlatformConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *PlatformConfigSuite) TestNoPlatform() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.PlatformConfigController{}))\n\n\tctest.AssertNoResource[*network.PlatformConfig](suite, network.PlatformConfigActiveID)\n}\n\nfunc (suite *PlatformConfigSuite) TestPlatform() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.PlatformConfigController{\n\t\t\t\tV1alpha1Platform: &platformMock{\n\t\t\t\t\thostname: []byte(\"talos-e2e-897b4e49-gcp-controlplane-jvcnl.c.talos-testbed.internal\"),\n\t\t\t\t\taddresses: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.168.1.24/24\"),\n\t\t\t\t\t\tnetip.MustParsePrefix(\"2001:fd::3/64\"),\n\t\t\t\t\t},\n\t\t\t\t\tdefaultRoutes: []netip.Addr{netip.MustParseAddr(\"10.0.0.1\")},\n\t\t\t\t\tlinksUp:       []string{\"eth0\", \"eth1\"},\n\t\t\t\t\tdhcp4Links:    []string{\"eth1\", \"eth2\"},\n\t\t\t\t\tresolvers:     []netip.Addr{netip.MustParseAddr(\"1.1.1.1\")},\n\t\t\t\t\ttimeServers:   []string{\"pool.ntp.org\"},\n\t\t\t\t\ttcpProbes:     []string{\"example.com:80\", \"example.com:443\"},\n\t\t\t\t\texternalIPs: []netip.Addr{\n\t\t\t\t\t\tnetip.MustParseAddr(\"10.3.4.5\"),\n\t\t\t\t\t\tnetip.MustParseAddr(\"2001:470:6d:30e:96f4:4219:5733:b860\"),\n\t\t\t\t\t},\n\t\t\t\t\tmetadata: &runtimeres.PlatformMetadataSpec{\n\t\t\t\t\t\tPlatform: \"mock\",\n\t\t\t\t\t\tZone:     \"mock-zone\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResource(suite, network.PlatformConfigActiveID, func(cfg *network.PlatformConfig, asrt *assert.Assertions) {\n\t\tspec := cfg.TypedSpec()\n\n\t\tasrt.Equal(\n\t\t\t[]string{\"talos-e2e-897b4e49-gcp-controlplane-jvcnl.c.talos-testbed.internal\"},\n\t\t\txslices.Map(spec.Hostnames, func(h network.HostnameSpecSpec) string {\n\t\t\t\treturn h.FQDN()\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"192.168.1.24/24\", \"2001:fd::3/64\"},\n\t\t\txslices.Map(spec.Addresses, func(a network.AddressSpecSpec) string {\n\t\t\t\treturn a.Address.String()\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"10.0.0.1\"},\n\t\t\txslices.Map(spec.Routes, func(r network.RouteSpecSpec) string {\n\t\t\t\treturn r.Gateway.String()\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"eth0\", \"eth1\"},\n\t\t\txslices.Map(spec.Links, func(l network.LinkSpecSpec) string {\n\t\t\t\treturn l.Name\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"eth1\", \"eth2\"},\n\t\t\txslices.Map(spec.Operators, func(l network.OperatorSpecSpec) string {\n\t\t\t\treturn l.LinkName\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"1.1.1.1\"},\n\t\t\txslices.Map(spec.Resolvers, func(r network.ResolverSpecSpec) string {\n\t\t\t\treturn strings.Join(xslices.Map(r.DNSServers, netip.Addr.String), \", \")\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"pool.ntp.org\"},\n\t\t\txslices.Map(spec.TimeServers, func(t network.TimeServerSpecSpec) string {\n\t\t\t\treturn strings.Join(t.NTPServers, \", \")\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"example.com:80\", \"example.com:443\"},\n\t\t\txslices.Map(spec.Probes, func(p network.ProbeSpecSpec) string {\n\t\t\t\treturn p.TCP.Endpoint\n\t\t\t}),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t[]string{\"10.3.4.5\", \"2001:470:6d:30e:96f4:4219:5733:b860\"},\n\t\t\txslices.Map(spec.ExternalIPs, netip.Addr.String),\n\t\t)\n\t\tasrt.Equal(\n\t\t\t\"mock\",\n\t\t\tspec.Metadata.Platform,\n\t\t)\n\t\tasrt.Equal(\n\t\t\t\"mock-zone\",\n\t\t\tspec.Metadata.Zone,\n\t\t)\n\t})\n}\n\nfunc TestPlatformConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &PlatformConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n\ntype platformMock struct {\n\tnoData bool\n\n\thostname      []byte\n\texternalIPs   []netip.Addr\n\taddresses     []netip.Prefix\n\tdefaultRoutes []netip.Addr\n\tlinksUp       []string\n\tresolvers     []netip.Addr\n\ttimeServers   []string\n\tdhcp4Links    []string\n\ttcpProbes     []string\n\n\tmetadata *runtimeres.PlatformMetadataSpec\n}\n\nfunc (mock *platformMock) Name() string {\n\treturn \"mock\"\n}\n\nfunc (mock *platformMock) Configuration(context.Context, state.State) ([]byte, error) {\n\treturn nil, nil\n}\n\nfunc (mock *platformMock) Metadata(context.Context, state.State) (runtimeres.PlatformMetadataSpec, error) {\n\treturn runtimeres.PlatformMetadataSpec{Platform: mock.Name()}, nil\n}\n\nfunc (mock *platformMock) Mode() v1alpha1runtime.Mode {\n\treturn v1alpha1runtime.ModeCloud\n}\n\nfunc (mock *platformMock) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (mock *platformMock) NetworkConfiguration(\n\tctx context.Context,\n\tst state.State,\n\tch chan<- *v1alpha1runtime.PlatformNetworkConfig,\n) error {\n\tif mock.noData {\n\t\treturn nil\n\t}\n\n\tnetworkConfig := &v1alpha1runtime.PlatformNetworkConfig{\n\t\tExternalIPs: mock.externalIPs,\n\t}\n\n\tif mock.hostname != nil {\n\t\thostnameSpec := network.HostnameSpecSpec{}\n\t\tif err := hostnameSpec.ParseFQDN(string(mock.hostname)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = []network.HostnameSpecSpec{hostnameSpec}\n\t}\n\n\tfor _, addr := range mock.addresses {\n\t\tfamily := nethelpers.FamilyInet4\n\t\tif addr.Addr().Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\tnetworkConfig.Addresses = append(\n\t\t\tnetworkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\tAddress:     addr,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      family,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, gw := range mock.defaultRoutes {\n\t\tfamily := nethelpers.FamilyInet4\n\t\tif gw.Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     gw,\n\t\t\tOutLinkName: \"eth0\",\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      family,\n\t\t\tPriority:    1024,\n\t\t}\n\n\t\troute.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t}\n\n\tfor _, link := range mock.linksUp {\n\t\tnetworkConfig.Links = append(\n\t\t\tnetworkConfig.Links, network.LinkSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tName:        link,\n\t\t\t\tUp:          true,\n\t\t\t},\n\t\t)\n\t}\n\n\tif len(mock.resolvers) > 0 {\n\t\tnetworkConfig.Resolvers = append(\n\t\t\tnetworkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tDNSServers:  mock.resolvers,\n\t\t\t},\n\t\t)\n\t}\n\n\tif len(mock.timeServers) > 0 {\n\t\tnetworkConfig.TimeServers = append(\n\t\t\tnetworkConfig.TimeServers, network.TimeServerSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tNTPServers:  mock.timeServers,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, link := range mock.dhcp4Links {\n\t\tnetworkConfig.Operators = append(\n\t\t\tnetworkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    link,\n\t\t\t\tOperator:    network.OperatorDHCP4,\n\t\t\t\tDHCP4:       network.DHCP4OperatorSpec{},\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, endpoint := range mock.tcpProbes {\n\t\tnetworkConfig.Probes = append(\n\t\t\tnetworkConfig.Probes, network.ProbeSpecSpec{\n\t\t\t\tInterval: time.Second,\n\t\t\t\tTCP: network.TCPProbeSpec{\n\t\t\t\t\tEndpoint: endpoint,\n\t\t\t\t\tTimeout:  time.Second,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t}\n\n\tnetworkConfig.Metadata = mock.metadata\n\n\tfor range 5 { // send the network config multiple times to test duplicate suppression\n\t\tselect {\n\t\tcase ch <- networkConfig:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/internal/probe\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ProbeController runs network probes configured with ProbeSpecs and outputs ProbeStatuses.\ntype ProbeController struct {\n\trunners map[string]*probe.Runner\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ProbeController) Name() string {\n\treturn \"network.ProbeController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ProbeController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.ProbeSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ProbeController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.ProbeStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *ProbeController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tnotifyCh := make(chan probe.Notification)\n\n\tctrl.runners = make(map[string]*probe.Runner)\n\n\tdefer func() {\n\t\tfor _, runner := range ctrl.runners {\n\t\t\trunner.Stop()\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tif err := ctrl.reconcileRunners(ctx, r, logger, notifyCh); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase ev := <-notifyCh:\n\t\t\tif err := ctrl.reconcileOutputs(ctx, r, ev); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *ProbeController) reconcileRunners(ctx context.Context, r controller.Runtime, logger *zap.Logger, notifyCh chan<- probe.Notification) error {\n\tspecList, err := safe.ReaderListAll[*network.ProbeSpec](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing probe specs: %w\", err)\n\t}\n\n\t// figure out which operators should run\n\tshouldRun := make(map[string]network.ProbeSpecSpec)\n\n\tfor probeSpec := range specList.All() {\n\t\tshouldRun[probeSpec.Metadata().ID()] = *probeSpec.TypedSpec()\n\t}\n\n\t// stop running probes which shouldn't run\n\tfor id := range ctrl.runners {\n\t\tif _, exists := shouldRun[id]; !exists {\n\t\t\tlogger.Debug(\"stopping probe\", zap.String(\"probe\", id))\n\n\t\t\tctrl.runners[id].Stop()\n\t\t\tdelete(ctrl.runners, id)\n\t\t} else if !shouldRun[id].Equal(ctrl.runners[id].Spec) {\n\t\t\tlogger.Debug(\"replacing probe\", zap.String(\"probe\", id))\n\n\t\t\tctrl.runners[id].Stop()\n\t\t\tdelete(ctrl.runners, id)\n\t\t}\n\t}\n\n\t// start probes which aren't running\n\tfor id := range shouldRun {\n\t\tif _, exists := ctrl.runners[id]; !exists {\n\t\t\tctrl.runners[id] = &probe.Runner{\n\t\t\t\tID:   id,\n\t\t\t\tSpec: shouldRun[id],\n\t\t\t}\n\n\t\t\tlogger.Debug(\"starting probe\", zap.String(\"probe\", id))\n\t\t\tctrl.runners[id].Start(ctx, notifyCh, logger)\n\t\t}\n\t}\n\n\t// clean up statuses which should no longer exist\n\tstatusList, err := safe.ReaderListAll[*network.ProbeStatus](ctx, r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing probe statuses: %w\", err)\n\t}\n\n\tfor res := range statusList.All() {\n\t\tif _, exists := shouldRun[res.Metadata().ID()]; exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error destroying probe status: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *ProbeController) reconcileOutputs(ctx context.Context, r controller.Runtime, ev probe.Notification) error {\n\tif _, exists := ctrl.runners[ev.ID]; !exists {\n\t\t// probe was already removed, late notification, ignore it\n\t\treturn nil\n\t}\n\n\treturn safe.WriterModify(ctx, r, network.NewProbeStatus(network.NamespaceName, ev.ID),\n\t\tfunc(status *network.ProbeStatus) error {\n\t\t\t*status.TypedSpec() = ev.Status\n\n\t\t\treturn nil\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ProbeConfigController manages network.ProbeSpec based on ProbeConfig documents in machine configuration.\ntype ProbeConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ProbeConfigController) Name() string {\n\treturn \"network.ProbeConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ProbeConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ProbeConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.ProbeSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *ProbeConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar specs []network.ProbeSpecSpec\n\n\t\t// parse machine configuration for probe config documents\n\t\tif cfg != nil {\n\t\t\tconfigSpecs := ctrl.parseMachineConfiguration(cfg)\n\t\t\tspecs = append(specs, configSpecs...)\n\t\t}\n\n\t\tif err = ctrl.apply(ctx, r, specs); err != nil {\n\t\t\treturn fmt.Errorf(\"error applying specs: %w\", err)\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx,\n\t\t\tresource.NewMetadata(network.ConfigNamespaceName, network.ProbeSpecType, \"\", resource.VersionUndefined),\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning up outputs: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *ProbeConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.ProbeSpecSpec) error {\n\tfor _, spec := range specs {\n\t\tid, err := spec.ID()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting probe spec ID: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewProbeSpec(network.ConfigNamespaceName, network.LayeredID(spec.ConfigLayer, id)),\n\t\t\tfunc(r *network.ProbeSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying probe spec: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *ProbeConfigController) parseMachineConfiguration(cfg *config.MachineConfig) []network.ProbeSpecSpec {\n\tprobeConfigs := cfg.Config().NetworkProbeConfigs()\n\tspecs := make([]network.ProbeSpecSpec, 0, len(probeConfigs))\n\n\tfor _, probeConfig := range probeConfigs {\n\t\tspec := network.ProbeSpecSpec{\n\t\t\tInterval:         probeConfig.Interval(),\n\t\t\tFailureThreshold: probeConfig.FailureThreshold(),\n\t\t\tConfigLayer:      network.ConfigMachineConfiguration,\n\t\t}\n\n\t\tswitch probeConfig := probeConfig.(type) {\n\t\tcase configconfig.NetworkTCPProbeConfig:\n\t\t\tspec.TCP = network.TCPProbeSpec{\n\t\t\t\tEndpoint: probeConfig.Endpoint(),\n\t\t\t\tTimeout:  probeConfig.Timeout(),\n\t\t\t}\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unsupported probe config type: %T\", probeConfig))\n\t\t}\n\n\t\tspecs = append(specs, spec)\n\t}\n\n\treturn specs\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ProbeConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ProbeConfigSuite) TestNoConfig() {\n\t// With no config, no ProbeSpec resources should be created\n\tctest.AssertNoResource[*network.ProbeSpec](suite, \"tcp:proxy.example.com:3128\", rtestutils.WithNamespace(network.NamespaceName))\n}\n\nfunc (suite *ProbeConfigSuite) TestSingleProbe() {\n\tprobeConfig := networkcfg.NewTCPProbeConfigV1Alpha1(\"proxy-check\")\n\tprobeConfig.ProbeInterval = time.Second\n\tprobeConfig.ProbeFailureThreshold = 3\n\tprobeConfig.TCPEndpoint = \"proxy.example.com:3128\"\n\tprobeConfig.TCPTimeout = 10 * time.Second\n\n\tctr, err := container.New(probeConfig)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/tcp:proxy.example.com:3128\",\n\t\t}, func(r *network.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(time.Second, r.TypedSpec().Interval)\n\t\t\tasrt.Equal(3, r.TypedSpec().FailureThreshold)\n\t\t\tasrt.Equal(\"proxy.example.com:3128\", r.TypedSpec().TCP.Endpoint)\n\t\t\tasrt.Equal(10*time.Second, r.TypedSpec().TCP.Timeout)\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// Update the probe config\n\tctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error {\n\t\tdocs := r.Container().Documents()\n\t\tprobeDoc := docs[0].(*networkcfg.TCPProbeConfigV1Alpha1)\n\t\tprobeDoc.ProbeFailureThreshold = 5\n\n\t\treturn nil\n\t})\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/tcp:proxy.example.com:3128\",\n\t\t}, func(r *network.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(5, r.TypedSpec().FailureThreshold)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// Remove the config\n\tsuite.Destroy(cfg)\n\n\tctest.AssertNoResource[*network.ProbeSpec](suite, \"configuration/tcp:proxy.example.com:3128\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *ProbeConfigSuite) TestMultipleProbes() {\n\t// Create first probe\n\tprobeConfig1 := networkcfg.NewTCPProbeConfigV1Alpha1(\"proxy-check\")\n\tprobeConfig1.ProbeInterval = time.Second\n\tprobeConfig1.ProbeFailureThreshold = 3\n\tprobeConfig1.TCPEndpoint = \"proxy.example.com:3128\"\n\tprobeConfig1.TCPTimeout = 10 * time.Second\n\n\t// Create second probe\n\tprobeConfig2 := networkcfg.NewTCPProbeConfigV1Alpha1(\"dns-check\")\n\tprobeConfig2.ProbeInterval = 5 * time.Second\n\tprobeConfig2.ProbeFailureThreshold = 2\n\tprobeConfig2.TCPEndpoint = \"8.8.8.8:53\"\n\tprobeConfig2.TCPTimeout = 5 * time.Second\n\n\tctr, err := container.New(probeConfig1, probeConfig2)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\t// Verify both probes are created\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/tcp:proxy.example.com:3128\",\n\t\t}, func(r *network.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"proxy.example.com:3128\", r.TypedSpec().TCP.Endpoint)\n\t\t\tasrt.Equal(3, r.TypedSpec().FailureThreshold)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/tcp:8.8.8.8:53\",\n\t\t}, func(r *network.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"8.8.8.8:53\", r.TypedSpec().TCP.Endpoint)\n\t\t\tasrt.Equal(2, r.TypedSpec().FailureThreshold)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tsuite.Destroy(cfg)\n\n\t// Verify both probes are removed\n\tctest.AssertNoResource[*network.ProbeSpec](suite, \"configuration/tcp:proxy.example.com:3128\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n\tctest.AssertNoResource[*network.ProbeSpec](suite, \"configuration/tcp:8.8.8.8:53\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc TestProbeConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ProbeConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.ProbeConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"cmp\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewProbeMergeController initializes a ProbeMergeController.\n//\n// ProbeMergeController merges network.ProbeSpec in network.ConfigNamespace and produces final network.ProbeSpec in network.Namespace.\nfunc NewProbeMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.ProbeSpec]) map[resource.ID]*network.ProbeSpecSpec {\n\t\t\t// sort by link name, configuration layer\n\t\t\tlist.SortFunc(func(left, right *network.ProbeSpec) int {\n\t\t\t\treturn cmp.Compare(left.TypedSpec().ConfigLayer, right.TypedSpec().ConfigLayer)\n\t\t\t})\n\n\t\t\t// build final probe definition merging multiple layers\n\t\t\tprobes := make(map[string]*network.ProbeSpecSpec, list.Len())\n\n\t\t\tfor probe := range list.All() {\n\t\t\t\tid, err := probe.TypedSpec().ID()\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Warn(\"error getting probe ID\", zap.Error(err))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// no way to actually have multiple probes with the same ID in different layers,\n\t\t\t\t// so we can just merge them one by one\n\t\t\t\tprobes[id] = probe.TypedSpec()\n\t\t\t}\n\n\t\t\treturn probes\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ProbeMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ProbeMergeSuite) TestMerge() {\n\tp1 := network.NewProbeSpec(network.ConfigNamespaceName, \"configuration/tcp:proxy.example.com:3128\")\n\t*p1.TypedSpec() = network.ProbeSpecSpec{\n\t\tInterval:         time.Second,\n\t\tFailureThreshold: 3,\n\t\tTCP: network.TCPProbeSpec{\n\t\t\tEndpoint: \"proxy.example.com:3128\",\n\t\t\tTimeout:  10 * time.Second,\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tp2 := network.NewProbeSpec(network.ConfigNamespaceName, \"platform/tcp:proxy.example.com:3128\")\n\t*p2.TypedSpec() = network.ProbeSpecSpec{\n\t\tInterval:         5 * time.Second,\n\t\tFailureThreshold: 5,\n\t\tTCP: network.TCPProbeSpec{\n\t\t\tEndpoint: \"proxy.example.com:3128\",\n\t\t\tTimeout:  5 * time.Second,\n\t\t},\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tp3 := network.NewProbeSpec(network.ConfigNamespaceName, \"configuration/tcp:google.com:80\")\n\t*p3.TypedSpec() = network.ProbeSpecSpec{\n\t\tInterval:         2 * time.Second,\n\t\tFailureThreshold: 4,\n\t\tTCP: network.TCPProbeSpec{\n\t\t\tEndpoint: \"google.com:80\",\n\t\t\tTimeout:  3 * time.Second,\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{p1, p2, p3} {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(suite, []resource.ID{\"tcp:proxy.example.com:3128\", \"tcp:google.com:80\"},\n\t\tfunc(p *network.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tif p.Metadata().ID() == \"tcp:proxy.example.com:3128\" {\n\t\t\t\tasrt.Equal(time.Second, p.TypedSpec().Interval)\n\t\t\t\tasrt.Equal(3, p.TypedSpec().FailureThreshold)\n\t\t\t\tasrt.Equal(\"proxy.example.com:3128\", p.TypedSpec().TCP.Endpoint)\n\t\t\t\tasrt.Equal(10*time.Second, p.TypedSpec().TCP.Timeout)\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(p3)\n\n\tctest.AssertNoResource[*network.ProbeSpec](suite, \"tcp:google.com:80\")\n}\n\nfunc TestProbeMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ProbeMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewProbeMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/probe_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetworkctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ProbeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ProbeSuite) TestReconcile() {\n\tgoogleProbeSpec := network.ProbeSpecSpec{\n\t\tInterval: 100 * time.Millisecond,\n\t\tTCP: network.TCPProbeSpec{\n\t\t\tEndpoint: \"google.com:80\",\n\t\t\tTimeout:  5 * time.Second,\n\t\t},\n\t}\n\tgoogleProbeSpecID, err := googleProbeSpec.ID()\n\tsuite.Require().NoError(err)\n\n\tprobeGoogle := network.NewProbeSpec(network.NamespaceName, googleProbeSpecID)\n\t*probeGoogle.TypedSpec() = googleProbeSpec\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), probeGoogle))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{googleProbeSpecID}, func(r *network.ProbeStatus, assert *assert.Assertions) {\n\t\tassert.Equal(network.ProbeStatusSpec{\n\t\t\tSuccess: true,\n\t\t}, *r.TypedSpec())\n\t})\n\n\tfailingProbeSpec := network.ProbeSpecSpec{\n\t\tInterval:         100 * time.Millisecond,\n\t\tFailureThreshold: 1,\n\t\tTCP: network.TCPProbeSpec{\n\t\t\tEndpoint: \"google.com:81\",\n\t\t\tTimeout:  time.Second,\n\t\t},\n\t}\n\tfailingProbeSpecID, err := failingProbeSpec.ID()\n\tsuite.Require().NoError(err)\n\n\tprobeFailing := network.NewProbeSpec(network.NamespaceName, failingProbeSpecID)\n\t*probeFailing.TypedSpec() = failingProbeSpec\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), probeFailing))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{failingProbeSpecID}, func(r *network.ProbeStatus, assert *assert.Assertions) {\n\t\tassert.False(r.TypedSpec().Success)\n\t})\n\n\tprobeFailing.TypedSpec().TCP.Endpoint = \"google.com:443\"\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), probeFailing))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{failingProbeSpecID}, func(r *network.ProbeStatus, assert *assert.Assertions) {\n\t\tassert.Equal(network.ProbeStatusSpec{\n\t\t\tSuccess: true,\n\t\t}, *r.TypedSpec())\n\t})\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), probeFailing.Metadata()))\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), probeGoogle.Metadata()))\n\n\trtestutils.AssertNoResource[*network.ProbeStatus](suite.Ctx(), suite.T(), suite.State(), failingProbeSpecID)\n\trtestutils.AssertNoResource[*network.ProbeStatus](suite.Ctx(), suite.T(), suite.State(), googleProbeSpecID)\n}\n\n// TestProbeSuite runs the ProbeSuite.\nfunc TestProbeSuite(t *testing.T) {\n\tsuite.Run(t, &ProbeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 20 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&networkctrl.ProbeController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ResolverConfigController manages network.ResolverSpec based on machine configuration, kernel cmdline.\ntype ResolverConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ResolverConfigController) Name() string {\n\treturn \"network.ResolverConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ResolverConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ResolverConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.ResolverSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ResolverConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\tvar specs []network.ResolverSpecSpec\n\n\t\thostnameStatus, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting hostname status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar hostnameStatusSpec *network.HostnameStatusSpec\n\t\tif hostnameStatus != nil {\n\t\t\thostnameStatusSpec = hostnameStatus.TypedSpec()\n\t\t}\n\n\t\t// defaults\n\t\tspecs = append(specs, ctrl.getDefault(cfgProvider, hostnameStatusSpec))\n\n\t\t// parse kernel cmdline for the default gateway\n\t\tcmdlineServers := ctrl.parseCmdline(logger)\n\t\tif cmdlineServers.DNSServers != nil {\n\t\t\tspecs = append(specs, cmdlineServers)\n\t\t}\n\n\t\t// parse machine configuration for specs\n\t\tif cfgProvider != nil {\n\t\t\tif configServers, ok := ctrl.parseMachineConfiguration(cfgProvider); ok {\n\t\t\t\tspecs = append(specs, configServers)\n\t\t\t}\n\t\t}\n\n\t\tvar ids []string\n\n\t\tids, err = ctrl.apply(ctx, r, specs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error applying specs: %w\", err)\n\t\t}\n\n\t\tfor _, id := range ids {\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\t// list specs for cleanup\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.ResolverSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\t// skip specs created by other controllers\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *ResolverConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.ResolverSpecSpec) ([]resource.ID, error) {\n\tids := make([]string, 0, len(specs))\n\n\tfor _, spec := range specs {\n\t\tid := network.LayeredID(spec.ConfigLayer, network.ResolverID)\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewResolverSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.ResolverSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn ids, err\n\t\t}\n\n\t\tids = append(ids, id)\n\t}\n\n\treturn ids, nil\n}\n\nfunc (ctrl *ResolverConfigController) getDefault(cfg talosconfig.Config, hostnameStatus *network.HostnameStatusSpec) (spec network.ResolverSpecSpec) {\n\tspec.DNSServers = []netip.Addr{netip.MustParseAddr(constants.DefaultPrimaryResolver), netip.MustParseAddr(constants.DefaultSecondaryResolver)}\n\tspec.ConfigLayer = network.ConfigDefault\n\n\tif cfg == nil ||\n\t\tcfg.NetworkResolverConfig() == nil ||\n\t\tcfg.NetworkResolverConfig().DisableSearchDomain() ||\n\t\thostnameStatus == nil ||\n\t\thostnameStatus.Domainname == \"\" {\n\t\treturn spec\n\t}\n\n\tspec.SearchDomains = []string{hostnameStatus.Domainname}\n\n\treturn spec\n}\n\nfunc (ctrl *ResolverConfigController) parseCmdline(logger *zap.Logger) (spec network.ResolverSpecSpec) {\n\tif ctrl.Cmdline == nil {\n\t\treturn spec\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, network.NewEmptyLinkResolver())\n\tif err != nil {\n\t\tlogger.Warn(\"ignoring error\", zap.Error(err))\n\n\t\treturn spec\n\t}\n\n\tif len(settings.DNSAddresses) == 0 {\n\t\treturn spec\n\t}\n\n\tspec.DNSServers = settings.DNSAddresses\n\tspec.ConfigLayer = network.ConfigCmdline\n\n\treturn spec\n}\n\nfunc (ctrl *ResolverConfigController) parseMachineConfiguration(cfgProvider talosconfig.Config) (network.ResolverSpecSpec, bool) {\n\tvar spec network.ResolverSpecSpec\n\n\tif cfgProvider.NetworkResolverConfig() == nil {\n\t\treturn spec, false\n\t}\n\n\tresolvers := cfgProvider.NetworkResolverConfig().Resolvers()\n\tsearchDomains := cfgProvider.NetworkResolverConfig().SearchDomains()\n\n\tif len(resolvers) == 0 && len(searchDomains) == 0 {\n\t\treturn spec, false\n\t}\n\n\tspec.DNSServers = slices.Clone(resolvers)\n\tspec.SearchDomains = slices.Clone(searchDomains)\n\tspec.ConfigLayer = network.ConfigMachineConfiguration\n\n\treturn spec, true\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ResolverConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ResolverConfigSuite) TestDefaults() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.ResolverConfigController{}))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"default/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(constants.DefaultPrimaryResolver),\n\t\t\t\t\tnetip.MustParseAddr(constants.DefaultSecondaryResolver),\n\t\t\t\t}, r.TypedSpec().DNSServers,\n\t\t\t)\n\t\t\tasrt.Empty(r.TypedSpec().SearchDomains)\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *ResolverConfigSuite) TestWithHostnameStatus() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.ResolverConfigController{}))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"irrelevant\"\n\thostnameStatus.TypedSpec().Domainname = \"example.org\"\n\tsuite.Create(hostnameStatus)\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{}, //nolint:staticcheck // legacy config\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"default/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(constants.DefaultPrimaryResolver),\n\t\t\t\t\tnetip.MustParseAddr(constants.DefaultSecondaryResolver),\n\t\t\t\t}, r.TypedSpec().DNSServers,\n\t\t\t)\n\t\t\tasrt.Equal([]string{\"example.org\"}, r.TypedSpec().SearchDomains)\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// make domain name empty\n\thostnameStatus.TypedSpec().Domainname = \"\"\n\tsuite.Update(hostnameStatus)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"default/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(r.TypedSpec().SearchDomains)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// bring back domain name, but disable via machine config\n\thostnameStatus.TypedSpec().Domainname = \"example.org\"\n\tsuite.Update(hostnameStatus)\n\n\tcfg.Container().RawV1Alpha1().MachineConfig.MachineNetwork.NetworkDisableSearchDomain = new(true) //nolint:staticcheck\n\tsuite.Update(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"default/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(r.TypedSpec().SearchDomains)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *ResolverConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.ResolverConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"cmdline/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"10.0.0.1\"),\n\t\t\t\t\tnetip.MustParseAddr(\"10.0.0.2\"),\n\t\t\t\t}, r.TypedSpec().DNSServers,\n\t\t\t)\n\t\t\tasrt.Empty(r.TypedSpec().SearchDomains)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *ResolverConfigSuite) TestMachineConfigurationLegacy() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.ResolverConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNameServers: []string{\"2.2.2.2\", \"3.3.3.3\"},\n\t\t\t\t\t\tSearches:    []string{\"example.com\", \"example.org\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"2.2.2.2\"),\n\t\t\t\t\tnetip.MustParseAddr(\"3.3.3.3\"),\n\t\t\t\t}, r.TypedSpec().DNSServers,\n\t\t\t)\n\n\t\t\tasrt.Equal(\n\t\t\t\t[]string{\"example.com\", \"example.org\"},\n\t\t\t\tr.TypedSpec().SearchDomains,\n\t\t\t)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error {\n\t\tr.Container().RawV1Alpha1().MachineConfig.MachineNetwork.NameServers = nil //nolint:staticcheck\n\t\tr.Container().RawV1Alpha1().MachineConfig.MachineNetwork.Searches = nil    //nolint:staticcheck\n\n\t\treturn nil\n\t})\n\n\tctest.AssertNoResource[*network.ResolverSpec](suite, \"configuration/resolvers\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *ResolverConfigSuite) TestMachineConfigurationNewStyle() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.ResolverConfigController{}))\n\n\trc := networkcfg.NewResolverConfigV1Alpha1()\n\trc.ResolverNameservers = []networkcfg.NameserverConfig{\n\t\t{\n\t\t\tAddress: networkcfg.Addr{Addr: netip.MustParseAddr(\"2.2.2.2\")},\n\t\t},\n\t\t{\n\t\t\tAddress: networkcfg.Addr{Addr: netip.MustParseAddr(\"3.3.3.3\")},\n\t\t},\n\t}\n\trc.ResolverSearchDomains = networkcfg.SearchDomainsConfig{\n\t\tSearchDomains: []string{\"example.com\", \"example.org\"},\n\t}\n\n\tctr, err := container.New(rc)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"2.2.2.2\"),\n\t\t\t\t\tnetip.MustParseAddr(\"3.3.3.3\"),\n\t\t\t\t}, r.TypedSpec().DNSServers,\n\t\t\t)\n\n\t\t\tasrt.Equal(\n\t\t\t\t[]string{\"example.com\", \"example.org\"},\n\t\t\t\tr.TypedSpec().SearchDomains,\n\t\t\t)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tsuite.Destroy(cfg)\n\n\tctest.AssertNoResource[*network.ResolverSpec](suite, \"configuration/resolvers\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc TestResolverConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ResolverConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"cmp\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewResolverMergeController initializes a ResolverMergeController.\n//\n// ResolverMergeController merges network.ResolverSpec in network.ConfigNamespace and produces final network.ResolverSpec in network.Namespace.\nfunc NewResolverMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.ResolverSpec]) map[resource.ID]*network.ResolverSpecSpec {\n\t\t\t// sort by config layer\n\t\t\tlist.SortFunc(func(l, r *network.ResolverSpec) int {\n\t\t\t\treturn cmp.Compare(l.TypedSpec().ConfigLayer, r.TypedSpec().ConfigLayer)\n\t\t\t})\n\n\t\t\t// simply merge by layers, overriding with the next configuration layer\n\t\t\tvar final network.ResolverSpecSpec\n\n\t\t\tfor res := range list.All() {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tfinal.SearchDomains = slices.Insert(final.SearchDomains, 0, spec.SearchDomains...)\n\n\t\t\t\tswitch spec.ConfigLayer { //nolint:exhaustive\n\t\t\t\tcase final.ConfigLayer:\n\t\t\t\t\t// simply append server lists on the same layer\n\t\t\t\t\tfinal.DNSServers = append(final.DNSServers, spec.DNSServers...)\n\t\t\t\tcase network.ConfigMachineConfiguration:\n\t\t\t\t\t// machine configuration layer overrides any previous layers completely\n\t\t\t\t\tfinal.DNSServers = slices.Clone(spec.DNSServers)\n\t\t\t\tdefault:\n\t\t\t\t\t// otherwise, do a smart merge across IPv4/IPv6\n\t\t\t\t\tmergeDNSServers(&final.DNSServers, spec.DNSServers)\n\t\t\t\t}\n\n\t\t\t\tfinal.ConfigLayer = spec.ConfigLayer\n\t\t\t}\n\n\t\t\tif final.DNSServers != nil {\n\t\t\t\treturn map[resource.ID]*network.ResolverSpecSpec{\n\t\t\t\t\tnetwork.ResolverID: &final,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n}\n\nfunc mergeDNSServers(dst *[]netip.Addr, src []netip.Addr) {\n\tif *dst == nil {\n\t\t*dst = slices.Clone(src)\n\n\t\treturn\n\t}\n\n\tsrcHasV4 := slices.IndexFunc(src, netip.Addr.Is4) != -1\n\tsrcHasV6 := slices.IndexFunc(src, netip.Addr.Is6) != -1\n\tdstHasV4 := slices.IndexFunc(*dst, netip.Addr.Is4) != -1\n\tdstHasV6 := slices.IndexFunc(*dst, netip.Addr.Is6) != -1\n\n\t// if old set has IPv4, and new one doesn't, preserve IPv4\n\t// and same vice versa for IPv6\n\tswitch {\n\tcase dstHasV4 && !srcHasV4:\n\t\t*dst = slices.Concat(src, xslices.Filter(*dst, netip.Addr.Is4))\n\tcase dstHasV6 && !srcHasV6:\n\t\t*dst = slices.Concat(src, xslices.Filter(*dst, netip.Addr.Is6))\n\tdefault:\n\t\t*dst = slices.Clone(src)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ResolverMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ResolverMergeSuite) assertResolvers(requiredIDs []string, check func(*network.ResolverSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *ResolverMergeSuite) TestMerge() {\n\tdef := network.NewResolverSpec(network.ConfigNamespaceName, \"default/resolvers\")\n\t*def.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers: []netip.Addr{\n\t\t\tnetip.MustParseAddr(constants.DefaultPrimaryResolver),\n\t\t\tnetip.MustParseAddr(constants.DefaultSecondaryResolver),\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp1 := network.NewResolverSpec(network.ConfigNamespaceName, \"dhcp/eth0\")\n\t*dhcp1.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"1.1.2.0\")},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tdhcp2 := network.NewResolverSpec(network.ConfigNamespaceName, \"dhcp/eth1\")\n\t*dhcp2.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"1.1.2.1\")},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewResolverSpec(network.ConfigNamespaceName, \"configuration/resolvers\")\n\t*static.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:    []netip.Addr{netip.MustParseAddr(\"2.2.2.2\")},\n\t\tSearchDomains: []string{\"example.com\", \"example.org\", \"example.net\"},\n\t\tConfigLayer:   network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{def, dhcp1, dhcp2, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertResolvers(\n\t\t[]string{\n\t\t\t\"resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\tasrt.Equal([]string{\"example.com\", \"example.org\", \"example.net\"}, r.TypedSpec().SearchDomains)\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertResolvers(\n\t\t[]string{\n\t\t\t\"resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"1.1.2.0\"), netip.MustParseAddr(\"1.1.2.1\")}, r.TypedSpec().DNSServers)\n\t\t},\n\t)\n}\n\nfunc (suite *ResolverMergeSuite) TestMergeIPv46() {\n\tdef := network.NewResolverSpec(network.ConfigNamespaceName, \"default/resolvers\")\n\t*def.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers: []netip.Addr{\n\t\t\tnetip.MustParseAddr(constants.DefaultPrimaryResolver),\n\t\t\tnetip.MustParseAddr(constants.DefaultSecondaryResolver),\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tplatform := network.NewResolverSpec(network.ConfigNamespaceName, \"platform/resolvers\")\n\t*platform.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"1.1.2.0\"), netip.MustParseAddr(\"fe80::1\")},\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tdhcp := network.NewResolverSpec(network.ConfigNamespaceName, \"dhcp/eth1\")\n\t*dhcp.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"1.1.2.1\")},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tfor _, res := range []resource.Resource{def, platform, dhcp} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertResolvers(\n\t\t[]string{\n\t\t\t\"resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigOperator, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.Equal(`[\"1.1.2.1\" \"fe80::1\"]`, fmt.Sprintf(\"%q\", r.TypedSpec().DNSServers))\n\t\t},\n\t)\n}\n\nfunc (suite *ResolverMergeSuite) TestMergeIPv6OnlyConfig() {\n\tdef := network.NewResolverSpec(network.ConfigNamespaceName, \"default/resolvers\")\n\t*def.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers: []netip.Addr{\n\t\t\tnetip.MustParseAddr(constants.DefaultPrimaryResolver),\n\t\t\tnetip.MustParseAddr(constants.DefaultSecondaryResolver),\n\t\t},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tcfg := network.NewResolverSpec(network.ConfigNamespaceName, \"cfg/resolvers\")\n\t*cfg.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{def, cfg} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertResolvers(\n\t\t[]string{\n\t\t\t\"resolvers\",\n\t\t}, func(r *network.ResolverSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.Equal(`[\"fe80::1\"]`, fmt.Sprintf(\"%q\", r.TypedSpec().DNSServers))\n\t\t},\n\t)\n}\n\nfunc TestResolverMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ResolverMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewResolverMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ResolverSpecController applies network.ResolverSpec to the actual interfaces.\ntype ResolverSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ResolverSpecController) Name() string {\n\treturn \"network.ResolverSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ResolverSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.ResolverSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ResolverSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.ResolverStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ResolverSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := safe.ReaderListAll[*network.ResolverSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network addresses: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// loop over specs and sync to statuses\n\t\tfor spec := range list.All() {\n\t\t\tswitch spec.Metadata().Phase() {\n\t\t\tcase resource.PhaseTearingDown:\n\t\t\t\tif err = r.Destroy(ctx, resource.NewMetadata(network.NamespaceName, network.ResolverStatusType, spec.Metadata().ID(), resource.VersionUndefined)); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = r.RemoveFinalizer(ctx, spec.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t\t}\n\t\t\tcase resource.PhaseRunning:\n\t\t\t\tlogger.Info(\n\t\t\t\t\t\"setting resolvers\",\n\t\t\t\t\tzap.Stringers(\"resolvers\", spec.TypedSpec().DNSServers),\n\t\t\t\t\tzap.Strings(\"searchDomains\", spec.TypedSpec().SearchDomains),\n\t\t\t\t)\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, network.NewResolverStatus(network.NamespaceName, spec.Metadata().ID()), func(r *network.ResolverStatus) error {\n\t\t\t\t\tr.TypedSpec().DNSServers = spec.TypedSpec().DNSServers\n\t\t\t\t\tr.TypedSpec().SearchDomains = spec.TypedSpec().SearchDomains\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error modifying status: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/resolver_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"context\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype ResolverSpecSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *ResolverSpecSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&netctrl.ResolverSpecController{}))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *ResolverSpecSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *ResolverSpecSuite) assertStatus(id string, servers ...netip.Addr) error {\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(network.NamespaceName, network.ResolverStatusType, id, resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tstatus := r.(*network.ResolverStatus) //nolint:forcetypeassert\n\n\tif !slices.Equal(status.TypedSpec().DNSServers, servers) {\n\t\treturn retry.ExpectedErrorf(\"server list mismatch: %q != %q\", status.TypedSpec().DNSServers, servers)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *ResolverSpecSuite) TestSpec() {\n\tspec := network.NewResolverSpec(network.NamespaceName, \"resolvers\")\n\t*spec.TypedSpec() = network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{netip.MustParseAddr(constants.DefaultPrimaryResolver)},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tfor _, res := range []resource.Resource{spec} {\n\t\tsuite.Require().NoError(suite.state.Create(suite.ctx, res), \"%v\", res.Spec())\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertStatus(\"resolvers\", netip.MustParseAddr(constants.DefaultPrimaryResolver))\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *ResolverSpecSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestResolverSpecSuite(t *testing.T) {\n\tsuite.Run(t, new(ResolverSpecSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\tcfg \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RouteConfigController manages network.RouteSpec based on machine configuration, kernel cmdline.\ntype RouteConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RouteConfigController) Name() string {\n\treturn \"network.RouteConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RouteConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.DeviceConfigSpecType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RouteConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.RouteSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *RouteConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tdevices, err := safe.ReaderListAll[*network.DeviceConfigSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t}\n\n\t\tignoredInterfaces := map[string]struct{}{}\n\n\t\tfor device := range devices.All() {\n\t\t\tif device.TypedSpec().Device.Ignore() {\n\t\t\t\tignoredInterfaces[device.TypedSpec().Device.Interface()] = struct{}{}\n\t\t\t}\n\t\t}\n\n\t\t// parse kernel cmdline for the default gateway\n\t\tcmdlineRoutes := ctrl.parseCmdline(logger)\n\t\tfor _, cmdlineRoute := range cmdlineRoutes {\n\t\t\tif _, ignored := ignoredInterfaces[cmdlineRoute.OutLinkName]; !ignored {\n\t\t\t\tif err = ctrl.apply(ctx, r, []network.RouteSpecSpec{cmdlineRoute}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error applying cmdline route: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// parse machine configuration for static routes (legacy)\n\t\tif devices.Len() > 0 {\n\t\t\troutes := ctrl.processDevicesConfiguration(logger, devices)\n\n\t\t\tif err = ctrl.apply(ctx, r, routes); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying machine configuration routes: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// parse machine configuration (modern)\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif cfg != nil {\n\t\t\tif err = ctrl.apply(ctx, r, ctrl.processMachineConfig(cfg.Config().NetworkCommonLinkConfigs(), cfg.Config().NetworkBlackholeRouteConfigs())); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying machine configuration routes: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.RouteSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *RouteConfigController) apply(ctx context.Context, r controller.Runtime, routes []network.RouteSpecSpec) error {\n\tfor _, route := range routes {\n\t\tid := network.LayeredID(route.ConfigLayer, network.RouteID(route.Table, route.Family, route.Destination, route.Gateway, route.Priority, route.OutLinkName))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewRouteSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.RouteSpec) error {\n\t\t\t\t*r.TypedSpec() = route\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *RouteConfigController) parseCmdline(logger *zap.Logger) (routes []network.RouteSpecSpec) {\n\tif ctrl.Cmdline == nil {\n\t\treturn routes\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, network.NewEmptyLinkResolver())\n\tif err != nil {\n\t\tlogger.Info(\"ignoring error\", zap.Error(err))\n\n\t\treturn routes\n\t}\n\n\tfor idx, linkConfig := range settings.LinkConfigs {\n\t\tif value.IsZero(linkConfig.Gateway) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// add a default gateway route\n\t\tdefaultGatewayRoute := network.RouteSpecSpec{\n\t\t\tGateway:     linkConfig.Gateway,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tPriority:    network.DefaultRouteMetric + uint32(idx), // set different priorities to avoid a conflict\n\t\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tOutLinkName: linkConfig.LinkName,\n\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t}\n\n\t\tif defaultGatewayRoute.Gateway.Is6() {\n\t\t\tdefaultGatewayRoute.Family = nethelpers.FamilyInet6\n\t\t} else {\n\t\t\tdefaultGatewayRoute.Family = nethelpers.FamilyInet4\n\t\t}\n\n\t\tdefaultGatewayRoute.Normalize()\n\n\t\troutes = append(routes, defaultGatewayRoute)\n\n\t\t// for IPv4, if the gateway is not directly reachable on the link, add a link-scope route for the gateway\n\t\tif linkConfig.Gateway.Is4() && !linkConfig.Address.Contains(linkConfig.Gateway) {\n\t\t\troutes = append(routes, network.RouteSpecSpec{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tDestination: netip.PrefixFrom(linkConfig.Gateway, linkConfig.Gateway.BitLen()),\n\t\t\t\tSource:      linkConfig.Address.Addr(),\n\t\t\t\tOutLinkName: linkConfig.LinkName,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tPriority:    defaultGatewayRoute.Priority,\n\t\t\t\tScope:       nethelpers.ScopeLink,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\t\t\tConfigLayer: network.ConfigCmdline,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn routes\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *RouteConfigController) processDevicesConfiguration(logger *zap.Logger, devices safe.List[*network.DeviceConfigSpec]) (routes []network.RouteSpecSpec) {\n\tconvert := func(linkName string, in cfg.Route) (route network.RouteSpecSpec, err error) {\n\t\tif in.Network() != \"\" {\n\t\t\troute.Destination, err = netip.ParsePrefix(in.Network())\n\t\t\tif err != nil {\n\t\t\t\treturn route, fmt.Errorf(\"error parsing route network: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif in.Gateway() != \"\" {\n\t\t\troute.Gateway, err = netip.ParseAddr(in.Gateway())\n\t\t\tif err != nil {\n\t\t\t\treturn route, fmt.Errorf(\"error parsing route gateway: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif in.Source() != \"\" {\n\t\t\troute.Source, err = netip.ParseAddr(in.Source())\n\t\t\tif err != nil {\n\t\t\t\treturn route, fmt.Errorf(\"error parsing route source: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tnormalizedFamily := route.Normalize()\n\n\t\troute.Priority = in.Metric()\n\t\tif route.Priority == 0 {\n\t\t\troute.Priority = network.DefaultRouteMetric\n\t\t}\n\n\t\troute.MTU = in.MTU()\n\n\t\tswitch {\n\t\tcase !value.IsZero(route.Gateway) && route.Gateway.Is6():\n\t\t\troute.Family = nethelpers.FamilyInet6\n\t\tcase !value.IsZero(route.Destination) && route.Destination.Addr().Is6():\n\t\t\troute.Family = nethelpers.FamilyInet6\n\t\tcase normalizedFamily != 0:\n\t\t\troute.Family = normalizedFamily\n\t\tdefault:\n\t\t\troute.Family = nethelpers.FamilyInet4\n\t\t}\n\n\t\troute.Table = nethelpers.TableMain\n\t\troute.Protocol = nethelpers.ProtocolStatic\n\t\troute.OutLinkName = linkName\n\t\troute.ConfigLayer = network.ConfigMachineConfiguration\n\n\t\troute.Type = nethelpers.TypeUnicast\n\n\t\tif route.Destination.Addr().IsMulticast() {\n\t\t\troute.Type = nethelpers.TypeMulticast\n\t\t}\n\n\t\treturn route, nil\n\t}\n\n\tfor item := range devices.All() {\n\t\tdevice := item.TypedSpec().Device\n\n\t\tif device.Ignore() {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, route := range device.Routes() {\n\t\t\trouteSpec, err := convert(device.Interface(), route)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Sugar().Infof(\"skipping route %q -> %q on interface %q: %s\", route.Network(), route.Gateway(), device.Interface(), err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\troutes = append(routes, routeSpec)\n\t\t}\n\n\t\tfor _, vlan := range device.Vlans() {\n\t\t\tvlanLinkName := nethelpers.VLANLinkName(device.Interface(), vlan.ID())\n\n\t\t\tfor _, route := range vlan.Routes() {\n\t\t\t\trouteSpec, err := convert(vlanLinkName, route)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Sugar().Infof(\"skipping route %q -> %q on interface %q: %s\", route.Network(), route.Gateway(), vlanLinkName, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\troutes = append(routes, routeSpec)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn routes\n}\n\n//nolint:gocyclo\nfunc (ctrl *RouteConfigController) processMachineConfig(linkConfigs []cfg.NetworkCommonLinkConfig, blackholeRouteConfigs []cfg.NetworkBlackholeRouteConfig) (routes []network.RouteSpecSpec) {\n\tfor _, linkConfig := range linkConfigs {\n\t\tfor _, spec := range linkConfig.Routes() {\n\t\t\tvar route network.RouteSpecSpec\n\n\t\t\troute.Destination = spec.Destination().ValueOrZero()\n\t\t\troute.Gateway = spec.Gateway().ValueOrZero()\n\t\t\troute.Source = spec.Source().ValueOrZero()\n\n\t\t\tnormalizedFamily := route.Normalize()\n\n\t\t\troute.Priority = spec.Metric().ValueOr(network.DefaultRouteMetric)\n\n\t\t\troute.MTU = spec.MTU().ValueOrZero()\n\n\t\t\tswitch {\n\t\t\tcase !value.IsZero(route.Gateway) && route.Gateway.Is6():\n\t\t\t\troute.Family = nethelpers.FamilyInet6\n\t\t\tcase !value.IsZero(route.Destination) && route.Destination.Addr().Is6():\n\t\t\t\troute.Family = nethelpers.FamilyInet6\n\t\t\tcase normalizedFamily != 0:\n\t\t\t\troute.Family = normalizedFamily\n\t\t\tdefault:\n\t\t\t\troute.Family = nethelpers.FamilyInet4\n\t\t\t}\n\n\t\t\troute.Table = nethelpers.TableMain\n\t\t\troute.Protocol = nethelpers.ProtocolStatic\n\t\t\troute.OutLinkName = linkConfig.Name()\n\t\t\troute.ConfigLayer = network.ConfigMachineConfiguration\n\n\t\t\troute.Type = nethelpers.TypeUnicast\n\n\t\t\tif route.Destination.Addr().IsMulticast() {\n\t\t\t\troute.Type = nethelpers.TypeMulticast\n\t\t\t}\n\n\t\t\troutes = append(routes, route)\n\t\t}\n\t}\n\n\tfor _, blackholeRouteConfig := range blackholeRouteConfigs {\n\t\tdestination, err := netip.ParsePrefix(blackholeRouteConfig.Name())\n\t\tif err != nil {\n\t\t\t// validated in the machine config\n\t\t\tcontinue\n\t\t}\n\n\t\tfamily := nethelpers.FamilyInet4\n\n\t\tif destination.Addr().Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tDestination: destination,\n\t\t\tFamily:      family,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeBlackhole,\n\t\t\tOutLinkName: \"lo\",\n\t\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t\t\tPriority:    blackholeRouteConfig.Metric().ValueOr(network.DefaultRouteMetric),\n\t\t}\n\n\t\troutes = append(routes, route)\n\t}\n\n\treturn routes\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RouteConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RouteConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.RouteConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1::::: ip=eth3:dhcp ip=10.3.5.7::10.3.5.1:255.255.255.0::eth4\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"cmdline/inet4/172.20.0.1//1024\",\n\t\t\t\"cmdline/inet4/10.3.5.1//1026\",\n\t\t},\n\t\tfunc(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"cmdline/inet4/172.20.0.1//1024\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\tcase \"cmdline/inet4/10.3.5.1//1025\":\n\t\t\t\tasrt.Equal(\"eth4\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric+2, r.TypedSpec().Priority)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *RouteConfigSuite) TestCmdlineNotReachable() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.RouteConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2::172.20.0.1:255.255.255.255::eth1:::::\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"cmdline/inet4/172.20.0.1//1024\",\n\t\t\t\"cmdline/inet4//172.20.0.1/32/1024\",\n\t\t},\n\t\tfunc(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"cmdline/inet4/172.20.0.1//1024\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\tcase \"cmdline/inet4//172.20.0.1/32/1024\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(netip.Addr{}, r.TypedSpec().Gateway)\n\t\t\t\tasrt.Equal(netip.MustParsePrefix(\"172.20.0.1/32\"), r.TypedSpec().Destination)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *RouteConfigSuite) TestMachineConfigurationLegacy() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RouteConfigController{}))\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.DeviceConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth3\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.24/28\"},\n\t\t\t\t\t\t\t\tDeviceRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"192.168.0.0/18\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"192.168.0.25\",\n\t\t\t\t\t\t\t\t\t\tRouteMetric:  25,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"169.254.254.254/32\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceIgnore:    new(true),\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth4\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"192.168.0.24/28\"},\n\t\t\t\t\t\t\t\tDeviceRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"192.168.0.0/18\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"192.168.0.26\",\n\t\t\t\t\t\t\t\t\t\tRouteMetric:  25,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64\"},\n\t\t\t\t\t\t\t\tDeviceRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"2001:470:6d:30e:8ed2:b60c:9d2f:803b\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 24,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"10.0.0.1/8\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tVlanRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"10.0.3.0/24\",\n\t\t\t\t\t\t\t\t\t\t\t\tRouteGateway: \"10.0.3.1\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"192.244.0.0/24\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"192.244.0.1\",\n\t\t\t\t\t\t\t\t\t\tRouteSource:  \"192.244.0.10\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/eth2/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024\",\n\t\t\t\"configuration/inet4/10.0.3.1/10.0.3.0/24/1024\",\n\t\t\t\"configuration/inet4/192.168.0.25/192.168.0.0/18/25\",\n\t\t\t\"configuration/inet4/192.244.0.1/192.244.0.0/24/1024\",\n\t\t\t\"configuration/inet4//169.254.254.254/32/1024\",\n\t\t},\n\t\tfunc(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024\":\n\t\t\t\tasrt.Equal(\"eth2\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet6, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4/10.0.3.1/10.0.3.0/24/1024\":\n\t\t\t\tasrt.Equal(\"eth0.24\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4/192.168.0.25/192.168.0.0/18/25\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(25, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4/192.244.0.1/192.244.0.0/24/1024\":\n\t\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\t\tasrt.EqualValues(netip.MustParseAddr(\"192.244.0.10\"), r.TypedSpec().Source)\n\t\t\tcase \"configuration/inet4//169.254.254.254/32/1024\":\n\t\t\t\tasrt.Equal(\"eth3\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\t\tasrt.Equal(nethelpers.ScopeLink, r.TypedSpec().Scope)\n\t\t\t\tasrt.Equal(\"169.254.254.254/32\", r.TypedSpec().Destination.String())\n\t\t\t}\n\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *RouteConfigSuite) TestMachineConfiguration() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RouteConfigController{}))\n\n\tlc1 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s2\")\n\tlc1.LinkRoutes = []networkcfg.RouteConfig{\n\t\t{\n\t\t\tRouteDestination: networkcfg.Prefix{Prefix: netip.MustParsePrefix(\"10.12.3.0/24\")},\n\t\t\tRouteGateway:     networkcfg.Addr{Addr: netip.MustParseAddr(\"10.12.3.1\")},\n\t\t},\n\t}\n\n\tlc2 := networkcfg.NewLinkConfigV1Alpha1(\"enp0s3\")\n\tlc2.LinkRoutes = []networkcfg.RouteConfig{\n\t\t{\n\t\t\tRouteGateway: networkcfg.Addr{Addr: netip.MustParseAddr(\"2001:470:6d:30e:8ed2:b60c:9d2f:803b\")},\n\t\t\tRouteMetric:  200,\n\t\t},\n\t}\n\n\tbc1 := networkcfg.NewBlackholeRouteConfigV1Alpha1(\"10.1.3.4/32\")\n\tbc1.RouteMetric = 300\n\n\tctr, err := container.New(lc1, lc2, bc1)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/enp0s3/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//200\",\n\t\t\t\"configuration/inet4/10.12.3.1/10.12.3.0/24/1024\",\n\t\t\t\"configuration/inet4//10.1.3.4/32/300\",\n\t\t},\n\t\tfunc(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/enp0s3/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//200\":\n\t\t\t\tasrt.Equal(\"enp0s3\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet6, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(200, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4/10.12.3.1/10.12.3.0/24/1024\":\n\t\t\t\tasrt.Equal(\"enp0s2\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(network.DefaultRouteMetric, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4//10.1.3.4/32/300\":\n\t\t\t\tasrt.Equal(\"lo\", r.TypedSpec().OutLinkName)\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t\tasrt.EqualValues(300, r.TypedSpec().Priority)\n\t\t\t\tasrt.Equal(nethelpers.TypeBlackhole, r.TypedSpec().Type)\n\t\t\t}\n\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc TestRouteConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RouteConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewRouteMergeController initializes a RouteMergeController.\n//\n// RouteMergeController merges network.RouteSpec in network.ConfigNamespace and produces final network.RouteSpec in network.Namespace.\nfunc NewRouteMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.RouteSpec]) map[resource.ID]*network.RouteSpecSpec {\n\t\t\t// route is allowed as long as it's not duplicate, for duplicate higher layer takes precedence\n\t\t\troutes := map[string]*network.RouteSpecSpec{}\n\n\t\t\tfor route := range list.All() {\n\t\t\t\tid := network.RouteID(route.TypedSpec().Table, route.TypedSpec().Family, route.TypedSpec().Destination, route.TypedSpec().Gateway, route.TypedSpec().Priority, route.TypedSpec().OutLinkName)\n\n\t\t\t\texisting, ok := routes[id]\n\t\t\t\tif ok && existing.ConfigLayer > route.TypedSpec().ConfigLayer {\n\t\t\t\t\t// skip this route, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\troutes[id] = route.TypedSpec()\n\t\t\t}\n\n\t\t\treturn routes\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"math/rand/v2\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RouteMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RouteMergeSuite) assertRoutes(requiredIDs []string, check func(*network.RouteSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *RouteMergeSuite) assertNoRoute(id string) {\n\tctest.AssertNoResource[*network.RouteSpec](suite, id)\n}\n\nfunc (suite *RouteMergeSuite) TestMerge() {\n\tcmdline := network.NewRouteSpec(network.ConfigNamespaceName, \"cmdline/inet4//10.5.0.3/50\")\n\t*cmdline.TypedSpec() = network.RouteSpecSpec{\n\t\tGateway:     netip.MustParseAddr(\"10.5.0.3\"),\n\t\tOutLinkName: \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tTable:       nethelpers.TableMain,\n\t\tPriority:    50,\n\t\tConfigLayer: network.ConfigCmdline,\n\t}\n\n\tdhcp := network.NewRouteSpec(network.ConfigNamespaceName, \"dhcp/inet4//10.5.0.3/50\")\n\t*dhcp.TypedSpec() = network.RouteSpecSpec{\n\t\tGateway:     netip.MustParseAddr(\"10.5.0.3\"),\n\t\tOutLinkName: \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tTable:       nethelpers.TableMain,\n\t\tPriority:    50,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewRouteSpec(network.ConfigNamespaceName, \"configuration/inet4/10.0.0.35/32/10.0.0.34/1024\")\n\t*static.TypedSpec() = network.RouteSpecSpec{\n\t\tDestination: netip.MustParsePrefix(\"10.0.0.35/32\"),\n\t\tGateway:     netip.MustParseAddr(\"10.0.0.34\"),\n\t\tOutLinkName: \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tTable:       nethelpers.TableMain,\n\t\tPriority:    1024,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{cmdline, dhcp, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertRoutes(\n\t\t[]string{\n\t\t\t\"inet4/10.5.0.3//50\",\n\t\t\t\"inet4/10.0.0.34/10.0.0.35/32/1024\",\n\t\t}, func(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"inet4/10.5.0.3//50\":\n\t\t\t\tasrt.Equal(*dhcp.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"inet4/10.0.0.34/10.0.0.35/32/1024\":\n\t\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(dhcp)\n\n\tsuite.assertRoutes(\n\t\t[]string{\n\t\t\t\"inet4/10.5.0.3//50\",\n\t\t\t\"inet4/10.0.0.34/10.0.0.35/32/1024\",\n\t\t}, func(r *network.RouteSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"inet4/10.5.0.3//50\":\n\t\t\t\tasrt.Equal(*cmdline.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"inet4/10.0.0.34/10.0.0.35/32/1024\":\n\t\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertNoRoute(\"inet4/10.0.0.34/10.0.0.35/32/1024\")\n}\n\nfunc testMergeFlapping[R rtestutils.ResourceWithRD](suite *ctest.DefaultSuite, resources []R, outputID string, mergedResource R) {\n\tvar zeroR R\n\n\toutputMetadata := resource.NewMetadata(\n\t\tzeroR.ResourceDefinition().DefaultNamespace,\n\t\tzeroR.ResourceDefinition().Type,\n\t\toutputID,\n\t\tresource.VersionUndefined,\n\t)\n\n\tfor range 30 {\n\t\t// pick a set of input resources to create, each bit in the choice represents a resource\n\t\tchoice := rand.IntN(1 << len(resources))\n\n\t\tif choice == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor idx, res := range resources {\n\t\t\tif choice&(1<<idx) != 0 {\n\t\t\t\tsuite.Create(res)\n\t\t\t}\n\t\t}\n\n\t\t// wait for output to be created\n\t\tctest.AssertResources(suite, []string{outputID}, func(r R, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\t\t})\n\n\t\t// put a finalizer on the output resource\n\t\tsuite.Require().NoError(suite.State().AddFinalizer(\n\t\t\tsuite.Ctx(),\n\t\t\toutputMetadata,\n\t\t\t\"foo\",\n\t\t))\n\n\t\tfor idx, res := range resources {\n\t\t\tif choice&(1<<idx) != 0 {\n\t\t\t\tsuite.Destroy(res)\n\t\t\t}\n\t\t}\n\n\t\t// wait for output to be torn down\n\t\tctest.AssertResources(suite, []string{outputID}, func(r R, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseTearingDown, r.Metadata().Phase())\n\t\t})\n\n\t\t// remove a finalizer\n\t\tsuite.Require().NoError(suite.State().RemoveFinalizer(\n\t\t\tsuite.Ctx(),\n\t\t\toutputMetadata,\n\t\t\t\"foo\",\n\t\t))\n\t}\n\n\t// create all resources\n\tfor _, res := range resources {\n\t\tsuite.Create(res)\n\t}\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\toutputID,\n\t\t}, func(r R, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\t\t\tasrt.Equal(mergedResource.Spec(), r.Spec())\n\t\t},\n\t)\n}\n\n//nolint:gocyclo\nfunc (suite *RouteMergeSuite) TestMergeFlapping() {\n\t// simulate two conflicting default route definitions which are getting removed/added constantly\n\tcmdline := network.NewRouteSpec(network.ConfigNamespaceName, \"cmdline/inet4//10.5.0.3/50\")\n\t*cmdline.TypedSpec() = network.RouteSpecSpec{\n\t\tGateway:     netip.MustParseAddr(\"10.5.0.3\"),\n\t\tOutLinkName: \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tTable:       nethelpers.TableMain,\n\t\tPriority:    50,\n\t\tConfigLayer: network.ConfigCmdline,\n\t}\n\n\tdhcp := network.NewRouteSpec(network.ConfigNamespaceName, \"dhcp/inet4//10.5.0.3/50\")\n\t*dhcp.TypedSpec() = network.RouteSpecSpec{\n\t\tGateway:     netip.MustParseAddr(\"10.5.0.3\"),\n\t\tOutLinkName: \"eth1\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tTable:       nethelpers.TableMain,\n\t\tPriority:    50,\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\ttestMergeFlapping(&suite.DefaultSuite, []*network.RouteSpec{cmdline, dhcp}, \"inet4/10.5.0.3//50\", dhcp)\n}\n\nfunc TestRouteMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RouteMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewRouteMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RouteSpecController applies network.RouteSpec to the actual interfaces.\ntype RouteSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RouteSpecController) Name() string {\n\treturn \"network.RouteSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RouteSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.RouteSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RouteSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *RouteSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// watch link changes as some routes might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_LINK|unix.RTMGRP_IPV4_ROUTE)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := safe.ReaderListAll[*network.RouteSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network routes: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// list rtnetlink links (interfaces)\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\t// list rtnetlink routes\n\t\troutes, err := conn.Route.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing addresses: %w\", err)\n\t\t}\n\n\t\tvar multiErr *multierror.Error\n\n\t\t// loop over routes and make reconcile decision\n\t\tfor route := range list.All() {\n\t\t\tif err = ctrl.syncRoute(ctx, r, logger, conn, links, routes, route); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t}\n\t\t}\n\n\t\tif err = multiErr.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n// netipPrefixBitsCorrected returns the number of bits in the prefix, corrected for zero value to have bits of 0.\n//\n// Go stdlib returns -1 for zero value, which is not what we want.\nfunc netipPrefixBitsCorrected(p netip.Prefix) int {\n\tif p.Addr().AsSlice() == nil {\n\t\treturn 0\n\t}\n\n\treturn p.Bits()\n}\n\nfunc findMatchingRoutes(existingRoutes []rtnetlink.RouteMessage, expected *network.RouteSpecSpec) []*rtnetlink.RouteMessage {\n\tvar result []*rtnetlink.RouteMessage //nolint:prealloc\n\n\tfor i, route := range existingRoutes {\n\t\tif route.Family != uint8(expected.Family) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif int(route.DstLength) != netipPrefixBitsCorrected(expected.Destination) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !route.Attributes.Dst.Equal(expected.Destination.Addr().AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !route.Attributes.Gateway.Equal(expected.Gateway.AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif nethelpers.RoutingTable(route.Table) != expected.Table {\n\t\t\tcontinue\n\t\t}\n\n\t\tif route.Attributes.Priority != expected.Priority {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, &existingRoutes[i])\n\t}\n\n\treturn result\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn,\n\tlinks []rtnetlink.LinkMessage, routes []rtnetlink.RouteMessage, route *network.RouteSpec,\n) error {\n\tlinkIndex := resolveLinkName(links, route.TypedSpec().OutLinkName)\n\n\tdestinationStr := route.TypedSpec().Destination.String()\n\tif value.IsZero(route.TypedSpec().Destination) {\n\t\tdestinationStr = \"default\"\n\t}\n\n\tsourceStr := route.TypedSpec().Source.String()\n\tif value.IsZero(route.TypedSpec().Source) {\n\t\tsourceStr = \"\"\n\t}\n\n\tgatewayStr := route.TypedSpec().Gateway.String()\n\tif value.IsZero(route.TypedSpec().Gateway) {\n\t\tgatewayStr = \"\"\n\t}\n\n\tswitch route.Metadata().Phase() {\n\tcase resource.PhaseTearingDown:\n\t\tfor _, existing := range findMatchingRoutes(routes, route.TypedSpec()) {\n\t\t\t// delete route\n\t\t\tif err := conn.Route.Delete(existing); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing route: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"deleted route\",\n\t\t\t\tzap.String(\"destination\", destinationStr),\n\t\t\t\tzap.String(\"gateway\", gatewayStr),\n\t\t\t\tzap.Stringer(\"table\", route.TypedSpec().Table),\n\t\t\t\tzap.String(\"link\", route.TypedSpec().OutLinkName),\n\t\t\t\tzap.Uint32(\"priority\", route.TypedSpec().Priority),\n\t\t\t\tzap.Stringer(\"family\", route.TypedSpec().Family),\n\t\t\t\tzap.Stringer(\"type\", route.TypedSpec().Type),\n\t\t\t)\n\t\t}\n\n\t\t// now remove finalizer as address was deleted\n\t\tif err := r.RemoveFinalizer(ctx, route.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t}\n\tcase resource.PhaseRunning:\n\t\tif linkIndex == 0 && route.TypedSpec().OutLinkName != \"\" {\n\t\t\t// route can't be created as link doesn't exist (yet), skip it\n\t\t\treturn nil\n\t\t}\n\n\t\tmatchFound := false\n\n\t\tfor _, existing := range findMatchingRoutes(routes, route.TypedSpec()) {\n\t\t\tvar existingMTU uint32\n\n\t\t\tif existing.Attributes.Metrics != nil {\n\t\t\t\texistingMTU = existing.Attributes.Metrics.MTU\n\t\t\t}\n\n\t\t\t// check if existing route matches the spec: if it does, skip update\n\t\t\tif existing.Scope == uint8(route.TypedSpec().Scope) && nethelpers.RouteFlags(existing.Flags).Equal(route.TypedSpec().Flags) &&\n\t\t\t\texisting.Protocol == uint8(route.TypedSpec().Protocol) &&\n\t\t\t\texisting.Attributes.OutIface == linkIndex &&\n\t\t\t\t(value.IsZero(route.TypedSpec().Source) ||\n\t\t\t\t\texisting.Attributes.Src.Equal(route.TypedSpec().Source.AsSlice())) &&\n\t\t\t\texistingMTU == route.TypedSpec().MTU &&\n\t\t\t\texisting.Type == uint8(route.TypedSpec().Type) {\n\t\t\t\tmatchFound = true\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// delete the route, it doesn't match the spec\n\t\t\tif err := conn.Route.Delete(existing); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error removing route: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Debug(\"removed route due to mismatch\",\n\t\t\t\tzap.String(\"destination\", destinationStr),\n\t\t\t\tzap.String(\"gateway\", gatewayStr),\n\t\t\t\tzap.Stringer(\"table\", route.TypedSpec().Table),\n\t\t\t\tzap.String(\"link\", route.TypedSpec().OutLinkName),\n\t\t\t\tzap.Uint32(\"priority\", route.TypedSpec().Priority),\n\t\t\t\tzap.Stringer(\"family\", route.TypedSpec().Family),\n\t\t\t\tzap.Stringer(\"old_scope\", nethelpers.Scope(existing.Scope)),\n\t\t\t\tzap.Stringer(\"new_scope\", route.TypedSpec().Scope),\n\t\t\t\tzap.Stringer(\"old_flags\", nethelpers.RouteFlags(existing.Flags)),\n\t\t\t\tzap.Stringer(\"new_flags\", route.TypedSpec().Flags),\n\t\t\t\tzap.Stringer(\"old_protocol\", nethelpers.RouteProtocol(existing.Protocol)),\n\t\t\t\tzap.Stringer(\"new_protocol\", route.TypedSpec().Protocol),\n\t\t\t\tzap.Uint32(\"old_link_index\", existing.Attributes.OutIface),\n\t\t\t\tzap.Uint32(\"new_link_index\", linkIndex),\n\t\t\t\tzap.Stringer(\"old_source\", existing.Attributes.Src),\n\t\t\t\tzap.String(\"new_source\", sourceStr),\n\t\t\t\tzap.Uint32(\"old_mtu\", existingMTU),\n\t\t\t\tzap.Uint32(\"new_mtu\", route.TypedSpec().MTU),\n\t\t\t\tzap.Stringer(\"old_type\", nethelpers.RouteType(existing.Type)),\n\t\t\t\tzap.Stringer(\"new_type\", route.TypedSpec().Type),\n\t\t\t)\n\t\t}\n\n\t\tif matchFound {\n\t\t\treturn nil\n\t\t}\n\n\t\trouteAttributes := rtnetlink.RouteAttributes{\n\t\t\tDst:      route.TypedSpec().Destination.Addr().AsSlice(),\n\t\t\tSrc:      route.TypedSpec().Source.AsSlice(),\n\t\t\tGateway:  route.TypedSpec().Gateway.AsSlice(),\n\t\t\tOutIface: linkIndex,\n\t\t\tPriority: route.TypedSpec().Priority,\n\t\t\tTable:    uint32(route.TypedSpec().Table),\n\t\t}\n\n\t\tif route.TypedSpec().MTU != 0 {\n\t\t\trouteAttributes.Metrics = &rtnetlink.RouteMetrics{\n\t\t\t\tMTU: route.TypedSpec().MTU,\n\t\t\t}\n\t\t}\n\n\t\t// add route\n\t\tmsg := &rtnetlink.RouteMessage{\n\t\t\tFamily:     uint8(route.TypedSpec().Family),\n\t\t\tDstLength:  uint8(netipPrefixBitsCorrected(route.TypedSpec().Destination)),\n\t\t\tSrcLength:  0,\n\t\t\tProtocol:   uint8(route.TypedSpec().Protocol),\n\t\t\tScope:      uint8(route.TypedSpec().Scope),\n\t\t\tType:       uint8(route.TypedSpec().Type),\n\t\t\tFlags:      uint32(route.TypedSpec().Flags),\n\t\t\tAttributes: routeAttributes,\n\t\t}\n\n\t\tif err := conn.Route.Add(msg); err != nil {\n\t\t\treturn fmt.Errorf(\"error adding route: %w, message %+v\", err, *msg)\n\t\t}\n\n\t\tlogger.Info(\"created route\",\n\t\t\tzap.String(\"destination\", destinationStr),\n\t\t\tzap.String(\"gateway\", gatewayStr),\n\t\t\tzap.Stringer(\"table\", route.TypedSpec().Table),\n\t\t\tzap.String(\"link\", route.TypedSpec().OutLinkName),\n\t\t\tzap.Uint32(\"priority\", route.TypedSpec().Priority),\n\t\t\tzap.Stringer(\"family\", route.TypedSpec().Family),\n\t\t\tzap.Stringer(\"type\", route.TypedSpec().Type),\n\t\t)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RouteSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RouteSpecSuite) uniqueDummyInterface() string {\n\treturn fmt.Sprintf(\"dummy%02x%02x%02x\", rand.Int32()&0xff, rand.Int32()&0xff, rand.Int32()&0xff)\n}\n\nfunc (suite *RouteSpecSuite) assertRoute(\n\tdestination netip.Prefix,\n\tgateway netip.Addr,\n\tcheck func(rtnetlink.RouteMessage) error,\n) error {\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\troutes, err := conn.Route.List()\n\tsuite.Require().NoError(err)\n\n\tmatching := 0\n\n\tfor _, route := range routes {\n\t\tif !route.Attributes.Gateway.Equal(gateway.AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !(int(route.DstLength) == destination.Bits() || (route.DstLength == 0 && destination.Bits() == -1)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !route.Attributes.Dst.Equal(destination.Addr().AsSlice()) {\n\t\t\tcontinue\n\t\t}\n\n\t\tmatching++\n\n\t\tif err = check(route); err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\t}\n\n\tswitch matching {\n\tcase 1:\n\t\treturn nil\n\tcase 0:\n\t\treturn retry.ExpectedErrorf(\"route to %s via %s not found\", destination, gateway)\n\tdefault:\n\t\treturn retry.ExpectedErrorf(\"route to %s via %s found %d matches\", destination, gateway, matching)\n\t}\n}\n\nfunc (suite *RouteSpecSuite) assertNoRoute(destination netip.Prefix, gateway netip.Addr) error {\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\troutes, err := conn.Route.List()\n\tsuite.Require().NoError(err)\n\n\tfor _, route := range routes {\n\t\tif route.Attributes.Gateway.Equal(gateway.AsSlice()) &&\n\t\t\t(destination.Bits() == int(route.DstLength) || (destination.Bits() == -1 && route.DstLength == 0)) &&\n\t\t\troute.Attributes.Dst.Equal(destination.Addr().AsSlice()) {\n\t\t\treturn retry.ExpectedErrorf(\"route to %s via %s is present\", destination, gateway)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (suite *RouteSpecSuite) TestLoopback() {\n\tloopback := network.NewRouteSpec(network.NamespaceName, \"loopback\")\n\t*loopback.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"127.0.11.0/24\"),\n\t\tGateway:     netip.MustParseAddr(\"127.0.11.1\"),\n\t\tOutLinkName: \"lo\",\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{loopback} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.MustParsePrefix(\"127.0.11.0/24\"),\n\t\t\t\t\tnetip.MustParseAddr(\"127.0.11.1\"),\n\t\t\t\t\tfunc(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().EqualValues(0, route.Attributes.Priority)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// teardown the route\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), loopback.Metadata()))\n\n\t// torn down address should be removed immediately\n\tsuite.Assert().NoError(\n\t\tsuite.assertNoRoute(\n\t\t\tnetip.MustParsePrefix(\"127.0.11.0/24\"),\n\t\t\tnetip.MustParseAddr(\"127.0.11.1\"),\n\t\t),\n\t)\n}\n\nfunc (suite *RouteSpecSuite) TestDefaultRoute() {\n\t// adding default route with high metric to avoid messing up with the actual default route\n\tdef := network.NewRouteSpec(network.NamespaceName, \"default\")\n\t*def.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.Prefix{},\n\t\tGateway:     netip.MustParseAddr(\"127.0.11.2\"),\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tTable:       nethelpers.TableMain,\n\t\tOutLinkName: \"lo\",\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tPriority:    1048576,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{def} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.Prefix{}, netip.MustParseAddr(\"127.0.11.2\"), func(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().Nil(route.Attributes.Dst)\n\t\t\t\t\t\tsuite.Assert().EqualValues(1048576, route.Attributes.Priority)\n\t\t\t\t\t\t// make sure not extra route metric attributes are set\n\t\t\t\t\t\tsuite.Assert().Empty(route.Attributes.Metrics)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// update the route metric and mtu\n\tctest.UpdateWithConflicts(suite, def, func(defR *network.RouteSpec) error {\n\t\tdefR.TypedSpec().MTU = 1700\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.Prefix{}, netip.MustParseAddr(\"127.0.11.2\"), func(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().Nil(route.Attributes.Dst)\n\n\t\t\t\t\t\tif route.Attributes.Metrics == nil || route.Attributes.Metrics.MTU == 0 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"route metric wasn't updated: %v\", route.Attributes.Metrics)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsuite.Assert().EqualValues(1700, route.Attributes.Metrics.MTU)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// remove mtu and make sure it's unset\n\tctest.UpdateWithConflicts(suite, def, func(defR *network.RouteSpec) error {\n\t\tdefR.TypedSpec().MTU = 0\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.Prefix{}, netip.MustParseAddr(\"127.0.11.2\"), func(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().Nil(route.Attributes.Dst)\n\n\t\t\t\t\t\tif route.Attributes.Metrics != nil {\n\t\t\t\t\t\t\treturn retry.ExpectedErrorf(\"route mtu expected to be empty, got: %d\", route.Attributes.Metrics.MTU)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tsuite.Assert().Empty(route.Attributes.Metrics)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// teardown the route\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), def.Metadata()))\n\n\t// torn down route should be removed immediately\n\tsuite.Assert().NoError(suite.assertNoRoute(netip.Prefix{}, netip.MustParseAddr(\"127.0.11.2\")))\n}\n\nfunc (suite *RouteSpecSuite) TestDefaultAndInterfaceRoutes() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType:   unix.ARPHRD_ETHER,\n\t\t\t\tFlags:  unix.IFF_UP,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1400,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tlocalIP := net.ParseIP(\"10.28.0.27\").To4()\n\n\tsuite.Require().NoError(\n\t\tconn.Address.New(\n\t\t\t&rtnetlink.AddressMessage{\n\t\t\t\tFamily:       unix.AF_INET,\n\t\t\t\tPrefixLength: 32,\n\t\t\t\tScope:        unix.RT_SCOPE_UNIVERSE,\n\t\t\t\tIndex:        uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.AddressAttributes{\n\t\t\t\t\tAddress: localIP,\n\t\t\t\t\tLocal:   localIP,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tdef := network.NewRouteSpec(network.NamespaceName, \"default\")\n\t*def.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.Prefix{},\n\t\tGateway:     netip.MustParseAddr(\"10.28.0.1\"),\n\t\tSource:      netip.MustParseAddr(\"10.28.0.27\"),\n\t\tTable:       nethelpers.TableMain,\n\t\tOutLinkName: dummyInterface,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tPriority:    1048576,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\tdef.TypedSpec().Normalize()\n\n\thost := network.NewRouteSpec(network.NamespaceName, \"aninterface\")\n\t*host.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"10.28.0.1/32\"),\n\t\tGateway:     netip.MustParseAddr(\"0.0.0.0\"),\n\t\tSource:      netip.MustParseAddr(\"10.28.0.27\"),\n\t\tTable:       nethelpers.TableMain,\n\t\tOutLinkName: dummyInterface,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tPriority:    1048576,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\thost.TypedSpec().Normalize()\n\n\tfor _, res := range []resource.Resource{def, host} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tif err := suite.assertRoute(\n\t\t\t\t\tnetip.Prefix{}, netip.MustParseAddr(\"10.28.0.1\"), func(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().Nil(route.Attributes.Dst)\n\t\t\t\t\t\tsuite.Assert().EqualValues(1048576, route.Attributes.Priority)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.MustParsePrefix(\"10.28.0.1/32\"), netip.Addr{}, func(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().Nil(route.Attributes.Gateway)\n\t\t\t\t\t\tsuite.Assert().EqualValues(1048576, route.Attributes.Priority)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// teardown the routes\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), def.Metadata()))\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), host.Metadata()))\n\n\t// torn down route should be removed immediately\n\tsuite.Assert().NoError(suite.assertNoRoute(netip.Prefix{}, netip.MustParseAddr(\"10.28.0.1\")))\n\tsuite.Assert().NoError(suite.assertNoRoute(netip.MustParsePrefix(\"10.28.0.1/32\"), netip.Addr{}))\n}\n\nfunc (suite *RouteSpecSuite) TestLinkLocalRoute() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType:   unix.ARPHRD_ETHER,\n\t\t\t\tFlags:  unix.IFF_UP,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1500,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tlocalIP := net.ParseIP(\"10.28.0.27\").To4()\n\n\tsuite.Require().NoError(\n\t\tconn.Address.New(\n\t\t\t&rtnetlink.AddressMessage{\n\t\t\t\tFamily:       unix.AF_INET,\n\t\t\t\tPrefixLength: 24,\n\t\t\t\tScope:        unix.RT_SCOPE_UNIVERSE,\n\t\t\t\tIndex:        uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.AddressAttributes{\n\t\t\t\t\tAddress: localIP,\n\t\t\t\t\tLocal:   localIP,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tll := network.NewRouteSpec(network.NamespaceName, \"ll\")\n\t*ll.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\tGateway:     netip.MustParseAddr(\"10.28.0.1\"),\n\t\tSource:      netip.MustParseAddr(\"10.28.0.27\"),\n\t\tTable:       nethelpers.TableMain,\n\t\tOutLinkName: dummyInterface,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tPriority:    1048576,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\tll.TypedSpec().Normalize()\n\n\tfor _, res := range []resource.Resource{ll} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\t\t\t\tnetip.MustParseAddr(\"10.28.0.1\"),\n\t\t\t\t\tfunc(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().EqualValues(1048576, route.Attributes.Priority)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// teardown the routes\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), ll.Metadata()))\n\n\t// torn down route should be removed immediately\n\tsuite.Assert().NoError(\n\t\tsuite.assertNoRoute(\n\t\t\tnetip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\t\tnetip.MustParseAddr(\"10.28.0.1\"),\n\t\t),\n\t)\n}\n\nfunc (suite *RouteSpecSuite) TestLinkLocalRouteAlias() {\n\tdummyInterface := suite.uniqueDummyInterface()\n\tdummyAlias := suite.uniqueDummyInterface()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tsuite.Require().NoError(\n\t\tconn.Link.New(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tType:   unix.ARPHRD_ETHER,\n\t\t\t\tFlags:  unix.IFF_UP,\n\t\t\t\tChange: unix.IFF_UP,\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tName: dummyInterface,\n\t\t\t\t\tMTU:  1500,\n\t\t\t\t\tInfo: &rtnetlink.LinkInfo{\n\t\t\t\t\t\tKind: \"dummy\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tiface, err := net.InterfaceByName(dummyInterface)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(\n\t\tconn.Link.Set(\n\t\t\t&rtnetlink.LinkMessage{\n\t\t\t\tIndex: uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.LinkAttributes{\n\t\t\t\t\tAlias: &dummyAlias,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tdefer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck\n\n\tlocalIP := net.ParseIP(\"10.28.0.27\").To4()\n\n\tsuite.Require().NoError(\n\t\tconn.Address.New(\n\t\t\t&rtnetlink.AddressMessage{\n\t\t\t\tFamily:       unix.AF_INET,\n\t\t\t\tPrefixLength: 24,\n\t\t\t\tScope:        unix.RT_SCOPE_UNIVERSE,\n\t\t\t\tIndex:        uint32(iface.Index),\n\t\t\t\tAttributes: &rtnetlink.AddressAttributes{\n\t\t\t\t\tAddress: localIP,\n\t\t\t\t\tLocal:   localIP,\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tll := network.NewRouteSpec(network.NamespaceName, \"ll\")\n\t*ll.TypedSpec() = network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\tGateway:     netip.MustParseAddr(\"10.28.0.1\"),\n\t\tSource:      netip.MustParseAddr(\"10.28.0.27\"),\n\t\tTable:       nethelpers.TableMain,\n\t\tOutLinkName: dummyAlias, // using alias name instead of the actual interface name\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tPriority:    1048576,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\tll.TypedSpec().Normalize()\n\n\tfor _, res := range []resource.Resource{ll} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRoute(\n\t\t\t\t\tnetip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\t\t\t\tnetip.MustParseAddr(\"10.28.0.1\"),\n\t\t\t\t\tfunc(route rtnetlink.RouteMessage) error {\n\t\t\t\t\t\tsuite.Assert().EqualValues(1048576, route.Attributes.Priority)\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// teardown the routes\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), ll.Metadata()))\n\n\t// torn down route should be removed immediately\n\tsuite.Assert().NoError(\n\t\tsuite.assertNoRoute(\n\t\t\tnetip.MustParsePrefix(\"169.254.169.254/32\"),\n\t\t\tnetip.MustParseAddr(\"10.28.0.1\"),\n\t\t),\n\t)\n}\n\nfunc TestRouteSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, &RouteSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 15 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RouteSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RouteStatusController manages secrets.Etcd based on configuration.\ntype RouteStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RouteStatusController) Name() string {\n\treturn \"network.RouteStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RouteStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RouteStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.RouteStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *RouteStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_IPV4_MROUTE|unix.RTMGRP_IPV4_ROUTE|unix.RTMGRP_IPV6_MROUTE|unix.RTMGRP_IPV6_ROUTE)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\t// build links lookup table\n\t\tlinks, err := conn.Link.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing links: %w\", err)\n\t\t}\n\n\t\tlinkLookup := make(map[uint32]string, len(links))\n\n\t\tfor _, link := range links {\n\t\t\tlinkLookup[link.Index] = link.Attributes.Name\n\t\t}\n\n\t\troutes, err := conn.Route.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing routes: %w\", err)\n\t\t}\n\n\t\tfor _, route := range routes {\n\t\t\tdstAddr, _ := netip.AddrFromSlice(route.Attributes.Dst)\n\t\t\tdstPrefix := netip.PrefixFrom(dstAddr, int(route.DstLength))\n\t\t\tsrcAddr, _ := netip.AddrFromSlice(route.Attributes.Src)\n\t\t\tgatewayAddr, _ := netip.AddrFromSlice(route.Attributes.Gateway)\n\t\t\toutLinkName := linkLookup[route.Attributes.OutIface]\n\n\t\t\tid := network.RouteID(nethelpers.RoutingTable(route.Table), nethelpers.Family(route.Family), dstPrefix, gatewayAddr, route.Attributes.Priority, outLinkName)\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewRouteStatus(network.NamespaceName, id), func(r *network.RouteStatus) error {\n\t\t\t\tstatus := r.TypedSpec()\n\n\t\t\t\tstatus.Family = nethelpers.Family(route.Family)\n\t\t\t\tstatus.Destination = dstPrefix\n\t\t\t\tstatus.Source = srcAddr\n\t\t\t\tstatus.Gateway = gatewayAddr\n\t\t\t\tstatus.OutLinkIndex = route.Attributes.OutIface\n\t\t\t\tstatus.OutLinkName = outLinkName\n\t\t\t\tstatus.Priority = route.Attributes.Priority\n\t\t\t\tstatus.Table = nethelpers.RoutingTable(route.Table)\n\t\t\t\tstatus.Scope = nethelpers.Scope(route.Scope)\n\t\t\t\tstatus.Type = nethelpers.RouteType(route.Type)\n\t\t\t\tstatus.Protocol = nethelpers.RouteProtocol(route.Protocol)\n\t\t\t\tstatus.Flags = nethelpers.RouteFlags(route.Flags)\n\n\t\t\t\tif route.Attributes.Metrics != nil {\n\t\t\t\t\tstatus.MTU = route.Attributes.Metrics.MTU\n\t\t\t\t} else {\n\t\t\t\t\tstatus.MTU = 0\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*network.RouteStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error doing cleanup: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/route_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RouteStatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RouteStatusSuite) TestRoutes() {\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"local/inet4//127.0.0.0/8/0\",\n\t\tfunc(r *network.RouteStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().Source.IsLoopback())\n\t\t\tasrt.Equal(\"lo\", r.TypedSpec().OutLinkName)\n\t\t\tasrt.Equal(nethelpers.TableLocal, r.TypedSpec().Table)\n\t\t\tasrt.Equal(nethelpers.ScopeHost, r.TypedSpec().Scope)\n\t\t\tasrt.Equal(nethelpers.TypeLocal, r.TypedSpec().Type)\n\t\t\tasrt.Equal(nethelpers.ProtocolKernel, r.TypedSpec().Protocol)\n\t\t\tasrt.EqualValues(0, r.TypedSpec().MTU)\n\t\t},\n\t)\n}\n\nfunc TestRouteStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RouteStatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RouteStatusController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tcfg \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RoutingRuleConfigController manages network.RoutingRuleSpec based on machine configuration.\ntype RoutingRuleConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RoutingRuleConfigController) Name() string {\n\treturn \"network.RoutingRuleConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.RoutingRuleSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *RoutingRuleConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tmachineConfig, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif machineConfig != nil {\n\t\t\trules := ctrl.processConfig(\n\t\t\t\tmachineConfig.Config().NetworkRoutingRuleConfigs(),\n\t\t\t)\n\n\t\t\tif err = ctrl.apply(ctx, r, rules); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error applying routing rule config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = r.CleanupOutputs(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.RoutingRuleSpecType, \"\", resource.VersionUndefined)); err != nil {\n\t\t\treturn fmt.Errorf(\"error cleaning outputs: %w\", err)\n\t\t}\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *RoutingRuleConfigController) apply(ctx context.Context, r controller.Runtime, rules []network.RoutingRuleSpecSpec) error {\n\tfor _, rule := range rules {\n\t\tid := network.LayeredID(rule.ConfigLayer, network.RoutingRuleID(rule.Family, rule.Priority))\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewRoutingRuleSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(res *network.RoutingRuleSpec) error {\n\t\t\t\t*res.TypedSpec() = rule\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *RoutingRuleConfigController) processConfig(\n\truleConfigs []cfg.NetworkRoutingRuleConfig,\n) []network.RoutingRuleSpecSpec {\n\trules := make([]network.RoutingRuleSpecSpec, 0, len(ruleConfigs))\n\n\tfor _, ruleCfg := range ruleConfigs {\n\t\tvar rule network.RoutingRuleSpecSpec\n\n\t\tsrc := ruleCfg.Src().ValueOrZero()\n\t\tdst := ruleCfg.Dst().ValueOrZero()\n\n\t\trule.Src = src\n\t\trule.Dst = dst\n\t\trule.IIFName = ruleCfg.IIFName()\n\t\trule.OIFName = ruleCfg.OIFName()\n\t\trule.FwMark = ruleCfg.FwMark()\n\t\trule.FwMask = ruleCfg.FwMask()\n\t\trule.ConfigLayer = network.ConfigMachineConfiguration\n\t\trule.Priority = ruleCfg.Priority()\n\n\t\trule.Table = ruleCfg.Table()\n\n\t\taction := ruleCfg.Action()\n\t\tif action == nethelpers.RoutingRuleActionUnspec {\n\t\t\taction = nethelpers.RoutingRuleActionUnicast\n\t\t}\n\n\t\trule.Action = action\n\n\t\tfor _, family := range ctrl.determineFamily(src, dst) {\n\t\t\trule.Family = family\n\n\t\t\trules = append(rules, rule)\n\t\t}\n\t}\n\n\treturn rules\n}\n\nfunc (ctrl *RoutingRuleConfigController) determineFamily(src, dst netip.Prefix) []nethelpers.Family {\n\tif src.IsValid() && src.Addr().Is6() {\n\t\treturn []nethelpers.Family{nethelpers.FamilyInet6}\n\t}\n\n\tif dst.IsValid() && dst.Addr().Is6() {\n\t\treturn []nethelpers.Family{nethelpers.FamilyInet6}\n\t}\n\n\t// If both src and dst are invalid, we need to create rules for both families, as we don't know which one will be used.\n\tif !src.IsValid() && !dst.IsValid() {\n\t\treturn []nethelpers.Family{nethelpers.FamilyInet6, nethelpers.FamilyInet4}\n\t}\n\n\treturn []nethelpers.Family{nethelpers.FamilyInet4}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RoutingRuleConfigSuite struct {\n\tctest.DefaultSuite\n}\n\n//nolint:goconst\nfunc (suite *RoutingRuleConfigSuite) TestMachineConfiguration() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RoutingRuleConfigController{}))\n\n\trc1 := networkcfg.NewRoutingRuleConfigV1Alpha1(1100)\n\trc1.RuleSrc = networkcfg.Prefix{Prefix: netip.MustParsePrefix(\"10.0.0.0/8\")}\n\trc1.RuleTable = nethelpers.RoutingTable(100)\n\trc1.RuleAction = nethelpers.RoutingRuleActionUnicast\n\n\trc2 := networkcfg.NewRoutingRuleConfigV1Alpha1(1200)\n\trc2.RuleDst = networkcfg.Prefix{Prefix: netip.MustParsePrefix(\"192.168.0.0/16\")}\n\trc2.RuleTable = nethelpers.RoutingTable(200)\n\n\trc3 := networkcfg.NewRoutingRuleConfigV1Alpha1(1300)\n\trc3.RuleSrc = networkcfg.Prefix{Prefix: netip.MustParsePrefix(\"2001:db8::/32\")}\n\trc3.RuleTable = nethelpers.RoutingTable(100)\n\n\trc4 := networkcfg.NewRoutingRuleConfigV1Alpha1(1400)\n\trc4.RuleTable = nethelpers.RoutingTable(100)\n\n\tctr, err := container.New(rc1, rc2, rc3, rc4)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/inet4/01100\",\n\t\t\t\"configuration/inet4/01200\",\n\t\t\t\"configuration/inet6/01300\",\n\t\t\t\"configuration/inet4/01400\",\n\t\t\t\"configuration/inet6/01400\",\n\t\t},\n\t\tfunc(r *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\n\t\t\tif strings.Contains(r.Metadata().ID(), \"inet4\") {\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t} else {\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet6, r.TypedSpec().Family)\n\t\t\t}\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"configuration/inet4/01100\":\n\t\t\t\tasrt.Equal(netip.MustParsePrefix(\"10.0.0.0/8\"), r.TypedSpec().Src)\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Dst)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(100), r.TypedSpec().Table)\n\t\t\t\tasrt.EqualValues(1100, r.TypedSpec().Priority)\n\t\t\t\tasrt.Equal(nethelpers.RoutingRuleActionUnicast, r.TypedSpec().Action)\n\t\t\tcase \"configuration/inet4/01200\":\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Src)\n\t\t\t\tasrt.Equal(netip.MustParsePrefix(\"192.168.0.0/16\"), r.TypedSpec().Dst)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(200), r.TypedSpec().Table)\n\t\t\t\tasrt.EqualValues(1200, r.TypedSpec().Priority)\n\t\t\t\tasrt.Equal(nethelpers.RoutingRuleActionUnicast, r.TypedSpec().Action) // defaults to unicast\n\t\t\tcase \"configuration/inet6/01300\":\n\t\t\t\tasrt.Equal(netip.MustParsePrefix(\"2001:db8::/32\"), r.TypedSpec().Src)\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Dst)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(100), r.TypedSpec().Table)\n\t\t\t\tasrt.EqualValues(1300, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet4/01400\":\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Src)\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Dst)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(100), r.TypedSpec().Table)\n\t\t\t\tasrt.EqualValues(1400, r.TypedSpec().Priority)\n\t\t\tcase \"configuration/inet6/01400\":\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Src)\n\t\t\t\tasrt.Equal(netip.Prefix{}, r.TypedSpec().Dst)\n\t\t\t\tasrt.Equal(nethelpers.RoutingTable(100), r.TypedSpec().Table)\n\t\t\t\tasrt.EqualValues(1400, r.TypedSpec().Priority)\n\t\t\t}\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\n//nolint:goconst\nfunc (suite *RoutingRuleConfigSuite) TestMachineConfigurationWithFwMark() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RoutingRuleConfigController{}))\n\n\trc1 := networkcfg.NewRoutingRuleConfigV1Alpha1(500)\n\trc1.RuleTable = nethelpers.RoutingTable(100)\n\trc1.RuleFwMark = 0x100\n\trc1.RuleFwMask = 0xff00\n\trc1.RuleIIFName = \"eth0\"\n\trc1.RuleOIFName = \"eth1\"\n\n\tctr, err := container.New(rc1)\n\tsuite.Require().NoError(err)\n\n\tsuite.Create(config.NewMachineConfig(ctr))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/inet4/00500\",\n\t\t\t\"configuration/inet6/00500\",\n\t\t},\n\t\tfunc(r *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tif strings.Contains(r.Metadata().ID(), \"inet4\") {\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\t} else {\n\t\t\t\tasrt.Equal(nethelpers.FamilyInet6, r.TypedSpec().Family)\n\t\t\t}\n\n\t\t\tasrt.Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(100), r.TypedSpec().Table)\n\t\t\tasrt.EqualValues(500, r.TypedSpec().Priority)\n\t\t\tasrt.EqualValues(0x100, r.TypedSpec().FwMark)\n\t\t\tasrt.EqualValues(0xff00, r.TypedSpec().FwMask)\n\t\t\tasrt.Equal(\"eth0\", r.TypedSpec().IIFName)\n\t\t\tasrt.Equal(\"eth1\", r.TypedSpec().OIFName)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc TestRoutingRuleConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RoutingRuleConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewRoutingRuleMergeController initializes a RoutingRuleMergeController.\n//\n// RoutingRuleMergeController merges network.RoutingRuleSpec in network.ConfigNamespace and produces final network.RoutingRuleSpec in network.Namespace.\nfunc NewRoutingRuleMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.RoutingRuleSpec]) map[resource.ID]*network.RoutingRuleSpecSpec {\n\t\t\t// routing rule is allowed as long as it's not duplicate, for duplicate higher layer takes precedence\n\t\t\trules := map[string]*network.RoutingRuleSpecSpec{}\n\n\t\t\tfor rule := range list.All() {\n\t\t\t\tid := network.RoutingRuleID(rule.TypedSpec().Family, rule.TypedSpec().Priority)\n\n\t\t\t\texisting, ok := rules[id]\n\t\t\t\tif ok && existing.ConfigLayer > rule.TypedSpec().ConfigLayer {\n\t\t\t\t\t// skip this rule, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\trules[id] = rule.TypedSpec()\n\t\t\t}\n\n\t\t\treturn rules\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RoutingRuleMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RoutingRuleMergeSuite) assertRoutingRules(requiredIDs []string, check func(*network.RoutingRuleSpec, *assert.Assertions)) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *RoutingRuleMergeSuite) assertNoRoutingRule(id string) {\n\tctest.AssertNoResource[*network.RoutingRuleSpec](suite, id)\n}\n\nfunc (suite *RoutingRuleMergeSuite) TestMerge() {\n\t// Create two rules with the same key (family/src/dst/priority) but different config layers.\n\t// The higher layer should win.\n\tcmdline := network.NewRoutingRuleSpec(network.ConfigNamespaceName, \"cmdline/inet4/01000\")\n\t*cmdline.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tSrc:         netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    1000,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigCmdline,\n\t}\n\n\tmachineConfig := network.NewRoutingRuleSpec(network.ConfigNamespaceName, \"configuration/inet4/01000\")\n\t*machineConfig.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tSrc:         netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\tTable:       nethelpers.RoutingTable(200),\n\t\tPriority:    1000,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\t// A unique rule with no conflict.\n\tstatic := network.NewRoutingRuleSpec(network.ConfigNamespaceName, \"configuration/inet4/02000\")\n\t*static.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDst:         netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\tTable:       nethelpers.RoutingTable(123),\n\t\tPriority:    2000,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{cmdline, machineConfig, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertRoutingRules(\n\t\t[]string{\n\t\t\t\"inet4/01000\",\n\t\t\t\"inet4/02000\",\n\t\t},\n\t\tfunc(r *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"inet4/01000\":\n\t\t\t\t// machineConfig (ConfigMachineConfiguration) has higher layer than cmdline (ConfigCmdline)\n\t\t\t\tasrt.Equal(*machineConfig.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"inet4/02000\":\n\t\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\t// Remove the higher-layer resource; cmdline should now surface.\n\tsuite.Destroy(machineConfig)\n\n\tsuite.assertRoutingRules(\n\t\t[]string{\n\t\t\t\"inet4/01000\",\n\t\t\t\"inet4/02000\",\n\t\t},\n\t\tfunc(r *network.RoutingRuleSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(resource.PhaseRunning, r.Metadata().Phase())\n\n\t\t\tswitch r.Metadata().ID() {\n\t\t\tcase \"inet4/01000\":\n\t\t\t\tasrt.Equal(*cmdline.TypedSpec(), *r.TypedSpec())\n\t\t\tcase \"inet4/02000\":\n\t\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t\t}\n\t\t},\n\t)\n\n\t// Destroy the static rule and verify it disappears.\n\tsuite.Destroy(static)\n\n\tsuite.assertNoRoutingRule(\"inet4/02000\")\n}\n\n//nolint:gocyclo\nfunc (suite *RoutingRuleMergeSuite) TestMergeFlapping() {\n\t// Simulate two conflicting rule definitions which are getting removed/added constantly.\n\tcmdline := network.NewRoutingRuleSpec(network.ConfigNamespaceName, \"cmdline/inet4/00500\")\n\t*cmdline.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tSrc:         netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    500,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigCmdline,\n\t}\n\n\tmachineConfig := network.NewRoutingRuleSpec(network.ConfigNamespaceName, \"configuration/inet4/00500\")\n\t*machineConfig.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tSrc:         netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\tTable:       nethelpers.RoutingTable(200),\n\t\tPriority:    500,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\ttestMergeFlapping(&suite.DefaultSuite, []*network.RoutingRuleSpec{cmdline, machineConfig}, \"inet4/00500\", machineConfig)\n}\n\nfunc TestRoutingRuleMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RoutingRuleMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewRoutingRuleMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RoutingRuleSpecController applies network.RoutingRuleSpec to the kernel.\ntype RoutingRuleSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RoutingRuleSpecController) Name() string {\n\treturn \"network.RoutingRuleSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.RoutingRuleSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *RoutingRuleSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// watch link changes as some routes might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_IPV4_RULE)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// list source network configuration resources\n\t\tlist, err := safe.ReaderListAll[*network.RoutingRuleSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source routing rules: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor res := range list.All() {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// list existing kernel rules\n\t\texistingRules, err := conn.Rule.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing kernel rules: %w\", err)\n\t\t}\n\n\t\tvar multiErr *multierror.Error\n\n\t\t// loop over rules and make reconcile decision\n\t\tfor rule := range list.All() {\n\t\t\tif err = ctrl.syncRule(ctx, r, logger, conn, existingRules, rule); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t}\n\t\t}\n\n\t\tif err = multiErr.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *RoutingRuleSpecController) syncRule(\n\tctx context.Context,\n\tr controller.Runtime,\n\tlogger *zap.Logger,\n\tconn *rtnetlink.Conn,\n\texistingRules []rtnetlink.RuleMessage,\n\trule *network.RoutingRuleSpec,\n) error {\n\tspec := rule.TypedSpec()\n\n\tswitch rule.Metadata().Phase() {\n\tcase resource.PhaseTearingDown:\n\t\tfor i := range existingRules {\n\t\t\tif ctrl.matchesRuleKey(&existingRules[i], spec) {\n\t\t\t\tif err := conn.Rule.Delete(&existingRules[i]); err != nil {\n\t\t\t\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\t\treturn fmt.Errorf(\"error removing routing rule: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"deleted routing rule\",\n\t\t\t\t\tzap.Uint8(\"family\", existingRules[i].Family),\n\t\t\t\t\tzap.Uint8(\"table\", existingRules[i].Table),\n\t\t\t\t\tzap.Uint8(\"action\", existingRules[i].Action),\n\t\t\t\t\tzap.Uint32(\"priority\", pointer.SafeDeref(existingRules[i].Attributes.Priority)),\n\t\t\t\t\tzap.Stringer(\"src\", pointer.SafeDeref(existingRules[i].Attributes.Src)),\n\t\t\t\t\tzap.Stringer(\"dst\", pointer.SafeDeref(existingRules[i].Attributes.Dst)),\n\t\t\t\t\tzap.String(\"iif\", pointer.SafeDeref(existingRules[i].Attributes.IIFName)),\n\t\t\t\t\tzap.String(\"oif\", pointer.SafeDeref(existingRules[i].Attributes.OIFName)),\n\t\t\t\t\tzap.Uint32(\"fwmark\", pointer.SafeDeref(existingRules[i].Attributes.FwMark)),\n\t\t\t\t\tzap.Uint32(\"fwmask\", pointer.SafeDeref(existingRules[i].Attributes.FwMask)),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\t// remove finalizer\n\t\tif err := r.RemoveFinalizer(ctx, rule.Metadata(), ctrl.Name()); err != nil {\n\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t}\n\n\tcase resource.PhaseRunning:\n\t\texistingIdx := []int{}\n\n\t\tfor i := range existingRules {\n\t\t\t// find rules that match the unique key but differ in other attributes - these need to be deleted and re-created to update\n\t\t\tif ctrl.matchesRuleKey(&existingRules[i], spec) && !ctrl.matchesRule(&existingRules[i], spec) {\n\t\t\t\texistingIdx = append(existingIdx, i)\n\t\t\t}\n\t\t}\n\n\t\tmsg := ctrl.buildRuleMessage(spec)\n\n\t\tfor _, idx := range existingIdx {\n\t\t\tif err := conn.Rule.Delete(&existingRules[idx]); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error deleting routing rule during update: %w, spec %+v\", err, *spec)\n\t\t\t}\n\t\t}\n\n\t\tif err := conn.Rule.Add(msg); err != nil {\n\t\t\t// If the rule already exists, it means there was no change in attributes and we can ignore the error.\n\t\t\tif !errors.Is(err, os.ErrExist) {\n\t\t\t\treturn fmt.Errorf(\"error adding routing rule: %w, spec %+v\", err, *spec)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\taction := \"created\"\n\t\tif len(existingIdx) > 0 {\n\t\t\taction = \"replaced\"\n\t\t}\n\n\t\tlogger.Info(action+\" routing rule\",\n\t\t\tzap.Stringer(\"family\", spec.Family),\n\t\t\tzap.Stringer(\"src\", spec.Src),\n\t\t\tzap.Stringer(\"dst\", spec.Dst),\n\t\t\tzap.Stringer(\"table\", spec.Table),\n\t\t\tzap.Uint32(\"priority\", spec.Priority),\n\t\t\tzap.Stringer(\"action\", spec.Action),\n\t\t\tzap.String(\"iif\", spec.IIFName),\n\t\t\tzap.String(\"oif\", spec.OIFName),\n\t\t\tzap.Uint32(\"fwmark\", spec.FwMark),\n\t\t\tzap.Uint32(\"fwmask\", spec.FwMask),\n\t\t)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *RoutingRuleSpecController) matchesRule(existing *rtnetlink.RuleMessage, spec *network.RoutingRuleSpecSpec) bool {\n\t// Compare priority only - this is the unique key\n\texistingPriority := pointer.SafeDeref(existing.Attributes.Priority)\n\tif existingPriority != spec.Priority {\n\t\treturn false\n\t}\n\n\t// Compare family\n\tif existing.Family != uint8(spec.Family) {\n\t\treturn false\n\t}\n\n\t// Compare action\n\tif existing.Action != uint8(spec.Action) {\n\t\treturn false\n\t}\n\n\t// compare table\n\texistingTable := uint32(existing.Table)\n\tif existing.Attributes.Table != nil {\n\t\texistingTable = *existing.Attributes.Table\n\t}\n\n\tif existingTable != uint32(spec.Table) {\n\t\treturn false\n\t}\n\n\t// compare src\n\tif !ctrl.matchesPrefix(existing.Attributes.Src, existing.SrcLength, spec.Src, spec.Family) {\n\t\treturn false\n\t}\n\n\t// compare dst\n\tif !ctrl.matchesPrefix(existing.Attributes.Dst, existing.DstLength, spec.Dst, spec.Family) {\n\t\treturn false\n\t}\n\n\t// compare iif/oif\n\tif pointer.SafeDeref(existing.Attributes.IIFName) != spec.IIFName {\n\t\treturn false\n\t}\n\n\tif pointer.SafeDeref(existing.Attributes.OIFName) != spec.OIFName {\n\t\treturn false\n\t}\n\n\t// compare fwmark/fwmask\n\tif pointer.SafeDeref(existing.Attributes.FwMark) != spec.FwMark {\n\t\treturn false\n\t}\n\n\tif pointer.SafeDeref(existing.Attributes.FwMask) != spec.FwMask {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n//nolint:gocyclo\nfunc (ctrl *RoutingRuleSpecController) matchesPrefix(existingIP *net.IP, existingLen uint8, specPrefix netip.Prefix, family nethelpers.Family) bool {\n\tif specPrefix.IsValid() {\n\t\tif family == nethelpers.FamilyInet4 && !specPrefix.Addr().Is4() {\n\t\t\treturn false\n\t\t}\n\n\t\tif family == nethelpers.FamilyInet6 && !specPrefix.Addr().Is6() {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif !specPrefix.IsValid() || specPrefix.Bits() == 0 {\n\t\treturn existingLen == 0\n\t}\n\n\tif existingLen != uint8(specPrefix.Bits()) {\n\t\treturn false\n\t}\n\n\tif existingIP == nil {\n\t\treturn false\n\t}\n\n\texistingAddr, ok := netip.AddrFromSlice(*existingIP)\n\tif !ok {\n\t\treturn false\n\t}\n\n\treturn existingAddr == specPrefix.Addr()\n}\n\nfunc (ctrl *RoutingRuleSpecController) matchesRuleKey(existing *rtnetlink.RuleMessage, spec *network.RoutingRuleSpecSpec) bool {\n\tif pointer.SafeDeref(existing.Attributes.Priority) != spec.Priority {\n\t\treturn false\n\t}\n\n\tif existing.Family != uint8(spec.Family) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (ctrl *RoutingRuleSpecController) buildRuleMessage(spec *network.RoutingRuleSpecSpec) *rtnetlink.RuleMessage {\n\tmsg := &rtnetlink.RuleMessage{\n\t\tFamily: uint8(spec.Family),\n\t\tTable:  uint8(spec.Table),\n\t\tAction: uint8(spec.Action),\n\t\tAttributes: &rtnetlink.RuleAttributes{\n\t\t\tPriority: new(spec.Priority),\n\t\t\tTable:    new(uint32(spec.Table)),\n\t\t},\n\t}\n\n\tif spec.Src.IsValid() && spec.Src.Bits() > 0 {\n\t\tmsg.SrcLength = uint8(spec.Src.Bits())\n\n\t\tsrcIP := net.IP(spec.Src.Addr().AsSlice())\n\t\tmsg.Attributes.Src = &srcIP\n\t}\n\n\tif spec.Dst.IsValid() && spec.Dst.Bits() > 0 {\n\t\tmsg.DstLength = uint8(spec.Dst.Bits())\n\n\t\tdstIP := net.IP(spec.Dst.Addr().AsSlice())\n\t\tmsg.Attributes.Dst = &dstIP\n\t}\n\n\tif spec.IIFName != \"\" {\n\t\tmsg.Attributes.IIFName = new(spec.IIFName)\n\t}\n\n\tif spec.OIFName != \"\" {\n\t\tmsg.Attributes.OIFName = new(spec.OIFName)\n\t}\n\n\tif spec.FwMark != 0 {\n\t\tmsg.Attributes.FwMark = new(spec.FwMark)\n\t}\n\n\tif spec.FwMask != 0 {\n\t\tmsg.Attributes.FwMask = new(spec.FwMask)\n\t}\n\n\t// set protocol to indicate this rule was created by us\n\tproto := uint8(unix.RTPROT_STATIC)\n\tmsg.Attributes.Protocol = &proto\n\n\treturn msg\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RoutingRuleSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RoutingRuleSpecSuite) assertRule(\n\tfamily nethelpers.Family,\n\tsrc, dst netip.Prefix,\n\tpriority uint32,\n\tcheck func(rtnetlink.RuleMessage) error,\n) error {\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\trules, err := conn.Rule.List()\n\tsuite.Require().NoError(err)\n\n\tfor _, rule := range rules {\n\t\tif rule.Family != uint8(family) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif pointer.SafeDeref(rule.Attributes.Priority) != priority {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !matchPrefix(rule.Attributes.Src, rule.SrcLength, src) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !matchPrefix(rule.Attributes.Dst, rule.DstLength, dst) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = check(rule); err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn retry.ExpectedErrorf(\"rule family=%s src=%s dst=%s priority=%d not found\", family, src, dst, priority)\n}\n\nfunc (suite *RoutingRuleSpecSuite) assertNoRule(\n\tfamily nethelpers.Family,\n\tsrc, dst netip.Prefix,\n\tpriority uint32,\n) error {\n\tconn, err := rtnetlink.Dial(nil)\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\trules, err := conn.Rule.List()\n\tsuite.Require().NoError(err)\n\n\tfor _, rule := range rules {\n\t\tif rule.Family != uint8(family) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif pointer.SafeDeref(rule.Attributes.Priority) != priority {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !matchPrefix(rule.Attributes.Src, rule.SrcLength, src) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !matchPrefix(rule.Attributes.Dst, rule.DstLength, dst) {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn retry.ExpectedErrorf(\"rule family=%s src=%q dst=%q priority=%d is still present\", family, src, dst, priority)\n\t}\n\n\treturn nil\n}\n\nfunc matchPrefix(ip *net.IP, length uint8, prefix netip.Prefix) bool {\n\tif !prefix.IsValid() || prefix.Bits() == 0 {\n\t\treturn length == 0\n\t}\n\n\tif length != uint8(prefix.Bits()) {\n\t\treturn false\n\t}\n\n\tif ip == nil {\n\t\treturn false\n\t}\n\n\taddr, ok := netip.AddrFromSlice(*ip)\n\tif !ok {\n\t\treturn false\n\t}\n\n\treturn addr == prefix.Addr()\n}\n\n//nolint:dupl\nfunc (suite *RoutingRuleSpecSuite) TestCreateAndDelete() {\n\tpriority := uint32(31000)\n\n\t// Use a high priority number to avoid conflicting with default rules.\n\trule := network.NewRoutingRuleSpec(network.NamespaceName, \"test-rule\")\n\t*rule.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tSrc:         netip.MustParsePrefix(\"10.99.0.0/16\"),\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    priority,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tsuite.Create(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.MustParsePrefix(\"10.99.0.0/16\"),\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\ttable := uint32(r.Table)\n\t\t\t\t\t\tif r.Attributes.Table != nil {\n\t\t\t\t\t\t\ttable = *r.Attributes.Table\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif table != 100 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected table: got %d, want %d\", table, 100)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif r.Action != unix.FR_ACT_TO_TBL {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected action: got %d, want %d\", r.Action, unix.FR_ACT_TO_TBL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// Teardown the rule.\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), rule.Metadata()))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.MustParsePrefix(\"10.99.0.0/16\"),\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\n//nolint:dupl\nfunc (suite *RoutingRuleSpecSuite) TestFwMarkUpdate() {\n\tpriority := uint32(31002)\n\n\trule := network.NewRoutingRuleSpec(network.NamespaceName, \"fwmark-update-rule\")\n\t*rule.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    priority,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tFwMark:      0x100,\n\t\tFwMask:      0xff00,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tsuite.Create(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMark) != 0x100 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmark: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMark), 0x100)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMask) != 0xff00 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmask: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMask), 0xff00)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// finalizer updates the rule, so we need to fetch the latest version before proceeding with the update.\n\tr, err := suite.State().Get(suite.Ctx(), rule.Metadata())\n\tsuite.Require().NoError(err)\n\n\trule = r.(*network.RoutingRuleSpec)\n\trule.TypedSpec().FwMark = 0x200\n\tsuite.Update(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMark) != 0x200 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmark after update: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMark), 0x200)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMask) != 0xff00 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmask after update: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMask), 0xff00)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), rule.Metadata()))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\n//nolint:dupl\nfunc (suite *RoutingRuleSpecSuite) TestFwMark() {\n\tpriority := uint32(31001)\n\n\trule := network.NewRoutingRuleSpec(network.NamespaceName, \"fwmark-rule\")\n\t*rule.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    priority,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tFwMark:      0x100,\n\t\tFwMask:      0xff00,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tsuite.Create(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMark) != 0x100 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmark: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMark), 0x100)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif pointer.SafeDeref(r.Attributes.FwMask) != 0xff00 {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected fwmask: got %x, want %x\", pointer.SafeDeref(r.Attributes.FwMask), 0xff00)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\t// Teardown.\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), rule.Metadata()))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\n//nolint:dupl\nfunc (suite *RoutingRuleSpecSuite) TestIPv6() {\n\tpriority := uint32(31003)\n\n\trule := network.NewRoutingRuleSpec(network.NamespaceName, \"ipv6-rule\")\n\t*rule.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet6,\n\t\tSrc:         netip.MustParsePrefix(\"fd00::/8\"),\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    priority,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tsuite.Create(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet6,\n\t\t\t\t\tnetip.MustParsePrefix(\"fd00::/8\"),\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\tif r.Action != unix.FR_ACT_TO_TBL {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected action: got %d, want %d\", r.Action, unix.FR_ACT_TO_TBL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), rule.Metadata()))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoRule(\n\t\t\t\t\tnethelpers.FamilyInet6,\n\t\t\t\t\tnetip.MustParsePrefix(\"fd00::/8\"),\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tpriority,\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\n//nolint:dupl\nfunc (suite *RoutingRuleSpecSuite) TestDstPrefix() {\n\tpriority := uint32(31004)\n\n\trule := network.NewRoutingRuleSpec(network.NamespaceName, \"dst-prefix-rule\")\n\t*rule.TypedSpec() = network.RoutingRuleSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDst:         netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\tTable:       nethelpers.RoutingTable(100),\n\t\tPriority:    priority,\n\t\tAction:      nethelpers.RoutingRuleActionUnicast,\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tsuite.Create(rule)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\tpriority,\n\t\t\t\t\tfunc(r rtnetlink.RuleMessage) error {\n\t\t\t\t\t\tif r.Action != unix.FR_ACT_TO_TBL {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"unexpected action: got %d, want %d\", r.Action, unix.FR_ACT_TO_TBL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().TeardownAndDestroy(suite.Ctx(), rule.Metadata()))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertNoRule(\n\t\t\t\t\tnethelpers.FamilyInet4,\n\t\t\t\t\tnetip.Prefix{},\n\t\t\t\t\tnetip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\tpriority,\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc TestRoutingRuleSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, &RoutingRuleSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 15 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RoutingRuleSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// RoutingRuleStatusController observes kernel routing rules and publishes them as resources.\ntype RoutingRuleStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *RoutingRuleStatusController) Name() string {\n\treturn \"network.RoutingRuleStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *RoutingRuleStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.RoutingRuleStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *RoutingRuleStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// watch link changes as some routes might need to be re-applied if the link appears\n\twatcher, err := watch.NewRtNetlink(watch.NewDefaultRateLimitedTrigger(ctx, r), unix.RTMGRP_IPV4_RULE,\n\t\tunix.RTNLGRP_IPV4_RULE, unix.RTNLGRP_IPV6_RULE)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Done()\n\n\tconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rtnetlink socket: %w\", err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\trules, err := conn.Rule.List()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing kernel rules: %w\", err)\n\t\t}\n\n\t\tfor _, rule := range rules {\n\t\t\tfamily := nethelpers.Family(rule.Family)\n\n\t\t\tvar src netip.Prefix\n\n\t\t\tif rule.Attributes.Src != nil {\n\t\t\t\tsrcAddr, ok := netip.AddrFromSlice(*rule.Attributes.Src)\n\t\t\t\tif ok {\n\t\t\t\t\tsrc = netip.PrefixFrom(srcAddr, int(rule.SrcLength))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar dst netip.Prefix\n\n\t\t\tif rule.Attributes.Dst != nil {\n\t\t\t\tdstAddr, ok := netip.AddrFromSlice(*rule.Attributes.Dst)\n\t\t\t\tif ok {\n\t\t\t\t\tdst = netip.PrefixFrom(dstAddr, int(rule.DstLength))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpriority := pointer.SafeDeref(rule.Attributes.Priority)\n\n\t\t\ttable := uint32(rule.Table)\n\t\t\tif rule.Attributes.Table != nil {\n\t\t\t\ttable = *rule.Attributes.Table\n\t\t\t}\n\n\t\t\tid := network.RoutingRuleID(family, priority)\n\n\t\t\tif err = safe.WriterModify(ctx, r, network.NewRoutingRuleStatus(network.NamespaceName, id), func(res *network.RoutingRuleStatus) error {\n\t\t\t\tstatus := res.TypedSpec()\n\n\t\t\t\tstatus.Family = family\n\t\t\t\tstatus.Src = src\n\t\t\t\tstatus.Dst = dst\n\t\t\t\tstatus.Table = nethelpers.RoutingTable(table)\n\t\t\t\tstatus.Priority = priority\n\t\t\t\tstatus.Action = nethelpers.RoutingRuleAction(rule.Action)\n\t\t\t\tstatus.IIFName = pointer.SafeDeref(rule.Attributes.IIFName)\n\t\t\t\tstatus.OIFName = pointer.SafeDeref(rule.Attributes.OIFName)\n\t\t\t\tstatus.FwMark = pointer.SafeDeref(rule.Attributes.FwMark)\n\t\t\t\tstatus.FwMask = pointer.SafeDeref(rule.Attributes.FwMask)\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*network.RoutingRuleStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"error doing cleanup: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/routing_rule_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype RoutingRuleStatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RoutingRuleStatusSuite) TestRules() {\n\t// Every Linux system has default rules:\n\t//   0:      from all lookup local\n\t//   32766:  from all lookup main\n\t//   32767:  from all lookup default\n\t//\n\t// Assert that at least the \"from all lookup local\" rule (priority 0, table 255/local) is published.\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"inet4/00000\",\n\t\tfunc(r *network.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(255), r.TypedSpec().Table) // local table\n\t\t\tasrt.EqualValues(0, r.TypedSpec().Priority)\n\t\t\tasrt.Equal(nethelpers.RoutingRuleActionUnicast, r.TypedSpec().Action)\n\t\t},\n\t)\n}\n\nfunc TestRoutingRuleStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RoutingRuleStatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.RoutingRuleStatusController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// StatusController manages network.Status based on state of other resources.\ntype StatusController struct {\n\tV1Alpha1Mode runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *StatusController) Name() string {\n\treturn \"network.StatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *StatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.NodeAddressCurrentID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.RouteStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: files.NamespaceName,\n\t\t\tType:      files.EtcFileStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.ProbeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *StatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.StatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *StatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tresult := network.StatusSpec{}\n\n\t\t// addresses\n\t\tcurrentAddresses, err := safe.ReaderGet[*network.NodeAddress](ctx, r, resource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.NodeAddressCurrentID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting resource: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tresult.AddressReady = len(currentAddresses.TypedSpec().Addresses) > 0\n\t\t}\n\n\t\t// connectivity\n\t\t// if any probes are defined, use their status, otherwise rely on presence of the default gateway\n\t\tprobeStatuses, err := safe.ReaderListAll[*network.ProbeStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting probe statuses: %w\", err)\n\t\t}\n\n\t\tallProbesSuccess := true\n\n\t\tfor res := range probeStatuses.All() {\n\t\t\tif !res.TypedSpec().Success {\n\t\t\t\tallProbesSuccess = false\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif probeStatuses.Len() > 0 && allProbesSuccess {\n\t\t\tresult.ConnectivityReady = true\n\t\t} else if probeStatuses.Len() == 0 {\n\t\t\tvar routes safe.List[*network.RouteStatus]\n\n\t\t\troutes, err = safe.ReaderListAll[*network.RouteStatus](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting routes: %w\", err)\n\t\t\t}\n\n\t\t\tfor route := range routes.All() {\n\t\t\t\tif value.IsZero(route.TypedSpec().Destination) {\n\t\t\t\t\tresult.ConnectivityReady = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// hostname\n\t\t_, err = r.Get(ctx, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting resource: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tresult.HostnameReady = true\n\t\t}\n\n\t\t// etc files\n\t\tresult.EtcFilesReady = true\n\n\t\tfor _, requiredFile := range []string{\"hosts\", \"resolv.conf\"} {\n\t\t\t// in container mode, ignore resolv.conf, it's managed by the container runtime\n\t\t\tif ctrl.V1Alpha1Mode.InContainer() && requiredFile == \"resolv.conf\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t_, err = r.Get(ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, requiredFile, resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error getting resource: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tresult.EtcFilesReady = false\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// update output status\n\t\tif err = safe.WriterModify(ctx, r, network.NewStatus(network.NamespaceName, network.StatusID),\n\t\t\tfunc(r *network.Status) error {\n\t\t\t\t*r.TypedSpec() = result\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying output status: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype StatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *StatusSuite) TestNone() {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{}, *r.TypedSpec())\n\t})\n}\n\nfunc (suite *StatusSuite) TestAddresses() {\n\tnodeAddress := network.NewNodeAddress(network.NamespaceName, network.NodeAddressCurrentID)\n\tnodeAddress.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"10.0.0.1/24\")}\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddress))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{AddressReady: true}, *r.TypedSpec())\n\t})\n}\n\nfunc (suite *StatusSuite) TestRoutes() {\n\troute := network.NewRouteStatus(network.NamespaceName, \"foo\")\n\troute.TypedSpec().Gateway = netip.MustParseAddr(\"10.0.0.1\")\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), route))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{ConnectivityReady: true}, *r.TypedSpec())\n\t})\n}\n\nfunc (suite *StatusSuite) TestProbeStatuses() {\n\tprobeStatus := network.NewProbeStatus(network.NamespaceName, \"foo\")\n\tprobeStatus.TypedSpec().Success = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), probeStatus))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{ConnectivityReady: true}, *r.TypedSpec())\n\t})\n\n\t// failing probe make status not ready\n\troute := network.NewRouteStatus(network.NamespaceName, \"foo\")\n\troute.TypedSpec().Gateway = netip.MustParseAddr(\"10.0.0.1\")\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), route))\n\n\tprobeStatusFail := network.NewProbeStatus(network.NamespaceName, \"failing\")\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), probeStatusFail))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{}, *r.TypedSpec())\n\t})\n}\n\nfunc (suite *StatusSuite) TestHostname() {\n\thostname := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostname.TypedSpec().Hostname = \"foo\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostname))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{HostnameReady: true}, *r.TypedSpec())\n\t})\n}\n\nfunc (suite *StatusSuite) TestEtcFiles() {\n\tfor _, f := range []string{\"hosts\", \"resolv.conf\"} {\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), files.NewEtcFileStatus(files.NamespaceName, f)))\n\t}\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{network.StatusID}, func(r *network.Status, assert *assert.Assertions) {\n\t\tassert.Equal(network.StatusSpec{EtcFilesReady: true}, *r.TypedSpec())\n\t})\n}\n\nfunc TestStatusSuite(t *testing.T) {\n\tsuite.Run(t, &StatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(\n\t\t\t\t\t&netctrl.StatusController{\n\t\t\t\t\t\tV1Alpha1Mode: runtime.ModeMetal,\n\t\t\t\t\t},\n\t\t\t\t))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// TimeServerConfigController manages network.TimeServerSpec based on machine configuration, kernel cmdline.\ntype TimeServerConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *TimeServerConfigController) Name() string {\n\treturn \"network.TimeServerConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *TimeServerConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *TimeServerConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.TimeServerSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *TimeServerConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\ttouchedIDs := make(map[resource.ID]struct{})\n\n\t\tvar cfgProvider talosconfig.Config\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tcfgProvider = cfg.Config()\n\t\t}\n\n\t\tvar specs []network.TimeServerSpecSpec\n\n\t\t// defaults\n\t\tspecs = append(specs, ctrl.getDefault())\n\n\t\t// parse kernel cmdline for the default gateway\n\t\tcmdlineServers := ctrl.parseCmdline(logger)\n\t\tif cmdlineServers.NTPServers != nil {\n\t\t\tspecs = append(specs, cmdlineServers)\n\t\t}\n\n\t\t// parse machine configuration for specs\n\t\tif cfgProvider != nil {\n\t\t\tconfigServers := ctrl.parseMachineConfiguration(cfgProvider)\n\n\t\t\tif configServers.NTPServers != nil {\n\t\t\t\tspecs = append(specs, configServers)\n\t\t\t}\n\t\t}\n\n\t\tvar ids []string\n\n\t\tids, err = ctrl.apply(ctx, r, specs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error applying specs: %w\", err)\n\t\t}\n\n\t\tfor _, id := range ids {\n\t\t\ttouchedIDs[id] = struct{}{}\n\t\t}\n\n\t\t// list specs for cleanup\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.TimeServerSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing resources: %w\", err)\n\t\t}\n\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Owner() != ctrl.Name() {\n\t\t\t\t// skip specs created by other controllers\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif _, ok := touchedIDs[res.Metadata().ID()]; !ok {\n\t\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error cleaning up specs: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:dupl\nfunc (ctrl *TimeServerConfigController) apply(ctx context.Context, r controller.Runtime, specs []network.TimeServerSpecSpec) ([]resource.ID, error) {\n\tids := make([]string, 0, len(specs))\n\n\tfor _, spec := range specs {\n\t\tid := network.LayeredID(spec.ConfigLayer, network.TimeServerID)\n\n\t\tif err := safe.WriterModify(\n\t\t\tctx,\n\t\t\tr,\n\t\t\tnetwork.NewTimeServerSpec(network.ConfigNamespaceName, id),\n\t\t\tfunc(r *network.TimeServerSpec) error {\n\t\t\t\t*r.TypedSpec() = spec\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn ids, err\n\t\t}\n\n\t\tids = append(ids, id)\n\t}\n\n\treturn ids, nil\n}\n\nfunc (ctrl *TimeServerConfigController) getDefault() (spec network.TimeServerSpecSpec) {\n\tspec.NTPServers = []string{constants.DefaultNTPServer}\n\tspec.ConfigLayer = network.ConfigDefault\n\n\treturn spec\n}\n\nfunc (ctrl *TimeServerConfigController) parseCmdline(logger *zap.Logger) (spec network.TimeServerSpecSpec) {\n\tif ctrl.Cmdline == nil {\n\t\treturn spec\n\t}\n\n\tsettings, err := ParseCmdlineNetwork(ctrl.Cmdline, network.NewEmptyLinkResolver())\n\tif err != nil {\n\t\tlogger.Warn(\"ignoring error\", zap.Error(err))\n\n\t\treturn spec\n\t}\n\n\tif len(settings.NTPAddresses) == 0 {\n\t\treturn spec\n\t}\n\n\tspec.NTPServers = make([]string, len(settings.NTPAddresses))\n\tspec.ConfigLayer = network.ConfigCmdline\n\n\tfor i := range settings.NTPAddresses {\n\t\tspec.NTPServers[i] = settings.NTPAddresses[i].String()\n\t}\n\n\treturn spec\n}\n\nfunc (ctrl *TimeServerConfigController) parseMachineConfiguration(cfgProvider talosconfig.Config) (spec network.TimeServerSpecSpec) {\n\tif cfgProvider.NetworkTimeSyncConfig() == nil {\n\t\treturn spec\n\t}\n\n\tspec.NTPServers = slices.Clone(cfgProvider.NetworkTimeSyncConfig().Servers())\n\tspec.ConfigLayer = network.ConfigMachineConfiguration\n\n\treturn spec\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype TimeServerConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TimeServerConfigSuite) TestDefaults() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.TimeServerConfigController{}))\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"default/timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{constants.DefaultNTPServer}, r.TypedSpec().NTPServers)\n\t\t\tasrt.Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *TimeServerConfigSuite) TestCmdline() {\n\tsuite.Require().NoError(\n\t\tsuite.Runtime().RegisterController(\n\t\t\t&netctrl.TimeServerConfigController{\n\t\t\t\tCmdline: procfs.NewCmdline(\"ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1\"),\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"cmdline/timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{\"10.0.0.1\"}, r.TypedSpec().NTPServers)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *TimeServerConfigSuite) TestMachineConfigurationLegacy() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.TimeServerConfigController{}))\n\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeServers: []string{\"za.pool.ntp.org\", \"pool.ntp.org\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{\"za.pool.ntp.org\", \"pool.ntp.org\"}, r.TypedSpec().NTPServers)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error {\n\t\tr.Container().RawV1Alpha1().MachineConfig.MachineTime = nil //nolint:staticcheck\n\n\t\treturn nil\n\t})\n\n\tctest.AssertNoResource[*network.TimeServerSpec](suite, \"configuration/timeservers\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc (suite *TimeServerConfigSuite) TestMachineConfigurationNewStyle() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.TimeServerConfigController{}))\n\n\ttsc := networkcfg.NewTimeSyncConfigV1Alpha1()\n\ttsc.TimeNTP = &networkcfg.NTPConfig{\n\t\tServers: []string{\"za.pool.ntp.org\", \"pool.ntp.org\"},\n\t}\n\n\tctr, err := container.New(tsc)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertResources(\n\t\tsuite,\n\t\t[]string{\n\t\t\t\"configuration/timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{\"za.pool.ntp.org\", \"pool.ntp.org\"}, r.TypedSpec().NTPServers)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tsuite.Destroy(cfg)\n\n\tctest.AssertNoResource[*network.TimeServerSpec](suite, \"configuration/timeservers\", rtestutils.WithNamespace(network.ConfigNamespaceName))\n}\n\nfunc TestTimeServerConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TimeServerConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides controllers which manage network resources.\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NewTimeServerMergeController initializes a TimeServerMergeController.\n//\n// TimeServerMergeController merges network.TimeServerSpec in network.ConfigNamespace and produces final network.TimeServerSpec in network.Namespace.\nfunc NewTimeServerMergeController() controller.Controller {\n\treturn GenericMergeController(\n\t\tnetwork.ConfigNamespaceName,\n\t\tnetwork.NamespaceName,\n\t\tfunc(logger *zap.Logger, list safe.List[*network.TimeServerSpec]) map[resource.ID]*network.TimeServerSpecSpec {\n\t\t\t// simply merge by layers, overriding with the next configuration layer\n\t\t\tvar final network.TimeServerSpecSpec\n\n\t\t\tfor spec := range list.All() {\n\t\t\t\tif final.NTPServers != nil && spec.TypedSpec().ConfigLayer < final.ConfigLayer {\n\t\t\t\t\t// skip this spec, as existing one is higher layer\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif spec.TypedSpec().ConfigLayer == final.ConfigLayer {\n\t\t\t\t\t// merge server lists on the same level\n\t\t\t\t\tfinal.NTPServers = append(final.NTPServers, spec.TypedSpec().NTPServers...)\n\t\t\t\t} else {\n\t\t\t\t\t// otherwise, replace the lists\n\t\t\t\t\tfinal = *spec.TypedSpec()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif final.NTPServers != nil {\n\t\t\t\treturn map[resource.ID]*network.TimeServerSpecSpec{\n\t\t\t\t\tnetwork.TimeServerID: &final,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype TimeServerMergeSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TimeServerMergeSuite) assertTimeServers(\n\trequiredIDs []string,\n\tcheck func(*network.TimeServerSpec, *assert.Assertions),\n) {\n\tctest.AssertResources(suite, requiredIDs, check)\n}\n\nfunc (suite *TimeServerMergeSuite) TestMerge() {\n\tdef := network.NewTimeServerSpec(network.ConfigNamespaceName, \"default/timeservers\")\n\t*def.TypedSpec() = network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{constants.DefaultNTPServer},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tdhcp1 := network.NewTimeServerSpec(network.ConfigNamespaceName, \"dhcp/eth0\")\n\t*dhcp1.TypedSpec() = network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{\"ntp.eth0\"},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tdhcp2 := network.NewTimeServerSpec(network.ConfigNamespaceName, \"dhcp/eth1\")\n\t*dhcp2.TypedSpec() = network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{\"ntp.eth1\"},\n\t\tConfigLayer: network.ConfigOperator,\n\t}\n\n\tstatic := network.NewTimeServerSpec(network.ConfigNamespaceName, \"configuration/timeservers\")\n\t*static.TypedSpec() = network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{\"my.ntp\"},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tfor _, res := range []resource.Resource{def, dhcp1, dhcp2, static} {\n\t\tsuite.Create(res)\n\t}\n\n\tsuite.assertTimeServers(\n\t\t[]string{\n\t\t\t\"timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(*static.TypedSpec(), *r.TypedSpec())\n\t\t},\n\t)\n\n\tsuite.Destroy(static)\n\n\tsuite.assertTimeServers(\n\t\t[]string{\n\t\t\t\"timeservers\",\n\t\t}, func(r *network.TimeServerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{\"ntp.eth0\", \"ntp.eth1\"}, r.TypedSpec().NTPServers)\n\t\t},\n\t)\n}\n\nfunc TestTimeServerMergeSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TimeServerMergeSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(netctrl.NewTimeServerMergeController()))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// TimeServerSpecController applies network.TimeServerSpec to the actual interfaces.\ntype TimeServerSpecController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *TimeServerSpecController) Name() string {\n\treturn \"network.TimeServerSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *TimeServerSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.TimeServerSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *TimeServerSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.TimeServerStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *TimeServerSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// as there's nothing to do actually apply time servers, simply copy spec to status\n\n\t\t// list source network configuration resources\n\t\tlist, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.TimeServerSpecType, \"\", resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing source network addresses: %w\", err)\n\t\t}\n\n\t\t// add finalizers for all live resources\n\t\tfor _, res := range list.Items {\n\t\t\tif res.Metadata().Phase() != resource.PhaseRunning {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = r.AddFinalizer(ctx, res.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error adding finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// loop over specs and sync to statuses\n\t\tfor _, res := range list.Items {\n\t\t\tspec := res.(*network.TimeServerSpec) //nolint:forcetypeassert\n\n\t\t\tswitch spec.Metadata().Phase() {\n\t\t\tcase resource.PhaseTearingDown:\n\t\t\t\tif err = r.Destroy(ctx, resource.NewMetadata(network.NamespaceName, network.TimeServerStatusType, spec.Metadata().ID(), resource.VersionUndefined)); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying status: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = r.RemoveFinalizer(ctx, spec.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer: %w\", err)\n\t\t\t\t}\n\t\t\tcase resource.PhaseRunning:\n\t\t\t\tntps := make([]string, len(spec.TypedSpec().NTPServers))\n\n\t\t\t\tfor i := range ntps {\n\t\t\t\t\tntps[i] = spec.TypedSpec().NTPServers[i]\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"setting time servers\", zap.Strings(\"addresses\", ntps))\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, network.NewTimeServerStatus(network.NamespaceName, spec.Metadata().ID()), func(status *network.TimeServerStatus) error {\n\t\t\t\t\tstatus.TypedSpec().NTPServers = spec.TypedSpec().NTPServers\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error modifying status: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/timeserver_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tnetctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\ntype TimeServerSpecSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TimeServerSpecSuite) TestSpec() {\n\tspec := network.NewTimeServerSpec(network.NamespaceName, \"timeservers\")\n\t*spec.TypedSpec() = network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{constants.DefaultNTPServer},\n\t\tConfigLayer: network.ConfigDefault,\n\t}\n\n\tsuite.Create(spec)\n\n\tctest.AssertResource(\n\t\tsuite,\n\t\t\"timeservers\",\n\t\tfunc(status *network.TimeServerStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{constants.DefaultNTPServer}, status.TypedSpec().NTPServers)\n\t\t},\n\t)\n}\n\nfunc TestTimeServerSpecSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TimeServerSpecSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&netctrl.TimeServerSpecController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/utils/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package networkutils provides utilities for controllers to interact with network resources.\npackage networkutils\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// WaitForNetworkReady waits for devices to be ready.\n//\n// It is a helper function for controllers.\nfunc WaitForNetworkReady(ctx context.Context, r controller.Runtime, condition func(*network.StatusSpec) bool, nextInputs []controller.Input) error {\n\t// set inputs temporarily to a service only\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tstatus, err := safe.ReaderGetByID[*network.Status](ctx, r, network.StatusID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif condition(status.TypedSpec()) {\n\t\t\t// condition met\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// restore inputs\n\tif err := r.UpdateInputs(nextInputs); err != nil {\n\t\treturn err\n\t}\n\n\t// queue an update to reprocess with new inputs\n\tr.QueueReconcile()\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/watch/ethtool.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage watch\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/mdlayher/genetlink\"\n\t\"golang.org/x/sys/unix\"\n)\n\ntype ethtoolWatcher struct {\n\twg   sync.WaitGroup\n\tconn *genetlink.Conn\n}\n\n// NewEthtool starts ethtool watch.\nfunc NewEthtool(trigger Trigger) (Watcher, error) {\n\twatcher := &ethtoolWatcher{}\n\n\tvar err error\n\n\twatcher.conn, err = genetlink.Dial(nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error dialing ethtool watch socket: %w\", err)\n\t}\n\n\tethFamily, err := watcher.conn.GetFamily(unix.ETHTOOL_GENL_NAME)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting family information for ethtool: %w\", err)\n\t}\n\n\tvar monitorID uint32\n\n\tfor _, g := range ethFamily.Groups {\n\t\tif g.Name == unix.ETHTOOL_MCGRP_MONITOR_NAME {\n\t\t\tmonitorID = g.ID\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif monitorID == 0 {\n\t\treturn nil, errors.New(\"could not find monitor multicast group ID for ethtool\")\n\t}\n\n\tif err = watcher.conn.JoinGroup(monitorID); err != nil {\n\t\treturn nil, fmt.Errorf(\"error joing multicast group for ethtool: %w\", err)\n\t}\n\n\twatcher.wg.Go(func() {\n\t\tfor {\n\t\t\t_, _, watchErr := watcher.conn.Receive()\n\t\t\tif watchErr != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttrigger.QueueReconcile()\n\t\t}\n\t})\n\n\treturn watcher, nil\n}\n\nfunc (watcher *ethtoolWatcher) Done() {\n\twatcher.conn.Close() //nolint:errcheck\n\n\twatcher.wg.Wait()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/watch/rtnetlink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage watch\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/mdlayher/netlink\"\n)\n\ntype rtnetlinkWatcher struct {\n\twg   sync.WaitGroup\n\tconn *rtnetlink.Conn\n}\n\n// NewRtNetlink starts rtnetlink watch over specified groups.\nfunc NewRtNetlink(trigger Trigger, groups uint32, netlinkGroups ...uint32) (Watcher, error) {\n\twatcher := &rtnetlinkWatcher{}\n\n\tvar err error\n\n\twatcher.conn, err = rtnetlink.Dial(&netlink.Config{\n\t\tGroups: groups,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error dialing watch socket: %w\", err)\n\t}\n\n\tfor _, group := range netlinkGroups {\n\t\tif err := watcher.conn.JoinGroup(group); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error joining group %d: %w\", group, err)\n\t\t}\n\t}\n\n\twatcher.wg.Go(func() {\n\t\tfor {\n\t\t\t_, _, watchErr := watcher.conn.Receive()\n\t\t\tif watchErr != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttrigger.QueueReconcile()\n\t\t}\n\t})\n\n\treturn watcher, nil\n}\n\nfunc (watcher *rtnetlinkWatcher) Done() {\n\twatcher.conn.Close() //nolint:errcheck\n\n\twatcher.wg.Wait()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/watch/trigger.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage watch\n\nimport (\n\t\"context\"\n\n\t\"golang.org/x/time/rate\"\n)\n\n// RateLimitedTrigger wraps a Trigger with rate limiting.\ntype RateLimitedTrigger struct {\n\ttrigger Trigger\n\tlimiter *rate.Limiter\n\tch      chan struct{}\n}\n\n// Interface check.\nvar _ Trigger = &RateLimitedTrigger{}\n\n// NewRateLimitedTrigger creates a new RateLimitedTrigger with specified params.\n//\n// Trigger's goroutine exists when the context is canceled.\nfunc NewRateLimitedTrigger(ctx context.Context, trigger Trigger, rateLimit rate.Limit, burst int) *RateLimitedTrigger {\n\tt := &RateLimitedTrigger{\n\t\ttrigger: trigger,\n\t\tlimiter: rate.NewLimiter(rateLimit, burst),\n\t\tch:      make(chan struct{}),\n\t}\n\n\tgo t.run(ctx)\n\n\treturn t\n}\n\n// NewDefaultRateLimitedTrigger creates a new RateLimitedTrigger with default params.\nfunc NewDefaultRateLimitedTrigger(ctx context.Context, trigger Trigger) *RateLimitedTrigger {\n\tconst (\n\t\tdefaultRate  = 10 // 10 events per second\n\t\tdefaultBurst = 5  // 5 events\n\t)\n\n\treturn NewRateLimitedTrigger(ctx, trigger, defaultRate, defaultBurst)\n}\n\n// QueueReconcile implements Trigger interface.\n//\n// The event is queued if the goroutine is ready to accept it (otherwise it's already\n// busy processing a previous event).\n// This function returns immediately.\nfunc (t *RateLimitedTrigger) QueueReconcile() {\n\tselect {\n\tcase t.ch <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc (t *RateLimitedTrigger) run(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-t.ch:\n\t\t}\n\n\t\tif err := t.limiter.Wait(ctx); err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tt.trigger.QueueReconcile()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/watch/trigger_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage watch_test\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/watch\"\n)\n\ntype mockTrigger struct {\n\tcount atomic.Int64\n}\n\nfunc (t *mockTrigger) QueueReconcile() {\n\tt.count.Add(1)\n}\n\nfunc (t *mockTrigger) Get() int64 {\n\treturn t.count.Load()\n}\n\nfunc TestRateLimitedTrigger(t *testing.T) {\n\tmock := &mockTrigger{}\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tt.Cleanup(cancel)\n\n\ttrigger := watch.NewRateLimitedTrigger(ctx, mock, 10, 5)\n\n\tstart := time.Now()\n\n\tfor time.Since(start) < time.Second {\n\t\ttrigger.QueueReconcile()\n\t}\n\n\tassert.InDelta(t, int64(14), mock.Get(), 5)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/network/watch/watch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package watch provides netlink watchers via multicast groups.\npackage watch\n\n// Watcher interface allows to stop watching.\ntype Watcher interface {\n\tDone()\n}\n\n// Trigger is used by watcher to trigger reconcile loops.\ntype Trigger interface {\n\tQueueReconcile()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/perf/perf.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/prometheus/procfs\"\n\t\"go.uber.org/zap\"\n\n\tperfadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/perf\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n)\n\nconst updateInterval = time.Second * 30\n\n// StatsController manages v1alpha1.Stats which is the current snaphot of the machine CPU and Memory consumption.\ntype StatsController struct{}\n\n// Name implements controller.StatsController interface.\nfunc (ctrl *StatsController) Name() string {\n\treturn \"perf.StatsController\"\n}\n\n// Inputs implements controller.StatsController interface.\nfunc (ctrl *StatsController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.StatsController interface.\nfunc (ctrl *StatsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: perf.CPUType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t\t{\n\t\t\tType: perf.MemoryType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.StatsController interface.\nfunc (ctrl *StatsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tticker := time.NewTicker(updateInterval)\n\n\tdefer ticker.Stop()\n\n\tvar (\n\t\tfs  procfs.FS\n\t\terr error\n\t)\n\n\tfs, err = procfs.NewDefaultFS()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\tif err := ctrl.updateMemory(ctx, r, &fs); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := ctrl.updateCPU(ctx, r, &fs); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *StatsController) updateCPU(ctx context.Context, r controller.Runtime, fs *procfs.FS) error {\n\tcpu := perf.NewCPU()\n\n\tstat, err := fs.Stat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn safe.WriterModify(ctx, r, cpu, func(r *perf.CPU) error {\n\t\tperfadapter.CPU(r).Update(&stat)\n\n\t\treturn nil\n\t})\n}\n\nfunc (ctrl *StatsController) updateMemory(ctx context.Context, r controller.Runtime, fs *procfs.FS) error {\n\tmem := perf.NewMemory()\n\n\tinfo, err := fs.Meminfo()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn safe.WriterModify(ctx, r, mem, func(r *perf.Memory) error {\n\t\tperfadapter.Memory(r).Update(&info)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/perf/perf_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf_test\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/perf\"\n\tperfresource \"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n)\n\ntype PerfSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\t//nolint:containedctx\n\tctx       context.Context\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *PerfSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *PerfSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *PerfSuite) TestReconcile() {\n\tsuite.Require().NoError(suite.runtime.RegisterController(&perf.StatsController{}))\n\n\tsuite.startRuntime()\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tcpu, err := suite.state.Get(\n\t\t\t\t\tsuite.ctx,\n\t\t\t\t\tresource.NewMetadata(\n\t\t\t\t\t\tperfresource.NamespaceName,\n\t\t\t\t\t\tperfresource.CPUType,\n\t\t\t\t\t\tperfresource.CPUID,\n\t\t\t\t\t\tresource.VersionUndefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tmem, err := suite.state.Get(\n\t\t\t\t\tsuite.ctx,\n\t\t\t\t\tresource.NewMetadata(\n\t\t\t\t\t\tperfresource.NamespaceName,\n\t\t\t\t\t\tperfresource.MemoryType,\n\t\t\t\t\t\tperfresource.MemoryID,\n\t\t\t\t\t\tresource.VersionUndefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tcpuSpec := cpu.(*perfresource.CPU).TypedSpec()\n\t\t\t\tmemSpec := mem.(*perfresource.Memory).TypedSpec()\n\n\t\t\t\tif len(cpuSpec.CPU) == 0 || memSpec.MemTotal == 0 {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"cpu spec does not contain any CPU or Total memory is zero\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *PerfSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestPerfSuite(t *testing.T) {\n\tsuite.Run(t, new(PerfSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/api_service_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// APIServiceConfigController provides apid service configuration.\ntype APIServiceConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *APIServiceConfigController) Name() string {\n\treturn \"runtime.APIServiceConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *APIServiceConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MaintenanceServiceRequestType,\n\t\t\tID:        optional.Some(runtime.MaintenanceServiceRequestID),\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MaintenanceServiceConfigType,\n\t\t\tID:        optional.Some(runtime.MaintenanceServiceConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.APIType,\n\t\t\tID:        optional.Some(secrets.APIID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *APIServiceConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.APIServiceConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *APIServiceConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\trequest, err := safe.ReaderGetByID[*runtime.MaintenanceServiceRequest](ctx, r, runtime.MaintenanceServiceRequestID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get maintenance service request: %w\", err)\n\t\t}\n\n\t\tif request != nil && request.Metadata().Phase() == resource.PhaseTearingDown {\n\t\t\t// remove the finalizer\n\t\t\tif err = r.RemoveFinalizer(ctx, request.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer: %w\", err)\n\t\t\t}\n\n\t\t\trequest = nil\n\t\t}\n\n\t\t// immediately add a finalizer\n\t\tif request != nil {\n\t\t\tif err = r.AddFinalizer(ctx, request.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to add finalizer: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*runtime.MaintenanceServiceConfig](ctx, r, runtime.MaintenanceServiceConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get maintenance service config: %w\", err)\n\t\t}\n\n\t\tcert, err := safe.ReaderGetByID[*secrets.API](ctx, r, secrets.APIID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get API secret: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\t// decide whether to create maintenance mode API or not\n\t\tif request != nil {\n\t\t\tif cfg != nil {\n\t\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\t\truntime.NewAPIServiceConfig(),\n\t\t\t\t\tfunc(r *runtime.APIServiceConfig) error {\n\t\t\t\t\t\tr.TypedSpec().ListenAddress = cfg.TypedSpec().ListenAddress\n\t\t\t\t\t\tr.TypedSpec().NodeRoutingDisabled = true\n\t\t\t\t\t\tr.TypedSpec().ReadonlyRoleMode = true\n\t\t\t\t\t\tr.TypedSpec().SkipVerifyingClientCert = true\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create API service config: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if cert != nil && !cert.TypedSpec().SkipVerifyingClientCert {\n\t\t\tif err = safe.WriterModify(ctx, r,\n\t\t\t\truntime.NewAPIServiceConfig(),\n\t\t\t\tfunc(r *runtime.APIServiceConfig) error {\n\t\t\t\t\tr.TypedSpec().ListenAddress = fmt.Sprintf(\":%d\", constants.ApidPort)\n\t\t\t\t\tr.TypedSpec().NodeRoutingDisabled = false\n\t\t\t\t\tr.TypedSpec().ReadonlyRoleMode = false\n\t\t\t\t\tr.TypedSpec().SkipVerifyingClientCert = false\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create API service config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.APIServiceConfig](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup API service config outputs: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/api_service_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\ntype APIServiceConfigControllerSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestAPIServiceConfigControllerSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &APIServiceConfigControllerSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&runtime.APIServiceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *APIServiceConfigControllerSuite) TestMaintenanceMode() {\n\trequest := runtimeres.NewMaintenanceServiceRequest()\n\tsuite.Create(request)\n\n\tctest.AssertResource(suite, runtimeres.MaintenanceServiceRequestID,\n\t\tfunc(req *runtimeres.MaintenanceServiceRequest, asrt *assert.Assertions) {\n\t\t\tasrt.False(req.Metadata().Finalizers().Empty())\n\t\t},\n\t)\n\n\tcfg := runtimeres.NewMaintenanceServiceConfig()\n\tcfg.TypedSpec().ListenAddress = \":1\"\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, runtimeres.APIServiceConfigID,\n\t\tfunc(cfg *runtimeres.APIServiceConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\":1\", cfg.TypedSpec().ListenAddress)\n\t\t\tasrt.True(cfg.TypedSpec().NodeRoutingDisabled)\n\t\t\tasrt.True(cfg.TypedSpec().ReadonlyRoleMode)\n\t\t\tasrt.True(cfg.TypedSpec().SkipVerifyingClientCert)\n\t\t},\n\t)\n\n\t_, err := suite.State().Teardown(suite.Ctx(), request.Metadata())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertNoResource[*runtimeres.APIServiceConfig](suite, runtimeres.APIServiceConfigID)\n\n\tctest.AssertResource(suite, runtimeres.MaintenanceServiceRequestID,\n\t\tfunc(req *runtimeres.MaintenanceServiceRequest, asrt *assert.Assertions) {\n\t\t\tasrt.True(req.Metadata().Finalizers().Empty())\n\t\t},\n\t)\n\n\tsuite.Destroy(request)\n}\n\nfunc (suite *APIServiceConfigControllerSuite) TestRegularMode() {\n\tcert := secrets.NewAPI()\n\tsuite.Create(cert)\n\n\tctest.AssertResource(suite, runtimeres.APIServiceConfigID,\n\t\tfunc(cfg *runtimeres.APIServiceConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\":50000\", cfg.TypedSpec().ListenAddress)\n\t\t\tasrt.False(cfg.TypedSpec().NodeRoutingDisabled)\n\t\t\tasrt.False(cfg.TypedSpec().ReadonlyRoleMode)\n\t\t\tasrt.False(cfg.TypedSpec().SkipVerifyingClientCert)\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/booted_entry.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// BootedEntryController is a controller that updates the booted entry resource.\ntype BootedEntryController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *BootedEntryController) Name() string {\n\treturn \"runtime.BootedEntryController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *BootedEntryController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      runtimeres.SecurityStateType,\n\t\t\tID:        optional.Some(runtimeres.SecurityStateID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *BootedEntryController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtimeres.BootedEntryType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *BootedEntryController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// If we're booted in Container mode, short-circuit the controller.\n\tif ctrl.V1Alpha1Mode == machineruntime.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// wait for the SecurityState resource to be created\n\t\tst, err := safe.ReaderGetByID[*runtimeres.SecurityState](ctx, r, runtimeres.SecurityStateID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get machined state: %w\", err)\n\t\t}\n\n\t\t// If we're not booted with UKI, we don't need to create the BootedEntry resource.\n\t\t// This is because the BootedEntry resource is only relevant when UKI is used with systemd-boot.\n\t\tif !st.TypedSpec().BootedWithUKI {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Read `LoaderEntryOneShot`, `LoaderEntryRebootReason`, `LoaderEntrySelected` and `LoaderEntryBooted` resources\n\t\t// to determine the booted entry.\n\t\tloaderEntryOneShot, err := sdboot.ReadVariable(sdboot.LoaderEntryOneShotName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read LoaderEntryOneShot variable: %w\", err)\n\t\t}\n\n\t\tloaderEntryRebootReason, err := sdboot.ReadVariable(sdboot.LoaderEntryRebootReasonName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read LoaderEntryRebootReason variable: %w\", err)\n\t\t}\n\n\t\tloaderEntrySelected, err := sdboot.ReadVariable(sdboot.LoaderEntrySelectedName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read LoaderEntrySelected variable: %w\", err)\n\t\t}\n\n\t\tloaderEntryDefault, err := sdboot.ReadVariable(sdboot.LoaderEntryDefaultName)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read LoaderEntryDefault variable: %w\", err)\n\t\t}\n\n\t\tvar bootedEntry string\n\n\t\tswitch {\n\t\t// in this case `LoaderEntryOneShot` is set to \"kexec reboot\" and `LoaderEntryRebootReason` is set to \"reboot\"\n\t\t// by the kernel, the system was installed/upgraded via kexec and `LoaderEntryDefault` is the correct booted entry\n\t\t// Ref: https://cateee.net/lkddb/web-lkddb/EFI_BOOTLOADER_CONTROL.html\n\t\tcase loaderEntryRebootReason == \"reboot\" && loaderEntryOneShot == \"kexec reboot\":\n\t\t\tif loaderEntryDefault == \"\" {\n\t\t\t\treturn fmt.Errorf(\"LoaderEntryDefault variable is empty, cannot determine booted entry\")\n\t\t\t}\n\n\t\t\tbootedEntry = loaderEntryDefault\n\t\t// this case is when we have a `LoaderEntryDefault` set by the installer and during a reboot the user selected\n\t\t// a different entry, so we set the `LoaderEntrySelected` as the booted entry\n\t\t// we can use this information later to decide which UKI's to clean up\n\t\tcase loaderEntryOneShot == \"\" && loaderEntryDefault != \"\" && loaderEntrySelected != \"\":\n\t\t\tbootedEntry = loaderEntrySelected\n\t\t// this case is when we have a `LoaderEntryDefault` set by the installer and the system was rebooted/upgraded\n\t\t// with kexec, so `sd-boot` is not involved and nothing sets the `LoaderEntrySelected`\n\t\tcase loaderEntryOneShot == \"\" && loaderEntryDefault != \"\" && loaderEntrySelected == \"\":\n\t\t\tbootedEntry = loaderEntryDefault\n\t\t// this is the case when we just booted with UKI/kernel+initrd and bootloader is not installed\n\t\t// this case is only currently applicable when locally developing Talos\n\t\tcase loaderEntryOneShot == \"\" && loaderEntryDefault == \"\" && loaderEntrySelected != \"\":\n\t\t\tbootedEntry = loaderEntrySelected\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, runtimeres.NewBootedEntrySpec(), func(entry *runtimeres.BootedEntry) error {\n\t\t\tentry.TypedSpec().BootedEntry = bootedEntry\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update BootedEntry resource: %w\", err)\n\t\t}\n\n\t\t// terminating the controller here, as we need to only populate the BootedEntry resource once\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/common_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n)\n\nconst (\n\tfsFileMax        = \"fs.file-max\"\n\tprocSysfsFileMax = \"proc.sys.fs.file-max\"\n\tsysfsFileMax     = \"sys.fs.file-max\"\n)\n\ntype RuntimeSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *RuntimeSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *RuntimeSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *RuntimeSuite) assertResource(md resource.Metadata, compare func(res resource.Resource) bool) func() error {\n\treturn func() error {\n\t\tr, err := suite.state.Get(suite.ctx, md)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !compare(r) {\n\t\t\treturn errors.New(\"resource is not equal to the expected one\")\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\nfunc (suite *RuntimeSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/devices_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/v1alpha1\"\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// DevicesStatusController loads extensions.yaml and updates DevicesStatus resources.\ntype DevicesStatusController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DevicesStatusController) Name() string {\n\treturn \"runtime.DevicesStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DevicesStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DevicesStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.DevicesStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *DevicesStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// in container mode, devices are always ready\n\tif ctrl.V1Alpha1Mode != machineruntime.ModeContainer {\n\t\tif err := v1alpha1.WaitForServiceHealthy(ctx, r, \"udevd\", nil); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, runtime.NewDevicesStatus(runtime.NamespaceName, runtime.DevicesID), func(status *runtime.DevicesStatus) error {\n\t\t\tstatus.TypedSpec().Ready = true\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/diagnostics.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/diagnostics\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// DiagnosticsController analyzes state of Talos Linux system and provides warnings on common problems.\ntype DiagnosticsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DiagnosticsController) Name() string {\n\treturn \"runtime.DiagnosticsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DiagnosticsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DiagnosticsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.DiagnosticType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nconst (\n\tdiagnosticsCheckTimeout   = time.Minute\n\tdiagnostricsCheckInterval = time.Minute\n)\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DiagnosticsController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// firstDiscovery is used to track when a warning was first discovered.\n\tfirstDiscovered := map[string]time.Time{}\n\n\tticker := time.NewTicker(diagnostricsCheckInterval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tfor _, checkDescription := range diagnostics.Checks() {\n\t\t\tif err := func() error {\n\t\t\t\tcheckCtx, checkCtxCancel := context.WithTimeout(ctx, diagnosticsCheckTimeout)\n\t\t\t\tdefer checkCtxCancel()\n\n\t\t\t\twarning, err := checkDescription.Check(checkCtx, r, logger)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Debug(\"diagnostic check failed\", zap.String(\"check\", checkDescription.ID), zap.Error(err))\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif warning == nil {\n\t\t\t\t\tdelete(firstDiscovered, checkDescription.ID)\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tfirstDiscoveredTime, ok := firstDiscovered[checkDescription.ID]\n\t\t\t\tif !ok {\n\t\t\t\t\tfirstDiscoveredTime = time.Now()\n\t\t\t\t\tfirstDiscovered[checkDescription.ID] = firstDiscoveredTime\n\t\t\t\t}\n\n\t\t\t\tif time.Since(firstDiscoveredTime) < checkDescription.Hysteresis {\n\t\t\t\t\t// don't publish it yet\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn safe.WriterModify(ctx, r, runtime.NewDiagnostic(runtime.NamespaceName, checkDescription.ID), func(res *runtime.Diagnostic) error {\n\t\t\t\t\t*res.TypedSpec() = *warning\n\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t}(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*runtime.Diagnostic](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/diagnostics_logger.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// DiagnosticsLoggerController logs warnings generated by DiagnosticsController.\ntype DiagnosticsLoggerController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DiagnosticsLoggerController) Name() string {\n\treturn \"runtime.DiagnosticsLoggerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DiagnosticsLoggerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.DiagnosticType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DiagnosticsLoggerController) Outputs() []controller.Output {\n\treturn nil\n}\n\nconst diagnosticsReportInterval = 5 * time.Minute\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DiagnosticsLoggerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\treportedWarnings := map[string]struct{}{}\n\n\tticker := time.NewTicker(diagnosticsReportInterval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\twarnings, err := safe.ReaderListAll[*runtime.Diagnostic](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error listing diagnostics: %w\", err)\n\t\t\t}\n\n\t\t\tseenWarnings := map[string]struct{}{}\n\n\t\t\tfor warning := range warnings.All() {\n\t\t\t\tseenWarnings[warning.Metadata().ID()] = struct{}{}\n\n\t\t\t\tif _, reported := reportedWarnings[warning.Metadata().ID()]; !reported {\n\t\t\t\t\tlogger.Warn(\"new diagnostic\",\n\t\t\t\t\t\tzap.String(\"id\", warning.Metadata().ID()),\n\t\t\t\t\t\tzap.String(\"message\", warning.TypedSpec().Message),\n\t\t\t\t\t\tzap.Strings(\"details\", warning.TypedSpec().Details),\n\t\t\t\t\t\tzap.String(\"url\", warning.TypedSpec().DocumentationURL(warning.Metadata().ID())),\n\t\t\t\t\t)\n\n\t\t\t\t\treportedWarnings[warning.Metadata().ID()] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor id := range reportedWarnings {\n\t\t\t\tif _, seen := seenWarnings[id]; !seen {\n\t\t\t\t\tlogger.Info(\"diagnostic resolved\", zap.String(\"id\", id))\n\n\t\t\t\t\tdelete(reportedWarnings, id)\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-ticker.C:\n\t\t\tif len(reportedWarnings) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\twarnings, err := safe.ReaderListAll[*runtime.Diagnostic](ctx, r)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error listing diagnostics: %w\", err)\n\t\t\t}\n\n\t\t\tfor warning := range warnings.All() {\n\t\t\t\tlogger.Warn(\"diagnostic still active\",\n\t\t\t\t\tzap.String(\"id\", warning.Metadata().ID()),\n\t\t\t\t\tzap.String(\"message\", warning.TypedSpec().Message),\n\t\t\t\t\tzap.Strings(\"details\", warning.TypedSpec().Details),\n\t\t\t\t\tzap.String(\"url\", warning.TypedSpec().DocumentationURL(warning.Metadata().ID())),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/drop_upgrade_fallback.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// MetaProvider wraps acquiring meta.\ntype MetaProvider interface {\n\tMeta() machineruntime.Meta\n}\n\n// DropUpgradeFallbackController removes upgrade fallback key once machine reaches ready & running.\ntype DropUpgradeFallbackController struct {\n\tMetaProvider MetaProvider\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *DropUpgradeFallbackController) Name() string {\n\treturn \"runtime.DropUpgradeFallbackController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *DropUpgradeFallbackController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MachineStatusType,\n\t\t\tID:        optional.Some(runtime.MachineStatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *DropUpgradeFallbackController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *DropUpgradeFallbackController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmachineStatus, err := safe.ReaderGetByID[*runtime.MachineStatus](ctx, r, runtime.MachineStatusID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine status: %w\", err)\n\t\t}\n\n\t\tif !(machineStatus.TypedSpec().Stage == runtime.MachineStageRunning && machineStatus.TypedSpec().Status.Ready) {\n\t\t\tcontinue\n\t\t}\n\n\t\tok, err := ctrl.MetaProvider.Meta().DeleteTag(ctx, meta.Upgrade)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ok {\n\t\t\tlogger.Info(\"removing fallback entry\")\n\n\t\t\tif err = ctrl.MetaProvider.Meta().Flush(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// terminating the controller here, as removing fallback is required only once on boot after upgrade\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/drop_upgrade_fallback_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta\"\n\tmetaconsts \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype DropUpgradeFallbackControllerSuite struct {\n\tctest.DefaultSuite\n\n\tmeta *meta.Meta\n}\n\ntype metaProvider struct {\n\tmeta *meta.Meta\n}\n\nfunc (m metaProvider) Meta() machineruntime.Meta {\n\treturn m.meta\n}\n\nfunc TestUpgradeFallbackControllerSuite(t *testing.T) {\n\ttmpDir := t.TempDir()\n\n\tpath := filepath.Join(tmpDir, \"meta\")\n\n\tf, err := os.Create(path)\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Truncate(1024*1024))\n\trequire.NoError(t, f.Close())\n\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tm, err := meta.New(t.Context(), st, meta.WithFixedPath(path))\n\trequire.NoError(t, err)\n\n\tsuite.Run(t, &DropUpgradeFallbackControllerSuite{\n\t\tmeta: m,\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&runtime.DropUpgradeFallbackController{\n\t\t\t\t\tMetaProvider: metaProvider{meta: m},\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *DropUpgradeFallbackControllerSuite) TestDropUpgradeFallback() {\n\t_, err := suite.meta.SetTag(suite.Ctx(), metaconsts.Upgrade, \"A\")\n\tsuite.Require().NoError(err)\n\n\tmachineStatus := runtimeres.NewMachineStatus()\n\tmachineStatus.TypedSpec().Stage = runtimeres.MachineStageBooting\n\tmachineStatus.TypedSpec().Status.Ready = false\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineStatus))\n\n\ttime.Sleep(time.Second)\n\n\t// controller should not remove the tag\n\tval, ok := suite.meta.ReadTag(metaconsts.Upgrade)\n\tsuite.Require().True(ok)\n\tsuite.Require().Equal(\"A\", val)\n\n\t// update machine status to ready\n\tmachineStatus.TypedSpec().Status.Ready = true\n\tmachineStatus.TypedSpec().Stage = runtimeres.MachineStageRunning\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), machineStatus))\n\n\tsuite.AssertWithin(time.Second, 10*time.Millisecond, func() error {\n\t\t_, ok = suite.meta.ReadTag(metaconsts.Upgrade)\n\t\tif ok {\n\t\t\treturn retry.ExpectedErrorf(\"tag is still present\")\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// EnvironmentController watches v1alpha1.Config and sets environment variables accordingly.\ntype EnvironmentController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EnvironmentController) Name() string {\n\treturn \"runtime.EnvironmentController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EnvironmentController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EnvironmentController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.EnvironmentType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EnvironmentController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config().Environment() != nil {\n\t\t\tfor key, value := range cfg.Config().Environment().Variables() {\n\t\t\t\tif err := os.Setenv(key, value); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error setting env var: \\\"%s=%s\\\": %w\", key, value, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\titem := runtime.NewEnvironment(\"machined\")\n\n\t\tif err = safe.WriterModify(ctx, r, item, func(res *runtime.Environment) error {\n\t\t\tenv := os.Environ()\n\n\t\t\tslices.Sort(env)\n\n\t\t\tres.TypedSpec().Variables = env\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.Environment](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/environment_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\truntimecfg \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype EnvironmentSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestEnvironmentSuite(t *testing.T) {\n\tsuite.Run(t, new(EnvironmentSuite))\n}\n\nfunc (suite *EnvironmentSuite) TestEnvironmentNone() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.EnvironmentController{}))\n\n\trtestutils.AssertResource[*runtime.Environment](suite.Ctx(), suite.T(), suite.State(), \"machined\",\n\t\tfunc(r *runtime.Environment, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(r.TypedSpec().Variables)\n\t\t})\n}\n\nfunc (suite *EnvironmentSuite) TestEnvironmentMachineConfig() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.EnvironmentController{}))\n\n\tcfg, err := container.New(&runtimecfg.EnvironmentV1Alpha1{\n\t\tEnvironmentVariables: map[string]string{\n\t\t\t\"TEST\": \"value\",\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources[*runtime.Environment](suite.Ctx(), suite.T(), suite.State(), []resource.ID{\"machined\"},\n\t\tfunc(cfg *runtime.Environment, asrt *assert.Assertions) {\n\t\t\tasrt.Contains(\n\t\t\t\tcfg.TypedSpec().Variables,\n\t\t\t\t\"TEST=value\",\n\t\t\t)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/events_sink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/rs/xid\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/siderolink/api/events\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/protobuf/types/known/anypb\"\n\n\tnetworkutils \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/utils\"\n\tmachinedruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// EventsSinkController watches events and forwards them to the events sink server\n// if it's configured.\ntype EventsSinkController struct {\n\tV1Alpha1Events machinedruntime.Watcher\n\tDrainer        *machinedruntime.Drainer\n\n\tdrainSub *machinedruntime.DrainSubscription\n\teventID  xid.ID\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EventsSinkController) Name() string {\n\treturn \"v1alpha1.EventsSinkController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EventsSinkController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EventsSinkController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *EventsSinkController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tif ctrl.drainSub == nil {\n\t\tctrl.drainSub = ctrl.Drainer.Subscribe()\n\t}\n\n\tdefer func() {\n\t\tif ctrl.drainSub != nil {\n\t\t\tctrl.drainSub.Cancel()\n\t\t}\n\t}()\n\n\tif err := networkutils.WaitForNetworkReady(ctx, r,\n\t\tfunc(status *network.StatusSpec) bool {\n\t\t\treturn status.AddressReady\n\t\t},\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: runtime.NamespaceName,\n\t\t\t\tType:      runtime.EventSinkConfigType,\n\t\t\t\tID:        optional.Some(runtime.EventSinkConfigID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for network: %w\", err)\n\t}\n\n\tvar (\n\t\tconn                    *grpc.ClientConn\n\t\tclient                  events.EventSinkServiceClient\n\t\twatchCh, consumeWatchCh chan machinedruntime.EventInfo\n\t\tbacklog                 int\n\t\tdraining                bool\n\t)\n\n\tdefer func() {\n\t\tif conn != nil {\n\t\t\tconn.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ctrl.drainSub.EventCh():\n\t\t\t// drain started, return immediately if there's no backlog\n\t\t\tdraining = true\n\n\t\t\tif backlog == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase event := <-consumeWatchCh:\n\t\t\t// if consumeWatchCh is not nil, client connection was established\n\t\t\tbacklog = event.Backlog\n\n\t\t\tdata, err := anypb.New(event.Payload)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treq := &events.EventRequest{\n\t\t\t\tId:      event.ID.String(),\n\t\t\t\tData:    data,\n\t\t\t\tActorId: event.ActorID,\n\t\t\t}\n\n\t\t\t_, err = client.Publish(ctx, req)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error publishing event: %w\", err)\n\t\t\t}\n\n\t\t\t// adjust last consumed event\n\t\t\tctrl.eventID = event.ID\n\n\t\t\t// if draining and backlog is 0, return immediately\n\t\t\tif draining && backlog == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\tcase <-r.EventCh():\n\t\t\t// configuration changed, re-establish connection\n\t\t\tcfg, err := safe.ReaderGetByID[*runtime.EventSinkConfig](ctx, r, runtime.EventSinkConfigID)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting event sink config: %w\", err)\n\t\t\t}\n\n\t\t\tif conn != nil {\n\t\t\t\tlogger.Debug(\"closing connection to event sink\")\n\n\t\t\t\tconn.Close() //nolint:errcheck\n\t\t\t\tconn = nil\n\t\t\t\tclient = nil\n\t\t\t\tconsumeWatchCh = nil // stop consuming events\n\t\t\t\tbacklog = 0\n\t\t\t}\n\n\t\t\tif cfg == nil {\n\t\t\t\t// no config, no event streaming\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// establish connection\n\t\t\tlogger.Debug(\"establishing connection to event sink\", zap.String(\"endpoint\", cfg.TypedSpec().Endpoint))\n\n\t\t\tconn, err = grpc.NewClient(\n\t\t\t\tcfg.TypedSpec().Endpoint,\n\t\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t\t\tgrpc.WithSharedWriteBuffer(true),\n\t\t\t\tgrpc.WithContextDialer(dialer.DynamicProxyDialerWithTLSConfig(httpdefaults.RootCAsTLSConfig)),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error establishing connection to event sink: %w\", err)\n\t\t\t}\n\n\t\t\tclient = events.NewEventSinkServiceClient(conn)\n\n\t\t\t// start watching events if we haven't already done so\n\t\t\t//\n\t\t\t// watch is only established with the first live connection to make sure we don't miss any events\n\t\t\tif watchCh == nil {\n\t\t\t\twatchCh = make(chan machinedruntime.EventInfo)\n\n\t\t\t\tvar opts []machinedruntime.WatchOptionFunc\n\n\t\t\t\tif ctrl.eventID.IsNil() {\n\t\t\t\t\topts = append(opts, machinedruntime.WithTailEvents(-1))\n\t\t\t\t} else {\n\t\t\t\t\topts = append(opts, machinedruntime.WithTailID(ctrl.eventID))\n\t\t\t\t}\n\n\t\t\t\t// Watch returns immediately, setting up a goroutine which will copy events to `watchCh`\n\t\t\t\tif err = ctrl.V1Alpha1Events.Watch(func(eventCh <-chan machinedruntime.EventInfo) {\n\t\t\t\t\tfor {\n\t\t\t\t\t\tselect {\n\t\t\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\tcase event := <-eventCh:\n\t\t\t\t\t\t\tif !channel.SendWithContext(ctx, watchCh, event) {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, opts...); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconsumeWatchCh = watchCh\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/events_sink_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// EventsSinkConfigController generates configuration for kmsg log delivery.\ntype EventsSinkConfigController struct {\n\tCmdline      *procfs.Cmdline\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EventsSinkConfigController) Name() string {\n\treturn \"runtime.EventsSinkConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EventsSinkConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EventsSinkConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.EventSinkConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EventsSinkConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) (err error) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar endpoint string\n\n\t\tif ctrl.Cmdline != nil && ctrl.V1Alpha1Mode != v1alpha1runtime.ModeContainer {\n\t\t\tif val := ctrl.Cmdline.Get(constants.KernelParamEventsSink).First(); val != nil {\n\t\t\t\tendpoint = *val\n\t\t\t}\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tif cfg != nil && cfg.Config().Runtime().EventsEndpoint() != nil {\n\t\t\tendpoint = *cfg.Config().Runtime().EventsEndpoint()\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif endpoint != \"\" {\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewEventSinkConfig(), func(cfg *runtime.EventSinkConfig) error {\n\t\t\t\tcfg.TypedSpec().Endpoint = endpoint\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating kmsg log config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.EventSinkConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/events_sink_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\truntimecfg \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype EventsSinkConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestEventsSinkConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(EventsSinkConfigSuite))\n}\n\nfunc (suite *EventsSinkConfigSuite) TestEventSinkConfigNone() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.EventsSinkConfigController{}))\n\n\trtestutils.AssertNoResource[*runtime.EventSinkConfig](suite.Ctx(), suite.T(), suite.State(), runtime.EventSinkConfigID)\n}\n\nfunc (suite *EventsSinkConfigSuite) TestEventSinkConfigMachineConfig() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.EventsSinkConfigController{}))\n\n\teventSinkConfig := &runtimecfg.EventSinkV1Alpha1{\n\t\tEndpoint: \"10.0.0.2:4444\",\n\t}\n\n\tcfg, err := container.New(eventSinkConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources[*runtime.EventSinkConfig](suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.EventSinkConfigID},\n\t\tfunc(cfg *runtime.EventSinkConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t\"10.0.0.2:4444\",\n\t\t\t\tcfg.TypedSpec().Endpoint,\n\t\t\t)\n\t\t})\n}\n\nfunc (suite *EventsSinkConfigSuite) TestEventSinkConfigCmdline() {\n\tcmdline := procfs.NewCmdline(\"\")\n\tcmdline.Append(constants.KernelParamEventsSink, \"10.0.0.1:3333\")\n\n\tcfg, err := container.New()\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.EventsSinkConfigController{\n\t\tCmdline: cmdline,\n\t}))\n\n\trtestutils.AssertResources[*runtime.EventSinkConfig](suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.EventSinkConfigID},\n\t\tfunc(cfg *runtime.EventSinkConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t\"10.0.0.1:3333\",\n\t\t\t\tcfg.TypedSpec().Endpoint,\n\t\t\t)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/events_sink_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\teventsapi \"github.com/siderolabs/siderolink/api/events\"\n\t\"github.com/siderolabs/siderolink/pkg/events\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc\"\n\n\tcontrollerruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\ttalosruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype handler struct {\n\teventsMu sync.Mutex\n\tevents   []events.Event\n}\n\n// HandleEvent implements events.Adapter.\nfunc (s *handler) HandleEvent(ctx context.Context, e events.Event) error {\n\ts.eventsMu.Lock()\n\tdefer s.eventsMu.Unlock()\n\n\ts.events = append(s.events, e)\n\n\treturn nil\n}\n\ntype EventsSinkSuite struct {\n\tsuite.Suite\n\n\tevents  *v1alpha1.Events\n\tstate   state.State\n\thandler *handler\n\tserver  *grpc.Server\n\tsink    *events.Sink\n\n\truntime *runtime.Runtime\n\tdrainer *talosruntime.Drainer\n\twg      sync.WaitGroup\n\teg      errgroup.Group\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *EventsSinkSuite) SetupTest() {\n\tsuite.events = v1alpha1.NewEvents(1000, 10)\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\tsuite.handler = &handler{}\n\tsuite.drainer = talosruntime.NewDrainer()\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&controllerruntime.EventsSinkController{\n\t\t\t\tV1Alpha1Events: suite.events,\n\t\t\t\tDrainer:        suite.drainer,\n\t\t\t},\n\t\t),\n\t)\n\n\tstatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tstatus.TypedSpec().AddressReady = true\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, status))\n\n\tsuite.startRuntime()\n}\n\nfunc (suite *EventsSinkSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *EventsSinkSuite) startServer(ctx context.Context) string {\n\tsuite.sink = events.NewSink(\n\t\tsuite.handler,\n\t\t[]proto.Message{\n\t\t\t&machine.AddressEvent{},\n\t\t\t&machine.PhaseEvent{},\n\t\t})\n\n\tlis, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", \"localhost:0\")\n\tsuite.Require().NoError(err)\n\n\tsuite.server = grpc.NewServer()\n\teventsapi.RegisterEventSinkServiceServer(suite.server, suite.sink)\n\n\tsuite.eg.Go(\n\t\tfunc() error {\n\t\t\t<-ctx.Done()\n\n\t\t\tsuite.server.Stop()\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\tsuite.eg.Go(\n\t\tfunc() error {\n\t\t\treturn suite.server.Serve(lis)\n\t\t},\n\t)\n\n\treturn lis.Addr().String()\n}\n\nfunc (suite *EventsSinkSuite) TestPublish() {\n\tctx, cancel := context.WithCancel(suite.ctx)\n\tdefer cancel()\n\n\tsuite.events.Publish(\n\t\tctx,\n\t\t&machine.AddressEvent{\n\t\t\tHostname: \"localhost\",\n\t\t},\n\t)\n\n\tsuite.events.Publish(\n\t\tctx,\n\t\t&machine.PhaseEvent{\n\t\t\tPhase:  \"test\",\n\t\t\tAction: machine.PhaseEvent_START,\n\t\t},\n\t)\n\n\tsuite.Require().Equal(0, len(suite.handler.events))\n\n\tendpoint := suite.startServer(ctx)\n\tconfig := runtimeres.NewEventSinkConfig()\n\tconfig.TypedSpec().Endpoint = endpoint\n\tsuite.Require().NoError(suite.state.Create(ctx, config))\n\n\tsuite.Require().NoError(retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(\n\t\tfunc() error {\n\t\t\tsuite.handler.eventsMu.Lock()\n\t\t\tdefer suite.handler.eventsMu.Unlock()\n\n\t\t\tif len(suite.handler.events) != 2 {\n\t\t\t\treturn retry.ExpectedErrorf(\"expected 2 events, got %d\", len(suite.handler.events))\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\tsuite.events.Publish(\n\t\tctx,\n\t\t&machine.PhaseEvent{\n\t\t\tPhase:  \"test\",\n\t\t\tAction: machine.PhaseEvent_STOP,\n\t\t},\n\t)\n\n\tsuite.Require().NoError(retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(\n\t\tfunc() error {\n\t\t\tsuite.handler.eventsMu.Lock()\n\t\t\tdefer suite.handler.eventsMu.Unlock()\n\n\t\t\tif len(suite.handler.events) != 3 {\n\t\t\t\treturn retry.ExpectedErrorf(\"expected 3 events, got %d\", len(suite.handler.events))\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n}\n\nfunc (suite *EventsSinkSuite) TestDrain() {\n\tctx, cancel := context.WithCancel(suite.ctx)\n\tdefer cancel()\n\n\tfor range 10 {\n\t\tsuite.events.Publish(\n\t\t\tctx,\n\t\t\t&machine.PhaseEvent{\n\t\t\t\tPhase:  \"test\",\n\t\t\t\tAction: machine.PhaseEvent_START,\n\t\t\t},\n\t\t)\n\t\tsuite.events.Publish(\n\t\t\tctx,\n\t\t\t&machine.PhaseEvent{\n\t\t\t\tPhase:  \"test\",\n\t\t\t\tAction: machine.PhaseEvent_STOP,\n\t\t\t},\n\t\t)\n\t}\n\n\tsuite.Require().Equal(0, len(suite.handler.events))\n\n\t// first, publish wrong endpoint\n\tbadLis, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", \"localhost:0\")\n\tsuite.Require().NoError(err)\n\n\tbadEndpoint := badLis.Addr().String()\n\tsuite.Require().NoError(badLis.Close())\n\n\tconfig := runtimeres.NewEventSinkConfig()\n\tconfig.TypedSpec().Endpoint = badEndpoint\n\tsuite.Require().NoError(suite.state.Create(ctx, config))\n\n\tsuite.T().Logf(\"%s starting bad server at %s\", time.Now().Format(time.RFC3339), badEndpoint)\n\n\ttime.Sleep(time.Second * 1)\n\n\tdrainCtx, drainCtxCancel := context.WithTimeout(ctx, time.Second*5)\n\tdefer drainCtxCancel()\n\n\tvar eg errgroup.Group\n\n\teg.Go(\n\t\tfunc() error {\n\t\t\tsuite.T().Logf(\"%s starting drain\", time.Now().Format(time.RFC3339))\n\n\t\t\treturn suite.drainer.Drain(drainCtx)\n\t\t},\n\t)\n\n\teg.Go(\n\t\tfunc() error {\n\t\t\t// start real server with delay\n\t\t\ttime.Sleep(300 * time.Millisecond)\n\n\t\t\tendpoint := suite.startServer(ctx)\n\n\t\t\tsuite.T().Logf(\"%s starting real server at %s\", time.Now().Format(time.RFC3339), endpoint)\n\n\t\t\t_, updateErr := safe.StateUpdateWithConflicts(\n\t\t\t\tctx, suite.state, runtimeres.NewEventSinkConfig().Metadata(),\n\t\t\t\tfunc(cfg *runtimeres.EventSinkConfig) error {\n\t\t\t\t\tcfg.TypedSpec().Endpoint = endpoint\n\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\n\t\t\treturn updateErr\n\t\t},\n\t)\n\n\tsuite.Require().NoError(retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(\n\t\tfunc() error {\n\t\t\tsuite.handler.eventsMu.Lock()\n\t\t\tdefer suite.handler.eventsMu.Unlock()\n\n\t\t\tif len(suite.handler.events) != 20 {\n\t\t\t\treturn retry.ExpectedErrorf(\"expected 20 events, got %d\", len(suite.handler.events))\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\tsuite.Require().NoError(eg.Wait())\n}\n\nfunc (suite *EventsSinkSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.Require().NoError(suite.eg.Wait())\n\n\tsuite.wg.Wait()\n}\n\nfunc TestEventsSinkSuite(t *testing.T) {\n\tsuite.Run(t, new(EventsSinkSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\textservices \"github.com/siderolabs/talos/pkg/machinery/extensions/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ServiceManager is the interface to the v1alpha1 services subsystems.\ntype ServiceManager interface {\n\tIsRunning(id string) (system.Service, bool, error)\n\tLoad(services ...system.Service) []string\n\tStop(ctx context.Context, serviceIDs ...string) (err error)\n\tStart(serviceIDs ...string) error\n}\n\n// ExtensionServiceController creates extension services based on the extension service configuration found in the rootfs.\ntype ExtensionServiceController struct {\n\tV1Alpha1Services ServiceManager\n\tConfigPath       string\n\n\tconfigStatusCache map[string]string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceController) Name() string {\n\treturn \"runtime.ExtensionServiceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.ExtensionServiceConfigStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ExtensionServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\t// wait for controller runtime to be ready\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\t// extensions loading only needs to run once, as services are static\n\tserviceFiles, err := os.ReadDir(ctrl.ConfigPath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t// directory not present, skip completely\n\t\t\tlogger.Debug(\"extension service directory is not found\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\t// load initial state of configStatuses\n\tif ctrl.configStatusCache == nil {\n\t\tconfigStatuses, err := safe.ReaderListAll[*runtime.ExtensionServiceConfigStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing extension services config: %w\", err)\n\t\t}\n\n\t\tctrl.configStatusCache = make(map[string]string, configStatuses.Len())\n\n\t\tfor res := range configStatuses.All() {\n\t\t\tctrl.configStatusCache[res.Metadata().ID()] = res.TypedSpec().SpecVersion\n\t\t}\n\t}\n\n\t// load services from definitions into the service runner framework\n\textServices := map[string]struct{}{}\n\n\tfor _, serviceFile := range serviceFiles {\n\t\tif filepath.Ext(serviceFile.Name()) != \".yaml\" {\n\t\t\tlogger.Debug(\"skipping config file\", zap.String(\"filename\", serviceFile.Name()))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tspec, err := ctrl.loadSpec(filepath.Join(ctrl.ConfigPath, serviceFile.Name()))\n\t\tif err != nil {\n\t\t\tlogger.Error(\"error loading extension service spec\", zap.String(\"filename\", serviceFile.Name()), zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = spec.Validate(); err != nil {\n\t\t\tlogger.Error(\"error validating extension service spec\", zap.String(\"filename\", serviceFile.Name()), zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, exists := extServices[spec.Name]; exists {\n\t\t\tlogger.Error(\"duplicate service spec\", zap.String(\"filename\", serviceFile.Name()), zap.String(\"name\", spec.Name))\n\n\t\t\tcontinue\n\t\t}\n\n\t\textServices[spec.Name] = struct{}{}\n\n\t\tsvc := &services.Extension{\n\t\t\tSpec: spec,\n\t\t}\n\n\t\tctrl.V1Alpha1Services.Load(svc)\n\n\t\tif err = ctrl.V1Alpha1Services.Start(svc.ID(nil)); err != nil {\n\t\t\treturn fmt.Errorf(\"error starting %q service: %w\", spec.Name, err)\n\t\t}\n\t}\n\n\t// watch for changes in the configStatuses\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tconfigStatuses, err := safe.ReaderListAll[*runtime.ExtensionServiceConfigStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing extension services config: %w\", err)\n\t\t}\n\n\t\tconfigStatusesPresent := map[string]struct{}{}\n\n\t\tfor res := range configStatuses.All() {\n\t\t\tconfigStatusesPresent[res.Metadata().ID()] = struct{}{}\n\n\t\t\tif ctrl.configStatusCache[res.Metadata().ID()] == res.TypedSpec().SpecVersion {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = ctrl.handleRestart(ctx, logger, \"ext-\"+res.Metadata().ID(), res.TypedSpec().SpecVersion); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tctrl.configStatusCache[res.Metadata().ID()] = res.TypedSpec().SpecVersion\n\t\t}\n\n\t\t// cleanup configStatusesCache\n\t\tfor id := range ctrl.configStatusCache {\n\t\t\tif _, ok := configStatusesPresent[id]; !ok {\n\t\t\t\tif err = ctrl.handleRestart(ctx, logger, \"ext-\"+id, \"nan\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tdelete(ctrl.configStatusCache, id)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ctrl *ExtensionServiceController) loadSpec(path string) (extservices.Spec, error) {\n\tvar spec extservices.Spec\n\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn spec, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tif err = yaml.NewDecoder(f).Decode(&spec); err != nil {\n\t\treturn spec, fmt.Errorf(\"error unmarshalling extension service config: %w\", err)\n\t}\n\n\treturn spec, nil\n}\n\nfunc (ctrl *ExtensionServiceController) handleRestart(ctx context.Context, logger *zap.Logger, svcName, specVersion string) error {\n\t_, running, err := ctrl.V1Alpha1Services.IsRunning(svcName)\n\tif err != nil {\n\t\treturn nil //nolint:nilerr // IsRunning returns an error only if the service is not found, so ignore it\n\t}\n\n\t// this means it's a new config and the service runner is already waiting for the config to start the service\n\t// we don't need restart it again since it will be started automatically\n\tif running && specVersion == \"1\" {\n\t\treturn nil\n\t}\n\n\tlogger.Warn(\"extension service config changed, restarting\", zap.String(\"service\", svcName))\n\n\tif running {\n\t\tif err = ctrl.V1Alpha1Services.Stop(ctx, svcName); err != nil {\n\t\t\treturn fmt.Errorf(\"error stopping extension service %s: %w\", svcName, err)\n\t\t}\n\t}\n\n\tif err = ctrl.V1Alpha1Services.Start(svcName); err != nil {\n\t\treturn fmt.Errorf(\"error starting extension service %s: %w\", svcName, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\textconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ExtensionServiceConfigController watches v1alpha1.Config, creates/updates/deletes extension services config.\ntype ExtensionServiceConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigController) Name() string {\n\treturn \"runtime.ExtensionServiceConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.ExtensionServiceConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ExtensionServiceConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config() != nil {\n\t\t\tfor _, extConfig := range cfg.Config().ExtensionServiceConfigs() {\n\t\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewExtensionServiceConfigSpec(runtime.NamespaceName, extConfig.Name()), func(spec *runtime.ExtensionServiceConfig) error {\n\t\t\t\t\tspec.TypedSpec().Files = xslices.Map(extConfig.ConfigFiles(), func(c extconfig.ExtensionServiceConfigFile) runtime.ExtensionServiceConfigFile {\n\t\t\t\t\t\treturn runtime.ExtensionServiceConfigFile{\n\t\t\t\t\t\t\tContent:   c.Content(),\n\t\t\t\t\t\t\tMountPath: c.MountPath(),\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\n\t\t\t\t\tspec.TypedSpec().Environment = extConfig.Environment()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.ExtensionServiceConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service_config_files.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ExtensionServiceConfigFilesController writes down the config files for extension services.\ntype ExtensionServiceConfigFilesController struct {\n\tV1Alpha1Mode            v1alpha1runtime.Mode\n\tExtensionsConfigBaseDir string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigFilesController) Name() string {\n\treturn \"runtime.ExtensionServiceConfigFilesController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigFilesController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.ExtensionServiceConfigType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ExtensionServiceConfigFilesController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.ExtensionServiceConfigStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ExtensionServiceConfigFilesController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\treturn nil\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tlist, err := safe.ReaderListAll[*runtime.ExtensionServiceConfig](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing extension services config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\ttouchedFiles := map[string]struct{}{}\n\n\t\tfor res := range list.All() {\n\t\t\textensionConfigPath := filepath.Join(ctrl.ExtensionsConfigBaseDir, res.Metadata().ID())\n\n\t\t\tif err = os.MkdirAll(extensionConfigPath, 0o755); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating directory %q: %w\", extensionConfigPath, err)\n\t\t\t}\n\n\t\t\ttouchedFiles[extensionConfigPath] = struct{}{}\n\n\t\t\tfor _, file := range res.TypedSpec().Files {\n\t\t\t\tfileName := filepath.Join(extensionConfigPath, strings.ReplaceAll(strings.TrimPrefix(file.MountPath, \"/\"), \"/\", \"-\"))\n\n\t\t\t\tif err = updateFile(fileName, []byte(file.Content), 0o644); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error writing file %q: %w\", fileName, err)\n\t\t\t\t}\n\n\t\t\t\ttouchedFiles[fileName] = struct{}{}\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewExtensionServiceConfigStatusSpec(runtime.NamespaceName, res.Metadata().ID()), func(spec *runtime.ExtensionServiceConfigStatus) error {\n\t\t\t\tspec.TypedSpec().SpecVersion = res.Metadata().Version().String()\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// remove all files not managed by us\n\t\tif err = filepath.WalkDir(ctrl.ExtensionsConfigBaseDir, func(path string, d fs.DirEntry, walkErr error) error {\n\t\t\tif _, ok := touchedFiles[path]; path != ctrl.ExtensionsConfigBaseDir && !ok {\n\t\t\t\tif err = os.RemoveAll(path); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.ExtensionServiceConfigStatus](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service_config_files_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage runtime_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype ExtensionServiceConfigFilesSuite struct {\n\tctest.DefaultSuite\n\n\textensionsConfigDir string\n}\n\nfunc TestExtensionServiceConfigFilesSuite(t *testing.T) {\n\textensionsConfigDir := t.TempDir()\n\n\tsuite.Run(t, &ExtensionServiceConfigFilesSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtime.ExtensionServiceConfigFilesController{\n\t\t\t\t\tExtensionsConfigBaseDir: extensionsConfigDir,\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t\textensionsConfigDir: extensionsConfigDir,\n\t})\n}\n\nfunc (suite *ExtensionServiceConfigFilesSuite) TestReconcileExtensionServiceConfigFiles() {\n\tfor _, tt := range []struct {\n\t\textensionName string\n\t\tconfigFiles   []struct {\n\t\t\tcontent   string\n\t\t\tmountPath string\n\t\t}\n\t}{\n\t\t{\n\t\t\textensionName: \"test-extension-a\",\n\t\t\tconfigFiles: []struct {\n\t\t\t\tcontent   string\n\t\t\t\tmountPath string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-a\",\n\t\t\t\t\tmountPath: \"/etc/test\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\textensionName: \"test-extension-b\",\n\t\t\tconfigFiles: []struct {\n\t\t\t\tcontent   string\n\t\t\t\tmountPath string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-b\",\n\t\t\t\t\tmountPath: \"/etc/bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-c\",\n\t\t\t\t\tmountPath: \"/var/etc/foo\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\textensionServiceConfigFiles := runtimeres.NewExtensionServiceConfigSpec(runtimeres.NamespaceName, tt.extensionName)\n\t\textensionServiceConfigFiles.TypedSpec().Files = xslices.Map(tt.configFiles, func(config struct {\n\t\t\tcontent   string\n\t\t\tmountPath string\n\t\t},\n\t\t) runtimeres.ExtensionServiceConfigFile {\n\t\t\treturn runtimeres.ExtensionServiceConfigFile{\n\t\t\t\tContent:   config.content,\n\t\t\t\tMountPath: config.mountPath,\n\t\t\t}\n\t\t})\n\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), extensionServiceConfigFiles))\n\n\t\tctest.AssertResource(suite, tt.extensionName,\n\t\t\tfunc(status *runtimeres.ExtensionServiceConfigStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(extensionServiceConfigFiles.Metadata().Version().String(), status.TypedSpec().SpecVersion)\n\t\t\t},\n\t\t)\n\n\t\tfor _, file := range tt.configFiles {\n\t\t\tcontent, err := os.ReadFile(filepath.Join(suite.extensionsConfigDir, tt.extensionName, strings.ReplaceAll(strings.TrimPrefix(file.mountPath, \"/\"), \"/\", \"-\")))\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tsuite.Assert().Equal(file.content, string(content))\n\t\t}\n\t}\n\n\t// create a directory and file manually in the extensions config directory\n\t// ensure that the controller deletes the manually created directory/file\n\t// also ensure that an update doesn't update existing files timestamp\n\tsuite.Assert().NoError(os.Mkdir(filepath.Join(suite.extensionsConfigDir, \"test\"), 0o755))\n\tsuite.Assert().NoError(os.WriteFile(filepath.Join(suite.extensionsConfigDir, \"test\", \"testdata\"), []byte(\"{}\"), 0o644))\n\n\textensionAConfigFileInfo, err := os.Stat(filepath.Join(suite.extensionsConfigDir, \"test-extension-a\", \"etc-test\"))\n\tsuite.Assert().NoError(err)\n\n\t// delete test-extension-b resource\n\tsuite.Assert().NoError(suite.State().Destroy(suite.Ctx(), runtimeres.NewExtensionServiceConfigSpec(runtimeres.NamespaceName, \"test-extension-b\").Metadata()))\n\tctest.AssertNoResource[*runtimeres.ExtensionServiceConfigStatus](suite, \"test-extension-b\")\n\n\tsuite.Assert().NoFileExists(filepath.Join(suite.extensionsConfigDir, \"test\", \"testdata\"))\n\tsuite.Assert().NoDirExists(filepath.Join(suite.extensionsConfigDir, \"test\"))\n\tsuite.Assert().NoFileExists(filepath.Join(suite.extensionsConfigDir, \"test-extension-b\", \"etc-bar\"))\n\tsuite.Assert().NoFileExists(filepath.Join(suite.extensionsConfigDir, \"test-extension-b\", \"var-etc-foo\"))\n\tsuite.Assert().NoDirExists(filepath.Join(suite.extensionsConfigDir, \"test-extension-b\"))\n\n\textensionAConfigFileInfoAfterUpdate, err := os.Stat(filepath.Join(suite.extensionsConfigDir, \"test-extension-a\", \"etc-test\"))\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(extensionAConfigFileInfo.ModTime(), extensionAConfigFileInfoAfterUpdate.ModTime())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tcntrconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype ExtensionServiceConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestExtensionServiceConfigSuite(t *testing.T) {\n\tsuite.Run(t, &ExtensionServiceConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtime.ExtensionServiceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *ExtensionServiceConfigSuite) TestReconcileExtensionServiceConfig() {\n\textensionServiceConfigs := []struct {\n\t\textensionName string\n\t\tconfigFiles   []struct {\n\t\t\tcontent   string\n\t\t\tmountPath string\n\t\t}\n\t\tenvironment []string\n\t}{\n\t\t{\n\t\t\textensionName: \"test-extension-a\",\n\t\t\tconfigFiles: []struct {\n\t\t\t\tcontent   string\n\t\t\t\tmountPath string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-a\",\n\t\t\t\t\tmountPath: \"/etc/test\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\textensionName: \"test-extension-b\",\n\t\t\tconfigFiles: []struct {\n\t\t\t\tcontent   string\n\t\t\t\tmountPath string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-b\",\n\t\t\t\t\tmountPath: \"/etc/bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcontent:   \"test-content-c\",\n\t\t\t\t\tmountPath: \"/var/etc/foo\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tenvironment: []string{\n\t\t\t\t\"FOO=BAR\",\n\t\t\t},\n\t\t},\n\t}\n\n\tcfgs := xslices.Map(extensionServiceConfigs, func(tt struct {\n\t\textensionName string\n\t\tconfigFiles   []struct {\n\t\t\tcontent   string\n\t\t\tmountPath string\n\t\t}\n\t\tenvironment []string\n\t},\n\t) cntrconfig.Document {\n\t\tcfg := extensions.NewServicesConfigV1Alpha1()\n\t\tcfg.ServiceName = tt.extensionName\n\t\tcfg.ServiceConfigFiles = xslices.Map(tt.configFiles, func(config struct {\n\t\t\tcontent   string\n\t\t\tmountPath string\n\t\t},\n\t\t) extensions.ConfigFile {\n\t\t\treturn extensions.ConfigFile{\n\t\t\t\tConfigFileContent:   config.content,\n\t\t\t\tConfigFileMountPath: config.mountPath,\n\t\t\t}\n\t\t})\n\t\tcfg.ServiceEnvironment = tt.environment\n\n\t\treturn cfg\n\t})\n\n\tcntr, err := container.New(cfgs...)\n\tsuite.Require().NoError(err)\n\n\tmachineConfig := config.NewMachineConfig(cntr)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineConfig))\n\n\tfor _, tt := range extensionServiceConfigs {\n\t\tctest.AssertResource(suite, tt.extensionName, func(config *runtimeres.ExtensionServiceConfig, asrt *assert.Assertions) {\n\t\t\tspec := config.TypedSpec()\n\n\t\t\tconfigFileData := xslices.Map(tt.configFiles, func(config struct {\n\t\t\t\tcontent   string\n\t\t\t\tmountPath string\n\t\t\t},\n\t\t\t) runtimeres.ExtensionServiceConfigFile {\n\t\t\t\treturn runtimeres.ExtensionServiceConfigFile{\n\t\t\t\t\tContent:   config.content,\n\t\t\t\t\tMountPath: config.mountPath,\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tsuite.Assert().Equal(configFileData, spec.Files)\n\t\t\tsuite.Assert().Equal(tt.environment, spec.Environment)\n\t\t})\n\t}\n\n\t// test deletion\n\tcfg := extensions.NewServicesConfigV1Alpha1()\n\tcfg.ServiceName = \"test-extension-a\"\n\tcntr, err = container.New(cfg)\n\tsuite.Require().NoError(err)\n\n\tmachineConfig = config.NewMachineConfig(cntr)\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), machineConfig.Metadata()))\n\n\tctest.AssertNoResource[*runtimeres.ExtensionServiceConfig](suite, \"test-extension-a\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_service_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype ExtensionServiceSuite struct {\n\tRuntimeSuite\n}\n\ntype serviceMock struct {\n\tmu           sync.Mutex\n\tservices     map[string]system.Service\n\trunning      map[string]bool\n\ttimesStarted map[string]int\n\ttimesStopped map[string]int\n}\n\nfunc (mock *serviceMock) Load(services ...system.Service) []string {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tids := make([]string, 0, len(services))\n\n\tfor _, svc := range services {\n\t\tmock.services[svc.ID(nil)] = svc\n\t\tids = append(ids, svc.ID(nil))\n\t}\n\n\treturn ids\n}\n\nfunc (mock *serviceMock) Start(serviceIDs ...string) error {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tfor _, id := range serviceIDs {\n\t\tmock.running[id] = true\n\t\tmock.timesStarted[id]++\n\t}\n\n\treturn nil\n}\n\nfunc (mock *serviceMock) IsRunning(id string) (system.Service, bool, error) {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tsvc, exists := mock.services[id]\n\tif !exists {\n\t\treturn nil, false, fmt.Errorf(\"service %q not found\", id)\n\t}\n\n\t_, running := mock.running[id]\n\n\treturn svc, running, nil\n}\n\nfunc (mock *serviceMock) Stop(ctx context.Context, serviceIDs ...string) error {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tfor _, id := range serviceIDs {\n\t\tmock.running[id] = false\n\t\tmock.timesStopped[id]++\n\t}\n\n\treturn nil\n}\n\nfunc (mock *serviceMock) getIDs() []string {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tids := make([]string, 0, len(mock.services))\n\n\tfor id := range mock.services {\n\t\tids = append(ids, id)\n\t}\n\n\tslices.Sort(ids)\n\n\treturn ids\n}\n\ntype serviceStartStopInfo struct {\n\tstarted int\n\tstopped int\n}\n\nfunc (mock *serviceMock) getTimesStartedStopped() map[string]serviceStartStopInfo {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tresult := map[string]serviceStartStopInfo{}\n\n\tfor id := range mock.services {\n\t\tresult[id] = serviceStartStopInfo{\n\t\t\tstarted: mock.timesStarted[id],\n\t\t\tstopped: mock.timesStopped[id],\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc (mock *serviceMock) get(id string) system.Service {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn mock.services[id]\n}\n\nfunc (suite *ExtensionServiceSuite) TestReconcile() {\n\tsvcMock := &serviceMock{\n\t\tservices:     map[string]system.Service{},\n\t\trunning:      map[string]bool{},\n\t\ttimesStarted: map[string]int{},\n\t\ttimesStopped: map[string]int{},\n\t}\n\n\tsuite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.ExtensionServiceController{\n\t\tV1Alpha1Services: svcMock,\n\t\tConfigPath:       \"testdata/extservices/\",\n\t}))\n\n\tsuite.startRuntime()\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\tids := svcMock.getIDs()\n\n\t\t\tif !slices.Equal(ids, []string{\"ext-frr\", \"ext-hello-world\"}) {\n\t\t\t\treturn retry.ExpectedErrorf(\"services registered: %q\", ids)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\thelloSvc := svcMock.get(\"ext-hello-world\")\n\tsuite.Require().IsType(&services.Extension{}, helloSvc)\n\n\tsuite.Assert().Equal(\"./hello-world\", helloSvc.(*services.Extension).Spec.Container.Entrypoint)\n\n\tsuite.Assert().Equal(\n\t\tmap[string]serviceStartStopInfo{\n\t\t\t\"ext-hello-world\": {\n\t\t\t\tstarted: 1,\n\t\t\t},\n\t\t\t\"ext-frr\": {\n\t\t\t\tstarted: 1,\n\t\t\t},\n\t\t},\n\t\tsvcMock.getTimesStartedStopped(),\n\t)\n\n\thelloConfig := runtime.NewExtensionServiceConfigStatusSpec(runtime.NamespaceName, \"hello-world\")\n\thelloConfig.TypedSpec().SpecVersion = \"1\"\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, helloConfig))\n\n\tassertTimesStartedStopped := func(expected map[string]serviceStartStopInfo) {\n\t\tsuite.Assert().NoError(retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tactual := svcMock.getTimesStartedStopped()\n\n\t\t\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"services restart status expected %v, actual %v\", expected, actual)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t))\n\t}\n\n\t// specVersion is 1, and ext-hello-world is already started, so it should not be restarted\n\tassertTimesStartedStopped(map[string]serviceStartStopInfo{\n\t\t\"ext-hello-world\": {\n\t\t\tstarted: 1,\n\t\t\tstopped: 0,\n\t\t},\n\t\t\"ext-frr\": {\n\t\t\tstarted: 1,\n\t\t},\n\t})\n\n\tunexpectedConfig := runtime.NewExtensionServiceConfigStatusSpec(runtime.NamespaceName, \"unexpected\")\n\tunexpectedConfig.TypedSpec().SpecVersion = \"1\"\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, unexpectedConfig))\n\n\tassertTimesStartedStopped(map[string]serviceStartStopInfo{\n\t\t\"ext-hello-world\": {\n\t\t\tstarted: 1,\n\t\t\tstopped: 0,\n\t\t},\n\t\t\"ext-frr\": {\n\t\t\tstarted: 1,\n\t\t},\n\t})\n\n\t// update config for hello service\n\thelloConfig.TypedSpec().SpecVersion = \"2\"\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, helloConfig))\n\n\tassertTimesStartedStopped(map[string]serviceStartStopInfo{\n\t\t\"ext-hello-world\": {\n\t\t\tstarted: 2,\n\t\t\tstopped: 1,\n\t\t},\n\t\t\"ext-frr\": {\n\t\t\tstarted: 1,\n\t\t},\n\t})\n\n\t// destroy config for hello service\n\tsuite.Require().NoError(suite.state.Destroy(suite.ctx, helloConfig.Metadata()))\n\n\tassertTimesStartedStopped(map[string]serviceStartStopInfo{\n\t\t\"ext-hello-world\": {\n\t\t\tstarted: 3,\n\t\t\tstopped: 2,\n\t\t},\n\t\t\"ext-frr\": {\n\t\t\tstarted: 1,\n\t\t},\n\t})\n}\n\nfunc TestExtensionServiceSuite(t *testing.T) {\n\tsuite.Run(t, new(ExtensionServiceSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/extension_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ExtensionStatusController loads extensions.yaml and updates ExtensionStatus resources.\ntype ExtensionStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ExtensionStatusController) Name() string {\n\treturn \"runtime.ExtensionStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ExtensionStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ExtensionStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.ExtensionStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *ExtensionStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// controller runs once, as extensions are static\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tvar cfg extensions.Config\n\n\tif err := cfg.Read(constants.ExtensionsRuntimeConfigFile); err != nil {\n\t\tif errors.Is(err, io.EOF) {\n\t\t\t// no extensions installed\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed loading extensions config: %w\", err)\n\t}\n\n\tfor _, layer := range cfg.Layers {\n\t\tid := strings.TrimSuffix(layer.Image, \".sqsh\")\n\n\t\tif err := safe.WriterModify(ctx, r, runtime.NewExtensionStatus(runtime.NamespaceName, id), func(res *runtime.ExtensionStatus) error {\n\t\t\t*res.TypedSpec() = *layer\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/diagnostics/address_overlap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage diagnostics\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// AddressOverlapCheck checks for overlapping host and Kubernetes pod/service CIDR addresses.\nfunc AddressOverlapCheck(ctx context.Context, r controller.Reader, logger *zap.Logger) (*runtime.DiagnosticSpec, error) {\n\thostAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressRoutedID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error reading host addresses: %w\", err)\n\t}\n\n\thostMinusK8s, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error reading host minus k8s addresses: %w\", err)\n\t}\n\n\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error reading machine configuration: %w\", err)\n\t}\n\n\tif len(hostAddresses.TypedSpec().Addresses) > 0 && len(hostMinusK8s.TypedSpec().Addresses) == 0 {\n\t\tdetails := []string{\n\t\t\tfmt.Sprintf(\"host routed addresses: %q\", xslices.Map(hostAddresses.TypedSpec().Addresses, netip.Prefix.String)),\n\t\t}\n\n\t\tif cfg.Config().Cluster() != nil {\n\t\t\tdetails = append(details, fmt.Sprintf(\"Kubernetes pod CIDRs: %q\", cfg.Config().Cluster().Network().PodCIDRs()))\n\t\t\tdetails = append(details, fmt.Sprintf(\"Kubernetes service CIDRs: %q\", cfg.Config().Cluster().Network().ServiceCIDRs()))\n\t\t}\n\n\t\treturn &runtime.DiagnosticSpec{\n\t\t\tMessage: \"host and Kubernetes pod/service CIDR addresses overlap\",\n\t\t\tDetails: details,\n\t\t}, nil\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/diagnostics/address_overlap_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage diagnostics_test\n\nimport (\n\t\"context\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/diagnostics\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestAddressOverlapCheck(t *testing.T) {\n\tt.Parallel()\n\n\tctx, cancel := context.WithTimeout(t.Context(), time.Minute)\n\tt.Cleanup(cancel)\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tsetup func(t *testing.T, ctx context.Context, st state.State)\n\n\t\texpectedWarning *runtime.DiagnosticSpec\n\t}{\n\t\t{\n\t\t\tname: \"no addresses\",\n\n\t\t\tsetup: func(t *testing.T, ctx context.Context, st state.State) {},\n\t\t},\n\t\t{\n\t\t\tname: \"no overlap\",\n\n\t\t\tsetup: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\thostAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressRoutedID)\n\t\t\t\thostAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"10.0.0.1/8\"), netip.MustParsePrefix(\"10.244.1.3/32\")}\n\t\t\t\trequire.NoError(t, st.Create(ctx, hostAddresses))\n\n\t\t\t\thostMinusK8s := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\t\t\t\thostMinusK8s.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"10.0.0.1/8\")}\n\t\t\t\trequire.NoError(t, st.Create(ctx, hostMinusK8s))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with overlap\",\n\n\t\t\tsetup: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\thostAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressRoutedID)\n\t\t\t\thostAddresses.TypedSpec().Addresses = []netip.Prefix{netip.MustParsePrefix(\"10.244.3.4/24\"), netip.MustParsePrefix(\"10.244.1.3/32\")}\n\t\t\t\trequire.NoError(t, st.Create(ctx, hostAddresses))\n\n\t\t\t\thostMinusK8s := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s))\n\t\t\t\thostMinusK8s.TypedSpec().Addresses = []netip.Prefix{}\n\t\t\t\trequire.NoError(t, st.Create(ctx, hostMinusK8s))\n\t\t\t},\n\n\t\t\texpectedWarning: &runtime.DiagnosticSpec{\n\t\t\t\tMessage: \"host and Kubernetes pod/service CIDR addresses overlap\",\n\t\t\t\tDetails: []string{\n\t\t\t\t\t\"host routed addresses: [\\\"10.244.3.4/24\\\" \\\"10.244.1.3/32\\\"]\",\n\t\t\t\t\t\"Kubernetes pod CIDRs: [\\\"10.244.0.0/16\\\"]\", \"Kubernetes service CIDRs: [\\\"10.96.0.0/12\\\"]\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlogger := zaptest.NewLogger(t)\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tin, err := generate.NewInput(\"test-cluster\", \"https://localhost\", constants.DefaultKubernetesVersion)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tcfg, err := in.Config(machine.TypeWorker)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tcfgResource := config.NewMachineConfig(cfg)\n\t\t\trequire.NoError(t, st.Create(ctx, cfgResource))\n\n\t\t\ttest.setup(t, ctx, st)\n\n\t\t\tspec, err := diagnostics.AddressOverlapCheck(ctx, st, logger)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif test.expectedWarning == nil {\n\t\t\t\trequire.Nil(t, spec)\n\t\t\t} else {\n\t\t\t\trequire.Equal(t, test.expectedWarning, spec)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/diagnostics/diagnostic.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package diagnostics provides Talos diagnostics specific checks.\npackage diagnostics\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Check defines a function that checks for a specific issue.\n//\n// If the check produces a warning, it should return a non-nil warning and nil error.\n// If the check produces an error, the error will be logged, and other checks will proceed running.\ntype Check func(ctx context.Context, r controller.Reader, logger *zap.Logger) (*runtime.DiagnosticSpec, error)\n\n// CheckDescription combines a check with a semantic ID.\ntype CheckDescription struct {\n\t// Semantic ID is used to identify the check and help message.\n\tID string\n\n\t// Hysteresis time to wait before announcing the warning after the first appearance.\n\tHysteresis time.Duration\n\n\t// Check function to run.\n\tCheck Check\n}\n\n// Checks returns a list of checks to be run by the diagnostics engine.\nfunc Checks() []CheckDescription {\n\treturn []CheckDescription{\n\t\t{\n\t\t\tID:         \"address-overlap\",\n\t\t\tHysteresis: 30 * time.Second,\n\t\t\tCheck:      AddressOverlapCheck,\n\t\t},\n\t\t{\n\t\t\tID:         \"kubelet-csr\",\n\t\t\tHysteresis: 30 * time.Second,\n\t\t\tCheck:      KubeletCSRNotApprovedCheck,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/diagnostics/kubelet_csr_not_approved.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage diagnostics\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/certificates/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// KubeletCSRNotApprovedCheck checks for kubelet server certificate rotation and no CSR approvers.\n//\n//nolint:gocyclo\nfunc KubeletCSRNotApprovedCheck(ctx context.Context, r controller.Reader, logger *zap.Logger) (*runtime.DiagnosticSpec, error) {\n\t// check kubelet status to make sure it's running & health before proceeding any further\n\tkubeletService, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"kubelet\")\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error reading kubelet service: %w\", err)\n\t}\n\n\tif !kubeletService.TypedSpec().Running || !kubeletService.TypedSpec().Healthy {\n\t\treturn nil, nil\n\t}\n\n\t// fetch nodename\n\tnodeName, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error reading nodename: %w\", err)\n\t}\n\n\t// try to access kubelet API to see if we get 'tls: internal error'\n\tc, err := (&tls.Dialer{\n\t\tNetDialer: &net.Dialer{Timeout: 5 * time.Second},\n\t\tConfig: &tls.Config{\n\t\t\tInsecureSkipVerify: true,\n\t\t},\n\t}).DialContext(ctx, \"tcp\", \"127.0.0.1:10250\")\n\tif err == nil {\n\t\treturn nil, c.Close()\n\t}\n\n\tvar netError *net.OpError\n\tif !errors.As(err, &netError) {\n\t\t// not our error\n\t\treturn nil, nil\n\t}\n\n\tif !(netError.Op == \"remote error\" && netError.Err.Error() == tls.AlertError(80).Error()) { // remote error: tls: internal error\n\t\treturn nil, nil\n\t}\n\n\tk8sClient, err := kubernetes.NewClientFromKubeletKubeconfig()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating k8s client: %w\", err)\n\t}\n\n\tdefer k8sClient.Close() //nolint:errcheck\n\n\tcsrs, err := k8sClient.Clientset.CertificatesV1().CertificateSigningRequests().List(ctx,\n\t\tmetav1.ListOptions{\n\t\t\tFieldSelector: fields.OneTermEqualSelector(\"spec.signerName\", \"kubernetes.io/kubelet-serving\").String(),\n\t\t},\n\t)\n\tif err != nil {\n\t\t// error getting CSRs\n\t\treturn nil, fmt.Errorf(\"error listing CSRs: %w\", err)\n\t}\n\n\texpectedUsername := fmt.Sprintf(\"system:node:%s\", nodeName.TypedSpec().Nodename)\n\n\tcsrs.Items = xslices.Filter(csrs.Items, func(csr v1.CertificateSigningRequest) bool {\n\t\tif csr.Spec.Username != expectedUsername {\n\t\t\treturn false\n\t\t}\n\n\t\tfor _, condition := range csr.Status.Conditions {\n\t\t\tif condition.Type == v1.CertificateApproved {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\treturn true\n\t})\n\n\tif len(csrs.Items) == 0 {\n\t\treturn nil, nil\n\t}\n\n\treturn &runtime.DiagnosticSpec{\n\t\tMessage: \"kubelet server certificate rotation is enabled, but CSR is not approved\",\n\t\tDetails: []string{\n\t\t\tfmt.Sprintf(\"kubelet API error: %s\", netError),\n\t\t\tfmt.Sprintf(\"pending CSRs: %s\",\n\t\t\t\tstrings.Join(\n\t\t\t\t\txslices.Map(csrs.Items, func(csr v1.CertificateSigningRequest) string { return csr.Name }),\n\t\t\t\t\t\", \",\n\t\t\t\t),\n\t\t\t),\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/filehash/filehash.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package filehash implements a specialized file watcher that detects changes in pseudo-files like /proc/modules.\npackage filehash\n\nimport (\n\t\"crypto/sha256\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n)\n\n// Watcher monitors a file for changes by comparing its hash every second.\ntype Watcher struct {\n\tfilepath string\n\tlastHash [32]byte\n\tquit     chan struct{}\n}\n\n// NewWatcher creates a new file watcher for the specified filepath.\nfunc NewWatcher(filepath string) (*Watcher, error) {\n\treturn &Watcher{\n\t\tfilepath: filepath,\n\t\tquit:     make(chan struct{}),\n\t}, nil\n}\n\n// Close stops the watcher and releases resources.\nfunc (w *Watcher) Close() error {\n\tclose(w.quit)\n\n\treturn nil\n}\n\n// Run polls the file every second and emits the path if the hash changes.\nfunc (w *Watcher) Run() (<-chan string, <-chan error) {\n\teventCh := make(chan string, 1)\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\tticker := time.NewTicker(time.Second)\n\t\tdefer ticker.Stop()\n\n\t\tdefer close(eventCh)\n\t\tdefer close(errCh)\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-w.quit:\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:\n\t\t\t\thash, err := hashFile(w.filepath)\n\t\t\t\tif err != nil {\n\t\t\t\t\terrCh <- err\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif hash != w.lastHash {\n\t\t\t\t\tw.lastHash = hash\n\t\t\t\t\teventCh <- w.filepath\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn eventCh, errCh\n}\n\nfunc hashFile(path string) ([32]byte, error) {\n\tvar zero [32]byte\n\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn zero, err\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\th := sha256.New()\n\tif _, err := io.Copy(h, f); err != nil {\n\t\treturn zero, err\n\t}\n\n\tvar sum [32]byte\n\tcopy(sum[:], h.Sum(nil))\n\n\treturn sum, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/filehash/filehash_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage filehash_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/filehash\"\n)\n\nfunc assertEvent(t *testing.T, eventCh <-chan string, errCh <-chan error, expected string) {\n\tt.Helper()\n\n\tselect {\n\tcase path := <-eventCh:\n\t\trequire.Equal(t, expected, path)\n\tcase err := <-errCh:\n\t\trequire.FailNow(t, \"unexpected error: %v\", err)\n\tcase <-time.After(2 * time.Second):\n\t\trequire.FailNow(t, \"timeout waiting for event\")\n\t}\n}\n\nfunc assertNoEvent(t *testing.T, eventCh <-chan string, errCh <-chan error) {\n\tt.Helper()\n\n\tselect {\n\tcase path := <-eventCh:\n\t\trequire.FailNow(t, \"unexpected event: %v\", path)\n\tcase err := <-errCh:\n\t\trequire.FailNow(t, \"unexpected error: %v\", err)\n\tcase <-time.After(500 * time.Millisecond):\n\t}\n}\n\nfunc TestWatcherDetectsChange(t *testing.T) {\n\tt.Parallel()\n\n\tdir := t.TempDir()\n\tfile := filepath.Join(dir, \"testfile\")\n\trequire.NoError(t, os.WriteFile(file, []byte(\"foo\"), 0o644))\n\n\twatcher, err := filehash.NewWatcher(file)\n\trequire.NoError(t, err)\n\n\tdefer watcher.Close() //nolint:errcheck\n\n\teventCh, errCh := watcher.Run()\n\n\t// Initial change should be detected\n\tassertEvent(t, eventCh, errCh, file)\n\n\t// No change, so no event\n\tassertNoEvent(t, eventCh, errCh)\n\n\t// Modify file\n\trequire.NoError(t, os.WriteFile(file, []byte(\"bar\"), 0o644))\n\tassertEvent(t, eventCh, errCh, file)\n\n\t// No change, so no event\n\tassertNoEvent(t, eventCh, errCh)\n}\n\nfunc TestWatcherHandlesMissingFile(t *testing.T) {\n\tt.Parallel()\n\n\tdir := t.TempDir()\n\tfile := filepath.Join(dir, \"missingfile\")\n\n\twatcher, err := filehash.NewWatcher(file)\n\trequire.NoError(t, err)\n\n\tdefer watcher.Close() //nolint:errcheck\n\n\teventCh, errCh := watcher.Run()\n\n\t// Should get an error because file does not exist\n\tselect {\n\tcase <-eventCh:\n\t\trequire.FailNow(t, \"unexpected event for missing file\")\n\tcase err := <-errCh:\n\t\trequire.Error(t, err)\n\tcase <-time.After(2 * time.Second):\n\t\trequire.FailNow(t, \"timeout waiting for error\")\n\t}\n}\n\nfunc TestWatcherClose(t *testing.T) {\n\tt.Parallel()\n\n\tdir := t.TempDir()\n\tfile := filepath.Join(dir, \"testfile\")\n\trequire.NoError(t, os.WriteFile(file, []byte(\"foo\"), 0o644))\n\n\twatcher, err := filehash.NewWatcher(file)\n\trequire.NoError(t, err)\n\n\teventCh, errCh := watcher.Run()\n\twatcher.Close() //nolint:errcheck\n\n\t// Channels should be closed\n\t_, ok1 := <-eventCh\n\t_, ok2 := <-errCh\n\n\trequire.False(t, ok1)\n\trequire.False(t, ok2)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/logfile/logfile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package logfile implements a buffered, rotating log file.\npackage logfile\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync\"\n)\n\n// LogFile is an implementation of a buffered and rotated log file.\ntype LogFile struct {\n\tmu   sync.Mutex\n\tfile *os.File\n\tbuf  bufio.Writer\n\n\tpath              string\n\tsize              int64\n\trotationThreshold int64\n}\n\n// NewLogFile creates a LogFile.\nfunc NewLogFile(path string, rotationThreshold int64) *LogFile {\n\treturn &LogFile{\n\t\tpath:              path,\n\t\trotationThreshold: rotationThreshold,\n\t}\n}\n\n// Write appends a line to the end of file, handling file creation and rotation.\nfunc (lf *LogFile) Write(line []byte) error {\n\tvar err error\n\n\tlf.mu.Lock()\n\tdefer lf.mu.Unlock()\n\n\tif lf.file == nil {\n\t\tlf.file, err = os.OpenFile(lf.path, os.O_CREATE|os.O_WRONLY, 0o640)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error opening log file %q: %w\", lf.path, err)\n\t\t}\n\n\t\tlf.size, err = lf.file.Seek(0, io.SeekEnd)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error determining log file %q length: %w\", lf.path, err)\n\t\t}\n\n\t\tlf.buf.Reset(lf.file)\n\t}\n\n\tvar n int\n\tif n, err = lf.buf.Write(append(line, '\\n')); err != nil {\n\t\treturn fmt.Errorf(\"error writing log line to file %q: %w\", lf.path, err)\n\t}\n\n\tlf.size += int64(n)\n\tif lf.size < lf.rotationThreshold {\n\t\treturn nil\n\t}\n\n\tif err = lf.close(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.Rename(lf.path, lf.path+\".1\"); err != nil {\n\t\treturn fmt.Errorf(\"error renaming log file %q: %w\", lf.path, err)\n\t}\n\n\treturn nil\n}\n\nfunc (lf *LogFile) flush() error {\n\tif err := lf.buf.Flush(); err != nil {\n\t\treturn fmt.Errorf(\"failed to flush log file %s buffer: %w\", lf.path, err)\n\t}\n\n\treturn nil\n}\n\n// Flush flushes the internal buffer to persist data to the filesystem.\nfunc (lf *LogFile) Flush() error {\n\tlf.mu.Lock()\n\tdefer lf.mu.Unlock()\n\n\treturn lf.flush()\n}\n\nfunc (lf *LogFile) close() error {\n\tif err := lf.flush(); err != nil {\n\t\treturn err\n\t}\n\n\tlf.buf.Reset(nil)\n\n\tif lf.file == nil {\n\t\treturn nil\n\t}\n\n\terr := lf.file.Close()\n\tlf.file = nil\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to close log file %s: %w\", lf.path, err)\n\t}\n\n\treturn nil\n}\n\n// Close flushes and closes the underlying file.\nfunc (lf *LogFile) Close() error {\n\tlf.mu.Lock()\n\tdefer lf.mu.Unlock()\n\n\treturn lf.close()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/logfile/logfile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage logfile_test\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/logfile\"\n)\n\nfunc TestWrite(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 1024)\n\tdefer require.NoError(t, lf.Close())\n\n\terr := lf.Write([]byte(\"hello world\"))\n\trequire.NoError(t, err)\n\n\t// Expect write to retain data in the buffer\n\tst, err := os.Stat(path)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(0), st.Size(), \"file should be empty before flush\")\n\trequire.NoError(t, lf.Flush())\n\n\t// After flush, check the data got written to the file\n\tcontent, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"hello world\\n\", string(content))\n}\n\nfunc TestWriteMultipleLines(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 1024)\n\tdefer require.NoError(t, lf.Close())\n\n\tlines := []string{\"line1\", \"line2\", \"line3\"}\n\tfor _, line := range lines {\n\t\trequire.NoError(t, lf.Write([]byte(line)))\n\t}\n\n\trequire.NoError(t, lf.Flush())\n\n\tcontent, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"line1\\nline2\\nline3\\n\", string(content))\n}\n\nfunc TestLogRotation(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\texpectedRotatedPath := path + \".1\"\n\n\tlf := logfile.NewLogFile(path, 50)\n\tdefer require.NoError(t, lf.Close())\n\n\t// We write 4 lines (indices 0-3)\n\t// expecting 0-2 to be written before rotation and 3 after rotation\n\tfor i := range 4 {\n\t\tline := []byte(\"_20_character_line_\" + strconv.Itoa(i))\n\t\trequire.NoError(t, lf.Write(line))\n\t}\n\n\t_, err := os.Stat(expectedRotatedPath)\n\trequire.NoError(t, err)\n\n\t// Verify the rotated file contains the written data\n\trotatedContent, err := os.ReadFile(expectedRotatedPath)\n\trequire.NoError(t, err)\n\trequire.Len(t, rotatedContent, 63)\n\trequire.Contains(t, string(rotatedContent), \"_20_character_line_2\")\n\trequire.NoError(t, lf.Flush())\n\n\tcurrentContent, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\trequire.Len(t, currentContent, 21)\n\trequire.Contains(t, string(currentContent), \"_20_character_line_3\")\n}\n\nfunc TestLogRotationMultipleTimes(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\trotatedPath := path + \".1\"\n\n\tlf := logfile.NewLogFile(path, 40)\n\tdefer require.NoError(t, lf.Close())\n\n\tfor i := range 10 {\n\t\tline := []byte(\"_20_character_line_\" + strconv.Itoa(i))\n\t\trequire.NoError(t, lf.Write(line))\n\t}\n\n\t// Rotated file should exist and contain most recent events before the current\n\trotatedContent, err := os.ReadFile(rotatedPath)\n\trequire.NoError(t, err)\n\trequire.Len(t, rotatedContent, 42)\n\trequire.Contains(t, string(rotatedContent), \"_20_character_line_8\")\n\trequire.Contains(t, string(rotatedContent), \"_20_character_line_9\")\n}\n\nfunc TestFlushWithoutFile(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 1024)\n\tdefer require.NoError(t, lf.Close())\n\n\trequire.NoError(t, lf.Flush())\n}\n\nfunc TestClose(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 1024)\n\n\trequire.NoError(t, lf.Write([]byte(\"data\")))\n\n\terr := lf.Close()\n\trequire.NoError(t, err)\n\n\t// Expect Close to have flushed the buffer\n\tcontent, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(content), \"data\")\n}\n\nfunc TestCloseWithoutWrite(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 1024)\n\trequire.NoError(t, lf.Close())\n}\n\nfunc TestConcurrentWrites(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\t// Do not rotate while the test runs\n\tlf := logfile.NewLogFile(path, 100000)\n\tdefer require.NoError(t, lf.Close())\n\n\tvar wg sync.WaitGroup\n\n\tnumGoroutines := 10\n\twritesPerGoroutine := 100\n\n\tfor range numGoroutines {\n\t\twg.Go(func() {\n\t\t\tfor range writesPerGoroutine {\n\t\t\t\trequire.NoError(t, lf.Write([]byte(\"goroutine write\")))\n\t\t\t}\n\t\t})\n\t}\n\n\twg.Wait()\n\n\trequire.NoError(t, lf.Flush())\n\n\tcontent, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\n\t// Count lines to verify all writes succeeded\n\tlineCount := bytes.Count(content, []byte(\"\\n\"))\n\texpectedLines := numGoroutines * writesPerGoroutine\n\trequire.Equal(t, expectedLines, lineCount)\n}\n\nfunc TestConcurrentWriteAndFlush(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\tlf := logfile.NewLogFile(path, 10000)\n\tdefer require.NoError(t, lf.Close())\n\n\tvar wg sync.WaitGroup\n\n\t// Writer goroutines\n\tfor range 5 {\n\t\twg.Go(func() {\n\t\t\tfor range 50 {\n\t\t\t\trequire.NoError(t, lf.Write([]byte(\"concurrent data\")))\n\t\t\t}\n\t\t})\n\t}\n\n\t// Flusher goroutines\n\tfor range 3 {\n\t\twg.Go(func() {\n\t\t\tfor range 10 {\n\t\t\t\trequire.NoError(t, lf.Flush())\n\t\t\t}\n\t\t})\n\t}\n\n\twg.Wait()\n\n\trequire.NoError(t, lf.Flush())\n}\n\nfunc TestConcurrentWritesWithRotation(t *testing.T) {\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"test.log\")\n\n\t// Small threshold to trigger rotation during concurrent writes\n\tlf := logfile.NewLogFile(path, 100)\n\tdefer require.NoError(t, lf.Close())\n\n\tvar wg sync.WaitGroup\n\n\tnumGoroutines := 5\n\twritesPerGoroutine := 50\n\n\tfor range numGoroutines {\n\t\twg.Go(func() {\n\t\t\tfor range writesPerGoroutine {\n\t\t\t\trequire.NoError(t, lf.Write([]byte(\"rotation test line\")))\n\t\t\t}\n\t\t})\n\t}\n\n\twg.Wait()\n\n\t_, err := os.Stat(path + \".1\")\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/oom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package oom contains utilities for OOM handler.\npackage oom\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/google/cel-go/common/types\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// RankedCgroup contains information about a cgroup used for OOM handling.\ntype RankedCgroup struct {\n\tClass         runtime.QoSCgroupClass\n\tPath          string\n\tMemoryCurrent cgroups.Value\n\tMemoryPeak    cgroups.Value\n\tMemoryMax     cgroups.Value\n}\n\nfunc cgroupValueToOptionalUint(v cgroups.Value, evalContext map[string]any, key string) {\n\tif !v.IsSet || v.IsMax || v.Frac > 0 || v.Val < 0 {\n\t\tevalContext[key] = types.OptionalNone\n\t} else {\n\t\tevalContext[key] = types.OptionalOf(types.Uint(v.Val))\n\t}\n}\n\n// CalculateScore calculates the score of the cgroup for OOM handling.\n//\n// Higher score means the cgroup is more likely to be killed.\nfunc (cgroup *RankedCgroup) CalculateScore(expr *cel.Expression) (float64, error) {\n\tevalContext := map[string]any{\n\t\t\"class\": int(cgroup.Class),\n\t\t\"path\":  cgroup.Path,\n\t}\n\n\tcgroupValueToOptionalUint(cgroup.MemoryCurrent, evalContext, \"memory_current\")\n\tcgroupValueToOptionalUint(cgroup.MemoryPeak, evalContext, \"memory_peak\")\n\tcgroupValueToOptionalUint(cgroup.MemoryMax, evalContext, \"memory_max\")\n\n\treturn expr.EvalDouble(celenv.OOMCgroupScoring(), evalContext)\n}\n\n// EvaluateTrigger is a method obtaining data and evaluating the trigger expression.\n// When the result is true, designated OOM action is to be executed.\nfunc EvaluateTrigger(triggerExpr cel.Expression, evalContext map[string]any) (bool, error) {\n\ttrigger, err := triggerExpr.EvalBool(celenv.OOMTrigger(), evalContext)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"cannot evaluate expression: %w\", err)\n\t}\n\n\treturn trigger, nil\n}\n\n// PopulatePsiToCtx populates the context with PSI data from a cgroup.\n//\n//nolint:gocyclo\nfunc PopulatePsiToCtx(cgroup string, evalContext map[string]any, oldValues map[string]float64, sampleInterval time.Duration) error {\n\tif sampleInterval <= 0 {\n\t\treturn fmt.Errorf(\"sample interval must be greater than zero\")\n\t}\n\n\tfor _, subtree := range []struct {\n\t\tpath string\n\t\tqos  runtime.QoSCgroupClass\n\t}{\n\t\t{\"\", -1},\n\t\t{\"init\", runtime.QoSCgroupClassSystem},\n\t\t{\"system\", runtime.QoSCgroupClassSystem},\n\t\t{\"podruntime\", runtime.QoSCgroupClassPodruntime},\n\t\t{\"kubepods/besteffort\", runtime.QoSCgroupClassBesteffort},\n\t\t{\"kubepods/burstable\", runtime.QoSCgroupClassBurstable},\n\t\t{\"kubepods/guaranteed\", runtime.QoSCgroupClassGuaranteed},\n\t} {\n\t\tnode, err := cgroups.GetCgroupProperty(filepath.Join(cgroup, subtree.path), \"memory.pressure\")\n\n\t\tfor _, psiType := range []string{\"some\", \"full\"} {\n\t\t\tfor _, span := range []string{\"avg10\", \"avg60\", \"avg300\", \"total\"} {\n\t\t\t\tvalue := 0.\n\n\t\t\t\t// Default non-existent cgroups to all-zero, e.g. during system boot\n\t\t\t\tif err == nil {\n\t\t\t\t\tvalue, err = extractPsiEntry(node, psiType, span)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// calculate delta\n\t\t\t\tpsiPath := subtree.path + \"/\" + \"memory_\" + psiType + \"_\" + span\n\n\t\t\t\tdiff := 0.\n\t\t\t\tif oldValue, ok := oldValues[psiPath]; ok {\n\t\t\t\t\tdiff = (value - oldValue) / sampleInterval.Seconds()\n\t\t\t\t}\n\n\t\t\t\toldValues[psiPath] = value\n\n\t\t\t\tif subtree.qos == -1 {\n\t\t\t\t\tevalContext[\"d_memory_\"+psiType+\"_\"+span] = diff\n\t\t\t\t\tevalContext[\"memory_\"+psiType+\"_\"+span] = value\n\t\t\t\t} else {\n\t\t\t\t\tvaluesMap, ok := evalContext[\"qos_memory_\"+psiType+\"_\"+span]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tvaluesMap = map[int]float64{}\n\t\t\t\t\t\tevalContext[\"qos_memory_\"+psiType+\"_\"+span] = valuesMap\n\t\t\t\t\t}\n\n\t\t\t\t\tvaluesMap.(map[int]float64)[int(subtree.qos)] += value\n\n\t\t\t\t\tdValuesMap, ok := evalContext[\"d_qos_memory_\"+psiType+\"_\"+span]\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tdValuesMap = map[int]float64{}\n\t\t\t\t\t\tevalContext[\"d_qos_memory_\"+psiType+\"_\"+span] = dValuesMap\n\t\t\t\t\t}\n\n\t\t\t\t\tdValuesMap.(map[int]float64)[int(subtree.qos)] += diff\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnode = &cgroups.Node{}\n\t\t// Best effort, if any is not present it will return NaN\n\t\tcgroups.ReadCgroupfsProperty(node, filepath.Join(cgroup, subtree.path), \"memory.current\") //nolint:errcheck\n\t\tcgroups.ReadCgroupfsProperty(node, filepath.Join(cgroup, subtree.path), \"memory.max\")     //nolint:errcheck\n\t\tcgroups.ReadCgroupfsProperty(node, filepath.Join(cgroup, subtree.path), \"memory.peak\")    //nolint:errcheck\n\n\t\tif subtree.qos == -1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, parameter := range []struct {\n\t\t\tname  string\n\t\t\tvalue float64\n\t\t}{\n\t\t\t{\"current\", node.MemoryCurrent.Float64()},\n\t\t\t{\"max\", node.MemoryMax.Float64()},\n\t\t\t{\"peak\", node.MemoryPeak.Float64()},\n\t\t} {\n\t\t\tvalue := parameter.value\n\t\t\t// These values cannot be expressed in JSON\n\t\t\tif math.IsNaN(value) || math.IsInf(value, 0) {\n\t\t\t\tvalue = 0.0\n\t\t\t}\n\n\t\t\tvaluesMap, ok := evalContext[\"qos_memory_\"+parameter.name]\n\t\t\tif !ok {\n\t\t\t\tvaluesMap = map[int]float64{}\n\t\t\t\tevalContext[\"qos_memory_\"+parameter.name] = valuesMap\n\t\t\t}\n\n\t\t\tvaluesMap.(map[int]float64)[int(subtree.qos)] += value\n\n\t\t\toldPath := subtree.path + \"/\" + \"memory_\" + parameter.name\n\n\t\t\tdiff := 0.\n\t\t\tif oldValue, ok := oldValues[oldPath]; ok {\n\t\t\t\tdiff = (value - oldValue) / sampleInterval.Seconds()\n\t\t\t}\n\n\t\t\tdValuesMap, ok := evalContext[\"d_qos_memory_\"+parameter.name]\n\t\t\tif !ok {\n\t\t\t\tdValuesMap = map[int]float64{}\n\t\t\t\tevalContext[\"d_qos_memory_\"+parameter.name] = dValuesMap\n\t\t\t}\n\n\t\t\tdValuesMap.(map[int]float64)[int(subtree.qos)] += diff\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc extractPsiEntry(node *cgroups.Node, psiType string, span string) (float64, error) {\n\tspans, ok := node.MemoryPressure[psiType]\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"cannot find memory pressure type: type: %s\", psiType)\n\t}\n\n\tcgValue, ok := spans[span]\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"cannot find memory pressure span: span: %s\", span)\n\t}\n\n\tif !cgValue.IsSet || cgValue.IsMax {\n\t\treturn 0, fmt.Errorf(\"PSI is not defined\")\n\t}\n\n\treturn cgValue.Float64(), nil\n}\n\n// RankCgroups ranks cgroups using a scoring expression and returns a map.\nfunc RankCgroups(logger *zap.Logger, root string, scoringExpr cel.Expression) map[RankedCgroup]float64 {\n\tranking := map[RankedCgroup]float64{}\n\n\tfor _, cg := range []struct {\n\t\tdir   string\n\t\tclass runtime.QoSCgroupClass\n\t}{\n\t\t{\"kubepods/besteffort\", runtime.QoSCgroupClassBesteffort},\n\t\t{\"kubepods/burstable\", runtime.QoSCgroupClassBurstable},\n\t\t{\"kubepods/guaranteed\", runtime.QoSCgroupClassGuaranteed},\n\t\t{constants.CgroupPodRuntimeRoot, runtime.QoSCgroupClassPodruntime},\n\t\t{constants.CgroupSystem, runtime.QoSCgroupClassSystem},\n\t} {\n\t\tentries, err := os.ReadDir(filepath.Join(root, cg.dir))\n\t\tif err != nil && !os.IsNotExist(err) {\n\t\t\tlogger.Error(\"cannot list cgroup members\", zap.String(\"dir\", cg.dir), zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, leaf := range entries {\n\t\t\tif !leaf.IsDir() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tleafDir := filepath.Join(root, cg.dir, leaf.Name())\n\n\t\t\tnode := cgroups.Node{}\n\n\t\t\tfor _, prop := range []string{\"memory.current\", \"memory.peak\", \"memory.max\"} {\n\t\t\t\terr := cgroups.ReadCgroupfsProperty(&node, leafDir, prop)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.Error(\"cannot read property for cgroup\",\n\t\t\t\t\t\tzap.String(\"dir\", leafDir), zap.String(\"propery\", prop), zap.Error(err),\n\t\t\t\t\t)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcgroup := RankedCgroup{\n\t\t\t\tPath:          leafDir,\n\t\t\t\tClass:         cg.class,\n\t\t\t\tMemoryCurrent: node.MemoryCurrent,\n\t\t\t\tMemoryPeak:    node.MemoryPeak,\n\t\t\t\tMemoryMax:     node.MemoryMax,\n\t\t\t}\n\n\t\t\tranking[cgroup], err = cgroup.CalculateScore(&scoringExpr)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error(\"cannot calculate score for cgroup\",\n\t\t\t\t\tzap.String(\"dir\", cgroup.Path), zap.Error(err),\n\t\t\t\t)\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ranking\n}\n\n// ListCgroupProcs returns a list of process IDs for a given cgroup path.\nfunc ListCgroupProcs(cgroupPath string) []int {\n\tprocesses := []int{}\n\n\t// Ignore errors, find as many processes as possible\n\t//nolint:errcheck\n\tfilepath.WalkDir(cgroupPath, func(path string, d fs.DirEntry, walkErr error) error {\n\t\tif walkErr != nil {\n\t\t\treturn walkErr\n\t\t}\n\n\t\tif !d.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tnode, err := cgroups.GetCgroupProperty(path, \"cgroup.procs\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, p := range node.CgroupProcs {\n\t\t\tprocesses = append(processes, int(p.Val))\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn processes\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/oom_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage oom_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/oom\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nconst expr1 = constants.DefaultOOMCgroupRankingExpression\n\nfunc TestCalculateScore(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname   string\n\t\texpr   string\n\t\tcgroup oom.RankedCgroup\n\t\texpect float64\n\t}{\n\t\t{\n\t\t\tname: \"basic\",\n\t\t\texpr: expr1,\n\t\t\tcgroup: oom.RankedCgroup{\n\t\t\t\tClass:         runtime.QoSCgroupClassBurstable,\n\t\t\t\tPath:          \"/some/path\",\n\t\t\t\tMemoryCurrent: cgroups.Value{Val: 42, IsSet: true},\n\t\t\t\tMemoryPeak:    cgroups.Value{Val: 50, IsSet: true},\n\t\t\t\tMemoryMax:     cgroups.Value{IsSet: true, IsMax: true},\n\t\t\t},\n\t\t\texpect: 21,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tparsedExpr, err := cel.ParseDoubleExpression(test.expr, celenv.OOMCgroupScoring())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tscore, err := test.cgroup.CalculateScore(&parsedExpr)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expect, score)\n\t\t},\n\t\t)\n\t}\n}\n\nfunc TestRankCgroups(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname   string\n\t\tdir    string\n\t\texpr   string\n\t\texpect map[oom.RankedCgroup]float64\n\t}{\n\t\t{\n\t\t\tname: \"basic\",\n\t\t\tdir:  \"./testdata/rank1\",\n\t\t\texpr: expr1,\n\t\t\texpect: map[oom.RankedCgroup]float64{\n\t\t\t\t{\n\t\t\t\t\tClass:         runtime.QoSCgroupClassBesteffort,\n\t\t\t\t\tPath:          \"testdata/rank1/kubepods/besteffort/pod123\",\n\t\t\t\t\tMemoryCurrent: cgroups.Value{Val: 222593024, IsSet: true},\n\t\t\t\t\tMemoryPeak:    cgroups.Value{Val: 371011584, IsSet: true},\n\t\t\t\t\tMemoryMax:     cgroups.Value{IsMax: true, IsSet: true},\n\t\t\t\t}: 2.22593024e+08,\n\t\t\t\t{\n\t\t\t\t\tClass:         runtime.QoSCgroupClassBurstable,\n\t\t\t\t\tPath:          \"testdata/rank1/kubepods/burstable/podABC\",\n\t\t\t\t\tMemoryCurrent: cgroups.Value{Val: 42, IsSet: true},\n\t\t\t\t\tMemoryPeak:    cgroups.Value{Val: 50, IsSet: true},\n\t\t\t\t\tMemoryMax:     cgroups.Value{IsSet: true, IsMax: true},\n\t\t\t\t}: 21,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlogger := zap.New(nil)\n\n\t\t\tparsedExpr, err := cel.ParseDoubleExpression(test.expr, celenv.OOMCgroupScoring())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult := oom.RankCgroups(logger, test.dir, parsedExpr)\n\n\t\t\tassert.Equal(t, test.expect, result)\n\t\t})\n\t}\n}\n\nfunc TestPopulatePsiToCtx(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname      string\n\t\tdir       string\n\t\texpectErr string\n\t\texpect    map[string]any\n\t}{\n\t\t//nolint:dupl\n\t\t{\n\t\t\tname:      \"empty\",\n\t\t\tdir:       \"./testdata/empty\",\n\t\t\texpectErr: \"\",\n\t\t\texpect: map[string]any{\n\t\t\t\t\"memory_full_avg10\":    0.0,\n\t\t\t\t\"memory_full_avg300\":   0.0,\n\t\t\t\t\"memory_full_avg60\":    0.0,\n\t\t\t\t\"memory_full_total\":    0.0,\n\t\t\t\t\"memory_some_avg10\":    0.0,\n\t\t\t\t\"memory_some_avg300\":   0.0,\n\t\t\t\t\"memory_some_avg60\":    0.0,\n\t\t\t\t\"memory_some_total\":    0.0,\n\t\t\t\t\"d_memory_full_avg10\":  0.0,\n\t\t\t\t\"d_memory_full_avg300\": 0.0,\n\t\t\t\t\"d_memory_full_avg60\":  0.0,\n\t\t\t\t\"d_memory_full_total\":  0.0,\n\t\t\t\t\"d_memory_some_avg10\":  0.0,\n\t\t\t\t\"d_memory_some_avg300\": 0.0,\n\t\t\t\t\"d_memory_some_avg60\":  0.0,\n\t\t\t\t\"d_memory_some_total\":  0.0,\n\n\t\t\t\t\"qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t//nolint:dupl\n\t\t{\n\t\t\tname:      \"false\",\n\t\t\tdir:       \"./testdata/trigger-false\",\n\t\t\texpectErr: \"\",\n\t\t\texpect: map[string]any{\n\t\t\t\t\"memory_full_avg10\":    2.4,\n\t\t\t\t\"memory_full_avg300\":   1.71,\n\t\t\t\t\"memory_full_avg60\":    5.16,\n\t\t\t\t\"memory_full_total\":    1.0654831e+07,\n\t\t\t\t\"memory_some_avg10\":    2.82,\n\t\t\t\t\"memory_some_avg300\":   1.97,\n\t\t\t\t\"memory_some_avg60\":    5.95,\n\t\t\t\t\"memory_some_total\":    1.217234e+07,\n\t\t\t\t\"d_memory_full_avg10\":  0.0,\n\t\t\t\t\"d_memory_full_avg300\": 0.0,\n\t\t\t\t\"d_memory_full_avg60\":  0.0,\n\t\t\t\t\"d_memory_full_total\":  0.0,\n\t\t\t\t\"d_memory_some_avg10\":  0.0,\n\t\t\t\t\"d_memory_some_avg300\": 0.0,\n\t\t\t\t\"d_memory_some_avg60\":  0.0,\n\t\t\t\t\"d_memory_some_total\":  0.0,\n\n\t\t\t\t\"qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 2.82,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     5.64,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 5.95,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     11.9,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.97,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     3.94,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.217234e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     2.434468e+07,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 2.4,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     4.8,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 5.16,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     10.32,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.71,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     3.42,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.0654831e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     1.0654937e+07,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// //nolint:dupl\n\t\t{\n\t\t\tname:      \"true\",\n\t\t\tdir:       \"./testdata/trigger-true\",\n\t\t\texpectErr: \"\",\n\t\t\texpect: map[string]any{\n\t\t\t\t\"memory_full_avg10\":    14.54,\n\t\t\t\t\"memory_full_avg60\":    6.97,\n\t\t\t\t\"memory_full_avg300\":   1.82,\n\t\t\t\t\"memory_full_total\":    1.0654831e+07,\n\t\t\t\t\"memory_some_avg10\":    17.06,\n\t\t\t\t\"memory_some_avg60\":    8.04,\n\t\t\t\t\"memory_some_avg300\":   2.1,\n\t\t\t\t\"memory_some_total\":    1.217234e+07,\n\t\t\t\t\"d_memory_full_avg10\":  0.0,\n\t\t\t\t\"d_memory_full_avg300\": 0.0,\n\t\t\t\t\"d_memory_full_avg60\":  0.0,\n\t\t\t\t\"d_memory_full_total\":  0.0,\n\t\t\t\t\"d_memory_some_avg10\":  0.0,\n\t\t\t\t\"d_memory_some_avg300\": 0.0,\n\t\t\t\t\"d_memory_some_avg60\":  0.0,\n\t\t\t\t\"d_memory_some_total\":  0.0,\n\n\t\t\t\t\"qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 17.06,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 17.06,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     34.12,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 8.04,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 8.04,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     16.08,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 2.1,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 2.1,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     4.2,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 1.217234e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.217234e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     2.434468e+07,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 14.54,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 14.54,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     29.08,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 6.97,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 6.97,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     13.94,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 1.82,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.82,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     3.64,\n\t\t\t\t},\n\t\t\t\t\"qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 1.0654831e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 1.0654831e+07,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     2.1309662e+07,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_some_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg10\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg60\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_avg300\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_full_total\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_current\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_peak\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\n\t\t\t\t\"qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t\t\"d_qos_memory_max\": map[int]float64{\n\t\t\t\t\tint(runtime.QoSCgroupClassBesteffort): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassBurstable):  0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassGuaranteed): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassPodruntime): 0.0,\n\t\t\t\t\tint(runtime.QoSCgroupClassSystem):     0.0,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx := map[string]any{}\n\n\t\t\terr := oom.PopulatePsiToCtx(test.dir, ctx, make(map[string]float64), 500*time.Millisecond)\n\n\t\t\tif test.expectErr == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, test.expect, ctx)\n\t\t\t} else {\n\t\t\t\tassert.ErrorContains(t, err, test.expectErr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestEvaluateTrigger(t *testing.T) {\n\tt.Parallel()\n\n\ttriggerExpr1 := cel.MustExpression(cel.ParseBooleanExpression(\n\t\tconstants.DefaultOOMTriggerExpression,\n\t\tcelenv.OOMTrigger(),\n\t))\n\n\tfor _, test := range []struct {\n\t\tname        string\n\t\tdir         string\n\t\tctx         map[string]any\n\t\ttriggerExpr cel.Expression\n\t\texpect      bool\n\t\texpectErr   string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tdir:  \"./testdata/empty\",\n\t\t\tctx: map[string]any{\n\t\t\t\t\"time_since_trigger\": 3 * time.Second,\n\t\t\t},\n\t\t\ttriggerExpr: triggerExpr1,\n\t\t\texpect:      false,\n\t\t\texpectErr:   \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"cgroup-false\",\n\t\t\tdir:  \"./testdata/trigger-false\",\n\t\t\tctx: map[string]any{\n\t\t\t\t\"time_since_trigger\": 3 * time.Second,\n\t\t\t},\n\t\t\ttriggerExpr: triggerExpr1,\n\t\t\texpect:      false,\n\t\t\texpectErr:   \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"cgroup-true-cool\",\n\t\t\tdir:  \"./testdata/trigger-true\",\n\t\t\tctx: map[string]any{\n\t\t\t\t\"time_since_trigger\": 3 * time.Second,\n\t\t\t},\n\t\t\ttriggerExpr: triggerExpr1,\n\t\t\texpect:      true,\n\t\t\texpectErr:   \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"cgroup-true-hot\",\n\t\t\tdir:  \"./testdata/trigger-true\",\n\t\t\tctx: map[string]any{\n\t\t\t\t\"time_since_trigger\": 300 * time.Millisecond,\n\t\t\t},\n\t\t\ttriggerExpr: cel.MustExpression(cel.ParseBooleanExpression(\n\t\t\t\t`memory_full_avg10 > 12.0 && time_since_trigger > duration(\"500ms\")`,\n\t\t\t\tcelenv.OOMTrigger(),\n\t\t\t)),\n\t\t\texpect:    false,\n\t\t\texpectErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"cgroup-true-hot-overridden\",\n\t\t\tdir:  \"./testdata/trigger-true\",\n\t\t\tctx: map[string]any{\n\t\t\t\t\"time_since_trigger\": 300 * time.Millisecond,\n\t\t\t},\n\t\t\ttriggerExpr: cel.MustExpression(cel.ParseBooleanExpression(\n\t\t\t\t`memory_full_avg10 > 12.0 && time_since_trigger > duration(\"250ms\")`,\n\t\t\t\tcelenv.OOMTrigger(),\n\t\t\t)),\n\t\t\texpect:    true,\n\t\t\texpectErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"test multiply_qos\",\n\t\t\tctx:  map[string]any{},\n\t\t\tdir:  \"./testdata/trigger-true\",\n\t\t\ttriggerExpr: cel.MustExpression(cel.ParseBooleanExpression(\n\t\t\t\t// 5 * 1 + 2 * -1 + 0 * 3 == 3\n\t\t\t\t`multiply_qos_vectors({Besteffort: 5.0, Burstable: 2.0, Guaranteed: 0.0, System: 1.0}, {Besteffort: 1.0, Burstable: -1.0, Guaranteed: 3.0}) == 3.0`,\n\t\t\t\tcelenv.OOMTrigger(),\n\t\t\t)),\n\t\t\texpect: true,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := oom.PopulatePsiToCtx(test.dir, test.ctx, map[string]float64{\n\t\t\t\t\"memory_full_avg10\":  0,\n\t\t\t\t\"memory_full_avg300\": 0,\n\t\t\t\t\"memory_full_avg60\":  0,\n\t\t\t\t\"memory_full_total\":  0,\n\t\t\t\t\"memory_some_avg10\":  0,\n\t\t\t\t\"memory_some_avg300\": 0,\n\t\t\t\t\"memory_some_avg60\":  0,\n\t\t\t\t\"memory_some_total\":  0,\n\n\t\t\t\t\"init/memory_full_total\": 0,\n\t\t\t}, 500*time.Millisecond)\n\n\t\t\tif test.expectErr == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\ttrigger, err := oom.EvaluateTrigger(test.triggerExpr, test.ctx)\n\n\t\t\t\tassert.Equal(t, test.expect, trigger)\n\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.ErrorContains(t, err, test.expectErr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestListCgroupProcs(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname   string\n\t\tdir    string\n\t\texpect []int\n\t}{\n\t\t{\n\t\t\tname:   \"pod123\",\n\t\t\tdir:    \"testdata/rank1/kubepods/besteffort/pod123\",\n\t\t\texpect: []int{1},\n\t\t},\n\t\t{\n\t\t\tname:   \"podABC\",\n\t\t\tdir:    \"testdata/rank1/kubepods/burstable/podABC\",\n\t\t\texpect: []int{132, 142536},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expect, oom.ListCgroupProcs(test.dir))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/besteffort/pod123/cgroup.procs",
    "content": "1\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/besteffort/pod123/memory.current",
    "content": "222593024\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/besteffort/pod123/memory.max",
    "content": "max\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/besteffort/pod123/memory.peak",
    "content": "371011584\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/burstable/podABC/cgroup.procs",
    "content": "132\n142536\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/burstable/podABC/memory.current",
    "content": "42\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/burstable/podABC/memory.max",
    "content": "max\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/rank1/kubepods/burstable/podABC/memory.peak",
    "content": "50\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-false/init/memory.pressure",
    "content": "some avg10=2.82 avg60=5.95 avg300=1.97 total=12172340\nfull avg10=2.40 avg60=5.16 avg300=1.71 total=106\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-false/memory.pressure",
    "content": "some avg10=2.82 avg60=5.95 avg300=1.97 total=12172340\nfull avg10=2.40 avg60=5.16 avg300=1.71 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-false/podruntime/memory.pressure",
    "content": "some avg10=2.82 avg60=5.95 avg300=1.97 total=12172340\nfull avg10=2.40 avg60=5.16 avg300=1.71 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-false/system/memory.pressure",
    "content": "some avg10=2.82 avg60=5.95 avg300=1.97 total=12172340\nfull avg10=2.40 avg60=5.16 avg300=1.71 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-true/init/memory.pressure",
    "content": "some avg10=17.06 avg60=8.04 avg300=2.10 total=12172340\nfull avg10=14.54 avg60=6.97 avg300=1.82 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-true/kubepods/besteffort/memory.pressure",
    "content": "some avg10=17.06 avg60=8.04 avg300=2.10 total=12172340\nfull avg10=14.54 avg60=6.97 avg300=1.82 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-true/memory.pressure",
    "content": "some avg10=17.06 avg60=8.04 avg300=2.10 total=12172340\nfull avg10=14.54 avg60=6.97 avg300=1.82 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-true/podruntime/memory.pressure",
    "content": "some avg10=17.06 avg60=8.04 avg300=2.10 total=12172340\nfull avg10=14.54 avg60=6.97 avg300=1.82 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/internal/oom/testdata/trigger-true/system/memory.pressure",
    "content": "some avg10=17.06 avg60=8.04 avg300=2.10 total=12172340\nfull avg10=14.54 avg60=6.97 avg300=1.82 total=10654831\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_cmdline.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelCmdlineController presents /proc/cmdline as a resource.\ntype KernelCmdlineController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelCmdlineController) Name() string {\n\treturn \"runtime.KernelCmdlineController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelCmdlineController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelCmdlineController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelCmdlineType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *KernelCmdlineController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode.InContainer() {\n\t\t// no cmdline in containers\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tcontents, err := os.ReadFile(\"/proc/cmdline\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading /proc/cmdline: %w\", err)\n\t}\n\n\tif err := safe.WriterModify(ctx, r,\n\t\truntime.NewKernelCmdline(),\n\t\tfunc(res *runtime.KernelCmdline) error {\n\t\t\tres.TypedSpec().Cmdline = strings.TrimSpace(string(contents))\n\n\t\t\treturn nil\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error updating KernelCmdline resource: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_cmdline_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestKernelCmdlineSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &KernelCmdlineSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.KernelCmdlineController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype KernelCmdlineSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KernelCmdlineSuite) TestKernelCmdline() {\n\tctest.AssertResource(suite, runtime.KernelCmdlineID, func(res *runtime.KernelCmdline, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(res.TypedSpec().Cmdline)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_module_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelModuleConfigController watches v1alpha1.Config, creates/updates/deletes kernel module specs.\ntype KernelModuleConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelModuleConfigController) Name() string {\n\treturn \"runtime.KernelModuleConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelModuleConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelModuleConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelModuleSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KernelModuleConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tfor _, module := range cfg.Config().Machine().Kernel().Modules() {\n\t\t\t\titem := runtime.NewKernelModuleSpec(runtime.NamespaceName, module.Name())\n\n\t\t\t\tif err = safe.WriterModify(ctx, r, item, func(res *runtime.KernelModuleSpec) error {\n\t\t\t\t\tres.TypedSpec().Name = module.Name()\n\t\t\t\t\tres.TypedSpec().Parameters = module.Parameters()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.KernelModuleSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_module_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\truntimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype KernelModuleConfigSuite struct {\n\tRuntimeSuite\n}\n\nfunc (suite *KernelModuleConfigSuite) TestReconcileConfig() {\n\tsuite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.KernelModuleConfigController{}))\n\n\tsuite.startRuntime()\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKernel: &v1alpha1.KernelConfig{\n\t\t\t\t\t\tKernelModules: []*v1alpha1.KernelModuleConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tModuleName: \"btrfs\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tModuleName: \"e1000\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tspecMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelModuleSpecType, \"e1000\", resource.VersionUndefined)\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertResource(\n\t\t\tspecMD,\n\t\t\tfunc(res resource.Resource) bool {\n\t\t\t\treturn res.(*runtimeresource.KernelModuleSpec).TypedSpec().Name == \"e1000\"\n\t\t\t},\n\t\t),\n\t))\n\n\told := cfg.Metadata().Version()\n\tcfg = config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineKernel: nil,\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tcfg.Metadata().SetVersion(old)\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, cfg))\n\n\tvar err error\n\n\t// wait for the resource to be removed\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\tfor _, md := range []resource.Metadata{specMD} {\n\t\t\t\t_, err = suite.state.Get(suite.ctx, md)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn retry.ExpectedErrorf(\"resource still exists\")\n\t\t},\n\t))\n}\n\nfunc TestKernelModuleConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(KernelModuleConfigSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_module_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/pmorjan/kmod\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelModuleSpecController watches KernelModuleSpecs, sets/resets kernel params.\ntype KernelModuleSpecController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelModuleSpecController) Name() string {\n\treturn \"runtime.KernelModuleSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelModuleSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.KernelModuleSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelModuleSpecController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *KernelModuleSpecController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\t// not supported in container mode\n\t\treturn nil\n\t}\n\n\tmanager, err := kmod.New()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing kmod manager: %w\", err)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmodules, err := safe.ReaderListAll[*runtime.KernelModuleSpec](ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar multiErr error\n\n\t\t// note: this code doesn't support module unloading in any way for now\n\t\tfor module := range modules.All() {\n\t\t\tmoduleSpec := module.TypedSpec()\n\t\t\tparameters := strings.Join(moduleSpec.Parameters, \" \")\n\n\t\t\tif err = manager.Load(moduleSpec.Name, parameters, 0); err != nil {\n\t\t\t\tmultiErr = errors.Join(multiErr, fmt.Errorf(\"error loading module %q: %w\", moduleSpec.Name, err))\n\t\t\t}\n\t\t}\n\n\t\tif multiErr != nil {\n\t\t\treturn multiErr\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelParamConfigController watches v1alpha1.Config, creates/updates/deletes kernel param specs.\ntype KernelParamConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelParamConfigController) Name() string {\n\treturn \"runtime.KernelParamConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelParamConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelParamConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelParamSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KernelParamConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tsetKernelParam := func(kind, key, value string) error {\n\t\t\titem := runtime.NewKernelParamSpec(runtime.NamespaceName, kind+\".\"+key)\n\n\t\t\treturn safe.WriterModify(ctx, r, item, func(res *runtime.KernelParamSpec) error {\n\t\t\t\tres.TypedSpec().Value = value\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\n\t\tif cfg != nil && cfg.Config().Machine() != nil {\n\t\t\tfor key, value := range cfg.Config().Machine().Sysctls() {\n\t\t\t\tif err = setKernelParam(kernel.Sysctl, key, value); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor key, value := range cfg.Config().Machine().Sysfs() {\n\t\t\t\tif err = setKernelParam(kernel.Sysfs, key, value); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.KernelParamSpec](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\truntimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype KernelParamConfigSuite struct {\n\tRuntimeSuite\n}\n\nfunc (suite *KernelParamConfigSuite) TestReconcileConfig() {\n\tsuite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.KernelParamConfigController{}))\n\n\tsuite.startRuntime()\n\n\tvalue := \"500000\"\n\tvalueSysfs := \"600000\"\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineSysctls: map[string]string{\n\t\t\t\t\t\tfsFileMax: value,\n\t\t\t\t\t},\n\t\t\t\t\tMachineSysfs: map[string]string{\n\t\t\t\t\t\tfsFileMax: valueSysfs,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsysctlMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelParamSpecType, procSysfsFileMax, resource.VersionUndefined)\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertResource(\n\t\t\tsysctlMD,\n\t\t\tfunc(res resource.Resource) bool {\n\t\t\t\tspec := res.(*runtimeresource.KernelParamSpec).TypedSpec()\n\n\t\t\t\treturn suite.Assert().Equal(value, spec.Value)\n\t\t\t},\n\t\t),\n\t))\n\n\tsysfsMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelParamSpecType, sysfsFileMax, resource.VersionUndefined)\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertResource(\n\t\t\tsysfsMD,\n\t\t\tfunc(res resource.Resource) bool {\n\t\t\t\tspec := res.(*runtimeresource.KernelParamSpec).TypedSpec()\n\n\t\t\t\treturn suite.Assert().Equal(valueSysfs, spec.Value)\n\t\t\t},\n\t\t),\n\t))\n\n\told := cfg.Metadata().Version()\n\tcfg = config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineSysctls: map[string]string{},\n\t\t\t\t\tMachineSysfs: map[string]string{\n\t\t\t\t\t\tfsFileMax: valueSysfs,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tcfg.Metadata().SetVersion(old)\n\tsuite.Require().NoError(suite.state.Update(suite.ctx, cfg))\n\n\tvar err error\n\n\t// wait for the resource to be removed\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\tfor _, md := range []resource.Metadata{sysctlMD} {\n\t\t\t\t_, err = suite.state.Get(suite.ctx, md)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn retry.ExpectedErrorf(\"resource still exists\")\n\t\t},\n\t))\n}\n\nfunc TestKernelParamConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(KernelParamConfigSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_defaults.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/kernel/kspp\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelParamDefaultsController creates default kernel params.\ntype KernelParamDefaultsController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelParamDefaultsController) Name() string {\n\treturn \"runtime.KernelParamDefaultsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelParamDefaultsController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelParamDefaultsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelParamDefaultSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *KernelParamDefaultsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t\tkernelParams := ctrl.getKernelParams()\n\t\tif ctrl.V1Alpha1Mode != v1alpha1runtime.ModeContainer {\n\t\t\tkernelParams = append(kernelParams, kspp.GetKernelParams()...)\n\t\t}\n\n\t\tfor _, prop := range kernelParams {\n\t\t\tvalue := prop.Value\n\t\t\titem := runtime.NewKernelParamDefaultSpec(runtime.NamespaceName, prop.Key)\n\n\t\t\tif err := safe.WriterModify(ctx, r, item, func(res *runtime.KernelParamDefaultSpec) error {\n\t\t\t\tres.TypedSpec().Value = value\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *KernelParamDefaultsController) getKernelParams() []*kernel.Param {\n\tres := []*kernel.Param{\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.ip_forward\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.icmp_ignore_bogus_error_responses\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.icmp_echo_ignore_broadcasts\",\n\t\t\tValue: \"1\",\n\t\t},\n\t}\n\n\t// block apid and trustd from the ephemeral port range\n\tres = append(res, []*kernel.Param{\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.ip_local_reserved_ports\",\n\t\t\tValue: fmt.Sprintf(\"%d,%d\", constants.ApidPort, constants.TrustdPort),\n\t\t},\n\t}...)\n\n\tif ctrl.V1Alpha1Mode != v1alpha1runtime.ModeContainer {\n\t\tres = append(res, []*kernel.Param{\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.bridge.bridge-nf-call-iptables\",\n\t\t\t\tValue: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.bridge.bridge-nf-call-ip6tables\",\n\t\t\t\tValue: \"1\",\n\t\t\t},\n\t\t}...)\n\t}\n\n\t// Apply IPv6 defaults only if IPv6 is enabled.\n\t// NB: we only prevent the application of these rules if the IPv6 node does not exist.\n\t// Other errors should be ignored here so that they bubble up later, where errors can be logged and handled.\n\t_, err := os.Stat(\"/proc/sys/net/ipv6/conf/default/accept_ra\")\n\tif err == nil || !errors.Is(err, os.ErrNotExist) {\n\t\tres = append(res, []*kernel.Param{\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.ipv6.conf.default.forwarding\",\n\t\t\t\tValue: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.ipv6.conf.default.accept_ra\",\n\t\t\t\tValue: \"2\",\n\t\t\t},\n\t\t}...)\n\t}\n\n\tres = append(res, []*kernel.Param{\n\t\t// ipvs/conntrack tcp keepalive refresh.\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.tcp_keepalive_time\",\n\t\t\tValue: \"600\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.tcp_keepalive_intvl\",\n\t\t\tValue: \"60\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.panic\",\n\t\t\tValue: \"10\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.pid_max\",\n\t\t\tValue: \"262144\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.vm.overcommit_memory\",\n\t\t\tValue: \"1\",\n\t\t},\n\t}...)\n\n\t// kernel optimization for kubernetes workloads.\n\tres = append(res, []*kernel.Param{\n\t\t// configs inotify.\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.inotify.max_user_instances\",\n\t\t\tValue: \"8192\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.aio-max-nr\",\n\t\t\tValue: \"1048576\",\n\t\t},\n\t}...)\n\n\treturn res\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_defaults_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\truntimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype KernelParamDefaultsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc getParams(mode runtime.Mode) []*kernel.Param {\n\tres := []*kernel.Param{\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.ip_forward\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv6.conf.default.forwarding\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv6.conf.default.accept_ra\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.panic\",\n\t\t\tValue: \"10\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.pid_max\",\n\t\t\tValue: \"262144\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.vm.overcommit_memory\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.ipv4.ip_local_reserved_ports\",\n\t\t\tValue: \"50000,50001\",\n\t\t},\n\t}\n\n\tif mode != runtime.ModeContainer {\n\t\tres = append(res, []*kernel.Param{\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.bridge.bridge-nf-call-iptables\",\n\t\t\t\tValue: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.net.bridge.bridge-nf-call-ip6tables\",\n\t\t\t\tValue: \"1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tKey:   \"proc.sys.fs.protected_fifos\",\n\t\t\t\tValue: \"2\",\n\t\t\t},\n\t\t}...)\n\t}\n\n\treturn res\n}\n\n//nolint:dupl\nfunc (suite *KernelParamDefaultsSuite) TestContainerMode() {\n\tcontroller := &runtimecontrollers.KernelParamDefaultsController{\n\t\truntime.ModeContainer,\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(controller))\n\n\tfor _, prop := range getParams(runtime.ModeContainer) {\n\t\tctest.AssertResource(suite, prop.Key, func(param *runtimeresource.KernelParamDefaultSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(prop.Value, param.TypedSpec().Value)\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc (suite *KernelParamDefaultsSuite) TestMetalMode() {\n\tcontroller := &runtimecontrollers.KernelParamDefaultsController{\n\t\truntime.ModeMetal,\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(controller))\n\n\tfor _, prop := range getParams(runtime.ModeMetal) {\n\t\tctest.AssertResource(suite, prop.Key, func(param *runtimeresource.KernelParamDefaultSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(prop.Value, param.TypedSpec().Value)\n\t\t})\n\t}\n}\n\nfunc TestKernelParamDefaultsSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &KernelParamDefaultsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"go.uber.org/zap\"\n\n\tkrnl \"github.com/siderolabs/talos/pkg/kernel\"\n\t\"github.com/siderolabs/talos/pkg/kernel/kspp\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelParamSpecController watches KernelParamSpecs, sets/resets kernel params.\ntype KernelParamSpecController struct {\n\tdefaults map[string]string\n\tstate    map[string]string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KernelParamSpecController) Name() string {\n\treturn \"runtime.KernelParamSpecController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KernelParamSpecController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.KernelParamDefaultSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.KernelParamSpecType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KernelParamSpecController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KernelParamStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KernelParamSpecController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.state == nil {\n\t\tctrl.state = map[string]string{}\n\t}\n\n\tif ctrl.defaults == nil {\n\t\tctrl.defaults = map[string]string{}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tksppParams := map[string]struct{}{}\n\n\t\t\tfor _, param := range kspp.GetKernelParams() {\n\t\t\t\tksppParams[param.Key] = struct{}{}\n\t\t\t}\n\n\t\t\tdefaults, err := r.List(ctx, resource.NewMetadata(runtime.NamespaceName, runtime.KernelParamDefaultSpecType, \"\", resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfigs, err := r.List(ctx, resource.NewMetadata(runtime.NamespaceName, runtime.KernelParamSpecType, \"\", resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfigsCounts := len(configs.Items)\n\n\t\t\tlist := slices.Concat(configs.Items, defaults.Items)\n\n\t\t\ttouchedIDs := map[string]string{}\n\n\t\t\tvar errs *multierror.Error\n\n\t\t\tfor i, item := range list {\n\t\t\t\tspec := item.(runtime.KernelParam).TypedSpec()\n\t\t\t\tid := item.Metadata().ID()\n\n\t\t\t\tif value, duplicate := touchedIDs[id]; i >= configsCounts && duplicate {\n\t\t\t\t\tif _, ok := ksppParams[id]; ok {\n\t\t\t\t\t\tlogger.Warn(\"overriding KSPP enforced parameter, this is not recommended\", zap.String(\"key\", id), zap.String(\"value\", value))\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err = ctrl.updateKernelParam(ctx, r, id, spec.Value); err != nil {\n\t\t\t\t\tif errors.Is(err, os.ErrNotExist) && spec.IgnoreErrors {\n\t\t\t\t\t\tstatus := runtime.NewKernelParamStatus(runtime.NamespaceName, id)\n\n\t\t\t\t\t\tif e := safe.WriterModify(ctx, r, status, func(res *runtime.KernelParamStatus) error {\n\t\t\t\t\t\t\tres.TypedSpec().Unsupported = true\n\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t}); e != nil {\n\t\t\t\t\t\t\terrs = multierror.Append(errs, e)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\terrs = multierror.Append(errs, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ttouchedIDs[id] = spec.Value\n\t\t\t}\n\n\t\t\tfor key := range ctrl.state {\n\t\t\t\tif _, ok := touchedIDs[key]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err = ctrl.resetKernelParam(ctx, r, key); err != nil {\n\t\t\t\t\terrs = multierror.Append(errs, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif errs != nil {\n\t\t\t\treturn errs\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *KernelParamSpecController) updateKernelParam(ctx context.Context, r controller.Runtime, key, value string) error {\n\tprop := &kernel.Param{Key: key, Value: value}\n\n\tif _, ok := ctrl.defaults[key]; !ok {\n\t\tif data, err := krnl.ReadParam(prop); err == nil {\n\t\t\tctrl.defaults[key] = string(data)\n\t\t} else if !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := krnl.WriteParam(prop); err != nil {\n\t\treturn err\n\t}\n\n\tctrl.state[key] = value\n\n\tstatus := runtime.NewKernelParamStatus(runtime.NamespaceName, key)\n\n\treturn safe.WriterModify(ctx, r, status, func(res *runtime.KernelParamStatus) error {\n\t\tres.TypedSpec().Current = value\n\t\tres.TypedSpec().Default = strings.TrimSpace(ctrl.defaults[key])\n\n\t\treturn nil\n\t})\n}\n\nfunc (ctrl *KernelParamSpecController) resetKernelParam(ctx context.Context, r controller.Runtime, key string) error {\n\tvar err error\n\n\tif def, ok := ctrl.defaults[key]; ok {\n\t\terr = krnl.WriteParam(&kernel.Param{Key: key, Value: def})\n\t} else {\n\t\terr = krnl.DeleteParam(&kernel.Param{Key: key})\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdelete(ctrl.defaults, key)\n\tdelete(ctrl.state, key)\n\n\treturn r.Destroy(ctx, resource.NewMetadata(runtime.NamespaceName, runtime.KernelParamStatusType, key, resource.VersionUndefined))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kernel_param_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tkrnl \"github.com/siderolabs/talos/pkg/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\truntimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype KernelParamSpecSuite struct {\n\tRuntimeSuite\n}\n\nfunc (suite *KernelParamSpecSuite) TestParamsSynced() {\n\tsuite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.KernelParamSpecController{}))\n\n\tsuite.startRuntime()\n\n\tvalue := \"500000\"\n\tdef := \"\"\n\n\tspec := runtimeresource.NewKernelParamSpec(runtimeresource.NamespaceName, procSysfsFileMax)\n\tspec.TypedSpec().Value = value\n\n\tparam := &kernel.Param{Key: procSysfsFileMax}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, spec))\n\n\tstatusMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelParamStatusType, procSysfsFileMax, resource.VersionUndefined)\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertResource(\n\t\t\tstatusMD,\n\t\t\tfunc(res resource.Resource) bool {\n\t\t\t\tdef = res.(*runtimeresource.KernelParamStatus).TypedSpec().Default\n\n\t\t\t\treturn res.(*runtimeresource.KernelParamStatus).TypedSpec().Current == value\n\t\t\t},\n\t\t),\n\t))\n\n\tprop, err := krnl.ReadParam(param)\n\tsuite.Assert().NoError(err)\n\tsuite.Require().Equal(value, strings.TrimSpace(string(prop)))\n\n\tsuite.Require().NoError(suite.state.Destroy(suite.ctx, spec.Metadata()))\n\n\t// wait for the resource to be removed\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tfunc() error {\n\t\t\tfor _, md := range []resource.Metadata{statusMD} {\n\t\t\t\t_, err = suite.state.Get(suite.ctx, md)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn retry.ExpectedErrorf(\"resource still exists\")\n\t\t},\n\t))\n\n\tprop, err = krnl.ReadParam(param)\n\tsuite.Assert().NoError(err)\n\tsuite.Require().Equal(def, strings.TrimSpace(string(prop)))\n}\n\nfunc (suite *KernelParamSpecSuite) TestParamsUnsupported() {\n\tsuite.Require().NoError(suite.runtime.RegisterController(&runtimecontrollers.KernelParamSpecController{}))\n\n\tsuite.startRuntime()\n\n\tid := \"proc.sys.some.really.not.existing.sysctl\"\n\n\tspec := runtimeresource.NewKernelParamSpec(runtimeresource.NamespaceName, id)\n\tspec.TypedSpec().Value = \"value\"\n\tspec.TypedSpec().IgnoreErrors = true\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, spec))\n\n\tstatusMD := resource.NewMetadata(runtimeresource.NamespaceName, runtimeresource.KernelParamStatusType, id, resource.VersionUndefined)\n\n\tsuite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\tsuite.assertResource(\n\t\t\tstatusMD,\n\t\t\tfunc(res resource.Resource) bool {\n\t\t\t\treturn res.(*runtimeresource.KernelParamStatus).TypedSpec().Unsupported == true\n\t\t\t},\n\t\t),\n\t))\n}\n\nfunc TestKernelParamSpecSuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test because it requires root privileges\")\n\t}\n\n\tsuite.Run(t, new(KernelParamSpecSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kmsg_log.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\n\tnetworkutils \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/utils\"\n\tmachinedruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nconst (\n\tdrainTimeout    = 100 * time.Millisecond\n\tlogSendTimeout  = 5 * time.Second\n\tlogRetryTimeout = 1 * time.Second\n\tlogCloseTimeout = 5 * time.Second\n)\n\n// KmsgLogDeliveryController watches events and forwards them to the events sink server\n// if it's configured.\ntype KmsgLogDeliveryController struct {\n\tDrainer *machinedruntime.Drainer\n\n\tdrainSub *machinedruntime.DrainSubscription\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KmsgLogDeliveryController) Name() string {\n\treturn \"runtime.KmsgLogDeliveryController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogDeliveryController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogDeliveryController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *KmsgLogDeliveryController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif err := networkutils.WaitForNetworkReady(ctx, r,\n\t\tfunc(status *network.StatusSpec) bool {\n\t\t\treturn status.AddressReady\n\t\t},\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: runtime.NamespaceName,\n\t\t\t\tType:      runtime.KmsgLogConfigType,\n\t\t\t\tID:        optional.Some(runtime.KmsgLogConfigID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for network: %w\", err)\n\t}\n\n\t// initilalize kmsg reader early, so that we don't lose position on config changes\n\treader, err := kmsg.NewReader(kmsg.Follow())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading kernel messages: %w\", err)\n\t}\n\n\tdefer reader.Close() //nolint:errcheck\n\n\tkmsgCh := reader.Scan(ctx)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*runtime.KmsgLogConfig](ctx, r, runtime.KmsgLogConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting configuration: %w\", err)\n\t\t}\n\n\t\tif cfg == nil {\n\t\t\t// no config, wait for the next event\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = ctrl.deliverLogs(ctx, r, logger, kmsgCh, cfg.TypedSpec().Destinations); err != nil {\n\t\t\treturn fmt.Errorf(\"error delivering logs: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\ntype logConfig struct {\n\tendpoint *url.URL\n}\n\nfunc (c logConfig) Format() string {\n\treturn constants.LoggingFormatJSONLines\n}\n\nfunc (c logConfig) Endpoint() *url.URL {\n\treturn c.endpoint\n}\n\nfunc (c logConfig) ExtraTags() map[string]string {\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (ctrl *KmsgLogDeliveryController) deliverLogs(ctx context.Context, r controller.Runtime, logger *zap.Logger, kmsgCh <-chan kmsg.Packet, destURLs []*url.URL) error {\n\tif ctrl.drainSub == nil {\n\t\tctrl.drainSub = ctrl.Drainer.Subscribe()\n\t}\n\n\t// initialize all log senders\n\tdestLogConfigs := xslices.Map(destURLs, func(u *url.URL) config.LoggingDestination {\n\t\treturn logConfig{endpoint: u}\n\t})\n\tsenders := xslices.Map(destLogConfigs, logging.NewJSONLines)\n\n\tdefer func() {\n\t\tcloseCtx, closeCtxCancel := context.WithTimeout(context.Background(), logCloseTimeout)\n\t\tdefer closeCtxCancel()\n\n\t\tfor _, sender := range senders {\n\t\t\tif err := sender.Close(closeCtx); err != nil {\n\t\t\t\tlogger.Error(\"error closing log sender\", zap.Error(err))\n\t\t\t}\n\t\t}\n\t}()\n\n\tvar (\n\t\tdrainTimer   *time.Timer\n\t\tdrainTimerCh <-chan time.Time\n\t)\n\n\tfor {\n\t\tvar msg kmsg.Packet\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tctrl.drainSub.Cancel()\n\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\t// config changed, restart the loop\n\t\t\treturn nil\n\t\tcase <-ctrl.drainSub.EventCh():\n\t\t\t// drain started, assume that ksmg is drained if there're no new messages in drainTimeout\n\t\t\tdrainTimer = time.NewTimer(drainTimeout)\n\t\t\tdrainTimerCh = drainTimer.C\n\n\t\t\tcontinue\n\t\tcase <-drainTimerCh:\n\t\t\tctrl.drainSub.Cancel()\n\n\t\t\treturn nil\n\t\tcase msg = <-kmsgCh:\n\t\t\tif drainTimer != nil {\n\t\t\t\t// if draining, reset the timer as there's a new message\n\t\t\t\tif !drainTimer.Stop() {\n\t\t\t\t\t<-drainTimer.C\n\t\t\t\t}\n\n\t\t\t\tdrainTimer.Reset(drainTimeout)\n\t\t\t}\n\t\t}\n\n\t\tif msg.Err != nil {\n\t\t\treturn fmt.Errorf(\"error receiving kernel logs: %w\", msg.Err)\n\t\t}\n\n\t\tevent := machinedruntime.LogEvent{\n\t\t\tMsg:   msg.Message.Message,\n\t\t\tTime:  msg.Message.Timestamp,\n\t\t\tLevel: kmsgPriorityToLevel(msg.Message.Priority),\n\t\t\tFields: map[string]any{\n\t\t\t\t\"facility\": msg.Message.Facility.String(),\n\t\t\t\t\"seq\":      msg.Message.SequenceNumber,\n\t\t\t\t\"clock\":    msg.Message.Clock,\n\t\t\t\t\"priority\": msg.Message.Priority.String(),\n\t\t\t},\n\t\t}\n\n\t\tif err := ctrl.resend(ctx, r, logger, senders, &event); err != nil {\n\t\t\treturn fmt.Errorf(\"error sending log event: %w\", err)\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *KmsgLogDeliveryController) resend(ctx context.Context, r controller.Runtime, logger *zap.Logger, senders []machinedruntime.LogSender, e *machinedruntime.LogEvent) error {\n\tfor {\n\t\tsendCtx, sendCancel := context.WithTimeout(ctx, logSendTimeout)\n\t\tsendErrors := make(chan error, len(senders))\n\n\t\tfor _, sender := range senders {\n\t\t\tgo func() {\n\t\t\t\tsendErrors <- sender.Send(sendCtx, e)\n\t\t\t}()\n\t\t}\n\n\t\tvar dontRetry bool\n\n\t\tfor range senders {\n\t\t\terr := <-sendErrors\n\n\t\t\t// don't retry if at least one sender succeed to avoid implementing per-sender queue, etc\n\t\t\tif err == nil {\n\t\t\t\tdontRetry = true\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlogger.Debug(\"error sending log event\", zap.Error(err))\n\n\t\t\tif errors.Is(err, machinedruntime.ErrDontRetry) || errors.Is(err, context.Canceled) {\n\t\t\t\tdontRetry = true\n\t\t\t}\n\t\t}\n\n\t\tsendCancel()\n\n\t\tif dontRetry {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\t// config changed, restart the loop\n\t\t\treturn errors.New(\"config changed\")\n\t\tcase <-time.After(logRetryTimeout):\n\t\t}\n\t}\n}\n\nfunc kmsgPriorityToLevel(pri kmsg.Priority) zapcore.Level {\n\tswitch pri {\n\tcase kmsg.Alert, kmsg.Crit, kmsg.Emerg, kmsg.Err:\n\t\treturn zapcore.ErrorLevel\n\tcase kmsg.Debug:\n\t\treturn zapcore.DebugLevel\n\tcase kmsg.Info, kmsg.Notice:\n\t\treturn zapcore.InfoLevel\n\tcase kmsg.Warning:\n\t\treturn zapcore.WarnLevel\n\tdefault:\n\t\treturn zapcore.ErrorLevel\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kmsg_log_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KmsgLogConfigController generates configuration for kmsg log delivery.\ntype KmsgLogConfigController struct {\n\tCmdline *procfs.Cmdline\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KmsgLogConfigController) Name() string {\n\treturn \"runtime.KmsgLogConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.KmsgLogConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KmsgLogConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) (err error) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tvar destinations []*url.URL\n\n\t\tif ctrl.Cmdline != nil {\n\t\t\tif val := ctrl.Cmdline.Get(constants.KernelParamLoggingKernel).First(); val != nil {\n\t\t\t\tdestURL, err := url.Parse(*val)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error parsing %q: %w\", constants.KernelParamLoggingKernel, err)\n\t\t\t\t}\n\n\t\t\t\tdestinations = append(destinations, destURL)\n\t\t\t}\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tif cfg != nil {\n\t\t\t// remove duplicate URLs in case same destination is specified in both machine config and kernel args\n\t\t\tdestinations = append(destinations, xslices.Filter(cfg.Config().Runtime().KmsgLogURLs(),\n\t\t\t\tfunc(u *url.URL) bool {\n\t\t\t\t\treturn !slices.ContainsFunc(destinations, func(v *url.URL) bool {\n\t\t\t\t\t\treturn v.String() == u.String()\n\t\t\t\t\t})\n\t\t\t\t})...)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif len(destinations) > 0 {\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewKmsgLogConfig(), func(cfg *runtime.KmsgLogConfig) error {\n\t\t\t\tcfg.TypedSpec().Destinations = destinations\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating kmsg log config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.KmsgLogConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kmsg_log_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\truntimecfg \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype KmsgLogConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestKmsgLogConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(KmsgLogConfigSuite))\n}\n\nfunc (suite *KmsgLogConfigSuite) TestKmsgLogConfigNone() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.KmsgLogConfigController{}))\n\n\trtestutils.AssertNoResource[*runtime.KmsgLogConfig](suite.Ctx(), suite.T(), suite.State(), runtime.KmsgLogConfigID)\n}\n\nfunc (suite *KmsgLogConfigSuite) TestKmsgLogConfigMachineConfig() {\n\tcmdline := procfs.NewCmdline(\"\")\n\tcmdline.Append(constants.KernelParamLoggingKernel, \"https://10.0.0.1:3333/logs\")\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.KmsgLogConfigController{\n\t\tCmdline: cmdline,\n\t}))\n\n\tkmsgLogConfig1 := &runtimecfg.KmsgLogV1Alpha1{\n\t\tMetaName: \"1\",\n\t\tKmsgLogURL: meta.URL{\n\t\t\tURL: must(url.Parse(\"https://10.0.0.2:4444/logs\")),\n\t\t},\n\t}\n\n\tkmsgLogConfig2 := &runtimecfg.KmsgLogV1Alpha1{\n\t\tMetaName: \"2\",\n\t\tKmsgLogURL: meta.URL{\n\t\t\tURL: must(url.Parse(\"https://10.0.0.1:3333/logs\")),\n\t\t},\n\t}\n\n\tcfg, err := container.New(kmsgLogConfig1, kmsgLogConfig2)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources[*runtime.KmsgLogConfig](suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.KmsgLogConfigID},\n\t\tfunc(cfg *runtime.KmsgLogConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]string{\n\t\t\t\t\t\"https://10.0.0.1:3333/logs\",\n\t\t\t\t\t\"https://10.0.0.2:4444/logs\",\n\t\t\t\t},\n\t\t\t\txslices.Map(cfg.TypedSpec().Destinations, func(u *url.URL) string { return u.String() }),\n\t\t\t)\n\t\t})\n}\n\nfunc (suite *KmsgLogConfigSuite) TestKmsgLogConfigCmdline() {\n\tcmdline := procfs.NewCmdline(\"\")\n\tcmdline.Append(constants.KernelParamLoggingKernel, \"https://10.0.0.1:3333/logs\")\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.KmsgLogConfigController{\n\t\tCmdline: cmdline,\n\t}))\n\n\trtestutils.AssertResources[*runtime.KmsgLogConfig](suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.KmsgLogConfigID},\n\t\tfunc(cfg *runtime.KmsgLogConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t[]string{\"https://10.0.0.1:3333/logs\"},\n\t\t\t\txslices.Map(cfg.TypedSpec().Destinations, func(u *url.URL) string { return u.String() }),\n\t\t\t)\n\t\t})\n}\n\nfunc must[T any](t T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn t\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kmsg_log_storage.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// KmsgLogStorageController presents kernel message log as a 'kernel' log.\ntype KmsgLogStorageController struct {\n\tV1Alpha1Logging runtime.LoggingManager\n\tV1Alpha1Mode    runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KmsgLogStorageController) Name() string {\n\treturn \"runtime.KmsgLogStorageController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogStorageController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KmsgLogStorageController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KmsgLogStorageController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode.InContainer() {\n\t\treturn nil\n\t}\n\n\tvar err error\n\n\tlogWriter, err := ctrl.V1Alpha1Logging.ServiceLog(\"kernel\").Writer()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening logger: %w\", err)\n\t}\n\tdefer logWriter.Close() //nolint:errcheck\n\n\t// initilalize kmsg reader early, so that we don't lose position on config changes\n\treader, err := kmsg.NewReader(kmsg.Follow())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading kernel messages: %w\", err)\n\t}\n\n\tdefer reader.Close() //nolint:errcheck\n\n\tkmsgCh := reader.Scan(ctx)\n\n\t// wait for the initial event to start processing messages\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tfor {\n\t\tvar msg kmsg.Packet\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase msg = <-kmsgCh:\n\t\t}\n\n\t\tif msg.Err != nil {\n\t\t\treturn fmt.Errorf(\"error receiving kernel logs: %w\", msg.Err)\n\t\t}\n\n\t\tif _, err = logWriter.Write(\n\t\t\tfmt.Appendf(nil, \"%s: %7s: [%s]: %s\", msg.Message.Facility, msg.Message.Priority, msg.Message.Timestamp.Format(time.RFC3339Nano), msg.Message.Message),\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/kmsg_log_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/siderolabs/siderolink/pkg/logreceiver\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap/zaptest\"\n\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\ttalosruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype logHandler struct {\n\tmu    sync.Mutex\n\tcount int\n}\n\n// HandleLog implements logreceiver.Handler.\nfunc (s *logHandler) HandleLog(srcAddr netip.Addr, msg map[string]any) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\ts.count++\n}\n\nfunc (s *logHandler) getCount() int {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\treturn s.count\n}\n\ntype KmsgLogDeliverySuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\tdrainer *talosruntime.Drainer\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\thandler1, handler2 *logHandler\n\n\tlistener1, listener2 net.Listener\n\tsrv1, srv2           *logreceiver.Server\n}\n\nfunc (suite *KmsgLogDeliverySuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Second)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tlogger := zaptest.NewLogger(suite.T())\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, logger)\n\tsuite.Require().NoError(err)\n\n\tsuite.handler1 = &logHandler{}\n\tsuite.handler2 = &logHandler{}\n\n\tsuite.listener1, err = (&net.ListenConfig{}).Listen(suite.ctx, \"tcp\", \"localhost:0\")\n\tsuite.Require().NoError(err)\n\n\tsuite.listener2, err = (&net.ListenConfig{}).Listen(suite.ctx, \"tcp\", \"localhost:0\")\n\tsuite.Require().NoError(err)\n\n\tsuite.srv1 = logreceiver.NewServer(logger, suite.listener1, suite.handler1.HandleLog)\n\n\tsuite.srv2 = logreceiver.NewServer(logger, suite.listener2, suite.handler2.HandleLog)\n\n\tsuite.wg.Go(func() {\n\t\tsuite.srv1.Serve() //nolint:errcheck\n\t})\n\n\tsuite.wg.Go(func() {\n\t\tsuite.srv2.Serve() //nolint:errcheck\n\t})\n\n\tsuite.drainer = talosruntime.NewDrainer()\n\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&runtimectrl.KmsgLogDeliveryController{\n\t\t\t\tDrainer: suite.drainer,\n\t\t\t},\n\t\t),\n\t)\n\n\tstatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tstatus.TypedSpec().AddressReady = true\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, status))\n}\n\nfunc (suite *KmsgLogDeliverySuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *KmsgLogDeliverySuite) TestDeliverySingleDestination() {\n\tsuite.startRuntime()\n\n\tkmsgLogConfig := runtimeres.NewKmsgLogConfig()\n\tkmsgLogConfig.TypedSpec().Destinations = []*url.URL{\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener1.Addr().String(),\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, kmsgLogConfig))\n\n\t// controller should deliver some kernel logs from host's kmsg buffer\n\tsuite.assertLogsSeen(suite.handler1)\n}\n\nfunc (suite *KmsgLogDeliverySuite) TestDeliveryMultipleDestinations() {\n\tsuite.startRuntime()\n\n\tkmsgLogConfig := runtimeres.NewKmsgLogConfig()\n\tkmsgLogConfig.TypedSpec().Destinations = []*url.URL{\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener1.Addr().String(),\n\t\t},\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener2.Addr().String(),\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, kmsgLogConfig))\n\n\t// controller should deliver logs to both destinations\n\tsuite.assertLogsSeen(suite.handler1)\n\tsuite.assertLogsSeen(suite.handler2)\n}\n\nfunc (suite *KmsgLogDeliverySuite) TestDeliveryOneDeadDestination() {\n\tsuite.startRuntime()\n\n\t// stop one listener\n\tsuite.Require().NoError(suite.listener1.Close())\n\n\tkmsgLogConfig := runtimeres.NewKmsgLogConfig()\n\tkmsgLogConfig.TypedSpec().Destinations = []*url.URL{\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener1.Addr().String(),\n\t\t},\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener2.Addr().String(),\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, kmsgLogConfig))\n\n\t// controller should deliver logs to live destination\n\tsuite.assertLogsSeen(suite.handler2)\n}\n\nfunc (suite *KmsgLogDeliverySuite) TestDeliveryAllDeadDestinations() {\n\tsuite.startRuntime()\n\n\t// stop all listeners\n\tsuite.Require().NoError(suite.listener1.Close())\n\tsuite.Require().NoError(suite.listener2.Close())\n\n\tkmsgLogConfig := runtimeres.NewKmsgLogConfig()\n\tkmsgLogConfig.TypedSpec().Destinations = []*url.URL{\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener1.Addr().String(),\n\t\t},\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener2.Addr().String(),\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, kmsgLogConfig))\n}\n\nfunc (suite *KmsgLogDeliverySuite) TestDrain() {\n\tsuite.startRuntime()\n\n\tkmsgLogConfig := runtimeres.NewKmsgLogConfig()\n\tkmsgLogConfig.TypedSpec().Destinations = []*url.URL{\n\t\t{\n\t\t\tScheme: \"tcp\",\n\t\t\tHost:   suite.listener1.Addr().String(),\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, kmsgLogConfig))\n\n\t// wait for controller to start delivering some logs\n\tsuite.assertLogsSeen(suite.handler1)\n\n\t// drain should be successful, i.e. controller should stop on its own before context is canceled\n\tsuite.Assert().NoError(suite.drainer.Drain(suite.ctx))\n}\n\nfunc (suite *KmsgLogDeliverySuite) assertLogsSeen(handler *logHandler) {\n\terr := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(\n\t\tfunc() error {\n\t\t\tif handler.getCount() == 0 {\n\t\t\t\treturn retry.ExpectedErrorf(\"no logs received\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *KmsgLogDeliverySuite) TearDownTest() {\n\tsuite.srv1.Stop()\n\tsuite.srv2.Stop()\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc TestKmsgLogDeliverySuite(t *testing.T) {\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"requires root\")\n\t}\n\n\tsuite.Run(t, new(KmsgLogDeliverySuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/loaded_kernel_module.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/filehash\"\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// LoadedKernelModuleController presents /proc/modules as a resource.\ntype LoadedKernelModuleController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LoadedKernelModuleController) Name() string {\n\treturn \"runtime.LoadedKernelModuleController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LoadedKernelModuleController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LoadedKernelModuleController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.LoadedKernelModuleType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *LoadedKernelModuleController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode.InContainer() {\n\t\t// no modules in containers\n\t\treturn nil\n\t}\n\n\twatcher, err := filehash.NewWatcher(\"/proc/modules\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating filehash watcher: %w\", err)\n\t}\n\n\tnotifyCh, notifyErrCh := watcher.Run()\n\n\tdefer watcher.Close() //nolint:errcheck\n\n\tfor {\n\t\tselect {\n\t\tcase updatedPath := <-notifyCh:\n\t\t\tif err := ctrl.reconcile(ctx, r, updatedPath); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reconciling LoadedKernelModule resources: %w\", err)\n\t\t\t}\n\t\tcase err = <-notifyErrCh:\n\t\t\treturn fmt.Errorf(\"error watching /proc/modules: %w\", err)\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\t}\n}\n\n// Module represents a kernel module parsed from /proc/modules.\ntype Module struct {\n\tName           string\n\tSize           int\n\tReferenceCount int\n\tDependencies   []string\n\tState          string\n\tAddress        string\n}\n\n// ParseModules parses the contents of /proc/modules from the given reader\n// and returns a slice of module structs representing each loaded kernel module.\nfunc ParseModules(r io.Reader) ([]Module, error) {\n\tvar modules []Module\n\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\t\tif len(fields) < 6 {\n\t\t\tcontinue // malformed line\n\t\t}\n\n\t\tname := fields[0]\n\n\t\tsize, err := strconv.Atoi(fields[1])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid size for module %s: %v\", name, err)\n\t\t}\n\n\t\trefCount, err := strconv.Atoi(fields[2])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid instance count for module %s: %v\", name, err)\n\t\t}\n\n\t\tdeps := []string{}\n\t\tif fields[3] != \"-\" {\n\t\t\tdeps = slices.DeleteFunc(\n\t\t\t\tstrings.Split(fields[3], \",\"),\n\t\t\t\tfunc(s string) bool { return s == \"\" },\n\t\t\t)\n\t\t}\n\n\t\tmodules = append(modules, Module{\n\t\t\tName:           name,\n\t\t\tSize:           size,\n\t\t\tDependencies:   deps,\n\t\t\tReferenceCount: refCount,\n\t\t\tState:          fields[4],\n\t\t\tAddress:        fields[5],\n\t\t})\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"error scanning modules: %w\", err)\n\t}\n\n\treturn modules, nil\n}\n\nfunc (ctrl *LoadedKernelModuleController) reconcile(ctx context.Context, r controller.Runtime, path string) error {\n\tr.StartTrackingOutputs()\n\n\tf, err := os.OpenFile(path, os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening %s: %w\", path, err)\n\t}\n\n\trawModules, err := ParseModules(f)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing modules from %s: %w\", path, err)\n\t}\n\n\t// create a map to track which modules were touched\n\tfor _, module := range rawModules {\n\t\tif err := safe.WriterModify(ctx, r,\n\t\t\truntime.NewLoadedKernelModule(runtime.NamespaceName, module.Name),\n\t\t\tfunc(res *runtime.LoadedKernelModule) error {\n\t\t\t\tres.TypedSpec().Size = module.Size\n\t\t\t\tres.TypedSpec().ReferenceCount = module.ReferenceCount\n\t\t\t\tres.TypedSpec().Dependencies = module.Dependencies\n\t\t\t\tres.TypedSpec().State = module.State\n\t\t\t\tres.TypedSpec().Address = module.Address\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating LoadedKernelModule resource: %w\", err)\n\t\t}\n\t}\n\n\treturn safe.CleanupOutputs[*runtime.LoadedKernelModule](ctx, r)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/loaded_kernel_module_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n)\n\nfunc TestLoadedKernelModuleSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &LoadedKernelModuleSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.LoadedKernelModuleController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype LoadedKernelModuleSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *LoadedKernelModuleSuite) TestParseModules() {\n\tfor _, tc := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected []runtimectrl.Module\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tinput:    \"\",\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"single module\",\n\t\t\tinput: `module1 12345 0 - Live 0x00000000`,\n\t\t\texpected: []runtimectrl.Module{\n\t\t\t\t{Name: \"module1\", Size: 12345, ReferenceCount: 0, Dependencies: []string{}, State: \"Live\", Address: \"0x00000000\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple modules\",\n\t\t\tinput: `module1 12345 0 - Live 0x00000000\nmodule2 67890 1 module1 Live 0x00000001\nmodule3 54321 2 module1,module2 Live 0x00000002`,\n\t\t\texpected: []runtimectrl.Module{\n\t\t\t\t{Name: \"module1\", Size: 12345, ReferenceCount: 0, Dependencies: []string{}, State: \"Live\", Address: \"0x00000000\"},\n\t\t\t\t{Name: \"module2\", Size: 67890, ReferenceCount: 1, Dependencies: []string{\"module1\"}, State: \"Live\", Address: \"0x00000001\"},\n\t\t\t\t{Name: \"module3\", Size: 54321, ReferenceCount: 2, Dependencies: []string{\"module1\", \"module2\"}, State: \"Live\", Address: \"0x00000002\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"malformed lines\",\n\t\t\tinput: `module1 12345 0 - Live 0x00000000\nmodule2 67890 1 module1 Live 0x00000001\nmodule3 54321 2 module1,module2 Live 0x00000002\ninvalid_line\nmodule4 11111 0 - Live 0x00000003`,\n\t\t\texpected: []runtimectrl.Module{\n\t\t\t\t{Name: \"module1\", Size: 12345, ReferenceCount: 0, Dependencies: []string{}, State: \"Live\", Address: \"0x00000000\"},\n\t\t\t\t{Name: \"module2\", Size: 67890, ReferenceCount: 1, Dependencies: []string{\"module1\"}, State: \"Live\", Address: \"0x00000001\"},\n\t\t\t\t{Name: \"module3\", Size: 54321, ReferenceCount: 2, Dependencies: []string{\"module1\", \"module2\"}, State: \"Live\", Address: \"0x00000002\"},\n\t\t\t\t{Name: \"module4\", Size: 11111, ReferenceCount: 0, Dependencies: []string{}, State: \"Live\", Address: \"0x00000003\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.Run(tc.name, func() {\n\t\t\tmodules, err := runtimectrl.ParseModules(strings.NewReader(tc.input))\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Require().Equal(tc.expected, modules)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/log_persistence.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/concurrent\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/logfile\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// LogPersistenceController is a controller that persists logs in files.\ntype LogPersistenceController struct {\n\tV1Alpha1Logging runtime.LoggingManager\n\n\tstartup sync.Once\n\t// RLocked by the log writers, Locked by volume handlers\n\tcanLog        sync.RWMutex\n\tfiles         *concurrent.HashTrieMap[string, *logfile.LogFile]\n\tlogMountPoint string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *LogPersistenceController) Name() string {\n\treturn \"runtime.LogPersistenceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *LogPersistenceController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *LogPersistenceController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// WriteLog writes a single log line into the corresponding file.\nfunc (ctrl *LogPersistenceController) WriteLog(id string, line []byte) error {\n\tctrl.canLog.RLock()\n\tdefer ctrl.canLog.RUnlock()\n\n\tlf, _ := ctrl.files.LoadOrStore(\n\t\tid,\n\t\tlogfile.NewLogFile(\n\t\t\tfilepath.Join(ctrl.logMountPoint, id+\".log\"),\n\t\t\tconstants.LogRotateThreshold,\n\t\t),\n\t)\n\n\treturn lf.Write(line)\n}\n\nfunc (ctrl *LogPersistenceController) startLogging(vms *block.VolumeMountStatus) {\n\t// here we can start logging activities\n\tctrl.logMountPoint = vms.TypedSpec().Target\n\n\tctrl.canLog.Unlock()\n}\n\nfunc (ctrl *LogPersistenceController) stopLogging() error {\n\t// Stop all logging activities, close files\n\t// after this call we should not hold /var/log\n\tctrl.canLog.Lock()\n\n\tfor _, f := range ctrl.files.All() {\n\t\tif err := f.Close(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to close log buffer %w\", err)\n\t\t}\n\t}\n\n\tctrl.files.Clear()\n\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *LogPersistenceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tctrl.startup.Do(func() {\n\t\tctrl.files = concurrent.NewHashTrieMap[string, *logfile.LogFile]()\n\t\t// Block writes until /var/log is ready\n\t\tctrl.canLog.Lock()\n\n\t\tctrl.V1Alpha1Logging.SetLineWriter(ctrl)\n\t})\n\n\tticker := time.NewTicker(constants.LogFlushPeriod)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\t\tfor _, f := range ctrl.files.All() {\n\t\t\t\tif err := f.Flush(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to flush log buffer %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontinue\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\trequestID := ctrl.Name() + \"-\" + constants.LogMountPoint\n\n\t\t// create a volume mount request for the logs volume mount point\n\t\t// to keep it alive and prevent it from being torn down\n\t\tif err := safe.WriterModify(ctx, r,\n\t\t\tblock.NewVolumeMountRequest(block.NamespaceName, requestID),\n\t\t\tfunc(v *block.VolumeMountRequest) error {\n\t\t\t\tv.TypedSpec().Requester = ctrl.Name()\n\t\t\t\tv.TypedSpec().VolumeID = constants.LogMountPoint\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating volume mount request for user volume mount point: %w\", err)\n\t\t}\n\n\t\tvms, err := safe.ReaderGetByID[*block.VolumeMountStatus](ctx, r, requestID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t// volume mount not ready yet, wait more\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting volume mount status for log volume: %w\", err)\n\t\t}\n\n\t\tswitch vms.Metadata().Phase() {\n\t\tcase resource.PhaseRunning:\n\t\t\tif !vms.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\tif err = r.AddFinalizer(ctx, vms.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error adding finalizer to volume mount status for log volume: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tctrl.startLogging(vms)\n\t\t\t}\n\t\tcase resource.PhaseTearingDown:\n\t\t\tif vms.Metadata().Finalizers().Has(ctrl.Name()) {\n\t\t\t\tif err = ctrl.stopLogging(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error stopping persistent logging: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = r.RemoveFinalizer(ctx, vms.Metadata(), ctrl.Name()); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error removing finalizer from volume mount status for log volume: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/log_persistence_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestLogPersistenceSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &LogPersistenceSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t},\n\t})\n}\n\ntype LogPersistenceSuite struct {\n\tctest.DefaultSuite\n}\n\ntype loggingMock struct{}\n\nfunc (loggingMock) ServiceLog(service string) runtime.LogHandler { return nil }\n\nfunc (loggingMock) SetSenders(senders []runtime.LogSender) []runtime.LogSender { return nil }\n\nfunc (loggingMock) SetLineWriter(w runtime.LogWriter) {}\n\nfunc (loggingMock) RegisteredLogs() []string { return nil }\n\nfunc (suite *LogPersistenceSuite) TestDefault() {\n\tctrl := &runtimectrl.LogPersistenceController{\n\t\tV1Alpha1Logging: loggingMock{},\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(ctrl))\n\n\trequestID := ctrl.Name() + \"-\" + constants.LogMountPoint\n\n\tctest.AssertResource(suite, requestID, func(*block.VolumeMountRequest, *assert.Assertions) {})\n\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\terrCh <- ctrl.WriteLog(\"service1\", []byte(\"line1\"))\n\t}()\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Fail(\"expected WriteLog to block\")\n\tcase <-time.After(10 * time.Millisecond):\n\t\t// expected\n\t}\n\n\tlogDir := suite.T().TempDir()\n\n\tvms := block.NewVolumeMountStatus(block.NamespaceName, requestID)\n\tvms.TypedSpec().Target = logDir\n\tsuite.Create(vms)\n\n\tctest.AssertResource(suite, requestID, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Has(ctrl.Name()))\n\t})\n\n\tselect {\n\tcase err := <-errCh:\n\t\tsuite.NoError(err)\n\tcase <-time.After(500 * time.Millisecond):\n\t\tsuite.Fail(\"expected WriteLog to complete after mount\")\n\t}\n\n\tsuite.Assert().FileExists(filepath.Join(logDir, \"service1.log\"))\n\n\t_, err := suite.State().Teardown(suite.Ctx(), vms.Metadata())\n\tsuite.Require().NoError(err)\n\n\tctest.AssertResource(suite, requestID, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.False(vms.Metadata().Finalizers().Has(ctrl.Name()))\n\t})\n\n\tst, err := os.Stat(filepath.Join(logDir, \"service1.log\"))\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(int64(6), st.Size())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/machine_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\tk8sadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/k8s\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// MachineStatusController watches MachineStatuss, sets/resets kernel params.\ntype MachineStatusController struct {\n\tV1Alpha1Events v1alpha1runtime.Watcher\n\n\tsetupOnce  sync.Once\n\tnotifyOnce sync.Once\n\n\tnotifyCh chan struct{}\n\n\tmu           sync.Mutex\n\tcurrentStage runtime.MachineStage\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MachineStatusController) Name() string {\n\treturn \"runtime.MachineStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MachineStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      time.StatusType,\n\t\t\tID:        optional.Some(time.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.StaticPodStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodenameType,\n\t\t\tID:        optional.Some(k8s.NodenameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: k8s.NamespaceName,\n\t\t\tType:      k8s.NodeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MachineStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.MachineStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *MachineStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tctrl.setupOnce.Do(func() {\n\t\t// watcher is started once and runs for all controller runs, as if we reconnect to the event stream,\n\t\t// we might lose some state which was in the events, but it got \"scrolled away\" from the buffer.\n\t\tctrl.notifyCh = make(chan struct{}, 1)\n\t\tgo ctrl.watchEvents()\n\t})\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ctrl.notifyCh:\n\t\t}\n\n\t\tmachineTypeResource, err := safe.ReaderGet[*config.MachineType](ctx, r, config.NewMachineType().Metadata())\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar machineType machine.Type\n\n\t\tif machineTypeResource != nil {\n\t\t\tmachineType = machineTypeResource.MachineType()\n\t\t}\n\n\t\tctrl.mu.Lock()\n\t\tcurrentStage := ctrl.currentStage\n\t\tctrl.mu.Unlock()\n\n\t\tready := true\n\n\t\tvar unmetConditions []runtime.UnmetCondition\n\n\t\tfor _, check := range ctrl.getReadinessChecks(currentStage, machineType) {\n\t\t\tif err := check.f(ctx, r); err != nil {\n\t\t\t\tready = false\n\n\t\t\t\tunmetConditions = append(unmetConditions, runtime.UnmetCondition{\n\t\t\t\t\tName:   check.name,\n\t\t\t\t\tReason: err.Error(),\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, runtime.NewMachineStatus(), func(ms *runtime.MachineStatus) error {\n\t\t\tms.TypedSpec().Stage = currentStage\n\t\t\tms.TypedSpec().Status.Ready = ready\n\t\t\tms.TypedSpec().Status.UnmetConditions = unmetConditions\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating machine status: %w\", err)\n\t\t}\n\n\t\tif currentStage == runtime.MachineStageRunning && ready {\n\t\t\tctrl.notifyOnce.Do(func() {\n\t\t\t\tlogger.Info(\"machine is running and ready\")\n\t\t\t})\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\ntype readinessCheck struct {\n\tname string\n\tf    func(context.Context, controller.Runtime) error\n}\n\nfunc (ctrl *MachineStatusController) getReadinessChecks(stage runtime.MachineStage, machineType machine.Type) []readinessCheck {\n\trequiredServices := []string{\n\t\t\"apid\",\n\t\t\"machined\",\n\t\t\"kubelet\",\n\t}\n\n\tif machineType.IsControlPlane() {\n\t\trequiredServices = append(requiredServices,\n\t\t\t\"etcd\",\n\t\t\t\"trustd\",\n\t\t)\n\t}\n\n\tswitch stage { //nolint:exhaustive\n\tcase runtime.MachineStageBooting, runtime.MachineStageRunning:\n\t\treturn []readinessCheck{\n\t\t\t{\n\t\t\t\tname: \"time\",\n\t\t\t\tf:    ctrl.timeSyncCheck,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"network\",\n\t\t\t\tf:    ctrl.networkReadyCheck,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"services\",\n\t\t\t\tf:    ctrl.servicesCheck(requiredServices),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"staticPods\",\n\t\t\t\tf:    ctrl.staticPodsCheck,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"nodeReady\",\n\t\t\t\tf:    ctrl.nodeReadyCheck,\n\t\t\t},\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc (ctrl *MachineStatusController) timeSyncCheck(ctx context.Context, r controller.Runtime) error {\n\ttimeSyncStatus, err := safe.ReaderGet[*time.Status](ctx, r, time.NewStatus().Metadata())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !timeSyncStatus.TypedSpec().Synced {\n\t\treturn errors.New(\"time is not synced\")\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *MachineStatusController) networkReadyCheck(ctx context.Context, r controller.Runtime) error {\n\tnetworkStatus, err := safe.ReaderGet[*network.Status](ctx, r, network.NewStatus(network.NamespaceName, network.StatusID).Metadata())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar notReady []string\n\n\tif !networkStatus.TypedSpec().AddressReady {\n\t\tnotReady = append(notReady, \"address\")\n\t}\n\n\tif !networkStatus.TypedSpec().ConnectivityReady {\n\t\tnotReady = append(notReady, \"connectivity\")\n\t}\n\n\tif !networkStatus.TypedSpec().EtcFilesReady {\n\t\tnotReady = append(notReady, \"etc-files\")\n\t}\n\n\tif !networkStatus.TypedSpec().HostnameReady {\n\t\tnotReady = append(notReady, \"hostname\")\n\t}\n\n\tif len(notReady) == 0 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"waiting on: %s\", strings.Join(notReady, \", \"))\n}\n\nfunc (ctrl *MachineStatusController) servicesCheck(requiredServices []string) func(ctx context.Context, r controller.Runtime) error {\n\treturn func(ctx context.Context, r controller.Runtime) error {\n\t\tserviceList, err := safe.ReaderListAll[*v1alpha1.Service](ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar problems []string\n\n\t\trunningServices := map[string]struct{}{}\n\n\t\tfor service := range serviceList.All() {\n\t\t\tif !service.TypedSpec().Running {\n\t\t\t\tproblems = append(problems, fmt.Sprintf(\"%s not running\", service.Metadata().ID()))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\trunningServices[service.Metadata().ID()] = struct{}{}\n\n\t\t\tif !service.TypedSpec().Unknown && !service.TypedSpec().Healthy {\n\t\t\t\tproblems = append(problems, fmt.Sprintf(\"%s not healthy\", service.Metadata().ID()))\n\t\t\t}\n\t\t}\n\n\t\tfor _, svc := range requiredServices {\n\t\t\tif _, running := runningServices[svc]; !running {\n\t\t\t\tproblems = append(problems, fmt.Sprintf(\"%s not running\", svc))\n\t\t\t}\n\t\t}\n\n\t\tif len(problems) == 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"%s\", strings.Join(problems, \", \"))\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *MachineStatusController) staticPodsCheck(ctx context.Context, r controller.Runtime) error {\n\tstaticPodList, err := safe.ReaderListAll[*k8s.StaticPodStatus](ctx, r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar problems []string\n\n\tfor staticPod := range staticPodList.All() {\n\t\tstatus, err := k8sadapter.StaticPodStatus(staticPod).Status()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch status.Phase {\n\t\tcase v1.PodPending, v1.PodFailed, v1.PodUnknown:\n\t\t\tproblems = append(problems, fmt.Sprintf(\"%s %s\", staticPod.Metadata().ID(), strings.ToLower(string(status.Phase))))\n\t\tcase v1.PodSucceeded:\n\t\t\t// do nothing, terminal phase\n\t\tcase v1.PodRunning:\n\t\t\t// check readiness\n\t\t\tready := false\n\n\t\t\tfor _, condition := range status.Conditions {\n\t\t\t\tif condition.Type == v1.PodReady {\n\t\t\t\t\tready = condition.Status == v1.ConditionTrue\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !ready {\n\t\t\t\tproblems = append(problems, fmt.Sprintf(\"%s not ready\", staticPod.Metadata().ID()))\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(problems) == 0 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"%s\", strings.Join(problems, \", \"))\n}\n\nfunc (ctrl *MachineStatusController) nodeReadyCheck(ctx context.Context, r controller.Runtime) error {\n\tnodename, err := safe.ReaderGetByID[*k8s.Nodename](ctx, r, k8s.NodenameID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// nodename not established yet, skip\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to get nodename: %w\", err)\n\t}\n\n\tif nodename.TypedSpec().SkipNodeRegistration {\n\t\t// node registration skipped, skip the check\n\t\treturn nil\n\t}\n\n\tnodeStatus, err := safe.ReaderGetByID[*k8s.NodeStatus](ctx, r, nodename.TypedSpec().Nodename)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// node not established yet, skip\n\t\t\treturn fmt.Errorf(\"node %q status is not available yet\", nodename.TypedSpec().Nodename)\n\t\t}\n\n\t\treturn fmt.Errorf(\"failed to get node status: %w\", err)\n\t}\n\n\tif !nodeStatus.TypedSpec().NodeReady {\n\t\treturn fmt.Errorf(\"node %q is not ready\", nodename.TypedSpec().Nodename)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (ctrl *MachineStatusController) watchEvents() {\n\t// the interface of the Watch function is weird (blaming myself @smira)\n\t//\n\t// at the same time as it is events based, it's impossible to reconcile the current state\n\t// from the events, so what we're doing is watching the events forever as soon as the controller starts,\n\t// and aggregating the state into the stage variable, notifying the controller whenever the state changes.\n\tctrl.V1Alpha1Events.Watch(func(eventCh <-chan v1alpha1runtime.EventInfo) { //nolint:errcheck\n\t\tvar (\n\t\t\toldStage        runtime.MachineStage\n\t\t\tcurrentSequence string\n\t\t)\n\n\t\tfor ev := range eventCh {\n\t\t\tnewStage := oldStage\n\n\t\t\tswitch event := ev.Event.Payload.(type) {\n\t\t\tcase *machineapi.SequenceEvent:\n\t\t\t\tcurrentSequence = event.Sequence\n\n\t\t\t\tswitch event.Action {\n\t\t\t\tcase machineapi.SequenceEvent_START:\n\t\t\t\t\t// mostly interested in sequence start events\n\t\t\t\t\tswitch event.Sequence {\n\t\t\t\t\tcase v1alpha1runtime.SequenceBoot.String(), v1alpha1runtime.SequenceInitialize.String():\n\t\t\t\t\t\tnewStage = runtime.MachineStageBooting\n\t\t\t\t\tcase v1alpha1runtime.SequenceInstall.String():\n\t\t\t\t\t\t// install sequence is run always, even if the machine is already installed, so we'll catch it by phase name\n\t\t\t\t\tcase v1alpha1runtime.SequenceShutdown.String():\n\t\t\t\t\t\tnewStage = runtime.MachineStageShuttingDown\n\t\t\t\t\tcase v1alpha1runtime.SequenceUpgrade.String(), v1alpha1runtime.SequenceStageUpgrade.String(), v1alpha1runtime.SequenceMaintenanceUpgrade.String():\n\t\t\t\t\t\tnewStage = runtime.MachineStageUpgrading\n\t\t\t\t\tcase v1alpha1runtime.SequenceReset.String():\n\t\t\t\t\t\tnewStage = runtime.MachineStageResetting\n\t\t\t\t\tcase v1alpha1runtime.SequenceReboot.String():\n\t\t\t\t\t\tnewStage = runtime.MachineStageRebooting\n\t\t\t\t\t}\n\t\t\t\tcase machineapi.SequenceEvent_NOOP:\n\t\t\t\t\tif event.Error != nil && event.Error.Code == common.Code_FATAL {\n\t\t\t\t\t\t// fatal errors lead to reboot\n\t\t\t\t\t\tnewStage = runtime.MachineStageRebooting\n\t\t\t\t\t}\n\t\t\t\tcase machineapi.SequenceEvent_STOP:\n\t\t\t\t\tif event.Sequence == v1alpha1runtime.SequenceBoot.String() && event.Error == nil {\n\t\t\t\t\t\tnewStage = runtime.MachineStageRunning\n\t\t\t\t\t}\n\n\t\t\t\t\t// sequence finished, it doesn't matter whether if it was successful or not\n\t\t\t\t\tcurrentSequence = \"\"\n\t\t\t\t}\n\t\t\tcase *machineapi.PhaseEvent:\n\t\t\t\tif event.Action == machineapi.PhaseEvent_START {\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase currentSequence == v1alpha1runtime.SequenceInstall.String() && event.Phase == \"install\":\n\t\t\t\t\t\tnewStage = runtime.MachineStageInstalling\n\t\t\t\t\tcase (currentSequence == v1alpha1runtime.SequenceInstall.String() ||\n\t\t\t\t\t\tcurrentSequence == v1alpha1runtime.SequenceUpgrade.String() ||\n\t\t\t\t\t\tcurrentSequence == v1alpha1runtime.SequenceStageUpgrade.String() ||\n\t\t\t\t\t\tcurrentSequence == v1alpha1runtime.SequenceMaintenanceUpgrade.String()) && event.Phase == \"kexec\":\n\t\t\t\t\t\tnewStage = runtime.MachineStageRebooting\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *machineapi.TaskEvent:\n\t\t\t\tif event.Task == \"runningMaintenance\" {\n\t\t\t\t\tswitch event.Action {\n\t\t\t\t\tcase machineapi.TaskEvent_START:\n\t\t\t\t\t\tnewStage = runtime.MachineStageMaintenance\n\t\t\t\t\tcase machineapi.TaskEvent_STOP:\n\t\t\t\t\t\tnewStage = runtime.MachineStageBooting\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif oldStage != newStage {\n\t\t\t\tctrl.mu.Lock()\n\t\t\t\tctrl.currentStage = newStage\n\t\t\t\tctrl.mu.Unlock()\n\n\t\t\t\tselect {\n\t\t\t\tcase ctrl.notifyCh <- struct{}{}:\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toldStage = newStage\n\t\t}\n\t}, v1alpha1runtime.WithTailEvents(-1))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/machine_status_publisher.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// MachineStatusPublisherController watches MachineStatusPublishers, sets/resets kernel params.\ntype MachineStatusPublisherController struct {\n\tV1Alpha1Events v1alpha1runtime.Publisher\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MachineStatusPublisherController) Name() string {\n\treturn \"runtime.MachineStatusPublisherController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MachineStatusPublisherController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MachineStatusType,\n\t\t\tID:        optional.Some(runtime.MachineStatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MachineStatusPublisherController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *MachineStatusPublisherController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tmachineStatus, err := safe.ReaderGet[*runtime.MachineStatus](ctx, r, runtime.NewMachineStatus().Metadata())\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error reading machine status: %w\", err)\n\t\t}\n\n\t\tctrl.V1Alpha1Events.Publish(ctx, &machine.MachineStatusEvent{\n\t\t\tStage: machine.MachineStatusEvent_MachineStage(machineStatus.TypedSpec().Stage),\n\t\t\tStatus: &machine.MachineStatusEvent_MachineStatus{\n\t\t\t\tReady: machineStatus.TypedSpec().Status.Ready,\n\t\t\t\tUnmetConditions: xslices.Map(machineStatus.TypedSpec().Status.UnmetConditions,\n\t\t\t\t\tfunc(unmetCondition runtime.UnmetCondition) *machine.MachineStatusEvent_MachineStatus_UnmetCondition {\n\t\t\t\t\t\treturn &machine.MachineStatusEvent_MachineStatus_UnmetCondition{\n\t\t\t\t\t\t\tName:   unmetCondition.Name,\n\t\t\t\t\t\t\tReason: unmetCondition.Reason,\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t},\n\t\t})\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/machine_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\ttimeres \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nfunc TestMachineStatusSuite(t *testing.T) {\n\teventCh := make(chan v1alpha1runtime.EventInfo)\n\n\tsuite.Run(t, &MachineStatusSuite{\n\t\teventCh: eventCh,\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.MachineStatusController{\n\t\t\t\t\tV1Alpha1Events: &mockWatcher{eventCh: eventCh},\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype mockWatcher struct {\n\teventCh chan v1alpha1runtime.EventInfo\n}\n\nfunc (m *mockWatcher) Watch(f v1alpha1runtime.WatchFunc, opt ...v1alpha1runtime.WatchOptionFunc) error {\n\tf(m.eventCh)\n\n\treturn nil\n}\n\ntype MachineStatusSuite struct {\n\tctest.DefaultSuite\n\n\teventCh chan v1alpha1runtime.EventInfo\n}\n\nfunc (suite *MachineStatusSuite) assertMachineStatus(stage runtime.MachineStage, ready bool, unmetConditions []string) {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MachineStatusID},\n\t\tfunc(machineStatus *runtime.MachineStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(stage, machineStatus.TypedSpec().Stage)\n\t\t\tasrt.Equal(ready, machineStatus.TypedSpec().Status.Ready)\n\n\t\t\tasrt.Equal(unmetConditions,\n\t\t\t\txslices.Map(machineStatus.TypedSpec().Status.UnmetConditions, func(c runtime.UnmetCondition) string { return c.Name }))\n\t\t})\n}\n\nfunc (suite *MachineStatusSuite) TestReconcile() {\n\tsuite.assertMachineStatus(runtime.MachineStageUnknown, true, nil)\n\n\tsuite.eventCh <- v1alpha1runtime.EventInfo{\n\t\tEvent: v1alpha1runtime.Event{\n\t\t\tPayload: &machineapi.SequenceEvent{\n\t\t\t\tSequence: v1alpha1runtime.SequenceInitialize.String(),\n\t\t\t\tAction:   machineapi.SequenceEvent_START,\n\t\t\t},\n\t\t},\n\t}\n\n\tsuite.assertMachineStatus(runtime.MachineStageBooting, false, []string{\"time\", \"network\", \"services\"})\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\ttimeStatus := timeres.NewStatus()\n\ttimeStatus.TypedSpec().Synced = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), timeStatus))\n\n\tsuite.eventCh <- v1alpha1runtime.EventInfo{\n\t\tEvent: v1alpha1runtime.Event{\n\t\t\tPayload: &machineapi.SequenceEvent{\n\t\t\t\tSequence: v1alpha1runtime.SequenceBoot.String(),\n\t\t\t\tAction:   machineapi.SequenceEvent_START,\n\t\t\t},\n\t\t},\n\t}\n\n\tsuite.assertMachineStatus(runtime.MachineStageBooting, false, []string{\"network\", \"services\"})\n\n\tsuite.eventCh <- v1alpha1runtime.EventInfo{\n\t\tEvent: v1alpha1runtime.Event{\n\t\t\tPayload: &machineapi.SequenceEvent{\n\t\t\t\tSequence: v1alpha1runtime.SequenceBoot.String(),\n\t\t\t\tAction:   machineapi.SequenceEvent_STOP,\n\t\t\t},\n\t\t},\n\t}\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tnetworkStatus.TypedSpec().ConnectivityReady = true\n\tnetworkStatus.TypedSpec().EtcFilesReady = true\n\tnetworkStatus.TypedSpec().HostnameReady = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), networkStatus))\n\n\tsuite.assertMachineStatus(runtime.MachineStageRunning, false, []string{\"services\"})\n\n\tfor _, service := range []string{\"apid\", \"etcd\", \"kubelet\", \"machined\", \"trustd\"} {\n\t\tserviceStatus := v1alpha1.NewService(service)\n\t\tserviceStatus.TypedSpec().Running = true\n\t\tserviceStatus.TypedSpec().Healthy = true\n\t\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), serviceStatus))\n\t}\n\n\tsuite.assertMachineStatus(runtime.MachineStageRunning, true, nil)\n\n\tnodename := k8s.NewNodename(k8s.NamespaceName, k8s.NodenameID)\n\tnodename.TypedSpec().Nodename = \"test\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodename))\n\n\tsuite.assertMachineStatus(runtime.MachineStageRunning, false, []string{\"nodeReady\"})\n\n\tnodeStatus := k8s.NewNodeStatus(k8s.NamespaceName, \"test\")\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeStatus))\n\n\tsuite.assertMachineStatus(runtime.MachineStageRunning, false, []string{\"nodeReady\"})\n\n\tnodeStatus.TypedSpec().NodeReady = true\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), nodeStatus))\n\n\tsuite.assertMachineStatus(runtime.MachineStageRunning, true, nil)\n\n\tsuite.eventCh <- v1alpha1runtime.EventInfo{\n\t\tEvent: v1alpha1runtime.Event{\n\t\t\tPayload: &machineapi.SequenceEvent{\n\t\t\t\tSequence: v1alpha1runtime.SequenceReboot.String(),\n\t\t\t\tAction:   machineapi.SequenceEvent_START,\n\t\t\t},\n\t\t},\n\t}\n\n\tsuite.assertMachineStatus(runtime.MachineStageRebooting, true, nil)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/maintenance_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\n// MaintenanceConfigController manages Maintenance Service config: which address it should listen on, etc.\ntype MaintenanceConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MaintenanceConfigController) Name() string {\n\treturn \"runtime.MaintenanceConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      siderolink.ConfigType,\n\t\t\tID:        optional.Some(siderolink.ConfigID),\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.NodeAddressCurrentID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.MaintenanceServiceConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *MaintenanceConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tnodeAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressCurrentID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting node address: %w\", err)\n\t\t}\n\n\t\tvar (\n\t\t\tlistenAddress      string\n\t\t\treachableAddresses []netip.Addr\n\t\t)\n\n\t\tif nodeAddresses != nil {\n\t\t\treachableAddresses = nodeAddresses.TypedSpec().IPs()\n\t\t}\n\n\t\t_, err = safe.ReaderGetByID[*siderolink.Config](ctx, r, siderolink.ConfigID)\n\n\t\t// check if SideroLink config exists:\n\t\tswitch {\n\t\t// * if it exists, find the SideroLink address and listen only on it\n\t\tcase err == nil:\n\t\t\tif nodeAddresses != nil {\n\t\t\t\tsideroLinkAddresses := xslices.Filter(nodeAddresses.TypedSpec().IPs(), func(addr netip.Addr) bool {\n\t\t\t\t\treturn network.IsULA(addr, network.ULASideroLink)\n\t\t\t\t})\n\n\t\t\t\tif len(sideroLinkAddresses) > 0 {\n\t\t\t\t\tlistenAddress = nethelpers.JoinHostPort(sideroLinkAddresses[0].String(), constants.ApidPort)\n\t\t\t\t\treachableAddresses = sideroLinkAddresses[:1]\n\t\t\t\t}\n\t\t\t}\n\t\t// * if it doesn't exist, listen on '*'\n\t\tcase state.IsNotFoundError(err):\n\t\t\tlistenAddress = fmt.Sprintf(\":%d\", constants.ApidPort)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"error getting siderolink config: %w\", err)\n\t\t}\n\n\t\tif listenAddress == \"\" {\n\t\t\t// drop config\n\t\t\tif err = r.Destroy(ctx, runtime.NewMaintenanceServiceConfig().Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error destroying maintenance config: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\t// create/update config\n\t\t\tif err = safe.WriterModify[*runtime.MaintenanceServiceConfig](ctx, r, runtime.NewMaintenanceServiceConfig(),\n\t\t\t\tfunc(config *runtime.MaintenanceServiceConfig) error {\n\t\t\t\t\tconfig.TypedSpec().ListenAddress = listenAddress\n\t\t\t\t\tconfig.TypedSpec().ReachableAddresses = reachableAddresses\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating maintenance config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/maintenance_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\nfunc TestMaintenanceConfigSuite(t *testing.T) {\n\tsuite.Run(t, &MaintenanceConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrl.MaintenanceConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype MaintenanceConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *MaintenanceConfigSuite) TestReconcile() {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MaintenanceServiceConfigID},\n\t\tfunc(cfg *runtime.MaintenanceServiceConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\":50000\", cfg.TypedSpec().ListenAddress)\n\t\t\tasrt.Nil(cfg.TypedSpec().ReachableAddresses)\n\t\t})\n\n\tsiderolinkConfig := siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), siderolinkConfig))\n\n\trtestutils.AssertNoResource[*runtime.MaintenanceServiceConfig](suite.Ctx(), suite.T(), suite.State(), runtime.MaintenanceServiceConfigID)\n\n\tnodeAddresses := network.NewNodeAddress(network.NamespaceName, network.NodeAddressCurrentID)\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"172.16.0.1/24\"),\n\t\tnetip.MustParsePrefix(\"fdae:41e4:649b:9303:2a07:9c7:5b08:aef7/64\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.MaintenanceServiceConfigID},\n\t\tfunc(cfg *runtime.MaintenanceServiceConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"[fdae:41e4:649b:9303:2a07:9c7:5b08:aef7]:50000\", cfg.TypedSpec().ListenAddress)\n\t\t\tasrt.Equal([]netip.Addr{netip.MustParseAddr(\"fdae:41e4:649b:9303:2a07:9c7:5b08:aef7\")}, cfg.TypedSpec().ReachableAddresses)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/maintenance_service_inform.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\n\tmachinedruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// MaintenanceServiceInformController provides logging when the maintenance service is running.\ntype MaintenanceServiceInformController struct {\n\tV1Alpha1Mode machinedruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MaintenanceServiceInformController) Name() string {\n\treturn \"runtime.MaintenanceServiceInformController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceServiceInformController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MaintenanceServiceRequestType,\n\t\t\tID:        optional.Some(runtime.MaintenanceServiceRequestID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MaintenanceServiceConfigType,\n\t\t\tID:        optional.Some(runtime.MaintenanceServiceConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.APIType,\n\t\t\tID:        optional.Some(secrets.APIID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceServiceInformController) Outputs() []controller.Output {\n\treturn nil\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *MaintenanceServiceInformController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tlastReachableAddresses     []string\n\t\tlastCertificateFingerprint string\n\t\tusagePrinted               bool\n\t)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\trequest, err := safe.ReaderGetByID[*runtime.MaintenanceServiceRequest](ctx, r, runtime.MaintenanceServiceRequestID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get maintenance service request: %w\", err)\n\t\t}\n\n\t\tif request == nil {\n\t\t\t// no request, nothing to do\n\t\t\tcontinue\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*runtime.MaintenanceServiceConfig](ctx, r, runtime.MaintenanceServiceConfigID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get maintenance service config: %w\", err)\n\t\t}\n\n\t\tcert, err := safe.ReaderGetByID[*secrets.API](ctx, r, secrets.APIID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get API secret: %w\", err)\n\t\t}\n\n\t\tif cert != nil && !cert.TypedSpec().SkipVerifyingClientCert {\n\t\t\t// not a maintenance mode yet\n\t\t\tcert = nil\n\t\t}\n\n\t\t// print additional information for the user on important state changes\n\t\treachableAddresses := xslices.Map(cfg.TypedSpec().ReachableAddresses, netip.Addr.String)\n\n\t\tif !slices.Equal(lastReachableAddresses, reachableAddresses) {\n\t\t\tlogger.Info(\"this machine is reachable at:\")\n\n\t\t\tfor _, addr := range reachableAddresses {\n\t\t\t\tlogger.Info(\"\\t\" + addr)\n\t\t\t}\n\n\t\t\tlastReachableAddresses = reachableAddresses\n\t\t}\n\n\t\tif cert != nil {\n\t\t\tcertificateFingerprint, err := x509.SPKIFingerprintFromPEM(cert.TypedSpec().Server.Crt)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to get certificate fingerprint: %w\", err)\n\t\t\t}\n\n\t\t\tfingerprint := certificateFingerprint.String()\n\n\t\t\tif fingerprint != lastCertificateFingerprint {\n\t\t\t\tlogger.Info(\"server certificate issued\", zap.String(\"fingerprint\", fingerprint))\n\t\t\t}\n\n\t\t\tlastCertificateFingerprint = fingerprint\n\t\t}\n\n\t\tif !usagePrinted && len(reachableAddresses) > 0 && lastCertificateFingerprint != \"\" && !ctrl.V1Alpha1Mode.IsAgent() {\n\t\t\tfirstIP := reachableAddresses[0]\n\n\t\t\tlogger.Sugar().Info(\"upload configuration using talosctl:\")\n\t\t\tlogger.Sugar().Infof(\"\\ttalosctl apply-config --insecure --nodes %s --file <config.yaml>\", firstIP)\n\t\t\tlogger.Sugar().Info(\"optionally with node fingerprint check:\")\n\t\t\tlogger.Sugar().Infof(\"\\ttalosctl apply-config --insecure --nodes %s --cert-fingerprint '%s' --file <config.yaml>\", firstIP, lastCertificateFingerprint)\n\n\t\t\tusagePrinted = true\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// MountStatusController transforms block.MountStatus resources into legacy v1alpha1.MountStatus.\n//\n// It only exists to provide backwards compatibility with legacy consumers.\ntype MountStatusController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Name() string {\n\treturn \"runtime.MountStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.MountStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeStatusType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MountStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.MountStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *MountStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-r.EventCh():\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\n\t\tmountStatuses, err := safe.ReaderListAll[*block.MountStatus](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read mount statuses: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tfor mountStatus := range mountStatuses.All() {\n\t\t\tvolumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, r, mountStatus.TypedSpec().Spec.VolumeID)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to get volume status %q: %w\", mountStatus.TypedSpec().Spec.VolumeID, err)\n\t\t\t}\n\n\t\t\tif volumeStatus.TypedSpec().Type != block.VolumeTypePartition && volumeStatus.TypedSpec().Type != block.VolumeTypeDisk {\n\t\t\t\t// legacy volume statuses shouldn't show up for non-partition/disk volumes\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewMountStatus(runtime.NamespaceName, volumeStatus.Metadata().ID()),\n\t\t\t\tfunc(res *runtime.MountStatus) error {\n\t\t\t\t\tres.TypedSpec().Source = mountStatus.TypedSpec().Source\n\t\t\t\t\tres.TypedSpec().Target = mountStatus.TypedSpec().Target\n\t\t\t\t\tres.TypedSpec().FilesystemType = volumeStatus.TypedSpec().Filesystem.String()\n\t\t\t\t\tres.TypedSpec().Encrypted = volumeStatus.TypedSpec().EncryptionProvider != block.EncryptionProviderNone\n\t\t\t\t\tres.TypedSpec().EncryptionProviders = volumeStatus.TypedSpec().ConfiguredEncryptionKeys\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to write mount status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*runtime.MountStatus](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup mount statuses: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/oom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime/internal/oom\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype actionLogItem struct {\n\truntimeres.OOMActionSpec\n\n\tID int\n}\n\n// OOMController is a controller that monitors memory PSI and handles near-OOM situations.\ntype OOMController struct {\n\tCgroupRoot      string\n\tActionTriggered time.Time\n\tV1Alpha1Mode    runtime.Mode\n\tactionLog       []actionLogItem\n\tidSeq           int\n\toldValues       map[string]float64\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *OOMController) Name() string {\n\treturn \"runtime.OOMController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *OOMController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *OOMController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtimeres.OOMActionType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\nvar defaultTriggerExpr = sync.OnceValue(func() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(\n\t\tconstants.DefaultOOMTriggerExpression,\n\t\tcelenv.OOMTrigger(),\n\t))\n})\n\n// Sort processes by the following hierarchy:\n// First, sort by high-level group:\n//     kubepods (workloads)\n//     podruntime (CRI, kubelet, etcd)\n//     runtime (core containerd, system services)\n//     init\n// Second, inside kubepods we have QoS groups:\n//     first priority: BestEffort\n//     second: Burstable\n//     last: Guaranteed\n// Third, look into other attributes, e.g. OOM score.\n// Fourth, look into memory max - memory current (if memory max is set).\n//\n// Sort to make the most prioritized to OOM-kill cgroup to the first place\n\nvar defaultScoringExpr = sync.OnceValue(func() cel.Expression {\n\treturn cel.MustExpression(cel.ParseDoubleExpression(\n\t\tconstants.DefaultOOMCgroupRankingExpression,\n\t\tcelenv.OOMCgroupScoring(),\n\t))\n})\n\nconst defaultSampleInterval = 500 * time.Millisecond\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *OOMController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode.InContainer() {\n\t\treturn nil\n\t}\n\n\ttriggerExpr := defaultTriggerExpr()\n\tscoringExpr := defaultScoringExpr()\n\tsampleInterval := defaultSampleInterval\n\tctrl.oldValues = make(map[string]float64)\n\n\tticker := time.NewTicker(sampleInterval)\n\ttickerC := ticker.C\n\n\tif ctrl.CgroupRoot == \"\" {\n\t\tctrl.CgroupRoot = constants.CgroupMountPath\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"cannot get active machine config: %w\", err)\n\t\t\t}\n\n\t\t\tvar newInterval time.Duration\n\n\t\t\ttriggerExpr, scoringExpr, newInterval = ctrl.getConfig(cfg)\n\n\t\t\tif sampleInterval != newInterval {\n\t\t\t\tticker.Reset(newInterval)\n\t\t\t\tsampleInterval = newInterval\n\t\t\t}\n\t\tcase <-tickerC:\n\t\t}\n\n\t\tevalContext := map[string]any{\n\t\t\t\"time_since_trigger\": time.Since(ctrl.ActionTriggered),\n\t\t}\n\n\t\terr := oom.PopulatePsiToCtx(ctrl.CgroupRoot, evalContext, ctrl.oldValues, sampleInterval)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"cannot populate PSI context\", zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\ttrigger, err := oom.EvaluateTrigger(triggerExpr, evalContext)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"cannot evaluate OOM trigger expression\", zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tfor _, action := range ctrl.actionLog {\n\t\t\tif err := safe.WriterModify(ctx, r, runtimeres.NewOOMActionSpec(runtimeres.NamespaceName, strconv.Itoa(action.ID)),\n\t\t\t\tfunc(item *runtimeres.OOMAction) error {\n\t\t\t\t\t*item.TypedSpec() = action.OOMActionSpec\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create OOM action log: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtimeres.OOMAction](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif trigger {\n\t\t\tscore, processes := ctrl.OomAction(logger, ctrl.CgroupRoot, scoringExpr)\n\n\t\t\tctxString, err := json.Marshal(evalContext)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to marshal trigger context: %w\", err)\n\t\t\t}\n\n\t\t\tctrl.actionLog = append(ctrl.actionLog, actionLogItem{\n\t\t\t\tID: ctrl.idSeq,\n\t\t\t\tOOMActionSpec: runtimeres.OOMActionSpec{\n\t\t\t\t\tTriggerContext: string(ctxString),\n\t\t\t\t\tProcesses:      processes,\n\t\t\t\t\tScore:          score,\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tctrl.idSeq++\n\n\t\t\tif len(ctrl.actionLog) > constants.OOMActionLogKeep {\n\t\t\t\tctrl.actionLog = ctrl.actionLog[len(ctrl.actionLog)-constants.OOMActionLogKeep:]\n\t\t\t}\n\n\t\t\tctrl.ActionTriggered = time.Now()\n\t\t}\n\t}\n}\n\nfunc (*OOMController) getConfig(cfg *config.MachineConfig) (cel.Expression, cel.Expression, time.Duration) {\n\ttriggerExpr := defaultTriggerExpr()\n\n\tif cfg != nil {\n\t\tif oomCfg := cfg.Config().OOMConfig(); oomCfg != nil {\n\t\t\tif expr, ok := oomCfg.TriggerExpression().Get(); ok {\n\t\t\t\ttriggerExpr = expr\n\t\t\t}\n\t\t}\n\t}\n\n\tscoringExpr := defaultScoringExpr()\n\n\tif cfg != nil {\n\t\tif oomCfg := cfg.Config().OOMConfig(); oomCfg != nil {\n\t\t\tif expr, ok := oomCfg.CgroupRankingExpression().Get(); ok {\n\t\t\t\tscoringExpr = expr\n\t\t\t}\n\t\t}\n\t}\n\n\tnewInterval := defaultSampleInterval\n\n\tif cfg != nil {\n\t\tif oomCfg := cfg.Config().OOMConfig(); oomCfg != nil {\n\t\t\tif interval, ok := oomCfg.SampleInterval().Get(); ok {\n\t\t\t\tnewInterval = interval\n\t\t\t}\n\t\t}\n\t}\n\n\treturn triggerExpr, scoringExpr, newInterval\n}\n\n// OomAction handles out of memory conditions by selecting and killing cgroups based on memory usage data.\nfunc (ctrl *OOMController) OomAction(logger *zap.Logger, root string, scoringExpr cel.Expression) (float64, []string) {\n\tlogger.Info(\"OOM controller triggered\")\n\n\tranking := oom.RankCgroups(logger, root, scoringExpr)\n\n\tif len(ranking) == 0 {\n\t\treturn 0, []string{}\n\t}\n\n\tvar (\n\t\tmaxScore     = math.Inf(-1)\n\t\tcgroupToKill oom.RankedCgroup\n\t)\n\n\tfor cgroup, score := range ranking {\n\t\tif score > maxScore {\n\t\t\tmaxScore = score\n\t\t\tcgroupToKill = cgroup\n\t\t}\n\t}\n\n\tprocesses, err := reapCg(logger, cgroupToKill.Path)\n\tif err != nil {\n\t\tlogger.Error(\"cannot reap cgroup\", zap.String(\"cgroup\", cgroupToKill.Path), zap.Error(err))\n\t}\n\n\treturn maxScore, processes\n}\n\nfunc reapCg(logger *zap.Logger, cgroupPath string) ([]string, error) {\n\tlogger.Warn(\"Sending SIGKILL to cgroup\", zap.String(\"cgroup\", cgroupPath))\n\n\tprocesses := oom.ListCgroupProcs(cgroupPath)\n\tlogger.Info(\"victim processes:\", zap.Any(\"processes\", processes))\n\n\t// Open pidfd's of all the processes in cgroup to accelerate kernel\n\t// garbage-collecting those processes via mrelease.\n\tpidfds := []int{}\n\tcmdlines := []string{}\n\n\tfor _, pid := range processes {\n\t\tcmdBytes, err := os.ReadFile(filepath.Join(\"/proc\", strconv.Itoa(pid), \"cmdline\"))\n\t\tif err == nil {\n\t\t\tcmdlines = append(\n\t\t\t\tcmdlines,\n\t\t\t\tstring(bytes.ReplaceAll(bytes.TrimRight(cmdBytes, \"\\x00\"), []byte{0}, []byte{' '})),\n\t\t\t)\n\t\t}\n\n\t\t// pidfd is always opened with CLOEXEC:\n\t\t// https://github.com/torvalds/linux/blob/bf40f4b87761e2ec16efc8e49b9ca0d81f4115d8/kernel/pid.c#L637\n\t\tpidfd, err := unix.PidfdOpen(pid, 0)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to open pidfd\", zap.Int(\"pid\", pid), zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\t\tdefer unix.Close(pidfd) //nolint:errcheck\n\n\t\tpidfds = append(pidfds, pidfd)\n\t}\n\n\terr := os.WriteFile(filepath.Join(cgroupPath, \"cgroup.kill\"), []byte{'1'}, 0o644)\n\tif err != nil {\n\t\tlogger.Error(\"failed to send SIGKILL\", zap.String(\"cgroup\", cgroupPath), zap.Error(err))\n\n\t\treturn cmdlines, err\n\t}\n\n\tfor _, pidfd := range pidfds {\n\t\t_, _, errno := syscall.Syscall(unix.SYS_PROCESS_MRELEASE, uintptr(pidfd), uintptr(0), uintptr(0))\n\t\tif errno != 0 && errno != syscall.ESRCH {\n\t\t\t// FIXME: tolerate some errors esp given that some processes might have been freed already.\n\t\t\tlogger.Error(\"failed to call mrelease\", zap.Int(\"errno\", int(errno)))\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn cmdlines, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package runtime provides the runtime implementation.\npackage runtime\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/sbom_item.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// SBOMItemController is a controller that publishes Talos SBOMs as resources.\ntype SBOMItemController struct {\n\tSPDXPath          string\n\tExtensionSPDXPath string\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SBOMItemController) Name() string {\n\treturn \"runtime.SBOMItemController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SBOMItemController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SBOMItemController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtimeres.SBOMItemType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *SBOMItemController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.SPDXPath == \"\" {\n\t\tctrl.SPDXPath = constants.SPDXPath\n\t}\n\n\tif ctrl.ExtensionSPDXPath == \"\" {\n\t\tctrl.ExtensionSPDXPath = constants.ExtensionSPDXPath\n\t}\n\n\t// the controller runs a single time\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\tfor _, spec := range []struct {\n\t\tisExtension bool\n\t\tpath        string\n\t}{\n\t\t{false, ctrl.SPDXPath},\n\t\t{true, ctrl.ExtensionSPDXPath},\n\t} {\n\t\tif err := ctrl.processSPDXDirectory(ctx, r, logger, spec.path, spec.isExtension); err != nil {\n\t\t\tif spec.isExtension && errors.Is(err, os.ErrNotExist) {\n\t\t\t\t// Extension SBOM directory is only present if extensions are installed\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *SBOMItemController) processSPDXDirectory(ctx context.Context, r controller.Runtime, logger *zap.Logger, path string, isExtension bool) error {\n\tfiles, err := os.ReadDir(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read SBOM directory %q: %w\", path, err)\n\t}\n\n\tfor _, file := range files {\n\t\tif !file.Type().IsRegular() {\n\t\t\tlogger.Debug(\"skipping non-regular file\", zap.String(\"file\", file.Name()))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !strings.HasSuffix(file.Name(), \".spdx.json\") {\n\t\t\tlogger.Debug(\"skipping non-SPDX file\", zap.String(\"file\", file.Name()))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = ctrl.processSPDXFile(ctx, r, filepath.Join(path, file.Name()), isExtension); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to process SBOM file %q: %w\", file.Name(), err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// spdxDocument is a reduced structure of SPDX document.\n//\n// We are only interested in some fields.\ntype spdxDocument struct {\n\tPackages []spdxPackage `json:\"packages\"`\n}\n\ntype spdxPackage struct {\n\tName         string            `json:\"name\"`\n\tVersion      string            `json:\"versionInfo\"`\n\tLicense      string            `json:\"licenseDeclared\"`\n\tExternalRefs []spdxExternalRef `json:\"externalRefs\"`\n}\n\ntype spdxExternalRef struct {\n\tType    string `json:\"referenceType\"`\n\tLocator string `json:\"referenceLocator\"`\n}\n\nfunc (ctrl *SBOMItemController) processSPDXFile(ctx context.Context, r controller.Runtime, path string, isExtension bool) error {\n\tin, err := os.Open(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open SBOM file %q: %w\", path, err)\n\t}\n\n\tdefer in.Close() //nolint:errcheck\n\n\tvar doc spdxDocument\n\n\tif err := json.NewDecoder(in).Decode(&doc); err != nil {\n\t\treturn fmt.Errorf(\"failed to decode SBOM file %q: %w\", path, err)\n\t}\n\n\tfor _, pkg := range doc.Packages {\n\t\tif strings.HasPrefix(pkg.Name, version.Name+\" (\") {\n\t\t\tpkg.Name = version.Name\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, runtimeres.NewSBOMItemSpec(runtimeres.NamespaceName, pkg.Name),\n\t\t\tfunc(item *runtimeres.SBOMItem) error {\n\t\t\t\titem.TypedSpec().Name = pkg.Name\n\t\t\t\titem.TypedSpec().Version = pkg.Version\n\n\t\t\t\tif pkg.License != \"NOASSERTION\" {\n\t\t\t\t\titem.TypedSpec().License = pkg.License\n\t\t\t\t}\n\n\t\t\t\tfor _, ref := range pkg.ExternalRefs {\n\t\t\t\t\tswitch ref.Type {\n\t\t\t\t\tcase \"cpe23Type\":\n\t\t\t\t\t\titem.TypedSpec().CPEs = append(item.TypedSpec().CPEs, ref.Locator)\n\t\t\t\t\tcase \"purl\":\n\t\t\t\t\t\titem.TypedSpec().PURLs = append(item.TypedSpec().PURLs, ref.Locator)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\titem.TypedSpec().Extension = isExtension\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create SBOM item for package %q: %w\", pkg.Name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/sbom_item_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype SBOMItemSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestSBOMItemSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &SBOMItemSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.SBOMItemController{\n\t\t\t\t\tSPDXPath:          \"./testdata/spdx\",\n\t\t\t\t\tExtensionSPDXPath: \"./testdata/ext-spdx\",\n\t\t\t\t}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *SBOMItemSuite) TestReconcile() {\n\tctest.AssertResource(suite, \"apparmor-x86_64\", func(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"apparmor-x86_64\", item.TypedSpec().Name)\n\t\tasrt.Equal(\"v3.1.7\", item.TypedSpec().Version)\n\t\tasrt.Equal(\"GPL-2.0-or-later\", item.TypedSpec().License)\n\t\tasrt.Contains(item.TypedSpec().CPEs, \"cpe:2.3:a:apparmor:apparmor:v3.1.7:*:*:*:*:*:*:*\")\n\t\tasrt.Contains(item.TypedSpec().CPEs, \"cpe:2.3:a:canonical:apparmor:v3.1.7:*:*:*:*:*:*:*\")\n\t\tasrt.Empty(item.TypedSpec().PURLs)\n\t\tasrt.False(item.TypedSpec().Extension)\n\t})\n\n\tctest.AssertResource(suite, \"cel.dev/expr\", func(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"cel.dev/expr\", item.TypedSpec().Name)\n\t\tasrt.Equal(\"v0.24.0\", item.TypedSpec().Version)\n\t\tasrt.Empty(item.TypedSpec().License)\n\t\tasrt.Empty(item.TypedSpec().CPEs)\n\t\tasrt.Contains(item.TypedSpec().PURLs, \"pkg:golang/cel.dev/expr@v0.24.0\")\n\t\tasrt.False(item.TypedSpec().Extension)\n\t})\n\n\tctest.AssertResource(suite, \"tailscale\", func(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"tailscale\", item.TypedSpec().Name)\n\t\tasrt.Equal(\"1.84.2\", item.TypedSpec().Version)\n\t\tasrt.Equal(\"BSD-3-Clause\", item.TypedSpec().License)\n\t\tasrt.Contains(item.TypedSpec().CPEs, \"cpe:2.3:a:tailscale:tailscale:1.84.2:*:*:*:*:*:*:*\")\n\t\tasrt.Empty(item.TypedSpec().PURLs)\n\t\tasrt.True(item.TypedSpec().Extension)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/security_state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"encoding/hex\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/foxboron/go-uefi/efi\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\tmachineruntime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// SecurityStateController is a controller that updates the security state of Talos.\ntype SecurityStateController struct {\n\tV1Alpha1Mode machineruntime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SecurityStateController) Name() string {\n\treturn \"runtime.SecurityStateController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SecurityStateController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SecurityStateController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtimeres.SecurityStateType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *SecurityStateController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// wait for the `machined` service to start, as by that time initial mounts will be done\n\t\t_, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, \"machined\")\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get machined state: %w\", err)\n\t\t}\n\n\t\tvar (\n\t\t\tsecureBootState          bool\n\t\t\tbootedWithUKI            bool\n\t\t\tmoduleSignatureEnforced  bool\n\t\t\tpcrSigningKeyFingerprint string\n\t\t)\n\n\t\t// in container mode, never populate the fields\n\t\tif ctrl.V1Alpha1Mode != machineruntime.ModeContainer {\n\t\t\tif efi.GetSecureBoot() && !efi.GetSetupMode() {\n\t\t\t\tsecureBootState = true\n\t\t\t}\n\n\t\t\tdefaultEntry, err := sdboot.ReadVariable(sdboot.LoaderEntryDefaultName)\n\t\t\tif err == nil {\n\t\t\t\tif strings.HasPrefix(defaultEntry, \"Talos-\") {\n\t\t\t\t\tbootedWithUKI = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if defaultEntry is empty in the case when we booted off a disk image when installer never runs, we can rely on the\n\t\t\t// stub image identifier to determine if we booted with UKI\n\t\t\tif defaultEntry == \"\" {\n\t\t\t\tstubImageIdentifier, err := sdboot.ReadVariable(sdboot.StubImageIdentifierName)\n\t\t\t\tif err == nil {\n\t\t\t\t\tif strings.HasPrefix(filepath.Base(strings.ReplaceAll(stubImageIdentifier, \"\\\\\", \"/\")), \"Talos-\") {\n\t\t\t\t\t\tbootedWithUKI = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif pcrPublicKeyData, err := os.ReadFile(constants.PCRPublicKey); err == nil {\n\t\t\t\tblock, _ := pem.Decode(pcrPublicKeyData)\n\t\t\t\tif block == nil {\n\t\t\t\t\treturn errors.New(\"failed to decode PEM block for PCR public key\")\n\t\t\t\t}\n\n\t\t\t\tcert := x509.Certificate{\n\t\t\t\t\tRaw: block.Bytes,\n\t\t\t\t}\n\n\t\t\t\tpcrSigningKeyFingerprint = x509CertFingerprint(cert)\n\t\t\t}\n\t\t}\n\n\t\tselinuxState, err := getSelinuxState()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get SELinux state: %w\", err)\n\t\t}\n\n\t\tmoduleSignatureEnforcedInfo := procfs.ProcCmdline().Get(constants.KernelParamEnforceModuleSigVerify).First()\n\t\tif moduleSignatureEnforcedInfo != nil && *moduleSignatureEnforcedInfo == \"1\" {\n\t\t\tmoduleSignatureEnforced = true\n\t\t}\n\n\t\tfipsState := runtimeres.FIPSStateDisabled\n\n\t\tif fipsmode.Enabled() {\n\t\t\tif fipsmode.Strict() {\n\t\t\t\tfipsState = runtimeres.FIPSStateStrict\n\t\t\t} else {\n\t\t\t\tfipsState = runtimeres.FIPSStateEnabled\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, runtimeres.NewSecurityStateSpec(runtimeres.NamespaceName), func(state *runtimeres.SecurityState) error {\n\t\t\tstate.TypedSpec().SecureBoot = secureBootState\n\t\t\tstate.TypedSpec().PCRSigningKeyFingerprint = pcrSigningKeyFingerprint\n\t\t\tstate.TypedSpec().SELinuxState = selinuxState\n\t\t\tstate.TypedSpec().FIPSState = fipsState\n\t\t\tstate.TypedSpec().BootedWithUKI = bootedWithUKI\n\t\t\tstate.TypedSpec().ModuleSignatureEnforced = moduleSignatureEnforced\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// terminating the controller here, as we need to only populate securitystate once\n\t\treturn nil\n\t}\n}\n\nfunc x509CertFingerprint(cert x509.Certificate) string {\n\thash := sha256.Sum256(cert.Raw)\n\n\tvar buf bytes.Buffer\n\n\tfor i, b := range hex.EncodeToString(hash[:]) {\n\t\tif i > 0 && i%2 == 0 {\n\t\t\tbuf.WriteByte(':')\n\t\t}\n\n\t\tbuf.WriteString(strings.ToUpper(string(b)))\n\t}\n\n\treturn buf.String()\n}\n\nfunc getSelinuxState() (runtimeres.SELinuxState, error) {\n\tif !selinux.IsEnabled() {\n\t\treturn runtimeres.SELinuxStateDisabled, nil\n\t}\n\n\t// Read /sys/fs/selinux/enforce to determine if SELinux is in enforcing mode\n\t// Make sure LSM mode is actually enforcing, in case we later allow setenforce\n\t// IsEnabled is reliable, since LSM is active whenever SELinuxFS is mounted, which is done accordingly\n\tdata, err := os.ReadFile(\"/sys/fs/selinux/enforce\")\n\tif err != nil {\n\t\treturn runtimeres.SELinuxStateDisabled, err\n\t}\n\n\tif strings.TrimSpace(string(data)) == \"1\" {\n\t\treturn runtimeres.SELinuxStateEnforcing, nil\n\t}\n\n\treturn runtimeres.SELinuxStatePermissive, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/ext-spdx/tailscale.spdx.json",
    "content": "{\n \"spdxVersion\": \"SPDX-2.3\",\n \"dataLicense\": \"CC0-1.0\",\n \"SPDXID\": \"SPDXRef-DOCUMENT\",\n \"name\": \"sidero-pkgs-tailscale\",\n \"documentNamespace\": \"https://anchore.com/bldr/dir/sidero-pkgs-tailscale-945fd1b5-e1c4-5ceb-8c4e-7de776c0983c\",\n \"creationInfo\": {\n  \"licenseListVersion\": \"3.25\",\n  \"creators\": [\n   \"Organization: Anchore, Inc\",\n   \"Tool: bldr-v0.5.1\"\n  ],\n  \"created\": \"2022-01-20T18:35:52Z\"\n },\n \"packages\": [\n  {\n   \"name\": \"tailscale\",\n   \"SPDXID\": \"SPDXRef-Package-bldr-package-tailscale-bc56a5bc00e5302c\",\n   \"versionInfo\": \"1.84.2\",\n   \"supplier\": \"NOASSERTION\",\n   \"downloadLocation\": \"NOASSERTION\",\n   \"filesAnalyzed\": false,\n   \"sourceInfo\": \"acquired package info from the following paths: /Pkgfile\",\n   \"licenseConcluded\": \"NOASSERTION\",\n   \"licenseDeclared\": \"BSD-3-Clause\",\n   \"copyrightText\": \"NOASSERTION\",\n   \"externalRefs\": [\n    {\n     \"referenceCategory\": \"SECURITY\",\n     \"referenceType\": \"cpe23Type\",\n     \"referenceLocator\": \"cpe:2.3:a:tailscale:tailscale:1.84.2:*:*:*:*:*:*:*\"\n    }\n   ]\n  },\n  {\n   \"name\": \"sidero-pkgs-tailscale\",\n   \"SPDXID\": \"SPDXRef-DocumentRoot-Directory-sidero-pkgs-tailscale\",\n   \"versionInfo\": \"1.84.2\",\n   \"supplier\": \"NOASSERTION\",\n   \"downloadLocation\": \"NOASSERTION\",\n   \"filesAnalyzed\": false,\n   \"licenseConcluded\": \"NOASSERTION\",\n   \"licenseDeclared\": \"NOASSERTION\",\n   \"copyrightText\": \"NOASSERTION\",\n   \"primaryPackagePurpose\": \"FILE\"\n  }\n ],\n \"files\": [\n  {\n   \"fileName\": \"https://github.com/tailscale/tailscale/archive/refs/tags/v1.84.2.tar.gz\",\n   \"SPDXID\": \"SPDXRef-File-...archive-refs-tags-v1.84.2.tar.gz-c5546c6b96afad2e\",\n   \"checksums\": [\n    {\n     \"algorithm\": \"SHA256\",\n     \"checksumValue\": \"32673e5552e1176f1028a6a90a4c892d2475c92d1e952ca16156dc523d14d914\"\n    },\n    {\n     \"algorithm\": \"SHA512\",\n     \"checksumValue\": \"f4baaa9070a2ad4f4ddef9bac89fc5333dc1a74db68a976c30a20a7359ebc51d14905ef0098b1046493fb99a829b9b10502e03b12799e94ef543ebffc6018553\"\n    }\n   ],\n   \"licenseConcluded\": \"NOASSERTION\",\n   \"licenseInfoInFiles\": [\n    \"NOASSERTION\"\n   ],\n   \"copyrightText\": \"NOASSERTION\",\n   \"comment\": \"layerID: bldr sources\"\n  }\n ],\n \"relationships\": [\n  {\n   \"spdxElementId\": \"SPDXRef-Package-bldr-package-tailscale-\",\n   \"relatedSpdxElement\": \"SPDXRef-File-...archive-refs-tags-v1.84.2.tar.gz-c5546c6b96afad2e\",\n   \"relationshipType\": \"CONTAINS\"\n  },\n  {\n   \"spdxElementId\": \"SPDXRef-DocumentRoot-Directory-sidero-pkgs-tailscale\",\n   \"relatedSpdxElement\": \"SPDXRef-Package-bldr-package-tailscale-bc56a5bc00e5302c\",\n   \"relationshipType\": \"CONTAINS\"\n  },\n  {\n   \"spdxElementId\": \"SPDXRef-DOCUMENT\",\n   \"relatedSpdxElement\": \"SPDXRef-DocumentRoot-Directory-sidero-pkgs-tailscale\",\n   \"relationshipType\": \"DESCRIBES\"\n  }\n ]\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/extservices/foo.bar",
    "content": ""
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/extservices/frr.yaml",
    "content": "name: frr\ncontainer:\n  entrypoint: ./frr\n  args:\n    - --msg\n    - BGP FRR\ndepends:\n  - network:\n    - addresses\nrestart: always\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/extservices/hello.yaml",
    "content": "name: hello-world\ncontainer:\n  entrypoint: ./hello-world\n  args:\n    - --msg\n    - Talos Linux Extension Service\ndepends:\n  - network:\n    - addresses\nrestart: always\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/extservices/invalid.yaml",
    "content": "name: invalid\ncontainer:\n  entrypoint: ./hello-world\n  args:\n    - --msg\n    - Talos Linux Extension Service\ndepends:\n  - nothing: true\nrestart: random\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/extservices/zduplicate.yaml",
    "content": "name: hello-world\ncontainer:\n  entrypoint: ./duplicate\n  args:\n    - should not get registered\ndepends:\n  - network:\n    - addresses\nrestart: always\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/testdata/spdx/test.spdx.json",
    "content": "{\n \"spdxVersion\": \"SPDX-2.3\",\n \"dataLicense\": \"CC0-1.0\",\n \"SPDXID\": \"SPDXRef-DOCUMENT\",\n \"name\": \"Talos (amd64)\",\n \"documentNamespace\": \"https://anchore.com/syft/dir/Talos%20%28amd64%29-ab5f950d-20cd-5a2f-b198-9e345e29f1c8\",\n \"creationInfo\": {\n  \"licenseListVersion\": \"3.25\",\n  \"creators\": [\n   \"Organization: Anchore, Inc\",\n   \"Tool: syft-[not provided]\"\n  ],\n  \"created\": \"2025-07-07T19:03:36Z\"\n },\n \"packages\": [\n  {\n   \"name\": \"apparmor-x86_64\",\n   \"SPDXID\": \"SPDXRef-Package-bldr-package-apparmor-x86-64-925cc702a977d6be\",\n   \"versionInfo\": \"v3.1.7\",\n   \"supplier\": \"NOASSERTION\",\n   \"downloadLocation\": \"NOASSERTION\",\n   \"filesAnalyzed\": false,\n   \"sourceInfo\": \"acquired package info from SBOM: /apparmor.spdx.json\",\n   \"licenseConcluded\": \"NOASSERTION\",\n   \"licenseDeclared\": \"GPL-2.0-or-later\",\n   \"copyrightText\": \"NOASSERTION\",\n   \"externalRefs\": [\n    {\n     \"referenceCategory\": \"SECURITY\",\n     \"referenceType\": \"cpe23Type\",\n     \"referenceLocator\": \"cpe:2.3:a:apparmor:apparmor:v3.1.7:*:*:*:*:*:*:*\"\n    },\n    {\n     \"referenceCategory\": \"SECURITY\",\n     \"referenceType\": \"cpe23Type\",\n     \"referenceLocator\": \"cpe:2.3:a:canonical:apparmor:v3.1.7:*:*:*:*:*:*:*\"\n    }\n   ]\n  },\n  {\n   \"name\": \"cel.dev/expr\",\n   \"SPDXID\": \"SPDXRef-Package-go-module-cel.dev-expr-e4715f3e7652c734\",\n   \"versionInfo\": \"v0.24.0\",\n   \"supplier\": \"NOASSERTION\",\n   \"downloadLocation\": \"NOASSERTION\",\n   \"filesAnalyzed\": false,\n   \"sourceInfo\": \"acquired package info from go module information: /go.mod\",\n   \"licenseConcluded\": \"NOASSERTION\",\n   \"licenseDeclared\": \"NOASSERTION\",\n   \"copyrightText\": \"NOASSERTION\",\n   \"externalRefs\": [\n    {\n     \"referenceCategory\": \"PACKAGE-MANAGER\",\n     \"referenceType\": \"purl\",\n     \"referenceLocator\": \"pkg:golang/cel.dev/expr@v0.24.0\"\n    }\n   ]\n  }\n ],\n \"relationships\": [\n  {\n   \"spdxElementId\": \"SPDXRef-Package-go-module-github.com-jonboulle-clockwork-008a81e8156b0c05\",\n   \"relatedSpdxElement\": \"SPDXRef-File-go.mod-3fc5a8d3d86e9790\",\n   \"relationshipType\": \"OTHER\",\n   \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n  }\n ]\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/unique_token.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// UniqueMachineTokenController is a controller that manages SideroLink unique token.\ntype UniqueMachineTokenController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *UniqueMachineTokenController) Name() string {\n\treturn \"runtime.UniqueMachineTokenController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *UniqueMachineTokenController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MetaKeyType,\n\t\t\tID:        optional.Some(runtime.MetaKeyTagToID(meta.UniqueMachineToken)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.MetaLoadedType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *UniqueMachineTokenController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.UniqueMachineTokenType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *UniqueMachineTokenController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tmetaLoaded, err := safe.ReaderGetByID[*runtime.MetaLoaded](ctx, r, runtime.MetaLoadedID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get meta loaded: %w\", err)\n\t\t}\n\n\t\tmetaKey, err := safe.ReaderGetByID[*runtime.MetaKey](ctx, r, runtime.MetaKeyTagToID(meta.UniqueMachineToken))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get unique token meta key: %w\", err)\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get machine config: %w\", err)\n\t\t}\n\n\t\tif metaLoaded != nil {\n\t\t\tvar token string\n\n\t\t\tif metaKey != nil {\n\t\t\t\ttoken = metaKey.TypedSpec().Value\n\t\t\t} else if cfg != nil {\n\t\t\t\tif cfg.Config().SideroLink() != nil {\n\t\t\t\t\ttoken = cfg.Config().SideroLink().UniqueToken()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewUniqueMachineToken(), func(out *runtime.UniqueMachineToken) error {\n\t\t\t\tout.TypedSpec().Token = token\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to update unique token: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.UniqueMachineToken](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/unique_token_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype UniqueMachineTokenSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestUniqueMachineTokenSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &UniqueMachineTokenSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.UniqueMachineTokenController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *UniqueMachineTokenSuite) TestReconcileNoConfig() {\n\tctest.AssertNoResource[*runtime.UniqueMachineToken](suite, runtime.UniqueMachineTokenID)\n\n\tsuite.Create(runtime.NewMetaLoaded())\n\n\tctest.AssertResource(suite, runtime.UniqueMachineTokenID, func(token *runtime.UniqueMachineToken, asrt *assert.Assertions) {\n\t\tasrt.Empty(token.TypedSpec().Token)\n\t})\n\n\tmetaKey := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.UniqueMachineToken))\n\tmetaKey.TypedSpec().Value = \"token1\"\n\tsuite.Create(metaKey)\n\n\tctest.AssertResource(suite, runtime.UniqueMachineTokenID, func(token *runtime.UniqueMachineToken, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"token1\", token.TypedSpec().Token)\n\t})\n}\n\nfunc (suite *UniqueMachineTokenSuite) TestReconcileWithConfig() {\n\tsideroLinkConfig := siderolink.NewConfigV1Alpha1()\n\tsideroLinkConfig.UniqueTokenConfig = \"token2\"\n\n\tctr, err := container.New(sideroLinkConfig)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(ctr)\n\tsuite.Create(cfg)\n\n\tctest.AssertNoResource[*runtime.UniqueMachineToken](suite, runtime.UniqueMachineTokenID)\n\n\tsuite.Create(runtime.NewMetaLoaded())\n\n\tctest.AssertResource(suite, runtime.UniqueMachineTokenID, func(token *runtime.UniqueMachineToken, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"token2\", token.TypedSpec().Token)\n\t})\n\n\tmetaKey := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.UniqueMachineToken))\n\tmetaKey.TypedSpec().Value = \"token1\"\n\tsuite.Create(metaKey)\n\n\tctest.AssertResource(suite, runtime.UniqueMachineTokenID, func(token *runtime.UniqueMachineToken, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"token1\", token.TypedSpec().Token)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// WaitForDevicesReady waits for devices to be ready.\n//\n// It is a helper function for controllers.\nfunc WaitForDevicesReady(ctx context.Context, r controller.Runtime, nextInputs []controller.Input) error {\n\t// set inputs temporarily to a service only\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.DevicesStatusType,\n\t\t\tID:        optional.Some(runtime.DevicesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tstatus, err := safe.ReaderGetByID[*runtime.DevicesStatus](ctx, r, runtime.DevicesID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif status.TypedSpec().Ready {\n\t\t\t// condition met\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// restore inputs\n\tif err := r.UpdateInputs(nextInputs); err != nil {\n\t\treturn err\n\t}\n\n\t// queue an update to reprocess with new inputs\n\tr.QueueReconcile()\n\n\treturn nil\n}\n\n// updateFile is like `os.WriteFile`, but it will only update the file if the\n// contents have changed.\nfunc updateFile(filename string, contents []byte, mode os.FileMode) error {\n\toldContents, err := os.ReadFile(filename)\n\tif err == nil && bytes.Equal(oldContents, contents) {\n\t\treturn nil\n\t}\n\n\treturn os.WriteFile(filename, contents, mode)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// VersionController populates the version of currently running Talos.\ntype VersionController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *VersionController) Name() string {\n\treturn \"runtime.VersionController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *VersionController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *VersionController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.VersionType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *VersionController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif err := safe.WriterModify(ctx, r, runtime.NewVersion(), func(status *runtime.Version) error {\n\t\tstatus.TypedSpec().Version = version.Tag\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to update version status: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/watchdog_timer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// WatchdogTimerController watches v1alpha1.Config, creates/updates/deletes kernel module specs.\ntype WatchdogTimerController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerController) Name() string {\n\treturn \"runtime.WatchdogTimerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: runtime.NamespaceName,\n\t\t\tType:      runtime.WatchdogTimerConfigType,\n\t\t\tID:        optional.Some(runtime.WatchdogTimerConfigID),\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.WatchdogTimerStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *WatchdogTimerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar (\n\t\tticker  *time.Ticker\n\t\ttickerC <-chan time.Time\n\t)\n\n\ttickerStop := func() {\n\t\tif ticker == nil {\n\t\t\treturn\n\t\t}\n\n\t\tticker.Stop()\n\n\t\tticker = nil\n\t\ttickerC = nil\n\t}\n\n\tdefer tickerStop()\n\n\tvar wd *os.File\n\n\twdClose := func() {\n\t\tif wd == nil {\n\t\t\treturn\n\t\t}\n\n\t\tlogger.Info(\"closing hardware watchdog\", zap.String(\"path\", wd.Name()))\n\n\t\t// Magic close: make sure old watchdog won't trip after we close it\n\t\tif _, err := wd.WriteString(\"V\"); err != nil {\n\t\t\tlogger.Error(\"failed to send magic close to watchdog\", zap.String(\"path\", wd.Name()))\n\t\t}\n\n\t\tif err := wd.Close(); err != nil {\n\t\t\tlogger.Error(\"failed to close watchdog\", zap.String(\"path\", wd.Name()))\n\t\t}\n\n\t\twd = nil\n\t}\n\n\tdefer wdClose()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-tickerC:\n\t\t\tif _, _, err := syscall.Syscall(syscall.SYS_IOCTL, wd.Fd(), unix.WDIOC_KEEPALIVE, 0); err != 0 {\n\t\t\t\treturn fmt.Errorf(\"failed to feed watchdog: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*runtime.WatchdogTimerConfig](ctx, r, runtime.WatchdogTimerConfigID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting watchdog config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg == nil {\n\t\t\ttickerStop()\n\t\t\twdClose()\n\t\t} else {\n\t\t\t// close the watchdog if requested to use new one\n\t\t\tif wd != nil && wd.Name() != cfg.TypedSpec().Device {\n\t\t\t\twdClose()\n\t\t\t}\n\n\t\t\tif wd == nil {\n\t\t\t\twd, err = os.OpenFile(cfg.TypedSpec().Device, syscall.O_RDWR, 0o600)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to open watchdog device: %s\", err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Info(\"opened hardware watchdog\", zap.String(\"path\", cfg.TypedSpec().Device))\n\t\t\t}\n\n\t\t\ttimeout := int(cfg.TypedSpec().Timeout.Seconds())\n\n\t\t\tif _, _, err := syscall.Syscall(syscall.SYS_IOCTL, wd.Fd(), uintptr(unix.WDIOC_SETTIMEOUT), uintptr(unsafe.Pointer(&timeout))); err != 0 {\n\t\t\t\treturn fmt.Errorf(\"failed to set watchdog timeout: %w\", err)\n\t\t\t}\n\n\t\t\ttickerStop()\n\n\t\t\t// 3 pings per timeout should suffice in any case\n\t\t\tfeedInterval := cfg.TypedSpec().Timeout / 3\n\n\t\t\tticker = time.NewTicker(feedInterval)\n\t\t\ttickerC = ticker.C\n\n\t\t\tif _, _, err := syscall.Syscall(syscall.SYS_IOCTL, wd.Fd(), uintptr(unix.WDIOC_KEEPALIVE), 0); err != 0 {\n\t\t\t\treturn fmt.Errorf(\"failed to feed watchdog: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"set hardware watchdog timeout\", zap.Duration(\"timeout\", cfg.TypedSpec().Timeout), zap.Duration(\"feed_interval\", feedInterval))\n\n\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewWatchdogTimerStatus(cfg.Metadata().ID()), func(status *runtime.WatchdogTimerStatus) error {\n\t\t\t\tstatus.TypedSpec().Device = cfg.TypedSpec().Device\n\t\t\t\tstatus.TypedSpec().Timeout = cfg.TypedSpec().Timeout\n\t\t\t\tstatus.TypedSpec().FeedInterval = feedInterval\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating watchdog status: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.WatchdogTimerStatus](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/watchdog_timer_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// WatchdogTimerConfigController generates configuration for watchdog timers.\ntype WatchdogTimerConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerConfigController) Name() string {\n\treturn \"runtime.WatchdogTimerConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: runtime.WatchdogTimerConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *WatchdogTimerConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) (err error) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine config: %w\", err)\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif cfg != nil {\n\t\t\tif watchdogConfig := cfg.Config().Runtime().WatchdogTimer(); watchdogConfig != nil {\n\t\t\t\tif err = safe.WriterModify(ctx, r, runtime.NewWatchdogTimerConfig(), func(cfg *runtime.WatchdogTimerConfig) error {\n\t\t\t\t\tcfg.TypedSpec().Device = watchdogConfig.Device()\n\t\t\t\t\tcfg.TypedSpec().Timeout = watchdogConfig.Timeout()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error updating kmsg log config: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*runtime.WatchdogTimerConfig](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/runtime/watchdog_timer_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\truntimectrls \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\truntimecfg \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype WatchdogTimerConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestWatchdogTimerConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(WatchdogTimerConfigSuite))\n}\n\nfunc (suite *WatchdogTimerConfigSuite) TestWatchdogTimerConfigNone() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.WatchdogTimerConfigController{}))\n\n\trtestutils.AssertNoResource[*runtime.WatchdogTimerConfig](suite.Ctx(), suite.T(), suite.State(), runtime.WatchdogTimerConfigID)\n}\n\nfunc (suite *WatchdogTimerConfigSuite) TestWatchdogTimerConfigMachineConfig() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&runtimectrls.WatchdogTimerConfigController{}))\n\n\twatchdogTimerConfig := &runtimecfg.WatchdogTimerV1Alpha1{\n\t\tWatchdogDevice: \"/dev/watchdog0\",\n\t}\n\n\tcfg, err := container.New(watchdogTimerConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources[*runtime.WatchdogTimerConfig](suite.Ctx(), suite.T(), suite.State(), []resource.ID{runtime.WatchdogTimerConfigID},\n\t\tfunc(cfg *runtime.WatchdogTimerConfig, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\n\t\t\t\t\"/dev/watchdog0\",\n\t\t\t\tcfg.TypedSpec().Device,\n\t\t\t)\n\t\t\tasrt.Equal(\n\t\t\t\truntimecfg.DefaultWatchdogTimeout,\n\t\t\t\tcfg.TypedSpec().Timeout,\n\t\t\t)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/api.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\tstdlibx509 \"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/gen\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// APIController manages secrets.API based on configuration to provide apid certificate.\ntype APIController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *APIController) Name() string {\n\treturn \"secrets.APIController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *APIController) Inputs() []controller.Input {\n\t// initial set of inputs: wait for machine type to be known and network to be partially configured\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *APIController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.APIType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// errMachineTypeChanged is used to signal that machine type has changed, and the current reconcile loop should be aborted, and restarted with new machine type.\nvar errMachineTypeChanged = errors.New(\"machine type changed\")\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *APIController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// reset inputs back to what they were initially\n\t\tif err := r.UpdateInputs(ctrl.Inputs()); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\t// Default to machine.TypeUnknown here (zero value).\n\t\tvar machineType machine.Type\n\n\t\tif machineTypeRes != nil {\n\t\t\tmachineType = machineTypeRes.MachineType()\n\t\t}\n\n\t\tnetworkResource, err := safe.ReaderGet[*network.Status](ctx, r, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkStatus := networkResource.TypedSpec()\n\n\t\tif !networkStatus.AddressReady {\n\t\t\tcontinue\n\t\t}\n\n\t\t// machine type is known and network is ready, we can now proceed to one or another reconcile loop\n\t\tswitch machineType {\n\t\tcase machine.TypeInit, machine.TypeControlPlane:\n\t\t\terr = ctrl.reconcile(ctx, r, logger, true)\n\t\tcase machine.TypeWorker:\n\t\t\terr = ctrl.reconcile(ctx, r, logger, false)\n\t\tcase machine.TypeUnknown:\n\t\t\t// maintenance mode configuration, use maintenance service root CA, and skip client verification\n\t\t\terr = ctrl.reconcileMaintenance(ctx, r, logger)\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unexpected machine type %v\", machineType))\n\t\t}\n\n\t\tif err != nil {\n\t\t\t// this is expected error, we just need to restart the reconcile loop\n\t\t\t// the teardownAll below will take care of tearing down current API secrets\n\t\t\tif !errors.Is(err, errMachineTypeChanged) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tr.QueueReconcile()\n\t\t}\n\n\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo,cyclop,dupl\nfunc (ctrl *APIController) reconcile(ctx context.Context, r controller.Runtime, logger *zap.Logger, isControlplane bool) error {\n\tinputs := []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.OSRootType,\n\t\t\tID:        optional.Some(secrets.OSRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.CertSANType,\n\t\t\tID:        optional.Some(secrets.CertSANAPIID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t// time status isn't fetched, but the fact that it is in dependencies means\n\t\t// that certs will be regenerated on time sync/jump (as reconcile will be triggered)\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      timeresource.StatusType,\n\t\t\tID:        optional.Some(timeresource.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n\n\tif !isControlplane {\n\t\t// worker nodes depend on endpoint list\n\t\tinputs = append(inputs, controller.Input{\n\t\t\tNamespace: k8s.ControlPlaneNamespaceName,\n\t\t\tType:      k8s.EndpointType,\n\t\t\tKind:      controller.InputWeak,\n\t\t})\n\t}\n\n\tif err := r.UpdateInputs(inputs); err != nil {\n\t\treturn fmt.Errorf(\"error updating inputs: %w\", err)\n\t}\n\n\tr.QueueReconcile()\n\n\trefreshTicker := time.NewTicker(x509.DefaultCertificateValidityDuration / 2)\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-refreshTicker.C:\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tvar machineType machine.Type\n\n\t\tif machineTypeRes != nil {\n\t\t\tmachineType = machineTypeRes.MachineType()\n\t\t}\n\n\t\tswitch machineType {\n\t\tcase machine.TypeInit, machine.TypeControlPlane:\n\t\t\tif !isControlplane {\n\t\t\t\treturn errMachineTypeChanged\n\t\t\t}\n\t\tcase machine.TypeWorker:\n\t\t\tif isControlplane {\n\t\t\t\treturn errMachineTypeChanged\n\t\t\t}\n\t\tcase machine.TypeUnknown:\n\t\t\treturn errMachineTypeChanged\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unexpected machine type %v\", machineType))\n\t\t}\n\n\t\trootResource, err := safe.ReaderGet[*secrets.OSRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.OSRootType, secrets.OSRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd root secrets: %w\", err)\n\t\t}\n\n\t\trootSpec := rootResource.TypedSpec()\n\n\t\tcertSANResource, err := safe.ReaderGet[*secrets.CertSAN](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, secrets.CertSANAPIID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting certSANs: %w\", err)\n\t\t}\n\n\t\tcertSANs := certSANResource.TypedSpec()\n\n\t\tvar endpointsStr []string\n\n\t\tif !isControlplane {\n\t\t\tendpointResources, err := r.List(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.EndpointType, \"\", resource.VersionUndefined))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error getting endpoints resources: %w\", err)\n\t\t\t}\n\n\t\t\tvar endpointAddrs k8s.EndpointList\n\n\t\t\t// merge all endpoints into a single list\n\t\t\tfor _, res := range endpointResources.Items {\n\t\t\t\tendpointAddrs = endpointAddrs.Merge(res.(*k8s.Endpoint))\n\t\t\t}\n\n\t\t\tif endpointAddrs.IsEmpty() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tendpointsStr = endpointAddrs.Strings()\n\t\t}\n\n\t\tif isControlplane {\n\t\t\tif err := ctrl.generateControlPlane(ctx, r, logger, rootSpec, certSANs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tif err := ctrl.generateWorker(ctx, r, logger, rootSpec, endpointsStr, certSANs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *APIController) generateControlPlane(ctx context.Context, r controller.Runtime, logger *zap.Logger, rootSpec *secrets.OSRootSpec, certSANs *secrets.CertSANSpec) error {\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(rootSpec.IssuingCA)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tserverCert, err := x509.NewKeyPair(ca,\n\t\tx509.IPAddresses(certSANs.StdIPs()),\n\t\tx509.DNSNames(certSANs.DNSNames),\n\t\tx509.CommonName(certSANs.FQDN),\n\t\tx509.NotAfter(time.Now().Add(x509.DefaultCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate API server cert: %w\", err)\n\t}\n\n\tclientCert, err := x509.NewKeyPair(ca,\n\t\tx509.CommonName(certSANs.FQDN),\n\t\tx509.Organization(string(role.Impersonator)),\n\t\tx509.NotAfter(time.Now().Add(x509.DefaultCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate API client cert: %w\", err)\n\t}\n\n\tif err := safe.WriterModify(ctx, r, secrets.NewAPI(),\n\t\tfunc(r *secrets.API) error {\n\t\t\tapiSecrets := r.TypedSpec()\n\n\t\t\tapiSecrets.AcceptedCAs = rootSpec.AcceptedCAs\n\t\t\tapiSecrets.Server = x509.NewCertificateAndKeyFromKeyPair(serverCert)\n\t\t\tapiSecrets.Client = x509.NewCertificateAndKeyFromKeyPair(clientCert)\n\t\t\tapiSecrets.SkipVerifyingClientCert = false\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t}\n\n\tclientFingerprint, _ := x509.SPKIFingerprintFromDER(clientCert.Certificate.Certificate[0]) //nolint:errcheck\n\tserverFingerprint, _ := x509.SPKIFingerprintFromDER(serverCert.Certificate.Certificate[0]) //nolint:errcheck\n\n\tlogger.Debug(\"generated new certificates\",\n\t\tzap.Stringer(\"client\", clientFingerprint),\n\t\tzap.Stringer(\"server\", serverFingerprint),\n\t)\n\n\treturn nil\n}\n\nfunc (ctrl *APIController) generateWorker(ctx context.Context, r controller.Runtime, logger *zap.Logger,\n\trootSpec *secrets.OSRootSpec, endpointsStr []string, certSANs *secrets.CertSANSpec,\n) error {\n\tremoteGen, err := gen.NewRemoteGenerator(rootSpec.Token, endpointsStr, rootSpec.AcceptedCAs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed creating trustd client: %w\", err)\n\t}\n\n\tdefer remoteGen.Close() //nolint:errcheck\n\n\t// use the last CA in the list of accepted CAs as a template\n\tif len(rootSpec.AcceptedCAs) == 0 {\n\t\treturn errors.New(\"no accepted CAs\")\n\t}\n\n\tacceptedCA, err := rootSpec.AcceptedCAs[len(rootSpec.AcceptedCAs)-1].GetCert()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tserverCSR, serverCert, err := x509.NewCSRAndIdentityFromCA(\n\t\tacceptedCA,\n\t\tx509.IPAddresses(certSANs.StdIPs()),\n\t\tx509.DNSNames(certSANs.DNSNames),\n\t\tx509.CommonName(certSANs.FQDN),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate API server CSR: %w\", err)\n\t}\n\n\tlogger.Debug(\"sending CSR\", zap.Strings(\"endpoints\", endpointsStr))\n\n\tvar ca []byte\n\n\t// run the CSR generation in a goroutine, so we can abort the request if the inputs change\n\terrCh := make(chan error)\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tgo func() {\n\t\tca, serverCert.Crt, err = remoteGen.IdentityContext(ctx, serverCSR)\n\t\terrCh <- err\n\t}()\n\n\tselect {\n\tcase <-r.EventCh():\n\t\t// there's an update to the inputs, terminate the attempt, and let the controller handle the retry\n\t\tcancel()\n\n\t\t// re-queue the reconcile event, so that controller retries with new inputs\n\t\tr.QueueReconcile()\n\n\t\t// wait for the goroutine to finish, ignoring the error (should be context.Canceled)\n\t\t<-errCh\n\n\t\treturn nil\n\tcase err = <-errCh:\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to sign API server CSR: %w\", err)\n\t}\n\n\tif err := safe.WriterModify(ctx, r, secrets.NewAPI(),\n\t\tfunc(r *secrets.API) error {\n\t\t\tapiSecrets := r.TypedSpec()\n\n\t\t\tapiSecrets.AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t\t\t{\n\t\t\t\t\tCrt: ca,\n\t\t\t\t},\n\t\t\t}\n\t\t\tapiSecrets.Client = nil\n\t\t\tapiSecrets.Server = serverCert\n\t\t\tapiSecrets.SkipVerifyingClientCert = false\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t}\n\n\tserverFingerprint, _ := x509.SPKIFingerprintFromPEM(serverCert.Crt) //nolint:errcheck\n\n\tlogger.Debug(\"generated new certificates\",\n\t\tzap.Stringer(\"server\", serverFingerprint),\n\t)\n\n\treturn nil\n}\n\n//nolint:dupl,gocyclo\nfunc (ctrl *APIController) reconcileMaintenance(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tinputs := []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.MaintenanceRootType,\n\t\t\tID:        optional.Some(secrets.MaintenanceRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.CertSANType,\n\t\t\tID:        optional.Some(secrets.CertSANMaintenanceID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t// time status isn't fetched, but the fact that it is in dependencies means\n\t\t// that certs will be regenerated on time sync/jump (as reconcile will be triggered)\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      timeresource.StatusType,\n\t\t\tID:        optional.Some(timeresource.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n\n\tif err := r.UpdateInputs(inputs); err != nil {\n\t\treturn fmt.Errorf(\"error updating inputs: %w\", err)\n\t}\n\n\tr.QueueReconcile()\n\n\trefreshTicker := time.NewTicker(x509.DefaultCertificateValidityDuration / 2)\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-refreshTicker.C:\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tvar machineType machine.Type\n\n\t\tif machineTypeRes != nil {\n\t\t\tmachineType = machineTypeRes.MachineType()\n\t\t}\n\n\t\tif machineType != machine.TypeUnknown {\n\t\t\treturn errMachineTypeChanged\n\t\t}\n\n\t\trootSecrets, err := safe.ReaderGetByID[*secrets.MaintenanceRoot](ctx, r, secrets.MaintenanceRootID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting maintenance root secrets: %w\", err)\n\t\t}\n\n\t\tcertSANs, err := safe.ReaderGetByID[*secrets.CertSAN](ctx, r, secrets.CertSANMaintenanceID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting certSANs: %w\", err)\n\t\t}\n\n\t\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(rootSecrets.TypedSpec().CA)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t\t}\n\n\t\tserverCert, err := x509.NewKeyPair(ca,\n\t\t\tx509.IPAddresses(certSANs.TypedSpec().StdIPs()),\n\t\t\tx509.DNSNames(certSANs.TypedSpec().DNSNames),\n\t\t\tx509.CommonName(certSANs.TypedSpec().FQDN),\n\t\t\tx509.NotAfter(time.Now().Add(x509.DefaultCertificateValidityDuration)),\n\t\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature),\n\t\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t\t}),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate maintenance server cert: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, secrets.NewAPI(),\n\t\t\tfunc(r *secrets.API) error {\n\t\t\t\tapiSecrets := r.TypedSpec()\n\n\t\t\t\tapiSecrets.AcceptedCAs = nil\n\t\t\t\tapiSecrets.Client = nil\n\t\t\t\tapiSecrets.Server = x509.NewCertificateAndKeyFromKeyPair(serverCert)\n\t\t\t\tapiSecrets.SkipVerifyingClientCert = true\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\tserverFingerprint, _ := x509.SPKIFingerprintFromDER(serverCert.Certificate.Certificate[0]) //nolint:errcheck\n\n\t\tlogger.Debug(\"generated new certificates\",\n\t\t\tzap.Stringer(\"server\", serverFingerprint),\n\t\t)\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *APIController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.APIType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range list.Items {\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/api_cert_sans.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// APICertSANsController manages secrets.APICertSANs based on configuration.\ntype APICertSANsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *APICertSANsController) Name() string {\n\treturn \"secrets.APICertSANsController\"\n}\n\n// Inputs implements controller.Controller interface.\n//\n//nolint:dupl\nfunc (ctrl *APICertSANsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.OSRootType,\n\t\t\tID:        optional.Some(secrets.OSRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *APICertSANsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.CertSANType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *APICertSANsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tapiRootRes, err := safe.ReaderGet[*secrets.OSRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.OSRootType, secrets.OSRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting root k8s secrets: %w\", err)\n\t\t}\n\n\t\tapiRoot := apiRootRes.TypedSpec()\n\n\t\thostnameResource, err := safe.ReaderGet[*network.HostnameStatus](ctx, r, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\thostnameStatus := hostnameResource.TypedSpec()\n\n\t\taddressesResource, err := safe.ReaderGet[*network.NodeAddress](ctx, r,\n\t\t\tresource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s), resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnodeAddresses := addressesResource.TypedSpec()\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANAPIID), func(r *secrets.CertSAN) error {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tspec.Reset()\n\n\t\t\tspec.AppendIPs(apiRoot.CertSANIPs...)\n\t\t\tspec.AppendIPs(nodeAddresses.IPs()...)\n\n\t\t\tspec.AppendDNSNames(apiRoot.CertSANDNSNames...)\n\t\t\tspec.AppendDNSNames(hostnameStatus.Hostname, hostnameStatus.FQDN())\n\n\t\t\tspec.FQDN = hostnameStatus.FQDN()\n\n\t\t\tspec.Sort()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *APICertSANsController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range list.Items {\n\t\tif res.Metadata().Owner() == ctrl.Name() {\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/api_cert_sans_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestAPICertSANsSuite(t *testing.T) {\n\tsuite.Run(t, &APICertSANsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.APICertSANsController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype APICertSANsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *APICertSANsSuite) TestReconcileControlPlane() {\n\trootSecrets := secrets.NewOSRoot(secrets.OSRootID)\n\n\trootSecrets.TypedSpec().CertSANDNSNames = []string{\"some.org\"}\n\trootSecrets.TypedSpec().CertSANIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"bar\"\n\thostnameStatus.TypedSpec().Domainname = \"some.org\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\tnodeAddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s),\n\t)\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.2.1.3/24\"),\n\t\tnetip.MustParsePrefix(\"172.16.0.1/32\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses))\n\n\tsuite.AssertWithin(10*time.Second, 100*time.Millisecond, func() error {\n\t\tcertSANs, err := ctest.Get[*secrets.CertSAN](\n\t\t\tsuite,\n\t\t\tresource.NewMetadata(\n\t\t\t\tsecrets.NamespaceName,\n\t\t\t\tsecrets.CertSANType,\n\t\t\t\tsecrets.CertSANAPIID,\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tspec := certSANs.TypedSpec()\n\n\t\tsuite.Assert().Equal([]string{\"bar\", \"bar.some.org\", \"some.org\"}, spec.DNSNames)\n\t\tsuite.Assert().Equal(\"[10.2.1.3 10.4.3.2 172.16.0.1]\", fmt.Sprintf(\"%v\", spec.IPs))\n\t\tsuite.Assert().Equal(\"bar.some.org\", spec.FQDN)\n\n\t\treturn nil\n\t})\n\n\tctest.UpdateWithConflicts(suite, rootSecrets, func(rootSecrets *secrets.OSRoot) error {\n\t\trootSecrets.TypedSpec().CertSANDNSNames = []string{\"other.org\"}\n\n\t\treturn nil\n\t})\n\n\tsuite.AssertWithin(10*time.Second, 100*time.Millisecond, func() error {\n\t\tcertSANs, err := ctest.Get[*secrets.CertSAN](\n\t\t\tsuite,\n\t\t\tresource.NewMetadata(\n\t\t\t\tsecrets.NamespaceName,\n\t\t\t\tsecrets.CertSANType,\n\t\t\t\tsecrets.CertSANAPIID,\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tspec := certSANs.TypedSpec()\n\n\t\texpectedDNSNames := []string{\"bar\", \"bar.some.org\", \"other.org\"}\n\n\t\tif !slices.Equal(expectedDNSNames, spec.DNSNames) {\n\t\t\treturn retry.ExpectedErrorf(\"expected %v, got %v\", expectedDNSNames, spec.DNSNames)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/api_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nfunc TestAPISuite(t *testing.T) {\n\tsuite.Run(t, &APISuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.APIController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype APISuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *APISuite) TestReconcileControlPlane() {\n\trootSecrets := secrets.NewOSRoot(secrets.OSRootID)\n\n\ttalosCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"talos\"),\n\t)\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().IssuingCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: talosCA.CrtPEM,\n\t\tKey: talosCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t{\n\t\t\tCrt: talosCA.CrtPEM,\n\t\t},\n\t}\n\trootSecrets.TypedSpec().CertSANDNSNames = []string{\"example.com\"}\n\trootSecrets.TypedSpec().CertSANIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\trootSecrets.TypedSpec().Token = \"something\"\n\tsuite.Create(rootSecrets)\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Create(machineType)\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tsuite.Create(networkStatus)\n\n\tcertSANs := secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANAPIID)\n\tcertSANs.TypedSpec().Append(\n\t\t\"example.com\",\n\t\t\"foo\",\n\t\t\"foo.example.com\",\n\t\t\"10.2.1.3\",\n\t\t\"10.4.3.2\",\n\t\t\"172.16.0.1\",\n\t)\n\n\tcertSANs.TypedSpec().FQDN = \"foo.example.com\"\n\tsuite.Create(certSANs)\n\n\tctest.AssertResource(suite, secrets.APIID,\n\t\tfunc(certs *secrets.API, asrt *assert.Assertions) {\n\t\t\tapiCerts := certs.TypedSpec()\n\n\t\t\tasrt.Equal(\n\t\t\t\t[]*x509.PEMEncodedCertificate{\n\t\t\t\t\t{\n\t\t\t\t\t\tCrt: talosCA.CrtPEM,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tapiCerts.AcceptedCAs,\n\t\t\t)\n\n\t\t\tserverCert, err := apiCerts.Server.GetCert()\n\t\t\tif !asrt.NoError(err) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tasrt.Equal([]string{\"example.com\", \"foo\", \"foo.example.com\"}, serverCert.DNSNames)\n\t\t\tasrt.Equal(\"[10.2.1.3 10.4.3.2 172.16.0.1]\", fmt.Sprintf(\"%v\", serverCert.IPAddresses))\n\n\t\t\tasrt.Equal(\"foo.example.com\", serverCert.Subject.CommonName)\n\t\t\tasrt.Empty(serverCert.Subject.Organization)\n\n\t\t\tasrt.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature,\n\t\t\t\tserverCert.KeyUsage,\n\t\t\t)\n\t\t\tasrt.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage)\n\n\t\t\tclientCert, err := apiCerts.Client.GetCert()\n\t\t\tif !asrt.NoError(err) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tasrt.Empty(clientCert.DNSNames)\n\t\t\tasrt.Empty(clientCert.IPAddresses)\n\n\t\t\tasrt.Equal(\"foo.example.com\", clientCert.Subject.CommonName)\n\t\t\tasrt.Equal([]string{string(role.Impersonator)}, clientCert.Subject.Organization)\n\n\t\t\tasrt.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature,\n\t\t\t\tclientCert.KeyUsage,\n\t\t\t)\n\t\t\tasrt.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage)\n\n\t\t\tasrt.False(apiCerts.SkipVerifyingClientCert)\n\t\t},\n\t)\n\n\t// destroy machine type, mocking transition to maintenance mode\n\tsuite.Destroy(machineType)\n\n\tctest.AssertNoResource[*secrets.API](suite, secrets.APIID)\n}\n\nfunc (suite *APISuite) TestReconcileMaintenance() {\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceRootController{}))\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tsuite.Create(networkStatus)\n\n\tcertSANs := secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANMaintenanceID)\n\tcertSANs.TypedSpec().Append(\n\t\t\"example.com\",\n\t\t\"10.2.1.3\",\n\t)\n\tcertSANs.TypedSpec().FQDN = constants.MaintenanceServiceCommonName\n\tsuite.Create(certSANs)\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeUnknown)\n\tsuite.Create(machineType)\n\n\tctest.AssertResource(suite, secrets.APIID,\n\t\tfunc(certs *secrets.API, asrt *assert.Assertions) {\n\t\t\tapiCerts := certs.TypedSpec()\n\n\t\t\tasrt.True(apiCerts.SkipVerifyingClientCert)\n\t\t\tasrt.Nil(apiCerts.Client)\n\t\t\tasrt.Nil(apiCerts.AcceptedCAs)\n\n\t\t\tserverCert, err := apiCerts.Server.GetCert()\n\t\t\tif !asrt.NoError(err) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tasrt.Equal([]string{\"example.com\"}, serverCert.DNSNames)\n\t\t\tasrt.Equal(\"[10.2.1.3]\", fmt.Sprintf(\"%v\", serverCert.IPAddresses))\n\n\t\t\tasrt.Equal(constants.MaintenanceServiceCommonName, serverCert.Subject.CommonName)\n\t\t\tasrt.Empty(serverCert.Subject.Organization)\n\n\t\t\tasrt.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature,\n\t\t\t\tserverCert.KeyUsage,\n\t\t\t)\n\t\t\tasrt.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage)\n\t\t},\n\t)\n\n\t// create machine type, mocking transition to control plane mode\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Update(machineType)\n\n\tctest.AssertNoResource[*secrets.API](suite, secrets.APIID)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/data/ca-certificates",
    "content": "##\n## Bundle of CA Root Certificates\n##\n## Certificate data from Mozilla as of: Tue Dec  2 04:12:02 2025 GMT\n##\n## Find updated versions here: https://curl.se/docs/caextract.html\n##\n## This is a bundle of X.509 certificates of public Certificate Authorities\n## (CA). These were automatically extracted from Mozilla's root certificates\n## file (certdata.txt).  This file can be found in the mozilla source tree:\n## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt\n##\n## It contains the certificates in PEM format and therefore\n## can be directly used with curl / libcurl / php_curl, or with\n## an Apache+mod_ssl webserver for SSL client authentication.\n## Just configure this file as the SSLCACertificateFile.\n##\n## Conversion done with mk-ca-bundle.pl version 1.30.\n## SHA256: a903b3cd05231e39332515ef7ebe37e697262f39515a52015c23c62805b73cd0\n##\n\n\nEntrust Root Certification Authority\n====================================\n-----BEGIN CERTIFICATE-----\nMIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV\nBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw\nb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG\nA1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0\nMloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu\nMTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu\nY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v\ndCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz\nA9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww\nCj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68\nj6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN\nrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw\nDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1\nMzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH\nhmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\nA4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM\nY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa\nv52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS\nW3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0\ntHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 2\n==================\n-----BEGIN CERTIFICATE-----\nMIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\nEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx\nODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\naW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6\nXJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk\nlvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB\nlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy\nlZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt\n66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn\nwQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh\nD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy\nBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie\nJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud\nDgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU\na6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\nElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv\nZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3\nUIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm\nVjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK\n+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW\nIozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1\nWVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X\nf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II\n4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8\nVCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 3\n==================\n-----BEGIN CERTIFICATE-----\nMIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\nEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx\nOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\naW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg\nDhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij\nKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K\nDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv\nBNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp\np5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8\nnT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX\nMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM\nGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz\nuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT\nBgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj\nYXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\naWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB\nBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD\nVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4\nywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE\nAxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV\nqyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s\nhvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z\nPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2\nPb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp\n8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC\nbjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu\ng/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p\nvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr\nqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root CA\n===========================\n-----BEGIN CERTIFICATE-----\nMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\nIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx\nMTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\nExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO\n9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy\nUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW\n/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy\noeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf\nGHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF\n66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq\nhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc\nEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn\nSbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i\n8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n-----END CERTIFICATE-----\n\nDigiCert Global Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\nHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw\nMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\ndy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn\nTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5\nBmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H\n4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y\n7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB\no2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm\n8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF\nBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr\nEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt\ntep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886\nUAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\nCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n-----END CERTIFICATE-----\n\nDigiCert High Assurance EV Root CA\n==================================\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw\nKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw\nMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ\nMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu\nY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t\nMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS\nOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3\nMRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ\nNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe\nh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB\nAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY\nJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ\nV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp\nmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK\nmNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\nvEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\n-----END CERTIFICATE-----\n\nSwissSign Gold CA - G2\n======================\n-----BEGIN CERTIFICATE-----\nMIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw\nEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN\nMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp\nc3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq\nt2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C\njCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg\nvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF\nylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR\nAiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend\njIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO\npeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR\n7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi\nGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw\nAwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64\nOfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov\nL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm\n5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr\n44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf\nMke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m\nGu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp\nmo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk\nvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf\nKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br\nNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj\nviOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ\n-----END CERTIFICATE-----\n\nSecureTrust CA\n==============\n-----BEGIN CERTIFICATE-----\nMIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG\nEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy\ndXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe\nBgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX\nOZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t\nDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH\nGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b\n01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH\nursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/\nBAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj\naHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\nKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu\nSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf\nmbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ\nnMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR\n3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\n-----END CERTIFICATE-----\n\nSecure Global CA\n================\n-----BEGIN CERTIFICATE-----\nMIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG\nEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH\nbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg\nMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg\nQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx\nYDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ\nbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g\n8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV\nHDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi\n0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\nEwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn\noCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA\nMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+\nOYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn\nCDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5\n3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc\nf8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\n-----END CERTIFICATE-----\n\nCOMODO Certification Authority\n==============================\n-----BEGIN CERTIFICATE-----\nMIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE\nBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\nA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1\ndGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb\nMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD\nT01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH\n+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww\nxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV\n4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA\n1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI\nrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k\nb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC\nAQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP\nOGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\nRxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc\nIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN\n+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==\n-----END CERTIFICATE-----\n\nCOMODO ECC Certification Authority\n==================================\n-----BEGIN CERTIFICATE-----\nMIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC\nR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\nChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix\nGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\nQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo\nb3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X\n4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni\nwz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG\nFAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA\nU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n-----END CERTIFICATE-----\n\nCertigna\n========\n-----BEGIN CERTIFICATE-----\nMIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw\nEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3\nMDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI\nQ2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q\nXOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH\nGxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p\nogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg\nDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf\nIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ\ntCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ\nBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J\nSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA\nhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+\nImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu\nPBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY\n1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw\nWyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\n-----END CERTIFICATE-----\n\nePKI Root Certification Authority\n=================================\n-----BEGIN CERTIFICATE-----\nMIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG\nEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg\nUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx\nMjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq\nMCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs\nIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi\nlTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv\nqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX\n12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O\nWQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+\nETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao\nlQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/\nvv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi\nZo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi\nMAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH\nClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0\n1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\nKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV\nxrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP\nNXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r\nGNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE\nxJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx\ngMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy\nsP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD\nBCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=\n-----END CERTIFICATE-----\n\ncertSIGN ROOT CA\n================\n-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD\nVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa\nFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE\nCxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I\nJUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH\nrfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2\nssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD\n0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943\nAAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\nAf8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB\nAQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8\nSG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0\nx2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt\nvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz\nTogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD\n-----END CERTIFICATE-----\n\nNetLock Arany (Class Gold) Főtanúsítvány\n========================================\n-----BEGIN CERTIFICATE-----\nMIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G\nA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610\ndsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB\ncmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx\nMjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO\nZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv\nbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6\nc8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu\n0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw\n/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk\nH3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw\nfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1\nneWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB\nBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW\nqZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta\nYtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC\nbLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna\nNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu\ndZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\n-----END CERTIFICATE-----\n\nMicrosec e-Szigno Root CA 2009\n==============================\n-----BEGIN CERTIFICATE-----\nMIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER\nMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv\nc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o\ndTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE\nBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt\nU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA\nfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG\n0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA\npxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm\n1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC\nAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf\nQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE\nFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o\nlZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX\nI/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775\ntyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02\nyULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi\nLXpUq3DDfSJlgnCW\n-----END CERTIFICATE-----\n\nGlobalSign Root CA - R3\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv\nYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\nbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\naWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\nbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt\niHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ\n0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3\nrHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl\nOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2\nxmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\nFI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7\nlgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8\nEpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E\nbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18\nYIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r\nkpeDMdmztcpHWD9f\n-----END CERTIFICATE-----\n\nIzenpe.com\n==========\n-----BEGIN CERTIFICATE-----\nMIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG\nEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz\nMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu\nQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ\n03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK\nClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU\n+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC\nPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT\nOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK\nF7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK\n0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+\n0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB\nleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID\nAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+\nSVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG\nNjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx\nMCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\nBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\nFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga\nkEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q\nhT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs\ng1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5\naTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5\nnXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC\nClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo\nQ0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z\nWrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==\n-----END CERTIFICATE-----\n\nGo Daddy Root Certificate Authority - G2\n========================================\n-----BEGIN CERTIFICATE-----\nMIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu\nMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\nMDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\nb25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G\nA1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\nhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq\n9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD\n+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd\nfMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl\nNAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC\nMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9\nBUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac\nvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r\n5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV\nN8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\nLPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1\n-----END CERTIFICATE-----\n\nStarfield Root Certificate Authority - G2\n=========================================\n-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\nb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0\neSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw\nDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg\nVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB\ndXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv\nW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs\nbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk\nN3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf\nZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU\nJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol\nTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx\n4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw\nF5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\npL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ\nc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n-----END CERTIFICATE-----\n\nStarfield Services Root Certificate Authority - G2\n==================================================\n-----BEGIN CERTIFICATE-----\nMIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\nB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\nb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl\nIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV\nBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT\ndGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg\nUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2\nh/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa\nhHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP\nLJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB\nrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG\nSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP\nE95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy\nxQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\niEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza\nYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6\n-----END CERTIFICATE-----\n\nAffirmTrust Commercial\n======================\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw\nMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\nbVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb\nDuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV\nC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6\nBfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww\nMmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV\nHQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG\nhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi\nqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv\n0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh\nsUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n-----END CERTIFICATE-----\n\nAffirmTrust Networking\n======================\n-----BEGIN CERTIFICATE-----\nMIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw\nMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\nbVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE\nHi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI\ndIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24\n/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb\nh+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV\nHQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu\nUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6\n12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23\nWJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9\n/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n-----END CERTIFICATE-----\n\nAffirmTrust Premium\n===================\n-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS\nBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy\nOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy\ndXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn\nBKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV\n5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs\n+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd\nGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R\np9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI\nS+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04\n6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5\n/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo\n+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB\n/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv\nMiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\nNt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC\n6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S\nL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK\n+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV\nBtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg\nIxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60\ng2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb\nzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==\n-----END CERTIFICATE-----\n\nAffirmTrust Premium ECC\n=======================\n-----BEGIN CERTIFICATE-----\nMIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV\nBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx\nMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U\ncnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ\nN8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW\nBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK\nBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X\n57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM\neQ==\n-----END CERTIFICATE-----\n\nCertum Trusted Network CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK\nExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy\nMTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU\nZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nMSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC\nl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J\nJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4\nfOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0\ncvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB\nAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw\nDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj\njSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1\nmS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj\nZt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI\n03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\n-----END CERTIFICATE-----\n\nTWCA Root Certification Authority\n=================================\n-----BEGIN CERTIFICATE-----\nMIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ\nVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG\nEwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB\nIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx\nQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC\noi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP\n4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r\ny+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB\nBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG\n9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC\nmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW\nQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY\nT0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny\nYh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\n-----END CERTIFICATE-----\n\nSecurity Communication RootCA2\n==============================\n-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\nU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh\ndGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC\nSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy\naXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++\n+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R\n3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV\nspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K\nEOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8\nQIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\nCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj\nu/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk\n3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q\ntnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29\nmvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\n-----END CERTIFICATE-----\n\nActalis Authentication Root CA\n==============================\n-----BEGIN CERTIFICATE-----\nMIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM\nBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE\nAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky\nMjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz\nIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290\nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ\nwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa\nby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6\nzfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f\nYVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2\noxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l\nEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7\nhNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8\nEBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5\njF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY\niDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt\nifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI\nWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0\nJZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx\nK3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+\nXlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC\n4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo\n2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz\nlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem\nOR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9\nvwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==\n-----END CERTIFICATE-----\n\nBuypass Class 2 Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\nQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X\nDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\neXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1\ng1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn\n9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b\n/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU\nCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff\nawrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI\nzRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn\nBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX\nUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs\nM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\nAAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s\nA20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI\nosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S\naq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd\nDnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD\nLfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0\noyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC\nwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS\nCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN\nrJgWVqA=\n-----END CERTIFICATE-----\n\nBuypass Class 3 Root CA\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\nQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X\nDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\neXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH\nsJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR\n5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh\n7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ\nZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH\n2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV\n/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ\nRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA\nXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq\nj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\nAAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV\ncSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G\nuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG\nQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8\nZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2\nKSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz\n6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug\nUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe\neOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi\nCp/HuZc=\n-----END CERTIFICATE-----\n\nT-TeleSec GlobalRoot Class 3\n============================\n-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\nIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\ncnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx\nMDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\ndGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\nZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK\n9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU\nNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF\niP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W\n0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr\nAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb\nfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT\nucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h\nP0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml\ne9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==\n-----END CERTIFICATE-----\n\nD-TRUST Root Class 3 CA 2 2009\n==============================\n-----BEGIN CERTIFICATE-----\nMIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe\nFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE\nLVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw\nDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD\nER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA\nBF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv\nKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z\np+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC\nAwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ\n4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y\neS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw\nMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G\nPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw\nOS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm\n2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0\no3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV\ndT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph\nX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=\n-----END CERTIFICATE-----\n\nD-TRUST Root Class 3 CA 2 EV 2009\n=================================\n-----BEGIN CERTIFICATE-----\nMIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\nOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\nDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\nOTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS\negpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh\nzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T\n7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60\nsUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35\n11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv\ncop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v\nZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El\nMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp\nb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh\nc3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+\nPPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05\nnsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX\nANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA\nNCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv\nw9y4AyHqnxbxLFS1\n-----END CERTIFICATE-----\n\nCA Disig Root R2\n================\n-----BEGIN CERTIFICATE-----\nMIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw\nEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\nZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx\nEzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\nc2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC\nw3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia\nxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7\nA7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S\nGBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV\ng8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa\n5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE\nkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A\nAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i\nFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV\nHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u\nQu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM\ntCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV\nsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je\ndR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8\n1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx\nmHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01\nutI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0\nsorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg\nUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV\n7+ZtsH8tZ/3zbBt1RqPlShfppNcL\n-----END CERTIFICATE-----\n\nACCVRAIZ1\n=========\n-----BEGIN CERTIFICATE-----\nMIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB\nSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1\nMDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH\nUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM\njmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0\nRGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD\naaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ\n0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG\nWuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7\n8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR\n5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J\n9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK\nQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw\nOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu\nY3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2\nVuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM\nHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA\nQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh\nAO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA\nYwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj\nAHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA\nIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk\naHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0\ndHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2\nMV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI\nhvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E\nR9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN\nYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49\nnCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ\nTS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3\nsCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\nI6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg\nNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd\n3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p\nEfbRD0tVNEYqi4Y7\n-----END CERTIFICATE-----\n\nTWCA Global Root CA\n===================\n-----BEGIN CERTIFICATE-----\nMIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT\nCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD\nQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK\nEwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg\nQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C\nnJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV\nr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR\nQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV\ntTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W\nKKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99\nsy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p\nyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn\nkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI\nzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g\ncFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn\nLhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M\n8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg\n/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg\nlPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP\nA9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m\ni4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8\nEHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3\nzqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=\n-----END CERTIFICATE-----\n\nTeliaSonera Root CA v1\n======================\n-----BEGIN CERTIFICATE-----\nMIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE\nCgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4\nMTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW\nVGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+\n6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA\n3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k\nB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn\nXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH\noLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3\nF0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ\noWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7\ngUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc\nTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB\nAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW\nDNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm\nzqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx\n0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW\npb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV\nG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc\nc41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT\nJsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2\nqReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6\nY2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems\nWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=\n-----END CERTIFICATE-----\n\nT-TeleSec GlobalRoot Class 2\n============================\n-----BEGIN CERTIFICATE-----\nMIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\nIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\ncnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx\nMDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\ndGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\nZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ\nSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F\nvudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970\n2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV\nWOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy\nYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4\nr6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf\nvNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR\n3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN\n9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==\n-----END CERTIFICATE-----\n\nAtos TrustedRoot 2011\n=====================\n-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU\ncnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4\nMzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG\nA1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV\nhTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr\n54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+\nDgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320\nHLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR\nz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R\nl+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ\nbNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\nCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h\nk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh\nTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9\n61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G\n3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 1 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE\nPBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm\nPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6\nPser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN\nofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l\ng6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV\n7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX\n9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f\niyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg\nt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI\nhvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC\nMTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3\nGPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct\nTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP\n+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh\n3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa\nwx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6\nO0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0\nFU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV\nhMJKzRwuJIczYOXD\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 2 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh\nZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY\nNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t\noIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o\nMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l\nV0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo\nL1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ\nsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD\n6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh\nlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI\nhvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66\nAarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K\npVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9\nx52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz\ndWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X\nU/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw\nmNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD\nzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN\nJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr\nO3jtZsSOeWmD3n+M\n-----END CERTIFICATE-----\n\nQuoVadis Root CA 3 G3\n=====================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG\nA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\nb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN\nMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg\nRzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286\nIxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL\nMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe\n6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3\nI4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U\nVDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7\n5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi\nMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM\ndyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt\nrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI\nhvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px\nKGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS\nt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ\nTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du\nDcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib\nIh6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD\nhPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX\n0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW\ndSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2\nPpxxVJkES/1Y+Zj0\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root G2\n===========================\n-----BEGIN CERTIFICATE-----\nMIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\nIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw\nMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\nExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH\n35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq\nbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw\nVWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP\nYLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn\nlTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO\nw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv\n0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz\nd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW\nhsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M\njomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\nIhNzbM8m9Yop5w==\n-----END CERTIFICATE-----\n\nDigiCert Assured ID Root G3\n===========================\n-----BEGIN CERTIFICATE-----\nMIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD\nVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\nMTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb\nRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs\nKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF\nUaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy\nYZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy\n1vUhZscv6pZjamVFkpUBtA==\n-----END CERTIFICATE-----\n\nDigiCert Global Root G2\n=======================\n-----BEGIN CERTIFICATE-----\nMIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\nHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx\nMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\ndy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ\nkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO\n3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV\nBJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM\nUNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB\no0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu\n5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr\nF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U\nWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH\nQRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/\niyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\nMrY=\n-----END CERTIFICATE-----\n\nDigiCert Global Root G3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV\nUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD\nVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw\nMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k\naWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O\nYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP\nBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp\nYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y\n3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34\nVOKa5Vt8sycX\n-----END CERTIFICATE-----\n\nDigiCert Trusted Root G4\n========================\n-----BEGIN CERTIFICATE-----\nMIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG\nEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw\nHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\nMTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp\npz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o\nk3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa\nvOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY\nQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6\nMUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm\nmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7\nf/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH\ndL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8\noR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\nDwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\nggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY\nZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr\nyF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy\n7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah\nixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN\n5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb\n/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa\n5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK\nG48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP\n82Z+\n-----END CERTIFICATE-----\n\nCOMODO RSA Certification Authority\n==================================\n-----BEGIN CERTIFICATE-----\nMIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\nBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\nA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC\nR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\nChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn\ndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ\nFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+\n5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG\nx8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX\n2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL\nOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3\nsgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C\nGCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5\nWdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\nFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt\nrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+\nnq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg\ntZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\nsRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\npC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA\nzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq\nZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52\n7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\nLaZRfyHBNVOFBkpdn627G190\n-----END CERTIFICATE-----\n\nUSERTrust RSA Certification Authority\n=====================================\n-----BEGIN CERTIFICATE-----\nMIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\nExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\nExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\ndGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz\n0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j\nY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn\nRghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O\n+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq\n/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE\nY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM\nlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8\nyexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+\neLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\nBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW\nFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ\n7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ\nEg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM\n8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi\nFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi\nyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c\nJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw\nsAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx\nQ+6IHdfGjjxDah2nGN59PRbxYvnKkKj9\n-----END CERTIFICATE-----\n\nUSERTrust ECC Certification Authority\n=====================================\n-----BEGIN CERTIFICATE-----\nMIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC\nVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\naGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC\nVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\naGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2\n0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez\nnPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV\nHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB\nHU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu\n9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n-----END CERTIFICATE-----\n\nGlobalSign ECC Root CA - R5\n===========================\n-----BEGIN CERTIFICATE-----\nMIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb\nR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\nEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\nR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\nEwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6\nSFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS\nh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\nBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx\nuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7\nyFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3\n-----END CERTIFICATE-----\n\nIdenTrust Commercial Root CA 1\n==============================\n-----BEGIN CERTIFICATE-----\nMIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG\nEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS\nb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES\nMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB\nIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld\nhNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/\nmNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi\n1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C\nXZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl\n3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy\nNeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV\nWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg\nxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix\nuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI\nhvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH\n6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg\nghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt\nozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV\nYjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX\nfeu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro\nkTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe\n2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz\nZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R\ncGzM7vRX+Bi6hG6H\n-----END CERTIFICATE-----\n\nIdenTrust Public Sector Root CA 1\n=================================\n-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG\nEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv\nciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV\nUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS\nb290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy\nP4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6\nHi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI\nrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf\nqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS\nmJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn\nol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh\nLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v\niDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL\n4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B\nAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw\nDQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj\nt2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A\nmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt\nGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt\nm6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx\nNRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4\nMhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI\najjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC\nZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ\n3Wl9af0AVqW3rLatt8o+Ae+c\n-----END CERTIFICATE-----\n\nEntrust Root Certification Authority - G2\n=========================================\n-----BEGIN CERTIFICATE-----\nMIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV\nBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy\nbXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug\nb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw\nHhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT\nDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx\nOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s\neTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP\n/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz\nHHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU\ns/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y\nTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx\nAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6\n0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z\niXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\nRkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi\nnWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+\nvGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO\ne4pIb4tF9g==\n-----END CERTIFICATE-----\n\nEntrust Root Certification Authority - EC1\n==========================================\n-----BEGIN CERTIFICATE-----\nMIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx\nFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn\nYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl\nZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\nIC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw\nFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs\nLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg\ndXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt\nIEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy\nAsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef\n9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\nFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h\nvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8\nkmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n-----END CERTIFICATE-----\n\nCFCA EV ROOT\n============\n-----BEGIN CERTIFICATE-----\nMIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE\nCgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB\nIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw\nMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD\nDAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV\nBU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD\n7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN\nuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW\nZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7\nxzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f\npy25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K\ngWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol\nhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ\ntqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf\nBgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB\n/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\nACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q\necsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua\n4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG\nE5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX\nBDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn\naH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy\nPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX\nkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C\nekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\n-----END CERTIFICATE-----\n\nOISTE WISeKey Global Root GB CA\n===============================\n-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG\nEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl\nZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw\nMzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD\nVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds\nb2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX\nscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP\nrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk\n9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o\nQnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg\nGUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI\nhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD\ndHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0\nVQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui\nHZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic\nNc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=\n-----END CERTIFICATE-----\n\nSZAFIR ROOT CA2\n===============\n-----BEGIN CERTIFICATE-----\nMIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV\nBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ\nBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD\nVQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q\nqEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK\nDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE\n2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ\nckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi\nieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC\nAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5\nO/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67\noPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul\n4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6\n+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==\n-----END CERTIFICATE-----\n\nCertum Trusted Network CA 2\n===========================\n-----BEGIN CERTIFICATE-----\nMIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE\nBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1\nbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y\nayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ\nTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl\ncnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB\nIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9\n7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o\nCgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b\nRr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p\nuTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130\nGO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ\n9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB\nRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye\nhizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM\nBhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI\nhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW\nAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA\nL55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo\nclm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM\npkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb\nw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo\nJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm\nypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX\nis7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7\nzAYspsbiDrW5viSP\n-----END CERTIFICATE-----\n\nHellenic Academic and Research Institutions RootCA 2015\n=======================================================\n-----BEGIN CERTIFICATE-----\nMIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT\nBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0\naW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl\nYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx\nMTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg\nQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV\nBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw\nMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv\nbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh\niGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+\n6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd\nFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr\ni5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F\nGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2\nfu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu\niNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc\nBw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\nAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI\nhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+\nD1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM\nd/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y\nd+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn\n82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb\ndavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F\nJej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt\nJ94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa\nJI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q\np/UsQu0yrbYhnr68\n-----END CERTIFICATE-----\n\nHellenic Academic and Research Institutions ECC RootCA 2015\n===========================================================\n-----BEGIN CERTIFICATE-----\nMIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0\naGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\ncyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj\naCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw\nMzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj\nIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD\nVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290\nQ0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP\ndJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK\nVlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\nBBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA\nGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn\ndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR\n-----END CERTIFICATE-----\n\nISRG Root X1\n============\n-----BEGIN CERTIFICATE-----\nMIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE\nBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD\nEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG\nEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT\nDElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r\nVygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1\n3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K\nb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN\nAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ\n4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf\n1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu\nhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH\nusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r\nOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G\nA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY\n9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\nubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV\n0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt\nhDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw\nTdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx\ne5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA\nJzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD\nYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n\nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ\nm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n-----END CERTIFICATE-----\n\nAC RAIZ FNMT-RCM\n================\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT\nAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw\nMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD\nTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf\nqQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr\nbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL\nj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou\n08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw\nWsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT\ntOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ\n47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC\nll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa\ni0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\nFPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o\ndHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD\nnFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s\nD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ\nj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT\nQfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW\n+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7\nIxjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d\n8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm\n5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG\nrp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=\n-----END CERTIFICATE-----\n\nAmazon Root CA 1\n================\n-----BEGIN CERTIFICATE-----\nMIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD\nVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1\nMDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\nbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH\nFzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ\ngLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t\ndHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce\nVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\n/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3\nDQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM\nCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy\n8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa\n2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2\nxJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\n-----END CERTIFICATE-----\n\nAmazon Root CA 2\n================\n-----BEGIN CERTIFICATE-----\nMIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD\nVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1\nMDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\nbjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\nggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4\nkHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp\nN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9\nAElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd\nfLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx\nkv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS\nbtqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0\nQ5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN\nc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+\n3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw\nDPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA\nA7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\n+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE\nYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW\nxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ\ngj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW\naQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV\nYh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3\nKadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi\nJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=\n-----END CERTIFICATE-----\n\nAmazon Root CA 3\n================\n-----BEGIN CERTIFICATE-----\nMIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG\nEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy\nNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\nMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB\nf8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr\nZt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43\nrDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc\neGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==\n-----END CERTIFICATE-----\n\nAmazon Root CA 4\n================\n-----BEGIN CERTIFICATE-----\nMIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG\nEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy\nNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\nMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN\n/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri\n83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA\nMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1\nAE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n-----END CERTIFICATE-----\n\nTUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT\nD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr\nIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g\nTWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp\nZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD\nVQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt\nc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth\nbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11\nIFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\nMIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8\n6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc\nwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0\n3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9\nWSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU\nZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ\nKoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh\nAHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc\nlNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R\ne37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j\nq5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=\n-----END CERTIFICATE-----\n\nGDCA TrustAUTH R5 ROOT\n======================\n-----BEGIN CERTIFICATE-----\nMIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw\nBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD\nDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow\nYjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ\nIENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B\nAQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs\nAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p\nOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr\npftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ\n9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ\nxXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM\nR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ\nD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4\noR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx\n9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR\nMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg\np8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9\nH5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35\n6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd\n+PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ\nHtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD\nF8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ\n8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv\n/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT\naaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==\n-----END CERTIFICATE-----\n\nSSL.com Root Certification Authority RSA\n========================================\n-----BEGIN CERTIFICATE-----\nMIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM\nBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x\nMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw\nMjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx\nEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM\nLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD\nggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C\nFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8\nP2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge\noeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp\nk8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z\nfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ\ngUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2\nUzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8\n1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s\nbE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV\nHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE\nAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr\ndIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf\nijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl\nu1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq\nerQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj\nMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ\nvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI\nPb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y\nwKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI\nWuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=\n-----END CERTIFICATE-----\n\nSSL.com Root Certification Authority ECC\n========================================\n-----BEGIN CERTIFICATE-----\nMIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV\nBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv\nBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy\nMTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO\nBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv\nbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA\nBEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+\n8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR\nhXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT\njgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW\ne+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z\n5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl\n-----END CERTIFICATE-----\n\nSSL.com EV Root Certification Authority RSA R2\n==============================================\n-----BEGIN CERTIFICATE-----\nMIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w\nDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u\nMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy\nMB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI\nDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD\nVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN\nBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh\nhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w\ncXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO\nZw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+\nB6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh\nCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim\n9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto\nRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm\nJuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48\n+qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV\nHSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp\nqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1\n++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx\nY/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G\nguDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz\nOFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7\nCTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq\nlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR\nrwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1\nhlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX\n9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==\n-----END CERTIFICATE-----\n\nSSL.com EV Root Certification Authority ECC\n===========================================\n-----BEGIN CERTIFICATE-----\nMIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV\nBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy\nBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw\nMjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx\nEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM\nLmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB\nBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy\n3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O\nBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe\n5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ\nN+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm\nm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==\n-----END CERTIFICATE-----\n\nGlobalSign Root CA - R6\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX\nR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i\nYWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs\nU2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss\ngrRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE\n3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF\nvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM\nPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+\nazayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O\nWgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy\nCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP\n0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN\nb7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE\nAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV\nHSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN\nnsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0\nlV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY\nBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym\nFe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr\n3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1\n0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T\nuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK\noZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t\nJDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=\n-----END CERTIFICATE-----\n\nOISTE WISeKey Global Root GC CA\n===============================\n-----BEGIN CERTIFICATE-----\nMIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD\nSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo\nMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa\nFw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL\nExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh\nbCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr\nVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab\nNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\nBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E\nAwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk\nAjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9\n-----END CERTIFICATE-----\n\nUCA Global G2 Root\n==================\n-----BEGIN CERTIFICATE-----\nMIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG\nEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x\nNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU\ncnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\nMIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT\noni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV\n8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS\nh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o\nLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/\nR+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe\nKW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa\n4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc\nOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97\n8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\nBBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo\n5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5\n1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A\nDs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9\nyBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX\nc47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo\njhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk\nbxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x\nygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn\nRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==\n-----END CERTIFICATE-----\n\nUCA Extended Validation Root\n============================\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG\nEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u\nIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G\nA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs\niWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF\nRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu\neUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR\n59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH\n0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR\nel7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv\nB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth\nWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS\nNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS\n3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL\nBQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR\nap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM\naVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4\ndxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb\n+7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW\nF3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi\nGpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc\nGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi\ndjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr\ndhh2n1ax\n-----END CERTIFICATE-----\n\nCertigna Root CA\n================\n-----BEGIN CERTIFICATE-----\nMIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE\nBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ\nMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda\nMFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz\nMDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC\nDwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX\nstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz\nKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8\nJXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16\nXdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq\n4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej\nwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ\nlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI\njzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/\n/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\nHQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of\n1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy\ndGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h\nLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl\ncnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt\nOoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP\nTGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq\n7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3\n4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd\n8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS\n6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY\ntlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS\naX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde\nE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=\n-----END CERTIFICATE-----\n\nemSign Root CA - G1\n===================\n-----BEGIN CERTIFICATE-----\nMIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET\nMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl\nZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx\nODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk\naHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN\nLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1\ncM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW\nDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ\n6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH\nhQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG\nMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2\nvZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q\nNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q\n+Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih\nU80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx\niN66zB+Afko=\n-----END CERTIFICATE-----\n\nemSign ECC Root CA - G3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG\nA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg\nMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4\nMTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11\nZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g\nRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc\n58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr\nMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC\nAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D\nCBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7\njHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj\n-----END CERTIFICATE-----\n\nemSign Root CA - C1\n===================\n-----BEGIN CERTIFICATE-----\nMIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx\nEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp\nZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE\nBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD\nExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up\nufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/\nXse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX\nOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V\nI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms\nlMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+\nXJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD\nggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp\n/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1\nNnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9\nwC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ\nBmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=\n-----END CERTIFICATE-----\n\nemSign ECC Root CA - C3\n=======================\n-----BEGIN CERTIFICATE-----\nMIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG\nA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF\nQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE\nBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD\nExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd\n6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9\nSMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA\nB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA\nMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU\nZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==\n-----END CERTIFICATE-----\n\nHongkong Post Root CA 3\n=======================\n-----BEGIN CERTIFICATE-----\nMIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG\nA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK\nEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2\nMDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv\nbmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX\nSG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz\niNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf\njTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim\n5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe\nsL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj\n0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/\nJgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u\ny1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h\n+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG\nxVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID\nAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e\ni9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN\nAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw\nW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld\ny8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov\n+BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc\neqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw\n9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7\nnwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY\nhcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB\n60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq\ndBb9HxEGmpv0\n-----END CERTIFICATE-----\n\nMicrosoft ECC Root Certificate Authority 2017\n=============================================\n-----BEGIN CERTIFICATE-----\nMIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\nUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND\nIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4\nMjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw\nNAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6\nthaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB\neMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM\n+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf\nXu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR\neNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=\n-----END CERTIFICATE-----\n\nMicrosoft RSA Root Certificate Authority 2017\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG\nEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg\nUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw\nNzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u\nMTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw\nggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml\n7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e\nS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7\n1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+\ndkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F\nyGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS\nMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr\nlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ\n0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ\nClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw\nDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC\nNxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og\n6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80\ndK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk\n+ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex\n/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy\nAmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW\nZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE\n7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT\nc0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D\n5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E\n-----END CERTIFICATE-----\n\ne-Szigno Root CA 2017\n=====================\n-----BEGIN CERTIFICATE-----\nMIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw\nDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt\nMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa\nFw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE\nCgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp\nZ25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx\ns1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G\nA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv\nvzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA\ntVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO\nsvxyqltZ+efcMQ==\n-----END CERTIFICATE-----\n\ncertSIGN Root CA G2\n===================\n-----BEGIN CERTIFICATE-----\nMIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw\nEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy\nMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH\nTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05\nN0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk\nabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg\nwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp\ndWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh\nngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732\njcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf\n95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc\nz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL\niohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud\nDgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB\nywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC\nb6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB\n/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5\n8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5\nBiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW\natKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU\nSxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M\nNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N\n0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=\n-----END CERTIFICATE-----\n\nTrustwave Global Certification Authority\n========================================\n-----BEGIN CERTIFICATE-----\nMIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV\nUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2\nZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u\nIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV\nUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2\nZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u\nIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29\nzd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf\nLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq\nstTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o\nWN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+\nOsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40\nCz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE\nuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm\n+9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj\nifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud\nEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB\nBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H\nPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H\nZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla\n4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R\nvbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd\nzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O\n856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH\nYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu\n3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP\n29FpHOTKyeC2nOnOcXHebD8WpHk=\n-----END CERTIFICATE-----\n\nTrustwave Global ECC P256 Certification Authority\n=================================================\n-----BEGIN CERTIFICATE-----\nMIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER\nMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI\nb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD\nVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy\ndXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1\nNiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj\n43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm\nP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt\n0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz\nRM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7\n-----END CERTIFICATE-----\n\nTrustwave Global ECC P384 Certification Authority\n=================================================\n-----BEGIN CERTIFICATE-----\nMIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER\nMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI\nb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp\nY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD\nVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy\ndXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4\nNCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH\nBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr\n/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV\nHQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn\nADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl\nCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw==\n-----END CERTIFICATE-----\n\nNAVER Global Root Certification Authority\n=========================================\n-----BEGIN CERTIFICATE-----\nMIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG\nA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD\nDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4\nNDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT\nUyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv\nbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb\nUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW\n+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7\nXNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2\naacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4\nYb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z\nVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B\nA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai\ncdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy\nYhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV\nHQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB\nAf8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK\n21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB\njCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx\nhYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg\nE34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH\nD8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ\nA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY\nqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG\nI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg\nkpzNNIaRkPpkUZ3+/uul9XXeifdy\n-----END CERTIFICATE-----\n\nAC RAIZ FNMT-RCM SERVIDORES SEGUROS\n===================================\n-----BEGIN CERTIFICATE-----\nMIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF\nUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy\nNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4\nMTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt\nUkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB\nQyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA\nBPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2\nLEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG\nSM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD\nzBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c=\n-----END CERTIFICATE-----\n\nGlobalSign Root R46\n===================\n-----BEGIN CERTIFICATE-----\nMIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV\nBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv\nb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX\nBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es\nCVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/\nr6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje\n2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt\nbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj\nK8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4\n12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on\nccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls\neVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9\nvXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM\nBQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg\nJuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy\ngxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92\nCC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm\nOUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq\nJZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye\nqiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz\nnxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7\nDEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3\nQEUxeCp6\n-----END CERTIFICATE-----\n\nGlobalSign Root E46\n===================\n-----BEGIN CERTIFICATE-----\nMIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT\nAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg\nRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV\nBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq\nhkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB\njtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj\nQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL\ngLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk\nvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+\nCAezNIm8BZ/3Hobui3A=\n-----END CERTIFICATE-----\n\nGLOBALTRUST 2020\n================\n-----BEGIN CERTIFICATE-----\nMIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx\nIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT\nVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh\nBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy\nMDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi\nD59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO\nVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM\nCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm\nfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA\nA1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR\nJitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG\nDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU\nclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ\nmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw\nAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud\nIwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA\nVC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw\n4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9\niuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS\n8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2\nHcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS\nvTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918\noa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF\nYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl\ngqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==\n-----END CERTIFICATE-----\n\nANF Secure Server Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4\nNzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv\nbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg\nQ0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw\nMQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw\nEgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz\nBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv\nT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv\nB2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse\nzx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM\nVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j\n7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z\nJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe\n8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO\nHj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj\no1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E\nBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ\nUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx\nj6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt\ndD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM\n5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb\n5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54\nEX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H\nhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy\ng77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3\nr5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=\n-----END CERTIFICATE-----\n\nCertum EC-384 CA\n================\n-----BEGIN CERTIFICATE-----\nMIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ\nTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy\ndGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2\nMDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh\ndGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx\nGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq\nvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn\niBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo\nADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0\nQoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=\n-----END CERTIFICATE-----\n\nCertum Trusted Root CA\n======================\n-----BEGIN CERTIFICATE-----\nMIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG\nEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g\nQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew\nHhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY\nQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB\ndXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB\nAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p\nfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52\nHO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2\nfJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt\ng/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4\nNboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk\nfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ\nP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY\nnjYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK\nHRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1\nvALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL\nLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s\nALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K\nh2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8\nCYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA\n4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo\nWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj\n6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT\nOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck\nbxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb\n-----END CERTIFICATE-----\n\nTunTrust Root CA\n================\n-----BEGIN CERTIFICATE-----\nMIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG\nA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj\ndHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw\nNDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD\nZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz\n2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b\nbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7\nNegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd\ngjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW\nVSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f\nTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ\njuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas\nDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS\nVXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI\n04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0\n90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl\n0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd\nAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY\nYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp\nadbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x\nxBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP\njCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM\nMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z\nZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r\nAZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=\n-----END CERTIFICATE-----\n\nHARICA TLS RSA Root CA 2021\n===========================\n-----BEGIN CERTIFICATE-----\nMIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG\nEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\ncyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz\nOFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl\nbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB\nIFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN\nJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu\na2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y\nUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K\n5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv\ndmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR\n0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH\nGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm\nhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ\nCPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE\nAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU\nEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq\nQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD\nQpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR\nj88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5\nvZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0\nqPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6\nAlfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/\nPFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn\nkf3/W9b3raYvAwtt41dU63ZTGI0RmLo=\n-----END CERTIFICATE-----\n\nHARICA TLS ECC Root CA 2021\n===========================\n-----BEGIN CERTIFICATE-----\nMIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH\nUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD\nQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX\nDTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj\nIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv\nb3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l\nAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b\nECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW\n0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi\nrcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw\nCZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps\n-----END CERTIFICATE-----\n\nAutoridad de Certificacion Firmaprofesional CIF A62634068\n=========================================================\n-----BEGIN CERTIFICATE-----\nMIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA\nBgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\nMjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw\nQAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB\nNjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD\nUtd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P\nB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY\n7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH\nECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI\nplD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX\nMbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX\nLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK\nbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU\nvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud\nDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w\ngZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j\nb20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A\nbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC\nAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL\n4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb\nLIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il\nI45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP\ncjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA\nLI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A\nlun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH\n9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf\nNIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE\nZycPvEJdvSRUDewdcAZfpLz6IHxV\n-----END CERTIFICATE-----\n\nvTrus ECC Root CA\n=================\n-----BEGIN CERTIFICATE-----\nMIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE\nBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS\nb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa\nBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw\nEAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c\nToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n\nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO\nBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT\nQJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL\nYgmRWAD5Tfs0aNoJrSEGGJTO\n-----END CERTIFICATE-----\n\nvTrus Root CA\n=============\n-----BEGIN CERTIFICATE-----\nMIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG\nA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv\nb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG\nA1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ\nKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots\nSKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI\nZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF\nXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA\nYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70\nkLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2\nAXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu\n/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu\n1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO\n9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg\nscasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC\nAgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd\nnxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr\njld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4\n8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn\nxDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg\nicEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4\nsEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW\nnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc\nSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H\nl3s=\n-----END CERTIFICATE-----\n\nISRG Root X2\n============\n-----BEGIN CERTIFICATE-----\nMIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV\nUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT\nUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT\nMSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS\nRyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H\nttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb\nd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\nHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF\ncP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5\nU6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn\n-----END CERTIFICATE-----\n\nHiPKI Root CA - G1\n==================\n-----BEGIN CERTIFICATE-----\nMIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG\nEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ\nIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT\nAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg\nUm9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0\no9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k\nwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE\nYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA\nGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd\nhSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj\n1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4\n9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/\nVm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF\n8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD\nVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD\nAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi\n7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl\ntJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE\nwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q\nJNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv\n5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz\njLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg\nhUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb\nyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/\nyPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==\n-----END CERTIFICATE-----\n\nGlobalSign ECC Root CA - R4\n===========================\n-----BEGIN CERTIFICATE-----\nMIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i\nYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i\nYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds\nb2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW\nymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E\nBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI\nKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg\nUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm\n-----END CERTIFICATE-----\n\nGTS Root R1\n===========\n-----BEGIN CERTIFICATE-----\nMIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV\nUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg\nUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE\nChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\nf/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0\nxlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w\nB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW\nnOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk\n9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq\nkUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A\nK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX\nV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW\ncfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD\nggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe\nQkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi\nClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar\nJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci\nNuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me\nLMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF\nfbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+\n7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3\nFL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3\ngm3c\n-----END CERTIFICATE-----\n\nGTS Root R2\n===========\n-----BEGIN CERTIFICATE-----\nMIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV\nUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg\nUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE\nChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G\nCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\nCvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl\ne3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb\na96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS\n+LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M\nkogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG\nr61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q\nS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV\nJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL\ndWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T\nAQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD\nggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8\n0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh\nswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel\n/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn\njWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5\n9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M\n7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8\n0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR\nWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW\nHYbL\n-----END CERTIFICATE-----\n\nGTS Root R3\n===========\n-----BEGIN CERTIFICATE-----\nMIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi\nMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw\nHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ\nR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO\nPQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA\nMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq\nEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT\nL818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV\n11RZt+cRLInUue4X\n-----END CERTIFICATE-----\n\nGTS Root R4\n===========\n-----BEGIN CERTIFICATE-----\nMIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi\nMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw\nHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ\nR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO\nPQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\nhXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA\nMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1\nPsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C\nr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh\n4rsUecrNIdSUtUlD\n-----END CERTIFICATE-----\n\nTelia Root CA v2\n================\n-----BEGIN CERTIFICATE-----\nMIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT\nAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2\nMjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK\nDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI\nhvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7\n6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q\n9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn\npNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl\ntI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW\n5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr\nRBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E\nBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4\nM0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau\nBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W\nxy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD\nVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ\n8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5\ntFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H\neW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C\ny748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC\nQMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15\nh2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70\nsz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9\nxnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ\nraVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=\n-----END CERTIFICATE-----\n\nD-TRUST BR Root CA 1 2020\n=========================\n-----BEGIN CERTIFICATE-----\nMIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE\nRTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy\nMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV\nBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG\nByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7\ndPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu\nQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t\nMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu\nbmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj\ndG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP\nPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD\nAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom\nAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87\n-----END CERTIFICATE-----\n\nD-TRUST EV Root CA 1 2020\n=========================\n-----BEGIN CERTIFICATE-----\nMIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE\nRTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy\nMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV\nBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG\nByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8\nZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ\nraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL\nMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu\nbmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj\ndG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP\nPUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD\nAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR\nAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW\n-----END CERTIFICATE-----\n\nDigiCert TLS ECC P384 Root G5\n=============================\n-----BEGIN CERTIFICATE-----\nMIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV\nUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4\nNCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx\nFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg\nUm9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd\nlHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj\nn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB\n/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds\nJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx\nAJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA==\n-----END CERTIFICATE-----\n\nDigiCert TLS RSA4096 Root G5\n============================\n-----BEGIN CERTIFICATE-----\nMIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG\nEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0\nMDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV\nUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2\nIFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8\n7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU\nAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces\ntyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa\nzOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV\nDdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q\nTXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy\nz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/\nMZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk\nwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E\nFgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w\nDQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw\nGXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN\nlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN\nMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/\nu4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G\nOUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh\n47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU\nFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ\nyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP\nbEtoL8pU9ozaMv7Da4M/OMZ+\n-----END CERTIFICATE-----\n\nCertainly Root R1\n=================\n-----BEGIN CERTIFICATE-----\nMIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE\nBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN\nMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy\ndGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O\n5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl\n8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl\nDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI\nXsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN\nKPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ\nAjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb\nrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1\nVwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS\np6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\nDgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz\nHQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d\n8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v\nMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB\nGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+\ngjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH\nJBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7\nfpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw\nx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S\nX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8=\n-----END CERTIFICATE-----\n\nCertainly Root E1\n=================\n-----BEGIN CERTIFICATE-----\nMIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV\nUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0\nMDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu\nbHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4\nfxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9\nYBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw\nDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E\nAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8\nrgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR\n-----END CERTIFICATE-----\n\nSecurity Communication ECC RootCA1\n==================================\n-----BEGIN CERTIFICATE-----\nMIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD\nVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t\ndW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL\nMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV\nBAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA\nIgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo\n5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW\nBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK\nBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L\nsnNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e\nN9k=\n-----END CERTIFICATE-----\n\nBJCA Global Root CA1\n====================\n-----BEGIN CERTIFICATE-----\nMIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG\nEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK\nQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG\nA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD\nDBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm\nCL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS\nsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn\nP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW\nyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj\neulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn\nMoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b\nOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh\nGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK\nH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB\nAAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G\nA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4\nYRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ\ndMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8\n60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh\nTaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW\n4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp\nGQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx\n4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps\n3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S\nSPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI=\n-----END CERTIFICATE-----\n\nBJCA Global Root CA2\n====================\n-----BEGIN CERTIFICATE-----\nMIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD\nTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg\nR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE\nBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC\nSkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl\nSR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK\n/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI\n1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8\nW9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g\nUXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==\n-----END CERTIFICATE-----\n\nSectigo Public Server Authentication Root E46\n=============================================\n-----BEGIN CERTIFICATE-----\nMIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH\nQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2\nZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5\nWjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0\naWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr\ngQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0\nNSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud\nDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH\nlAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U\nSAGKcw==\n-----END CERTIFICATE-----\n\nSectigo Public Server Authentication Root R46\n=============================================\n-----BEGIN CERTIFICATE-----\nMIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG\nEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT\nZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1\nOTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T\nZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3\nDQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k\n1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf\nGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP\nFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu\nZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz\nYw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A\nwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF\nplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ\nEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW\n6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI\nIUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c\nmTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp\nE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4\nexqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M\n0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI\n84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m\npFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd\nVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b\nE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm\nJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL\n-----END CERTIFICATE-----\n\nSSL.com TLS RSA Root CA 2022\n============================\n-----BEGIN CERTIFICATE-----\nMIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG\nEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg\nUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC\nVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv\nb3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u\n9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y\n7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac\noOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M\nR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG\nD6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW\nTO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk\n8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq\ng+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk\n7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud\nEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu\nN+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt\nhEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN\nj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by\niB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU\no3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo\nENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib\nMOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi\nvRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7\nP0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0\n9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=\n-----END CERTIFICATE-----\n\nSSL.com TLS ECC Root CA 2022\n============================\n-----BEGIN CERTIFICATE-----\nMIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV\nUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v\ndCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx\nGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg\nQ0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy\nJGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1\n5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7\n81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG\nMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w\n7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5\nZn6g6g==\n-----END CERTIFICATE-----\n\nAtos TrustedRoot Root CA ECC TLS 2021\n=====================================\n-----BEGIN CERTIFICATE-----\nMIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB\ndG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD\nVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg\nVHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT\nAkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K\nDP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS\nb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX\nNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+\nuDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY\na3cpetskz2VAv9LcjBHo9H1/IISpQuQo\n-----END CERTIFICATE-----\n\nAtos TrustedRoot Root CA RSA TLS 2021\n=====================================\n-----BEGIN CERTIFICATE-----\nMIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD\nDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw\nCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0\nb3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV\nBAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB\nl01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG\nvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK\nZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt\n0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK\nPNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY\nsluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY\nBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+\nrrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa\nfJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/\nBAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G\nCSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS\n4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl\nQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX\nAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G\nslA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt\nafcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q\nTFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj\n1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l\nPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W\nHYMfRsCbvUOZ58SWLs5fyQ==\n-----END CERTIFICATE-----\n\nTrustAsia Global Root CA G3\n===========================\n-----BEGIN CERTIFICATE-----\nMIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG\nA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM\nG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw\nMTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu\nMSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA\nA4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz\nlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ\nQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V\nP68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag\ndB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm\n9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc\nD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg\nWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea\nmseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF\nTIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj\n7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E\nBAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1\nD/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T\nG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj\nduMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl\ncHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys\n+TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli\n2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y\naFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS\nZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR\nJQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH\n-----END CERTIFICATE-----\n\nTrustAsia Global Root CA G4\n===========================\n-----BEGIN CERTIFICATE-----\nMIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE\nBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry\ndXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa\nMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw\nIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi\nAATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8\nm7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF\nMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/\npDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA\nbbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk\ndUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==\n-----END CERTIFICATE-----\n\nTelekom Security TLS ECC Root 2020\n==================================\n-----BEGIN CERTIFICATE-----\nMIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE\nRTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl\na29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz\nNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg\nR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG\nSM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1\n2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC\nMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ\nMo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU\nga/sf+Rn27iQ7t0l\n-----END CERTIFICATE-----\n\nTelekom Security TLS RSA Root 2023\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG\nEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU\nZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy\nNzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp\ndHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw\nDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC\nKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP\nGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx\nUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo\nl8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9\nFIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v\nzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg\nrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML\nKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S\nWWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV\nHQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2\np5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+\nsVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp\nkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy\n/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4\nmZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz\naL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa\noqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8\nwPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE\nHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0\no82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=\n-----END CERTIFICATE-----\n\nFIRMAPROFESIONAL CA ROOT-A WEB\n==============================\n-----BEGIN CERTIFICATE-----\nMIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQswCQYDVQQGEwJF\nUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4\nMScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENBIFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2\nWhcNNDcwMzMxMDkwMTM2WjBuMQswCQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25h\nbCBTQTEYMBYGA1UEYQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFM\nIENBIFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zfe9MEkVz6\niMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6CcyvHZpsKjECcfIr28jlg\nst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FD\nY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0OBBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB\n/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgL\ncFBTApFwhVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dGXSaQ\npYXFuXqUPoeovQA=\n-----END CERTIFICATE-----\n\nTWCA CYBER Root CA\n==================\n-----BEGIN CERTIFICATE-----\nMIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG\nEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB\nIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG\nEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB\nIENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s\nTs6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh\nV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT\no0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT\nNq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK\n/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH\nIuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM\nfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF\n2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR\nwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO\nBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83\nQOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB\nAGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN\nc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x\nX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR\nIG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq\n/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R\nFxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe\nPm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv\nIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl\nIhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X\n-----END CERTIFICATE-----\n\nSecureSign Root CA12\n====================\n-----BEGIN CERTIFICATE-----\nMIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT\nZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ\nBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU\nU2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3\nemhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc\nJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl\nfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF\nEaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef\nNzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\nAQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC\nAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi\nLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce\nmik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS\nvWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga\naaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==\n-----END CERTIFICATE-----\n\nSecureSign Root CA14\n====================\n-----BEGIN CERTIFICATE-----\nMIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG\nA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT\nZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ\nBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU\nU2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh\n1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn\nbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb\n1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa\n/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE\nkJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx\njVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz\nju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0\ndFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY\nAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB\no0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq\nYR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E\nrX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA\nymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds\nHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG\nFrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q\nnsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/\nOfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa\nOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO\npygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN\neLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S\n-----END CERTIFICATE-----\n\nSecureSign Root CA15\n====================\n-----BEGIN CERTIFICATE-----\nMIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE\nBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1\ncmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV\nBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj\ndXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G\ndCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB\n2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\nAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J\nfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ\nSwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=\n-----END CERTIFICATE-----\n\nD-TRUST BR Root CA 2 2023\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG\nEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg\nMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT\nBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT\ncfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z\nsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ\nWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6\n++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL\nQyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv\nx9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV\nMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX\n/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9\nCZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC\nMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y\nXzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr\nd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv\nU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4\nnj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij\nYQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff\n/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP\npz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB\nWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/\n5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt\nn/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA==\n-----END CERTIFICATE-----\n\nTrustAsia TLS ECC Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMwWDELMAkGA1UE\nBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMTGVRy\ndXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBY\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAG\nA1UEAxMZVHJ1c3RBc2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/\npVs/AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDpguMqWzJ8\nS5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAwDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49\nBAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15K\neAIxAKORh/IRM4PDwYqROkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ==\n-----END CERTIFICATE-----\n\nTrustAsia TLS RSA Root CA\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEMBQAwWDELMAkG\nA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMT\nGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2\nWjBYMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEi\nMCAGA1UEAxMZVHJ1c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\nADCCAgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+NmDQDIPN\nlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJQ1DNDX3eRA5gEk9bNb2/\nmThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fk\nzv93uMltrOXVmPGZLmzjyUT5tUMnCE32ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYo\nzza/+lcK7Fs/6TAWe8TbxNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyr\nz2I8sMeXi9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQUNoy\nIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+jTnhMmCWr8n4uIF6C\nFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DTbE3txci3OE9kxJRMT6DNrqXGJyV1\nJ23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnT\nq1mt1tve1CuBAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZ\nylomkadFK/hTMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3\nRz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4iqME3mmL5Dw8\nveWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt7DlK9RME7I10nYEKqG/odv6L\nTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHx\ntlotJnMnlvm5P1vQiJ3koP26TpUJg3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp\n27RIGAAtvKLEiUUjpQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87q\nqA8MpugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongPXvPKnbwb\nPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIweSsCI3zWQzj8C9GRh3sfI\nB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNz\nFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy323imttUQ/hHWKNddBWcwauwxzQ=\n-----END CERTIFICATE-----\n\nD-TRUST EV Root CA 2 2023\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG\nEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg\nMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT\nBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC\nAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1\nsJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/\nMHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf\nvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM\nlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3\nYG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910\n7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo\nnMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa\nQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF\nAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB\n/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC\nMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y\nXzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS\nMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2\nQHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD\nUmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V\n4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo\ndNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi\nTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi\nS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/\nHxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L\n+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==\n-----END CERTIFICATE-----\n\nSwissSign RSA TLS Root CA 2022 - 1\n==================================\n-----BEGIN CERTIFICATE-----\nMIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQELBQAwUTELMAkG\nA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UEAxMiU3dpc3NTaWduIFJTQSBU\nTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgxMTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJ\nBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0Eg\nVExTIFJvb3QgQ0EgMjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmji\nC8NXvDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7LCTLf5Im\ngKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX5XH8irCRIFucdFJtrhUn\nWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyEEPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlf\nGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36q\nOTw7D59Ke4LKa2/KIj4x0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLO\nEGrOyvi5KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM0ZPl\nEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shdOxtYk8EXlFXIC+OC\neYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrtaclXvyFu1cvh43zcgTFeRc5JzrBh3\nQ4IgaezprClG5QtO+DdziZaKHG29777YtvTKwP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQAB\no2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow\n4UD2p8P98Q+4DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL\nBQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO310aewCoSPY6W\nlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgzHqp41eZUBDqyggmNzhYzWUUo\n8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQiJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zp\ny1FVCypM9fJkT6lc/2cyjlUtMoIcgC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3Cjlvr\nzG4ngRhZi0Rjn9UMZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6M\nOuhFLhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJpzv1/THfQ\nwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/TdAo9QAwKxuDdollDruF/U\nKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0n\nhzck5npgL7XTgwSqT0N1osGDsieYK7EOgLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rw\ntnu64ZzZ\n-----END CERTIFICATE-----\n\nOISTE Server Root ECC G1\n========================\n-----BEGIN CERTIFICATE-----\nMIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQswCQYDVQQGEwJD\nSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJvb3Qg\nRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUyNDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAX\nBgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBH\nMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOuj\nvqQycvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N2xml4z+c\nKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3TYhlz/w9itWj8UnATgwQ\nb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9CtJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqG\nSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFRQD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxg\nZzFDJe0CMQCSia7pXGKDYmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c=\n-----END CERTIFICATE-----\n\n OISTE Server Root RSA G1\n=========================\n-----BEGIN CERTIFICATE-----\nMIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBLMQswCQYDVQQG\nEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJv\nb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gx\nGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJT\nQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxV\nYOPMvLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7brEi56rAU\njtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzkik/HEzxux9UTl7Ko2yRp\ng1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4zO8vbUZeUapU8zhhabkvG/AePLhq5Svdk\nNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8RtOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY\n+m0o/DjH40ytas7ZTpOSjswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+\nlKXHiHUhsd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+HomnqT\n8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu+zrkL8Fl47l6QGzw\nBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYRi3drVByjtdgQ8K4p92cIiBdcuJd5\nz+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnTkCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQF\nMAMBAf8wHwYDVR0jBBgwFoAU8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC7\n7EUOSh+1sbM2zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33\nI3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG5D1rd9QhEOP2\n8yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8qyiWXmFcuCIzGEgWUOrKL+ml\nSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dPAGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l\n8PjaV8GUgeV6Vg27Rn9vkf195hfkgSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+\nFKrDgHGdPY3ofRRsYWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNq\nqYY19tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome/msVuduC\nmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3J8tRd/iWkx7P8nd9H0aT\nolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2wq1yVAb+axj5d9spLFKebXd7Yv0PTY6Y\nMjAwcRLWJTXjn/hvnLXrahut6hDTlhZyBiElxky8j3C7DOReIoMt0r7+hVu05L0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/encryption_salt.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\n\tblockadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/block\"\n\tsecretsadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/secrets\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/automaton/blockautomaton\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// EncryptionSaltController manages secrets.EncryptionSalt in STATE.\ntype EncryptionSaltController struct {\n\tstateMachine blockautomaton.VolumeMounterAutomaton\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EncryptionSaltController) Name() string {\n\treturn \"secrets.EncryptionSaltController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EncryptionSaltController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountStatusType,\n\t\t\tKind:      controller.InputStrong,\n\t\t},\n\t\t{\n\t\t\tNamespace: block.NamespaceName,\n\t\t\tType:      block.VolumeMountRequestType,\n\t\t\tKind:      controller.InputDestroyReady,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EncryptionSaltController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.EncryptionSaltType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: block.VolumeMountRequestType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EncryptionSaltController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tif ctrl.stateMachine == nil {\n\t\t\tctrl.stateMachine = blockautomaton.NewVolumeMounter(\n\t\t\t\tctrl.Name(),\n\t\t\t\tconstants.StatePartitionLabel,\n\t\t\t\tctrl.establishEncryptionSalt,\n\t\t\t\tblockautomaton.WithDetached(true),\n\t\t\t)\n\t\t}\n\n\t\tif err := ctrl.stateMachine.Run(ctx, r, logger); err != nil {\n\t\t\treturn fmt.Errorf(\"error running volume mounter machine: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *EncryptionSaltController) establishEncryptionSalt(ctx context.Context, r controller.ReaderWriter, logger *zap.Logger, mountStatus *block.VolumeMountStatus) error {\n\treturn blockadapter.VolumeMountStatus(mountStatus).WithRoot(logger, func(root xfs.Root) error {\n\t\tvar salt secrets.EncryptionSaltSpec\n\n\t\tif err := controllers.LoadOrNewFromFile(root, constants.EncryptionSaltFilename, &salt, func(v *secrets.EncryptionSaltSpec) error {\n\t\t\treturn secretsadapter.EncryptionSalt(v).Generate()\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error caching node identity: %w\", err)\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, secrets.NewEncryptionSalt(), func(r *secrets.EncryptionSalt) error {\n\t\t\t*r.TypedSpec() = salt\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t\t}\n\n\t\t// encryption salt thumbprint for debugging purposes\n\t\tsaltHMAC := hmac.New(sha256.New, salt.DiskSalt)\n\t\tsaltHMAC.Write([]byte(\"encryption salt checksum\"))\n\t\tsaltChecksum := saltHMAC.Sum(nil)\n\n\t\tlogger.Info(\"encryption salt established\",\n\t\t\tzap.String(\"salt_checksum\", hex.EncodeToString(saltChecksum)),\n\t\t)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/encryption_salt_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\ntype EncryptionSaltSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *EncryptionSaltSuite) TestDefault() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&secretsctrl.EncryptionSaltController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\tctest.AssertNoResource[*secrets.EncryptionSalt](suite, secrets.EncryptionSaltID)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, secrets.EncryptionSaltID, func(*secrets.EncryptionSalt, *assert.Assertions) {})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n\n\tsuite.Assert().FileExists(filepath.Join(statePath, constants.EncryptionSaltFilename), \"encryption salt file should exist\")\n\n\tcontents, err := os.ReadFile(filepath.Join(statePath, constants.EncryptionSaltFilename))\n\tsuite.Require().NoError(err, \"should be able to read encryption salt file\")\n\n\tlog.Printf(\"contents: %q\", contents)\n}\n\nfunc (suite *EncryptionSaltSuite) TestLoad() {\n\tstatePath := suite.T().TempDir()\n\tmountID := (&secretsctrl.EncryptionSaltController{}).Name() + \"-\" + constants.StatePartitionLabel\n\n\tctest.AssertResource(suite, mountID, func(mountRequest *block.VolumeMountRequest, asrt *assert.Assertions) {\n\t\tasrt.Equal(constants.StatePartitionLabel, mountRequest.TypedSpec().VolumeID)\n\t})\n\n\t// using verbatim data here to make sure salt representation is supported in future version fo Talos\n\tsuite.Require().NoError(os.WriteFile(filepath.Join(statePath, constants.EncryptionSaltFilename),\n\t\t[]byte(\"diskSalt:\\n    - 240\\n    - 180\\n    - 79\\n    - 128\\n    - 31\\n    - 0\\n    - 19\\n    - 124\\n    - 165\\n    - 74\\n    - 113\\n    - 220\\n    - 27\\n    - 83\\n    - 46\\n    - 74\\n    - 204\\n    - 190\\n    - 217\\n    - 96\\n    - 221\\n    - 2\\n    - 165\\n    - 98\\n    - 245\\n    - 36\\n    - 165\\n    - 151\\n    - 149\\n    - 66\\n    - 113\\n    - 16\\n\"), //nolint:lll\n\t\t0o600))\n\n\tctest.AssertNoResource[*secrets.EncryptionSalt](suite, secrets.EncryptionSaltID)\n\n\tvolumeMountStatus := block.NewVolumeMountStatus(block.NamespaceName, mountID)\n\tvolumeMountStatus.TypedSpec().Target = statePath\n\tsuite.Create(volumeMountStatus)\n\n\tctest.AssertResource(suite, secrets.EncryptionSaltID, func(encryptionSalt *secrets.EncryptionSalt, asrt *assert.Assertions) {\n\t\tasrt.Equal(\n\t\t\t[]byte{0xf0, 0xb4, 0x4f, 0x80, 0x1f, 0x0, 0x13, 0x7c, 0xa5, 0x4a, 0x71, 0xdc, 0x1b, 0x53, 0x2e, 0x4a, 0xcc, 0xbe, 0xd9, 0x60, 0xdd, 0x2, 0xa5, 0x62, 0xf5, 0x24, 0xa5, 0x97, 0x95, 0x42, 0x71, 0x10},\n\t\t\tencryptionSalt.TypedSpec().DiskSalt,\n\t\t)\n\t})\n\n\tctest.AssertResources(suite, []resource.ID{volumeMountStatus.Metadata().ID()}, func(vms *block.VolumeMountStatus, asrt *assert.Assertions) {\n\t\tasrt.True(vms.Metadata().Finalizers().Empty())\n\t})\n\n\tsuite.Destroy(volumeMountStatus)\n\n\tctest.AssertNoResource[*block.VolumeMountRequest](suite, mountID)\n}\n\nfunc TestEncryptionSaltSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"skipping test that requires root privileges\")\n\t}\n\n\tsuite.Run(t, &EncryptionSaltSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.EncryptionSaltController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// EtcdController manages secrets.Etcd based on configuration.\ntype EtcdController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *EtcdController) Name() string {\n\treturn \"secrets.EtcdController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *EtcdController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.EtcdRootType,\n\t\t\tID:        optional.Some(secrets.EtcdRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      time.StatusType,\n\t\t\tID:        optional.Some(time.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *EtcdController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.EtcdType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *EtcdController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tetcdRootRes, err := safe.ReaderGet[*secrets.EtcdRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdRootType, secrets.EtcdRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd root secrets: %w\", err)\n\t\t}\n\n\t\tetcdRoot := etcdRootRes.TypedSpec()\n\n\t\t// wait for network to be ready as it might change IPs/hostname\n\t\tnetworkResource, err := safe.ReaderGet[*network.Status](ctx, r, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkStatus := networkResource.TypedSpec()\n\n\t\tif !(networkStatus.AddressReady && networkStatus.HostnameReady) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// wait for time sync as certs depend on current time\n\t\ttimeSyncResource, err := safe.ReaderGet[*time.Status](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, time.StatusType, time.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !timeSyncResource.TypedSpec().Synced {\n\t\t\tcontinue\n\t\t}\n\n\t\thostnameStatus, err := safe.ReaderGet[*network.HostnameStatus](ctx, r, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting hostname status: %w\", err)\n\t\t}\n\n\t\tnodeAddrs, err := safe.ReaderGet[*network.NodeAddress](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(\n\t\t\t\tnetwork.NamespaceName,\n\t\t\t\tnetwork.NodeAddressType,\n\t\t\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s),\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting addresses: %w\", err)\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewEtcd(), func(r *secrets.Etcd) error {\n\t\t\treturn ctrl.updateSecrets(etcdRoot, nodeAddrs, hostnameStatus, r.TypedSpec())\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *EtcdController) updateSecrets(etcdRoot *secrets.EtcdRootSpec, nodeAddress *network.NodeAddress, hostnameStatus *network.HostnameStatus, etcdCerts *secrets.EtcdCertsSpec) error {\n\tgenerator := etcd.CertificateGenerator{\n\t\tCA: etcdRoot.EtcdCA,\n\n\t\tNodeAddresses:  nodeAddress,\n\t\tHostnameStatus: hostnameStatus,\n\t}\n\n\tvar err error\n\n\tetcdCerts.Etcd, err = generator.GenerateServerCert()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating etcd client certs: %w\", err)\n\t}\n\n\tetcdCerts.EtcdPeer, err = generator.GeneratePeerCert()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating etcd peer certs: %w\", err)\n\t}\n\n\tetcdCerts.EtcdAdmin, err = generator.GenerateClientCert(\"talos\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating admin client certs: %w\", err)\n\t}\n\n\tetcdCerts.EtcdAPIServer, err = generator.GenerateClientCert(\"kube-apiserver\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating kube-apiserver etcd client certs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (ctrl *EtcdController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.EtcdType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO: change this to proper teardown sequence\n\n\tfor _, res := range list.Items {\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/etcd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeres \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nfunc TestEtcdSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &EtcdSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.EtcdController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype EtcdSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *EtcdSuite) TestReconcile() {\n\trootSecrets := secrets.NewEtcdRoot(secrets.EtcdRootID)\n\n\tetcdCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"talos\"),\n\t\tx509.ECDSA(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().EtcdCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: etcdCA.CrtPEM,\n\t\tKey: etcdCA.KeyPEM,\n\t}\n\tsuite.Create(rootSecrets)\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tnetworkStatus.TypedSpec().HostnameReady = true\n\tsuite.Create(networkStatus)\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"host\"\n\thostnameStatus.TypedSpec().Domainname = \"domain\"\n\tsuite.Create(hostnameStatus)\n\n\tnodeAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s))\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.3.4.5/24\"),\n\t\tnetip.MustParsePrefix(\"2001:db8::1eaf/64\"),\n\t}\n\tsuite.Create(nodeAddresses)\n\n\ttimeSync := timeres.NewStatus()\n\ttimeSync.TypedSpec().Synced = true\n\tsuite.Create(timeSync)\n\n\tctest.AssertResource(suite, secrets.EtcdID, func(certs *secrets.Etcd, asrt *assert.Assertions) {\n\t\tetcdCerts := certs.TypedSpec()\n\n\t\tserverCert, err := etcdCerts.Etcd.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal([]string{\"host\", \"host.domain\", \"localhost\"}, serverCert.DNSNames)\n\t\tasrt.Equal(\"[10.3.4.5 2001:db8::1eaf 127.0.0.1 ::1]\", fmt.Sprintf(\"%v\", serverCert.IPAddresses))\n\n\t\tasrt.Equal(\"host\", serverCert.Subject.CommonName)\n\n\t\tpeerCert, err := etcdCerts.EtcdPeer.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal([]string{\"host\", \"host.domain\"}, peerCert.DNSNames)\n\t\tasrt.Equal(\"[10.3.4.5 2001:db8::1eaf]\", fmt.Sprintf(\"%v\", peerCert.IPAddresses))\n\n\t\tasrt.Equal(\"host\", peerCert.Subject.CommonName)\n\n\t\tadminCert, err := etcdCerts.EtcdAdmin.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Empty(adminCert.DNSNames)\n\t\tasrt.Empty(adminCert.IPAddresses)\n\n\t\tasrt.Equal(\"talos\", adminCert.Subject.CommonName)\n\n\t\tkubeAPICert, err := etcdCerts.EtcdAPIServer.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Empty(kubeAPICert.DNSNames)\n\t\tasrt.Empty(kubeAPICert.IPAddresses)\n\n\t\tasrt.Equal(\"kube-apiserver\", kubeAPICert.Subject.CommonName)\n\t})\n\n\t// update node addresses, certs should be updated\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.3.4.5/24\"),\n\t}\n\tsuite.Update(nodeAddresses)\n\n\tctest.AssertResource(suite, secrets.EtcdID, func(certs *secrets.Etcd, asrt *assert.Assertions) {\n\t\tetcdCerts := certs.TypedSpec()\n\n\t\tserverCert, err := etcdCerts.Etcd.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal([]string{\"host\", \"host.domain\", \"localhost\"}, serverCert.DNSNames)\n\t\tasrt.Equal(\"[10.3.4.5 127.0.0.1 ::1]\", fmt.Sprintf(\"%v\", serverCert.IPAddresses))\n\n\t\tasrt.Equal(\"host\", serverCert.Subject.CommonName)\n\n\t\tpeerCert, err := etcdCerts.EtcdPeer.GetCert()\n\t\tif !asrt.NoError(err) {\n\t\t\treturn\n\t\t}\n\n\t\tasrt.Equal([]string{\"host\", \"host.domain\"}, peerCert.DNSNames)\n\t\tasrt.Equal(\"[10.3.4.5]\", fmt.Sprintf(\"%v\", peerCert.IPAddresses))\n\n\t\tasrt.Equal(\"host\", peerCert.Subject.CommonName)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// KubeletController manages secrets.Kubelet based on configuration.\ntype KubeletController = transform.Controller[*config.MachineConfig, *secrets.Kubelet]\n\n// NewKubeletController instanciates the controller.\nfunc NewKubeletController() *KubeletController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *secrets.Kubelet]{\n\t\t\tName: \"secrets.KubeletController\",\n\t\t\tMapMetadataOptionalFunc: func(cfg *config.MachineConfig) optional.Optional[*secrets.Kubelet] {\n\t\t\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\t\t\treturn optional.None[*secrets.Kubelet]()\n\t\t\t\t}\n\n\t\t\t\tif cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {\n\t\t\t\t\treturn optional.None[*secrets.Kubelet]()\n\t\t\t\t}\n\n\t\t\t\treturn optional.Some(secrets.NewKubelet(secrets.KubeletID))\n\t\t\t},\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.Kubelet) error {\n\t\t\t\tcfgProvider := cfg.Config()\n\t\t\t\tkubeletSecrets := res.TypedSpec()\n\n\t\t\t\tswitch {\n\t\t\t\tcase cfgProvider.Machine().Features().KubePrism().Enabled():\n\t\t\t\t\t// use cluster endpoint for controlplane nodes with loadbalancer support\n\t\t\t\t\tlocalEndpoint, err := url.Parse(fmt.Sprintf(\"https://127.0.0.1:%d\", cfgProvider.Machine().Features().KubePrism().Port()))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tkubeletSecrets.Endpoint = localEndpoint\n\t\t\t\tcase cfgProvider.Machine().Type().IsControlPlane():\n\t\t\t\t\t// use localhost endpoint for controlplane nodes\n\t\t\t\t\tlocalEndpoint, err := url.Parse(fmt.Sprintf(\"https://localhost:%d\", cfgProvider.Cluster().LocalAPIServerPort()))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tkubeletSecrets.Endpoint = localEndpoint\n\t\t\t\tdefault:\n\t\t\t\t\t// use cluster endpoint for workers\n\t\t\t\t\tkubeletSecrets.Endpoint = cfgProvider.Cluster().Endpoint()\n\t\t\t\t}\n\n\t\t\t\tkubeletSecrets.AcceptedCAs = nil\n\n\t\t\t\tif cfgProvider.Cluster().IssuingCA() != nil {\n\t\t\t\t\tkubeletSecrets.AcceptedCAs = append(kubeletSecrets.AcceptedCAs, &x509.PEMEncodedCertificate{Crt: cfgProvider.Cluster().IssuingCA().Crt})\n\t\t\t\t}\n\n\t\t\t\tkubeletSecrets.AcceptedCAs = append(kubeletSecrets.AcceptedCAs, cfgProvider.Cluster().AcceptedCAs()...)\n\n\t\t\t\tif len(kubeletSecrets.AcceptedCAs) == 0 {\n\t\t\t\t\treturn errors.New(\"missing accepted Kubernetes CAs\")\n\t\t\t\t}\n\n\t\t\t\tkubeletSecrets.BootstrapTokenID = cfgProvider.Cluster().Token().ID()\n\t\t\t\tkubeletSecrets.BootstrapTokenSecret = cfgProvider.Cluster().Token().Secret()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubelet_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestKubeletSuite(t *testing.T) {\n\tsuite.Run(t, &KubeletSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(secretsctrl.NewKubeletController()))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype KubeletSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubeletSuite) TestReconcile() {\n\tu, err := url.Parse(\"https://foo:6443\")\n\tsuite.Require().NoError(err)\n\n\tca, err := x509.NewSelfSignedCertificateAuthority(x509.RSA(false))\n\tsuite.Require().NoError(err)\n\n\tk8sCA := x509.NewCertificateAndKeyFromCertificateAuthority(ca)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: u,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterCA:      k8sCA,\n\t\t\t\t\tBootstrapToken: \"abc.def\",\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tkubeletSecrets, err := ctest.Get[*secrets.Kubelet](\n\t\t\t\t\tsuite,\n\t\t\t\t\tresource.NewMetadata(\n\t\t\t\t\t\tsecrets.NamespaceName,\n\t\t\t\t\t\tsecrets.KubeletType,\n\t\t\t\t\t\tsecrets.KubeletID,\n\t\t\t\t\t\tresource.VersionUndefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tspec := kubeletSecrets.TypedSpec()\n\n\t\t\t\tsuite.Assert().Equal(\"https://foo:6443\", spec.Endpoint.String())\n\t\t\t\tsuite.Assert().Equal([]*x509.PEMEncodedCertificate{{Crt: k8sCA.Crt}}, spec.AcceptedCAs)\n\t\t\t\tsuite.Assert().Equal(\"abc\", spec.BootstrapTokenID)\n\t\t\t\tsuite.Assert().Equal(\"def\", spec.BootstrapTokenSecret)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/kubeconfig\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// KubernetesCertificateValidityDuration is the validity duration for the certificates created with this controller.\n//\n// Controller automatically refreshes certs at 50% of CertificateValidityDuration.\nconst KubernetesCertificateValidityDuration = constants.KubernetesDefaultCertificateValidityDuration\n\n// KubernetesController manages secrets.Kubernetes based on configuration.\ntype KubernetesController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubernetesController) Name() string {\n\treturn \"secrets.KubernetesController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubernetesController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      timeresource.StatusType,\n\t\t\tID:        optional.Some(timeresource.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubernetesController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.KubernetesType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KubernetesController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\trefreshTicker := time.NewTicker(KubernetesCertificateValidityDuration / 2)\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-refreshTicker.C:\n\t\t}\n\n\t\tk8sRoot, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting root k8s secrets: %w\", err)\n\t\t}\n\n\t\t// wait for time sync as certs depend on current time\n\t\ttimeSync, err := safe.ReaderGet[*timeresource.Status](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, timeresource.StatusType, timeresource.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !timeSync.TypedSpec().Synced {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewKubernetes(), func(r *secrets.Kubernetes) error {\n\t\t\treturn ctrl.updateSecrets(k8sRoot.TypedSpec(), r.TypedSpec())\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *KubernetesController) updateSecrets(k8sRoot *secrets.KubernetesRootSpec, k8sSecrets *secrets.KubernetesCertsSpec) error {\n\tvar buf bytes.Buffer\n\n\tif err := kubeconfig.Generate(&kubeconfig.GenerateInput{\n\t\tClusterName: k8sRoot.Name,\n\n\t\tIssuingCA:           k8sRoot.IssuingCA,\n\t\tAcceptedCAs:         k8sRoot.AcceptedCAs,\n\t\tCertificateLifetime: KubernetesCertificateValidityDuration,\n\n\t\tCommonName:   constants.KubernetesControllerManagerOrganization,\n\t\tOrganization: constants.KubernetesControllerManagerOrganization,\n\n\t\tEndpoint:    k8sRoot.LocalEndpoint.String(),\n\t\tUsername:    constants.KubernetesControllerManagerOrganization,\n\t\tContextName: \"default\",\n\t}, &buf); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate controller manager kubeconfig: %w\", err)\n\t}\n\n\tk8sSecrets.ControllerManagerKubeconfig = buf.String()\n\n\tbuf.Reset()\n\n\tif err := kubeconfig.Generate(&kubeconfig.GenerateInput{\n\t\tClusterName: k8sRoot.Name,\n\n\t\tIssuingCA:           k8sRoot.IssuingCA,\n\t\tAcceptedCAs:         k8sRoot.AcceptedCAs,\n\t\tCertificateLifetime: KubernetesCertificateValidityDuration,\n\n\t\tCommonName:   constants.KubernetesSchedulerOrganization,\n\t\tOrganization: constants.KubernetesSchedulerOrganization,\n\n\t\tEndpoint:    k8sRoot.LocalEndpoint.String(),\n\t\tUsername:    constants.KubernetesSchedulerOrganization,\n\t\tContextName: \"default\",\n\t}, &buf); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate scheduler kubeconfig: %w\", err)\n\t}\n\n\tk8sSecrets.SchedulerKubeconfig = buf.String()\n\n\tbuf.Reset()\n\n\tif err := kubeconfig.GenerateAdmin(&generateAdminAdapter{\n\t\tk8sRoot:  k8sRoot,\n\t\tendpoint: k8sRoot.Endpoint,\n\t}, &buf); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate admin kubeconfig: %w\", err)\n\t}\n\n\tk8sSecrets.AdminKubeconfig = buf.String()\n\n\tbuf.Reset()\n\n\tif err := kubeconfig.GenerateAdmin(&generateAdminAdapter{\n\t\tk8sRoot:  k8sRoot,\n\t\tendpoint: k8sRoot.LocalEndpoint,\n\t}, &buf); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate admin kubeconfig: %w\", err)\n\t}\n\n\tk8sSecrets.LocalhostAdminKubeconfig = buf.String()\n\n\treturn nil\n}\n\nfunc (ctrl *KubernetesController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO: change this to proper teardown sequence\n\n\tfor _, res := range list.Items {\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// generateAdminAdapter allows to translate input config into GenerateAdmin input.\ntype generateAdminAdapter struct {\n\tk8sRoot  *secrets.KubernetesRootSpec\n\tendpoint *url.URL\n}\n\nfunc (adapter *generateAdminAdapter) Name() string {\n\treturn adapter.k8sRoot.Name\n}\n\nfunc (adapter *generateAdminAdapter) Endpoint() *url.URL {\n\treturn adapter.endpoint\n}\n\nfunc (adapter *generateAdminAdapter) IssuingCA() *x509.PEMEncodedCertificateAndKey {\n\treturn adapter.k8sRoot.IssuingCA\n}\n\nfunc (adapter *generateAdminAdapter) AcceptedCAs() []*x509.PEMEncodedCertificate {\n\treturn adapter.k8sRoot.AcceptedCAs\n}\n\nfunc (adapter *generateAdminAdapter) AdminKubeconfig() config.AdminKubeconfig {\n\treturn adapter\n}\n\nfunc (adapter *generateAdminAdapter) CertLifetime() time.Duration {\n\t// this certificate is not delivered to the user, it's used only internally by control plane components\n\treturn KubernetesCertificateValidityDuration\n}\n\nfunc (adapter *generateAdminAdapter) CommonName() string {\n\treturn constants.KubernetesTalosAdminCertCommonName\n}\n\nfunc (adapter *generateAdminAdapter) CertOrganization() string {\n\treturn constants.KubernetesAdminCertOrganization\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes_cert_sans.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// KubernetesCertSANsController manages secrets.KubernetesCertSANs based on configuration.\ntype KubernetesCertSANsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubernetesCertSANsController) Name() string {\n\treturn \"secrets.KubernetesCertSANsController\"\n}\n\n// Inputs implements controller.Controller interface.\n//\n//nolint:dupl\nfunc (ctrl *KubernetesCertSANsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s)),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubernetesCertSANsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.CertSANType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *KubernetesCertSANsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tk8sRootRes, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting root k8s secrets: %w\", err)\n\t\t}\n\n\t\tk8sRoot := k8sRootRes.TypedSpec()\n\n\t\thostnameResource, err := safe.ReaderGet[*network.HostnameStatus](ctx, r, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, network.HostnameID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\thostnameStatus := hostnameResource.TypedSpec()\n\n\t\taddressesResource, err := safe.ReaderGet[*network.NodeAddress](ctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s), resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnodeAddresses := addressesResource.TypedSpec()\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANKubernetesID), func(r *secrets.CertSAN) error {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tspec.Reset()\n\n\t\t\tspec.Append(k8sRoot.Endpoint.Hostname())\n\t\t\tspec.Append(k8sRoot.CertSANs...)\n\n\t\t\tspec.AppendDNSNames(\n\t\t\t\t\"kubernetes\",\n\t\t\t\t\"kubernetes.default\",\n\t\t\t\t\"kubernetes.default.svc\",\n\t\t\t\t\"kubernetes.default.svc.\"+k8sRoot.DNSDomain,\n\t\t\t\t\"localhost\",\n\t\t\t)\n\n\t\t\tspec.Append(\n\t\t\t\thostnameStatus.Hostname,\n\t\t\t\thostnameStatus.FQDN(),\n\t\t\t)\n\n\t\t\tspec.AppendIPs(k8sRoot.APIServerIPs...)\n\t\t\tspec.AppendIPs(nodeAddresses.IPs()...)\n\t\t\tspec.AppendIPs(netip.MustParseAddr(\"127.0.0.1\"))\n\n\t\t\tspec.Sort()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *KubernetesCertSANsController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range list.Items {\n\t\tif res.Metadata().Owner() == ctrl.Name() {\n\t\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes_cert_sans_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\ntype KubernetesCertSANsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestKubernetesCertSANsSuite(t *testing.T) {\n\tsuite.Run(t, &KubernetesCertSANsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.KubernetesCertSANsController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (suite *KubernetesCertSANsSuite) TestReconcile() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\n\tvar err error\n\n\trootSecrets.TypedSpec().CertSANs = []string{\"example.com\"}\n\trootSecrets.TypedSpec().APIServerIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\trootSecrets.TypedSpec().DNSDomain = \"cluster.remote\"\n\trootSecrets.TypedSpec().Endpoint, err = url.Parse(\"https://some.url:6443/\")\n\tsuite.Require().NoError(err)\n\trootSecrets.TypedSpec().LocalEndpoint, err = url.Parse(\"https://localhost:6443/\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets))\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"foo\"\n\thostnameStatus.TypedSpec().Domainname = \"example.com\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\tnodeAddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s),\n\t)\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.2.1.3/24\"),\n\t\tnetip.MustParsePrefix(\"172.16.0.1/32\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses))\n\n\tsuite.AssertWithin(10*time.Second, 100*time.Millisecond, func() error {\n\t\tcertSANs, err := ctest.Get[*secrets.CertSAN](\n\t\t\tsuite,\n\t\t\tresource.NewMetadata(\n\t\t\t\tsecrets.NamespaceName,\n\t\t\t\tsecrets.CertSANType,\n\t\t\t\tsecrets.CertSANKubernetesID,\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tspec := certSANs.TypedSpec()\n\n\t\tsuite.Assert().Equal(\n\t\t\t[]string{\n\t\t\t\t\"example.com\",\n\t\t\t\t\"foo\",\n\t\t\t\t\"foo.example.com\",\n\t\t\t\t\"kubernetes\",\n\t\t\t\t\"kubernetes.default\",\n\t\t\t\t\"kubernetes.default.svc\",\n\t\t\t\t\"kubernetes.default.svc.cluster.remote\",\n\t\t\t\t\"localhost\",\n\t\t\t\t\"some.url\",\n\t\t\t}, spec.DNSNames,\n\t\t)\n\t\tsuite.Assert().Equal(\"[10.2.1.3 10.4.3.2 127.0.0.1 172.16.0.1]\", fmt.Sprintf(\"%v\", spec.IPs))\n\n\t\treturn nil\n\t})\n\n\tctest.UpdateWithConflicts(suite, rootSecrets, func(rootSecrets *secrets.KubernetesRoot) error {\n\t\tvar err error\n\n\t\trootSecrets.TypedSpec().Endpoint, err = url.Parse(\"https://some.other.url:6443/\")\n\n\t\treturn err\n\t})\n\n\tsuite.AssertWithin(10*time.Second, 100*time.Millisecond, func() error {\n\t\tvar certSANs resource.Resource\n\n\t\tcertSANs, err := ctest.Get[*secrets.CertSAN](\n\t\t\tsuite,\n\t\t\tresource.NewMetadata(\n\t\t\t\tsecrets.NamespaceName,\n\t\t\t\tsecrets.CertSANType,\n\t\t\t\tsecrets.CertSANKubernetesID,\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tspec := certSANs.(*secrets.CertSAN).TypedSpec()\n\n\t\texpectedDNSNames := []string{\n\t\t\t\"example.com\",\n\t\t\t\"foo\",\n\t\t\t\"foo.example.com\",\n\t\t\t\"kubernetes\",\n\t\t\t\"kubernetes.default\",\n\t\t\t\"kubernetes.default.svc\",\n\t\t\t\"kubernetes.default.svc.cluster.remote\",\n\t\t\t\"localhost\",\n\t\t\t\"some.other.url\",\n\t\t}\n\n\t\tif !slices.Equal(spec.DNSNames, expectedDNSNames) {\n\t\t\treturn retry.ExpectedErrorf(\"expected %v, got %v\", expectedDNSNames, spec.DNSNames)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// KubernetesDynamicCertsController manages secrets.KubernetesDynamicCerts based on configuration.\ntype KubernetesDynamicCertsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *KubernetesDynamicCertsController) Name() string {\n\treturn \"secrets.KubernetesDynamicCertsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *KubernetesDynamicCertsController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *KubernetesDynamicCertsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.KubernetesDynamicCertsType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *KubernetesDynamicCertsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// wait for the network to be ready first, then switch to regular inputs\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating inputs: %w\", err)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\t\t// wait for network to be ready as it might change IPs/hostname\n\t\tnetworkStatus, err := safe.ReaderGet[*network.Status](ctx, r, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif networkStatus.TypedSpec().AddressReady && networkStatus.TypedSpec().HostnameReady {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// switch to regular inputs once the network is ready\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.KubernetesRootType,\n\t\t\tID:        optional.Some(secrets.KubernetesRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      timeresource.StatusType,\n\t\t\tID:        optional.Some(timeresource.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.CertSANType,\n\t\t\tID:        optional.Some(secrets.CertSANKubernetesID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error updating inputs: %w\", err)\n\t}\n\n\tr.QueueReconcile()\n\n\trefreshTicker := time.NewTicker(KubernetesCertificateValidityDuration / 2)\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-refreshTicker.C:\n\t\t}\n\n\t\tk8sRoot, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting root k8s secrets: %w\", err)\n\t\t}\n\n\t\t// wait for time sync as certs depend on current time\n\t\ttimeSync, err := safe.ReaderGet[*timeresource.Status](ctx, r, resource.NewMetadata(v1alpha1.NamespaceName, timeresource.StatusType, timeresource.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif !timeSync.TypedSpec().Synced {\n\t\t\tcontinue\n\t\t}\n\n\t\tcertSANs, err := safe.ReaderGet[*secrets.CertSAN](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, secrets.CertSANKubernetesID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewKubernetesDynamicCerts(), func(r *secrets.KubernetesDynamicCerts) error {\n\t\t\treturn ctrl.updateSecrets(k8sRoot.TypedSpec(), r.TypedSpec(), certSANs.TypedSpec())\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\nfunc (ctrl *KubernetesDynamicCertsController) updateSecrets(k8sRoot *secrets.KubernetesRootSpec, k8sCerts *secrets.KubernetesDynamicCertsSpec,\n\tcertSANs *secrets.CertSANSpec,\n) error {\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sRoot.IssuingCA)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tapiServer, err := x509.NewKeyPair(ca,\n\t\tx509.IPAddresses(certSANs.StdIPs()),\n\t\tx509.DNSNames(certSANs.DNSNames),\n\t\tx509.CommonName(\"kube-apiserver\"),\n\t\tx509.Organization(\"kube-master\"),\n\t\tx509.NotAfter(time.Now().Add(KubernetesCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate api-server cert: %w\", err)\n\t}\n\n\tk8sCerts.APIServer = x509.NewCertificateAndKeyFromKeyPair(apiServer)\n\n\tapiServerKubeletClient, err := x509.NewKeyPair(ca,\n\t\tx509.CommonName(constants.KubernetesAPIServerKubeletClientCommonName),\n\t\tx509.Organization(constants.KubernetesAdminCertOrganization),\n\t\tx509.NotAfter(time.Now().Add(KubernetesCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate api-server cert: %w\", err)\n\t}\n\n\tk8sCerts.APIServerKubeletClient = x509.NewCertificateAndKeyFromKeyPair(apiServerKubeletClient)\n\n\taggregatorCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sRoot.AggregatorCA)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse aggregator CA: %w\", err)\n\t}\n\n\tfrontProxy, err := x509.NewKeyPair(aggregatorCA,\n\t\tx509.CommonName(\"front-proxy-client\"),\n\t\tx509.NotAfter(time.Now().Add(KubernetesCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate aggregator cert: %w\", err)\n\t}\n\n\tk8sCerts.FrontProxy = x509.NewCertificateAndKeyFromKeyPair(frontProxy)\n\n\treturn nil\n}\n\nfunc (ctrl *KubernetesDynamicCertsController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesDynamicCertsType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO: change this to proper teardown sequence\n\n\tfor _, res := range list.Items {\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes_dynamic_certs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nfunc TestKubernetesDynamicCertsSuite(t *testing.T) {\n\tsuite.Run(t, &KubernetesDynamicCertsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.KubernetesDynamicCertsController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype KubernetesDynamicCertsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubernetesDynamicCertsSuite) TestReconcile() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\n\tk8sCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"kubernetes\"),\n\t\tx509.ECDSA(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\taggregatorCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"kubernetes\"),\n\t\tx509.ECDSA(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\tserviceAccount, err := x509.NewECDSAKey()\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().Name = \"cluster1\"\n\trootSecrets.TypedSpec().Endpoint, err = url.Parse(\"https://some.url:6443/\")\n\tsuite.Require().NoError(err)\n\trootSecrets.TypedSpec().LocalEndpoint, err = url.Parse(\"https://localhost:6443/\")\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().IssuingCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: k8sCA.CrtPEM,\n\t\tKey: k8sCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().AggregatorCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: aggregatorCA.CrtPEM,\n\t\tKey: aggregatorCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().ServiceAccount = &x509.PEMEncodedKey{\n\t\tKey: serviceAccount.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().CertSANs = []string{\"example.com\"}\n\trootSecrets.TypedSpec().APIServerIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\trootSecrets.TypedSpec().DNSDomain = \"cluster.remote\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tnetworkStatus.TypedSpec().HostnameReady = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), networkStatus))\n\n\tcertSANs := secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANKubernetesID)\n\tcertSANs.TypedSpec().Append(\n\t\t\"example.com\",\n\t\t\"foo\",\n\t\t\"foo.example.com\",\n\t\t\"kubernetes\",\n\t\t\"kubernetes.default\",\n\t\t\"kubernetes.default.svc\",\n\t\t\"kubernetes.default.svc.cluster.remote\",\n\t\t\"localhost\",\n\t\t\"some.url\",\n\t\t\"10.2.1.3\",\n\t\t\"10.4.3.2\",\n\t\t\"172.16.0.1\",\n\t)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), certSANs))\n\n\ttimeSync := timeresource.NewStatus()\n\t*timeSync.TypedSpec() = timeresource.StatusSpec{\n\t\tSynced: true,\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), timeSync))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.KubernetesDynamicCertsID},\n\t\tfunc(certs *secrets.KubernetesDynamicCerts, assertion *assert.Assertions) {\n\t\t\tkubernetesCerts := certs.TypedSpec()\n\n\t\t\tapiCert, err := kubernetesCerts.APIServer.GetCert()\n\t\t\tassertion.NoError(err)\n\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassertion.Equal(\n\t\t\t\t[]string{\n\t\t\t\t\t\"example.com\",\n\t\t\t\t\t\"foo\",\n\t\t\t\t\t\"foo.example.com\",\n\t\t\t\t\t\"kubernetes\",\n\t\t\t\t\t\"kubernetes.default\",\n\t\t\t\t\t\"kubernetes.default.svc\",\n\t\t\t\t\t\"kubernetes.default.svc.cluster.remote\",\n\t\t\t\t\t\"localhost\",\n\t\t\t\t\t\"some.url\",\n\t\t\t\t}, apiCert.DNSNames,\n\t\t\t)\n\t\t\tassertion.Equal(\"[10.2.1.3 10.4.3.2 172.16.0.1]\", fmt.Sprintf(\"%v\", apiCert.IPAddresses))\n\n\t\t\tassertion.Equal(\"kube-apiserver\", apiCert.Subject.CommonName)\n\t\t\tassertion.Equal([]string{\"kube-master\"}, apiCert.Subject.Organization)\n\n\t\t\tassertion.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,\n\t\t\t\tapiCert.KeyUsage,\n\t\t\t)\n\t\t\tassertion.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, apiCert.ExtKeyUsage)\n\n\t\t\tclientCert, err := kubernetesCerts.APIServerKubeletClient.GetCert()\n\t\t\tassertion.NoError(err)\n\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassertion.Empty(clientCert.DNSNames)\n\t\t\tassertion.Empty(clientCert.IPAddresses)\n\n\t\t\tassertion.Equal(\n\t\t\t\tconstants.KubernetesAPIServerKubeletClientCommonName,\n\t\t\t\tclientCert.Subject.CommonName,\n\t\t\t)\n\t\t\tassertion.Equal(\n\t\t\t\t[]string{constants.KubernetesAdminCertOrganization},\n\t\t\t\tclientCert.Subject.Organization,\n\t\t\t)\n\n\t\t\tassertion.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,\n\t\t\t\tclientCert.KeyUsage,\n\t\t\t)\n\t\t\tassertion.Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage)\n\n\t\t\tfrontProxyCert, err := kubernetesCerts.FrontProxy.GetCert()\n\t\t\tassertion.NoError(err)\n\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassertion.Empty(frontProxyCert.DNSNames)\n\t\t\tassertion.Empty(frontProxyCert.IPAddresses)\n\n\t\t\tassertion.Equal(\"front-proxy-client\", frontProxyCert.Subject.CommonName)\n\t\t\tassertion.Empty(frontProxyCert.Subject.Organization)\n\n\t\t\tassertion.Equal(\n\t\t\t\tstdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,\n\t\t\t\tfrontProxyCert.KeyUsage,\n\t\t\t)\n\t\t\tassertion.Equal(\n\t\t\t\t[]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth},\n\t\t\t\tfrontProxyCert.ExtKeyUsage,\n\t\t\t)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/kubernetes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nfunc TestKubernetesSuite(t *testing.T) {\n\tsuite.Run(t, &KubernetesSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.KubernetesController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype KubernetesSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *KubernetesSuite) TestReconcile() {\n\trootSecrets := secrets.NewKubernetesRoot(secrets.KubernetesRootID)\n\n\tk8sCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"kubernetes\"),\n\t\tx509.ECDSA(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\taggregatorCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"kubernetes\"),\n\t\tx509.ECDSA(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\tserviceAccount, err := x509.NewECDSAKey()\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().Name = \"cluster1\"\n\trootSecrets.TypedSpec().Endpoint, err = url.Parse(\"https://some.url:6443/\")\n\tsuite.Require().NoError(err)\n\trootSecrets.TypedSpec().LocalEndpoint, err = url.Parse(\"https://localhost:6443/\")\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().IssuingCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: k8sCA.CrtPEM,\n\t\tKey: k8sCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().AggregatorCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: aggregatorCA.CrtPEM,\n\t\tKey: aggregatorCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().ServiceAccount = &x509.PEMEncodedKey{\n\t\tKey: serviceAccount.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().CertSANs = []string{\"example.com\"}\n\trootSecrets.TypedSpec().APIServerIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\trootSecrets.TypedSpec().DNSDomain = \"cluster.svc\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\ttimeSync := timeresource.NewStatus()\n\t*timeSync.TypedSpec() = timeresource.StatusSpec{\n\t\tSynced: true,\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), timeSync))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.KubernetesID},\n\t\tfunc(certs *secrets.Kubernetes, assertion *assert.Assertions) {\n\t\t\tkubernetesCerts := certs.TypedSpec()\n\n\t\t\tfor _, kubeconfig := range []string{\n\t\t\t\tkubernetesCerts.ControllerManagerKubeconfig,\n\t\t\t\tkubernetesCerts.SchedulerKubeconfig,\n\t\t\t\tkubernetesCerts.LocalhostAdminKubeconfig,\n\t\t\t\tkubernetesCerts.AdminKubeconfig,\n\t\t\t} {\n\t\t\t\tconfig, err := clientcmd.Load([]byte(kubeconfig))\n\t\t\t\tassertion.NoError(err)\n\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tassertion.NoError(clientcmd.ConfirmUsable(*config, config.CurrentContext))\n\t\t\t}\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// MaintenanceCertSANsController manages secrets.APICertSANs based on configuration.\ntype MaintenanceCertSANsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MaintenanceCertSANsController) Name() string {\n\treturn \"secrets.MaintenanceCertSANsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceCertSANsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.HostnameStatusType,\n\t\t\tID:        optional.Some(network.HostnameID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.NodeAddressType,\n\t\t\tID:        optional.Some(network.NodeAddressAccumulativeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceCertSANsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.CertSANType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *MaintenanceCertSANsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\thostnameStatus, err := safe.ReaderGetByID[*network.HostnameStatus](ctx, r, network.HostnameID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get hostname status: %w\", err)\n\t\t}\n\n\t\tnodeAddresses, err := safe.ReaderGetByID[*network.NodeAddress](ctx, r, network.NodeAddressAccumulativeID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANMaintenanceID), func(r *secrets.CertSAN) error {\n\t\t\tspec := r.TypedSpec()\n\n\t\t\tspec.Reset()\n\n\t\t\tspec.AppendIPs(nodeAddresses.TypedSpec().IPs()...)\n\t\t\tspec.AppendIPs(netip.MustParseAddr(\"127.0.0.1\"))\n\t\t\tspec.AppendIPs(netip.MustParseAddr(\"::1\"))\n\n\t\t\tif hostnameStatus != nil {\n\t\t\t\tspec.AppendDNSNames(hostnameStatus.TypedSpec().DNSNames()...)\n\t\t\t}\n\n\t\t\tspec.FQDN = constants.MaintenanceServiceCommonName\n\n\t\t\tspec.Sort()\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/maintenance_cert_sans_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestMaintenanceCertSANsSuite(t *testing.T) {\n\tsuite.Run(t, &MaintenanceCertSANsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 2 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceCertSANsController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype MaintenanceCertSANsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *MaintenanceCertSANsSuite) TestReconcile() {\n\tnodeAddresses := network.NewNodeAddress(\n\t\tnetwork.NamespaceName,\n\t\tnetwork.NodeAddressAccumulativeID,\n\t)\n\tnodeAddresses.TypedSpec().Addresses = []netip.Prefix{\n\t\tnetip.MustParsePrefix(\"10.2.1.3/24\"),\n\t\tnetip.MustParsePrefix(\"172.16.0.1/32\"),\n\t}\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), nodeAddresses))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.CertSANMaintenanceID},\n\t\tfunc(certSANs *secrets.CertSAN, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(certSANs.TypedSpec().DNSNames)\n\t\t\tasrt.Equal(\"[10.2.1.3 127.0.0.1 172.16.0.1 ::1]\", fmt.Sprintf(\"%v\", certSANs.TypedSpec().IPs))\n\t\t\tasrt.Equal(constants.MaintenanceServiceCommonName, certSANs.TypedSpec().FQDN)\n\t\t})\n\n\thostnameStatus := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameStatus.TypedSpec().Hostname = \"bar\"\n\thostnameStatus.TypedSpec().Domainname = \"some.org\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), hostnameStatus))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.CertSANMaintenanceID},\n\t\tfunc(certSANs *secrets.CertSAN, asrt *assert.Assertions) {\n\t\t\tasrt.Equal([]string{\"bar\", \"bar.some.org\"}, certSANs.TypedSpec().DNSNames)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/maintenance_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// MaintenanceRootController manages secrets.Root based on configuration.\ntype MaintenanceRootController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *MaintenanceRootController) Name() string {\n\treturn \"secrets.MaintenanceRootController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceRootController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *MaintenanceRootController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.MaintenanceRootType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *MaintenanceRootController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\t// run this controller only once, as the CA never changes\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil\n\tcase <-r.EventCh():\n\t}\n\n\treturn safe.WriterModify(ctx, r, secrets.NewMaintenanceRoot(secrets.MaintenanceRootID), func(root *secrets.MaintenanceRoot) error {\n\t\tca, err := x509.NewSelfSignedCertificateAuthority()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate self-signed CA: %w\", err)\n\t\t}\n\n\t\troot.TypedSpec().CA = x509.NewCertificateAndKeyFromCertificateAuthority(ca)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/maintenance_root_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestMaintenanceRootSuite(t *testing.T) {\n\tsuite.Run(t, &MaintenanceRootSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.MaintenanceRootController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype MaintenanceRootSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *MaintenanceRootSuite) TestReconcile() {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.MaintenanceRootID},\n\t\tfunc(root *secrets.MaintenanceRoot, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(root.TypedSpec().CA)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic\"\n\t\"github.com/cosi-project/runtime/pkg/controller/generic/transform\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc rootMapFunc[Output generic.ResourceWithRD](output Output, requireControlPlane bool) func(cfg *config.MachineConfig) optional.Optional[Output] {\n\treturn func(cfg *config.MachineConfig) optional.Optional[Output] {\n\t\tif cfg.Metadata().ID() != config.ActiveID {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\tif cfg.Config().Cluster() == nil || cfg.Config().Machine() == nil {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\tif requireControlPlane && !cfg.Config().Machine().Type().IsControlPlane() {\n\t\t\treturn optional.None[Output]()\n\t\t}\n\n\t\treturn optional.Some(output)\n\t}\n}\n\n// RootEtcdController manages secrets.EtcdRoot based on configuration.\ntype RootEtcdController = transform.Controller[*config.MachineConfig, *secrets.EtcdRoot]\n\n// NewRootEtcdController instanciates the controller.\nfunc NewRootEtcdController() *RootEtcdController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *secrets.EtcdRoot]{\n\t\t\tName:                    \"secrets.RootEtcdController\",\n\t\t\tMapMetadataOptionalFunc: rootMapFunc(secrets.NewEtcdRoot(secrets.EtcdRootID), true),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.EtcdRoot) error {\n\t\t\t\tcfgProvider := cfg.Config()\n\t\t\t\tetcdSecrets := res.TypedSpec()\n\n\t\t\t\tetcdSecrets.EtcdCA = cfgProvider.Cluster().Etcd().CA()\n\n\t\t\t\tif etcdSecrets.EtcdCA == nil {\n\t\t\t\t\treturn errors.New(\"missing cluster.etcdCA secret\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// RootKubernetesController manages secrets.KubernetesRoot based on configuration.\ntype RootKubernetesController = transform.Controller[*config.MachineConfig, *secrets.KubernetesRoot]\n\n// NewRootKubernetesController instanciates the controller.\nfunc NewRootKubernetesController() *RootKubernetesController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *secrets.KubernetesRoot]{\n\t\t\tName:                    \"secrets.RootKubernetesController\",\n\t\t\tMapMetadataOptionalFunc: rootMapFunc(secrets.NewKubernetesRoot(secrets.KubernetesRootID), true),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.KubernetesRoot) error {\n\t\t\t\tcfgProvider := cfg.Config()\n\t\t\t\tk8sSecrets := res.TypedSpec()\n\n\t\t\t\tvar (\n\t\t\t\t\terr           error\n\t\t\t\t\tlocalEndpoint *url.URL\n\t\t\t\t)\n\n\t\t\t\tif cfgProvider.Machine().Features().KubePrism().Enabled() {\n\t\t\t\t\tlocalEndpoint, err = url.Parse(fmt.Sprintf(\"https://127.0.0.1:%d\", cfgProvider.Machine().Features().KubePrism().Port()))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlocalEndpoint, err = url.Parse(fmt.Sprintf(\"https://localhost:%d\", cfgProvider.Cluster().LocalAPIServerPort()))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tk8sSecrets.Name = cfgProvider.Cluster().Name()\n\t\t\t\tk8sSecrets.Endpoint = cfgProvider.Cluster().Endpoint()\n\t\t\t\tk8sSecrets.LocalEndpoint = localEndpoint\n\t\t\t\tk8sSecrets.CertSANs = cfgProvider.Cluster().CertSANs()\n\t\t\t\tk8sSecrets.DNSDomain = cfgProvider.Cluster().Network().DNSDomain()\n\n\t\t\t\tk8sSecrets.APIServerIPs, err = cfgProvider.Cluster().Network().APIServerIPs()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error building API service IPs: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tk8sSecrets.AggregatorCA = cfgProvider.Cluster().AggregatorCA()\n\n\t\t\t\tif k8sSecrets.AggregatorCA == nil {\n\t\t\t\t\treturn errors.New(\"missing cluster.aggregatorCA secret\")\n\t\t\t\t}\n\n\t\t\t\tk8sSecrets.IssuingCA = cfgProvider.Cluster().IssuingCA()\n\t\t\t\tk8sSecrets.AcceptedCAs = cfgProvider.Cluster().AcceptedCAs()\n\n\t\t\t\tif k8sSecrets.IssuingCA != nil {\n\t\t\t\t\tk8sSecrets.AcceptedCAs = append(k8sSecrets.AcceptedCAs, &x509.PEMEncodedCertificate{\n\t\t\t\t\t\tCrt: k8sSecrets.IssuingCA.Crt,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif len(k8sSecrets.IssuingCA.Key) == 0 {\n\t\t\t\t\t// drop incomplete issuing CA, as the machine config for workers contains just the cert\n\t\t\t\t\tk8sSecrets.IssuingCA = nil\n\t\t\t\t}\n\n\t\t\t\tif len(k8sSecrets.AcceptedCAs) == 0 {\n\t\t\t\t\treturn errors.New(\"missing cluster.CA secret\")\n\t\t\t\t}\n\n\t\t\t\tk8sSecrets.ServiceAccount = cfgProvider.Cluster().ServiceAccount()\n\n\t\t\t\tk8sSecrets.AESCBCEncryptionSecret = cfgProvider.Cluster().AESCBCEncryptionSecret()\n\t\t\t\tk8sSecrets.SecretboxEncryptionSecret = cfgProvider.Cluster().SecretboxEncryptionSecret()\n\n\t\t\t\tk8sSecrets.BootstrapTokenID = cfgProvider.Cluster().Token().ID()\n\t\t\t\tk8sSecrets.BootstrapTokenSecret = cfgProvider.Cluster().Token().Secret()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n\n// RootOSController manages secrets.OSRoot based on configuration.\ntype RootOSController = transform.Controller[*config.MachineConfig, *secrets.OSRoot]\n\n// NewRootOSController instanciates the controller.\nfunc NewRootOSController() *RootOSController {\n\treturn transform.NewController(\n\t\ttransform.Settings[*config.MachineConfig, *secrets.OSRoot]{\n\t\t\tName:                    \"secrets.RootOSController\",\n\t\t\tMapMetadataOptionalFunc: rootMapFunc(secrets.NewOSRoot(secrets.OSRootID), false),\n\t\t\tTransformFunc: func(ctx context.Context, r controller.Reader, logger *zap.Logger, cfg *config.MachineConfig, res *secrets.OSRoot) error {\n\t\t\t\tcfgProvider := cfg.Config()\n\t\t\t\tosSecrets := res.TypedSpec()\n\n\t\t\t\tosSecrets.IssuingCA = cfgProvider.Machine().Security().IssuingCA()\n\t\t\t\tosSecrets.AcceptedCAs = cfgProvider.Machine().Security().AcceptedCAs()\n\n\t\t\t\tif osSecrets.IssuingCA != nil {\n\t\t\t\t\tosSecrets.AcceptedCAs = append(osSecrets.AcceptedCAs, &x509.PEMEncodedCertificate{\n\t\t\t\t\t\tCrt: osSecrets.IssuingCA.Crt,\n\t\t\t\t\t})\n\n\t\t\t\t\tif len(osSecrets.IssuingCA.Key) == 0 {\n\t\t\t\t\t\t// drop incomplete issuing CA, as the machine config for workers contains just the cert\n\t\t\t\t\t\tosSecrets.IssuingCA = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tosSecrets.CertSANIPs = nil\n\t\t\t\tosSecrets.CertSANDNSNames = nil\n\n\t\t\t\tfor _, san := range cfgProvider.Machine().Security().CertSANs() {\n\t\t\t\t\tif ip, err := netip.ParseAddr(san); err == nil {\n\t\t\t\t\t\tosSecrets.CertSANIPs = append(osSecrets.CertSANIPs, ip)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tosSecrets.CertSANDNSNames = append(osSecrets.CertSANDNSNames, san)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif cfgProvider.Machine().Features().KubernetesTalosAPIAccess().Enabled() {\n\t\t\t\t\t// add Kubernetes Talos service name to the list of SANs\n\t\t\t\t\tosSecrets.CertSANDNSNames = append(osSecrets.CertSANDNSNames,\n\t\t\t\t\t\tconstants.KubernetesTalosAPIServiceName,\n\t\t\t\t\t\tconstants.KubernetesTalosAPIServiceName+\".\"+constants.KubernetesTalosAPIServiceNamespace,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tosSecrets.Token = cfgProvider.Machine().Security().Token()\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/root_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestRootSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &RootSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(secretsctrl.NewRootEtcdController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(secretsctrl.NewRootKubernetesController()))\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(secretsctrl.NewRootOSController()))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype RootSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *RootSuite) genConfig(controlplane bool) talosconfig.Config {\n\tinput, err := generate.NewInput(\"test-cluster\", \"http://localhost:6443\", \"\")\n\tsuite.Require().NoError(err)\n\n\tvar cfg talosconfig.Provider\n\n\tif controlplane {\n\t\tcfg, err = input.Config(machine.TypeControlPlane)\n\t} else {\n\t\tcfg, err = input.Config(machine.TypeWorker)\n\t}\n\n\tsuite.Require().NoError(err)\n\n\tmachineCfg := config.NewMachineConfig(cfg)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineCfg))\n\n\treturn cfg\n}\n\nfunc (suite *RootSuite) TestReconcileControlPlane() {\n\tcfg := suite.genConfig(true)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.EtcdRootID},\n\t\tfunc(res *secrets.EtcdRoot, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(res.TypedSpec().EtcdCA, cfg.Cluster().Etcd().CA())\n\t\t},\n\t)\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.KubernetesRootID},\n\t\tfunc(res *secrets.KubernetesRoot, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(res.TypedSpec().IssuingCA, cfg.Cluster().IssuingCA())\n\t\t\tasrt.Equal(\n\t\t\t\t[]*x509.PEMEncodedCertificate{\n\t\t\t\t\t{\n\t\t\t\t\t\tCrt: cfg.Cluster().IssuingCA().Crt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tres.TypedSpec().AcceptedCAs,\n\t\t\t)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.OSRootID},\n\t\tfunc(res *secrets.OSRoot, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(res.TypedSpec().IssuingCA, cfg.Machine().Security().IssuingCA())\n\t\t\tasrt.Equal(\n\t\t\t\t[]*x509.PEMEncodedCertificate{\n\t\t\t\t\t{\n\t\t\t\t\t\tCrt: cfg.Machine().Security().IssuingCA().Crt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tres.TypedSpec().AcceptedCAs,\n\t\t\t)\n\t\t},\n\t)\n}\n\nfunc (suite *RootSuite) TestReconcileWorker() {\n\tcfg := suite.genConfig(false)\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{secrets.OSRootID},\n\t\tfunc(res *secrets.OSRoot, asrt *assert.Assertions) {\n\t\t\tasrt.Nil(res.TypedSpec().IssuingCA)\n\t\t\tasrt.Equal(\n\t\t\t\t[]*x509.PEMEncodedCertificate{\n\t\t\t\t\t{\n\t\t\t\t\t\tCrt: cfg.Machine().Security().IssuingCA().Crt,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tres.TypedSpec().AcceptedCAs,\n\t\t\t)\n\t\t},\n\t)\n\n\trtestutils.AssertNoResource[*secrets.Etcd](suite.Ctx(), suite.T(), suite.State(), secrets.EtcdRootID)\n\trtestutils.AssertNoResource[*secrets.Kubernetes](suite.Ctx(), suite.T(), suite.State(), secrets.KubernetesRootID)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/secrets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package secrets provides controllers which manage secret resources.\npackage secrets\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/trustd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\tstdlibx509 \"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// TrustdController manages secrets.API based on configuration to provide apid certificate.\ntype TrustdController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *TrustdController) Name() string {\n\treturn \"secrets.TrustdController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *TrustdController) Inputs() []controller.Input {\n\t// initial set of inputs: wait for machine type to be known and network to be partially configured\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: network.NamespaceName,\n\t\t\tType:      network.StatusType,\n\t\t\tID:        optional.Some(network.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *TrustdController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: secrets.TrustdType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *TrustdController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\t// reset inputs back to what they were initially\n\t\tif err := r.UpdateInputs(ctrl.Inputs()); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tmachineType := machineTypeRes.MachineType()\n\n\t\tnetworkResource, err := safe.ReaderGet[*network.Status](ctx, r, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkStatus := networkResource.TypedSpec()\n\n\t\tif !(networkStatus.AddressReady && networkStatus.HostnameReady) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// machine type is known and network is ready, we can now proceed to one or another reconcile loop\n\t\tif machineType.IsControlPlane() {\n\t\t\tif err = ctrl.reconcile(ctx, r, logger); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo,dupl\nfunc (ctrl *TrustdController) reconcile(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tinputs := []controller.Input{\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.OSRootType,\n\t\t\tID:        optional.Some(secrets.OSRootID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: secrets.NamespaceName,\n\t\t\tType:      secrets.CertSANType,\n\t\t\tID:        optional.Some(secrets.CertSANAPIID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineTypeType,\n\t\t\tID:        optional.Some(config.MachineTypeID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t// time status isn't fetched, but the fact that it is in dependencies means\n\t\t// that certs will be regenerated on time sync/jump (as reconcile will be triggered)\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      timeresource.StatusType,\n\t\t\tID:        optional.Some(timeresource.StatusID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n\n\tif err := r.UpdateInputs(inputs); err != nil {\n\t\treturn fmt.Errorf(\"error updating inputs: %w\", err)\n\t}\n\n\tr.QueueReconcile()\n\n\trefreshTicker := time.NewTicker(x509.DefaultCertificateValidityDuration / 2)\n\tdefer refreshTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-refreshTicker.C:\n\t\t}\n\n\t\tmachineTypeRes, err := safe.ReaderGet[*config.MachineType](ctx, r, resource.NewMetadata(config.NamespaceName, config.MachineTypeType, config.MachineTypeID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting machine type: %w\", err)\n\t\t}\n\n\t\tmachineType := machineTypeRes.MachineType()\n\n\t\tif !machineType.IsControlPlane() {\n\t\t\treturn errors.New(\"machine type changed\")\n\t\t}\n\n\t\trootResource, err := safe.ReaderGet[*secrets.OSRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.OSRootType, secrets.OSRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tif err = ctrl.teardownAll(ctx, r); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error destroying resources: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting etcd root secrets: %w\", err)\n\t\t}\n\n\t\trootSpec := rootResource.TypedSpec()\n\n\t\tcertSANResource, err := safe.ReaderGet[*secrets.CertSAN](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, secrets.CertSANAPIID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error getting certSANs: %w\", err)\n\t\t}\n\n\t\tcertSANs := certSANResource.TypedSpec()\n\n\t\tif err := ctrl.generateControlPlane(ctx, r, logger, rootSpec, certSANs); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (ctrl *TrustdController) generateControlPlane(ctx context.Context, r controller.Runtime, logger *zap.Logger, rootSpec *secrets.OSRootSpec, certSANs *secrets.CertSANSpec) error {\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(rootSpec.IssuingCA)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CA certificate: %w\", err)\n\t}\n\n\tserverCert, err := x509.NewKeyPair(ca,\n\t\tx509.IPAddresses(certSANs.StdIPs()),\n\t\tx509.DNSNames(certSANs.DNSNames),\n\t\tx509.CommonName(certSANs.FQDN),\n\t\tx509.NotAfter(time.Now().Add(x509.DefaultCertificateValidityDuration)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to generate API server cert: %w\", err)\n\t}\n\n\tif err := safe.WriterModify(ctx, r, secrets.NewTrustd(),\n\t\tfunc(r *secrets.Trustd) error {\n\t\t\ttrustdSecrets := r.TypedSpec()\n\n\t\t\ttrustdSecrets.AcceptedCAs = rootSpec.AcceptedCAs\n\t\t\ttrustdSecrets.Server = x509.NewCertificateAndKeyFromKeyPair(serverCert)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error modifying resource: %w\", err)\n\t}\n\n\tserverFingerprint, _ := x509.SPKIFingerprintFromDER(serverCert.Certificate.Certificate[0]) //nolint:errcheck\n\n\tlogger.Debug(\"generated new certificates\",\n\t\tzap.Stringer(\"server\", serverFingerprint),\n\t)\n\n\treturn nil\n}\n\nfunc (ctrl *TrustdController) teardownAll(ctx context.Context, r controller.Runtime) error {\n\tlist, err := r.List(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.TrustdType, \"\", resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, res := range list.Items {\n\t\tif err = r.Destroy(ctx, res.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/trustd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestTrustdSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TrustdSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.TrustdController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype TrustdSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TrustdSuite) TestReconcileControlPlane() {\n\trootSecrets := secrets.NewOSRoot(secrets.OSRootID)\n\n\ttalosCA, err := x509.NewSelfSignedCertificateAuthority(\n\t\tx509.Organization(\"talos\"),\n\t)\n\tsuite.Require().NoError(err)\n\n\trootSecrets.TypedSpec().IssuingCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: talosCA.CrtPEM,\n\t\tKey: talosCA.KeyPEM,\n\t}\n\trootSecrets.TypedSpec().AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t{\n\t\t\tCrt: talosCA.CrtPEM,\n\t\t},\n\t}\n\trootSecrets.TypedSpec().CertSANDNSNames = []string{\"example.com\"}\n\trootSecrets.TypedSpec().CertSANIPs = []netip.Addr{netip.MustParseAddr(\"10.4.3.2\"), netip.MustParseAddr(\"10.2.1.3\")}\n\trootSecrets.TypedSpec().Token = \"something\"\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), rootSecrets))\n\n\tmachineType := config.NewMachineType()\n\tmachineType.SetMachineType(machine.TypeControlPlane)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), machineType))\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tnetworkStatus.TypedSpec().HostnameReady = true\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), networkStatus))\n\n\tcertSANs := secrets.NewCertSAN(secrets.NamespaceName, secrets.CertSANAPIID)\n\tcertSANs.TypedSpec().Append(\n\t\t\"example.com\",\n\t\t\"foo\",\n\t\t\"foo.example.com\",\n\t\t\"10.2.1.3\",\n\t\t\"10.4.3.2\",\n\t\t\"172.16.0.1\",\n\t)\n\n\tcertSANs.TypedSpec().FQDN = \"foo.example.com\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), certSANs))\n\tsuite.AssertWithin(10*time.Second, 100*time.Millisecond, func() error {\n\t\tcerts, err := ctest.Get[*secrets.Trustd](\n\t\t\tsuite,\n\t\t\tresource.NewMetadata(\n\t\t\t\tsecrets.NamespaceName,\n\t\t\t\tsecrets.TrustdType,\n\t\t\t\tsecrets.TrustdID,\n\t\t\t\tresource.VersionUndefined,\n\t\t\t),\n\t\t)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\ttrustdCerts := certs.TypedSpec()\n\n\t\tsuite.Assert().Equal(\n\t\t\t[]*x509.PEMEncodedCertificate{\n\t\t\t\t{\n\t\t\t\t\tCrt: talosCA.CrtPEM,\n\t\t\t\t},\n\t\t\t},\n\t\t\ttrustdCerts.AcceptedCAs,\n\t\t)\n\n\t\tserverCert, err := trustdCerts.Server.GetCert()\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Assert().Equal([]string{\"example.com\", \"foo\", \"foo.example.com\"}, serverCert.DNSNames)\n\t\tsuite.Assert().Equal(\"[10.2.1.3 10.4.3.2 172.16.0.1]\", fmt.Sprintf(\"%v\", serverCert.IPAddresses))\n\n\t\tsuite.Assert().Equal(\"foo.example.com\", serverCert.Subject.CommonName)\n\t\tsuite.Assert().Empty(serverCert.Subject.Organization)\n\n\t\tsuite.Assert().Equal(\n\t\t\tstdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,\n\t\t\tserverCert.KeyUsage,\n\t\t)\n\t\tsuite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage)\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/trusted_roots.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\n//go:embed data/ca-certificates\nvar defaultCACertificates []byte\n\n// TrustedRootsController manages CA trusted roots based on configuration.\ntype TrustedRootsController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *TrustedRootsController) Name() string {\n\treturn \"secrets.TrustedRootsController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *TrustedRootsController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *TrustedRootsController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: files.EtcFileSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *TrustedRootsController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get machine config: %w\", err)\n\t\t}\n\n\t\tcontents := slices.Clone(defaultCACertificates)\n\n\t\tif cfg != nil {\n\t\t\tcontents = slices.Concat(contents, []byte(strings.Join(cfg.Config().TrustedRoots().ExtraTrustedRootCertificates(), \"\\n\\n\")))\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, files.NewEtcFileSpec(files.NamespaceName, constants.DefaultTrustedRelativeCAFile), func(spec *files.EtcFileSpec) error {\n\t\t\tspec.TypedSpec().Mode = 0o644\n\t\t\tspec.TypedSpec().Contents = contents\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write trusted roots: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/secrets/trusted_roots_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecretsctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\nfunc TestTrustedRootsSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TrustedRootsSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 10 * time.Second,\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&secretsctrl.TrustedRootsController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n\ntype TrustedRootsSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TrustedRootsSuite) TestReconcileDefault() {\n\tctest.AssertResources(suite, []string{constants.DefaultTrustedRelativeCAFile}, func(r *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\tasrt.EqualValues(0o644, r.TypedSpec().Mode)\n\t\tasrt.Contains(string(r.TypedSpec().Contents), \"Bundle of CA Root Certificates\")\n\t})\n}\n\nfunc (suite *TrustedRootsSuite) TestReconcileExtraCAs() {\n\ttrustedRoot1 := security.NewTrustedRootsConfigV1Alpha1()\n\ttrustedRoot1.MetaName = \"root1\"\n\ttrustedRoot1.Certificates = \"-- BEGIN1 --\"\n\n\ttrustedRoot2 := security.NewTrustedRootsConfigV1Alpha1()\n\ttrustedRoot2.MetaName = \"root2\"\n\ttrustedRoot2.Certificates = \"-- BEGIN2 --\"\n\n\tcfg, err := container.New(trustedRoot1, trustedRoot2)\n\tsuite.Require().NoError(err)\n\n\tmc := config.NewMachineConfig(cfg)\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), mc))\n\n\tctest.AssertResources(suite, []string{constants.DefaultTrustedRelativeCAFile}, func(r *files.EtcFileSpec, asrt *assert.Assertions) {\n\t\tasrt.EqualValues(0o644, r.TypedSpec().Mode)\n\n\t\tasrt.Contains(string(r.TypedSpec().Contents), \"Bundle of CA Root Certificates\")\n\n\t\tfor _, contains := range []string{\n\t\t\ttrustedRoot1.MetaName,\n\t\t\ttrustedRoot1.Certificates,\n\t\t\ttrustedRoot2.MetaName,\n\t\t\ttrustedRoot2.Certificates,\n\t\t} {\n\t\t\tasrt.Contains(string(r.TypedSpec().Contents), contains)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/security/image_verification_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage security\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\tconfigres \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\n// ImageVerificationConfigController watches machine config and produces ImageVerificationRule resource.\ntype ImageVerificationConfigController struct{}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ImageVerificationConfigController) Name() string {\n\treturn \"security.ImageVerificationConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ImageVerificationConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: configres.NamespaceName,\n\t\t\tType:      configres.MachineConfigType,\n\t\t\tID:        optional.Some(configres.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ImageVerificationConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: security.ImageVerificationRuleType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ImageVerificationConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tmachineConfig, err := safe.ReaderGetByID[*configres.MachineConfig](ctx, r, configres.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn fmt.Errorf(\"failed to get machine config: %w\", err)\n\t\t}\n\n\t\tif machineConfig != nil {\n\t\t\tif cfg := machineConfig.Config().ImageVerificationConfig(); cfg != nil {\n\t\t\t\tfor idx, rule := range cfg.Rules() {\n\t\t\t\t\tif err := safe.WriterModify(ctx, r, security.NewImageVerificationRule(fmt.Sprintf(\"%04d\", idx)),\n\t\t\t\t\t\tfunc(r *security.ImageVerificationRule) error {\n\t\t\t\t\t\t\tr.TypedSpec().ImagePattern = rule.ImagePattern()\n\t\t\t\t\t\t\tr.TypedSpec().Skip = rule.Skip()\n\t\t\t\t\t\t\tr.TypedSpec().Deny = rule.Deny()\n\n\t\t\t\t\t\t\tif kv := rule.VerifierKeyless(); kv != nil {\n\t\t\t\t\t\t\t\tr.TypedSpec().KeylessVerifier = &security.ImageKeylessVerifierSpec{\n\t\t\t\t\t\t\t\t\tIssuer:       kv.Issuer(),\n\t\t\t\t\t\t\t\t\tSubject:      kv.Subject(),\n\t\t\t\t\t\t\t\t\tSubjectRegex: kv.SubjectRegex(),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tr.TypedSpec().KeylessVerifier = nil\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif cv := rule.VerifierPublicKey(); cv != nil {\n\t\t\t\t\t\t\t\tr.TypedSpec().PublicKeyVerifier = &security.ImagePublicKeyVerifierSpec{\n\t\t\t\t\t\t\t\t\tCertificate: cv.Certificate(),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tr.TypedSpec().PublicKeyVerifier = nil\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t},\n\t\t\t\t\t); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"failed to create/update image verification rule: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*security.ImageVerificationRule](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/security/image_verification_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecurityctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tsecuritycfg \"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\ntype ImageVerificationConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *ImageVerificationConfigSuite) TestReconcileNoConfig() {\n\tctest.AssertNoResource[*security.ImageVerificationRule](suite, \"0000\")\n}\n\nfunc (suite *ImageVerificationConfigSuite) TestReconcileNoVerificationConfig() {\n\tcfg := config.NewMachineConfig(container.NewV1Alpha1(&v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"controlplane\",\n\t\t},\n\t}))\n\tsuite.Create(cfg)\n\n\tctest.AssertNoResource[*security.ImageVerificationRule](suite, \"0000\")\n}\n\nfunc (suite *ImageVerificationConfigSuite) TestReconcileWithRules() {\n\tverificationCfg := securitycfg.NewImageVerificationConfigV1Alpha1()\n\tverificationCfg.ConfigRules = []securitycfg.ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"ghcr.io/myorg/*\",\n\t\t\tRuleKeylessVerifier: &securitycfg.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\tKeylessSubjectRegex: \"https://github.com/myorg/.*\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"quay.io/*\",\n\t\t\tRulePublicKeyVerifier: &securitycfg.ImagePublicKeyVerifierV1Alpha1{\n\t\t\t\tConfigCertificate: \"TEST\",\n\t\t\t},\n\t\t},\n\t}\n\n\tcont, err := container.New(verificationCfg)\n\tsuite.Require().NoError(err)\n\n\tcfg := config.NewMachineConfig(cont)\n\tsuite.Create(cfg)\n\n\tctest.AssertResource(suite, \"0000\", func(rule *security.ImageVerificationRule, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"docker.io/*\", rule.TypedSpec().ImagePattern)\n\t\tasrt.True(rule.TypedSpec().Skip)\n\t\tasrt.False(rule.TypedSpec().Deny)\n\t\tasrt.Nil(rule.TypedSpec().KeylessVerifier)\n\t\tasrt.Nil(rule.TypedSpec().PublicKeyVerifier)\n\t})\n\n\tctest.AssertResource(suite, \"0001\", func(rule *security.ImageVerificationRule, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"ghcr.io/myorg/*\", rule.TypedSpec().ImagePattern)\n\t\tasrt.False(rule.TypedSpec().Skip)\n\t\tasrt.False(rule.TypedSpec().Deny)\n\t\tasrt.NotNil(rule.TypedSpec().KeylessVerifier)\n\t\tasrt.Equal(\"https://token.actions.githubusercontent.com\", rule.TypedSpec().KeylessVerifier.Issuer)\n\t\tasrt.Equal(\"https://github.com/myorg/.*\", rule.TypedSpec().KeylessVerifier.SubjectRegex)\n\t\tasrt.Nil(rule.TypedSpec().PublicKeyVerifier)\n\t})\n\n\tctest.AssertResource(suite, \"0002\", func(rule *security.ImageVerificationRule, asrt *assert.Assertions) {\n\t\tasrt.Equal(\"quay.io/*\", rule.TypedSpec().ImagePattern)\n\t\tasrt.False(rule.TypedSpec().Skip)\n\t\tasrt.False(rule.TypedSpec().Deny)\n\t\tasrt.Nil(rule.TypedSpec().KeylessVerifier)\n\t\tasrt.NotNil(rule.TypedSpec().PublicKeyVerifier)\n\t\tasrt.Equal(\"TEST\", rule.TypedSpec().PublicKeyVerifier.Certificate)\n\t})\n\n\tsuite.Destroy(cfg)\n\n\tctest.AssertNoResource[*security.ImageVerificationRule](suite, \"0000\")\n\tctest.AssertNoResource[*security.ImageVerificationRule](suite, \"0001\")\n\tctest.AssertNoResource[*security.ImageVerificationRule](suite, \"0002\")\n}\n\nfunc TestImageVerificationConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ImageVerificationConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&securityctrl.ImageVerificationConfigController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/security/tuf_trusted_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage security\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/sigstore/sigstore-go/pkg/tuf\"\n\t\"github.com/theupdateframework/go-tuf/v2/metadata/fetcher\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\n// TUFTrustedRootController fetches root TUF trusted roots.\ntype TUFTrustedRootController struct {\n\tRefreshInterval time.Duration\n\n\tlastRefresh time.Time\n}\n\n// DefaultTUFRefreshInterval is the default interval for refreshing TUF trusted roots.\nconst DefaultTUFRefreshInterval = 24 * time.Hour\n\n// Name implements controller.Controller interface.\nfunc (ctrl *TUFTrustedRootController) Name() string {\n\treturn \"security.TUFTrustedRootController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *TUFTrustedRootController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: security.NamespaceName,\n\t\t\tType:      security.ImageVerificationRuleType,\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *TUFTrustedRootController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: security.TUFTrustedRootType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *TUFTrustedRootController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.RefreshInterval == 0 {\n\t\tctrl.RefreshInterval = DefaultTUFRefreshInterval\n\t}\n\n\tticker := time.NewTicker(ctrl.RefreshInterval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\t// first, determine if we need to fetch TUF at all\n\t\trules, err := safe.ReaderListAll[*security.ImageVerificationRule](ctx, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to list image verification rules: %w\", err)\n\t\t}\n\n\t\tneedsTUF := false\n\n\t\tfor rule := range rules.All() {\n\t\t\tif rule.TypedSpec().KeylessVerifier != nil {\n\t\t\t\tneedsTUF = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// suppress TUF refresh if not needed\n\t\tif needsTUF && time.Since(ctrl.lastRefresh) < ctrl.RefreshInterval {\n\t\t\tcontinue\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif needsTUF {\n\t\t\ttufData, err := ctrl.getTrustedRootTarget(security.TrustedRootID)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to get TUF trusted root: %w\", err)\n\t\t\t}\n\n\t\t\tctrl.lastRefresh = time.Now()\n\n\t\t\tif err := safe.WriterModify(ctx, r,\n\t\t\t\tsecurity.NewTUFTrustedRoot(security.TrustedRootID),\n\t\t\t\tfunc(root *security.TUFTrustedRoot) error {\n\t\t\t\t\troot.TypedSpec().JSONData = string(tufData)\n\t\t\t\t\troot.TypedSpec().LastRefreshTime = ctrl.lastRefresh\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create/update TUF trusted root: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Info(\"refreshed TUF trusted root\")\n\t\t} else {\n\t\t\t// we are going to remove TUF, so reset last refresh time\n\t\t\tctrl.lastRefresh = time.Time{}\n\t\t}\n\n\t\tif err := safe.CleanupOutputs[*security.TUFTrustedRoot](ctx, r); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup outputs: %w\", err)\n\t\t}\n\t}\n}\n\nfunc (ctrl *TUFTrustedRootController) getTrustedRootTarget(id string) ([]byte, error) {\n\ttransport := httpdefaults.PatchTransport(cleanhttp.DefaultTransport())\n\thttpClient := &http.Client{\n\t\tTransport: transport,\n\t}\n\n\tfetcher := fetcher.NewDefaultFetcher()\n\tfetcher.SetHTTPClient(httpClient)\n\tfetcher.SetHTTPUserAgent(httpdefaults.UserAgent())\n\n\topts := tuf.Options{\n\t\tRoot:              tuf.DefaultRoot(),\n\t\tRepositoryBaseURL: tuf.DefaultMirror,\n\t\tDisableLocalCache: true,\n\t\tFetcher:           fetcher,\n\t}\n\n\tclient, err := tuf.New(&opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create TUF client: %w\", err)\n\t}\n\n\treturn client.GetTarget(id)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/security/tuf_trusted_root_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsecurityctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\ntype TUFTrustedRootSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc (suite *TUFTrustedRootSuite) TestReconcileNoConfig() {\n\tctest.AssertNoResource[*security.TUFTrustedRoot](suite, security.TrustedRootID)\n}\n\nfunc (suite *TUFTrustedRootSuite) TestReconcileNoKeylessRules() {\n\trule := security.NewImageVerificationRule(\"0000\")\n\trule.TypedSpec().ImagePattern = \"ghcr.io/myorg/*\"\n\tsuite.Create(rule)\n\n\tctest.AssertNoResource[*security.TUFTrustedRoot](suite, security.TrustedRootID)\n}\n\nfunc (suite *TUFTrustedRootSuite) TestReconcileWithRules() {\n\trule := security.NewImageVerificationRule(\"0000\")\n\trule.TypedSpec().ImagePattern = \"ghcr.io/myorg/*\"\n\trule.TypedSpec().KeylessVerifier = &security.ImageKeylessVerifierSpec{\n\t\tIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\tSubjectRegex: \"https://github.com/myorg/.*\",\n\t}\n\tsuite.Create(rule)\n\n\tctest.AssertResource(suite, security.TrustedRootID, func(root *security.TUFTrustedRoot, asrt *assert.Assertions) {\n\t\tasrt.NotEmpty(root.TypedSpec().JSONData)\n\t})\n\n\tsuite.Destroy(rule)\n\n\tctest.AssertNoResource[*security.TUFTrustedRoot](suite, security.TrustedRootID)\n}\n\nfunc TestTUFTrustedRootSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &TUFTrustedRootSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tAfterSetup: func(s *ctest.DefaultSuite) {\n\t\t\t\ts.Require().NoError(s.Runtime().RegisterController(&securityctrl.TUFTrustedRootController{}))\n\t\t\t},\n\t\t},\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/endpoint\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\n// ConfigController interacts with SideroLink API and brings up the SideroLink Wireguard interface.\ntype ConfigController struct {\n\tCmdline      *procfs.Cmdline\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ConfigController) Name() string {\n\treturn \"siderolink.ConfigController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ConfigController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      config.MachineConfigType,\n\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ConfigController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: siderolink.ConfigType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ConfigController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn err\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif ep := ctrl.apiEndpoint(cfg); ep != \"\" {\n\t\t\tvar parsed endpoint.Endpoint\n\n\t\t\tparsed, err = endpoint.Parse(ep)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse siderolink API endpoint: %w\", err)\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID), func(c *siderolink.Config) error {\n\t\t\t\tc.TypedSpec().APIEndpoint = ep\n\t\t\t\tc.TypedSpec().Host = parsed.Host\n\t\t\t\tc.TypedSpec().JoinToken = parsed.GetParam(\"jointoken\")\n\t\t\t\tc.TypedSpec().Insecure = parsed.Insecure\n\t\t\t\tc.TypedSpec().Tunnel = parsed.GetParam(\"grpc_tunnel\") == \"true\" || parsed.GetParam(\"grpc_tunnel\") == \"y\"\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to update config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*siderolink.Config](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\nfunc (ctrl *ConfigController) apiEndpoint(machineConfig *config.MachineConfig) string {\n\tif machineConfig != nil && machineConfig.Config().SideroLink() != nil && machineConfig.Config().SideroLink().APIUrl() != nil {\n\t\treturn machineConfig.Config().SideroLink().APIUrl().String()\n\t}\n\n\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\treturn \"\"\n\t}\n\n\tif ctrl.Cmdline == nil || ctrl.Cmdline.Get(constants.KernelParamSideroLink).First() == nil {\n\t\treturn \"\"\n\t}\n\n\treturn *ctrl.Cmdline.Get(constants.KernelParamSideroLink).First()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsiderolinkctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\tsiderolinkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\ntype ConfigSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &ConfigSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tAfterSetup: func(suite *ctest.DefaultSuite) {\n\t\t\t\tsuite.Require().NoError(suite.Runtime().RegisterController(&siderolinkctrl.ConfigController{}))\n\t\t\t},\n\t\t\tTimeout: time.Second,\n\t\t},\n\t})\n}\n\nfunc (suite *ConfigSuite) TestConfig() {\n\trtestutils.AssertNoResource[*siderolink.Config](suite.Ctx(), suite.T(), suite.State(), siderolink.ConfigID)\n\n\tsiderolinkConfig := &siderolinkcfg.ConfigV1Alpha1{\n\t\tAPIUrlConfig: meta.URL{\n\t\t\tURL: must.Value(url.Parse(\"https://api.sidero.dev:334\"))(suite.T()),\n\t\t},\n\t}\n\n\tcfg, err := container.New(siderolinkConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{siderolink.ConfigID},\n\t\tfunc(c *siderolink.Config, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"https://api.sidero.dev:334\", c.TypedSpec().APIEndpoint)\n\t\t\tassert.Equal(\"api.sidero.dev:334\", c.TypedSpec().Host)\n\t\t})\n}\n\nfunc (suite *ConfigSuite) TestConfigTunnel() {\n\trtestutils.AssertNoResource[*siderolink.Config](suite.Ctx(), suite.T(), suite.State(), siderolink.ConfigID)\n\n\tsiderolinkConfig := &siderolinkcfg.ConfigV1Alpha1{\n\t\tAPIUrlConfig: meta.URL{\n\t\t\tURL: must.Value(url.Parse(\"https://api.sidero.dev?grpc_tunnel=true\"))(suite.T()),\n\t\t},\n\t}\n\n\tcfg, err := container.New(siderolinkConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), config.NewMachineConfig(cfg)))\n\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{siderolink.ConfigID},\n\t\tfunc(c *siderolink.Config, assert *assert.Assertions) {\n\t\t\tassert.Equal(\"https://api.sidero.dev?grpc_tunnel=true\", c.TypedSpec().APIEndpoint)\n\t\t\tassert.True(c.TypedSpec().Tunnel)\n\t\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/manager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\tpb \"github.com/siderolabs/siderolink/api/siderolink\"\n\t\"github.com/siderolabs/siderolink/pkg/wireguard\"\n\t\"go.uber.org/zap\"\n\t\"golang.zx2c4.com/wireguard/wgctrl\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\tnetworkutils \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network/utils\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// ManagerController interacts with SideroLink API and brings up the SideroLink Wireguard interface.\ntype ManagerController struct {\n\tnodeKey wgtypes.Key\n\tpd      provisionData\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ManagerController) Name() string {\n\treturn \"siderolink.ManagerController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ManagerController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ManagerController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: network.AddressSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: network.LinkSpecType,\n\t\t\tKind: controller.OutputShared,\n\t\t},\n\t\t{\n\t\t\tType: siderolink.TunnelType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *ManagerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif fipsmode.Strict() {\n\t\tlogger.Warn(\"SideroLink is not supported in strict FIPS mode\")\n\n\t\treturn nil\n\t}\n\n\t// initially, wait for the network address status to be ready\n\tif err := networkutils.WaitForNetworkReady(ctx, r,\n\t\tfunc(status *network.StatusSpec) bool {\n\t\t\treturn status.AddressReady\n\t\t},\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: config.NamespaceName,\n\t\t\t\tType:      siderolink.ConfigType,\n\t\t\t\tID:        optional.Some(siderolink.ConfigID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t\t{\n\t\t\t\tNamespace: hardware.NamespaceName,\n\t\t\t\tType:      hardware.SystemInformationType,\n\t\t\t\tID:        optional.Some(hardware.SystemInformationID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t\t{\n\t\t\t\tNamespace: runtime.NamespaceName,\n\t\t\t\tType:      runtime.UniqueMachineTokenType,\n\t\t\t\tID:        optional.Some(runtime.UniqueMachineTokenID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for network: %w\", err)\n\t}\n\n\t// normal reconcile loop\n\twgClient, wgClientErr := wgctrl.New()\n\tif wgClientErr != nil {\n\t\treturn wgClientErr\n\t}\n\n\tdefer func() {\n\t\tif closeErr := wgClient.Close(); closeErr != nil {\n\t\t\tlogger.Error(\"failed to close wg client\", zap.Error(closeErr))\n\t\t}\n\t}()\n\n\tvar zeroKey wgtypes.Key\n\n\tif bytes.Equal(ctrl.nodeKey[:], zeroKey[:]) {\n\t\tvar err error\n\n\t\tctrl.nodeKey, err = wgtypes.GeneratePrivateKey()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating Wireguard key: %w\", err)\n\t\t}\n\t}\n\n\tticker := time.NewTicker(30 * time.Second)\n\tdefer ticker.Stop()\n\n\t// default name, actual name is set based on the provision API response:\n\t// whether we use the Wireguard tunnel over gRPC or not\n\tlinkName := constants.SideroLinkName\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-ticker.C:\n\t\t\treconnect, err := peerDown(wgClient, linkName)\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\t\t\t// no Wireguard device, so no need to reconnect\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif !reconnect {\n\t\t\t\t// nothing to do\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase <-r.EventCh():\n\t\t\t// if the SideroLink configuration changed (either config itself, or machine UUID or Unique Token),\n\t\t\t// clear any previous provision data we had so that Talos doesn't cycle through endpoints from\n\t\t\t// stale provisioning data until it reaches out to SideroLink Provision API again\n\t\t\tctrl.pd = provisionData{}\n\t\t}\n\n\t\tif ctrl.pd.IsEmpty() {\n\t\t\tprovision, err := ctrl.provision(ctx, r, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error provisioning: %w\", err)\n\t\t\t}\n\n\t\t\tif !provision.IsPresent() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tctrl.pd = provision.ValueOrZero()\n\t\t}\n\n\t\tuseWgTunnel := ctrl.pd.grpcPeerAddrPort != \"\"\n\n\t\tif useWgTunnel {\n\t\t\tlinkName = constants.SideroLinkTunnelName\n\t\t} else {\n\t\t\tlinkName = constants.SideroLinkName\n\t\t}\n\n\t\tserverAddress, err := netip.ParseAddr(ctrl.pd.ServerAddress)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing server address: %w\", err)\n\t\t}\n\n\t\tnodeAddress, err := netip.ParsePrefix(ctrl.pd.NodeAddressPrefix)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing node address: %w\", err)\n\t\t}\n\n\t\tlinkSpec := network.NewLinkSpec(network.ConfigNamespaceName, network.LayeredID(network.ConfigOperator, network.LinkID(linkName)))\n\t\taddressSpec := network.NewAddressSpec(network.ConfigNamespaceName, network.LayeredID(network.ConfigOperator, network.AddressID(linkName, nodeAddress)))\n\n\t\t// Rotate through the endpoints.\n\t\tep, ok := ctrl.pd.TakeEndpoint()\n\t\tif !ok {\n\t\t\treturn errors.New(\"host returned no endpoints\")\n\t\t}\n\n\t\t// in case the endpoint is a hostname, resolve it to an IP address each time we reconnect\n\t\t// if the IP behind the DNS name changes, it will trigger a change in the LinkSpec, and\n\t\t// it will update the Wireguard peer endpoint accordingly\n\t\tresolvedEndpoint, err := net.ResolveUDPAddr(\"udp\", ep)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error resolving endpoint %q: %w\", ep, err)\n\t\t}\n\n\t\tlogger.Info(\n\t\t\t\"configuring siderolink connection\",\n\t\t\tzap.String(\"peer_endpoint\", resolvedEndpoint.String()),\n\t\t\tzap.String(\"next_peer_endpoint\", ctrl.pd.PeekNextEndpoint()),\n\t\t)\n\n\t\tif err = safe.WriterModify(ctx, r, linkSpec,\n\t\t\tfunc(res *network.LinkSpec) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tspec.ConfigLayer = network.ConfigOperator\n\t\t\t\tspec.Name = linkName\n\t\t\t\tspec.Type = nethelpers.LinkNone\n\t\t\t\tspec.Kind = \"wireguard\"\n\n\t\t\t\t// if using wg-tunnel, the actual link will be created in the userspace\n\t\t\t\t// as a tunnel device\n\t\t\t\t// if using native, we create a native kernel wireguard interface\n\t\t\t\tif useWgTunnel {\n\t\t\t\t\tspec.Logical = false // the controller does not create the link\n\t\t\t\t} else {\n\t\t\t\t\tspec.Logical = true // allow controller to create the link\n\t\t\t\t}\n\n\t\t\t\tspec.Up = true\n\t\t\t\tspec.MTU = wireguard.LinkMTU\n\n\t\t\t\tspec.Wireguard = network.WireguardSpec{\n\t\t\t\t\tPrivateKey: ctrl.nodeKey.String(),\n\t\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tPublicKey: ctrl.pd.ServerPublicKey,\n\t\t\t\t\t\t\tEndpoint:  resolvedEndpoint.String(),\n\t\t\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\t\t\tnetip.PrefixFrom(serverAddress, serverAddress.BitLen()),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// make sure Talos pings SideroLink endpoint, so that tunnel is established:\n\t\t\t\t\t\t\t// SideroLink doesn't know Talos endpoint.\n\t\t\t\t\t\t\tPersistentKeepaliveInterval: constants.SideroLinkDefaultPeerKeepalive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tspec.Wireguard.Sort()\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating siderolink spec: %w\", err)\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, addressSpec,\n\t\t\tfunc(res *network.AddressSpec) error {\n\t\t\t\tspec := res.TypedSpec()\n\n\t\t\t\tspec.ConfigLayer = network.ConfigOperator\n\t\t\t\tspec.Address = nodeAddress\n\t\t\t\tspec.Family = nethelpers.FamilyInet6\n\t\t\t\tspec.Flags = nethelpers.AddressFlags(nethelpers.AddressPermanent)\n\t\t\t\tspec.LinkName = linkName\n\t\t\t\tspec.Scope = nethelpers.ScopeGlobal\n\n\t\t\t\treturn nil\n\t\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating address spec: %w\", err)\n\t\t}\n\n\t\tif ctrl.pd.grpcPeerAddrPort != \"\" {\n\t\t\tvar ourAddr netip.AddrPort\n\n\t\t\tourAddr, err = netip.ParseAddrPort(ctrl.pd.grpcPeerAddrPort)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err = safe.WriterModify(ctx, r, siderolink.NewTunnel(),\n\t\t\t\tfunc(tunnel *siderolink.Tunnel) error {\n\t\t\t\t\ttunnel.TypedSpec().APIEndpoint = ctrl.pd.apiEndpont\n\t\t\t\t\ttunnel.TypedSpec().LinkName = linkName\n\t\t\t\t\ttunnel.TypedSpec().MTU = wireguard.LinkMTU\n\t\t\t\t\ttunnel.TypedSpec().NodeAddress = ourAddr\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating tunnel spec: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tif err = r.Destroy(ctx, siderolink.NewTunnel().Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error destroying tunnel spec: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tkeepLinkSpecSet := map[resource.ID]struct{}{\n\t\t\tlinkSpec.Metadata().ID(): {},\n\t\t}\n\n\t\tkeepAddressSpecSet := map[resource.ID]struct{}{\n\t\t\taddressSpec.Metadata().ID(): {},\n\t\t}\n\n\t\tif err := ctrl.cleanup(ctx, r, keepLinkSpecSet, keepAddressSpecSet, logger); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Info(\n\t\t\t\"siderolink connection configured\",\n\t\t\tzap.String(\"endpoint\", ctrl.pd.apiEndpont),\n\t\t\tzap.String(\"node_uuid\", ctrl.pd.nodeUUID),\n\t\t\tzap.String(\"node_address\", nodeAddress.String()),\n\t\t)\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *ManagerController) provision(ctx context.Context, r controller.Runtime, logger *zap.Logger) (optional.Optional[provisionData], error) {\n\tcfg, err := safe.ReaderGetByID[*siderolink.Config](ctx, r, siderolink.ConfigID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\tif cleanupErr := ctrl.cleanup(ctx, r, nil, nil, logger); cleanupErr != nil {\n\t\t\t\treturn optional.None[provisionData](), fmt.Errorf(\"failed to do cleanup: %w\", cleanupErr)\n\t\t\t}\n\n\t\t\t// no config\n\t\t\treturn optional.None[provisionData](), nil\n\t\t}\n\n\t\treturn optional.None[provisionData](), fmt.Errorf(\"failed to get siderolink config: %w\", err)\n\t}\n\n\tsysInfo, err := safe.ReaderGetByID[*hardware.SystemInformation](ctx, r, hardware.SystemInformationID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\t// no system information\n\t\t\treturn optional.None[provisionData](), nil\n\t\t}\n\n\t\treturn optional.None[provisionData](), fmt.Errorf(\"failed to get system information: %w\", err)\n\t}\n\n\tnodeUUID := sysInfo.TypedSpec().UUID\n\n\tprovision := func() (*pb.ProvisionResponse, error) {\n\t\t// set a timeout for the provisioning call\n\t\tctx, cancel := context.WithTimeout(ctx, 30*time.Second)\n\t\tdefer cancel()\n\n\t\tconn, connErr := grpc.NewClient(\n\t\t\tcfg.TypedSpec().Host,\n\t\t\twithTransportCredentials(cfg.TypedSpec().Insecure),\n\t\t\tgrpc.WithSharedWriteBuffer(true),\n\t\t\tgrpc.WithContextDialer(dialer.DynamicProxyDialerWithTLSConfig(httpdefaults.RootCAsTLSConfig)),\n\t\t)\n\t\tif connErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"error dialing SideroLink endpoint %q: %w\", cfg.TypedSpec().Host, connErr)\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif closeErr := conn.Close(); closeErr != nil {\n\t\t\t\tlogger.Error(\"failed to close SideroLink provisioning GRPC connection\", zap.Error(closeErr))\n\t\t\t}\n\t\t}()\n\n\t\tuniqTokenRes, rdrErr := safe.ReaderGetByID[*runtime.UniqueMachineToken](ctx, r, runtime.UniqueMachineTokenID)\n\t\tif rdrErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get unique token: %w\", rdrErr)\n\t\t}\n\n\t\tvar wgOverGRPC *bool\n\n\t\tif cfg.TypedSpec().Tunnel {\n\t\t\twgOverGRPC = new(true)\n\t\t}\n\n\t\tsideroLinkClient := pb.NewProvisionServiceClient(conn)\n\t\trequest := &pb.ProvisionRequest{\n\t\t\tNodeUuid:          nodeUUID,\n\t\t\tNodePublicKey:     ctrl.nodeKey.PublicKey().String(),\n\t\t\tNodeUniqueToken:   new(uniqTokenRes.TypedSpec().Token),\n\t\t\tTalosVersion:      new(version.Tag),\n\t\t\tWireguardOverGrpc: wgOverGRPC,\n\t\t}\n\n\t\ttoken := cfg.TypedSpec().JoinToken\n\n\t\tif token != \"\" {\n\t\t\trequest.JoinToken = new(token)\n\t\t}\n\n\t\treturn sideroLinkClient.Provision(ctx, request)\n\t}\n\n\tresp, err := provision()\n\tif err != nil {\n\t\treturn optional.None[provisionData](), err\n\t}\n\n\treturn optional.Some(provisionData{\n\t\tnodeUUID:          nodeUUID,\n\t\tapiEndpont:        cfg.TypedSpec().APIEndpoint,\n\t\tServerAddress:     resp.ServerAddress,\n\t\tServerPublicKey:   resp.ServerPublicKey,\n\t\tNodeAddressPrefix: resp.NodeAddressPrefix,\n\t\tendpoints:         resp.GetEndpoints(),\n\t\tgrpcPeerAddrPort:  resp.GrpcPeerAddrPort,\n\t}), nil\n}\n\ntype provisionData struct {\n\tnodeUUID          string\n\tapiEndpont        string\n\tServerAddress     string\n\tServerPublicKey   string\n\tNodeAddressPrefix string\n\tendpoints         []string\n\tgrpcPeerAddrPort  string\n}\n\nfunc (d *provisionData) IsEmpty() bool {\n\treturn d == nil || len(d.endpoints) == 0\n}\n\nfunc (d *provisionData) TakeEndpoint() (string, bool) {\n\tif d.IsEmpty() {\n\t\treturn \"\", false\n\t}\n\n\tep := d.endpoints[0]\n\td.endpoints = d.endpoints[1:]\n\n\treturn ep, true\n}\n\nfunc (d *provisionData) PeekNextEndpoint() string {\n\tif d.IsEmpty() {\n\t\treturn \"\"\n\t}\n\n\treturn d.endpoints[0]\n}\n\nfunc (ctrl *ManagerController) cleanup(\n\tctx context.Context,\n\tr controller.Runtime,\n\tkeepLinkSpecIDSet, keepAddressSpecIDSet map[resource.ID]struct{},\n\tlogger *zap.Logger,\n) error {\n\tif err := ctrl.cleanupLinkSpecs(ctx, r, keepLinkSpecIDSet, logger); err != nil {\n\t\treturn err\n\t}\n\n\treturn ctrl.cleanupAddressSpecs(ctx, r, keepAddressSpecIDSet, logger)\n}\n\n//nolint:dupl\nfunc (ctrl *ManagerController) cleanupLinkSpecs(ctx context.Context, r controller.Runtime, keepSet map[resource.ID]struct{}, logger *zap.Logger) error {\n\tlist, err := safe.ReaderList[*network.LinkSpec](ctx, r, network.NewLinkSpec(network.ConfigNamespaceName, \"\").Metadata())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor link := range list.All() {\n\t\tif link.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := keepSet[link.Metadata().ID()]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif destroyErr := r.Destroy(ctx, link.Metadata()); destroyErr != nil && !state.IsNotFoundError(destroyErr) {\n\t\t\treturn destroyErr\n\t\t}\n\n\t\tlogger.Info(\"destroyed link spec\", zap.String(\"link_id\", link.Metadata().ID()))\n\t}\n\n\treturn nil\n}\n\n//nolint:dupl\nfunc (ctrl *ManagerController) cleanupAddressSpecs(ctx context.Context, r controller.Runtime, keepSet map[resource.ID]struct{}, logger *zap.Logger) error {\n\tlist, err := safe.ReaderList[*network.AddressSpec](ctx, r, network.NewAddressSpec(network.ConfigNamespaceName, \"\").Metadata())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor address := range list.All() {\n\t\tif address.Metadata().Owner() != ctrl.Name() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := keepSet[address.Metadata().ID()]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif destroyErr := r.Destroy(ctx, address.Metadata()); destroyErr != nil && !state.IsNotFoundError(destroyErr) {\n\t\t\treturn destroyErr\n\t\t}\n\n\t\tlogger.Info(\"destroyed address spec\", zap.String(\"address_id\", address.Metadata().ID()))\n\t}\n\n\treturn nil\n}\n\nfunc withTransportCredentials(insec bool) grpc.DialOption {\n\tvar transportCredentials credentials.TransportCredentials\n\n\tif insec {\n\t\ttransportCredentials = insecure.NewCredentials()\n\t} else {\n\t\ttransportCredentials = credentials.NewTLS(&tls.Config{\n\t\t\tRootCAs: httpdefaults.RootCAs(),\n\t\t})\n\t}\n\n\treturn grpc.WithTransportCredentials(transportCredentials)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/manager_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\tpb \"github.com/siderolabs/siderolink/api/siderolink\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsiderolinkctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\nfunc TestManagerSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif fipsmode.Strict() {\n\t\tt.Skip(\"skipping test in strict FIPS mode\")\n\t}\n\n\tsuite.Run(t, &ManagerSuite{})\n}\n\ntype ManagerSuite struct {\n\tctest.DefaultSuite\n\n\ts *grpc.Server\n}\n\ntype mockServer struct {\n\tpb.UnimplementedProvisionServiceServer\n\n\tsuite     *ManagerSuite\n\tendpoints []string\n}\n\nconst (\n\tmockNodeUUID          = \"71233efd-7a07-43f8-b6ba-da90fae0e88b\"\n\tmockUniqueToken       = \"random-token\"\n\tmockServerEndpoint1   = \"127.0.0.11:51820\"\n\tmockServerEndpoint2   = \"localhost:51821\"\n\tmockServerAddress     = \"fdae:41e4:649b:9303:b6db:d99c:215e:dfc4\"\n\tmockServerPublicKey   = \"2aq/V91QyrHAoH24RK0bldukgo2rWk+wqE5Eg6TArCM=\"\n\tmockNodeAddressPrefix = \"fdae:41e4:649b:9303:2a07:9c7:5b08:aef7/64\"\n)\n\nfunc (srv mockServer) Provision(_ context.Context, req *pb.ProvisionRequest) (*pb.ProvisionResponse, error) {\n\tsrv.suite.Assert().Equal(mockNodeUUID, req.GetNodeUuid())\n\tsrv.suite.Assert().Empty(req.GetJoinToken())\n\tsrv.suite.Assert().False(req.GetWireguardOverGrpc())\n\tsrv.suite.Assert().Equal(mockUniqueToken, req.GetNodeUniqueToken())\n\n\treturn &pb.ProvisionResponse{\n\t\tServerEndpoint:    pb.MakeEndpoints(srv.endpoints...),\n\t\tServerAddress:     mockServerAddress,\n\t\tServerPublicKey:   mockServerPublicKey,\n\t\tNodeAddressPrefix: mockNodeAddressPrefix,\n\t}, nil\n}\n\nfunc (suite *ManagerSuite) initialSetup(endpoints ...string) {\n\tlis, err := (&net.ListenConfig{}).Listen(suite.Ctx(), \"tcp\", \"localhost:0\")\n\tsuite.Require().NoError(err)\n\n\tsuite.s = grpc.NewServer()\n\tpb.RegisterProvisionServiceServer(suite.s, mockServer{\n\t\tsuite:     suite,\n\t\tendpoints: endpoints,\n\t})\n\n\tsuite.T().Cleanup(suite.s.Stop)\n\n\tgo func() {\n\t\tsuite.Require().NoError(suite.s.Serve(lis))\n\t}()\n\n\tcmdline := procfs.NewCmdline(fmt.Sprintf(\"%s=%s\", constants.KernelParamSideroLink, lis.Addr().String()))\n\tconfigController := siderolinkctrl.ConfigController{Cmdline: cmdline}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&siderolinkctrl.ManagerController{}))\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&configController))\n\n\tnetworkStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetworkStatus.TypedSpec().AddressReady = true\n\tsuite.Create(networkStatus)\n\n\tsystemInformation := hardware.NewSystemInformation(hardware.SystemInformationID)\n\tsystemInformation.TypedSpec().UUID = mockNodeUUID\n\tsuite.Create(systemInformation)\n\n\tuniqToken := runtime.NewUniqueMachineToken()\n\tuniqToken.TypedSpec().Token = mockUniqueToken\n\tsuite.Create(uniqToken)\n}\n\nfunc (suite *ManagerSuite) TestReconcile() {\n\tsuite.initialSetup(mockServerEndpoint1)\n\n\tnodeAddress := netip.MustParsePrefix(mockNodeAddressPrefix)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.AddressID(constants.SideroLinkName, nodeAddress)),\n\t\tfunc(r *network.AddressSpec, asrt *assert.Assertions) {\n\t\t\taddress := r.TypedSpec()\n\n\t\t\tasrt.Equal(nodeAddress, address.Address)\n\t\t\tasrt.Equal(network.ConfigOperator, address.ConfigLayer)\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, address.Family)\n\t\t\tasrt.Equal(constants.SideroLinkName, address.LinkName)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),\n\t\tfunc(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tlink := r.TypedSpec()\n\n\t\t\tasrt.Equal(\"wireguard\", link.Kind)\n\t\t\tasrt.Equal(network.ConfigOperator, link.ConfigLayer)\n\t\t\tasrt.NotEmpty(link.Wireguard.PrivateKey)\n\t\t\tasrt.Len(link.Wireguard.Peers, 1)\n\t\t\tasrt.Equal(mockServerEndpoint1, link.Wireguard.Peers[0].Endpoint)\n\t\t\tasrt.Equal(mockServerPublicKey, link.Wireguard.Peers[0].PublicKey)\n\t\t\tasrt.Equal(\n\t\t\t\t[]netip.Prefix{\n\t\t\t\t\tnetip.PrefixFrom(\n\t\t\t\t\t\tnetip.MustParseAddr(mockServerAddress),\n\t\t\t\t\t\t128,\n\t\t\t\t\t),\n\t\t\t\t}, link.Wireguard.Peers[0].AllowedIPs,\n\t\t\t)\n\t\t\tasrt.Equal(\n\t\t\t\tconstants.SideroLinkDefaultPeerKeepalive,\n\t\t\t\tlink.Wireguard.Peers[0].PersistentKeepaliveInterval,\n\t\t\t)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\t// remove config\n\tconfigPtr := siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID).Metadata()\n\tdestroyErr := suite.State().Destroy(suite.Ctx(), configPtr,\n\t\tstate.WithDestroyOwner(new(siderolinkctrl.ConfigController{}).Name()))\n\tsuite.Require().NoError(destroyErr)\n\n\tctest.AssertNoResource[*network.LinkSpec](suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n\n\tctest.AssertNoResource[*network.AddressSpec](suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.AddressID(constants.SideroLinkName, nodeAddress)),\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *ManagerSuite) TestMultipleEndpoints() {\n\tsuite.initialSetup(mockServerEndpoint1, mockServerEndpoint2)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),\n\t\tfunc(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tlink := r.TypedSpec()\n\n\t\t\tasrt.Len(link.Wireguard.Peers, 1)\n\t\t\t// Talos should pick the first endpoint from the list.\n\t\t\tasrt.Equal(mockServerEndpoint1, link.Wireguard.Peers[0].Endpoint)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n\nfunc (suite *ManagerSuite) TestResolveEndpoints() {\n\tsuite.initialSetup(mockServerEndpoint2)\n\n\tctest.AssertResource(suite,\n\t\tnetwork.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),\n\t\tfunc(r *network.LinkSpec, asrt *assert.Assertions) {\n\t\t\tlink := r.TypedSpec()\n\n\t\t\tasrt.Len(link.Wireguard.Peers, 1)\n\t\t\t// Talos should resolve the hostname to an IP address.\n\t\t\tasrt.Equal(\"127.0.0.1:51821\", link.Wireguard.Peers[0].Endpoint)\n\t\t},\n\t\trtestutils.WithNamespace(network.ConfigNamespaceName),\n\t)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/siderolink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package siderolink provides controllers which manage file resources.\npackage siderolink\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/siderolink/pkg/wireguard\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n)\n\n// WireguardClient allows mocking Wireguard client.\ntype WireguardClient interface {\n\tDevice(string) (*wgtypes.Device, error)\n\tClose() error\n}\n\nfunc peerDown(wgClient WireguardClient, linkName string) (bool, error) {\n\twgDevice, err := wgClient.Device(linkName)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"error reading Wireguard device: %w\", err)\n\t}\n\n\tif len(wgDevice.Peers) != 1 {\n\t\treturn false, fmt.Errorf(\"unexpected number of Wireguard peers: %d\", len(wgDevice.Peers))\n\t}\n\n\tpeer := wgDevice.Peers[0]\n\tsince := time.Since(peer.LastHandshakeTime)\n\n\treturn since >= wireguard.PeerDownInterval, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\t\"golang.zx2c4.com/wireguard/wgctrl\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\n// DefaultStatusUpdateInterval is the default interval between status updates.\nconst DefaultStatusUpdateInterval = 30 * time.Second\n\n// StatusController reports siderolink status.\ntype StatusController struct {\n\t// WGClientFunc is a function that returns a WireguardClient.\n\t//\n\t// When nil, it defaults to an actual Wireguard client.\n\tWGClientFunc func() (WireguardClient, error)\n\n\t// Interval is the time between peer status checks.\n\t//\n\t// When zero, it defaults to DefaultStatusUpdateInterval.\n\tInterval time.Duration\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *StatusController) Name() string {\n\treturn \"siderolink.StatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *StatusController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      siderolink.ConfigType,\n\t\t\tID:        optional.Some(siderolink.ConfigID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      siderolink.TunnelType,\n\t\t\tID:        optional.Some(siderolink.TunnelID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *StatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: siderolink.StatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *StatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tinterval := ctrl.Interval\n\tif interval == 0 {\n\t\tinterval = DefaultStatusUpdateInterval\n\t}\n\n\tticker := time.NewTicker(interval)\n\tdefer ticker.Stop()\n\n\twgClientFunc := ctrl.WGClientFunc\n\tif wgClientFunc == nil {\n\t\twgClientFunc = func() (WireguardClient, error) {\n\t\t\treturn wgctrl.New()\n\t\t}\n\t}\n\n\twgClient, err := wgClientFunc()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create wireguard client: %w\", err)\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\tr.StartTrackingOutputs()\n\n\t\tif err = ctrl.reconcileStatus(ctx, r, wgClient); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = safe.CleanupOutputs[*siderolink.Status](ctx, r); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n\n//nolint:gocyclo\nfunc (ctrl *StatusController) reconcileStatus(ctx context.Context, r controller.Runtime, wgClient WireguardClient) (err error) {\n\tcfg, err := safe.ReaderGetByID[*siderolink.Config](ctx, r, siderolink.ConfigID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tif cfg.TypedSpec().APIEndpoint == \"\" {\n\t\treturn nil\n\t}\n\n\ttunnelConfig, err := safe.ReaderGetByID[*siderolink.Tunnel](ctx, r, siderolink.TunnelID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn err\n\t}\n\n\tlinkName := constants.SideroLinkName\n\tif tunnelConfig != nil {\n\t\tlinkName = constants.SideroLinkTunnelName\n\t}\n\n\thost, _, err := net.SplitHostPort(cfg.TypedSpec().Host)\n\tif err != nil {\n\t\thost = cfg.TypedSpec().Host\n\t}\n\n\tdown, err := peerDown(wgClient, linkName)\n\tif err != nil {\n\t\tif !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\tdown = true // wireguard device does not exist, we mark it as down\n\t}\n\n\tif err = safe.WriterModify(ctx, r, siderolink.NewStatus(), func(status *siderolink.Status) error {\n\t\tstatus.TypedSpec().Host = host\n\t\tstatus.TypedSpec().Connected = !down\n\t\tstatus.TypedSpec().LinkName = linkName\n\t\tstatus.TypedSpec().GRPCTunnel = tunnelConfig != nil\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to update status: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink_test\n\nimport (\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\tsiderolinkctrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\ntype StatusSuite struct {\n\tctest.DefaultSuite\n}\n\nfunc TestStatusSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, &StatusSuite{\n\t\tDefaultSuite: ctest.DefaultSuite{\n\t\t\tTimeout: 3 * time.Second,\n\t\t},\n\t})\n}\n\nfunc (suite *StatusSuite) TestStatus() {\n\twgClient := &mockWgClient{\n\t\tdevice: &wgtypes.Device{\n\t\t\tPeers: []wgtypes.Peer{\n\t\t\t\t{\n\t\t\t\t\tLastHandshakeTime: time.Now().Add(-time.Minute),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tsuite.Require().NoError(suite.Runtime().RegisterController(&siderolinkctrl.StatusController{\n\t\tWGClientFunc: func() (siderolinkctrl.WireguardClient, error) {\n\t\t\treturn wgClient, nil\n\t\t},\n\t\tInterval: 100 * time.Millisecond,\n\t}))\n\n\trtestutils.AssertNoResource[*siderolink.Status](suite.Ctx(), suite.T(), suite.State(), siderolink.StatusID)\n\n\tsiderolinkConfig := siderolink.NewConfig(config.NamespaceName, siderolink.ConfigID)\n\n\tsiderolinkConfig.TypedSpec().APIEndpoint = \"https://siderolink.example.org:1234?jointoken=supersecret&foo=bar#some=fragment\"\n\tsiderolinkConfig.TypedSpec().Host = \"siderolink.example.org:1234\"\n\n\tsuite.Require().NoError(suite.State().Create(suite.Ctx(), siderolinkConfig))\n\n\tsuite.assertStatus(\"siderolink.example.org\", true)\n\n\t// disconnect the peer\n\n\twgClient.setDevice(&wgtypes.Device{\n\t\tPeers: []wgtypes.Peer{\n\t\t\t{LastHandshakeTime: time.Now().Add(-time.Hour)},\n\t\t},\n\t})\n\n\t// no device\n\twgClient.setDevice(nil)\n\tsuite.assertStatus(\"siderolink.example.org\", false)\n\n\t// reconnect the peer\n\twgClient.setDevice(&wgtypes.Device{\n\t\tPeers: []wgtypes.Peer{\n\t\t\t{LastHandshakeTime: time.Now().Add(-5 * time.Second)},\n\t\t},\n\t})\n\n\tsuite.assertStatus(\"siderolink.example.org\", true)\n\n\t// update API endpoint\n\n\tsiderolinkConfig.TypedSpec().APIEndpoint = \"https://new.example.org?jointoken=supersecret\"\n\tsiderolinkConfig.TypedSpec().Host = \"new.example.org\"\n\n\tsuite.Require().NoError(suite.State().Update(suite.Ctx(), siderolinkConfig))\n\tsuite.assertStatus(\"new.example.org\", true)\n\n\t// no config\n\n\tsuite.Require().NoError(suite.State().Destroy(suite.Ctx(), siderolinkConfig.Metadata()))\n\trtestutils.AssertNoResource[*siderolink.Status](suite.Ctx(), suite.T(), suite.State(), siderolink.StatusID)\n}\n\nfunc (suite *StatusSuite) assertStatus(endpoint string, connected bool) {\n\trtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []resource.ID{siderolink.StatusID},\n\t\tfunc(c *siderolink.Status, assert *assert.Assertions) {\n\t\t\tassert.Equal(endpoint, c.TypedSpec().Host)\n\t\t\tassert.Equal(connected, c.TypedSpec().Connected)\n\t\t})\n}\n\ntype mockWgClient struct {\n\tmu     sync.Mutex\n\tdevice *wgtypes.Device\n}\n\nfunc (m *mockWgClient) setDevice(device *wgtypes.Device) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tm.device = device\n}\n\nfunc (m *mockWgClient) Device(string) (*wgtypes.Device, error) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tif m.device == nil {\n\t\treturn nil, os.ErrNotExist\n\t}\n\n\treturn m.device, nil\n}\n\nfunc (m *mockWgClient) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/siderolink/userspace.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/siderolink/pkg/wgtunnel\"\n\t\"github.com/siderolabs/siderolink/pkg/wgtunnel/wgbind\"\n\t\"github.com/siderolabs/siderolink/pkg/wgtunnel/wggrpc\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/ctxutil\"\n\t\"github.com/siderolabs/talos/internal/pkg/endpoint\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\n// UserspaceWireguardController imlements a controller that manages a Wireguard over GRPC tunnel in userspace.\ntype UserspaceWireguardController struct {\n\tRelayRetryTimeout time.Duration\n\tDebugDataStream   bool\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *UserspaceWireguardController) Name() string {\n\treturn \"siderolink.UserspaceWireguardController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *UserspaceWireguardController) Inputs() []controller.Input {\n\treturn []controller.Input{\n\t\t{\n\t\t\tNamespace: config.NamespaceName,\n\t\t\tType:      siderolink.TunnelType,\n\t\t\tID:        optional.Some(siderolink.TunnelID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *UserspaceWireguardController) Outputs() []controller.Output {\n\treturn []controller.Output{}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *UserspaceWireguardController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\teg, ctx := errgroup.WithContext(ctx)\n\n\tvar (\n\t\trelayRetryTimer resettableTimer\n\t\ttunnelDevice    tunnelDeviceProps\n\t\ttunnelRelay     tunnelProps\n\t)\n\n\tdefer func() {\n\t\ttunnelRelay.relay.Close()\n\t\ttunnelDevice.device.Close()\n\t}()\n\n\tconst (\n\t\t// maxPendingServerMessages is the maximum number of messages that can be pending in the queue before blocking.\n\t\tmaxPendingServerMessages = 100\n\t\t// maxPendingClientMessages is the maximum number of messages that can be pending in the ring before being overwritten.\n\t\tmaxPendingClientMessages = 100\n\t)\n\n\tqp := wgbind.NewQueuePair(maxPendingServerMessages, maxPendingClientMessages)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctxutil.Cause(ctx)\n\t\tcase <-r.EventCh():\n\t\tcase <-relayRetryTimer.C():\n\t\t\trelayRetryTimer.Clear()\n\t\t}\n\n\t\tres, err := safe.ReaderGetByID[*siderolink.Tunnel](ctx, r, siderolink.TunnelID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\ttunnelRelay.relay.Close()\n\t\t\t\ttunnelDevice.device.Close()\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to read link spec: %w\", err)\n\t\t}\n\n\t\tif tunnelDevice.device.IsClosed() {\n\t\t\ttunnelDevice.device.Close()\n\n\t\t\tdev, err := wgtunnel.NewTunnelDevice(res.TypedSpec().LinkName, res.TypedSpec().MTU, qp, ctrl.makeLogger(logger))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create tunnel device: %w\", err)\n\t\t\t}\n\n\t\t\t// Store in outer scope because modifying the same variable will lead to the data race below\n\t\t\ttunnelDevice = tunnelDeviceProps{device: dev, linkName: res.TypedSpec().LinkName, mtu: res.TypedSpec().MTU}\n\n\t\t\tlogger.Info(\"wg over grpc tunnel device created\", zap.String(\"link_name\", res.TypedSpec().LinkName))\n\n\t\t\teg.Go(func() error {\n\t\t\t\tlogger.Debug(\"tunnel device running\")\n\t\t\t\tdefer logger.Debug(\"tunnel device exited\")\n\n\t\t\t\treturn dev.Run()\n\t\t\t})\n\t\t}\n\n\t\tep, err := endpoint.Parse(res.TypedSpec().APIEndpoint)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse siderolink API endpoint: %w\", err)\n\t\t}\n\n\t\tdstHost := ep.Host\n\t\tourAddrPort := res.TypedSpec().NodeAddress\n\n\t\tif tunnelRelay.relay.IsClosed() || tunnelRelay.dstHost != dstHost || tunnelRelay.ourAddrPort != ourAddrPort {\n\t\t\t// Reset timer because we are going to start tunnel anyway\n\t\t\trelayRetryTimer.Reset(0)\n\n\t\t\ttunnelRelay.relay.Close()\n\n\t\t\tlogger.Info(\n\t\t\t\t\"updating tunnel relay\",\n\t\t\t\tzap.String(\"old_endpoint\", tunnelRelay.dstHost),\n\t\t\t\tzap.Stringer(\"old_node_address\", tunnelRelay.ourAddrPort),\n\t\t\t\tzap.String(\"new_endpoint\", dstHost),\n\t\t\t\tzap.Stringer(\"new_node_address\", ourAddrPort),\n\t\t\t)\n\n\t\t\trelay, err := wggrpc.NewRelayToHost(dstHost, ctrl.RelayRetryTimeout, qp, ourAddrPort, withTransportCredentials(ep.Insecure))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to create tunnel relay: %w\", err)\n\t\t\t}\n\n\t\t\t// Store in outer scope because modifying the same variable will lead to the data race below\n\t\t\ttunnelRelay = tunnelProps{relay: relay, dstHost: dstHost, ourAddrPort: ourAddrPort}\n\n\t\t\teg.Go(func() error {\n\t\t\t\tlogger.Debug(\"running tunnel relay\")\n\n\t\t\t\terr := relay.Run(ctx, ctrl.makeLogger(logger))\n\t\t\t\tif err == nil {\n\t\t\t\t\tlogger.Debug(\"tunnel relay exited gracefully\",\n\t\t\t\t\t\tzap.String(\"endpoint\", dstHost),\n\t\t\t\t\t\tzap.Stringer(\"node_address\", ourAddrPort),\n\t\t\t\t\t)\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// Relay returned an error, close the relay and print the error, device should be kept running.\n\t\t\t\trelay.Close()\n\n\t\t\t\tconst retryIn = 5 * time.Second\n\n\t\t\t\tlogger.Error(\"tunnel relay failed, retrying\",\n\t\t\t\t\tzap.Duration(\"timeout\", retryIn),\n\t\t\t\t\tzap.String(\"endpoint\", dstHost),\n\t\t\t\t\tzap.Stringer(\"node_address\", ourAddrPort),\n\t\t\t\t\tzap.Error(err),\n\t\t\t\t)\n\n\t\t\t\trelayRetryTimer.Reset(retryIn)\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t}\n}\n\n// makeLogger ensures that we do not spam like crazy into our ring buffer loggers unless we explicitly want to.\nfunc (ctrl *UserspaceWireguardController) makeLogger(logger *zap.Logger) *zap.Logger {\n\tif ctrl.DebugDataStream {\n\t\treturn logger\n\t}\n\n\treturn logger.WithOptions(zap.IncreaseLevel(zap.InfoLevel))\n}\n\ntype tunnelProps struct {\n\trelay       *wggrpc.Relay\n\tdstHost     string\n\tourAddrPort netip.AddrPort\n}\n\ntype tunnelDeviceProps struct {\n\tdevice   *wgtunnel.TunnelDevice\n\tlinkName string\n\tmtu      int\n}\n\n// resettableTimer wraps time.Timer to allow resetting the timer to any duration.\ntype resettableTimer struct {\n\tmx    sync.Mutex\n\ttimer *time.Timer\n}\n\n// Reset resets the timer to the given duration.\n//\n// If the duration is zero, the timer is removed (and stopped as needed).\n// If the duration is non-zero, the timer is created if it doesn't exist, or reset if it does.\nfunc (rt *resettableTimer) Reset(delay time.Duration) {\n\trt.mx.Lock()\n\tdefer rt.mx.Unlock()\n\n\tif delay == 0 {\n\t\tif rt.timer != nil {\n\t\t\tif !rt.timer.Stop() {\n\t\t\t\t<-rt.timer.C\n\t\t\t}\n\n\t\t\trt.timer = nil\n\t\t}\n\t} else {\n\t\tif rt.timer == nil {\n\t\t\trt.timer = time.NewTimer(delay)\n\t\t} else {\n\t\t\tif !rt.timer.Stop() {\n\t\t\t\t<-rt.timer.C\n\t\t\t}\n\n\t\t\trt.timer.Reset(delay)\n\t\t}\n\t}\n}\n\n// Clear should be called after receiving from the timer channel.\nfunc (rt *resettableTimer) Clear() {\n\trt.mx.Lock()\n\tdefer rt.mx.Unlock()\n\n\trt.timer = nil\n}\n\n// C returns the timer channel.\n//\n// If the timer was not reset to a non-zero duration, nil is returned.\nfunc (rt *resettableTimer) C() <-chan time.Time {\n\trt.mx.Lock()\n\tdefer rt.mx.Unlock()\n\n\tif rt.timer == nil {\n\t\treturn nil\n\t}\n\n\treturn rt.timer.C\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/time/adjtime_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\tstdtime \"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/timex\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\n// AdjtimeStatusController manages time.AdjtimeStatus based on Linux kernel info.\ntype AdjtimeStatusController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *AdjtimeStatusController) Name() string {\n\treturn \"time.AdjtimeStatusController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *AdjtimeStatusController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *AdjtimeStatusController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: time.AdjtimeStatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\nfunc (ctrl *AdjtimeStatusController) Run(ctx context.Context, r controller.Runtime, _ *zap.Logger) error {\n\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\t// in container mode, clock is managed by the host\n\t\treturn nil\n\t}\n\n\tconst pollInterval = 30 * stdtime.Second\n\n\tpollTicker := stdtime.NewTicker(pollInterval)\n\tdefer pollTicker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-pollTicker.C:\n\t\t}\n\n\t\tvar timexBuf unix.Timex\n\n\t\tstate, err := timex.Adjtimex(&timexBuf)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get adjtimex state: %w\", err)\n\t\t}\n\n\t\tscale := stdtime.Nanosecond\n\n\t\tif timexBuf.Status&unix.STA_NANO == 0 {\n\t\t\tscale = stdtime.Microsecond\n\t\t}\n\n\t\tif err := safe.WriterModify(ctx, r, time.NewAdjtimeStatus(), func(status *time.AdjtimeStatus) error {\n\t\t\tstatus.TypedSpec().Offset = stdtime.Duration(timexBuf.Offset) * scale //nolint:durationcheck\n\t\t\tstatus.TypedSpec().FrequencyAdjustmentRatio = 1 + float64(timexBuf.Freq)/65536.0/1000000.0\n\t\t\tstatus.TypedSpec().MaxError = stdtime.Duration(timexBuf.Maxerror) * stdtime.Microsecond //nolint:durationcheck\n\t\t\tstatus.TypedSpec().EstError = stdtime.Duration(timexBuf.Esterror) * stdtime.Microsecond //nolint:durationcheck\n\t\t\tstatus.TypedSpec().Status = timex.Status(timexBuf.Status).String()\n\t\t\tstatus.TypedSpec().State = state.String()\n\t\t\tstatus.TypedSpec().Constant = int(timexBuf.Constant)\n\t\t\tstatus.TypedSpec().SyncStatus = timexBuf.Status&unix.STA_UNSYNC == 0\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update adjtime status: %w\", err)\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/time/sync.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\tstdtime \"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/ntp\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\n// SyncController manages v1alpha1.TimeSync based on configuration and NTP sync process.\ntype SyncController struct {\n\tV1Alpha1Mode v1alpha1runtime.Mode\n\tNewNTPSyncer NewNTPSyncerFunc\n\n\tbootTime stdtime.Time\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *SyncController) Name() string {\n\treturn \"time.SyncController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *SyncController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *SyncController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: time.StatusType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// NTPSyncer interface is implemented by ntp.Syncer, interface for mocking.\ntype NTPSyncer interface {\n\tRun(ctx context.Context)\n\tSynced() <-chan struct{}\n\tEpochChange() <-chan struct{}\n\tSetTimeServers([]string)\n}\n\n// NewNTPSyncerFunc function allows to replace ntp.Syncer with the mock.\ntype NewNTPSyncerFunc func(*zap.Logger, []string) NTPSyncer\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo,cyclop\nfunc (ctrl *SyncController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tif ctrl.bootTime.IsZero() {\n\t\tctrl.bootTime = stdtime.Now()\n\t}\n\n\tif ctrl.NewNTPSyncer == nil {\n\t\tctrl.NewNTPSyncer = func(logger *zap.Logger, timeServers []string) NTPSyncer {\n\t\t\treturn ntp.NewSyncer(logger, timeServers)\n\t\t}\n\t}\n\n\t// wait for udevd to be healthy, which implies that all RTC devices\n\tif err := runtime.WaitForDevicesReady(ctx, r,\n\t\t[]controller.Input{\n\t\t\t{\n\t\t\t\tNamespace: network.NamespaceName,\n\t\t\t\tType:      network.TimeServerStatusType,\n\t\t\t\tID:        optional.Some(network.TimeServerID),\n\t\t\t\tKind:      controller.InputWeak,\n\t\t\t},\n\t\t\t{\n\t\t\t\tNamespace: config.NamespaceName,\n\t\t\t\tType:      config.MachineConfigType,\n\t\t\t\tID:        optional.Some(config.ActiveID),\n\t\t\t},\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\tvar (\n\t\tsyncCtx       context.Context\n\t\tsyncCtxCancel context.CancelFunc\n\t\tsyncWg        sync.WaitGroup\n\n\t\tsyncCh  <-chan struct{}\n\t\tepochCh <-chan struct{}\n\t\tsyncer  NTPSyncer\n\n\t\ttimeSynced bool\n\t\tepoch      int\n\n\t\ttimeSyncTimeoutTimer *stdtime.Timer\n\t\ttimeSyncTimeoutCh    <-chan stdtime.Time\n\t)\n\n\tdefer func() {\n\t\tif syncer != nil {\n\t\t\tsyncCtxCancel()\n\n\t\t\tsyncWg.Wait()\n\t\t}\n\n\t\tif timeSyncTimeoutTimer != nil {\n\t\t\ttimeSyncTimeoutTimer.Stop()\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase <-r.EventCh():\n\t\tcase <-syncCh:\n\t\t\tsyncCh = nil\n\t\t\ttimeSynced = true\n\t\tcase <-epochCh:\n\t\t\tepoch++\n\t\tcase <-timeSyncTimeoutCh:\n\t\t\ttimeSynced = true\n\t\t\ttimeSyncTimeoutTimer = nil\n\t\t}\n\n\t\ttimeServersStatus, err := safe.ReaderGet[*network.TimeServerStatus](\n\t\t\tctx,\n\t\t\tr,\n\t\t\tresource.NewMetadata(network.NamespaceName, network.TimeServerStatusType, network.TimeServerID, resource.VersionUndefined),\n\t\t)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting time server status: %w\", err)\n\t\t\t}\n\n\t\t\t// time server list is not ready yet, wait for the next reconcile\n\t\t\tcontinue\n\t\t}\n\n\t\ttimeServers := timeServersStatus.TypedSpec().NTPServers\n\n\t\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.ActiveID)\n\t\tif err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error getting config: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar syncTimeout stdtime.Duration\n\n\t\tsyncDisabled := false\n\n\t\tif ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {\n\t\t\tsyncDisabled = true\n\t\t}\n\n\t\tif cfg != nil && cfg.Config().NetworkTimeSyncConfig() != nil {\n\t\t\tif cfg.Config().NetworkTimeSyncConfig().Disabled() {\n\t\t\t\tsyncDisabled = true\n\t\t\t}\n\n\t\t\tsyncTimeout = cfg.Config().NetworkTimeSyncConfig().BootTimeout()\n\t\t}\n\n\t\tif !timeSynced {\n\t\t\tsinceBoot := stdtime.Since(ctrl.bootTime)\n\n\t\t\tswitch {\n\t\t\tcase syncTimeout == 0:\n\t\t\t\t// disable sync timeout\n\t\t\t\tif timeSyncTimeoutTimer != nil {\n\t\t\t\t\ttimeSyncTimeoutTimer.Stop()\n\t\t\t\t}\n\n\t\t\t\ttimeSyncTimeoutCh = nil\n\t\t\tcase sinceBoot > syncTimeout:\n\t\t\t\t// over sync timeout already, so in sync\n\t\t\t\ttimeSynced = true\n\t\t\tdefault:\n\t\t\t\t// make sure timer fires in whatever time is left till the timeout\n\t\t\t\tif timeSyncTimeoutTimer == nil || !timeSyncTimeoutTimer.Reset(syncTimeout-sinceBoot) {\n\t\t\t\t\ttimeSyncTimeoutTimer = stdtime.NewTimer(syncTimeout - sinceBoot)\n\t\t\t\t\ttimeSyncTimeoutCh = timeSyncTimeoutTimer.C\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase syncDisabled && syncer != nil:\n\t\t\t// stop syncing\n\t\t\tsyncCtxCancel()\n\n\t\t\tsyncWg.Wait()\n\n\t\t\tsyncer = nil\n\t\t\tsyncCh = nil\n\t\t\tepochCh = nil\n\t\tcase !syncDisabled && syncer == nil:\n\t\t\t// start syncing\n\t\t\tsyncer = ctrl.NewNTPSyncer(logger, timeServers)\n\t\t\tsyncCh = syncer.Synced()\n\t\t\tepochCh = syncer.EpochChange()\n\n\t\t\ttimeSynced = false\n\n\t\t\tsyncCtx, syncCtxCancel = context.WithCancel(ctx) //nolint:govet,fatcontext\n\n\t\t\tsyncWg.Go(func() {\n\t\t\t\tsyncer.Run(syncCtx)\n\t\t\t})\n\t\t}\n\n\t\tif syncer != nil {\n\t\t\tsyncer.SetTimeServers(timeServers)\n\t\t}\n\n\t\tif syncDisabled {\n\t\t\ttimeSynced = true\n\t\t}\n\n\t\tif err = safe.WriterModify(ctx, r, time.NewStatus(), func(r *time.Status) error {\n\t\t\t*r.TypedSpec() = time.StatusSpec{\n\t\t\t\tEpoch:        epoch,\n\t\t\t\tSynced:       timeSynced,\n\t\t\t\tSyncDisabled: syncDisabled,\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating objects: %w\", err) //nolint:govet\n\t\t}\n\n\t\tr.ResetRestartBackoff()\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/time/sync_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time_test\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/ctest\"\n\ttimectrl \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/time\"\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\tv1alpha1resource \"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\ntype SyncSuite struct {\n\tsuite.Suite\n\n\tstate state.State\n\n\truntime *runtime.Runtime\n\twg      sync.WaitGroup\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tsyncerMu sync.Mutex\n\tsyncer   *mockSyncer\n}\n\nfunc (suite *SyncSuite) State() state.State { return suite.state }\n\nfunc (suite *SyncSuite) Ctx() context.Context { return suite.ctx }\n\nfunc (suite *SyncSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tsuite.state = state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tvar err error\n\n\tsuite.runtime, err = runtime.NewRuntime(suite.state, zaptest.NewLogger(suite.T()))\n\tsuite.Require().NoError(err)\n\n\t// create fake device ready status\n\tdeviceStatus := runtimeres.NewDevicesStatus(runtimeres.NamespaceName, runtimeres.DevicesID)\n\tdeviceStatus.TypedSpec().Ready = true\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, deviceStatus))\n}\n\nfunc (suite *SyncSuite) startRuntime() {\n\tsuite.wg.Go(func() {\n\t\tsuite.Assert().NoError(suite.runtime.Run(suite.ctx))\n\t})\n}\n\nfunc (suite *SyncSuite) assertTimeStatus(spec timeresource.StatusSpec) error {\n\tr, err := suite.state.Get(\n\t\tsuite.ctx,\n\t\tresource.NewMetadata(\n\t\t\tv1alpha1resource.NamespaceName,\n\t\t\ttimeresource.StatusType,\n\t\t\ttimeresource.StatusID,\n\t\t\tresource.VersionUndefined,\n\t\t),\n\t)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tstatus := r.(*timeresource.Status) //nolint:forcetypeassert\n\n\tif *status.TypedSpec() != spec {\n\t\treturn retry.ExpectedErrorf(\"time status doesn't match: %v != %v\", *status.TypedSpec(), spec)\n\t}\n\n\treturn nil\n}\n\nfunc (suite *SyncSuite) TestReconcileContainerMode() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&timectrl.SyncController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeContainer,\n\t\t\t\tNewNTPSyncer: suite.newMockSyncer,\n\t\t\t},\n\t\t),\n\t)\n\n\ttimeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)\n\ttimeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, timeServers))\n\n\tsuite.startRuntime()\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: true,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *SyncSuite) TestReconcileSyncDisabled() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&timectrl.SyncController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeMetal,\n\t\t\t\tNewNTPSyncer: suite.newMockSyncer,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\ttimeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)\n\ttimeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, timeServers))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       false,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeDisabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: true,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *SyncSuite) TestReconcileSyncDefaultConfig() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&timectrl.SyncController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeMetal,\n\t\t\t\tNewNTPSyncer: suite.newMockSyncer,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\ttimeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)\n\ttimeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, timeServers))\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       false,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *SyncSuite) TestReconcileSyncChangeConfig() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&timectrl.SyncController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeMetal,\n\t\t\t\tNewNTPSyncer: suite.newMockSyncer,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\ttimeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)\n\ttimeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, timeServers))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       false,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tvar mockSyncer *mockSyncer\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tmockSyncer = suite.getMockSyncer()\n\n\t\t\t\tif mockSyncer == nil {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"syncer not created yet\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Assert().Equal([]string{constants.DefaultNTPServer}, mockSyncer.getTimeServers())\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       false,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tclose(mockSyncer.syncedCh)\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.UpdateWithConflicts(suite, timeServers, func(r *network.TimeServerStatus) error {\n\t\tr.TypedSpec().NTPServers = []string{\"127.0.0.1\"}\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tif !slices.Equal(mockSyncer.getTimeServers(), []string{\"127.0.0.1\"}) {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"time servers not updated yet\")\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n\n\tmockSyncer.epochCh <- struct{}{}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        1,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tctest.UpdateWithConflicts(suite, cfg, func(r *config.MachineConfig) error {\n\t\tr.Container().RawV1Alpha1().MachineConfig.MachineTime = &v1alpha1.TimeConfig{ //nolint:staticcheck\n\t\t\tTimeDisabled: new(true),\n\t\t}\n\n\t\treturn nil\n\t})\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        1,\n\t\t\t\t\t\tSyncDisabled: true,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *SyncSuite) TestReconcileSyncBootTimeout() {\n\tsuite.Require().NoError(\n\t\tsuite.runtime.RegisterController(\n\t\t\t&timectrl.SyncController{\n\t\t\t\tV1Alpha1Mode: v1alpha1runtime.ModeMetal,\n\t\t\t\tNewNTPSyncer: suite.newMockSyncer,\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.startRuntime()\n\n\ttimeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)\n\ttimeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, timeServers))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       false,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n\n\tcfg := config.NewMachineConfig(\n\t\tcontainer.NewV1Alpha1(\n\t\t\t&v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeBootTimeout: 5 * time.Second,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.Require().NoError(suite.state.Create(suite.ctx, cfg))\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(\n\t\t\tfunc() error {\n\t\t\t\treturn suite.assertTimeStatus(\n\t\t\t\t\ttimeresource.StatusSpec{\n\t\t\t\t\t\tSynced:       true,\n\t\t\t\t\t\tEpoch:        0,\n\t\t\t\t\t\tSyncDisabled: false,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t},\n\t\t),\n\t)\n}\n\nfunc (suite *SyncSuite) TearDownTest() {\n\tsuite.T().Log(\"tear down\")\n\n\tsuite.ctxCancel()\n\n\tsuite.wg.Wait()\n}\n\nfunc (suite *SyncSuite) newMockSyncer(logger *zap.Logger, servers []string) timectrl.NTPSyncer {\n\tsuite.syncerMu.Lock()\n\tdefer suite.syncerMu.Unlock()\n\n\tsuite.syncer = newMockSyncer(logger, servers)\n\n\treturn suite.syncer\n}\n\nfunc (suite *SyncSuite) getMockSyncer() *mockSyncer {\n\tsuite.syncerMu.Lock()\n\tdefer suite.syncerMu.Unlock()\n\n\treturn suite.syncer\n}\n\nfunc TestSyncSuite(t *testing.T) {\n\tsuite.Run(t, new(SyncSuite))\n}\n\ntype mockSyncer struct {\n\tmu sync.Mutex\n\n\ttimeServers []string\n\tsyncedCh    chan struct{}\n\tepochCh     chan struct{}\n}\n\nfunc (mock *mockSyncer) Run(ctx context.Context) {\n\t<-ctx.Done()\n}\n\nfunc (mock *mockSyncer) Synced() <-chan struct{} {\n\treturn mock.syncedCh\n}\n\nfunc (mock *mockSyncer) EpochChange() <-chan struct{} {\n\treturn mock.epochCh\n}\n\nfunc (mock *mockSyncer) getTimeServers() (servers []string) {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn slices.Clone(mock.timeServers)\n}\n\nfunc (mock *mockSyncer) SetTimeServers(servers []string) {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tmock.timeServers = slices.Clone(servers)\n}\n\nfunc newMockSyncer(_ *zap.Logger, servers []string) *mockSyncer {\n\treturn &mockSyncer{\n\t\ttimeServers: slices.Clone(servers),\n\t\tsyncedCh:    make(chan struct{}, 1),\n\t\tepochCh:     make(chan struct{}, 1),\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/time/time.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package time contains controllers managing time, synchronization, etc.\npackage time\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package controllers provides common methods for controller operations.\npackage controllers\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"reflect\"\n\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// LoadOrNewFromFile either loads value from file.yaml or generates new values and saves as file.yaml.\n//\n//nolint:gocyclo\nfunc LoadOrNewFromFile[T any](root xfs.Root, path string, empty T, generate func(T) error) error {\n\tf, err := xfs.OpenFile(root, path, os.O_RDONLY, 0)\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"error reading state file %q: %w\", path, err)\n\t}\n\n\t// file doesn't exist yet, generate new value and save it\n\tif f == nil || errors.Is(err, fs.ErrNotExist) {\n\t\tif err = generate(empty); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tf, err = xfs.OpenFile(root, path, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0o600)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating state file %q: %w\", path, err)\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tencoder := yaml.NewEncoder(f)\n\t\tif err = encoder.Encode(empty); err != nil {\n\t\t\treturn fmt.Errorf(\"error marshaling %q: %w\", path, err)\n\t\t}\n\n\t\tif err = encoder.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn f.Close()\n\t}\n\n\t// read existing cached value\n\tdefer f.Close() //nolint:errcheck\n\n\tif err = yaml.NewDecoder(f).Decode(empty); err != nil {\n\t\treturn fmt.Errorf(\"error unmarshaling %q: %w\", path, err)\n\t}\n\n\tif reflect.ValueOf(empty).Elem().IsZero() {\n\t\treturn fmt.Errorf(\"value of %q is still zero after unmarshaling\", path)\n\t}\n\n\treturn f.Close()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/v1alpha1/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// ServiceController manages v1alpha1.Service based on services subsystem state.\ntype ServiceController struct {\n\tV1Alpha1Events runtime.Watcher\n}\n\n// Name implements controller.Controller interface.\nfunc (ctrl *ServiceController) Name() string {\n\treturn \"v1alpha1.ServiceController\"\n}\n\n// Inputs implements controller.Controller interface.\nfunc (ctrl *ServiceController) Inputs() []controller.Input {\n\treturn nil\n}\n\n// Outputs implements controller.Controller interface.\nfunc (ctrl *ServiceController) Outputs() []controller.Output {\n\treturn []controller.Output{\n\t\t{\n\t\t\tType: v1alpha1.ServiceType,\n\t\t\tKind: controller.OutputExclusive,\n\t\t},\n\t}\n}\n\n// Run implements controller.Controller interface.\n//\n//nolint:gocyclo\nfunc (ctrl *ServiceController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\n\tif err := ctrl.V1Alpha1Events.Watch(func(eventCh <-chan runtime.EventInfo) {\n\t\tdefer wg.Done()\n\n\t\tfor {\n\t\t\tvar (\n\t\t\t\tevent runtime.EventInfo\n\t\t\t\tok    bool\n\t\t\t)\n\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tcase event, ok = <-eventCh:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif msg, ok := event.Payload.(*machine.ServiceStateEvent); ok {\n\t\t\t\tservice := v1alpha1.NewService(msg.Service)\n\n\t\t\t\tswitch msg.Action { //nolint:exhaustive\n\t\t\t\tcase machine.ServiceStateEvent_RUNNING:\n\t\t\t\t\tif err := safe.WriterModify(ctx, r, service, func(svc *v1alpha1.Service) error {\n\t\t\t\t\t\t*svc.TypedSpec() = v1alpha1.ServiceSpec{\n\t\t\t\t\t\t\tRunning: true,\n\t\t\t\t\t\t\tHealthy: msg.GetHealth().GetHealthy(),\n\t\t\t\t\t\t\tUnknown: msg.GetHealth().GetUnknown(),\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}); err != nil {\n\t\t\t\t\t\tlogger.Info(\"failed creating service resource\", zap.String(\"id\", service.Metadata().ID()), zap.Error(err))\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tif err := r.Destroy(ctx, service.Metadata()); err != nil && !state.IsNotFoundError(err) {\n\t\t\t\t\t\tlogger.Info(\"failed destroying service resource\", zap.String(\"id\", service.Metadata().ID()), zap.Error(err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}, runtime.WithTailEvents(-1)); err != nil {\n\t\treturn err\n\t}\n\n\twg.Wait()\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/v1alpha1/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// WaitForServiceHealthy waits for a service to be healthy.\n//\n// It is a helper function for controllers.\nfunc WaitForServiceHealthy(ctx context.Context, r controller.Runtime, serviceID string, nextInputs []controller.Input) error {\n\t// set inputs temporarily to a service only\n\tif err := r.UpdateInputs([]controller.Input{\n\t\t{\n\t\t\tNamespace: v1alpha1.NamespaceName,\n\t\t\tType:      v1alpha1.ServiceType,\n\t\t\tID:        optional.Some(serviceID),\n\t\t\tKind:      controller.InputWeak,\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-r.EventCh():\n\t\t}\n\n\t\tservice, err := safe.ReaderGetByID[*v1alpha1.Service](ctx, r, serviceID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tif service.TypedSpec().Running && service.TypedSpec().Healthy {\n\t\t\t// condition met\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// restore inputs\n\tif err := r.UpdateInputs(nextInputs); err != nil {\n\t\treturn err\n\t}\n\n\t// queue an update to reprocess with new inputs\n\tr.QueueReconcile()\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/controllers/v1alpha1/v1alpha1.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package v1alpha1 provides controllers managing v1alpha1 resources.\npackage v1alpha1\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"go.uber.org/zap\"\n)\n\n// TaskSetupFunc defines the function that a task will execute for a specific runtime\n// mode.\ntype TaskSetupFunc func(seq Sequence, data any) (TaskExecutionFunc, string)\n\n// TaskExecutionFunc defines the function that a task will execute for a specific runtime\n// mode.\ntype TaskExecutionFunc func(context.Context, *log.Logger, Runtime) error\n\n// Phase represents a collection of tasks to be performed concurrently.\ntype Phase struct {\n\tName      string\n\tTasks     []TaskSetupFunc\n\tCheckFunc func() bool\n}\n\n// LockOptions represents the options for a controller.\ntype LockOptions struct {\n\tTakeover bool\n}\n\n// LockOption represents an option setter.\ntype LockOption func(o *LockOptions) error\n\n// WithTakeover sets the take option to true.\nfunc WithTakeover() LockOption {\n\treturn func(o *LockOptions) error {\n\t\to.Takeover = true\n\n\t\treturn nil\n\t}\n}\n\n// DefaultControllerOptions returns the default controller options.\nfunc DefaultControllerOptions() LockOptions {\n\treturn LockOptions{}\n}\n\n// Controller represents the controller responsible for managing the execution\n// of sequences.\ntype Controller interface {\n\tRuntime() Runtime\n\tSequencer() Sequencer\n\tRun(context.Context, Sequence, any, ...LockOption) error\n\tV1Alpha2() V1Alpha2Controller\n}\n\n// V1Alpha2Controller provides glue into v2alpha1 controller runtime.\ntype V1Alpha2Controller interface {\n\tRun(context.Context, *Drainer) error\n\tDependencyGraph() (*controller.DependencyGraph, error)\n\tMakeLogger(serviceName string) (*zap.Logger, error)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/disk/disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package disk contains abstract utility function to filter disks in MachineState.Disk call.\npackage disk\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/disk/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage disk\n\n// Option defines a function that can alter MachineState.Disk() method output.\ntype Option func(options *Options)\n\n// Options contains disk selection options.\ntype Options struct {\n\tLabel string\n}\n\n// WithPartitionLabel select a disk which has the partition labeled.\nfunc WithPartitionLabel(label string) Option {\n\treturn func(opts *Options) {\n\t\topts.Label = label\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package runtime defines interfaces for accessing runtime specific settings,\n// and state.\npackage runtime\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/drainer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"slices\"\n\t\"sync\"\n)\n\n// NewDrainer creates new drainer.\nfunc NewDrainer() *Drainer {\n\treturn &Drainer{\n\t\tshutdown: make(chan struct{}, 1),\n\t}\n}\n\n// Drainer is used in controllers to ensure graceful shutdown.\ntype Drainer struct {\n\tsubscriptionsMu sync.Mutex\n\tdraining        bool\n\tsubscriptions   []*DrainSubscription\n\n\tshutdown chan struct{}\n}\n\n// Drain initializes drain sequence waits for it to succeed until the context is canceled.\nfunc (d *Drainer) Drain(ctx context.Context) error {\n\td.subscriptionsMu.Lock()\n\n\tif d.draining {\n\t\td.subscriptionsMu.Unlock()\n\n\t\treturn errors.New(\"already draining\")\n\t}\n\n\td.draining = true\n\n\tfor _, s := range d.subscriptions {\n\t\tselect {\n\t\tcase s.events <- DrainEvent{}:\n\t\tdefault:\n\t\t}\n\t}\n\n\td.subscriptionsMu.Unlock()\n\n\tfor {\n\t\td.subscriptionsMu.Lock()\n\t\tl := len(d.subscriptions)\n\t\td.subscriptionsMu.Unlock()\n\n\t\tif l == 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-d.shutdown:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n}\n\n// Subscribe should be called from a controller that needs graceful shutdown.\nfunc (d *Drainer) Subscribe() *DrainSubscription {\n\td.subscriptionsMu.Lock()\n\tdefer d.subscriptionsMu.Unlock()\n\n\tsubscription := &DrainSubscription{\n\t\tevents:  make(chan DrainEvent, 1),\n\t\tdrainer: d,\n\t}\n\n\tif d.draining {\n\t\tsubscription.events <- DrainEvent{}\n\t}\n\n\td.subscriptions = append(d.subscriptions, subscription)\n\n\treturn subscription\n}\n\n// DrainSubscription keeps ingoing and outgoing events channels.\ntype DrainSubscription struct {\n\tdrainer *Drainer\n\tevents  chan DrainEvent\n}\n\n// EventCh returns drain events channel.\nfunc (s *DrainSubscription) EventCh() <-chan DrainEvent {\n\treturn s.events\n}\n\n// Cancel the subscription which triggers drain to shutdown.\nfunc (s *DrainSubscription) Cancel() {\n\ts.drainer.subscriptionsMu.Lock()\n\n\tfor i, sub := range s.drainer.subscriptions {\n\t\tif sub == s {\n\t\t\ts.drainer.subscriptions = slices.Delete(s.drainer.subscriptions, i, i+1)\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\ts.drainer.subscriptionsMu.Unlock()\n\n\tselect {\n\tcase s.drainer.shutdown <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// DrainEvent is sent to the events channel when drainer starts the shutdown sequence.\ntype DrainEvent struct{}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/drainer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n//nolint:gocyclo\nfunc TestDrainer(t *testing.T) {\n\tdrainer := runtime.NewDrainer()\n\n\tsub1 := drainer.Subscribe()\n\tsub2 := drainer.Subscribe()\n\n\terrCh := make(chan error)\n\n\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\tdefer cancel()\n\n\tgo func() {\n\t\terrCh <- drainer.Drain(ctx)\n\t}()\n\n\tselect {\n\tcase <-sub1.EventCh():\n\tcase <-time.After(time.Second):\n\t\trequire.Fail(t, \"should be notified\")\n\t}\n\n\tselect {\n\tcase <-sub2.EventCh():\n\tcase <-time.After(time.Second):\n\t\trequire.Fail(t, \"should be notified\")\n\t}\n\n\tselect {\n\tcase <-errCh:\n\t\trequire.Fail(t, \"shouldn't be drained now\")\n\tdefault:\n\t}\n\n\tsub1.Cancel()\n\n\tselect {\n\tcase <-errCh:\n\t\trequire.Fail(t, \"shouldn't be drained now\")\n\tdefault:\n\t}\n\n\tsub3 := drainer.Subscribe()\n\n\tselect {\n\tcase <-sub3.EventCh():\n\tcase <-time.After(time.Second):\n\t\trequire.Fail(t, \"should be notified\")\n\t}\n\n\tsub3.Cancel()\n\tsub2.Cancel()\n\n\tselect {\n\tcase err := <-errCh:\n\t\tassert.NoError(t, err)\n\tcase <-time.After(time.Second):\n\t\trequire.Fail(t, \"should be drained now\")\n\t}\n}\n\nfunc TestDrainTimeout(t *testing.T) {\n\tdrainer := runtime.NewDrainer()\n\n\tdrainer.Subscribe()\n\n\terrCh := make(chan error)\n\n\tctx, cancel := context.WithTimeout(t.Context(), time.Second)\n\tdefer cancel()\n\n\tgo func() {\n\t\terrCh <- drainer.Drain(ctx)\n\t}()\n\n\tselect {\n\tcase err := <-errCh:\n\t\tassert.ErrorIs(t, err, context.DeadlineExceeded)\n\tcase <-time.After(5 * time.Second):\n\t\trequire.Fail(t, \"should be drained now\")\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/emergency/emergency.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package emergency provides values to handle emergency (panic/unrecoverable error) handling for machined.\npackage emergency\n\nimport (\n\t\"sync/atomic\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// RebootCmd is a command to reboot the system after an unrecoverable error.\nvar RebootCmd atomic.Int64\n\nfunc init() {\n\tRebootCmd.Store(unix.LINUX_REBOOT_CMD_RESTART)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/errors.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\t// ErrLocked indicates that the sequencer is currently locked, and processing\n\t// another sequence.\n\tErrLocked = errors.New(\"locked\")\n\n\t// ErrInvalidSequenceData indicates that the sequencer got data the wrong\n\t// data type for a sequence.\n\tErrInvalidSequenceData = errors.New(\"invalid sequence data\")\n\n\t// ErrUndefinedRuntime indicates that the sequencer's runtime is not defined.\n\tErrUndefinedRuntime = errors.New(\"undefined runtime\")\n)\n\n// RebootError encapsulates unix.Reboot() cmd argument.\ntype RebootError struct {\n\tCmd int\n}\n\nfunc (e RebootError) Error() string {\n\treturn fmt.Sprintf(\"unix.Reboot(%x)\", e.Cmd)\n}\n\n// IsRebootError checks whether given error is RebootError.\nfunc IsRebootError(err error) bool {\n\tvar rebootErr RebootError\n\n\treturn errors.As(err, &rebootErr)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/rs/xid\"\n\t\"google.golang.org/protobuf/types/known/anypb\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ActorIDCtxKey is the context key used for event actor id.\ntype ActorIDCtxKey struct{}\n\n// Event is what is sent on the wire.\ntype Event struct {\n\tTypeURL string\n\tID      xid.ID\n\tPayload proto.Message\n\tActorID string\n}\n\n// EventInfo unifies event and queue information for the WatchFunc.\ntype EventInfo struct {\n\tEvent\n\n\tBacklog int\n}\n\n// WatchFunc defines the watcher callback function.\ntype WatchFunc func(<-chan EventInfo)\n\n// WatchOptions defines options for the watch call.\n//\n// Only one of TailEvents, TailID or TailDuration should be non-zero.\ntype WatchOptions struct {\n\t// Return that many past events.\n\t//\n\t// If TailEvents is negative, return all the events available.\n\tTailEvents int\n\t// Start at ID > specified.\n\tTailID xid.ID\n\t// Start at timestamp Now() - TailDuration.\n\tTailDuration time.Duration\n\t// ActorID to ID of the actor to filter events by.\n\tActorID string\n}\n\n// WatchOptionFunc defines the options for the watcher.\ntype WatchOptionFunc func(opts *WatchOptions) error\n\n// WithTailEvents sets up Watcher to return specified number of past events.\n//\n// If number is negative, all the available past events are returned.\nfunc WithTailEvents(number int) WatchOptionFunc {\n\treturn func(opts *WatchOptions) error {\n\t\tif !opts.TailID.IsNil() || opts.TailDuration != 0 {\n\t\t\treturn errors.New(\"WithTailEvents can't be specified at the same time with WithTailID or WithTailDuration\")\n\t\t}\n\n\t\topts.TailEvents = number\n\n\t\treturn nil\n\t}\n}\n\n// WithTailID sets up Watcher to return events with ID > TailID.\nfunc WithTailID(id xid.ID) WatchOptionFunc {\n\treturn func(opts *WatchOptions) error {\n\t\tif opts.TailEvents != 0 || opts.TailDuration != 0 {\n\t\t\treturn errors.New(\"WithTailID can't be specified at the same time with WithTailEvents or WithTailDuration\")\n\t\t}\n\n\t\topts.TailID = id\n\n\t\treturn nil\n\t}\n}\n\n// WithTailDuration sets up Watcher to return events with timestamp >= (now - tailDuration).\nfunc WithTailDuration(dur time.Duration) WatchOptionFunc {\n\treturn func(opts *WatchOptions) error {\n\t\tif opts.TailEvents != 0 || !opts.TailID.IsNil() {\n\t\t\treturn errors.New(\"WithTailDuration can't be specified at the same time with WithTailEvents or WithTailID\")\n\t\t}\n\n\t\topts.TailDuration = dur\n\n\t\treturn nil\n\t}\n}\n\n// WithActorID sets up Watcher to return events filtered by given actor id.\nfunc WithActorID(actorID string) WatchOptionFunc {\n\treturn func(opts *WatchOptions) error {\n\t\topts.ActorID = actorID\n\n\t\treturn nil\n\t}\n}\n\n// Watcher defines a runtime event watcher.\ntype Watcher interface {\n\tWatch(WatchFunc, ...WatchOptionFunc) error\n}\n\n// Publisher defines a runtime event publisher.\ntype Publisher interface {\n\tPublish(context.Context, proto.Message)\n}\n\n// EventStream defines the runtime event stream.\ntype EventStream interface {\n\tWatcher\n\tPublisher\n}\n\n// NewEvent creates a new event with the provided payload and actor ID.\nfunc NewEvent(payload proto.Message, actorID string) Event {\n\ttypeURL := \"\"\n\tif payload != nil {\n\t\ttypeURL = fmt.Sprintf(\"talos/runtime/%s\", payload.ProtoReflect().Descriptor().FullName())\n\t}\n\n\treturn Event{\n\t\t// In the future, we can publish `talos/runtime`, and\n\t\t// `talos/plugin/<plugin>` (or something along those lines) events.\n\t\t// TypeURL: fmt.Sprintf(\"talos/runtime/%s\", protoreflect.MessageDescriptor.FullName(msg)),\n\t\tTypeURL: typeURL,\n\t\tPayload: payload,\n\t\tID:      xid.New(),\n\t\tActorID: actorID,\n\t}\n}\n\n// ToMachineEvent serializes Event as proto message machine.Event.\nfunc (event *Event) ToMachineEvent() (*machine.Event, error) {\n\tvalue, err := proto.Marshal(event.Payload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &machine.Event{\n\t\tData: &anypb.Any{\n\t\t\tTypeUrl: event.TypeURL,\n\t\t\tValue:   value,\n\t\t},\n\t\tId:      event.ID.String(),\n\t\tActorId: event.ActorID,\n\t}, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/kernel_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\n// KernelCap represents kernel capabilities that we can check at runtime.\ntype KernelCap interface {\n\t// OpentreeOnAnonymousFS returns true if the kernel supports opentree on anonymous filesystems.\n\tOpentreeOnAnonymousFS() (bool, error)\n}\n\n// KernelCapabilities returns a singleton instance of KernelCap.\nvar KernelCapabilities = sync.OnceValue(func() KernelCap {\n\treturn &kernelCap{\n\t\topentreeOnAnonymousFSOnce: sync.OnceValues(canOpnetreeOnAnonymousFS),\n\t}\n})\n\ntype kernelCap struct {\n\topentreeOnAnonymousFSOnce func() (bool, error)\n}\n\n// opentreeOnAnonymousFSOnce implements KernelCap.\nfunc (k *kernelCap) OpentreeOnAnonymousFS() (bool, error) {\n\treturn k.opentreeOnAnonymousFSOnce()\n}\n\nfunc canOpnetreeOnAnonymousFS() (bool, error) {\n\ttmpfs := fsopen.New(\"tmpfs\")\n\n\tmntfd, err := tmpfs.Open()\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"unexpected error while checking for opentree on anonymous fs support: %w\", err)\n\t}\n\tdefer tmpfs.Close() //nolint:errcheck\n\n\totfs := opentree.NewFromFd(mntfd)\n\n\t_, err = otfs.Open()\n\n\tdefer otfs.Close() //nolint:errcheck\n\n\tif err == nil {\n\t\treturn true, nil // yes, the kernel supports this\n\t}\n\n\tif errors.Is(err, unix.EINVAL) {\n\t\treturn false, nil // no, the kernel does not supports this\n\t}\n\n\treturn false, fmt.Errorf(\"unexpected error while checking for opentree on anonymous fs support: %w\", err)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/circular.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"maps\"\n\t\"sync\"\n\t\"time\"\n\n\tcorezstd \"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/go-circular\"\n\t\"github.com/siderolabs/go-circular/zstd\"\n\t\"github.com/siderolabs/go-debug\"\n\t\"github.com/siderolabs/go-tail\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// These constants should some day move to config.\nconst (\n\t// Overall capacity of the log buffer (in raw bytes, memory size will be smaller due to compression).\n\tDesiredCapacity = 1048576\n\t// Some logs are tiny, no need to reserve too much memory.\n\tInitialCapacity = 16384\n\t// Chunk capacity is the length of each chunk, it should be\n\t// big enough for the compression to be efficient.\n\tChunkCapacity = 65536\n\t// Number of zstd-compressed chunks to keep.\n\tNumCompressedChunks = (DesiredCapacity / ChunkCapacity) - 1\n\t// Safety gap to avoid buffer overruns, can be lowered as with compression we don't need much.\n\tSafetyGap = 1\n)\n\n// CircularBufferLoggingManager implements logging to circular fixed size buffer.\ntype CircularBufferLoggingManager struct {\n\tfallbackLogger *log.Logger\n\n\tbuffers    sync.Map\n\tcompressor circular.Compressor\n\n\tsendersRW      sync.RWMutex\n\tsenders        []runtime.LogSender\n\tsendersChanged chan struct{}\n\n\tlineWriter chan runtime.LogWriter\n}\n\n// NewCircularBufferLoggingManager initializes new CircularBufferLoggingManager.\nfunc NewCircularBufferLoggingManager(fallbackLogger *log.Logger) *CircularBufferLoggingManager {\n\tcompressor, err := zstd.NewCompressor(\n\t\tcorezstd.WithEncoderConcurrency(1),\n\t\tcorezstd.WithWindowSize(2*corezstd.MinWindowSize),\n\t)\n\tif err != nil {\n\t\t// should not happen\n\t\tpanic(fmt.Sprintf(\"failed to create zstd compressor: %s\", err))\n\t}\n\n\treturn &CircularBufferLoggingManager{\n\t\tfallbackLogger: fallbackLogger,\n\t\tsendersChanged: make(chan struct{}),\n\t\tcompressor:     compressor,\n\t\tlineWriter:     make(chan runtime.LogWriter, 1),\n\t}\n}\n\n// ServiceLog implements runtime.LoggingManager interface.\nfunc (manager *CircularBufferLoggingManager) ServiceLog(id string) runtime.LogHandler {\n\treturn &circularHandler{\n\t\tmanager: manager,\n\t\tid:      id,\n\t\tfields: map[string]any{\n\t\t\t// use field name that is not used by anything else\n\t\t\t\"talos-service\": id,\n\t\t},\n\t}\n}\n\n// SetSenders implements runtime.LoggingManager interface.\nfunc (manager *CircularBufferLoggingManager) SetSenders(senders []runtime.LogSender) []runtime.LogSender {\n\tmanager.sendersRW.Lock()\n\n\tprevChanged := manager.sendersChanged\n\tmanager.sendersChanged = make(chan struct{})\n\n\tprevSenders := manager.senders\n\tmanager.senders = senders\n\n\tmanager.sendersRW.Unlock()\n\n\tclose(prevChanged)\n\n\treturn prevSenders\n}\n\n// SetLineWriter implements runtime.LoggingManager interface.\nfunc (manager *CircularBufferLoggingManager) SetLineWriter(w runtime.LogWriter) {\n\tselect {\n\tcase manager.lineWriter <- w:\n\tdefault:\n\t\t<-manager.lineWriter\n\n\t\tmanager.lineWriter <- w\n\t}\n}\n\n// getSenders waits for senders to be set and returns them.\nfunc (manager *CircularBufferLoggingManager) getSenders() []runtime.LogSender {\n\tfor {\n\t\tmanager.sendersRW.RLock()\n\n\t\tsenders, changed := manager.senders, manager.sendersChanged\n\n\t\tmanager.sendersRW.RUnlock()\n\n\t\tif len(senders) > 0 {\n\t\t\treturn senders\n\t\t}\n\n\t\t<-changed\n\t}\n}\n\nfunc (manager *CircularBufferLoggingManager) getBuffer(id string, create bool) (*circular.Buffer, bool, error) {\n\tbuf, ok := manager.buffers.Load(id)\n\tif ok {\n\t\treturn buf.(*circular.Buffer), false, nil\n\t}\n\n\tif !create {\n\t\treturn nil, false, nil\n\t}\n\n\tb, err := circular.NewBuffer(\n\t\tcircular.WithInitialCapacity(InitialCapacity),\n\t\tcircular.WithMaxCapacity(ChunkCapacity),\n\t\tcircular.WithNumCompressedChunks(NumCompressedChunks, manager.compressor),\n\t\tcircular.WithSafetyGap(SafetyGap))\n\tif err != nil {\n\t\treturn nil, false, err // only configuration issue might raise error\n\t}\n\n\tbuf, _ = manager.buffers.LoadOrStore(id, b)\n\n\treturn buf.(*circular.Buffer), true, nil\n}\n\n// RegisteredLogs implements runtime.LoggingManager interface.\nfunc (manager *CircularBufferLoggingManager) RegisteredLogs() []string {\n\tvar result []string\n\n\tmanager.buffers.Range(func(key, val any) bool {\n\t\tresult = append(result, key.(string))\n\n\t\treturn true\n\t})\n\n\treturn result\n}\n\ntype circularHandler struct {\n\tmanager *CircularBufferLoggingManager\n\tid      string\n\tfields  map[string]any\n\n\tbuf *circular.Buffer\n}\n\ntype nopCloser struct {\n\tio.Writer\n}\n\nfunc (nopCloser) Close() error {\n\treturn nil\n}\n\n// Writer implements runtime.LogHandler interface.\nfunc (handler *circularHandler) Writer() (io.WriteCloser, error) {\n\tif handler.buf == nil {\n\t\tvar (\n\t\t\tcreated bool\n\t\t\terr     error\n\t\t)\n\n\t\thandler.buf, created, err = handler.manager.getBuffer(handler.id, true)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif created {\n\t\t\tgo func() {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\thandler.manager.fallbackLogger.Printf(\"log sender panic: %v\", r)\n\t\t\t\t\t}\n\t\t\t\t}()\n\n\t\t\t\tif err := handler.runSenders(); err != nil {\n\t\t\t\t\thandler.manager.fallbackLogger.Printf(\"log senders stopped: %s\", err)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tgo func() {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\thandler.manager.fallbackLogger.Printf(\"log writer panic: %v\", r)\n\t\t\t\t\t}\n\t\t\t\t}()\n\n\t\t\t\tif err := handler.runLineWriter(); err != nil {\n\t\t\t\t\thandler.manager.fallbackLogger.Printf(\"log writer stopped: %s\", err)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\tswitch handler.id {\n\tcase \"machined\":\n\t\treturn &timeStampWriter{w: handler.buf}, nil\n\tdefault:\n\t\treturn nopCloser{handler.buf}, nil\n\t}\n}\n\n// Reader implements runtime.LogHandler interface.\nfunc (handler *circularHandler) Reader(opts ...runtime.LogOption) (io.ReadCloser, error) {\n\tif handler.buf == nil {\n\t\tvar err error\n\n\t\thandler.buf, _, err = handler.manager.getBuffer(handler.id, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif handler.buf == nil {\n\t\t\t// only Writer() operation creates new buffers\n\t\t\treturn nil, fmt.Errorf(\"log %q was not registered\", handler.id)\n\t\t}\n\t}\n\n\tvar opt runtime.LogOptions\n\n\tfor _, o := range opts {\n\t\tif err := o(&opt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar r interface {\n\t\tio.ReadCloser\n\t\tio.Seeker\n\t}\n\n\tif opt.Follow {\n\t\tr = handler.buf.GetStreamingReader()\n\t} else {\n\t\tr = handler.buf.GetReader()\n\t}\n\n\tif opt.TailLines != nil {\n\t\terr := tail.SeekLines(r, *opt.TailLines)\n\t\tif err != nil {\n\t\t\tr.Close() //nolint:errcheck\n\n\t\t\treturn nil, fmt.Errorf(\"error tailing log: %w\", err)\n\t\t}\n\t}\n\n\treturn r, nil\n}\n\nfunc (handler *circularHandler) runSenders() error {\n\tr, err := handler.Reader(runtime.WithFollow())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Close() //nolint:errcheck\n\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tl := bytes.TrimSpace(scanner.Bytes())\n\t\tif len(l) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\te := parseLogLine(l, time.Now())\n\t\tif e.Fields == nil {\n\t\t\te.Fields = handler.fields\n\t\t} else {\n\t\t\tmaps.Copy(e.Fields, handler.fields)\n\t\t}\n\n\t\thandler.resend(e)\n\t}\n\n\treturn fmt.Errorf(\"scanner: %w\", scanner.Err())\n}\n\n// resend sends and resends given event until success or ErrDontRetry error.\nfunc (handler *circularHandler) resend(e *runtime.LogEvent) {\n\tfor {\n\t\tsenders := handler.manager.getSenders()\n\n\t\tsendCtx, sendCancel := context.WithTimeout(context.TODO(), 5*time.Second)\n\t\tsendErrors := make(chan error, len(senders))\n\n\t\tfor _, sender := range senders {\n\t\t\tgo func() {\n\t\t\t\tsendErrors <- sender.Send(sendCtx, e)\n\t\t\t}()\n\t\t}\n\n\t\tvar dontRetry bool\n\n\t\tfor range senders {\n\t\t\terr := <-sendErrors\n\n\t\t\t// don't retry if at least one sender succeed to avoid implementing per-sender queue, etc\n\t\t\tif err == nil {\n\t\t\t\tdontRetry = true\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif debug.Enabled {\n\t\t\t\thandler.manager.fallbackLogger.Print(err)\n\t\t\t}\n\n\t\t\tif errors.Is(err, runtime.ErrDontRetry) {\n\t\t\t\tdontRetry = true\n\t\t\t}\n\t\t}\n\n\t\tsendCancel()\n\n\t\tif dontRetry {\n\t\t\treturn\n\t\t}\n\n\t\ttime.Sleep(time.Second)\n\t}\n}\n\nfunc (handler *circularHandler) runLineWriter() error {\n\tr, err := handler.Reader(runtime.WithFollow())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Close() //nolint:errcheck\n\n\tw := <-handler.manager.lineWriter\n\tselect {\n\tcase handler.manager.lineWriter <- w:\n\tdefault:\n\t}\n\n\tscanner := bufio.NewScanner(r)\n\tfor scanner.Scan() {\n\t\tl := scanner.Bytes()\n\n\t\terr = w.WriteLog(handler.id, l)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"line writer: %w\", err)\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"scanner: %w\", scanner.Err())\n}\n\n// timeStampWriter is a writer that adds a timestamp to each line.\ntype timeStampWriter struct {\n\tw io.WriteCloser\n}\n\n// Write implements the io.Writer interface.\nfunc (t *timeStampWriter) Write(p []byte) (int, error) {\n\tbuf := make([]byte, 0, len(p)+27)\n\n\t// Current log.Logger implementation always adds a newline to the message, so we don't need to wait for it.\n\tbuf = time.Now().AppendFormat(buf, \"2006/01/02 15:04:05.000000\")\n\tbuf = append(buf, ' ')\n\tbuf = append(buf, p...)\n\n\tn, err := t.w.Write(buf)\n\n\tswitch {\n\tcase err == nil && n == len(buf):\n\t\treturn len(p), nil // success, return original length\n\tcase err == nil && n != len(buf):\n\t\treturn n, fmt.Errorf(\"time stamp writer error: %w\", io.ErrShortWrite)\n\tdefault:\n\t\treturn n, fmt.Errorf(\"time stamp writer internal error: %w\", err)\n\t}\n}\n\n// Close implements the io.Closer interface.\nfunc (t *timeStampWriter) Close() error { return t.w.Close() }\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/extract.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"math\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\nvar maxEpochTS = float64(time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC).Unix())\n\n//nolint:gocyclo\nfunc parseLogLine(l []byte, now time.Time) *runtime.LogEvent {\n\tmsg, m := parseJSONLogLine(l)\n\te := &runtime.LogEvent{\n\t\tMsg:   msg,\n\t\tTime:  now,\n\t\tLevel: zapcore.InfoLevel,\n\t}\n\n\tif m == nil {\n\t\treturn e\n\t}\n\n\tfor _, k := range []string{\"time\", \"ts\"} {\n\t\tvar t time.Time\n\n\t\tswitch ts := m[k].(type) {\n\t\tcase string:\n\t\t\tt, _ = time.Parse(time.RFC3339Nano, ts) //nolint:errcheck\n\t\tcase float64:\n\t\t\t// seconds or milliseconds since epoch\n\t\t\tsec, fsec := math.Modf(ts)\n\t\t\tif sec > maxEpochTS {\n\t\t\t\tsec, fsec = math.Modf(ts / 1000)\n\t\t\t}\n\n\t\t\tt = time.Unix(int64(sec), int64(fsec*float64(time.Second)))\n\t\t}\n\n\t\tif !t.IsZero() {\n\t\t\te.Time = t.UTC()\n\n\t\t\tdelete(m, k)\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif levelS, ok := m[\"level\"].(string); ok {\n\t\tlevelS = strings.ToLower(levelS)\n\n\t\t// convert containerd's logrus' level to zap's level\n\t\tif levelS == \"warning\" {\n\t\t\tlevelS = \"warn\"\n\t\t}\n\n\t\tvar level zapcore.Level\n\t\tif err := level.UnmarshalText([]byte(levelS)); err == nil {\n\t\t\te.Level = level\n\n\t\t\tdelete(m, \"level\")\n\t\t}\n\t}\n\n\tif msgS, ok := m[\"msg\"].(string); ok {\n\t\t// in case we have both message before JSON and \"msg\" JSON field\n\t\tif e.Msg != \"\" {\n\t\t\te.Msg += \" \"\n\t\t}\n\n\t\te.Msg += strings.TrimSpace(msgS)\n\n\t\tdelete(m, \"msg\")\n\t}\n\n\tif errS, ok := m[\"err\"].(string); ok {\n\t\tif e.Level < zap.WarnLevel {\n\t\t\te.Level = zap.WarnLevel\n\t\t}\n\n\t\tif e.Msg != \"\" {\n\t\t\te.Msg += \": \"\n\t\t}\n\n\t\te.Msg += strings.TrimSpace(errS)\n\n\t\tdelete(m, \"err\")\n\t}\n\n\te.Fields = m\n\n\treturn e\n}\n\nfunc parseJSONLogLine(l []byte) (msg string, m map[string]any) {\n\t// the whole line is valid JSON\n\tif err := json.Unmarshal(l, &m); err == nil {\n\t\treturn msg, m\n\t}\n\n\t// the line is a message followed by JSON\n\tif i := bytes.Index(l, []byte(\"{\")); i != -1 {\n\t\tif err := json.Unmarshal(l[i:], &m); err == nil {\n\t\t\tmsg = string(bytes.TrimSpace(l[:i]))\n\n\t\t\treturn msg, m\n\t\t}\n\t}\n\n\t// no JSON found\n\tmsg = string(l)\n\n\treturn msg, m\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/extract_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging //nolint:testpackage\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\nfunc TestParseLogLine(t *testing.T) {\n\tt.Parallel()\n\n\tnow := time.Date(2021, 10, 19, 12, 42, 37, 123456789, time.UTC)\n\n\tfor name, tc := range map[string]struct {\n\t\tl        string\n\t\texpected *runtime.LogEvent\n\t}{\n\t\t\"machined\": {\n\t\t\tl: `[talos] task updateBootloader (1/1): done, 219.885384ms`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:   `[talos] task updateBootloader (1/1): done, 219.885384ms`,\n\t\t\t\tTime:  now,\n\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t},\n\t\t},\n\t\t\"controller-runtime\": {\n\t\t\tl: `reconfigured wireguard link {\"component\": \"controller-runtime\", \"controller\": \"network.LinkSpecController\", \"link\": \"kubespan\", \"peers\": 4}`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:   `reconfigured wireguard link`,\n\t\t\t\tTime:  now,\n\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\"component\":  \"controller-runtime\",\n\t\t\t\t\t\"controller\": \"network.LinkSpecController\",\n\t\t\t\t\t\"link\":       \"kubespan\",\n\t\t\t\t\t\"peers\":      float64(4),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"etcd-zap\": {\n\t\t\tl: `{\"level\":\"info\",\"ts\":\"2021-10-19T14:53:05.815Z\",\"caller\":\"mvcc/kvstore_compaction.go:57\",\"msg\":\"finished scheduled compaction\",\"compact-revision\":34567,\"took\":\"21.041639ms\"}`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:   `finished scheduled compaction`,\n\t\t\t\tTime:  time.Date(2021, 10, 19, 14, 53, 5, 815000000, time.UTC),\n\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\"caller\":           \"mvcc/kvstore_compaction.go:57\",\n\t\t\t\t\t\"compact-revision\": float64(34567),\n\t\t\t\t\t\"took\":             \"21.041639ms\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"cri-logrus\": {\n\t\t\tl: `{\"level\":\"warning\",\"msg\":\"cleanup warnings time=\\\"2021-10-19T14:52:20Z\\\" level=info msg=\\\"starting signal loop\\\" namespace=k8s.io pid=2629\\n\",\"time\":\"2021-10-19T14:52:20.578858689Z\"}`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:    `cleanup warnings time=\"2021-10-19T14:52:20Z\" level=info msg=\"starting signal loop\" namespace=k8s.io pid=2629`,\n\t\t\t\tTime:   time.Date(2021, 10, 19, 14, 52, 20, 578858689, time.UTC),\n\t\t\t\tLevel:  zapcore.WarnLevel,\n\t\t\t\tFields: map[string]any{},\n\t\t\t},\n\t\t},\n\t\t\"kubelet\": {\n\t\t\tl: `{\"ts\":1635266764792.703,\"caller\":\"topologymanager/scope.go:110\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"0194fac91ac1d3949497f6912f3c7e73a062c3bf29b6d3da05557d4db2f8482b\"}`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:   `RemoveContainer`,\n\t\t\t\tTime:  time.Date(2021, 10, 26, 16, 46, 4, 792702913, time.UTC),\n\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\"caller\":      \"topologymanager/scope.go:110\",\n\t\t\t\t\t\"containerID\": \"0194fac91ac1d3949497f6912f3c7e73a062c3bf29b6d3da05557d4db2f8482b\",\n\t\t\t\t\t\"v\":           float64(0),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"kubelet-err\": {\n\t\t\tl: `{\"ts\":1635266751595.943,\"caller\":\"kubelet/kubelet.go:1703\",\"msg\":\"Failed creating a mirror pod for\",` +\n\t\t\t\t`\"pod\":\"kube-system/kube-controller-manager-talos-dev-qemu-master-1\",\"err\":\"pods \\\"kube-controller-manager-talos-dev-qemu-master-1\\\" already exists\"}`,\n\t\t\texpected: &runtime.LogEvent{\n\t\t\t\tMsg:   `Failed creating a mirror pod for: pods \"kube-controller-manager-talos-dev-qemu-master-1\" already exists`,\n\t\t\t\tTime:  time.Date(2021, 10, 26, 16, 45, 51, 595943212, time.UTC),\n\t\t\t\tLevel: zapcore.WarnLevel,\n\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\"caller\": \"kubelet/kubelet.go:1703\",\n\t\t\t\t\t\"pod\":    \"kube-system/kube-controller-manager-talos-dev-qemu-master-1\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual := parseLogLine([]byte(tc.l), now)\n\t\t\tassert.Equal(t, tc.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/file.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/containers\"\n\t\"github.com/siderolabs/go-tail\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/follow\"\n)\n\n// FileLoggingManager implements simple logging to files.\ntype FileLoggingManager struct {\n\tlogDirectory string\n\n\tregisteredLogs containers.ConcurrentMap[string, struct{}]\n}\n\n// NewFileLoggingManager initializes new FileLoggingManager.\nfunc NewFileLoggingManager(logDirectory string) *FileLoggingManager {\n\treturn &FileLoggingManager{\n\t\tlogDirectory: logDirectory,\n\t}\n}\n\n// ServiceLog implements runtime.LoggingManager interface.\nfunc (manager *FileLoggingManager) ServiceLog(id string) runtime.LogHandler {\n\treturn &fileLogHandler{\n\t\tlogDirectory: manager.logDirectory,\n\t\tid:           id,\n\t\tmanager:      manager,\n\t}\n}\n\n// SetSenders implements runtime.LoggingManager interface (by doing nothing).\nfunc (manager *FileLoggingManager) SetSenders([]runtime.LogSender) []runtime.LogSender {\n\treturn nil\n}\n\n// SetLineWriter implements runtime.LoggingManager interface (by doing nothing).\nfunc (manager *FileLoggingManager) SetLineWriter(runtime.LogWriter) {}\n\n// RegisteredLogs implements runtime.LoggingManager interface.\nfunc (manager *FileLoggingManager) RegisteredLogs() []string {\n\tvar result []string\n\n\tmanager.registeredLogs.ForEach(func(key string, _ struct{}) {\n\t\tresult = append(result, key)\n\t})\n\n\treturn result\n}\n\ntype fileLogHandler struct {\n\tpath string\n\n\tlogDirectory string\n\tid           string\n\tmanager      *FileLoggingManager\n}\n\nfunc (handler *fileLogHandler) buildPath() error {\n\tif strings.ContainsAny(handler.id, string(os.PathSeparator)+\".\") {\n\t\treturn errors.New(\"service ID is invalid\")\n\t}\n\n\thandler.path = filepath.Join(handler.logDirectory, handler.id+\".log\")\n\n\treturn nil\n}\n\n// Writer implements runtime.LogHandler interface.\nfunc (handler *fileLogHandler) Writer() (io.WriteCloser, error) {\n\tif err := handler.buildPath(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult, err := os.OpenFile(handler.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o666)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thandler.manager.registeredLogs.GetOrCreate(handler.id, struct{}{})\n\n\treturn result, nil\n}\n\n// Reader implements runtime.LogHandler interface.\nfunc (handler *fileLogHandler) Reader(opts ...runtime.LogOption) (io.ReadCloser, error) {\n\tvar opt runtime.LogOptions\n\n\tfor _, o := range opts {\n\t\tif err := o(&opt); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err := handler.buildPath(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tf, err := os.OpenFile(handler.path, os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif opt.TailLines != nil {\n\t\terr = tail.SeekLines(f, *opt.TailLines)\n\t\tif err != nil {\n\t\t\tf.Close() //nolint:errcheck\n\n\t\t\treturn nil, fmt.Errorf(\"error tailing log: %w\", err)\n\t\t}\n\t}\n\n\tif opt.Follow {\n\t\treturn follow.NewReader(context.Background(), f), nil\n\t}\n\n\treturn f, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/logging.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package logging provides implementations of runtime.LoggingManager.\npackage logging\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/null.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// NullLoggingManager sends all the logs to /dev/null.\ntype NullLoggingManager struct{}\n\n// NewNullLoggingManager initializes NullLoggingManager.\nfunc NewNullLoggingManager() *NullLoggingManager {\n\treturn &NullLoggingManager{}\n}\n\n// ServiceLog implements LoggingManager.\nfunc (*NullLoggingManager) ServiceLog(id string) runtime.LogHandler {\n\treturn &nullLogHandler{}\n}\n\n// SetSenders implements runtime.LoggingManager interface (by doing nothing).\nfunc (*NullLoggingManager) SetSenders([]runtime.LogSender) []runtime.LogSender {\n\treturn nil\n}\n\n// SetLineWriter implements runtime.LoggingManager interface (by doing nothing).\nfunc (*NullLoggingManager) SetLineWriter(runtime.LogWriter) {}\n\n// RegisteredLogs implements runtime.LoggingManager interface (by doing nothing).\nfunc (*NullLoggingManager) RegisteredLogs() []string {\n\treturn nil\n}\n\ntype nullLogHandler struct{}\n\nfunc (*nullLogHandler) Writer() (io.WriteCloser, error) {\n\treturn os.OpenFile(os.DevNull, os.O_WRONLY, 0)\n}\n\nfunc (*nullLogHandler) Reader(...runtime.LogOption) (io.ReadCloser, error) {\n\treturn os.OpenFile(os.DevNull, os.O_RDONLY, 0)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/sender_jsonlines.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\ntype jsonLinesSender struct {\n\tendpoint  *url.URL\n\textraTags map[string]string\n\n\tsema chan struct{}\n\tconn net.Conn\n}\n\n// NewJSONLines returns log sender that sends logs in JSON over TCP (newline-delimited)\n// or UDP (one message per packet).\nfunc NewJSONLines(cfg config.LoggingDestination) runtime.LogSender {\n\tsema := make(chan struct{}, 1)\n\tsema <- struct{}{}\n\n\treturn &jsonLinesSender{\n\t\tendpoint:  cfg.Endpoint(),\n\t\textraTags: cfg.ExtraTags(),\n\n\t\tsema: sema,\n\t}\n}\n\nfunc (j *jsonLinesSender) tryLock(ctx context.Context) (unlock func()) {\n\tselect {\n\tcase <-j.sema:\n\t\tunlock = func() { j.sema <- struct{}{} }\n\tcase <-ctx.Done():\n\t\tunlock = nil\n\t}\n\n\treturn unlock\n}\n\nfunc (j *jsonLinesSender) marshalJSON(e *runtime.LogEvent) ([]byte, error) {\n\tm := make(map[string]any, len(e.Fields)+3)\n\n\tmaps.Copy(m, e.Fields)\n\tm[\"msg\"] = e.Msg\n\tm[\"talos-time\"] = e.Time.Format(time.RFC3339Nano)\n\tm[\"talos-level\"] = e.Level.String()\n\n\tfor k, v := range j.extraTags {\n\t\tm[k] = v\n\t}\n\n\treturn json.Marshal(m)\n}\n\n// Send implements LogSender interface.\nfunc (j *jsonLinesSender) Send(ctx context.Context, e *runtime.LogEvent) error {\n\tb, err := j.marshalJSON(e)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%w: %s\", runtime.ErrDontRetry, err)\n\t}\n\n\tif j.endpoint.Scheme == \"tcp\" {\n\t\tb = append(b, '\\n')\n\t}\n\n\tunlock := j.tryLock(ctx)\n\tif unlock == nil {\n\t\treturn ctx.Err()\n\t}\n\n\tdefer unlock()\n\n\t// Connect (or \"connect\" for UDP) if no connection is established already.\n\tif j.conn == nil {\n\t\tconn, err := new(net.Dialer).DialContext(ctx, j.endpoint.Scheme, j.endpoint.Host)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tj.conn = conn\n\t}\n\n\td, _ := ctx.Deadline()\n\tj.conn.SetWriteDeadline(d) //nolint:errcheck\n\n\t// Close connection on send error.\n\tif n, err := j.conn.Write(b); err != nil {\n\t\tj.conn.Close() //nolint:errcheck\n\t\tj.conn = nil\n\n\t\t// skip partially sent events to avoid partial duplicates in the receiver\n\t\tif n > 0 {\n\t\t\terr = fmt.Errorf(\"%w: %s\", runtime.ErrDontRetry, err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// Close implements LogSender interface.\nfunc (j *jsonLinesSender) Close(ctx context.Context) error {\n\tunlock := j.tryLock(ctx)\n\tif unlock == nil {\n\t\treturn ctx.Err()\n\t}\n\n\tdefer unlock()\n\n\tif j.conn == nil {\n\t\treturn nil\n\t}\n\n\tconn := j.conn\n\tj.conn = nil\n\n\tclosed := make(chan error, 1)\n\n\tgo func() {\n\t\tclosed <- conn.Close()\n\t}()\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase err := <-closed:\n\t\treturn err\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging/sender_jsonlines_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging_test\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"net\"\n\t\"net/url\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc udpHandler(ctx context.Context, t *testing.T, conn net.PacketConn, sendCh chan<- []byte) {\n\tt.Helper()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tif err := conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond)); err != nil {\n\t\t\tt.Logf(\"failed to set read deadline: %v\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tbuf := make([]byte, 1024)\n\n\t\tn, _, err := conn.ReadFrom(buf)\n\t\tif err != nil {\n\t\t\tif netErr, ok := err.(net.Error); ok && netErr.Timeout() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt.Logf(\"failed to read from UDP connection: %v\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tif !channel.SendWithContext(ctx, sendCh, buf[:n]) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc tcpHandler(ctx context.Context, t *testing.T, conn net.Listener, sendCh chan<- []byte) {\n\tt.Helper()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tif err := conn.(*net.TCPListener).SetDeadline(time.Now().Add(10 * time.Millisecond)); err != nil {\n\t\t\tt.Logf(\"failed to set accept deadline: %v\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tc, err := conn.Accept()\n\t\tif err != nil {\n\t\t\tif netErr, ok := err.(net.Error); ok && netErr.Timeout() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt.Logf(\"failed to accept UDP connection: %v\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tgo func() {\n\t\t\tdefer c.Close() //nolint:errcheck\n\n\t\t\tscanner := bufio.NewScanner(c)\n\n\t\t\tfor scanner.Scan() {\n\t\t\t\tif !channel.SendWithContext(ctx, sendCh, scanner.Bytes()) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n}\n\ntype loggingDestination struct {\n\tendpoint  *url.URL\n\textraTags map[string]string\n}\n\nfunc (l *loggingDestination) Endpoint() *url.URL {\n\treturn l.endpoint\n}\n\nfunc (l *loggingDestination) ExtraTags() map[string]string {\n\treturn l.extraTags\n}\n\nfunc (l *loggingDestination) Format() string {\n\treturn constants.LoggingFormatJSONLines\n}\n\nfunc TestSenderJSONLines(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tlisUDP, err := (&net.ListenConfig{}).ListenPacket(t.Context(), \"udp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, lisUDP.Close())\n\t})\n\n\tlisTCP, err := (&net.ListenConfig{}).Listen(t.Context(), \"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, lisTCP.Close())\n\t})\n\n\tudpEndpoint := lisUDP.LocalAddr().String()\n\ttcpEndpoint := lisTCP.Addr().String()\n\n\tctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)\n\tt.Cleanup(cancel)\n\n\tsendCh := make(chan []byte, 32)\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tudpHandler(ctx, t, lisUDP, sendCh)\n\t})\n\n\twg.Go(func() {\n\t\ttcpHandler(ctx, t, lisTCP, sendCh)\n\t})\n\n\tt.Cleanup(wg.Wait)\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tendpoint  *url.URL\n\t\textraTags map[string]string\n\n\t\tmessages []*runtime.LogEvent\n\n\t\texpected []map[string]any\n\t}{\n\t\t{\n\t\t\tname: \"UDP\",\n\n\t\t\tendpoint: ensure.Value(url.Parse(\"udp://\" + udpEndpoint)),\n\n\t\t\tmessages: []*runtime.LogEvent{\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"msg1\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:00Z\")),\n\t\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"msg2\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:01Z\")),\n\t\t\t\t\tLevel: zapcore.DebugLevel,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: []map[string]any{\n\t\t\t\t{\n\t\t\t\t\t\"field1\":      \"value1\",\n\t\t\t\t\t\"msg\":         \"msg1\",\n\t\t\t\t\t\"talos-level\": \"info\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:00Z\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"msg\":         \"msg2\",\n\t\t\t\t\t\"talos-level\": \"debug\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:01Z\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UDP with extra tags\",\n\n\t\t\tendpoint: ensure.Value(url.Parse(\"udp://\" + udpEndpoint)),\n\t\t\textraTags: map[string]string{\n\t\t\t\t\"extra1\": \"value1\",\n\t\t\t},\n\n\t\t\tmessages: []*runtime.LogEvent{\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"msg1\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:00Z\")),\n\t\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"msg2\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:01Z\")),\n\t\t\t\t\tLevel: zapcore.DebugLevel,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: []map[string]any{\n\t\t\t\t{\n\t\t\t\t\t\"field1\":      \"value1\",\n\t\t\t\t\t\"extra1\":      \"value1\",\n\t\t\t\t\t\"msg\":         \"msg1\",\n\t\t\t\t\t\"talos-level\": \"info\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:00Z\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"msg\":         \"msg2\",\n\t\t\t\t\t\"extra1\":      \"value1\",\n\t\t\t\t\t\"talos-level\": \"debug\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:01Z\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP\",\n\n\t\t\tendpoint: ensure.Value(url.Parse(\"tcp://\" + tcpEndpoint)),\n\n\t\t\tmessages: []*runtime.LogEvent{\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"hello\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:00Z\")),\n\t\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: []map[string]any{\n\t\t\t\t{\n\t\t\t\t\t\"field1\":      \"value1\",\n\t\t\t\t\t\"msg\":         \"hello\",\n\t\t\t\t\t\"talos-level\": \"info\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:00Z\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TCP with extra tags\",\n\n\t\t\tendpoint: ensure.Value(url.Parse(\"tcp://\" + tcpEndpoint)),\n\t\t\textraTags: map[string]string{\n\t\t\t\t\"extra1\": \"value1\",\n\t\t\t},\n\n\t\t\tmessages: []*runtime.LogEvent{\n\t\t\t\t{\n\t\t\t\t\tMsg:   \"hello\",\n\t\t\t\t\tTime:  ensure.Value(time.Parse(time.RFC3339Nano, \"2021-01-01T00:00:00Z\")),\n\t\t\t\t\tLevel: zapcore.InfoLevel,\n\t\t\t\t\tFields: map[string]any{\n\t\t\t\t\t\t\"field1\": \"value1\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: []map[string]any{\n\t\t\t\t{\n\t\t\t\t\t\"field1\":      \"value1\",\n\t\t\t\t\t\"extra1\":      \"value1\",\n\t\t\t\t\t\"msg\":         \"hello\",\n\t\t\t\t\t\"talos-level\": \"info\",\n\t\t\t\t\t\"talos-time\":  \"2021-01-01T00:00:00Z\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t// not parallel - need sequential execution\n\t\t\tloggingCfg := &loggingDestination{\n\t\t\t\tendpoint:  test.endpoint,\n\t\t\t\textraTags: test.extraTags,\n\t\t\t}\n\n\t\t\tsender := logging.NewJSONLines(loggingCfg)\n\n\t\t\tfor _, msg := range test.messages {\n\t\t\t\trequire.NoError(t, sender.Send(ctx, msg))\n\t\t\t}\n\n\t\t\tfor _, expected := range test.expected {\n\t\t\t\tselect {\n\t\t\t\tcase <-time.After(time.Second):\n\t\t\t\t\tt.Fatalf(\"timed out waiting for message\")\n\t\t\t\tcase msg := <-sendCh:\n\t\t\t\t\tvar m map[string]any\n\n\t\t\t\t\trequire.NoError(t, json.Unmarshal(msg, &m))\n\n\t\t\t\t\trequire.Equal(t, expected, m)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.NoError(t, sender.Close(ctx))\n\t\t})\n\t}\n\n\tcancel()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/logging.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"time\"\n\n\t\"go.uber.org/zap/zapcore\"\n)\n\n// LoggingManager provides unified interface to publish and consume logs.\ntype LoggingManager interface {\n\t// ServiceLog privides a log handler for a given service (that may not exist).\n\tServiceLog(service string) LogHandler\n\n\t// SetSenders sets log senders for all derived log handlers\n\t// and returns the previous ones for closing.\n\t//\n\t// SetSenders should be thread-safe.\n\tSetSenders(senders []LogSender) []LogSender\n\n\t// SetLineWriter sets a writer that will receive raw log lines.\n\t//\n\t// SetLineWriter can be only singularly called, subsequent calls override previous writer.\n\tSetLineWriter(w LogWriter)\n\n\t// RegisteredLogs returns a list of registered logs containers.\n\tRegisteredLogs() []string\n}\n\n// LogOptions for LogHandler.Reader.\ntype LogOptions struct {\n\tFollow    bool\n\tTailLines *int\n}\n\n// LogOption provides functional options for LogHandler.Reader.\ntype LogOption func(*LogOptions) error\n\n// WithFollow enables follow mode for the logs.\nfunc WithFollow() LogOption {\n\treturn func(o *LogOptions) error {\n\t\to.Follow = true\n\n\t\treturn nil\n\t}\n}\n\n// WithTailLines starts log reading from lines from the tail of the log.\nfunc WithTailLines(lines int) LogOption {\n\treturn func(o *LogOptions) error {\n\t\to.TailLines = &lines\n\n\t\treturn nil\n\t}\n}\n\n// LogHandler provides interface to access particular log source.\ntype LogHandler interface {\n\tWriter() (io.WriteCloser, error)\n\tReader(opt ...LogOption) (io.ReadCloser, error)\n}\n\n// LogEvent represents a log message to be send.\ntype LogEvent struct {\n\tMsg    string\n\tTime   time.Time\n\tLevel  zapcore.Level\n\tFields map[string]any\n}\n\n// ErrDontRetry indicates that log event should not be resent.\nvar ErrDontRetry = errors.New(\"don't retry\")\n\n// LogSender provides common interface for log senders.\ntype LogSender interface {\n\t// Send tries to send the log event once, exiting on success, error, or context cancelation.\n\t//\n\t// Returned error is nil on success, non-nil otherwise.\n\t// As a special case, Send can return (possibly wrapped) ErrDontRetry if the log event should not be resent\n\t// (if it is invalid, if it was sent partially, etc).\n\t//\n\t// Send should be thread-safe.\n\tSend(ctx context.Context, e *LogEvent) error\n\n\t// Close stops the sender gracefully if possible, or forcefully on context cancelation.\n\t//\n\t// Close should be thread-safe.\n\tClose(ctx context.Context) error\n}\n\n// LogWriter provider common interface for text-based log writers.\ntype LogWriter interface {\n\t// WriteLog writes a single log line.\n\t//\n\t// WriteLog should be thread-safe.\n\tWriteLog(id string, line []byte) error\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/mode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n)\n\n// Mode is a runtime mode.\ntype Mode int\n\n// ModeCapability describes mode capability flags.\ntype ModeCapability uint64\n\nconst (\n\t// ModeCloud is the cloud runtime mode.\n\tModeCloud Mode = iota\n\t// ModeContainer is the container runtime mode.\n\tModeContainer\n\t// ModeMetal is the metal runtime mode.\n\tModeMetal\n\t// ModeMetalAgent is the metal agent runtime mode.\n\tModeMetalAgent\n)\n\nconst (\n\t// Reboot node reboot.\n\tReboot ModeCapability = 1 << iota\n\t// Rollback node rollback.\n\tRollback\n\t// Shutdown node shutdown.\n\tShutdown\n\t// Upgrade node upgrade.\n\tUpgrade\n\t// MetaKV is META partition.\n\tMetaKV\n)\n\nconst (\n\tcloud      = \"cloud\"\n\tcontainer  = \"container\"\n\tmetal      = \"metal\"\n\tmetalAgent = \"metal-agent\"\n)\n\n// String returns the string representation of a Mode.\nfunc (m Mode) String() string {\n\treturn [...]string{cloud, container, metal, metalAgent}[m]\n}\n\n// RequiresInstall implements config.RuntimeMode.\nfunc (m Mode) RequiresInstall() bool {\n\treturn m == ModeMetal\n}\n\n// InContainer implements config.RuntimeMode.\nfunc (m Mode) InContainer() bool {\n\treturn m == ModeContainer\n}\n\n// Supports returns mode capability.\nfunc (m Mode) Supports(feature ModeCapability) bool {\n\treturn (m.capabilities() & uint64(feature)) != 0\n}\n\n// IsAgent returns true if the mode is an agent mode (i.e. metal agent mode).\nfunc (m Mode) IsAgent() bool {\n\treturn m == ModeMetalAgent\n}\n\n// ParseMode returns a `Mode` that matches the specified string.\nfunc ParseMode(s string) (mod Mode, err error) {\n\tswitch s {\n\tcase cloud:\n\t\tmod = ModeCloud\n\tcase container:\n\t\tmod = ModeContainer\n\tcase metal:\n\t\tmod = ModeMetal\n\tcase metalAgent:\n\t\tmod = ModeMetalAgent\n\tdefault:\n\t\treturn mod, fmt.Errorf(\"unknown runtime mode: %q\", s)\n\t}\n\n\treturn mod, nil\n}\n\nfunc (m Mode) capabilities() uint64 {\n\tall := ^uint64(0)\n\n\treturn [...]uint64{\n\t\t// metal\n\t\tall,\n\t\t// container\n\t\tall ^ uint64(Reboot|Shutdown|Upgrade|Rollback|MetaKV),\n\t\t// cloud\n\t\tall,\n\t}[m]\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/mode_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\nfunc TestMode_String(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tm    runtime.Mode\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"cloud\",\n\t\t\tm:    runtime.ModeCloud,\n\t\t\twant: \"cloud\",\n\t\t},\n\t\t{\n\t\t\tname: \"container\",\n\t\t\tm:    runtime.ModeContainer,\n\t\t\twant: \"container\",\n\t\t},\n\t\t{\n\t\t\tname: \"metal\",\n\t\t\tm:    runtime.ModeMetal,\n\t\t\twant: \"metal\",\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 := tt.m.String(); got != tt.want {\n\t\t\t\tt.Errorf(\"Mode.String() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseMode(t *testing.T) {\n\ttype args struct {\n\t\ts string\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twantM   runtime.Mode\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname:    \"cloud\",\n\t\t\targs:    args{\"cloud\"},\n\t\t\twantM:   runtime.ModeCloud,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"container\",\n\t\t\targs:    args{\"container\"},\n\t\t\twantM:   runtime.ModeContainer,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"metal\",\n\t\t\targs:    args{\"metal\"},\n\t\t\twantM:   runtime.ModeMetal,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid\",\n\t\t\targs:    args{\"invalid\"},\n\t\t\twantM:   0,\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgotM, err := runtime.ParseMode(tt.args.s)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ParseMode() error = %v, wantErr %v\", err, tt.wantErr)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif gotM != tt.wantM {\n\t\t\t\tt.Errorf(\"ParseMode() = %v, want %v\", gotM, tt.wantM)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/platform.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// Platform defines the requirements for a platform.\ntype Platform interface {\n\t// Name returns platform name.\n\tName() string\n\n\t// Mode returns platform mode (metal, cloud or container).\n\tMode() Mode\n\n\t// Configuration fetches the machine configuration from platform-specific location.\n\t//\n\t// On cloud-like platform it is user-data in metadata service.\n\t// For metal platform that is either `talos.config=` URL or mounted ISO image.\n\tConfiguration(context.Context, state.State) ([]byte, error)\n\n\t// KernelArgs returns additional kernel arguments which should be injected for the kernel boot.\n\tKernelArgs(arch string, quirks quirks.Quirks) procfs.Parameters\n\n\t// NetworkConfiguration fetches network configuration from the platform metadata.\n\t//\n\t// Controller will run this in function a separate goroutine, restarting it\n\t// on error. Platform is expected to deliver network configuration over the channel,\n\t// including updates to the configuration over time.\n\tNetworkConfiguration(context.Context, state.State, chan<- *PlatformNetworkConfig) error\n}\n\n// PlatformNetworkConfig describes the network configuration produced by the platform.\n//\n// This structure is marshaled to STATE partition to persist cached network configuration across\n// reboots.\ntype PlatformNetworkConfig = network.PlatformConfigSpec\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// Runtime defines the runtime parameters.\ntype Runtime interface { //nolint:interfacebloat\n\tConfig() config.Config\n\tConfigContainer() config.Container\n\tConfigCompleteForBoot() bool\n\tRollbackToConfigAfter(time.Duration) error\n\tCancelConfigRollbackTimeout()\n\tSetConfig(config.Provider) error\n\tSetPersistedConfig(config.Provider) error\n\tCanApplyImmediate(config.Provider) error\n\tState() State\n\tEvents() EventStream\n\tLogging() LoggingManager\n\tNodeName() (string, error)\n\tIsBootstrapAllowed() bool\n\tGetSystemInformation(ctx context.Context) (*hardware.SystemInformation, error)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/sequencer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// Sequence represents a sequence type.\ntype Sequence int\n\nconst (\n\t// SequenceNoop is the noop sequence.\n\tSequenceNoop Sequence = iota\n\t// SequenceBoot is the boot sequence.\n\tSequenceBoot\n\t// SequenceInitialize is the initialize sequence.\n\tSequenceInitialize\n\t// SequenceInstall is the install sequence.\n\tSequenceInstall\n\t// SequenceShutdown is the shutdown sequence.\n\tSequenceShutdown\n\t// SequenceUpgrade is the upgrade sequence.\n\tSequenceUpgrade\n\t// SequenceStageUpgrade is the stage upgrade sequence.\n\tSequenceStageUpgrade\n\t// SequenceMaintenanceUpgrade is the upgrade sequence in maintenance mode.\n\tSequenceMaintenanceUpgrade\n\t// SequenceReset is the reset sequence.\n\tSequenceReset\n\t// SequenceReboot is the reboot sequence.\n\tSequenceReboot\n)\n\nconst (\n\tboot               = \"boot\"\n\tinitialize         = \"initialize\"\n\tinstall            = \"install\"\n\tshutdown           = \"shutdown\"\n\tupgrade            = \"upgrade\"\n\tstageUpgrade       = \"stageUpgrade\"\n\tmaintenanceUpgrade = \"maintenanceUpgrade\"\n\treset              = \"reset\"\n\treboot             = \"reboot\"\n\tnoop               = \"noop\"\n)\n\nvar sequenceTakeOver = map[Sequence]map[Sequence]struct{}{\n\tSequenceInitialize: {\n\t\tSequenceMaintenanceUpgrade: {},\n\t},\n\tSequenceBoot: {\n\t\tSequenceReboot:  {},\n\t\tSequenceReset:   {},\n\t\tSequenceUpgrade: {},\n\t},\n\tSequenceReboot: {\n\t\tSequenceReboot: {},\n\t},\n\tSequenceReset: {\n\t\tSequenceReboot: {},\n\t},\n}\n\n// String returns the string representation of a `Sequence`.\nfunc (s Sequence) String() string {\n\treturn [...]string{noop, boot, initialize, install, shutdown, upgrade, stageUpgrade, maintenanceUpgrade, reset, reboot}[s]\n}\n\n// CanTakeOver defines sequences priority.\n//\n// | what is running (columns) what is requested (rows) | boot | reboot | reset | upgrade |\n// |----------------------------------------------------|------|--------|-------|---------|\n// | reboot                                             | Y    | Y      | Y     | N       |\n// | reset                                              | Y    | N      | N     | N       |\n// | upgrade                                            | Y    | N      | N     | N       |.\nfunc (s Sequence) CanTakeOver(running Sequence) bool {\n\tif running == SequenceNoop {\n\t\treturn true\n\t}\n\n\tif sequences, ok := sequenceTakeOver[running]; ok {\n\t\tif _, ok = sequences[s]; ok {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// ParseSequence returns a `Sequence` that matches the specified string.\n//\n//nolint:gocyclo\nfunc ParseSequence(s string) (seq Sequence, err error) {\n\tswitch s {\n\tcase boot:\n\t\tseq = SequenceBoot\n\tcase initialize:\n\t\tseq = SequenceInitialize\n\tcase install:\n\t\tseq = SequenceInstall\n\tcase shutdown:\n\t\tseq = SequenceShutdown\n\tcase upgrade:\n\t\tseq = SequenceUpgrade\n\tcase stageUpgrade:\n\t\tseq = SequenceStageUpgrade\n\tcase maintenanceUpgrade:\n\t\tseq = SequenceMaintenanceUpgrade\n\tcase reset:\n\t\tseq = SequenceReset\n\tcase reboot:\n\t\tseq = SequenceReboot\n\tcase noop:\n\t\tseq = SequenceNoop\n\tdefault:\n\t\treturn seq, fmt.Errorf(\"unknown runtime sequence: %q\", s)\n\t}\n\n\treturn seq, nil\n}\n\n// ResetOptions are parameters to Reset sequence.\ntype ResetOptions interface {\n\tGetGraceful() bool\n\tGetReboot() bool\n\tGetMode() machine.ResetRequest_WipeMode\n\tGetUserDisksToWipe() []string\n\tGetSystemDiskTargets() []PartitionTarget\n\tGetSystemDiskPaths() []string\n}\n\n// PartitionTarget provides interface to the disk partition.\ntype PartitionTarget interface {\n\tWipe(context.Context, func(string, ...any)) error\n\tGetLabel() string\n}\n\n// Sequencer describes the set of sequences required for the lifecycle\n// management of the operating system.\ntype Sequencer interface {\n\tBoot(Runtime) []Phase\n\tInitialize(Runtime) []Phase\n\tInstall(Runtime) []Phase\n\tReboot(Runtime, *machine.RebootRequest) []Phase\n\tReset(Runtime, ResetOptions) []Phase\n\tShutdown(Runtime, *machine.ShutdownRequest) []Phase\n\tStageUpgrade(Runtime, *machine.UpgradeRequest) []Phase\n\tUpgrade(Runtime, *machine.UpgradeRequest) []Phase\n\tMaintenanceUpgrade(Runtime, *machine.UpgradeRequest) []Phase\n}\n\n// EventSequenceStart represents the sequence start event.\ntype EventSequenceStart struct {\n\tSequence Sequence\n}\n\n// EventFatalSequencerError represents a fatal sequencer error.\ntype EventFatalSequencerError struct {\n\tError    error\n\tSequence Sequence\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/sequencer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\nfunc TestSequence_String(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\ts    runtime.Sequence\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"boot\",\n\t\t\ts:    runtime.SequenceBoot,\n\t\t\twant: \"boot\",\n\t\t},\n\t\t{\n\t\t\tname: \"initialize\",\n\t\t\ts:    runtime.SequenceInitialize,\n\t\t\twant: \"initialize\",\n\t\t},\n\t\t{\n\t\t\tname: \"shutdown\",\n\t\t\ts:    runtime.SequenceShutdown,\n\t\t\twant: \"shutdown\",\n\t\t},\n\t\t{\n\t\t\tname: \"upgrade\",\n\t\t\ts:    runtime.SequenceUpgrade,\n\t\t\twant: \"upgrade\",\n\t\t},\n\t\t{\n\t\t\tname: \"stageUpgrade\",\n\t\t\ts:    runtime.SequenceStageUpgrade,\n\t\t\twant: \"stageUpgrade\",\n\t\t},\n\t\t{\n\t\t\tname: \"reboot\",\n\t\t\ts:    runtime.SequenceReboot,\n\t\t\twant: \"reboot\",\n\t\t},\n\t\t{\n\t\t\tname: \"reset\",\n\t\t\ts:    runtime.SequenceReset,\n\t\t\twant: \"reset\",\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 := tt.s.String(); got != tt.want {\n\t\t\t\tt.Errorf(\"Sequence.String() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseSequence(t *testing.T) {\n\ttype args struct {\n\t\ts string\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twantSeq runtime.Sequence\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname:    \"boot\",\n\t\t\targs:    args{\"boot\"},\n\t\t\twantSeq: runtime.SequenceBoot,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"initialize\",\n\t\t\targs:    args{\"initialize\"},\n\t\t\twantSeq: runtime.SequenceInitialize,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"shutdown\",\n\t\t\targs:    args{\"shutdown\"},\n\t\t\twantSeq: runtime.SequenceShutdown,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"upgrade\",\n\t\t\targs:    args{\"upgrade\"},\n\t\t\twantSeq: runtime.SequenceUpgrade,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"stageUpgrade\",\n\t\t\targs:    args{\"stageUpgrade\"},\n\t\t\twantSeq: runtime.SequenceStageUpgrade,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"reboot\",\n\t\t\targs:    args{\"reboot\"},\n\t\t\twantSeq: runtime.SequenceReboot,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"reset\",\n\t\t\targs:    args{\"reset\"},\n\t\t\twantSeq: runtime.SequenceReset,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid\",\n\t\t\targs:    args{\"invalid\"},\n\t\t\twantSeq: 0,\n\t\t\twantErr: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgotSeq, err := runtime.ParseSequence(tt.args.s)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"ParseSequence() error = %v, wantErr %v\", err, tt.wantErr)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif gotSeq != tt.wantSeq {\n\t\t\t\tt.Errorf(\"ParseSequence() = %v, want %v\", gotSeq, tt.wantSeq)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\n\tconfigcore \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n// State defines the state.\ntype State interface {\n\tPlatform() Platform\n\tMachine() MachineState\n\tCluster() ClusterState\n\tV1Alpha2() V1Alpha2State\n}\n\n// Machine defines the runtime parameters.\ntype Machine interface {\n\tState() MachineState\n\tConfig() config.MachineConfig\n}\n\n// MachineState defines the machined state.\ntype MachineState interface {\n\tInstalled() bool\n\tIsInstallStaged() bool\n\tStagedInstallImageRef() string\n\tStagedInstallOptions() []byte\n\tKexecPrepared(bool)\n\tIsKexecPrepared() bool\n\tDBus() DBusState\n\tMeta() Meta\n}\n\n// Meta defines the access to META partition.\ntype Meta interface {\n\tReadTag(t uint8) (val string, ok bool)\n\tReadTagBytes(t uint8) (val []byte, ok bool)\n\tSetTag(ctx context.Context, t uint8, val string) (bool, error)\n\tSetTagBytes(ctx context.Context, t uint8, val []byte) (bool, error)\n\tDeleteTag(ctx context.Context, t uint8) (bool, error)\n\tReload(ctx context.Context) error\n\tFlush() error\n}\n\n// ClusterState defines the cluster state.\ntype ClusterState any\n\n// V1Alpha2State defines the next generation (v2) interface binding into v1 runtime.\ntype V1Alpha2State interface {\n\tResources() state.State\n\n\tNamespaceRegistry() *registry.NamespaceRegistry\n\tResourceRegistry() *registry.ResourceRegistry\n\n\tGetConfig(context.Context) (configcore.Provider, error)\n\tSetConfig(context.Context, string, configcore.Provider) error\n}\n\n// DBusState defines the D-Bus logind mock.\ntype DBusState interface {\n\tStart() error\n\tStop() error\n\tWaitShutdown(ctx context.Context) error\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/acpi/acpi.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage acpi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/mdlayher/genetlink\"\n\t\"github.com/mdlayher/netlink\"\n)\n\nconst (\n\t// PowerButtonEvent is the ACPI event name associated with the power off\n\t// button.\n\tPowerButtonEvent = \"button/power\"\n\t// See https://github.com/torvalds/linux/blob/master/drivers/acpi/event.c\n\tacpiGenlFamilyName     = \"acpi_event\"\n\tacpiGenlMcastGroupName = \"acpi_mc_group\"\n)\n\n// StartACPIListener starts listening for ACPI netlink events.\n//\n//nolint:gocyclo\nfunc StartACPIListener() (err error) {\n\t// Get the acpi_event family.\n\tconn, err := genetlink.Dial(nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tf, err := conn.GetFamily(acpiGenlFamilyName)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\t//nolint:errcheck\n\t\tconn.Close()\n\n\t\treturn fmt.Errorf(acpiGenlFamilyName+\" not available: %w\", err)\n\t}\n\n\tvar id uint32\n\n\tfor _, group := range f.Groups {\n\t\tif group.Name == acpiGenlMcastGroupName {\n\t\t\tid = group.ID\n\t\t}\n\t}\n\n\tif err = conn.JoinGroup(id); err != nil {\n\t\t//nolint:errcheck\n\t\tconn.Close()\n\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer conn.Close()\n\n\tfor {\n\t\tmsgs, _, err := conn.Receive()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error reading from ACPI channel: %w\", err)\n\t\t}\n\n\t\tif len(msgs) > 0 {\n\t\t\tok, err := parse(msgs, PowerButtonEvent)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"failed to parse netlink message: %v\", err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc parse(msgs []genetlink.Message, event string) (bool, error) {\n\tvar result *multierror.Error\n\n\tfor _, msg := range msgs {\n\t\tad, err := netlink.NewAttributeDecoder(msg.Data)\n\t\tif err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"failed to create attribute decoder: %w\", err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tfor ad.Next() {\n\t\t\tif strings.HasPrefix(ad.String(), event) {\n\t\t\t\treturn true, nil\n\t\t\t}\n\n\t\t\tlog.Printf(\"ignoring ACPI event: %q\", ad.String())\n\t\t}\n\t}\n\n\treturn false, result.ErrorOrNil()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/acpi/acpi_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint,testpackage\npackage acpi\n\nimport (\n\t\"testing\"\n\n\t\"github.com/mdlayher/genetlink\"\n)\n\nfunc Test_parse(t *testing.T) {\n\ttype args struct {\n\t\tmsgs  []genetlink.Message\n\t\tevent string\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twant    bool\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: PowerButtonEvent,\n\t\t\targs: args{\n\t\t\t\tmsgs: []genetlink.Message{\n\t\t\t\t\t{\n\t\t\t\t\t\tHeader: genetlink.Header{\n\t\t\t\t\t\t\tCommand: 1,\n\t\t\t\t\t\t\tVersion: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tData: []byte{48, 0, 1, 0, 98, 117, 116, 116, 111, 110, 47, 112, 111, 119, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 76, 78, 88, 80, 87, 82, 66, 78, 58, 48, 48, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 0, 0, 0},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tevent: PowerButtonEvent,\n\t\t\t},\n\t\t\twant:    true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"battery\",\n\t\t\targs: args{\n\t\t\t\tmsgs: []genetlink.Message{\n\t\t\t\t\t{\n\t\t\t\t\t\tHeader: genetlink.Header{\n\t\t\t\t\t\t\tCommand: 1,\n\t\t\t\t\t\t\tVersion: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tData: []byte{48, 0, 1, 0, 98, 117, 116, 116, 111, 110, 47, 112, 111, 119, 101, 114, 0, 0, 0, 0, 0, 0, 0, 0, 76, 78, 88, 80, 87, 82, 66, 78, 58, 48, 48, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 0, 0, 0},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tevent: \"battery\",\n\t\t\t},\n\t\t\twant:    false,\n\t\t\twantErr: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := parse(tt.args.msgs, tt.args.event)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"parse() error = %v, wantErr %v\", err, tt.wantErr)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif got != tt.want {\n\t\t\t\tt.Errorf(\"parse() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package bootloader provides bootloader implementation.\npackage bootloader\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/dual\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/imageropts\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Bootloader describes a bootloader.\ntype Bootloader interface {\n\tGenerateAssets(options options.InstallOptions) ([]partition.Options, error)\n\t// Install the bootloader.\n\t//\n\t// Install mounts the partitions as required.\n\tInstall(options options.InstallOptions) (*options.InstallResult, error)\n\t// Upgrade upgrades the bootloader installation.\n\t//\n\t// Upgrade mounts the partitions as required.\n\tUpgrade(options options.InstallOptions) (*options.InstallResult, error)\n\t// Revert reverts the bootloader entry to the previous state.\n\t//\n\t// Revert mounts the partitions as required.\n\tRevert(disk string) error\n\n\t// KexecLoad does a kexec_file_load using the current entry of the bootloader.\n\tKexecLoad(r runtime.Runtime, disk string) error\n}\n\n// Probe checks if any supported bootloaders are installed.\n//\n// Returns nil if it cannot detect any supported bootloader.\nfunc Probe(disk string, options options.ProbeOptions) (Bootloader, error) {\n\toptions.Logf(\"probing bootloader on %q\", disk)\n\n\tgrubBootloader, err := grub.Probe(disk, options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif grubBootloader != nil {\n\t\toptions.Logf(\"found GRUB bootloader on %q\", disk)\n\n\t\treturn grubBootloader, nil\n\t}\n\n\tsdbootBootloader, err := sdboot.Probe(disk, options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif sdbootBootloader != nil {\n\t\toptions.Logf(\"found sd-boot bootloader on %q\", disk)\n\n\t\treturn sdbootBootloader, nil\n\t}\n\n\treturn nil, os.ErrNotExist\n}\n\n// NewAuto returns a new bootloader based on auto-detection.\nfunc NewAuto() Bootloader {\n\tif sdboot.IsUEFIBoot() {\n\t\treturn sdboot.New()\n\t}\n\n\treturn grub.NewConfig()\n}\n\n// New returns a new bootloader based on the secureboot flag and architecture.\nfunc New(bootloader, talosVersion, arch string) (Bootloader, error) {\n\tswitch bootloader {\n\tcase imageropts.BootLoaderKindGrub.String():\n\t\tg := grub.NewConfig()\n\t\tg.AddResetOption = quirks.New(talosVersion).SupportsResetGRUBOption()\n\n\t\treturn g, nil\n\tcase imageropts.BootLoaderKindSDBoot.String():\n\t\treturn sdboot.New(), nil\n\tcase imageropts.BootLoaderKindDualBoot.String():\n\t\treturn dual.New(), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported bootloader %q\", bootloader)\n\t}\n}\n\n// CleanupBootloader cleans up the alternate bootloader when booting off via BIOS or UEFI.\nfunc CleanupBootloader(disk string, sdboot bool) error {\n\tdev, err := block.NewFromPath(disk, block.OpenForWrite())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer dev.Close() //nolint:errcheck\n\n\tif err := dev.Lock(true); err != nil {\n\t\treturn fmt.Errorf(\"failed to lock device: %w\", err)\n\t}\n\n\tdefer dev.Unlock() //nolint:errcheck\n\n\tgptDev, err := gpt.DeviceFromBlockDevice(dev)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get GPT device: %w\", err)\n\t}\n\n\tgptTable, err := gpt.Read(gptDev)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read GPT: %w\", err)\n\t}\n\n\tif sdboot {\n\t\t// we wipe upto 446 bytes where the protective MBR is located\n\t\tif _, err := dev.WipeRange(0, 446); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to wipe MBR: %w\", err)\n\t\t}\n\n\t\tif err := deletePartitions(gptTable, constants.BIOSGrubPartitionLabel, constants.BootPartitionLabel); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\t// means we are using GRUB\n\t\tif err := deletePartitions(gptTable, constants.EFIPartitionLabel); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := gptTable.Write(); err != nil {\n\t\treturn fmt.Errorf(\"failed to write GPT: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc deletePartitions(gptTable *gpt.Table, labels ...string) error {\n\tfor i, part := range gptTable.Partitions() {\n\t\tif part == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, label := range labels {\n\t\t\tif part.Name == label {\n\t\t\t\tif err := gptTable.DeletePartition(i); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to delete partition %s %d: %w\", part.Name, i, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage bootloader_test\n\nimport (\n\t\"errors\"\n\trandv2 \"math/rand/v2\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/freddierice/go-losetup/v2\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nfunc checkRequirements(t *testing.T) {\n\tt.Helper()\n\n\tif os.Geteuid() != 0 {\n\t\tt.Skip(\"test requires root privileges\")\n\t}\n\n\tif hostname, _ := os.Hostname(); hostname == \"buildkitsandbox\" { //nolint: errcheck\n\t\tt.Skip(\"test not supported under buildkit as partition devices are not propagated from /dev\")\n\t}\n}\n\nfunc losetupAttachHelper(t *testing.T, rawImage string, readonly bool) losetup.Device {\n\tt.Helper()\n\n\tfor range 10 {\n\t\tloDev, err := losetup.Attach(rawImage, 0, readonly)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, unix.EBUSY) {\n\t\t\t\tspraySleep := max(randv2.ExpFloat64(), 2.0)\n\n\t\t\t\tt.Logf(\"retrying after %v seconds\", spraySleep)\n\n\t\t\t\ttime.Sleep(time.Duration(spraySleep * float64(time.Second)))\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\trequire.NoError(t, err)\n\n\t\treturn loDev\n\t}\n\n\tt.Fatal(\"failed to attach loop device\") //nolint:revive\n\n\tpanic(\"unreachable\")\n}\n\nfunc prepareRawImage(t *testing.T, size int64) string {\n\tt.Helper()\n\n\ttmpDir := t.TempDir()\n\n\trawImage := filepath.Join(tmpDir, \"image.raw\")\n\n\tf, err := os.Create(rawImage)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f.Truncate(size))\n\trequire.NoError(t, f.Close())\n\n\tloDev := losetupAttachHelper(t, rawImage, false)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, loDev.Detach())\n\t})\n\n\treturn loDev.Path()\n}\n\nconst mib = 1024 * 1024\n\nfunc TestCleanup(t *testing.T) {\n\tcheckRequirements(t)\n\n\tdisk := prepareRawImage(t, 2*1024*mib)\n\n\tdev, err := block.NewFromPath(disk, block.OpenForWrite())\n\tassert.NoError(t, err)\n\n\tcleanupFunc := sync.OnceValue(dev.Close)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, cleanupFunc())\n\t})\n\n\tgptDev, err := gpt.DeviceFromBlockDevice(dev)\n\tassert.NoError(t, err)\n\n\tpt, err := gpt.New(gptDev, gpt.WithMarkPMBRBootable())\n\tassert.NoError(t, err)\n\n\tquirk := quirks.New(\"\")\n\n\tpartitions := []partition.Options{ //nolint:prealloc // this is a test\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.EFIPartitionLabel)),\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.BIOSGrubPartitionLabel)),\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.BootPartitionLabel)),\n\t}\n\n\tpartitions = append(partitions, partition.NewPartitionOptions(false, quirks.New(\"\"), partition.WithLabel(constants.MetaPartitionLabel)))\n\n\tfor _, p := range partitions {\n\t\tsize := p.Size\n\n\t\tif size == 0 {\n\t\t\tsize = pt.LargestContiguousAllocatable()\n\t\t}\n\n\t\tpartitionTyp := uuid.MustParse(p.PartitionType)\n\n\t\t_, _, err = pt.AllocatePartition(size, p.PartitionLabel, partitionTyp, p.PartitionOpts...)\n\t\tassert.NoError(t, err)\n\t}\n\n\tassert.NoError(t, pt.Write())\n\n\t// close operations on the disk\n\tassert.NoError(t, cleanupFunc())\n\n\tassert.NoError(t, bootloader.CleanupBootloader(disk, false))\n\n\ttestPartitionsWiped(t, disk, []string{constants.BIOSGrubPartitionLabel, constants.BootPartitionLabel, constants.MetaPartitionLabel}, false)\n\n\tassert.NoError(t, bootloader.CleanupBootloader(disk, true))\n\n\ttestPartitionsWiped(t, disk, []string{constants.MetaPartitionLabel}, true)\n}\n\nfunc testPartitionsWiped(t *testing.T, disk string, expectedLabels []string, sdboot bool) {\n\tdev, err := block.NewFromPath(disk)\n\tassert.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, dev.Close())\n\t})\n\n\tgptDev, err := gpt.DeviceFromBlockDevice(dev)\n\tassert.NoError(t, err)\n\n\tpt, err := gpt.Read(gptDev)\n\tassert.NoError(t, err)\n\n\tlabels := xslices.Filter(xslices.Map(pt.Partitions(), func(p *gpt.Partition) string {\n\t\tif p == nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn p.Name\n\t}), func(label string) bool {\n\t\treturn label != \"\"\n\t})\n\n\tassert.Equal(t, expectedLabels, labels)\n\n\tif sdboot {\n\t\tvar mbrData [446]byte\n\n\t\t_, err = dev.File().Read(mbrData[:])\n\t\tassert.NoError(t, err)\n\n\t\tassert.Equal(t, [446]byte{}, mbrData)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/dual/dual.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package dual provides dual-boot bootloader implementation.\npackage dual\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Config describes a dual-boot bootloader.\n// this is a dummy implementation of the bootloader interface\n// allowing to install GRUB for BIOS and sd-boot for UEFI\n// so we only care about `GenerateAssets()`.\ntype Config struct{}\n\n// New creates a new bootloader.\nfunc New() *Config {\n\treturn &Config{}\n}\n\n// GenerateAssets generates the dual-boot bootloader assets and returns the partition options with source directory set.\nfunc (c *Config) GenerateAssets(opts options.InstallOptions) ([]partition.Options, error) {\n\tif opts.Arch == \"arm64\" {\n\t\treturn nil, fmt.Errorf(\"dual-boot bootloader is not supported on arm64 architecture, either GRUB or sd-boot must be used\")\n\t}\n\n\t// here we'll use the grub and sd-boot GenerateAssets logic\n\t// and remove the grub `EFI` directory after we're done\n\tif _, err := grub.NewConfig().GenerateAssets(opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to install GRUB bootloader: %w\", err)\n\t}\n\n\tif err := os.RemoveAll(filepath.Join(opts.MountPrefix, constants.EFIMountPoint)); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to cleanup GRUB EFI assets directory: %w\", err)\n\t}\n\n\tif _, err := sdboot.New().GenerateAssets(opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate sd-boot assets: %w\", err)\n\t}\n\n\tquirk := quirks.New(opts.Version)\n\n\tpartitionOptions := []partition.Options{\n\t\tpartition.NewPartitionOptions(\n\t\t\ttrue,\n\t\t\tquirk,\n\t\t\tpartition.WithLabel(constants.EFIPartitionLabel),\n\t\t\tpartition.WithSourceDirectory(filepath.Join(opts.MountPrefix, \"EFI\")),\n\t\t),\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.BIOSGrubPartitionLabel)),\n\t\tpartition.NewPartitionOptions(\n\t\t\tfalse,\n\t\t\tquirk,\n\t\t\tpartition.WithLabel(constants.BootPartitionLabel),\n\t\t\tpartition.WithSourceDirectory(filepath.Join(opts.MountPrefix, constants.BootMountPoint)),\n\t\t),\n\t}\n\n\tif opts.ImageMode {\n\t\tpartitionOptions = xslices.Map(partitionOptions, func(o partition.Options) partition.Options {\n\t\t\to.Reproducible = true\n\n\t\t\treturn o\n\t\t})\n\t}\n\n\treturn partitionOptions, nil\n}\n\n// Install installs the bootloader.\nfunc (c *Config) Install(opts options.InstallOptions) (*options.InstallResult, error) {\n\treturn nil, fmt.Errorf(\"dual-boot bootloader is only supported in image mode, installation is not implemented\")\n}\n\n// Upgrade is not implemented since dual-boot is only supported in image mode.\nfunc (c *Config) Upgrade(opts options.InstallOptions) (*options.InstallResult, error) {\n\treturn nil, fmt.Errorf(\"dual-boot bootloader is only supported in image mode, upgrade is not implemented\")\n}\n\n// Revert is not implemented.\nfunc (c *Config) Revert(disk string) error {\n\treturn fmt.Errorf(\"dual-boot bootloader is only supported in image mode, revert is not implemented\")\n}\n\n// KexecLoad is not implemented.\nfunc (c *Config) KexecLoad(r runtime.Runtime, disk string) error {\n\treturn fmt.Errorf(\"dual-boot bootloader is only supported in image mode, kexec load is not implemented\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/efiutils/efiutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package efiutils provides common bootloader utils.\npackage efiutils\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n)\n\n// Name returns the standard EFI file path for the given architecture.\nfunc Name(arch string) (string, error) {\n\tbasePath := filepath.Join(\"EFI\", \"boot\")\n\n\tswitch arch {\n\tcase \"amd64\":\n\t\treturn filepath.Join(basePath, \"BOOTX64.efi\"), nil\n\tcase \"arm64\":\n\t\treturn filepath.Join(basePath, \"BOOTAA64.efi\"), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported architecture: %s\", arch)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/blocklist.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// PatchBlocklistsForDiskImage patches the GRUB boot.img and core.img with blocklist information\n// for GPT+BIOS boot. This should be called after the disk partition layout is finalized.\n//\n// References (GRUB source tree inside orb VM):\n// - grub-core/boot/i386/pc/boot.S: defines GRUB_BOOT_MACHINE_KERNEL_SECTOR and MBR code\n// - include/grub/i386/pc/boot.h: GRUB_BOOT_MACHINE_KERNEL_SECTOR == 0x5c\n// - util/setup.c: write_rootdev() patches boot.img fields and writes sector in LE64\n// - core image embedded blocklist continuation at core.img offset 0x1F4.\nfunc PatchBlocklistsForDiskImage(sectorSize uint, biosBootStartSector uint64, mountPrefix string) error {\n\tif sectorSize == 0 {\n\t\treturn fmt.Errorf(\"sector size must be set to patch GRUB blocklists\")\n\t}\n\n\t// Talos partition layout (GPT): EFI (gpt1, efiPartitionSizeBytes), BIOS (gpt2, 1MiB), BOOT (gpt3)\n\t// BIOS boot partition starts immediately after the EFI partition.\n\tconst (\n\t\tbootImgKernelSectorOffset = 0x5c  // include/grub/i386/pc/boot.h (GRUB_BOOT_MACHINE_KERNEL_SECTOR)\n\t\tbootImgJumpOffset         = 0x66  // patched to NOP NOP (0x90 0x90) by grub-install on GPT\n\t\tcoreImgBlocklistOffset    = 0x1f4 // embedded blocklist continuation inside core.img\n\t)\n\n\tbootImgPath := filepath.Join(mountPrefix, \"boot.img\")\n\tcoreImgPath := filepath.Join(mountPrefix, \"core.img\")\n\n\tbootImg, err := os.ReadFile(bootImgPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read boot.img: %w\", err)\n\t}\n\n\t// validate bootImgKernelSectorOffset and bootImgJumpOffset can be patched into bootImg\n\tif len(bootImg) < bootImgKernelSectorOffset+8 {\n\t\treturn fmt.Errorf(\"boot.img is too small (%d bytes) to patch kernel sector offset at 0x%x\", len(bootImg), bootImgKernelSectorOffset)\n\t}\n\n\tif len(bootImg) < bootImgJumpOffset+2 {\n\t\treturn fmt.Errorf(\"boot.img is too small (%d bytes) to patch jump offset at 0x%x\", len(bootImg), bootImgJumpOffset)\n\t}\n\n\t// Patch 1: tell boot.img where to find core.img (LE64 sector number at 0x5C)\n\tbinary.LittleEndian.PutUint64(bootImg[bootImgKernelSectorOffset:], biosBootStartSector)\n\n\t// Patch 2: NOP the short jump at 0x66 for GPT installs (matches grub-install behavior)\n\tbootImg[bootImgJumpOffset] = 0x90\n\tbootImg[bootImgJumpOffset+1] = 0x90\n\n\tif err := os.WriteFile(bootImgPath, bootImg, 0o644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write patched boot.img: %w\", err)\n\t}\n\n\tcoreImg, err := os.ReadFile(coreImgPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read core.img: %w\", err)\n\t}\n\n\t// validate coreImgBlocklistOffset can be patched into coreImg\n\tif len(coreImg) < coreImgBlocklistOffset+8 {\n\t\treturn fmt.Errorf(\"core.img is too small (%d bytes) to patch blocklist offset at 0x%x\", len(coreImg), coreImgBlocklistOffset)\n\t}\n\n\t// Patch 3: core.img embedded blocklist continuation (LE64) points to start+1\n\t//\n\t// The boot.img only loads the first sector of core.img, so the embedded blocklist\n\t// continuation must point to the second sector of core.img.\n\tbinary.LittleEndian.PutUint64(coreImg[coreImgBlocklistOffset:], biosBootStartSector+1)\n\n\tif err := os.WriteFile(coreImgPath, coreImg, 0o644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write patched core.img: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/boot_label.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// flipBootLabel flips the boot label.\nfunc flipBootLabel(e BootLabel) (BootLabel, error) {\n\tswitch e {\n\tcase BootA:\n\t\treturn BootB, nil\n\tcase BootB:\n\t\treturn BootA, nil\n\tcase BootReset:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"invalid entry: %s\", e)\n\t}\n}\n\n// Flip flips the default boot label.\nfunc (c *Config) flip() error {\n\tif _, exists := c.Entries[c.Default]; !exists {\n\t\treturn nil\n\t}\n\n\tcurrent := c.Default\n\n\tnext, err := flipBootLabel(c.Default)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.Default = next\n\tc.Fallback = current\n\n\treturn nil\n}\n\n// ParseBootLabel parses the given human-readable boot label to a BootLabel.\nfunc ParseBootLabel(name string) (BootLabel, error) {\n\tswitch {\n\tcase strings.HasPrefix(name, string(BootA)):\n\t\treturn BootA, nil\n\tcase strings.HasPrefix(name, string(BootB)):\n\t\treturn BootB, nil\n\tcase strings.HasPrefix(name, \"Reset\"):\n\t\treturn BootReset, nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"could not parse boot entry from name: %s\", name)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// BootLabel represents a boot label, e.g. A or B.\ntype BootLabel string\n\nconst (\n\t// ConfigPath is the path to the grub config.\n\tConfigPath = constants.BootMountPoint + \"/grub/grub.cfg\"\n\t// BootA is a bootloader label.\n\tBootA BootLabel = \"A\"\n\t// BootB is a bootloader label.\n\tBootB BootLabel = \"B\"\n\t// BootReset is a bootloader label.\n\tBootReset BootLabel = \"Reset\"\n)\n\nconst (\n\tbootloaderNotInstalled = \"bootloader not installed\"\n)\n\ntype bootloaderNotInstalledError struct{}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/decode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n)\n\nvar (\n\tdefaultEntryRegex  = regexp.MustCompile(`(?m)^\\s*set default=\"(.*)\"\\s*$`)\n\tfallbackEntryRegex = regexp.MustCompile(`(?m)^\\s*set fallback=\"(.*)\"\\s*$`)\n\tmenuEntryRegex     = regexp.MustCompile(`(?ms)^menuentry\\s+\"(.+?)\" {(.+?)[^\\\\]}`)\n\tlinuxRegex         = regexp.MustCompile(`(?m)^\\s*linux\\s+(.+?)\\s+(.*)$`)\n\tinitrdRegex        = regexp.MustCompile(`(?m)^\\s*initrd\\s+(.+)$`)\n)\n\n// Read reads the grub configuration from the disk.\nfunc Read(path string) (*Config, error) {\n\tc, err := os.ReadFile(path)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn nil, nil\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn Decode(c)\n}\n\n// Decode parses the grub configuration from the given bytes.\nfunc Decode(c []byte) (*Config, error) {\n\tdefaultEntryMatches := defaultEntryRegex.FindAllSubmatch(c, -1)\n\tif len(defaultEntryMatches) != 1 {\n\t\treturn nil, errors.New(\"failed to find default\")\n\t}\n\n\tfallbackEntryMatches := fallbackEntryRegex.FindAllSubmatch(c, -1)\n\tif len(fallbackEntryMatches) > 1 {\n\t\treturn nil, errors.New(\"found multiple fallback entries\")\n\t}\n\n\tvar fallbackEntry BootLabel\n\n\tif len(fallbackEntryMatches) == 1 {\n\t\tif len(fallbackEntryMatches[0]) != 2 {\n\t\t\treturn nil, errors.New(\"failed to parse fallback entry\")\n\t\t}\n\n\t\tentry, err := ParseBootLabel(string(fallbackEntryMatches[0][1]))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfallbackEntry = entry\n\t}\n\n\tif len(defaultEntryMatches[0]) != 2 {\n\t\treturn nil, fmt.Errorf(\"default entry: expected 2 matches, got %d\", len(defaultEntryMatches[0]))\n\t}\n\n\tdefaultEntry, err := ParseBootLabel(string(defaultEntryMatches[0][1]))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tentries, hasResetOption, err := parseEntries(c)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconf := Config{\n\t\tDefault:        defaultEntry,\n\t\tFallback:       fallbackEntry,\n\t\tEntries:        entries,\n\t\tAddResetOption: hasResetOption,\n\t}\n\n\treturn &conf, nil\n}\n\nfunc parseEntries(conf []byte) (map[BootLabel]MenuEntry, bool, error) {\n\tentries := make(map[BootLabel]MenuEntry)\n\thasResetOption := false\n\n\tmatches := menuEntryRegex.FindAllSubmatch(conf, -1)\n\tfor _, m := range matches {\n\t\tif len(m) != 3 {\n\t\t\treturn nil, false, fmt.Errorf(\"conf block: expected 3 matches, got %d\", len(m))\n\t\t}\n\n\t\tconfBlock := m[2]\n\n\t\tlinux, cmdline, initrd, err := parseConfBlock(confBlock)\n\t\tif err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\n\t\tname := string(m[1])\n\n\t\tbootEntry, err := ParseBootLabel(name)\n\t\tif err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\n\t\tif bootEntry == BootReset {\n\t\t\thasResetOption = true\n\n\t\t\tcontinue\n\t\t}\n\n\t\tentries[bootEntry] = MenuEntry{\n\t\t\tName:    name,\n\t\t\tLinux:   linux,\n\t\t\tCmdline: cmdline,\n\t\t\tInitrd:  initrd,\n\t\t}\n\t}\n\n\treturn entries, hasResetOption, nil\n}\n\nfunc parseConfBlock(block []byte) (linux, cmdline, initrd string, err error) {\n\tblock = []byte(Unquote(string(block)))\n\n\tlinuxMatches := linuxRegex.FindAllSubmatch(block, -1)\n\tif len(linuxMatches) != 1 {\n\t\treturn \"\", \"\", \"\",\n\t\t\tfmt.Errorf(\"linux: expected 1 match, got %d\", len(linuxMatches))\n\t}\n\n\tif len(linuxMatches[0]) != 3 {\n\t\treturn \"\", \"\", \"\",\n\t\t\tfmt.Errorf(\"linux: expected 3 matches, got %d\", len(linuxMatches[0]))\n\t}\n\n\tlinux = string(linuxMatches[0][1])\n\tcmdline = string(linuxMatches[0][2])\n\n\tinitrdMatches := initrdRegex.FindAllSubmatch(block, -1)\n\tif len(initrdMatches) != 1 {\n\t\treturn \"\", \"\", \"\",\n\t\t\tfmt.Errorf(\"initrd: expected 1 match, got %d: %s\", len(initrdMatches), string(block))\n\t}\n\n\tif len(initrdMatches[0]) != 2 {\n\t\treturn \"\", \"\", \"\",\n\t\t\tfmt.Errorf(\"initrd: expected 2 matches, got %d\", len(initrdMatches[0]))\n\t}\n\n\tinitrd = string(initrdMatches[0][1])\n\n\treturn linux, cmdline, initrd, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/encode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// Write the grub configuration to the given file.\nfunc (c *Config) Write(path string, printf func(string, ...any)) error {\n\tdir := filepath.Dir(path)\n\tif err := os.MkdirAll(dir, 0o700); err != nil {\n\t\treturn err\n\t}\n\n\twr := new(bytes.Buffer)\n\n\terr := c.Encode(wr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprintf(\"writing %s to disk\", path)\n\n\treturn os.WriteFile(path, wr.Bytes(), 0o600)\n}\n\n// Encode writes the grub configuration to the given writer.\nfunc (c *Config) Encode(wr io.Writer) error {\n\tif err := c.validate(); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintf(wr, \"set default=\\\"%s\\\"\\n\", c.Entries[c.Default].Name)\n\n\tif fallback, ok := c.Entries[c.Fallback]; ok {\n\t\tfmt.Fprintf(wr, \"set fallback=\\\"%s\\\"\\n\", fallback.Name)\n\t}\n\n\tfmt.Fprint(wr, `\nset timeout=3\n\ninsmod all_video\n\nterminal_input console\nterminal_output console\n\n`)\n\n\tfor _, entry := range c.Entries {\n\t\tfmt.Fprintf(wr, `menuentry \"%s\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux %s %s\n  initrd %s\n}\n`, entry.Name, entry.Linux, Quote(entry.Cmdline), entry.Initrd)\n\t}\n\n\tif c.AddResetOption {\n\t\tdefaultEntry := c.Entries[c.Default]\n\n\t\tfmt.Fprintf(wr, `menuentry \"Reset Talos installation and return to maintenance mode\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux %s %s talos.experimental.wipe=system:EPHEMERAL,STATE\n  initrd %s\n}\n`, defaultEntry.Linux, Quote(defaultEntry.Cmdline), defaultEntry.Initrd)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package grub provides the interface to the GRUB bootloader: config management, installation, etc.\npackage grub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/kexec\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// Config represents a grub configuration file (grub.cfg).\ntype Config struct {\n\tDefault        BootLabel\n\tFallback       BootLabel\n\tEntries        map[BootLabel]MenuEntry\n\tAddResetOption bool\n}\n\n// MenuEntry represents a grub menu entry in the grub config file.\ntype MenuEntry struct {\n\tName    string\n\tLinux   string\n\tCmdline string\n\tInitrd  string\n}\n\nfunc (e bootloaderNotInstalledError) Error() string {\n\treturn bootloaderNotInstalled\n}\n\n// NewConfig creates a new grub configuration (nothing is written to disk).\nfunc NewConfig() *Config {\n\treturn &Config{\n\t\tDefault:        BootA,\n\t\tEntries:        map[BootLabel]MenuEntry{},\n\t\tAddResetOption: true,\n\t}\n}\n\n// KexecLoad does a kexec using the bootloader config.\nfunc (c *Config) KexecLoad(r runtime.Runtime, disk string) error {\n\t_, err := ProbeWithCallback(disk, options.ProbeOptions{}, func(grubConf *Config) error {\n\t\tdefaultEntry, ok := grubConf.Entries[grubConf.Default]\n\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\n\t\tkernelPath := filepath.Join(constants.BootMountPoint, defaultEntry.Linux)\n\t\tinitrdPath := filepath.Join(constants.BootMountPoint, defaultEntry.Initrd)\n\n\t\tkernel, err := os.Open(kernelPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer kernel.Close() //nolint:errcheck\n\n\t\tinitrd, err := os.Open(initrdPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer initrd.Close() //nolint:errcheck\n\n\t\tcmdline := strings.TrimSpace(defaultEntry.Cmdline)\n\n\t\tif err = kexec.Load(r, kernel, int(initrd.Fd()), cmdline); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlog.Printf(\"prepared kexec environment kernel=%q initrd=%q cmdline=%q\", kernelPath, initrdPath, cmdline)\n\n\t\treturn nil\n\t})\n\n\treturn err\n}\n\n// GenerateAssets generates the bootloader assets and returns partition options to create the bootloader partitions.\nfunc (c *Config) GenerateAssets(opts options.InstallOptions) ([]partition.Options, error) {\n\tif err := c.generateAssets(opts); err != nil {\n\t\treturn nil, err\n\t}\n\n\tquirk := quirks.New(opts.Version)\n\n\tefiFormatOptions := []partition.FormatOption{\n\t\tpartition.WithLabel(constants.EFIPartitionLabel),\n\t}\n\n\tif opts.ImageMode {\n\t\t// in bios install mode grub generated assets only contains the grub config file and kernel and initramfs\n\t\t// so we don't need to set the source directory for the EFI partition\n\t\tefiFormatOptions = append(\n\t\t\tefiFormatOptions,\n\t\t\tpartition.WithSourceDirectory(filepath.Join(opts.MountPrefix, \"EFI\")),\n\t\t)\n\t}\n\n\tpartitionOptions := []partition.Options{\n\t\tpartition.NewPartitionOptions(\n\t\t\tfalse,\n\t\t\tquirk,\n\t\t\tefiFormatOptions...,\n\t\t),\n\t\tpartition.NewPartitionOptions(false, quirk, partition.WithLabel(constants.BIOSGrubPartitionLabel)),\n\t\tpartition.NewPartitionOptions(\n\t\t\tfalse,\n\t\t\tquirk,\n\t\t\tpartition.WithLabel(constants.BootPartitionLabel),\n\t\t\tpartition.WithSourceDirectory(filepath.Join(opts.MountPrefix, constants.BootMountPoint)),\n\t\t),\n\t}\n\n\tif opts.ImageMode {\n\t\tpartitionOptions = xslices.Map(partitionOptions, func(o partition.Options) partition.Options {\n\t\t\to.Reproducible = true\n\n\t\t\treturn o\n\t\t})\n\t}\n\n\tif opts.ExtraInstallStep != nil {\n\t\tif err := opts.ExtraInstallStep(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn partitionOptions, nil\n}\n\n// Put puts a new menu entry to the grub config (nothing is written to disk).\nfunc (c *Config) Put(entry BootLabel, cmdline, version string) error {\n\tc.Entries[entry] = buildMenuEntry(entry, cmdline, version)\n\n\treturn nil\n}\n\nfunc (c *Config) validate() error {\n\tif _, ok := c.Entries[c.Default]; !ok {\n\t\treturn fmt.Errorf(\"invalid default entry: %s\", c.Default)\n\t}\n\n\tif c.Fallback != \"\" {\n\t\tif _, ok := c.Entries[c.Fallback]; !ok {\n\t\t\treturn fmt.Errorf(\"invalid fallback entry: %s\", c.Fallback)\n\t\t}\n\t}\n\n\tif c.Default == c.Fallback {\n\t\treturn errors.New(\"default and fallback entries must not be the same\")\n\t}\n\n\treturn nil\n}\n\nfunc buildMenuEntry(entry BootLabel, cmdline, versionTag string) MenuEntry {\n\treturn MenuEntry{\n\t\tName:    fmt.Sprintf(\"%s - %s %s\", entry, version.Name, versionTag),\n\t\tLinux:   filepath.Join(\"/\", string(entry), constants.KernelAsset),\n\t\tCmdline: cmdline,\n\t\tInitrd:  filepath.Join(\"/\", string(entry), constants.InitramfsAsset),\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub_test\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nvar (\n\t//go:embed testdata/grub_parse_test.cfg\n\tgrubCfg []byte\n\n\t//go:embed testdata/grub_write_test.cfg\n\tnewConfig string\n\n\t//go:embed testdata/grub_write_no_reset_test.cfg\n\tnewNoResetConfig string\n)\n\nfunc TestDecode(t *testing.T) {\n\tconf, err := grub.Decode(grubCfg)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, grub.BootA, conf.Default)\n\tassert.Equal(t, grub.BootB, conf.Fallback)\n\n\tassert.Len(t, conf.Entries, 2)\n\n\ta := conf.Entries[grub.BootA]\n\tassert.Equal(t, \"A - v1\", a.Name)\n\tassert.True(t, strings.HasPrefix(a.Linux, \"/A/\"))\n\tassert.True(t, strings.HasPrefix(a.Initrd, \"/A/\"))\n\tassert.Equal(t, \"cmdline A\", a.Cmdline)\n\n\tb := conf.Entries[grub.BootB]\n\tassert.Equal(t, \"B - v2\", b.Name)\n\tassert.Equal(t, \"cmdline B\", b.Cmdline)\n\tassert.True(t, strings.HasPrefix(b.Linux, \"/B/\"))\n\tassert.True(t, strings.HasPrefix(b.Initrd, \"/B/\"))\n\n\tassert.True(t, conf.AddResetOption)\n}\n\nfunc TestEncodeDecode(t *testing.T) {\n\tconfig := grub.NewConfig()\n\trequire.NoError(t, config.Put(grub.BootA, \"talos.platform=metal talos.config=https://my-metadata.server/talos/config?hostname=${hostname}&mac=${mac}\", \"v1.2.3\"))\n\trequire.NoError(t, config.Put(grub.BootB, \"talos.platform=metal talos.config=https://my-metadata.server/talos/config?uuid=${uuid}\", \"v1.3.4\"))\n\n\tvar b bytes.Buffer\n\n\trequire.NoError(t, config.Encode(&b))\n\n\tt.Logf(\"config encoded to:\\n%s\", b.String())\n\n\tconfig2, err := grub.Decode(b.Bytes())\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, config, config2)\n}\n\nfunc TestParseBootLabel(t *testing.T) {\n\tlabel, err := grub.ParseBootLabel(\"A - v1\")\n\tassert.NoError(t, err)\n\tassert.Equal(t, grub.BootA, label)\n\n\tlabel, err = grub.ParseBootLabel(\"B - v2\")\n\tassert.NoError(t, err)\n\tassert.Equal(t, grub.BootB, label)\n\n\tlabel, err = grub.ParseBootLabel(\"Reset Talos installation and return to maintenance mode\\n\")\n\tassert.NoError(t, err)\n\tassert.Equal(t, grub.BootReset, label)\n\n\t_, err = grub.ParseBootLabel(\"C - v3\")\n\tassert.Error(t, err)\n}\n\n//nolint:errcheck\nfunc TestWrite(t *testing.T) {\n\toldName := version.Name\n\n\tt.Cleanup(func() {\n\t\tversion.Name = oldName\n\t})\n\n\tversion.Name = \"Test\"\n\n\ttempFile, _ := os.CreateTemp(t.TempDir(), \"talos-test-grub-*.cfg\")\n\n\tconfig := grub.NewConfig()\n\trequire.NoError(t, config.Put(grub.BootA, \"cmdline A\", \"v0.0.1\"))\n\n\terr := config.Write(tempFile.Name(), t.Logf)\n\tassert.NoError(t, err)\n\n\twritten, _ := os.ReadFile(tempFile.Name())\n\tassert.Equal(t, newConfig, string(written))\n}\n\n//nolint:errcheck\nfunc TestWriteNoReset(t *testing.T) {\n\toldName := version.Name\n\n\tt.Cleanup(func() {\n\t\tversion.Name = oldName\n\t})\n\n\tversion.Name = \"TestOld\"\n\n\ttempFile, _ := os.CreateTemp(t.TempDir(), \"talos-test-grub-*.cfg\")\n\n\tconfig := grub.NewConfig()\n\tconfig.AddResetOption = false\n\trequire.NoError(t, config.Put(grub.BootA, \"cmdline A\", \"v0.0.1\"))\n\n\terr := config.Write(tempFile.Name(), t.Logf)\n\tassert.NoError(t, err)\n\n\twritten, _ := os.ReadFile(tempFile.Name())\n\tassert.Equal(t, newNoResetConfig, string(written))\n}\n\nfunc TestPut(t *testing.T) {\n\tconfig := grub.NewConfig()\n\trequire.NoError(t, config.Put(grub.BootA, \"cmdline A\", \"v1.2.3\"))\n\n\terr := config.Put(grub.BootB, \"cmdline B\", \"v1.0.0\")\n\n\tassert.NoError(t, err)\n\n\tassert.Len(t, config.Entries, 2)\n\tassert.Equal(t, \"cmdline B\", config.Entries[grub.BootB].Cmdline)\n\n\terr = config.Put(grub.BootA, \"cmdline A 2\", \"v1.3.4\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"cmdline A 2\", config.Entries[grub.BootA].Cmdline)\n}\n\n//nolint:errcheck\nfunc TestFallback(t *testing.T) {\n\tconfig := grub.NewConfig()\n\trequire.NoError(t, config.Put(grub.BootA, \"cmdline A\", \"v1.0.0\"))\n\n\t_ = config.Put(grub.BootB, \"cmdline B\", \"1.2.0\")\n\n\tconfig.Fallback = grub.BootB\n\n\tvar buf bytes.Buffer\n\n\t_ = config.Encode(&buf)\n\n\tresult := buf.String()\n\n\tassert.Contains(t, result, `set fallback=\"B - `)\n\n\tbuf.Reset()\n\n\tconfig.Fallback = \"\"\n\t_ = config.Encode(&buf)\n\n\tresult = buf.String()\n\tassert.NotContains(t, result, \"set fallback\")\n}\n\ntype bootEntry struct {\n\tLinux   string\n\tInitrd  string\n\tCmdline string\n}\n\n// oldParser is the kexec parser used before the GRUB parser was rewritten.\n//\n// This makes sure Talos 0.14 can kexec into newly written GRUB config.\n//\n//nolint:gocyclo\nfunc oldParser(r io.Reader) (*bootEntry, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tentry := &bootEntry{}\n\n\tvar (\n\t\tdefaultEntry string\n\t\tcurrentEntry string\n\t)\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tswitch {\n\t\tcase strings.HasPrefix(line, \"set default\"):\n\t\t\tmatches := regexp.MustCompile(`set default=\"(.*)\"`).FindStringSubmatch(line)\n\t\t\tif len(matches) != 2 {\n\t\t\t\treturn nil, fmt.Errorf(\"malformed default entry: %q\", line)\n\t\t\t}\n\n\t\t\tdefaultEntry = matches[1]\n\t\tcase strings.HasPrefix(line, \"menuentry\"):\n\t\t\tmatches := regexp.MustCompile(`menuentry \"(.*)\"`).FindStringSubmatch(line)\n\t\t\tif len(matches) != 2 {\n\t\t\t\treturn nil, fmt.Errorf(\"malformed menuentry: %q\", line)\n\t\t\t}\n\n\t\t\tcurrentEntry = matches[1]\n\t\tcase strings.HasPrefix(line, \"  linux \"):\n\t\t\tif currentEntry != defaultEntry {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tparts := strings.SplitN(line[8:], \" \", 2)\n\n\t\t\tentry.Linux = parts[0]\n\t\t\tif len(parts) == 2 {\n\t\t\t\tentry.Cmdline = parts[1]\n\t\t\t}\n\t\tcase strings.HasPrefix(line, \"  initrd \"):\n\t\t\tif currentEntry != defaultEntry {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tentry.Initrd = line[9:]\n\t\t}\n\t}\n\n\tif entry.Linux == \"\" || entry.Initrd == \"\" {\n\t\treturn nil, scanner.Err()\n\t}\n\n\treturn entry, scanner.Err()\n}\n\nfunc TestBackwardsCompat(t *testing.T) {\n\toldName := version.Name\n\n\tt.Cleanup(func() {\n\t\tversion.Name = oldName\n\t})\n\n\tversion.Name = \"Test\"\n\n\tvar buf bytes.Buffer\n\n\tconfig := grub.NewConfig()\n\trequire.NoError(t, config.Put(grub.BootA, \"cmdline A\", \"v0.0.1\"))\n\trequire.NoError(t, config.Put(grub.BootB, \"cmdline B\", \"v0.0.1\"))\n\tconfig.Default = grub.BootB\n\n\terr := config.Encode(&buf)\n\tassert.NoError(t, err)\n\n\tentry, err := oldParser(&buf)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &bootEntry{\n\t\tLinux:   \"/B/vmlinuz\",\n\t\tInitrd:  \"/B/initramfs.xz\",\n\t\tCmdline: \"cmdline B\",\n\t}, entry)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\tbootloaderutils \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/efiutils\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/internal/pkg/smbios\"\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tamd64 = \"amd64\"\n\tarm64 = \"arm64\"\n)\n\n// Install validates the grub configuration and writes it to the disk.\nfunc (c *Config) Install(opts options.InstallOptions) (*options.InstallResult, error) {\n\tmountSpecs := []mount.Spec{\n\t\t{\n\t\t\tPartitionLabel: constants.BootPartitionLabel,\n\t\t\tFilesystemType: partition.FilesystemTypeXFS,\n\t\t\tMountTarget:    filepath.Join(opts.MountPrefix, constants.BootMountPoint),\n\t\t},\n\t}\n\n\tefiMountSpec := mount.Spec{\n\t\tPartitionLabel: constants.EFIPartitionLabel,\n\t\tFilesystemType: partition.FilesystemTypeVFAT,\n\t\tMountTarget:    filepath.Join(opts.MountPrefix, constants.EFIMountPoint),\n\t}\n\n\tvar efiFound bool\n\n\t// check if the EFI partition is present\n\tif err := mount.PartitionOp(\n\t\topts.BootDisk,\n\t\t[]mount.Spec{efiMountSpec},\n\t\tfunc() error {\n\t\t\treturn nil\n\t\t},\n\t\t[]blkid.ProbeOption{\n\t\t\tblkid.WithSkipLocking(true),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\topts.BlkidInfo,\n\t); err == nil {\n\t\tefiFound = true\n\t}\n\n\tif efiFound {\n\t\tmountSpecs = append(mountSpecs, efiMountSpec)\n\t}\n\n\terr := mount.PartitionOp(\n\t\topts.BootDisk,\n\t\tmountSpecs,\n\t\tfunc() error {\n\t\t\tif err := c.runGrubInstall(context.Background(), opts, efiFound); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\t[]blkid.ProbeOption{\n\t\t\t// installation happens with locked blockdevice\n\t\t\tblkid.WithSkipLocking(true),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\topts.BlkidInfo,\n\t)\n\n\treturn &options.InstallResult{\n\t\tPreviousLabel: string(c.Fallback),\n\t}, err\n}\n\nfunc (c *Config) generateGrubImage(ctx context.Context, opts options.InstallOptions) error {\n\tvar copyInstructions []utils.CopyInstruction\n\n\tgrubSourceDirectory := \"/usr/lib/grub\"\n\n\tgrubModules := []string{\n\t\t\"part_gpt\",\n\t\t\"ext2\",\n\t\t\"fat\",\n\t\t\"xfs\",\n\t\t\"normal\",\n\t\t\"configfile\",\n\t\t\"linux\",\n\t\t\"boot\",\n\t\t\"search\",\n\t\t\"search_fs_uuid\",\n\t\t\"search_fs_file\",\n\t\t\"ls\",\n\t\t\"cat\",\n\t\t\"echo\",\n\t\t\"test\",\n\t\t\"help\",\n\t\t\"reboot\",\n\t\t\"halt\",\n\t\t\"all_video\",\n\t}\n\n\tconst grubPrefix = \"(hd0,gpt3)/grub\" // EFI, BIOS, BOOT\n\n\t// in amd64 mode only, install GRUB BIOS mode\n\tif opts.Arch == \"amd64\" {\n\t\tgrub32Modules := []string{\n\t\t\t\"biosdisk\",\n\t\t\t\"part_msdos\",\n\t\t}\n\n\t\targs := []string{ //nolint:prealloc // very dynamic length\n\t\t\t\"--format\",\n\t\t\t\"i386-pc\",\n\t\t\t\"--output\",\n\t\t\tfilepath.Join(opts.MountPrefix, \"core.img\"),\n\t\t\t\"--prefix\",\n\t\t\tgrubPrefix,\n\t\t}\n\n\t\targs = append(args, slices.Concat(grubModules, grub32Modules)...)\n\n\t\tif _, err := cmd.RunWithOptions(\n\t\t\tctx,\n\t\t\t\"grub-mkimage\",\n\t\t\targs,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate grub core image: %w\", err)\n\t\t}\n\n\t\tcopyInstructions = append(copyInstructions, utils.SourceDestination(\n\t\t\tfilepath.Join(grubSourceDirectory, \"i386-pc\", \"boot.img\"),\n\t\t\tfilepath.Join(opts.MountPrefix, \"boot.img\"),\n\t\t))\n\t}\n\n\tgrubEFIPath := filepath.Join(opts.MountPrefix, \"grub-efi.img\")\n\n\tvar platform string\n\n\t// install GRUB in UEFI mode\n\tswitch opts.Arch {\n\tcase \"amd64\":\n\t\tplatform = \"x86_64-efi\"\n\tcase \"arm64\":\n\t\tplatform = \"arm64-efi\"\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported architecture for grub image: %s\", opts.Arch)\n\t}\n\n\targs := []string{ //nolint:prealloc // very dynamic length\n\t\t\"--format\",\n\t\tplatform,\n\t\t\"--output\",\n\t\tgrubEFIPath,\n\t\t\"--prefix\",\n\t\tgrubPrefix,\n\t\t\"--compression\",\n\t\t\"xz\",\n\t}\n\targs = append(args, grubModules...)\n\n\tif _, err := cmd.RunWithOptions(\n\t\tctx,\n\t\t\"grub-mkimage\",\n\t\targs,\n\t); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate grub efi image: %w\", err)\n\t}\n\n\tefiFile, err := bootloaderutils.Name(opts.Arch)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcopyInstructions = append(copyInstructions, utils.SourceDestination(\n\t\tgrubEFIPath,\n\t\tfilepath.Join(opts.MountPrefix, constants.EFIMountPoint, efiFile),\n\t))\n\n\tif err := utils.CopyFiles(\n\t\topts.Printf,\n\t\tcopyInstructions...,\n\t); err != nil {\n\t\treturn fmt.Errorf(\"failed to copy grub generated img files: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (c *Config) generateAssets(opts options.InstallOptions) error {\n\tcmdline := opts.Cmdline\n\n\t// if we have a kernel path, assume that the kernel and initramfs are available\n\tif _, err := os.Stat(opts.BootAssets.KernelPath); err == nil {\n\t\tif err := utils.CopyFiles(\n\t\t\topts.Printf,\n\t\t\tutils.SourceDestination(\n\t\t\t\topts.BootAssets.KernelPath,\n\t\t\t\tfilepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.KernelAsset),\n\t\t\t),\n\t\t\tutils.SourceDestination(\n\t\t\t\topts.BootAssets.InitramfsPath,\n\t\t\t\tfilepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.InitramfsAsset),\n\t\t\t),\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif opts.GrubUseUKICmdline {\n\t\t\treturn fmt.Errorf(\"cannot use UKI cmdline when boot assets are not UKI\")\n\t\t}\n\t} else {\n\t\t// if the kernel path does not exist, assume that the kernel and initramfs are in the UKI\n\t\tassetInfo, err := uki.Extract(opts.BootAssets.UKIPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif assetInfo.Closer != nil {\n\t\t\t\tassetInfo.Close() //nolint:errcheck\n\t\t\t}\n\t\t}()\n\n\t\tif err := utils.CopyReader(\n\t\t\topts.Printf,\n\t\t\tutils.ReaderDestination(\n\t\t\t\tassetInfo.Kernel,\n\t\t\t\tfilepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.KernelAsset),\n\t\t\t),\n\t\t\tutils.ReaderDestination(\n\t\t\t\tassetInfo.Initrd,\n\t\t\t\tfilepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.InitramfsAsset),\n\t\t\t),\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif opts.GrubUseUKICmdline {\n\t\t\tcmdlineBytes, err := io.ReadAll(assetInfo.Cmdline)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to read cmdline from UKI: %w\", err)\n\t\t\t}\n\n\t\t\tcmdline = string(cmdlineBytes)\n\n\t\t\tif extraCmdline, err := smbios.ReadOEMVariable(constants.SDStubCmdlineExtraOEMVar); err == nil {\n\t\t\t\tfor _, extra := range extraCmdline {\n\t\t\t\t\tcmdline += \" \" + extra\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := c.Put(c.Default, cmdline, opts.Version); err != nil {\n\t\treturn err\n\t}\n\n\tif err := c.Write(filepath.Join(opts.MountPrefix, ConfigPath), opts.Printf); err != nil {\n\t\treturn err\n\t}\n\n\tif opts.ImageMode {\n\t\treturn c.generateGrubImage(context.Background(), opts)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (c *Config) runGrubInstall(ctx context.Context, opts options.InstallOptions, efiMode bool) error {\n\tvar platforms []string\n\n\tswitch opts.Arch {\n\tcase amd64:\n\t\tif efiMode {\n\t\t\tplatforms = append(platforms, \"x86_64-efi\")\n\t\t}\n\n\t\tplatforms = append(platforms, \"i386-pc\")\n\tcase arm64:\n\t\tplatforms = []string{\"arm64-efi\"}\n\t}\n\n\tif runtime.GOARCH == amd64 && opts.Arch == amd64 {\n\t\t// let grub choose the platform automatically if not building an image\n\t\tplatforms = []string{\"\"}\n\t}\n\n\tfor _, platform := range platforms {\n\t\targs := []string{\n\t\t\t\"--boot-directory=\" + filepath.Join(opts.MountPrefix, constants.BootMountPoint),\n\t\t\t\"--removable\",\n\t\t}\n\n\t\tif efiMode {\n\t\t\targs = append(args, \"--efi-directory=\"+filepath.Join(opts.MountPrefix, constants.EFIMountPoint))\n\t\t}\n\n\t\tif opts.ImageMode {\n\t\t\targs = append(args, \"--no-nvram\")\n\t\t}\n\n\t\tif platform != \"\" {\n\t\t\targs = append(args, \"--target=\"+platform)\n\t\t}\n\n\t\targs = append(args, opts.BootDisk)\n\n\t\topts.Printf(\"executing: grub-install %s\", strings.Join(args, \" \"))\n\n\t\tif _, err := cmd.RunWithOptions(ctx, \"grub-install\", args); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to install grub: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/probe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package grub provides the interface to the GRUB bootloader: config management, installation, etc.\npackage grub\n\nimport (\n\t\"github.com/siderolabs/gen/xerrors\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\tmountv3 \"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ProbeWithCallback probes the GRUB bootloader, and calls the callback function with the Config.\nfunc ProbeWithCallback(disk string, options options.ProbeOptions, callback func(*Config) error) (*Config, error) {\n\tvar grubConf *Config\n\n\tif err := mount.PartitionOp(\n\t\tdisk,\n\t\t[]mount.Spec{\n\t\t\t{\n\t\t\t\tPartitionLabel: constants.BootPartitionLabel,\n\t\t\t\tFilesystemType: partition.FilesystemTypeXFS,\n\t\t\t\tMountTarget:    constants.BootMountPoint,\n\t\t\t},\n\t\t},\n\t\tfunc() error {\n\t\t\tvar err error\n\n\t\t\tgrubConf, err = Read(ConfigPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif grubConf != nil && callback != nil {\n\t\t\t\treturn callback(grubConf)\n\t\t\t}\n\n\t\t\tif grubConf == nil {\n\t\t\t\toptions.Logf(\"GRUB: config not found\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\toptions.BlockProbeOptions,\n\t\t[]mountv3.ManagerOption{\n\t\t\tmountv3.WithSkipIfMounted(),\n\t\t\tmountv3.WithReadOnly(),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t); err != nil {\n\t\tif xerrors.TagIs[mount.NotFoundTag](err) {\n\t\t\t// if partitions are not found, it means GRUB is not installed\n\t\t\toptions.Logf(\"GRUB: BOOT partition not found, skipping probing\")\n\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn grubConf, nil\n}\n\n// Probe probes a block device for GRUB bootloader.\nfunc Probe(disk string, options options.ProbeOptions) (*Config, error) {\n\treturn ProbeWithCallback(disk, options, nil)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/quote.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"strings\"\n)\n\n// Quote according to (incomplete) GRUB quoting rules.\n//\n// See https://www.gnu.org/software/grub/manual/grub/html_node/Shell_002dlike-scripting.html\nfunc Quote(s string) string {\n\tfor _, c := range `\\{}&$|;<>\"` {\n\t\ts = strings.ReplaceAll(s, string(c), `\\`+string(c))\n\t}\n\n\treturn s\n}\n\n// Unquote according to (incomplete) GRUB quoting rules.\nfunc Unquote(s string) string {\n\tfor _, c := range `{}&$|;<>\\\"` {\n\t\ts = strings.ReplaceAll(s, `\\`+string(c), string(c))\n\t}\n\n\treturn s\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/quote_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n)\n\n//nolint:dupl\nfunc TestQuote(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tinput:    \"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"no special characters\",\n\t\t\tinput:    \"foo\",\n\t\t\texpected: \"foo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"backslash\",\n\t\t\tinput:    `foo\\`,\n\t\t\texpected: `foo\\\\`,\n\t\t},\n\t\t{\n\t\t\tname:     \"escaped backslash\",\n\t\t\tinput:    `foo\\$`,\n\t\t\texpected: `foo\\\\\\$`,\n\t\t},\n\t\t{\n\t\t\tname:     \"url\",\n\t\t\tinput:    \"http://my-host/config.yaml?uuid=${uuid}&serial=${serial}&mac=${mac}&hostname=${hostname}\",\n\t\t\texpected: \"http://my-host/config.yaml?uuid=\\\\$\\\\{uuid\\\\}\\\\&serial=\\\\$\\\\{serial\\\\}\\\\&mac=\\\\$\\\\{mac\\\\}\\\\&hostname=\\\\$\\\\{hostname\\\\}\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual := grub.Quote(test.input)\n\n\t\t\tif actual != test.expected {\n\t\t\t\tt.Fatalf(\"expected %q, got %q\", test.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc TestUnquote(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tinput:    \"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"no special characters\",\n\t\t\tinput:    \"foo\",\n\t\t\texpected: \"foo\",\n\t\t},\n\t\t{\n\t\t\tname:     \"backslash\",\n\t\t\tinput:    `foo\\\\`,\n\t\t\texpected: `foo\\`,\n\t\t},\n\t\t{\n\t\t\tname:     \"escaped backslash\",\n\t\t\tinput:    `foo\\\\\\$`,\n\t\t\texpected: `foo\\$`,\n\t\t},\n\t\t{\n\t\t\tname:     \"url\",\n\t\t\tinput:    \"http://my-host/config.yaml?uuid=\\\\$\\\\{uuid\\\\}\\\\&serial=\\\\$\\\\{serial\\\\}\\\\&mac=\\\\$\\\\{mac\\\\}\\\\&hostname=\\\\$\\\\{hostname\\\\}\",\n\t\t\texpected: \"http://my-host/config.yaml?uuid=${uuid}&serial=${serial}&mac=${mac}&hostname=${hostname}\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual := grub.Unquote(test.input)\n\n\t\t\tif actual != test.expected {\n\t\t\t\tt.Fatalf(\"expected %q, got %q\", test.expected, actual)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/revert.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package grub provides the interface to the GRUB bootloader: config management, installation, etc.\npackage grub\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount\"\n\tmountv3 \"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Revert reverts the bootloader to the previous version.\nfunc (c *Config) Revert(disk string) error {\n\tif c == nil {\n\t\treturn fmt.Errorf(\"cannot revert bootloader: %w\", bootloaderNotInstalledError{})\n\t}\n\n\terr := mount.PartitionOp(\n\t\tdisk,\n\t\t[]mount.Spec{\n\t\t\t{\n\t\t\t\tPartitionLabel: constants.BootPartitionLabel,\n\t\t\t\tFilesystemType: partition.FilesystemTypeXFS,\n\t\t\t\tMountTarget:    constants.BootMountPoint,\n\t\t\t},\n\t\t},\n\t\tc.revert,\n\t\tnil,\n\t\t[]mountv3.ManagerOption{\n\t\t\tmountv3.WithSkipIfMounted(),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t)\n\tif err != nil && !xerrors.TagIs[mount.NotFoundTag](err) {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) revert() error {\n\tif err := c.flip(); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := os.Stat(filepath.Join(constants.BootMountPoint, string(c.Default))); errors.Is(err, os.ErrNotExist) {\n\t\treturn fmt.Errorf(\"cannot rollback to %q, label does not exist\", \"\")\n\t}\n\n\tif err := c.Write(ConfigPath, log.Printf); err != nil {\n\t\treturn fmt.Errorf(\"failed to revert bootloader: %v\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/testdata/grub_parse_test.cfg",
    "content": "set default=\"A - v1\"\nset timeout=3\nset fallback=\"B - v2\"\n\ninsmod all_video\n\nterminal_input console\nterminal_output console\n\nmenuentry \"A - v1\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /A/vmlinuz cmdline A\n  initrd /A/initramfs.xz\n}\n\nmenuentry \"B - v2\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /B/vmlinuz cmdline B\n  initrd /B/initramfs.xz\n}\n\nmenuentry \"Reset Talos installation and return to maintenance mode\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /A/vmlinuz cmdline A talos.experimental.wipe=system:EPHEMERAL,STATE\n  initrd /A/initramfs.xz\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/testdata/grub_write_no_reset_test.cfg",
    "content": "set default=\"A - TestOld v0.0.1\"\n\nset timeout=3\n\ninsmod all_video\n\nterminal_input console\nterminal_output console\n\nmenuentry \"A - TestOld v0.0.1\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /A/vmlinuz cmdline A\n  initrd /A/initramfs.xz\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/testdata/grub_write_test.cfg",
    "content": "set default=\"A - Test v0.0.1\"\n\nset timeout=3\n\ninsmod all_video\n\nterminal_input console\nterminal_output console\n\nmenuentry \"A - Test v0.0.1\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /A/vmlinuz cmdline A\n  initrd /A/initramfs.xz\n}\nmenuentry \"Reset Talos installation and return to maintenance mode\" {\n  set gfxmode=auto\n  set gfxpayload=text\n  linux /A/vmlinuz cmdline A talos.experimental.wipe=system:EPHEMERAL,STATE\n  initrd /A/initramfs.xz\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/upgrade.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage grub\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Upgrade copies new boot assets and updates grub configuration on an existing installation.\nfunc (c *Config) Upgrade(opts options.InstallOptions) (*options.InstallResult, error) {\n\tmountSpecs := []mount.Spec{\n\t\t{\n\t\t\tPartitionLabel: constants.BootPartitionLabel,\n\t\t\tFilesystemType: partition.FilesystemTypeXFS,\n\t\t\tMountTarget:    filepath.Join(opts.MountPrefix, constants.BootMountPoint),\n\t\t},\n\t}\n\n\tefiMountSpec := mount.Spec{\n\t\tPartitionLabel: constants.EFIPartitionLabel,\n\t\tFilesystemType: partition.FilesystemTypeVFAT,\n\t\tMountTarget:    filepath.Join(opts.MountPrefix, constants.EFIMountPoint),\n\t}\n\n\tvar efiFound bool\n\n\t// check if the EFI partition is present\n\tif err := mount.PartitionOp(\n\t\topts.BootDisk,\n\t\t[]mount.Spec{efiMountSpec},\n\t\tfunc() error {\n\t\t\treturn nil\n\t\t},\n\t\t[]blkid.ProbeOption{\n\t\t\tblkid.WithSkipLocking(true),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\topts.BlkidInfo,\n\t); err == nil {\n\t\tefiFound = true\n\t}\n\n\tif efiFound {\n\t\tmountSpecs = append(mountSpecs, efiMountSpec)\n\t}\n\n\terr := mount.PartitionOp(\n\t\topts.BootDisk,\n\t\tmountSpecs,\n\t\tfunc() error {\n\t\t\tif err := c.flip(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := c.generateAssets(opts); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := c.runGrubInstall(context.Background(), opts, efiFound); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif opts.ExtraInstallStep != nil {\n\t\t\t\tif err := opts.ExtraInstallStep(); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\t[]blkid.ProbeOption{\n\t\t\t// installation happens with locked blockdevice\n\t\t\tblkid.WithSkipLocking(true),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\topts.BlkidInfo,\n\t)\n\n\treturn &options.InstallResult{\n\t\tPreviousLabel: string(c.Fallback),\n\t}, err\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/kexec/kexec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kexec call unix.KexecFileLoad with error handling.\npackage kexec\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\tgoruntime \"runtime\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/zboot\"\n)\n\n// Load handles zboot for arm64 and calls unix.KexecFileLoad with error handling and sets the machine state to kexec prepared.\nfunc Load(r runtime.Runtime, kernel *os.File, initrdFD int, cmdline string) error {\n\tkernelFD := int(kernel.Fd())\n\n\t// on arm64 we need to extract the kernel from the zboot image if it's compressed\n\tif goruntime.GOARCH == \"arm64\" {\n\t\tvar (\n\t\t\tfileCloser io.Closer\n\t\t\textractErr error\n\t\t)\n\n\t\tkernelFD, fileCloser, extractErr = zboot.Extract(kernel)\n\t\tif extractErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to extract kernel from zboot: %w\", extractErr)\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif fileCloser != nil {\n\t\t\t\tfileCloser.Close() //nolint:errcheck\n\t\t\t}\n\t\t}()\n\t}\n\n\tif err := unix.KexecFileLoad(kernelFD, initrdFD, cmdline, 0); err != nil {\n\t\tswitch {\n\t\tcase errors.Is(err, unix.ENOSYS):\n\t\t\tlog.Printf(\"kexec support is disabled in the kernel\")\n\n\t\t\treturn nil\n\t\tcase errors.Is(err, unix.EPERM):\n\t\t\tlog.Printf(\"kexec support is disabled via sysctl\")\n\n\t\t\treturn nil\n\t\tcase errors.Is(err, unix.EBUSY):\n\t\t\tlog.Printf(\"kexec is busy\")\n\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"error loading kernel for kexec: %w\", err)\n\t\t}\n\t}\n\n\tr.State().Machine().KexecPrepared(true)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount/mount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package mount provides bootloader mount operations.\npackage mount\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\n// Spec specifies what has to be mounted.\ntype Spec struct {\n\tPartitionLabel string\n\n\tFilesystemType string\n\n\tMountTarget string\n}\n\n// NotFoundTag is a tag for a partition not found/mismatch errors.\ntype NotFoundTag struct{}\n\n// PartitionOp mounts specified partitions with the specified label, executes the operation func, and unmounts the partition(s).\nfunc PartitionOp(\n\tdisk string, specs []Spec, opFunc func() error,\n\tprobeOptions []blkid.ProbeOption,\n\tmountOptions []mount.ManagerOption,\n\tfilesystemOptions []fsopen.Option,\n\tinfo *blkid.Info, // might be nil\n) error {\n\tif info == nil {\n\t\tvar err error\n\n\t\tinfo, err = blkid.ProbePath(disk, probeOptions...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error probing disk %s: %w\", disk, err)\n\t\t}\n\t}\n\n\tvar managers mount.Managers\n\n\tfor _, spec := range specs {\n\t\tvar found bool\n\n\t\tfor _, partition := range info.Parts {\n\t\t\tif pointer.SafeDeref(partition.PartitionLabel) == spec.PartitionLabel {\n\t\t\t\tif partition.Name != spec.FilesystemType {\n\t\t\t\t\treturn xerrors.NewTaggedf[NotFoundTag](\"partition %d with label %s is not of type %s (actual %q)\", partition.PartitionIndex, *partition.PartitionLabel, spec.FilesystemType, partition.Name)\n\t\t\t\t}\n\n\t\t\t\tmanager := mount.NewManager(slices.Concat(\n\t\t\t\t\t[]mount.ManagerOption{\n\t\t\t\t\t\tmount.WithTarget(spec.MountTarget),\n\t\t\t\t\t\tmount.WithFsopen(\n\t\t\t\t\t\t\tspec.FilesystemType,\n\t\t\t\t\t\t\tslices.Concat(\n\t\t\t\t\t\t\t\t[]fsopen.Option{\n\t\t\t\t\t\t\t\t\tfsopen.WithSource(partitioning.DevName(disk, partition.PartitionIndex)),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tfilesystemOptions,\n\t\t\t\t\t\t\t)...,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\tmountOptions,\n\t\t\t\t)...)\n\n\t\t\t\tmanagers = append(managers,\n\t\t\t\t\tmanager,\n\t\t\t\t)\n\n\t\t\t\tfound = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\treturn xerrors.NewTaggedf[NotFoundTag](\"partition with label %s not found\", spec.PartitionLabel)\n\t\t}\n\t}\n\n\tunmounter, err := managers.Mount()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error mounting partitions: %w\", err)\n\t}\n\n\tdefer unmounter() //nolint:errcheck\n\n\treturn opFunc()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package options provides bootloader options.\npackage options\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// InstallOptions configures bootloader installation.\ntype InstallOptions struct {\n\t// The disk to install to.\n\tBootDisk string\n\t// Target architecture.\n\tArch string\n\t// Kernel command line (grub only, and only if GrubUseUKICmdline is false).\n\tCmdline string\n\t// Whether to use the UKI cmdline instead of building it on the host (grub only).\n\tGrubUseUKICmdline bool\n\t// Talos version.\n\tVersion string\n\n\t// Are we running in image mode?\n\tImageMode bool\n\n\t// Mount prefix for /boot-like partitions.\n\tMountPrefix string\n\n\t// Boot assets to install.\n\tBootAssets BootAssets\n\n\t// ExtraInstallStep is a function to run after the bootloader is installed.\n\tExtraInstallStep func() error\n\n\t// Printf-like function to use.\n\tPrintf func(format string, v ...any)\n\n\t// Optional: blkid probe result.\n\tBlkidInfo *blkid.Info\n}\n\n// InstallResult is the result of the installation.\ntype InstallResult struct {\n\t// Previous label (if upgrading).\n\tPreviousLabel string\n}\n\n// BootAssets describes the assets to be installed by the bootloader.\ntype BootAssets struct {\n\tKernelPath    string\n\tInitramfsPath string\n\n\tUKIPath    string\n\tSDBootPath string\n}\n\n// FillDefaults fills in default paths to be used when in the context of the installer.\nfunc (assets *BootAssets) FillDefaults(arch string) {\n\tif assets.KernelPath == \"\" {\n\t\tassets.KernelPath = fmt.Sprintf(constants.KernelAssetPath, arch)\n\t}\n\n\tif assets.InitramfsPath == \"\" {\n\t\tassets.InitramfsPath = fmt.Sprintf(constants.InitramfsAssetPath, arch)\n\t}\n\n\tif assets.UKIPath == \"\" {\n\t\tassets.UKIPath = fmt.Sprintf(constants.UKIAssetPath, arch)\n\t}\n\n\tif assets.SDBootPath == \"\" {\n\t\tassets.SDBootPath = fmt.Sprintf(constants.SDBootAssetPath, arch)\n\t}\n}\n\n// ProbeOptions configures bootloader probing.\ntype ProbeOptions struct {\n\tBlockProbeOptions []blkid.ProbeOption\n\tLogger            func(format string, v ...any)\n}\n\n// Logf logs the message using the provided logger.\nfunc (options *ProbeOptions) Logf(format string, v ...any) {\n\tif options.Logger == nil {\n\t\treturn\n\t}\n\n\toptions.Logger(format, v...)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/efivars.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage sdboot\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"maps\"\n\t\"math\"\n\t\"os\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// TalosBootEntryDescription is the description of the Talos Linux UKI UEFI boot entry.\nconst TalosBootEntryDescription = \"Talos Linux UKI\"\n\n// SystemdBootStubInfoPath is the path to the SystemdBoot StubInfo EFI variable.\nvar SystemdBootStubInfoPath = constants.EFIVarsMountPoint + \"/\" + \"StubInfo-\" + efivarfs.ScopeSystemd.String()\n\n// Variable names.\nconst (\n\tLoaderConfigTimeoutName     = \"LoaderConfigTimeout\"\n\tLoaderEntryDefaultName      = \"LoaderEntryDefault\"\n\tLoaderEntryOneShotName      = \"LoaderEntryOneShot\"\n\tLoaderEntryRebootReasonName = \"LoaderEntryRebootReason\"\n\tLoaderEntrySelectedName     = \"LoaderEntrySelected\"\n\n\tStubImageIdentifierName = \"StubImageIdentifier\"\n)\n\n// ReadVariable reads a SystemdBoot EFI variable.\nfunc ReadVariable(name string) (string, error) {\n\tefi, err := efivarfs.NewFilesystemReaderWriter(false)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create efivarfs reader/writer: %w\", err)\n\t}\n\n\tdefer efi.Close() //nolint:errcheck\n\n\tdata, _, err := efi.Read(efivarfs.ScopeSystemd, name)\n\tif err != nil {\n\t\t// if the variable does not exist, return an empty string\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn \"\", nil\n\t\t}\n\n\t\treturn \"\", err\n\t}\n\n\tout := make([]byte, len(data))\n\n\tdecoder := efivarfs.Encoding.NewDecoder()\n\n\tn, _, err := decoder.Transform(out, data, true)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif n > 0 && out[n-1] == 0 {\n\t\tn--\n\t}\n\n\treturn string(out[:n]), nil\n}\n\n// WriteVariable reads a SystemdBoot EFI variable.\nfunc WriteVariable(name, value string) error {\n\tefi, err := efivarfs.NewFilesystemReaderWriter(true)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create efivarfs reader/writer: %w\", err)\n\t}\n\n\tdefer efi.Close() //nolint:errcheck\n\n\tout := make([]byte, (len(value)+1)*2)\n\n\tencoder := efivarfs.Encoding.NewEncoder()\n\n\tn, _, err := encoder.Transform(out, []byte(value), true)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tout = append(out[:n], 0, 0)\n\n\treturn efi.Write(efivarfs.ScopeSystemd, name, efivarfs.AttrBootserviceAccess|efivarfs.AttrRuntimeAccess|efivarfs.AttrNonVolatile, out)\n}\n\n// CreateBootEntry creates a UEFI boot entry named \"Talos Linux UKI\" and sets it as the first in the `BootOrder`\n// The entry will point to the SystemdBoot PE binary located at the specified install disk path.\n//\n//nolint:gocyclo,cyclop\nfunc CreateBootEntry(rw efivarfs.ReadWriter, blkidInfo *blkid.Info, printf func(format string, args ...any), sdBootFilePath string) error {\n\tefiPartInfo := xslices.Filter(blkidInfo.Parts, func(part blkid.NestedProbeResult) bool {\n\t\treturn part.PartitionLabel != nil && *part.PartitionLabel == constants.EFIPartitionLabel\n\t})\n\n\tif len(efiPartInfo) == 0 {\n\t\treturn fmt.Errorf(\"EFI partition not found on install disk %q\", blkidInfo.Name)\n\t}\n\n\tif len(efiPartInfo) > 1 {\n\t\treturn fmt.Errorf(\"multiple EFI partitions found on install disk %q, expected only one\", blkidInfo.Name)\n\t}\n\n\tpartitionUUID := efiPartInfo[0].PartitionUUID\n\n\tif partitionUUID == nil {\n\t\treturn fmt.Errorf(\"EFI partition UUID not found on install disk %q\", blkidInfo.Name)\n\t}\n\n\tprintf(\"using disk %s with partition %d and UUID %s\", blkidInfo.Name, efiPartInfo[0].PartitionIndex, partitionUUID.String())\n\n\tbootOrder, err := efivarfs.GetBootOrder(rw)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\tbootOrder = efivarfs.BootOrder{}\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"failed to get BootOrder: %w\", err)\n\t\t}\n\t}\n\n\tprintf(\"Current BootOrder: %v\", bootOrder)\n\n\tbootEntries, err := efivarfs.ListBootEntries(rw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to list existing Talos boot entries: %w\", err)\n\t}\n\n\tprintf(\"Existing boot entries: %v\", slices.Collect(maps.Keys(bootEntries)))\n\n\tvar existingTalosBootEntryIndexes []int\n\n\t// Find all boot entries with the Talos Linux UKI description.\n\tfor idx, entry := range bootEntries {\n\t\tif entry.Description == TalosBootEntryDescription {\n\t\t\texistingTalosBootEntryIndexes = append(existingTalosBootEntryIndexes, idx)\n\t\t}\n\t}\n\n\t// we sort the indexes to make sure we always keep the lowest index\n\t// when removing duplicate Talos Linux UKI boot entries\n\tslices.Sort(existingTalosBootEntryIndexes)\n\n\tprintf(\"Found existing Talos Linux UKI boot entries: %v\", existingTalosBootEntryIndexes)\n\n\t// Remove any existing Talos Linux UKI boot entries from the BootOrder.\n\t// We need to do this since Talos 1.11.x release assumed that the boot order set by the code stays even after a reboot,\n\t// but UEFI firmware settings can set a different boot order on boot, which lead to multiple Talos Linux UKI entries in the boot order,\n\t// causing some UEFI firmwares to fail to boot at all.\n\t// See https://github.com/siderolabs/talos/issues/11829\n\n\t// find the next minimal available index for the new Talos Linux UKI boot entry\n\tnextMinimalIndex := -1\n\n\tfor i := range math.MaxUint16 {\n\t\tif _, ok := bootEntries[i]; !ok {\n\t\t\tnextMinimalIndex = i\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif nextMinimalIndex == -1 {\n\t\treturn errors.New(\"all 2^16 boot entry variables are occupied\")\n\t}\n\n\t// remove all existing Talos Linux UKI boot entries except the first one\n\t// and use its index for the new/updated entry\n\tfor i, idx := range existingTalosBootEntryIndexes {\n\t\tif i == 0 {\n\t\t\tnextMinimalIndex = idx\n\n\t\t\tcontinue\n\t\t}\n\n\t\tprintf(\"Removing existing Talos Linux UKI boot entry at index %d\", idx)\n\n\t\tif err := efivarfs.DeleteBootEntry(rw, idx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to delete existing Talos boot entry at index %d: %w\", idx, err)\n\t\t}\n\t}\n\n\tif err := efivarfs.SetBootEntry(rw, nextMinimalIndex, &efivarfs.LoadOption{\n\t\tDescription: TalosBootEntryDescription,\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\t&efivarfs.HardDrivePath{\n\t\t\t\tPartitionNumber:     uint32(efiPartInfo[0].PartitionIndex),\n\t\t\t\tPartitionStartBlock: efiPartInfo[0].PartitionOffset / uint64(blkidInfo.SectorSize),\n\t\t\t\tPartitionSizeBlocks: efiPartInfo[0].PartitionSize / uint64(blkidInfo.SectorSize),\n\t\t\t\tPartitionMatch: &efivarfs.PartitionGPT{\n\t\t\t\t\tPartitionUUID: *partitionUUID,\n\t\t\t\t},\n\t\t\t},\n\t\t\tefivarfs.FilePath(\"/\" + sdBootFilePath),\n\t\t},\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to create Talos Linux UKI boot entry at index %d: %w\", nextMinimalIndex, err)\n\t}\n\n\tprintf(\"created Talos Linux UKI boot entry at index %d\", nextMinimalIndex)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/efivars_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage sdboot_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\ntype mockLogger struct {\n\tstrings.Builder\n}\n\nfunc (m *mockLogger) Printf(format string, v ...any) {\n\tm.WriteString(fmt.Sprintf(format, v...) + \"\\n\")\n}\n\nfunc TestSetBootEntry(t *testing.T) {\n\tt.Parallel()\n\n\tloadOption := &efivarfs.LoadOption{\n\t\tDescription: \"Default Boot Entry\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/default.efi\"),\n\t\t},\n\t}\n\n\tdefaultBootEntry, err := loadOption.Marshal()\n\trequire.NoError(t, err)\n\n\ttalosLoadOption := &efivarfs.LoadOption{\n\t\tDescription: sdboot.TalosBootEntryDescription,\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/EFI/TALOS/UKI.efi\"),\n\t\t},\n\t}\n\n\ttalosBootEntry, err := talosLoadOption.Marshal()\n\trequire.NoError(t, err)\n\n\tblkidInfo := &blkid.Info{\n\t\tProbeResult: blkid.ProbeResult{\n\t\t\tName: \"loop0\",\n\t\t},\n\t\tSectorSize: 512,\n\t\tParts: []blkid.NestedProbeResult{\n\t\t\t{\n\t\t\t\tNestedResult: blkid.NestedResult{\n\t\t\t\t\tPartitionUUID:   new(uuid.MustParse(\"3c8f4e2e-1dd2-4a5b-9f6d-8f3c9e6d7c3b\")),\n\t\t\t\t\tPartitionLabel:  new(constants.EFIPartitionLabel),\n\t\t\t\t\tPartitionOffset: 2048,\n\t\t\t\t\tPartitionSize:   409600,\n\t\t\t\t\tPartitionIndex:  1,\n\t\t\t\t\tPartitionType:   new(uuid.MustParse(\"c12a7328-f81f-11d2-ba4b-00a0c93ec93b\")),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, testData := range []struct {\n\t\tname         string\n\t\tefivarfsMock *efivarfs.Mock\n\n\t\texpectedEntries map[int]string\n\t}{\n\t\t{\n\t\t\tname:         \"empty efivarfs\", // both BootOrder and BootEntries are initially empty\n\t\t\tefivarfsMock: &efivarfs.Mock{},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootEntry but empty BootOrder\", // BootOrder is empty but there is already a BootEntry\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootOrder but empty BootEntries\", // BootOrder has an entry but there are no BootEntries\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x00, 0x00},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootOrder and BootEntries matching\", // both BootOrder and BootEntries have an entry and they match\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x00, 0x00}, // BootOrder: [0]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootOrder and BootEntries not matching\", // both BootOrder and BootEntries have an entry but they don't match\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00}, // BootOrder: [1]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootOrder and BootEntries not matching multiple\", // both BootOrder and BootEntries have an entry but they don't match\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00}, // BootOrder: [1, 0, 3, 2]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0002\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t\t2: \"Default Boot Entry\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"existing BootOrder and BootEntries not matching multiple-1\", // both BootOrder and BootEntries have an entry but they don't match\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00}, // BootOrder: [5, 0, 3, 2]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0003\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t\t3: \"Default Boot Entry\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate entries in BootOrder but not BootEntries\", // BootOrder has duplicate entries and no matching BootEntries\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00}, // BootOrder: [1, 0, 0, 3, 2, 3]\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate Talos entries in BootEntries\", // BootOrder has unique entries but there are multiple Talos BootEntries\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00, 0x02, 0x00}, // BootOrder: [1, 2]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0001\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  talosBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0002\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  talosBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate Talos entries in BootEntries and duplicate BootOrder\", // BootOrder has duplicate entries and there are multiple Talos BootEntries\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00}, // BootOrder: [1, 2, 2, 0]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0001\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  talosBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0002\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  talosBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0: \"Default Boot Entry\",\n\t\t\t\t1: sdboot.TalosBootEntryDescription,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"duplicate entries in BootOrder and BootEntries\", // BootOrder has duplicate entries and has multiple BootEntries\n\t\t\tefivarfsMock: &efivarfs.Mock{\n\t\t\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\t\t\"BootOrder\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x03, 0x00}, // BootOrder: [1, 0, 0, 3, 2, 3]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0000\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0001\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot0003\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"Boot002a\": {\n\t\t\t\t\t\t\tAttrs: 0,\n\t\t\t\t\t\t\tData:  defaultBootEntry,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedEntries: map[int]string{\n\t\t\t\t0:  \"Default Boot Entry\",\n\t\t\t\t1:  \"Default Boot Entry\",\n\t\t\t\t2:  sdboot.TalosBootEntryDescription,\n\t\t\t\t3:  \"Default Boot Entry\",\n\t\t\t\t42: \"Default Boot Entry\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(testData.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tif testData.efivarfsMock == nil {\n\t\t\t\tt.Fatal(\"efivarfsMock must be set\")\n\t\t\t}\n\n\t\t\tlogger := &mockLogger{}\n\n\t\t\trequire.NoError(t, sdboot.CreateBootEntry(testData.efivarfsMock, blkidInfo, logger.Printf, \"test-entry\"))\n\n\t\t\tbootEntries, err := efivarfs.ListBootEntries(testData.efivarfsMock)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Len(t, bootEntries, len(testData.expectedEntries), \"number of boot entries does not match expected value\")\n\n\t\t\tfor idx, desc := range testData.expectedEntries {\n\t\t\t\tentry, err := efivarfs.GetBootEntry(testData.efivarfsMock, idx)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\trequire.Equal(t, desc, entry.Description, \"boot entry description does not match expected value\")\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage sdboot\n\n// exported for testing only.\nvar (\n\tFindMatchingUKIFile = findMatchingUKIFile\n\tGenerateNextUKIName = generateNextUKIName\n)\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/loader.conf",
    "content": "# systemd-boot configuration\n\ntimeout 10\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package sdboot provides the interface to the Systemd-Boot bootloader: config management, installation, etc.\npackage sdboot\n\nimport (\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/foxboron/go-uefi/efi\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tbootloaderutils \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/efiutils\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/kexec\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n\tmountv3 \"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/internal/pkg/smbios\"\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// LoaderConfBytes is the content of the loader.conf file.\n//\n//go:embed loader.conf\nvar LoaderConfBytes []byte\n\n// Config describe sd-boot state.\ntype Config struct {\n\tDefault  string\n\tFallback string\n}\n\n// IsUEFIBoot returns true if the system is booted using UEFI.\nfunc IsUEFIBoot() bool {\n\t// https://renenyffenegger.ch/notes/Linux/fhs/sys/firmware/efi/index\n\t_, err := os.Stat(\"/sys/firmware/efi\")\n\n\treturn err == nil\n}\n\n// IsBootedUsingSDBoot returns true if the system is booted using sd-boot.\nfunc IsBootedUsingSDBoot() bool {\n\t// https://www.freedesktop.org/software/systemd/man/systemd-stub.html#EFI%20Variables\n\t// https://www.freedesktop.org/software/systemd/man/systemd-stub.html#StubInfo\n\t_, err := os.Stat(SystemdBootStubInfoPath)\n\n\treturn err == nil\n}\n\n// New creates a new sdboot bootloader config.\nfunc New() *Config {\n\treturn &Config{}\n}\n\n// ProbeWithCallback probes the sd-boot bootloader, and calls the callback function with the Config.\n// this is called when we upgrade, do KexecLoad, or for reverting the bootloader.\n//\n//nolint:gocyclo\nfunc ProbeWithCallback(disk string, options options.ProbeOptions, callback func(*Config) error) (*Config, error) {\n\t// if not UEFI boot, nothing to do\n\tif !IsUEFIBoot() {\n\t\toptions.Logf(\"sd-boot: not booted using UEFI, skipping probing\")\n\n\t\treturn nil, nil\n\t}\n\n\tvar sdbootConf *Config\n\n\t// read /boot/EFI and find if sd-boot is already being used\n\t// this is to make sure sd-boot from Talos is being used and not sd-boot from another distro\n\tif err := mount.PartitionOp(\n\t\tdisk,\n\t\t[]mount.Spec{\n\t\t\t{\n\t\t\t\tPartitionLabel: constants.EFIPartitionLabel,\n\t\t\t\tFilesystemType: partition.FilesystemTypeVFAT,\n\t\t\t\tMountTarget:    constants.EFIMountPoint,\n\t\t\t},\n\t\t},\n\t\tfunc() error {\n\t\t\t// list existing boot*.efi files in boot folder\n\t\t\tfiles, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, \"EFI\", \"boot\", \"BOOT*.efi\"))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif len(files) == 0 {\n\t\t\t\treturn fmt.Errorf(\"no boot*.efi files found in %s\", filepath.Join(constants.EFIMountPoint, \"EFI\", \"boot\"))\n\t\t\t}\n\n\t\t\t// list existing UKIs, and check if the current one is present\n\t\t\tukiFiles, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, \"EFI\", \"Linux\", \"Talos-*.efi\"))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif len(ukiFiles) == 0 {\n\t\t\t\treturn fmt.Errorf(\"no UKI files found in %q\", filepath.Join(constants.EFIMountPoint, \"EFI\", \"Linux\"))\n\t\t\t}\n\n\t\t\toptions.Logf(\"sd-boot: found UKI files: %v\", xslices.Map(ukiFiles, filepath.Base))\n\n\t\t\t// If we booted of UKI/Kernel+Initramfs/ISO Talos installer will always be run which\n\t\t\t// sets the `LoaderEntryDefault` to the UKI file name, so either for reboot with Kexec or upgrade\n\t\t\t// we will always have the UKI file name in the `LoaderEntryDefault`\n\t\t\t// and we can use it to determine the default entry.\n\t\t\tloaderEntryDefault, err := ReadVariable(LoaderEntryDefaultName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\toptions.Logf(\"sd-boot: LoaderEntryDefault: %s\", loaderEntryDefault)\n\n\t\t\t// If we booted of a Disk image, only `LoaderEntrySelected` will be set until we do an upgrade\n\t\t\t// which will set the `LoaderEntryDefault` to the UKI file name.\n\t\t\t// So for reboot with Kexec we will have to read the `LoaderEntrySelected`\n\t\t\t// upgrades will always have `LoaderEntryDefault` set to the UKI file name.\n\t\t\tloaderEntrySelected, err := ReadVariable(LoaderEntrySelectedName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\toptions.Logf(\"sd-boot: LoaderEntrySelected: %s\", loaderEntrySelected)\n\n\t\t\tif loaderEntrySelected == \"\" && loaderEntryDefault == \"\" {\n\t\t\t\treturn errors.New(\"sd-boot: no LoaderEntryDefault or LoaderEntrySelected found, cannot continue\")\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tbootEntry   string\n\t\t\t\tbootEntryOk bool\n\t\t\t)\n\n\t\t\t// first try to find the default entry, then the selected one\n\t\t\tbootEntry, bootEntryOk = findMatchingUKIFile(ukiFiles, loaderEntryDefault)\n\t\t\tif !bootEntryOk {\n\t\t\t\tbootEntry, bootEntryOk = findMatchingUKIFile(ukiFiles, loaderEntrySelected)\n\t\t\t\tif !bootEntryOk {\n\t\t\t\t\treturn errors.New(\"sd-boot: no valid boot entry found matching LoaderEntryDefault or LoaderEntrySelected\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptions.Logf(\"sd-boot: found boot entry: %s\", bootEntry)\n\n\t\t\tsdbootConf = &Config{\n\t\t\t\tDefault: bootEntry,\n\t\t\t}\n\n\t\t\toptions.Logf(\"sd-boot: using %s as default entry\", sdbootConf.Default)\n\n\t\t\tif callback != nil {\n\t\t\t\treturn callback(sdbootConf)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\toptions.BlockProbeOptions,\n\t\t[]mountv3.ManagerOption{\n\t\t\tmountv3.WithSkipIfMounted(),\n\t\t\tmountv3.WithReadOnly(),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t); err != nil {\n\t\tif xerrors.TagIs[mount.NotFoundTag](err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn sdbootConf, nil\n}\n\n// Probe for existing sd-boot bootloader.\nfunc Probe(disk string, options options.ProbeOptions) (*Config, error) {\n\treturn ProbeWithCallback(disk, options, nil)\n}\n\n// KexecLoad does a kexec using the bootloader config.\n//\n//nolint:gocyclo\nfunc (c *Config) KexecLoad(r runtime.Runtime, disk string) error {\n\t_, err := ProbeWithCallback(disk, options.ProbeOptions{}, func(conf *Config) error {\n\t\tvar kernelFd int\n\n\t\tassetInfo, err := uki.Extract(filepath.Join(constants.EFIMountPoint, \"EFI\", \"Linux\", conf.Default))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to extract kernel and initrd from uki: %w\", err)\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif assetInfo.Closer != nil {\n\t\t\t\tassetInfo.Close() //nolint:errcheck\n\t\t\t}\n\t\t}()\n\n\t\tkernelFd, err = unix.MemfdCreate(\"vmlinux\", 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"memfdCreate: %v\", err)\n\t\t}\n\n\t\tkernelMemfd := os.NewFile(uintptr(kernelFd), \"vmlinux\")\n\n\t\tdefer kernelMemfd.Close() //nolint:errcheck\n\n\t\tif _, err := io.Copy(kernelMemfd, assetInfo.Kernel); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read kernel from uki: %w\", err)\n\t\t}\n\n\t\tif _, err = kernelMemfd.Seek(0, io.SeekStart); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to seek kernel: %w\", err)\n\t\t}\n\n\t\tinitrdFd, err := unix.MemfdCreate(\"initrd\", 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"memfdCreate: %v\", err)\n\t\t}\n\n\t\tinitrdMemfd := os.NewFile(uintptr(initrdFd), \"initrd\")\n\n\t\tdefer initrdMemfd.Close() //nolint:errcheck\n\n\t\tif _, err := io.Copy(initrdMemfd, assetInfo.Initrd); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read initrd from uki: %w\", err)\n\t\t}\n\n\t\tif _, err = initrdMemfd.Seek(0, io.SeekStart); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to seek initrd: %w\", err)\n\t\t}\n\n\t\tvar cmdline strings.Builder\n\n\t\tif _, err := io.Copy(&cmdline, assetInfo.Cmdline); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read cmdline from uki: %w\", err)\n\t\t}\n\n\t\tif !efi.GetSecureBoot() {\n\t\t\tif extraCmdline, err := smbios.ReadOEMVariable(constants.SDStubCmdlineExtraOEMVar); err == nil {\n\t\t\t\tfor _, s := range extraCmdline {\n\t\t\t\t\tcmdline.WriteString(\" \" + s)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err := kexec.Load(r, kernelMemfd, initrdFd, cmdline.String()); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load kernel for kexec: %w\", err)\n\t\t}\n\n\t\tlog.Printf(\"prepared kexec environment with kernel and initrd extracted from uki, cmdline=%q\", cmdline.String())\n\n\t\treturn nil\n\t})\n\n\treturn err\n}\n\n// GenerateAssets generates the sd-boot bootloader assets and returns the partition options with source directory set.\nfunc (c *Config) GenerateAssets(opts options.InstallOptions) ([]partition.Options, error) {\n\tukiFileName, err := generateNextUKIName(opts.Version, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := c.generateAssets(opts, ukiFileName); err != nil {\n\t\treturn nil, err\n\t}\n\n\tquirk := quirks.New(opts.Version)\n\n\tpartitionOptions := []partition.Options{\n\t\tpartition.NewPartitionOptions(\n\t\t\ttrue,\n\t\t\tquirk,\n\t\t\tpartition.WithLabel(constants.EFIPartitionLabel),\n\t\t\tpartition.WithSourceDirectory(filepath.Join(opts.MountPrefix, \"EFI\")),\n\t\t),\n\t}\n\n\tif opts.ImageMode {\n\t\tpartitionOptions = xslices.Map(partitionOptions, func(o partition.Options) partition.Options {\n\t\t\to.Reproducible = true\n\n\t\t\treturn o\n\t\t})\n\t}\n\n\treturn partitionOptions, nil\n}\n\n// Install the bootloader.\n// here we don't need to mount anything since we just need to write the EFI variables\n// since the partitions are already pre-populated.\nfunc (c *Config) Install(opts options.InstallOptions) (*options.InstallResult, error) {\n\tukiFileName, err := generateNextUKIName(opts.Version, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.setup(opts, ukiFileName)\n}\n\n// Upgrade the bootloader.\n// On upgrade we mount the EFI partition, cleanup old UKIs, copy the new UKI and sd-boot.efi, and update the EFI variables.\nfunc (c *Config) Upgrade(opts options.InstallOptions) (*options.InstallResult, error) {\n\tvar installResult *options.InstallResult\n\n\terr := mount.PartitionOp(\n\t\topts.BootDisk,\n\t\t[]mount.Spec{\n\t\t\t{\n\t\t\t\tPartitionLabel: constants.EFIPartitionLabel,\n\t\t\t\tFilesystemType: partition.FilesystemTypeVFAT,\n\t\t\t\tMountTarget:    filepath.Join(opts.MountPrefix, constants.EFIMountPoint),\n\t\t\t},\n\t\t},\n\t\tfunc() error {\n\t\t\t// list existing UKIs, and clean up all but the current one (used to boot)\n\t\t\tfiles, err := filepath.Glob(filepath.Join(opts.MountPrefix, constants.EFIMountPoint, \"EFI\", \"Linux\", \"Talos-*.efi\"))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\topts.Printf(\"sd-boot: found existing UKIs during upgrade: %v\", xslices.Map(files, filepath.Base))\n\n\t\t\tukiPath, err := generateNextUKIName(opts.Version, files)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to generate next UKI name: %w\", err)\n\t\t\t}\n\n\t\t\tfor _, file := range files {\n\t\t\t\tif strings.EqualFold(filepath.Base(file), c.Default) {\n\t\t\t\t\tif !strings.EqualFold(c.Default, ukiPath) {\n\t\t\t\t\t\t// set fallback to the current default unless it matches the new install\n\t\t\t\t\t\tc.Fallback = c.Default\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\topts.Printf(\"removing old UKI: %s\", file)\n\n\t\t\t\tif err = os.Remove(file); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := c.generateAssets(opts, ukiPath); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tinstallResult, err = c.setup(opts, ukiPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t\t[]blkid.ProbeOption{\n\t\t\t// installation happens with locked blockdevice\n\t\t\tblkid.WithSkipLocking(true),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t\topts.BlkidInfo,\n\t)\n\n\treturn installResult, err\n}\n\n// Install the bootloader.\n//\n// Assumes that EFI partition is already mounted.\n// Writes down the UKI and updates the EFI variables.\n//\n//nolint:gocyclo,cyclop\nfunc (c *Config) setup(opts options.InstallOptions, ukiFileName string) (*options.InstallResult, error) {\n\topts.Printf(\"updating EFI variables\")\n\n\t// set the new entry as a default one\n\tif err := WriteVariable(LoaderEntryDefaultName, ukiFileName); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// set default 5 second boot timeout\n\tif err := WriteVariable(LoaderConfigTimeoutName, \"5\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tefiRW, err := efivarfs.NewFilesystemReaderWriter(true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create efivarfs reader/writer: %w\", err)\n\t}\n\n\tdefer efiRW.Close() //nolint:errcheck\n\n\tblkidInfo, err := blkid.ProbePath(opts.BootDisk, blkid.WithSkipLocking(true))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to probe block device %s: %w\", opts.BootDisk, err)\n\t}\n\n\tsdbootFilename, err := bootloaderutils.Name(opts.Arch)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get sd-boot file path: %w\", err)\n\t}\n\n\tif err := CreateBootEntry(efiRW, blkidInfo, opts.Printf, sdbootFilename); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create boot entry: %w\", err)\n\t}\n\n\tif opts.ExtraInstallStep != nil {\n\t\tif err := opts.ExtraInstallStep(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &options.InstallResult{\n\t\tPreviousLabel: c.Fallback,\n\t}, nil\n}\n\nfunc (c *Config) generateAssets(opts options.InstallOptions, ukiFileName string) error {\n\tif err := os.MkdirAll(filepath.Join(opts.MountPrefix, constants.EFIMountPoint, \"loader\"), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(opts.MountPrefix, constants.EFIMountPoint, \"loader\", \"loader.conf\"), LoaderConfBytes, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tsdbootFilename, err := bootloaderutils.Name(opts.Arch)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get sd-boot file path: %w\", err)\n\t}\n\n\tif err := utils.CopyFiles(\n\t\topts.Printf,\n\t\tutils.SourceDestination(\n\t\t\topts.BootAssets.UKIPath,\n\t\t\tfilepath.Join(opts.MountPrefix, constants.EFIMountPoint, \"EFI\", \"Linux\", ukiFileName),\n\t\t),\n\t\tutils.SourceDestination(\n\t\t\topts.BootAssets.SDBootPath,\n\t\t\tfilepath.Join(opts.MountPrefix, constants.EFIMountPoint, sdbootFilename),\n\t\t),\n\t); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// generateNextUKIName generates the next UKI name based on the version and existing files.\n// It checks for existing files and increments the index if necessary.\nfunc generateNextUKIName(version string, existingFiles []string) (string, error) {\n\tmaxIndex := -1\n\n\tfor _, file := range existingFiles {\n\t\tbase := strings.TrimSuffix(filepath.Base(file), \".efi\")\n\t\tif !strings.HasPrefix(base, \"Talos-\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tsuffix := strings.TrimPrefix(base, \"Talos-\")\n\t\tparts := strings.SplitN(suffix, \"~\", 2)\n\n\t\tif parts[0] != version {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(parts) == 1 {\n\t\t\t// Talos-{version}.efi format\n\t\t\tif maxIndex < 0 {\n\t\t\t\tmaxIndex = 0\n\t\t\t}\n\t\t} else if len(parts) == 2 {\n\t\t\t// Talos-{version}+{index}.efi format\n\t\t\tif idx, err := strconv.Atoi(parts[1]); err == nil && idx > maxIndex {\n\t\t\t\tmaxIndex = idx\n\t\t\t}\n\t\t}\n\t}\n\n\tif maxIndex >= 0 {\n\t\treturn fmt.Sprintf(\"Talos-%s~%d.efi\", version, maxIndex+1), nil\n\t}\n\n\treturn fmt.Sprintf(\"Talos-%s.efi\", version), nil\n}\n\n// Revert the bootloader to the previous version.\nfunc (c *Config) Revert(disk string) error {\n\terr := mount.PartitionOp(\n\t\tdisk,\n\t\t[]mount.Spec{\n\t\t\t{\n\t\t\t\tPartitionLabel: constants.EFIPartitionLabel,\n\t\t\t\tFilesystemType: partition.FilesystemTypeVFAT,\n\t\t\t\tMountTarget:    constants.EFIMountPoint,\n\t\t\t},\n\t\t},\n\t\tc.revert,\n\t\tnil,\n\t\t[]mountv3.ManagerOption{\n\t\t\tmountv3.WithSkipIfMounted(),\n\t\t},\n\t\tnil,\n\t\tnil,\n\t)\n\tif err != nil && !xerrors.TagIs[mount.NotFoundTag](err) {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *Config) revert() error {\n\tfiles, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, \"EFI\", \"Linux\", \"Talos-*.efi\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, file := range files {\n\t\tif strings.EqualFold(filepath.Base(file), c.Default) {\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Printf(\"reverting to previous UKI: %s\", file)\n\n\t\treturn WriteVariable(LoaderEntryDefaultName, filepath.Base(file))\n\t}\n\n\treturn errors.New(\"previous UKI not found\")\n}\n\nfunc findMatchingUKIFile(ukiFiles []string, entry string) (string, bool) {\n\tif slices.ContainsFunc(ukiFiles, func(file string) bool {\n\t\treturn strings.EqualFold(filepath.Base(file), entry)\n\t}) {\n\t\treturn entry, true\n\t}\n\n\treturn \"\", false\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage sdboot_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n)\n\nfunc TestGenerateNextUKIFileName(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, testData := range []struct {\n\t\tname string\n\n\t\tversion          string\n\t\texistingFiles    []string\n\t\texpectedFileName string\n\t}{\n\t\t{\n\t\t\tname:             \"empty_existing_files\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texpectedFileName: \"Talos-1.10.0.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"initial_upgrade_to_same_version\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~1.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"second_upgrade_to_same_version\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\", \"Talos-1.10.0~1.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~2.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"third_upgrade_to_same_version\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0~1.efi\", \"Talos-1.10.0~2.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~3.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"upgrade_with_missing_version_in_index\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0~1.efi\", \"Talos-1.10.0~3.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~4.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"upgrade_with_non-suffixed_file\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\", \"Talos-1.10.0~2.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~3.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"direct_upgrade_to_different_version\",\n\t\t\tversion:          \"1.11.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\"},\n\t\t\texpectedFileName: \"Talos-1.11.0.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"direct_upgrade_to_different_version_with_different_files\",\n\t\t\tversion:          \"1.11.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\", \"Talos-1.10.0~1.efi\"},\n\t\t\texpectedFileName: \"Talos-1.11.0.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"downgrade\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0.efi\", \"Talos-1.11.0.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~1.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"downgrade_with_suffixed_version\",\n\t\t\tversion:          \"1.10.0\",\n\t\t\texistingFiles:    []string{\"Talos-1.10.0~1.efi\", \"Talos-1.11.0.efi\"},\n\t\t\texpectedFileName: \"Talos-1.10.0~2.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"dirty_version_initial\",\n\t\t\tversion:          \"v1.11.0-alpha.3-40-ge4c24983e-dirty\",\n\t\t\texistingFiles:    []string{\"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty.efi\"},\n\t\t\texpectedFileName: \"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty~1.efi\",\n\t\t},\n\t\t{\n\t\t\tname:             \"dirty_suffixed_version\",\n\t\t\tversion:          \"v1.11.0-alpha.3-40-ge4c24983e-dirty\",\n\t\t\texistingFiles:    []string{\"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty~1.efi\", \"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty.efi\"},\n\t\t\texpectedFileName: \"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty~2.efi\",\n\t\t},\n\t} {\n\t\tt.Run(testData.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tukiPath, err := sdboot.GenerateNextUKIName(testData.version, testData.existingFiles)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, testData.expectedFileName, ukiPath)\n\t\t})\n\t}\n}\n\nfunc TestFindMatchingUKIFile(t *testing.T) {\n\tt.Parallel()\n\n\texistingFiles := []string{\n\t\t\"/EFI/boot/Linux/Talos-1.10.0.efi\",\n\t\t\"/EFI/boot/Linux/Talos-1.10.0~1.efi\",\n\t\t\"/EFI/boot/Linux/talos-1.11.0.efi\",\n\t\t\"/EFI/boot/Linux/Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty.efi\",\n\t\t\"/EFI/boot/Linux/Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty~1.efi\",\n\t}\n\n\ttests := []struct {\n\t\texistingFiles  []string\n\t\tentry          string\n\t\texpectedFile   string\n\t\texpectingFound bool\n\t}{\n\t\t{\n\t\t\texistingFiles:  existingFiles,\n\t\t\tentry:          \"Talos-1.10.0.efi\",\n\t\t\texpectedFile:   \"Talos-1.10.0.efi\",\n\t\t\texpectingFound: true,\n\t\t},\n\t\t{\n\t\t\texistingFiles:  existingFiles,\n\t\t\tentry:          \"Talos-1.11.0.efi\",\n\t\t\texpectedFile:   \"Talos-1.11.0.efi\",\n\t\t\texpectingFound: true,\n\t\t},\n\t\t{\n\t\t\texistingFiles:  existingFiles,\n\t\t\tentry:          \"Talos-1.12.0.efi\",\n\t\t\texpectedFile:   \"\",\n\t\t\texpectingFound: false,\n\t\t},\n\t\t{\n\t\t\texistingFiles:  existingFiles,\n\t\t\tentry:          \"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty.efi\",\n\t\t\texpectedFile:   \"Talos-v1.11.0-alpha.3-40-ge4c24983e-dirty.efi\",\n\t\t\texpectingFound: true,\n\t\t},\n\t\t{\n\t\t\tentry:          \"Talos-v1.11.0.efi\",\n\t\t\texpectedFile:   \"\",\n\t\t\texpectingFound: false,\n\t\t},\n\t\t{\n\t\t\tentry:          \"\",\n\t\t\texpectedFile:   \"\",\n\t\t\texpectingFound: false,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tfoundFile, found := sdboot.FindMatchingUKIFile(test.existingFiles, test.entry)\n\n\t\trequire.Equal(t, test.expectingFound, found)\n\t\trequire.Equal(t, test.expectedFile, foundFile)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package v1alpha1 implements a `Runtime`.\npackage v1alpha1\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/akamai.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package akamai contains the Akamai implementation of the [platform.Platform].\npackage akamai\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\takametadata \"github.com/linode/go-metadata\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Akamai is the concrete type that implements the platform.Platform interface.\ntype Akamai struct{}\n\n// Name implements the platform.Platform interface.\nfunc (a *Akamai) Name() string {\n\treturn \"akamai\"\n}\n\n// ParseMetadata converts Akamai platform metadata into platform network config.\nfunc (a *Akamai) ParseMetadata(metadata *akametadata.InstanceData, interfaceAddresses *akametadata.NetworkData) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Label != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Label); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tpublicIPs := make([]string, 0, len(interfaceAddresses.IPv4.Public)+len(interfaceAddresses.IPv6.Ranges))\n\n\t// external IP\n\tfor _, iface := range interfaceAddresses.IPv4.Public {\n\t\tpublicIPs = append(publicIPs, iface.Addr().String())\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\tAddress:     iface,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, iface := range interfaceAddresses.IPv4.Private {\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\tAddress:     iface,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, iface := range interfaceAddresses.IPv6.Ranges {\n\t\tpublicIPs = append(publicIPs, iface.Addr().String())\n\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\tAddress:     iface,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressManagementTemp),\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t},\n\t\t)\n\t}\n\n\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\tnetwork.AddressSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tLinkName:    \"eth0\",\n\t\t\tAddress:     interfaceAddresses.IPv6.LinkLocal,\n\t\t\tScope:       nethelpers.ScopeLink,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t},\n\t)\n\n\tipv6gw, err := netip.ParseAddr(strings.Split(interfaceAddresses.IPv6.LinkLocal.String(), \":\")[0] + \"::1\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\troute := network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tGateway:     ipv6gw,\n\t\tOutLinkName: \"eth0\",\n\t\tDestination: interfaceAddresses.IPv6.LinkLocal,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      nethelpers.FamilyInet6,\n\t\tPriority:    1024,\n\t}\n\n\troute.Normalize()\n\n\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     a.Name(),\n\t\tHostname:     metadata.Label,\n\t\tRegion:       metadata.Region,\n\t\tInstanceType: metadata.Type,\n\t\tInstanceID:   strconv.Itoa(metadata.ID),\n\t\tProviderID:   fmt.Sprintf(\"linode://%d\", metadata.ID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (a *Akamai) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmetadataClient, err := akametadata.NewClient(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"new metadata client: %w\", err)\n\t}\n\n\tuserData, err := metadataClient.GetUserData(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get user data: %w\", err)\n\t}\n\n\tif userData == \"\" {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn []byte(userData), nil\n}\n\n// Mode implements the platform.Platform interface.\nfunc (a *Akamai) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (a *Akamai) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"ttyS0\").Append(\"tty0\").Append(\"tty1\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (a *Akamai) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tmetadataClient, err := akametadata.NewClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"new metadata client: %w\", err)\n\t}\n\n\tmetadata, err := metadataClient.GetInstance(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get instance data: %w\", err)\n\t}\n\n\tmetadataNetworkConfig, err := metadataClient.GetNetwork(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get network data: %w\", err)\n\t}\n\n\tnetworkConfig, err := a.ParseMetadata(metadata, metadataNetworkConfig)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse metadata: %w\", err)\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/akamai_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage akamai_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\takametadata \"github.com/linode/go-metadata\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/akamai\"\n)\n\n//go:embed testdata/instance.json\nvar rawMetadata []byte\n\n//go:embed testdata/network.json\n\nvar rawNetwork []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &akamai.Akamai{}\n\n\tvar metadata akametadata.InstanceData\n\n\tvar interfaceConfig akametadata.NetworkData\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\trequire.NoError(t, json.Unmarshal(rawNetwork, &interfaceConfig))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata, &interfaceConfig)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/expected.yaml",
    "content": "addresses:\n    - address: 172.1.2.3/32\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 192.1.2.3/32\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2600:3c05:d011:797::/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: mngmtmpaddr\n      layer: platform\n    - address: fe80::f03c:93ff:fe6e:5cd9/128\n      linkName: eth0\n      family: inet6\n      scope: link\n      flags: \"\"\n      layer: platform\nlinks: []\nroutes:\n    - family: inet6\n      dst: fe80::f03c:93ff:fe6e:5cd9/128\n      src: \"\"\n      gateway: fe80::1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 172.1.2.3\n    - '2600:3c05:d011:797::'\nmetadata:\n    platform: akamai\n    hostname: talos\n    region: us-east\n    instanceType: g6-standard-1\n    instanceId: \"123456\"\n    providerId: linode://123456\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/instance.json",
    "content": "{\n    \"id\": 123456,\n    \"label\": \"talos\",\n    \"region\": \"us-east\",\n    \"type\": \"g6-standard-1\",\n    \"specs\": {\n        \"vcpus\": 1,\n        \"memory\": 2048,\n        \"gpus\": 0,\n        \"transfer\": 2000,\n        \"disk\": 51200\n    },\n    \"backups\": {\n        \"enabled\": false,\n        \"status\": null\n    },\n    \"host_uuid\": \"0c2897331ea446f483f754852b18a67c\",\n    \"tags\": []\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/akamai/testdata/network.json",
    "content": "{\n    \"interfaces\": [],\n    \"ipv4\": {\n        \"public\": [\n            \"172.1.2.3/32\"\n        ],\n        \"private\": [\n            \"192.1.2.3/32\"\n        ],\n        \"shared\": []\n    },\n    \"ipv6\": {\n        \"slaac\": \"2600:3c06::f03c:93ff:fe6e:5cd9/128\",\n        \"ranges\": [\n            \"2600:3c05:d011:797::/64\"\n        ],\n        \"link_local\": \"fe80::f03c:93ff:fe6e:5cd9/128\",\n        \"shared_ranges\": []\n    }\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/aws/aws.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package aws contains the AWS implementation of the [platform.Platform].\npackage aws\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/feature/ec2/imds\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// AWS is the concrete type that implements the runtime.Platform interface.\ntype AWS struct {\n\tmetadataClient *imds.Client\n}\n\n// NewAWS initializes AWS platform building the IMDS client.\nfunc NewAWS() (*AWS, error) {\n\ta := &AWS{}\n\n\tcfg, err := config.LoadDefaultConfig(context.TODO())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error initializing AWS default config: %w\", err)\n\t}\n\n\ta.metadataClient = imds.NewFromConfig(cfg)\n\n\treturn a, nil\n}\n\n// ParseMetadata converts AWS platform metadata into platform network config.\nfunc (a *AWS) ParseMetadata(metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{\n\t\tTimeServers: []network.TimeServerSpecSpec{\n\t\t\t{\n\t\t\t\tNTPServers: []string{\n\t\t\t\t\t// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configure-ec2-ntp.html\n\t\t\t\t\t//\n\t\t\t\t\t// Include both IPv4 & IPv6 addresses for the NTP servers, Talos would lock to one of them (whichever works),\n\t\t\t\t\t// but it would be compatible with v4-only and v6-only deployments.\n\t\t\t\t\t\"169.254.169.123\",\n\t\t\t\t\t\"fd00:ec2::123\",\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar publicIPs []string\n\n\tif metadata.PublicIPv4 != \"\" {\n\t\tpublicIPs = append(publicIPs, metadata.PublicIPv4)\n\t}\n\n\tif metadata.PublicIPv6 != \"\" {\n\t\tpublicIPs = append(publicIPs, metadata.PublicIPv6)\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     a.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       metadata.Region,\n\t\tZone:         metadata.Zone,\n\t\tInstanceType: metadata.InstanceType,\n\t\tInstanceID:   metadata.InstanceID,\n\t\tProviderID:   fmt.Sprintf(\"aws:///%s/%s\", metadata.Zone, metadata.InstanceID),\n\t\tSpot:         metadata.InstanceLifeCycle == \"spot\",\n\t\tInternalDNS:  metadata.InternalDNS,\n\t\tExternalDNS:  metadata.ExternalDNS,\n\t\tTags:         metadata.Tags,\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Name implements the runtime.Platform interface.\nfunc (a *AWS) Name() string {\n\treturn \"aws\"\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (a *AWS) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from AWS\")\n\n\tuserdata, err := netutils.RetryFetch(ctx, a.fetchConfiguration)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif strings.TrimSpace(userdata) == \"\" {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn []byte(userdata), nil\n}\n\nfunc (a *AWS) fetchConfiguration(ctx context.Context) (string, error) {\n\tresp, err := a.metadataClient.GetUserData(ctx, &imds.GetUserDataInput{})\n\tif err != nil {\n\t\tif isNotFoundError(err) {\n\t\t\treturn \"\", errors.ErrNoConfigSource\n\t\t}\n\n\t\treturn \"\", retry.ExpectedErrorf(\"failed to fetch EC2 userdata: %w\", err)\n\t}\n\n\tdefer resp.Content.Close() //nolint:errcheck\n\n\tuserdata, err := io.ReadAll(resp.Content)\n\n\treturn string(userdata), err\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (a *AWS) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (a *AWS) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (a *AWS) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching aws instance config\")\n\n\tmetadata, err := a.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := a.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/aws/aws_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage aws_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/aws\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestEmpty(t *testing.T) {\n\tp := &aws.AWS{}\n\n\tvar metadata aws.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/aws/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage aws\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-sdk-go-v2/feature/ec2/imds\"\n\tsmithyhttp \"github.com/aws/smithy-go/transport/http\"\n)\n\n// MetadataConfig represents a metadata AWS instance.\ntype MetadataConfig struct {\n\tHostname          string            `json:\"hostname,omitempty\"`\n\tInstanceID        string            `json:\"instance-id,omitempty\"`\n\tInstanceType      string            `json:\"instance-type,omitempty\"`\n\tInstanceLifeCycle string            `json:\"instance-life-cycle,omitempty\"`\n\tPublicIPv4        string            `json:\"public-ipv4,omitempty\"`\n\tPublicIPv6        string            `json:\"ipv6,omitempty\"`\n\tInternalDNS       string            `json:\"local-hostname,omitempty\"`\n\tExternalDNS       string            `json:\"public-hostname,omitempty\"`\n\tRegion            string            `json:\"region,omitempty\"`\n\tZone              string            `json:\"zone,omitempty\"`\n\tTags              map[string]string `json:\"tags,omitempty\"`\n}\n\n//nolint:gocyclo\nfunc (a *AWS) getMetadata(ctx context.Context) (*MetadataConfig, error) {\n\t// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html\n\tgetMetadataKey := func(key string) (string, error) {\n\t\tresp, err := a.metadataClient.GetMetadata(ctx, &imds.GetMetadataInput{\n\t\t\tPath: key,\n\t\t})\n\t\tif err != nil {\n\t\t\tif isNotFoundError(err) {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn \"\", fmt.Errorf(\"failed to fetch %q from IMDS: %w\", key, err)\n\t\t}\n\n\t\tdefer resp.Content.Close() //nolint:errcheck\n\n\t\tv, err := io.ReadAll(resp.Content)\n\n\t\treturn string(v), err\n\t}\n\n\tvar (\n\t\tmetadata MetadataConfig\n\t\terr      error\n\t)\n\tif metadata.Hostname, err = getMetadataKey(\"hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceType, err = getMetadataKey(\"instance-type\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceLifeCycle, err = getMetadataKey(\"instance-life-cycle\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceID, err = getMetadataKey(\"instance-id\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.PublicIPv4, err = getMetadataKey(\"public-ipv4\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.PublicIPv6, err = getMetadataKey(\"ipv6\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InternalDNS, err = getMetadataKey(\"local-hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.ExternalDNS, err = getMetadataKey(\"public-hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.Region, err = getMetadataKey(\"placement/region\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.Zone, err = getMetadataKey(\"placement/availability-zone\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif tags, err := getMetadataKey(\"tags/instance\"); err == nil {\n\t\tmetadata.Tags = make(map[string]string)\n\n\t\tfor key := range strings.FieldsSeq(tags) {\n\t\t\tif value, err := getMetadataKey(\"tags/instance/\" + key); err == nil {\n\t\t\t\tmetadata.Tags[key] = value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &metadata, nil\n}\n\nfunc isNotFoundError(err error) bool {\n\tvar awsErr *smithyhttp.ResponseError\n\tif errors.As(err, &awsErr) {\n\t\treturn awsErr.HTTPStatusCode() == http.StatusNotFound\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/aws/testdata/expected.yaml",
    "content": "addresses: []\nlinks: []\nroutes: []\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers:\n    - timeServers:\n        - 169.254.169.123\n        - fd00:ec2::123\n      layer: platform\noperators: []\nexternalIPs:\n    - 1.2.3.4\nmetadata:\n    platform: aws\n    hostname: talos\n    region: us-east-1\n    zone: us-east-1a\n    instanceId: i-0a0a0a0a0a0a0a0a0\n    providerId: aws:///us-east-1a/i-0a0a0a0a0a0a0a0a0\n    tags:\n        cluster: mycluster\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/aws/testdata/metadata.json",
    "content": "{\n    \"hostname\": \"talos\",\n\t\"instance-id\": \"i-0a0a0a0a0a0a0a0a0\",\n    \"public-ipv4\": \"1.2.3.4\",\n    \"region\": \"us-east-1\",\n    \"zone\": \"us-east-1a\",\n    \"tags\": {\"cluster\": \"mycluster\"}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/azure.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package azure contains the Azure implementation of the [platform.Platform].\npackage azure\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NetworkConfig holds network interface meta config.\ntype NetworkConfig struct {\n\tIPv4 struct {\n\t\tIPAddresses []IPAddresses `json:\"ipAddress\"`\n\t} `json:\"ipv4\"`\n\tIPv6 struct {\n\t\tIPAddresses []IPAddresses `json:\"ipAddress\"`\n\t} `json:\"ipv6\"`\n}\n\n// IPAddresses holds public/private IPs.\ntype IPAddresses struct {\n\tPrivateIPAddress string `json:\"privateIpAddress\"`\n\tPublicIPAddress  string `json:\"publicIpAddress\"`\n}\n\n// LoadBalancerMetadata represents load balancer metadata in IMDS.\ntype LoadBalancerMetadata struct {\n\tLoadBalancer struct {\n\t\tPublicIPAddresses []struct {\n\t\t\tFrontendIPAddress string `json:\"frontendIpAddress,omitempty\"`\n\t\t\tPrivateIPAddress  string `json:\"privateIpAddress,omitempty\"`\n\t\t} `json:\"publicIpAddresses,omitempty\"`\n\t} `json:\"loadbalancer\"`\n}\n\n// Azure is the concrete type that implements the platform.Platform interface.\ntype Azure struct{}\n\n// ovfXML is a simple struct to help us fish custom data out from the ovf-env.xml file.\ntype ovfXML struct {\n\tXMLName    xml.Name `xml:\"Environment\"`\n\tCustomData string   `xml:\"ProvisioningSection>LinuxProvisioningConfigurationSet>CustomData\"`\n}\n\n// Name implements the platform.Platform interface.\nfunc (a *Azure) Name() string {\n\treturn \"azure\"\n}\n\n// ParseMetadata parses Azure network metadata into the platform network config.\n//\n//nolint:gocyclo\nfunc (a *Azure) ParseMetadata(metadata *ComputeMetadata, interfaceAddresses []NetworkConfig, host []byte) (*runtime.PlatformNetworkConfig, error) {\n\tvar networkConfig runtime.PlatformNetworkConfig\n\n\t// hostname\n\tif len(host) > 0 {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(string(host)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar publicIPs []string\n\n\t// external IP\n\tfor _, iface := range interfaceAddresses {\n\t\tfor _, ipv4addr := range iface.IPv4.IPAddresses {\n\t\t\tpublicIPs = append(publicIPs, ipv4addr.PublicIPAddress)\n\t\t}\n\n\t\tfor _, ipv6addr := range iface.IPv6.IPAddresses {\n\t\t\tpublicIPs = append(publicIPs, ipv6addr.PublicIPAddress)\n\t\t}\n\t}\n\n\t// DHCP6 for enabled interfaces\n\tfor idx, iface := range interfaceAddresses {\n\t\tipv6 := false\n\n\t\tfor _, ipv6addr := range iface.IPv6.IPAddresses {\n\t\t\tipv6 = ipv6addr.PublicIPAddress != \"\" || ipv6addr.PrivateIPAddress != \"\"\n\t\t}\n\n\t\tif ipv6 {\n\t\t\tifname := fmt.Sprintf(\"eth%d\", idx)\n\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\tLinkName:  ifname,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\tRouteMetric: 2 * network.DefaultRouteMetric,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\n\t\t\t// If accept_ra is not set, use the default gateway.\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     netip.MustParseAddr(\"fe80::1234:5678:9abc\"),\n\t\t\t\tOutLinkName: ifname,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tPriority:    4 * network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tzone := metadata.FaultDomain\n\tif metadata.Zone != \"\" {\n\t\tzone = fmt.Sprintf(\"%s-%s\", metadata.Location, metadata.Zone)\n\t}\n\n\tproviderID, err := convertResourceGroupNameToLower(metadata.ResourceID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\tOperator:    network.OperatorDHCP4,\n\t\tLinkName:    \"eth0\",\n\t\tRequireUp:   true,\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tnetworkConfig.Links = append(networkConfig.Links,\n\t\tnetwork.LinkSpecSpec{\n\t\t\tName:        \"eth0\",\n\t\t\tUp:          true,\n\t\t\tMTU:         1400,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t)\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     a.Name(),\n\t\tHostname:     metadata.OSProfile.ComputerName,\n\t\tRegion:       strings.ToLower(metadata.Location),\n\t\tZone:         strings.ToLower(zone),\n\t\tInstanceType: metadata.VMSize,\n\t\tInstanceID:   metadata.ResourceID,\n\t\tProviderID:   fmt.Sprintf(\"azure://%s\", providerID),\n\t\tSpot:         metadata.EvictionPolicy != \"\",\n\t}\n\n\treturn &networkConfig, nil\n}\n\n// ParseLoadBalancerIP parses Azure LoadBalancer metadata into the platform external ip list.\nfunc (a *Azure) ParseLoadBalancerIP(lbConfig LoadBalancerMetadata, exIP []netip.Addr) ([]netip.Addr, error) {\n\tlbAddresses := exIP\n\n\tfor _, addr := range lbConfig.LoadBalancer.PublicIPAddresses {\n\t\tipaddr := addr.FrontendIPAddress\n\n\t\tif i := strings.IndexByte(ipaddr, ']'); i != -1 {\n\t\t\tipaddr = strings.TrimPrefix(ipaddr[:i], \"[\")\n\t\t}\n\n\t\tif ip, err := netip.ParseAddr(ipaddr); err == nil {\n\t\t\tlbAddresses = append(lbAddresses, ip)\n\t\t}\n\t}\n\n\treturn lbAddresses, nil\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (a *Azure) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tdefer func() {\n\t\tif err := netutils.Wait(ctx, r); err != nil {\n\t\t\tlog.Printf(\"failed to wait for network, err: %s\", err)\n\t\t}\n\n\t\tif err := linuxAgent(ctx); err != nil {\n\t\t\tlog.Printf(\"failed to update instance status, err: %s\", err)\n\t\t}\n\t}()\n\n\tlog.Printf(\"fetching machine config from ovf-env.xml\")\n\n\t// Custom data is not available in IMDS, so trying to find it on CDROM.\n\treturn a.configFromCD()\n}\n\n// Mode implements the platform.Platform interface.\nfunc (a *Azure) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (a *Azure) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"ttyS0,115200n8\"),\n\t\tprocfs.NewParameter(\"earlyprintk\").Append(\"ttyS0,115200\"),\n\t\tprocfs.NewParameter(\"rootdelay\").Append(\"300\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\tprocfs.NewParameter(constants.KernelParamDashboardDisabled).Append(\"1\"),\n\t\t// disable 'kexec' as Azure VMs sometimes are stuck on kexec, and normal soft reboot\n\t\t// doesn't take much longer on VMs\n\t\tprocfs.NewParameter(\"sysctl.kernel.kexec_load_disabled\").Append(\"1\"),\n\t}\n}\n\n// configFromCD handles looking for devices and trying to mount/fetch xml to get the custom data.\n//\n//nolint:gocyclo\nfunc (a *Azure) configFromCD() ([]byte, error) {\n\tdevList, err := os.ReadDir(\"/dev\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdiskRegex := regexp.MustCompile(\"(sr[0-9]|hd[c-z]|cdrom[0-9]|cd[0-9])\")\n\n\tfor _, dev := range devList {\n\t\tif diskRegex.MatchString(dev.Name()) {\n\t\t\tfmt.Printf(\"found matching device. checking for ovf-env.xml: %s\\n\", dev.Name())\n\n\t\t\t// Mount and slurp xml from disk\n\t\t\tif err = unix.Mount(filepath.Join(\"/dev\", dev.Name()), mnt, \"udf\", unix.MS_RDONLY, \"\"); err != nil {\n\t\t\t\tfmt.Printf(\"unable to mount %s, possibly not udf: %s\", dev.Name(), err.Error())\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tovfEnvFile, err := os.ReadFile(filepath.Join(mnt, \"ovf-env.xml\"))\n\t\t\tif err != nil {\n\t\t\t\t// Device mount worked, but it wasn't the \"CD\" that contains the xml file\n\t\t\t\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn nil, fmt.Errorf(\"failed to read config: %w\", err)\n\t\t\t}\n\n\t\t\tif err = unix.Unmount(mnt, 0); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to unmount: %w\", err)\n\t\t\t}\n\n\t\t\t// Unmarshall xml we slurped\n\t\t\tovfEnvData := ovfXML{}\n\n\t\t\terr = xml.Unmarshal(ovfEnvFile, &ovfEnvData)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif len(ovfEnvData.CustomData) > 0 {\n\t\t\t\tb64CustomData, err := base64.StdEncoding.DecodeString(ovfEnvData.CustomData)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\treturn b64CustomData, nil\n\t\t\t}\n\n\t\t\treturn nil, errors.ErrNoConfigSource\n\t\t}\n\t}\n\n\treturn nil, errors.ErrNoConfigSource\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\n//\n//nolint:gocyclo\nfunc (a *Azure) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tmetadata, apiVersion, err := a.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinterfacesEndpoint := fmt.Sprintf(AzureInterfacesEndpoint, apiVersion)\n\n\tlog.Printf(\"fetching network config from %q\", interfacesEndpoint)\n\n\tmetadataNetworkConfig, err := download.Download(ctx, interfacesEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Metadata\": \"true\"}))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch network config from metadata service: %w\", err)\n\t}\n\n\tvar interfaceAddresses []NetworkConfig\n\n\tif err = json.Unmarshal(metadataNetworkConfig, &interfaceAddresses); err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := a.ParseMetadata(metadata, interfaceAddresses, []byte(metadata.OSProfile.ComputerName))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse network metadata: %w\", err)\n\t}\n\n\tloadbalancerEndpoint := fmt.Sprintf(AzureLoadbalancerEndpoint, apiVersion)\n\n\tlog.Printf(\"fetching load balancer metadata from: %q\", loadbalancerEndpoint)\n\n\tvar loadBalancerAddresses LoadBalancerMetadata\n\n\tlbConfig, err := download.Download(ctx, loadbalancerEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Metadata\": \"true\"}),\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\tif err != nil && !stderrors.Is(err, errors.ErrNoConfigSource) {\n\t\tlog.Printf(\"failed to fetch load balancer config from metadata service: %s\", err)\n\n\t\tlbConfig = nil\n\t}\n\n\tif len(lbConfig) > 0 {\n\t\tif err = json.Unmarshal(lbConfig, &loadBalancerAddresses); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse loadbalancer metadata: %w\", err)\n\t\t}\n\n\t\tnetworkConfig.ExternalIPs, err = a.ParseLoadBalancerIP(loadBalancerAddresses, networkConfig.ExternalIPs)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to define externalIPs: %w\", err)\n\t\t}\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n\n// convertResourceGroupNameToLower converts the resource group name in the resource ID to be lowered.\n// https://github.com/kubernetes-sigs/cloud-provider-azure/blob/4192b264611aebef8070505dd56680a862acfbbf/pkg/provider/azure_wrap.go#L91\nfunc convertResourceGroupNameToLower(resourceID string) (string, error) {\n\t// https://github.com/kubernetes-sigs/cloud-provider-azure/blob/4192b264611aebef8070505dd56680a862acfbbf/pkg/provider/azure_wrap.go#L37\n\tazureResourceGroupNameRE := regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(.+)/providers/(?:.*)`)\n\n\tmatches := azureResourceGroupNameRE.FindStringSubmatch(resourceID)\n\tif len(matches) != 2 {\n\t\treturn \"\", fmt.Errorf(\"%q isn't in Azure resource ID format %q\", resourceID, azureResourceGroupNameRE.String())\n\t}\n\n\tresourceGroup := matches[1]\n\n\treturn strings.Replace(resourceID, resourceGroup, strings.ToLower(resourceGroup), 1), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/azure_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/azure\"\n)\n\n//go:embed testdata/interfaces.json\nvar rawInterfaces []byte\n\n//go:embed testdata/compute.json\nvar rawCompute []byte\n\n//go:embed testdata/loadbalancer.json\nvar rawLoadBalancerMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\ta := &azure.Azure{}\n\n\tvar interfacesMetadata []azure.NetworkConfig\n\n\trequire.NoError(t, json.Unmarshal(rawInterfaces, &interfacesMetadata))\n\n\tvar computeMetadata azure.ComputeMetadata\n\n\trequire.NoError(t, json.Unmarshal(rawCompute, &computeMetadata))\n\n\tnetworkConfig, err := a.ParseMetadata(&computeMetadata, interfacesMetadata, []byte(\"some.fqdn\"))\n\trequire.NoError(t, err)\n\n\tvar lb azure.LoadBalancerMetadata\n\n\trequire.NoError(t, json.Unmarshal(rawLoadBalancerMetadata, &lb))\n\n\tnetworkConfig.ExternalIPs, err = a.ParseLoadBalancerIP(lb, networkConfig.ExternalIPs)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// AzureMetadata documentation\n\t// ref: https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service\n\t// ref: https://github.com/Azure/azure-rest-api-specs/blob/main/specification/imds/data-plane/Microsoft.InstanceMetadataService/stable/2023-07-01/examples/GetInstanceMetadata.json\n\n\t// AzureVersion is the version of the Azure metadata service.\n\tAzureVersion = \"2021-12-13\"\n\n\t// AzureVersionFallback is the fallback version of the Azure metadata service (e.g. Azure Stack Hub).\n\tAzureVersionFallback = \"2019-06-01\"\n\n\t// AzureInternalEndpoint is the Azure Internal Channel IP\n\t// https://blogs.msdn.microsoft.com/mast/2015/05/18/what-is-the-ip-address-168-63-129-16/\n\tAzureInternalEndpoint = \"http://168.63.129.16\"\n\t// AzureMetadataEndpoint is the local endpoint for the metadata.\n\tAzureMetadataEndpoint = \"http://169.254.169.254/metadata/instance/compute?api-version=%s&format=json\"\n\t// AzureInterfacesEndpoint is the local endpoint to get external IPs.\n\tAzureInterfacesEndpoint = \"http://169.254.169.254/metadata/instance/network/interface?api-version=%s&format=json\"\n\t// AzureLoadbalancerEndpoint is the local endpoint for load balancer config.\n\tAzureLoadbalancerEndpoint = \"http://169.254.169.254/metadata/loadbalancer?api-version=%s&format=json\"\n\n\tmnt = \"/mnt\"\n)\n\n// ComputeMetadata represents metadata compute information.\ntype ComputeMetadata struct {\n\tEnvironment string `json:\"azEnvironment,omitempty\"`\n\tSKU         string `json:\"sku,omitempty\"`\n\tName        string `json:\"name,omitempty\"`\n\tZone        string `json:\"zone,omitempty\"`\n\tVMSize      string `json:\"vmSize,omitempty\"`\n\tOSType      string `json:\"osType,omitempty\"`\n\tOSProfile   struct {\n\t\tComputerName string `json:\"computerName,omitempty\"`\n\t} `json:\"osProfile\"`\n\tLocation               string `json:\"location,omitempty\"`\n\tFaultDomain            string `json:\"platformFaultDomain,omitempty\"`\n\tPlatformSubFaultDomain string `json:\"platformSubFaultDomain,omitempty\"`\n\tUpdateDomain           string `json:\"platformUpdateDomain,omitempty\"`\n\tResourceGroup          string `json:\"resourceGroupName,omitempty\"`\n\tResourceID             string `json:\"resourceId,omitempty\"`\n\tVMScaleSetName         string `json:\"vmScaleSetName,omitempty\"`\n\tSubscriptionID         string `json:\"subscriptionId,omitempty\"`\n\tEvictionPolicy         string `json:\"evictionPolicy,omitempty\"`\n}\n\nfunc (a *Azure) getMetadata(ctx context.Context) (*ComputeMetadata, string, error) {\n\tapiVersion := AzureVersion\n\terrBadRequest := stderrors.New(\"bad request\")\n\n\tmetadataEndpoint := fmt.Sprintf(AzureMetadataEndpoint, apiVersion)\n\n\tlog.Printf(\"fetching azure instance config from: %q\", metadataEndpoint)\n\n\tmetadataDl, err := download.Download(ctx, metadataEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Metadata\": \"true\"}),\n\t\tdownload.WithErrorOnBadRequest(errBadRequest),\n\t)\n\tif err != nil && stderrors.Is(err, errBadRequest) {\n\t\tapiVersion = AzureVersionFallback\n\t\tmetadataEndpoint = fmt.Sprintf(AzureMetadataEndpoint, apiVersion)\n\n\t\tlog.Printf(\"fetching azure instance config from: %q\", metadataEndpoint)\n\n\t\tmetadataDl, err = download.Download(ctx, metadataEndpoint,\n\t\t\tdownload.WithHeaders(map[string]string{\"Metadata\": \"true\"}),\n\t\t)\n\t}\n\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"error fetching metadata: %w\", err)\n\t}\n\n\tvar metadata ComputeMetadata\n\n\tif err = json.Unmarshal(metadataDl, &metadata); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"failed to parse compute metadata: %w\", err)\n\t}\n\n\treturn &metadata, apiVersion, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/register.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\n// This should provide the bare minimum to trigger a node in ready condition to allow\n// azure to be happy with the node and let it on it's lawn.\nfunc linuxAgent(ctx context.Context) (err error) {\n\tvar gs *GoalState\n\n\tgs, err = goalState(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to register with Azure and fetch GoalState XML: %w\", err)\n\t}\n\n\treturn reportHealth(ctx, gs.Incarnation, gs.Container.ContainerID, gs.Container.RoleInstanceList.RoleInstance.InstanceID)\n}\n\nfunc goalState(ctx context.Context) (gs *GoalState, err error) {\n\tbody, err := download.Download(ctx, AzureInternalEndpoint+\"/machine/?comp=goalstate\",\n\t\tdownload.WithHeaders(map[string]string{\n\t\t\t\"x-ms-agent-name\": \"WALinuxAgent\",\n\t\t\t\"x-ms-version\":    \"2015-04-05\",\n\t\t\t\"Content-Type\":    \"text/xml;charset=utf-8\",\n\t\t}))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgs = &GoalState{}\n\terr = xml.Unmarshal(body, gs)\n\n\treturn gs, err\n}\n\nfunc reportHealth(ctx context.Context, gsIncarnation, gsContainerID, gsInstanceID string) (err error) {\n\t// Construct health response\n\th := &Health{\n\t\tXsi: \"http://www.w3.org/2001/XMLSchema-instance\",\n\t\tXsd: \"http://www.w3.org/2001/XMLSchema\",\n\t\tWAAgent: WAAgent{\n\t\t\tGoalStateIncarnation: gsIncarnation,\n\t\t\tContainer: &Container{\n\t\t\t\tContainerID: gsContainerID,\n\t\t\t\tRoleInstanceList: &RoleInstanceList{\n\t\t\t\t\tRole: &RoleInstance{\n\t\t\t\t\t\tInstanceID: gsInstanceID,\n\t\t\t\t\t\tHealth: &HealthStatus{\n\t\t\t\t\t\t\tState: \"Ready\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Encode health response as xml\n\tb := new(bytes.Buffer)\n\tb.WriteString(xml.Header)\n\n\terr = xml.NewEncoder(b).Encode(h)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar u *url.URL\n\n\tu, err = url.Parse(AzureInternalEndpoint + \"/machine/?comp=health\")\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\tvar (\n\t\treq  *http.Request\n\t\tresp *http.Response\n\t)\n\n\treq, err = http.NewRequestWithContext(ctx, http.MethodPost, u.String(), b)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\taddHeaders(req)\n\n\tclient := &http.Client{}\n\n\tresp, err = client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO probably should do some better check here ( verify status code )\n\t//nolint:errcheck\n\tdefer resp.Body.Close()\n\n\t_, err = io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn err\n}\n\nfunc addHeaders(req *http.Request) {\n\treq.Header.Add(\"X-Ms-Agent-Name\", \"WALinuxAgent\")\n\treq.Header.Add(\"X-Ms-Version\", \"2015-04-05\")\n\treq.Header.Add(\"Content-Type\", \"text/xml;charset=utf-8\")\n}\n\n// GoalState is the response from the Azure platform when a machine\n// starts up. Ref:\n// https://github.com/Azure/WALinuxAgent/blob/b26feb7822f7d4a19507b6762fe1bd280c2ba2de/bin/waagent2.0#L4331\n// https://github.com/Azure/WALinuxAgent/blob/3be3e1fbf2330303f76961b87d891672e847ce4e/azurelinuxagent/common/protocol/wire.py#L216\ntype GoalState struct {\n\tXMLName xml.Name `xml:\"GoalState\"`\n\tXsi     string   `xml:\"xsi,attr\"`\n\tXsd     string   `xml:\"xsd,attr\"`\n\tWAAgent          //nolint:embeddedstructfieldcheck\n}\n\n// Health is the response from the local machine to Azure to denote current\n// machine state.\ntype Health struct {\n\tXMLName xml.Name `xml:\"Health\"`\n\tXsi     string   `xml:\"xmlns:xsi,attr\"`\n\tXsd     string   `xml:\"xmlns:xsd,attr\"`\n\tWAAgent          //nolint:embeddedstructfieldcheck\n}\n\n// WAAgent contains the meat of the data format that is passed between the\n// Azure platform and the machine.\n// Mostly, we just care about the Incarnation and Container fields here.\ntype WAAgent struct {\n\tText                 string     `xml:\",chardata\"`\n\tVersion              string     `xml:\"Version,omitempty\"`\n\tIncarnation          string     `xml:\"Incarnation,omitempty\"`\n\tGoalStateIncarnation string     `xml:\"GoalStateIncarnation,omitempty\"`\n\tMachine              *Machine   `xml:\"Machine,omitempty\"`\n\tContainer            *Container `xml:\"Container,omitempty\"`\n}\n\n// Container holds the interesting details about a provisioned machine.\ntype Container struct {\n\tText             string            `xml:\",chardata\"`\n\tContainerID      string            `xml:\"ContainerId\"`\n\tRoleInstanceList *RoleInstanceList `xml:\"RoleInstanceList\"`\n}\n\n// RoleInstanceList is a list but only has a single item which is cool I guess.\ntype RoleInstanceList struct {\n\tText         string        `xml:\",chardata\"`\n\tRoleInstance *RoleInstance `xml:\"RoleInstance,omitempty\"`\n\tRole         *RoleInstance `xml:\"Role,omitempty\"`\n}\n\n// RoleInstance contains the specifics for the provisioned VM.\ntype RoleInstance struct {\n\tText          string         `xml:\",chardata\"`\n\tInstanceID    string         `xml:\"InstanceId\"`\n\tState         string         `xml:\"State,omitempty\"`\n\tConfiguration *Configuration `xml:\"Configuration,omitempty\"`\n\tHealth        *HealthStatus  `xml:\"Health,omitempty\"`\n}\n\n// Configuration seems important but isnt really used right now. We could\n// very well not include it because we have no use for it right now, but\n// since we want completeness, we're going to include it.\ntype Configuration struct {\n\tText                     string `xml:\",chardata\"`\n\tHostingEnvironmentConfig string `xml:\"HostingEnvironmentConfig\"`\n\tSharedConfig             string `xml:\"SharedConfig\"`\n\tExtensionsConfig         string `xml:\"ExtensionsConfig\"`\n\tFullConfig               string `xml:\"FullConfig\"`\n\tCertificates             string `xml:\"Certificates\"`\n\tConfigName               string `xml:\"ConfigName\"`\n}\n\n// Machine holds no useful information for us.\ntype Machine struct {\n\tText                  string `xml:\",chardata\"`\n\tExpectedState         string `xml:\"ExpectedState\"`\n\tStopRolesDeadlineHint string `xml:\"StopRolesDeadlineHint\"`\n\tLBProbePorts          *struct {\n\t\tText string `xml:\",chardata\"`\n\t\tPort string `xml:\"Port\"`\n\t} `xml:\"LBProbePorts,omitempty\"`\n\tExpectHealthReport string `xml:\"ExpectHealthReport\"`\n}\n\n// HealthStatus provides mechanism to trigger Azure to understand that our\n// machine has transitioned to a 'Ready' state and is good to go.\n// We can fill out details if we want to be more verbose...\ntype HealthStatus struct {\n\tText    string `xml:\",chardata\"`\n\tState   string `xml:\"State\"`\n\tDetails *struct {\n\t\tText        string `xml:\",chardata\"`\n\t\tSubStatus   string `xml:\"SubStatus\"`\n\t\tDescription string `xml:\"Description\"`\n\t} `xml:\"Details,omitempty\"`\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/testdata/compute.json",
    "content": "{\n    \"location\": \"CentralUS\",\n    \"name\": \"IMDSCanary\",\n    \"offer\": \"RHEL\",\n    \"osProfile\": {\n        \"computerName\": \"examplevmname\"\n    },\n    \"osType\": \"Linux\",\n    \"platformFaultDomain\": \"0\",\n    \"platformUpdateDomain\": \"0\",\n    \"publisher\": \"RedHat\",\n    \"resourceId\": \"/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/Test/providers/Microsoft.Compute/virtualMachines/examplevmname\",\n    \"sku\": \"7.2\",\n    \"version\": \"7.2.20161026\",\n    \"vmId\": \"5c08b38e-4d57-4c23-ac45-aca61037f084\",\n    \"vmSize\": \"Standard_DS2\"\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/testdata/expected.yaml",
    "content": "addresses: []\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 1400\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::1234:5678:9abc\n      outLinkName: eth0\n      table: main\n      priority: 4096\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: some\n      domainname: fqdn\n      layer: platform\nresolvers: []\ntimeServers: []\noperators:\n    - operator: dhcp6\n      linkName: eth0\n      requireUp: true\n      dhcp6:\n        routeMetric: 2048\n      layer: platform\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      layer: platform\nexternalIPs:\n    - 1.2.3.4\n    - 2603:1020:10:5::34\n    - 20.10.5.34\nmetadata:\n    platform: azure\n    hostname: examplevmname\n    region: centralus\n    zone: \"0\"\n    instanceType: Standard_DS2\n    instanceId: /subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/Test/providers/Microsoft.Compute/virtualMachines/examplevmname\n    providerId: azure:///subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/test/providers/Microsoft.Compute/virtualMachines/examplevmname\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/testdata/interfaces.json",
    "content": "[\n    {\n        \"ipv4\": {\n            \"ipAddress\": [\n                {\n                    \"privateIpAddress\": \"172.18.1.10\",\n                    \"publicIpAddress\": \"1.2.3.4\"\n                }\n            ],\n            \"subnet\": [\n                {\n                    \"address\": \"172.18.1.0\",\n                    \"prefix\": \"24\"\n                }\n            ]\n        },\n        \"ipv6\": {\n            \"ipAddress\": [\n                {\n                    \"privateIpAddress\": \"fd00::10\",\n                    \"publicIpAddress\": \"\"\n                }\n            ]\n        },\n        \"macAddress\": \"000D3AD631EE\"\n    }\n]\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/azure/testdata/loadbalancer.json",
    "content": "{\n    \"loadbalancer\": {\n        \"publicIpAddresses\": [\n            {\n                \"frontendIpAddress\": \"[2603:1020:10:5::34]\",\n                \"privateIpAddress\": \"[fd00::10]\"\n            },\n            {\n                \"frontendIpAddress\": \"20.10.5.34\",\n                \"privateIpAddress\": \"172.18.1.10\"\n            }\n        ],\n        \"inboundRules\": [\n            {\n                \"frontendIpAddress\": \"[fd60:172:16:88::5]\",\n                \"protocol\": \"Tcp\",\n                \"frontendPort\": 6443,\n                \"backendPort\": 6443,\n                \"privateIpAddress\": \"[fd00::10]\"\n            },\n            {\n                \"frontendIpAddress\": \"172.16.136.5\",\n                \"protocol\": \"Tcp\",\n                \"frontendPort\": 6443,\n                \"backendPort\": 6443,\n                \"privateIpAddress\": \"172.18.1.10\"\n            }\n        ],\n        \"outboundRules\": []\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack/cloudstack.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cloudstack contains the Cloudstack platform implementation.\npackage cloudstack\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Cloudstack is the concrete type that implements the runtime.Platform interface.\ntype Cloudstack struct{}\n\n// ParseMetadata converts Cloudstack platform metadata into platform network config.\nfunc (e *Cloudstack) ParseMetadata(metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tif metadata.PublicIPv4 != \"\" {\n\t\tif ip, err := netip.ParseAddr(metadata.PublicIPv4); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     e.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       metadata.Zone,\n\t\tZone:         metadata.Zone,\n\t\tInstanceType: strings.ToLower(strings.SplitN(metadata.InstanceType, \" \", 2)[0]),\n\t\tInstanceID:   metadata.InstanceID,\n\t\tProviderID:   fmt.Sprintf(\"cloudstack://%s\", metadata.InstanceID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Name implements the runtime.Platform interface.\nfunc (e *Cloudstack) Name() string {\n\treturn \"cloudstack\"\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (e *Cloudstack) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from %q\", CloudstackUserDataEndpoint)\n\n\treturn download.Download(ctx, CloudstackUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (e *Cloudstack) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (e *Cloudstack) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (e *Cloudstack) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching cloudstack instance config from: %q\", CloudstackMetadataEndpoint)\n\n\tmetadata, err := e.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := e.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack/cloudstack_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cloudstack_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestEmpty(t *testing.T) {\n\tp := &cloudstack.Cloudstack{}\n\n\tvar m cloudstack.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &m))\n\n\tnetworkConfig, err := p.ParseMetadata(&m)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cloudstack\n\nimport (\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// CloudstackMetadataEndpoint is the local Cloudstack endpoint.\n\tCloudstackMetadataEndpoint = \"http://data-server./latest/meta-data\"\n\t// CloudstackUserDataEndpoint is the local Cloudstack endpoint for the config.\n\tCloudstackUserDataEndpoint = \"http://data-server./latest/user-data\"\n)\n\n// MetadataConfig represents a metadata Cloudstack instance.\ntype MetadataConfig struct {\n\tHostname     string `json:\"local-hostname,omitempty\"`\n\tInstanceID   string `json:\"instance-id,omitempty\"`\n\tInstanceType string `json:\"service-offering,omitempty\"`\n\tPublicIPv4   string `json:\"public-ipv4,omitempty\"`\n\tZone         string `json:\"availability-zone,omitempty\"`\n}\n\n/*\nlocal-ipv4\npublic-hostname\nvm-id\npublic-keys\ncloud-identifier\nhypervisor-host-name\n*/\n\nfunc (e *Cloudstack) getMetadata(ctx context.Context) (metadata *MetadataConfig, err error) {\n\tgetMetadataKey := func(key string) (string, error) {\n\t\tres, metaerr := download.Download(ctx, fmt.Sprintf(\"%s/%s\", CloudstackMetadataEndpoint, key),\n\t\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\t\tif metaerr != nil && !stderrors.Is(metaerr, errors.ErrNoConfigSource) {\n\t\t\treturn \"\", fmt.Errorf(\"failed to fetch %q from IMDS: %w\", key, metaerr)\n\t\t}\n\n\t\treturn string(res), nil\n\t}\n\n\tmetadata = &MetadataConfig{}\n\n\tif metadata.Hostname, err = getMetadataKey(\"local-hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceType, err = getMetadataKey(\"service-offering\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceID, err = getMetadataKey(\"instance-id\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.PublicIPv4, err = getMetadataKey(\"public-ipv4\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.Zone, err = getMetadataKey(\"availability-zone\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn metadata, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack/testdata/expected.yaml",
    "content": "addresses: []\nlinks: []\nroutes: []\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 1.2.3.4\nmetadata:\n    platform: cloudstack\n    hostname: talos.fqdn\n    instanceType: standard.tiny\n    instanceId: 3fe6b28a-669e-4eb2-bffd-4180c572c410\n    providerId: cloudstack://3fe6b28a-669e-4eb2-bffd-4180c572c410\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack/testdata/metadata.json",
    "content": "{\n    \"local-hostname\": \"talos.fqdn\",\n    \"instance-id\": \"3fe6b28a-669e-4eb2-bffd-4180c572c410\",\n    \"public-ipv4\": \"1.2.3.4\",\n    \"service-offering\": \"standard.tiny\"\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/container.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package container contains the Container implementation of the [platform.Platform].\npackage container\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Container is a platform for installing Talos via an Container image.\ntype Container struct{}\n\n// Name implements the platform.Platform interface.\nfunc (c *Container) Name() string {\n\treturn \"container\"\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (c *Container) Configuration(context.Context, state.State) ([]byte, error) {\n\tlog.Printf(\"fetching machine config from: USERDATA environment variable\")\n\n\ts := os.Getenv(\"USERDATA\")\n\tif s == \"\" {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\tdecoded, err := base64.StdEncoding.DecodeString(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn decoded, nil\n}\n\n// Mode implements the platform.Platform interface.\nfunc (c *Container) Mode() runtime.Mode {\n\treturn runtime.ModeContainer\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (c *Container) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn nil\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (c *Container) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\thostnameSpec, err := files.ReadHostname(\"/etc/hostname\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\n\tresolverSpec, err := files.ReadResolvConf(\"/etc/resolv.conf\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(resolverSpec.DNSServers) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, resolverSpec)\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     c.Name(),\n\t\tHostname:     hostnameSpec.FQDN(),\n\t\tInstanceType: os.Getenv(\"TALOSSKU\"),\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/hostname.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package files provides internal methods to container platform to read files.\npackage files\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ReadHostname reads and parses /etc/hostname file.\nfunc ReadHostname(path string) (network.HostnameSpecSpec, error) {\n\thostname, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn network.HostnameSpecSpec{}, err\n\t}\n\n\thostname = bytes.TrimSpace(hostname)\n\n\thostnameSpec := network.HostnameSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tif err = hostnameSpec.ParseFQDN(string(hostname)); err != nil {\n\t\treturn network.HostnameSpecSpec{}, err\n\t}\n\n\treturn hostnameSpec, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/hostname_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files\"\n)\n\nfunc TestReadHostname(t *testing.T) {\n\tt.Parallel()\n\n\tspec, err := files.ReadHostname(\"testdata/hostname\")\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"foo\", spec.Hostname)\n\trequire.Equal(t, \"example.com\", spec.Domainname)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/resolv.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"bytes\"\n\t\"net/netip\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// ReadResolvConf reads and parses /etc/resolv.conf file.\nfunc ReadResolvConf(path string) (network.ResolverSpecSpec, error) {\n\tresolverSpec := network.ResolverSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tresolvers, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn resolverSpec, err\n\t}\n\n\tfor line := range bytes.SplitSeq(resolvers, []byte(\"\\n\")) {\n\t\tline = bytes.TrimSpace(line)\n\t\tline, _, _ = bytes.Cut(line, []byte(\"#\"))\n\n\t\tif !bytes.HasPrefix(line, []byte(\"nameserver\")) {\n\t\t\tcontinue\n\t\t}\n\n\t\tline = bytes.TrimSpace(bytes.TrimPrefix(line, []byte(\"nameserver\")))\n\n\t\tif addr, err := netip.ParseAddr(string(line)); err == nil {\n\t\t\tresolverSpec.DNSServers = append(resolverSpec.DNSServers, addr)\n\t\t}\n\t}\n\n\treturn resolverSpec, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/resolv_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files\"\n)\n\nfunc TestReadResolvConf(t *testing.T) {\n\tt.Parallel()\n\n\tspec, err := files.ReadResolvConf(\"testdata/resolv.conf\")\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, []netip.Addr{\n\t\tnetip.MustParseAddr(\"127.0.0.53\"),\n\t\tnetip.MustParseAddr(\"::1\"),\n\t}, spec.DNSServers)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/testdata/hostname",
    "content": "foo.example.com\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/container/internal/files/testdata/resolv.conf",
    "content": "# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).\n# Do not edit.\n\nnameserver 127.0.0.53 # v4 one\noptions edns0 trust-ad\nsearch .\n\n  nameserver ::1   # this is V6\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean/digitalocean.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package digitalocean contains the Digital Ocean implementation of the [platform.Platform].\npackage digitalocean\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/address\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// DigitalOcean is the concrete type that implements the platform.Platform interface.\ntype DigitalOcean struct{}\n\n// Name implements the platform.Platform interface.\nfunc (d *DigitalOcean) Name() string {\n\treturn \"digital-ocean\"\n}\n\n// ParseMetadata converts DigitalOcean platform metadata into platform network config.\n//\n//nolint:gocyclo,cyclop\nfunc (d *DigitalOcean) ParseMetadata(metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tif len(metadata.DNS.Nameservers) > 0 {\n\t\tvar dnsIPs []netip.Addr\n\n\t\tfor _, dnsIP := range metadata.DNS.Nameservers {\n\t\t\tif ip, err := netip.ParseAddr(dnsIP); err == nil {\n\t\t\t\tdnsIPs = append(dnsIPs, ip)\n\t\t\t}\n\t\t}\n\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:  dnsIPs,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tvar publicIPs []string\n\n\tfor _, iface := range metadata.Interfaces[\"public\"] {\n\t\tif iface.IPv4 != nil {\n\t\t\tifAddr, err := address.IPPrefixFrom(iface.IPv4.IPAddress, iface.IPv4.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tpublicIPs = append(publicIPs, iface.IPv4.IPAddress)\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tAddress:     ifAddr,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif iface.IPv4.Gateway != \"\" {\n\t\t\t\tgw, err := netip.ParseAddr(iface.IPv4.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to parse gateway ip: %w\", err)\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\n\t\t\t\tmetaServer, _ := netip.ParsePrefix(\"169.254.169.254/32\") //nolint:errcheck\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tDestination: metaServer,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    512,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tif iface.IPv6 != nil {\n\t\t\tifAddr, err := address.IPPrefixFrom(iface.IPv6.IPAddress, strconv.Itoa(iface.IPv6.CIDR))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tpublicIPs = append(publicIPs, iface.IPv6.IPAddress)\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tAddress:     ifAddr,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif iface.IPv6.Gateway != \"\" {\n\t\t\t\tgw, err := netip.ParseAddr(iface.IPv6.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to parse gateway ip: %w\", err)\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t}\n\t\t}\n\n\t\tif iface.AnchorIPv4 != nil {\n\t\t\tifAddr, err := address.IPPrefixFrom(iface.AnchorIPv4.IPAddress, iface.AnchorIPv4.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tAddress:     ifAddr,\n\t\t\t\t\tScope:       nethelpers.ScopeLink,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\tfor idx, iface := range metadata.Interfaces[\"private\"] {\n\t\tifName := fmt.Sprintf(\"eth%d\", idx+1)\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        ifName,\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tif iface.IPv4 != nil {\n\t\t\tifAddr, err := address.IPPrefixFrom(iface.IPv4.IPAddress, iface.IPv4.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    ifName,\n\t\t\t\t\tAddress:     ifAddr,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:   d.Name(),\n\t\tHostname:   metadata.Hostname,\n\t\tRegion:     metadata.Region,\n\t\tInstanceID: strconv.Itoa(metadata.DropletID),\n\t\tProviderID: fmt.Sprintf(\"digitalocean://%d\", metadata.DropletID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (d *DigitalOcean) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", DigitalOceanUserDataEndpoint)\n\n\treturn download.Download(ctx, DigitalOceanUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the platform.Platform interface.\nfunc (d *DigitalOcean) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (d *DigitalOcean) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"ttyS0\").Append(\"tty0\").Append(\"tty1\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (d *DigitalOcean) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching DigitalOcean instance config from: %q \", DigitalOceanMetadataEndpoint)\n\n\tmetadata, err := d.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := d.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean/digitalocean_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage digitalocean_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &digitalocean.DigitalOcean{}\n\n\tvar metadata digitalocean.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage digitalocean\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\tstderrors \"errors\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// DigitalOceanExternalIPEndpoint displays all external addresses associated with the instance.\n\tDigitalOceanExternalIPEndpoint = \"http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address\"\n\t// DigitalOceanMetadataEndpoint is the local endpoint for the platform metadata.\n\tDigitalOceanMetadataEndpoint = \"http://169.254.169.254/metadata/v1.json\"\n\t// DigitalOceanUserDataEndpoint is the local endpoint for the config.\n\tDigitalOceanUserDataEndpoint = \"http://169.254.169.254/metadata/v1/user-data\"\n)\n\n// MetadataConfig represents a metadata Digital Ocean instance.\ntype MetadataConfig struct {\n\tHostname   string   `json:\"hostname,omitempty\"`\n\tDropletID  int      `json:\"droplet_id,omitempty\"`\n\tRegion     string   `json:\"region,omitempty\"`\n\tPublicIPv4 string   `json:\"public-ipv4,omitempty\"`\n\tTags       []string `json:\"tags,omitempty\"`\n\n\tDNS struct {\n\t\tNameservers []string `json:\"nameservers,omitempty\"`\n\t} `json:\"dns\"`\n\tInterfaces map[string][]struct {\n\t\tMACAddress string `json:\"mac,omitempty\"`\n\t\tType       string `json:\"type,omitempty\"`\n\n\t\tIPv4 *struct {\n\t\t\tIPAddress string `json:\"ip_address,omitempty\"`\n\t\t\tNetmask   string `json:\"netmask,omitempty\"`\n\t\t\tGateway   string `json:\"gateway,omitempty\"`\n\t\t} `json:\"ipv4,omitempty\"`\n\t\tIPv6 *struct {\n\t\t\tIPAddress string `json:\"ip_address,omitempty\"`\n\t\t\tCIDR      int    `json:\"cidr,omitempty\"`\n\t\t\tGateway   string `json:\"gateway,omitempty\"`\n\t\t} `json:\"ipv6,omitempty\"`\n\t\tAnchorIPv4 *struct {\n\t\t\tIPAddress string `json:\"ip_address,omitempty\"`\n\t\t\tNetmask   string `json:\"netmask,omitempty\"`\n\t\t\tGateway   string `json:\"gateway,omitempty\"`\n\t\t} `json:\"anchor_ipv4,omitempty\"`\n\t} `json:\"interfaces,omitempty\"`\n}\n\nfunc (d *DigitalOcean) getMetadata(ctx context.Context) (*MetadataConfig, error) {\n\tmetaConfigDl, err := download.Download(ctx, DigitalOceanMetadataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoHostname),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoHostname))\n\tif err != nil && !stderrors.Is(err, errors.ErrNoHostname) {\n\t\treturn nil, err\n\t}\n\n\tvar metadata MetadataConfig\n\tif err = json.Unmarshal(metaConfigDl, &metadata); err != nil {\n\t\treturn nil, err\n\t}\n\n\textIP, err := download.Download(ctx, DigitalOceanExternalIPEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoExternalIPs),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoExternalIPs))\n\tif err != nil && !stderrors.Is(err, errors.ErrNoExternalIPs) {\n\t\treturn nil, err\n\t}\n\n\tmetadata.PublicIPv4 = string(extIP)\n\n\treturn &metadata, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean/testdata/expected.yaml",
    "content": "addresses:\n    - address: 128.199.52.32/19\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2a03:b0c0:2:d0::1478:3001/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.18.0.5/16\n      linkName: eth0\n      family: inet4\n      scope: link\n      flags: permanent\n      layer: platform\n    - address: 10.133.0.2/16\n      linkName: eth1\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 128.199.32.1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 169.254.169.254/32\n      src: \"\"\n      gateway: 128.199.32.1\n      outLinkName: eth0\n      table: main\n      priority: 512\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: 2a03:b0c0:2:d0::1\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: debian-s-1vcpu-512mb-10gb-ams3-01\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 67.207.67.2\n        - 67.207.67.3\n      layer: platform\ntimeServers: []\noperators: []\nexternalIPs:\n    - 128.199.52.32\n    - 2a03:b0c0:2:d0::1478:3001\nmetadata:\n    platform: digital-ocean\n    hostname: debian-s-1vcpu-512mb-10gb-ams3-01\n    region: ams3\n    instanceId: \"320206672\"\n    providerId: digitalocean://320206672\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean/testdata/metadata.json",
    "content": "{\n    \"droplet_id\": 320206672,\n    \"hostname\": \"debian-s-1vcpu-512mb-10gb-ams3-01\",\n    \"user_data\": \"\",\n    \"vendor_data\": \"\",\n    \"public_keys\": [],\n    \"auth_key\": \"490eac0a2fc04503267ef85064407f2f\",\n    \"region\": \"ams3\",\n    \"interfaces\": {\n        \"private\": [\n            {\n                \"ipv4\": {\n                    \"ip_address\": \"10.133.0.2\",\n                    \"netmask\": \"255.255.0.0\",\n                    \"gateway\": \"10.133.0.1\"\n                },\n                \"mac\": \"2a:3c:79:3d:f3:b7\",\n                \"type\": \"private\"\n            }\n        ],\n        \"public\": [\n            {\n                \"ipv4\": {\n                    \"ip_address\": \"128.199.52.32\",\n                    \"netmask\": \"255.255.224.0\",\n                    \"gateway\": \"128.199.32.1\"\n                },\n                \"ipv6\": {\n                    \"ip_address\": \"2A03:B0C0:0002:00D0:0000:0000:1478:3001\",\n                    \"cidr\": 64,\n                    \"gateway\": \"2a03:b0c0:2:d0::1\"\n                },\n                \"anchor_ipv4\": {\n                    \"ip_address\": \"10.18.0.5\",\n                    \"netmask\": \"255.255.0.0\",\n                    \"gateway\": \"10.18.0.1\"\n                },\n                \"mac\": \"12:2f:49:0c:eb:c0\",\n                \"type\": \"public\"\n            }\n        ]\n    },\n    \"floating_ip\": {\n        \"ipv4\": {\n            \"active\": false\n        }\n    },\n    \"reserved_ip\": {\n        \"ipv4\": {\n            \"active\": false\n        }\n    },\n    \"dns\": {\n        \"nameservers\": [\n            \"67.207.67.2\",\n            \"67.207.67.3\"\n        ]\n    },\n    \"tags\": [\n        \"label123\"\n    ],\n    \"features\": {\n        \"dhcp_enabled\": false\n    },\n    \"modify_index\": 113261986,\n    \"dotty_status\": \"running\",\n    \"ssh_info\": {\n        \"port\": 22\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/equinix.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package equinixmetal contains the Equinix Metal implementation of the [platform.Platform].\npackage equinixmetal\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Event holds data to pass to the Equinix Metal event URL.\ntype Event struct {\n\tType    string `json:\"type\"`\n\tMessage string `json:\"msg\"`\n}\n\n// Network holds network info from the equinixmetal metadata.\ntype Network struct {\n\tBonding    Bonding     `json:\"bonding\"`\n\tInterfaces []Interface `json:\"interfaces\"`\n\tAddresses  []Address   `json:\"addresses\"`\n}\n\n// Bonding holds bonding info from the equinixmetal metadata.\ntype Bonding struct {\n\tMode int `json:\"mode\"`\n}\n\n// Interface holds interface info from the equinixmetal metadata.\ntype Interface struct {\n\tName string `json:\"name\"`\n\tMAC  string `json:\"mac\"`\n\tBond string `json:\"bond\"`\n}\n\n// Address holds address info from the equinixmetal metadata.\ntype Address struct {\n\tPublic     bool   `json:\"public\"`\n\tManagement bool   `json:\"management\"`\n\tEnabled    bool   `json:\"enabled\"`\n\tCIDR       int    `json:\"cidr\"`\n\tFamily     int    `json:\"address_family\"`\n\tNetmask    string `json:\"netmask\"`\n\tNetwork    string `json:\"network\"`\n\tAddress    string `json:\"address\"`\n\tGateway    string `json:\"gateway\"`\n}\n\n// BGPNeighbor holds BGP neighbor info from the equinixmetal metadata.\ntype BGPNeighbor struct {\n\tAddressFamily int      `json:\"address_family\"`\n\tPeerIPs       []string `json:\"peer_ips\"`\n}\n\nconst (\n\t// EquinixMetalUserDataEndpoint is the local metadata endpoint for Equinix.\n\tEquinixMetalUserDataEndpoint = \"https://metadata.platformequinix.com/userdata\"\n\t// EquinixMetalMetaDataEndpoint is the local endpoint for machine info like networking.\n\tEquinixMetalMetaDataEndpoint = \"https://metadata.platformequinix.com/metadata\"\n)\n\n// EquinixMetal is a platform for EquinixMetal Metal cloud.\ntype EquinixMetal struct{}\n\n// Name implements the platform.Platform interface.\nfunc (p *EquinixMetal) Name() string {\n\treturn \"equinixMetal\"\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (p *EquinixMetal) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", EquinixMetalUserDataEndpoint)\n\n\treturn download.Download(ctx, EquinixMetalUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the platform.Platform interface.\nfunc (p *EquinixMetal) Mode() runtime.Mode {\n\treturn runtime.ModeMetal\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (p *EquinixMetal) KernelArgs(arch string, _ quirks.Quirks) procfs.Parameters {\n\tswitch arch {\n\tcase \"amd64\":\n\t\treturn []*procfs.Parameter{\n\t\t\tprocfs.NewParameter(\"console\").Append(\"ttyS1,115200n8\"),\n\t\t}\n\tcase \"arm64\":\n\t\treturn []*procfs.Parameter{\n\t\t\tprocfs.NewParameter(\"console\").Append(\"ttyAMA0,115200\"),\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// ParseMetadata converts Equinix Metal metadata into Talos network configuration.\n//\n//nolint:gocyclo,cyclop\nfunc (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *MetadataConfig, st state.State) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\t// 1. Links\n\n\t// translate the int returned from bond mode metadata to the type needed by network resources\n\tbondMode := nethelpers.BondMode(uint8(equinixMetadata.Network.Bonding.Mode))\n\n\thostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing host interfaces: %w\", err)\n\t}\n\n\tbondSlaveIndexes := map[string]int{}\n\tfirstBond := \"\"\n\n\tfor _, iface := range equinixMetadata.Network.Interfaces {\n\t\tif iface.Bond == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif firstBond == \"\" {\n\t\t\tfirstBond = iface.Bond\n\t\t}\n\n\t\tfound := false\n\n\t\tfor hostInterface := range hostInterfaces.All() {\n\t\t\t// match using permanent MAC address:\n\t\t\t// - bond interfaces don't have permanent addresses set, so we skip them this way\n\t\t\t// - if the bond is already configured, regular hardware address is overwritten with bond address\n\t\t\tif hostInterface.TypedSpec().PermanentAddr.String() == iface.MAC {\n\t\t\t\tfound = true\n\n\t\t\t\tslaveIndex := bondSlaveIndexes[iface.Bond]\n\n\t\t\t\tnetworkConfig.Links = append(networkConfig.Links,\n\t\t\t\t\tnetwork.LinkSpecSpec{\n\t\t\t\t\t\tName: hostInterface.Metadata().ID(),\n\t\t\t\t\t\tUp:   true,\n\t\t\t\t\t\tBondSlave: network.BondSlave{\n\t\t\t\t\t\t\tMasterName: iface.Bond,\n\t\t\t\t\t\t\tSlaveIndex: slaveIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t})\n\n\t\t\t\tbondSlaveIndexes[iface.Bond]++\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\tlog.Printf(\"interface with MAC %q wasn't found on the host, adding with the name from metadata\", iface.MAC)\n\n\t\t\tslaveIndex := bondSlaveIndexes[iface.Bond]\n\n\t\t\tnetworkConfig.Links = append(networkConfig.Links,\n\t\t\t\tnetwork.LinkSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tName:        iface.Name,\n\t\t\t\t\tUp:          true,\n\t\t\t\t\tBondSlave: network.BondSlave{\n\t\t\t\t\t\tMasterName: iface.Bond,\n\t\t\t\t\t\tSlaveIndex: slaveIndex,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\tbondSlaveIndexes[iface.Bond]++\n\t\t}\n\t}\n\n\tbondNames := maps.Keys(bondSlaveIndexes)\n\tslices.Sort(bondNames)\n\n\tfor _, bondName := range bondNames {\n\t\tbondLink := network.LinkSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tName:        bondName,\n\t\t\tLogical:     true,\n\t\t\tUp:          true,\n\t\t\tKind:        network.LinkKindBond,\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tBondMaster: network.BondMasterSpec{\n\t\t\t\tMode:       bondMode,\n\t\t\t\tDownDelay:  200,\n\t\t\t\tMIIMon:     100,\n\t\t\t\tUpDelay:    200,\n\t\t\t\tHashPolicy: nethelpers.BondXmitPolicyLayer34,\n\t\t\t},\n\t\t}\n\n\t\tif bondMode == nethelpers.BondMode8023AD {\n\t\t\tbondLink.BondMaster.ADLACPActive = nethelpers.ADLACPActiveOn\n\t\t}\n\n\t\tnetworkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, bondLink)\n\t}\n\n\t// 2. addresses\n\n\tvar publicIPs []string\n\n\tfor _, addr := range equinixMetadata.Network.Addresses {\n\t\tif !(addr.Enabled && addr.Management) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif addr.Public {\n\t\t\tpublicIPs = append(publicIPs, addr.Address)\n\t\t}\n\n\t\tipAddr, err := netip.ParsePrefix(fmt.Sprintf(\"%s/%d\", addr.Address, addr.CIDR))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfamily := nethelpers.FamilyInet4\n\t\tif ipAddr.Addr().Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    firstBond,\n\t\t\t\tAddress:     ipAddr,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      family,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\t// 3. routes\n\tvar privateGateway netip.Addr\n\n\tfor _, addr := range equinixMetadata.Network.Addresses {\n\t\tif !(addr.Enabled && addr.Management) {\n\t\t\tcontinue\n\t\t}\n\n\t\tipAddr, err := netip.ParsePrefix(fmt.Sprintf(\"%s/%d\", addr.Address, addr.CIDR))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfamily := nethelpers.FamilyInet4\n\t\tif ipAddr.Addr().Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\tif addr.Public {\n\t\t\t// for \"Public\" address add the default route\n\t\t\tgw, err := netip.ParseAddr(addr.Gateway)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: firstBond,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      family,\n\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\tif addr.Family == 6 {\n\t\t\t\troute.Priority = 2 * network.DefaultRouteMetric\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t} else {\n\t\t\t// for \"Private\" addresses, we add a route that goes out the gateway for the private subnets.\n\t\t\tfor _, privSubnet := range equinixMetadata.PrivateSubnets {\n\t\t\t\tgw, err := netip.ParseAddr(addr.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tprivateGateway = gw\n\n\t\t\t\tdest, err := netip.ParsePrefix(privSubnet)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tDestination: dest,\n\t\t\t\t\tOutLinkName: firstBond,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      family,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. hostname\n\n\tif equinixMetadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(equinixMetadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\t// 5. platform metadata\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     p.Name(),\n\t\tHostname:     equinixMetadata.Hostname,\n\t\tRegion:       equinixMetadata.Metro,\n\t\tZone:         equinixMetadata.Facility,\n\t\tInstanceType: equinixMetadata.Plan,\n\t\tInstanceID:   equinixMetadata.ID,\n\t\tProviderID:   fmt.Sprintf(\"equinixmetal://%s\", equinixMetadata.ID),\n\t}\n\n\t// 6. BGP neighbors\n\n\tfor _, bgpNeighbor := range equinixMetadata.BGPNeighbors {\n\t\tif bgpNeighbor.AddressFamily != 4 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, peerIP := range bgpNeighbor.PeerIPs {\n\t\t\tpeer, err := netip.ParseAddr(peerIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     privateGateway,\n\t\t\t\tDestination: netip.PrefixFrom(peer, 32),\n\t\t\t\tOutLinkName: firstBond,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\t}\n\n\treturn networkConfig, nil\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (p *EquinixMetal) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching equinix network config from: %q\", EquinixMetalMetaDataEndpoint)\n\n\tmetadataConfig, err := download.Download(ctx, EquinixMetalMetaDataEndpoint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar meta MetadataConfig\n\tif err = json.Unmarshal(metadataConfig, &meta); err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := p.ParseMetadata(ctx, &meta, st)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase ch <- networkConfig:\n\t}\n\n\treturn nil\n}\n\n// FireEvent will take an event and pass it to an events server.\n// nb: This is currently only used with Equinix Metal but we may find interesting ways\n// to extend it for other event servers (Azure may have something similar?)\nfunc (p *EquinixMetal) FireEvent(ctx context.Context, event Event) error {\n\tvar eventURL *string\n\tif eventURL = procfs.ProcCmdline().Get(constants.KernelParamEquinixMetalEvents).First(); eventURL == nil {\n\t\treturn errors.ErrNoEventURL\n\t}\n\n\teventData, err := json.Marshal(event)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = retry.Constant(5*time.Minute,\n\t\tretry.WithUnits(time.Second),\n\t\tretry.WithErrorLogging(true)).RetryWithContext(\n\t\tctx,\n\t\tfunc(ctx context.Context) error {\n\t\t\treq, reqErr := http.NewRequestWithContext(ctx, http.MethodPost, *eventURL, bytes.NewReader(eventData))\n\t\t\tif reqErr != nil {\n\t\t\t\treturn reqErr\n\t\t\t}\n\n\t\t\tresp, reqErr := http.DefaultClient.Do(req)\n\t\t\tif resp != nil {\n\t\t\t\tio.Copy(io.Discard, io.LimitReader(resp.Body, 4*1024*1024)) //nolint:errcheck\n\t\t\t\tresp.Body.Close()                                           //nolint:errcheck\n\t\t\t}\n\n\t\t\treturn retry.ExpectedError(reqErr)\n\t\t},\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/equinix_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage equinixmetal_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\n//go:embed testdata/metadata-2bonds.json\nvar rawMetadata2Bonds []byte\n\n//go:embed testdata/expected-2bonds.yaml\nvar expectedNetworkConfig2Bonds string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &equinixmetal.EquinixMetal{}\n\n\tvar m equinixmetal.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &m))\n\n\tctx := t.Context()\n\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\teth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf8}\n\trequire.NoError(t, st.Create(ctx, eth1))\n\n\teth2 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\teth2.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9}\n\trequire.NoError(t, st.Create(ctx, eth2))\n\n\tnetworkConfig, err := p.ParseMetadata(ctx, &m, st)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n\nfunc TestParseMetadata2Bonds(t *testing.T) {\n\tp := &equinixmetal.EquinixMetal{}\n\n\tvar m equinixmetal.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata2Bonds, &m))\n\n\tctx := t.Context()\n\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\teth0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xe4, 0x43, 0x4b, 0xd0, 0x7b, 0x50}\n\trequire.NoError(t, st.Create(ctx, eth0))\n\n\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\teth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xe4, 0x43, 0x4b, 0xd0, 0x7b, 0x51}\n\trequire.NoError(t, st.Create(ctx, eth1))\n\n\teth2 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\teth2.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xe4, 0x43, 0x4b, 0xd0, 0x7b, 0x52}\n\trequire.NoError(t, st.Create(ctx, eth2))\n\n\teth3 := network.NewLinkStatus(network.NamespaceName, \"eth3\")\n\teth3.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xe4, 0x43, 0x4b, 0xd0, 0x7b, 0x53}\n\trequire.NoError(t, st.Create(ctx, eth3))\n\n\tnetworkConfig, err := p.ParseMetadata(ctx, &m, st)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tfmt.Println(string(marshaled))\n\n\tassert.Equal(t, expectedNetworkConfig2Bonds, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage equinixmetal\n\n// MetadataConfig holds equinixmetal metadata info.\ntype MetadataConfig struct {\n\tID             string        `json:\"id\"`\n\tHostname       string        `json:\"hostname\"`\n\tPlan           string        `json:\"plan\"`\n\tMetro          string        `json:\"metro\"`\n\tFacility       string        `json:\"facility\"`\n\tNetwork        Network       `json:\"network\"`\n\tBGPNeighbors   []BGPNeighbor `json:\"bgp_neighbors\"`\n\tPrivateSubnets []string      `json:\"private_subnets\"`\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/testdata/expected-2bonds.yaml",
    "content": "addresses:\n    - address: 147.28.162.183/31\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2604:1380:45f2:6f00::1/127\n      linkName: bond0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.68.217.1/31\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond1\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      slaveIndex: 1\n      layer: platform\n    - name: eth3\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond1\n      slaveIndex: 1\n      layer: platform\n    - name: bond0\n      logical: true\n      up: true\n      mtu: 0\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: slow\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\n    - name: bond1\n      logical: true\n      up: true\n      mtu: 0\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: slow\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 147.28.162.182\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: '2604:1380:45f2:6f00::'\n      outLinkName: bond0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 10.68.217.0\n      outLinkName: bond0\n      table: main\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: devcluster-38uvi6\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 147.28.162.183\n    - 2604:1380:45f2:6f00::1\nmetadata:\n    platform: equinixMetal\n    hostname: devcluster-38uvi6\n    region: dc\n    zone: dc13\n    instanceType: n2.xlarge.x86\n    instanceId: b45359b0-5a13-454b-82eb-d4959924f9f0\n    providerId: equinixmetal://b45359b0-5a13-454b-82eb-d4959924f9f0\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/testdata/expected.yaml",
    "content": "addresses:\n    - address: 147.75.78.41/31\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2604:1380:45d1:fd00::11/127\n      linkName: bond0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.66.142.17/31\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      slaveIndex: 1\n      layer: platform\n    - name: bond0\n      logical: true\n      up: true\n      mtu: 0\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: slow\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 147.75.78.40\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: 2604:1380:45d1:fd00::10\n      outLinkName: bond0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 10.66.142.16\n      outLinkName: bond0\n      table: main\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 169.254.255.1/32\n      src: \"\"\n      gateway: 10.66.142.16\n      outLinkName: bond0\n      table: main\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 169.254.255.2/32\n      src: \"\"\n      gateway: 10.66.142.16\n      outLinkName: bond0\n      table: main\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: infra-green-ci\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 147.75.78.41\n    - 2604:1380:45d1:fd00::11\nmetadata:\n    platform: equinixMetal\n    hostname: infra-green-ci\n    region: ny\n    zone: ny5\n    instanceType: c3.medium.x86\n    instanceId: X\n    providerId: equinixmetal://X\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/testdata/metadata-2bonds.json",
    "content": "{\n    \"id\": \"b45359b0-5a13-454b-82eb-d4959924f9f0\",\n    \"hostname\": \"devcluster-38uvi6\",\n    \"iqn\": \"iqn.2024-05.net.packet:device.b45359b0\",\n    \"operating_system\": {\n      \"slug\": \"custom_ipxe\",\n      \"version\": \"1\",\n      \"distro\": \"custom_ipxe\",\n      \"license_activation\": { \"state\": \"unlicensed\" },\n      \"image_tag\": null\n    },\n    \"plan\": \"n2.xlarge.x86\",\n    \"reserved\": false,\n    \"class\": \"n2.xlarge.x86\",\n    \"facility\": \"dc13\",\n    \"metro\": \"dc\",\n    \"private_subnets\": [\"10.0.0.0/8\"],\n    \"tags\": [],\n    \"ssh_keys\": [\n    ],\n    \"customdata\": {},\n    \"specs\": {\n      \"cpus\": [\n        { \"count\": 2, \"type\": \"Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz\" }\n      ],\n      \"memory\": { \"total\": \"384GB\" },\n      \"drives\": [\n        { \"count\": 2, \"size\": \"120GB\", \"type\": \"SSD\", \"category\": \"boot\" },\n        { \"count\": 1, \"size\": \"3.8TB\", \"type\": \"NVME\", \"category\": \"storage\" }\n      ],\n      \"nics\": [{ \"count\": 4, \"type\": \"10Gbps\" }],\n      \"features\": { \"uefi\": false }\n    },\n    \"switch_short_id\": \"5b2b2148\",\n    \"state\": \"active\",\n    \"storage_source\": \"default\",\n    \"storage\": {\n      \"disks\": [\n        {\n          \"device\": \"/dev/sda\",\n          \"wipeTable\": true,\n          \"partitions\": [\n            { \"label\": \"BIOS\", \"number\": 1, \"size\": 4096 },\n            { \"label\": \"SWAP\", \"number\": 2, \"size\": \"3993600\" },\n            { \"label\": \"ROOT\", \"number\": 3, \"size\": 0 }\n          ]\n        }\n      ],\n      \"filesystems\": [\n        {\n          \"mount\": {\n            \"device\": \"/dev/sda3\",\n            \"format\": \"ext4\",\n            \"point\": \"/\",\n            \"create\": { \"options\": [\"-L\", \"ROOT\"] }\n          }\n        },\n        {\n          \"mount\": {\n            \"device\": \"/dev/sda2\",\n            \"format\": \"swap\",\n            \"point\": \"none\",\n            \"create\": { \"options\": [\"-L\", \"SWAP\"] }\n          }\n        }\n      ]\n    },\n    \"volumes\": [],\n    \"boot_drive_hint\": \"DELLBOSS VD\",\n    \"network\": {\n      \"bonding\": {\n        \"mode\": 4,\n        \"link_aggregation\": \"mlag_ha\",\n        \"mac\": \"e4:43:4b:d0:7b:50\"\n      },\n      \"interfaces\": [\n        { \"name\": \"eth0\", \"mac\": \"e4:43:4b:d0:7b:50\", \"bond\": \"bond0\" },\n        { \"name\": \"eth1\", \"mac\": \"e4:43:4b:d0:7b:51\", \"bond\": \"bond1\" },\n        { \"name\": \"eth2\", \"mac\": \"e4:43:4b:d0:7b:52\", \"bond\": \"bond0\" },\n        { \"name\": \"eth3\", \"mac\": \"e4:43:4b:d0:7b:53\", \"bond\": \"bond1\" }\n      ],\n      \"addresses\": [\n        {\n          \"id\": \"e5e5c1db-ef6d-4461-958e-50b88a96833e\",\n          \"address_family\": 4,\n          \"netmask\": \"255.255.255.254\",\n          \"created_at\": \"2024-05-22T17:59:09Z\",\n          \"public\": true,\n          \"cidr\": 31,\n          \"management\": true,\n          \"enabled\": true,\n          \"network\": \"147.28.162.182\",\n          \"address\": \"147.28.162.183\",\n          \"gateway\": \"147.28.162.182\",\n          \"parent_block\": {\n            \"network\": \"147.28.162.182\",\n            \"netmask\": \"255.255.255.254\",\n            \"cidr\": 31,\n            \"href\": \"/ips/909dbc49-1640-4b0a-b9c4-20e4cef044e8\"\n          }\n        },\n        {\n          \"id\": \"1cc68fbc-c0d3-42e2-a186-a73923e65bec\",\n          \"address_family\": 6,\n          \"netmask\": \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe\",\n          \"created_at\": \"2024-05-22T17:59:09Z\",\n          \"public\": true,\n          \"cidr\": 127,\n          \"management\": true,\n          \"enabled\": true,\n          \"network\": \"2604:1380:45f2:6f00::\",\n          \"address\": \"2604:1380:45f2:6f00::1\",\n          \"gateway\": \"2604:1380:45f2:6f00::\",\n          \"parent_block\": {\n            \"network\": \"2604:1380:45f2:6f00:0000:0000:0000:0000\",\n            \"netmask\": \"ffff:ffff:ffff:ff00:0000:0000:0000:0000\",\n            \"cidr\": 56,\n            \"href\": \"/ips/77b6f5dd-11e9-47bd-9c5c-6db6ec29fe42\"\n          }\n        },\n        {\n          \"id\": \"8d4d7e88-730c-409e-97b6-99b2f69aeede\",\n          \"address_family\": 4,\n          \"netmask\": \"255.255.255.254\",\n          \"created_at\": \"2024-05-22T17:59:09Z\",\n          \"public\": false,\n          \"cidr\": 31,\n          \"management\": true,\n          \"enabled\": true,\n          \"network\": \"10.68.217.0\",\n          \"address\": \"10.68.217.1\",\n          \"gateway\": \"10.68.217.0\",\n          \"parent_block\": {\n            \"network\": \"10.68.217.0\",\n            \"netmask\": \"255.255.255.128\",\n            \"cidr\": 25,\n            \"href\": \"/ips/6258119f-c7c4-4158-a54a-fb317263a3ce\"\n          }\n        }\n      ],\n      \"metal_gateways\": []\n    },\n    \"api_url\": \"https://metadata.packet.net\",\n    \"phone_home_url\": \"http://tinkerbell.dc13.packet.net/phone-home\",\n    \"user_state_url\": \"http://tinkerbell.dc13.packet.net/events\"\n  }\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal/testdata/metadata.json",
    "content": "{\n    \"id\": \"X\",\n    \"hostname\": \"infra-green-ci\",\n    \"plan\": \"c3.medium.x86\",\n    \"reserved\": false,\n    \"class\": \"c3.medium.x86\",\n    \"facility\": \"ny5\",\n    \"metro\": \"ny\",\n    \"private_subnets\": [\n        \"10.0.0.0/8\"\n    ],\n    \"tags\": [],\n    \"ssh_keys\": [\n    ],\n    \"customdata\": {},\n    \"network\": {\n        \"bonding\": {\n            \"mode\": 4,\n            \"link_aggregation\": \"mlag_ha\",\n            \"mac\": \"68:05:ca:b8:f1:f8\"\n        },\n        \"interfaces\": [\n            {\n                \"name\": \"eth0\",\n                \"mac\": \"68:05:ca:b8:f1:f8\",\n                \"bond\": \"bond0\"\n            },\n            {\n                \"name\": \"eth1\",\n                \"mac\": \"68:05:ca:b8:f1:f9\",\n                \"bond\": \"bond0\"\n            }\n        ],\n        \"addresses\": [\n            {\n                \"id\": \"d6be5d63-50f8-452c-b5cd-6cba42fbd5b3\",\n                \"address_family\": 4,\n                \"netmask\": \"255.255.255.254\",\n                \"created_at\": \"2021-11-24T20:24:54Z\",\n                \"public\": true,\n                \"cidr\": 31,\n                \"management\": true,\n                \"enabled\": true,\n                \"network\": \"147.75.78.40\",\n                \"address\": \"147.75.78.41\",\n                \"gateway\": \"147.75.78.40\",\n                \"parent_block\": {\n                    \"network\": \"147.75.78.40\",\n                    \"netmask\": \"255.255.255.254\",\n                    \"cidr\": 31,\n                    \"href\": \"/ips/e5cc5a4e-1d80-42c8-b5ea-39644effb407\"\n                }\n            },\n            {\n                \"id\": \"09c743e9-52e4-4125-9e88-da56c8e62ae4\",\n                \"address_family\": 6,\n                \"netmask\": \"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe\",\n                \"created_at\": \"2021-11-24T20:24:54Z\",\n                \"public\": true,\n                \"cidr\": 127,\n                \"management\": true,\n                \"enabled\": true,\n                \"network\": \"2604:1380:45d1:fd00::10\",\n                \"address\": \"2604:1380:45d1:fd00::11\",\n                \"gateway\": \"2604:1380:45d1:fd00::10\",\n                \"parent_block\": {\n                    \"network\": \"2604:1380:45d1:fd00:0000:0000:0000:0000\",\n                    \"netmask\": \"ffff:ffff:ffff:ff00:0000:0000:0000:0000\",\n                    \"cidr\": 56,\n                    \"href\": \"/ips/a76e6dd1-a22a-4f8a-a04d-7b68b4f358e5\"\n                }\n            },\n            {\n                \"id\": \"c7d3cd31-beae-460a-b008-29776c95562b\",\n                \"address_family\": 4,\n                \"netmask\": \"255.255.255.255\",\n                \"created_at\": \"2021-12-10T13:41:14Z\",\n                \"public\": true,\n                \"cidr\": 32,\n                \"management\": false,\n                \"enabled\": true,\n                \"network\": \"147.75.195.143\",\n                \"address\": \"147.75.195.143\",\n                \"gateway\": \"147.75.195.143\",\n                \"parent_block\": {\n                  \"network\": \"147.75.195.143\",\n                  \"netmask\": \"255.255.255.255\",\n                  \"cidr\": 32,\n                  \"href\": \"/ips/77e054ac-cd40-473a-9c59-8f6c322c5a20\"\n                }\n              },\n              {\n                \"id\": \"5e0bc796-9e7f-46a5-9472-ced35b8acb6d\",\n                \"address_family\": 4,\n                \"netmask\": \"255.255.255.254\",\n                \"created_at\": \"2021-11-24T20:24:54Z\",\n                \"public\": false,\n                \"cidr\": 31,\n                \"management\": true,\n                \"enabled\": true,\n                \"network\": \"10.66.142.16\",\n                \"address\": \"10.66.142.17\",\n                \"gateway\": \"10.66.142.16\",\n                \"parent_block\": {\n                    \"network\": \"10.66.142.0\",\n                    \"netmask\": \"255.255.255.128\",\n                    \"cidr\": 25,\n                    \"href\": \"/ips/045b5dd5-6a32-48e6-870d-8ea9a39169d6\"\n                }\n            }\n        ],\n        \"metal_gateways\": []\n    },\n    \"bgp_neighbors\": [\n        {\n          \"address_family\": 4,\n          \"customer_as\": 65000,\n          \"customer_ip\": \"10.67.50.1\",\n          \"md5_enabled\": false,\n          \"md5_password\": null,\n          \"multihop\": true,\n          \"peer_as\": 65530,\n          \"peer_ips\": [\n            \"169.254.255.1\",\n            \"169.254.255.2\"\n          ],\n          \"routes_in\": [],\n          \"routes_out\": []\n        },\n        {\n          \"address_family\": 6,\n          \"customer_as\": 65000,\n          \"customer_ip\": \"2604:1380:45e1:5000::1\",\n          \"md5_enabled\": false,\n          \"md5_password\": null,\n          \"multihop\": true,\n          \"peer_as\": 65530,\n          \"peer_ips\": [\n            \"fc00:0000:0000:0000:0000:0000:0000:000e\",\n            \"fc00:0000:0000:0000:0000:0000:0000:000f\"\n          ],\n          \"routes_in\": [],\n          \"routes_out\": []\n        }\n    ],\n    \"api_url\": \"https://metadata.packet.net\",\n    \"phone_home_url\": \"http://tinkerbell.ny5.packet.net/phone-home\",\n    \"user_state_url\": \"http://tinkerbell.ny5.packet.net/events\"\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/errors/errors.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package errors contains errors used by the platform package.\npackage errors\n\nimport \"errors\"\n\n// ErrNoConfigSource indicates that the platform does not have a configured source for the configuration.\nvar ErrNoConfigSource = errors.New(\"no configuration source\")\n\n// ErrNoHostname indicates that the meta server does not have a instance hostname.\nvar ErrNoHostname = errors.New(\"failed to fetch hostname from metadata service\")\n\n// ErrNoExternalIPs indicates that the meta server does not have a external addresses.\nvar ErrNoExternalIPs = errors.New(\"failed to fetch external addresses from metadata service\")\n\n// ErrNoEventURL indicates that the platform does not have an expected events URL in the kernel params.\nvar ErrNoEventURL = errors.New(\"no event URL\")\n\n// ErrMetadataNotReady indicates that the platform does not have metadata yet.\nvar ErrMetadataNotReady = errors.New(\"platform metadata is not ready\")\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale/exoscale.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package exoscale contains the Exoscale platform implementation.\npackage exoscale\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Exoscale is the concrete type that implements the runtime.Platform interface.\ntype Exoscale struct{}\n\n// ParseMetadata converts Exoscale platform metadata into platform network config.\nfunc (e *Exoscale) ParseMetadata(metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tif metadata.PublicIPv4 != \"\" {\n\t\tif ip, err := netip.ParseAddr(metadata.PublicIPv4); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     e.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       metadata.Zone,\n\t\tZone:         metadata.Zone,\n\t\tInstanceType: strings.ToLower(strings.SplitN(metadata.InstanceType, \" \", 2)[0]),\n\t\tInstanceID:   metadata.InstanceID,\n\t\tProviderID:   fmt.Sprintf(\"exoscale://%s\", metadata.InstanceID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Name implements the runtime.Platform interface.\nfunc (e *Exoscale) Name() string {\n\treturn \"exoscale\"\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (e *Exoscale) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from %q\", ExoscaleUserDataEndpoint)\n\n\treturn download.Download(ctx, ExoscaleUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (e *Exoscale) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (e *Exoscale) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (e *Exoscale) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching exoscale instance config from: %q\", ExoscaleMetadataEndpoint)\n\n\tmetadata, err := e.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := e.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale/exoscale_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage exoscale_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestEmpty(t *testing.T) {\n\tp := &exoscale.Exoscale{}\n\n\tvar m exoscale.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &m))\n\n\tnetworkConfig, err := p.ParseMetadata(&m)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage exoscale\n\nimport (\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// ExoscaleMetadataEndpoint is the local Exoscale endpoint.\n\tExoscaleMetadataEndpoint = \"http://169.254.169.254/1.0/meta-data\"\n\t// ExoscaleUserDataEndpoint is the local Exoscale endpoint for the config.\n\tExoscaleUserDataEndpoint = \"http://169.254.169.254/1.0/user-data\"\n)\n\n// MetadataConfig represents a metadata Exoscale instance.\ntype MetadataConfig struct {\n\tHostname     string `json:\"local-hostname,omitempty\"`\n\tInstanceID   string `json:\"instance-id,omitempty\"`\n\tInstanceType string `json:\"service-offering,omitempty\"`\n\tPublicIPv4   string `json:\"public-ipv4,omitempty\"`\n\tZone         string `json:\"availability-zone,omitempty\"`\n}\n\nfunc (e *Exoscale) getMetadata(ctx context.Context) (metadata *MetadataConfig, err error) {\n\tgetMetadataKey := func(key string) (string, error) {\n\t\tres, metaerr := download.Download(ctx, fmt.Sprintf(\"%s/%s\", ExoscaleMetadataEndpoint, key),\n\t\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\t\tif metaerr != nil && !stderrors.Is(metaerr, errors.ErrNoConfigSource) {\n\t\t\treturn \"\", fmt.Errorf(\"failed to fetch %q from IMDS: %w\", key, metaerr)\n\t\t}\n\n\t\treturn string(res), nil\n\t}\n\n\tmetadata = &MetadataConfig{}\n\n\tif metadata.Hostname, err = getMetadataKey(\"local-hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceType, err = getMetadataKey(\"service-offering\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceID, err = getMetadataKey(\"instance-id\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.PublicIPv4, err = getMetadataKey(\"public-ipv4\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.Zone, err = getMetadataKey(\"availability-zone\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn metadata, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale/testdata/expected.yaml",
    "content": "addresses: []\nlinks: []\nroutes: []\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 1.2.3.4\nmetadata:\n    platform: exoscale\n    hostname: talos.fqdn\n    instanceType: standard.tiny\n    instanceId: 3085c764-b270-45b0-b974-68c55a9c2d53\n    providerId: exoscale://3085c764-b270-45b0-b974-68c55a9c2d53\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale/testdata/metadata.json",
    "content": "{\n    \"local-hostname\": \"talos.fqdn\",\n    \"instance-id\": \"3085c764-b270-45b0-b974-68c55a9c2d53\",\n    \"public-ipv4\": \"1.2.3.4\",\n    \"service-offering\": \"standard.tiny\"\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/gcp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package gcp contains the GCP implementation of the [platform.Platform].\npackage gcp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"cloud.google.com/go/compute/metadata\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// GCP is the concrete type that implements the platform.Platform interface.\ntype GCP struct{}\n\n// Name implements the platform.Platform interface.\nfunc (g *GCP) Name() string {\n\treturn \"gcp\"\n}\n\n// ParseMetadata converts GCP platform metadata into platform network config.\n//\n//nolint:gocyclo\nfunc (g *GCP) ParseMetadata(metadata *MetadataConfig, interfaces []NetworkInterfaceConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tdns, _ := netip.ParseAddr(gcpResolverServer) //nolint:errcheck\n\n\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{dns},\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tnetworkConfig.TimeServers = append(networkConfig.TimeServers, network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{gcpTimeServer},\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tregion := metadata.Zone\n\n\tif idx := strings.LastIndex(region, \"-\"); idx != -1 {\n\t\tregion = region[:idx]\n\t}\n\n\tfor idx, iface := range interfaces {\n\t\tifname := fmt.Sprintf(\"eth%d\", idx)\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        ifname,\n\t\t\tUp:          true,\n\t\t\tMTU:         uint32(iface.MTU),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\tOperator: network.OperatorDHCP4,\n\t\t\tLinkName: ifname,\n\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t},\n\t\t\tRequireUp:   true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tfor _, ipv6addr := range iface.IPv6 {\n\t\t\tif ipv6addr == \"\" || iface.GatewayIPv6 == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tipPrefix, err := netip.ParsePrefix(ipv6addr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    ifname,\n\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tgw, err := netip.ParseAddr(iface.GatewayIPv6)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: ifname,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\t}\n\n\tfor _, iface := range interfaces {\n\t\tfor _, ipStr := range iface.AccessConfigs {\n\t\t\tif ipStr.Type == \"ONE_TO_ONE_NAT\" {\n\t\t\t\tif ip, err := netip.ParseAddr(ipStr.ExternalIP); err == nil {\n\t\t\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpreempted, _ := strconv.ParseBool(metadata.Preempted) //nolint:errcheck\n\n\tvar tags map[string]string\n\n\tif len(metadata.Tags) > 0 {\n\t\ttags = make(map[string]string, len(metadata.Tags))\n\n\t\tfor _, tag := range metadata.Tags {\n\t\t\ttags[tag] = \"\"\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     g.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       region,\n\t\tZone:         metadata.Zone,\n\t\tInstanceType: metadata.InstanceType,\n\t\tInstanceID:   metadata.InstanceID,\n\t\tProviderID:   fmt.Sprintf(\"gce://%s/%s/%s\", metadata.ProjectID, metadata.Zone, metadata.Name),\n\t\tSpot:         preempted,\n\t\tTags:         tags,\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (g *GCP) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from GCP metadata service\")\n\n\tuserdata, err := netutils.RetryFetch(ctx, g.fetchConfiguration)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif strings.TrimSpace(userdata) == \"\" {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn []byte(userdata), nil\n}\n\nfunc (g *GCP) fetchConfiguration(ctx context.Context) (string, error) {\n\tuserdata, err := metadata.InstanceAttributeValueWithContext(ctx, \"user-data\")\n\tif err != nil {\n\t\tif _, ok := err.(metadata.NotDefinedError); ok {\n\t\t\treturn \"\", errors.ErrNoConfigSource\n\t\t}\n\n\t\treturn \"\", retry.ExpectedError(err)\n\t}\n\n\treturn userdata, nil\n}\n\n// Mode implements the platform.Platform interface.\nfunc (g *GCP) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (g *GCP) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\tprocfs.NewParameter(constants.KernelParamDashboardDisabled).Append(\"1\"),\n\t\t// disable 'kexec' as GCP VMs sometimes are stuck on kexec, and normal soft reboot\n\t\t// doesn't take much longer on VMs\n\t\tprocfs.NewParameter(\"sysctl.kernel.kexec_load_disabled\").Append(\"1\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (g *GCP) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching gcp instance config\")\n\n\tmetadata, err := g.getMetadata(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to receive GCP metadata: %w\", err)\n\t}\n\n\tnetwork, err := g.getNetworkMetadata(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to receive GCP network metadata: %w\", err)\n\t}\n\n\tnetworkConfig, err := g.ParseMetadata(metadata, network)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/gcp_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gcp_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/gcp\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/interfaces.json\nvar rawInterfaces []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &gcp.GCP{}\n\n\tvar (\n\t\tmetadata   gcp.MetadataConfig\n\t\tinterfaces []gcp.NetworkInterfaceConfig\n\t)\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\trequire.NoError(t, json.Unmarshal(rawInterfaces, &interfaces))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata, interfaces)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gcp\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"strings\"\n\n\t\"cloud.google.com/go/compute/metadata\"\n)\n\nconst (\n\t// https://cloud.google.com/compute/docs/metadata/overview\n\tgcpResolverServer = \"169.254.169.254\"\n\tgcpTimeServer     = \"metadata.google.internal\"\n)\n\n// MetadataConfig holds meta info.\ntype MetadataConfig struct {\n\tProjectID    string   `json:\"project-id\"`\n\tName         string   `json:\"name,omitempty\"`\n\tHostname     string   `json:\"hostname,omitempty\"`\n\tZone         string   `json:\"zone,omitempty\"`\n\tInstanceType string   `json:\"machine-type\"`\n\tInstanceID   string   `json:\"id\"`\n\tPreempted    string   `json:\"preempted\"`\n\tTags         []string `json:\"tags,omitempty\"`\n}\n\n// NetworkInterfaceConfig holds network meta info.\ntype NetworkInterfaceConfig struct {\n\tAccessConfigs []struct {\n\t\tExternalIP string `json:\"externalIp,omitempty\"`\n\t\tType       string `json:\"type,omitempty\"`\n\t} `json:\"accessConfigs,omitempty\"`\n\tGatewayIPv4 string   `json:\"gateway,omitempty\"`\n\tGatewayIPv6 string   `json:\"gatewayIpv6,omitempty\"`\n\tIPv4        string   `json:\"ip,omitempty\"`\n\tIPv6        []string `json:\"ipv6,omitempty\"`\n\tMTU         int      `json:\"mtu,omitempty\"`\n}\n\nfunc (g *GCP) getMetadata(ctx context.Context) (*MetadataConfig, error) {\n\tvar (\n\t\tmeta MetadataConfig\n\t\terr  error\n\t)\n\tif meta.ProjectID, err = metadata.ProjectIDWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif meta.Name, err = metadata.InstanceNameWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tinstanceType, err := metadata.GetWithContext(ctx, \"instance/machine-type\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeta.InstanceType = strings.TrimSpace(instanceType[strings.LastIndex(instanceType, \"/\")+1:])\n\n\tif meta.InstanceID, err = metadata.InstanceIDWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif meta.Hostname, err = metadata.HostnameWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif meta.Zone, err = metadata.ZoneWithContext(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeta.Preempted, err = metadata.GetWithContext(ctx, \"instance/scheduling/preemptible\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeta.Tags, err = metadata.InstanceTagsWithContext(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &meta, nil\n}\n\nfunc (g *GCP) getNetworkMetadata(ctx context.Context) ([]NetworkInterfaceConfig, error) {\n\tmetadataNetworkConfigDl, err := metadata.GetWithContext(ctx, \"instance/network-interfaces/?recursive=true&alt=json\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar unmarshalledNetworkConfig []NetworkInterfaceConfig\n\n\tif err = json.Unmarshal([]byte(metadataNetworkConfigDl), &unmarshalledNetworkConfig); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn unmarshalledNetworkConfig, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/testdata/expected.yaml",
    "content": "addresses:\n    - address: fd20:172:1610:7003:0:1::/96\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 1500\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::4001:acff:fe10:1\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 169.254.169.254\n      layer: platform\ntimeServers:\n    - timeServers:\n        - metadata.google.internal\n      layer: platform\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs:\n    - 35.1.2.3\nmetadata:\n    platform: gcp\n    hostname: talos\n    region: us-central1\n    zone: us-central1-a\n    instanceType: n1-standard-1\n    instanceId: \"0\"\n    providerId: gce://123/us-central1-a/my-server\n    tags:\n        tag1: \"\"\n        tag2: \"\"\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/testdata/interfaces.json",
    "content": "[\n    {\n        \"accessConfigs\": [\n            {\n                \"externalIp\": \"35.1.2.3\",\n                \"type\": \"ONE_TO_ONE_NAT\"\n            }\n        ],\n        \"dhcpv6Refresh\": \"2219726792944608985\",\n        \"dnsServers\": [\n            \"169.254.169.254\"\n        ],\n        \"forwardedIps\": [\n            \"172.16.0.230\"\n        ],\n        \"gateway\": \"172.16.0.1\",\n        \"gatewayIpv6\": \"fe80::4001:acff:fe10:1\",\n        \"ip\": \"172.16.0.4\",\n        \"ipAliases\": [],\n        \"ipv6\": [\n            \"fd20:172:1610:7003:0:1::/96\"\n        ],\n        \"ipv6s\": [\n            \"fd20:172:1610:7003:0:1:0:0\"\n        ],\n        \"mac\": \"42:01:ac:10:00:04\",\n        \"mtu\": 1500,\n        \"network\": \"projects/123/networks/main\",\n        \"subnetmask\": \"255.255.255.0\",\n        \"targetInstanceIps\": []\n    }\n]"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/gcp/testdata/metadata.json",
    "content": "{\n    \"project-id\": \"123\",\n    \"hostname\": \"talos\",\n    \"id\": \"0\",\n    \"zone\": \"us-central1-a\",\n    \"name\": \"my-server\",\n    \"machine-type\": \"n1-standard-1\",\n    \"preempted\": \"FALSE\",\n    \"tags\": [\n        \"tag1\",\n        \"tag2\"\n    ]\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hcloud\n\n// MaybeBase64Decode is exported for testing.\nfunc MaybeBase64Decode(data []byte) []byte {\n\treturn maybeBase64Decode(data)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/hcloud.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package hcloud contains the Hcloud implementation of the [platform.Platform].\npackage hcloud\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Hcloud is the concrete type that implements the runtime.Platform interface.\ntype Hcloud struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (h *Hcloud) Name() string {\n\treturn \"hcloud\"\n}\n\n// ParseMetadata converts HCloud metadata to platform network configuration.\n//\n//nolint:gocyclo\nfunc (h *Hcloud) ParseMetadata(unmarshalledNetworkConfig *NetworkConfig, metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar publicIPs []string\n\n\tif metadata.PublicIPv4 != \"\" {\n\t\tpublicIPs = append(publicIPs, metadata.PublicIPv4)\n\t}\n\n\tfor _, ntwrk := range unmarshalledNetworkConfig.Config {\n\t\tif ntwrk.Type != \"physical\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        ntwrk.Interfaces,\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tfor _, subnet := range ntwrk.Subnets {\n\t\t\tif subnet.Type == \"dhcp\" && subnet.Ipv4 {\n\t\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\t\tOperator: network.OperatorDHCP4,\n\t\t\t\t\tLinkName: ntwrk.Interfaces,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif subnet.Type == \"static\" {\n\t\t\t\tipAddr, err := netip.ParsePrefix(subnet.Address)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tfamily := nethelpers.FamilyInet4\n\n\t\t\t\tif ipAddr.Addr().Is6() {\n\t\t\t\t\tpublicIPs = append(publicIPs, strings.SplitN(subnet.Address, \"/\", 2)[0])\n\t\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t\t}\n\n\t\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t\tLinkName:    ntwrk.Interfaces,\n\t\t\t\t\t\tAddress:     ipAddr,\n\t\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\t\tFamily:      family,\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif subnet.Gateway != \"\" && subnet.Ipv6 {\n\t\t\t\tgw, err := netip.ParseAddr(subnet.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tOutLinkName: ntwrk.Interfaces,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:   h.Name(),\n\t\tHostname:   metadata.Hostname,\n\t\tRegion:     metadata.Region,\n\t\tZone:       metadata.AvailabilityZone,\n\t\tInstanceID: metadata.InstanceID,\n\t\tProviderID: fmt.Sprintf(\"hcloud://%s\", metadata.InstanceID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (h *Hcloud) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", HCloudUserDataEndpoint)\n\n\tconfigBytes, err := download.Download(ctx, HCloudUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Try to parse the downloaded config bytes as base64 string, so that users can provide the config in base64 format.\n\t// This also allows users to gzip this data, since the calling code will try to un-gzip the data if it detects it.\n\treturn maybeBase64Decode(configBytes), nil\n}\n\n// maybeBase64Decode tries to interpret the provided bytes as base64 string and decode them.\n// If the provided bytes are not a valid base64 string, the original bytes are returned.\nfunc maybeBase64Decode(data []byte) []byte {\n\tout, err := base64.StdEncoding.AppendDecode(nil, data)\n\tif err != nil {\n\t\treturn data\n\t}\n\n\treturn out\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (h *Hcloud) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (h *Hcloud) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (h *Hcloud) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tmetadata, err := h.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Printf(\"fetching hcloud network config from: %q\", HCloudNetworkEndpoint)\n\n\tmetadataNetworkConfig, err := download.Download(ctx, HCloudNetworkEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch network config from metadata service: %w\", err)\n\t}\n\n\tvar unmarshalledNetworkConfig NetworkConfig\n\n\tif err = yaml.Unmarshal(metadataNetworkConfig, &unmarshalledNetworkConfig); err != nil {\n\t\treturn err\n\t}\n\n\tif unmarshalledNetworkConfig.Version != 1 {\n\t\treturn fmt.Errorf(\"network-config metadata version=%d is not supported\", unmarshalledNetworkConfig.Version)\n\t}\n\n\tnetworkConfig, err := h.ParseMetadata(&unmarshalledNetworkConfig, metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/hcloud_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hcloud_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud\"\n)\n\n//go:embed testdata/metadata.yaml\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\th := &hcloud.Hcloud{}\n\n\tmetadata := &hcloud.MetadataConfig{\n\t\tHostname:         \"talos.fqdn\",\n\t\tPublicIPv4:       \"1.2.3.4\",\n\t\tInstanceID:       \"0\",\n\t\tRegion:           \"hel1\",\n\t\tAvailabilityZone: \"hel1-dc2\",\n\t}\n\n\tvar m hcloud.NetworkConfig\n\n\trequire.NoError(t, yaml.Unmarshal(rawMetadata, &m))\n\n\tnetworkConfig, err := h.ParseMetadata(&m, metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n\n//go:embed testdata/userdata-plain.yaml\nvar userdataPlain []byte\n\n//go:embed testdata/userdata-base64.txt\nvar userdataBase64 []byte\n\nfunc TestParseUserdata(t *testing.T) {\n\tdecodedUserdataPlain := hcloud.MaybeBase64Decode(userdataPlain)\n\tdecodedUserdataBase64 := hcloud.MaybeBase64Decode(userdataBase64)\n\n\tassert.Equal(t, decodedUserdataPlain, decodedUserdataBase64)\n\tassert.Equal(t, userdataPlain, decodedUserdataBase64)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hcloud\n\nimport (\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// HCloudMetadataEndpoint is the local HCloud metadata endpoint.\n\tHCloudMetadataEndpoint = \"http://169.254.169.254/hetzner/v1/metadata\"\n\n\t// HCloudNetworkEndpoint is the local HCloud metadata endpoint for the network-config.\n\tHCloudNetworkEndpoint = \"http://169.254.169.254/hetzner/v1/metadata/network-config\"\n\n\t// HCloudUserDataEndpoint is the local HCloud metadata endpoint for the config.\n\tHCloudUserDataEndpoint = \"http://169.254.169.254/hetzner/v1/userdata\"\n)\n\n// MetadataConfig holds meta info.\ntype MetadataConfig struct {\n\tHostname         string `yaml:\"hostname,omitempty\"`\n\tRegion           string `yaml:\"region,omitempty\"`\n\tAvailabilityZone string `yaml:\"availability-zone,omitempty\"`\n\tInstanceID       string `yaml:\"instance-id,omitempty\"`\n\tPublicIPv4       string `yaml:\"public-ipv4,omitempty\"`\n}\n\n// NetworkConfig holds hcloud network-config info.\ntype NetworkConfig struct {\n\tVersion int `yaml:\"version\"`\n\tConfig  []struct {\n\t\tMac        string `yaml:\"mac_address\"`\n\t\tInterfaces string `yaml:\"name\"`\n\t\tSubnets    []struct {\n\t\t\tNameServers []string `yaml:\"dns_nameservers,omitempty\"`\n\t\t\tAddress     string   `yaml:\"address,omitempty\"`\n\t\t\tGateway     string   `yaml:\"gateway,omitempty\"`\n\t\t\tIpv4        bool     `yaml:\"ipv4,omitempty\"`\n\t\t\tIpv6        bool     `yaml:\"ipv6,omitempty\"`\n\t\t\tType        string   `yaml:\"type\"`\n\t\t} `yaml:\"subnets\"`\n\t\tType string `yaml:\"type\"`\n\t} `yaml:\"config\"`\n}\n\nfunc (h *Hcloud) getMetadata(ctx context.Context) (metadata *MetadataConfig, err error) {\n\tgetMetadataKey := func(key string) (string, error) {\n\t\tres, metaerr := download.Download(ctx, fmt.Sprintf(\"%s/%s\", HCloudMetadataEndpoint, key),\n\t\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\t\tif metaerr != nil && !stderrors.Is(metaerr, errors.ErrNoConfigSource) {\n\t\t\treturn \"\", fmt.Errorf(\"failed to fetch %q from IMDS: %w\", key, metaerr)\n\t\t}\n\n\t\treturn string(res), nil\n\t}\n\n\tmetadata = &MetadataConfig{}\n\n\tif metadata.Hostname, err = getMetadataKey(\"hostname\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.InstanceID, err = getMetadataKey(\"instance-id\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif metadata.AvailabilityZone, err = getMetadataKey(\"availability-zone\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Original CCM/CSI uses first part of availability-zone to define region name.\n\t// But metadata has different value.\n\t// We will follow official behavior.\n\tmetadata.Region = strings.SplitN(metadata.AvailabilityZone, \"-\", 2)[0]\n\n\tif metadata.PublicIPv4, err = getMetadataKey(\"public-ipv4\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn metadata, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/testdata/expected.yaml",
    "content": "addresses:\n    - address: 2a01:4f8:1:2::1/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers: []\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: false\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs:\n    - 1.2.3.4\n    - 2a01:4f8:1:2::1\nmetadata:\n    platform: hcloud\n    hostname: talos.fqdn\n    region: hel1\n    zone: hel1-dc2\n    instanceId: \"0\"\n    providerId: hcloud://0\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/testdata/metadata.yaml",
    "content": "config:\n- mac_address: 96:00:00:1:2:3\n  name: eth0\n  subnets:\n  - ipv4: true\n    type: dhcp\n  - address: 2a01:4f8:1:2::1/64\n    gateway: fe80::1\n    ipv6: true\n    type: static\n  type: physical\n- address:\n  - 185.12.64.2\n  - 185.12.64.1\n  interface: eth0\n  type: nameserver\nversion: 1\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/testdata/userdata-base64.txt",
    "content": "dmVyc2lvbjogdjFhbHBoYTEKZGVidWc6IGZhbHNlCnBlcnNpc3Q6IHRydWUKbWFjaGluZToKICB0eXBlOiBjb250cm9scGxhbmUKICBjZXJ0U0FOczoKICAgIC0gMTAuMC4xLjEwMQogICAgLSAxMC4wLjEuMTAwCiAga3ViZWxldDoKICAgIGltYWdlOiBnaGNyLmlvL3NpZGVyb2xhYnMva3ViZWxldDp2MS4zMS4xCiAgICBleHRyYUFyZ3M6CiAgICAgIGNsb3VkLXByb3ZpZGVyOiBleHRlcm5hbAogICAgICByb3RhdGUtc2VydmVyLWNlcnRpZmljYXRlczogInRydWUiCiAgICBkZWZhdWx0UnVudGltZVNlY2NvbXBQcm9maWxlRW5hYmxlZDogdHJ1ZQogICAgbm9kZUlQOgogICAgICB2YWxpZFN1Ym5ldHM6CiAgICAgICAgLSAxMC4wLjEuMC8yNAogICAgZGlzYWJsZU1hbmlmZXN0c0RpcmVjdG9yeTogdHJ1ZQogIG5ldHdvcms6CiAgICBob3N0bmFtZTogY29udHJvbHBsYW5lLTAwMQogICAgaW50ZXJmYWNlczoKICAgICAgLSBpbnRlcmZhY2U6IGV0aDAKICAgICAgICBkaGNwOiB0cnVlCiAgICBrdWJlc3BhbjoKICAgICAgZW5hYmxlZDogZmFsc2UKICBpbnN0YWxsOgogICAgZGlzazogL2Rldi9zZGEKICAgIGV4dHJhS2VybmVsQXJnczoKICAgICAgLSBpcHY2LmRpc2FibGU9MQogICAgaW1hZ2U6IGdoY3IuaW8vc2lkZXJvbGFicy9pbnN0YWxsZXI6djEuOC4wCiAgICB3aXBlOiBmYWxzZQogIHN5c2N0bHM6CiAgICBuZXQuY29yZS5uZXRkZXZfbWF4X2JhY2tsb2c6ICI0MDk2IgogICAgbmV0LmNvcmUuc29tYXhjb25uOiAiNjU1MzUiCiAgZmVhdHVyZXM6CiAgICByYmFjOiB0cnVlCiAgICBzdGFibGVIb3N0bmFtZTogdHJ1ZQogICAga3ViZXJuZXRlc1RhbG9zQVBJQWNjZXNzOgogICAgICBlbmFibGVkOiB0cnVlCiAgICAgIGFsbG93ZWRSb2xlczoKICAgICAgICAtIG9zOnJlYWRlcgogICAgICBhbGxvd2VkS3ViZXJuZXRlc05hbWVzcGFjZXM6CiAgICAgICAgLSBrdWJlLXN5c3RlbQogICAgYXBpZENoZWNrRXh0S2V5VXNhZ2U6IHRydWUKICAgIGRpc2tRdW90YVN1cHBvcnQ6IHRydWUKICAgIGt1YmVQcmlzbToKICAgICAgZW5hYmxlZDogdHJ1ZQogICAgICBwb3J0OiA3NDQ1CiAgICBob3N0RE5TOgogICAgICBlbmFibGVkOiB0cnVlCiAgICAgIGZvcndhcmRLdWJlRE5TVG9Ib3N0OiB0cnVlCiAgICAgIHJlc29sdmVNZW1iZXJOYW1lczogdHJ1ZQogIGtlcm5lbDoge30KICBub2RlTGFiZWxzOgogICAgbm9kZS5rdWJlcm5ldGVzLmlvL2V4Y2x1ZGUtZnJvbS1leHRlcm5hbC1sb2FkLWJhbGFuY2VyczogIiIKY2x1c3RlcjoKICBjb250cm9sUGxhbmU6CiAgICBlbmRwb2ludDogaHR0cHM6Ly8xMC4wLjEuMTAwOjY0NDMKICBjbHVzdGVyTmFtZTogdGVzdC1jbHVzdGVyCiAgbmV0d29yazoKICAgIGNuaToKICAgICAgbmFtZTogbm9uZQogICAgZG5zRG9tYWluOiBjbHVzdGVyLmxvY2FsCiAgICBwb2RTdWJuZXRzOgogICAgICAtIDEwLjAuMTYuMC8yMAogICAgc2VydmljZVN1Ym5ldHM6CiAgICAgIC0gMTAuMC44LjAvMjEKICBhcGlTZXJ2ZXI6CiAgICBpbWFnZTogcmVnaXN0cnkuazhzLmlvL2t1YmUtYXBpc2VydmVyOnYxLjMxLjEKICAgIGNlcnRTQU5zOgogICAgICAtIDEwLjAuMS4xMDAKICAgICAgLSAxMC4wLjEuMTAxCiAgICAgIC0gMTAuMC4xLjEwMAogICAgZGlzYWJsZVBvZFNlY3VyaXR5UG9saWN5OiB0cnVlCiAgICBhZG1pc3Npb25Db250cm9sOgogICAgICAtIG5hbWU6IFBvZFNlY3VyaXR5CiAgICAgICAgY29uZmlndXJhdGlvbjoKICAgICAgICAgIGFwaVZlcnNpb246IHBvZC1zZWN1cml0eS5hZG1pc3Npb24uY29uZmlnLms4cy5pby92MWFscGhhMQogICAgICAgICAgZGVmYXVsdHM6CiAgICAgICAgICAgIGF1ZGl0OiByZXN0cmljdGVkCiAgICAgICAgICAgIGF1ZGl0LXZlcnNpb246IGxhdGVzdAogICAgICAgICAgICBlbmZvcmNlOiBiYXNlbGluZQogICAgICAgICAgICBlbmZvcmNlLXZlcnNpb246IGxhdGVzdAogICAgICAgICAgICB3YXJuOiByZXN0cmljdGVkCiAgICAgICAgICAgIHdhcm4tdmVyc2lvbjogbGF0ZXN0CiAgICAgICAgICBleGVtcHRpb25zOgogICAgICAgICAgICBuYW1lc3BhY2VzOgogICAgICAgICAgICAgIC0ga3ViZS1zeXN0ZW0KICAgICAgICAgICAgcnVudGltZUNsYXNzZXM6IFtdCiAgICAgICAgICAgIHVzZXJuYW1lczogW10KICAgICAgICAgIGtpbmQ6IFBvZFNlY3VyaXR5Q29uZmlndXJhdGlvbgogICAgYXVkaXRQb2xpY3k6CiAgICAgIGFwaVZlcnNpb246IGF1ZGl0Lms4cy5pby92MQogICAgICBraW5kOiBQb2xpY3kKICAgICAgcnVsZXM6CiAgICAgICAgLSBsZXZlbDogTWV0YWRhdGEKICBjb250cm9sbGVyTWFuYWdlcjoKICAgIGltYWdlOiByZWdpc3RyeS5rOHMuaW8va3ViZS1jb250cm9sbGVyLW1hbmFnZXI6djEuMzEuMQogICAgZXh0cmFBcmdzOgogICAgICBiaW5kLWFkZHJlc3M6IDAuMC4wLjAKICAgICAgY2xvdWQtcHJvdmlkZXI6IGV4dGVybmFsCiAgICAgIG5vZGUtY2lkci1tYXNrLXNpemUtaXB2NDogIjI0IgogIHByb3h5OgogICAgZGlzYWJsZWQ6IHRydWUKICAgIGltYWdlOiByZWdpc3RyeS5rOHMuaW8va3ViZS1wcm94eTp2MS4zMS4xCiAgc2NoZWR1bGVyOgogICAgaW1hZ2U6IHJlZ2lzdHJ5Lms4cy5pby9rdWJlLXNjaGVkdWxlcjp2MS4zMS4xCiAgICBleHRyYUFyZ3M6CiAgICAgIGJpbmQtYWRkcmVzczogMC4wLjAuMAogIGRpc2NvdmVyeToKICAgIGVuYWJsZWQ6IHRydWUKICAgIHJlZ2lzdHJpZXM6CiAgICAgIGt1YmVybmV0ZXM6CiAgICAgICAgZGlzYWJsZWQ6IHRydWUKICAgICAgc2VydmljZToge30KICBldGNkOgogICAgZXh0cmFBcmdzOgogICAgICBsaXN0ZW4tbWV0cmljcy11cmxzOiBodHRwOi8vMC4wLjAuMDoyMzgxCiAgICBhZHZlcnRpc2VkU3VibmV0czoKICAgICAgLSAxMC4wLjEuMC8yNAogIGNvcmVETlM6CiAgICBkaXNhYmxlZDogZmFsc2UKICBleHRlcm5hbENsb3VkUHJvdmlkZXI6CiAgICBlbmFibGVkOiB0cnVlCg=="
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud/testdata/userdata-plain.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n  type: controlplane\n  certSANs:\n    - 10.0.1.101\n    - 10.0.1.100\n  kubelet:\n    image: ghcr.io/siderolabs/kubelet:v1.31.1\n    extraArgs:\n      cloud-provider: external\n      rotate-server-certificates: \"true\"\n    defaultRuntimeSeccompProfileEnabled: true\n    nodeIP:\n      validSubnets:\n        - 10.0.1.0/24\n    disableManifestsDirectory: true\n  network:\n    hostname: controlplane-001\n    interfaces:\n      - interface: eth0\n        dhcp: true\n    kubespan:\n      enabled: false\n  install:\n    disk: /dev/sda\n    extraKernelArgs:\n      - ipv6.disable=1\n    image: ghcr.io/siderolabs/installer:v1.8.0\n    wipe: false\n  sysctls:\n    net.core.netdev_max_backlog: \"4096\"\n    net.core.somaxconn: \"65535\"\n  features:\n    rbac: true\n    stableHostname: true\n    kubernetesTalosAPIAccess:\n      enabled: true\n      allowedRoles:\n        - os:reader\n      allowedKubernetesNamespaces:\n        - kube-system\n    apidCheckExtKeyUsage: true\n    diskQuotaSupport: true\n    kubePrism:\n      enabled: true\n      port: 7445\n    hostDNS:\n      enabled: true\n      forwardKubeDNSToHost: true\n      resolveMemberNames: true\n  kernel: {}\n  nodeLabels:\n    node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n  controlPlane:\n    endpoint: https://10.0.1.100:6443\n  clusterName: test-cluster\n  network:\n    cni:\n      name: none\n    dnsDomain: cluster.local\n    podSubnets:\n      - 10.0.16.0/20\n    serviceSubnets:\n      - 10.0.8.0/21\n  apiServer:\n    image: registry.k8s.io/kube-apiserver:v1.31.1\n    certSANs:\n      - 10.0.1.100\n      - 10.0.1.101\n      - 10.0.1.100\n    disablePodSecurityPolicy: true\n    admissionControl:\n      - name: PodSecurity\n        configuration:\n          apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n          defaults:\n            audit: restricted\n            audit-version: latest\n            enforce: baseline\n            enforce-version: latest\n            warn: restricted\n            warn-version: latest\n          exemptions:\n            namespaces:\n              - kube-system\n            runtimeClasses: []\n            usernames: []\n          kind: PodSecurityConfiguration\n    auditPolicy:\n      apiVersion: audit.k8s.io/v1\n      kind: Policy\n      rules:\n        - level: Metadata\n  controllerManager:\n    image: registry.k8s.io/kube-controller-manager:v1.31.1\n    extraArgs:\n      bind-address: 0.0.0.0\n      cloud-provider: external\n      node-cidr-mask-size-ipv4: \"24\"\n  proxy:\n    disabled: true\n    image: registry.k8s.io/kube-proxy:v1.31.1\n  scheduler:\n    image: registry.k8s.io/kube-scheduler:v1.31.1\n    extraArgs:\n      bind-address: 0.0.0.0\n  discovery:\n    enabled: true\n    registries:\n      kubernetes:\n        disabled: true\n      service: {}\n  etcd:\n    extraArgs:\n      listen-metrics-urls: http://0.0.0.0:2381\n    advertisedSubnets:\n      - 10.0.1.0/24\n  coreDNS:\n    disabled: false\n  externalCloudProvider:\n    enabled: true\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/internal/address/address.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package address provides utility functions for address parsing.\npackage address\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// IPPrefixFrom make netip.Prefix from cidr-address and netmask strings.\n// address can be IP or CIDR (1.1.1.1 or 1.1.1.1/8 or 1.1.1.1/255.0.0.0)\n// netmask can be IP or number (255.255.255.0 or 24 or empty).\nfunc IPPrefixFrom(address, netmask string) (netip.Prefix, error) {\n\tcidr := strings.SplitN(address, \"/\", 2)\n\tif len(cidr) == 1 {\n\t\taddress = cidr[0]\n\t} else {\n\t\taddress = cidr[0]\n\t\tnetmask = cidr[1]\n\t}\n\n\tip, err := netip.ParseAddr(address)\n\tif err != nil {\n\t\treturn netip.Prefix{}, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t}\n\n\tif netmask == \"\" {\n\t\tif ip.Is4() {\n\t\t\tnetmask = \"32\"\n\t\t} else {\n\t\t\tnetmask = \"128\"\n\t\t}\n\t}\n\n\tbits, err := strconv.Atoi(netmask)\n\tif err != nil {\n\t\tnetmask, err := netip.ParseAddr(netmask)\n\t\tif err != nil {\n\t\t\treturn netip.Prefix{}, fmt.Errorf(\"failed to parse netmask: %w\", err)\n\t\t}\n\n\t\tmask, _ := netmask.MarshalBinary() //nolint:errcheck // never fails\n\t\tbits, _ = net.IPMask(mask).Size()\n\t}\n\n\tif ip.Is4() && bits > 32 {\n\t\treturn netip.Prefix{}, errors.New(\"failed netmask should be the same address family\")\n\t}\n\n\treturn netip.PrefixFrom(ip, bits), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils/blockutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package blockutils provides volume-related helpers for platform implementation.\npackage blockutils\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/google/cel-go/common/ast\"\n\t\"github.com/google/cel-go/common/operators\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\n// VolumeMatch returns a CEL expression that matches a volume by filesystem or partition label.\nfunc VolumeMatch(labels []string) (*cel.Expression, error) {\n\tbuilder := cel.NewBuilder(celenv.VolumeLocator())\n\n\t// \"(volume.label in ['%s', ...] || volume.partition_label in ['%s', ...]) && volume.name != ''\"\n\texpr := builder.NewCall(\n\t\tbuilder.NextID(),\n\t\toperators.LogicalAnd,\n\t\tbuilder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.LogicalOr,\n\t\t\tbuilder.NewCall(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\toperators.In,\n\t\t\t\tbuilder.NewSelect(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\t\t\"label\",\n\t\t\t\t),\n\t\t\t\tbuilder.NewList(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\txslices.Map(labels, func(label string) ast.Expr {\n\t\t\t\t\t\treturn builder.NewLiteral(builder.NextID(), types.String(label))\n\t\t\t\t\t}),\n\t\t\t\t\tnil,\n\t\t\t\t),\n\t\t\t),\n\t\t\tbuilder.NewCall(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\toperators.In,\n\t\t\t\tbuilder.NewSelect(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\t\t\"partition_label\",\n\t\t\t\t),\n\t\t\t\tbuilder.NewList(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\txslices.Map(labels, func(label string) ast.Expr {\n\t\t\t\t\t\treturn builder.NewLiteral(builder.NextID(), types.String(label))\n\t\t\t\t\t}),\n\t\t\t\t\tnil,\n\t\t\t\t),\n\t\t\t),\n\t\t),\n\t\tbuilder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.NotEquals,\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"volume\"),\n\t\t\t\t\"name\",\n\t\t\t),\n\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(\"\")),\n\t\t),\n\t)\n\n\tboolExpr, err := builder.ToBooleanExpression(expr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating boolean expression: %w\", err)\n\t}\n\n\treturn boolExpr, nil\n}\n\n// ReadFromVolume tries to find a volume with the given label, mounts it\n// as read-only, calls the provided function with xfs.Root and unmounts it.\n//\n// If the volume wasn't found, fs.ErrNotExist is returned.\nfunc ReadFromVolume(ctx context.Context, r state.State, labels []string, cb func(xfs.Root, *block.VolumeStatus) error) error {\n\tif len(labels) == 0 {\n\t\tpanic(\"at least one label must be provided\")\n\t}\n\n\tvolumeID := \"platform/\" + labels[0] + \"/config\"\n\n\tmatchExr, err := VolumeMatch(labels)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating volume match expression: %w\", err)\n\t}\n\n\t// create a volume which matches the expected filesystem label\n\tvc := block.NewVolumeConfig(block.NamespaceName, volumeID)\n\tvc.Metadata().Labels().Set(block.PlatformLabel, \"\")\n\tvc.TypedSpec().Type = block.VolumeTypePartition\n\tvc.TypedSpec().Locator = block.LocatorSpec{\n\t\tMatch: *matchExr,\n\t}\n\n\tif err := r.Create(ctx, vc); err != nil && !state.IsConflictError(err) {\n\t\treturn fmt.Errorf(\"error creating user disk volume configuration: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer cancel()\n\n\t\tif err := r.TeardownAndDestroy(ctx, vc.Metadata()); err != nil {\n\t\t\tlog.Printf(\"error destroying volume config %s/%s: %v\", vc.Metadata().Namespace(), vc.Metadata().ID(), err)\n\t\t}\n\t}()\n\n\t// wait for the volume to be either ready or missing (includes waiting for devices to be ready)\n\tvolumeStatus, err := safe.StateWatchFor[*block.VolumeStatus](ctx,\n\t\tr,\n\t\tblock.NewVolumeStatus(vc.Metadata().Namespace(), vc.Metadata().ID()).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tphase := r.(*block.VolumeStatus).TypedSpec().Phase\n\n\t\t\treturn phase == block.VolumePhaseReady || phase == block.VolumePhaseMissing, nil\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to watch for volume status: %w\", err)\n\t}\n\n\tif volumeStatus.TypedSpec().Phase == block.VolumePhaseMissing {\n\t\treturn fmt.Errorf(\"failed to find volume with machine configuration %s: %w\", vc.TypedSpec().Locator.Match, fs.ErrNotExist)\n\t}\n\n\tmanager := mount.NewManager(\n\t\tmount.WithReadOnly(),\n\t\tmount.WithPrinter(log.Printf),\n\t\tmount.WithFsopen(\n\t\t\tvolumeStatus.TypedSpec().Filesystem.String(),\n\t\t\tfsopen.WithSource(volumeStatus.TypedSpec().MountLocation),\n\t\t\tfsopen.WithBoolParameter(\"ro\"),\n\t\t),\n\t\tmount.WithDetached(),\n\t)\n\n\t// mount the volume, unmount when done\n\tp, err := manager.Mount()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to mount volume: %w\", err)\n\t}\n\n\tdefer manager.Unmount() //nolint:errcheck\n\n\treturn cb(p.Root(), volumeStatus)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils/blockutils_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage blockutils_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestVolumeMatch(t *testing.T) {\n\tt.Parallel()\n\n\texpr, err := blockutils.VolumeMatch([]string{constants.MetalConfigISOLabel})\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, `(volume.label in [\"metal-iso\"] || volume.partition_label in [\"metal-iso\"]) && volume.name != \"\"`, expr.String())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils/netutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package netutils provides network-related helpers for platform implementation.\npackage netutils\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Wait for the network to be ready to interact with platform metadata services.\nfunc Wait(ctx context.Context, r state.State) error {\n\tlog.Printf(\"waiting for network to be ready\")\n\n\treturn network.NewReadyCondition(r, network.AddressReady).Wait(ctx)\n}\n\n// WaitForDevicesReady waits for devices to be ready.\nfunc WaitForDevicesReady(ctx context.Context, r state.State) error {\n\tlog.Printf(\"waiting for devices to be ready...\")\n\n\treturn runtime.NewDevicesStatusCondition(r).Wait(ctx)\n}\n\n// RetryFetch retries fetching from metadata service.\nfunc RetryFetch(ctx context.Context, f func(ctx context.Context) (string, error)) (string, error) {\n\tvar (\n\t\tuserdata string\n\t\terr      error\n\t)\n\n\terr = retry.Exponential(\n\t\tconstants.ConfigLoadTimeout,\n\t\tretry.WithUnits(time.Second),\n\t\tretry.WithJitter(time.Second),\n\t\tretry.WithErrorLogging(true),\n\t).RetryWithContext(\n\t\tctx, func(ctx context.Context) error {\n\t\t\tuserdata, err = f(ctx)\n\n\t\t\treturn err\n\t\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn userdata, err\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package metal contains the metal implementation of the [platform.Platform].\npackage metal\n\nimport (\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/oauth2\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// Metal is a discoverer for non-cloud environments.\ntype Metal struct {\n\tIsAgent bool\n}\n\n// Name implements the platform.Platform interface.\nfunc (m *Metal) Name() string {\n\treturn constants.PlatformMetal\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (m *Metal) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tvar option *string\n\tif option = procfs.ProcCmdline().Get(constants.KernelParamConfig).First(); option == nil {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\tif *option == constants.ConfigNone {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\tgetURL := func(ctx context.Context) (string, error) {\n\t\t// give a shorter timeout to populate the URL, leave the rest of the time to the actual download\n\t\tctx, cancel := context.WithTimeout(ctx, constants.ConfigLoadAttemptTimeout/2)\n\t\tdefer cancel()\n\n\t\tdownloadEndpoint, err := url.Populate(ctx, *option, r)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed to populate talos.config fetch URL %q: %s\", *option, err.Error())\n\t\t}\n\n\t\tlog.Printf(\"fetching machine config from: %q\", downloadEndpoint)\n\n\t\treturn downloadEndpoint, nil\n\t}\n\n\tswitch *option {\n\tcase constants.MetalConfigISOLabel:\n\t\treturn readConfigFromISO(ctx, r)\n\tdefault:\n\t\tif err := netutils.Wait(ctx, r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\toauth2Cfg, err := oauth2.NewConfig(procfs.ProcCmdline(), *option)\n\t\tif err != nil && !stderrors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse OAuth2 config: %w\", err)\n\t\t}\n\n\t\tvar extraHeaders map[string]string\n\n\t\t// perform OAuth2 device auth flow first to acquire extra headers\n\t\tif oauth2Cfg != nil {\n\t\t\tif err = retry.Constant(constants.ConfigLoadTimeout, retry.WithUnits(30*time.Second)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\t\t\treturn oauth2Cfg.DeviceAuthFlow(ctx, r)\n\t\t\t}); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"OAuth2 device auth flow failed: %w\", err)\n\t\t\t}\n\n\t\t\textraHeaders = oauth2Cfg.ExtraHeaders()\n\t\t}\n\n\t\treturn download.Download(\n\t\t\tctx,\n\t\t\t*option,\n\t\t\tdownload.WithEndpointFunc(getURL),\n\t\t\tdownload.WithTimeout(constants.ConfigLoadTimeout),\n\t\t\tdownload.WithRetryOptions(\n\t\t\t\t// give a timeout per attempt, max 50% of that is dedicated for URL interpolation, the rest is for the actual download\n\t\t\t\tretry.WithAttemptTimeout(constants.ConfigLoadAttemptTimeout),\n\t\t\t),\n\t\t\tdownload.WithHeaders(extraHeaders),\n\t\t)\n\t}\n}\n\n// Mode implements the platform.Platform interface.\nfunc (m *Metal) Mode() runtime.Mode {\n\tif m.IsAgent {\n\t\treturn runtime.ModeMetalAgent\n\t}\n\n\treturn runtime.ModeMetal\n}\n\nfunc readConfigFromISO(ctx context.Context, r state.State) ([]byte, error) {\n\tvar b []byte\n\n\terr := blockutils.ReadFromVolume(ctx, r, []string{constants.MetalConfigISOLabel}, func(root xfs.Root, volumeStatus *block.VolumeStatus) error {\n\t\tvar err error\n\n\t\tb, err = xfs.ReadFile(root, constants.ConfigFilename)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read config: %w\", err)\n\t\t}\n\n\t\tlog.Printf(\"read machine config from volume: %s (filesystem %q, UUID %q, size %s)\",\n\t\t\tvolumeStatus.TypedSpec().Location,\n\t\t\tvolumeStatus.TypedSpec().Filesystem,\n\t\t\tvolumeStatus.TypedSpec().UUID,\n\t\t\tvolumeStatus.TypedSpec().PrettySize,\n\t\t)\n\n\t\treturn nil\n\t})\n\n\treturn b, err\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (m *Metal) KernelArgs(arch string, quirks quirks.Quirks) procfs.Parameters {\n\tswitch arch {\n\tcase \"amd64\":\n\t\tif quirks.SupportsMetalPlatformConsoleTTYS0() {\n\t\t\treturn procfs.Parameters{\n\t\t\t\tprocfs.NewParameter(\"console\").Append(\"ttyS0\").Append(\"tty0\"),\n\t\t\t}\n\t\t}\n\n\t\treturn procfs.Parameters{\n\t\t\tprocfs.NewParameter(\"console\").Append(\"tty0\"),\n\t\t}\n\tcase \"arm64\":\n\t\treturn procfs.Parameters{\n\t\t\tprocfs.NewParameter(\"console\").Append(\"ttyAMA0\").Append(\"tty0\"),\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\n//\n//nolint:gocyclo\nfunc (m *Metal) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\twatchCh := make(chan state.Event)\n\n\tif err := st.Watch(ctx, hardware.NewSystemInformation(hardware.SystemInformationID).Metadata(), watchCh); err != nil {\n\t\treturn err\n\t}\n\n\tif err := st.Watch(ctx, runtimeres.NewMetaKey(runtimeres.NamespaceName, runtimeres.MetaKeyTagToID(meta.MetalNetworkPlatformConfig)).Metadata(), watchCh); err != nil {\n\t\treturn err\n\t}\n\n\t// network config from META partition\n\tvar metaCfg runtime.PlatformNetworkConfig\n\n\t// fixed metadata filled by this function\n\tmetadata := &runtimeres.PlatformMetadataSpec{}\n\tmetadata.Platform = m.Name()\n\n\tif option := procfs.ProcCmdline().Get(constants.KernelParamHostname).First(); option != nil {\n\t\tmetadata.Hostname = *option\n\t}\n\n\tfor {\n\t\tvar event state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase event = <-watchCh:\n\t\t}\n\n\t\tswitch event.Type {\n\t\tcase state.Errored:\n\t\t\treturn fmt.Errorf(\"watch failed: %w\", event.Error)\n\t\tcase state.Bootstrapped, state.Noop:\n\t\t\t// ignored, should not happen\n\t\tcase state.Created, state.Updated:\n\t\t\tswitch r := event.Resource.(type) {\n\t\t\tcase *hardware.SystemInformation:\n\t\t\t\tmetadata.InstanceID = r.TypedSpec().UUID\n\t\t\tcase *runtimeres.MetaKey:\n\t\t\t\tmetaCfg = runtime.PlatformNetworkConfig{}\n\n\t\t\t\tif err := yaml.Unmarshal([]byte(r.TypedSpec().Value), &metaCfg); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to unmarshal metal network config from META: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\tcase state.Destroyed:\n\t\t\tswitch event.Resource.(type) {\n\t\t\tcase *hardware.SystemInformation:\n\t\t\t\tmetadata.InstanceID = \"\"\n\t\t\tcase *runtimeres.MetaKey:\n\t\t\t\tmetaCfg = runtime.PlatformNetworkConfig{}\n\t\t\t}\n\t\t}\n\n\t\tcfg := metaCfg\n\t\tcfg.Metadata = new(metadata.DeepCopy())\n\n\t\tif !channel.SendWithContext(ctx, ch, &cfg) {\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/metal_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage metal_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n//nolint:gocyclo\nfunc TestNetworkConfig(t *testing.T) {\n\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\tt.Cleanup(cancel)\n\n\tp := &metal.Metal{}\n\n\tch := make(chan *runtime.PlatformNetworkConfig, 1)\n\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tuuid := hardware.NewSystemInformation(hardware.SystemInformationID)\n\tuuid.TypedSpec().UUID = \"0123-4567-89ab-cdef\"\n\trequire.NoError(t, st.Create(ctx, uuid))\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- p.NetworkConfiguration(ctx, st, ch)\n\t}()\n\n\t// platform might see updates coming in different order, so we need to wait a bit for the final state\nouterLoop:\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\trequire.FailNow(t, \"timed out waiting for network config\")\n\t\tcase cfg := <-ch:\n\t\t\tassert.Equal(t, constants.PlatformMetal, cfg.Metadata.Platform)\n\n\t\t\tif cfg.Metadata.InstanceID == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tassert.Equal(t, uuid.TypedSpec().UUID, cfg.Metadata.InstanceID)\n\n\t\t\tbreak outerLoop\n\t\t}\n\t}\n\n\tmetaKey := runtimeres.NewMetaKey(runtimeres.NamespaceName, runtimeres.MetaKeyTagToID(meta.MetalNetworkPlatformConfig))\n\tmetaKey.TypedSpec().Value = `{\"externalIPs\": [\"1.2.3.4\"]}`\n\trequire.NoError(t, st.Create(ctx, metaKey))\n\n\t// platform might see updates coming in different order, so we need to wait a bit for the final state\nouterLoop2:\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\trequire.FailNow(t, \"timed out waiting for network config\")\n\t\tcase cfg := <-ch:\n\t\t\tassert.Equal(t, constants.PlatformMetal, cfg.Metadata.Platform)\n\t\t\tassert.Equal(t, uuid.TypedSpec().UUID, cfg.Metadata.InstanceID)\n\n\t\t\tif len(cfg.ExternalIPs) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tassert.Equal(t, \"[1.2.3.4]\", fmt.Sprintf(\"%v\", cfg.ExternalIPs))\n\n\t\t\tbreak outerLoop2\n\t\t}\n\t}\n\n\tmetaKey.TypedSpec().Value = `{\"hostnames\": [{\"hostname\": \"talos\", \"domainname\": \"fqdn\", \"layer\": \"platform\"}]}`\n\trequire.NoError(t, st.Update(ctx, metaKey))\n\n\tselect {\n\tcase <-ctx.Done():\n\t\trequire.FailNow(t, \"timed out waiting for network config\")\n\tcase cfg := <-ch:\n\t\tassert.Equal(t, constants.PlatformMetal, cfg.Metadata.Platform)\n\t\tassert.Equal(t, uuid.TypedSpec().UUID, cfg.Metadata.InstanceID)\n\n\t\tassert.Equal(t, \"[]\", fmt.Sprintf(\"%v\", cfg.ExternalIPs))\n\t\tassert.Equal(t, \"[{talos fqdn platform}]\", fmt.Sprintf(\"%v\", cfg.Hostnames))\n\t}\n\n\trequire.NoError(t, st.Destroy(ctx, metaKey.Metadata()))\n\n\tselect {\n\tcase <-ctx.Done():\n\t\trequire.FailNow(t, \"timed out waiting for network config\")\n\tcase cfg := <-ch:\n\t\tassert.Equal(t, constants.PlatformMetal, cfg.Metadata.Platform)\n\t\tassert.Equal(t, uuid.TypedSpec().UUID, cfg.Metadata.InstanceID)\n\n\t\tassert.Equal(t, \"[]\", fmt.Sprintf(\"%v\", cfg.ExternalIPs))\n\t\tassert.Equal(t, \"[]\", fmt.Sprintf(\"%v\", cfg.Hostnames))\n\t}\n\n\tcancel()\n\trequire.ErrorIs(t, <-errCh, context.Canceled)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/oauth2/oauth2.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package oauth2 implements OAuth2 Device Flow to authenticate machine config download.\npackage oauth2\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/mdp/qrterminal/v3\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/oauth2\"\n\n\tmetalurl \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Config represents the OAuth2 configuration.\ntype Config struct {\n\tClientID     string\n\tClientSecret string\n\tAudience     string\n\tScopes       []string\n\n\tExtraVariables []string\n\n\tDeviceAuthURL string\n\tTokenURL      string\n\n\textraHeaders map[string]string\n}\n\n// NewConfig returns a new Config from cmdline.\n//\n// If OAuth2 is not configured, it returns os.ErrNotExist.\n//\n//nolint:gocyclo\nfunc NewConfig(cmdline *procfs.Cmdline, downloadURL string) (*Config, error) {\n\tvar cfg Config\n\n\tclientID := cmdline.Get(constants.KernelParamConfigOAuthClientID).First()\n\n\tif clientID == nil {\n\t\treturn nil, os.ErrNotExist\n\t}\n\n\tcfg.ClientID = *clientID\n\n\tif clientSecret := cmdline.Get(constants.KernelParamConfigOAuthClientSecret).First(); clientSecret != nil {\n\t\tcfg.ClientSecret = *clientSecret\n\t}\n\n\tif audience := cmdline.Get(constants.KernelParamConfigOAuthAudience).First(); audience != nil {\n\t\tcfg.Audience = *audience\n\t}\n\n\tfor i := 0; ; i++ {\n\t\tscope := cmdline.Get(constants.KernelParamConfigOAuthScope).Get(i)\n\n\t\tif scope == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcfg.Scopes = append(cfg.Scopes, *scope)\n\t}\n\n\tfor i := 0; ; i++ {\n\t\textra := cmdline.Get(constants.KernelParamConfigOAuthExtraVariable).Get(i)\n\n\t\tif extra == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcfg.ExtraVariables = append(cfg.ExtraVariables, *extra)\n\t}\n\n\tif deviceAuthURL := cmdline.Get(constants.KernelParamConfigOAuthDeviceAuthURL).First(); deviceAuthURL != nil {\n\t\tcfg.DeviceAuthURL = *deviceAuthURL\n\t} else {\n\t\tu, err := url.Parse(downloadURL)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tu.Path = \"/device/code\"\n\n\t\tcfg.DeviceAuthURL = u.String()\n\t}\n\n\tif tokenURL := cmdline.Get(constants.KernelParamConfigOAuthTokenURL).First(); tokenURL != nil {\n\t\tcfg.TokenURL = *tokenURL\n\t} else {\n\t\tu, err := url.Parse(downloadURL)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tu.Path = \"/token\"\n\n\t\tcfg.TokenURL = u.String()\n\t}\n\n\treturn &cfg, nil\n}\n\n// DeviceAuthFlow represents the device auth flow response.\nfunc (c *Config) DeviceAuthFlow(ctx context.Context, st state.State) error {\n\ttransport := httpdefaults.PatchTransport(cleanhttp.DefaultTransport())\n\n\tclient := &http.Client{\n\t\tTransport: transport,\n\t}\n\n\t// register the HTTP client with OAuth2 flow\n\tctx = context.WithValue(ctx, oauth2.HTTPClient, client)\n\n\tcfg := oauth2.Config{\n\t\tClientID: c.ClientID,\n\t\tScopes:   c.Scopes,\n\t\tEndpoint: oauth2.Endpoint{\n\t\t\tDeviceAuthURL: c.DeviceAuthURL,\n\t\t\tTokenURL:      c.TokenURL,\n\t\t},\n\t}\n\n\tlog.Printf(\"[OAuth] starting the authentication device flow with the following settings:\")\n\tlog.Printf(\"[OAuth]  - client ID: %q\", c.ClientID)\n\tlog.Printf(\"[OAuth]  - device auth URL: %q\", c.DeviceAuthURL)\n\tlog.Printf(\"[OAuth]  - token URL: %q\", c.TokenURL)\n\tlog.Printf(\"[OAuth]  - extra variables: %q\", c.ExtraVariables)\n\n\t// acquire device variables\n\tvariables, err := c.getVariableValues(ctx, st)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get variable values: %w\", err)\n\t}\n\n\tvar deviceAuthOptions []oauth2.AuthCodeOption //nolint:prealloc\n\n\tif c.Audience != \"\" {\n\t\tdeviceAuthOptions = append(deviceAuthOptions, oauth2.SetAuthURLParam(\"audience\", c.Audience))\n\t}\n\n\tfor k, v := range variables {\n\t\tdeviceAuthOptions = append(deviceAuthOptions, oauth2.SetAuthURLParam(k, v))\n\t}\n\n\tdeviceAuthResponse, err := cfg.DeviceAuth(ctx, deviceAuthOptions...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get device auth response: %w\", err)\n\t}\n\n\tlog.Printf(\"[OAuth] please visit the URL %s and enter the code %s\", deviceAuthResponse.VerificationURI, deviceAuthResponse.UserCode)\n\n\tif deviceAuthResponse.VerificationURIComplete != \"\" {\n\t\tvar qrBuf bytes.Buffer\n\n\t\tqrterminal.GenerateHalfBlock(deviceAuthResponse.VerificationURIComplete, qrterminal.L, &qrBuf)\n\n\t\tlog.Printf(\"[OAuth] or scan the following QR code:\\n%s\", qrBuf.String())\n\t}\n\n\tlog.Printf(\"[OAuth] waiting for the device to be authorized (expires at %s)...\", deviceAuthResponse.Expiry.Format(\"15:04:05\"))\n\n\tif c.ClientSecret != \"\" {\n\t\tdeviceAuthOptions = append(deviceAuthOptions, oauth2.SetAuthURLParam(\"client_secret\", c.ClientSecret))\n\t}\n\n\ttoken, err := cfg.DeviceAccessToken(ctx, deviceAuthResponse, deviceAuthOptions...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get device access token: %w\", err)\n\t}\n\n\tlog.Printf(\"[OAuth] device authorized successfully\")\n\n\tc.extraHeaders = map[string]string{\n\t\t\"Authorization\": token.Type() + \" \" + token.AccessToken,\n\t}\n\n\treturn nil\n}\n\n// getVariableValues returns the variable values to include in the device auth request.\nfunc (c *Config) getVariableValues(ctx context.Context, st state.State) (map[string]string, error) {\n\tctx, cancel := context.WithTimeout(ctx, constants.ConfigLoadAttemptTimeout/2)\n\tdefer cancel()\n\n\treturn metalurl.MapValues(ctx, st, c.ExtraVariables)\n}\n\n// ExtraHeaders returns the extra headers to include in the download request.\nfunc (c *Config) ExtraHeaders() map[string]string {\n\treturn c.extraHeaders\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/oauth2/oauth2_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage oauth2_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/oauth2\"\n)\n\nfunc TestNewConfig(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcmdline  string\n\t\texpected *oauth2.Config\n\t}{\n\t\t{\n\t\t\tname: \"no config\",\n\t\t},\n\t\t{\n\t\t\tname:    \"only client ID\",\n\t\t\tcmdline: `talos.config.oauth.client_id=device_client_id`,\n\t\t\texpected: &oauth2.Config{\n\t\t\t\tClientID:      \"device_client_id\",\n\t\t\t\tTokenURL:      \"https://example.com/token\",\n\t\t\t\tDeviceAuthURL: \"https://example.com/device/code\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"client ID and custom URLs\",\n\t\t\tcmdline: `talos.config.oauth.client_id=device_client_id talos.config.oauth.token_url=https://google.com/token talos.config.oauth.device_auth_url=https://google.com/device/code`,\n\t\t\texpected: &oauth2.Config{\n\t\t\t\tClientID:      \"device_client_id\",\n\t\t\t\tTokenURL:      \"https://google.com/token\",\n\t\t\t\tDeviceAuthURL: \"https://google.com/device/code\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"complete config\",\n\t\t\tcmdline: `talos.config.oauth.client_id=device_client_id talos.config.oauth.client_secret=device_secret ` +\n\t\t\t\t`talos.config.oauth.token_url=https://google.com/token talos.config.oauth.device_auth_url=https://google.com/device/code ` +\n\t\t\t\t`talos.config.oauth.scope=foo talos.config.oauth.scope=bar talos.config.oauth.audience=world ` +\n\t\t\t\t`talos.config.oauth.extra_variable=uuid talos.config.oauth.extra_variable=mac`,\n\t\t\texpected: &oauth2.Config{\n\t\t\t\tClientID:       \"device_client_id\",\n\t\t\t\tClientSecret:   \"device_secret\",\n\t\t\t\tAudience:       \"world\",\n\t\t\t\tScopes:         []string{\"foo\", \"bar\"},\n\t\t\t\tExtraVariables: []string{\"uuid\", \"mac\"},\n\t\t\t\tTokenURL:       \"https://google.com/token\",\n\t\t\t\tDeviceAuthURL:  \"https://google.com/device/code\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tcfg, err := oauth2.NewConfig(procfs.NewCmdline(test.cmdline), \"https://example.com/my/config\")\n\t\t\tif test.expected == nil {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.True(t, errors.Is(err, fs.ErrNotExist))\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, test.expected, cfg)\n\t\t})\n\t}\n}\n\nfunc TestDeviceAuthFlow(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := &oauth2.Config{\n\t\tClientID: \"device_client_id\",\n\t}\n\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tdefer r.Body.Close() //nolint:errcheck\n\n\t\tt.Logf(\"received request: %s %s\", r.Method, r.RequestURI)\n\n\t\tswitch r.Method + r.RequestURI {\n\t\tcase \"POST/device/code\":\n\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\tw.Write([]byte(`{\"device_code\":\"abcd\", \"user_code\":\"1234\", \"verification_uri\":\"https://example.com/verify\",\"verification_uri_complete\":\"https://example.com/verify/1234\",\"interval\":1,\"expires_in\":36000}`)) //nolint:errcheck,lll\n\t\tcase \"POST/token\":\n\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\tw.Write([]byte(`{\"access_token\":\"abcd\",\"token_type\":\"bearer\",\"expires_in\":3600,\"refresh_token\":\"efgh\",\"id_token\":\"ijkl\"}`)) //nolint:errcheck\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n\tt.Cleanup(ts.Close)\n\n\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\tt.Cleanup(cancel)\n\n\tcfg.DeviceAuthURL = ts.URL + \"/device/code\"\n\tcfg.TokenURL = ts.URL + \"/token\"\n\n\trequire.NoError(t, cfg.DeviceAuthFlow(ctx, nil))\n\tassert.Equal(t, map[string]string{\"Authorization\": \"Bearer abcd\"}, cfg.ExtraHeaders())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/map.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\n// MapValues maps variable names to values.\n//\n//nolint:gocyclo\nfunc MapValues(ctx context.Context, st state.State, variableNames []string) (map[string]string, error) {\n\t// happy case\n\tif len(variableNames) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tavailableVariables := AllVariables()\n\tactiveVariables := make(map[string]*Variable, len(variableNames))\n\n\tfor _, variableName := range variableNames {\n\t\tif v, ok := availableVariables[variableName]; ok {\n\t\t\tactiveVariables[variableName] = v\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"unsupported variable name: %q\", variableName)\n\t\t}\n\t}\n\n\t// setup watches\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\twatchCh := make(chan state.Event)\n\n\tfor _, variable := range activeVariables {\n\t\tif err := variable.Value.RegisterWatch(ctx, st, watchCh); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error watching variable %q: %w\", variable.Key, err)\n\t\t}\n\t}\n\n\tpendingVariables := xslices.ToSet(maps.Values(activeVariables))\n\n\t// wait for all variables to be populated\nwaitLoop:\n\tfor len(pendingVariables) > 0 {\n\t\tlog.Printf(\"waiting for variables: %v\", xslices.Map(maps.Keys(pendingVariables), func(v *Variable) string { return v.Key }))\n\n\t\tvar ev state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// context was canceled, return what we have\n\t\t\tbreak waitLoop\n\t\tcase ev = <-watchCh:\n\t\t}\n\n\t\tswitch ev.Type {\n\t\tcase state.Errored:\n\t\t\treturn nil, fmt.Errorf(\"error watching variables: %w\", ev.Error)\n\t\tcase state.Bootstrapped, state.Noop:\n\t\t\t// ignored\n\t\tcase state.Created, state.Updated, state.Destroyed:\n\t\t\tfor _, variable := range activeVariables {\n\t\t\t\thandled, err := variable.Value.EventHandler(ev)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"error handling variable %q: %w\", variable.Key, err)\n\t\t\t\t}\n\n\t\t\t\tif handled {\n\t\t\t\t\tdelete(pendingVariables, variable)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn maps.Map(activeVariables, func(k string, v *Variable) (string, string) { return k, v.Value.Get() }), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/map_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n)\n\nfunc TestMapValues(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname          string\n\t\tvariableNames []string\n\n\t\tpreSetup      []setupFunc\n\t\tparallelSetup []setupFunc\n\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"no variables\",\n\t\t},\n\t\t{\n\t\t\tname:          \"multiple variables\",\n\t\t\tvariableNames: []string{\"uuid\", \"mac\", \"hostname\", \"code\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"code\":     \"top-secret\",\n\t\t\t\t\"hostname\": \"some-node\",\n\t\t\t\t\"mac\":      \"12:34:56:78:90:ce\",\n\t\t\t\t\"uuid\":     \"0000-0000\",\n\t\t\t},\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-0000\", \"12345\"),\n\t\t\t\tcreateMac(\"12:34:56:78:90:ce\"),\n\t\t\t\tcreateHostname(\"some-node\"),\n\t\t\t\tcreateCode(\"top-secret\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"mixed wait variables\",\n\t\t\tvariableNames: []string{\"uuid\", \"mac\", \"hostname\", \"code\"},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"code\":     \"\",\n\t\t\t\t\"hostname\": \"another-node\",\n\t\t\t\t\"mac\":      \"12:34:56:78:90:ab\",\n\t\t\t\t\"uuid\":     \"0000-1234\",\n\t\t\t},\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-1234\", \"12345\"),\n\t\t\t\tcreateMac(\"12:34:56:78:90:ab\"),\n\t\t\t\tcreateHostname(\"example-node\"),\n\t\t\t},\n\t\t\tparallelSetup: []setupFunc{\n\t\t\t\tsleep(time.Second),\n\t\t\t\tupdateHostname(\"another-node\"),\n\t\t\t\tsleep(time.Second / 2),\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tfor _, f := range test.preSetup {\n\t\t\t\tf(ctx, t, st)\n\t\t\t}\n\n\t\t\terrCh := make(chan error)\n\n\t\t\tvar result map[string]string\n\n\t\t\tgo func() {\n\t\t\t\tvar e error\n\n\t\t\t\tresult, e = url.MapValues(ctx, st, test.variableNames)\n\t\t\t\terrCh <- e\n\t\t\t}()\n\n\t\t\tfor _, f := range test.parallelSetup {\n\t\t\t\tf(ctx, t, st)\n\t\t\t}\n\n\t\t\terr := <-errCh\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/url.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package url handles expansion of the download URL for the config.\npackage url\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\n// Populate populates the config download URL with values replacing variables.\nfunc Populate(ctx context.Context, downloadURL string, st state.State) (string, error) {\n\treturn PopulateVariables(ctx, downloadURL, st, maps.Values(AllVariables()))\n}\n\n// PopulateVariables populates the config download URL with values replacing variables.\n//\n//nolint:gocyclo\nfunc PopulateVariables(ctx context.Context, downloadURL string, st state.State, variables []*Variable) (string, error) {\n\tu, err := url.Parse(downloadURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse URL: %w\", err)\n\t}\n\n\tquery := u.Query()\n\n\tvar activeVariables []*Variable\n\n\tfor _, variable := range variables {\n\t\tif variable.Matches(query) {\n\t\t\tactiveVariables = append(activeVariables, variable)\n\t\t}\n\t}\n\n\t// happy path: no variables\n\tif len(activeVariables) == 0 {\n\t\treturn downloadURL, nil\n\t}\n\n\t// setup watches\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\twatchCh := make(chan state.Event)\n\n\tfor _, variable := range activeVariables {\n\t\tif err = variable.Value.RegisterWatch(ctx, st, watchCh); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error watching variable %q: %w\", variable.Key, err)\n\t\t}\n\t}\n\n\tpendingVariables := xslices.ToSet(activeVariables)\n\n\t// wait for all variables to be populated\n\tfor len(pendingVariables) > 0 {\n\t\tlog.Printf(\"waiting for URL variables: %v\", xslices.Map(maps.Keys(pendingVariables), func(v *Variable) string { return v.Key }))\n\n\t\tvar ev state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// context was canceled, return the URL as is\n\t\t\tu.RawQuery = query.Encode()\n\n\t\t\treturn u.String(), ctx.Err()\n\t\tcase ev = <-watchCh:\n\t\t}\n\n\t\tswitch ev.Type {\n\t\tcase state.Errored:\n\t\t\treturn \"\", fmt.Errorf(\"error watching variables: %w\", ev.Error)\n\t\tcase state.Bootstrapped, state.Noop:\n\t\t\t// ignored\n\t\tcase state.Created, state.Updated, state.Destroyed:\n\t\t\tanyHandled := false\n\n\t\t\tfor _, variable := range activeVariables {\n\t\t\t\thandled, err := variable.Value.EventHandler(ev)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", fmt.Errorf(\"error handling variable %q: %w\", variable.Key, err)\n\t\t\t\t}\n\n\t\t\t\tif handled {\n\t\t\t\t\tdelete(pendingVariables, variable)\n\n\t\t\t\t\tanyHandled = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !anyHandled {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// perform another round of replacing\n\t\t\tquery = u.Query()\n\n\t\t\tfor _, variable := range activeVariables {\n\t\t\t\tif _, pending := pendingVariables[variable]; pending {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvariable.Replace(query)\n\t\t\t}\n\t\t}\n\t}\n\n\tu.RawQuery = query.Encode()\n\n\treturn u.String(), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/url_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\ntype setupFunc func(context.Context, *testing.T, state.State)\n\nfunc TestPopulate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\turl  string\n\n\t\tpreSetup      []setupFunc\n\t\tparallelSetup []setupFunc\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no variables\",\n\t\t\turl:      \"https://example.com?foo=bar\",\n\t\t\texpected: \"https://example.com?foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname:     \"legacy UUID\",\n\t\t\turl:      \"https://example.com?uuid=\",\n\t\t\texpected: \"https://example.com?uuid=0000-0000\",\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-0000\", \"\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"sys info\",\n\t\t\turl:      \"https://example.com?uuid=${uuid}&no=${serial}\",\n\t\t\texpected: \"https://example.com?no=12345&uuid=0000-0000\",\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-0000\", \"12345\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"multiple variables\",\n\t\t\turl:      \"https://example.com?uuid=${uuid}&mac=${mac}&hostname=${hostname}&code=${code}\",\n\t\t\texpected: \"https://example.com?code=top-secret&hostname=example-node&mac=12%3A34%3A56%3A78%3A90%3Aab&uuid=0000-0000\",\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-0000\", \"12345\"),\n\t\t\t\tcreateMac(\"12:34:56:78:90:ab\"),\n\t\t\t\tcreateHostname(\"example-node\"),\n\t\t\t\tcreateCode(\"top-secret\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"mixed wait variables\",\n\t\t\turl:      \"https://example.com?uuid=${uuid}&mac=${mac}&hostname=${hostname}&code=${code}\",\n\t\t\texpected: \"https://example.com?code=top-secret&hostname=another-node&mac=12%3A34%3A56%3A78%3A90%3Aab&uuid=0000-1234\",\n\t\t\tpreSetup: []setupFunc{\n\t\t\t\tcreateSysInfo(\"0000-1234\", \"12345\"),\n\t\t\t\tcreateMac(\"12:34:56:78:90:ab\"),\n\t\t\t\tcreateHostname(\"example-node\"),\n\t\t\t},\n\t\t\tparallelSetup: []setupFunc{\n\t\t\t\tsleep(time.Second),\n\t\t\t\tupdateHostname(\"another-node\"),\n\t\t\t\tsleep(time.Second),\n\t\t\t\tcreateCode(\"top-secret\"),\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tfor _, f := range test.preSetup {\n\t\t\t\tf(ctx, t, st)\n\t\t\t}\n\n\t\t\terrCh := make(chan error)\n\n\t\t\tvar result string\n\n\t\t\tgo func() {\n\t\t\t\tvar e error\n\n\t\t\t\tresult, e = url.Populate(ctx, test.url, st)\n\t\t\t\terrCh <- e\n\t\t\t}()\n\n\t\t\tfor _, f := range test.parallelSetup {\n\t\t\t\tf(ctx, t, st)\n\t\t\t}\n\n\t\t\terr := <-errCh\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, result)\n\t\t})\n\t}\n}\n\nfunc createSysInfo(uuid, serial string) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\tsysInfo := hardware.NewSystemInformation(hardware.SystemInformationID)\n\t\tsysInfo.TypedSpec().UUID = uuid\n\t\tsysInfo.TypedSpec().SerialNumber = serial\n\t\trequire.NoError(t, st.Create(ctx, sysInfo))\n\t}\n}\n\nfunc createMac(mac string) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\taddr, err := net.ParseMAC(mac)\n\t\trequire.NoError(t, err)\n\n\t\thwAddr := network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr)\n\t\thwAddr.TypedSpec().HardwareAddr = nethelpers.HardwareAddr(addr)\n\t\trequire.NoError(t, st.Create(ctx, hwAddr))\n\t}\n}\n\nfunc createHostname(hostname string) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\thn := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\t\thn.TypedSpec().Hostname = hostname\n\t\trequire.NoError(t, st.Create(ctx, hn))\n\t}\n}\n\nfunc updateHostname(hostname string) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\thn, err := safe.StateGet[*network.HostnameStatus](ctx, st, network.NewHostnameStatus(network.NamespaceName, network.HostnameID).Metadata())\n\t\trequire.NoError(t, err)\n\n\t\thn.TypedSpec().Hostname = hostname\n\t\trequire.NoError(t, st.Update(ctx, hn))\n\t}\n}\n\nfunc createCode(code string) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\tmk := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.DownloadURLCode))\n\t\tmk.TypedSpec().Value = code\n\t\trequire.NoError(t, st.Create(ctx, mk))\n\t}\n}\n\nfunc sleep(d time.Duration) setupFunc {\n\treturn func(ctx context.Context, t *testing.T, st state.State) {\n\t\ttime.Sleep(d)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/value.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Value of a variable.\ntype Value interface {\n\t// Get the value.\n\tGet() string\n\t// RegisterWatch handles registering a watch for the variable.\n\tRegisterWatch(ctx context.Context, st state.State, ch chan<- state.Event) error\n\t// EventHandler is called for each watch event, returns when the variable value is ready.\n\tEventHandler(event state.Event) (bool, error)\n}\n\ntype value struct {\n\tmu  sync.Mutex\n\tval string\n\n\tregisterWatch func(ctx context.Context, st state.State, ch chan<- state.Event) error\n\teventHandler  func(event state.Event) (string, error)\n}\n\nfunc (v *value) Get() string {\n\tv.mu.Lock()\n\tdefer v.mu.Unlock()\n\n\treturn v.val\n}\n\nfunc (v *value) RegisterWatch(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\treturn v.registerWatch(ctx, st, ch)\n}\n\nfunc (v *value) EventHandler(event state.Event) (bool, error) {\n\tval, err := v.eventHandler(event)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif val == \"\" {\n\t\treturn false, nil\n\t}\n\n\tv.mu.Lock()\n\tv.val = val\n\tv.mu.Unlock()\n\n\treturn true, nil\n}\n\n// UUIDValue is a value for UUID variable.\nfunc UUIDValue() Value {\n\treturn &value{\n\t\tregisterWatch: func(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\t\t\treturn st.Watch(ctx, hardware.NewSystemInformation(hardware.SystemInformationID).Metadata(), ch)\n\t\t},\n\t\teventHandler: func(event state.Event) (string, error) {\n\t\t\tsysInfo, ok := event.Resource.(*hardware.SystemInformation)\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn sysInfo.TypedSpec().UUID, nil\n\t\t},\n\t}\n}\n\n// SerialNumberValue is a value for SerialNumber variable.\nfunc SerialNumberValue() Value {\n\treturn &value{\n\t\tregisterWatch: func(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\t\t\treturn st.Watch(ctx, hardware.NewSystemInformation(hardware.SystemInformationID).Metadata(), ch)\n\t\t},\n\t\teventHandler: func(event state.Event) (string, error) {\n\t\t\tsysInfo, ok := event.Resource.(*hardware.SystemInformation)\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn sysInfo.TypedSpec().SerialNumber, nil\n\t\t},\n\t}\n}\n\n// MACValue is a value for MAC variable.\nfunc MACValue() Value {\n\treturn &value{\n\t\tregisterWatch: func(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\t\t\treturn st.Watch(ctx, network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr).Metadata(), ch)\n\t\t},\n\t\teventHandler: func(event state.Event) (string, error) {\n\t\t\thwAddr, ok := event.Resource.(*network.HardwareAddr)\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn hwAddr.TypedSpec().HardwareAddr.String(), nil\n\t\t},\n\t}\n}\n\n// HostnameValue is a value for Hostname variable.\nfunc HostnameValue() Value {\n\treturn &value{\n\t\tregisterWatch: func(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\t\t\treturn st.Watch(ctx, network.NewHostnameStatus(network.NamespaceName, network.HostnameID).Metadata(), ch)\n\t\t},\n\t\teventHandler: func(event state.Event) (string, error) {\n\t\t\thostname, ok := event.Resource.(*network.HostnameStatus)\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn hostname.TypedSpec().Hostname, nil\n\t\t},\n\t}\n}\n\n// CodeValue is a value for Code variable.\nfunc CodeValue() Value {\n\treturn &value{\n\t\tregisterWatch: func(ctx context.Context, st state.State, ch chan<- state.Event) error {\n\t\t\treturn st.Watch(ctx, runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(meta.DownloadURLCode)).Metadata(), ch)\n\t\t},\n\t\teventHandler: func(event state.Event) (string, error) {\n\t\t\tcode, ok := event.Resource.(*runtime.MetaKey)\n\t\t\tif !ok {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\n\t\t\treturn code.TypedSpec().Value, nil\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/variable.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url\n\nimport (\n\t\"net/url\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Variable represents a variable substitution in the download URL.\ntype Variable struct {\n\t// Key is the variable name.\n\tKey string\n\t// MatchOnArg is set for variables which are match on the arg name with empty value.\n\t//\n\t// Required to support legacy `?uuid=` style of the download URL.\n\tMatchOnArg bool\n\t// Value is the variable value.\n\tValue Value\n\n\trOnce sync.Once\n\tr     *regexp.Regexp\n}\n\n// AllVariables is a map of all supported variables.\nfunc AllVariables() map[string]*Variable {\n\treturn map[string]*Variable{\n\t\tconstants.UUIDKey: {\n\t\t\tKey:        constants.UUIDKey,\n\t\t\tMatchOnArg: true,\n\t\t\tValue:      UUIDValue(),\n\t\t},\n\t\tconstants.SerialNumberKey: {\n\t\t\tKey:   constants.SerialNumberKey,\n\t\t\tValue: SerialNumberValue(),\n\t\t},\n\t\tconstants.MacKey: {\n\t\t\tKey:   constants.MacKey,\n\t\t\tValue: MACValue(),\n\t\t},\n\t\tconstants.HostnameKey: {\n\t\t\tKey:   constants.HostnameKey,\n\t\t\tValue: HostnameValue(),\n\t\t},\n\t\tconstants.CodeKey: {\n\t\t\tKey:   constants.CodeKey,\n\t\t\tValue: CodeValue(),\n\t\t},\n\t}\n}\n\nfunc keyToVar(key string) string {\n\treturn `${` + key + `}`\n}\n\nfunc (v *Variable) init() {\n\tv.rOnce.Do(func() {\n\t\tv.r = regexp.MustCompile(`(?i)` + regexp.QuoteMeta(keyToVar(v.Key)))\n\t})\n}\n\n// Matches checks if the variable is present in the URL.\nfunc (v *Variable) Matches(query url.Values) bool {\n\tv.init()\n\n\tfor arg, values := range query {\n\t\tif v.MatchOnArg {\n\t\t\tif arg == v.Key && !(len(values) == 1 && strings.TrimSpace(values[0]) != \"\") {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tif slices.ContainsFunc(values, v.r.MatchString) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Replace modifies the URL query replacing the variable with the value.\nfunc (v *Variable) Replace(query url.Values) {\n\tv.init()\n\n\tfor arg, values := range query {\n\t\tif v.MatchOnArg {\n\t\t\tif arg == v.Key && !(len(values) == 1 && strings.TrimSpace(values[0]) != \"\") {\n\t\t\t\tquery.Set(arg, v.Value.Get())\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tfor idx, value := range values {\n\t\t\tvalues[idx] = v.r.ReplaceAllString(value, v.Value.Get())\n\t\t}\n\n\t\tquery[arg] = values\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url/variable_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage url_test\n\nimport (\n\t\"context\"\n\tneturl \"net/url\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestVariableMatches(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname        string\n\t\turl         string\n\t\tshouldMatch map[string]struct{}\n\t}{\n\t\t{\n\t\t\tname: \"no matches\",\n\t\t\turl:  \"https://example.com?foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname: \"legacy UUID\",\n\t\t\turl:  \"https://example.com?uuid=&foo=bar\",\n\t\t\tshouldMatch: map[string]struct{}{\n\t\t\t\tconstants.UUIDKey: {},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UUID static\",\n\t\t\turl:  \"https://example.com?uuid=0000-0000&foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname: \"more variables\",\n\t\t\turl:  \"https://example.com?uuid=${uuid}&foo=bar&serial=${serial}&mac=${mac}&hostname=fixed&hostname=${hostname}\",\n\t\t\tshouldMatch: map[string]struct{}{\n\t\t\t\tconstants.UUIDKey:         {},\n\t\t\t\tconstants.SerialNumberKey: {},\n\t\t\t\tconstants.MacKey:          {},\n\t\t\t\tconstants.HostnameKey:     {},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"case insensitive\",\n\t\t\turl:  \"https://example.com?uuid=${UUId}&foo=bar&serial=${SeRiaL}\",\n\t\t\tshouldMatch: map[string]struct{}{\n\t\t\t\tconstants.UUIDKey:         {},\n\t\t\t\tconstants.SerialNumberKey: {},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tu, err := neturl.Parse(test.url)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor _, variable := range url.AllVariables() {\n\t\t\t\tif _, ok := test.shouldMatch[variable.Key]; ok {\n\t\t\t\t\tassert.True(t, variable.Matches(u.Query()))\n\t\t\t\t} else {\n\t\t\t\t\tassert.False(t, variable.Matches(u.Query()))\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype mockValue struct {\n\tvalue string\n}\n\nfunc (v mockValue) Get() string {\n\treturn v.value\n}\n\nfunc (v mockValue) RegisterWatch(context.Context, state.State, chan<- state.Event) error {\n\treturn nil\n}\n\nfunc (v mockValue) EventHandler(state.Event) (bool, error) {\n\treturn true, nil\n}\n\nfunc TestVariableReplace(t *testing.T) {\n\tt.Parallel()\n\n\tvar1 := &url.Variable{\n\t\tKey:        \"var1\",\n\t\tMatchOnArg: true,\n\t\tValue: mockValue{\n\t\t\tvalue: \"value1\",\n\t\t},\n\t}\n\n\tvar2 := &url.Variable{\n\t\tKey: \"var2\",\n\t\tValue: mockValue{\n\t\t\tvalue: \"value2\",\n\t\t},\n\t}\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\turl      string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no matches\",\n\t\t\turl:      \"https://example.com?foo=bar\",\n\t\t\texpected: \"https://example.com?foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname:     \"legacy match\",\n\t\t\turl:      \"https://example.com?var1=&foo=bar\",\n\t\t\texpected: \"https://example.com?foo=bar&var1=value1\",\n\t\t},\n\t\t{\n\t\t\tname:     \"variable match\",\n\t\t\turl:      \"https://example.com?a=${var1}-suffix&foo=bar&b=${var2}&b=xyz&b=${var2}\",\n\t\t\texpected: \"https://example.com?a=value1-suffix&b=value2&b=xyz&b=value2&foo=bar\",\n\t\t},\n\t\t{\n\t\t\tname:     \"case insensitive\",\n\t\t\turl:      \"https://example.com?a=${VAR1}\",\n\t\t\texpected: \"https://example.com?a=value1\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tu, err := neturl.Parse(test.url)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tquery := u.Query()\n\n\t\t\tfor _, variable := range []*url.Variable{var1, var2} {\n\t\t\t\tvariable.Replace(query)\n\t\t\t}\n\n\t\t\tu.RawQuery = query.Encode()\n\n\t\t\tassert.Equal(t, test.expected, u.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/metal/url_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage metal_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc createOrUpdate(ctx context.Context, st state.State, r resource.Resource) error {\n\toldRes, err := st.Get(ctx, r.Metadata())\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn err\n\t}\n\n\tif oldRes == nil {\n\t\terr = st.Create(ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tr.Metadata().SetVersion(oldRes.Metadata().Version())\n\n\t\terr = st.Update(ctx, r)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setup(ctx context.Context, t *testing.T, st state.State, mockUUID, mockSerialNumber, mockHostname, mockMAC string) {\n\tsysInfo := hardware.NewSystemInformation(hardware.SystemInformationID)\n\tsysInfo.TypedSpec().UUID = mockUUID\n\tsysInfo.TypedSpec().SerialNumber = mockSerialNumber\n\tassert.NoError(t, createOrUpdate(ctx, st, sysInfo))\n\n\thostnameSpec := network.NewHostnameStatus(network.NamespaceName, network.HostnameID)\n\thostnameSpec.TypedSpec().Hostname = mockHostname\n\tassert.NoError(t, createOrUpdate(ctx, st, hostnameSpec))\n\n\tlinkStatusSpec := network.NewHardwareAddr(network.NamespaceName, network.FirstHardwareAddr)\n\tparsedMockMAC, err := net.ParseMAC(mockMAC)\n\tassert.NoError(t, err)\n\n\tlinkStatusSpec.TypedSpec().HardwareAddr = nethelpers.HardwareAddr(parsedMockMAC)\n\tassert.NoError(t, createOrUpdate(ctx, st, linkStatusSpec))\n\n\tnetStatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\tnetStatus.TypedSpec().AddressReady = true\n\tassert.NoError(t, createOrUpdate(ctx, st, netStatus))\n}\n\nfunc TestRepopulateOnRetry(t *testing.T) {\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\tdefer cancel()\n\n\tnCalls := 0\n\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch nCalls {\n\t\tcase 0:\n\t\t\tassert.Equal(t, \"h=myTestHostname&m=52%3A2f%3Afd%3Adf%3Afc%3Ac0&s=0OCZJ19N65&u=40dcbd19-3b10-444e-bfff-aaee44a51fda\", r.URL.RawQuery)\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\n\t\t\t// After the first call we change the resources that should be substituted in the next call.\n\t\t\tuuid2 := \"9fba530f-767d-40f9-9410-bb1fed5d2134\"\n\t\t\tmac2 := \"aa:aa:bb:bb:cc:cc\"\n\t\t\tserialNumber2 := \"111AAA9N65\"\n\t\t\thostname2 := \"anotherHostname\"\n\n\t\t\tsetup(ctx, t, st, uuid2, serialNumber2, hostname2, mac2)\n\t\tcase 1:\n\t\t\t// Before the second call Configuration() should have resubstituted all the new parameters in the URL.\n\t\t\tassert.Equal(t, \"h=anotherHostname&m=aa%3Aaa%3Abb%3Abb%3Acc%3Acc&s=111AAA9N65&u=9fba530f-767d-40f9-9410-bb1fed5d2134\", r.URL.RawQuery)\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}\n\n\t\tnCalls++\n\t}))\n\tdefer server.Close()\n\n\tuuid1 := \"40dcbd19-3b10-444e-bfff-aaee44a51fda\"\n\tmac1 := \"52:2f:fd:df:fc:c0\"\n\tserialNumber1 := \"0OCZJ19N65\"\n\thostname1 := \"myTestHostname\"\n\n\tsetup(ctx, t, st, uuid1, serialNumber1, hostname1, mac1)\n\n\tdownloadURL := server.URL + \"/metadata?h=${hostname}&m=${mac}&s=${serial}&u=${uuid}\"\n\n\tparam := procfs.NewParameter(constants.KernelParamConfig)\n\tparam.Append(downloadURL)\n\n\tprocfs.ProcCmdline().Set(constants.KernelParamConfig, param)\n\tdefer procfs.ProcCmdline().Set(constants.KernelParamConfig, nil)\n\n\tgo func() {\n\t\ttestObj := metal.Metal{}\n\t\t_, err := testObj.Configuration(ctx, st)\n\t\tassert.NoError(t, err)\n\n\t\tcancel()\n\t}()\n\n\t<-ctx.Done()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package nocloud provides the NoCloud platform implementation.\npackage nocloud\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/internal/pkg/smbios\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\nconst (\n\tconfigISOLabel          = \"cidata\"\n\tconfigNetworkConfigPath = \"network-config\"\n\tconfigMetaDataPath      = \"meta-data\"\n\tconfigUserDataPath      = \"user-data\"\n)\n\n// NetworkCloudInitConfig wraps nocloud network config to match cloud-init format.\ntype NetworkCloudInitConfig struct {\n\tConfig NetworkConfig `yaml:\"network\"`\n}\n\n// NetworkConfig holds network-config info.\ntype NetworkConfig struct {\n\tVersion   int                 `yaml:\"version\"`\n\tConfig    []ConfigV1          `yaml:\"config,omitempty\"`\n\tEthernets map[string]Ethernet `yaml:\"ethernets,omitempty\"`\n\tBonds     map[string]Bond     `yaml:\"bonds,omitempty\"`\n\tVLANs     map[string]VLAN     `yaml:\"vlans,omitempty\"`\n}\n\n// ConfigV1 holds nocloud v1 config.\ntype ConfigV1 struct {\n\tMac        string `yaml:\"mac_address,omitempty\"`\n\tInterfaces string `yaml:\"name,omitempty\"`\n\tMTU        uint32 `yaml:\"mtu,omitempty\"`\n\tSubnets    []struct {\n\t\tAddress string `yaml:\"address,omitempty\"`\n\t\tNetmask string `yaml:\"netmask,omitempty\"`\n\t\tGateway string `yaml:\"gateway,omitempty\"`\n\t\tType    string `yaml:\"type\"`\n\t} `yaml:\"subnets,omitempty\"`\n\tAddress        []string      `yaml:\"address,omitempty\"`\n\tType           string        `yaml:\"type\"`\n\tBondInterfaces []string      `yaml:\"bond_interfaces,omitempty\"`\n\tVlanID         uint16        `yaml:\"vlan_id,omitempty\"`\n\tVlanLink       string        `yaml:\"vlan_link,omitempty\"`\n\tParams         NetworkParams `yaml:\"params,omitempty\"`\n}\n\n// Ethernet holds network interface info.\ntype Ethernet struct {\n\tMatch struct {\n\t\tName   string `yaml:\"name,omitempty\"`\n\t\tHWAddr string `yaml:\"macaddress,omitempty\"`\n\t} `yaml:\"match,omitempty\"`\n\tDHCPv4      bool     `yaml:\"dhcp4,omitempty\"`\n\tDHCPv6      bool     `yaml:\"dhcp6,omitempty\"`\n\tAddress     []string `yaml:\"addresses,omitempty\"`\n\tGateway4    string   `yaml:\"gateway4,omitempty\"`\n\tGateway6    string   `yaml:\"gateway6,omitempty\"`\n\tMTU         uint32   `yaml:\"mtu,omitempty\"`\n\tNameServers struct {\n\t\tSearch  []string `yaml:\"search,omitempty\"`\n\t\tAddress []string `yaml:\"addresses,omitempty\"`\n\t} `yaml:\"nameservers,omitempty\"`\n\tRoutes []struct {\n\t\tTo     string `yaml:\"to,omitempty\"`\n\t\tVia    string `yaml:\"via,omitempty\"`\n\t\tMetric uint32 `yaml:\"metric,omitempty\"`\n\t\tTable  uint32 `yaml:\"table,omitempty\"`\n\t\tOnLink bool   `yaml:\"on-link,omitempty\"`\n\t} `yaml:\"routes,omitempty\"`\n\tRoutingPolicy []struct { // TODO\n\t\tFrom  string `yaml:\"froom,omitempty\"`\n\t\tTable uint32 `yaml:\"table,omitempty\"`\n\t} `yaml:\"routing-policy,omitempty\"`\n}\n\n// Bond holds bonding interface info.\ntype Bond struct {\n\tEthernet `yaml:\",inline\"`\n\n\tInterfaces []string `yaml:\"interfaces,omitempty\"`\n\tParams     struct {\n\t\tMode       string `yaml:\"mode,omitempty\"`\n\t\tLACPRate   string `yaml:\"lacp-rate,omitempty\"`\n\t\tHashPolicy string `yaml:\"transmit-hash-policy,omitempty\"`\n\t\tMIIMon     uint32 `yaml:\"mii-monitor-interval,omitempty\"`\n\t\tUpDelay    uint32 `yaml:\"up-delay,omitempty\"`\n\t\tDownDelay  uint32 `yaml:\"down-delay,omitempty\"`\n\t} `yaml:\"parameters,omitempty\"`\n}\n\n// VLAN holds vlan interface info.\ntype VLAN struct {\n\tEthernet `yaml:\",inline\"`\n\n\tID   uint16 `yaml:\"id,omitempty\"`\n\tLink string `yaml:\"link,omitempty\"`\n}\n\n// MetadataConfig holds meta info.\ntype MetadataConfig struct {\n\tHostname     string `yaml:\"hostname,omitempty\"`\n\tInternalDNS  string `yaml:\"local-hostname,omitempty\"`\n\tExternalDNS  string `yaml:\"public-hostname,omitempty\"`\n\tInstanceID   string `yaml:\"instance-id,omitempty\"`\n\tInstanceType string `yaml:\"instance-type,omitempty\"`\n\tProviderID   string `yaml:\"provider-id,omitempty\"`\n\tRegion       string `yaml:\"region,omitempty\"`\n\tZone         string `yaml:\"zone,omitempty\"`\n}\n\n// NetworkParams holds network parameters (mostly bond for v1 network-config).\ntype NetworkParams struct {\n\tBondLACPRate       string `yaml:\"bond-lacp-rate,omitempty\"`\n\tBondMiimon         uint32 `yaml:\"bond-miimon,omitempty\"`\n\tBondMode           string `yaml:\"bond-mode,omitempty\"`\n\tBondXmitHashPolicy string `yaml:\"bond-xmit-hash-policy,omitempty\"`\n\tUpDelay            uint32 `yaml:\"up-delay,omitempty\"`\n\tDownDelay          uint32 `yaml:\"down-delay,omitempty\"`\n}\n\nfunc (n *Nocloud) configFromNetwork(ctx context.Context, metaBaseURL string, r state.State) (metaConfig []byte, networkConfig []byte, machineConfig []byte, err error) {\n\tlog.Printf(\"fetching meta config from: %q\", metaBaseURL+configMetaDataPath)\n\n\tif err = netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tmetaConfig, err = download.Download(ctx, metaBaseURL+configMetaDataPath)\n\tif err != nil {\n\t\tmetaConfig = nil\n\t}\n\n\tlog.Printf(\"fetching network config from: %q\", metaBaseURL+configNetworkConfigPath)\n\n\tnetworkConfig, err = download.Download(ctx, metaBaseURL+configNetworkConfigPath)\n\tif err != nil {\n\t\tnetworkConfig = nil\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", metaBaseURL+configUserDataPath)\n\n\tmachineConfig, err = download.Download(ctx, metaBaseURL+configUserDataPath,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\n\treturn metaConfig, networkConfig, machineConfig, err\n}\n\n//nolint:gocyclo\nfunc (n *Nocloud) configFromCD(ctx context.Context, r state.State) (metaConfig []byte, networkConfig []byte, machineConfig []byte, err error) {\n\terr = blockutils.ReadFromVolume(ctx, r,\n\t\t[]string{strings.ToLower(configISOLabel), strings.ToUpper(configISOLabel)},\n\t\tfunc(root xfs.Root, volumeStatus *block.VolumeStatus) error {\n\t\t\tlog.Printf(\"found config disk (cidata) at %s\", volumeStatus.TypedSpec().Location)\n\n\t\t\tlog.Printf(\"fetching meta config from: cidata/%s\", configMetaDataPath)\n\n\t\t\tmetaConfig, err = xfs.ReadFile(root, configMetaDataPath)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"failed to read %s: %s\", configMetaDataPath, err)\n\n\t\t\t\tmetaConfig = nil\n\t\t\t}\n\n\t\t\tlog.Printf(\"fetching network config from: cidata/%s\", configNetworkConfigPath)\n\n\t\t\tnetworkConfig, err = xfs.ReadFile(root, configNetworkConfigPath)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"failed to read %s: %s\", configNetworkConfigPath, err)\n\n\t\t\t\tnetworkConfig = nil\n\t\t\t}\n\n\t\t\tlog.Printf(\"fetching machine config from: cidata/%s\", configUserDataPath)\n\n\t\t\tmachineConfig, err = xfs.ReadFile(root, configUserDataPath)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"failed to read %s: %s\", configUserDataPath, err)\n\n\t\t\t\tmachineConfig = nil\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\tif err != nil {\n\t\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil, nil, errors.ErrNoConfigSource\n\t\t}\n\n\t\treturn nil, nil, nil, err\n\t}\n\n\tif machineConfig == nil {\n\t\terr = errors.ErrNoConfigSource\n\t}\n\n\treturn metaConfig, networkConfig, machineConfig, err\n}\n\n//nolint:gocyclo\nfunc (n *Nocloud) acquireConfig(ctx context.Context, r state.State) (metadataNetworkConfigDl, machineConfigDl []byte, metadata *MetadataConfig, err error) {\n\ts, err := smbios.GetSMBIOSInfo()\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tvar (\n\t\tmetaBaseURL, hostname, instanceID string\n\t\tnetworkSource                     bool\n\t)\n\n\tfor option := range strings.SplitSeq(s.SystemInformation.SerialNumber, \";\") {\n\t\tparts := strings.SplitN(option, \"=\", 2)\n\t\tif len(parts) == 2 {\n\t\t\tswitch parts[0] {\n\t\t\tcase \"ds\":\n\t\t\t\tif parts[1] == \"nocloud-net\" {\n\t\t\t\t\tnetworkSource = true\n\t\t\t\t}\n\t\t\tcase \"s\":\n\t\t\t\tvar u *url.URL\n\n\t\t\t\tu, err = url.Parse(parts[1])\n\t\t\t\tif err == nil && strings.HasPrefix(u.Scheme, \"http\") {\n\t\t\t\t\tif strings.HasSuffix(u.Path, \"/\") {\n\t\t\t\t\t\tmetaBaseURL = parts[1]\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmetaBaseURL = parts[1] + \"/\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase \"h\":\n\t\t\t\thostname = parts[1]\n\n\t\t\tcase \"i\":\n\t\t\t\tinstanceID = parts[1]\n\t\t\t}\n\t\t}\n\t}\n\n\tvar metadataConfigDl []byte\n\n\tif networkSource && metaBaseURL != \"\" {\n\t\tmetadataConfigDl, metadataNetworkConfigDl, machineConfigDl, err = n.configFromNetwork(ctx, metaBaseURL, r)\n\t} else {\n\t\tmetadataConfigDl, metadataNetworkConfigDl, machineConfigDl, err = n.configFromCD(ctx, r)\n\t}\n\n\tmetadata = &MetadataConfig{}\n\n\tif metadataConfigDl != nil {\n\t\t_ = yaml.Unmarshal(metadataConfigDl, metadata) //nolint:errcheck\n\t}\n\n\tif hostname != \"\" {\n\t\tmetadata.Hostname = hostname\n\t}\n\n\tif instanceID != \"\" {\n\t\tmetadata.InstanceID = instanceID\n\t}\n\n\t// Some providers may provide the hostname via user-data instead of meta-data (e.g. Proxmox VE)\n\t// As long as the user doesn't use it for machine config, it can still be used to obtain the hostname\n\tif metadata.Hostname == \"\" && metadata.InternalDNS == \"\" && machineConfigDl != nil {\n\t\tfallbackMetadata := &MetadataConfig{}\n\t\t_ = yaml.Unmarshal(machineConfigDl, fallbackMetadata) //nolint:errcheck\n\t\tmetadata.Hostname = fallbackMetadata.Hostname\n\t\tmetadata.InternalDNS = fallbackMetadata.InternalDNS\n\t}\n\n\treturn metadataNetworkConfigDl, machineConfigDl, metadata, err\n}\n\n//nolint:gocyclo,cyclop\nfunc (n *Nocloud) applyNetworkConfigV1(ctx context.Context, config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) (bool, error) {\n\thostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"error listing host interfaces: %w\", err)\n\t}\n\n\tvar needsReconcile bool\n\n\tparseSubnets := func(ntwrk ConfigV1, name string) error {\n\t\tfor _, subnet := range ntwrk.Subnets {\n\t\t\tswitch subnet.Type {\n\t\t\tcase \"dhcp\", \"dhcp4\":\n\t\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\tLinkName:  name,\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t})\n\t\t\tcase \"static\", \"static6\":\n\t\t\t\tfamily := nethelpers.FamilyInet4\n\n\t\t\t\tif subnet.Type == \"static6\" {\n\t\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t\t}\n\n\t\t\t\tipPrefix, err := netip.ParsePrefix(subnet.Address)\n\t\t\t\tif err != nil {\n\t\t\t\t\tip, err := netip.ParseAddr(subnet.Address)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tnetmask, err := netip.ParseAddr(subnet.Netmask)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tmask, _ := netmask.MarshalBinary() //nolint:errcheck // never fails\n\t\t\t\t\tones, _ := net.IPMask(mask).Size()\n\t\t\t\t\tipPrefix = netip.PrefixFrom(ip, ones)\n\t\t\t\t}\n\n\t\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t\tLinkName:    name,\n\t\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\t\tFamily:      family,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\tif subnet.Gateway != \"\" {\n\t\t\t\t\tgw, err := netip.ParseAddr(subnet.Gateway)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t\tGateway:     gw,\n\t\t\t\t\t\tOutLinkName: name,\n\t\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\t\tFamily:      family,\n\t\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\t}\n\n\t\t\t\t\tif family == nethelpers.FamilyInet6 {\n\t\t\t\t\t\troute.Priority = 2 * network.DefaultRouteMetric\n\t\t\t\t\t}\n\n\t\t\t\t\troute.Normalize()\n\n\t\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t\t}\n\t\t\tcase \"ipv6_dhcpv6-stateful\":\n\t\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\t\tLinkName:  name,\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\t\tRouteMetric: 2 * network.DefaultRouteMetric,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tphysicalNameMap := map[string]string{}\n\n\ttype enslavedLink struct {\n\t\tbondName   string\n\t\tslaveIndex int\n\t}\n\n\tenslavedLinks := map[string]enslavedLink{}\n\n\tfor _, ntwrk := range config.Config {\n\t\tswitch ntwrk.Type {\n\t\tcase \"nameserver\":\n\t\t\tdnsIPs := make([]netip.Addr, 0, len(ntwrk.Address))\n\n\t\t\tfor i := range ntwrk.Address {\n\t\t\t\tif ip, err := netip.ParseAddr(ntwrk.Address[i]); err == nil {\n\t\t\t\t\tdnsIPs = append(dnsIPs, ip)\n\t\t\t\t} else {\n\t\t\t\t\treturn false, err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\t\tDNSServers:  dnsIPs,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\tcase \"bond\":\n\t\t\tname := ntwrk.Interfaces\n\n\t\t\tmode, err := nethelpers.BondModeByName(ntwrk.Params.BondMode)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"invalid mode: %w\", err)\n\t\t\t}\n\n\t\t\thashPolicy, err := nethelpers.BondXmitHashPolicyByName(ntwrk.Params.BondXmitHashPolicy)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"invalid transmit-hash-policy: %w\", err)\n\t\t\t}\n\n\t\t\tlacpRate, err := nethelpers.LACPRateByName(ntwrk.Params.BondLACPRate)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"invalid lacp-rate: %w\", err)\n\t\t\t}\n\n\t\t\tbondLink := network.LinkSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tName:        name,\n\t\t\t\tLogical:     true,\n\t\t\t\tUp:          true,\n\t\t\t\tKind:        network.LinkKindBond,\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tBondMaster: network.BondMasterSpec{\n\t\t\t\t\tMode:       mode,\n\t\t\t\t\tHashPolicy: hashPolicy,\n\t\t\t\t\tMIIMon:     ntwrk.Params.BondMiimon,\n\t\t\t\t\tUpDelay:    ntwrk.Params.UpDelay,\n\t\t\t\t\tDownDelay:  ntwrk.Params.DownDelay,\n\t\t\t\t\tLACPRate:   lacpRate,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tif mode == nethelpers.BondMode8023AD {\n\t\t\t\tbondLink.BondMaster.ADLACPActive = nethelpers.ADLACPActiveOn\n\t\t\t}\n\n\t\t\tif ntwrk.MTU != 0 {\n\t\t\t\tbondLink.MTU = ntwrk.MTU\n\t\t\t}\n\n\t\t\tnetworkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()\n\t\t\tnetworkConfig.Links = append(networkConfig.Links, bondLink)\n\n\t\t\tfor idx, slave := range ntwrk.BondInterfaces {\n\t\t\t\tenslavedLinks[slave] = enslavedLink{\n\t\t\t\t\tbondName:   name,\n\t\t\t\t\tslaveIndex: idx,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err = parseSubnets(ntwrk, name); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\tcase \"vlan\":\n\t\t\tname := ntwrk.Interfaces\n\n\t\t\tparentName, ok := physicalNameMap[ntwrk.VlanLink]\n\t\t\tif !ok {\n\t\t\t\tparentName = ntwrk.VlanLink\n\t\t\t}\n\n\t\t\tlinkSpec := network.LinkSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tName:        name,\n\t\t\t\tLogical:     true,\n\t\t\t\tUp:          true,\n\t\t\t\tKind:        network.LinkKindVLAN,\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tParentName:  parentName,\n\t\t\t\tVLAN: network.VLANSpec{\n\t\t\t\t\tVID:      ntwrk.VlanID,\n\t\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tif ntwrk.MTU != 0 {\n\t\t\t\tlinkSpec.MTU = ntwrk.MTU\n\t\t\t}\n\n\t\t\tnetworkConfig.Links = append(networkConfig.Links, linkSpec)\n\n\t\t\tif err = parseSubnets(ntwrk, name); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\tcase \"physical\":\n\t\t\tname := ntwrk.Interfaces\n\n\t\t\tif ntwrk.Mac != \"\" {\n\t\t\t\tmacAddressMatched := false\n\n\t\t\t\tfor hostInterface := range hostInterfaces.All() {\n\t\t\t\t\tif !hostInterface.TypedSpec().Physical() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tmacAddress := hostInterface.TypedSpec().PermanentAddr.String()\n\t\t\t\t\tif macAddress == \"\" {\n\t\t\t\t\t\tmacAddress = hostInterface.TypedSpec().HardwareAddr.String()\n\t\t\t\t\t}\n\n\t\t\t\t\tif strings.EqualFold(macAddress, ntwrk.Mac) {\n\t\t\t\t\t\tname = hostInterface.Metadata().ID()\n\t\t\t\t\t\tmacAddressMatched = true\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif !macAddressMatched {\n\t\t\t\t\tlog.Printf(\"nocloud: no link with matching MAC address %q, defaulted to use name %s instead\", ntwrk.Mac, name)\n\n\t\t\t\t\tneedsReconcile = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tphysicalNameMap[ntwrk.Interfaces] = name\n\n\t\t\tlinkSpec := network.LinkSpecSpec{\n\t\t\t\tName:        name,\n\t\t\t\tUp:          true,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t}\n\n\t\t\tif ntwrk.MTU != 0 {\n\t\t\t\tlinkSpec.MTU = ntwrk.MTU\n\t\t\t}\n\n\t\t\tnetworkConfig.Links = append(networkConfig.Links, linkSpec)\n\n\t\t\tif err = parseSubnets(ntwrk, name); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t}\n\t}\n\n\tfor slaveName, enslavedLink := range enslavedLinks {\n\t\tphysicalName, ok := physicalNameMap[slaveName]\n\t\tif !ok {\n\t\t\tphysicalName = slaveName\n\t\t}\n\n\t\tfor idx := range networkConfig.Links {\n\t\t\tif networkConfig.Links[idx].Name != physicalName {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tnetworkConfig.Links[idx].BondSlave = network.BondSlave{\n\t\t\t\tMasterName: enslavedLink.bondName,\n\t\t\t\tSlaveIndex: enslavedLink.slaveIndex,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn needsReconcile, nil\n}\n\n//nolint:gocyclo,cyclop\nfunc applyNetworkConfigV2Ethernet(name string, eth Ethernet, networkConfig *runtime.PlatformNetworkConfig, dnsIPs *[]netip.Addr) error {\n\tif eth.DHCPv4 {\n\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\tLinkName:  name,\n\t\t\tRequireUp: true,\n\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tif eth.DHCPv6 {\n\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\tLinkName:  name,\n\t\t\tRequireUp: true,\n\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tfor _, addr := range eth.Address {\n\t\tipPrefix, err := netip.ParsePrefix(addr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfamily := nethelpers.FamilyInet4\n\n\t\tif ipPrefix.Addr().Is6() {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    name,\n\t\t\t\tAddress:     ipPrefix,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      family,\n\t\t\t},\n\t\t)\n\t}\n\n\tif eth.Gateway4 != \"\" {\n\t\tgw, err := netip.ParseAddr(eth.Gateway4)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     gw,\n\t\t\tOutLinkName: name,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t}\n\n\t\troute.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t}\n\n\tif eth.Gateway6 != \"\" {\n\t\tgw, err := netip.ParseAddr(eth.Gateway6)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     gw,\n\t\t\tOutLinkName: name,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t}\n\n\t\troute.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t}\n\n\tfor _, addr := range eth.NameServers.Address {\n\t\tif ip, err := netip.ParseAddr(addr); err == nil {\n\t\t\t*dnsIPs = append(*dnsIPs, ip)\n\t\t} else {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, route := range eth.Routes {\n\t\tgw, err := netip.ParseAddr(route.Via)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse route gateway: %w\", err)\n\t\t}\n\n\t\tif route.To == \"default\" {\n\t\t\tif gw.Is4() {\n\t\t\t\troute.To = \"0.0.0.0/0\"\n\t\t\t} else {\n\t\t\t\troute.To = \"::/0\"\n\t\t\t}\n\t\t}\n\n\t\tdest, err := netip.ParsePrefix(route.To)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse route destination: %w\", err)\n\t\t}\n\n\t\trouteSpec := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tDestination: dest,\n\t\t\tGateway:     gw,\n\t\t\tOutLinkName: name,\n\t\t\tTable:       withDefault(nethelpers.RoutingTable(route.Table), nethelpers.TableMain),\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tPriority:    withDefault(route.Metric, network.DefaultRouteMetric),\n\t\t}\n\n\t\tif gw.Is6() {\n\t\t\trouteSpec.Family = nethelpers.FamilyInet6\n\n\t\t\tif routeSpec.Priority == network.DefaultRouteMetric {\n\t\t\t\trouteSpec.Priority = 2 * network.DefaultRouteMetric\n\t\t\t}\n\t\t}\n\n\t\trouteSpec.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, routeSpec)\n\n\t\tif route.OnLink && gw.Is4() {\n\t\t\t// This assumes an interface with multiple routes will never have multiple statically set ips.\n\t\t\tipPrefix, err := netip.ParsePrefix(eth.Address[0])\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse route source: %w\", err)\n\t\t\t}\n\n\t\t\trouteSpec := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tDestination: netip.PrefixFrom(gw, gw.BitLen()),\n\t\t\t\tSource:      ipPrefix.Addr(),\n\t\t\t\tOutLinkName: name,\n\t\t\t\tScope:       nethelpers.ScopeLink,\n\t\t\t\tTable:       withDefault(nethelpers.RoutingTable(route.Table), nethelpers.TableMain),\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tPriority:    withDefault(route.Metric, network.DefaultRouteMetric),\n\t\t\t}\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, routeSpec)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (n *Nocloud) applyNetworkConfigV2(ctx context.Context, config *NetworkConfig, st state.State, networkConfig *runtime.PlatformNetworkConfig) (bool, error) {\n\tvar (\n\t\tdnsIPs         []netip.Addr\n\t\tneedsReconcile bool\n\t)\n\n\thostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"error listing host interfaces: %w\", err)\n\t}\n\n\tethernetNames := maps.Keys(config.Ethernets)\n\tslices.Sort(ethernetNames)\n\n\tfor _, name := range ethernetNames {\n\t\teth := config.Ethernets[name]\n\n\t\tvar bondSlave network.BondSlave\n\n\t\tfor bondName, bond := range config.Bonds {\n\t\t\tfor idx, iface := range bond.Interfaces {\n\t\t\t\tif iface == name {\n\t\t\t\t\tbondSlave.MasterName = bondName\n\t\t\t\t\tbondSlave.SlaveIndex = idx\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif eth.Match.HWAddr != \"\" {\n\t\t\tvar availableMACAddresses []string\n\n\t\t\tmacAddressMatched := false\n\n\t\t\tfor hostInterface := range hostInterfaces.All() {\n\t\t\t\tif !hostInterface.TypedSpec().Physical() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tmacAddress := hostInterface.TypedSpec().PermanentAddr.String()\n\t\t\t\tif macAddress == \"\" {\n\t\t\t\t\tmacAddress = hostInterface.TypedSpec().HardwareAddr.String()\n\t\t\t\t}\n\n\t\t\t\tif strings.EqualFold(macAddress, eth.Match.HWAddr) {\n\t\t\t\t\tname = hostInterface.Metadata().ID()\n\t\t\t\t\tmacAddressMatched = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tavailableMACAddresses = append(availableMACAddresses, macAddress)\n\t\t\t}\n\n\t\t\tif !macAddressMatched {\n\t\t\t\tlog.Printf(\"nocloud: no link with matching MAC address %q (available %v), defaulted to use name %s instead\", eth.Match.HWAddr, availableMACAddresses, name)\n\n\t\t\t\tneedsReconcile = true\n\t\t\t}\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        name,\n\t\t\tUp:          true,\n\t\t\tMTU:         eth.MTU,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tBondSlave:   bondSlave,\n\t\t})\n\n\t\terr := applyNetworkConfigV2Ethernet(name, eth, networkConfig, &dnsIPs)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\tbondNames := maps.Keys(config.Bonds)\n\tslices.Sort(bondNames)\n\n\tfor _, bondName := range bondNames {\n\t\tbond := config.Bonds[bondName]\n\n\t\tmode, err := nethelpers.BondModeByName(bond.Params.Mode)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"invalid mode: %w\", err)\n\t\t}\n\n\t\thashPolicy, err := nethelpers.BondXmitHashPolicyByName(bond.Params.HashPolicy)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"invalid transmit-hash-policy: %w\", err)\n\t\t}\n\n\t\tlacpRate, err := nethelpers.LACPRateByName(bond.Params.LACPRate)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"invalid lacp-rate: %w\", err)\n\t\t}\n\n\t\tbondLink := network.LinkSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tName:        bondName,\n\t\t\tLogical:     true,\n\t\t\tUp:          true,\n\t\t\tMTU:         bond.Ethernet.MTU,\n\t\t\tKind:        network.LinkKindBond,\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tBondMaster: network.BondMasterSpec{\n\t\t\t\tMode:       mode,\n\t\t\t\tHashPolicy: hashPolicy,\n\t\t\t\tMIIMon:     bond.Params.MIIMon,\n\t\t\t\tUpDelay:    bond.Params.UpDelay,\n\t\t\t\tDownDelay:  bond.Params.DownDelay,\n\t\t\t\tLACPRate:   lacpRate,\n\t\t\t},\n\t\t}\n\n\t\tif mode == nethelpers.BondMode8023AD {\n\t\t\tbondLink.BondMaster.ADLACPActive = nethelpers.ADLACPActiveOn\n\t\t}\n\n\t\tnetworkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()\n\t\tnetworkConfig.Links = append(networkConfig.Links, bondLink)\n\n\t\terr = applyNetworkConfigV2Ethernet(bondName, bond.Ethernet, networkConfig, &dnsIPs)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\tvlanNames := maps.Keys(config.VLANs)\n\tslices.Sort(vlanNames)\n\n\tfor _, vlanName := range vlanNames {\n\t\tvlan := config.VLANs[vlanName]\n\n\t\tvlanLink := network.LinkSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tName:        vlanName,\n\t\t\tLogical:     true,\n\t\t\tUp:          true,\n\t\t\tMTU:         vlan.Ethernet.MTU,\n\t\t\tKind:        network.LinkKindVLAN,\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tParentName:  vlan.Link,\n\t\t\tVLAN: network.VLANSpec{\n\t\t\t\tVID:      vlan.ID,\n\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t},\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, vlanLink)\n\n\t\terr = applyNetworkConfigV2Ethernet(vlanName, vlan.Ethernet, networkConfig, &dnsIPs)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\tif len(dnsIPs) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:  dnsIPs,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\treturn needsReconcile, nil\n}\n\nfunc withDefault[T comparable](v T, defaultValue T) T {\n\tvar zeroT T\n\n\tif v == zeroT {\n\t\treturn defaultValue\n\t}\n\n\treturn v\n}\n\n// FetchInclude fetches nocloud #include configuration from the URL specified in the body.\nfunc (n *Nocloud) FetchInclude(ctx context.Context, body []byte, st state.State) ([]byte, error) {\n\tu, err := ExtractIncludeURL(body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching the nocloud #include configuration from: %q\", u.String())\n\n\tif err = netutils.Wait(ctx, st); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn download.Download(ctx, u.String(), download.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// ExtractIncludeURL extracts the URL from the body of a nocloud #include configuration.\n//\n// Note: only a single URL is expected in the body.\nfunc ExtractIncludeURL(body []byte) (*url.URL, error) {\n\tvar urlLine string\n\n\tscanner := bufio.NewScanner(bytes.NewReader(body))\n\n\tfor scanner.Scan() {\n\t\tline := strings.TrimSpace(scanner.Text())\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif urlLine != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"multiple #include URLs found in nocloud configuration: %q and %q\", urlLine, line)\n\t\t}\n\n\t\turlLine = line\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif urlLine == \"\" {\n\t\treturn nil, stderrors.New(\"no #include URL found in nocloud configuration\")\n\t}\n\n\treturn url.Parse(urlLine)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nocloud\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cenkalti/backoff/v4\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Nocloud is the concrete type that implements the runtime.Platform interface.\ntype Nocloud struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (n *Nocloud) Name() string {\n\treturn \"nocloud\"\n}\n\n// ParseMetadata converts nocloud metadata to platform network config.\nfunc (n *Nocloud) ParseMetadata(ctx context.Context, unmarshalledNetworkConfig *NetworkConfig, st state.State, metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, bool, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\thostname := metadata.Hostname\n\tif hostname == \"\" {\n\t\thostname = metadata.InternalDNS\n\t}\n\n\tif hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(hostname); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar (\n\t\tneedsReconcile bool\n\t\terr            error\n\t)\n\n\tswitch unmarshalledNetworkConfig.Version {\n\tcase 1:\n\t\tif needsReconcile, err = n.applyNetworkConfigV1(ctx, unmarshalledNetworkConfig, st, networkConfig); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\tcase 2:\n\t\tif needsReconcile, err = n.applyNetworkConfigV2(ctx, unmarshalledNetworkConfig, st, networkConfig); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\tdefault:\n\t\treturn nil, false, fmt.Errorf(\"network-config metadata version=%d is not supported\", unmarshalledNetworkConfig.Version)\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     n.Name(),\n\t\tHostname:     hostname,\n\t\tInstanceID:   metadata.InstanceID,\n\t\tInstanceType: metadata.InstanceType,\n\t\tProviderID:   metadata.ProviderID,\n\t\tRegion:       metadata.Region,\n\t\tZone:         metadata.Zone,\n\t\tInternalDNS:  metadata.InternalDNS,\n\t\tExternalDNS:  metadata.ExternalDNS,\n\t}\n\n\treturn networkConfig, needsReconcile, nil\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (n *Nocloud) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\t_, machineConfigDl, _, err := n.acquireConfig(ctx, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfirstLine, rest, _ := bytes.Cut(machineConfigDl, []byte(\"\\n\"))\n\tfirstLine = bytes.TrimSpace(firstLine)\n\n\tswitch {\n\tcase bytes.Equal(firstLine, []byte(\"#cloud-config\")):\n\t\t// ignore cloud-config, Talos does not support it\n\t\treturn nil, errors.ErrNoConfigSource\n\tcase bytes.Equal(firstLine, []byte(\"#include\")):\n\t\treturn n.FetchInclude(ctx, rest, r)\n\t}\n\n\treturn machineConfigDl, nil\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (n *Nocloud) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (n *Nocloud) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\n//\n//nolint:gocyclo\nfunc (n *Nocloud) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\t// wait for devices to be ready before proceeding\n\tif err := netutils.WaitForDevicesReady(ctx, st); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for devices to be ready: %w\", err)\n\t}\n\n\tmetadataNetworkConfigDl, _, metadata, err := n.acquireConfig(ctx, st)\n\tif stderrors.Is(err, errors.ErrNoConfigSource) {\n\t\terr = nil\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif metadataNetworkConfigDl == nil {\n\t\t// no data, use cached network configuration if available\n\t\treturn nil\n\t}\n\n\tunmarshalledNetworkConfig, err := DecodeNetworkConfig(metadataNetworkConfigDl)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// do a loop to retry network config remap in case of missing links\n\t// on each try, export the configuration as it is, and if the network is reconciled next time, export the reconciled configuration\n\tbckoff := backoff.NewExponentialBackOff()\n\n\tfor {\n\t\tnetworkConfig, needsReconcile, err := n.ParseMetadata(ctx, unmarshalledNetworkConfig, st, metadata)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !channel.SendWithContext(ctx, ch, networkConfig) {\n\t\t\treturn ctx.Err()\n\t\t}\n\n\t\tif !needsReconcile {\n\t\t\treturn nil\n\t\t}\n\n\t\t// wait for for backoff to retry network config remap\n\t\tnextBackoff := bckoff.NextBackOff()\n\t\tif nextBackoff == backoff.Stop {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(nextBackoff):\n\t\t}\n\t}\n}\n\n// DecodeNetworkConfig decodes the network configuration guessing the format from the content.\nfunc DecodeNetworkConfig(content []byte) (*NetworkConfig, error) {\n\tvar decoded map[string]any\n\n\terr := yaml.Unmarshal(content, &decoded)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif _, ok := decoded[\"network\"]; ok {\n\t\tvar ciNetworkConfig NetworkCloudInitConfig\n\n\t\terr = yaml.Unmarshal(content, &ciNetworkConfig)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &ciNetworkConfig.Config, nil\n\t}\n\n\t// If it is not plain *v2 cloud-init* config then we attempt to decode *nocloud*\n\tif _, ok := decoded[\"version\"]; ok {\n\t\tvar nc NetworkConfig\n\n\t\terr = yaml.Unmarshal(content, &nc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &nc, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to decode network configuration, keys: %v\", maps.Keys(decoded))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nocloud_test\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n//go:embed testdata/in-v1.yaml\nvar rawNetworkConfigV1 []byte\n\n//go:embed testdata/in-v1-pnap.yaml\nvar rawNetworkConfigV1Pnap []byte\n\n//go:embed testdata/in-v2-nocloud.yaml\nvar rawNetworkConfigV2Nocloud []byte\n\n//go:embed testdata/in-v2-cloud-init.yaml\nvar rawNetworkConfigV2CloudInit []byte\n\n//go:embed testdata/in-v2-serverscom.yaml\nvar rawNetworkConfigV2Serverscom []byte\n\n//go:embed testdata/expected-v1.yaml\nvar expectedNetworkConfigV1 string\n\n//go:embed testdata/expected-v1-pnap.yaml\nvar expectedNetworkConfigV1Pnap string\n\n//go:embed testdata/expected-v2.yaml\nvar expectedNetworkConfigV2 string\n\n//go:embed testdata/expected-v2-serverscom.yaml\nvar expectedNetworkConfigV2Serverscom string\n\nfunc TestParseNetworkConfig(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tname string\n\t\traw  []byte\n\n\t\texpected              string\n\t\texpectedNeedsRecocile bool\n\t}{\n\t\t{\n\t\t\tname:     \"V1\",\n\t\t\traw:      rawNetworkConfigV1,\n\t\t\texpected: expectedNetworkConfigV1,\n\t\t},\n\t\t{\n\t\t\tname:     \"V1-pnap\",\n\t\t\traw:      rawNetworkConfigV1Pnap,\n\t\t\texpected: expectedNetworkConfigV1Pnap,\n\t\t},\n\t\t{\n\t\t\tname:                  \"V2-nocloud\",\n\t\t\traw:                   rawNetworkConfigV2Nocloud,\n\t\t\texpected:              expectedNetworkConfigV2,\n\t\t\texpectedNeedsRecocile: true,\n\t\t},\n\t\t{\n\t\t\tname:                  \"V2-cloud-init\",\n\t\t\traw:                   rawNetworkConfigV2CloudInit,\n\t\t\texpected:              expectedNetworkConfigV2,\n\t\t\texpectedNeedsRecocile: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"V2-servers.com\",\n\t\t\traw:      rawNetworkConfigV2Serverscom,\n\t\t\texpected: expectedNetworkConfigV2Serverscom,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\t\t\tt.Cleanup(cancel)\n\n\t\t\tn := &nocloud.Nocloud{}\n\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tdevicesReady := runtime.NewDevicesStatus(runtime.NamespaceName, runtime.DevicesID)\n\t\t\tdevicesReady.TypedSpec().Ready = true\n\t\t\trequire.NoError(t, st.Create(ctx, devicesReady))\n\n\t\t\tbond0 := network.NewLinkStatus(network.NamespaceName, \"bond0\")\n\t\t\tbond0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf7} // this link is not a physical one, so it should be ignored\n\t\t\tbond0.TypedSpec().Type = nethelpers.LinkEther\n\t\t\tbond0.TypedSpec().Kind = \"bond\"\n\t\t\trequire.NoError(t, st.Create(ctx, bond0))\n\n\t\t\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t\t\teth0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf7}\n\t\t\teth0.TypedSpec().Type = nethelpers.LinkEther\n\t\t\teth0.TypedSpec().Kind = \"\"\n\t\t\trequire.NoError(t, st.Create(ctx, eth0))\n\n\t\t\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\t\t\teth1.TypedSpec().HardwareAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9} // this link has a permanent address, so hardware addr should be ignored\n\t\t\teth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf8}\n\t\t\teth1.TypedSpec().Type = nethelpers.LinkEther\n\t\t\teth1.TypedSpec().Kind = \"\"\n\t\t\trequire.NoError(t, st.Create(ctx, eth1))\n\n\t\t\teth2 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\t\t\teth2.TypedSpec().HardwareAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9} // this link doesn't have a permanent address, but only a hardware address\n\t\t\teth2.TypedSpec().Type = nethelpers.LinkEther\n\t\t\teth2.TypedSpec().Kind = \"\"\n\t\t\trequire.NoError(t, st.Create(ctx, eth2))\n\n\t\t\teno1np0 := network.NewLinkStatus(network.NamespaceName, \"eno1np0\")\n\t\t\teno1np0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(must.Value(net.ParseMAC(\"3c:ec:ef:e0:45:28\"))(t))\n\t\t\teno1np0.TypedSpec().Type = nethelpers.LinkEther\n\t\t\teno1np0.TypedSpec().Kind = \"\"\n\t\t\trequire.NoError(t, st.Create(ctx, eno1np0))\n\n\t\t\teno2np1 := network.NewLinkStatus(network.NamespaceName, \"eno2np1\")\n\t\t\teno2np1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr(must.Value(net.ParseMAC(\"3c:ec:ef:e0:45:29\"))(t))\n\t\t\teno2np1.TypedSpec().Type = nethelpers.LinkEther\n\t\t\teno2np1.TypedSpec().Kind = \"\"\n\t\t\trequire.NoError(t, st.Create(ctx, eno2np1))\n\n\t\t\tm, err := nocloud.DecodeNetworkConfig(tt.raw)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmc := nocloud.MetadataConfig{\n\t\t\t\tHostname:    \"talos.fqdn\",\n\t\t\t\tInternalDNS: \"talos.fqdn\",\n\t\t\t\tInstanceID:  \"0\",\n\t\t\t}\n\t\t\tmc2 := nocloud.MetadataConfig{\n\t\t\t\tInternalDNS: \"talos.fqdn\",\n\t\t\t\tInstanceID:  \"0\",\n\t\t\t}\n\n\t\t\tnetworkConfig, needsReconcile, err := n.ParseMetadata(ctx, m, st, &mc)\n\t\t\trequire.NoError(t, err)\n\t\t\tnetworkConfig2, needsReconcile2, err := n.ParseMetadata(ctx, m, st, &mc2)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, needsReconcile, needsReconcile2)\n\t\t\tassert.Equal(t, tt.expectedNeedsRecocile, needsReconcile)\n\n\t\t\tmarshaled, err := yaml.Marshal(networkConfig)\n\t\t\trequire.NoError(t, err)\n\t\t\tmarshaled2, err := yaml.Marshal(networkConfig2)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expected, string(marshaled))\n\t\t\tassert.Equal(t, tt.expected, string(marshaled2))\n\t\t})\n\t}\n}\n\n//go:embed testdata/metadata-nocloud.yaml\nvar rawMetadataNocloud []byte\n\nfunc TestMedatada(t *testing.T) {\n\tt.Parallel()\n\n\tvar md nocloud.MetadataConfig\n\n\terr := yaml.Unmarshal(rawMetadataNocloud, &md)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, nocloud.MetadataConfig{\n\t\tInstanceID:  \"80d6927ecb30c1707b12f38ed1211535930ff16e\",\n\t\tInternalDNS: \"talos-worker-3\",\n\t}, md)\n}\n\nfunc TestExtractURL(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tuserdata []byte\n\n\t\texpectedURL   string\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"valid include userdata URL\",\n\t\t\tuserdata: []byte(`https://metadataserver/userdata\n`),\n\t\t\texpectedURL: \"https://metadataserver/userdata\",\n\t\t},\n\t\t{\n\t\t\tname: \"multiple URLs is invalid\",\n\t\t\tuserdata: []byte(`\nhttps://metadataserver1/userdata\nhttps://metadataserver2/userdata\nhttps://metadataserver3/userdata\n`),\n\t\t\texpectedError: \"multiple #include URLs found\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL\",\n\t\t\tuserdata: []byte(`\n:/invalidurl/userdata`),\n\t\t\texpectedError: \"missing protocol scheme\",\n\t\t},\n\t\t{\n\t\t\tname: \"no URL found\",\n\t\t\tuserdata: []byte(`\n`),\n\t\t\texpectedError: \"no #include URL found in nocloud configuration\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tu, err := nocloud.ExtractIncludeURL(test.userdata)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.ErrorContains(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, test.expectedURL, u.String())\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1-pnap.yaml",
    "content": "addresses:\n    - address: 1.2.3.4/29\n      linkName: bond0.2\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.0.0.11/24\n      linkName: bond0.4\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eno1np0\n      logical: false\n      up: true\n      mtu: 9000\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      layer: platform\n    - name: eno2np1\n      logical: false\n      up: true\n      mtu: 9000\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      slaveIndex: 1\n      layer: platform\n    - name: bond0\n      logical: true\n      up: true\n      mtu: 9000\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: fast\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\n    - name: bond0.2\n      logical: true\n      up: true\n      mtu: 9000\n      kind: vlan\n      type: ether\n      parentName: bond0\n      vlan:\n        vlanID: 2\n        vlanProtocol: 802.1q\n      layer: platform\n    - name: bond0.4\n      logical: true\n      up: true\n      mtu: 9000\n      kind: vlan\n      type: ether\n      parentName: bond0\n      vlan:\n        vlanID: 4\n        vlanProtocol: 802.1q\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 1.2.3.5\n      outLinkName: bond0.2\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 8.8.8.8\n        - 8.8.4.4\n      layer: platform\ntimeServers: []\noperators: []\nexternalIPs: []\nmetadata:\n    platform: nocloud\n    hostname: talos.fqdn\n    instanceId: \"0\"\n    internalDNS: talos.fqdn\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v1.yaml",
    "content": "addresses:\n    - address: 192.168.1.11/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2001:2:3:4:5:6:7:f7/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 192.168.2.11/24\n      linkName: eth2\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2001:2:3:4:5:6:7:f9/64\n      linkName: eth2\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::1\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.2.1\n      outLinkName: eth2\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::2\n      outLinkName: eth2\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 192.168.1.1\n      layer: platform\ntimeServers: []\noperators: []\nexternalIPs: []\nmetadata:\n    platform: nocloud\n    hostname: talos.fqdn\n    instanceId: \"0\"\n    internalDNS: talos.fqdn\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-serverscom.yaml",
    "content": "addresses:\n    - address: 188.42.48.188/29\n      linkName: agge\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.26.98.92/29\n      linkName: aggi\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eno1np0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: agge\n      layer: platform\n    - name: eno2np1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: agge\n      slaveIndex: 1\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: aggi\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: aggi\n      slaveIndex: 1\n      layer: platform\n    - name: agge\n      logical: true\n      up: true\n      mtu: 0\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: slow\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\n    - name: aggi\n      logical: true\n      up: true\n      mtu: 0\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: slow\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 188.42.48.187\n      outLinkName: agge\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 10.26.98.91\n      outLinkName: aggi\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 192.168.0.0/16\n      src: \"\"\n      gateway: 10.26.98.91\n      outLinkName: aggi\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 188.42.208.0/21\n      src: \"\"\n      gateway: 10.26.98.91\n      outLinkName: aggi\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs: []\nmetadata:\n    platform: nocloud\n    hostname: talos.fqdn\n    instanceId: \"0\"\n    internalDNS: talos.fqdn\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml",
    "content": "addresses:\n    - address: 192.168.14.2/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2001:1::1/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.22.14.2/32\n      linkName: eth1\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.10.4.140/29\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 192.34.34.34/32\n      linkName: bond0.4\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      slaveIndex: 1\n      layer: platform\n    - name: bond0\n      logical: true\n      up: true\n      mtu: 1500\n      kind: bond\n      type: ether\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer3+4\n        lacpRate: fast\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\n    - name: bond0.4\n      logical: true\n      up: true\n      mtu: 1500\n      kind: vlan\n      type: ether\n      parentName: bond0\n      vlan:\n        vlanID: 4\n        vlanProtocol: 802.1q\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.14.1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: 2001:1::2\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.14.1\n      outLinkName: eth1\n      table: main\n      priority: 100\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 192.168.14.1/32\n      src: 10.22.14.2\n      gateway: \"\"\n      outLinkName: eth1\n      table: main\n      priority: 100\n      scope: link\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 10.10.4.147\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 192.168.0.0/16\n      src: \"\"\n      gateway: 10.10.4.147\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 188.42.208.0/21\n      src: \"\"\n      gateway: 10.10.4.147\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: fqdn\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 8.8.8.8\n        - 1.1.1.1\n        - 2.2.2.2\n      layer: platform\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs: []\nmetadata:\n    platform: nocloud\n    hostname: talos.fqdn\n    instanceId: \"0\"\n    internalDNS: talos.fqdn\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v1-pnap.yaml",
    "content": "version: 1\nconfig:\n\n- type: physical\n  name: eno1np0\n  mac_address: \"3c:ec:ef:e0:45:28\"\n  mtu: 9000\n\n- type: physical\n  name: eno2np1\n  mac_address: \"3c:ec:ef:e0:45:29\"\n  mtu: 9000\n\n- type: bond\n  name: bond0\n  mac_address: \"3c:ec:ef:e0:45:28\"\n  mtu: 9000\n  bond_interfaces:\n  - eno1np0\n  - eno2np1\n  params:\n    bond-lacp-rate: fast\n    bond-miimon: 100\n    bond-mode: 802.3ad\n    bond-xmit-hash-policy: layer3+4\n    up-delay: 0\n    down-delay: 0\n\n# public frontend MERGED_FRONTEND vlan 2\n- type: vlan\n  name: bond0.2\n  mtu: 9000\n  vlan_id: 2\n  vlan_link: bond0\n  subnets:\n  - address: 1.2.3.4/29\n    gateway: 1.2.3.5\n    type: static\n\n# private backend vlan 4\n- type: vlan\n  mtu: 9000\n  name: bond0.4\n  vlan_id: 4\n  vlan_link: bond0\n  subnets:\n  - type: static\n    address: 10.0.0.11/24\n\n- type: nameserver\n  address:\n  - 8.8.8.8\n  - 8.8.4.4\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v1.yaml",
    "content": "version: 1\nconfig:\n  - type: physical\n    name: eth0\n    mac_address: '68:05:ca:b8:f1:f7'\n    subnets:\n    - type: static\n      address: '192.168.1.11'\n      netmask: '255.255.255.0'\n      gateway: '192.168.1.1'\n    - type: static6\n      address: '2001:2:3:4:5:6:7:f7/64'\n      gateway: 'fe80::1'\n  - type: physical\n    name: eth1\n    mac_address: '68:05:ca:b8:f1:f9'\n    subnets:\n    - type: static\n      address: '192.168.2.11'\n      netmask: '255.255.255.0'\n      gateway: '192.168.2.1'\n    - type: static6\n      address: '2001:2:3:4:5:6:7:f9/64'\n      gateway: 'fe80::2'\n  - type: nameserver\n    address:\n    - '192.168.1.1'\n    search:\n    - 'lan'\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-cloud-init.yaml",
    "content": "network:\n  version: 2\n  ethernets:\n    eth0:\n      match:\n        macaddress: \"00:20:6e:1f:f9:a8\"\n      dhcp4: true\n      addresses:\n        - 192.168.14.2/24\n        - 2001:1::1/64\n      gateway4: 192.168.14.1\n      gateway6: 2001:1::2\n      nameservers:\n        search: [foo.local, bar.local]\n        addresses: [8.8.8.8]\n    eth1:\n      match:\n        macaddress: '00:20:6e:1f:f9:a9'\n      addresses:\n        - 10.22.14.2/32\n      nameservers:\n        search: [ foo.local, bar.local ]\n      routes:\n        - to: default\n          via: \"192.168.14.1\"\n          metric: 100\n          on-link: true\n\n    ext1:\n      match:\n        macaddress: 68:05:ca:b8:f1:f8\n    ext2:\n      match:\n        macaddress: 68:05:ca:b8:f1:f9\n\n  bonds:\n    bond0:\n      interfaces:\n        - ext1\n        - ext2\n      macaddress: e4:3d:1a:4d:6a:28\n      mtu: 1500\n      parameters:\n        mode: 802.3ad\n        mii-monitor-interval: 100\n        down-delay: 200\n        up-delay: 200\n        lacp-rate: fast\n        transmit-hash-policy: layer3+4\n      addresses:\n        - 10.10.4.140/29\n      nameservers:\n        addresses:\n          - 1.1.1.1\n          - 2.2.2.2\n      routes:\n        - to: 10.0.0.0/8\n          via: 10.10.4.147\n        - to: 192.168.0.0/16\n          via: 10.10.4.147\n        - to: 188.42.208.0/21\n          via: 10.10.4.147\n\n  vlans:\n    bond0.4:\n      id: 4\n      link: bond0\n      mtu: 1500\n      addresses:\n        - 192.34.34.34/32\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-nocloud.yaml",
    "content": "version: 2\nethernets:\n  eth0:\n    match:\n      macaddress: \"00:20:6e:1f:f9:a8\"\n    dhcp4: true\n    addresses:\n      - 192.168.14.2/24\n      - 2001:1::1/64\n    gateway4: 192.168.14.1\n    gateway6: 2001:1::2\n    nameservers:\n      search: [foo.local, bar.local]\n      addresses: [8.8.8.8]\n  eth1:\n    match:\n      macaddress: '00:20:6e:1f:f9:a9'\n    addresses:\n      - 10.22.14.2/32\n    nameservers:\n      search: [ foo.local, bar.local ]\n    routes:\n      - to: \"0.0.0.0/0\"\n        via: \"192.168.14.1\"\n        metric: 100\n        on-link: true\n\n  ext1:\n    match:\n      macaddress: 68:05:ca:b8:f1:f8\n  ext2:\n    match:\n      macaddress: 68:05:ca:b8:f1:f9\n\nbonds:\n  bond0:\n    interfaces:\n      - ext1\n      - ext2\n    macaddress: e4:3d:1a:4d:6a:28\n    mtu: 1500\n    parameters:\n      mode: 802.3ad\n      mii-monitor-interval: 100\n      down-delay: 200\n      up-delay: 200\n      lacp-rate: fast\n      transmit-hash-policy: layer3+4\n    addresses:\n      - 10.10.4.140/29\n    nameservers:\n      addresses:\n        - 1.1.1.1\n        - 2.2.2.2\n    routes:\n      - to: 10.0.0.0/8\n        via: 10.10.4.147\n      - to: 192.168.0.0/16\n        via: 10.10.4.147\n      - to: 188.42.208.0/21\n        via: 10.10.4.147\n\nvlans:\n  bond0.4:\n    id: 4\n    link: bond0\n    mtu: 1500\n    addresses:\n      - 192.34.34.34/32\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-serverscom.yaml",
    "content": "version: 2\nbonds:\n  aggi:\n    interfaces:\n    - int0\n    - int1\n    addresses:\n    - 10.26.98.92/29\n    parameters:\n      mode: 802.3ad\n      lacp-rate: slow\n      mii-monitor-interval: 100\n      up-delay: 200\n      down-delay: 200\n      transmit-hash-policy: layer3+4\n    routes:\n    - to: 10.0.0.0/8\n      via: 10.26.98.91\n    - to: 192.168.0.0/16\n      via: 10.26.98.91\n    - to: 188.42.208.0/21\n      via: 10.26.98.91\n  agge:\n    interfaces:\n    - ext0\n    - ext1\n    addresses:\n    - 188.42.48.188/29\n    parameters:\n      mode: 802.3ad\n      lacp-rate: slow\n      mii-monitor-interval: 100\n      up-delay: 200\n      down-delay: 200\n      transmit-hash-policy: layer3+4\n    gateway4: 188.42.48.187\nethernets:\n  int0:\n    match:\n      macaddress: 68:05:ca:b8:f1:f8\n  int1:\n    match:\n      macaddress: 68:05:ca:b8:f1:f9\n  ext0:\n    match:\n      macaddress: 3c:ec:EF:e0:45:28\n  ext1:\n    match:\n      macaddress: 3c:EC:ef:e0:45:29\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/metadata-nocloud.yaml",
    "content": "instance-id: 80d6927ecb30c1707b12f38ed1211535930ff16e\nlocal-hostname: talos-worker-3\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/aliases_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst aliasContextBase = `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\nNAME = \"test\"\n`\n\n// aliasContext builds a minimal context string for alias testing.\nfunc aliasContext(extra string) []byte {\n\treturn []byte(aliasContextBase + extra)\n}\n\nfunc TestParseAliases(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\talias0IPv4 := network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\talias1IPv4 := network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"192.168.1.101/24\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\talias0IPv6 := network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"2001:db8::100/64\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet6,\n\t\tScope:       nethelpers.ScopeGlobal,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tfor _, tc := range []struct {\n\t\tname          string\n\t\textra         string\n\t\twantAliasAddr []network.AddressSpecSpec\n\t}{\n\t\t{\n\t\t\tname: \"IPv4 alias included\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv4},\n\t\t},\n\t\t{\n\t\t\tname: \"EXTERNAL=YES skips alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"YES\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"EXTERNAL=NO includes alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv4},\n\t\t},\n\t\t{\n\t\t\tname: \"DETACH non-empty skips alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"yes\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"DETACH empty includes alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv4},\n\t\t},\n\t\t{\n\t\t\tname: \"both DETACH non-empty and EXTERNAL=YES skips alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"YES\"\nETH0_ALIAS0_DETACH = \"yes\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple aliases sorted deterministically\",\n\t\t\textra: `ETH0_ALIAS1_MAC = \"02:00:c0:a8:01:65\"\nETH0_ALIAS1_IP = \"192.168.1.101\"\nETH0_ALIAS1_MASK = \"255.255.255.0\"\nETH0_ALIAS1_EXTERNAL = \"NO\"\nETH0_ALIAS1_DETACH = \"\"\nETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\t// ALIAS0 must appear before ALIAS1 regardless of map iteration order\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv4, alias1IPv4},\n\t\t},\n\t\t{\n\t\t\tname:          \"no alias keys — no extra addresses\",\n\t\t\textra:         \"\",\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"IPv6 alias included\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv6},\n\t\t},\n\t\t{\n\t\t\tname: \"ETH*_ALIAS*_IPV6 legacy alias used when IP6 absent\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IPV6 = \"2001:db8::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv6},\n\t\t},\n\t\t{\n\t\t\tname: \"IPv6 alias explicit prefix length respected\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_IP6_PREFIX_LENGTH = \"48\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tAddress:     netip.MustParsePrefix(\"2001:db8::100/48\"),\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"EXTERNAL=YES skips IPv6 alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_EXTERNAL = \"YES\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"DETACH non-empty skips IPv6 alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"yes\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed IPv4 and IPv6 aliases both emitted\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{alias0IPv4, alias0IPv6},\n\t\t},\n\t\t{\n\t\t\tname: \"IPv6 ULA alias emits two IPv6 addresses\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_IP6_ULA = \"fd00::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{\n\t\t\t\talias0IPv6,\n\t\t\t\t{\n\t\t\t\t\tAddress:     netip.MustParsePrefix(\"fd00::100/64\"),\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"EXTERNAL=YES skips IPv6 ULA alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6_ULA = \"fd00::100\"\nETH0_ALIAS0_EXTERNAL = \"YES\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"DETACH non-empty skips IPv6 ULA alias\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6_ULA = \"fd00::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"yes\"`,\n\t\t\twantAliasAddr: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed IPv4 and IPv6 and ULA alias emits all three addresses\",\n\t\t\textra: `ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_IP6 = \"2001:db8::100\"\nETH0_ALIAS0_IP6_ULA = \"fd00::100\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`,\n\t\t\twantAliasAddr: []network.AddressSpecSpec{\n\t\t\t\talias0IPv4,\n\t\t\t\talias0IPv6,\n\t\t\t\t{\n\t\t\t\t\tAddress:     netip.MustParsePrefix(\"fd00::100/64\"),\n\t\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, aliasContext(tc.extra))\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// The first address is always the primary ETH0 address; aliases follow.\n\t\t\tvar aliasAddrs []network.AddressSpecSpec\n\t\t\tif len(networkConfig.Addresses) > 1 {\n\t\t\t\taliasAddrs = networkConfig.Addresses[1:]\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.wantAliasAddr, aliasAddrs)\n\t\t})\n\t}\n}\n\nfunc TestParseErrors(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tt.Run(\"malformed alias IPv4 returns descriptive error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := aliasContext(`ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP = \"notanip\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`)\n\n\t\t_, err := o.ParseMetadata(st, ctx)\n\t\trequire.ErrorContains(t, err, \"ETH0_ALIAS0\")\n\t\trequire.ErrorContains(t, err, \"IPv4\")\n\t})\n\n\tt.Run(\"malformed alias IPv6 returns descriptive error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := aliasContext(`ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6 = \"notanip\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`)\n\n\t\t_, err := o.ParseMetadata(st, ctx)\n\t\trequire.ErrorContains(t, err, \"ETH0_ALIAS0\")\n\t\trequire.ErrorContains(t, err, \"IPv6\")\n\t})\n\n\tt.Run(\"malformed alias IPv6 ULA returns error containing alias name and ULA\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := aliasContext(`ETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_IP6_ULA = \"notanip\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_DETACH = \"\"`)\n\n\t\t_, err := o.ParseMetadata(st, ctx)\n\t\trequire.ErrorContains(t, err, \"ETH0_ALIAS0\")\n\t\trequire.ErrorContains(t, err, \"ULA\")\n\t})\n\n\tt.Run(\"malformed interface IPv6 address returns descriptive error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := aliasContext(\"ETH0_IP6 = \\\"notanip\\\"\")\n\n\t\t_, err := o.ParseMetadata(st, ctx)\n\t\trequire.ErrorContains(t, err, \"ETH0\")\n\t\trequire.ErrorContains(t, err, \"IPv6\")\n\t})\n\n\tt.Run(\"malformed IPv6 gateway returns descriptive error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := aliasContext(\"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"notanip\\\"\")\n\n\t\t_, err := o.ParseMetadata(st, ctx)\n\t\trequire.ErrorContains(t, err, \"ETH0\")\n\t\trequire.ErrorContains(t, err, \"gateway\")\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/dns_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n)\n\nfunc TestDNSMerge(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tmac := `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\nNAME = \"test\"\n`\n\n\tfor _, tc := range []struct {\n\t\tname           string\n\t\textra          string\n\t\twantDNS        []string\n\t\twantSearch     []string\n\t\twantNoResolver bool\n\t}{\n\t\t{\n\t\t\tname:           \"global DNS only\",\n\t\t\textra:          `DNS = \"9.9.9.9 1.1.1.1\"`,\n\t\t\twantDNS:        []string{\"9.9.9.9\", \"1.1.1.1\"},\n\t\t\twantSearch:     nil,\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"per-interface DNS only\",\n\t\t\textra:          `ETH0_DNS = \"192.168.1.1 8.8.8.8\"`,\n\t\t\twantDNS:        []string{\"192.168.1.1\", \"8.8.8.8\"},\n\t\t\twantSearch:     nil,\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"global and per-interface DNS merged, global first\",\n\t\t\textra:          \"DNS = \\\"9.9.9.9\\\"\\nETH0_DNS = \\\"192.168.1.1\\\"\",\n\t\t\twantDNS:        []string{\"9.9.9.9\", \"192.168.1.1\"},\n\t\t\twantSearch:     nil,\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"global SEARCH_DOMAIN only\",\n\t\t\textra:          `SEARCH_DOMAIN = \"global.example.com\"`,\n\t\t\twantDNS:        nil,\n\t\t\twantSearch:     []string{\"global.example.com\"},\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"per-interface search domain only\",\n\t\t\textra:          `ETH0_SEARCH_DOMAIN = \"example.com\"`,\n\t\t\twantDNS:        nil,\n\t\t\twantSearch:     []string{\"example.com\"},\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"global and per-interface search domains merged, global first\",\n\t\t\textra:          \"SEARCH_DOMAIN = \\\"global.example.com\\\"\\nETH0_SEARCH_DOMAIN = \\\"example.com\\\"\",\n\t\t\twantDNS:        nil,\n\t\t\twantSearch:     []string{\"global.example.com\", \"example.com\"},\n\t\t\twantNoResolver: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"neither global nor per-interface set — no resolver emitted\",\n\t\t\textra:          \"\",\n\t\t\twantNoResolver: true,\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tinput := []byte(mac + tc.extra)\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif tc.wantNoResolver {\n\t\t\t\tassert.Empty(t, networkConfig.Resolvers)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.Len(t, networkConfig.Resolvers, 1)\n\n\t\t\tresolver := networkConfig.Resolvers[0]\n\n\t\t\tvar dnsStrs []string\n\n\t\t\tfor _, ip := range resolver.DNSServers {\n\t\t\t\tdnsStrs = append(dnsStrs, ip.String())\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.wantDNS, dnsStrs)\n\t\t\tassert.Equal(t, tc.wantSearch, resolver.SearchDomains)\n\t\t})\n\t}\n}\n\nfunc TestDNSMergeError(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tbase := `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\nNAME = \"test\"\n`\n\n\tt.Run(\"malformed global DNS returns error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := o.ParseMetadata(st, []byte(base+`DNS = \"notanip\"`))\n\t\trequire.ErrorContains(t, err, \"failed to parse global DNS server\")\n\t\trequire.ErrorContains(t, err, \"notanip\")\n\t})\n\n\tt.Run(\"malformed per-interface DNS returns error with interface name\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := o.ParseMetadata(st, []byte(base+`ETH0_DNS = \"notanip\"`))\n\t\trequire.ErrorContains(t, err, \"ETH0\")\n\t\trequire.ErrorContains(t, err, \"notanip\")\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/hostname_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n)\n\n// minimalContext returns the minimum context bytes needed to exercise hostname\n// parsing without triggering ETH* processing.\nfunc minimalContext(vars string) []byte {\n\treturn []byte(\"ETH0_MAC = \\\"02:00:c0:a8:01:5c\\\"\\nETH0_IP = \\\"10.0.0.1\\\"\\nETH0_MASK = \\\"255.255.255.0\\\"\\n\" + vars)\n}\n\nfunc TestSanitizeHostname(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tfor _, tc := range []struct {\n\t\tname           string\n\t\tsetHostname    string\n\t\twantHostname   string\n\t\twantDomainname string\n\t}{\n\t\t{\n\t\t\tname:           \"clean hostname passes through unchanged\",\n\t\t\tsetHostname:    \"myhost\",\n\t\t\twantHostname:   \"myhost\",\n\t\t\twantDomainname: \"\",\n\t\t},\n\t\t{\n\t\t\tname:           \"FQDN is split on first dot\",\n\t\t\tsetHostname:    \"myhost.example.com\",\n\t\t\twantHostname:   \"myhost\",\n\t\t\twantDomainname: \"example.com\",\n\t\t},\n\t\t{\n\t\t\tname:           \"invalid chars replaced with hyphen\",\n\t\t\tsetHostname:    \"my_host\",\n\t\t\twantHostname:   \"my-host\",\n\t\t\twantDomainname: \"\",\n\t\t},\n\t\t{\n\t\t\tname:           \"leading and trailing hyphens stripped\",\n\t\t\tsetHostname:    \"-myhost-\",\n\t\t\twantHostname:   \"myhost\",\n\t\t\twantDomainname: \"\",\n\t\t},\n\t\t{\n\t\t\tname:           \"per-label hyphen trimming\",\n\t\t\tsetHostname:    \"my-.host\",\n\t\t\twantHostname:   \"my\",\n\t\t\twantDomainname: \"host\",\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx := minimalContext(\"SET_HOSTNAME = \\\"\" + tc.setHostname + \"\\\"\")\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, ctx)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, networkConfig.Hostnames, 1)\n\n\t\t\tassert.Equal(t, tc.wantHostname, networkConfig.Hostnames[0].Hostname)\n\t\t\tassert.Equal(t, tc.wantDomainname, networkConfig.Hostnames[0].Domainname)\n\t\t})\n\t}\n\n\tt.Run(\"empty SET_HOSTNAME produces no hostname entry\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := minimalContext(\"SET_HOSTNAME = \\\"\\\"\")\n\n\t\tnetworkConfig, err := o.ParseMetadata(st, ctx)\n\t\trequire.NoError(t, err)\n\t\tassert.Empty(t, networkConfig.Hostnames)\n\t})\n}\n\nfunc TestParseMetadataHostname(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tfor _, tc := range []struct {\n\t\tname           string\n\t\tvars           string\n\t\twantHostnames  int\n\t\twantHostname   string\n\t\twantDomainname string\n\t}{\n\t\t{\n\t\t\tname:          \"SET_HOSTNAME is used as hostname\",\n\t\t\tvars:          \"SET_HOSTNAME = \\\"myhost\\\"\",\n\t\t\twantHostnames: 1,\n\t\t\twantHostname:  \"myhost\",\n\t\t},\n\t\t{\n\t\t\tname:           \"FQDN in SET_HOSTNAME is split into Hostname and Domainname\",\n\t\t\tvars:           \"SET_HOSTNAME = \\\"myhost.example.com\\\"\",\n\t\t\twantHostnames:  1,\n\t\t\twantHostname:   \"myhost\",\n\t\t\twantDomainname: \"example.com\",\n\t\t},\n\t\t{\n\t\t\tname:          \"HOSTNAME variable is ignored\",\n\t\t\tvars:          \"HOSTNAME = \\\"fromhostname\\\"\",\n\t\t\twantHostnames: 0,\n\t\t},\n\t\t{\n\t\t\tname:          \"NAME variable is ignored\",\n\t\t\tvars:          \"NAME = \\\"fromname\\\"\",\n\t\t\twantHostnames: 0,\n\t\t},\n\t\t{\n\t\t\tname:          \"SET_HOSTNAME takes precedence over HOSTNAME and NAME\",\n\t\t\tvars:          \"SET_HOSTNAME = \\\"correct\\\"\\nHOSTNAME = \\\"wrong\\\"\\nNAME = \\\"alsowrong\\\"\",\n\t\t\twantHostnames: 1,\n\t\t\twantHostname:  \"correct\",\n\t\t},\n\t\t{\n\t\t\tname:          \"DNS_HOSTNAME=YES is not used as a hostname value\",\n\t\t\tvars:          \"DNS_HOSTNAME = \\\"YES\\\"\",\n\t\t\twantHostnames: 0,\n\t\t},\n\t\t{\n\t\t\tname:          \"absent SET_HOSTNAME produces no hostname entry\",\n\t\t\tvars:          \"\",\n\t\t\twantHostnames: 0,\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx := minimalContext(tc.vars)\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, ctx)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, networkConfig.Hostnames, tc.wantHostnames)\n\n\t\t\tif tc.wantHostnames > 0 {\n\t\t\t\tassert.Equal(t, tc.wantHostname, networkConfig.Hostnames[0].Hostname)\n\t\t\t\tassert.Equal(t, tc.wantDomainname, networkConfig.Hostnames[0].Domainname)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/ipv6_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst ipv6ContextBase = `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\nNAME = \"test\"\n`\n\nfunc ipv6Context(extra string) []byte {\n\treturn []byte(ipv6ContextBase + extra)\n}\n\nfunc TestParseIPv6(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tgw6Route := func(gw string, priority uint32) network.RouteSpecSpec {\n\t\treturn network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     netip.MustParseAddr(gw),\n\t\t\tOutLinkName: \"eth0\",\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tPriority:    priority,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t}\n\t}\n\n\tdhcp6Op := func(metric uint32) network.OperatorSpecSpec {\n\t\treturn network.OperatorSpecSpec{\n\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\tLinkName:  \"eth0\",\n\t\t\tRequireUp: true,\n\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\tRouteMetric:         metric,\n\t\t\t\tSkipHostnameRequest: true,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\t}\n\n\tfor _, tc := range []struct {\n\t\tname          string\n\t\textra         string\n\t\twantAddrs     []netip.Prefix\n\t\twantRoutes    []network.RouteSpecSpec\n\t\twantOperators []network.OperatorSpecSpec\n\t}{\n\t\t{\n\t\t\tname:      \"static IPv6 address with explicit prefix length\",\n\t\t\textra:     \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_PREFIX_LENGTH = \\\"48\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/48\")},\n\t\t},\n\t\t{\n\t\t\tname:      \"ETH*_IPV6 legacy alias used when ETH*_IP6 absent\",\n\t\t\textra:     \"ETH0_IPV6 = \\\"2001:db8::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:      \"prefix length defaults to 64\",\n\t\t\textra:     \"ETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:      \"explicit prefix length respected\",\n\t\t\textra:     \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_PREFIX_LENGTH = \\\"56\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/56\")},\n\t\t},\n\t\t{\n\t\t\tname:      \"ULA address emitted as second AddressSpecSpec\",\n\t\t\textra:     \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_ULA = \\\"fd00::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\"), netip.MustParsePrefix(\"fd00::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:       \"IPv6 gateway emits default route with metric 1\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"2001:db8::fffe\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 1)},\n\t\t},\n\t\t{\n\t\t\tname:       \"ETH*_GATEWAY6 legacy alias used when ETH*_IP6_GATEWAY absent\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_GATEWAY6 = \\\"2001:db8::fffe\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 1)},\n\t\t},\n\t\t{\n\t\t\tname:       \"ETH*_IP6_METRIC overrides default metric of 1\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"2001:db8::fffe\\\"\\nETH0_IP6_METRIC = \\\"100\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 100)},\n\t\t},\n\t\t{\n\t\t\tname:  \"no IPv6 variables — no IPv6 output\",\n\t\t\textra: \"\",\n\t\t},\n\t\t{\n\t\t\tname:          \"IP6_METHOD=dhcp emits OperatorDHCP6 with default metric 1\",\n\t\t\textra:         \"ETH0_IP6_METHOD = \\\"dhcp\\\"\",\n\t\t\twantOperators: []network.OperatorSpecSpec{dhcp6Op(1)},\n\t\t},\n\t\t{\n\t\t\tname:          \"IP6_METHOD=dhcp with IP6_METRIC uses custom metric\",\n\t\t\textra:         \"ETH0_IP6_METHOD = \\\"dhcp\\\"\\nETH0_IP6_METRIC = \\\"200\\\"\",\n\t\t\twantOperators: []network.OperatorSpecSpec{dhcp6Op(200)},\n\t\t},\n\t\t{\n\t\t\tname:  \"IP6_METHOD=auto emits nothing\",\n\t\t\textra: \"ETH0_IP6_METHOD = \\\"auto\\\"\\nETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:  \"IP6_METHOD=disable emits nothing even if IP6 is set\",\n\t\t\textra: \"ETH0_IP6_METHOD = \\\"disable\\\"\\nETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"IP6_METHOD=static with IP6 set emits address\",\n\t\t\textra:     \"ETH0_IP6_METHOD = \\\"static\\\"\\nETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:      \"IP6_METHOD absent and IP6 set uses static path\",\n\t\t\textra:     \"ETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:          \"METHOD=dhcp with no IP6_METHOD inherits dhcp and emits OperatorDHCP6\",\n\t\t\textra:         \"ETH0_METHOD = \\\"dhcp\\\"\",\n\t\t\twantOperators: []network.OperatorSpecSpec{dhcp6Op(1)},\n\t\t},\n\t\t{\n\t\t\tname:      \"METHOD=dhcp with IP6_METHOD=static and IP6 set uses static IPv6\",\n\t\t\textra:     \"ETH0_METHOD = \\\"dhcp\\\"\\nETH0_IP6_METHOD = \\\"static\\\"\\nETH0_IP6 = \\\"2001:db8::1\\\"\",\n\t\t\twantAddrs: []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t},\n\t\t{\n\t\t\tname:  \"METHOD=dhcp with IP6_METHOD=disable emits no IPv6 config\",\n\t\t\textra: \"ETH0_METHOD = \\\"dhcp\\\"\\nETH0_IP6_METHOD = \\\"disable\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:  \"METHOD=static with no IP6_METHOD and no IP6 emits no IPv6 config\",\n\t\t\textra: \"ETH0_METHOD = \\\"static\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:       \"METRIC=200 with no IP6_METRIC cascades to IPv6 gateway metric\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"2001:db8::fffe\\\"\\nETH0_METRIC = \\\"200\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 200)},\n\t\t},\n\t\t{\n\t\t\tname:       \"METRIC=200 with IP6_METRIC=50 uses explicit IP6_METRIC\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"2001:db8::fffe\\\"\\nETH0_METRIC = \\\"200\\\"\\nETH0_IP6_METRIC = \\\"50\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 50)},\n\t\t},\n\t\t{\n\t\t\tname:          \"METRIC=200 with IP6_METHOD=dhcp and no IP6_METRIC cascades to DHCPv6 metric\",\n\t\t\textra:         \"ETH0_IP6_METHOD = \\\"dhcp\\\"\\nETH0_METRIC = \\\"200\\\"\",\n\t\t\twantOperators: []network.OperatorSpecSpec{dhcp6Op(200)},\n\t\t},\n\t\t{\n\t\t\tname:       \"no METRIC and no IP6_METRIC uses IPv6 default of 1\",\n\t\t\textra:      \"ETH0_IP6 = \\\"2001:db8::1\\\"\\nETH0_IP6_GATEWAY = \\\"2001:db8::fffe\\\"\",\n\t\t\twantAddrs:  []netip.Prefix{netip.MustParsePrefix(\"2001:db8::1/64\")},\n\t\t\twantRoutes: []network.RouteSpecSpec{gw6Route(\"2001:db8::fffe\", 1)},\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, ipv6Context(tc.extra))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar ip6Addrs []netip.Prefix\n\n\t\t\tfor _, a := range networkConfig.Addresses {\n\t\t\t\tif a.Family == nethelpers.FamilyInet6 {\n\t\t\t\t\tip6Addrs = append(ip6Addrs, a.Address)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.wantAddrs, ip6Addrs)\n\n\t\t\tvar ip6Routes []network.RouteSpecSpec\n\n\t\t\tfor _, r := range networkConfig.Routes {\n\t\t\t\tif r.Family == nethelpers.FamilyInet6 {\n\t\t\t\t\tip6Routes = append(ip6Routes, r)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.wantRoutes, ip6Routes)\n\n\t\t\tvar ip6Operators []network.OperatorSpecSpec\n\n\t\t\tfor _, op := range networkConfig.Operators {\n\t\t\t\tif op.Operator == network.OperatorDHCP6 {\n\t\t\t\t\tip6Operators = append(ip6Operators, op)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.wantOperators, ip6Operators)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package opennebula provides the OpenNebula platform implementation.\npackage opennebula\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\nconst (\n\tconfigISOLabel = \"context\"\n\toneContextPath = \"context.sh\"\n)\n\nfunc (o *OpenNebula) contextFromCD(ctx context.Context, r state.State) (oneContext []byte, err error) {\n\terr = blockutils.ReadFromVolume(ctx, r,\n\t\t[]string{strings.ToLower(configISOLabel), strings.ToUpper(configISOLabel)},\n\t\tfunc(root xfs.Root, volumeStatus *block.VolumeStatus) error {\n\t\t\tlog.Printf(\"found config disk (context) at %s\", volumeStatus.TypedSpec().Location)\n\n\t\t\tlog.Printf(\"fetching context from: %s/\", oneContextPath)\n\n\t\t\toneContext, err = xfs.ReadFile(root, oneContextPath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"read config: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif oneContext == nil {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn oneContext, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/onegate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// staticIfaceContext builds a minimal context with a static ETH0 and an\n// optional ONEGATE_ENDPOINT.\nfunc staticIfaceContext(endpoint string) []byte {\n\tctx := `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\n`\n\n\tif endpoint != \"\" {\n\t\tctx += `ONEGATE_ENDPOINT = \"` + endpoint + `\"` + \"\\n\"\n\t}\n\n\treturn []byte(ctx)\n}\n\nfunc linkLocalRoute(ip, outLink string) network.RouteSpecSpec {\n\treturn network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tDestination: netip.PrefixFrom(netip.MustParseAddr(ip), 32),\n\t\tOutLinkName: outLink,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeLink,\n\t}\n}\n\nfunc scopeLinkRoutes(routes []network.RouteSpecSpec) []network.RouteSpecSpec {\n\tvar out []network.RouteSpecSpec\n\n\tfor _, r := range routes {\n\t\tif r.Scope == nethelpers.ScopeLink {\n\t\t\tout = append(out, r)\n\t\t}\n\t}\n\n\treturn out\n}\n\nfunc TestOnegateProxyRoute(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\ttests := []struct {\n\t\tname      string\n\t\tendpoint  string\n\t\twantRoute *network.RouteSpecSpec\n\t}{\n\t\t{\n\t\t\tname:     \"link-local with port and path emits scope-link /32 route\",\n\t\t\tendpoint: \"http://169.254.16.9:5030/RPC2\",\n\t\t\twantRoute: func() *network.RouteSpecSpec {\n\t\t\t\tr := linkLocalRoute(\"169.254.16.9\", \"eth0\")\n\n\t\t\t\treturn &r\n\t\t\t}(),\n\t\t},\n\t\t{\n\t\t\tname:     \"link-local without port emits route\",\n\t\t\tendpoint: \"http://169.254.16.9/RPC2\",\n\t\t\twantRoute: func() *network.RouteSpecSpec {\n\t\t\t\tr := linkLocalRoute(\"169.254.16.9\", \"eth0\")\n\n\t\t\t\treturn &r\n\t\t\t}(),\n\t\t},\n\t\t{\n\t\t\tname:      \"non-link-local IP emits no route\",\n\t\t\tendpoint:  \"http://10.0.0.1:5030/RPC2\",\n\t\t\twantRoute: nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"absent ONEGATE_ENDPOINT emits no route\",\n\t\t\tendpoint:  \"\",\n\t\t\twantRoute: nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"IPv6 URL emits no route\",\n\t\t\tendpoint:  \"http://[::1]:5030/RPC2\",\n\t\t\twantRoute: nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"malformed endpoint emits no route without panic\",\n\t\t\tendpoint:  \"not-a-url\",\n\t\t\twantRoute: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg, err := o.ParseMetadata(st, staticIfaceContext(tt.endpoint))\n\t\t\trequire.NoError(t, err)\n\n\t\t\troutes := scopeLinkRoutes(cfg.Routes)\n\n\t\t\tif tt.wantRoute == nil {\n\t\t\t\tassert.Empty(t, routes)\n\t\t\t} else {\n\t\t\t\trequire.Len(t, routes, 1)\n\t\t\t\tassert.Equal(t, *tt.wantRoute, routes[0])\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestOnegateRouteAttachedToFirstStaticInterface(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t// ETH0=dhcp, ETH1=static — route must be on eth1 (first static).\n\tctx := []byte(`ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_METHOD = \"dhcp\"\nETH1_MAC = \"02:00:c0:a8:01:5d\"\nETH1_IP = \"192.168.1.92\"\nETH1_MASK = \"255.255.255.0\"\nONEGATE_ENDPOINT = \"http://169.254.16.9:5030/RPC2\"\n`)\n\n\tcfg, err := o.ParseMetadata(st, ctx)\n\trequire.NoError(t, err)\n\n\troutes := scopeLinkRoutes(cfg.Routes)\n\trequire.Len(t, routes, 1)\n\tassert.Equal(t, \"eth1\", routes[0].OutLinkName)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/opennebula.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-envparse\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/address\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nconst methodSkip = \"skip\"\n\n// OpenNebula is the concrete type that implements the runtime.Platform interface.\ntype OpenNebula struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (o *OpenNebula) Name() string {\n\treturn \"opennebula\"\n}\n\n// isDigitsOnly returns true if s is non-empty and contains only ASCII digits.\nfunc isDigitsOnly(s string) bool {\n\tfor _, c := range s {\n\t\tif c < '0' || c > '9' {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn s != \"\"\n}\n\n// collectAliasNames scans oneContext for keys of the form\n// <aliasPrefix><digits>_MAC and returns the sorted list of alias base names\n// (e.g. \"ETH0_ALIAS0\", \"ETH0_ALIAS1\").\nfunc collectAliasNames(oneContext map[string]string, aliasPrefix string) []string {\n\tseen := map[string]bool{}\n\n\tvar aliasNames []string\n\n\tfor key := range oneContext {\n\t\tif !strings.HasPrefix(key, aliasPrefix) || !strings.HasSuffix(key, \"_MAC\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tmiddle := strings.TrimPrefix(strings.TrimSuffix(key, \"_MAC\"), aliasPrefix)\n\t\tif !isDigitsOnly(middle) {\n\t\t\tcontinue\n\t\t}\n\n\t\taliasName := aliasPrefix + middle\n\t\tif !seen[aliasName] {\n\t\t\tseen[aliasName] = true\n\t\t\taliasNames = append(aliasNames, aliasName)\n\t\t}\n\t}\n\n\tslices.Sort(aliasNames)\n\n\treturn aliasNames\n}\n\n// parseAlias parses the addresses for a single alias entry. Returns nil, nil\n// when the alias should be skipped (DETACH non-empty or EXTERNAL=YES).\nfunc parseAlias(oneContext map[string]string, aliasName, ifaceNameLower string) ([]network.AddressSpecSpec, error) {\n\t// Skip detached aliases — reference: [ -z \"${detach}\" ]\n\tif oneContext[aliasName+\"_DETACH\"] != \"\" {\n\t\treturn nil, nil\n\t}\n\n\t// Skip externally managed aliases — reference: ! is_true \"${external}\"\n\tif strings.EqualFold(oneContext[aliasName+\"_EXTERNAL\"], \"yes\") {\n\t\treturn nil, nil\n\t}\n\n\tvar addrs []network.AddressSpecSpec\n\n\tif ipStr := oneContext[aliasName+\"_IP\"]; ipStr != \"\" {\n\t\tipPrefix, err := address.IPPrefixFrom(ipStr, oneContext[aliasName+\"_MASK\"])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"alias %s: failed to parse IPv4: %w\", aliasName, err)\n\t\t}\n\n\t\taddrs = append(addrs, network.AddressSpecSpec{\n\t\t\tAddress:     ipPrefix,\n\t\t\tLinkName:    ifaceNameLower,\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tip6Str := oneContext[aliasName+\"_IP6\"]\n\tif ip6Str == \"\" {\n\t\tip6Str = oneContext[aliasName+\"_IPV6\"]\n\t}\n\n\tif ip6Str != \"\" {\n\t\tip6Prefix, err := ip6PrefixFrom(ip6Str, oneContext[aliasName+\"_IP6_PREFIX_LENGTH\"])\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"alias %s: failed to parse IPv6: %w\", aliasName, err)\n\t\t}\n\n\t\taddrs = append(addrs, network.AddressSpecSpec{\n\t\t\tAddress:     ip6Prefix,\n\t\t\tLinkName:    ifaceNameLower,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tif ulaStr := oneContext[aliasName+\"_IP6_ULA\"]; ulaStr != \"\" {\n\t\tulaPrefix, err := ip6PrefixFrom(ulaStr, \"64\")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"alias %s: failed to parse IPv6 ULA: %w\", aliasName, err)\n\t\t}\n\n\t\taddrs = append(addrs, network.AddressSpecSpec{\n\t\t\tAddress:     ulaPrefix,\n\t\t\tLinkName:    ifaceNameLower,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\treturn addrs, nil\n}\n\n// parseAliases collects ETHn_ALIASm_* address entries for a given interface.\n// An alias is skipped when DETACH is non-empty OR EXTERNAL=YES, matching the\n// reference netcfg-networkd behavior (lines 395-400).\nfunc parseAliases(oneContext map[string]string, ifaceName, ifaceNameLower string) ([]network.AddressSpecSpec, error) {\n\taliasNames := collectAliasNames(oneContext, ifaceName+\"_ALIAS\")\n\n\tvar addrs []network.AddressSpecSpec\n\n\tfor _, aliasName := range aliasNames {\n\t\taliasAddrs, err := parseAlias(oneContext, aliasName, ifaceNameLower)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\taddrs = append(addrs, aliasAddrs...)\n\t}\n\n\treturn addrs, nil\n}\n\n// sanitizeHostname replaces characters invalid in DNS labels with hyphens,\n// strips leading/trailing hyphens from the whole string and from each label.\n// This mirrors the reference sanitization in one-apps/context-linux:\n//\n//\tsed -e 's/[^-a-zA-Z0-9\\.]/-/g' -e 's/^-*//g' -e 's/-*$//g'\n//\n// Talos is intentionally stricter: it also trims hyphens per-label so every\n// label is RFC-1123-valid (no label may start or end with a hyphen).\nfunc sanitizeHostname(raw string) string {\n\tvar b strings.Builder\n\n\tfor _, r := range raw {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z',\n\t\t\tr >= 'A' && r <= 'Z',\n\t\t\tr >= '0' && r <= '9',\n\t\t\tr == '-', r == '.':\n\t\t\tb.WriteRune(r)\n\t\tdefault:\n\t\t\tb.WriteRune('-')\n\t\t}\n\t}\n\n\ts := strings.Trim(b.String(), \"-\")\n\n\tlabels := strings.Split(s, \".\")\n\tfor i, l := range labels {\n\t\tlabels[i] = strings.Trim(l, \"-\")\n\t}\n\n\treturn strings.Join(labels, \".\")\n}\n\n// parseRouteFields extracts the destination prefix, gateway string, and optional\n// metric string from the fields of a single route entry.\n//\n// The reference one-apps implementation (context-linux) always parses routes as:\n//\n//\trsplit=( ${route} ); dst=\"${rsplit[0]}\"; gw=\"${rsplit[2]}\"\n//\n// meaning token[1] is always skipped and the gateway is always at token[2].\n// The canonical format is \"DEST/PREFIX via GW\" where \"via\" occupies token[1].\n// The legacy dotted-mask format \"DEST MASK GW\" follows the same index layout.\n//\n// As a Talos extension, an optional bare metric may follow the gateway.\nfunc parseRouteFields(parts []string) (dest netip.Prefix, gwStr, metricStr string, err error) {\n\t// Both CIDR (\"DEST/PREFIX via GW\") and legacy (\"DEST MASK GW\") formats\n\t// require at least 3 tokens, with the gateway always at index 2.\n\tif len(parts) < 3 {\n\t\treturn dest, \"\", \"\", fmt.Errorf(\"expected at least 3 fields (DEST/PREFIX via GW or DEST MASK GW)\")\n\t}\n\n\tif strings.Contains(parts[0], \"/\") {\n\t\t// CIDR format: \"DEST/PREFIX via GW [METRIC]\"\n\t\t// parts[1] is the separator token (conventionally \"via\") and is skipped,\n\t\t// matching the reference rsplit[1] which is never read.\n\t\tdest, err = netip.ParsePrefix(parts[0])\n\t\tif err != nil {\n\t\t\treturn dest, \"\", \"\", fmt.Errorf(\"failed to parse destination: %w\", err)\n\t\t}\n\n\t\tdest = dest.Masked()\n\t} else {\n\t\t// Legacy format: \"DEST MASK GW [METRIC]\"\n\t\tvar prefix netip.Prefix\n\n\t\tprefix, err = address.IPPrefixFrom(parts[0], parts[1])\n\t\tif err != nil {\n\t\t\treturn dest, \"\", \"\", fmt.Errorf(\"failed to parse destination: %w\", err)\n\t\t}\n\n\t\tdest = prefix.Masked()\n\t}\n\n\tgwStr = parts[2]\n\n\tif len(parts) >= 4 {\n\t\tmetricStr = parts[3]\n\t}\n\n\treturn dest, gwStr, metricStr, nil\n}\n\n// parseRouteEntry parses a single trimmed route entry into a RouteSpecSpec.\nfunc parseRouteEntry(entry, linkName string) (network.RouteSpecSpec, error) {\n\tdest, gwStr, metricStr, err := parseRouteFields(strings.Fields(entry))\n\tif err != nil {\n\t\treturn network.RouteSpecSpec{}, fmt.Errorf(\"route entry %q: %w\", entry, err)\n\t}\n\n\tgw, err := netip.ParseAddr(gwStr)\n\tif err != nil {\n\t\treturn network.RouteSpecSpec{}, fmt.Errorf(\"route entry %q: failed to parse gateway: %w\", entry, err)\n\t}\n\n\tmetric := uint32(network.DefaultRouteMetric)\n\n\tif metricStr != \"\" {\n\t\tm, err := strconv.ParseUint(metricStr, 10, 32)\n\t\tif err != nil {\n\t\t\treturn network.RouteSpecSpec{}, fmt.Errorf(\"route entry %q: failed to parse metric: %w\", entry, err)\n\t\t}\n\n\t\tmetric = uint32(m)\n\t}\n\n\tfamily := nethelpers.FamilyInet4\n\tif gw.Is6() {\n\t\tfamily = nethelpers.FamilyInet6\n\t}\n\n\troute := network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tDestination: dest,\n\t\tGateway:     gw,\n\t\tOutLinkName: linkName,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      family,\n\t\tPriority:    metric,\n\t}\n\n\troute.Normalize()\n\n\treturn route, nil\n}\n\n// ParseRoutes parses the ETH*_ROUTES variable into RouteSpecSpec entries.\n// Multiple routes are separated by commas.\nfunc ParseRoutes(routesStr, linkName string) ([]network.RouteSpecSpec, error) {\n\tvar routes []network.RouteSpecSpec\n\n\tfor entry := range strings.SplitSeq(routesStr, \",\") {\n\t\tentry = strings.TrimSpace(entry)\n\t\tif entry == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\troute, err := parseRouteEntry(entry, linkName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\troutes = append(routes, route)\n\t}\n\n\treturn routes, nil\n}\n\n// parseIPv4StaticConfig handles the static addressing path for an interface:\n// address, link, gateway route, extra static routes, and per-interface DNS.\nfunc parseIPv4StaticConfig(\n\toneContext map[string]string, ifaceName, ifaceNameLower string, routeMetric uint32,\n\tnetworkConfig *runtime.PlatformNetworkConfig, allDNSIPs *[]netip.Addr, allSearchDomains *[]string,\n) error {\n\tipPrefix, err := address.IPPrefixFrom(oneContext[ifaceName+\"_IP\"], oneContext[ifaceName+\"_MASK\"])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse IP address: %w\", err)\n\t}\n\n\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\tnetwork.AddressSpecSpec{\n\t\t\tAddress:         ipPrefix,\n\t\t\tLinkName:        ifaceNameLower,\n\t\t\tFamily:          nethelpers.FamilyInet4,\n\t\t\tScope:           nethelpers.ScopeGlobal,\n\t\t\tFlags:           nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tAnnounceWithARP: false,\n\t\t\tConfigLayer:     network.ConfigPlatform,\n\t\t},\n\t)\n\n\tvar mtu uint32\n\n\tif mtuStr := oneContext[ifaceName+\"_MTU\"]; mtuStr != \"\" {\n\t\tmtu64, err := strconv.ParseUint(mtuStr, 10, 32)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse MTU: %w\", err)\n\t\t}\n\n\t\tmtu = uint32(mtu64)\n\t}\n\n\tnetworkConfig.Links = append(networkConfig.Links,\n\t\tnetwork.LinkSpecSpec{\n\t\t\tName:        ifaceNameLower,\n\t\t\tLogical:     false,\n\t\t\tUp:          true,\n\t\t\tMTU:         mtu,\n\t\t\tKind:        \"\",\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tParentName:  \"\",\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t)\n\n\tif gwStr := oneContext[ifaceName+\"_GATEWAY\"]; gwStr != \"\" {\n\t\tgateway, err := netip.ParseAddr(gwStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse gateway ip: %w\", err)\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     gateway,\n\t\t\tOutLinkName: ifaceNameLower,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\tPriority:    routeMetric,\n\t\t}\n\n\t\troute.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t}\n\n\tif routesStr := oneContext[ifaceName+\"_ROUTES\"]; routesStr != \"\" {\n\t\tstaticRoutes, err := ParseRoutes(routesStr, ifaceNameLower)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"interface %s: %w\", ifaceName, err)\n\t\t}\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, staticRoutes...)\n\t}\n\n\tfor s := range strings.FieldsSeq(oneContext[ifaceName+\"_DNS\"]) {\n\t\tip, err := netip.ParseAddr(s)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"interface %s: failed to parse DNS server %q: %w\", ifaceName, s, err)\n\t\t}\n\n\t\t*allDNSIPs = append(*allDNSIPs, ip)\n\t}\n\n\t*allSearchDomains = append(*allSearchDomains, strings.Fields(oneContext[ifaceName+\"_SEARCH_DOMAIN\"])...)\n\n\treturn nil\n}\n\n// parseIPv4Metric reads ETH*_METRIC and returns the parsed value, or 0 when\n// the variable is absent. Callers apply their own default (e.g.\n// network.DefaultRouteMetric for IPv4, 1 for IPv6 via parseIPv6Metric).\nfunc parseIPv4Metric(oneContext map[string]string, ifaceName string) (uint32, error) {\n\tif metricStr := oneContext[ifaceName+\"_METRIC\"]; metricStr != \"\" {\n\t\tm, err := strconv.ParseUint(metricStr, 10, 32)\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"interface %s: failed to parse metric: %w\", ifaceName, err)\n\t\t}\n\n\t\treturn uint32(m), nil\n\t}\n\n\treturn 0, nil\n}\n\n// parseIPv6Metric reads ETH*_IP6_METRIC; falls back to ipv4Metric (when > 0),\n// then to 1, matching the reference [ -z \"$ip6_metric\" ] && ip6_metric=\"${metric}\".\nfunc parseIPv6Metric(oneContext map[string]string, ifaceName string, ipv4Metric uint32) (uint32, error) {\n\tif metricStr := oneContext[ifaceName+\"_IP6_METRIC\"]; metricStr != \"\" {\n\t\tm, err := strconv.ParseUint(metricStr, 10, 32)\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"interface %s: failed to parse IPv6 metric: %w\", ifaceName, err)\n\t\t}\n\n\t\treturn uint32(m), nil\n\t}\n\n\tif ipv4Metric > 0 {\n\t\treturn ipv4Metric, nil\n\t}\n\n\treturn 1, nil\n}\n\n// parseInterfaceIPv4 configures the IPv4 stack for one interface.\n// Dispatches to DHCP4 operator or static config based on ETH*_METHOD.\nfunc parseInterfaceIPv4(\n\toneContext map[string]string, ifaceName, ifaceNameLower string, routeMetric uint32,\n\tnetworkConfig *runtime.PlatformNetworkConfig, allDNSIPs *[]netip.Addr, allSearchDomains *[]string,\n) error {\n\tif oneContext[ifaceName+\"_METHOD\"] == methodSkip {\n\t\treturn nil\n\t}\n\n\tif routeMetric == 0 {\n\t\trouteMetric = uint32(network.DefaultRouteMetric)\n\t}\n\n\tif oneContext[ifaceName+\"_METHOD\"] == \"dhcp\" {\n\t\tnetworkConfig.Operators = append(networkConfig.Operators,\n\t\t\tnetwork.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\tLinkName:  ifaceNameLower,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\tRouteMetric:         routeMetric,\n\t\t\t\t\tSkipHostnameRequest: true,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t)\n\n\t\treturn nil\n\t}\n\n\treturn parseIPv4StaticConfig(oneContext, ifaceName, ifaceNameLower, routeMetric, networkConfig, allDNSIPs, allSearchDomains)\n}\n\n// ip6PrefixFrom builds a netip.Prefix from an IPv6 address string and an\n// optional prefix-length string (default 64). The prefix is not masked so the\n// full host address is preserved on the interface.\nfunc ip6PrefixFrom(ipStr, prefixLenStr string) (netip.Prefix, error) {\n\tip, err := netip.ParseAddr(ipStr)\n\tif err != nil {\n\t\treturn netip.Prefix{}, fmt.Errorf(\"failed to parse IPv6 address %q: %w\", ipStr, err)\n\t}\n\n\tbits := 64\n\n\tif prefixLenStr != \"\" {\n\t\tn, err := strconv.Atoi(prefixLenStr)\n\t\tif err != nil {\n\t\t\treturn netip.Prefix{}, fmt.Errorf(\"failed to parse IPv6 prefix length %q: %w\", prefixLenStr, err)\n\t\t}\n\n\t\tbits = n\n\t}\n\n\treturn netip.PrefixFrom(ip, bits), nil\n}\n\n// parseIPv6Gateway reads ETH*_IP6_GATEWAY (or legacy GATEWAY6) and emits the\n// default IPv6 route (::/0) with metric from parseIPv6Metric.\nfunc parseIPv6Gateway(oneContext map[string]string, ifaceName, ifaceNameLower string, ipv4Metric uint32, networkConfig *runtime.PlatformNetworkConfig) error {\n\tgwStr := oneContext[ifaceName+\"_IP6_GATEWAY\"]\n\tif gwStr == \"\" {\n\t\tgwStr = oneContext[ifaceName+\"_GATEWAY6\"]\n\t}\n\n\tif gwStr == \"\" {\n\t\treturn nil\n\t}\n\n\tgw, err := netip.ParseAddr(gwStr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interface %s: failed to parse IPv6 gateway %q: %w\", ifaceName, gwStr, err)\n\t}\n\n\tmetric, err := parseIPv6Metric(oneContext, ifaceName, ipv4Metric)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\troute := network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tGateway:     gw,\n\t\tOutLinkName: ifaceNameLower,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      nethelpers.FamilyInet6,\n\t\tPriority:    metric,\n\t}\n\n\troute.Normalize()\n\n\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\n\treturn nil\n}\n\n// parseIPv6DHCP emits a DHCPv6 operator for an interface, with metric from\n// parseIPv6Metric.\nfunc parseIPv6DHCP(oneContext map[string]string, ifaceName, ifaceNameLower string, ipv4Metric uint32, networkConfig *runtime.PlatformNetworkConfig) error {\n\tmetric, err := parseIPv6Metric(oneContext, ifaceName, ipv4Metric)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorDHCP6,\n\t\tLinkName:  ifaceNameLower,\n\t\tRequireUp: true,\n\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\tRouteMetric:         metric,\n\t\t\tSkipHostnameRequest: true,\n\t\t},\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\treturn nil\n}\n\n// parseInterfaceIPv6 configures the IPv6 stack for one interface.\n// Dispatches on the effective IP6_METHOD: disable/skip (no-op), auto (SLAAC),\n// dhcp (DHCPv6 operator), or static/empty (static address path).\n// When IP6_METHOD is unset, ipv4Method is used as fallback, matching the\n// reference: [ -z \"$ip6_method\" ] && ip6_method=\"${method}\".\nfunc parseInterfaceIPv6(oneContext map[string]string, ifaceName, ifaceNameLower string, ipv4Method string, ipv4Metric uint32, networkConfig *runtime.PlatformNetworkConfig) error {\n\tip6Method := strings.ToLower(oneContext[ifaceName+\"_IP6_METHOD\"])\n\tif ip6Method == \"\" {\n\t\tip6Method = ipv4Method\n\t}\n\n\tswitch ip6Method {\n\tcase \"disable\", methodSkip:\n\t\treturn nil\n\tcase \"auto\":\n\t\t// SLAAC: the kernel accepts Router Advertisements by default in Talos;\n\t\t// no operator or sysctl is required to enable address auto-configuration.\n\t\treturn nil\n\tcase \"dhcp\":\n\t\treturn parseIPv6DHCP(oneContext, ifaceName, ifaceNameLower, ipv4Metric, networkConfig)\n\t}\n\n\tip6Str := oneContext[ifaceName+\"_IP6\"]\n\tif ip6Str == \"\" {\n\t\tip6Str = oneContext[ifaceName+\"_IPV6\"]\n\t}\n\n\tprefixLenStr := oneContext[ifaceName+\"_IP6_PREFIX_LENGTH\"]\n\n\tif ip6Str != \"\" {\n\t\tip6Prefix, err := ip6PrefixFrom(ip6Str, prefixLenStr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"interface %s: %w\", ifaceName, err)\n\t\t}\n\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses, network.AddressSpecSpec{\n\t\t\tAddress:     ip6Prefix,\n\t\t\tLinkName:    ifaceNameLower,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tif ulaStr := oneContext[ifaceName+\"_IP6_ULA\"]; ulaStr != \"\" {\n\t\tulaPrefix, err := ip6PrefixFrom(ulaStr, \"64\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"interface %s ULA: %w\", ifaceName, err)\n\t\t}\n\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses, network.AddressSpecSpec{\n\t\t\tAddress:     ulaPrefix,\n\t\t\tLinkName:    ifaceNameLower,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\treturn parseIPv6Gateway(oneContext, ifaceName, ifaceNameLower, ipv4Metric, networkConfig)\n}\n\n// parseInterface runs all per-interface configuration (IPv4, IPv6, aliases).\nfunc parseInterface(oneContext map[string]string, ifaceName string, networkConfig *runtime.PlatformNetworkConfig, allDNSIPs *[]netip.Addr, allSearchDomains *[]string) error {\n\tifaceNameLower := strings.ToLower(ifaceName)\n\tipv4Method := strings.ToLower(oneContext[ifaceName+\"_METHOD\"])\n\n\tip6Method := strings.ToLower(oneContext[ifaceName+\"_IP6_METHOD\"])\n\tif ip6Method == \"\" {\n\t\tip6Method = ipv4Method\n\t}\n\n\tif ipv4Method == methodSkip && (ip6Method == \"\" || ip6Method == methodSkip || ip6Method == \"disable\") {\n\t\treturn nil\n\t}\n\n\tipv4Metric, err := parseIPv4Metric(oneContext, ifaceName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := parseInterfaceIPv4(oneContext, ifaceName, ifaceNameLower, ipv4Metric, networkConfig, allDNSIPs, allSearchDomains); err != nil {\n\t\treturn err\n\t}\n\n\tif err := parseInterfaceIPv6(oneContext, ifaceName, ifaceNameLower, ipv4Method, ipv4Metric, networkConfig); err != nil {\n\t\treturn err\n\t}\n\n\taliasAddrs, err := parseAliases(oneContext, ifaceName, ifaceNameLower)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig.Addresses = append(networkConfig.Addresses, aliasAddrs...)\n\n\treturn nil\n}\n\n// ethInterfaceName returns the interface name (e.g. \"ETH0\") from a context map\n// key of the form ETH<digits>_MAC, or (\"\", false) for any other key.\nfunc ethInterfaceName(key string) (string, bool) {\n\tif !strings.HasPrefix(key, \"ETH\") || !strings.HasSuffix(key, \"_MAC\") {\n\t\treturn \"\", false\n\t}\n\n\tname := strings.TrimSuffix(key, \"_MAC\")\n\n\tif !isDigitsOnly(strings.TrimPrefix(name, \"ETH\")) {\n\t\treturn \"\", false\n\t}\n\n\treturn name, true\n}\n\n// resolveHostname reads SET_HOSTNAME from the context map and sanitizes it,\n// matching the reference net-15-hostname script precedence. HOSTNAME and NAME\n// are not used — the reference never reads them for hostname configuration.\n// DNS_HOSTNAME is a server-side flag that triggers a reverse DNS lookup\n// (a live network operation) and cannot be honored inside ParseMetadata.\nfunc resolveHostname(oneContext map[string]string) string {\n\treturn sanitizeHostname(oneContext[\"SET_HOSTNAME\"])\n}\n\n// extractIPv4FromEndpoint extracts the host IPv4 address from a URL-like\n// string (e.g. \"http://169.254.16.9:5030\"). Returns an invalid Addr if no\n// IPv4 address can be parsed from the host portion.\nfunc extractIPv4FromEndpoint(endpoint string) netip.Addr {\n\ts := endpoint\n\n\t// Strip scheme (e.g. \"http://\").\n\tif idx := strings.Index(s, \"://\"); idx >= 0 {\n\t\ts = s[idx+3:]\n\t}\n\n\t// Strip path, query, and port in order to isolate the bare host.\n\tfor _, sep := range []string{\"/\", \"?\", \":\"} {\n\t\tif idx := strings.Index(s, sep); idx >= 0 {\n\t\t\ts = s[:idx]\n\t\t}\n\t}\n\n\taddr, err := netip.ParseAddr(s)\n\tif err != nil {\n\t\treturn netip.Addr{}\n\t}\n\n\treturn addr\n}\n\n// parseOnegateProxyRoute emits a /32 scope-link host route to the ONEGATE\n// endpoint when its host is a link-local IPv4 address (169.254.x.x). The\n// route is attached to outLink (the first static interface), matching the\n// reference add_onegate_proxy_route behavior.\nfunc parseOnegateProxyRoute(oneContext map[string]string, outLink string, networkConfig *runtime.PlatformNetworkConfig) {\n\tendpoint := oneContext[\"ONEGATE_ENDPOINT\"]\n\tif endpoint == \"\" {\n\t\treturn\n\t}\n\n\tip := extractIPv4FromEndpoint(endpoint)\n\tif !ip.IsValid() || !ip.Is4() || !ip.IsLinkLocalUnicast() {\n\t\treturn\n\t}\n\n\troute := network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tDestination: netip.PrefixFrom(ip, 32),\n\t\tOutLinkName: outLink,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeLink,\n\t}\n\n\troute.Normalize()\n\n\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n}\n\n// processInterfaces iterates ETHn interfaces in sorted order, configures each\n// one, and returns the name of the first static interface link (used to attach\n// the ONEGATE proxy route). Sorted order matches the reference behavior of\n// env | grep ... | sort (ETH0, ETH1, ETH2, ...).\nfunc processInterfaces(\n\toneContext map[string]string,\n\tnetworkConfig *runtime.PlatformNetworkConfig,\n\tallDNSIPs *[]netip.Addr,\n\tallSearchDomains *[]string,\n) (firstStaticLink string, err error) {\n\tvar ifaceNames []string\n\n\tfor key := range oneContext {\n\t\tif ifaceName, ok := ethInterfaceName(key); ok {\n\t\t\tifaceNames = append(ifaceNames, ifaceName)\n\t\t}\n\t}\n\n\tslices.Sort(ifaceNames)\n\n\tfor _, ifaceName := range ifaceNames {\n\t\tif err := parseInterface(oneContext, ifaceName, networkConfig, allDNSIPs, allSearchDomains); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif firstStaticLink == \"\" {\n\t\t\tmethod := strings.ToLower(oneContext[ifaceName+\"_METHOD\"])\n\t\t\tif method == \"\" || method == \"static\" {\n\t\t\t\tfirstStaticLink = strings.ToLower(ifaceName)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn firstStaticLink, nil\n}\n\n// ParseMetadata converts opennebula metadata to platform network config.\nfunc (o *OpenNebula) ParseMetadata(st state.State, oneContextPlain []byte) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\toneContext, err := envparse.Parse(bytes.NewReader(oneContextPlain))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse context file %q: %w\", oneContextPlain, err)\n\t}\n\n\thostnameValue := resolveHostname(oneContext)\n\n\t// Seed the merged DNS/search-domain slices with global variables (DNS,\n\t// SEARCH_DOMAIN). These are applied regardless of interface, matching the\n\t// reference get_nameservers()/get_searchdomains() which processes global\n\t// variables before per-interface ones.\n\tvar allDNSIPs []netip.Addr\n\n\tfor s := range strings.FieldsSeq(oneContext[\"DNS\"]) {\n\t\tip, err := netip.ParseAddr(s)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse global DNS server %q: %w\", s, err)\n\t\t}\n\n\t\tallDNSIPs = append(allDNSIPs, ip)\n\t}\n\n\tallSearchDomains := append([]string(nil), strings.Fields(oneContext[\"SEARCH_DOMAIN\"])...)\n\n\tfirstStaticLink, err := processInterfaces(oneContext, networkConfig, &allDNSIPs, &allSearchDomains)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif firstStaticLink != \"\" {\n\t\tparseOnegateProxyRoute(oneContext, firstStaticLink, networkConfig)\n\t}\n\n\tif len(allDNSIPs)+len(allSearchDomains) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:    allDNSIPs,\n\t\t\tSearchDomains: allSearchDomains,\n\t\t\tConfigLayer:   network.ConfigPlatform,\n\t\t})\n\t}\n\n\thostnameSpec := network.HostnameSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tif hostnameValue != \"\" {\n\t\tif err := hostnameSpec.ParseFQDN(hostnameValue); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse hostname: %w\", err)\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:   o.Name(),\n\t\tHostname:   hostnameSpec.Hostname,\n\t\tInstanceID: oneContext[\"VMID\"],\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (o *OpenNebula) Configuration(ctx context.Context, r state.State) (machineConfig []byte, err error) {\n\toneContextPlain, err := o.contextFromCD(ctx, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\toneContext, err := envparse.Parse(bytes.NewReader(oneContextPlain))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse environment file %q: %w\", oneContextPlain, err)\n\t}\n\n\tuserData, ok := oneContext[\"USER_DATA\"]\n\tif !ok {\n\t\t// Legacy fallback: reference does USER_DATA=\"${USER_DATA:-${USERDATA}}\".\n\t\tuserData, ok = oneContext[\"USERDATA\"]\n\t}\n\n\tif !ok {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\tmachineConfig, err = base64.StdEncoding.DecodeString(userData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode USER_DATA: %v\", err)\n\t}\n\n\treturn machineConfig, nil\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (o *OpenNebula) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (o *OpenNebula) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (o *OpenNebula) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\toneContext, err := o.contextFromCD(ctx, st)\n\tif stderrors.Is(err, errors.ErrNoConfigSource) {\n\t\terr = nil\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := o.ParseMetadata(st, oneContext)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/opennebula_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n)\n\n//go:embed testdata/metadata.yaml\nvar oneContextPlain []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\n//go:embed testdata/metadata_no_network_flag.yaml\nvar oneContextPlainNoNetworkFlag []byte\n\n//go:embed testdata/expected_no_network_flag.yaml\nvar expectedNetworkConfigNoNetworkFlag string\n\nfunc TestParseMetadata(t *testing.T) {\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tnetworkConfig, err := o.ParseMetadata(st, oneContextPlain)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n\n// TestParseMetadataNoNetworkFlag verifies that ETH*_ variables are processed\n// regardless of the NETWORK context variable value. NETWORK=YES is a\n// server-side OpenNebula directive and should not gate guest-side processing.\nfunc TestParseMetadataNoNetworkFlag(t *testing.T) {\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tnetworkConfig, err := o.ParseMetadata(st, oneContextPlainNoNetworkFlag)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\tassert.Equal(t, expectedNetworkConfigNoNetworkFlag, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/routes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestParseRoutes(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tname      string\n\t\troutesStr string\n\t\tlinkName  string\n\t\texpected  []network.RouteSpecSpec\n\t\terrMsg    string\n\t}{\n\t\t{\n\t\t\tname:      \"empty string\",\n\t\t\troutesStr: \"\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected:  nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"whitespace only\",\n\t\t\troutesStr: \"   ,  ,  \",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected:  nil,\n\t\t},\n\t\t{\n\t\t\tname:      \"legacy single route default metric\",\n\t\t\troutesStr: \"10.0.0.0 255.0.0.0 192.168.1.1\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"legacy single route custom metric\",\n\t\t\troutesStr: \"172.16.0.0 255.255.0.0 192.168.1.1 500\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"172.16.0.0/16\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    500,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"cidr single route\",\n\t\t\troutesStr: \"10.0.0.0/8 via 192.168.1.1\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"cidr single route with metric\",\n\t\t\troutesStr: \"10.0.0.0/8 via 192.168.1.1 200\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    200,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"multiple routes comma separated\",\n\t\t\troutesStr: \"10.0.0.0 255.0.0.0 192.168.1.1, 172.16.0.0 255.255.0.0 192.168.1.1 500\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"172.16.0.0/16\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    500,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"cidr host bits masked\",\n\t\t\troutesStr: \"10.1.2.0/8 via 192.168.1.1\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\texpected: []network.RouteSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tDestination: netip.MustParsePrefix(\"10.0.0.0/8\"),\n\t\t\t\t\tGateway:     netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\t\t\tOutLinkName: \"eth0\",\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"malformed gateway\",\n\t\t\troutesStr: \"10.0.0.0/8 via notanip\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"failed to parse gateway\",\n\t\t},\n\t\t{\n\t\t\tname:      \"malformed cidr destination\",\n\t\t\troutesStr: \"notaprefix/8 via 192.168.1.1\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"failed to parse destination\",\n\t\t},\n\t\t{\n\t\t\tname:      \"malformed legacy destination\",\n\t\t\troutesStr: \"notanip 255.0.0.0 192.168.1.1\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"failed to parse destination\",\n\t\t},\n\t\t{\n\t\t\tname:      \"malformed metric\",\n\t\t\troutesStr: \"10.0.0.0/8 via 192.168.1.1 notanumber\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"failed to parse metric\",\n\t\t},\n\t\t{\n\t\t\tname:      \"too few fields\",\n\t\t\troutesStr: \"10.0.0.0/8 via\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"expected at least 3 fields\",\n\t\t},\n\t\t{\n\t\t\tname:      \"legacy too few fields\",\n\t\t\troutesStr: \"10.0.0.0 255.0.0.0\",\n\t\t\tlinkName:  \"eth0\",\n\t\t\terrMsg:    \"expected at least 3 fields\",\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\troutes, err := opennebula.ParseRoutes(tc.routesStr, tc.linkName)\n\n\t\t\tif tc.errMsg != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tc.errMsg)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expected, routes)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/skip_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage opennebula_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst skipContextBase = `ETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_IP = \"192.168.1.92\"\nETH0_MASK = \"255.255.255.0\"\nNAME = \"test\"\n`\n\nfunc skipContext(extra string) []byte {\n\treturn []byte(skipContextBase + extra)\n}\n\nfunc TestParseMethodSkip(t *testing.T) {\n\tt.Parallel()\n\n\to := &opennebula.OpenNebula{}\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tfor _, tc := range []struct {\n\t\tname          string\n\t\textra         string\n\t\twantAddrs     int\n\t\twantLinks     int\n\t\twantRoutes    int\n\t\twantOperators []network.OperatorSpecSpec\n\t}{\n\t\t{\n\t\t\tname:       \"METHOD=skip omits interface entirely\",\n\t\t\textra:      `ETH0_METHOD = \"skip\"`,\n\t\t\twantAddrs:  0,\n\t\t\twantLinks:  0,\n\t\t\twantRoutes: 0,\n\t\t},\n\t\t{\n\t\t\tname:  \"METHOD=skip with IP6_METHOD=dhcp emits DHCPv6 operator only\",\n\t\t\textra: \"ETH0_METHOD = \\\"skip\\\"\\nETH0_IP6_METHOD = \\\"dhcp\\\"\",\n\t\t\twantOperators: []network.OperatorSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\t\tLinkName:  \"eth0\",\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\t\tRouteMetric:         1,\n\t\t\t\t\t\tSkipHostnameRequest: true,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"METHOD=skip with IP6_METHOD=disable omits interface entirely\",\n\t\t\textra:      \"ETH0_METHOD = \\\"skip\\\"\\nETH0_IP6_METHOD = \\\"disable\\\"\",\n\t\t\twantAddrs:  0,\n\t\t\twantLinks:  0,\n\t\t\twantRoutes: 0,\n\t\t},\n\t\t{\n\t\t\tname:       \"METHOD=skip with IP6_METHOD=skip omits interface entirely\",\n\t\t\textra:      \"ETH0_METHOD = \\\"skip\\\"\\nETH0_IP6_METHOD = \\\"skip\\\"\",\n\t\t\twantAddrs:  0,\n\t\t\twantLinks:  0,\n\t\t\twantRoutes: 0,\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnetworkConfig, err := o.ParseMetadata(st, skipContext(tc.extra))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Len(t, networkConfig.Addresses, tc.wantAddrs)\n\t\t\tassert.Len(t, networkConfig.Links, tc.wantLinks)\n\t\t\tassert.Len(t, networkConfig.Routes, tc.wantRoutes)\n\t\t\tassert.Equal(t, tc.wantOperators, networkConfig.Operators)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/expected.yaml",
    "content": "addresses:\n    - address: 192.168.1.92/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 192.168.1.100/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: ether\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 100\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 172.16.0.0/16\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 500\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: code-server\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 9.9.9.9\n        - 192.168.1.1\n        - 8.8.8.8\n        - 1.1.1.1\n      layer: platform\n      searchDomains:\n        - global.example.com\n        - example.com\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth1\n      requireUp: true\n      dhcp4:\n        routeMetric: 200\n        skipHostnameRequest: true\n      layer: platform\n    - operator: dhcp6\n      linkName: eth1\n      requireUp: true\n      dhcp6:\n        routeMetric: 200\n        skipHostnameRequest: true\n      layer: platform\nexternalIPs: []\nmetadata:\n    platform: opennebula\n    hostname: code-server\n    instanceId: \"14\"\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/expected_no_network_flag.yaml",
    "content": "addresses:\n    - address: 192.168.1.92/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 192.168.1.100/24\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: ether\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 100\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 10.0.0.0/8\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 172.16.0.0/16\n      src: \"\"\n      gateway: 192.168.1.1\n      outLinkName: eth0\n      table: main\n      priority: 500\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: code-server\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 9.9.9.9\n        - 192.168.1.1\n        - 8.8.8.8\n        - 1.1.1.1\n      layer: platform\n      searchDomains:\n        - global.example.com\n        - example.com\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth1\n      requireUp: true\n      dhcp4:\n        routeMetric: 200\n        skipHostnameRequest: true\n      layer: platform\n    - operator: dhcp6\n      linkName: eth1\n      requireUp: true\n      dhcp6:\n        routeMetric: 200\n        skipHostnameRequest: true\n      layer: platform\nexternalIPs: []\nmetadata:\n    platform: opennebula\n    hostname: code-server\n    instanceId: \"14\"\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/metadata.yaml",
    "content": "# Context variables generated by OpenNebula\nDISK_ID = \"1\"\nDNS = \"9.9.9.9\"\nETH0_DNS = \"192.168.1.1 8.8.8.8 1.1.1.1\"\nETH0_ALIAS0_DETACH = \"\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_EXTERNAL = \"\"\nETH0_GATEWAY = \"192.168.1.1\"\nETH0_IP = \"192.168.1.92\"\nETH0_IP6 = \"\"\nETH0_IP6_GATEWAY = \"\"\nETH0_IP6_METHOD = \"\"\nETH0_IP6_METRIC = \"\"\nETH0_IP6_PREFIX_LENGTH = \"\"\nETH0_IP6_ULA = \"\"\nETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_MASK = \"255.255.255.0\"\nETH0_METHOD = \"\"\nETH0_METRIC = \"100\"\nETH0_MTU = \"\"\nETH0_NETWORK = \"192.168.1.0\"\nETH0_ROUTES = \"10.0.0.0 255.0.0.0 192.168.1.1, 172.16.0.0 255.255.0.0 192.168.1.1 500\"\nETH0_SEARCH_DOMAIN = \"example.com\"\nETH0_VLAN_ID = \"3\"\nETH0_VROUTER_IP = \"\"\nETH0_VROUTER_IP6 = \"\"\nETH0_VROUTER_MANAGEMENT = \"\"\nSEARCH_DOMAIN = \"global.example.com\"\nNETWORK = \"YES\"\nSSH_PUBLIC_KEY = \"\"\nTARGET = \"hda\"\nVMID = \"14\"\nETH1_MAC = \"02:00:c0:a8:01:5d\"\nETH1_METHOD = \"dhcp\"\nETH1_METRIC = \"200\"\nSET_HOSTNAME = \"code-server\""
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula/testdata/metadata_no_network_flag.yaml",
    "content": "# Context variables generated by OpenNebula with NETWORK=NO.\n# ETH*_ variables are manually specified (e.g. for ETHER-type address ranges\n# where NETWORK=YES would cause the server to overwrite them with empty values).\nDISK_ID = \"1\"\nDNS = \"9.9.9.9\"\nETH0_DNS = \"192.168.1.1 8.8.8.8 1.1.1.1\"\nETH0_ALIAS0_DETACH = \"\"\nETH0_ALIAS0_EXTERNAL = \"NO\"\nETH0_ALIAS0_IP = \"192.168.1.100\"\nETH0_ALIAS0_MAC = \"02:00:c0:a8:01:64\"\nETH0_ALIAS0_MASK = \"255.255.255.0\"\nETH0_EXTERNAL = \"\"\nETH0_GATEWAY = \"192.168.1.1\"\nETH0_IP = \"192.168.1.92\"\nETH0_IP6 = \"\"\nETH0_IP6_GATEWAY = \"\"\nETH0_IP6_METHOD = \"\"\nETH0_IP6_METRIC = \"\"\nETH0_IP6_PREFIX_LENGTH = \"\"\nETH0_IP6_ULA = \"\"\nETH0_MAC = \"02:00:c0:a8:01:5c\"\nETH0_MASK = \"255.255.255.0\"\nETH0_METHOD = \"\"\nETH0_METRIC = \"100\"\nETH0_MTU = \"\"\nETH0_NETWORK = \"192.168.1.0\"\nETH0_ROUTES = \"10.0.0.0 255.0.0.0 192.168.1.1, 172.16.0.0 255.255.0.0 192.168.1.1 500\"\nETH0_SEARCH_DOMAIN = \"example.com\"\nETH0_VLAN_ID = \"3\"\nETH0_VROUTER_IP = \"\"\nETH0_VROUTER_IP6 = \"\"\nETH0_VROUTER_MANAGEMENT = \"\"\nSEARCH_DOMAIN = \"global.example.com\"\nNETWORK = \"NO\"\nSSH_PUBLIC_KEY = \"\"\nTARGET = \"hda\"\nVMID = \"14\"\nETH1_MAC = \"02:00:c0:a8:01:5d\"\nETH1_METHOD = \"dhcp\"\nETH1_METRIC = \"200\"\nSET_HOSTNAME = \"code-server\"\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage openstack\n\nimport (\n\t\"context\"\n\tstderrors \"errors\"\n\t\"io/fs\"\n\t\"log\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/blockutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\nconst (\n\t// config-drive configs path.\n\tconfigISOLabel        = \"config-2\"\n\tconfigMetadataPath    = \"openstack/latest/meta_data.json\"\n\tconfigNetworkDataPath = \"openstack/latest/network_data.json\"\n\tconfigUserDataPath    = \"openstack/latest/user_data\"\n\n\tendpoint = \"http://169.254.169.254/\"\n\n\t// OpenStackExternalIPEndpoint is the local OpenStack endpoint for the external IP.\n\tOpenStackExternalIPEndpoint = endpoint + \"latest/meta-data/public-ipv4\"\n\t// OpenStackInstanceTypeEndpoint is the local OpenStack endpoint for the instance-type.\n\tOpenStackInstanceTypeEndpoint = endpoint + \"latest/meta-data/instance-type\"\n\t// OpenStackMetaDataEndpoint is the local OpenStack endpoint for the meta config.\n\tOpenStackMetaDataEndpoint = endpoint + configMetadataPath\n\t// OpenStackNetworkDataEndpoint is the local OpenStack endpoint for the network config.\n\tOpenStackNetworkDataEndpoint = endpoint + configNetworkDataPath\n\t// OpenStackUserDataEndpoint is the local OpenStack endpoint for the config.\n\tOpenStackUserDataEndpoint = endpoint + configUserDataPath\n)\n\n// NetworkConfig holds NetworkData config.\ntype NetworkConfig struct {\n\tLinks []struct {\n\t\tID             string   `json:\"id,omitempty\"`\n\t\tType           string   `json:\"type\"`\n\t\tMac            string   `json:\"ethernet_mac_address,omitempty\"`\n\t\tMTU            int      `json:\"mtu,omitempty\"`\n\t\tBondMode       string   `json:\"bond_mode,omitempty\"`\n\t\tBondLinks      []string `json:\"bond_links,omitempty\"`\n\t\tBondMIIMon     uint32   `json:\"bond_miimon,string,omitempty\"`\n\t\tBondHashPolicy string   `json:\"bond_xmit_hash_policy,omitempty\"`\n\t\tVlanID         uint16   `json:\"vlan_id,omitempty\"`\n\t\tVlanLink       string   `json:\"vlan_link,omitempty\"`\n\t\tVlanMac        string   `json:\"vlan_mac_address,omitempty\"`\n\t} `json:\"links\"`\n\tNetworks []struct {\n\t\tID      string `json:\"id,omitempty\"`\n\t\tLink    string `json:\"link\"`\n\t\tType    string `json:\"type\"`\n\t\tAddress string `json:\"ip_address,omitempty\"`\n\t\tNetmask string `json:\"netmask,omitempty\"`\n\t\tGateway string `json:\"gateway,omitempty\"`\n\t\tRoutes  []struct {\n\t\t\tNetwork string `json:\"network,omitempty\"`\n\t\t\tNetmask string `json:\"netmask,omitempty\"`\n\t\t\tGateway string `json:\"gateway,omitempty\"`\n\t\t} `json:\"routes,omitempty\"`\n\t} `json:\"networks\"`\n\tServices []struct {\n\t\tType    string `json:\"type\"`\n\t\tAddress string `json:\"address\"`\n\t} `json:\"services,omitempty\"`\n}\n\n// MetadataConfig holds meta info.\ntype MetadataConfig struct {\n\tUUID             string `json:\"uuid,omitempty\"`\n\tHostname         string `json:\"hostname,omitempty\"`\n\tAvailabilityZone string `json:\"availability_zone,omitempty\"`\n\tProjectID        string `json:\"project_id\"`\n\tInstanceType     string `json:\"instance_type\"`\n}\n\nfunc (o *OpenStack) configFromNetwork(ctx context.Context) (metaConfig []byte, networkConfig []byte, machineConfig []byte, err error) {\n\tlog.Printf(\"fetching meta config from: %q\", OpenStackMetaDataEndpoint)\n\n\tmetaConfig, err = download.Download(ctx, OpenStackMetaDataEndpoint)\n\tif err != nil {\n\t\tmetaConfig = nil\n\t}\n\n\tlog.Printf(\"fetching network config from: %q\", OpenStackNetworkDataEndpoint)\n\n\tnetworkConfig, err = download.Download(ctx, OpenStackNetworkDataEndpoint)\n\tif err != nil {\n\t\tnetworkConfig = nil\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", OpenStackUserDataEndpoint)\n\n\tmachineConfig, err = download.Download(ctx, OpenStackUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\n\treturn metaConfig, networkConfig, machineConfig, err\n}\n\n//nolint:gocyclo\nfunc (o *OpenStack) configFromCD(ctx context.Context, r state.State) (metaConfig []byte, networkConfig []byte, machineConfig []byte, err error) {\n\terr = blockutils.ReadFromVolume(ctx, r, []string{configISOLabel}, func(root xfs.Root, volumeStatus *block.VolumeStatus) error {\n\t\tlog.Printf(\"found config disk (config-drive) at %s\", volumeStatus.TypedSpec().Location)\n\n\t\tlog.Printf(\"fetching meta config from: config-drive/%s\", configMetadataPath)\n\n\t\tmetaConfig, err = xfs.ReadFile(root, configMetadataPath)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed to read %s\", configMetadataPath)\n\n\t\t\tmetaConfig = nil\n\t\t}\n\n\t\tlog.Printf(\"fetching network config from: config-drive/%s\", configNetworkDataPath)\n\n\t\tnetworkConfig, err = xfs.ReadFile(root, configNetworkDataPath)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed to read %s\", configNetworkDataPath)\n\n\t\t\tnetworkConfig = nil\n\t\t}\n\n\t\tlog.Printf(\"fetching machine config from: config-drive/%s\", configUserDataPath)\n\n\t\tmachineConfig, err = xfs.ReadFile(root, configUserDataPath)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed to read %s\", configUserDataPath)\n\n\t\t\tmachineConfig = nil\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\tif stderrors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil, nil, errors.ErrNoConfigSource\n\t\t}\n\n\t\treturn nil, nil, nil, err\n\t}\n\n\tif machineConfig == nil {\n\t\terr = errors.ErrNoConfigSource\n\t}\n\n\treturn metaConfig, networkConfig, machineConfig, err\n}\n\nfunc (o *OpenStack) instanceType(ctx context.Context) string {\n\tlog.Printf(\"fetching instance-type from: %q\", OpenStackInstanceTypeEndpoint)\n\n\tsku, err := download.Download(ctx, OpenStackInstanceTypeEndpoint)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn string(sku)\n}\n\nfunc (o *OpenStack) externalIPs(ctx context.Context) (addrs []netip.Addr) {\n\tlog.Printf(\"fetching externalIP from: %q\", OpenStackExternalIPEndpoint)\n\n\texIP, err := download.Download(ctx, OpenStackExternalIPEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoExternalIPs),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoExternalIPs))\n\tif err != nil {\n\t\tlog.Printf(\"failed to fetch external IPs, ignored: %s\", err)\n\n\t\treturn nil\n\t}\n\n\tif addr, err := netip.ParseAddr(string(exIP)); err == nil {\n\t\taddrs = append(addrs, addr)\n\t}\n\n\treturn addrs\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/openstack.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package openstack provides the OpenStack platform implementation.\npackage openstack\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\tstderrors \"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cenkalti/backoff/v4\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\tnetworkadapter \"github.com/siderolabs/talos/internal/app/machined/pkg/adapters/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/address\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// OpenStack is the concrete type that implements the runtime.Platform interface.\ntype OpenStack struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (o *OpenStack) Name() string {\n\treturn \"openstack\"\n}\n\n// ParseMetadata converts OpenStack metadata to platform network configuration.\n//\n//nolint:gocyclo,cyclop\nfunc (o *OpenStack) ParseMetadata(\n\tctx context.Context,\n\tunmarshalledNetworkConfig *NetworkConfig,\n\textIPs []netip.Addr,\n\tmetadata *MetadataConfig,\n\tst state.State,\n) (*runtime.PlatformNetworkConfig, bool, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\tneedsReconcile := false\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tnetworkConfig.ExternalIPs = extIPs\n\n\tvar dnsIPs []netip.Addr\n\n\tfor _, netsvc := range unmarshalledNetworkConfig.Services {\n\t\tif netsvc.Type == \"dns\" && netsvc.Address != \"\" {\n\t\t\tif ip, err := netip.ParseAddr(netsvc.Address); err == nil {\n\t\t\t\tdnsIPs = append(dnsIPs, ip)\n\t\t\t} else {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse dns service ip: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(dnsIPs) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:  dnsIPs,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\thostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)\n\tif err != nil {\n\t\treturn nil, false, fmt.Errorf(\"error listing host interfaces: %w\", err)\n\t}\n\n\tifaces := make(map[string]string)\n\tbondLinks := make(map[string]string)\n\n\t// Bonds\n\n\tbondIndex := 0\n\n\tfor _, netLink := range unmarshalledNetworkConfig.Links {\n\t\tif netLink.Type != \"bond\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tmode, err := nethelpers.BondModeByName(netLink.BondMode)\n\t\tif err != nil {\n\t\t\treturn nil, false, fmt.Errorf(\"invalid bond_mode: %w\", err)\n\t\t}\n\n\t\thashPolicy, err := nethelpers.BondXmitHashPolicyByName(netLink.BondHashPolicy)\n\t\tif err != nil {\n\t\t\treturn nil, false, fmt.Errorf(\"invalid bond_xmit_hash_policy: %w\", err)\n\t\t}\n\n\t\tbondName := fmt.Sprintf(\"bond%d\", bondIndex)\n\t\tifaces[netLink.ID] = bondName\n\n\t\tbondLink := network.LinkSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tName:        bondName,\n\t\t\tLogical:     true,\n\t\t\tUp:          true,\n\t\t\tMTU:         uint32(netLink.MTU),\n\t\t\tKind:        network.LinkKindBond,\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tBondMaster: network.BondMasterSpec{\n\t\t\t\tMode:       mode,\n\t\t\t\tMIIMon:     netLink.BondMIIMon,\n\t\t\t\tHashPolicy: hashPolicy,\n\t\t\t\tUpDelay:    200,\n\t\t\t\tDownDelay:  200,\n\t\t\t\tLACPRate:   nethelpers.LACPRateFast,\n\t\t\t},\n\t\t}\n\n\t\tif netLink.Mac != \"\" {\n\t\t\tmac, err := net.ParseMAC(netLink.Mac)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"invalid bond MAC address %q: %w\", netLink.Mac, err)\n\t\t\t}\n\n\t\t\tbondLink.HardwareAddress = nethelpers.HardwareAddr(mac)\n\t\t}\n\n\t\tif mode == nethelpers.BondMode8023AD {\n\t\t\tbondLink.BondMaster.ADLACPActive = nethelpers.ADLACPActiveOn\n\t\t}\n\n\t\tnetworkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()\n\t\tnetworkConfig.Links = append(networkConfig.Links, bondLink)\n\n\t\tfor _, link := range netLink.BondLinks {\n\t\t\tbondLinks[link] = bondName\n\t\t}\n\n\t\tbondIndex++\n\t}\n\n\tbondSlaveIndexes := make(map[string]int)\n\n\t// Interfaces\n\n\tfor idx, netLink := range unmarshalledNetworkConfig.Links {\n\t\t// OpenStack network metadata schema:\n\t\t// \"type\": {\n\t\t// \t\"$id\": \"#/definitions/l2_link/properties/type\",\n\t\t// \t\"type\": \"string\",\n\t\t// \t\"enum\": [\n\t\t// \t  \"bridge\",\n\t\t// \t  \"dvs\",\n\t\t// \t  \"hw_veb\",\n\t\t// \t  \"hyperv\",\n\t\t// \t  \"ovs\",\n\t\t// \t  \"tap\",\n\t\t// \t  \"vhostuser\",\n\t\t// \t  \"vif\",\n\t\t// \t  \"phy\"\n\t\t// \t],\n\t\t// \t\"title\": \"Interface type\",\n\t\t// \t\"examples\": [\n\t\t// \t  \"bridge\"\n\t\t// \t]\n\t\t//   },\n\t\t//   \"vif_id\": {\n\t\t// \t\"$ref\": \"#/definitions/l2_vif_id\"\n\t\t//   }\n\t\tswitch netLink.Type {\n\t\tcase \"phy\", \"vif\", \"ovs\", \"bridge\", \"tap\", \"vhostuser\", \"hw_veb\":\n\t\t\tlinkName := \"\"\n\n\t\t\tif netLink.Mac != \"\" {\n\t\t\t\tfor hostInterface := range hostInterfaces.All() {\n\t\t\t\t\tmacAddress := hostInterface.TypedSpec().PermanentAddr.String()\n\t\t\t\t\tif macAddress == \"\" {\n\t\t\t\t\t\tmacAddress = hostInterface.TypedSpec().HardwareAddr.String()\n\t\t\t\t\t}\n\n\t\t\t\t\tif strings.EqualFold(macAddress, netLink.Mac) {\n\t\t\t\t\t\tlinkName = hostInterface.Metadata().ID()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif linkName == \"\" {\n\t\t\t\tlinkName = fmt.Sprintf(\"eth%d\", idx)\n\n\t\t\t\tlog.Printf(\"failed to find interface with MAC %q, using %q\", netLink.Mac, linkName)\n\n\t\t\t\tneedsReconcile = true\n\t\t\t}\n\n\t\t\tifaces[netLink.ID] = linkName\n\n\t\t\tlink := network.LinkSpecSpec{\n\t\t\t\tName:        ifaces[netLink.ID],\n\t\t\t\tUp:          true,\n\t\t\t\tMTU:         uint32(netLink.MTU),\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t}\n\n\t\t\tif bondName, ok := bondLinks[netLink.ID]; ok {\n\t\t\t\tlink.BondSlave = network.BondSlave{\n\t\t\t\t\tMasterName: bondName,\n\t\t\t\t\tSlaveIndex: bondSlaveIndexes[bondName],\n\t\t\t\t}\n\n\t\t\t\tbondSlaveIndexes[bondName]++\n\t\t\t}\n\n\t\t\tnetworkConfig.Links = append(networkConfig.Links, link)\n\t\t}\n\t}\n\n\t// VLANs\n\tfor _, netLink := range unmarshalledNetworkConfig.Links {\n\t\tif netLink.Type != \"vlan\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tparentName, ok := ifaces[netLink.VlanLink]\n\t\tif !ok {\n\t\t\tparentName = netLink.VlanLink\n\t\t}\n\n\t\tvlanName := fmt.Sprintf(\"%s.%d\", parentName, netLink.VlanID)\n\t\tifaces[netLink.ID] = vlanName\n\n\t\tvlanLink := network.LinkSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tName:        vlanName,\n\t\t\tLogical:     true,\n\t\t\tUp:          true,\n\t\t\tKind:        network.LinkKindVLAN,\n\t\t\tType:        nethelpers.LinkEther,\n\t\t\tParentName:  parentName,\n\t\t\tVLAN: network.VLANSpec{\n\t\t\t\tVID:      netLink.VlanID,\n\t\t\t\tProtocol: nethelpers.VLANProtocol8021Q,\n\t\t\t},\n\t\t}\n\n\t\tif netLink.MTU != 0 {\n\t\t\tvlanLink.MTU = uint32(netLink.MTU)\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, vlanLink)\n\t}\n\n\tfor _, ntwrk := range unmarshalledNetworkConfig.Networks {\n\t\tif ntwrk.ID == \"\" || ifaces[ntwrk.Link] == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tiface := ifaces[ntwrk.Link]\n\n\t\tswitch ntwrk.Type {\n\t\tcase \"ipv4_dhcp\":\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\tLinkName:  iface,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\tRouteMetric:         network.DefaultRouteMetric,\n\t\t\t\t\tSkipHostnameRequest: true,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\tcase \"ipv6_dhcp\", \"ipv6_dhcpv6-stateless\", \"ipv6_dhcpv6-stateful\":\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\tLinkName:  iface,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\tRouteMetric:         2 * network.DefaultRouteMetric,\n\t\t\t\t\tSkipHostnameRequest: true,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\tcase \"ipv4\", \"ipv6\", \"ipv6_slaac\":\n\t\t\t// FIXME: we need to switch on/off slaac here\n\t\tdefault:\n\t\t\tlog.Printf(\"network type %s is not supported\", ntwrk.Type)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif ntwrk.Address != \"\" {\n\t\t\tipPrefix, err := address.IPPrefixFrom(ntwrk.Address, ntwrk.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse ip address: %w\", err)\n\t\t\t}\n\n\t\t\tfamily := nethelpers.FamilyInet4\n\t\t\tif ipPrefix.Addr().Is6() {\n\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t}\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    iface,\n\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      family,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif ntwrk.Gateway != \"\" {\n\t\t\t\tgw, err := netip.ParseAddr(ntwrk.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse gateway ip: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tpriority := uint32(network.DefaultRouteMetric)\n\n\t\t\t\tif family == nethelpers.FamilyInet6 {\n\t\t\t\t\tpriority *= 2\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tOutLinkName: iface,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      family,\n\t\t\t\t\tPriority:    priority,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t}\n\t\t}\n\n\t\tfor _, route := range ntwrk.Routes {\n\t\t\tgw, err := netip.ParseAddr(route.Gateway)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse route gateway: %w\", err)\n\t\t\t}\n\n\t\t\tdest, err := address.IPPrefixFrom(route.Network, route.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, false, fmt.Errorf(\"failed to parse route network: %w\", err)\n\t\t\t}\n\n\t\t\tfamily := nethelpers.FamilyInet4\n\t\t\tif dest.Addr().Is6() {\n\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tDestination: dest,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: iface,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      family,\n\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\t// double the priority of the route if it is actually the default gateway and IPv6\n\t\t\tif route.Destination == (netip.Prefix{}) && family == nethelpers.FamilyInet6 {\n\t\t\t\troute.Priority *= 2\n\t\t\t}\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     o.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tZone:         metadata.AvailabilityZone,\n\t\tInstanceID:   metadata.UUID,\n\t\tInstanceType: metadata.InstanceType,\n\t\tProviderID:   fmt.Sprintf(\"openstack:///%s\", metadata.UUID),\n\t}\n\n\treturn networkConfig, needsReconcile, nil\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (o *OpenStack) Configuration(ctx context.Context, r state.State) (machineConfig []byte, err error) {\n\t_, _, machineConfig, err = o.configFromCD(ctx, r)\n\tif err != nil {\n\t\tif err = netutils.Wait(ctx, r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t_, _, machineConfig, err = o.configFromNetwork(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Some openstack setups does not allow you to change user-data,\n\t// so skip this case.\n\tif bytes.HasPrefix(machineConfig, []byte(\"#cloud-config\")) {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn machineConfig, nil\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (o *OpenStack) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (o *OpenStack) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\n//\n//nolint:gocyclo\nfunc (o *OpenStack) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\t// wait for devices to be ready before proceeding, otherwise we might not find network interfaces by MAC\n\tif err := netutils.WaitForDevicesReady(ctx, st); err != nil {\n\t\treturn fmt.Errorf(\"error waiting for devices to be ready: %w\", err)\n\t}\n\n\tnetworkSource := false\n\n\tmetadataConfigDl, metadataNetworkConfigDl, _, err := o.configFromCD(ctx, st)\n\tif err != nil {\n\t\tmetadataConfigDl, metadataNetworkConfigDl, _, err = o.configFromNetwork(ctx)\n\t\tif stderrors.Is(err, errors.ErrNoConfigSource) {\n\t\t\terr = nil\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkSource = true\n\t}\n\n\tvar (\n\t\tmeta                      MetadataConfig\n\t\tunmarshalledNetworkConfig NetworkConfig\n\t)\n\n\t// ignore errors unmarshaling, empty configs work just fine as empty default\n\t_ = json.Unmarshal(metadataConfigDl, &meta)                             //nolint:errcheck\n\t_ = json.Unmarshal(metadataNetworkConfigDl, &unmarshalledNetworkConfig) //nolint:errcheck\n\n\tvar extIPs []netip.Addr\n\n\tif networkSource {\n\t\textIPs = o.externalIPs(ctx)\n\n\t\tif meta.InstanceType == \"\" {\n\t\t\tmeta.InstanceType = o.instanceType(ctx)\n\t\t}\n\t}\n\n\t// do a loop to retry network config remap in case of missing links\n\t// on each try, export the configuration as it is, and if the network is reconciled next time, export the reconciled configuration\n\tbckoff := backoff.NewExponentialBackOff()\n\n\tfor {\n\t\tnetworkConfig, needsReconcile, err := o.ParseMetadata(ctx, &unmarshalledNetworkConfig, extIPs, &meta, st)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase ch <- networkConfig:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\n\t\tif !needsReconcile {\n\t\t\treturn nil\n\t\t}\n\n\t\t// wait for backoff to retry network config remap\n\t\tnextBackoff := bckoff.NextBackOff()\n\t\tif nextBackoff == backoff.Stop {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(nextBackoff):\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/openstack_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage openstack_test\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/openstack\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/network.json\nvar rawNetwork []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tname                   string\n\t\tnetworkJSON            []byte\n\t\tmetadataJSON           []byte\n\t\textIPs                 []netip.Addr\n\t\tsetupState             func(t *testing.T, ctx context.Context, st state.State)\n\t\texpectedNeedsReconcile bool\n\t\texpected               string\n\t\tcheckResult            func(t *testing.T, cfg *runtime.PlatformNetworkConfig)\n\t}{\n\t\t{\n\t\t\tname:         \"full config\",\n\t\t\tnetworkJSON:  rawNetwork,\n\t\t\tmetadataJSON: rawMetadata,\n\t\t\textIPs:       []netip.Addr{netip.MustParseAddr(\"1.2.3.4\")},\n\t\t\tsetupState: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t\t\t\teth0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xa4, 0xbf, 0x00, 0x10, 0x20, 0x30}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth0))\n\n\t\t\t\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\t\t\t\teth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xa4, 0xbf, 0x00, 0x10, 0x20, 0x31}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth1))\n\n\t\t\t\teth2 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\t\t\t\teth2.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0xa4, 0xbf, 0x00, 0x10, 0x20, 0x33}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth2))\n\n\t\t\t\teth3 := network.NewLinkStatus(network.NamespaceName, \"eth3\")\n\t\t\t\teth3.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x4c, 0xd9, 0x8f, 0xb3, 0x34, 0xf8}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth3))\n\n\t\t\t\teth4 := network.NewLinkStatus(network.NamespaceName, \"eth4\")\n\t\t\t\teth4.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x4c, 0xd9, 0x8f, 0xb3, 0x34, 0xf7}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth4))\n\t\t\t},\n\t\t\texpected: expectedNetworkConfig,\n\t\t},\n\t\t{\n\t\t\tname:        \"HardwareAddr fallback\",\n\t\t\tnetworkJSON: []byte(`{\"links\":[{\"id\":\"iface1\",\"type\":\"phy\",\"ethernet_mac_address\":\"aa:bb:cc:dd:ee:ff\",\"mtu\":1500}],\"networks\":[{\"id\":\"net1\",\"link\":\"iface1\",\"type\":\"ipv4_dhcp\"}]}`),\n\t\t\tsetupState: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t\t\t\teth0.TypedSpec().HardwareAddr = nethelpers.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth0))\n\t\t\t},\n\t\t\tcheckResult: func(t *testing.T, cfg *runtime.PlatformNetworkConfig) {\n\t\t\t\trequire.Len(t, cfg.Links, 1)\n\t\t\t\tassert.Equal(t, \"eth0\", cfg.Links[0].Name)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"empty MAC does not match\",\n\t\t\tnetworkJSON: []byte(`{\"links\":[{\"id\":\"iface1\",\"type\":\"phy\",\"ethernet_mac_address\":\"\",\"mtu\":1500}],\"networks\":[{\"id\":\"net1\",\"link\":\"iface1\",\"type\":\"ipv4_dhcp\"}]}`),\n\t\t\tsetupState: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth0))\n\t\t\t},\n\t\t\texpectedNeedsReconcile: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"MAC mismatch triggers reconcile\",\n\t\t\tnetworkJSON: []byte(`{\"links\":[{\"id\":\"iface1\",\"type\":\"phy\",\"ethernet_mac_address\":\"aa:bb:cc:dd:ee:ff\",\"mtu\":1500}],\"networks\":[{\"id\":\"net1\",\"link\":\"iface1\",\"type\":\"ipv4_dhcp\"}]}`),\n\t\t\tsetupState: func(t *testing.T, ctx context.Context, st state.State) {\n\t\t\t\teth0 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\t\t\t\teth0.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}\n\t\t\t\trequire.NoError(t, st.Create(ctx, eth0))\n\t\t\t},\n\t\t\texpectedNeedsReconcile: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx := t.Context()\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\ttt.setupState(t, ctx, st)\n\n\t\t\tvar (\n\t\t\t\tmetadata openstack.MetadataConfig\n\t\t\t\tn        openstack.NetworkConfig\n\t\t\t)\n\n\t\t\tif tt.metadataJSON != nil {\n\t\t\t\trequire.NoError(t, json.Unmarshal(tt.metadataJSON, &metadata))\n\t\t\t}\n\n\t\t\trequire.NoError(t, json.Unmarshal(tt.networkJSON, &n))\n\n\t\t\to := &openstack.OpenStack{}\n\n\t\t\tnetworkConfig, needsReconcile, err := o.ParseMetadata(ctx, &n, tt.extIPs, &metadata, st)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expectedNeedsReconcile, needsReconcile)\n\n\t\t\tif tt.expected != \"\" {\n\t\t\t\tmarshaled, err := yaml.Marshal(networkConfig)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, tt.expected, string(marshaled))\n\t\t\t}\n\n\t\t\tif tt.checkResult != nil {\n\t\t\t\ttt.checkResult(t, networkConfig)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/testdata/expected.yaml",
    "content": "addresses:\n    - address: 2000:0:100::/56\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.184.0.244/20\n      linkName: eth1\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2001:db8::3257:9652/64\n      linkName: eth1\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: fd60:172:16:84:f816:3eff:fe73:5901/64\n      linkName: eth2\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 94.156.45.48/24\n      linkName: bond0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: bond0\n      logical: true\n      up: true\n      mtu: 1500\n      kind: bond\n      type: ether\n      hardwareAddr: 4c:d9:8f:b3:34:f7\n      bondMaster:\n        mode: 802.3ad\n        xmitHashPolicy: layer2+3\n        lacpRate: fast\n        arpValidate: none\n        arpAllTargets: any\n        primaryReselect: always\n        failOverMac: none\n        miimon: 100\n        updelay: 200\n        downdelay: 200\n        resendIgmp: 1\n        lpInterval: 1\n        packetsPerSlave: 1\n        numPeerNotif: 1\n        tlbLogicalLb: 1\n        useCarrier: true\n        adActorSysPrio: 65535\n        adLacpActive: \"on\"\n      layer: platform\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 1450\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 9000\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth3\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      layer: platform\n    - name: eth4\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      masterName: bond0\n      slaveIndex: 1\n      layer: platform\n    - name: bond0.100\n      logical: true\n      up: true\n      mtu: 1400\n      kind: vlan\n      type: ether\n      parentName: bond0\n      vlan:\n        vlanID: 100\n        vlanProtocol: 802.1q\n      layer: platform\nroutes:\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: 2000:0:100:2fff:ff:ff:ff:ff\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: 2000:0:100:2f00::/58\n      src: \"\"\n      gateway: 2000:0:100:2fff:ff:ff:ff:f0\n      outLinkName: eth0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: 192.168.0.0/16\n      src: \"\"\n      gateway: 10.184.0.1\n      outLinkName: eth1\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 10.184.0.1\n      outLinkName: eth1\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fd00::1\n      outLinkName: eth1\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 94.156.45.1\n      outLinkName: bond0\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 8.8.8.8\n        - 1.1.1.1\n      layer: platform\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n        skipHostnameRequest: true\n      layer: platform\n    - operator: dhcp6\n      linkName: eth2\n      requireUp: true\n      dhcp6:\n        routeMetric: 2048\n        skipHostnameRequest: true\n      layer: platform\n    - operator: dhcp4\n      linkName: bond0.100\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n        skipHostnameRequest: true\n      layer: platform\nexternalIPs:\n    - 1.2.3.4\nmetadata:\n    platform: openstack\n    hostname: talos\n    zone: nova\n    instanceId: 39073b0a-1234-1234-1234-5e76a4bd64b2\n    providerId: openstack:///39073b0a-1234-1234-1234-5e76a4bd64b2\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/testdata/metadata.json",
    "content": "{\n    \"availability_zone\": \"nova\",\n    \"devices\": [],\n    \"hostname\": \"talos\",\n    \"keys\": [],\n    \"launch_index\": 0,\n    \"name\": \"talos\",\n    \"project_id\": \"39073b0a-1234-1234-1234-5e76a4bd64b2\",\n    \"public_keys\": {},\n    \"uuid\": \"39073b0a-1234-1234-1234-5e76a4bd64b2\"\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/openstack/testdata/network.json",
    "content": "{\n    \"links\": [\n        {\n            \"ethernet_mac_address\": \"A4:BF:00:10:20:30\",\n            \"id\": \"aae16046-6c74-4f33-acf2-a16e9ab093eb\",\n            \"type\": \"phy\",\n            \"mtu\": 1450,\n            \"vif_id\": \"7607af2d-c24d-4bfb-909e-c447b119f4e2\"\n        },\n        {\n            \"ethernet_mac_address\": \"A4:BF:00:10:20:31\",\n            \"id\": \"aae16046-6c74-4f33-acf2-a16e9ab093ec\",\n            \"type\": \"ovs\",\n            \"mtu\": 9000,\n            \"vif_id\": \"c816df7e-7bcc-45ca-9eb2-3d3d3dca0639\"\n        },\n        {\n            \"ethernet_mac_address\": \"A4:BF:00:10:20:33\",\n            \"id\": \"aae16046-6c74-4f33-acf2-a16e9ab093ed\",\n            \"type\": \"vif\",\n            \"vif_id\": \"c816df7e-7bcc-45ca-9eb2-3d3d3dca063a\"\n        },\n        {\n            \"id\": \"tap7819ff08-20\",\n            \"vif_id\": \"7819ff08-204b-4193-8c4d-1fff242932e5\",\n            \"type\": \"bond\",\n            \"mtu\": 1500,\n            \"ethernet_mac_address\": \"4c:d9:8f:b3:34:f7\",\n            \"bond_mode\": \"802.3ad\",\n            \"bond_links\": [\n                \"411f3980-d8f9-4bf0-a09a-9c01c81e1022\",\n                \"83f59825-bf2d-4ea7-98be-edc772fe82de\"\n            ],\n            \"bond_miimon\": \"100\",\n            \"bond_xmit_hash_policy\": \"layer2+3\"\n        },\n        {\n            \"id\": \"411f3980-d8f9-4bf0-a09a-9c01c81e1022\",\n            \"type\": \"bridge\",\n            \"ethernet_mac_address\": \"4c:d9:8f:b3:34:f8\"\n        },\n        {\n            \"id\": \"83f59825-bf2d-4ea7-98be-edc772fe82de\",\n            \"type\": \"phy\",\n            \"ethernet_mac_address\": \"4c:d9:8f:b3:34:f7\"\n        },\n        {\n            \"id\": \"vlan-interface-001\",\n            \"vif_id\": \"acf55ef1-9a79-4c59-bec7-1ebf01a9a918\",\n            \"type\": \"vlan\",\n            \"mtu\": 1400,\n            \"vlan_mac_address\": null,\n            \"vlan_link\": \"tap7819ff08-20\",\n            \"vlan_id\": 100\n        }\n    ],\n    \"networks\": [\n        {\n            \"id\": \"publicnet-ipv4\",\n            \"link\": \"aae16046-6c74-4f33-acf2-a16e9ab093eb\",\n            \"network_id\": \"66374c4d-5123-4f11-8fa9-8a6dea2b4fe7\",\n            \"type\": \"ipv4_dhcp\"\n        },\n        {\n            \"routes\": [\n                {\n                    \"network\": \"2000:0:100:2f00::\",\n                    \"gateway\": \"2000:0:100:2fff:ff:ff:ff:f0\",\n                    \"netmask\": \"ffff:ffff:ffff:ffc0::\"\n                }\n            ],\n            \"dns_nameservers\": [\n                \"2000:0:100::1\"\n            ],\n            \"gateway\": \"2000:0:100:2fff:ff:ff:ff:ff\",\n            \"link\": \"aae16046-6c74-4f33-acf2-a16e9ab093eb\",\n            \"ip_address\": \"2000:0:100::/56\",\n            \"network_id\": \"39b48637-d98a-4dfc-a05b-d61e8d88fafe\",\n            \"id\": \"publicnet-ipv6\",\n            \"type\": \"ipv6\"\n        },\n        {\n            \"id\": \"privatnet-ipv4\",\n            \"link\": \"aae16046-6c74-4f33-acf2-a16e9ab093ec\",\n            \"network_id\": \"66374c4d-5123-4f11-8fa9-8a6dea2b4fe7\",\n            \"type\": \"ipv4\",\n            \"ip_address\": \"10.184.0.244\",\n            \"netmask\": \"255.255.240.0\",\n            \"routes\": [\n                {\n                    \"network\": \"192.168.0.0\",\n                    \"netmask\": \"255.255.0.0\",\n                    \"gateway\": \"10.184.0.1\"\n                },\n                {\n                    \"network\": \"0.0.0.0\",\n                    \"netmask\": \"0.0.0.0\",\n                    \"gateway\": \"10.184.0.1\"\n                }\n            ]\n        },\n        {\n            \"id\": \"privatnet-ipv6\",\n            \"link\": \"aae16046-6c74-4f33-acf2-a16e9ab093ec\",\n            \"network_id\": \"66374c4d-5123-4f11-8fa9-8a6dea2b4fe7\",\n            \"type\": \"ipv6\",\n            \"ip_address\": \"2001:db8::3257:9652\",\n            \"netmask\": \"ffff:ffff:ffff:ffff::\",\n            \"routes\": [\n                {\n                    \"network\": \"::\",\n                    \"netmask\": \"::\",\n                    \"gateway\": \"fd00::1\"\n                }\n            ]\n        },\n        {\n            \"id\": \"privatnet-ipv6-2\",\n            \"link\": \"aae16046-6c74-4f33-acf2-a16e9ab093ed\",\n            \"network_id\": \"66374c4d-5123-4f11-8fa9-8a6dea2b4fe7\",\n            \"type\": \"ipv6_dhcpv6-stateless\",\n            \"ip_address\": \"fd60:172:16:84:f816:3eff:fe73:5901\",\n            \"netmask\": \"ffff:ffff:ffff:ffff::\",\n            \"routes\": []\n        },\n        {\n            \"id\": \"network0\",\n            \"type\": \"ipv4\",\n            \"link\": \"tap7819ff08-20\",\n            \"ip_address\": \"94.156.45.48\",\n            \"netmask\": \"255.255.255.0\",\n            \"routes\": [\n                {\n                    \"network\": \"0.0.0.0\",\n                    \"netmask\": \"0.0.0.0\",\n                    \"gateway\": \"94.156.45.1\"\n                }\n            ],\n            \"network_id\": \"dc4b2e65-869b-46b1-b53b-538774dbdc16\",\n            \"services\": [\n                {\n                    \"type\": \"dns\",\n                    \"address\": \"8.8.8.8\"\n                },\n                {\n                    \"type\": \"dns\",\n                    \"address\": \"8.8.4.4\"\n                }\n            ]\n        },\n        {\n            \"id\": \"vlan-network\",\n            \"type\": \"ipv4_dhcp\",\n            \"link\": \"vlan-interface-001\",\n            \"network_id\": \"5ee412a7-13c5-4306-ad4d-85c06241e5f4\"\n        }\n    ],\n    \"services\": [\n        {\n            \"address\": \"8.8.8.8\",\n            \"type\": \"dns\"\n        },\n        {\n            \"address\": \"1.1.1.1\",\n            \"type\": \"dns\"\n        }\n    ]\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage oracle\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\n// Ref: https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/gettingmetadata.htm\nconst (\n\t// OracleMetadataEndpoint is the local metadata endpoint for the hostname.\n\tOracleMetadataEndpoint = \"http://169.254.169.254/opc/v2/instance/\"\n\t// OracleUserDataEndpoint is the local metadata endpoint inside of Oracle Cloud.\n\tOracleUserDataEndpoint = \"http://169.254.169.254/opc/v2/instance/metadata/user_data\"\n\t// OracleNetworkEndpoint is the local network metadata endpoint inside of Oracle Cloud.\n\tOracleNetworkEndpoint = \"http://169.254.169.254/opc/v2/vnics/\"\n\n\toracleResolverServer = \"169.254.169.254\"\n\toracleTimeServer     = \"169.254.169.254\"\n)\n\n// MetadataConfig represents a metadata Oracle instance.\ntype MetadataConfig struct {\n\tHostname           string `json:\"hostname,omitempty\"`\n\tID                 string `json:\"id,omitempty\"`\n\tRegion             string `json:\"region,omitempty\"`\n\tAvailabilityDomain string `json:\"availabilityDomain,omitempty\"`\n\tFaultDomain        string `json:\"faultDomain,omitempty\"`\n\tShape              string `json:\"shape,omitempty\"`\n}\n\nfunc (o *Oracle) getMetadata(ctx context.Context) (*MetadataConfig, error) {\n\tmetaConfigDl, err := download.Download(ctx, OracleMetadataEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Authorization\": \"Bearer Oracle\"}),\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoHostname),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoHostname))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching metadata: %w\", err)\n\t}\n\n\tvar meta MetadataConfig\n\tif err = json.Unmarshal(metaConfigDl, &meta); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &meta, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/oracle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package oracle provides the Oracle platform implementation.\npackage oracle\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NetworkConfig holds network interface meta config.\ntype NetworkConfig struct {\n\tHWAddr              string   `json:\"macAddr\"`\n\tPrivateIP           string   `json:\"privateIp\"`\n\tVirtualRouterIP     string   `json:\"virtualRouterIp\"`\n\tSubnetCidrBlock     string   `json:\"subnetCidrBlock\"`\n\tIpv6SubnetCidrBlock string   `json:\"ipv6SubnetCidrBlock,omitempty\"`\n\tIpv6VirtualRouterIP string   `json:\"ipv6VirtualRouterIp,omitempty\"`\n\tIpv6Addresses       []string `json:\"ipv6Addresses,omitempty\"`\n}\n\n// Oracle is the concrete type that implements the platform.Platform interface.\ntype Oracle struct{}\n\n// Name implements the platform.Platform interface.\nfunc (o *Oracle) Name() string {\n\treturn \"oracle\"\n}\n\n// ParseMetadata converts Oracle Cloud metadata into platform network configuration.\nfunc (o *Oracle) ParseMetadata(interfaceAddresses []NetworkConfig, metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tfor idx, iface := range interfaceAddresses {\n\t\tifname := fmt.Sprintf(\"eth%d\", idx)\n\n\t\tif iface.Ipv6SubnetCidrBlock != \"\" && iface.Ipv6VirtualRouterIP != \"\" {\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\tLinkName:  ifname,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\n\t\t\tgw, err := netip.ParseAddr(iface.Ipv6VirtualRouterIP)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: ifname,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\t}\n\n\tdns, _ := netip.ParseAddr(oracleResolverServer) //nolint:errcheck\n\n\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\tDNSServers:  []netip.Addr{dns},\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tnetworkConfig.TimeServers = append(networkConfig.TimeServers, network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{oracleTimeServer},\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tzone := metadata.AvailabilityDomain\n\n\tif idx := strings.LastIndex(zone, \":\"); idx != -1 {\n\t\tzone = zone[idx+1:]\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     o.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       metadata.Region,\n\t\tZone:         zone,\n\t\tInstanceType: metadata.Shape,\n\t\tInstanceID:   metadata.ID,\n\t\tProviderID:   fmt.Sprintf(\"oci://%s\", metadata.ID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the platform.Platform interface.\nfunc (o *Oracle) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", OracleUserDataEndpoint)\n\n\tmachineConfigDl, err := download.Download(ctx, OracleUserDataEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Authorization\": \"Bearer Oracle\"}),\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmachineConfig, err := base64.StdEncoding.DecodeString(string(machineConfigDl))\n\tif err != nil {\n\t\treturn nil, errors.ErrNoConfigSource\n\t}\n\n\treturn machineConfig, nil\n}\n\n// Mode implements the platform.Platform interface.\nfunc (o *Oracle) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (o *Oracle) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\tprocfs.NewParameter(constants.KernelParamDashboardDisabled).Append(\"1\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (o *Oracle) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching oracle metadata from: %q\", OracleMetadataEndpoint)\n\n\tmetadata, err := o.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlog.Printf(\"fetching network config from %q\", OracleNetworkEndpoint)\n\n\tmetadataNetworkConfigDl, err := download.Download(ctx, OracleNetworkEndpoint,\n\t\tdownload.WithHeaders(map[string]string{\"Authorization\": \"Bearer Oracle\"}))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch network config from: %w\", err)\n\t}\n\n\tvar interfaceAddresses []NetworkConfig\n\n\tif err = json.Unmarshal(metadataNetworkConfigDl, &interfaceAddresses); err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := o.ParseMetadata(interfaceAddresses, metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/oracle_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage oracle_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/oracle\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/metadatanetwork.json\nvar rawMetadataNetwork []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &oracle.Oracle{}\n\n\tvar metadata oracle.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\tvar m []oracle.NetworkConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadataNetwork, &m))\n\n\tnetworkConfig, err := p.ParseMetadata(m, &metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/testdata/expected.yaml",
    "content": "addresses: []\nlinks: []\nroutes:\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::a:b:c:d\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 169.254.169.254\n      layer: platform\ntimeServers:\n    - timeServers:\n        - 169.254.169.254\n      layer: platform\noperators:\n    - operator: dhcp6\n      linkName: eth0\n      requireUp: true\n      dhcp6:\n        routeMetric: 1024\n      layer: platform\nexternalIPs: []\nmetadata:\n    platform: oracle\n    hostname: talos\n    region: phx\n    zone: PHX-AD-1\n    instanceType: VM.Standard.E3.Flex\n    instanceId: ocid1.instance.oc1.phx.exampleuniqueID\n    providerId: oci://ocid1.instance.oc1.phx.exampleuniqueID\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/testdata/metadata.json",
    "content": "{\n    \"availabilityDomain\": \"EMIr:PHX-AD-1\",\n    \"faultDomain\": \"FAULT-DOMAIN-3\",\n    \"compartmentId\": \"ocid1.tenancy.oc1..exampleuniqueID\",\n    \"displayName\": \"talos-instance\",\n    \"hostname\": \"talos\",\n    \"id\": \"ocid1.instance.oc1.phx.exampleuniqueID\",\n    \"image\": \"ocid1.image.oc1.phx.exampleuniqueID\",\n    \"metadata\": {},\n    \"region\": \"phx\",\n    \"canonicalRegionName\": \"us-phoenix-1\",\n    \"ociAdName\": \"phx-ad-1\",\n    \"regionInfo\": {\n        \"realmKey\": \"oc1\",\n        \"realmDomainComponent\": \"oraclecloud.com\",\n        \"regionKey\": \"PHX\",\n        \"regionIdentifier\": \"us-phoenix-1\"\n    },\n    \"shape\": \"VM.Standard.E3.Flex\",\n    \"state\": \"Running\",\n    \"timeCreated\": 1600381928581,\n    \"agentConfig\": {\n        \"monitoringDisabled\": false,\n        \"managementDisabled\": false,\n        \"allPluginsDisabled\": false,\n        \"pluginsConfig\": [\n            {\n                \"name\": \"OS Management Service Agent\",\n                \"desiredState\": \"ENABLED\"\n            },\n            {\n                \"name\": \"Custom Logs Monitoring\",\n                \"desiredState\": \"ENABLED\"\n            },\n            {\n                \"name\": \"Compute Instance Run Command\",\n                \"desiredState\": \"ENABLED\"\n            },\n            {\n                \"name\": \"Compute Instance Monitoring\",\n                \"desiredState\": \"ENABLED\"\n            }\n        ]\n    },\n    \"freeformTags\": {\n        \"Department\": \"Finance\"\n    },\n    \"definedTags\": {\n        \"Operations\": {\n            \"CostCenter\": \"42\"\n        }\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/oracle/testdata/metadatanetwork.json",
    "content": "[\n    {\n        \"vnicId\": \"ocid1.vnic.oc1.eu-amsterdam-1.asdasd\",\n        \"privateIp\": \"172.16.1.11\",\n        \"vlanTag\": 1,\n        \"macAddr\": \"02:00:17:00:00:00\",\n        \"virtualRouterIp\": \"172.16.1.1\",\n        \"subnetCidrBlock\": \"172.16.1.0/24\",\n        \"ipv6SubnetCidrBlock\": \"2603:a:b:c::/64\",\n        \"ipv6VirtualRouterIp\": \"fe80::a:b:c:d\",\n        \"ipv6Addresses\": [\n            \"2603:a:b:c::1234\"\n        ]\n    }\n]"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/platform.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package platform provides functions to get the [runtime.Platform].\npackage platform\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/akamai\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/aws\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/azure\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/cloudstack\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/container\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/digitalocean\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/equinixmetal\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/exoscale\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/gcp\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/hcloud\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/metal\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/opennebula\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/openstack\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/oracle\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/vultr\"\n\t\"github.com/siderolabs/talos/internal/pkg/containermode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Event is a struct used below in FireEvent\n// in hopes that we can reuse some of this eventing in other platforms if possible.\ntype Event struct {\n\tType    string\n\tMessage string\n\tError   error\n}\n\n// nb: these events currently map to those expected by\n// equinix metal. if/when we do other platforms, we should\n// maybe generalize this and map the events inside each platform.\nconst (\n\t// EventTypeActivate is the activate event string.\n\tEventTypeActivate = \"activate\"\n\t// EventTypeFailure is the failure event string.\n\tEventTypeFailure = \"failure\"\n\t// EventTypeInfo is the info event string.\n\tEventTypeInfo = \"info\"\n\t// EventTypeConfigLoaded is the config loaded event string.\n\tEventTypeConfigLoaded = \"talos.prov.config.loaded\"\n\t// EventTypeRebooted is the reboot event string.\n\tEventTypeRebooted = \"talos.prov.host.rebooted\"\n\t// EventTypeInstalled is the installation event string.\n\tEventTypeInstalled = \"talos.prov.os.installed\"\n\t// EventTypeUpgraded is the upgrade event string.\n\tEventTypeUpgraded = \"talos.prov.os.upgraded\"\n)\n\n// CurrentPlatform is a helper func for discovering the current platform.\nfunc CurrentPlatform() (p runtime.Platform, err error) {\n\tif containermode.InContainer() {\n\t\treturn newPlatform(\"container\")\n\t}\n\n\tvar platform string\n\n\tif p := procfs.ProcCmdline().Get(constants.KernelParamPlatform).First(); p != nil {\n\t\tplatform = *p\n\t}\n\n\tif p, ok := os.LookupEnv(\"PLATFORM\"); ok {\n\t\tplatform = p\n\t}\n\n\tif platform == \"\" {\n\t\treturn nil, errors.New(\"failed to determine platform\")\n\t}\n\n\treturn newPlatform(platform)\n}\n\n// NewPlatform initializes and returns a runtime.Platform.\nfunc NewPlatform(platform string) (p runtime.Platform, err error) {\n\treturn newPlatform(platform)\n}\n\n//nolint:gocyclo,cyclop\nfunc newPlatform(platform string) (p runtime.Platform, err error) {\n\tswitch platform {\n\tcase \"akamai\":\n\t\tp = &akamai.Akamai{}\n\tcase \"aws\":\n\t\treturn aws.NewAWS()\n\tcase \"azure\":\n\t\tp = &azure.Azure{}\n\tcase \"cloudstack\":\n\t\tp = &cloudstack.Cloudstack{}\n\tcase \"container\":\n\t\tp = &container.Container{}\n\tcase \"digital-ocean\":\n\t\tp = &digitalocean.DigitalOcean{}\n\tcase \"gcp\":\n\t\tp = &gcp.GCP{}\n\tcase \"hcloud\":\n\t\tp = &hcloud.Hcloud{}\n\tcase constants.PlatformMetal:\n\t\t_, metalAgentCheckErr := os.Stat(constants.MetalAgentModeFlagPath)\n\n\t\tp = &metal.Metal{\n\t\t\tIsAgent: metalAgentCheckErr == nil,\n\t\t}\n\tcase \"opennebula\":\n\t\tp = &opennebula.OpenNebula{}\n\tcase \"openstack\":\n\t\tp = &openstack.OpenStack{}\n\tcase \"oracle\":\n\t\tp = &oracle.Oracle{}\n\tcase \"nocloud\":\n\t\tp = &nocloud.Nocloud{}\n\t// \"packet\" kept for backwards compatibility\n\tcase \"equinixMetal\", \"packet\":\n\t\tp = &equinixmetal.EquinixMetal{}\n\tcase \"exoscale\":\n\t\tp = &exoscale.Exoscale{}\n\tcase \"scaleway\":\n\t\tp = &scaleway.Scaleway{}\n\tcase \"upcloud\":\n\t\tp = &upcloud.UpCloud{}\n\tcase \"vmware\":\n\t\tp = &vmware.VMware{}\n\tcase \"vultr\":\n\t\tp = &vultr.Vultr{}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown platform: %q\", platform)\n\t}\n\n\treturn p, nil\n}\n\n// FireEvent will call the implemented platform's event function if we know it has one.\n// Error logging is handled in this function and we don't return any error values to the sequencer.\nfunc FireEvent(ctx context.Context, p runtime.Platform, e Event) {\n\tswitch platType := p.(type) {\n\tcase *equinixmetal.EquinixMetal:\n\t\temEvent := equinixmetal.Event{\n\t\t\tType:    e.Type,\n\t\t\tMessage: e.Message,\n\t\t}\n\n\t\tif e.Error != nil {\n\t\t\temEvent.Message = fmt.Sprintf(\"%s: %s\", e.Message, e.Error)\n\t\t}\n\n\t\teventErr := platType.FireEvent(ctx, emEvent)\n\t\tif eventErr != nil {\n\t\t\tlog.Printf(\"failed sending event: %s\", eventErr)\n\t\t}\n\n\tdefault:\n\t\t// Treat anything else as a no-op b/c we don't support event firing\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage scaleway\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/scaleway/scaleway-sdk-go/api/instance/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// ScalewayMetadataEndpoint is the local Scaleway endpoint.\n\tScalewayMetadataEndpoint = \"http://169.254.42.42/conf?format=json\"\n\t// ScalewayUserDataEndpoint is the local Scaleway endpoint for the config.\n\tScalewayUserDataEndpoint = \"http://169.254.42.42/user_data/cloud-init\"\n)\n\nfunc (u *Scaleway) getMetadata(ctx context.Context) (*instance.Metadata, error) {\n\tmetaConfigDl, err := download.Download(ctx, ScalewayMetadataEndpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching metadata: %w\", err)\n\t}\n\n\tvar meta instance.Metadata\n\tif err = json.Unmarshal(metaConfigDl, &meta); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &meta, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package scaleway provides the Scaleway platform implementation.\npackage scaleway\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/scaleway/scaleway-sdk-go/api/instance/v1\"\n\t\"github.com/scaleway/scaleway-sdk-go/scw\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Scaleway is the concrete type that implements the runtime.Platform interface.\ntype Scaleway struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (s *Scaleway) Name() string {\n\treturn \"scaleway\"\n}\n\n// ParseMetadata converts Scaleway platform metadata into platform network config.\n//\n//nolint:gocyclo\nfunc (s *Scaleway) ParseMetadata(metadata *instance.Metadata) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar publicIPs []string\n\n\tif metadata.PublicIP.Address != \"\" && metadata.PublicIP.Family == \"inet\" {\n\t\tpublicIPs = append(publicIPs, metadata.PublicIP.Address)\n\t}\n\n\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\tName:        \"eth0\",\n\t\tUp:          true,\n\t\tConfigLayer: network.ConfigPlatform,\n\t})\n\n\tgw, _ := netip.ParsePrefix(\"169.254.42.42/32\") //nolint:errcheck\n\troute := network.RouteSpecSpec{\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tOutLinkName: \"eth0\",\n\t\tDestination: gw,\n\t\tTable:       nethelpers.TableMain,\n\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\tType:        nethelpers.TypeUnicast,\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tPriority:    4 * network.DefaultRouteMetric,\n\t}\n\n\troute.Normalize()\n\tnetworkConfig.Routes = []network.RouteSpecSpec{route}\n\n\tif len(metadata.PublicIpsV4) > 0 {\n\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\tLinkName:  \"eth0\",\n\t\t\tRequireUp: true,\n\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t},\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tif metadata.IPv6.Address != \"\" || len(metadata.PublicIpsV6) > 0 {\n\t\taddress := metadata.IPv6.Address\n\t\tnetmask := metadata.IPv6.Netmask\n\t\tgateway := metadata.IPv6.Gateway\n\n\t\tif address == \"\" || netmask == \"\" || gateway == \"\" {\n\t\t\taddress = metadata.PublicIpsV6[0].Address\n\t\t\tnetmask = metadata.PublicIpsV6[0].Netmask\n\t\t\tgateway = metadata.PublicIpsV6[0].Gateway\n\t\t}\n\n\t\tbits, err := strconv.Atoi(netmask)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tip, err := netip.ParseAddr(address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\taddr := netip.PrefixFrom(ip, bits)\n\n\t\tpublicIPs = append(publicIPs, address)\n\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tLinkName:    \"eth0\",\n\t\t\t\tAddress:     addr,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t},\n\t\t)\n\n\t\tgw, err := netip.ParseAddr(gateway)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\troute := network.RouteSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\tGateway:     gw,\n\t\t\tOutLinkName: \"eth0\",\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t}\n\n\t\troute.Normalize()\n\n\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tzone, err := scw.ParseZone(metadata.Location.ZoneID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tregion, err := zone.Region()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:     s.Name(),\n\t\tHostname:     metadata.Hostname,\n\t\tRegion:       region.String(),\n\t\tZone:         zone.String(),\n\t\tInstanceType: metadata.CommercialType,\n\t\tInstanceID:   metadata.ID,\n\t\tProviderID:   fmt.Sprintf(\"scaleway://instance/%s/%s\", zone.String(), metadata.ID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the runtime.Platform interface.\n//\n//nolint:stylecheck\nfunc (s *Scaleway) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from %q\", ScalewayUserDataEndpoint)\n\n\treturn download.Download(ctx, ScalewayUserDataEndpoint,\n\t\tdownload.WithLowSrcPort(),\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (s *Scaleway) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (s *Scaleway) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(\"console\").Append(\"tty1\").Append(\"ttyS0\"),\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\tprocfs.NewParameter(constants.KernelParamDashboardDisabled).Append(\"1\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (s *Scaleway) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching scaleway instance config from: %q\", ScalewayMetadataEndpoint)\n\n\tmetadata, err := s.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := s.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/scaleway_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage scaleway_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/scaleway/scaleway-sdk-go/api/instance/v1\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway\"\n)\n\n//go:embed testdata/metadata-v1.json\nvar rawMetadataV1 []byte\n\n//go:embed testdata/metadata-v2.json\nvar rawMetadataV2 []byte\n\n//go:embed testdata/metadata-v3.json\nvar rawMetadataV3 []byte\n\n//go:embed testdata/expected-v1.yaml\nvar expectedNetworkConfigV1 string\n\n//go:embed testdata/expected-v2.yaml\nvar expectedNetworkConfigV2 string\n\n//go:embed testdata/expected-v3.yaml\nvar expectedNetworkConfigV3 string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &scaleway.Scaleway{}\n\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\traw      []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"V1\",\n\t\t\traw:      rawMetadataV1,\n\t\t\texpected: expectedNetworkConfigV1,\n\t\t},\n\t\t{\n\t\t\tname:     \"V2\",\n\t\t\traw:      rawMetadataV2,\n\t\t\texpected: expectedNetworkConfigV2,\n\t\t},\n\t\t{\n\t\t\tname:     \"V3\",\n\t\t\traw:      rawMetadataV3,\n\t\t\texpected: expectedNetworkConfigV3,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar metadata instance.Metadata\n\n\t\t\trequire.NoError(t, json.Unmarshal(tt.raw, &metadata))\n\n\t\t\tnetworkConfig, err := p.ParseMetadata(&metadata)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmarshaled, err := yaml.Marshal(networkConfig)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expected, string(marshaled))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/expected-v1.yaml",
    "content": "addresses:\n    - address: 2001:111:222:3333::1/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: 169.254.42.42/32\n      src: \"\"\n      gateway: \"\"\n      outLinkName: eth0\n      table: main\n      priority: 4096\n      scope: link\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: '2001:111:222:3333::'\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: scw-talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs:\n    - 11.22.222.222\n    - 2001:111:222:3333::1\nmetadata:\n    platform: scaleway\n    hostname: scw-talos\n    region: fr-par\n    zone: fr-par-1\n    instanceType: DEV1-S\n    instanceId: 11111111-1111-1111-1111-111111111111\n    providerId: scaleway://instance/fr-par-1/11111111-1111-1111-1111-111111111111\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/expected-v2.yaml",
    "content": "addresses:\n    - address: 2001:111:222:3333::1/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: 169.254.42.42/32\n      src: \"\"\n      gateway: \"\"\n      outLinkName: eth0\n      table: main\n      priority: 4096\n      scope: link\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::dc00:ff:fe12:3456\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: scw-talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs:\n    - 11.22.222.222\n    - 2001:111:222:3333::1\nmetadata:\n    platform: scaleway\n    hostname: scw-talos\n    region: fr-par\n    zone: fr-par-2\n    instanceType: DEV1-S\n    instanceId: 11111111-1111-1111-1111-111111111111\n    providerId: scaleway://instance/fr-par-2/11111111-1111-1111-1111-111111111111\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/expected-v3.yaml",
    "content": "addresses:\n    - address: 2001:111:222:3333::1/64\n      linkName: eth0\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: 169.254.42.42/32\n      src: \"\"\n      gateway: \"\"\n      outLinkName: eth0\n      table: main\n      priority: 4096\n      scope: link\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\n    - family: inet6\n      dst: \"\"\n      src: \"\"\n      gateway: fe80::dc00:ff:fe12:3456\n      outLinkName: eth0\n      table: main\n      priority: 2048\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: scw-talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 2001:111:222:3333::1\nmetadata:\n    platform: scaleway\n    hostname: scw-talos\n    region: nl-ams\n    zone: nl-ams-1\n    instanceType: DEV1-S\n    instanceId: 11111111-1111-1111-1111-111111111111\n    providerId: scaleway://instance/nl-ams-1/11111111-1111-1111-1111-111111111111\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/metadata-v1.json",
    "content": "{\n    \"id\": \"11111111-1111-1111-1111-111111111111\",\n    \"name\": \"scw-talos\",\n    \"commercial_type\": \"DEV1-S\",\n    \"hostname\": \"scw-talos\",\n    \"tags\": [],\n    \"state_detail\": \"booted\",\n    \"public_ip\": {\n        \"id\": \"11111111-1111-1111-1111-111111111111\",\n        \"address\": \"11.22.222.222\",\n        \"dynamic\": false,\n        \"family\": \"inet\"\n    },\n    \"public_ips_v4\": [\n        {\n            \"address\": \"11.22.222.222\",\n            \"dynamic\": false,\n            \"family\": \"inet\",\n            \"gateway\": null,\n            \"id\": \"11111111-1111-1111-1111-111111111111\",\n            \"ipam_id\": null,\n            \"netmask\": \"32\",\n            \"provisioning_mode\": \"dhcp\",\n            \"state\": \"detached\",\n            \"tags\": []\n        }\n    ],\n    \"public_ips_v6\": [],\n    \"private_ip\": \"10.00.222.222\",\n    \"ipv6\": {\n        \"address\": \"2001:111:222:3333::1\",\n        \"gateway\": \"2001:111:222:3333::\",\n        \"netmask\": \"64\"\n    },\n    \"location\": {\n        \"zone_id\": \"fr-par-1\"\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/metadata-v2.json",
    "content": "{\n    \"id\": \"11111111-1111-1111-1111-111111111111\",\n    \"name\": \"scw-talos\",\n    \"commercial_type\": \"DEV1-S\",\n    \"hostname\": \"scw-talos\",\n    \"tags\": [],\n    \"state_detail\": \"booted\",\n    \"public_ip\": {\n        \"id\": \"11111111-1111-1111-1111-111111111111\",\n        \"address\": \"11.22.222.222\",\n        \"dynamic\": false,\n        \"family\": \"inet\"\n    },\n    \"public_ips_v4\": [\n        {\n            \"address\": \"11.22.222.222\",\n            \"dynamic\": false,\n            \"family\": \"inet\",\n            \"gateway\": \"11.22.222.1\",\n            \"netmask\": \"32\"\n        }\n    ],\n    \"public_ips_v6\": [\n        {\n            \"address\": \"2001:111:222:3333::1\",\n            \"dynamic\": false,\n            \"family\": \"inet6\",\n            \"gateway\": \"fe80::dc00:ff:fe12:3456\",\n            \"netmask\": \"64\"\n        }\n    ],\n    \"location\": {\n        \"zone_id\": \"fr-par-2\"\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/scaleway/testdata/metadata-v3.json",
    "content": "{\n    \"id\": \"11111111-1111-1111-1111-111111111111\",\n    \"name\": \"scw-talos\",\n    \"commercial_type\": \"DEV1-S\",\n    \"hostname\": \"scw-talos\",\n    \"tags\": [],\n    \"state_detail\": \"booted\",\n    \"public_ip\": {\n        \"id\": \"11111111-1111-1111-1111-111111111111\",\n        \"address\": \"2001:111:222:3333::1\",\n        \"dynamic\": false\n    },\n    \"public_ips_v4\": [],\n    \"public_ips_v6\": [\n        {\n            \"address\": \"2001:111:222:3333::1\",\n            \"dynamic\": false,\n            \"family\": \"inet6\",\n            \"gateway\": \"fe80::dc00:ff:fe12:3456\",\n            \"netmask\": \"64\"\n        }\n    ],\n    \"location\": {\n        \"zone_id\": \"ams1\"\n    }\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage upcloud\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// UpCloudMetadataEndpoint is the local UpCloud endpoint.\n\tUpCloudMetadataEndpoint = \"http://169.254.169.254/metadata/v1.json\"\n\n\t// UpCloudUserDataEndpoint is the local UpCloud endpoint for the config.\n\tUpCloudUserDataEndpoint = \"http://169.254.169.254/metadata/v1/user_data\"\n)\n\n// MetadataConfig represents a metadata Upcloud instance.\ntype MetadataConfig struct {\n\tHostname   string   `json:\"hostname,omitempty\"`\n\tInstanceID string   `json:\"instance_id,omitempty\"`\n\tPublicKeys []string `json:\"public_keys,omitempty\"`\n\tZone       string   `json:\"region,omitempty\"`\n\tTags       []string `json:\"tags,omitempty\"`\n\n\tNetwork struct {\n\t\tInterfaces []struct {\n\t\t\tIndex       int `json:\"index,omitempty\"`\n\t\t\tIPAddresses []struct {\n\t\t\t\tAddress  string   `json:\"address,omitempty\"`\n\t\t\t\tDHCP     bool     `json:\"dhcp,omitempty\"`\n\t\t\t\tDNS      []string `json:\"dns,omitempty\"`\n\t\t\t\tFamily   string   `json:\"family,omitempty\"`\n\t\t\t\tFloating bool     `json:\"floating,omitempty\"`\n\t\t\t\tGateway  string   `json:\"gateway,omitempty\"`\n\t\t\t\tNetwork  string   `json:\"network,omitempty\"`\n\t\t\t} `json:\"ip_addresses,omitempty\"`\n\t\t\tMAC         string `json:\"mac,omitempty\"`\n\t\t\tNetworkType string `json:\"type,omitempty\"`\n\t\t\tNetworkID   string `json:\"network_id,omitempty\"`\n\t\t} `json:\"interfaces,omitempty\"`\n\t\tDNS []string `json:\"dns,omitempty\"`\n\t} `json:\"network\"`\n}\n\nfunc (u *UpCloud) getMetadata(ctx context.Context) (*MetadataConfig, error) {\n\tmetaConfigDl, err := download.Download(ctx, UpCloudMetadataEndpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching metadata: %w\", err)\n\t}\n\n\tvar meta MetadataConfig\n\tif err = json.Unmarshal(metaConfigDl, &meta); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &meta, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud/testdata/expected.yaml",
    "content": "addresses:\n    - address: 185.70.197.3/32\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 2a04:3544:8000:1000:0:1111:2222:3333/64\n      linkName: eth2\n      family: inet6\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet6\n      dst: 2a04:3544:8000:1000::/64\n      src: \"\"\n      gateway: 2a04:3544:8000:1000::1\n      outLinkName: eth2\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers:\n    - dnsServers:\n        - 94.237.127.9\n        - 94.237.40.9\n        - 2a04:3540:53::1\n        - 2a04:3544:53::1\n      layer: platform\ntimeServers: []\noperators:\n    - operator: dhcp4\n      linkName: eth0\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\n    - operator: dhcp4\n      linkName: eth1\n      requireUp: true\n      dhcp4:\n        routeMetric: 1024\n      layer: platform\nexternalIPs:\n    - 185.70.197.2\n    - 2a04:3544:8000:1000:0:1111:2222:3333\nmetadata:\n    platform: upcloud\n    hostname: talos\n    instanceId: 00123456-1111-2222-3333-123456789012\n    providerId: upcloud://00123456-1111-2222-3333-123456789012\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud/testdata/metadata.json",
    "content": "{\n    \"cloud_name\": \"upcloud\",\n    \"instance_id\": \"00123456-1111-2222-3333-123456789012\",\n    \"hostname\": \"talos\",\n    \"network\": {\n        \"interfaces\": [\n            {\n                \"index\": 1,\n                \"ip_addresses\": [\n                    {\n                        \"address\": \"185.70.197.2\",\n                        \"dhcp\": true,\n                        \"dns\": [\n                            \"94.237.127.9\",\n                            \"94.237.40.9\"\n                        ],\n                        \"family\": \"IPv4\",\n                        \"floating\": false,\n                        \"gateway\": \"185.70.196.1\",\n                        \"network\": \"185.70.196.0/22\"\n                    },\n                    {\n                        \"address\": \"185.70.197.3\",\n                        \"dhcp\": false,\n                        \"dns\": null,\n                        \"family\": \"IPv4\",\n                        \"floating\": true,\n                        \"gateway\": \"\",\n                        \"network\": \"185.70.197.3/32\"\n                    }\n                ],\n                \"mac\": \"5e:bf:5e:02:28:07\",\n                \"network_id\": \"035ef879-1111-2222-3333-123456789012\",\n                \"type\": \"public\"\n            },\n            {\n                \"index\": 2,\n                \"ip_addresses\": [\n                    {\n                        \"address\": \"10.11.0.2\",\n                        \"dhcp\": true,\n                        \"dns\": null,\n                        \"family\": \"IPv4\",\n                        \"floating\": false,\n                        \"gateway\": \"10.11.0.1\",\n                        \"network\": \"10.11.0.0/22\"\n                    }\n                ],\n                \"mac\": \"5e:bf:5e:02:cd:e0\",\n                \"network_id\": \"031c9f9c-1111-2222-3333-123456789012\",\n                \"type\": \"utility\"\n            },\n            {\n                \"index\": 3,\n                \"ip_addresses\": [\n                    {\n                        \"address\": \"2a04:3544:8000:1000:0000:1111:2222:3333\",\n                        \"dhcp\": false,\n                        \"dns\": [\n                            \"2a04:3540:53::1\",\n                            \"2a04:3544:53::1\"\n                        ],\n                        \"family\": \"IPv6\",\n                        \"floating\": false,\n                        \"gateway\": \"2a04:3544:8000:1000::1\",\n                        \"network\": \"2a04:3544:8000:1000::/64\"\n                    }\n                ],\n                \"mac\": \"5e:bf:5e:02:78:a4\",\n                \"network_id\": \"03b326a2-1111-2222-3333-123456789012\",\n                \"type\": \"public\"\n            }\n        ],\n        \"dns\": [\n            \"94.237.127.9\",\n            \"94.237.40.9\"\n        ]\n    },\n    \"storage\": {},\n    \"tags\": [],\n    \"user_data\": \"\",\n    \"vendor_data\": \"\"\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud/upcloud.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package upcloud provides the UpCloud platform implementation.\npackage upcloud\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// UpCloud is the concrete type that implements the runtime.Platform interface.\ntype UpCloud struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (u *UpCloud) Name() string {\n\treturn \"upcloud\"\n}\n\n// ParseMetadata converts Upcloud metadata into platform network configuration.\n//\n//nolint:gocyclo\nfunc (u *UpCloud) ParseMetadata(metadata *MetadataConfig) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar (\n\t\tpublicIPs []string\n\t\tdnsIPs    []netip.Addr\n\t)\n\n\tfirstIP := true\n\n\tfor _, addr := range metadata.Network.Interfaces {\n\t\tif addr.Index <= 0 { // protect from negative interface name\n\t\t\tcontinue\n\t\t}\n\n\t\tiface := fmt.Sprintf(\"eth%d\", addr.Index-1)\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        iface,\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tfor _, ip := range addr.IPAddresses {\n\t\t\tif firstIP {\n\t\t\t\tpublicIPs = append(publicIPs, ip.Address)\n\n\t\t\t\tfirstIP = false\n\t\t\t}\n\n\t\t\tfor _, addr := range ip.DNS {\n\t\t\t\tif ipAddr, err := netip.ParseAddr(addr); err == nil {\n\t\t\t\t\tdnsIPs = append(dnsIPs, ipAddr)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ip.DHCP && ip.Family == \"IPv4\" {\n\t\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\tLinkName:  iface,\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif !ip.DHCP {\n\t\t\t\tntwrk, err := netip.ParsePrefix(ip.Network)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\taddr, err := netip.ParseAddr(ip.Address)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tipPrefix := netip.PrefixFrom(addr, ntwrk.Bits())\n\n\t\t\t\tfamily := nethelpers.FamilyInet4\n\n\t\t\t\tif addr.Is6() {\n\t\t\t\t\tpublicIPs = append(publicIPs, ip.Address)\n\t\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t\t}\n\n\t\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t\tLinkName:    iface,\n\t\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\t\tFamily:      family,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\tif ip.Gateway != \"\" {\n\t\t\t\t\tgw, err := netip.ParseAddr(ip.Gateway)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\n\t\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\t\tGateway:     gw,\n\t\t\t\t\t\tDestination: ntwrk,\n\t\t\t\t\t\tOutLinkName: iface,\n\t\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\t\tFamily:      family,\n\t\t\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t\t\t}\n\n\t\t\t\t\troute.Normalize()\n\n\t\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(dnsIPs) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:  dnsIPs,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:   u.Name(),\n\t\tHostname:   metadata.Hostname,\n\t\tZone:       metadata.Zone,\n\t\tInstanceID: metadata.InstanceID,\n\t\tProviderID: fmt.Sprintf(\"upcloud://%s\", metadata.InstanceID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the runtime.Platform interface.\nfunc (u *UpCloud) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", UpCloudUserDataEndpoint)\n\n\treturn download.Download(ctx, UpCloudUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (u *UpCloud) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (u *UpCloud) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (u *UpCloud) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching UpCloud instance config from: %q\", UpCloudMetadataEndpoint)\n\n\tmetadata, err := u.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := u.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud/upcloud_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage upcloud_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/upcloud\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &upcloud.UpCloud{}\n\n\tvar metadata upcloud.MetadataConfig\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vmware provides the VMware platform implementation.\npackage vmware\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NetworkConfig maps to VMware GuestInfo metadata.\n// See also definition of GuestInfo in CAPV https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/main/pkg/util/constants.go\ntype NetworkConfig struct {\n\tInstanceID    string `yaml:\"instance-id\"`\n\tLocalHostname string `yaml:\"local-hostname\"`\n\t// Talos doesn't block on network, it will reconfigure itself as network information becomes available. WaitOnNetwork is not used.\n\tWaitOnNetwork struct {\n\t\tIpv4 bool `yaml:\"ipv4\"`\n\t\tIpv6 bool `yaml:\"ipv6\"`\n\t} `yaml:\"wait-on-network,omitempty\"`\n\tNetwork struct {\n\t\tVersion   int                 `yaml:\"version\"`\n\t\tEthernets map[string]Ethernet `yaml:\"ethernets\"`\n\t}\n\tRoutes []Route `yaml:\"routes,omitempty\"`\n}\n\n// Ethernet holds network interface info.\ntype Ethernet struct {\n\tMatch struct {\n\t\tName   string `yaml:\"name,omitempty\"`\n\t\tHWAddr string `yaml:\"macaddress,omitempty\"`\n\t} `yaml:\"match,omitempty\"`\n\tSetName        string        `yaml:\"set-name,omitempty\"`\n\tWakeonlan      bool          `yaml:\"wakeonlan,omitempty\"`\n\tDHCPv4         bool          `yaml:\"dhcp4,omitempty\"`\n\tDHCP4Overrides DHCPOverrides `yaml:\"dhcp4-overrides,omitempty\"`\n\tDHCPv6         bool          `yaml:\"dhcp6,omitempty\"`\n\tDHCP6Overrides DHCPOverrides `yaml:\"dhcp6-overrides,omitempty\"`\n\tAddress        []string      `yaml:\"addresses,omitempty\"`\n\tGateway4       string        `yaml:\"gateway4,omitempty\"`\n\tGateway6       string        `yaml:\"gateway6,omitempty\"`\n\tMTU            int           `yaml:\"mtu,omitempty\"`\n\tNameServers    struct {\n\t\tSearch  []string `yaml:\"search,omitempty\"`\n\t\tAddress []string `yaml:\"addresses,omitempty\"`\n\t} `yaml:\"nameservers,omitempty\"`\n\tRoutes []Route `yaml:\"routes,omitempty\"`\n}\n\n// Route configuration. Not used.\ntype Route struct {\n\tTo     string `yaml:\"to,omitempty\"`\n\tVia    string `yaml:\"via,omitempty\"`\n\tMetric string `yaml:\"metric,omitempty\"`\n}\n\n// DHCPOverrides is partial implemented. Only RouteMetric is use, the other elements are not processed.\ntype DHCPOverrides struct {\n\tHostname     string `yaml:\"hostname,omitempty\"`\n\tRouteMetric  uint32 `yaml:\"route-metric,omitempty\"`\n\tSendHostname string `yaml:\"send-hostname,omitempty\"`\n\tUseDNS       string `yaml:\"use-dns,omitempty\"`\n\tUseDomains   string `yaml:\"use-domains,omitempty\"`\n\tUseHostname  string `yaml:\"use-hostname,omitempty\"`\n\tUseMTU       string `yaml:\"use-mtu,omitempty\"`\n\tUseNTP       string `yaml:\"use-ntp,omitempty\"`\n\tUseRoutes    string `yaml:\"use-routes,omitempty\"`\n}\n\n// ApplyNetworkConfigV2 gets GuestInfo and applies to the Talos runtime platform network configuration.\n//\n//nolint:gocyclo,cyclop\nfunc (v *VMware) ApplyNetworkConfigV2(ctx context.Context, st state.State, config *NetworkConfig, networkConfig *runtime.PlatformNetworkConfig) error {\n\tvar dnsIPs []netip.Addr\n\n\thostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing host interfaces: %w\", err)\n\t}\n\n\tfor name, eth := range config.Network.Ethernets {\n\t\tif eth.SetName != \"\" {\n\t\t\tname = eth.SetName\n\t\t}\n\n\t\tif !strings.HasPrefix(name, \"eth\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tif eth.Match.HWAddr != \"\" {\n\t\t\tvar availableMACAddresses []string\n\n\t\t\tmacAddressMatched := false\n\n\t\t\tfor hostInterface := range hostInterfaces.All() {\n\t\t\t\tmacAddress := hostInterface.TypedSpec().PermanentAddr.String()\n\t\t\t\tif macAddress == eth.Match.HWAddr {\n\t\t\t\t\tname = hostInterface.Metadata().ID()\n\t\t\t\t\tmacAddressMatched = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tavailableMACAddresses = append(availableMACAddresses, macAddress)\n\t\t\t}\n\n\t\t\tif !macAddressMatched {\n\t\t\t\tlog.Printf(\"vmware: no link with matching MAC address %q (available %v), defaulted to use name %s instead\", eth.Match.HWAddr, availableMACAddresses, name)\n\t\t\t}\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{\n\t\t\tName:        name,\n\t\t\tUp:          true,\n\t\t\tMTU:         uint32(eth.MTU),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\n\t\tif eth.DHCPv4 {\n\t\t\trouteMetric := uint32(network.DefaultRouteMetric)\n\n\t\t\tif eth.DHCP4Overrides.RouteMetric != 0 {\n\t\t\t\trouteMetric = eth.DHCP4Overrides.RouteMetric\n\t\t\t}\n\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\tLinkName:  name,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\tRouteMetric: routeMetric,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\t}\n\n\t\tif eth.DHCPv6 {\n\t\t\trouteMetric := uint32(2 * network.DefaultRouteMetric)\n\n\t\t\tif eth.DHCP4Overrides.RouteMetric != 0 {\n\t\t\t\trouteMetric = eth.DHCP6Overrides.RouteMetric\n\t\t\t}\n\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP6,\n\t\t\t\tLinkName:  name,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\t\t\tRouteMetric: routeMetric,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\t}\n\n\t\tfor _, addr := range eth.Address {\n\t\t\tipPrefix, err := netip.ParsePrefix(addr)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfamily := nethelpers.FamilyInet4\n\n\t\t\tif ipPrefix.Addr().Is6() {\n\t\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\t}\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    name,\n\t\t\t\t\tAddress:     ipPrefix,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      family,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\n\t\tif eth.Gateway4 != \"\" {\n\t\t\tgw, err := netip.ParseAddr(eth.Gateway4)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: name,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tPriority:    network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\n\t\tif eth.Gateway6 != \"\" {\n\t\t\tgw, err := netip.ParseAddr(eth.Gateway6)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\troute := network.RouteSpecSpec{\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\tGateway:     gw,\n\t\t\t\tOutLinkName: name,\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tFamily:      nethelpers.FamilyInet6,\n\t\t\t\tPriority:    2 * network.DefaultRouteMetric,\n\t\t\t}\n\n\t\t\troute.Normalize()\n\n\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t}\n\n\t\tfor _, addr := range eth.NameServers.Address {\n\t\t\tif ip, err := netip.ParseAddr(addr); err == nil {\n\t\t\t\tdnsIPs = append(dnsIPs, ip)\n\t\t\t} else {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif config.LocalHostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(config.LocalHostname); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tif len(dnsIPs) > 0 {\n\t\tnetworkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{\n\t\t\tDNSServers:  dnsIPs,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/testdata/expected-match-by-mac.yaml",
    "content": "addresses:\n    - address: 192.168.0.230/24\n      linkName: eth2\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth2\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.0.1\n      outLinkName: eth2\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: vmware-test-controlplane-zhnhr\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs: []\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/testdata/expected-match-by-name.yaml",
    "content": "addresses:\n    - address: 192.168.0.230/24\n      linkName: eth1\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 192.168.0.1\n      outLinkName: eth1\n      table: main\n      priority: 1024\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: vmware-test-controlplane-zhnhr\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs: []\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/testdata/metadata-match-by-mac.yaml",
    "content": "instance-id: \"1\"\nlocal-hostname: \"vmware-test-controlplane-zhnhr\"\nwait-on-network:\n  ipv4: false\n  ipv6: false\nnetwork:\n  version: 2\n  ethernets:\n    id0:\n      match:\n        macaddress: \"68:05:ca:b8:f1:f9\"\n      set-name: \"eth0\"\n      wakeonlan: true\n      addresses:\n      - \"192.168.0.230/24\"\n      gateway4: \"192.168.0.1\""
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/testdata/metadata-match-by-name.yaml",
    "content": "instance-id: \"1\"\nlocal-hostname: \"vmware-test-controlplane-zhnhr\"\nwait-on-network:\n  ipv4: false\n  ipv6: false\nnetwork:\n  version: 2\n  ethernets:\n    id0:\n      match:\n        name: \"eth1\"\n      set-name: \"eth1\"\n      wakeonlan: true\n      addresses:\n      - \"192.168.0.230/24\"\n      gateway4: \"192.168.0.1\""
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vmware provides the VMware platform implementation.\npackage vmware\n\nimport (\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// VMware is the concrete type that implements the platform.Platform interface.\ntype VMware struct{}\n\n// Name implements the platform.Platform interface.\nfunc (v *VMware) Name() string {\n\treturn \"vmware\"\n}\n\n// Mode implements the platform.Platform interface.\nfunc (v *VMware) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (v *VMware) KernelArgs(arch string, _ quirks.Quirks) procfs.Parameters {\n\tswitch arch {\n\tcase \"amd64\":\n\t\treturn []*procfs.Parameter{\n\t\t\tprocfs.NewParameter(constants.KernelParamConfig).Append(constants.ConfigGuestInfo),\n\t\t\tprocfs.NewParameter(\"console\").Append(\"tty0\").Append(\"ttyS0\"),\n\t\t\tprocfs.NewParameter(\"earlyprintk\").Append(\"ttyS0,115200\"),\n\t\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\t}\n\tcase \"arm64\":\n\t\treturn []*procfs.Parameter{\n\t\t\tprocfs.NewParameter(constants.KernelParamConfig).Append(constants.ConfigGuestInfo),\n\t\t\tprocfs.NewParameter(\"console\").Append(\"tty0\").Append(\"ttyAMA0\"),\n\t\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t\t}\n\tdefault:\n\t\treturn nil // not supported\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !(amd64 || arm64)\n\npackage vmware\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// Configuration implements the platform.Platform interface.\nfunc (v *VMware) Configuration(context.Context, state.State) ([]byte, error) {\n\treturn nil, errors.New(\"arch not supported\")\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (v *VMware) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_supported.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// the build is constrained to architectures supported by the hypercall package\n//go:build amd64 || arm64\n\npackage vmware\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/xml\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"log/slog\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/equinix-ms/go-vmw-guestrpc/pkg/hypercall\"\n\t\"github.com/equinix-ms/go-vmw-guestrpc/pkg/nanotoolbox\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tplatformerrors \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Read and de-base64 a property from `extraConfig`. This is commonly referred to as `guestinfo`.\nfunc readConfigFromExtraConfig(rpci *nanotoolbox.RPCI, key string) ([]byte, error) {\n\tval, err := rpci.InfoGet(constants.VMwareGuestInfoPrefix+key, \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get extraConfig %s: %w\", key, err)\n\t}\n\n\tif val == \"\" { // not present\n\t\tlog.Printf(\"empty (thus absent) %s\", key)\n\n\t\treturn nil, nil\n\t}\n\n\tdecoded, err := base64.StdEncoding.DecodeString(val)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode extraConfig %s: %w\", key, err)\n\t}\n\n\tif len(decoded) == 0 {\n\t\tlog.Printf(\"skipping zero-length config in extraConfig\")\n\n\t\treturn nil, nil\n\t}\n\n\treturn decoded, nil\n}\n\n// ofvEnv and related types are extracted from github.com/vmware/govmomi/ovf/env.go.\ntype ovfEnvFile struct {\n\tXMLName xml.Name `xml:\"http://schemas.dmtf.org/ovf/environment/1 Environment\"`\n\tID      string   `xml:\"id,attr\"`\n\tEsxID   string   `xml:\"http://www.vmware.com/schema/ovfenv esxId,attr\"`\n\n\tPlatform *ovfPlatformSection `xml:\"PlatformSection\"`\n\tProperty *ovfPropertySection `xml:\"PropertySection\"`\n}\n\ntype ovfPlatformSection struct {\n\tKind    string `xml:\"Kind\"`\n\tVersion string `xml:\"Version\"`\n\tVendor  string `xml:\"Vendor\"`\n\tLocale  string `xml:\"Locale\"`\n}\n\ntype ovfPropertySection struct {\n\tProperties []ovfEnvProperty `xml:\"Property\"`\n}\n\ntype ovfEnvProperty struct {\n\tKey   string `xml:\"key,attr\"`\n\tValue string `xml:\"value,attr\"`\n}\n\n// Read and de-base64 a property from the OVF env. This is different way to pass data to your VM.\n// This is how data gets passed when using vCloud Director.\nfunc readConfigFromOvf(rpci *nanotoolbox.RPCI, key string) ([]byte, error) {\n\tovfXML, err := rpci.InfoGet(constants.VMwareGuestInfoPrefix+constants.VMwareGuestInfoOvfEnvKey, \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read extraConfig var '%s': %w\", key, err)\n\t}\n\n\tif ovfXML == \"\" { // value empty (probably because not present)\n\t\treturn nil, nil\n\t}\n\n\tvar ovfEnv ovfEnvFile\n\n\terr = xml.Unmarshal([]byte(ovfXML), &ovfEnv)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshall XML from OVF env: %w\", err)\n\t}\n\n\tif ovfEnv.Property == nil || ovfEnv.Property.Properties == nil { // no data in OVF env\n\t\tlog.Printf(\"empty OVF env\")\n\n\t\treturn nil, nil\n\t}\n\n\tlog.Printf(\"searching for property '%s' in OVF\", key)\n\n\tfor _, property := range ovfEnv.Property.Properties { // iterate to check if our key is present\n\t\tif property.Key == key {\n\t\t\tlog.Printf(\"it is there, decoding\")\n\n\t\t\tdecoded, err := base64.StdEncoding.DecodeString(property.Value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to decode OVF property %s: %w\", property.Key, err)\n\t\t\t}\n\n\t\t\tif len(decoded) == 0 {\n\t\t\t\tlog.Printf(\"skipping zero-length config in OVF\")\n\n\t\t\t\treturn nil, nil\n\t\t\t}\n\n\t\t\treturn decoded, nil\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\nfunc initializeRPCI() (*nanotoolbox.RPCI, error) {\n\tinVMWare, err := hypercall.IsVMWareVM()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not determine if we are running in VMWare VM: %w\", err)\n\t}\n\n\tif !inVMWare {\n\t\treturn nil, errors.New(\"this is not a VMWare VM\")\n\t}\n\n\trpci, err := nanotoolbox.NewRPCI(slog.New(slog.NewTextHandler(log.Writer(), nil)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not initialize RPCI: %w\", err)\n\t}\n\n\tif err = rpci.Start(); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not start RPCI: %w\", err)\n\t}\n\n\treturn rpci, nil\n}\n\n// Configuration implements the platform.Platform interface.\n//\n//nolint:gocyclo\nfunc (v *VMware) Configuration(context.Context, state.State) ([]byte, error) {\n\tvar option *string\n\tif option = procfs.ProcCmdline().Get(constants.KernelParamConfig).First(); option == nil {\n\t\treturn nil, fmt.Errorf(\"%s not found\", constants.KernelParamConfig)\n\t}\n\n\tif *option == constants.ConfigGuestInfo {\n\t\tlog.Printf(\"fetching machine config from VMware extraConfig or OVF env\")\n\n\t\trpci, err := initializeRPCI()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error initiliazing RPCI: %w\", err)\n\t\t}\n\t\tdefer rpci.Stop() //nolint:errcheck\n\n\t\t// try to fetch `talos.config` from plain extraConfig (ie, the old behavior)\n\t\tlog.Printf(\"trying to find '%s' in extraConfig\", constants.VMwareGuestInfoConfigKey)\n\n\t\tconfig, err := readConfigFromExtraConfig(rpci, constants.VMwareGuestInfoConfigKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif config != nil {\n\t\t\treturn config, nil\n\t\t}\n\n\t\t// try to fetch `userdata` from plain extraConfig (ie, the old behavior)\n\t\tlog.Printf(\"trying to find '%s' in extraConfig\", constants.VMwareGuestInfoFallbackKey)\n\n\t\tconfig, err = readConfigFromExtraConfig(rpci, constants.VMwareGuestInfoFallbackKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif config != nil {\n\t\t\treturn config, nil\n\t\t}\n\n\t\t// try to fetch `talos.config` from OVF\n\t\tlog.Printf(\"trying to find '%s' in OVF env\", constants.VMwareGuestInfoConfigKey)\n\n\t\tconfig, err = readConfigFromOvf(rpci, constants.VMwareGuestInfoConfigKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif config != nil {\n\t\t\treturn config, nil\n\t\t}\n\n\t\t// try to fetch `userdata` from OVF\n\t\tlog.Printf(\"trying to find '%s' in OVF env\", constants.VMwareGuestInfoFallbackKey)\n\n\t\tconfig, err = readConfigFromOvf(rpci, constants.VMwareGuestInfoFallbackKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif config != nil {\n\t\t\treturn config, nil\n\t\t}\n\n\t\treturn nil, platformerrors.ErrNoConfigSource\n\t}\n\n\treturn nil, nil\n}\n\n// Read VMware GuestInfo metadata if available.\nfunc (v *VMware) readMetadata(rpci *nanotoolbox.RPCI) ([]byte, error) {\n\tguestInfoMetadata, err := readConfigFromExtraConfig(rpci, constants.VMwareGuestInfoMetadataKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif guestInfoMetadata == nil {\n\t\tguestInfoMetadata, err = readConfigFromOvf(rpci, constants.VMwareGuestInfoMetadataKey)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn guestInfoMetadata, nil\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (v *VMware) NetworkConfiguration(ctx context.Context, st state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\trpci, err := initializeRPCI()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initiliazing RPCI: %w\", err)\n\t}\n\tdefer rpci.Stop() //nolint:errcheck\n\n\tguestInfoMetadata, err := v.readMetadata(rpci)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read GuestInfo: %w\", err)\n\t}\n\n\tnetworkConfig := &runtime.PlatformNetworkConfig{\n\t\tMetadata: &runtimeres.PlatformMetadataSpec{Platform: v.Name()},\n\t}\n\n\tif guestInfoMetadata != nil {\n\t\tvar unmarshalledNetworkConfig NetworkConfig\n\t\tif err = yaml.Unmarshal(guestInfoMetadata, &unmarshalledNetworkConfig); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshall metadata '%s'. Error '%w'\", guestInfoMetadata, err)\n\t\t}\n\n\t\tswitch unmarshalledNetworkConfig.Network.Version {\n\t\tcase 2:\n\t\t\terr := v.ApplyNetworkConfigV2(ctx, st, &unmarshalledNetworkConfig, networkConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to apply metadata '%s'. Error '%w'\", guestInfoMetadata, err)\n\t\t\t}\n\n\t\t\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\t\t\tPlatform:   v.Name(),\n\t\t\t\tHostname:   unmarshalledNetworkConfig.LocalHostname,\n\t\t\t\tInstanceID: unmarshalledNetworkConfig.InstanceID,\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"GuestInfo version=%d is not supported. GuestInfo: %s\", unmarshalledNetworkConfig.Network.Version, guestInfoMetadata)\n\t\t}\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase ch <- networkConfig:\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vmware_test\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n//go:embed testdata/metadata-match-by-mac.yaml\nvar rawMetadataMatchByMAC []byte\n\n//go:embed testdata/expected-match-by-mac.yaml\nvar expectedNetworkConfigMatchByMAC string\n\n//go:embed testdata/metadata-match-by-name.yaml\nvar rawMetadataMatchByName []byte\n\n//go:embed testdata/expected-match-by-name.yaml\nvar expectedNetworkConfigMatchByName string\n\nfunc TestApplyNetworkConfigV2a(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\traw      []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"byMAC\",\n\t\t\traw:      rawMetadataMatchByMAC,\n\t\t\texpected: expectedNetworkConfigMatchByMAC,\n\t\t},\n\t\t{\n\t\t\tname:     \"byName\",\n\t\t\traw:      rawMetadataMatchByName,\n\t\t\texpected: expectedNetworkConfigMatchByName,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tctx := t.Context()\n\t\t\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\teth1 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\t\t\teth1.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf8}\n\t\t\trequire.NoError(t, st.Create(ctx, eth1))\n\n\t\t\teth2 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\t\t\teth2.TypedSpec().PermanentAddr = nethelpers.HardwareAddr{0x68, 0x05, 0xca, 0xb8, 0xf1, 0xf9}\n\t\t\trequire.NoError(t, st.Create(ctx, eth2))\n\n\t\t\tvar metadata vmware.NetworkConfig\n\n\t\t\trequire.NoError(t, yaml.Unmarshal(tt.raw, &metadata))\n\n\t\t\tv := &vmware.VMware{}\n\t\t\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\t\t\terr := v.ApplyNetworkConfigV2(ctx, st, &metadata, networkConfig)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmarshaled, err := yaml.Marshal(networkConfig)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfmt.Print(string(marshaled))\n\n\t\t\tassert.Equal(t, tt.expected, string(marshaled))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vultr/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vultr\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/vultr/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\nconst (\n\t// VultrMetadataEndpoint is the local Vultr endpoint fot the instance metadata.\n\tVultrMetadataEndpoint = \"http://169.254.169.254/v1.json\"\n\t// VultrExternalIPEndpoint is the local Vultr endpoint for the external IP.\n\tVultrExternalIPEndpoint = \"http://169.254.169.254/latest/meta-data/public-ipv4\"\n\t// VultrUserDataEndpoint is the local Vultr endpoint for the config.\n\tVultrUserDataEndpoint = \"http://169.254.169.254/latest/user-data\"\n)\n\nfunc (g *Vultr) getMetadata(ctx context.Context) (*metadata.MetaData, error) {\n\tmetaConfigDl, err := download.Download(ctx, VultrMetadataEndpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching metadata: %w\", err)\n\t}\n\n\tvar meta metadata.MetaData\n\tif err = json.Unmarshal(metaConfigDl, &meta); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &meta, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vultr/testdata/expected.yaml",
    "content": "addresses:\n    - address: 95.111.222.111/23\n      linkName: eth0\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\n    - address: 10.7.96.3/20\n      linkName: eth1\n      family: inet4\n      scope: global\n      flags: permanent\n      layer: platform\nlinks:\n    - name: eth0\n      logical: false\n      up: true\n      mtu: 0\n      kind: \"\"\n      type: netrom\n      layer: platform\n    - name: eth1\n      logical: false\n      up: true\n      mtu: 1450\n      kind: \"\"\n      type: netrom\n      layer: platform\nroutes:\n    - family: inet4\n      dst: \"\"\n      src: \"\"\n      gateway: 95.111.222.1\n      outLinkName: eth0\n      table: main\n      scope: global\n      type: unicast\n      flags: \"\"\n      protocol: static\n      layer: platform\nhostnames:\n    - hostname: talos\n      domainname: \"\"\n      layer: platform\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n    - 95.111.222.111\n    - 2001:19f0:5001:2095:1111:2222:3333:4444\nmetadata:\n    platform: vultr\n    hostname: talos\n    region: AMS\n    instanceId: 91b07056-af72-4551-b15b-d57d34071be9\n    providerId: vultr://91b07056-af72-4551-b15b-d57d34071be9\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vultr/testdata/metadata.json",
    "content": "{\n    \"bgp\": {\n        \"ipv4\": {\n            \"my-address\": \"\",\n            \"my-asn\": \"\",\n            \"peer-address\": \"\",\n            \"peer-asn\": \"\"\n        },\n        \"ipv6\": {\n            \"my-address\": \"\",\n            \"my-asn\": \"\",\n            \"peer-address\": \"\",\n            \"peer-asn\": \"\"\n        }\n    },\n    \"hostname\": \"talos\",\n    \"instance-v2-id\": \"91b07056-af72-4551-b15b-d57d34071be9\",\n    \"instanceid\": \"50190000\",\n    \"interfaces\": [\n        {\n            \"ipv4\": {\n                \"additional\": [],\n                \"address\": \"95.111.222.111\",\n                \"gateway\": \"95.111.222.1\",\n                \"netmask\": \"255.255.254.0\"\n            },\n            \"ipv6\": {\n                \"additional\": [],\n                \"address\": \"2001:19f0:5001:2095:1111:2222:3333:4444\",\n                \"network\": \"2001:19f0:5001:2095::\",\n                \"prefix\": \"64\"\n            },\n            \"mac\": \"56:00:03:89:53:e0\",\n            \"network-type\": \"public\"\n        },\n        {\n            \"ipv4\": {\n                \"additional\": [],\n                \"address\": \"10.7.96.3\",\n                \"gateway\": \"\",\n                \"netmask\": \"255.255.240.0\"\n            },\n            \"ipv6\": {\n                \"additional\": [],\n                \"network\": \"\",\n                \"prefix\": \"\"\n            },\n            \"mac\": \"5a:00:03:89:53:e0\",\n            \"network-type\": \"private\",\n            \"network-v2-id\": \"dadc2b30-0b55-4fa1-8c29-f67215bd5ac4\",\n            \"networkid\": \"net6126811851cd7\"\n        }\n    ],\n    \"public-keys\": [\n        \"ssh-ed25519\"\n    ],\n    \"region\": {\n        \"regioncode\": \"AMS\"\n    },\n    \"user-defined\": []\n}"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vultr/vultr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vultr provides the Vultr platform implementation.\npackage vultr\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/vultr/metadata\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/errors\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/internal/netutils\"\n\t\"github.com/siderolabs/talos/pkg/download\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Vultr is the concrete type that implements the runtime.Platform interface.\ntype Vultr struct{}\n\n// Name implements the runtime.Platform interface.\nfunc (v *Vultr) Name() string {\n\treturn \"vultr\"\n}\n\n// ParseMetadata converts Vultr platform metadata into platform network config.\n//\n//nolint:gocyclo\nfunc (v *Vultr) ParseMetadata(metadata *metadata.MetaData) (*runtime.PlatformNetworkConfig, error) {\n\tnetworkConfig := &runtime.PlatformNetworkConfig{}\n\n\tif metadata.Hostname != \"\" {\n\t\thostnameSpec := network.HostnameSpecSpec{\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif err := hostnameSpec.ParseFQDN(metadata.Hostname); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnetworkConfig.Hostnames = append(networkConfig.Hostnames, hostnameSpec)\n\t}\n\n\tvar publicIPs []string\n\n\tfor i, addr := range metadata.Interfaces {\n\t\tiface := fmt.Sprintf(\"eth%d\", i)\n\n\t\tlink := network.LinkSpecSpec{\n\t\t\tName:        iface,\n\t\t\tUp:          true,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t}\n\n\t\tif addr.NetworkType == \"private\" {\n\t\t\tlink.MTU = 1450\n\t\t}\n\n\t\tnetworkConfig.Links = append(networkConfig.Links, link)\n\n\t\tif addr.IPv4.Address != \"\" {\n\t\t\tif addr.NetworkType == \"public\" {\n\t\t\t\tpublicIPs = append(publicIPs, addr.IPv4.Address)\n\t\t\t}\n\n\t\t\tip, err := netip.ParseAddr(addr.IPv4.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tnetmask, err := netip.ParseAddr(addr.IPv4.Netmask)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tmask, _ := netmask.MarshalBinary() //nolint:errcheck // never fails\n\t\t\tones, _ := net.IPMask(mask).Size()\n\t\t\tipAddr := netip.PrefixFrom(ip, ones)\n\n\t\t\tnetworkConfig.Addresses = append(networkConfig.Addresses,\n\t\t\t\tnetwork.AddressSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tLinkName:    iface,\n\t\t\t\t\tAddress:     ipAddr,\n\t\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif addr.IPv4.Gateway != \"\" {\n\t\t\t\tgw, err := netip.ParseAddr(addr.IPv4.Gateway)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\troute := network.RouteSpecSpec{\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t\tGateway:     gw,\n\t\t\t\t\tOutLinkName: iface,\n\t\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\t}\n\n\t\t\t\troute.Normalize()\n\n\t\t\t\tnetworkConfig.Routes = append(networkConfig.Routes, route)\n\t\t\t}\n\t\t} else {\n\t\t\tnetworkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{\n\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\tLinkName:  iface,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\tRouteMetric: network.DefaultRouteMetric,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t})\n\t\t}\n\n\t\tif addr.IPv6.Address != \"\" {\n\t\t\tif addr.NetworkType == \"public\" {\n\t\t\t\tpublicIPs = append(publicIPs, addr.IPv6.Address)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, ipStr := range publicIPs {\n\t\tif ip, err := netip.ParseAddr(ipStr); err == nil {\n\t\t\tnetworkConfig.ExternalIPs = append(networkConfig.ExternalIPs, ip)\n\t\t}\n\t}\n\n\tnetworkConfig.Metadata = &runtimeres.PlatformMetadataSpec{\n\t\tPlatform:   v.Name(),\n\t\tHostname:   metadata.Hostname,\n\t\tRegion:     metadata.Region.RegionCode,\n\t\tInstanceID: metadata.InstanceV2ID,\n\t\tProviderID: fmt.Sprintf(\"vultr://%s\", metadata.InstanceV2ID),\n\t}\n\n\treturn networkConfig, nil\n}\n\n// Configuration implements the runtime.Platform interface.\n//\n//nolint:stylecheck\nfunc (v *Vultr) Configuration(ctx context.Context, r state.State) ([]byte, error) {\n\tif err := netutils.Wait(ctx, r); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlog.Printf(\"fetching machine config from: %q\", VultrUserDataEndpoint)\n\n\treturn download.Download(ctx, VultrUserDataEndpoint,\n\t\tdownload.WithErrorOnNotFound(errors.ErrNoConfigSource),\n\t\tdownload.WithErrorOnEmptyResponse(errors.ErrNoConfigSource))\n}\n\n// Mode implements the runtime.Platform interface.\nfunc (v *Vultr) Mode() runtime.Mode {\n\treturn runtime.ModeCloud\n}\n\n// KernelArgs implements the runtime.Platform interface.\nfunc (v *Vultr) KernelArgs(string, quirks.Quirks) procfs.Parameters {\n\treturn []*procfs.Parameter{\n\t\tprocfs.NewParameter(constants.KernelParamNetIfnames).Append(\"0\"),\n\t}\n}\n\n// NetworkConfiguration implements the runtime.Platform interface.\nfunc (v *Vultr) NetworkConfiguration(ctx context.Context, _ state.State, ch chan<- *runtime.PlatformNetworkConfig) error {\n\tlog.Printf(\"fetching Vultr instance metadata from: %q\", VultrMetadataEndpoint)\n\n\tmetadata, err := v.getMetadata(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnetworkConfig, err := v.ParseMetadata(metadata)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase ch <- networkConfig:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/platform/vultr/vultr_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vultr_test\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/vultr/metadata\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform/vultr\"\n)\n\n//go:embed testdata/metadata.json\nvar rawMetadata []byte\n\n//go:embed testdata/expected.yaml\nvar expectedNetworkConfig string\n\nfunc TestParseMetadata(t *testing.T) {\n\tp := &vultr.Vultr{}\n\n\tvar metadata metadata.MetaData\n\n\trequire.NoError(t, json.Unmarshal(rawMetadata, &metadata))\n\n\tnetworkConfig, err := p.ParseMetadata(&metadata)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := yaml.Marshal(networkConfig)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedNetworkConfig, string(marshaled))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/acpi\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha2\"\n\tkrnl \"github.com/siderolabs/talos/pkg/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n)\n\n// Controller represents the controller responsible for managing the execution\n// of sequences.\ntype Controller struct {\n\ts  runtime.Sequencer\n\tr  *Runtime\n\tv2 *v1alpha2.Controller\n\n\tpriorityLock *PriorityLock[runtime.Sequence]\n}\n\n// NewController intializes and returns a controller.\nfunc NewController() (*Controller, error) {\n\ts, err := NewState()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// TODO: this should be streaming capacity and probably some constant\n\te := NewEvents(1000, 10)\n\n\tl := logging.NewCircularBufferLoggingManager(log.New(os.Stdout, \"machined fallback logger: \", log.Flags()))\n\n\tctlr := &Controller{\n\t\tr:            NewRuntime(s, e, l),\n\t\ts:            NewSequencer(),\n\t\tpriorityLock: NewPriorityLock[runtime.Sequence](),\n\t}\n\n\tctlr.v2, err = v1alpha2.NewController(ctlr.r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := ctlr.setupLogging(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ctlr, nil\n}\n\nfunc (c *Controller) setupLogging() error {\n\tmachinedLog, err := c.r.Logging().ServiceLog(\"machined\").Writer()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif c.r.State().Platform().Mode() == runtime.ModeContainer {\n\t\t// send all the logs to machinedLog as well, but skip /dev/kmsg logging\n\t\tlog.SetOutput(io.MultiWriter(log.Writer(), machinedLog))\n\t\tlog.SetPrefix(\"[talos] \")\n\n\t\treturn nil\n\t}\n\n\t// disable ratelimiting for kmsg, otherwise logs might be not visible.\n\t// this should be set via kernel arg, but in case it's not set, try to force it.\n\tif err = krnl.WriteParam(&kernel.Param{\n\t\tKey:   \"proc.sys.kernel.printk_devkmsg\",\n\t\tValue: \"on\\n\",\n\t}); err != nil {\n\t\tvar serr syscall.Errno\n\t\tif !(errors.As(err, &serr) && serr == syscall.EINVAL) { // ignore EINVAL which is returned when kernel arg is set\n\t\t\tlog.Printf(\"failed setting kernel.printk_devkmsg: %s, error ignored\", err)\n\t\t}\n\t}\n\n\tif err = kmsg.SetupLogger(nil, \"[talos]\", machinedLog); err != nil {\n\t\treturn fmt.Errorf(\"failed to setup logging: %w\", err)\n\t}\n\n\t// Ensure that the logger is initialized and writer returns properly.\n\tif err = log.Output(1, \"machined logger initialized\"); err != nil {\n\t\treturn fmt.Errorf(\"failed on log initialization: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Run executes all phases known to the controller in serial. `Controller`\n// aborts immediately if any phase fails.\nfunc (c *Controller) Run(ctx context.Context, seq runtime.Sequence, data any, setters ...runtime.LockOption) error {\n\t// We must ensure that the runtime is configured since all sequences depend\n\t// on the runtime.\n\tif c.r == nil {\n\t\treturn runtime.ErrUndefinedRuntime\n\t}\n\n\tctx, err := c.priorityLock.Lock(ctx, time.Minute, seq, setters...)\n\tif err != nil {\n\t\tif errors.Is(err, runtime.ErrLocked) {\n\t\t\tc.Runtime().Events().Publish(context.Background(), &machine.SequenceEvent{\n\t\t\t\tSequence: seq.String(),\n\t\t\t\tAction:   machine.SequenceEvent_NOOP,\n\t\t\t\tError: &common.Error{\n\t\t\t\t\tCode:    common.Code_LOCKED,\n\t\t\t\t\tMessage: fmt.Sprintf(\"sequence not started: %s\", runtime.ErrLocked.Error()),\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn err\n\t}\n\n\tdefer c.priorityLock.Unlock()\n\n\tphases, err := c.phases(seq, data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = c.run(ctx, seq, phases, data)\n\tif err != nil {\n\t\tcode := common.Code_FATAL\n\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tcode = common.Code_CANCELED\n\t\t}\n\n\t\tc.Runtime().Events().Publish(ctx, &machine.SequenceEvent{\n\t\t\tSequence: seq.String(),\n\t\t\tAction:   machine.SequenceEvent_NOOP,\n\t\t\tError: &common.Error{\n\t\t\t\tCode:    code,\n\t\t\t\tMessage: fmt.Sprintf(\"sequence failed: %s\", err.Error()),\n\t\t\t},\n\t\t})\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// V1Alpha2 implements the controller interface.\nfunc (c *Controller) V1Alpha2() runtime.V1Alpha2Controller {\n\treturn c.v2\n}\n\n// Runtime implements the controller interface.\nfunc (c *Controller) Runtime() runtime.Runtime {\n\treturn c.r\n}\n\n// Sequencer implements the controller interface.\nfunc (c *Controller) Sequencer() runtime.Sequencer {\n\treturn c.s\n}\n\n// ListenForEvents starts the event listener. The listener will trigger a\n// shutdown in response to a SIGTERM signal and ACPI button/power event.\nfunc (c *Controller) ListenForEvents(ctx context.Context) error {\n\tsigs := make(chan os.Signal, 1)\n\n\tsignal.Notify(sigs, syscall.SIGTERM)\n\n\terrCh := make(chan error, 2)\n\n\tgo func() {\n\t\t<-sigs\n\t\tsignal.Stop(sigs)\n\n\t\tlog.Printf(\"shutdown via SIGTERM received\")\n\n\t\tif err := c.Run(ctx, runtime.SequenceShutdown, &machine.ShutdownRequest{Force: true}, runtime.WithTakeover()); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Printf(\"shutdown failed: %v\", err)\n\t\t\t}\n\t\t}\n\n\t\terrCh <- nil\n\t}()\n\n\tif c.r.State().Platform().Mode() == runtime.ModeContainer {\n\t\treturn nil\n\t}\n\n\tgo func() {\n\t\tif err := acpi.StartACPIListener(); err != nil {\n\t\t\terrCh <- err\n\n\t\t\treturn\n\t\t}\n\n\t\tlog.Printf(\"shutdown via ACPI received\")\n\n\t\tif err := c.Run(ctx, runtime.SequenceShutdown, &machine.ShutdownRequest{Force: true}, runtime.WithTakeover()); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Printf(\"failed to run shutdown sequence: %s\", err)\n\t\t\t}\n\t\t}\n\n\t\terrCh <- nil\n\t}()\n\n\terr := <-errCh\n\n\treturn err\n}\n\nfunc (c *Controller) run(ctx context.Context, seq runtime.Sequence, phases []runtime.Phase, data any) error {\n\tc.Runtime().Events().Publish(ctx, &machine.SequenceEvent{\n\t\tSequence: seq.String(),\n\t\tAction:   machine.SequenceEvent_START,\n\t})\n\n\tdefer c.Runtime().Events().Publish(ctx, &machine.SequenceEvent{\n\t\tSequence: seq.String(),\n\t\tAction:   machine.SequenceEvent_STOP,\n\t})\n\n\tstart := time.Now()\n\n\tvar (\n\t\tnumber int\n\t\tphase  runtime.Phase\n\t\terr    error\n\t)\n\n\tlog.Printf(\"%s sequence: %d phase(s)\", seq.String(), len(phases))\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Printf(\"%s sequence: failed\", seq.String())\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\"%s sequence: done: %s\", seq.String(), time.Since(start))\n\t\t}\n\t}()\n\n\tfor number, phase = range phases {\n\t\tif phase.CheckFunc != nil && !phase.CheckFunc() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Make the phase number human friendly.\n\t\tnumber++\n\n\t\tstart := time.Now()\n\n\t\tprogress := fmt.Sprintf(\"%d/%d\", number, len(phases))\n\n\t\tlog.Printf(\"phase %s (%s): %d tasks(s)\", phase.Name, progress, len(phase.Tasks))\n\n\t\tif err = c.runPhase(ctx, phase, seq, data); err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Printf(\"phase %s (%s): failed\", phase.Name, progress)\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error running phase %d in %s sequence: %w\", number, seq.String(), err)\n\t\t}\n\n\t\tlog.Printf(\"phase %s (%s): done, %s\", phase.Name, progress, time.Since(start))\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (c *Controller) runPhase(ctx context.Context, phase runtime.Phase, seq runtime.Sequence, data any) error {\n\tc.Runtime().Events().Publish(ctx, &machine.PhaseEvent{\n\t\tPhase:  phase.Name,\n\t\tAction: machine.PhaseEvent_START,\n\t})\n\n\tdefer c.Runtime().Events().Publish(ctx, &machine.PhaseEvent{\n\t\tPhase:  phase.Name,\n\t\tAction: machine.PhaseEvent_STOP,\n\t})\n\n\teg, ctx := errgroup.WithContext(ctx)\n\n\tfor number, task := range phase.Tasks {\n\t\t// Make the task number human friendly.\n\t\tnumber++\n\n\t\teg.Go(func() error {\n\t\t\tprogress := fmt.Sprintf(\"%d/%d\", number, len(phase.Tasks))\n\n\t\t\tif err := c.runTask(ctx, progress, task, seq, data); err != nil {\n\t\t\t\treturn fmt.Errorf(\"task %s: failed, %w\", progress, err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn eg.Wait()\n}\n\nfunc (c *Controller) runTask(ctx context.Context, progress string, f runtime.TaskSetupFunc, seq runtime.Sequence, data any) error {\n\ttask, taskName := f(seq, data)\n\tif task == nil {\n\t\treturn nil\n\t}\n\n\tstart := time.Now()\n\n\tc.Runtime().Events().Publish(ctx, &machine.TaskEvent{\n\t\tTask:   taskName,\n\t\tAction: machine.TaskEvent_START,\n\t})\n\n\tvar err error\n\n\tlog.Printf(\"task %s (%s): starting\", taskName, progress)\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tif !runtime.IsRebootError(err) {\n\t\t\t\tlog.Printf(\"task %s (%s): failed: %s\", taskName, progress, err)\n\t\t\t}\n\t\t} else {\n\t\t\tlog.Printf(\"task %s (%s): done, %s\", taskName, progress, time.Since(start))\n\t\t}\n\t}()\n\n\tdefer c.Runtime().Events().Publish(ctx, &machine.TaskEvent{\n\t\tTask:   taskName,\n\t\tAction: machine.TaskEvent_STOP,\n\t})\n\n\tlogger := log.New(log.Writer(), fmt.Sprintf(\"[talos] task %s (%s): \", taskName, progress), log.Flags())\n\n\terr = task(ctx, logger, c.r)\n\n\treturn err\n}\n\n//nolint:gocyclo\nfunc (c *Controller) phases(seq runtime.Sequence, data any) ([]runtime.Phase, error) {\n\tvar phases []runtime.Phase\n\n\tswitch seq {\n\tcase runtime.SequenceBoot:\n\t\tphases = c.s.Boot(c.r)\n\tcase runtime.SequenceInitialize:\n\t\tphases = c.s.Initialize(c.r)\n\tcase runtime.SequenceInstall:\n\t\tphases = c.s.Install(c.r)\n\tcase runtime.SequenceShutdown:\n\t\tin, ok := data.(*machine.ShutdownRequest)\n\t\tif !ok {\n\t\t\treturn nil, runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tphases = c.s.Shutdown(c.r, in)\n\tcase runtime.SequenceReboot:\n\t\tvar in *machine.RebootRequest\n\t\tif req, ok := data.(*machine.RebootRequest); ok {\n\t\t\tin = req\n\t\t} else {\n\t\t\tlog.Printf(\"warning: API reboot missing reboot request\")\n\t\t}\n\n\t\tphases = c.s.Reboot(c.r, in)\n\tcase runtime.SequenceUpgrade:\n\t\tin, ok := data.(*machine.UpgradeRequest)\n\t\tif !ok {\n\t\t\treturn nil, runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tphases = c.s.Upgrade(c.r, in)\n\tcase runtime.SequenceStageUpgrade:\n\t\tin, ok := data.(*machine.UpgradeRequest)\n\t\tif !ok {\n\t\t\treturn nil, runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tphases = c.s.StageUpgrade(c.r, in)\n\tcase runtime.SequenceMaintenanceUpgrade:\n\t\tin, ok := data.(*machine.UpgradeRequest)\n\t\tif !ok {\n\t\t\treturn nil, runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tphases = c.s.MaintenanceUpgrade(c.r, in)\n\tcase runtime.SequenceReset:\n\t\tin, ok := data.(runtime.ResetOptions)\n\t\tif !ok {\n\t\t\treturn nil, runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tphases = c.s.Reset(c.r, in)\n\tcase runtime.SequenceNoop:\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"sequence not implemented: %q\", seq)\n\t}\n\n\treturn phases, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_controller_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint,testpackage\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sync/errgroup\"\n\n\tv1alpha1server \"github.com/siderolabs/talos/internal/app/machined/internal/server/v1alpha1\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\ntype mockSequencer struct {\n\tcallsMu sync.Mutex\n\tcalls   map[runtime.Sequence]int\n\n\tphases map[runtime.Sequence]PhaseList\n}\n\nfunc (m *mockSequencer) Boot(r runtime.Runtime) []runtime.Phase {\n\treturn m.phases[runtime.SequenceBoot]\n}\n\nfunc (m *mockSequencer) Initialize(r runtime.Runtime) []runtime.Phase {\n\treturn m.phases[runtime.SequenceInitialize]\n}\n\nfunc (m *mockSequencer) Install(r runtime.Runtime) []runtime.Phase {\n\treturn m.phases[runtime.SequenceInstall]\n}\n\nfunc (m *mockSequencer) Reboot(r runtime.Runtime, _ *machine.RebootRequest) []runtime.Phase {\n\treturn m.phases[runtime.SequenceReboot]\n}\n\nfunc (m *mockSequencer) Reset(r runtime.Runtime, opts runtime.ResetOptions) []runtime.Phase {\n\treturn m.phases[runtime.SequenceReset]\n}\n\nfunc (m *mockSequencer) Shutdown(r runtime.Runtime, req *machine.ShutdownRequest) []runtime.Phase {\n\treturn m.phases[runtime.SequenceShutdown]\n}\n\nfunc (m *mockSequencer) StageUpgrade(r runtime.Runtime, req *machine.UpgradeRequest) []runtime.Phase {\n\treturn m.phases[runtime.SequenceStageUpgrade]\n}\n\nfunc (m *mockSequencer) MaintenanceUpgrade(r runtime.Runtime, req *machine.UpgradeRequest) []runtime.Phase {\n\treturn m.phases[runtime.SequenceMaintenanceUpgrade]\n}\n\nfunc (m *mockSequencer) Upgrade(r runtime.Runtime, req *machine.UpgradeRequest) []runtime.Phase {\n\treturn m.phases[runtime.SequenceUpgrade]\n}\n\nfunc (m *mockSequencer) trackCall(name string, doneCh chan struct{}) func(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(seq runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\tif doneCh != nil {\n\t\t\t\tdefer func() {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase doneCh <- struct{}{}:\n\t\t\t\t\tcase <-time.After(time.Second):\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\n\t\t\tm.callsMu.Lock()\n\t\t\tdefer m.callsMu.Unlock()\n\n\t\t\tm.calls[seq]++\n\n\t\t\treturn nil\n\t\t}, name\n\t}\n}\n\nfunc TestRun(t *testing.T) {\n\ttests := []struct {\n\t\tname        string\n\t\tfrom        runtime.Sequence\n\t\tto          runtime.Sequence\n\t\texpectError error\n\t\tdataFrom    any\n\t\tdataTo      any\n\t}{\n\t\t{\n\t\t\tname:        \"reboot should take over boot\",\n\t\t\tfrom:        runtime.SequenceBoot,\n\t\t\tto:          runtime.SequenceReboot,\n\t\t\texpectError: context.Canceled,\n\t\t},\n\t\t{\n\t\t\tname:        \"reset should take over boot\",\n\t\t\tfrom:        runtime.SequenceBoot,\n\t\t\tto:          runtime.SequenceReset,\n\t\t\texpectError: context.Canceled,\n\t\t\tdataTo:      &v1alpha1server.ResetOptions{},\n\t\t},\n\t\t{\n\t\t\tname:        \"upgrade should take over boot\",\n\t\t\tfrom:        runtime.SequenceBoot,\n\t\t\tto:          runtime.SequenceUpgrade,\n\t\t\texpectError: context.Canceled,\n\t\t\tdataTo:      &machine.UpgradeRequest{},\n\t\t},\n\t\t{\n\t\t\tname:        \"boot should not take over reboot\",\n\t\t\tfrom:        runtime.SequenceReboot,\n\t\t\tto:          runtime.SequenceBoot,\n\t\t\texpectError: runtime.ErrLocked,\n\t\t},\n\t\t{\n\t\t\tname:        \"reset should not take over upgrade\",\n\t\t\tfrom:        runtime.SequenceUpgrade,\n\t\t\tto:          runtime.SequenceReset,\n\t\t\texpectError: runtime.ErrLocked,\n\t\t\tdataFrom:    &machine.UpgradeRequest{},\n\t\t\tdataTo:      &v1alpha1server.ResetOptions{},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\trequire := require.New(t)\n\t\t\tassert := assert.New(t)\n\n\t\t\te := NewEvents(1000, 10)\n\n\t\t\tt.Setenv(\"PLATFORM\", \"container\")\n\n\t\t\ts, err := NewState()\n\t\t\trequire.NoError(err)\n\n\t\t\tsequencer := &mockSequencer{\n\t\t\t\tcalls:  map[runtime.Sequence]int{},\n\t\t\t\tphases: map[runtime.Sequence]PhaseList{},\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\teg     errgroup.Group\n\t\t\t\tdoneCh = make(chan struct{})\n\t\t\t)\n\n\t\t\tsequencer.phases[tt.from] = sequencer.phases[tt.from].\n\t\t\t\tAppend(tt.from.String(), sequencer.trackCall(tt.from.String(), doneCh)).\n\t\t\t\tAppend(\"wait\", wait)\n\n\t\t\tsequencer.phases[tt.to] = sequencer.phases[tt.to].Append(tt.to.String(), sequencer.trackCall(tt.to.String(), nil))\n\n\t\t\tl := logging.NewCircularBufferLoggingManager(log.New(os.Stdout, \"machined fallback logger: \", log.Flags()))\n\n\t\t\tr := NewRuntime(s, e, l)\n\n\t\t\tcontroller := Controller{\n\t\t\t\tr:            r,\n\t\t\t\ts:            sequencer,\n\t\t\t\tpriorityLock: NewPriorityLock[runtime.Sequence](),\n\t\t\t}\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), time.Millisecond*200)\n\t\t\tdefer cancel()\n\n\t\t\teg.Go(func() error {\n\t\t\t\tt.Logf(\"starting %s sequence\", tt.from.String())\n\n\t\t\t\tseqErr := controller.Run(ctx, tt.from, tt.dataFrom)\n\n\t\t\t\tt.Logf(\"sequence %s finished with error: %v\", tt.from.String(), seqErr)\n\n\t\t\t\treturn seqErr\n\t\t\t})\n\n\t\t\teg.Go(func() error {\n\t\t\t\tselect {\n\t\t\t\tcase <-doneCh:\n\t\t\t\tcase <-time.After(time.Second):\n\t\t\t\t\treturn fmt.Errorf(\"timed out waiting for %s sequence to start\", tt.from.String())\n\t\t\t\t}\n\n\t\t\t\tt.Logf(\"starting %s sequence\", tt.to.String())\n\n\t\t\t\tseqErr := controller.Run(ctx, tt.to, tt.dataTo)\n\n\t\t\t\tt.Logf(\"sequence %s finished with error: %v\", tt.to.String(), seqErr)\n\n\t\t\t\treturn seqErr\n\t\t\t})\n\n\t\t\trequire.ErrorIs(eg.Wait(), tt.expectError)\n\n\t\t\tif errors.Is(tt.expectError, runtime.ErrLocked) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tsequencer.callsMu.Lock()\n\t\t\tdefer sequencer.callsMu.Unlock()\n\n\t\t\tassert.Equal(1, sequencer.calls[tt.to])\n\t\t})\n\t}\n}\n\nfunc wait(seq runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(time.Second * 1):\n\t\t}\n\n\t\treturn nil\n\t}, \"wait\"\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_dbus.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/logind\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// DBusState implements the logind mock.\ntype DBusState struct {\n\tbroker     *logind.DBusBroker\n\tlogindMock *logind.ServiceMock\n\terrCh      chan error\n\tcancel     context.CancelFunc\n}\n\n// Start the D-Bus broker and logind mock.\nfunc (dbus *DBusState) Start() error {\n\tfor _, path := range []string{constants.DBusServiceSocketPath, constants.DBusClientSocketPath} {\n\t\tif err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar (\n\t\terr error\n\t\tctx context.Context\n\t)\n\n\tctx, dbus.cancel = context.WithCancel(context.Background())\n\n\tdbus.broker, err = logind.NewBroker(ctx, constants.DBusServiceSocketPath, constants.DBusClientSocketPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdbus.errCh = make(chan error)\n\n\tgo func() {\n\t\tdbus.errCh <- dbus.broker.Run(ctx)\n\t}()\n\n\tdbus.logindMock, err = logind.NewServiceMock(constants.DBusServiceSocketPath)\n\n\treturn err\n}\n\n// Stop the D-Bus broker and logind mock.\nfunc (dbus *DBusState) Stop() error {\n\tif dbus.cancel == nil {\n\t\treturn nil\n\t}\n\n\tdbus.cancel()\n\n\tif dbus.logindMock == nil || dbus.broker == nil {\n\t\treturn nil\n\t}\n\n\tif err := dbus.logindMock.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := dbus.broker.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase <-time.After(time.Second):\n\t\treturn errors.New(\"timed out stopping D-Bus broker\")\n\tcase err := <-dbus.errCh:\n\t\treturn err\n\t}\n}\n\n// WaitShutdown signals the shutdown over the D-Bus and waits for the inhibit lock to be released.\nfunc (dbus *DBusState) WaitShutdown(ctx context.Context) error {\n\tif dbus.logindMock == nil {\n\t\treturn nil\n\t}\n\n\tif err := dbus.logindMock.EmitShutdown(); err != nil {\n\t\treturn err\n\t}\n\n\treturn dbus.logindMock.WaitLockRelease(ctx)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"sort\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// Events represents the runtime event stream.\n//\n// Events internally is implemented as circular buffer of `runtime.Event`.\n// `e.stream` slice is allocated to the initial capacity and slice size doesn't change\n// throughout the lifetime of Events.\n//\n// To explain the internals, let's call `Publish()` method 'Publisher' (there might be\n// multiple callers for it), and each `Watch()` handler as 'Consumer'.\n//\n// For Publisher, `Events` keeps `e.writePos`, `e.writePos` is write offset into `e.stream`.\n// Offset `e.writePos` is always incremeneted, real write index is `e.writePos % e.cap`\n//\n// Each Consumer captures initial position it starts consumption from as `pos` which is\n// local to each Consumer, as Consumers are free to work on their own pace. Following diagram shows\n// Publisher and three Consumers:\n//\n//\t                                               Consumer 3                         Consumer 2\n//\t                                               pos = 27                           pos = 34\n//\te.stream []Event                               |                                  |\n//\t                                               |                                  |\n//\t+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+\n//\t| 0  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 10 | 11 | 12 | 13 | 14 | 15 | 16 |17  |\n//\t+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+\n//\t                                     |                                  |\n//\t                                     |                                  |\n//\t                                     Consumer 1                         Publisher\n//\t                                     pos = 43                           e.writePos = 50\n//\n// Capacity of Events in this diagram is 18, Publisher published already 50 events, so it\n// already overwrote `e.stream` twice fully.\n//\n// Consumer1 is trying to keep up with the publisher, it has 14-7 = 7 events to catch up.\n//\n// Consumer2 is reading events published by Publisher before last wraparound, it has\n// 50-34 = 16 events to catch up. Consumer 2 has a lot of events to catch up, but as it stays\n// on track, it can still do that.\n//\n// Consumer3 is doing bad: 50-27 = 23 > 18 (capacity), so its read position has already been\n// overwritten, it can't read consistent data,  soit should error out.\n//\n// Synchronization: at the moment single mutex protects `e.stream`  and `e.writePos`, consumers keep their\n// position as local variable, so it doesn't require synchronization. If Consumer catches up with Publisher,\n// it sleeps on condition variable to be woken up by Publisher on next publish.\ntype Events struct {\n\t// stream is used as ring buffer of events\n\tstream []runtime.Event\n\n\t// writePos is the index in streams for the next write (publish)\n\t//\n\t// writePos gets always incremented, real position in slice is (writePos % cap)\n\twritePos int64\n\n\t// cap is a capacity of the stream\n\tcap int\n\t// gap is a safety gap between consumers and publishers\n\tgap int\n\n\t// mutext protects access to writePos and stream\n\tmu sync.Mutex\n\tc  *sync.Cond\n}\n\n// NewEvents initializes and returns the v1alpha1 runtime event stream.\n//\n// Argument cap is a maximum event stream capacity (available event history).\n// Argument gap is a safety gap to separate consumer from the publisher.\n// Maximum available event history is (cap-gap).\nfunc NewEvents(capacity, gap int) *Events {\n\te := &Events{\n\t\tstream: make([]runtime.Event, capacity),\n\t\tcap:    capacity,\n\t\tgap:    gap,\n\t}\n\n\tif gap >= capacity {\n\t\t// we should never reach this, but if we do, panic so that we know.\n\t\tpanic(\"NewEvents: gap >= capacity\")\n\t}\n\n\te.c = sync.NewCond(&e.mu)\n\n\treturn e\n}\n\n// Watch implements the Events interface.\n//\n//nolint:gocyclo\nfunc (e *Events) Watch(f runtime.WatchFunc, opt ...runtime.WatchOptionFunc) error {\n\tvar opts runtime.WatchOptions\n\n\tfor _, o := range opt {\n\t\tif err := o(&opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// context is used to abort the loop when WatchFunc exits\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tch := make(chan runtime.EventInfo)\n\n\tgo func() {\n\t\tdefer ctxCancel()\n\n\t\tf(ch)\n\t}()\n\n\te.mu.Lock()\n\n\t// capture initial consumer position: by default, consumer starts consuming from the next\n\t// event to be published\n\tpos := e.writePos\n\tminPos := e.writePos - int64(e.cap-e.gap)\n\tminPos = max(minPos, 0)\n\n\t// calculate initial position based on options\n\tswitch {\n\tcase opts.TailEvents != 0:\n\t\tif opts.TailEvents < 0 {\n\t\t\tpos = minPos\n\t\t} else {\n\t\t\tpos -= int64(opts.TailEvents)\n\n\t\t\tpos = max(pos, minPos)\n\t\t}\n\tcase !opts.TailID.IsNil():\n\t\tpos = minPos + int64(sort.Search(int(pos-minPos), func(i int) bool {\n\t\t\tevent := e.stream[(minPos+int64(i))%int64(e.cap)]\n\n\t\t\treturn event.ID.Compare(opts.TailID) > 0\n\t\t}))\n\tcase opts.TailDuration != 0:\n\t\ttimestamp := time.Now().Add(-opts.TailDuration)\n\n\t\tpos = minPos + int64(sort.Search(int(pos-minPos), func(i int) bool {\n\t\t\tevent := e.stream[(minPos+int64(i))%int64(e.cap)]\n\n\t\t\treturn event.ID.Time().After(timestamp)\n\t\t}))\n\t}\n\n\te.mu.Unlock()\n\n\tgo func() {\n\t\tdefer close(ch)\n\n\t\tfor {\n\t\t\te.mu.Lock()\n\t\t\t// while there's no data to consume (pos == e.writePos), wait for Condition variable signal,\n\t\t\t// then recheck the condition to be true.\n\t\t\tfor pos == e.writePos {\n\t\t\t\te.c.Wait()\n\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\te.mu.Unlock()\n\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif e.writePos-pos >= int64(e.cap) {\n\t\t\t\t// buffer overrun, there's no way to signal error in this case,\n\t\t\t\t// so for now just return\n\t\t\t\te.mu.Unlock()\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tevent := e.stream[pos%int64(e.cap)]\n\t\t\tpos++\n\t\t\tbacklog := int(e.writePos - pos)\n\n\t\t\te.mu.Unlock()\n\n\t\t\t// if actor id filter is specified and does not match the event, skip it\n\t\t\tif opts.ActorID != \"\" && event.ActorID != opts.ActorID {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// send event to WatchFunc, wait for it to process the event\n\t\t\tselect {\n\t\t\tcase ch <- runtime.EventInfo{\n\t\t\t\tEvent:   event,\n\t\t\t\tBacklog: backlog,\n\t\t\t}:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// Publish implements the Events interface.\nfunc (e *Events) Publish(ctx context.Context, msg proto.Message) {\n\tactorID, ok := ctx.Value(runtime.ActorIDCtxKey{}).(string)\n\tif !ok {\n\t\tactorID = \"\"\n\t}\n\n\tevent := runtime.NewEvent(msg, actorID)\n\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\n\te.stream[e.writePos%int64(e.cap)] = event\n\te.writePos++\n\n\te.c.Broadcast()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_events_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint,testpackage\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"golang.org/x/time/rate\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\nfunc TestEvents_Publish(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcap      int\n\t\twatchers int\n\t\tmessages int\n\t}{\n\t\t{\n\t\t\tname:     \"nowatchers\",\n\t\t\tcap:      100,\n\t\t\twatchers: 0,\n\t\t\tmessages: 100,\n\t\t},\n\t\t{\n\t\t\tname:     \"onemessage\",\n\t\t\tcap:      100,\n\t\t\twatchers: 10,\n\t\t\tmessages: 1,\n\t\t},\n\t\t{\n\t\t\tname:     \"manymessages_singlewatcher\",\n\t\t\tcap:      100,\n\t\t\twatchers: 1,\n\t\t\tmessages: 50,\n\t\t},\n\t\t{\n\t\t\tname:     \"manymessages_manywatchers\",\n\t\t\tcap:      100,\n\t\t\twatchers: 20,\n\t\t\tmessages: 50,\n\t\t},\n\t\t{\n\t\t\tname:     \"manymessages_overcap\",\n\t\t\tcap:      10,\n\t\t\twatchers: 5,\n\t\t\tmessages: 200,\n\t\t},\n\t\t{\n\t\t\tname:     \"megamessages_overcap\",\n\t\t\tcap:      1000,\n\t\t\twatchers: 1,\n\t\t\tmessages: 2000,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\te := NewEvents(tt.cap, tt.cap/10)\n\n\t\t\tvar wg sync.WaitGroup\n\n\t\t\twg.Add(tt.watchers)\n\n\t\t\tgot := uint32(0)\n\n\t\t\tfor range tt.watchers {\n\t\t\t\tif err := e.Watch(func(events <-chan runtime.EventInfo) {\n\t\t\t\t\tdefer wg.Done()\n\n\t\t\t\t\tl := rate.NewLimiter(500, tt.cap*8/10)\n\n\t\t\t\t\tfor j := range tt.messages {\n\t\t\t\t\t\tevent, ok := <-events\n\n\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\t// on buffer overrun Watch() closes the channel\n\t\t\t\t\t\t\tt.Fatalf(\"buffer overrun\")\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tseq, err := strconv.Atoi(event.Payload.(*machine.SequenceEvent).Sequence)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tt.Fatalf(\"failed to convert sequence to number: %s\", err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif seq != j {\n\t\t\t\t\t\t\tt.Fatalf(\"unexpected sequence: %d != %d\", seq, j)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tatomic.AddUint32(&got, 1)\n\n\t\t\t\t\t\t_ = l.Wait(t.Context()) //nolint:errcheck\n\t\t\t\t\t}\n\t\t\t\t}); err != nil {\n\t\t\t\t\tt.Errorf(\"Watch error %s\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tl := rate.NewLimiter(500, tt.cap/2)\n\n\t\t\tfor i := range tt.messages {\n\t\t\t\t_ = l.Wait(t.Context()) //nolint:errcheck\n\n\t\t\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\t\t\tSequence: strconv.Itoa(i),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\twg.Wait()\n\n\t\t\tif got != uint32(tt.messages*tt.watchers) {\n\t\t\t\tt.Errorf(\"Watch() = got %v, want %v\", got, tt.messages*tt.watchers)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc receive(t *testing.T, e runtime.Watcher, n int, opts ...runtime.WatchOptionFunc) (result []runtime.EventInfo) {\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\n\tif err := e.Watch(func(events <-chan runtime.EventInfo) {\n\t\tdefer wg.Done()\n\n\t\tfor range n {\n\t\t\tevent, ok := <-events\n\t\t\tif !ok {\n\t\t\t\tt.Fatalf(\"Watch: chanel closed\")\n\t\t\t}\n\n\t\t\tresult = append(result, event)\n\t\t}\n\n\t\tselect {\n\t\tcase _, ok := <-events:\n\t\t\tif ok {\n\t\t\t\tt.Fatal(\"received extra events\")\n\t\t\t} else {\n\t\t\t\tt.Fatalf(\"Watch: chanel closed\")\n\t\t\t}\n\t\tcase <-time.After(50 * time.Millisecond):\n\t\t}\n\t}, opts...); err != nil {\n\t\tt.Fatalf(\"Watch() error %s\", err)\n\t}\n\n\twg.Wait()\n\n\treturn result\n}\n\nfunc extractSeq(t *testing.T, events []runtime.EventInfo) (result []int) {\n\tfor _, event := range events {\n\t\tseq, err := strconv.Atoi(event.Payload.(*machine.SequenceEvent).Sequence)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"failed to convert sequence to number: %s\", err)\n\t\t}\n\n\t\tresult = append(result, seq)\n\t}\n\n\treturn result\n}\n\nfunc gen(k, l int) (result []int) {\n\tfor j := k; j < l; j++ {\n\t\tresult = append(result, j)\n\t}\n\n\treturn result\n}\n\nfunc TestEvents_WatchOptionsTailEvents(t *testing.T) {\n\te := NewEvents(100, 10)\n\n\tfor i := range 200 {\n\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\tSequence: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tassert.Equal(t, []int(nil), extractSeq(t, receive(t, e, 0)))\n\tassert.Equal(t, gen(199, 200), extractSeq(t, receive(t, e, 1, runtime.WithTailEvents(1))))\n\tassert.Equal(t, gen(195, 200), extractSeq(t, receive(t, e, 5, runtime.WithTailEvents(5))))\n\tassert.Equal(t, gen(111, 200), extractSeq(t, receive(t, e, 89, runtime.WithTailEvents(89))))\n\tassert.Equal(t, gen(110, 200), extractSeq(t, receive(t, e, 90, runtime.WithTailEvents(90))))\n\tassert.Equal(t, gen(110, 200), extractSeq(t, receive(t, e, 90, runtime.WithTailEvents(91))))   // can't tail more than cap-gap\n\tassert.Equal(t, gen(110, 200), extractSeq(t, receive(t, e, 90, runtime.WithTailEvents(1000)))) // can't tail more than cap-gap\n\tassert.Equal(t, gen(110, 200), extractSeq(t, receive(t, e, 90, runtime.WithTailEvents(-1))))   // tail all events\n\n\te = NewEvents(100, 10)\n\n\tfor i := range 30 {\n\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\tSequence: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tassert.Equal(t, []int(nil), extractSeq(t, receive(t, e, 0)))\n\tassert.Equal(t, gen(29, 30), extractSeq(t, receive(t, e, 1, runtime.WithTailEvents(1))))\n\tassert.Equal(t, gen(28, 30), extractSeq(t, receive(t, e, 2, runtime.WithTailEvents(2))))\n\tassert.Equal(t, gen(25, 30), extractSeq(t, receive(t, e, 5, runtime.WithTailEvents(5))))\n\tassert.Equal(t, gen(0, 30), extractSeq(t, receive(t, e, 30, runtime.WithTailEvents(40))))\n}\n\nfunc TestEvents_WatchOptionsTailSeconds(t *testing.T) {\n\te := NewEvents(100, 10)\n\n\tfor i := range 20 {\n\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\tSequence: strconv.Itoa(i),\n\t\t})\n\t}\n\n\t// sleep to get time gap between two series of events\n\ttime.Sleep(3 * time.Second)\n\n\tfor i := 20; i < 30; i++ {\n\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\tSequence: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tassert.Equal(t, []int(nil), extractSeq(t, receive(t, e, 0, runtime.WithTailDuration(0))))\n\tassert.Equal(t, gen(20, 30), extractSeq(t, receive(t, e, 10, runtime.WithTailDuration(2*time.Second))))\n\tassert.Equal(t, gen(0, 30), extractSeq(t, receive(t, e, 30, runtime.WithTailDuration(10*time.Second))))\n}\n\nfunc TestEvents_WatchOptionsTailID(t *testing.T) {\n\te := NewEvents(100, 10)\n\n\tfor i := range 20 {\n\t\te.Publish(t.Context(), &machine.SequenceEvent{\n\t\t\tSequence: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tevents := receive(t, e, 20, runtime.WithTailEvents(-1))\n\n\tfor i, event := range events {\n\t\tassert.Equal(t, gen(i+1, 20), extractSeq(t, receive(t, e, 20-i-1, runtime.WithTailID(event.ID))))\n\t}\n}\n\nfunc BenchmarkWatch(b *testing.B) {\n\te := NewEvents(100, 10)\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(b.N)\n\n\tfor range b.N {\n\t\t_ = e.Watch(func(events <-chan runtime.EventInfo) { wg.Done() }) //nolint:errcheck\n\t}\n\n\twg.Wait()\n}\n\nfunc BenchmarkPublish(bb *testing.B) {\n\tfor _, watchers := range []int{0, 1, 10} {\n\t\tbb.Run(fmt.Sprintf(\"Watchers-%d\", watchers), func(b *testing.B) {\n\t\t\te := NewEvents(10000, 10)\n\n\t\t\tvar wg sync.WaitGroup\n\n\t\t\twatchers := 10\n\n\t\t\twg.Add(watchers)\n\n\t\t\tfor range watchers {\n\t\t\t\t_ = e.Watch(func(events <-chan runtime.EventInfo) { //nolint:errcheck\n\t\t\t\t\tdefer wg.Done()\n\n\t\t\t\t\tfor range b.N {\n\t\t\t\t\t\tif _, ok := <-events; !ok {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tev := machine.SequenceEvent{}\n\n\t\t\tb.ResetTimer()\n\n\t\t\tfor range b.N {\n\t\t\t\te.Publish(bb.Context(), &ev)\n\t\t\t}\n\n\t\t\twg.Wait()\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_priority_lock.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// Priority describes the running priority of a process.\n//\n// If CanTakeOver returns true, current process with \"lower\" priority\n// will be canceled and \"higher\" priority process will be run.\ntype Priority[T any] interface {\n\tcomparable\n\tCanTakeOver(another T) bool\n}\n\n// PriorityLock is a lock that makes sure that only a single process can run at a time.\n//\n// If a process with \"higher\" priority tries to acquire the lock, previous process is stopped\n// and new process with \"higher\" priority is run.\ntype PriorityLock[T Priority[T]] struct {\n\trunningCh  chan struct{}\n\ttakeoverCh chan struct{}\n\n\tmu              sync.Mutex\n\trunningPriority T\n\tcancelCtx       context.CancelFunc\n}\n\n// NewPriorityLock returns a new PriorityLock.\nfunc NewPriorityLock[T Priority[T]]() *PriorityLock[T] {\n\trunningCh := make(chan struct{}, 1)\n\trunningCh <- struct{}{}\n\n\treturn &PriorityLock[T]{\n\t\trunningCh:  runningCh,\n\t\ttakeoverCh: make(chan struct{}, 1),\n\t}\n}\n\nfunc (lock *PriorityLock[T]) getRunningPriority() (T, context.CancelFunc) {\n\tlock.mu.Lock()\n\tdefer lock.mu.Unlock()\n\n\treturn lock.runningPriority, lock.cancelCtx\n}\n\nfunc (lock *PriorityLock[T]) setRunningPriority(seq T, cancelCtx context.CancelFunc) {\n\tlock.mu.Lock()\n\tdefer lock.mu.Unlock()\n\n\tvar zeroSeq T\n\n\tif seq == zeroSeq && lock.cancelCtx != nil {\n\t\tlock.cancelCtx()\n\t}\n\n\tlock.runningPriority, lock.cancelCtx = seq, cancelCtx\n}\n\n// Lock acquires the lock according the priority rules and returns a context that should be used within the process.\n//\n// Process should terminate as soon as the context is canceled.\n// Argument seq defines the priority of the process.\n// Argument takeOverTimeout defines the maximum time to wait for the low-priority process to terminate.\nfunc (lock *PriorityLock[T]) Lock(ctx context.Context, takeOverTimeout time.Duration, seq T, options ...runtime.LockOption) (context.Context, error) {\n\topts := runtime.DefaultControllerOptions()\n\tfor _, o := range options {\n\t\tif err := o(&opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\ttakeOverTimer := time.NewTimer(takeOverTimeout)\n\tdefer takeOverTimer.Stop()\n\n\tselect {\n\tcase lock.takeoverCh <- struct{}{}:\n\tcase <-takeOverTimer.C:\n\t\treturn nil, errors.New(\"failed to acquire lock: timeout\")\n\t}\n\n\tdefer func() {\n\t\t<-lock.takeoverCh\n\t}()\n\n\tsequence, cancelCtx := lock.getRunningPriority()\n\n\tif !seq.CanTakeOver(sequence) && !opts.Takeover {\n\t\treturn nil, runtime.ErrLocked\n\t}\n\n\tif cancelCtx != nil {\n\t\tcancelCtx()\n\t}\n\n\tselect {\n\tcase <-lock.runningCh:\n\t\tseqCtx, seqCancel := context.WithCancel(ctx)\n\t\tlock.setRunningPriority(seq, seqCancel)\n\n\t\treturn seqCtx, nil\n\tcase <-takeOverTimer.C:\n\t\treturn nil, errors.New(\"failed to acquire lock: timeout\")\n\t}\n}\n\n// Unlock releases the lock.\nfunc (lock *PriorityLock[T]) Unlock() {\n\tvar zeroSeq T\n\n\tlock.setRunningPriority(zeroSeq, nil)\n\n\tlock.runningCh <- struct{}{}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_priority_lock_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1\"\n)\n\ntype testSequenceNumber int\n\nfunc (candidate testSequenceNumber) CanTakeOver(running testSequenceNumber) bool {\n\treturn candidate > running\n}\n\nfunc TestPriorityLock(t *testing.T) {\n\trequire := require.New(t)\n\n\tlock := v1alpha1.NewPriorityLock[testSequenceNumber]()\n\tctx := t.Context()\n\n\tctx1, err := lock.Lock(ctx, time.Second, 2)\n\trequire.NoError(err)\n\n\tselect {\n\tcase <-ctx1.Done():\n\t\trequire.FailNow(\"should not be canceled\")\n\tdefault:\n\t}\n\n\t_, err = lock.Lock(ctx, time.Millisecond, 1)\n\trequire.Error(err)\n\trequire.EqualError(err, runtime.ErrLocked.Error())\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\t_, err2 := lock.Lock(ctx, time.Second, 3)\n\t\terrCh <- err2\n\t}()\n\n\tselect {\n\tcase <-ctx1.Done():\n\tcase <-time.After(time.Second):\n\t\trequire.FailNow(\"should be canceled\")\n\t}\n\n\tselect {\n\tcase <-errCh:\n\t\trequire.FailNow(\"should not be reached\")\n\tdefault:\n\t}\n\n\tlock.Unlock()\n\n\tselect {\n\tcase err = <-errCh:\n\t\trequire.NoError(err)\n\tcase <-time.After(time.Second):\n\t\trequire.FailNow(\"should be canceled\")\n\t}\n}\n\nfunc TestPriorityLockSequential(t *testing.T) {\n\trequire := require.New(t)\n\n\tlock := v1alpha1.NewPriorityLock[testSequenceNumber]()\n\tctx := t.Context()\n\n\t_, err := lock.Lock(ctx, time.Second, 2)\n\trequire.NoError(err)\n\n\tlock.Unlock()\n\n\t_, err = lock.Lock(ctx, time.Second, 1)\n\trequire.NoError(err)\n\n\tlock.Unlock()\n}\n\n//nolint:gocyclo\nfunc TestPriorityLockConcurrent(t *testing.T) {\n\trequire := require.New(t)\n\n\tlock := v1alpha1.NewPriorityLock[testSequenceNumber]()\n\n\tglobalCtx, globalCtxCancel := context.WithCancel(t.Context())\n\tdefer globalCtxCancel()\n\n\tvar eg errgroup.Group\n\n\tsequenceCh := make(chan testSequenceNumber)\n\n\tfor seq := testSequenceNumber(1); seq <= 20; seq++ {\n\t\teg.Go(func() error {\n\t\t\tctx, err := lock.Lock(globalCtx, time.Second, seq)\n\t\t\tif errors.Is(err, runtime.ErrLocked) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase sequenceCh <- seq:\n\t\t\t\t<-ctx.Done()\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\n\t\t\tlock.Unlock()\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\ttimer := time.NewTimer(5 * time.Second)\n\tdefer timer.Stop()\n\n\tvar prevSeq testSequenceNumber\n\n\tfor {\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\trequire.FailNow(\"timeout\")\n\t\tcase seq := <-sequenceCh:\n\t\t\tt.Logf(\"sequence running: %d\", seq)\n\n\t\t\tif prevSeq >= seq {\n\t\t\t\trequire.FailNowf(\"can take over inversion\", \"sequence %d should be greater than %d\", seq, prevSeq)\n\t\t\t}\n\n\t\t\tprevSeq = seq\n\t\t}\n\n\t\tif prevSeq == 20 {\n\t\t\tglobalCtxCancel()\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\trequire.NoError(eg.Wait())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configdiff\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tmachineconfig \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// Runtime implements the Runtime interface.\ntype Runtime struct {\n\ts runtime.State\n\te runtime.EventStream\n\tl runtime.LoggingManager\n\n\trollbackTimerMu sync.Mutex\n\trollbackTimer   *time.Timer\n}\n\n// NewRuntime initializes and returns the v1alpha1 runtime.\nfunc NewRuntime(s runtime.State, e runtime.EventStream, l runtime.LoggingManager) *Runtime {\n\treturn &Runtime{\n\t\ts: s,\n\t\te: e,\n\t\tl: l,\n\t}\n}\n\nfunc (r *Runtime) configProvider() config.Provider {\n\tcfg, err := r.s.V1Alpha2().GetConfig(context.TODO())\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn cfg\n}\n\n// Config implements the Runtime interface.\nfunc (r *Runtime) Config() config.Config {\n\tcfg := r.configProvider()\n\n\tif cfg == nil {\n\t\treturn nil\n\t}\n\n\treturn cfg\n}\n\n// ConfigCompleteForBoot implements the Runtime interface.\nfunc (r *Runtime) ConfigCompleteForBoot() bool {\n\tcfg := r.configProvider()\n\n\tif cfg == nil {\n\t\treturn false\n\t}\n\n\treturn cfg.CompleteForBoot()\n}\n\n// ConfigContainer implements the Runtime interface.\nfunc (r *Runtime) ConfigContainer() config.Container {\n\tcfg := r.configProvider()\n\n\tif cfg == nil {\n\t\treturn nil\n\t}\n\n\treturn cfg\n}\n\n// RollbackToConfigAfter implements the Runtime interface.\nfunc (r *Runtime) RollbackToConfigAfter(timeout time.Duration) error {\n\tcfgProvider := r.configProvider()\n\n\tr.CancelConfigRollbackTimeout()\n\n\tr.rollbackTimer = time.AfterFunc(timeout, func() {\n\t\tlog.Println(\"rolling back the configuration\")\n\n\t\tif err := r.SetConfig(cfgProvider); err != nil {\n\t\t\tlog.Printf(\"config rollback failed %s\", err)\n\t\t}\n\t})\n\n\treturn nil\n}\n\n// CancelConfigRollbackTimeout implements the Runtime interface.\nfunc (r *Runtime) CancelConfigRollbackTimeout() {\n\tr.rollbackTimerMu.Lock()\n\tdefer r.rollbackTimerMu.Unlock()\n\n\tif r.rollbackTimer != nil {\n\t\tr.rollbackTimer.Stop()\n\t\tr.rollbackTimer = nil\n\t}\n}\n\n// SetConfig implements the Runtime interface.\nfunc (r *Runtime) SetConfig(cfg config.Provider) error {\n\treturn r.s.V1Alpha2().SetConfig(context.TODO(), machineconfig.ActiveID, cfg)\n}\n\n// SetPersistedConfig implements the Runtime interface.\nfunc (r *Runtime) SetPersistedConfig(cfg config.Provider) error {\n\treturn r.s.V1Alpha2().SetConfig(context.TODO(), machineconfig.PersistentID, cfg)\n}\n\n// CanApplyImmediate implements the Runtime interface.\nfunc (r *Runtime) CanApplyImmediate(cfg config.Provider) error {\n\tcfgProv := r.configProvider()\n\tif cfgProv == nil {\n\t\treturn errors.New(\"no current config\")\n\t}\n\n\tcurrentConfig := cfgProv.RawV1Alpha1()\n\tif currentConfig == nil {\n\t\treturn errors.New(\"current config is not v1alpha1\")\n\t}\n\n\tnewConfig := cfg.RawV1Alpha1()\n\tif newConfig == nil {\n\t\treturn errors.New(\"new config is not v1alpha1\")\n\t}\n\n\t// copy the config as we're going to modify it\n\tnewConfig = newConfig.DeepCopy()\n\n\t// the config changes allowed to be applied immediately are:\n\t// * .debug\n\t// * .cluster\n\t// * .machine.ca\n\t// * .machine.acceptedCAs\n\t// * .machine.time\n\t// * .machine.certCANs\n\t// * .machine.install\n\t// * .machine.network\n\t// * .machine.sysfs\n\t// * .machine.sysctls\n\t// * .machine.logging\n\t// * .machine.controlplane\n\t// * .machine.kubelet\n\t// * .machine.kernel\n\t// * .machine.registries (note that auth is not applied immediately, containerd limitation)\n\t// * .machine.pods\n\t// * .machine.seccompProfiles\n\t// * .machine.nodeAnnotations\n\t// * .machine.nodeLabels\n\t// * .machine.nodeTaints\n\t// * .machine.features.kubernetesTalosAPIAccess\n\t// * .machine.features.kubePrism\n\t// * .machine.features.hostDNS\n\t// * .machine.features.imageCache\n\t// * .machine.features.nodeAddressSortAlgorithm\n\tnewConfig.ConfigDebug = currentConfig.ConfigDebug\n\tnewConfig.ClusterConfig = currentConfig.ClusterConfig\n\n\tif newConfig.MachineConfig != nil && currentConfig.MachineConfig != nil {\n\t\tnewConfig.MachineConfig.MachineCA = currentConfig.MachineConfig.MachineCA\n\t\tnewConfig.MachineConfig.MachineAcceptedCAs = currentConfig.MachineConfig.MachineAcceptedCAs\n\t\tnewConfig.MachineConfig.MachineTime = currentConfig.MachineConfig.MachineTime //nolint:staticcheck\n\t\tnewConfig.MachineConfig.MachineCertSANs = currentConfig.MachineConfig.MachineCertSANs\n\t\tnewConfig.MachineConfig.MachineInstall = currentConfig.MachineConfig.MachineInstall\n\t\tnewConfig.MachineConfig.MachineNetwork = currentConfig.MachineConfig.MachineNetwork //nolint:staticcheck\n\t\tnewConfig.MachineConfig.MachineSysfs = currentConfig.MachineConfig.MachineSysfs\n\t\tnewConfig.MachineConfig.MachineSysctls = currentConfig.MachineConfig.MachineSysctls\n\t\tnewConfig.MachineConfig.MachineLogging = currentConfig.MachineConfig.MachineLogging\n\t\tnewConfig.MachineConfig.MachineControlPlane = currentConfig.MachineConfig.MachineControlPlane\n\t\tnewConfig.MachineConfig.MachineKubelet = currentConfig.MachineConfig.MachineKubelet\n\t\tnewConfig.MachineConfig.MachineKernel = currentConfig.MachineConfig.MachineKernel\n\t\tnewConfig.MachineConfig.MachineRegistries = currentConfig.MachineConfig.MachineRegistries //nolint:staticcheck // backwards compatibility\n\t\tnewConfig.MachineConfig.MachinePods = currentConfig.MachineConfig.MachinePods\n\t\tnewConfig.MachineConfig.MachineSeccompProfiles = currentConfig.MachineConfig.MachineSeccompProfiles\n\t\tnewConfig.MachineConfig.MachineNodeAnnotations = currentConfig.MachineConfig.MachineNodeAnnotations\n\t\tnewConfig.MachineConfig.MachineNodeLabels = currentConfig.MachineConfig.MachineNodeLabels\n\t\tnewConfig.MachineConfig.MachineNodeTaints = currentConfig.MachineConfig.MachineNodeTaints\n\n\t\tif newConfig.MachineConfig.MachineFeatures != nil && currentConfig.MachineConfig.MachineFeatures != nil {\n\t\t\tnewConfig.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig = currentConfig.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig\n\t\t\tnewConfig.MachineConfig.MachineFeatures.KubePrismSupport = currentConfig.MachineConfig.MachineFeatures.KubePrismSupport\n\t\t\tnewConfig.MachineConfig.MachineFeatures.HostDNSSupport = currentConfig.MachineConfig.MachineFeatures.HostDNSSupport\n\t\t\tnewConfig.MachineConfig.MachineFeatures.ImageCacheSupport = currentConfig.MachineConfig.MachineFeatures.ImageCacheSupport\n\t\t\tnewConfig.MachineConfig.MachineFeatures.FeatureNodeAddressSortAlgorithm = currentConfig.MachineConfig.MachineFeatures.FeatureNodeAddressSortAlgorithm\n\t\t}\n\t}\n\n\tif !reflect.DeepEqual(currentConfig, newConfig) {\n\t\tdiff, err := configdiff.DiffConfigs(container.NewV1Alpha1(currentConfig), container.NewV1Alpha1(newConfig))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error calculating diff: %w\", err)\n\t\t}\n\n\t\treturn fmt.Errorf(\"this config change can't be applied in immediate mode\\ndiff:\\n%s\", diff)\n\t}\n\n\treturn nil\n}\n\n// State implements the Runtime interface.\nfunc (r *Runtime) State() runtime.State {\n\treturn r.s\n}\n\n// Events implements the Runtime interface.\nfunc (r *Runtime) Events() runtime.EventStream {\n\treturn r.e\n}\n\n// Logging implements the Runtime interface.\nfunc (r *Runtime) Logging() runtime.LoggingManager {\n\treturn r.l\n}\n\n// NodeName implements the Runtime interface.\nfunc (r *Runtime) NodeName() (string, error) {\n\tnodenameResource, err := safe.ReaderGet[*k8s.Nodename](\n\t\tcontext.Background(),\n\t\tr.s.V1Alpha2().Resources(),\n\t\tresource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, k8s.NodenameID, resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error getting nodename resource: %w\", err)\n\t}\n\n\treturn nodenameResource.TypedSpec().Nodename, nil\n}\n\n// IsBootstrapAllowed checks for CRI to be up, checked in the bootstrap method.\nfunc (r *Runtime) IsBootstrapAllowed() bool {\n\tctx, cancel := context.WithTimeout(context.Background(), time.Second)\n\tdefer cancel()\n\n\tsvc := &services.CRI{}\n\tif err := system.WaitForService(system.StateEventUp, svc.ID(r)).Wait(ctx); err != nil {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// GetSystemInformation returns system information resource if it exists.\nfunc (r *Runtime) GetSystemInformation(ctx context.Context) (*hardware.SystemInformation, error) {\n\treturn safe.StateGet[*hardware.SystemInformation](ctx, r.State().V1Alpha2().Resources(), hardware.NewSystemInformation(hardware.SystemInformationID).Metadata())\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/imageropts\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n)\n\n// Sequencer implements the sequencer interface.\ntype Sequencer struct{}\n\n// NewSequencer intializes and returns a sequencer.\nfunc NewSequencer() *Sequencer {\n\treturn &Sequencer{}\n}\n\n// PhaseList represents a list of phases.\ntype PhaseList []runtime.Phase\n\n// Append appends a task to the phase list.\nfunc (p PhaseList) Append(name string, tasks ...runtime.TaskSetupFunc) PhaseList {\n\tp = append(p, runtime.Phase{\n\t\tName:  name,\n\t\tTasks: tasks,\n\t})\n\n\treturn p\n}\n\n// AppendWhen appends a task to the phase list when `when` is `true`.\nfunc (p PhaseList) AppendWhen(when bool, name string, tasks ...runtime.TaskSetupFunc) PhaseList {\n\tif when {\n\t\tp = p.Append(name, tasks...)\n\t}\n\n\treturn p\n}\n\n// AppendWithDeferredCheck appends a task to the phase list but skips the sequence if `check func()` returns `false` during execution.\nfunc (p PhaseList) AppendWithDeferredCheck(check func() bool, name string, tasks ...runtime.TaskSetupFunc) PhaseList {\n\tp = append(p, runtime.Phase{\n\t\tName:      name,\n\t\tTasks:     tasks,\n\t\tCheckFunc: check,\n\t})\n\n\treturn p\n}\n\n// AppendList appends an additional PhaseList to the existing one.\nfunc (p PhaseList) AppendList(list PhaseList) PhaseList {\n\treturn append(p, list...)\n}\n\n// Initialize is the initialize sequence. The primary goals of this sequence is\n// to load the config and enforce kernel security requirements.\nfunc (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase {\n\tmode := r.State().Platform().Mode()\n\tphases := PhaseList{}\n\n\tswitch mode { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\tphases = phases.Append(\n\t\t\t\"machined\",\n\t\t\tStartApid,\n\t\t\tStartMachined,\n\t\t\tStartContainerd,\n\t\t).Append(\n\t\t\t\"config\",\n\t\t\tLoadConfig,\n\t\t)\n\tdefault:\n\t\tphases = phases.Append(\n\t\t\t\"systemRequirements\",\n\t\t\tEnforceKSPPRequirements,\n\t\t).Append(\n\t\t\t\"earlyServices\",\n\t\t\tStartUdevd,\n\t\t\tStartMachined,\n\t\t\tStartApid,\n\t\t\tStartAuditd,\n\t\t\tStartSyslogd,\n\t\t\tStartContainerd,\n\t\t).Append(\n\t\t\t\"usb\",\n\t\t\tWaitForUSB,\n\t\t).Append(\n\t\t\t\"meta\",\n\t\t\tReloadMeta,\n\t\t).AppendWithDeferredCheck(\n\t\t\tfunc() bool {\n\t\t\t\tval, ok := r.State().Machine().Meta().ReadTag(meta.DiskImageBootloader)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\treturn r.State().Machine().Installed() && val == imageropts.BootLoaderKindDualBoot.String()\n\t\t\t},\n\t\t\t\"cleanupBootloader\",\n\t\t\tCleanupBootloader,\n\t\t).AppendWithDeferredCheck(\n\t\t\tfunc() bool {\n\t\t\t\tif mode == runtime.ModeMetalAgent {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tdisabledStr := procfs.ProcCmdline().Get(constants.KernelParamDashboardDisabled).First()\n\t\t\t\tdisabled, _ := strconv.ParseBool(pointer.SafeDeref(disabledStr)) //nolint:errcheck\n\n\t\t\t\treturn !disabled\n\t\t\t},\n\t\t\t\"dashboard\",\n\t\t\tStartDashboard,\n\t\t).AppendWithDeferredCheck(\n\t\t\tfunc() bool {\n\t\t\t\twipe := procfs.ProcCmdline().Get(constants.KernelParamWipe).First()\n\n\t\t\t\treturn pointer.SafeDeref(wipe) != \"\"\n\t\t\t},\n\t\t\t\"wipeDisks\",\n\t\t\tResetSystemDiskPartitions,\n\t\t).AppendWithDeferredCheck(\n\t\t\tfunc() bool {\n\t\t\t\thaltIfInstalledStr := procfs.ProcCmdline().Get(constants.KernelParamHaltIfInstalled).First()\n\t\t\t\thaltIfInstalled, _ := strconv.ParseBool(pointer.SafeDeref(haltIfInstalledStr)) //nolint:errcheck\n\n\t\t\t\treturn r.State().Machine().Installed() && haltIfInstalled\n\t\t\t},\n\t\t\t\"haltIfInstalled\",\n\t\t\thaltIfInstalled,\n\t\t).Append(\n\t\t\t\"config\",\n\t\t\tLoadConfig,\n\t\t)\n\t}\n\n\treturn phases\n}\n\n// Install is the install sequence.\nfunc (*Sequencer) Install(r runtime.Runtime) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\treturn nil\n\tdefault:\n\t\tif !r.State().Machine().Installed() || r.State().Machine().IsInstallStaged() {\n\t\t\tphases = phases.Append(\n\t\t\t\t\"env\",\n\t\t\t\tSetUserEnvVars,\n\t\t\t).Append(\n\t\t\t\t\"install\",\n\t\t\t\tInstall,\n\t\t\t).Append(\n\t\t\t\t\"meta\",\n\t\t\t\tReloadMeta,\n\t\t\t).Append(\n\t\t\t\t\"saveMeta\", // saving META here to merge in-memory changes with the on-disk ones from the installer\n\t\t\t\tFlushMeta,\n\t\t\t).Append(\n\t\t\t\t\"volumeFinalize\",\n\t\t\t\tTeardownVolumeLifecycle,\n\t\t\t).Append(\n\t\t\t\t\"stopEverything\",\n\t\t\t\tStopAllServices,\n\t\t\t).Append(\n\t\t\t\t\"kexec\",\n\t\t\t\tKexecPrepare,\n\t\t\t).Append(\n\t\t\t\t\"reboot\",\n\t\t\t\tReboot,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn phases\n}\n\n// Boot is the boot sequence. This primary goal if this sequence is to apply\n// user supplied settings and start the services for the specific machine type.\n// This sequence should never be reached if an installation is not found.\nfunc (*Sequencer) Boot(r runtime.Runtime) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tphases = phases.Append(\n\t\t\"memorySizeCheck\",\n\t\tMemorySizeCheck,\n\t).Append(\n\t\t\"diskSizeCheck\",\n\t\tDiskSizeCheck,\n\t).Append(\n\t\t\"env\",\n\t\tSetUserEnvVars,\n\t\tWaitForCARoots,\n\t).Append(\n\t\t\"dbus\",\n\t\tStartDBus,\n\t).AppendWhen(\n\t\tr.State().Platform().Mode() == runtime.ModeContainer,\n\t\t\"sharedFilesystems\",\n\t\tSetupSharedFilesystems,\n\t).Append(\n\t\t\"ephemeral\",\n\t\tMountEphemeralPartition,\n\t).AppendWhen(\n\t\tr.State().Platform().Mode() != runtime.ModeContainer,\n\t\t\"udevSetup\",\n\t\tWriteUdevRules,\n\t).AppendWhen(\n\t\tr.State().Platform().Mode() != runtime.ModeContainer,\n\t\t\"userDisks\",\n\t\tpauseOnFailure(MountUserDisks, constants.FailurePauseTimeout),\n\t).Append(\n\t\t\"userSetup\",\n\t\tpauseOnFailure(WriteUserFiles, constants.FailurePauseTimeout),\n\t).Append(\n\t\t\"startEverything\",\n\t\tStartAllServices,\n\t)\n\n\treturn phases\n}\n\n// Reboot is the reboot sequence.\nfunc (*Sequencer) Reboot(r runtime.Runtime, in *machineapi.RebootRequest) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tif in.GetMode() != machineapi.RebootRequest_FORCE {\n\t\tphases = phases.\n\t\t\tAppend(\n\t\t\t\t\"cleanup\",\n\t\t\t\tStopAllPods,\n\t\t\t).\n\t\t\tAppend(\n\t\t\t\t\"dbus\",\n\t\t\t\tStopDBus,\n\t\t\t).\n\t\t\tAppendList(stopAllPhaselist(r, true))\n\t}\n\n\treturn phases.Append(\"reboot\", Reboot)\n}\n\n// Reset is the reset sequence.\n//\n//nolint:gocyclo\nfunc (*Sequencer) Reset(r runtime.Runtime, in runtime.ResetOptions) []runtime.Phase {\n\tphases := PhaseList{}\n\n\t// Use kexec if we don't wipe the boot partition.\n\twithKexec := false\n\tif len(in.GetSystemDiskTargets()) > 0 {\n\t\twithKexec = !bootPartitionInTargets(in.GetSystemDiskTargets())\n\t}\n\n\tvar (\n\t\tresetUserDisks  bool\n\t\tresetSystemDisk bool\n\t)\n\n\tswitch in.GetMode() {\n\tcase machineapi.ResetRequest_ALL:\n\t\tresetUserDisks = true\n\t\tresetSystemDisk = true\n\tcase machineapi.ResetRequest_USER_DISKS:\n\t\tresetUserDisks = true\n\tcase machineapi.ResetRequest_SYSTEM_DISK:\n\t\tresetSystemDisk = true\n\t}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\tphases = phases.AppendList(stopAllPhaselist(r, false)).\n\t\t\tAppend(\n\t\t\t\t\"shutdown\",\n\t\t\t\tShutdown,\n\t\t\t)\n\tdefault:\n\t\tphases = phases.AppendWhen(\n\t\t\tin.GetGraceful() && !r.Config().Machine().Kubelet().SkipNodeRegistration(),\n\t\t\t\"drain\",\n\t\t\ttaskErrorHandler(logError, CordonAndDrainNode),\n\t\t).AppendWhen(\n\t\t\tin.GetGraceful(),\n\t\t\t\"cleanup\",\n\t\t\ttaskErrorHandler(logError, RemoveAllPods),\n\t\t).AppendWhen(\n\t\t\t!in.GetGraceful(),\n\t\t\t\"cleanup\",\n\t\t\ttaskErrorHandler(logError, StopAllPods),\n\t\t).Append(\n\t\t\t\"dbus\",\n\t\t\tStopDBus,\n\t\t).AppendWhen(\n\t\t\tin.GetGraceful() && (r.Config().Machine().Type() != machine.TypeWorker),\n\t\t\t\"leave\",\n\t\t\tLeaveEtcd,\n\t\t).Append(\n\t\t\t\"preReset\",\n\t\t\tSendResetSignal,\n\t\t).AppendList(\n\t\t\tphaseListErrorHandler(logError, stopAllPhaselist(r, withKexec)...),\n\t\t).Append(\n\t\t\t\"forceCleanup\",\n\t\t\tForceCleanup,\n\t\t).AppendWhen(\n\t\t\tlen(in.GetSystemDiskTargets()) == 0 && resetSystemDisk,\n\t\t\t\"reset\",\n\t\t\tResetSystemDisk,\n\t\t).AppendWhen(\n\t\t\tlen(in.GetSystemDiskTargets()) > 0 && resetSystemDisk,\n\t\t\t\"resetSpec\",\n\t\t\tResetSystemDiskSpec,\n\t\t).AppendWhen(\n\t\t\tlen(in.GetUserDisksToWipe()) > 0 && resetUserDisks,\n\t\t\t\"resetUserDisks\",\n\t\t\tResetUserDisks,\n\t\t).AppendWhen(\n\t\t\tin.GetReboot(),\n\t\t\t\"reboot\",\n\t\t\tReboot,\n\t\t).AppendWhen(\n\t\t\t!in.GetReboot(),\n\t\t\t\"shutdown\",\n\t\t\tShutdown,\n\t\t)\n\t}\n\n\treturn phases\n}\n\n// Shutdown is the shutdown sequence.\nfunc (*Sequencer) Shutdown(r runtime.Runtime, in *machineapi.ShutdownRequest) []runtime.Phase {\n\tskipNodeRegistration := r.Config() != nil && r.Config().Machine() != nil && r.Config().Machine().Kubelet().SkipNodeRegistration()\n\n\tphases := PhaseList{}.Append(\n\t\t\"storeShutdown\",\n\t\tStoreShutdownEmergency,\n\t).AppendWhen(\n\t\t!in.GetForce() && !skipNodeRegistration,\n\t\t\"drain\",\n\t\tCordonAndDrainNode,\n\t).Append(\n\t\t\"cleanup\",\n\t\tStopAllPods,\n\t).Append(\n\t\t\"dbus\",\n\t\tStopDBus,\n\t).\n\t\tAppendList(stopAllPhaselist(r, false)).\n\t\tAppend(\"shutdown\", Shutdown)\n\n\treturn phases\n}\n\n// StageUpgrade is the stage upgrade sequence.\nfunc (*Sequencer) StageUpgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\treturn nil\n\tdefault:\n\t\tphases = phases.Append(\n\t\t\t\"cleanup\",\n\t\t\tStopAllPods,\n\t\t).Append(\n\t\t\t\"dbus\",\n\t\t\tStopDBus,\n\t\t).AppendList(\n\t\t\tstopAllPhaselist(r, in.GetRebootMode() == machineapi.UpgradeRequest_DEFAULT),\n\t\t).Append(\n\t\t\t\"reboot\",\n\t\t\tReboot,\n\t\t)\n\t}\n\n\treturn phases\n}\n\n// MaintenanceUpgrade is the upgrade sequence in maintenance mode.\nfunc (*Sequencer) MaintenanceUpgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\treturn nil\n\tdefault:\n\t\tphases = phases.Append(\n\t\t\t\"upgrade\",\n\t\t\tUpgrade,\n\t\t).Append(\n\t\t\t\"meta\",\n\t\t\tReloadMeta,\n\t\t).AppendWhen(\n\t\t\tin.GetRebootMode() == machineapi.UpgradeRequest_DEFAULT,\n\t\t\t\"kexec\",\n\t\t\tKexecPrepare,\n\t\t).Append(\n\t\t\t\"stopEverything\",\n\t\t\tStopAllServices,\n\t\t).Append(\n\t\t\t\"reboot\",\n\t\t\tReboot,\n\t\t)\n\t}\n\n\treturn phases\n}\n\n// Upgrade is the upgrade sequence.\nfunc (*Sequencer) Upgrade(r runtime.Runtime, in *machineapi.UpgradeRequest) []runtime.Phase {\n\tphases := PhaseList{}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\treturn nil\n\tdefault:\n\t\tphases = phases.AppendWhen(\n\t\t\t!r.Config().Machine().Kubelet().SkipNodeRegistration(),\n\t\t\t\"drain\",\n\t\t\tCordonAndDrainNode,\n\t\t).Append(\n\t\t\t\"cleanup\",\n\t\t\tStopAllPods,\n\t\t).Append(\n\t\t\t\"dbus\",\n\t\t\tStopDBus,\n\t\t).Append(\n\t\t\t\"stopServices\",\n\t\t\tStopServicesEphemeral,\n\t\t).Append(\n\t\t\t\"unmount\",\n\t\t\tUnmountPodMounts,\n\t\t).Append(\n\t\t\t\"unmountBind\",\n\t\t\tUnmountSystemDiskBindMounts,\n\t\t).Append(\n\t\t\t\"unmountSystem\",\n\t\t\tUnmountEphemeralPartition,\n\t\t).Append(\n\t\t\t\"volumeFinalize\",\n\t\t\tTeardownVolumeLifecycle,\n\t\t).Append(\n\t\t\t\"upgrade\",\n\t\t\tUpgrade,\n\t\t).Append(\n\t\t\t\"meta\",\n\t\t\tReloadMeta,\n\t\t).AppendWhen(\n\t\t\tin.GetRebootMode() == machineapi.UpgradeRequest_DEFAULT,\n\t\t\t\"kexec\",\n\t\t\tKexecPrepare,\n\t\t).Append(\n\t\t\t\"stopEverything\",\n\t\t\tStopAllServices,\n\t\t).Append(\n\t\t\t\"reboot\",\n\t\t\tReboot,\n\t\t)\n\t}\n\n\treturn phases\n}\n\nfunc stopAllPhaselist(r runtime.Runtime, enableKexec bool) PhaseList {\n\tphases := PhaseList{}\n\n\tswitch r.State().Platform().Mode() { //nolint:exhaustive\n\tcase runtime.ModeContainer:\n\t\tphases = phases.Append(\n\t\t\t\"stopEverything\",\n\t\t\tStopAllServices,\n\t\t)\n\tdefault:\n\t\tphases = phases.Append(\n\t\t\t\"stopServices\",\n\t\t\tStopServicesEphemeral,\n\t\t).Append(\n\t\t\t\"umount\",\n\t\t\tUnmountPodMounts,\n\t\t).Append(\n\t\t\t\"unmountBind\",\n\t\t\tUnmountSystemDiskBindMounts,\n\t\t).Append(\n\t\t\t\"unmountSystem\",\n\t\t\tUnmountEphemeralPartition,\n\t\t).Append(\n\t\t\t\"volumeFinalize\",\n\t\t\tTeardownVolumeLifecycle,\n\t\t).AppendWhen(\n\t\t\tenableKexec,\n\t\t\t\"kexec\",\n\t\t\tKexecPrepare,\n\t\t).Append(\n\t\t\t\"stopEverything\",\n\t\t\tStopAllServices,\n\t\t)\n\t}\n\n\treturn phases\n}\n\nfunc bootPartitionInTargets(targets []runtime.PartitionTarget) bool {\n\tfor _, target := range targets {\n\t\tif target.GetLabel() == constants.BootPartitionLabel {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\tgoruntime \"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/foxboron/go-uefi/efi\"\n\t\"github.com/hashicorp/go-multierror\"\n\tpprocfs \"github.com/prometheus/procfs\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd/proc\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\tclientv3 \"go.etcd.io/etcd/client/v3\"\n\t\"golang.org/x/sys/unix\"\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/emergency\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/internal/pkg/cri\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/internal/pkg/install\"\n\t\"github.com/siderolabs/talos/internal/pkg/logind\"\n\tmountv3 \"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/kernel/kspp\"\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block/blockhelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tmetamachinery \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tcrires \"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\tresourcefiles \"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\tresourceruntime \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\tresourcev1alpha1 \"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/minimal\"\n)\n\n// WaitForUSB represents the WaitForUSB task.\nfunc WaitForUSB(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t// Wait for USB storage in the case that the install disk is supplied over\n\t\t// USB. If we don't wait, there is the chance that we will fail to detect the\n\t\t// install disk.\n\t\tfile := \"/sys/module/usb_storage/parameters/delay_use\"\n\n\t\t_, err := os.Stat(file)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tb, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tval := strings.TrimSuffix(string(b), \"\\n\")\n\n\t\tvar i int\n\n\t\ti, err = strconv.Atoi(val)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Printf(\"waiting %d second(s) for USB storage\", i)\n\n\t\ttime.Sleep(time.Duration(i) * time.Second)\n\n\t\treturn nil\n\t}, \"waitForUSB\"\n}\n\n// EnforceKSPPRequirements represents the EnforceKSPPRequirements task.\nfunc EnforceKSPPRequirements(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tif err = resourceruntime.NewKernelParamsSetCondition(r.State().V1Alpha2().Resources(), kspp.GetKernelParams()...).Wait(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn kspp.EnforceKSPPKernelParameters()\n\t}, \"enforceKSPPRequirements\"\n}\n\n// LoadConfig represents the LoadConfig task.\nfunc LoadConfig(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t// create a request to initialize the process acquisition process\n\t\trequest := resourcev1alpha1.NewAcquireConfigSpec()\n\t\tif err := r.State().V1Alpha2().Resources().Create(ctx, request); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create config request: %w\", err)\n\t\t}\n\n\t\t// wait for the config to be acquired\n\t\tstatus := resourcev1alpha1.NewAcquireConfigStatus()\n\t\tif _, err := r.State().V1Alpha2().Resources().WatchFor(ctx, status.Metadata(), state.WithEventTypes(state.Created)); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// clean up request to make sure controller doesn't work after this point\n\t\treturn r.State().V1Alpha2().Resources().Destroy(ctx, request.Metadata())\n\t}, \"loadConfig\"\n}\n\n// Sleep represents the Sleep task.\nfunc Sleep(d time.Duration) func(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(_ runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\tselect {\n\t\t\tcase <-time.After(d):\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}, \"sleep\"\n\t}\n}\n\n// MemorySizeCheck represents the MemorySizeCheck task.\nfunc MemorySizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif r.State().Platform().Mode() == runtime.ModeContainer {\n\t\t\tlogger.Println(\"skipping memory size check in the container\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tpc, err := pprocfs.NewDefaultFS()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open procfs: %w\", err)\n\t\t}\n\n\t\tinfo, err := pc.Meminfo()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read meminfo: %w\", err)\n\t\t}\n\n\t\tminimum, recommended, err := minimal.Memory(r.Config().Machine().Type())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch memTotal := pointer.SafeDeref(info.MemTotal) * humanize.KiByte; {\n\t\tcase memTotal < minimum:\n\t\t\tlogger.Println(\"WARNING: memory size is less than recommended\")\n\t\t\tlogger.Println(\"WARNING: Talos may not work properly\")\n\t\t\tlogger.Println(\"WARNING: minimum memory size is\", minimum/humanize.MiByte, \"MiB\")\n\t\t\tlogger.Println(\"WARNING: recommended memory size is\", recommended/humanize.MiByte, \"MiB\")\n\t\t\tlogger.Println(\"WARNING: current total memory size is\", memTotal/humanize.MiByte, \"MiB\")\n\t\tcase memTotal < recommended:\n\t\t\tlogger.Println(\"NOTE: recommended memory size is\", recommended/humanize.MiByte, \"MiB\")\n\t\t\tlogger.Println(\"NOTE: current total memory size is\", memTotal/humanize.MiByte, \"MiB\")\n\t\tdefault:\n\t\t\tlogger.Println(\"memory size is OK\")\n\t\t\tlogger.Println(\"memory size is\", memTotal/humanize.MiByte, \"MiB\")\n\t\t}\n\n\t\treturn nil\n\t}, \"memorySizeCheck\"\n}\n\n// DiskSizeCheck represents the DiskSizeCheck task.\nfunc DiskSizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif r.State().Platform().Mode() == runtime.ModeContainer {\n\t\t\tlogger.Println(\"skipping disk size check in the container\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tvolumeStatus, err := r.State().V1Alpha2().Resources().WatchFor(ctx,\n\t\t\tblockres.NewVolumeStatus(blockres.NamespaceName, constants.EphemeralPartitionLabel).Metadata(),\n\t\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\t\tvolumeStatus, ok := r.(*blockres.VolumeStatus)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\n\t\t\t\treturn volumeStatus.TypedSpec().Size > 0, nil\n\t\t\t}),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error waiting for volume %q to be discovered: %w\", constants.EphemeralPartitionLabel, err)\n\t\t}\n\n\t\tdiskSize := volumeStatus.(*blockres.VolumeStatus).TypedSpec().Size\n\n\t\tif minimum := minimal.DiskSize(); diskSize < minimum {\n\t\t\tlogger.Println(\"WARNING: disk size is less than recommended\")\n\t\t\tlogger.Println(\"WARNING: Talos may not work properly\")\n\t\t\tlogger.Println(\"WARNING: minimum recommended disk size is\", minimum/humanize.MiByte, \"MiB\")\n\t\t\tlogger.Println(\"WARNING: current total disk size is\", diskSize/humanize.MiByte, \"MiB\")\n\t\t} else {\n\t\t\tlogger.Println(\"disk size is OK\")\n\t\t\tlogger.Println(\"disk size is\", diskSize/humanize.MiByte, \"MiB\")\n\t\t}\n\n\t\treturn nil\n\t}, \"diskSizeCheck\"\n}\n\n// SetUserEnvVars represents the SetUserEnvVars task.\nfunc SetUserEnvVars(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tfor _, env := range environment.Get(r.Config()) {\n\t\t\tkey, val, _ := strings.Cut(env, \"=\")\n\n\t\t\tif err = os.Setenv(key, val); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to set enivronment variable: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, \"setUserEnvVars\"\n}\n\n// StartContainerd represents the task to start containerd.\nfunc StartContainerd(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tsvc := &services.Containerd{}\n\n\t\tsystem.Services(r).LoadAndStart(svc)\n\n\t\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\t\tdefer cancel()\n\n\t\treturn system.WaitForService(system.StateEventUp, svc.ID(r)).Wait(ctx)\n\t}, \"startContainerd\"\n}\n\n// WriteUdevRules is the task that writes udev rules to a udev rules file.\n// TODO: frezbo: move this to controller based since writing udev rules doesn't need a restart.\nfunc WriteUdevRules(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\trules := r.Config().Machine().Udev().Rules()\n\n\t\tvar content strings.Builder\n\n\t\tfor _, rule := range rules {\n\t\t\tcontent.WriteString(strings.ReplaceAll(rule, \"\\n\", \"\\\\\\n\"))\n\t\t\tcontent.WriteByte('\\n')\n\t\t}\n\n\t\tif err = os.WriteFile(constants.UdevRulesPath, []byte(content.String()), 0o644); err != nil {\n\t\t\treturn fmt.Errorf(\"failed writing custom udev rules: %w\", err)\n\t\t}\n\n\t\tif err = selinux.SetLabel(constants.UdevRulesPath, constants.UdevRulesLabel); err != nil {\n\t\t\treturn fmt.Errorf(\"failed labeling custom udev rules: %w\", err)\n\t\t}\n\n\t\tif len(rules) > 0 {\n\t\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"control\", \"--reload\"}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"trigger\", \"--type=devices\", \"--action=add\"}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"trigger\", \"--type=subsystems\", \"--action=add\"}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// This ensures that `udevd` finishes processing kernel events, triggered by\n\t\t\t// `udevd trigger`, to prevent a race condition when a user specifies a path\n\t\t\t// under `/dev/disk/*` in any disk definitions.\n\t\t\t_, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"settle\", \"--timeout=50\"})\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}, \"writeUdevRules\"\n}\n\n// StartMachined represents the task to start machined.\nfunc StartMachined(_ runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tsvc := &services.Machined{}\n\n\t\tid := svc.ID(r)\n\n\t\terr := system.Services(r).Start(id)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to start machined service: %w\", err)\n\t\t}\n\n\t\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\t\tdefer cancel()\n\n\t\treturn system.WaitForService(system.StateEventUp, id).Wait(ctx)\n\t}, \"startMachined\"\n}\n\n// StartSyslogd represents the task to start syslogd.\nfunc StartSyslogd(r runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\treturn func(_ context.Context, _ *log.Logger, r runtime.Runtime) error {\n\t\tsystem.Services(r).LoadAndStart(&services.Syslogd{})\n\n\t\treturn nil\n\t}, \"startSyslogd\"\n}\n\n// StartApid represents the task to start apid.\nfunc StartApid(r runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\treturn func(_ context.Context, _ *log.Logger, r runtime.Runtime) error {\n\t\tsystem.Services(r).LoadAndStart(&services.APID{})\n\n\t\treturn nil\n\t}, \"startApid\"\n}\n\n// StartAuditd represents the task to start auditd.\nfunc StartAuditd(r runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\treturn func(_ context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif !r.State().Platform().Mode().InContainer() {\n\t\t\tdisabledStr := procfs.ProcCmdline().Get(constants.KernelParamAuditdDisabled).First()\n\t\t\tdisabled, _ := strconv.ParseBool(pointer.SafeDeref(disabledStr)) //nolint:errcheck\n\n\t\t\tif disabled {\n\t\t\t\tlogger.Printf(\"auditd is disabled by kernel parameter %s\", constants.KernelParamAuditdDisabled)\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tsystem.Services(r).LoadAndStart(&services.Auditd{})\n\n\t\treturn nil\n\t}, \"startAuditd\"\n}\n\n// StartDashboard represents the task to start dashboard.\nfunc StartDashboard(_ runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\treturn func(_ context.Context, _ *log.Logger, r runtime.Runtime) error {\n\t\tsystem.Services(r).LoadAndStart(&services.Dashboard{})\n\n\t\treturn nil\n\t}, \"startDashboard\"\n}\n\n// StartUdevd represents the task to start udevd.\nfunc StartUdevd(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tmp := mountv3.NewSystemOverlay(\n\t\t\t[]string{constants.UdevDir},\n\t\t\tconstants.UdevDir,\n\t\t\tlogger.Printf,\n\t\t\tmountv3.WithShared(),\n\t\t\tmountv3.WithSelinuxLabel(constants.UdevRulesLabel),\n\t\t)\n\n\t\tif _, err = mp.Mount(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar extraSettleTime time.Duration\n\n\t\tsettleTimeStr := procfs.ProcCmdline().Get(constants.KernelParamDeviceSettleTime).First()\n\t\tif settleTimeStr != nil {\n\t\t\textraSettleTime, err = time.ParseDuration(*settleTimeStr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to parse %s: %w\", constants.KernelParamDeviceSettleTime, err)\n\t\t\t}\n\n\t\t\tlogger.Printf(\"extra settle time: %s\", extraSettleTime)\n\t\t}\n\n\t\tsvc := &services.Udevd{\n\t\t\tExtraSettleTime: extraSettleTime,\n\t\t}\n\n\t\tsystem.Services(r).LoadAndStart(svc)\n\n\t\tctx, cancel := context.WithTimeout(ctx, 10*time.Minute)\n\t\tdefer cancel()\n\n\t\treturn system.WaitForService(system.StateEventUp, svc.ID(r)).Wait(ctx)\n\t}, \"startUdevd\"\n}\n\n// StartAllServices represents the task to start the system services.\nfunc StartAllServices(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t// nb: Treating the beginning of \"service starts\" as the activate event for a normal\n\t\t// non-maintenance mode boot. At this point, we'd expect the user to\n\t\t// start interacting with the system for troubleshooting at least.\n\t\tplatform.FireEvent(\n\t\t\tctx,\n\t\t\tr.State().Platform(),\n\t\t\tplatform.Event{\n\t\t\t\tType:    platform.EventTypeActivate,\n\t\t\t\tMessage: \"Talos is ready for user interaction.\",\n\t\t\t},\n\t\t)\n\n\t\tsvcs := system.Services(r)\n\n\t\t// load the kubelet service, but don't start it;\n\t\t// KubeletServiceController will start it once it's ready.\n\t\tsvcs.Load(\n\t\t\t&services.Kubelet{},\n\t\t)\n\n\t\tserviceList := []system.Service{\n\t\t\t&services.CRI{},\n\t\t}\n\n\t\tswitch t := r.Config().Machine().Type(); t {\n\t\tcase machine.TypeInit:\n\t\t\tserviceList = append(serviceList,\n\t\t\t\t&services.Trustd{},\n\t\t\t\t&services.Etcd{Bootstrap: true},\n\t\t\t)\n\t\tcase machine.TypeControlPlane:\n\t\t\tserviceList = append(serviceList,\n\t\t\t\t&services.Trustd{},\n\t\t\t\t&services.Etcd{},\n\t\t\t)\n\t\tcase machine.TypeWorker:\n\t\t\t// nothing\n\t\tcase machine.TypeUnknown:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unexpected machine type %v\", t))\n\t\t}\n\n\t\tsvcs.LoadAndStart(serviceList...)\n\n\t\tall := make([]conditions.Condition, 0, len(svcs.List()))\n\n\t\tlogger.Printf(\"waiting for %d services\", len(svcs.List()))\n\n\t\tfor _, svc := range svcs.List() {\n\t\t\tcond := system.WaitForService(system.StateEventUp, svc.AsProto().GetId())\n\t\t\tall = append(all, cond)\n\t\t}\n\n\t\tctx, cancel := context.WithTimeout(ctx, constants.BootTimeout)\n\t\tdefer cancel()\n\n\t\taggregateCondition := conditions.WaitForAll(all...)\n\n\t\terrChan := make(chan error)\n\n\t\tgo func() {\n\t\t\terrChan <- aggregateCondition.Wait(ctx)\n\t\t}()\n\n\t\tticker := time.NewTicker(15 * time.Second)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tlogger.Printf(\"%s\", aggregateCondition.String())\n\n\t\t\tselect {\n\t\t\tcase err := <-errChan:\n\t\t\t\treturn err\n\t\t\tcase <-ticker.C:\n\t\t\t}\n\t\t}\n\t}, \"startAllServices\"\n}\n\n// StopServicesEphemeral represents the StopServicesEphemeral task.\nfunc StopServicesEphemeral(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t// stopping 'cri' service stops everything which depends on it (kubelet, etcd, ...)\n\t\treturn system.Services(nil).StopWithRevDepenencies(ctx, \"cri\", \"trustd\")\n\t}, \"stopServicesForUpgrade\"\n}\n\n// StopAllServices represents the StopAllServices task.\nfunc StopAllServices(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tsystem.Services(nil).Shutdown(ctx)\n\n\t\treturn nil\n\t}, \"stopAllServices\"\n}\n\n// SetupSharedFilesystems represents the SetupSharedFilesystems task.\nfunc SetupSharedFilesystems(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\ttargets := []string{\"/\", \"/var\", \"/etc/cni\", \"/run\"}\n\t\tfor _, t := range targets {\n\t\t\tif err = unix.Mount(\"\", t, \"\", unix.MS_SHARED|unix.MS_REC, \"\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, \"setupSharedFilesystems\"\n}\n\n// MountUserDisks represents the MountUserDisks task.\nfunc MountUserDisks(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t// wait for user disk config to be ready\n\t\t_, err := r.State().V1Alpha2().Resources().WatchFor(ctx,\n\t\t\tblockres.NewUserDiskConfigStatus(blockres.NamespaceName, blockres.UserDiskConfigStatusID).Metadata(),\n\t\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\t\treturn r.(*blockres.UserDiskConfigStatus).TypedSpec().Ready, nil\n\t\t\t}),\n\t\t)\n\n\t\treturn err\n\t}, \"mountUserDisks\"\n}\n\n// WriteUserFiles represents the WriteUserFiles task.\n//\n//nolint:gocyclo,cyclop\nfunc WriteUserFiles(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tvar result *multierror.Error\n\n\t\tfiles, err := r.Config().Machine().Files()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error generating extra files: %w\", err)\n\t\t}\n\n\t\tfor _, f := range files {\n\t\t\tcontent := f.Content()\n\n\t\t\tswitch f.Op() {\n\t\t\tcase \"create\":\n\t\t\t\t// Allow create at all times.\n\t\t\tcase \"overwrite\":\n\t\t\t\tif err = existsAndIsFile(f.Path()); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\tcase \"append\":\n\t\t\t\tif err = existsAndIsFile(f.Path()); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvar existingFileContents []byte\n\n\t\t\t\texistingFileContents, err = os.ReadFile(f.Path())\n\t\t\t\tif err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tcontent = string(existingFileContents) + \"\\n\" + f.Content()\n\t\t\tdefault:\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"unknown operation for file %q: %q\", f.Path(), f.Op()))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif filepath.Dir(f.Path()) == constants.ManifestsDirectory {\n\t\t\t\tif err = os.WriteFile(f.Path(), []byte(content), f.Permissions()); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif err = os.Chmod(f.Path(), f.Permissions()); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// CRI configuration customization\n\t\t\tif f.Path() == filepath.Join(\"/etc\", constants.CRICustomizationConfigPart) {\n\t\t\t\tif err = injectCRIConfigPatch(ctx, r.State().V1Alpha2().Resources(), []byte(f.Content())); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Determine if supplied path is in /var or not.\n\t\t\t// If not, we'll write it to /var anyways and bind mount below\n\t\t\tp := f.Path()\n\t\t\tinVar := true\n\t\t\tparts := strings.Split(\n\t\t\t\tstrings.TrimLeft(f.Path(), \"/\"),\n\t\t\t\tstring(os.PathSeparator),\n\t\t\t)\n\n\t\t\tif parts[0] != \"var\" {\n\t\t\t\tp = filepath.Join(\"/var\", f.Path())\n\t\t\t\tinVar = false\n\t\t\t}\n\n\t\t\t// We do not want to support creating new files anywhere outside of\n\t\t\t// /var. If a valid use case comes up, we can reconsider then.\n\t\t\tif !inVar && f.Op() == \"create\" {\n\t\t\t\treturn fmt.Errorf(\"create operation not allowed outside of /var: %q\", f.Path())\n\t\t\t}\n\n\t\t\tif err = os.MkdirAll(filepath.Dir(p), 0o755); err != nil {\n\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = os.WriteFile(p, []byte(content), f.Permissions()); err != nil {\n\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err = os.Chmod(p, f.Permissions()); err != nil {\n\t\t\t\tresult = multierror.Append(result, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !inVar {\n\t\t\t\tif err = unix.Mount(p, f.Path(), \"\", unix.MS_BIND|unix.MS_RDONLY, \"\"); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"failed to create bind mount for %s: %w\", p, err))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result.ErrorOrNil()\n\t}, \"writeUserFiles\"\n}\n\nfunc injectCRIConfigPatch(ctx context.Context, st state.State, content []byte) error {\n\t// limit overall waiting time\n\tctx, cancel := context.WithTimeout(ctx, time.Minute)\n\tdefer cancel()\n\n\tetcFileSpec := resourcefiles.NewEtcFileSpec(resourcefiles.NamespaceName, constants.CRICustomizationConfigPart)\n\tetcFileSpec.TypedSpec().Mode = 0o600\n\tetcFileSpec.TypedSpec().Contents = content\n\tetcFileSpec.TypedSpec().SelinuxLabel = constants.EtcSelinuxLabel\n\n\tif err := st.Create(ctx, etcFileSpec); err != nil {\n\t\treturn err\n\t}\n\n\tchecksumRaw := sha256.Sum256(content)\n\texpectedChecksum := hex.EncodeToString(checksumRaw[:])\n\texpectedAnnotation := resourcefiles.SourceFileAnnotation + \":\" + filepath.Join(\"/etc\", etcFileSpec.Metadata().ID())\n\n\tfileSpec, err := st.WatchFor(ctx, resourcefiles.NewEtcFileSpec(resourcefiles.NamespaceName, constants.CRIConfig).Metadata(),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tspec, ok := r.(*resourcefiles.EtcFileSpec)\n\t\t\tif !ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tvalue, ok := spec.Metadata().Annotations().Get(expectedAnnotation)\n\n\t\t\treturn ok && value == expectedChecksum, nil\n\t\t}))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error waiting for file %q to be updated: %w\", constants.CRIConfig, err)\n\t}\n\n\t// wait for the file to be rendered\n\t_, err = st.WatchFor(ctx, resourcefiles.NewEtcFileStatus(resourcefiles.NamespaceName, constants.CRIConfig).Metadata(), state.WithCondition(func(r resource.Resource) (bool, error) {\n\t\tfileStatus, ok := r.(*resourcefiles.EtcFileStatus)\n\t\tif !ok {\n\t\t\treturn false, nil\n\t\t}\n\n\t\treturn fileStatus.TypedSpec().SpecVersion == fileSpec.Metadata().Version().String(), nil\n\t}))\n\n\treturn err\n}\n\nfunc existsAndIsFile(p string) (err error) {\n\tvar info os.FileInfo\n\n\tinfo, err = os.Stat(p)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\treturn fmt.Errorf(\"file must exist: %q\", p)\n\t}\n\n\tif !info.Mode().IsRegular() {\n\t\treturn fmt.Errorf(\"invalid mode: %q\", info.Mode().String())\n\t}\n\n\treturn nil\n}\n\n// UnmountPodMounts represents the UnmountPodMounts task.\nfunc UnmountPodMounts(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tvar b []byte\n\n\t\tif b, err = os.ReadFile(\"/proc/self/mounts\"); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trdr := bytes.NewReader(b)\n\n\t\tscanner := bufio.NewScanner(rdr)\n\t\tfor scanner.Scan() {\n\t\t\tfields := strings.Fields(scanner.Text())\n\n\t\t\tif len(fields) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmountpoint := fields[1]\n\t\t\tif strings.HasPrefix(mountpoint, constants.EphemeralMountPoint+\"/\") {\n\t\t\t\tlogger.Printf(\"unmounting %s\\n\", mountpoint)\n\n\t\t\t\tif err = mountv3.SafeUnmount(ctx, logger.Printf, mountpoint, false); err != nil {\n\t\t\t\t\tif errors.Is(err, syscall.EINVAL) {\n\t\t\t\t\t\tlog.Printf(\"ignoring unmount error %s: %v\", mountpoint, err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn fmt.Errorf(\"error unmounting %s: %w\", mountpoint, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn scanner.Err()\n\t}, \"unmountPodMounts\"\n}\n\n// UnmountSystemDiskBindMounts represents the UnmountSystemDiskBindMounts task.\n//\n//nolint:gocyclo\nfunc UnmountSystemDiskBindMounts(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tephemeralStatus, err := safe.StateGetByID[*blockres.VolumeStatus](ctx, r.State().V1Alpha2().Resources(), constants.EphemeralPartitionLabel)\n\t\tif err != nil && !state.IsNotFoundError(err) {\n\t\t\treturn err\n\t\t}\n\n\t\tif ephemeralStatus == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tdevname := ephemeralStatus.TypedSpec().MountLocation\n\n\t\tif devname == \"\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tf, err := os.Open(\"/proc/mounts\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tscanner := bufio.NewScanner(f)\n\t\tfor scanner.Scan() {\n\t\t\tfields := strings.Fields(scanner.Text())\n\n\t\t\tif len(fields) < 2 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdevice, mountpoint := fields[0], fields[1]\n\n\t\t\tif device != devname || mountpoint == constants.EphemeralMountPoint {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlogger.Printf(\"unmounting %s\\n\", mountpoint)\n\n\t\t\tif err = mountv3.SafeUnmount(ctx, logger.Printf, mountpoint, false); err != nil {\n\t\t\t\tif errors.Is(err, syscall.EINVAL) {\n\t\t\t\t\tlog.Printf(\"ignoring unmount error %s: %v\", mountpoint, err)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"error unmounting %s: %w\", mountpoint, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn scanner.Err()\n\t}, \"unmountSystemDiskBindMounts\"\n}\n\n// CordonAndDrainNode represents the task for stop all containerd tasks in the\n// k8s.io namespace.\nfunc CordonAndDrainNode(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t// skip not exist error as it means that the node hasn't fully joined yet\n\t\tif _, err = os.Stat(\"/var/lib/kubelet/pki/kubelet-client-current.pem\"); err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tvar nodename string\n\n\t\tif nodename, err = r.NodeName(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// controllers will automatically cordon the node when the node enters appropriate phase,\n\t\t// so here we just wait for the node to be cordoned\n\t\tif err = waitForNodeCordoned(ctx, logger, r, nodename); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar kubeHelper *kubernetes.Client\n\n\t\tif kubeHelper, err = kubernetes.NewClientFromKubeletKubeconfig(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer kubeHelper.Close() //nolint:errcheck\n\n\t\treturn kubeHelper.Drain(ctx, nodename)\n\t}, \"cordonAndDrainNode\"\n}\n\nfunc waitForNodeCordoned(ctx context.Context, logger *log.Logger, r runtime.Runtime, nodename string) error {\n\tctx, cancel := context.WithTimeout(ctx, time.Minute)\n\tdefer cancel()\n\n\tlogger.Print(\"waiting for node to be cordoned\")\n\n\t_, err := r.State().V1Alpha2().Resources().WatchFor(\n\t\tctx,\n\t\tk8s.NewNodeStatus(k8s.NamespaceName, nodename).Metadata(),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tnodeStatus, ok := r.(*k8s.NodeStatus)\n\t\t\tif !ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn nodeStatus.TypedSpec().Unschedulable, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n\n// LeaveEtcd represents the task for removing a control plane node from etcd.\n//\n//nolint:gocyclo\nfunc LeaveEtcd(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t_, err = os.Stat(filepath.Join(constants.EtcdDataPath, \"/member\"))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tetcdID := (&services.Etcd{}).ID(r)\n\n\t\tservices := system.Services(r).List()\n\n\t\tshouldLeaveEtcd := false\n\n\t\tfor _, service := range services {\n\t\t\tif service.AsProto().Id != etcdID {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch service.GetState() { //nolint:exhaustive\n\t\t\tcase events.StateRunning:\n\t\t\t\tfallthrough\n\t\t\tcase events.StateStopping:\n\t\t\t\tfallthrough\n\t\t\tcase events.StateFailed:\n\t\t\t\tshouldLeaveEtcd = true\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tif !shouldLeaveEtcd {\n\t\t\treturn nil\n\t\t}\n\n\t\tclient, err := etcd.NewClientFromControlPlaneIPs(ctx, r.State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create etcd client: %w\", err)\n\t\t}\n\n\t\t//nolint:errcheck\n\t\tdefer client.Close()\n\n\t\tctx = clientv3.WithRequireLeader(ctx)\n\n\t\tif err = client.LeaveCluster(ctx, r.State().V1Alpha2().Resources()); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to leave cluster: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}, \"leaveEtcd\"\n}\n\n// RemoveAllPods represents the task for stopping and removing all pods.\nfunc RemoveAllPods(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn stopAndRemoveAllPods(cri.StopAndRemove), \"removeAllPods\"\n}\n\n// StopAllPods represents the task for stopping all pods.\nfunc StopAllPods(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn stopAndRemoveAllPods(cri.StopOnly), \"stopAllPods\"\n}\n\nfunc waitForKubeletLifecycleFinalizers(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\tlogger.Printf(\"waiting for kubelet lifecycle finalizers\")\n\n\tctx, cancel := context.WithTimeout(ctx, 30*time.Second)\n\tdefer cancel()\n\n\tlifecycle := resource.NewMetadata(k8s.NamespaceName, k8s.KubeletLifecycleType, k8s.KubeletLifecycleID, resource.VersionUndefined)\n\n\tfor {\n\t\tok, err := r.State().V1Alpha2().Resources().Teardown(ctx, lifecycle)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ok {\n\t\t\tbreak\n\t\t}\n\n\t\t_, err = r.State().V1Alpha2().Resources().WatchFor(ctx, lifecycle, state.WithFinalizerEmpty())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn r.State().V1Alpha2().Resources().Destroy(ctx, lifecycle)\n}\n\nfunc stopAndRemoveAllPods(stopAction cri.StopAction) runtime.TaskExecutionFunc {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tif err = waitForKubeletLifecycleFinalizers(ctx, logger, r); err != nil {\n\t\t\tlogger.Printf(\"failed waiting for kubelet lifecycle finalizers: %s\", err)\n\t\t}\n\n\t\tlogger.Printf(\"shutting down kubelet gracefully\")\n\n\t\tshutdownCtx, shutdownCtxCancel := context.WithTimeout(ctx, logind.InhibitMaxDelay)\n\t\tdefer shutdownCtxCancel()\n\n\t\tif err = r.State().Machine().DBus().WaitShutdown(shutdownCtx); err != nil {\n\t\t\tlogger.Printf(\"failed waiting for inhibit shutdown lock: %s\", err)\n\t\t}\n\n\t\tif err = system.Services(nil).Stop(ctx, \"kubelet\"); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// check that the CRI is running and the socket is available, if not, skip the rest\n\t\tif _, err = os.Stat(constants.CRIContainerdAddress); errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\tclient, err := cri.NewClient(\"unix://\"+constants.CRIContainerdAddress, 10*time.Second)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t//nolint:errcheck\n\t\tdefer client.Close()\n\n\t\tctx, cancel := context.WithTimeout(ctx, time.Minute*3)\n\t\tdefer cancel()\n\n\t\t// We remove pods with POD network mode first so that the CNI can perform\n\t\t// any cleanup tasks. If we don't do this, we run the risk of killing the\n\t\t// CNI, preventing the CRI from cleaning up the pod's networking.\n\n\t\tif err = client.StopAndRemovePodSandboxes(ctx, stopAction, runtimeapi.NamespaceMode_POD, runtimeapi.NamespaceMode_CONTAINER); err != nil {\n\t\t\tlogger.Printf(\"failed to stop and remove pods with POD network mode: %s\", err)\n\t\t}\n\n\t\t// With the POD network mode pods out of the way, we kill the remaining\n\t\t// pods.\n\n\t\tif err = client.StopAndRemovePodSandboxes(ctx, stopAction); err != nil {\n\t\t\tlogger.Printf(\"failed to stop and remove pods: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// ResetSystemDiskPartitions represents the task for wiping the system disk partitions.\nfunc ResetSystemDiskPartitions(seq runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) {\n\twipeStr := procfs.ProcCmdline().Get(constants.KernelParamWipe).First()\n\treboot, _ := Reboot(seq, nil)\n\n\tif pointer.SafeDeref(wipeStr) == \"\" {\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\treturn errors.New(\"no wipe target specified\")\n\t\t}, \"wipeSystemDisk\"\n\t}\n\n\tif *wipeStr == \"system\" {\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\tsystemDiskPaths, err := blockres.GetSystemDiskPaths(ctx, r.State().V1Alpha2().Resources())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\ttargets := targets{\n\t\t\t\tsystemDiskPaths: systemDiskPaths,\n\t\t\t}\n\n\t\t\tlogger.Printf(\"resetting system disks\")\n\n\t\t\tresetSystemDisk, _ := ResetSystemDisk(seq, targets)\n\n\t\t\terr = resetSystemDisk(ctx, logger, r)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Printf(\"resetting system disks failed\")\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlogger.Printf(\"finished resetting system disks\")\n\n\t\t\treturn reboot(ctx, logger, r) // only reboot when we wiped boot partition\n\t\t}, \"wipeSystemDisk\"\n\t}\n\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\ttargets, err := parseTargets(ctx, r, *wipeStr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfn, _ := ResetSystemDiskSpec(seq, targets)\n\t\tdiskTargets := targets.GetSystemDiskTargets()\n\n\t\tlogger.Printf(\"resetting system disks %s\", diskTargets)\n\n\t\terr = fn(ctx, logger, r)\n\t\tif err != nil {\n\t\t\tlogger.Printf(\"resetting system disks %s failed\", diskTargets)\n\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Printf(\"finished resetting system disks %s\", diskTargets)\n\n\t\treturn reboot(ctx, logger, r)\n\t}, \"wipeSystemDiskPartitions\"\n}\n\n// ResetSystemDisk represents the task to reset the system disk.\n//\n//nolint:gocyclo\nfunc ResetSystemDisk(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tin, ok := data.(SystemDiskTargets)\n\t\tif !ok {\n\t\t\treturn errors.New(\"unexpected runtime data\")\n\t\t}\n\n\t\tfor _, systemDiskPath := range in.GetSystemDiskPaths() {\n\t\t\tif err := func(devPath string) error {\n\t\t\t\tlogger.Printf(\"wiping system disk %s\", devPath)\n\n\t\t\t\tdev, err := block.NewFromPath(devPath, block.OpenForWrite())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif err = dev.RetryLockWithTimeout(ctx, true, time.Minute); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to lock device %s: %w\", devPath, err)\n\t\t\t\t}\n\n\t\t\t\tdefer dev.Close() //nolint:errcheck\n\n\t\t\t\tif err = partition.WipeWithSignatures(dev, devPath, logger.Printf); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t}(systemDiskPath); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to wipe system disk %s: %w\", systemDiskPath, err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, \"resetSystemDisk\"\n}\n\n// ResetUserDisks represents the task to reset the user disks.\nfunc ResetUserDisks(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tin, ok := data.(runtime.ResetOptions)\n\t\tif !ok {\n\t\t\treturn errors.New(\"unexpected runtime data\")\n\t\t}\n\n\t\twipeDevice := func(deviceName string) error {\n\t\t\tdev, err := block.NewFromPath(deviceName, block.OpenForWrite())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer func() {\n\t\t\t\tif closeErr := dev.Close(); closeErr != nil {\n\t\t\t\t\tlogger.Printf(\"failed to close device %s: %s\", deviceName, closeErr)\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tif err = dev.RetryLockWithTimeout(ctx, true, time.Minute); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to lock device %s: %w\", deviceName, err)\n\t\t\t}\n\n\t\t\tdefer dev.Unlock() //nolint:errcheck\n\n\t\t\tlogger.Printf(\"wiping user disk %s\", deviceName)\n\n\t\t\tif err = partition.WipeWithSignatures(dev, deviceName, logger.Printf); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tfor _, deviceName := range in.GetUserDisksToWipe() {\n\t\t\tif err := wipeDevice(deviceName); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, \"resetUserDisks\"\n}\n\ntype targets struct {\n\tsystemDiskTargets []*partition.VolumeWipeTarget\n\tsystemDiskPaths   []string\n}\n\nvar _ SystemDiskTargets = targets{}\n\nfunc (opt targets) GetSystemDiskTargets() []runtime.PartitionTarget {\n\treturn xslices.Map(opt.systemDiskTargets, func(t *partition.VolumeWipeTarget) runtime.PartitionTarget { return t })\n}\n\nfunc (opt targets) GetSystemDiskPaths() []string {\n\treturn opt.systemDiskPaths\n}\n\nfunc (opt targets) String() string {\n\treturn strings.Join(xslices.Map(opt.systemDiskTargets, func(t *partition.VolumeWipeTarget) string { return t.String() }), \", \")\n}\n\nfunc parseTargets(ctx context.Context, r runtime.Runtime, wipeStr string) (SystemDiskTargets, error) {\n\tafter, found := strings.CutPrefix(wipeStr, \"system:\")\n\tif !found {\n\t\treturn targets{}, fmt.Errorf(\"invalid wipe labels string: %q\", wipeStr)\n\t}\n\n\tvar result []*partition.VolumeWipeTarget\n\n\t// in this early phase, we don't have VolumeStatus resources, so instead we'd use DiscoveredVolumes\n\t// to get the volume paths\n\tdiscoveredVolumes, err := safe.StateListAll[*blockres.DiscoveredVolume](ctx, r.State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn targets{}, err\n\t}\n\n\tfor label := range strings.SplitSeq(after, \",\") {\n\t\tfound := false\n\n\t\tfor discoveredVolume := range discoveredVolumes.All() {\n\t\t\tif discoveredVolume.TypedSpec().PartitionLabel != label {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tresult = append(result, partition.VolumeWipeTargetFromDiscoveredVolume(discoveredVolume))\n\n\t\t\tfound = true\n\n\t\t\tbreak\n\t\t}\n\n\t\tif !found {\n\t\t\treturn targets{}, fmt.Errorf(\"failed to get volume status with label %q\", label)\n\t\t}\n\t}\n\n\tif len(result) == 0 {\n\t\treturn targets{}, errors.New(\"no wipe labels specified\")\n\t}\n\n\treturn targets{systemDiskTargets: result}, nil\n}\n\n// SystemDiskTargets represents the interface for getting the system disk targets.\n// It's a subset of [runtime.ResetOptions].\ntype SystemDiskTargets interface {\n\tGetSystemDiskTargets() []runtime.PartitionTarget\n\tGetSystemDiskPaths() []string\n\tfmt.Stringer\n}\n\n// ResetSystemDiskSpec represents the task to reset the system disk by spec.\nfunc ResetSystemDiskSpec(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) { //nolint:gocyclo\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tin, ok := data.(SystemDiskTargets)\n\t\tif !ok {\n\t\t\treturn errors.New(\"unexpected runtime data\")\n\t\t}\n\n\t\tvar (\n\t\t\tmetaWiped, stateWiped bool\n\t\t\twipeErrors            *multierror.Error\n\t\t)\n\n\t\tfor _, target := range in.GetSystemDiskTargets() {\n\t\t\tif err := target.Wipe(ctx, logger.Printf); err != nil {\n\t\t\t\twipeErrors = multierror.Append(wipeErrors,\n\t\t\t\t\tfmt.Errorf(\"failed wiping partition %s: %w\", target, err))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch target.GetLabel() {\n\t\t\tcase constants.MetaPartitionLabel:\n\t\t\t\tmetaWiped = true\n\t\t\tcase constants.StatePartitionLabel:\n\t\t\t\tstateWiped = true\n\t\t\t}\n\t\t}\n\n\t\tif stateWiped && !metaWiped {\n\t\t\tremoved, err := r.State().Machine().Meta().DeleteTag(ctx, metamachinery.StateEncryptionConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to remove state encryption META config tag: %w\", err)\n\t\t\t}\n\n\t\t\tif removed {\n\t\t\t\tif err = r.State().Machine().Meta().Flush(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to flush META: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tlogger.Printf(\"reset the state encryption META config tag\")\n\t\t\t}\n\t\t}\n\n\t\tif err := wipeErrors.ErrorOrNil(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Printf(\"successfully reset system disk by the spec\")\n\n\t\treturn nil\n\t}, \"resetSystemDiskSpec\"\n}\n\n// Upgrade represents the task for performing an upgrade.\nfunc Upgrade(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t// This should be checked by the gRPC server, but we double check here just\n\t\t// to be safe.\n\t\tin, ok := data.(*machineapi.UpgradeRequest)\n\t\tif !ok {\n\t\t\treturn runtime.ErrInvalidSequenceData\n\t\t}\n\n\t\tsystemDisk, err := blockres.GetSystemDisk(ctx, r.State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif systemDisk == nil {\n\t\t\treturn fmt.Errorf(\"system disk not found\")\n\t\t}\n\n\t\tdevname := systemDisk.DevPath\n\n\t\tlogger.Printf(\"performing upgrade via %q\", in.GetImage())\n\n\t\t// We pull the installer image when we receive an upgrade request. No need\n\t\t// to pull it again.\n\t\terr = install.RunInstallerContainer(\n\t\t\tdevname, r.State().Platform().Name(),\n\t\t\tin.GetImage(),\n\t\t\tr.Config(),\n\t\t\tr.ConfigContainer(),\n\t\t\tr.State().V1Alpha2().Resources(),\n\t\t\tcrires.RegistryBuilder(r.State().V1Alpha2().Resources()),\n\t\t\tinstall.OptionsFromUpgradeRequest(r, in)...,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogger.Println(\"upgrade successful\")\n\n\t\treturn nil\n\t}, \"upgrade\"\n}\n\n// Reboot represents the Reboot task.\nfunc Reboot(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\trebootCmd := unix.LINUX_REBOOT_CMD_RESTART\n\n\t\tif r.State().Machine().IsKexecPrepared() {\n\t\t\trebootCmd = unix.LINUX_REBOOT_CMD_KEXEC\n\t\t}\n\n\t\tr.Events().Publish(ctx, &machineapi.RestartEvent{\n\t\t\tCmd: int64(rebootCmd),\n\t\t})\n\n\t\tplatform.FireEvent(\n\t\t\tctx,\n\t\t\tr.State().Platform(),\n\t\t\tplatform.Event{\n\t\t\t\tType:    platform.EventTypeRebooted,\n\t\t\t\tMessage: \"Talos rebooted.\",\n\t\t\t},\n\t\t)\n\n\t\treturn runtime.RebootError{Cmd: rebootCmd}\n\t}, \"reboot\"\n}\n\n// Shutdown represents the Shutdown task.\nfunc Shutdown(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tcmd := unix.LINUX_REBOOT_CMD_POWER_OFF\n\n\t\tif p := procfs.ProcCmdline().Get(constants.KernelParamShutdown).First(); p != nil {\n\t\t\tif *p == \"halt\" {\n\t\t\t\tcmd = unix.LINUX_REBOOT_CMD_HALT\n\t\t\t}\n\t\t}\n\n\t\tr.Events().Publish(ctx, &machineapi.RestartEvent{\n\t\t\tCmd: int64(cmd),\n\t\t})\n\n\t\treturn runtime.RebootError{Cmd: cmd}\n\t}, \"shutdown\"\n}\n\n// haltIfInstalled halts the boot process if Talos is installed to disk but booted from ISO.\nfunc haltIfInstalled(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tctx, cancel := context.WithTimeout(ctx, constants.BootTimeout)\n\t\tdefer cancel()\n\n\t\ttimer := time.NewTicker(30 * time.Second)\n\t\tdefer timer.Stop()\n\n\t\tfor {\n\t\t\tlogger.Printf(\"Talos is already installed to disk but booted from another media and %s kernel parameter is set. Please reboot from the disk.\", constants.KernelParamHaltIfInstalled)\n\n\t\t\tselect {\n\t\t\tcase <-timer.C:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\t}\n\t\t}\n\t}, \"haltIfInstalled\"\n}\n\n// CleanupBootloader cleans up the ununsed bootloader if booted from a disk image with both bootloaders present.\nfunc CleanupBootloader(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tsystemDisk, err := blockres.GetSystemDisk(ctx, r.State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif systemDisk == nil {\n\t\t\treturn nil // no system disk, we can't do anything\n\t\t}\n\n\t\tif err := bootloader.CleanupBootloader(systemDisk.DevPath, sdboot.IsBootedUsingSDBoot()); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif _, err := r.State().Machine().Meta().DeleteTag(ctx, metamachinery.DiskImageBootloader); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to delete tag %d: %w\", metamachinery.DiskImageBootloader, err)\n\t\t}\n\n\t\treturn r.State().Machine().Meta().Flush()\n\t}, \"cleanupBootloader\"\n}\n\n// MountEphemeralPartition mounts the ephemeral partition.\nfunc MountEphemeralPartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tmountRequest := blockres.NewVolumeMountRequest(blockres.NamespaceName, constants.EphemeralPartitionLabel)\n\t\tmountRequest.TypedSpec().VolumeID = constants.EphemeralPartitionLabel\n\t\tmountRequest.TypedSpec().Requester = \"sequencer\"\n\n\t\tif cfg := r.Config(); cfg != nil {\n\t\t\tvol, _ := cfg.Volumes().ByName(constants.EphemeralPartitionLabel)\n\t\t\tmountRequest.TypedSpec().Secure = vol.Mount().Secure()\n\t\t}\n\n\t\tif err := r.State().V1Alpha2().Resources().Create(ctx, mountRequest); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create EPHEMERAL mount request: %w\", err)\n\t\t}\n\n\t\tif _, err := r.State().V1Alpha2().Resources().WatchFor(\n\t\t\tctx,\n\t\t\tblockres.NewVolumeMountStatus(blockres.NamespaceName, constants.EphemeralPartitionLabel).Metadata(),\n\t\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to wait for EPHEMERAL to be mounted: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}, \"mountEphemeralPartition\"\n}\n\n// UnmountEphemeralPartition unmounts the ephemeral partition.\nfunc UnmountEphemeralPartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tmountRequest := blockres.NewVolumeMountRequest(blockres.NamespaceName, constants.EphemeralPartitionLabel).Metadata()\n\n\t\terr := r.State().V1Alpha2().Resources().Destroy(ctx, mountRequest)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to destroy EPHEMERAL mount request: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}, \"unmountEphemeralPartition\"\n}\n\n// Install mounts or installs the system partitions.\n//\n//nolint:gocyclo,cyclop\nfunc Install(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\tswitch {\n\t\tcase !r.State().Machine().Installed():\n\t\t\tinstallerImage := r.Config().Machine().Install().Image()\n\t\t\tif installerImage == \"\" {\n\t\t\t\tinstallerImage = images.DefaultInstallerImage\n\t\t\t}\n\n\t\t\tlogger.Printf(\"waiting for the image cache\")\n\n\t\t\tif err = crires.WaitForImageCache(ctx, r.State().V1Alpha2().Resources()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to wait for the image cache: %w\", err)\n\t\t\t}\n\n\t\t\tvar disk string\n\n\t\t\tmatchExpr, err := r.Config().Machine().Install().DiskMatchExpression()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to get disk match expression: %w\", err)\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase matchExpr != nil:\n\t\t\t\tlogger.Printf(\"using disk match expression: %s\", matchExpr)\n\n\t\t\t\tmatchedDisks, err := blockhelpers.MatchDisks(ctx, r.State().V1Alpha2().Resources(), matchExpr)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif len(matchedDisks) == 0 {\n\t\t\t\t\treturn fmt.Errorf(\"no disks matched the expression: %s\", matchExpr)\n\t\t\t\t}\n\n\t\t\t\tdisk = matchedDisks[0].TypedSpec().DevPath\n\t\t\tcase r.Config().Machine().Install().Disk() != \"\":\n\t\t\t\tdisk = r.Config().Machine().Install().Disk()\n\t\t\t}\n\n\t\t\tdisk, err = filepath.EvalSymlinks(disk)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlogger.Printf(\"installing Talos to disk %s\", disk)\n\n\t\t\terr = install.RunInstallerContainer(\n\t\t\t\tdisk,\n\t\t\t\tr.State().Platform().Name(),\n\t\t\t\tinstallerImage,\n\t\t\t\tr.Config(),\n\t\t\t\tr.ConfigContainer(),\n\t\t\t\tr.State().V1Alpha2().Resources(),\n\t\t\t\tcrires.RegistryBuilder(r.State().V1Alpha2().Resources()),\n\t\t\t\tinstall.WithForce(true),\n\t\t\t\tinstall.WithZero(r.Config().Machine().Install().Zero()),\n\t\t\t\tinstall.WithExtraKernelArgs(r.Config().Machine().Install().ExtraKernelArgs()),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tplatform.FireEvent(\n\t\t\t\t\tctx,\n\t\t\t\t\tr.State().Platform(),\n\t\t\t\t\tplatform.Event{\n\t\t\t\t\t\tType:    platform.EventTypeFailure,\n\t\t\t\t\t\tMessage: \"Talos install failed.\",\n\t\t\t\t\t\tError:   err,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tplatform.FireEvent(\n\t\t\t\tctx,\n\t\t\t\tr.State().Platform(),\n\t\t\t\tplatform.Event{\n\t\t\t\t\tType:    platform.EventTypeInstalled,\n\t\t\t\t\tMessage: \"Talos installed successfully.\",\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tlogger.Println(\"install successful\")\n\n\t\t\tlogger.Printf(\"waiting for the image cache copy\")\n\n\t\t\tif err = crires.WaitForImageCacheCopy(ctx, r.State().V1Alpha2().Resources()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to wait for the image cache: %w\", err)\n\t\t\t}\n\t\tcase r.State().Machine().IsInstallStaged():\n\t\t\tsystemDisk, err := blockres.GetSystemDisk(ctx, r.State().V1Alpha2().Resources())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif systemDisk == nil {\n\t\t\t\treturn fmt.Errorf(\"system disk not found\")\n\t\t\t}\n\n\t\t\tdevname := systemDisk.DevPath\n\n\t\t\tvar options install.Options\n\n\t\t\tif err = json.Unmarshal(r.State().Machine().StagedInstallOptions(), &options); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error unserializing install options: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Printf(\"waiting for the image cache\")\n\n\t\t\tif err = crires.WaitForImageCache(ctx, r.State().V1Alpha2().Resources()); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to wait for the image cache: %w\", err)\n\t\t\t}\n\n\t\t\tlogger.Printf(\"performing staged upgrade via %q\", r.State().Machine().StagedInstallImageRef())\n\n\t\t\terr = install.RunInstallerContainer(\n\t\t\t\tdevname, r.State().Platform().Name(),\n\t\t\t\tr.State().Machine().StagedInstallImageRef(),\n\t\t\t\tr.Config(),\n\t\t\t\tr.ConfigContainer(),\n\t\t\t\tr.State().V1Alpha2().Resources(),\n\t\t\t\tcrires.RegistryBuilder(r.State().V1Alpha2().Resources()),\n\t\t\t\tinstall.WithOptions(options),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tplatform.FireEvent(\n\t\t\t\t\tctx,\n\t\t\t\t\tr.State().Platform(),\n\t\t\t\t\tplatform.Event{\n\t\t\t\t\t\tType:    platform.EventTypeFailure,\n\t\t\t\t\t\tMessage: \"Talos staged upgrade failed.\",\n\t\t\t\t\t\tError:   err,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// nb: we don't fire an \"activate\" event after this one\n\t\t\t// b/c we'd only ever get here if Talos was already\n\t\t\t// installed I believe.\n\t\t\tplatform.FireEvent(\n\t\t\t\tctx,\n\t\t\t\tr.State().Platform(),\n\t\t\t\tplatform.Event{\n\t\t\t\t\tType:    platform.EventTypeUpgraded,\n\t\t\t\t\tMessage: \"Talos staged upgrade successful.\",\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tlogger.Println(\"staged upgrade successful\")\n\n\t\tdefault:\n\t\t\treturn errors.New(\"unsupported configuration for install task\")\n\t\t}\n\n\t\treturn nil\n\t}, \"install\"\n}\n\n// KexecPrepare loads next boot kernel via kexec_file_load.\nfunc KexecPrepare(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif req, ok := data.(*machineapi.RebootRequest); ok {\n\t\t\tif req.Mode == machineapi.RebootRequest_POWERCYCLE {\n\t\t\t\tlog.Print(\"kexec skipped as reboot with power cycle was requested\")\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tif efi.GetSecureBoot() {\n\t\t\tlog.Print(\"kexec skipped as secure boot is enabled\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif goruntime.GOARCH == \"arm64\" {\n\t\t\t// see https://lkml.org/lkml/2025/11/27/178\n\t\t\t// [TODO]: remove this once the kernel issue is resolved\n\t\t\t// see also https://github.com/siderolabs/talos/pull/12396\n\t\t\tlog.Print(\"kexec skipped as kexec has issues on arm64\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tsystemDisk, err := blockres.GetSystemDisk(ctx, r.State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif systemDisk == nil {\n\t\t\tlog.Print(\"kexec skipped as system disk is not found\")\n\n\t\t\treturn nil // no system disk, no kexec\n\t\t}\n\n\t\tdev, err := block.NewFromPath(systemDisk.DevPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer dev.Close() //nolint:errcheck\n\n\t\tif err = dev.RetryLockWithTimeout(ctx, false, 3*time.Minute); err != nil {\n\t\t\tlog.Print(\"kexec skipped as system disk is busy\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tdefer dev.Unlock() //nolint:errcheck\n\n\t\tbootloaderInfo, err := bootloader.Probe(systemDisk.DevPath, options.ProbeOptions{\n\t\t\tLogger: log.Printf,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to probe system disk: %w\", err)\n\t\t}\n\n\t\treturn bootloaderInfo.KexecLoad(r, systemDisk.DevPath)\n\t}, \"kexecPrepare\"\n}\n\n// StartDBus starts the D-Bus mock.\nfunc StartDBus(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\treturn r.State().Machine().DBus().Start()\n\t}, \"startDBus\"\n}\n\n// StopDBus stops the D-Bus mock.\nfunc StopDBus(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif err := r.State().Machine().DBus().Stop(); err != nil {\n\t\t\tlogger.Printf(\"error stopping D-Bus: %s, ignored\", err)\n\t\t}\n\n\t\treturn nil\n\t}, \"stopDBus\"\n}\n\n// ForceCleanup kills remaining procs and forces partitions unmount.\nfunc ForceCleanup(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tif err := proc.KillAll(); err != nil {\n\t\t\tlogger.Printf(\"error killing all procs: %s\", err)\n\t\t}\n\n\t\tif err := mountv3.UnmountAll(); err != nil {\n\t\t\tlogger.Printf(\"error unmounting: %s\", err)\n\t\t}\n\n\t\treturn nil\n\t}, \"forceCleanup\"\n}\n\n// ReloadMeta reloads META partition after disk mount, installer run, etc.\n//\n//nolint:gocyclo\nfunc ReloadMeta(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\terr := r.State().Machine().Meta().Reload(ctx)\n\t\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\t// attempt to populate meta from the environment if Talos is not installed (yet)\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\tenv := environment.Get(r.Config())\n\n\t\t\tprefix := constants.MetaValuesEnvVar + \"=\"\n\n\t\t\tfor _, e := range env {\n\t\t\t\tif !strings.HasPrefix(e, prefix) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tvalues, err := metamachinery.DecodeValues(e[len(prefix):])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error decoding meta values: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tfor _, value := range values {\n\t\t\t\t\t_, err = r.State().Machine().Meta().SetTag(ctx, value.Key, value.Value)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error setting meta tag %x: %w\", value.Key, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif _, err := safe.ReaderGetByID[*resourceruntime.MetaLoaded](\n\t\t\tctx,\n\t\t\tr.State().V1Alpha2().Resources(),\n\t\t\tresourceruntime.MetaLoadedID,\n\t\t); err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"error reading MetaLoaded resource: %w\", err)\n\t\t\t}\n\n\t\t\t// create MetaLoaded resource signaling that META is now loaded\n\t\t\tloaded := resourceruntime.NewMetaLoaded()\n\t\t\tloaded.TypedSpec().Done = true\n\n\t\t\terr = r.State().V1Alpha2().Resources().Create(ctx, loaded)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating MetaLoaded resource: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, \"reloadMeta\"\n}\n\n// FlushMeta flushes META partition after install run.\nfunc FlushMeta(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t// META partition should be created at this point.\n\t\tif _, err := waitForVolumeReady(ctx, r, constants.MetaPartitionLabel); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn r.State().Machine().Meta().Flush()\n\t}, \"flushMeta\"\n}\n\n// StoreShutdownEmergency stores shutdown emergency state.\nfunc StoreShutdownEmergency(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t// for shutdown sequence, store power_off as the intent, it will be picked up\n\t\t// by emergency handled in machined/main.go if the Shutdown sequence fails\n\t\temergency.RebootCmd.Store(unix.LINUX_REBOOT_CMD_POWER_OFF)\n\n\t\treturn nil\n\t}, \"storeShutdownEmergency\"\n}\n\n// SendResetSignal func represents the task to send the final reset signal.\nfunc SendResetSignal(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\treturn r.State().V1Alpha2().Resources().Create(ctx, resourceruntime.NewMachineResetSignal())\n\t}, \"sendResetSignal\"\n}\n\n// WaitForCARoots represents the WaitForCARoots task.\n//\n//nolint:gocyclo\nfunc WaitForCARoots(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) {\n\t\t// watch EtcFileSpec & Status for CA roots and ensure they match\n\t\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\t\tdefer cancel()\n\n\t\tch := make(chan state.Event)\n\n\t\tif err = r.State().V1Alpha2().Resources().Watch(ctx, resourcefiles.NewEtcFileSpec(resourcefiles.NamespaceName, constants.DefaultTrustedRelativeCAFile).Metadata(), ch); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = r.State().V1Alpha2().Resources().Watch(ctx, resourcefiles.NewEtcFileStatus(resourcefiles.NamespaceName, constants.DefaultTrustedRelativeCAFile).Metadata(), ch); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar specVersion, statusVersion string\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase e := <-ch:\n\t\t\t\tswitch e.Type {\n\t\t\t\tcase state.Errored:\n\t\t\t\t\treturn e.Error\n\t\t\t\tcase state.Bootstrapped, state.Destroyed, state.Noop: // ignore\n\t\t\t\tcase state.Created, state.Updated:\n\t\t\t\t\tswitch res := e.Resource.(type) {\n\t\t\t\t\tcase *resourcefiles.EtcFileSpec:\n\t\t\t\t\t\tspecVersion = res.Metadata().Version().String()\n\t\t\t\t\tcase *resourcefiles.EtcFileStatus:\n\t\t\t\t\t\tstatusVersion = res.TypedSpec().SpecVersion\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif specVersion != \"\" && statusVersion != \"\" && specVersion == statusVersion {\n\t\t\t\t// success\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}, \"waitForCARoots\"\n}\n\n// TeardownVolumeLifecycle tears down volume lifecycle resource.\nfunc TeardownVolumeLifecycle(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {\n\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\t\tdefer cancel()\n\n\t\tvolumeLifecycle := blockres.NewVolumeLifecycle(blockres.NamespaceName, blockres.VolumeLifecycleID).Metadata()\n\n\t\t_, err := r.State().V1Alpha2().Resources().Teardown(ctx, volumeLifecycle)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = r.State().V1Alpha2().Resources().WatchFor(ctx, volumeLifecycle, state.WithFinalizerEmpty())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn r.State().V1Alpha2().Resources().Destroy(ctx, volumeLifecycle)\n\t}, \"teardownLifecycle\"\n}\n\nfunc pauseOnFailure(callback func(runtime.Sequence, any) (runtime.TaskExecutionFunc, string),\n\ttimeout time.Duration,\n) func(seq runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\treturn func(seq runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\t\tf, name := callback(seq, data)\n\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\terr := f(ctx, logger, r)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Printf(\"%s failed, rebooting in %.0f minutes. You can use talosctl apply-config or talosctl edit mc to fix the issues, error:\\n%s\", name, timeout.Minutes(), err)\n\n\t\t\t\ttimer := time.NewTimer(time.Minute * 5)\n\t\t\t\tdefer timer.Stop()\n\n\t\t\t\tselect {\n\t\t\t\tcase <-timer.C:\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn err\n\t\t}, name\n\t}\n}\n\nfunc taskErrorHandler(handler func(error, *log.Logger) error, task runtime.TaskSetupFunc) runtime.TaskSetupFunc {\n\treturn func(seq runtime.Sequence, data any) (runtime.TaskExecutionFunc, string) {\n\t\tf, name := task(seq, data)\n\n\t\treturn func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error {\n\t\t\terr := f(ctx, logger, r)\n\t\t\tif err != nil {\n\t\t\t\treturn handler(err, logger)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}, name\n\t}\n}\n\nfunc phaseListErrorHandler(handler func(error, *log.Logger) error, phases ...runtime.Phase) PhaseList {\n\tfor _, phase := range phases {\n\t\tfor i, task := range phase.Tasks {\n\t\t\tphase.Tasks[i] = taskErrorHandler(handler, task)\n\t\t}\n\t}\n\n\treturn phases\n}\n\nfunc logError(err error, logger *log.Logger) error {\n\tlogger.Printf(\"WARNING: task failed: %s\", err)\n\n\treturn nil\n}\n\nfunc waitForVolumeReady(ctx context.Context, r runtime.Runtime, volumeID string) (*blockres.VolumeStatus, error) {\n\treturn blockres.WaitForVolumePhase(ctx, r.State().V1Alpha2().Resources(), volumeID, blockres.VolumePhaseReady)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:scopelint,testpackage\npackage v1alpha1\n\nimport (\n\t\"reflect\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\nfunc TestNewSequencer(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\twant *Sequencer\n\t}{\n\t\t{\n\t\t\tname: \"test\",\n\t\t\twant: &Sequencer{},\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 := NewSequencer(); !reflect.DeepEqual(got, tt.want) {\n\t\t\t\tt.Errorf(\"NewSequencer() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPhaseList_Append(t *testing.T) {\n\tt.Skip(\"temporarily disabling until reflect.DeepEqual responds as expected\")\n\n\ttype args struct {\n\t\tname  string\n\t\ttasks []runtime.TaskSetupFunc\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\tp    PhaseList\n\t\targs args\n\t\twant PhaseList\n\t}{\n\t\t{\n\t\t\tname: \"test\",\n\t\t\tp:    PhaseList{},\n\t\t\targs: args{\n\t\t\t\tname:  \"mount\",\n\t\t\t\ttasks: []runtime.TaskSetupFunc{KexecPrepare},\n\t\t\t},\n\t\t\twant: PhaseList{runtime.Phase{Name: \"mount\", Tasks: []runtime.TaskSetupFunc{KexecPrepare}}},\n\t\t},\n\t}\n\n\tcmp := func(a, b runtime.Phase) bool { return a.Name == b.Name }\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.p = tt.p.Append(tt.args.name, tt.args.tasks...); !slices.EqualFunc(tt.p, tt.want, cmp) {\n\t\t\t\tt.Errorf(\"PhaseList.Append() = %v, want %v\", tt.p, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPhaseList_AppendWhen(t *testing.T) {\n\tt.Skip(\"temporarily disabling until reflect.DeepEqual responds as expected\")\n\n\ttype args struct {\n\t\twhen  bool\n\t\tname  string\n\t\ttasks []runtime.TaskSetupFunc\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\tp    PhaseList\n\t\targs args\n\t\twant PhaseList\n\t}{\n\t\t{\n\t\t\tname: \"true\",\n\t\t\tp:    PhaseList{},\n\t\t\targs: args{\n\t\t\t\twhen:  true,\n\t\t\t\tname:  \"mount\",\n\t\t\t\ttasks: []runtime.TaskSetupFunc{KexecPrepare},\n\t\t\t},\n\t\t\twant: PhaseList{runtime.Phase{Name: \"mount\", Tasks: []runtime.TaskSetupFunc{KexecPrepare}}},\n\t\t},\n\t\t{\n\t\t\tname: \"false\",\n\t\t\tp:    PhaseList{},\n\t\t\targs: args{\n\t\t\t\twhen:  false,\n\t\t\t\ttasks: []runtime.TaskSetupFunc{KexecPrepare},\n\t\t\t},\n\t\t\twant: PhaseList{},\n\t\t},\n\t}\n\n\tcmp := func(a, b runtime.Phase) bool { return a.Name == b.Name }\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif tt.p = tt.p.AppendWhen(tt.args.when, tt.args.name, tt.args.tasks...); !slices.EqualFunc(tt.p, tt.want, cmp) {\n\t\t\t\tt.Errorf(\"PhaseList.AppendWhen() = %v, want %v\", tt.p, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha2\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tmetaconsts \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// State implements the state interface.\ntype State struct {\n\tplatform runtime.Platform\n\tmachine  *MachineState\n\tcluster  *ClusterState\n\tv2       runtime.V1Alpha2State\n}\n\n// MachineState represents the machine's state.\ntype MachineState struct {\n\tplatform  runtime.Platform\n\tresources state.State\n\n\tmeta     *meta.Meta\n\tmetaOnce sync.Once\n\n\tstagedInstall         bool\n\tstagedInstallImageRef string\n\tstagedInstallOptions  []byte\n\n\tkexecPrepared bool\n\n\tdbus DBusState\n}\n\n// ClusterState represents the cluster's state.\ntype ClusterState struct{}\n\n// NewState initializes and returns the v1alpha1 state.\nfunc NewState() (s *State, err error) {\n\tp, err := platform.CurrentPlatform()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tv2State, err := v1alpha2.NewState()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmachine := &MachineState{\n\t\tplatform:  p,\n\t\tresources: v2State.Resources(),\n\t}\n\n\tcluster := &ClusterState{}\n\n\ts = &State{\n\t\tplatform: p,\n\t\tcluster:  cluster,\n\t\tmachine:  machine,\n\t\tv2:       v2State,\n\t}\n\n\treturn s, nil\n}\n\n// Platform implements the state interface.\nfunc (s *State) Platform() runtime.Platform {\n\treturn s.platform\n}\n\n// Machine implements the state interface.\nfunc (s *State) Machine() runtime.MachineState {\n\treturn s.machine\n}\n\n// Cluster implements the state interface.\nfunc (s *State) Cluster() runtime.ClusterState {\n\treturn s.cluster\n}\n\n// V1Alpha2 implements the state interface.\nfunc (s *State) V1Alpha2() runtime.V1Alpha2State {\n\treturn s.v2\n}\n\n// Meta implements the runtime.MachineState interface.\nfunc (s *MachineState) Meta() runtime.Meta {\n\t// no META in container mode\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn s\n\t}\n\n\tvar (\n\t\tjustLoaded bool\n\t\tloadErr    error\n\t)\n\n\ts.metaOnce.Do(func() {\n\t\ts.meta, loadErr = meta.New(context.Background(), s.resources)\n\t\tif loadErr != nil {\n\t\t\tif !os.IsNotExist(loadErr) {\n\t\t\t\tlog.Printf(\"META: failed to load: %s\", loadErr)\n\t\t\t}\n\t\t} else {\n\t\t\ts.probeMeta()\n\t\t}\n\n\t\tjustLoaded = true\n\t})\n\n\treturn metaWrapper{\n\t\tMachineState: s,\n\t\tjustLoaded:   justLoaded,\n\t\tloadErr:      loadErr,\n\t}\n}\n\n// ReadTag implements the runtime.Meta interface.\nfunc (s *MachineState) ReadTag(t uint8) (val string, ok bool) {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn \"\", false\n\t}\n\n\treturn s.meta.ReadTag(t)\n}\n\n// ReadTagBytes implements the runtime.Meta interface.\nfunc (s *MachineState) ReadTagBytes(t uint8) (val []byte, ok bool) {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn nil, false\n\t}\n\n\treturn s.meta.ReadTagBytes(t)\n}\n\n// SetTag implements the runtime.Meta interface.\nfunc (s *MachineState) SetTag(ctx context.Context, t uint8, val string) (bool, error) {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn false, nil\n\t}\n\n\treturn s.meta.SetTag(ctx, t, val)\n}\n\n// SetTagBytes implements the runtime.Meta interface.\nfunc (s *MachineState) SetTagBytes(ctx context.Context, t uint8, val []byte) (bool, error) {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn false, nil\n\t}\n\n\treturn s.meta.SetTagBytes(ctx, t, val)\n}\n\n// DeleteTag implements the runtime.Meta interface.\nfunc (s *MachineState) DeleteTag(ctx context.Context, t uint8) (bool, error) {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn false, nil\n\t}\n\n\treturn s.meta.DeleteTag(ctx, t)\n}\n\n// Reload implements the runtime.Meta interface.\nfunc (s *MachineState) Reload(ctx context.Context) error {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn nil\n\t}\n\n\terr := s.meta.Reload(ctx)\n\tif err == nil {\n\t\ts.probeMeta()\n\t}\n\n\treturn err\n}\n\n// Flush implements the runtime.Meta interface.\nfunc (s *MachineState) Flush() error {\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn nil\n\t}\n\n\treturn s.meta.Flush()\n}\n\nfunc (s *MachineState) probeMeta() {\n\tstagedInstallImageRef, ok1 := s.meta.ReadTag(metaconsts.StagedUpgradeImageRef)\n\tstagedInstallOptions, ok2 := s.meta.ReadTag(metaconsts.StagedUpgradeInstallOptions)\n\n\ts.stagedInstall = ok1 && ok2\n\n\tif s.stagedInstall {\n\t\t// clear the staged install flags\n\t\t_, err1 := s.meta.DeleteTag(context.Background(), metaconsts.StagedUpgradeImageRef)\n\n\t\t_, err2 := s.meta.DeleteTag(context.Background(), metaconsts.StagedUpgradeInstallOptions)\n\t\tif err := s.meta.Flush(); err != nil || err1 != nil || err2 != nil {\n\t\t\t// failed to delete staged install tags, clear the stagedInstall to prevent boot looping\n\t\t\ts.stagedInstall = false\n\t\t}\n\n\t\ts.stagedInstallImageRef = stagedInstallImageRef\n\t\ts.stagedInstallOptions = []byte(stagedInstallOptions)\n\t}\n}\n\n// Installed implements the machine state interface.\nfunc (s *MachineState) Installed() bool {\n\t// undefined in container mode\n\tif s.platform.Mode() == runtime.ModeContainer {\n\t\treturn true\n\t}\n\n\t// legacy flow, no context available\n\tctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)\n\tdefer cancel()\n\n\tmetaStatus, err := safe.StateWatchFor[*block.VolumeStatus](\n\t\tctx,\n\t\ts.resources,\n\t\tblock.NewVolumeStatus(block.NamespaceName, constants.MetaPartitionLabel).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tvs, ok := r.(*block.VolumeStatus)\n\t\t\tif !ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tswitch vs.TypedSpec().Phase { //nolint:exhaustive\n\t\t\tcase block.VolumePhaseMissing:\n\t\t\t\t// no META, talos is not installed\n\t\t\t\treturn true, nil\n\t\t\tcase block.VolumePhaseReady:\n\t\t\t\t// META found\n\t\t\t\treturn true, nil\n\t\t\tdefault:\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn metaStatus.TypedSpec().Phase == block.VolumePhaseReady\n}\n\n// IsInstallStaged implements the machine state interface.\nfunc (s *MachineState) IsInstallStaged() bool {\n\treturn s.stagedInstall\n}\n\n// StagedInstallImageRef implements the machine state interface.\nfunc (s *MachineState) StagedInstallImageRef() string {\n\treturn s.stagedInstallImageRef\n}\n\n// StagedInstallOptions implements the machine state interface.\nfunc (s *MachineState) StagedInstallOptions() []byte {\n\treturn s.stagedInstallOptions\n}\n\n// KexecPrepared implements the machine state interface.\nfunc (s *MachineState) KexecPrepared(prepared bool) {\n\ts.kexecPrepared = prepared\n}\n\n// IsKexecPrepared implements the machine state interface.\nfunc (s *MachineState) IsKexecPrepared() bool {\n\treturn s.kexecPrepared\n}\n\n// DBus implements the machine state interface.\nfunc (s *MachineState) DBus() runtime.DBusState {\n\treturn &s.dbus\n}\n\ntype metaWrapper struct {\n\t*MachineState\n\n\tjustLoaded bool\n\tloadErr    error\n}\n\nfunc (m metaWrapper) Reload(ctx context.Context) error {\n\tif m.justLoaded {\n\t\treturn m.loadErr\n\t}\n\n\treturn m.MachineState.Reload(ctx)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha2/adapters.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha2\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n)\n\n// platformConfigurator adapts a runtime.Platform to the config.PlatformConfigurator interface.\ntype platformConfigurator struct {\n\tplatform runtime.Platform\n\tstate    state.State\n}\n\n// Check interfaces.\nvar (\n\t_ config.PlatformConfigurator = &platformConfigurator{}\n)\n\nfunc (p *platformConfigurator) Name() string {\n\treturn p.platform.Name()\n}\n\nfunc (p *platformConfigurator) Configuration(ctx context.Context) ([]byte, error) {\n\treturn p.platform.Configuration(ctx, p.state)\n}\n\n// platformEventer adapts a runtime.Platform to the config.PlatformEventer interface.\ntype platformEventer struct {\n\tplatform runtime.Platform\n}\n\n// Check interfaces.\nvar (\n\t_ config.PlatformEventer = &platformEventer{}\n)\n\nfunc (p *platformEventer) FireEvent(ctx context.Context, event platform.Event) {\n\tplatform.FireEvent(ctx, p.platform, event)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha2/v1alpha2.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package v1alpha2 provides runtime implementation based on os-runtime.\npackage v1alpha2\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha2\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\tosruntime \"github.com/cosi-project/runtime/pkg/controller/runtime\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cluster\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/config\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/cri\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/etcd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/files\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/hardware\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/k8s\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubeaccess\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/kubespan\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/network\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/perf\"\n\truntimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/secrets\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/security\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/siderolink\"\n\ttimecontrollers \"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/time\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/controllers/v1alpha1\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\truntimelogging \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tconfigresource \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\n// Controller implements runtime.V1alpha2Controller.\ntype Controller struct {\n\tcontrollerRuntime *osruntime.Runtime\n\n\tloggingManager  runtime.LoggingManager\n\tconsoleLogLevel zap.AtomicLevel\n\tlogger          *zap.Logger\n\n\tv1alpha1Runtime runtime.Runtime\n}\n\n// NewController creates Controller.\nfunc NewController(v1alpha1Runtime runtime.Runtime) (*Controller, error) {\n\tctrl := &Controller{\n\t\tconsoleLogLevel: zap.NewAtomicLevel(),\n\t\tloggingManager:  v1alpha1Runtime.Logging(),\n\t\tv1alpha1Runtime: v1alpha1Runtime,\n\t}\n\n\tvar err error\n\n\tctrl.logger, err = ctrl.MakeLogger(\"controller-runtime\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tctrl.controllerRuntime, err = osruntime.NewRuntime(v1alpha1Runtime.State().V1Alpha2().Resources(), ctrl.logger)\n\n\treturn ctrl, err\n}\n\n// Run the controller runtime.\nfunc (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error {\n\t// adjust the log level based on machine configuration\n\tgo ctrl.watchMachineConfig(ctx)\n\n\tdnsCacheLogger, err := ctrl.MakeLogger(\"dns-resolve-cache\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar (\n\t\tetcRoot                xfs.Root\n\t\tnetworkEtcRoot         xfs.Root\n\t\tnetworkBindMountTarget string\n\t)\n\n\tetcRoot = &xfs.UnixRoot{\n\t\tFS: fsopen.New(\n\t\t\t\"tmpfs\",\n\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\tfsopen.WithStringParameter(\"size\", \"8M\"),\n\t\t),\n\t}\n\n\tnetworkEtcRoot = &xfs.UnixRoot{\n\t\tFS: fsopen.New(\n\t\t\t\"tmpfs\",\n\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\tfsopen.WithStringParameter(\"size\", \"4M\"),\n\t\t),\n\t}\n\n\tnetworkBindMountTarget = constants.SystemResolvedPath\n\n\t// While running in container, we don't have control over kernel version\n\t// shipped with the machine. If the kernel does not support open_tree syscall\n\t// on anonymous filesystem file descriptors, we need to fallback to the classic,\n\t// less secure mode. This capability was added in kernel 6.15.0.\n\tif ctrl.v1alpha1Runtime.State().Platform().Mode().InContainer() {\n\t\topentreeOnAnonymous, err := runtime.KernelCapabilities().OpentreeOnAnonymousFS()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !opentreeOnAnonymous {\n\t\t\tetcRoot = &xfs.OSRoot{\n\t\t\t\tShadow: constants.SystemEtcPath,\n\t\t\t}\n\n\t\t\tnetworkEtcRoot = &xfs.OSRoot{\n\t\t\t\tShadow: constants.SystemResolvedPath,\n\t\t\t}\n\n\t\t\tnetworkBindMountTarget = \"\"\n\t\t}\n\t}\n\n\tif err := etcRoot.OpenFS(); err != nil {\n\t\treturn fmt.Errorf(\"failed to open etc root: %w\", err)\n\t}\n\tdefer etcRoot.Close() //nolint:errcheck\n\n\tif err := networkEtcRoot.OpenFS(); err != nil {\n\t\treturn fmt.Errorf(\"failed to open network etc root: %w\", err)\n\t}\n\tdefer networkEtcRoot.Close() //nolint:errcheck\n\n\tfor _, c := range []controller.Controller{\n\t\t&block.DevicesController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&block.DiscoveryController{},\n\t\t&block.DisksController{},\n\t\t&block.LVMActivationController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&block.MountController{},\n\t\t&block.MountRequestController{},\n\t\t&block.MountStatusController{},\n\t\t&block.SwapStatusController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&block.SymlinksController{},\n\t\t&block.SystemDiskController{},\n\t\t&block.UserDiskConfigController{},\n\t\t&block.VolumeConfigController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t\tMetaProvider: ctrl.v1alpha1Runtime.State().Machine(),\n\t\t},\n\t\t&block.VolumeManagerController{},\n\t\t&block.ZswapConfigController{},\n\t\t&block.ZswapStatusController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&cluster.AffiliateMergeController{},\n\t\tcluster.NewConfigController(),\n\t\t&cluster.DiscoveryServiceController{},\n\t\t&cluster.EndpointController{},\n\t\tcluster.NewInfoController(),\n\t\t&cluster.KubernetesPullController{},\n\t\t&cluster.KubernetesPushController{},\n\t\t&cluster.LocalAffiliateController{},\n\t\t&cluster.MemberController{},\n\t\t&cluster.NodeIdentityController{},\n\t\t&config.AcquireController{\n\t\t\tPlatformConfiguration: &platformConfigurator{\n\t\t\t\tplatform: ctrl.v1alpha1Runtime.State().Platform(),\n\t\t\t\tstate:    ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),\n\t\t\t},\n\t\t\tPlatformEvent: &platformEventer{\n\t\t\t\tplatform: ctrl.v1alpha1Runtime.State().Platform(),\n\t\t\t},\n\t\t\tMode:           ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t\tCmdlineGetter:  procfs.ProcCmdline,\n\t\t\tConfigSetter:   ctrl.v1alpha1Runtime,\n\t\t\tEventPublisher: ctrl.v1alpha1Runtime.Events(),\n\t\t\tValidationMode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t\tResourceState:  ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),\n\t\t},\n\t\t&config.MachineTypeController{},\n\t\t&config.PersistenceController{},\n\t\t&cri.ImageCacheConfigController{\n\t\t\tV1Alpha1ServiceManager: system.Services(ctrl.v1alpha1Runtime),\n\t\t},\n\t\tcri.NewImageGCController(\"containerd\", false),\n\t\tcri.NewImageGCController(\"cri\", true),\n\t\t&cri.RegistriesConfigController{},\n\t\t&cri.SeccompProfileController{},\n\t\t&cri.SeccompProfileFileController{\n\t\t\tV1Alpha1Mode:             ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t\tSeccompProfilesDirectory: constants.SeccompProfilesDirectory,\n\t\t},\n\t\t&etcd.AdvertisedPeerController{},\n\t\tetcd.NewConfigController(),\n\t\t&etcd.PKIController{},\n\t\t&etcd.SpecController{},\n\t\t&etcd.MemberController{},\n\t\t&files.CRIBaseRuntimeSpecController{},\n\t\t&files.CRIConfigPartsController{},\n\t\t&files.CRIRegistryConfigController{\n\t\t\tEtcRoot: etcRoot,\n\t\t\tEtcPath: \"/etc\",\n\t\t},\n\t\t&files.EtcFileController{\n\t\t\tEtcRoot: etcRoot,\n\t\t\tEtcPath: \"/etc\",\n\t\t},\n\t\t&files.IQNController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&files.NQNController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&hardware.PCIDevicesController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&hardware.PCIDriverRebindConfigController{},\n\t\t&hardware.PCIDriverRebindController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&hardware.PCRStatusController{},\n\t\t&hardware.SystemInfoController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&k8s.AddressFilterController{},\n\t\tk8s.NewControlPlaneAPIServerController(),\n\t\tk8s.NewControlPlaneAdmissionControlController(),\n\t\tk8s.NewControlPlaneAuditPolicyController(),\n\t\tk8s.NewControlPlaneAuthorizationController(),\n\t\tk8s.NewControlPlaneBootstrapManifestsController(),\n\t\tk8s.NewControlPlaneControllerManagerController(),\n\t\tk8s.NewControlPlaneExtraManifestsController(),\n\t\tk8s.NewControlPlaneSchedulerController(),\n\t\t&k8s.ControlPlaneStaticPodController{},\n\t\t&k8s.EndpointController{},\n\t\t&k8s.ExtraManifestController{},\n\t\tk8s.NewKubeletConfigController(),\n\t\t&k8s.KubeletServiceController{\n\t\t\tV1Alpha1Services: system.Services(ctrl.v1alpha1Runtime),\n\t\t\tV1Alpha1Mode:     ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&k8s.KubeletSpecController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&k8s.KubeletStaticPodController{},\n\t\tk8s.NewKubePrismEndpointsController(),\n\t\tk8s.NewKubePrismConfigController(),\n\t\t&k8s.KubePrismController{},\n\t\t&k8s.ManifestApplyController{},\n\t\t&k8s.ManifestController{},\n\t\tk8s.NewNodeIPConfigController(),\n\t\t&k8s.NodeIPController{},\n\t\t&k8s.NodeAnnotationSpecController{},\n\t\t&k8s.NodeApplyController{},\n\t\t&k8s.NodeCordonedSpecController{},\n\t\t&k8s.NodeLabelSpecController{},\n\t\t&k8s.NodeStatusController{},\n\t\t&k8s.NodeTaintSpecController{},\n\t\t&k8s.NodenameController{},\n\t\t&k8s.RenderConfigsStaticPodController{},\n\t\t&k8s.RenderSecretsStaticPodController{},\n\t\t&k8s.StaticEndpointController{},\n\t\t&k8s.StaticPodConfigController{},\n\t\t&k8s.StaticPodServerController{},\n\t\tkubeaccess.NewConfigController(),\n\t\t&kubeaccess.CRDController{},\n\t\t&kubeaccess.EndpointController{},\n\t\tkubespan.NewConfigController(),\n\t\t&kubespan.EndpointController{},\n\t\t&kubespan.IdentityController{},\n\t\t&kubespan.ManagerController{},\n\t\t&kubespan.PeerSpecController{},\n\t\t&network.AddressConfigController{\n\t\t\tCmdline:      procfs.ProcCmdline(),\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&network.AddressEventController{\n\t\t\tV1Alpha1Events: ctrl.v1alpha1Runtime.Events(),\n\t\t},\n\t\tnetwork.NewAddressMergeController(),\n\t\t&network.AddressSpecController{},\n\t\t&network.AddressStatusController{},\n\t\t&network.DeviceConfigController{},\n\t\t&network.DNSResolveCacheController{\n\t\t\tState:  ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),\n\t\t\tLogger: dnsCacheLogger,\n\t\t},\n\t\t&network.DNSUpstreamController{},\n\t\t&network.EtcFileController{\n\t\t\tEtcRoot:         networkEtcRoot,\n\t\t\tBindMountTarget: networkBindMountTarget,\n\t\t\tV1Alpha1Mode:    ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&network.EthernetConfigController{},\n\t\t&network.EthernetSpecController{},\n\t\t&network.EthernetStatusController{},\n\t\t&network.HardwareAddrController{},\n\t\t&network.HostDNSConfigController{},\n\t\t&network.HostnameConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewHostnameMergeController(),\n\t\t&network.HostnameSpecController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&network.LinkAliasConfigController{},\n\t\t&network.LinkAliasSpecController{},\n\t\t&network.LinkConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewLinkMergeController(),\n\t\t&network.LinkSpecController{},\n\t\t&network.LinkStatusController{},\n\t\t&network.NfTablesChainConfigController{},\n\t\t&network.NfTablesChainController{},\n\t\t&network.NodeAddressController{},\n\t\t&network.NodeAddressSortAlgorithmController{},\n\t\t&network.OperatorConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewOperatorMergeController(),\n\t\t&network.OperatorSpecController{\n\t\t\tV1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(),\n\t\t\tState:            ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),\n\t\t},\n\t\t&network.OperatorVIPConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\t&network.PlatformConfigApplyController{\n\t\t\tV1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(),\n\t\t},\n\t\t&network.PlatformConfigController{\n\t\t\tV1alpha1Platform: ctrl.v1alpha1Runtime.State().Platform(),\n\t\t\tPlatformState:    ctrl.v1alpha1Runtime.State().V1Alpha2().Resources(),\n\t\t},\n\t\t&network.PlatformConfigLoadController{},\n\t\t&network.PlatformConfigStoreController{},\n\t\t&network.ProbeController{},\n\t\t&network.ProbeConfigController{},\n\t\tnetwork.NewProbeMergeController(),\n\t\t&network.ResolverConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewResolverMergeController(),\n\t\t&network.ResolverSpecController{},\n\t\t&network.RouteConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewRouteMergeController(),\n\t\t&network.RouteSpecController{},\n\t\t&network.RouteStatusController{},\n\t\t&network.RoutingRuleConfigController{},\n\t\tnetwork.NewRoutingRuleMergeController(),\n\t\t&network.RoutingRuleSpecController{},\n\t\t&network.RoutingRuleStatusController{},\n\t\t&network.StatusController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&network.TimeServerConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\tnetwork.NewTimeServerMergeController(),\n\t\t&network.TimeServerSpecController{},\n\t\t&perf.StatsController{},\n\t\t&runtimecontrollers.APIServiceConfigController{},\n\t\t&runtimecontrollers.BootedEntryController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.DevicesStatusController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.DiagnosticsController{},\n\t\t&runtimecontrollers.DiagnosticsLoggerController{},\n\t\t&runtimecontrollers.DropUpgradeFallbackController{\n\t\t\tMetaProvider: ctrl.v1alpha1Runtime.State().Machine(),\n\t\t},\n\t\t&runtimecontrollers.EnvironmentController{},\n\t\t&runtimecontrollers.ExtensionServiceConfigController{},\n\t\t&runtimecontrollers.ExtensionServiceConfigFilesController{\n\t\t\tV1Alpha1Mode:            ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t\tExtensionsConfigBaseDir: constants.ExtensionServiceUserConfigPath,\n\t\t},\n\t\t&runtimecontrollers.EventsSinkConfigController{\n\t\t\tCmdline:      procfs.ProcCmdline(),\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.EventsSinkController{\n\t\t\tV1Alpha1Events: ctrl.v1alpha1Runtime.Events(),\n\t\t\tDrainer:        drainer,\n\t\t},\n\t\t&runtimecontrollers.ExtensionServiceController{\n\t\t\tV1Alpha1Services: system.Services(ctrl.v1alpha1Runtime),\n\t\t\tConfigPath:       constants.ExtensionServiceConfigPath,\n\t\t},\n\t\t&runtimecontrollers.ExtensionStatusController{},\n\t\t&runtimecontrollers.KernelCmdlineController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.KernelModuleConfigController{},\n\t\t&runtimecontrollers.KernelModuleSpecController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.KernelParamConfigController{},\n\t\t&runtimecontrollers.KernelParamDefaultsController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.KernelParamSpecController{},\n\t\t&runtimecontrollers.KmsgLogConfigController{\n\t\t\tCmdline: procfs.ProcCmdline(),\n\t\t},\n\t\t&runtimecontrollers.KmsgLogDeliveryController{\n\t\t\tDrainer: drainer,\n\t\t},\n\t\t&runtimecontrollers.KmsgLogStorageController{\n\t\t\tV1Alpha1Logging: ctrl.v1alpha1Runtime.Logging(),\n\t\t\tV1Alpha1Mode:    ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.LogPersistenceController{\n\t\t\tV1Alpha1Logging: ctrl.v1alpha1Runtime.Logging(),\n\t\t},\n\t\t&runtimecontrollers.LoadedKernelModuleController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.MaintenanceConfigController{},\n\t\t&runtimecontrollers.MaintenanceServiceInformController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.MachineStatusController{\n\t\t\tV1Alpha1Events: ctrl.v1alpha1Runtime.Events(),\n\t\t},\n\t\t&runtimecontrollers.MachineStatusPublisherController{\n\t\t\tV1Alpha1Events: ctrl.v1alpha1Runtime.Events(),\n\t\t},\n\t\t&runtimecontrollers.MountStatusController{},\n\t\t&runtimecontrollers.SBOMItemController{},\n\t\t&runtimecontrollers.SecurityStateController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&runtimecontrollers.UniqueMachineTokenController{},\n\t\t&runtimecontrollers.VersionController{},\n\t\t&runtimecontrollers.WatchdogTimerConfigController{},\n\t\t&runtimecontrollers.WatchdogTimerController{},\n\t\t&runtimecontrollers.OOMController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&secrets.APICertSANsController{},\n\t\t&secrets.APIController{},\n\t\t&secrets.EncryptionSaltController{},\n\t\t&secrets.EtcdController{},\n\t\tsecrets.NewKubeletController(),\n\t\t&secrets.KubernetesCertSANsController{},\n\t\t&secrets.KubernetesDynamicCertsController{},\n\t\t&secrets.KubernetesController{},\n\t\t&secrets.MaintenanceCertSANsController{},\n\t\t&secrets.MaintenanceRootController{},\n\t\tsecrets.NewRootEtcdController(),\n\t\tsecrets.NewRootKubernetesController(),\n\t\tsecrets.NewRootOSController(),\n\t\t&secrets.TrustedRootsController{},\n\t\t&secrets.TrustdController{},\n\t\t&security.ImageVerificationConfigController{},\n\t\t&security.TUFTrustedRootController{},\n\t\t&siderolink.ConfigController{\n\t\t\tCmdline:      procfs.ProcCmdline(),\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&siderolink.ManagerController{},\n\t\t&siderolink.StatusController{},\n\t\t&siderolink.UserspaceWireguardController{\n\t\t\tRelayRetryTimeout: 10 * time.Second,\n\t\t},\n\t\t&timecontrollers.AdjtimeStatusController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&timecontrollers.SyncController{\n\t\t\tV1Alpha1Mode: ctrl.v1alpha1Runtime.State().Platform().Mode(),\n\t\t},\n\t\t&v1alpha1.ServiceController{\n\t\t\tV1Alpha1Events: ctrl.v1alpha1Runtime.Events(),\n\t\t},\n\t} {\n\t\tif err := ctrl.controllerRuntime.RegisterController(c); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn ctrl.controllerRuntime.Run(ctx)\n}\n\n// DependencyGraph returns controller-resources dependencies.\nfunc (ctrl *Controller) DependencyGraph() (*controller.DependencyGraph, error) {\n\treturn ctrl.controllerRuntime.GetDependencyGraph()\n}\n\ntype loggingDestination struct {\n\tFormat    string\n\tEndpoint  *url.URL\n\tExtraTags map[string]string\n}\n\nfunc (a *loggingDestination) Equal(b *loggingDestination) bool {\n\tif a.Format != b.Format {\n\t\treturn false\n\t}\n\n\tif a.Endpoint.String() != b.Endpoint.String() {\n\t\treturn false\n\t}\n\n\tif len(a.ExtraTags) != len(b.ExtraTags) {\n\t\treturn false\n\t}\n\n\tfor k, v := range a.ExtraTags {\n\t\tif vv, ok := b.ExtraTags[k]; !ok || vv != v {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (ctrl *Controller) watchMachineConfig(ctx context.Context) {\n\twatchCh := make(chan state.Event)\n\n\tif err := ctrl.v1alpha1Runtime.State().V1Alpha2().Resources().Watch(\n\t\tctx,\n\t\tresource.NewMetadata(configresource.NamespaceName, configresource.MachineConfigType, configresource.ActiveID, resource.VersionUndefined),\n\t\twatchCh,\n\t); err != nil {\n\t\tctrl.logger.Warn(\"error watching machine configuration\", zap.Error(err))\n\n\t\treturn\n\t}\n\n\tvar loggingDestinations []loggingDestination\n\n\tfor {\n\t\tvar cfg talosconfig.Config\n\n\t\tselect {\n\t\tcase event := <-watchCh:\n\t\t\tif event.Type != state.Created && event.Type != state.Updated {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcfg = event.Resource.(*configresource.MachineConfig).Config()\n\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\n\t\tctrl.updateConsoleLoggingConfig(cfg.Debug())\n\n\t\tif cfg.Machine() == nil {\n\t\t\tctrl.updateLoggingConfig(ctx, nil, &loggingDestinations)\n\t\t} else {\n\t\t\tctrl.updateLoggingConfig(ctx, cfg.Machine().Logging().Destinations(), &loggingDestinations)\n\t\t}\n\t}\n}\n\nfunc (ctrl *Controller) updateConsoleLoggingConfig(debug bool) {\n\tnewLogLevel := zapcore.InfoLevel\n\tif debug {\n\t\tnewLogLevel = zapcore.DebugLevel\n\t}\n\n\tif newLogLevel != ctrl.consoleLogLevel.Level() {\n\t\tctrl.logger.Info(\"setting console log level\", zap.Stringer(\"level\", newLogLevel))\n\t\tctrl.consoleLogLevel.SetLevel(newLogLevel)\n\t}\n}\n\nfunc (ctrl *Controller) updateLoggingConfig(ctx context.Context, dests []talosconfig.LoggingDestination, prevLoggingDestinations *[]loggingDestination) {\n\tloggingDestinations := make([]loggingDestination, len(dests))\n\n\tfor i, dest := range dests {\n\t\tswitch f := dest.Format(); f {\n\t\tcase constants.LoggingFormatJSONLines:\n\t\t\tloggingDestinations[i] = loggingDestination{\n\t\t\t\tFormat:    f,\n\t\t\t\tEndpoint:  dest.Endpoint(),\n\t\t\t\tExtraTags: dest.ExtraTags(),\n\t\t\t}\n\t\tdefault:\n\t\t\t// should not be possible due to validation\n\t\t\tpanic(fmt.Sprintf(\"unhandled log destination format %q\", f))\n\t\t}\n\t}\n\n\tloggingChanged := len(*prevLoggingDestinations) != len(loggingDestinations)\n\tif !loggingChanged {\n\t\tfor i, u := range *prevLoggingDestinations {\n\t\t\tif !u.Equal(&loggingDestinations[i]) {\n\t\t\t\tloggingChanged = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif !loggingChanged {\n\t\treturn\n\t}\n\n\t*prevLoggingDestinations = loggingDestinations\n\n\tvar prevSenders []runtime.LogSender\n\n\tif len(loggingDestinations) > 0 {\n\t\tsenders := xslices.Map(dests, runtimelogging.NewJSONLines)\n\n\t\tctrl.logger.Info(\"enabling JSON logging\")\n\t\tprevSenders = ctrl.loggingManager.SetSenders(senders)\n\t} else {\n\t\tctrl.logger.Info(\"disabling JSON logging\")\n\t\tprevSenders = ctrl.loggingManager.SetSenders(nil)\n\t}\n\n\tcloseCtx, closeCancel := context.WithTimeout(ctx, 3*time.Second)\n\tdefer closeCancel()\n\n\tvar wg sync.WaitGroup\n\n\tfor _, sender := range prevSenders {\n\t\twg.Go(func() {\n\t\t\terr := sender.Close(closeCtx)\n\t\t\tctrl.logger.Info(\"log sender closed\", zap.Error(err))\n\t\t})\n\t}\n\n\twg.Wait()\n}\n\n// MakeLogger creates a logger for a service.\nfunc (ctrl *Controller) MakeLogger(serviceName string) (*zap.Logger, error) {\n\tlogWriter, err := ctrl.loggingManager.ServiceLog(serviceName).Writer()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn logging.ZapLogger(\n\t\tlogging.NewLogDestination(logWriter, zapcore.DebugLevel,\n\t\t\tlogging.WithColoredLevels(),\n\t\t),\n\t\tlogging.NewLogDestination(logging.StdWriter, ctrl.consoleLogLevel,\n\t\t\tlogging.WithoutTimestamp(),\n\t\t\tlogging.WithoutLogLevels(),\n\t\t\tlogging.WithControllerErrorSuppressor(constants.ConsoleLogErrorSuppressThreshold),\n\t\t),\n\t).With(logging.Component(serviceName)), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha2\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\n\ttalosconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// State implements runtime.V1alpha2State interface.\ntype State struct {\n\tresources state.State\n\n\tnamespaceRegistry *registry.NamespaceRegistry\n\tresourceRegistry  *registry.ResourceRegistry\n}\n\n// NewState creates State.\nfunc NewState() (*State, error) {\n\ts := &State{}\n\n\tctx := context.TODO()\n\n\ts.resources = state.WrapCore(namespaced.NewState(\n\t\tfunc(ns string) state.CoreState {\n\t\t\treturn inmem.NewStateWithOptions(\n\t\t\t\tinmem.WithHistoryInitialCapacity(8),\n\t\t\t\tinmem.WithHistoryMaxCapacity(1024),\n\t\t\t\tinmem.WithHistoryGap(4),\n\t\t\t)(ns)\n\t\t},\n\t))\n\ts.namespaceRegistry = registry.NewNamespaceRegistry(s.resources)\n\ts.resourceRegistry = registry.NewResourceRegistry(s.resources)\n\n\tif err := s.namespaceRegistry.RegisterDefault(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := s.resourceRegistry.RegisterDefault(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// register Talos namespaces\n\tfor _, ns := range []struct {\n\t\tname        string\n\t\tdescription string\n\t}{\n\t\t{v1alpha1.NamespaceName, \"Talos v1alpha1 subsystems glue resources.\"},\n\t\t{cluster.NamespaceName, \"Cluster configuration and discovery resources.\"},\n\t\t{cluster.RawNamespaceName, \"Cluster unmerged raw resources.\"},\n\t\t{config.NamespaceName, \"Talos node configuration.\"},\n\t\t{etcd.NamespaceName, \"etcd resources.\"},\n\t\t{files.NamespaceName, \"Files and file-like resources.\"},\n\t\t{hardware.NamespaceName, \"Hardware resources.\"},\n\t\t{k8s.NamespaceName, \"Kubernetes all node types resources.\"},\n\t\t{k8s.ControlPlaneNamespaceName, \"Kubernetes control plane resources.\"},\n\t\t{kubespan.NamespaceName, \"KubeSpan resources.\"},\n\t\t{network.NamespaceName, \"Networking resources.\"},\n\t\t{network.ConfigNamespaceName, \"Networking configuration resources.\"},\n\t\t{cri.NamespaceName, \"CRI Seccomp resources.\"},\n\t\t{secrets.NamespaceName, \"Resources with secret material.\"},\n\t\t{security.NamespaceName, \"Security resources.\"},\n\t\t{perf.NamespaceName, \"Stats resources.\"},\n\t} {\n\t\tif err := s.namespaceRegistry.Register(ctx, ns.name, ns.description); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// register Talos resources\n\tfor _, r := range []meta.ResourceWithRD{\n\t\t&block.Device{},\n\t\t&block.DiscoveredVolume{},\n\t\t&block.DiscoveryRefreshRequest{},\n\t\t&block.DiscoveryRefreshStatus{},\n\t\t&block.Disk{},\n\t\t&block.MountRequest{},\n\t\t&block.MountStatus{},\n\t\t&block.SwapStatus{},\n\t\t&block.Symlink{},\n\t\t&block.SystemDisk{},\n\t\t&block.UserDiskConfigStatus{},\n\t\t&block.VolumeConfig{},\n\t\t&block.VolumeLifecycle{},\n\t\t&block.VolumeMountRequest{},\n\t\t&block.VolumeMountStatus{},\n\t\t&block.VolumeStatus{},\n\t\t&block.ZswapStatus{},\n\t\t&cluster.Affiliate{},\n\t\t&cluster.Config{},\n\t\t&cluster.Identity{},\n\t\t&cluster.Info{},\n\t\t&cluster.Member{},\n\t\t&config.MachineConfig{},\n\t\t&config.MachineType{},\n\t\t&cri.ImageCacheConfig{},\n\t\t&cri.SeccompProfile{},\n\t\t&etcd.Config{},\n\t\t&etcd.PKIStatus{},\n\t\t&etcd.Spec{},\n\t\t&etcd.Member{},\n\t\t&files.EtcFileSpec{},\n\t\t&files.EtcFileStatus{},\n\t\t&hardware.MemoryModule{},\n\t\t&hardware.PCIDevice{},\n\t\t&hardware.PCIDriverRebindConfig{},\n\t\t&hardware.PCIDriverRebindStatus{},\n\t\t&hardware.PCRStatus{},\n\t\t&hardware.Processor{},\n\t\t&hardware.SystemInformation{},\n\t\t&k8s.AdmissionControlConfig{},\n\t\t&k8s.AuditPolicyConfig{},\n\t\t&k8s.AuthorizationConfig{},\n\t\t&k8s.APIServerConfig{},\n\t\t&k8s.KubePrismEndpoints{},\n\t\t&k8s.ConfigStatus{},\n\t\t&k8s.ControllerManagerConfig{},\n\t\t&k8s.Endpoint{},\n\t\t&k8s.ExtraManifestsConfig{},\n\t\t&k8s.KubeletConfig{},\n\t\t&k8s.KubeletLifecycle{},\n\t\t&k8s.KubeletSpec{},\n\t\t&k8s.KubePrismConfig{},\n\t\t&k8s.KubePrismStatuses{},\n\t\t&k8s.Manifest{},\n\t\t&k8s.ManifestStatus{},\n\t\t&k8s.BootstrapManifestsConfig{},\n\t\t&k8s.NodeAnnotationSpec{},\n\t\t&k8s.NodeCordonedSpec{},\n\t\t&k8s.NodeIP{},\n\t\t&k8s.NodeIPConfig{},\n\t\t&k8s.NodeLabelSpec{},\n\t\t&k8s.Nodename{},\n\t\t&k8s.NodeStatus{},\n\t\t&k8s.NodeTaintSpec{},\n\t\t&k8s.SchedulerConfig{},\n\t\t&k8s.StaticPod{},\n\t\t&k8s.StaticPodServerStatus{},\n\t\t&k8s.StaticPodStatus{},\n\t\t&k8s.SecretsStatus{},\n\t\t&kubeaccess.Config{},\n\t\t&kubespan.Config{},\n\t\t&kubespan.Endpoint{},\n\t\t&kubespan.Identity{},\n\t\t&kubespan.PeerSpec{},\n\t\t&kubespan.PeerStatus{},\n\t\t&network.AddressStatus{},\n\t\t&network.AddressSpec{},\n\t\t&network.DeviceConfigSpec{},\n\t\t&network.DNSResolveCache{},\n\t\t&network.DNSUpstream{},\n\t\t&network.EthernetSpec{},\n\t\t&network.EthernetStatus{},\n\t\t&network.HardwareAddr{},\n\t\t&network.HostDNSConfig{},\n\t\t&network.HostnameStatus{},\n\t\t&network.HostnameSpec{},\n\t\t&network.LinkAliasSpec{},\n\t\t&network.LinkRefresh{},\n\t\t&network.LinkStatus{},\n\t\t&network.LinkSpec{},\n\t\t&network.NfTablesChain{},\n\t\t&network.NodeAddress{},\n\t\t&network.NodeAddressFilter{},\n\t\t&network.NodeAddressSortAlgorithm{},\n\t\t&network.OperatorSpec{},\n\t\t&network.PlatformConfig{},\n\t\t&network.ProbeSpec{},\n\t\t&network.ProbeStatus{},\n\t\t&network.ResolverStatus{},\n\t\t&network.ResolverSpec{},\n\t\t&network.RouteStatus{},\n\t\t&network.RouteSpec{},\n\t\t&network.RoutingRuleSpec{},\n\t\t&network.RoutingRuleStatus{},\n\t\t&network.Status{},\n\t\t&network.TimeServerStatus{},\n\t\t&network.TimeServerSpec{},\n\t\t&perf.CPU{},\n\t\t&perf.Memory{},\n\t\t&cri.RegistriesConfig{},\n\t\t&runtime.APIServiceConfig{},\n\t\t&runtime.BootedEntry{},\n\t\t&runtime.DevicesStatus{},\n\t\t&runtime.Diagnostic{},\n\t\t&runtime.Environment{},\n\t\t&runtime.EventSinkConfig{},\n\t\t&runtime.ExtensionServiceConfig{},\n\t\t&runtime.ExtensionServiceConfigStatus{},\n\t\t&runtime.ExtensionStatus{},\n\t\t&runtime.KernelCmdline{},\n\t\t&runtime.KernelModuleSpec{},\n\t\t&runtime.KernelParamSpec{},\n\t\t&runtime.KernelParamDefaultSpec{},\n\t\t&runtime.KernelParamStatus{},\n\t\t&runtime.KmsgLogConfig{},\n\t\t&runtime.LoadedKernelModule{},\n\t\t&runtime.MaintenanceServiceConfig{},\n\t\t&runtime.MaintenanceServiceRequest{},\n\t\t&runtime.MachineResetSignal{},\n\t\t&runtime.MachineStatus{},\n\t\t&runtime.MetaKey{},\n\t\t&runtime.MetaLoaded{},\n\t\t&runtime.MountStatus{},\n\t\t&runtime.OOMAction{},\n\t\t&runtime.PlatformMetadata{},\n\t\t&runtime.SBOMItem{},\n\t\t&runtime.SecurityState{},\n\t\t&runtime.UniqueMachineToken{},\n\t\t&runtime.Version{},\n\t\t&runtime.WatchdogTimerConfig{},\n\t\t&runtime.WatchdogTimerStatus{},\n\t\t&secrets.API{},\n\t\t&secrets.CertSAN{},\n\t\t&secrets.EncryptionSalt{},\n\t\t&secrets.Etcd{},\n\t\t&secrets.EtcdRoot{},\n\t\t&secrets.Kubelet{},\n\t\t&secrets.Kubernetes{},\n\t\t&secrets.KubernetesDynamicCerts{},\n\t\t&secrets.KubernetesRoot{},\n\t\t&secrets.MaintenanceRoot{},\n\t\t&secrets.OSRoot{},\n\t\t&secrets.Trustd{},\n\t\t&security.ImageVerificationRule{},\n\t\t&security.TUFTrustedRoot{},\n\t\t&siderolink.Config{},\n\t\t&siderolink.Status{},\n\t\t&siderolink.Tunnel{},\n\t\t&time.AdjtimeStatus{},\n\t\t&time.Status{},\n\t\t&v1alpha1.AcquireConfigSpec{},\n\t\t&v1alpha1.AcquireConfigStatus{},\n\t\t&v1alpha1.Service{},\n\t} {\n\t\tif err := s.resourceRegistry.Register(ctx, r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn s, nil\n}\n\n// Resources implements runtime.V1alpha2State interface.\nfunc (s *State) Resources() state.State {\n\treturn s.resources\n}\n\n// NamespaceRegistry implements runtime.V1alpha2State interface.\nfunc (s *State) NamespaceRegistry() *registry.NamespaceRegistry {\n\treturn s.namespaceRegistry\n}\n\n// ResourceRegistry implements runtime.V1alpha2State interface.\nfunc (s *State) ResourceRegistry() *registry.ResourceRegistry {\n\treturn s.resourceRegistry\n}\n\n// GetConfig implements runtime.V1alpha2State interface.\nfunc (s *State) GetConfig(ctx context.Context) (talosconfig.Provider, error) {\n\tcfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, s.resources, config.ActiveID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn cfg.Provider(), nil\n}\n\n// SetConfig implements runtime.V1alpha2State interface.\nfunc (s *State) SetConfig(ctx context.Context, id string, cfg talosconfig.Provider) error {\n\tcfgResource := config.NewMachineConfigWithID(cfg, id)\n\n\toldCfg, err := s.resources.Get(ctx, cfgResource.Metadata())\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn s.resources.Create(ctx, cfgResource)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tcfgResource.Metadata().SetVersion(oldCfg.Metadata().Version())\n\n\treturn s.resources.Update(ctx, cfgResource)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/startup/cgroups.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage startup\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// CreateSystemCgroups creates system cgroups.\nfunc CreateSystemCgroups(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\t// in container mode cgroups mode depends on cgroups provided by the container runtime\n\tif !rt.State().Platform().Mode().InContainer() {\n\t\t// assert that cgroupsv2 is being used when running not in container mode,\n\t\t// as Talos sets up cgroupsv2 on its own\n\t\tif cgroups.Mode() != cgroups.Unified {\n\t\t\treturn errors.New(\"cgroupsv2 should be used\")\n\t\t}\n\t}\n\n\t// Initialize cgroups root path.\n\tif err := cgroup.InitRoot(); err != nil {\n\t\treturn fmt.Errorf(\"error initializing cgroups root path: %w\", err)\n\t}\n\n\tlog.Info(\"initializing cgroups\", zap.String(\"root\", cgroup.Root()))\n\n\tgroups := []string{\n\t\tconstants.CgroupInit,\n\t\tconstants.CgroupSystem,\n\t\tconstants.CgroupPodRuntimeRoot,\n\t}\n\n\tfor _, c := range groups {\n\t\t_, err := cgroup.CreateCgroup(c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn next()(ctx, log, rt, next)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/startup/startup.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package startup provides machined startup tasks.\npackage startup\n\nimport (\n\t\"context\"\n\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n)\n\n// Task is a function that performs a startup task.\n//\n// It is supposed to call the next task in the chain.\ntype Task func(context.Context, *zap.Logger, runtime.Runtime, NextTaskFunc) error\n\n// NextTaskFunc is a function which returns the next task in the chain.\ntype NextTaskFunc func() Task\n\n// RunTasks runs the given tasks in order.\nfunc RunTasks(ctx context.Context, log *zap.Logger, rt runtime.Runtime, tasks ...Task) error {\n\tvar idx int\n\n\tnextTaskFunc := func() Task {\n\t\tidx++\n\n\t\treturn tasks[idx]\n\t}\n\n\treturn tasks[0](ctx, log, rt, nextTaskFunc)\n}\n\n// DefaultTasks returns the default startup tasks.\nfunc DefaultTasks() []Task {\n\treturn []Task{\n\t\tLogMode,\n\t\tMountPseudoLate,\n\t\tSetupSystemDirectories,\n\t\tInitVolumeLifecycle,\n\t\tMountCgroups,\n\t\tSetRLimit,\n\t\tSetEnvironmentVariables,\n\t\tCreateSystemCgroups,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/startup/tasks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage startup\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// LogMode prints the current mode.\nfunc LogMode(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tlog.Info(\"platform information\", zap.Stringer(\"mode\", rt.State().Platform().Mode()))\n\tlog.Info(\"FIPS mode\", zap.Bool(\"enabled\", fipsmode.Enabled()), zap.Bool(\"strict\", fipsmode.Strict()))\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// SetupSystemDirectories creates system default directories.\nfunc SetupSystemDirectories(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tfor _, dir := range []struct {\n\t\tpath  string\n\t\tperm  os.FileMode\n\t\tlabel string\n\t}{\n\t\t{constants.SystemEtcPath, 0o700, constants.EtcSelinuxLabel},\n\t\t{constants.SystemVarPath, 0o700, constants.SystemVarSelinuxLabel},\n\t\t{constants.StateMountPoint, 0o700, \"\"},\n\t\t{constants.SystemRunPath, 0o751, \"system_u:object_r:system_run_t:s0\"},\n\t\t{\"/system/run/containerd\", 0o711, \"system_u:object_r:sys_containerd_run_t:s0\"},\n\t\t{\"/run/containerd\", 0o711, \"system_u:object_r:pod_containerd_run_t:s0\"},\n\t} {\n\t\tif err := os.MkdirAll(dir.path, dir.perm); err != nil {\n\t\t\treturn fmt.Errorf(\"setupSystemDirectories: %w\", err)\n\t\t}\n\n\t\tif dir.label != \"\" {\n\t\t\tif err := selinux.SetLabel(dir.path, dir.label); err != nil {\n\t\t\t\treturn fmt.Errorf(\"setupSystemDirectories: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// InitVolumeLifecycle initializes volume lifecycle resource.\nfunc InitVolumeLifecycle(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tif err := rt.State().V1Alpha2().Resources().Create(ctx, block.NewVolumeLifecycle(block.NamespaceName, block.VolumeLifecycleID)); err != nil {\n\t\treturn fmt.Errorf(\"initVolumeLifecycle: %w\", err)\n\t}\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// MountCgroups represents mounts the cgroupfs (only in !container).\nfunc MountCgroups(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tif rt.State().Platform().Mode().InContainer() {\n\t\treturn next()(ctx, log, rt, next)\n\t}\n\n\tif pointer.SafeDeref(procfs.ProcCmdline().Get(constants.KernelParamCGroups).First()) == \"0\" {\n\t\tlog.Warn(fmt.Sprintf(\"kernel argument %v is no longer supported\", constants.KernelParamCGroups))\n\t}\n\n\tcgroup := mount.NewCgroup2()\n\n\tif _, err := cgroup.Mount(); err != nil {\n\t\treturn fmt.Errorf(\"mountCgroups: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := cgroup.Unmount(); err != nil {\n\t\t\tlog.Warn(\"failed to unmount cgroups\", zap.Error(err))\n\t\t}\n\t}()\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// MountPseudoLate mounts the late pseudo filesystems (only in !container).\nfunc MountPseudoLate(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tif rt.State().Platform().Mode().InContainer() {\n\t\treturn next()(ctx, log, rt, next)\n\t}\n\n\tlate := mount.PseudoLate(log.Sugar().Infof)\n\n\tunmounter, err := late.Mount()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"mountPseudoLate: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := unmounter(); err != nil {\n\t\t\tlog.Warn(\"failed to unmount pseudo late\", zap.Error(err))\n\t\t}\n\t}()\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// SetRLimit sets the file descriptor limit.\nfunc SetRLimit(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\tif rt.State().Platform().Mode().InContainer() {\n\t\treturn next()(ctx, log, rt, next)\n\t}\n\n\tif err := unix.Setrlimit(unix.RLIMIT_NOFILE, &unix.Rlimit{Cur: 1048576, Max: 1048576}); err != nil {\n\t\treturn fmt.Errorf(\"setRLimit: %w\", err)\n\t}\n\n\treturn next()(ctx, log, rt, next)\n}\n\n// SetEnvironmentVariables sets the environment variables.\nfunc SetEnvironmentVariables(ctx context.Context, log *zap.Logger, rt runtime.Runtime, next NextTaskFunc) error {\n\t// Set the PATH env var.\n\tif err := os.Setenv(\"PATH\", constants.PATH); err != nil {\n\t\treturn errors.New(\"error setting PATH\")\n\t}\n\n\tif !rt.State().Platform().Mode().InContainer() {\n\t\t// in container mode, ignore cmdline\n\t\tfor _, env := range environment.Get(nil) {\n\t\t\tkey, val, _ := strings.Cut(env, \"=\")\n\n\t\t\tif err := os.Setenv(key, val); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting %s: %w\", val, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn next()(ctx, log, rt, next)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/events/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage events\n\nimport (\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// MaxEventsToKeep is maximum number of events to keep per service before dropping old entries.\nconst MaxEventsToKeep = 64\n\n// ServiceState is enum of service run states.\ntype ServiceState int\n\n// ServiceState constants.\nconst (\n\tStateInitialized ServiceState = iota\n\tStatePreparing\n\tStateWaiting\n\tStateRunning\n\tStateStopping\n\tStateFinished\n\tStateFailed\n\tStateSkipped\n\tStateStarting\n)\n\nfunc (state ServiceState) String() string {\n\tswitch state {\n\tcase StateInitialized:\n\t\treturn \"Initialized\"\n\tcase StateStarting:\n\t\treturn \"Starting\"\n\tcase StatePreparing:\n\t\treturn \"Preparing\"\n\tcase StateWaiting:\n\t\treturn \"Waiting\"\n\tcase StateRunning:\n\t\treturn \"Running\"\n\tcase StateStopping:\n\t\treturn \"Stopping\"\n\tcase StateFinished:\n\t\treturn \"Finished\"\n\tcase StateFailed:\n\t\treturn \"Failed\"\n\tcase StateSkipped:\n\t\treturn \"Skipped\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\n// ServiceEvent describes state change of the running service.\ntype ServiceEvent struct {\n\tMessage   string\n\tState     ServiceState\n\tHealth    health.Status\n\tTimestamp time.Time\n}\n\n// AsProto returns protobuf representation of respective machined event.\nfunc (event *ServiceEvent) AsProto(service string) *machineapi.ServiceStateEvent {\n\treturn &machineapi.ServiceStateEvent{\n\t\tService: service,\n\t\tAction:  machineapi.ServiceStateEvent_Action(event.State),\n\t\tMessage: event.Message,\n\t\tHealth:  event.Health.AsProto(),\n\t}\n}\n\n// ServiceEvents is a fixed length history of events.\ntype ServiceEvents struct {\n\tevents    []ServiceEvent\n\tpos       int\n\tdiscarded uint\n}\n\n// Push appends new event to the history popping out oldest event on overflow.\nfunc (events *ServiceEvents) Push(event ServiceEvent) {\n\tif events.events == nil {\n\t\tevents.events = make([]ServiceEvent, MaxEventsToKeep)\n\t}\n\n\tif events.events[events.pos].Message != \"\" {\n\t\t// overwriting some entry\n\t\tevents.discarded++\n\t}\n\n\tevents.events[events.pos] = event\n\tevents.pos = (events.pos + 1) % len(events.events)\n}\n\n// Get return a copy of event history, with most recent event being the last one.\nfunc (events *ServiceEvents) Get(count int) (result []ServiceEvent) {\n\tif events.events == nil {\n\t\treturn result\n\t}\n\n\tif count > MaxEventsToKeep {\n\t\tcount = MaxEventsToKeep\n\t}\n\n\tn := len(events.events)\n\n\tfor i := (events.pos - count + n) % n; count > 0; i = (i + 1) % n {\n\t\tif events.events[i].Message != \"\" {\n\t\t\tresult = append(result, events.events[i])\n\t\t}\n\n\t\tcount--\n\t}\n\n\treturn result\n}\n\n// AsProto returns protobuf-ready serialized snapshot.\nfunc (events *ServiceEvents) AsProto(count int) *machineapi.ServiceEvents {\n\teventList := events.Get(count)\n\n\tfn := func(event ServiceEvent) *machineapi.ServiceEvent {\n\t\ttspb := timestamppb.New(event.Timestamp)\n\n\t\treturn &machineapi.ServiceEvent{\n\t\t\tMsg:   event.Message,\n\t\t\tState: event.State.String(),\n\t\t\tTs:    tspb,\n\t\t}\n\t}\n\n\treturn &machineapi.ServiceEvents{\n\t\tEvents: xslices.Map(eventList, fn),\n\t}\n}\n\n// Recorder adds new event to the history of events, formatting message with args using Sprintf.\ntype Recorder func(newstate ServiceState, message string, args ...any)\n\n// NullRecorder discards events.\nfunc NullRecorder(newstate ServiceState, message string, args ...any) {\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/events/events_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage events_test\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n)\n\ntype EventsSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *EventsSuite) assertEvents(expectedMessages []string, evs []events.ServiceEvent) {\n\tmessages := xslices.Map(evs, func(ev events.ServiceEvent) string { return ev.Message })\n\tsuite.Assert().Equal(expectedMessages, messages)\n}\n\nfunc (suite *EventsSuite) TestEmpty() {\n\tvar e events.ServiceEvents\n\n\tsuite.Assert().Equal([]events.ServiceEvent(nil), e.Get(100))\n}\n\nfunc (suite *EventsSuite) TestSome() {\n\tvar e events.ServiceEvents\n\n\tfor i := range 5 {\n\t\te.Push(events.ServiceEvent{\n\t\t\tMessage: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tsuite.Assert().Equal([]events.ServiceEvent(nil), e.Get(0))\n\tsuite.assertEvents([]string{\"4\"}, e.Get(1))\n\tsuite.assertEvents([]string{\"1\", \"2\", \"3\", \"4\"}, e.Get(4))\n\tsuite.assertEvents([]string{\"0\", \"1\", \"2\", \"3\", \"4\"}, e.Get(5))\n\tsuite.assertEvents([]string{\"0\", \"1\", \"2\", \"3\", \"4\"}, e.Get(6))\n\tsuite.assertEvents([]string{\"0\", \"1\", \"2\", \"3\", \"4\"}, e.Get(100))\n\n\tprotoEvents := e.AsProto(1)\n\tsuite.Assert().Len(protoEvents.Events, 1)\n\tsuite.Assert().Equal(\"4\", protoEvents.Events[0].Msg)\n\tsuite.Assert().Equal(\"Initialized\", protoEvents.Events[0].State)\n}\n\nfunc (suite *EventsSuite) TestOverflow() {\n\tvar e events.ServiceEvents\n\n\tnumEvents := events.MaxEventsToKeep*2 + 3\n\n\tfor i := range numEvents {\n\t\te.Push(events.ServiceEvent{\n\t\t\tMessage: strconv.Itoa(i),\n\t\t})\n\t}\n\n\tsuite.Assert().Equal([]events.ServiceEvent(nil), e.Get(0))\n\tsuite.assertEvents([]string{strconv.Itoa(numEvents - 1)}, e.Get(1))\n\n\tvar expected []string\n\n\tfor i := numEvents - events.MaxEventsToKeep; i < numEvents; i++ {\n\t\texpected = append(expected, strconv.Itoa(i))\n\t}\n\n\tsuite.assertEvents(expected, e.Get(events.MaxEventsToKeep*10))\n\tsuite.assertEvents(expected[len(expected)-3:], e.Get(3))\n}\n\nfunc TestEventsSuite(t *testing.T) {\n\tsuite.Run(t, new(EventsSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\nfunc NewServices(runtime runtime.Runtime) *singleton { //nolint:revive\n\treturn newServices(runtime)\n}\n\nfunc WaitForServiceWithInstance(instance *singleton, event StateEvent, service string) conditions.Condition {\n\treturn waitForService(instance, event, service)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/health/check.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage health\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Check runs the health check under given context.\n//\n// Healthcheck is considered successful when func returns no error.\n// Func should terminate when context is canceled.\ntype Check func(ctx context.Context) error\n\n// Run the health check publishing the results to state.\n//\n// Run aborts when context is canceled.\nfunc Run(ctx context.Context, settings *Settings, state *State, check Check) error {\n\tstate.Init()\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-time.After(settings.InitialDelay):\n\t}\n\n\tticker := time.NewTicker(settings.Period)\n\tdefer ticker.Stop()\n\n\tvar (\n\t\terr            error\n\t\thealthy        bool\n\t\tmessage        string\n\t\tcheckCtx       context.Context\n\t\tcheckCtxCancel context.CancelFunc\n\t)\n\n\tfor {\n\t\terr = func() error {\n\t\t\tcheckCtx, checkCtxCancel = context.WithTimeout(ctx, settings.Timeout) //nolint:fatcontext\n\t\t\tdefer checkCtxCancel()\n\n\t\t\treturn check(checkCtx)\n\t\t}()\n\n\t\thealthy = err == nil\n\t\tmessage = \"\"\n\n\t\tif !healthy {\n\t\t\tmessage = err.Error()\n\t\t}\n\n\t\tstate.Update(healthy, message)\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/health/health_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage health_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n)\n\ntype CheckSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *CheckSuite) TestHealthy() {\n\tsettings := health.Settings{\n\t\tInitialDelay: time.Millisecond,\n\t\tPeriod:       10 * time.Millisecond,\n\t\tTimeout:      time.Millisecond,\n\t}\n\n\tvar called uint32\n\n\t//nolint:unparam\n\tcheck := func(context.Context) error {\n\t\tatomic.AddUint32(&called, 1)\n\n\t\treturn nil\n\t}\n\n\tvar state health.State\n\n\terrCh := make(chan error)\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tgo func() {\n\t\terrCh <- health.Run(ctx, &settings, &state, check)\n\t}()\n\n\tfor range 20 {\n\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\tif atomic.LoadUint32(&called) > 2 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tctxCancel()\n\n\tsuite.Assert().EqualError(<-errCh, context.Canceled.Error())\n\tsuite.Assert().True(called > 2)\n\n\tprotoHealth := state.AsProto()\n\tsuite.Assert().False(protoHealth.Unknown)\n\tsuite.Assert().True(protoHealth.Healthy)\n\tsuite.Assert().Equal(\"\", protoHealth.LastMessage)\n}\n\nfunc (suite *CheckSuite) TestHealthChange() {\n\tsettings := health.Settings{\n\t\tInitialDelay: time.Millisecond,\n\t\tPeriod:       time.Millisecond,\n\t\tTimeout:      time.Millisecond,\n\t}\n\n\tvar healthy atomic.Uint32\n\n\tcheck := func(context.Context) error {\n\t\tif healthy.Load() == 1 {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn errors.New(\"health failed\")\n\t}\n\n\tvar state health.State\n\n\tnotifyCh := make(chan health.StateChange, 2)\n\tstate.Subscribe(notifyCh)\n\n\terrCh := make(chan error)\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tgo func() {\n\t\terrCh <- health.Run(ctx, &settings, &state, check)\n\t}()\n\n\t// wait for the first health change\n\tfor range 20 {\n\t\tif state.Get().Healthy != nil {\n\t\t\tbreak\n\t\t}\n\n\t\ttime.Sleep(50 * time.Millisecond)\n\t}\n\n\tsuite.Require().False(*state.Get().Healthy)\n\tsuite.Require().Equal(\"health failed\", state.Get().LastMessage)\n\n\thealthy.Store(1)\n\n\tfor range 10 {\n\t\ttime.Sleep(20 * time.Millisecond)\n\n\t\tif *state.Get().Healthy {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Require().True(*state.Get().Healthy)\n\tsuite.Require().Equal(\"\", state.Get().LastMessage)\n\n\tctxCancel()\n\n\tsuite.Assert().EqualError(<-errCh, context.Canceled.Error())\n\n\tstate.Unsubscribe(notifyCh)\n\n\tclose(notifyCh)\n\n\tchange := <-notifyCh\n\tsuite.Assert().Nil(change.Old.Healthy)\n\tsuite.Assert().False(*change.New.Healthy)\n\n\tchange = <-notifyCh\n\tsuite.Assert().False(*change.Old.Healthy)\n\tsuite.Assert().True(*change.New.Healthy)\n}\n\nfunc (suite *CheckSuite) TestCheckAbort() {\n\tsettings := health.Settings{\n\t\tInitialDelay: time.Millisecond,\n\t\tPeriod:       time.Millisecond,\n\t\tTimeout:      time.Millisecond,\n\t}\n\n\tcheck := func(ctx context.Context) error {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-time.After(50 * time.Second):\n\t\t\t// should never be triggered, as Timeout is 1ms\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tvar state health.State\n\n\terrCh := make(chan error)\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tgo func() {\n\t\terrCh <- health.Run(ctx, &settings, &state, check)\n\t}()\n\n\t// wait for the first health change\n\tfor range 20 {\n\t\tif state.Get().Healthy != nil {\n\t\t\tbreak\n\t\t}\n\n\t\ttime.Sleep(50 * time.Millisecond)\n\t}\n\n\tsuite.Require().False(*state.Get().Healthy)\n\tsuite.Require().Equal(\"context deadline exceeded\", state.Get().LastMessage)\n\n\tctxCancel()\n\n\tsuite.Assert().EqualError(<-errCh, context.Canceled.Error())\n}\n\nfunc (suite *CheckSuite) TestInitialState() {\n\tsettings := health.Settings{\n\t\tInitialDelay: 5 * time.Minute,\n\t}\n\n\tvar state health.State\n\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- health.Run(ctx, &settings, &state, nil)\n\t}()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tsuite.Require().Nil(state.Get().Healthy)\n\tsuite.Require().Equal(\"Unknown\", state.Get().LastMessage)\n\n\tctxCancel()\n\n\tsuite.Assert().EqualError(<-errCh, context.Canceled.Error())\n}\n\nfunc TestCheckSuite(t *testing.T) {\n\tsuite.Run(t, new(CheckSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/health/settings.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage health\n\nimport \"time\"\n\n// Settings configures health check\n//\n// Fields are similar to k8s pod probe definitions.\ntype Settings struct {\n\tInitialDelay time.Duration\n\tPeriod       time.Duration\n\tTimeout      time.Duration\n}\n\n// DefaultSettings provides some default health check settings.\nvar DefaultSettings = Settings{\n\tInitialDelay: time.Second,\n\tPeriod:       5 * time.Second,\n\tTimeout:      500 * time.Millisecond,\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/health/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage health\n\nimport (\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// Status of the healthcheck.\ntype Status struct {\n\tHealthy     *bool\n\tLastChange  time.Time\n\tLastMessage string\n}\n\n// AsProto returns protobuf-ready health state.\nfunc (status *Status) AsProto() *machineapi.ServiceHealth {\n\ttspb := timestamppb.New(status.LastChange)\n\n\treturn &machineapi.ServiceHealth{\n\t\tUnknown:     status.Healthy == nil,\n\t\tHealthy:     status.Healthy != nil && *status.Healthy,\n\t\tLastMessage: status.LastMessage,\n\t\tLastChange:  tspb,\n\t}\n}\n\n// StateChange is used to notify about status changes.\ntype StateChange struct {\n\tOld Status\n\tNew Status\n}\n\n// State provides proper locking around health state.\ntype State struct {\n\tsync.Mutex\n\n\tstatus      Status\n\tsubscribers []chan<- StateChange\n}\n\n// Update health status (locked).\nfunc (state *State) Update(healthy bool, message string) {\n\tstate.Lock()\n\n\toldStatus := state.status\n\tnotify := false\n\n\tif state.status.Healthy == nil || *state.status.Healthy != healthy {\n\t\tnotify = true\n\t\tstate.status.Healthy = &healthy\n\t\tstate.status.LastChange = time.Now()\n\t}\n\n\tstate.status.LastMessage = message\n\n\tnewStatus := state.status\n\n\tvar subscribers []chan<- StateChange\n\tif notify {\n\t\tsubscribers = slices.Clone(state.subscribers)\n\t}\n\n\tstate.Unlock()\n\n\tif notify {\n\t\tfor _, ch := range subscribers {\n\t\t\tselect {\n\t\t\tcase ch <- StateChange{oldStatus, newStatus}:\n\t\t\tdefault: // drop messages to clients which don't consume them\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Subscribe for the notifications on state changes.\nfunc (state *State) Subscribe(ch chan<- StateChange) {\n\tstate.Lock()\n\tdefer state.Unlock()\n\n\tstate.subscribers = append(state.subscribers, ch)\n}\n\n// Unsubscribe from state changes.\nfunc (state *State) Unsubscribe(ch chan<- StateChange) {\n\tstate.Lock()\n\tdefer state.Unlock()\n\n\tfor i := 0; i < len(state.subscribers); {\n\t\tif state.subscribers[i] == ch {\n\t\t\tstate.subscribers[i] = state.subscribers[len(state.subscribers)-1]\n\t\t\tstate.subscribers[len(state.subscribers)-1] = nil\n\t\t\tstate.subscribers = state.subscribers[:len(state.subscribers)-1]\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n}\n\n// Init health status (locked).\nfunc (state *State) Init() {\n\tstate.Lock()\n\tdefer state.Unlock()\n\n\tstate.status.LastMessage = \"Unknown\"\n\tstate.status.LastChange = time.Now()\n\tstate.status.Healthy = nil\n}\n\n// Get returns health status (locked).\nfunc (state *State) Get() Status {\n\tstate.Lock()\n\tdefer state.Unlock()\n\n\treturn state.status\n}\n\n// AsProto returns protobuf-ready health state.\nfunc (state *State) AsProto() *machineapi.ServiceHealth {\n\tstatus := state.Get()\n\n\treturn status.AsProto()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/integration_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system_test\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\ntype TestCondition struct{}\n\nfunc (TestCondition) String() string {\n\treturn \"test-condition\"\n}\n\nfunc (TestCondition) Wait(ctx context.Context) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-time.After(10 * time.Millisecond):\n\t\treturn nil\n\t}\n}\n\ntype TestService struct{}\n\nfunc (TestService) ID(runtime.Runtime) string {\n\treturn \"test-service\"\n}\n\nfunc (TestService) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc (TestService) Runner(r runtime.Runtime) (runner.Runner, error) {\n\treturn goroutine.NewRunner(r, \"test-service\", func(ctx context.Context, r runtime.Runtime, logOutput io.Writer) error {\n\t\t<-ctx.Done()\n\n\t\treturn nil\n\t}), nil\n}\n\nfunc (TestService) PostFunc(runtime.Runtime, events.ServiceState) error {\n\treturn nil\n}\n\nfunc (TestService) Condition(runtime.Runtime) conditions.Condition {\n\treturn TestCondition{}\n}\n\nfunc (TestService) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\nfunc (TestService) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\nfunc TestRestartService(t *testing.T) {\n\tdeadline, ok := t.Deadline()\n\tif !ok {\n\t\tdeadline = time.Now().Add(15 * time.Second)\n\t}\n\n\tctx, cancel := context.WithDeadline(t.Context(), deadline)\n\tdefer cancel()\n\n\tservices := system.NewServices(nil)\n\n\tservices.Load(TestService{})\n\n\tfor range 100 {\n\t\trequire.NoError(t, services.Start(\"test-service\"))\n\n\t\trequire.NoError(t, system.WaitForServiceWithInstance(services, system.StateEventUp, \"test-service\").Wait(ctx))\n\n\t\trequire.NoError(t, services.Stop(ctx, \"test-service\"))\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/mocks_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\ntype MockService struct {\n\tname         string\n\tpreError     error\n\trunnerError  error\n\tnilRunner    bool\n\trunner       runner.Runner\n\tcondition    conditions.Condition\n\tpostError    error\n\tdependencies []string\n}\n\nfunc (m *MockService) ID(runtime.Runtime) string {\n\tif m.name != \"\" {\n\t\treturn m.name\n\t}\n\n\treturn \"MockRunner\"\n}\n\nfunc (m *MockService) PreFunc(context.Context, runtime.Runtime) error {\n\treturn m.preError\n}\n\nfunc (m *MockService) Runner(runtime.Runtime) (runner.Runner, error) {\n\tif m.runner != nil {\n\t\treturn m.runner, m.runnerError\n\t}\n\n\tif m.nilRunner {\n\t\treturn nil, nil\n\t}\n\n\treturn &MockRunner{exitCh: make(chan error)}, m.runnerError\n}\n\nfunc (m *MockService) PostFunc(runtime.Runtime, events.ServiceState) error {\n\treturn m.postError\n}\n\nfunc (m *MockService) Condition(runtime.Runtime) conditions.Condition {\n\treturn m.condition\n}\n\nfunc (m *MockService) DependsOn(runtime.Runtime) []string {\n\treturn m.dependencies\n}\n\nfunc (m *MockService) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\ntype MockHealthcheckedService struct {\n\tMockService\n\n\tnotHealthy atomic.Uint32\n}\n\nfunc (m *MockHealthcheckedService) SetHealthy(healthy bool) {\n\tif healthy {\n\t\tm.notHealthy.Store(0)\n\t} else {\n\t\tm.notHealthy.Store(1)\n\t}\n}\n\nfunc (m *MockHealthcheckedService) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(context.Context) error {\n\t\tif m.notHealthy.Load() == 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn errors.New(\"not healthy\")\n\t}\n}\n\nfunc (m *MockHealthcheckedService) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.Settings{\n\t\tInitialDelay: time.Millisecond,\n\t\tTimeout:      time.Second,\n\t\tPeriod:       time.Millisecond,\n\t}\n}\n\ntype MockRunner struct {\n\texitCh chan error\n}\n\nfunc (m *MockRunner) Open() error {\n\treturn nil\n}\n\nfunc (m *MockRunner) Close() error {\n\treturn nil\n}\n\nfunc (m *MockRunner) Run(eventSink events.Recorder) error {\n\teventSink(events.StateRunning, \"Running\")\n\n\treturn <-m.exitCh\n}\n\nfunc (m *MockRunner) Stop() error {\n\tclose(m.exitCh)\n\n\treturn nil\n}\n\nfunc (m *MockRunner) String() string {\n\treturn \"MockRunner()\"\n}\n\ntype MockCondition struct {\n\tdone chan struct{}\n\tdesc string\n}\n\nfunc NewMockCondition(desc string) *MockCondition {\n\treturn &MockCondition{\n\t\tdone: make(chan struct{}),\n\t\tdesc: desc,\n\t}\n}\n\nfunc (m *MockCondition) String() string {\n\treturn m.desc\n}\n\nfunc (m *MockCondition) Wait(ctx context.Context) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-m.done:\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/containerd/containerd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"syscall\"\n\t\"time\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/contrib/seccomp\"\n\t\"github.com/containerd/containerd/v2/pkg/cio\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/errdefs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/internal/lastlog\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// containerdRunner is a runner.Runner that runs container in containerd.\ntype containerdRunner struct {\n\targs         *runner.Args\n\topts         *runner.Options\n\tlogToConsole bool\n\n\tstop    chan struct{}\n\tstopped chan struct{}\n\n\tclient      *containerd.Client\n\tctx         context.Context //nolint:containedctx\n\tcontainer   containerd.Container\n\tstdinCloser *StdinCloser\n}\n\n// NewRunner creates runner.Runner that runs a container in containerd.\nfunc NewRunner(logToConsole bool, args *runner.Args, setters ...runner.Option) runner.Runner {\n\tr := &containerdRunner{\n\t\targs:         args,\n\t\topts:         runner.DefaultOptions(),\n\t\tlogToConsole: logToConsole,\n\t\tstop:         make(chan struct{}),\n\t\tstopped:      make(chan struct{}),\n\t}\n\n\tfor _, setter := range setters {\n\t\tsetter(r.opts)\n\t}\n\n\treturn r\n}\n\n// Open implements the Runner interface.\nfunc (c *containerdRunner) Open() error {\n\t// Create the containerd client.\n\tvar err error\n\n\tc.ctx = namespaces.WithNamespace(context.Background(), c.opts.Namespace)\n\n\tc.client, err = containerd.New(c.opts.ContainerdAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar image containerd.Image\n\n\tif c.opts.ContainerImage != \"\" {\n\t\timage, err = c.client.GetImage(c.ctx, c.opts.ContainerImage)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// See if there's previous container/snapshot to clean up\n\tvar oldcontainer containerd.Container\n\n\tif oldcontainer, err = c.client.LoadContainer(c.ctx, c.args.ID); err == nil {\n\t\tif err = oldcontainer.Delete(c.ctx, containerd.WithSnapshotCleanup); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting old container instance: %w\", err)\n\t\t}\n\t}\n\n\tif err = c.client.SnapshotService(\"\").Remove(c.ctx, c.args.ID); err != nil && !errdefs.IsNotFound(err) {\n\t\treturn fmt.Errorf(\"error cleaning up stale snapshot: %w\", err)\n\t}\n\n\t// Create the container.\n\tspecOpts := c.newOCISpecOpts(image)\n\tcontainerOpts := c.newContainerOpts(image, specOpts)\n\n\tc.container, err = c.client.NewContainer(\n\t\tc.ctx,\n\t\tc.args.ID,\n\t\tcontainerOpts...,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create container %q: %w\", c.args.ID, err)\n\t}\n\n\treturn nil\n}\n\n// Close implements runner.Runner interface.\nfunc (c *containerdRunner) Close() error {\n\tif c.container != nil {\n\t\terr := c.container.Delete(c.ctx, containerd.WithSnapshotCleanup)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif c.client == nil {\n\t\treturn nil\n\t}\n\n\treturn c.client.Close()\n}\n\n// Run implements runner.Runner interface\n//\n//nolint:gocyclo,cyclop\nfunc (c *containerdRunner) Run(eventSink events.Recorder) error {\n\tdefer close(c.stopped)\n\n\tvar (\n\t\ttask containerd.Task\n\t\tlogW io.WriteCloser\n\t\terr  error\n\t)\n\n\t// attempt to clean up a task if it already exists\n\ttask, err = c.container.Task(c.ctx, nil)\n\tif err == nil {\n\t\tvar s <-chan containerd.ExitStatus\n\n\t\ts, err = task.Wait(c.ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to wait for the task %q: %w\", c.args.ID, err)\n\t\t}\n\n\t\terr = task.Kill(c.ctx, syscall.SIGKILL, containerd.WithKillAll)\n\t\tif err != nil && !errdefs.IsNotFound(err) {\n\t\t\treturn fmt.Errorf(\"failed to kill the task %q: %w\", c.args.ID, err)\n\t\t}\n\n\t\tselect {\n\t\tcase <-s:\n\t\tcase <-c.stop:\n\t\t\treturn nil\n\t\t}\n\n\t\tif _, err = task.Delete(c.ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to clean up task %q: %w\", c.args.ID, err)\n\t\t}\n\t}\n\n\tlogW, err = c.opts.LoggingManager.ServiceLog(c.args.ID).Writer()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating log: %w\", err)\n\t}\n\n\tcg, err := cgroup.CreateCgroup(c.opts.CgroupPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating cgroup: %w\", err)\n\t}\n\n\t// If the task is not cleaned up by containerd or another error\n\t// happens during the lifecycle, remove the cgroup before exiting\n\t// if one still exists\n\tdefer func() {\n\t\terr := cg.Delete()\n\t\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t\teventSink(events.StateStopping, \"Failed to remove cgroup for %s, %s\", c, err)\n\t\t}\n\t}()\n\n\tdefer logW.Close() //nolint:errcheck\n\n\tvar (\n\t\tlastLog lastlog.Writer\n\t\tw       = io.MultiWriter(logW, &lastLog)\n\t)\n\n\tif c.logToConsole {\n\t\tw = io.MultiWriter(w, log.Writer())\n\t}\n\n\tr, err := c.StdinReader()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create stdin reader: %w\", err)\n\t}\n\n\tcreator := cio.NewCreator(cio.WithStreams(r, w, w))\n\n\t// Create the task and start it.\n\ttask, err = c.container.NewTask(c.ctx, creator)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create task: %q: %w\", c.args.ID, err)\n\t}\n\n\tif r != nil {\n\t\t// See https://github.com/containerd/containerd/issues/4489.\n\t\tgo c.stdinCloser.WaitAndClose(c.ctx, task)\n\t}\n\n\tdefer task.Delete(c.ctx) //nolint:errcheck\n\n\tif err = task.Start(c.ctx); err != nil {\n\t\treturn fmt.Errorf(\"failed to start task: %q: %w\", c.args.ID, err)\n\t}\n\n\teventSink(events.StateRunning, \"Started task %s (PID %d) for container %s\", task.ID(), task.Pid(), c.container.ID())\n\n\tstatusC, err := task.Wait(c.ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed waiting for task: %q: %w\", c.args.ID, err)\n\t}\n\n\tselect {\n\tcase status := <-statusC:\n\t\tcode := status.ExitCode()\n\t\tif code != 0 {\n\t\t\treturn fmt.Errorf(\"task %q failed: exit code %d (last log %q)\", c.args.ID, code, lastLog.GetLastLog())\n\t\t}\n\n\t\treturn nil\n\tcase <-c.stop:\n\t\t// graceful stop the task\n\t\teventSink(\n\t\t\tevents.StateStopping,\n\t\t\t\"Sending SIGTERM to task %s (PID %d, container %s)\",\n\t\t\ttask.ID(),\n\t\t\ttask.Pid(),\n\t\t\tc.container.ID(),\n\t\t)\n\n\t\tif err = task.Kill(c.ctx, syscall.SIGTERM, containerd.WithKillAll); err != nil {\n\t\t\treturn fmt.Errorf(\"error sending SIGTERM: %w\", err)\n\t\t}\n\t}\n\n\tselect {\n\tcase <-statusC:\n\t\t// stopped process exited\n\t\treturn nil\n\tcase <-time.After(c.opts.GracefulShutdownTimeout):\n\t\t// kill the process\n\t\teventSink(\n\t\t\tevents.StateStopping,\n\t\t\t\"Sending SIGKILL to task %s (PID %d, container %s)\",\n\t\t\ttask.ID(),\n\t\t\ttask.Pid(),\n\t\t\tc.container.ID(),\n\t\t)\n\n\t\tif err = task.Kill(c.ctx, syscall.SIGKILL, containerd.WithKillAll); err != nil {\n\t\t\treturn fmt.Errorf(\"error sending SIGKILL: %w\", err)\n\t\t}\n\t}\n\n\t<-statusC\n\n\treturn logW.Close()\n}\n\n// Stop implements runner.Runner interface.\nfunc (c *containerdRunner) Stop() error {\n\tclose(c.stop)\n\n\t<-c.stopped\n\n\tc.stop = make(chan struct{})\n\tc.stopped = make(chan struct{})\n\n\treturn nil\n}\n\nfunc (c *containerdRunner) newContainerOpts(\n\timage containerd.Image,\n\tspecOpts []oci.SpecOpts,\n) []containerd.NewContainerOpts {\n\tvar containerOpts []containerd.NewContainerOpts\n\n\tif image != nil {\n\t\tcontainerOpts = append(\n\t\t\tcontainerOpts,\n\t\t\tcontainerd.WithImage(image),\n\t\t\tcontainerd.WithNewSnapshot(c.args.ID, image),\n\t\t)\n\t}\n\n\tcontainerOpts = append(\n\t\tcontainerOpts,\n\t\tcontainerd.WithNewSpec(specOpts...),\n\t)\n\n\tcontainerOpts = append(\n\t\tcontainerOpts,\n\t\tc.opts.ContainerOpts...,\n\t)\n\n\treturn containerOpts\n}\n\nfunc (c *containerdRunner) newOCISpecOpts(image oci.Image) []oci.SpecOpts {\n\tvar specOpts []oci.SpecOpts\n\n\tif image != nil {\n\t\tspecOpts = append(\n\t\t\tspecOpts,\n\t\t\toci.WithImageConfig(image),\n\t\t)\n\t}\n\n\tspecOpts = append(\n\t\tspecOpts,\n\t\toci.WithProcessArgs(c.args.ProcessArgs...),\n\t\toci.WithEnv(c.opts.Env),\n\t\toci.WithHostHostsFile,\n\t\toci.WithHostResolvconf,\n\t\toci.WithNoNewPrivileges,\n\t)\n\n\tif c.opts.OOMScoreAdj != 0 {\n\t\tspecOpts = append(\n\t\t\tspecOpts,\n\t\t\tWithOOMScoreAdj(c.opts.OOMScoreAdj),\n\t\t)\n\t}\n\n\tif c.opts.CgroupPath != \"\" {\n\t\tspecOpts = append(\n\t\t\tspecOpts,\n\t\t\toci.WithCgroup(cgroup.Path(c.opts.CgroupPath)),\n\t\t)\n\t}\n\n\tspecOpts = append(\n\t\tspecOpts,\n\t\tc.opts.OCISpecOpts...,\n\t)\n\n\tif c.opts.OverrideSeccompProfile != nil {\n\t\tspecOpts = append(\n\t\t\tspecOpts,\n\t\t\tWithCustomSeccompProfile(c.opts.OverrideSeccompProfile),\n\t\t)\n\t} else {\n\t\tspecOpts = append(\n\t\t\tspecOpts,\n\t\t\tseccomp.WithDefaultProfile(), // add seccomp profile last, as it depends on process capabilities\n\t\t)\n\t}\n\n\tif selinux.IsEnabled() {\n\t\tif c.opts.SelinuxLabel != \"\" {\n\t\t\tspecOpts = append(\n\t\t\t\tspecOpts,\n\t\t\t\toci.WithSelinuxLabel(c.opts.SelinuxLabel),\n\t\t\t)\n\t\t} else {\n\t\t\tspecOpts = append(\n\t\t\t\tspecOpts,\n\t\t\t\toci.WithSelinuxLabel(constants.SelinuxLabelUnconfinedSysContainer),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn specOpts\n}\n\nfunc (c *containerdRunner) String() string {\n\treturn fmt.Sprintf(\"Containerd(%v)\", c.args.ID)\n}\n\nfunc (c *containerdRunner) StdinReader() (io.Reader, error) {\n\tif c.opts.Stdin == nil {\n\t\treturn nil, nil\n\t}\n\n\tif _, err := c.opts.Stdin.Seek(0, 0); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// copy the input buffer as containerd API seems to be buggy:\n\t//  * if the task fails to start, IO loop is not stopped properly, so after a restart there are two goroutines concurrently reading from stdin\n\tcontents, err := io.ReadAll(c.opts.Stdin)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.stdinCloser = &StdinCloser{\n\t\tStdin:  bytes.NewReader(contents),\n\t\tCloser: make(chan struct{}),\n\t}\n\n\treturn c.stdinCloser, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/containerd/containerd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/google/uuid\"\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\tcontainerdrunner \"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tbusyboxImage = \"docker.io/library/busybox:latest\"\n)\n\nfunc MockEventSink(state events.ServiceState, message string, args ...any) {\n\tlog.Printf(\"state %s: %s\", state, fmt.Sprintf(message, args...))\n}\n\ntype ContainerdSuite struct {\n\tsuite.Suite\n\n\ttmpDir string\n\n\tloggingManager runtime.LoggingManager\n\n\tcontainerdNamespace string\n\tcontainerdRunner    runner.Runner\n\tcontainerdWg        sync.WaitGroup\n\tcontainerdAddress   string\n\n\tcontainerID string\n\n\tclient *containerd.Client\n\timage  containerd.Image\n}\n\nfunc (suite *ContainerdSuite) SetupSuite() {\n\tvar err error\n\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tsuite.loggingManager = logging.NewFileLoggingManager(suite.tmpDir)\n\n\tstateDir, rootDir := filepath.Join(suite.tmpDir, \"state\"), filepath.Join(suite.tmpDir, \"root\")\n\tsuite.Require().NoError(os.Mkdir(stateDir, 0o777))\n\tsuite.Require().NoError(os.Mkdir(rootDir, 0o777))\n\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tvar manager *cgroup2.Manager\n\n\t\tmanager, err = cgroup2.NewManager(constants.CgroupMountPath, \"/\"+suite.T().Name(), &cgroup2.Resources{})\n\t\tsuite.Require().NoError(err)\n\n\t\t// when using buildkit runner, parent `cgroup.type` is set to `domain threaded`, so child cgroups have to explicitly specify\n\t\t// `cgroup.type` to \"threaded\" https://www.kernel.org/doc/html/v5.0/admin-guide/cgroup-v2.html#threads\n\t\tsuite.Require().NoError(os.WriteFile(filepath.Join(constants.CgroupMountPath, suite.T().Name(), \"cgroup.type\"), []byte(\"threaded\"), 0o644))\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t} else {\n\t\tvar manager cgroup1.Cgroup\n\n\t\tmanager, err = cgroup1.New(cgroup1.NestedPath(suite.tmpDir), &specs.LinuxResources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t}\n\n\tsuite.containerdAddress = filepath.Join(suite.tmpDir, \"run.sock\")\n\n\targs := &runner.Args{\n\t\tID: \"containerd\",\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\", suite.containerdAddress,\n\t\t\t\"--state\", stateDir,\n\t\t\t\"--root\", rootDir,\n\t\t\t\"--config\", constants.CRIContainerdConfig,\n\t\t},\n\t}\n\n\tsuite.containerdRunner = process.NewRunner(\n\t\tfalse,\n\t\targs,\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithEnv([]string{constants.EnvPathWithBin}),\n\t\trunner.WithCgroupPath(\"/\"+suite.T().Name()),\n\t)\n\tsuite.Require().NoError(suite.containerdRunner.Open())\n\n\tsuite.containerdWg.Go(func() {\n\t\tdefer suite.containerdRunner.Close() //nolint:errcheck\n\n\t\tsuite.containerdRunner.Run(MockEventSink) //nolint:errcheck\n\t})\n\n\tsuite.client, err = containerd.New(suite.containerdAddress)\n\tsuite.Require().NoError(err)\n\n\tnamespace := ([16]byte)(uuid.New())\n\tsuite.containerdNamespace = \"talos\" + hex.EncodeToString(namespace[:])\n\n\tctx := namespaces.WithNamespace(context.Background(), suite.containerdNamespace)\n\n\tsuite.image, err = suite.client.Pull(ctx, busyboxImage, containerd.WithPullUnpack)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *ContainerdSuite) SetupTest() {\n\tsuite.containerID = uuid.New().String()\n}\n\nfunc (suite *ContainerdSuite) TearDownSuite() {\n\tsuite.Require().NoError(suite.client.Close())\n\n\tsuite.Require().NoError(suite.containerdRunner.Stop())\n\tsuite.containerdWg.Wait()\n}\n\nfunc (suite *ContainerdSuite) getLogContents(filename string) []byte {\n\tlogFile, err := os.Open(filepath.Join(suite.tmpDir, filename))\n\tsuite.Assert().NoError(err)\n\n\t//nolint:errcheck\n\tdefer logFile.Close()\n\n\tlogContents, err := io.ReadAll(logFile)\n\tsuite.Assert().NoError(err)\n\n\treturn logContents\n}\n\nfunc (suite *ContainerdSuite) TestRunSuccess() {\n\tr := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"exit 0\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink))\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *ContainerdSuite) TestRunTwice() {\n\tr := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"exit 0\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\t// running same container twice should be fine\n\t// (checks that containerd state is cleaned up properly)\n\tfor i := range 2 {\n\t\tsuite.Assert().NoError(r.Run(MockEventSink))\n\t\t// calling stop when Run has finished is no-op\n\t\tsuite.Assert().NoError(r.Stop())\n\n\t\tif i == 0 {\n\t\t\t// wait a bit to let containerd clean up the state\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t}\n\t}\n}\n\nfunc (suite *ContainerdSuite) TestContainerCleanup() {\n\t// create two runners with the same container ID\n\t//\n\t// open first runner, but don't close it; second runner should be\n\t// able to start the container by cleaning up container created by the first\n\t// runner\n\tr1 := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"exit 1\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r1.Open())\n\n\tr2 := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"exit 0\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\tsuite.Require().NoError(r2.Open())\n\n\tdefer func() { suite.Assert().NoError(r2.Close()) }()\n\n\tsuite.Assert().NoError(r2.Run(MockEventSink))\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r2.Stop())\n}\n\nfunc (suite *ContainerdSuite) TestRunLogs() {\n\tr := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"echo -n \\\"Test 1\\nTest 2\\n\\\"\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink))\n\n\tlogFile, err := os.Open(filepath.Join(suite.tmpDir, suite.containerID+\".log\"))\n\tsuite.Assert().NoError(err)\n\n\t//nolint:errcheck\n\tdefer logFile.Close()\n\n\tlogContents, err := io.ReadAll(logFile)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Equal([]byte(\"Test 1\\nTest 2\\n\"), logContents)\n}\n\nfunc (suite *ContainerdSuite) TestStopFailingAndRestarting() {\n\ttestDir := filepath.Join(suite.tmpDir, \"test\")\n\tsuite.Assert().NoError(os.Mkdir(testDir, 0o770))\n\n\ttestFile := filepath.Join(testDir, \"talos-test\")\n\t//nolint:errcheck\n\t_ = os.Remove(testFile)\n\n\tr := restart.New(containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"test -f \" + testFile + \" && echo ok || (echo fail; false)\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithOCISpecOpts(\n\t\t\toci.WithMounts([]specs.Mount{\n\t\t\t\t{Type: \"bind\", Destination: testDir, Source: testDir, Options: []string{\"bind\", \"ro\"}},\n\t\t\t}),\n\t\t),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t\trestart.WithRestartInterval(5*time.Millisecond),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink)\n\t}()\n\n\tfor range 10 {\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\tif bytes.Contains(suite.getLogContents(suite.containerID+\".log\"), []byte(\"fail\\n\")) {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tselect {\n\tcase err := <-done:\n\t\tsuite.Assert().Failf(\"task should be running\", \"error: %s\", err)\n\n\t\treturn\n\tdefault:\n\t}\n\n\tf, err := os.Create(testFile)\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().NoError(f.Close())\n\n\tfor range 10 {\n\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\tif bytes.Contains(suite.getLogContents(suite.containerID+\".log\"), []byte(\"ok\\n\")) {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tselect {\n\tcase err = <-done:\n\t\tsuite.Assert().Failf(\"task should be running\", \"error: %s\", err)\n\n\t\treturn\n\tdefault:\n\t}\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n\n\tlogContents := suite.getLogContents(suite.containerID + \".log\")\n\n\tsuite.Assert().Truef(bytes.Contains(logContents, []byte(\"ok\\n\")), \"logContents doesn't contain success entry: %v\", logContents)\n\tsuite.Assert().Truef(bytes.Contains(logContents, []byte(\"fail\\n\")), \"logContents doesn't contain fail entry: %v\", logContents)\n}\n\nfunc (suite *ContainerdSuite) TestStopSigKill() {\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tsuite.T().Skip(\"test doesn't pass under cgroupsv2\")\n\t}\n\n\tr := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"trap -- '' SIGTERM; while :; do :; done\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink)\n\t}()\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tselect {\n\tcase <-done:\n\t\tsuite.Assert().Fail(\"container should be still running\")\n\tdefault:\n\t}\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().NoError(<-done)\n}\n\nfunc (suite *ContainerdSuite) TestContainerStdin() {\n\tstdin := bytes.Repeat([]byte{0xde, 0xad, 0xbe, 0xef}, 2000)\n\n\tr := containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/cat\"},\n\t},\n\t\trunner.WithStdin(bytes.NewReader(stdin)),\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t)\n\n\tsuite.Require().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink))\n\n\tlogFile, err := os.Open(filepath.Join(suite.tmpDir, suite.containerID+\".log\"))\n\tsuite.Assert().NoError(err)\n\n\t//nolint:errcheck\n\tdefer logFile.Close()\n\n\tlogContents, err := io.ReadAll(logFile)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Equal(stdin, logContents)\n}\n\nfunc TestContainerdSuite(t *testing.T) {\n\tif os.Getuid() != 0 {\n\t\tt.Skip(\"can't run the test as non-root\")\n\t}\n\n\t_, err := os.Stat(\"/bin/containerd\")\n\tif err != nil {\n\t\tt.Skip(\"containerd binary is not available, skipping the test\")\n\t}\n\n\tsuite.Run(t, new(ContainerdSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/containerd/opts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd\n\nimport (\n\t\"context\"\n\n\t\"github.com/containerd/containerd/v2/contrib/seccomp\"\n\t\"github.com/containerd/containerd/v2/core/containers\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n)\n\n// WithRootfsPropagation sets the root filesystem propagation.\nfunc WithRootfsPropagation(rp string) oci.SpecOpts {\n\treturn func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {\n\t\ts.Linux.RootfsPropagation = rp\n\n\t\treturn nil\n\t}\n}\n\n// WithOOMScoreAdj sets the oom score.\nfunc WithOOMScoreAdj(score int) oci.SpecOpts {\n\treturn func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {\n\t\ts.Process.OOMScoreAdj = &score\n\n\t\treturn nil\n\t}\n}\n\n// WithCustomSeccompProfile allows to override default seccomp profile.\nfunc WithCustomSeccompProfile(override func(*specs.LinuxSeccomp)) oci.SpecOpts {\n\treturn func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {\n\t\ts.Linux.Seccomp = seccomp.DefaultProfile(s)\n\n\t\toverride(s.Linux.Seccomp)\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/containerd/stdin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n)\n\n// StdinCloser wraps io.Reader providing a signal when reader is read till EOF.\ntype StdinCloser struct {\n\tStdin  io.Reader\n\tCloser chan struct{}\n}\n\nfunc (s *StdinCloser) Read(p []byte) (int, error) {\n\tn, err := s.Stdin.Read(p)\n\tif err == io.EOF {\n\t\tclose(s.Closer)\n\t}\n\n\treturn n, err\n}\n\n// WaitAndClose closes containerd task stdin when StdinCloser is exhausted.\nfunc (s *StdinCloser) WaitAndClose(ctx context.Context, task containerd.Task) {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn\n\tcase <-s.Closer:\n\t\t//nolint:errcheck\n\t\ttask.CloseIO(ctx, containerd.WithStdinCloser)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/goroutine/goroutine.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage goroutine\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\tstdlibruntime \"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n)\n\n// ErrAborted is returned by the service when it's aborted (doesn't stop on timeout).\nvar ErrAborted = errors.New(\"service aborted\")\n\n// goroutineRunner is a runner.Runner that runs a service in a goroutine.\ntype goroutineRunner struct {\n\tmain    FuncMain\n\tid      string\n\truntime runtime.Runtime\n\n\topts *runner.Options\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\twg sync.WaitGroup\n}\n\n// FuncMain is a entrypoint into the service.\n//\n// Service should abort and return when ctx is canceled.\ntype FuncMain func(ctx context.Context, r runtime.Runtime, logOutput io.Writer) error\n\n// NewRunner creates runner.Runner that runs a service as goroutine.\nfunc NewRunner(r runtime.Runtime, id string, main FuncMain, setters ...runner.Option) runner.Runner {\n\trun := &goroutineRunner{\n\t\tid:      id,\n\t\truntime: r,\n\t\tmain:    main,\n\t\topts:    runner.DefaultOptions(),\n\t}\n\n\trun.ctx, run.ctxCancel = context.WithCancel(context.Background())\n\n\tfor _, setter := range setters {\n\t\tsetter(run.opts)\n\t}\n\n\treturn run\n}\n\n// Open implements the Runner interface.\nfunc (r *goroutineRunner) Open() error {\n\treturn nil\n}\n\n// Run implements the Runner interface.\nfunc (r *goroutineRunner) Run(eventSink events.Recorder) error {\n\tr.wg.Add(1)\n\tdefer r.wg.Done()\n\n\teventSink(events.StateRunning, \"Service started as goroutine\")\n\n\terrCh := make(chan error)\n\tctx := r.ctx\n\n\tgo func() {\n\t\terrCh <- r.wrappedMain(ctx)\n\t}()\n\n\tselect {\n\tcase <-r.ctx.Done():\n\t\teventSink(events.StateStopping, \"Service stopping\")\n\tcase err := <-errCh:\n\t\t// service finished on its own\n\t\treturn err\n\t}\n\n\tselect {\n\tcase <-time.After(r.opts.GracefulShutdownTimeout * 2):\n\t\teventSink(events.StateStopping, \"Service hasn't stopped gracefully on timeout, aborting\")\n\n\t\treturn ErrAborted\n\tcase err := <-errCh:\n\t\treturn err\n\t}\n}\n\nfunc (r *goroutineRunner) wrappedMain(ctx context.Context) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tbuf := make([]byte, 8192)\n\t\t\tn := stdlibruntime.Stack(buf, false)\n\t\t\terr = fmt.Errorf(\"panic in service: %v\\n%s\", r, string(buf[:n]))\n\t\t}\n\t}()\n\n\tw, err := r.opts.LoggingManager.ServiceLog(r.id).Writer()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"service log handler: %w\", err)\n\t}\n\n\twriterCloser := sync.OnceValue(w.Close)\n\n\tdefer writerCloser() //nolint:errcheck\n\n\tif err = r.main(ctx, r.runtime, w); !errors.Is(err, context.Canceled) {\n\t\treturn err // return error if it's not context.Canceled (service was not aborted)\n\t}\n\n\treturn writerCloser()\n}\n\n// Stop implements the Runner interface.\nfunc (r *goroutineRunner) Stop() error {\n\tr.ctxCancel()\n\n\tr.wg.Wait()\n\n\tr.ctx, r.ctxCancel = context.WithCancel(context.Background())\n\n\treturn nil\n}\n\n// Close implements the Runner interface.\nfunc (r *goroutineRunner) Close() error {\n\treturn nil\n}\n\nfunc (r *goroutineRunner) String() string {\n\treturn fmt.Sprintf(\"Goroutine(%q)\", r.id)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/goroutine/goroutine_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage goroutine_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\tv1alpha1cfg \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc MockEventSink(state events.ServiceState, message string, args ...any) {\n\tlog.Printf(\"state %s: %s\", state, fmt.Sprintf(message, args...))\n}\n\ntype GoroutineSuite struct {\n\tsuite.Suite\n\n\tr runtime.Runtime\n\n\ttmpDir string\n\n\tloggingManager runtime.LoggingManager\n}\n\nfunc (suite *GoroutineSuite) SetupSuite() {\n\tvar err error\n\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tsuite.loggingManager = logging.NewFileLoggingManager(suite.tmpDir)\n\n\ts, err := v1alpha1.NewState()\n\tsuite.Require().NoError(err)\n\n\tcfg, err := container.New(&v1alpha1cfg.Config{})\n\tsuite.Require().NoError(err)\n\n\te := v1alpha1.NewEvents(100, 10)\n\n\tr := v1alpha1.NewRuntime(s, e, suite.loggingManager)\n\n\tsuite.Require().NoError(r.SetConfig(cfg))\n\n\tsuite.r = r\n}\n\nfunc (suite *GoroutineSuite) TestRunSuccess() {\n\tr := goroutine.NewRunner(suite.r, \"testsuccess\",\n\t\tfunc(context.Context, runtime.Runtime, io.Writer) error {\n\t\t\treturn nil\n\t\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink))\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *GoroutineSuite) TestRunFail() {\n\tr := goroutine.NewRunner(suite.r, \"testfail\",\n\t\tfunc(context.Context, runtime.Runtime, io.Writer) error {\n\t\t\treturn errors.New(\"service failed\")\n\t\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().EqualError(r.Run(MockEventSink), \"service failed\")\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *GoroutineSuite) TestRunPanic() {\n\tr := goroutine.NewRunner(suite.r, \"testpanic\",\n\t\tfunc(context.Context, runtime.Runtime, io.Writer) error {\n\t\t\tpanic(\"service panic\")\n\t\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\terr := r.Run(MockEventSink)\n\tsuite.Assert().Error(err)\n\tsuite.Assert().Regexp(\"^panic in service: service panic.*\", err.Error())\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *GoroutineSuite) TestStop() {\n\tr := goroutine.NewRunner(suite.r, \"teststop\",\n\t\tfunc(ctx context.Context, data runtime.Runtime, logger io.Writer) error {\n\t\t\t<-ctx.Done()\n\n\t\t\treturn ctx.Err()\n\t\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.Run(MockEventSink)\n\t}()\n\n\ttime.Sleep(20 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"should not return yet\")\n\tdefault:\n\t}\n\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().NoError(<-errCh)\n}\n\nfunc (suite *GoroutineSuite) TestStuckOnStop() {\n\tr := goroutine.NewRunner(suite.r, \"teststop\",\n\t\tfunc(ctx context.Context, data runtime.Runtime, logger io.Writer) error {\n\t\t\t// hanging forever\n\t\t\tselect {}\n\t\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t)\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.Run(MockEventSink)\n\t}()\n\n\ttime.Sleep(20 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"should not return yet\")\n\tdefault:\n\t}\n\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().ErrorIs(<-errCh, goroutine.ErrAborted)\n}\n\nfunc (suite *GoroutineSuite) TestRunLogs() {\n\tr := goroutine.NewRunner(suite.r, \"logtest\",\n\t\tfunc(ctx context.Context, data runtime.Runtime, logger io.Writer) error {\n\t\t\t//nolint:errcheck\n\t\t\t_, _ = logger.Write([]byte(\"Test 1\\nTest 2\\n\"))\n\n\t\t\treturn nil\n\t\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink))\n\n\tlogFile, err := os.Open(filepath.Join(suite.tmpDir, \"logtest.log\"))\n\tsuite.Assert().NoError(err)\n\n\t//nolint:errcheck\n\tdefer logFile.Close()\n\n\tlogContents, err := io.ReadAll(logFile)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Equal([]byte(\"Test 1\\nTest 2\\n\"), logContents)\n}\n\nfunc TestGoroutineSuite(t *testing.T) {\n\tt.Setenv(\"PLATFORM\", \"metal\")\n\n\tsuite.Run(t, new(GoroutineSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/internal/lastlog/lastlog.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package lastlog provides utilities for capturing last log line(s) with a writer.\npackage lastlog\n\nimport (\n\t\"bytes\"\n\t\"sync\"\n)\n\n// limit is the maximum number of bytes to capture.\nconst limit = 512\n\n// Writer is a writer that captures the last log line(s).\ntype Writer struct {\n\tmu  sync.Mutex\n\tbuf []byte\n}\n\n// Writer implements io.Writer.\nfunc (w *Writer) Write(p []byte) (n int, err error) {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\tif w.buf == nil {\n\t\tw.buf = make([]byte, 0, limit)\n\t}\n\n\tif len(p) >= limit {\n\t\tcut := p\n\n\t\tfor len(cut) > limit {\n\t\t\tnlIndex := bytes.IndexByte(cut, '\\n')\n\t\t\tif nlIndex == -1 {\n\t\t\t\t// no newline found, append the last part of the cut\n\t\t\t\tif len(cut) > limit {\n\t\t\t\t\tcut = cut[len(cut)-limit:]\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcut = cut[nlIndex+1:]\n\t\t}\n\n\t\tw.buf = append(w.buf[:0], cut...)\n\n\t\treturn len(p), nil\n\t}\n\n\tbufPos := 0\n\n\tfor len(w.buf)-bufPos+len(p) > limit {\n\t\tnlIndex := bytes.IndexByte(w.buf[bufPos:], '\\n')\n\t\tif nlIndex == -1 {\n\t\t\t// no newline found, drop the whole buffer\n\t\t\tbufPos = len(w.buf)\n\t\t}\n\n\t\t// we are over the limit, drop the beginning of the buffer\n\t\tbufPos += nlIndex + 1\n\t}\n\n\tif bufPos > 0 {\n\t\t// drop the beginning of the buffer\n\t\tcopy(w.buf, w.buf[bufPos:])\n\t\tw.buf = w.buf[:len(w.buf)-bufPos]\n\t}\n\n\tw.buf = append(w.buf, p...)\n\n\treturn len(p), nil\n}\n\n// GetLastLog returns the last log line(s) captured by the writer.\nfunc (w *Writer) GetLastLog() string {\n\tw.mu.Lock()\n\tdefer w.mu.Unlock()\n\n\treturn string(bytes.TrimRight(w.buf, \"\\n\"))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/internal/lastlog/lastlog_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage lastlog_test\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/internal/lastlog\"\n)\n\n//go:embed testdata/kubelet.log\nvar lastLogData []byte\n\ntype readerWrap struct {\n\tio.Reader\n}\n\nfunc TestLastLog(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, step := range []int{1, 7, 13, 29, 37, 64, 128, 256, 512, 1024} {\n\t\tt.Run(fmt.Sprintf(\"step=%d\", step), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tw := &lastlog.Writer{}\n\n\t\t\tfor i := 0; i < len(lastLogData); i += step {\n\t\t\t\tn := min(step, len(lastLogData)-i)\n\n\t\t\t\tout, err := w.Write(lastLogData[i : i+n])\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, n, out)\n\t\t\t}\n\n\t\t\tassert.Equal(t, \"172.20.0.2: {\\\"ts\\\":1758106728112.3425,\\\"caller\\\":\\\"topologymanager/scope.go:117\\\",\\\"msg\\\":\\\"RemoveContainer\\\",\\\"v\\\":0,\\\"containerID\\\":\\\"d89f847ed0a3500dd712577fcb52dbbc5169bac1b7017d2c6a3f5f809693806c\\\"}\\n172.20.0.2: {\\\"ts\\\":1758106728119.877,\\\"caller\\\":\\\"topologymanager/scope.go:117\\\",\\\"msg\\\":\\\"RemoveContainer\\\",\\\"v\\\":0,\\\"containerID\\\":\\\"56aeb1c5d4785d1d5cc51984dd244fdd4fb672f91e82cfa21e02c92d0f7c3be3\\\"}\", w.GetLastLog()) //nolint:lll\n\t\t})\n\t}\n}\n\nfunc BenchmarkWrites(b *testing.B) {\n\tbuf := make([]byte, 128)\n\n\tvar r bytes.Reader\n\n\tb.ReportAllocs()\n\tb.ResetTimer()\n\n\tw := &lastlog.Writer{}\n\n\tfor b.Loop() {\n\t\tr.Reset(lastLogData)\n\t\tsrc := readerWrap{&r}\n\n\t\tn, err := io.CopyBuffer(w, src, buf)\n\t\trequire.NoError(b, err)\n\t\trequire.Equal(b, int64(len(lastLogData)), n)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/internal/lastlog/testdata/kubelet.log",
    "content": "172.20.0.2: {\"ts\":1758106668007.8376,\"caller\":\"app/server.go:529\",\"msg\":\"Kubelet version\",\"v\":0,\"kubeletVersion\":\"v1.34.1\"}\n172.20.0.2: {\"ts\":1758106668007.8638,\"caller\":\"app/server.go:531\",\"msg\":\"Golang settings\",\"v\":0,\"GOGC\":\"\",\"GOMAXPROCS\":\"\",\"GOTRACEBACK\":\"\"}\n172.20.0.2: {\"ts\":1758106668008.2092,\"caller\":\"watchdog/watchdog_linux.go:95\",\"msg\":\"Systemd watchdog is not enabled\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668008.2358,\"caller\":\"watchdog/watchdog_linux.go:137\",\"msg\":\"Systemd watchdog is not enabled or the interval is invalid, so health checking will not be started.\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668008.5452,\"caller\":\"app/server.go:956\",\"msg\":\"Client rotation is on, will bootstrap in background\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668009.3418,\"caller\":\"certificate/certificate_store.go:147\",\"msg\":\"Loading cert/key pair from a file\",\"v\":0,\"filePath\":\"/var/lib/kubelet/pki/kubelet-client-current.pem\"}\n172.20.0.2: {\"ts\":1758106668011.8005,\"caller\":\"dynamiccertificates/dynamic_cafile_content.go:161\",\"msg\":\"Starting controller\",\"v\":0,\"name\":\"client-ca-bundle::/etc/kubernetes/pki/ca.crt\"}\n172.20.0.2: {\"ts\":1758106668017.9783,\"caller\":\"app/server.go:1423\",\"msg\":\"Using cgroup driver setting received from the CRI runtime\",\"v\":0,\"cgroupDriver\":\"cgroupfs\"}\n172.20.0.2: {\"ts\":1758106668023.9102,\"caller\":\"app/server.go:842\",\"msg\":\"NoSwap is set due to memorySwapBehavior not specified\",\"v\":0,\"memorySwapBehavior\":\"\",\"FailSwapOn\":false}\n172.20.0.2: {\"ts\":1758106668025.0066,\"caller\":\"cm/container_manager_linux.go:270\",\"msg\":\"Container manager verified user specified cgroup-root exists\",\"v\":0,\"cgroupRoot\":[]}\n172.20.0.2: {\"ts\":1758106668025.0332,\"caller\":\"cm/container_manager_linux.go:275\",\"msg\":\"Creating Container Manager object based on Node Config\",\"v\":0,\"nodeConfig\":{\"NodeName\":\"talos-default-controlplane-1\",\"RuntimeCgroupsName\":\"\",\"SystemCgroupsName\":\"/system\",\"KubeletCgroupsName\":\"/podruntime/kubelet\",\"KubeletOOMScoreAdj\":-450,\"ContainerRuntime\":\"\",\"CgroupsPerQOS\":true,\"CgroupRoot\":\"/\",\"CgroupDriver\":\"cgroupfs\",\"KubeletRootDir\":\"/var/lib/kubelet\",\"ProtectKernelDefaults\":true,\"KubeReservedCgroupName\":\"\",\"SystemReservedCgroupName\":\"\",\"ReservedSystemCPUs\":{},\"EnforceNodeAllocatable\":{\"pods\":{}},\"KubeReserved\":null,\"SystemReserved\":{\"cpu\":\"50m\",\"ephemeral-storage\":\"256Mi\",\"memory\":\"512Mi\",\"pid\":\"100\"},\"HardEvictionThresholds\":[{\"Signal\":\"memory.available\",\"Operator\":\"LessThan\",\"Value\":{\"Quantity\":\"100Mi\",\"Percentage\":0},\"GracePeriod\":0,\"MinReclaim\":null},{\"Signal\":\"nodefs.available\",\"Operator\":\"LessThan\",\"Value\":{\"Quantity\":null,\"Percentage\":0.1},\"GracePeriod\":0,\"MinReclaim\":null},{\"Signal\":\"nodefs.inodesFree\",\"Operator\":\"LessThan\",\"Value\":{\"Quantity\":null,\"Percentage\":0.05},\"GracePeriod\":0,\"MinReclaim\":null},{\"Signal\":\"imagefs.available\",\"Operator\":\"LessThan\",\"Value\":{\"Quantity\":null,\"Percentage\":0.15},\"GracePeriod\":0,\"MinReclaim\":null},{\"Signal\":\"imagefs.inodesFree\",\"Operator\":\"LessThan\",\"Value\":{\"Quantity\":null,\"Percentage\":0.05},\"GracePeriod\":0,\"MinReclaim\":null}],\"QOSReserved\":{},\"CPUManagerPolicy\":\"none\",\"CPUManagerPolicyOptions\":null,\"TopologyManagerScope\":\"container\",\"CPUManagerReconcilePeriod\":10000000000,\"MemoryManagerPolicy\":\"None\",\"MemoryManagerReservedMemory\":null,\"PodPidsLimit\":-1,\"EnforceCPULimits\":true,\"CPUCFSQuotaPeriod\":100000000,\"TopologyManagerPolicy\":\"none\",\"TopologyManagerPolicyOptions\":null,\"CgroupVersion\":2}}\n172.20.0.2: {\"ts\":1758106668025.5054,\"caller\":\"topologymanager/topology_manager.go:138\",\"msg\":\"Creating topology manager with none policy\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668025.517,\"caller\":\"cm/container_manager_linux.go:306\",\"msg\":\"Creating device plugin manager\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668025.5674,\"caller\":\"cm/container_manager_linux.go:315\",\"msg\":\"Creating Dynamic Resource Allocation (DRA) manager\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668026.719,\"caller\":\"state/state_mem.go:36\",\"msg\":\"Initialized new in-memory state store\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668027.4104,\"caller\":\"kubelet/kubelet.go:475\",\"msg\":\"Attempting to sync node with API server\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668027.427,\"caller\":\"kubelet/kubelet.go:382\",\"msg\":\"Adding pod URL with HTTP header\",\"v\":0,\"URL\":\"http://127.0.0.1:34045\",\"header\":{}}\n172.20.0.2: {\"ts\":1758106668027.6672,\"caller\":\"kubelet/kubelet.go:387\",\"msg\":\"Adding apiserver pod source\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668027.6926,\"caller\":\"config/apiserver.go:42\",\"msg\":\"Waiting for node sync before watching apiserver pods\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668031.0547,\"caller\":\"kuberuntime/kuberuntime_manager.go:291\",\"msg\":\"Container runtime initialized\",\"v\":0,\"containerRuntime\":\"containerd\",\"version\":\"v2.1.4\",\"apiVersion\":\"v1\"}\n172.20.0.2: {\"ts\":1758106668031.528,\"caller\":\"kubelet/kubelet.go:940\",\"msg\":\"Not starting ClusterTrustBundle informer because we are in static kubelet mode or the ClusterTrustBundleProjection featuregate is disabled\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668031.6064,\"caller\":\"kubelet/kubelet.go:964\",\"msg\":\"Not starting PodCertificateRequest manager because we are in static kubelet mode or the PodCertificateProjection feature gate is disabled\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668033.0266,\"caller\":\"nodeshutdown/nodeshutdown_manager_linux.go:105\",\"msg\":\"Creating node shutdown manager\",\"v\":0,\"shutdownGracePeriodRequested\":\"30s\",\"shutdownGracePeriodCriticalPods\":\"10s\",\"shutdownGracePeriodByPodPriority\":[{\"Priority\":0,\"ShutdownGracePeriodSeconds\":20},{\"Priority\":2000000000,\"ShutdownGracePeriodSeconds\":10}]}\n172.20.0.2: {\"ts\":1758106668034.3818,\"caller\":\"app/server.go:1262\",\"msg\":\"Started kubelet\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668035.7124,\"caller\":\"stats/fs_resource_analyzer.go:67\",\"msg\":\"Starting FS ResourceAnalyzer\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668037.3792,\"caller\":\"record/event.go:368\",\"msg\":\"Unable to write event (may retry after sleeping)\",\"event\":\"&Event{ObjectMeta:{talos-default-controlplane-1.18660cb3216ebb50  default    0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] [] []},InvolvedObject:ObjectReference{Kind:Node,Namespace:,Name:talos-default-controlplane-1,UID:talos-default-controlplane-1,APIVersion:,ResourceVersion:,FieldPath:,},Reason:Starting,Message:Starting kubelet.,Source:EventSource{Component:kubelet,Host:talos-default-controlplane-1,},FirstTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,LastTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,Count:1,Type:Normal,EventTime:0001-01-01 00:00:00 +0000 UTC,Series:nil,Action:,Related:nil,ReportingController:kubelet,ReportingInstance:talos-default-controlplane-1,}\",\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/namespaces/default/events\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106668042.905,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"6808d56050203041f12f406d3f0c9baa812282a5a9e2f5f8d7b3ddbd8fd04c5c\"}\n172.20.0.2: {\"ts\":1758106668042.9885,\"caller\":\"server/server.go:180\",\"msg\":\"Starting to listen\",\"v\":0,\"address\":\"0.0.0.0\",\"port\":10250}\n172.20.0.2: {\"ts\":1758106668043.6199,\"caller\":\"server/server.go:310\",\"msg\":\"Adding debug handlers to kubelet server\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668047.2854,\"caller\":\"grpc/ratelimit.go:56\",\"msg\":\"Setting rate limiting for endpoint\",\"v\":0,\"service\":\"podresources\",\"qps\":100,\"burstTokens\":10}\n172.20.0.2: {\"ts\":1758106668047.3354,\"caller\":\"podresources/server_v1.go:49\",\"msg\":\"podresources\",\"v\":0,\"method\":\"list\",\"useActivePods\":true}\n172.20.0.2: {\"ts\":1758106668047.4949,\"caller\":\"server/server.go:249\",\"msg\":\"Starting to serve the podresources API\",\"v\":0,\"endpoint\":\"unix:/var/lib/kubelet/pod-resources/kubelet.sock\"}\n172.20.0.2: {\"ts\":1758106668048.1006,\"caller\":\"dynamiccertificates/dynamic_serving_content.go:135\",\"msg\":\"Starting controller\",\"v\":0,\"name\":\"kubelet-server-cert-files::/var/lib/kubelet/pki/kubelet.crt::/var/lib/kubelet/pki/kubelet.key\"}\n172.20.0.2: {\"ts\":1758106668051.4663,\"caller\":\"volumemanager/volume_manager.go:313\",\"msg\":\"Starting Kubelet Volume Manager\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668051.6091,\"caller\":\"kubelet/kubelet_node_status.go:404\",\"msg\":\"Error getting the current node from lister\",\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106668051.839,\"caller\":\"populator/desired_state_of_world_populator.go:146\",\"msg\":\"Desired state populator starts to run\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668052.162,\"caller\":\"reconciler/reconciler.go:29\",\"msg\":\"Reconciler: start to sync state\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668055.2058,\"caller\":\"container/factory.go:223\",\"msg\":\"Registration of the containerd container factory successfully\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668055.2915,\"caller\":\"container/factory.go:223\",\"msg\":\"Registration of the systemd container factory successfully\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668055.45,\"caller\":\"container/factory.go:221\",\"msg\":\"Registration of the crio container factory failed: Get \\\"http://%2Fvar%2Frun%2Fcrio%2Fcrio.sock/info\\\": dial unix /var/run/crio/crio.sock: connect: no such file or directory\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668058.806,\"caller\":\"kubelet/kubelet.go:1615\",\"msg\":\"Image garbage collection failed once. Stats initialization may not have completed yet\",\"err\":\"invalid capacity 0 on image filesystem\"}\n172.20.0.2: {\"ts\":1758106668063.6414,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"6874b1c5fe7136331a47236461534fa835053e0b750101a80ee2ea29f3980d39\"}\n172.20.0.2: {\"ts\":1758106668076.3552,\"caller\":\"cpumanager/cpu_manager.go:221\",\"msg\":\"Starting CPU manager\",\"v\":0,\"policy\":\"none\"}\n172.20.0.2: {\"ts\":1758106668076.446,\"caller\":\"cpumanager/cpu_manager.go:222\",\"msg\":\"Reconciling\",\"v\":0,\"reconcilePeriod\":\"10s\"}\n172.20.0.2: {\"ts\":1758106668076.5164,\"caller\":\"state/state_mem.go:36\",\"msg\":\"Initialized new in-memory state store\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668076.7607,\"caller\":\"state/state_mem.go:88\",\"msg\":\"Updated default CPUSet\",\"v\":0,\"cpuSet\":\"\"}\n172.20.0.2: {\"ts\":1758106668076.8374,\"caller\":\"state/state_mem.go:96\",\"msg\":\"Updated CPUSet assignments\",\"v\":0,\"assignments\":{}}\n172.20.0.2: {\"ts\":1758106668076.8877,\"caller\":\"cpumanager/policy_none.go:49\",\"msg\":\"None policy: Start\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668077.186,\"caller\":\"memorymanager/memory_manager.go:187\",\"msg\":\"Starting memorymanager\",\"v\":0,\"policy\":\"None\"}\n172.20.0.2: {\"ts\":1758106668077.2717,\"logger\":\"Memory Manager state checkpoint\",\"caller\":\"state/state_mem.go:36\",\"msg\":\"Initializing new in-memory state store\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668077.8845,\"logger\":\"Memory Manager state checkpoint\",\"caller\":\"state/state_mem.go:77\",\"msg\":\"Updated machine memory state\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668077.9558,\"caller\":\"memorymanager/policy_none.go:47\",\"msg\":\"Start\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668083.122,\"caller\":\"devicemanager/manager.go:513\",\"msg\":\"Failed to read data from checkpoint\",\"checkpoint\":\"kubelet_internal_checkpoint\",\"err\":\"checkpoint is not found\"}\n172.20.0.2: {\"ts\":1758106668085.8274,\"caller\":\"eviction/eviction_manager.go:189\",\"msg\":\"Eviction manager: starting control loop\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668085.876,\"caller\":\"logs/container_log_manager.go:146\",\"msg\":\"Initializing container log rotate workers\",\"v\":0,\"workers\":1,\"monitorPeriod\":\"10s\"}\n172.20.0.2: {\"ts\":1758106668086.1648,\"caller\":\"pluginmanager/plugin_manager.go:118\",\"msg\":\"Starting Kubelet Plugin Manager\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668089.1938,\"caller\":\"eviction/eviction_manager.go:267\",\"msg\":\"eviction manager: failed to check if we have separate container filesystem. Ignoring.\",\"err\":\"no imagefs label for configured runtime\"}\n172.20.0.2: {\"ts\":1758106668089.3218,\"caller\":\"eviction/eviction_manager.go:292\",\"msg\":\"Eviction manager: failed to get summary stats\",\"err\":\"failed to get node info: node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106668093.0972,\"caller\":\"kubelet/kubelet_network_linux.go:54\",\"msg\":\"Initialized iptables rules.\",\"v\":0,\"protocol\":\"IPv4\"}\n172.20.0.2: {\"ts\":1758106668094.1462,\"caller\":\"kubelet/kubelet_network_linux.go:54\",\"msg\":\"Initialized iptables rules.\",\"v\":0,\"protocol\":\"IPv6\"}\n172.20.0.2: {\"ts\":1758106668094.1702,\"caller\":\"status/status_manager.go:244\",\"msg\":\"Starting to sync pod status with apiserver\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668094.3052,\"caller\":\"kubelet/kubelet.go:2427\",\"msg\":\"Starting kubelet main sync loop\",\"v\":0}\n172.20.0.2: {\"ts\":1758106668094.4678,\"caller\":\"kubelet/kubelet.go:2451\",\"msg\":\"Skipping pod synchronization\",\"err\":\"PLEG is not healthy: pleg has yet to be successful\",\"errCauses\":[{\"error\":\"PLEG is not healthy: pleg has yet to be successful\"}]}\n172.20.0.2: {\"ts\":1758106668191.7249,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106668192.5737,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106668194.6191,\"caller\":\"kubelet/pod_container_deletor.go:80\",\"msg\":\"Container not found in pod's containers\",\"v\":0,\"containerID\":\"5f3eade1f306db00c4b8671d76bb0548472d98a974b2b3a635ff2ee83c91c3f3\"}\n172.20.0.2: {\"ts\":1758106668194.635,\"caller\":\"kubelet/pod_container_deletor.go:80\",\"msg\":\"Container not found in pod's containers\",\"v\":0,\"containerID\":\"6f6aaa0f4a9268afb3b97bc7dc492508435cfac4c5d36c0025ae17564a502a4d\"}\n172.20.0.2: {\"ts\":1758106668194.6438,\"caller\":\"kubelet/pod_container_deletor.go:80\",\"msg\":\"Container not found in pod's containers\",\"v\":0,\"containerID\":\"e6125235fae9c2154cca503ade1e11dee01ef40d31c916ae3bfc77b519658e8d\"}\n172.20.0.2: {\"ts\":1758106668194.6877,\"caller\":\"kubelet/pod_container_deletor.go:80\",\"msg\":\"Container not found in pod's containers\",\"v\":0,\"containerID\":\"af6833318327a76e36f22d0e1dc6de31e3c1a3b68facb070839eadd0952e2cd4\"}\n172.20.0.2: {\"ts\":1758106668194.697,\"caller\":\"kubelet/pod_container_deletor.go:80\",\"msg\":\"Container not found in pod's containers\",\"v\":0,\"containerID\":\"2988531464a3c775dafc369acbee0e3c4b244a02736ee211689b62fcf8f3aecf\"}\n172.20.0.2: {\"ts\":1758106668393.494,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106668394.5703,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106668796.2822,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106668797.1108,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106669598.726,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106669599.78,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106671200.8167,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106671201.587,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106674402.306,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106674403.182,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106675621.227,\"caller\":\"record/event.go:368\",\"msg\":\"Unable to write event (may retry after sleeping)\",\"event\":\"&Event{ObjectMeta:{talos-default-controlplane-1.18660cb3216ebb50  default    0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] [] []},InvolvedObject:ObjectReference{Kind:Node,Namespace:,Name:talos-default-controlplane-1,UID:talos-default-controlplane-1,APIVersion:,ResourceVersion:,FieldPath:,},Reason:Starting,Message:Starting kubelet.,Source:EventSource{Component:kubelet,Host:talos-default-controlplane-1,},FirstTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,LastTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,Count:1,Type:Normal,EventTime:0001-01-01 00:00:00 +0000 UTC,Series:nil,Action:,Related:nil,ReportingController:kubelet,ReportingInstance:talos-default-controlplane-1,}\",\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/namespaces/default/events\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678042.8213,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.Service\",\"err\":\"failed to list *v1.Service: Get \\\"https://127.0.0.1:7445/api/v1/services?fieldSelector=spec.clusterIP%21%3DNone&limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678042.8445,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.Node\",\"err\":\"failed to list *v1.Node: Get \\\"https://127.0.0.1:7445/api/v1/nodes?fieldSelector=metadata.name%3Dtalos-default-controlplane-1&limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678052.8208,\"caller\":\"lease/controller.go:145\",\"msg\":\"Failed to ensure lease exists, will retry\",\"interval\":\"200ms\",\"err\":\"Get \\\"https://127.0.0.1:7445/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/talos-default-controlplane-1?timeout=10s\\\": context deadline exceeded - error from a previous attempt: EOF\"}\n172.20.0.2: {\"ts\":1758106678067.7424,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.CSIDriver\",\"err\":\"failed to list *v1.CSIDriver: Get \\\"https://127.0.0.1:7445/apis/storage.k8s.io/v1/csidrivers?limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678067.744,\"caller\":\"reconciler/reconstruct.go:189\",\"msg\":\"Failed to get Node status to reconstruct device paths\",\"err\":\"Get \\\"https://127.0.0.1:7445/api/v1/nodes/talos-default-controlplane-1\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678089.3804,\"caller\":\"eviction/eviction_manager.go:292\",\"msg\":\"Eviction manager: failed to get summary stats\",\"err\":\"failed to get node info: node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106678109.1099,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.RuntimeClass\",\"err\":\"failed to list *v1.RuntimeClass: Get \\\"https://127.0.0.1:7445/apis/node.k8s.io/v1/runtimeclasses?limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678503.5498,\"caller\":\"webhook/webhook.go:269\",\"msg\":\"Failed to make webhook authorizer request: Post \\\"https://127.0.0.1:7445/apis/authorization.k8s.io/v1/subjectaccessreviews\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106678503.5718,\"caller\":\"server/server.go:347\",\"msg\":\"Authorization error\",\"user\":\"apiserver-kubelet-client\",\"verb\":\"get\",\"resource\":\"nodes\",\"subresource\":\"pods\",\"err\":\"Post \\\"https://127.0.0.1:7445/apis/authorization.k8s.io/v1/subjectaccessreviews\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106680804.753,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106680805.5906,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106685622.703,\"caller\":\"record/event.go:368\",\"msg\":\"Unable to write event (may retry after sleeping)\",\"event\":\"&Event{ObjectMeta:{talos-default-controlplane-1.18660cb3216ebb50  default    0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] [] []},InvolvedObject:ObjectReference{Kind:Node,Namespace:,Name:talos-default-controlplane-1,UID:talos-default-controlplane-1,APIVersion:,ResourceVersion:,FieldPath:,},Reason:Starting,Message:Starting kubelet.,Source:EventSource{Component:kubelet,Host:talos-default-controlplane-1,},FirstTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,LastTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,Count:1,Type:Normal,EventTime:0001-01-01 00:00:00 +0000 UTC,Series:nil,Action:,Related:nil,ReportingController:kubelet,ReportingInstance:talos-default-controlplane-1,}\",\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/namespaces/default/events\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106687806.421,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106687807.2507,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106688040.816,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106688046.192,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106688048.2466,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106688089.7534,\"caller\":\"eviction/eviction_manager.go:292\",\"msg\":\"Eviction manager: failed to get summary stats\",\"err\":\"failed to get node info: node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106688183.5593,\"caller\":\"reconciler/reconstruct.go:189\",\"msg\":\"Failed to get Node status to reconstruct device paths\",\"err\":\"Get \\\"https://127.0.0.1:7445/api/v1/nodes/talos-default-controlplane-1\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106688253.933,\"caller\":\"lease/controller.go:145\",\"msg\":\"Failed to ensure lease exists, will retry\",\"interval\":\"400ms\",\"err\":\"Get \\\"https://127.0.0.1:7445/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/talos-default-controlplane-1?timeout=10s\\\": context deadline exceeded - error from a previous attempt: EOF\"}\n172.20.0.2: {\"ts\":1758106688284.332,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"secrets\\\" (UniqueName: \\\"kubernetes.io/host-path/cf26aa92a3daac8c6fe4af9557491017-secrets\\\") pod \\\"kube-scheduler-talos-default-controlplane-1\\\" (UID: \\\"cf26aa92a3daac8c6fe4af9557491017\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106688284.3755,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"config\\\" (UniqueName: \\\"kubernetes.io/host-path/cf26aa92a3daac8c6fe4af9557491017-config\\\") pod \\\"kube-scheduler-talos-default-controlplane-1\\\" (UID: \\\"cf26aa92a3daac8c6fe4af9557491017\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106688284.3943,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"secrets\\\" (UniqueName: \\\"kubernetes.io/host-path/981612585a0b5246fd0e4918415cf15a-secrets\\\") pod \\\"kube-apiserver-talos-default-controlplane-1\\\" (UID: \\\"981612585a0b5246fd0e4918415cf15a\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106688284.4104,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"config\\\" (UniqueName: \\\"kubernetes.io/host-path/981612585a0b5246fd0e4918415cf15a-config\\\") pod \\\"kube-apiserver-talos-default-controlplane-1\\\" (UID: \\\"981612585a0b5246fd0e4918415cf15a\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106688284.4329,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"audit\\\" (UniqueName: \\\"kubernetes.io/host-path/981612585a0b5246fd0e4918415cf15a-audit\\\") pod \\\"kube-apiserver-talos-default-controlplane-1\\\" (UID: \\\"981612585a0b5246fd0e4918415cf15a\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106688284.4543,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"secrets\\\" (UniqueName: \\\"kubernetes.io/host-path/cdadad5a0038b90e98f6a53c15c67a5d-secrets\\\") pod \\\"kube-controller-manager-talos-default-controlplane-1\\\" (UID: \\\"cdadad5a0038b90e98f6a53c15c67a5d\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106689355.9502,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.Service\",\"err\":\"failed to list *v1.Service: Get \\\"https://127.0.0.1:7445/api/v1/services?fieldSelector=spec.clusterIP%21%3DNone&limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106689368.3943,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.RuntimeClass\",\"err\":\"failed to list *v1.RuntimeClass: Get \\\"https://127.0.0.1:7445/apis/node.k8s.io/v1/runtimeclasses?limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106689436.3508,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.Node\",\"err\":\"failed to list *v1.Node: Get \\\"https://127.0.0.1:7445/api/v1/nodes?fieldSelector=metadata.name%3Dtalos-default-controlplane-1&limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106689593.513,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.CSIDriver\",\"err\":\"failed to list *v1.CSIDriver: Get \\\"https://127.0.0.1:7445/apis/storage.k8s.io/v1/csidrivers?limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106693994.0713,\"caller\":\"webhook/webhook.go:269\",\"msg\":\"Failed to make webhook authorizer request: Post \\\"https://127.0.0.1:7445/apis/authorization.k8s.io/v1/subjectaccessreviews\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106693994.0884,\"caller\":\"server/server.go:347\",\"msg\":\"Authorization error\",\"user\":\"apiserver-kubelet-client\",\"verb\":\"get\",\"resource\":\"nodes\",\"subresource\":\"pods\",\"err\":\"Post \\\"https://127.0.0.1:7445/apis/authorization.k8s.io/v1/subjectaccessreviews\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106694808.4841,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106694809.2092,\"caller\":\"kubelet/kubelet_node_status.go:107\",\"msg\":\"Unable to register node with API server\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/nodes\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106695624.5645,\"caller\":\"record/event.go:368\",\"msg\":\"Unable to write event (may retry after sleeping)\",\"event\":\"&Event{ObjectMeta:{talos-default-controlplane-1.18660cb3216ebb50  default    0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] [] []},InvolvedObject:ObjectReference{Kind:Node,Namespace:,Name:talos-default-controlplane-1,UID:talos-default-controlplane-1,APIVersion:,ResourceVersion:,FieldPath:,},Reason:Starting,Message:Starting kubelet.,Source:EventSource{Component:kubelet,Host:talos-default-controlplane-1,},FirstTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,LastTimestamp:2025-09-17 10:57:48.034341712 +0000 UTC m=+0.515208206,Count:1,Type:Normal,EventTime:0001-01-01 00:00:00 +0000 UTC,Series:nil,Action:,Related:nil,ReportingController:kubelet,ReportingInstance:talos-default-controlplane-1,}\",\"err\":\"Post \\\"https://127.0.0.1:7445/api/v1/namespaces/default/events\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106698090.628,\"caller\":\"eviction/eviction_manager.go:292\",\"msg\":\"Eviction manager: failed to get summary stats\",\"err\":\"failed to get node info: node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106698298.185,\"caller\":\"reconciler/reconstruct.go:189\",\"msg\":\"Failed to get Node status to reconstruct device paths\",\"err\":\"Get \\\"https://127.0.0.1:7445/api/v1/nodes/talos-default-controlplane-1\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106698654.832,\"caller\":\"lease/controller.go:145\",\"msg\":\"Failed to ensure lease exists, will retry\",\"interval\":\"800ms\",\"err\":\"Get \\\"https://127.0.0.1:7445/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/talos-default-controlplane-1?timeout=10s\\\": context deadline exceeded - error from a previous attempt: EOF\"}\n172.20.0.2: {\"ts\":1758106699156.1372,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106699158.0012,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106699159.5417,\"caller\":\"kubelet/kubelet.go:3215\",\"msg\":\"No need to create a mirror pod, since failed to get node info from the cluster\",\"node\":{\"name\":\"talos-default-controlplane-1\"},\"err\":\"node \\\"talos-default-controlplane-1\\\" not found\"}\n172.20.0.2: {\"ts\":1758106701067.7002,\"logger\":\"UnhandledError\",\"caller\":\"cache/reflector.go:205\",\"msg\":\"Failed to watch\",\"reflector\":\"k8s.io/client-go/informers/factory.go:160\",\"type\":\"*v1.Service\",\"err\":\"failed to list *v1.Service: Get \\\"https://127.0.0.1:7445/api/v1/services?fieldSelector=spec.clusterIP%21%3DNone&limit=500&resourceVersion=0\\\": EOF\"}\n172.20.0.2: {\"ts\":1758106701552.0469,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106701560.222,\"caller\":\"kubelet/kubelet.go:3221\",\"msg\":\"Failed creating a mirror pod\",\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"err\":\"pods \\\"kube-scheduler-talos-default-controlplane-1\\\" already exists\"}\n172.20.0.2: {\"ts\":1758106701560.2449,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106701567.1072,\"caller\":\"kubelet/kubelet.go:3221\",\"msg\":\"Failed creating a mirror pod\",\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"err\":\"pods \\\"kube-apiserver-talos-default-controlplane-1\\\" already exists\"}\n172.20.0.2: {\"ts\":1758106701567.1692,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106701573.502,\"caller\":\"kubelet/kubelet.go:3221\",\"msg\":\"Failed creating a mirror pod\",\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"err\":\"pods \\\"kube-controller-manager-talos-default-controlplane-1\\\" already exists\"}\n172.20.0.2: {\"ts\":1758106701810.7104,\"caller\":\"kubelet/kubelet_node_status.go:75\",\"msg\":\"Attempting to register node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106701818.06,\"caller\":\"kubelet/kubelet_node_status.go:124\",\"msg\":\"Node was previously registered\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106701818.2197,\"caller\":\"kubelet/kubelet_node_status.go:78\",\"msg\":\"Successfully registered node\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"}}\n172.20.0.2: {\"ts\":1758106701818.2822,\"caller\":\"kuberuntime/kuberuntime_manager.go:1828\",\"msg\":\"Updating runtime config through cri with podcidr\",\"v\":0,\"CIDR\":\"10.244.0.0/24\"}\n172.20.0.2: {\"ts\":1758106701818.729,\"caller\":\"kubelet/kubelet_network.go:47\",\"msg\":\"Updating Pod CIDR\",\"v\":0,\"originalPodCIDR\":\"\",\"newPodCIDR\":\"10.244.0.0/24\"}\n172.20.0.2: {\"ts\":1758106701819.1897,\"caller\":\"nodestatus/setters.go:543\",\"msg\":\"Node became not ready\",\"v\":0,\"node\":{\"name\":\"talos-default-controlplane-1\"},\"condition\":{\"type\":\"Ready\",\"status\":\"False\",\"lastHeartbeatTime\":\"2025-09-17T10:58:21Z\",\"lastTransitionTime\":\"2025-09-17T10:58:21Z\",\"reason\":\"KubeletNotReady\",\"message\":\"CSINode is not yet initialized\"}}\n172.20.0.2: {\"ts\":1758106702045.5874,\"caller\":\"config/apiserver.go:52\",\"msg\":\"Watching apiserver\",\"v\":0}\n172.20.0.2: {\"ts\":1758106702052.1104,\"caller\":\"kubelet/kubelet.go:3202\",\"msg\":\"Trying to delete pod\",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podUID\":\"ff721e54-8d9f-4456-8f05-b43954afb707\"}\n172.20.0.2: {\"ts\":1758106702052.2893,\"caller\":\"populator/desired_state_of_world_populator.go:154\",\"msg\":\"Finished populating initial desired state of world\",\"v\":0}\n172.20.0.2: {\"ts\":1758106702053.334,\"caller\":\"kubelet/kubelet.go:3202\",\"msg\":\"Trying to delete pod\",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podUID\":\"5cf1af57-2c52-4664-a870-335bb359bac1\"}\n172.20.0.2: {\"ts\":1758106702053.4333,\"caller\":\"kubelet/kubelet.go:3202\",\"msg\":\"Trying to delete pod\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podUID\":\"0079b8ef-61bc-436e-ae79-0a386af0b448\"}\n172.20.0.2: {\"ts\":1758106702100.5447,\"caller\":\"kubelet/kubelet_volumes.go:163\",\"msg\":\"Cleaned up orphaned pod volumes dir\",\"v\":0,\"podUID\":\"52bfc7fae30f5922b2215aa79f5b3751\",\"path\":\"/var/lib/kubelet/pods/52bfc7fae30f5922b2215aa79f5b3751/volumes\"}\n172.20.0.2: {\"ts\":1758106702100.7961,\"caller\":\"kubelet/kubelet_volumes.go:163\",\"msg\":\"Cleaned up orphaned pod volumes dir\",\"v\":0,\"podUID\":\"56cf311ad81b6b54947482a9ebbce301\",\"path\":\"/var/lib/kubelet/pods/56cf311ad81b6b54947482a9ebbce301/volumes\"}\n172.20.0.2: {\"ts\":1758106702101.0337,\"caller\":\"kubelet/kubelet_volumes.go:163\",\"msg\":\"Cleaned up orphaned pod volumes dir\",\"v\":0,\"podUID\":\"797f25ac28f9618d52a80b171838d145\",\"path\":\"/var/lib/kubelet/pods/797f25ac28f9618d52a80b171838d145/volumes\"}\n172.20.0.2: {\"ts\":1758106702104.23,\"caller\":\"kubelet/kubelet.go:3208\",\"msg\":\"Deleted mirror pod as it didn't match the static Pod\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702104.2478,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702104.6187,\"caller\":\"kubelet/kubelet.go:3208\",\"msg\":\"Deleted mirror pod as it didn't match the static Pod\",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702104.6335,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702112.9602,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"run\\\" (UniqueName: \\\"kubernetes.io/host-path/5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb-run\\\") pod \\\"kube-flannel-bhgc2\\\" (UID: \\\"5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-flannel-bhgc2\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702113.0017,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"cni\\\" (UniqueName: \\\"kubernetes.io/host-path/5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb-cni\\\") pod \\\"kube-flannel-bhgc2\\\" (UID: \\\"5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-flannel-bhgc2\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702113.0527,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"lib-modules\\\" (UniqueName: \\\"kubernetes.io/host-path/e06f16fc-4f9b-47d5-89cb-f0d6f2891f60-lib-modules\\\") pod \\\"kube-proxy-pvlfh\\\" (UID: \\\"e06f16fc-4f9b-47d5-89cb-f0d6f2891f60\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-proxy-pvlfh\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702113.0637,\"caller\":\"reconciler/reconciler_common.go:251\",\"msg\":\"operationExecutor.VerifyControllerAttachedVolume started for volume \\\"ssl-certs-host\\\" (UniqueName: \\\"kubernetes.io/host-path/e06f16fc-4f9b-47d5-89cb-f0d6f2891f60-ssl-certs-host\\\") pod \\\"kube-proxy-pvlfh\\\" (UID: \\\"e06f16fc-4f9b-47d5-89cb-f0d6f2891f60\\\") \",\"v\":0,\"pod\":{\"name\":\"kube-proxy-pvlfh\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702117.5718,\"caller\":\"kubelet/kubelet.go:3208\",\"msg\":\"Deleted mirror pod as it didn't match the static Pod\",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702117.6743,\"caller\":\"kubelet/kubelet.go:3219\",\"msg\":\"Creating a mirror pod for static pod\",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"}}\n172.20.0.2: {\"ts\":1758106702127.056,\"caller\":\"status/status_manager.go:1018\",\"msg\":\"Failed to get status for pod\",\"podUID\":\"cdadad5a0038b90e98f6a53c15c67a5d\",\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"err\":\"pods \\\"kube-controller-manager-talos-default-controlplane-1\\\" is forbidden: User \\\"system:node:talos-default-controlplane-1\\\" cannot get resource \\\"pods\\\" in API group \\\"\\\" in the namespace \\\"kube-system\\\": no relationship found between node 'talos-default-controlplane-1' and this object\"}\n172.20.0.2: {\"ts\":1758106702136.1614,\"caller\":\"kubelet/kubelet_node_status.go:439\",\"msg\":\"Fast updating node status as it just became ready\",\"v\":0}\n172.20.0.2: {\"ts\":1758106702168.9478,\"caller\":\"kubelet/kubelet.go:3202\",\"msg\":\"Trying to delete pod\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podUID\":\"0079b8ef-61bc-436e-ae79-0a386af0b448\"}\n172.20.0.2: {\"ts\":1758106702201.8083,\"caller\":\"util/pod_startup_latency_tracker.go:104\",\"msg\":\"Observed pod startup duration\",\"v\":0,\"pod\":{\"name\":\"kube-scheduler-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podStartSLOduration\":0.201783166,\"podStartE2EDuration\":\"201.783166ms\",\"podCreationTimestamp\":1758106702201.819,\"firstStartedPulling\":1758106702201.8193,\"lastFinishedPulling\":1758106702201.8196,\"observedRunningTime\":1758106702201.8198,\"watchObservedRunningTime\":1758106702201.82}\n172.20.0.2: {\"ts\":1758106702241.6372,\"caller\":\"util/pod_startup_latency_tracker.go:104\",\"msg\":\"Observed pod startup duration\",\"v\":0,\"pod\":{\"name\":\"kube-apiserver-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podStartSLOduration\":0.241612236,\"podStartE2EDuration\":\"241.612236ms\",\"podCreationTimestamp\":1758106702241.6472,\"firstStartedPulling\":1758106702241.6477,\"lastFinishedPulling\":1758106702241.6477,\"observedRunningTime\":1758106702241.648,\"watchObservedRunningTime\":1758106702241.6482}\n172.20.0.2: {\"ts\":1758106702241.9497,\"caller\":\"util/pod_startup_latency_tracker.go:104\",\"msg\":\"Observed pod startup duration\",\"v\":0,\"pod\":{\"name\":\"kube-controller-manager-talos-default-controlplane-1\",\"namespace\":\"kube-system\"},\"podStartSLOduration\":0.241937002,\"podStartE2EDuration\":\"241.937002ms\",\"podCreationTimestamp\":1758106702241.9705,\"firstStartedPulling\":1758106702241.9707,\"lastFinishedPulling\":1758106702241.9707,\"observedRunningTime\":1758106702241.971,\"watchObservedRunningTime\":1758106702241.9712}\n172.20.0.2: {\"ts\":1758106702355.4495,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"3fc7b56fc3907f2a62b1b38f10ac6d2865146017c70a3af57455874d4712969f\"}\n172.20.0.2: {\"ts\":1758106702431.3733,\"logger\":\"UnhandledError\",\"caller\":\"kuberuntime/kuberuntime_manager.go:1449\",\"msg\":\"Unhandled Error\",\"err\":\"container kube-proxy start failed in pod kube-proxy-pvlfh_kube-system(e06f16fc-4f9b-47d5-89cb-f0d6f2891f60): CreateContainerConfigError: services have not yet been read at least once, cannot construct envvars\"}\n172.20.0.2: {\"ts\":1758106702431.404,\"caller\":\"kubelet/pod_workers.go:1324\",\"msg\":\"Error syncing pod, skipping\",\"pod\":{\"name\":\"kube-proxy-pvlfh\",\"namespace\":\"kube-system\"},\"podUID\":\"e06f16fc-4f9b-47d5-89cb-f0d6f2891f60\",\"err\":\"failed to \\\"StartContainer\\\" for \\\"kube-proxy\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\",\"errCauses\":[{\"error\":\"failed to \\\"StartContainer\\\" for \\\"kube-proxy\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\"}]}\n172.20.0.2: {\"ts\":1758106702471.5806,\"logger\":\"UnhandledError\",\"caller\":\"kuberuntime/kuberuntime_manager.go:1449\",\"msg\":\"Unhandled Error\",\"err\":\"init container install-config start failed in pod kube-flannel-bhgc2_kube-system(5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb): CreateContainerConfigError: services have not yet been read at least once, cannot construct envvars\"}\n172.20.0.2: {\"ts\":1758106702471.6323,\"caller\":\"kubelet/pod_workers.go:1324\",\"msg\":\"Error syncing pod, skipping\",\"pod\":{\"name\":\"kube-flannel-bhgc2\",\"namespace\":\"kube-system\"},\"podUID\":\"5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb\",\"err\":\"failed to \\\"StartContainer\\\" for \\\"install-config\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\",\"errCauses\":[{\"error\":\"failed to \\\"StartContainer\\\" for \\\"install-config\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\"}]}\n172.20.0.2: {\"ts\":1758106703171.0913,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"7ab9f8e1e9db423676249bcbf5c6321989fe0025db751f991ee4a37e3349b118\"}\n172.20.0.2: {\"ts\":1758106703171.7766,\"logger\":\"UnhandledError\",\"caller\":\"kuberuntime/kuberuntime_manager.go:1449\",\"msg\":\"Unhandled Error\",\"err\":\"container kube-proxy start failed in pod kube-proxy-pvlfh_kube-system(e06f16fc-4f9b-47d5-89cb-f0d6f2891f60): CreateContainerConfigError: services have not yet been read at least once, cannot construct envvars\"}\n172.20.0.2: {\"ts\":1758106703171.8262,\"caller\":\"kubelet/pod_workers.go:1324\",\"msg\":\"Error syncing pod, skipping\",\"pod\":{\"name\":\"kube-proxy-pvlfh\",\"namespace\":\"kube-system\"},\"podUID\":\"e06f16fc-4f9b-47d5-89cb-f0d6f2891f60\",\"err\":\"failed to \\\"StartContainer\\\" for \\\"kube-proxy\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\",\"errCauses\":[{\"error\":\"failed to \\\"StartContainer\\\" for \\\"kube-proxy\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\"}]}\n172.20.0.2: {\"ts\":1758106703175.387,\"logger\":\"UnhandledError\",\"caller\":\"kuberuntime/kuberuntime_manager.go:1449\",\"msg\":\"Unhandled Error\",\"err\":\"init container install-config start failed in pod kube-flannel-bhgc2_kube-system(5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb): CreateContainerConfigError: services have not yet been read at least once, cannot construct envvars\"}\n172.20.0.2: {\"ts\":1758106703175.4192,\"caller\":\"kubelet/pod_workers.go:1324\",\"msg\":\"Error syncing pod, skipping\",\"pod\":{\"name\":\"kube-flannel-bhgc2\",\"namespace\":\"kube-system\"},\"podUID\":\"5a5b2b3a-c43e-477f-a3dc-de8bdab94eeb\",\"err\":\"failed to \\\"StartContainer\\\" for \\\"install-config\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\",\"errCauses\":[{\"error\":\"failed to \\\"StartContainer\\\" for \\\"install-config\\\" with CreateContainerConfigError: \\\"services have not yet been read at least once, cannot construct envvars\\\"\"}]}\n172.20.0.2: {\"ts\":1758106715095.6794,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"7ab9f8e1e9db423676249bcbf5c6321989fe0025db751f991ee4a37e3349b118\"}\n172.20.0.2: {\"ts\":1758106719206.4553,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"aef247c9c003f94ef52aff29ac354d0bb7652c97603f518a0b9de716415f1858\"}\n172.20.0.2: {\"ts\":1758106728097.1938,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"4e1d8b1e0e84f8a5a025422b1ca3c4596c7323009b31f6c5c47977bfab9daac8\"}\n172.20.0.2: {\"ts\":1758106728112.3425,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"d89f847ed0a3500dd712577fcb52dbbc5169bac1b7017d2c6a3f5f809693806c\"}\n172.20.0.2: {\"ts\":1758106728119.877,\"caller\":\"topologymanager/scope.go:117\",\"msg\":\"RemoveContainer\",\"v\":0,\"containerID\":\"56aeb1c5d4785d1d5cc51984dd244fdd4fb672f91e82cfa21e02c92d0f7c3be3\"}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/process/process.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage process\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"os\"\n\t\"path\"\n\t\"slices\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\t\"github.com/containerd/containerd/v2/pkg/sys\"\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd/proc/reaper\"\n\t\"kernel.org/pub/linux/libs/security/libcap/cap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/internal/lastlog\"\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// processRunner is a runner.Runner that runs a process on the host.\ntype processRunner struct {\n\targs  *runner.Args\n\topts  *runner.Options\n\tdebug bool\n\n\tstop    chan struct{}\n\tstopped chan struct{}\n}\n\n// NewRunner creates runner.Runner that runs a process on the host.\nfunc NewRunner(debug bool, args *runner.Args, setters ...runner.Option) runner.Runner {\n\tr := &processRunner{\n\t\targs:    args,\n\t\topts:    runner.DefaultOptions(),\n\t\tdebug:   debug,\n\t\tstop:    make(chan struct{}),\n\t\tstopped: make(chan struct{}),\n\t}\n\n\tfor _, setter := range setters {\n\t\tsetter(r.opts)\n\t}\n\n\treturn r\n}\n\n// Open implements the Runner interface.\nfunc (p *processRunner) Open() error {\n\treturn nil\n}\n\n// Run implements the Runner interface.\nfunc (p *processRunner) Run(eventSink events.Recorder) error {\n\tdefer close(p.stopped)\n\n\treturn p.run(eventSink)\n}\n\n// Stop implements the Runner interface.\nfunc (p *processRunner) Stop() error {\n\tclose(p.stop)\n\n\t<-p.stopped\n\n\tp.stop = make(chan struct{})\n\tp.stopped = make(chan struct{})\n\n\treturn nil\n}\n\n// Close implements the Runner interface.\nfunc (p *processRunner) Close() error {\n\treturn nil\n}\n\ntype commandWrapper struct {\n\tlauncher     *cap.Launcher\n\tctty         optional.Optional[int]\n\tselinuxLabel string\n\tcgroupFile   *os.File\n\tstdin        *os.File\n\tstdout       *os.File\n\tstderr       *os.File\n\tafterStart   func()\n}\n\nfunc dropCaps(droppedCapabilities []string, launcher *cap.Launcher) error {\n\tdropCaps := xslices.Map(droppedCapabilities, func(c string) cap.Value {\n\t\tcapability, capErr := cap.FromName(c)\n\t\tif capErr != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to parse capability: %s\", capErr))\n\t\t}\n\n\t\treturn capability\n\t})\n\n\tiab := cap.IABGetProc()\n\tif err := iab.SetVector(cap.Bound, true, dropCaps...); err != nil {\n\t\treturn fmt.Errorf(\"failed to set capabilities: %w\", err)\n\t}\n\n\tlauncher.SetIAB(iab)\n\n\treturn nil\n}\n\n// This callback is run in the thread before executing child process.\nfunc beforeExecCallback(pa *syscall.ProcAttr, data any) error {\n\twrapper, ok := data.(*commandWrapper)\n\tif !ok {\n\t\treturn fmt.Errorf(\"failed to get command info\")\n\t}\n\n\tctty, cttySet := wrapper.ctty.Get()\n\tif cttySet {\n\t\tif pa.Sys == nil {\n\t\t\tpa.Sys = &syscall.SysProcAttr{}\n\t\t}\n\n\t\tpa.Sys.Ctty = ctty\n\t\tpa.Sys.Setsid = true\n\t\tpa.Sys.Setctty = true\n\t}\n\n\tpa.Files = []uintptr{\n\t\twrapper.stdin.Fd(),\n\t\twrapper.stdout.Fd(),\n\t\twrapper.stderr.Fd(),\n\t}\n\n\t// It is only set in case we should use CgroupFD\n\tif wrapper.cgroupFile != nil {\n\t\tif pa.Sys == nil {\n\t\t\tpa.Sys = &syscall.SysProcAttr{}\n\t\t}\n\n\t\tpa.Sys.UseCgroupFD = true\n\t\tpa.Sys.CgroupFD = int(wrapper.cgroupFile.Fd())\n\t}\n\n\t// Use /proc/thread-self (Linux 3.17+) to avoid races between current\n\t// process threads leading to loss of the domain transition\n\tif selinux.IsEnabled() {\n\t\tif wrapper.selinuxLabel != \"\" {\n\t\t\terr := os.WriteFile(\"/proc/thread-self/attr/exec\", []byte(wrapper.selinuxLabel), 0o777)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalf(\"%s\", err)\n\t\t\t}\n\t\t} else {\n\t\t\terr := os.WriteFile(\"/proc/thread-self/attr/exec\", []byte(constants.SelinuxLabelUnconfinedService), 0o777)\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatalf(\"%s\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (p *processRunner) build(extraLogWriter io.Writer) (commandWrapper, error) {\n\twrapper := commandWrapper{}\n\n\tenv := slices.Concat([]string{constants.EnvPath}, p.opts.Env, os.Environ())\n\tlauncher := cap.NewLauncher(p.args.ProcessArgs[0], p.args.ProcessArgs, env)\n\n\tif p.opts.UID > 0 {\n\t\tlauncher.SetUID(int(p.opts.UID))\n\t}\n\n\t// reduce capabilities and assign them to launcher\n\tif err := dropCaps(p.opts.DroppedCapabilities, launcher); err != nil {\n\t\treturn commandWrapper{}, err\n\t}\n\n\tlauncher.Callback(beforeExecCallback)\n\n\t// Setup logging.\n\tlogSink, err := p.opts.LoggingManager.ServiceLog(p.args.ID).Writer()\n\tif err != nil {\n\t\treturn commandWrapper{}, fmt.Errorf(\"service log handler: %w\", err)\n\t}\n\n\tlogWriter := io.MultiWriter(logSink, extraLogWriter)\n\n\tif p.debug {\n\t\tlogWriter = io.MultiWriter(logSink, log.Writer())\n\t}\n\n\t// As MultiWriter is not a file, we need to create a pipe\n\t// Pipe writer is passed to the child process while we read from the read side\n\tpr, pw, err := os.Pipe()\n\tif err != nil {\n\t\treturn commandWrapper{}, err\n\t}\n\n\tgo func() {\n\t\tdefer pr.Close()      //nolint:errcheck\n\t\tdefer logSink.Close() //nolint:errcheck\n\n\t\tio.Copy(logWriter, pr) //nolint:errcheck\n\t}()\n\n\t// close the writer if we exit early due to an error\n\tcloseWriter := true\n\n\tafterStartClosers := []io.Closer{pw}\n\n\tcloseLogging := func() {\n\t\tfor _, closer := range afterStartClosers {\n\t\t\tcloser.Close() //nolint:errcheck\n\t\t}\n\t}\n\n\tdefer func() {\n\t\tif closeWriter {\n\t\t\tcloseLogging()\n\t\t}\n\t}()\n\n\tif p.opts.StdinFile != \"\" {\n\t\tstdin, err := os.Open(p.opts.StdinFile)\n\t\tif err != nil {\n\t\t\treturn commandWrapper{}, err\n\t\t}\n\n\t\twrapper.stdin = stdin\n\n\t\tafterStartClosers = append(afterStartClosers, stdin)\n\t}\n\n\tif p.opts.StdoutFile != \"\" {\n\t\tstdout, err := os.OpenFile(p.opts.StdoutFile, os.O_WRONLY, 0)\n\t\tif err != nil {\n\t\t\treturn commandWrapper{}, err\n\t\t}\n\n\t\twrapper.stdout = stdout\n\n\t\tafterStartClosers = append(afterStartClosers, stdout)\n\t} else {\n\t\t// Do not close the fd in this case, it'll be done by closeLogger\n\t\twrapper.stdout = pw\n\t}\n\n\tif p.opts.StderrFile != \"\" {\n\t\tstderr, err := os.OpenFile(p.opts.StderrFile, os.O_WRONLY, 0)\n\t\tif err != nil {\n\t\t\treturn commandWrapper{}, err\n\t\t}\n\n\t\twrapper.stderr = stderr\n\n\t\tafterStartClosers = append(afterStartClosers, stderr)\n\t} else {\n\t\t// Do not close the fd in this case, it'll be done by closeLogger\n\t\twrapper.stderr = pw\n\t}\n\n\tcloseWriter = false\n\n\twrapper.launcher = launcher\n\twrapper.afterStart = closeLogging\n\twrapper.ctty = p.opts.Ctty\n\twrapper.selinuxLabel = p.opts.SelinuxLabel\n\n\tcgroupFdSupported := false\n\n\tplatform, err := platform.CurrentPlatform()\n\tif err == nil {\n\t\tcgroupFdSupported = platform.Mode() != runtime.ModeContainer\n\t}\n\n\t// cgroupfd is more reliable, use it when possible\n\tif cgroups.Mode() == cgroups.Unified && cgroupFdSupported && p.opts.UID == 0 {\n\t\tcg, err := os.Open(path.Join(constants.CgroupMountPath, cgroup.Path(p.opts.CgroupPath)))\n\t\tif err == nil {\n\t\t\twrapper.cgroupFile = cg\n\n\t\t\tafterStartClosers = append(afterStartClosers, cg)\n\t\t}\n\t}\n\n\treturn wrapper, nil\n}\n\n// Apply cgroup and OOM score after the process is launched.\n//\n//nolint:gocyclo,cyclop\nfunc applyProperties(p *processRunner, pid int) error {\n\tif p.opts.CgroupPath != \"\" {\n\t\tpath := cgroup.Path(p.opts.CgroupPath)\n\n\t\tif cgroups.Mode() == cgroups.Unified {\n\t\t\tcgv2, err := cgroup2.Load(path)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to load cgroup %s: %w\", path, err)\n\t\t\t}\n\n\t\t\t// No such process error can happen in case the process is terminated before this code runs\n\t\t\tif err := cgv2.AddProc(uint64(pid)); err != nil {\n\t\t\t\tpathError, ok := err.(*fs.PathError)\n\t\t\t\tif !ok || pathError.Err != syscall.ESRCH {\n\t\t\t\t\treturn fmt.Errorf(\"failed to move process %s to cgroup: %w\", p, err)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tcgv1, err := cgroup1.Load(cgroup1.StaticPath(path))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to load cgroup %s: %w\", path, err)\n\t\t\t}\n\n\t\t\tif err := cgv1.Add(cgroup1.Process{\n\t\t\t\tPid: pid,\n\t\t\t}); err != nil {\n\t\t\t\tpathError, ok := err.(*fs.PathError)\n\t\t\t\tif !ok || pathError.Err != syscall.ESRCH {\n\t\t\t\t\treturn fmt.Errorf(\"failed to move process %s to cgroup: %w\", p, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif p.opts.OOMScoreAdj != 0 {\n\t\tif err := sys.AdjustOOMScore(pid, p.opts.OOMScoreAdj); err != nil {\n\t\t\tpathError, ok := err.(*fs.PathError)\n\t\t\tif !ok || pathError.Err != syscall.ENOENT {\n\t\t\t\treturn fmt.Errorf(\"failed to change OOMScoreAdj of process %s to %d: %w\", p, p.opts.OOMScoreAdj, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif p.opts.Priority != 0 {\n\t\tif err := syscall.Setpriority(syscall.PRIO_PROCESS, pid, p.opts.Priority); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to set priority of process %s to %d: %w\", p, p.opts.Priority, err)\n\t\t}\n\t}\n\n\tif ioPriority, ioPrioritySet := p.opts.IOPriority.Get(); ioPrioritySet {\n\t\terr := setIOPriority(p, pid, ioPriority)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif schedulingPolicy, schedulingPolicySet := p.opts.SchedulingPolicy.Get(); schedulingPolicySet {\n\t\terr := setSchedulingPolicy(p, pid, schedulingPolicy)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setIOPriority(p *processRunner, pid int, ioPriority runner.IOPriorityParam) error {\n\tif ioPriority.Class > runner.IoprioClassIdle {\n\t\treturn fmt.Errorf(\"failed to set IO priority of process %s: class %d is not valid\", p, ioPriority.Class)\n\t}\n\n\tif ioPriority.Priority > 7 {\n\t\treturn fmt.Errorf(\"failed to set IO priority of process %s: priority %d is not valid\", p, ioPriority.Priority)\n\t}\n\n\tclassPos := 13 // IOPRIO_CLASS_SHIFT\n\tpriorityValue := ioPriority.Class<<classPos | ioPriority.Priority\n\tsysctlWho := uintptr(1) // IOPRIO_WHO_PROCESS, we don't operate on threads or groups\n\n\tret, _, syscallError := syscall.Syscall(syscall.SYS_IOPRIO_SET, sysctlWho, uintptr(pid), uintptr(priorityValue))\n\tif int(ret) == -1 {\n\t\treturn fmt.Errorf(\"failed to set IO priority of process %s to %d: syscall failed with %s\", p, priorityValue, syscallError.Error())\n\t}\n\n\treturn nil\n}\n\nfunc setSchedulingPolicy(p *processRunner, pid int, schedulingPolicy uint) error {\n\tif schedulingPolicy > runner.SchedulingPolicyDeadline {\n\t\treturn fmt.Errorf(\"failed to set scheduling policy of process %s: policy %d is not valid\", p, schedulingPolicy)\n\t}\n\n\toptions := struct{ Priority int32 }{\n\t\tPriority: int32(0),\n\t}\n\n\tif _, _, syscallError := syscall.Syscall(\n\t\tsyscall.SYS_SCHED_SETSCHEDULER,\n\t\tuintptr(pid),\n\t\tuintptr(schedulingPolicy),\n\t\tuintptr(unsafe.Pointer(&options)),\n\t); syscallError != 0 {\n\t\treturn fmt.Errorf(\"failed to set scheduling policy of process %s to %d: syscall failed with %s\", p, schedulingPolicy, syscallError.Error())\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (p *processRunner) run(eventSink events.Recorder) error {\n\tcg, err := cgroup.CreateCgroup(p.opts.CgroupPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating cgroup: %w\", err)\n\t}\n\n\tdefer func() {\n\t\terr := cg.Delete()\n\t\tif err != nil {\n\t\t\teventSink(events.StateStopping, \"Failed to remove cgroup for %s, %s\", p, err)\n\t\t}\n\t}()\n\n\tvar lastLog lastlog.Writer\n\n\tcmdWrapper, err := p.build(&lastLog)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building command: %w\", err)\n\t}\n\n\tdefer cmdWrapper.afterStart()\n\n\tnotifyCh := make(chan reaper.ProcessInfo, 8)\n\n\tusingReaper := reaper.Notify(notifyCh)\n\tif usingReaper {\n\t\tdefer reaper.Stop(notifyCh)\n\t}\n\n\tpid, err := cmdWrapper.launcher.Launch(&cmdWrapper)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error starting process: %w\", err)\n\t}\n\n\tif err := applyProperties(p, pid); err != nil {\n\t\treturn err\n\t}\n\n\tcmdWrapper.afterStart()\n\n\teventSink(events.StateRunning, \"Process %s started with PID %d\", p, pid)\n\n\tprocess, err := os.FindProcess(pid)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not find process: %w\", err)\n\t}\n\n\twaitCh := make(chan error)\n\n\tgo func() {\n\t\twaitCh <- reaper.ProcessWaitWrapper(usingReaper, notifyCh, process)\n\t}()\n\n\tselect {\n\tcase err = <-waitCh:\n\t\t// process exited\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"%w (last log %q)\", err, lastLog.GetLastLog())\n\t\t}\n\n\t\treturn err\n\tcase <-p.stop:\n\t\t// graceful stop the service\n\t\teventSink(events.StateStopping, \"Sending SIGTERM to %s\", p)\n\n\t\t//nolint:errcheck\n\t\t_ = process.Signal(syscall.SIGTERM)\n\t}\n\n\tselect {\n\tcase <-waitCh:\n\t\t// stopped process exited\n\t\treturn nil\n\tcase <-time.After(p.opts.GracefulShutdownTimeout):\n\t\t// kill the process\n\t\teventSink(events.StateStopping, \"Sending SIGKILL to %s\", p)\n\n\t\t//nolint:errcheck\n\t\t_ = process.Signal(syscall.SIGKILL)\n\t}\n\n\t// wait for process to terminate\n\t<-waitCh\n\n\treturn nil\n}\n\nfunc (p *processRunner) String() string {\n\treturn fmt.Sprintf(\"Process(%q)\", p.args.ProcessArgs)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/process/process_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage process_test\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd/proc/reaper\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/goleak\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n)\n\nfunc MockEventSink(t *testing.T) func(state events.ServiceState, message string, args ...any) {\n\treturn func(state events.ServiceState, message string, args ...any) {\n\t\tt.Logf(\"state %s: %s\", state, fmt.Sprintf(message, args...))\n\t}\n}\n\ntype ProcessSuite struct {\n\tsuite.Suite\n\n\ttmpDir    string\n\trunReaper bool\n\n\tloggingManager runtime.LoggingManager\n}\n\nfunc (suite *ProcessSuite) SetupSuite() {\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tsuite.loggingManager = logging.NewFileLoggingManager(suite.tmpDir)\n\n\tif suite.runReaper {\n\t\treaper.Run()\n\t}\n}\n\nfunc (suite *ProcessSuite) TearDownSuite() {\n\tif suite.runReaper {\n\t\treaper.Shutdown()\n\t}\n}\n\nfunc (suite *ProcessSuite) TestRunSuccess() {\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"test\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"exit 0\"},\n\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink(suite.T())))\n\t// calling stop when Run has finished is no-op\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *ProcessSuite) TestRunLogs() {\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"logtest\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"echo -n \\\"Test 1\\nTest 2\\n\\\"\"},\n\t}, runner.WithLoggingManager(suite.loggingManager))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tsuite.Assert().NoError(r.Run(MockEventSink(suite.T())))\n\n\t// the log file is written asynchronously, so we need to wait a bit\n\tsuite.EventuallyWithT(func(collect *assert.CollectT) {\n\t\tasrt := assert.New(collect)\n\n\t\tlogContents, err := os.ReadFile(filepath.Join(suite.tmpDir, \"logtest.log\"))\n\t\tasrt.NoError(err)\n\n\t\tasrt.Equal([]byte(\"Test 1\\nTest 2\\n\"), logContents)\n\t}, time.Second, 10*time.Millisecond)\n}\n\nfunc (suite *ProcessSuite) TestRunRestartFailed() {\n\ttestFile := filepath.Join(suite.tmpDir, \"talos-test\")\n\t//nolint:errcheck\n\t_ = os.Remove(testFile)\n\n\tr := restart.New(process.NewRunner(false, &runner.Args{\n\t\tID:          \"restarter\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"echo \\\"ran\\\"; test -f \" + testFile},\n\t}, runner.WithLoggingManager(suite.loggingManager)), restart.WithType(restart.UntilSuccess), restart.WithRestartInterval(time.Millisecond))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsuite.Assert().NoError(r.Run(MockEventSink(suite.T())))\n\t})\n\n\tfetchLog := func() []byte {\n\t\tlogFile, err := os.Open(filepath.Join(suite.tmpDir, \"restarter.log\"))\n\t\tsuite.Assert().NoError(err)\n\n\t\t//nolint:errcheck\n\t\tdefer logFile.Close()\n\n\t\tlogContents, err := io.ReadAll(logFile)\n\t\tsuite.Assert().NoError(err)\n\n\t\treturn logContents\n\t}\n\n\tfor range 20 {\n\t\ttime.Sleep(100 * time.Millisecond)\n\n\t\tif len(fetchLog()) > 20 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tf, err := os.Create(testFile)\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().NoError(f.Close())\n\n\twg.Wait()\n\n\tsuite.Assert().GreaterOrEqual(len(fetchLog()), 20, fetchLog())\n}\n\nfunc (suite *ProcessSuite) TestStopFailingAndRestarting() {\n\ttestFile := filepath.Join(suite.tmpDir, \"talos-test\")\n\t//nolint:errcheck\n\t_ = os.Remove(testFile)\n\n\tr := restart.New(process.NewRunner(false, &runner.Args{\n\t\tID:          \"endless\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"test -f \" + testFile},\n\t}, runner.WithLoggingManager(suite.loggingManager)), restart.WithType(restart.Forever), restart.WithRestartInterval(5*time.Millisecond))\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink(suite.T()))\n\t}()\n\n\ttime.Sleep(40 * time.Millisecond)\n\n\tselect {\n\tcase <-done:\n\t\tsuite.Assert().Fail(\"task should be running\")\n\n\t\treturn\n\tdefault:\n\t}\n\n\tf, err := os.Create(testFile)\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().NoError(f.Close())\n\n\ttime.Sleep(40 * time.Millisecond)\n\n\tselect {\n\tcase <-done:\n\t\tsuite.Assert().Fail(\"task should be running\")\n\n\t\treturn\n\tdefault:\n\t}\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n}\n\nfunc (suite *ProcessSuite) TestStopSigKill() {\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"nokill\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"trap -- '' SIGTERM; while :; do :; done\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t)\n\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink(suite.T()))\n\t}()\n\n\ttime.Sleep(100 * time.Millisecond)\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n}\n\nfunc (suite *ProcessSuite) TestPriority() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test, need root privileges\")\n\t}\n\n\tpidFile := filepath.Join(suite.tmpDir, \"talos-test-pid-prio\")\n\t//nolint:errcheck\n\t_ = os.Remove(pidFile)\n\n\tcurrentPriority, err := syscall.Getpriority(syscall.PRIO_PROCESS, os.Getpid())\n\tsuite.Assert().NoError(err)\n\n\tif currentPriority <= 3 {\n\t\tsuite.T().Skipf(\"skipping test, we already have low priority %d\", currentPriority)\n\t}\n\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"nokill\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"echo $BASHPID >> \" + pidFile + \"; trap -- '' SIGTERM; while :; do :; done\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t\trunner.WithPriority(17),\n\t)\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink(suite.T()))\n\t}()\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tpidString, err := os.ReadFile(pidFile)\n\tsuite.Assert().NoError(err)\n\n\tpid, err := strconv.ParseUint(strings.Trim(string(pidString), \"\\r\\n\"), 10, 32)\n\tsuite.Assert().NoError(err)\n\n\tcurrentPriority, err = syscall.Getpriority(syscall.PRIO_PROCESS, int(pid))\n\tsuite.Assert().NoError(err)\n\t// 40..1 corresponds to -20..19 since system call interface must reserve -1 for error\n\tsuite.Assert().Equalf(3, currentPriority, \"process priority should be 3 (nice 17), got %d\", currentPriority)\n\n\ttime.Sleep(1000 * time.Millisecond)\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n}\n\nfunc (suite *ProcessSuite) TestIOPriority() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test, need root privileges\")\n\t}\n\n\tpidFile := filepath.Join(suite.tmpDir, \"talos-test-pid-ionice\")\n\t//nolint:errcheck\n\t_ = os.Remove(pidFile)\n\n\t//nolint:errcheck\n\tioprio, _, _ := syscall.Syscall(syscall.SYS_IOPRIO_GET, uintptr(1), uintptr(os.Getpid()), 0)\n\tsuite.Assert().NotEqual(-1, int(ioprio))\n\n\tif ioprio>>13 == runner.IoprioClassIdle {\n\t\tsuite.T().Skipf(\"skipping test, we already have idle IO priority %d\", ioprio)\n\t}\n\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"nokill\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"echo $BASHPID >> \" + pidFile + \"; trap -- '' SIGTERM; while :; do :; done\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t\trunner.WithIOPriority(runner.IoprioClassIdle, 6),\n\t)\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink(suite.T()))\n\t}()\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tpidString, err := os.ReadFile(pidFile)\n\tsuite.Assert().NoError(err)\n\n\tpid, err := strconv.ParseUint(strings.Trim(string(pidString), \"\\r\\n\"), 10, 32)\n\tsuite.Assert().NoError(err)\n\n\t//nolint:errcheck\n\tioprio, _, _ = syscall.Syscall(syscall.SYS_IOPRIO_GET, uintptr(1), uintptr(pid), 0)\n\tsuite.Assert().NotEqual(-1, int(ioprio))\n\tsuite.Assert().Equal(runner.IoprioClassIdle<<13+6, int(ioprio))\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n}\n\nfunc (suite *ProcessSuite) TestSchedulingPolicy() {\n\tif os.Geteuid() != 0 {\n\t\tsuite.T().Skip(\"skipping test, need root privileges\")\n\t}\n\n\tpidFile := filepath.Join(suite.tmpDir, \"talos-test-pid-sched\")\n\t//nolint:errcheck\n\t_ = os.Remove(pidFile)\n\n\tpol, _, errno := syscall.Syscall(syscall.SYS_SCHED_GETSCHEDULER, uintptr(os.Getpid()), 0, 0)\n\tsuite.Assert().Equal(0, int(errno))\n\n\tif pol == runner.SchedulingPolicyIdle {\n\t\tsuite.T().Skipf(\"skipping test, we already have idle scheduling policy\")\n\t}\n\n\tr := process.NewRunner(false, &runner.Args{\n\t\tID:          \"nokill\",\n\t\tProcessArgs: []string{\"/bin/bash\", \"-c\", \"echo $BASHPID >> \" + pidFile + \"; trap -- '' SIGTERM; while :; do :; done\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithGracefulShutdownTimeout(10*time.Millisecond),\n\t\trunner.WithSchedulingPolicy(runner.SchedulingPolicyIdle),\n\t)\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tdone := make(chan error, 1)\n\n\tgo func() {\n\t\tdone <- r.Run(MockEventSink(suite.T()))\n\t}()\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tpidString, err := os.ReadFile(pidFile)\n\tsuite.Assert().NoError(err)\n\n\tpid, err := strconv.ParseUint(strings.Trim(string(pidString), \"\\r\\n\"), 10, 32)\n\tsuite.Assert().NoError(err)\n\n\tpol, _, errno = syscall.Syscall(syscall.SYS_SCHED_GETSCHEDULER, uintptr(pid), 0, 0)\n\tsuite.Assert().Equal(0, int(errno))\n\tsuite.Assert().Equal(runner.SchedulingPolicyIdle, int(pol))\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tsuite.Assert().NoError(r.Stop())\n\t<-done\n}\n\nfunc TestProcessSuite(t *testing.T) {\n\tfor _, runReaper := range []bool{true, false} {\n\t\tt.Run(fmt.Sprintf(\"runReaper=%v\", runReaper),\n\t\t\tfunc(t *testing.T) {\n\t\t\t\tsuite.Run(t, &ProcessSuite{runReaper: runReaper})\n\t\t\t},\n\t\t)\n\t}\n}\n\nfunc TestMain(m *testing.M) {\n\tgoleak.VerifyTestMain(m)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/restart/restart.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage restart\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n)\n\ntype restarter struct {\n\twrappedRunner runner.Runner\n\topts          *Options\n\n\tstop    chan struct{}\n\tstopped chan struct{}\n}\n\n// New wraps runner.Runner with restart policy.\nfunc New(wrapRunner runner.Runner, opts ...Option) runner.Runner {\n\tr := &restarter{\n\t\twrappedRunner: wrapRunner,\n\t\topts:          DefaultOptions(),\n\t\tstop:          make(chan struct{}),\n\t\tstopped:       make(chan struct{}),\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(r.opts)\n\t}\n\n\treturn r\n}\n\n// Options is the functional options struct.\ntype Options struct {\n\t// Type describes the service's restart policy.\n\tType Type\n\t// RestartInterval is the interval between restarts for failed runs.\n\tRestartInterval time.Duration\n}\n\n// Option is the functional option func.\ntype Option func(*Options)\n\n// Type represents the service's restart policy.\ntype Type int\n\nconst (\n\t// Forever will always restart a process.\n\tForever Type = iota\n\t// Once will run process exactly once.\n\tOnce\n\t// UntilSuccess will restart process until run succeeds.\n\tUntilSuccess\n)\n\nfunc (t Type) String() string {\n\tswitch t {\n\tcase Forever:\n\t\treturn \"Forever\"\n\tcase Once:\n\t\treturn \"Once\"\n\tcase UntilSuccess:\n\t\treturn \"UntilSuccess\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\n// DefaultOptions describes the default options to a runner.\nfunc DefaultOptions() *Options {\n\treturn &Options{\n\t\tType:            Forever,\n\t\tRestartInterval: 5 * time.Second,\n\t}\n}\n\n// WithType sets the type of a service.\nfunc WithType(o Type) Option {\n\treturn func(args *Options) {\n\t\targs.Type = o\n\t}\n}\n\n// WithRestartInterval sets the interval between restarts of the failed task.\nfunc WithRestartInterval(interval time.Duration) Option {\n\treturn func(args *Options) {\n\t\targs.RestartInterval = interval\n\t}\n}\n\n// Open implements the Runner interface.\nfunc (r *restarter) Open() error {\n\treturn r.wrappedRunner.Open()\n}\n\n// Run implements the Runner interface\n//\n//nolint:gocyclo\nfunc (r *restarter) Run(eventSink events.Recorder) error {\n\tdefer close(r.stopped)\n\n\tfor {\n\t\terrCh := make(chan error)\n\n\t\tgo func() {\n\t\t\terrCh <- r.wrappedRunner.Run(eventSink)\n\t\t}()\n\n\t\tvar err error\n\n\t\tselect {\n\t\tcase <-r.stop:\n\t\t\t//nolint:errcheck\n\t\t\t_ = r.wrappedRunner.Stop()\n\n\t\t\treturn <-errCh\n\t\tcase err = <-errCh:\n\t\t}\n\n\t\terrStop := r.wrappedRunner.Stop()\n\t\tif errStop != nil {\n\t\t\treturn errStop\n\t\t}\n\n\t\tswitch r.opts.Type {\n\t\tcase Once:\n\t\t\treturn err\n\t\tcase UntilSuccess:\n\t\t\tif err == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\teventSink(events.StateWaiting, \"Error running %s, going to restart until it succeeds: %v\", r.wrappedRunner, err)\n\t\tcase Forever:\n\t\t\tif err == nil {\n\t\t\t\teventSink(events.StateWaiting, \"Runner %s exited without error, going to restart it\", r.wrappedRunner)\n\t\t\t} else {\n\t\t\t\teventSink(events.StateWaiting, \"Error running %v, going to restart forever: %v\", r.wrappedRunner, err)\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase <-r.stop:\n\t\t\teventSink(events.StateStopping, \"Aborting restart sequence\")\n\n\t\t\treturn nil\n\t\tcase <-time.After(r.opts.RestartInterval):\n\t\t}\n\t}\n}\n\n// Stop implements the Runner interface.\nfunc (r *restarter) Stop() error {\n\tclose(r.stop)\n\n\t<-r.stopped\n\n\treturn nil\n}\n\n// Close implements the Runner interface.\nfunc (r *restarter) Close() error {\n\treturn r.wrappedRunner.Close()\n}\n\n// String implements the Runner interface.\nfunc (r *restarter) String() string {\n\treturn fmt.Sprintf(\"Restart(%s, %s)\", r.opts.Type, r.wrappedRunner)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/restart/restart_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage restart_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n)\n\ntype RestartSuite struct {\n\tsuite.Suite\n}\n\ntype MockRunner struct {\n\texitCh  chan error\n\ttimes   int\n\tstop    chan struct{}\n\tstopped chan struct{}\n}\n\nfunc (m *MockRunner) Open() error {\n\tm.stop = make(chan struct{})\n\tm.stopped = make(chan struct{})\n\n\treturn nil\n}\n\nfunc (m *MockRunner) Close() error {\n\tclose(m.exitCh)\n\n\treturn nil\n}\n\nfunc (m *MockRunner) Run(eventSink events.Recorder) error {\n\tdefer close(m.stopped)\n\n\tselect {\n\tcase err := <-m.exitCh:\n\t\tm.times++\n\n\t\treturn err\n\tcase <-m.stop:\n\t\treturn nil\n\t}\n}\n\nfunc (m *MockRunner) Stop() error {\n\tclose(m.stop)\n\n\t<-m.stopped\n\n\tm.stop = make(chan struct{})\n\tm.stopped = make(chan struct{})\n\n\treturn nil\n}\n\nfunc (m *MockRunner) String() string {\n\treturn \"MockRunner()\"\n}\n\nfunc MockEventSink(state events.ServiceState, message string, args ...any) {\n\tlog.Printf(\"state %s: %s\", state, fmt.Sprintf(message, args...))\n}\n\nfunc (suite *RestartSuite) TestString() {\n\tsuite.Assert().Equal(\"Restart(UntilSuccess, MockRunner())\", restart.New(&MockRunner{}, restart.WithType(restart.UntilSuccess)).String())\n}\n\nfunc (suite *RestartSuite) TestRunOnce() {\n\tmock := MockRunner{\n\t\texitCh: make(chan error),\n\t}\n\n\tr := restart.New(&mock, restart.WithType(restart.Once))\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tfailed := errors.New(\"failed\")\n\n\tgo func() {\n\t\tmock.exitCh <- failed\n\t}()\n\n\tsuite.Assert().EqualError(r.Run(MockEventSink), failed.Error())\n\tsuite.Assert().NoError(r.Stop())\n}\n\nfunc (suite *RestartSuite) TestRunOnceStop() {\n\tmock := MockRunner{\n\t\texitCh: make(chan error),\n\t}\n\n\tr := restart.New(&mock, restart.WithType(restart.Once))\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.Run(MockEventSink)\n\t}()\n\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().NoError(<-errCh)\n}\n\nfunc (suite *RestartSuite) TestRunUntilSuccess() {\n\tmock := MockRunner{\n\t\texitCh: make(chan error),\n\t}\n\n\tr := restart.New(&mock, restart.WithType(restart.UntilSuccess), restart.WithRestartInterval(time.Millisecond))\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tfailed := errors.New(\"failed\")\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.Run(MockEventSink)\n\t}()\n\n\tmock.exitCh <- failed\n\n\tmock.exitCh <- failed\n\n\tmock.exitCh <- failed\n\n\tmock.exitCh <- nil\n\n\tsuite.Assert().NoError(<-errCh)\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().Equal(4, mock.times)\n}\n\nfunc (suite *RestartSuite) TestRunForever() {\n\tmock := MockRunner{\n\t\texitCh: make(chan error),\n\t}\n\n\tr := restart.New(&mock, restart.WithType(restart.Forever), restart.WithRestartInterval(time.Millisecond))\n\tsuite.Assert().NoError(r.Open())\n\n\tdefer func() { suite.Assert().NoError(r.Close()) }()\n\n\tfailed := errors.New(\"failed\")\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.Run(MockEventSink)\n\t}()\n\n\tmock.exitCh <- failed\n\n\tmock.exitCh <- nil\n\n\tmock.exitCh <- failed\n\n\tmock.exitCh <- nil\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Assert().Fail(\"runner should be still running\")\n\tdefault:\n\t}\n\n\tsuite.Assert().NoError(r.Stop())\n\tsuite.Assert().NoError(<-errCh)\n\tsuite.Assert().Equal(4, mock.times)\n}\n\nfunc TestRestartSuite(t *testing.T) {\n\tsuite.Run(t, new(RestartSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/runner.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package runner provides a runner for running services.\npackage runner\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Runner describes the requirements for running a process.\ntype Runner interface {\n\tfmt.Stringer\n\tOpen() error\n\tRun(events.Recorder) error\n\tStop() error\n\tClose() error\n}\n\n// Args represents the required options for services.\ntype Args struct {\n\tID          string\n\tProcessArgs []string\n}\n\n// IOPriorityParam represents the combination of IO scheduling class and priority.\ntype IOPriorityParam struct {\n\tClass    uint\n\tPriority uint\n}\n\n// Options is the functional options struct.\ntype Options struct {\n\t// LoggingManager provides service log handling.\n\tLoggingManager runtime.LoggingManager\n\t// Env describes the service's environment variables. Elements should be in\n\t// the format <key=<value>\n\tEnv []string\n\t// ContainerdAddress is containerd socket address.\n\tContainerdAddress string\n\t// ContainerOpts describes the container options.\n\tContainerOpts []containerd.NewContainerOpts\n\t// OCISpecOpts describes the OCI spec options.\n\tOCISpecOpts []oci.SpecOpts\n\t// ContainerImage is the container's image.\n\tContainerImage string\n\t// Namespace is the containerd namespace.\n\tNamespace string\n\t// GracefulShutdownTimeout is the time to wait for process to exit after SIGTERM\n\t// before sending SIGKILL\n\tGracefulShutdownTimeout time.Duration\n\t// Stdin is the process standard input.\n\tStdin io.ReadSeeker\n\t// Specify an oom_score_adj for the process.\n\tOOMScoreAdj int\n\t// CgroupPath (optional) sets the cgroup path to use\n\tCgroupPath string\n\t// OverrideSeccompProfile default Linux seccomp profile.\n\tOverrideSeccompProfile func(*specs.LinuxSeccomp)\n\t// DroppedCapabilities is the list of capabilities to drop.\n\tDroppedCapabilities []string\n\t// SelinuxLabel is the SELinux label to be assigned\n\tSelinuxLabel string\n\t// StdinFile is the path to the file to use as stdin.\n\tStdinFile string\n\t// StdoutFile is the path to the file to use as stdout.\n\tStdoutFile string\n\t// StderrFile is the path to the file to use as stderr.\n\tStderrFile string\n\t// Ctty is the controlling tty.\n\tCtty optional.Optional[int]\n\t// UID is the user id of the process.\n\tUID uint32\n\t// Priority is the niceness value of the process.\n\tPriority int\n\t// IOPriority is the IO priority value and class of the process.\n\tIOPriority optional.Optional[IOPriorityParam]\n\t// SchedulingPolicy is the scheduling policy of the process.\n\tSchedulingPolicy optional.Optional[uint]\n}\n\n// Option is the functional option func.\ntype Option func(*Options)\n\n// DefaultOptions describes the default options to a runner.\nfunc DefaultOptions() *Options {\n\treturn &Options{\n\t\tLoggingManager:          logging.NewNullLoggingManager(),\n\t\tEnv:                     []string{},\n\t\tNamespace:               constants.SystemContainerdNamespace,\n\t\tGracefulShutdownTimeout: 10 * time.Second,\n\t\tContainerdAddress:       constants.CRIContainerdAddress,\n\t\tStdin:                   nil,\n\t\tOOMScoreAdj:             0,\n\t}\n}\n\n// WithEnv sets the environment variables of a service.\nfunc WithEnv(o []string) Option {\n\treturn func(args *Options) {\n\t\targs.Env = o\n\t}\n}\n\n// WithNamespace sets the tar file to load.\nfunc WithNamespace(o string) Option {\n\treturn func(args *Options) {\n\t\targs.Namespace = o\n\t}\n}\n\n// WithContainerdAddress sets the containerd socket path.\nfunc WithContainerdAddress(a string) Option {\n\treturn func(args *Options) {\n\t\targs.ContainerdAddress = a\n\t}\n}\n\n// WithContainerImage sets the image ref.\nfunc WithContainerImage(o string) Option {\n\treturn func(args *Options) {\n\t\targs.ContainerImage = o\n\t}\n}\n\n// WithContainerOpts sets the containerd container options.\nfunc WithContainerOpts(o ...containerd.NewContainerOpts) Option {\n\treturn func(args *Options) {\n\t\targs.ContainerOpts = o\n\t}\n}\n\n// WithOCISpecOpts sets the OCI spec options.\nfunc WithOCISpecOpts(o ...oci.SpecOpts) Option {\n\treturn func(args *Options) {\n\t\targs.OCISpecOpts = o\n\t}\n}\n\n// WithLoggingManager sets the LoggingManager option.\nfunc WithLoggingManager(manager runtime.LoggingManager) Option {\n\treturn func(args *Options) {\n\t\targs.LoggingManager = manager\n\t}\n}\n\n// WithGracefulShutdownTimeout sets the timeout for the task to terminate before sending SIGKILL.\nfunc WithGracefulShutdownTimeout(timeout time.Duration) Option {\n\treturn func(args *Options) {\n\t\targs.GracefulShutdownTimeout = timeout\n\t}\n}\n\n// WithStdin sets the standard input.\nfunc WithStdin(stdin io.ReadSeeker) Option {\n\treturn func(args *Options) {\n\t\targs.Stdin = stdin\n\t}\n}\n\n// WithOOMScoreAdj sets the oom_score_adj.\nfunc WithOOMScoreAdj(score int) Option {\n\treturn func(args *Options) {\n\t\targs.OOMScoreAdj = score\n\t}\n}\n\n// WithCgroupPath sets the cgroup path.\nfunc WithCgroupPath(path string) Option {\n\treturn func(args *Options) {\n\t\targs.CgroupPath = path\n\t}\n}\n\n// WithSelinuxLabel sets the SELinux label.\nfunc WithSelinuxLabel(label string) Option {\n\treturn func(args *Options) {\n\t\targs.SelinuxLabel = label\n\t}\n}\n\n// WithCustomSeccompProfile sets the function to override seccomp profile.\nfunc WithCustomSeccompProfile(override func(*specs.LinuxSeccomp)) Option {\n\treturn func(args *Options) {\n\t\targs.OverrideSeccompProfile = override\n\t}\n}\n\n// WithDroppedCapabilities sets the list of capabilities to drop.\nfunc WithDroppedCapabilities(caps map[string]struct{}) Option {\n\treturn func(args *Options) {\n\t\targs.DroppedCapabilities = maps.Keys(caps)\n\t}\n}\n\n// WithStdinFile sets the path to the file to use as stdin.\nfunc WithStdinFile(path string) Option {\n\treturn func(args *Options) {\n\t\targs.StdinFile = path\n\t}\n}\n\n// WithStdoutFile sets the path to the file to use as stdout.\nfunc WithStdoutFile(path string) Option {\n\treturn func(args *Options) {\n\t\targs.StdoutFile = path\n\t}\n}\n\n// WithStderrFile sets the path to the file to use as stderr.\nfunc WithStderrFile(path string) Option {\n\treturn func(args *Options) {\n\t\targs.StdoutFile = path\n\t}\n}\n\n// WithCtty sets the controlling tty.\nfunc WithCtty(ctty int) Option {\n\treturn func(args *Options) {\n\t\targs.Ctty = optional.Some(ctty)\n\t}\n}\n\n// WithUID sets the user id of the process.\nfunc WithUID(uid uint32) Option {\n\treturn func(args *Options) {\n\t\targs.UID = uid\n\t}\n}\n\n// WithPriority sets the priority of the process.\nfunc WithPriority(priority int) Option {\n\treturn func(args *Options) {\n\t\targs.Priority = priority\n\t}\n}\n\nconst (\n\t// IoprioClassNone represents IOPRIO_CLASS_NONE.\n\tIoprioClassNone = iota\n\t// IoprioClassRt represents IOPRIO_CLASS_RT.\n\tIoprioClassRt\n\t// IoprioClassBe represents IOPRIO_CLASS_BE.\n\tIoprioClassBe\n\t// IoprioClassIdle represents IOPRIO_CLASS_IDLE.\n\tIoprioClassIdle\n)\n\n// WithIOPriority sets the IO priority and class of the process.\nfunc WithIOPriority(class, priority uint) Option {\n\treturn func(args *Options) {\n\t\targs.IOPriority = optional.Some(IOPriorityParam{\n\t\t\tClass:    class,\n\t\t\tPriority: priority,\n\t\t})\n\t}\n}\n\nconst (\n\t// SchedulingPolicyNormal represents SCHED_NORMAL.\n\tSchedulingPolicyNormal = iota\n\t// SchedulingPolicyFIFO represents SCHED_FIFO.\n\tSchedulingPolicyFIFO\n\t// SchedulingPolicyRR represents SCHED_RR.\n\tSchedulingPolicyRR\n\t// SchedulingPolicyBatch represents SCHED_BATCH.\n\tSchedulingPolicyBatch\n\t// SchedulingPolicyIsoUnimplemented represents SCHED_ISO.\n\tSchedulingPolicyIsoUnimplemented\n\t// SchedulingPolicyIdle represents SCHED_IDLE.\n\tSchedulingPolicyIdle\n\t// SchedulingPolicyDeadline represents SCHED_DEADLINE.\n\tSchedulingPolicyDeadline\n)\n\n// WithSchedulingPolicy sets the scheduling policy of the process.\nfunc WithSchedulingPolicy(policy uint) Option {\n\treturn func(args *Options) {\n\t\targs.SchedulingPolicy = optional.Some(policy)\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/runner/runner_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runner_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\n// Service is an interface describing a system service.\ntype Service interface {\n\t// ID is the service id.\n\tID(runtime.Runtime) string\n\t// PreFunc is invoked before a runner is created\n\tPreFunc(context.Context, runtime.Runtime) error\n\t// Runner creates runner for the service\n\tRunner(runtime.Runtime) (runner.Runner, error)\n\t// PostFunc is invoked after a runner is closed.\n\tPostFunc(runtime.Runtime, events.ServiceState) error\n\t// Condition describes the conditions under which a service should\n\t// start.\n\tCondition(runtime.Runtime) conditions.Condition\n\t// DependsOn returns list of service IDs this service depends on.\n\tDependsOn(runtime.Runtime) []string\n\t// Volumes returns a list of volume IDs the service needs.\n\tVolumes(runtime.Runtime) []string\n}\n\n// HealthcheckedService is a service which provides health check.\ntype HealthcheckedService interface {\n\t// HealtFunc provides function that checks health of the service\n\tHealthFunc(runtime.Runtime) health.Check\n\t// HealthSettings returns settings for the health check\n\tHealthSettings(runtime.Runtime) *health.Settings\n}\n\n// APIStartableService is a service which allows to be started via API.\ntype APIStartableService interface {\n\tAPIStartAllowed(runtime.Runtime) bool\n}\n\n// APIStoppableService is a service which allows to be stopped via API.\ntype APIStoppableService interface {\n\tAPIStopAllowed(runtime.Runtime) bool\n}\n\n// APIRestartableService is a service which allows to be restarted via API.\ntype APIRestartableService interface {\n\tAPIRestartAllowed(runtime.Runtime) bool\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/service_events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\n// StateEvent is a service event (e.g. 'up', 'down').\ntype StateEvent string\n\n// Service event list.\nconst (\n\tStateEventUp       = StateEvent(\"up\")\n\tStateEventDown     = StateEvent(\"down\")\n\tStateEventFinished = StateEvent(\"finished\")\n)\n\ntype serviceCondition struct {\n\tmu              sync.Mutex\n\twaitingRegister bool\n\tinstance        *singleton\n\n\tevent   StateEvent\n\tservice string\n}\n\nfunc (sc *serviceCondition) Wait(ctx context.Context) error {\n\tsc.instance.mu.Lock()\n\tsvcrunner := sc.instance.state[sc.service]\n\tsc.instance.mu.Unlock()\n\n\tif svcrunner == nil {\n\t\treturn sc.waitRegister(ctx)\n\t}\n\n\treturn sc.waitEvent(ctx, svcrunner)\n}\n\nfunc (sc *serviceCondition) waitEvent(ctx context.Context, svcrunner *ServiceRunner) error {\n\tnotifyCh := make(chan struct{}, 1)\n\n\tsvcrunner.Subscribe(sc.event, notifyCh)\n\tdefer svcrunner.Unsubscribe(sc.event, notifyCh)\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-notifyCh:\n\t\treturn nil\n\t}\n}\n\nfunc (sc *serviceCondition) waitRegister(ctx context.Context) error {\n\tsc.mu.Lock()\n\tsc.waitingRegister = true\n\tsc.mu.Unlock()\n\n\tticker := time.NewTicker(100 * time.Millisecond)\n\tdefer ticker.Stop()\n\n\tvar svcrunner *ServiceRunner\n\n\tfor {\n\t\tsc.instance.mu.Lock()\n\t\tsvcrunner = sc.instance.state[sc.service]\n\t\tsc.instance.mu.Unlock()\n\n\t\tif svcrunner != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t}\n\t}\n\n\tsc.mu.Lock()\n\tsc.waitingRegister = false\n\tsc.mu.Unlock()\n\n\treturn sc.waitEvent(ctx, svcrunner)\n}\n\nfunc (sc *serviceCondition) String() string {\n\tsc.mu.Lock()\n\twaitingRegister := sc.waitingRegister\n\tsc.mu.Unlock()\n\n\tif waitingRegister {\n\t\treturn fmt.Sprintf(\"service %q to be registered\", sc.service)\n\t}\n\n\treturn fmt.Sprintf(\"service %q to be %q\", sc.service, string(sc.event))\n}\n\n// WaitForService waits for service to reach some state event.\nfunc WaitForService(event StateEvent, service string) conditions.Condition {\n\treturn waitForService(instance, event, service)\n}\n\nfunc waitForService(instance *singleton, event StateEvent, service string) conditions.Condition {\n\treturn &serviceCondition{\n\t\tinstance: instance,\n\t\tevent:    event,\n\t\tservice:  service,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/service_runner.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// WaitConditionCheckInterval is time between checking for wait condition\n// description changes.\n//\n// Exposed here for unit-tests to override.\nvar WaitConditionCheckInterval = time.Second\n\n// ServiceRunner wraps the state of the service (running, stopped, ...).\ntype ServiceRunner struct {\n\tmu sync.Mutex\n\n\truntime  runtime.Runtime\n\tservice  Service\n\tid       string\n\tinstance *singleton\n\n\tstate  events.ServiceState\n\tevents events.ServiceEvents\n\n\thealthState health.State\n\n\tstateSubscribers map[StateEvent][]chan<- struct{}\n\n\tstopCh chan struct{}\n}\n\n// NewServiceRunner creates new ServiceRunner around Service instance.\nfunc NewServiceRunner(instance *singleton, service Service, runtime runtime.Runtime) *ServiceRunner {\n\treturn &ServiceRunner{\n\t\tservice:          service,\n\t\tinstance:         instance,\n\t\truntime:          runtime,\n\t\tid:               service.ID(runtime),\n\t\tstate:            events.StateInitialized,\n\t\tstateSubscribers: make(map[StateEvent][]chan<- struct{}),\n\t\tstopCh:           make(chan struct{}, 1),\n\t}\n}\n\n// GetState implements events.Recorder.\nfunc (svcrunner *ServiceRunner) GetState() events.ServiceState {\n\tsvcrunner.mu.Lock()\n\tdefer svcrunner.mu.Unlock()\n\n\treturn svcrunner.state\n}\n\n// UpdateState implements events.Recorder.\nfunc (svcrunner *ServiceRunner) UpdateState(ctx context.Context, newstate events.ServiceState, message string, args ...any) {\n\tsvcrunner.mu.Lock()\n\n\tevent := events.ServiceEvent{\n\t\tMessage:   fmt.Sprintf(message, args...),\n\t\tState:     newstate,\n\t\tTimestamp: time.Now(),\n\t}\n\n\tsvcrunner.state = newstate\n\tsvcrunner.events.Push(event)\n\n\tlog.Printf(\"service[%s](%s): %s\", svcrunner.id, svcrunner.state, event.Message)\n\n\tisUp := svcrunner.inStateLocked(StateEventUp)\n\tisDown := svcrunner.inStateLocked(StateEventDown)\n\tisFinished := svcrunner.inStateLocked(StateEventFinished)\n\tsvcrunner.mu.Unlock()\n\n\tif svcrunner.runtime != nil {\n\t\tsvcrunner.runtime.Events().Publish(ctx, event.AsProto(svcrunner.id))\n\t}\n\n\tif isUp {\n\t\tsvcrunner.notifyEvent(StateEventUp)\n\t}\n\n\tif isDown {\n\t\tsvcrunner.notifyEvent(StateEventDown)\n\t}\n\n\tif isFinished {\n\t\tsvcrunner.notifyEvent(StateEventFinished)\n\t}\n}\n\nfunc (svcrunner *ServiceRunner) healthUpdate(ctx context.Context, change health.StateChange) {\n\tsvcrunner.mu.Lock()\n\n\t// service not running, suppress event\n\tif svcrunner.state != events.StateRunning {\n\t\tsvcrunner.mu.Unlock()\n\n\t\treturn\n\t}\n\n\tvar message string\n\tif *change.New.Healthy {\n\t\tmessage = \"Health check successful\"\n\t} else {\n\t\tmessage = fmt.Sprintf(\"Health check failed: %s\", change.New.LastMessage)\n\t}\n\n\tevent := events.ServiceEvent{\n\t\tMessage:   message,\n\t\tState:     svcrunner.state,\n\t\tHealth:    change.New,\n\t\tTimestamp: time.Now(),\n\t}\n\tsvcrunner.events.Push(event)\n\n\tlog.Printf(\"service[%s](%s): %s\", svcrunner.id, svcrunner.state, event.Message)\n\n\tisUp := svcrunner.inStateLocked(StateEventUp)\n\tsvcrunner.mu.Unlock()\n\n\tif isUp {\n\t\tsvcrunner.notifyEvent(StateEventUp)\n\t}\n\n\tif svcrunner.runtime != nil {\n\t\tsvcrunner.runtime.Events().Publish(ctx, event.AsProto(svcrunner.id))\n\t}\n}\n\n// GetEventHistory returns history of events for this service.\nfunc (svcrunner *ServiceRunner) GetEventHistory(count int) []events.ServiceEvent {\n\tsvcrunner.mu.Lock()\n\tdefer svcrunner.mu.Unlock()\n\n\treturn svcrunner.events.Get(count)\n}\n\nfunc (svcrunner *ServiceRunner) waitFor(ctx context.Context, condition conditions.Condition) error {\n\tdescription := condition.String()\n\tsvcrunner.UpdateState(ctx, events.StateWaiting, \"Waiting for %s\", description)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- condition.Wait(ctx)\n\t}()\n\n\tticker := time.NewTicker(WaitConditionCheckInterval)\n\tdefer ticker.Stop()\n\n\t// update state if condition description changes (some conditions are satisfied)\n\tfor {\n\t\tselect {\n\t\tcase err := <-errCh:\n\t\t\treturn err\n\t\tcase <-ticker.C:\n\t\t\tnewDescription := condition.String()\n\t\t\tif newDescription != description && newDescription != \"\" {\n\t\t\t\tdescription = newDescription\n\t\t\t\tsvcrunner.UpdateState(ctx, events.StateWaiting, \"Waiting for %s\", description)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ErrSkip is returned by Run when service is skipped.\nvar ErrSkip = errors.New(\"service skipped\")\n\ntype volumeRequest struct {\n\tvolumeID  string\n\trequestID string\n\trequester string\n}\n\n// Run initializes the service and runs it.\n//\n// Run returns an error when a service stops.\n//\n// Run should be run in a goroutine.\n//\n//nolint:gocyclo\nfunc (svcrunner *ServiceRunner) Run(notifyChannels ...chan<- struct{}) error {\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tgo func() {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-svcrunner.stopCh:\n\t\t\tcancel()\n\t\t}\n\t}()\n\n\tsvcrunner.UpdateState(ctx, events.StateStarting, \"Starting service\")\n\n\tfor _, notifyCh := range notifyChannels {\n\t\tclose(notifyCh)\n\t}\n\n\tcondition := svcrunner.service.Condition(svcrunner.runtime)\n\n\tif dependencies := svcrunner.service.DependsOn(svcrunner.runtime); len(dependencies) > 0 {\n\t\tserviceConditions := xslices.Map(dependencies, func(dep string) conditions.Condition { return waitForService(instance, StateEventUp, dep) })\n\t\tserviceDependencies := conditions.WaitForAll(serviceConditions...)\n\n\t\tcondition = conditions.WaitForAll(serviceDependencies, condition)\n\t}\n\n\tif volumeIDs := svcrunner.service.Volumes(svcrunner.runtime); len(volumeIDs) > 0 {\n\t\t// create volume mount request for each volume requested\n\t\tvolumeRequests := make([]volumeRequest, 0, len(volumeIDs))\n\n\t\tfor _, volumeID := range volumeIDs {\n\t\t\trequester := \"service/\" + svcrunner.id\n\t\t\trequestID := requester + \"-\" + volumeID\n\n\t\t\tvolumeRequests = append(volumeRequests, volumeRequest{volumeID: volumeID, requestID: requestID, requester: requester})\n\t\t}\n\n\t\tcondition = conditions.WaitForAll(WaitForVolumesToBeMounted(svcrunner.runtime.State().V1Alpha2().Resources(), volumeRequests), condition)\n\n\t\t// cleanup volume mounts\n\t\tdefer func() {\n\t\t\tcleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\t\tdefer cleanupCancel()\n\n\t\t\tif err := svcrunner.deleteVolumeMountRequest(cleanupCtx, volumeRequests); err != nil {\n\t\t\t\tsvcrunner.UpdateState(cleanupCtx, events.StateFailed, \"Failed to clean up volumes: %v\", err)\n\t\t\t}\n\t\t}()\n\t}\n\n\tif condition != nil {\n\t\tif err := svcrunner.waitFor(ctx, condition); err != nil {\n\t\t\treturn fmt.Errorf(\"condition failed: %w\", err)\n\t\t}\n\t}\n\n\tsvcrunner.UpdateState(ctx, events.StatePreparing, \"Running pre state\")\n\n\tif err := svcrunner.service.PreFunc(ctx, svcrunner.runtime); err != nil {\n\t\treturn fmt.Errorf(\"failed to run pre stage: %w\", err)\n\t}\n\n\tsvcrunner.UpdateState(ctx, events.StatePreparing, \"Creating service runner\")\n\n\trunnr, err := svcrunner.service.Runner(svcrunner.runtime)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create runner: %w\", err)\n\t}\n\n\tdefer func() {\n\t\t// PostFunc passes in the state so that we can take actions that depend on the outcome of the run\n\t\tstate := svcrunner.GetState()\n\n\t\tif err := svcrunner.service.PostFunc(svcrunner.runtime, state); err != nil {\n\t\t\tsvcrunner.UpdateState(ctx, events.StateFailed, \"Failed to run post stage: %v\", err)\n\t\t}\n\t}()\n\n\tif runnr == nil {\n\t\treturn ErrSkip\n\t}\n\n\tif err := svcrunner.run(ctx, runnr); err != nil {\n\t\treturn fmt.Errorf(\"failed running service: %w\", err)\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (svcrunner *ServiceRunner) run(ctx context.Context, runnr runner.Runner) error {\n\tif runnr == nil {\n\t\t// special case - run nothing (TODO: we should handle it better, e.g. in PreFunc)\n\t\treturn nil\n\t}\n\n\tif err := runnr.Open(); err != nil {\n\t\treturn fmt.Errorf(\"error opening runner: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer runnr.Close()\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- runnr.Run(func(s events.ServiceState, msg string, args ...any) {\n\t\t\tsvcrunner.UpdateState(ctx, s, msg, args...)\n\n\t\t\tif _, healthSupported := svcrunner.service.(HealthcheckedService); healthSupported && s != events.StateRunning {\n\t\t\t\tsvcrunner.healthState.Update(false, \"service not running\")\n\t\t\t}\n\t\t})\n\t}()\n\n\tif healthSvc, ok := svcrunner.service.(HealthcheckedService); ok {\n\t\tvar healthWg sync.WaitGroup\n\t\tdefer healthWg.Wait()\n\n\t\thealthWg.Go(func() {\n\t\t\t//nolint:errcheck\n\t\t\thealth.Run(\n\t\t\t\tctx,\n\t\t\t\thealthSvc.HealthSettings(svcrunner.runtime),\n\t\t\t\t&svcrunner.healthState,\n\t\t\t\thealthSvc.HealthFunc(svcrunner.runtime),\n\t\t\t)\n\t\t})\n\n\t\tnotifyCh := make(chan health.StateChange, 2)\n\n\t\tsvcrunner.healthState.Subscribe(notifyCh)\n\t\tdefer svcrunner.healthState.Unsubscribe(notifyCh)\n\n\t\thealthWg.Go(func() {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase change := <-notifyCh:\n\t\t\t\t\tsvcrunner.healthUpdate(ctx, change)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\terr := runnr.Stop()\n\n\t\t<-errCh\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error stopping service: %w\", err)\n\t\t}\n\tcase err := <-errCh:\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error running service: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Shutdown initiates shutdown of the service runner\n//\n// Shutdown completes when Start() returns.\nfunc (svcrunner *ServiceRunner) Shutdown() {\n\tselect {\n\tcase svcrunner.stopCh <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// AsProto returns protobuf struct with the state of the service runner.\nfunc (svcrunner *ServiceRunner) AsProto() *machineapi.ServiceInfo {\n\tsvcrunner.mu.Lock()\n\tdefer svcrunner.mu.Unlock()\n\n\treturn &machineapi.ServiceInfo{\n\t\tId:     svcrunner.id,\n\t\tState:  svcrunner.state.String(),\n\t\tEvents: svcrunner.events.AsProto(events.MaxEventsToKeep),\n\t\tHealth: svcrunner.healthState.AsProto(),\n\t}\n}\n\n// Subscribe to a specific event for this service.\n//\n// Channel `ch` should be buffered or it should have listener attached to it,\n// as event might be delivered before Subscribe() returns.\nfunc (svcrunner *ServiceRunner) Subscribe(event StateEvent, ch chan<- struct{}) {\n\tsvcrunner.mu.Lock()\n\n\tif svcrunner.inStateLocked(event) {\n\t\tsvcrunner.mu.Unlock()\n\n\t\t// svcrunner is already in expected state, notify immediately\n\t\tselect {\n\t\tcase ch <- struct{}{}:\n\t\tdefault:\n\t\t}\n\n\t\treturn\n\t}\n\n\tsvcrunner.stateSubscribers[event] = append(svcrunner.stateSubscribers[event], ch)\n\tsvcrunner.mu.Unlock()\n}\n\n// Unsubscribe cancels subscription established with Subscribe.\nfunc (svcrunner *ServiceRunner) Unsubscribe(event StateEvent, ch chan<- struct{}) {\n\tsvcrunner.mu.Lock()\n\tdefer svcrunner.mu.Unlock()\n\n\tchannels := svcrunner.stateSubscribers[event]\n\n\tfor i := 0; i < len(channels); {\n\t\tif channels[i] == ch {\n\t\t\tchannels[i], channels[len(channels)-1] = channels[len(channels)-1], nil\n\t\t\tchannels = channels[:len(channels)-1]\n\t\t} else {\n\t\t\ti++\n\t\t}\n\t}\n\n\tsvcrunner.stateSubscribers[event] = channels\n}\n\nfunc (svcrunner *ServiceRunner) notifyEvent(event StateEvent) {\n\tsvcrunner.mu.Lock()\n\tchannels := slices.Clone(svcrunner.stateSubscribers[event])\n\tsvcrunner.mu.Unlock()\n\n\tfor _, ch := range channels {\n\t\tselect {\n\t\tcase ch <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n}\n\nfunc (svcrunner *ServiceRunner) inStateLocked(event StateEvent) bool {\n\tswitch event {\n\tcase StateEventUp:\n\t\t// up when:\n\t\t//   a) either skipped or already finished\n\t\t//   b) or running and healthy (if supports health checks)\n\t\tswitch svcrunner.state { //nolint:exhaustive\n\t\tcase events.StateSkipped, events.StateFinished:\n\t\t\treturn true\n\t\tcase events.StateRunning:\n\t\t\t// check if service supports health checks\n\t\t\t_, supportsHealth := svcrunner.service.(HealthcheckedService)\n\t\t\thealth := svcrunner.healthState.Get()\n\n\t\t\treturn !supportsHealth || (health.Healthy != nil && *health.Healthy)\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase StateEventDown:\n\t\t// down when in any of the terminal states\n\t\tswitch svcrunner.state { //nolint:exhaustive\n\t\tcase events.StateFailed, events.StateFinished, events.StateSkipped:\n\t\t\treturn true\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\tcase StateEventFinished:\n\t\tif svcrunner.state == events.StateFinished {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\tdefault:\n\t\tpanic(\"unsupported event\")\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/service_runner_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\ntype ServiceRunnerSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *ServiceRunnerSuite) assertStateSequence(expectedStates []events.ServiceState, sr *system.ServiceRunner) {\n\tstates := make([]events.ServiceState, 0, 1000)\n\n\tfor _, event := range sr.GetEventHistory(1000) {\n\t\tstates = append(states, event.State)\n\t}\n\n\tsuite.Assert().Equal(expectedStates, states)\n}\n\nfunc (suite *ServiceRunnerSuite) TestFullFlow() {\n\tsr := system.NewServiceRunner(system.Services(nil), &MockService{\n\t\tcondition: conditions.None(),\n\t}, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateRunning.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be running\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t}, sr)\n\n\tprotoService := sr.AsProto()\n\tsuite.Assert().Equal(\"MockRunner\", protoService.Id)\n\tsuite.Assert().Equal(\"Running\", protoService.State)\n\tsuite.Assert().True(protoService.Health.Unknown)\n\tsuite.Assert().Len(protoService.Events.Events, 5)\n}\n\nfunc (suite *ServiceRunnerSuite) TestFullFlowHealthy() {\n\tsr := system.NewServiceRunner(system.Services(nil), &MockHealthcheckedService{}, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\thealth := sr.AsProto().Health\n\t\tif health.Unknown || !health.Healthy {\n\t\t\treturn retry.ExpectedErrorf(\"service should be healthy\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t\tevents.StateRunning, // one more notification when service is healthy\n\t}, sr)\n}\n\nfunc (suite *ServiceRunnerSuite) TestFullFlowHealthChanges() {\n\tm := MockHealthcheckedService{\n\t\tMockService: MockService{\n\t\t\tcondition: conditions.None(),\n\t\t},\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), &m, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\thealth := sr.AsProto().Health\n\t\tif health.Unknown || !health.Healthy {\n\t\t\treturn retry.ExpectedErrorf(\"service should be healthy\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tm.SetHealthy(false)\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\thealth := sr.AsProto().Health\n\t\tif health.Unknown || health.Healthy {\n\t\t\treturn retry.ExpectedErrorf(\"service should be not healthy\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tm.SetHealthy(true)\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\thealth := sr.AsProto().Health\n\t\tif health.Unknown || !health.Healthy {\n\t\t\treturn retry.ExpectedErrorf(\"service should be healthy\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t\tevents.StateRunning, // initial: healthy\n\t\tevents.StateRunning, // not healthy\n\t\tevents.StateRunning, // once again healthy\n\t}, sr)\n}\n\nfunc (suite *ServiceRunnerSuite) TestWaitingDescriptionChange() {\n\toldWaitConditionCheckInterval := system.WaitConditionCheckInterval\n\tsystem.WaitConditionCheckInterval = 10 * time.Millisecond\n\n\tdefer func() {\n\t\tsystem.WaitConditionCheckInterval = oldWaitConditionCheckInterval\n\t}()\n\n\tcond1 := NewMockCondition(\"cond1\")\n\tcond2 := NewMockCondition(\"cond2\")\n\tsr := system.NewServiceRunner(system.Services(nil), &MockService{\n\t\tcondition: conditions.WaitForAll(cond1, cond2),\n\t}, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateWaiting.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be waiting\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tclose(cond1.done)\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tevents := sr.AsProto().Events.Events\n\n\t\tlastMsg := events[len(events)-1].Msg\n\t\tif lastMsg != \"Waiting for cond2\" {\n\t\t\treturn retry.ExpectedErrorf(\"service should be waiting on 2nd condition\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tclose(cond2.done)\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateRunning.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be running\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t}, sr)\n\n\tevents := sr.GetEventHistory(10000)\n\tsuite.Assert().Equal(\"Waiting for cond1, cond2\", events[1].Message)\n\tsuite.Assert().Equal(\"Waiting for cond2\", events[2].Message)\n}\n\nfunc (suite *ServiceRunnerSuite) TestPreStageFail() {\n\tsvc := &MockService{\n\t\tpreError: errors.New(\"pre failed\"),\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\terr := sr.Run()\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StatePreparing,\n\t}, sr)\n\tsuite.Assert().EqualError(err, \"failed to run pre stage: pre failed\")\n}\n\nfunc (suite *ServiceRunnerSuite) TestRunnerStageFail() {\n\tsvc := &MockService{\n\t\trunnerError: errors.New(\"runner failed\"),\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\terr := sr.Run()\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t}, sr)\n\tsuite.Assert().EqualError(err, \"failed to create runner: runner failed\")\n}\n\nfunc (suite *ServiceRunnerSuite) TestRunnerStageSkipped() {\n\tsvc := &MockService{\n\t\tnilRunner: true,\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\terr := sr.Run()\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t}, sr)\n\tsuite.Assert().ErrorIs(err, system.ErrSkip)\n}\n\nfunc (suite *ServiceRunnerSuite) TestAbortOnCondition() {\n\tsvc := &MockService{\n\t\tcondition: conditions.WaitForFileToExist(\"/doesntexistever\"),\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateWaiting.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be waiting\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tsr.Shutdown()\n\n\tsuite.Assert().EqualError(<-errCh, \"condition failed: context canceled\")\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t}, sr)\n}\n\nfunc (suite *ServiceRunnerSuite) TestPostStateFail() {\n\tsvc := &MockService{\n\t\tcondition: conditions.None(),\n\t\tpostError: errors.New(\"post failed\"),\n\t}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\n\terrCh := make(chan error)\n\trunNotify := make(chan struct{})\n\n\tgo func() {\n\t\terrCh <- sr.Run(runNotify)\n\t}()\n\n\t<-runNotify\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t\tevents.StateFailed,\n\t}, sr)\n}\n\nfunc (suite *ServiceRunnerSuite) TestRunFail() {\n\trunner := &MockRunner{exitCh: make(chan error)}\n\tsvc := &MockService{runner: runner}\n\tsr := system.NewServiceRunner(system.Services(nil), svc, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\trunner.exitCh <- errors.New(\"run failed\")\n\n\tsuite.Assert().EqualError(<-errCh, \"failed running service: error running service: run failed\")\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t}, sr)\n}\n\nfunc (suite *ServiceRunnerSuite) TestFullFlowRestart() {\n\tsr := system.NewServiceRunner(system.Services(nil), &MockService{\n\t\tcondition: conditions.None(),\n\t}, nil)\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- sr.Run()\n\t}()\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateRunning.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be running\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tnotifyCh := make(chan struct{})\n\n\tgo func() {\n\t\terrCh <- sr.Run(notifyCh)\n\t}()\n\n\t<-notifyCh\n\n\tsuite.Require().NoError(retry.Constant(time.Minute, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tstate := sr.AsProto().State\n\t\tif state != events.StateRunning.String() {\n\t\t\treturn retry.ExpectedErrorf(\"service should be running\")\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Require().Fail(\"service running should be still running\")\n\tdefault:\n\t}\n\n\tsr.Shutdown()\n\n\tsuite.Assert().NoError(<-errCh)\n\n\tsuite.assertStateSequence([]events.ServiceState{\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t\tevents.StateStarting,\n\t\tevents.StateWaiting,\n\t\tevents.StatePreparing,\n\t\tevents.StatePreparing,\n\t\tevents.StateRunning,\n\t}, sr)\n}\n\nfunc TestServiceRunnerSuite(t *testing.T) {\n\tsuite.Run(t, new(ServiceRunnerSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/apid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:golint\npackage services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/pkg/cap\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/server\"\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-debug\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nvar _ system.HealthcheckedService = (*APID)(nil)\n\n// APID implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype APID struct {\n\truntimeServer *grpc.Server\n}\n\n// ID implements the Service interface.\nfunc (o *APID) ID(r runtime.Runtime) string {\n\treturn \"apid\"\n}\n\n// apidResourceFilter filters access to COSI state for apid.\n//\n//nolint:gocyclo\nfunc apidResourceFilter(_ context.Context, access state.Access) error {\n\tif !access.Verb.Readonly() {\n\t\treturn errors.New(\"write access denied\")\n\t}\n\n\tswitch {\n\tcase access.ResourceNamespace == runtimeres.NamespaceName && access.ResourceType == runtimeres.APIServiceConfigType && access.ResourceID == runtimeres.APIServiceConfigID:\n\t\t// allowed, contains apid service configuration\n\tcase access.ResourceNamespace == secrets.NamespaceName && access.ResourceType == secrets.APIType && access.ResourceID == secrets.APIID:\n\t\t// allowed, contains apid certificates\n\tcase access.ResourceNamespace == network.NamespaceName && access.ResourceType == network.NodeAddressType:\n\t\t// allowed, contains local node addresses\n\tcase access.ResourceNamespace == network.NamespaceName && access.ResourceType == network.HostnameStatusType:\n\t\t// allowed, contains local node hostname\n\tdefault:\n\t\treturn errors.New(\"access denied\")\n\t}\n\n\treturn nil\n}\n\n// PreFunc implements the Service interface.\nfunc (o *APID) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\t// filter apid access to make sure apid can only access its certificates\n\tresources := state.Filter(r.State().V1Alpha2().Resources(), apidResourceFilter)\n\n\t// ensure socket dir exists\n\tif err := os.MkdirAll(filepath.Dir(constants.APIRuntimeSocketPath), 0o750); err != nil {\n\t\treturn err\n\t}\n\n\t// set the final leaf to be world-executable to make apid connect to the socket\n\tif err := os.Chmod(filepath.Dir(constants.APIRuntimeSocketPath), 0o751); err != nil {\n\t\treturn err\n\t}\n\n\t// clean up the socket if it already exists (important for Talos in a container)\n\tif err := os.RemoveAll(constants.APIRuntimeSocketPath); err != nil {\n\t\treturn err\n\t}\n\n\tlistener, err := (&net.ListenConfig{}).Listen(ctx, \"unix\", constants.APIRuntimeSocketPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := selinux.SetLabel(constants.APIRuntimeSocketPath, constants.APIRuntimeSocketLabel); err != nil {\n\t\treturn err\n\t}\n\n\t// chown the socket path to make it accessible to the apid\n\tif err := os.Chown(constants.APIRuntimeSocketPath, constants.ApidUserID, constants.ApidUserID); err != nil {\n\t\treturn err\n\t}\n\n\to.runtimeServer = grpc.NewServer(\n\t\tgrpc.SharedWriteBuffer(true),\n\t)\n\tv1alpha1.RegisterStateServer(o.runtimeServer, server.NewState(resources))\n\n\tgo o.runtimeServer.Serve(listener) //nolint:errcheck\n\n\treturn prepareRootfs(o.ID(r))\n}\n\n// PostFunc implements the Service interface.\nfunc (o *APID) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\to.runtimeServer.Stop()\n\n\treturn os.RemoveAll(constants.APIRuntimeSocketPath)\n}\n\n// Condition implements the Service interface.\nfunc (o *APID) Condition(r runtime.Runtime) conditions.Condition {\n\treturn conditions.WaitForAll(\n\t\tsecrets.NewAPIReadyCondition(r.State().V1Alpha2().Resources()),\n\t\truntimeres.NewAPIServiceConfigCondition(r.State().V1Alpha2().Resources()),\n\t)\n}\n\n// DependsOn implements the Service interface.\nfunc (o *APID) DependsOn(runtime.Runtime) []string {\n\treturn []string{\"containerd\"}\n}\n\n// Volumes implements the Service interface.\nfunc (o *APID) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\n//\n//nolint:gocyclo\nfunc (o *APID) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := runner.Args{\n\t\tID: o.ID(r),\n\t\tProcessArgs: []string{\n\t\t\t\"/apid\",\n\t\t},\n\t}\n\n\t// Set the mounts.\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: \"/etc/ssl\", Source: \"/etc/ssl\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: filepath.Dir(constants.MachineSocketPath), Source: filepath.Dir(constants.MachineSocketPath), Options: []string{\"rbind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: filepath.Dir(constants.APIRuntimeSocketPath), Source: filepath.Dir(constants.APIRuntimeSocketPath), Options: []string{\"rbind\", \"rw\"}},\n\t}\n\n\tmounts = bindMountContainerMarker(mounts)\n\n\tenv := []string{\n\t\tconstants.EnvTcellMinimizeEnvironment,\n\t\tconstants.EnvGRPCEnforccceALPNEnabled,\n\t\tconstants.EnvApidGomemlimit(),\n\t}\n\n\tfor _, value := range environment.Get(r.Config()) {\n\t\tkey, _, _ := strings.Cut(value, \"=\")\n\n\t\tswitch strings.ToLower(key) {\n\t\t// explicitly exclude proxy variables from apid since this will\n\t\t// negatively impact grpc connections.\n\t\t// ref: https://github.com/grpc/grpc-go/blob/0f32486dd3c9bc29705535bd7e2e43801824cbc4/clientconn.go#L199-L206\n\t\t// ref: https://github.com/grpc/grpc-go/blob/63ae68c9686cc0dd26c4f7476d66bb2f5c31789f/proxy.go#L118-L144\n\t\tcase \"no_proxy\":\n\t\tcase \"http_proxy\":\n\t\tcase \"https_proxy\":\n\t\tdefault:\n\t\t\tenv = append(env, value)\n\t\t}\n\t}\n\n\tif debug.RaceEnabled {\n\t\tenv = append(env, constants.EnvGoraceHaltOnError)\n\t}\n\n\tif fipsmode.Strict() {\n\t\tenv = append(env, constants.EnvFIPS140ModeStrict)\n\t}\n\n\tvar debug bool\n\n\tif r.Config() != nil {\n\t\tdebug = r.Config().Debug()\n\t}\n\n\treturn restart.New(containerd.NewRunner(\n\t\tdebug,\n\t\t&args,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithContainerdAddress(constants.SystemContainerdAddress),\n\t\trunner.WithEnv(env),\n\t\trunner.WithGracefulShutdownTimeout(15*time.Second),\n\t\trunner.WithCgroupPath(constants.CgroupApid),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelApid),\n\t\trunner.WithOCISpecOpts(\n\t\t\toci.WithDroppedCapabilities(cap.Known()),\n\t\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\t\toci.WithMounts(mounts),\n\t\t\toci.WithRootFSPath(filepath.Join(constants.SystemLibexecPath, o.ID(r))),\n\t\t\toci.WithRootFSReadonly(),\n\t\t\toci.WithUser(fmt.Sprintf(\"%d:%d\", constants.ApidUserID, constants.ApidUserID)),\n\t\t),\n\t\trunner.WithOOMScoreAdj(-998),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (o *APID) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tvar d net.Dialer\n\n\t\tconn, err := d.DialContext(ctx, \"tcp\", fmt.Sprintf(\"%s:%d\", \"127.0.0.1\", constants.ApidPort))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn conn.Close()\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (o *APID) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/auditd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/internal/app/auditd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\nconst auditdServiceID = \"auditd\"\n\nvar _ system.HealthcheckedService = (*Auditd)(nil)\n\n// Auditd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Auditd struct{}\n\n// ID implements the Service interface.\nfunc (s *Auditd) ID(runtime.Runtime) string {\n\treturn auditdServiceID\n}\n\n// PreFunc implements the Service interface.\nfunc (s *Auditd) PreFunc(context.Context, runtime.Runtime) error {\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (s *Auditd) PostFunc(runtime.Runtime, events.ServiceState) error {\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (s *Auditd) Condition(runtime.Runtime) conditions.Condition {\n\treturn nil\n}\n\n// DependsOn implements the Service interface.\nfunc (s *Auditd) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Volumes implements the Service interface.\nfunc (s *Auditd) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (s *Auditd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\treturn goroutine.NewRunner(r, auditdServiceID, auditd.Main, runner.WithLoggingManager(r.Logging())), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (s *Auditd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\treturn nil\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (s *Auditd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/containerd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"google.golang.org/grpc/health/grpc_health_v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar _ system.HealthcheckedService = (*Containerd)(nil)\n\n// Containerd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Containerd struct {\n\t// client is a lazy-initialized containerd client. It should be accessed using the Client() method.\n\tclient *containerd.Client\n}\n\n// Client lazy-initializes the containerd client if needed and returns it.\nfunc (c *Containerd) Client() (*containerd.Client, error) {\n\tif c.client != nil {\n\t\treturn c.client, nil\n\t}\n\n\tclient, err := containerd.New(constants.SystemContainerdAddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.client = client\n\n\treturn c.client, err\n}\n\n// ID implements the Service interface.\nfunc (c *Containerd) ID(runtime.Runtime) string {\n\treturn \"containerd\"\n}\n\n// PreFunc implements the Service interface.\nfunc (c *Containerd) PreFunc(context.Context, runtime.Runtime) error {\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (c *Containerd) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\tif c.client != nil {\n\t\treturn c.client.Close()\n\t}\n\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (c *Containerd) Condition(runtime.Runtime) conditions.Condition {\n\treturn nil\n}\n\n// DependsOn implements the Service interface.\nfunc (c *Containerd) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Volumes implements the Service interface.\nfunc (c *Containerd) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (c *Containerd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := &runner.Args{\n\t\tID: c.ID(r),\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\",\n\t\t\tconstants.SystemContainerdAddress,\n\t\t\t\"--state\",\n\t\t\tfilepath.Join(constants.SystemRunPath, \"containerd\"),\n\t\t\t\"--root\",\n\t\t\tfilepath.Join(constants.SystemVarPath, \"lib\", \"containerd\"),\n\t\t},\n\t}\n\n\tdebug := false\n\n\tif r.Config() != nil {\n\t\tdebug = r.Config().Debug()\n\t}\n\n\treturn restart.New(process.NewRunner(\n\t\tdebug,\n\t\targs,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithEnv(append(\n\t\t\tenvironment.Get(r.Config()),\n\t\t\tconstants.EnvXDGRuntimeDir,\n\t\t)),\n\t\trunner.WithOOMScoreAdj(-999),\n\t\trunner.WithCgroupPath(constants.CgroupSystemRuntime),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelSystemRuntime),\n\t\trunner.WithDroppedCapabilities(constants.DefaultDroppedCapabilities),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (c *Containerd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tclient, err := c.Client()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresp, err := client.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif resp.Status != grpc_health_v1.HealthCheckResponse_SERVING {\n\t\t\treturn fmt.Errorf(\"unexpected serving status: %d\", resp.Status)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (c *Containerd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/defaults\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc/health/grpc_health_v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nvar _ system.HealthcheckedService = (*CRI)(nil)\n\n// CRI implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype CRI struct {\n\t// client is a lazy-initialized containerd client. It should be accessed using the Client() method.\n\tclient *containerd.Client\n}\n\n// Client lazy-initializes the containerd client if needed and returns it.\nfunc (c *CRI) Client() (*containerd.Client, error) {\n\tif c.client != nil {\n\t\treturn c.client, nil\n\t}\n\n\tclient, err := containerd.New(constants.CRIContainerdAddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.client = client\n\n\treturn c.client, err\n}\n\n// ID implements the Service interface.\nfunc (c *CRI) ID(runtime.Runtime) string {\n\treturn \"cri\"\n}\n\n// PreFunc implements the Service interface.\nfunc (c *CRI) PreFunc(context.Context, runtime.Runtime) error {\n\treturn os.MkdirAll(defaults.DefaultRootDir, os.ModeDir)\n}\n\n// PostFunc implements the Service interface.\nfunc (c *CRI) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\tif c.client != nil {\n\t\treturn c.client.Close()\n\t}\n\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (c *CRI) Condition(r runtime.Runtime) conditions.Condition {\n\treturn network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady)\n}\n\n// DependsOn implements the Service interface.\nfunc (c *CRI) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Volumes implements the Service interface.\nfunc (c *CRI) Volumes(r runtime.Runtime) []string {\n\tvolumes := []string{\n\t\t\"/var/lib\",\n\t\t\"/var/lib/cni\",\n\t\t\"/var/lib/containerd\",\n\t\t\"/var/run\",\n\t\t\"/var/run/lock\",\n\t}\n\n\tif !r.State().Platform().Mode().InContainer() {\n\t\tvolumes = append(volumes,\n\t\t\txslices.Map(constants.Overlays, func(target constants.SELinuxLabeledPath) string {\n\t\t\t\treturn target.Path\n\t\t\t})...,\n\t\t)\n\t}\n\n\treturn volumes\n}\n\n// Runner implements the Service interface.\nfunc (c *CRI) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := &runner.Args{\n\t\tID: c.ID(r),\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\",\n\t\t\tconstants.CRIContainerdAddress,\n\t\t\t\"--config\",\n\t\t\tconstants.CRIContainerdConfig,\n\t\t},\n\t}\n\n\treturn restart.New(process.NewRunner(\n\t\tr.Config().Debug(),\n\t\targs,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithEnv(append(\n\t\t\tenvironment.Get(r.Config()),\n\t\t\tconstants.EnvXDGRuntimeDir,\n\t\t)),\n\t\trunner.WithOOMScoreAdj(-500),\n\t\trunner.WithCgroupPath(constants.CgroupPodRuntime),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelPodRuntime),\n\t\trunner.WithDroppedCapabilities(constants.DefaultDroppedCapabilities),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (c *CRI) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tclient, err := c.Client()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresp, err := client.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif resp.Status != grpc_health_v1.HealthCheckResponse_SERVING {\n\t\t\treturn fmt.Errorf(\"unexpected serving status: %d\", resp.Status)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (c *CRI) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/dashboard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:golint\npackage services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/console\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Dashboard implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Dashboard struct{}\n\n// getCustomConsole returns the custom console parameter value if specified, empty string otherwise.\nfunc (d *Dashboard) getCustomConsole() string {\n\tconsoleParam := procfs.ProcCmdline().Get(constants.KernelParamDashboardConsole).First()\n\n\treturn pointer.SafeDeref(consoleParam)\n}\n\n// hasCustomConsole checks if a custom console is specified via kernel parameter.\nfunc (d *Dashboard) hasCustomConsole() bool {\n\treturn d.getCustomConsole() != \"\"\n}\n\n// getConsoleDevice returns the console device path to use for the dashboard.\nfunc (d *Dashboard) getConsoleDevice() (string, error) {\n\tconsoleName := d.getCustomConsole()\n\n\tif consoleName != \"\" {\n\t\t// Validate that the console name starts with \"tty\"\n\t\tif !strings.HasPrefix(consoleName, \"tty\") || strings.Contains(consoleName, \"/\") {\n\t\t\treturn \"\", fmt.Errorf(\"invalid console name %q: must start with 'tty'\", consoleName)\n\t\t}\n\n\t\treturn fmt.Sprintf(\"/dev/%s\", consoleName), nil\n\t}\n\n\t// Default to the standard dashboard TTY\n\treturn fmt.Sprintf(\"/dev/tty%d\", constants.DashboardTTY), nil\n}\n\n// ID implements the Service interface.\nfunc (d *Dashboard) ID(_ runtime.Runtime) string {\n\treturn \"dashboard\"\n}\n\n// PreFunc implements the Service interface.\nfunc (d *Dashboard) PreFunc(_ context.Context, _ runtime.Runtime) error {\n\t// Skip TTY switching if a custom console is specified\n\tif d.hasCustomConsole() {\n\t\treturn nil\n\t}\n\n\treturn console.Switch(constants.DashboardTTY)\n}\n\n// PostFunc implements the Service interface.\nfunc (d *Dashboard) PostFunc(_ runtime.Runtime, _ events.ServiceState) error {\n\t// Skip TTY switching if a custom console is specified\n\tif d.hasCustomConsole() {\n\t\treturn nil\n\t}\n\n\treturn console.Switch(constants.KernelLogsTTY)\n}\n\n// Condition implements the Service interface.\nfunc (d *Dashboard) Condition(_ runtime.Runtime) conditions.Condition {\n\treturn conditions.WaitForFileToExist(constants.MachineSocketPath)\n}\n\n// DependsOn implements the Service interface.\nfunc (d *Dashboard) DependsOn(_ runtime.Runtime) []string {\n\treturn []string{machinedServiceID}\n}\n\n// Volumes implements the Service interface.\nfunc (d *Dashboard) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (d *Dashboard) Runner(r runtime.Runtime) (runner.Runner, error) {\n\ttty, err := d.getConsoleDevice()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to determine console device: %w\", err)\n\t}\n\n\treturn restart.New(process.NewRunner(false, &runner.Args{\n\t\tID:          d.ID(r),\n\t\tProcessArgs: []string{\"/sbin/dashboard\"},\n\t},\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithEnv([]string{\n\t\t\tconstants.EnvTerm,\n\t\t\tconstants.EnvTcellMinimizeEnvironment,\n\t\t\tconstants.EnvDashboardGomemlimit(),\n\t\t}),\n\t\trunner.WithStdinFile(tty),\n\t\trunner.WithStdoutFile(tty),\n\t\trunner.WithCtty(0),\n\t\trunner.WithOOMScoreAdj(-400),\n\t\trunner.WithDroppedCapabilities(capability.AllCapabilitiesSetLowercase()),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelDashboard),\n\t\trunner.WithCgroupPath(constants.CgroupDashboard),\n\t\trunner.WithUID(constants.DashboardUserID),\n\t\trunner.WithPriority(constants.DashboardPriority),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/netip\"\n\t\"os\"\n\tgoruntime \"runtime\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/cap\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\tclientv3 \"go.etcd.io/etcd/client/v3\"\n\t\"go.etcd.io/etcd/etcdutl/v3/snapshot\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/console\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/etcd\"\n\t\"github.com/siderolabs/talos/pkg/argsbuilder\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/filetree\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\tetcdresource \"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nvar _ system.HealthcheckedService = (*Etcd)(nil)\n\n// Etcd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Etcd struct {\n\tBootstrap            bool\n\tRecoverFromSnapshot  bool\n\tRecoverSkipHashCheck bool\n\n\targs   []string\n\tclient *etcd.Client\n\n\timgRef string\n\n\t// if the new member was added as a learner during the service start, its ID is kept here\n\tlearnerMemberID uint64\n\n\tpromoteCtxCancel context.CancelFunc\n}\n\n// ID implements the Service interface.\nfunc (e *Etcd) ID(runtime.Runtime) string {\n\treturn \"etcd\"\n}\n\n// PreFunc implements the Service interface.\n//\n//nolint:gocyclo\nfunc (e *Etcd) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\tclient, err := containerdapi.New(constants.CRIContainerdAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\t// Pull the image and unpack it.\n\tcontainerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)\n\n\tspec, err := safe.ReaderGet[*etcdresource.Spec](ctx, r.State().V1Alpha2().Resources(), etcdresource.NewSpec(etcdresource.NamespaceName, etcdresource.SpecID).Metadata())\n\tif err != nil {\n\t\t// spec should be ready\n\t\treturn fmt.Errorf(\"failed to get etcd spec: %w\", err)\n\t}\n\n\timg, err := image.Pull(containerdctx,\n\t\tcri.RegistryBuilder(r.State().V1Alpha2().Resources()),\n\t\tr.State().V1Alpha2().Resources(),\n\t\tclient, spec.TypedSpec().Image,\n\t\timage.WithSkipIfAlreadyPulled(),\n\t\timage.WithProgressReporter(console.NewProgressReporter),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to pull image %q: %w\", spec.TypedSpec().Image, err)\n\t}\n\n\te.imgRef = img.Target().Digest.String()\n\n\t// Clear any previously set learner member ID\n\te.learnerMemberID = 0\n\n\tswitch t := r.Config().Machine().Type(); t {\n\tcase machine.TypeInit:\n\t\tif err = e.argsForInit(ctx, r, spec.TypedSpec()); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase machine.TypeControlPlane:\n\t\tif err = e.argsForControlPlane(ctx, r, spec.TypedSpec()); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase machine.TypeWorker:\n\t\treturn fmt.Errorf(\"unexpected machine type: %v\", t)\n\tcase machine.TypeUnknown:\n\t\tfallthrough\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected machine type %v\", t))\n\t}\n\n\tif err = waitPKI(ctx, r); err != nil {\n\t\treturn fmt.Errorf(\"failed to generate etcd PKI: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (e *Etcd) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\tif e.promoteCtxCancel != nil {\n\t\te.promoteCtxCancel()\n\t}\n\n\tif e.client != nil {\n\t\te.client.Close() //nolint:errcheck\n\t}\n\n\te.client = nil\n\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (e *Etcd) Condition(r runtime.Runtime) conditions.Condition {\n\treturn conditions.WaitForAll(\n\t\ttimeresource.NewSyncCondition(r.State().V1Alpha2().Resources()),\n\t\tnetwork.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady),\n\t\tetcdresource.NewSpecReadyCondition(r.State().V1Alpha2().Resources()),\n\t)\n}\n\n// DependsOn implements the Service interface.\nfunc (e *Etcd) DependsOn(runtime.Runtime) []string {\n\treturn []string{\"cri\"}\n}\n\n// Volumes implements the Service interface.\nfunc (e *Etcd) Volumes(runtime.Runtime) []string {\n\treturn []string{\n\t\t\"/var/lib\",\n\t\tconstants.EtcdDataVolumeID,\n\t}\n}\n\n// Runner implements the Service interface.\nfunc (e *Etcd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := runner.Args{\n\t\tID:          e.ID(r),\n\t\tProcessArgs: append([]string{\"/usr/local/bin/etcd\"}, e.args...),\n\t}\n\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: constants.EtcdPKIPath, Source: constants.EtcdPKIPath, Options: []string{\"rbind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: constants.EtcdDataPath, Source: constants.EtcdDataPath, Options: []string{\"rbind\", \"rw\"}},\n\t}\n\n\tenv := environment.Get(r.Config())\n\n\t// NOTE: leave it here for future unsupported architectures, so we can know where to add them\n\tif slices.Contains([]string{}, goruntime.GOARCH) {\n\t\tenv = append(env, \"ETCD_UNSUPPORTED_ARCH=\"+goruntime.GOARCH)\n\t}\n\n\tenv = append(env, \"ETCD_CIPHER_SUITES=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305\") //nolint:lll\n\n\tif e.learnerMemberID != 0 {\n\t\tvar promoteCtx context.Context\n\n\t\tpromoteCtx, e.promoteCtxCancel = context.WithCancel(context.Background())\n\n\t\tgo func() {\n\t\t\tif err := promoteMember(promoteCtx, r, e.learnerMemberID); err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\tlog.Printf(\"failed promoting member: %s\", err)\n\t\t\t} else if err == nil {\n\t\t\t\tlog.Printf(\"successfully promoted etcd member\")\n\t\t\t}\n\t\t}()\n\t}\n\n\treturn restart.New(containerd.NewRunner(\n\t\tr.Config().Debug(),\n\t\t&args,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithNamespace(constants.SystemContainerdNamespace),\n\t\trunner.WithContainerImage(e.imgRef),\n\t\trunner.WithEnv(env),\n\t\trunner.WithCgroupPath(constants.CgroupEtcd),\n\t\trunner.WithSelinuxLabel(constants.SELinuxLabelEtcd),\n\t\trunner.WithOCISpecOpts(\n\t\t\toci.WithDroppedCapabilities(cap.Known()),\n\t\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\t\toci.WithMounts(mounts),\n\t\t\toci.WithUser(fmt.Sprintf(\"%d:%d\", constants.EtcdUserID, constants.EtcdUserID)),\n\t\t),\n\t\trunner.WithOOMScoreAdj(-998),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (e *Etcd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tif e.client == nil {\n\t\t\tvar err error\n\n\t\t\te.client, err = etcd.NewLocalClient(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn e.client.ValidateQuorum(ctx)\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (e *Etcd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.Settings{\n\t\tInitialDelay: 5 * time.Second,\n\t\tPeriod:       20 * time.Second,\n\t\tTimeout:      15 * time.Second,\n\t}\n}\n\nfunc waitPKI(ctx context.Context, r runtime.Runtime) error {\n\t_, err := r.State().V1Alpha2().Resources().WatchFor(ctx,\n\t\tresource.NewMetadata(etcdresource.NamespaceName, etcdresource.PKIStatusType, etcdresource.PKIID, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\n\treturn err\n}\n\nfunc addMember(ctx context.Context, r runtime.Runtime, addrs []string, name string) (*clientv3.MemberListResponse, uint64, error) {\n\tclient, err := etcd.NewClientFromControlPlaneIPs(ctx, r.State().V1Alpha2().Resources())\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\tctx = clientv3.WithRequireLeader(ctx)\n\n\tlist, err := client.MemberList(ctx)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"error getting etcd member list: %w\", err)\n\t}\n\n\tfor _, member := range list.Members {\n\t\t// addMember only gets called when the etcd data directory is empty, so the node is about to join the etcd cluster\n\t\t// if there's already a member with same hostname, it should be removed, as there will be a conflict between the existing\n\t\t// member and a new joining member.\n\t\t// here we assume that control plane nodes have unique hostnames (if that's not the case, it will be a problem anyways)\n\t\tif member.Name == name {\n\t\t\tif _, err = client.MemberRemove(ctx, member.ID); err != nil {\n\t\t\t\treturn nil, 0, fmt.Errorf(\"error removing self from the member list: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tadd, err := client.MemberAddAsLearner(ctx, addrs)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"error adding member: %w\", err)\n\t}\n\n\tlist, err = client.MemberList(ctx)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"error getting second etcd member list: %w\", err)\n\t}\n\n\treturn list, add.Member.ID, nil\n}\n\nfunc buildInitialCluster(ctx context.Context, r runtime.Runtime, name string, peerAddrs []string) (initial string, learnerMemberID uint64, err error) {\n\tvar (\n\t\tid      uint64\n\t\tlastNag time.Time\n\t)\n\n\terr = retry.Constant(constants.EtcdJoinTimeout,\n\t\tretry.WithUnits(3*time.Second),\n\t\tretry.WithJitter(time.Second),\n\t\tretry.WithErrorLogging(true),\n\t).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tvar resp *clientv3.MemberListResponse\n\n\t\tif time.Since(lastNag) > 30*time.Second {\n\t\t\tlastNag = time.Now()\n\n\t\t\tlog.Printf(\"etcd is waiting to join the cluster, if this node is the first node in the cluster, please run `talosctl bootstrap` against one of the following IPs:\")\n\n\t\t\t// we \"allow\" a failure here since we want to fallthrough and attempt to add the etcd member regardless of\n\t\t\t// whether we can print our IPs\n\t\t\tcurrentAddresses, addrErr := safe.ReaderGet[*network.NodeAddress](\n\t\t\t\tctx,\n\t\t\t\tr.State().V1Alpha2().Resources(),\n\t\t\t\tresource.NewMetadata(network.NamespaceName, network.NodeAddressType, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s), resource.VersionUndefined),\n\t\t\t)\n\t\t\tif addrErr != nil {\n\t\t\t\tlog.Printf(\"error getting node addresses: %s\", addrErr.Error())\n\t\t\t} else {\n\t\t\t\tips := currentAddresses.TypedSpec().IPs()\n\t\t\t\tlog.Printf(\"%s\", ips)\n\t\t\t}\n\t\t}\n\n\t\tattemptCtx, attemptCtxCancel := context.WithTimeout(ctx, 30*time.Second)\n\t\tdefer attemptCtxCancel()\n\n\t\tresp, id, err = addMember(attemptCtx, r, peerAddrs, name)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, context.Canceled) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// TODO(andrewrynhard): We should check the error type here and\n\t\t\t// handle the specific error accordingly.\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tvar conf []string\n\n\t\tfor _, memb := range resp.Members {\n\t\t\tfor _, u := range memb.PeerURLs {\n\t\t\t\tn := memb.Name\n\t\t\t\tif memb.ID == id {\n\t\t\t\t\tn = name\n\t\t\t\t}\n\n\t\t\t\tconf = append(conf, fmt.Sprintf(\"%s=%s\", n, u))\n\t\t\t}\n\t\t}\n\n\t\tinitial = strings.Join(conf, \",\")\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn \"\", 0, fmt.Errorf(\"failed to build cluster arguments: %w\", err)\n\t}\n\n\treturn initial, id, nil\n}\n\n//nolint:gocyclo\nfunc (e *Etcd) argsForInit(ctx context.Context, r runtime.Runtime, spec *etcdresource.SpecSpec) error {\n\tvar upgraded bool\n\n\t_, upgraded = r.State().Machine().Meta().ReadTag(meta.Upgrade)\n\n\tdenyListArgs := argsbuilder.Args{\n\t\t\"name\":                               {spec.Name},\n\t\t\"auto-tls\":                           {\"false\"},\n\t\t\"peer-auto-tls\":                      {\"false\"},\n\t\t\"data-dir\":                           {constants.EtcdDataPath},\n\t\t\"listen-peer-urls\":                   {formatEtcdURLs(spec.ListenPeerAddresses, constants.EtcdPeerPort)},\n\t\t\"listen-client-urls\":                 {formatEtcdURLs(spec.ListenClientAddresses, constants.EtcdClientPort)},\n\t\t\"client-cert-auth\":                   {\"true\"},\n\t\t\"cert-file\":                          {constants.EtcdCert},\n\t\t\"key-file\":                           {constants.EtcdKey},\n\t\t\"trusted-ca-file\":                    {constants.EtcdCACert},\n\t\t\"peer-client-cert-auth\":              {\"true\"},\n\t\t\"peer-cert-file\":                     {constants.EtcdPeerCert},\n\t\t\"peer-key-file\":                      {constants.EtcdPeerKey},\n\t\t\"peer-trusted-ca-file\":               {constants.EtcdCACert},\n\t\t\"experimental-initial-corrupt-check\": {\"true\"},\n\t\t\"experimental-watch-progress-notify-interval\": {\"5s\"},\n\t\t\"experimental-compact-hash-check-enabled\":     {\"true\"},\n\t}\n\n\textraArgs := make(argsbuilder.Args, len(spec.ExtraArgs))\n\tfor k, v := range spec.ExtraArgs {\n\t\textraArgs[k] = v.Values\n\t}\n\n\tdenyList := argsbuilder.WithDenyList(denyListArgs)\n\n\tif !extraArgs.Contains(\"initial-cluster-state\") {\n\t\tdenyListArgs.Set(\"initial-cluster-state\", argsbuilder.Value{\"new\"})\n\t}\n\n\t// If the initial cluster isn't explicitly defined, we need to discover any\n\t// existing members.\n\tif !extraArgs.Contains(\"initial-cluster\") {\n\t\tok, err := IsDirEmpty(constants.EtcdDataPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif ok {\n\t\t\tinitialCluster := formatClusterURLs(spec.Name, getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort))\n\n\t\t\tif upgraded {\n\t\t\t\tdenyListArgs.Set(\"initial-cluster-state\", argsbuilder.Value{\"existing\"})\n\n\t\t\t\tinitialCluster, e.learnerMemberID, err = buildInitialCluster(ctx, r, spec.Name, getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdenyListArgs.Set(\"initial-cluster\", argsbuilder.Value{initialCluster})\n\t\t} else {\n\t\t\tdenyListArgs.Set(\"initial-cluster-state\", argsbuilder.Value{\"existing\"})\n\t\t}\n\t}\n\n\tif !extraArgs.Contains(\"initial-advertise-peer-urls\") {\n\t\tdenyListArgs.Set(\"initial-advertise-peer-urls\",\n\t\t\targsbuilder.Value{formatEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort)},\n\t\t)\n\t}\n\n\tif !extraArgs.Contains(\"advertise-client-urls\") {\n\t\tdenyListArgs.Set(\"advertise-client-urls\",\n\t\t\targsbuilder.Value{formatEtcdURLs(spec.AdvertisedAddresses, constants.EtcdClientPort)},\n\t\t)\n\t}\n\n\tif err := denyListArgs.Merge(extraArgs, denyList); err != nil {\n\t\treturn err\n\t}\n\n\te.args = denyListArgs.Args()\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (e *Etcd) argsForControlPlane(ctx context.Context, r runtime.Runtime, spec *etcdresource.SpecSpec) error {\n\tdenyListArgs := argsbuilder.Args{\n\t\t\"name\":                               {spec.Name},\n\t\t\"auto-tls\":                           {\"false\"},\n\t\t\"peer-auto-tls\":                      {\"false\"},\n\t\t\"data-dir\":                           {constants.EtcdDataPath},\n\t\t\"listen-peer-urls\":                   {formatEtcdURLs(spec.ListenPeerAddresses, constants.EtcdPeerPort)},\n\t\t\"listen-client-urls\":                 {formatEtcdURLs(spec.ListenClientAddresses, constants.EtcdClientPort)},\n\t\t\"client-cert-auth\":                   {\"true\"},\n\t\t\"cert-file\":                          {constants.EtcdCert},\n\t\t\"key-file\":                           {constants.EtcdKey},\n\t\t\"trusted-ca-file\":                    {constants.EtcdCACert},\n\t\t\"peer-client-cert-auth\":              {\"true\"},\n\t\t\"peer-cert-file\":                     {constants.EtcdPeerCert},\n\t\t\"peer-key-file\":                      {constants.EtcdPeerKey},\n\t\t\"peer-trusted-ca-file\":               {constants.EtcdCACert},\n\t\t\"experimental-initial-corrupt-check\": {\"true\"},\n\t\t\"experimental-watch-progress-notify-interval\": {\"5s\"},\n\t\t\"experimental-compact-hash-check-enabled\":     {\"true\"},\n\t}\n\n\textraArgs := make(argsbuilder.Args, len(spec.ExtraArgs))\n\tfor k, v := range spec.ExtraArgs {\n\t\textraArgs[k] = v.Values\n\t}\n\n\tdenyList := argsbuilder.WithDenyList(denyListArgs)\n\n\tif e.RecoverFromSnapshot {\n\t\tif err := e.recoverFromSnapshot(spec); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tok, err := IsDirEmpty(constants.EtcdDataPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// The only time that we need to build the initial cluster args, is when we\n\t// don't have any data.\n\tif ok {\n\t\tif !extraArgs.Contains(\"initial-cluster-state\") {\n\t\t\tif e.Bootstrap {\n\t\t\t\tdenyListArgs.Set(\"initial-cluster-state\", argsbuilder.Value{\"new\"})\n\t\t\t} else {\n\t\t\t\tdenyListArgs.Set(\"initial-cluster-state\", argsbuilder.Value{\"existing\"})\n\t\t\t}\n\t\t}\n\n\t\tif !extraArgs.Contains(\"initial-cluster\") {\n\t\t\tvar initialCluster string\n\n\t\t\tif e.Bootstrap {\n\t\t\t\tinitialCluster = formatClusterURLs(spec.Name, getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort))\n\t\t\t} else {\n\t\t\t\tinitialCluster, e.learnerMemberID, err = buildInitialCluster(ctx, r, spec.Name, getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to build initial etcd cluster: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdenyListArgs.Set(\"initial-cluster\", argsbuilder.Value{initialCluster})\n\t\t}\n\t}\n\n\tif !extraArgs.Contains(\"advertise-client-urls\") {\n\t\tdenyListArgs.Set(\"advertise-client-urls\",\n\t\t\targsbuilder.Value{formatEtcdURLs(spec.AdvertisedAddresses, constants.EtcdClientPort)},\n\t\t)\n\t}\n\n\tif !extraArgs.Contains(\"initial-advertise-peer-urls\") {\n\t\tdenyListArgs.Set(\"initial-advertise-peer-urls\",\n\t\t\targsbuilder.Value{formatEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort)},\n\t\t)\n\t}\n\n\tif err = denyListArgs.Merge(extraArgs, denyList); err != nil {\n\t\treturn err\n\t}\n\n\te.args = denyListArgs.Args()\n\n\treturn nil\n}\n\n// recoverFromSnapshot recovers etcd data directory from the snapshot uploaded previously.\nfunc (e *Etcd) recoverFromSnapshot(spec *etcdresource.SpecSpec) error {\n\tmanager := snapshot.NewV3(logging.Wrap(log.Writer()))\n\n\tstatus, err := manager.Status(constants.EtcdRecoverySnapshotPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error verifying snapshot: %w\", err)\n\t}\n\n\tlog.Printf(\"recovering etcd from snapshot: hash %08x, revision %d, total keys %d, total size %d\\n\",\n\t\tstatus.Hash, status.Revision, status.TotalKey, status.TotalSize)\n\n\tif err = manager.Restore(snapshot.RestoreConfig{\n\t\tSnapshotPath: constants.EtcdRecoverySnapshotPath,\n\n\t\tName:          spec.Name,\n\t\tOutputDataDir: constants.EtcdDataPath,\n\n\t\tPeerURLs: getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort),\n\n\t\tInitialCluster: formatClusterURLs(spec.Name, getEtcdURLs(spec.AdvertisedAddresses, constants.EtcdPeerPort)),\n\n\t\tSkipHashCheck: e.RecoverSkipHashCheck,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error recovering from the snapshot: %w\", err)\n\t}\n\n\tif err = os.Remove(constants.EtcdRecoverySnapshotPath); err != nil {\n\t\treturn fmt.Errorf(\"error deleting snapshot: %w\", err)\n\t}\n\n\treturn filetree.ChownRecursive(constants.EtcdDataPath, constants.EtcdUserID, constants.EtcdUserID)\n}\n\nfunc promoteMember(ctx context.Context, r runtime.Runtime, memberID uint64) error {\n\t// try to promote a member until it succeeds (call might fail until the member catches up with the leader)\n\t// promote member call will fail until member catches up with the master\n\t//\n\t// iterate over all endpoints until we find the one which works\n\t// if we stick with the default behavior, we might hit the member being promoted, and that will never\n\t// promote itself.\n\tidx := 0\n\n\treturn retry.Constant(10*time.Minute,\n\t\tretry.WithUnits(15*time.Second),\n\t\tretry.WithAttemptTimeout(30*time.Second),\n\t\tretry.WithJitter(time.Second),\n\t\tretry.WithErrorLogging(true),\n\t).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tendpoints, err := etcd.GetEndpoints(ctx, r.State().V1Alpha2().Resources())\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif len(endpoints) == 0 {\n\t\t\treturn retry.ExpectedErrorf(\"no endpoints\")\n\t\t}\n\n\t\t// try to iterate all available endpoints in the time available for an attempt\n\t\tfor range endpoints {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn retry.ExpectedError(ctx.Err())\n\t\t\tdefault:\n\t\t\t}\n\n\t\t\tendpoint := endpoints[idx%len(endpoints)]\n\t\t\tidx++\n\n\t\t\terr = attemptPromote(ctx, endpoint, memberID)\n\t\t\tif err == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treturn retry.ExpectedError(err)\n\t})\n}\n\nfunc attemptPromote(ctx context.Context, endpoint string, memberID uint64) error {\n\tclient, err := etcd.NewClient(ctx, []string{endpoint})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\t_, err = client.MemberPromote(ctx, memberID)\n\n\treturn err\n}\n\n// IsDirEmpty checks if a directory is empty or not.\nfunc IsDirEmpty(name string) (bool, error) {\n\tf, err := os.Open(name)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\t//nolint:errcheck\n\tdefer f.Close()\n\n\t_, err = f.Readdirnames(1)\n\tif err == io.EOF {\n\t\treturn true, nil\n\t}\n\n\treturn false, err\n}\n\n// BootstrapEtcd bootstraps the etcd cluster.\n//\n// Current instance of etcd (not joined yet) is stopped, and new instance is started in bootstrap mode.\nfunc BootstrapEtcd(ctx context.Context, r runtime.Runtime, req *machineapi.BootstrapRequest) error {\n\tif err := system.Services(r).Stop(ctx, \"etcd\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to stop etcd: %w\", err)\n\t}\n\n\t// This is hack. We need to fake a finished state so that we can get the\n\t// wait in the boot sequence to unblock.\n\tfor _, svc := range system.Services(r).List() {\n\t\tif svc.AsProto().GetId() == \"etcd\" {\n\t\t\tsvc.UpdateState(ctx, events.StateFinished, \"Bootstrap requested\")\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif entries, _ := os.ReadDir(constants.EtcdDataPath); len(entries) > 0 { //nolint:errcheck\n\t\treturn errors.New(\"etcd data directory is not empty\")\n\t}\n\n\tsvc := &Etcd{\n\t\tBootstrap:            true,\n\t\tRecoverFromSnapshot:  req.RecoverEtcd,\n\t\tRecoverSkipHashCheck: req.RecoverSkipHashCheck,\n\t}\n\n\tif err := system.Services(r).Unload(ctx, svc.ID(r)); err != nil {\n\t\treturn err\n\t}\n\n\tsystem.Services(r).Load(svc)\n\n\tif err := system.Services(r).Start(svc.ID(r)); err != nil {\n\t\treturn fmt.Errorf(\"error starting etcd in bootstrap mode: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc formatEtcdURL(addr netip.Addr, port int) string {\n\treturn fmt.Sprintf(\"https://%s\", nethelpers.JoinHostPort(addr.String(), port))\n}\n\nfunc getEtcdURLs(addrs []netip.Addr, port int) []string {\n\treturn xslices.Map(addrs, func(addr netip.Addr) string {\n\t\treturn formatEtcdURL(addr, port)\n\t})\n}\n\nfunc formatEtcdURLs(addrs []netip.Addr, port int) string {\n\treturn strings.Join(getEtcdURLs(addrs, port), \",\")\n}\n\nfunc formatClusterURLs(name string, urls []string) string {\n\treturn strings.Join(xslices.Map(urls, func(url string) string {\n\t\treturn fmt.Sprintf(\"%s=%s\", name, url)\n\t}), \",\")\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport \"github.com/containerd/containerd/v2/pkg/oci\"\n\n// GetOCIOptions gets all OCI options from an Extension.\nfunc (svc *Extension) GetOCIOptions() ([]oci.SpecOpts, error) {\n\tenvVars, err := svc.parseEnvironment()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn svc.getOCIOptions(envVars, svc.Spec.Container.Mounts), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/extension.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-envparse\"\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/gen/maps\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\textservices \"github.com/siderolabs/talos/pkg/machinery/extensions/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\n// Extension service is a generic wrapper around extension services spec.\ntype Extension struct {\n\tSpec extservices.Spec\n\n\toverlayUnmounter func() error\n}\n\n// ID implements the Service interface.\nfunc (svc *Extension) ID(r runtime.Runtime) string {\n\treturn \"ext-\" + svc.Spec.Name\n}\n\n// PreFunc implements the Service interface.\nfunc (svc *Extension) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\t// re-mount service rootfs as overlay rw mount to allow containerd to mount there /dev, /proc, etc.\n\trootfsPath := filepath.Join(constants.ExtensionServiceRootfsPath, svc.Spec.Name)\n\n\t// TODO: label system extensions\n\toverlay := mount.NewSystemOverlay(\n\t\t[]string{rootfsPath},\n\t\trootfsPath,\n\t\tnil,\n\t)\n\n\tif _, err := overlay.Mount(); err != nil {\n\t\treturn err\n\t}\n\n\tsvc.overlayUnmounter = overlay.Unmount\n\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (svc *Extension) PostFunc(r runtime.Runtime, state events.ServiceState) (err error) {\n\treturn svc.overlayUnmounter()\n}\n\n// Condition implements the Service interface.\nfunc (svc *Extension) Condition(r runtime.Runtime) conditions.Condition {\n\tvar conds []conditions.Condition\n\n\tif svc.Spec.Container.EnvironmentFile != \"\" {\n\t\t// add a dependency on the environment file\n\t\tconds = append(conds, conditions.WaitForFileToExist(svc.Spec.Container.EnvironmentFile))\n\t}\n\n\tfor _, dep := range svc.Spec.Depends {\n\t\tswitch {\n\t\tcase dep.Path != \"\":\n\t\t\tconds = append(conds, conditions.WaitForFileToExist(dep.Path))\n\t\tcase len(dep.Network) > 0:\n\t\t\tconds = append(conds, network.NewReadyCondition(r.State().V1Alpha2().Resources(), network.StatusChecksFromStatuses(dep.Network...)...))\n\t\tcase dep.Time:\n\t\t\tconds = append(conds, time.NewSyncCondition(r.State().V1Alpha2().Resources()))\n\t\tcase dep.Configuration:\n\t\t\tconds = append(conds, runtimeres.NewExtensionServiceConfigStatusCondition(r.State().V1Alpha2().Resources(), svc.Spec.Name))\n\t\t}\n\t}\n\n\tif len(conds) == 0 {\n\t\treturn nil\n\t}\n\n\treturn conditions.WaitForAll(conds...)\n}\n\n// DependsOn implements the Service interface.\nfunc (svc *Extension) DependsOn(r runtime.Runtime) []string {\n\tdeps := []string{\"containerd\"}\n\n\tfor _, dep := range svc.Spec.Depends {\n\t\tif dep.Service != \"\" {\n\t\t\tdeps = append(deps, dep.Service)\n\t\t}\n\t}\n\n\treturn deps\n}\n\n// Volumes implements the Service interface.\nfunc (svc *Extension) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\nfunc (svc *Extension) getOCIOptions(envVars []string, mounts []specs.Mount) []oci.SpecOpts {\n\tociOpts := []oci.SpecOpts{\n\t\toci.WithRootFSPath(filepath.Join(constants.ExtensionServiceRootfsPath, svc.Spec.Name)),\n\t\tcontainerd.WithRootfsPropagation(svc.Spec.Container.Security.RootfsPropagation),\n\t\toci.WithMounts(mounts),\n\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\toci.WithSelinuxLabel(\"\"),\n\t\toci.WithApparmorProfile(\"\"),\n\t\toci.WithCapabilities(capability.AllGrantableCapabilities()),\n\t\toci.WithAllDevicesAllowed,\n\t\toci.WithEnv(envVars),\n\t}\n\n\tif !svc.Spec.Container.Security.WriteableRootfs {\n\t\tociOpts = append(ociOpts, oci.WithRootFSReadonly())\n\t}\n\n\tif svc.Spec.Container.Security.WriteableSysfs {\n\t\tociOpts = append(ociOpts, oci.WithWriteableSysfs)\n\t}\n\n\tif svc.Spec.Container.Security.MaskedPaths != nil {\n\t\tociOpts = append(ociOpts, oci.WithMaskedPaths(svc.Spec.Container.Security.MaskedPaths))\n\t}\n\n\tif svc.Spec.Container.Security.ReadonlyPaths != nil {\n\t\tociOpts = append(ociOpts, oci.WithReadonlyPaths(svc.Spec.Container.Security.ReadonlyPaths))\n\t}\n\n\treturn ociOpts\n}\n\n// Runner implements the Service interface.\n//\n//nolint:gocyclo\nfunc (svc *Extension) Runner(r runtime.Runtime) (runner.Runner, error) {\n\targs := runner.Args{\n\t\tID:          svc.ID(r),\n\t\tProcessArgs: append([]string{svc.Spec.Container.Entrypoint}, svc.Spec.Container.Args...),\n\t}\n\n\tfor _, mount := range svc.Spec.Container.Mounts {\n\t\tif _, err := os.Stat(mount.Source); err == nil {\n\t\t\t// already exists, skip\n\t\t\tcontinue\n\t\t} else if !errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := os.MkdirAll(mount.Source, 0o700); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tmounts := append([]specs.Mount{}, svc.Spec.Container.Mounts...)\n\n\tmounts = bindMountContainerMarker(mounts)\n\n\tenvVars, err := svc.parseEnvironment()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfigSpec, err := safe.StateGetByID[*runtimeres.ExtensionServiceConfig](context.Background(), r.State().V1Alpha2().Resources(), svc.Spec.Name)\n\tif err == nil {\n\t\tspec := configSpec.TypedSpec()\n\n\t\tfor _, ext := range spec.Files {\n\t\t\tmounts = append(mounts, specs.Mount{\n\t\t\t\tSource:      filepath.Join(constants.ExtensionServiceUserConfigPath, svc.Spec.Name, strings.ReplaceAll(strings.TrimPrefix(ext.MountPath, \"/\"), \"/\", \"-\")),\n\t\t\t\tDestination: ext.MountPath,\n\t\t\t\tType:        \"bind\",\n\t\t\t\tOptions:     []string{\"ro\", \"bind\"},\n\t\t\t})\n\t\t}\n\n\t\tenvVars = append(envVars, spec.Environment...)\n\t} else if !state.IsNotFoundError(err) {\n\t\treturn nil, err\n\t}\n\n\tvar restartType restart.Type\n\n\tswitch svc.Spec.Restart {\n\tcase extservices.RestartAlways:\n\t\trestartType = restart.Forever\n\tcase extservices.RestartNever:\n\t\trestartType = restart.Once\n\tcase extservices.RestartUntilSuccess:\n\t\trestartType = restart.UntilSuccess\n\t}\n\n\tociSpecOpts := svc.getOCIOptions(envVars, mounts)\n\n\tlogToConsole := false\n\n\tif r.Config() != nil {\n\t\tlogToConsole = r.Config().Debug()\n\t}\n\n\tif svc.Spec.LogToConsole {\n\t\tlogToConsole = true\n\t}\n\n\treturn restart.New(containerd.NewRunner(\n\t\tlogToConsole,\n\t\t&args,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithNamespace(constants.SystemContainerdNamespace),\n\t\trunner.WithContainerdAddress(constants.SystemContainerdAddress),\n\t\trunner.WithEnv(environment.Get(r.Config())),\n\t\trunner.WithOCISpecOpts(ociSpecOpts...),\n\t\trunner.WithCgroupPath(filepath.Join(constants.CgroupExtensions, svc.Spec.Name)),\n\t\trunner.WithOOMScoreAdj(-600),\n\t),\n\t\trestart.WithType(restartType),\n\t), nil\n}\n\n// APIRestartAllowed implements APIRestartableService.\nfunc (svc *Extension) APIRestartAllowed(runtime.Runtime) bool {\n\treturn true\n}\n\n// APIStartAllowed implements APIStartableService.\nfunc (svc *Extension) APIStartAllowed(runtime.Runtime) bool {\n\treturn true\n}\n\n// APIStopAllowed implements APIStoppableService.\nfunc (svc *Extension) APIStopAllowed(runtime.Runtime) bool {\n\treturn true\n}\n\nfunc (svc *Extension) parseEnvironment() ([]string, error) {\n\tvar envVars []string\n\n\tif svc.Spec.Container.EnvironmentFile != \"\" {\n\t\tenvFile, err := os.OpenFile(svc.Spec.Container.EnvironmentFile, os.O_RDONLY, 0)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif closeErr := envFile.Close(); err != nil {\n\t\t\t\terr = closeErr\n\t\t\t}\n\t\t}()\n\n\t\tparsedEnvVars, err := envparse.Parse(envFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse environment file %q: %w\", svc.Spec.Container.EnvironmentFile, err)\n\t\t}\n\n\t\tenvVarsSlice := maps.ToSlice(parsedEnvVars, func(k, v string) string {\n\t\t\treturn fmt.Sprintf(\"%s=%s\", k, v)\n\t\t})\n\n\t\tenvVars = append(envVars, envVarsSlice...)\n\t}\n\n\tif svc.Spec.Container.Environment != nil {\n\t\tenvVars = append(envVars, svc.Spec.Container.Environment...)\n\t}\n\n\treturn envVars, nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/extension_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/containerd/containerd/v2/core/containers\"\n\t\"github.com/containerd/containerd/v2/core/snapshots\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/golang/mock/gomock\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services/mocks\"\n\textservices \"github.com/siderolabs/talos/pkg/machinery/extensions/services\"\n)\n\ntype MockClient struct {\n\tcontroller *gomock.Controller\n}\n\nfunc (c *MockClient) SnapshotService(snapshotterName string) snapshots.Snapshotter {\n\treturn mocks.NewMockSnapshotter(c.controller)\n}\n\nfunc TestGetOCIOptions(t *testing.T) {\n\tmockClient := MockClient{\n\t\tcontroller: gomock.NewController(t),\n\t}\n\tdefer mockClient.controller.Finish()\n\n\tgenerateOCISpec := func(svc *services.Extension) (*oci.Spec, error) {\n\t\tociOpts, err := svc.GetOCIOptions()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn oci.GenerateSpec(namespaces.WithNamespace(t.Context(), \"testNamespace\"), &mockClient, &containers.Container{}, ociOpts...)\n\t}\n\n\tt.Run(\"default configurations are cleared away if user passes empty arrays for MaskedPaths and ReadonlyPaths\", func(t *testing.T) {\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tSecurity: extservices.Security{\n\t\t\t\t\t\tMaskedPaths:   []string{},\n\t\t\t\t\t\tReadonlyPaths: []string{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []string{}, spec.Linux.MaskedPaths)\n\t\tassert.Equal(t, []string{}, spec.Linux.ReadonlyPaths)\n\t})\n\n\tt.Run(\"default configuration applies if user passes nil for MaskedPaths and ReadonlyPaths\", func(t *testing.T) {\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tSecurity: extservices.Security{\n\t\t\t\t\t\tMaskedPaths:   nil,\n\t\t\t\t\t\tReadonlyPaths: nil,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []string{\n\t\t\t\"/proc/acpi\",\n\t\t\t\"/proc/asound\",\n\t\t\t\"/proc/kcore\",\n\t\t\t\"/proc/keys\",\n\t\t\t\"/proc/latency_stats\",\n\t\t\t\"/proc/timer_list\",\n\t\t\t\"/proc/timer_stats\",\n\t\t\t\"/proc/sched_debug\",\n\t\t\t\"/sys/firmware\",\n\t\t\t\"/sys/devices/virtual/powercap\",\n\t\t\t\"/proc/scsi\",\n\t\t}, spec.Linux.MaskedPaths)\n\t\tassert.Equal(t, []string{\n\t\t\t\"/proc/bus\",\n\t\t\t\"/proc/fs\",\n\t\t\t\"/proc/irq\",\n\t\t\t\"/proc/sys\",\n\t\t\t\"/proc/sysrq-trigger\",\n\t\t}, spec.Linux.ReadonlyPaths)\n\t})\n\n\tt.Run(\"root fs is readonly unless explicitly enabled\", func(t *testing.T) {\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tSecurity: extservices.Security{\n\t\t\t\t\t\tWriteableRootfs: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, false, spec.Root.Readonly)\n\t})\n\n\tt.Run(\"root fs is readonly by default\", func(t *testing.T) {\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tSecurity: extservices.Security{},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, true, spec.Root.Readonly)\n\t})\n\n\tt.Run(\"allows setting extra env vars\", func(t *testing.T) {\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tEnvironment: []string{\n\t\t\t\t\t\t\"FOO=BAR\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []string{\"FOO=BAR\"}, spec.Process.Env)\n\t})\n\n\tt.Run(\"allows setting extra envFile\", func(t *testing.T) {\n\t\ttempDir := t.TempDir()\n\t\tenvFile := tempDir + \"/envfile\"\n\n\t\tassert.NoError(t, os.WriteFile(envFile, []byte(\"FOO=BARFROMENVFILE\"), 0o644))\n\n\t\t// given\n\t\tsvc := &services.Extension{\n\t\t\tSpec: extservices.Spec{\n\t\t\t\tContainer: extservices.Container{\n\t\t\t\t\tEnvironmentFile: envFile,\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// when\n\t\tspec, err := generateOCISpec(svc)\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, []string{\"FOO=BARFROMENVFILE\"}, spec.Process.Env)\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\tcontainerdapi \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/console\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nvar _ system.HealthcheckedService = (*Kubelet)(nil)\n\n// Kubelet implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Kubelet struct {\n\timgRef string\n}\n\n// ID implements the Service interface.\nfunc (k *Kubelet) ID(runtime.Runtime) string {\n\treturn \"kubelet\"\n}\n\n// PreFunc implements the Service interface.\nfunc (k *Kubelet) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\tspecResource, err := safe.ReaderGet[*k8s.KubeletSpec](ctx, r.State().V1Alpha2().Resources(), resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tspec := specResource.TypedSpec()\n\n\tclient, err := containerdapi.New(constants.CRIContainerdAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\t//nolint:errcheck\n\tdefer client.Close()\n\n\t// Pull the image and unpack it.\n\tcontainerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)\n\n\timg, err := image.Pull(containerdctx,\n\t\tcri.RegistryBuilder(r.State().V1Alpha2().Resources()),\n\t\tr.State().V1Alpha2().Resources(),\n\t\tclient, spec.Image,\n\t\timage.WithSkipIfAlreadyPulled(),\n\t\timage.WithProgressReporter(console.NewProgressReporter),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tk.imgRef = img.Target().Digest.String()\n\n\t// Create lifecycle resource to signal that the kubelet is about to start.\n\terr = r.State().V1Alpha2().Resources().Create(ctx, k8s.NewKubeletLifecycle(k8s.NamespaceName, k8s.KubeletLifecycleID))\n\tif err != nil && !state.IsConflictError(err) { // ignore if the lifecycle resource already exists\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (k *Kubelet) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (k *Kubelet) Condition(r runtime.Runtime) conditions.Condition {\n\treturn conditions.WaitForAll(\n\t\ttimeresource.NewSyncCondition(r.State().V1Alpha2().Resources()),\n\t\tnetwork.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady, network.EtcFilesReady),\n\t)\n}\n\n// DependsOn implements the Service interface.\nfunc (k *Kubelet) DependsOn(runtime.Runtime) []string {\n\treturn []string{\"cri\"}\n}\n\n// Volumes implements the Service interface.\nfunc (k *Kubelet) Volumes(runtime.Runtime) []string {\n\treturn []string{\n\t\t\"/var/lib\",\n\t\t\"/var/lib/kubelet\",\n\t\tconstants.LogMountPoint,\n\t\t\"/var/log/audit\",\n\t\t\"/var/log/containers\",\n\t\t\"/var/log/pods\",\n\t\t\"/var/lib/kubelet/seccomp\",\n\t\tconstants.SeccompProfilesDirectory,\n\t\tconstants.KubernetesAuditLogDir,\n\t\tconstants.UserVolumeMountPoint,\n\t}\n}\n\n// Runner implements the Service interface.\nfunc (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) {\n\tspecResource, err := safe.ReaderGet[*k8s.KubeletSpec](\n\t\tcontext.Background(),\n\t\tr.State().V1Alpha2().Resources(),\n\t\tresource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tspec := specResource.TypedSpec()\n\n\t// Set the process arguments.\n\targs := runner.Args{\n\t\tID:          k.ID(r),\n\t\tProcessArgs: append([]string{\"/usr/local/bin/kubelet\"}, spec.Args...),\n\t}\n\n\t// Set the required kubelet mounts.\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: \"/dev\", Source: \"/dev\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"sysfs\", Destination: \"/sys\", Source: \"/sys\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: constants.CgroupMountPath, Source: constants.CgroupMountPath, Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/lib/modules\", Source: \"/usr/lib/modules\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/etc/kubernetes\", Source: \"/etc/kubernetes\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: constants.KubeletCredentialProviderBinDir, Source: constants.KubeletCredentialProviderBinDir, Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/etc/nfsmount.conf\", Source: \"/etc/nfsmount.conf\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/etc/machine-id\", Source: \"/etc/machine-id\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/etc/os-release\", Source: \"/etc/os-release\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: constants.PodResolvConfPath, Source: constants.PodResolvConfPath, Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/etc/cni\", Source: \"/etc/cni\", Options: []string{\"bind\", \"ro\"}},\n\t\t{Type: \"bind\", Destination: \"/usr/libexec/kubernetes\", Source: \"/usr/libexec/kubernetes\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/var/run\", Source: \"/run\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/var/lib/containerd\", Source: \"/var/lib/containerd\", Options: []string{\"rbind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/var/lib/kubelet\", Source: \"/var/lib/kubelet\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/var/log/containers\", Source: \"/var/log/containers\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: \"/var/log/pods\", Source: \"/var/log/pods\", Options: []string{\"bind\", \"rw\"}},\n\t\t{Type: \"bind\", Destination: constants.UserVolumeMountPoint, Source: constants.UserVolumeMountPoint, Options: []string{\"rbind\", \"ro\"}},\n\t}\n\n\tif _, err := os.Stat(\"/sys/kernel/security\"); err == nil {\n\t\tmounts = append(mounts,\n\t\t\tspecs.Mount{Type: \"securityfs\", Destination: \"/sys/kernel/security\", Source: \"/sys/kernel/security\", Options: []string{\"bind\", \"ro\"}},\n\t\t)\n\t}\n\n\t// Add extra mounts.\n\t// TODO(andrewrynhard): We should verify that the mount source is\n\t// allowlisted. There is the potential that a user can expose\n\t// sensitive information.\n\tfor _, mount := range spec.ExtraMounts {\n\t\tif err = os.MkdirAll(mount.Source, 0o700); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmounts = append(mounts, mount)\n\t}\n\n\treturn restart.New(containerd.NewRunner(\n\t\tr.Config().Debug() && r.Config().Machine().Type() == machine.TypeWorker, // enable debug logs only for the worker nodes\n\t\t&args,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithNamespace(constants.SystemContainerdNamespace),\n\t\trunner.WithContainerImage(k.imgRef),\n\t\trunner.WithEnv(environment.Get(r.Config())),\n\t\trunner.WithCgroupPath(constants.CgroupKubelet),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelKubelet),\n\t\trunner.WithOCISpecOpts(\n\t\t\tcontainerd.WithRootfsPropagation(\"shared\"),\n\t\t\toci.WithMounts(mounts),\n\t\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\t\toci.WithHostNamespace(specs.PIDNamespace),\n\t\t\toci.WithParentCgroupDevices,\n\t\t\toci.WithMaskedPaths(nil),\n\t\t\toci.WithReadonlyPaths(nil),\n\t\t\toci.WithWriteableSysfs,\n\t\t\toci.WithWriteableCgroupfs,\n\t\t\toci.WithApparmorProfile(\"\"),\n\t\t\toci.WithAllDevicesAllowed,\n\t\t\toci.WithCapabilities(capability.AllGrantableCapabilities()), // TODO: kubelet doesn't need all of these, we should consider limiting capabilities\n\t\t),\n\t\trunner.WithOOMScoreAdj(constants.KubeletOOMScoreAdj),\n\t\trunner.WithCustomSeccompProfile(kubeletSeccomp),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (k *Kubelet) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error { return simpleHealthCheck(ctx, \"http://127.0.0.1:10248/healthz\") }\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (k *Kubelet) HealthSettings(runtime.Runtime) *health.Settings {\n\tsettings := health.DefaultSettings\n\tsettings.InitialDelay = 2 * time.Second // increase initial delay as kubelet is slow on startup\n\n\treturn &settings\n}\n\n// APIRestartAllowed implements APIRestartableService.\nfunc (k *Kubelet) APIRestartAllowed(runtime.Runtime) bool {\n\treturn true\n}\n\n// APIStartAllowed implements APIStartableService.\nfunc (k *Kubelet) APIStartAllowed(runtime.Runtime) bool {\n\treturn true\n}\n\nfunc kubeletSeccomp(seccomp *specs.LinuxSeccomp) {\n\t// for cephfs mounts\n\tseccomp.Syscalls = append(seccomp.Syscalls,\n\t\tspecs.LinuxSyscall{\n\t\t\tNames: []string{\n\t\t\t\t\"add_key\",\n\t\t\t\t\"request_key\",\n\t\t\t},\n\t\t\tAction: specs.ActAllow,\n\t\t\tArgs:   []specs.LinuxSeccompArg{},\n\t\t},\n\t)\n}\n\nfunc simpleHealthCheck(ctx context.Context, url string) error {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresp, err := http.DefaultClient.Do(req) //nolint:bodyclose\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbodyCloser := sync.OnceValue(resp.Body.Close)\n\n\tdefer bodyCloser() //nolint:errcheck\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"expected HTTP status OK, got %s\", resp.Status)\n\t}\n\n\treturn bodyCloser()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/machined.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-debug\"\n\t\"go.uber.org/zap/zapcore\"\n\t\"google.golang.org/grpc\"\n\n\tv1alpha1server \"github.com/siderolabs/talos/internal/app/machined/internal/server/v1alpha1\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/grpc/factory\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nconst machinedServiceID = \"machined\"\n\nvar rules = map[string]role.Set{\n\t\"/cluster.ClusterService/HealthCheck\": role.MakeSet(role.Admin, role.Operator, role.Reader),\n\n\t\"/inspect.InspectService/ControllerRuntimeDependencies\": role.MakeSet(role.Admin, role.Operator, role.Reader),\n\n\t\"/machine.ImageService/Import\": role.MakeSet(role.Admin),\n\t\"/machine.ImageService/List\":   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.ImageService/Pull\":   role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.ImageService/Remove\": role.MakeSet(role.Admin),\n\t\"/machine.ImageService/Verify\": role.MakeSet(role.Admin, role.Operator, role.Reader),\n\n\t\"/machine.DebugService/ContainerRun\": role.MakeSet(role.Admin),\n\n\t\"/machine.LifecycleService/Install\": role.MakeSet(role.Admin),\n\t\"/machine.LifecycleService/Upgrade\": role.MakeSet(role.Admin),\n\n\t\"/machine.MachineService/ApplyConfiguration\": role.MakeSet(\n\t\trole.Admin,\n\t\t// for maintenance only, verified in the handler\n\t\trole.Reader,\n\t),\n\t\"/machine.MachineService/Bootstrap\":                   role.MakeSet(role.Admin),\n\t\"/machine.MachineService/CPUInfo\":                     role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/CPUFreqStats\":                role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Containers\":                  role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Copy\":                        role.MakeSet(role.Admin),\n\t\"/machine.MachineService/DiskStats\":                   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/DiskUsage\":                   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Dmesg\":                       role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/EtcdAlarmList\":               role.MakeSet(role.Admin, role.Operator, role.Reader, role.EtcdBackup),\n\t\"/machine.MachineService/EtcdAlarmDisarm\":             role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/EtcdDefragment\":              role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/EtcdForfeitLeadership\":       role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdLeaveCluster\":            role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdMemberList\":              role.MakeSet(role.Admin, role.Operator, role.Reader, role.EtcdBackup),\n\t\"/machine.MachineService/EtcdRecover\":                 role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdRemoveMemberByID\":        role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdSnapshot\":                role.MakeSet(role.Admin, role.Operator, role.EtcdBackup),\n\t\"/machine.MachineService/EtcdStatus\":                  role.MakeSet(role.Admin, role.Operator, role.Reader, role.EtcdBackup),\n\t\"/machine.MachineService/EtcdDowngradeCancel\":         role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdDowngradeEnable\":         role.MakeSet(role.Admin),\n\t\"/machine.MachineService/EtcdDowngradeValidate\":       role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Events\":                      role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/GenerateClientConfiguration\": role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Hostname\":                    role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/ImageList\":                   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/ImagePull\":                   role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Kubeconfig\":                  role.MakeSet(role.Admin),\n\t\"/machine.MachineService/List\":                        role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/LoadAvg\":                     role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Logs\":                        role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/LogsContainers\":              role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Memory\":                      role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/MetaWrite\":                   role.MakeSet(role.Admin),\n\t\"/machine.MachineService/MetaDelete\":                  role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Mounts\":                      role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/NetworkDeviceStats\":          role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Netstat\":                     role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/PacketCapture\":               role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Processes\":                   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Read\":                        role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Reboot\":                      role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Reset\":                       role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Restart\":                     role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Rollback\":                    role.MakeSet(role.Admin),\n\t\"/machine.MachineService/ServiceList\":                 role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/ServiceRestart\":              role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/ServiceStart\":                role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/ServiceStop\":                 role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Shutdown\":                    role.MakeSet(role.Admin, role.Operator),\n\t\"/machine.MachineService/Stats\":                       role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/SystemStat\":                  role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/machine.MachineService/Upgrade\":                     role.MakeSet(role.Admin),\n\t\"/machine.MachineService/Version\":                     role.MakeSet(role.Admin, role.Operator, role.Reader),\n\n\t// per-type authorization is handled by the service itself\n\t\"/cosi.resource.State/Create\":  role.MakeSet(role.Admin),\n\t\"/cosi.resource.State/Destroy\": role.MakeSet(role.Admin),\n\t\"/cosi.resource.State/Get\":     role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/cosi.resource.State/List\":    role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/cosi.resource.State/Update\":  role.MakeSet(role.Admin),\n\t\"/cosi.resource.State/Watch\":   role.MakeSet(role.Admin, role.Operator, role.Reader),\n\n\t\"/storage.StorageService/Disks\":           role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/storage.StorageService/BlockDeviceWipe\": role.MakeSet(role.Admin),\n\n\t\"/time.TimeService/Time\":      role.MakeSet(role.Admin, role.Operator, role.Reader),\n\t\"/time.TimeService/TimeCheck\": role.MakeSet(role.Admin, role.Operator, role.Reader),\n}\n\ntype machinedService struct {\n\tc runtime.Controller\n}\n\n// Main is an entrypoint to the API service.\nfunc (s *machinedService) Main(ctx context.Context, _ runtime.Runtime, logWriter io.Writer) error {\n\tinjector := &authz.Injector{\n\t\tMode: authz.MetadataOnly,\n\t}\n\n\tif debug.Enabled {\n\t\tinjector.Logger = log.New(logWriter, \"machined/authz/injector \", log.Flags()).Printf\n\t}\n\n\tauthorizer := &authz.Authorizer{\n\t\tRules:         rules,\n\t\tFallbackRoles: role.MakeSet(role.Admin),\n\t\tLogger:        log.New(logWriter, \"machined/authz/authorizer \", log.Flags()).Printf,\n\t}\n\n\tlogger := logging.ZapLogger(\n\t\tlogging.NewLogDestination(logWriter, zapcore.DebugLevel,\n\t\t\tlogging.WithColoredLevels(),\n\t\t),\n\t)\n\n\t// Start the API server.\n\tserver := factory.NewServer( //nolint:contextcheck\n\t\t&v1alpha1server.Server{\n\t\t\tController: s.c,\n\t\t\t// breaking the import loop cycle between services/ package and v1alpha1_server.go\n\t\t\tEtcdBootstrapper: BootstrapEtcd,\n\t\t\tLogger:           logger,\n\n\t\t\tShutdownCtx: ctx,\n\t\t},\n\t\tfactory.WithLog(\"machined \", logWriter),\n\n\t\tfactory.ServerOptions(\n\t\t\tgrpc.MaxRecvMsgSize(constants.GRPCMaxMessageSize),\n\t\t),\n\n\t\tfactory.WithUnaryInterceptor(injector.UnaryInterceptor()),\n\t\tfactory.WithStreamInterceptor(injector.StreamInterceptor()), //nolint:contextcheck\n\n\t\tfactory.WithUnaryInterceptor(authorizer.UnaryInterceptor()),\n\t\tfactory.WithStreamInterceptor(authorizer.StreamInterceptor()), //nolint:contextcheck\n\t)\n\n\t// ensure socket dir exists\n\tif err := os.MkdirAll(filepath.Dir(constants.MachineSocketPath), 0o770); err != nil {\n\t\treturn err\n\t}\n\n\t// set the final leaf to be world-executable to make apid connect to the socket\n\tif err := os.Chmod(filepath.Dir(constants.MachineSocketPath), 0o771); err != nil {\n\t\treturn err\n\t}\n\n\tlistener, err := factory.NewListener(ctx, factory.Network(\"unix\"), factory.SocketPath(constants.MachineSocketPath)) //nolint:contextcheck\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := selinux.SetLabel(constants.MachineSocketPath, constants.MachineSocketLabel); err != nil {\n\t\treturn err\n\t}\n\n\t// chown the socket path to make it accessible to the apid\n\tif err := os.Chown(constants.MachineSocketPath, constants.ApidUserID, constants.ApidUserID); err != nil {\n\t\treturn err\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tclosed := make(chan struct{})\n\n\tcontext.AfterFunc(ctx, func() {\n\t\tdefer close(closed)\n\n\t\tshutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer shutdownCancel()\n\n\t\tfactory.ServerGracefulStop(server, shutdownCtx) //nolint:contextcheck\n\t})\n\n\terr = server.Serve(listener)\n\n\tcancel()\n\t<-closed\n\n\treturn err\n}\n\nvar _ system.HealthcheckedService = (*Machined)(nil)\n\n// Machined implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Machined struct {\n\tController runtime.Controller\n}\n\n// ID implements the Service interface.\nfunc (m *Machined) ID(runtime.Runtime) string {\n\treturn machinedServiceID\n}\n\n// PreFunc implements the Service interface.\nfunc (m *Machined) PreFunc(context.Context, runtime.Runtime) error {\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (m *Machined) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (m *Machined) Condition(runtime.Runtime) conditions.Condition {\n\treturn nil\n}\n\n// DependsOn implements the Service interface.\nfunc (m *Machined) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Volumes implements the Service interface.\nfunc (m *Machined) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (m *Machined) Runner(r runtime.Runtime) (runner.Runner, error) {\n\tsvc := &machinedService{m.Controller}\n\n\treturn goroutine.NewRunner(r, machinedServiceID, svc.Main, runner.WithLoggingManager(r.Logging())), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (m *Machined) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tvar d net.Dialer\n\n\t\tconn, err := d.DialContext(ctx, \"unix\", constants.MachineSocketPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn conn.Close()\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (m *Machined) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/machined_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services //nolint:testpackage // to test unexported variable\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api\"\n)\n\nfunc collectMethods(t *testing.T) map[string]struct{} {\n\tmethods := make(map[string]struct{})\n\n\tfor _, service := range api.TalosAPIdAllAPIs() {\n\t\tfor i := range service.Services().Len() {\n\t\t\tsvc := service.Services().Get(i)\n\n\t\t\tfor j := range svc.Methods().Len() {\n\t\t\t\tmethod := svc.Methods().Get(j)\n\n\t\t\t\ts := fmt.Sprintf(\"/%s/%s\", svc.FullName(), method.Name())\n\t\t\t\trequire.NotContains(t, methods, s)\n\t\t\t\tmethods[s] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn methods\n}\n\nfunc TestRules(t *testing.T) {\n\tt.Parallel()\n\n\tmethods := collectMethods(t)\n\n\t// check that there are no rules without matching methods\n\tt.Run(\"NoMethodForRule\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor rule := range rules {\n\t\t\t_, ok := methods[rule]\n\t\t\tassert.True(t, ok, \"no method for rule %q\", rule)\n\t\t}\n\t})\n\n\t// check that there are no methods without matching rules\n\tt.Run(\"NoRuleForMethod\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor method := range methods {\n\t\t\t_, ok := rules[method]\n\t\t\tassert.True(t, ok, \"no rule for method %q\", method)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/mocks/snapshotter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by MockGen. DO NOT EDIT.\n// Source: ~/go/pkg/mod/github.com/containerd/containerd@v1.6.4/snapshots/snapshotter.go\n\n// Package mocks is a generated GoMock package.\npackage mocks\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\n\tmount \"github.com/containerd/containerd/v2/core/mount\"\n\tsnapshots \"github.com/containerd/containerd/v2/core/snapshots\"\n\tgomock \"github.com/golang/mock/gomock\"\n)\n\n// MockSnapshotter is a mock of Snapshotter interface.\ntype MockSnapshotter struct {\n\tctrl     *gomock.Controller\n\trecorder *MockSnapshotterMockRecorder\n}\n\n// MockSnapshotterMockRecorder is the mock recorder for MockSnapshotter.\ntype MockSnapshotterMockRecorder struct {\n\tmock *MockSnapshotter\n}\n\n// NewMockSnapshotter creates a new mock instance.\nfunc NewMockSnapshotter(ctrl *gomock.Controller) *MockSnapshotter {\n\tmock := &MockSnapshotter{ctrl: ctrl}\n\tmock.recorder = &MockSnapshotterMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockSnapshotter) EXPECT() *MockSnapshotterMockRecorder {\n\treturn m.recorder\n}\n\n// Close mocks base method.\nfunc (m *MockSnapshotter) Close() error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Close\")\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Close indicates an expected call of Close.\nfunc (mr *MockSnapshotterMockRecorder) Close() *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Close\", reflect.TypeOf((*MockSnapshotter)(nil).Close))\n}\n\n// Commit mocks base method.\nfunc (m *MockSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []any{ctx, name, key}\n\tfor _, a := range opts {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"Commit\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Commit indicates an expected call of Commit.\nfunc (mr *MockSnapshotterMockRecorder) Commit(ctx, name, key any, opts ...any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]any{ctx, name, key}, opts...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Commit\", reflect.TypeOf((*MockSnapshotter)(nil).Commit), varargs...)\n}\n\n// Mounts mocks base method.\nfunc (m *MockSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Mounts\", ctx, key)\n\tret0, _ := ret[0].([]mount.Mount)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Mounts indicates an expected call of Mounts.\nfunc (mr *MockSnapshotterMockRecorder) Mounts(ctx, key any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Mounts\", reflect.TypeOf((*MockSnapshotter)(nil).Mounts), ctx, key)\n}\n\n// Prepare mocks base method.\nfunc (m *MockSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []any{ctx, key, parent}\n\tfor _, a := range opts {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"Prepare\", varargs...)\n\tret0, _ := ret[0].([]mount.Mount)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Prepare indicates an expected call of Prepare.\nfunc (mr *MockSnapshotterMockRecorder) Prepare(ctx, key, parent any, opts ...any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]any{ctx, key, parent}, opts...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Prepare\", reflect.TypeOf((*MockSnapshotter)(nil).Prepare), varargs...)\n}\n\n// Remove mocks base method.\nfunc (m *MockSnapshotter) Remove(ctx context.Context, key string) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Remove\", ctx, key)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Remove indicates an expected call of Remove.\nfunc (mr *MockSnapshotterMockRecorder) Remove(ctx, key any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Remove\", reflect.TypeOf((*MockSnapshotter)(nil).Remove), ctx, key)\n}\n\n// Stat mocks base method.\nfunc (m *MockSnapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Stat\", ctx, key)\n\tret0, _ := ret[0].(snapshots.Info)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Stat indicates an expected call of Stat.\nfunc (mr *MockSnapshotterMockRecorder) Stat(ctx, key any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Stat\", reflect.TypeOf((*MockSnapshotter)(nil).Stat), ctx, key)\n}\n\n// Update mocks base method.\nfunc (m *MockSnapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []any{ctx, info}\n\tfor _, a := range fieldpaths {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"Update\", varargs...)\n\tret0, _ := ret[0].(snapshots.Info)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Update indicates an expected call of Update.\nfunc (mr *MockSnapshotterMockRecorder) Update(ctx, info any, fieldpaths ...any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]any{ctx, info}, fieldpaths...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Update\", reflect.TypeOf((*MockSnapshotter)(nil).Update), varargs...)\n}\n\n// Usage mocks base method.\nfunc (m *MockSnapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Usage\", ctx, key)\n\tret0, _ := ret[0].(snapshots.Usage)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// Usage indicates an expected call of Usage.\nfunc (mr *MockSnapshotterMockRecorder) Usage(ctx, key any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Usage\", reflect.TypeOf((*MockSnapshotter)(nil).Usage), ctx, key)\n}\n\n// View mocks base method.\nfunc (m *MockSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {\n\tm.ctrl.T.Helper()\n\tvarargs := []any{ctx, key, parent}\n\tfor _, a := range opts {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"View\", varargs...)\n\tret0, _ := ret[0].([]mount.Mount)\n\tret1, _ := ret[1].(error)\n\treturn ret0, ret1\n}\n\n// View indicates an expected call of View.\nfunc (mr *MockSnapshotterMockRecorder) View(ctx, key, parent any, opts ...any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]any{ctx, key, parent}, opts...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"View\", reflect.TypeOf((*MockSnapshotter)(nil).View), varargs...)\n}\n\n// Walk mocks base method.\nfunc (m *MockSnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error {\n\tm.ctrl.T.Helper()\n\tvarargs := []any{ctx, fn}\n\tfor _, a := range filters {\n\t\tvarargs = append(varargs, a)\n\t}\n\tret := m.ctrl.Call(m, \"Walk\", varargs...)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Walk indicates an expected call of Walk.\nfunc (mr *MockSnapshotterMockRecorder) Walk(ctx, fn any, filters ...any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\tvarargs := append([]any{ctx, fn}, filters...)\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Walk\", reflect.TypeOf((*MockSnapshotter)(nil).Walk), varargs...)\n}\n\n// MockCleaner is a mock of Cleaner interface.\ntype MockCleaner struct {\n\tctrl     *gomock.Controller\n\trecorder *MockCleanerMockRecorder\n}\n\n// MockCleanerMockRecorder is the mock recorder for MockCleaner.\ntype MockCleanerMockRecorder struct {\n\tmock *MockCleaner\n}\n\n// NewMockCleaner creates a new mock instance.\nfunc NewMockCleaner(ctrl *gomock.Controller) *MockCleaner {\n\tmock := &MockCleaner{ctrl: ctrl}\n\tmock.recorder = &MockCleanerMockRecorder{mock}\n\treturn mock\n}\n\n// EXPECT returns an object that allows the caller to indicate expected use.\nfunc (m *MockCleaner) EXPECT() *MockCleanerMockRecorder {\n\treturn m.recorder\n}\n\n// Cleanup mocks base method.\nfunc (m *MockCleaner) Cleanup(ctx context.Context) error {\n\tm.ctrl.T.Helper()\n\tret := m.ctrl.Call(m, \"Cleanup\", ctx)\n\tret0, _ := ret[0].(error)\n\treturn ret0\n}\n\n// Cleanup indicates an expected call of Cleanup.\nfunc (mr *MockCleanerMockRecorder) Cleanup(ctx any) *gomock.Call {\n\tmr.mock.ctrl.T.Helper()\n\treturn mr.mock.ctrl.RecordCallWithMethodType(mr.mock, \"Cleanup\", reflect.TypeOf((*MockCleaner)(nil).Cleanup), ctx)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/app/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services/registry\"\n)\n\nfunc main() {\n\tif err := app(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"error: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc app() error {\n\tctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)\n\tdefer cancel()\n\n\tdevelopment, err := zap.NewDevelopment()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create development logger: %w\", err)\n\t}\n\n\thomeDir, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get user home directory: %w\", err)\n\t}\n\n\tit := func(yield func(string) bool) {\n\t\tfor _, root := range []string{\"registry-cache-2\", \"registry-cache\"} {\n\t\t\tif !yield(filepath.Join(homeDir, root)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\treturn registry.NewService(registry.NewMultiPathFS(it), development).Run(ctx)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/fs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"io/fs\"\n\t\"iter\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/hashicorp/go-multierror\"\n)\n\n// MultiPathFS is a [fs.FS] that reads from multiple paths sequentially until it finds the file.\ntype MultiPathFS struct {\n\tfsIt iter.Seq[string]\n}\n\n// NewMultiPathFS creates a new MultiPathFS. It takes an iterator of FSs which can be used multiple times asynchrously.\nfunc NewMultiPathFS(it iter.Seq[string]) *MultiPathFS { return &MultiPathFS{fsIt: it} }\n\n// Open opens the named file.\nfunc (m *MultiPathFS) Open(name string) (fs.File, error) {\n\tvar multiErr *multierror.Error\n\n\tfor root := range m.fsIt {\n\t\tabs, err := filepath.Abs(root)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tr, err := os.Open(filepath.Join(abs, name))\n\t\tif err == nil {\n\t\t\treturn r, nil\n\t\t}\n\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\tif multiErr == nil {\n\t\treturn nil, os.ErrNotExist\n\t}\n\n\treturn nil, multiErr.ErrorOrNil()\n}\n\n// Stat returns a [fs.FileInfo] describing the named file.\nfunc (m *MultiPathFS) Stat(name string) (fs.FileInfo, error) {\n\tvar multiErr *multierror.Error\n\n\tfor root := range m.fsIt {\n\t\tabs, err := filepath.Abs(root)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tr, err := os.Stat(filepath.Join(abs, name))\n\t\tif err == nil {\n\t\t\treturn r, nil\n\t\t}\n\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\tif multiErr == nil {\n\t\treturn nil, os.ErrNotExist\n\t}\n\n\treturn nil, multiErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/params.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"net/http\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/distribution/reference\"\n\t\"github.com/siderolabs/gen/xerrors\"\n)\n\nfunc extractParams(req *http.Request) (params, error) {\n\tregistry := req.URL.Query().Get(\"ns\")\n\n\tvalue := req.PathValue(\"args\")\n\n\tparts := strings.Split(path.Clean(value), \"/\")\n\tif len(parts) < 3 {\n\t\treturn params{}, xerrors.NewTaggedf[notFoundTag](\"incorrect args value '%s'\", value)\n\t}\n\n\tnumParts := len(parts)\n\tisBlob := parts[numParts-2] == \"blobs\"\n\tisManifest := parts[numParts-2] == \"manifests\"\n\n\tif !isBlob && !isManifest {\n\t\treturn params{}, xerrors.NewTaggedf[notFoundTag](\"incorrect ref: '%s'\", parts[numParts-2])\n\t}\n\n\tname := strings.Join(parts[:numParts-2], \"/\")\n\tdig := parts[numParts-1]\n\n\tif !reference.NameRegexp.MatchString(name) {\n\t\treturn params{}, xerrors.NewTaggedf[badRequestTag](\"incorrect name: '%s'\", name)\n\t}\n\n\treturn params{registry: registry, name: name, dig: dig, isBlob: isBlob}, nil\n}\n\ntype params struct {\n\tregistry string\n\tname     string\n\tdig      string\n\tisBlob   bool\n}\n\nfunc (p params) String() string {\n\tvar result strings.Builder\n\n\tif p.registry != \"\" {\n\t\tresult.WriteString(p.registry)\n\t\tresult.WriteByte('/')\n\t}\n\n\tresult.WriteString(p.name)\n\n\tif strings.HasPrefix(p.dig, \"sha256:\") {\n\t\tresult.WriteByte('@')\n\t\tresult.WriteString(p.dig)\n\t} else {\n\t\tresult.WriteByte(':')\n\t\tresult.WriteString(p.dig)\n\t}\n\n\treturn result.String()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/readers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\n\t\"github.com/containerd/containerd/v2/core/content\"\n\t\"github.com/containerd/errdefs\"\n)\n\nvar (\n\terrInvalidSize            = errors.New(\"readerat: invalid size\")\n\terrSeekToInvalidWhence    = errors.New(\"readerat: seek to invalid whence\")\n\terrSeekToNegativePosition = errors.New(\"readerat: seek to negative position\")\n)\n\n// readSeeker is an io.ReadSeeker implementation based on an io.ReaderAt (and\n// an int64 size).\n//\n// For example, an os.File is both an io.ReaderAt and an io.ReadSeeker, but its\n// io.ReadSeeker methods are not safe to use concurrently. In comparison,\n// multiple readerat.readSeeker values (using the same os.File as their\n// io.ReaderAt) are safe to use concurrently. Each can Read and Seek\n// independently.\n//\n// A single readerat.readSeeker is not safe to use concurrently.\n//\n// Do not modify its exported fields after calling any of its methods.\ntype readSeeker struct {\n\tReaderAt io.ReaderAt\n\tSize     int64\n\toffset   int64\n}\n\n// Read implements io.Reader.\nfunc (r *readSeeker) Read(p []byte) (int, error) {\n\tif r.Size < 0 {\n\t\treturn 0, errInvalidSize\n\t} else if r.Size <= r.offset {\n\t\treturn 0, io.EOF\n\t}\n\n\tif length := r.Size - r.offset; int64(len(p)) > length {\n\t\tp = p[:length]\n\t}\n\n\tif len(p) == 0 {\n\t\treturn 0, nil\n\t}\n\n\tactual, err := r.ReaderAt.ReadAt(p, r.offset)\n\tr.offset += int64(actual)\n\n\tif err == nil && r.offset == r.Size {\n\t\terr = io.EOF\n\t}\n\n\treturn actual, err\n}\n\n// Seek implements io.Seeker.\nfunc (r *readSeeker) Seek(offset int64, whence int) (int64, error) {\n\tif r.Size < 0 {\n\t\treturn 0, errInvalidSize\n\t}\n\n\tswitch whence {\n\tcase io.SeekStart:\n\t\t// No-op.\n\tcase io.SeekCurrent:\n\t\toffset += r.offset\n\tcase io.SeekEnd:\n\t\toffset += r.Size\n\tdefault:\n\t\treturn 0, errSeekToInvalidWhence\n\t}\n\n\tif offset < 0 {\n\t\treturn 0, errSeekToNegativePosition\n\t}\n\n\tr.offset = offset\n\n\treturn r.offset, nil\n}\n\n// openReaderAt creates ReaderAt from a file.\nfunc openReaderAt(p string, statFS fs.StatFS) (content.ReaderAt, error) {\n\tfi, err := statFS.Stat(p)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"blob not found: %w\", errdefs.ErrNotFound)\n\t}\n\n\tfp, err := statFS.Open(p)\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"blob not found: %w\", errdefs.ErrNotFound)\n\t}\n\n\tf, ok := fp.(fsFileReaderAt)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"not a fsFileReaderAt: %T, details: %v\", fp, fp)\n\t}\n\n\treturn sizeReaderAt{size: fi.Size(), fp: f}, nil\n}\n\n// readerat implements io.ReaderAt in a completely stateless manner by opening\n// the referenced file for each call to ReadAt.\ntype sizeReaderAt struct {\n\tsize int64\n\tfp   fsFileReaderAt\n}\n\nfunc (ra sizeReaderAt) ReadAt(p []byte, offset int64) (int, error) { return ra.fp.ReadAt(p, offset) }\nfunc (ra sizeReaderAt) Size() int64                                { return ra.size }\nfunc (ra sizeReaderAt) Close() error                               { return ra.fp.Close() }\nfunc (ra sizeReaderAt) Reader() io.Reader                          { return io.LimitReader(ra.fp, ra.size) }\n\ntype fsFileReaderAt interface {\n\tio.ReaderAt\n\tfs.File\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/registry.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package registry provides a simple container registry service.\npackage registry\n\nimport (\n\t\"bytes\"\n\t\"cmp\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/core/content\"\n\t\"github.com/distribution/reference\"\n\t\"github.com/opencontainers/go-digest\"\n\tocispec \"github.com/opencontainers/image-spec/specs-go/v1\"\n\t\"github.com/siderolabs/gen/xerrors\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// NewService creates a new instance of the registry service.\nfunc NewService(root fs.StatFS, logger *zap.Logger) *Service {\n\treturn &Service{root: root, logger: logger}\n}\n\n// Service is a container registry service.\ntype Service struct {\n\tlogger *zap.Logger\n\troot   fs.StatFS\n}\n\ntype config struct {\n\taddr        string\n\ttlsKeyPath  string\n\ttlsCertPath string\n}\n\n// Option is a functional option for configuring the service.\ntype Option func(*config)\n\n// WithTLS enables TLS with the given certificate and key paths.\nfunc WithTLS(certPath, keyPath string) Option {\n\treturn func(c *config) {\n\t\tc.tlsCertPath = certPath\n\t\tc.tlsKeyPath = keyPath\n\t}\n}\n\n// WithAddress sets the address to listen on.\nfunc WithAddress(addr string) Option {\n\treturn func(c *config) {\n\t\tc.addr = addr\n\t}\n}\n\n// Run is an entrypoint to the API service.\nfunc (svc *Service) Run(ctx context.Context, options ...Option) error {\n\tmux := http.NewServeMux()\n\n\tmux.HandleFunc(\"GET /v2/{args...}\", svc.serveHTTP)\n\n\tgiveOk := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }\n\tfor _, p := range []string{\"v2\", \"healthz\"} {\n\t\tmux.HandleFunc(\"GET /\"+p, giveOk)\n\t\tmux.HandleFunc(\"GET /\"+p+\"/{$}\", giveOk)\n\t}\n\n\tcfg := &config{\n\t\taddr: constants.RegistrydListenAddress,\n\t}\n\n\tfor _, option := range options {\n\t\toption(cfg)\n\t}\n\n\tserver := http.Server{Addr: cfg.addr, Handler: mux}\n\terrCh := make(chan error, 1)\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tcontext.AfterFunc(ctx, func() {\n\t\tsvc.logger.Info(\"shutting down registry server\", zap.String(\"addr\", server.Addr))\n\n\t\tshutdownCtx, shutdownCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer shutdownCtxCancel()\n\n\t\terrCh <- server.Shutdown(shutdownCtx)\n\t})\n\n\tsvc.logger.Info(\"starting registry server\", zap.String(\"addr\", server.Addr))\n\n\tvar err error\n\n\tif cfg.tlsCertPath != \"\" && cfg.tlsKeyPath != \"\" {\n\t\terr = server.ListenAndServeTLS(cfg.tlsCertPath, cfg.tlsKeyPath)\n\t\tif errors.Is(err, http.ErrServerClosed) {\n\t\t\terr = nil\n\t\t}\n\t} else {\n\t\terr = server.ListenAndServe()\n\t\tif errors.Is(err, http.ErrServerClosed) {\n\t\t\terr = nil\n\t\t}\n\t}\n\n\tcancel()\n\n\terr = cmp.Or(err, <-errCh)\n\n\tsvc.logger.Info(\"registry server stopped\", zap.Error(err))\n\n\treturn err\n}\n\nfunc (svc *Service) serveHTTP(w http.ResponseWriter, req *http.Request) {\n\tif err := svc.handler(w, req); err != nil {\n\t\tsvc.logger.Error(\"failed to handle request\", zap.Error(err))\n\t\tw.WriteHeader(getStatusCode(err))\n\t}\n}\n\n//nolint:gocyclo\nfunc (svc *Service) handler(w http.ResponseWriter, req *http.Request) error {\n\tlogger := svc.logger.With(\n\t\tzap.String(\"method\", req.Method),\n\t\tzap.String(\"url\", req.URL.String()),\n\t\tzap.String(\"remote_addr\", req.RemoteAddr),\n\t)\n\n\tp, err := extractParams(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to extract params: %w\", err)\n\t}\n\n\tlogger.Info(\n\t\t\"image request\",\n\t\tzap.String(\"name\", p.name),\n\t\tzap.String(\"digest\", p.dig),\n\t\tzap.Bool(\"is_blob\", p.isBlob),\n\t\tzap.String(\"registry\", p.registry),\n\t)\n\n\tif p.registry == \"\" {\n\t\tp.registry, err = svc.tryFindRegistry(p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif p.registry == \"\" {\n\t\t\treturn fmt.Errorf(\"failed to extract params: %w\", xerrors.NewTaggedf[badRequestTag](\"missing ns\"))\n\t\t}\n\t}\n\n\tref, err := svc.resolveCanonicalRef(p)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar s content.Store\n\tif p.isBlob {\n\t\ts = &singleFileStore{root: svc.root, path: \"blob\"}\n\t} else {\n\t\trefName := handleRegistryWithPort(ref, p)\n\n\t\ts = &singleFileStore{root: svc.root, path: filepath.Join(\"manifests\", refName, \"digest\")}\n\t}\n\n\tinfo, err := s.Info(req.Context(), ref.Digest())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tw.Header().Set(\"Content-Length\", strconv.FormatInt(info.Size, 10))\n\tw.Header().Set(\"Docker-Content-Digest\", ref.Digest().String())\n\n\tif !p.isBlob {\n\t\tmanType, manBlob, err := getManifestData(req.Context(), s, ref)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", manType)\n\n\t\tif req.Method == http.MethodHead {\n\t\t\treturn nil // nothing to do here\n\t\t}\n\n\t\thttp.ServeContent(w, req, ref.Digest().String(), info.UpdatedAt, bytes.NewReader(manBlob))\n\n\t\treturn nil\n\t}\n\n\treader, err := s.ReaderAt(req.Context(), ocispec.Descriptor{Digest: info.Digest})\n\tif err != nil {\n\t\treturn xerrors.NewTaggedf[internalErrorTag](\"failed to get content reader: %w\", err)\n\t}\n\n\treaderCloser := sync.OnceValue(reader.Close)\n\n\tdefer readerCloser() //nolint:errcheck\n\n\thttp.ServeContent(w, req, ref.Digest().String(), info.UpdatedAt, &readSeeker{ReaderAt: reader, Size: info.Size})\n\n\treturn readerCloser()\n}\n\nfunc (svc *Service) resolveCanonicalRef(p params) (reference.Canonical, error) {\n\tref, err := reference.ParseDockerRef(p.String())\n\tif err != nil {\n\t\treturn nil, xerrors.NewTaggedf[badRequestTag](\"failed to parse docker ref %q: %w\", p.String(), err)\n\t}\n\n\tcRef, ok := ref.(reference.Canonical)\n\tif ok {\n\t\treturn cRef, nil\n\t}\n\n\tnamedTagged, ok := ref.(reference.NamedTagged)\n\tif !ok {\n\t\treturn nil, xerrors.NewTaggedf[internalErrorTag](\"incorrect reference type: %T\", ref)\n\t}\n\n\tnamedTaggedName := handleRegistryWithPort(namedTagged, p)\n\n\ttaggedFile := filepath.Join(\"manifests\", namedTaggedName, \"reference\", namedTagged.Tag())\n\n\tntSum, err := hashFile(taggedFile, svc.root)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil, xerrors.NewTagged[notFoundTag](err)\n\t\t}\n\n\t\treturn nil, xerrors.NewTaggedf[internalErrorTag](\"failed to hash manifest: %w\", err)\n\t}\n\n\tdigestString := strings.ReplaceAll(digest.NewDigestFromBytes(digest.SHA256, ntSum).String(), \"sha256:\", \"sha256-\")\n\n\tsha256file := filepath.Join(\"manifests\", namedTaggedName, \"digest\", digestString)\n\n\tsSum, err := hashFile(sha256file, svc.root)\n\tif err != nil {\n\t\treturn nil, xerrors.NewTaggedf[internalErrorTag](\"failed to hash '%x': %w\", sSum, err)\n\t}\n\n\tif !bytes.Equal(ntSum, sSum) {\n\t\treturn nil, xerrors.NewTaggedf[internalErrorTag](\"hash for '%s' is not equal for hash to '%s'\", taggedFile, sha256file)\n\t}\n\n\treturn &canonical{\n\t\tNamedTagged: namedTagged,\n\t\tdigest:      digest.NewDigestFromBytes(digest.SHA256, ntSum),\n\t}, nil\n}\n\nfunc handleRegistryWithPort(namedTagged reference.Named, p params) string {\n\tnamedTaggedName := namedTagged.Name()\n\n\tidx := strings.LastIndex(p.registry, \":\")\n\tif idx > 0 {\n\t\tpath := strings.TrimPrefix(namedTaggedName, p.registry)\n\n\t\tnamedTaggedName = p.registry[:idx] + \"_\" + p.registry[idx+1:] + \"_\" + path\n\t}\n\n\treturn namedTaggedName\n}\n\nfunc createRegistryWithPort(s string) string {\n\tparts := strings.SplitN(s, \"_\", 3)\n\tif len(parts) < 3 {\n\t\treturn s\n\t}\n\n\treturn parts[0] + \":\" + parts[1] + parts[2]\n}\n\nfunc hashFile(f string, where fs.FS) (_ []byte, returnErr error) {\n\tdata, err := where.Open(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer func() { returnErr = cmp.Or(returnErr, data.Close()) }()\n\n\th := sha256.New()\n\tif _, err = io.Copy(h, data); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn h.Sum(nil), nil\n}\n\nfunc getManifestData(ctx context.Context, store content.Store, ref reference.Canonical) (string, []byte, error) {\n\tmanifestBlob, err := content.ReadBlob(ctx, store, ocispec.Descriptor{Digest: ref.Digest()})\n\tif err != nil {\n\t\treturn \"\", nil, xerrors.NewTaggedf[internalErrorTag](\"failed to read content blob: %w\", err)\n\t}\n\n\tvar manifest struct {\n\t\tMediaType string          `json:\"mediaType\"`\n\t\tManifests json.RawMessage `json:\"manifests\"`\n\t\tLayers    json.RawMessage `json:\"layers\"`\n\t\tConfig    json.RawMessage `json:\"config\"`\n\t}\n\n\tif err = json.Unmarshal(manifestBlob, &manifest); err != nil {\n\t\treturn \"\", nil, xerrors.NewTaggedf[internalErrorTag](\"failed to unmarshal manifest: %w\", err)\n\t}\n\n\tmediaType := manifest.MediaType\n\tif mediaType == \"\" {\n\t\t// OCI manifests may omit the top-level mediaType field; infer from structure.\n\t\tswitch {\n\t\tcase manifest.Manifests != nil:\n\t\t\tmediaType = ocispec.MediaTypeImageIndex\n\t\tcase manifest.Layers != nil || manifest.Config != nil:\n\t\t\tmediaType = ocispec.MediaTypeImageManifest\n\t\tdefault:\n\t\t\treturn \"\", nil, xerrors.NewTaggedf[internalErrorTag](\"media type is empty and cannot be inferred\")\n\t\t}\n\t}\n\n\treturn mediaType, manifestBlob, nil\n}\n\ntype canonical struct {\n\treference.NamedTagged\n\n\tdigest digest.Digest\n}\n\nfunc (c *canonical) String() string        { return c.NamedTagged.String() + \"@\" + c.digest.Encoded() }\nfunc (c *canonical) Digest() digest.Digest { return c.digest }\n\nfunc getStatusCode(err error) int {\n\tswitch {\n\tcase xerrors.TagIs[notFoundTag](err):\n\t\treturn http.StatusNotFound\n\tcase xerrors.TagIs[badRequestTag](err):\n\t\treturn http.StatusBadRequest\n\tcase xerrors.TagIs[internalErrorTag](err):\n\t\tfallthrough\n\tdefault:\n\t\treturn http.StatusInternalServerError\n\t}\n}\n\ntype (\n\tnotFoundTag      struct{}\n\tbadRequestTag    struct{}\n\tinternalErrorTag struct{}\n)\n\nfunc (svc *Service) tryFindRegistry(p params) (string, error) {\n\tentries, err := fs.ReadDir(svc.root, \"manifests\")\n\tif err != nil {\n\t\treturn \"\", xerrors.NewTaggedf[internalErrorTag](\"failed to read manifests directory: %w\", err)\n\t}\n\n\tfor _, entry := range entries {\n\t\tp.registry = createRegistryWithPort(entry.Name())\n\n\t\tref, err := reference.ParseDockerRef(p.String())\n\t\tif err != nil {\n\t\t\treturn \"\", xerrors.NewTaggedf[badRequestTag](\"failed to parse docker ref %q: %w\", p.String(), err)\n\t\t}\n\n\t\tnamedTaggedName := handleRegistryWithPort(ref, p)\n\n\t\ttaggedFile := filepath.Join(\"manifests\", namedTaggedName, \"reference\")\n\n\t\tif _, err := fs.Stat(svc.root, taggedFile); err == nil {\n\t\t\treturn p.registry, nil\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/registry_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry_test\n\nimport (\n\t\"archive/tar\"\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/google/go-containerregistry/pkg/crane\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/layout\"\n\t\"github.com/google/go-containerregistry/pkg/v1/remote\"\n\t\"github.com/siderolabs/gen/xtesting/check\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services/registry\"\n\t\"github.com/siderolabs/talos/pkg/imager/cache\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestRegistry(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip(\"skipping test in short mode.\")\n\t}\n\n\tcacheDir := t.TempDir()\n\n\timages := []string{\n\t\tfmt.Sprintf(\"%s:%s\", constants.CoreDNSImage, constants.DefaultCoreDNSVersion),\n\t\tfmt.Sprintf(\"%s:%s\", strings.ReplaceAll(constants.CoreDNSImage, \"registry.k8s.io\", \"registry.k8s.io:443\"), constants.DefaultCoreDNSVersion),\n\t}\n\n\tplatform, err := v1.ParsePlatform(\"linux/amd64\")\n\tassert.NoError(t, err)\n\n\tassert.NoError(t, cache.Generate(images, []string{platform.String()}, false, \"\", cacheDir, false, false))\n\n\tl, err := layout.ImageIndexFromPath(cacheDir)\n\tassert.NoError(t, err)\n\n\tm, err := l.IndexManifest()\n\tassert.NoError(t, err)\n\n\timage, err := l.Image(m.Manifests[0].Digest)\n\tassert.NoError(t, err)\n\n\tregistryRoot := t.TempDir()\n\n\ttarExtract(t, image, registryRoot)\n\n\tlogger := zaptest.NewLogger(t)\n\n\tit := func(yield func(string) bool) {\n\t\tif !yield(registryRoot) {\n\t\t\treturn\n\t\t}\n\t}\n\n\tsvc := registry.NewService(registry.NewMultiPathFS(it), logger)\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\n\tctx, cancel := context.WithCancelCause(t.Context())\n\tdefer cancel(nil)\n\n\tgo func() {\n\t\tdefer wg.Done()\n\n\t\tcancel(cmp.Or(svc.Run(ctx), errors.New(\"service exited\")))\n\t}()\n\n\tdefer wg.Wait()\n\n\tfor _, image := range images {\n\t\tt.Run(image, func(t *testing.T) {\n\t\t\tref, err := name.ParseReference(image)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tmanifest, err := crane.Manifest(ref.String())\n\t\t\tassert.NoError(t, err)\n\n\t\t\trmt, err := remote.Get(ref, remote.WithPlatform(*platform))\n\t\t\tassert.NoError(t, err)\n\n\t\t\tfor _, path := range []string{\n\t\t\t\tfmt.Sprintf(\"/v2/%s/manifests/%s?ns=%s\", ref.Context().RepositoryStr(), constants.DefaultCoreDNSVersion, ref.Context().RegistryStr()),\n\t\t\t\tfmt.Sprintf(\"/v2/%s/manifests/%s?ns=%s\", ref.Context().RepositoryStr(), rmt.Digest.String(), ref.Context().RegistryStr()),\n\t\t\t} {\n\t\t\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, \"http://\"+constants.RegistrydListenAddress+path, nil)\n\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\tif resp != nil {\n\t\t\t\t\tt.Cleanup(func() {\n\t\t\t\t\t\tassert.NoError(t, resp.Body.Close())\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, http.StatusOK, pointer.SafeDeref(resp).StatusCode, \"unexpected status code\")\n\t\t\t\tassert.Equal(t, string(manifest), readAll(t, resp))\n\t\t\t}\n\n\t\t\timg, err := rmt.Image()\n\t\t\tassert.NoError(t, err)\n\n\t\t\tlayers, err := img.Layers()\n\t\t\tassert.NoError(t, err)\n\n\t\t\thandleLayers(ctx, t, layers, ref)\n\t\t})\n\t}\n\n\ttests := []struct {\n\t\tname         string\n\t\tpath         string\n\t\tmethod       string\n\t\tcheck        check.Check\n\t\texpectedCode int\n\t}{\n\t\t{\n\t\t\tname:         \"HEAD /v2/\",\n\t\t\tpath:         \"/v2/\",\n\t\t\tmethod:       http.MethodHead,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"GET /v2/\",\n\t\t\tpath:         \"/v2/\",\n\t\t\tmethod:       http.MethodGet,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"HEAD /healthz\",\n\t\t\tpath:         \"/healthz\",\n\t\t\tmethod:       http.MethodHead,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"GET /healthz\",\n\t\t\tpath:         \"/healthz\",\n\t\t\tmethod:       http.MethodGet,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"GET /v2/alpine/manifests/3.20.3\",\n\t\t\tpath:         \"/v2/alpine/manifests/3.20.3\",\n\t\t\tmethod:       http.MethodGet,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusBadRequest,\n\t\t},\n\t\t{\n\t\t\tname:         \"GET /v2/alpine/manifests/3.20.3?ns=docker.io\",\n\t\t\tpath:         \"/v2/alpine/manifests/3.20.3?ns=docker.io\",\n\t\t\tmethod:       http.MethodGet,\n\t\t\tcheck:        check.NoError(),\n\t\t\texpectedCode: http.StatusNotFound,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\treq, err := http.NewRequestWithContext(ctx, test.method, \"http://\"+constants.RegistrydListenAddress+test.path, nil)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tresp, err := http.DefaultClient.Do(req)\n\t\t\ttest.check(t, err)\n\n\t\t\tif resp != nil {\n\t\t\t\tt.Cleanup(func() {\n\t\t\t\t\tassert.NoError(t, resp.Body.Close())\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tassert.Equal(t, test.expectedCode, pointer.SafeDeref(resp).StatusCode, \"unexpected status code, body is %s\", readAll(t, resp))\n\t\t})\n\t}\n\n\tcancel(nil)\n\twg.Wait()\n\n\terr = ctx.Err()\n\tif err == context.Canceled || err == context.DeadlineExceeded {\n\t\terr = nil\n\t}\n\n\tassert.NoError(t, err)\n}\n\nfunc handleLayers(ctx context.Context, t *testing.T, layers []v1.Layer, ref name.Reference) {\n\tfor _, layer := range layers {\n\t\tdig, err := layer.Digest()\n\t\tassert.NoError(t, err)\n\n\t\tpath := fmt.Sprintf(\"/v2/%s/blobs/%s?ns=%s\", ref.Context().RepositoryStr(), dig, ref.Context().RegistryStr())\n\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodHead, \"http://\"+constants.RegistrydListenAddress+path, nil)\n\t\tassert.NoError(t, err)\n\n\t\tresp, err := http.DefaultClient.Do(req)\n\t\tassert.NoError(t, err)\n\n\t\tif resp != nil {\n\t\t\tt.Cleanup(func() {\n\t\t\t\tassert.NoError(t, resp.Body.Close())\n\t\t\t})\n\t\t}\n\n\t\tassert.Equal(t, http.StatusOK, pointer.SafeDeref(resp).StatusCode, \"unexpected status code\")\n\t}\n}\n\nfunc tarExtract(t *testing.T, img v1.Image, dest string) {\n\tpipeReader, pipeWriter := io.Pipe()\n\n\tgo func() {\n\t\tpipeWriter.CloseWithError(crane.Export(img, pipeWriter))\n\t}()\n\n\ttr := tar.NewReader(pipeReader)\n\n\tfor {\n\t\theader, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tassert.NoError(t, err)\n\n\t\tswitch header.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tassert.NoError(t, os.MkdirAll(filepath.Join(dest, header.Name), 0o755))\n\t\tcase tar.TypeReg:\n\t\t\tf, err := os.Create(filepath.Join(dest, header.Name))\n\t\t\tassert.NoError(t, err)\n\n\t\t\t_, err = io.Copy(f, tr)\n\t\t\tassert.NoError(t, err)\n\t\tdefault:\n\t\t\tassert.Failf(t, \"unexpected tar entry type\", \"type: %v\", header.Typeflag)\n\t\t}\n\t}\n}\n\nfunc readAll(t *testing.T, resp *http.Response) string {\n\tif resp == nil || resp.Body == nil {\n\t\treturn \"<no response>\"\n\t}\n\n\tvar builder strings.Builder\n\n\t_, err := io.Copy(&builder, resp.Body)\n\tassert.NoError(t, err)\n\n\tif builder.String() == \"\" {\n\t\treturn \"<empty response>\"\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/store.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/containerd/containerd/v2/core/content\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/opencontainers/go-digest\"\n\tocispec \"github.com/opencontainers/image-spec/specs-go/v1\"\n\t\"github.com/siderolabs/gen/xerrors\"\n)\n\ntype singleFileStore struct {\n\troot fs.StatFS\n\tpath string\n}\n\n// Info implements [content.InfoProvider] reading method.\nfunc (s *singleFileStore) Info(_ context.Context, dgst digest.Digest) (content.Info, error) {\n\tp, err := s.blobPath(dgst)\n\tif err != nil {\n\t\treturn content.Info{}, fmt.Errorf(\"calculating blob info path: %w\", err)\n\t}\n\n\tfi, err := s.root.Stat(p)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) || errors.Is(err, errdefs.ErrNotFound) {\n\t\t\treturn content.Info{}, xerrors.NewTaggedf[notFoundTag](\"content '%s': %w\", dgst, errdefs.ErrNotFound)\n\t\t}\n\n\t\treturn content.Info{}, xerrors.NewTagged[internalErrorTag](err)\n\t}\n\n\treturn content.Info{\n\t\tDigest:    dgst,\n\t\tSize:      fi.Size(),\n\t\tCreatedAt: fi.ModTime(),\n\t\tUpdatedAt: getATime(fi),\n\t}, nil\n}\n\n// ReaderAt implements [content.Provider] reading method.\nfunc (s *singleFileStore) ReaderAt(_ context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {\n\tp, err := s.blobPath(desc.Digest)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"calculating blob path for ReaderAt: %w\", err)\n\t}\n\n\treader, err := openReaderAt(p, s.root)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"blob '%s' expected at '%s': %w\", desc.Digest, p, err)\n\t}\n\n\treturn reader, nil\n}\n\n// Status implements [content.IngestManager] ingesting which we don't need.\nfunc (s *singleFileStore) Status(context.Context, string) (content.Status, error) {\n\treturn content.Status{}, errUnimplemented\n}\n\n// ListStatuses implements [content.IngestManager] ingesting which we don't need.\nfunc (s *singleFileStore) ListStatuses(context.Context, ...string) ([]content.Status, error) {\n\treturn nil, errUnimplemented\n}\n\n// Abort implements [content.IngestManager] ingesting which we don't need.\nfunc (s *singleFileStore) Abort(context.Context, string) error { return errUnimplemented }\n\n// Writer implements [content.Ingester] ingesting which we don't need.\nfunc (s *singleFileStore) Writer(context.Context, ...content.WriterOpt) (content.Writer, error) {\n\treturn nil, errUnimplemented\n}\n\n// Walk implements [content.Manager] ingesting which we don't need.\nfunc (s *singleFileStore) Walk(context.Context, content.WalkFunc, ...string) error {\n\treturn errUnimplemented\n}\n\n// Delete implements [content.Manager] ingesting which we don't need.\nfunc (s *singleFileStore) Delete(context.Context, digest.Digest) error { return errUnimplemented }\n\n// Update implements [content.Manager] ingesting which we don't need.\nfunc (s *singleFileStore) Update(context.Context, content.Info, ...string) (content.Info, error) {\n\treturn content.Info{}, errUnimplemented\n}\n\nfunc (s *singleFileStore) blobPath(dgst digest.Digest) (string, error) {\n\tif err := dgst.Validate(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"cannot calculate blob path from invalid digest: %v: %w\", err, errdefs.ErrInvalidArgument)\n\t}\n\n\treturn filepath.Join(s.path, strings.ReplaceAll(dgst.String(), \"sha256:\", \"sha256-\")), nil\n}\n\nvar errUnimplemented = errors.New(\"unimplemented\")\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/store_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc getATime(fi os.FileInfo) time.Time {\n\tif st, ok := fi.Sys().(*syscall.Stat_t); ok {\n\t\treturn time.Unix(st.Atim.Unix())\n\t}\n\n\treturn fi.ModTime()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/store_unix.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build darwin || freebsd || openbsd || netbsd || dragonfly\n\npackage registry\n\nimport (\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc getATime(fi os.FileInfo) time.Time {\n\tif st, ok := fi.Sys().(*syscall.Stat_t); ok {\n\t\treturn time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec))\n\t}\n\n\treturn fi.ModTime()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registry/store_windows.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build windows\n\npackage registry\n\nimport (\n\t\"os\"\n\t\"time\"\n)\n\nfunc getATime(fi os.FileInfo) time.Time {\n\treturn fi.ModTime()\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/registryd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/services/registry\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/logging\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\ntype registryD struct{}\n\n// RegistryID is the ID of the registry service.\nconst RegistryID = \"registryd\"\n\n// NewRegistryD returns a new docker mirror registry service.\nfunc NewRegistryD() system.Service                                       { return &registryD{} }\nfunc (r *registryD) ID(runtime.Runtime) string                           { return RegistryID }\nfunc (r *registryD) HealthSettings(runtime.Runtime) *health.Settings     { return &health.DefaultSettings }\nfunc (r *registryD) PreFunc(context.Context, runtime.Runtime) error      { return nil }\nfunc (r *registryD) PostFunc(runtime.Runtime, events.ServiceState) error { return nil }\nfunc (r *registryD) Condition(runtime.Runtime) conditions.Condition      { return nil }\nfunc (r *registryD) DependsOn(runtime.Runtime) []string                  { return nil }\nfunc (r *registryD) Volumes(runtime.Runtime) []string                    { return nil }\n\nfunc (r *registryD) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\treturn simpleHealthCheck(ctx, \"http://\"+constants.RegistrydListenAddress+\"/healthz\")\n\t}\n}\n\nfunc (r *registryD) Runner(rt runtime.Runtime) (runner.Runner, error) {\n\treturn goroutine.NewRunner(rt, \"registryd\", func(ctx context.Context, r runtime.Runtime, logOutput io.Writer) error {\n\t\tlogger := logging.ZapLogger(\n\t\t\tlogging.NewLogDestination(logOutput, zapcore.DebugLevel, logging.WithColoredLevels()),\n\t\t)\n\n\t\tst := r.State().V1Alpha2().Resources()\n\t\tit := func(yield func(string) bool) {\n\t\t\timageCacheConfig, err := safe.StateGetByID[*cri.ImageCacheConfig](ctx, st, cri.ImageCacheConfigID)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Error(\"failed to get image cache config\", zap.Error(err))\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor _, root := range imageCacheConfig.TypedSpec().Roots {\n\t\t\t\tif _, err = os.Stat(root); err != nil {\n\t\t\t\t\tlogger.Error(\"failed to stat image cache root\", zap.String(\"root\", root), zap.Error(err))\n\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif !yield(root) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn registry.NewService(registry.NewMultiPathFS(it), logger).Run(ctx)\n\t}, runner.WithLoggingManager(rt.Logging())), nil\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/syslogd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/goroutine\"\n\t\"github.com/siderolabs/talos/internal/app/syslogd\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\nconst syslogServiceID = \"syslogd\"\n\nvar _ system.HealthcheckedService = (*Syslogd)(nil)\n\n// Syslogd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Syslogd struct{}\n\n// ID implements the Service interface.\nfunc (s *Syslogd) ID(runtime.Runtime) string {\n\treturn syslogServiceID\n}\n\n// PreFunc implements the Service interface.\nfunc (s *Syslogd) PreFunc(context.Context, runtime.Runtime) error {\n\treturn nil\n}\n\n// PostFunc implements the Service interface.\nfunc (s *Syslogd) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (s *Syslogd) Condition(runtime.Runtime) conditions.Condition {\n\treturn nil\n}\n\n// DependsOn implements the Service interface.\nfunc (s *Syslogd) DependsOn(runtime.Runtime) []string {\n\treturn []string{machinedServiceID}\n}\n\n// Volumes implements the Service interface.\nfunc (s *Syslogd) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (s *Syslogd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\treturn goroutine.NewRunner(r, syslogServiceID, syslogd.Main, runner.WithLoggingManager(r.Logging())), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (s *Syslogd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\treturn nil\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (s *Syslogd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/trustd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:golint\npackage services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/pkg/cap\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/server\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-debug\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\ttimeresource \"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nvar _ system.HealthcheckedService = (*Trustd)(nil)\n\n// Trustd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Trustd struct {\n\truntimeServer *grpc.Server\n}\n\n// ID implements the Service interface.\nfunc (t *Trustd) ID(runtime.Runtime) string {\n\treturn \"trustd\"\n}\n\n// PreFunc implements the Service interface.\n//\n//nolint:gocyclo\nfunc (t *Trustd) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\t// filter apid access to make sure apid can only access its certificates\n\tresources := state.Filter(\n\t\tr.State().V1Alpha2().Resources(),\n\t\tfunc(ctx context.Context, access state.Access) error {\n\t\t\tif !access.Verb.Readonly() {\n\t\t\t\treturn errors.New(\"write access denied\")\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase access.ResourceNamespace == secrets.NamespaceName && access.ResourceType == secrets.TrustdType && access.ResourceID == secrets.TrustdID:\n\t\t\tcase access.ResourceNamespace == secrets.NamespaceName && access.ResourceType == secrets.OSRootType && access.ResourceID == secrets.OSRootID:\n\t\t\tdefault:\n\t\t\t\treturn errors.New(\"access denied\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\t// ensure socket dir exists\n\tif err := os.MkdirAll(filepath.Dir(constants.TrustdRuntimeSocketPath), 0o750); err != nil {\n\t\treturn err\n\t}\n\n\t// set the final leaf to be world-executable to make trustd connect to the socket\n\tif err := os.Chmod(filepath.Dir(constants.TrustdRuntimeSocketPath), 0o751); err != nil {\n\t\treturn err\n\t}\n\n\t// clean up the socket if it already exists (important for Talos in a container)\n\tif err := os.RemoveAll(constants.TrustdRuntimeSocketPath); err != nil {\n\t\treturn err\n\t}\n\n\tlistener, err := (&net.ListenConfig{}).Listen(ctx, \"unix\", constants.TrustdRuntimeSocketPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := selinux.SetLabel(constants.TrustdRuntimeSocketPath, constants.TrustdRuntimeSocketLabel); err != nil {\n\t\treturn err\n\t}\n\n\t// chown the socket path to make it accessible to the apid\n\tif err := os.Chown(constants.TrustdRuntimeSocketPath, constants.TrustdUserID, constants.TrustdUserID); err != nil {\n\t\treturn err\n\t}\n\n\tt.runtimeServer = grpc.NewServer(\n\t\tgrpc.SharedWriteBuffer(true),\n\t)\n\tv1alpha1.RegisterStateServer(t.runtimeServer, server.NewState(resources))\n\n\tgo t.runtimeServer.Serve(listener) //nolint:errcheck\n\n\treturn prepareRootfs(t.ID(r))\n}\n\n// PostFunc implements the Service interface.\nfunc (t *Trustd) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\tt.runtimeServer.Stop()\n\n\treturn os.RemoveAll(constants.TrustdRuntimeSocketPath)\n}\n\n// Condition implements the Service interface.\nfunc (t *Trustd) Condition(r runtime.Runtime) conditions.Condition {\n\treturn conditions.WaitForAll(\n\t\ttimeresource.NewSyncCondition(r.State().V1Alpha2().Resources()),\n\t\tnetwork.NewReadyCondition(r.State().V1Alpha2().Resources(), network.AddressReady, network.HostnameReady),\n\t)\n}\n\n// DependsOn implements the Service interface.\nfunc (t *Trustd) DependsOn(runtime.Runtime) []string {\n\treturn []string{\"containerd\"}\n}\n\n// Volumes implements the Service interface.\nfunc (t *Trustd) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (t *Trustd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := runner.Args{\n\t\tID:          t.ID(r),\n\t\tProcessArgs: []string{\"/trustd\"},\n\t}\n\n\t// Set the mounts.\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: filepath.Dir(constants.TrustdRuntimeSocketPath), Source: filepath.Dir(constants.TrustdRuntimeSocketPath), Options: []string{\"rbind\", \"ro\"}},\n\t}\n\n\tmounts = bindMountContainerMarker(mounts)\n\n\tenv := environment.Get(r.Config())\n\tenv = append(env,\n\t\tconstants.EnvTcellMinimizeEnvironment,\n\t\tconstants.EnvTrustdGomemlimit(),\n\t)\n\n\tif debug.RaceEnabled {\n\t\tenv = append(env, constants.EnvGoraceHaltOnError)\n\t}\n\n\tif fipsmode.Strict() {\n\t\tenv = append(env, constants.EnvFIPS140ModeStrict)\n\t}\n\n\treturn restart.New(containerd.NewRunner(\n\t\tr.Config().Debug(),\n\t\t&args,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithContainerdAddress(constants.SystemContainerdAddress),\n\t\trunner.WithEnv(env),\n\t\trunner.WithCgroupPath(constants.CgroupTrustd),\n\t\trunner.WithGracefulShutdownTimeout(15*time.Second),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelTrustd),\n\t\trunner.WithOCISpecOpts(\n\t\t\toci.WithDroppedCapabilities(cap.Known()),\n\t\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\t\toci.WithMounts(mounts),\n\t\t\toci.WithRootFSPath(filepath.Join(constants.SystemLibexecPath, t.ID(r))),\n\t\t\toci.WithRootFSReadonly(),\n\t\t\toci.WithUser(fmt.Sprintf(\"%d:%d\", constants.TrustdUserID, constants.TrustdUserID)),\n\t\t),\n\t\trunner.WithOOMScoreAdj(-998),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\nfunc (t *Trustd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\tvar d net.Dialer\n\n\t\tconn, err := d.DialContext(ctx, \"tcp\", fmt.Sprintf(\"%s:%d\", \"127.0.0.1\", constants.TrustdPort))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn conn.Close()\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (t *Trustd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.DefaultSettings\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/udevd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/health\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/restart\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar _ system.HealthcheckedService = (*Udevd)(nil)\n\n// Udevd implements the Service interface. It serves as the concrete type with\n// the required methods.\ntype Udevd struct {\n\tExtraSettleTime time.Duration\n\n\ttriggered        bool\n\textraSettleStart time.Time\n}\n\n// ID implements the Service interface.\nfunc (c *Udevd) ID(runtime.Runtime) string {\n\treturn \"udevd\"\n}\n\n// PreFunc implements the Service interface.\nfunc (c *Udevd) PreFunc(ctx context.Context, r runtime.Runtime) error {\n\t_, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"hwdb\", \"--update\", \"--root=/usr\"})\n\n\treturn err\n}\n\n// PostFunc implements the Service interface.\nfunc (c *Udevd) PostFunc(runtime.Runtime, events.ServiceState) (err error) {\n\treturn nil\n}\n\n// Condition implements the Service interface.\nfunc (c *Udevd) Condition(runtime.Runtime) conditions.Condition {\n\treturn nil\n}\n\n// DependsOn implements the Service interface.\nfunc (c *Udevd) DependsOn(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Volumes implements the Service interface.\nfunc (c *Udevd) Volumes(runtime.Runtime) []string {\n\treturn nil\n}\n\n// Runner implements the Service interface.\nfunc (c *Udevd) Runner(r runtime.Runtime) (runner.Runner, error) {\n\t// Set the process arguments.\n\targs := &runner.Args{\n\t\tID: c.ID(r),\n\t\tProcessArgs: []string{\n\t\t\t\"/sbin/systemd-udevd\",\n\t\t\t\"--resolve-names=never\",\n\t\t},\n\t}\n\n\tdebug := false\n\n\tif r.Config() != nil {\n\t\tdebug = r.Config().Debug()\n\t}\n\n\treturn restart.New(process.NewRunner(\n\t\tdebug,\n\t\targs,\n\t\trunner.WithLoggingManager(r.Logging()),\n\t\trunner.WithCgroupPath(constants.CgroupUdevd),\n\t\trunner.WithSelinuxLabel(constants.SelinuxLabelUdevd),\n\t\trunner.WithDroppedCapabilities(constants.UdevdDroppedCapabilities),\n\t\trunner.WithEnv([]string{\n\t\t\tconstants.EnvXDGRuntimeDir,\n\t\t}),\n\t),\n\t\trestart.WithType(restart.Forever),\n\t), nil\n}\n\n// HealthFunc implements the HealthcheckedService interface.\n//\n//nolint:gocyclo\nfunc (c *Udevd) HealthFunc(runtime.Runtime) health.Check {\n\treturn func(ctx context.Context) error {\n\t\t// checking for the existence of the udev control socket is a faster way to check\n\t\t// that udevd is running, but not a complete check since the socket can persist if the process\n\t\t// was not gracefully stopped\n\t\tif err := conditions.WaitForFileToExist(\"/run/udev/control\").Wait(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// udevadm trigger returns with an exit code of 0 even if udevd is not fully running,\n\t\t// so running `udevadm control --reload` to ensure that udevd is fully initialized\n\t\t// which returns an exit code of 2 if udevd is not running. This complements the previous check\n\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"control\", \"--reload\"}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !c.triggered {\n\t\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"trigger\", \"--type=devices\", \"--action=add\"}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif _, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"trigger\", \"--type=subsystems\", \"--action=add\"}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tc.triggered = true\n\t\t}\n\n\t\t// This ensures that `udevd` finishes processing kernel events, triggered by\n\t\t// `udevd trigger`, to prevent a race condition when a user specifies a path\n\t\t// under `/dev/disk/*` in any disk definitions.\n\t\t_, err := cmd.RunWithOptions(ctx, \"/sbin/udevadm\", []string{\"settle\", \"--timeout=50\"}) // timeout here should be less than health.Settings.Timeout\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// If we got to the point where everything is settled, and the healthcheck would report\n\t\t// success, we start the extra settle timer.\n\t\tif c.extraSettleStart.IsZero() {\n\t\t\tc.extraSettleStart = time.Now()\n\t\t}\n\n\t\t// Wait for c.ExtraSettleTime before returning success (if configured).\n\t\tif c.ExtraSettleTime <= 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\tsettleEnd := c.extraSettleStart.Add(c.ExtraSettleTime)\n\n\t\tif time.Now().After(settleEnd) {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Can we wait until the health check deadline?\n\t\tif deadline, ok := ctx.Deadline(); ok {\n\t\t\t// if the deadline is before the settleEnd, we should wait until the deadline\n\t\t\tif settleEnd.Before(deadline) {\n\t\t\t\ttime.Sleep(time.Until(settleEnd))\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treturn fmt.Errorf(\"waiting for udevd for extra settle timeout\")\n\t}\n}\n\n// HealthSettings implements the HealthcheckedService interface.\nfunc (c *Udevd) HealthSettings(runtime.Runtime) *health.Settings {\n\treturn &health.Settings{\n\t\tInitialDelay: 100 * time.Millisecond,\n\t\tPeriod:       time.Minute,\n\t\tTimeout:      55 * time.Second,\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/services/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containermode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// prepareRootfs creates /system/libexec/<service> rootfs and bind-mounts /sbin/init there.\nfunc prepareRootfs(id string) error {\n\trootfsPath := filepath.Join(constants.SystemLibexecPath, id)\n\n\tif err := os.MkdirAll(rootfsPath, 0o711); err != nil { // rwx--x--x, non-root programs should be able to follow path\n\t\treturn fmt.Errorf(\"failed to create rootfs %q: %w\", rootfsPath, err)\n\t}\n\n\texecutablePath := filepath.Join(rootfsPath, id)\n\n\tif err := os.WriteFile(executablePath, nil, 0o555); err != nil { // r-xr-xr-x, non-root programs should be able to execute & read\n\t\treturn fmt.Errorf(\"failed to create empty executable %q: %w\", executablePath, err)\n\t}\n\n\tif err := unix.Mount(\"/sbin/init\", executablePath, \"\", unix.MS_BIND, \"\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to create bind mount for %q: %w\", executablePath, err)\n\t}\n\n\treturn nil\n}\n\n// bindMountContainerMarker bind-mounts a file used for container detection into a container service.\nfunc bindMountContainerMarker(mounts []specs.Mount) []specs.Mount {\n\tif containermode.InContainer() {\n\t\tmounts = append(\n\t\t\tmounts,\n\t\t\tspecs.Mount{Type: \"bind\", Destination: constants.ContainerMarkerFilePath, Source: constants.ContainerMarkerFilePath, Options: []string{\"bind\", \"ro\"}},\n\t\t)\n\t}\n\n\treturn mounts\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/system.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\tstdmaps \"maps\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\n// singleton the system services API interface.\ntype singleton struct {\n\truntime runtime.Runtime\n\n\t// State of running services by ID\n\tstate map[string]*ServiceRunner\n\n\t// List of running services at the moment.\n\t//\n\t// Service might be in any state, but service ID in the map\n\t// implies ServiceRunner.Start() method is running at the momemnt\n\trunningMu sync.Mutex\n\trunning   map[string]struct{}\n\n\tmu          sync.Mutex\n\twg          sync.WaitGroup\n\tterminating bool\n}\n\nvar (\n\tinstance *singleton\n\tonce     sync.Once\n)\n\nfunc newServices(runtime runtime.Runtime) *singleton {\n\treturn &singleton{\n\t\truntime: runtime,\n\t\tstate:   map[string]*ServiceRunner{},\n\t\trunning: map[string]struct{}{},\n\t}\n}\n\n// Services returns the instance of the system services API.\n//\n//nolint:revive,golint\nfunc Services(runtime runtime.Runtime) *singleton {\n\tonce.Do(func() {\n\t\tinstance = newServices(runtime)\n\t})\n\n\treturn instance\n}\n\n// Load adds service to the list of services managed by the runner.\n//\n// Load returns service IDs for each of the services.\nfunc (s *singleton) Load(services ...Service) []string {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tif s.terminating {\n\t\treturn nil\n\t}\n\n\tids := make([]string, 0, len(services))\n\n\tfor _, service := range services {\n\t\tid := service.ID(s.runtime)\n\t\tids = append(ids, id)\n\n\t\tif _, exists := s.state[id]; exists {\n\t\t\t// service already loaded, ignore\n\t\t\tcontinue\n\t\t}\n\n\t\tsvcrunner := NewServiceRunner(s, service, s.runtime)\n\t\ts.state[id] = svcrunner\n\t}\n\n\treturn ids\n}\n\n// Unload stops the service and removes it from the list of running services.\n//\n// It is not an error to unload a service which was already removed or stopped.\nfunc (s *singleton) Unload(ctx context.Context, serviceIDs ...string) error {\n\ts.mu.Lock()\n\n\tif s.terminating {\n\t\ts.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\tservicesToRemove := make([]string, 0, len(serviceIDs))\n\n\tfor _, id := range serviceIDs {\n\t\tif _, exists := s.state[id]; exists {\n\t\t\tservicesToRemove = append(servicesToRemove, id)\n\t\t}\n\t}\n\n\ts.mu.Unlock()\n\n\tif err := s.Stop(ctx, servicesToRemove...); err != nil {\n\t\treturn fmt.Errorf(\"error stopping services %v: %w\", servicesToRemove, err)\n\t}\n\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\ts.runningMu.Lock()\n\tdefer s.runningMu.Unlock()\n\n\tfor _, id := range servicesToRemove {\n\t\tdelete(s.state, id)\n\t\tdelete(s.running, id) // this fixes an edge case when defer() in Start() doesn't have time to remove stopped service from running\n\t}\n\n\treturn nil\n}\n\n// Start will invoke the service's Pre, Condition, and Type funcs. If any\n// error occurs in the Pre or Condition invocations, it is up to the caller to\n// restart the service.\nfunc (s *singleton) Start(serviceIDs ...string) error {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tif s.terminating {\n\t\treturn nil\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor _, id := range serviceIDs {\n\t\tsvcrunner := s.state[id]\n\t\tif svcrunner == nil {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"service %q not defined\", id))\n\t\t}\n\n\t\ts.runningMu.Lock()\n\n\t\t_, running := s.running[id]\n\t\tif !running {\n\t\t\ts.running[id] = struct{}{}\n\t\t}\n\n\t\ts.runningMu.Unlock()\n\n\t\tif running {\n\t\t\t// service already running, skip\n\t\t\tcontinue\n\t\t}\n\n\t\trunNotify := make(chan struct{})\n\n\t\ts.wg.Add(1)\n\n\t\tgo func(id string, svcrunner *ServiceRunner) {\n\t\t\terr := func() error {\n\t\t\t\tdefer func() {\n\t\t\t\t\ts.runningMu.Lock()\n\t\t\t\t\tdelete(s.running, id)\n\t\t\t\t\ts.runningMu.Unlock()\n\t\t\t\t}()\n\t\t\t\tdefer s.wg.Done()\n\n\t\t\t\treturn svcrunner.Run(runNotify)\n\t\t\t}()\n\n\t\t\tswitch {\n\t\t\tcase err == nil:\n\t\t\t\tsvcrunner.UpdateState(context.Background(), events.StateFinished, \"Service finished successfully\")\n\t\t\tcase errors.Is(err, ErrSkip):\n\t\t\t\tsvcrunner.UpdateState(context.Background(), events.StateSkipped, \"Service skipped\")\n\t\t\tdefault:\n\t\t\t\tmsg := err.Error()\n\t\t\t\tif len(msg) > 0 {\n\t\t\t\t\tmsg = strings.ToUpper(msg[:1]) + msg[1:]\n\t\t\t\t}\n\n\t\t\t\tsvcrunner.UpdateState(context.Background(), events.StateFailed, \"%s\", msg)\n\t\t\t}\n\t\t}(id, svcrunner)\n\n\t\t// wait for svcrunner.Run to enter the running phase, and then return\n\t\t<-runNotify\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// StartAll starts all the services.\nfunc (s *singleton) StartAll() {\n\ts.mu.Lock()\n\tserviceIDs := maps.Keys(s.state)\n\ts.mu.Unlock()\n\n\t//nolint:errcheck\n\ts.Start(serviceIDs...)\n}\n\n// LoadAndStart combines Load and Start into single call.\nfunc (s *singleton) LoadAndStart(services ...Service) {\n\terr := s.Start(s.Load(services...)...)\n\tif err != nil {\n\t\t// should never happen\n\t\tpanic(err)\n\t}\n}\n\n// Shutdown all the services.\nfunc (s *singleton) Shutdown(ctx context.Context) {\n\ts.mu.Lock()\n\n\tif s.terminating {\n\t\ts.mu.Unlock()\n\n\t\treturn\n\t}\n\n\ts.terminating = true\n\n\t_ = s.stopServices(ctx, nil, true) //nolint:errcheck\n}\n\n// Stop will initiate a shutdown of the specified service.\nfunc (s *singleton) Stop(ctx context.Context, serviceIDs ...string) (err error) {\n\tif len(serviceIDs) == 0 {\n\t\treturn err\n\t}\n\n\ts.mu.Lock()\n\n\tif s.terminating {\n\t\ts.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\treturn s.stopServices(ctx, serviceIDs, false)\n}\n\n// StopWithRevDepenencies will initiate a shutdown of the specified services waiting for reverse dependencies to finish first.\n//\n// If reverse dependency is not stopped, this method might block waiting on it being stopped for up to 30 seconds.\nfunc (s *singleton) StopWithRevDepenencies(ctx context.Context, serviceIDs ...string) (err error) {\n\tif len(serviceIDs) == 0 {\n\t\treturn err\n\t}\n\n\ts.mu.Lock()\n\n\tif s.terminating {\n\t\ts.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\treturn s.stopServices(ctx, serviceIDs, true)\n}\n\n//nolint:gocyclo\nfunc (s *singleton) stopServices(ctx context.Context, services []string, waitForRevDependencies bool) error {\n\tservicesToStop := map[string]*ServiceRunner{}\n\n\tif services == nil {\n\t\tstdmaps.Copy(servicesToStop, s.state)\n\t} else {\n\t\tfor _, name := range services {\n\t\t\tif _, ok := s.state[name]; !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tservicesToStop[name] = s.state[name]\n\t\t}\n\t}\n\n\t// build reverse dependencies, and expand the list of services to stop\n\t// with services which depend on the one being stopped\n\treverseDependencies := map[string][]string{}\n\n\tif waitForRevDependencies {\n\t\t// expand the list of services to stop with the list of services which depend\n\t\t// on the ones being stopped\n\t\t// the loop is run as long as more dependencies are added to the list\n\t\tfor {\n\t\t\texpanded := false\n\n\t\t\tfor name, svcrunner := range s.state {\n\t\t\t\tif _, scheduledToStop := servicesToStop[name]; scheduledToStop {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tdependencies := svcrunner.service.DependsOn(s.runtime)\n\n\t\t\t\tshouldStopService := false\n\n\t\t\t\tfor _, dependency := range dependencies {\n\t\t\t\t\tfor scheduledService := range servicesToStop {\n\t\t\t\t\t\tif scheduledService == dependency {\n\t\t\t\t\t\t\tshouldStopService = true\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif shouldStopService {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif shouldStopService {\n\t\t\t\t\tservicesToStop[name] = svcrunner\n\t\t\t\t\texpanded = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !expanded {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// build a list of dependencies to wait for before stopping each of the services\n\t\tfor name, svcrunner := range servicesToStop {\n\t\t\tfor _, dependency := range svcrunner.service.DependsOn(s.runtime) {\n\t\t\t\treverseDependencies[dependency] = append(reverseDependencies[dependency], name)\n\t\t\t}\n\t\t}\n\t}\n\n\ts.mu.Unlock()\n\n\t// shutdown all the services waiting for rev deps\n\tvar shutdownWg sync.WaitGroup\n\n\t// wait max 30 seconds for reverse deps to shut down\n\tshutdownCtx, shutdownCtxCancel := context.WithTimeout(ctx, 30*time.Second)\n\tdefer shutdownCtxCancel()\n\n\tstoppedConds := make([]conditions.Condition, 0, len(servicesToStop))\n\n\tfor name, svcrunner := range servicesToStop {\n\t\tshutdownWg.Add(1)\n\n\t\tstoppedConds = append(stoppedConds, waitForService(s, StateEventDown, name))\n\n\t\tgo func(svcrunner *ServiceRunner, reverseDeps []string) {\n\t\t\tdefer shutdownWg.Done()\n\n\t\t\tconds := xslices.Map(reverseDeps, func(dep string) conditions.Condition { return waitForService(s, StateEventDown, dep) })\n\t\t\tallDeps := conditions.WaitForAll(conds...)\n\n\t\t\tif err := allDeps.Wait(shutdownCtx); err != nil {\n\t\t\t\tlog.Printf(\"gave up on %s while stopping %q\", allDeps, svcrunner.id)\n\t\t\t}\n\n\t\t\tsvcrunner.Shutdown()\n\t\t}(svcrunner, reverseDependencies[name])\n\t}\n\n\tshutdownWg.Wait()\n\n\treturn conditions.WaitForAll(stoppedConds...).Wait(ctx)\n}\n\n// List returns snapshot of ServiceRunner instances.\nfunc (s *singleton) List() (result []*ServiceRunner) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tresult = maps.Values(s.state)\n\n\t// TODO: results should be sorted properly with topological sort on dependencies\n\t//       but, we don't have dependencies yet, so sort by service id for now to get stable order\n\tslices.SortFunc(result, func(a, b *ServiceRunner) int { return cmp.Compare(a.id, b.id) })\n\n\treturn result\n}\n\n// IsRunning checks service status (started/stopped).\n//\n// It doesn't check if service runner was started or not, just pure\n// check for service status in terms of start/stop.\nfunc (s *singleton) IsRunning(id string) (Service, bool, error) {\n\ts.mu.Lock()\n\trunner, exists := s.state[id]\n\ts.mu.Unlock()\n\n\tif !exists {\n\t\treturn nil, false, fmt.Errorf(\"service %q not defined\", id)\n\t}\n\n\ts.runningMu.Lock()\n\t_, running := s.running[id]\n\ts.runningMu.Unlock()\n\n\treturn runner.service, running, nil\n}\n\n// APIStart processes service start request from the API.\nfunc (s *singleton) APIStart(ctx context.Context, id string) error {\n\tservice, running, err := s.IsRunning(id)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif running {\n\t\t// already started, skip\n\t\treturn nil\n\t}\n\n\tif svc, ok := service.(APIStartableService); ok && svc.APIStartAllowed(s.runtime) {\n\t\treturn s.Start(id)\n\t}\n\n\treturn fmt.Errorf(\"service %q doesn't support start operation via API\", id)\n}\n\n// APIStop processes services stop request from the API.\nfunc (s *singleton) APIStop(ctx context.Context, id string) error {\n\tservice, running, err := s.IsRunning(id)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !running {\n\t\t// already stopped, skip\n\t\treturn nil\n\t}\n\n\tif svc, ok := service.(APIStoppableService); ok && svc.APIStopAllowed(s.runtime) {\n\t\treturn s.Stop(ctx, id)\n\t}\n\n\treturn fmt.Errorf(\"service %q doesn't support stop operation via API\", id)\n}\n\n// APIRestart processes services restart request from the API.\nfunc (s *singleton) APIRestart(ctx context.Context, id string) error {\n\tservice, running, err := s.IsRunning(id)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !running {\n\t\t// restart for not running service is equivalent to Start()\n\t\treturn s.APIStart(ctx, id)\n\t}\n\n\tif svc, ok := service.(APIRestartableService); ok && svc.APIRestartAllowed(s.runtime) {\n\t\tif err := s.Stop(ctx, id); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn s.Start(id)\n\t}\n\n\treturn fmt.Errorf(\"service %q doesn't support restart operation via API\", id)\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/system_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n)\n\ntype SystemServicesSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *SystemServicesSuite) TestStartShutdown() {\n\tsystem.Services(nil).LoadAndStart(\n\t\t&MockService{name: \"containerd\"},\n\t\t&MockService{name: \"trustd\", dependencies: []string{\"containerd\"}},\n\t\t&MockService{name: \"machined\", dependencies: []string{\"containerd\", \"trustd\"}},\n\t)\n\ttime.Sleep(10 * time.Millisecond)\n\n\tsuite.Require().NoError(system.Services(nil).Unload(context.Background(), \"trustd\", \"notrunning\"))\n}\n\nfunc (suite *SystemServicesSuite) TestStartStop() {\n\tsystem.Services(nil).LoadAndStart(\n\t\t&MockService{name: \"yolo\"},\n\t)\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\terr := system.Services(nil).Stop(\n\t\tcontext.TODO(), \"yolo\",\n\t)\n\tsuite.Assert().NoError(err)\n}\n\nfunc (suite *SystemServicesSuite) TestStopWithRevDeps() {\n\tsystem.Services(nil).LoadAndStart(\n\t\t&MockService{name: \"cri\"},\n\t\t&MockService{name: \"networkd\", dependencies: []string{\"cri\"}},\n\t\t&MockService{name: \"vland\", dependencies: []string{\"networkd\"}},\n\t)\n\ttime.Sleep(10 * time.Millisecond)\n\n\t// stopping cri should stop all services\n\tsuite.Require().NoError(system.Services(nil).StopWithRevDepenencies(context.Background(), \"cri\"))\n\n\t// no services should be running\n\tfor _, name := range []string{\"cri\", \"networkd\", \"vland\"} {\n\t\tsvc, running, err := system.Services(nil).IsRunning(name)\n\t\tsuite.Require().NoError(err)\n\t\tsuite.Assert().NotNil(svc)\n\t\tsuite.Assert().False(running)\n\t}\n\n\tsystem.Services(nil).Shutdown(context.TODO())\n}\n\nfunc TestSystemServicesSuite(t *testing.T) {\n\tsuite.Run(t, new(SystemServicesSuite))\n}\n"
  },
  {
    "path": "internal/app/machined/pkg/system/volumes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage system\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc (svcrunner *ServiceRunner) deleteVolumeMountRequest(ctx context.Context, requests []volumeRequest) error {\n\tst := svcrunner.runtime.State().V1Alpha2().Resources()\n\n\trequests = slices.Clone(requests)\n\tslices.Reverse(requests)\n\n\tfor _, request := range requests {\n\t\tif err := st.RemoveFinalizer(ctx, block.NewVolumeMountStatus(block.NamespaceName, request.requestID).Metadata(), \"service\"); err != nil {\n\t\t\tif !state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to remove finalizer from mount status %q: %w\", request.requestID, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, request := range requests {\n\t\terr := st.Destroy(ctx, block.NewVolumeMountRequest(block.NamespaceName, request.requestID).Metadata())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to destroy volume mount request %q: %w\", request.requestID, err)\n\t\t}\n\t}\n\n\tfor _, request := range requests {\n\t\tif _, err := st.WatchFor(ctx, block.NewVolumeMountStatus(block.NamespaceName, request.requestID).Metadata(), state.WithEventTypes(state.Destroyed)); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to watch for volume mount status to be destroyed %q: %w\", request.requestID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype volumesMountedCondition struct {\n\tst       state.State\n\trequests []volumeRequest\n\n\tmu              sync.Mutex\n\tpendingRequests []volumeRequest\n}\n\nfunc (cond *volumesMountedCondition) Wait(ctx context.Context) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\t// we mount all requests sequentially one by one\n\tfor idx := range cond.requests {\n\t\treq := cond.requests[idx]\n\n\t\t// create volume mount request\n\t\tmountRequest := block.NewVolumeMountRequest(block.NamespaceName, req.requestID)\n\t\tmountRequest.TypedSpec().Requester = req.requester\n\t\tmountRequest.TypedSpec().VolumeID = req.volumeID\n\n\t\tif err := cond.st.Create(ctx, mountRequest); err != nil {\n\t\t\tif !state.IsConflictError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to create mount request: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// wait for the mount status\n\t\t_, err := cond.st.WatchFor(ctx,\n\t\t\tblock.NewVolumeMountStatus(block.NamespaceName, req.requestID).Metadata(),\n\t\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\t\tstate.WithPhases(resource.PhaseRunning),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = cond.st.AddFinalizer(ctx, block.NewVolumeMountStatus(block.NamespaceName, req.requestID).Metadata(), \"service\"); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcond.mu.Lock()\n\t\tcond.pendingRequests = slices.Clone(cond.requests[idx+1:])\n\t\tcond.mu.Unlock()\n\t}\n\n\treturn nil\n}\n\nfunc (cond *volumesMountedCondition) String() string {\n\tcond.mu.Lock()\n\tpendingVolumeIDs := xslices.Map(cond.pendingRequests, func(r volumeRequest) string { return r.volumeID })\n\tcond.mu.Unlock()\n\n\treturn fmt.Sprintf(\"volumes %s to be mounted\", strings.Join(pendingVolumeIDs, \", \"))\n}\n\n// WaitForVolumesToBeMounted is a service condition that will wait for the volumes to be mounted.\nfunc WaitForVolumesToBeMounted(st state.State, requests []volumeRequest) conditions.Condition {\n\treturn &volumesMountedCondition{\n\t\tst:              st,\n\t\trequests:        requests,\n\t\tpendingRequests: slices.Clone(requests),\n\t}\n}\n"
  },
  {
    "path": "internal/app/machined/revert.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta\"\n\tmetaconsts \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nvar revertState state.State\n\nfunc revertSetState(s state.State) {\n\trevertState = s\n}\n\nfunc revertBootloader(ctx context.Context) {\n\tif revertState == nil {\n\t\tlog.Printf(\"no state to revert bootloader\")\n\n\t\treturn\n\t}\n\n\tif err := revertBootloadInternal(ctx, revertState); err != nil {\n\t\tlog.Printf(\"failed to revert bootloader: %s\", err)\n\t}\n}\n\n//nolint:gocyclo\nfunc revertBootloadInternal(ctx context.Context, resourceState state.State) error {\n\tsystemDisk, err := block.GetSystemDisk(ctx, resourceState)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"system disk lookup failed: %w\", err)\n\t}\n\n\tif systemDisk == nil {\n\t\tlog.Printf(\"no system disk found, nothing to revert\")\n\n\t\treturn nil\n\t}\n\n\tmetaState, err := meta.New(ctx, resourceState)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t// no META, no way to revert\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tlabel, ok := metaState.ReadTag(metaconsts.Upgrade)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tif label == \"\" {\n\t\tif _, err = metaState.DeleteTag(ctx, metaconsts.Upgrade); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn metaState.Flush()\n\t}\n\n\tlog.Printf(\"reverting failed upgrade, switching to %q\", label)\n\n\tif err := func() error {\n\t\tconfig, err := bootloader.Probe(systemDisk.DevPath, options.ProbeOptions{})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn config.Revert(systemDisk.DevPath)\n\t}(); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err = metaState.DeleteTag(ctx, metaconsts.Upgrade); err != nil {\n\t\treturn err\n\t}\n\n\treturn metaState.Flush()\n}\n"
  },
  {
    "path": "internal/app/poweroff/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage poweroff\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"slices\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// Action is the action to be performed by the poweroff command.\ntype Action string\n\nconst (\n\t// Shutdown is the action to shutdown the machine.\n\tShutdown Action = \"shutdown\"\n\t// Reboot is the action to reboot the machine.\n\tReboot Action = \"reboot\"\n)\n\n// Main is the entrypoint into /sbin/poweroff.\nfunc Main(args []string) {\n\tctx := context.Background()\n\n\tmd := metadata.Pairs()\n\tauthz.SetMetadata(md, role.MakeSet(role.Admin))\n\tadminCtx := metadata.NewOutgoingContext(ctx, md)\n\n\tclient, err := client.New(\n\t\tadminCtx,\n\t\tclient.WithUnixSocket(constants.MachineSocketPath),\n\t\tclient.WithGRPCDialOptions(\n\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"error while creating machinery client: %s\", err)\n\t}\n\n\tswitch ActionFromArgs(args) {\n\tcase Shutdown:\n\t\terr = client.Shutdown(adminCtx)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"error while sending shutdown command: %s\", err)\n\t\t}\n\tcase Reboot:\n\t\terr = client.Reboot(adminCtx)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"error while sending reboot command: %s\", err)\n\t\t}\n\t}\n}\n\n// ActionFromArgs returns the action to be performed based on the arguments.\nfunc ActionFromArgs(args []string) Action {\n\tif len(args) > 1 {\n\t\tif slices.ContainsFunc(args[1:], func(s string) bool {\n\t\t\treturn s == \"--halt\" || s == \"-H\" || s == \"--poweroff\" || s == \"-P\" || s == \"-p\"\n\t\t}) {\n\t\t\treturn Shutdown\n\t\t}\n\n\t\tif slices.ContainsFunc(args[1:], func(s string) bool {\n\t\t\treturn s == \"--reboot\" || s == \"-r\"\n\t\t}) {\n\t\t\treturn Reboot\n\t\t}\n\t}\n\n\treturn Shutdown\n}\n"
  },
  {
    "path": "internal/app/poweroff/poweroff_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage poweroff_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/app/poweroff\"\n)\n\nfunc TestParseArgs(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname   string\n\t\targs   []string\n\t\taction poweroff.Action\n\t}{\n\t\t{\n\t\t\tname:   \"shutdown no args\",\n\t\t\targs:   []string{\"shutdown\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with reboot\",\n\t\t\targs:   []string{\"shutdown\", \"-r\"},\n\t\t\taction: poweroff.Reboot,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with reboot long\",\n\t\t\targs:   []string{\"shutdown\", \"--reboot\"},\n\t\t\taction: poweroff.Reboot,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff\",\n\t\t\targs:   []string{\"shutdown\", \"-P\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff long\",\n\t\t\targs:   []string{\"shutdown\", \"--poweroff\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff and reboot\",\n\t\t\targs:   []string{\"shutdown\", \"-h\", \"-r\"},\n\t\t\taction: poweroff.Reboot,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff, reboot and timer\",\n\t\t\targs:   []string{\"shutdown\", \"-h\", \"-r\", \"+0\"},\n\t\t\taction: poweroff.Reboot,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff and halt\",\n\t\t\targs:   []string{\"shutdown\", \"-h\", \"-H\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"shutdown with poweroff and halt long\",\n\t\t\targs:   []string{\"shutdown\", \"-h\", \"--halt\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"poweroff no args\",\n\t\t\targs:   []string{\"poweroff\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"poweroff with halt\",\n\t\t\targs:   []string{\"poweroff\", \"--halt\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"poweroff with poweroff\",\n\t\t\targs:   []string{\"poweroff\", \"-p\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"poweroff with poweroff long\",\n\t\t\targs:   []string{\"poweroff\", \"--poweroff\"},\n\t\t\taction: poweroff.Shutdown,\n\t\t},\n\t\t{\n\t\t\tname:   \"poweroff with reboot\",\n\t\t\targs:   []string{\"poweroff\", \"--reboot\"},\n\t\t\taction: poweroff.Reboot,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\taction := poweroff.ActionFromArgs(tt.args)\n\t\t\tif action != tt.action {\n\t\t\t\tt.Errorf(\"expected %q, got %q\", tt.action, action)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/resources/access.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package resources contains shared implementation of COSI resource API.\npackage resources\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// AccessPolicy defines the access policy for resources accessed via the API.\nfunc AccessPolicy(st state.State) state.FilteringRule {\n\treturn func(ctx context.Context, access state.Access) error {\n\t\tif !access.Verb.Readonly() {\n\t\t\treturn status.Error(codes.PermissionDenied, \"write access is not allowed\")\n\t\t}\n\n\t\trd, err := safe.StateGet[*meta.ResourceDefinition](ctx, st, resource.NewMetadata(meta.NamespaceName, meta.ResourceDefinitionType, strings.ToLower(access.ResourceType), resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn status.Error(codes.PermissionDenied, fmt.Sprintf(\"resource type %q is not supported\", access.ResourceType))\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\troles := authz.GetRoles(ctx)\n\t\tspec := rd.TypedSpec()\n\n\t\tswitch spec.Sensitivity {\n\t\tcase meta.Sensitive:\n\t\t\tif !roles.Includes(role.Admin) {\n\t\t\t\treturn authz.ErrNotAuthorized\n\t\t\t}\n\t\tcase meta.NonSensitive:\n\t\t\t// nothing\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected sensitivity %q\", spec.Sensitivity)\n\t\t}\n\n\t\t_, err = safe.StateGet[*meta.Namespace](ctx, st, resource.NewMetadata(meta.NamespaceName, meta.NamespaceType, access.ResourceNamespace, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn status.Error(codes.PermissionDenied, fmt.Sprintf(\"namespace %q is not supported\", access.ResourceNamespace))\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/app/storaged/server.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package internal contains server implementation.\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\t\"golang.org/x/sys/unix\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/partition\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Server implements storage.StorageService.\n//\n// It is only kept here for compatibility purposes, proper API is to query `block.Disk` resources.\ntype Server struct {\n\tstorage.UnimplementedStorageServiceServer\n\n\tController      runtime.Controller\n\tMaintenanceMode bool\n}\n\n// Disks implements storage.StorageService.\nfunc (s *Server) Disks(ctx context.Context, in *emptypb.Empty) (reply *storage.DisksResponse, err error) {\n\tst := s.Controller.Runtime().State().V1Alpha2().Resources()\n\n\tsystemDisk, err := safe.StateGetByID[*block.SystemDisk](ctx, st, block.SystemDiskID)\n\tif err != nil && !state.IsNotFoundError(err) {\n\t\treturn nil, err\n\t}\n\n\tdisks, err := safe.StateListAll[*block.Disk](ctx, st)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdiskConv := func(d *block.Disk) *storage.Disk {\n\t\tvar diskType storage.Disk_DiskType\n\n\t\tswitch {\n\t\tcase d.TypedSpec().CDROM:\n\t\t\tdiskType = storage.Disk_CD\n\t\tcase d.TypedSpec().Transport == \"nvme\":\n\t\t\tdiskType = storage.Disk_NVME\n\t\tcase d.TypedSpec().Transport == \"mmc\":\n\t\t\tdiskType = storage.Disk_SD\n\t\tcase d.TypedSpec().Rotational:\n\t\t\tdiskType = storage.Disk_HDD\n\t\tcase d.TypedSpec().Transport != \"\":\n\t\t\tdiskType = storage.Disk_SSD\n\t\t}\n\n\t\treturn &storage.Disk{\n\t\t\tDeviceName: filepath.Join(\"/dev\", d.Metadata().ID()),\n\t\t\tModel:      d.TypedSpec().Model,\n\t\t\tSize:       d.TypedSpec().Size,\n\t\t\tSerial:     d.TypedSpec().Serial,\n\t\t\tModalias:   d.TypedSpec().Modalias,\n\t\t\tWwid:       d.TypedSpec().WWID,\n\t\t\tUuid:       d.TypedSpec().UUID,\n\t\t\tType:       diskType,\n\t\t\tBusPath:    d.TypedSpec().BusPath,\n\t\t\tSystemDisk: systemDisk != nil && d.Metadata().ID() == systemDisk.TypedSpec().DiskID,\n\t\t\tSubsystem:  d.TypedSpec().SubSystem,\n\t\t\tReadonly:   d.TypedSpec().Readonly,\n\t\t}\n\t}\n\n\treply = &storage.DisksResponse{\n\t\tMessages: []*storage.Disks{\n\t\t\t{\n\t\t\t\tDisks: safe.ToSlice(disks, diskConv),\n\t\t\t},\n\t\t},\n\t}\n\n\treturn reply, nil\n}\n\n// BlockDeviceWipe implements storage.StorageService.\n//\n// It allows to wipe unused block devices, for blockdevices in use (volumes), use a different method.\nfunc (s *Server) BlockDeviceWipe(ctx context.Context, req *storage.BlockDeviceWipeRequest) (*storage.BlockDeviceWipeResponse, error) {\n\t// the storage server is included both into machined and maintenance service\n\t// in apid/machined mode, the normal authz checks are used before reaching this method\n\t// in maintenance mode, we allow this method to be accessible, as it only allows to wipe block devices\n\t//\n\t// validate the list of devices\n\tfor _, deviceRequest := range req.GetDevices() {\n\t\tif err := s.validateDeviceForWipe(ctx, deviceRequest.GetDevice(), deviceRequest.GetSkipVolumeCheck(), deviceRequest.GetSkipSecondaryCheck()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// perform the actual wipe\n\tfor _, deviceRequest := range req.GetDevices() {\n\t\tif err := s.wipeDevice(deviceRequest.GetDevice(), deviceRequest.GetMethod(), deviceRequest.GetDropPartition()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &storage.BlockDeviceWipeResponse{\n\t\tMessages: []*storage.BlockDeviceWipe{\n\t\t\t{},\n\t\t},\n\t}, nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (s *Server) validateDeviceForWipe(ctx context.Context, deviceName string, skipVolumeCheck, skipSecondaryCheck bool) error {\n\t// first, resolve the blockdevice and figure out what type it is\n\tst := s.Controller.Runtime().State().V1Alpha2().Resources()\n\n\tblockdevice, err := safe.StateGetByID[*block.Device](ctx, st, deviceName)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn status.Errorf(codes.NotFound, \"blockdevice %q not found\", deviceName)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tvar parent string\n\n\tdeviceType := blockdevice.TypedSpec().Type\n\n\tswitch deviceType {\n\tcase block.DeviceTypeDisk: // supported\n\tcase block.DeviceTypePartition: // supported\n\t\tparent = blockdevice.TypedSpec().Parent\n\tdefault:\n\t\treturn status.Errorf(codes.InvalidArgument, \"blockdevice %q is of unsupported type %q\", deviceName, deviceType)\n\t}\n\n\t// check the disk (or parent)\n\tvar disk *block.Disk\n\n\tif parent != \"\" {\n\t\tdisk, err = safe.StateGetByID[*block.Disk](ctx, st, parent)\n\t} else {\n\t\tdisk, err = safe.StateGetByID[*block.Disk](ctx, st, deviceName)\n\t}\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get disk (or parent) for %q: %w\", deviceName, err)\n\t}\n\n\tif disk.TypedSpec().Readonly {\n\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is read-only\", deviceName)\n\t}\n\n\tif disk.TypedSpec().CDROM {\n\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is a CD-ROM\", deviceName)\n\t}\n\n\t// secondaries check\n\tif !skipSecondaryCheck {\n\t\tswitch deviceType {\n\t\tcase block.DeviceTypeDisk: // for disks, check secondaries even if the partition is used as secondary (track via Disk resource)\n\t\t\tdisks, err := safe.StateListAll[*block.Disk](ctx, st)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor disk := range disks.All() {\n\t\t\t\tif slices.Index(disk.TypedSpec().SecondaryDisks, deviceName) != -1 {\n\t\t\t\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is in use by disk %q\", deviceName, disk.Metadata().ID())\n\t\t\t\t}\n\t\t\t}\n\t\tcase block.DeviceTypePartition: // for partitions, check secondaries only if the partition is used as a secondary\n\t\t\tblockdevices, err := safe.StateListAll[*block.Device](ctx, st)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor blockdevice := range blockdevices.All() {\n\t\t\t\tif slices.Index(blockdevice.TypedSpec().Secondaries, deviceName) != -1 {\n\t\t\t\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is in use by blockdevice %q\", deviceName, blockdevice.Metadata().ID())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// volume in use checks\n\tif !skipVolumeCheck {\n\t\tvolumeStatuses, err := safe.StateListAll[*block.VolumeStatus](ctx, st)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor volumeStatus := range volumeStatuses.All() {\n\t\t\tfor _, location := range []string{\n\t\t\t\tfilepath.Base(volumeStatus.TypedSpec().Location),\n\t\t\t\tfilepath.Base(volumeStatus.TypedSpec().MountLocation),\n\t\t\t} {\n\t\t\t\tfor _, dev := range []string{deviceName, parent} {\n\t\t\t\t\tif dev == \"\" || location == \"\" {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif location == dev {\n\t\t\t\t\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is in use by volume %q\", dev, volumeStatus.Metadata().ID())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif filepath.Base(volumeStatus.TypedSpec().ParentLocation) == deviceName {\n\t\t\t\treturn status.Errorf(codes.FailedPrecondition, \"blockdevice %q is in use by volume %q\", deviceName, volumeStatus.Metadata().ID())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *Server) findParentDevice(deviceName string) (string, int, error) {\n\tst := s.Controller.Runtime().State().V1Alpha2().Resources()\n\n\tblockdevice, err := safe.StateGetByID[*block.Device](context.Background(), st, deviceName)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}\n\n\tif blockdevice.TypedSpec().Type == block.DeviceTypePartition {\n\t\treturn blockdevice.TypedSpec().Parent, blockdevice.TypedSpec().PartitionNumber, nil\n\t}\n\n\treturn \"\", 0, nil\n}\n\n// wipeDevice wipes the block device with the given method.\n//\n//nolint:gocyclo,cyclop\nfunc (s *Server) wipeDevice(deviceName string, method storage.BlockDeviceWipeDescriptor_Method, dropPartition bool) error {\n\tparentName, partitionNumber, err := s.findParentDevice(deviceName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar parentBd *blockdev.Device\n\n\tif parentName != \"\" {\n\t\tparentBd, err = blockdev.NewFromPath(filepath.Join(\"/dev\", parentName), blockdev.OpenForWrite())\n\t\tif err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to open block device %q: %v\", parentName, err)\n\t\t}\n\n\t\tdefer parentBd.Close() //nolint:errcheck\n\t}\n\n\tbd, err := blockdev.NewFromPath(filepath.Join(\"/dev\", deviceName),\n\t\tblockdev.OpenForWrite(),\n\t\tblockdev.OpenAssertNotMounted(),\n\t)\n\tif err != nil {\n\t\tif errors.Is(err, unix.EBUSY) {\n\t\t\treturn status.Errorf(codes.FailedPrecondition, \"block device %q is mounted or in use\", deviceName)\n\t\t}\n\n\t\treturn status.Errorf(codes.Internal, \"failed to open block device %q: %v\", deviceName, err)\n\t}\n\n\tdefer bd.Close() //nolint:errcheck\n\n\t// lock the parent device always (if available)\n\tif parentBd != nil {\n\t\tlog.Printf(\"locking parent block device %q\", parentName)\n\n\t\tif err = parentBd.Lock(true); err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to lock parent block device %q: %v\", parentName, err)\n\t\t}\n\n\t\tdefer parentBd.Unlock() //nolint:errcheck\n\t} else {\n\t\tlog.Printf(\"locking block device %q\", deviceName)\n\n\t\tif err = bd.Lock(true); err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to lock block device %q: %v\", deviceName, err)\n\t\t}\n\n\t\tdefer bd.Unlock() //nolint:errcheck\n\t}\n\n\tswitch method {\n\tcase storage.BlockDeviceWipeDescriptor_ZEROES:\n\t\tlog.Printf(\"wiping block device %q with zeroes\", deviceName)\n\n\t\tmethod, err := bd.Wipe()\n\t\tif err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to wipe block device %q: %v\", deviceName, err)\n\t\t}\n\n\t\tlog.Printf(\"block device %q wiped with method %q\", deviceName, method)\n\tcase storage.BlockDeviceWipeDescriptor_FAST:\n\t\tlog.Printf(\"wiping block device %q with fast method\", deviceName)\n\n\t\tif err = partition.WipeWithSignatures(bd, deviceName, log.Printf); err != nil {\n\t\t\treturn status.Error(codes.Internal, err.Error())\n\t\t}\n\tdefault:\n\t\treturn status.Errorf(codes.InvalidArgument, \"unsupported wipe method %s\", method)\n\t}\n\n\tif dropPartition && parentBd != nil && partitionNumber != 0 {\n\t\t// first, close the blockdevice, otherwise the partition table cannot be modified\n\t\tif err = bd.Close(); err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to close block device %q: %v\", deviceName, err)\n\t\t}\n\n\t\tgptdev, err := gpt.DeviceFromBlockDevice(parentBd)\n\t\tif err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to get GPT device: %v\", err)\n\t\t}\n\n\t\tpt, err := gpt.Read(gptdev)\n\t\tif err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to read GPT table: %v\", err)\n\t\t}\n\n\t\tif err = pt.DeletePartition(partitionNumber - 1); err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to delete partition: %v\", err)\n\t\t}\n\n\t\tif err = pt.Write(); err != nil {\n\t\t\treturn status.Errorf(codes.Internal, \"failed to write GPT table: %v\", err)\n\t\t}\n\n\t\tlog.Printf(\"deleted partition %d from block device %q\", partitionNumber, parentName)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/app/syslogd/internal/parser/parse.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package parser provides a syslog parser that can parse both RFC3164 and RFC5424 with best effort.\npackage parser\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/jeromer/syslogparser\"\n\t\"github.com/jeromer/syslogparser/rfc3164\"\n\t\"github.com/jeromer/syslogparser/rfc5424\"\n)\n\n// Parse parses a syslog message and returns a json encoded representation of the message.\n// If an RFC3164 message is detected and there is no hostname field in the message,\n// the hostname field is set to \"localhost\".\nfunc Parse(b []byte) (string, error) {\n\t// Detect the RFC version\n\trfc, err := syslogparser.DetectRFC(b)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvar parser syslogparser.LogParser\n\n\tswitch rfc {\n\tcase syslogparser.RFC_3164:\n\t\tinput := slices.Clone(b)\n\n\t\ttagPresent, hostnamePresent := rfc3164ContainsTagHostname(b)\n\n\t\tif !tagPresent {\n\t\t\tinput = enhanceRFC3164WithTag(b)\n\t\t}\n\n\t\tparser = rfc3164.NewParser(input)\n\n\t\tif !hostnamePresent {\n\t\t\tparser.WithHostname(\"localhost\")\n\t\t}\n\tcase syslogparser.RFC_5424:\n\t\tparser = rfc5424.NewParser(b)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported RFC version: %v\", rfc)\n\t}\n\n\tif err = parser.Parse(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmsg, err := json.Marshal(parser.Dump())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn string(msg), nil\n}\n\nfunc rfc3164ContainsTagHostname(buf []byte) (bool, bool) {\n\tindx := bytes.Index(buf, []byte(`]:`)) //nolint:modernize\n\tif indx == -1 {\n\t\treturn false, false\n\t}\n\n\t// handle case when timestamp is of the format `<6>Mar  3 12:55:18`\n\tif len(bytes.Split(buf[:indx], []byte(`  `))) > 1 {\n\t\treturn true, false\n\t}\n\n\treturn true, bytes.Count(buf[:indx], []byte(` `)) > 3\n}\n\nfunc enhanceRFC3164WithTag(buf []byte) []byte {\n\tvar count int\n\n\tspaces := 3\n\n\tsingleDigitDayIndex := bytes.Index(buf, []byte(`  `))\n\tif singleDigitDayIndex != -1 && singleDigitDayIndex < 8 {\n\t\tspaces = 4\n\t}\n\n\ti := bytes.IndexFunc(buf, func(r rune) bool {\n\t\tif r == rune(' ') {\n\t\t\tcount++\n\t\t}\n\n\t\tif count == spaces {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t},\n\t)\n\n\tinitial := buf[:i]\n\tremaining := buf[i:]\n\n\tvar syslogBytes bytes.Buffer\n\n\tsyslogBytes.Write(initial)\n\tsyslogBytes.WriteString(\" unknown:\")\n\tsyslogBytes.Write(remaining)\n\n\treturn syslogBytes.Bytes()\n}\n"
  },
  {
    "path": "internal/app/syslogd/internal/parser/parse_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// package parser provides a syslog parser that can parse both RFC3164 and RFC5424 with best effort.\npackage parser_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/syslogd/internal/parser\"\n)\n\nfunc TestParser(t *testing.T) {\n\tyear := time.Now().Year()\n\n\tfor _, tc := range []struct {\n\t\tname     string\n\t\tinput    []byte\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"RFC3164 without tag and hostname\",\n\t\t\tinput:    []byte(`<4>Feb 16 17:54:19 time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup`),\n\t\t\texpected: fmt.Sprintf(`{\"content\":\"time=\\\"2024-02-16T17:54:19.857755073Z\\\" level=warning msg=\\\"Could not add /dev/mshv to the devices cgroup\",\"facility\":0,\"hostname\":\"localhost\",\"priority\":4,\"severity\":4,\"tag\":\"unknown\",\"timestamp\":\"%d-02-16T17:54:19Z\"}`, year), //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname:     \"RFC3164 timestamp contains single digit day\",\n\t\t\tinput:    []byte(`<6>Mar  3 12:55:18 syslogd_test[834097]: Hello, syslogd!`),\n\t\t\texpected: fmt.Sprintf(`{\"content\":\"Hello, syslogd!\",\"facility\":0,\"hostname\":\"localhost\",\"priority\":6,\"severity\":6,\"tag\":\"syslogd_test\",\"timestamp\":\"%d-03-03T12:55:18Z\"}`, year),\n\t\t},\n\t\t{\n\t\t\tname:     \"RFC3164 timestamp contains single digit day & without tag and hostname\",\n\t\t\tinput:    []byte(`<6>Mar  3 12:55:18 Hello, syslogd!`),\n\t\t\texpected: fmt.Sprintf(`{\"content\":\"Hello, syslogd!\",\"facility\":0,\"hostname\":\"localhost\",\"priority\":6,\"severity\":6,\"tag\":\"unknown\",\"timestamp\":\"%d-03-03T12:55:18Z\"}`, year),\n\t\t},\n\t\t{\n\t\t\tname:     \"RFC3164 without hostname\",\n\t\t\tinput:    []byte(`<4>Feb 16 17:54:19 kata[2569]: time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup`),\n\t\t\texpected: fmt.Sprintf(`{\"content\":\"time=\\\"2024-02-16T17:54:19.857755073Z\\\" level=warning msg=\\\"Could not add /dev/mshv to the devices cgroup\",\"facility\":0,\"hostname\":\"localhost\",\"priority\":4,\"severity\":4,\"tag\":\"kata\",\"timestamp\":\"%d-02-16T17:54:19Z\"}`, year), //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname:     \"RFC3164 with hostname\",\n\t\t\tinput:    []byte(`<4>Feb 16 17:54:19 hostname kata[2569]: time=\"2024-02-16T17:54:19.857755073Z\" level=warning msg=\"Could not add /dev/mshv to the devices cgroup`),\n\t\t\texpected: fmt.Sprintf(`{\"content\":\"time=\\\"2024-02-16T17:54:19.857755073Z\\\" level=warning msg=\\\"Could not add /dev/mshv to the devices cgroup\",\"facility\":0,\"hostname\":\"hostname\",\"priority\":4,\"severity\":4,\"tag\":\"kata\",\"timestamp\":\"%d-02-16T17:54:19Z\"}`, year), //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname:     \"RFC5424\",\n\t\t\tinput:    []byte(`<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"] An application event log entry...`),\n\t\t\texpected: `{\"app_name\":\"evntslog\",\"facility\":20,\"hostname\":\"mymachine.example.com\",\"message\":\"An application event log entry...\",\"msg_id\":\"ID47\",\"priority\":165,\"proc_id\":\"-\",\"severity\":5,\"structured_data\":\"[exampleSDID@32473 iut=\\\"3\\\" eventSource=\\\"Application\\\" eventID=\\\"1011\\\"]\",\"timestamp\":\"2003-10-11T22:14:15.003Z\",\"version\":1}`, //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tparsedJSON, err := parser.Parse(tc.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tc.expected, parsedJSON)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/syslogd/syslogd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package syslogd provides a syslogd service that listens on a unix socket\npackage syslogd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/syslogd/internal/parser\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Main is an entrypoint to the API service.\nfunc Main(ctx context.Context, _ runtime.Runtime, logWriter io.Writer) error {\n\treturn Run(ctx, logWriter, constants.SyslogListenSocketPath)\n}\n\n// Run starts the syslogd service.\nfunc Run(ctx context.Context, logWriter io.Writer, listenSocketPath string) error {\n\tunixAddr, err := net.ResolveUnixAddr(\"unixgram\", listenSocketPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconnection, err := net.ListenUnixgram(\"unixgram\", unixAddr)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = connection.SetReadBuffer(65536); err != nil {\n\t\treturn fmt.Errorf(\"failed to set read buffer: %w\", err)\n\t}\n\n\tbuf := make([]byte, 1024)\n\n\tgo func(con *net.UnixConn) {\n\t\tfor {\n\t\t\tn, err := con.Read(buf)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsyslogJSON, err := parser.Parse(buf[:n])\n\t\t\tif err != nil { // if the message is not a valid syslog message, skip it\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfmt.Fprintln(logWriter, syslogJSON)\n\t\t}\n\t}(connection)\n\n\t<-ctx.Done()\n\n\treturn connection.Close()\n}\n"
  },
  {
    "path": "internal/app/syslogd/syslogd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage syslogd_test\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"log/syslog\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/syslogd\"\n)\n\ntype chanWriter struct {\n\tch chan []byte\n}\n\nfunc (w *chanWriter) Write(p []byte) (n int, err error) {\n\tw.ch <- p\n\n\treturn len(p), nil\n}\n\nfunc TestParsing(t *testing.T) {\n\tch := chanWriter{\n\t\tch: make(chan []byte),\n\t}\n\n\tctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)\n\n\tdefer cancel()\n\n\tsocketPath := t.TempDir() + \"/syslogd.sock\"\n\n\terrChan := make(chan error)\n\n\tgo func() {\n\t\terrChan <- syslogd.Run(ctx, &ch, socketPath)\n\t}()\n\n\tassert.Eventually(t, func() bool {\n\t\tif _, err := os.Stat(socketPath); err == nil {\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}, 1*time.Second, 100*time.Millisecond)\n\n\t// Send a message to the syslogd service\n\tsyslog, err := syslog.Dial(\"unixgram\", socketPath, syslog.LOG_INFO, \"syslogd_test\")\n\trequire.NoError(t, err)\n\n\t_, err = syslog.Write([]byte(\"Hello, syslogd!\"))\n\trequire.NoError(t, err)\n\n\tdefer syslog.Close() //nolint:errcheck\n\n\tselect {\n\tcase msg := <-ch.ch:\n\t\tvar parsed map[string]any\n\n\t\trequire.NoError(t, json.Unmarshal(msg, &parsed))\n\n\t\t// {\"content\":\"Hello, syslogd!\\n\",\"facility\":0,\"hostname\":\"localhost\",\"priority\":6,\"severity\":6,\"tag\":\"syslogd_test\",\"timestamp\":\"2024-02-20T00:20:55Z\"\n\t\tassert.Equal(t, \"syslogd_test\", parsed[\"tag\"])\n\t\tassert.Equal(t, \"localhost\", parsed[\"hostname\"])\n\t\tassert.Equal(t, float64(6), parsed[\"priority\"])\n\t\tassert.Equal(t, float64(6), parsed[\"severity\"])\n\t\tassert.Equal(t, float64(0), parsed[\"facility\"])\n\t\tassert.Equal(t, \"Hello, syslogd!\\n\", parsed[\"content\"])\n\t\tassert.NotEmpty(t, parsed[\"timestamp\"])\n\tcase <-ctx.Done():\n\t\trequire.Fail(t, \"timed out waiting for message\")\n\t}\n\n\tcancel()\n\n\trequire.NoError(t, <-errChan)\n}\n"
  },
  {
    "path": "internal/app/trustd/internal/provider/provider.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package provider provides TLS config for client & server.\npackage provider\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tstdlibtls \"crypto/tls\"\n\tstdx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/tls\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// TLSConfig provides client & server TLS configs for trustd.\ntype TLSConfig struct {\n\tcertificateProvider *certificateProvider\n\n\twatchCh <-chan state.Event\n}\n\n// NewTLSConfig builds provider from configuration and endpoints.\nfunc NewTLSConfig(ctx context.Context, resources state.State) (*TLSConfig, error) {\n\twatchCh := make(chan state.Event)\n\n\tif err := resources.Watch(ctx, resource.NewMetadata(secrets.NamespaceName, secrets.TrustdType, secrets.TrustdID, resource.VersionUndefined), watchCh); err != nil {\n\t\treturn nil, fmt.Errorf(\"error setting up watch: %w\", err)\n\t}\n\n\t// wait for the first event to set up certificate provider\n\tprovider := &certificateProvider{}\n\n\tfor {\n\t\tvar event state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tcase event = <-watchCh:\n\t\t}\n\n\t\tswitch event.Type {\n\t\tcase state.Created, state.Updated:\n\t\t\t// expected\n\t\tcase state.Destroyed, state.Bootstrapped, state.Noop:\n\t\t\t// ignore, we'll get another event\n\t\t\tcontinue\n\t\tcase state.Errored:\n\t\t\treturn nil, fmt.Errorf(\"error watching for trustd certificates: %w\", event.Error)\n\t\t}\n\n\t\ttrustdCerts := event.Resource.(*secrets.Trustd) //nolint:forcetypeassert\n\n\t\tif err := provider.Update(trustdCerts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &TLSConfig{\n\t\t\tcertificateProvider: provider,\n\t\t\twatchCh:             watchCh,\n\t\t}, nil\n\t}\n}\n\n// Watch for updates to trustd certificates.\nfunc (tlsConfig *TLSConfig) Watch(ctx context.Context) error {\n\tfor {\n\t\tvar event state.Event\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase event = <-tlsConfig.watchCh:\n\t\t}\n\n\t\tswitch event.Type {\n\t\tcase state.Created, state.Updated:\n\t\t\t// expected\n\t\tcase state.Destroyed, state.Bootstrapped, state.Noop:\n\t\t\t// ignore, we'll get another event\n\t\t\tcontinue\n\t\tcase state.Errored:\n\t\t\tlog.Printf(\"error watching for trustd certificates: %s\", event.Error)\n\t\t}\n\n\t\ttrustdCerts := event.Resource.(*secrets.Trustd) //nolint:forcetypeassert\n\n\t\tif err := tlsConfig.certificateProvider.Update(trustdCerts); err != nil {\n\t\t\treturn fmt.Errorf(\"failed updating cert: %w\", err)\n\t\t}\n\t}\n}\n\n// ServerConfig generates server-side tls.Config.\nfunc (tlsConfig *TLSConfig) ServerConfig() (*stdlibtls.Config, error) {\n\tca, err := tlsConfig.certificateProvider.GetCA()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get root CA: %w\", err)\n\t}\n\n\treturn tls.New(\n\t\ttls.WithClientAuthType(tls.ServerOnly),\n\t\ttls.WithCACertPEM(ca),\n\t\ttls.WithServerCertificateProvider(tlsConfig.certificateProvider),\n\t)\n}\n\ntype certificateProvider struct {\n\tmu sync.Mutex\n\n\tca         []byte\n\tcaCertPool *stdx509.CertPool\n\n\tserverCert *stdlibtls.Certificate\n}\n\nfunc (p *certificateProvider) Update(trustdCerts *secrets.Trustd) error {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tp.ca = bytes.Join(\n\t\txslices.Map(\n\t\t\ttrustdCerts.TypedSpec().AcceptedCAs,\n\t\t\tfunc(cert *x509.PEMEncodedCertificate) []byte {\n\t\t\t\treturn cert.Crt\n\t\t\t},\n\t\t),\n\t\tnil,\n\t)\n\n\tp.caCertPool = stdx509.NewCertPool()\n\tif !p.caCertPool.AppendCertsFromPEM(p.ca) {\n\t\treturn fmt.Errorf(\"failed to parse root CA\")\n\t}\n\n\tserverCert, err := stdlibtls.X509KeyPair(trustdCerts.TypedSpec().Server.Crt, trustdCerts.TypedSpec().Server.Key)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse server cert and key into a TLS Certificate: %w\", err)\n\t}\n\n\tp.serverCert = &serverCert\n\n\treturn nil\n}\n\nfunc (p *certificateProvider) GetCA() ([]byte, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.ca, nil\n}\n\nfunc (p *certificateProvider) GetCACertPool() (*stdx509.CertPool, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.caCertPool, nil\n}\n\nfunc (p *certificateProvider) GetCertificate(h *stdlibtls.ClientHelloInfo) (*stdlibtls.Certificate, error) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\treturn p.serverCert, nil\n}\n\nfunc (p *certificateProvider) GetClientCertificate(*stdlibtls.CertificateRequestInfo) (*stdlibtls.Certificate, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "internal/app/trustd/internal/reg/reg.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage reg\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\tstdx509 \"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"log\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/peer\"\n\t\"google.golang.org/grpc/status\"\n\n\tsecurityapi \"github.com/siderolabs/talos/pkg/machinery/api/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\n// Registrator is the concrete type that implements the factory.Registrator and\n// securityapi.SecurityServiceServer interfaces.\ntype Registrator struct {\n\tsecurityapi.UnimplementedSecurityServiceServer\n\n\tResources state.State\n}\n\n// Register implements the factory.Registrator interface.\n//\n//nolint:interfacer\nfunc (r *Registrator) Register(s *grpc.Server) {\n\tsecurityapi.RegisterSecurityServiceServer(s, r)\n}\n\n// Certificate implements the securityapi.SecurityServer interface.\n//\n// This API is called by Talos worker nodes to request a server certificate for apid running on the node.\n// Control plane nodes generate certificates (client and server) directly from machine config PKI.\nfunc (r *Registrator) Certificate(ctx context.Context, in *securityapi.CertificateRequest) (resp *securityapi.CertificateResponse, err error) {\n\tremotePeer, ok := peer.FromContext(ctx)\n\tif !ok {\n\t\treturn nil, status.Error(codes.PermissionDenied, \"peer not found\")\n\t}\n\n\tosRoot, err := safe.StateGet[*secrets.OSRoot](ctx, r.Resources, resource.NewMetadata(secrets.NamespaceName, secrets.OSRootType, secrets.OSRootID, resource.VersionUndefined))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode and validate CSR\n\tcsrPemBlock, _ := pem.Decode(in.Csr)\n\tif csrPemBlock == nil {\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"failed to decode CSR\")\n\t}\n\n\trequest, err := stdx509.ParseCertificateRequest(csrPemBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"failed to parse CSR: %s\", err)\n\t}\n\n\tlog.Printf(\"received CSR signing request from %s: subject %s dns names %s addresses %s\", remotePeer.Addr, request.Subject, request.DNSNames, request.IPAddresses)\n\n\t// allow only server auth certificates\n\tx509Opts := []x509.Option{\n\t\tx509.KeyUsage(stdx509.KeyUsageDigitalSignature),\n\t\tx509.ExtKeyUsage([]stdx509.ExtKeyUsage{stdx509.ExtKeyUsageServerAuth}),\n\t}\n\n\t// don't allow any certificates which can be used for client authentication\n\t//\n\t// we don't return an error here, as otherwise workers running old versions of Talos\n\t// will fail to provision client certificate and will never launch apid\n\t//\n\t// instead, the returned certificate will be rejected when being used\n\tif len(request.Subject.Organization) > 0 {\n\t\tlog.Printf(\"removing client auth organization from CSR: %s\", request.Subject.Organization)\n\n\t\tx509Opts = append(x509Opts, x509.OverrideSubject(func(subject *pkix.Name) {\n\t\t\tsubject.Organization = nil\n\t\t}))\n\t}\n\n\t// TODO: Verify that the request is coming from the IP address declared in\n\t// the CSR.\n\tsigned, err := x509.NewCertificateFromCSRBytes(\n\t\tosRoot.TypedSpec().IssuingCA.Crt,\n\t\tosRoot.TypedSpec().IssuingCA.Key,\n\t\tin.Csr,\n\t\tx509Opts...,\n\t)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Internal, \"failed to sign CSR: %s\", err)\n\t}\n\n\tresp = &securityapi.CertificateResponse{\n\t\tCa: bytes.Join(\n\t\t\txslices.Map(\n\t\t\t\tosRoot.TypedSpec().AcceptedCAs,\n\t\t\t\tfunc(cert *x509.PEMEncodedCertificate) []byte {\n\t\t\t\t\treturn cert.Crt\n\t\t\t\t},\n\t\t\t),\n\t\t\tnil,\n\t\t),\n\t\tCrt: signed.X509CertificatePEM,\n\t}\n\n\treturn resp, nil\n}\n"
  },
  {
    "path": "internal/app/trustd/internal/reg/reg_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage reg_test\n\nimport (\n\t\"context\"\n\tstdx509 \"crypto/x509\"\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/internal/app/trustd/internal/reg\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/security\"\n\tgensecrets \"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nfunc TestCertificate(t *testing.T) {\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tca, err := gensecrets.NewTalosCA(time.Now())\n\trequire.NoError(t, err)\n\n\tosRoot := secrets.NewOSRoot(secrets.OSRootID)\n\tosRoot.TypedSpec().IssuingCA = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: ca.CrtPEM,\n\t\tKey: ca.KeyPEM,\n\t}\n\tosRoot.TypedSpec().AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t{\n\t\t\tCrt: ca.CrtPEM,\n\t\t},\n\t}\n\trequire.NoError(t, resources.Create(ctx, osRoot))\n\n\tctx = peer.NewContext(ctx, &peer.Peer{\n\t\tAddr: &net.TCPAddr{\n\t\t\tIP:   netip.MustParseAddr(\"127.0.0.1\").AsSlice(),\n\t\t\tPort: 30000,\n\t\t},\n\t})\n\n\tr := &reg.Registrator{\n\t\tResources: resources,\n\t}\n\n\tfor _, tt := range []struct {\n\t\tname       string\n\t\tcsrSetters []x509.Option\n\t}{\n\t\t{\n\t\t\tname: \"server certificate\",\n\t\t\tcsrSetters: []x509.Option{\n\t\t\t\tx509.IPAddresses([]net.IP{netip.MustParseAddr(\"10.5.0.4\").AsSlice()}),\n\t\t\t\tx509.DNSNames([]string{\"talos-default-worker-1\"}),\n\t\t\t\tx509.CommonName(\"talos-default-worker-1\"),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"attempt at client certificate\",\n\t\t\tcsrSetters: []x509.Option{\n\t\t\t\tx509.CommonName(\"talos-default-worker-1\"),\n\t\t\t\tx509.Organization(string(role.Impersonator)),\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar (\n\t\t\t\tserverCSR  *x509.CertificateSigningRequest\n\t\t\t\tserverCert *x509.PEMEncodedCertificateAndKey\n\t\t\t)\n\n\t\t\tserverCSR, serverCert, err = x509.NewEd25519CSRAndIdentity(tt.csrSetters...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresp, err := r.Certificate(ctx, &security.CertificateRequest{\n\t\t\t\tCsr: serverCSR.X509CertificateRequestPEM,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, resp.Ca, ca.CrtPEM)\n\n\t\t\tserverCert.Crt = resp.Crt\n\n\t\t\tcert, err := serverCert.GetCert()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, stdx509.KeyUsageDigitalSignature, cert.KeyUsage)\n\t\t\tassert.Equal(t, []stdx509.ExtKeyUsage{stdx509.ExtKeyUsageServerAuth}, cert.ExtKeyUsage)\n\t\t\tassert.Equal(t, \"talos-default-worker-1\", cert.Subject.CommonName)\n\t\t\tassert.Equal(t, []string(nil), cert.Subject.Organization)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/app/trustd/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package trustd implements trustd functionality.\npackage trustd\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/client\"\n\tdebug \"github.com/siderolabs/go-debug\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/siderolabs/talos/internal/app/trustd/internal/provider\"\n\t\"github.com/siderolabs/talos/internal/app/trustd/internal/reg\"\n\t\"github.com/siderolabs/talos/pkg/grpc/factory\"\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/auth/basic\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/startup\"\n)\n\nfunc runDebugServer(ctx context.Context) {\n\tconst debugAddr = \":9983\"\n\n\tdebugLogFunc := func(msg string) {\n\t\tlog.Print(msg)\n\t}\n\n\tif err := debug.ListenAndServe(ctx, debugAddr, debugLogFunc); err != nil {\n\t\tlog.Fatalf(\"failed to start debug server: %s\", err)\n\t}\n}\n\n// Main is the entrypoint into trustd.\nfunc Main() {\n\tif err := trustdMain(); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc trustdMain() error {\n\tctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)\n\tdefer cancel()\n\n\tlog.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime)\n\n\tflag.Parse()\n\n\tgo runDebugServer(ctx)\n\n\tstartup.LimitMaxProcs(constants.TrustdMaxProcs)\n\n\tvar err error\n\n\truntimeConn, err := grpc.NewClient(\n\t\t\"unix://\"+constants.TrustdRuntimeSocketPath,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t\tgrpc.WithNoProxy(),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dial runtime connection: %w\", err)\n\t}\n\n\tstateClient := v1alpha1.NewStateClient(runtimeConn)\n\tresources := state.WrapCore(client.NewAdapter(stateClient))\n\n\ttlsConfig, err := provider.NewTLSConfig(ctx, resources)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create remote certificate provider: %w\", err)\n\t}\n\n\tserverTLSConfig, err := tlsConfig.ServerConfig()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create OS-level TLS configuration: %w\", err)\n\t}\n\n\tcreds := basic.NewTokenCredentialsDynamic(tokenGetter(resources))\n\n\tnetworkListener, err := factory.NewListener(\n\t\tctx,\n\t\tfactory.Port(constants.TrustdPort),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating listener: %w\", err)\n\t}\n\n\tnetworkServer := factory.NewServer(\n\t\t&reg.Registrator{Resources: resources},\n\t\tfactory.WithDefaultLog(),\n\t\tfactory.WithUnaryInterceptor(creds.UnaryInterceptor()),\n\t\tfactory.ServerOptions(\n\t\t\tgrpc.Creds(\n\t\t\t\tcredentials.NewTLS(serverTLSConfig),\n\t\t\t),\n\t\t),\n\t)\n\n\terrGroup, ctx := errgroup.WithContext(ctx)\n\n\terrGroup.Go(func() error {\n\t\treturn networkServer.Serve(networkListener)\n\t})\n\n\terrGroup.Go(func() error {\n\t\treturn tlsConfig.Watch(ctx)\n\t})\n\n\terrGroup.Go(func() error {\n\t\t<-ctx.Done()\n\n\t\tshutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer shutdownCancel()\n\n\t\tfactory.ServerGracefulStop(networkServer, shutdownCtx)\n\n\t\treturn nil\n\t})\n\n\treturn errGroup.Wait()\n}\n\nfunc tokenGetter(state state.State) basic.TokenGetterFunc {\n\treturn func(ctx context.Context) (string, error) {\n\t\tosRoot, err := safe.StateGet[*secrets.OSRoot](ctx, state, resource.NewMetadata(secrets.NamespaceName, secrets.OSRootType, secrets.OSRootID, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treturn osRoot.TypedSpec().Token, nil\n\t}\n}\n"
  },
  {
    "path": "internal/integration/api/api.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package api provides API integration tests for Talos\npackage api\n\nimport \"github.com/stretchr/testify/suite\"\n\nvar allSuites []suite.TestingSuite\n\n// GetAllSuites returns all the suites for API test.\n//\n// Depending on build tags, this might return different lists.\nfunc GetAllSuites() []suite.TestingSuite {\n\treturn allSuites\n}\n"
  },
  {
    "path": "internal/integration/api/apid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/dustin/go-humanize\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\tcfg \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// ApidSuite verifies Discovery API.\ntype ApidSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ApidSuite) SuiteName() string {\n\treturn \"api.ApidSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ApidSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ApidSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestControlPlaneRouting verify access to all nodes via each control plane node as an endpoints.\nfunc (suite *ApidSuite) TestControlPlaneRouting() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"information about routable endpoints is not available\")\n\t}\n\n\tif suite.APISuite.Endpoint != \"\" {\n\t\tsuite.T().Skip(\"test skipped as custom endpoint is set\")\n\t}\n\n\tendpoints := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, endpoint := range endpoints {\n\t\tsuite.Run(endpoint, func() {\n\t\t\tcli, err := client.New(suite.ctx,\n\t\t\t\tclient.WithConfig(suite.Talosconfig),\n\t\t\t\tclient.WithEndpoints(endpoint),\n\t\t\t)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tdefer cli.Close() //nolint:errcheck\n\n\t\t\t// try with multiple nodes\n\t\t\tresp, err := cli.Version(client.WithNodes(suite.ctx, nodes...))\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Assert().Len(resp.Messages, len(nodes))\n\n\t\t\t// try with 'nodes' but a single node at a time\n\t\t\tfor _, node := range nodes {\n\t\t\t\tresp, err = cli.Version(client.WithNodes(suite.ctx, node))\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\t\t\t}\n\n\t\t\t// try with 'node'\n\t\t\tfor _, node := range nodes {\n\t\t\t\tresp, err = cli.Version(client.WithNode(suite.ctx, node))\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\t\t\t}\n\n\t\t\t// try without any nodes set\n\t\t\tresp, err = cli.Version(suite.ctx)\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\t\t})\n\t}\n}\n\n// TestWorkerNoRouting verifies that worker nodes perform no routing.\nfunc (suite *ApidSuite) TestWorkerNoRouting() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"information about routable endpoints is not available\")\n\t}\n\n\tif suite.APISuite.Endpoint != \"\" {\n\t\tsuite.T().Skip(\"test skipped as custom endpoint is set\")\n\t}\n\n\tendpoints := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker)\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tif len(endpoints) == 0 {\n\t\tsuite.T().Skip(\"no worker nodes found\")\n\t}\n\n\t_, err := safe.StateGetByID[*network.NfTablesChain](client.WithNode(suite.ctx, endpoints[0]), suite.Client.COSI, \"ingress\")\n\tif err == nil {\n\t\tsuite.T().Skip(\"worker nodes have ingress firewall enabled, skipping\")\n\t}\n\n\tfor _, endpoint := range endpoints {\n\t\tsuite.Run(endpoint, func() {\n\t\t\tcli, err := client.New(suite.ctx,\n\t\t\t\tclient.WithConfig(suite.Talosconfig),\n\t\t\t\tclient.WithEndpoints(endpoint),\n\t\t\t)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tdefer cli.Close() //nolint:errcheck\n\n\t\t\t// try every other node but the one we're connected to\n\t\t\t// there should be no routing\n\t\t\tfor _, node := range nodes {\n\t\t\t\tif node == endpoint {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// 'nodes'\n\t\t\t\t_, err = cli.Version(client.WithNodes(suite.ctx, node))\n\t\t\t\tsuite.Require().Error(err)\n\t\t\t\tsuite.Assert().Equal(codes.PermissionDenied, client.StatusCode(err))\n\n\t\t\t\t// 'node'\n\t\t\t\t_, err = cli.Version(client.WithNode(suite.ctx, node))\n\t\t\t\tsuite.Require().Error(err)\n\t\t\t\tsuite.Assert().Equal(codes.PermissionDenied, client.StatusCode(err))\n\t\t\t}\n\n\t\t\t// try with 'nodes' but a single node (node itself)\n\t\t\tresp, err := cli.Version(client.WithNodes(suite.ctx, endpoint))\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\n\t\t\t// try with 'node' (node itself)\n\t\t\tresp, err = cli.Version(client.WithNode(suite.ctx, endpoint))\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\n\t\t\t// try without any nodes set\n\t\t\tresp, err = cli.Version(suite.ctx)\n\t\t\tsuite.Require().NoError(err)\n\t\t\tsuite.Assert().Len(resp.Messages, 1)\n\t\t})\n\t}\n}\n\n// TestBigPayload verifies that big payloads are handled correctly.\nfunc (suite *ApidSuite) TestBigPayload() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing big payload on node %s\", node)\n\n\t// we are going to simulate a big payload by making machine configuration big enough\n\tcfg, err := safe.StateGetByID[*config.MachineConfig](nodeCtx, suite.Client.COSI, config.ActiveID)\n\tsuite.Require().NoError(err)\n\n\toriginalCfg, err := cfg.Container().Bytes()\n\tsuite.Require().NoError(err)\n\n\t// the config is encoded twice in the resource gRPC message, so ensure that we can get to the one third of the size\n\tconst targetConfigSize = constants.GRPCMaxMessageSize / 3\n\n\tsuite.T().Logf(\"original config size: %d (%s), target size is %d (%s)\",\n\t\tlen(originalCfg), humanize.Bytes(uint64(len(originalCfg))), targetConfigSize, humanize.Bytes(uint64(targetConfigSize)),\n\t)\n\n\tbytesToAdd := targetConfigSize - len(originalCfg)\n\tif bytesToAdd <= 0 {\n\t\tsuite.T().Skip(\"configuration is already big enough\")\n\t}\n\n\tconst commentLine = \"# this is a comment line added to make the config bigger and bigger and bigger and bigger all the way\\n\"\n\n\tnewConfig := slices.Concat(originalCfg, bytes.Repeat([]byte(commentLine), bytesToAdd/len(commentLine)+1))\n\n\tsuite.Assert().Greater(len(newConfig), targetConfigSize)\n\n\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: newConfig,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\tsuite.Require().NoError(err)\n\n\t// now get the machine configuration back several times\n\tfor range 5 {\n\t\tcfg, err = safe.StateGetByID[*config.MachineConfig](nodeCtx, suite.Client.COSI, config.ActiveID)\n\t\tsuite.Require().NoError(err)\n\n\t\t// check that the configuration is the same\n\t\tnewCfg, err := cfg.Container().Bytes()\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Assert().Equal(newConfig, newCfg)\n\t}\n\n\t// revert the configuration\n\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: originalCfg,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\tsuite.Require().NoError(err)\n}\n\n// TestPKIMismatch verifies that PKI mismatch is handled correctly.\nfunc (suite *ApidSuite) TestPKIMismatch() {\n\tbundle, err := secrets.NewBundle(secrets.NewClock(), cfg.TalosVersionCurrent)\n\tsuite.Require().NoError(err)\n\n\tcert, err := bundle.GenerateTalosAPIClientCertificate(role.MakeSet(role.Admin))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(suite.Talosconfig.Contexts, suite.Talosconfig.Context)\n\n\tcaCrt, err := base64.StdEncoding.DecodeString(suite.Talosconfig.Contexts[suite.Talosconfig.Context].CA)\n\tsuite.Require().NoError(err)\n\n\twrongConfig := clientconfig.NewConfig(\"wrong\", suite.Talosconfig.Contexts[suite.Talosconfig.Context].Endpoints, caCrt, cert)\n\n\twrongClient, err := client.New(suite.ctx, client.WithConfig(wrongConfig))\n\tsuite.Require().NoError(err)\n\n\t_, err = wrongClient.Version(suite.ctx)\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.Unavailable, client.StatusCode(err))\n\tsuite.Assert().ErrorContains(err, \"remote error: tls: unknown certificate authority\")\n\n\tsuite.Require().NoError(wrongClient.Close())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ApidSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/apply-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tmc \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// Sysctl to use for testing config changes.\n// This sysctl should:\n//\n//   - default to a non-Go-null value in the kernel\n//\n//   - not be defined by the default Talos configuration\n//\n//   - be generally harmless\nconst applyConfigTestSysctl = \"net.ipv6.conf.all.accept_ra_mtu\"\n\nconst applyConfigTestSysctlVal = \"1\"\n\nconst applyConfigNoRebootTestSysctl = \"fs.file-max\"\n\nconst applyConfigNoRebootTestSysctlVal = \"500000\"\n\nconst assertRebootedRebootTimeout = 10 * time.Minute\n\n// ApplyConfigSuite ...\ntype ApplyConfigSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ApplyConfigSuite) SuiteName() string {\n\treturn \"api.ApplyConfigSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ApplyConfigSuite) SetupTest() {\n\t// make sure we abort at some point in time, but give enough room for Recovers\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ApplyConfigSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestApply verifies the apply config API.\nfunc (suite *ApplyConfigSuite) TestApply() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot\")\n\t}\n\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q\", node)\n\n\tcfgDataOut := suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\tif cfg.MachineConfig.MachineSysctls == nil {\n\t\t\tcfg.MachineConfig.MachineSysctls = make(map[string]string)\n\t\t}\n\n\t\tcfg.MachineConfig.MachineSysctls[applyConfigTestSysctl] = applyConfigTestSysctlVal\n\t})\n\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t_, err = suite.Client.ApplyConfiguration(\n\t\t\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\t\tData: cfgDataOut,\n\t\t\t\t\tMode: machineapi.ApplyConfigurationRequest_REBOOT,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to apply configuration (node %q): %w\", node, err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}, assertRebootedRebootTimeout,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\t// Verify configuration change\n\tvar newProvider config.Provider\n\n\tsuite.Require().NoErrorf(\n\t\tretry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(\n\t\t\tfunc() error {\n\t\t\t\tnewProvider, err = suite.ReadConfigFromNode(nodeCtx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t), \"failed to read updated configuration from node %q\", node,\n\t)\n\n\tsuite.Assert().Equal(\n\t\tnewProvider.Machine().Sysctls()[applyConfigTestSysctl],\n\t\tapplyConfigTestSysctlVal,\n\t\t\"expected sysctl %s to be set to %s, got %s on node %q\",\n\t\tapplyConfigTestSysctl, applyConfigTestSysctlVal, newProvider.Machine().Sysctls()[applyConfigTestSysctl], node,\n\t)\n}\n\n// TestApplyNoOpCRIPatch verifies the apply config with no-op CRI patch.\nfunc (suite *ApplyConfigSuite) TestApplyNoOpCRIPatch() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot\")\n\t}\n\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q\", node)\n\n\t// this CRI patch is a no-op, as NRI is already disabled by default, this verifies that CRI config generation handles it correctly.\n\tcfgDataOut := suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\tcfg.MachineConfig.MachineFiles = xslices.Filter(cfg.MachineConfig.MachineFiles, func(file *v1alpha1.MachineFile) bool {\n\t\t\treturn file.FilePath != \"/etc/cri/conf.d/20-customization.part\"\n\t\t})\n\n\t\tcfg.MachineConfig.MachineFiles = append(cfg.MachineConfig.MachineFiles,\n\t\t\t&v1alpha1.MachineFile{\n\t\t\t\tFilePath: \"/etc/cri/conf.d/20-customization.part\",\n\t\t\t\tFileOp:   \"create\",\n\t\t\t\tFileContent: `[plugins]\n          [plugins.\"io.containerd.nri.v1.nri\"]\n             disable = true`,\n\t\t\t},\n\t\t)\n\t})\n\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t_, err = suite.Client.ApplyConfiguration(\n\t\t\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\t\tData: cfgDataOut,\n\t\t\t\t\tMode: machineapi.ApplyConfigurationRequest_REBOOT,\n\t\t\t\t},\n\t\t\t)\n\t\t\tsuite.Assert().NoErrorf(err, \"failed to apply configuration (node %q)\", node)\n\n\t\t\treturn nil\n\t\t}, assertRebootedRebootTimeout,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\t// revert the patch\n\tprovider, err = suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q\", node)\n\n\t// this CRI patch is a no-op, as NRI is already disabled by default, this verifies that CRI config generation handles it correctly.\n\tcfgDataOut = suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\tcfg.MachineConfig.MachineFiles = xslices.Filter(cfg.MachineConfig.MachineFiles, func(file *v1alpha1.MachineFile) bool {\n\t\t\treturn file.FilePath != \"/etc/cri/conf.d/20-customization.part\"\n\t\t})\n\t})\n\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t_, err = suite.Client.ApplyConfiguration(\n\t\t\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\t\tData: cfgDataOut,\n\t\t\t\t\tMode: machineapi.ApplyConfigurationRequest_REBOOT,\n\t\t\t\t},\n\t\t\t)\n\t\t\tsuite.Assert().NoErrorf(err, \"failed to apply configuration (node %q)\", node)\n\n\t\t\treturn nil\n\t\t}, assertRebootedRebootTimeout,\n\t\tsuite.CleanupFailedPods,\n\t)\n}\n\n// TestApplyWithoutReboot verifies the apply config API without reboot.\nfunc (suite *ApplyConfigSuite) TestApplyWithoutReboot() {\n\tfor _, mode := range []machineapi.ApplyConfigurationRequest_Mode{\n\t\tmachineapi.ApplyConfigurationRequest_AUTO,\n\t\tmachineapi.ApplyConfigurationRequest_STAGED,\n\t} {\n\t\tsuite.WaitForBootDone(suite.ctx)\n\n\t\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\t\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\t\tsuite.Require().NoError(err, \"failed to read existing config from node %q\", node)\n\n\t\tcfgDataOut := suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\t\tif cfg.MachineConfig.MachineSysctls == nil {\n\t\t\t\tcfg.MachineConfig.MachineSysctls = make(map[string]string)\n\t\t\t}\n\n\t\t\tcfg.MachineConfig.MachineSysctls[applyConfigNoRebootTestSysctl] = applyConfigNoRebootTestSysctlVal\n\t\t})\n\n\t\t_, err = suite.Client.ApplyConfiguration(\n\t\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\tData: cfgDataOut,\n\t\t\t\tMode: mode,\n\t\t\t},\n\t\t)\n\t\tsuite.Require().NoError(err, \"failed to apply deferred configuration (node %q)\", node)\n\n\t\t// Verify configuration change\n\t\tvar newProvider config.Provider\n\n\t\tnewProvider, err = suite.ReadConfigFromNode(nodeCtx)\n\n\t\tsuite.Require().NoError(err, \"failed to read updated configuration from node %q\", node)\n\n\t\tif mode == machineapi.ApplyConfigurationRequest_AUTO {\n\t\t\tsuite.Assert().Equal(\n\t\t\t\tnewProvider.Machine().Sysctls()[applyConfigNoRebootTestSysctl],\n\t\t\t\tapplyConfigNoRebootTestSysctlVal,\n\t\t\t)\n\t\t} else {\n\t\t\tsuite.Assert().NotContains(newProvider.Machine().Sysctls(), applyConfigNoRebootTestSysctl)\n\t\t}\n\n\t\tcfgDataOut = suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\t\t// revert back\n\t\t\tdelete(cfg.MachineConfig.MachineSysctls, applyConfigNoRebootTestSysctl)\n\t\t})\n\n\t\t_, err = suite.Client.ApplyConfiguration(\n\t\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\tData: cfgDataOut,\n\t\t\t\tMode: mode,\n\t\t\t},\n\t\t)\n\t\tsuite.Require().NoError(err, \"failed to apply deferred configuration (node %q)\", node)\n\t}\n}\n\n// TestApplyConfigRotateEncryptionSecrets verify key rotation by sequential apply config calls.\nfunc (suite *ApplyConfigSuite) TestApplyConfigRotateEncryptionSecrets() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tephemeralCfg, _ := provider.Volumes().ByName(constants.EphemeralPartitionLabel)\n\tencryption := ephemeralCfg.Encryption()\n\n\tif encryption == nil {\n\t\tsuite.T().Skip(\"skipped in not encrypted mode\")\n\t}\n\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tsuite.T().Logf(\"testing encryption key rotation on node %s\", node)\n\n\tcfg, ok := encryption.(blockcfg.EncryptionSpec)\n\tsuite.Require().True(ok, \"expected blockcfg.EncryptionSpec, got %T\", encryption)\n\n\texisting := cfg.EncryptionKeys[0]\n\tslot := existing.Slot() + 1\n\n\tkeySets := [][]blockcfg.EncryptionKey{\n\t\t{\n\t\t\texisting,\n\t\t\t{\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"AlO93jayutOpsDxDS=-\",\n\t\t\t\t},\n\t\t\t\tKeySlot: slot,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t{\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"AlO93jayutOpsDxDS=-\",\n\t\t\t\t},\n\t\t\t\tKeySlot: slot,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\texisting,\n\t\t\t{\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"AlO93jayutOpsDxDS=-\",\n\t\t\t\t},\n\t\t\t\tKeySlot: slot,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\texisting,\n\t\t\t{\n\t\t\t\tKeyNodeID: &blockcfg.EncryptionKeyNodeID{},\n\t\t\t\tKeySlot:   slot,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t{\n\t\t\t\tKeyNodeID: &blockcfg.EncryptionKeyNodeID{},\n\t\t\t\tKeySlot:   slot,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, keys := range keySets {\n\t\tsuite.T().Logf(\"applying encryption keys %s on node %s\", toJSONString(suite.T(), keys), node)\n\n\t\t// prepare a patch to apply, first removing existing keys\n\t\tremoveKeysPatch := map[string]any{\n\t\t\t\"apiVersion\": \"v1alpha1\",\n\t\t\t\"kind\":       \"VolumeConfig\",\n\t\t\t\"name\":       constants.EphemeralPartitionLabel,\n\t\t\t\"encryption\": map[string]any{\n\t\t\t\t\"keys\": map[string]any{\n\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tnewEphemeralCfg := blockcfg.NewVolumeConfigV1Alpha1()\n\t\tnewEphemeralCfg.MetaName = constants.EphemeralPartitionLabel\n\t\tnewEphemeralCfg.EncryptionSpec.EncryptionKeys = keys\n\n\t\t// right now, patching encryption keys doesn't reboot and doesn't rotate the secrets either\n\t\tsuite.PatchMachineConfig(nodeCtx, removeKeysPatch, newEphemeralCfg)\n\n\t\tsuite.AssertRebooted(\n\t\t\tsuite.ctx, node,\n\t\t\tfunc(nodeCtx context.Context) error {\n\t\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t\t}, assertRebootedRebootTimeout,\n\t\t\tsuite.CleanupFailedPods,\n\t\t)\n\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\t\t// Verify configuration change\n\t\tvar newProvider config.Provider\n\n\t\tsuite.Require().NoError(\n\t\t\tretry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(\n\t\t\t\tfunc() error {\n\t\t\t\t\tnewProvider, err = suite.ReadConfigFromNode(nodeCtx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t), \"failed to read updated configuration from node %q\", node,\n\t\t)\n\n\t\tnewEphemeral, _ := newProvider.Volumes().ByName(constants.EphemeralPartitionLabel)\n\t\te := newEphemeral.Encryption()\n\n\t\tfor i, k := range e.Keys() {\n\t\t\tif keys[i].KeyStatic == nil {\n\t\t\t\tsuite.Require().Nil(k.Static())\n\t\t\t} else {\n\t\t\t\tsuite.Require().Equal(keys[i].Static().Key(), k.Static().Key())\n\t\t\t}\n\n\t\t\tif keys[i].KeyNodeID == nil {\n\t\t\t\tsuite.Require().Nil(k.NodeID())\n\t\t\t} else {\n\t\t\t\tsuite.Require().NotNil(keys[i].NodeID())\n\t\t\t}\n\n\t\t\tsuite.Require().Equal(keys[i].Slot(), k.Slot())\n\t\t\tsuite.Require().Equal(keys[i].Slot(), k.Slot())\n\t\t}\n\n\t\tsuite.WaitForBootDone(suite.ctx)\n\n\t\t// verify that encryption key sync has no failures\n\t\trtestutils.AssertAll(nodeCtx, suite.T(), suite.Client.COSI, func(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tsuite.Assert().Contains([]block.VolumePhase{block.VolumePhaseReady, block.VolumePhaseMissing}, vs.TypedSpec().Phase)\n\t\t\tsuite.Assert().Empty(vs.TypedSpec().EncryptionFailedSyncs)\n\t\t})\n\t}\n}\n\nfunc toJSONString(t *testing.T, v any) string {\n\tt.Helper()\n\n\tout, err := json.Marshal(v)\n\trequire.NoError(t, err)\n\n\treturn string(out)\n}\n\n// TestApplyNoReboot verifies the apply config API fails if NoReboot mode is requested on a field that can not be applied immediately.\nfunc (suite *ApplyConfigSuite) TestApplyNoReboot() {\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q: %s\", node, err)\n\n\tcfgDataOut := suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\t// this won't be possible without a reboot\n\t\tcfg.MachineConfig.MachineType = \"controlplane\"\n\t})\n\n\t_, err = suite.Client.ApplyConfiguration(\n\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\tData: cfgDataOut,\n\t\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t\t},\n\t)\n\tsuite.Require().Error(err)\n\n\tsuite.Require().Equal(codes.InvalidArgument, client.StatusCode(err))\n}\n\n// TestApplyDryRun verifies the apply config API with dry run enabled.\nfunc (suite *ApplyConfigSuite) TestApplyDryRun() {\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q: %s\", node, err)\n\n\tcfgDataOut := suite.PatchV1Alpha1Config(provider, func(cfg *v1alpha1.Config) {\n\t\t// this won't be possible without a reboot\n\t\tcfg.MachineConfig.MachineFiles = append(cfg.MachineConfig.MachineFiles,\n\t\t\t&v1alpha1.MachineFile{\n\t\t\t\tFileContent:     \"test\",\n\t\t\t\tFilePermissions: v1alpha1.FileMode(os.ModePerm),\n\t\t\t\tFilePath:        \"/var/lib/test\",\n\t\t\t\tFileOp:          \"create\",\n\t\t\t},\n\t\t)\n\t})\n\n\treply, err := suite.Client.ApplyConfiguration(\n\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\tData:   cfgDataOut,\n\t\t\tMode:   machineapi.ApplyConfigurationRequest_AUTO,\n\t\t\tDryRun: true,\n\t\t},\n\t)\n\n\tsuite.Require().NoErrorf(err, \"failed to apply configuration (node %q): %s\", node, err)\n\tsuite.Assert().Contains(reply.Messages[0].ModeDetails, \"Dry run summary\")\n}\n\n// TestApplyDryRunDocuments verifies the apply config API with multi doc and dry run enabled.\nfunc (suite *ApplyConfigSuite) TestApplyDryRunDocuments() {\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q: %s\", node, err)\n\n\tkmsg := runtime.NewKmsgLogV1Alpha1()\n\tkmsg.MetaName = \"omni-kmsg\"\n\tkmsg.KmsgLogURL.URL = ensure.Value(url.Parse(\"tcp://[fdae:41e4:649b:9303::1]:8092\"))\n\n\tcont, err := container.New(provider.RawV1Alpha1(), kmsg)\n\tsuite.Require().NoErrorf(err, \"failed to create container: %s\", err)\n\n\tcfgDataOut, err := cont.Bytes()\n\tsuite.Require().NoErrorf(err, \"failed to marshal container: %s\", err)\n\n\treply, err := suite.Client.ApplyConfiguration(\n\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\tData:   cfgDataOut,\n\t\t\tMode:   machineapi.ApplyConfigurationRequest_AUTO,\n\t\t\tDryRun: true,\n\t\t},\n\t)\n\n\tsuite.Require().NoErrorf(err, \"failed to apply configuration (node %q): %s\", node, err)\n\tsuite.Assert().Contains(reply.Messages[0].ModeDetails, \"Dry run summary\")\n\tsuite.Assert().Contains(reply.Messages[0].ModeDetails, \"omni-kmsg\")\n\tsuite.Assert().Contains(reply.Messages[0].ModeDetails, \"tcp://[fdae:41e4:649b:9303::1]:8092\")\n}\n\n// TestApplyTry applies the config in try mode with a short timeout.\nfunc (suite *ApplyConfigSuite) TestApplyTry() {\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tdummyCfg := network.NewDummyLinkConfigV1Alpha1(\"dummy-try\")\n\n\tsuite.PatchMachineConfigWithModeSetter(nodeCtx, func(acr *machineapi.ApplyConfigurationRequest) {\n\t\tacr.Mode = machineapi.ApplyConfigurationRequest_TRY\n\t\tacr.TryModeTimeout = durationpb.New(time.Second * 1)\n\t}, dummyCfg)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoErrorf(err, \"failed to read existing config from node %q\", node)\n\n\tassertDummyInterface := func(provider config.Provider) bool {\n\t\tdocs := provider.Documents()\n\n\t\tfor _, doc := range docs {\n\t\t\tif doc.Kind() == network.DummyLinkKind {\n\t\t\t\tif namedDocument, ok := doc.(configconfig.NamedDocument); ok && namedDocument.Name() == \"dummy-try\" {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false\n\t}\n\n\tsuite.Assert().Truef(assertDummyInterface(provider), \"dummy interface wasn't found\")\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, mc.ActiveID, func(r *mc.MachineConfig, asrt *assert.Assertions) {\n\t\tasrt.False(assertDummyInterface(r.Provider()))\n\t})\n}\n\n// TestApplyRemovingV1Alpha1 verifies the apply config doesn't accept removal of v1alpha1 config.\nfunc (suite *ApplyConfigSuite) TestApplyRemovingV1Alpha1() {\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.T().Logf(\"applying configuration to node %q\", node)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t// create a simple multi-doc config without v1alpha1\n\tcfgDocument := runtime.NewWatchdogTimerV1Alpha1()\n\tcfgDocument.WatchdogDevice = \"/dev/watchdog0\"\n\tcfgDocument.WatchdogTimeout = 120 * time.Second\n\n\tctr, err := container.New(cfgDocument)\n\tsuite.Require().NoError(err, \"failed to create container\")\n\n\tcfgDataOut, err := ctr.Bytes()\n\tsuite.Require().NoError(err, \"failed to marshal container\")\n\n\t// Talos should deny a request that effectively removes the v1alpha1 config\n\t_, err = suite.Client.ApplyConfiguration(\n\t\tnodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\tData: cfgDataOut,\n\t\t\tMode: machineapi.ApplyConfigurationRequest_AUTO,\n\t\t},\n\t)\n\tsuite.Require().Error(err)\n\tsuite.Require().Equal(codes.InvalidArgument, client.StatusCode(err))\n\tsuite.Require().ErrorContains(err, \"the applied machine configuration doesn't contain v1alpha1 config\")\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ApplyConfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/cgroups.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// CGroupsSuite ...\ntype CGroupsSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *CGroupsSuite) SuiteName() string {\n\treturn \"api.CGroupsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *CGroupsSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *CGroupsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestCGroupsVersion tests that cgroups mount match expected version.\nfunc (suite *CGroupsSuite) TestCGroupsVersion() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tstream, err := suite.Client.MachineClient.List(ctx, &machineapi.ListRequest{Root: constants.CgroupMountPath})\n\tsuite.Require().NoError(err)\n\n\tnames := map[string]struct{}{}\n\n\tfor {\n\t\tvar info *machineapi.FileInfo\n\n\t\tinfo, err = stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tnames[filepath.Base(info.Name)] = struct{}{}\n\t}\n\n\tsuite.T().Log(\"detected cgroups v2\")\n\n\tfor _, subpath := range []string{\n\t\t\"cgroup.controllers\",\n\t\t\"cgroup.max.depth\",\n\t\t\"cgroup.max.descendants\",\n\t\t\"cgroup.procs\",\n\t\t\"cgroup.stat\",\n\t\t\"cgroup.subtree_control\",\n\t\t\"cgroup.threads\",\n\t\t\"cpu.stat\",\n\t\t\"cpuset.cpus.effective\",\n\t\t\"cpuset.mems.effective\",\n\t\t\"init\",\n\t\t\"io.stat\",\n\t\t\"kubepods\",\n\t\t\"memory.numa_stat\",\n\t\t\"memory.stat\",\n\t\t\"podruntime\",\n\t\t\"system\",\n\t} {\n\t\tsuite.Assert().Contains(names, subpath)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(CGroupsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/common.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// CommonSuite verifies some default settings such as ulimits.\ntype CommonSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *CommonSuite) SuiteName() string {\n\treturn \"api.CommonSuite\"\n}\n\n// SetupTest ...\nfunc (suite *CommonSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *CommonSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestVirtioModulesLoaded verifies that the virtio modules are loaded.\nfunc (suite *CommonSuite) TestVirtioModulesLoaded() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping virtio test since provisioner is not qemu\")\n\t}\n\n\texpectedVirtIOModules := map[string]string{\n\t\t\"virtio_balloon\":        \"virtio_balloon.ko\",\n\t\t\"virtio_pci\":            \"virtio_pci.ko\",\n\t\t\"virtio_pci_legacy_dev\": \"virtio_pci_legacy_dev.ko\",\n\t\t\"virtio_pci_modern_dev\": \"virtio_pci_modern_dev.ko\",\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.AssertExpectedModules(suite.ctx, node, expectedVirtIOModules)\n}\n\n// TestCommonDefaults verifies that the default ulimits are set.\nfunc (suite *CommonSuite) TestCommonDefaults() {\n\tif suite.Cluster != nil && suite.Cluster.Provisioner() == base.ProvisionerDocker {\n\t\tsuite.T().Skip(\"skipping ulimits test since provisioner is docker\")\n\t}\n\n\texpectedUlimit := `\ncore file size (blocks)         (-c) 0\ndata seg size (kb)              (-d) unlimited\nscheduling priority             (-e) 0\nfile size (blocks)              (-f) unlimited\nmax locked memory (kb)          (-l) 8192\nmax memory size (kb)            (-m) unlimited\nopen files                      (-n) 1048576\nPOSIX message queues (bytes)    (-q) 819200\nreal-time priority              (-r) 0\nstack size (kb)                 (-s) 8192\ncpu time (seconds)              (-t) unlimited\nvirtual memory (kb)             (-v) unlimited\nfile locks                      (-x) unlimited\n`\n\n\tdefaultsTestPodDef, err := suite.NewPod(\"defaults-ulimits-test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(defaultsTestPodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer defaultsTestPodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, stderr, err := defaultsTestPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"ulimit -c -d -e -f -l -m -n -q -r -s -t -v -x\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Equal(strings.TrimPrefix(expectedUlimit, \"\\n\"), stdout)\n}\n\n// TestDNSResolver verifies that external DNS resolving works from a pod.\nfunc (suite *CommonSuite) TestDNSResolver() {\n\tif suite.Airgapped {\n\t\tsuite.T().Skip(\"skipping test in airgapped mode\")\n\t}\n\n\tif suite.Cluster != nil {\n\t\t// cluster should be healthy for kube-dns resolving to work\n\t\tsuite.AssertClusterHealthy(suite.ctx)\n\t}\n\n\tdnsTestPodDef, err := suite.NewPod(\"dns-test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(dnsTestPodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer dnsTestPodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, stderr, err := dnsTestPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"wget -S https://www.google.com/\",\n\t)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Equal(\"\", stdout)\n\tsuite.Assert().Contains(stderr, \"'index.html' saved\")\n\n\tif suite.T().Failed() {\n\t\tsuite.LogPodLogsByLabel(suite.ctx, \"kube-system\", \"k8s-app\", \"kube-dns\")\n\n\t\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\t\tsuite.DumpLogs(suite.ctx, node, \"dns-resolve-cache\", \"google\")\n\t\t}\n\n\t\tsuite.T().FailNow()\n\t}\n\n\t_, stderr, err = dnsTestPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"apk add --update bind-tools\",\n\t)\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Empty(stderr, \"stderr: %s\", stderr)\n\n\tif suite.T().Failed() {\n\t\tsuite.T().FailNow()\n\t}\n\n\tstdout, stderr, err = dnsTestPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"dig really-long-record.dev.siderolabs.io\",\n\t)\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Contains(stdout, \"status: NOERROR\")\n\tsuite.Assert().Contains(stdout, \"ANSWER: 34\")\n\tsuite.Assert().NotContains(stdout, \"status: NXDOMAIN\")\n\tsuite.Assert().Equal(stderr, \"\")\n\n\tif suite.T().Failed() {\n\t\tsuite.T().FailNow()\n\t}\n}\n\n// TestBaseOCISpec verifies that the base OCI spec can be modified.\nfunc (suite *CommonSuite) TestBaseOCISpec() {\n\tif suite.Cluster != nil && suite.Cluster.Provisioner() == base.ProvisionerDocker {\n\t\tsuite.T().Skip(\"skipping ulimits test since provisioner is docker\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tsuite.T().Logf(\"adjusting base OCI specs on %s/%s\", node, nodeName)\n\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\tsuite.PatchMachineConfig(nodeCtx, &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineBaseRuntimeSpecOverrides: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"process\": map[string]any{\n\t\t\t\t\t\t\t\t\"rlimits\": []map[string]any{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"type\": \"RLIMIT_NOFILE\",\n\t\t\t\t\t\t\t\t\t\t\"hard\": 1024,\n\t\t\t\t\t\t\t\t\t\t\"soft\": 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}, assertRebootedRebootTimeout,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tociUlimits1PodDef, err := suite.NewPod(\"oci-ulimits-test-1\")\n\tsuite.Require().NoError(err)\n\n\tociUlimits1PodDef = ociUlimits1PodDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(ociUlimits1PodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer func() { suite.Assert().NoError(ociUlimits1PodDef.Delete(suite.ctx)) }()\n\n\tstdout, stderr, err := ociUlimits1PodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"ulimit -n\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Equal(\"1024\\n\", stdout)\n\n\t// delete immediately, as we're going to reboot the node\n\tsuite.Assert().NoError(ociUlimits1PodDef.Delete(suite.ctx))\n\n\t// revert the patch\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\tsuite.PatchMachineConfig(nodeCtx, map[string]any{\n\t\t\t\t\"machine\": map[string]any{\n\t\t\t\t\t\"baseRuntimeSpecOverrides\": map[string]any{\n\t\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}, assertRebootedRebootTimeout,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tociUlimits2PodDef, err := suite.NewPod(\"oci-ulimits-test-2\")\n\tsuite.Require().NoError(err)\n\n\tociUlimits2PodDef = ociUlimits2PodDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(ociUlimits2PodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer func() { suite.Assert().NoError(ociUlimits2PodDef.Delete(suite.ctx)) }()\n\n\tstdout, stderr, err = ociUlimits2PodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"ulimit -n\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Equal(\"1048576\\n\", stdout)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &CommonSuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nconst (\n\t// NvidiaGPUOperatorChartVersion is the version of the NVIDA device plugin chart to use\n\t// renovate: datasource=helm versioning=helm depName=gpu-operator registryUrl=https://helm.ngc.nvidia.com/nvidia\n\tNvidiaGPUOperatorChartVersion = \"v25.10.1\"\n\t// NvidiaCUDATestImageVersion is the version of the NVIDIA CUDA test image to use\n\t// renovate: datasource=docker versioning=docker depName=nvcr.io/nvidia/k8s/cuda-sample\n\tNvidiaCUDATestImageVersion = \"vectoradd-cuda12.5.0\"\n)\n"
  },
  {
    "path": "internal/integration/api/containers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ContainersSuite ...\ntype ContainersSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ContainersSuite) SuiteName() string {\n\treturn \"api.ContainersSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ContainersSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ContainersSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestSandboxImage verifies sandbox image.\nfunc (suite *ContainersSuite) TestSandboxImage() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tctx := client.WithNode(suite.ctx, node)\n\n\tresp, err := suite.Client.Containers(ctx, constants.K8sContainerdNamespace, common.ContainerDriver_CRI)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().NotEmpty(resp.GetMessages())\n\n\tfor _, message := range resp.GetMessages() {\n\t\tsuite.Assert().NotEmpty(message.GetContainers())\n\n\t\tmatched := false\n\n\t\tfor _, ctr := range message.GetContainers() {\n\t\t\tif ctr.PodId == ctr.Id {\n\t\t\t\tsuite.Assert().Equal(images.DefaultSandboxImage, ctr.Image)\n\n\t\t\t\tmatched = true\n\t\t\t}\n\t\t}\n\n\t\tsuite.Assert().True(matched, \"no pods found, node %s\", node)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ContainersSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// DebugSuite ...\ntype DebugSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *DebugSuite) SuiteName() string {\n\treturn \"api.DebugSuite\"\n}\n\n// SetupTest ...\nfunc (suite *DebugSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *DebugSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestRunAlpine tests running a simple alpine container via DebugService.\nfunc (suite *DebugSuite) TestRunAlpine() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\timage := \"docker.io/library/alpine:3.23\"\n\n\tfor _, driver := range []common.ContainerDriver{common.ContainerDriver_CRI, common.ContainerDriver_CONTAINERD} {\n\t\trcv, err := suite.Client.ImageClient.Pull(ctx, &machine.ImageServicePullRequest{\n\t\t\tContainerd: &common.ContainerdInstance{\n\t\t\t\tDriver:    driver,\n\t\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t\t},\n\t\t\tImageRef: image,\n\t\t})\n\t\tsuite.Require().NoError(err)\n\n\t\tvar pulledImage string\n\n\t\tfor {\n\t\t\tmsg, err := rcv.Recv()\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t}\n\n\t\t\t// ignore progress messages, but the last message should contain the image name\n\t\t\tpulledImage = msg.GetName()\n\t\t}\n\n\t\tcli, err := suite.Client.DebugClient.ContainerRun(ctx)\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(cli.Send(&machine.DebugContainerRunRequest{\n\t\t\tRequest: &machine.DebugContainerRunRequest_Spec{\n\t\t\t\tSpec: &machine.DebugContainerRunRequestSpec{\n\t\t\t\t\tContainerd: &common.ContainerdInstance{\n\t\t\t\t\t\tDriver:    driver,\n\t\t\t\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t\t\t\t},\n\t\t\t\t\tImageName: pulledImage,\n\t\t\t\t\tProfile:   machine.DebugContainerRunRequestSpec_PROFILE_PRIVILEGED,\n\t\t\t\t\tTty:       true,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\n\t\treadUntil := func(needle string) {\n\t\t\tvar out strings.Builder\n\n\t\t\tfor {\n\t\t\t\tmsg, err := cli.Recv()\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tif msg.GetStdoutData() != nil {\n\t\t\t\t\tout.Write(msg.GetStdoutData())\n\t\t\t\t}\n\n\t\t\t\tif strings.Contains(out.String(), needle) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treadUntil(\"/ # \")\n\n\t\tsuite.Require().NoError(cli.Send(&machine.DebugContainerRunRequest{\n\t\t\tRequest: &machine.DebugContainerRunRequest_StdinData{\n\t\t\t\tStdinData: []byte(\"uname\\n\"),\n\t\t\t},\n\t\t}))\n\n\t\treadUntil(\"Linux\")\n\n\t\tsuite.Require().NoError(cli.CloseSend())\n\n\t\tfor {\n\t\t\tmsg, err := cli.Recv()\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tif exitCode, ok := msg.GetResp().(*machine.DebugContainerRunResponse_ExitCode); ok {\n\t\t\t\t// SIGHUP is 128 + 1\n\t\t\t\tsuite.Equal(int32(129), exitCode.ExitCode)\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.T().Logf(\"got extra stdout: %q\", string(msg.GetStdoutData()))\n\t\t}\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DebugSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/discovery.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\n// DiscoverySuite verifies Discovery API.\ntype DiscoverySuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *DiscoverySuite) SuiteName() string {\n\treturn \"api.DiscoverySuite\"\n}\n\n// SetupTest ...\nfunc (suite *DiscoverySuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n\n\t// check that cluster has discovery enabled\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tif !provider.Cluster().Discovery().Enabled() {\n\t\tsuite.T().Skip(\"cluster discovery is disabled\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *DiscoverySuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestMembers checks that `talosctl get members` matches expected cluster discovery.\n//\n//nolint:gocyclo\nfunc (suite *DiscoverySuite) TestMembers() {\n\tnodes := suite.DiscoverNodes(suite.ctx).Nodes()\n\n\texpectedTalosVersion := fmt.Sprintf(\"Talos (%s)\", suite.Version)\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node.InternalIP.String())\n\n\t\tmembers := suite.getMembers(nodeCtx)\n\n\t\tsuite.Assert().Len(members, len(nodes))\n\n\t\t// do basic check against discovered nodes\n\t\tfor _, expectedNode := range nodes {\n\t\t\tnodeAddresses := xslices.Map(expectedNode.IPs, func(t netip.Addr) string {\n\t\t\t\treturn t.String()\n\t\t\t})\n\n\t\t\tfound := false\n\n\t\t\tfor _, member := range members {\n\t\t\t\tmemberAddresses := xslices.Map(member.TypedSpec().Addresses, func(t netip.Addr) string {\n\t\t\t\t\treturn t.String()\n\t\t\t\t})\n\n\t\t\t\tif maps.Contains(xslices.ToSet(memberAddresses), nodeAddresses) {\n\t\t\t\t\tfound = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif found {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsuite.Assert().True(found, \"addr %q\", nodeAddresses)\n\t\t}\n\n\t\t// if cluster information is available, perform additional checks\n\t\tif suite.Cluster == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tmemberByName := xslices.ToMap(members,\n\t\t\tfunc(member *cluster.Member) (string, *cluster.Member) {\n\t\t\t\treturn member.Metadata().ID(), member\n\t\t\t},\n\t\t)\n\n\t\tmemberByIP := make(map[netip.Addr]*cluster.Member)\n\n\t\tfor _, member := range members {\n\t\t\tfor _, addr := range member.TypedSpec().Addresses {\n\t\t\t\tmemberByIP[addr] = member\n\t\t\t}\n\t\t}\n\n\t\tnodesInfo := suite.Cluster.Info().Nodes\n\n\t\tfor _, nodeInfo := range nodesInfo {\n\t\t\tmatchingMember := memberByName[nodeInfo.Name]\n\n\t\t\tvar matchingMemberByIP *cluster.Member\n\n\t\t\tfor _, nodeIP := range nodeInfo.IPs {\n\t\t\t\tmatchingMemberByIP = memberByIP[nodeIP]\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// if hostnames are not set via DHCP, use match by IP\n\t\t\tif matchingMember == nil {\n\t\t\t\tmatchingMember = matchingMemberByIP\n\t\t\t}\n\n\t\t\tsuite.Require().NotNil(matchingMember)\n\n\t\t\tsuite.Assert().Equal(nodeInfo.Type, matchingMember.TypedSpec().MachineType)\n\t\t\tsuite.Assert().Equal(expectedTalosVersion, matchingMember.TypedSpec().OperatingSystem)\n\n\t\t\tfor _, nodeIP := range nodeInfo.IPs {\n\t\t\t\tfound := false\n\n\t\t\t\tfor _, memberAddr := range matchingMember.TypedSpec().Addresses {\n\t\t\t\t\tif memberAddr.Compare(nodeIP) == 0 {\n\t\t\t\t\t\tfound = true\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsuite.Assert().True(found, \"addr %s\", nodeIP)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TestRegistries checks that all registries produce same raw Affiliate data.\nfunc (suite *DiscoverySuite) TestRegistries() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tvar registries []string\n\n\tif provider.Cluster().Discovery().Registries().Kubernetes().Enabled() {\n\t\tregistries = append(registries, \"k8s/\")\n\t}\n\n\tif provider.Cluster().Discovery().Registries().Service().Enabled() {\n\t\tregistries = append(registries, \"service/\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\tmembers := suite.getMembers(nodeCtx)\n\t\tlocalIdentity := suite.getNodeIdentity(nodeCtx)\n\n\t\t// raw affiliates don't contain the local node\n\t\texpectedRawAffiliates := len(registries) * (len(members) - 1)\n\n\t\tvar rawAffiliates []*cluster.Affiliate\n\n\t\tfor range 30 {\n\t\t\trawAffiliates = suite.getAffiliates(nodeCtx, cluster.RawNamespaceName)\n\n\t\t\tif len(rawAffiliates) == expectedRawAffiliates {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.T().Logf(\"waiting for cluster affiliates to be discovered: %d expected, %d found\", expectedRawAffiliates, len(rawAffiliates))\n\n\t\t\ttime.Sleep(2 * time.Second)\n\t\t}\n\n\t\tsuite.Assert().Len(rawAffiliates, expectedRawAffiliates)\n\n\t\trawAffiliatesByID := make(map[string]*cluster.Affiliate)\n\n\t\tfor _, rawAffiliate := range rawAffiliates {\n\t\t\trawAffiliatesByID[rawAffiliate.Metadata().ID()] = rawAffiliate\n\t\t}\n\n\t\t// every member except for local identity member should be discovered via each registry\n\t\tfor _, member := range members {\n\t\t\tif member.TypedSpec().NodeID == localIdentity.TypedSpec().NodeID {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, registry := range registries {\n\t\t\t\trawAffiliate := rawAffiliatesByID[registry+member.TypedSpec().NodeID]\n\t\t\t\tsuite.Require().NotNil(rawAffiliate)\n\n\t\t\t\tstripDomain := func(s string) string { return strings.Split(s, \".\")[0] }\n\n\t\t\t\t// registries can be a bit inconsistent, e.g. whether they report fqdn or just hostname\n\t\t\t\tsuite.Assert().Contains([]string{member.TypedSpec().Hostname, stripDomain(member.TypedSpec().Hostname)}, rawAffiliate.TypedSpec().Hostname)\n\n\t\t\t\tsuite.Assert().Equal(member.TypedSpec().Addresses, rawAffiliate.TypedSpec().Addresses)\n\t\t\t\tsuite.Assert().Equal(member.TypedSpec().OperatingSystem, rawAffiliate.TypedSpec().OperatingSystem)\n\t\t\t\tsuite.Assert().Equal(member.TypedSpec().MachineType, rawAffiliate.TypedSpec().MachineType)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TestKubeSpanPeers verifies that KubeSpan peer specs are populated, and that peer statuses are available.\nfunc (suite *DiscoverySuite) TestKubeSpanPeers() {\n\tif !suite.Capabilities().RunsTalosKernel {\n\t\tsuite.T().Skip(\"not running Talos kernel\")\n\t}\n\n\t// check that cluster has KubeSpan enabled\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tif kubeSpan := provider.NetworkKubeSpanConfig(); kubeSpan == nil || !kubeSpan.Enabled() {\n\t\tsuite.T().Skip(\"KubeSpan is disabled\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\trtestutils.AssertLength[*kubespan.PeerSpec](nodeCtx, suite.T(), suite.Client.COSI, len(nodes)-1)\n\t\trtestutils.AssertLength[*kubespan.PeerStatus](nodeCtx, suite.T(), suite.Client.COSI, len(nodes)-1)\n\n\t\trtestutils.AssertAll(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t\tfunc(status *kubespan.PeerStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(kubespan.PeerStateUp, status.TypedSpec().State)\n\t\t\t\tasrt.False(value.IsZero(status.TypedSpec().Endpoint))\n\t\t\t\tasrt.Greater(status.TypedSpec().ReceiveBytes, int64(0))\n\t\t\t\tasrt.Greater(status.TypedSpec().TransmitBytes, int64(0))\n\t\t\t})\n\t}\n}\n\n// TestKubeSpanExtraEndpoints verifies that KubeSpan peer specs are updated with extra endpoints.\nfunc (suite *DiscoverySuite) TestKubeSpanExtraEndpoints() {\n\tif !suite.Capabilities().RunsTalosKernel {\n\t\tsuite.T().Skip(\"not running Talos kernel\")\n\t}\n\n\t// check that cluster has KubeSpan enabled\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tif kubeSpan := provider.NetworkKubeSpanConfig(); kubeSpan == nil || !kubeSpan.Enabled() {\n\t\tsuite.T().Skip(\"KubeSpan is disabled\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tif len(nodes) < 2 {\n\t\tsuite.T().Skip(\"need at least two nodes for this test\")\n\t}\n\n\tperm := rand.Perm(len(nodes))\n\n\tcheckNode := nodes[perm[0]]\n\ttargetNode := nodes[perm[1]]\n\n\tmockEndpoint := netip.MustParseAddrPort(\"169.254.121.121:5820\")\n\n\t// inject extra endpoint to target node\n\tcfgDocument := network.NewKubespanEndpointsV1Alpha1()\n\tcfgDocument.ExtraAnnouncedEndpointsConfig = []netip.AddrPort{mockEndpoint}\n\n\tsuite.T().Logf(\"injecting extra endpoint %s to node %s\", mockEndpoint, targetNode)\n\tsuite.PatchMachineConfig(client.WithNode(suite.ctx, targetNode), cfgDocument)\n\n\ttargetIdentity, err := safe.ReaderGetByID[*kubespan.Identity](client.WithNode(suite.ctx, targetNode), suite.Client.COSI, kubespan.LocalIdentity)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"checking extra endpoint %s on node %s\", mockEndpoint, checkNode)\n\trtestutils.AssertResources(client.WithNode(suite.ctx, checkNode), suite.T(), suite.Client.COSI, []string{targetIdentity.TypedSpec().PublicKey},\n\t\tfunc(peer *kubespan.PeerSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Contains(peer.TypedSpec().Endpoints, mockEndpoint)\n\t\t},\n\t)\n\n\t// the extra endpoints disappears with a timeout from the discovery service, so can't assert on that\n\tsuite.T().Logf(\"removin extra endpoint %s from node %s\", mockEndpoint, targetNode)\n\tsuite.RemoveMachineConfigDocuments(client.WithNode(suite.ctx, targetNode), cfgDocument.MetaKind)\n}\n\nfunc (suite *DiscoverySuite) getMembers(nodeCtx context.Context) []*cluster.Member {\n\titems, err := safe.StateListAll[*cluster.Member](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\treturn safe.ToSlice(items, func(m *cluster.Member) *cluster.Member { return m })\n}\n\nfunc (suite *DiscoverySuite) getNodeIdentity(nodeCtx context.Context) *cluster.Identity {\n\tidentity, err := safe.StateGet[*cluster.Identity](nodeCtx, suite.Client.COSI, resource.NewMetadata(cluster.NamespaceName, cluster.IdentityType, cluster.LocalIdentity, resource.VersionUndefined))\n\tsuite.Require().NoError(err)\n\n\treturn identity\n}\n\nfunc (suite *DiscoverySuite) getAffiliates(nodeCtx context.Context, namespace resource.Namespace) []*cluster.Affiliate {\n\tvar result []*cluster.Affiliate\n\n\titems, err := safe.StateList[*cluster.Affiliate](nodeCtx, suite.Client.COSI, resource.NewMetadata(namespace, cluster.AffiliateType, \"\", resource.VersionUndefined))\n\tsuite.Require().NoError(err)\n\n\titems.ForEach(func(item *cluster.Affiliate) { result = append(result, item) })\n\n\treturn result\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DiscoverySuite))\n}\n"
  },
  {
    "path": "internal/integration/api/diskusage.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// DiskUsageSuite verifies Logs API.\ntype DiskUsageSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tnodeCtx context.Context //nolint:containedctx\n}\n\n// SuiteName ...\nfunc (suite *DiskUsageSuite) SuiteName() string {\n\treturn \"api.DiskUsageSuite\"\n}\n\n// SetupTest ...\nfunc (suite *DiskUsageSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n\n\tsuite.nodeCtx = client.WithNodes(suite.ctx, suite.RandomDiscoveredNodeInternalIP())\n}\n\n// TearDownTest ...\nfunc (suite *DiskUsageSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestDiskUsageRequests compares results of disk usage requests with different parameters.\nfunc (suite *DiskUsageSuite) TestDiskUsageRequests() {\n\ttype testParams struct {\n\t\trecursionDepth int32\n\t\tall            bool\n\t\tpaths          []string\n\t}\n\n\tdefaultPaths := []string{\n\t\t\"/etc\",\n\t\t\"/bin\",\n\t}\n\n\tcases := []*testParams{\n\t\t{\n\t\t\trecursionDepth: 0,\n\t\t\tall:            false,\n\t\t\tpaths:          defaultPaths,\n\t\t},\n\t\t{\n\t\t\trecursionDepth: 1,\n\t\t\tall:            false,\n\t\t\tpaths:          defaultPaths,\n\t\t},\n\t\t{\n\t\t\trecursionDepth: 0,\n\t\t\tall:            true,\n\t\t\tpaths:          defaultPaths,\n\t\t},\n\t\t{\n\t\t\trecursionDepth: 1,\n\t\t\tall:            true,\n\t\t\tpaths:          defaultPaths,\n\t\t},\n\t\t{\n\t\t\trecursionDepth: 0,\n\t\t\tall:            true,\n\t\t\tpaths:          append([]string{\"/this/is/going/to/fail\"}, defaultPaths...),\n\t\t},\n\t}\n\n\tsizes := map[string]int64{}\n\n\tfor _, params := range cases {\n\t\tlookupPaths := map[string]bool{}\n\t\tfor _, path := range params.paths {\n\t\t\tlookupPaths[path] = true\n\t\t}\n\n\t\tstream, err := suite.Client.DiskUsage(\n\t\t\tsuite.nodeCtx,\n\t\t\t&machineapi.DiskUsageRequest{\n\t\t\t\tPaths:          params.paths,\n\t\t\t\tRecursionDepth: params.recursionDepth,\n\t\t\t\tAll:            params.all,\n\t\t\t},\n\t\t)\n\t\tsuite.Require().NoError(err)\n\n\t\tresponseCount := 0\n\n\t\tfor {\n\t\t\tinfo, err := stream.Recv()\n\t\t\tresponseCount++\n\n\t\t\tif err != nil {\n\t\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t}\n\n\t\t\tif size, ok := sizes[info.Name]; ok {\n\t\t\t\tsuite.Require().EqualValues(size, info.Size)\n\t\t\t}\n\n\t\t\tsizes[info.Name] = info.Size\n\t\t}\n\n\t\tsuite.Require().Greater(responseCount, 1)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DiskUsageSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/dmesg.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// DmesgSuite verifies Dmesg API.\ntype DmesgSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *DmesgSuite) SuiteName() string {\n\treturn \"api.DmesgSuite\"\n}\n\n// SetupTest ...\nfunc (suite *DmesgSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *DmesgSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestNodeHasDmesg verifies that default node has dmesg.\nfunc (suite *DmesgSuite) TestNodeHasDmesg() {\n\tdmesgStream, err := suite.Client.Dmesg(\n\t\tsuite.ctx,\n\t\tfalse,\n\t\tfalse,\n\t)\n\tsuite.Require().NoError(err)\n\n\tlogReader, err := client.ReadStream(dmesgStream)\n\tsuite.Require().NoError(err)\n\n\tn, err := io.Copy(io.Discard, logReader)\n\tsuite.Require().NoError(err)\n\n\t// dmesg shouldn't be empty\n\tsuite.Require().Greater(n, int64(1024))\n}\n\n// TestStreaming verifies that logs are streamed in real-time.\nfunc (suite *DmesgSuite) TestStreaming() {\n\tdmesgStream, err := suite.Client.Dmesg(\n\t\tsuite.ctx,\n\t\ttrue,\n\t\tfalse,\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(dmesgStream.CloseSend())\n\n\trespCh := make(chan *common.Data)\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\tdefer close(respCh)\n\n\t\tfor {\n\t\t\tmsg, err := dmesgStream.Recv()\n\t\t\tif err != nil {\n\t\t\t\terrCh <- err\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trespCh <- msg\n\t\t}\n\t}()\n\n\tdefer func() {\n\t\tsuite.ctxCancel()\n\t\t// drain respCh\n\t\tfor range respCh { //nolint:revive\n\t\t}\n\t}()\n\n\t// drain the stream until flow stops\n\tlogCount := 0\n\nDrainLoop:\n\tfor {\n\t\tselect {\n\t\tcase msg, ok := <-respCh:\n\t\t\tlogCount++\n\n\t\t\tsuite.Require().True(ok)\n\t\t\tsuite.Assert().NotEmpty(msg.Bytes)\n\t\tcase <-time.After(200 * time.Millisecond):\n\t\t\tbreak DrainLoop\n\t\t}\n\t}\n\n\tsuite.Assert().Greater(logCount, 10)\n}\n\n// TestClusterHasDmesg verifies that all the cluster nodes have dmesg.\nfunc (suite *DmesgSuite) TestClusterHasDmesg() {\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\tctx := client.WithNodes(suite.ctx, nodes...)\n\n\tdmesgStream, err := suite.Client.Dmesg(\n\t\tctx,\n\t\tfalse,\n\t\tfalse,\n\t)\n\tsuite.Require().NoError(err)\n\n\tsizeByNode := map[string]int{}\n\n\tfor {\n\t\tmsg, err := dmesgStream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tsuite.Require().NotNil(msg.Metadata)\n\t\tsuite.Assert().Empty(msg.Metadata.Error)\n\n\t\tsizeByNode[msg.Metadata.Hostname] += len(msg.Bytes)\n\t}\n\n\tfor _, node := range nodes {\n\t\tsuite.Assert().Greater(sizeByNode[node], 1024)\n\t}\n\n\tfor node := range sizeByNode {\n\t\tsuite.Assert().Contains(nodes, node)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DmesgSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\truntimecfg \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// EnvironmentSuite verifies Environment API.\ntype EnvironmentSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *EnvironmentSuite) SuiteName() string {\n\treturn \"api.EnvironmentSuite\"\n}\n\n// SetupTest ...\nfunc (suite *EnvironmentSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *EnvironmentSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestEnvironment tests setting environment variables via Environment API.\nfunc (suite *EnvironmentSuite) TestEnvironment() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn suite.validateEnvironment(node, []string{\"TALOS_TEST_ENV=1\"}, false)\n\t}, 5*time.Second, 1*time.Second, \"environment variable was there before apply\")\n\n\tsuite.T().Logf(\"applying environment configuration\")\n\n\tdoc := runtimecfg.NewEnvironmentV1Alpha1()\n\tdoc.EnvironmentVariables = map[string]string{\"TALOS_TEST_ENV\": \"1\"}\n\n\tsuite.PatchMachineConfig(ctx, doc)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn suite.validateEnvironment(node, []string{\"TALOS_TEST_ENV=1\"}, true)\n\t}, 5*time.Second, 1*time.Second, \"environment variable was not set after apply\")\n\n\t// now we want to reboot the node and make sure the env is retained\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn suite.validateEnvironment(node, []string{\"TALOS_TEST_ENV=1\"}, true)\n\t}, 5*time.Second, 1*time.Second, \"environment variable was not retained after reboot\")\n\n\tsuite.T().Logf(\"removing environment configuration\")\n\n\tsuite.RemoveMachineConfigDocuments(ctx, runtimecfg.EnvironmentConfigKind)\n\n\t// now we want to reboot the node and make sure the env is removed\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn suite.validateEnvironment(node, []string{\"TALOS_TEST_ENV=1\"}, false)\n\t}, 5*time.Second, 1*time.Second, \"environment variable was not removed after reboot\")\n}\n\nfunc (suite *EnvironmentSuite) validateEnvironment(node string, expectedVariables []string, shouldContain bool) bool {\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tenv, err := safe.StateGetByID[*runtime.Environment](ctx, suite.Client.COSI, \"machined\")\n\tif err != nil {\n\t\tcode := client.StatusCode(err)\n\n\t\tswitch code { //nolint:exhaustive\n\t\tcase codes.Unavailable, codes.Canceled, codes.NotFound:\n\t\t\treturn false\n\t\t}\n\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tfor _, v := range expectedVariables {\n\t\tif slices.Contains(env.TypedSpec().Variables, v) != shouldContain {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EnvironmentSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/etcd-recover.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// EtcdRecoverSuite ...\ntype EtcdRecoverSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *EtcdRecoverSuite) SuiteName() string {\n\treturn \"api.EtcdRecoverSuite\"\n}\n\n// SetupTest ...\nfunc (suite *EtcdRecoverSuite) SetupTest() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\t// make sure we abort at some point in time, but give enough room for Recovers\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *EtcdRecoverSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestSnapshotRecover snapshot etcd, wipes control plane nodes and recovers etcd from a snapshot.\nfunc (suite *EtcdRecoverSuite) TestSnapshotRecover() {\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot\")\n\t}\n\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)\")\n\t}\n\n\t// 'init' nodes are not compatible with etcd recovery\n\tsuite.Require().Empty(suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeInit))\n\n\tcontrolPlaneNodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\tsuite.Require().NotEmpty(controlPlaneNodes)\n\n\tsnapshotNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\trecoverNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tsuite.T().Logf(\"taking etcd snapshot at node %q\", snapshotNode)\n\n\tvar snapshot bytes.Buffer\n\n\tsuite.Require().NoError(suite.snapshotEtcd(snapshotNode, &snapshot))\n\n\t// leave etcd on all nodes but one\n\tfor _, node := range controlPlaneNodes[1:] {\n\t\tsuite.T().Logf(\"leaving etcd on node %q\", node)\n\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\t_, err := suite.Client.EtcdForfeitLeadership(nodeCtx, &machineapi.EtcdForfeitLeadershipRequest{})\n\t\tsuite.Require().NoError(err)\n\n\t\terr = suite.Client.EtcdLeaveCluster(nodeCtx, &machineapi.EtcdLeaveClusterRequest{})\n\t\tsuite.Require().NoError(err)\n\t}\n\n\t// wipe ephemeral partition on all control plane nodes, starting with the one that still has etcd running\n\tfor _, node := range controlPlaneNodes {\n\t\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\t\tReboot:   true,\n\t\t\tGraceful: false,\n\t\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t\t{\n\t\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\t\tWipe:  true,\n\t\t\t\t},\n\t\t\t},\n\t\t}, false)\n\t}\n\n\t// verify that etcd data directory doesn't exist on the nodes\n\tfor _, node := range controlPlaneNodes {\n\t\tstream, err := suite.Client.MachineClient.List(client.WithNode(suite.ctx, node), &machineapi.ListRequest{Root: filepath.Join(constants.EtcdDataPath, \"member\")})\n\t\tsuite.Require().NoError(err)\n\n\t\t_, err = stream.Recv()\n\t\tsuite.Require().Error(err)\n\t\tsuite.Require().Equal(client.StatusCode(err), codes.Unknown)\n\t\tsuite.Require().Contains(client.Status(err).Message(), \"no such file or directory\")\n\t}\n\n\tsuite.T().Logf(\"recovering etcd snapshot at node %q\", recoverNode)\n\n\tsuite.Require().NoError(suite.recoverEtcd(recoverNode, bytes.NewReader(snapshot.Bytes())))\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\nfunc (suite *EtcdRecoverSuite) snapshotEtcd(snapshotNode string, dest io.Writer) error {\n\tctx := client.WithNodes(suite.ctx, snapshotNode)\n\n\tr, err := suite.Client.EtcdSnapshot(ctx, &machineapi.EtcdSnapshotRequest{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading snapshot: %w\", err)\n\t}\n\n\tdefer r.Close() //nolint:errcheck\n\n\t_, err = io.Copy(dest, r)\n\n\treturn err\n}\n\nfunc (suite *EtcdRecoverSuite) recoverEtcd(recoverNode string, src io.ReadSeeker) error {\n\tctx := client.WithNodes(suite.ctx, recoverNode)\n\n\tsuite.T().Log(\"uploading the snapshot\")\n\n\tif err := retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(\n\t\tctx, func(ctx context.Context) error {\n\t\t\t_, err := src.Seek(0, io.SeekStart)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t_, err = suite.Client.EtcdRecover(ctx, src)\n\n\t\t\tif client.StatusCode(err) == codes.FailedPrecondition {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t},\n\t); err != nil {\n\t\treturn fmt.Errorf(\"error uploading snapshot: %w\", err)\n\t}\n\n\tsuite.T().Log(\"bootstrapping from the snapshot\")\n\n\treturn retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(\n\t\tctx, func(ctx context.Context) error {\n\t\t\terr := suite.Client.Bootstrap(\n\t\t\t\tctx, &machineapi.BootstrapRequest{\n\t\t\t\t\tRecoverEtcd: true,\n\t\t\t\t},\n\t\t\t)\n\t\t\tif client.StatusCode(err) == codes.FailedPrecondition || client.StatusCode(err) == codes.DeadlineExceeded {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t},\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EtcdRecoverSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EtcdSuite ...\ntype EtcdSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *EtcdSuite) SuiteName() string {\n\treturn \"api.EtcdSuite\"\n}\n\n// SetupTest ...\nfunc (suite *EtcdSuite) SetupTest() {\n\t// make sure we abort at some point in time, but give enough room for Etcds\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *EtcdSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestForfeitLeadership tests moving etcd leadership to another member.\nfunc (suite *EtcdSuite) TestForfeitLeadership() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state etcd test is not reliable (can't wait for cluster readiness in between resets)\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\tif len(nodes) < 3 {\n\t\tsuite.T().Skip(\"test only can be run on HA etcd clusters\")\n\t}\n\n\tvar leader string\n\n\tfor _, node := range nodes {\n\t\tresp, err := suite.Client.EtcdForfeitLeadership(\n\t\t\tclient.WithNodes(suite.ctx, node),\n\t\t\t&machineapi.EtcdForfeitLeadershipRequest{},\n\t\t)\n\t\tsuite.Require().NoError(err)\n\n\t\tif resp.Messages[0].GetMember() != \"\" {\n\t\t\tleader = resp.Messages[0].GetMember()\n\n\t\t\tsuite.T().Log(\"Moved leadership to\", leader)\n\t\t}\n\t}\n\n\tsuite.Assert().NotEmpty(leader)\n}\n\n// TestLeaveCluster tests removing an etcd member.\n//\n//nolint:gocyclo\nfunc (suite *EtcdSuite) TestLeaveCluster() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot (and reset)\")\n\t}\n\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\tif len(nodes) < 3 {\n\t\tsuite.T().Skip(\"test only can be run on HA etcd clusters\")\n\t}\n\n\tnode := nodes[len(nodes)-1]\n\n\tsuite.T().Log(\"Removing etcd member\", node)\n\n\tnodeCtx := client.WithNodes(suite.ctx, node)\n\n\t_, err := suite.Client.EtcdForfeitLeadership(nodeCtx, &machineapi.EtcdForfeitLeadershipRequest{})\n\tsuite.Require().NoError(err)\n\n\terr = suite.Client.EtcdLeaveCluster(nodeCtx, &machineapi.EtcdLeaveClusterRequest{})\n\tsuite.Require().NoError(err)\n\n\tservices, err := suite.Client.ServiceInfo(nodeCtx, \"etcd\")\n\tsuite.Require().NoError(err)\n\n\tfor _, service := range services {\n\t\tif service.Service.Id == \"etcd\" {\n\t\t\tsuite.Assert().Equal(\"Finished\", service.Service.State)\n\t\t}\n\t}\n\n\tstream, err := suite.Client.MachineClient.List(nodeCtx, &machineapi.ListRequest{Root: constants.EtcdDataPath})\n\tsuite.Require().NoError(err)\n\n\tfor {\n\t\tvar info *machineapi.FileInfo\n\n\t\tinfo, err = stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tsuite.Assert().Equal(\n\t\t\t\"rpc error: code = Unknown desc = lstat /var/lib/etcd: no such file or directory\",\n\t\t\tinfo.Metadata.Error,\n\t\t)\n\t}\n\n\t// NB: Reboot the node so that it can rejoin the etcd cluster. This allows us\n\t// to check the cluster health and catch any issues in rejoining.\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t_, err = suite.Client.MachineClient.Reboot(nodeCtx, &machineapi.RebootRequest{})\n\n\t\t\treturn err\n\t\t}, 10*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n}\n\n// TestMembers verifies that etcd members as resources and API response are consistent.\nfunc (suite *EtcdSuite) TestMembers() {\n\tnodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\t// map member ID to hostname\n\tetcdMembers := map[string]string{}\n\n\tfor _, node := range nodes {\n\t\tmember, err := safe.StateGet[*etcd.Member](client.WithNode(suite.ctx, node), suite.Client.COSI, etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID).Metadata())\n\t\tsuite.Require().NoError(err)\n\n\t\thostname, err := safe.StateGet[*network.HostnameStatus](client.WithNode(suite.ctx, node), suite.Client.COSI, network.NewHostnameStatus(network.NamespaceName, network.HostnameID).Metadata())\n\t\tsuite.Require().NoError(err)\n\n\t\tetcdMembers[member.TypedSpec().MemberID] = hostname.TypedSpec().Hostname\n\t}\n\n\tsuite.Assert().Len(etcdMembers, len(nodes))\n\n\tresp, err := suite.Client.EtcdMemberList(suite.ctx, &machineapi.EtcdMemberListRequest{})\n\tsuite.Require().NoError(err)\n\n\tcount := 0\n\n\tfor _, message := range resp.GetMessages() {\n\t\tfor _, member := range message.GetMembers() {\n\t\t\tcount++\n\n\t\t\tmemberID := etcd.FormatMemberID(member.GetId())\n\n\t\t\tsuite.Assert().Contains(etcdMembers, memberID)\n\t\t\tsuite.Assert().Equal(etcdMembers[memberID], member.GetHostname())\n\t\t}\n\t}\n\n\tsuite.Assert().Equal(len(etcdMembers), count)\n}\n\n// TestRemoveMember tests removing an etcd member forcefully.\nfunc (suite *EtcdSuite) TestRemoveMember() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot (and reset)\")\n\t}\n\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\tif len(nodes) < 3 {\n\t\tsuite.T().Skip(\"test only can be run on HA etcd clusters\")\n\t}\n\n\tcontrolNode, nodeToRemove := nodes[len(nodes)-1], nodes[0]\n\n\tsuite.T().Log(\"Removing etcd member\", nodeToRemove)\n\n\tremoveCtx := client.WithNode(suite.ctx, nodeToRemove)\n\tcontrolCtx := client.WithNode(suite.ctx, controlNode)\n\n\t_, err := suite.Client.EtcdForfeitLeadership(removeCtx, &machineapi.EtcdForfeitLeadershipRequest{})\n\tsuite.Require().NoError(err)\n\n\tmember, err := safe.StateGet[*etcd.Member](removeCtx, suite.Client.COSI, etcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID).Metadata())\n\tsuite.Require().NoError(err)\n\n\tmemberID, err := etcd.ParseMemberID(member.TypedSpec().MemberID)\n\tsuite.Require().NoError(err)\n\n\terr = suite.Client.EtcdRemoveMemberByID(controlCtx, &machineapi.EtcdRemoveMemberByIDRequest{\n\t\tMemberId: memberID,\n\t})\n\tsuite.Require().NoError(err)\n\n\t// verify that memberID disappeared from etcd member list\n\tresp, err := suite.Client.EtcdMemberList(controlCtx, &machineapi.EtcdMemberListRequest{})\n\tsuite.Require().NoError(err)\n\n\tfor _, message := range resp.GetMessages() {\n\t\tfor _, member := range message.GetMembers() {\n\t\t\tsuite.Assert().NotEqual(memberID, member.GetId())\n\t\t}\n\t}\n\n\t// NB: Reset the ephemeral the node so that it can rejoin the etcd cluster. This allows us\n\t// to check the cluster health and catch any issues in rejoining.\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, nodeToRemove, func(nodeCtx context.Context) error {\n\t\t\t_, err = suite.Client.MachineClient.Reset(nodeCtx, &machineapi.ResetRequest{\n\t\t\t\tReboot: true,\n\t\t\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t\t\t{\n\t\t\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\t\t\tWipe:  true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\n\t\t\treturn err\n\t\t}, 10*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n}\n\nfunc (suite *EtcdSuite) downgradesSupported() bool {\n\tsuite.T().Helper()\n\n\tdowngradeFromAtLeast := semver.Version{Major: 3, Minor: 6}\n\n\tstatus, err := suite.Client.EtcdStatus(suite.ctx)\n\tsuite.Require().NoError(err)\n\n\tfor _, message := range status.Messages {\n\t\tetcdVersion := message.GetMemberStatus().GetProtocolVersion()\n\n\t\tetcdVersionSemver, err := semver.Parse(etcdVersion)\n\t\tif err != nil {\n\t\t\tsuite.T().Logf(\"ETCD version parsing failed: %s\", err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif etcdVersionSemver.LT(downgradeFromAtLeast) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// TestDowngrade tests downgrade API of etcd.\nfunc (suite *EtcdSuite) TestDowngrade() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot (and reset)\")\n\t}\n\n\tif !suite.downgradesSupported() {\n\t\tsuite.T().Skip(\"cluster needs to run ETCD 3.6.x to support downgrades\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\tnode := nodes[0]\n\tdowngradeTo := \"3.5\"\n\n\t// test the downgrade validate API\n\tvalidateResp, err := suite.Client.EtcdDowngradeValidate(\n\t\tclient.WithNodes(suite.ctx, node),\n\t\t&machineapi.EtcdDowngradeValidateRequest{Version: downgradeTo},\n\t)\n\tsuite.Require().NoError(err)\n\n\tfor _, message := range validateResp.GetMessages() {\n\t\tsuite.Assert().NotEqual(downgradeTo, message.GetClusterDowngrade().GetClusterVersion())\n\t}\n\n\t// test the downgrade enable API\n\tenableResp, err := suite.Client.EtcdDowngradeEnable(\n\t\tclient.WithNodes(suite.ctx, node),\n\t\t&machineapi.EtcdDowngradeEnableRequest{Version: downgradeTo},\n\t)\n\tsuite.Require().NoError(err)\n\n\tfor _, message := range enableResp.GetMessages() {\n\t\tsuite.Assert().NotEqual(downgradeTo, message.GetClusterDowngrade().GetClusterVersion())\n\t}\n\n\t// test the downgrade cancel API\n\tcancelResp, err := suite.Client.EtcdDowngradeCancel(\n\t\tclient.WithNodes(suite.ctx, node),\n\t)\n\tsuite.Require().NoError(err)\n\n\tfor _, message := range cancelResp.GetMessages() {\n\t\tsuite.Assert().NotEqual(downgradeTo, message.GetClusterDowngrade().GetClusterVersion())\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EtcdSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/ethernet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tnetworkconfig \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// EthernetSuite ...\ntype EthernetSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *EthernetSuite) SuiteName() string {\n\treturn \"api.EthernetSuite\"\n}\n\n// SetupTest ...\nfunc (suite *EthernetSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping ethernet test since provisioner is not qemu\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *EthernetSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\nfunc getFeatureStatus(t *testing.T, features network.EthernetFeatureStatusList, name string) bool {\n\tt.Helper()\n\n\tfor _, f := range features {\n\t\tif f.Name == name {\n\t\t\tswitch f.Status {\n\t\t\tcase \"on\":\n\t\t\t\treturn true\n\t\t\tcase \"off\":\n\t\t\t\treturn false\n\t\t\tdefault:\n\t\t\t\trequire.Fail(t, \"unexpected feature status: %s\", f.Status)\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.Fail(t, \"feature %s not found\", name)\n\n\tpanic(\"unreachable\")\n}\n\n// TestEthernetConfig verifies changing Ethernet settings.\nfunc (suite *EthernetSuite) TestEthernetConfig() {\n\t// pick up a random node to test the Ethernet on, and use it throughout the test\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.T().Logf(\"testing Ethernet on node %s\", node)\n\n\t// build a Talos API context which is tied to the node\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t// pick a Ethernet links\n\tethStatuses, err := safe.StateListAll[*network.EthernetStatus](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tvar (\n\t\tlinkName       string\n\t\tprevRingConfig *network.EthernetRingsStatus\n\t\tprevFeatures   network.EthernetFeatureStatusList\n\t)\n\n\tfor ethStatus := range ethStatuses.All() {\n\t\tif ethStatus.TypedSpec().Rings != nil && ethStatus.TypedSpec().Rings.RXMax != nil {\n\t\t\tlinkName = ethStatus.Metadata().ID()\n\t\t\tprevRingConfig = ethStatus.TypedSpec().Rings\n\t\t\tprevFeatures = ethStatus.TypedSpec().Features\n\n\t\t\tmarshaled, err := resource.MarshalYAML(ethStatus)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tout, err := yaml.Marshal(marshaled)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tsuite.T().Logf(\"found link %s with: %s\", linkName, string(out))\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Require().NotEmpty(linkName, \"no link provides RX rings\")\n\tsuite.Require().NotEmpty(prevFeatures, \"no link provides features\")\n\n\tsuite.Run(\"Rings\", func() {\n\t\tif os.Getenv(\"CI\") != \"\" {\n\t\t\tsuite.T().Skip(\"skipping ethtool test in CI, as QEMU version doesn't support updating RX rings for virtio\")\n\t\t}\n\n\t\t// first, adjust RX rings to be 50% of what it was before\n\t\tnewRX := pointer.SafeDeref(prevRingConfig.RXMax) / 2\n\n\t\tsuite.T().Logf(\"testing RX rings on link %s: %d -> %d\", linkName, pointer.SafeDeref(prevRingConfig.RX), newRX)\n\n\t\tcfgDocument := networkconfig.NewEthernetConfigV1Alpha1(linkName)\n\t\tcfgDocument.RingsConfig = &networkconfig.EthernetRingsConfig{\n\t\t\tRX: new(newRX),\n\t\t}\n\t\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t\t// now EthernetStatus should reflect the new RX rings\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(newRX, pointer.SafeDeref(ethStatus.TypedSpec().Rings.RX))\n\t\t\t},\n\t\t)\n\n\t\t// now, let's revert the RX rings to what it was before\n\t\tcfgDocument.RingsConfig.RX = prevRingConfig.RX\n\n\t\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t\t// now EthernetStatus should reflect the new RX rings\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(pointer.SafeDeref(prevRingConfig.RX), pointer.SafeDeref(ethStatus.TypedSpec().Rings.RX))\n\t\t\t},\n\t\t)\n\n\t\t// remove the config document\n\t\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\t})\n\n\tsuite.Run(\"Features\", func() {\n\t\tconst featureName = \"tx-tcp-segmentation\"\n\n\t\t// get the initial state\n\t\tinitialState := getFeatureStatus(suite.T(), prevFeatures, featureName)\n\n\t\tsuite.T().Logf(\"testing feature %s on link %s: %v -> %v\", featureName, linkName, initialState, !initialState)\n\n\t\tcfgDocument := networkconfig.NewEthernetConfigV1Alpha1(linkName)\n\t\tcfgDocument.FeaturesConfig = map[string]bool{\n\t\t\tfeatureName: !initialState,\n\t\t}\n\t\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t\t// now EthernetStatus should reflect the new feature status\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(!initialState, getFeatureStatus(suite.T(), ethStatus.TypedSpec().Features, featureName))\n\t\t\t},\n\t\t)\n\n\t\t// now, let's revert the RX rings to what it was before\n\t\tcfgDocument.FeaturesConfig[featureName] = initialState\n\n\t\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t\t// now EthernetStatus should reflect the old feature status\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(ethStatus *network.EthernetStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(initialState, getFeatureStatus(suite.T(), ethStatus.TypedSpec().Features, featureName))\n\t\t\t},\n\t\t)\n\n\t\t// remove the config document\n\t\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\t})\n\n\tsuite.Run(\"Channels\", func() {\n\t\tsuite.T().Skip(\"channels are not supported by the current QEMU version\")\n\t})\n}\n\n// TestBridgeMAC verifies bridge MAC address.\nfunc (suite *EthernetSuite) TestBridgeMAC() {\n\t// pick up a random node to test the Ethernet on, and use it throughout the test\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.T().Logf(\"testing bridge MAC on node %s\", node)\n\n\t// build a Talos API context which is tied to the node\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\trandomSuffix := fmt.Sprintf(\"%04x\", rand.Int32())\n\n\tdc := networkconfig.NewDummyLinkConfigV1Alpha1(\"dummy\" + randomSuffix)\n\tbc := networkconfig.NewBridgeConfigV1Alpha1(\"bridge\" + randomSuffix)\n\n\tsuite.PatchMachineConfig(nodeCtx, dc, bc)\n\n\tvar dummyMAC string\n\n\t// the links should be created\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]string{\"dummy\" + randomSuffix, \"bridge\" + randomSuffix},\n\t\tfunc(link *network.LinkStatus, _ *assert.Assertions) {\n\t\t\tif link.TypedSpec().Kind == \"dummy\" {\n\t\t\t\tdummyMAC = link.TypedSpec().HardwareAddr.String()\n\t\t\t}\n\t\t})\n\n\tsuite.Assert().NotEmpty(dummyMAC, \"dummy MAC address is empty\")\n\n\t// now, let's put dummy interface into the bridge\n\tbc.BridgeLinks = []string{\"dummy\" + randomSuffix}\n\n\tsuite.PatchMachineConfig(nodeCtx, dc, bc)\n\n\t// now bridge should have the same MAC address as dummy\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]string{\"dummy\" + randomSuffix, \"bridge\" + randomSuffix},\n\t\tfunc(link *network.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(dummyMAC, link.TypedSpec().HardwareAddr.String(), \"dummy MAC address is not equal to bridge MAC address\")\n\t\t})\n\n\t// revert the changes removing the dummy interface from the bridge\n\tpatches := []any{\n\t\tmap[string]any{\n\t\t\t\"apiVersion\": \"v1alpha1\",\n\t\t\t\"kind\":       networkconfig.BridgeKind,\n\t\t\t\"name\":       \"bridge\" + randomSuffix,\n\t\t\t\"$patch\":     \"delete\",\n\t\t},\n\t\tmap[string]any{\n\t\t\t\"apiVersion\": \"v1alpha1\",\n\t\t\t\"kind\":       networkconfig.DummyLinkKind,\n\t\t\t\"name\":       \"dummy\" + randomSuffix,\n\t\t\t\"$patch\":     \"delete\",\n\t\t},\n\t}\n\n\tsuite.PatchMachineConfig(nodeCtx, patches...)\n\n\trtestutils.AssertNoResource[*network.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, \"dummy\"+randomSuffix)\n\trtestutils.AssertNoResource[*network.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, \"bridge\"+randomSuffix)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EthernetSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tmachinetype \"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// EventsSuite verifies Events API.\ntype EventsSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tnodeCtx context.Context //nolint:containedctx\n}\n\n// SuiteName ...\nfunc (suite *EventsSuite) SuiteName() string {\n\treturn \"api.EventsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *EventsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n\n\tsuite.nodeCtx = client.WithNodes(suite.ctx, suite.RandomDiscoveredNodeInternalIP(machinetype.TypeWorker))\n}\n\n// TearDownTest ...\nfunc (suite *EventsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestEventsWatch verifies events watch API.\nfunc (suite *EventsSuite) TestEventsWatch() {\n\treceiveEvents := func(opts ...client.EventsOptionFunc) []client.Event {\n\t\tvar result []client.Event\n\n\t\twatchCtx, watchCtxCancel := context.WithCancel(suite.nodeCtx)\n\t\tdefer watchCtxCancel()\n\n\t\tsuite.Assert().NoError(\n\t\t\tsuite.Client.EventsWatch(\n\t\t\t\twatchCtx, func(ch <-chan client.Event) {\n\t\t\t\t\tdefer watchCtxCancel()\n\n\t\t\t\t\ttimer := time.NewTimer(500 * time.Millisecond)\n\t\t\t\t\tdefer timer.Stop()\n\n\t\t\t\t\tfor {\n\t\t\t\t\t\tselect {\n\t\t\t\t\t\tcase event, ok := <-ch:\n\t\t\t\t\t\t\tif !ok {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tresult = append(result, event)\n\t\t\t\t\t\tcase <-timer.C:\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, opts...,\n\t\t\t),\n\t\t)\n\n\t\treturn result\n\t}\n\n\tallEvents := receiveEvents(client.WithTailEvents(-1))\n\tsuite.Require().Greater(len(allEvents), 20)\n\n\tsuite.Assert().Len(receiveEvents(), 0)\n\tsuite.Assert().Len(receiveEvents(client.WithTailEvents(5)), 5)\n\tsuite.Assert().Len(receiveEvents(client.WithTailEvents(20)), 20)\n\n\t// pick some ID of 15th event in the past; API should return at least 14 events\n\t// (as check excludes that event with picked ID)\n\tid := allEvents[len(allEvents)-15].ID\n\teventsSinceID := receiveEvents(client.WithTailID(id))\n\tsuite.Require().GreaterOrEqual(\n\t\tlen(eventsSinceID),\n\t\t14,\n\t) //  there might some new events since allEvents, but at least 15 should be received\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EventsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/extensions_nvidia.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\tbatchv1 \"k8s.io/api/batch/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n//go:embed testdata/nvidia-gpu-operator.yaml\nvar nvidiaGPUOperatorHelmChartValues []byte\n\n// ExtensionsSuiteNVIDIA verifies Talos is securebooted.\ntype ExtensionsSuiteNVIDIA struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ExtensionsSuiteNVIDIA) SuiteName() string {\n\treturn \"api.ExtensionsSuiteNVIDIA\"\n}\n\n// SetupTest ...\nfunc (suite *ExtensionsSuiteNVIDIA) SetupTest() {\n\tif !suite.ExtensionsNvidia {\n\t\tsuite.T().Skip(\"skipping as nvidia extensions test are not enabled\")\n\t}\n\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ExtensionsSuiteNVIDIA) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestExtensionsNVIDIA verifies that a cuda workload can be run.\n//\n//nolint:gocyclo\nfunc (suite *ExtensionsSuiteNVIDIA) TestExtensionsNVIDIA() {\n\texpectedModulesModDep := map[string]string{\n\t\t\"nvidia\":         \"nvidia.ko\",\n\t\t\"nvidia_uvm\":     \"nvidia-uvm.ko\",\n\t\t\"nvidia_drm\":     \"nvidia-drm.ko\",\n\t\t\"nvidia_modeset\": \"nvidia-modeset.ko\",\n\t}\n\n\t// if we're testing NVIDIA stuff we need to get the nodes having NVIDIA GPUs\n\t// we query k8s to get the nodes having the label node.kubernetes.io/instance-type.\n\t// this label is set by the cloud provider and it's value is the instance type.\n\t// the nvidia e2e-aws tests creates gpu nodes one with g4dn.xlarge and another\n\t// with p4d.24xlarge\n\tfor _, nvidiaNode := range suite.getNVIDIANodes(\"node.kubernetes.io/instance-type in (g4dn.xlarge, p4d.24xlarge)\") {\n\t\tsuite.AssertExpectedModules(suite.ctx, nvidiaNode, expectedModulesModDep)\n\t}\n\n\tnodes := suite.getNVIDIANodes(\"node.kubernetes.io/instance-type=g4dn.xlarge\")\n\tfor _, node := range nodes {\n\t\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\n\t\t\t\"ext-nvidia-persistenced\": \"Running\",\n\t\t\t\"ext-nvidia-cdi-gen\":      \"Finished\",\n\t\t})\n\t}\n\n\t// nodes = suite.getNVIDIANodes(\"node.kubernetes.io/instance-type=p4d.24xlarge\")\n\t// for _, node := range nodes {\n\t// \tsuite.testServicesRunning(node, map[string]string{\n\t// \t\t\"ext-nvidia-persistenced\":  \"Running\",\n\t// \t\t\"ext-nvidia-fabricmanager\": \"Running\",\n\t// \t})\n\t// }\n\n\t_, err := suite.Clientset.CoreV1().Namespaces().Create(suite.ctx, &corev1.Namespace{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"gpu-operator\",\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"pod-security.kubernetes.io/enforce\": \"privileged\",\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.CoreV1().Namespaces().Delete(suite.ctx, \"gpu-operator\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.HelmInstall(\n\t\tsuite.ctx,\n\t\t\"gpu-operator\",\n\t\t\"https://helm.ngc.nvidia.com/nvidia\",\n\t\tNvidiaGPUOperatorChartVersion,\n\t\t\"gpu-operator\",\n\t\t\"gpu-operator\",\n\t\tnvidiaGPUOperatorHelmChartValues,\n\t))\n\n\t// now we can create a cuda test job\n\t_, err = suite.Clientset.BatchV1().Jobs(\"default\").Create(suite.ctx, nvidiaCUDATestJob(), metav1.CreateOptions{})\n\tdefer suite.Clientset.BatchV1().Jobs(\"default\").Delete(suite.ctx, \"cuda-test\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t// delete all pods with label app.kubernetes.io/name=cuda-test\n\tdefer func() {\n\t\tpodList, listErr := suite.GetPodsWithLabel(suite.ctx, \"default\", \"app.kubernetes.io/name=cuda-test\")\n\t\tif listErr != nil {\n\t\t\terr = listErr\n\t\t}\n\n\t\tfor _, pod := range podList.Items {\n\t\t\terr = suite.Clientset.CoreV1().Pods(\"default\").Delete(suite.ctx, pod.Name, metav1.DeleteOptions{})\n\t\t}\n\t}()\n\n\t// wait for the pods to be completed\n\tsuite.Require().NoError(retry.Constant(4*time.Minute, retry.WithUnits(time.Second*10)).Retry(\n\t\tfunc() error {\n\t\t\tpodList, listErr := suite.GetPodsWithLabel(suite.ctx, \"default\", \"app.kubernetes.io/name=cuda-test\")\n\t\t\tif listErr != nil {\n\t\t\t\treturn retry.ExpectedErrorf(\"error getting pod: %s\", listErr)\n\t\t\t}\n\n\t\t\tfor _, pod := range podList.Items {\n\t\t\t\tif pod.Status.Phase == corev1.PodFailed {\n\t\t\t\t\tlogData := suite.getPodLogs(\"default\", pod.Name)\n\n\t\t\t\t\tsuite.T().Logf(\"pod %s logs:\\n%s\", pod.Name, logData)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(podList.Items) != 1 {\n\t\t\t\treturn retry.ExpectedErrorf(\"expected 1 pod, got %d\", len(podList.Items))\n\t\t\t}\n\n\t\t\tfor _, pod := range podList.Items {\n\t\t\t\tif pod.Status.Phase != corev1.PodSucceeded {\n\t\t\t\t\treturn retry.ExpectedErrorf(\"%s is not completed yet: %s\", pod.Name, pod.Status.Phase)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\t// now we can check the logs\n\tpodList, err := suite.GetPodsWithLabel(suite.ctx, \"default\", \"app.kubernetes.io/name=cuda-test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Len(podList.Items, 1)\n\n\tfor _, pod := range podList.Items {\n\t\tlogData := suite.getPodLogs(\"default\", pod.Name)\n\n\t\tsuite.Require().Contains(logData, \"Test PASSED\")\n\t}\n}\n\nfunc (suite *ExtensionsSuiteNVIDIA) getPodLogs(namespace, name string) string {\n\tres := suite.Clientset.CoreV1().Pods(namespace).GetLogs(name, &corev1.PodLogOptions{})\n\tstream, err := res.Stream(suite.ctx)\n\tsuite.Require().NoError(err)\n\n\tdefer stream.Close() //nolint:errcheck\n\n\tlogData, err := io.ReadAll(stream)\n\tsuite.Require().NoError(err)\n\n\treturn string(logData)\n}\n\nfunc (suite *ExtensionsSuiteNVIDIA) getNVIDIANodes(labelQuery string) []string {\n\tnodes, err := suite.Clientset.CoreV1().Nodes().List(suite.ctx, metav1.ListOptions{\n\t\tLabelSelector: labelQuery,\n\t})\n\tsuite.Require().NoError(err)\n\n\t// if we don't have any node with NVIDIA GPUs we fail the test\n\t// since we explicitly asked for them\n\tsuite.Require().NotEmpty(nodes.Items, \"no nodes with NVIDIA GPUs matching label selector '%s' found\", labelQuery)\n\n\tnodeList := make([]string, len(nodes.Items))\n\n\tfor i, node := range nodes.Items {\n\t\tfor _, addr := range node.Status.Addresses {\n\t\t\tif addr.Type == corev1.NodeInternalIP {\n\t\t\t\tnodeList[i] = addr.Address\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nodeList\n}\n\nfunc nvidiaCUDATestJob() *batchv1.Job {\n\treturn &batchv1.Job{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"cuda-test\",\n\t\t},\n\t\tSpec: batchv1.JobSpec{\n\t\t\tCompletions: new(int32(1)),\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName: \"cuda-test\",\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\t\"app.kubernetes.io/name\": \"cuda-test\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:  \"cuda-test\",\n\t\t\t\t\t\t\tImage: fmt.Sprintf(\"nvcr.io/nvidia/k8s/cuda-sample:%s\", NvidiaCUDATestImageVersion),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAffinity: &corev1.Affinity{\n\t\t\t\t\t\tNodeAffinity: &corev1.NodeAffinity{\n\t\t\t\t\t\t\tRequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{\n\t\t\t\t\t\t\t\tNodeSelectorTerms: []corev1.NodeSelectorTerm{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tMatchExpressions: []corev1.NodeSelectorRequirement{\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tKey:      \"node.kubernetes.io/instance-type\",\n\t\t\t\t\t\t\t\t\t\t\t\tOperator: corev1.NodeSelectorOpIn,\n\t\t\t\t\t\t\t\t\t\t\t\tValues:   []string{\"g4dn.xlarge\", \"p4d.24xlarge\"},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tRestartPolicy:    corev1.RestartPolicyNever,\n\t\t\t\t\tRuntimeClassName: new(\"nvidia\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &ExtensionsSuiteNVIDIA{})\n}\n"
  },
  {
    "path": "internal/integration/api/extensions_qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tnodev1 \"k8s.io/api/node/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// ExtensionsSuiteQEMU verifies Talos extensions on QEMU.\ntype ExtensionsSuiteQEMU struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ExtensionsSuiteQEMU) SuiteName() string {\n\treturn \"api.ExtensionsSuiteQEMU\"\n}\n\n// SetupTest ...\nfunc (suite *ExtensionsSuiteQEMU) SetupTest() {\n\tif !suite.ExtensionsQEMU {\n\t\tsuite.T().Skip(\"skipping as qemu extensions test are not enabled\")\n\t}\n\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ExtensionsSuiteQEMU) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestExtensionsExpectedPaths verifies expected paths are present.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsExpectedPaths() {\n\texpectedPaths := []string{\n\t\t\"/lib/firmware/amdgpu\",\n\t\t\"/lib/firmware/amd-ucode\",\n\t\t\"/lib/firmware/bnx2x\",\n\t\t\"/lib/firmware/cxgb3\",\n\t\t\"/lib/firmware/cxgb4/configs\",\n\t\t\"/lib/firmware/i915\",\n\t\t\"/lib/firmware/intel/ice/ddp\",\n\t\t\"/lib/firmware/intel-ucode\",\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tctx := client.WithNode(suite.ctx, node)\n\n\tfor _, path := range expectedPaths {\n\t\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\t\tRoot:  path,\n\t\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t\t})\n\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\t\tsuite.Require().Equal(path, info.Name, \"expected %s to exist\", path)\n\n\t\t\treturn nil\n\t\t}))\n\t}\n}\n\n// TestExtensionsExpectedModules verifies expected modules are loaded and in modules.dep.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsExpectedModules() {\n\t// expectedModulesModDep is a map of module name to module.dep name\n\texpectedModulesModDep := map[string]string{\n\t\t\"asix\":            \"asix.ko\",\n\t\t\"ax88179_178a\":    \"ax88179_178a.ko\",\n\t\t\"ax88796b\":        \"ax88796b.ko\",\n\t\t\"binfmt_misc\":     \"binfmt_misc.ko\",\n\t\t\"btrfs\":           \"btrfs.ko\",\n\t\t\"cdc_ether\":       \"cdc_ether.ko\",\n\t\t\"cdc_mbim\":        \"cdc_mbim.ko\",\n\t\t\"cdc_ncm\":         \"cdc_ncm.ko\",\n\t\t\"cdc_subset\":      \"cdc_subset.ko\",\n\t\t\"cdc_wdm\":         \"cdc-wdm.ko\",\n\t\t\"cxgb\":            \"cxgb.ko\",\n\t\t\"cxgb3\":           \"cxgb3.ko\",\n\t\t\"cxgb4\":           \"cxgb4.ko\",\n\t\t\"cxgb4vf\":         \"cxgb4vf.ko\",\n\t\t\"drbd\":            \"drbd.ko\",\n\t\t\"ena\":             \"ena.ko\",\n\t\t\"gasket\":          \"gasket.ko\",\n\t\t\"net1080\":         \"net1080.ko\",\n\t\t\"option\":          \"option.ko\",\n\t\t\"qmi_wwan\":        \"qmi_wwan.ko\",\n\t\t\"r8153_ecm\":       \"r8153_ecm.ko\",\n\t\t\"thunderbolt\":     \"thunderbolt.ko\",\n\t\t\"thunderbolt_net\": \"thunderbolt_net.ko\",\n\t\t\"usb_wwan\":        \"usb_wwan.ko\",\n\t\t\"usbnet\":          \"usbnet.ko\",\n\t\t\"xdma\":            \"xdma.ko\",\n\t\t\"zaurus\":          \"zaurus.ko\",\n\t\t\"zfs\":             \"zfs.ko\",\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertExpectedModules(suite.ctx, node, expectedModulesModDep)\n}\n\n// TestExtensionsNutClient verifies nut client is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsNutClient() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\"ext-nut-client\": \"Running\"})\n}\n\n// TestExtensionsQEMUGuestAgent verifies qemu guest agent is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsQEMUGuestAgent() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\"ext-qemu-guest-agent\": \"Running\"})\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\thostnameSpec, err := safe.StateWatchFor[*network.HostnameStatus](\n\t\tctx,\n\t\tsuite.Client.COSI,\n\t\tnetwork.NewHostnameStatus(network.NamespaceName, resource.ID(\"hostname\")).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\tsuite.Require().NoError(err)\n\n\tclusterStatePath, err := suite.Cluster.StatePath()\n\tsuite.Require().NoError(err)\n\n\tconn, err := (&net.Dialer{}).DialContext(ctx, \"unix\", filepath.Join(clusterStatePath, hostnameSpec.TypedSpec().Hostname+\".sock\"))\n\tsuite.Require().NoError(err)\n\n\tdefer conn.Close() //nolint:errcheck\n\n\t// now we want to reboot the node using the guest agent\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t_, err = conn.Write([]byte(`{\"execute\":\"guest-shutdown\", \"arguments\": {\"mode\": \"reboot\"}}`))\n\n\t\t\treturn err\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n}\n\n// TestExtensionsTailscale verifies tailscale is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsTailscale() {\n\t// Tailscale service keeps on restarting unless authed, so this test is disabled for now.\n\tif ok := os.Getenv(\"TALOS_INTEGRATION_RUN_TAILSCALE\"); ok == \"\" {\n\t\tsuite.T().Skip(\"skipping as tailscale integration tests are not enabled\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\"ext-tailscale\": \"Running\"})\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tlinkSpec, err := safe.StateWatchFor[*network.LinkStatus](\n\t\tctx,\n\t\tsuite.Client.COSI,\n\t\tnetwork.NewHostnameStatus(network.NamespaceName, resource.ID(\"tailscale0\")).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"tun\", linkSpec.TypedSpec().Kind)\n}\n\n// TestExtensionsHelloWorldService verifies hello world service is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsHelloWorldService() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\n\t\t\"ext-hello-world\": \"Running\",\n\t})\n\n\turl := url.URL{\n\t\tScheme: \"http\",\n\t\tHost:   node,\n\t}\n\n\tresp, err := http.Get(url.String()) //nolint:noctx\n\tsuite.Require().NoError(err)\n\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"Hello from Talos Linux Extension Service!\", string(respBody))\n}\n\n// TestExtensionsGvisor verifies gvisor runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsGvisor() {\n\tsuite.testRuntimeClass(\"gvisor\", \"runsc\")\n}\n\n// TestExtensionsGvisorKVM verifies gvisor runtime class with kvm platform is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsGvisorKVM() {\n\tsuite.testRuntimeClass(\"gvisor-kvm\", \"runsc-kvm\")\n}\n\n// TestExtensionsCrun verifies crun runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsCrun() {\n\tsuite.testRuntimeClass(\"crun\", \"crun\")\n}\n\n// TestExtensionsKataContainers verifies gvisor runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsKataContainers() {\n\tsuite.testRuntimeClass(\"kata\", \"kata\")\n}\n\n// TestExtensionsYouki verifies youki runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsYouki() {\n\tsuite.testRuntimeClass(\"youki\", \"youki\")\n}\n\nfunc (suite *ExtensionsSuiteQEMU) testRuntimeClass(runtimeClassName, handlerName string) {\n\ttestName := \"nginx-\" + runtimeClassName\n\n\t_, err := suite.Clientset.NodeV1().RuntimeClasses().Create(suite.ctx, &nodev1.RuntimeClass{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: runtimeClassName,\n\t\t},\n\t\tHandler: handlerName,\n\t}, metav1.CreateOptions{})\n\tif apierrors.IsAlreadyExists(err) {\n\t\t// ignore if the runtime class already exists\n\t\terr = nil\n\t}\n\n\tsuite.Require().NoError(err)\n\n\tdefer suite.Clientset.NodeV1().RuntimeClasses().Delete(suite.ctx, runtimeClassName, metav1.DeleteOptions{}) //nolint:errcheck\n\n\t_, err = suite.Clientset.CoreV1().Pods(\"default\").Create(suite.ctx, &corev1.Pod{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: testName,\n\t\t},\n\t\tSpec: corev1.PodSpec{\n\t\t\tRuntimeClassName: new(runtimeClassName),\n\t\t\tContainers: []corev1.Container{\n\t\t\t\t{\n\t\t\t\t\tName:  testName,\n\t\t\t\t\tImage: \"nginx\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n\tsuite.Require().NoError(err)\n\n\tdefer suite.Clientset.CoreV1().Pods(\"default\").Delete(suite.ctx, testName, metav1.DeleteOptions{}) //nolint:errcheck\n\n\t// wait for the pod to be ready\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(suite.ctx, 5*time.Minute, \"default\", testName))\n}\n\n// TestExtensionsStargz verifies stargz snapshotter.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsStargz() {\n\t_, err := suite.Clientset.CoreV1().Pods(\"default\").Create(suite.ctx, &corev1.Pod{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"stargz-hello\",\n\t\t},\n\t\tSpec: corev1.PodSpec{\n\t\t\tContainers: []corev1.Container{\n\t\t\t\t{\n\t\t\t\t\tName:  \"stargz-hello\",\n\t\t\t\t\tImage: \"ghcr.io/stargz-containers/alpine:3.15.3-esgz\",\n\t\t\t\t\tArgs:  []string{\"sleep\", \"inf\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.CoreV1().Pods(\"default\").Delete(suite.ctx, \"stargz-hello\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t// wait for the pod to be ready\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(suite.ctx, 5*time.Minute, \"default\", \"stargz-hello\"))\n}\n\n// TestExtensionsMdADM verifies mdadm is working, udev rules work and the raid is mounted on reboot.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsMdADM() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tsuite.Require().GreaterOrEqual(len(userDisks), 2, \"expected at least two user disks to be available\")\n\n\tuserDisksJoined := strings.Join(userDisks[:2], \" \")\n\n\tmdAdmCreatePodDef, err := suite.NewPrivilegedPod(\"mdadm-create\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(mdAdmCreatePodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer mdAdmCreatePodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, _, err := mdAdmCreatePodDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- mdadm --create /dev/md/testmd --raid-devices=2 --metadata=1.2 --level=1 %s\", userDisksJoined),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(stdout, \"mdadm: array /dev/md/testmd started.\")\n\n\tdefer func() {\n\t\thostNameStatus, err := safe.StateGetByID[*network.HostnameStatus](client.WithNode(suite.ctx, node), suite.Client.COSI, \"hostname\")\n\t\tsuite.Require().NoError(err)\n\n\t\thostname := hostNameStatus.TypedSpec().Hostname\n\n\t\tdeletePodDef, err := suite.NewPrivilegedPod(\"mdadm-destroy\")\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(deletePodDef.Create(suite.ctx, 5*time.Minute))\n\n\t\tdefer deletePodDef.Delete(suite.ctx) //nolint:errcheck\n\n\t\tif _, _, err := deletePodDef.Exec(\n\t\t\tsuite.ctx,\n\t\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- mdadm --wait --stop /dev/md/%s:testmd\", hostname),\n\t\t); err != nil {\n\t\t\tsuite.T().Logf(\"failed to stop mdadm array: %v\", err)\n\t\t}\n\n\t\tif _, _, err := deletePodDef.Exec(\n\t\t\tsuite.ctx,\n\t\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- mdadm --zero-superblock %s\", userDisksJoined),\n\t\t); err != nil {\n\t\t\tsuite.T().Logf(\"failed to remove md array backed by volumes %s: %v\", userDisksJoined, err)\n\t\t}\n\t}()\n\n\t// now we want to reboot the node and make sure the array is still mounted\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.Require().True(suite.mdADMArrayExists(), \"expected mdadm array to be present\")\n}\n\nfunc (suite *ExtensionsSuiteQEMU) mdADMArrayExists() bool {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisks, err := safe.StateListAll[*block.Disk](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tfor disk := range disks.All() {\n\t\tif strings.HasPrefix(disk.TypedSpec().DevPath, \"/dev/md\") {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// TestExtensionsZFS verifies zfs is working, udev rules work and the pool is mounted on reboot.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsZFS() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.AssertServicesRunning(suite.ctx, node, map[string]string{\"ext-zfs-service\": \"Running\"})\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tsuite.Require().NotEmpty(userDisks, \"expected at least one user disks to be available\")\n\n\tzfsPodDef, err := suite.NewPrivilegedPod(\"zpool-create\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(zfsPodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer zfsPodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, stderr, err := zfsPodDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- zpool create -m /var/tank tank %s\", userDisks[0]),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Equal(\"\", stdout)\n\n\tstdout, stderr, err = zfsPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"nsenter --mount=/proc/1/ns/mnt -- zfs create -V 1gb tank/vol\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Equal(\"\", stdout)\n\n\tdefer func() {\n\t\tdeletePodDef, err := suite.NewPrivilegedPod(\"zpool-destroy\")\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(deletePodDef.Create(suite.ctx, 5*time.Minute))\n\n\t\tdefer deletePodDef.Delete(suite.ctx) //nolint:errcheck\n\n\t\tif _, _, err := deletePodDef.Exec(\n\t\t\tsuite.ctx,\n\t\t\t\"nsenter --mount=/proc/1/ns/mnt -- zfs destroy tank/vol\",\n\t\t); err != nil {\n\t\t\tsuite.T().Logf(\"failed to remove zfs dataset tank/vol: %v\", err)\n\t\t}\n\n\t\tif _, _, err := deletePodDef.Exec(\n\t\t\tsuite.ctx,\n\t\t\t\"nsenter --mount=/proc/1/ns/mnt -- zpool destroy tank\",\n\t\t); err != nil {\n\t\t\tsuite.T().Logf(\"failed to remove zpool tank: %v\", err)\n\t\t}\n\t}()\n\n\tsuite.Require().True(suite.checkZFSPoolMounted(), \"expected zfs pool to be mounted\")\n\n\t// now we want to reboot the node and make sure the pool is still mounted\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.Require().True(suite.checkZFSPoolMounted(), \"expected zfs pool to be mounted\")\n}\n\nfunc (suite *ExtensionsSuiteQEMU) checkZFSPoolMounted() bool {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  \"/dev/zvol/tank/vol\",\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_REGULAR},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\tsuite.Require().Equal(\"/dev/zvol/tank/vol\", info.Name, \"expected /dev/zvol/tank/vol to exist\")\n\t\tsuite.Require().Equal(\"zd0\", info.Link, \"expected /dev/zvol/tank/vol to be linked to zd0\")\n\n\t\treturn nil\n\t}))\n\n\tdisks, err := safe.StateListAll[*block.Disk](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tfor disk := range disks.All() {\n\t\tif strings.HasPrefix(disk.TypedSpec().DevPath, \"/dev/zd\") {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// TestExtensionsUtilLinuxTools verifies util-linux-tools are working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsUtilLinuxTools() {\n\tutilLinuxPodDef, err := suite.NewPrivilegedPod(\"util-linux-tools-test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(utilLinuxPodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer utilLinuxPodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, stderr, err := utilLinuxPodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"nsenter --mount=/proc/1/ns/mnt -- /usr/local/sbin/fstrim --version\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(\"\", stderr)\n\tsuite.Require().Contains(stdout, \"fstrim from util-linux\")\n}\n\n// TestExtensionsWasmEdge verifies wasmedge runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsWasmEdge() {\n\t_, err := suite.Clientset.NodeV1().RuntimeClasses().Create(suite.ctx, &nodev1.RuntimeClass{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"wasmedge\",\n\t\t},\n\t\tHandler: \"wasmedge\",\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.NodeV1().RuntimeClasses().Delete(suite.ctx, \"wasmedge\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Clientset.CoreV1().Pods(\"default\").Create(suite.ctx, &corev1.Pod{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"wasmedge-test\",\n\t\t},\n\t\tSpec: corev1.PodSpec{\n\t\t\tContainers: []corev1.Container{\n\t\t\t\t{\n\t\t\t\t\tName:  \"wasmedge-test\",\n\t\t\t\t\tImage: \"wasmedge/example-wasi:latest\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.CoreV1().Pods(\"default\").Delete(suite.ctx, \"wasmedge-test\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t// wait for the pod to be ready\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(suite.ctx, 5*time.Minute, \"default\", \"wasmedge-test\"))\n}\n\n// TestExtensionsSpin verifies spin runtime class is working.\nfunc (suite *ExtensionsSuiteQEMU) TestExtensionsSpin() {\n\t_, err := suite.Clientset.NodeV1().RuntimeClasses().Create(suite.ctx, &nodev1.RuntimeClass{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"wasmtime-spin-v2\",\n\t\t},\n\t\tHandler: \"spin\",\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.NodeV1().RuntimeClasses().Delete(suite.ctx, \"wasmtime-spin-v2\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Clientset.CoreV1().Pods(\"default\").Create(suite.ctx, &corev1.Pod{\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName: \"spin-test\",\n\t\t},\n\t\tSpec: corev1.PodSpec{\n\t\t\tContainers: []corev1.Container{\n\t\t\t\t{\n\t\t\t\t\tName:    \"spin-test\",\n\t\t\t\t\tImage:   \"ghcr.io/spinkube/containerd-shim-spin/examples/spin-rust-hello\",\n\t\t\t\t\tCommand: []string{\"/\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tRuntimeClassName: new(\"wasmtime-spin-v2\"),\n\t\t},\n\t}, metav1.CreateOptions{})\n\tdefer suite.Clientset.CoreV1().Pods(\"default\").Delete(suite.ctx, \"spin-test\", metav1.DeleteOptions{}) //nolint:errcheck\n\n\tsuite.Require().NoError(err)\n\n\t// wait for the pod to be ready\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(suite.ctx, 5*time.Minute, \"default\", \"spin-test\"))\n}\n\n// TestLoadedKernelModule tests the /proc/modules resource.\nfunc (suite *ExtensionsSuiteQEMU) TestLoadedKernelModule() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{\n\t\t\"virtio_balloon\",\n\t\t\"virtio_pci\",\n\t\t\"virtio_pci_legacy_dev\",\n\t\t\"virtio_pci_modern_dev\",\n\t},\n\t\tfunc(res *runtime.LoadedKernelModule, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(res.TypedSpec().Size, \"kernel module size should not be empty\")\n\t\t\tasrt.NotEmpty(res.TypedSpec().Address, \"kernel module address should not be empty\")\n\t\t\tasrt.GreaterOrEqual(res.TypedSpec().ReferenceCount, 0, \"kernel module instances should be non-negative\")\n\t\t},\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &ExtensionsSuiteQEMU{})\n}\n"
  },
  {
    "path": "internal/integration/api/firewall.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"golang.org/x/sync/errgroup\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// FirewallSuite ...\ntype FirewallSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *FirewallSuite) SuiteName() string {\n\treturn \"api.FirewallSuite\"\n}\n\n// SetupTest ...\nfunc (suite *FirewallSuite) SetupTest() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state can't guarantee availability of kubelet IPs\")\n\t}\n\n\t// make sure we abort at some point in time, but give enough room for Resets\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *FirewallSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestKubeletAccess verifies that without firewall kubelet API is available, and not available otherwise.\nfunc (suite *FirewallSuite) TestKubeletAccess() {\n\tallNodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\t_, err := safe.StateGetByID[*network.NfTablesChain](client.WithNode(suite.ctx, allNodes[0]), suite.Client.COSI, \"ingress\")\n\tfirewallEnabled := err == nil\n\n\teg, ctx := errgroup.WithContext(suite.ctx)\n\n\ttransport := cleanhttp.DefaultTransport()\n\ttransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}\n\n\tclient := http.Client{\n\t\tTransport: transport,\n\t}\n\n\tfor _, node := range allNodes {\n\t\teg.Go(func() error {\n\t\t\tattemptCtx, cancel := context.WithTimeout(ctx, time.Second)\n\t\t\tdefer cancel()\n\n\t\t\treq, err := http.NewRequestWithContext(\n\t\t\t\tattemptCtx,\n\t\t\t\thttp.MethodGet,\n\t\t\t\tfmt.Sprintf(\"https://%s/healthz\", net.JoinHostPort(node, strconv.Itoa(constants.KubeletPort))),\n\t\t\t\tnil,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresp, err := client.Do(req)\n\n\t\t\tif resp != nil {\n\t\t\t\tresp.Body.Close() //nolint:errcheck\n\t\t\t}\n\n\t\t\tif firewallEnabled {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"kubelet API should not be available\")\n\t\t\t\t}\n\n\t\t\t\tif !errors.Is(err, os.ErrDeadlineExceeded) && !errors.Is(err, context.DeadlineExceeded) {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected error: %w\", err)\n\t\t\t\t}\n\t\t\t} else if err != nil {\n\t\t\t\treturn fmt.Errorf(\"kubelet API should be available: %w\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tsuite.Require().NoError(eg.Wait())\n}\n\n//go:embed testdata/nodeport.yaml\nvar nodePortServiceYAML []byte\n\n// TestNodePortAccess verifies that without firewall NodePort is available, and not available otherwise.\n//\n//nolint:gocyclo\nfunc (suite *FirewallSuite) TestNodePortAccess() {\n\tallNodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tchain, err := safe.StateGetByID[*network.NfTablesChain](client.WithNode(suite.ctx, allNodes[0]), suite.Client.COSI, \"ingress\")\n\tfirewallEnabled := err == nil\n\tfirewallDefaultBlock := firewallEnabled && chain.TypedSpec().Policy == nethelpers.VerdictDrop\n\n\t// our blocking only works with kube-proxy, so we need to make sure it's running\n\tout, err := suite.Clientset.CoreV1().Pods(\"kube-system\").List(suite.ctx, metav1.ListOptions{LabelSelector: \"k8s-app=kube-proxy\"})\n\tsuite.Require().NoError(err)\n\n\tif len(out.Items) == 0 {\n\t\tsuite.T().Skip(\"kube-proxy not running\")\n\t}\n\n\t// create a deployment with a NodePort service\n\tlocalPathStorage := suite.ParseManifests(nodePortServiceYAML)\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, localPathStorage)\n\t})\n\n\tsuite.ApplyManifests(suite.ctx, localPathStorage)\n\n\t// fetch the NodePort service\n\t// read back Service to figure out the ports\n\tsvc, err := suite.Clientset.CoreV1().Services(\"default\").Get(suite.ctx, \"test-nginx\", metav1.GetOptions{})\n\tsuite.Require().NoError(err)\n\n\tvar nodePort int\n\n\tfor _, portSpec := range svc.Spec.Ports {\n\t\tnodePort = int(portSpec.NodePort)\n\t}\n\n\tsuite.Require().NotZero(nodePort)\n\n\tsuite.T().Log(\"sleeping for 5 seconds to allow kube-proxy to update nftables\")\n\n\ttime.Sleep(5 * time.Second)\n\n\teg, ctx := errgroup.WithContext(suite.ctx)\n\n\tfor _, node := range allNodes {\n\t\teg.Go(func() error {\n\t\t\tattemptCtx, cancel := context.WithTimeout(ctx, time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tvar d net.Dialer\n\n\t\t\tconn, err := d.DialContext(attemptCtx, \"tcp\", net.JoinHostPort(node, strconv.Itoa(nodePort)))\n\t\t\tif conn != nil {\n\t\t\t\tconn.Close() //nolint:errcheck\n\t\t\t}\n\n\t\t\tif firewallDefaultBlock {\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn errors.New(\"nodePort API should not be available\")\n\t\t\t\t}\n\n\t\t\t\tif !errors.Is(err, os.ErrDeadlineExceeded) && !errors.Is(err, context.DeadlineExceeded) {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected error: %w\", err)\n\t\t\t\t}\n\t\t\t} else if err != nil {\n\t\t\t\t// ignore connection refused, as it's not firewall, but rather service proxy not ready yet\n\t\t\t\tif !strings.Contains(err.Error(), \"connection refused\") {\n\t\t\t\t\treturn fmt.Errorf(\"nodePort API should be available: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tsuite.Require().NoError(eg.Wait())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(FirewallSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/hardware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// HardwareSuite ...\ntype HardwareSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *HardwareSuite) SuiteName() string {\n\treturn \"api.HardwareSuite\"\n}\n\n// SetupTest ...\nfunc (suite *HardwareSuite) SetupTest() {\n\tif !suite.Capabilities().RunsTalosKernel {\n\t\tsuite.T().Skipf(\"doesn't run Talos kernel, skipping\")\n\t}\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *HardwareSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestSystemInformation tests that SystemInformation is populated.\nfunc (suite *HardwareSuite) TestSystemInformation() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsysInfo, err := safe.StateGetByID[*hardware.SystemInformation](client.WithNode(suite.ctx, node), suite.Client.COSI, hardware.SystemInformationID)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().NotEmpty(sysInfo.TypedSpec().UUID)\n\tsuite.Assert().NotEqual((uuid.UUID{}).String(), sysInfo.TypedSpec().UUID)\n}\n\n// TestHardwareInfo tests that hardware info is populated.\nfunc (suite *HardwareSuite) TestHardwareInfo() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tresourceList := []resource.Type{\n\t\thardware.MemoryModuleType,\n\t\thardware.ProcessorType,\n\t}\n\n\tif suite.Cluster != nil {\n\t\t// cloud VMs might not publish PCI devices\n\t\tresourceList = append(resourceList, hardware.PCIDeviceType)\n\t}\n\n\tfor _, resourceType := range resourceList {\n\t\titems, err := suite.Client.COSI.List(client.WithNode(suite.ctx, node), resource.NewMetadata(hardware.NamespaceName, resourceType, \"\", resource.VersionUndefined))\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Assert().NotEmpty(items.Items, \"resource type %s is not populated\", resourceType)\n\t}\n}\n\n// TestPCRStatus tests that the PCR was correctly extended.\nfunc (suite *HardwareSuite) TestPCRStatus() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertNoResource[*hardware.PCRStatus](ctx, suite.T(), suite.Client.COSI, hardware.NewPCCRStatus(constants.UKIPCR).Metadata().ID())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(HardwareSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tsecurityres \"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\n// ImagesSuite ...\ntype ImagesSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ImagesSuite) SuiteName() string {\n\treturn \"api.ImagesSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ImagesSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ImagesSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestList tests ImageService.List().\nfunc (suite *ImagesSuite) TestList() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\trcv, err := suite.Client.ImageClient.List(ctx, &machine.ImageServiceListRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tvar imageNames []string\n\n\tfor {\n\t\tmsg, err := rcv.Recv()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\timageNames = append(imageNames, msg.GetName())\n\t}\n\n\tsuite.Require().NotEmpty(imageNames, \"expected to receive at least one image from List()\")\n\n\tfor _, name := range imageNames {\n\t\tif strings.Contains(name, \"registry.k8s.io/pause\") {\n\t\t\treturn\n\t\t}\n\t}\n\n\tsuite.Fail(\"expected to find pause image in the list\")\n}\n\n// TestPull tests ImageService.Pull().\nfunc (suite *ImagesSuite) TestPull() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\tconst (\n\t\timage         = \"registry.k8s.io/kube-apiserver:v1.27.1\"\n\t\tdigestedImage = \"registry.k8s.io/kube-apiserver@sha256:a6daed8429c54f0008910fc4ecc17aefa1dfcd7cc2ff0089570854d4f95213ed\"\n\t)\n\n\trcv, err := suite.Client.ImageClient.Pull(ctx, &machine.ImageServicePullRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t},\n\t\tImageRef: image,\n\t})\n\tsuite.Require().NoError(err)\n\n\tvar pulledImage string\n\n\tfor {\n\t\tmsg, err := rcv.Recv()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\t// ignore progress messages, but the last message should contain the image name\n\t\tpulledImage = msg.GetName()\n\t}\n\n\tsuite.Require().NotEmpty(pulledImage, \"expected pulled image name in the response\")\n\t// depending on whether the image verification is enabled or not, the pulled image ref can be either the original one (without digest) or the digested one, so we should accept both\n\tsuite.Assert().Contains([]string{digestedImage, image}, pulledImage, \"pulled image name should match requested image\")\n}\n\n//go:embed testdata/pause.tar\nvar pauseImageTar []byte\n\n// TestImportRemove tests ImageService.Import() and ImageService.Remove().\nfunc (suite *ImagesSuite) TestImportRemove() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\t// we can only import the image if it matches Talos architecture\n\tversionResp, err := suite.Client.Version(ctx)\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(versionResp.GetMessages(), 1)\n\n\tarch := versionResp.GetMessages()[0].GetVersion().GetArch()\n\tif arch != \"amd64\" {\n\t\tsuite.T().Skipf(\"skipping import test on unsupported architecture %q\", arch)\n\t}\n\n\trcv, err := suite.Client.ImageClient.Import(ctx)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(rcv.Send(&machine.ImageServiceImportRequest{\n\t\tRequest: &machine.ImageServiceImportRequest_Containerd{\n\t\t\tContainerd: &common.ContainerdInstance{\n\t\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t\t},\n\t\t},\n\t}))\n\n\tconst chunkSize = 4 * 1024\n\n\tfor offset := 0; offset < len(pauseImageTar); offset += chunkSize {\n\t\tend := min(offset+chunkSize, len(pauseImageTar))\n\n\t\tsuite.Require().NoError(rcv.Send(&machine.ImageServiceImportRequest{\n\t\t\tRequest: &machine.ImageServiceImportRequest_ImageChunk{\n\t\t\t\tImageChunk: &common.Data{\n\t\t\t\t\tBytes: pauseImageTar[offset:end],\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}\n\n\tsuite.Require().NoError(rcv.CloseSend())\n\n\tresp, err := rcv.CloseAndRecv()\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotEmpty(resp.GetName(), \"expected imported image name in the response\")\n\tsuite.Assert().Equal(\"registry.k8s.io/pause:i-was-a-digest\", resp.GetName(), \"imported image name should match expected\")\n\n\t// now remove the imported image\n\t_, err = suite.Client.ImageClient.Remove(ctx, &machine.ImageServiceRemoveRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t},\n\t\tImageRef: resp.GetName(),\n\t})\n\tsuite.Require().NoError(err)\n\n\t// try once again\n\t_, err = suite.Client.ImageClient.Remove(ctx, &machine.ImageServiceRemoveRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_CRI,\n\t\t},\n\t\tImageRef: resp.GetName(),\n\t})\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(status.Code(err), codes.NotFound)\n}\n\n// TestVerify tests ImageService.Verify().\n//\n//nolint:gocyclo\nfunc (suite *ImagesSuite) TestVerify() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\t// query the current image verification config to restore it after the test\n\tcfg, err := suite.ReadConfigFromNode(ctx)\n\tsuite.Require().NoError(err)\n\n\toriginalConfig := xslices.Filter(cfg.Documents(), func(doc config.Document) bool {\n\t\treturn doc.Kind() == security.ImageVerificationConfigKind\n\t})\n\n\tif len(originalConfig) == 0 {\n\t\t// if the image verification hasn't been enabled, skip the test\n\t\tsuite.T().Skip(\"skipping image verification test since no image verification config is present in the cluster\")\n\t}\n\n\t// remove any existing image verification config to start with a clean slate\n\tsuite.RemoveMachineConfigDocuments(ctx, security.ImageVerificationConfigKind)\n\n\t// our custom image verification config for this test\n\timageVerificationConfig := security.NewImageVerificationConfigV1Alpha1()\n\timageVerificationConfig.ConfigRules = security.ImageVerificationRules{\n\t\t{\n\t\t\tRuleImagePattern: \"do.not.verify/*\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"registry.k8s.io/*\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:  \"https://accounts.google.com\",\n\t\t\t\tKeylessSubject: \"krel-trust@k8s-releng-prod.iam.gserviceaccount.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"localhost:4444/*\",\n\t\t\tRuleDeny:         new(true),\n\t\t},\n\t}\n\n\tsuite.PatchMachineConfig(ctx, imageVerificationConfig)\n\n\t// wait for the configuration to be applied\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{\"0000\", \"0001\", \"0002\"},\n\t\tfunc(rule *securityres.ImageVerificationRule, asrt *assert.Assertions) {\n\t\t\tswitch rule.Metadata().ID() {\n\t\t\tcase \"0000\":\n\t\t\t\tasrt.Equal(\"do.not.verify/*\", rule.TypedSpec().ImagePattern)\n\t\t\tcase \"0001\":\n\t\t\t\tasrt.Equal(\"registry.k8s.io/*\", rule.TypedSpec().ImagePattern)\n\t\t\tcase \"0002\":\n\t\t\t\tasrt.Equal(\"localhost:4444/*\", rule.TypedSpec().ImagePattern)\n\t\t\t}\n\t\t},\n\t)\n\n\tconst etcdImage = constants.EtcdImage + \":\" + constants.DefaultEtcdVersion\n\n\t// run the tests, first with an etcd image, which should be in the image cache anyways\n\tresp, err := suite.Client.ImageClient.Verify(ctx, &machine.ImageServiceVerifyRequest{\n\t\tImageRef: etcdImage, // this image is under registry.k8s.io\n\t})\n\tsuite.Require().NoError(err)\n\tsuite.Assert().True(resp.GetVerified(), \"expected image to be verified according to our config\")\n\tsuite.Assert().Equal(\"verified via legacy signature (bundle verified true)\", resp.GetMessage())\n\tsuite.Assert().Contains(resp.GetDigestedImageRef(), constants.EtcdImage)\n\tsuite.Assert().Contains(resp.GetDigestedImageRef(), \"@sha256:\")\n\n\t// now test with an image that should be skipped\n\tresp, err = suite.Client.ImageClient.Verify(ctx, &machine.ImageServiceVerifyRequest{\n\t\tImageRef: \"do.not.verify/myimage:latest\",\n\t})\n\tsuite.Require().NoError(err)\n\tsuite.Assert().False(resp.GetVerified(), \"expected image verification to be skipped according to our config\")\n\tsuite.Assert().Equal(\"verification skipped by matched rule (0000)\", resp.GetMessage())\n\n\t// finally test with an image that should be denied\n\t_, err = suite.Client.ImageClient.Verify(ctx, &machine.ImageServiceVerifyRequest{\n\t\tImageRef: \"localhost:4444/myimage:latest\",\n\t})\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.PermissionDenied, status.Code(err), \"expected image verification to be denied according to our config\")\n\tsuite.Assert().Equal(\"verification denied by matched rule (0002)\", status.Convert(err).Message())\n\n\t// now test via the image pull flow\n\trcv, err := suite.Client.ImageClient.Pull(ctx, &machine.ImageServicePullRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t},\n\t\tImageRef: etcdImage,\n\t})\n\tsuite.Require().NoError(err)\n\n\tfor {\n\t\t_, err = rcv.Recv()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\t}\n\n\tlistResp, err := suite.Client.ImageClient.List(ctx, &machine.ImageServiceListRequest{\n\t\tContainerd: &common.ContainerdInstance{\n\t\t\tDriver:    common.ContainerDriver_CRI,\n\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tvar found bool\n\n\tfor {\n\t\tmsg, err := listResp.Recv()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tif msg.GetName() == etcdImage {\n\t\t\tfound = true\n\n\t\t\tsuite.Assert().Contains(msg.GetLabels(), constants.ImageLabelVerified)\n\t\t}\n\t}\n\n\tsuite.Assert().True(found, \"expected to find the pulled image in the list response\")\n\n\t// remove our config\n\tsuite.RemoveMachineConfigDocuments(ctx, security.ImageVerificationConfigKind)\n\n\tif len(originalConfig) > 0 {\n\t\t// put back original image verification config\n\t\tsuite.PatchMachineConfig(ctx, xslices.Map(originalConfig, func(doc config.Document) any { return doc })...)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ImagesSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/kernel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// KernelSuite ...\ntype KernelSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *KernelSuite) SuiteName() string {\n\treturn \"api.KernelSuite\"\n}\n\n// SetupTest ...\nfunc (suite *KernelSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Second)\n\n\tif !suite.Capabilities().RunsTalosKernel {\n\t\tsuite.T().Skip(\"skipping kernel test since Talos kernel is not running\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *KernelSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestCmdline tests the /proc/cmdline resource.\nfunc (suite *KernelSuite) TestCmdline() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"using node %s\", node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{runtime.KernelCmdlineID},\n\t\tfunc(res *runtime.KernelCmdline, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(res.TypedSpec().Cmdline, \"kernel cmdline should not be empty\")\n\t\t},\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(KernelSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/logs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// LogsSuite verifies Logs API.\ntype LogsSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tnodeCtx context.Context //nolint:containedctx\n}\n\n// SuiteName ...\nfunc (suite *LogsSuite) SuiteName() string {\n\treturn \"api.LogsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *LogsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n\n\tsuite.nodeCtx = client.WithNodes(suite.ctx, suite.RandomDiscoveredNodeInternalIP())\n}\n\n// TearDownTest ...\nfunc (suite *LogsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestServicesHaveLogs verifies that each service has logs.\nfunc (suite *LogsSuite) TestServicesHaveLogs() {\n\tservicesReply, err := suite.Client.ServiceList(suite.nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Len(servicesReply.Messages, 1)\n\n\tlogsSize := int64(0)\n\n\tfor _, svc := range servicesReply.Messages[0].Services {\n\t\tlogsStream, err := suite.Client.Logs(\n\t\t\tsuite.nodeCtx,\n\t\t\tconstants.SystemContainerdNamespace,\n\t\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\tsvc.Id,\n\t\t\tfalse,\n\t\t\t-1,\n\t\t)\n\t\tsuite.Require().NoError(err)\n\n\t\tlogReader, err := client.ReadStream(logsStream)\n\t\tsuite.Require().NoError(err)\n\n\t\tn, err := io.Copy(io.Discard, logReader)\n\t\tsuite.Require().NoError(err)\n\n\t\tlogsSize += n\n\t}\n\n\t// overall logs shouldn't be empty\n\tsuite.Require().Greater(logsSize, int64(1024))\n}\n\n// TestAuditdLogs verifies that auditd logs are present.\nfunc (suite *LogsSuite) TestAuditdLogs() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skip auditd logs test for non-QEMU clusters\")\n\t}\n\n\tlogsStream, err := suite.Client.Logs(\n\t\tsuite.nodeCtx,\n\t\tconstants.SystemContainerdNamespace,\n\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\"auditd\",\n\t\tfalse,\n\t\t-1,\n\t)\n\tsuite.Require().NoError(err)\n\n\tlogReader, err := client.ReadStream(logsStream)\n\tsuite.Require().NoError(err)\n\n\tn, err := io.Copy(io.Discard, logReader)\n\tsuite.Require().NoError(err)\n\n\t// auditd logs shouldn't be empty\n\tsuite.Require().Greater(n, int64(1024))\n}\n\n// TestKernelLogs verifies that kernel logs are present and valid.\nfunc (suite *LogsSuite) TestKernelLogs() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skip kernel logs test for non-QEMU clusters\")\n\t}\n\n\tlogsStream, err := suite.Client.Logs(\n\t\tsuite.nodeCtx,\n\t\tconstants.SystemContainerdNamespace,\n\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\"kernel\",\n\t\tfalse,\n\t\t-1,\n\t)\n\tsuite.Require().NoError(err)\n\n\tlogReader, err := client.ReadStream(logsStream)\n\tsuite.Require().NoError(err)\n\n\tvar buf bytes.Buffer\n\n\tn, err := io.Copy(&buf, logReader)\n\tsuite.Require().NoError(err)\n\n\t// kernel logs shouldn't be empty\n\tsuite.Require().Greater(n, int64(1024))\n\n\tversion := strings.Contains(buf.String(), fmt.Sprintf(\"Linux version %s\", constants.DefaultKernelVersion))\n\toverflow := n >= logging.DesiredCapacity/2\n\n\tif !version && overflow {\n\t\tsuite.T().Skip(\"skipping the test as kernel log buffer might have overflowed\")\n\t}\n\n\tsuite.Require().Truef(\n\t\tversion,\n\t\t\"did not find kernel version (%s) in the log buffer\", constants.DefaultKernelVersion,\n\t)\n}\n\n// TestTail verifies that log tail might be requested.\nfunc (suite *LogsSuite) TestTail() {\n\t// invoke machined enough times to generate\n\t// some logs\n\tfor range 20 {\n\t\t_, err := suite.Client.Version(suite.nodeCtx)\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tfor _, tailLines := range []int32{0, 1, 10} {\n\t\tlogsStream, err := suite.Client.Logs(\n\t\t\tsuite.nodeCtx,\n\t\t\tconstants.SystemContainerdNamespace,\n\t\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\t\"apid\",\n\t\t\tfalse,\n\t\t\ttailLines,\n\t\t)\n\t\tsuite.Require().NoError(err)\n\n\t\tlogReader, err := client.ReadStream(logsStream)\n\t\tsuite.Require().NoError(err)\n\n\t\tscanner := bufio.NewScanner(logReader)\n\t\tlines := 0\n\n\t\tfor scanner.Scan() {\n\t\t\tlines++\n\t\t}\n\n\t\tsuite.Require().NoError(scanner.Err())\n\n\t\tsuite.Assert().EqualValues(tailLines, lines)\n\t}\n}\n\n// TODO: TestContainersHaveLogs (CRI, containerd)\n\n// TestServiceNotFound verifies error if service name is not found.\nfunc (suite *LogsSuite) TestServiceNotFound() {\n\tlogsStream, err := suite.Client.Logs(\n\t\tsuite.nodeCtx,\n\t\tconstants.SystemContainerdNamespace,\n\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\"nosuchservice\",\n\t\tfalse,\n\t\t-1,\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(logsStream.CloseSend())\n\n\tmsg, err := logsStream.Recv()\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Regexp(`.+log \"nosuchservice\" was not registered$`, msg.Metadata.Error)\n}\n\n// TestStreaming verifies that logs are streamed in real-time.\nfunc (suite *LogsSuite) TestStreaming() {\n\tsuite.testStreaming(-1)\n}\n\n// TestTailStreaming3 verifies tail + streaming.\nfunc (suite *LogsSuite) TestTailStreaming3() {\n\tsuite.testStreaming(3)\n}\n\n// TestTailStreaming0 verifies tail + streaming.\nfunc (suite *LogsSuite) TestTailStreaming0() {\n\tsuite.testStreaming(0)\n}\n\n//nolint:gocyclo\nfunc (suite *LogsSuite) testStreaming(tailLines int32) {\n\tif tailLines >= 0 {\n\t\t// invoke machined enough times to generate\n\t\t// some logs\n\t\tfor range tailLines {\n\t\t\t_, err := suite.Client.Stats(\n\t\t\t\tsuite.nodeCtx,\n\t\t\t\tconstants.SystemContainerdNamespace,\n\t\t\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\t)\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\t}\n\n\tlogsStream, err := suite.Client.Logs(\n\t\tsuite.nodeCtx,\n\t\tconstants.SystemContainerdNamespace,\n\t\tcommon.ContainerDriver_CONTAINERD,\n\t\t\"machined\",\n\t\ttrue,\n\t\ttailLines,\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(logsStream.CloseSend())\n\n\trespCh := make(chan *common.Data)\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\tdefer close(respCh)\n\n\t\tfor {\n\t\t\tmsg, e := logsStream.Recv()\n\t\t\tif e != nil {\n\t\t\t\terrCh <- e\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trespCh <- msg\n\t\t}\n\t}()\n\n\tdefer func() {\n\t\tsuite.ctxCancel()\n\t\t// drain respCh\n\t\tfor range respCh { //nolint:revive\n\t\t}\n\t}()\n\n\tlinesDrained := 0\n\n\t// first, drain the stream until flow stops\nDrainLoop:\n\tfor {\n\t\tselect {\n\t\tcase msg, ok := <-respCh:\n\t\t\tsuite.Require().True(ok)\n\t\t\tsuite.Assert().NotEmpty(msg.Bytes)\n\t\t\tlinesDrained += bytes.Count(msg.Bytes, []byte{'\\n'})\n\t\tcase <-time.After(200 * time.Millisecond):\n\t\t\tbreak DrainLoop\n\t\t}\n\t}\n\n\tsuite.Assert().GreaterOrEqual(int32(linesDrained), tailLines)\n\n\t// invoke machined API\n\t_, err = suite.Client.Stats(suite.nodeCtx, constants.SystemContainerdNamespace, common.ContainerDriver_CONTAINERD)\n\tsuite.Require().NoError(err)\n\n\t// there should be a line in the logs\n\tselect {\n\tcase msg, ok := <-respCh:\n\t\tsuite.Require().True(ok)\n\t\tsuite.Assert().NotEmpty(msg.Bytes)\n\tcase <-time.After(200 * time.Millisecond):\n\t\tsuite.Assert().Fail(\"no log message received\")\n\t}\n\n\tselect {\n\tcase err = <-errCh:\n\t\tsuite.Require().NoError(err)\n\tdefault:\n\t}\n}\n\n// TestPersistent confirms there are persistent logs stored in /var/log.\nfunc (suite *LogsSuite) TestPersistent() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tstream, err := suite.Client.MachineClient.List(ctx, &machineapi.ListRequest{Root: constants.LogMountPoint})\n\tsuite.Require().NoError(err)\n\n\tsizes := map[string]int64{}\n\n\tfor {\n\t\tvar info *machineapi.FileInfo\n\n\t\tinfo, err = stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || client.StatusCode(err) == codes.Canceled {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tsizes[filepath.Base(info.Name)] = info.Size\n\t}\n\n\tfor _, name := range []string{\n\t\t\"machined.log\",\n\t\t\"controller-runtime.log\",\n\t\t\"kubelet.log\",\n\t} {\n\t\tsuite.Assert().Contains(sizes, name)\n\n\t\trotatedSize, rotated := sizes[name+\".1\"]\n\t\tsuite.Assert().Truef(\n\t\t\tsizes[name] > 1000 || (rotated && rotatedSize > 10000),\n\t\t\t\"Expected either more than 1000 bytes in the log file or a rotated file for %s\",\n\t\t\tname,\n\t\t)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(LogsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/machine-status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// MachineStatusSuite ...\ntype MachineStatusSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *MachineStatusSuite) SuiteName() string {\n\treturn \"api.MachineStatusSuite\"\n}\n\n// SetupTest ...\nfunc (suite *MachineStatusSuite) SetupTest() {\n\t// make sure we abort at some point in time, but give enough room for MachineStatuss\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *MachineStatusSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestMachineStatusReady tests that MachineStatus is eventually ready & running.\nfunc (suite *MachineStatusSuite) TestMachineStatusReady() {\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, node := range nodes {\n\t\tsuite.Assert().NoError(suite.waitMachineStatusReady(node))\n\t}\n}\n\nfunc (suite *MachineStatusSuite) waitMachineStatusReady(node string) error {\n\tctx, cancel := context.WithTimeout(client.WithNode(suite.ctx, node), 30*time.Second)\n\tdefer cancel()\n\n\twatchCh := make(chan safe.WrappedStateEvent[*runtime.MachineStatus])\n\n\tif err := safe.StateWatch(\n\t\tctx,\n\t\tsuite.Client.COSI,\n\t\tresource.NewMetadata(runtime.NamespaceName, runtime.MachineStatusType, runtime.MachineStatusID, resource.VersionUndefined),\n\t\twatchCh,\n\t); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn fmt.Errorf(\"%s: timed out waiting for MachineStatus to be ready\", node)\n\t\tcase event := <-watchCh:\n\t\t\tmachineStatus, err := event.Resource()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif machineStatus.TypedSpec().Stage == runtime.MachineStageRunning && machineStatus.TypedSpec().Status.Ready {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tsuite.T().Logf(\n\t\t\t\t\"%s: MachineStatus stage %s ready %v, unmetConditions %v\",\n\t\t\t\tnode, machineStatus.TypedSpec().Stage,\n\t\t\t\tmachineStatus.TypedSpec().Status.Ready,\n\t\t\t\tmachineStatus.TypedSpec().Status.UnmetConditions,\n\t\t\t)\n\t\t}\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MachineStatusSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/monitoring.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// MonitoringSuite ...\ntype MonitoringSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *MonitoringSuite) SuiteName() string {\n\treturn \"api.MonitoringSuite\"\n}\n\n// SetupTest ...\nfunc (suite *MonitoringSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *MonitoringSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestMonitoringAPIs tests that monitoring APIs are working.\nfunc (suite *MonitoringSuite) TestMonitoringAPIs() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t_, err := suite.Client.MachineClient.CPUFreqStats(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.CPUInfo(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.DiskStats(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.LoadAvg(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.Memory(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.NetworkDeviceStats(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.Client.MachineClient.SystemStat(nodeCtx, &emptypb.Empty{})\n\tsuite.Require().NoError(err)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MonitoringSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/network-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"golang.zx2c4.com/wireguard/wgctrl/wgtypes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\tnetworkres \"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// NetworkConfigSuite ...\ntype NetworkConfigSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *NetworkConfigSuite) SuiteName() string {\n\treturn \"api.NetworkConfigSuite\"\n}\n\n// SetupTest ...\nfunc (suite *NetworkConfigSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *NetworkConfigSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestStaticHostConfig tests that /etc/hosts updates are working.\nfunc (suite *NetworkConfigSuite) TestStaticHostConfig() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\thost1 := network.NewStaticHostConfigV1Alpha1(\"1.2.3.4\")\n\thost1.Hostnames = []string{\"example.com\", \"example2\"}\n\n\thost2 := network.NewStaticHostConfigV1Alpha1(\"2001:db8::1\")\n\thost2.Hostnames = []string{\"v6\"}\n\n\tsuite.PatchMachineConfig(nodeCtx, host1, host2)\n\n\tsuite.EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\thosts := suite.ReadFile(nodeCtx, \"/etc/hosts\")\n\t\t\tscanner := bufio.NewScanner(strings.NewReader(hosts))\n\n\t\t\tvar found1, found2 bool\n\n\t\t\tfor scanner.Scan() {\n\t\t\t\tline := scanner.Text()\n\n\t\t\t\tswitch {\n\t\t\t\tcase strings.HasPrefix(line, \"1.2.3.4\"):\n\t\t\t\t\tfound1 = true\n\n\t\t\t\t\tasrt.Contains(line, \"example.com\", \"expected to find hostname in IPv4 entry\")\n\t\t\t\t\tasrt.Contains(line, \"example2\", \"expected to find hostname in IPv4 entry\")\n\t\t\t\tcase strings.HasPrefix(line, \"2001:db8::1\"):\n\t\t\t\t\tfound2 = true\n\n\t\t\t\t\tasrt.Contains(line, \"v6\", \"expected to find hostname in IPv6 entry\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tasrt.True(found1, \"expected to find IPv4 entry in /etc/hosts\")\n\t\t\tasrt.True(found2, \"expected to find IPv6 entry in /etc/hosts\")\n\t\t},\n\t\ttime.Second, time.Millisecond, \"waiting for /etc/hosts to be updated\",\n\t)\n\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, network.StaticHostKind)\n\n\tsuite.EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\thosts := suite.ReadFile(nodeCtx, \"/etc/hosts\")\n\n\t\t\tasrt.NotContains(hosts, \"1.2.3.4\", \"expected to not find IPv4 entry in /etc/hosts\")\n\t\t\tasrt.NotContains(hosts, \"2001:db8::1\", \"expected to not find IPv6 entry in /etc/hosts\")\n\t\t},\n\t\ttime.Second, time.Millisecond, \"waiting for /etc/hosts to be updated\",\n\t)\n}\n\n// TestDummyLinkConfig tests creation of dummy link interfaces.\nfunc (suite *NetworkConfigSuite) TestDummyLinkConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tdummyName := fmt.Sprintf(\"dummy%d\", rand.IntN(10000))\n\n\tdummy := network.NewDummyLinkConfigV1Alpha1(dummyName)\n\tdummy.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\tdummy.LinkUp = new(true)\n\tdummy.LinkMTU = 9000\n\tdummy.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"fd13:1234::1/64\"),\n\t\t\tAddressPriority: new(uint32(100)),\n\t\t},\n\t}\n\tdummy.LinkRoutes = []network.RouteConfig{\n\t\t{\n\t\t\tRouteDestination: network.Prefix{Prefix: netip.MustParsePrefix(\"fd13:1235::/64\")},\n\t\t\tRouteGateway:     network.Addr{Addr: netip.MustParseAddr(\"fd13:1234::ffff\")},\n\t\t},\n\t}\n\n\taddressID := dummyName + \"/fd13:1234::1/64\"\n\trouteID := dummyName + \"/inet6/fd13:1234::ffff/fd13:1235::/64/1024\"\n\taddressRouteID := dummyName + \"/inet6//fd13:1234::/64/100\"\n\n\tsuite.PatchMachineConfig(nodeCtx, dummy)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, dummyName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"dummy\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(dummy.HardwareAddressConfig, link.TypedSpec().HardwareAddr)\n\t\t\tasrt.Equal(dummy.LinkMTU, link.TypedSpec().MTU)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, addressID,\n\t\tfunc(addr *networkres.AddressStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(dummyName, addr.TypedSpec().LinkName)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{routeID, addressRouteID},\n\t\tfunc(route *networkres.RouteStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(dummyName, route.TypedSpec().OutLinkName)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.DummyLinkKind, dummyName)\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, dummyName)\n\trtestutils.AssertNoResource[*networkres.AddressStatus](nodeCtx, suite.T(), suite.Client.COSI, addressID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, addressRouteID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, routeID)\n}\n\n// TestLinkConfig tests configuring physical links.\nfunc (suite *NetworkConfigSuite) TestLinkConfig() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\t// find the first physical link\n\tlinks, err := safe.ReaderListAll[*networkres.LinkStatus](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tvar linkName string\n\n\tfor link := range links.All() {\n\t\tif link.TypedSpec().Physical() {\n\t\t\tlinkName = link.Metadata().ID()\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Require().NotEmpty(linkName, \"expected to find at least one physical link\")\n\n\tcfg := network.NewLinkConfigV1Alpha1(linkName)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"fd13:1234::2/64\"),\n\t\t\tAddressPriority: new(uint32(2048)),\n\t\t},\n\t}\n\n\taddressID := linkName + \"/fd13:1234::2/64\"\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, addressID,\n\t\tfunc(addr *networkres.AddressStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(linkName, addr.TypedSpec().LinkName)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.LinkKind, linkName)\n\n\trtestutils.AssertNoResource[*networkres.AddressStatus](nodeCtx, suite.T(), suite.Client.COSI, addressID)\n}\n\n// TestLinkAliasConfig tests configuring physical link aliases.\nfunc (suite *NetworkConfigSuite) TestLinkAliasConfig() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\t// find the first physical link without an alias\n\tlinks, err := safe.ReaderListAll[*networkres.LinkStatus](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tvar (\n\t\tlinkName      string\n\t\tpermanentAddr string\n\t)\n\n\tfor link := range links.All() {\n\t\tif link.TypedSpec().Physical() && link.TypedSpec().Alias == \"\" {\n\t\t\tlinkName = link.Metadata().ID()\n\t\t\tpermanentAddr = link.TypedSpec().PermanentAddr.String()\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif linkName != \"\" {\n\t\t// we have unaliased physical link to test with, try aliasing it\n\t\tconst aliasName = \"test-alias\"\n\n\t\tcfg := network.NewLinkAliasConfigV1Alpha1(aliasName)\n\t\tcfg.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(\"mac(link.permanent_addr) == '\"+permanentAddr+\"'\", celenv.LinkLocator()))\n\n\t\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(aliasName, link.TypedSpec().Alias)\n\t\t\t},\n\t\t)\n\n\t\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.LinkAliasKind, aliasName)\n\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, linkName,\n\t\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Empty(link.TypedSpec().Alias)\n\t\t\t},\n\t\t)\n\t} else {\n\t\tsuite.T().Log(\"all physical links are already aliased, verifying existing aliases\")\n\n\t\t// no unaliased physical links, verify that alias worked properly\n\t\tfor link := range links.All() {\n\t\t\tif link.TypedSpec().Physical() && link.TypedSpec().Alias != \"\" {\n\t\t\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, link.Metadata().ID(),\n\t\t\t\t\tfunc(linkAlias *networkres.LinkAliasSpec, asrt *assert.Assertions) {\n\t\t\t\t\t\tasrt.Equal(link.TypedSpec().Alias, linkAlias.TypedSpec().Alias)\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TestVirtualIPConfig tests configuring virtual IPs.\nfunc (suite *NetworkConfigSuite) TestVirtualIPConfig() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\t// find the first physical link\n\tlinks, err := safe.ReaderListAll[*networkres.LinkStatus](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tvar linkName string\n\n\tfor link := range links.All() {\n\t\tif link.TypedSpec().Physical() {\n\t\t\tlinkName = link.Metadata().ID()\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Require().NotEmpty(linkName, \"expected to find at least one physical link\")\n\n\t// using link-local address to avoid kube-apiserver picking it up\n\tvirtualIP := \"169.254.100.100\"\n\n\tcfg := network.NewLayer2VIPConfigV1Alpha1(virtualIP)\n\tcfg.LinkName = linkName\n\n\taddressID := linkName + \"/\" + virtualIP + \"/32\"\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, addressID,\n\t\tfunc(addr *networkres.AddressStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(linkName, addr.TypedSpec().LinkName)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.Layer2VIPKind, virtualIP)\n\n\trtestutils.AssertNoResource[*networkres.AddressStatus](nodeCtx, suite.T(), suite.Client.COSI, addressID)\n}\n\n// TestVLANConfig tests creation of VLAN interfaces.\nfunc (suite *NetworkConfigSuite) TestVLANConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tdummyName := fmt.Sprintf(\"dummy%d\", rand.IntN(10000))\n\n\tdummy := network.NewDummyLinkConfigV1Alpha1(dummyName)\n\tdummy.LinkUp = new(true)\n\tdummy.LinkMTU = 9000\n\n\tvlanName := dummyName + \".v\"\n\n\tvlan := network.NewVLANConfigV1Alpha1(vlanName)\n\tvlan.VLANIDConfig = 100\n\tvlan.LinkMTU = 2000\n\tvlan.ParentLinkConfig = dummyName\n\tvlan.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"fd13:1234::1/64\"),\n\t\t\tAddressPriority: new(uint32(100)),\n\t\t},\n\t}\n\tvlan.LinkRoutes = []network.RouteConfig{\n\t\t{\n\t\t\tRouteDestination: network.Prefix{Prefix: netip.MustParsePrefix(\"fd13:1235::/64\")},\n\t\t\tRouteGateway:     network.Addr{Addr: netip.MustParseAddr(\"fd13:1234::ffff\")},\n\t\t},\n\t}\n\n\taddressID := vlanName + \"/fd13:1234::1/64\"\n\trouteID := vlanName + \"/inet6/fd13:1234::ffff/fd13:1235::/64/1024\"\n\taddressRouteID := vlanName + \"/inet6//fd13:1234::/64/100\"\n\n\tsuite.PatchMachineConfig(nodeCtx, dummy, vlan)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, dummyName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"dummy\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(dummy.LinkMTU, link.TypedSpec().MTU)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, vlanName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"vlan\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(vlan.LinkMTU, link.TypedSpec().MTU)\n\t\t\tasrt.NotZero(link.TypedSpec().LinkIndex)\n\t\t\tasrt.Equal(vlan.VLANIDConfig, link.TypedSpec().VLAN.VID)\n\t\t\tasrt.Equal(nethelpers.VLANProtocol8021Q, link.TypedSpec().VLAN.Protocol)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, addressID,\n\t\tfunc(addr *networkres.AddressStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(vlanName, addr.TypedSpec().LinkName)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{routeID, addressRouteID},\n\t\tfunc(route *networkres.RouteStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(vlanName, route.TypedSpec().OutLinkName)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.VLANKind, vlanName)\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.DummyLinkKind, dummyName)\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, dummyName)\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, vlanName)\n\trtestutils.AssertNoResource[*networkres.AddressStatus](nodeCtx, suite.T(), suite.Client.COSI, addressID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, addressRouteID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, routeID)\n}\n\n// TestBondConfig tests creation of bond interfaces.\nfunc (suite *NetworkConfigSuite) TestBondConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tdummyNames := xslices.Map([]int{0, 1}, func(int) string {\n\t\treturn fmt.Sprintf(\"dummy%d\", rand.IntN(10000))\n\t})\n\n\tdummyConfigs := xslices.Map(dummyNames, func(name string) any {\n\t\treturn network.NewDummyLinkConfigV1Alpha1(name)\n\t})\n\n\tbondName := \"agg.\" + strconv.Itoa(rand.IntN(10000))\n\n\tbond := network.NewBondConfigV1Alpha1(bondName)\n\tbond.BondLinks = dummyNames\n\tbond.BondMode = new(nethelpers.BondMode8023AD)\n\tbond.BondMIIMon = new(uint32(100))\n\tbond.BondUpDelay = new(uint32(200))\n\tbond.BondDownDelay = new(uint32(300))\n\tbond.BondLACPRate = new(nethelpers.LACPRateSlow)\n\tbond.BondADActorSysPrio = new(uint16(65535))\n\tbond.BondResendIGMP = new(uint32(1))\n\tbond.BondPacketsPerSlave = new(uint32(1))\n\tbond.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\tbond.LinkUp = new(true)\n\tbond.LinkMTU = 2000\n\tbond.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"fd13:1235::1/64\"),\n\t\t\tAddressPriority: new(uint32(100)),\n\t\t},\n\t}\n\tbond.LinkRoutes = []network.RouteConfig{\n\t\t{\n\t\t\tRouteDestination: network.Prefix{Prefix: netip.MustParsePrefix(\"fd13:1236::/64\")},\n\t\t\tRouteGateway:     network.Addr{Addr: netip.MustParseAddr(\"fd13:1235::ffff\")},\n\t\t},\n\t}\n\n\taddressID := bondName + \"/fd13:1235::1/64\"\n\trouteID := bondName + \"/inet6/fd13:1235::ffff/fd13:1236::/64/1024\"\n\taddressRouteID := bondName + \"/inet6//fd13:1235::/64/100\"\n\n\tsuite.PatchMachineConfig(nodeCtx, append(dummyConfigs, bond)...)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI, dummyNames,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"dummy\", link.TypedSpec().Kind)\n\t\t\tasrt.NotZero(link.TypedSpec().MasterIndex)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, bondName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"bond\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(nethelpers.OperStateUp, link.TypedSpec().OperationalState)\n\t\t\tasrt.Equal(bond.LinkMTU, link.TypedSpec().MTU)\n\t\t\tasrt.Equal(nethelpers.BondMode8023AD, link.TypedSpec().BondMaster.Mode)\n\t\t\tasrt.Equal(bond.HardwareAddressConfig, link.TypedSpec().HardwareAddr)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, addressID,\n\t\tfunc(addr *networkres.AddressStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(bondName, addr.TypedSpec().LinkName)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{routeID, addressRouteID},\n\t\tfunc(route *networkres.RouteStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(bondName, route.TypedSpec().OutLinkName)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.BondKind, bondName)\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.DummyLinkKind, dummyNames...)\n\n\tfor _, dummyName := range dummyNames {\n\t\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, dummyName)\n\t}\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, bondName)\n\trtestutils.AssertNoResource[*networkres.AddressStatus](nodeCtx, suite.T(), suite.Client.COSI, addressID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, addressRouteID)\n\trtestutils.AssertNoResource[*networkres.RouteStatus](nodeCtx, suite.T(), suite.Client.COSI, routeID)\n}\n\n// TestBridgeConfig tests creation of bridge interfaces.\nfunc (suite *NetworkConfigSuite) TestBridgeConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tdummyNames := xslices.Map([]int{0, 1}, func(int) string {\n\t\treturn fmt.Sprintf(\"dummy%d\", rand.IntN(10000))\n\t})\n\n\tdummyConfigs := xslices.Map(dummyNames, func(name string) any {\n\t\treturn network.NewDummyLinkConfigV1Alpha1(name)\n\t})\n\n\tbridgeName := \"bridge.\" + strconv.Itoa(rand.IntN(10000))\n\n\tbridge := network.NewBridgeConfigV1Alpha1(bridgeName)\n\tbridge.BridgeLinks = dummyNames\n\tbridge.BridgeSTP.BridgeSTPEnabled = new(true)\n\tbridge.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\tbridge.LinkUp = new(true)\n\n\tsuite.PatchMachineConfig(nodeCtx, append(dummyConfigs, bridge)...)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI, dummyNames,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"dummy\", link.TypedSpec().Kind)\n\t\t\tasrt.NotZero(link.TypedSpec().MasterIndex)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, bridgeName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"bridge\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(pointer.SafeDeref(bridge.BridgeSTP.BridgeSTPEnabled), link.TypedSpec().BridgeMaster.STP.Enabled)\n\t\t\tasrt.Equal(bridge.HardwareAddressConfig, link.TypedSpec().HardwareAddr)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.BridgeKind, bridgeName)\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.DummyLinkKind, dummyNames...)\n\n\tfor _, dummyName := range dummyNames {\n\t\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, dummyName)\n\t}\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, bridgeName)\n}\n\n// TestVRFConfig tests creation of vrf interfaces.\nfunc (suite *NetworkConfigSuite) TestVRFConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tdummyNames := xslices.Map([]int{0, 1}, func(int) string {\n\t\treturn fmt.Sprintf(\"dummy%d\", rand.IntN(10000))\n\t})\n\n\tdummyConfigs := xslices.Map(dummyNames, func(name string) any {\n\t\treturn network.NewDummyLinkConfigV1Alpha1(name)\n\t})\n\n\tvrfName := \"vrf.\" + strconv.Itoa(rand.IntN(10000))\n\n\tvrf := network.NewVRFConfigV1Alpha1(vrfName)\n\tvrf.VRFLinks = dummyNames\n\tvrf.VRFTable = nethelpers.RoutingTable(123)\n\tvrf.HardwareAddressConfig = nethelpers.HardwareAddr{0x02, 0x00, 0x00, 0x00, byte(rand.IntN(256)), byte(rand.IntN(256))}\n\tvrf.LinkUp = new(true)\n\n\tsuite.PatchMachineConfig(nodeCtx, append(dummyConfigs, vrf)...)\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI, dummyNames,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"dummy\", link.TypedSpec().Kind)\n\t\t\tasrt.NotZero(link.TypedSpec().MasterIndex)\n\t\t},\n\t)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, vrfName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"vrf\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(vrf.VRFTable, link.TypedSpec().VRFMaster.Table)\n\t\t\tasrt.Equal(vrf.HardwareAddressConfig, link.TypedSpec().HardwareAddr)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.VRFKind, vrfName)\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.DummyLinkKind, dummyNames...)\n\n\tfor _, dummyName := range dummyNames {\n\t\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, dummyName)\n\t}\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, vrfName)\n}\n\n// TestWireguardConfig tests creation of Wireguard interfaces.\nfunc (suite *NetworkConfigSuite) TestWireguardConfig() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\twgName := \"wg.\" + strconv.Itoa(rand.IntN(10000))\n\n\tprivateKey, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\tpeerKey, err := wgtypes.GeneratePrivateKey()\n\tsuite.Require().NoError(err)\n\n\twg := network.NewWireguardConfigV1Alpha1(wgName)\n\twg.WireguardPrivateKey = privateKey.String()\n\twg.WireguardListenPort = 3042\n\twg.WireguardPeers = []network.WireguardPeer{\n\t\t{\n\t\t\tWireguardPublicKey: peerKey.PublicKey().String(),\n\t\t\tWireguardAllowedIPs: []network.Prefix{\n\t\t\t\t{\n\t\t\t\t\tPrefix: netip.MustParsePrefix(\"192.168.2.0/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\twg.LinkUp = new(true)\n\n\tsuite.PatchMachineConfig(nodeCtx, wg)\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, wgName,\n\t\tfunc(link *networkres.LinkStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"wireguard\", link.TypedSpec().Kind)\n\t\t\tasrt.Equal(wg.WireguardListenPort, link.TypedSpec().Wireguard.ListenPort)\n\n\t\t\tif asrt.Len(link.TypedSpec().Wireguard.Peers, 1) {\n\t\t\t\tasrt.Equal(peerKey.PublicKey().String(), link.TypedSpec().Wireguard.Peers[0].PublicKey)\n\t\t\t}\n\n\t\t\tasrt.Equal(privateKey.PublicKey().String(), link.TypedSpec().Wireguard.PublicKey)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.WireguardKind, wgName)\n\n\trtestutils.AssertNoResource[*networkres.LinkStatus](nodeCtx, suite.T(), suite.Client.COSI, wgName)\n}\n\n// TestBlackholeRouteConfig tests creation of blackhole routes.\nfunc (suite *NetworkConfigSuite) TestBlackholeRouteConfig() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing on node %q\", node)\n\n\tconst dest = \"fd13:1236::/64\"\n\n\tcfg := network.NewBlackholeRouteConfigV1Alpha1(dest)\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst routeBlackholeID = \"lo/inet6//\" + dest + \"/1024\"\n\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{routeBlackholeID},\n\t\tfunc(route *networkres.RouteStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.TypeBlackhole, route.TypedSpec().Type)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.BlackholeRouteKind, dest)\n}\n\n// routingRuleTestCtx creates a context with a longer timeout for routing rule tests,\n// because the RoutingRuleStatusController uses 30s polling (no rtnetlink multicast group for rule changes).\nfunc (suite *NetworkConfigSuite) routingRuleTestCtx() (context.Context, context.CancelFunc) {\n\treturn context.WithTimeout(context.Background(), 2*time.Minute)\n}\n\n// TestRoutingRuleBasic tests creation of a routing rule with a numeric table ID.\n//\n//nolint:dupl\nfunc (suite *NetworkConfigSuite) TestRoutingRuleBasic() {\n\tctx, cancel := suite.routingRuleTestCtx()\n\tdefer cancel()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tsuite.T().Logf(\"testing routing rule (basic) on node %q\", node)\n\n\tconst rulePriority uint32 = 1000\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(rulePriority)\n\tcfg.RuleSrc = network.Prefix{Prefix: netip.MustParsePrefix(\"10.99.0.0/16\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst ruleStatusID = \"inet4/01000\"\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID,\n\t\tfunc(rule *networkres.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, rule.TypedSpec().Family)\n\t\t\tasrt.Equal(netip.MustParsePrefix(\"10.99.0.0/16\"), rule.TypedSpec().Src)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(100), rule.TypedSpec().Table)\n\t\t\tasrt.Equal(uint32(1000), rule.TypedSpec().Priority)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.RoutingRuleKind, strconv.FormatUint(uint64(rulePriority), 10))\n\n\trtestutils.AssertNoResource[*networkres.RoutingRuleStatus](nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID)\n}\n\n// TestRoutingRuleIPv6 tests creation of an IPv6 routing rule.\n//\n//nolint:dupl\nfunc (suite *NetworkConfigSuite) TestRoutingRuleIPv6() {\n\tctx, cancel := suite.routingRuleTestCtx()\n\tdefer cancel()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tsuite.T().Logf(\"testing routing rule (IPv6) on node %q\", node)\n\n\tconst rulePriority uint32 = 3000\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(rulePriority)\n\tcfg.RuleSrc = network.Prefix{Prefix: netip.MustParsePrefix(\"fd99:1234::/48\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst ruleStatusID = \"inet6/03000\"\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID,\n\t\tfunc(rule *networkres.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet6, rule.TypedSpec().Family)\n\t\t\tasrt.Equal(netip.MustParsePrefix(\"fd99:1234::/48\"), rule.TypedSpec().Src)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(100), rule.TypedSpec().Table)\n\t\t\tasrt.Equal(uint32(3000), rule.TypedSpec().Priority)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.RoutingRuleKind, strconv.FormatUint(uint64(rulePriority), 10))\n\n\trtestutils.AssertNoResource[*networkres.RoutingRuleStatus](nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID)\n}\n\n// TestRoutingRuleSrcAndDst tests creation of a routing rule with both source and destination prefixes.\nfunc (suite *NetworkConfigSuite) TestRoutingRuleSrcAndDst() {\n\tctx, cancel := suite.routingRuleTestCtx()\n\tdefer cancel()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tsuite.T().Logf(\"testing routing rule (src+dst) on node %q\", node)\n\n\tconst rulePriority uint32 = 4000\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(rulePriority)\n\tcfg.RuleSrc = network.Prefix{Prefix: netip.MustParsePrefix(\"10.96.0.0/16\")}\n\tcfg.RuleDst = network.Prefix{Prefix: netip.MustParsePrefix(\"192.168.99.0/24\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst ruleStatusID = \"inet4/04000\"\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID,\n\t\tfunc(rule *networkres.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, rule.TypedSpec().Family)\n\t\t\tasrt.Equal(netip.MustParsePrefix(\"10.96.0.0/16\"), rule.TypedSpec().Src)\n\t\t\tasrt.Equal(netip.MustParsePrefix(\"192.168.99.0/24\"), rule.TypedSpec().Dst)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(100), rule.TypedSpec().Table)\n\t\t\tasrt.Equal(uint32(4000), rule.TypedSpec().Priority)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.RoutingRuleKind, strconv.FormatUint(uint64(rulePriority), 10))\n\n\trtestutils.AssertNoResource[*networkres.RoutingRuleStatus](nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID)\n}\n\n// TestRoutingRuleBlackholeAction tests creation of a routing rule with blackhole action.\nfunc (suite *NetworkConfigSuite) TestRoutingRuleBlackholeAction() {\n\tctx, cancel := suite.routingRuleTestCtx()\n\tdefer cancel()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tsuite.T().Logf(\"testing routing rule (blackhole action) on node %q\", node)\n\n\tconst rulePriority uint32 = 5000\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(rulePriority)\n\tcfg.RuleSrc = network.Prefix{Prefix: netip.MustParsePrefix(\"10.95.0.0/16\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\tcfg.RuleAction = nethelpers.RoutingRuleActionBlackhole\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst ruleStatusID = \"inet4/05000\"\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID,\n\t\tfunc(rule *networkres.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, rule.TypedSpec().Family)\n\t\t\tasrt.Equal(nethelpers.RoutingRuleActionBlackhole, rule.TypedSpec().Action)\n\t\t\tasrt.Equal(uint32(5000), rule.TypedSpec().Priority)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.RoutingRuleKind, strconv.FormatUint(uint64(rulePriority), 10))\n\n\trtestutils.AssertNoResource[*networkres.RoutingRuleStatus](nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID)\n}\n\n// TestRoutingRuleFwMark tests creation of a routing rule with firewall mark matching.\nfunc (suite *NetworkConfigSuite) TestRoutingRuleFwMark() {\n\tctx, cancel := suite.routingRuleTestCtx()\n\tdefer cancel()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tsuite.T().Logf(\"testing routing rule (fwmark) on node %q\", node)\n\n\tconst rulePriority uint32 = 6000\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(rulePriority)\n\tcfg.RuleSrc = network.Prefix{Prefix: netip.MustParsePrefix(\"10.94.0.0/16\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\tcfg.RuleFwMark = 0x100\n\tcfg.RuleFwMask = 0xff00\n\n\tsuite.PatchMachineConfig(nodeCtx, cfg)\n\n\tconst ruleStatusID = \"inet4/06000\"\n\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID,\n\t\tfunc(rule *networkres.RoutingRuleStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(nethelpers.FamilyInet4, rule.TypedSpec().Family)\n\t\t\tasrt.Equal(nethelpers.RoutingTable(100), rule.TypedSpec().Table)\n\t\t\tasrt.Equal(uint32(6000), rule.TypedSpec().Priority)\n\t\t\tasrt.Equal(uint32(0x100), rule.TypedSpec().FwMark)\n\t\t\tasrt.Equal(uint32(0xff00), rule.TypedSpec().FwMask)\n\t\t},\n\t)\n\n\tsuite.RemoveMachineConfigDocumentsByName(nodeCtx, network.RoutingRuleKind, strconv.FormatUint(uint64(rulePriority), 10))\n\n\trtestutils.AssertNoResource[*networkres.RoutingRuleStatus](nodeCtx, suite.T(), suite.Client.COSI, ruleStatusID)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(NetworkConfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/node-annotations.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// NodeAnnotationsSuite verifies updating node annotations via machine config.\ntype NodeAnnotationsSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *NodeAnnotationsSuite) SuiteName() string {\n\treturn \"api.NodeAnnotationsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *NodeAnnotationsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *NodeAnnotationsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestUpdateControlPlane verifies node annotation updates on control plane nodes.\nfunc (suite *NodeAnnotationsSuite) TestUpdateControlPlane() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.testUpdate(node)\n}\n\n// TestUpdateWorker verifies node annotation updates on worker nodes.\nfunc (suite *NodeAnnotationsSuite) TestUpdateWorker() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tsuite.testUpdate(node)\n}\n\n// testUpdate cycles through a set of node annotation updates reverting the change in the end.\nfunc (suite *NodeAnnotationsSuite) testUpdate(node string) {\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"updating annotations on node %q (%q)\", node, k8sNode.Name)\n\n\twatchCh := suite.SetupNodeInformer(suite.ctx, k8sNode.Name)\n\n\t// set two new annotation\n\tsuite.setNodeAnnotations(node, map[string]string{\n\t\t\"talos.dev/ann1\": \"value1\",\n\t\t\"talos.dev/ann2\": \"value2\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/ann1\": \"value1\",\n\t\t\"talos.dev/ann2\": \"value2\",\n\t})\n\n\t// remove one annotation owned by Talos\n\tsuite.setNodeAnnotations(node, map[string]string{\n\t\t\"talos.dev/ann1\": \"foo\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/ann1\": \"foo\",\n\t\t\"talos.dev/ann2\": \"\",\n\t})\n\n\t// remove all Talos annoations\n\tsuite.setNodeAnnotations(node, nil)\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/ann1\": \"\",\n\t\t\"talos.dev/ann2\": \"\",\n\t})\n}\n\nfunc (suite *NodeAnnotationsSuite) waitUntil(watchCh <-chan *v1.Node, expectedAnnotations map[string]string) {\nouter:\n\tfor {\n\t\tselect {\n\t\tcase k8sNode := <-watchCh:\n\t\t\tsuite.T().Logf(\"annotations %#v\", k8sNode.Annotations)\n\n\t\t\tfor k, v := range expectedAnnotations {\n\t\t\t\tif v == \"\" {\n\t\t\t\t\t_, ok := k8sNode.Annotations[k]\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tsuite.T().Logf(\"annotation %q is still present\", k)\n\n\t\t\t\t\t\tcontinue outer\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif k8sNode.Annotations[k] != v {\n\t\t\t\t\tsuite.T().Logf(\"annotation %q is %q but expected %q\", k, k8sNode.Annotations[k], v)\n\n\t\t\t\t\tcontinue outer\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn\n\t\tcase <-suite.ctx.Done():\n\t\t\tsuite.T().Fatal(\"timeout\")\n\t\t}\n\t}\n}\n\nfunc (suite *NodeAnnotationsSuite) setNodeAnnotations(nodeIP string, nodeAnnotations map[string]string) { //nolint:dupl\n\tnodeCtx := client.WithNode(suite.ctx, nodeIP)\n\n\tnodeConfig, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tbytes := suite.PatchV1Alpha1Config(nodeConfig, func(nodeConfigRaw *v1alpha1.Config) {\n\t\tnodeConfigRaw.MachineConfig.MachineNodeAnnotations = nodeAnnotations\n\t})\n\n\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: bytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\n\tsuite.Require().NoError(err)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(NodeAnnotationsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/node-labels.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// NodeLabelsSuite verifies updating node labels via machine config.\ntype NodeLabelsSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *NodeLabelsSuite) SuiteName() string {\n\treturn \"api.NodeLabelsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *NodeLabelsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *NodeLabelsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestUpdateControlPlane verifies node label updates on control plane nodes.\nfunc (suite *NodeLabelsSuite) TestUpdateControlPlane() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.testUpdate(node, true)\n}\n\n// TestUpdateWorker verifies node label updates on worker nodes.\nfunc (suite *NodeLabelsSuite) TestUpdateWorker() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tsuite.testUpdate(node, false)\n}\n\n// testUpdate cycles through a set of node label updates reverting the change in the end.\nfunc (suite *NodeLabelsSuite) testUpdate(node string, isControlplane bool) {\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"updating labels on node %q (%q)\", node, k8sNode.Name)\n\n\twatchCh := suite.SetupNodeInformer(suite.ctx, k8sNode.Name)\n\n\tconst stdLabelName = \"kubernetes.io/hostname\"\n\n\tstdLabelValue := k8sNode.Labels[stdLabelName]\n\n\t// set two new labels\n\tsuite.setNodeLabels(node, map[string]string{\n\t\t\"talos.dev/test1\": \"value1\",\n\t\t\"talos.dev/test2\": \"value2\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/test1\": \"value1\",\n\t\t\"talos.dev/test2\": \"value2\",\n\t}, isControlplane)\n\n\t// remove one label owned by Talos\n\tsuite.setNodeLabels(node, map[string]string{\n\t\t\"talos.dev/test1\": \"foo\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/test1\": \"foo\",\n\t\t\"talos.dev/test2\": \"\",\n\t}, isControlplane)\n\n\t// on control plane node, try to override a label not owned by Talos\n\tif isControlplane {\n\t\tsuite.setNodeLabels(node, map[string]string{\n\t\t\t\"talos.dev/test1\": \"foo2\",\n\t\t\tstdLabelName:      \"bar\",\n\t\t})\n\n\t\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\t\"talos.dev/test1\": \"foo2\",\n\t\t\tstdLabelName:      stdLabelValue,\n\t\t}, isControlplane)\n\t}\n\n\t// remove all Talos Labels\n\tsuite.setNodeLabels(node, nil)\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\t\"talos.dev/test1\": \"\",\n\t\t\"talos.dev/test2\": \"\",\n\t}, isControlplane)\n}\n\n// TestAllowScheduling verifies node taints are updated.\nfunc (suite *NodeLabelsSuite) TestAllowScheduling() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"updating taints on node %q (%q)\", node, k8sNode.Name)\n\n\twatchCh := suite.SetupNodeInformer(suite.ctx, k8sNode.Name)\n\n\tsuite.waitUntil(watchCh, nil, true)\n\n\tsuite.setAllowScheduling(node, true)\n\n\tsuite.waitUntil(watchCh, nil, false)\n\n\tsuite.setAllowScheduling(node, false)\n\n\tsuite.waitUntil(watchCh, nil, true)\n}\n\n//nolint:gocyclo\nfunc (suite *NodeLabelsSuite) waitUntil(watchCh <-chan *v1.Node, expectedLabels map[string]string, taintNoSchedule bool) {\nouter:\n\tfor {\n\t\tselect {\n\t\tcase k8sNode := <-watchCh:\n\t\t\tsuite.T().Logf(\"labels %#v, taints %#v\", k8sNode.Labels, k8sNode.Spec.Taints)\n\n\t\t\tfor k, v := range expectedLabels {\n\t\t\t\tif v == \"\" {\n\t\t\t\t\t_, ok := k8sNode.Labels[k]\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tsuite.T().Logf(\"label %q is still present\", k)\n\n\t\t\t\t\t\tcontinue outer\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif k8sNode.Labels[k] != v {\n\t\t\t\t\tsuite.T().Logf(\"label %q is %q but expected %q\", k, k8sNode.Labels[k], v)\n\n\t\t\t\t\tcontinue outer\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar found bool\n\n\t\t\tfor _, taint := range k8sNode.Spec.Taints {\n\t\t\t\tif taint.Key == constants.LabelNodeRoleControlPlane && taint.Effect == v1.TaintEffectNoSchedule {\n\t\t\t\t\tfound = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif taintNoSchedule && !found {\n\t\t\t\tsuite.T().Logf(\"taint %q is not present\", constants.LabelNodeRoleControlPlane)\n\n\t\t\t\tcontinue outer\n\t\t\t} else if !taintNoSchedule && found {\n\t\t\t\tsuite.T().Logf(\"taint %q is still present\", constants.LabelNodeRoleControlPlane)\n\n\t\t\t\tcontinue outer\n\t\t\t}\n\n\t\t\treturn\n\t\tcase <-suite.ctx.Done():\n\t\t\tsuite.T().Fatal(\"timeout\")\n\t\t}\n\t}\n}\n\nfunc (suite *NodeLabelsSuite) setNodeLabels(nodeIP string, nodeLabels map[string]string) { //nolint:dupl\n\tnodeCtx := client.WithNode(suite.ctx, nodeIP)\n\n\tnodeConfig, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tbytes := suite.PatchV1Alpha1Config(nodeConfig, func(nodeConfigRaw *v1alpha1.Config) {\n\t\tnodeConfigRaw.MachineConfig.MachineNodeLabels = nodeLabels\n\t})\n\n\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: bytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *NodeLabelsSuite) setAllowScheduling(nodeIP string, allowScheduling bool) {\n\tnodeCtx := client.WithNode(suite.ctx, nodeIP)\n\n\tnodeConfig, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tbytes := suite.PatchV1Alpha1Config(nodeConfig, func(nodeConfigRaw *v1alpha1.Config) {\n\t\tif allowScheduling {\n\t\t\tnodeConfigRaw.ClusterConfig.AllowSchedulingOnControlPlanes = new(true)\n\t\t} else {\n\t\t\tnodeConfigRaw.ClusterConfig.AllowSchedulingOnControlPlanes = nil\n\t\t}\n\t})\n\n\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: bytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\n\tsuite.Require().NoError(err)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(NodeLabelsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/node-taints.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\tv1 \"k8s.io/api/core/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// NodeTaintsSuite verifies updating node taints via machine config.\ntype NodeTaintsSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *NodeTaintsSuite) SuiteName() string {\n\treturn \"api.NodeTaintsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *NodeTaintsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *NodeTaintsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestUpdateControlPlane verifies node taints updates on control plane nodes.\nfunc (suite *NodeTaintsSuite) TestUpdateControlPlane() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.testUpdate(node)\n}\n\n// testUpdate cycles through a set of node taints updates reverting the change in the end.\nfunc (suite *NodeTaintsSuite) testUpdate(node string) {\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"updating taints on node %q (%q)\", node, k8sNode.Name)\n\n\twatchCh := suite.SetupNodeInformer(suite.ctx, k8sNode.Name)\n\n\t// set two new taints\n\tsuite.setNodeTaints(node, map[string]string{\n\t\t\"talos.dev/test1\": \"value1:NoSchedule\",\n\t\t\"talos.dev/test2\": \"NoSchedule\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\tconstants.LabelNodeRoleControlPlane: \"NoSchedule\",\n\t\t\"talos.dev/test1\":                   \"value1:NoSchedule\",\n\t\t\"talos.dev/test2\":                   \"NoSchedule\",\n\t})\n\n\t// remove one taint\n\tsuite.setNodeTaints(node, map[string]string{\n\t\t\"talos.dev/test1\": \"value1:NoSchedule\",\n\t})\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\tconstants.LabelNodeRoleControlPlane: \"NoSchedule\",\n\t\t\"talos.dev/test1\":                   \"value1:NoSchedule\",\n\t})\n\n\t// remove all taints\n\tsuite.setNodeTaints(node, nil)\n\n\tsuite.waitUntil(watchCh, map[string]string{\n\t\tconstants.LabelNodeRoleControlPlane: \"NoSchedule\",\n\t})\n}\n\nfunc (suite *NodeTaintsSuite) waitUntil(watchCh <-chan *v1.Node, expectedTaints map[string]string) {\nouter:\n\tfor {\n\t\tselect {\n\t\tcase k8sNode := <-watchCh:\n\t\t\tsuite.T().Logf(\"labels %#v, taints %#v\", k8sNode.Labels, k8sNode.Spec.Taints)\n\n\t\t\ttaints := xslices.ToMap(k8sNode.Spec.Taints, func(t v1.Taint) (string, string) {\n\t\t\t\tswitch {\n\t\t\t\tcase t.Value == \"\":\n\t\t\t\t\treturn t.Key, string(t.Effect)\n\t\t\t\tcase t.Effect == \"\":\n\t\t\t\t\treturn t.Key, t.Value\n\t\t\t\tdefault:\n\t\t\t\t\treturn t.Key, strings.Join([]string{t.Value, string(t.Effect)}, \":\")\n\t\t\t\t}\n\t\t\t})\n\n\t\t\texpectedTaintsKeys := maps.Keys(expectedTaints)\n\n\t\t\tslices.Sort(expectedTaintsKeys)\n\n\t\t\tfor _, key := range expectedTaintsKeys {\n\t\t\t\tactualValue, ok := taints[key]\n\t\t\t\tif !ok {\n\t\t\t\t\tsuite.T().Logf(\"taint %q is not present\", key)\n\n\t\t\t\t\tcontinue outer\n\t\t\t\t}\n\n\t\t\t\texpectedValue := expectedTaints[key]\n\n\t\t\t\tif expectedValue != actualValue {\n\t\t\t\t\tsuite.T().Logf(\"expected taint %q to be %q but was %q\", key, expectedValue, actualValue)\n\n\t\t\t\t\tcontinue outer\n\t\t\t\t}\n\n\t\t\t\tdelete(taints, key)\n\t\t\t}\n\n\t\t\tif len(taints) > 0 {\n\t\t\t\tkeys := maps.Keys(taints)\n\n\t\t\t\tslices.Sort(keys)\n\n\t\t\t\tsuite.T().Logf(\"taints %v are still present\", keys)\n\n\t\t\t\tcontinue outer\n\t\t\t}\n\n\t\t\treturn\n\t\tcase <-suite.ctx.Done():\n\t\t\tsuite.T().Fatal(\"timeout\")\n\t\t}\n\t}\n}\n\nfunc (suite *NodeTaintsSuite) setNodeTaints(nodeIP string, nodeTaints map[string]string) {\n\tnodeCtx := client.WithNode(suite.ctx, nodeIP)\n\n\tnodeConfig := must.Value(suite.ReadConfigFromNode(nodeCtx))(suite.T())\n\n\tbytes := suite.PatchV1Alpha1Config(nodeConfig, func(nodeConfigRaw *v1alpha1.Config) {\n\t\tnodeConfigRaw.MachineConfig.MachineNodeTaints = nodeTaints\n\t})\n\n\tmust.Value(suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\tData: bytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t}))(suite.T())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(NodeTaintsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/pci_driver_rebind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\thardwareconfigtype \"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// PCIDriverRebindSuite is a suite of tests for PCI rebind.\ntype PCIDriverRebindSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *PCIDriverRebindSuite) SuiteName() string {\n\treturn \"api.PCIDriverRebindSuite\"\n}\n\n// SetupTest sets up the test.\nfunc (suite *PCIDriverRebindSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping virtio test since provisioner is not qemu\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tstream, err := suite.Client.LS(nodeCtx, &machineapi.ListRequest{\n\t\tRoot: \"/sys/class/iommu\",\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tvar count int\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\tif info.GetRelativeName() == \".\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tcount++\n\n\t\treturn nil\n\t}))\n\n\tif count == 0 {\n\t\tsuite.T().Skip(\"skipping PCI rebind test since IOMMU is not enabled\")\n\t}\n}\n\n// TearDownTest tears down the test.\nfunc (suite *PCIDriverRebindSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestIOMMURebind tests PCI rebind.\nfunc (suite *PCIDriverRebindSuite) TestIOMMURebind() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\titems, err := suite.Client.COSI.List(nodeCtx, resource.NewMetadata(hardware.NamespaceName, hardware.PCIDeviceType, \"\", resource.VersionUndefined))\n\tsuite.Require().NoError(err)\n\n\tvar pciDeviceID string\n\n\tfor _, item := range items.Items {\n\t\tpci, ok := item.(*hardware.PCIDevice)\n\t\tsuite.Require().True(ok, \"expected PCI device, got %T\", item)\n\n\t\tif pci.TypedSpec().Product == \"82540EM Gigabit Ethernet Controller\" {\n\t\t\tpciDeviceID = pci.Metadata().ID()\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// validate that the driver is bound to e1000 initially\n\tsuite.validateDriver(nodeCtx, pciDeviceID, \"e1000\")\n\n\tcfgDocument := hardwareconfigtype.NewPCIDriverRebindConfigV1Alpha1()\n\tcfgDocument.MetaName = pciDeviceID\n\tcfgDocument.PCITargetDriver = \"vfio-pci\"\n\n\tv1alpha1CfgDocument := &v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineKernel: &v1alpha1.KernelConfig{\n\t\t\t\tKernelModules: []*v1alpha1.KernelModuleConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tModuleName: \"vfio-pci\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tsuite.PatchMachineConfig(nodeCtx, v1alpha1CfgDocument, cfgDocument)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, hardware.NewPCIDriverRebindStatus(pciDeviceID).Metadata(), state.WithEventTypes(state.Created, state.Updated))\n\tsuite.Require().NoError(err)\n\n\tdefer func() {\n\t\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\t\tsuite.PatchMachineConfig(nodeCtx, map[string]any{\n\t\t\t\"machine\": map[string]any{\n\t\t\t\t\"kernel\": map[string]any{\n\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}()\n\n\t// after applying the patch the device should be bound to vfio-pci\n\tsuite.validateDriver(nodeCtx, pciDeviceID, \"vfio-pci\")\n\n\tcfgDocument.PCITargetDriver = \"e1000\"\n\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, hardware.NewPCIDriverRebindStatus(pciDeviceID).Metadata(), state.WithEventTypes(state.Updated))\n\tsuite.Require().NoError(err)\n\n\t// verify that an update to the target driver takes effect\n\tsuite.validateDriver(nodeCtx, pciDeviceID, \"e1000\")\n\n\t// switch back to vfio-pci\n\tcfgDocument.PCITargetDriver = \"vfio-pci\"\n\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, hardware.NewPCIDriverRebindStatus(pciDeviceID).Metadata(), state.WithEventTypes(state.Updated))\n\tsuite.Require().NoError(err)\n\n\t// verify that the update has taken effect\n\tsuite.validateDriver(nodeCtx, pciDeviceID, \"vfio-pci\")\n\n\t// now remove the pci driver rebind config\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, hardware.NewPCIDriverRebindStatus(pciDeviceID).Metadata(), state.WithEventTypes(state.Destroyed))\n\tsuite.Require().NoError(err)\n\n\t// verify that the device is back to original host driver\n\tsuite.validateDriver(nodeCtx, pciDeviceID, \"e1000\")\n}\n\nfunc (suite *PCIDriverRebindSuite) validateDriver(nodeCtx context.Context, pciDeviceID, driver string) {\n\tstream, err := suite.Client.LS(nodeCtx, &machineapi.ListRequest{\n\t\tRoot:  fmt.Sprintf(\"/sys/bus/pci/devices/%s\", pciDeviceID),\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_SYMLINK},\n\t})\n\tsuite.Require().NoError(err)\n\n\tvar driverLink string\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\tif info.GetRelativeName() == \"driver\" {\n\t\t\tdriverLink = info.Link\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tsuite.Require().Equal(driver, filepath.Base(driverLink), \"expected driver %q, got %q\", driver, filepath.Base(driverLink))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &PCIDriverRebindSuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/platform.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.yaml.in/yaml/v4\"\n\n\tv1alpha1runtime \"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// PlatformSuite ...\ntype PlatformSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *PlatformSuite) SuiteName() string {\n\treturn \"api.PlatformSuite\"\n}\n\n// SetupTest ...\nfunc (suite *PlatformSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *PlatformSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestPlatformMetadata verifies platform metadata.\nfunc (suite *PlatformSuite) TestPlatformMetadata() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, runtime.PlatformMetadataID, func(md *runtime.PlatformMetadata, asrt *assert.Assertions) {\n\t\tmarshaled, err := resource.MarshalYAML(md)\n\t\tsuite.Require().NoError(err)\n\n\t\tyml, err := yaml.Marshal(marshaled)\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.T().Logf(\"platform metadata:\\n%s\", string(yml))\n\n\t\tif md.TypedSpec().Platform == \"aws\" || md.TypedSpec().Platform == \"gcp\" {\n\t\t\tasrt.NotEmpty(md.TypedSpec().Tags)\n\t\t}\n\t})\n}\n\n// TestMetalPlatformMetadata verifies platform metadata for metal platform.\nfunc (suite *PlatformSuite) TestMetalPlatformMetadata() {\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping platform metal test since provisioner is not qemu\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"verifying metal platform network config on node %s\", node)\n\n\tconst linkName = \"dummy-platform\"\n\n\tplatformNetworkConfig := v1alpha1runtime.PlatformNetworkConfig{\n\t\tLinks: []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName:    linkName,\n\t\t\t\tLogical: true,\n\t\t\t\tUp:      false,\n\t\t\t\tMTU:     1500,\n\t\t\t\tType:    nethelpers.LinkEther,\n\t\t\t\tKind:    \"dummy\",\n\t\t\t},\n\t\t},\n\t}\n\n\tplatformNetworkConfigMarshaled, err := yaml.Marshal(platformNetworkConfig)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.Client.MetaWrite(ctx, meta.MetalNetworkPlatformConfig, platformNetworkConfigMarshaled))\n\n\t// link should appear on the node\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, linkName, func(*network.LinkStatus, *assert.Assertions) {})\n\n\tsuite.Require().NoError(suite.Client.MetaDelete(ctx, meta.MetalNetworkPlatformConfig))\n\n\t// address should be removed\n\trtestutils.AssertNoResource[*network.LinkStatus](ctx, suite.T(), suite.Client.COSI, linkName)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(PlatformSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/probe-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\tnetworkres \"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst (\n\tgoogleDNS = \"8.8.8.8:53\"\n\tcfDNS     = \"1.1.1.1:53\"\n)\n\n// ProbeConfigSuite tests ProbeConfig functionality via the API.\ntype ProbeConfigSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *ProbeConfigSuite) SuiteName() string {\n\treturn \"api.ProbeConfigSuite\"\n}\n\n// SetupTest initializes test context.\nfunc (suite *ProbeConfigSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)\n}\n\n// TearDownTest cleans up test context.\nfunc (suite *ProbeConfigSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestProbeConfig tests that ProbeConfig documents create ProbeSpec resources.\nfunc (suite *ProbeConfigSuite) TestProbeConfig() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing ProbeConfig on node %q\", node)\n\n\t// Create a probe that checks if we can reach a public DNS server\n\tprobeConfig := network.NewTCPProbeConfigV1Alpha1(\"test-probe\")\n\tprobeConfig.ProbeInterval = 2 * time.Second\n\tprobeConfig.ProbeFailureThreshold = 3\n\tprobeConfig.TCPEndpoint = googleDNS\n\tprobeConfig.TCPTimeout = 5 * time.Second\n\n\tsuite.PatchMachineConfig(nodeCtx, probeConfig)\n\n\t// Wait for ProbeSpec resource to be created\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS,\n\t\tfunc(spec *networkres.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(2*time.Second, spec.TypedSpec().Interval)\n\t\t\tasrt.Equal(3, spec.TypedSpec().FailureThreshold)\n\t\t\tasrt.Equal(googleDNS, spec.TypedSpec().TCP.Endpoint)\n\t\t\tasrt.Equal(5*time.Second, spec.TypedSpec().TCP.Timeout)\n\t\t\tasrt.Equal(networkres.ConfigMachineConfiguration, spec.TypedSpec().ConfigLayer)\n\t\t},\n\t)\n\n\t// Update the probe config\n\tprobeConfig.ProbeFailureThreshold = 5\n\tsuite.PatchMachineConfig(nodeCtx, probeConfig)\n\n\t// Wait for ProbeSpec resource to be updated\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS,\n\t\tfunc(spec *networkres.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(5, spec.TypedSpec().FailureThreshold)\n\t\t},\n\t)\n\n\t// Remove the ProbeConfig\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, network.TCPProbeKind)\n\n\t// Wait for ProbeSpec resource to be removed\n\trtestutils.AssertNoResource[*networkres.ProbeSpec](nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS)\n}\n\n// TestMultipleProbes tests that multiple ProbeConfig documents create multiple ProbeSpec resources.\nfunc (suite *ProbeConfigSuite) TestMultipleProbes() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing multiple ProbeConfigs on node %q\", node)\n\n\t// Create first probe\n\tprobeConfig1 := network.NewTCPProbeConfigV1Alpha1(\"proxy-check\")\n\n\tprobeConfig1.ProbeInterval = 1 * time.Second\n\tprobeConfig1.ProbeFailureThreshold = 3\n\tprobeConfig1.TCPEndpoint = cfDNS\n\tprobeConfig1.TCPTimeout = 10 * time.Second\n\n\t// Create second probe\n\tprobeConfig2 := network.NewTCPProbeConfigV1Alpha1(\"dns-check\")\n\tprobeConfig2.ProbeInterval = 5 * time.Second\n\tprobeConfig2.ProbeFailureThreshold = 2\n\tprobeConfig2.TCPEndpoint = googleDNS\n\tprobeConfig2.TCPTimeout = 5 * time.Second\n\n\tsuite.PatchMachineConfig(nodeCtx, probeConfig1, probeConfig2)\n\n\t// Verify both probes are created\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]string{\"tcp:\" + cfDNS, \"tcp:\" + googleDNS},\n\t\tfunc(spec *networkres.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tswitch spec.TypedSpec().TCP.Endpoint {\n\t\t\tcase cfDNS:\n\t\t\t\tasrt.Equal(1*time.Second, spec.TypedSpec().Interval)\n\t\t\t\tasrt.Equal(3, spec.TypedSpec().FailureThreshold)\n\t\t\tcase googleDNS:\n\t\t\t\tasrt.Equal(5*time.Second, spec.TypedSpec().Interval)\n\t\t\t\tasrt.Equal(2, spec.TypedSpec().FailureThreshold)\n\t\t\t}\n\n\t\t\tasrt.Equal(networkres.ConfigMachineConfiguration, spec.TypedSpec().ConfigLayer)\n\t\t},\n\t)\n\n\t// Remove all ProbeConfigs\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, network.TCPProbeKind)\n\n\t// Verify both probes are removed\n\trtestutils.AssertNoResource[*networkres.ProbeSpec](nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+cfDNS)\n\trtestutils.AssertNoResource[*networkres.ProbeSpec](nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS)\n}\n\n// TestProbeStatus tests that ProbeSpec resources create ProbeStatus resources.\nfunc (suite *ProbeConfigSuite) TestProbeStatus() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"testing ProbeStatus on node %q\", node)\n\n\t// Create a probe with a very short interval\n\tprobeConfig := network.NewTCPProbeConfigV1Alpha1(\"dns-status-check\")\n\tprobeConfig.ProbeInterval = 1 * time.Second\n\tprobeConfig.ProbeFailureThreshold = 1\n\tprobeConfig.TCPEndpoint = googleDNS\n\tprobeConfig.TCPTimeout = 3 * time.Second\n\n\tsuite.PatchMachineConfig(nodeCtx, probeConfig)\n\n\t// Wait for ProbeSpec to be created\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS,\n\t\tfunc(spec *networkres.ProbeSpec, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(googleDNS, spec.TypedSpec().TCP.Endpoint)\n\t\t},\n\t)\n\n\t// Give the probe controller time to run at least one probe\n\ttime.Sleep(3 * time.Second)\n\n\t// Verify ProbeStatus is created and has success/failure data\n\tprobeStatuses, err := safe.StateListAll[*networkres.ProbeStatus](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tvar found bool\n\n\tfor status := range probeStatuses.All() {\n\t\tif status.Metadata().ID() == \"tcp:\"+googleDNS {\n\t\t\tfound = true\n\n\t\t\tsuite.T().Logf(\"ProbeStatus: success=%v, lastError=%s\", status.TypedSpec().Success, status.TypedSpec().LastError)\n\t\t\t// The status should have been updated at least once (either success or failure)\n\t\t\tsuite.Assert().True(status.TypedSpec().Success || status.TypedSpec().LastError != \"\")\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Assert().True(found, \"expected to find ProbeStatus for tcp:\"+googleDNS)\n\n\t// Clean up\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, network.TCPProbeKind)\n\trtestutils.AssertNoResource[*networkres.ProbeSpec](nodeCtx, suite.T(), suite.Client.COSI, \"tcp:\"+googleDNS)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &ProbeConfigSuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/process.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ProcessSuite ...\ntype ProcessSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ProcessSuite) SuiteName() string {\n\treturn \"api.ProcessSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ProcessSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\t// TODO: should we test caps and cgroups in Docker?\n\t\tsuite.T().Skip(\"skipping process test since provisioner is not qemu\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *ProcessSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\nfunc (suite *ProcessSuite) readProcfs(nodeCtx context.Context, pid int32, property string) string {\n\tr, err := suite.Client.Read(nodeCtx, filepath.Join(\"/proc\", strconv.Itoa(int(pid)), property))\n\tsuite.Require().NoError(err)\n\n\tvalue, err := io.ReadAll(r)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(r.Close())\n\n\treturn string(bytes.TrimSpace(value))\n}\n\n// TestProcessCapabilities reads capabilities of processes from procfs\n// and validates system services get necessary capabilities dropped.\nfunc (suite *ProcessSuite) TestProcessCapabilities() {\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\tr, err := suite.Client.Processes(nodeCtx)\n\t\tsuite.Require().NoError(err)\n\n\t\tfound := 0\n\n\t\tfor _, msg := range r.Messages {\n\t\t\tprocs := msg.Processes\n\n\t\t\tfor _, p := range procs {\n\t\t\t\tswitch p.Command {\n\t\t\t\tcase \"systemd-udevd\":\n\t\t\t\t\tfound++\n\n\t\t\t\t\t// All but cap_sys_boot\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"CapPrm:\\t000001ffffbfffff\\nCapEff:\\t000001ffffbfffff\\nCapBnd:\\t000001ffffbfffff\",\n\t\t\t\t\t)\n\n\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"cgroup\"),\n\t\t\t\t\t\t\"0::/system/udevd\",\n\t\t\t\t\t)\n\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"environ\"),\n\t\t\t\t\t\tconstants.EnvXDGRuntimeDir,\n\t\t\t\t\t)\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"Uid:\\t0\",\n\t\t\t\t\t)\n\t\t\t\tcase \"dashboard\":\n\t\t\t\t\tfound++\n\n\t\t\t\t\t// None\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"CapPrm:\\t0000000000000000\\nCapEff:\\t0000000000000000\\nCapBnd:\\t0000000000000000\",\n\t\t\t\t\t)\n\n\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"cgroup\"),\n\t\t\t\t\t\t\"0::/system/dashboard\",\n\t\t\t\t\t)\n\n\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"oom_score_adj\"),\n\t\t\t\t\t\t\"-400\",\n\t\t\t\t\t)\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"environ\"),\n\t\t\t\t\t\t\"TERM=linux\",\n\t\t\t\t\t)\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"Uid:\\t50\",\n\t\t\t\t\t)\n\t\t\t\tcase \"containerd\":\n\t\t\t\t\tfound++\n\n\t\t\t\t\t// All but cap_sys_boot, cap_sys_module\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"CapPrm:\\t000001ffffbeffff\\nCapEff:\\t000001ffffbeffff\\nCapBnd:\\t000001ffffbeffff\",\n\t\t\t\t\t)\n\n\t\t\t\t\tif strings.Contains(p.Args, \"/system/run/containerd\") {\n\t\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"cgroup\"),\n\t\t\t\t\t\t\t\"0::/system/runtime\",\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"oom_score_adj\"),\n\t\t\t\t\t\t\t\"-999\",\n\t\t\t\t\t\t)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"cgroup\"),\n\t\t\t\t\t\t\t\"0::/podruntime/runtime\",\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tsuite.Require().Equal(\n\t\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"oom_score_adj\"),\n\t\t\t\t\t\t\t\"-500\",\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"environ\"),\n\t\t\t\t\t\tconstants.EnvXDGRuntimeDir,\n\t\t\t\t\t)\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.readProcfs(nodeCtx, p.Pid, \"status\"),\n\t\t\t\t\t\t\"Uid:\\t0\",\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsuite.Require().Equal(4, found, \"Not all processes found\")\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ProcessSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/reboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// RebootSuite ...\ntype RebootSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *RebootSuite) SuiteName() string {\n\treturn \"api.RebootSuite\"\n}\n\n// SetupTest ...\nfunc (suite *RebootSuite) SetupTest() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\t// make sure we abort at some point in time, but give enough room for reboots\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *RebootSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestRebootNodeByNode reboots cluster node by node, waiting for health between reboots.\nfunc (suite *RebootSuite) TestRebootNodeByNode() {\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboots\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\tfor _, node := range nodes {\n\t\tsuite.T().Log(\"rebooting node\", node)\n\n\t\tsuite.AssertRebooted(\n\t\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t\t}, 10*time.Minute,\n\t\t\tsuite.CleanupFailedPods,\n\t\t)\n\t}\n}\n\n// TestForcedReboot force-reboots cluster node by node,\n// ensuring that the 'cleanup' phase/'stopAllPods' task doesn't run.\nfunc (suite *RebootSuite) TestForcedReboot() { //nolint:gocyclo\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboots\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\tfor _, node := range nodes {\n\t\tsuite.T().Log(\"force rebooting node\", node)\n\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t\tvar (\n\t\t\tsawStopAllPods  atomic.Bool\n\t\t\tsawCleanupPhase atomic.Bool\n\t\t)\n\n\t\t// watch events so we can verify graceful teardown did not happen\n\t\twatchCtx, watchCancel := context.WithCancel(nodeCtx)\n\t\teventsCh := make(chan client.EventResult)\n\t\tsuite.Require().NoError(suite.Client.EventsWatchV2(watchCtx, eventsCh))\n\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-watchCtx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase ev := <-eventsCh:\n\t\t\t\t\tif ev.Error != nil {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch msg := ev.Event.Payload.(type) {\n\t\t\t\t\tcase *machineapi.TaskEvent:\n\t\t\t\t\t\tif msg.GetTask() == \"stopAllPods\" {\n\t\t\t\t\t\t\tsawStopAllPods.Store(true)\n\t\t\t\t\t\t}\n\t\t\t\t\tcase *machineapi.PhaseEvent:\n\t\t\t\t\t\tif msg.GetPhase() == \"cleanup\" {\n\t\t\t\t\t\t\tsawCleanupPhase.Store(true)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\n\t\tsuite.AssertRebooted(\n\t\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx, client.WithForce))\n\t\t\t}, 10*time.Minute,\n\t\t\tsuite.CleanupFailedPods,\n\t\t)\n\n\t\twatchCancel()\n\n\t\tsuite.Require().Falsef(sawCleanupPhase.Load(), \"cleanup phase must not run during forced reboot\")\n\t\tsuite.Require().Falsef(sawStopAllPods.Load(), \"stopAllPods task must not run during forced reboot\")\n\t}\n\n\tsuite.WaitForBootDone(suite.ctx)\n}\n\n// TestRebootMultiple reboots a node, issues consequent reboots\n// reboot should cancel boot sequence, and cancel another reboot.\nfunc (suite *RebootSuite) TestRebootMultiple() {\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboots\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNodes(suite.ctx, node)\n\n\tbootID := suite.ReadBootIDWithRetry(nodeCtx, time.Minute*5)\n\n\t// Issue reboot.\n\tsuite.Require().NoError(base.IgnoreGRPCUnavailable(\n\t\tsuite.Client.Reboot(nodeCtx),\n\t))\n\n\t// Issue reboot once again and wait for node to get a new boot id.\n\tsuite.Require().NoError(base.IgnoreGRPCUnavailable(\n\t\tsuite.Client.Reboot(nodeCtx),\n\t))\n\n\tsuite.AssertBootIDChanged(nodeCtx, bootID, node, time.Minute*7)\n\n\tbootID = suite.ReadBootIDWithRetry(nodeCtx, time.Minute*5)\n\n\tsuite.Require().NoError(retry.Constant(time.Second * 5).Retry(func() error {\n\t\t// Issue reboot while the node is still booting.\n\t\terr := suite.Client.Reboot(nodeCtx)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\t// Reboot again and wait for cluster to become healthy.\n\t\tsuite.Require().NoError(base.IgnoreGRPCUnavailable(\n\t\t\tsuite.Client.Reboot(nodeCtx),\n\t\t))\n\n\t\treturn nil\n\t}))\n\n\tsuite.AssertBootIDChanged(nodeCtx, bootID, node, time.Minute*7)\n\tsuite.WaitForBootDone(suite.ctx)\n}\n\n// TestRebootAllNodes reboots all cluster nodes at the same time.\n//\n//nolint:gocyclo\nfunc (suite *RebootSuite) TestRebootAllNodes() {\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboots\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\terrCh := make(chan error, len(nodes))\n\n\tvar initialBootID sync.Map\n\n\tfor _, node := range nodes {\n\t\tgo func(node string) {\n\t\t\terrCh <- func() error {\n\t\t\t\tnodeCtx := client.WithNodes(suite.ctx, node)\n\n\t\t\t\t// read boot_id before reboot\n\t\t\t\tbootIDBefore, err := suite.ReadBootID(nodeCtx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error reading initial bootID (node %q): %w\", node, err)\n\t\t\t\t}\n\n\t\t\t\tinitialBootID.Store(node, bootIDBefore)\n\n\t\t\t\treturn nil\n\t\t\t}()\n\t\t}(node)\n\t}\n\n\tfor range nodes {\n\t\tsuite.Require().NoError(<-errCh)\n\t}\n\n\tallNodesCtx := client.WithNodes(suite.ctx, nodes...)\n\n\terr := base.IgnoreGRPCUnavailable(suite.Client.Reboot(allNodesCtx))\n\n\tsuite.Require().NoError(err)\n\n\tfor _, node := range nodes {\n\t\tgo func(node string) {\n\t\t\terrCh <- func() error {\n\t\t\t\tbootIDBeforeInterface, ok := initialBootID.Load(node)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"bootID record not found for %q\", node)\n\t\t\t\t}\n\n\t\t\t\tbootIDBefore := bootIDBeforeInterface.(string) //nolint:forcetypeassert\n\n\t\t\t\tnodeCtx := client.WithNodes(suite.ctx, node)\n\n\t\t\t\treturn retry.Constant(10 * time.Minute).Retry(\n\t\t\t\t\tfunc() error {\n\t\t\t\t\t\trequestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, 5*time.Second)\n\t\t\t\t\t\tdefer requestCtxCancel()\n\n\t\t\t\t\t\tbootIDAfter, err := suite.ReadBootID(requestCtx)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t// API might be unresponsive during reboot\n\t\t\t\t\t\t\treturn retry.ExpectedErrorf(\"error reading bootID for node %q: %w\", node, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif bootIDAfter == bootIDBefore {\n\t\t\t\t\t\t\t// bootID should be different after reboot\n\t\t\t\t\t\t\treturn retry.ExpectedErrorf(\n\t\t\t\t\t\t\t\t\"bootID didn't change for node %q: before %s, after %s\",\n\t\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\t\tbootIDBefore,\n\t\t\t\t\t\t\t\tbootIDAfter,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t}()\n\t\t}(node)\n\t}\n\n\tfor range nodes {\n\t\tsuite.Assert().NoError(<-errCh)\n\t}\n\n\tif suite.Cluster != nil {\n\t\t// without cluster state we can't do deep checks, but basic reboot test still works\n\t\t// NB: using `ctx` here to have client talking to init node by default\n\t\tsuite.AssertClusterHealthy(suite.ctx)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(RebootSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/reset.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// ResetSuite ...\ntype ResetSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ResetSuite) SuiteName() string {\n\treturn \"api.ResetSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ResetSuite) SetupTest() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot (and reset)\")\n\t}\n\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reset test is not reliable (can't wait for cluster readiness in between resets)\")\n\t}\n\n\t// make sure we abort at some point in time, but give enough room for Resets\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ResetSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestResetNodeByNode Resets cluster node by node, waiting for health between Resets.\nfunc (suite *ResetSuite) TestResetNodeByNode() {\n\tif suite.Capabilities().SecureBooted {\n\t\t// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args\n\t\tsuite.T().Skip(\"skipping as talos is explicitly trusted booted\")\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\tslices.Sort(nodes)\n\n\tfor _, node := range nodes {\n\t\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\t\tReboot:   true,\n\t\t\tGraceful: true,\n\t\t}, true)\n\t}\n}\n\nfunc (suite *ResetSuite) testResetNoGraceful(nodeType machine.Type) {\n\tif suite.Capabilities().SecureBooted {\n\t\t// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args\n\t\tsuite.T().Skip(\"skipping as talos is explicitly trusted booted\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(nodeType)\n\n\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\tReboot:   true,\n\t\tGraceful: false,\n\t}, true)\n}\n\n// TestResetNoGracefulWorker resets a worker in !graceful mode.\nfunc (suite *ResetSuite) TestResetNoGracefulWorker() {\n\tsuite.testResetNoGraceful(machine.TypeWorker)\n}\n\n// TestResetNoGracefulControlplane resets a control plane node in !graceful mode.\n//\n// As the node doesn't leave etcd, it relies on Talos to fix the problem on rejoin.\nfunc (suite *ResetSuite) TestResetNoGracefulControlplane() {\n\tsuite.testResetNoGraceful(machine.TypeControlPlane)\n}\n\n// TestResetWithSpecEphemeral resets only ephemeral partition on the node.\nfunc (suite *ResetSuite) TestResetWithSpecEphemeral() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\tReboot:   true,\n\t\tGraceful: true,\n\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t{\n\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\tWipe:  true,\n\t\t\t},\n\t\t},\n\t}, true)\n}\n\n// TestResetWithSpecStateAndUserDisks resets state partition and user disks on the node.\n//\n// As ephemeral partition is not reset, so kubelet cert shouldn't change.\n//\n//nolint:gocyclo\nfunc (suite *ResetSuite) TestResetWithSpecStateAndUserDisks() {\n\tif suite.Capabilities().SecureBooted {\n\t\t// this is because in secure boot mode, the machine config is only applied and cannot be passed as kernel args\n\t\tsuite.T().Skip(\"skipping as talos is explicitly trusted booted\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tsuite.T().Logf(\"resetting STATE + user disk on node %s\", node)\n\n\tconfig, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\t// check if EPHEMERAL is encrypted locked to STATE\n\tvar lockedToState bool\n\n\tif volume, ok := config.Volumes().ByName(constants.EphemeralPartitionLabel); ok && volume.Encryption() != nil {\n\t\tfor _, key := range volume.Encryption().Keys() {\n\t\t\tif key.LockToSTATE() {\n\t\t\t\tlockedToState = true\n\t\t\t}\n\t\t}\n\t}\n\n\tdisks, err := suite.Client.Disks(nodeCtx)\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotEmpty(disks.Messages)\n\n\tuserDisksToWipe := xslices.Map(\n\t\txslices.Filter(disks.Messages[0].Disks, func(disk *storage.Disk) bool {\n\t\t\tswitch {\n\t\t\tcase disk.SystemDisk:\n\t\t\t\treturn false\n\t\t\tcase disk.Type == storage.Disk_UNKNOWN, disk.Type == storage.Disk_CD, disk.Type == storage.Disk_SD, disk.Type == storage.Disk_NVME:\n\t\t\t\treturn false\n\t\t\tcase disk.Readonly:\n\t\t\t\treturn false\n\t\t\tcase disk.BusPath == \"/virtual\":\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn true\n\t\t}),\n\t\tfunc(disk *storage.Disk) string {\n\t\t\treturn disk.DeviceName\n\t\t},\n\t)\n\n\tif !lockedToState {\n\t\t// if not locked to STATE, wipe will be successful\n\t\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\t\tReboot:   true,\n\t\t\tGraceful: true,\n\t\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t\t{\n\t\t\t\t\tLabel: constants.StatePartitionLabel,\n\t\t\t\t\tWipe:  true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tUserDisksToWipe: userDisksToWipe,\n\t\t}, true)\n\n\t\treturn\n\t}\n\n\tsuite.T().Logf(\"verifying that EPHEMERAL partition would fail to unlock after reset, as it is locked to STATE\")\n\n\t// if the EPHEMERAL partition is locked to STATE, it will fail to unlock after reset, so let's verify it\n\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\tReboot:   true,\n\t\tGraceful: true,\n\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t{\n\t\t\t\tLabel: constants.StatePartitionLabel,\n\t\t\t\tWipe:  true,\n\t\t\t},\n\t\t},\n\t\tUserDisksToWipe: userDisksToWipe,\n\t}, false)\n\n\t// wait for EPHEMERAL failure\n\trtestutils.AssertResources(nodeCtx, suite.T(), suite.Client.COSI,\n\t\t[]string{constants.EphemeralPartitionLabel},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(block.VolumePhaseFailed, vs.TypedSpec().Phase)\n\t\t\tasrt.Contains(vs.TypedSpec().ErrorMessage, \"encryption key rejected\")\n\t\t},\n\t)\n\n\t// now reset EPHEMERAL\n\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\tReboot:   true,\n\t\tGraceful: false,\n\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t{\n\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\tWipe:  true,\n\t\t\t},\n\t\t},\n\t}, true)\n}\n\n// TestResetDuringBoot resets the node while it is in boot sequence.\nfunc (suite *ResetSuite) TestResetDuringBoot() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNodes(suite.ctx, node)\n\n\tsuite.T().Log(\"rebooting node\", node)\n\n\tbootIDBefore, err := suite.ReadBootID(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(suite.Client.Reboot(nodeCtx))\n\n\tsuite.AssertBootIDChanged(nodeCtx, bootIDBefore, node, 3*time.Minute)\n\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\t// make sure EPHEMERAL is ready\n\trtestutils.AssertResources(client.WithNode(suite.ctx, node), suite.T(), suite.Client.COSI,\n\t\t[]string{constants.EphemeralPartitionLabel},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(block.VolumePhaseReady, vs.TypedSpec().Phase)\n\t\t},\n\t)\n\n\tsuite.ResetNode(suite.ctx, node, &machineapi.ResetRequest{\n\t\tReboot:   true,\n\t\tGraceful: true,\n\t\tSystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{\n\t\t\t{\n\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\tWipe:  true,\n\t\t\t},\n\t\t},\n\t}, true)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ResetSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/resources.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// ResourcesSuite ...\ntype ResourcesSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ResourcesSuite) SuiteName() string {\n\treturn \"api.ResourcesSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ResourcesSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *ResourcesSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestListResources tries to fetch every resource in the system.\nfunc (suite *ResourcesSuite) TestListResources() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tctx := client.WithNode(suite.ctx, node)\n\n\tnsList, err := safe.StateListAll[*meta.Namespace](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tnamespaces := safe.ToSlice(nsList, func(ns *meta.Namespace) string {\n\t\treturn ns.Metadata().ID()\n\t})\n\n\trdList, err := safe.StateListAll[*meta.ResourceDefinition](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tresourceTypes := safe.ToSlice(rdList, func(rd *meta.ResourceDefinition) string {\n\t\treturn rd.TypedSpec().Type\n\t})\n\n\teg, egCtx := errgroup.WithContext(ctx)\n\n\tfor _, resourceType := range resourceTypes {\n\t\teg.Go(func() error {\n\t\t\tfor _, namespace := range namespaces {\n\t\t\t\t_, err := suite.Client.COSI.List(egCtx, resource.NewMetadata(namespace, resourceType, \"\", resource.VersionUndefined))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to list resources of type %q in namespace %q: %w\", resourceType, namespace, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tsuite.Assert().NoError(eg.Wait())\n}\n\n// TestForbiddenOperations verifies that write operations are forbidden.\nfunc (suite *ResourcesSuite) TestForbiddenOperations() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\terr := suite.Client.COSI.Create(ctx, v1alpha1.NewService(\"foo\"))\n\tsuite.Require().Error(err)\n\tsuite.Assert().True(state.IsConflictError(err)) // this is how COSI wraps the error\n\n\terr = suite.Client.COSI.Destroy(ctx, v1alpha1.NewService(\"kubelet\").Metadata())\n\tsuite.Require().Error(err)\n\tsuite.Assert().True(state.IsConflictError(err)) // this is how COSI wraps the error\n\n\terr = suite.Client.COSI.Update(ctx, v1alpha1.NewService(\"kubelet\"))\n\tsuite.Require().Error(err)\n\tsuite.Assert().True(state.IsConflictError(err)) // this is how COSI wraps the error\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ResourcesSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/rotate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tsecretsres \"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/talos\"\n)\n\n// RotateCASuite verifies rotation of Talos and Kubernetes CAs.\ntype RotateCASuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *RotateCASuite) SuiteName() string {\n\treturn \"api.RotateCASuite\"\n}\n\n// SetupTest ...\nfunc (suite *RotateCASuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *RotateCASuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestTalos updates Talos CA in the cluster.\nfunc (suite *RotateCASuite) TestTalos() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"cluster information is not available\")\n\t}\n\n\tsuite.T().Logf(\"capturing current Talos CA\")\n\n\tnodeInternalIP := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\t// save osRoot\n\tosRoot, err := safe.StateGetByID[*secretsres.OSRoot](client.WithNode(suite.ctx, nodeInternalIP), suite.Client.COSI, secretsres.OSRootID)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"rotating current CA -> new CA\")\n\n\tnewBundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\tsuite.Require().NoError(err)\n\n\toptions := talos.Options{\n\t\tCurrentClient: suite.Client,\n\t\tClusterInfo:   access.NewAdapter(suite.Cluster),\n\n\t\tContextName: suite.Talosconfig.Context,\n\t\tEndpoints:   suite.Client.GetEndpoints(),\n\n\t\tNewTalosCA: newBundle.Certs.OS,\n\n\t\tEncoderOption: encoder.WithComments(encoder.CommentsAll),\n\n\t\tPrintf: suite.T().Logf,\n\t}\n\n\tnewTalosconfig, err := talos.Rotate(suite.ctx, options)\n\tsuite.Require().NoError(err)\n\n\tnewClient, err := client.New(suite.ctx, client.WithConfig(newTalosconfig))\n\tsuite.Require().NoError(err)\n\n\tif !testing.Short() {\n\t\tsuite.restartAPIServices(newClient)\n\t}\n\n\tsuite.T().Logf(\"rotating back new CA -> old CA\")\n\n\toptions = talos.Options{\n\t\tCurrentClient: newClient,\n\t\tClusterInfo:   access.NewAdapter(suite.Cluster),\n\n\t\tContextName: suite.Talosconfig.Context,\n\t\tEndpoints:   suite.Client.GetEndpoints(),\n\n\t\tNewTalosCA: osRoot.TypedSpec().IssuingCA,\n\n\t\tEncoderOption: encoder.WithComments(encoder.CommentsAll),\n\n\t\tPrintf: suite.T().Logf,\n\t}\n\n\t_, err = talos.Rotate(suite.ctx, options)\n\tsuite.Require().NoError(err)\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n\n\tsuite.ClearConnectionRefused(suite.ctx, suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker)...)\n}\n\n// TestKubernetes updates Kubernetes CA in the cluster.\nfunc (suite *RotateCASuite) TestKubernetes() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"cluster information is not available\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tsuite.T().Logf(\"capturing current Kubernetes CA\")\n\n\tnodeInternalIP := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\t// save k8sRoot\n\tk8sRoot, err := safe.StateGetByID[*secretsres.KubernetesRoot](client.WithNode(suite.ctx, nodeInternalIP), suite.Client.COSI, secretsres.KubernetesRootID)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"rotating current CA -> new CA\")\n\n\tnewBundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\tsuite.Require().NoError(err)\n\n\toptions := kubernetes.Options{\n\t\tTalosClient: suite.Client,\n\t\tClusterInfo: access.NewAdapter(suite.Cluster),\n\n\t\tNewKubernetesCA: newBundle.Certs.K8s,\n\n\t\tEncoderOption: encoder.WithComments(encoder.CommentsAll),\n\n\t\tPrintf: suite.T().Logf,\n\t}\n\n\tsuite.Require().NoError(kubernetes.Rotate(suite.ctx, options))\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n\n\tsuite.T().Logf(\"rotating back new CA -> old CA\")\n\n\toptions = kubernetes.Options{\n\t\tTalosClient: suite.Client,\n\t\tClusterInfo: access.NewAdapter(suite.Cluster),\n\n\t\tNewKubernetesCA: k8sRoot.TypedSpec().IssuingCA,\n\n\t\tEncoderOption: encoder.WithComments(encoder.CommentsAll),\n\n\t\tPrintf: suite.T().Logf,\n\t}\n\n\tsuite.Require().NoError(kubernetes.Rotate(suite.ctx, options))\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\nfunc (suite *RotateCASuite) restartAPIServices(c *client.Client) {\n\tsuite.T().Logf(\"restarting API services\")\n\n\tvar oldClient *client.Client\n\n\toldClient, suite.Client = suite.Client, c\n\n\tdefer func() {\n\t\tsuite.Client = oldClient\n\t}()\n\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\tsuite.T().Logf(\"restarting API services on %s\", node)\n\n\t\terr := c.Restart(client.WithNode(suite.ctx, node), constants.SystemContainerdNamespace, common.ContainerDriver_CONTAINERD, \"trustd\")\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\t\terr = c.Restart(client.WithNode(suite.ctx, node), constants.SystemContainerdNamespace, common.ContainerDriver_CONTAINERD, \"apid\")\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\t}\n\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker) {\n\t\tsuite.T().Logf(\"restarting API services on %s\", node)\n\n\t\terr := c.Restart(client.WithNode(suite.ctx, node), constants.SystemContainerdNamespace, common.ContainerDriver_CONTAINERD, \"apid\")\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\t}\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(RotateCASuite))\n}\n"
  },
  {
    "path": "internal/integration/api/sbom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// SBOMSuite ...\ntype SBOMSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *SBOMSuite) SuiteName() string {\n\treturn \"api.SBOMSuite\"\n}\n\n// SetupTest ...\nfunc (suite *SBOMSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n}\n\n// TearDownTest ...\nfunc (suite *SBOMSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestCommon verifies that common SBOM items are available.\nfunc (suite *SBOMSuite) TestCommon() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{\n\t\t\t// list of common SBOM items which should be present always\n\t\t\t\"Talos\",\n\t\t\t\"github.com/siderolabs/go-kubernetes\",\n\t\t},\n\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\tasrt.NotEmpty(item.TypedSpec().Name, \"SBOM item name should not be empty\")\n\t\t\tasrt.NotEmpty(item.TypedSpec().Version, \"SBOM item version should not be empty\")\n\t\t},\n\t)\n\n\t// Talos SBOM item should have a matching version.\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\"Talos\",\n\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(version.Name, item.TypedSpec().Name, \"SBOM item name should match Talos version name\")\n\t\t\t// asrt.Equal(version.Tag, item.TypedSpec().Version, \"SBOM item version should match Talos version\")\n\t\t},\n\t)\n\n\t// Assert on containerd/runc versions.\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\"containerd\",\n\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"v\"+constants.DefaultContainerdVersion, item.TypedSpec().Version)\n\t\t},\n\t)\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\"runc\",\n\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(\"v\"+constants.RuncVersion, item.TypedSpec().Version)\n\t\t},\n\t)\n\n\t// Assert on Go version.\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\"golang\",\n\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\tgoVersion := strings.TrimPrefix(constants.GoVersion, \"go\")\n\n\t\t\tasrt.Equal(goVersion, item.TypedSpec().Version)\n\t\t},\n\t)\n\n\tif suite.Capabilities().RunsTalosKernel {\n\t\t// Assert on Talos kernel version.\n\t\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\"kernel\",\n\t\t\tfunc(item *runtime.SBOMItem, asrt *assert.Assertions) {\n\t\t\t\t// cut the suffix, first try removing .0 patch version for kernel releases like 6.17\n\t\t\t\tversion, _, ok := strings.Cut(constants.DefaultKernelVersion, \".0-\")\n\t\t\t\tif !ok {\n\t\t\t\t\tversion, _, ok = strings.Cut(constants.DefaultKernelVersion, \"-\")\n\t\t\t\t\tsuite.Require().True(ok, \"kernel version should have a suffix\")\n\t\t\t\t}\n\n\t\t\t\tasrt.Equal(version, item.TypedSpec().Version)\n\t\t\t},\n\t\t)\n\t} else {\n\t\trtestutils.AssertNoResource[*runtime.SBOMItem](ctx, suite.T(), suite.Client.COSI, \"kernel\")\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(SBOMSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/security.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// SecuritySuite verifies the security state resource.\ntype SecuritySuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *SecuritySuite) SuiteName() string {\n\treturn \"api.SecuritySuite\"\n}\n\n// SetupTest sets up the test.\nfunc (suite *SecuritySuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)\n\n\tif suite.Cluster != nil && suite.Cluster.Provisioner() == base.ProvisionerDocker {\n\t\tsuite.T().Skip(\"skipping Security test since provisioner is not docker\")\n\t}\n}\n\n// TearDownTest tears down the test.\nfunc (suite *SecuritySuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestSecurityState verifies that the security state resource is present and has valid values.\nfunc (suite *SecuritySuite) TestSecurityState() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{runtimeres.SecurityStateID},\n\t\tfunc(r *runtimeres.SecurityState, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().ModuleSignatureEnforced, \"module signature enforcement should be enabled\")\n\t\t},\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &SecuritySuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/selinux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"maps\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// SELinuxSuite ...\ntype SELinuxSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *SELinuxSuite) SuiteName() string {\n\treturn \"api.SELinuxSuite\"\n}\n\n// SetupTest ...\nfunc (suite *SELinuxSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 15*time.Second)\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping SELinux test since provisioner is not qemu\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *SELinuxSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\nfunc (suite *SELinuxSuite) getLabel(nodeCtx context.Context, pid int32) string {\n\tr, err := suite.Client.Read(nodeCtx, filepath.Join(\"/proc\", strconv.Itoa(int(pid)), \"attr/current\"))\n\tsuite.Require().NoError(err)\n\n\tvalue, err := io.ReadAll(r)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(r.Close())\n\n\treturn string(bytes.TrimSpace(value))\n}\n\n// TestFileMountLabels reads labels of runtime-created files and mounts from xattrs\n// to ensure SELinux labels for files are set when they are created and FS's are mounted with correct labels.\n// FIXME: cancel the test in case system was upgraded.\nfunc (suite *SELinuxSuite) TestFileMountLabels() {\n\tworkers := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker)\n\tcontrolplanes := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\texpectedLabelsWorker := map[string]string{\n\t\t// Mounts\n\t\tconstants.SystemPath:          constants.SystemSelinuxLabel,\n\t\tconstants.EphemeralMountPoint: constants.EphemeralSelinuxLabel,\n\t\tconstants.StateMountPoint:     constants.SystemSelinuxLabel,\n\t\tconstants.SystemVarPath:       constants.SystemVarSelinuxLabel,\n\t\tconstants.RunPath:             constants.RunSelinuxLabel,\n\t\t\"/run/containerd\":             \"system_u:object_r:pod_containerd_run_t:s0\",\n\t\t\"/run/lock\":                   \"system_u:object_r:var_lock_t:s0\",\n\t\tconstants.SystemRunPath:       \"system_u:object_r:system_run_t:s0\",\n\t\t\"/var/run\":                    constants.RunSelinuxLabel,\n\t\t// Runtime files\n\t\tconstants.APIRuntimeSocketPath:  constants.APIRuntimeSocketLabel,\n\t\tconstants.DBusClientSocketPath:  constants.DBusClientSocketLabel,\n\t\tconstants.UdevRulesPath:         constants.UdevRulesLabel,\n\t\tconstants.DBusServiceSocketPath: constants.DBusServiceSocketLabel,\n\t\tconstants.MachineSocketPath:     constants.MachineSocketLabel,\n\t\t// Overlays\n\t\t\"/etc/cni\":                        constants.CNISELinuxLabel,\n\t\tconstants.KubernetesConfigBaseDir: constants.KubernetesConfigSELinuxLabel,\n\t\t\"/usr/libexec/kubernetes\":         constants.KubeletPluginsSELinuxLabel,\n\t\t\"/opt\":                            constants.OptSELinuxLabel,\n\t\t\"/opt/cni\":                        \"system_u:object_r:cni_plugin_t:s0\",\n\t\t\"/opt/containerd\":                 \"system_u:object_r:containerd_plugin_t:s0\",\n\t\t// Directories\n\t\t\"/var/lib/containerd\":           \"system_u:object_r:containerd_state_t:s0\",\n\t\t\"/var/lib/cni\":                  \"system_u:object_r:cni_state_t:s0\",\n\t\t\"/var/lib/kubelet\":              \"system_u:object_r:kubelet_state_t:s0\",\n\t\t\"/var/lib/kubelet/seccomp\":      \"system_u:object_r:seccomp_profile_t:s0\",\n\t\tconstants.LogMountPoint:         \"system_u:object_r:var_log_t:s0\",\n\t\t\"/var/log/audit\":                \"system_u:object_r:audit_log_t:s0\",\n\t\tconstants.KubernetesAuditLogDir: \"system_u:object_r:kube_log_t:s0\",\n\t\t\"/var/log/containers\":           \"system_u:object_r:containers_log_t:s0\",\n\t\t\"/var/log/pods\":                 \"system_u:object_r:pods_log_t:s0\",\n\t\t// Mounts and runtime-generated files\n\t\t\"/etc\":                  constants.EtcSelinuxLabel,\n\t\tconstants.SystemEtcPath: constants.EtcSelinuxLabel,\n\t}\n\n\t// Only running on controlplane\n\texpectedLabelsControlPlane := map[string]string{\n\t\tconstants.EtcdPKIPath:                           constants.EtcdPKISELinuxLabel,\n\t\tconstants.EtcdDataPath:                          constants.EtcdDataSELinuxLabel,\n\t\tconstants.KubernetesAPIServerConfigDir:          constants.KubernetesAPIServerConfigDirSELinuxLabel,\n\t\tconstants.KubernetesAPIServerSecretsDir:         constants.KubernetesAPIServerSecretsDirSELinuxLabel,\n\t\tconstants.KubernetesControllerManagerSecretsDir: constants.KubernetesControllerManagerSecretsDirSELinuxLabel,\n\t\tconstants.KubernetesSchedulerConfigDir:          constants.KubernetesSchedulerConfigDirSELinuxLabel,\n\t\tconstants.KubernetesSchedulerSecretsDir:         constants.KubernetesSchedulerSecretsDirSELinuxLabel,\n\t\tconstants.TrustdRuntimeSocketPath:               constants.TrustdRuntimeSocketLabel,\n\t}\n\tmaps.Copy(expectedLabelsControlPlane, expectedLabelsWorker)\n\n\t// Devices labeled by subsystems, labeled by udev\n\texpectedLabelsDevices := map[string]string{\n\t\t\"/dev/rtc0\":      \"system_u:object_r:rtc_device_t:s0\",\n\t\t\"/dev/tpm0\":      \"system_u:object_r:tpm_device_t:s0\",\n\t\t\"/dev/tpmrm0\":    \"system_u:object_r:tpm_device_t:s0\",\n\t\t\"/dev/watchdog\":  \"system_u:object_r:wdt_device_t:s0\",\n\t\t\"/dev/watchdog0\": \"system_u:object_r:wdt_device_t:s0\",\n\t\t\"/dev/null\":      \"system_u:object_r:null_device_t:s0\",\n\t\t\"/dev/zero\":      \"system_u:object_r:null_device_t:s0\",\n\t}\n\n\tsuite.checkFileLabels(workers, expectedLabelsWorker, false)\n\tsuite.checkFileLabels(controlplanes, expectedLabelsControlPlane, false)\n\tsuite.checkFileLabels(workers, expectedLabelsDevices, true)\n\tsuite.checkFileLabels(controlplanes, expectedLabelsDevices, true)\n}\n\n//nolint:gocyclo\nfunc (suite *SELinuxSuite) checkFileLabels(nodes []string, expectedLabels map[string]string, allowMissing bool) {\n\tpaths := make([]string, 0, len(expectedLabels))\n\tfor k := range expectedLabels {\n\t\tpaths = append(paths, k)\n\t}\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\t\tcmdline := suite.ReadCmdline(nodeCtx)\n\n\t\tseLinuxEnabled := pointer.SafeDeref(procfs.NewCmdline(cmdline).Get(constants.KernelParamSELinux).First()) != \"\"\n\t\tif !seLinuxEnabled {\n\t\t\tsuite.T().Skip(\"skipping SELinux test since SELinux is disabled\")\n\t\t}\n\n\t\textensions, err := safe.StateListAll[*runtimeres.ExtensionStatus](nodeCtx, suite.Client.COSI)\n\t\tsuite.Require().NoError(err)\n\n\t\tif extensions.Len() > 0 {\n\t\t\tsuite.T().Skip(\"skipping SELinux test since extensions are running\")\n\t\t}\n\n\t\tfor path, label := range expectedLabels {\n\t\t\treq := &machineapi.ListRequest{\n\t\t\t\tRoot:         path,\n\t\t\t\tReportXattrs: true,\n\t\t\t}\n\n\t\t\tstream, err := suite.Client.LS(nodeCtx, req)\n\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\terr = helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {\n\t\t\t\t// E.g. /var/lib should inherit /var label, while /var/run is a new mountpoint\n\t\t\t\tif slices.Contains(paths, info.Name) && info.Name != path {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tif slices.Contains(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\tconstants.RunPath,\n\t\t\t\t\t\tconstants.SystemRunPath,\n\t\t\t\t\t\t\"/run/containerd\",\n\t\t\t\t\t\t\"/var/run\",\n\t\t\t\t\t\t\"/var/log/containers\",\n\t\t\t\t\t},\n\t\t\t\t\tpath,\n\t\t\t\t) && info.Name != path {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// these are symlinks that comes from files from extensions, and we don't set xattrs for extensions yet\n\t\t\t\t// TODO(frezbo): update the test to check for correct labels once we set xattrs for extensions\n\t\t\t\tif info.Name == \"/etc/ld.so.conf\" || info.Name == \"/etc/ld.so.cache\" || info.Name == \"/usr/bin/nvidia-smi\" {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tsuite.Require().NotNil(info.Xattrs, \"expected %s to have xattrs (checking %s)\", info.Name, path)\n\n\t\t\t\tfound := false\n\n\t\t\t\tfor _, l := range info.Xattrs {\n\t\t\t\t\tif l.Name == \"security.selinux\" {\n\t\t\t\t\t\tgot := string(bytes.Trim(l.Data, \"\\x00\\n\"))\n\t\t\t\t\t\tsuite.Require().Contains(got, label, \"expected %s to have label %s, got %s (checking %s)\", info.Name, label, got, path)\n\n\t\t\t\t\t\tfound = true\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsuite.Require().True(found, \"expected to find security.selinux xattr for %s (checking %s)\", info.Name, path)\n\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\tif allowMissing {\n\t\t\t\tif err != nil {\n\t\t\t\t\tsuite.Require().Contains(err.Error(), \"lstat\")\n\t\t\t\t\tsuite.Require().Contains(err.Error(), \"no such file or directory\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsuite.Require().NoError(err)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TestProcessLabels reads labels of system processes from procfs\n// to ensure SELinux labels for processes are correctly set\n//\n//nolint:gocyclo\nfunc (suite *SELinuxSuite) TestProcessLabels() {\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\n\tfor _, node := range nodes {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\t\tcmdline := suite.ReadCmdline(nodeCtx)\n\n\t\tseLinuxEnabled := pointer.SafeDeref(procfs.NewCmdline(cmdline).Get(constants.KernelParamSELinux).First()) != \"\"\n\t\tif !seLinuxEnabled {\n\t\t\tsuite.T().Skip(\"skipping SELinux test since SELinux is disabled\")\n\t\t}\n\n\t\tr, err := suite.Client.Processes(nodeCtx)\n\t\tsuite.Require().NoError(err)\n\n\t\tfor _, msg := range r.Messages {\n\t\t\tprocs := msg.Processes\n\n\t\t\tfor _, p := range procs {\n\t\t\t\tswitch p.Command {\n\t\t\t\tcase \"systemd-udevd\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelUdevd,\n\t\t\t\t\t)\n\t\t\t\tcase \"dashboard\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelDashboard,\n\t\t\t\t\t)\n\t\t\t\tcase \"containerd\":\n\t\t\t\t\tif strings.Contains(p.Args, \"/system/run/containerd\") {\n\t\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\t\tconstants.SelinuxLabelSystemRuntime,\n\t\t\t\t\t\t)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\t\tconstants.SelinuxLabelPodRuntime,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\tcase \"init\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelMachined,\n\t\t\t\t\t)\n\t\t\t\tcase \"kubelet\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelKubelet,\n\t\t\t\t\t)\n\t\t\t\tcase \"apid\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelApid,\n\t\t\t\t\t)\n\t\t\t\tcase \"trustd\":\n\t\t\t\t\tsuite.Require().Contains(\n\t\t\t\t\t\tsuite.getLabel(nodeCtx, p.Pid),\n\t\t\t\t\t\tconstants.SelinuxLabelTrustd,\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// TestSecurityState validates SecurityState in accordance to -talos.enforcing.\nfunc (suite *SELinuxSuite) TestSecurityState() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tnodeCtx := client.WithNode(suite.ctx, node)\n\t\tcmdline := suite.ReadCmdline(nodeCtx)\n\n\t\tseLinuxEnabled := pointer.SafeDeref(procfs.NewCmdline(cmdline).Get(constants.KernelParamSELinux).First()) != \"\"\n\t\tif !seLinuxEnabled {\n\t\t\tcontinue\n\t\t}\n\n\t\trtestutils.AssertResource(\n\t\t\tnodeCtx,\n\t\t\tsuite.T(),\n\t\t\tsuite.Client.COSI,\n\t\t\truntimeres.SecurityStateID,\n\t\t\tfunc(state *runtimeres.SecurityState, asrt *assert.Assertions) {\n\t\t\t\tif suite.SelinuxEnforcing {\n\t\t\t\t\tasrt.Equal(runtimeres.SELinuxStateEnforcing, state.TypedSpec().SELinuxState)\n\t\t\t\t} else {\n\t\t\t\t\tasrt.Equal(runtimeres.SELinuxStatePermissive, state.TypedSpec().SELinuxState)\n\t\t\t\t}\n\t\t\t},\n\t\t)\n\t}\n}\n\n// TODO: test for system and CRI container labels\n// TODO: test labels for unconfined system extensions, pods\n// TODO: test for no avc denials in dmesg\n\n// TestNoPtrace confirms ptracing system processes is prohibited in enforcing mode.\nfunc (suite *SELinuxSuite) TestNoPtrace() {\n\tif !suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping SELinux negative tests in permissive mode\")\n\t}\n\n\tpodDef, err := suite.NewPrivilegedPod(\"pid1-ptrace-test\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithQuiet(true)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\t_, stderr, err := podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"apk add --update strace\",\n\t)\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Empty(stderr, \"stderr: %s\", stderr)\n\n\t// if attached, timeout\n\tctx, cancel := context.WithTimeout(suite.ctx, time.Second*5)\n\tdefer cancel()\n\n\t_, stderr, err = podDef.Exec(\n\t\tctx,\n\t\t\"strace -p 1\",\n\t)\n\n\t// in case of successful attach it will be context.DeadlineExceeded\n\tsuite.Require().Error(err)\n\tsuite.Assert().ErrorContains(err, \"command terminated with exit code 1\")\n\t// strace first tests ptrace against itself, which we also deny currently\n\tsuite.Assert().Contains(stderr, \"strace: do_test_ptrace_get_syscall_info: PTRACE_TRACEME: Permission denied\")\n\tsuite.Assert().Contains(stderr, \"strace: attach: ptrace(PTRACE_SEIZE, 1): Permission denied\")\n\tsuite.Assert().NotContains(stderr, \"attached\")\n}\n\n// TestNoMachineSocketAccess confirms pods cannot reach machined socket (not apid, but unsecured one).\nfunc (suite *SELinuxSuite) TestNoMachineSocketAccess() {\n\tif !suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping SELinux negative tests in permissive mode\")\n\t}\n\n\tpodDef, err := suite.NewPrivilegedPod(\"pid1-socket-test\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithQuiet(true)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\t_, stderr, err := podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"apk add --update socat\",\n\t)\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Empty(stderr, \"stderr: %s\", stderr)\n\n\t// if attached, timeout\n\tctx, cancel := context.WithTimeout(suite.ctx, time.Second*5)\n\tdefer cancel()\n\n\t_, stderr, err = podDef.Exec(\n\t\tctx,\n\t\t\"socat - UNIX-CONNECT:/host/system/run/machined/machine.sock\",\n\t)\n\n\t// in case of successful attach it will be context.DeadlineExceeded\n\tsuite.Require().Error(err)\n\tsuite.Assert().ErrorContains(err, \"command terminated with exit code 1\")\n\tsuite.Assert().Contains(stderr, \"Permission denied\")\n}\n\n// TestNoStateAccess verifies mounting STATE does not allow /system/state/config.yaml access.\nfunc (suite *SELinuxSuite) TestNoStateAccess() {\n\tif !suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping SELinux negative tests in permissive mode\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tstate, err := safe.StateGetByID[*block.VolumeStatus](nodeCtx, suite.Client.COSI, \"STATE\")\n\tsuite.Assert().NoError(err)\n\n\tpodDef, err := suite.NewPrivilegedPod(\"system-state-test\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithQuiet(true)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\t_, stderr, err := podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"mount \"+state.TypedSpec().MountLocation+\" /mnt\",\n\t)\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Empty(stderr, \"stderr: %s\", stderr)\n\n\t_, stderr, err = podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"cat /mnt/config.yaml\",\n\t)\n\n\tsuite.Require().Error(err)\n\tsuite.Assert().ErrorContains(err, \"command terminated with exit code 1\")\n\tsuite.Assert().Contains(stderr, \"cat: can't open '/mnt/config.yaml': Permission denied\")\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(SELinuxSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/serviceaccount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\teventsv1 \"k8s.io/api/events/v1\"\n\tkubeerrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime/schema\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar (\n\tserviceAccountGVR = schema.GroupVersionResource{\n\t\tGroup:    constants.ServiceAccountResourceGroup,\n\t\tVersion:  constants.ServiceAccountResourceVersion,\n\t\tResource: constants.ServiceAccountResourcePlural,\n\t}\n\tsecretGVR = schema.GroupVersionResource{\n\t\tGroup:    \"\",\n\t\tVersion:  \"v1\",\n\t\tResource: \"secrets\",\n\t}\n\tjobGVR = schema.GroupVersionResource{\n\t\tGroup:    \"batch\",\n\t\tVersion:  \"v1\",\n\t\tResource: \"jobs\",\n\t}\n)\n\n// ServiceAccountSuite verifies Talos ServiceAccount.\ntype ServiceAccountSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *ServiceAccountSuite) SuiteName() string {\n\treturn \"api.ServiceAccountSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ServiceAccountSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n\n\tsuite.ClearConnectionRefused(suite.ctx, suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker)...)\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\n// TearDownTest ...\nfunc (suite *ServiceAccountSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestValid tests Kubernetes service accounts.\nfunc (suite *ServiceAccountSuite) TestValid() {\n\tname := \"test-valid\"\n\n\terr := suite.configureAPIAccess(true, []string{\"os:reader\"}, []string{\"kube-system\"})\n\tsuite.Assert().NoError(err)\n\n\t_, err = suite.getCRD()\n\tsuite.Assert().NoError(err)\n\n\tsa, err := suite.createServiceAccount(\"kube-system\", name, []string{\"os:reader\"})\n\tsuite.Assert().NoError(err)\n\n\tdefer suite.DeleteResource(suite.ctx, serviceAccountGVR, \"default\", name) //nolint:errcheck\n\n\terr = suite.WaitForEventExists(suite.ctx, \"kube-system\", func(event eventsv1.Event) bool {\n\t\treturn event.Regarding.UID == sa.GetUID() &&\n\t\t\tevent.Type == corev1.EventTypeNormal &&\n\t\t\tevent.Reason == \"Synced\"\n\t})\n\tsuite.Assert().NoError(err)\n\n\tsecret, err := suite.waitForSecret(\"kube-system\", name)\n\tsuite.Assert().NoError(err)\n\n\ttalosConfig := secret.Data[\"config\"]\n\n\tconf, err := config.FromBytes(talosConfig)\n\tsuite.Assert().NoError(err)\n\n\texpectedServiceName := fmt.Sprintf(\n\t\t\"%s.%s\",\n\t\tconstants.KubernetesTalosAPIServiceName,\n\t\tconstants.KubernetesTalosAPIServiceNamespace,\n\t)\n\tsuite.Assert().Equal([]string{expectedServiceName}, conf.Contexts[conf.Context].Endpoints)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\t_, err = suite.creteTestJob(\"kube-system\", name, name, node)\n\tsuite.Assert().NoError(err)\n\n\terr = suite.waitForJobReady(2*time.Minute, \"kube-system\", name)\n\tsuite.Assert().NoError(err)\n\n\terr = suite.DeleteResource(suite.ctx, jobGVR, \"kube-system\", name)\n\tsuite.Require().NoError(err)\n\n\terr = suite.EnsureResourceIsDeleted(suite.ctx, 30*time.Second, jobGVR, \"kube-system\", name)\n\tsuite.Assert().NoError(err)\n\n\terr = suite.DeleteResource(suite.ctx, serviceAccountGVR, \"kube-system\", name)\n\tsuite.Require().NoError(err)\n\n\terr = suite.EnsureResourceIsDeleted(suite.ctx, 30*time.Second, secretGVR, \"kube-system\", name)\n\tsuite.Assert().NoError(err)\n}\n\n// TestNotAllowedNamespace tests Kubernetes service accounts in not allowed namespaces.\nfunc (suite *ServiceAccountSuite) TestNotAllowedNamespace() {\n\tname := \"test-allowed-ns\"\n\n\terr := suite.configureAPIAccess(true, []string{\"os:reader\"}, []string{\"kube-system\"})\n\tsuite.Require().NoError(err)\n\n\tsa, err := suite.createServiceAccount(\"default\", name, []string{\"os:reader\"})\n\tsuite.Require().NoError(err)\n\n\tdefer suite.DeleteResource(suite.ctx, serviceAccountGVR, \"default\", name) //nolint:errcheck\n\n\terr = suite.WaitForEventExists(suite.ctx, \"default\", func(event eventsv1.Event) bool {\n\t\treturn event.Regarding.UID == sa.GetUID() &&\n\t\t\tevent.Type == corev1.EventTypeWarning &&\n\t\t\tevent.Reason == \"ErrNamespaceNotAllowed\"\n\t})\n\tsuite.Require().NoError(err)\n}\n\n// TestNotAllowedRoles tests Kubernetes service accounts with not allowed roles.\nfunc (suite *ServiceAccountSuite) TestNotAllowedRoles() {\n\tname := \"test-not-allowed-roles\"\n\n\terr := suite.configureAPIAccess(true, []string{\"os:reader\"}, []string{\"kube-system\"})\n\tsuite.Assert().NoError(err)\n\n\tsa, err := suite.createServiceAccount(\"kube-system\", name, []string{\"os:admin\"})\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().NotNil(sa)\n\n\tdefer suite.DeleteResource(suite.ctx, serviceAccountGVR, \"kube-system\", name) //nolint:errcheck\n\n\terr = suite.WaitForEventExists(suite.ctx, \"kube-system\", func(event eventsv1.Event) bool {\n\t\treturn event.Regarding.UID == sa.GetUID() &&\n\t\t\tevent.Type == corev1.EventTypeWarning &&\n\t\t\tevent.Reason == \"ErrRolesNotAllowed\"\n\t})\n\tsuite.Assert().NoError(err)\n}\n\n// TestFeatureNotEnabled tests Kubernetes service accounts when API access feature is not enabled.\nfunc (suite *ServiceAccountSuite) TestFeatureNotEnabled() {\n\tname := \"test-feature-not-enabled\"\n\n\terr := suite.configureAPIAccess(false, []string{\"os:reader\"}, []string{\"kube-system\"})\n\tsuite.Assert().NoError(err)\n\n\tsa, err := suite.createServiceAccount(\"kube-system\", name, []string{\"os:reader\"})\n\tif kubeerrors.IsNotFound(err) {\n\t\t// CRD is not created because the feature was never enabled, all good\n\t\treturn\n\t}\n\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().NotNil(sa)\n\n\tdefer suite.DeleteResource(suite.ctx, serviceAccountGVR, \"kube-system\", name) //nolint:errcheck\n\n\terr = suite.WaitForEventExists(suite.ctx, \"kube-system\", func(event eventsv1.Event) bool {\n\t\treturn event.Regarding.UID == sa.GetUID() &&\n\t\t\tevent.Type == corev1.EventTypeWarning &&\n\t\t\tevent.Reason == \"ErrAccessNotEnabled\"\n\t})\n\n\tsuite.Assert().NoError(err)\n}\n\nfunc (suite *ServiceAccountSuite) waitForSecret(ns, name string) (*corev1.Secret, error) {\n\tvar (\n\t\tsecret *corev1.Secret\n\t\terr    error\n\t)\n\n\terr = retry.Constant(1*time.Minute).RetryWithContext(suite.ctx, func(ctx context.Context) error {\n\t\tsecret, err = suite.Clientset.CoreV1().Secrets(ns).Get(suite.ctx, name, metav1.GetOptions{})\n\t\tif kubeerrors.IsNotFound(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn secret, nil\n}\n\nfunc (suite *ServiceAccountSuite) getCRD() (*unstructured.Unstructured, error) {\n\tcrdName := fmt.Sprintf(\"%s.%s\", constants.ServiceAccountResourcePlural, constants.ServiceAccountResourceGroup)\n\n\treturn suite.DynamicClient.Resource(schema.GroupVersionResource{\n\t\tGroup:    \"apiextensions.k8s.io\",\n\t\tVersion:  \"v1\",\n\t\tResource: \"customresourcedefinitions\",\n\t}).Get(suite.ctx, crdName, metav1.GetOptions{})\n}\n\nfunc (suite *ServiceAccountSuite) createServiceAccount(ns string, name string, roles []string) (*unstructured.Unstructured, error) {\n\treturn suite.DynamicClient.Resource(serviceAccountGVR).Namespace(ns).Create(suite.ctx, &unstructured.Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"apiVersion\": fmt.Sprintf(\"%s/%s\", constants.ServiceAccountResourceGroup, constants.ServiceAccountResourceVersion),\n\t\t\t\"kind\":       constants.ServiceAccountResourceKind,\n\t\t\t\"metadata\": map[string]any{\n\t\t\t\t\"name\": name,\n\t\t\t},\n\t\t\t\"spec\": map[string]any{\n\t\t\t\t\"roles\": roles,\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n}\n\nfunc (suite *ServiceAccountSuite) creteTestJob(ns, name, serviceAccount, node string) (*unstructured.Unstructured, error) {\n\treturn suite.DynamicClient.Resource(jobGVR).Namespace(ns).Create(suite.ctx, &unstructured.Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"apiVersion\": fmt.Sprintf(\"%s/%s\", jobGVR.Group, jobGVR.Version),\n\t\t\t\"kind\":       \"Job\",\n\t\t\t\"metadata\": map[string]any{\n\t\t\t\t\"name\": name,\n\t\t\t},\n\t\t\t\"spec\": map[string]any{\n\t\t\t\t\"template\": map[string]any{\n\t\t\t\t\t\"spec\": map[string]any{\n\t\t\t\t\t\t\"restartPolicy\": \"Never\",\n\t\t\t\t\t\t\"volumes\": []map[string]any{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\": \"talos-secrets\",\n\t\t\t\t\t\t\t\t\"secret\": map[string]any{\n\t\t\t\t\t\t\t\t\t\"secretName\": serviceAccount,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"containers\": []map[string]any{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\":  \"talosctl\",\n\t\t\t\t\t\t\t\t\"image\": \"ghcr.io/siderolabs/talosctl:v1.12.4\", // sync with cmd/talos/image.go list\n\t\t\t\t\t\t\t\t\"args\": []string{\n\t\t\t\t\t\t\t\t\t\"--nodes\", node,\n\t\t\t\t\t\t\t\t\t\"version\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"volumeMounts\": []map[string]any{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"mountPath\": \"/var/run/secrets/talos.dev\",\n\t\t\t\t\t\t\t\t\t\t\"name\":      \"talos-secrets\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, metav1.CreateOptions{})\n}\n\nfunc (suite *ServiceAccountSuite) waitForJobReady(duration time.Duration, ns, name string) error {\n\tcli := suite.DynamicClient.Resource(jobGVR).Namespace(ns)\n\n\treturn retry.Constant(duration).RetryWithContext(suite.ctx, func(ctx context.Context) error {\n\t\tjob, err := cli.Get(ctx, name, metav1.GetOptions{})\n\t\tif kubeerrors.IsNotFound(err) {\n\t\t\treturn retry.ExpectedError(fmt.Errorf(\"job %s/%s not found\", ns, name))\n\t\t} else if err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif job.Object[\"status\"] == nil {\n\t\t\treturn retry.ExpectedError(fmt.Errorf(\"job %s/%s status is not set\", ns, name))\n\t\t}\n\n\t\tstatus := job.Object[\"status\"].(map[string]any)\n\t\tif status[\"succeeded\"] == nil || status[\"succeeded\"].(int64) == 0 {\n\t\t\treturn retry.ExpectedError(fmt.Errorf(\"job %s/%s is not ready yet\", ns, name))\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// configureAPIAccess configures the API access feature on all control plane nodes.\nfunc (suite *ServiceAccountSuite) configureAPIAccess(\n\tenabled bool,\n\tallowedRoles []string,\n\tallowedNamespaces []string,\n) error {\n\tcontrolPlaneIPs := suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane)\n\n\tfor _, ip := range controlPlaneIPs {\n\t\tnodeCtx := client.WithNode(suite.ctx, ip)\n\n\t\tnodeConfig, err := suite.ReadConfigFromNode(nodeCtx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbytes := suite.PatchV1Alpha1Config(nodeConfig, func(nodeConfigRaw *v1alpha1.Config) {\n\t\t\taccessConfig := v1alpha1.KubernetesTalosAPIAccessConfig{\n\t\t\t\tAccessEnabled:                     new(enabled),\n\t\t\t\tAccessAllowedRoles:                allowedRoles,\n\t\t\t\tAccessAllowedKubernetesNamespaces: allowedNamespaces,\n\t\t\t}\n\n\t\t\tnodeConfigRaw.MachineConfig.MachineFeatures.KubernetesTalosAPIAccessConfig = &accessConfig\n\t\t})\n\n\t\t_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{\n\t\t\tData: bytes,\n\t\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif enabled { // wait for CRD and the Talos endpoint to be created\n\t\treturn retry.Constant(30*time.Second).RetryWithContext(suite.ctx, func(ctx context.Context) error {\n\t\t\t_, err := suite.getCRD()\n\t\t\tif err != nil {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\t_, err = suite.Clientset.CoreV1().\n\t\t\t\tServices(constants.KubernetesTalosAPIServiceNamespace).\n\t\t\t\tGet(suite.ctx, constants.KubernetesTalosAPIServiceName, metav1.GetOptions{})\n\t\t\tif err != nil {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ServiceAccountSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/siderolink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tsiderolinkconfig \"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\n// SideroLinkSuite ...\ntype SideroLinkSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *SideroLinkSuite) SuiteName() string {\n\treturn \"api.SideroLinkSuite\"\n}\n\n// SetupTest ...\nfunc (suite *SideroLinkSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *SideroLinkSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestTunnelSettingFlip enables/disables the tunnel-over-GRPC setting of the link.\nfunc (suite *SideroLinkSuite) TestTunnelSettingFlip() {\n\t// pick up a random node to test the SideroLink on, and use it throughout the test\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.T().Logf(\"testing SideroLink on node %s\", node)\n\n\t// build a Talos API context which is tied to the node\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t// check if SideroLink is enabled\n\tsideroLinkConfig, err := safe.StateGetByID[*siderolink.Config](nodeCtx, suite.Client.COSI, siderolink.ConfigID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\tsuite.T().Skip(\"skipping the test since SideroLink is not enabled\")\n\t\t}\n\n\t\tsuite.Require().NoError(err)\n\t}\n\n\t// assert that siderolink is connected\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, siderolink.StatusID, func(status *siderolink.Status, asrt *assert.Assertions) {\n\t\tasrt.True(status.TypedSpec().Connected, \"SideroLink is not connected\")\n\t})\n\n\tapiURL, err := url.Parse(sideroLinkConfig.TypedSpec().APIEndpoint)\n\tsuite.Require().NoError(err)\n\n\tq := apiURL.Query()\n\n\t// flip the tunnel setting\n\tif sideroLinkConfig.TypedSpec().Tunnel {\n\t\tq.Del(\"grpc_tunnel\")\n\n\t\tsuite.T().Log(\"flipping the tunnel setting to false\")\n\t} else {\n\t\tq.Set(\"grpc_tunnel\", \"true\")\n\n\t\tsuite.T().Log(\"flipping the tunnel setting to true\")\n\t}\n\n\tapiURL.RawQuery = q.Encode()\n\n\tcfgDocument := siderolinkconfig.NewConfigV1Alpha1()\n\tcfgDocument.APIUrlConfig.URL = apiURL\n\n\t// patch settings\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t// first, the config should be updated\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, siderolink.ConfigID, func(config *siderolink.Config, asrt *assert.Assertions) {\n\t\tasrt.Equal(!sideroLinkConfig.TypedSpec().Tunnel, config.TypedSpec().Tunnel, \"SideroLink tunnel setting is not updated\")\n\t})\n\n\tsuite.T().Log(\"configuration updated, waiting for SideroLink to reconnect...\")\n\n\t// second, new status should reflect the change\n\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, siderolink.StatusID, func(status *siderolink.Status, asrt *assert.Assertions) {\n\t\tasrt.True(status.TypedSpec().Connected, \"SideroLink is not connected\")\n\t\tasrt.Equal(!sideroLinkConfig.TypedSpec().Tunnel, status.TypedSpec().GRPCTunnel, \"SideroLink tunnel setting is not updated\")\n\t})\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(SideroLinkSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/testdata/nodeport.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  labels:\n    app: test-nginx\n  name: test-nginx\n  namespace: default\nspec:\n  progressDeadlineSeconds: 600\n  replicas: 1\n  revisionHistoryLimit: 10\n  selector:\n    matchLabels:\n      app: test-nginx\n  strategy:\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n    type: RollingUpdate\n  template:\n    metadata:\n      labels:\n        app: test-nginx\n    spec:\n      containers:\n      - image: nginx\n        imagePullPolicy: Always\n        name: nginx\n        ports:\n        - containerPort: 80\n          protocol: TCP\n        resources:\n          limits:\n            cpu: 100m\n            memory: 128Mi\n          requests:\n            cpu: 100m\n            memory: 128Mi\n      restartPolicy: Always\n      terminationGracePeriodSeconds: 5\n---\napiVersion: v1\nkind: Service\nmetadata:\n  labels:\n    app: test-nginx\n  name: test-nginx\n  namespace: default\nspec:\n  ipFamilies:\n  - IPv4\n  ipFamilyPolicy: SingleStack\n  ports:\n  - port: 80\n    protocol: TCP\n    targetPort: 80\n  selector:\n    app: test-nginx\n  type: NodePort\n"
  },
  {
    "path": "internal/integration/api/testdata/nvidia-gpu-operator.yaml",
    "content": "driver:\n  enabled: false\ntoolkit:\n  enabled: false\nhostPaths:\n  driverInstallDir: /usr/local/glibc/usr\n"
  },
  {
    "path": "internal/integration/api/trusted-roots.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// TrustedRootsSuite ...\ntype TrustedRootsSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *TrustedRootsSuite) SuiteName() string {\n\treturn \"api.TrustedRootsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *TrustedRootsSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *TrustedRootsSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\nfunc (suite *TrustedRootsSuite) readTrustedRoots(nodeCtx context.Context) string {\n\tr, err := suite.Client.Read(nodeCtx, constants.DefaultTrustedCAFile)\n\tsuite.Require().NoError(err)\n\n\tvalue, err := io.ReadAll(r)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(r.Close())\n\n\treturn string(value)\n}\n\n// TestTrustedRoots verifies default and custom trusted CA roots.\nfunc (suite *TrustedRootsSuite) TestTrustedRoots() {\n\t// pick up a random node to test the TrustedRoots on, and use it throughout the test\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.T().Logf(\"testing TrustedRoots on node %s\", node)\n\n\t// build a Talos API context which is tied to the node\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tconst name = \"test-ca\"\n\n\tcfgDocument := security.NewTrustedRootsConfigV1Alpha1()\n\tcfgDocument.MetaName = name\n\tcfgDocument.Certificates = \"--- BEGIN CERTIFICATE ---\\nMIIC0DCCAbigAwIBAgIUI\\n--- END CERTIFICATE ---\\n\"\n\n\t// clean up custom config if it exists\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\tcertificates := suite.readTrustedRoots(nodeCtx)\n\tsuite.Require().Contains(certificates, \"Bundle of CA Root Certificates\")\n\n\t// enable custom trusted roots\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn strings.Contains(suite.readTrustedRoots(nodeCtx), name)\n\t}, 5*time.Second, 100*time.Millisecond)\n\n\t// deactivate the TrustedRoots\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn !strings.Contains(suite.readTrustedRoots(nodeCtx), name)\n\t}, 5*time.Second, 100*time.Millisecond)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(TrustedRootsSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/trustedboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// TrustedBootSuite verifies Talos is securebooted.\ntype TrustedBootSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *TrustedBootSuite) SuiteName() string {\n\treturn \"api.TrustedBootSuite\"\n}\n\n// SetupTest ...\nfunc (suite *TrustedBootSuite) SetupTest() {\n\tif !suite.TrustedBoot {\n\t\tsuite.T().Skip(\"skipping since talos.trustedboot is false\")\n\t}\n\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 10*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *TrustedBootSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestTrustedBootState verifies that the system is booted in secure boot mode\n// and that the disks are encrypted.\nfunc (suite *TrustedBootSuite) TestTrustedBootState() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{runtimeres.SecurityStateID},\n\t\tfunc(r *runtimeres.SecurityState, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().SecureBoot)\n\t\t},\n\t)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t[]resource.ID{constants.StatePartitionLabel, constants.EphemeralPartitionLabel},\n\t\tfunc(r *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(block.VolumePhaseReady, r.TypedSpec().Phase)\n\t\t\tasrt.Equal(block.EncryptionProviderLUKS2, r.TypedSpec().EncryptionProvider)\n\t\t},\n\t)\n\n\tdmesgStream, err := suite.Client.Dmesg(\n\t\tsuite.ctx,\n\t\tfalse,\n\t\tfalse,\n\t)\n\tsuite.Require().NoError(err)\n\n\tlogReader, err := client.ReadStream(dmesgStream)\n\tsuite.Require().NoError(err)\n\n\tvar dmesg bytes.Buffer\n\n\t_, err = io.Copy(bufio.NewWriter(&dmesg), logReader)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(dmesg.String(), \"Secure boot enabled\")\n}\n\n// TestEncryptionConfigRotate verifies that the encryption supports locking and unlocking to different PCRs.\nfunc (suite *TrustedBootSuite) TestEncryptionConfigRotate() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tprovider, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tephemeralCfg, _ := provider.Volumes().ByName(constants.EphemeralPartitionLabel)\n\tencryption := ephemeralCfg.Encryption()\n\n\tsuite.Require().NotNil(encryption, \"encryption config must be set for EPHEMERAL in trustedboot test\")\n\n\tsuite.WaitForBootDone(suite.ctx)\n\n\tsuite.T().Logf(\"testing encryption key rotation on node %s\", node)\n\n\tcfg, ok := encryption.(blockcfg.EncryptionSpec)\n\tsuite.Require().True(ok, \"expected blockcfg.EncryptionSpec, got %T\", encryption)\n\n\t// when we start the test we do not know the current encryption provider in use\n\t// so let's read the volumestatus to get the information about the slot in use and whether lockToState is set\n\tvolumeStatus, err := safe.StateGetByID[*block.VolumeStatus](nodeCtx, suite.Client.COSI, constants.EphemeralPartitionLabel)\n\tsuite.Require().NoError(err)\n\n\texistingEncryptionSlotInUse := *volumeStatus.TypedSpec().EncryptionSlot\n\n\texisting := xslices.Filter(cfg.EncryptionKeys, func(key blockcfg.EncryptionKey) bool {\n\t\treturn key.Slot() == existingEncryptionSlotInUse\n\t})[0]\n\n\tvar (\n\t\texistingPCRs       []int\n\t\texpectedPubKeyPCRs []int\n\t)\n\n\tif existing.TPM() != nil {\n\t\texistingPCRs = existing.TPM().PCRs()\n\t\texpectedPubKeyPCRs = existing.TPM().PubKeyPCRs()\n\t}\n\n\tnextSlot := existing.Slot() + 1\n\n\tfor _, test := range []struct {\n\t\tkeys []blockcfg.EncryptionKey\n\n\t\texpectedPCRs          []int\n\t\texpectedPubKeyPCRs    []int\n\t\texpectedLockedToState bool\n\t}{\n\t\t// for the initial set, let's add a new TPM based key with no PCR options specified\n\t\t// in this case after reboot the new slot will be added for the TPM key and the expected PCRs\n\t\t// and lockToState status will be the same as the existing key\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\texisting,\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot,\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          existingPCRs,\n\t\t\texpectedPubKeyPCRs:    expectedPubKeyPCRs,\n\t\t\texpectedLockedToState: existing.LockToSTATE(),\n\t\t},\n\t\t// now remove the existing key and add a new TPM based key with no PCRs specified\n\t\t// in this case after a reboot we should have default TPM based encryption values\n\t\t// i.e. PCR is SecureBootStatePCR and lockToState is true\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot,\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          []int{constants.SecureBootStatePCR},\n\t\t\texpectedPubKeyPCRs:    []int{constants.UKIPCR},\n\t\t\texpectedLockedToState: true,\n\t\t},\n\t\t// now keep the previous TPM based key with no PCRs specified and add a new key with PCRs set\n\t\t// to empty and lockToState set to false, after reboot we should have default TPM based encryption values\n\t\t// i.e. PCR is SecureBootStatePCR and lockToState is true\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot,\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t\tTPMOptions: &blockcfg.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\tPCRs: []int{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot + 1,\n\t\t\t\t\tKeyLockToSTATE: new(false),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          []int{constants.SecureBootStatePCR},\n\t\t\texpectedPubKeyPCRs:    []int{constants.UKIPCR},\n\t\t\texpectedLockedToState: true,\n\t\t},\n\t\t// now only keep the TPM key with PCRs set to empty and lockToState set to false\n\t\t// in this case after a reboot we should have no PCRs and lockToState is false\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t\tTPMOptions: &blockcfg.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\tPCRs: []int{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot + 1,\n\t\t\t\t\tKeyLockToSTATE: new(false),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          nil,\n\t\t\texpectedPubKeyPCRs:    []int{constants.UKIPCR},\n\t\t\texpectedLockedToState: false,\n\t\t},\n\t\t// now keep the previous TPM based key with PCRs set to empty and lockToState set to false\n\t\t// and add a new key with PCRs set to [0, SecureBootStatePCR] and lockToState set to true\n\t\t// in this case after a reboot we should have no PCRs and lockToState is false\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t\tTPMOptions: &blockcfg.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\tPCRs: []int{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot + 1,\n\t\t\t\t\tKeyLockToSTATE: new(false),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t\tTPMOptions: &blockcfg.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\tPCRs: []int{0, constants.SecureBootStatePCR},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot + 2,\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          nil,\n\t\t\texpectedPubKeyPCRs:    []int{constants.UKIPCR},\n\t\t\texpectedLockedToState: false,\n\t\t},\n\t\t// now only keep the TPM key with PCRs set to [0, SecureBootStatePCR] and lockToState set to true\n\t\t// in this case after a reboot we should have PCRs set to [0, SecureBootStatePCR] and lockToState is true\n\t\t{\n\t\t\tkeys: []blockcfg.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeyTPM: &blockcfg.EncryptionKeyTPM{\n\t\t\t\t\t\t// TPMCheckSecurebootStatusOnEnroll: new(true),\n\t\t\t\t\t\tTPMOptions: &blockcfg.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\tPCRs: []int{0, constants.SecureBootStatePCR},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tKeySlot:        nextSlot + 2,\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedPCRs:          []int{0, constants.SecureBootStatePCR},\n\t\t\texpectedPubKeyPCRs:    []int{constants.UKIPCR},\n\t\t\texpectedLockedToState: true,\n\t\t},\n\t} {\n\t\tsuite.T().Logf(\"applying encryption keys %s on node %s\", toJSONString(suite.T(), test.keys), node)\n\n\t\t// prepare a patch to apply, first removing existing keys\n\t\tremoveKeysPatch := map[string]any{\n\t\t\t\"apiVersion\": \"v1alpha1\",\n\t\t\t\"kind\":       \"VolumeConfig\",\n\t\t\t\"name\":       constants.EphemeralPartitionLabel,\n\t\t\t\"encryption\": map[string]any{\n\t\t\t\t\"keys\": map[string]any{\n\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tnewEphemeralCfg := blockcfg.NewVolumeConfigV1Alpha1()\n\t\tnewEphemeralCfg.MetaName = constants.EphemeralPartitionLabel\n\t\tnewEphemeralCfg.EncryptionSpec.EncryptionKeys = test.keys\n\n\t\t// right now, patching encryption keys doesn't reboot and doesn't rotate the secrets either\n\t\tsuite.PatchMachineConfig(nodeCtx, removeKeysPatch, newEphemeralCfg)\n\n\t\tsuite.AssertRebooted(\n\t\t\tsuite.ctx, node,\n\t\t\tfunc(nodeCtx context.Context) error {\n\t\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t\t}, assertRebootedRebootTimeout,\n\t\t\tsuite.CleanupFailedPods,\n\t\t)\n\n\t\tsuite.ClearConnectionRefused(suite.ctx, node)\n\n\t\tsuite.WaitForBootDone(suite.ctx)\n\n\t\trtestutils.AssertResource(nodeCtx, suite.T(), suite.Client.COSI, constants.EphemeralPartitionLabel, func(r *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equal(test.expectedPCRs, r.TypedSpec().TPMEncryptionOptions.PCRs)\n\t\t\tasrt.Equal(test.expectedPubKeyPCRs, r.TypedSpec().TPMEncryptionOptions.PubKeyPCRs)\n\t\t\tasrt.Equal(test.expectedLockedToState, r.TypedSpec().EncryptionLockedToState)\n\t\t})\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &TrustedBootSuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/uki.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// UKISuite verifies Talos is booted from a UKI.\ntype UKISuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *UKISuite) SuiteName() string {\n\treturn \"api.UKISuite\"\n}\n\n// SetupTest sets up the test.\nfunc (suite *UKISuite) SetupTest() {\n\tif suite.Cluster != nil && suite.Cluster.Provisioner() == base.ProvisionerDocker {\n\t\tsuite.T().Skip(\"skipping uki booted test since docker provisioner does not support UKI\")\n\t}\n\n\tif !suite.VerifyUKIBooted {\n\t\tsuite.T().Skip(\"skipping uki booted test since talos.verifyukibooted is false\")\n\t}\n\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 3*time.Minute)\n}\n\n// TearDownTest tears down the test.\nfunc (suite *UKISuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestUKIBooted verifies that the system is booted from a UKI.\nfunc (suite *UKISuite) TestUKIBooted() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\tctx := client.WithNode(suite.ctx, node)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{runtimeres.SecurityStateID},\n\t\tfunc(r *runtimeres.SecurityState, asrt *assert.Assertions) {\n\t\t\tasrt.True(r.TypedSpec().BootedWithUKI)\n\t\t},\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, &UKISuite{})\n}\n"
  },
  {
    "path": "internal/integration/api/update-hostname.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// UpdateHostnameSuite verifies UpdateHostname API.\ntype UpdateHostnameSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *UpdateHostnameSuite) SuiteName() string {\n\treturn \"api.UpdateHostnameSuite\"\n}\n\n// SetupTest ...\nfunc (suite *UpdateHostnameSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *UpdateHostnameSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestUpdateHostname updates the hostname of a worker node,\n// then asserts that the node re-joins the cluster with the new hostname.\n// It reverts the change at the end of the test and asserts that the node is reported again as Ready.\nfunc (suite *UpdateHostnameSuite) TestUpdateHostname() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif !suite.Capabilities().SupportsReboot {\n\t\tsuite.T().Skip(\"cluster doesn't support reboot\")\n\t}\n\n\tnodeInternalIP := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeCtx := client.WithNode(suite.ctx, nodeInternalIP)\n\n\tnode, err := suite.GetK8sNodeByInternalIP(suite.ctx, nodeInternalIP)\n\tsuite.Require().NoError(err)\n\n\t// ec2.internal and compute.internal are reserved domains in AWS\n\t// ref: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html#instance-naming-ipbn\n\tif strings.HasSuffix(node.Name, \".ec2.internal\") || strings.HasSuffix(node.Name, \".compute.internal\") {\n\t\tsuite.T().Skip(\"aws does not support hostname changes\")\n\t}\n\n\toldHostname := node.Name\n\n\tnewHostname := \"test-update-hostname\"\n\n\tsuite.T().Logf(\"updating hostname of node %q to %q (IP: %s)\", oldHostname, newHostname, nodeInternalIP)\n\n\tsuite.updateHostname(nodeCtx, newHostname)\n\tsuite.ClearConnectionRefused(suite.ctx, nodeInternalIP)\n\n\tnodeReady := func(status corev1.ConditionStatus) bool {\n\t\treturn status == corev1.ConditionTrue\n\t}\n\n\tnodeNotReady := func(status corev1.ConditionStatus) bool {\n\t\treturn status != corev1.ConditionTrue\n\t}\n\n\tdefer func() {\n\t\tsuite.T().Logf(\"reverting hostname of node %q to %q (IP: %s)\", newHostname, oldHostname, nodeInternalIP)\n\n\t\t// revert the hostname back to the original one\n\t\tsuite.updateHostname(nodeCtx, oldHostname)\n\n\t\tsuite.T().Logf(\"waiting for node %q to be ready\", oldHostname)\n\n\t\t// expect node status to be Ready again\n\t\tsuite.Assert().NoError(suite.WaitForK8sNodeReadinessStatus(suite.ctx, oldHostname, nodeReady))\n\n\t\tsuite.T().Logf(\"deleting node %q\", newHostname)\n\n\t\t// Delete the node with the test hostname\n\t\terr = suite.Clientset.CoreV1().Nodes().Delete(suite.ctx, newHostname, metav1.DeleteOptions{})\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.T().Logf(\"rebooting node %s\", nodeInternalIP)\n\n\t\t// Reboot node for CNI bridge to be reconfigured: https://stackoverflow.com/questions/61373366\n\t\tsuite.AssertRebooted(\n\t\t\tsuite.ctx, nodeInternalIP, func(nodeCtx context.Context) error {\n\t\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t\t}, 10*time.Minute,\n\t\t\tsuite.CleanupFailedPods,\n\t\t)\n\t}()\n\n\tsuite.T().Logf(\"waiting for node %q to be not ready\", oldHostname)\n\n\t// expect node with old hostname to become NotReady\n\tsuite.Assert().NoError(suite.WaitForK8sNodeReadinessStatus(suite.ctx, oldHostname, nodeNotReady))\n\n\tsuite.T().Logf(\"waiting for node %q to be ready\", newHostname)\n\n\t// expect node with new hostname to become Ready\n\tsuite.Assert().NoError(suite.WaitForK8sNodeReadinessStatus(suite.ctx, newHostname, nodeReady))\n\n\tsuite.T().Logf(\"deleting node %q\", oldHostname)\n\n\t// Delete the node with the old hostname\n\terr = suite.Clientset.CoreV1().Nodes().Delete(suite.ctx, oldHostname, metav1.DeleteOptions{})\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *UpdateHostnameSuite) updateHostname(nodeCtx context.Context, newHostname string) {\n\thostnameConfig := network.NewHostnameConfigV1Alpha1()\n\thostnameConfig.ConfigAuto = new(nethelpers.AutoHostnameKindOff)\n\thostnameConfig.ConfigHostname = newHostname\n\n\tsuite.PatchMachineConfig(nodeCtx, hostnameConfig)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(UpdateHostnameSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tconfigmachine \"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// VersionSuite verifies version API.\ntype VersionSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *VersionSuite) SuiteName() string {\n\treturn \"api.VersionSuite\"\n}\n\n// SetupTest ...\nfunc (suite *VersionSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *VersionSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestExpectedVersionMaster verifies master node version matches expected.\nfunc (suite *VersionSuite) TestExpectedVersionMaster() {\n\tv, err := suite.Client.Version(suite.ctx)\n\tsuite.Require().NoError(err)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(configmachine.TypeControlPlane)\n\n\tclientCtx := client.WithNode(suite.ctx, node)\n\tversion, err := safe.StateGetByID[*runtime.Version](clientCtx, suite.Client.COSI, \"version\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotNil(version)\n\n\tsuite.Assert().Equal(v.Messages[0].Version.Tag, version.TypedSpec().Version)\n\n\tsuite.Assert().Equal(suite.Version, v.Messages[0].Version.Tag)\n\tsuite.Assert().Equal(suite.GoVersion, v.Messages[0].Version.GoVersion)\n}\n\n// TestSameVersionCluster verifies that all the nodes are on the same version.\nfunc (suite *VersionSuite) TestSameVersionCluster() {\n\tnodes := suite.DiscoverNodeInternalIPs(suite.ctx)\n\tsuite.Require().NotEmpty(nodes)\n\n\tctx := client.WithNodes(suite.ctx, nodes...)\n\n\tvar v *machine.VersionResponse\n\n\terr := retry.Constant(\n\t\ttime.Minute,\n\t).Retry(func() error {\n\t\tvar e error\n\n\t\tv, e = suite.Client.Version(ctx)\n\n\t\treturn retry.ExpectedError(e)\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Len(v.Messages, len(nodes))\n\n\texpectedVersion := v.Messages[0].Version.Tag\n\n\tfor _, version := range v.Messages {\n\t\tsuite.Assert().Equal(expectedVersion, version.Version.Tag)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(VersionSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/volumes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tblockcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumesSuite ...\ntype VolumesSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *VolumesSuite) SuiteName() string {\n\treturn \"api.VolumesSuite\"\n}\n\n// SetupTest ...\nfunc (suite *VolumesSuite) SetupTest() {\n\tif !suite.Capabilities().SupportsVolumes {\n\t\tsuite.T().Skip(\"cluster doesn't support volumes\")\n\t}\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 2*time.Minute)\n}\n\n// TearDownTest ...\nfunc (suite *VolumesSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestDiscoveredVolumes verifies that standard Talos partitions are discovered.\nfunc (suite *VolumesSuite) TestDiscoveredVolumes() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tsuite.testDiscoveredVolumes(node)\n\t\t})\n\t}\n}\n\nfunc (suite *VolumesSuite) testDiscoveredVolumes(node string) {\n\tctx := client.WithNode(suite.ctx, node)\n\n\tvolumes, err := safe.StateListAll[*block.DiscoveredVolume](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\texpectedVolumes := map[string]struct {\n\t\tNames []string\n\t}{\n\t\t\"META\": {\n\t\t\tNames: []string{\"talosmeta\", \"\"}, // if META was never written, it will not be detected\n\t\t},\n\t\t\"STATE\": {\n\t\t\tNames: []string{\"xfs\"},\n\t\t},\n\t\t\"EPHEMERAL\": {\n\t\t\tNames: []string{\"xfs\"},\n\t\t},\n\t}\n\n\tfor dv := range volumes.All() {\n\t\tsuite.T().Logf(\"volume: %s %s %s %s\", dv.Metadata().ID(), dv.TypedSpec().Name, dv.TypedSpec().PartitionLabel, dv.TypedSpec().Label)\n\n\t\tpartitionLabel := dv.TypedSpec().PartitionLabel\n\t\tfilesystemLabel := dv.TypedSpec().Label\n\n\t\t// this is encrypted partition, skip it, we should see another device with the actual filesystem\n\t\tif dv.TypedSpec().Name == \"luks\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// match either by partition or filesystem label\n\t\tid := partitionLabel\n\n\t\texpected, ok := expectedVolumes[id]\n\t\tif !ok {\n\t\t\tid = filesystemLabel\n\n\t\t\texpected, ok = expectedVolumes[id]\n\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tsuite.Assert().Contains(expected.Names, dv.TypedSpec().Name, \"node: %s\", node)\n\n\t\tdelete(expectedVolumes, id)\n\t}\n\n\tsuite.Assert().Empty(expectedVolumes, \"node: \", node)\n\n\tif suite.T().Failed() {\n\t\tsuite.DumpLogs(suite.ctx, node, \"controller-runtime\", \"block.\")\n\t}\n}\n\n// TestSystemDisk verifies that Talos system disk is discovered.\nfunc (suite *VolumesSuite) TestSystemDisk() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\tsystemDisk, err := safe.StateGetByID[*block.SystemDisk](ctx, suite.Client.COSI, block.SystemDiskID)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tsuite.Assert().NotEmpty(systemDisk.TypedSpec().DiskID)\n\n\t\t\tsuite.T().Logf(\"system disk: %s\", systemDisk.TypedSpec().DiskID)\n\t\t})\n\t}\n}\n\n// TestDisks verifies that Talos discovers disks.\nfunc (suite *VolumesSuite) TestDisks() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\tdisks, err := safe.StateListAll[*block.Disk](ctx, suite.Client.COSI)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\t// there should be at least two disks - loop0 for Talos squashfs and a system disk\n\t\t\tsuite.Assert().Greater(disks.Len(), 1)\n\n\t\t\tvar diskNames []string\n\n\t\t\tfor disk := range disks.All() {\n\t\t\t\tif disk.TypedSpec().Readonly {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif !disk.TypedSpec().CDROM {\n\t\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().Size, \"disk: %s\", disk.Metadata().ID())\n\t\t\t\t}\n\n\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().Symlinks, \"disk: %s\", disk.Metadata().ID())\n\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().IOSize, \"disk: %s\", disk.Metadata().ID())\n\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().SectorSize, \"disk: %s\", disk.Metadata().ID())\n\n\t\t\t\tif suite.Cluster != nil {\n\t\t\t\t\t// running on our own provider, transport should be always detected\n\t\t\t\t\tif disk.TypedSpec().BusPath == \"/virtual\" {\n\t\t\t\t\t\tsuite.Assert().Empty(disk.TypedSpec().Transport, \"disk: %s\", disk.Metadata().ID())\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().Transport, \"disk: %s\", disk.Metadata().ID())\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif strings.HasPrefix(disk.Metadata().ID(), \"dm-\") {\n\t\t\t\t\t// devicemapper disks should have secondaries\n\t\t\t\t\tsuite.Assert().NotEmpty(disk.TypedSpec().SecondaryDisks, \"disk: %s\", disk.Metadata().ID())\n\n\t\t\t\t\tsuite.T().Logf(\"disk: %s secondaries: %v\", disk.Metadata().ID(), disk.TypedSpec().SecondaryDisks)\n\t\t\t\t}\n\n\t\t\t\tdiskNames = append(diskNames, disk.Metadata().ID())\n\t\t\t}\n\n\t\t\tsuite.T().Logf(\"disks: %v\", diskNames)\n\t\t})\n\t}\n}\n\n// TestLVMActivation verifies that LVM volume group is activated after reboot.\nfunc (suite *VolumesSuite) TestLVMActivation() {\n\tif suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping tests with nsenter in SELinux enforcing mode\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 2 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tuserDisksJoined := strings.Join(userDisks[:2], \" \")\n\n\tsuite.T().Logf(\"creating LVM volume group on node %s/%s with disks %s\", node, nodeName, userDisksJoined)\n\n\tpodDef, err := suite.NewPrivilegedPod(\"pv-create\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\tstdout, _, err := podDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- vgcreate --nolocking vg0 %s\", userDisksJoined),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(stdout, \"Volume group \\\"vg0\\\" successfully created\")\n\n\tstdout, _, err = podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"nsenter --mount=/proc/1/ns/mnt -- lvcreate --mirrors=1 --type=raid1 --nosync -n lv0 -L 1G vg0\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(stdout, \"Logical volume \\\"lv0\\\" created.\")\n\n\tstdout, _, err = podDef.Exec(\n\t\tsuite.ctx,\n\t\t\"nsenter --mount=/proc/1/ns/mnt -- lvcreate -n lv1 -L 1G vg0\",\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Contains(stdout, \"Logical volume \\\"lv1\\\" created.\")\n\n\tdefer suite.deleteLVMVolumes(node, nodeName, userDisksJoined)\n\n\tsuite.T().Logf(\"rebooting node %s/%s\", node, nodeName)\n\n\t// now we want to reboot the node and make sure the array is still mounted\n\tsuite.AssertRebooted(\n\t\tsuite.ctx, node, func(nodeCtx context.Context) error {\n\t\t\treturn base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))\n\t\t}, 5*time.Minute,\n\t\tsuite.CleanupFailedPods,\n\t)\n\n\tsuite.T().Logf(\"verifying LVM activation %s/%s\", node, nodeName)\n\n\tsuite.Require().Eventually(func() bool {\n\t\treturn suite.lvmVolumeExists(node, []string{\"lv0\", \"lv1\"})\n\t}, 5*time.Second, 1*time.Second, \"LVM volume group was not activated after reboot\")\n}\n\nfunc (suite *VolumesSuite) deleteLVMVolumes(node, nodeName, userDisksJoined string) {\n\tsuite.T().Logf(\"removing LVM volumes %s/%s\", node, nodeName)\n\n\tdeletePodDef, err := suite.NewPrivilegedPod(\"pv-destroy\")\n\tsuite.Require().NoError(err)\n\n\tdeletePodDef = deletePodDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(deletePodDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer deletePodDef.Delete(suite.ctx) //nolint:errcheck\n\n\tif _, _, err := deletePodDef.Exec(\n\t\tsuite.ctx,\n\t\t\"nsenter --mount=/proc/1/ns/mnt -- vgremove --nolocking --yes vg0\",\n\t); err != nil {\n\t\tsuite.T().Logf(\"failed to remove pv vg0: %v\", err)\n\t}\n\n\tif _, _, err := deletePodDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- pvremove --nolocking --yes %s\", userDisksJoined),\n\t); err != nil {\n\t\tsuite.T().Logf(\"failed to remove pv backed by volumes %s: %v\", userDisksJoined, err)\n\t}\n}\n\nfunc (suite *VolumesSuite) lvmVolumeExists(node string, expectedVolumes []string) bool {\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisks, err := safe.StateListAll[*block.Disk](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tfoundVolumes := xslices.ToSet(expectedVolumes)\n\n\t// device-mapper volumes will have udevd-created symlinks which contain volume name\n\tfor disk := range disks.All() {\n\t\tif strings.HasPrefix(disk.TypedSpec().DevPath, \"/dev/dm\") {\n\t\t\tfor _, volumeName := range expectedVolumes {\n\t\t\t\tfor _, symlink := range disk.TypedSpec().Symlinks {\n\t\t\t\t\tif strings.Contains(symlink, volumeName) {\n\t\t\t\t\t\tfoundVolumes[volumeName] = struct{}{}\n\n\t\t\t\t\t\tsuite.T().Logf(\"found LVM volume %s as disk %s with symlink %s\", volumeName, disk.Metadata().ID(), symlink)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn len(foundVolumes) == len(expectedVolumes)\n}\n\n// TestSymlinks that Talos can update disk symlinks on the fly.\nfunc (suite *VolumesSuite) TestSymlinks() {\n\tif suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping tests with nsenter in SELinux enforcing mode\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tuserDisk := userDisks[0]\n\tuserDiskName := filepath.Base(userDisk)\n\n\tsuite.T().Logf(\"performing a symlink test %s on %s/%s with disk %s\", userDisk, node, nodeName, userDiskName)\n\n\tpodDef, err := suite.NewPrivilegedPod(\"xfs-format\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\tfsUUID := uuid.New().String()\n\n\t_, _, err = podDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- mkfs.xfs -m uuid=%s %s\", fsUUID, userDisk),\n\t)\n\tsuite.Require().NoError(err)\n\n\texpectedSymlink := \"/dev/disk/by-uuid/\" + fsUUID\n\n\t// Talos should report a symlink to the disk via FS UUID\n\t_, err = suite.Client.COSI.WatchFor(client.WithNode(suite.ctx, node), block.NewDisk(block.NamespaceName, userDiskName).Metadata(),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tdisk, ok := r.(*block.Disk)\n\t\t\tif !ok {\n\t\t\t\treturn false, fmt.Errorf(\"unexpected resource type: %T\", r)\n\t\t\t}\n\n\t\t\treturn slices.Index(disk.TypedSpec().Symlinks, expectedSymlink) != -1, nil\n\t\t}),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"wiping user disk %s on %s/%s\", userDisk, node, nodeName)\n\n\tsuite.Require().NoError(suite.Client.BlockDeviceWipe(client.WithNode(suite.ctx, node), &storage.BlockDeviceWipeRequest{\n\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t{\n\t\t\t\tDevice: userDiskName,\n\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t},\n\t\t},\n\t}))\n\n\t// Talos should remove a symlink to the disk\n\t_, err = suite.Client.COSI.WatchFor(client.WithNode(suite.ctx, node), block.NewDisk(block.NamespaceName, userDiskName).Metadata(),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tdisk, ok := r.(*block.Disk)\n\t\t\tif !ok {\n\t\t\t\treturn false, fmt.Errorf(\"unexpected resource type: %T\", r)\n\t\t\t}\n\n\t\t\treturn slices.Index(disk.TypedSpec().Symlinks, expectedSymlink) == -1, nil\n\t\t}),\n\t)\n\tsuite.Require().NoError(err)\n}\n\n// TestUserVolumesStatus verifies that existing user volumes were provisioned successfully.\nfunc (suite *VolumesSuite) TestUserVolumesStatus() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\tuserVolumeIDs := rtestutils.ResourceIDs[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, state.WithLabelQuery(resource.LabelExists(block.UserVolumeLabel)))\n\n\t\t\t// check that the volumes are ready\n\t\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\tuserVolumeIDs,\n\t\t\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif len(userVolumeIDs) > 0 {\n\t\t\t\tsuite.T().Logf(\"found %d user volumes\", len(userVolumeIDs))\n\t\t\t}\n\n\t\t\t// check that the volumes are mounted\n\t\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\tuserVolumeIDs,\n\t\t\t\tfunc(vs *block.MountStatus, _ *assert.Assertions) {},\n\t\t\t)\n\t\t})\n\t}\n}\n\n// TestVolumesStatus verifies that all volumes are either ready or missing.\nfunc (suite *VolumesSuite) TestVolumesStatus() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\trtestutils.AssertAll(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\t\t\tasrt.Contains([]block.VolumePhase{block.VolumePhaseReady, block.VolumePhaseMissing}, vs.TypedSpec().Phase)\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t}\n}\n\n// TestUserVolumesPartition performs a series of operations on user volumes: creating, destroying, verifying, etc.\nfunc (suite *VolumesSuite) TestUserVolumesPartition() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tsuite.T().Logf(\"verifying user volumes on node %s/%s with disk %s\", node, nodeName, userDisks[0])\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisk, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\tsuite.Require().NoError(err)\n\n\tvolumeName := fmt.Sprintf(\"%04x\", rand.Int31()) + \"-\"\n\n\tconst numVolumes = 3\n\n\tvolumeIDs := make([]string, numVolumes)\n\n\tfor i := range numVolumes {\n\t\tvolumeIDs[i] = volumeName + strconv.Itoa(i)\n\t}\n\n\tuserVolumeIDs := xslices.Map(volumeIDs, func(volumeID string) string { return constants.UserVolumePrefix + volumeID })\n\n\tconfigDocs := xslices.Map(volumeIDs[:1], func(volumeID string) any {\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t\t)\n\t\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\t\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"1GiB\")\n\n\t\treturn doc\n\t})\n\n\tconfigDocs = append(configDocs, xslices.Map(volumeIDs[1:2], func(volumeID string) any {\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t\t)\n\t\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\t\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"-60%\")\n\n\t\treturn doc\n\t})...)\n\n\tconfigDocs = append(configDocs, xslices.Map(volumeIDs[2:], func(volumeID string) any {\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t\t)\n\t\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\t\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"20%\")\n\n\t\treturn doc\n\t})...)\n\n\tsuite.Require().Equal(len(configDocs), len(volumeIDs))\n\n\t// create user volumes\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// check that the volumes are mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.MountStatus, _ *assert.Assertions) {})\n\n\t// create a pod using user volumes\n\tpodDef, err := suite.NewPod(\"user-volume-test\")\n\tsuite.Require().NoError(err)\n\n\t// using subdirectory here to test that the hostPath mount is properly propagated into the kubelet\n\tpodDef = podDef.WithNodeName(nodeName).\n\t\tWithNamespace(\"kube-system\").\n\t\tWithHostVolumeMount(filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\"), \"/mnt/data\")\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 1*time.Minute))\n\n\t_, _, err = podDef.Exec(suite.ctx, \"mkdir -p /mnt/data/test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(podDef.Delete(suite.ctx))\n\n\t// verify that directory exists\n\texpectedPath := filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\", \"test\")\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  expectedPath,\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, _ string, _ bool) error {\n\t\tsuite.T().Logf(\"found %s on node %s\", info.Name, node)\n\t\tsuite.Require().Equal(expectedPath, info.Name, \"expected %s to exist\", expectedPath)\n\n\t\treturn nil\n\t}))\n\n\t// verify that volume labels are set properly\n\texpectedLabels := xslices.ToSet(userVolumeIDs)\n\n\tdvs, err := safe.StateListAll[*block.DiscoveredVolume](ctx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tfor dv := range dvs.All() {\n\t\tdelete(expectedLabels, dv.TypedSpec().PartitionLabel)\n\t}\n\n\tsuite.Require().Empty(expectedLabels, \"expected labels %v to be set on discovered volumes\", expectedLabels)\n\n\t// test disableAccessTime mount option\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountDisableAccessTime = new(true)\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountSecure = new(false)\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{userVolumeIDs[0]},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().Spec.Secure, \"expected Secure to be false\")\n\t\t\tasrt.True(vs.TypedSpec().Spec.DisableAccessTime, \"expected DisableAccessTime to be true\")\n\t\t})\n\n\t// test secure mount option\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountDisableAccessTime = new(false)\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountSecure = new(true)\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{userVolumeIDs[0]},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().Spec.DisableAccessTime, \"expected DisableAccessTime to be false\")\n\t\t\tasrt.True(vs.TypedSpec().Spec.Secure, \"expected Secure to be true\")\n\t\t})\n\n\t// now, remove one of the volumes, wipe the partition and re-create the volume\n\tvs, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, suite.Client.COSI, userVolumeIDs[0])\n\tsuite.Require().NoError(err)\n\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs[0])\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeIDs[0])\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice:        filepath.Base(vs.TypedSpec().Location),\n\t\t\t\t\tMethod:        storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t\tDropPartition: true,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe partition %s\", vs.TypedSpec().Location)\n\n\t// wait for the discovered volume to disappear\n\trtestutils.AssertNoResource[*block.DiscoveredVolume](ctx, suite.T(), suite.Client.COSI, filepath.Base(vs.TypedSpec().Location))\n\n\t// re-create the volume with project quota support\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).FilesystemSpec.ProjectQuotaSupportConfig = new(true)\n\tsuite.PatchMachineConfig(ctx, configDocs[0])\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tif vs.Metadata().ID() == userVolumeIDs[0] {\n\t\t\t\t// check that the project quota support is enabled\n\t\t\t\tasrt.True(vs.TypedSpec().ProjectQuotaSupport, \"project quota support should be enabled for %s\", vs.Metadata().ID())\n\t\t\t} else {\n\t\t\t\t// check that the project quota support is disabled\n\t\t\t\tasrt.False(vs.TypedSpec().ProjectQuotaSupport, \"project quota support should be disabled for %s\", vs.Metadata().ID())\n\t\t\t}\n\t\t})\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs...)\n\n\tfor _, userVolumeID := range userVolumeIDs {\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\t}\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice: filepath.Base(userDisks[0]),\n\t\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe disk %s\", userDisks[0])\n\n\t// wait for the discovered volume reflect wiped status\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(userDisks[0]),\n\t\tfunc(dv *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(dv.TypedSpec().Name, \"expected discovered volume %s to be wiped\", dv.Metadata().ID())\n\t\t})\n}\n\n// TestUserVolumesDisk performs a series of operations on user volumes: creating, destroying, verifying, etc.\nfunc (suite *VolumesSuite) TestUserVolumesDisk() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tsuite.T().Logf(\"verifying user volumes on node %s/%s with disk %s\", node, nodeName, userDisks[0])\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisk, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\tsuite.Require().NoError(err)\n\n\tvolumeName := fmt.Sprintf(\"%04x\", rand.Int31()) + \"-\"\n\n\tconst numVolumes = 1\n\n\tvolumeIDs := make([]string, numVolumes)\n\n\tfor i := range numVolumes {\n\t\tvolumeIDs[i] = volumeName + strconv.Itoa(i)\n\t}\n\n\tuserVolumeIDs := xslices.Map(volumeIDs, func(volumeID string) string { return constants.UserVolumePrefix + volumeID })\n\n\tconfigDocs := xslices.Map(volumeIDs, func(volumeID string) any {\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.VolumeType = new(block.VolumeTypeDisk)\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t\t)\n\n\t\treturn doc\n\t})\n\n\t// create user volumes\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// check that the volumes are mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.MountStatus, _ *assert.Assertions) {})\n\n\t// create a pod using user volumes\n\tpodDef, err := suite.NewPod(\"user-volume-test\")\n\tsuite.Require().NoError(err)\n\n\t// using subdirectory here to test that the hostPath mount is properly propagated into the kubelet\n\tpodDef = podDef.WithNodeName(nodeName).\n\t\tWithNamespace(\"kube-system\").\n\t\tWithHostVolumeMount(filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\"), \"/mnt/data\")\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 1*time.Minute))\n\n\t_, _, err = podDef.Exec(suite.ctx, \"mkdir -p /mnt/data/test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(podDef.Delete(suite.ctx))\n\n\t// verify that directory exists\n\texpectedPath := filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\", \"test\")\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  expectedPath,\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, _ string, _ bool) error {\n\t\tsuite.T().Logf(\"found %s on node %s\", info.Name, node)\n\t\tsuite.Require().Equal(expectedPath, info.Name, \"expected %s to exist\", expectedPath)\n\n\t\treturn nil\n\t}))\n\n\t// test disableAccessTime mount option\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountDisableAccessTime = new(true)\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountSecure = new(false)\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{userVolumeIDs[0]},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().Spec.Secure, \"expected Secure to be false\")\n\t\t\tasrt.True(vs.TypedSpec().Spec.DisableAccessTime, \"expected DisableAccessTime to be true\")\n\t\t})\n\n\t// test secure mount option\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountDisableAccessTime = new(false)\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).MountSpec.MountSecure = new(true)\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{userVolumeIDs[0]},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().Spec.DisableAccessTime, \"expected DisableAccessTime to be false\")\n\t\t\tasrt.True(vs.TypedSpec().Spec.Secure, \"expected Secure to be true\")\n\t\t})\n\n\t// now, remove one of the volumes, wipe the partition and re-create the volume\n\tvs, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, suite.Client.COSI, userVolumeIDs[0])\n\tsuite.Require().NoError(err)\n\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs[0])\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeIDs[0])\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice:        filepath.Base(vs.TypedSpec().Location),\n\t\t\t\t\tMethod:        storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t\tDropPartition: true,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe partition %s\", vs.TypedSpec().Location)\n\n\t// wait for the discovered volume to lose filesystem\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(vs.TypedSpec().Location), func(r *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\tasrt.Empty(r.TypedSpec().Name) // no filesystem\n\t})\n\n\t// re-create the volume with project quota support\n\tconfigDocs[0].(*blockcfg.UserVolumeConfigV1Alpha1).FilesystemSpec.ProjectQuotaSupportConfig = new(true)\n\tsuite.PatchMachineConfig(ctx, configDocs[0])\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tif vs.Metadata().ID() == userVolumeIDs[0] {\n\t\t\t\t// check that the project quota support is enabled\n\t\t\t\tasrt.True(vs.TypedSpec().ProjectQuotaSupport, \"project quota support should be enabled for %s\", vs.Metadata().ID())\n\t\t\t} else {\n\t\t\t\t// check that the project quota support is disabled\n\t\t\t\tasrt.False(vs.TypedSpec().ProjectQuotaSupport, \"project quota support should be disabled for %s\", vs.Metadata().ID())\n\t\t\t}\n\t\t})\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs...)\n\n\tfor _, userVolumeID := range userVolumeIDs {\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\t}\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice: filepath.Base(userDisks[0]),\n\t\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe disk %s\", userDisks[0])\n\n\t// wait for the discovered volume reflect wiped status\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(userDisks[0]),\n\t\tfunc(dv *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(dv.TypedSpec().Name, \"expected discovered volume %s to be wiped\", dv.Metadata().ID())\n\t\t})\n}\n\n// TestUserVolumesDirectory performs a series of operations on user volumes: creating, destroying, verifying, etc.\nfunc (suite *VolumesSuite) TestUserVolumesDirectory() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tvolumeName := fmt.Sprintf(\"%04x\", rand.Int31()) + \"-\"\n\n\tconst numVolumes = 3\n\n\tvolumeIDs := make([]string, numVolumes)\n\n\tfor i := range numVolumes {\n\t\tvolumeIDs[i] = volumeName + strconv.Itoa(i)\n\t}\n\n\tuserVolumeIDs := xslices.Map(volumeIDs, func(volumeID string) string { return constants.UserVolumePrefix + volumeID })\n\n\tconfigDocs := xslices.Map(volumeIDs, func(volumeID string) any {\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.VolumeType = new(block.VolumeTypeDirectory)\n\n\t\treturn doc\n\t})\n\n\t// create user volumes\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// check that the volumes are mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.MountStatus, _ *assert.Assertions) {})\n\n\t// create a pod using user volumes\n\tpodDef, err := suite.NewPod(\"user-volume-test\")\n\tsuite.Require().NoError(err)\n\n\t// using subdirectory here to test that the hostPath mount is properly propagated into the kubelet\n\tpodDef = podDef.WithNodeName(nodeName).\n\t\tWithNamespace(\"kube-system\").\n\t\tWithHostVolumeMount(filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\"), \"/mnt/data\")\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 1*time.Minute))\n\n\t_, _, err = podDef.Exec(suite.ctx, \"mkdir -p /mnt/data/test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(podDef.Delete(suite.ctx))\n\n\t// verify that directory exists\n\texpectedPath := filepath.Join(constants.UserVolumeMountPoint, volumeIDs[0], \"data\", \"test\")\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  expectedPath,\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, _ string, _ bool) error {\n\t\tsuite.T().Logf(\"found %s on node %s\", info.Name, node)\n\t\tsuite.Require().Equal(expectedPath, info.Name, \"expected %s to exist\", expectedPath)\n\n\t\treturn nil\n\t}))\n\n\t// now, remove one of the volumes and re-create the volume\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs[0])\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeIDs[0])\n\n\t// re-create the volume\n\tsuite.PatchMachineConfig(ctx, configDocs[0])\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, userVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeIDs...)\n\n\tfor _, userVolumeID := range userVolumeIDs {\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\t}\n}\n\n// TestRawVolumes performs a series of operations on raw volumes: creating, destroying, etc.\nfunc (suite *VolumesSuite) TestRawVolumes() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tsuite.T().Logf(\"verifying raw volumes on node %s/%s with disk %s\", node, nodeName, userDisks[0])\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisk, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\tsuite.Require().NoError(err)\n\n\tvolumeName := fmt.Sprintf(\"%04x\", rand.Int31()) + \"-\"\n\n\tconst numVolumes = 2\n\n\tvolumeIDs := make([]string, numVolumes)\n\n\tfor i := range numVolumes {\n\t\tvolumeIDs[i] = volumeName + strconv.Itoa(i)\n\t}\n\n\trawVolumeIDs := xslices.Map(volumeIDs, func(volumeID string) string { return constants.RawVolumePrefix + volumeID })\n\n\tconfigDocs := xslices.Map(volumeIDs, func(volumeID string) any {\n\t\tdoc := blockcfg.NewRawVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t\t)\n\t\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\t\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"500MiB\")\n\n\t\treturn doc\n\t})\n\n\t// create raw volumes\n\tsuite.PatchMachineConfig(ctx, configDocs...)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, rawVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// verify that volume labels are set properly\n\tfor _, rawVolumeID := range rawVolumeIDs {\n\t\tvs, err := safe.StateGetByID[*block.VolumeStatus](ctx, suite.Client.COSI, rawVolumeID)\n\t\tsuite.Require().NoError(err)\n\n\t\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(vs.TypedSpec().Location),\n\t\t\tfunc(dv *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(vs.Metadata().ID(), dv.TypedSpec().PartitionLabel, \"expected discovered volume %s to have label %s\", dv.Metadata().ID(), vs.Metadata().ID())\n\t\t\t})\n\t}\n\n\t// now, remove one of the volumes, wipe the partition and re-create the volume\n\tvs, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, suite.Client.COSI, rawVolumeIDs[0])\n\tsuite.Require().NoError(err)\n\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.RawVolumeConfigKind, volumeIDs[0])\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, rawVolumeIDs[0])\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice:        filepath.Base(vs.TypedSpec().Location),\n\t\t\t\t\tMethod:        storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t\tDropPartition: true,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe partition %s\", vs.TypedSpec().Location)\n\n\t// wait for the discovered volume to disappear\n\trtestutils.AssertNoResource[*block.DiscoveredVolume](ctx, suite.T(), suite.Client.COSI, filepath.Base(vs.TypedSpec().Location))\n\n\t// re-create the volume\n\tsuite.PatchMachineConfig(ctx, configDocs[0])\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, rawVolumeIDs,\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.RawVolumeConfigKind, volumeIDs...)\n\n\tfor _, rawVolumeID := range rawVolumeIDs {\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, rawVolumeID)\n\t}\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice: filepath.Base(userDisks[0]),\n\t\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe disk %s\", userDisks[0])\n\n\t// wait for the discovered volume reflect wiped status\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(userDisks[0]),\n\t\tfunc(dv *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(dv.TypedSpec().Name, \"expected discovered volume %s to be wiped\", dv.Metadata().ID())\n\t\t})\n}\n\n// TestExistingVolumes performs a series of operations on existing volumes: mount/unmount, etc.\n//\n//nolint:gocyclo\nfunc (suite *VolumesSuite) TestExistingVolumes() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tsuite.T().Logf(\"verifying existing volumes on node %s/%s with disk %s\", node, nodeName, userDisks[0])\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisk, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\tsuite.Require().NoError(err)\n\n\tvolumeID := fmt.Sprintf(\"%04x\", rand.Int31())\n\texistingVolumeID := constants.ExistingVolumePrefix + volumeID\n\n\t// first, create a user volume config to get the volume created\n\tuserVolumeID := constants.UserVolumePrefix + volumeID\n\n\tuserVolumeDoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\tuserVolumeDoc.MetaName = volumeID\n\tuserVolumeDoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t)\n\tuserVolumeDoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\tuserVolumeDoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"1GiB\")\n\n\t// create user volumes\n\tsuite.PatchMachineConfig(ctx, userVolumeDoc)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{userVolumeID},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// now destroy a user volume\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeID)\n\n\t// wait for the user volume to be removed\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\n\t// now, recreate the volume as an existing volume\n\texistingVolumeDoc := blockcfg.NewExistingVolumeConfigV1Alpha1()\n\texistingVolumeDoc.MetaName = volumeID\n\texistingVolumeDoc.VolumeDiscoverySpec.VolumeSelectorConfig.Match = cel.MustExpression(\n\t\tcel.ParseBooleanExpression(\n\t\t\tfmt.Sprintf(\"volume.partition_label == '%s' && '%s' in disk.symlinks\", userVolumeID, disk.TypedSpec().Symlinks[0]),\n\t\t\tcelenv.VolumeLocator(),\n\t\t),\n\t)\n\n\t// create existing volume\n\tsuite.PatchMachineConfig(ctx, existingVolumeDoc)\n\n\t// wait for the existing volume to be discovered\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{existingVolumeID},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t\tasrt.Equal(userDisks[0], vs.TypedSpec().ParentLocation)\n\t\t},\n\t)\n\n\t// check that the volume is mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{existingVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().ReadOnly)\n\t\t})\n\n\t// create a pod using existing volumes\n\tpodDef, err := suite.NewPod(\"existing-volume-test\")\n\tsuite.Require().NoError(err)\n\n\t// using subdirectory here to test that the hostPath mount is properly propagated into the kubelet\n\tpodDef = podDef.WithNodeName(nodeName).\n\t\tWithNamespace(\"kube-system\").\n\t\tWithHostVolumeMount(filepath.Join(constants.UserVolumeMountPoint, volumeID, \"data\"), \"/mnt/data\")\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 1*time.Minute))\n\n\t_, _, err = podDef.Exec(suite.ctx, \"mkdir -p /mnt/data/test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(podDef.Delete(suite.ctx))\n\n\t// verify that directory exists\n\texpectedPath := filepath.Join(constants.UserVolumeMountPoint, volumeID, \"data\", \"test\")\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  expectedPath,\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, _ string, _ bool) error {\n\t\tsuite.T().Logf(\"found %s on node %s\", info.Name, node)\n\t\tsuite.Require().Equal(expectedPath, info.Name, \"expected %s to exist\", expectedPath)\n\n\t\treturn nil\n\t}))\n\n\t// now, re-mount the existing volume as read-only\n\texistingVolumeDoc.MountSpec.MountReadOnly = new(true)\n\tsuite.PatchMachineConfig(ctx, existingVolumeDoc)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{existingVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vs.TypedSpec().ReadOnly)\n\t\t})\n\n\t// test disableAccessTime mount option\n\texistingVolumeDoc.MountSpec.MountReadOnly = nil\n\texistingVolumeDoc.MountSpec.MountDisableAccessTime = new(true)\n\texistingVolumeDoc.MountSpec.MountSecure = new(false)\n\tsuite.PatchMachineConfig(ctx, existingVolumeDoc)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{existingVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vs.TypedSpec().Spec.DisableAccessTime, \"expected DisableAccessTime to be true\")\n\t\t})\n\n\t// test secure mount option\n\texistingVolumeDoc.MountSpec.MountDisableAccessTime = new(false)\n\texistingVolumeDoc.MountSpec.MountSecure = new(true)\n\tsuite.PatchMachineConfig(ctx, existingVolumeDoc)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{existingVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vs.TypedSpec().Spec.Secure, \"expected Secure to be true\")\n\t\t})\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.ExistingVolumeConfigKind, volumeID)\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, existingVolumeID)\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice: filepath.Base(userDisks[0]),\n\t\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe disk %s\", userDisks[0])\n\n\t// wait for the discovered volume reflect wiped status\n\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI, filepath.Base(userDisks[0]),\n\t\tfunc(dv *block.DiscoveredVolume, asrt *assert.Assertions) {\n\t\t\tasrt.Empty(dv.TypedSpec().Name, \"expected discovered volume %s to be wiped\", dv.Metadata().ID())\n\t\t})\n}\n\n// TestExternalVolumesVirtiofs performs a series of operations on external virtiofs volumes: mount/unmount, etc.\nfunc (suite *VolumesSuite) TestExternalVolumesVirtiofs() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tif !suite.Virtiofsd {\n\t\tsuite.T().Skip(\"skipping test without virtiofsd running\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tvolumeID := fmt.Sprintf(\"%04x\", rand.Int31())\n\texternalVolumeID := constants.ExternalVolumePrefix + volumeID\n\n\t// create the volume as an external volume\n\texternalVolumeDoc := blockcfg.NewExternalVolumeConfigV1Alpha1()\n\texternalVolumeDoc.MetaName = volumeID\n\texternalVolumeDoc.FilesystemType = block.FilesystemTypeVirtiofs\n\texternalVolumeDoc.MountSpec = blockcfg.ExternalMountSpec{\n\t\tMountVirtiofs: &blockcfg.VirtiofsMountSpec{\n\t\t\tVirtiofsTag: \"disk0\",\n\t\t},\n\t}\n\n\t// create external volume\n\tsuite.PatchMachineConfig(ctx, externalVolumeDoc)\n\n\t// wait for the external volume to be discovered\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{externalVolumeID},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// check that the volume is mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{externalVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.False(vs.TypedSpec().ReadOnly)\n\t\t})\n\n\t// create a pod using external volumes\n\tpodDef, err := suite.NewPod(\"external-volume-virtiofs-test\")\n\tsuite.Require().NoError(err)\n\n\t// using subdirectory here to test that the hostPath mount is properly propagated into the kubelet\n\tpodDef = podDef.WithNodeName(nodeName).\n\t\tWithNamespace(\"kube-system\").\n\t\tWithHostVolumeMount(filepath.Join(constants.UserVolumeMountPoint, volumeID, \"data\"), \"/mnt/data\")\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 1*time.Minute))\n\n\t_, _, err = podDef.Exec(suite.ctx, \"mkdir -p /mnt/data/test\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(podDef.Delete(suite.ctx))\n\n\t// verify that directory exists\n\texpectedPath := filepath.Join(constants.UserVolumeMountPoint, volumeID, \"data\", \"test\")\n\n\tstream, err := suite.Client.LS(ctx, &machineapi.ListRequest{\n\t\tRoot:  expectedPath,\n\t\tTypes: []machineapi.ListRequest_Type{machineapi.ListRequest_DIRECTORY},\n\t})\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, _ string, _ bool) error {\n\t\tsuite.T().Logf(\"found %s on node %s\", info.Name, node)\n\t\tsuite.Require().Equal(expectedPath, info.Name, \"expected %s to exist\", expectedPath)\n\n\t\treturn nil\n\t}))\n\n\t// now, re-mount the external volume as read-only\n\texternalVolumeDoc.MountSpec.MountReadOnly = new(true)\n\tsuite.PatchMachineConfig(ctx, externalVolumeDoc)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []resource.ID{externalVolumeID},\n\t\tfunc(vs *block.MountStatus, asrt *assert.Assertions) {\n\t\t\tasrt.True(vs.TypedSpec().ReadOnly)\n\t\t})\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.ExternalVolumeConfigKind, volumeID)\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, externalVolumeID)\n}\n\n// TestVolumeProvisioningErrors verifies that volume provisioning fails correctly for invalid disk selectors.\nfunc (suite *VolumesSuite) TestVolumeProvisioningErrors() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tsuite.Run(\"NoDisksMatchedSelector\", func() {\n\t\tvolumeID := fmt.Sprintf(\"nodsks-%04x\", rand.Int31())\n\t\tuserVolumeID := constants.UserVolumePrefix + volumeID\n\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(\n\t\t\t\t\"disk.serial == 'nonexistent-serial-xyz-00000'\",\n\t\t\t\tcelenv.DiskLocator(),\n\t\t\t),\n\t\t)\n\t\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\t\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"500MiB\")\n\n\t\tsuite.PatchMachineConfig(ctx, doc)\n\n\t\tsuite.T().Logf(\"verifying volume %s on node %s/%s fails with no disks matched\", userVolumeID, node, nodeName)\n\n\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []string{userVolumeID},\n\t\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equalf(block.VolumePhaseFailed, vs.TypedSpec().Phase,\n\t\t\t\t\t\"Expected %q, but got %q (%s)\", block.VolumePhaseFailed, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t\t\tasrt.Contains(vs.TypedSpec().ErrorMessage, \"no disks matched selector for volume\",\n\t\t\t\t\t\"expected error message to contain 'no disks matched selector for volume', got: %s\", vs.TypedSpec().ErrorMessage)\n\t\t\t},\n\t\t)\n\n\t\t// clean up\n\t\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeID)\n\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\t})\n\n\tsuite.Run(\"MultipleDisksMatchedForDiskVolume\", func() {\n\t\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\t\tif len(userDisks) < 2 {\n\t\t\tsuite.T().Skipf(\"skipping test, need at least 2 user disks on node %s/%s: %q\", node, nodeName, userDisks)\n\t\t}\n\n\t\tvolumeID := fmt.Sprintf(\"multi-%04x\", rand.Int31())\n\t\tuserVolumeID := constants.UserVolumePrefix + volumeID\n\n\t\t// build a selector that matches multiple user disks by using an OR of their symlinks\n\t\tdisk0, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\t\tsuite.Require().NoError(err)\n\t\tsuite.Require().NotEmpty(disk0.TypedSpec().Symlinks, \"expected disk0 to have at least one symlink\")\n\n\t\tdisk1, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[1]))\n\t\tsuite.Require().NoError(err)\n\t\tsuite.Require().NotEmpty(disk1.TypedSpec().Symlinks, \"expected disk1 to have at least one symlink\")\n\n\t\tmatchExpr := fmt.Sprintf(\"'%s' in disk.symlinks || '%s' in disk.symlinks\",\n\t\t\tdisk0.TypedSpec().Symlinks[0], disk1.TypedSpec().Symlinks[0])\n\n\t\tdoc := blockcfg.NewUserVolumeConfigV1Alpha1()\n\t\tdoc.MetaName = volumeID\n\t\tdoc.VolumeType = new(block.VolumeTypeDisk)\n\t\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\t\tcel.ParseBooleanExpression(matchExpr, celenv.DiskLocator()),\n\t\t)\n\n\t\tsuite.PatchMachineConfig(ctx, doc)\n\n\t\tsuite.T().Logf(\"verifying volume %s on node %s/%s fails with multiple disks matched\", userVolumeID, node, nodeName)\n\n\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []string{userVolumeID},\n\t\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equalf(block.VolumePhaseFailed, vs.TypedSpec().Phase,\n\t\t\t\t\t\"Expected %q, but got %q (%s)\", block.VolumePhaseFailed, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t\t\tasrt.Contains(vs.TypedSpec().ErrorMessage, \"multiple disks matched locator for disk volume\",\n\t\t\t\t\t\"expected error message to contain 'multiple disks matched locator for disk volume', got: %s\", vs.TypedSpec().ErrorMessage)\n\t\t\t},\n\t\t)\n\n\t\t// clean up\n\t\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.UserVolumeConfigKind, volumeID)\n\n\t\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, userVolumeID)\n\t})\n}\n\n// TestSwapStatus verifies that all swap volumes are successfully enabled.\nfunc (suite *VolumesSuite) TestSwapStatus() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\tswapVolumes, err := safe.StateListAll[*block.VolumeConfig](ctx, suite.Client.COSI, state.WithLabelQuery(resource.LabelExists(block.SwapVolumeLabel)))\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tif swapVolumes.Len() == 0 {\n\t\t\t\tsuite.T().Skipf(\"skipping test, no swap volumes found on node %s\", node)\n\t\t\t}\n\n\t\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\txslices.Map(slices.Collect(swapVolumes.All()), func(sv *block.VolumeConfig) string {\n\t\t\t\t\treturn sv.Metadata().ID()\n\t\t\t\t}),\n\t\t\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tswapVolumesStatus, err := safe.StateListAll[*block.VolumeStatus](ctx, suite.Client.COSI, state.WithLabelQuery(resource.LabelExists(block.SwapVolumeLabel)))\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tdeviceNames := xslices.Map(slices.Collect(swapVolumesStatus.All()), func(sv *block.VolumeStatus) string {\n\t\t\t\treturn sv.TypedSpec().MountLocation\n\t\t\t})\n\n\t\t\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\tdeviceNames,\n\t\t\t\tfunc(vs *block.SwapStatus, asrt *assert.Assertions) {},\n\t\t\t)\n\n\t\t\tsuite.T().Logf(\"found swap volumes (%q) on node %s\", deviceNames, node)\n\t\t})\n\t}\n}\n\n// TestSwapOnOff performs a series of operations on swap volume: creating, destroying, enabling, disabling, etc.\nfunc (suite *VolumesSuite) TestSwapOnOff() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tsuite.T().Logf(\"verifying swap on node %s/%s with disk %s\", node, nodeName, userDisks[0])\n\n\tctx := client.WithNode(suite.ctx, node)\n\n\tdisk, err := safe.StateGetByID[*block.Disk](ctx, suite.Client.COSI, filepath.Base(userDisks[0]))\n\tsuite.Require().NoError(err)\n\n\tvolumeName := fmt.Sprintf(\"%04x\", rand.Int31())\n\n\tdoc := blockcfg.NewSwapVolumeConfigV1Alpha1()\n\tdoc.MetaName = volumeName\n\tdoc.ProvisioningSpec.DiskSelectorSpec.Match = cel.MustExpression(\n\t\tcel.ParseBooleanExpression(fmt.Sprintf(\"'%s' in disk.symlinks\", disk.TypedSpec().Symlinks[0]), celenv.DiskLocator()),\n\t)\n\tdoc.EncryptionSpec = blockcfg.EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []blockcfg.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyStatic: &blockcfg.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"secretswap\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tdoc.ProvisioningSpec.ProvisioningMinSize = blockcfg.MustByteSize(\"100MiB\")\n\tdoc.ProvisioningSpec.ProvisioningMaxSize = blockcfg.MustSize(\"500MiB\")\n\n\t// create user volumes\n\tsuite.PatchMachineConfig(ctx, doc)\n\n\tswapVolumeID := constants.SwapVolumePrefix + doc.MetaName\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []string{swapVolumeID},\n\t\tfunc(vs *block.VolumeStatus, asrt *assert.Assertions) {\n\t\t\tasrt.Equalf(block.VolumePhaseReady, vs.TypedSpec().Phase, \"Expected %q, but got %q (%s)\", block.VolumePhaseReady, vs.TypedSpec().Phase, vs.Metadata().ID())\n\t\t},\n\t)\n\n\t// check that the volumes are mounted\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []string{swapVolumeID},\n\t\tfunc(vs *block.MountStatus, _ *assert.Assertions) {})\n\n\t// check that the swap is enabled\n\tvolumeStatus, err := safe.ReaderGetByID[*block.VolumeStatus](ctx, suite.Client.COSI, swapVolumeID)\n\tsuite.Require().NoError(err)\n\n\trtestutils.AssertResources(ctx, suite.T(), suite.Client.COSI, []string{volumeStatus.TypedSpec().MountLocation},\n\t\tfunc(vs *block.SwapStatus, asrt *assert.Assertions) {})\n\n\t// clean up\n\tsuite.RemoveMachineConfigDocumentsByName(ctx, blockcfg.SwapVolumeConfigKind, volumeName)\n\n\trtestutils.AssertNoResource[*block.VolumeStatus](ctx, suite.T(), suite.Client.COSI, swapVolumeID)\n\trtestutils.AssertNoResource[*block.SwapStatus](ctx, suite.T(), suite.Client.COSI, volumeStatus.TypedSpec().MountLocation)\n\trtestutils.AssertNoResource[*block.VolumeConfig](ctx, suite.T(), suite.Client.COSI, swapVolumeID)\n\n\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t// a little retry loop, as the device might be considered busy for a little while after unmounting\n\t\tasrt := assert.New(collect)\n\n\t\tasrt.NoError(suite.Client.BlockDeviceWipe(ctx, &storage.BlockDeviceWipeRequest{\n\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t{\n\t\t\t\t\tDevice: filepath.Base(userDisks[0]),\n\t\t\t\t\tMethod: storage.BlockDeviceWipeDescriptor_FAST,\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}, time.Minute, time.Second, \"failed to wipe disk %s\", userDisks[0])\n}\n\n// TestZswapStatus verifies that all zswap-enabled machines have zswap running.\nfunc (suite *VolumesSuite) TestZswapStatus() {\n\tfor _, node := range suite.DiscoverNodeInternalIPs(suite.ctx) {\n\t\tsuite.Run(node, func() {\n\t\t\tctx := client.WithNode(suite.ctx, node)\n\n\t\t\tcfg, err := suite.ReadConfigFromNode(ctx)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tif cfg.ZswapConfig() == nil {\n\t\t\t\tsuite.T().Skipf(\"skipping test, zswap is not enabled on node %s\", node)\n\t\t\t}\n\n\t\t\trtestutils.AssertResource(ctx, suite.T(), suite.Client.COSI,\n\t\t\t\tblock.ZswapStatusID,\n\t\t\t\tfunc(vs *block.ZswapStatus, asrt *assert.Assertions) {\n\t\t\t\t\tsuite.T().Logf(\"zswap total size %s, stored pages %d\", vs.TypedSpec().TotalSizeHuman, vs.TypedSpec().StoredPages)\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(VolumesSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/watchdog.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// WatchdogSuite ...\ntype WatchdogSuite struct {\n\tbase.APISuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *WatchdogSuite) SuiteName() string {\n\treturn \"api.WatchdogSuite\"\n}\n\n// SetupTest ...\nfunc (suite *WatchdogSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 1*time.Minute)\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping watchdog test since provisioner is not qemu\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *WatchdogSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\nfunc (suite *WatchdogSuite) readWatchdogSysfs(nodeCtx context.Context, watchdog, property string) string { //nolint:unparam\n\tr, err := suite.Client.Read(nodeCtx, filepath.Join(\"/sys/class/watchdog\", watchdog, property))\n\tsuite.Require().NoError(err)\n\n\tvalue, err := io.ReadAll(r)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(r.Close())\n\n\treturn string(bytes.TrimSpace(value))\n}\n\n// TestWatchdogSysfs sets up the watchdog and validates its parameters from the /sys/class/watchdog.\nfunc (suite *WatchdogSuite) TestWatchdogSysfs() {\n\t// pick up a random node to test the watchdog on, and use it throughout the test\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.T().Logf(\"testing watchdog on node %s\", node)\n\n\t// build a Talos API context which is tied to the node\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t// pick a watchdog\n\tconst watchdog = \"watchdog0\"\n\n\tcfgDocument := runtime.NewWatchdogTimerV1Alpha1()\n\tcfgDocument.WatchdogDevice = \"/dev/\" + watchdog\n\tcfgDocument.WatchdogTimeout = 120 * time.Second\n\n\t// deactivate the watchdog\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\t_, err := suite.Client.COSI.WatchFor(nodeCtx, runtimeres.NewWatchdogTimerStatus(runtimeres.WatchdogTimerConfigID).Metadata(), state.WithEventTypes(state.Destroyed))\n\tsuite.Require().NoError(err)\n\n\twdState := suite.readWatchdogSysfs(nodeCtx, watchdog, \"state\")\n\tsuite.Require().Equal(\"inactive\", wdState)\n\n\t// enable watchdog with 120s timeout\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, runtimeres.NewWatchdogTimerStatus(runtimeres.WatchdogTimerConfigID).Metadata(), state.WithEventTypes(state.Created, state.Updated))\n\tsuite.Require().NoError(err)\n\n\twdState = suite.readWatchdogSysfs(nodeCtx, watchdog, \"state\")\n\tsuite.Require().Equal(\"active\", wdState)\n\n\twdTimeout := suite.readWatchdogSysfs(nodeCtx, watchdog, \"timeout\")\n\tsuite.Require().Equal(\"120\", wdTimeout)\n\n\t// update watchdog timeout to 60s\n\tcfgDocument.WatchdogTimeout = 60 * time.Second\n\tsuite.PatchMachineConfig(nodeCtx, cfgDocument)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, runtimeres.NewWatchdogTimerStatus(runtimeres.WatchdogTimerConfigID).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\treturn r.(*runtimeres.WatchdogTimerStatus).TypedSpec().Timeout == cfgDocument.WatchdogTimeout, nil\n\t\t}),\n\t)\n\tsuite.Require().NoError(err)\n\n\twdState = suite.readWatchdogSysfs(nodeCtx, watchdog, \"state\")\n\tsuite.Require().Equal(\"active\", wdState)\n\n\twdTimeout = suite.readWatchdogSysfs(nodeCtx, watchdog, \"timeout\")\n\tsuite.Require().Equal(\"60\", wdTimeout)\n\n\t// deactivate the watchdog\n\tsuite.RemoveMachineConfigDocuments(nodeCtx, cfgDocument.MetaKind)\n\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx, runtimeres.NewWatchdogTimerStatus(runtimeres.WatchdogTimerConfigID).Metadata(), state.WithEventTypes(state.Destroyed))\n\tsuite.Require().NoError(err)\n\n\twdState = suite.readWatchdogSysfs(nodeCtx, watchdog, \"state\")\n\tsuite.Require().Equal(\"inactive\", wdState)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(WatchdogSuite))\n}\n"
  },
  {
    "path": "internal/integration/api/wipe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage api\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// WipeSuite ...\ntype WipeSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName ...\nfunc (suite *WipeSuite) SuiteName() string {\n\treturn \"api.WipeSuite\"\n}\n\n// SetupTest ...\nfunc (suite *WipeSuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n\n\tif !suite.Capabilities().SupportsVolumes {\n\t\tsuite.T().Skip(\"cluster doesn't support volumes\")\n\t}\n}\n\n// TearDownTest ...\nfunc (suite *WipeSuite) TearDownTest() {\n\tif suite.ctxCancel != nil {\n\t\tsuite.ctxCancel()\n\t}\n}\n\n// TestWipeBlockDeviceInvalid verifies that invalid wipe requests are rejected.\nfunc (suite *WipeSuite) TestWipeBlockDeviceInvalid() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\tdisks, err := safe.StateListAll[*block.Disk](nodeCtx, suite.Client.COSI)\n\tsuite.Require().NoError(err)\n\n\tfor disk := range disks.All() {\n\t\tif disk.TypedSpec().Readonly || disk.TypedSpec().CDROM {\n\t\t\tsuite.T().Logf(\"invalid wipe request for %s at %s\", disk.Metadata().ID(), node)\n\n\t\t\terr = suite.Client.BlockDeviceWipe(nodeCtx, &storage.BlockDeviceWipeRequest{\n\t\t\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t\t\t{\n\t\t\t\t\t\tDevice: disk.Metadata().ID(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t\tsuite.Require().Error(err)\n\t\t\tsuite.Assert().Equal(codes.FailedPrecondition, client.StatusCode(err))\n\t\t}\n\t}\n\n\terr = suite.Client.BlockDeviceWipe(nodeCtx, &storage.BlockDeviceWipeRequest{\n\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t{\n\t\t\t\tDevice: \"nosuchdevice\",\n\t\t\t},\n\t\t},\n\t})\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.NotFound, client.StatusCode(err))\n\n\t// try to wipe a system disk\n\tsystemDisk, err := safe.StateGetByID[*block.SystemDisk](nodeCtx, suite.Client.COSI, block.SystemDiskID)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"invalid wipe request for %s at %s\", systemDisk.TypedSpec().DiskID, node)\n\terr = suite.Client.BlockDeviceWipe(nodeCtx, &storage.BlockDeviceWipeRequest{\n\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t{\n\t\t\t\tDevice: systemDisk.TypedSpec().DiskID,\n\t\t\t},\n\t\t},\n\t})\n\tsuite.Require().Error(err)\n\tsuite.Assert().Equal(codes.FailedPrecondition, client.StatusCode(err))\n}\n\n// TestWipeFilesystem verifies that the filesystem can be wiped.\nfunc (suite *WipeSuite) TestWipeFilesystem() {\n\tif suite.SelinuxEnforcing {\n\t\tsuite.T().Skip(\"skipping tests with nsenter in SELinux enforcing mode\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping test in short mode.\")\n\t}\n\n\tif suite.Cluster == nil || suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping test for non-qemu provisioner\")\n\t}\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(suite.ctx, node)\n\tsuite.Require().NoError(err)\n\n\tnodeName := k8sNode.Name\n\n\tsuite.T().Logf(\"creating filesystem on %s/%s\", node, nodeName)\n\n\tuserDisks := suite.UserDisks(suite.ctx, node)\n\n\tif len(userDisks) < 1 {\n\t\tsuite.T().Skipf(\"skipping test, not enough user disks available on node %s/%s: %q\", node, nodeName, userDisks)\n\t}\n\n\tuserDisk := userDisks[0]\n\n\tpodDef, err := suite.NewPrivilegedPod(\"fs-format\")\n\tsuite.Require().NoError(err)\n\n\tpodDef = podDef.WithNodeName(nodeName)\n\n\tsuite.Require().NoError(podDef.Create(suite.ctx, 5*time.Minute))\n\n\tdefer podDef.Delete(suite.ctx) //nolint:errcheck\n\n\t_, _, err = podDef.Exec(\n\t\tsuite.ctx,\n\t\tfmt.Sprintf(\"nsenter --mount=/proc/1/ns/mnt -- mkfs.xfs %s\", userDisk),\n\t)\n\tsuite.Require().NoError(err)\n\n\t// now Talos should report the disk as xfs formatted\n\tdeviceName := filepath.Base(userDisk)\n\n\tnodeCtx := client.WithNode(suite.ctx, node)\n\n\t// wait for Talos to discover xfs\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx,\n\t\tblock.NewDiscoveredVolume(block.NamespaceName, deviceName).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\treturn r.(*block.DiscoveredVolume).TypedSpec().Name == \"xfs\", nil\n\t\t}),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"xfs filesystem created on %s/%s\", node, nodeName)\n\n\t// wipe the filesystem\n\terr = suite.Client.BlockDeviceWipe(nodeCtx, &storage.BlockDeviceWipeRequest{\n\t\tDevices: []*storage.BlockDeviceWipeDescriptor{\n\t\t\t{\n\t\t\t\tDevice: deviceName,\n\t\t\t},\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\t// wait for Talos to discover that the disk is wiped\n\t_, err = suite.Client.COSI.WatchFor(nodeCtx,\n\t\tblock.NewDiscoveredVolume(block.NamespaceName, deviceName).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\treturn r.(*block.DiscoveredVolume).TypedSpec().Name == \"\", nil\n\t\t}),\n\t)\n\tsuite.Require().NoError(err)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(WipeSuite))\n}\n"
  },
  {
    "path": "internal/integration/base/api.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_api\n\npackage base\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand/v2\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/grpc/backoff\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\tconfigres \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n)\n\n// APISuite is a base suite for API tests.\ntype APISuite struct {\n\tsuite.Suite\n\tTalosSuite\n\n\tClient      *client.Client\n\tTalosconfig *clientconfig.Config\n}\n\n// SetupSuite initializes Talos API client.\nfunc (apiSuite *APISuite) SetupSuite() {\n\tvar err error\n\n\tapiSuite.Talosconfig, err = clientconfig.Open(apiSuite.TalosConfig)\n\tapiSuite.Require().NoError(err)\n\n\tif apiSuite.Endpoint != \"\" {\n\t\tapiSuite.Client = apiSuite.GetClientWithEndpoints(apiSuite.Endpoint)\n\t} else {\n\t\tapiSuite.Client = apiSuite.GetClientWithEndpoints()\n\t}\n\n\t// clear any connection refused errors left after the previous tests\n\tnodes := apiSuite.DiscoverNodeInternalIPs(context.TODO())\n\n\tif len(nodes) > 0 {\n\t\t// grpc might trigger backoff on reconnect attempts, so make sure we clear them\n\t\tapiSuite.ClearConnectionRefused(context.Background(), nodes...)\n\t}\n}\n\n// GetClientWithEndpoints returns Talos API client with provided endpoints.\nfunc (apiSuite *APISuite) GetClientWithEndpoints(endpoints ...string) *client.Client {\n\topts := []client.OptionFunc{\n\t\tclient.WithConfig(apiSuite.Talosconfig),\n\t\tclient.WithEndpoints(endpoints...),\n\t}\n\n\tcli, err := client.New(context.TODO(), opts...)\n\tapiSuite.Require().NoError(err)\n\n\treturn cli\n}\n\n// DiscoverNodes provides list of Talos nodes in the cluster.\n//\n// As there's no way to provide this functionality via Talos API, it works the following way:\n// 1. If there's a provided cluster info, it's used.\n// 2. If integration test was compiled with k8s support, k8s is used.\n//\n// The passed ctx is additionally limited to one minute.\nfunc (apiSuite *APISuite) DiscoverNodes(ctx context.Context) cluster.Info {\n\tdiscoveredNodes := apiSuite.TalosSuite.DiscoverNodes(ctx)\n\tif discoveredNodes != nil {\n\t\treturn discoveredNodes\n\t}\n\n\tvar err error\n\n\tvar ctxCancel context.CancelFunc\n\n\tctx, ctxCancel = context.WithTimeout(ctx, time.Minute)\n\n\tdefer ctxCancel()\n\n\tapiSuite.discoveredNodes, err = discoverNodesK8s(ctx, apiSuite.Client, &apiSuite.TalosSuite)\n\tapiSuite.Require().NoError(err, \"k8s discovery failed\")\n\n\tif apiSuite.discoveredNodes == nil {\n\t\t// still no nodes, skip the test\n\t\tapiSuite.T().Skip(\"no nodes were discovered\")\n\t}\n\n\treturn apiSuite.discoveredNodes\n}\n\n// DiscoverNodeInternalIPs provides list of Talos node internal IPs in the cluster.\nfunc (apiSuite *APISuite) DiscoverNodeInternalIPs(ctx context.Context) []string {\n\tnodes := apiSuite.DiscoverNodes(ctx).Nodes()\n\n\treturn mapNodeInfosToInternalIPs(nodes)\n}\n\n// DiscoverNodeInternalIPsByType provides list of Talos node internal IPs in the cluster for given machine type.\nfunc (apiSuite *APISuite) DiscoverNodeInternalIPsByType(ctx context.Context, machineType machine.Type) []string {\n\tnodesByType := apiSuite.DiscoverNodes(ctx).NodesByType(machineType)\n\n\treturn mapNodeInfosToInternalIPs(nodesByType)\n}\n\n// RandomDiscoveredNodeInternalIP returns the internal IP a random node of the specified type (or any type if no types are specified).\nfunc (apiSuite *APISuite) RandomDiscoveredNodeInternalIP(types ...machine.Type) string {\n\tnodeInfo := apiSuite.DiscoverNodes(context.TODO())\n\n\tvar nodes []cluster.NodeInfo\n\n\tif len(types) == 0 {\n\t\tnodeInfos := nodeInfo.Nodes()\n\n\t\tnodes = nodeInfos\n\t} else {\n\t\tfor _, t := range types {\n\t\t\tnodeInfosByType := nodeInfo.NodesByType(t)\n\n\t\t\tnodes = append(nodes, nodeInfosByType...)\n\t\t}\n\t}\n\n\tapiSuite.Require().NotEmpty(nodes)\n\n\treturn nodes[rand.IntN(len(nodes))].InternalIP.String()\n}\n\n// Capabilities describes current cluster allowed actions.\ntype Capabilities struct {\n\tRunsTalosKernel bool\n\tSupportsReboot  bool\n\tSupportsRecover bool\n\tSupportsVolumes bool\n\tSecureBooted    bool\n}\n\n// Capabilities returns a set of capabilities to skip tests for different environments.\nfunc (apiSuite *APISuite) Capabilities() Capabilities {\n\tv, err := apiSuite.Client.Version(context.Background())\n\tapiSuite.Require().NoError(err)\n\n\tcaps := Capabilities{}\n\n\tif v.Messages[0].Platform != nil {\n\t\tswitch v.Messages[0].Platform.Mode {\n\t\tcase runtime.ModeContainer.String():\n\t\tdefault:\n\t\t\tcaps.RunsTalosKernel = true\n\t\t\tcaps.SupportsReboot = true\n\t\t\tcaps.SupportsRecover = true\n\t\t\tcaps.SupportsVolumes = true\n\t\t}\n\t}\n\n\tctx := context.Background()\n\tctx, ctxCancel := context.WithTimeout(ctx, 2*time.Minute)\n\n\tdefer ctxCancel()\n\n\tsecurityResource, err := safe.StateWatchFor[*runtimeres.SecurityState](\n\t\tctx,\n\t\tapiSuite.Client.COSI,\n\t\truntimeres.NewSecurityStateSpec(runtimeres.NamespaceName).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\tapiSuite.Require().NoError(err)\n\n\tcaps.SecureBooted = securityResource.TypedSpec().SecureBoot\n\n\treturn caps\n}\n\n// AssertClusterHealthy verifies that cluster is healthy using provisioning checks.\nfunc (apiSuite *APISuite) AssertClusterHealthy(ctx context.Context) {\n\tif apiSuite.Cluster == nil {\n\t\t// can't assert if cluster state was provided\n\t\tapiSuite.T().Skip(\"cluster health can't be verified when cluster state is not provided\")\n\t}\n\n\tclusterAccess := access.NewAdapter(apiSuite.Cluster, provision.WithTalosClient(apiSuite.Client))\n\tdefer clusterAccess.Close() //nolint:errcheck\n\n\tapiSuite.Require().NoError(check.Wait(ctx, clusterAccess, append(check.DefaultClusterChecks(), check.ExtraClusterChecks()...), check.StderrReporter()))\n}\n\n// ReadBootID reads node boot_id.\n//\n// Context provided might have specific node attached for API call.\nfunc (apiSuite *APISuite) ReadBootID(ctx context.Context) (string, error) {\n\t// set up a short timeout around boot_id read calls to work around\n\t// cases when rebooted node doesn't answer for a long time on requests\n\treqCtx, reqCtxCancel := context.WithTimeout(ctx, 10*time.Second)\n\tdefer reqCtxCancel()\n\n\treader, err := apiSuite.Client.Read(reqCtx, \"/proc/sys/kernel/random/boot_id\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer reader.Close() //nolint:errcheck\n\n\tbody, err := io.ReadAll(reader)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tbootID := strings.TrimSpace(string(body))\n\n\t_, err = io.Copy(io.Discard, reader)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn bootID, reader.Close()\n}\n\n// ReadBootIDWithRetry reads node boot_id.\n//\n// Context provided might have specific node attached for API call.\nfunc (apiSuite *APISuite) ReadBootIDWithRetry(ctx context.Context, timeout time.Duration) string {\n\tvar bootID string\n\n\tapiSuite.Require().NoError(retry.Constant(timeout, retry.WithUnits(time.Millisecond*1000)).Retry(\n\t\tfunc() error {\n\t\t\tvar err error\n\n\t\t\tbootID, err = apiSuite.ReadBootID(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\tif bootID == \"\" {\n\t\t\t\treturn retry.ExpectedErrorf(\"boot id is empty\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t))\n\n\treturn bootID\n}\n\n// AssertRebooted verifies that node got rebooted as result of running some API call.\n//\n// Verification happens via reading boot_id of the node.\nfunc (apiSuite *APISuite) AssertRebooted(ctx context.Context, node string, rebootFunc func(nodeCtx context.Context) error, timeout time.Duration, extraHooks ...func(context.Context, string)) {\n\tapiSuite.AssertRebootedNoChecks(ctx, node, rebootFunc, timeout)\n\n\tapiSuite.WaitForBootDone(ctx)\n\n\tfor _, hook := range extraHooks {\n\t\thook(ctx, node)\n\t}\n\n\tif apiSuite.Cluster != nil {\n\t\t// without cluster state we can't do deep checks, but basic reboot test still works\n\t\t// NB: using `ctx` here to have client talking to init node by default\n\t\tapiSuite.AssertClusterHealthy(ctx)\n\t}\n}\n\n// AssertRebootedNoChecks waits for node to be rebooted without waiting for cluster to become healthy afterwards.\nfunc (apiSuite *APISuite) AssertRebootedNoChecks(ctx context.Context, node string, rebootFunc func(nodeCtx context.Context) error, timeout time.Duration) {\n\t// timeout for single node Reset\n\tctx, ctxCancel := context.WithTimeout(ctx, timeout)\n\tdefer ctxCancel()\n\n\tnodeCtx := client.WithNode(ctx, node)\n\n\t// read boot_id before reboot\n\tbootIDBefore, err := apiSuite.ReadBootID(nodeCtx)\n\tapiSuite.Require().NoError(err, \"failed to read boot_id before reboot\")\n\n\tapiSuite.Assert().NotEmpty(bootIDBefore, \"boot_id should not be empty\")\n\n\tapiSuite.Assert().NoError(rebootFunc(nodeCtx))\n\n\tapiSuite.AssertBootIDChanged(nodeCtx, bootIDBefore, node, timeout)\n}\n\n// AssertBootIDChanged waits until node boot id changes.\nfunc (apiSuite *APISuite) AssertBootIDChanged(nodeCtx context.Context, bootIDBefore, node string, timeout time.Duration) {\n\tapiSuite.Require().NoError(retry.Constant(timeout).Retry(func() error {\n\t\trequestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, time.Second)\n\t\tdefer requestCtxCancel()\n\n\t\tbootIDAfter, err := apiSuite.ReadBootID(requestCtx)\n\t\tif err != nil {\n\t\t\t// API might be unresponsive during reboot\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif bootIDAfter == bootIDBefore {\n\t\t\t// bootID should be different after reboot\n\t\t\treturn retry.ExpectedErrorf(\"bootID didn't change for node %q: before %s, after %s\", node, bootIDBefore, bootIDAfter)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// WaitForBootDone waits for boot phase done event.\nfunc (apiSuite *APISuite) WaitForBootDone(ctx context.Context) {\n\tapiSuite.WaitForSequenceDone(\n\t\tctx,\n\t\truntime.SequenceBoot,\n\t\tapiSuite.DiscoverNodeInternalIPs(ctx)...,\n\t)\n}\n\n// WaitForSequenceDone waits for sequence done event.\nfunc (apiSuite *APISuite) WaitForSequenceDone(ctx context.Context, sequence runtime.Sequence, nodes ...string) {\n\tnodesNotDone := make(map[string]struct{})\n\n\tfor _, node := range nodes {\n\t\tnodesNotDone[node] = struct{}{}\n\t}\n\n\tapiSuite.Require().NoError(retry.Constant(5*time.Minute, retry.WithUnits(time.Second*10)).Retry(func() error {\n\t\teventsCtx, cancel := context.WithTimeout(client.WithNodes(ctx, nodes...), 5*time.Second)\n\t\tdefer cancel()\n\n\t\terr := apiSuite.Client.EventsWatch(eventsCtx, func(ch <-chan client.Event) {\n\t\t\tdefer cancel()\n\n\t\t\tfor event := range ch {\n\t\t\t\tif msg, ok := event.Payload.(*machineapi.SequenceEvent); ok {\n\t\t\t\t\tif msg.GetAction() == machineapi.SequenceEvent_STOP && msg.GetSequence() == sequence.String() {\n\t\t\t\t\t\tdelete(nodesNotDone, event.Node)\n\n\t\t\t\t\t\tif len(nodesNotDone) == 0 {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, client.WithTailEvents(-1))\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif len(nodesNotDone) > 0 {\n\t\t\treturn retry.ExpectedErrorf(\"nodes %#v sequence %s is not completed\", nodesNotDone, sequence.String())\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// ClearConnectionRefused clears cached connection refused errors which might be left after node reboot.\nfunc (apiSuite *APISuite) ClearConnectionRefused(ctx context.Context, nodes ...string) {\n\tctx, cancel := context.WithTimeout(ctx, backoff.DefaultConfig.MaxDelay)\n\tdefer cancel()\n\n\tcontrolPlaneNodes := apiSuite.DiscoverNodes(ctx).NodesByType(machine.TypeControlPlane)\n\tinitNodes := apiSuite.DiscoverNodes(ctx).NodesByType(machine.TypeInit)\n\n\tnumMasterNodes := len(controlPlaneNodes) + len(initNodes)\n\tif numMasterNodes == 0 {\n\t\tnumMasterNodes = 3\n\t}\n\n\tapiSuite.T().Log(\"run ClearConnectionRefused\")\n\n\tapiSuite.Require().NoError(retry.Constant(backoff.DefaultConfig.MaxDelay, retry.WithUnits(time.Second)).Retry(func() error {\n\t\tfor range numMasterNodes * 5 {\n\t\t\t_, err := apiSuite.Client.Version(client.WithNodes(ctx, nodes...))\n\t\t\tif err == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tapiSuite.T().Log(err.Error())\n\n\t\t\tif client.StatusCode(err) == codes.Unavailable || client.StatusCode(err) == codes.Canceled {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\tif strings.Contains(err.Error(), \"connection refused\") || strings.Contains(err.Error(), \"connection reset by peer\") {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// HashKubeletCert returns hash of the kubelet certificate file.\n//\n// This function can be used to verify that the node ephemeral partition got wiped.\nfunc (apiSuite *APISuite) HashKubeletCert(ctx context.Context, node string) (string, error) {\n\treqCtx, reqCtxCancel := context.WithTimeout(ctx, 10*time.Second)\n\tdefer reqCtxCancel()\n\n\treqCtx = client.WithNodes(reqCtx, node)\n\n\treader, err := apiSuite.Client.Read(reqCtx, \"/var/lib/kubelet/pki/kubelet-client-current.pem\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer reader.Close() //nolint:errcheck\n\n\thash := sha256.New()\n\n\t_, err = io.Copy(hash, reader)\n\tif err != nil {\n\t\tif client.StatusCode(err) != codes.NotFound { // not found, swallow it\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\treturn hex.EncodeToString(hash.Sum(nil)), reader.Close()\n}\n\n// ReadConfigFromNode reads machine configuration from the node.\nfunc (apiSuite *APISuite) ReadConfigFromNode(nodeCtx context.Context) (config.Provider, error) {\n\tcfg, err := safe.StateGetByID[*configres.MachineConfig](nodeCtx, apiSuite.Client.COSI, configres.ActiveID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching machine config resource: %w\", err)\n\t}\n\n\treturn cfg.Provider(), nil\n}\n\n// UserDisks returns list of user disks not having any partitions present.\nfunc (apiSuite *APISuite) UserDisks(ctx context.Context, node string) []string {\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tdisks, err := safe.ReaderListAll[*block.Disk](nodeCtx, apiSuite.Client.COSI)\n\tapiSuite.Require().NoError(err, \"failed to list disks\")\n\n\tvar candidateDisks []string //nolint:prealloc\n\n\tfor disk := range disks.All() {\n\t\t// skip CD-ROM, readonly and disks without transport (this is usually lvms, md, zfs devices etc)\n\t\t// also skip iscsi disks (these are created in tests)\n\t\tif disk.TypedSpec().Readonly || disk.TypedSpec().CDROM || disk.TypedSpec().Transport == \"\" || disk.TypedSpec().Transport == \"iscsi\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tcandidateDisks = append(candidateDisks, disk.Metadata().ID())\n\t}\n\n\tvar availableDisks []string\n\n\tfor _, disk := range candidateDisks {\n\t\tdiscoveredVolume, err := safe.ReaderGetByID[*block.DiscoveredVolume](nodeCtx, apiSuite.Client.COSI, disk)\n\t\tapiSuite.Require().NoError(err, \"failed to get discovered volume\")\n\n\t\tif discoveredVolume.TypedSpec().Name == \"\" {\n\t\t\tavailableDisks = append(availableDisks, discoveredVolume.TypedSpec().DevPath)\n\t\t}\n\t}\n\n\treturn availableDisks\n}\n\n// AssertServicesRunning verifies that services are running on the node.\nfunc (apiSuite *APISuite) AssertServicesRunning(ctx context.Context, node string, serviceStatus map[string]string) {\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tfor svc, state := range serviceStatus {\n\t\tresp, err := apiSuite.Client.ServiceInfo(nodeCtx, svc)\n\t\tapiSuite.Require().NoError(err)\n\t\tapiSuite.Require().NotNil(resp, \"expected service %s to be registered\", svc)\n\n\t\tfor _, svcInfo := range resp {\n\t\t\tapiSuite.Require().Equal(state, svcInfo.Service.State, \"expected service %s to have state %s\", svc, state)\n\t\t}\n\t}\n}\n\n// AssertExpectedModules verifies that expected kernel modules are loaded on the node.\nfunc (apiSuite *APISuite) AssertExpectedModules(ctx context.Context, node string, expectedModules map[string]string) {\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tfileReader, err := apiSuite.Client.Read(nodeCtx, \"/proc/modules\")\n\tapiSuite.Require().NoError(err)\n\n\tdefer func() {\n\t\tapiSuite.Require().NoError(fileReader.Close())\n\t}()\n\n\tscanner := bufio.NewScanner(fileReader)\n\n\tvar loadedModules []string\n\n\tfor scanner.Scan() {\n\t\tloadedModules = append(loadedModules, strings.Split(scanner.Text(), \" \")[0])\n\t}\n\n\tapiSuite.Require().NoError(scanner.Err())\n\n\tfileReader, err = apiSuite.Client.Read(nodeCtx, fmt.Sprintf(\"/usr/lib/modules/%s/modules.dep\", constants.DefaultKernelVersion))\n\tapiSuite.Require().NoError(err)\n\n\tdefer func() {\n\t\tapiSuite.Require().NoError(fileReader.Close())\n\t}()\n\n\tscanner = bufio.NewScanner(fileReader)\n\n\tvar modulesDep []string\n\n\tfor scanner.Scan() {\n\t\tmodulesDep = append(modulesDep, filepath.Base(strings.Split(scanner.Text(), \":\")[0]))\n\t}\n\n\tapiSuite.Require().NoError(scanner.Err())\n\n\tfor module, moduleDep := range expectedModules {\n\t\tapiSuite.Require().Contains(loadedModules, module, \"expected %s to be loaded\", module)\n\t\tapiSuite.Require().Contains(modulesDep, moduleDep, \"expected %s to be in modules.dep\", moduleDep)\n\t}\n}\n\n// UpdateMachineConfig fetches machine configuration, patches it and applies the changes.\nfunc (apiSuite *APISuite) UpdateMachineConfig(\n\tnodeCtx context.Context, modeSetter func(*machineapi.ApplyConfigurationRequest), patch func(config.Provider) (config.Provider, error),\n) {\n\tcfg, err := apiSuite.ReadConfigFromNode(nodeCtx)\n\tapiSuite.Require().NoError(err)\n\n\tpatchedCfg, err := patch(cfg)\n\tapiSuite.Require().NoError(err)\n\n\tbytes, err := patchedCfg.Bytes()\n\tapiSuite.Require().NoError(err)\n\n\treq := &machineapi.ApplyConfigurationRequest{\n\t\tData: bytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_AUTO,\n\t}\n\n\tmodeSetter(req)\n\n\tresp, err := apiSuite.Client.ApplyConfiguration(nodeCtx, req)\n\tapiSuite.Require().NoError(err)\n\n\tapiSuite.T().Logf(\"patched machine config: %s\", resp.Messages[0].ModeDetails)\n}\n\n// PatchMachineConfig patches machine configuration on the node.\nfunc (apiSuite *APISuite) PatchMachineConfig(nodeCtx context.Context, patches ...any) {\n\tapiSuite.PatchMachineConfigWithModeSetter(nodeCtx, func(*machineapi.ApplyConfigurationRequest) {}, patches...)\n}\n\n// PatchMachineConfigWithModeSetter patches machine configuration on the node with a specific mode.\nfunc (apiSuite *APISuite) PatchMachineConfigWithModeSetter(\n\tnodeCtx context.Context, modeSetter func(*machineapi.ApplyConfigurationRequest), patches ...any,\n) {\n\tconfigPatches := make([]configpatcher.Patch, 0, len(patches))\n\n\tfor _, patch := range patches {\n\t\tmarshaled, err := yaml.Marshal(patch)\n\t\tapiSuite.Require().NoError(err)\n\n\t\tconfigPatch, err := configpatcher.LoadPatch(marshaled)\n\t\tapiSuite.Require().NoError(err)\n\n\t\tconfigPatches = append(configPatches, configPatch)\n\t}\n\n\tapiSuite.UpdateMachineConfig(nodeCtx,\n\t\tmodeSetter,\n\t\tfunc(cfg config.Provider) (config.Provider, error) {\n\t\t\tout, err := configpatcher.Apply(configpatcher.WithConfig(cfg), configPatches)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn out.Config()\n\t\t})\n}\n\n// RemoveMachineConfigDocuments removes machine configuration documents of specified type from the node.\nfunc (apiSuite *APISuite) RemoveMachineConfigDocuments(nodeCtx context.Context, docTypes ...string) {\n\tapiSuite.UpdateMachineConfig(nodeCtx,\n\t\tfunc(*machineapi.ApplyConfigurationRequest) {},\n\t\tfunc(cfg config.Provider) (config.Provider, error) {\n\t\t\treturn container.New(xslices.Filter(cfg.Documents(), func(doc configconfig.Document) bool {\n\t\t\t\treturn slices.Index(docTypes, doc.Kind()) == -1\n\t\t\t})...)\n\t\t})\n}\n\n// RemoveMachineConfigDocumentsByName removes machine configuration documents of specified type and names from the node.\nfunc (apiSuite *APISuite) RemoveMachineConfigDocumentsByName(nodeCtx context.Context, docType string, names ...string) {\n\tapiSuite.UpdateMachineConfig(nodeCtx,\n\t\tfunc(*machineapi.ApplyConfigurationRequest) {},\n\t\tfunc(cfg config.Provider) (config.Provider, error) {\n\t\t\treturn container.New(xslices.Filter(cfg.Documents(), func(doc configconfig.Document) bool {\n\t\t\t\tif doc.Kind() != docType {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\tnamedDoc, ok := doc.(configconfig.NamedDocument)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\treturn slices.Index(names, namedDoc.Name()) == -1\n\t\t\t})...)\n\t\t})\n}\n\n// PatchV1Alpha1Config patches v1alpha1 config in the config provider.\nfunc (apiSuite *APISuite) PatchV1Alpha1Config(provider config.Provider, patch func(*v1alpha1.Config)) []byte {\n\tctr, err := provider.PatchV1Alpha1(func(c *v1alpha1.Config) error {\n\t\tpatch(c)\n\n\t\treturn nil\n\t})\n\tapiSuite.Require().NoError(err)\n\n\tbytes, err := ctr.Bytes()\n\tapiSuite.Require().NoError(err)\n\n\treturn bytes\n}\n\n// ResetNode wraps the reset node sequence with checks, waiting for the reset to finish and verifying the result.\n//\n//nolint:gocyclo\nfunc (apiSuite *APISuite) ResetNode(ctx context.Context, node string, resetSpec *machineapi.ResetRequest, runHealthChecks bool) {\n\tapiSuite.T().Logf(\"resetting node %q with graceful %v mode %s, system %v, user %v\", node, resetSpec.Graceful, resetSpec.Mode, resetSpec.SystemPartitionsToWipe, resetSpec.UserDisksToWipe)\n\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tnodeClient := apiSuite.GetClientWithEndpoints(node)\n\tdefer nodeClient.Close() //nolint:errcheck\n\n\t// any reset should lead to a reboot, so read boot_id before reboot\n\tbootIDBefore, err := apiSuite.ReadBootID(nodeCtx)\n\tapiSuite.Require().NoError(err)\n\n\t// figure out if EPHEMERAL is going to be reset\n\tephemeralIsGoingToBeReset := false\n\n\tif len(resetSpec.SystemPartitionsToWipe) == 0 && len(resetSpec.UserDisksToWipe) == 0 {\n\t\tephemeralIsGoingToBeReset = true\n\t} else {\n\t\tfor _, part := range resetSpec.SystemPartitionsToWipe {\n\t\t\tif part.Label == constants.EphemeralPartitionLabel {\n\t\t\t\tephemeralIsGoingToBeReset = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tpreReset, err := apiSuite.HashKubeletCert(ctx, node)\n\tapiSuite.Require().NoError(err)\n\n\tresp, err := nodeClient.ResetGenericWithResponse(nodeCtx, resetSpec)\n\tapiSuite.Require().NoError(err)\n\n\tactorID := resp.Messages[0].ActorId\n\n\teventCh := make(chan client.EventResult)\n\n\t// watch for events\n\tapiSuite.Require().NoError(nodeClient.EventsWatchV2(nodeCtx, eventCh, client.WithActorID(actorID), client.WithTailEvents(-1)))\n\n\twaitTimer := time.NewTimer(5 * time.Minute)\n\tdefer waitTimer.Stop()\n\nwaitLoop:\n\tfor {\n\t\tselect {\n\t\tcase ev := <-eventCh:\n\t\t\tapiSuite.Require().NoError(ev.Error)\n\n\t\t\tswitch msg := ev.Event.Payload.(type) {\n\t\t\tcase *machineapi.SequenceEvent:\n\t\t\t\tif msg.Error != nil {\n\t\t\t\t\tapiSuite.FailNow(\"reset failed\", \"%s: %s\", msg.Error.Message, msg.Error.Code)\n\t\t\t\t}\n\t\t\tcase *machineapi.PhaseEvent:\n\t\t\t\tif msg.Action == machineapi.PhaseEvent_START && msg.Phase == \"unmountSystem\" {\n\t\t\t\t\t// about to be reset, break waitLoop\n\t\t\t\t\tbreak waitLoop\n\t\t\t\t}\n\n\t\t\t\tif msg.Action == machineapi.PhaseEvent_STOP {\n\t\t\t\t\tapiSuite.T().Logf(\"reset phase %q finished\", msg.Phase)\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-waitTimer.C:\n\t\t\tapiSuite.FailNow(\"timeout waiting for reset to finish\")\n\t\tcase <-ctx.Done():\n\t\t\tapiSuite.FailNow(\"context canceled\")\n\t\t}\n\t}\n\n\t// wait for the apid to be shut down\n\ttime.Sleep(10 * time.Second)\n\n\tapiSuite.AssertBootIDChanged(nodeCtx, bootIDBefore, node, 3*time.Minute)\n\n\tapiSuite.ClearConnectionRefused(ctx, node)\n\n\tif runHealthChecks {\n\t\tif apiSuite.Cluster != nil {\n\t\t\t// without cluster state we can't do deep checks, but basic reboot test still works\n\t\t\t// NB: using `ctx` here to have client talking to init node by default\n\t\t\tapiSuite.AssertClusterHealthy(ctx)\n\t\t}\n\n\t\tpostReset, err := apiSuite.HashKubeletCert(ctx, node)\n\t\tapiSuite.Require().NoError(err)\n\n\t\tif ephemeralIsGoingToBeReset {\n\t\t\tapiSuite.Assert().NotEqual(preReset, postReset, \"reset should lead to new kubelet cert being generated\")\n\t\t} else {\n\t\t\tapiSuite.Assert().Equal(preReset, postReset, \"ephemeral partition was not reset\")\n\t\t}\n\t}\n}\n\n// DumpLogs dumps a set of logs from the node.\nfunc (apiSuite *APISuite) DumpLogs(ctx context.Context, node string, service, pattern string) {\n\tnodeCtx := client.WithNode(ctx, node)\n\n\tlogsStream, err := apiSuite.Client.Logs(\n\t\tnodeCtx,\n\t\tconstants.SystemContainerdNamespace,\n\t\tcommon.ContainerDriver_CONTAINERD,\n\t\tservice,\n\t\tfalse,\n\t\t-1,\n\t)\n\tapiSuite.Require().NoError(err)\n\n\tlogReader, err := client.ReadStream(logsStream)\n\tapiSuite.Require().NoError(err)\n\n\tdefer logReader.Close() //nolint:errcheck\n\n\tscanner := bufio.NewScanner(logReader)\n\n\tfor scanner.Scan() {\n\t\tif pattern == \"\" || strings.Contains(scanner.Text(), pattern) {\n\t\t\tapiSuite.T().Logf(\"%s (%s): %s\", node, service, scanner.Text())\n\t\t}\n\t}\n}\n\n// ReadFile reads file from the node.\nfunc (apiSuite *APISuite) ReadFile(nodeCtx context.Context, path string) string {\n\treader, err := apiSuite.Client.Read(nodeCtx, path)\n\tapiSuite.Require().NoError(err)\n\n\tdefer reader.Close() //nolint:errcheck\n\n\tbody, err := io.ReadAll(reader)\n\tapiSuite.Require().NoError(err)\n\n\tcontent := strings.TrimSpace(string(body))\n\n\t_, err = io.Copy(io.Discard, reader)\n\tapiSuite.Require().NoError(err)\n\n\tapiSuite.Require().NoError(reader.Close())\n\n\treturn content\n}\n\n// ReadCmdline reads cmdline from the node.\nfunc (apiSuite *APISuite) ReadCmdline(nodeCtx context.Context) string {\n\treturn apiSuite.ReadFile(nodeCtx, \"/proc/cmdline\")\n}\n\n// TearDownSuite closes Talos API client.\nfunc (apiSuite *APISuite) TearDownSuite() {\n\tif apiSuite.Client != nil {\n\t\tapiSuite.Assert().NoError(apiSuite.Client.Close())\n\t}\n}\n\nfunc mapNodeInfosToInternalIPs(nodes []cluster.NodeInfo) []string {\n\tips := make([]string, len(nodes))\n\n\tfor i, node := range nodes {\n\t\tips[i] = node.InternalIP.String()\n\t}\n\n\treturn ips\n}\n"
  },
  {
    "path": "internal/integration/base/base.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package base provides shared definition of base suites for tests\npackage base\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n)\n\nconst (\n\t// ProvisionerQEMU is the name of the QEMU provisioner.\n\tProvisionerQEMU = \"qemu\"\n\t// ProvisionerDocker is the name of the Docker provisioner.\n\tProvisionerDocker = \"docker\"\n)\n\n// TalosSuite defines most common settings for integration test suites.\ntype TalosSuite struct {\n\t// Endpoint to use to connect, if not set config is used\n\tEndpoint string\n\t// K8sEndpoint is API server endpoint, if set overrides kubeconfig\n\tK8sEndpoint string\n\t// Cluster describes provisioned cluster, used for discovery purposes\n\tCluster provision.Cluster\n\t// TalosConfig is a path to talosconfig\n\tTalosConfig string\n\t// Version is the (expected) version of Talos tests are running against\n\tVersion string\n\t// GoVersion is the (expected) version of Go compiler.\n\tGoVersion string\n\t// TalosctlPath is a path to talosctl binary\n\tTalosctlPath string\n\t// KubectlPath is a path to kubectl binary\n\tKubectlPath string\n\t// HelmPath is a path to helm binary\n\tHelmPath string\n\t// KubeStrPath is a path to kubestr binary\n\tKubeStrPath string\n\t// ExtensionsQEMU runs tests with qemu and extensions enabled\n\tExtensionsQEMU bool\n\t// ExtensionsNvidia runs tests with nvidia extensions enabled\n\tExtensionsNvidia bool\n\t// TrustedBoot tells if the cluster is secure booted and disks are encrypted\n\tTrustedBoot bool\n\t// SelinuxEnforcing tells if the cluster is booted with the image with selinux enforcement enabled\n\tSelinuxEnforcing bool\n\t// VerifyUKIBooted runs tests to verify Talos is booted from a UKI\n\tVerifyUKIBooted bool\n\t// TalosImage is the image name for 'talos' container.\n\tTalosImage string\n\t// CSITestName is the name of the CSI test to run\n\tCSITestName string\n\t// CSITestTimeout is the timeout for the CSI test\n\tCSITestTimeout string\n\t// Airgapped marks that cluster has no access to external networks\n\tAirgapped bool\n\t// Virtiofsd marks that cluster has virtiofs volumes (virtiofsd is running for workers)\n\tVirtiofsd bool\n\t// Race informs test suites about race detector being enabled (e.g. for skipping incompatible tests)\n\tRace bool\n\n\tdiscoveredNodes cluster.Info\n}\n\n// DiscoverNodes provides basic functionality to discover cluster nodes via test settings.\n//\n// This method is overridden in specific suites to allow for specific discovery.\nfunc (talosSuite *TalosSuite) DiscoverNodes(_ context.Context) cluster.Info {\n\tif talosSuite.discoveredNodes == nil {\n\t\tif talosSuite.Cluster != nil {\n\t\t\ttalosSuite.discoveredNodes = access.NewAdapter(talosSuite.Cluster).Info\n\t\t}\n\t}\n\n\treturn talosSuite.discoveredNodes\n}\n\n// ConfiguredSuite expects config to be set before running.\ntype ConfiguredSuite interface {\n\tSetConfig(config TalosSuite)\n}\n\n// SetConfig implements ConfiguredSuite.\nfunc (talosSuite *TalosSuite) SetConfig(config TalosSuite) {\n\t*talosSuite = config\n}\n\n// NamedSuite interface provides names for test suites.\ntype NamedSuite interface {\n\tSuiteName() string\n}\n"
  },
  {
    "path": "internal/integration/base/cli.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage base\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// CLISuite is a base suite for CLI tests.\ntype CLISuite struct {\n\tsuite.Suite\n\tTalosSuite\n}\n\n// DiscoverNodes provides list of Talos nodes in the cluster.\n//\n// As there's no way to provide this functionality via Talos CLI, it relies on cluster info.\nfunc (cliSuite *CLISuite) DiscoverNodes(ctx context.Context) cluster.Info {\n\tdiscoveredNodes := cliSuite.TalosSuite.DiscoverNodes(ctx)\n\tif discoveredNodes != nil {\n\t\treturn discoveredNodes\n\t}\n\n\treturn cliSuite.discoverKubectl()\n}\n\n// DiscoverNodeInternalIPs provides list of Talos node internal IPs in the cluster.\nfunc (cliSuite *CLISuite) DiscoverNodeInternalIPs(ctx context.Context) []string {\n\tnodes := cliSuite.DiscoverNodes(ctx)\n\n\treturn mapNodeInfosToInternalIPs(nodes.Nodes())\n}\n\n// DiscoverNodeInternalIPsByType provides list of Talos node internal IPs in the cluster for given machine type.\nfunc (cliSuite *CLISuite) DiscoverNodeInternalIPsByType(ctx context.Context, machineType machine.Type) []string {\n\tnodesByType := cliSuite.DiscoverNodes(ctx).NodesByType(machineType)\n\n\treturn mapNodeInfosToInternalIPs(nodesByType)\n}\n\n// RandomDiscoveredNodeInternalIP returns the internal IP a random node of the specified type (or any type if no types are specified).\nfunc (cliSuite *CLISuite) RandomDiscoveredNodeInternalIP(types ...machine.Type) string {\n\tnodeInfo := cliSuite.DiscoverNodes(context.TODO())\n\n\tvar nodes []cluster.NodeInfo\n\n\tif len(types) == 0 {\n\t\tnodes = nodeInfo.Nodes()\n\t} else {\n\t\tfor _, t := range types {\n\t\t\tnodes = append(nodes, nodeInfo.NodesByType(t)...)\n\t\t}\n\t}\n\n\tcliSuite.Require().NotEmpty(nodes)\n\n\treturn nodes[rand.IntN(len(nodes))].InternalIP.String()\n}\n\nfunc (cliSuite *CLISuite) discoverKubectl() cluster.Info {\n\t// pull down kubeconfig into temporary directory\n\ttempDir := cliSuite.T().TempDir()\n\n\t// rely on `nodes:` being set in talosconfig\n\tcliSuite.RunCLI([]string{\"kubeconfig\", tempDir}, StdoutEmpty())\n\n\tmasterNodes, err := cmd.RunWithOptions(cliSuite.T().Context(), cliSuite.KubectlPath,\n\t\t[]string{\n\t\t\t\"--kubeconfig\", filepath.Join(tempDir, \"kubeconfig\"), \"get\", \"nodes\",\n\t\t\t\"-o\", \"jsonpath={.items[*].status.addresses[?(@.type==\\\"InternalIP\\\")].address}\", fmt.Sprintf(\"--selector=%s\", constants.LabelNodeRoleControlPlane),\n\t\t})\n\tcliSuite.Require().NoError(err)\n\n\tworkerNodes, err := cmd.RunWithOptions(cliSuite.T().Context(), cliSuite.KubectlPath,\n\t\t[]string{\n\t\t\t\"--kubeconfig\", filepath.Join(tempDir, \"kubeconfig\"), \"get\", \"nodes\",\n\t\t\t\"-o\", \"jsonpath={.items[*].status.addresses[?(@.type==\\\"InternalIP\\\")].address}\", fmt.Sprintf(\"--selector=!%s\", constants.LabelNodeRoleControlPlane),\n\t\t})\n\tcliSuite.Require().NoError(err)\n\n\tnodeInfo, err := newNodeInfo(\n\t\tstrings.Fields(strings.TrimSpace(masterNodes)),\n\t\tstrings.Fields(strings.TrimSpace(workerNodes)),\n\t)\n\tcliSuite.Require().NoError(err)\n\n\treturn nodeInfo\n}\n\n// RunCLI runs talosctl binary with the options provided.\nfunc (cliSuite *CLISuite) RunCLI(args []string, options ...RunOption) (stdout, stderr string) {\n\treturn run(cliSuite.T(), cliSuite.MakeCMDFn(args), options...)\n}\n\n// MakeCMDFn returns a function that creates a new exec.Cmd with the provided args.\n// TalosSuite flags are added at the beginning so they can be overridden by args.\nfunc (cliSuite *CLISuite) MakeCMDFn(args []string) func() *exec.Cmd {\n\tif cliSuite.Endpoint != \"\" {\n\t\targs = append([]string{\"--endpoints\", cliSuite.Endpoint}, args...)\n\t}\n\n\tvar firstArg string\n\n\tfor _, arg := range args {\n\t\tif strings.HasPrefix(arg, \"--\") {\n\t\t\t// this is a flag, skip it\n\t\t\tcontinue\n\t\t}\n\n\t\tfirstArg = arg\n\n\t\tbreak\n\t}\n\n\tmgmtCommand := slices.Contains([]string{\"completion\", \"gen\", \"inject\", \"machineconfig\", \"validate\"}, firstArg)\n\n\tif !mgmtCommand {\n\t\targs = append([]string{\"--talosconfig\", cliSuite.TalosConfig}, args...)\n\t}\n\n\tpath := cliSuite.TalosctlPath\n\n\treturn func() *exec.Cmd { return exec.CommandContext(cliSuite.T().Context(), path, args...) }\n}\n\n// RunCLI runs talosctl binary with the options provided.\nfunc RunCLI(t *testing.T, f func() *exec.Cmd, options ...RunOption) (stdout, stderr string) {\n\treturn run(t, f, options...)\n}\n\n// RunAndWaitForMatch retries command until output matches.\nfunc (cliSuite *CLISuite) RunAndWaitForMatch(args []string, regex *regexp.Regexp, duration time.Duration, options ...retry.Option) {\n\tcliSuite.Assert().NoError(retry.Constant(duration, options...).Retry(func() error {\n\t\tstdout, _, err := runAndWait(cliSuite.Suite.T(), cliSuite.MakeCMDFn(args)(), nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !regex.MatchString(stdout.String()) {\n\t\t\treturn retry.ExpectedErrorf(\"stdout doesn't match: %q\", stdout)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n"
  },
  {
    "path": "internal/integration/base/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\npackage base\n\nimport (\n\t\"slices\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\ntype infoWrapper struct {\n\tnodeInfos       []cluster.NodeInfo\n\tnodeInfosByType map[machine.Type][]cluster.NodeInfo\n}\n\nfunc newNodeInfo(masterNodes, workerNodes []string) (*infoWrapper, error) {\n\tcontrolPlaneNodeInfos, err := cluster.IPsToNodeInfos(masterNodes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tworkerNodeInfos, err := cluster.IPsToNodeInfos(workerNodes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &infoWrapper{\n\t\tnodeInfos: slices.Concat(controlPlaneNodeInfos, workerNodeInfos),\n\t\tnodeInfosByType: map[machine.Type][]cluster.NodeInfo{\n\t\t\tmachine.TypeControlPlane: controlPlaneNodeInfos,\n\t\t\tmachine.TypeWorker:       workerNodeInfos,\n\t\t},\n\t}, nil\n}\n\nfunc (wrapper *infoWrapper) Nodes() []cluster.NodeInfo {\n\treturn wrapper.nodeInfos\n}\n\nfunc (wrapper *infoWrapper) NodesByType(t machine.Type) []cluster.NodeInfo {\n\treturn wrapper.nodeInfosByType[t]\n}\n"
  },
  {
    "path": "internal/integration/base/discovery_k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage base\n\nimport (\n\t\"context\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n//nolint:gocyclo\nfunc discoverNodesK8s(ctx context.Context, client *client.Client, suite *TalosSuite) (cluster.Info, error) {\n\tkubeconfig, err := client.Kubeconfig(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\treturn clientcmd.Load(kubeconfig)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// patch timeout\n\tif suite.K8sEndpoint != \"\" {\n\t\tconfig.Host = suite.K8sEndpoint\n\t}\n\n\tclientset, err := kubernetes.NewForConfig(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar masterNodes, workerNodes []string\n\n\tfor _, node := range nodes.Items {\n\t\tvar address string\n\n\t\tfor _, nodeAddress := range node.Status.Addresses {\n\t\t\tif nodeAddress.Type == v1.NodeInternalIP {\n\t\t\t\taddress = nodeAddress.Address\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif address == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, ok := node.Labels[constants.LabelNodeRoleControlPlane]; ok {\n\t\t\tmasterNodes = append(masterNodes, address)\n\t\t} else {\n\t\t\tworkerNodes = append(workerNodes, address)\n\t\t}\n\t}\n\n\treturn newNodeInfo(masterNodes, workerNodes)\n}\n"
  },
  {
    "path": "internal/integration/base/discovery_nok8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration && !integration_k8s\n\npackage base\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc discoverNodesK8s(ctx context.Context, client *client.Client, suite *TalosSuite) (cluster.Info, error) {\n\treturn nil, nil\n}\n"
  },
  {
    "path": "internal/integration/base/errors.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\npackage base\n\nimport (\n\t\"errors\"\n\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// IgnoreGRPCUnavailable searches through unwrapped errors and ignores the error if it is grpc.Unavailable.\nfunc IgnoreGRPCUnavailable(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tunwrappedErr := err\n\n\tfor {\n\t\tif s, ok := status.FromError(unwrappedErr); ok && s.Code() == codes.Unavailable {\n\t\t\t// ignore errors if reboot happens before response is fully received\n\t\t\treturn nil\n\t\t}\n\n\t\tunwrappedErr = errors.Unwrap(unwrappedErr)\n\t\tif unwrappedErr == nil {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/integration/base/flags.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\npackage base\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xiter/xstrings\"\n)\n\n// StringList implements flag.Value for list of strings.\ntype StringList []string\n\n// String implements flag.Value.\nfunc (l *StringList) String() string {\n\treturn strings.Join(*l, \",\")\n}\n\n// Set implements flag.Value.\nfunc (l *StringList) Set(value string) error {\n\t*l = slices.AppendSeq(*l, xstrings.SplitSeq(value, \",\"))\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/integration/base/k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage base\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\teventsv1 \"k8s.io/api/events/v1\"\n\t\"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/runtime/schema\"\n\t\"k8s.io/apimachinery/pkg/types\"\n\t\"k8s.io/apimachinery/pkg/util/yaml\"\n\t\"k8s.io/apimachinery/pkg/watch\"\n\t\"k8s.io/client-go/discovery\"\n\t\"k8s.io/client-go/discovery/cached/memory\"\n\t\"k8s.io/client-go/dynamic\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/restmapper\"\n\t\"k8s.io/client-go/tools/cache\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\t\"k8s.io/client-go/tools/remotecommand\"\n\twatchtools \"k8s.io/client-go/tools/watch\"\n\t\"k8s.io/client-go/util/jsonpath\"\n\t\"k8s.io/kubectl/pkg/scheme\"\n\n\ttaloskubernetes \"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// K8sSuite is a base suite for K8s tests.\ntype K8sSuite struct {\n\tAPISuite\n\n\tClientset       *kubernetes.Clientset\n\tDynamicClient   dynamic.Interface\n\tDiscoveryClient *discovery.DiscoveryClient\n\tRestConfig      *rest.Config\n\tMapper          *restmapper.DeferredDiscoveryRESTMapper\n}\n\n// SetupSuite initializes Kubernetes client.\nfunc (k8sSuite *K8sSuite) SetupSuite() {\n\tk8sSuite.APISuite.SetupSuite()\n\n\tkubeconfig, err := k8sSuite.Client.Kubeconfig(context.Background())\n\tk8sSuite.Require().NoError(err)\n\n\tconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\treturn clientcmd.Load(kubeconfig)\n\t})\n\tk8sSuite.Require().NoError(err)\n\n\tif k8sSuite.K8sEndpoint != \"\" {\n\t\tconfig.Host = k8sSuite.K8sEndpoint\n\t}\n\n\tk8sSuite.RestConfig = config\n\tk8sSuite.Clientset, err = kubernetes.NewForConfig(config)\n\tk8sSuite.Require().NoError(err)\n\n\tk8sSuite.DynamicClient, err = dynamic.NewForConfig(config)\n\tk8sSuite.Require().NoError(err)\n\n\tk8sSuite.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(config)\n\tk8sSuite.Require().NoError(err)\n\n\tk8sSuite.Mapper = restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(k8sSuite.DiscoveryClient))\n}\n\n// GetK8sNodeByInternalIP returns the kubernetes node by its internal ip or error if it is not found.\nfunc (k8sSuite *K8sSuite) GetK8sNodeByInternalIP(ctx context.Context, internalIP string) (*corev1.Node, error) {\n\tnodeList, err := k8sSuite.Clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, item := range nodeList.Items {\n\t\tfor _, address := range item.Status.Addresses {\n\t\t\tif address.Type == corev1.NodeInternalIP {\n\t\t\t\tif address.Address == internalIP {\n\t\t\t\t\treturn &item, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"node with internal IP %s not found\", internalIP)\n}\n\n// CleanupFailedPods deletes all pods in kube-system namespace with the status Failed.\nfunc (k8sSuite *K8sSuite) CleanupFailedPods(ctx context.Context, internalIP string) {\n\tnodeName, err := k8sSuite.GetK8sNodeByInternalIP(ctx, internalIP)\n\tif err != nil {\n\t\tk8sSuite.T().Logf(\"failed to get node by internal IP %s: %v\", internalIP, err)\n\n\t\treturn\n\t}\n\n\tpods, err := k8sSuite.Clientset.CoreV1().Pods(\"kube-system\").List(ctx, metav1.ListOptions{\n\t\tFieldSelector: fields.OneTermEqualSelector(\"spec.nodeName\", nodeName.Name).String(),\n\t})\n\tif err != nil {\n\t\tk8sSuite.T().Logf(\"failed to list pods in kube-system namespace: %v\", err)\n\n\t\treturn\n\t}\n\n\tfor _, pod := range pods.Items {\n\t\tif pod.Status.Phase == corev1.PodFailed {\n\t\t\tif err := k8sSuite.Clientset.CoreV1().Pods(\"kube-system\").Delete(ctx, pod.Name, metav1.DeleteOptions{}); err != nil {\n\t\t\t\tk8sSuite.T().Logf(\"failed to delete pod %s: %v\", pod.Name, err)\n\t\t\t} else {\n\t\t\t\tk8sSuite.T().Logf(\"deleted pod %s\", pod.Name)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// WaitForK8sNodeReadinessStatus waits for node to have the given status.\n// It retries until the node with the name is found and matches the expected condition.\nfunc (k8sSuite *K8sSuite) WaitForK8sNodeReadinessStatus(ctx context.Context, nodeName string, checkFn func(corev1.ConditionStatus) bool) error {\n\treturn retry.Constant(5 * time.Minute).Retry(func() error {\n\t\treadinessStatus, err := k8sSuite.GetK8sNodeReadinessStatus(ctx, nodeName)\n\t\tif errors.IsNotFound(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif taloskubernetes.IsRetryableError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !checkFn(readinessStatus) {\n\t\t\treturn retry.ExpectedErrorf(\"node readiness status is %s\", readinessStatus)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\n// GetK8sNodeReadinessStatus returns the node readiness status of the node.\nfunc (k8sSuite *K8sSuite) GetK8sNodeReadinessStatus(ctx context.Context, nodeName string) (corev1.ConditionStatus, error) {\n\tnode, err := k8sSuite.Clientset.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor _, condition := range node.Status.Conditions {\n\t\tif condition.Type == corev1.NodeReady {\n\t\t\treturn condition.Status, nil\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"node %s has no readiness condition\", nodeName)\n}\n\n// DeleteResource deletes the resource with the given GroupVersionResource, namespace and name.\n// Does not return an error if the resource is not found.\nfunc (k8sSuite *K8sSuite) DeleteResource(ctx context.Context, gvr schema.GroupVersionResource, ns, name string) error {\n\terr := k8sSuite.DynamicClient.Resource(gvr).Namespace(ns).Delete(ctx, name, metav1.DeleteOptions{})\n\tif errors.IsNotFound(err) {\n\t\treturn nil\n\t}\n\n\treturn err\n}\n\n// EnsureResourceIsDeleted ensures that the resource with the given GroupVersionResource, namespace and name does not exist on Kubernetes.\n// It repeatedly checks the resource for the given duration.\nfunc (k8sSuite *K8sSuite) EnsureResourceIsDeleted(\n\tctx context.Context,\n\tduration time.Duration,\n\tgvr schema.GroupVersionResource,\n\tns, name string,\n) error {\n\treturn retry.Constant(duration).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\t_, err := k8sSuite.DynamicClient.Resource(gvr).Namespace(ns).Get(ctx, name, metav1.GetOptions{})\n\t\tif errors.IsNotFound(err) {\n\t\t\treturn nil\n\t\t}\n\n\t\tif err == nil {\n\t\t\treturn retry.ExpectedErrorf(\"resource %s %s/%s still exists\", gvr, ns, name)\n\t\t}\n\n\t\treturn err\n\t})\n}\n\n// WaitForEventExists waits for the event with the given namespace and check condition to exist on Kubernetes.\nfunc (k8sSuite *K8sSuite) WaitForEventExists(ctx context.Context, ns string, checkFn func(event eventsv1.Event) bool) error {\n\treturn retry.Constant(15*time.Second).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tevents, err := k8sSuite.Clientset.EventsV1().Events(ns).List(ctx, metav1.ListOptions{})\n\n\t\tfilteredEvents := xslices.Filter(events.Items, func(item eventsv1.Event) bool {\n\t\t\treturn checkFn(item)\n\t\t})\n\n\t\tif len(filteredEvents) == 0 {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\ntype podInfo interface {\n\tName() string\n\tWithNodeName(nodeName string) podInfo\n\tWithQuiet(quiet bool) podInfo\n\tWithNamespace(namespace string) podInfo\n\tWithHostVolumeMount(hostPath, mountPath string) podInfo\n\tCreate(ctx context.Context, waitTimeout time.Duration) error\n\tDelete(ctx context.Context) error\n\tExec(ctx context.Context, command string) (string, string, error)\n}\n\ntype pod struct {\n\tname      string\n\tnamespace string\n\tpod       *corev1.Pod\n\tquiet     bool\n\n\tsuite *K8sSuite\n}\n\nfunc (p *pod) Name() string {\n\treturn p.name\n}\n\nfunc (p *pod) WithNodeName(nodeName string) podInfo {\n\tp.pod.Spec.NodeName = nodeName\n\n\treturn p\n}\n\nfunc (p *pod) WithQuiet(quiet bool) podInfo {\n\tp.quiet = quiet\n\n\treturn p\n}\n\nfunc (p *pod) WithNamespace(namespace string) podInfo {\n\tp.namespace = namespace\n\n\treturn p\n}\n\nfunc (p *pod) WithHostVolumeMount(hostPath, mountPath string) podInfo {\n\tname := filepath.Base(hostPath)\n\n\tp.pod.Spec.Volumes = append(p.pod.Spec.Volumes, corev1.Volume{\n\t\tName: name,\n\t\tVolumeSource: corev1.VolumeSource{\n\t\t\tHostPath: &corev1.HostPathVolumeSource{\n\t\t\t\tPath: hostPath,\n\t\t\t\tType: new(corev1.HostPathDirectoryOrCreate),\n\t\t\t},\n\t\t},\n\t})\n\n\tp.pod.Spec.Containers[0].VolumeMounts = append(p.pod.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{\n\t\tName:      name,\n\t\tMountPath: mountPath,\n\t})\n\n\treturn p\n}\n\nfunc (p *pod) Create(ctx context.Context, waitTimeout time.Duration) error {\n\t_, err := p.suite.Clientset.CoreV1().Pods(p.namespace).Create(ctx, p.pod, metav1.CreateOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn p.suite.WaitForPodToBeRunning(ctx, waitTimeout, p.namespace, p.name)\n}\n\nfunc (p *pod) Exec(ctx context.Context, command string) (string, string, error) {\n\tcmd := []string{\n\t\t\"/bin/sh\",\n\t\t\"-c\",\n\t\tcommand,\n\t}\n\treq := p.suite.Clientset.CoreV1().RESTClient().Post().Resource(\"pods\").Name(p.name).\n\t\tNamespace(p.namespace).SubResource(\"exec\")\n\n\toption := &corev1.PodExecOptions{\n\t\tCommand: cmd,\n\t\tStdin:   false,\n\t\tStdout:  true,\n\t\tStderr:  true,\n\t\tTTY:     false,\n\t}\n\n\treq.VersionedParams(\n\t\toption,\n\t\tscheme.ParameterCodec,\n\t)\n\n\twebsocketExec, err := remotecommand.NewWebSocketExecutor(p.suite.RestConfig, \"GET\", req.URL().String())\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\tvar stdout, stderr strings.Builder\n\n\terr = websocketExec.StreamWithContext(ctx, remotecommand.StreamOptions{\n\t\tStdout: &stdout,\n\t\tStderr: &stderr,\n\t})\n\tif err != nil && !p.quiet {\n\t\tp.suite.T().Logf(\n\t\t\t\"error executing command in pod %s/%s: %v\\n\\ncommand %q stdout:\\n%s\\n\\ncommand %q stderr:\\n%s\",\n\t\t\tp.namespace,\n\t\t\tp.name,\n\t\t\terr,\n\t\t\tcommand,\n\t\t\tstdout.String(),\n\t\t\tcommand,\n\t\t\tstderr.String(),\n\t\t)\n\t}\n\n\treturn stdout.String(), stderr.String(), err\n}\n\nfunc (p *pod) Delete(ctx context.Context) error {\n\terr := p.suite.Clientset.CoreV1().Pods(p.namespace).Delete(ctx, p.name, metav1.DeleteOptions{\n\t\tGracePeriodSeconds: new(int64(0)),\n\t})\n\tif err != nil && errors.IsNotFound(err) {\n\t\treturn nil\n\t}\n\n\treturn err\n}\n\n// NewPrivilegedPod creates a new pod definition with a random suffix\n// in the kube-system namespace with privileged security context.\nfunc (k8sSuite *K8sSuite) NewPrivilegedPod(name string) (podInfo, error) {\n\trandomSuffix := make([]byte, 4)\n\n\tif _, err := rand.Read(randomSuffix); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate random suffix: %w\", err)\n\t}\n\n\tpodName := fmt.Sprintf(\"%s-%x\", name, randomSuffix)\n\n\treturn &pod{\n\t\tname:      podName,\n\t\tnamespace: \"kube-system\",\n\t\tpod: &corev1.Pod{\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName: podName,\n\t\t\t},\n\t\t\tSpec: corev1.PodSpec{\n\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  podName,\n\t\t\t\t\t\tImage: \"alpine\",\n\t\t\t\t\t\tCommand: []string{\n\t\t\t\t\t\t\t\"/bin/sh\",\n\t\t\t\t\t\t\t\"-c\",\n\t\t\t\t\t\t\t\"--\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tArgs: []string{\n\t\t\t\t\t\t\t\"trap : TERM INT; (tail -f /dev/null) & wait\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\t\t\t\tPrivileged: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// lvm commands even though executed in the host mount namespace, still need access to /dev 🤷🏼,\n\t\t\t\t\t\t// otherwise lvcreate commands hangs on semop syscall\n\t\t\t\t\t\tVolumeMounts: []corev1.VolumeMount{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"dev\",\n\t\t\t\t\t\t\t\tMountPath: \"/dev\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName:      \"host\",\n\t\t\t\t\t\t\t\tMountPath: \"/host\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVolumes: []corev1.Volume{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"dev\",\n\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &corev1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: \"/dev\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"host\",\n\t\t\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\t\t\tHostPath: &corev1.HostPathVolumeSource{\n\t\t\t\t\t\t\t\tPath: \"/\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tHostNetwork: true,\n\t\t\t\tHostIPC:     true,\n\t\t\t\tHostPID:     true,\n\t\t\t},\n\t\t},\n\n\t\tsuite: k8sSuite,\n\t}, nil\n}\n\n// NewPod creates a new pod definition with a random suffix\n// in the default namespace.\nfunc (k8sSuite *K8sSuite) NewPod(name string) (podInfo, error) {\n\trandomSuffix := make([]byte, 4)\n\n\tif _, err := rand.Read(randomSuffix); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate random suffix: %w\", err)\n\t}\n\n\tpodName := fmt.Sprintf(\"%s-%x\", name, randomSuffix)\n\n\treturn &pod{\n\t\tname:      podName,\n\t\tnamespace: \"default\",\n\t\tpod: &corev1.Pod{\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName: podName,\n\t\t\t},\n\t\t\tSpec: corev1.PodSpec{\n\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  podName,\n\t\t\t\t\t\tImage: \"alpine\",\n\t\t\t\t\t\tCommand: []string{\n\t\t\t\t\t\t\t\"/bin/sh\",\n\t\t\t\t\t\t\t\"-c\",\n\t\t\t\t\t\t\t\"--\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tArgs: []string{\n\t\t\t\t\t\t\t\"trap : TERM INT; (tail -f /dev/null) & wait\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\tsuite: k8sSuite,\n\t}, nil\n}\n\n// WaitForPodToBeRunning waits for the pod with the given namespace and name to be running.\nfunc (k8sSuite *K8sSuite) WaitForPodToBeRunning(ctx context.Context, timeout time.Duration, namespace, podName string) error {\n\tctx, cancel := context.WithTimeout(ctx, timeout)\n\tdefer cancel()\n\n\twatcher, err := k8sSuite.Clientset.CoreV1().Pods(namespace).Watch(ctx, metav1.ListOptions{\n\t\tFieldSelector: fields.OneTermEqualSelector(\"metadata.name\", podName).String(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase event := <-watcher.ResultChan():\n\t\t\tif event.Type == watch.Error {\n\t\t\t\treturn fmt.Errorf(\"error watching pod: %v\", event.Object)\n\t\t\t}\n\n\t\t\tpod, ok := event.Object.(*corev1.Pod)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif pod.Name == podName && pod.Status.Phase == corev1.PodRunning {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n\n// WaitForDeploymentAvailable waits for the deployment with the given namespace and name to be running with the requested replicas.\nfunc (k8sSuite *K8sSuite) WaitForDeploymentAvailable(ctx context.Context, timeout time.Duration, namespace, deplName string, replicas int32) error {\n\tctx, cancel := context.WithTimeout(ctx, timeout)\n\tdefer cancel()\n\n\twatcher, err := k8sSuite.Clientset.AppsV1().Deployments(namespace).Watch(ctx, metav1.ListOptions{\n\t\tFieldSelector: fields.OneTermEqualSelector(\"metadata.name\", deplName).String(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer watcher.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase event := <-watcher.ResultChan():\n\t\t\tif event.Type == watch.Error {\n\t\t\t\treturn fmt.Errorf(\"error watching deployment: %v\", event.Object)\n\t\t\t}\n\n\t\t\tdeployment, ok := event.Object.(*appsv1.Deployment)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif deployment.Name == deplName && deployment.Status.AvailableReplicas == replicas {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n\n// LogPodLogsByLabel logs the logs of the pod with the given namespace and label.\nfunc (k8sSuite *K8sSuite) LogPodLogsByLabel(ctx context.Context, namespace, label, value string) {\n\tctx, cancel := context.WithTimeout(ctx, time.Minute)\n\tdefer cancel()\n\n\tpodList, err := k8sSuite.Clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: fmt.Sprintf(\"%s=%s\", label, value),\n\t})\n\tk8sSuite.Require().NoError(err)\n\n\tfor _, pod := range podList.Items {\n\t\tk8sSuite.LogPodLogs(ctx, namespace, pod.Name)\n\t}\n}\n\n// LogPodLogs logs the logs of the pod with the given namespace and name.\nfunc (k8sSuite *K8sSuite) LogPodLogs(ctx context.Context, namespace, podName string) {\n\tctx, cancel := context.WithTimeout(ctx, time.Minute)\n\tdefer cancel()\n\n\treq := k8sSuite.Clientset.CoreV1().Pods(namespace).GetLogs(podName, &corev1.PodLogOptions{})\n\n\treadCloser, err := req.Stream(ctx)\n\tif err != nil {\n\t\tk8sSuite.T().Logf(\"failed to get pod logs: %s\", err)\n\t}\n\n\tdefer readCloser.Close() //nolint:errcheck\n\n\tscanner := bufio.NewScanner(readCloser)\n\n\tfor scanner.Scan() {\n\t\tk8sSuite.T().Logf(\"%s/%s: %s\", namespace, podName, scanner.Text())\n\t}\n}\n\n// HelmInstall installs the Helm chart with the given namespace, repository, version, release name, chart name and values.\nfunc (k8sSuite *K8sSuite) HelmInstall(ctx context.Context, namespace, repository, version, releaseName, chartName string, valuesBytes []byte) error {\n\ttempFile := filepath.Join(k8sSuite.T().TempDir(), \"values.yaml\")\n\n\tif err := os.WriteFile(tempFile, valuesBytes, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tdefer os.Remove(tempFile) //nolint:errcheck\n\n\targs := []string{\n\t\t\"upgrade\",\n\t\t\"--install\",\n\t\t\"--cleanup-on-fail\",\n\t\t\"--create-namespace\",\n\t\t\"--namespace\",\n\t\tnamespace,\n\t\t\"--wait\",\n\t\t\"--timeout\",\n\t\tk8sSuite.CSITestTimeout,\n\t\t\"--repo\",\n\t\trepository,\n\t\t\"--version\",\n\t\tversion,\n\t\t\"--values\",\n\t\ttempFile,\n\t\treleaseName,\n\t\tchartName,\n\t}\n\n\tcmd := exec.CommandContext(k8sSuite.T().Context(), k8sSuite.HelmPath, args...)\n\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\tk8sSuite.T().Logf(\"running helm command: %s\", strings.Join(cmd.Args, \" \"))\n\n\treturn cmd.Run()\n}\n\n// WaitForResource waits for the resource with the given group, kind, version, namespace and jsonpath field selector to have the given expected value.\n// mostly a restructuring of `kubectl wait` from https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/wait/wait.go\n//\n//nolint:gocyclo\nfunc (k8sSuite *K8sSuite) WaitForResource(ctx context.Context, namespace, group, kind, version, resourceName, jsonPathSelector, expectedValue string) error {\n\tj := jsonpath.New(\"wait\").AllowMissingKeys(true)\n\n\tif jsonPathSelector == \"\" {\n\t\treturn fmt.Errorf(\"jsonpath condition is empty\")\n\t}\n\n\tif err := j.Parse(jsonPathSelector); err != nil {\n\t\treturn fmt.Errorf(\"error parsing jsonpath condition: %v\", err)\n\t}\n\n\tmapping, err := k8sSuite.Mapper.RESTMapping(schema.GroupKind{\n\t\tGroup: group,\n\t\tKind:  kind,\n\t}, version)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating mapping for resource %s/%s/%s\", group, kind, version)\n\t}\n\n\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(namespace)\n\n\tfieldSelector := fields.OneTermEqualSelector(\"metadata.name\", resourceName).String()\n\n\tlw := &cache.ListWatch{\n\t\tListFunc: func(options metav1.ListOptions) (runtime.Object, error) {\n\t\t\toptions.FieldSelector = fieldSelector\n\n\t\t\treturn dr.List(ctx, options)\n\t\t},\n\t\tWatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {\n\t\t\toptions.FieldSelector = fieldSelector\n\n\t\t\treturn dr.Watch(ctx, options)\n\t\t},\n\t}\n\n\tpreconditionFunc := func(store cache.Store) (bool, error) {\n\t\tvar exists bool\n\n\t\t_, exists, err = store.Get(&metav1.ObjectMeta{Namespace: namespace, Name: resourceName})\n\t\tif err != nil {\n\t\t\treturn true, err\n\t\t}\n\n\t\tif !exists {\n\t\t\treturn true, errors.NewNotFound(mapping.Resource.GroupResource(), resourceName)\n\t\t}\n\n\t\treturn false, nil\n\t}\n\tif _, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, preconditionFunc, func(event watch.Event) (bool, error) {\n\t\tobj, ok := event.Object.(*unstructured.Unstructured)\n\t\tif !ok {\n\t\t\treturn false, fmt.Errorf(\"error converting object to unstructured\")\n\t\t}\n\n\t\tqueryObj := obj.UnstructuredContent()\n\n\t\tk8sSuite.T().Logf(\"waiting for resource %s/%s/%s/%s to have field %s with value %s\", group, version, kind, resourceName, jsonPathSelector, expectedValue)\n\n\t\tparseResults, err := j.FindResults(queryObj)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error finding results: %v\", err)\n\t\t}\n\n\t\tif len(parseResults) == 0 || len(parseResults[0]) == 0 {\n\t\t\treturn false, nil\n\t\t}\n\n\t\tif len(parseResults) > 1 {\n\t\t\treturn false, fmt.Errorf(\"given jsonpath expression matches more than one list\")\n\t\t}\n\n\t\tif len(parseResults[0]) > 1 {\n\t\t\treturn false, fmt.Errorf(\"given jsonpath expression matches more than one value\")\n\t\t}\n\n\t\tswitch parseResults[0][0].Interface().(type) {\n\t\tcase map[string]any, []any:\n\t\t\treturn false, fmt.Errorf(\"jsonpath leads to a nested object or list which is not supported\")\n\t\t}\n\n\t\ts := fmt.Sprintf(\"%v\", parseResults[0][0].Interface())\n\n\t\treturn strings.TrimSpace(s) == strings.TrimSpace(expectedValue), nil\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// WaitForResourceToBeAvailable waits for the resource with the given namespace, group, kind, version and name to be available.\nfunc (k8sSuite *K8sSuite) WaitForResourceToBeAvailable(ctx context.Context, duration time.Duration, namespace, group, kind, version, resourceName string) error {\n\treturn retry.Constant(duration).Retry(func() error {\n\t\tmapping, err := k8sSuite.Mapper.RESTMapping(schema.GroupKind{\n\t\t\tGroup: group,\n\t\t\tKind:  kind,\n\t\t}, version)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating mapping for resource %s/%s/%s\", group, kind, version)\n\t\t}\n\n\t\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(namespace)\n\n\t\t_, err = dr.Get(ctx, resourceName, metav1.GetOptions{})\n\t\tif errors.IsNotFound(err) {\n\t\t\tk8sSuite.T().Logf(\"resource %s/%s/%s/%s not found, retrying\", group, version, kind, resourceName)\n\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t})\n}\n\n// GetUnstructuredResource gets the unstructured resource with the given namespace, group, kind, version and name.\nfunc (k8sSuite *K8sSuite) GetUnstructuredResource(ctx context.Context, namespace, group, kind, version, resourceName string) (*unstructured.Unstructured, error) {\n\tmapping, err := k8sSuite.Mapper.RESTMapping(schema.GroupKind{\n\t\tGroup: group,\n\t\tKind:  kind,\n\t}, version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating mapping for resource %s/%s/%s\", group, kind, version)\n\t}\n\n\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(namespace)\n\n\tresult, err := dr.Get(ctx, resourceName, metav1.GetOptions{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting resource %s/%s/%s/%s: %v\", group, version, kind, resourceName, err)\n\t}\n\n\treturn result, nil\n}\n\n// RunFIOTest runs the FIO test with the given storage class and size using kubestr.\nfunc (k8sSuite *K8sSuite) RunFIOTest(ctx context.Context, storageClass, size string) error {\n\targs := []string{\n\t\t\"--outfile\",\n\t\tfmt.Sprintf(\"/tmp/fio-%s.json\", storageClass),\n\t\t\"--output\",\n\t\t\"json\",\n\t\t\"fio\",\n\t\t\"--storageclass\",\n\t\tstorageClass,\n\t\t\"--size\",\n\t\tsize,\n\t}\n\n\tcmd := exec.CommandContext(k8sSuite.T().Context(), k8sSuite.KubeStrPath, args...)\n\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\tk8sSuite.T().Logf(\"running kubestr command: %s\", strings.Join(cmd.Args, \" \"))\n\n\treturn cmd.Run()\n}\n\n// GetPodsWithLabel returns the pods with the given label in the specified namespace.\nfunc (k8sSuite *K8sSuite) GetPodsWithLabel(ctx context.Context, namespace, label string) (*corev1.PodList, error) {\n\tpodList, err := k8sSuite.Clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: label,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn podList, nil\n}\n\n// ParseManifests parses YAML manifest bytes into unstructured objects.\nfunc (k8sSuite *K8sSuite) ParseManifests(manifests []byte) []unstructured.Unstructured {\n\treader := yaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(manifests)))\n\n\tvar parsedManifests []unstructured.Unstructured\n\n\tfor {\n\t\tyamlManifest, err := reader.Read()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tk8sSuite.Require().NoError(err)\n\t\t}\n\n\t\tyamlManifest = bytes.TrimSpace(yamlManifest)\n\n\t\tif len(yamlManifest) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tjsonManifest, err := yaml.ToJSON(yamlManifest)\n\t\tif err != nil {\n\t\t\tk8sSuite.Require().NoError(err, \"error converting manifest to JSON\")\n\t\t}\n\n\t\tif bytes.Equal(jsonManifest, []byte(\"null\")) || bytes.Equal(jsonManifest, []byte(\"{}\")) {\n\t\t\t// skip YAML docs which contain only comments\n\t\t\tcontinue\n\t\t}\n\n\t\tvar obj unstructured.Unstructured\n\n\t\tif err = json.Unmarshal(jsonManifest, &obj); err != nil {\n\t\t\tk8sSuite.Require().NoError(err, \"error loading JSON manifest into unstructured\")\n\t\t}\n\n\t\tparsedManifests = append(parsedManifests, obj)\n\t}\n\n\treturn parsedManifests\n}\n\n// ApplyManifests applies the given manifests to the Kubernetes cluster.\nfunc (k8sSuite *K8sSuite) ApplyManifests(ctx context.Context, manifests []unstructured.Unstructured) {\n\tfor _, obj := range manifests {\n\t\tmapping, err := k8sSuite.Mapper.RESTMapping(obj.GetObjectKind().GroupVersionKind().GroupKind(), obj.GetObjectKind().GroupVersionKind().Version)\n\t\tif err != nil {\n\t\t\tk8sSuite.Require().NoError(err, \"error creating mapping for object %s\", obj.GetName())\n\t\t}\n\n\t\tif obj.GetNamespace() == \"\" {\n\t\t\tk8sSuite.T().Logf(\"namespace not set for object %s, kind %s\", obj.GetName(), obj.GetObjectKind().GroupVersionKind())\n\t\t}\n\n\t\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(obj.GetNamespace())\n\n\t\t_, err = dr.Apply(ctx, obj.GetName(), &obj, metav1.ApplyOptions{\n\t\t\tFieldManager: \"talos-e2e\",\n\t\t})\n\t\tk8sSuite.Require().NoError(err, \"error creating object %s\", obj.GetName())\n\n\t\tk8sSuite.T().Logf(\"created object %s/%s/%s\", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName())\n\t}\n}\n\n// DeleteManifests deletes the given manifests from the Kubernetes cluster.\nfunc (k8sSuite *K8sSuite) DeleteManifests(ctx context.Context, manifests []unstructured.Unstructured) {\n\t// process in reverse orderd\n\tmanifests = slices.Clone(manifests)\n\tslices.Reverse(manifests)\n\n\tfor _, obj := range manifests {\n\t\tmapping, err := k8sSuite.Mapper.RESTMapping(obj.GetObjectKind().GroupVersionKind().GroupKind(), obj.GetObjectKind().GroupVersionKind().Version)\n\t\tif err != nil {\n\t\t\tk8sSuite.Require().NoError(err, \"error creating mapping for object %s\", obj.GetName())\n\t\t}\n\n\t\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(obj.GetNamespace())\n\n\t\terr = dr.Delete(ctx, obj.GetName(), metav1.DeleteOptions{})\n\t\tif errors.IsNotFound(err) {\n\t\t\tcontinue\n\t\t}\n\n\t\tk8sSuite.Require().NoError(err, \"error deleting object %s\", obj.GetName())\n\n\t\t// wait for the object to be deleted\n\t\tfieldSelector := fields.OneTermEqualSelector(\"metadata.name\", obj.GetName()).String()\n\t\tlw := &cache.ListWatch{\n\t\t\tListFunc: func(options metav1.ListOptions) (runtime.Object, error) {\n\t\t\t\toptions.FieldSelector = fieldSelector\n\n\t\t\t\treturn dr.List(ctx, options)\n\t\t\t},\n\t\t\tWatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {\n\t\t\t\toptions.FieldSelector = fieldSelector\n\n\t\t\t\treturn dr.Watch(ctx, options)\n\t\t\t},\n\t\t}\n\n\t\tpreconditionFunc := func(store cache.Store) (bool, error) {\n\t\t\tvar exists bool\n\n\t\t\t_, exists, err = store.Get(&metav1.ObjectMeta{Namespace: obj.GetNamespace(), Name: obj.GetName()})\n\t\t\tif err != nil {\n\t\t\t\treturn true, err\n\t\t\t}\n\n\t\t\tif !exists {\n\t\t\t\t// since we're looking for it to disappear we just return here if it no longer exists\n\t\t\t\treturn true, nil\n\t\t\t}\n\n\t\t\treturn false, nil\n\t\t}\n\n\t\t_, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, preconditionFunc, func(event watch.Event) (bool, error) {\n\t\t\treturn event.Type == watch.Deleted, nil\n\t\t})\n\n\t\tk8sSuite.Require().NoError(err, \"error waiting for the object to be deleted %s/%s/%s\", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName())\n\n\t\tk8sSuite.T().Logf(\"deleted object %s/%s/%s\", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName())\n\t}\n}\n\n// PatchK8sObject patches the kubernetes object with the given namespace, group, kind, version and name.\nfunc (k8sSuite *K8sSuite) PatchK8sObject(ctx context.Context, namespace, group, kind, version, resourceName string, patchBytes []byte) {\n\tpatchBytes, err := yaml.ToJSON(patchBytes)\n\tk8sSuite.Require().NoError(err, \"error converting patch to JSON\")\n\n\tmapping, err := k8sSuite.Mapper.RESTMapping(schema.GroupKind{\n\t\tGroup: group,\n\t\tKind:  kind,\n\t}, version)\n\n\tk8sSuite.Require().NoError(err, \"error creating mapping for resource %s/%s/%s\", group, kind, version)\n\n\tdr := k8sSuite.DynamicClient.Resource(mapping.Resource).Namespace(namespace)\n\n\t_, err = dr.Patch(ctx, resourceName, types.MergePatchType, patchBytes, metav1.PatchOptions{})\n\tk8sSuite.Require().NoError(err, \"error patching resource %s/%s/%s/%s\", group, version, kind, resourceName)\n}\n\n// ToUnstructured converts the given runtime.Object to unstructured.Unstructured.\nfunc (k8sSuite *K8sSuite) ToUnstructured(obj runtime.Object) unstructured.Unstructured {\n\tunstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)\n\tif err != nil {\n\t\tk8sSuite.Require().NoError(err, \"error converting object to unstructured\")\n\t}\n\n\tu := unstructured.Unstructured{Object: unstructuredObj}\n\tu.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind())\n\n\treturn u\n}\n\n// SetupNodeInformer sets up a node informer for the given node name.\nfunc (k8sSuite *K8sSuite) SetupNodeInformer(ctx context.Context, nodeName string) <-chan *corev1.Node {\n\tconst metadataKeyName = \"metadata.name=\"\n\n\twatchCh := make(chan *corev1.Node)\n\n\tinformerFactory := informers.NewSharedInformerFactoryWithOptions(\n\t\tk8sSuite.Clientset, constants.KubernetesInformerDefaultResyncPeriod,\n\t\tinformers.WithTweakListOptions(func(options *metav1.ListOptions) {\n\t\t\toptions.FieldSelector = metadataKeyName + nodeName\n\t\t}),\n\t)\n\n\tnodeInformer := informerFactory.Core().V1().Nodes().Informer()\n\t_, err := nodeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc: func(obj any) {\n\t\t\tnode, ok := obj.(*corev1.Node)\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tchannel.SendWithContext(ctx, watchCh, node)\n\t\t},\n\t\tUpdateFunc: func(_, obj any) {\n\t\t\tnode, ok := obj.(*corev1.Node)\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tchannel.SendWithContext(ctx, watchCh, node)\n\t\t},\n\t})\n\tk8sSuite.Require().NoError(err)\n\n\tinformerFactory.Start(ctx.Done())\n\tk8sSuite.T().Cleanup(informerFactory.Shutdown)\n\n\tresult := informerFactory.WaitForCacheSync(ctx.Done())\n\n\tfor k, v := range result {\n\t\tk8sSuite.Assert().True(v, \"informer %q failed to sync\", k.String())\n\t}\n\n\treturn watchCh\n}\n"
  },
  {
    "path": "internal/integration/base/run.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage base\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// RunOption configures options for Run.\ntype RunOption func(*runOptions)\n\n// MatchFunc runs against output (stdout or stderr).\ntype MatchFunc func(output string) error\n\ntype runOptions struct {\n\tretryer               retry.Retryer\n\tstdin                 io.Reader\n\tshouldFail            bool\n\tstdoutEmpty           bool\n\tstderrNotEmpty        bool\n\tstdoutRegexps         []*regexp.Regexp\n\tstdoutNegativeRegexps []*regexp.Regexp\n\tstderrRegexps         []*regexp.Regexp\n\tstderrNegativeRegexps []*regexp.Regexp\n\tstdoutMatchers        []MatchFunc\n\tstderrMatchers        []MatchFunc\n}\n\n// WithRetry retries failing command runs.\nfunc WithRetry(retryer retry.Retryer) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.retryer = retryer\n\t}\n}\n\n// WithStdin sets stdin for the command.\nfunc WithStdin(r io.Reader) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stdin = r\n\t}\n}\n\n// ShouldFail tells run command should fail (with non-empty stderr).\n//\n// ShouldFail also sets StdErrNotEmpty.\nfunc ShouldFail() RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.shouldFail = true\n\t\topts.stderrNotEmpty = true\n\t}\n}\n\n// StdoutEmpty tells run that stdout of the command should be empty.\nfunc StdoutEmpty() RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stdoutEmpty = true\n\t}\n}\n\n// StderrNotEmpty tells run that stderr of the command should not be empty.\nfunc StderrNotEmpty() RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stderrNotEmpty = true\n\t}\n}\n\n// StdoutShouldMatch appends to the set of regexps stdout contents should match.\nfunc StdoutShouldMatch(r *regexp.Regexp) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stdoutRegexps = append(opts.stdoutRegexps, r)\n\t}\n}\n\n// StdoutShouldNotMatch appends to the set of regexps stdout contents should not match.\nfunc StdoutShouldNotMatch(r *regexp.Regexp) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stdoutNegativeRegexps = append(opts.stdoutNegativeRegexps, r)\n\t}\n}\n\n// StderrShouldMatch appends to the set of regexps stderr contents should match.\n//\n// StderrShouldMatch also sets StdErrNotEmpty.\nfunc StderrShouldMatch(r *regexp.Regexp) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stderrRegexps = append(opts.stderrRegexps, r)\n\t\topts.stderrNotEmpty = true\n\t}\n}\n\n// StderrShouldNotMatch appends to the set of regexps stderr contents should not match.\nfunc StderrShouldNotMatch(r *regexp.Regexp) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stderrNegativeRegexps = append(opts.stderrNegativeRegexps, r)\n\t}\n}\n\n// StdoutMatchFunc appends to the list of MatchFuncs to run against stdout.\nfunc StdoutMatchFunc(f MatchFunc) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stdoutMatchers = append(opts.stdoutMatchers, f)\n\t}\n}\n\n// StderrMatchFunc appends to the list of MatchFuncs to run against stderr.\nfunc StderrMatchFunc(f MatchFunc) RunOption {\n\treturn func(opts *runOptions) {\n\t\topts.stderrMatchers = append(opts.stderrMatchers, f)\n\t}\n}\n\n// runAndWait launches the command and waits for completion.\n//\n// runAndWait doesn't do any assertions on result.\nfunc runAndWait(t *testing.T, cmd *exec.Cmd, stdin io.Reader) (stdoutBuf, stderrBuf *bytes.Buffer, err error) {\n\tvar stdout, stderr bytes.Buffer\n\n\tcmd.Stdin = stdin\n\tcmd.Stdout = &stdout\n\tcmd.Stderr = &stderr\n\tcmd.Env = []string{}\n\n\t// filter environment variables\n\tfor _, keyvalue := range os.Environ() {\n\t\tname, _, ok := strings.Cut(keyvalue, \"=\")\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch strings.ToUpper(name) {\n\t\tcase \"PATH\":\n\t\t\tfallthrough\n\t\tcase \"HOME\":\n\t\t\tfallthrough\n\t\tcase \"USERNAME\":\n\t\t\tcmd.Env = append(cmd.Env, keyvalue)\n\t\t}\n\t}\n\n\tt.Logf(\"Running %q\", strings.Join(cmd.Args, \" \"))\n\n\trequire.NoError(t, cmd.Start())\n\n\terr = cmd.Wait()\n\n\treturn &stdout, &stderr, err\n}\n\n// retryRunAndWait retries runAndWait if the command fails to run.\nfunc retryRunAndWait(t *testing.T, cmdFunc func() *exec.Cmd, retryer retry.Retryer, stdin io.Reader) (stdoutBuf, stderrBuf *bytes.Buffer, err error) {\n\terr = retryer.Retry(func() error {\n\t\tstdoutBuf, stderrBuf, err = runAndWait(t, cmdFunc(), stdin)\n\n\t\tvar exitError *exec.ExitError\n\t\tif errors.As(err, &exitError) {\n\t\t\treturn retry.ExpectedErrorf(\"command failed, stderr %v: %w\", stderrBuf.String(), err)\n\t\t}\n\n\t\treturn err\n\t})\n\n\treturn stdoutBuf, stderrBuf, err\n}\n\n// run executes command, asserts on its exit status/output, and returns stdout.\n//\n//nolint:gocyclo,nakedret\nfunc run(t *testing.T, cmdFunc func() *exec.Cmd, options ...RunOption) (stdout, stderr string) {\n\tvar opts runOptions\n\n\tfor _, o := range options {\n\t\to(&opts)\n\t}\n\n\tvar (\n\t\tstdoutBuf, stderrBuf *bytes.Buffer\n\t\terr                  error\n\t)\n\n\tif opts.retryer != nil {\n\t\tstdoutBuf, stderrBuf, err = retryRunAndWait(t, cmdFunc, opts.retryer, opts.stdin)\n\t} else {\n\t\tstdoutBuf, stderrBuf, err = runAndWait(t, cmdFunc(), opts.stdin)\n\t}\n\n\tif err != nil {\n\t\t// check that command failed, not something else happened\n\t\tvar exitError *exec.ExitError\n\n\t\trequire.True(t, errors.As(err, &exitError), \"%s\", err)\n\t}\n\n\tif stdoutBuf != nil {\n\t\tstdout = stdoutBuf.String()\n\t}\n\n\tif stderrBuf != nil {\n\t\tstderr = stderrBuf.String()\n\t}\n\n\tif opts.shouldFail {\n\t\tassert.Error(t, err, \"command expected to fail, but did not\")\n\t} else {\n\t\tassert.NoError(t, err, \"command failed, stdout: %q, stderr: %q\", stdout, stderr)\n\t}\n\n\tif opts.stdoutEmpty {\n\t\tassert.Empty(t, stdout, \"stdout should be empty\")\n\t} else {\n\t\tassert.NotEmpty(t, stdout, \"stdout should be not empty\")\n\t}\n\n\tif opts.stderrNotEmpty {\n\t\tassert.NotEmpty(t, stderr, \"stderr should be not empty\")\n\t} else {\n\t\tassert.Empty(t, stderr, \"stderr should be empty\")\n\t}\n\n\tfor _, rx := range opts.stdoutRegexps {\n\t\tassert.Regexp(t, rx, stdout)\n\t}\n\n\tfor _, rx := range opts.stderrRegexps {\n\t\tassert.Regexp(t, rx, stderr)\n\t}\n\n\tfor _, rx := range opts.stdoutNegativeRegexps {\n\t\tassert.NotRegexp(t, rx, stdout)\n\t}\n\n\tfor _, rx := range opts.stderrNegativeRegexps {\n\t\tassert.NotRegexp(t, rx, stderr)\n\t}\n\n\tfor _, f := range opts.stdoutMatchers {\n\t\tassert.NoError(t, f(stdout), \"stdout match: %q\", stdout)\n\t}\n\n\tfor _, f := range opts.stderrMatchers {\n\t\tassert.NoError(t, f(stderr), \"stderr match: %q\", stderr)\n\t}\n\n\treturn stdout, stderr\n}\n"
  },
  {
    "path": "internal/integration/cli/apply-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t_ \"embed\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// ApplyConfigSuite verifies dmesg command.\ntype ApplyConfigSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ApplyConfigSuite) SuiteName() string {\n\treturn \"cli.ApplyConfigSuite\"\n}\n\n//go:embed testdata/patches/dummy-ap.yaml\nvar dummyAPPatch []byte\n\n//go:embed testdata/patches/delete-dummy-ap.yaml\nvar deleteDummyAPPatch []byte\n\n// TestApplyWithPatch verifies that .\nfunc (suite *ApplyConfigSuite) TestApplyWithPatch() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skipping if cluster is not qemu/docker\")\n\t}\n\n\ttmpDir := suite.T().TempDir()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tdata, _ := suite.RunCLI([]string{\"get\", \"--nodes\", node, \"mc\", \"v1alpha1\", \"-o\", \"jsonpath={.spec}\"})\n\n\tconfigPath := filepath.Join(tmpDir, \"config.yaml\")\n\tsuite.Require().NoError(os.WriteFile(configPath, []byte(data), 0o777))\n\n\tpatchPath := filepath.Join(tmpDir, \"patch.yaml\")\n\tsuite.Require().NoError(os.WriteFile(patchPath, dummyAPPatch, 0o777))\n\n\tsuite.RunCLI([]string{\"apply-config\", \"--nodes\", node, \"--config-patch\", patchPath, \"-f\", configPath},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(\"Applied configuration without a reboot\")),\n\t)\n\n\t// sleep a bit to let the config propagate\n\ttime.Sleep(1 * time.Second)\n\n\tsuite.RunCLI([]string{\"get\", \"--nodes\", node, \"links\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"dummy-ap-patch\")),\n\t)\n\n\t// now delete the dummy-ap-patch\n\tdata, _ = suite.RunCLI([]string{\"get\", \"--nodes\", node, \"mc\", \"v1alpha1\", \"-o\", \"jsonpath={.spec}\"})\n\tsuite.Require().NoError(os.WriteFile(configPath, []byte(data), 0o777))\n\n\tsuite.Require().NoError(os.WriteFile(patchPath, deleteDummyAPPatch, 0o777))\n\n\tsuite.RunCLI([]string{\"apply-config\", \"--nodes\", node, \"--config-patch\", patchPath, \"-f\", configPath},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(\"Applied configuration without a reboot\")),\n\t)\n\n\t// sleep a bit to let the config propagate\n\ttime.Sleep(1 * time.Second)\n\n\tsuite.RunCLI([]string{\"get\", \"--nodes\", node, \"links\"},\n\t\tbase.StdoutShouldNotMatch(regexp.MustCompile(\"dummy-ap-patch\")),\n\t\tbase.WithRetry(retry.Constant(15*time.Second, retry.WithUnits(time.Second))),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ApplyConfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/cgroups.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// CgroupsSuite verifies dmesg command.\ntype CgroupsSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *CgroupsSuite) SuiteName() string {\n\treturn \"cli.CgroupsSuite\"\n}\n\n// TestPresets verifies successful execution.\nfunc (suite *CgroupsSuite) TestPresets() {\n\tfor _, preset := range []string{\"cpu\", \"cpuset\", \"io\", \"memory\", \"process\", \"swap\"} {\n\t\tsuite.Run(preset, func() {\n\t\t\tsuite.RunCLI(\n\t\t\t\t[]string{\n\t\t\t\t\t\"cgroups\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(),\n\t\t\t\t\t\"--preset\", preset,\n\t\t\t\t},\n\t\t\t\tbase.StdoutShouldMatch(regexp.MustCompile(`apid`)))\n\t\t})\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(CgroupsSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/cli.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package cli provides CLI (talosctl) integration tests for Talos\npackage cli\n\nimport \"github.com/stretchr/testify/suite\"\n\nvar allSuites []suite.TestingSuite\n\n// GetAllSuites returns all the suites for CLI test.\n//\n// Depending on build tags, this might return different lists.\nfunc GetAllSuites() []suite.TestingSuite {\n\treturn allSuites\n}\n"
  },
  {
    "path": "internal/integration/cli/completion.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// CompletionSuite verifies dmesg command.\ntype CompletionSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *CompletionSuite) SuiteName() string {\n\treturn \"cli.CompletionSuite\"\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *CompletionSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"completion\", \"bash\"})\n\tsuite.RunCLI([]string{\"completion\", \"fish\"})\n\tsuite.RunCLI([]string{\"completion\", \"zsh\"})\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(CompletionSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"encoding/json\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// TalosconfigSuite checks `talosctl config`.\ntype TalosconfigSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName implements base.NamedSuite.\nfunc (suite *TalosconfigSuite) SuiteName() string {\n\treturn \"cli.TalosconfigSuite\"\n}\n\n// TestList checks `talosctl config contexts`.\nfunc (suite *TalosconfigSuite) TestList() {\n\tsuite.RunCLI([]string{\"config\", \"contexts\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`CURRENT`)))\n}\n\n// TestInfo checks `talosctl config info`.\nfunc (suite *TalosconfigSuite) TestInfo() {\n\tsuite.RunCLI([]string{\"config\", \"info\"}, // TODO: remove 10 years once the CABPT & TF providers are updated to 1.5.2+\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`(1 year|10 years) from now`)))\n\n\tsuite.RunCLI([]string{\"config\", \"info\", \"--output\", \"text\"}, // TODO: remove 10 years once the CABPT & TF providers are updated to 1.5.2+\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`(1 year|10 years) from now`)))\n\n\tsuite.RunCLI([]string{\"config\", \"info\", \"--output\", \"yaml\"},\n\t\tbase.StdoutMatchFunc(func(stdout string) error {\n\t\t\tvar out map[string]any\n\n\t\t\terr := yaml.Unmarshal([]byte(stdout), &out)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsuite.Assert().Contains(out, \"endpoints\")\n\t\t\tsuite.Assert().Contains(out, \"nodes\")\n\t\t\tsuite.Assert().Contains(out, \"roles\")\n\t\t\tsuite.Assert().Contains(out, \"context\")\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tsuite.RunCLI([]string{\"config\", \"info\", \"--output\", \"json\"},\n\t\tbase.StdoutMatchFunc(func(stdout string) error {\n\t\t\tvar out map[string]any\n\n\t\t\terr := json.Unmarshal([]byte(stdout), &out)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsuite.Assert().Contains(out, \"endpoints\")\n\t\t\tsuite.Assert().Contains(out, \"nodes\")\n\t\t\tsuite.Assert().Contains(out, \"roles\")\n\t\t\tsuite.Assert().Contains(out, \"context\")\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tsuite.RunCLI([]string{\"config\", \"info\", \"--output\", \"table\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.ShouldFail(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`unknown output format: \"table\"`)),\n\t)\n}\n\n// TestMerge checks `talosctl config merge`.\nfunc (suite *TalosconfigSuite) TestMerge() {\n\ttempDir := suite.T().TempDir()\n\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"-o\", tempDir, \"foo\", \"https://192.168.0.1:6443\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\ttalosconfigPath := filepath.Join(tempDir, \"talosconfig\")\n\n\tsuite.Assert().FileExists(talosconfigPath)\n\n\tpath := filepath.Join(tempDir, \"merged\")\n\n\tsuite.RunCLI([]string{\"config\", \"merge\", \"--talosconfig\", path, talosconfigPath},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Require().FileExists(path)\n\n\tc, err := clientconfig.Open(path)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NotNil(c.Contexts[\"foo\"])\n\n\tsuite.RunCLI([]string{\"config\", \"merge\", \"--talosconfig\", path, talosconfigPath},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`renamed`)),\n\t)\n\n\tc, err = clientconfig.Open(path)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NotNil(c.Contexts[\"foo-1\"])\n}\n\n// TestNewTTL checks `talosctl config new --crt-ttl`.\nfunc (suite *TalosconfigSuite) TestNewTTL() {\n\ttempDir := suite.T().TempDir()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\ttalosconfig := filepath.Join(tempDir, \"talosconfig\")\n\tsuite.RunCLI([]string{\"--nodes\", node, \"config\", \"new\", \"--roles\", \"os:reader\", talosconfig, \"--crt-ttl\", \"17520h\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"config\", \"info\", \"--talosconfig\", talosconfig},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`2 years from now`)))\n}\n\n// TestNew checks `talosctl config new`.\nfunc (suite *TalosconfigSuite) TestNew() {\n\tstdout, _ := suite.RunCLI([]string{\"version\", \"--json\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()})\n\n\tvar v machineapi.Version\n\n\terr := protojson.Unmarshal([]byte(stdout), &v)\n\tsuite.Require().NoError(err)\n\n\trbacEnabled := v.Features.GetRbac()\n\n\ttempDir := suite.T().TempDir()\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\treaderConfig := filepath.Join(tempDir, \"readerconfig\")\n\tsuite.RunCLI([]string{\"--nodes\", node, \"config\", \"new\", \"--roles\", \"os:reader\", readerConfig},\n\t\tbase.StdoutEmpty())\n\n\toperatorConfig := filepath.Join(tempDir, \"operatorconfig\")\n\tsuite.RunCLI([]string{\"--nodes\", node, \"config\", \"new\", \"--roles\", \"os:operator\", operatorConfig},\n\t\tbase.StdoutEmpty())\n\n\t// commands that work for admin, operator and reader, with and without RBAC\n\tfor _, tt := range []struct {\n\t\targs []string\n\t\topts []base.RunOption\n\t}{\n\t\t{\n\t\t\targs: []string{\"ls\", \"/etc/hosts\"},\n\t\t\topts: []base.RunOption{base.StdoutShouldMatch(regexp.MustCompile(`hosts`))},\n\t\t},\n\t} {\n\t\tname := strings.Join(tt.args, \"_\")\n\t\tsuite.Run(name, func() {\n\t\t\tfor _, config := range []string{readerConfig, operatorConfig} {\n\t\t\t\targs := append([]string{\"--nodes\", node}, tt.args...)\n\t\t\t\tsuite.RunCLI(args, tt.opts...)\n\n\t\t\t\targs = append([]string{\"--talosconfig\", config}, args...)\n\t\t\t\tsuite.RunCLI(args, tt.opts...)\n\t\t\t}\n\t\t})\n\t}\n\n\t// commands that work for admin, but not for reader&operator (when RBAC is enabled)\n\tfor _, tt := range []struct {\n\t\targs        []string\n\t\tadminOpts   []base.RunOption\n\t\tnonprivOpts []base.RunOption\n\t}{\n\t\t{\n\t\t\targs:      []string{\"read\", \"/etc/hosts\"},\n\t\t\tadminOpts: []base.RunOption{base.StdoutShouldMatch(regexp.MustCompile(`localhost`))},\n\t\t\tnonprivOpts: []base.RunOption{\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t\tbase.ShouldFail(),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\targs:      []string{\"get\", \"mc\"},\n\t\t\tadminOpts: []base.RunOption{base.StdoutShouldMatch(regexp.MustCompile(`MachineConfig`))},\n\t\t\tnonprivOpts: []base.RunOption{\n\t\t\t\tbase.ShouldFail(),\n\t\t\t\tbase.StdoutShouldMatch(regexp.MustCompile(`\\QNODE   NAMESPACE   TYPE   ID   VERSION`)),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\targs:      []string{\"get\", \"osrootsecret\"},\n\t\t\tadminOpts: []base.RunOption{base.StdoutShouldMatch(regexp.MustCompile(`OSRootSecret`))},\n\t\t\tnonprivOpts: []base.RunOption{\n\t\t\t\tbase.ShouldFail(),\n\t\t\t\tbase.StdoutShouldMatch(regexp.MustCompile(`\\QNODE   NAMESPACE   TYPE   ID   VERSION`)),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\targs:      []string{\"kubeconfig\", \"--force\", tempDir},\n\t\t\tadminOpts: []base.RunOption{base.StdoutEmpty()},\n\t\t\tnonprivOpts: []base.RunOption{\n\t\t\t\tbase.ShouldFail(),\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t},\n\t\t},\n\t} {\n\t\tname := strings.Join(tt.args, \"_\")\n\t\tsuite.Run(name, func() {\n\t\t\targs := append([]string{\"--nodes\", node}, tt.args...)\n\t\t\tsuite.RunCLI(args, tt.adminOpts...)\n\n\t\t\tfor _, config := range []string{readerConfig, operatorConfig} {\n\t\t\t\tif rbacEnabled {\n\t\t\t\t\tsuite.RunCLI(append([]string{\"--talosconfig\", config}, args...), tt.nonprivOpts...)\n\t\t\t\t} else {\n\t\t\t\t\t// check that it works the same way as for admin with reader's config\n\t\t\t\t\tsuite.RunCLI(append([]string{\"--talosconfig\", config}, args...), tt.adminOpts...)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\t// commands which work for operator, but not reader (when RBAC is enabled)\n\tfor _, tt := range []struct {\n\t\targs        []string\n\t\tprivOpts    []base.RunOption\n\t\tnonprivOpts []base.RunOption\n\t}{\n\t\t{\n\t\t\targs: []string{\"etcd\", \"alarm\", \"disarm\"},\n\t\t\tprivOpts: []base.RunOption{\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t},\n\t\t\tnonprivOpts: []base.RunOption{\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t\tbase.ShouldFail(),\n\t\t\t},\n\t\t},\n\t} {\n\t\tname := strings.Join(tt.args, \"_\")\n\t\tsuite.Run(name, func() {\n\t\t\targs := append([]string{\"--nodes\", node}, tt.args...)\n\t\t\tsuite.RunCLI(args, tt.privOpts...)\n\n\t\t\tsuite.RunCLI(append([]string{\"--talosconfig\", operatorConfig}, args...), tt.privOpts...)\n\n\t\t\tif rbacEnabled {\n\t\t\t\tsuite.RunCLI(append([]string{\"--talosconfig\", readerConfig}, args...), tt.nonprivOpts...)\n\t\t\t} else {\n\t\t\t\t// check that it works the same way as for admin with reader's config\n\t\t\t\tsuite.RunCLI(append([]string{\"--talosconfig\", readerConfig}, args...), tt.privOpts...)\n\t\t\t}\n\t\t})\n\t}\n\n\t// do not test destructive command with disabled RBAC\n\tif !rbacEnabled {\n\t\treturn\n\t}\n\n\t// destructive commands that don't work for reader\n\t// (and that we don't test for admin because they are destructive)\n\tfor _, tt := range []struct {\n\t\targs       []string\n\t\treaderOpts []base.RunOption\n\t}{\n\t\t{\n\t\t\targs: []string{\"reboot\", \"--wait=false\"},\n\t\t\treaderOpts: []base.RunOption{\n\t\t\t\tbase.ShouldFail(),\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\targs: []string{\"reset\", \"--wait=false\"},\n\t\t\treaderOpts: []base.RunOption{\n\t\t\t\tbase.ShouldFail(),\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qrpc error: code = PermissionDenied desc = not authorized`)),\n\t\t\t},\n\t\t},\n\t} {\n\t\tname := strings.Join(tt.args, \"_\")\n\t\tsuite.Run(name, func() {\n\t\t\targs := append([]string{\"--nodes\", node, \"--talosconfig\", readerConfig}, tt.args...)\n\t\t\tsuite.RunCLI(args, tt.readerOpts...)\n\t\t})\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(TalosconfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/containers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// ContainersSuite verifies dmesg command.\ntype ContainersSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ContainersSuite) SuiteName() string {\n\treturn \"cli.ContainersSuite\"\n}\n\n// TestContainerd inspects containers via containerd driver.\nfunc (suite *ContainersSuite) TestContainerd() {\n\tsuite.RunCLI([]string{\"containers\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`IMAGE`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`apid`)),\n\t)\n}\n\n// TestCRI inspects containers via CRI driver.\nfunc (suite *ContainersSuite) TestCRI() {\n\tsuite.RunCLI([]string{\n\t\t\"containers\", \"-k\", \"--nodes\",\n\t\tsuite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane),\n\t},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`kube-system/kube-apiserver`)),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ContainersSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/copy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// CopySuite verifies dmesg command.\ntype CopySuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *CopySuite) SuiteName() string {\n\treturn \"cli.CopySuite\"\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *CopySuite) TestSuccess() {\n\ttempDir := suite.T().TempDir()\n\n\tsuite.RunCLI([]string{\"copy\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(), \"/etc/os-release\", tempDir},\n\t\tbase.StdoutEmpty())\n\n\t_, err := os.Stat(filepath.Join(tempDir, \"os-release\"))\n\tsuite.Require().NoError(err)\n}\n\n// TestMultiNodeFail verifies that command fails with multiple nodes.\nfunc (suite *CopySuite) TestMultiNodeFail() {\n\tsuite.RunCLI([]string{\"copy\", \"--nodes\", \"127.0.0.1\", \"--nodes\", \"127.0.0.1\", \"/etc/os-release\", \".\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`is not supported with multiple nodes`)))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(CopySuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/debug.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// DebugSuite verifies debug command.\ntype DebugSuite struct {\n\tbase.CLISuite\n}\n\nconst debugImage = \"docker.io/library/alpine:3.23\"\n\n// SuiteName ...\nfunc (suite *DebugSuite) SuiteName() string {\n\treturn \"cli.DebugSuite\"\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *DebugSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"debug\", debugImage, \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"Linux\")),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.WithStdin(strings.NewReader(\"uname\\n\")),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DebugSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/diskusage.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// DiskUsageSuite verifies dmesg command.\ntype DiskUsageSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *DiskUsageSuite) SuiteName() string {\n\treturn \"cli.DiskUsageSuite\"\n}\n\ntype duInfo struct {\n\tsize int64\n\tname string\n\tnode string\n}\n\nfunc splitLine(line string) []string {\n\tvar columns []string\n\n\tfor part := range strings.SplitSeq(line, \" \") {\n\t\tif part != \"\" {\n\t\t\tcolumns = append(columns, strings.TrimSpace(part))\n\t\t}\n\t}\n\n\treturn columns\n}\n\nfunc parseLine(line string) (*duInfo, error) {\n\tcolumns := splitLine(line)\n\n\tif len(columns) < 2 || len(columns) > 3 {\n\t\treturn nil, fmt.Errorf(\"failed to parse line %s\", line)\n\t}\n\n\tres := &duInfo{}\n\toffset := 0\n\n\tif len(columns) == 3 {\n\t\tres.node = columns[0]\n\t\toffset++\n\t}\n\n\tsize, err := strconv.ParseInt(columns[offset], 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tres.size = size\n\tres.name = columns[offset+1]\n\n\treturn res, nil\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *DiskUsageSuite) TestSuccess() {\n\tfolder := \"/etc\"\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tvar folderSize int64 = 4096\n\n\tsuite.RunCLI([]string{\"list\", \"--nodes\", node, folder, \"-l\"},\n\t\tbase.StdoutMatchFunc(func(stdout string) error {\n\t\t\tlines := strings.Split(strings.TrimSpace(stdout), \"\\n\")\n\t\t\tif len(lines) == 1 {\n\t\t\t\treturn errors.New(\"expected lines > 0\")\n\t\t\t}\n\n\t\t\tparts := splitLine(lines[1])\n\n\t\t\tvar err error\n\n\t\t\tfolderSize, err = strconv.ParseInt(parts[4], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}))\n\n\t// check total calculation\n\tsuite.RunCLI([]string{\"usage\", \"--nodes\", node, folder, \"-d1\", \"--all\"},\n\t\tbase.StdoutMatchFunc(func(stdout string) error {\n\t\t\tlines := strings.Split(strings.TrimSpace(stdout), \"\\n\")\n\t\t\tif len(lines) == 1 {\n\t\t\t\treturn errors.New(\"expected lines > 0\")\n\t\t\t}\n\n\t\t\tvar totalExpected int64\n\n\t\t\tfor _, line := range lines[1 : len(lines)-1] {\n\t\t\t\tinfo, err := parseLine(line)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\ttotalExpected += info.size\n\t\t\t}\n\n\t\t\t// add folder size\n\t\t\ttotalExpected += folderSize\n\n\t\t\tinfo, err := parseLine(lines[len(lines)-1])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif info.size != totalExpected {\n\t\t\t\treturn fmt.Errorf(\"folder size was calculated incorrectly. Expected %d, got %d\", totalExpected, info.size)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}))\n}\n\n// TestError runs comand with error.\nfunc (suite *DiskUsageSuite) TestError() {\n\tsuite.RunCLI([]string{\n\t\t\"usage\", \"--nodes\",\n\t\tsuite.RandomDiscoveredNodeInternalIP(), \"/no/such/folder/here/just/for/sure\",\n\t},\n\t\tbase.ShouldFail(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StdoutEmpty(),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DiskUsageSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/dmesg.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// DmesgSuite verifies dmesg command.\ntype DmesgSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *DmesgSuite) SuiteName() string {\n\treturn \"cli.DmesgSuite\"\n}\n\n// TestHasOutput verifies that dmesg is displayed.\nfunc (suite *DmesgSuite) TestHasOutput() {\n\tsuite.RunCLI([]string{\"dmesg\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()}) // default checks for stdout not empty\n}\n\n// TestClusterHasOutput verifies that each node in the cluster has some output.\nfunc (suite *DmesgSuite) TestClusterHasOutput() {\n\tnodes := suite.DiscoverNodeInternalIPs(context.TODO())\n\tsuite.Require().NotEmpty(nodes)\n\n\tmatchers := xslices.Map(nodes, func(node string) base.RunOption {\n\t\treturn base.StdoutShouldMatch(\n\t\t\tregexp.MustCompile(fmt.Sprintf(`(?m)^%s:`, regexp.QuoteMeta(node))),\n\t\t)\n\t})\n\n\tsuite.RunCLI([]string{\"--nodes\", strings.Join(nodes, \",\"), \"dmesg\"},\n\t\tmatchers...)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(DmesgSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// EtcdSuite verifies etcd command.\ntype EtcdSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *EtcdSuite) SuiteName() string {\n\treturn \"cli.EtcdSuite\"\n}\n\n// TestMembers etcd members should have some output.\nfunc (suite *EtcdSuite) TestMembers() {\n\tsuite.RunCLI([]string{\"etcd\", \"members\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)}) // default checks for stdout not empty\n}\n\n// TestStatus etcd status should have some output.\nfunc (suite *EtcdSuite) TestStatus() {\n\tcpNodes := suite.DiscoverNodeInternalIPsByType(context.TODO(), machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"etcd\", \"status\", \"--nodes\", strings.Join(cpNodes, \",\")}) // default checks for stdout not empty\n}\n\n// TestAlarm etcd alarm should have no output.\nfunc (suite *EtcdSuite) TestAlarm() {\n\tcpNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"etcd\", \"alarm\", \"list\", \"--nodes\", cpNode}, base.StdoutEmpty())\n\tsuite.RunCLI([]string{\"etcd\", \"alarm\", \"disarm\", \"--nodes\", cpNode}, base.StdoutEmpty())\n}\n\n// TestForfeitLeadership etcd forfeit-leadership check.\nfunc (suite *EtcdSuite) TestForfeitLeadership() {\n\tnodes := suite.DiscoverNodes(context.TODO()).NodesByType(machine.TypeControlPlane)\n\n\tif len(nodes) < 3 {\n\t\tsuite.T().Skip(\"test only can be run on HA etcd clusters\")\n\t}\n\n\tsuite.RunCLI([]string{\"etcd\", \"forfeit-leadership\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)},\n\t\tbase.StdoutEmpty(),\n\t)\n}\n\n// TestSnapshot tests etcd snapshot (backup).\nfunc (suite *EtcdSuite) TestSnapshot() {\n\ttempDir := suite.T().TempDir()\n\n\tdbPath := filepath.Join(tempDir, \"snapshot.db\")\n\n\tsuite.RunCLI([]string{\"etcd\", \"snapshot\", dbPath, \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`etcd snapshot saved to .+\\d+ bytes.+`)),\n\t)\n}\n\n// TestDowngrade tests etcd downgrade.\nfunc (suite *EtcdSuite) TestDowngrade() {\n\tdowngradeTo := \"3.5\"\n\n\t// FIXME: enable tests once the tests run on on ETCD >=3.6.0\n\tsuite.T().Skip(\"ETCD below 3.6.0\")\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"etcd\", \"downgrade\", \"validate\", \"--nodes\", node, downgradeTo},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`downgrade validate success, cluster version \\d+\\.\\d+`)),\n\t)\n\tsuite.RunCLI([]string{\"etcd\", \"downgrade\", \"enable\", \"--nodes\", node, downgradeTo},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`downgrade enable success, cluster version \\d+\\.\\d+`)),\n\t)\n\tsuite.RunCLI([]string{\"etcd\", \"downgrade\", \"cancel\", \"--nodes\", node},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`downgrade cancel success, cluster version \\d+\\.\\d+`)),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(EtcdSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/gen.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n)\n\n// GenSuite verifies gen command.\ntype GenSuite struct {\n\tbase.CLISuite\n\n\ttmpDir   string\n\tsavedCwd string\n}\n\n// SuiteName ...\nfunc (suite *GenSuite) SuiteName() string {\n\treturn \"cli.GenSuite\"\n}\n\n// SetupTest ...\nfunc (suite *GenSuite) SetupTest() {\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tvar err error\n\n\tsuite.savedCwd, err = os.Getwd()\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(os.Chdir(suite.tmpDir))\n}\n\n// TearDownTest ...\nfunc (suite *GenSuite) TearDownTest() {\n\tif suite.savedCwd != \"\" {\n\t\tsuite.Require().NoError(os.Chdir(suite.savedCwd))\n\t}\n}\n\n// TestCA ...\nfunc (suite *GenSuite) TestCA() {\n\tsuite.RunCLI([]string{\"gen\", \"ca\", \"--organization\", \"Foo\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Assert().FileExists(\"Foo.crt\")\n\tsuite.Assert().FileExists(\"Foo.sha256\")\n\tsuite.Assert().FileExists(\"Foo.key\")\n}\n\n// TestKey ...\nfunc (suite *GenSuite) TestKey() {\n\tsuite.RunCLI([]string{\"gen\", \"key\", \"--name\", \"Foo\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Assert().FileExists(\"Foo.key\")\n}\n\n// TestCSR ...\nfunc (suite *GenSuite) TestCSR() {\n\tsuite.RunCLI([]string{\"gen\", \"key\", \"--name\", \"Foo\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"gen\", \"csr\", \"--key\", \"Foo.key\", \"--ip\", \"10.0.0.1\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Assert().FileExists(\"Foo.csr\")\n}\n\n// TestCrt ...\nfunc (suite *GenSuite) TestCrt() {\n\tsuite.RunCLI([]string{\"gen\", \"ca\", \"--organization\", \"Foo\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"gen\", \"key\", \"--name\", \"Bar\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"gen\", \"csr\", \"--key\", \"Bar.key\", \"--ip\", \"10.0.0.1\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"gen\", \"crt\", \"--ca\", \"Foo\", \"--csr\", \"Bar.csr\", \"--name\", \"foobar\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Assert().FileExists(\"foobar.crt\")\n}\n\n// TestKeypair ...\nfunc (suite *GenSuite) TestKeypair() {\n\tsuite.RunCLI([]string{\"gen\", \"keypair\", \"--organization\", \"Foo\", \"--ip\", \"10.0.0.1\"},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Assert().FileExists(\"Foo.crt\")\n\tsuite.Assert().FileExists(\"Foo.key\")\n}\n\n// TestGenConfigURLValidation ...\nfunc (suite *GenSuite) TestGenConfigURLValidation() {\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foo\", \"192.168.0.1\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qtry: \"https://192.168.0.1:6443\"`)))\n\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foo\", \"192.168.0.1:6443\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qtry: \"https://192.168.0.1:6443\"`)))\n\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foo\", \"192.168.0.1:2000\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qtry: \"https://192.168.0.1:2000\"`)))\n\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foo\", \"http://192.168.0.1:2000\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`\\Qtry: \"https://192.168.0.1:2000\"`)))\n}\n\n// TestGenConfigPatchStrategic verifies that gen config --config-patch works with strategic merge patches.\nfunc (suite *GenSuite) TestGenConfigPatchStrategic() {\n\tpatch, err := yaml.Marshal(map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"clusterName\": \"bar\",\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tfor _, tt := range []struct {\n\t\tflag         string\n\t\tshouldAffect map[string]bool\n\t}{\n\t\t{\n\t\t\tflag: \"config-patch\",\n\t\t\tshouldAffect: map[string]bool{\n\t\t\t\t\"controlplane.yaml\": true,\n\t\t\t\t\"worker.yaml\":       true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tflag: \"config-patch-control-plane\",\n\t\t\tshouldAffect: map[string]bool{\n\t\t\t\t\"controlplane.yaml\": true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tflag: \"config-patch-worker\",\n\t\t\tshouldAffect: map[string]bool{\n\t\t\t\t\"worker.yaml\": true,\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.Run(tt.flag, func() {\n\t\t\tsuite.RunCLI([]string{\"gen\", \"config\", \"--force\", \"foo\", \"https://192.168.0.1:6443\", \"--\" + tt.flag, string(patch)},\n\t\t\t\tbase.StdoutEmpty(),\n\t\t\t\tbase.StderrNotEmpty(),\n\t\t\t\tbase.StderrShouldMatch(regexp.MustCompile(\"generating PKI and tokens\")))\n\n\t\t\tfor _, configName := range []string{\"controlplane.yaml\", \"worker.yaml\"} {\n\t\t\t\tcfg, err := configloader.NewFromFile(configName)\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tswitch {\n\t\t\t\tcase tt.shouldAffect[configName]:\n\t\t\t\t\tsuite.Assert().Equal(\"bar\", cfg.Cluster().Name(), \"checking %q\", configName)\n\t\t\t\tdefault:\n\t\t\t\t\tsuite.Assert().Equal(\"foo\", cfg.Cluster().Name(), \"checking %q\", configName)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestSecrets ...\nfunc (suite *GenSuite) TestSecrets() {\n\tsuite.RunCLI([]string{\"gen\", \"secrets\"}, base.StdoutEmpty())\n\tsuite.Assert().FileExists(\"secrets.yaml\")\n\n\tsuite.RunCLI([]string{\"gen\", \"secrets\"}, base.StdoutEmpty(), base.ShouldFail(), base.StderrMatchFunc(func(output string) error {\n\t\texpected := \"file \\\"secrets.yaml\\\" already exists, use --force to overwrite\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stdout does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n\n\tsuite.RunCLI([]string{\"gen\", \"secrets\", \"--force\"}, base.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"gen\", \"secrets\", \"--output-file\", \"secrets2.yaml\"}, base.StdoutEmpty())\n\tsuite.Assert().FileExists(\"secrets2.yaml\")\n\n\tsuite.RunCLI([]string{\"gen\", \"secrets\", \"-o\", \"secrets3.yaml\", \"--talos-version\", \"v0.8\"}, base.StdoutEmpty())\n\tsuite.Assert().FileExists(\"secrets3.yaml\")\n}\n\n// TestSecretsWithPKIDirAndToken ...\nfunc (suite *GenSuite) TestSecretsWithPKIDirAndToken() {\n\tpath := \"secrets-with-pki-dir-and-token.yaml\"\n\n\tsuite.Require().NoError(writeKubernetesPKIFiles(\"k8s-pki/\"))\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"secrets\", \"--from-kubernetes-pki\", \"k8s-pki/\",\n\t\t\"--kubernetes-bootstrap-token\", \"test-token\",\n\t\t\"--output-file\", path,\n\t}, base.StdoutEmpty())\n\n\tsuite.Assert().FileExists(path)\n\n\tsecretsYaml, err := os.ReadFile(path)\n\tsuite.Assert().NoError(err)\n\n\tvar secretsBundle secrets.Bundle\n\n\terr = yaml.Unmarshal(secretsYaml, &secretsBundle)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Equal(\"test-token\", secretsBundle.Secrets.BootstrapToken, \"bootstrap token does not match\")\n\tsuite.Assert().Equal(pkiCACrt, secretsBundle.Certs.K8s.Crt, \"k8s ca cert does not match\")\n\tsuite.Assert().Equal(pkiCAKey, secretsBundle.Certs.K8s.Key, \"k8s ca key does not match\")\n\tsuite.Assert().Equal(pkiFrontProxyCACrt, secretsBundle.Certs.K8sAggregator.Crt, \"k8s aggregator ca cert does not match\")\n\tsuite.Assert().Equal(pkiFrontProxyCAKey, secretsBundle.Certs.K8sAggregator.Key, \"k8s aggregator ca key does not match\")\n\tsuite.Assert().Equal(pkiSAKey, secretsBundle.Certs.K8sServiceAccount.Key, \"k8s service account key does not match\")\n\tsuite.Assert().Equal(pkiEtcdCACrt, secretsBundle.Certs.Etcd.Crt, \"etcd ca cert does not match\")\n\tsuite.Assert().Equal(pkiEtcdCAKey, secretsBundle.Certs.Etcd.Key, \"etcd ca key does not match\")\n}\n\n// TestConfigWithSecrets tests the gen config command with secrets provided.\nfunc (suite *GenSuite) TestConfigWithSecrets() {\n\tsuite.RunCLI([]string{\"gen\", \"secrets\"}, base.StdoutEmpty())\n\tsuite.Assert().FileExists(\"secrets.yaml\")\n\n\tsecretsYaml, err := os.ReadFile(\"secrets.yaml\")\n\tsuite.Assert().NoError(err)\n\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foo\", \"https://192.168.0.1:6443\", \"--with-secrets\", \"secrets.yaml\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tsuite.RunCLI([]string{\"gen\", \"secrets\", \"--from-controlplane-config\", \"controlplane.yaml\", \"--output-file\", \"secrets-from-config.yaml\"},\n\t\tbase.StdoutEmpty(),\n\t)\n\n\tconfigSecretsBundle, err := os.ReadFile(\"secrets-from-config.yaml\")\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().YAMLEq(string(secretsYaml), string(configSecretsBundle))\n}\n\n// TestGenConfigWithDeprecatedOutputDirFlag tests that gen config command still works with the deprecated --output-dir flag.\nfunc (suite *GenSuite) TestGenConfigWithDeprecatedOutputDirFlag() {\n\ttempDir := suite.T().TempDir()\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-dir\", tempDir,\n\t},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"controlplane.yaml\"))\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"worker.yaml\"))\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"talosconfig\"))\n}\n\n// TestGenConfigToStdoutControlPlane tests that the gen config command can output a control plane config to stdout.\nfunc (suite *GenSuite) TestGenConfigToStdoutControlPlane() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane\",\n\t\t\"--output\", \"-\",\n\t}, base.StderrNotEmpty(), base.StdoutMatchFunc(func(output string) error {\n\t\texpected := \"type: controlplane\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stdout does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestGenConfigToStdoutWorker tests that the gen config command can output a worker config to stdout.\nfunc (suite *GenSuite) TestGenConfigToStdoutWorker() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"worker\",\n\t\t\"--output\", \"-\",\n\t}, base.StderrNotEmpty(), base.StdoutMatchFunc(func(output string) error {\n\t\texpected := \"type: worker\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stdout does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestGenConfigToStdoutTalosconfig tests that the gen config command can output a talosconfig to stdout.\nfunc (suite *GenSuite) TestGenConfigToStdoutTalosconfig() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"talosconfig\",\n\t\t\"--output\", \"-\",\n\t}, base.StderrNotEmpty(), base.StdoutMatchFunc(func(output string) error {\n\t\texpected := \"context: foo\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stdout does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestGenConfigToStdoutMultipleTypesError tests that the gen config command fails when\n// multiple output types are specified and output target is stdout.\nfunc (suite *GenSuite) TestGenConfigToStdoutMultipleTypesError() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane,worker\",\n\t\t\"--output\", \"-\",\n\t}, base.StdoutEmpty(), base.ShouldFail(), base.StderrMatchFunc(func(output string) error {\n\t\texpected := \"can't use multiple output types with stdout\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stderr does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestGenConfigMultipleTypesToDirectory tests that the gen config command works as expected\n// when some output types are specified and output target is a directory.\nfunc (suite *GenSuite) TestGenConfigMultipleTypesToDirectory() {\n\ttempDir := filepath.Join(suite.T().TempDir(), \"inner\")\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane,worker\",\n\t\t\"--output\", tempDir,\n\t},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"controlplane.yaml\"))\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"worker.yaml\"))\n\tsuite.Assert().NoFileExists(filepath.Join(tempDir, \"talosconfig\"))\n}\n\n// TestGenConfigSingleTypeToFile tests that the gen config command treats\n// the output flag as a file path and not as a directory when a single output type is requested.\nfunc (suite *GenSuite) TestGenConfigSingleTypeToFile() {\n\ttempFile := filepath.Join(suite.T().TempDir(), \"worker-conf.yaml\")\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"worker\",\n\t\t\"--output\", tempFile,\n\t},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tsuite.Assert().FileExists(tempFile)\n}\n\n// TestGenConfigSingleTypeWithDeprecatedOutputDirFlagToDirectory tests that the gen config command treats\n// the output flag still as a directory when the deprecated --output-dir flag is used.\nfunc (suite *GenSuite) TestGenConfigSingleTypeWithDeprecatedOutputDirFlagToDirectory() {\n\ttempDir := filepath.Join(suite.T().TempDir(), \"inner\")\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"worker\",\n\t\t\"--output-dir\", tempDir,\n\t},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tsuite.Assert().FileExists(filepath.Join(tempDir, \"worker.yaml\"))\n}\n\n// TestGenConfigInvalidOutputType tests that the gen config command fails when\n// and invalid output type is requested.\nfunc (suite *GenSuite) TestGenConfigInvalidOutputType() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"worker,foobar\",\n\t}, base.StdoutEmpty(), base.ShouldFail(), base.StderrMatchFunc(func(output string) error {\n\t\texpected := \"invalid output type\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stderr does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestGenConfigNoOutputType tests that the gen config command fails when an empty list of output types is requested.\nfunc (suite *GenSuite) TestGenConfigNoOutputType() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"\",\n\t}, base.StdoutEmpty(), base.ShouldFail(), base.StderrMatchFunc(func(output string) error {\n\t\texpected := \"at least one output type must be specified\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stderr does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(GenSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/health.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// HealthSuite verifies health command.\ntype HealthSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *HealthSuite) SuiteName() string {\n\treturn \"cli.HealthSuite\"\n}\n\n// TestClientSideWithExplicitNodes does successful health check run from client-side, providing the explicit set of nodes.\nfunc (suite *HealthSuite) TestClientSideWithExplicitNodes() {\n\tinfo := suite.DiscoverNodes(context.TODO())\n\n\tvar args []string\n\n\tfor _, machineType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {\n\t\tfor _, node := range info.NodesByType(machineType) {\n\t\t\tswitch machineType {\n\t\t\tcase machine.TypeInit:\n\t\t\t\targs = append(args, \"--init-node\", node.IPs[0].String())\n\t\t\tcase machine.TypeControlPlane:\n\t\t\t\targs = append(args, \"--control-plane-nodes\", node.IPs[0].String())\n\t\t\tcase machine.TypeWorker:\n\t\t\t\targs = append(args, \"--worker-nodes\", node.IPs[0].String())\n\t\t\tcase machine.TypeUnknown:\n\t\t\t\t// skip it\n\t\t\tdefault:\n\t\t\t\tpanic(fmt.Sprintf(\"unexpected machine type: %v\", machineType))\n\t\t\t}\n\t\t}\n\t}\n\n\tsuite.testClientSide(args...)\n}\n\n// TestClientSideWithDiscovery does a health check run from client-side without explicitly specifying the nodes.\n// It verifies that the check still passes, because the nodes get populated by the discovery service.\nfunc (suite *HealthSuite) TestClientSideWithDiscovery() {\n\tdiscoveryEnabled, err := suite.isDiscoveryEnabled()\n\tsuite.Require().NoError(err)\n\n\tif !discoveryEnabled {\n\t\tsuite.T().Skipf(\"skipping test: discovery is not enabled on the cluster\")\n\t}\n\n\tsuite.testClientSide()\n}\n\n// TestServerSide does successful health check run from server-side.\nfunc (suite *HealthSuite) TestServerSide() {\n\trandomControlPlaneNodeInternalIP := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tsuite.RunCLI([]string{\"health\", \"--nodes\", randomControlPlaneNodeInternalIP},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`waiting for all k8s nodes to report ready`)),\n\t)\n}\n\nfunc (suite *HealthSuite) testClientSide(extraArgs ...string) {\n\targs := append([]string{\"--server=false\"}, extraArgs...)\n\n\tif suite.K8sEndpoint != \"\" {\n\t\targs = append(args, \"--k8s-endpoint\", suite.K8sEndpoint)\n\t}\n\n\tsuite.RunCLI(append([]string{\"health\"}, args...),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`waiting for all k8s nodes to report ready`)),\n\t)\n}\n\nfunc (suite *HealthSuite) isDiscoveryEnabled() (bool, error) {\n\ttemp := struct {\n\t\tSpec cluster.ConfigSpec `yaml:\"spec\"`\n\t}{}\n\n\trandomControlPlaneNodeInternalIP := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tstdout, _ := suite.RunCLI([]string{\"--nodes\", randomControlPlaneNodeInternalIP, \"get\", \"discoveryconfigs\", \"-oyaml\"})\n\n\terr := yaml.Unmarshal([]byte(stdout), &temp)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn temp.Spec.DiscoveryEnabled, nil\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(HealthSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// ImageSuite verifies the image command.\ntype ImageSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ImageSuite) SuiteName() string {\n\treturn \"cli.ImageSuite\"\n}\n\n// TestDefault verifies default Talos list of images.\nfunc (suite *ImageSuite) TestDefault() {\n\tsuite.RunCLI([]string{\"image\", \"k8s-bundle\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"registry.k8s.io/kube-apiserver\"))),\n\t)\n}\n\nvar versionRe = regexp.MustCompile(`^[v]?(\\d+\\.\\d+\\.\\d+(?:-(?:alpha|beta|rc)\\.\\d+)?)`)\n\nfunc normalizeTag(tag string) string {\n\tm := versionRe.FindStringSubmatch(tag)\n\tif len(m) == 0 {\n\t\treturn tag\n\t}\n\n\treturn m[1]\n}\n\n// TestSourceBundle verifies talos-bundle Talos list of images.\nfunc (suite *ImageSuite) TestSourceBundle() {\n\tout := `ghcr.io/siderolabs/installer:v1.11.2\nghcr.io/siderolabs/installer-base:v1.11.2\nghcr.io/siderolabs/imager:v1.11.2\nghcr.io/siderolabs/talos:v1.11.2\nghcr.io/siderolabs/talosctl-all:v1.11.2\nghcr.io/siderolabs/overlays:v1.11.2\nghcr.io/siderolabs/extensions:v1.11.2\nghcr.io/siderolabs/amazon-ena:2.15.0-v1.11.2@sha256:e21baee86adfb637b113751a678e9a57e970d3d597a2e488fc13440db1437732\nghcr.io/siderolabs/amd-ucode:20250917@sha256:9b1a5fd03b9c5bc685d3a363ddc471ff6092a304f5fdfe67aa1f4626e34d72eb\nghcr.io/siderolabs/amdgpu:20250917-v1.11.2@sha256:09899678ea287b01ff7104f4a0a7c731fd688d9c0047c58a535dfd1d68875364\nghcr.io/siderolabs/binfmt-misc:v1.11.2@sha256:2da530ba50ca5053636405620d91764d1debacbfd7ecd9c5fe91be0d3d4f90ca\nghcr.io/siderolabs/bnx2-bnx2x:20250917@sha256:ac6aaaa0d3312e72279a5cde7de0d71fb61774aa2f97a4e56dd914a9f1dde4d1\nghcr.io/siderolabs/btrfs:v1.11.2@sha256:f1d9351b6627807cd8923204662c0f876b3db70a5b57e5363aadf399bea4a8ed\nghcr.io/siderolabs/chelsio-drivers:v1.11.2@sha256:d1800384e3a55b8cb1d82cab086c6dbe5af28e1d56f18fd763fa0aabbde538f8\nghcr.io/siderolabs/chelsio-firmware:20250917@sha256:f54cea7351565001abf9a26794dc1c96ba8182150b2c18777e9eed04dc6d3d8d\nghcr.io/siderolabs/cloudflared:2024.12.1@sha256:ab2792aca1108b22a2f59a9852edf6f77fbb337ecf5bedcedfa0ae5a12bd0e41\nghcr.io/siderolabs/crun:1.24@sha256:157f1c563931275443dd46fbc44c854c669f5cf4bbc285356636a57c6d33caed\nghcr.io/siderolabs/ctr:v2.1.4@sha256:9291fccaf2dcb05a053dd20472437ce69ef3784c95f633a5278758d24eb407a3\nghcr.io/siderolabs/drbd:9.2.14-v1.11.2@sha256:4e8a32cbff6d96c6a61e523636f7c11f5a72984097e3e4a68f9f5354ac070b99\nghcr.io/siderolabs/dvb-cx23885:v1.11.2@sha256:631785a877a36adf2c7d26db5a2b29f64bcf0ea2356b07aa50a5be8493acc33e\nghcr.io/siderolabs/dvb-m88ds3103:v1.11.2@sha256:6cb61a2d0b3257168906b6eeda023b60ae96e16d5a31d549486f7f6ca39c5cab\nghcr.io/siderolabs/ecr-credential-provider:v1.34.0@sha256:ca6754837ecb19aba419ba2e9fe558a3aff6b2d897a93f897ac44aa01053fab6\nghcr.io/siderolabs/fuse3:3.17.4@sha256:a4770b619691b64e516fbe65e57e7ca54f2132f230d41c1e3bbce6ae6c14547b\nghcr.io/siderolabs/gasket-driver:5815ee3-v1.11.2@sha256:430397008e0f214391a44a2748c5009d373dce5a5d689b99d817a6d4372b922b\nghcr.io/siderolabs/glibc:2.41@sha256:7b70eccac7f5ee44e2d7558bc21da67988ca36413be45de5dba2679a12317ce8\nghcr.io/siderolabs/gvisor-debug:v1.0.0@sha256:cc443f896ce6f822fc74234cd285e9ecf39f809654040576c98166819b5ef0a6\nghcr.io/siderolabs/gvisor:20250707.0@sha256:3f43bb94c1b09caa4a82559478b88c30b0b735303e37129e6e7bdc2cefe3ebc7\nghcr.io/siderolabs/hailort:4.21.0@sha256:bcdd3088158b7c71cd852ccea0945d5074040669155f43e33c159c567a23cdb8\nghcr.io/siderolabs/hello-world-service:v1.0.0@sha256:7e5de44b094bbe24d5c22cac45828975dc654c4ff4c1169482fe3671b2e490c9\nghcr.io/siderolabs/i915:20250917-v1.11.2@sha256:46251cb415b5036d7ebb460b0babe98f855930ef2cdc4709acdfa6e379278dd6\nghcr.io/siderolabs/intel-ice-firmware:20250917@sha256:c25225c371e81485c64f339864ede410b560f07eb0fc2702a73315e977a6323d\nghcr.io/siderolabs/intel-ucode:20250812@sha256:84ada70546d2f8d28d209ccfc7895c2cd0fa5f623815dcd45e6b118a06ad0959\nghcr.io/siderolabs/iscsi-tools:v0.2.0@sha256:ef6e8038ddaca1faad2d0e5b87ef4696fa6359f287682c9492462abfa1e26906\nghcr.io/siderolabs/kata-containers:3.20.0@sha256:4d8a59c058eb9678385b868e38a21dcd531dad64e708c282c7ef5d06dc27c98b\nghcr.io/siderolabs/lldpd:1.0.20@sha256:01fc489e506117b157e45f5ec77183a8984bb538c4223855ce1d8102e32c5d3e\nghcr.io/siderolabs/mdadm:v4.3@sha256:70576ecb239156c822b419d3169a478baebafb71432a4961cb71305bcddb7a36\nghcr.io/siderolabs/mei:v1.11.2@sha256:ec5978f641f6db18248f452343e93912852ef45c256dc1b836af7f40783786b6\nghcr.io/siderolabs/metal-agent:v0.1.3@sha256:0bb8dfd62e058af4dd85deed4864e7628e2ac5d7705d711570abf1be19a2f507\nghcr.io/siderolabs/nebula:1.9.6@sha256:e234e575cfffd6cc67ce1b67ba1b72d2827ca26793d82459ed389952e842b4c4\nghcr.io/siderolabs/newt:1.4.4@sha256:9226d5c591cafa714743f3f5519b19997202078704fcb7e1a1264c1613c59bff\nghcr.io/siderolabs/nfsd:v1.11.2@sha256:faa93d11292e96ee9c64209178fb641b49a89b600b605b5c2b0283a850a28a3f\nghcr.io/siderolabs/nfsrahead:2.8.3@sha256:9f140fd2735dfef1793acc7afaec57fdd547b497b559c12fb088ed3ee449c439\nghcr.io/siderolabs/nonfree-kmod-nvidia-lts:535.247.01-v1.11.2@sha256:af6b123c5269f47aa828c9e472d482fca69efb714b9e256a13b2384ea2b13549\nghcr.io/siderolabs/nonfree-kmod-nvidia-production:570.172.08-v1.11.2@sha256:162ade2a1a826403b5d7d1121c744db13825fc1238f380d3b98c74cf6d233916\nghcr.io/siderolabs/nut-client:2.8.4@sha256:6555859aba70aa4f20bd98171123da6f1ef76060d43d283178c05fe99d536715\nghcr.io/siderolabs/nvidia-container-toolkit-lts:535.247.01-v1.17.8@sha256:e425765c607b34029b61b16add2c455492059e360f73057f54e6a1a3d60279ad\nghcr.io/siderolabs/nvidia-container-toolkit-production:570.172.08-v1.17.8@sha256:eff6eb15bb5ceabe84904a6d62f872d5547bb98fdf78f119297f739fd775973d\nghcr.io/siderolabs/nvidia-fabricmanager-lts:535.247.01@sha256:aaf3d09e87ef9a0bfa2522775ba7518b30ccac4b909d8d2d739a24410daba769\nghcr.io/siderolabs/nvidia-fabricmanager-production:570.172.08@sha256:43d2649dc55582e1922408663425f7bd14f277839831c3601667d588ffcdfdf3\nghcr.io/siderolabs/nvidia-open-gpu-kernel-modules-lts:535.247.01-v1.11.2@sha256:69fafd7fa4b708226672d2334670bfbb0004fced548d6a0b2fab9807517c7971\nghcr.io/siderolabs/nvidia-open-gpu-kernel-modules-production:570.172.08-v1.11.2@sha256:3b68c873acf144048fd28e43e3054131d777b34101cd3cf9ce1b0d90c77da114\nghcr.io/siderolabs/nvme-cli:v2.14@sha256:6d5052488d524ec1791a6d6c3150e5cff3c88a774f8d828a4553d42deece56f7\nghcr.io/siderolabs/panfrost:20250917-v1.11.2@sha256:8339980ff926f3de05df90008643458234769bb6a68351e255030fce8ec08739\nghcr.io/siderolabs/qemu-guest-agent:10.0.2@sha256:9720300de00544eca155bc19369dfd7789d39a0e23d72837a7188f199e13dc6c\nghcr.io/siderolabs/qlogic-firmware:20250917@sha256:9a62f7562ebf07392a1184e6f9354eaea786072bdd8b76ef85a08528ad3a7c53\nghcr.io/siderolabs/realtek-firmware:20250917@sha256:6710269640d8684dfcf782b638b6c4e34896df136185218d8fdb0312a2bf00b0\nghcr.io/siderolabs/revpi-firmware:v1.0.0@sha256:9649e42c71862b9c4b9f0887d0929297e78530854ae507436344cecd6176debe\nghcr.io/siderolabs/sbc-allwinner:v0.1.2@sha256:c662949ad20bb37a20bc96c21187fefdcce8c6543769d993656f40d82fd88e2b\nghcr.io/siderolabs/sbc-jetson:v0.1.2@sha256:896d043ad0780cccbcd6f7984f3db5685d63f2659eb9dc7023542b72639599d6\nghcr.io/siderolabs/sbc-raspberrypi:v0.1.5@sha256:70a1b174a5bddd57da33e377af324c1f93d7ed87b9bc8f6cdefe5ec179abb4c9\nghcr.io/siderolabs/sbc-rockchip:v0.1.5@sha256:406c0ed9708772d72f0a0afc2998e14e673bf889135d2b47d92771c0d3566ff5\nghcr.io/siderolabs/spin:v0.21.0@sha256:b405524de2a2826b22354962d48688237ff4f5f7cf79f80c27d08f057c51b505\nghcr.io/siderolabs/stargz-snapshotter:v0.17.0@sha256:10280ee408e2e73a6d6f96f64efac3a3ef93bf3874e353a515cf2aa34ce7f2a5\nghcr.io/siderolabs/tailscale:1.88.1@sha256:36e484cbd93340b10e4c0d9ffef5b626e48ba435295936167d2711dd21ed4c3b\nghcr.io/siderolabs/tenstorrent:1.34@sha256:ea51e09b201548a3856783828b47be0d76e912f7ee7b02ced6b6dfde9ba1f1c2\nghcr.io/siderolabs/thunderbolt:v1.11.2@sha256:bf6482be7df448317443bfcd8b66bf68c6231e86b85d69c1e7c92ddb8aaf70dc\nghcr.io/siderolabs/uinput:v1.11.2@sha256:435b1187a17e1c1153b8374cfcd47ca24d4faab9d6efa0949894d85ade8ff3b7\nghcr.io/siderolabs/usb-modem-drivers:v1.11.2@sha256:c9ee048484cb0d2609f746dc7d90b213d26ad01e07342771bdb10841ec09b886\nghcr.io/siderolabs/util-linux-tools:2.41.1@sha256:bcd353bb7635d6dc9e6e913abdbff5b73d00829e3fd14e549b50533df8aa4faf\nghcr.io/siderolabs/v4l-uvc-drivers:v1.11.2@sha256:ae29326c8c3d34d1f1bc5aedf9f79f7b16c833722520c9763d7dd76212d041bd\nghcr.io/siderolabs/vc4:v1.11.2@sha256:f5c81fbd7cab1b1eecf904a93e501c7334a47db0dcc12232d2b76295d29c537d\nghcr.io/siderolabs/vmtoolsd-guest-agent:v1.4.0@sha256:06cc9885433eb9ca8148e76b38f9b7a1b85e375864b2f0bab5da75e9389ad027\nghcr.io/siderolabs/wasmedge:v0.6.0@sha256:aa255c9d3d5c61010943fd4fc9e3818739605243f4288ef2166915e57267b6d9\nghcr.io/siderolabs/xdma-driver:aefa9a1-v1.11.2@sha256:b65cb2033d46a7c88d317cb29a87741f8c72d768869bbfae832cb76121e4ab14\nghcr.io/siderolabs/xen-guest-agent:0.4.0-g5c274e6@sha256:91e08d9ae45e325bf20da77f251e265d0e72cb38751a6dcee930bf21c9adacc1\nghcr.io/siderolabs/youki:0.5.5@sha256:562ceabb69570203024dbb9b8673ba485af1ffdd082210656573e22557235372\nghcr.io/siderolabs/zerotier:1.16.0@sha256:9444baa3acdc665dba56ed16c8a983c81c3f37fc73877be8fd882f9cf8c9fa5a\nghcr.io/siderolabs/zfs:2.3.3-v1.11.2@sha256:73782571f334b18995ddf324d24b86ea9a11aa37661a468b4e077da63e0d9714`\n\n\tsuite.RunCLI([]string{\"image\", \"talos-bundle\", \"v1.11.2\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(out))),\n\t)\n\n\ttag, err := semver.ParseTolerant(normalizeTag(version.Tag))\n\tassert.NoError(suite.T(), err)\n\n\tsuite.T().Log(normalizeTag(version.Tag))\n\tsuite.T().Log(version.Tag)\n\n\tif strings.TrimLeft(version.Tag, \"v\") == normalizeTag(version.Tag) {\n\t\tsuite.T().Skip(\"skipping the test for the exact version tag\")\n\t}\n\n\tsuite.RunCLI([]string{\"image\", \"talos-bundle\", \"v\" + tag.String()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"ghcr.io/siderolabs/talos:v\"+tag.String()))),\n\t)\n\n\tsuite.RunCLI([]string{\"image\", \"talos-bundle\", tag.String()},\n\t\tbase.StdoutEmpty(),\n\t\tbase.ShouldFail(),\n\t)\n\n\ttag.Patch = 0\n\tassert.NoError(suite.T(), tag.IncrementMinor())\n\tsuite.RunCLI([]string{\"image\", \"talos-bundle\", \"v\" + tag.FinalizeVersion()},\n\t\tbase.StdoutEmpty(),\n\t\tbase.ShouldFail(),\n\t)\n}\n\n// TestList verifies listing images in the CRI.\nfunc (suite *ImageSuite) TestList() {\n\tsuite.RunCLI([]string{\"image\", \"ls\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`IMAGE\\s+DIGEST\\s+SIZE`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"registry.k8s.io/kube-apiserver\"))),\n\t)\n\n\tsuite.RunCLI([]string{\"image\", \"ls\", \"--namespace\", \"system\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`IMAGE\\s+DIGEST\\s+SIZE`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"ghcr.io/siderolabs/kubelet:\"))),\n\t)\n}\n\n// TestPull verifies pulling images to the CRI.\nfunc (suite *ImageSuite) TestPull() {\n\tconst image = \"registry.k8s.io/kube-apiserver:v1.27.0\" // sync this to e2e.sh `build_image_cache`\n\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tif stdout, _ := suite.RunCLI([]string{\"get\", \"imagecacheconfig\", \"--nodes\", node, \"--output\", \"jsonpath='{.spec.status}'\"}); strings.Contains(stdout, \"ready\") {\n\t\tsuite.T().Logf(\"skipping as the image cache is present\")\n\n\t\treturn\n\t}\n\n\tsuite.RunCLI([]string{\"image\", \"pull\", \"--nodes\", node, image},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(\n\t\t\t\"(\"+ // either pinned image (verification on)\n\t\t\t\tregexp.QuoteMeta(\"pulled image registry.k8s.io/kube-apiserver@sha256:89b8d9dbef2b905b7d028ca8b7f79d35ebd9baa66b0a3ee2ddd4f3e0e2804b45\")+\n\t\t\t\t\"|\"+ // or original ref (without verification)\n\t\t\t\tregexp.QuoteMeta(\"pulled image \"+image)+\n\t\t\t\t\")\",\n\t\t)),\n\t)\n\n\t// verify that pulled image appeared, also image aliases should appear\n\tsuite.RunCLI([]string{\"image\", \"ls\", \"--nodes\", node},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(image))),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"sha256:89b8d9dbef2b905b7d028ca8b7f79d35ebd9baa66b0a3ee2ddd4f3e0e2804b45\"))),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(\"registry.k8s.io/kube-apiserver@sha256:89b8d9dbef2b905b7d028ca8b7f79d35ebd9baa66b0a3ee2ddd4f3e0e2804b45\"))),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(image))),\n\t)\n\n\t// remove the image\n\tsuite.RunCLI([]string{\"image\", \"remove\", \"--nodes\", node, image},\n\t\tbase.StdoutEmpty(),\n\t)\n}\n\n// TestCacheCreateOCI verifies creating a cache tarball.\nfunc (suite *ImageSuite) TestCacheCreateOCI() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tstdOut, _ := suite.RunCLI([]string{\"image\", \"k8s-bundle\"})\n\n\timagesList := strings.Split(strings.Trim(stdOut, \"\\n\"), \"\\n\")\n\n\timagesArgs := xslices.Map(imagesList[:2], func(image string) string {\n\t\treturn \"--images=\" + image\n\t})\n\n\tcacheDir := suite.T().TempDir()\n\n\targs := []string{\"image\", \"cache-create\", \"--image-cache-path\", cacheDir, \"--force\", \"--layout\", \"oci\"} //nolint:prealloc // this is a test\n\n\targs = append(args, imagesArgs...)\n\n\tsuite.RunCLI(args, base.StdoutEmpty(), base.StderrNotEmpty())\n\n\tassert.FileExistsf(suite.T(), cacheDir+\"/index.json\", \"index.json should exist in the image cache directory\")\n}\n\n// TestCacheCreateFlat verifies creating a cache directory.\nfunc (suite *ImageSuite) TestCacheCreateFlat() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tstdOut, _ := suite.RunCLI([]string{\"image\", \"k8s-bundle\"})\n\n\timagesList := strings.Split(strings.Trim(stdOut, \"\\n\"), \"\\n\")\n\n\timagesArgs := xslices.Map(imagesList[:2], func(image string) string {\n\t\treturn \"--images=\" + image\n\t})\n\n\tcacheDir := suite.T().TempDir()\n\n\targs := []string{\"image\", \"cache-create\", \"--image-cache-path\", cacheDir, \"--force\", \"--layout\", \"flat\"} //nolint:prealloc // this is a test\n\n\targs = append(args, imagesArgs...)\n\n\tsuite.RunCLI(args, base.StdoutEmpty(), base.StderrNotEmpty())\n\n\tassert.DirExistsf(suite.T(), cacheDir+\"/blob\", \"blob directory should exist in the image cache directory\")\n\tassert.DirExistsf(suite.T(), cacheDir+\"/manifests\", \"manifests directory should exist in the image cache directory\")\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ImageSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/inject.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\nvar (\n\t//go:embed testdata/inject/talosconfig-input.yaml\n\tinputManifests []byte\n\n\t//go:embed testdata/inject/talosconfig-expected.yaml\n\texpectedManifests []byte\n)\n\n// InjectSuite verifies inject command.\ntype InjectSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *InjectSuite) SuiteName() string {\n\treturn \"cli.InjectSuite\"\n}\n\n// TestServiceAccount tests inject serviceaccount command.\nfunc (suite *InjectSuite) TestServiceAccount() {\n\tsuite.testServiceAccount(inputManifests)\n}\n\n// TestServiceAccountAlreadyInjectedNoChange tests inject serviceaccount command when the input manifest is already injected,\n// makes sure that it stays the same.\nfunc (suite *InjectSuite) TestServiceAccountAlreadyInjectedNoChange() {\n\tsuite.testServiceAccount(expectedManifests)\n}\n\nfunc (suite *InjectSuite) testServiceAccount(input []byte) {\n\texpectedDocs, err := yamlDocs(expectedManifests)\n\tsuite.Require().NoError(err)\n\n\ttempDir := suite.T().TempDir()\n\n\tinputPath := filepath.Join(tempDir, \"input.yaml\")\n\n\terr = os.WriteFile(inputPath, input, 0o644)\n\tsuite.Require().NoError(err)\n\n\tstdout, _ := suite.RunCLI([]string{\"inject\", \"serviceaccount\", \"-f\", inputPath, \"--roles\", \"os:reader,os:admin\"})\n\n\tstdoutDocs, err := yamlDocs([]byte(stdout))\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(expectedDocs, stdoutDocs, \"inject serviceaccount output did not match expected output\")\n}\n\nfunc yamlDocs(input []byte) ([]map[string]any, error) {\n\tdecoder := yaml.NewDecoder(bytes.NewReader(input))\n\n\tvar docs []map[string]any\n\n\tfor {\n\t\tvar doc map[string]any\n\n\t\tif err := decoder.Decode(&doc); err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"document decode failed: %w\", err)\n\t\t}\n\n\t\tdocs = append(docs, doc)\n\t}\n\n\treturn docs, nil\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(InjectSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/jsonpath.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// JSONPathSuite verifies dmesg command.\ntype JSONPathSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *JSONPathSuite) SuiteName() string {\n\treturn \"cli.JSONPathSuite\"\n}\n\n// TestGetScalarPropertyWithJSONPath verifies that the jsonpath filter to the get command can return scalar data.\nfunc (suite *JSONPathSuite) TestGetScalarPropertyWithJSONPath() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.RunCLI([]string{\"get\", \"--nodes\", node, \"etcfilestatus\", \"--output\", `jsonpath='{.metadata.namespace}'`},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"files\")),\n\t\tbase.WithRetry(retry.Constant(15*time.Second, retry.WithUnits(time.Second))),\n\t)\n}\n\n// TestGetWithJSONPathWildcard verifies that the jsonpath filter to the get command accepts a wildcard operator.\n// It is handy when 'get' requests a list of resources.\nfunc (suite *JSONPathSuite) TestGetWithJSONPathWildcard() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"get\", \"--nodes\", node, \"manifests\", \"--output\", `jsonpath='{.spec[*].metadata.name}'`},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"coredns\")),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"kube-dns\")),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(\"kubeconfig-in-cluster\")),\n\t\tbase.WithRetry(retry.Constant(15*time.Second, retry.WithUnits(time.Second))),\n\t)\n}\n\n// TestGetComplexPropertyWithJSONPath verifies that the jsonpath filter to the get command can return JSON.\nfunc (suite *JSONPathSuite) TestGetComplexPropertyWithJSONPath() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tconst jsonMetadataRegex = `\\{\\s*\"created\":\\s\".*\",\\s*\"id\":\\s\".*\",\\s*\\s*\"namespace\":\\s\".*\",\\s*\"owner\":\\s\".*\",\\s*\"phase\":\\s\".*\",\\s*\"type\":\\s\".*\",\\s*\"updated\":\\s\".*\",\\s*\"version\":\\s\\d\\n\\}`\n\n\tsuite.RunCLI([]string{\"get\", \"--nodes\", node, \"etcfilestatus\", \"--output\", `jsonpath='{.metadata}'`},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(jsonMetadataRegex)),\n\t\tbase.WithRetry(retry.Constant(15*time.Second, retry.WithUnits(time.Second))),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(JSONPathSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/kubeconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// KubeconfigSuite verifies dmesg command.\ntype KubeconfigSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *KubeconfigSuite) SuiteName() string {\n\treturn \"cli.KubeconfigSuite\"\n}\n\n// TestDirectory generates kubeconfig in specified directory.\nfunc (suite *KubeconfigSuite) TestDirectory() {\n\ttempDir := suite.T().TempDir()\n\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--merge=false\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), tempDir},\n\t\tbase.StdoutEmpty())\n\n\tpath := filepath.Join(tempDir, \"kubeconfig\")\n\tsuite.Require().FileExists(path)\n\n\t_, err := clientcmd.LoadFromFile(path)\n\tsuite.Require().NoError(err)\n}\n\n// TestCwd generates kubeconfig in cwd.\nfunc (suite *KubeconfigSuite) TestCwd() {\n\ttempDir := suite.T().TempDir()\n\n\tsavedCwd, err := os.Getwd()\n\tsuite.Require().NoError(err)\n\n\tdefer os.Chdir(savedCwd) //nolint:errcheck\n\n\tsuite.Require().NoError(os.Chdir(tempDir))\n\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--merge=false\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Require().FileExists(filepath.Join(tempDir, \"kubeconfig\"))\n}\n\n// TestCustomName generates kubeconfig with custom name.\nfunc (suite *KubeconfigSuite) TestCustomName() {\n\ttempDir := suite.T().TempDir()\n\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--merge=false\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), filepath.Join(tempDir, \"k8sconfig\")},\n\t\tbase.StdoutEmpty())\n\n\tsuite.Require().FileExists(filepath.Join(tempDir, \"k8sconfig\"))\n}\n\n// TestMultiNodeFail verifies that command fails with multiple nodes.\nfunc (suite *KubeconfigSuite) TestMultiNodeFail() {\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--merge=false\", \"--nodes\", \"127.0.0.1\", \"--nodes\", \"127.0.0.1\", \".\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`is not supported with multiple nodes`)))\n}\n\n// TestMergeRename tests merge config into existing kubeconfig with default rename conflict resolution.\nfunc (suite *KubeconfigSuite) TestMergeRename() {\n\ttempDir := suite.T().TempDir()\n\n\tpath := filepath.Join(tempDir, \"config\")\n\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), path},\n\t\tbase.StdoutEmpty())\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), path})\n\n\tconfig, err := clientcmd.LoadFromFile(path)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(len(config.Contexts), 2)\n}\n\n// TestMergeOverwrite test merge config into existing kubeconfig with overwrite conflict resolution.\nfunc (suite *KubeconfigSuite) TestMergeOverwrite() {\n\ttempDir := suite.T().TempDir()\n\n\tpath := filepath.Join(tempDir, \"config\")\n\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), path},\n\t\tbase.StdoutEmpty())\n\tsuite.RunCLI([]string{\"kubeconfig\", \"--force\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), path},\n\t\tbase.StdoutEmpty())\n\n\tconfig, err := clientcmd.LoadFromFile(path)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal(len(config.Contexts), 1)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(KubeconfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/list.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// ListSuite verifies dmesg command.\ntype ListSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ListSuite) SuiteName() string {\n\treturn \"cli.ListSuite\"\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *ListSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"list\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(), \"/etc\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`os-release`)))\n\n\tsuite.RunCLI([]string{\"list\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(), \"/\"},\n\t\tbase.StdoutShouldNotMatch(regexp.MustCompile(`os-release`)))\n}\n\n// TestDepth tests various combinations of --recurse and --depth flags.\n//\n//nolint:tparallel\nfunc (suite *ListSuite) TestDepth() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\t// Expected maximum number of separators in the output\n\t// In plain terms, it's the maximum depth of the directory tree\n\tmaxSeps := 5\n\n\tif stdout, _ := suite.RunCLI([]string{\"get\", \"imagecacheconfig\", \"--nodes\", node, \"--output\", \"yaml\"}); strings.Contains(stdout, \"ready\") {\n\t\t// Image cache paths parts are longer\n\t\tmaxSeps = 9\n\t}\n\n\t// checks that enough separators are encountered in the output\n\tfor _, test := range []struct {\n\t\tseparators int\n\t\tflags      []string\n\t}{\n\t\t{separators: 0},\n\t\t{separators: 0, flags: []string{\"--recurse=false\"}},\n\t\t{separators: 0, flags: []string{\"--depth=-1\"}},\n\t\t{separators: 0, flags: []string{\"--depth=0\"}},\n\t\t{separators: 0, flags: []string{\"--depth=1\"}},\n\t\t{separators: 1, flags: []string{\"--depth=2\"}},\n\t\t{separators: 2, flags: []string{\"--depth=3\"}},\n\t\t{separators: -maxSeps, flags: []string{\"--recurse=true\"}}, // negative means \"at least\"\n\t} {\n\t\tcmdFn := suite.MakeCMDFn(slices.Insert(test.flags, 0, \"list\", \"--nodes\", node, \"/system\"))\n\n\t\tsuite.T().Run(strings.Join(test.flags, \",\"), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trunAndCheck(t, test.separators, cmdFn, test.flags...)\n\t\t})\n\t}\n}\n\nfunc runAndCheck(t *testing.T, expectedSeparators int, cmdFn func() *exec.Cmd, flags ...string) {\n\tstdout, _ := base.RunCLI(t, cmdFn)\n\n\tlines := strings.Split(strings.TrimSpace(stdout), \"\\n\")\n\tassert.Greater(t, len(lines), 2)\n\tassert.Equal(t, []string{\"NODE\", \"NAME\"}, strings.Fields(lines[0]))\n\tassert.Equal(t, []string{\".\"}, strings.Fields(lines[1])[1:])\n\n\tvar maxActualSeparators int\n\n\tfor _, line := range lines[2:] {\n\t\tactualSeparators := strings.Count(strings.Fields(line)[1], string(os.PathSeparator))\n\n\t\tif expectedSeparators >= 0 && !assert.LessOrEqual(\n\t\t\tt,\n\t\t\tactualSeparators,\n\t\t\texpectedSeparators,\n\t\t\t\"too many separators, flags: %s\\nlines:\\n%s\",\n\t\t\tstrings.Join(flags, \" \"),\n\t\t\tstdout,\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tmaxActualSeparators = max(maxActualSeparators, actualSeparators)\n\t}\n\n\tif expectedSeparators < 0 {\n\t\tassert.LessOrEqual(\n\t\t\tt,\n\t\t\t-expectedSeparators,\n\t\t\tmaxActualSeparators,\n\t\t\t\"not enough separators, \\nflags: %s\\nlines:\\n%s\",\n\t\t\tstrings.Join(flags, \" \"),\n\t\t\tstdout,\n\t\t)\n\t} else {\n\t\tassert.Equal(\n\t\t\tt,\n\t\t\texpectedSeparators,\n\t\t\tmaxActualSeparators,\n\t\t\t\"not enough separators, \\nflags: %s\\nlines:\\n%s\",\n\t\t\tstrings.Join(flags, \" \"),\n\t\t\tstdout,\n\t\t)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ListSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/logs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// LogsSuite verifies logs command.\ntype LogsSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *LogsSuite) SuiteName() string {\n\treturn \"cli.LogsSuite\"\n}\n\n// TestServiceLogs verifies that logs are displayed.\nfunc (suite *LogsSuite) TestServiceLogs() {\n\tsuite.RunCLI([]string{\"logs\", \"kubelet\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()}) // default checks for stdout not empty\n}\n\n// TestTailLogs verifies that logs can be displayed with tail lines.\nfunc (suite *LogsSuite) TestTailLogs() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\t// run some machined API calls to produce enough log lines\n\tfor range 10 {\n\t\tsuite.RunCLI([]string{\"-n\", node, \"version\"})\n\t}\n\n\tsuite.RunCLI([]string{\"logs\", \"apid\", \"-n\", node, \"--tail\", \"5\"},\n\t\tbase.StdoutMatchFunc(func(stdout string) error {\n\t\t\tlines := strings.Count(stdout, \"\\n\")\n\t\t\tif lines != 5 {\n\t\t\t\treturn fmt.Errorf(\"expected %d lines, found %d lines\", 5, lines)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}))\n}\n\n// TestServiceNotFound verifies that logs displays an error if service is not found.\nfunc (suite *LogsSuite) TestServiceNotFound() {\n\tsuite.RunCLI([]string{\"logs\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(), \"servicenotfound\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`ERROR:.+ log \"servicenotfound\" was not registered`)),\n\t\tbase.ShouldFail(),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(LogsSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/machineconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// MachineConfigSuite verifies machineconfig command.\ntype MachineConfigSuite struct {\n\tbase.CLISuite\n\n\tsavedCwd string\n}\n\n// SuiteName ...\nfunc (suite *MachineConfigSuite) SuiteName() string {\n\treturn \"cli.MachineConfigSuite\"\n}\n\n// SetupTest ...\nfunc (suite *MachineConfigSuite) SetupTest() {\n\tvar err error\n\n\tsuite.savedCwd, err = os.Getwd()\n\tsuite.Require().NoError(err)\n}\n\n// TearDownTest ...\nfunc (suite *MachineConfigSuite) TearDownTest() {\n\tif suite.savedCwd != \"\" {\n\t\tsuite.Require().NoError(os.Chdir(suite.savedCwd))\n\t}\n}\n\n// TestGen tests the gen subcommand.\n// Identical to GenSuite.TestGenConfigToStdoutControlPlane\n// The remaining functionality is checked for `talosctl gen config` in GenSuite.\nfunc (suite *MachineConfigSuite) TestGen() {\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane\",\n\t\t\"--output\", \"-\",\n\t}, base.StderrNotEmpty(), base.StdoutMatchFunc(func(output string) error {\n\t\texpected := \"type: controlplane\"\n\t\tif !strings.Contains(output, expected) {\n\t\t\treturn fmt.Errorf(\"stdout does not contain %q: %q\", expected, output)\n\t\t}\n\n\t\treturn nil\n\t}))\n}\n\n// TestPatchPrintStdout tests the patch subcommand with output set to stdout\n// with multiple patches from the command line and from file.\nfunc (suite *MachineConfigSuite) TestPatchPrintStdout() {\n\tpatch1, err := yaml.Marshal(map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"clusterName\": \"replaced\",\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tpatch2, err := yaml.Marshal(map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"controlPlane\": map[string]any{\n\t\t\t\t\"endpoint\": \"https://replaced\",\n\t\t\t},\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tpatch2Path := filepath.Join(suite.T().TempDir(), \"patch2.json\")\n\n\terr = os.WriteFile(patch2Path, patch2, 0o644)\n\tsuite.Require().NoError(err)\n\n\tmc := filepath.Join(suite.T().TempDir(), \"input.yaml\")\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane\",\n\t\t\"--output\", mc,\n\t},\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StdoutEmpty(),\n\t)\n\n\tsuite.RunCLI([]string{\n\t\t\"machineconfig\", \"patch\", mc, \"--patch\", string(patch1), \"-p\", \"@\" + patch2Path,\n\t}, base.StdoutMatchFunc(func(output string) error {\n\t\tvar matchErr *multierror.Error\n\n\t\tif !strings.Contains(output, \"clusterName: replaced\") {\n\t\t\tmatchErr = multierror.Append(matchErr, errors.New(\"clusterName not replaced\"))\n\t\t}\n\n\t\tif !strings.Contains(output, \"endpoint: https://replaced\") {\n\t\t\tmatchErr = multierror.Append(matchErr, errors.New(\"endpoint not replaced\"))\n\t\t}\n\n\t\treturn matchErr.ErrorOrNil()\n\t}))\n}\n\n// TestPatchWriteToFile tests the patch subcommand with output set to a file.\nfunc (suite *MachineConfigSuite) TestPatchWriteToFile() {\n\tpatch1, err := yaml.Marshal(map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"clusterName\": \"replaced\",\n\t\t},\n\t})\n\tsuite.Require().NoError(err)\n\n\tmc := filepath.Join(suite.T().TempDir(), \"input2.yaml\")\n\n\tsuite.RunCLI([]string{\n\t\t\"gen\", \"config\",\n\t\t\"foo\", \"https://192.168.0.1:6443\",\n\t\t\"--output-types\", \"controlplane\",\n\t\t\"--output\", mc,\n\t},\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StdoutEmpty(),\n\t)\n\n\toutputFile := filepath.Join(suite.T().TempDir(), \"inner\", \"output.yaml\")\n\n\tsuite.RunCLI([]string{\n\t\t\"machineconfig\", \"patch\", mc, \"--patch\", string(patch1), \"--output\", outputFile,\n\t}, base.StdoutEmpty())\n\n\toutputBytes, err := os.ReadFile(outputFile)\n\tsuite.Assert().NoError(err)\n\n\tsuite.Assert().Contains(string(outputBytes), \"clusterName: replaced\")\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MachineConfigSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/memory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// MemorySuite verifies dmesg command.\ntype MemorySuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *MemorySuite) SuiteName() string {\n\treturn \"cli.MemorySuite\"\n}\n\n// TestSuccess verifies successful execution.\nfunc (suite *MemorySuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"memory\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`FREE`)))\n}\n\n// TestVerbose verifies verbose mode.\nfunc (suite *MemorySuite) TestVerbose() {\n\tsuite.RunCLI([]string{\"memory\", \"-v\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`MemFree: \\d+ kB`)))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MemorySuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// MetaSuite verifies meta sub-commands.\ntype MetaSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *MetaSuite) SuiteName() string {\n\treturn \"cli.MetaSuite\"\n}\n\n// TestKey writes a META key, deletes it, verifies via resources.\nfunc (suite *MetaSuite) TestKey() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\t// detect docker platform and skip the test\n\tstdout, _ := suite.RunCLI([]string{\"--nodes\", node, \"get\", \"platformmetadata\"})\n\tif strings.Contains(stdout, \"container\") {\n\t\tsuite.T().Skip(\"skipping on container platform\")\n\t}\n\n\tkey := \"0x05\" // unused/reserved key\n\tvalue := uuid.New().String()\n\n\tsuite.RunCLI([]string{\"--nodes\", node, \"meta\", \"write\", key, value},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"--nodes\", node, \"get\", \"metakeys\", key},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(key)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(value)),\n\t)\n\n\tsuite.RunCLI([]string{\"--nodes\", node, \"meta\", \"delete\", key},\n\t\tbase.StdoutEmpty())\n\n\tsuite.RunCLI([]string{\"--nodes\", node, \"get\", \"metakeys\", key},\n\t\tbase.ShouldFail(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(\"NotFound\")),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MetaSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/mounts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// MountsSuite verifies dmesg command.\ntype MountsSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *MountsSuite) SuiteName() string {\n\treturn \"cli.MountsSuite\"\n}\n\n// TestSuccess verifies successful execution.\nfunc (suite *MountsSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"mounts\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`(?s)FILESYSTEM.*`)))\n}\n\n// TestUserDisksMounted verifies user disk mounts created.\nfunc (suite *MountsSuite) TestUserDisksMounted() {\n\tpaths := os.Getenv(\"USER_DISKS_MOUNTS\")\n\n\tif paths == \"\" {\n\t\tsuite.T().Skip(\"USER_DISKS_MOUNTS is not set\")\n\t}\n\n\tfor path := range strings.SplitSeq(paths, \",\") {\n\t\tsuite.RunCLI([]string{\"mounts\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\t\tbase.StdoutShouldMatch(regexp.MustCompile(path)))\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(MountsSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/netstat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// NetstatSuite verifies etcd command and coredns container.\ntype NetstatSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *NetstatSuite) SuiteName() string {\n\treturn \"cli.NetstatSuite\"\n}\n\n// TestListening verifies that there are listening connections.\nfunc (suite *NetstatSuite) TestListening() {\n\tsuite.RunCLI([]string{\"netstat\", \"--listening\", \"--programs\", \"--tcp\", \"--extend\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`:::50000.+LISTEN.+/apid`)))\n}\n\n// TestContainers verifies that containers are listed.\nfunc (suite *NetstatSuite) TestContainers() {\n\tnodes := suite.DiscoverNodeInternalIPs(context.TODO())\n\n\tsuite.RunCLI([]string{\"netstat\", \"--listening\", \"--programs\", \"--udp\", \"--ipv6\", \"--pods\", \"--nodes\", strings.Join(nodes, \",\")},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`:::53\\s+:::\\*.+/coredns\\s+kube-system/coredns-`)))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(NetstatSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/patch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// PatchSuite verifies dmesg command.\ntype PatchSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *PatchSuite) SuiteName() string {\n\treturn \"cli.PatchSuite\"\n}\n\n// TestSuccess successful run.\nfunc (suite *PatchSuite) TestSuccess() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tpatch := map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"proxy\": map[string]any{\n\t\t\t\t\"image\": fmt.Sprintf(\"%s:v%s\", constants.KubeProxyImage, constants.DefaultKubernetesVersion),\n\t\t\t},\n\t\t},\n\t}\n\n\tdata, err := json.Marshal(patch)\n\tsuite.Require().NoError(err)\n\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch\", string(data), \"machineconfig\", \"--mode=no-reboot\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch\", string(data), \"machineconfig\", \"--mode=no-reboot\", \"--dry-run\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n}\n\n// TestError runs comand with error.\nfunc (suite *PatchSuite) TestError() {\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tpatch := []map[string]any{\n\t\t{\n\t\t\t\"op\":   \"crash\",\n\t\t\t\"path\": \"/cluster/proxy\",\n\t\t\t\"value\": map[string]any{\n\t\t\t\t\"image\": fmt.Sprintf(\"%s:v%s\", constants.KubeProxyImage, constants.DefaultKubernetesVersion),\n\t\t\t},\n\t\t},\n\t}\n\n\tdata, err := json.Marshal(patch)\n\tsuite.Require().NoError(err)\n\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch\", string(data), \"machineconfig\"},\n\t\tbase.StdoutEmpty(), base.ShouldFail())\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch\", string(data), \"machineconfig\", \"v1alpha2\"},\n\t\tbase.StdoutEmpty(), base.ShouldFail())\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch-file\", \"/nnnope\", \"machineconfig\"},\n\t\tbase.StdoutEmpty(), base.ShouldFail())\n\tsuite.RunCLI([]string{\"patch\", \"--nodes\", node, \"--patch\", \"it's not even a json\", \"machineconfig\"},\n\t\tbase.StdoutEmpty(), base.ShouldFail())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(PatchSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/pcap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// PcapSuite verifies etcd command.\ntype PcapSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *PcapSuite) SuiteName() string {\n\treturn \"cli.PcapSuite\"\n}\n\n// TestLoopback verifies that there are some packets on loopback interface.\nfunc (suite *PcapSuite) TestLoopback() {\n\tsuite.RunCLI([]string{\"pcap\", \"--interface\", \"lo\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane), \"--duration\", \"2s\"}) // default checks for stdout not empty\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(PcapSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/pki.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cli\n\nimport (\n\t_ \"embed\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nvar (\n\t//go:embed \"testdata/pki/ca.crt\"\n\tpkiCACrt []byte\n\t//go:embed \"testdata/pki/ca.key\"\n\tpkiCAKey []byte\n\t//go:embed \"testdata/pki/front-proxy-ca.crt\"\n\tpkiFrontProxyCACrt []byte\n\t//go:embed \"testdata/pki/front-proxy-ca.key\"\n\tpkiFrontProxyCAKey []byte\n\t//go:embed \"testdata/pki/sa.key\"\n\tpkiSAKey []byte\n\t//go:embed \"testdata/pki/etcd/ca.crt\"\n\tpkiEtcdCACrt []byte\n\t//go:embed \"testdata/pki/etcd/ca.key\"\n\tpkiEtcdCAKey []byte\n)\n\nfunc writeKubernetesPKIFiles(dir string) error {\n\tif err := os.Mkdir(dir, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(dir, \"ca.crt\"), pkiCACrt, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(dir, \"ca.key\"), pkiCAKey, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(dir, \"front-proxy-ca.crt\"), pkiFrontProxyCACrt, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(dir, \"front-proxy-ca.key\"), pkiFrontProxyCAKey, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(dir, \"sa.key\"), pkiSAKey, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tetcdDir := filepath.Join(dir, \"etcd\")\n\tif err := os.Mkdir(etcdDir, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(etcdDir, \"ca.crt\"), pkiEtcdCACrt, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(filepath.Join(etcdDir, \"ca.key\"), pkiEtcdCAKey, 0o777)\n}\n"
  },
  {
    "path": "internal/integration/cli/processes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// ProcessesSuite verifies dmesg command.\ntype ProcessesSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ProcessesSuite) SuiteName() string {\n\treturn \"cli.ProcessesSuite\"\n}\n\n// TestSuccess verifies successful execution.\nfunc (suite *ProcessesSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"processes\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`PID`)))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ProcessesSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/read.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// ReadSuite verifies dmesg command.\ntype ReadSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ReadSuite) SuiteName() string {\n\treturn \"cli.ReadSuite\"\n}\n\n// TestSuccess runs comand with success.\nfunc (suite *ReadSuite) TestSuccess() {\n\tsuite.RunCLI([]string{\"read\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(), \"/etc/os-release\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`ID=talos`)))\n}\n\n// TestMultiNodeFail verifies that command fails with multiple nodes.\nfunc (suite *ReadSuite) TestMultiNodeFail() {\n\tsuite.RunCLI([]string{\"read\", \"--nodes\", \"127.0.0.1\", \"--nodes\", \"127.0.0.1\", \"/etc/os-release\"},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrShouldMatch(regexp.MustCompile(`is not supported with multiple nodes`)))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ReadSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/reboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// RebootSuite tests reboot command.\ntype RebootSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *RebootSuite) SuiteName() string {\n\treturn \"cli.RebootSuite\"\n}\n\n// TestReboot tests rebooting nodes.\nfunc (suite *RebootSuite) TestReboot() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tcontrolPlaneNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tworkerNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\tnodes := fmt.Sprintf(\n\t\t\"%s,%s\",\n\t\tcontrolPlaneNode,\n\t\tworkerNode,\n\t)\n\n\tsuite.T().Logf(\"rebooting nodes %s via the CLI\", nodes)\n\n\tsuite.RunCLI([]string{\"reboot\", \"-n\", nodes, \"--debug\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrMatchFunc(func(stdout string) error {\n\t\t\tif strings.Contains(stdout, \"method is not supported\") {\n\t\t\t\tsuite.T().Skip(\"reboot is not supported\")\n\t\t\t}\n\n\t\t\tvar err error\n\n\t\t\tfor _, node := range []string{controlPlaneNode, workerNode} {\n\t\t\t\tif !strings.Contains(stdout, fmt.Sprintf(\"%q: events check condition met\", node)) {\n\t\t\t\t\terr = multierror.Append(err, fmt.Errorf(\"events check condition not met on %v\", node))\n\t\t\t\t}\n\n\t\t\t\tif !strings.Contains(stdout, fmt.Sprintf(\"%q: post check passed\", node)) {\n\t\t\t\t\terr = multierror.Append(err, fmt.Errorf(\"post check not passed on %v\", node))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn err\n\t\t}))\n\n\tsuite.T().Logf(\"running the cluster health check\")\n\n\t// run the health check to make sure cluster is fully healthy after a node reboot\n\targs := []string{\"--server=false\"}\n\n\tif suite.K8sEndpoint != \"\" {\n\t\targs = append(args, \"--k8s-endpoint\", strings.Split(suite.K8sEndpoint, \":\")[0])\n\t}\n\n\tsuite.RunCLI(append([]string{\"health\"}, args...),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n}\n\n// TestRebootEarlyFailPrintsOutput tests the action tracker used by reboot command to track reboot status\n// does not suppress the stderr output if there is an error occurring at an early stage, i.e. before the\n// action status reporting starts.\nfunc (suite *RebootSuite) TestRebootEarlyFailPrintsOutput() {\n\tcontrolPlaneNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\tinvalidTalosconfig := filepath.Join(suite.T().TempDir(), \"talosconfig.yaml\")\n\n\tsuite.T().Logf(\"attempting to reboot node %q using talosconfig %q\", controlPlaneNode, invalidTalosconfig)\n\n\tsuite.RunCLI([]string{\"--talosconfig\", invalidTalosconfig, \"reboot\", \"-n\", controlPlaneNode},\n\t\tbase.ShouldFail(),\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t\tbase.StderrMatchFunc(func(stdout string) error {\n\t\t\tif strings.Contains(stdout, \"method is not supported\") {\n\t\t\t\tsuite.T().Skip(\"reboot is not supported\")\n\t\t\t}\n\n\t\t\tif !strings.Contains(stdout, \"failed to determine endpoints\") {\n\t\t\t\treturn errors.New(\"expected to find 'failed to determine endpoints' in stderr\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(RebootSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/restart.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// RestartSuite verifies dmesg command.\ntype RestartSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *RestartSuite) SuiteName() string {\n\treturn \"cli.RestartSuite\"\n}\n\n// TestSystem restarts system containerd process.\nfunc (suite *RestartSuite) TestSystem() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\t// trustd only runs on control plane nodes\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"restart\", \"-n\", node, \"trustd\"},\n\t\tbase.StdoutEmpty())\n\n\ttime.Sleep(200 * time.Millisecond)\n\n\tsuite.RunAndWaitForMatch([]string{\"service\", \"-n\", node, \"trustd\"}, regexp.MustCompile(`EVENTS\\s+\\[Running\\]: Health check successful`), 30*time.Second)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(RestartSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/services.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// ServicesSuite verifies dmesg command.\ntype ServicesSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *ServicesSuite) SuiteName() string {\n\treturn \"cli.ServicesSuite\"\n}\n\n// TestList verifies service list.\nfunc (suite *ServicesSuite) TestList() {\n\tsuite.RunCLI([]string{\"services\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`STATE`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`apid`)),\n\t)\n}\n\n// TestStatus verifies service status.\nfunc (suite *ServicesSuite) TestStatus() {\n\tsuite.RunCLI([]string{\"service\", \"apid\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`STATE`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`apid`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`\\[Running\\]`)),\n\t)\n}\n\n// TestRestart verifies kubelet restart.\nfunc (suite *ServicesSuite) TestRestart() {\n\tnode := suite.RandomDiscoveredNodeInternalIP()\n\n\tsuite.RunCLI([]string{\"service\", \"kubelet\", \"restart\", \"--nodes\", node})\n\n\ttime.Sleep(200 * time.Millisecond)\n\n\tsuite.RunAndWaitForMatch([]string{\"service\", \"-n\", node, \"kubelet\"}, regexp.MustCompile(`EVENTS\\s+\\[Running\\]: Health check successful`), 30*time.Second)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ServicesSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/stats.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// StatsSuite verifies dmesg command.\ntype StatsSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *StatsSuite) SuiteName() string {\n\treturn \"cli.StatsSuite\"\n}\n\n// TestContainerd inspects stats via containerd driver.\nfunc (suite *StatsSuite) TestContainerd() {\n\tsuite.RunCLI([]string{\"stats\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`CPU`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`apid`)),\n\t)\n}\n\n// TestCRI inspects stats via CRI driver.\nfunc (suite *StatsSuite) TestCRI() {\n\tsuite.RunCLI([]string{\"stats\", \"-k\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`CPU`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`kube-system/kube-apiserver`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`k8s.io`)),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(StatsSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/support.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"archive/zip\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// SupportSuite verifies support command.\ntype SupportSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *SupportSuite) SuiteName() string {\n\treturn \"cli.SupportSuite\"\n}\n\n// TestSupport does successful support run.\nfunc (suite *SupportSuite) TestSupport() {\n\ttempDir := suite.T().TempDir()\n\n\toutput := filepath.Join(tempDir, \"support.zip\")\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tsuite.RunCLI([]string{\"support\", \"--nodes\", node, \"-w\", \"5\", \"-O\", output},\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tarchive, err := zip.OpenReader(output)\n\tsuite.Require().NoError(err)\n\n\tdefer archive.Close() //nolint:errcheck\n\n\tfiles := map[string]struct{}{}\n\n\tfor _, f := range archive.File {\n\t\tfiles[f.Name] = struct{}{}\n\n\t\tif strings.HasSuffix(f.Name, \"dmesg.log\") {\n\t\t\tsuite.Require().Greater(f.UncompressedSize64, uint64(0), \"dmesg log is empty\")\n\t\t}\n\t}\n\n\tfor _, name := range []string{\n\t\t\"dmesg.log\",\n\t\t\"service-logs/apid.log\",\n\t\t\"service-logs/apid.state\",\n\t\t\"service-logs/machined.log\",\n\t\t\"service-logs/machined.state\",\n\t\t\"service-logs/kubelet.log\",\n\t\t\"service-logs/kubelet.state\",\n\t\t\"resources/kernelparamstatuses.runtime.talos.dev.yaml\",\n\t\t\"controller-runtime.log\",\n\t\t\"mounts\",\n\t\t\"processes\",\n\t\t\"io\",\n\t\t\"summary\",\n\t} {\n\t\tn := fmt.Sprintf(\"%s/%s\", node, name)\n\t\tsuite.Require().Contains(files, n, \"File %s doesn't exist in the support bundle\", n)\n\t}\n\n\tfor _, name := range []string{\n\t\t\"kubernetes-logs/kube-system/kube-apiserver-\",\n\t} {\n\t\tn := fmt.Sprintf(\"%s/%s\", node, name)\n\n\t\tfound := false\n\n\t\tfor fileName := range files {\n\t\t\tif strings.HasPrefix(fileName, n) {\n\t\t\t\tfound = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tsuite.Require().True(found, \"File with prefix %s doesn't exist in the support bundle\", n)\n\t}\n\n\tfor _, name := range []string{\n\t\t\"kubernetesResources/nodes.yaml\",\n\t\t\"kubernetesResources/systemPods.yaml\",\n\t} {\n\t\tsuite.Require().Contains(files, name, \"File %s doesn't exist in the support bundle\", name)\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(SupportSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/testdata/inject/talosconfig-expected.yaml",
    "content": "apiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: donottouch\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: test1\nspec:\n  containers:\n    - env:\n        - name: TEST\n          value: test\n      image: alpine:3\n      name: container1\n      resources: {}\n      volumeMounts:\n        - mountPath: /mnt/vol1\n          name: vol1\n        - mountPath: /var/run/secrets/talos.dev\n          name: talos-secrets\n    - image: alpine:3\n      name: container2\n      resources: {}\n      volumeMounts:\n        - mountPath: /var/run/secrets/talos.dev\n          name: talos-secrets\n  initContainers:\n    - image: busybox\n      name: init1\n      resources: {}\n      volumeMounts:\n        - mountPath: /tmp/hello\n          name: vol1\n        - mountPath: /var/run/secrets/talos.dev\n          name: talos-secrets\n    - image: busybox\n      name: init2\n      resources: {}\n      volumeMounts:\n        - mountPath: /tmp/hello\n          name: vol1\n        - mountPath: /var/run/secrets/talos.dev\n          name: talos-secrets\n  volumes:\n    - emptyDir: {}\n      name: vol1\n    - name: talos-secrets\n      secret:\n        secretName: test1-talos-secrets\nstatus: {}\n---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: test1-talos-secrets\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test1\nspec:\n  selector:\n    matchLabels:\n      app: test\n  strategy: {}\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      containers:\n        - image: alpine:3\n          name: container1\n          resources: {}\n          volumeMounts:\n            - mountPath: /mnt/vol1\n              name: vol1\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n        - image: alpine:3\n          name: container2\n          resources: {}\n          volumeMounts:\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n      volumes:\n        - emptyDir: {}\n          name: vol1\n        - name: talos-secrets\n          secret:\n            secretName: test1-talos-secrets\nstatus: {}\n---\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: test2\nspec:\n  selector:\n    matchLabels:\n      app: test\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      containers:\n        - image: alpine:3\n          name: container1\n          resources: {}\n          volumeMounts:\n            - mountPath: /mnt/vol1\n              name: vol1\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n        - image: alpine:3\n          name: container2\n          resources: {}\n          volumeMounts:\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n      volumes:\n        - emptyDir: {}\n          name: vol1\n        - name: talos-secrets\n          secret:\n            secretName: test2-talos-secrets\n  updateStrategy: {}\nstatus:\n  currentNumberScheduled: 0\n  desiredNumberScheduled: 0\n  numberMisscheduled: 0\n  numberReady: 0\n---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: test2-talos-secrets\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: test3\nspec:\n  selector:\n    matchLabels:\n      app: test\n  serviceName: test\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      containers:\n        - image: alpine:3\n          name: container1\n          resources: {}\n          volumeMounts:\n            - mountPath: /mnt/vol1\n              name: vol1\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n        - image: alpine:3\n          name: container2\n          resources: {}\n          volumeMounts:\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n      volumes:\n        - emptyDir: {}\n          name: vol1\n        - name: talos-secrets\n          secret:\n            secretName: test3-talos-secrets\n  updateStrategy: {}\nstatus:\n  availableReplicas: 0\n  replicas: 0\n---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: test3-talos-secrets\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: batch/v1\nkind: CronJob\nmetadata:\n  name: test4\n  namespace: testns\nspec:\n  jobTemplate:\n    metadata:\n      labels:\n        app: test\n    spec:\n      template:\n        metadata:\n          labels:\n            app: test\n        spec:\n          containers:\n            - image: alpine:3\n              name: container1\n              resources: {}\n              volumeMounts:\n                - mountPath: /mnt/vol1\n                  name: vol1\n                - mountPath: /var/run/secrets/talos.dev\n                  name: talos-secrets\n            - image: alpine:3\n              name: container2\n              resources: {}\n              volumeMounts:\n                - mountPath: /var/run/secrets/talos.dev\n                  name: talos-secrets\n          volumes:\n            - name: talos-secrets\n              secret:\n                secretName: test4-talos-secrets\n  schedule: '*/1 * * * *'\nstatus: {}\n---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: test4-talos-secrets\n  namespace: testns\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: test5\n  namespace: testns2\nspec:\n  template:\n    metadata: {}\n    spec:\n      containers:\n        - image: alpine:3\n          name: container1\n          resources: {}\n          volumeMounts:\n            - mountPath: /mnt/vol1\n              name: vol1\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n        - image: alpine:3\n          name: container2\n          resources: {}\n          volumeMounts:\n            - mountPath: /var/run/secrets/talos.dev\n              name: talos-secrets\n      volumes:\n        - name: talos-secrets\n          secret:\n            secretName: test5-talos-secrets\nstatus: {}\n---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: test5-talos-secrets\n  namespace: testns2\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\n"
  },
  {
    "path": "internal/integration/cli/testdata/inject/talosconfig-input.yaml",
    "content": "---\napiVersion: talos.dev/v1alpha1\nkind: ServiceAccount\nmetadata:\n  name: donottouch\nspec:\n  roles:\n    - os:reader\n    - os:admin\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: test1\nspec:\n  volumes:\n    - name: vol1\n      emptyDir: {}\n  initContainers:\n    - name: init1\n      image: busybox\n      volumeMounts:\n        - name: vol1\n          mountPath: /tmp/hello\n    - name: init2\n      image: busybox\n      volumeMounts:\n        - name: vol1\n          mountPath: /tmp/hello\n  containers:\n    - name: container1\n      image: alpine:3\n      env:\n        - name: TEST\n          value: test\n      volumeMounts:\n        - name: vol1\n          mountPath: /mnt/vol1\n    - name: container2\n      image: alpine:3\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: test1\nspec:\n  selector:\n    matchLabels:\n      app: test\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      volumes:\n        - name: vol1\n          emptyDir: {}\n      containers:\n        - name: container1\n          image: alpine:3\n          volumeMounts:\n            - name: vol1\n              mountPath: /mnt/vol1\n        - name: container2\n          image: alpine:3\n---\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: test2\nspec:\n  selector:\n    matchLabels:\n      app: test\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      volumes:\n        - name: vol1\n          emptyDir: {}\n      containers:\n        - name: container1\n          image: alpine:3\n          volumeMounts:\n            - name: vol1\n              mountPath: /mnt/vol1\n        - name: container2\n          image: alpine:3\n---\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: test3\nspec:\n  serviceName: test\n  selector:\n    matchLabels:\n      app: test\n  template:\n    metadata:\n      labels:\n        app: test\n    spec:\n      volumes:\n        - name: vol1\n          emptyDir: {}\n      containers:\n        - name: container1\n          image: alpine:3\n          volumeMounts:\n            - name: vol1\n              mountPath: /mnt/vol1\n        - name: container2\n          image: alpine:3\n---\napiVersion: batch/v1\nkind: CronJob\nmetadata:\n  name: test4\n  namespace: testns\nspec:\n  schedule: \"*/1 * * * *\"\n  jobTemplate:\n    metadata:\n      labels:\n        app: test\n    spec:\n      template:\n        metadata:\n          labels:\n            app: test\n        spec:\n          containers:\n            - name: container1\n              image: alpine:3\n              volumeMounts:\n                - name: vol1\n                  mountPath: /mnt/vol1\n            - name: container2\n              image: alpine:3\n---\napiVersion: batch/v1\nkind: Job\nmetadata:\n    name: test5\n    namespace: testns2\nspec:\n  template:\n    spec:\n      containers:\n        - name: container1\n          image: alpine:3\n          volumeMounts:\n            - name: vol1\n              mountPath: /mnt/vol1\n        - name: container2\n          image: alpine:3\n"
  },
  {
    "path": "internal/integration/cli/testdata/patches/delete-dummy-ap.yaml",
    "content": "---\napiVersion: v1alpha1\nkind: DummyLinkConfig\nname: dummy-ap-patch\n$patch: delete\n"
  },
  {
    "path": "internal/integration/cli/testdata/patches/dummy-ap.yaml",
    "content": "---\napiVersion: v1alpha1\nkind: DummyLinkConfig\nname: dummy-ap-patch\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl\ncm5ldGVzMB4XDTIyMDcwODExMTM0OFoXDTMyMDcwNTExMTM0OFowFTETMBEGA1UE\nAxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGI\nT8ncEbVJ7LtRTZY6Vc2bXlMtagzCqpP+29H7HtsgV4T64QJsPRnfCh0PzOit7JJq\nSRj526wHZRfSvu0M9wZ2KaC4MVDMP2KhBUKW63nUmdXQMf+z1gHKzCMloAMa0Avb\nDVsoc9NaiiHX8m59gX328xEHQjNxnNGIretBjsjZw/Xeo2BflVXahnnxMVJqnzEa\n0jpnGh5BaO4aPKDrJbyELz8Y8F+NGJ2zkSVtBh0gYZrejnioEiSFkSvcxDw3Xhg2\nQL+NUsRrhYHq10apJhuSkPkraCogbHlN33dslJ+I85xszKt437gGkpDoTKXaxe9L\nf9xB40PgToK9QfAOIFMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB\n/wQFMAMBAf8wHQYDVR0OBBYEFF06xQ3JTko0LcX5pvAdp+mLFWgMMBUGA1UdEQQO\nMAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBAIkhsj6yVvEoN4q7nj97\nvY0RpAOyysmhigHK0miioKsd94GDb+aMBYFLKliU48B5/n/KXblu7xsTane8uB3C\nVeBywkDXLN2a9ax4BaxIkleDOX1xZN4BtxIfdU1QGhFQU0JPDCMxbDjbfN2Kg2Wi\niESrsXYKDq2pLNeQdszxPGNlAOjssVHY6IivWOcMRHP0yCDTl5ooq180+U7smFdz\nNM/6udMOhsgh6bUCeMu9mhaPXMBmK0Lcd68PFunAA8q7a5OfTgIhGC9n7Q0L6CMw\n7yXb97bd9bPZqeiuw7G7+UiNkJrBdIMc0AYE+wG44Uxu9usrGZZt6zLYzfnJ2vRZ\nqac=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/ca.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAsYhPydwRtUnsu1FNljpVzZteUy1qDMKqk/7b0fse2yBXhPrh\nAmw9Gd8KHQ/M6K3skmpJGPnbrAdlF9K+7Qz3BnYpoLgxUMw/YqEFQpbredSZ1dAx\n/7PWAcrMIyWgAxrQC9sNWyhz01qKIdfybn2BffbzEQdCM3Gc0Yit60GOyNnD9d6j\nYF+VVdqGefExUmqfMRrSOmcaHkFo7ho8oOslvIQvPxjwX40YnbORJW0GHSBhmt6O\neKgSJIWRK9zEPDdeGDZAv41SxGuFgerXRqkmG5KQ+StoKiBseU3fd2yUn4jznGzM\nq3jfuAaSkOhMpdrF70t/3EHjQ+BOgr1B8A4gUwIDAQABAoIBAQCIvqY2pfw916Mw\n5X8NqAFPTc1p5CE7kvYw6K4JH5S01ESVeWi3pQerVdFEcVc0IkOGw7dqNYqvB0Mn\nBn1pugLMR1fpI/dYdPqdzclvcTAPt2KG/saEXtEIsFxs9h46RfzaJPA0twQAWEzt\npJhn4uRLUlwHUb/8QBa6jrzn6KdCrLC0jc0g8c77x3omkfy0chug7q2s/yX2MwEX\np5pbyPiGZkNIjuDeic3D0ssrH7v7gEYBdybgl78LrLkKA8gEFLrGvrT5nuLYhxkF\ndhRu3+p9mhhKmJQndto8Y4WeYhXZ7qN2YZbfcv1Xni6cq4UhLmr2czRaK0KVZ15H\nkzYh0I8BAoGBAOTjpoVVc+IgVJnGeglrJP8zOKEiwj3R+eF9DiQuTdnop0SBiqYB\nJT6/b/apdYEGz2nBs3M1k6CmNrkzGADMNins7m1MRHkljRqu1IHSF3Us2yifPUef\nlEUHtXf3ANvf3YJWuGO7RT4sird/1vXE/0TCzjWEvkHc6Zvky/DCydTJAoGBAMaP\nbWsiDSFpLV6iCiq18bmJJoUDnkXqnwsUVw9C978h2Hx5ysYfOUt6S6Q7UsR7hKW5\niay1aiFPBjLQyD4Ac8feZFQEQ5gFYXPEfIV3OYZDz2U+gAZp33ow7/H/73kngelV\n6EXhTYgDRUwfTBOMSlzhCZwQb8Rzpv+gC3TFsmY7AoGAWewB2LIYo8bV1c/+08Jv\nN39VCSERtJ3QkMDDlH1Igop/ZE+MO+mJS1yETSCIFFerlr3NlT6AMAX8y8eB75ZK\n1S/K/8+NuxaAl/IFdLcoFhW4R/4/YesUogYESgwVH0yUxobxS+Ufr+xp1ut3dPie\n3NG3l5j98fwrHt7FLGIqTtkCgYEAjezfDQCd2g/PuiCgm77JNRDvU4wuiVMWs1iq\nkeIQK7IJh4+WfN68mVKk1pMAqiiPu9VOrwBNB9nwWEoblxXDrE0t8U/K8NKHwbPk\nPZHmsC2wBHIUGIF8l157Y8LIbRTsKtiY2bodLOcJlUuZmS9hx9migMbO3OC9sWG4\nTpMw3RkCgYA8ssuhj5wrSQabCXbOU0pn/qbePHWfvh+DcRUXnTtRoothpqvDQxuS\n73j2NB42UG7j0eWRK993ONGTJ/QNMAJxXwLEuLFtoKHdh7pkq3uFolyNzR+T0vna\nawkSRmJsbuV7C4mDVHgEaqcEzv/VyeAokw/hqB1Ga9fvauj6MDPshw==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/etcd/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIC9TCCAd2gAwIBAgIBADANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwdldGNk\nLWNhMB4XDTIyMDcwODExMTM0OFoXDTMyMDcwNTExMTM0OFowEjEQMA4GA1UEAxMH\nZXRjZC1jYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOgw+tA7odeO\nH5gKPlhWBjijuNoLlMCJSkGG0Ca/fI6Bk2Y+fzuVv8NWsRrhML3dEWJgXccMhoG0\nv9MatmvF5nYfm802ZaDCsA6RdJG3PygRTw69pmC4ETfv0+YXpFFfFBeWWb9MsXIP\nULooepYy4bWvjG7ZDCeFQ8ACHGE17U0O5rFBqiY0okBjSkl1/oHSzlAVCxa4dOaK\n/Vj8A8CefT18JZ+jzAbgN7jRm1GWzYTWqACVa5CnRDYRglrZr9DLvaj0ASqck5DD\nzdJYVQJeVqS7L8qghXfbXzxlkKesRtQsj7V2trpDBuDASJPk6ZmwEWlaI0Wdc3eK\nnYHgaWybLykCAwEAAaNWMFQwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB/wQFMAMB\nAf8wHQYDVR0OBBYEFKN5e0IuTpOoTqWB9+MQp/k/OgXgMBIGA1UdEQQLMAmCB2V0\nY2QtY2EwDQYJKoZIhvcNAQELBQADggEBAGmGUUqeGe4RXd3kZGTRcdJMo7OkuEK5\nhH/FHfrLLc3VNoWQafdq4oVrF9bwqDUPRuPgrXl+QY+s4/ztDyHmuKGdLWIT2dCE\n0Ztnpe17VoMrkJxmFvKEWrT74EnT0QIeFs+lf8+SJWTLYKBRpGrsQKq84uds++gV\nBPLuu8Z0e5vvkAFnX8m65SqyZwKfs3HuzaAnA57VGSJHCBrnKojsP8JdlWeQiStG\nCtmzePeLqjVJnpNF/n1ST5Ewr4Kq/Cvf707gzs+spn0bt97QyNke6b24ZrkpUNu6\nT/0bImLeYiGmSanRF3hAdN7IV0ah7tYOpmwk560kyF8tmd8jcKFgEd8=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/etcd/ca.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA6DD60Duh144fmAo+WFYGOKO42guUwIlKQYbQJr98joGTZj5/\nO5W/w1axGuEwvd0RYmBdxwyGgbS/0xq2a8Xmdh+bzTZloMKwDpF0kbc/KBFPDr2m\nYLgRN+/T5hekUV8UF5ZZv0yxcg9Quih6ljLhta+MbtkMJ4VDwAIcYTXtTQ7msUGq\nJjSiQGNKSXX+gdLOUBULFrh05or9WPwDwJ59PXwln6PMBuA3uNGbUZbNhNaoAJVr\nkKdENhGCWtmv0Mu9qPQBKpyTkMPN0lhVAl5WpLsvyqCFd9tfPGWQp6xG1CyPtXa2\nukMG4MBIk+TpmbARaVojRZ1zd4qdgeBpbJsvKQIDAQABAoIBAHI8xun0rOfU8Q5o\n28uyZ1UumCAPWpxv76zVm0u1Ip8qeU7wqMC0KKj+2hwTd1uyjH8OUpVAQF1IhKhk\nmCPmNkEfxBPvE4lIwD4qqmOW+OfJvE/QVy924GHZCTRHpXyzfrssKfPI0/T+PAWb\nLNUBK7OsLzfKagR3uKGbaEMbuSkTn5zeCJ1vrFAuCaLmeauBsnoV7Z9AlbG6t8sp\nhyD0O+pDPGuc+J99suGiysndwjczqntIKXcdgba2XxRE0QHM+ZYDPpyvCggKfoUH\nsQ9Vz/UHpqTv8pbrTSZK59E8+16YfFyFC+iwTnTzoBAkO6NIivDTQvLcipweZEzt\n5146EEECgYEA6O+Pd1tdkTVHLgSkKrkBo4p3g2iBFl626g7vlZGvDjVNNPBWwk5f\nj3PbMKPfUfr96YB86lbetDzYdiB5LrLW5xG2GaSRziGI1/Tgdp6aR142TNljiEu7\ndv4v3eAR5VfiA5CGera+k1VzKLIygfCDkUWWdG17LvVdHFtjN6XVU2UCgYEA/y6M\nhZbZqCX9cx58rhJ38YvH9fdWSzw1r9crgM40uPHE4SHvin6/lR/rbNU4Geg/b4bn\nFWnffCem8ov2tXcFe/ZBM8ZWrsRGDinkTh8dReh8ujE90YOqf3YSRYgUvSx8ITUn\nzqhe43sGVAelKeVKPW/3Ok7RJXnRRsDIbSmfqnUCgYB7sDmON4XHxXK2jOBfjz2/\niZdMwAFLz59xSd0Onv1FnigRJE3tf5BerDaH7Xx4G78YbpHmHZrEOkr27udqVKyo\npk777tc9jbEMe4t1cWKa4vwScpzXkt9IoFDqkEDwd2ocWnIOV1t7ALTVt0n6laxH\nR5xM1pXCqad3l09oDTbpwQKBgDlHwqVOCkeTV4QayNPuM1xWCymsPoOe3VI+U3aT\nUwRcyNvcWT/WWbzosFj6t6AhIPQw7PhCjrb406HIRzXOpL2Btnsfv191kWAmiSf8\nFf8WQ8ErwnugOYpo/4r6E+Wu8aImo2vhIYOgnvgHy0xPOs31ryI4hPwLjy15osPW\nPw/tAoGBAKaT53bqIl+wzltM2ROtH9ppA98prDPM0GyZMhFed+XMLAkUX3qmFtj5\nk51bhaq7ER4yByHX17Q7y3SoJ5NpccmFUhWhttRf/IraWEKsHXW6OY22wvtZN9Lx\nEh+rpZsjcozUCaoQWkOf20UpBSltIV5U4GmSpthnj0+zaRrorxWx\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/front-proxy-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5mcm9u\ndC1wcm94eS1jYTAeFw0yMjA3MDgxMTEzNDhaFw0zMjA3MDUxMTEzNDhaMBkxFzAV\nBgNVBAMTDmZyb250LXByb3h5LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA4thL1utf/iXxylt24O3o3IV7oif5tiYR4SN9YnVb/GLyVtVdHuzPpigw\nj+S7aw3mldNHVWbIPq9GncvVsgvlJYHu53WRzVfV7tAylt/ssSqHFv/p1e6rC2m9\nhETHUZjSs8v0APWi8pfh15lJPqLS1lGF3QPVCPdc1t+8dBVnx8wnTgGVE7FVLjmc\n3qIcXTR1TfcB4+X1ZnY5FNK7kR/kgIS64uZqntyNSW5W0SCFgWQClwwkzVpo4v/Y\nsCHiWI7cIuXHTTd7ntHJab1Og1jAPNEmENvEtza1SqGTSEUQs5wjS+p+ii5E09b3\nNufj1e8hJaodTxr+24hoFcYxWIgxhwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAqQw\nDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvw91sUxAgIX7zdqTKwJ0Sdxa9TUw\nGQYDVR0RBBIwEIIOZnJvbnQtcHJveHktY2EwDQYJKoZIhvcNAQELBQADggEBAGHW\nsnsEJkN3d2vNJuFu6IVKurEZM8UbwHebJ5fQUHpCOKpFqSMdngF8rdcYNmHeUFMv\nQf9Fkm9nwKOhO9hApsQad7UgJ98YCzE+heTye7nKjrga+2lsJN/T3SgJGiAEkVjP\nrq2SQ4MLCp56PyFI5CL9zqtjuXCI8Uhqqfru6tJEA75GA6VJZmfiOgzFQum7DeC2\n9dNcvQb8p91LIl5tjvuTgPbJDjF1YX4n0iwoiA05e+rPrsPhyySQnJwFgTi+hqPZ\ncBUPwVDYeiHseRbj3ODOoCv6PO4koO5m+tiFeUXJTynMbCUkyJqZ11TAYC6snHxi\nmg+fblveomK3F3hLFdk=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/front-proxy-ca.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA4thL1utf/iXxylt24O3o3IV7oif5tiYR4SN9YnVb/GLyVtVd\nHuzPpigwj+S7aw3mldNHVWbIPq9GncvVsgvlJYHu53WRzVfV7tAylt/ssSqHFv/p\n1e6rC2m9hETHUZjSs8v0APWi8pfh15lJPqLS1lGF3QPVCPdc1t+8dBVnx8wnTgGV\nE7FVLjmc3qIcXTR1TfcB4+X1ZnY5FNK7kR/kgIS64uZqntyNSW5W0SCFgWQClwwk\nzVpo4v/YsCHiWI7cIuXHTTd7ntHJab1Og1jAPNEmENvEtza1SqGTSEUQs5wjS+p+\nii5E09b3Nufj1e8hJaodTxr+24hoFcYxWIgxhwIDAQABAoIBAQDa55WQCcWxkNZa\ny5bVimBbZeif2+nKj8RTOZdGyzAAR0/K4c0iCa58jm4GfdkqftiUnrVIwY3dh/Ei\nV1CZp4byggeUjs0rlmaZNYqMM/zKHtsMI9t4mf+vXNQI7wJVSJ+T5+5IesJLTqwf\nDQo0ipXhQfxnAsqzA1ow9Ol8MCfdEeFL5SFaVNiNhany/7PR0letngwMIAje6arY\n6dPzjPYDsCjMTjoNarUADIZeVxMdbOCmiMy+yGDZlgV80fK0+Fw81axot2KOufhy\nCvqClUlJV5Csz2egHuThuVd39kX2vAAGXdPEUbXga1JTDB3cQiHXJo0hLUsUGniS\n6KdsJOyRAoGBAOmNX/V7awLiVyWsRLTNr1IeoMwHeS3Wdt5/nedqh6p2fLpfbN1D\nM8R29yqvNn1YmpZsDBhQlnddq7i7OEKjSODwNnLPys6fqalsIY/AIRJPOmHvVJl6\ner4scaiGXA/FztvxGGQh4W92+Nb69dCXXXcG1QUljr+uGwrIGXc8aqzpAoGBAPil\n4qGf/0s3Fv0tyLj+ZRWVjg5o4s/IsJyGRFc6RplU65y9VL9WsYvi5+d06w7lovac\nomycJ/z+HiqTLcixdcHse54N9HHO5Ekui6cRbGAOdlzgS84TxYrmQK/FQkFvlcmO\nrsfkDMmAgBc2yGP3N5IL60u90N2Kf3OiT5aHoCTvAoGAamdwioS6EkxQa+d6Pe1f\nrMgrdgkJmmqVKXV22VHdkTn+RWLoVD4jvaR9o0LEToMpmtKLCCDfDG7up3EUhreh\nommOROyKd2yifX+4Iqfj6VWTQb8qCeqVNUNGXQMpuj3iqq3C8QvGi2PmpvsbNvdf\nK7U/I+MikA2gYF8dywcJitECgYArDe5UNjQqffuJE2hyP/qY5jCW5ip/+Cw8rjMf\nN4QKAN5bYZ1PFF/h7QRi26foCHNTaIPncpKqCAaJMLr4yWGulphBIgF1w3FcCqc7\n4pR1fYuZQW1e3aWTC5Of2/RBCGVTZVV2X1KngYyseFvyk1gX/eBcWR3VfqnbB/vo\nAMwGGQKBgB/MXrB2Z61WlxR0Y289k+5gjUSS9foZIkCjr1TFDvLbEStAW8Z3WFcS\nGxzjs5s45VO3+KRRd3591WHaPWcVdNze+y5ICUr4u3WSBKg8D+9H3cMKWq8QLCRP\nbgMDGq8TzTLdGmb9vw3n5OG2aAQUQfwoAp+uUwh2EDMDYixYd2UJ\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "internal/integration/cli/testdata/pki/sa.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0H28tj4Zgoj5y+/NF7Dhrf96+TQUolLR5j4YqoxbFRvgWtPE\n0JFueoC0n6v4l58z4vog+1JjPHMO8rr0W3q9o/wWaY1CL3XqZJIkHI/fE/Eu1VLv\ngLfDHsPevPNLczcpwXo7AadqxiUC/HRYZBJY+LA2OzWwO5ylx4YKnOzKxBXQ7a2q\nqdpwZJSTTmGKyRx5pD6V5mCr47ITVAXqcjorTtJmG3zCFRhUjMscXIWC04S0IY/C\n+cfMKaK4Jbqj1h2/9uNhbb55r9HdCEV/TLw+QL1Q+S6MWtng1S4Q3hyDXzB1LqfP\n1brz7xl1pSLh+l0vF2pXom5zYiHlX4cAddR7MQIDAQABAoIBAAQtULeR/O7Zka+d\nSU2dNJhI0wzlFzi9Ugk720CneTeuDEuljH7lOwJnS7cbOerHvMFiY4DFgMl4QKdq\nSXT/u4bqiQRqWRYcVarYJrMPytdacKbDd5rrk5QtNmwwr6VKSKLgsQfyc7gui6XF\nKvQuTewFk8CR7crz83pQ3CuSrulIwVny17HSE9NlXlv8SlHy7E2/a6H0UeOm7BRn\n13An62CfRuBVFRd96oyTMpuNf2l+fcL5nnfM/F+tdr5MRR0pnEW2UKGdCbkTkAKd\nAJnH2mmhWwbA8Gcx0Zn1X9/zu8Z3S6hTGnQmWIP25EcgipqKe/gocA9ervyR+0nb\nFgwZZXECgYEA6D/mx3dI6AUY7RVIY9GexiJWLtS9O1d7PddmajoqVpwtjXT9jUf/\n9BAAVWNKcIEs1t4foncJeYph6JnTrQjDz1LORC2kAjPUYhDQod/m6dqHxvjRAIns\nv0NezDvWQ2v8CgklDjUc5hYtvqj51OkkbKpphRClAdJZvrlxBhXTT1UCgYEA5c/c\nA6D3xIcGUrSVrjtLWUyJ9hszjjBrI5txtmwMzWDSkV3Hp1VhSfhCdIxqQxELxlxS\nA8SOU0XKxRB7QiwpgHfnbGxtQ8tJ5JufIecwJkqRcD5fqQk69xva/76fNfes41L8\ndoNpFiu0fXbVdcB8UNN61VYsz31D/JD0qA9k5G0CgYEA5gq1egkrC7ZQ1DRqeYSd\n8b79AnHx5Z9nEQAUD1ABs7wKWrzwkEoqugJHckxg5ULtuP5W80NY/SwWgqArTI8L\n9IUejeVvOEdCLMhe/peaTzQHnQvDaPc0qtX+RelW9300LnSUYZg2QajiMqGIpF0x\nmPjKf+TWrBFAl2tzCgYAQekCgYEAukqjaXWlI/To1UZ6R8DdNchr1cr7Ifpx/21U\n4rH4NsyUJS7GWAlIUnQjOuNQiIla6DOScGd3kF11IAZaRKwUAIYyXZwPfvNeNSlJ\n+Gu2hnPQLhMB7L8Ew6gbAVH/MfpSdfyhl1izaTuIlmQsacXdgI/OdP3kWVaMNEM1\ncL755IkCgYAv10G49Mc57WBi6knRHM2cXbYVxjzedJf8zBnAYkQoLdRiYT6uj34U\nhI1EajSfXYJ2t8PG5nbHMNHAEbYNBikhjDvSrZW+HaTmjsVGV25cqCHPy7giSqVS\nVftcMlIX/MlTdfcYtNT4wHORZdO2P4wW/y5JSFNol4z3xB4TNXp55A==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "internal/integration/cli/time.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// TimeSuite verifies dmesg command.\ntype TimeSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *TimeSuite) SuiteName() string {\n\treturn \"cli.TimeSuite\"\n}\n\n// TestDefault runs default time check.\nfunc (suite *TimeSuite) TestDefault() {\n\tsuite.RunCLI([]string{\"time\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`NTP-SERVER`)),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`UTC`)),\n\t\tbase.WithRetry(retry.Constant(time.Minute, retry.WithUnits(time.Second))),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(TimeSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/validate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// ValidateSuite verifies dmesg command.\ntype ValidateSuite struct {\n\tbase.CLISuite\n\n\ttmpDir   string\n\tsavedCwd string\n}\n\n// SuiteName ...\nfunc (suite *ValidateSuite) SuiteName() string {\n\treturn \"cli.ValidateSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ValidateSuite) SetupTest() {\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tvar err error\n\n\tsuite.savedCwd, err = os.Getwd()\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(os.Chdir(suite.tmpDir))\n}\n\n// TearDownTest ...\nfunc (suite *ValidateSuite) TearDownTest() {\n\tif suite.savedCwd != \"\" {\n\t\tsuite.Require().NoError(os.Chdir(suite.savedCwd))\n\t}\n}\n\n// TestValidate generates config and validates it for all the modes.\nfunc (suite *ValidateSuite) TestValidate() {\n\tsuite.RunCLI([]string{\"gen\", \"config\", \"foobar\", \"https://10.0.0.1\"},\n\t\tbase.StdoutEmpty(),\n\t\tbase.StderrNotEmpty(),\n\t)\n\n\tfor _, configFile := range []string{\"controlplane.yaml\", \"worker.yaml\"} {\n\t\tfor _, mode := range []string{\"cloud\", \"metal\"} {\n\t\t\tsuite.Run(fmt.Sprintf(\"%s-%s\", configFile, mode), func() {\n\t\t\t\tsuite.RunCLI([]string{\"validate\", \"-m\", mode, \"-c\", configFile, \"--strict\"})\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ValidateSuite))\n}\n"
  },
  {
    "path": "internal/integration/cli/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_cli\n\npackage cli\n\nimport (\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// VersionSuite verifies version command.\ntype VersionSuite struct {\n\tbase.CLISuite\n}\n\n// SuiteName ...\nfunc (suite *VersionSuite) SuiteName() string {\n\treturn \"cli.VersionSuite\"\n}\n\n// TestExpectedVersionMaster verifies master node version matches expected.\nfunc (suite *VersionSuite) TestExpectedVersionMaster() {\n\tsuite.RunCLI([]string{\"version\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`Client:\\n\\s*Tag:\\s*`+regexp.QuoteMeta(suite.Version))),\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`Server:\\n(\\s*NODE:[^\\n]+\\n)?\\s*Tag:\\s*`+regexp.QuoteMeta(suite.Version))),\n\t)\n}\n\n// TestShortVersion verifies short version output.\nfunc (suite *VersionSuite) TestShortVersion() {\n\tsuite.RunCLI([]string{\"version\", \"--short\", \"--nodes\", suite.RandomDiscoveredNodeInternalIP()},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(regexp.QuoteMeta(version.Name)+`\\s*`+regexp.QuoteMeta(suite.Version))),\n\t)\n}\n\n// TestClient verifies only client version output.\nfunc (suite *VersionSuite) TestClient() {\n\tsuite.RunCLI([]string{\"version\", \"--client\"},\n\t\tbase.StdoutShouldMatch(regexp.MustCompile(`Client:\\n\\s*Tag:\\s*`+regexp.QuoteMeta(suite.Version))),\n\t\tbase.StdoutShouldNotMatch(regexp.MustCompile(`Server`)),\n\t)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(VersionSuite))\n}\n"
  },
  {
    "path": "internal/integration/integration_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package integration_test contains core runners for integration tests\npackage integration_test\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/integration/api\"\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/internal/integration/cli\"\n\t\"github.com/siderolabs/talos/internal/integration/k8s\"\n\tprovision_test \"github.com/siderolabs/talos/internal/integration/provision\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers\"\n)\n\n// Accumulated list of all the suites to run.\nvar allSuites []suite.TestingSuite\n\n// Flag values.\nvar (\n\tfailFast         bool\n\ttrustedBoot      bool\n\tselinuxEnforcing bool\n\textensionsQEMU   bool\n\textensionsNvidia bool\n\tverifyUKIBooted  bool\n\tairgapped        bool\n\tvirtiofsd        bool\n\trace             bool\n\n\ttalosConfig       string\n\tendpoint          string\n\tk8sEndpoint       string\n\texpectedVersion   string\n\texpectedGoVersion string\n\ttalosctlPath      string\n\tkubectlPath       string\n\thelmPath          string\n\tkubeStrPath       string\n\tprovisionerName   string\n\tclusterName       string\n\tstateDir          string\n\ttalosImage        string\n\tcsiTestName       string\n\tcsiTestTimeout    string\n)\n\n// TestIntegration ...\n//\n//nolint:gocyclo\nfunc TestIntegration(t *testing.T) {\n\tif talosConfig == \"\" {\n\t\tt.Error(\"--talos.config is not provided\")\n\t}\n\n\tvar (\n\t\tcluster     provision.Cluster\n\t\tprovisioner provision.Provisioner\n\t\terr         error\n\t)\n\n\tif provisionerName != \"\" {\n\t\t// use provisioned cluster state as discovery source\n\t\tctx := t.Context()\n\n\t\tprovisioner, err = providers.Factory(ctx, provisionerName)\n\t\tif err != nil {\n\t\t\tt.Error(\"error initializing provisioner\", err)\n\t\t}\n\n\t\tdefer provisioner.Close() //nolint:errcheck\n\n\t\tcluster, err = provisioner.Reflect(ctx, clusterName, stateDir)\n\t\tif err != nil {\n\t\t\tt.Error(\"error reflecting cluster via provisioner\", err)\n\t\t}\n\n\t\tif k8sEndpoint == \"\" && provisionerName == base.ProvisionerDocker {\n\t\t\tk8sEndpoint = cluster.Info().KubernetesEndpoint\n\t\t}\n\t}\n\n\tprovision_test.DefaultSettings.CurrentVersion = expectedVersion\n\n\tfor _, s := range allSuites {\n\t\tif configuredSuite, ok := s.(base.ConfiguredSuite); ok {\n\t\t\tconfiguredSuite.SetConfig(base.TalosSuite{\n\t\t\t\tEndpoint:         endpoint,\n\t\t\t\tK8sEndpoint:      k8sEndpoint,\n\t\t\t\tCluster:          cluster,\n\t\t\t\tTalosConfig:      talosConfig,\n\t\t\t\tVersion:          expectedVersion,\n\t\t\t\tGoVersion:        expectedGoVersion,\n\t\t\t\tTalosctlPath:     talosctlPath,\n\t\t\t\tKubectlPath:      kubectlPath,\n\t\t\t\tHelmPath:         helmPath,\n\t\t\t\tKubeStrPath:      kubeStrPath,\n\t\t\t\tExtensionsQEMU:   extensionsQEMU,\n\t\t\t\tExtensionsNvidia: extensionsNvidia,\n\t\t\t\tTrustedBoot:      trustedBoot,\n\t\t\t\tSelinuxEnforcing: selinuxEnforcing,\n\t\t\t\tVerifyUKIBooted:  verifyUKIBooted,\n\t\t\t\tTalosImage:       talosImage,\n\t\t\t\tCSITestName:      csiTestName,\n\t\t\t\tCSITestTimeout:   csiTestTimeout,\n\t\t\t\tAirgapped:        airgapped,\n\t\t\t\tVirtiofsd:        virtiofsd,\n\t\t\t\tRace:             race,\n\t\t\t})\n\t\t}\n\n\t\tvar suiteName string\n\t\tif namedSuite, ok := s.(base.NamedSuite); ok {\n\t\t\tsuiteName = namedSuite.SuiteName()\n\t\t}\n\n\t\tt.Run(suiteName, func(tt *testing.T) {\n\t\t\tsuite.Run(tt, s) //nolint:scopelint\n\t\t})\n\n\t\tif failFast && t.Failed() {\n\t\t\tt.Log(\"fastfail mode enabled, aborting on first failure\")\n\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc init() {\n\tdefaultTalosConfigs, _ := clientconfig.GetDefaultPaths() //nolint:errcheck\n\n\tdefaultStateDir, err := clientconfig.GetTalosDirectory()\n\tif err == nil {\n\t\tdefaultStateDir = filepath.Join(defaultStateDir, \"clusters\")\n\t}\n\n\tflag.BoolVar(&failFast, \"talos.failfast\", false, \"fail the test run on the first failed test\")\n\tflag.BoolVar(&trustedBoot, \"talos.trustedboot\", false, \"enable tests for trusted boot mode\")\n\tflag.BoolVar(&selinuxEnforcing, \"talos.enforcing\", false, \"enable tests for SELinux enforcing mode\")\n\tflag.BoolVar(&extensionsQEMU, \"talos.extensions.qemu\", false, \"enable tests for qemu extensions\")\n\tflag.BoolVar(&extensionsNvidia, \"talos.extensions.nvidia\", false, \"enable tests for nvidia extensions\")\n\tflag.BoolVar(&race, \"talos.race\", false, \"skip tests that are incompatible with race detector\")\n\tflag.BoolVar(&verifyUKIBooted, \"talos.verifyukibooted\", true, \"enable tests for verifying that Talos was booted using a UKI\")\n\n\tflag.StringVar(\n\t\t&talosConfig,\n\t\t\"talos.config\",\n\t\tdefaultTalosConfigs[0].Path,\n\t\tfmt.Sprintf(\"The path to the Talos configuration file. Defaults to '%s' env variable if set, otherwise '%s' and '%s' in order.\",\n\t\t\tconstants.TalosConfigEnvVar,\n\t\t\tfilepath.Join(\"$HOME\", constants.TalosDir, constants.TalosconfigFilename),\n\t\t\tfilepath.Join(constants.ServiceAccountMountPath, constants.TalosconfigFilename),\n\t\t),\n\t)\n\tflag.StringVar(&endpoint, \"talos.endpoint\", \"\", \"endpoint to use (overrides config)\")\n\tflag.StringVar(&k8sEndpoint, \"talos.k8sendpoint\", \"\", \"Kubernetes endpoint to use (overrides kubeconfig)\")\n\tflag.StringVar(&provisionerName, \"talos.provisioner\", \"\", \"Talos cluster provisioner to use, if not set cluster state is disabled\")\n\tflag.StringVar(&stateDir, \"talos.state\", defaultStateDir, \"directory path to store cluster state\")\n\tflag.StringVar(&clusterName, \"talos.name\", \"talos-default\", \"the name of the cluster\")\n\tflag.StringVar(&expectedVersion, \"talos.version\", version.Tag, \"expected Talos version\")\n\tflag.StringVar(&expectedGoVersion, \"talos.go.version\", constants.GoVersion, \"expected Talos version\")\n\tflag.StringVar(&talosctlPath, \"talos.talosctlpath\", \"talosctl\", \"The path to 'talosctl' binary\")\n\tflag.StringVar(&kubectlPath, \"talos.kubectlpath\", \"kubectl\", \"The path to 'kubectl' binary\")\n\tflag.StringVar(&helmPath, \"talos.helmpath\", \"helm\", \"The path to 'helm' binary\")\n\tflag.StringVar(&kubeStrPath, \"talos.kubestrpath\", \"kubestr\", \"The path to 'kubestr' binary\")\n\tflag.StringVar(&talosImage, \"talos.image\", images.DefaultTalosImageRepository, \"The default 'talos' container image\")\n\tflag.StringVar(&csiTestName, \"talos.csi\", \"\", \"CSI test to run\")\n\tflag.StringVar(&csiTestTimeout, \"talos.csi.timeout\", \"15m\", \"CSI test timeout\")\n\tflag.BoolVar(&airgapped, \"talos.airgapped\", false, \"Marker to skip tests that should not be run on airgapped talos cluster\")\n\tflag.BoolVar(&virtiofsd, \"talos.virtiofsd\", false, \"Marker to skip tests that should not be run without virtiofsd\")\n\n\tflag.StringVar(&provision_test.DefaultSettings.CIDR, \"talos.provision.cidr\", provision_test.DefaultSettings.CIDR, \"CIDR to use to provision clusters (provision tests only)\")\n\tflag.Var(&provision_test.DefaultSettings.RegistryMirrors, \"talos.provision.registry-mirror\", \"registry mirrors to use (provision tests only)\")\n\tflag.IntVar(&provision_test.DefaultSettings.MTU, \"talos.provision.mtu\", provision_test.DefaultSettings.MTU, \"MTU to use for cluster network (provision tests only)\")\n\tflag.Int64Var(&provision_test.DefaultSettings.CPUs, \"talos.provision.cpu\", provision_test.DefaultSettings.CPUs, \"CPU count for each VM (provision tests only)\")\n\tflag.Int64Var(&provision_test.DefaultSettings.MemMB, \"talos.provision.mem\", provision_test.DefaultSettings.MemMB, \"memory (in MiB) for each VM (provision tests only)\")\n\tflag.Uint64Var(&provision_test.DefaultSettings.DiskGB, \"talos.provision.disk\", provision_test.DefaultSettings.DiskGB, \"disk size (in GiB) for each VM (provision tests only)\")\n\tflag.IntVar(&provision_test.DefaultSettings.ControlplaneNodes, \"talos.provision.controlplanes\", provision_test.DefaultSettings.ControlplaneNodes, \"controlplane node count (provision tests only)\")\n\tflag.IntVar(&provision_test.DefaultSettings.WorkerNodes, \"talos.provision.workers\", provision_test.DefaultSettings.WorkerNodes, \"worker node count (provision tests only)\")\n\tflag.StringVar(&provision_test.DefaultSettings.TargetInstallImageRegistry, \"talos.provision.target-installer-registry\",\n\t\tprovision_test.DefaultSettings.TargetInstallImageRegistry, \"image registry for target installer image (provision tests only)\")\n\tflag.StringVar(&provision_test.DefaultSettings.CustomCNIURL, \"talos.provision.custom-cni-url\", provision_test.DefaultSettings.CustomCNIURL, \"custom CNI URL for the cluster (provision tests only)\")\n\tflag.StringVar(&provision_test.DefaultSettings.CNIBundleURL, \"talos.provision.cni-bundle-url\", provision_test.DefaultSettings.CNIBundleURL, \"URL to download CNI bundle from\")\n\n\tallSuites = slices.Concat(api.GetAllSuites(), cli.GetAllSuites(), k8s.GetAllSuites(), provision_test.GetAllSuites())\n}\n"
  },
  {
    "path": "internal/integration/k8s/apparmor.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// ApparmorSuite verifies that a pod with apparmor security context with `RuntimeDefault` works.\ntype ApparmorSuite struct {\n\tbase.K8sSuite\n}\n\n//go:embed testdata/apparmor.yaml\nvar apparmorPodSpec []byte\n\n// SuiteName returns the name of the suite.\nfunc (suite *ApparmorSuite) SuiteName() string {\n\treturn \"k8s.ApparmorSuite\"\n}\n\n// TestApparmor verifies that a pod with apparmor security context with `RuntimeDefault` works.\nfunc (suite *ApparmorSuite) TestApparmor() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping apparmor test since provisioner is not qemu\")\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\n\tsuite.T().Cleanup(cancel)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeCtx := client.WithNodes(ctx, node)\n\n\treader, err := suite.Client.Read(nodeCtx, \"/sys/kernel/security/lsm\")\n\tsuite.Require().NoError(err)\n\n\t// read from reader into a buffer\n\tvar lsm bytes.Buffer\n\n\t_, err = lsm.ReadFrom(reader)\n\tsuite.Require().NoError(err)\n\n\tif !strings.Contains(lsm.String(), \"apparmor\") {\n\t\tsuite.T().Skip(\"skipping apparmor test since apparmor is not enabled\")\n\t}\n\n\tapparmorPodManifest := suite.ParseManifests(apparmorPodSpec)\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, apparmorPodManifest)\n\t})\n\n\tsuite.ApplyManifests(ctx, apparmorPodManifest)\n\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(ctx, time.Minute, \"default\", \"nginx-apparmor\"))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ApparmorSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package k8s provides Kubernetes integration tests.\npackage k8s\n\nconst (\n\t// RookCephHelmChartVersion is the version of the Rook Ceph Helm chart to use.\n\t// renovate: datasource=helm versioning=helm depName=rook-ceph registryUrl=https://charts.rook.io/release\n\tRookCephHelmChartVersion = \"v1.19.2\"\n\t// LongHornHelmChartVersion is the version of the Longhorn Helm chart to use.\n\t// renovate: datasource=helm versioning=helm depName=longhorn registryUrl=https://charts.longhorn.io\n\tLongHornHelmChartVersion = \"v1.11.0\"\n\t// OpenEBSChartVersion is the version of the OpenEBS Helm chart to use.\n\t// renovate: datasource=helm versioning=helm depName=openebs registryUrl=https://openebs.github.io/openebs\n\tOpenEBSChartVersion = \"v4.4.0\"\n)\n"
  },
  {
    "path": "internal/integration/k8s/k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package k8s provides Kubernetes integration tests for Talos\npackage k8s\n\nimport \"github.com/stretchr/testify/suite\"\n\nvar allSuites []suite.TestingSuite\n\n// GetAllSuites returns all the suites for K8s test.\n//\n// Depending on build tags, this might return different lists.\nfunc GetAllSuites() []suite.TestingSuite {\n\treturn allSuites\n}\n"
  },
  {
    "path": "internal/integration/k8s/longhorn.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\nvar (\n\t//go:embed testdata/longhorn-iscsi-volume.yaml\n\tlongHornISCSIVolumeManifest []byte\n\n\t//go:embed testdata/longhorn-volumeattachment.yaml\n\tlongHornISCSIVolumeAttachmentManifestTemplate []byte\n\n\t//go:embed testdata/pod-iscsi-volume.yaml\n\tpodWithISCSIVolumeTemplate []byte\n\n\t//go:embed testdata/longhorn-v2-engine-values.yaml\n\tlonghornEngineV2Values []byte\n\n\t//go:embed testdata/longhorn-v2-storageclass.yaml\n\tlonghornV2StorageClassManifest []byte\n\n\t//go:embed testdata/longhorn-v2-disk-patch.yaml\n\tlonghornNodeDiskPatch []byte\n)\n\n// LongHornSuite tests deploying Longhorn.\ntype LongHornSuite struct {\n\tbase.K8sSuite\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *LongHornSuite) SuiteName() string {\n\treturn \"k8s.LongHornSuite\"\n}\n\n// TestDeploy tests deploying Longhorn and running a simple test.\nfunc (suite *LongHornSuite) TestDeploy() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif suite.CSITestName != \"longhorn\" {\n\t\tsuite.T().Skip(\"skipping longhorn test as it is not enabled\")\n\t}\n\n\ttimeout, err := time.ParseDuration(suite.CSITestTimeout)\n\tif err != nil {\n\t\tsuite.T().Fatalf(\"failed to parse timeout: %v\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tsuite.T().Cleanup(cancel)\n\n\tif err := suite.HelmInstall(\n\t\tctx,\n\t\t\"longhorn-system\",\n\t\t\"https://charts.longhorn.io\",\n\t\tLongHornHelmChartVersion,\n\t\t\"longhorn\",\n\t\t\"longhorn\",\n\t\tlonghornEngineV2Values,\n\t); err != nil {\n\t\tsuite.T().Fatalf(\"failed to install Longhorn chart: %v\", err)\n\t}\n\n\tlonghornV2StorageClassunstructured := suite.ParseManifests(longhornV2StorageClassManifest)\n\n\tsuite.ApplyManifests(ctx, longhornV2StorageClassunstructured)\n\n\tsuite.T().Cleanup(func() {\n\t\tsuite.DeleteManifests(ctx, longhornV2StorageClassunstructured)\n\t})\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(ctx, machine.TypeWorker)\n\n\tsuite.Require().Equal(3, len(nodes), \"expected 3 worker nodes\")\n\n\tfor _, node := range nodes {\n\t\tk8sNode, err := suite.GetK8sNodeByInternalIP(ctx, node)\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(suite.WaitForResourceToBeAvailable(ctx, 2*time.Minute, \"longhorn-system\", \"longhorn.io\", \"Node\", \"v1beta2\", k8sNode.Name))\n\n\t\tsuite.Require().NoError(suite.WaitForResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Node\", \"v1beta2\", k8sNode.Name, \"{.status.diskStatus.*.conditions[?(@.type==\\\"Ready\\\")].status}\", \"True\"))\n\t\tsuite.Require().NoError(suite.WaitForResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Node\", \"v1beta2\", k8sNode.Name, \"{.status.diskStatus.*.conditions[?(@.type==\\\"Schedulable\\\")].status}\", \"True\"))\n\n\t\tsuite.PatchK8sObject(ctx, \"longhorn-system\", \"longhorn.io\", \"Node\", \"v1beta2\", k8sNode.Name, longhornNodeDiskPatch)\n\t}\n\n\tsuite.Run(\"fio\", func() {\n\t\tsuite.Require().NoError(suite.RunFIOTest(ctx, \"longhorn\", \"10G\"))\n\t})\n\n\tsuite.Run(\"fio-v2\", func() {\n\t\tsuite.Require().NoError(suite.RunFIOTest(ctx, \"longhorn-v2\", \"10G\"))\n\t})\n\n\tsuite.Run(\"iscsi\", func() {\n\t\tsuite.testDeployISCSI(ctx)\n\t})\n}\n\n//nolint:gocyclo\nfunc (suite *LongHornSuite) testDeployISCSI(ctx context.Context) {\n\tlongHornISCSIVolumeManifestUnstructured := suite.ParseManifests(longHornISCSIVolumeManifest)\n\n\tdefer func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), 2*time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, longHornISCSIVolumeManifestUnstructured)\n\t}()\n\n\tsuite.ApplyManifests(ctx, longHornISCSIVolumeManifestUnstructured)\n\n\ttmpl, err := template.New(\"longhorn-iscsi-volumeattachment\").Parse(string(longHornISCSIVolumeAttachmentManifestTemplate))\n\tsuite.Require().NoError(err)\n\n\tvar longHornISCSIVolumeAttachmentManifest bytes.Buffer\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeInfo, err := suite.GetK8sNodeByInternalIP(ctx, node)\n\tif err != nil {\n\t\tsuite.T().Fatalf(\"failed to get K8s node by internal IP: %v\", err)\n\t}\n\n\tif err := tmpl.Execute(&longHornISCSIVolumeAttachmentManifest, struct {\n\t\tNodeID string\n\t}{\n\t\tNodeID: nodeInfo.Name,\n\t}); err != nil {\n\t\tsuite.T().Fatalf(\"failed to render Longhorn ISCSI volume manifest: %v\", err)\n\t}\n\n\tlongHornISCSIVolumeAttachmentManifestUnstructured := suite.ParseManifests(longHornISCSIVolumeAttachmentManifest.Bytes())\n\n\tsuite.ApplyManifests(ctx, longHornISCSIVolumeAttachmentManifestUnstructured)\n\n\tif err := suite.WaitForResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Volume\", \"v1beta2\", \"iscsi\", \"{.status.robustness}\", \"healthy\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for LongHorn Engine to be Ready: %v\", err)\n\t}\n\n\tif err := suite.WaitForResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Volume\", \"v1beta2\", \"iscsi\", \"{.status.state}\", \"attached\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for LongHorn Engine to be Ready: %v\", err)\n\t}\n\n\tif err := suite.WaitForResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Engine\", \"v1beta2\", \"iscsi-e-0\", \"{.status.currentState}\", \"running\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for LongHorn Engine to be Ready: %v\", err)\n\t}\n\n\tunstructured, err := suite.GetUnstructuredResource(ctx, \"longhorn-system\", \"longhorn.io\", \"Engine\", \"v1beta2\", \"iscsi-e-0\")\n\tif err != nil {\n\t\tsuite.T().Fatalf(\"failed to get LongHorn Engine resource: %v\", err)\n\t}\n\n\tvar endpointData string\n\n\tif status, ok := unstructured.Object[\"status\"].(map[string]any); ok {\n\t\tendpointData, ok = status[\"endpoint\"].(string)\n\t\tif !ok {\n\t\t\tsuite.T().Fatalf(\"failed to get LongHorn Engine endpoint\")\n\t\t}\n\t}\n\n\ttmpl, err = template.New(\"pod-iscsi-volume\").Parse(string(podWithISCSIVolumeTemplate))\n\tsuite.Require().NoError(err)\n\n\t// endpoint is of the form `iscsi://10.244.0.5:3260/iqn.2019-10.io.longhorn:iscsi/1`\n\t// trim the iscsi:// prefix\n\tendpointData = strings.TrimPrefix(endpointData, \"iscsi://\")\n\t// trim the /1 suffix\n\tendpointData = strings.TrimSuffix(endpointData, \"/1\")\n\n\ttargetPortal, IQN, ok := strings.Cut(endpointData, \"/\")\n\tif !ok {\n\t\tsuite.T().Fatalf(\"failed to parse endpoint data from %s\", endpointData)\n\t}\n\n\tvar podWithISCSIVolume bytes.Buffer\n\n\tif err := tmpl.Execute(&podWithISCSIVolume, struct {\n\t\tNodeName     string\n\t\tTargetPortal string\n\t\tIQN          string\n\t}{\n\t\tNodeName:     nodeInfo.Name,\n\t\tTargetPortal: targetPortal,\n\t\tIQN:          IQN,\n\t}); err != nil {\n\t\tsuite.T().Fatalf(\"failed to render pod with ISCSI volume manifest: %v\", err)\n\t}\n\n\tpodWithISCSIVolumeUnstructured := suite.ParseManifests(podWithISCSIVolume.Bytes())\n\n\tdefer func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, podWithISCSIVolumeUnstructured)\n\t}()\n\n\tsuite.ApplyManifests(ctx, podWithISCSIVolumeUnstructured)\n\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(ctx, 3*time.Minute, \"default\", \"iscsipd\"))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(LongHornSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/manifests.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.yaml.in/yaml/v4\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/cluster/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n)\n\n// ManifestsSuite verifies Kubernetes manifest sync.\ntype ManifestsSuite struct {\n\tbase.K8sSuite\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *ManifestsSuite) SuiteName() string {\n\treturn \"k8s.ManifestsSuite\"\n}\n\n// SetupTest ...\nfunc (suite *ManifestsSuite) SetupTest() {\n\t// make sure API calls have timeout\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 5*time.Minute)\n\n\tsuite.ClearConnectionRefused(suite.ctx, suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeWorker)...)\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\ntype manifestSyncWriter struct {\n\tt *testing.T\n}\n\nfunc (w manifestSyncWriter) Write(p []byte) (n int, err error) {\n\tw.t.Log(\"  \" + string(p))\n\n\treturn len(p), nil\n}\n\n// TestSync verifies that manifest sync works.\nfunc (suite *ManifestsSuite) TestSync() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"skip without full cluster state\")\n\t}\n\n\tcpNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tnodeCtx := client.WithNode(suite.ctx, cpNode)\n\n\tconfig, err := suite.ReadConfigFromNode(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\t// some tests creates cluster without kube-proxy, skip in this case\n\tif !config.Cluster().Proxy().Enabled() {\n\t\tsuite.T().Skip(\"skip when kube-proxy is disabled\")\n\t}\n\n\tclusterAccess := access.NewAdapter(suite.Cluster, provision.WithTalosClient(suite.Client))\n\tdefer clusterAccess.Close() //nolint:errcheck\n\n\t// 1. Patch all controlplane nodes with extra arg for kube-proxy\n\tsuite.T().Log(\"adding extra arg to kube-proxy\")\n\n\textraArgPatch := map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"proxy\": map[string]any{\n\t\t\t\t\"extraArgs\": map[string]any{\n\t\t\t\t\t\"nodeport-addresses\": \"0.0.0.0/0\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\tsuite.PatchMachineConfig(client.WithNode(suite.ctx, node), extraArgPatch)\n\t}\n\n\t// wait for the manifest to be updated\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\trtestutils.AssertResource(client.WithNode(suite.ctx, node), suite.T(), suite.Client.COSI,\n\t\t\t\"10-kube-proxy\",\n\t\t\tfunc(manifest *k8s.Manifest, asrt *assert.Assertions) {\n\t\t\t\tmarshaled, err := yaml.Marshal(manifest.TypedSpec())\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tasrt.Contains(string(marshaled), \"nodeport-addresses=0.0.0.0/0\")\n\t\t\t},\n\t\t)\n\t}\n\n\t// 2. Roll out manifests\n\tsuite.Require().NoError(kubernetes.PerformManifestsSync(\n\t\tsuite.ctx,\n\t\tclusterAccess,\n\t\ttrue,\n\t\tkubernetes.UpgradeOptions{\n\t\t\tLogOutput:        manifestSyncWriter{t: suite.T()},\n\t\t\tReconcileTimeout: 30 * time.Second,\n\t\t},\n\t))\n\n\t// 3. Assert that kube-proxy has the extra arg\n\tpods, err := suite.Clientset.CoreV1().Pods(\"kube-system\").List(suite.ctx, metav1.ListOptions{\n\t\tLabelSelector: \"k8s-app=kube-proxy\",\n\t})\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotEmpty(pods.Items)\n\n\tfor _, pod := range pods.Items {\n\t\tsuite.Require().NotEmpty(pod.Spec.Containers)\n\n\t\tsuite.Assert().Contains(pod.Spec.Containers[0].Command, \"--nodeport-addresses=0.0.0.0/0\")\n\t}\n\n\t// 4. Disable kube-proxy\n\tsuite.T().Log(\"disabling kube-proxy\")\n\n\tdisablePatch := map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"proxy\": map[string]any{\n\t\t\t\t\"disabled\": true,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\tsuite.PatchMachineConfig(client.WithNode(suite.ctx, node), disablePatch)\n\t}\n\n\t// wait for the manifest to be removed\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\trtestutils.AssertNoResource[*k8s.Manifest](client.WithNode(suite.ctx, node), suite.T(), suite.Client.COSI,\n\t\t\t\"10-kube-proxy\",\n\t\t)\n\t}\n\n\t// 5. Roll out manifests\n\tsuite.Require().NoError(kubernetes.PerformManifestsSync(\n\t\tsuite.ctx,\n\t\tclusterAccess,\n\t\ttrue,\n\t\tkubernetes.UpgradeOptions{\n\t\t\tLogOutput: manifestSyncWriter{t: suite.T()},\n\t\t},\n\t))\n\n\t// 6. Assert that kube-proxy is removed\n\tsuite.Require().NoError(suite.EnsureResourceIsDeleted(suite.ctx, 10*time.Second, appsv1.SchemeGroupVersion.WithResource(\"daemonsets\"), \"kube-system\", \"kube-proxy\"))\n\n\t// 7. Re-enable kube-proxy\n\tsuite.T().Log(\"enabling kube-proxy\")\n\n\tenablePatch := map[string]any{\n\t\t\"cluster\": map[string]any{\n\t\t\t\"proxy\": map[string]any{\n\t\t\t\t\"disabled\": map[string]any{\n\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t},\n\t\t\t\t\"extraArgs\": map[string]any{\n\t\t\t\t\t\"$patch\": \"delete\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, node := range suite.DiscoverNodeInternalIPsByType(suite.ctx, machine.TypeControlPlane) {\n\t\tsuite.PatchMachineConfig(client.WithNode(suite.ctx, node), enablePatch)\n\t}\n\n\t// 8. Assert that kube-proxy is back\n\tsuite.Require().NoError(\n\t\tsuite.WaitForResourceToBeAvailable(suite.ctx, 30*time.Second, \"kube-system\", appsv1.GroupName, \"DaemonSet\", appsv1.SchemeGroupVersion.Version, \"kube-proxy\"),\n\t)\n\n\tsuite.AssertClusterHealthy(suite.ctx)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(ManifestsSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/oom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// OomSuite verifies that userspace OOM handler will kill excessive replicas of a heavy memory consumer deployment.\ntype OomSuite struct {\n\tbase.K8sSuite\n}\n\n//go:embed testdata/oom.yaml\nvar oomPodSpec []byte\n\n// SuiteName returns the name of the suite.\nfunc (suite *OomSuite) SuiteName() string {\n\treturn \"k8s.OomSuite\"\n}\n\n// TestOom verifies that system remains stable after handling an OOM event.\nfunc (suite *OomSuite) TestOom() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif suite.Race {\n\t\tsuite.T().Skip(\"skipping as OOM tests are incompatible with race detector\")\n\t}\n\n\tif suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping OOM test since provisioner is not qemu\")\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\n\tsuite.T().Cleanup(cancel)\n\n\toomPodManifest := suite.ParseManifests(oomPodSpec)\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), 2*time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, oomPodManifest)\n\n\t\tticker := time.NewTicker(time.Second)\n\t\tdone := cleanUpCtx.Done()\n\n\t\t// Wait for all stress-mem pods to complete terminating\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tpods, err := suite.Clientset.CoreV1().Pods(\"default\").List(ctx, metav1.ListOptions{\n\t\t\t\t\tLabelSelector: \"app=stress-mem\",\n\t\t\t\t})\n\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tif len(pods.Items) == 0 {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\tcase <-done:\n\t\t\t\tsuite.Require().Fail(\"Timed out waiting for cleanup\")\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\tsuite.ApplyManifests(ctx, oomPodManifest)\n\n\tsuite.Require().NoError(suite.WaitForDeploymentAvailable(ctx, time.Minute, \"default\", \"stress-mem\", 2))\n\n\t// Figure out number of replicas, this is ballpark estimation of 15 replicas per 2GB of memory (per worker node)\n\tnumWorkers := len(suite.DiscoverNodeInternalIPsByType(ctx, machine.TypeWorker))\n\tsuite.Require().Greaterf(numWorkers, 0, \"at least one worker node is required for the test\")\n\n\tmemInfo, err := suite.Client.Memory(client.WithNode(ctx, suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)))\n\tsuite.Require().NoError(err)\n\n\tmemoryBytes := memInfo.GetMessages()[0].GetMeminfo().GetMemtotal() * 1024\n\tnumReplicas := int((memoryBytes/1024/1024+2048-1)/2048) * numWorkers * 25\n\n\tsuite.T().Logf(\"detected memory: %s, workers %d => scaling to %d replicas\",\n\t\thumanize.IBytes(memoryBytes), numWorkers, numReplicas)\n\n\t// Scale to discovered number of replicas\n\tsuite.PatchK8sObject(ctx, \"default\", \"apps\", \"Deployment\", \"v1\", \"stress-mem\", patchToReplicas(suite.T(), numReplicas))\n\n\t// Expect at least one OOM kill of stress-ng within 15 seconds\n\tsuite.Assert().True(suite.waitForOOMKilled(ctx, 15*time.Second, 2*time.Minute, \"stress-ng\", 1))\n\n\t// Scale to 1, wait for deployment to scale down, proving system is operational\n\tsuite.PatchK8sObject(ctx, \"default\", \"apps\", \"Deployment\", \"v1\", \"stress-mem\", patchToReplicas(suite.T(), 1))\n\tsuite.Require().NoError(suite.WaitForDeploymentAvailable(ctx, time.Minute, \"default\", \"stress-mem\", 1))\n\n\t// Monitor OOM kills for 15 seconds and make sure no kills other than stress-ng happen\n\t// Allow 0 as well: ideally that'd be the case, but fail on anything not containing stress-ng\n\tsuite.Assert().True(suite.waitForOOMKilled(ctx, 15*time.Second, 2*time.Minute, \"stress-ng\", 0))\n\n\tsuite.APISuite.AssertClusterHealthy(ctx)\n}\n\nfunc patchToReplicas(t *testing.T, replicas int) []byte {\n\tspec := map[string]any{\n\t\t\"spec\": map[string]any{\n\t\t\t\"replicas\": replicas,\n\t\t},\n\t}\n\n\tpatch, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\treturn patch\n}\n\n// Waits for a period of time and return returns whether or not OOM events containing a specified process have been observed.\n//\n//nolint:gocyclo\nfunc (suite *OomSuite) waitForOOMKilled(ctx context.Context, timeToObserve, timeout time.Duration, substr string, n int) bool {\n\tstartTime := time.Now()\n\n\twatchCh := make(chan state.Event)\n\tworkerNodes := suite.DiscoverNodeInternalIPsByType(ctx, machine.TypeWorker)\n\n\t// start watching OOM events on all worker nodes\n\tfor _, workerNode := range workerNodes {\n\t\tsuite.Assert().NoError(suite.Client.COSI.WatchKind(\n\t\t\tclient.WithNode(ctx, workerNode),\n\t\t\truntime.NewOOMActionSpec(runtime.NamespaceName, \"\").Metadata(),\n\t\t\twatchCh,\n\t\t))\n\t}\n\n\ttimeoutCh := time.After(timeout)\n\ttimeToObserveCh := time.After(timeToObserve)\n\tnumOOMObserved := 0\n\n\tfor {\n\t\tselect {\n\t\tcase <-timeoutCh:\n\t\t\tsuite.T().Logf(\"observed %d OOM events containing process substring %q\", numOOMObserved, substr)\n\n\t\t\treturn numOOMObserved >= n\n\t\tcase <-timeToObserveCh:\n\t\t\tif numOOMObserved >= n {\n\t\t\t\t// if we already observed some OOM events, consider it a success\n\t\t\t\tsuite.T().Logf(\"observed %d OOM events containing process substring %q\", numOOMObserved, substr)\n\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase ev := <-watchCh:\n\t\t\tif ev.Type != state.Created || ev.Resource.Metadata().Created().Before(startTime) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tres := ev.Resource.(*runtime.OOMAction).TypedSpec()\n\n\t\t\tbailOut := false\n\n\t\t\tfor _, proc := range res.Processes {\n\t\t\t\tif strings.Contains(proc, substr) {\n\t\t\t\t\tnumOOMObserved++\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Sometimes OOM catches containers in restart phase (while the\n\t\t\t\t// cgroup has previously accumulated OOM score).\n\t\t\t\t// Consider an OOM event wrong if something other than that is found.\n\t\t\t\tif !strings.Contains(proc, \"runc init\") && !strings.Contains(proc, \"/pause\") && proc != \"\" {\n\t\t\t\t\tbailOut = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif bailOut {\n\t\t\t\tsuite.T().Logf(\"observed an OOM event not containing process substring %q: %q (%d containing)\", substr, res.Processes, numOOMObserved)\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(OomSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/openebs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"path/filepath\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n//go:embed testdata/openebs-values.yaml\nvar openEBSValues []byte\n\n//go:embed testdata/openebs-diskpool.yaml\nvar openEBSDiskPoolTemplate string\n\n// OpenEBSSuite tests deploying OpenEBS.\ntype OpenEBSSuite struct {\n\tbase.K8sSuite\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *OpenEBSSuite) SuiteName() string {\n\treturn \"k8s.OpenEBSSuite\"\n}\n\n// TestDeploy tests deploying OpenEBS and running a simple test.\nfunc (suite *OpenEBSSuite) TestDeploy() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif suite.CSITestName != \"openebs\" {\n\t\tsuite.T().Skip(\"skipping openebs test as it is not enabled\")\n\t}\n\n\ttimeout, err := time.ParseDuration(suite.CSITestTimeout)\n\tif err != nil {\n\t\tsuite.T().Fatalf(\"failed to parse timeout: %v\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tsuite.T().Cleanup(cancel)\n\n\tif err := suite.HelmInstall(\n\t\tctx,\n\t\t\"openebs\",\n\t\t\"https://openebs.github.io/openebs\",\n\t\tOpenEBSChartVersion,\n\t\t\"openebs\",\n\t\t\"openebs\",\n\t\topenEBSValues,\n\t); err != nil {\n\t\tsuite.T().Fatalf(\"failed to install OpenEBS chart: %v\", err)\n\t}\n\n\tnodes := suite.DiscoverNodeInternalIPsByType(ctx, machine.TypeWorker)\n\n\tsuite.Require().Equal(3, len(nodes), \"expected 3 worker nodes\")\n\n\tdisks := xslices.Map(nodes, func(node string) string {\n\t\treturn suite.UserDisks(ctx, node)[0]\n\t})\n\n\tsuite.Require().Equal(3, len(disks), \"expected 3 disks\")\n\n\tfor i, disk := range disks {\n\t\tnode := nodes[i]\n\n\t\tk8sNode, err := suite.GetK8sNodeByInternalIP(ctx, node)\n\t\tsuite.Require().NoError(err)\n\n\t\tdiskResource, err := safe.ReaderGetByID[*block.Disk](client.WithNode(ctx, node), suite.Client.COSI, filepath.Base(disk))\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().Greater(len(diskResource.TypedSpec().Symlinks), 1, \"disk symlinks should not be empty\")\n\n\t\tdiskSymlink := diskResource.TypedSpec().Symlinks[1]\n\n\t\ttmpl, err := template.New(node).Parse(openEBSDiskPoolTemplate)\n\t\tsuite.Require().NoError(err)\n\n\t\tvar result bytes.Buffer\n\n\t\tsuite.Require().NoError(tmpl.Execute(&result, struct {\n\t\t\tNode string\n\t\t\tDisk string\n\t\t}{\n\t\t\tNode: k8sNode.Name,\n\t\t\tDisk: diskSymlink,\n\t\t}))\n\n\t\tdiskPoolUnstructured := suite.ParseManifests(result.Bytes())\n\n\t\tsuite.ApplyManifests(ctx, diskPoolUnstructured)\n\t}\n\n\tsuite.Require().NoError(suite.RunFIOTest(ctx, \"openebs-single-replica\", \"10G\"))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(OpenEBSSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/rook.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n//go:embed testdata/rook-ceph-cluster-values.yaml\nvar rookCephClusterValues []byte\n\n// RookSuite tests deploying Rook.\ntype RookSuite struct {\n\tbase.K8sSuite\n}\n\n// SuiteName returns the name of the suite.\nfunc (suite *RookSuite) SuiteName() string {\n\treturn \"k8s.RookSuite\"\n}\n\n// TestDeploy tests deploying Rook and running a simple test.\nfunc (suite *RookSuite) TestDeploy() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif suite.CSITestName != \"rook-ceph\" {\n\t\tsuite.T().Skip(\"skipping rook-ceph test as it is not enabled\")\n\t}\n\n\ttimeout, err := time.ParseDuration(suite.CSITestTimeout)\n\tif err != nil {\n\t\tsuite.T().Fatalf(\"failed to parse timeout: %v\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tsuite.T().Cleanup(cancel)\n\n\tif err := suite.HelmInstall(\n\t\tctx,\n\t\t\"rook-ceph\",\n\t\t\"https://charts.rook.io/release\",\n\t\tRookCephHelmChartVersion,\n\t\t\"rook-ceph\",\n\t\t\"rook-ceph\",\n\t\tnil,\n\t); err != nil {\n\t\tsuite.T().Fatalf(\"failed to install Rook chart: %v\", err)\n\t}\n\n\tif err := suite.HelmInstall(\n\t\tctx,\n\t\t\"rook-ceph\",\n\t\t\"https://charts.rook.io/release\",\n\t\tRookCephHelmChartVersion,\n\t\t\"rook-ceph-cluster\",\n\t\t\"rook-ceph-cluster\",\n\t\trookCephClusterValues,\n\t); err != nil {\n\t\tsuite.T().Fatalf(\"failed to install Rook chart: %v\", err)\n\t}\n\n\tif err := suite.WaitForResource(ctx, \"rook-ceph\", \"ceph.rook.io\", \"CephCluster\", \"v1\", \"rook-ceph\", \"{.status.phase}\", \"Ready\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for CephCluster to be Ready: %v\", err)\n\t}\n\n\tif err := suite.WaitForResource(ctx, \"rook-ceph\", \"ceph.rook.io\", \"CephCluster\", \"v1\", \"rook-ceph\", \"{.status.state}\", \"Created\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for CephCluster to be Created: %v\", err)\n\t}\n\n\tif err := suite.WaitForResource(ctx, \"rook-ceph\", \"ceph.rook.io\", \"CephCluster\", \"v1\", \"rook-ceph\", \"{.status.ceph.health}\", \"HEALTH_OK\"); err != nil {\n\t\tsuite.T().Fatalf(\"failed to wait for CephCluster to be HEALTH_OK: %v\", err)\n\t}\n\n\tsuite.Require().NoError(suite.RunFIOTest(ctx, \"ceph-block\", \"10G\"))\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(RookSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/testdata/apparmor.yaml",
    "content": "\napiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: nginx-apparmor\n  name: nginx-apparmor\n  namespace: default\nspec:\n  containers:\n  - image: nginx\n    name: nginx-apparmor\n    resources: {}\n  dnsPolicy: ClusterFirst\n  securityContext:\n    appArmorProfile:\n      type: RuntimeDefault\n  restartPolicy: Always\n"
  },
  {
    "path": "internal/integration/k8s/testdata/local-path-storage.yaml",
    "content": "apiVersion: v1\nkind: Namespace\nmetadata:\n  labels:\n    pod-security.kubernetes.io/enforce: privileged\n  name: local-path-storage\n---\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  annotations:\n    storageclass.kubernetes.io/is-default-class: \"true\"\n  name: local-path\nprovisioner: rancher.io/local-path\nreclaimPolicy: Delete\nvolumeBindingMode: WaitForFirstConsumer\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: local-path-provisioner-service-account\n  namespace: local-path-storage\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: local-path-provisioner-role\n  namespace: local-path-storage\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - pods\n  verbs:\n  - get\n  - list\n  - watch\n  - create\n  - patch\n  - update\n  - delete\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: local-path-provisioner-role\nrules:\n- apiGroups:\n  - \"\"\n  resources:\n  - nodes\n  - persistentvolumeclaims\n  - configmaps\n  - pods\n  - pods/log\n  verbs:\n  - get\n  - list\n  - watch\n- apiGroups:\n  - \"\"\n  resources:\n  - persistentvolumes\n  verbs:\n  - get\n  - list\n  - watch\n  - create\n  - patch\n  - update\n  - delete\n- apiGroups:\n  - \"\"\n  resources:\n  - events\n  verbs:\n  - create\n  - patch\n- apiGroups:\n  - storage.k8s.io\n  resources:\n  - storageclasses\n  verbs:\n  - get\n  - list\n  - watch\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: local-path-provisioner-bind\n  namespace: local-path-storage\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: local-path-provisioner-role\nsubjects:\n- kind: ServiceAccount\n  name: local-path-provisioner-service-account\n  namespace: local-path-storage\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: local-path-provisioner-bind\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: local-path-provisioner-role\nsubjects:\n- kind: ServiceAccount\n  name: local-path-provisioner-service-account\n  namespace: local-path-storage\n---\napiVersion: v1\ndata:\n  config.json: |-\n    {\n            \"nodePathMap\":[\n            {\n                    \"node\":\"DEFAULT_PATH_FOR_NON_LISTED_NODES\",\n                    \"paths\":[\"/var/local-path-provisioner\"]\n            }\n            ]\n    }\n  helperPod.yaml: |-\n    apiVersion: v1\n    kind: Pod\n    metadata:\n      name: helper-pod\n    spec:\n      priorityClassName: system-node-critical\n      tolerations:\n        - key: node.kubernetes.io/disk-pressure\n          operator: Exists\n          effect: NoSchedule\n      containers:\n      - name: helper-pod\n        image: busybox\n        imagePullPolicy: IfNotPresent\n  setup: |-\n    #!/bin/sh\n    set -eu\n    mkdir -m 0777 -p \"$VOL_DIR\"\n  teardown: |-\n    #!/bin/sh\n    set -eu\n    rm -rf \"$VOL_DIR\"\nkind: ConfigMap\nmetadata:\n  name: local-path-config\n  namespace: local-path-storage\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: local-path-provisioner\n  namespace: local-path-storage\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: local-path-provisioner\n  template:\n    metadata:\n      labels:\n        app: local-path-provisioner\n    spec:\n      containers:\n      - command:\n        - local-path-provisioner\n        - --debug\n        - start\n        - --config\n        - /etc/config/config.json\n        env:\n        - name: POD_NAMESPACE\n          valueFrom:\n            fieldRef:\n              fieldPath: metadata.namespace\n        image: rancher/local-path-provisioner:v0.0.26\n        imagePullPolicy: IfNotPresent\n        name: local-path-provisioner\n        volumeMounts:\n        - mountPath: /etc/config/\n          name: config-volume\n      serviceAccountName: local-path-provisioner-service-account\n      volumes:\n      - configMap:\n          name: local-path-config\n        name: config-volume\n"
  },
  {
    "path": "internal/integration/k8s/testdata/longhorn-iscsi-volume.yaml",
    "content": "---\napiVersion: longhorn.io/v1beta2\nkind: Volume\nmetadata:\n  labels:\n    longhornvolume: iscsi\n  name: iscsi\n  namespace: longhorn-system\nspec:\n  frontend: iscsi\n  numberOfReplicas: 1\n  size: \"1073741824\"\n"
  },
  {
    "path": "internal/integration/k8s/testdata/longhorn-v2-disk-patch.yaml",
    "content": "---\nspec:\n  disks:\n    nvme:\n      allowScheduling: true\n      evictionRequested: false\n      path: /dev/nvme0n1\n      storageReserved: 0\n      tags: []\n      diskType: block\n"
  },
  {
    "path": "internal/integration/k8s/testdata/longhorn-v2-engine-values.yaml",
    "content": "defaultSettings:\n  v2DataEngine: true\n"
  },
  {
    "path": "internal/integration/k8s/testdata/longhorn-v2-storageclass.yaml",
    "content": "kind: StorageClass\napiVersion: storage.k8s.io/v1\nmetadata:\n  name: longhorn-v2\nprovisioner: driver.longhorn.io\nallowVolumeExpansion: true\nreclaimPolicy: Delete\nvolumeBindingMode: Immediate\nparameters:\n  numberOfReplicas: \"3\"\n  staleReplicaTimeout: \"2880\"\n  fsType: \"ext4\"\n  dataEngine: \"v2\"\n"
  },
  {
    "path": "internal/integration/k8s/testdata/longhorn-volumeattachment.yaml",
    "content": "---\napiVersion: longhorn.io/v1beta2\nkind: VolumeAttachment\nmetadata:\n  labels:\n    longhornvolume: iscsi\n  name: iscsi\n  namespace: longhorn-system\nspec:\n  attachmentTickets:\n    longhorn-ui:\n      generation: 0\n      id: longhorn-ui\n      nodeID: {{ .NodeID }}\n      parameters:\n        disableFrontend: \"false\"\n        lastAttachedBy: \"\"\n      type: longhorn-api\n  volume: iscsi\n"
  },
  {
    "path": "internal/integration/k8s/testdata/oom.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: stress-mem\n  namespace: default\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      app: stress-mem\n  template:\n    metadata:\n      labels:\n        app: stress-mem\n    spec:\n      containers:\n        - name: stress-mem\n          image: ghcr.io/siderolabs/stress-ng:v1\n          command:\n            - /usr/bin/stress-ng\n            - --vm\n            - \"1\"\n            - --vm-bytes\n            - 100M\n            - --vm-hang\n            - \"0\"\n            - --vm-keep\n            - --page-in\n            - --cpu\n            - \"1\"\n            - -l\n            - \"0\"\n"
  },
  {
    "path": "internal/integration/k8s/testdata/openebs-diskpool.yaml",
    "content": "apiVersion: \"openebs.io/v1beta3\"\nkind: DiskPool\nmetadata:\n  name: pool-{{ .Node }}\n  namespace: openebs\nspec:\n  node: {{ .Node }}\n  disks: [\"aio://{{ .Disk }}\"]\n"
  },
  {
    "path": "internal/integration/k8s/testdata/openebs-values.yaml",
    "content": "mayastor:\n  csi:\n    node:\n      initContainers:\n        enabled: false\nengines:\n  local:\n    lvm:\n      enabled: false\n    zfs:\n      enabled: false\n"
  },
  {
    "path": "internal/integration/k8s/testdata/pod-iscsi-volume.yaml",
    "content": "---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: iscsipd\n  namespace: default\nspec:\n  containers:\n  - name: iscsipd-rw\n    image: alpine\n    command: [\"/bin/sh\", \"-c\", \"--\"]\n    args: [\"trap : TERM INT; (sleep 1000) & wait\"]\n    volumeMounts:\n    - mountPath: \"/mnt/iscsipd\"\n      name: iscsipd-rw\n  nodeName: {{ .NodeName }}\n  volumes:\n  - name: iscsipd-rw\n    iscsi:\n      targetPortal: {{ .TargetPortal }}\n      iqn: {{ .IQN }}\n      lun: 1\n      fsType: ext4\n      readOnly: false\n"
  },
  {
    "path": "internal/integration/k8s/testdata/rook-ceph-cluster-values.yaml",
    "content": "operatorNamespace: rook-ceph\ncephFileSystems: []\ncephObjectStores: []\ncephClusterSpec:\n  crashCollector:\n    disable: true\n  logCollector:\n    enabled: false\n  dashboard:\n    enabled: false\n  resources:\n    osd:\n      limits:\n        memory: \"2Gi\"\n      requests:\n        cpu: \"500m\"\n        memory: \"1Gi\"\n  storage:\n    useAllNodes: true\n    useAllDevices: true\n    config:\n      encryptedDevice: \"true\"\n"
  },
  {
    "path": "internal/integration/k8s/testdata/usernamespace.yaml",
    "content": "apiVersion: v1\nkind: Pod\nmetadata:\n  name: userns\n  namespace: default\nspec:\n  hostUsers: false\n  nodeName: $NODE$\n  containers:\n  - name: userns\n    command: [\"/bin/sh\", \"-c\", \"--\"]\n    args: [\"trap : TERM INT; (sleep 1000) & wait\"]\n    image: alpine\n"
  },
  {
    "path": "internal/integration/k8s/tink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/api/resource\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/util/intstr\"\n\tpodsecurity \"k8s.io/pod-security-admission/api\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// TinkSuite verifies Talos-in-Kubernetes.\ntype TinkSuite struct {\n\tbase.K8sSuite\n}\n\n// SuiteName ...\nfunc (suite *TinkSuite) SuiteName() string {\n\treturn \"k8s.TinkSuite\"\n}\n\n//go:embed testdata/local-path-storage.yaml\nvar localPathStorageYAML []byte\n\nconst (\n\ttinkK8sPort   = \"k8s-api\"\n\ttinkTalosPort = \"talos-api\"\n)\n\n// TestDeploy verifies that tink can be deployed with a single control-plane node.\nfunc (suite *TinkSuite) TestDeploy() {\n\tif testing.Short() {\n\t\tsuite.T().Skip(\"skipping in short mode\")\n\t}\n\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)\n\tsuite.T().Cleanup(cancel)\n\n\tsuite.AssertClusterHealthy(ctx)\n\n\tlocalPathStorage := suite.ParseManifests(localPathStorageYAML)\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, localPathStorage)\n\t})\n\n\tsuite.ApplyManifests(ctx, localPathStorage)\n\n\tconst (\n\t\tnamespace = \"talos-in-talos\"\n\t\tservice   = \"talos\"\n\t\tss        = \"talos-cp\"\n\t)\n\n\ttalosImage := fmt.Sprintf(\"%s:%s\", suite.TalosImage, version.Tag)\n\n\tsuite.T().Logf(\"deploying Talos-in-Kubernetes from image %s\", talosImage)\n\n\ttinkManifests := suite.getTinkManifests(namespace, service, ss, talosImage)\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, tinkManifests)\n\t})\n\n\tsuite.ApplyManifests(ctx, tinkManifests)\n\n\t// wait for the control-plane pod to be running\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(ctx, 2*time.Minute, namespace, ss+\"-0\"))\n\n\t// read back Service to figure out the ports\n\tsvc, err := suite.Clientset.CoreV1().Services(namespace).Get(ctx, service, metav1.GetOptions{})\n\tsuite.Require().NoError(err)\n\n\tvar k8sPort, talosPort int\n\n\tfor _, portSpec := range svc.Spec.Ports {\n\t\tswitch portSpec.Name {\n\t\tcase tinkK8sPort:\n\t\t\tk8sPort = int(portSpec.NodePort)\n\t\tcase tinkTalosPort:\n\t\t\ttalosPort = int(portSpec.NodePort)\n\t\t}\n\t}\n\n\tsuite.Require().NotZero(k8sPort)\n\tsuite.Require().NotZero(talosPort)\n\n\t// find pod IP\n\tpod, err := suite.Clientset.CoreV1().Pods(namespace).Get(ctx, ss+\"-0\", metav1.GetOptions{})\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NotEmpty(pod.Status.PodIP)\n\n\tpodIP := netip.MustParseAddr(pod.Status.PodIP)\n\n\t// grab any random lbNode IP\n\tlbNode := suite.RandomDiscoveredNodeInternalIP()\n\n\ttalosEndpoint := net.JoinHostPort(lbNode, strconv.Itoa(talosPort))\n\n\tin, err := generate.NewInput(namespace,\n\t\tfmt.Sprintf(\"https://%s\", net.JoinHostPort(lbNode, strconv.Itoa(k8sPort))),\n\t\tconstants.DefaultKubernetesVersion,\n\t\tgenerate.WithAdditionalSubjectAltNames([]string{lbNode}),\n\t\tgenerate.WithHostDNSForwardKubeDNSToHost(true),\n\t)\n\tsuite.Require().NoError(err)\n\n\t// override pod/service subnets, as Talos-in-Talos would use it for \"host\" addresses\n\tin.PodNet = []string{\"192.168.0.0/20\"}\n\tin.ServiceNet = []string{\"192.168.128.0/20\"}\n\n\tcpCfg, err := in.Config(machine.TypeControlPlane)\n\tsuite.Require().NoError(err)\n\n\tcpCfgBytes, err := cpCfg.Bytes()\n\tsuite.Require().NoError(err)\n\n\treadyErr := suite.waitForEndpointReady(talosEndpoint)\n\tif readyErr != nil {\n\t\tsuite.LogPodLogs(ctx, namespace, ss+\"-0\")\n\t}\n\n\tsuite.Require().NoError(readyErr)\n\n\tinsecureClient, err := client.New(ctx,\n\t\tclient.WithEndpoints(talosEndpoint),\n\t\tclient.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Log(\"applying initial configuration\")\n\n\t_, err = insecureClient.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{\n\t\tData: cpCfgBytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_AUTO,\n\t})\n\tsuite.Require().NoError(err)\n\n\t// bootstrap\n\ttalosconfig, err := in.Talosconfig()\n\tsuite.Require().NoError(err)\n\n\ttalosconfig.Contexts[talosconfig.Context].Endpoints = []string{talosEndpoint}\n\ttalosconfig.Contexts[talosconfig.Context].Nodes = []string{podIP.String()}\n\n\tsuite.T().Logf(\"talosconfig = %s\", string(ensure.Value(talosconfig.Bytes())))\n\n\treadyErr = suite.waitForEndpointReady(talosEndpoint)\n\tif readyErr != nil {\n\t\tsuite.LogPodLogs(ctx, namespace, ss+\"-0\")\n\t}\n\n\tsuite.Require().NoError(readyErr)\n\n\ttalosClient, err := client.New(ctx,\n\t\tclient.WithConfigContext(talosconfig.Contexts[talosconfig.Context]),\n\t)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Log(\"bootstrapping\")\n\n\tif !suite.Assert().EventuallyWithT(\n\t\tfunc(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\tasrt.NoError(talosClient.Bootstrap(ctx, &machineapi.BootstrapRequest{}))\n\t\t},\n\t\ttime.Minute,\n\t\t100*time.Millisecond,\n\t) {\n\t\tsuite.LogPodLogs(ctx, namespace, ss+\"-0\")\n\t\tsuite.T().Fatalf(\"failed to bootstrap Talos-in-Kubernetes\")\n\t}\n\n\tclusterAccess := &tinkClusterAccess{\n\t\tKubernetesClient: cluster.KubernetesClient{\n\t\t\tClientProvider: &cluster.ConfigClientProvider{\n\t\t\t\tTalosConfig: talosconfig,\n\t\t\t},\n\t\t},\n\n\t\tnodeIP: podIP,\n\t}\n\n\tsuite.Require().NoError(\n\t\tcheck.Wait(\n\t\t\tctx,\n\t\t\tclusterAccess,\n\t\t\tcheck.DefaultClusterChecks(),\n\t\t\tcheck.StderrReporter(),\n\t\t),\n\t)\n}\n\ntype tinkClusterAccess struct {\n\tcluster.KubernetesClient\n\n\tnodeIP netip.Addr\n}\n\nfunc (access *tinkClusterAccess) Nodes() []cluster.NodeInfo {\n\treturn []cluster.NodeInfo{\n\t\t{\n\t\t\tInternalIP: access.nodeIP,\n\t\t\tIPs:        []netip.Addr{access.nodeIP},\n\t\t},\n\t}\n}\n\nfunc (access *tinkClusterAccess) NodesByType(typ machine.Type) []cluster.NodeInfo {\n\tswitch typ {\n\tcase machine.TypeControlPlane:\n\t\treturn []cluster.NodeInfo{\n\t\t\t{\n\t\t\t\tInternalIP: access.nodeIP,\n\t\t\t\tIPs:        []netip.Addr{access.nodeIP},\n\t\t\t},\n\t\t}\n\tcase machine.TypeWorker, machine.TypeInit:\n\t\treturn nil\n\tcase machine.TypeUnknown:\n\t\tfallthrough\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected machine type: %s\", typ))\n\t}\n}\n\nfunc (suite *TinkSuite) waitForEndpointReady(endpoint string) error {\n\treturn retry.Constant(30*time.Second, retry.WithUnits(10*time.Millisecond)).Retry(func() error {\n\t\tc, err := (&tls.Dialer{\n\t\t\tConfig: &tls.Config{\n\t\t\t\tInsecureSkipVerify: true,\n\t\t\t},\n\t\t}).DialContext(suite.T().Context(), \"tcp\", endpoint)\n\t\tif c != nil {\n\t\t\tc.Close() //nolint:errcheck\n\t\t}\n\n\t\treturn retry.ExpectedError(err)\n\t})\n}\n\nfunc (suite *TinkSuite) getTinkManifests(namespace, serviceName, ssName, talosImage string) []unstructured.Unstructured {\n\tlabels := map[string]string{\n\t\t\"app\": \"talos-cp\",\n\t}\n\n\ttinkManifests := []runtime.Object{ //nolint:prealloc // this is a test\n\t\t&corev1.Namespace{\n\t\t\tTypeMeta: metav1.TypeMeta{\n\t\t\t\tKind:       \"Namespace\",\n\t\t\t\tAPIVersion: \"v1\",\n\t\t\t},\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName: namespace,\n\t\t\t\tLabels: map[string]string{\n\t\t\t\t\tpodsecurity.EnforceLevelLabel: string(podsecurity.LevelPrivileged),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t&corev1.Service{\n\t\t\tTypeMeta: metav1.TypeMeta{\n\t\t\t\tKind:       \"Service\",\n\t\t\t\tAPIVersion: \"v1\",\n\t\t\t},\n\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\tName:      serviceName,\n\t\t\t\tNamespace: namespace,\n\t\t\t},\n\t\t\tSpec: corev1.ServiceSpec{\n\t\t\t\tType:     corev1.ServiceTypeNodePort,\n\t\t\t\tSelector: labels,\n\t\t\t\tPorts: []corev1.ServicePort{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:       tinkK8sPort,\n\t\t\t\t\t\tProtocol:   corev1.ProtocolTCP,\n\t\t\t\t\t\tPort:       constants.DefaultControlPlanePort,\n\t\t\t\t\t\tTargetPort: intstr.FromString(tinkK8sPort),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:       tinkTalosPort,\n\t\t\t\t\t\tProtocol:   corev1.ProtocolTCP,\n\t\t\t\t\t\tPort:       constants.ApidPort,\n\t\t\t\t\t\tTargetPort: intstr.FromString(tinkTalosPort),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tstatefulSet := &appsv1.StatefulSet{\n\t\tTypeMeta: metav1.TypeMeta{\n\t\t\tKind:       \"StatefulSet\",\n\t\t\tAPIVersion: \"apps/v1\",\n\t\t},\n\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\tName:      ssName,\n\t\t\tNamespace: namespace,\n\t\t},\n\t\tSpec: appsv1.StatefulSetSpec{\n\t\t\tServiceName: serviceName,\n\t\t\tReplicas:    new(int32(1)),\n\t\t\tSelector: &metav1.LabelSelector{\n\t\t\t\tMatchLabels: labels,\n\t\t\t},\n\t\t\tTemplate: corev1.PodTemplateSpec{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tLabels: labels,\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PodSpec{\n\t\t\t\t\tContainers: []corev1.Container{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:            \"talos\",\n\t\t\t\t\t\t\tImage:           talosImage,\n\t\t\t\t\t\t\tImagePullPolicy: corev1.PullAlways,\n\t\t\t\t\t\t\tSecurityContext: &corev1.SecurityContext{\n\t\t\t\t\t\t\t\tPrivileged:             new(true),\n\t\t\t\t\t\t\t\tReadOnlyRootFilesystem: new(true),\n\t\t\t\t\t\t\t\tSeccompProfile: &corev1.SeccompProfile{\n\t\t\t\t\t\t\t\t\tType: corev1.SeccompProfileTypeUnconfined,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tEnv: []corev1.EnvVar{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tName:  \"PLATFORM\",\n\t\t\t\t\t\t\t\t\tValue: \"container\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tResources: corev1.ResourceRequirements{\n\t\t\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\t\t\tcorev1.ResourceMemory: resource.MustParse(\"1Gi\"),\n\t\t\t\t\t\t\t\t\tcorev1.ResourceCPU:    resource.MustParse(\"750m\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tPorts: []corev1.ContainerPort{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tContainerPort: constants.ApidPort,\n\t\t\t\t\t\t\t\t\tName:          tinkTalosPort,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tContainerPort: constants.DefaultControlPlanePort,\n\t\t\t\t\t\t\t\t\tName:          tinkK8sPort,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, ephemeralMount := range []string{\"run\", \"system\", \"tmp\"} {\n\t\tstatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts = append(\n\t\t\tstatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts,\n\t\t\tcorev1.VolumeMount{\n\t\t\t\tMountPath: \"/\" + ephemeralMount,\n\t\t\t\tName:      ephemeralMount,\n\t\t\t},\n\t\t)\n\n\t\tstatefulSet.Spec.Template.Spec.Volumes = append(\n\t\t\tstatefulSet.Spec.Template.Spec.Volumes,\n\t\t\tcorev1.Volume{\n\t\t\t\tName: ephemeralMount,\n\t\t\t\tVolumeSource: corev1.VolumeSource{\n\t\t\t\t\tEmptyDir: &corev1.EmptyDirVolumeSource{},\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\ttype overlayMountSpec struct {\n\t\tMountPoint string\n\t\tSize       string\n\t}\n\n\tfor _, overlayMount := range append(\n\t\t[]overlayMountSpec{\n\t\t\t{\n\t\t\t\tMountPoint: constants.StateMountPoint,\n\t\t\t\tSize:       \"100Mi\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tMountPoint: constants.EphemeralMountPoint,\n\t\t\t\tSize:       \"6Gi\",\n\t\t\t},\n\t\t},\n\t\txslices.Map(\n\t\t\txslices.Filter(constants.Overlays, func(overlay constants.SELinuxLabeledPath) bool { return overlay.Path != \"/opt\" }), // /opt/cni/bin contains CNI binaries\n\t\t\tfunc(mnt constants.SELinuxLabeledPath) overlayMountSpec {\n\t\t\t\treturn overlayMountSpec{\n\t\t\t\t\tMountPoint: mnt.Path,\n\t\t\t\t\tSize:       \"100Mi\",\n\t\t\t\t}\n\t\t\t},\n\t\t)...,\n\t) {\n\t\tname := strings.ReplaceAll(strings.TrimLeft(overlayMount.MountPoint, \"/\"), \"/\", \"-\")\n\n\t\tstatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts = append(\n\t\t\tstatefulSet.Spec.Template.Spec.Containers[0].VolumeMounts,\n\t\t\tcorev1.VolumeMount{\n\t\t\t\tMountPath: overlayMount.MountPoint,\n\t\t\t\tName:      name,\n\t\t\t},\n\t\t)\n\n\t\tstatefulSet.Spec.VolumeClaimTemplates = append(\n\t\t\tstatefulSet.Spec.VolumeClaimTemplates,\n\t\t\tcorev1.PersistentVolumeClaim{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName: name,\n\t\t\t\t},\n\t\t\t\tSpec: corev1.PersistentVolumeClaimSpec{\n\t\t\t\t\tAccessModes: []corev1.PersistentVolumeAccessMode{\n\t\t\t\t\t\tcorev1.ReadWriteOnce,\n\t\t\t\t\t},\n\t\t\t\t\tResources: corev1.VolumeResourceRequirements{\n\t\t\t\t\t\tRequests: corev1.ResourceList{\n\t\t\t\t\t\t\tcorev1.ResourceStorage: resource.MustParse(overlayMount.Size),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t}\n\n\ttinkManifests = append(tinkManifests, statefulSet)\n\n\treturn xslices.Map(tinkManifests, suite.ToUnstructured)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(TinkSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/usernamespace.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// UserNamespaceSuite verifies that a pod with user namespace works.\ntype UserNamespaceSuite struct {\n\tbase.K8sSuite\n}\n\n//go:embed testdata/usernamespace.yaml\nvar userNamespacePodSpec []byte\n\n// SuiteName returns the name of the suite.\nfunc (suite *UserNamespaceSuite) SuiteName() string {\n\treturn \"k8s.UserNamespaceSuite\"\n}\n\n// TestUserNamespace verifies that a pod with user namespace works.\n//\n//nolint:gocyclo,cyclop\nfunc (suite *UserNamespaceSuite) TestUserNamespace() {\n\tif suite.Cluster == nil {\n\t\tsuite.T().Skip(\"without full cluster state reaching out to the node IP is not reliable\")\n\t}\n\n\tif suite.Cluster.Provisioner() != base.ProvisionerQEMU {\n\t\tsuite.T().Skip(\"skipping usernamespace test since provisioner is not qemu\")\n\t}\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\n\tsuite.T().Cleanup(cancel)\n\n\tnode := suite.RandomDiscoveredNodeInternalIP(machine.TypeWorker)\n\n\tnodeCtx := client.WithNodes(ctx, node)\n\n\treader, err := suite.Client.Read(nodeCtx, \"/proc/sys/user/max_user_namespaces\")\n\tsuite.Require().NoError(err)\n\n\tvar maxUserNamespaces bytes.Buffer\n\n\t_, err = maxUserNamespaces.ReadFrom(reader)\n\tsuite.Require().NoError(err)\n\n\tif strings.TrimSpace(maxUserNamespaces.String()) == \"0\" {\n\t\tsuite.T().Skip(\"skipping test since user namespace is disabled\")\n\t}\n\n\tcontrolPlaneNode := suite.RandomDiscoveredNodeInternalIP(machine.TypeControlPlane)\n\n\tcontrolPlaneNodeCtx := client.WithNode(ctx, controlPlaneNode)\n\n\tcontrolPlaneNodeConfig, err := suite.ReadConfigFromNode(controlPlaneNodeCtx)\n\tsuite.Require().NoError(err)\n\n\tif controlPlaneNodeConfig.Cluster().APIServer().ExtraArgs() == nil {\n\t\tsuite.T().Skip(\"skipping test since no api server extra args found\")\n\t} else {\n\t\tif featureGates, ok := controlPlaneNodeConfig.Cluster().APIServer().ExtraArgs()[\"feature-gates\"]; ok {\n\t\t\thasUserNamespacesSupport := false\n\n\t\t\tfor _, featureGate := range featureGates {\n\t\t\t\tif strings.Contains(featureGate, \"UserNamespacesSupport=true\") {\n\t\t\t\t\thasUserNamespacesSupport = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !hasUserNamespacesSupport {\n\t\t\t\tsuite.T().Skip(\"skipping test since user namespace feature gate is not enabled for kube-apiserver\")\n\t\t\t}\n\t\t}\n\t}\n\n\tworkerNodeConfig, err := suite.ReadConfigFromNode(client.WithNode(ctx, node))\n\tsuite.Require().NoError(err)\n\n\tif workerNodeConfig.Machine().Kubelet().ExtraConfig() == nil {\n\t\tsuite.T().Skip(\"skipping test since no kubelet extra config found\")\n\t} else {\n\t\tif featureGates, ok := workerNodeConfig.Machine().Kubelet().ExtraConfig()[\"featureGates\"]; ok {\n\t\t\tif fg, ok := featureGates.(map[string]string); ok {\n\t\t\t\tif val, ok := fg[\"UserNamespacesSupport\"]; !ok || val != \"true\" {\n\t\t\t\t\tsuite.T().Skip(\"skipping test since user namespace feature gate is not enabled for kubelet\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tk8sNode, err := suite.GetK8sNodeByInternalIP(ctx, node)\n\tsuite.Require().NoError(err)\n\n\tsuite.T().Logf(\"testing k8s user namespace on node %q (%q)\", node, k8sNode.Name)\n\n\t// bind the pod to the node\n\tusernamespacePodManifest := suite.ParseManifests(bytes.ReplaceAll(userNamespacePodSpec, []byte(\"$NODE$\"), []byte(k8sNode.Name)))\n\n\tsuite.T().Cleanup(func() {\n\t\tcleanUpCtx, cleanupCancel := context.WithTimeout(context.Background(), time.Minute)\n\t\tdefer cleanupCancel()\n\n\t\tsuite.DeleteManifests(cleanUpCtx, usernamespacePodManifest)\n\t})\n\n\tsuite.ApplyManifests(ctx, usernamespacePodManifest)\n\n\tsuite.Require().NoError(suite.WaitForPodToBeRunning(ctx, time.Minute, \"default\", \"userns\"))\n\n\tprocessResp, err := suite.Client.Processes(nodeCtx)\n\tsuite.Require().NoError(err)\n\n\tvar sleepProcessPID int\n\n\tfor _, processInfo := range processResp.Messages {\n\t\tfor _, process := range processInfo.Processes {\n\t\t\tif strings.Contains(process.Args, \"sleep 1000\") {\n\t\t\t\tsleepProcessPID = int(process.Pid)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tsuite.Require().NotZero(sleepProcessPID, \"sleep process not found for user namespace test\")\n\n\treader, err = suite.Client.Read(nodeCtx, fmt.Sprintf(\"/proc/%d/status\", sleepProcessPID))\n\tsuite.Require().NoError(err)\n\n\tvar processStatus bytes.Buffer\n\n\t_, err = processStatus.ReadFrom(reader)\n\tsuite.Require().NoError(err)\n\n\tscanner := bufio.NewScanner(&processStatus)\n\n\tvar processUsingUserNamespace bool\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tif strings.HasPrefix(line, \"Uid:\") {\n\t\t\tfields := strings.Fields(line)\n\n\t\t\tif fields[0] != \"0\" && fields[1] != \"0\" && fields[2] != \"0\" && fields[3] != \"0\" {\n\t\t\t\tprocessUsingUserNamespace = true\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tsuite.Require().True(processUsingUserNamespace, \"sleep process should not have root UID in host namespace\\n\", processStatus.String())\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(UserNamespaceSuite))\n}\n"
  },
  {
    "path": "internal/integration/k8s/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_k8s\n\npackage k8s\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// VersionSuite verifies Talos version.\ntype VersionSuite struct {\n\tbase.K8sSuite\n}\n\n// SuiteName ...\nfunc (suite *VersionSuite) SuiteName() string {\n\treturn \"k8s.VersionSuite\"\n}\n\n// TestExpectedVersion verifies that node versions matches expected.\nfunc (suite *VersionSuite) TestExpectedVersion() {\n\t// verify k8s version (api server)\n\tapiServerVersion, err := suite.DiscoveryClient.ServerVersion()\n\tsuite.Require().NoError(err)\n\n\texpectedAPIServerVersion := fmt.Sprintf(\"v%s\", constants.DefaultKubernetesVersion)\n\tsuite.Assert().Equal(expectedAPIServerVersion, apiServerVersion.GitVersion)\n\n\tcheckKernelVersion := suite.Capabilities().RunsTalosKernel\n\n\t// verify each node (kubelet version, Talos version, etc.)\n\tnodes, err := suite.Clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})\n\tsuite.Require().NoError(err)\n\n\texpectedTalosVersion := fmt.Sprintf(\"Talos (%s)\", suite.Version)\n\texpectedContainerRuntimeVersion := fmt.Sprintf(\"containerd://%s\", constants.DefaultContainerdVersion)\n\texpectedKubeletVersion := fmt.Sprintf(\"v%s\", constants.DefaultKubernetesVersion)\n\texpectedKernelVersion := constants.DefaultKernelVersion\n\n\tfor _, node := range nodes.Items {\n\t\tsuite.Assert().Equal(expectedTalosVersion, node.Status.NodeInfo.OSImage)\n\t\tsuite.Assert().Equal(\"linux\", node.Status.NodeInfo.OperatingSystem)\n\t\tsuite.Assert().Equal(expectedContainerRuntimeVersion, node.Status.NodeInfo.ContainerRuntimeVersion)\n\t\tsuite.Assert().Equal(expectedKubeletVersion, node.Status.NodeInfo.KubeletVersion)\n\n\t\tif checkKernelVersion {\n\t\t\tsuite.Assert().Equal(expectedKernelVersion, node.Status.NodeInfo.KernelVersion)\n\t\t}\n\t}\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(VersionSuite))\n}\n"
  },
  {
    "path": "internal/integration/provision/k8s_compatibility.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_provision\n\npackage provision\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/google/go-containerregistry/pkg/v1/remote\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// K8sCompatibilitySuite ...\ntype K8sCompatibilitySuite struct {\n\tBaseSuite\n\n\ttrack int\n\n\tversionsSequence []string\n}\n\n// SuiteName ...\nfunc (suite *K8sCompatibilitySuite) SuiteName() string {\n\treturn fmt.Sprintf(\"provision.UpgradeSuite.KubernetesCompatibility-TR%d\", suite.track)\n}\n\n// SetupSuite ...\nfunc (suite *K8sCompatibilitySuite) SetupSuite() {\n\t// figure out Kubernetes versions to go through, the calculation is based on:\n\t//  * DefaultKubernetesVersion, e.g. 1.29.0\n\t//  * SupportedKubernetesVersions, e.g. 6\n\t//  * available `kubelet` images (tags)\n\t//\n\t// E.g. with example values above, upgrade will go through:\n\t// 1.24 -> 1.25 -> 1.26 -> 1.27 -> 1.28 -> 1.29 (6 versions)\n\t// For each past Kubernetes release, latest patch release will be used,\n\t// for the latest version (DefaultKubernetesVersion), the exact version will be used\n\tkubeletRepository, err := name.NewRepository(constants.KubeletImage)\n\tsuite.Require().NoError(err)\n\n\tmaxVersion, err := semver.Parse(constants.DefaultKubernetesVersion)\n\tsuite.Require().NoError(err)\n\n\tminVersion := semver.Version{\n\t\tMajor: maxVersion.Major,\n\t\tMinor: maxVersion.Minor - constants.SupportedKubernetesVersions + 1,\n\t\tPatch: 0,\n\t}\n\n\t// while Talos is in alpha stage, DefaultKubernetesVersion might be 1 minor behind the latest alpha Kubernetes version,\n\t// so we need to ensure that minVersion fits into compatibility range\n\tminVersionAdjusted := false\n\n\tcurrentTalosVersion, err := compatibility.ParseTalosVersion(version.NewVersion())\n\tsuite.Require().NoError(err)\n\n\tminKubernetesVersion, err := compatibility.ParseKubernetesVersion(minVersion.String())\n\tsuite.Require().NoError(err)\n\n\tif minKubernetesVersion.SupportedWith(currentTalosVersion) != nil {\n\t\t// bump up minVersion to the next minor version\n\t\tminVersion.Minor++\n\t\tminVersionAdjusted = true\n\t}\n\n\ttype versionInfo struct {\n\t\tMajor uint64\n\t\tMinor uint64\n\t}\n\n\tversionsToUse := map[versionInfo]semver.Version{\n\t\t{\n\t\t\tMajor: maxVersion.Major,\n\t\t\tMinor: maxVersion.Minor,\n\t\t}: maxVersion,\n\t}\n\n\ttags, err := remote.List(kubeletRepository)\n\tsuite.Require().NoError(err)\n\n\tfor _, tag := range tags {\n\t\tversion, err := semver.ParseTolerant(tag)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif version.Pre != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif version.LT(minVersion) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif version.GT(maxVersion) {\n\t\t\tcontinue\n\t\t}\n\n\t\tversionKey := versionInfo{\n\t\t\tMajor: version.Major,\n\t\t\tMinor: version.Minor,\n\t\t}\n\n\t\tif curVersion := versionsToUse[versionKey]; version.GT(curVersion) {\n\t\t\tversionsToUse[versionKey] = version\n\t\t}\n\t}\n\n\tk8sVersions := maps.Values(versionsToUse)\n\n\tslices.SortFunc(k8sVersions, func(a, b semver.Version) int {\n\t\treturn a.Compare(b)\n\t})\n\n\tsuite.versionsSequence = xslices.Map(k8sVersions, semver.Version.String)\n\n\tsuite.T().Logf(\"using following upgrade sequence: %v\", suite.versionsSequence)\n\n\tif minVersionAdjusted {\n\t\tsuite.T().Logf(\"min Kubernetes version was adjusted to %s to fit Talos compatibility range\", minVersion.String())\n\t\tsuite.Assert().Len(suite.versionsSequence, constants.SupportedKubernetesVersions-1)\n\t} else {\n\t\tsuite.Assert().Len(suite.versionsSequence, constants.SupportedKubernetesVersions)\n\t}\n\n\tsuite.BaseSuite.SetupSuite()\n}\n\n// TestAllVersions tries to run cluster on all Kubernetes versions.\nfunc (suite *K8sCompatibilitySuite) TestAllVersions() {\n\t// start a cluster using latest Talos, and on earliest supported Kubernetes version\n\tsuite.setupCluster(clusterOptions{\n\t\tClusterName: \"k8s-compat\",\n\n\t\tControlplaneNodes: DefaultSettings.ControlplaneNodes,\n\t\tWorkerNodes:       DefaultSettings.WorkerNodes,\n\n\t\tSourceKernelPath:    helpers.ArtifactPath(constants.KernelAssetWithArch),\n\t\tSourceInitramfsPath: helpers.ArtifactPath(constants.InitramfsAssetWithArch),\n\t\tSourceInstallerImage: fmt.Sprintf(\n\t\t\t\"%s/%s:%s\",\n\t\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\t\timages.DefaultInstallerImageName,\n\t\t\tDefaultSettings.CurrentVersion,\n\t\t),\n\t\tSourceVersion:    DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion: suite.versionsSequence[0],\n\t})\n\n\tsuite.runE2E(suite.versionsSequence[0])\n\n\t// for each next supported Kubernetes version, upgrade k8s and run e2e tests\n\tfor i := 1; i < len(suite.versionsSequence); i++ {\n\t\tsuite.upgradeKubernetes(suite.versionsSequence[i-1], suite.versionsSequence[i], false)\n\n\t\tsuite.waitForClusterHealth()\n\n\t\tsuite.runE2E(suite.versionsSequence[i])\n\t}\n}\n\nfunc init() {\n\tallSuites = append(\n\t\tallSuites,\n\t\t&K8sCompatibilitySuite{track: 2},\n\t)\n}\n"
  },
  {
    "path": "internal/integration/provision/maintenance_basic.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_provision\n\npackage provision\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// MaintenanceBasicSuite ...\ntype MaintenanceBasicSuite struct {\n\tBaseSuite\n\n\ttrack int\n}\n\n// SuiteName ...\nfunc (suite *MaintenanceBasicSuite) SuiteName() string {\n\treturn fmt.Sprintf(\"provision.UpgradeSuite.MaintenanceBasic-TR%d\", suite.track)\n}\n\n// TestAPI tests basic maintenance API operations.\n//\n//nolint:gocyclo\nfunc (suite *MaintenanceBasicSuite) TestAPI() {\n\tconst (\n\t\tmaintenanceControlplanes = 1\n\t\tmaintenanceWorkers       = 1\n\t)\n\n\tsuite.setupCluster(clusterOptions{\n\t\tClusterName: \"maintenance\",\n\n\t\tControlplaneNodes: maintenanceControlplanes,\n\t\tWorkerNodes:       maintenanceWorkers,\n\n\t\tSourceKernelPath:    helpers.ArtifactPath(constants.KernelAssetWithArch),\n\t\tSourceInitramfsPath: helpers.ArtifactPath(constants.InitramfsAssetWithArch),\n\t\tSourceInstallerImage: fmt.Sprintf(\n\t\t\t\"%s/%s:%s\",\n\t\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\t\timages.DefaultInstallerImageName,\n\t\t\tDefaultSettings.CurrentVersion,\n\t\t),\n\t\tSourceVersion:    DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion: constants.DefaultKubernetesVersion,\n\n\t\tWithSkipInjectingConfig: true,\n\t})\n\n\tmaintenanceClients := make([]*client.Client, len(suite.Cluster.Info().Nodes))\n\n\tfor i, machine := range suite.Cluster.Info().Nodes {\n\t\tvar err error\n\n\t\tmaintenanceClients[i], err = client.New(\n\t\t\tsuite.ctx,\n\t\t\tclient.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}),\n\t\t\tclient.WithEndpoints(machine.IPs[0].String()),\n\t\t)\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tdefer func() {\n\t\tfor _, c := range maintenanceClients {\n\t\t\tsuite.Require().NoError(c.Close())\n\t\t}\n\t}()\n\n\tsuite.Run(\"wait for maintenance API\", func() {\n\t\t// we should be able to query version API for every machine\n\t\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\tfor _, maintenanceClient := range maintenanceClients {\n\t\t\t\tversion, err := maintenanceClient.Version(suite.ctx)\n\t\t\t\tif !asrt.NoError(err) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tsuite.Assert().Equal(DefaultSettings.CurrentVersion, version.GetMessages()[0].GetVersion().GetTag())\n\t\t\t}\n\t\t}, time.Minute, time.Second, \"version API should be available\")\n\t})\n\n\tsuite.Run(\"testing basic maintenance APIs\", func() {\n\t\t// it doesn't matter which machine to use, as they are all same in maintenance mode right now\n\t\tmaintenanceClient := maintenanceClients[0]\n\n\t\tlinkStatuses, err := safe.ReaderListAll[*network.LinkStatus](suite.ctx, maintenanceClient.COSI)\n\t\tsuite.Require().NoError(err)\n\t\tsuite.Assert().NotEmpty(linkStatuses)\n\n\t\t// link specs should be not available (sensitive)\n\t\t_, err = safe.ReaderListAll[*network.LinkSpec](suite.ctx, maintenanceClient.COSI)\n\t\tsuite.Require().Error(err)\n\t\tsuite.Require().Equal(codes.PermissionDenied, client.StatusCode(err))\n\n\t\t// reboot should be not authorized in maintenance mode\n\t\terr = maintenanceClient.Reboot(suite.ctx)\n\t\tsuite.Require().Error(err)\n\t\tsuite.Require().Equal(codes.PermissionDenied, client.StatusCode(err))\n\n\t\tlistClient, err := maintenanceClient.ImageClient.List(suite.ctx, &machine.ImageServiceListRequest{\n\t\t\tContainerd: &common.ContainerdInstance{\n\t\t\t\tDriver:    common.ContainerDriver_CONTAINERD,\n\t\t\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t\t\t},\n\t\t})\n\t\tsuite.Require().NoError(err)\n\n\t\tfor {\n\t\t\t_, err := listClient.Recv()\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\t})\n\n\tsuite.Run(\"apply config and have a cluster\", func() {\n\t\tfor i := range maintenanceControlplanes {\n\t\t\tmaintenanceClient := maintenanceClients[i]\n\n\t\t\tconfigData, err := suite.configBundle.ControlPlaneCfg.Bytes()\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\t_, err = maintenanceClient.ApplyConfiguration(suite.ctx, &machine.ApplyConfigurationRequest{\n\t\t\t\tData: configData,\n\t\t\t})\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tfor i := range maintenanceWorkers {\n\t\t\tmaintenanceClient := maintenanceClients[maintenanceControlplanes+i]\n\n\t\t\tconfigData, err := suite.configBundle.WorkerCfg.Bytes()\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\t_, err = maintenanceClient.ApplyConfiguration(suite.ctx, &machine.ApplyConfigurationRequest{\n\t\t\t\tData: configData,\n\t\t\t})\n\t\t\tsuite.Require().NoError(err)\n\t\t}\n\n\t\tsuite.Require().NoError(suite.clusterAccess.Bootstrap(suite.ctx, os.Stdout))\n\n\t\tsuite.waitForClusterHealth()\n\t})\n\n\tsuite.Run(\"reset STATE and EPHEMERAL\", func() {\n\t\t// reset starting from worker nodes\n\t\tfor idx := len(suite.Cluster.Info().Nodes) - 1; idx >= 0; idx-- {\n\t\t\tnode := suite.Cluster.Info().Nodes[idx].IPs[0].String()\n\n\t\t\tsuite.Run(fmt.Sprintf(\"resetting node %s\", node), func() {\n\t\t\t\tclient, err := suite.clusterAccess.Client(node)\n\t\t\t\tsuite.Require().NoError(err)\n\n\t\t\t\tdefer func() {\n\t\t\t\t\tsuite.Require().NoError(client.Close())\n\t\t\t\t}()\n\n\t\t\t\tsuite.Require().NoError(client.ResetGeneric(suite.ctx, &machine.ResetRequest{\n\t\t\t\t\tGraceful: false,\n\t\t\t\t\tReboot:   true,\n\t\t\t\t\tSystemPartitionsToWipe: []*machine.ResetPartitionSpec{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLabel: constants.StatePartitionLabel,\n\t\t\t\t\t\t\tWipe:  true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLabel: constants.EphemeralPartitionLabel,\n\t\t\t\t\t\t\tWipe:  true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}))\n\t\t\t})\n\t\t}\n\t})\n\n\tsuite.Run(\"wait for back to maintenance API\", func() {\n\t\t// we should be able to query version API for every machine\n\t\tsuite.Require().EventuallyWithT(func(collect *assert.CollectT) {\n\t\t\tasrt := assert.New(collect)\n\n\t\t\tfor _, maintenanceClient := range maintenanceClients {\n\t\t\t\tversion, err := maintenanceClient.Version(suite.ctx)\n\t\t\t\tif !asrt.NoError(err) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tsuite.Assert().Equal(DefaultSettings.CurrentVersion, version.GetMessages()[0].GetVersion().GetTag())\n\t\t\t}\n\t\t}, 3*time.Minute, time.Second, \"version API should be available\")\n\t})\n}\n\nfunc init() {\n\tallSuites = append(\n\t\tallSuites,\n\t\t&MaintenanceBasicSuite{track: 3},\n\t)\n}\n"
  },
  {
    "path": "internal/integration/provision/provision.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package provision provides integration tests which rely on provisioning cluster per test.\npackage provision\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/upgrade\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\tsideronet \"github.com/siderolabs/net\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/types\"\n\t\"k8s.io/apimachinery/pkg/util/strategicpatch\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n\t\"github.com/siderolabs/talos/pkg/cluster/check\"\n\t\"github.com/siderolabs/talos/pkg/cluster/hydrophone\"\n\t\"github.com/siderolabs/talos/pkg/cluster/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\ttalosclient \"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/access\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/qemu\"\n)\n\nvar allSuites []suite.TestingSuite\n\n// GetAllSuites returns all the suites for provision test.\n//\n// Depending on build tags, this might return different lists.\nfunc GetAllSuites() []suite.TestingSuite {\n\treturn allSuites\n}\n\n// Settings for provision tests.\ntype Settings struct {\n\t// CIDR to use for provisioned clusters\n\tCIDR string\n\t// Registry mirrors to push to Talos config, in format `host=endpoint`\n\tRegistryMirrors base.StringList\n\t// MTU for the network.\n\tMTU int\n\t// VM parameters\n\tCPUs   int64\n\tMemMB  int64\n\tDiskGB uint64\n\t// Node count for the tests\n\tControlplaneNodes int\n\tWorkerNodes       int\n\t// Target installer image registry\n\tTargetInstallImageRegistry string\n\t// Current version of the cluster (built in the CI pass)\n\tCurrentVersion string\n\t// Custom CNI URL to use.\n\tCustomCNIURL string\n\t// CNI bundle for QEMU provisioner.\n\tCNIBundleURL string\n}\n\n// DefaultSettings filled in by test runner.\nvar DefaultSettings = Settings{\n\tCIDR:                       \"172.21.0.0/24\",\n\tMTU:                        1500,\n\tCPUs:                       4,\n\tMemMB:                      3 * 1024,\n\tDiskGB:                     12,\n\tControlplaneNodes:          3,\n\tWorkerNodes:                1,\n\tTargetInstallImageRegistry: \"ghcr.io\",\n\tCNIBundleURL:               fmt.Sprintf(\"https://github.com/siderolabs/talos/releases/download/%s/talosctl-cni-bundle-%s.tar.gz\", trimVersion(version.Tag), constants.ArchVariable),\n}\n\nfunc trimVersion(version string) string {\n\t// remove anything extra after semantic version core, `v0.3.2-1-abcd` -> `v0.3.2`\n\treturn regexp.MustCompile(`(-\\d+-g[0-9a-f]+)$`).ReplaceAllString(version, \"\")\n}\n\nvar defaultNameservers = []netip.Addr{netip.MustParseAddr(\"8.8.8.8\"), netip.MustParseAddr(\"1.1.1.1\")}\n\n// BaseSuite provides base features for provision tests.\ntype BaseSuite struct {\n\tsuite.Suite\n\tbase.TalosSuite\n\n\tprovisioner provision.Provisioner\n\n\tconfigBundle *bundle.Bundle\n\n\tclusterAccess        *access.Adapter\n\tcontrolPlaneEndpoint string\n\n\t//nolint:containedctx\n\tctx       context.Context\n\tctxCancel context.CancelFunc\n\n\tstateDir string\n\tcniDir   string\n}\n\n// SetupSuite ...\nfunc (suite *BaseSuite) SetupSuite() {\n\t// timeout for the whole test\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), time.Hour)\n\n\tvar err error\n\n\tsuite.provisioner, err = qemu.NewProvisioner(suite.ctx)\n\tsuite.Require().NoError(err)\n}\n\n// TearDownSuite ...\nfunc (suite *BaseSuite) TearDownSuite() {\n\tif suite.clusterAccess != nil {\n\t\tsuite.Assert().NoError(suite.clusterAccess.Close())\n\t}\n\n\tif suite.Cluster != nil {\n\t\tsuite.Assert().NoError(suite.provisioner.Destroy(suite.ctx, suite.Cluster))\n\t}\n\n\tsuite.ctxCancel()\n\n\tif suite.stateDir != \"\" {\n\t\tsuite.Assert().NoError(os.RemoveAll(suite.stateDir))\n\t}\n\n\tif suite.provisioner != nil {\n\t\tsuite.Assert().NoError(suite.provisioner.Close())\n\t}\n}\n\n// waitForClusterHealth asserts cluster health after any change.\nfunc (suite *BaseSuite) waitForClusterHealth() {\n\truns := 1\n\n\tsingleNodeCluster := len(suite.Cluster.Info().Nodes) == 1\n\tif singleNodeCluster {\n\t\t// run health check several times for single node clusters,\n\t\t// as self-hosted control plane is not stable after reboot\n\t\truns = 3\n\t}\n\n\tfor run := range runs {\n\t\tif run > 0 {\n\t\t\ttime.Sleep(15 * time.Second)\n\t\t}\n\n\t\tcheckCtx, checkCtxCancel := context.WithTimeout(suite.ctx, 15*time.Minute)\n\t\tdefer checkCtxCancel()\n\n\t\tsuite.Require().NoError(\n\t\t\tcheck.Wait(\n\t\t\t\tcheckCtx,\n\t\t\t\tsuite.clusterAccess,\n\t\t\t\tcheck.DefaultClusterChecks(),\n\t\t\t\tcheck.StderrReporter(),\n\t\t\t),\n\t\t)\n\t}\n}\n\nfunc (suite *BaseSuite) untaint(name string) {\n\tclient, err := suite.clusterAccess.K8sClient(suite.ctx)\n\tsuite.Require().NoError(err)\n\n\tn, err := client.CoreV1().Nodes().Get(suite.ctx, name, metav1.GetOptions{})\n\tsuite.Require().NoError(err)\n\n\toldData, err := json.Marshal(n)\n\tsuite.Require().NoError(err)\n\n\tk := 0\n\n\tfor _, taint := range n.Spec.Taints {\n\t\tif taint.Key != constants.LabelNodeRoleControlPlane {\n\t\t\tn.Spec.Taints[k] = taint\n\t\t\tk++\n\t\t}\n\t}\n\n\tn.Spec.Taints = n.Spec.Taints[:k]\n\n\tnewData, err := json.Marshal(n)\n\tsuite.Require().NoError(err)\n\n\tpatchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, corev1.Node{})\n\tsuite.Require().NoError(err)\n\n\t_, err = client.CoreV1().Nodes().Patch(\n\t\tsuite.ctx,\n\t\tn.Name,\n\t\ttypes.StrategicMergePatchType,\n\t\tpatchBytes,\n\t\tmetav1.PatchOptions{},\n\t)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *BaseSuite) assertSameVersionCluster(client *talosclient.Client, expectedVersion string) {\n\tnodes := xslices.Map(suite.Cluster.Info().Nodes, func(node provision.NodeInfo) string { return node.IPs[0].String() })\n\tctx := talosclient.WithNodes(suite.ctx, nodes...)\n\n\tvar v *machineapi.VersionResponse\n\n\terr := retry.Constant(\n\t\ttime.Minute,\n\t).Retry(\n\t\tfunc() error {\n\t\t\tvar e error\n\n\t\t\tv, e = client.Version(ctx)\n\n\t\t\treturn retry.ExpectedError(e)\n\t\t},\n\t)\n\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Len(v.Messages, len(nodes))\n\n\tfor _, version := range v.Messages {\n\t\tsuite.Assert().Equal(expectedVersion, version.Version.Tag)\n\t}\n}\n\nfunc (suite *BaseSuite) assertCmdlineContains(client *talosclient.Client, node string, expectedCmdlineContains string) {\n\tctx := talosclient.WithNode(suite.ctx, node)\n\n\tcmdline, err := safe.ReaderGetByID[*runtime.KernelCmdline](ctx, client.COSI, runtime.KernelCmdlineID)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().NotEmpty(cmdline, \"expected cmdline to be not empty\")\n\n\tsuite.Assert().Contains(cmdline.TypedSpec().Cmdline, expectedCmdlineContains, \"expected cmdline to contain %q\", expectedCmdlineContains)\n}\n\nfunc (suite *BaseSuite) readVersion(nodeCtx context.Context, client *talosclient.Client) (\n\tversion string,\n\terr error,\n) {\n\tvar v *machineapi.VersionResponse\n\n\tv, err = client.Version(nodeCtx)\n\tif err != nil {\n\t\treturn version, err\n\t}\n\n\tversion = v.Messages[0].Version.Tag\n\n\treturn version, err\n}\n\ntype upgradeOptions struct {\n\tTargetInstallerImage string\n\t// Deprecated: staged upgrades are not supported by the new LifecycleService API.\n\t// Use the legacy MachineService.Upgrade path instead.\n\tUpgradeStage  bool\n\tTargetVersion string\n}\n\n//nolint:gocyclo,cyclop\nfunc (suite *BaseSuite) upgradeNode(client *talosclient.Client, node provision.NodeInfo, options upgradeOptions) {\n\tsuite.T().Logf(\"upgrading node %s\", node.IPs[0])\n\n\tctx, cancel := context.WithCancel(suite.ctx)\n\tdefer cancel()\n\n\tnodeCtx := talosclient.WithNodes(ctx, node.IPs[0].String())\n\n\t// Staged upgrades are not supported by the new LifecycleService API,\n\t// so skip straight to the legacy path.\n\tif !options.UpgradeStage {\n\t\tif suite.tryUpgradeViaLifecycleService(nodeCtx, client, node, options) {\n\t\t\t// LifecycleService.Upgrade succeeded — trigger reboot and wait.\n\t\t\tsuite.T().Logf(\"upgrade via LifecycleService succeeded, rebooting node %s\", node.IPs[0])\n\n\t\t\tsuite.Require().NoError(client.Reboot(nodeCtx))\n\t\t\tsuite.waitForUpgrade(nodeCtx, client, node, options)\n\n\t\t\treturn\n\t\t}\n\n\t\tsuite.T().Logf(\"LifecycleService.Upgrade not available, falling back to legacy MachineService.Upgrade\")\n\t}\n\n\t// Legacy path: MachineService.Upgrade (handles image pull, install, and reboot in one call).\n\tsuite.upgradeNodeLegacy(nodeCtx, client, options)\n\tsuite.waitForUpgrade(nodeCtx, client, node, options)\n}\n\n// tryUpgradeViaLifecycleService attempts to upgrade via the new streaming\n// LifecycleService.Upgrade API. It pre-pulls the installer image, then calls\n// the streaming RPC. Returns true on success, false if the server returned\n// codes.Unimplemented (indicating the API is not available).\n//\n//nolint:gocyclo\nfunc (suite *BaseSuite) tryUpgradeViaLifecycleService(\n\tnodeCtx context.Context,\n\tc *talosclient.Client,\n\tnode provision.NodeInfo,\n\toptions upgradeOptions,\n) bool {\n\t// Step 1: Pre-pull the installer image into the system containerd namespace.\n\tsuite.T().Logf(\"pre-pulling installer image %q on node %s\", options.TargetInstallerImage, node.IPs[0])\n\n\tcontainerdInstance := &common.ContainerdInstance{\n\t\tDriver:    common.ContainerDriver_CONTAINERD,\n\t\tNamespace: common.ContainerdNamespace_NS_SYSTEM,\n\t}\n\n\tnodes := []string{node.IPs[0].String()}\n\n\tif !suite.pullInstallerImageViaLifecycleService(nodeCtx, c, containerdInstance, nodes, options.TargetInstallerImage) {\n\t\treturn false\n\t}\n\n\tif !suite.upgradeViaLifecycleService(nodeCtx, c, containerdInstance, nodes, options.TargetInstallerImage) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\ntype provisionStreamResponse[ResponseT any] struct {\n\tNode    string\n\tPayload *ResponseT\n\tErr     error\n}\n\nfunc streamPerNode[ResponseT any](\n\tctx context.Context,\n\tnodes []string,\n\tinitiate func(context.Context) (grpc.ServerStreamingClient[ResponseT], error),\n) <-chan provisionStreamResponse[ResponseT] {\n\tresponseCh := make(chan provisionStreamResponse[ResponseT])\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(len(nodes))\n\n\tfor _, node := range nodes {\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\n\t\t\tstream, err := initiate(talosclient.WithNode(ctx, node))\n\t\t\tif err != nil {\n\t\t\t\tsendProvisionResponse(ctx, responseCh, provisionStreamResponse[ResponseT]{\n\t\t\t\t\tNode: node,\n\t\t\t\t\tErr:  err,\n\t\t\t\t})\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tpayload, err := stream.Recv()\n\t\t\t\tif err != nil {\n\t\t\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\tsendProvisionResponse(ctx, responseCh, provisionStreamResponse[ResponseT]{\n\t\t\t\t\t\tNode: node,\n\t\t\t\t\t\tErr:  err,\n\t\t\t\t\t})\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif !sendProvisionResponse(ctx, responseCh, provisionStreamResponse[ResponseT]{\n\t\t\t\t\tNode:    node,\n\t\t\t\t\tPayload: payload,\n\t\t\t\t}) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(responseCh)\n\t}()\n\n\treturn responseCh\n}\n\nfunc sendProvisionResponse[ResponseT any](\n\tctx context.Context,\n\tresponseCh chan<- provisionStreamResponse[ResponseT],\n\tresp provisionStreamResponse[ResponseT],\n) bool {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn false\n\tcase responseCh <- resp:\n\t\treturn true\n\t}\n}\n\nfunc (suite *BaseSuite) pullInstallerImageViaLifecycleService(\n\tctx context.Context,\n\tc *talosclient.Client,\n\tcontainerdInstance *common.ContainerdInstance,\n\tnodes []string,\n\timageRef string,\n) bool {\n\tresponseChan := streamPerNode(ctx, nodes,\n\t\tfunc(ctx context.Context) (grpc.ServerStreamingClient[machineapi.ImageServicePullResponse], error) {\n\t\t\treturn c.ImageClient.Pull(ctx, &machineapi.ImageServicePullRequest{\n\t\t\t\tContainerd: containerdInstance,\n\t\t\t\tImageRef:   imageRef,\n\t\t\t})\n\t\t},\n\t)\n\n\tvar (\n\t\tfinishedPulls = map[string]string{}\n\t\terrs          error\n\t)\n\n\tfor resp := range responseChan {\n\t\tif resp.Err != nil {\n\t\t\tif status.Code(resp.Err) == codes.Unimplemented {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.Payload == nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"empty image pull response from node %s\", resp.Node))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch payload := resp.Payload.Response.(type) {\n\t\tcase *machineapi.ImageServicePullResponse_Name:\n\t\t\tfinishedPulls[resp.Node] = payload.Name\n\t\tcase *machineapi.ImageServicePullResponse_PullProgress:\n\t\tdefault:\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"unexpected image pull response type from node %s: %T\", resp.Node, payload))\n\t\t}\n\t}\n\n\tsuite.Require().NoError(errs, \"error during image pull\")\n\n\tfor node, imageName := range finishedPulls {\n\t\tsuite.T().Logf(\"node %s pulled image %s\", node, imageName)\n\t}\n\n\treturn true\n}\n\nfunc (suite *BaseSuite) upgradeViaLifecycleService(\n\tctx context.Context,\n\tc *talosclient.Client,\n\tcontainerdInstance *common.ContainerdInstance,\n\tnodes []string,\n\timageRef string,\n) bool {\n\tresponseChan := streamPerNode(ctx, nodes,\n\t\tfunc(ctx context.Context) (grpc.ServerStreamingClient[machineapi.LifecycleServiceUpgradeResponse], error) {\n\t\t\treturn c.LifecycleClient.Upgrade(ctx, &machineapi.LifecycleServiceUpgradeRequest{\n\t\t\t\tContainerd: containerdInstance,\n\t\t\t\tSource: &machineapi.InstallArtifactsSource{\n\t\t\t\t\tImageName: imageRef,\n\t\t\t\t},\n\t\t\t})\n\t\t},\n\t)\n\n\tvar (\n\t\texitCodes = map[string]int32{}\n\t\terrs      error\n\t)\n\n\tfor resp := range responseChan {\n\t\tif resp.Err != nil {\n\t\t\tif status.Code(resp.Err) == codes.Unimplemented {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"error from node %s: %w\", resp.Node, resp.Err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif resp.Payload == nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"empty upgrade response from node %s\", resp.Node))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch payload := resp.Payload.GetProgress().GetResponse().(type) {\n\t\tcase *machineapi.LifecycleServiceInstallProgress_Message:\n\t\t\tsuite.T().Logf(\"upgrade log (%s): %s\", resp.Node, payload.Message)\n\t\tcase *machineapi.LifecycleServiceInstallProgress_ExitCode:\n\t\t\texitCodes[resp.Node] = payload.ExitCode\n\t\tdefault:\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"unexpected upgrade response type from node %s: %T\", resp.Node, payload))\n\t\t}\n\t}\n\n\tsuite.Require().NoError(errs, \"error during LifecycleService.Upgrade\")\n\n\tfor node, exitCode := range exitCodes {\n\t\tsuite.Require().Equalf(int32(0), exitCode, \"LifecycleService.Upgrade exited with non-zero code on node %s\", node)\n\t}\n\n\treturn true\n}\n\n// upgradeNodeLegacy performs an upgrade using the legacy (deprecated) MachineService.Upgrade\n// unary API, which handles image pull, install, and reboot in a single call.\n//\n//nolint:gocyclo\nfunc (suite *BaseSuite) upgradeNodeLegacy(\n\tnodeCtx context.Context,\n\tc *talosclient.Client,\n\toptions upgradeOptions,\n) {\n\tvar (\n\t\tresp *machineapi.UpgradeResponse\n\t\terr  error\n\t)\n\n\terr = retry.Constant(time.Minute, retry.WithUnits(10*time.Second)).Retry(\n\t\tfunc() error {\n\t\t\tresp, err = c.Upgrade( //nolint:staticcheck // using deprecated API for testing backward compatibility\n\t\t\t\tnodeCtx,\n\t\t\t\toptions.TargetInstallerImage,\n\t\t\t\toptions.UpgradeStage,\n\t\t\t\tfalse,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tif strings.Contains(err.Error(), \"leader changed\") {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\tif strings.Contains(err.Error(), \"failed to acquire upgrade lock\") {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t)\n\n\tsuite.Require().NoError(err)\n\tsuite.Require().Equal(\"Upgrade request received\", resp.Messages[0].Ack)\n\n\tactorID := resp.Messages[0].ActorId\n\n\teventCh := make(chan talosclient.EventResult)\n\n\t// watch for events\n\tsuite.Require().NoError(c.EventsWatchV2(nodeCtx, eventCh, talosclient.WithActorID(actorID), talosclient.WithTailEvents(-1)))\n\n\twaitTimer := time.NewTimer(5 * time.Minute)\n\tdefer waitTimer.Stop()\n\nwaitLoop:\n\tfor {\n\t\tselect {\n\t\tcase ev := <-eventCh:\n\t\t\tsuite.Require().NoError(ev.Error)\n\n\t\t\tswitch msg := ev.Event.Payload.(type) {\n\t\t\tcase *machineapi.SequenceEvent:\n\t\t\t\tif msg.Error != nil {\n\t\t\t\t\tsuite.FailNow(\"upgrade failed\", \"%s: %s\", msg.Error.Message, msg.Error.Code)\n\t\t\t\t}\n\t\t\tcase *machineapi.PhaseEvent:\n\t\t\t\tif msg.Action == machineapi.PhaseEvent_START && msg.Phase == \"kexec\" {\n\t\t\t\t\t// about to be rebooted\n\t\t\t\t\tbreak waitLoop\n\t\t\t\t}\n\n\t\t\t\tif msg.Action == machineapi.PhaseEvent_STOP {\n\t\t\t\t\tsuite.T().Logf(\"upgrade phase %q finished\", msg.Phase)\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-waitTimer.C:\n\t\t\tsuite.FailNow(\"timeout waiting for upgrade to finish\")\n\t\tcase <-nodeCtx.Done():\n\t\t\tsuite.FailNow(\"context canceled\")\n\t\t}\n\t}\n}\n\n// waitForUpgrade waits for the node to come back up after a reboot with the\n// expected target version, then verifies cluster health. This is shared by\n// both the new LifecycleService and the legacy MachineService upgrade paths.\nfunc (suite *BaseSuite) waitForUpgrade(\n\tnodeCtx context.Context,\n\tc *talosclient.Client,\n\tnode provision.NodeInfo,\n\toptions upgradeOptions,\n) {\n\t// wait for the apid to be shut down\n\ttime.Sleep(10 * time.Second)\n\n\t// wait for the version to be equal to target version\n\tvar err error\n\n\tsuite.Require().NoError(\n\t\tretry.Constant(10 * time.Minute).Retry(\n\t\t\tfunc() error {\n\t\t\t\tvar version string\n\n\t\t\t\tversion, err = suite.readVersion(nodeCtx, c)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// API might be unresponsive during upgrade\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\tif version != options.TargetVersion {\n\t\t\t\t\t// upgrade not finished yet\n\t\t\t\t\treturn retry.ExpectedErrorf(\n\t\t\t\t\t\t\"node %q version doesn't match expected: expected %q, got %q\",\n\t\t\t\t\t\tnode.IPs[0].String(),\n\t\t\t\t\t\toptions.TargetVersion,\n\t\t\t\t\t\tversion,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t),\n\t)\n\n\tsuite.waitForClusterHealth()\n}\n\nfunc (suite *BaseSuite) upgradeKubernetes(fromVersion, toVersion string, skipKubeletUpgrade bool) {\n\tif fromVersion == toVersion {\n\t\tsuite.T().Logf(\"skipping Kubernetes upgrade, as versions are equal %q -> %q\", fromVersion, toVersion)\n\n\t\treturn\n\t}\n\n\tsuite.T().Logf(\"upgrading Kubernetes: %q -> %q\", fromVersion, toVersion)\n\n\tpath, err := upgrade.NewPath(fromVersion, toVersion)\n\tsuite.Require().NoError(err)\n\n\toptions := kubernetes.UpgradeOptions{\n\t\tPath: path,\n\n\t\tControlPlaneEndpoint: suite.controlPlaneEndpoint,\n\n\t\tUpgradeKubelet: !skipKubeletUpgrade,\n\t\tPrePullImages:  true,\n\n\t\tKubeletImage:           constants.KubeletImage,\n\t\tAPIServerImage:         constants.KubernetesAPIServerImage,\n\t\tControllerManagerImage: constants.KubernetesControllerManagerImage,\n\t\tSchedulerImage:         constants.KubernetesSchedulerImage,\n\t\tProxyImage:             constants.KubeProxyImage,\n\n\t\tEncoderOpt: encoder.WithComments(encoder.CommentsAll),\n\n\t\tInventoryPolicy:  ssa.InventoryPolicyAdoptIfNoInventory,\n\t\tReconcileTimeout: 3 * time.Minute,\n\t}\n\n\tsuite.Require().NoError(kubernetes.Upgrade(suite.ctx, suite.clusterAccess, options))\n}\n\ntype clusterOptions struct {\n\tClusterName string\n\n\tControlplaneNodes int\n\tWorkerNodes       int\n\n\tInjectExtraKernelArgs *procfs.Cmdline\n\n\tSourceKernelPath     string\n\tSourceInitramfsPath  string\n\tSourceDiskImagePath  string\n\tSourceISOPath        string\n\tSourceInstallerImage string\n\tSourceVersion        string\n\tSourceK8sVersion     string\n\n\tWithEncryption          bool\n\tWithBios                bool\n\tWithApplyConfig         bool\n\tWithSkipInjectingConfig bool\n}\n\n// setupCluster provisions source clusters and waits for health.\n//\n//nolint:gocyclo\nfunc (suite *BaseSuite) setupCluster(options clusterOptions) {\n\tdefaultStateDir, err := clientconfig.GetTalosDirectory()\n\tsuite.Require().NoError(err)\n\n\tsuite.stateDir = filepath.Join(defaultStateDir, \"clusters\")\n\tsuite.cniDir = filepath.Join(defaultStateDir, \"cni\")\n\n\tcidr, err := netip.ParsePrefix(DefaultSettings.CIDR)\n\tsuite.Require().NoError(err)\n\n\tvar gatewayIP netip.Addr\n\n\tgatewayIP, err = sideronet.NthIPInNetwork(cidr, 1)\n\tsuite.Require().NoError(err)\n\n\tips := make([]netip.Addr, options.ControlplaneNodes+options.WorkerNodes)\n\n\tfor i := range ips {\n\t\tips[i], err = sideronet.NthIPInNetwork(cidr, i+2)\n\t\tsuite.Require().NoError(err)\n\t}\n\n\tsuite.T().Logf(\"initializing provisioner with cluster name %q, state directory %q\", options.ClusterName, suite.stateDir)\n\n\trequest := provision.ClusterRequest{\n\t\tName: options.ClusterName,\n\n\t\tNetwork: provision.NetworkRequest{\n\t\t\tName:         options.ClusterName,\n\t\t\tCIDRs:        []netip.Prefix{cidr},\n\t\t\tGatewayAddrs: []netip.Addr{gatewayIP},\n\t\t\tMTU:          DefaultSettings.MTU,\n\t\t\tNameservers:  defaultNameservers,\n\t\t\tCNI: provision.CNIConfig{\n\t\t\t\tBinPath:  []string{filepath.Join(suite.cniDir, \"bin\")},\n\t\t\t\tConfDir:  filepath.Join(suite.cniDir, \"conf.d\"),\n\t\t\t\tCacheDir: filepath.Join(suite.cniDir, \"cache\"),\n\n\t\t\t\tBundleURL: DefaultSettings.CNIBundleURL,\n\t\t\t},\n\t\t},\n\n\t\tSelfExecutable: suite.TalosctlPath,\n\t\tStateDirectory: suite.stateDir,\n\t}\n\n\tswitch {\n\tcase options.SourceISOPath != \"\":\n\t\trequest.ISOPath = options.SourceISOPath\n\tcase options.SourceDiskImagePath != \"\":\n\t\trequest.DiskImagePath = options.SourceDiskImagePath\n\tdefault:\n\t\trequest.KernelPath = options.SourceKernelPath\n\t\trequest.InitramfsPath = options.SourceInitramfsPath\n\t}\n\n\tsuite.controlPlaneEndpoint = suite.provisioner.GetExternalKubernetesControlPlaneEndpoint(request.Network, constants.DefaultControlPlanePort)\n\n\tversionContract, err := config.ParseContractFromVersion(options.SourceVersion)\n\tsuite.Require().NoError(err)\n\n\tgenOptions, bundleOptions := suite.provisioner.GenOptions(request.Network, versionContract)\n\n\tfor _, registryMirror := range DefaultSettings.RegistryMirrors {\n\t\tparts := strings.Split(registryMirror, \"=\")\n\t\tsuite.Require().Len(parts, 2)\n\n\t\tgenOptions = append(genOptions, generate.WithRegistryMirror(parts[0], parts[1]))\n\t}\n\n\tcontrolplaneEndpoints := make([]string, options.ControlplaneNodes)\n\tfor i := range controlplaneEndpoints {\n\t\tcontrolplaneEndpoints[i] = ips[i].String()\n\t}\n\n\tif DefaultSettings.CustomCNIURL != \"\" {\n\t\tgenOptions = append(\n\t\t\tgenOptions, generate.WithClusterCNIConfig(\n\t\t\t\t&v1alpha1.CNIConfig{\n\t\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t\t\tCNIUrls: []string{DefaultSettings.CustomCNIURL},\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t}\n\n\tvar extraPatches []configpatcher.Patch\n\n\tif options.WithEncryption {\n\t\tif versionContract.VolumeConfigEncryptionSupported() {\n\t\t\t// use modern encryption config\n\t\t\tstateCfg := block.NewVolumeConfigV1Alpha1()\n\t\t\tstateCfg.MetaName = constants.StatePartitionLabel\n\t\t\tstateCfg.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\tstateCfg.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeySlot:   0,\n\t\t\t\t\tKeyNodeID: &block.EncryptionKeyNodeID{},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tephemeralCfg := block.NewVolumeConfigV1Alpha1()\n\t\t\tephemeralCfg.MetaName = constants.EphemeralPartitionLabel\n\t\t\tephemeralCfg.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\tephemeralCfg.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t{\n\t\t\t\t\tKeySlot:        0,\n\t\t\t\t\tKeyNodeID:      &block.EncryptionKeyNodeID{},\n\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tctr, err := container.New(stateCfg, ephemeralCfg)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\textraPatches = append(extraPatches, configpatcher.NewStrategicMergePatch(ctr))\n\t\t} else {\n\t\t\t// use legacy encryption config\n\t\t\tdiskEncryptionConfig := &v1alpha1.SystemDiskEncryptionConfig{\n\t\t\t\tStatePartition: &v1alpha1.EncryptionConfig{\n\t\t\t\t\tEncryptionProvider: encryption.LUKS2,\n\t\t\t\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot:   0,\n\t\t\t\t\t\t\tKeyNodeID: &v1alpha1.EncryptionKeyNodeID{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tEphemeralPartition: &v1alpha1.EncryptionConfig{\n\t\t\t\t\tEncryptionProvider: encryption.LUKS2,\n\t\t\t\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot:   0,\n\t\t\t\t\t\t\tKeyNodeID: &v1alpha1.EncryptionKeyNodeID{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tpatchRaw := map[string]any{\n\t\t\t\t\"machine\": map[string]any{\n\t\t\t\t\t\"systemDiskEncryption\": diskEncryptionConfig,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tpatchData, err := yaml.Marshal(patchRaw)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tpatch, err := configpatcher.LoadPatch(patchData)\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\textraPatches = append(extraPatches, patch)\n\t\t}\n\t}\n\n\tsuite.configBundle, err = bundle.NewBundle(\n\t\tappend([]bundle.Option{\n\t\t\tbundle.WithInputOptions(\n\t\t\t\t&bundle.InputOptions{\n\t\t\t\t\tClusterName: options.ClusterName,\n\t\t\t\t\tEndpoint:    suite.controlPlaneEndpoint,\n\t\t\t\t\tKubeVersion: options.SourceK8sVersion,\n\t\t\t\t\tGenOptions: append(\n\t\t\t\t\t\tgenOptions,\n\t\t\t\t\t\tgenerate.WithEndpointList(controlplaneEndpoints),\n\t\t\t\t\t\tgenerate.WithInstallImage(options.SourceInstallerImage),\n\t\t\t\t\t\tgenerate.WithDNSDomain(\"cluster.local\"),\n\t\t\t\t\t\tgenerate.WithVersionContract(versionContract),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t),\n\t\t\tbundle.WithPatch(extraPatches),\n\t\t},\n\t\t\tbundleOptions...,\n\t\t)...,\n\t)\n\tsuite.Require().NoError(err)\n\n\tfor i := range options.ControlplaneNodes {\n\t\trequest.Nodes = append(\n\t\t\trequest.Nodes,\n\t\t\tprovision.NodeRequest{\n\t\t\t\tName:     fmt.Sprintf(\"control-plane-%d\", i+1),\n\t\t\t\tType:     machine.TypeControlPlane,\n\t\t\t\tIPs:      []netip.Addr{ips[i]},\n\t\t\t\tMemory:   DefaultSettings.MemMB * 1024 * 1024,\n\t\t\t\tNanoCPUs: DefaultSettings.CPUs * 1000 * 1000 * 1000,\n\t\t\t\tDisks: []*provision.Disk{\n\t\t\t\t\t{\n\t\t\t\t\t\tSize: DefaultSettings.DiskGB * 1024 * 1024 * 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tConfig:              suite.configBundle.ControlPlane(),\n\t\t\t\tSDStubKernelArgs:    options.InjectExtraKernelArgs,\n\t\t\t\tSkipInjectingConfig: options.WithSkipInjectingConfig,\n\t\t\t},\n\t\t)\n\t}\n\n\tfor i := 1; i <= options.WorkerNodes; i++ {\n\t\trequest.Nodes = append(\n\t\t\trequest.Nodes,\n\t\t\tprovision.NodeRequest{\n\t\t\t\tName:     fmt.Sprintf(\"worker-%d\", i),\n\t\t\t\tType:     machine.TypeWorker,\n\t\t\t\tIPs:      []netip.Addr{ips[options.ControlplaneNodes+i-1]},\n\t\t\t\tMemory:   DefaultSettings.MemMB * 1024 * 1024,\n\t\t\t\tNanoCPUs: DefaultSettings.CPUs * 1000 * 1000 * 1000,\n\t\t\t\tDisks: []*provision.Disk{\n\t\t\t\t\t{\n\t\t\t\t\t\tSize: DefaultSettings.DiskGB * 1024 * 1024 * 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tConfig:              suite.configBundle.Worker(),\n\t\t\t\tSDStubKernelArgs:    options.InjectExtraKernelArgs,\n\t\t\t\tSkipInjectingConfig: options.WithSkipInjectingConfig,\n\t\t\t},\n\t\t)\n\t}\n\n\tprovisionerOptions := []provision.Option{\n\t\tprovision.WithBootlader(true),\n\t\tprovision.WithUEFI(!options.WithBios),\n\t\tprovision.WithTalosConfig(suite.configBundle.TalosConfig()),\n\t}\n\n\tsuite.Cluster, err = suite.provisioner.Create(\n\t\tsuite.ctx, request,\n\t\tprovisionerOptions...,\n\t)\n\tsuite.Require().NoError(err)\n\n\tif options.WithApplyConfig {\n\t\tclusterAccess := access.NewAdapter(suite.Cluster, provisionerOptions...)\n\t\tdefer clusterAccess.Close() //nolint:errcheck\n\n\t\tif err := clusterAccess.ApplyConfig(suite.ctx, request.Nodes, request.SiderolinkRequest, os.Stderr); err != nil {\n\t\t\tsuite.FailNow(\"failed to apply config\", err.Error())\n\t\t}\n\t}\n\n\tc, err := clientconfig.Open(\"\")\n\tsuite.Require().NoError(err)\n\n\tc.Merge(suite.configBundle.TalosConfig())\n\n\tsuite.Require().NoError(c.Save(\"\"))\n\n\tsuite.clusterAccess = access.NewAdapter(suite.Cluster, provision.WithTalosConfig(suite.configBundle.TalosConfig()))\n\n\tif !options.WithSkipInjectingConfig {\n\t\tsuite.Require().NoError(suite.clusterAccess.Bootstrap(suite.ctx, os.Stdout))\n\n\t\tsuite.waitForClusterHealth()\n\t}\n}\n\n// runE2E runs e2e test on the cluster.\nfunc (suite *BaseSuite) runE2E(k8sVersion string) {\n\toptions := hydrophone.DefaultOptions()\n\toptions.KubernetesVersion = k8sVersion\n\n\tsuite.Assert().NoError(hydrophone.Run(suite.ctx, suite.clusterAccess, options))\n}\n"
  },
  {
    "path": "internal/integration/provision/upgrade.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration_provision\n\npackage provision\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/rtestutils\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/mgmt/helpers\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\ttalosclient \"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n//nolint:maligned\ntype upgradeSpec struct {\n\tShortName string\n\n\tInjectExtraKernelArgs *procfs.Cmdline\n\n\tSourceKernelPath     string\n\tSourceInitramfsPath  string\n\tSourceDiskImagePath  string\n\tSourceISOPath        string\n\tSourceInstallerImage string\n\tSourceVersion        string\n\tSourceK8sVersion     string\n\n\tTargetInstallerImage  string\n\tTargetVersion         string\n\tTargetK8sVersion      string\n\tTargetCmdlineContains string\n\n\tSkipKubeletUpgrade bool\n\n\tControlplaneNodes int\n\tWorkerNodes       int\n\n\t// Deprecated: staged upgrades are not supported by the new LifecycleService API.\n\t// Use the legacy MachineService.Upgrade path instead.\n\tUpgradeStage    bool\n\tWithEncryption  bool\n\tWithBios        bool\n\tWithApplyConfig bool\n\tWithEnforcing   bool\n}\n\nconst (\n\t// These versions should be kept in sync with Makefile variable RELEASES.\n\tpreviousRelease = \"v1.11.6\"\n\tstableRelease   = \"v1.12.0\" // or soon-to-be-stable\n\t// The current version (the one being built on CI) is DefaultSettings.CurrentVersion.\n\n\t// Command to find Kubernetes version for past releases:\n\t//\n\t//  git show ${TAG}:pkg/machinery/constants/constants.go | grep KubernetesVersion\n\tpreviousK8sVersion = \"1.34.1\" // constants.DefaultKubernetesVersion in the previousRelease\n\tstableK8sVersion   = \"1.35.0\" // constants.DefaultKubernetesVersion in the stableRelease\n\tcurrentK8sVersion  = constants.DefaultKubernetesVersion\n)\n\n// upgradePreviousToStable upgrades from the previous Talos release to the stable release.\nfunc upgradePreviousToStable() upgradeSpec {\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-%s\", previousRelease, stableRelease),\n\n\t\tSourceKernelPath: helpers.ArtifactPath(filepath.Join(trimVersion(previousRelease), constants.KernelAsset)),\n\t\tSourceInitramfsPath: helpers.ArtifactPath(\n\t\t\tfilepath.Join(\n\t\t\t\ttrimVersion(previousRelease),\n\t\t\t\tconstants.InitramfsAsset,\n\t\t\t),\n\t\t),\n\t\tSourceInstallerImage: fmt.Sprintf(\"%s:%s\", \"ghcr.io/siderolabs/installer\", previousRelease),\n\t\tSourceVersion:        previousRelease,\n\t\tSourceK8sVersion:     previousK8sVersion,\n\n\t\tTargetInstallerImage: fmt.Sprintf(\"%s:%s\", \"ghcr.io/siderolabs/installer\", stableRelease),\n\t\tTargetVersion:        stableRelease,\n\t\tTargetK8sVersion:     stableK8sVersion,\n\n\t\tControlplaneNodes: DefaultSettings.ControlplaneNodes,\n\t\tWorkerNodes:       DefaultSettings.WorkerNodes,\n\t}\n}\n\n// upgradeStableToCurrent upgrades from the stable Talos release to the current version.\nfunc upgradeStableToCurrent() upgradeSpec {\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-%s\", stableRelease, DefaultSettings.CurrentVersion),\n\n\t\tSourceKernelPath:     helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.KernelAsset)),\n\t\tSourceInitramfsPath:  helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.InitramfsAsset)),\n\t\tSourceInstallerImage: fmt.Sprintf(\"%s:%s\", \"ghcr.io/siderolabs/installer\", stableRelease),\n\t\tSourceVersion:        stableRelease,\n\t\tSourceK8sVersion:     stableK8sVersion,\n\n\t\tTargetInstallerImage: fmt.Sprintf(\n\t\t\t\"%s/%s:%s\",\n\t\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\t\timages.DefaultInstallerImageName,\n\t\t\tDefaultSettings.CurrentVersion,\n\t\t),\n\t\tTargetVersion:    DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion: currentK8sVersion,\n\n\t\tControlplaneNodes: DefaultSettings.ControlplaneNodes,\n\t\tWorkerNodes:       DefaultSettings.WorkerNodes,\n\n\t\tWithEncryption: true,\n\t}\n}\n\n// upgradeCurrentToCurrent upgrades the current version to itself.\nfunc upgradeCurrentToCurrent() upgradeSpec {\n\tinstallerImage := fmt.Sprintf(\n\t\t\"%s/%s:%s\",\n\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\timages.DefaultInstallerImageName,\n\t\tDefaultSettings.CurrentVersion,\n\t)\n\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-same-ver\", DefaultSettings.CurrentVersion),\n\n\t\tSourceKernelPath:     helpers.ArtifactPath(constants.KernelAssetWithArch),\n\t\tSourceInitramfsPath:  helpers.ArtifactPath(constants.InitramfsAssetWithArch),\n\t\tSourceInstallerImage: installerImage,\n\t\tSourceVersion:        DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion:     currentK8sVersion,\n\n\t\tTargetInstallerImage: installerImage,\n\t\tTargetVersion:        DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion:     currentK8sVersion,\n\n\t\tControlplaneNodes: DefaultSettings.ControlplaneNodes,\n\t\tWorkerNodes:       DefaultSettings.WorkerNodes,\n\n\t\tWithEncryption: true,\n\t}\n}\n\n// upgradeCurrentToCurrentBios upgrades the current version to itself without UEFI.\nfunc upgradeCurrentToCurrentBios() upgradeSpec {\n\tinstallerImage := fmt.Sprintf(\n\t\t\"%s/%s:%s\",\n\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\timages.DefaultInstallerImageName,\n\t\tDefaultSettings.CurrentVersion,\n\t)\n\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-same-ver-bios\", DefaultSettings.CurrentVersion),\n\n\t\tSourceDiskImagePath:  helpers.ArtifactPath(\"metal-amd64.raw.zst\"),\n\t\tSourceInstallerImage: installerImage,\n\t\tSourceVersion:        DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion:     currentK8sVersion,\n\n\t\tTargetInstallerImage: installerImage,\n\t\tTargetVersion:        DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion:     currentK8sVersion,\n\n\t\tControlplaneNodes: DefaultSettings.ControlplaneNodes,\n\t\tWorkerNodes:       DefaultSettings.WorkerNodes,\n\n\t\tWithEncryption:  true,\n\t\tWithBios:        true,\n\t\tWithApplyConfig: true,\n\t}\n}\n\n// upgradeStableToCurrentPreserveStage upgrades from the stable Talos release to the current version for single-node cluster with preserve and stage.\nfunc upgradeStableToCurrentPreserveStage() upgradeSpec {\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"prsrv-stg-%s-%s\", stableRelease, DefaultSettings.CurrentVersion),\n\n\t\tSourceKernelPath:     helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.KernelAsset)),\n\t\tSourceInitramfsPath:  helpers.ArtifactPath(filepath.Join(trimVersion(stableRelease), constants.InitramfsAsset)),\n\t\tSourceInstallerImage: fmt.Sprintf(\"%s:%s\", \"ghcr.io/siderolabs/installer\", stableRelease),\n\t\tSourceVersion:        stableRelease,\n\t\tSourceK8sVersion:     stableK8sVersion,\n\n\t\tTargetInstallerImage: fmt.Sprintf(\n\t\t\t\"%s/%s:%s\",\n\t\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\t\timages.DefaultInstallerImageName,\n\t\t\tDefaultSettings.CurrentVersion,\n\t\t),\n\t\tTargetVersion:    DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion: currentK8sVersion,\n\n\t\tControlplaneNodes: 1,\n\t\tWorkerNodes:       0,\n\t\tUpgradeStage:      true,\n\t}\n}\n\nfunc upgradeCurrentToCurrentNewCmdline() upgradeSpec {\n\tinstallerImage := fmt.Sprintf(\n\t\t\"%s/%s:%s\",\n\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\timages.DefaultInstallerImageName,\n\t\tDefaultSettings.CurrentVersion,\n\t)\n\n\ttargetInstallerImage := installerImage + \"-extra-cmdline\"\n\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-same-ver-extra-cmdline\", DefaultSettings.CurrentVersion),\n\n\t\tSourceISOPath:        helpers.ArtifactPath(\"metal-amd64.iso\"),\n\t\tSourceInstallerImage: installerImage,\n\t\tSourceVersion:        DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion:     currentK8sVersion,\n\n\t\tTargetInstallerImage: targetInstallerImage,\n\t\tTargetVersion:        DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion:     currentK8sVersion,\n\n\t\tControlplaneNodes: 1,\n\t\tWorkerNodes:       0,\n\n\t\tTargetCmdlineContains: \"talos.extra_cmdline=extra-super-cmdline\",\n\n\t\tWithApplyConfig: true,\n\t}\n}\n\nfunc upgradeCurrentToCurrentEnforcing() upgradeSpec {\n\tinstallerImage := fmt.Sprintf(\n\t\t\"%s/%s:%s\",\n\t\tDefaultSettings.TargetInstallImageRegistry,\n\t\timages.DefaultInstallerImageName,\n\t\tDefaultSettings.CurrentVersion,\n\t)\n\n\treturn upgradeSpec{\n\t\tShortName: fmt.Sprintf(\"%s-same-ver-enforcing\", DefaultSettings.CurrentVersion),\n\n\t\tInjectExtraKernelArgs: procfs.NewCmdline(\"enforcing=1\"),\n\n\t\tSourceISOPath:        helpers.ArtifactPath(\"metal-amd64.iso\"),\n\t\tSourceInstallerImage: installerImage,\n\t\tSourceVersion:        DefaultSettings.CurrentVersion,\n\t\tSourceK8sVersion:     currentK8sVersion,\n\n\t\tTargetInstallerImage: installerImage,\n\t\tTargetVersion:        DefaultSettings.CurrentVersion,\n\t\tTargetK8sVersion:     currentK8sVersion,\n\n\t\tControlplaneNodes: 1,\n\t\tWorkerNodes:       0,\n\n\t\tTargetCmdlineContains: \"enforcing=1\",\n\n\t\tWithApplyConfig: true,\n\t\tWithEnforcing:   true,\n\t}\n}\n\n// UpgradeSuite ...\ntype UpgradeSuite struct {\n\tBaseSuite\n\n\tspecGen func() upgradeSpec\n\tspec    upgradeSpec\n\n\ttrack int\n}\n\n// SetupSuite ...\nfunc (suite *UpgradeSuite) SetupSuite() {\n\t// call generate late in the flow, as it needs to pick up settings overridden by test runner\n\tsuite.spec = suite.specGen()\n\n\tsuite.T().Logf(\"upgrade spec = %v\", suite.spec)\n\n\tsuite.BaseSuite.SetupSuite()\n}\n\n// runE2E runs e2e test on the cluster.\nfunc (suite *UpgradeSuite) runE2E(k8sVersion string) {\n\tif suite.spec.WorkerNodes == 0 {\n\t\t// no worker nodes, should make masters schedulable\n\t\tsuite.untaint(\"control-plane-1\")\n\t}\n\n\tsuite.BaseSuite.runE2E(k8sVersion)\n}\n\n// TestRolling performs rolling upgrade starting with master nodes.\nfunc (suite *UpgradeSuite) TestRolling() {\n\tsuite.setupCluster(clusterOptions{\n\t\tClusterName: suite.spec.ShortName,\n\n\t\tControlplaneNodes: suite.spec.ControlplaneNodes,\n\t\tWorkerNodes:       suite.spec.WorkerNodes,\n\n\t\tInjectExtraKernelArgs: suite.spec.InjectExtraKernelArgs,\n\n\t\tSourceKernelPath:     suite.spec.SourceKernelPath,\n\t\tSourceInitramfsPath:  suite.spec.SourceInitramfsPath,\n\t\tSourceDiskImagePath:  suite.spec.SourceDiskImagePath,\n\t\tSourceISOPath:        suite.spec.SourceISOPath,\n\t\tSourceInstallerImage: suite.spec.SourceInstallerImage,\n\t\tSourceVersion:        suite.spec.SourceVersion,\n\t\tSourceK8sVersion:     suite.spec.SourceK8sVersion,\n\n\t\tWithEncryption:  suite.spec.WithEncryption,\n\t\tWithBios:        suite.spec.WithBios,\n\t\tWithApplyConfig: suite.spec.WithApplyConfig,\n\t})\n\n\tclient, err := suite.clusterAccess.Client()\n\tsuite.Require().NoError(err)\n\n\t// verify initial cluster version\n\tsuite.assertSameVersionCluster(client, suite.spec.SourceVersion)\n\n\t// verify enforcing state\n\tfor _, node := range suite.Cluster.Info().Nodes {\n\t\trtestutils.AssertResource(\n\t\t\ttalosclient.WithNode(suite.ctx, node.IPs[0].String()),\n\t\t\tsuite.T(), client.COSI,\n\t\t\truntime.SecurityStateID,\n\t\t\tfunc(r *runtime.SecurityState, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(suite.spec.WithEnforcing, r.TypedSpec().SELinuxState == runtime.SELinuxStateEnforcing)\n\t\t\t},\n\t\t)\n\t}\n\n\toptions := upgradeOptions{\n\t\tTargetInstallerImage: suite.spec.TargetInstallerImage,\n\t\tUpgradeStage:         suite.spec.UpgradeStage,\n\t\tTargetVersion:        suite.spec.TargetVersion,\n\t}\n\n\t// upgrade master nodes\n\tfor _, node := range suite.Cluster.Info().Nodes {\n\t\tif node.Type == machine.TypeInit || node.Type == machine.TypeControlPlane {\n\t\t\tsuite.upgradeNode(client, node, options)\n\t\t}\n\t}\n\n\t// upgrade worker nodes\n\tfor _, node := range suite.Cluster.Info().Nodes {\n\t\tif node.Type == machine.TypeWorker {\n\t\t\tsuite.upgradeNode(client, node, options)\n\t\t}\n\t}\n\n\t// verify final cluster version\n\tsuite.assertSameVersionCluster(client, suite.spec.TargetVersion)\n\n\t// verify enforcing state\n\tfor _, node := range suite.Cluster.Info().Nodes {\n\t\trtestutils.AssertResource(\n\t\t\ttalosclient.WithNode(suite.ctx, node.IPs[0].String()),\n\t\t\tsuite.T(), client.COSI,\n\t\t\truntime.SecurityStateID,\n\t\t\tfunc(r *runtime.SecurityState, asrt *assert.Assertions) {\n\t\t\t\tasrt.Equal(suite.spec.WithEnforcing, r.TypedSpec().SELinuxState == runtime.SELinuxStateEnforcing)\n\t\t\t},\n\t\t)\n\t}\n\n\t// upgrade Kubernetes if required\n\tsuite.upgradeKubernetes(suite.spec.SourceK8sVersion, suite.spec.TargetK8sVersion, suite.spec.SkipKubeletUpgrade)\n\n\tif suite.spec.TargetCmdlineContains != \"\" {\n\t\tfor _, node := range suite.Cluster.Info().Nodes {\n\t\t\tsuite.assertCmdlineContains(client, node.IPs[0].String(), suite.spec.TargetCmdlineContains)\n\t\t}\n\t}\n\n\t// run e2e test\n\tsuite.runE2E(suite.spec.TargetK8sVersion)\n}\n\n// SuiteName ...\nfunc (suite *UpgradeSuite) SuiteName() string {\n\tif suite.spec.ShortName == \"\" {\n\t\tsuite.spec = suite.specGen()\n\t}\n\n\treturn fmt.Sprintf(\"provision.UpgradeSuite.%s-TR%d\", suite.spec.ShortName, suite.track)\n}\n\nfunc init() {\n\tallSuites = append(\n\t\tallSuites,\n\t\t&UpgradeSuite{specGen: upgradePreviousToStable, track: 0},\n\t\t&UpgradeSuite{specGen: upgradeStableToCurrent, track: 1},\n\t\t&UpgradeSuite{specGen: upgradeCurrentToCurrent, track: 2},\n\t\t&UpgradeSuite{specGen: upgradeCurrentToCurrentBios, track: 0},\n\t\t&UpgradeSuite{specGen: upgradeStableToCurrentPreserveStage, track: 1},\n\t\t&UpgradeSuite{specGen: upgradeCurrentToCurrentNewCmdline, track: 2},\n\t\t&UpgradeSuite{specGen: upgradeCurrentToCurrentEnforcing, track: 1},\n\t)\n}\n"
  },
  {
    "path": "internal/integration/version_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build integration\n\n// Package integration_test contains core runners for integration tests\npackage integration_test\n\nimport (\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/integration/base\"\n)\n\n// VersionSuite.\ntype VersionSuite struct {\n\tsuite.Suite\n\tbase.TalosSuite\n}\n\nfunc (suite *VersionSuite) SuiteName() string {\n\treturn \"VersionSuite\"\n}\n\nfunc (suite *VersionSuite) TestExpectedVersion() {\n\tconst versionRegex = `v([0-9]+)\\.([0-9]+)\\.([0-9]+)(-[0-9]+-[a-z]+\\.[0-9]+)?(-.g[a-f0-9]+)?(-dirty)?`\n\n\tsuite.Assert().Regexp(versionRegex, suite.Version)\n}\n\nfunc init() {\n\tallSuites = append(allSuites, new(VersionSuite))\n}\n"
  },
  {
    "path": "internal/pkg/capability/capability.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package capability provides utility functions to work with capabilities.\npackage capability\n\nimport (\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"kernel.org/pub/linux/libs/security/libcap/cap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// AllCapabilitiesSet returns the set of all available capabilities.\n//\n// Returned capabilities are in UPPERCASE.\nfunc AllCapabilitiesSet() map[string]struct{} {\n\tcapabilities := make(map[string]struct{})\n\n\tfor v := cap.Value(0); v < cap.MaxBits(); v++ {\n\t\tif set, _ := cap.GetBound(v); set { //nolint:errcheck\n\t\t\tcapabilities[strings.ToUpper(v.String())] = struct{}{}\n\t\t}\n\t}\n\n\treturn capabilities\n}\n\n// AllCapabilitiesSetLowercase returns the set of all available capabilities.\n//\n// Returned capabilities are in lowercase.\nfunc AllCapabilitiesSetLowercase() map[string]struct{} {\n\treturn maps.Map(AllCapabilitiesSet(),\n\t\tfunc(capability string, _ struct{}) (string, struct{}) {\n\t\t\treturn strings.ToLower(capability), struct{}{}\n\t\t})\n}\n\n// AllGrantableCapabilities returns list of capabilities that can be granted to the container based on\n// process bounding capabilities.\n//\n// Returned capabilities are in UPPERCASE.\nfunc AllGrantableCapabilities() []string {\n\tallCapabilities := AllCapabilitiesSet()\n\n\tfor dropped := range constants.DefaultDroppedCapabilities {\n\t\tdelete(allCapabilities, strings.ToUpper(dropped))\n\t}\n\n\treturn maps.Keys(allCapabilities)\n}\n"
  },
  {
    "path": "internal/pkg/cgroup/cgroup.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cgroup provides cgroup utilities to handle nested cgroups.\n//\n// When Talos runs in a container, it might either share or not share the host cgroup namespace.\n// If the cgroup namespace is not shared, PID 1 will appear in cgroup '/', otherwise it will be\n// part of some pre-existing cgroup hierarchy.\n//\n// When Talos is running in a non-container mode, it is always at the root of the cgroup hierarchy.\n//\n// This package provides a transparent way to handle nested cgroups by providing a Path() function\n// which returns the correct cgroup path based on the cgroup hierarchy available.\npackage cgroup\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-debug\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containermode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// CommonCgroup interface presents a cgroup manager, be it v1 or v2\n// It can be further extended once new methods are required.\ntype CommonCgroup interface {\n\tDelete() error\n}\n\nvar root = \"/\"\n\n// InitRoot initializes the root cgroup path.\n//\n// This function should be called once at the beginning of the program, after the cgroup\n// filesystem is mounted.\n//\n// This function only supports cgroupv2 nesting.\nfunc InitRoot() error {\n\tif cgroups.Mode() != cgroups.Unified {\n\t\treturn nil\n\t}\n\n\tvar err error\n\n\troot, err = cgroup2.NestedGroupPath(\"/\")\n\n\treturn err\n}\n\n// Root returns the root cgroup path.\nfunc Root() string {\n\treturn root\n}\n\n// Path returns the path to the\n//\n// This function handles the case when the cgroups are nested.\nfunc Path(cgroupPath string) string {\n\tif cgroups.Mode() != cgroups.Unified {\n\t\treturn cgroupPath\n\t}\n\n\treturn filepath.Join(root, cgroupPath)\n}\n\nfunc zeroIfRace[T any](v T) T {\n\tif debug.RaceEnabled {\n\t\tvar zeroT T\n\n\t\treturn zeroT\n\t}\n\n\treturn v\n}\n\n//nolint:gocyclo\nfunc getCgroupV2Resources(name string) *cgroup2.Resources {\n\tswitch name {\n\tcase constants.CgroupInit:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupInitReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupInitReservedMemory * 2)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupInitMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupSystem:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin: new(int64(constants.CgroupSystemReservedMemory)),\n\t\t\t\tLow: new(int64(constants.CgroupSystemReservedMemory * 2)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupSystemMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupSystemDebug:\n\t\treturn &cgroup2.Resources{} // no limits for debug cgroup\n\tcase constants.CgroupSystemRuntime:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupSystemRuntimeReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupSystemRuntimeReservedMemory * 2)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupSystemRuntimeMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupUdevd:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupUdevdReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupUdevdReservedMemory * 2)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupUdevdMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupPodRuntimeRoot:\n\t\treturn &cgroup2.Resources{\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupPodRuntimeRootMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupPodRuntime:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupPodRuntimeReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupPodRuntimeReservedMemory * 2)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupPodRuntimeMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupKubelet:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupKubeletReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupKubeletReservedMemory * 2)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupKubeletMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupEtcd:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tLow:  new(int64(constants.CgroupEtcdReservedMemory)),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupEtcdMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupDashboard:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMax: zeroIfRace(new(int64(constants.CgroupDashboardMaxMemory))),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupDashboardMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupApid:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupApidReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupApidReservedMemory * 2)),\n\t\t\t\tMax:  zeroIfRace(new(int64(constants.CgroupApidMaxMemory))),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupApidMillicores))),\n\t\t\t},\n\t\t}\n\tcase constants.CgroupTrustd:\n\t\treturn &cgroup2.Resources{\n\t\t\tMemory: &cgroup2.Memory{\n\t\t\t\tMin:  new(int64(constants.CgroupTrustdReservedMemory)),\n\t\t\t\tLow:  new(int64(constants.CgroupTrustdReservedMemory * 2)),\n\t\t\t\tMax:  zeroIfRace(new(int64(constants.CgroupTrustdMaxMemory))),\n\t\t\t\tSwap: new(int64(0)),\n\t\t\t},\n\t\t\tCPU: &cgroup2.CPU{\n\t\t\t\tWeight: new(MillicoresToCPUWeight(MilliCores(constants.CgroupTrustdMillicores))),\n\t\t\t},\n\t\t}\n\t}\n\n\treturn &cgroup2.Resources{}\n}\n\n// CreateCgroup creates a cgroup, with resources limits if configured and supported.\nfunc CreateCgroup(name string) (CommonCgroup, error) {\n\tresources := getCgroupV2Resources(name)\n\n\tif containermode.InContainer() {\n\t\t// don't attempt to set resources in container mode, as they might conflict with the parent cgroup tree\n\t\tresources = &cgroup2.Resources{}\n\t}\n\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tcg, err := cgroup2.NewManager(constants.CgroupMountPath, Path(name), resources)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create cgroup: %w\", err)\n\t\t}\n\n\t\tif name == constants.CgroupInit {\n\t\t\tif err := cg.AddProc(uint64(os.Getpid())); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to move init process to cgroup: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn cg, nil\n\t}\n\n\tcg, err := cgroup1.New(cgroup1.StaticPath(name), &specs.LinuxResources{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create cgroup: %w\", err)\n\t}\n\n\tif name == constants.CgroupInit {\n\t\tif err := cg.Add(cgroup1.Process{\n\t\t\tPid: os.Getpid(),\n\t\t}); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to move init process to cgroup: %w\", err)\n\t\t}\n\t}\n\n\treturn cg, nil\n}\n"
  },
  {
    "path": "internal/pkg/cgroup/cpu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroup\n\nimport (\n\t\"runtime\"\n\t\"sync\"\n\n\t\"github.com/google/cadvisor/utils/sysfs\"\n\t\"github.com/google/cadvisor/utils/sysinfo\"\n)\n\nvar availableCPUCores = sync.OnceValue(func() int {\n\t_, cores, err := sysinfo.GetNodesInfo(sysfs.NewRealSysFs())\n\tif err != nil || cores < 1 {\n\t\treturn runtime.NumCPU()\n\t}\n\n\treturn cores\n})\n\n// MilliCores represents a CPU value in milli-cores.\ntype MilliCores uint\n\n// AvailableMilliCores returns the number of available CPU cores in milli-cores.\nfunc AvailableMilliCores() MilliCores {\n\treturn MilliCores(availableCPUCores()) * 1000\n}\n\n// CPUShare represents a CPU share value.\ntype CPUShare uint64\n\n// MilliCoresToShares converts milli-cores to CPU shares.\nfunc MilliCoresToShares(milliCores MilliCores) CPUShare {\n\treturn CPUShare(milliCores) * 1024 / 1000\n}\n\n// SharesToCPUWeight converts CPU shares to CPU weight.\nfunc SharesToCPUWeight(shares CPUShare) uint64 {\n\treturn uint64((((shares - 2) * 9999) / 262142) + 1)\n}\n\n// MillicoresToCPUWeight converts milli-cores to CPU weight.\n//\n// It limits millicores to available CPU cores.\nfunc MillicoresToCPUWeight(requested MilliCores) uint64 {\n\trequested = min(requested, AvailableMilliCores())\n\n\treturn SharesToCPUWeight(MilliCoresToShares(requested))\n}\n"
  },
  {
    "path": "internal/pkg/cgroup/cpu_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroup_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/cgroup\"\n)\n\nfunc TestAvailableMillicores(t *testing.T) {\n\tt.Logf(\"Available CPU milli-cores: %d\", cgroup.AvailableMilliCores())\n\n\tassert.GreaterOrEqual(t, cgroup.AvailableMilliCores(), cgroup.MilliCores(1000))\n}\n\nfunc TestMillicoresToShares(t *testing.T) {\n\tassert.Equal(t, cgroup.CPUShare(102), cgroup.MilliCoresToShares(100))\n\tassert.Equal(t, cgroup.CPUShare(1024), cgroup.MilliCoresToShares(1000))\n\tassert.Equal(t, cgroup.CPUShare(2560), cgroup.MilliCoresToShares(2500))\n}\n\nfunc TestSharesToCPUWeight(t *testing.T) {\n\tassert.Equal(t, uint64(4), cgroup.SharesToCPUWeight(102))\n\tassert.Equal(t, uint64(79), cgroup.SharesToCPUWeight(2048))\n\tassert.Equal(t, uint64(313), cgroup.SharesToCPUWeight(8192))\n}\n\nfunc TestMillicoresToCPUWeight(t *testing.T) {\n\t// depends on number of CPUs available, but for < 1000 millicores it should be same result\n\tassert.Equal(t, uint64(4), cgroup.MillicoresToCPUWeight(100))\n\tassert.Equal(t, uint64(20), cgroup.MillicoresToCPUWeight(500))\n\tassert.Equal(t, uint64(39), cgroup.MillicoresToCPUWeight(1000))\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/cgroups.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cgroups provides functions to parse cgroup information.\npackage cgroups\n\nimport (\n\t\"io\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n)\n\n// Tree represents a cgroup tree.\ntype Tree struct {\n\tRoot *Node\n}\n\n// Find the node by directory path.\nfunc (t *Tree) Find(directoryPath string) *Node {\n\tnode := t.Root\n\n\tfor component := range strings.SplitSeq(directoryPath, \"/\") {\n\t\tif component == \".\" || component == \"\" {\n\t\t\treturn node\n\t\t}\n\n\t\tif node.Children == nil {\n\t\t\tnode.Children = make(map[string]*Node)\n\t\t}\n\n\t\tchild, ok := node.Children[component]\n\t\tif !ok {\n\t\t\tchild = &Node{}\n\t\t\tnode.Children[component] = child\n\t\t}\n\n\t\tnode = child\n\t}\n\n\treturn node\n}\n\n// ResolveNames resolves the names of the node and its children.\nfunc (t *Tree) ResolveNames(nameMap map[string]string) {\n\tt.Root.ResolveNames(nameMap)\n}\n\n// Walk the tree.\nfunc (t *Tree) Walk(fn func(*Node)) {\n\tt.Root.Walk(fn)\n}\n\n// SortedChildren returns the sorted children of the node.\nfunc (n *Node) SortedChildren() []string {\n\tchildren := maps.Keys(n.Children)\n\n\tslices.Sort(children)\n\n\treturn children\n}\n\n// ResolveNames resolves the names of the node and its children.\nfunc (n *Node) ResolveNames(nameMap map[string]string) {\n\tfor name, child := range n.Children {\n\t\tif resolvedName, ok := nameMap[name]; ok {\n\t\t\tdelete(n.Children, name)\n\t\t\tn.Children[resolvedName] = child\n\t\t}\n\n\t\tchild.ResolveNames(nameMap)\n\t}\n}\n\n// Walk the node.\nfunc (n *Node) Walk(fn func(*Node)) {\n\tfn(n)\n\n\tfor _, child := range n.Children {\n\t\tchild.Walk(fn)\n\t}\n}\n\n// Node represents a cgroup node.\ntype Node struct {\n\tChildren map[string]*Node\n\n\tCgroupEvents  FlatMap\n\tCgroupFreeze  Value\n\tCgroupProcs   Values\n\tCgroupStat    FlatMap\n\tCgroupThreads Values\n\n\t// Resolved externally into process names.\n\tCgroupProcsResolved []RawValue\n\n\tCPUIdle       Value\n\tCPUMax        Values\n\tCPUMaxBurst   Value\n\tCPUPressure   NestedKeyed\n\tCPUStat       FlatMap\n\tCPUStatLocal  FlatMap\n\tCPUWeight     Value\n\tCPUWeightNice Value\n\n\tCPUSetCPUs          RawValue\n\tCPUSetCPUsEffective RawValue\n\tCPUSetMems          RawValue\n\tCPUSetMemsEffective RawValue\n\n\tIOBFQWeight FlatMap\n\tIOMax       NestedKeyed\n\tIOPressure  NestedKeyed\n\tIOStat      NestedKeyed\n\n\tMemoryCurrent     Value\n\tMemoryEvents      FlatMap\n\tMemoryEventsLocal FlatMap\n\tMemoryHigh        Value\n\tMemoryLow         Value\n\tMemoryMax         Value\n\tMemoryMin         Value\n\tMemoryNUMAStat    NestedKeyed\n\tMemoryOOMGroup    Value\n\tMemoryPeak        Value\n\tMemoryPressure    NestedKeyed\n\tMemoryStat        FlatMap\n\n\tMemorySwapCurrent Value\n\tMemorySwapEvents  FlatMap\n\tMemorySwapHigh    Value\n\tMemorySwapMax     Value\n\tMemorySwapPeak    Value\n\n\tMemoryZswapCurrent   Value\n\tMemoryZswapMax       Value\n\tMemoryZswapWriteback Value\n\n\tPidsCurrent Value\n\tPidsEvents  FlatMap\n\tPidsMax     Value\n\tPidsPeak    Value\n}\n\nfunc parseSingleValue(parser func(r io.Reader) (Values, error), out *Value, r io.Reader) error {\n\tvalues, err := parser(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(values) > 0 {\n\t\t*out = values[0]\n\t}\n\n\treturn nil\n}\n\n// Parse the cgroup information by filename from the reader.\n//\n//nolint:gocyclo,cyclop\nfunc (n *Node) Parse(filename string, r io.Reader) error {\n\tvar err error\n\n\tswitch filename {\n\tcase \"cgroup.events\":\n\t\tn.CgroupEvents, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"cgroup.freeze\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.CgroupFreeze, r)\n\tcase \"cgroup.procs\":\n\t\tn.CgroupProcs, err = ParseNewlineSeparatedValues(r)\n\n\t\treturn err\n\tcase \"cgroup.stat\":\n\t\tn.CgroupStat, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"cgroup.threads\":\n\t\tn.CgroupThreads, err = ParseNewlineSeparatedValues(r)\n\n\t\treturn err\n\tcase \"cpu.idle\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.CPUIdle, r)\n\tcase \"cpu.max\":\n\t\tn.CPUMax, err = ParseSpaceSeparatedValues(r)\n\n\t\treturn err\n\tcase \"cpu.max.burst\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.CPUMaxBurst, r)\n\tcase \"cpu.pressure\":\n\t\tn.CPUPressure, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"cpu.stat\":\n\t\tn.CPUStat, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"cpu.stat.local\":\n\t\tn.CPUStatLocal, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"cpu.weight\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.CPUWeight, r)\n\tcase \"cpu.weight.nice\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.CPUWeightNice, r)\n\tcase \"cpuset.cpus\":\n\t\tn.CPUSetCPUs, err = ParseRawValue(r)\n\n\t\treturn err\n\tcase \"cpuset.cpus.effective\":\n\t\tn.CPUSetCPUsEffective, err = ParseRawValue(r)\n\n\t\treturn err\n\tcase \"cpuset.mems\":\n\t\tn.CPUSetMems, err = ParseRawValue(r)\n\n\t\treturn err\n\tcase \"cpuset.mems.effective\":\n\t\tn.CPUSetMemsEffective, err = ParseRawValue(r)\n\n\t\treturn err\n\tcase \"io.bfq.weight\":\n\t\tn.IOBFQWeight, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"io.max\":\n\t\tn.IOMax, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"io.pressure\":\n\t\tn.IOPressure, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"io.stat\":\n\t\tn.IOStat, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"memory.current\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryCurrent, r)\n\tcase \"memory.events\":\n\t\tn.MemoryEvents, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"memory.events.local\":\n\t\tn.MemoryEventsLocal, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"memory.high\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryHigh, r)\n\tcase \"memory.low\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryLow, r)\n\tcase \"memory.max\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryMax, r)\n\tcase \"memory.min\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryMin, r)\n\tcase \"memory.numa_stat\":\n\t\tn.MemoryNUMAStat, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"memory.oom.group\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryOOMGroup, r)\n\tcase \"memory.peak\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryPeak, r)\n\tcase \"memory.pressure\":\n\t\tn.MemoryPressure, err = ParseNestedKeyedValues(r)\n\n\t\treturn err\n\tcase \"memory.stat\":\n\t\tn.MemoryStat, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"memory.swap.current\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemorySwapCurrent, r)\n\tcase \"memory.swap.events\":\n\t\tn.MemorySwapEvents, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"memory.swap.high\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemorySwapHigh, r)\n\tcase \"memory.swap.max\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemorySwapMax, r)\n\tcase \"memory.swap.peak\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemorySwapPeak, r)\n\tcase \"memory.zswap.current\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryZswapCurrent, r)\n\tcase \"memory.zswap.max\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryZswapMax, r)\n\tcase \"memory.zswap.writeback\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.MemoryZswapWriteback, r)\n\tcase \"pids.current\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.PidsCurrent, r)\n\tcase \"pids.events\":\n\t\tn.PidsEvents, err = ParseFlatMapValues(r)\n\n\t\treturn err\n\tcase \"pids.max\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.PidsMax, r)\n\tcase \"pids.peak\":\n\t\treturn parseSingleValue(ParseNewlineSeparatedValues, &n.PidsPeak, r)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/raw.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups\n\nimport (\n\t\"bufio\"\n\t\"io\"\n)\n\n// RawValue is a raw cgroup value (without any parsing).\ntype RawValue string\n\n// ParseRawValue parses the raw cgroup value.\nfunc ParseRawValue(r io.Reader) (RawValue, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tif !scanner.Scan() {\n\t\treturn RawValue(\"\"), nil\n\t}\n\n\tline := scanner.Text()\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn RawValue(\"\"), err\n\t}\n\n\treturn RawValue(line), nil\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/reader.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// ReadCgroupfsProperty reads a property from cgroupfs into an existing Node.\nfunc ReadCgroupfsProperty(node *Node, cgroupPath, property string) error {\n\tf, err := os.OpenFile(filepath.Join(cgroupPath, property), os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening cgroupfs file %w\", err)\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\terr = node.Parse(property, f)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing cgroupfs file %w\", err)\n\t}\n\n\treturn nil\n}\n\n// GetCgroupProperty reads a property from cgroupfs into a new Node.\nfunc GetCgroupProperty(cgroupPath, property string) (*Node, error) {\n\tnode := Node{}\n\terr := ReadCgroupfsProperty(&node, cgroupPath, property)\n\n\treturn &node, err\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/tar.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups\n\nimport (\n\t\"archive/tar\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n)\n\n// TreeFromTarGz builds a crgroup tree from the tar.gz reader.\n//\n// It is assumed to work with output of `talosctl cp /sys/fs/cgroup -`.\nfunc TreeFromTarGz(r io.Reader) (*Tree, error) {\n\tgzReader, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer gzReader.Close() //nolint:errcheck\n\n\ttarReader := tar.NewReader(gzReader)\n\n\ttree := &Tree{\n\t\tRoot: &Node{},\n\t}\n\n\tfor {\n\t\theader, err := tarReader.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif header.Typeflag != tar.TypeReg {\n\t\t\tcontinue\n\t\t}\n\n\t\tdirectory, filename := filepath.Split(header.Name)\n\n\t\tnode := tree.Find(directory)\n\n\t\tif err = node.Parse(filename, tarReader); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse %q: %w\", header.Name, err)\n\t\t}\n\t}\n\n\treturn tree, nil\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/tar_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n)\n\nfunc TestTreeFromTarGz(t *testing.T) {\n\tt.Parallel()\n\n\ttarFile, err := os.Open(\"testdata/cgroup.tar.gz\")\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, tarFile.Close())\n\t})\n\n\ttree, err := cgroups.TreeFromTarGz(tarFile)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, []string{\"init\", \"kubepods\", \"podruntime\", \"system\"}, tree.Root.SortedChildren())\n\tassert.Equal(t, \"114712576\", tree.Find(\"init\").MemoryCurrent.String())\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/value.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"io\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n)\n\n// Value represents a cgroup value.\n//\n// Value might represent 'max' value.\ntype Value struct {\n\tVal   int64\n\tFrac  int\n\tIsMax bool\n\tIsSet bool\n}\n\n// String returns the string representation of the cgroup value.\nfunc (v Value) String() string {\n\tswitch {\n\tcase !v.IsSet:\n\t\treturn \"unset\"\n\tcase v.IsMax:\n\t\treturn \"max\"\n\tdefault:\n\t\ts := strconv.FormatInt(v.Val, 10)\n\n\t\tif v.Frac == 0 {\n\t\t\treturn s\n\t\t}\n\n\t\tif len(s) < v.Frac+1 {\n\t\t\ts = strings.Repeat(\"0\", (v.Frac+1)-len(s)) + s\n\t\t}\n\n\t\treturn s[:len(s)-v.Frac] + \".\" + s[len(s)-v.Frac:]\n\t}\n}\n\n// HumanizeIBytes returns the humanized bytes representation of the cgroup value.\nfunc (v Value) HumanizeIBytes() string {\n\tif !v.IsSet || v.IsMax || v.Frac > 0 {\n\t\treturn v.String()\n\t}\n\n\treturn humanize.IBytes(uint64(v.Val))\n}\n\n// DivideBy returns the value divided by another value in percentage.\n//\n// a.DivideBy(b) = a / b * 100.\nfunc (v Value) DivideBy(other Value) Value {\n\tswitch {\n\tcase !v.IsSet || !other.IsSet:\n\t\t// if either value is unset, return unset\n\t\treturn Value{}\n\tcase other.IsMax && !v.IsMax:\n\t\t// if other is max and v is not, return 0.00%\n\t\treturn Value{IsSet: true, Frac: 2}\n\tcase v.IsMax && other.IsMax:\n\t\t// if both are max, return 100.00%\n\t\treturn Value{Val: 10000, IsSet: true, Frac: 2}\n\tcase other.Val == 0 || v.IsMax:\n\t\t// if other is 0, return max\n\t\treturn Value{IsMax: true, IsSet: true}\n\tdefault:\n\t\treturn Value{Val: int64(math.Round(float64(v.Val) / float64(other.Val) * 100 * 100)), IsSet: true, Frac: 2}\n\t}\n}\n\n// Float64 returns the float64 representation of the cgroup value.\nfunc (v Value) Float64() float64 {\n\tswitch {\n\tcase !v.IsSet:\n\t\treturn math.NaN()\n\tcase v.IsMax:\n\t\treturn math.Inf(1)\n\tcase v.Frac == 0:\n\t\treturn float64(v.Val)\n\tdefault:\n\t\treturn float64(v.Val) / math.Pow10(v.Frac)\n\t}\n}\n\n// UsecToDuration returns the duration representation of the cgroup value in microseconds.\nfunc (v Value) UsecToDuration() string {\n\tif !v.IsSet || v.IsMax {\n\t\treturn v.String()\n\t}\n\n\treturn (time.Duration(v.Val) * time.Microsecond).String()\n}\n\n// Values represents a list of cgroup values.\ntype Values []Value\n\n// FlatMap returns the flat map of the cgroup values.\ntype FlatMap map[string]Value\n\n// NestedKeyed returns the nested keyed map of the cgroup values.\ntype NestedKeyed map[string]FlatMap\n\n// ParseValue parses the cgroup value from the string.\nfunc ParseValue(s string) (Value, error) {\n\tif s == \"max\" {\n\t\treturn Value{IsMax: true, IsSet: true}, nil\n\t}\n\n\tvar frac int\n\n\tl, r, ok := strings.Cut(s, \".\")\n\tif ok {\n\t\tfrac = len(r)\n\n\t\ts = l + r\n\t}\n\n\tval, err := strconv.ParseInt(s, 10, 64)\n\tif err != nil {\n\t\treturn Value{}, err\n\t}\n\n\treturn Value{Val: val, Frac: frac, IsSet: true}, nil\n}\n\n// ParseNewlineSeparatedValues parses the cgroup values from the newline separated string.\n//\n// New-line separated values\n// (when only one value can be written at once)\n//\n// VAL0\\n\n// VAL1\\n\n// ...\nfunc ParseNewlineSeparatedValues(r io.Reader) (Values, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tvar values Values\n\n\tfor scanner.Scan() {\n\t\tval, err := ParseValue(scanner.Text())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvalues = append(values, val)\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn values, nil\n}\n\n// ParseSpaceSeparatedValues parses the cgroup values from the space separated string.\n//\n// Space separated values\n// (when read-only or multiple values can be written at once)\n//\n// VAL0 VAL1 ...\\n.\nfunc ParseSpaceSeparatedValues(r io.Reader) (Values, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tif !scanner.Scan() {\n\t\treturn nil, nil\n\t}\n\n\tline := scanner.Text()\n\tparts := strings.Fields(line)\n\n\tvalues := make(Values, 0, len(parts))\n\n\tfor _, s := range parts {\n\t\tval, err := ParseValue(s)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvalues = append(values, val)\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn values, nil\n}\n\n// ParseFlatMapValues parses the cgroup values from the flat map.\n//\n// Flat keyed:\n//\n// KEY0 VAL0\\n\n// KEY1 VAL1\\n\n// ...\nfunc ParseFlatMapValues(r io.Reader) (FlatMap, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tflatMap := FlatMap{}\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tkey, value, ok := strings.Cut(line, \" \")\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"invalid format\")\n\t\t}\n\n\t\tval, err := ParseValue(value)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tflatMap[key] = val\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn flatMap, nil\n}\n\n// ParseNestedKeyedValues parses the cgroup values from the nested keyed map.\n//\n// Nested keyed:\n//\n// KEY0 SUB_KEY0=VAL00 SUB_KEY1=VAL01...\n// KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11...\n// ...\nfunc ParseNestedKeyedValues(r io.Reader) (NestedKeyed, error) {\n\tscanner := bufio.NewScanner(r)\n\n\tnestedKeyed := NestedKeyed{}\n\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tkey, values, ok := strings.Cut(line, \" \")\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"invalid format\")\n\t\t}\n\n\t\tflatMap := FlatMap{}\n\n\t\tfor pair := range strings.FieldsSeq(values) {\n\t\t\tsubKey, value, ok := strings.Cut(pair, \"=\")\n\t\t\tif !ok {\n\t\t\t\treturn nil, errors.New(\"invalid format\")\n\t\t\t}\n\n\t\t\tval, err := ParseValue(value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tflatMap[subKey] = val\n\t\t}\n\n\t\tnestedKeyed[key] = flatMap\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn nestedKeyed, nil\n}\n"
  },
  {
    "path": "internal/pkg/cgroups/value_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cgroups_test\n\nimport (\n\t\"math\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/cgroups\"\n)\n\nfunc TestParseValue(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tin string\n\n\t\texpected        cgroups.Value\n\t\texpectedFloat64 float64\n\t}{\n\t\t{\n\t\t\tin:              \"42\",\n\t\t\texpected:        cgroups.Value{Val: 42, IsSet: true},\n\t\t\texpectedFloat64: 42,\n\t\t},\n\t\t{\n\t\t\tin:              \"max\",\n\t\t\texpected:        cgroups.Value{IsMax: true, IsSet: true},\n\t\t\texpectedFloat64: math.Inf(1),\n\t\t},\n\t\t{\n\t\t\tin:              \"42.5\",\n\t\t\texpected:        cgroups.Value{Val: 425, Frac: 1, IsSet: true},\n\t\t\texpectedFloat64: 42.5,\n\t\t},\n\t\t{\n\t\t\tin:       \"0.00\",\n\t\t\texpected: cgroups.Value{Val: 0, Frac: 2, IsSet: true},\n\t\t},\n\t} {\n\t\tt.Run(test.in, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tv, err := cgroups.ParseValue(test.in)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, v)\n\t\t\tassert.Equal(t, test.expectedFloat64, v.Float64())\n\n\t\t\tassert.Equal(t, test.in, v.String())\n\t\t})\n\t}\n}\n\nfunc TestParseNewlineSeparatedValues(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected cgroups.Values\n\t}{\n\t\t{\n\t\t\tname:  \"one\",\n\t\t\tinput: \"42\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{Val: 42, IsSet: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"two\",\n\t\t\tinput: \"42\\n43\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{Val: 42, IsSet: true},\n\t\t\t\t{Val: 43, IsSet: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"max\",\n\t\t\tinput: \"max\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{IsMax: true, IsSet: true},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr := strings.NewReader(test.input)\n\n\t\t\tvalues, err := cgroups.ParseNewlineSeparatedValues(r)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expected, values)\n\t\t})\n\t}\n}\n\nfunc TestParseSpaceSeparatedValues(t *testing.T) { //nolint:dupl\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected cgroups.Values\n\t}{\n\t\t{\n\t\t\tname:  \"one\",\n\t\t\tinput: \"42\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{Val: 42, IsSet: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"two\",\n\t\t\tinput: \"42 43\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{Val: 42, IsSet: true},\n\t\t\t\t{Val: 43, IsSet: true},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"max\",\n\t\t\tinput: \"max\\n\",\n\t\t\texpected: cgroups.Values{\n\t\t\t\t{IsMax: true, IsSet: true},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr := strings.NewReader(test.input)\n\n\t\t\tvalues, err := cgroups.ParseSpaceSeparatedValues(r)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expected, values)\n\t\t})\n\t}\n}\n\nfunc TestParseFlatMapValues(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected cgroups.FlatMap\n\t}{\n\t\t{\n\t\t\tname:  \"values\",\n\t\t\tinput: \"anon 3000\\nfile 6000\\n\",\n\t\t\texpected: cgroups.FlatMap{\n\t\t\t\t\"anon\": {Val: 3000, IsSet: true},\n\t\t\t\t\"file\": {Val: 6000, IsSet: true},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr := strings.NewReader(test.input)\n\n\t\t\tvalues, err := cgroups.ParseFlatMapValues(r)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expected, values)\n\t\t})\n\t}\n}\n\nfunc TestParseNestedKeyedValues(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected cgroups.NestedKeyed\n\t}{\n\t\t{\n\t\t\tname:  \"values\",\n\t\t\tinput: \"anon rss=3125 vms=123\\nreal rss=1234 vms=5678\\n\",\n\t\t\texpected: cgroups.NestedKeyed{\n\t\t\t\t\"anon\": {\n\t\t\t\t\t\"rss\": {Val: 3125, IsSet: true},\n\t\t\t\t\t\"vms\": {Val: 123, IsSet: true},\n\t\t\t\t},\n\t\t\t\t\"real\": {\n\t\t\t\t\t\"rss\": {Val: 1234, IsSet: true},\n\t\t\t\t\t\"vms\": {Val: 5678, IsSet: true},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr := strings.NewReader(test.input)\n\n\t\t\tvalues, err := cgroups.ParseNestedKeyedValues(r)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expected, values)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/console/console.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package console contains console-related functionality.\npackage console\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\t// vtActivate activates the specified virtual terminal.\n\t// See VT_ACTIVATE:\n\t// https://man7.org/linux/man-pages/man2/ioctl_console.2.html\n\t// https://github.com/torvalds/linux/blob/v6.2/include/uapi/linux/vt.h#L42\n\tvtActivate uintptr = 0x5606\n\n\t// tioclSetKmsgRedirect redirects kernel messages to the specified tty.\n\t// See TIOCL_SETKMSGREDIRECT:\n\t// https://github.com/torvalds/linux/blob/v6.2/include/uapi/linux/tiocl.h#L33\n\t// https://github.com/torvalds/linux/blob/v6.2/drivers/tty/vt/vt.c#L3242\n\ttioclSetKmsgRedirect byte = 11\n)\n\n// Switch switches the active console to the specified tty.\nfunc Switch(ttyNumber int) error {\n\t// redirect the kernel logs to their own TTY instead of the currently used one,\n\t// so that other TTYs (e.g., dashboard on tty2) do not get flooded with kernel logs\n\tif err := redirectKernelLogs(constants.KernelLogsTTY); err != nil {\n\t\treturn err\n\t}\n\n\t// we need a valid fd to any tty because ioctl requires it\n\ttty0, err := os.OpenFile(\"/dev/tty0\", os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer tty0.Close() //nolint:errcheck\n\n\tif _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, tty0.Fd(), vtActivate, uintptr(ttyNumber)); errno != 0 {\n\t\treturn fmt.Errorf(\"failed to activate console: %w\", errno)\n\t}\n\n\treturn nil\n}\n\n// redirectKernelLogs redirects kernel logs to the specified tty.\nfunc redirectKernelLogs(ttyNumber int) error {\n\ttty, err := os.OpenFile(fmt.Sprintf(\"/dev/tty%d\", ttyNumber), os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\targs := [2]byte{tioclSetKmsgRedirect, byte(ttyNumber)}\n\n\tif _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, tty.Fd(), syscall.TIOCLINUX, uintptr(unsafe.Pointer(&args))); errno != 0 {\n\t\treturn fmt.Errorf(\"failed to set redirect for kmsg: %w\", errno)\n\t}\n\n\treturn tty.Close()\n}\n"
  },
  {
    "path": "internal/pkg/containermode/containermode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package containermode contains a utility function to detect if Talos is running in a container.\npackage containermode\n\nimport (\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// InContainer checks whether or not Talos is running in a container.\nfunc InContainer() bool {\n\tif _, err := os.Stat(constants.ContainerMarkerFilePath); err == nil {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "internal/pkg/containers/container.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package containers provides the container implementatiom.\npackage containers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/go-tail\"\n\n\t\"github.com/siderolabs/talos/pkg/chunker\"\n\t\"github.com/siderolabs/talos/pkg/chunker/file\"\n\t\"github.com/siderolabs/talos/pkg/chunker/stream\"\n)\n\n// Container presents information about a container.\ntype Container struct {\n\tInspector Inspector\n\n\tDisplay          string // Friendly Name\n\tName             string // container name\n\tID               string // container sha/id\n\tUID              string // container uid\n\tDigest           string // Container Digest\n\tImage            string\n\tPodName          string\n\tSandbox          string\n\tStatus           string // Running state of container\n\tRestartCount     string\n\tLogPath          string\n\tMetrics          *ContainerMetrics\n\tPid              uint32\n\tIsPodSandbox     bool // real container or just pod sandbox\n\tNetworkNamespace string\n}\n\n// ContainerMetrics represents container cgroup stats.\ntype ContainerMetrics struct {\n\tMemoryUsage uint64\n\tCPUUsage    uint64\n}\n\n// GetProcessStderr returns process stderr.\nfunc (c *Container) GetProcessStderr() (string, error) {\n\treturn c.Inspector.GetProcessStderr(c.ID)\n}\n\n// GetLogFile returns path to log file, k8s-style.\nfunc (c *Container) GetLogFile() string {\n\tif c.LogPath != \"\" {\n\t\treturn c.LogPath\n\t}\n\n\tif c.Sandbox == \"\" || !strings.Contains(c.Display, \":\") {\n\t\treturn \"\"\n\t}\n\n\treturn filepath.Join(c.Sandbox, c.Name, c.RestartCount+\".log\")\n}\n\n// Kill sends signal to container task.\nfunc (c *Container) Kill(signal syscall.Signal) error {\n\treturn c.Inspector.Kill(c.ID, c.IsPodSandbox, signal)\n}\n\n// GetLogChunker returns chunker for container log file.\nfunc (c *Container) GetLogChunker(ctx context.Context, follow bool, tailLines int) (chunker.Chunker, io.Closer, error) {\n\tlogFile := c.GetLogFile()\n\tif logFile != \"\" {\n\t\tf, err := os.OpenFile(logFile, os.O_RDONLY, 0)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif tailLines >= 0 {\n\t\t\terr = tail.SeekLines(f, tailLines)\n\t\t\tif err != nil {\n\t\t\t\tf.Close() //nolint:errcheck\n\n\t\t\t\treturn nil, nil, fmt.Errorf(\"error tailing log: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tvar chunkerOptions []file.Option\n\n\t\tif follow {\n\t\t\tchunkerOptions = append(chunkerOptions, file.WithFollow())\n\t\t}\n\n\t\treturn file.NewChunker(ctx, f, chunkerOptions...), f, nil\n\t}\n\n\tfilename, err := c.GetProcessStderr()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tif filename == \"\" {\n\t\treturn nil, nil, errors.New(\"no log available\")\n\t}\n\n\tf, err := os.OpenFile(filename, os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn stream.NewChunker(ctx, f), f, nil\n}\n"
  },
  {
    "path": "internal/pkg/containers/containerd/containerd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package containerd implements containers.Inspector via containerd API\npackage containerd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\tv1 \"github.com/containerd/cgroups/v3/cgroup1/stats\"\n\tv2 \"github.com/containerd/cgroups/v3/cgroup2/stats\"\n\ttasks \"github.com/containerd/containerd/api/services/tasks/v1\"\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/containerd/typeurl/v2\"\n\t\"github.com/hashicorp/go-multierror\"\n\n\tctrs \"github.com/siderolabs/talos/internal/pkg/containers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\ntype inspector struct {\n\tclient *containerd.Client\n\t//nolint:containedctx\n\tnsctx context.Context\n}\n\ntype inspectorOptions struct {\n\tcontainerdAddress string\n}\n\n// Option configures containerd Inspector.\ntype Option func(*inspectorOptions)\n\n// WithContainerdAddress configures containerd address to use.\nfunc WithContainerdAddress(address string) Option {\n\treturn func(o *inspectorOptions) {\n\t\to.containerdAddress = address\n\t}\n}\n\n// NewInspector builds new Inspector instance in specified namespace.\nfunc NewInspector(ctx context.Context, namespace string, options ...Option) (ctrs.Inspector, error) {\n\tvar err error\n\n\topt := inspectorOptions{\n\t\tcontainerdAddress: constants.CRIContainerdAddress,\n\t}\n\n\tfor _, o := range options {\n\t\to(&opt)\n\t}\n\n\ti := inspector{}\n\n\ti.client, err = containerd.New(opt.containerdAddress)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ti.nsctx = namespaces.WithNamespace(ctx, namespace)\n\n\treturn &i, nil\n}\n\n// Close frees associated resources.\nfunc (i *inspector) Close() error {\n\treturn i.client.Close()\n}\n\n// Images returns a hash of image digest -> name.\nfunc (i *inspector) Images() (map[string]string, error) {\n\timages, err := i.client.ListImages(i.nsctx, \"\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// create a map[sha]name for easier lookups later\n\timageList := make(map[string]string, len(images))\n\n\tfor _, image := range images {\n\t\tif strings.HasPrefix(image.Name(), \"sha256:\") {\n\t\t\tcontinue\n\t\t}\n\n\t\timageList[image.Target().Digest.String()] = image.Name()\n\t}\n\n\treturn imageList, nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *inspector) containerInfo(\n\tcntr containerd.Container,\n\timageList map[string]string,\n\tsingleLookup bool,\n) (*ctrs.Container, error) {\n\tcp := &ctrs.Container{}\n\n\tinfo, err := cntr.Info(i.nsctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting container info for %q: %w\", cntr.ID(), err)\n\t}\n\n\tspec, err := cntr.Spec(i.nsctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting container spec for %q: %w\", cntr.ID(), err)\n\t}\n\n\timg, err := cntr.Image(i.nsctx)\n\tif err != nil {\n\t\tif !errdefs.IsNotFound(err) {\n\t\t\treturn nil, fmt.Errorf(\"error getting container image for %q: %w\", cntr.ID(), err)\n\t\t}\n\t}\n\n\ttask, err := cntr.Task(i.nsctx, nil)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\t// running task not found, skip container\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error getting container task for %q: %w\", cntr.ID(), err)\n\t}\n\n\tstatus, err := task.Status(i.nsctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting task status for %q: %w\", cntr.ID(), err)\n\t}\n\n\tcp.Inspector = i\n\tcp.ID = cntr.ID()\n\tcp.Name = cntr.ID()\n\tcp.Display = cntr.ID()\n\tcp.RestartCount = \"0\"\n\n\tif img != nil {\n\t\tcp.Digest = img.Target().Digest.String()\n\t}\n\n\tcp.Image = cp.Digest\n\n\tif imageList != nil {\n\t\tif resolved, ok := imageList[cp.Image]; ok {\n\t\t\tcp.Image = resolved\n\t\t}\n\t}\n\n\tcp.Pid = task.Pid()\n\tcp.Status = strings.ToUpper(string(status.Status))\n\n\tvar (\n\t\tcname, cns string\n\t\tok         bool\n\t)\n\n\tif cname, ok = info.Labels[\"io.kubernetes.pod.name\"]; ok {\n\t\tif cns, ok = info.Labels[\"io.kubernetes.pod.namespace\"]; ok {\n\t\t\tcp.Display = path.Join(cns, cname)\n\t\t}\n\t}\n\n\tif status.Status == containerd.Running {\n\t\tmetrics, err := task.Metrics(i.nsctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error pulling metrics for %q: %w\", cntr.ID(), err)\n\t\t}\n\n\t\tanydata, err := typeurl.UnmarshalAny(metrics.Data)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error unmarshalling metrics for %q: %w\", cntr.ID(), err)\n\t\t}\n\n\t\tcp.Metrics = &ctrs.ContainerMetrics{}\n\n\t\tswitch data := anydata.(type) {\n\t\tcase *v1.Metrics:\n\t\t\tmem := data.Memory\n\t\t\tif mem != nil && mem.Usage != nil {\n\t\t\t\tif mem.TotalInactiveFile < mem.Usage.Usage {\n\t\t\t\t\tcp.Metrics.MemoryUsage = mem.Usage.Usage - mem.TotalInactiveFile\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcpu := data.CPU\n\t\t\tif cpu != nil && cpu.Usage != nil {\n\t\t\t\tcp.Metrics.CPUUsage = cpu.Usage.Total\n\t\t\t}\n\t\tcase *v2.Metrics:\n\t\t\tmem := data.Memory\n\t\t\tif mem != nil {\n\t\t\t\tcp.Metrics.MemoryUsage = mem.Usage\n\t\t\t}\n\n\t\t\tcpu := data.CPU\n\t\t\tif cpu != nil {\n\t\t\t\tcp.Metrics.CPUUsage = cpu.UsageUsec * uint64(time.Microsecond/time.Nanosecond) // convert to nsec\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"failed to convert metric data to cgroups Metrics: %T\", anydata)\n\t\t}\n\t}\n\n\t// Save off an identifier for the pod\n\t// this is typically the container name (non-k8s namespace)\n\t// or will be k8s namespace\"/\"k8s pod name\":\"container name\n\tcp.PodName = cp.Display\n\n\t// Pull restart count\n\t// TODO: this doesn't work as CRI doesn't publish this to containerd annotations\n\tif _, ok := spec.Annotations[\"io.kubernetes.container.restartCount\"]; ok {\n\t\tcp.RestartCount = spec.Annotations[\"io.kubernetes.container.restartCount\"]\n\t}\n\n\t// Typically on the 'infrastructure' container, aka k8s.gcr.io/pause\n\tif _, ok := spec.Annotations[\"io.kubernetes.cri.sandbox-log-directory\"]; ok {\n\t\tcp.Sandbox = spec.Annotations[\"io.kubernetes.cri.sandbox-log-directory\"]\n\t\tcp.IsPodSandbox = true\n\t} else if singleLookup && cns != \"\" && cname != \"\" {\n\t\t// try to find matching infrastructure container and pull sandbox from it\n\t\tquery := fmt.Sprintf(\n\t\t\t\"labels.\\\"io.kubernetes.pod.namespace\\\"==%q,labels.\\\"io.kubernetes.pod.name\\\"==%q\",\n\t\t\tcns,\n\t\t\tcname,\n\t\t)\n\n\t\tinfraContainers, err := i.client.Containers(i.nsctx, query)\n\t\tif err == nil {\n\t\t\tfor j := range infraContainers {\n\t\t\t\tif infraSpec, err := infraContainers[j].Spec(i.nsctx); err == nil {\n\t\t\t\t\tif spec.Annotations[\"io.kubernetes.sandbox-id\"] != infraSpec.Annotations[\"io.kubernetes.sandbox-id\"] {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif sandbox, found := infraSpec.Annotations[\"io.kubernetes.cri.sandbox-log-directory\"]; found {\n\t\t\t\t\t\tcp.Sandbox = sandbox\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Typically on actual application containers inside the pod/sandbox\n\tif _, ok := info.Labels[\"io.kubernetes.container.name\"]; ok {\n\t\tcp.Name = info.Labels[\"io.kubernetes.container.name\"]\n\t\tcp.Display = cp.Display + \":\" + info.Labels[\"io.kubernetes.container.name\"]\n\t}\n\n\treturn cp, nil\n}\n\n// Container returns info about a single container.\n//\n// If container is not found, Container returns nil\n//\n//nolint:gocyclo\nfunc (i *inspector) Container(id string) (*ctrs.Container, error) {\n\tvar (\n\t\tquery           string\n\t\tskipWithK8sName bool\n\t)\n\n\t// if id looks like k8s one, ns/pod:container, parse it and build query\n\tslashIdx := strings.Index(id, \"/\") //nolint:modernize\n\tif slashIdx > 0 {\n\t\tname := \"\"\n\t\tnamespace, pod := id[:slashIdx], id[slashIdx+1:]\n\n\t\tsemicolonIdx := strings.LastIndex(pod, \":\")\n\t\tif semicolonIdx > 0 {\n\t\t\tname = pod[semicolonIdx+1:]\n\t\t\tpod = pod[:semicolonIdx]\n\t\t}\n\n\t\tquery = fmt.Sprintf(\n\t\t\t\"labels.\\\"io.kubernetes.pod.namespace\\\"==%q,labels.\\\"io.kubernetes.pod.name\\\"==%q\",\n\t\t\tnamespace,\n\t\t\tpod,\n\t\t)\n\n\t\tif name != \"\" {\n\t\t\tquery += fmt.Sprintf(\",labels.\\\"io.kubernetes.container.name\\\"==%q\", name)\n\t\t} else {\n\t\t\tskipWithK8sName = true\n\t\t}\n\t} else {\n\t\tquery = fmt.Sprintf(\"id==%q\", id)\n\t}\n\n\tcontainers, err := i.client.Containers(i.nsctx, query)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(containers) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tvar cntr *ctrs.Container\n\n\tfor j := range containers {\n\t\tif skipWithK8sName {\n\t\t\tvar labels map[string]string\n\n\t\t\tif labels, err = containers[j].Labels(i.nsctx); err == nil {\n\t\t\t\tif _, found := labels[\"io.kubernetes.container.name\"]; found {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcntr, err = i.containerInfo(containers[j], nil, true)\n\t\tif err == nil && cntr != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn cntr, err\n}\n\n// Pods collects information about running pods & containers.\n//\n//nolint:gocyclo\nfunc (i *inspector) Pods() ([]*ctrs.Pod, error) {\n\timageList, err := i.Images()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcontainers, err := i.client.Containers(i.nsctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar (\n\t\tmultiErr *multierror.Error\n\t\tpods     []*ctrs.Pod\n\t)\n\n\tfor _, cntr := range containers {\n\t\tcp, err := i.containerInfo(cntr, imageList, false)\n\t\tif err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif cp == nil {\n\t\t\t// not running container\n\t\t\tcontinue\n\t\t}\n\n\t\t// Figure out if we need to create a new pod or append\n\t\t// to an existing pod\n\t\t// Also set pod sandbox ID if defined\n\t\tfound := false\n\n\t\tfor _, pod := range pods {\n\t\t\tif pod.Name != cp.PodName {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif cp.Sandbox != \"\" {\n\t\t\t\tpod.Sandbox = cp.Sandbox\n\t\t\t}\n\n\t\t\tpod.Containers = append(pod.Containers, cp)\n\t\t\tfound = true\n\n\t\t\tbreak\n\t\t}\n\n\t\tif !found {\n\t\t\tp := &ctrs.Pod{\n\t\t\t\tName:       cp.PodName,\n\t\t\t\tContainers: []*ctrs.Container{cp},\n\t\t\t\tSandbox:    cp.Sandbox,\n\t\t\t}\n\t\t\tpods = append(pods, p)\n\t\t}\n\t}\n\n\t// This seems janky because it is\n\t// But we need to loop through everything again to associate\n\t// the sandbox with the container name so we can get a proper\n\t// filepath to the location of the logfile\n\tfor _, contents := range pods {\n\t\tfor _, cntr := range contents.Containers {\n\t\t\tif cntr.Sandbox == \"\" && contents.Sandbox != \"\" {\n\t\t\t\tcntr.Sandbox = contents.Sandbox\n\t\t\t}\n\t\t}\n\t}\n\n\treturn pods, multiErr.ErrorOrNil()\n}\n\n// GetProcessStderr returns process stderr.\nfunc (i *inspector) GetProcessStderr(id string) (string, error) {\n\ttask, err := i.client.TaskService().Get(i.nsctx, &tasks.GetRequest{ContainerID: id})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn task.Process.Stderr, nil\n}\n\n// Kill sends signal to container task.\nfunc (i *inspector) Kill(id string, isPodSandbox bool, signal syscall.Signal) error {\n\t_, err := i.client.TaskService().Kill(i.nsctx, &tasks.KillRequest{ContainerID: id, Signal: uint32(signal)})\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/pkg/containers/containerd/containerd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd_test\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/google/uuid\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\tcontainerdrunner \"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\tctrd \"github.com/siderolabs/talos/internal/pkg/containers/containerd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tbusyboxImage       = \"docker.io/library/busybox:1.30.1\"\n\tbusyboxImageDigest = \"sha256:4b6ad3a68d34da29bf7c8ccb5d355ba8b4babcad1f99798204e7abb43e54ee3d\"\n)\n\nfunc MockEventSink(state events.ServiceState, message string, args ...any) {\n}\n\n//nolint:maligned\ntype ContainerdSuite struct {\n\tsuite.Suite\n\n\ttmpDir string\n\n\tloggingManager runtime.LoggingManager\n\n\tcontainerdNamespace string\n\tcontainerdRunner    runner.Runner\n\tcontainerdWg        sync.WaitGroup\n\tcontainerdAddress   string\n\n\tcontainerID string\n\n\tclient *containerd.Client\n\timage  containerd.Image\n\n\tcontainerRunners []runner.Runner\n\tcontainersWg     sync.WaitGroup\n}\n\nfunc (suite *ContainerdSuite) SetupSuite() {\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tsuite.T().Skip(\"test doesn't pass under cgroupsv2\")\n\t}\n\n\tvar err error\n\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tsuite.loggingManager = logging.NewFileLoggingManager(suite.tmpDir)\n\n\tstateDir, rootDir := filepath.Join(suite.tmpDir, \"state\"), filepath.Join(suite.tmpDir, \"root\")\n\tsuite.Require().NoError(os.Mkdir(stateDir, 0o777))\n\tsuite.Require().NoError(os.Mkdir(rootDir, 0o777))\n\n\tsuite.containerdAddress = filepath.Join(suite.tmpDir, \"run.sock\")\n\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tvar (\n\t\t\tgroupPath string\n\t\t\tmanager   *cgroup2.Manager\n\t\t)\n\n\t\tgroupPath, err = cgroup2.NestedGroupPath(suite.tmpDir)\n\t\tsuite.Require().NoError(err)\n\n\t\tmanager, err = cgroup2.NewManager(constants.CgroupMountPath, groupPath, &cgroup2.Resources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t} else {\n\t\tvar manager cgroup1.Cgroup\n\n\t\tmanager, err = cgroup1.New(cgroup1.NestedPath(suite.tmpDir), &specs.LinuxResources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t}\n\n\targs := &runner.Args{\n\t\tID: \"containerd\",\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\", suite.containerdAddress,\n\t\t\t\"--state\", stateDir,\n\t\t\t\"--root\", rootDir,\n\t\t\t\"--config\", constants.CRIContainerdConfig,\n\t\t},\n\t}\n\n\tsuite.containerdRunner = process.NewRunner(\n\t\tfalse,\n\t\targs,\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithEnv([]string{constants.EnvPathWithBin}),\n\t\trunner.WithCgroupPath(suite.tmpDir),\n\t)\n\tsuite.Require().NoError(suite.containerdRunner.Open())\n\n\tsuite.containerdWg.Go(func() {\n\t\tdefer suite.containerdRunner.Close() //nolint:errcheck\n\n\t\tsuite.containerdRunner.Run(MockEventSink) //nolint:errcheck\n\t})\n\n\tsuite.client, err = containerd.New(suite.containerdAddress)\n\tsuite.Require().NoError(err)\n\n\tnamespace := ([16]byte)(uuid.New())\n\tsuite.containerdNamespace = \"talos\" + hex.EncodeToString(namespace[:])\n\n\tctx := namespaces.WithNamespace(context.Background(), suite.containerdNamespace)\n\n\tsuite.image, err = suite.client.Pull(ctx, busyboxImage, containerd.WithPullUnpack)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *ContainerdSuite) TearDownSuite() {\n\tsuite.Require().NoError(suite.client.Close())\n\n\tsuite.Require().NoError(suite.containerdRunner.Stop())\n\tsuite.containerdWg.Wait()\n}\n\nfunc (suite *ContainerdSuite) SetupTest() {\n\tsuite.containerRunners = nil\n\tsuite.containerID = uuid.New().String()\n}\n\nfunc (suite *ContainerdSuite) run(runners ...runner.Runner) {\n\trunningCh := make(chan bool, 2*len(runners))\n\n\tfor _, r := range runners {\n\t\tsuite.Require().NoError(r.Open())\n\n\t\tsuite.containerRunners = append(suite.containerRunners, r)\n\n\t\tsuite.containersWg.Add(1)\n\n\t\tgo func(r runner.Runner) {\n\t\t\trunningSink := func(state events.ServiceState, message string, args ...any) {\n\t\t\t\tif state == events.StateRunning {\n\t\t\t\t\trunningCh <- true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdefer func() { runningCh <- false }()\n\t\t\tdefer suite.containersWg.Done()\n\n\t\t\tsuite.Require().NoError(r.Run(runningSink))\n\t\t}(r)\n\t}\n\n\t// wait for the containers to be started actually\n\tfor range runners {\n\t\tresult := <-runningCh\n\t\tsuite.Require().True(result, \"some containers failed to start\")\n\t}\n}\n\nfunc (suite *ContainerdSuite) TearDownTest() {\n\tfor _, r := range suite.containerRunners {\n\t\tsuite.Assert().NoError(r.Stop())\n\t}\n\n\tsuite.containersWg.Wait()\n\n\tfor _, r := range suite.containerRunners {\n\t\tsuite.Assert().NoError(r.Close())\n\t}\n}\n\nfunc (suite *ContainerdSuite) runK8sContainers() {\n\tsuite.run(containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID + \"1\",\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerOpts(containerd.WithContainerLabels(map[string]string{\n\t\t\t\"io.kubernetes.pod.name\":      \"fun\",\n\t\t\t\"io.kubernetes.pod.namespace\": \"ns1\",\n\t\t})),\n\t\trunner.WithOCISpecOpts(oci.WithAnnotations(map[string]string{\n\t\t\t\"io.kubernetes.cri.sandbox-log-directory\": \"sandbox\",\n\t\t\t\"io.kubernetes.cri.sandbox-id\":            \"c888d69b73b5b444c2b0bd70da28c3da102b0aeb327f3a297626e2558def327f\",\n\t\t})),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t), containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID + \"2\",\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerOpts(containerd.WithContainerLabels(map[string]string{\n\t\t\t\"io.kubernetes.pod.name\":       \"fun\",\n\t\t\t\"io.kubernetes.pod.namespace\":  \"ns1\",\n\t\t\t\"io.kubernetes.container.name\": \"run\",\n\t\t})),\n\t\trunner.WithOCISpecOpts(oci.WithAnnotations(map[string]string{\n\t\t\t\"io.kubernetes.cri.sandbox-id\": \"c888d69b73b5b444c2b0bd70da28c3da102b0aeb327f3a297626e2558def327f\",\n\t\t})),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t))\n}\n\nfunc (suite *ContainerdSuite) TestPodsNonK8s() {\n\tsuite.run(containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t))\n\n\ti, err := ctrd.NewInspector(context.Background(), suite.containerdNamespace, ctrd.WithContainerdAddress(suite.containerdAddress))\n\tsuite.Assert().NoError(err)\n\n\tpods, err := i.Pods()\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(pods, 1)\n\tsuite.Assert().Equal(suite.containerID, pods[0].Name)\n\tsuite.Assert().Equal(\"\", pods[0].Sandbox)\n\tsuite.Require().Len(pods[0].Containers, 1)\n\tsuite.Assert().Equal(suite.containerID, pods[0].Containers[0].Display)\n\tsuite.Assert().Equal(suite.containerID, pods[0].Containers[0].Name)\n\tsuite.Assert().Equal(suite.containerID, pods[0].Containers[0].ID)\n\tsuite.Assert().Equal(busyboxImage, pods[0].Containers[0].Image)\n\tsuite.Assert().Equal(\"RUNNING\", pods[0].Containers[0].Status)\n\tsuite.Assert().NotNil(pods[0].Containers[0].Metrics)\n\n\tsuite.Assert().NoError(i.Close())\n}\n\nfunc (suite *ContainerdSuite) TestPodsK8s() {\n\tsuite.runK8sContainers()\n\n\ti, err := ctrd.NewInspector(context.Background(), suite.containerdNamespace, ctrd.WithContainerdAddress(suite.containerdAddress))\n\tsuite.Assert().NoError(err)\n\n\tpods, err := i.Pods()\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(pods, 1)\n\tsuite.Assert().Equal(\"ns1/fun\", pods[0].Name)\n\tsuite.Assert().Equal(\"sandbox\", pods[0].Sandbox)\n\tsuite.Require().Len(pods[0].Containers, 2)\n\n\tsuite.Assert().Equal(\"ns1/fun\", pods[0].Containers[0].Display)\n\tsuite.Assert().Equal(suite.containerID+\"1\", pods[0].Containers[0].Name)\n\tsuite.Assert().Equal(suite.containerID+\"1\", pods[0].Containers[0].ID)\n\tsuite.Assert().Equal(\"sandbox\", pods[0].Containers[0].Sandbox)\n\tsuite.Assert().Equal(\"0\", pods[0].Containers[0].RestartCount)\n\tsuite.Assert().Equal(\"\", pods[0].Containers[0].GetLogFile())\n\tsuite.Assert().Equal(busyboxImage, pods[0].Containers[0].Image)\n\tsuite.Assert().Equal(\"RUNNING\", pods[0].Containers[0].Status)\n\tsuite.Assert().NotNil(pods[0].Containers[0].Metrics)\n\n\tsuite.Assert().Equal(\"ns1/fun:run\", pods[0].Containers[1].Display)\n\tsuite.Assert().Equal(\"run\", pods[0].Containers[1].Name)\n\tsuite.Assert().Equal(suite.containerID+\"2\", pods[0].Containers[1].ID)\n\tsuite.Assert().Equal(\"sandbox\", pods[0].Containers[1].Sandbox)\n\tsuite.Assert().Equal(\"sandbox/run/0.log\", pods[0].Containers[1].GetLogFile())\n\tsuite.Assert().Equal(busyboxImage, pods[0].Containers[1].Image)\n\tsuite.Assert().Equal(\"RUNNING\", pods[0].Containers[1].Status)\n\tsuite.Assert().NotNil(pods[0].Containers[1].Metrics)\n\n\tsuite.Assert().NoError(i.Close())\n}\n\nfunc (suite *ContainerdSuite) TestContainerNonK8s() {\n\tsuite.run(containerdrunner.NewRunner(false, &runner.Args{\n\t\tID:          suite.containerID,\n\t\tProcessArgs: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t},\n\t\trunner.WithLoggingManager(suite.loggingManager),\n\t\trunner.WithNamespace(suite.containerdNamespace),\n\t\trunner.WithContainerImage(busyboxImage),\n\t\trunner.WithContainerdAddress(suite.containerdAddress),\n\t))\n\n\ti, err := ctrd.NewInspector(context.Background(), suite.containerdNamespace, ctrd.WithContainerdAddress(suite.containerdAddress))\n\tsuite.Assert().NoError(err)\n\n\tcntr, err := i.Container(suite.containerID)\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotNil(cntr)\n\tsuite.Assert().Equal(suite.containerID, cntr.Name)\n\tsuite.Assert().Equal(suite.containerID, cntr.Display)\n\tsuite.Assert().Equal(suite.containerID, cntr.ID)\n\tsuite.Assert().Equal(busyboxImageDigest, cntr.Image) // image is not resolved\n\tsuite.Assert().Equal(\"RUNNING\", cntr.Status)\n\n\tcntr, err = i.Container(\"nosuchcontainer\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(cntr)\n\n\tsuite.Assert().NoError(i.Close())\n}\n\nfunc (suite *ContainerdSuite) TestContainerK8s() {\n\tsuite.runK8sContainers()\n\n\ti, err := ctrd.NewInspector(context.Background(), suite.containerdNamespace, ctrd.WithContainerdAddress(suite.containerdAddress))\n\tsuite.Assert().NoError(err)\n\n\tcntr, err := i.Container(\"ns1/fun\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotNil(cntr)\n\tsuite.Assert().Equal(suite.containerID+\"1\", cntr.Name)\n\tsuite.Assert().Equal(\"ns1/fun\", cntr.Display)\n\tsuite.Assert().Equal(suite.containerID+\"1\", cntr.ID)\n\tsuite.Assert().Equal(\"sandbox\", cntr.Sandbox)\n\tsuite.Assert().Equal(\"\", cntr.GetLogFile())\n\tsuite.Assert().Equal(busyboxImageDigest, cntr.Image) // image is not resolved\n\tsuite.Assert().Equal(\"RUNNING\", cntr.Status)\n\n\tcntr, err = i.Container(\"ns1/fun:run\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().NotNil(cntr)\n\tsuite.Assert().Equal(\"run\", cntr.Name)\n\tsuite.Assert().Equal(\"ns1/fun:run\", cntr.Display)\n\tsuite.Assert().Equal(suite.containerID+\"2\", cntr.ID)\n\tsuite.Assert().Equal(\"sandbox\", cntr.Sandbox)\n\tsuite.Assert().Equal(\"sandbox/run/0.log\", cntr.GetLogFile())\n\tsuite.Assert().Equal(busyboxImageDigest, cntr.Image) // image is not resolved\n\tsuite.Assert().Equal(\"RUNNING\", cntr.Status)\n\n\tcntr, err = i.Container(\"ns2/fun:run\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(cntr)\n\n\tcntr, err = i.Container(\"ns1/run:run\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(cntr)\n\n\tcntr, err = i.Container(\"ns1/fun:go\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(cntr)\n\n\tsuite.Assert().NoError(i.Close())\n}\n\nfunc TestContainerdSuite(t *testing.T) {\n\tif os.Getuid() != 0 {\n\t\tt.Skip(\"can't run the test as non-root\")\n\t}\n\n\t_, err := os.Stat(\"/bin/containerd\")\n\tif err != nil {\n\t\tt.Skip(\"containerd binary is not available, skipping the test\")\n\t}\n\n\tsuite.Run(t, new(ContainerdSuite))\n}\n"
  },
  {
    "path": "internal/pkg/containers/containers_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containers_test\n\nimport (\n\t\"testing\"\n)\n\nfunc TestEmpty(t *testing.T) {\n\t// replace with real test\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd\n\n// AuthConfig represents the registry auth options.\ntype AuthConfig struct {\n\tUsername      string `toml:\"username\"`\n\tPassword      string `toml:\"password\"`\n\tAuth          string `toml:\"auth\"`\n\tIdentityToken string `toml:\"identitytoken\"`\n}\n\n// RegistryConfig represents a registry.\ntype RegistryConfig struct {\n\tAuth *AuthConfig `toml:\"auth\"`\n}\n\n// Registry represents the registry configuration.\ntype Registry struct {\n\tConfigPath string                    `toml:\"config_path\"`\n\tConfigs    map[string]RegistryConfig `toml:\"configs\"`\n}\n\n// CRIConfig represents the CRI config.\ntype CRIConfig struct {\n\tRegistry Registry `toml:\"registry\"`\n}\n\n// PluginsConfig represents the CRI plugins config.\ntype PluginsConfig struct {\n\tCRI CRIConfig `toml:\"io.containerd.cri.v1.images\"`\n}\n\n// Config represnts the containerd config.\ntype Config struct {\n\tPlugins PluginsConfig `toml:\"plugins\"`\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/cri/containerd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n//go:embed testdata/cri.toml\nvar expectedCRIConfig string\n\ntype mockConfig struct {\n\tmirrors map[string]*cri.RegistryMirrorConfig\n\tauths   map[string]*cri.RegistryAuthConfig\n\ttlses   map[string]*cri.RegistryTLSConfig\n}\n\n// Mirrors implements the Registries interface.\nfunc (c *mockConfig) Mirrors() map[string]config.RegistryMirrorConfig {\n\tmirrors := make(map[string]config.RegistryMirrorConfig, len(c.mirrors))\n\n\tfor k, v := range c.mirrors {\n\t\tmirrors[k] = v\n\t}\n\n\treturn mirrors\n}\n\n// Auths implements the Registries interface.\nfunc (c *mockConfig) Auths() map[string]config.RegistryAuthConfig {\n\tauths := make(map[string]config.RegistryAuthConfig, len(c.auths))\n\n\tfor k, v := range c.auths {\n\t\tauths[k] = v\n\t}\n\n\treturn auths\n}\n\n// TLSs implements the Registries interface.\nfunc (c *mockConfig) TLSs() map[string]cri.RegistryTLSConfigExtended {\n\ttlses := make(map[string]cri.RegistryTLSConfigExtended, len(c.tlses))\n\n\tfor k, v := range c.tlses {\n\t\ttlses[k] = v\n\t}\n\n\treturn tlses\n}\n\ntype ConfigSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *ConfigSuite) TestGenerateRegistriesConfig() {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-1.docker.io\"},\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-2.docker.io\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tauths: map[string]*cri.RegistryAuthConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tRegistryUsername:      \"root\",\n\t\t\t\tRegistryPassword:      \"secret\",\n\t\t\t\tRegistryAuth:          \"auth\",\n\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t},\n\t\t\t\"docker.io\": {\n\t\t\t\tRegistryUsername: \"root\",\n\t\t\t\tRegistryPassword: \"topsecret\",\n\t\t\t},\n\t\t},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\tTLSCA:                 []byte(\"cacert\"),\n\t\t\t\tTLSClientIdentity: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\tCrt: []byte(\"clientcert\"),\n\t\t\t\t\tKey: []byte(\"clientkey\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tcriConfig, err := containerd.GenerateCRIConfig(cfg)\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(expectedCRIConfig, string(criConfig))\n}\n\nfunc TestConfigSuite(t *testing.T) {\n\tsuite.Run(t, new(ConfigSuite))\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/containerd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package containerd provides support for containerd CRI plugin\npackage containerd\n\nimport (\n\t\"bytes\"\n\t\"maps\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/containerd/containerd/v2/core/remotes/docker\"\n\t\"github.com/pelletier/go-toml/v2\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// GenerateCRIConfig returns a part of CRI config for registry auth.\n//\n// Once containerd supports different way of supplying auth info, this should be updated.\nfunc GenerateCRIConfig(r cri.Registries) ([]byte, error) {\n\tvar ctrdCfg Config\n\n\tctrdCfg.Plugins.CRI.Registry.ConfigPath = filepath.Join(constants.EtcCRIConfdPath, \"hosts\")\n\tctrdCfg.Plugins.CRI.Registry.Configs = make(map[string]RegistryConfig)\n\n\tfor _, registryHost := range slices.Sorted(maps.Keys(r.Auths())) {\n\t\tauthConfig := r.Auths()[registryHost]\n\n\t\tcfg := RegistryConfig{}\n\t\tcfg.Auth = &AuthConfig{\n\t\t\tUsername:      authConfig.Username(),\n\t\t\tPassword:      authConfig.Password(),\n\t\t\tAuth:          authConfig.Auth(),\n\t\t\tIdentityToken: authConfig.IdentityToken(),\n\t\t}\n\n\t\tconfigHost, _ := docker.DefaultHost(registryHost) //nolint:errcheck // doesn't return an error\n\n\t\tctrdCfg.Plugins.CRI.Registry.Configs[configHost] = cfg\n\t}\n\n\tvar buf bytes.Buffer\n\n\tif err := toml.NewEncoder(&buf).SetIndentTables(true).Encode(&ctrdCfg); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/hosts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/containerd/containerd/v2/core/remotes/docker\"\n\t\"github.com/pelletier/go-toml/v2\"\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// HostsConfig describes layout of registry configuration in \"hosts\" format.\n//\n// See: https://github.com/containerd/containerd/blob/main/docs/hosts.md\ntype HostsConfig struct {\n\tDirectories map[string]*HostsDirectory\n}\n\n// HostsDirectory describes a single directory for a specific registry.\ntype HostsDirectory struct {\n\tFiles []*HostsFile\n}\n\n// HostsFile describes a single file configuring registry.\n//\n// This might be `hosts.toml` or a specific certificate.\ntype HostsFile struct {\n\tName     string\n\tContents []byte\n\tMode     os.FileMode\n}\n\n// GenerateHosts generates a structure describing contents of the containerd hosts configuration.\n//\n//nolint:gocyclo\nfunc GenerateHosts(cfg cri.Registries, basePath string) (*HostsConfig, error) {\n\tconfig := &HostsConfig{\n\t\tDirectories: map[string]*HostsDirectory{},\n\t}\n\n\tconfigureEndpoint := func(host string, directoryName string, hostToml *HostToml, directory *HostsDirectory) {\n\t\ttlsConfig, ok := cfg.TLSs()[host]\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\n\t\tif tlsConfig.InsecureSkipVerify() {\n\t\t\thostToml.SkipVerify = true\n\t\t}\n\n\t\tif tlsConfig.CA() != nil {\n\t\t\trelPath := fmt.Sprintf(\"%s-ca.crt\", host)\n\n\t\t\tdirectory.Files = append(directory.Files,\n\t\t\t\t&HostsFile{\n\t\t\t\t\tName:     relPath,\n\t\t\t\t\tContents: tlsConfig.CA(),\n\t\t\t\t\tMode:     0o600,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\thostToml.CACert = filepath.Join(basePath, directoryName, relPath)\n\t\t}\n\n\t\tif tlsConfig.ClientIdentity() != nil {\n\t\t\trelPathCrt := fmt.Sprintf(\"%s-client.crt\", host)\n\t\t\trelPathKey := fmt.Sprintf(\"%s-client.key\", host)\n\n\t\t\tdirectory.Files = append(directory.Files,\n\t\t\t\t&HostsFile{\n\t\t\t\t\tName:     relPathCrt,\n\t\t\t\t\tContents: tlsConfig.ClientIdentity().Crt,\n\t\t\t\t\tMode:     0o600,\n\t\t\t\t},\n\t\t\t\t&HostsFile{\n\t\t\t\t\tName:     relPathKey,\n\t\t\t\t\tContents: tlsConfig.ClientIdentity().Key,\n\t\t\t\t\tMode:     0o600,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\thostToml.Client = [][2]string{\n\t\t\t\t{\n\t\t\t\t\tfilepath.Join(basePath, directoryName, relPathCrt),\n\t\t\t\t\tfilepath.Join(basePath, directoryName, relPathKey),\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t}\n\n\t// process mirrors\n\tfor registryName, endpoints := range cfg.Mirrors() {\n\t\tdirectoryName := hostDirectory(registryName)\n\n\t\tdirectory := &HostsDirectory{}\n\n\t\tvar hostsConfig HostsConfiguration\n\n\t\tfor _, endpoint := range endpoints.Endpoints() {\n\t\t\tu, err := url.Parse(endpoint.Endpoint())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error parsing endpoint %q for host %q: %w\", endpoint, registryName, err)\n\t\t\t}\n\n\t\t\thostEntry := HostEntry{\n\t\t\t\tHost: endpoint.Endpoint(),\n\t\t\t\tHostToml: HostToml{\n\t\t\t\t\tCapabilities: []string{\"pull\", \"resolve\"}, // TODO: we should make it configurable eventually\n\t\t\t\t\tOverridePath: endpoint.OverridePath(),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tconfigureEndpoint(u.Host, directoryName, &hostEntry.HostToml, directory)\n\n\t\t\thostsConfig.HostEntries = append(hostsConfig.HostEntries, hostEntry)\n\t\t}\n\n\t\tif endpoints.SkipFallback() {\n\t\t\thostsConfig.DisableFallback()\n\t\t}\n\n\t\tcfgOut, err := hostsConfig.RenderTOML()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdirectory.Files = append(directory.Files,\n\t\t\t&HostsFile{\n\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\tMode:     0o600,\n\t\t\t\tContents: cfgOut,\n\t\t\t},\n\t\t)\n\n\t\tconfig.Directories[directoryName] = directory\n\t}\n\n\t// process TLS config for non-mirrored endpoints (even if they were already processed)\n\tfor hostname, tlsConfig := range cfg.TLSs() {\n\t\tdirectoryName := hostDirectory(hostname)\n\n\t\tif _, ok := config.Directories[directoryName]; ok {\n\t\t\t// skip, already configured\n\t\t\tcontinue\n\t\t}\n\n\t\tif tlsConfig == nil || (tlsConfig.CA() == nil && tlsConfig.ClientIdentity() == nil && !tlsConfig.InsecureSkipVerify()) {\n\t\t\t// skip, no specific config\n\t\t\tcontinue\n\t\t}\n\n\t\tif hostname == \"*\" {\n\t\t\t// no way to generate TLS config for wildcard host\n\t\t\treturn nil, errors.New(\"wildcard host TLS configuration is not supported\")\n\t\t}\n\n\t\tdirectory := &HostsDirectory{}\n\n\t\tdefaultHost, err := docker.DefaultHost(hostname)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdefaultHost = \"https://\" + defaultHost\n\n\t\trootEntry := HostEntry{\n\t\t\tHost: defaultHost,\n\t\t}\n\n\t\tconfigureEndpoint(hostname, directoryName, &rootEntry.HostToml, directory)\n\n\t\thostsToml := HostsConfiguration{\n\t\t\tRootEntry: optional.Some(rootEntry),\n\t\t}\n\n\t\tcfgOut, err := hostsToml.RenderTOML()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdirectory.Files = append(directory.Files,\n\t\t\t&HostsFile{\n\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\tMode:     0o600,\n\t\t\t\tContents: cfgOut,\n\t\t\t},\n\t\t)\n\n\t\tconfig.Directories[directoryName] = directory\n\t}\n\n\treturn config, nil\n}\n\n// hostDirectory converts \":port\" to \"_port_\" in directory names.\nfunc hostDirectory(host string) string {\n\tif host == \"*\" {\n\t\treturn \"_default\"\n\t}\n\n\tidx := strings.LastIndex(host, \":\")\n\tif idx > 0 {\n\t\treturn host[:idx] + \"_\" + host[idx+1:] + \"_\"\n\t}\n\n\treturn host\n}\n\n// HostEntry describes the configuration for a single host.\ntype HostEntry struct {\n\tHost     string\n\tHostToml //nolint:embeddedstructfieldcheck\n}\n\n// HostsConfiguration describes the configuration of `hosts.toml` file in the format not compatible with TOML.\n//\n// The hosts entries should come in order, and go-toml only supports map[string]any, so we need to do some tricks.\ntype HostsConfiguration struct {\n\tRootEntry optional.Optional[HostEntry] // might be missing\n\n\tHostEntries []HostEntry\n}\n\n// DisableFallback disables the fallback to the default host.\nfunc (hc *HostsConfiguration) DisableFallback() {\n\tif len(hc.HostEntries) == 0 {\n\t\treturn\n\t}\n\n\t// push the last entry as the root entry\n\thc.RootEntry = optional.Some(hc.HostEntries[len(hc.HostEntries)-1])\n\n\thc.HostEntries = hc.HostEntries[:len(hc.HostEntries)-1]\n}\n\n// RenderTOML renders the configuration to TOML format.\nfunc (hc *HostsConfiguration) RenderTOML() ([]byte, error) {\n\tvar out bytes.Buffer\n\n\t// toml marshaling doesn't guarantee proper order of map keys, so instead we should marshal\n\t// each time and append to the output\n\n\tif rootEntry, ok := hc.RootEntry.Get(); ok {\n\t\tserver := HostsTomlServer{\n\t\t\tServer:   rootEntry.Host,\n\t\t\tHostToml: rootEntry.HostToml,\n\t\t}\n\n\t\tif err := toml.NewEncoder(&out).SetIndentTables(true).Encode(server); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfor i, entry := range hc.HostEntries {\n\t\thostEntry := HostsTomlHost{\n\t\t\tHostConfigs: map[string]HostToml{\n\t\t\t\tentry.Host: entry.HostToml,\n\t\t\t},\n\t\t}\n\n\t\tvar tomlBuf bytes.Buffer\n\n\t\tif err := toml.NewEncoder(&tomlBuf).SetIndentTables(true).Encode(hostEntry); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\ttomlBytes := tomlBuf.Bytes()\n\n\t\t// this is an ugly hack, and neither TOML format nor go-toml library make it easier\n\t\t//\n\t\t// we need to marshal each endpoint in the order they are specified in the config, but go-toml defines\n\t\t// the tree as map[string]interface{} and doesn't guarantee the order of keys\n\t\t//\n\t\t// so we marshal each entry separately and combine the output, which results in something like:\n\t\t//\n\t\t//   [host]\n\t\t//     [host.\"foo.bar\"]\n\t\t//\t [host]\n\t\t//     [host.\"bar.foo\"]\n\t\t//\n\t\t// but this is invalid TOML, as `[host]' is repeated, so we do an ugly hack and remove it below\n\t\tconst hostPrefix = \"[host]\\n\"\n\n\t\tif i > 0 {\n\t\t\tif bytes.HasPrefix(tomlBytes, []byte(hostPrefix)) {\n\t\t\t\ttomlBytes = tomlBytes[len(hostPrefix):]\n\t\t\t}\n\t\t}\n\n\t\tout.Write(tomlBytes)\n\t}\n\n\treturn out.Bytes(), nil\n}\n\n// HostsTomlServer describes only 'server' part of the `hosts.toml` file.\ntype HostsTomlServer struct {\n\t// top-level entry is used as the last one in the fallback chain.\n\tServer   string `toml:\"server,omitempty\"`\n\tHostToml        //nolint:embeddedstructfieldcheck       // embedded, matches the server\n}\n\n// HostsTomlHost describes the `hosts.toml` file entry for hosts.\n//\n// It is supposed to be marshaled as a single-entry map to keep the order correct.\ntype HostsTomlHost struct {\n\t// Note: this doesn't match the TOML format, but allows use to keep endpoints ordered properly.\n\tHostConfigs map[string]HostToml `toml:\"host\"`\n}\n\n// HostToml is a single entry in `hosts.toml`.\ntype HostToml struct {\n\tCapabilities []string    `toml:\"capabilities,omitempty\"`\n\tOverridePath bool        `toml:\"override_path,omitempty\"`\n\tCACert       string      `toml:\"ca,omitempty\"`\n\tClient       [][2]string `toml:\"client,omitempty\"`\n\tSkipVerify   bool        `toml:\"skip_verify,omitempty\"`\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/hosts_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containerd_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/cri/containerd\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\nfunc TestGenerateHostsWithTLS(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-1.docker.io\"},\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-2.docker.io\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tauths: map[string]*cri.RegistryAuthConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tRegistryUsername:      \"root\",\n\t\t\t\tRegistryPassword:      \"secret\",\n\t\t\t\tRegistryAuth:          \"auth\",\n\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t},\n\t\t},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t\tTLSCA:                 []byte(\"cacert\"),\n\t\t\t\tTLSClientIdentity: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\tCrt: []byte(\"clientcert\"),\n\t\t\t\t\tKey: []byte(\"clientkey\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"registry-2.docker.io\": {\n\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tresult, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &containerd.HostsConfig{\n\t\tDirectories: map[string]*containerd.HostsDirectory{\n\t\t\t\"docker.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://registry-1.docker.io']\\n    capabilities = ['pull', 'resolve']\\n  [host.'https://registry-2.docker.io']\\n    capabilities = ['pull', 'resolve']\\n    skip_verify = true\\n\"), //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"some.host_123_\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"some.host:123-ca.crt\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"cacert\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"some.host:123-client.crt\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"clientcert\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"some.host:123-client.key\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"clientkey\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'https://some.host:123'\\nca = '/etc/cri/conf.d/hosts/some.host_123_/some.host:123-ca.crt'\\nclient = [['/etc/cri/conf.d/hosts/some.host_123_/some.host:123-client.crt', '/etc/cri/conf.d/hosts/some.host_123_/some.host:123-client.key']]\\nskip_verify = true\\n\"), //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"registry-2.docker.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'https://registry-2.docker.io'\\nskip_verify = true\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, result)\n}\n\nfunc TestGenerateHostsWithoutTLS(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-1.docker.io\"},\n\t\t\t\t\t{EndpointEndpoint: \"https://registry-2.docker.io\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"*\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://my-registry\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tauths: map[string]*cri.RegistryAuthConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tRegistryUsername:      \"root\",\n\t\t\t\tRegistryPassword:      \"secret\",\n\t\t\t\tRegistryAuth:          \"auth\",\n\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t},\n\t\t},\n\t}\n\n\tresult, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &containerd.HostsConfig{\n\t\tDirectories: map[string]*containerd.HostsDirectory{\n\t\t\t\"docker.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://registry-1.docker.io']\\n    capabilities = ['pull', 'resolve']\\n  [host.'https://registry-2.docker.io']\\n    capabilities = ['pull', 'resolve']\\n\"), //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"_default\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://my-registry']\\n    capabilities = ['pull', 'resolve']\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, result)\n}\n\nfunc TestGenerateHostsTLSWildcardWrong(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"*\": {\n\t\t\t\tTLSCA: []byte(\"allcert\"),\n\t\t\t},\n\t\t},\n\t}\n\n\t_, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\tassert.EqualError(t, err, \"wildcard host TLS configuration is not supported\")\n}\n\nfunc TestGenerateHostsTLSWildcard(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"*\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://my-registry1\"},\n\t\t\t\t\t{EndpointEndpoint: \"https://my-registry2\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"my-registry1\": {\n\t\t\t\tTLSCA: []byte(\"allcert\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tresult, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &containerd.HostsConfig{\n\t\tDirectories: map[string]*containerd.HostsDirectory{\n\t\t\t\"_default\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"my-registry1-ca.crt\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"allcert\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://my-registry1']\\n    capabilities = ['pull', 'resolve']\\n    ca = '/etc/cri/conf.d/hosts/_default/my-registry1-ca.crt'\\n  [host.'https://my-registry2']\\n    capabilities = ['pull', 'resolve']\\n\"), //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"my-registry1\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"my-registry1-ca.crt\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"allcert\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'https://my-registry1'\\nca = '/etc/cri/conf.d/hosts/my-registry1/my-registry1-ca.crt'\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, result)\n}\n\nfunc TestGenerateHostsWithHarbor(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointEndpoint:     \"https://harbor/v2/mirrors/proxy.docker.io\",\n\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"ghcr.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointEndpoint:     \"https://harbor/v2/mirrors/proxy.ghcr.io\",\n\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tauths: map[string]*cri.RegistryAuthConfig{\n\t\t\t\"harbor\": {\n\t\t\t\tRegistryUsername:      \"root\",\n\t\t\t\tRegistryPassword:      \"secret\",\n\t\t\t\tRegistryAuth:          \"auth\",\n\t\t\t\tRegistryIdentityToken: \"token\",\n\t\t\t},\n\t\t},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"harbor\": {\n\t\t\t\tTLSInsecureSkipVerify: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tresult, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\trequire.NoError(t, err)\n\n\tt.Logf(\n\t\t\"config %q\",\n\t\tstring(result.Directories[\"harbor\"].Files[0].Contents),\n\t)\n\n\tassert.Equal(t, &containerd.HostsConfig{\n\t\tDirectories: map[string]*containerd.HostsDirectory{\n\t\t\t\"docker.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://harbor/v2/mirrors/proxy.docker.io']\\n    capabilities = ['pull', 'resolve']\\n    override_path = true\\n    skip_verify = true\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"ghcr.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"[host]\\n  [host.'https://harbor/v2/mirrors/proxy.ghcr.io']\\n    capabilities = ['pull', 'resolve']\\n    override_path = true\\n    skip_verify = true\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"harbor\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'https://harbor'\\nskip_verify = true\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, result)\n}\n\nfunc TestGenerateHostsSkipFallback(t *testing.T) {\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"https://harbor/v2/mirrors/proxy.docker.io\", EndpointOverridePath: true},\n\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5001/v2/\", EndpointOverridePath: true},\n\t\t\t\t},\n\t\t\t\tMirrorSkipFallback: true,\n\t\t\t},\n\t\t\t\"ghcr.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5002\"},\n\t\t\t\t},\n\t\t\t\tMirrorSkipFallback: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tresult, err := containerd.GenerateHosts(cfg, \"/etc/cri/conf.d/hosts\")\n\trequire.NoError(t, err)\n\n\tt.Logf(\n\t\t\"config docker.io %q\",\n\t\tstring(result.Directories[\"docker.io\"].Files[0].Contents),\n\t)\n\tt.Logf(\n\t\t\"config ghcr.io %q\",\n\t\tstring(result.Directories[\"ghcr.io\"].Files[0].Contents),\n\t)\n\n\tassert.Equal(t, &containerd.HostsConfig{\n\t\tDirectories: map[string]*containerd.HostsDirectory{\n\t\t\t\"docker.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'http://127.0.0.1:5001/v2/'\\ncapabilities = ['pull', 'resolve']\\noverride_path = true\\n[host]\\n  [host.'https://harbor/v2/mirrors/proxy.docker.io']\\n    capabilities = ['pull', 'resolve']\\n    override_path = true\\n\"), //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"ghcr.io\": {\n\t\t\t\tFiles: []*containerd.HostsFile{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:     \"hosts.toml\",\n\t\t\t\t\t\tMode:     0o600,\n\t\t\t\t\t\tContents: []byte(\"server = 'http://127.0.0.1:5002'\\ncapabilities = ['pull', 'resolve']\\n\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, result)\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/containerd/testdata/cri.toml",
    "content": "[plugins]\n  [plugins.'io.containerd.cri.v1.images']\n    [plugins.'io.containerd.cri.v1.images'.registry]\n      config_path = '/etc/cri/conf.d/hosts'\n\n      [plugins.'io.containerd.cri.v1.images'.registry.configs]\n        [plugins.'io.containerd.cri.v1.images'.registry.configs.'registry-1.docker.io']\n          [plugins.'io.containerd.cri.v1.images'.registry.configs.'registry-1.docker.io'.auth]\n            username = 'root'\n            password = 'topsecret'\n            auth = ''\n            identitytoken = ''\n\n        [plugins.'io.containerd.cri.v1.images'.registry.configs.'some.host:123']\n          [plugins.'io.containerd.cri.v1.images'.registry.configs.'some.host:123'.auth]\n            username = 'root'\n            password = 'secret'\n            auth = 'auth'\n            identitytoken = 'token'\n"
  },
  {
    "path": "internal/pkg/containers/cri/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cri implements containers.Inspector via CRI\npackage cri\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\tctrs \"github.com/siderolabs/talos/internal/pkg/containers\"\n\tcriclient \"github.com/siderolabs/talos/internal/pkg/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\ntype inspector struct {\n\tclient *criclient.Client\n\tctx    context.Context //nolint:containedctx\n}\n\ntype inspectorOptions struct {\n\tcriEndpoint string\n}\n\n// Option configures containerd Inspector.\ntype Option func(*inspectorOptions)\n\n// WithCRIEndpoint configures CRI endpoint to use.\nfunc WithCRIEndpoint(endpoint string) Option {\n\treturn func(o *inspectorOptions) {\n\t\to.criEndpoint = endpoint\n\t}\n}\n\n// NewInspector builds new Inspector instance for CRI.\nfunc NewInspector(ctx context.Context, options ...Option) (ctrs.Inspector, error) {\n\tvar err error\n\n\topt := inspectorOptions{\n\t\tcriEndpoint: \"unix:\" + constants.CRIContainerdAddress,\n\t}\n\n\tfor _, o := range options {\n\t\to(&opt)\n\t}\n\n\ti := inspector{\n\t\tctx: ctx,\n\t}\n\n\ti.client, err = criclient.NewClient(opt.criEndpoint, 10*time.Second)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &i, nil\n}\n\n// Close frees associated resources.\nfunc (i *inspector) Close() error {\n\treturn i.client.Close()\n}\n\n// Images returns a hash of image digest -> name.\nfunc (i *inspector) Images() (map[string]string, error) {\n\timages, err := i.client.ListImages(i.ctx, &runtimeapi.ImageFilter{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make(map[string]string)\n\n\tfor _, image := range images {\n\t\tif len(image.RepoTags) > 0 {\n\t\t\tresult[image.Id] = image.RepoTags[0]\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc parseContainerDisplay(id string) (namespace, pod, name, containerID string) {\n\tnamespace, pod, ok := strings.Cut(id, \"/\")\n\tif !ok {\n\t\treturn \"\", \"\", id, \"\"\n\t}\n\n\tpod, name, ok = strings.Cut(pod, \":\")\n\tif !ok {\n\t\treturn namespace, pod, \"\", \"\"\n\t}\n\n\tname, containerID, ok = strings.Cut(name, \":\")\n\tif !ok {\n\t\treturn namespace, pod, name, \"\"\n\t}\n\n\treturn namespace, pod, name, containerID\n}\n\n// Container returns info about a single container.\n//\n// If container is not found, Container returns nil.\nfunc (i *inspector) Container(id string) (*ctrs.Container, error) {\n\tnamespace, pod, name, cntID := parseContainerDisplay(id)\n\tif pod == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tif name == \"\" { // request for a pod sandbox\n\t\tsandboxes, err := i.client.ListPodSandbox(\n\t\t\ti.ctx, &runtimeapi.PodSandboxFilter{\n\t\t\t\tState: &runtimeapi.PodSandboxStateValue{\n\t\t\t\t\tState: runtimeapi.PodSandboxState_SANDBOX_READY,\n\t\t\t\t},\n\t\t\t\tLabelSelector: map[string]string{\n\t\t\t\t\t\"io.kubernetes.pod.name\":      pod,\n\t\t\t\t\t\"io.kubernetes.pod.namespace\": namespace,\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif len(sandboxes) == 0 {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tpod, err := i.buildPod(sandboxes[0])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn pod.Containers[0], nil\n\t}\n\n\t// request for a container\n\tcontainers, err := i.client.ListContainers(\n\t\ti.ctx, &runtimeapi.ContainerFilter{\n\t\t\tLabelSelector: map[string]string{\n\t\t\t\t\"io.kubernetes.pod.name\":       pod,\n\t\t\t\t\"io.kubernetes.pod.namespace\":  namespace,\n\t\t\t\t\"io.kubernetes.container.name\": name,\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(containers) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tif cntID != \"\" {\n\t\tcnt, ok := findContainer(cntID, containers)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"container %q not found\", id)\n\t\t}\n\n\t\treturn i.buildContainer(cnt)\n\t}\n\n\treturn i.buildContainer(containers[0])\n}\n\nfunc findContainer(cntID string, containers []*runtimeapi.Container) (*runtimeapi.Container, bool) {\n\t// I'm sure that we can proabably find container using CRI labels, but\n\t// I'm not sure if it will work with partial IDs.\n\tfor _, cnt := range containers {\n\t\tif strings.Contains(cnt.Id, cntID) {\n\t\t\treturn cnt, true\n\t\t}\n\t}\n\n\treturn nil, false\n}\n\n//nolint:gocyclo\nfunc (i *inspector) buildPod(sandbox *runtimeapi.PodSandbox) (*ctrs.Pod, error) {\n\tsandboxStatus, sandboxInfo, err := i.client.PodSandboxStatus(i.ctx, sandbox.Id)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpodName := sandbox.Metadata.Namespace + \"/\" + sandbox.Metadata.Name\n\tpod := &ctrs.Pod{\n\t\tName: podName,\n\t\tContainers: []*ctrs.Container{\n\t\t\t{\n\t\t\t\tInspector:    i,\n\t\t\t\tDisplay:      podName,\n\t\t\t\tName:         podName,\n\t\t\t\tID:           sandbox.Id,\n\t\t\t\tUID:          sandbox.Metadata.Uid,\n\t\t\t\tPodName:      podName,\n\t\t\t\tStatus:       sandboxStatus.State.String(),\n\t\t\t\tIsPodSandbox: true,\n\t\t\t\tMetrics:      &ctrs.ContainerMetrics{\n\t\t\t\t\t// assume pod sandbox uses zero\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif info, ok := sandboxInfo[\"info\"]; ok {\n\t\tvar verboseInfo map[string]any\n\n\t\tif err := json.Unmarshal([]byte(info), &verboseInfo); err == nil {\n\t\t\tif pid, ok := verboseInfo[\"pid\"]; ok {\n\t\t\t\tif fpid, ok := pid.(float64); ok {\n\t\t\t\t\tpod.Containers[0].Pid = uint32(fpid)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif image, ok := verboseInfo[\"image\"]; ok {\n\t\t\t\tif digest, ok := image.(string); ok {\n\t\t\t\t\tpod.Containers[0].Image = digest\n\t\t\t\t\tpod.Containers[0].Digest = digest\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif runtimeSpec, ok := verboseInfo[\"runtimeSpec\"].(map[string]any); ok {\n\t\t\t\tif linuxSpec, ok := runtimeSpec[\"linux\"].(map[string]any); ok {\n\t\t\t\t\tif namespaces, ok := linuxSpec[\"namespaces\"].([]any); ok {\n\t\t\t\t\t\tfor _, n := range namespaces {\n\t\t\t\t\t\t\tif nt, ok := n.(map[string]any); ok && nt[\"type\"] == \"network\" {\n\t\t\t\t\t\t\t\tif netnsPath, ok := nt[\"path\"].(string); ok {\n\t\t\t\t\t\t\t\t\tpod.Containers[0].NetworkNamespace = path.Base(netnsPath)\n\n\t\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn pod, nil\n}\n\nfunc (i *inspector) buildContainer(container *runtimeapi.Container) (*ctrs.Container, error) {\n\tcontainerStatus, containerInfo, err := i.client.ContainerStatus(i.ctx, container.Id, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpodName := container.Labels[\"io.kubernetes.pod.namespace\"] + \"/\" + container.Labels[\"io.kubernetes.pod.name\"]\n\n\tctr := &ctrs.Container{\n\t\tInspector:    i,\n\t\tDisplay:      podName + \":\" + container.Metadata.Name + \":\" + safeCut(container.Id, 12),\n\t\tName:         container.Metadata.Name,\n\t\tID:           container.Id,\n\t\tDigest:       container.ImageRef,\n\t\tImage:        container.ImageRef,\n\t\tPodName:      podName,\n\t\tRestartCount: container.Annotations[\"io.kubernetes.container.restartCount\"],\n\t\tStatus:       container.State.String(),\n\t\tLogPath:      containerStatus.LogPath,\n\t}\n\n\tif info, ok := containerInfo[\"info\"]; ok {\n\t\tvar verboseInfo map[string]any\n\n\t\tif err := json.Unmarshal([]byte(info), &verboseInfo); err == nil {\n\t\t\tif pid, ok := verboseInfo[\"pid\"]; ok {\n\t\t\t\tif fpid, ok := pid.(float64); ok {\n\t\t\t\t\tctr.Pid = uint32(fpid)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ctr, nil\n}\n\nfunc safeCut(id string, i int) string {\n\treturn id[:min(i, len(id))]\n}\n\n// Pods collects information about running pods & containers.\n//\n//nolint:gocyclo\nfunc (i *inspector) Pods() ([]*ctrs.Pod, error) {\n\tsandboxes, err := i.client.ListPodSandbox(\n\t\ti.ctx, &runtimeapi.PodSandboxFilter{\n\t\t\tState: &runtimeapi.PodSandboxStateValue{\n\t\t\t\tState: runtimeapi.PodSandboxState_SANDBOX_READY,\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcontainers, err := i.client.ListContainers(i.ctx, &runtimeapi.ContainerFilter{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmetrics, err := i.client.ListContainerStats(i.ctx, &runtimeapi.ContainerStatsFilter{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmetricsPerContainer := map[string]*runtimeapi.ContainerStats{}\n\n\tfor _, metric := range metrics {\n\t\tmetricsPerContainer[metric.Attributes.Id] = metric\n\t}\n\n\timages, err := i.Images()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := []*ctrs.Pod(nil)\n\tpodMap := make(map[string]*ctrs.Pod)\n\n\tfor _, sandbox := range sandboxes {\n\t\tpod, err := i.buildPod(sandbox)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif imageName, ok := images[pod.Containers[0].Digest]; ok {\n\t\t\tpod.Containers[0].Image = imageName\n\t\t}\n\n\t\tresult = append(result, pod)\n\t\tpodMap[sandbox.Id] = pod\n\t}\n\n\tfor _, container := range containers {\n\t\tpod := podMap[container.PodSandboxId]\n\t\tif pod == nil {\n\t\t\t// should never happen\n\t\t\tcontinue\n\t\t}\n\n\t\tctr, err := i.buildContainer(container)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif imageName, ok := images[ctr.Digest]; ok {\n\t\t\tctr.Image = imageName\n\t\t}\n\n\t\tif metrics := metricsPerContainer[ctr.ID]; metrics != nil {\n\t\t\tctr.Metrics = &ctrs.ContainerMetrics{}\n\n\t\t\tif metrics.Memory != nil && metrics.Memory.WorkingSetBytes != nil {\n\t\t\t\tctr.Metrics.MemoryUsage = metrics.Memory.WorkingSetBytes.Value\n\t\t\t}\n\n\t\t\tif metrics.Cpu != nil && metrics.Cpu.UsageCoreNanoSeconds != nil {\n\t\t\t\tctr.Metrics.CPUUsage = metrics.Cpu.UsageCoreNanoSeconds.Value\n\t\t\t}\n\t\t}\n\n\t\tpod.Containers = append(pod.Containers, ctr)\n\t}\n\n\treturn result, nil\n}\n\n// GetProcessStderr returns process stderr.\nfunc (i *inspector) GetProcessStderr(string) (string, error) {\n\t// CRI doesn't seem to have an easy way to do that\n\treturn \"\", nil\n}\n\n// Kill sends signal to container task.\nfunc (i *inspector) Kill(id string, isPodSandbox bool, _ syscall.Signal) error {\n\tif isPodSandbox {\n\t\treturn i.client.StopPodSandbox(i.ctx, id)\n\t}\n\n\treturn i.client.StopContainer(i.ctx, id, 10)\n}\n"
  },
  {
    "path": "internal/pkg/containers/cri/cri_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime/debug\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/suite\"\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\tctrs \"github.com/siderolabs/talos/internal/pkg/containers\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/cri\"\n\tcriclient \"github.com/siderolabs/talos/internal/pkg/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tbusyboxImage = \"docker.io/library/busybox:1.30.1\"\n\t// busyboxImageDigest = \"sha256:64f5d945efcc0f39ab11b3cd4ba403cc9fefe1fa3613123ca016cf3708e8cafb\".\n\t// pauseImage         = \"k8s.gcr.io/pause:3.1\".\n\t// pauseImageDigest   = \"sha256:da86e6ba6ca197bf6bc5e9d900febd906b133eaa4750e6bed647b0fbe50ed43e\".\n)\n\nfunc MockEventSink(state events.ServiceState, message string, args ...any) {\n}\n\ntype CRISuite struct {\n\tsuite.Suite\n\n\ttmpDir string\n\n\tcontainerdRunner  runner.Runner\n\tcontainerdWg      sync.WaitGroup\n\tcontainerdAddress string\n\n\tclient    *criclient.Client\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\tinspector ctrs.Inspector\n\n\tpods []string\n}\n\nfunc (suite *CRISuite) SetupSuite() {\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tsuite.T().Skip(\"test doesn't pass under cgroupsv2\")\n\t}\n\n\tvar err error\n\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tstateDir, rootDir := filepath.Join(suite.tmpDir, \"state\"), filepath.Join(suite.tmpDir, \"root\")\n\tsuite.Require().NoError(os.Mkdir(stateDir, 0o777))\n\tsuite.Require().NoError(os.Mkdir(rootDir, 0o777))\n\n\tsuite.containerdAddress = filepath.Join(suite.tmpDir, \"run.sock\")\n\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tvar (\n\t\t\tgroupPath string\n\t\t\tmanager   *cgroup2.Manager\n\t\t)\n\n\t\tgroupPath, err = cgroup2.NestedGroupPath(suite.tmpDir)\n\t\tsuite.Require().NoError(err)\n\n\t\tmanager, err = cgroup2.NewManager(constants.CgroupMountPath, groupPath, &cgroup2.Resources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t} else {\n\t\tvar manager cgroup1.Cgroup\n\n\t\tmanager, err = cgroup1.New(cgroup1.NestedPath(suite.tmpDir), &specs.LinuxResources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t}\n\n\targs := &runner.Args{\n\t\tID: \"containerd\",\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\", suite.containerdAddress,\n\t\t\t\"--state\", stateDir,\n\t\t\t\"--root\", rootDir,\n\t\t\t\"--config\", constants.CRIContainerdConfig,\n\t\t},\n\t}\n\n\tsuite.containerdRunner = process.NewRunner(\n\t\tfalse,\n\t\targs,\n\t\trunner.WithLoggingManager(logging.NewFileLoggingManager(suite.tmpDir)),\n\t\trunner.WithEnv([]string{constants.EnvPathWithBin}),\n\t\trunner.WithCgroupPath(suite.tmpDir),\n\t)\n\tsuite.Require().NoError(suite.containerdRunner.Open())\n\n\tsuite.containerdWg.Go(func() {\n\t\tdefer suite.containerdRunner.Close() //nolint:errcheck\n\n\t\tsuite.containerdRunner.Run(MockEventSink) //nolint:errcheck\n\t})\n\n\tsuite.client, err = criclient.NewClient(\"unix:\"+suite.containerdAddress, 30*time.Second)\n\tsuite.Require().NoError(err)\n\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n\n\tsuite.inspector, err = cri.NewInspector(suite.ctx, cri.WithCRIEndpoint(\"unix:\"+suite.containerdAddress))\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *CRISuite) TearDownSuite() {\n\tsuite.ctxCancel()\n\tsuite.Require().NoError(suite.inspector.Close())\n\n\tsuite.Require().NoError(suite.client.Close())\n\n\tsuite.Require().NoError(suite.containerdRunner.Stop())\n\tsuite.containerdWg.Wait()\n}\n\nfunc (suite *CRISuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n\n\tsuite.pods = nil\n\n\tpodSandboxConfig := &runtimeapi.PodSandboxConfig{\n\t\tMetadata: &runtimeapi.PodSandboxMetadata{\n\t\t\tName:      \"etcd-master-1\",\n\t\t\tUid:       \"ed1a599a53090941c9b4025c7e3e883d\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tAttempt:   0,\n\t\t},\n\t\tLabels: map[string]string{\n\t\t\t\"io.kubernetes.pod.name\":      \"etcd-master-1\",\n\t\t\t\"io.kubernetes.pod.namespace\": \"kube-system\",\n\t\t},\n\t\tLogDirectory: suite.tmpDir,\n\t\tLinux: &runtimeapi.LinuxPodSandboxConfig{\n\t\t\tSecurityContext: &runtimeapi.LinuxSandboxSecurityContext{\n\t\t\t\tNamespaceOptions: &runtimeapi.NamespaceOption{\n\t\t\t\t\tNetwork: runtimeapi.NamespaceMode_NODE,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tpodSandboxID, err := suite.client.RunPodSandbox(suite.ctx, podSandboxConfig, \"\")\n\tsuite.Require().NoError(err)\n\tsuite.pods = append(suite.pods, podSandboxID)\n\tsuite.Require().Len(podSandboxID, 64)\n\n\timageRef, err := suite.client.PullImage(\n\t\tsuite.ctx, &runtimeapi.ImageSpec{\n\t\t\tImage: busyboxImage,\n\t\t}, podSandboxConfig,\n\t)\n\tsuite.Require().NoError(err)\n\n\tctrID, err := suite.client.CreateContainer(\n\t\tsuite.ctx, podSandboxID,\n\t\t&runtimeapi.ContainerConfig{\n\t\t\tMetadata: &runtimeapi.ContainerMetadata{\n\t\t\t\tName: \"etcd\",\n\t\t\t},\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"io.kubernetes.container.name\": \"etcd\",\n\t\t\t\t\"io.kubernetes.pod.name\":       \"etcd-master-1\",\n\t\t\t\t\"io.kubernetes.pod.namespace\":  \"kube-system\",\n\t\t\t},\n\t\t\tAnnotations: map[string]string{\n\t\t\t\t\"io.kubernetes.container.restartCount\": \"1\",\n\t\t\t},\n\t\t\tImage: &runtimeapi.ImageSpec{\n\t\t\t\tImage: imageRef,\n\t\t\t},\n\t\t\tCommand: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t\t}, podSandboxConfig,\n\t)\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(ctrID, 64)\n\n\terr = suite.client.StartContainer(suite.ctx, ctrID)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *CRISuite) TearDownTest() {\n\tfor _, pod := range suite.pods {\n\t\tsuite.Require().NoError(suite.client.StopPodSandbox(suite.ctx, pod))\n\t\tsuite.Require().NoError(suite.client.RemovePodSandbox(suite.ctx, pod))\n\t}\n\n\tsuite.ctxCancel()\n}\n\nfunc (suite *CRISuite) TestPods() {\n\tpods, err := suite.inspector.Pods()\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Len(pods, 1)\n\n\tsuite.Assert().Equal(\"kube-system/etcd-master-1\", pods[0].Name)\n\n\tsuite.Require().Len(pods[0].Containers, 2)\n\n\tsuite.Assert().Equal(pods[0].Name, pods[0].Containers[0].Display)\n\tsuite.Assert().Equal(pods[0].Name, pods[0].Containers[0].Name)\n\tsuite.Assert().Equal(\"SANDBOX_READY\", pods[0].Containers[0].Status)\n\t// suite.Assert().Equal(pauseImageDigest, pods[0].Containers[0].Digest)\n\t// suite.Assert().Equal(pauseImage, pods[0].Containers[0].Image)\n\tsuite.Assert().True(pods[0].Containers[0].Pid > 0)\n\n\tsuite.Assert().Equal(\"kube-system/etcd-master-1:etcd\", pods[0].Containers[1].Display)\n\tsuite.Assert().Equal(\"etcd\", pods[0].Containers[1].Name)\n\t// suite.Assert().Equal(busyboxImage, pods[0].Containers[1].Image)\n\t// suite.Assert().Equal(busyboxImageDigest, pods[0].Containers[1].Digest)\n\tsuite.Assert().Equal(\"CONTAINER_RUNNING\", pods[0].Containers[1].Status)\n\tsuite.Assert().Equal(\"1\", pods[0].Containers[1].RestartCount)\n\tsuite.Assert().True(pods[0].Containers[1].Pid > 0)\n}\n\nfunc (suite *CRISuite) TestContainer() {\n\tdefer func() {\n\t\tr := recover()\n\t\tif r != nil {\n\t\t\tt := suite.T()\n\t\t\tt.Errorf(\"test panicked: %v %s\", r, debug.Stack())\n\t\t\tt.FailNow()\n\t\t}\n\t}()\n\n\tcontainer, err := suite.inspector.Container(\"kube-system/etcd-master-1\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(\"kube-system/etcd-master-1\", container.Display)\n\tsuite.Assert().Equal(container.Display, container.Name)\n\tsuite.Assert().Equal(\"SANDBOX_READY\", container.Status)\n\t// suite.Assert().Equal(pauseImageDigest, container.Digest)\n\tsuite.Assert().True(container.Pid > 0)\n\n\tcontainer, err = suite.inspector.Container(\"kube-system/etcd-master-1:etcd\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(\"kube-system/etcd-master-1:etcd\", container.Display)\n\tsuite.Assert().Equal(\"etcd\", container.Name)\n\tsuite.Assert().Equal(\"CONTAINER_RUNNING\", container.Status)\n\t// suite.Assert().Equal(busyboxImageDigest, container.Image)\n\t// suite.Assert().Equal(busyboxImageDigest, container.Digest)\n\tsuite.Assert().Equal(\"1\", container.RestartCount)\n\tsuite.Assert().True(container.Pid > 0)\n\n\tcontainer, err = suite.inspector.Container(\"kube-system/etcd-master-1:etcd2\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(container)\n\n\tcontainer, err = suite.inspector.Container(\"kube-system/etcd-master-2\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(container)\n\n\tcontainer, err = suite.inspector.Container(\"talos\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Nil(container)\n}\n\nfunc TestCRISuite(t *testing.T) {\n\tif os.Getuid() != 0 {\n\t\tt.Skip(\"can't run the test as non-root\")\n\t}\n\n\t_, err := os.Stat(\"/bin/containerd\")\n\tif err != nil {\n\t\tt.Skip(\"containerd binary is not available, skipping the test\")\n\t}\n\n\tsuite.Run(t, new(CRISuite))\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/console/progress.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package console provides a console-based implementation of image pull progress reporting.\npackage console\n\nimport (\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/progress\"\n)\n\n// ReportInterval is the interval between progress reports.\nconst ReportInterval = 15 * time.Second\n\ntype layerProgress struct {\n\tstatus progress.LayerPullStatus\n\toffset int64\n\ttotal  int64\n}\n\n// ProgressReporter reports image pull progress to the console.\ntype ProgressReporter struct {\n\timageRef string\n\n\tmu     sync.Mutex\n\tlayers map[string]*layerProgress\n\tstopCh chan struct{}\n}\n\n// NewProgressReporter creates a new ProgressReporter.\nfunc NewProgressReporter(imageRef string) image.ProgressReporter {\n\treturn &ProgressReporter{\n\t\timageRef: imageRef,\n\t}\n}\n\n// Update implements UpdateFn interface.\nfunc (c *ProgressReporter) Update(upd progress.LayerPullProgress) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif c.layers == nil {\n\t\tc.layers = make(map[string]*layerProgress)\n\t}\n\n\tlp, ok := c.layers[upd.LayerID]\n\tif !ok {\n\t\tlp = &layerProgress{}\n\t\tc.layers[upd.LayerID] = lp\n\t}\n\n\tif upd.Status == progress.LayerPullStatusDownloading {\n\t\tlp.total = upd.Total\n\t\tlp.offset = upd.Offset\n\t} else {\n\t\tlp.offset = lp.total\n\t}\n\n\tlp.status = upd.Status\n}\n\n// Start implements ProgressReporter interface.\nfunc (c *ProgressReporter) Start() {\n\tc.stopCh = make(chan struct{})\n\n\tgo func() {\n\t\tticker := time.NewTicker(ReportInterval)\n\t\tdefer ticker.Stop()\n\n\t\tc.reportProgress()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tc.reportProgress()\n\t\t\tcase <-c.stopCh:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// Stop implements ProgressReporter interface.\nfunc (c *ProgressReporter) Stop() {\n\tclose(c.stopCh)\n}\n\nfunc (c *ProgressReporter) reportProgress() {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif len(c.layers) == 0 {\n\t\tlog.Printf(\"pulling image %s: starting...\", c.imageRef)\n\n\t\treturn\n\t}\n\n\tvar (\n\t\tanyDownloading bool\n\t\toverallOffset  int64\n\t\toverallTotal   int64\n\t)\n\n\tfor _, l := range c.layers {\n\t\tif l.status == progress.LayerPullStatusDownloading {\n\t\t\tanyDownloading = true\n\t\t}\n\n\t\toverallOffset += l.offset\n\t\toverallTotal += l.total\n\t}\n\n\tif !anyDownloading {\n\t\tlog.Printf(\"pulling image %s: extracting...\", c.imageRef)\n\n\t\treturn\n\t}\n\n\tvar percentage float64\n\n\tif overallTotal > 0 {\n\t\tpercentage = float64(overallOffset) / float64(overallTotal) * 100.0\n\t}\n\n\tlog.Printf(\"pulling image %s: downloading %d layers (%s/%s) (%.2f%%)...\",\n\t\tc.imageRef, len(c.layers),\n\t\thumanize.IBytes(uint64(overallOffset)),\n\t\thumanize.IBytes(uint64(overallTotal)),\n\t\tpercentage,\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage image\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\tstdlog \"log\"\n\t\"maps\"\n\t\"time\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/core/images\"\n\t\"github.com/containerd/containerd/v2/pkg/snapshotters\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/containerd/log\"\n\t\"github.com/containerd/platforms\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/distribution/reference\"\n\tocispec \"github.com/opencontainers/image-spec/specs-go/v1\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/sirupsen/logrus\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/progress\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/verify\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// Image pull retry settings.\nconst (\n\tPullTimeout       = 20 * time.Minute\n\tPullRetryInterval = 5 * time.Second\n)\n\n// PullOption is an option for Pull function.\ntype PullOption func(*PullOptions)\n\n// PullOptions configure Pull function.\ntype PullOptions struct {\n\tSkipIfAlreadyPulled bool\n\tMaxNotFoundRetries  int\n\tNewProgressReporter NewProgressReporter\n}\n\n// DefaultPullOptions returns default options for Pull function.\nfunc DefaultPullOptions() PullOptions {\n\treturn PullOptions{\n\t\tSkipIfAlreadyPulled: false,\n\t\tMaxNotFoundRetries:  5,\n\t}\n}\n\n// WithSkipIfAlreadyPulled skips pulling if image is already pulled and unpacked.\nfunc WithSkipIfAlreadyPulled() PullOption {\n\treturn func(opts *PullOptions) {\n\t\topts.SkipIfAlreadyPulled = true\n\t}\n}\n\n// WithMaxNotFoundRetries sets the maximum number of retries for not found errors.\nfunc WithMaxNotFoundRetries(maxRetries int) PullOption {\n\treturn func(opts *PullOptions) {\n\t\topts.MaxNotFoundRetries = maxRetries\n\t}\n}\n\n// WithProgressReporter enables reporting pull progress.\nfunc WithProgressReporter(newReporter NewProgressReporter) PullOption {\n\treturn func(opts *PullOptions) {\n\t\topts.NewProgressReporter = newReporter\n\t}\n}\n\n// ProgressReporter is an interface for reporting image pull progress.\ntype ProgressReporter interface {\n\tStart()\n\tStop()\n\tUpdate(progress.LayerPullProgress)\n}\n\n// NewProgressReporter creates a new progress reporter.\ntype NewProgressReporter func(imageRef string) ProgressReporter\n\n// RegistriesBuilder is a function that returns registries configuration.\ntype RegistriesBuilder = func(context.Context) (cri.Registries, error)\n\n// NewSimpleProgressReporter creates a simple progress reporter that just needs Update function.\nfunc NewSimpleProgressReporter(updateFn func(progress.LayerPullProgress)) NewProgressReporter {\n\treturn func(imageRef string) ProgressReporter {\n\t\treturn &simpleProgressReporter{\n\t\t\tupdateFn: updateFn,\n\t\t}\n\t}\n}\n\ntype simpleProgressReporter struct {\n\tupdateFn func(progress.LayerPullProgress)\n}\n\nfunc (s *simpleProgressReporter) Start() {}\n\nfunc (s *simpleProgressReporter) Stop() {}\n\nfunc (s *simpleProgressReporter) Update(p progress.LayerPullProgress) {\n\ts.updateFn(p)\n}\n\n// Pull is a convenience function that wraps the containerd image pull func with\n// retry functionality.\n//\n//nolint:gocyclo,cyclop\nfunc Pull(\n\tctx context.Context,\n\tregistryBuilder RegistriesBuilder,\n\tresources state.State,\n\tclient *containerd.Client,\n\tref string,\n\topt ...PullOption,\n) (img containerd.Image, err error) {\n\topts := DefaultPullOptions()\n\n\tfor _, o := range opt {\n\t\to(&opts)\n\t}\n\n\tnamedRef, err := reference.ParseDockerRef(ref)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse image reference %q: %w\", ref, err)\n\t}\n\n\t// normalize reference\n\tref = namedRef.String()\n\n\tif opts.SkipIfAlreadyPulled {\n\t\timg, err = client.GetImage(ctx, ref)\n\t\tif err == nil {\n\t\t\tvar unpacked bool\n\n\t\t\tunpacked, err = img.IsUnpacked(ctx, \"\")\n\t\t\tif err == nil && unpacked {\n\t\t\t\tif err = manageAliases(ctx, client, namedRef, img); err == nil {\n\t\t\t\t\treturn img, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tcontainerdLogger := logrus.New()\n\tcontainerdLogger.Out = stdlog.Default().Writer()\n\tcontainerdLogger.Formatter = &logrus.TextFormatter{\n\t\tDisableColors:    true,\n\t\tDisableQuote:     true,\n\t\tDisableTimestamp: true,\n\t}\n\n\tctx = log.WithLogger(ctx, containerdLogger.WithField(\"image\", ref))\n\n\tnotFoundErrors := 0\n\n\terr = retry.Exponential(PullTimeout, retry.WithUnits(PullRetryInterval), retry.WithErrorLogging(true)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tregistriesConfig, err := registryBuilder(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get configured registries: %w\", err)\n\t\t}\n\n\t\tresolver := NewResolver(registriesConfig)\n\n\t\tverifyResult, err := verify.ImageSignature(ctx, zap.NewNop(), resources, resolver, ref)\n\t\tif err != nil {\n\t\t\tswitch status.Code(err) { //nolint:exhaustive\n\t\t\tcase codes.PermissionDenied:\n\t\t\t\t// verification denied by matched rule, no need to retry\n\t\t\t\treturn errors.New(status.Convert(err).Message())\n\t\t\tcase codes.NotFound:\n\t\t\t\t// verification failed because image not found, no need to retry\n\t\t\t\tnotFoundErrors++\n\n\t\t\t\tif notFoundErrors > opts.MaxNotFoundRetries {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\tdefault:\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\t\t}\n\n\t\tcontainerdRemoteOpts := []containerd.RemoteOpt{\n\t\t\tcontainerd.WithPullUnpack,\n\t\t\tcontainerd.WithChildLabelMap(images.ChildGCLabelsFilterLayers),\n\t\t\tcontainerd.WithPlatformMatcher(platforms.Default()),\n\t\t\tcontainerd.WithResolver(resolver),\n\t\t}\n\n\t\tpullRef := ref\n\n\t\tif verifyResult.Verified {\n\t\t\tcontainerdRemoteOpts = append(containerdRemoteOpts,\n\t\t\t\tcontainerd.WithPullLabel(constants.ImageLabelVerified, verifyResult.Message),\n\t\t\t)\n\n\t\t\tpullRef = verifyResult.DigestedImageRef\n\t\t}\n\n\t\tif opts.NewProgressReporter != nil {\n\t\t\treporter := opts.NewProgressReporter(ref)\n\n\t\t\treporter.Start()\n\t\t\tdefer reporter.Stop()\n\n\t\t\tpp := progress.NewPullProgress(\n\t\t\t\tclient.ContentStore(),\n\t\t\t\tclient.SnapshotService(\"overlayfs\"),\n\t\t\t\treporter.Update,\n\t\t\t)\n\n\t\t\tfinishProgress := pp.ShowProgress(ctx)\n\t\t\tdefer finishProgress()\n\n\t\t\tcontainerdRemoteOpts = append(containerdRemoteOpts,\n\t\t\t\tcontainerd.WithImageHandler(\n\t\t\t\t\timages.HandlerFunc(\n\t\t\t\t\t\tfunc(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {\n\t\t\t\t\t\t\tif images.IsLayerType(desc.MediaType) {\n\t\t\t\t\t\t\t\tpp.Add(desc)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tcontainerd.WithImageHandlerWrapper(snapshotters.AppendInfoHandlerWrapper(ref)),\n\t\t\t)\n\t\t}\n\n\t\tif img, err = client.Pull(\n\t\t\tctx,\n\t\t\tpullRef,\n\t\t\tcontainerdRemoteOpts...,\n\t\t); err != nil {\n\t\t\terr = fmt.Errorf(\"failed to pull image %q: %w\", ref, err)\n\t\t\tif errors.Is(err, errdefs.ErrNotFound) {\n\t\t\t\tnotFoundErrors++\n\n\t\t\t\tif notFoundErrors > opts.MaxNotFoundRetries {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = manageAliases(ctx, client, namedRef, img); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn img, nil\n}\n\nfunc manageAliases(ctx context.Context, client *containerd.Client, namedRef reference.Named, img containerd.Image) error {\n\t// re-tag pulled image\n\timageDigest := img.Target().Digest.String()\n\n\trefs := []string{imageDigest}\n\n\tif _, ok := namedRef.(reference.NamedTagged); ok {\n\t\trefs = append(refs, namedRef.String())\n\t}\n\n\tif _, ok := namedRef.(reference.Canonical); ok {\n\t\trefs = append(refs, namedRef.String())\n\t} else {\n\t\trefs = append(refs, namedRef.Name()+\"@\"+imageDigest)\n\t}\n\n\tfor _, newRef := range refs {\n\t\tif err := createAlias(ctx, client, newRef, img.Target(), img.Labels()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc createAlias(ctx context.Context, client *containerd.Client, name string, desc ocispec.Descriptor, labels map[string]string) error {\n\timg := images.Image{\n\t\tName:   name,\n\t\tTarget: desc,\n\t\tLabels: labels,\n\t}\n\n\toldImg, err := client.ImageService().Create(ctx, img)\n\tif err == nil || !errdefs.IsAlreadyExists(err) {\n\t\treturn err\n\t}\n\n\tif oldImg.Target.Digest == img.Target.Digest && maps.Equal(oldImg.Labels, img.Labels) {\n\t\treturn nil\n\t}\n\n\t_, err = client.ImageService().Update(ctx, img, \"target\", \"labels\")\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/progress/pull_progress.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package progress provides functionality to track and report image pull progress.\npackage progress\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"log\"\n\t\"slices\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/core/content\"\n\t\"github.com/containerd/containerd/v2/core/images\"\n\t\"github.com/containerd/containerd/v2/core/remotes\"\n\t\"github.com/containerd/containerd/v2/core/snapshots\"\n\t\"github.com/containerd/containerd/v2/pkg/snapshotters\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/moby/moby/client/pkg/stringid\"\n\t\"github.com/opencontainers/go-digest\"\n\tocispec \"github.com/opencontainers/image-spec/specs-go/v1\"\n)\n\n// LayerPullStatus represents the status of a single image layer during pull.\ntype LayerPullStatus int\n\n// Possible values for LayerPullStatus.\nconst (\n\tLayerPullStatusDownloading LayerPullStatus = iota\n\tLayerPullStatusDownloadComplete\n\tLayerPullStatusExtracting\n\tLayerPullStatusExtractComplete\n\tLayerPullStatusAlreadyExists\n)\n\n// LayerPullProgress represents the progress of an image pull operation.\n//\n// Note: keep this in sync machine/images.proto.\ntype LayerPullProgress struct {\n\tLayerID string\n\tStatus  LayerPullStatus\n\t// If Status is Extracting, this shows the elapsed time since extraction started.\n\tElapsed time.Duration\n\t// If Status is Downloading, these show the current offset and total size of the layer.\n\tOffset int64\n\tTotal  int64\n}\n\n// UpdateFn is used by PullProgress to report progress updates.\ntype UpdateFn func(LayerPullProgress)\n\n// PullProgress tracks and reports the progress of image pulls.\ntype PullProgress struct {\n\tstore       content.Store\n\tsnapshotter snapshots.Snapshotter\n\tupdateFn    UpdateFn\n\n\tmu    sync.Mutex\n\tdescs map[digest.Digest]ocispec.Descriptor // guarded by mu\n\n\tlayers      []ocispec.Descriptor\n\tunpackStart map[digest.Digest]time.Time\n}\n\n// NewPullProgress creates a new PullProgress instance.\nfunc NewPullProgress(store content.Store, snapshotter snapshots.Snapshotter, fn UpdateFn) *PullProgress {\n\treturn &PullProgress{\n\t\tupdateFn:    fn,\n\t\tstore:       store,\n\t\tsnapshotter: snapshotter,\n\t\tdescs:       make(map[digest.Digest]ocispec.Descriptor),\n\t\tmu:          sync.Mutex{},\n\t}\n}\n\n// ShowProgress starts tracking and reporting pull progress.\nfunc (p *PullProgress) ShowProgress(ctx context.Context) func() {\n\tctx, cancel := context.WithCancel(ctx)\n\n\tstart := time.Now()\n\tlastUpdate := make(chan struct{})\n\n\tgo func() {\n\t\tticker := time.NewTicker(100 * time.Millisecond)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), time.Millisecond*500)\n\t\t\t\tdefer cancel()\n\n\t\t\t\tif err := p.trackProgress(ctx, start); err != nil {\n\t\t\t\t\tlog.Printf(\"failed to write pull progress: %s\", err.Error())\n\t\t\t\t}\n\n\t\t\t\tclose(lastUpdate)\n\n\t\t\t\treturn\n\n\t\t\tcase <-ticker.C:\n\t\t\t\tif err := p.trackProgress(ctx, start); err != nil {\n\t\t\t\t\tif !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {\n\t\t\t\t\t\tlog.Printf(\"updating progress failed %s\", err.Error())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\t// call this when done pulling to stop progress updates\n\treturn func() {\n\t\tcancel()\n\t\t<-lastUpdate\n\t}\n}\n\nfunc (p *PullProgress) trackProgress(ctx context.Context, start time.Time) error {\n\terr := p.trackOngoingPulls(ctx, start)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn p.trackPulledLayers(ctx)\n}\n\nfunc (p *PullProgress) trackOngoingPulls(ctx context.Context, start time.Time) error { //nolint:gocyclo\n\tactives, err := p.store.ListStatuses(ctx, \"\")\n\tif err != nil {\n\t\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tpulling := make(map[string]content.Status, len(actives))\n\n\tfor _, status := range actives {\n\t\tpulling[status.Ref] = status\n\t}\n\n\tfor _, j := range p.jobs() {\n\t\tkey := remotes.MakeRefKey(ctx, j)\n\t\tif info, ok := pulling[key]; ok {\n\t\t\tif info.Offset == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tp.updateFn(LayerPullProgress{\n\t\t\t\tLayerID: stringid.TruncateID(j.Digest.Encoded()),\n\t\t\t\tStatus:  LayerPullStatusDownloading,\n\t\t\t\tOffset:  info.Offset,\n\t\t\t\tTotal:   info.Total,\n\t\t\t})\n\n\t\t\tcontinue\n\t\t}\n\n\t\tinfo, err := p.store.Info(ctx, j.Digest)\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\tif !errdefs.IsNotFound(err) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\tcase info.CreatedAt.After(start):\n\t\t\tp.updateFn(LayerPullProgress{\n\t\t\t\tLayerID: stringid.TruncateID(j.Digest.Encoded()),\n\t\t\t\tStatus:  LayerPullStatusDownloadComplete,\n\t\t\t})\n\n\t\t\tif images.IsLayerType(j.MediaType) {\n\t\t\t\tp.layers = append(p.layers, j)\n\t\t\t}\n\n\t\t\tp.remove(j)\n\n\t\tdefault:\n\t\t\tp.updateFn(LayerPullProgress{\n\t\t\t\tLayerID: stringid.TruncateID(j.Digest.Encoded()),\n\t\t\t\tStatus:  LayerPullStatusAlreadyExists,\n\t\t\t})\n\n\t\t\tif images.IsLayerType(j.MediaType) {\n\t\t\t\tp.layers = append(p.layers, j)\n\t\t\t}\n\n\t\t\tp.remove(j)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (p *PullProgress) trackPulledLayers(ctx context.Context) error {\n\tvar committedIdx []int\n\n\tfor idx, desc := range p.layers {\n\t\twalkFilter := \"labels.\\\"\" + snapshotters.TargetLayerDigestLabel + \"\\\"==\" + p.layers[idx].Digest.String()\n\n\t\terr := p.snapshotter.Walk(ctx, func(ctx context.Context, sn snapshots.Info) error {\n\t\t\tif sn.Kind == snapshots.KindActive {\n\t\t\t\tif p.unpackStart == nil {\n\t\t\t\t\tp.unpackStart = make(map[digest.Digest]time.Time)\n\t\t\t\t}\n\n\t\t\t\tvar elapsed time.Duration\n\n\t\t\t\tif began, ok := p.unpackStart[desc.Digest]; !ok {\n\t\t\t\t\tp.unpackStart[desc.Digest] = time.Now()\n\t\t\t\t} else {\n\t\t\t\t\telapsed = time.Since(began)\n\t\t\t\t}\n\n\t\t\t\tp.updateFn(LayerPullProgress{\n\t\t\t\t\tLayerID: stringid.TruncateID(desc.Digest.Encoded()),\n\t\t\t\t\tStatus:  LayerPullStatusExtracting,\n\t\t\t\t\tElapsed: elapsed,\n\t\t\t\t})\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif sn.Kind == snapshots.KindCommitted {\n\t\t\t\tp.updateFn(\n\t\t\t\t\tLayerPullProgress{\n\t\t\t\t\t\tLayerID: stringid.TruncateID(desc.Digest.Encoded()),\n\t\t\t\t\t\tStatus:  LayerPullStatusExtractComplete,\n\t\t\t\t\t},\n\t\t\t\t)\n\n\t\t\t\tcommittedIdx = append(committedIdx, idx)\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}, walkFilter)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// remove finished/committed layers from p.layers\n\tif len(committedIdx) > 0 {\n\t\tslices.Sort(committedIdx)\n\n\t\tfor i := len(committedIdx) - 1; i >= 0; i-- {\n\t\t\tif i < len(committedIdx)-1 && committedIdx[i] == committedIdx[i+1] {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tp.layers = slices.Delete(p.layers, committedIdx[i], committedIdx[i]+1)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Add adds new descriptors to be tracked.\nfunc (p *PullProgress) Add(desc ...ocispec.Descriptor) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tfor _, d := range desc {\n\t\tif _, ok := p.descs[d.Digest]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tp.descs[d.Digest] = d\n\t}\n}\n\nfunc (p *PullProgress) remove(desc ocispec.Descriptor) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tdelete(p.descs, desc.Digest)\n}\n\nfunc (p *PullProgress) jobs() []ocispec.Descriptor {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\n\tdescs := make([]ocispec.Descriptor, 0, len(p.descs))\n\tfor _, d := range p.descs {\n\t\tdescs = append(descs, d)\n\t}\n\n\treturn descs\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/resolver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage image\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/containerd/containerd/v2/core/remotes\"\n\t\"github.com/containerd/containerd/v2/core/remotes/docker\"\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\n// NewResolver builds registry resolver based on Talos configuration.\nfunc NewResolver(reg cri.Registries) remotes.Resolver {\n\treturn docker.NewResolver(docker.ResolverOptions{\n\t\tHosts: RegistryHosts(reg),\n\t})\n}\n\n// RegistryHosts returns host configuration per registry.\n//\n//nolint:gocyclo\nfunc RegistryHosts(reg cri.Registries) docker.RegistryHosts {\n\treturn func(host string) ([]docker.RegistryHost, error) {\n\t\tvar registries []docker.RegistryHost\n\n\t\tendpoints, err := RegistryEndpoints(reg, host)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfor _, endpoint := range endpoints {\n\t\t\tu, err := url.Parse(endpoint.Endpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error parsing endpoint %q for host %q: %w\", endpoint.Endpoint, host, err)\n\t\t\t}\n\n\t\t\ttransport := newTransport()\n\t\t\tclient := &http.Client{Transport: transport}\n\n\t\t\tregistryTLSConfig := reg.TLSs()[u.Host]\n\t\t\tregistryAuthConfig := reg.Auths()[u.Host]\n\n\t\t\tif u.Scheme != \"https\" && registryTLSConfig != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"TLS config specified for non-HTTPS registry: %q\", u.Host)\n\t\t\t}\n\n\t\t\tif registryTLSConfig != nil {\n\t\t\t\ttransport.TLSClientConfig, err = registryTLSConfig.GetTLSConfig()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"error preparing TLS config for %q: %w\", u.Host, err)\n\t\t\t\t}\n\n\t\t\t\t// set up refreshing Root CAs if none were provided\n\t\t\t\tif transport.TLSClientConfig.RootCAs == nil {\n\t\t\t\t\ttransport.TLSClientConfig.RootCAs = httpdefaults.RootCAs()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif u.Path == \"\" {\n\t\t\t\tif !endpoint.OverridePath {\n\t\t\t\t\tu.Path = \"/v2\"\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tu.Path = path.Clean(u.Path)\n\n\t\t\t\tif !strings.HasSuffix(u.Path, \"/v2\") && !endpoint.OverridePath {\n\t\t\t\t\tu.Path += \"/v2\"\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuu := u\n\n\t\t\tregistries = append(registries, docker.RegistryHost{\n\t\t\t\tClient: client,\n\t\t\t\tAuthorizer: docker.NewDockerAuthorizer(\n\t\t\t\t\tdocker.WithAuthClient(client),\n\t\t\t\t\tdocker.WithAuthCreds(func(host string) (string, string, error) {\n\t\t\t\t\t\tif registryAuthConfig == nil {\n\t\t\t\t\t\t\treturn \"\", \"\", nil\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn PrepareAuth(registryAuthConfig, uu.Host, host)\n\t\t\t\t\t})),\n\t\t\t\tHost:         uu.Host,\n\t\t\t\tScheme:       uu.Scheme,\n\t\t\t\tPath:         uu.Path,\n\t\t\t\tCapabilities: docker.HostCapabilityResolve | docker.HostCapabilityPull,\n\t\t\t})\n\t\t}\n\n\t\treturn registries, nil\n\t}\n}\n\n// EndpointEntry represents a registry endpoint.\ntype EndpointEntry struct {\n\tEndpoint     string\n\tOverridePath bool\n}\n\n// RegistryEndpointEntriesFromConfig returns registry endpoints per host.\nfunc RegistryEndpointEntriesFromConfig(host string, reg config.RegistryMirrorConfig) ([]EndpointEntry, error) {\n\tentries := xslices.Map(reg.Endpoints(), func(endpoint config.RegistryEndpointConfig) EndpointEntry {\n\t\treturn EndpointEntry{Endpoint: endpoint.Endpoint(), OverridePath: endpoint.OverridePath()}\n\t})\n\n\tif reg.SkipFallback() {\n\t\treturn entries, nil\n\t}\n\n\tdefaultHost, err := docker.DefaultHost(host)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting default host for %q: %w\", host, err)\n\t}\n\n\tentries = append(entries, EndpointEntry{Endpoint: \"https://\" + defaultHost, OverridePath: false})\n\n\treturn entries, nil\n}\n\n// RegistryEndpoints returns registry endpoints per host using reg.\nfunc RegistryEndpoints(reg cri.Registries, host string) (endpoints []EndpointEntry, err error) {\n\t// direct hit by host\n\tif hostConfig, ok := reg.Mirrors()[host]; ok {\n\t\treturn RegistryEndpointEntriesFromConfig(host, hostConfig)\n\t}\n\n\t// '*'\n\tif catchAllConfig, ok := reg.Mirrors()[\"*\"]; ok {\n\t\treturn RegistryEndpointEntriesFromConfig(host, catchAllConfig)\n\t}\n\n\t// still no endpoints, use default\n\tdefaultHost, err := docker.DefaultHost(host)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting default host for %q: %w\", host, err)\n\t}\n\n\treturn []EndpointEntry{\n\t\t{\n\t\t\tEndpoint:     \"https://\" + defaultHost,\n\t\t\tOverridePath: false,\n\t\t},\n\t}, nil\n}\n\n// PrepareAuth returns authentication info in the format expected by containerd.\nfunc PrepareAuth(auth config.RegistryAuthConfig, host, expectedHost string) (string, string, error) {\n\tif auth == nil {\n\t\treturn \"\", \"\", nil\n\t}\n\n\tif expectedHost != host {\n\t\t// don't pass auth to unknown hosts\n\t\treturn \"\", \"\", nil\n\t}\n\n\tif auth.Username() != \"\" {\n\t\treturn auth.Username(), auth.Password(), nil\n\t}\n\n\tif auth.IdentityToken() != \"\" {\n\t\treturn \"\", auth.IdentityToken(), nil\n\t}\n\n\tif auth.Auth() != \"\" {\n\t\tdecLen := base64.StdEncoding.DecodedLen(len(auth.Auth()))\n\t\tdecoded := make([]byte, decLen)\n\n\t\t_, err := base64.StdEncoding.Decode(decoded, []byte(auth.Auth()))\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"error parsing auth for %q: %w\", host, err)\n\t\t}\n\n\t\tfields := strings.SplitN(string(decoded), \":\", 2)\n\t\tif len(fields) != 2 {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"invalid decoded auth for %q: %q\", host, decoded)\n\t\t}\n\n\t\tuser, password := fields[0], fields[1]\n\n\t\treturn user, strings.Trim(password, \"\\x00\"), nil\n\t}\n\n\treturn \"\", \"\", fmt.Errorf(\"invalid auth config for %q\", host)\n}\n\n// newTransport creates HTTP transport with default settings.\nfunc newTransport() *http.Transport {\n\treturn httpdefaults.PatchTransport(cleanhttp.DefaultTransport())\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/resolver_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage image_test\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/opencontainers/go-digest\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\ntype mockConfig struct {\n\tmirrors map[string]*cri.RegistryMirrorConfig\n\tauths   map[string]*cri.RegistryAuthConfig\n\ttlses   map[string]*cri.RegistryTLSConfig\n}\n\nfunc (c *mockConfig) Mirrors() map[string]config.RegistryMirrorConfig {\n\tmirrors := make(map[string]config.RegistryMirrorConfig, len(c.mirrors))\n\n\tfor k, v := range c.mirrors {\n\t\tmirrors[k] = v\n\t}\n\n\treturn mirrors\n}\n\nfunc (c *mockConfig) Auths() map[string]config.RegistryAuthConfig {\n\tauths := make(map[string]config.RegistryAuthConfig, len(c.auths))\n\n\tfor k, v := range c.auths {\n\t\tauths[k] = v\n\t}\n\n\treturn auths\n}\n\nfunc (c *mockConfig) TLSs() map[string]cri.RegistryTLSConfigExtended {\n\tregistries := make(map[string]cri.RegistryTLSConfigExtended, len(c.tlses))\n\n\tfor k, v := range c.tlses {\n\t\tregistries[k] = v\n\t}\n\n\treturn registries\n}\n\ntype ResolverSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *ResolverSuite) TestRegistryEndpoints() {\n\ttype request struct {\n\t\thost string\n\n\t\texpectedEndpoints []image.EndpointEntry\n\t}\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tconfig *mockConfig\n\n\t\trequests []request\n\t}{\n\t\t{\n\t\t\tname:   \"no config\",\n\t\t\tconfig: &mockConfig{},\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://registry-1.docker.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"quay.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://quay.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"config with mirror and no fallback\",\n\t\t\tconfig: &mockConfig{\n\t\t\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5000\"},\n\t\t\t\t\t\t\t{EndpointEndpoint: \"https://some.host\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMirrorSkipFallback: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5000\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://some.host\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"quay.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://quay.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"config with mirror and fallback\",\n\t\t\tconfig: &mockConfig{\n\t\t\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\t\t\"ghcr.io\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5000\"},\n\t\t\t\t\t\t\t{EndpointEndpoint: \"https://some.host\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"ghcr.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5000\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://some.host\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://ghcr.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://registry-1.docker.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"config with catch-all and no fallback\",\n\t\t\tconfig: &mockConfig{\n\t\t\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5000\"},\n\t\t\t\t\t\t\t{EndpointEndpoint: \"https://some.host\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMirrorSkipFallback: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"*\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5001\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMirrorSkipFallback: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5000\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://some.host\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"quay.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5001\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"config with catch-all and fallback\",\n\t\t\tconfig: &mockConfig{\n\t\t\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\t\t\"*\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5001\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5001\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://registry-1.docker.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"quay.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"http://127.0.0.1:5001\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://quay.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"config with override path\",\n\t\t\tconfig: &mockConfig{\n\t\t\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\t\t\"docker.io\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpointEndpoint:     \"https://harbor/v2/registry.docker.io\",\n\t\t\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMirrorSkipFallback: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"ghcr.io\": {\n\t\t\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tEndpointEndpoint:     \"https://harbor/v2/registry.ghcr.io\",\n\t\t\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\trequests: []request{\n\t\t\t\t{\n\t\t\t\t\thost: \"docker.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint:     \"https://harbor/v2/registry.docker.io\",\n\t\t\t\t\t\t\tOverridePath: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"ghcr.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint:     \"https://harbor/v2/registry.ghcr.io\",\n\t\t\t\t\t\t\tOverridePath: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://ghcr.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\thost: \"quay.io\",\n\t\t\t\t\texpectedEndpoints: []image.EndpointEntry{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEndpoint: \"https://quay.io\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tsuite.Run(tt.name, func() {\n\t\t\tfor _, req := range tt.requests {\n\t\t\t\tsuite.Run(req.host, func() {\n\t\t\t\t\tendpoints, err := image.RegistryEndpoints(tt.config, req.host)\n\n\t\t\t\t\tsuite.Assert().NoError(err)\n\t\t\t\t\tsuite.Assert().Equal(req.expectedEndpoints, endpoints)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc (suite *ResolverSuite) TestPrepareAuth() {\n\tuser, pass, err := image.PrepareAuth(nil, \"docker.io\", \"docker.io\")\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Equal(\"\", user)\n\tsuite.Assert().Equal(\"\", pass)\n\n\tuser, pass, err = image.PrepareAuth(&cri.RegistryAuthConfig{\n\t\tRegistryUsername: \"root\",\n\t\tRegistryPassword: \"secret\",\n\t}, \"docker.io\", \"not.docker.io\")\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Equal(\"\", user)\n\tsuite.Assert().Equal(\"\", pass)\n\n\tuser, pass, err = image.PrepareAuth(&cri.RegistryAuthConfig{\n\t\tRegistryUsername: \"root\",\n\t\tRegistryPassword: \"secret\",\n\t}, \"docker.io\", \"docker.io\")\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Equal(\"root\", user)\n\tsuite.Assert().Equal(\"secret\", pass)\n\n\tuser, pass, err = image.PrepareAuth(&cri.RegistryAuthConfig{\n\t\tRegistryIdentityToken: \"xyz\",\n\t}, \"docker.io\", \"docker.io\")\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Equal(\"\", user)\n\tsuite.Assert().Equal(\"xyz\", pass)\n\n\tuser, pass, err = image.PrepareAuth(&cri.RegistryAuthConfig{\n\t\tRegistryAuth: \"dXNlcjE6c2VjcmV0MQ==\",\n\t}, \"docker.io\", \"docker.io\")\n\tsuite.Assert().NoError(err)\n\tsuite.Assert().Equal(\"user1\", user)\n\tsuite.Assert().Equal(\"secret1\", pass)\n\n\t_, _, err = image.PrepareAuth(&cri.RegistryAuthConfig{}, \"docker.io\", \"docker.io\")\n\tsuite.Assert().EqualError(err, \"invalid auth config for \\\"docker.io\\\"\")\n}\n\nfunc (suite *ResolverSuite) TestRegistryHosts() {\n\tregistryHosts, err := image.RegistryHosts(&mockConfig{})(\"docker.io\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Len(registryHosts, 1)\n\tsuite.Assert().Equal(\"https\", registryHosts[0].Scheme)\n\tsuite.Assert().Equal(\"registry-1.docker.io\", registryHosts[0].Host)\n\tsuite.Assert().Equal(\"/v2\", registryHosts[0].Path)\n\tsuite.Assert().Nil(registryHosts[0].Client.Transport.(*http.Transport).TLSClientConfig.Certificates)\n\n\tcfg := &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{EndpointEndpoint: \"http://127.0.0.1:5000/docker.io\"},\n\t\t\t\t\t{EndpointEndpoint: \"https://some.host\"},\n\t\t\t\t},\n\t\t\t\tMirrorSkipFallback: true,\n\t\t\t},\n\t\t\t\"ghcr.io\": {\n\t\t\t\tMirrorEndpoints: []cri.RegistryEndpointConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointEndpoint:     \"https://harbor/v2/registry.ghcr.io\",\n\t\t\t\t\t\tEndpointOverridePath: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMirrorSkipFallback: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tregistryHosts, err = image.RegistryHosts(cfg)(\"docker.io\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Len(registryHosts, 2)\n\tsuite.Assert().Equal(\"http\", registryHosts[0].Scheme)\n\tsuite.Assert().Equal(\"127.0.0.1:5000\", registryHosts[0].Host)\n\tsuite.Assert().Equal(\"/docker.io/v2\", registryHosts[0].Path)\n\tsuite.Assert().Nil(registryHosts[0].Client.Transport.(*http.Transport).TLSClientConfig.Certificates)\n\tsuite.Assert().Equal(\"https\", registryHosts[1].Scheme)\n\tsuite.Assert().Equal(\"some.host\", registryHosts[1].Host)\n\tsuite.Assert().Equal(\"/v2\", registryHosts[1].Path)\n\tsuite.Assert().Nil(registryHosts[1].Client.Transport.(*http.Transport).TLSClientConfig.Certificates)\n\n\tregistryHosts, err = image.RegistryHosts(cfg)(\"ghcr.io\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Len(registryHosts, 1)\n\tsuite.Assert().Equal(\"https\", registryHosts[0].Scheme)\n\tsuite.Assert().Equal(\"harbor\", registryHosts[0].Host)\n\tsuite.Assert().Equal(\"/v2/registry.ghcr.io\", registryHosts[0].Path)\n\n\tcfg = &mockConfig{\n\t\tmirrors: map[string]*cri.RegistryMirrorConfig{\n\t\t\t\"docker.io\": {\n\t\t\t\tMirrorEndpoints:    []cri.RegistryEndpointConfig{{EndpointEndpoint: \"https://some.host:123\"}},\n\t\t\t\tMirrorSkipFallback: true,\n\t\t\t},\n\t\t},\n\t\tauths: map[string]*cri.RegistryAuthConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tRegistryUsername: \"root\",\n\t\t\t\tRegistryPassword: \"secret\",\n\t\t\t},\n\t\t},\n\t\ttlses: map[string]*cri.RegistryTLSConfig{\n\t\t\t\"some.host:123\": {\n\t\t\t\tTLSCA: []byte(caCertMock),\n\t\t\t},\n\t\t},\n\t}\n\n\tregistryHosts, err = image.RegistryHosts(cfg)(\"docker.io\")\n\tsuite.Require().NoError(err)\n\tsuite.Assert().Len(registryHosts, 1)\n\tsuite.Assert().Equal(\"https\", registryHosts[0].Scheme)\n\tsuite.Assert().Equal(\"some.host:123\", registryHosts[0].Host)\n\tsuite.Assert().Equal(\"/v2\", registryHosts[0].Path)\n\n\ttlsClientConfig := registryHosts[0].Client.Transport.(*http.Transport).TLSClientConfig\n\tsuite.Require().NotNil(tlsClientConfig)\n\tsuite.Require().NotNil(tlsClientConfig.RootCAs)\n\tsuite.Require().Empty(tlsClientConfig.Certificates)\n\n\tsuite.Require().NotNil(registryHosts[0].Authorizer)\n\n\treq, err := http.NewRequest(http.MethodGet, \"htts://some.host:123/v2\", nil) //nolint:noctx\n\tsuite.Require().NoError(err)\n\n\tresp := &http.Response{}\n\tresp.Request = req\n\tresp.Header = http.Header{}\n\tresp.Header.Add(\"Www-Authenticate\", \"Basic realm=\\\"Access to the staging site\\\", charset=\\\"UTF-8\\\"\")\n\n\tsuite.Require().NoError(registryHosts[0].Authorizer.AddResponses(context.Background(), []*http.Response{resp}))\n\tsuite.Require().NoError(registryHosts[0].Authorizer.Authorize(context.Background(), req))\n\n\tsuite.Assert().Equal(\"Basic cm9vdDpzZWNyZXQ=\", req.Header.Get(\"Authorization\"))\n}\n\nfunc (suite *ResolverSuite) TestResolveTag() {\n\tresolver := image.NewResolver(&mockConfig{})\n\n\tname, desc, err := resolver.Resolve(suite.T().Context(), \"ghcr.io/siderolabs/talos:v1.12.0\")\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().Equal(\"ghcr.io/siderolabs/talos:v1.12.0\", name)\n\tsuite.Assert().Equal(digest.Digest(\"sha256:342707af87028596549bb68882654f90122cbbaf29cb2a537dfbc8b1b7770898\"), desc.Digest)\n}\n\nfunc TestResolverSuite(t *testing.T) {\n\tt.Parallel()\n\n\tsuite.Run(t, new(ResolverSuite))\n}\n\nconst caCertMock = `-----BEGIN CERTIFICATE-----\nMIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC\nVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T\nU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0\naW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz\nWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0\nb24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS\nb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB\nBAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI\n7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg\nCemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud\nEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD\nVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T\nkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+\ngA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl\n-----END CERTIFICATE-----\n`\n"
  },
  {
    "path": "internal/pkg/containers/image/verify/internal/cosign/cosign.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cosign provides cosign-based image signature verification via Talos pull process.\npackage cosign\n\nimport (\n\t\"context\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/containerd/containerd/v2/core/remotes\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\tdigest \"github.com/opencontainers/go-digest\"\n\tocispec \"github.com/opencontainers/image-spec/specs-go/v1\"\n\t\"github.com/sigstore/cosign/v3/pkg/cosign\"\n\t\"github.com/sigstore/cosign/v3/pkg/cosign/bundle\"\n\t\"github.com/sigstore/cosign/v3/pkg/oci\"\n\t\"github.com/sigstore/cosign/v3/pkg/oci/static\"\n\tsgbundle \"github.com/sigstore/sigstore-go/pkg/bundle\"\n\t\"github.com/sigstore/sigstore-go/pkg/verify\"\n\t\"go.uber.org/zap\"\n)\n\nconst (\n\tmaxManifestSize = 128 * 1024\n\tmaxBundleSize   = 1024 * 1024\n\tmaxPayloadSize  = 1024 * 1024\n\tmaxLayers       = 100\n\n\tsigstoreBundleMediaTypePrefix = \"application/vnd.dev.sigstore.bundle\"\n\tsigstoreBundleV03ArtifactType = \"application/vnd.dev.sigstore.bundle.v0.3+json\"\n)\n\n// VerifyResult represents the result of a signature verification attempt.\ntype VerifyResult struct {\n\tMessage string\n}\n\n// VerifyImage verifies the given image reference and digest against the provided verification configuration.\n//\n// It checks in priority order:\n//  1. OCI referrers API for new-style sigstore bundles (sha256:xxx referrers).\n//  2. The bundle tag (sha256-xxx, no .sig suffix) for new-style sigstore bundles stored as a tag.\n//  3. The legacy .sig tag (sha256-xxx.sig) for legacy cosign signature layers.\n//\n// All registry I/O goes through the provided resolver, which handles authentication and mirror routing.\n//\n// The verifiers are in opts, if any of the verifiers returns true for bundle verification, the image is considered verified.\nfunc VerifyImage(ctx context.Context, logger *zap.Logger, resolver remotes.Resolver, imageRef name.Digest, co cosign.CheckOpts) (*VerifyResult, error) {\n\tlogger = logger.With(zap.Stringer(\"image\", imageRef))\n\n\timageDigest, err := v1.NewHash(imageRef.DigestStr())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse image digest: %w\", err)\n\t}\n\n\tdigestBytes, err := hex.DecodeString(imageDigest.Hex)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode digest hex: %w\", err)\n\t}\n\n\tartifactPolicyOption := verify.WithArtifactDigest(imageDigest.Algorithm, digestBytes)\n\n\t// Step 1: try OCI referrers for new-style sigstore bundles.\n\tfetcher, err := resolver.Fetcher(ctx, imageRef.Name())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get fetcher: %w\", err)\n\t}\n\n\tif refFetcher, ok := fetcher.(remotes.ReferrersFetcher); ok {\n\t\treferrers, err := refFetcher.FetchReferrers(ctx, digest.Digest(imageRef.DigestStr()),\n\t\t\tremotes.WithReferrerArtifactTypes(sigstoreBundleV03ArtifactType))\n\t\tif err == nil {\n\t\t\tbundleRefs := filterBundleReferrers(referrers)\n\t\t\tif len(bundleRefs) > 0 {\n\t\t\t\tlogger.Debug(\"verifying via OCI referrer bundles\", zap.Int(\"count\", len(bundleRefs)))\n\n\t\t\t\treturn verifyBundleReferrers(ctx, logger, fetcher, bundleRefs, artifactPolicyOption, co)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Step 2: try bundle tag (sha256-xxx) for new-style sigstore bundles stored as a tag.\n\tlogger.Debug(\"no bundle referrers found, trying bundle tag\")\n\n\tverified, result, bundleErr := verifyFromBundleTag(ctx, logger, resolver, imageRef, artifactPolicyOption, co)\n\n\tif verified {\n\t\treturn result, bundleErr\n\t}\n\n\t// Step 3: fall back to the legacy .sig tag (sha256-xxx.sig).\n\tlogger.Debug(\"no bundle tag found, falling back to legacy .sig tag\")\n\n\tresult, legacyErr := verifyFromLegacySigTag(ctx, logger, resolver, imageRef, imageDigest, co)\n\tif legacyErr != nil {\n\t\treturn nil, fmt.Errorf(\"no valid signature found: %w\", errors.Join(bundleErr, legacyErr))\n\t}\n\n\treturn result, nil\n}\n\n// filterBundleReferrers returns only referrers whose ArtifactType indicates a sigstore bundle.\nfunc filterBundleReferrers(referrers []ocispec.Descriptor) []ocispec.Descriptor {\n\tvar out []ocispec.Descriptor\n\n\tfor _, r := range referrers {\n\t\tif strings.HasPrefix(r.ArtifactType, sigstoreBundleMediaTypePrefix) {\n\t\t\tout = append(out, r)\n\t\t}\n\t}\n\n\treturn out\n}\n\n// verifyBundleReferrers verifies a set of OCI referrer descriptors as new-style sigstore bundles.\n//\n// Each referrer points to an OCI image manifest whose single layer contains the sigstore bundle JSON.\nfunc verifyBundleReferrers(\n\tctx context.Context, logger *zap.Logger, fetcher remotes.Fetcher, referrers []ocispec.Descriptor, artifactPolicyOption verify.ArtifactPolicyOption, co cosign.CheckOpts,\n) (*VerifyResult, error) {\n\tvar lastErr error\n\n\tfor _, referrer := range referrers {\n\t\tb, err := fetchBundleFromReferrer(ctx, fetcher, referrer)\n\t\tif err != nil {\n\t\t\tlogger.Debug(\"failed to fetch bundle referrer\", zap.String(\"digest\", referrer.Digest.String()), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tco.NewBundleFormat = true\n\n\t\tif _, err := cosign.VerifyNewBundle(ctx, &co, artifactPolicyOption, b); err != nil {\n\t\t\tlogger.Debug(\"bundle referrer verification failed\", zap.String(\"digest\", referrer.Digest.String()), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.Debug(\"bundle referrer verified\", zap.String(\"digest\", referrer.Digest.String()))\n\n\t\treturn &VerifyResult{\n\t\t\tMessage: fmt.Sprintf(\"verified via bundle referrer with digest %s\", referrer.Digest.String()),\n\t\t}, nil\n\t}\n\n\tif lastErr != nil {\n\t\treturn nil, fmt.Errorf(\"no valid bundle referrer: %w\", lastErr)\n\t}\n\n\treturn nil, errors.New(\"no valid bundle referrers\")\n}\n\n// verifyFromBundleTag fetches the bundle tag (sha256-xxx, no .sig suffix) and verifies via\n// new-style sigstore bundle layers.\n//\n// Returns (true, nil) if a bundle was successfully verified, (true, err) if bundle layers were\n// found but verification failed, and (false, nil) if the tag was not found or had no bundle layers.\n//\n//nolint:gocyclo\nfunc verifyFromBundleTag(\n\tctx context.Context, logger *zap.Logger, resolver remotes.Resolver, imageRef name.Digest, artifactPolicyOption verify.ArtifactPolicyOption, co cosign.CheckOpts,\n) (bool, *VerifyResult, error) {\n\tbundleTag := strings.ReplaceAll(imageRef.DigestStr(), \":\", \"-\")\n\n\tlogger.Debug(\"resolving bundle tag\", zap.String(\"bundleTag\", bundleTag))\n\n\tresolvedName, desc, err := resolver.Resolve(ctx, imageRef.Repository.Name()+\":\"+bundleTag)\n\tif err != nil {\n\t\tlogger.Debug(\"bundle tag not found\", zap.String(\"bundleTag\", bundleTag), zap.Error(err))\n\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn false, nil, errors.New(\"bundle tag not found\")\n\t\t}\n\n\t\treturn false, nil, fmt.Errorf(\"failed to resolve bundle tag %s: %w\", bundleTag, err)\n\t}\n\n\tlogger.Debug(\"resolved bundle tag\", zap.String(\"name\", resolvedName), zap.String(\"media_type\", desc.MediaType))\n\n\tfetcher, err := resolver.Fetcher(ctx, resolvedName)\n\tif err != nil {\n\t\treturn false, nil, fmt.Errorf(\"failed to get fetcher for bundle tag: %w\", err)\n\t}\n\n\tvar bundleLayers []ocispec.Descriptor\n\n\tswitch desc.MediaType {\n\tcase ocispec.MediaTypeImageManifest:\n\t\tmanifest, err := fetchManifest(ctx, fetcher, desc)\n\t\tif err != nil {\n\t\t\treturn false, nil, fmt.Errorf(\"failed to fetch bundle manifest: %w\", err)\n\t\t}\n\n\t\tfor _, layer := range manifest.Layers[:min(maxLayers, len(manifest.Layers))] {\n\t\t\tif strings.HasPrefix(layer.MediaType, sigstoreBundleMediaTypePrefix) {\n\t\t\t\tbundleLayers = append(bundleLayers, layer)\n\t\t\t}\n\t\t}\n\tcase ocispec.MediaTypeImageIndex:\n\t\t// The bundle tag may be an OCI image index wrapping individual bundle manifests.\n\t\t// Walk each manifest entry and collect bundle layers from all of them.\n\t\tindex, err := fetchIndex(ctx, fetcher, desc)\n\t\tif err != nil {\n\t\t\treturn false, nil, fmt.Errorf(\"failed to fetch bundle index: %w\", err)\n\t\t}\n\n\t\tfor _, manifestDesc := range index.Manifests[:min(maxLayers, len(index.Manifests))] {\n\t\t\tif manifestDesc.MediaType != ocispec.MediaTypeImageManifest {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tmanifest, err := fetchManifest(ctx, fetcher, manifestDesc)\n\t\t\tif err != nil {\n\t\t\t\tlogger.Debug(\"failed to fetch manifest from bundle index\", zap.String(\"digest\", manifestDesc.Digest.String()), zap.Error(err))\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, layer := range manifest.Layers[:min(maxLayers, len(manifest.Layers))] {\n\t\t\t\tif strings.HasPrefix(layer.MediaType, sigstoreBundleMediaTypePrefix) {\n\t\t\t\t\tbundleLayers = append(bundleLayers, layer)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tdefault:\n\t\tlogger.Debug(\"unexpected media type for bundle tag, skipping\", zap.String(\"media_type\", desc.MediaType))\n\n\t\treturn false, nil, nil\n\t}\n\n\tif len(bundleLayers) == 0 {\n\t\tlogger.Debug(\"no bundle layers found in bundle tag\")\n\n\t\treturn false, nil, nil\n\t}\n\n\tresult, err := verifyBundleLayers(ctx, logger, fetcher, bundleLayers, artifactPolicyOption, co)\n\n\treturn true, result, err\n}\n\n// verifyFromLegacySigTag fetches the legacy .sig tag (sha256-xxx.sig) and verifies via legacy\n// cosign signature layers.\nfunc verifyFromLegacySigTag(ctx context.Context, logger *zap.Logger, resolver remotes.Resolver, imageRef name.Digest, imageDigest v1.Hash, co cosign.CheckOpts) (*VerifyResult, error) {\n\tsignatureTag := strings.ReplaceAll(imageRef.DigestStr(), \":\", \"-\") + \".sig\"\n\n\tlogger.Debug(\"resolving .sig tag\", zap.String(\"signatureTag\", signatureTag))\n\n\tresolvedName, desc, err := resolver.Resolve(ctx, imageRef.Repository.Name()+\":\"+signatureTag)\n\tif err != nil {\n\t\tif errdefs.IsNotFound(err) {\n\t\t\treturn nil, fmt.Errorf(\"legacy signature tag not found\")\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to resolve .sig tag %s: %w\", signatureTag, err)\n\t}\n\n\tlogger.Debug(\"resolved .sig manifest\", zap.String(\"name\", resolvedName), zap.String(\"media_type\", desc.MediaType))\n\n\tif desc.MediaType != ocispec.MediaTypeImageManifest {\n\t\treturn nil, fmt.Errorf(\"unexpected media type for .sig manifest: %s\", desc.MediaType)\n\t}\n\n\tfetcher, err := resolver.Fetcher(ctx, resolvedName)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get fetcher for .sig manifest: %w\", err)\n\t}\n\n\tmanifest, err := fetchManifest(ctx, fetcher, desc)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch .sig manifest: %w\", err)\n\t}\n\n\tlegacyLayers := manifest.Layers[:min(maxLayers, len(manifest.Layers))]\n\n\treturn verifyLegacyLayers(ctx, logger, fetcher, legacyLayers, imageDigest, co)\n}\n\n// verifyBundleLayers verifies layers from a .sig manifest that carry sigstore bundle JSON directly.\nfunc verifyBundleLayers(\n\tctx context.Context, logger *zap.Logger, fetcher remotes.Fetcher, layers []ocispec.Descriptor, artifactPolicyOption verify.ArtifactPolicyOption, co cosign.CheckOpts,\n) (*VerifyResult, error) {\n\tvar lastErr error\n\n\tfor i, layer := range layers {\n\t\tb, err := fetchBundleFromLayer(ctx, fetcher, layer)\n\t\tif err != nil {\n\t\t\tlogger.Debug(\"failed to fetch bundle layer\", zap.Int(\"layer\", i), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tco.NewBundleFormat = true\n\n\t\tif _, err := cosign.VerifyNewBundle(ctx, &co, artifactPolicyOption, b); err != nil {\n\t\t\tlogger.Debug(\"bundle layer verification failed\", zap.Int(\"layer\", i), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.Debug(\"bundle layer verified\", zap.Int(\"layer\", i))\n\n\t\treturn &VerifyResult{\n\t\t\tMessage: \"verified via bundle\",\n\t\t}, nil\n\t}\n\n\tif lastErr != nil {\n\t\treturn nil, fmt.Errorf(\"no valid bundle layer: %w\", lastErr)\n\t}\n\n\treturn nil, errors.New(\"no valid bundle layers\")\n}\n\n// verifyLegacyLayers verifies layers from a .sig manifest as legacy cosign signatures.\nfunc verifyLegacyLayers(ctx context.Context, logger *zap.Logger, fetcher remotes.Fetcher, layers []ocispec.Descriptor, imageDigest v1.Hash, co cosign.CheckOpts) (*VerifyResult, error) {\n\tvar lastErr error\n\n\tfor i, layer := range layers {\n\t\tsig, err := buildLegacySignature(ctx, fetcher, layer)\n\t\tif err != nil {\n\t\t\tlogger.Debug(\"failed to build legacy signature from layer\", zap.Int(\"layer\", i), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tco.NewBundleFormat = false\n\n\t\tbundleVerified, err := cosign.VerifyImageSignature(ctx, sig, imageDigest, &co)\n\t\tif err != nil {\n\t\t\tlogger.Debug(\"legacy signature verification failed\", zap.Int(\"layer\", i), zap.Error(err))\n\t\t\tlastErr = err\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.Debug(\"legacy signature verified\", zap.Int(\"layer\", i), zap.Bool(\"bundle_verified\", bundleVerified))\n\n\t\treturn &VerifyResult{\n\t\t\tMessage: fmt.Sprintf(\"verified via legacy signature (bundle verified %v)\", bundleVerified),\n\t\t}, nil\n\t}\n\n\tif lastErr != nil {\n\t\treturn nil, fmt.Errorf(\"no valid legacy signature: %w\", lastErr)\n\t}\n\n\treturn nil, errors.New(\"no legacy signatures found\")\n}\n\n// fetchManifest fetches and decodes an OCI image manifest descriptor.\n//\n//nolint:dupl // not a duplicate!\nfunc fetchManifest(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor) (ocispec.Manifest, error) {\n\trc, err := fetcher.Fetch(ctx, desc)\n\tif err != nil {\n\t\treturn ocispec.Manifest{}, fmt.Errorf(\"failed to fetch: %w\", err)\n\t}\n\n\tdefer rc.Close() //nolint:errcheck\n\n\tvar manifest ocispec.Manifest\n\tif err := json.NewDecoder(io.LimitReader(rc, maxManifestSize)).Decode(&manifest); err != nil {\n\t\treturn ocispec.Manifest{}, fmt.Errorf(\"failed to decode manifest: %w\", err)\n\t}\n\n\treturn manifest, nil\n}\n\n// fetchIndex fetches and decodes an OCI image index descriptor.\n//\n//nolint:dupl // not a duplicate!\nfunc fetchIndex(ctx context.Context, fetcher remotes.Fetcher, desc ocispec.Descriptor) (ocispec.Index, error) {\n\trc, err := fetcher.Fetch(ctx, desc)\n\tif err != nil {\n\t\treturn ocispec.Index{}, fmt.Errorf(\"failed to fetch: %w\", err)\n\t}\n\n\tdefer rc.Close() //nolint:errcheck\n\n\tvar index ocispec.Index\n\tif err := json.NewDecoder(io.LimitReader(rc, maxManifestSize)).Decode(&index); err != nil {\n\t\treturn ocispec.Index{}, fmt.Errorf(\"failed to decode index: %w\", err)\n\t}\n\n\treturn index, nil\n}\n\n// fetchBundleFromReferrer fetches a sigstore bundle stored as an OCI referrer.\n//\n// The referrer descriptor points to an OCI image manifest whose single layer contains the\n// sigstore bundle JSON (media type application/vnd.dev.sigstore.bundle.v0.3+json).\nfunc fetchBundleFromReferrer(ctx context.Context, fetcher remotes.Fetcher, referrer ocispec.Descriptor) (*sgbundle.Bundle, error) {\n\tmanifest, err := fetchManifest(ctx, fetcher, referrer)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch bundle manifest: %w\", err)\n\t}\n\n\tif len(manifest.Layers) != 1 {\n\t\treturn nil, fmt.Errorf(\"expected exactly one layer in bundle manifest, got %d\", len(manifest.Layers))\n\t}\n\n\treturn fetchBundleFromLayer(ctx, fetcher, manifest.Layers[0])\n}\n\n// fetchBundleFromLayer fetches a sigstore bundle stored directly as a .sig manifest layer.\n//\n// The layer content is the sigstore bundle JSON.\nfunc fetchBundleFromLayer(ctx context.Context, fetcher remotes.Fetcher, layer ocispec.Descriptor) (*sgbundle.Bundle, error) {\n\trc, err := fetcher.Fetch(ctx, layer)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch bundle layer: %w\", err)\n\t}\n\n\tdefer rc.Close() //nolint:errcheck\n\n\tbundleBytes, err := io.ReadAll(io.LimitReader(rc, maxBundleSize))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read bundle layer: %w\", err)\n\t}\n\n\tb := &sgbundle.Bundle{}\n\tif err := b.UnmarshalJSON(bundleBytes); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse sigstore bundle: %w\", err)\n\t}\n\n\tif !b.MinVersion(\"v0.3\") {\n\t\treturn nil, errors.New(\"bundle version too old (requires v0.3+)\")\n\t}\n\n\treturn b, nil\n}\n\n// buildLegacySignature constructs an oci.Signature from a cosign legacy signature layer.\n//\n// The layer content is the simple signing payload (the data that was signed). The cryptographic\n// signature and optional certificate/chain/Rekor bundle are read from the layer annotations.\nfunc buildLegacySignature(ctx context.Context, fetcher remotes.Fetcher, layer ocispec.Descriptor) (oci.Signature, error) {\n\t// Fetch the layer content: the simple signing payload (what was signed).\n\trc, err := fetcher.Fetch(ctx, layer)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to fetch signature layer: %w\", err)\n\t}\n\n\tdefer rc.Close() //nolint:errcheck\n\n\tpayload, err := io.ReadAll(io.LimitReader(rc, maxPayloadSize))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read signature layer: %w\", err)\n\t}\n\n\t// Base64-encoded cryptographic signature from layer annotation.\n\tb64sig, ok := layer.Annotations[static.SignatureAnnotationKey]\n\tif !ok {\n\t\treturn nil, errors.New(\"missing signature annotation\")\n\t}\n\n\tvar staticOpts []static.Option\n\n\t// Certificate and intermediate chain for keyless (Fulcio-issued) signing.\n\tif certPEM, ok := layer.Annotations[static.CertificateAnnotationKey]; ok {\n\t\tchainPEM := layer.Annotations[static.ChainAnnotationKey]\n\n\t\tstaticOpts = append(staticOpts, static.WithCertChain([]byte(certPEM), []byte(chainPEM)))\n\t}\n\n\t// Rekor transparency log bundle, if present.\n\tif bundleJSON, ok := layer.Annotations[static.BundleAnnotationKey]; ok {\n\t\tvar rb bundle.RekorBundle\n\t\tif err := json.Unmarshal([]byte(bundleJSON), &rb); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse Rekor bundle annotation: %w\", err)\n\t\t}\n\n\t\tstaticOpts = append(staticOpts, static.WithBundle(&rb))\n\t}\n\n\treturn static.NewSignature(payload, b64sig, staticOpts...)\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/verify/internal/cosign/cosign_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cosign_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/sigstore/cosign/v3/pkg/cosign\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\tourcosign \"github.com/siderolabs/talos/internal/pkg/containers/image/verify/internal/cosign\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\ntype mockRegistriesConfig struct{}\n\nfunc (mockRegistriesConfig) Mirrors() map[string]config.RegistryMirrorConfig {\n\treturn nil\n}\n\nfunc (mockRegistriesConfig) Auths() map[string]config.RegistryAuthConfig {\n\treturn nil\n}\n\nfunc (mockRegistriesConfig) TLSs() map[string]cri.RegistryTLSConfigExtended {\n\treturn nil\n}\n\nfunc TestVerifyImage(t *testing.T) {\n\tt.Parallel()\n\n\tresolver := image.NewResolver(mockRegistriesConfig{})\n\ttrustedRoot, err := cosign.TrustedRoot()\n\trequire.NoError(t, err)\n\n\tfor _, test := range []struct {\n\t\timageRef string\n\n\t\tcheckOpts cosign.CheckOpts\n\n\t\texpectedResultMessage string\n\t\texpectedError         string\n\t}{\n\t\t{\n\t\t\timageRef: \"registry.k8s.io/etcd:v3.6.8@sha256:397189418d1a00e500c0605ad18d1baf3b541a1004d768448c367e48071622e5\",\n\t\t\tcheckOpts: cosign.CheckOpts{\n\t\t\t\tTrustedMaterial: trustedRoot,\n\t\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t\t{\n\t\t\t\t\t\tIssuer:  \"https://accounts.google.com\",\n\t\t\t\t\t\tSubject: \"krel-trust@k8s-releng-prod.iam.gserviceaccount.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedResultMessage: \"verified via legacy signature (bundle verified true)\",\n\t\t},\n\t\t{\n\t\t\timageRef: \"ghcr.io/siderolabs/talos:v1.13.0-alpha.2@sha256:9361de6684b441da62298998ab89166efccca35772afc24fee3ae53c569ec44c\",\n\t\t\tcheckOpts: cosign.CheckOpts{\n\t\t\t\tTrustedMaterial: trustedRoot,\n\t\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t\t{\n\t\t\t\t\t\tIssuer:        \"https://accounts.google.com\",\n\t\t\t\t\t\tSubjectRegExp: \"@siderolabs.com$\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedResultMessage: \"verified via bundle\",\n\t\t},\n\t\t{\n\t\t\timageRef: \"ghcr.io/siderolabs/extensions:v1.13.0-alpha.2@sha256:033cbce24e681208245797e53386b4bef1c4a995a32feebdfa05c5063f889334\",\n\t\t\tcheckOpts: cosign.CheckOpts{\n\t\t\t\tTrustedMaterial: trustedRoot,\n\t\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t\t{\n\t\t\t\t\t\tIssuer:  \"https://accounts.google.com\",\n\t\t\t\t\t\tSubject: \"releasemgr-svc@talos-production.iam.gserviceaccount.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedResultMessage: \"verified via bundle\",\n\t\t},\n\t\t{\n\t\t\timageRef: \"ghcr.io/siderolabs/extensions:v1.13.0-alpha.1-17-gc538dab@sha256:32ed7bb3845215bfd71bf4284a2a5113ecd49ce45cde0324764fe84b378c8633\",\n\t\t\tcheckOpts: cosign.CheckOpts{\n\t\t\t\tTrustedMaterial: trustedRoot,\n\t\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t\t{\n\t\t\t\t\t\tIssuer:  \"https://accounts.google.com\",\n\t\t\t\t\t\tSubject: \"releasemgr-svc@talos-production.iam.gserviceaccount.com\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedError: \"no valid signature found: bundle tag not found\\nlegacy signature tag not found\",\n\t\t},\n\t\t{\n\t\t\timageRef: \"ghcr.io/siderolabs/extensions:v1.13.0-alpha.1@sha256:5c3abcee03ef7369bb92f1f3d76c1afd27ccc97fa2879145a486b554f3091648\",\n\t\t\tcheckOpts: cosign.CheckOpts{\n\t\t\t\tTrustedMaterial: trustedRoot,\n\t\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t\t{\n\t\t\t\t\t\tIssuer:  \"https://some.entity\",\n\t\t\t\t\t\tSubject: \"releasemgr@world\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedError: \"no valid bundle layer: failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SAN \" +\n\t\t\t\t\"value \\\"releasemgr@world\\\", got \\\"releasemgr-svc@talos-production.iam.gserviceaccount.com\\\"\",\n\t\t},\n\t} {\n\t\tt.Run(test.imageRef, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlogger := zaptest.NewLogger(t)\n\n\t\t\timageRef, err := name.NewDigest(test.imageRef)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult, err := ourcosign.VerifyImage(t.Context(), logger, resolver, imageRef, test.checkOpts)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\n\t\t\tassert.Equal(t, test.expectedResultMessage, result.Message)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/containers/image/verify/verify.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package verify provides functionality to verify container images against configured verification policies.\npackage verify\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/containerd/containerd/v2/core/remotes\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/sigstore/cosign/v3/pkg/cosign\"\n\t\"github.com/sigstore/sigstore-go/pkg/root\"\n\t\"github.com/sigstore/sigstore/pkg/cryptoutils\"\n\tsigsig \"github.com/sigstore/sigstore/pkg/signature\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\tourcosign \"github.com/siderolabs/talos/internal/pkg/containers/image/verify/internal/cosign\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\n// ImageSignature verifies image signature within Talos source code.\n//\n//nolint:gocyclo\nfunc ImageSignature(\n\tctx context.Context, logger *zap.Logger, resources state.State, resolver remotes.Resolver, imageRef string,\n) (*machine.ImageServiceVerifyResponse, error) {\n\tlogger = logger.With(zap.String(\"image_ref\", imageRef))\n\n\tinRef, err := name.ParseReference(imageRef)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"image reference is invalid: %s\", err)\n\t}\n\n\truleMatcher, err := security.ImageVerificationRuleMatcher(ctx, resources)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Internal, \"failed to create image verification rule matcher: %s\", err)\n\t}\n\n\tlogger.Debug(\"finding matching image verification rule for image reference\", zap.Stringer(\"image_ref_context\", inRef.Context()))\n\n\tmatchedRule := ruleMatcher(inRef.Context().String())\n\tif matchedRule == nil {\n\t\tlogger.Info(\"no matched image verification rule, allowing by default\", zap.Stringer(\"image_ref_context\", inRef.Context()))\n\n\t\treturn &machine.ImageServiceVerifyResponse{\n\t\t\tVerified: false,\n\t\t\tMessage:  \"no matched rule\",\n\t\t}, nil\n\t}\n\n\tif matchedRule.TypedSpec().Deny {\n\t\tlogger.Info(\"verification denied by matched rule\", zap.String(\"rule_id\", matchedRule.Metadata().ID()))\n\n\t\treturn nil, status.Errorf(codes.PermissionDenied, \"verification denied by matched rule (%s)\", matchedRule.Metadata().ID())\n\t}\n\n\tif matchedRule.TypedSpec().Skip {\n\t\tlogger.Info(\"verification skipped by matched rule\", zap.String(\"rule_id\", matchedRule.Metadata().ID()))\n\n\t\treturn &machine.ImageServiceVerifyResponse{\n\t\t\tVerified: false,\n\t\t\tMessage:  fmt.Sprintf(\"verification skipped by matched rule (%s)\", matchedRule.Metadata().ID()),\n\t\t}, nil\n\t}\n\n\t// resolve the image reference to a digest reference if needed\n\tvar (\n\t\tdigestRef name.Digest\n\t\tok        bool\n\t)\n\n\tif digestRef, ok = inRef.(name.Digest); !ok {\n\t\t_, desc, err := resolver.Resolve(ctx, inRef.String())\n\t\tif err != nil {\n\t\t\tif errdefs.IsNotFound(err) {\n\t\t\t\tlogger.Info(\"image reference not found during resolution\", zap.Error(err))\n\n\t\t\t\treturn nil, status.Errorf(codes.NotFound, \"image reference not found during resolution: %s\", err)\n\t\t\t}\n\n\t\t\treturn nil, status.Errorf(codes.Internal, \"failed to resolve image reference: %s\", err)\n\t\t}\n\n\t\tdigestRef, err = name.NewDigest(inRef.Context().Name() + \"@\" + desc.Digest.String())\n\t\tif err != nil {\n\t\t\treturn nil, status.Errorf(codes.Internal, \"failed to construct digest reference: %s\", err)\n\t\t}\n\t}\n\n\t// convert the rule to cosign check opts\n\tcheckOpts, err := cosignCheckOptsFromRule(ctx, matchedRule.TypedSpec(), resources)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.Internal, \"failed to convert verification rule to cosign check options: %s\", err)\n\t}\n\n\tresult, err := ourcosign.VerifyImage(ctx, logger, resolver, digestRef, checkOpts)\n\tif err != nil {\n\t\treturn nil, status.Errorf(codes.PermissionDenied, \"image verification failed: %s\", err)\n\t}\n\n\treturn &machine.ImageServiceVerifyResponse{\n\t\tVerified:         true,\n\t\tMessage:          result.Message,\n\t\tDigestedImageRef: digestRef.String(),\n\t}, nil\n}\n\n// tufTimeout is the timeout for fetching TUF trusted root metadata during keyless verification.\nconst tufTimeout = 15 * time.Second\n\nfunc getTrustedRoot(ctx context.Context, resources state.State) (root.TrustedMaterial, error) {\n\tctx, cancel := context.WithTimeout(ctx, tufTimeout)\n\tdefer cancel()\n\n\tr, err := resources.WatchFor(ctx, security.NewTUFTrustedRoot(security.TrustedRootID).Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to watch for TUF trusted root: %w\", err)\n\t}\n\n\ttufData, ok := r.(*security.TUFTrustedRoot)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected resource type for TUF trusted root: %T\", r)\n\t}\n\n\treturn root.NewTrustedRootFromJSON([]byte(tufData.TypedSpec().JSONData))\n}\n\nfunc cosignCheckOptsFromRule(ctx context.Context, rule *security.ImageVerificationRuleSpec, resources state.State) (cosign.CheckOpts, error) {\n\tswitch {\n\tcase rule.KeylessVerifier != nil:\n\t\ttrustedRoot, err := getTrustedRoot(ctx, resources)\n\t\tif err != nil {\n\t\t\treturn cosign.CheckOpts{}, fmt.Errorf(\"failed to get trusted root: %w\", err)\n\t\t}\n\n\t\treturn cosign.CheckOpts{\n\t\t\tTrustedMaterial: trustedRoot,\n\t\t\tIdentities: []cosign.Identity{\n\t\t\t\t{\n\t\t\t\t\tSubject:       rule.KeylessVerifier.Subject,\n\t\t\t\t\tSubjectRegExp: rule.KeylessVerifier.SubjectRegex,\n\t\t\t\t\tIssuer:        rule.KeylessVerifier.Issuer,\n\t\t\t\t},\n\t\t\t},\n\t\t}, nil\n\tcase rule.PublicKeyVerifier != nil:\n\t\tpub, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(rule.PublicKeyVerifier.Certificate))\n\t\tif err != nil {\n\t\t\treturn cosign.CheckOpts{}, fmt.Errorf(\"failed to unmarshal public key: %w\", err)\n\t\t}\n\n\t\tverifier, err := sigsig.LoadVerifier(pub, crypto.SHA256)\n\t\tif err != nil {\n\t\t\treturn cosign.CheckOpts{}, fmt.Errorf(\"failed to load public key: %w\", err)\n\t\t}\n\n\t\treturn cosign.CheckOpts{\n\t\t\tOffline:     true,\n\t\t\tSigVerifier: verifier,\n\t\t}, nil\n\tdefault:\n\t\treturn cosign.CheckOpts{}, fmt.Errorf(\"unsupported verifier type in rule\")\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/containers/inspector.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containers\n\nimport \"syscall\"\n\n// Inspector gather information about pods & containers.\ntype Inspector interface {\n\t// Pods collects information about running pods & containers.\n\tPods() ([]*Pod, error)\n\t// Container returns info about a single container.\n\tContainer(id string) (*Container, error)\n\t// Close frees associated resources.\n\tClose() error\n\t// Returns path to the container's stderr pipe\n\tGetProcessStderr(ID string) (string, error)\n\t// Kill sends signal to container's process\n\tKill(ID string, isPodSandbox bool, signal syscall.Signal) error\n}\n"
  },
  {
    "path": "internal/pkg/containers/pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage containers\n\n// Pod presents information about a pod, including a list of containers.\ntype Pod struct {\n\tName    string\n\tSandbox string\n\n\tContainers []*Container\n}\n"
  },
  {
    "path": "internal/pkg/cri/client.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"fmt\"\n\t\"runtime/pprof\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n)\n\nvar newClientPprof = pprof.NewProfile(\"internal/pkg/cri.NewClient\")\n\n// Client is a lightweight implementation of CRI client.\ntype Client struct {\n\tconn          *grpc.ClientConn\n\truntimeClient runtimeapi.RuntimeServiceClient\n\timagesClient  runtimeapi.ImageServiceClient\n}\n\n// maxMsgSize use 16MB as the default message size limit.\n// grpc library default is 4MB.\nconst maxMsgSize = 1024 * 1024 * 16\n\n// NewClient builds CRI client.\nfunc NewClient(endpoint string, _ time.Duration) (*Client, error) {\n\tconn, err := grpc.NewClient(endpoint,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)),\n\t\tgrpc.WithContextDialer(dialer.DialUnix()),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error connecting to CRI: %w\", err)\n\t}\n\n\tres := &Client{\n\t\tconn:          conn,\n\t\truntimeClient: runtimeapi.NewRuntimeServiceClient(conn),\n\t\timagesClient:  runtimeapi.NewImageServiceClient(conn),\n\t}\n\n\tnewClientPprof.Add(res, 1)\n\n\treturn res, nil\n}\n\n// Close connection.\nfunc (c *Client) Close() error {\n\tnewClientPprof.Remove(c)\n\n\treturn c.conn.Close()\n}\n"
  },
  {
    "path": "internal/pkg/cri/containers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n)\n\n// CreateContainer creates a new container in the specified PodSandbox.\nfunc (c *Client) CreateContainer(ctx context.Context, podSandBoxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {\n\tresp, err := c.runtimeClient.CreateContainer(ctx, &runtimeapi.CreateContainerRequest{\n\t\tPodSandboxId:  podSandBoxID,\n\t\tConfig:        config,\n\t\tSandboxConfig: sandboxConfig,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"CreateContainer in sandbox %q from runtime service failed: %w\", podSandBoxID, err)\n\t}\n\n\tif resp.ContainerId == \"\" {\n\t\treturn \"\", fmt.Errorf(\"ContainerId is not set for container %q\", config.GetMetadata())\n\t}\n\n\treturn resp.ContainerId, nil\n}\n\n// StartContainer starts the container.\nfunc (c *Client) StartContainer(ctx context.Context, containerID string) error {\n\t_, err := c.runtimeClient.StartContainer(ctx, &runtimeapi.StartContainerRequest{\n\t\tContainerId: containerID,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"StartContainer %q from runtime service failed: %w\", containerID, err)\n\t}\n\n\treturn nil\n}\n\n// StopContainer stops a running container with a grace period (i.e., timeout).\nfunc (c *Client) StopContainer(ctx context.Context, containerID string, timeout int64) error {\n\t_, err := c.runtimeClient.StopContainer(ctx, &runtimeapi.StopContainerRequest{\n\t\tContainerId: containerID,\n\t\tTimeout:     timeout,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"StopContainer %q from runtime service failed: %w\", containerID, err)\n\t}\n\n\treturn nil\n}\n\n// RemoveContainer removes the container. If the container is running, the container\n// should be forced to removal.\nfunc (c *Client) RemoveContainer(ctx context.Context, containerID string) error {\n\t_, err := c.runtimeClient.RemoveContainer(ctx, &runtimeapi.RemoveContainerRequest{\n\t\tContainerId: containerID,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"RemoveContainer %q from runtime service failed: %w\", containerID, err)\n\t}\n\n\treturn nil\n}\n\n// ListContainers lists containers by filters.\nfunc (c *Client) ListContainers(ctx context.Context, filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error) {\n\tresp, err := c.runtimeClient.ListContainers(ctx, &runtimeapi.ListContainersRequest{\n\t\tFilter: filter,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ListContainers with filter %+v from runtime service failed: %w\", filter, err)\n\t}\n\n\treturn resp.Containers, nil\n}\n\n// ContainerStatus returns the container status.\nfunc (c *Client) ContainerStatus(ctx context.Context, containerID string, verbose bool) (*runtimeapi.ContainerStatus, map[string]string, error) {\n\tresp, err := c.runtimeClient.ContainerStatus(ctx, &runtimeapi.ContainerStatusRequest{\n\t\tContainerId: containerID,\n\t\tVerbose:     verbose,\n\t})\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"ContainerStatus %q from runtime service failed: %w\", containerID, err)\n\t}\n\n\treturn resp.Status, resp.Info, nil\n}\n\n// ContainerStats returns the stats of the container.\nfunc (c *Client) ContainerStats(ctx context.Context, containerID string) (*runtimeapi.ContainerStats, error) {\n\tresp, err := c.runtimeClient.ContainerStats(ctx, &runtimeapi.ContainerStatsRequest{\n\t\tContainerId: containerID,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ContainerStatus %q from runtime service failed: %w\", containerID, err)\n\t}\n\n\treturn resp.GetStats(), nil\n}\n\n// ListContainerStats returns stats for all the containers matching the filter.\nfunc (c *Client) ListContainerStats(ctx context.Context, filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error) {\n\tresp, err := c.runtimeClient.ListContainerStats(ctx, &runtimeapi.ListContainerStatsRequest{\n\t\tFilter: filter,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ListContainerStats with filter %+v from runtime service failed: %w\", filter, err)\n\t}\n\n\treturn resp.GetStats(), nil\n}\n"
  },
  {
    "path": "internal/pkg/cri/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cri provides minimal CRI client.\npackage cri\n\n// This client is based on k8s version in https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet/remote,\n// but it doesn't depend on k8s libs.\n"
  },
  {
    "path": "internal/pkg/cri/cri_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/containerd/cgroups/v3\"\n\t\"github.com/containerd/cgroups/v3/cgroup1\"\n\t\"github.com/containerd/cgroups/v3/cgroup2\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/suite\"\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/logging\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/events\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/process\"\n\t\"github.com/siderolabs/talos/internal/pkg/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tbusyboxImage = \"docker.io/library/busybox:1.30.1\"\n)\n\nfunc MockEventSink(t *testing.T) func(state events.ServiceState, message string, args ...any) {\n\treturn func(state events.ServiceState, message string, args ...any) {\n\t\tt.Logf(message, args...)\n\t}\n}\n\ntype CRISuite struct {\n\tsuite.Suite\n\n\ttmpDir string\n\n\tcontainerdRunner  runner.Runner\n\tcontainerdWg      sync.WaitGroup\n\tcontainerdAddress string\n\n\tclient    *cri.Client\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n}\n\nfunc (suite *CRISuite) SetupSuite() {\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tsuite.T().Skip(\"test doesn't pass under cgroupsv2\")\n\t}\n\n\tvar err error\n\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tstateDir, rootDir := filepath.Join(suite.tmpDir, \"state\"), filepath.Join(suite.tmpDir, \"root\")\n\tsuite.Require().NoError(os.Mkdir(stateDir, 0o777))\n\tsuite.Require().NoError(os.Mkdir(rootDir, 0o777))\n\n\tif cgroups.Mode() == cgroups.Unified {\n\t\tvar (\n\t\t\tgroupPath string\n\t\t\tmanager   *cgroup2.Manager\n\t\t)\n\n\t\tgroupPath, err = cgroup2.NestedGroupPath(suite.tmpDir)\n\t\tsuite.Require().NoError(err)\n\n\t\tmanager, err = cgroup2.NewManager(constants.CgroupMountPath, groupPath, &cgroup2.Resources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t} else {\n\t\tvar manager cgroup1.Cgroup\n\n\t\tmanager, err = cgroup1.New(cgroup1.NestedPath(suite.tmpDir), &specs.LinuxResources{})\n\t\tsuite.Require().NoError(err)\n\n\t\tdefer manager.Delete() //nolint:errcheck\n\t}\n\n\tsuite.containerdAddress = filepath.Join(suite.tmpDir, \"run.sock\")\n\n\targs := &runner.Args{\n\t\tID: \"containerd\",\n\t\tProcessArgs: []string{\n\t\t\t\"/bin/containerd\",\n\t\t\t\"--address\", suite.containerdAddress,\n\t\t\t\"--state\", stateDir,\n\t\t\t\"--root\", rootDir,\n\t\t\t\"--config\", constants.CRIContainerdConfig,\n\t\t},\n\t}\n\n\tsuite.containerdRunner = process.NewRunner(\n\t\tfalse,\n\t\targs,\n\t\trunner.WithLoggingManager(logging.NewFileLoggingManager(suite.tmpDir)),\n\t\trunner.WithEnv([]string{constants.EnvPathWithBin}),\n\t\trunner.WithCgroupPath(suite.tmpDir),\n\t)\n\tsuite.Require().NoError(suite.containerdRunner.Open())\n\n\tsuite.containerdWg.Go(func() {\n\t\tdefer suite.containerdRunner.Close() //nolint:errcheck\n\n\t\tsuite.containerdRunner.Run(MockEventSink(suite.T())) //nolint:errcheck\n\t})\n\n\tsuite.client, err = cri.NewClient(\"unix:\"+suite.containerdAddress, 30*time.Second)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *CRISuite) TearDownSuite() {\n\tsuite.ctxCancel()\n\n\tsuite.Require().NoError(suite.client.Close())\n\n\tsuite.Require().NoError(suite.containerdRunner.Stop())\n\tsuite.containerdWg.Wait()\n}\n\nfunc (suite *CRISuite) SetupTest() {\n\tsuite.ctx, suite.ctxCancel = context.WithTimeout(context.Background(), 30*time.Second)\n}\n\nfunc (suite *CRISuite) TearDownTest() {\n\tsuite.ctxCancel()\n}\n\nfunc (suite *CRISuite) TestRunSandboxContainer() {\n\tpodSandboxConfig := &runtimeapi.PodSandboxConfig{\n\t\tMetadata: &runtimeapi.PodSandboxMetadata{\n\t\t\tName:      \"etcd-master-1\",\n\t\t\tUid:       \"ed1a599a53090941c9b4025c7e3e883d\",\n\t\t\tNamespace: \"kube-system\",\n\t\t\tAttempt:   0,\n\t\t},\n\t\tLabels: map[string]string{\n\t\t\t\"io.kubernetes.pod.name\":      \"etcd-master-1\",\n\t\t\t\"io.kubernetes.pod.namespace\": \"kube-system\",\n\t\t},\n\t\tLogDirectory: suite.tmpDir,\n\t\tLinux: &runtimeapi.LinuxPodSandboxConfig{\n\t\t\tSecurityContext: &runtimeapi.LinuxSandboxSecurityContext{\n\t\t\t\tNamespaceOptions: &runtimeapi.NamespaceOption{\n\t\t\t\t\tNetwork: runtimeapi.NamespaceMode_NODE,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tpodSandboxID, err := suite.client.RunPodSandbox(suite.ctx, podSandboxConfig, \"\")\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(podSandboxID, 64)\n\n\timageRef, err := suite.client.PullImage(\n\t\tsuite.ctx, &runtimeapi.ImageSpec{\n\t\t\tImage: busyboxImage,\n\t\t}, podSandboxConfig,\n\t)\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.client.ImageStatus(\n\t\tsuite.ctx, &runtimeapi.ImageSpec{\n\t\t\tImage: imageRef,\n\t\t},\n\t)\n\tsuite.Require().NoError(err)\n\n\tctrID, err := suite.client.CreateContainer(\n\t\tsuite.ctx, podSandboxID,\n\t\t&runtimeapi.ContainerConfig{\n\t\t\tMetadata: &runtimeapi.ContainerMetadata{\n\t\t\t\tName: \"etcd\",\n\t\t\t},\n\t\t\tLabels: map[string]string{\n\t\t\t\t\"io.kubernetes.container.name\": \"etcd\",\n\t\t\t\t\"io.kubernetes.pod.name\":       \"etcd-master-1\",\n\t\t\t\t\"io.kubernetes.pod.namespace\":  \"kube-system\",\n\t\t\t},\n\t\t\tAnnotations: map[string]string{\n\t\t\t\t\"io.kubernetes.container.restartCount\": \"1\",\n\t\t\t},\n\t\t\tImage: &runtimeapi.ImageSpec{\n\t\t\t\tImage: imageRef,\n\t\t\t},\n\t\t\tCommand: []string{\"/bin/sh\", \"-c\", \"sleep 3600\"},\n\t\t}, podSandboxConfig,\n\t)\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(ctrID, 64)\n\n\terr = suite.client.StartContainer(suite.ctx, ctrID)\n\tsuite.Require().NoError(err)\n\n\t_, err = suite.client.ContainerStats(suite.ctx, ctrID)\n\tsuite.Require().NoError(err)\n\n\t_, _, err = suite.client.ContainerStatus(suite.ctx, ctrID, true)\n\tsuite.Require().NoError(err)\n\n\terr = suite.client.StopContainer(suite.ctx, ctrID, 10)\n\tsuite.Require().NoError(err)\n\n\terr = suite.client.RemoveContainer(suite.ctx, ctrID)\n\tsuite.Require().NoError(err)\n\n\terr = suite.client.StopPodSandbox(suite.ctx, podSandboxID)\n\tsuite.Require().NoError(err)\n\n\terr = suite.client.RemovePodSandbox(suite.ctx, podSandboxID)\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *CRISuite) TestList() {\n\tpods, err := suite.client.ListPodSandbox(suite.ctx, &runtimeapi.PodSandboxFilter{})\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(pods, 0)\n\n\tcontainers, err := suite.client.ListContainers(suite.ctx, &runtimeapi.ContainerFilter{})\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(containers, 0)\n\n\tcontainerStats, err := suite.client.ListContainerStats(suite.ctx, &runtimeapi.ContainerStatsFilter{})\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(containerStats, 0)\n\n\t_, err = suite.client.ListImages(suite.ctx, &runtimeapi.ImageFilter{})\n\tsuite.Require().NoError(err)\n}\n\nfunc TestCRISuite(t *testing.T) {\n\tif os.Getuid() != 0 {\n\t\tt.Skip(\"can't run the test as non-root\")\n\t}\n\n\t_, err := os.Stat(\"/bin/containerd\")\n\tif err != nil {\n\t\tt.Skip(\"containerd binary is not available, skipping the test\")\n\t}\n\n\tsuite.Run(t, new(CRISuite))\n}\n"
  },
  {
    "path": "internal/pkg/cri/images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n)\n\n// PullImage pulls container image.\nfunc (c *Client) PullImage(ctx context.Context, image *runtimeapi.ImageSpec, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) {\n\tresp, err := c.imagesClient.PullImage(ctx, &runtimeapi.PullImageRequest{\n\t\tImage:         image,\n\t\tSandboxConfig: sandboxConfig,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error pulling image %s: %w\", image, err)\n\t}\n\n\treturn resp.ImageRef, nil\n}\n\n// ListImages lists available images.\nfunc (c *Client) ListImages(ctx context.Context, filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error) {\n\tresp, err := c.imagesClient.ListImages(ctx, &runtimeapi.ListImagesRequest{\n\t\tFilter: filter,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error listing images: %w\", err)\n\t}\n\n\treturn resp.Images, nil\n}\n\n// ImageStatus returns the status of the image.\nfunc (c *Client) ImageStatus(ctx context.Context, image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) {\n\tresp, err := c.imagesClient.ImageStatus(ctx, &runtimeapi.ImageStatusRequest{\n\t\tImage: image,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ImageStatus %q from image service failed: %w\", image.Image, err)\n\t}\n\n\tif resp.Image != nil {\n\t\tif resp.Image.Id == \"\" || resp.Image.Size == 0 {\n\t\t\treturn nil, fmt.Errorf(\"id or size of image %q is not set\", image.Image)\n\t\t}\n\t}\n\n\treturn resp.Image, nil\n}\n"
  },
  {
    "path": "internal/pkg/cri/pods.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc/codes\"\n\truntimeapi \"k8s.io/cri-api/pkg/apis/runtime/v1\"\n\n\ttalosclient \"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure\n// the sandbox is in ready state.\nfunc (c *Client) RunPodSandbox(ctx context.Context, config *runtimeapi.PodSandboxConfig, runtimeHandler string) (string, error) {\n\tresp, err := c.runtimeClient.RunPodSandbox(ctx, &runtimeapi.RunPodSandboxRequest{\n\t\tConfig:         config,\n\t\tRuntimeHandler: runtimeHandler,\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif resp.PodSandboxId == \"\" {\n\t\treturn \"\", fmt.Errorf(\"PodSandboxId is not set for sandbox %q\", config.GetMetadata())\n\t}\n\n\treturn resp.PodSandboxId, nil\n}\n\n// StopPodSandbox stops the sandbox. If there are any running containers in the\n// sandbox, they should be forced to termination.\nfunc (c *Client) StopPodSandbox(ctx context.Context, podSandBoxID string) error {\n\t_, err := c.runtimeClient.StopPodSandbox(ctx, &runtimeapi.StopPodSandboxRequest{\n\t\tPodSandboxId: podSandBoxID,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"StopPodSandbox %q from runtime service failed: %w\", podSandBoxID, err)\n\t}\n\n\treturn nil\n}\n\n// RemovePodSandbox removes the sandbox. If there are any containers in the\n// sandbox, they should be forcibly removed.\nfunc (c *Client) RemovePodSandbox(ctx context.Context, podSandBoxID string) error {\n\t_, err := c.runtimeClient.RemovePodSandbox(ctx, &runtimeapi.RemovePodSandboxRequest{\n\t\tPodSandboxId: podSandBoxID,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"RemovePodSandbox %q from runtime service failed: %w\", podSandBoxID, err)\n\t}\n\n\treturn nil\n}\n\n// ListPodSandbox returns a list of PodSandboxes.\nfunc (c *Client) ListPodSandbox(ctx context.Context, filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error) {\n\tresp, err := c.runtimeClient.ListPodSandbox(ctx, &runtimeapi.ListPodSandboxRequest{\n\t\tFilter: filter,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ListPodSandbox with filter %+v from runtime service failed: %w\", filter, err)\n\t}\n\n\treturn resp.Items, nil\n}\n\n// PodSandboxStatus returns the status of the PodSandbox.\nfunc (c *Client) PodSandboxStatus(ctx context.Context, podSandBoxID string) (*runtimeapi.PodSandboxStatus, map[string]string, error) {\n\tresp, err := c.runtimeClient.PodSandboxStatus(ctx, &runtimeapi.PodSandboxStatusRequest{\n\t\tPodSandboxId: podSandBoxID,\n\t\tVerbose:      true,\n\t})\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn resp.Status, resp.Info, nil\n}\n\n// StopAction for StopAndRemovePodSandboxes.\ntype StopAction int\n\n// Stop actions.\nconst (\n\tStopOnly StopAction = iota\n\tStopAndRemove\n)\n\n// StopAndRemovePodSandboxes stops and removes all pods with the specified network mode. If no\n// network mode is specified, all pods will be removed.\nfunc (c *Client) StopAndRemovePodSandboxes(ctx context.Context, stopAction StopAction, modes ...runtimeapi.NamespaceMode) (err error) {\n\tpods, err := c.ListPodSandbox(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar g errgroup.Group\n\n\tfor _, pod := range pods {\n\t\tg.Go(func() error {\n\t\t\tstatus, _, e := c.PodSandboxStatus(ctx, pod.GetId())\n\t\t\tif e != nil {\n\t\t\t\tif talosclient.StatusCode(e) == codes.NotFound {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn e\n\t\t\t}\n\n\t\t\tnetworkMode := status.GetLinux().GetNamespaces().GetOptions().GetNetwork()\n\n\t\t\t// If any modes are specified, we verify that the current pod is\n\t\t\t// running any one of the modes. If it doesn't, we skip it.\n\t\t\tif len(modes) > 0 && !contains(networkMode, modes) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif e = stopAndRemove(ctx, stopAction, c, pod, networkMode.String()); e != nil {\n\t\t\t\treturn fmt.Errorf(\"failed stopping pod %s/%s: %w\", pod.Metadata.Namespace, pod.Metadata.Name, e)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn g.Wait()\n}\n\nfunc contains(mode runtimeapi.NamespaceMode, modes []runtimeapi.NamespaceMode) bool {\n\treturn slices.Contains(modes, mode)\n}\n\n//nolint:gocyclo\nfunc stopAndRemove(ctx context.Context, stopAction StopAction, client *Client, pod *runtimeapi.PodSandbox, mode string) (err error) {\n\taction := \"stopping\"\n\tstatus := \"stopped\"\n\n\tif stopAction == StopAndRemove {\n\t\taction = \"removing\"\n\t\tstatus = \"removed\"\n\t}\n\n\tlog.Printf(\"%s pod %s/%s with network mode %q\", action, pod.Metadata.Namespace, pod.Metadata.Name, mode)\n\n\tfilter := &runtimeapi.ContainerFilter{\n\t\tPodSandboxId: pod.Id,\n\t}\n\n\tcontainers, err := client.ListContainers(ctx, filter)\n\tif err != nil {\n\t\tif talosclient.StatusCode(err) == codes.NotFound {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tvar g errgroup.Group\n\n\tfor _, container := range containers {\n\t\tg.Go(func() error {\n\t\t\t// TODO(andrewrynhard): Can we set the timeout dynamically?\n\t\t\tif container.State == runtimeapi.ContainerState_CONTAINER_RUNNING || container.State == runtimeapi.ContainerState_CONTAINER_UNKNOWN {\n\t\t\t\tlog.Printf(\"stopping container %s/%s:%s\", pod.Metadata.Namespace, pod.Metadata.Name, container.Metadata.Name)\n\n\t\t\t\tif criErr := client.StopContainer(ctx, container.Id, int64(constants.KubeletShutdownGracePeriod.Seconds())); criErr != nil {\n\t\t\t\t\tif talosclient.StatusCode(criErr) == codes.NotFound {\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn criErr\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif stopAction == StopAndRemove {\n\t\t\t\tlog.Printf(\"removing container %s/%s:%s\", pod.Metadata.Namespace, pod.Metadata.Name, container.Metadata.Name)\n\n\t\t\t\tif removeErr := retry.Constant(constants.KubeletShutdownGracePeriod, retry.WithUnits(time.Second), retry.WithErrorLogging(true)).RetryWithContext(ctx,\n\t\t\t\t\tfunc(ctx context.Context) error {\n\t\t\t\t\t\tif criErr := client.RemoveContainer(ctx, container.Id); criErr != nil {\n\t\t\t\t\t\t\tif talosclient.StatusCode(criErr) == codes.NotFound {\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn retry.ExpectedError(criErr)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}); removeErr != nil {\n\t\t\t\t\treturn removeErr\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlog.Printf(\"%s container %s/%s:%s\", status, pod.Metadata.Namespace, pod.Metadata.Name, container.Metadata.Name)\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif err = g.Wait(); err != nil {\n\t\treturn err\n\t}\n\n\tif pod.State == runtimeapi.PodSandboxState_SANDBOX_READY {\n\t\tif err = client.StopPodSandbox(ctx, pod.Id); err != nil {\n\t\t\tif talosclient.StatusCode(err) == codes.NotFound {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tlog.Printf(\"error stopping pod %s/%s, ignored: %s\", pod.Metadata.Namespace, pod.Metadata.Name, err)\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif stopAction == StopAndRemove {\n\t\tif err = client.RemovePodSandbox(ctx, pod.Id); err != nil {\n\t\t\tif talosclient.StatusCode(err) == codes.NotFound {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tlog.Printf(\"error removing pod %s/%s, ignored: %s\", pod.Metadata.Namespace, pod.Metadata.Name, err)\n\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tlog.Printf(\"%s pod %s/%s\", status, pod.Metadata.Namespace, pod.Metadata.Name)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/ctxutil/ctxutil.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ctxutil provides utilities for working with contexts.\npackage ctxutil\n\nimport \"context\"\n\n// Cause returns the cause of the context error, or nil if there is no error or the error is a usual context error.\nfunc Cause(ctx context.Context) error {\n\tif c := context.Cause(ctx); c != ctx.Err() {\n\t\treturn c\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/apidata/apidata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package apidata implements the types and the data sources for the data sourced from various Talos APIs.\npackage apidata\n"
  },
  {
    "path": "internal/pkg/dashboard/apidata/data.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package apidata implements types to handle monitoring data, calculate values from it, etc.\npackage apidata\n\nimport (\n\t\"time\"\n)\n\nconst maxPoints = 1000\n\n// Data represents the monitoring data retrieved via Talos API.\n//\n// Data structure is sent over the channel each interval.\ntype Data struct {\n\t// Data per each node.\n\tNodes map[string]*Node\n\n\tTimestamp time.Time\n\tInterval  time.Duration\n}\n\n// CalculateDiff with data from previous iteration.\nfunc (data *Data) CalculateDiff(oldData *Data) {\n\tdata.Interval = data.Timestamp.Sub(oldData.Timestamp)\n\n\tfor node, nodeData := range data.Nodes {\n\t\toldNodeData := oldData.Nodes[node]\n\t\tif oldNodeData == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tnodeData.UpdateDiff(oldNodeData)\n\t\tnodeData.UpdateSeries(oldNodeData)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/apidata/diff.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage apidata\n\nimport \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\nfunc cpuInfoDiff(old, next *machine.CPUStat) *machine.CPUStat {\n\tif old == nil || next == nil {\n\t\treturn &machine.CPUStat{}\n\t}\n\n\t// TODO: support wraparound\n\treturn &machine.CPUStat{\n\t\tUser:      next.User - old.User,\n\t\tNice:      next.Nice - old.Nice,\n\t\tSystem:    next.System - old.System,\n\t\tIdle:      next.Idle - old.Idle,\n\t\tIowait:    next.Iowait - old.Iowait,\n\t\tIrq:       next.Irq - old.Irq,\n\t\tSoftIrq:   next.SoftIrq - old.SoftIrq,\n\t\tSteal:     next.Steal - old.Steal,\n\t\tGuest:     next.Guest - old.Guest,\n\t\tGuestNice: next.GuestNice - old.GuestNice,\n\t}\n}\n\nfunc netDevDiff(old, next *machine.NetDev) *machine.NetDev {\n\tif old == nil || next == nil {\n\t\treturn &machine.NetDev{}\n\t}\n\n\t// TODO: support wraparound\n\treturn &machine.NetDev{\n\t\tName:         next.Name,\n\t\tRxBytes:      next.RxBytes - old.RxBytes,\n\t\tRxPackets:    next.RxPackets - old.RxPackets,\n\t\tRxErrors:     next.RxErrors - old.RxErrors,\n\t\tRxDropped:    next.RxDropped - old.RxDropped,\n\t\tRxFifo:       next.RxFifo - old.RxFifo,\n\t\tRxFrame:      next.RxFrame - old.RxFrame,\n\t\tRxCompressed: next.RxCompressed - old.RxCompressed,\n\t\tRxMulticast:  next.RxMulticast - old.RxMulticast,\n\t\tTxBytes:      next.TxBytes - old.TxBytes,\n\t\tTxPackets:    next.TxPackets - old.TxPackets,\n\t\tTxErrors:     next.TxErrors - old.TxErrors,\n\t\tTxDropped:    next.TxDropped - old.TxDropped,\n\t\tTxFifo:       next.TxFifo - old.TxFifo,\n\t\tTxCollisions: next.TxCollisions - old.TxCollisions,\n\t\tTxCarrier:    next.TxCarrier - old.TxCarrier,\n\t\tTxCompressed: next.TxCompressed - old.TxCompressed,\n\t}\n}\n\nfunc diskStatDiff(old, next *machine.DiskStat) *machine.DiskStat {\n\tif old == nil || next == nil {\n\t\treturn &machine.DiskStat{}\n\t}\n\n\t// TODO: support wraparound\n\treturn &machine.DiskStat{\n\t\tName:             next.Name,\n\t\tReadCompleted:    next.ReadCompleted - old.ReadCompleted,\n\t\tReadMerged:       next.ReadMerged - old.ReadMerged,\n\t\tReadSectors:      next.ReadSectors - old.ReadSectors,\n\t\tWriteCompleted:   next.WriteCompleted - old.WriteCompleted,\n\t\tWriteMerged:      next.WriteMerged - old.WriteMerged,\n\t\tWriteSectors:     next.WriteSectors - old.WriteSectors,\n\t\tDiscardCompleted: next.DiscardCompleted - old.DiscardCompleted,\n\t\tDiscardMerged:    next.DiscardMerged - old.DiscardMerged,\n\t\tDiscardSectors:   next.DiscardSectors - old.DiscardSectors,\n\t}\n}\n\nfunc procDiff(old, next *machine.ProcessInfo) *machine.ProcessInfo {\n\tif old == nil || next == nil {\n\t\treturn &machine.ProcessInfo{}\n\t}\n\n\t// TODO: support wraparound\n\treturn &machine.ProcessInfo{\n\t\tCpuTime: next.CpuTime - old.CpuTime,\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/apidata/node.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage apidata\n\nimport (\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\n// Node represents data gathered from a single node.\ntype Node struct {\n\t// These fields are directly API responses.\n\tLoadAvg       *machine.LoadAvg\n\tVersion       *machine.Version\n\tMemory        *machine.Memory\n\tSystemStat    *machine.SystemStat\n\tCPUsFreqStats *machine.CPUsFreqStats\n\tCPUsInfo      *machine.CPUsInfo\n\tNetDevStats   *machine.NetworkDeviceStats\n\tDiskStats     *machine.DiskStats\n\tProcesses     *machine.Process\n\tServiceList   *machine.ServiceList\n\n\t// These fields are calculated as diff with Node data from previous pol.\n\tSystemStatDiff  *machine.SystemStat\n\tNetDevStatsDiff *machine.NetworkDeviceStats\n\tDiskStatsDiff   *machine.DiskStats\n\tProcsDiff       map[int32]*machine.ProcessInfo\n\n\t// Time-series data.\n\tSeries map[string][]float64\n}\n\n// MemUsage as used/total.\nfunc (node *Node) MemUsage() float64 {\n\tmemTotal := node.Memory.GetMeminfo().GetMemtotal()\n\tmemUsed := node.Memory.GetMeminfo().GetMemtotal() - node.Memory.GetMeminfo().GetMemfree() - node.Memory.GetMeminfo().GetCached() - node.Memory.GetMeminfo().GetBuffers()\n\n\tif memTotal == 0 {\n\t\treturn 0\n\t}\n\n\treturn float64(memUsed) / float64(memTotal)\n}\n\n// CPUUsageByName returns CPU usage by name.\n//\n//nolint:gocyclo\nfunc (node *Node) CPUUsageByName(name string) float64 {\n\tif node.SystemStatDiff == nil || node.SystemStatDiff.CpuTotal == nil {\n\t\treturn 0\n\t}\n\n\tstat := node.SystemStatDiff.CpuTotal\n\n\tidle := stat.Idle + stat.Iowait\n\tnonIdle := stat.User + stat.Nice + stat.System + stat.Irq + stat.Steal + stat.SoftIrq\n\ttotal := idle + nonIdle\n\n\tif total == 0 {\n\t\treturn 0\n\t}\n\n\tswitch name {\n\tcase \"user\":\n\t\treturn stat.User / total\n\tcase \"system\":\n\t\treturn stat.System / total\n\tcase \"idle\":\n\t\treturn stat.Idle / total\n\tcase \"iowait\":\n\t\treturn stat.Iowait / total\n\tcase \"nice\":\n\t\treturn stat.Nice / total\n\tcase \"irq\":\n\t\treturn stat.Irq / total\n\tcase \"steal\":\n\t\treturn stat.Steal / total\n\tcase \"softirq\":\n\t\treturn stat.SoftIrq / total\n\tcase \"usage\":\n\t\treturn (total - idle) / total\n\tcase \"total\":\n\t\treturn total\n\tcase \"total_weighted\":\n\t\tcpuCount := len(node.CPUsInfo.GetCpuInfo())\n\t\tif cpuCount == 0 {\n\t\t\treturn total\n\t\t}\n\n\t\treturn total / float64(cpuCount)\n\t}\n\n\tpanic(\"unknown cpu usage name\")\n}\n\n// CtxSwitches returns diff of context switches.\nfunc (node *Node) CtxSwitches() uint64 {\n\tif node.SystemStatDiff == nil {\n\t\treturn 0\n\t}\n\n\treturn node.SystemStatDiff.GetContextSwitches()\n}\n\n// ProcsCreated returns diff of processes created.\nfunc (node *Node) ProcsCreated() uint64 {\n\tif node.SystemStatDiff == nil {\n\t\treturn 0\n\t}\n\n\treturn node.SystemStatDiff.GetProcessCreated()\n}\n\n// UpdateSeries builds time-series data based on previous iteration data.\nfunc (node *Node) UpdateSeries(old *Node) {\n\tnode.Series = make(map[string][]float64)\n\n\tfor _, graphInfo := range []struct {\n\t\tname string\n\t\tf    func() float64\n\t}{\n\t\t{\n\t\t\t\"mem\",\n\t\t\tnode.MemUsage,\n\t\t},\n\t\t{\n\t\t\t\"user\",\n\t\t\tfunc() float64 { return node.CPUUsageByName(\"user\") },\n\t\t},\n\t\t{\n\t\t\t\"system\",\n\t\t\tfunc() float64 { return node.CPUUsageByName(\"system\") },\n\t\t},\n\t\t{\n\t\t\t\"loadavg\",\n\t\t\tfunc() float64 { return node.LoadAvg.GetLoad1() },\n\t\t},\n\t\t{\n\t\t\t\"netrxbytes\",\n\t\t\tfunc() float64 { return float64(node.NetDevStatsDiff.GetTotal().GetRxBytes()) },\n\t\t},\n\t\t{\n\t\t\t\"nettxbytes\",\n\t\t\tfunc() float64 { return float64(node.NetDevStatsDiff.GetTotal().GetTxBytes()) },\n\t\t},\n\t\t{\n\t\t\t\"diskrdsectors\",\n\t\t\tfunc() float64 { return float64(node.DiskStatsDiff.GetTotal().GetReadSectors()) },\n\t\t},\n\t\t{\n\t\t\t\"diskwrsectors\",\n\t\t\tfunc() float64 { return float64(node.DiskStatsDiff.GetTotal().GetWriteSectors()) },\n\t\t},\n\t} {\n\t\toldSeries := old.Series[graphInfo.name]\n\n\t\toff := 0\n\t\tif len(oldSeries) > maxPoints {\n\t\t\toff = len(oldSeries) - maxPoints\n\t\t}\n\n\t\tnode.Series[graphInfo.name] = append(oldSeries[off:], graphInfo.f())\n\n\t\t// TODO: bug with plot widget\n\t\tfor len(node.Series[graphInfo.name]) < 2 {\n\t\t\tnode.Series[graphInfo.name] = append([]float64{0.0}, node.Series[graphInfo.name]...)\n\t\t}\n\t}\n}\n\n// UpdateDiff calculates diff with node data from previous iteration.\nfunc (node *Node) UpdateDiff(old *Node) {\n\tif old.SystemStat != nil {\n\t\tnode.SystemStatDiff = &machine.SystemStat{\n\t\t\t// TODO: support other fields\n\t\t\tCpuTotal:        cpuInfoDiff(old.SystemStat.GetCpuTotal(), node.SystemStat.GetCpuTotal()),\n\t\t\tContextSwitches: node.SystemStat.GetContextSwitches() - old.SystemStat.GetContextSwitches(),\n\t\t\tProcessCreated:  node.SystemStat.GetProcessCreated() - old.SystemStat.GetProcessCreated(),\n\t\t}\n\t}\n\n\tif old.NetDevStats != nil {\n\t\tnode.NetDevStatsDiff = &machine.NetworkDeviceStats{\n\t\t\t// TODO: support other fields\n\t\t\tTotal: netDevDiff(old.NetDevStats.GetTotal(), node.NetDevStats.GetTotal()),\n\t\t}\n\t}\n\n\tif old.DiskStats != nil {\n\t\tnode.DiskStatsDiff = &machine.DiskStats{\n\t\t\t// TODO: support other fields\n\t\t\tTotal: diskStatDiff(old.DiskStats.GetTotal(), node.DiskStats.GetTotal()),\n\t\t}\n\t}\n\n\tif old.Processes != nil {\n\t\tindex := xslices.ToMap(old.Processes.GetProcesses(), func(proc *machine.ProcessInfo) (int32, *machine.ProcessInfo) {\n\t\t\treturn proc.Pid, proc\n\t\t})\n\n\t\tnode.ProcsDiff = xslices.ToMap(node.Processes.GetProcesses(), func(proc *machine.ProcessInfo) (int32, *machine.ProcessInfo) {\n\t\t\treturn proc.Pid, procDiff(index[proc.Pid], proc)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/apidata/source.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage apidata\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resolver\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// Source is a data source that gathers information about a Talos node using Talos API.\ntype Source struct {\n\t*client.Client\n\n\tResolver resolver.Resolver\n\n\tInterval time.Duration\n\n\tctx       context.Context //nolint:containedctx\n\tctxCancel context.CancelFunc\n\n\twg sync.WaitGroup\n}\n\n// Run the data poll on interval.\nfunc (source *Source) Run(ctx context.Context) <-chan *Data {\n\tdataCh := make(chan *Data)\n\n\tsource.ctx, source.ctxCancel = context.WithCancel(ctx)\n\n\tsource.wg.Add(1)\n\n\tgo source.run(dataCh)\n\n\treturn dataCh\n}\n\n// Stop the data collection process.\nfunc (source *Source) Stop() {\n\tsource.ctxCancel()\n\n\tsource.wg.Wait()\n}\n\nfunc (source *Source) run(dataCh chan<- *Data) {\n\tdefer source.wg.Done()\n\tdefer close(dataCh)\n\n\tticker := time.NewTicker(source.Interval)\n\tdefer ticker.Stop()\n\n\tvar oldData, currentData *Data\n\n\tfor {\n\t\tcurrentData = source.gather()\n\n\t\tif oldData == nil {\n\t\t\tcurrentData.CalculateDiff(currentData)\n\t\t} else {\n\t\t\tcurrentData.CalculateDiff(oldData)\n\t\t}\n\n\t\tselect {\n\t\tcase dataCh <- currentData:\n\t\tcase <-source.ctx.Done():\n\t\t\treturn\n\t\t}\n\n\t\tselect {\n\t\tcase <-source.ctx.Done():\n\t\t\treturn\n\t\tcase <-ticker.C:\n\t\t}\n\n\t\toldData = currentData\n\t}\n}\n\ntype protoMsg[T any] interface {\n\tGetMessages() []T\n}\n\nfunc unpack[T helpers.Message](source *Source, nodes map[string]*Node, resultLock *sync.Mutex, resp protoMsg[T], setter func(node *Node, value T)) {\n\tresultLock.Lock()\n\tdefer resultLock.Unlock()\n\n\tfor _, msg := range resp.GetMessages() {\n\t\tnode := source.node(msg)\n\n\t\tif _, ok := nodes[node]; !ok {\n\t\t\tnodes[node] = &Node{}\n\t\t}\n\n\t\tif msg.GetMetadata().GetError() != \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tsetter(nodes[node], msg)\n\t}\n}\n\n//nolint:gocyclo\nfunc (source *Source) gather() *Data {\n\tresult := &Data{\n\t\tTimestamp: time.Now(),\n\t\tNodes:     map[string]*Node{},\n\t}\n\n\tvar resultLock sync.Mutex\n\n\tgatherFuncs := []func() error{\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.LoadAvg(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.LoadAvg) {\n\t\t\t\tnode.LoadAvg = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.Version(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.Version) {\n\t\t\t\tnode.Version = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.Memory(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.Memory) {\n\t\t\t\tnode.Memory = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.SystemStat(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.SystemStat) {\n\t\t\t\tnode.SystemStat = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.CPUFreqStats(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.CPUsFreqStats) {\n\t\t\t\tnode.CPUsFreqStats = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.CPUInfo(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.CPUsInfo) {\n\t\t\t\tnode.CPUsInfo = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.NetworkDeviceStats(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.NetworkDeviceStats) {\n\t\t\t\tnode.NetDevStats = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.DiskStats(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.DiskStats) {\n\t\t\t\tnode.DiskStats = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.Processes(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.Process) {\n\t\t\t\tnode.Processes = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t\tfunc() error {\n\t\t\tresp, err := source.MachineClient.ServiceList(source.ctx, &emptypb.Empty{})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tunpack(source, result.Nodes, &resultLock, resp, func(node *Node, value *machine.ServiceList) {\n\t\t\t\tnode.ServiceList = value\n\t\t\t})\n\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tvar eg errgroup.Group\n\n\tfor _, f := range gatherFuncs {\n\t\teg.Go(f)\n\t}\n\n\tif err := eg.Wait(); err != nil {\n\t\t// TODO: handle error\n\t\t_ = err\n\t}\n\n\treturn result\n}\n\nfunc (source *Source) node(msg helpers.Message) string {\n\thostname := msg.GetMetadata().GetHostname()\n\n\treturn source.Resolver.Resolve(hostname)\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/components.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package components implements specific widgets for the dashboard.\npackage components\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\nconst (\n\tnoData       = \"...\"\n\tnotAvailable = \"n/a\"\n\tnone         = \"<none>\"\n\tmaxLogLines  = 1000\n)\n\n// field represents a field in a widget consist of a name and a value, rendered next to each other.\ntype field struct {\n\tName  string\n\tValue string\n}\n\nfunc (f *field) render(nameWidth int) string {\n\treturn fmt.Sprintf(\"[::b]%s[::-] %s\", padRight(f.Name, nameWidth), f.Value)\n}\n\ntype fieldGroup struct {\n\tfields []field\n}\n\n// String implements the Stringer interface.\nfunc (fg *fieldGroup) String() string {\n\twidth := fg.maxFieldNameLength()\n\n\treturn strings.Join(\n\t\txslices.Map(fg.fields, func(t field) string {\n\t\t\treturn t.render(width)\n\t\t}),\n\t\t\"\\n\",\n\t)\n}\n\nfunc (fg *fieldGroup) maxFieldNameLength() int {\n\tresult := 0\n\n\tfor _, f := range fg.fields {\n\t\tresult = max(result, len(f.Name))\n\t}\n\n\treturn result\n}\n\n// padRight pads a string to the specified width by appending spaces to the end.\nfunc padRight(s string, width int) string {\n\treturn fmt.Sprintf(\"%-*s\", width, s)\n}\n\nfunc toHealthStatus(healthy bool) string {\n\tif healthy {\n\t\treturn formatStatus(\"Healthy\")\n\t}\n\n\treturn formatStatus(\"Unhealthy\")\n}\n\nfunc formatStatus(status any) string {\n\tstatusStr := capitalizeFirst(fmt.Sprintf(\"%v\", status))\n\n\tswitch strings.ToLower(statusStr) {\n\tcase \"running\", \"healthy\", \"true\":\n\t\treturn formatText(statusStr, true)\n\tcase \"stopped\", \"unhealthy\", \"false\":\n\t\treturn formatText(statusStr, false)\n\tdefault:\n\t\treturn statusStr\n\t}\n}\n\nfunc formatText(text string, ok bool) string {\n\tif text == \"\" {\n\t\treturn \"\"\n\t}\n\n\tif ok {\n\t\treturn fmt.Sprintf(\"[green]√ %s[-]\", text)\n\t}\n\n\treturn fmt.Sprintf(\"[red]× %s[-]\", text)\n}\n\n// capitalizeFirst capitalizes the first character of string.\nfunc capitalizeFirst(s string) string {\n\tif s == \"\" {\n\t\treturn s\n\t}\n\n\treturn strings.ToUpper(string(s[0])) + strings.ToLower(s[1:])\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/diagnostics.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Diagnostics represents the diagnostics widget.\ntype Diagnostics struct {\n\ttview.Grid\n\n\thline *HorizontalLine\n\tinfo  *tview.TextView\n\n\tselectedNode    string\n\tperNodeWarnings map[string][]*runtime.Diagnostic\n}\n\n// NewDiagnostics initializes Diagnostics.\nfunc NewDiagnostics() *Diagnostics {\n\twidget := &Diagnostics{\n\t\tGrid:            *tview.NewGrid(),\n\t\tinfo:            tview.NewTextView(),\n\t\thline:           NewHorizontalLine(\"Diagnostics\"),\n\t\tperNodeWarnings: make(map[string][]*runtime.Diagnostic),\n\t}\n\n\twidget.info.\n\t\tSetDynamicColors(true).\n\t\tSetBorderPadding(0, 0, 1, 1)\n\n\twidget.SetRows(1, 0).SetColumns(0)\n\n\twidget.AddItem(widget.hline, 0, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(widget.info, 1, 0, 1, 1, 0, 0, false)\n\n\treturn widget\n}\n\n// GetCurrentHeight returns the height of the widget.\nfunc (widget *Diagnostics) GetCurrentHeight() int {\n\tnumWarnings := len(widget.perNodeWarnings[widget.selectedNode])\n\tif numWarnings == 0 {\n\t\treturn 0\n\t}\n\n\treturn 1 + numWarnings\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *Diagnostics) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *Diagnostics) OnResourceDataChange(data resourcedata.Data) {\n\tr, ok := data.Resource.(*runtime.Diagnostic)\n\tif !ok {\n\t\treturn\n\t}\n\n\tidx := slices.IndexFunc(widget.perNodeWarnings[data.Node], func(warning *runtime.Diagnostic) bool {\n\t\treturn warning.Metadata().ID() == r.Metadata().ID()\n\t})\n\n\tif data.Deleted {\n\t\tif idx != -1 {\n\t\t\twidget.perNodeWarnings[data.Node] = slices.Delete(widget.perNodeWarnings[data.Node], idx, idx+1)\n\t\t}\n\t} else {\n\t\tif idx == -1 {\n\t\t\twidget.perNodeWarnings[data.Node] = append(widget.perNodeWarnings[data.Node], r)\n\t\t} else {\n\t\t\twidget.perNodeWarnings[data.Node][idx] = r\n\t\t}\n\t}\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n// WriteLog writes the log line to the widget.\nfunc (widget *Diagnostics) redraw() {\n\twidget.info.SetWrap(true)\n\twidget.info.Clear()\n\n\tfor _, warning := range widget.perNodeWarnings[widget.selectedNode] {\n\t\tfmt.Fprintf(widget.info, \"■ (%s) [red]%s[-]\\n\", //nolint:errcheck\n\t\t\ttview.Escape(warning.TypedSpec().DocumentationURL(warning.Metadata().ID())),\n\t\t\ttview.Escape(warning.TypedSpec().Message))\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/footer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/gen/maps\"\n)\n\n// hitRegion represents a clickable region in the footer.\ntype hitRegion struct {\n\tstartX int\n\tendX   int\n\tnode   string // non-empty if this is a node region\n\tscreen string // non-empty if this is a screen region\n}\n\n// Footer represents the top bar with host info.\ntype Footer struct {\n\ttview.TextView\n\n\tselectedNode string\n\tnodes        []string\n\n\tscreenKeyToName map[string]string\n\n\tselectedScreen string\n\tpaused         bool\n\n\thitRegions []hitRegion\n\n\t// NodeClick is called when a node label is clicked. May be nil.\n\tNodeClick func(node string)\n\t// ScreenClick is called when a screen label is clicked. May be nil.\n\tScreenClick func(screen string)\n}\n\n// NewFooter initializes Footer.\n//\n//nolint:gocyclo\nfunc NewFooter(screenKeyToName map[string]string, nodes []string) *Footer {\n\tvar initialScreen string\n\tfor _, name := range screenKeyToName {\n\t\tinitialScreen = name\n\n\t\tbreak\n\t}\n\n\twidget := &Footer{\n\t\tTextView:        *tview.NewTextView(),\n\t\tscreenKeyToName: screenKeyToName,\n\t\tselectedScreen:  initialScreen,\n\t\tnodes:           nodes,\n\t}\n\n\twidget.SetDynamicColors(true)\n\n\t// set the background to be a horizontal line\n\twidget.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {\n\t\tfor i := x; i < x+width; i++ {\n\t\t\tfor j := y; j < y+height; j++ {\n\t\t\t\tscreen.SetContent(\n\t\t\t\t\ti,\n\t\t\t\t\tj,\n\t\t\t\t\ttview.BoxDrawingsLightHorizontal,\n\t\t\t\t\tnil,\n\t\t\t\t\ttcell.StyleDefault.Foreground(tcell.ColorWhite),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\treturn x, y, width, height\n\t})\n\n\twidget.SetMouseCapture(func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) {\n\t\tif action != tview.MouseLeftClick {\n\t\t\treturn action, event\n\t\t}\n\n\t\tmx, _ := event.Position()\n\t\twx, _, _, _ := widget.GetRect()\n\t\tclickX := mx - wx\n\n\t\tfor _, region := range widget.hitRegions {\n\t\t\tif clickX >= region.startX && clickX < region.endX {\n\t\t\t\tif region.node != \"\" && widget.NodeClick != nil {\n\t\t\t\t\twidget.NodeClick(region.node)\n\t\t\t\t} else if region.screen != \"\" && widget.ScreenClick != nil {\n\t\t\t\t\twidget.ScreenClick(region.screen)\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn action, event\n\t})\n\n\twidget.refresh()\n\n\treturn widget\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *Footer) OnNodeSelect(node string) {\n\twidget.selectedNode = node\n\n\twidget.refresh()\n}\n\n// SelectScreen refreshes the footer with the tabs and screens data.\nfunc (widget *Footer) SelectScreen(screen string) {\n\twidget.selectedScreen = screen\n\n\twidget.refresh()\n}\n\n// SetPaused refreshes the footer with the new paused state.\nfunc (widget *Footer) SetPaused(paused bool) {\n\twidget.paused = paused\n\n\twidget.refresh()\n}\n\n// refresh rebuilds the footer text and updates hit regions for mouse click detection.\n//\n// The footer format is: [node1 | node2 | node3] --- [F1: Screen1] --- [Screen2] --- ...\n// where the selected node/screen is highlighted in red.\n// Hit regions track the x-offset ranges of each node and screen label.\nfunc (widget *Footer) refresh() {\n\tvar sb strings.Builder\n\n\tx := 0\n\twidget.hitRegions = widget.hitRegions[:0]\n\n\t// write appends s to the text and advances x by the visible character width.\n\twrite := func(s string, visibleWidth int) {\n\t\tsb.WriteString(s)\n\n\t\tx += visibleWidth\n\t}\n\n\t// Opening bracket wrapping the nodes section.\n\twrite(\"[\", 1)\n\n\tfor i, node := range widget.nodes {\n\t\tif i > 0 {\n\t\t\twrite(\" | \", 3)\n\t\t}\n\n\t\tdisplayName := node\n\t\tif displayName == \"\" {\n\t\t\tdisplayName = \"(local)\"\n\t\t}\n\n\t\tstartX := x\n\t\tnameLen := len([]rune(displayName))\n\n\t\tif node == widget.selectedNode {\n\t\t\twrite(fmt.Sprintf(\"[red]%s[-]\", displayName), nameLen)\n\t\t} else {\n\t\t\twrite(displayName, nameLen)\n\t\t}\n\n\t\twidget.hitRegions = append(widget.hitRegions, hitRegion{\n\t\t\tstartX: startX,\n\t\t\tendX:   x,\n\t\t\tnode:   node,\n\t\t})\n\t}\n\n\t// Closing bracket and separator between nodes and screens.\n\twrite(\"] --- \", 6)\n\n\tscreenKeys := maps.Keys(widget.screenKeyToName)\n\tslices.Sort(screenKeys)\n\n\tfor i, screenKey := range screenKeys {\n\t\tif i > 0 {\n\t\t\twrite(\" --- \", 5)\n\t\t}\n\n\t\tscreenName := widget.screenKeyToName[screenKey]\n\t\tstartX := x\n\n\t\tif screenName == widget.selectedScreen {\n\t\t\t// [[red]ScreenName[-]] renders as [ScreenName] (the [[ is an escaped [).\n\t\t\twrite(fmt.Sprintf(\"[[red]%s[-]]\", screenName), len([]rune(screenName))+2)\n\t\t} else {\n\t\t\t// [F1: ScreenName] is not a tview color tag and renders literally.\n\t\t\twrite(fmt.Sprintf(\"[%s: %s]\", screenKey, screenName), len(screenKey)+len([]rune(screenName))+4)\n\t\t}\n\n\t\twidget.hitRegions = append(widget.hitRegions, hitRegion{\n\t\t\tstartX: startX,\n\t\t\tendX:   x,\n\t\t\tscreen: screenName,\n\t\t})\n\t}\n\n\tif widget.paused {\n\t\t// [[yellow]PAUSED[-]] renders as [PAUSED] — no click region needed.\n\t\twrite(\" --- \", 5)\n\t\twrite(\"[[yellow]PAUSED[-]]\", 8)\n\t}\n\n\twidget.SetText(sb.String())\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/gauges.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"math\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/navidys/tvxwidgets\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n)\n\n// SystemGauges quickly show CPU/mem load.\ntype SystemGauges struct {\n\ttview.Primitive\n\n\tcpuGauge *tvxwidgets.PercentageModeGauge\n\tmemGauge *tvxwidgets.PercentageModeGauge\n}\n\n// NewSystemGauges creates SystemGauges.\nfunc NewSystemGauges() *SystemGauges {\n\troot := tview.NewGrid().SetRows(0).SetColumns(0)\n\troot.SetBorderPadding(1, 2, 1, 1)\n\n\tcpuGauge := tvxwidgets.NewPercentageModeGauge()\n\tcpuGauge.SetBorder(false)\n\tcpuGauge.SetMaxValue(100)\n\tcpuGauge.SetPgBgColor(tview.Styles.ContrastBackgroundColor)\n\n\tcpuFrame := tview.NewFrame(cpuGauge)\n\tcpuFrame.SetBorders(0, 0, 0, 0, 0, 0).\n\t\tAddText(\"[::b]CPU\", true, tview.AlignLeft, tcell.ColorDefault)\n\n\troot.AddItem(cpuFrame, 0, 0, 1, 1, 0, 0, false)\n\n\tmemGauge := tvxwidgets.NewPercentageModeGauge()\n\tmemGauge.SetBorder(false)\n\tmemGauge.SetMaxValue(100)\n\tmemGauge.SetPgBgColor(tview.Styles.ContrastBackgroundColor)\n\n\tmemFrame := tview.NewFrame(memGauge)\n\tmemFrame.SetBorders(0, 0, 0, 0, 0, 0).\n\t\tAddText(\"[::b]MEM\", true, tview.AlignLeft, tcell.ColorDefault)\n\n\troot.AddItem(memFrame, 1, 0, 1, 1, 0, 0, false)\n\n\twidget := &SystemGauges{\n\t\tPrimitive: root,\n\n\t\tcpuGauge: cpuGauge,\n\t\tmemGauge: memGauge,\n\t}\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *SystemGauges) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.cpuGauge.SetValue(0)\n\t\twidget.memGauge.SetValue(0)\n\t} else {\n\t\tmemUsed := nodeData.MemUsage()\n\t\twidget.memGauge.SetValue(int(math.Round(memUsed * 100.0)))\n\n\t\tcpuUsed := nodeData.CPUUsageByName(\"usage\")\n\t\twidget.cpuGauge.SetValue(int(math.Round(cpuUsed * 100.0)))\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/graphs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"slices\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/navidys/tvxwidgets\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n)\n\n// BaseGraph represents the widget with some usage graph.\ntype BaseGraph struct {\n\ttview.Primitive\n\n\tplot   *tvxwidgets.Plot\n\tlabels []string\n}\n\n// NewBaseGraph initializes BaseGraph.\nfunc NewBaseGraph(title string, labels []string) *BaseGraph {\n\twidget := &BaseGraph{\n\t\tplot:   tvxwidgets.NewPlot(),\n\t\tlabels: labels,\n\t}\n\n\troot := tview.NewFrame(widget.plot).\n\t\tSetBorders(0, 0, 0, 0, 0, 0).\n\t\tAddText(title, true, tview.AlignCenter, tcell.ColorDefault)\n\n\twidget.plot.SetBorder(false)\n\twidget.plot.SetLineColor([]tcell.Color{\n\t\ttcell.ColorRed,\n\t\ttcell.ColorGreen,\n\t})\n\twidget.plot.SetTitle(title)\n\twidget.plot.SetDrawAxes(false)\n\twidget.plot.SetMarker(tvxwidgets.PlotMarkerBraille)\n\n\twidget.Primitive = root\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *BaseGraph) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\tplotData := make([][]float64, len(widget.labels))\n\n\t\tfor i := range widget.labels {\n\t\t\tplotData[i] = []float64{0}\n\t\t}\n\n\t\twidget.plot.SetData(plotData)\n\n\t\treturn\n\t}\n\n\t_, _, width, _ := widget.plot.GetPlotRect() //nolint:dogsled\n\n\tplotData := make([][]float64, len(widget.labels))\n\n\tfor i, name := range widget.labels {\n\t\tseries := nodeData.Series[name]\n\n\t\tmaxPoints := min(width, len(series))\n\n\t\tplotData[i] = slices.Clone(series[len(series)-maxPoints:])\n\t}\n\n\twidget.plot.SetData(plotData)\n}\n\n// NewCPUGraph creates CPU usage graph.\nfunc NewCPUGraph() *BaseGraph {\n\treturn NewBaseGraph(\"[::b]CPU USER/SYSTEM\", []string{\"user\", \"system\"})\n}\n\n// NewMemGraph creates mem usage graph.\nfunc NewMemGraph() *BaseGraph {\n\treturn NewBaseGraph(\"[::b]MEM USED\", []string{\"mem\"})\n}\n\n// NewLoadAvgGraph creates loadavg graph.\nfunc NewLoadAvgGraph() *BaseGraph {\n\treturn NewBaseGraph(\"[::b]LOAD AVG 60sec\", []string{\"loadavg\"})\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/header.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst noHostname = \"(no hostname)\"\n\ntype headerData struct {\n\thostname        string\n\tversion         string\n\tuptime          string\n\tcpuFreq         string\n\ttotalMem        string\n\tnumProcesses    string\n\tcpuUsagePercent string\n\tmemUsagePercent string\n}\n\n// Header represents the top bar with host info.\ntype Header struct {\n\ttview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*headerData\n\tspinnerPos   int\n}\n\n// NewHeader initializes Header.\nfunc NewHeader() *Header {\n\theader := &Header{\n\t\tTextView: *tview.NewTextView(),\n\t\tnodeMap:  make(map[string]*headerData),\n\t}\n\n\theader.SetDynamicColors(true).SetText(noData)\n\n\treturn header\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *Header) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *Header) OnResourceDataChange(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch res := data.Resource.(type) { //nolint:gocritic\n\tcase *network.HostnameStatus:\n\t\tif data.Deleted {\n\t\t\tnodeData.hostname = noHostname\n\t\t} else {\n\t\t\tnodeData.hostname = res.TypedSpec().Hostname\n\t\t}\n\t}\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *Header) OnAPIDataChange(node string, data *apidata.Data) {\n\tfor node, nodeData := range data.Nodes {\n\t\twidget.updateNodeAPIData(node, nodeData)\n\t}\n\n\tif node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n// OnTick implements the TickerListener interface.\nfunc (widget *Header) OnTick() {\n\twidget.spinnerPos++\n\n\twidget.redraw()\n}\n\nfunc (widget *Header) humanizeCPUFrequency(mhz float64) string {\n\tvalue := math.Round(mhz)\n\tunit := \"MHz\"\n\n\tif mhz >= 1000 {\n\t\tghz := value / 1000\n\t\tvalue = math.Round(ghz*100) / 100\n\t\tunit = \"GHz\"\n\t}\n\n\treturn fmt.Sprintf(\"%s%s\", humanize.Ftoa(value), unit)\n}\n\n// formatUptime returns a duration in a human readable form.\n//\n// If d>24h returns format \"23d72h3m5s\", otherwise \"72h3m5s\".\nfunc formatUptime(d time.Duration) string {\n\tconst day = 24 * time.Hour\n\n\td = d.Round(time.Second)\n\tif d >= day {\n\t\tuptimeDays := d / day\n\t\tuptimeRest := d % day\n\n\t\treturn fmt.Sprintf(\"%dd%s\", uptimeDays, uptimeRest)\n\t}\n\n\treturn d.String()\n}\n\n// Spinner is a set of characters compatible with Linux virtual console CP437.\nvar spinner = []string{\"\\u2510\", \"\\u2518\", \"\\u2514\", \"\\u250C\"}\n\nfunc (widget *Header) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\tspinnerPos := widget.spinnerPos % len(spinner)\n\n\ttext := fmt.Sprintf(\n\t\t\"[green]%s [yellow::b]%s[-:-:-] (%s): uptime %s, %s, %s RAM, PROCS %s, CPU %s, RAM %s\",\n\t\tspinner[spinnerPos],\n\t\tdata.hostname,\n\t\tdata.version,\n\t\tdata.uptime,\n\t\tdata.cpuFreq,\n\t\tdata.totalMem,\n\t\tdata.numProcesses,\n\t\tdata.cpuUsagePercent,\n\t\tdata.memUsagePercent,\n\t)\n\n\twidget.SetText(text)\n}\n\n//nolint:gocyclo\nfunc (widget *Header) updateNodeAPIData(node string, data *apidata.Node) {\n\tnodeData := widget.getOrCreateNodeData(node)\n\n\tif data == nil {\n\t\treturn\n\t}\n\n\tnodeData.cpuUsagePercent = fmt.Sprintf(\"%.1f%%\", data.CPUUsageByName(\"usage\")*100.0)\n\tnodeData.memUsagePercent = fmt.Sprintf(\"%.1f%%\", data.MemUsage()*100.0)\n\n\tif data.Version != nil {\n\t\tnodeData.version = data.Version.GetVersion().GetTag()\n\t} else {\n\t\tnodeData.version = notAvailable\n\t}\n\n\tif data.SystemStat != nil && data.SystemStat.BootTime != 0 {\n\t\tuptime := time.Since(time.Unix(int64(data.SystemStat.GetBootTime()), 0))\n\t\tnodeData.uptime = formatUptime(uptime)\n\t} else {\n\t\tnodeData.uptime = notAvailable\n\t}\n\n\tif data.CPUsInfo != nil {\n\t\tnumCPUs := len(data.CPUsInfo.GetCpuInfo())\n\n\t\tif numCPUs > 0 {\n\t\t\tnodeData.cpuFreq = fmt.Sprintf(\"%dx%s\", numCPUs, widget.humanizeCPUFrequency(data.CPUsInfo.GetCpuInfo()[0].GetCpuMhz()))\n\t\t}\n\t} else {\n\t\tnodeData.cpuFreq = notAvailable\n\t}\n\n\tif data.CPUsFreqStats != nil && data.CPUsFreqStats.CpuFreqStats != nil {\n\t\tnumCPUs := len(data.CPUsFreqStats.CpuFreqStats)\n\t\tuniqMhz := make(map[uint64]int, numCPUs)\n\n\t\tfor _, cpuFreqStat := range data.CPUsFreqStats.CpuFreqStats {\n\t\t\tuniqMhz[cpuFreqStat.CurrentFrequency]++\n\t\t}\n\n\t\tkeys := make([]uint64, 0, len(uniqMhz))\n\n\t\tfor mhz := range uniqMhz {\n\t\t\tif mhz == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tkeys = append(keys, mhz)\n\t\t}\n\n\t\tif len(keys) > 0 {\n\t\t\tsort.Slice(keys, func(i, j int) bool { return keys[i] > keys[j] })\n\n\t\t\tnodeData.cpuFreq = \"\"\n\t\t}\n\n\t\tfor i, mhz := range keys {\n\t\t\tif i > 0 {\n\t\t\t\tnodeData.cpuFreq += \" \"\n\t\t\t}\n\n\t\t\tnodeData.cpuFreq += fmt.Sprintf(\"%dx%s\", uniqMhz[mhz], widget.humanizeCPUFrequency(float64(mhz)/1000.0))\n\t\t}\n\t} else {\n\t\tnodeData.cpuFreq = notAvailable\n\t}\n\n\tif data.Processes != nil {\n\t\tnodeData.numProcesses = strconv.Itoa(len(data.Processes.GetProcesses()))\n\t} else {\n\t\tnodeData.numProcesses = notAvailable\n\t}\n\n\tif data.Memory != nil {\n\t\tnodeData.totalMem = humanize.IBytes(data.Memory.GetMeminfo().GetMemtotal() << 10)\n\t} else {\n\t\tnodeData.totalMem = notAvailable\n\t}\n}\n\nfunc (widget *Header) getOrCreateNodeData(node string) *headerData {\n\tdata, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tdata = &headerData{\n\t\t\thostname:        notAvailable,\n\t\t\tversion:         notAvailable,\n\t\t\tuptime:          notAvailable,\n\t\t\tcpuFreq:         notAvailable,\n\t\t\ttotalMem:        notAvailable,\n\t\t\tnumProcesses:    notAvailable,\n\t\t\tcpuUsagePercent: notAvailable,\n\t\t\tmemUsagePercent: notAvailable,\n\t\t}\n\n\t\twidget.nodeMap[node] = data\n\t}\n\n\treturn data\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/horizontalline.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tview\"\n)\n\n// HorizontalLine is a widget that draws a horizontal line.\ntype HorizontalLine struct {\n\ttview.TextView\n\n\tlabel []rune\n}\n\n// NewHorizontalLine initializes HorizontalLine.\nfunc NewHorizontalLine(label string) *HorizontalLine {\n\twidget := &HorizontalLine{\n\t\tTextView: *tview.NewTextView(),\n\t\tlabel:    []rune(\" \" + label + \" \"),\n\t}\n\n\tconst leftGap = 2\n\n\t// set the background to be a horizontal line\n\twidget.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {\n\t\tlabelLength := len(widget.label)\n\n\t\tfor i := x; i < x+width; i++ {\n\t\t\tfor j := y; j < y+height; j++ {\n\t\t\t\tif j == y && i >= leftGap && i-leftGap < labelLength {\n\t\t\t\t\tscreen.SetContent(i, j, widget.label[i-leftGap], nil, tcell.StyleDefault.Foreground(tcell.ColorYellow))\n\t\t\t\t} else {\n\t\t\t\t\tscreen.SetContent(i, j, tview.BoxDrawingsLightHorizontal, nil, tcell.StyleDefault.Foreground(tcell.ColorWhite))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn x, y, width, height\n\t})\n\n\treturn widget\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/info.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n)\n\n// LoadAvgInfo represents the widget with load average info.\ntype LoadAvgInfo struct {\n\ttview.TextView\n}\n\n// NewLoadAvgInfo initializes LoadAvgInfo.\nfunc NewLoadAvgInfo() *LoadAvgInfo {\n\twidget := &LoadAvgInfo{\n\t\tTextView: *tview.NewTextView(),\n\t}\n\n\twidget.SetBorder(false)\n\twidget.SetBorderPadding(1, 0, 1, 0)\n\twidget.SetDynamicColors(true)\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *LoadAvgInfo) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.SetText(noData)\n\t} else {\n\t\twidget.SetText(fmt.Sprintf(\n\t\t\t\"[::b]LOAD[::-]\\n\"+\n\t\t\t\t\"1 min  [::b]%6.2f[::-]\\n\"+\n\t\t\t\t\"5 min  [::b]%6.2f[::-]\\n\"+\n\t\t\t\t\"15 min [::b]%6.2f[::-]\",\n\t\t\tnodeData.LoadAvg.GetLoad1(),\n\t\t\tnodeData.LoadAvg.GetLoad5(),\n\t\t\tnodeData.LoadAvg.GetLoad15(),\n\t\t))\n\t}\n}\n\n// ProcsInfo represents the widget with processes info.\ntype ProcsInfo struct {\n\ttview.TextView\n}\n\n// NewProcsInfo initializes ProcsInfo.\nfunc NewProcsInfo() *ProcsInfo {\n\twidget := &ProcsInfo{\n\t\tTextView: *tview.NewTextView(),\n\t}\n\n\twidget.SetBorder(false)\n\twidget.SetBorderPadding(1, 0, 1, 0)\n\twidget.SetDynamicColors(true)\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *ProcsInfo) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.SetText(noData)\n\t} else {\n\t\tprocsCreated, suffix := humanize.ComputeSI(float64(nodeData.ProcsCreated()))\n\n\t\twidget.SetText(fmt.Sprintf(\n\t\t\t\"[::b]PROCS[::-]\\n\"+\n\t\t\t\t\"Created [::b]%5.1f%s[::-]\\n\"+\n\t\t\t\t\"Running [::b]%5d[::-]\\n\"+\n\t\t\t\t\"Blocked [::b]%5d[::-]\",\n\t\t\tprocsCreated, suffix,\n\t\t\tnodeData.SystemStat.GetProcessRunning(),\n\t\t\tnodeData.SystemStat.GetProcessBlocked(),\n\t\t))\n\t}\n}\n\n// MemInfo represents the widget with memory info.\ntype MemInfo struct {\n\ttview.TextView\n}\n\n// NewMemInfo initializes LoadAvgInfo.\nfunc NewMemInfo() *MemInfo {\n\twidget := &MemInfo{\n\t\tTextView: *tview.NewTextView(),\n\t}\n\n\twidget.SetBorder(false)\n\twidget.SetBorderPadding(1, 0, 1, 0)\n\twidget.SetDynamicColors(true)\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *MemInfo) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.SetText(noData)\n\t} else {\n\t\twidget.SetText(fmt.Sprintf(\n\t\t\t\"[::b]MEMORY[::-]\\n\"+\n\t\t\t\t\"Total  [::b]%8s[::-]  Buffers [::b]%8s[::-]\\n\"+\n\t\t\t\t\"Used   [::b]%8s[::-]  Cache   [::b]%8s[::-]\\n\"+\n\t\t\t\t\"Free   [::b]%8s[::-]  Avail   [::b]%8s[::-]\\n\"+\n\t\t\t\t\"Shared [::b]%8s[::-]  Swapped [::b]%8s[::-]\\n\",\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetMemtotal()<<10),\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetBuffers()<<10),\n\t\t\thumanize.Bytes((nodeData.Memory.GetMeminfo().GetMemtotal()-nodeData.Memory.GetMeminfo().GetMemfree()-nodeData.Memory.GetMeminfo().GetCached()-nodeData.Memory.GetMeminfo().GetBuffers())<<10),\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetCached()<<10),\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetMemfree()<<10),\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetMemavailable()<<10),\n\t\t\thumanize.Bytes(nodeData.Memory.GetMeminfo().GetShmem()<<10),\n\t\t\thumanize.Bytes((nodeData.Memory.GetMeminfo().GetSwaptotal()-nodeData.Memory.GetMeminfo().GetSwapfree())<<10),\n\t\t))\n\t}\n}\n\n// CPUInfo represents the widget with CPU info.\ntype CPUInfo struct {\n\ttview.TextView\n}\n\n// NewCPUInfo initializes CPUInfo.\nfunc NewCPUInfo() *CPUInfo {\n\twidget := &CPUInfo{\n\t\tTextView: *tview.NewTextView(),\n\t}\n\n\twidget.SetBorder(false)\n\twidget.SetBorderPadding(1, 0, 1, 0)\n\twidget.SetDynamicColors(true)\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *CPUInfo) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.SetText(noData)\n\t} else {\n\t\tctxSw, suffix := humanize.ComputeSI(float64(nodeData.CtxSwitches()))\n\n\t\twidget.SetText(fmt.Sprintf(\n\t\t\t\"[::b]CPU[::-]\\n\"+\n\t\t\t\t\"User   [::b]%5.1f%%[::-]  Nice   [::b]%5.1f%%[::-]\\n\"+\n\t\t\t\t\"System [::b]%5.1f%%[::-]  IRQ    [::b]%5.1f%%[::-]\\n\"+\n\t\t\t\t\"Idle   [::b]%5.1f%%[::-]  Iowait [::b]%5.1f%%[::-]\\n\"+\n\t\t\t\t\"Steal  [::b]%5.1f%%[::-]  CtxSw  [::b]%5.1f%s[::-]\\n\",\n\t\t\tnodeData.CPUUsageByName(\"user\")*100.0, nodeData.CPUUsageByName(\"nice\")*100.0,\n\t\t\tnodeData.CPUUsageByName(\"system\")*100.0, nodeData.CPUUsageByName(\"irq\")*100.0,\n\t\t\tnodeData.CPUUsageByName(\"idle\")*100.0, nodeData.CPUUsageByName(\"iowait\")*100.0,\n\t\t\tnodeData.CPUUsageByName(\"steal\")*100.0, ctxSw, suffix,\n\t\t))\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/kubernetesinfo.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/gen/maps\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\ntype staticPodStatuses struct {\n\tapiServer         string\n\tcontrollerManager string\n\tscheduler         string\n}\n\ntype kubernetesInfoData struct {\n\tisControlPlane    bool\n\ttyp               string\n\tkubernetesVersion string\n\tkubeletStatus     string\n\n\tpodStatuses        staticPodStatuses\n\tstaticPodStatusMap map[resource.ID]*k8s.StaticPodStatus\n}\n\n// KubernetesInfo represents the kubernetes info widget.\ntype KubernetesInfo struct {\n\ttview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*kubernetesInfoData\n}\n\n// NewKubernetesInfo initializes KubernetesInfo.\nfunc NewKubernetesInfo() *KubernetesInfo {\n\tkubernetes := &KubernetesInfo{\n\t\tTextView: *tview.NewTextView(),\n\t\tnodeMap:  make(map[string]*kubernetesInfoData),\n\t}\n\n\tkubernetes.SetDynamicColors(true).\n\t\tSetText(noData).\n\t\tSetBorderPadding(1, 0, 1, 0)\n\n\treturn kubernetes\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *KubernetesInfo) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *KubernetesInfo) OnResourceDataChange(data resourcedata.Data) {\n\twidget.updateNodeData(data)\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *KubernetesInfo) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeAPIData := data.Nodes[node]\n\n\twidget.updateNodeAPIData(node, nodeAPIData)\n\n\tif node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\nfunc (widget *KubernetesInfo) updateNodeData(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch res := data.Resource.(type) {\n\tcase *k8s.KubeletSpec:\n\t\tif data.Deleted {\n\t\t\tnodeData.kubernetesVersion = notAvailable\n\t\t} else {\n\t\t\timageParts := strings.Split(res.TypedSpec().Image, \":\")\n\t\t\tif len(imageParts) > 0 {\n\t\t\t\tnodeData.kubernetesVersion = imageParts[len(imageParts)-1]\n\t\t\t}\n\t\t}\n\tcase *k8s.StaticPodStatus:\n\t\tif data.Deleted {\n\t\t\tdelete(nodeData.staticPodStatusMap, res.Metadata().ID())\n\t\t} else {\n\t\t\tnodeData.staticPodStatusMap[res.Metadata().ID()] = res\n\t\t}\n\n\t\tnodeData.podStatuses = widget.staticPodStatuses(maps.Values(nodeData.staticPodStatusMap))\n\tcase *config.MachineType:\n\t\tif data.Deleted {\n\t\t\tnodeData.isControlPlane = false\n\t\t\tnodeData.typ = notAvailable\n\t\t} else {\n\t\t\tnodeData.isControlPlane = res.MachineType() == machine.TypeControlPlane\n\t\t\tnodeData.typ = res.MachineType().String()\n\t\t}\n\t}\n}\n\nfunc (widget *KubernetesInfo) updateNodeAPIData(node string, data *apidata.Node) {\n\tnodeData := widget.getOrCreateNodeData(node)\n\n\tif data != nil && data.ServiceList != nil {\n\t\tfor _, info := range data.ServiceList.GetServices() {\n\t\t\tif info.Id == \"kubelet\" {\n\t\t\t\tnodeData.kubeletStatus = toHealthStatus(info.GetHealth().Healthy)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (widget *KubernetesInfo) getOrCreateNodeData(node string) *kubernetesInfoData {\n\tnodeData, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tnodeData = &kubernetesInfoData{\n\t\t\ttyp:               notAvailable,\n\t\t\tkubernetesVersion: notAvailable,\n\t\t\tkubeletStatus:     notAvailable,\n\t\t\tpodStatuses: staticPodStatuses{\n\t\t\t\tapiServer:         notAvailable,\n\t\t\t\tcontrollerManager: notAvailable,\n\t\t\t\tscheduler:         notAvailable,\n\t\t\t},\n\t\t\tstaticPodStatusMap: make(map[resource.ID]*k8s.StaticPodStatus),\n\t\t}\n\n\t\twidget.nodeMap[node] = nodeData\n\t}\n\n\treturn nodeData\n}\n\nfunc (widget *KubernetesInfo) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tfieldList := make([]field, 0, 5)\n\n\tfieldList = append(fieldList,\n\t\tfield{\n\t\t\tName:  \"TYPE\",\n\t\t\tValue: data.typ,\n\t\t},\n\t\tfield{\n\t\t\tName:  \"KUBERNETES\",\n\t\t\tValue: data.kubernetesVersion,\n\t\t},\n\t\tfield{\n\t\t\tName:  \"KUBELET\",\n\t\t\tValue: data.kubeletStatus,\n\t\t})\n\n\tif data.isControlPlane {\n\t\tfieldList = append(fieldList,\n\t\t\tfield{\n\t\t\t\tName:  \"APISERVER\",\n\t\t\t\tValue: data.podStatuses.apiServer,\n\t\t\t},\n\t\t\tfield{\n\t\t\t\tName:  \"CONTROLLER-MANAGER\",\n\t\t\t\tValue: data.podStatuses.controllerManager,\n\t\t\t},\n\t\t\tfield{\n\t\t\t\tName:  \"SCHEDULER\",\n\t\t\t\tValue: data.podStatuses.scheduler,\n\t\t\t})\n\t}\n\n\tfields := fieldGroup{\n\t\tfields: fieldList,\n\t}\n\n\twidget.SetText(fields.String())\n}\n\nfunc (widget *KubernetesInfo) staticPodStatuses(statuses []*k8s.StaticPodStatus) staticPodStatuses {\n\tresult := staticPodStatuses{\n\t\tapiServer:         notAvailable,\n\t\tcontrollerManager: notAvailable,\n\t\tscheduler:         notAvailable,\n\t}\n\n\tisReady := func(podStatus map[string]any) string {\n\t\tconditions, conditionsOk := podStatus[\"conditions\"]\n\t\tif !conditionsOk {\n\t\t\treturn notAvailable\n\t\t}\n\n\t\tconditionsSlc, conditionsSlcOk := conditions.([]any)\n\t\tif !conditionsSlcOk {\n\t\t\treturn notAvailable\n\t\t}\n\n\t\tfor _, condition := range conditionsSlc {\n\t\t\tconditionObj, conditionObjOk := condition.(map[string]any)\n\t\t\tif !conditionObjOk {\n\t\t\t\treturn notAvailable\n\t\t\t}\n\n\t\t\tif conditionObj[\"type\"] == \"Ready\" {\n\t\t\t\treturn toHealthStatus(conditionObj[\"status\"] == \"True\")\n\t\t\t}\n\t\t}\n\n\t\treturn notAvailable\n\t}\n\n\tfor _, status := range statuses {\n\t\tpodStatus := status.TypedSpec().PodStatus\n\n\t\tswitch {\n\t\tcase strings.Contains(status.Metadata().ID(), \"kube-apiserver\"):\n\t\t\tresult.apiServer = isReady(podStatus)\n\t\tcase strings.Contains(status.Metadata().ID(), \"kube-controller-manager\"):\n\t\t\tresult.controllerManager = isReady(podStatus)\n\t\tcase strings.Contains(status.Metadata().ID(), \"kube-scheduler\"):\n\t\t\tresult.scheduler = isReady(podStatus)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/logviewer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tview\"\n)\n\n// LogViewer represents the logs widget.\ntype LogViewer struct {\n\ttview.Grid\n\n\tlogs tview.TextView\n}\n\n// NewLogViewer initializes LogViewer.\nfunc NewLogViewer() *LogViewer {\n\twidget := &LogViewer{\n\t\tGrid: *tview.NewGrid(),\n\t\tlogs: *tview.NewTextView(),\n\t}\n\n\twidget.logs.ScrollToEnd().\n\t\tSetDynamicColors(true).\n\t\tSetMaxLines(maxLogLines).\n\t\tSetText(noData).\n\t\tSetBorderPadding(0, 0, 1, 1).\n\t\tSetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {\n\t\t\t_, _, _, pageSize := widget.logs.GetInnerRect()\n\t\t\tlineOffset, columnOffset := widget.logs.GetScrollOffset()\n\n\t\t\t//nolint:exhaustive\n\t\t\tswitch event.Key() {\n\t\t\tcase tcell.KeyCtrlD:\n\t\t\t\twidget.logs.ScrollTo(lineOffset+(pageSize/2), columnOffset)\n\n\t\t\t\treturn nil\n\t\t\tcase tcell.KeyCtrlU:\n\t\t\t\twidget.logs.ScrollTo(lineOffset-(pageSize/2), columnOffset)\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn event\n\t\t})\n\n\twidget.SetRows(1, 0).SetColumns(0)\n\n\twidget.AddItem(NewHorizontalLine(\"Logs\"), 0, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(&widget.logs, 1, 0, 1, 1, 0, 0, true)\n\n\treturn widget\n}\n\n// WriteLog writes the log line to the widget.\nfunc (widget *LogViewer) WriteLog(logLine, logError string) {\n\tif logError != \"\" {\n\t\tlogLine = \"[red]\" + tview.Escape(logError) + \"[-]\\n\"\n\t} else {\n\t\tlogLine = tview.Escape(logLine) + \"\\n\"\n\t}\n\n\twidget.logs.Write([]byte(logLine)) //nolint:errcheck\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/networkinfo.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nvar (\n\tzeroPrefix    = netip.Prefix{}\n\troutedNoK8sID = network.FilteredNodeAddressID(network.NodeAddressRoutedID, k8s.NodeAddressFilterNoK8s)\n)\n\ntype networkInfoData struct {\n\thostname     string\n\tgateway      string\n\tconnectivity string\n\tresolvers    string\n\ttimeservers  string\n\n\taddresses              string\n\tnodeAddressRouted      *network.NodeAddress\n\tnodeAddressRoutedNoK8s *network.NodeAddress\n\n\trouteStatusMap map[resource.ID]*network.RouteStatus\n}\n\n// NetworkInfo represents the network info widget.\ntype NetworkInfo struct {\n\ttview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*networkInfoData\n}\n\n// NewNetworkInfo initializes NetworkInfo.\nfunc NewNetworkInfo() *NetworkInfo {\n\tcomponent := &NetworkInfo{\n\t\tTextView: *tview.NewTextView(),\n\t\tnodeMap:  make(map[string]*networkInfoData),\n\t}\n\n\tcomponent.SetDynamicColors(true).\n\t\tSetText(noData).\n\t\tSetBorderPadding(1, 0, 1, 0)\n\n\treturn component\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *NetworkInfo) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *NetworkInfo) OnResourceDataChange(data resourcedata.Data) {\n\twidget.updateNodeData(data)\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n//nolint:gocyclo\nfunc (widget *NetworkInfo) updateNodeData(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch res := data.Resource.(type) {\n\tcase *network.ResolverStatus:\n\t\tif data.Deleted {\n\t\t\tnodeData.resolvers = notAvailable\n\t\t} else {\n\t\t\tnodeData.resolvers = widget.resolvers(res)\n\t\t}\n\tcase *network.TimeServerStatus:\n\t\tif data.Deleted {\n\t\t\tnodeData.timeservers = notAvailable\n\t\t} else {\n\t\t\tnodeData.timeservers = widget.timeservers(res)\n\t\t}\n\tcase *network.Status:\n\t\tif data.Deleted {\n\t\t\tnodeData.connectivity = notAvailable\n\t\t} else {\n\t\t\tnodeData.connectivity = widget.connectivity(res)\n\t\t}\n\tcase *network.HostnameStatus:\n\t\tif data.Deleted {\n\t\t\tnodeData.hostname = notAvailable\n\t\t} else {\n\t\t\tnodeData.hostname = res.TypedSpec().Hostname\n\t\t}\n\tcase *network.RouteStatus:\n\t\tif data.Deleted {\n\t\t\tdelete(nodeData.routeStatusMap, res.Metadata().ID())\n\t\t} else {\n\t\t\tnodeData.routeStatusMap[res.Metadata().ID()] = res\n\t\t}\n\n\t\tnodeData.gateway = widget.gateway(maps.Values(nodeData.routeStatusMap))\n\tcase *network.NodeAddress:\n\t\twidget.setAddresses(data, res)\n\t}\n}\n\nfunc (widget *NetworkInfo) getOrCreateNodeData(node string) *networkInfoData {\n\tdata, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tdata = &networkInfoData{\n\t\t\thostname:       notAvailable,\n\t\t\taddresses:      notAvailable,\n\t\t\tgateway:        notAvailable,\n\t\t\tconnectivity:   notAvailable,\n\t\t\tresolvers:      notAvailable,\n\t\t\ttimeservers:    notAvailable,\n\t\t\trouteStatusMap: make(map[resource.ID]*network.RouteStatus),\n\t\t}\n\n\t\twidget.nodeMap[node] = data\n\t}\n\n\treturn data\n}\n\nfunc (widget *NetworkInfo) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tfields := fieldGroup{\n\t\tfields: []field{\n\t\t\t{\n\t\t\t\tName:  \"HOST\",\n\t\t\t\tValue: data.hostname,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"IP\",\n\t\t\t\tValue: data.addresses,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"GW\",\n\t\t\t\tValue: data.gateway,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"CONNECTIVITY\",\n\t\t\t\tValue: data.connectivity,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"DNS\",\n\t\t\t\tValue: data.resolvers,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"NTP\",\n\t\t\t\tValue: data.timeservers,\n\t\t\t},\n\t\t},\n\t}\n\n\twidget.SetText(fields.String())\n}\n\nfunc (widget *NetworkInfo) setAddresses(data resourcedata.Data, nodeAddress *network.NodeAddress) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch nodeAddress.Metadata().ID() {\n\tcase network.NodeAddressRoutedID:\n\t\tif data.Deleted {\n\t\t\tnodeData.nodeAddressRouted = nil\n\t\t} else {\n\t\t\tnodeData.nodeAddressRouted = nodeAddress\n\t\t}\n\tcase routedNoK8sID:\n\t\tif data.Deleted {\n\t\t\tnodeData.nodeAddressRoutedNoK8s = nil\n\t\t} else {\n\t\t\tnodeData.nodeAddressRoutedNoK8s = nodeAddress\n\t\t}\n\t}\n\n\tformatIPs := func(res *network.NodeAddress) string {\n\t\tif res == nil {\n\t\t\treturn notAvailable\n\t\t}\n\n\t\tstrs := xslices.Map(res.TypedSpec().Addresses, netip.Prefix.String)\n\n\t\tslices.Sort(strs)\n\n\t\treturn strings.Join(strs, \", \")\n\t}\n\n\t// if \"routed-no-k8s\" is available, use it\n\tif nodeData.nodeAddressRoutedNoK8s != nil {\n\t\tnodeData.addresses = formatIPs(nodeData.nodeAddressRoutedNoK8s)\n\n\t\treturn\n\t}\n\n\t// fallback to \"routed\"\n\tnodeData.addresses = formatIPs(nodeData.nodeAddressRouted)\n}\n\nfunc (widget *NetworkInfo) gateway(statuses []*network.RouteStatus) string {\n\tvar gatewaysV4, gatewaysV6 []string\n\n\tfor _, status := range statuses {\n\t\tgateway := status.TypedSpec().Gateway\n\t\tif !gateway.IsValid() ||\n\t\t\tstatus.TypedSpec().Destination != zeroPrefix {\n\t\t\tcontinue\n\t\t}\n\n\t\tif gateway.Is4() {\n\t\t\tgatewaysV4 = append(gatewaysV4, gateway.String())\n\t\t} else {\n\t\t\tgatewaysV6 = append(gatewaysV6, gateway.String())\n\t\t}\n\t}\n\n\tif len(gatewaysV4) == 0 && len(gatewaysV6) == 0 {\n\t\treturn notAvailable\n\t}\n\n\tslices.Sort(gatewaysV4)\n\tslices.Sort(gatewaysV6)\n\n\treturn strings.Join(append(gatewaysV4, gatewaysV6...), \", \")\n}\n\nfunc (widget *NetworkInfo) resolvers(status *network.ResolverStatus) string {\n\tstrs := xslices.Map(status.TypedSpec().DNSServers, netip.Addr.String)\n\n\tif len(strs) == 0 {\n\t\treturn none\n\t}\n\n\treturn strings.Join(strs, \", \")\n}\n\nfunc (widget *NetworkInfo) timeservers(status *network.TimeServerStatus) string {\n\tif len(status.TypedSpec().NTPServers) == 0 {\n\t\treturn none\n\t}\n\n\treturn strings.Join(status.TypedSpec().NTPServers, \", \")\n}\n\nfunc (widget *NetworkInfo) connectivity(status *network.Status) string {\n\tif status.TypedSpec().ConnectivityReady {\n\t\treturn \"[green]√ OK[-]\"\n\t}\n\n\treturn \"[red]× FAILED[-]\"\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/sparklines.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/navidys/tvxwidgets\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n)\n\n// BaseSparklineGroup represents the widget with some sparklines.\ntype BaseSparklineGroup struct {\n\ttview.Primitive\n\n\tsparklines []*tvxwidgets.Sparkline\n\tdataLabels []string\n}\n\n// NewBaseSparklineGroup initializes BaseSparklineGroup.\nfunc NewBaseSparklineGroup(title string, labels, dataLabels []string) *BaseSparklineGroup {\n\tflex := tview.NewFlex().SetDirection(tview.FlexRow)\n\troot := tview.NewFrame(flex).\n\t\tSetBorders(0, 0, 0, 0, 0, 0).\n\t\tAddText(title, true, tview.AlignLeft, tcell.ColorDefault)\n\n\tcolors := []tcell.Color{tcell.ColorRed, tcell.ColorGreen}\n\n\tsparklines := make([]*tvxwidgets.Sparkline, len(labels))\n\n\tfor i := range labels {\n\t\tsparklines[i] = tvxwidgets.NewSparkline()\n\t\tsparklines[i].SetBorder(false)\n\t\tsparklines[i].SetDataTitle(labels[i])\n\t\tsparklines[i].SetTitleColor(tcell.ColorDefault)\n\t\tsparklines[i].SetLineColor(colors[i%len(colors)])\n\n\t\tflex.AddItem(sparklines[i], 0, 1, false)\n\t}\n\n\treturn &BaseSparklineGroup{\n\t\tPrimitive:  root,\n\t\tsparklines: sparklines,\n\t\tdataLabels: dataLabels,\n\t}\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *BaseSparklineGroup) OnAPIDataChange(node string, data *apidata.Data) {\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\tfor i := range widget.sparklines {\n\t\t\twidget.sparklines[i].SetData([]float64{0})\n\t\t}\n\n\t\treturn\n\t}\n\n\t_, _, width, _ := widget.GetRect() //nolint:dogsled\n\n\tfor i, name := range widget.dataLabels {\n\t\tseries := nodeData.Series[name]\n\n\t\tif len(series) < width {\n\t\t\twidth = len(series)\n\t\t}\n\n\t\twidget.sparklines[i].SetData(series[len(series)-width:])\n\t}\n}\n\n// NewNetSparkline creates network sparkline.\nfunc NewNetSparkline() *BaseSparklineGroup {\n\treturn NewBaseSparklineGroup(\" [::b]NET\", []string{\"RX\", \"TX\"}, []string{\"netrxbytes\", \"nettxbytes\"})\n}\n\n// NewDiskSparkline creates disk sparkline.\nfunc NewDiskSparkline() *BaseSparklineGroup {\n\treturn NewBaseSparklineGroup(\" [::b]DISK\", []string{\"READ\", \"WRITE\"}, []string{\"diskrdsectors\", \"diskwrsectors\"})\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/tables.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n)\n\n// ProcessTable represents the widget with process info.\ntype ProcessTable struct {\n\t*tview.Table\n\n\tlastNode string\n}\n\n// NewProcessTable initializes ProcessTable.\nfunc NewProcessTable() *ProcessTable {\n\twidget := &ProcessTable{\n\t\tTable: tview.NewTable(),\n\t}\n\n\twidget.SetFixed(1, 0)\n\twidget.SetBorders(false)\n\twidget.SetSelectable(true, false)\n\twidget.SetBorderPadding(0, 0, 1, 0)\n\twidget.SetSelectedStyle(tcell.StyleDefault.Attributes(tcell.AttrReverse))\n\n\twidget.clear()\n\n\treturn widget\n}\n\n// width constants for ProcessTable columns.\nconst (\n\tpidWidth     = 7\n\tstateWidth   = 1\n\tcpuWidth     = 6\n\tmemWidth     = 6\n\tvirtWidth    = 8\n\tresWidth     = 8\n\ttimeWidth    = 10\n\tthreadsWidth = 4\n)\n\nfunc (widget *ProcessTable) clear() {\n\twidget.Clear()\n\n\twidget.SetCell(0, 0, &tview.TableCell{\n\t\tText:          \"[::b]PID\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      pidWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 1, &tview.TableCell{\n\t\tText:          \"[::b]S\",\n\t\tAlign:         tview.AlignCenter,\n\t\tMaxWidth:      stateWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 2, &tview.TableCell{\n\t\tText:          \"[::b]CPU%\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      cpuWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 3, &tview.TableCell{\n\t\tText:          \"[::b]MEM%\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      memWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 4, &tview.TableCell{\n\t\tText:          \"[::b]VIRT\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      virtWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 5, &tview.TableCell{\n\t\tText:          \"[::b]RES\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      resWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 6, &tview.TableCell{\n\t\tText:          \"[::b]TIME+\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      timeWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 7, &tview.TableCell{\n\t\tText:          \"[::b]THR\",\n\t\tAlign:         tview.AlignRight,\n\t\tMaxWidth:      threadsWidth,\n\t\tNotSelectable: true,\n\t})\n\twidget.SetCell(0, 8, &tview.TableCell{\n\t\tText:          \"[::b]COMMAND\",\n\t\tAlign:         tview.AlignLeft,\n\t\tNotSelectable: true,\n\t\tExpansion:     1,\n\t})\n\n\twidget.SetCell(1, 0, &tview.TableCell{\n\t\tText:          noData,\n\t\tAlign:         tview.AlignCenter,\n\t\tNotSelectable: true,\n\t})\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\n//\n//nolint:gocyclo\nfunc (widget *ProcessTable) OnAPIDataChange(node string, data *apidata.Data) {\n\twidget.clear()\n\n\tnodeData := data.Nodes[node]\n\n\tif nodeData == nil {\n\t\twidget.Select(1, 0)\n\n\t\treturn\n\t}\n\n\ttotalMem := nodeData.Memory.GetMeminfo().GetMemtotal() * 1024\n\tif totalMem == 0 {\n\t\ttotalMem = 1\n\t}\n\n\ttotalWeightedCPU := nodeData.CPUUsageByName(\"total_weighted\")\n\tif totalWeightedCPU == 0 {\n\t\ttotalWeightedCPU = 1\n\t}\n\n\t// All downstream logic relies on nodeData.Processes to be not nil\n\t// Putting a check here to reduce cyclomatic complexity\n\tif nodeData.Processes == nil {\n\t\treturn\n\t}\n\n\tif nodeData.ProcsDiff != nil {\n\t\tsort.Slice(nodeData.Processes.Processes, func(i, j int) bool {\n\t\t\tproc1 := nodeData.Processes.Processes[i]\n\t\t\tproc2 := nodeData.Processes.Processes[j]\n\n\t\t\treturn nodeData.ProcsDiff[proc1.Pid].CpuTime > nodeData.ProcsDiff[proc2.Pid].CpuTime\n\t\t})\n\t}\n\n\tfor idx, proc := range nodeData.Processes.Processes {\n\t\tvar args string\n\n\t\tswitch {\n\t\tcase proc.Executable == \"\":\n\t\t\targs = proc.Command\n\t\tcase proc.Args != \"\" && strings.Fields(proc.Args)[0] == filepath.Base(strings.Fields(proc.Executable)[0]):\n\t\t\targs = strings.Replace(proc.Args, strings.Fields(proc.Args)[0], proc.Executable, 1)\n\t\tdefault:\n\t\t\targs = proc.Args\n\t\t}\n\n\t\t// filter out non-printable characters\n\t\targs = strings.Map(func(r rune) rune {\n\t\t\tif r < 32 || r > 126 {\n\t\t\t\treturn ' '\n\t\t\t}\n\n\t\t\treturn r\n\t\t}, args)\n\n\t\twidget.SetCell(idx+1, 0, &tview.TableCell{\n\t\t\tText:     strconv.FormatInt(int64(proc.GetPid()), 10),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: pidWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 1, &tview.TableCell{\n\t\t\tText:     proc.State,\n\t\t\tAlign:    tview.AlignCenter,\n\t\t\tMaxWidth: stateWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 2, &tview.TableCell{\n\t\t\tText:     fmt.Sprintf(\"%.1f\", nodeData.ProcsDiff[proc.Pid].GetCpuTime()/totalWeightedCPU*100.0),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: cpuWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 3, &tview.TableCell{\n\t\t\tText:     fmt.Sprintf(\"%.1f\", float64(proc.ResidentMemory)/float64(totalMem)*100.0),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: memWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 4, &tview.TableCell{\n\t\t\tText:     humanize.Bytes(proc.VirtualMemory),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: virtWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 5, &tview.TableCell{\n\t\t\tText:     humanize.Bytes(proc.ResidentMemory),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: resWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 6, &tview.TableCell{\n\t\t\tText:     (time.Duration(proc.CpuTime) * time.Second).String(),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: timeWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 7, &tview.TableCell{\n\t\t\tText:     strconv.FormatInt(int64(proc.Threads), 10),\n\t\t\tAlign:    tview.AlignRight,\n\t\t\tMaxWidth: threadsWidth,\n\t\t})\n\n\t\twidget.SetCell(idx+1, 8, &tview.TableCell{\n\t\t\tText:  args,\n\t\t\tAlign: tview.AlignLeft,\n\t\t})\n\t}\n\n\tselectedRow, _ := widget.GetSelection()\n\tif selectedRow > len(nodeData.Processes.Processes)+1 || widget.lastNode != node {\n\t\twidget.Select(1, 0)\n\t}\n\n\twidget.lastNode = node\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/tables_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/components\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\nfunc TestUpdate(t *testing.T) {\n\ttestProcessTable := components.NewProcessTable()\n\n\ttestData := &apidata.Data{\n\t\tNodes: map[string]*apidata.Node{\n\t\t\t\"node1\": {\n\t\t\t\tProcesses: &machine.Process{\n\t\t\t\t\tProcesses: []*machine.ProcessInfo{},\n\t\t\t\t},\n\t\t\t\tProcsDiff: map[int32]*machine.ProcessInfo{\n\t\t\t\t\t1: {},\n\t\t\t\t},\n\t\t\t\tSeries: map[string][]float64{},\n\t\t\t},\n\t\t\t\"node2\": {\n\t\t\t\tProcsDiff: map[int32]*machine.ProcessInfo{\n\t\t\t\t\t1: {},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ttestProcessTable.OnAPIDataChange(\"node1\", testData)\n\t// Node2 does not have processes, without the check it panics\n\ttestProcessTable.OnAPIDataChange(\"node2\", testData)\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/components/talosinfo.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage components\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\ntype talosInfoData struct {\n\tuuid            string\n\tclusterName     string\n\tsiderolink      string\n\tstage           string\n\tready           string\n\tnumMachinesText string\n\tsecureBootState string\n\n\tmachineIDSet map[string]struct{}\n}\n\n// TalosInfo represents the Talos info widget.\ntype TalosInfo struct {\n\ttview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*talosInfoData\n}\n\n// NewTalosInfo initializes TalosInfo.\nfunc NewTalosInfo() *TalosInfo {\n\twidget := &TalosInfo{\n\t\tTextView: *tview.NewTextView(),\n\t\tnodeMap:  make(map[string]*talosInfoData),\n\t}\n\n\twidget.SetDynamicColors(true).\n\t\tSetText(noData).\n\t\tSetBorderPadding(1, 0, 1, 0)\n\n\treturn widget\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *TalosInfo) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *TalosInfo) OnResourceDataChange(data resourcedata.Data) {\n\twidget.updateNodeData(data)\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n//nolint:gocyclo\nfunc (widget *TalosInfo) updateNodeData(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch res := data.Resource.(type) {\n\tcase *hardware.SystemInformation:\n\t\tif data.Deleted {\n\t\t\tnodeData.uuid = notAvailable\n\t\t} else {\n\t\t\tnodeData.uuid = res.TypedSpec().UUID\n\t\t}\n\tcase *cluster.Info:\n\t\tclusterName := res.TypedSpec().ClusterName\n\t\tif data.Deleted || clusterName == \"\" {\n\t\t\tnodeData.clusterName = notAvailable\n\t\t} else {\n\t\t\tnodeData.clusterName = clusterName\n\t\t}\n\tcase *siderolink.Status:\n\t\tif data.Deleted {\n\t\t\tnodeData.siderolink = notAvailable\n\t\t} else {\n\t\t\tnodeData.siderolink = formatText(res.TypedSpec().Host, res.TypedSpec().Connected)\n\t\t}\n\tcase *runtime.MachineStatus:\n\t\tif data.Deleted {\n\t\t\tnodeData.stage = notAvailable\n\t\t\tnodeData.ready = notAvailable\n\t\t} else {\n\t\t\tnodeData.stage = formatStatus(res.TypedSpec().Stage.String())\n\t\t\tnodeData.ready = formatStatus(res.TypedSpec().Status.Ready)\n\t\t}\n\tcase *runtime.SecurityState:\n\t\tif data.Deleted {\n\t\t\tnodeData.secureBootState = notAvailable\n\t\t} else {\n\t\t\tnodeData.secureBootState = formatStatus(res.TypedSpec().SecureBoot)\n\t\t}\n\tcase *cluster.Member:\n\t\tif data.Deleted {\n\t\t\tdelete(nodeData.machineIDSet, res.Metadata().ID())\n\t\t} else {\n\t\t\tnodeData.machineIDSet[res.Metadata().ID()] = struct{}{}\n\t\t}\n\n\t\tsuffix := \"\"\n\t\tif len(nodeData.machineIDSet) != 1 {\n\t\t\tsuffix = \"s\"\n\t\t}\n\n\t\tnodeData.numMachinesText = fmt.Sprintf(\"(%d machine%s)\", len(nodeData.machineIDSet), suffix)\n\t}\n}\n\nfunc (widget *TalosInfo) getOrCreateNodeData(node string) *talosInfoData {\n\tnodeData, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tnodeData = &talosInfoData{\n\t\t\tuuid:            notAvailable,\n\t\t\tclusterName:     notAvailable,\n\t\t\tsiderolink:      notAvailable,\n\t\t\tstage:           notAvailable,\n\t\t\tready:           notAvailable,\n\t\t\tnumMachinesText: notAvailable,\n\t\t\tsecureBootState: notAvailable,\n\t\t\tmachineIDSet:    make(map[string]struct{}),\n\t\t}\n\n\t\twidget.nodeMap[node] = nodeData\n\t}\n\n\treturn nodeData\n}\n\nfunc (widget *TalosInfo) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tfields := fieldGroup{\n\t\tfields: []field{\n\t\t\t{\n\t\t\t\tName:  \"UUID\",\n\t\t\t\tValue: data.uuid,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"CLUSTER\",\n\t\t\t\tValue: data.clusterName + \" \" + data.numMachinesText,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"SIDEROLINK\",\n\t\t\t\tValue: data.siderolink,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"STAGE\",\n\t\t\t\tValue: data.stage,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"READY\",\n\t\t\t\tValue: data.ready,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"SECUREBOOT\",\n\t\t\t\tValue: data.secureBootState,\n\t\t\t},\n\t\t},\n\t}\n\n\twidget.SetText(fields.String())\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/configurl.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nconst unset = \"[gray](unset)[-]\"\n\ntype configURLData struct {\n\texistingCode string\n}\n\n// ConfigURLGrid represents the config URL grid.\ntype ConfigURLGrid struct {\n\ttview.Grid\n\n\tdashboard *Dashboard\n\n\tform *tview.Form\n\n\ttemplate     *tview.TextView\n\texistingCode *tview.TextView\n\tnewCodeField *tview.InputField\n\tinfoView     *tview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*configURLData\n}\n\n// NewConfigURLGrid returns a new config URL grid.\nfunc NewConfigURLGrid(ctx context.Context, dashboard *Dashboard) *ConfigURLGrid {\n\tgrid := &ConfigURLGrid{\n\t\tGrid:         *tview.NewGrid(),\n\t\tdashboard:    dashboard,\n\t\tform:         tview.NewForm(),\n\t\ttemplate:     tview.NewTextView().SetDynamicColors(true).SetLabel(\"Template\").SetScrollable(false),\n\t\texistingCode: tview.NewTextView().SetDynamicColors(true).SetLabel(\"Existing Code\").SetText(unset).SetSize(1, 0).SetScrollable(false),\n\t\tnewCodeField: tview.NewInputField().SetLabel(\"New Code\"),\n\t\tinfoView:     tview.NewTextView().SetDynamicColors(true).SetSize(2, 0).SetScrollable(false),\n\n\t\tnodeMap: make(map[string]*configURLData),\n\t}\n\n\tgrid.template.SetText(grid.readTemplateFromKernelArgs())\n\n\tgrid.SetRows(-1, 18, -1).SetColumns(-1, 72, -1)\n\n\tgrid.form.SetBorder(true)\n\n\tgrid.form.AddFormItem(grid.template)\n\tgrid.form.AddFormItem(grid.existingCode)\n\tgrid.form.AddFormItem(grid.newCodeField)\n\tgrid.form.AddButton(\"Save\", func() {\n\t\tctx = nodeContext(ctx, grid.selectedNode) //nolint:fatcontext\n\n\t\tvalue := grid.newCodeField.GetText()\n\n\t\tif value == \"\" {\n\t\t\tgrid.infoView.SetText(\"[red]Error: No code entered[-]\")\n\n\t\t\treturn\n\t\t}\n\n\t\terr := dashboard.cli.MetaWrite(ctx, meta.DownloadURLCode, []byte(value))\n\t\tif err != nil {\n\t\t\tgrid.infoView.SetText(fmt.Sprintf(\"[red]Error: %v[-]\", err))\n\n\t\t\treturn\n\t\t}\n\n\t\tgrid.clearForm()\n\t\tgrid.dashboard.selectScreen(ScreenSummary)\n\t})\n\tgrid.form.AddButton(\"Delete\", func() {\n\t\tctx = nodeContext(ctx, grid.selectedNode) //nolint:fatcontext\n\n\t\terr := dashboard.cli.MetaDelete(ctx, meta.DownloadURLCode)\n\t\tif err != nil {\n\t\t\tif status.Code(err) == codes.NotFound {\n\t\t\t\tgrid.clearForm()\n\t\t\t\tgrid.infoView.SetText(\"[green]Already deleted[-]\")\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tgrid.infoView.SetText(fmt.Sprintf(\"[red]Error: %v[-]\", err))\n\n\t\t\treturn\n\t\t}\n\n\t\tgrid.clearForm()\n\t\tgrid.infoView.SetText(\"[green]Deleted successfully[-]\")\n\t})\n\n\tgrid.form.AddFormItem(grid.infoView)\n\n\tgrid.AddItem(tview.NewBox(), 0, 0, 1, 3, 0, 0, false)\n\tgrid.AddItem(tview.NewBox(), 1, 0, 1, 1, 0, 0, false)\n\tgrid.AddItem(grid.form, 1, 1, 1, 1, 0, 0, false)\n\tgrid.AddItem(tview.NewBox(), 1, 2, 1, 1, 0, 0, false)\n\tgrid.AddItem(tview.NewBox(), 2, 0, 1, 3, 0, 0, false)\n\n\treturn grid\n}\n\nfunc (widget *ConfigURLGrid) readTemplateFromKernelArgs() (val string) {\n\tdefer func() { // catch potential panic from procfs.ProcCmdline()\n\t\tif r := recover(); r != nil {\n\t\t\tval = \"error reading kernel args\"\n\t\t}\n\t}()\n\n\toption := procfs.ProcCmdline().Get(constants.KernelParamConfig).First()\n\tif option == nil {\n\t\treturn unset\n\t}\n\n\tcodeVar := fmt.Sprintf(\"${%s}\", constants.CodeKey)\n\n\treturn strings.ReplaceAll(tview.Escape(*option), codeVar, fmt.Sprintf(\"[green]%s[-]\", codeVar))\n}\n\n// OnScreenSelect implements the screenSelectListener interface.\nfunc (widget *ConfigURLGrid) onScreenSelect(active bool) {\n\tif active {\n\t\twidget.dashboard.app.SetFocus(widget.form)\n\t} else {\n\t\twidget.clearForm()\n\t}\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *ConfigURLGrid) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.clearForm()\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *ConfigURLGrid) OnResourceDataChange(data resourcedata.Data) {\n\twidget.updateNodeData(data)\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\nfunc (widget *ConfigURLGrid) updateNodeData(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\t//nolint:gocritic\n\tswitch res := data.Resource.(type) {\n\tcase *runtimeres.MetaKey:\n\t\tif res.Metadata().ID() == runtimeres.MetaKeyTagToID(meta.DownloadURLCode) {\n\t\t\tif data.Deleted {\n\t\t\t\tnodeData.existingCode = unset\n\t\t\t} else {\n\t\t\t\tval := res.TypedSpec().Value\n\t\t\t\tif val == \"\" {\n\t\t\t\t\tval = \"(empty)\"\n\t\t\t\t}\n\n\t\t\t\tnodeData.existingCode = fmt.Sprintf(\"[blue]%s[-]\", val)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (widget *ConfigURLGrid) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\twidget.existingCode.SetText(data.existingCode)\n}\n\nfunc (widget *ConfigURLGrid) getOrCreateNodeData(node string) *configURLData {\n\tnodeData, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tnodeData = &configURLData{\n\t\t\texistingCode: unset,\n\t\t}\n\n\t\twidget.nodeMap[node] = nodeData\n\t}\n\n\treturn nodeData\n}\n\nfunc (widget *ConfigURLGrid) clearForm() {\n\twidget.form.SetFocus(0)\n\twidget.infoView.SetText(\"\")\n\twidget.newCodeField.SetText(\"\")\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/context.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc nodeContext(ctx context.Context, selectedNode string) context.Context {\n\tmd, mdOk := metadata.FromOutgoingContext(ctx)\n\tif mdOk {\n\t\tmd.Delete(\"nodes\")\n\n\t\tctx = metadata.NewOutgoingContext(ctx, md)\n\t}\n\n\tif selectedNode != \"\" {\n\t\tctx = client.WithNode(ctx, selectedNode)\n\t}\n\n\treturn ctx\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/dashboard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package dashboard implements a text-based UI dashboard.\npackage dashboard\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t_ \"github.com/gdamore/tcell/v2/terminfo/l/linux\" // linux terminal is used when running on the machine, but not included with tcell_minimal\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-api-signature/pkg/message\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/components\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/logdata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resolver\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc init() {\n\t// set background to be left as the default color of the terminal\n\ttview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault\n}\n\n// Screen is a dashboard screen.\ntype Screen string\n\nconst (\n\tpageMain = \"main\"\n\n\t// ScreenSummary is the summary screen.\n\tScreenSummary Screen = \"Summary\"\n\n\t// ScreenMonitor is the monitor (metrics) screen.\n\tScreenMonitor Screen = \"Monitor\"\n\n\t// ScreenNetworkConfig is the network configuration screen.\n\tScreenNetworkConfig Screen = \"Network Config\"\n\n\t// ScreenConfigURL is the config URL screen.\n\tScreenConfigURL Screen = \"Config URL\"\n)\n\n// APIDataListener is a listener which is notified when API-sourced data is updated.\ntype APIDataListener interface {\n\tOnAPIDataChange(node string, data *apidata.Data)\n}\n\n// ResourceDataListener is a listener which is notified when a resource is updated.\ntype ResourceDataListener interface {\n\tOnResourceDataChange(data resourcedata.Data)\n}\n\n// LogDataListener is a listener which is notified when a log line is received.\ntype LogDataListener interface {\n\tOnLogDataChange(node, logLine, logError string)\n}\n\n// NodeSelectListener is a listener which is notified when a node is selected.\ntype NodeSelectListener interface {\n\tOnNodeSelect(node string)\n}\n\n// TickerListener is a listener which is notified on every tick.\ntype TickerListener interface {\n\tOnTick()\n}\n\ntype screenConfig struct {\n\tscreenKey           string\n\tscreen              Screen\n\tkeyCode             tcell.Key\n\tprimitive           screenSelectListener\n\tallowNodeNavigation bool\n}\n\n// screenSelectListener is a listener which is notified when a screen is selected.\ntype screenSelectListener interface {\n\ttview.Primitive\n\n\tonScreenSelect(active bool)\n}\n\n// Dashboard implements the summary dashboard.\ntype Dashboard struct {\n\tcli      *client.Client\n\tinterval time.Duration\n\n\tapiDataSource      *apidata.Source\n\tresourceDataSource *resourcedata.Source\n\tlogDataSource      *logdata.Source\n\n\tapiDataListeners      []APIDataListener\n\tresourceDataListeners []ResourceDataListener\n\tlogDataListeners      []LogDataListener\n\tnodeSelectListeners   []NodeSelectListener\n\ttickerListeners       []TickerListener\n\n\tapp *tview.Application\n\n\tmainGrid *tview.Grid\n\n\tpages *tview.Pages\n\n\tselectedScreenConfig *screenConfig\n\tscreenConfigs        []screenConfig\n\tfooter               *components.Footer\n\n\tdata *apidata.Data\n\n\tselectedNodeIndex int\n\tselectedNode      string\n\tpaused            bool\n\tnodeSet           map[string]struct{}\n\tipsToNodeAliases  map[string]string\n\tnodes             []string\n}\n\n// buildDashboard initializes the summary dashboard.\n//\n//nolint:gocyclo,cyclop\nfunc buildDashboard(ctx context.Context, cli *client.Client, opts ...Option) (*Dashboard, error) {\n\tdefOptions := defaultOptions()\n\n\tfor _, opt := range opts {\n\t\topt(defOptions)\n\t}\n\n\t// map node IPs to their aliases (names/IPs - as specified \"nodes\" in context).\n\t// this will also trigger the interactive API authentication if needed - e.g., when the API is used through Omni.\n\tipsToNodeAliases, err := collectNodeIPsToNodeAliases(ctx, cli)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodes := getSortedNodeAliases(ipsToNodeAliases)\n\n\tdashboard := &Dashboard{\n\t\tcli:              cli,\n\t\tinterval:         defOptions.interval,\n\t\tapp:              tview.NewApplication(),\n\t\tnodeSet:          make(map[string]struct{}),\n\t\tnodes:            nodes,\n\t\tipsToNodeAliases: ipsToNodeAliases,\n\t}\n\n\tdashboard.mainGrid = tview.NewGrid().\n\t\tSetRows(1, 0, 1).\n\t\tSetColumns(0)\n\n\tdashboard.pages = tview.NewPages().AddPage(pageMain, dashboard.mainGrid, true, true)\n\n\tdashboard.app.EnableMouse(true)\n\tdashboard.app.SetRoot(dashboard.pages, true).SetFocus(dashboard.pages)\n\n\theader := components.NewHeader()\n\tdashboard.mainGrid.AddItem(header, 0, 0, 1, 1, 0, 0, false)\n\n\tif err = dashboard.initScreenConfigs(ctx, defOptions.screens); err != nil {\n\t\treturn nil, err\n\t}\n\n\tscreenKeyToName := xslices.ToMap(dashboard.screenConfigs, func(t screenConfig) (string, string) {\n\t\treturn t.screenKey, string(t.screen)\n\t})\n\n\tscreenConfigByKeyCode := xslices.ToMap(dashboard.screenConfigs, func(config screenConfig) (tcell.Key, screenConfig) {\n\t\treturn config.keyCode, config\n\t})\n\n\tdashboard.footer = components.NewFooter(screenKeyToName, nodes)\n\n\tdashboard.footer.NodeClick = func(node string) {\n\t\tallowNodeNavigation := dashboard.selectedScreenConfig != nil && dashboard.selectedScreenConfig.allowNodeNavigation\n\t\tif !allowNodeNavigation {\n\t\t\treturn\n\t\t}\n\n\t\tfor i, n := range dashboard.nodes {\n\t\t\tif n == node {\n\t\t\t\tdashboard.selectNodeByIndex(i)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tdashboard.footer.ScreenClick = func(screenName string) {\n\t\tdashboard.selectScreen(Screen(screenName))\n\t}\n\n\tdashboard.app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {\n\t\tconfig, screenOk := screenConfigByKeyCode[event.Key()]\n\n\t\tallowNodeNavigation := dashboard.selectedScreenConfig != nil && dashboard.selectedScreenConfig.allowNodeNavigation\n\n\t\tswitch {\n\t\tcase screenOk:\n\t\t\tdashboard.selectScreen(config.screen)\n\n\t\t\treturn nil\n\t\tcase allowNodeNavigation && (event.Key() == tcell.KeyLeft || event.Rune() == 'h'):\n\t\t\tdashboard.selectNodeByIndex(dashboard.selectedNodeIndex - 1)\n\n\t\t\treturn nil\n\t\tcase allowNodeNavigation && (event.Key() == tcell.KeyRight || event.Rune() == 'l'):\n\t\t\tdashboard.selectNodeByIndex(dashboard.selectedNodeIndex + 1)\n\n\t\t\treturn nil\n\t\tcase defOptions.allowExitKeys && (event.Key() == tcell.KeyCtrlC || event.Rune() == 'q'):\n\t\t\tdashboard.app.Stop()\n\n\t\t\treturn nil\n\t\tcase event.Key() == tcell.KeyCtrlZ:\n\t\t\tdashboard.paused = !dashboard.paused\n\t\t\tdashboard.footer.SetPaused(dashboard.paused)\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn event\n\t})\n\n\tdashboard.mainGrid.AddItem(dashboard.footer, 2, 0, 1, 1, 0, 0, false)\n\n\tdashboard.apiDataListeners = []APIDataListener{\n\t\theader,\n\t}\n\n\tdashboard.resourceDataListeners = []ResourceDataListener{\n\t\theader,\n\t}\n\n\tdashboard.logDataListeners = []LogDataListener{}\n\n\tdashboard.nodeSelectListeners = []NodeSelectListener{\n\t\theader,\n\t\tdashboard.footer,\n\t}\n\n\tdashboard.tickerListeners = []TickerListener{\n\t\theader,\n\t}\n\n\tfor _, config := range dashboard.screenConfigs {\n\t\tscreenPrimitive := config.primitive\n\n\t\tapiDataListener, ok := screenPrimitive.(APIDataListener)\n\t\tif ok {\n\t\t\tdashboard.apiDataListeners = append(dashboard.apiDataListeners, apiDataListener)\n\t\t}\n\n\t\tresourceDataListener, ok := screenPrimitive.(ResourceDataListener)\n\t\tif ok {\n\t\t\tdashboard.resourceDataListeners = append(dashboard.resourceDataListeners, resourceDataListener)\n\t\t}\n\n\t\tlogDataListener, ok := screenPrimitive.(LogDataListener)\n\t\tif ok {\n\t\t\tdashboard.logDataListeners = append(dashboard.logDataListeners, logDataListener)\n\t\t}\n\n\t\tnodeSelectListener, ok := screenPrimitive.(NodeSelectListener)\n\t\tif ok {\n\t\t\tdashboard.nodeSelectListeners = append(dashboard.nodeSelectListeners, nodeSelectListener)\n\t\t}\n\t}\n\n\tnodeResolver := resolver.New(ipsToNodeAliases)\n\n\tdashboard.apiDataSource = &apidata.Source{\n\t\tClient:   cli,\n\t\tInterval: defOptions.interval,\n\t\tResolver: nodeResolver,\n\t}\n\n\tdashboard.resourceDataSource = &resourcedata.Source{\n\t\tCOSI: cli.COSI,\n\t}\n\n\tdashboard.logDataSource = logdata.NewSource(cli, nodeResolver)\n\n\treturn dashboard, nil\n}\n\nfunc (d *Dashboard) initScreenConfigs(ctx context.Context, screens []Screen) error {\n\tprimitiveForScreen := func(screen Screen) screenSelectListener {\n\t\tswitch screen {\n\t\tcase ScreenSummary:\n\t\t\treturn NewSummaryGrid(d.app)\n\t\tcase ScreenMonitor:\n\t\t\treturn NewMonitorGrid(d.app)\n\t\tcase ScreenNetworkConfig:\n\t\t\treturn NewNetworkConfigGrid(ctx, d)\n\t\tcase ScreenConfigURL:\n\t\t\treturn NewConfigURLGrid(ctx, d)\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t}\n\n\td.screenConfigs = make([]screenConfig, 0, len(screens))\n\n\tfor i, screen := range screens {\n\t\tprimitive := primitiveForScreen(screen)\n\t\tif primitive == nil {\n\t\t\treturn fmt.Errorf(\"unknown screen %s\", screen)\n\t\t}\n\n\t\tconfig := screenConfig{\n\t\t\tscreenKey:           fmt.Sprintf(\"F%d\", i+1),\n\t\t\tscreen:              screen,\n\t\t\tkeyCode:             tcell.KeyF1 + tcell.Key(i),\n\t\t\tprimitive:           primitive,\n\t\t\tallowNodeNavigation: true,\n\t\t}\n\n\t\tif screen == ScreenNetworkConfig || screen == ScreenConfigURL {\n\t\t\tconfig.allowNodeNavigation = false\n\t\t}\n\n\t\td.screenConfigs = append(d.screenConfigs, config)\n\t}\n\n\treturn nil\n}\n\n// Run starts the dashboard.\nfunc Run(ctx context.Context, cli *client.Client, opts ...Option) (runErr error) {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tdashboard, err := buildDashboard(ctx, cli, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdashboard.selectNodeByIndex(0)\n\n\t// handle panic & stop dashboard gracefully on exit\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\trunErr = fmt.Errorf(\"dashboard panic: %v\", r)\n\t\t}\n\n\t\tdashboard.app.Stop()\n\t}()\n\n\tdashboard.selectScreen(ScreenSummary)\n\n\teg, ctx := errgroup.WithContext(ctx)\n\n\tstopFunc := dashboard.startDataHandler(ctx)\n\tdefer stopFunc() //nolint:errcheck\n\n\teg.Go(func() error {\n\t\tdefer cancel()\n\n\t\treturn dashboard.app.Run()\n\t})\n\n\t// stop dashboard when the context is canceled\n\teg.Go(func() error {\n\t\t<-ctx.Done()\n\n\t\tdashboard.app.Stop()\n\n\t\treturn nil\n\t})\n\n\treturn eg.Wait()\n}\n\n// startDataHandler starts the data and log update handler and returns a function to stop it.\n//\n//nolint:gocyclo\nfunc (d *Dashboard) startDataHandler(ctx context.Context) func() error {\n\tvar eg errgroup.Group\n\n\tctx, cancel := context.WithCancel(ctx)\n\n\tstopFunc := func() error {\n\t\tcancel()\n\n\t\terr := eg.Wait()\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\teg.Go(func() error {\n\t\t// start API data source\n\t\tdataCh := d.apiDataSource.Run(ctx)\n\t\tdefer d.apiDataSource.Stop()\n\n\t\t// start resources data source\n\t\td.resourceDataSource.Run(ctx)\n\t\tdefer d.resourceDataSource.Stop() //nolint:errcheck\n\n\t\t// start logs data source\n\t\td.logDataSource.Start(ctx)\n\t\tdefer d.logDataSource.Stop() //nolint:errcheck\n\n\t\tlastLogTime := time.Now()\n\n\t\tticker := time.NewTicker(500 * time.Millisecond)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase nodeLog := <-d.logDataSource.LogCh:\n\t\t\t\tif time.Since(lastLogTime) < 50*time.Millisecond {\n\t\t\t\t\td.app.QueueUpdate(func() {\n\t\t\t\t\t\td.processLog(nodeLog.Node, nodeLog.Log, nodeLog.Error)\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\td.app.QueueUpdateDraw(func() {\n\t\t\t\t\t\td.processLog(nodeLog.Node, nodeLog.Log, nodeLog.Error)\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tlastLogTime = time.Now()\n\t\t\tcase d.data = <-dataCh:\n\t\t\t\td.app.QueueUpdateDraw(func() {\n\t\t\t\t\tif !d.paused {\n\t\t\t\t\t\td.processAPIData()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\tcase nodeResource := <-d.resourceDataSource.NodeResourceCh:\n\t\t\t\td.app.QueueUpdateDraw(func() {\n\t\t\t\t\td.processNodeResource(nodeResource)\n\t\t\t\t})\n\t\t\tcase <-ticker.C:\n\t\t\t\td.app.QueueUpdateDraw(func() {\n\t\t\t\t\tif !d.paused {\n\t\t\t\t\t\td.processTick()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t})\n\n\treturn stopFunc\n}\n\nfunc (d *Dashboard) selectNodeByIndex(index int) {\n\tif len(d.nodes) == 0 {\n\t\treturn\n\t}\n\n\tif index < 0 {\n\t\tindex = 0\n\t} else if index >= len(d.nodes) {\n\t\tindex = len(d.nodes) - 1\n\t}\n\n\td.selectedNode = d.nodes[index]\n\td.selectedNodeIndex = index\n\n\td.processAPIData()\n\n\tfor _, listener := range d.nodeSelectListeners {\n\t\tlistener.OnNodeSelect(d.selectedNode)\n\t}\n}\n\n// processAPIData re-renders the components with new API-sourced data.\nfunc (d *Dashboard) processAPIData() {\n\tif d.data == nil {\n\t\treturn\n\t}\n\n\tfor _, component := range d.apiDataListeners {\n\t\tcomponent.OnAPIDataChange(d.selectedNode, d.data)\n\t}\n}\n\n// processNodeResource re-renders the components with new resource data.\nfunc (d *Dashboard) processNodeResource(nodeResource resourcedata.Data) {\n\tfor _, component := range d.resourceDataListeners {\n\t\tcomponent.OnResourceDataChange(nodeResource)\n\t}\n}\n\n// processLog re-renders the log components with new log data.\nfunc (d *Dashboard) processLog(node, logLine, logError string) {\n\tfor _, component := range d.logDataListeners {\n\t\tcomponent.OnLogDataChange(node, logLine, logError)\n\t}\n}\n\n// processTick re-renders the components with ticker.\nfunc (d *Dashboard) processTick() {\n\tfor _, component := range d.tickerListeners {\n\t\tcomponent.OnTick()\n\t}\n}\n\nfunc (d *Dashboard) selectScreen(screen Screen) {\n\tfor _, info := range d.screenConfigs {\n\t\tif info.screen == screen {\n\t\t\td.selectedScreenConfig = &info //nolint:exportloopref\n\n\t\t\td.mainGrid.AddItem(info.primitive, 1, 0, 1, 1, 0, 0, false)\n\n\t\t\tinfo.primitive.onScreenSelect(true)\n\n\t\t\tcontinue\n\t\t}\n\n\t\td.mainGrid.RemoveItem(info.primitive)\n\t\tinfo.primitive.onScreenSelect(false)\n\t}\n\n\td.footer.SelectScreen(string(screen))\n}\n\n// collectNodeIPsToNodeAliases probes all nodes in the context for their IP addresses by calling their .Version endpoint and maps them to the node aliases in the context.\n//\n// Sample output:\n//\n// 172.20.0.6 -> node-1\n//\n// 10.42.0.1 -> node-1\n//\n// 172.20.0.7 -> node-2\n//\n// 10.42.0.2 -> node-2.\nfunc collectNodeIPsToNodeAliases(ctx context.Context, c *client.Client) (map[string]string, error) {\n\tipsToNodeAliases := make(map[string]string)\n\n\tnodes := nodeAliasesInContext(ctx)\n\tfor _, node := range nodes {\n\t\tctx = client.WithNodes(ctx, node) //nolint:fatcontext // do not replace this with \"WithNode\" - it would not return the IP in the response metadata\n\n\t\tresp, err := c.Version(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get node %q version: %w\", node, err)\n\t\t}\n\n\t\tif len(resp.GetMessages()) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"node %q returned no messages in version response\", node)\n\t\t}\n\n\t\tnodeIP := resp.GetMessages()[0].GetMetadata().GetHostname()\n\t\tif nodeIP == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"node %q returned no IP in version response\", node)\n\t\t}\n\n\t\tipsToNodeAliases[nodeIP] = node\n\t}\n\n\treturn ipsToNodeAliases, nil\n}\n\n// nodeAliasesInContext extracts the node aliases (IP, name etc.) from the given context which are stored in the \"node\" or \"nodes\" GRPC metadata.\nfunc nodeAliasesInContext(ctx context.Context) []string {\n\tmd, mdOk := metadata.FromOutgoingContext(ctx)\n\tif !mdOk {\n\t\treturn nil\n\t}\n\n\tnodeVal := md.Get(\"node\")\n\tif len(nodeVal) > 0 {\n\t\treturn []string{nodeVal[0]}\n\t}\n\n\tnodesVal := md.Get(message.NodesHeaderKey)\n\n\treturn xslices.FlatMap(nodesVal, func(node string) []string {\n\t\treturn strings.Split(node, \",\")\n\t})\n}\n\n// getSortedNodeAliases returns the unique node aliases sorted by their IP address.\nfunc getSortedNodeAliases(ipToNodeAliases map[string]string) []string {\n\tif len(ipToNodeAliases) == 0 { // assume that it is the local node (running on TTY)\n\t\treturn []string{\"\"}\n\t}\n\n\tnodeAliases := maps.Keys(xslices.ToSet(maps.Values(ipToNodeAliases))) // eliminate duplicates\n\n\t// if the aliases are IP addresses, compare them as IPs\n\t// otherwise, compare them as strings\n\t// all IPs come before non-IPs\n\tslices.SortFunc(nodeAliases, func(a, b string) int {\n\t\taddrA, aErr := netip.ParseAddr(a)\n\n\t\taddrB, bErr := netip.ParseAddr(b)\n\t\tif aErr != nil && bErr != nil {\n\t\t\treturn strings.Compare(a, b)\n\t\t}\n\n\t\tif aErr != nil {\n\t\t\treturn 1\n\t\t}\n\n\t\tif bErr != nil {\n\t\t\treturn -1\n\t\t}\n\n\t\treturn addrA.Compare(addrB)\n\t})\n\n\treturn nodeAliases\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/formdata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nconst (\n\tinterfaceNone = \"(none)\"\n\n\t// ModeDHCP is the DHCP mode for the link.\n\tModeDHCP = \"DHCP\"\n\n\t// ModeStatic is the static IP mode for the link.\n\tModeStatic = \"Static\"\n)\n\n// NetworkConfigFormData is the form data for the network config.\ntype NetworkConfigFormData struct {\n\tBase        runtime.PlatformNetworkConfig\n\tHostname    string\n\tDNSServers  string\n\tTimeServers string\n\tIface       string\n\tMode        string\n\tAddresses   string\n\tGateway     string\n}\n\n// ToPlatformNetworkConfig converts the form data to a PlatformNetworkConfig.\n//\n//nolint:gocyclo\nfunc (formData *NetworkConfigFormData) ToPlatformNetworkConfig() (*runtime.PlatformNetworkConfig, error) {\n\tvar errs error\n\n\tconfig := &formData.Base\n\n\t// zero-out the fields managed by the form\n\tconfig.Hostnames = nil\n\tconfig.Resolvers = nil\n\tconfig.TimeServers = nil\n\tconfig.Links = nil\n\tconfig.Operators = nil\n\tconfig.Addresses = nil\n\tconfig.Routes = nil\n\n\tif formData.Hostname != \"\" {\n\t\tconfig.Hostnames = []network.HostnameSpecSpec{\n\t\t\t{\n\t\t\t\tHostname:    formData.Hostname,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t}\n\t}\n\n\tdnsServers, err := formData.parseAddresses(formData.DNSServers)\n\tif err != nil {\n\t\terrs = multierror.Append(errs, fmt.Errorf(\"failed to parse DNS servers: %w\", err))\n\t}\n\n\tif len(dnsServers) > 0 {\n\t\tconfig.Resolvers = []network.ResolverSpecSpec{\n\t\t\t{\n\t\t\t\tDNSServers:  dnsServers,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t}\n\t}\n\n\ttimeServers := formData.splitInputList(formData.TimeServers)\n\n\tif len(timeServers) > 0 {\n\t\tconfig.TimeServers = []network.TimeServerSpecSpec{\n\t\t\t{\n\t\t\t\tNTPServers:  timeServers,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t}\n\t}\n\n\tifaceSelected := formData.Iface != \"\" && formData.Iface != interfaceNone\n\tif ifaceSelected {\n\t\tconfig.Links = []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName:        formData.Iface,\n\t\t\t\tLogical:     false,\n\t\t\t\tUp:          true,\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t}\n\n\t\tswitch formData.Mode {\n\t\tcase ModeDHCP:\n\t\t\tconfig.Operators = []network.OperatorSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\t\tLinkName:  formData.Iface,\n\t\t\t\t\tRequireUp: true,\n\t\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\t\tRouteMetric: 1024,\n\t\t\t\t\t},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t}\n\t\tcase ModeStatic:\n\t\t\tconfig.Addresses, err = formData.buildAddresses(formData.Iface)\n\t\t\tif err != nil {\n\t\t\t\terrs = multierror.Append(errs, err)\n\t\t\t}\n\n\t\t\tif len(config.Addresses) == 0 {\n\t\t\t\terrs = multierror.Append(errs, errors.New(\"no addresses specified\"))\n\t\t\t}\n\n\t\t\tconfig.Routes, err = formData.buildRoutes(formData.Iface)\n\t\t\tif err != nil {\n\t\t\t\terrs = multierror.Append(errs, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif errs != nil {\n\t\treturn nil, errs\n\t}\n\n\treturn config, nil\n}\n\nfunc (formData *NetworkConfigFormData) parseAddresses(text string) ([]netip.Addr, error) {\n\tvar errs error\n\n\tsplit := formData.splitInputList(text)\n\taddresses := make([]netip.Addr, 0, len(split))\n\n\tfor _, address := range split {\n\t\taddr, err := netip.ParseAddr(address)\n\t\tif err != nil {\n\t\t\terrs = multierror.Append(errs, fmt.Errorf(\"address: %w\", err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\taddresses = append(addresses, addr)\n\t}\n\n\tif errs != nil {\n\t\treturn nil, errs\n\t}\n\n\treturn addresses, nil\n}\n\nfunc (formData *NetworkConfigFormData) buildAddresses(linkName string) ([]network.AddressSpecSpec, error) {\n\tvar errs error\n\n\taddressesSplit := formData.splitInputList(formData.Addresses)\n\taddresses := make([]network.AddressSpecSpec, 0, len(addressesSplit))\n\n\tfor _, address := range addressesSplit {\n\t\tprefix, err := netip.ParsePrefix(address)\n\t\tif err != nil {\n\t\t\terrs = multierror.Append(errs, err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tipFamily := nethelpers.FamilyInet4\n\t\tif prefix.Addr().Is6() {\n\t\t\tipFamily = nethelpers.FamilyInet6\n\t\t}\n\n\t\taddresses = append(addresses, network.AddressSpecSpec{\n\t\t\tAddress:     prefix,\n\t\t\tLinkName:    linkName,\n\t\t\tFamily:      ipFamily,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t})\n\t}\n\n\tif errs != nil {\n\t\treturn nil, errs\n\t}\n\n\treturn addresses, nil\n}\n\nfunc (formData *NetworkConfigFormData) buildRoutes(linkName string) ([]network.RouteSpecSpec, error) {\n\tgateway := strings.TrimSpace(formData.Gateway)\n\n\tgatewayAddr, err := netip.ParseAddr(gateway)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"gateway: %w\", err)\n\t}\n\n\tfamily := nethelpers.FamilyInet4\n\tif gatewayAddr.Is6() {\n\t\tfamily = nethelpers.FamilyInet6\n\t}\n\n\treturn []network.RouteSpecSpec{\n\t\t{\n\t\t\tFamily:      family,\n\t\t\tGateway:     gatewayAddr,\n\t\t\tOutLinkName: linkName,\n\t\t\tTable:       nethelpers.TableMain,\n\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t},\n\t}, nil\n}\n\nfunc (formData *NetworkConfigFormData) splitInputList(text string) []string {\n\tparts := strings.FieldsFunc(text, func(r rune) bool {\n\t\treturn r == ',' || unicode.IsSpace(r)\n\t})\n\n\tresult := make([]string, 0, len(parts))\n\n\tfor _, part := range parts {\n\t\ttrimmed := strings.TrimSpace(part)\n\n\t\tif trimmed != \"\" {\n\t\t\tresult = append(result, part)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/formdata_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestEmptyFormData(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, runtime.PlatformNetworkConfig{}, *config)\n}\n\nfunc TestBaseDataZeroOut(t *testing.T) {\n\tbase := runtime.PlatformNetworkConfig{\n\t\tAddresses: []network.AddressSpecSpec{\n\t\t\t{\n\t\t\t\tLinkName: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tLinks: []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tRoutes: []network.RouteSpecSpec{\n\t\t\t{\n\t\t\t\tOutLinkName: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tHostnames: []network.HostnameSpecSpec{\n\t\t\t{\n\t\t\t\tHostname: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tResolvers: []network.ResolverSpecSpec{\n\t\t\t{\n\t\t\t\tDNSServers: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"1.2.3.4\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tTimeServers: []network.TimeServerSpecSpec{\n\t\t\t{\n\t\t\t\tNTPServers: []string{\"foobar\"},\n\t\t\t},\n\t\t},\n\t\tOperators: []network.OperatorSpecSpec{\n\t\t\t{\n\t\t\t\tLinkName: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tExternalIPs: []netip.Addr{\n\t\t\tnetip.MustParseAddr(\"2.3.4.5\"),\n\t\t},\n\t\tMetadata: &runtimeres.PlatformMetadataSpec{\n\t\t\tPlatform: \"foobar\",\n\t\t\tSpot:     true,\n\t\t},\n\t}\n\n\tformData := dashboard.NetworkConfigFormData{\n\t\tBase: base,\n\t}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tassert.NoError(t, err)\n\n\t// assert that the fields managed by the form are zeroed out\n\tassert.Empty(t, config.Addresses)\n\tassert.Empty(t, config.Links)\n\tassert.Empty(t, config.Routes)\n\tassert.Empty(t, config.Hostnames)\n\tassert.Empty(t, config.Resolvers)\n\tassert.Empty(t, config.TimeServers)\n\tassert.Empty(t, config.Operators)\n\n\t// assert that the fields not managed by the form are untouched\n\tassert.Equal(t, base.ExternalIPs, config.ExternalIPs)\n\tassert.Equal(t, base.Metadata, config.Metadata)\n}\n\nfunc TestFilledFormNoIface(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{\n\t\tBase: runtime.PlatformNetworkConfig{\n\t\t\tMetadata: &runtimeres.PlatformMetadataSpec{\n\t\t\t\tPlatform: \"foobar\",\n\t\t\t},\n\t\t},\n\t\tHostname:    \"foobar\",\n\t\tDNSServers:  \"1.2.3.4 5.6.7.8\",\n\t\tTimeServers: \"a.example.com   ,  b.example.com\",\n\t}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tassert.NoError(t, err)\n\n\tassert.Equal(\n\t\tt,\n\t\truntime.PlatformNetworkConfig{\n\t\t\tHostnames: []network.HostnameSpecSpec{{\n\t\t\t\tHostname:    \"foobar\",\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t}},\n\t\t\tResolvers: []network.ResolverSpecSpec{{\n\t\t\t\tDNSServers: []netip.Addr{\n\t\t\t\t\tnetip.MustParseAddr(\"1.2.3.4\"),\n\t\t\t\t\tnetip.MustParseAddr(\"5.6.7.8\"),\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t}},\n\t\t\tTimeServers: []network.TimeServerSpecSpec{\n\t\t\t\t{\n\t\t\t\t\tNTPServers:  []string{\"a.example.com\", \"b.example.com\"},\n\t\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMetadata: &runtimeres.PlatformMetadataSpec{\n\t\t\t\tPlatform: \"foobar\",\n\t\t\t},\n\t\t},\n\t\t*config,\n\t)\n}\n\nfunc TestFilledFormModeDHCP(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{\n\t\tIface: \"eth0\",\n\t\tMode:  dashboard.ModeDHCP,\n\t}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, runtime.PlatformNetworkConfig{\n\t\tLinks: []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName:        formData.Iface,\n\t\t\t\tLogical:     false,\n\t\t\t\tUp:          true,\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t\tOperators: []network.OperatorSpecSpec{\n\t\t\t{\n\t\t\t\tOperator:  network.OperatorDHCP4,\n\t\t\t\tLinkName:  formData.Iface,\n\t\t\t\tRequireUp: true,\n\t\t\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\t\t\tRouteMetric: 1024,\n\t\t\t\t},\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t}, *config)\n}\n\nfunc TestFilledFormModeStaticNoAddresses(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{\n\t\tIface: \"eth0\",\n\t\tMode:  dashboard.ModeStatic,\n\t}\n\n\t_, err := formData.ToPlatformNetworkConfig()\n\tassert.ErrorContains(t, err, \"no addresses specified\")\n}\n\nfunc TestFilledFormModeStaticNoGateway(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{\n\t\tIface:     \"eth0\",\n\t\tMode:      dashboard.ModeStatic,\n\t\tAddresses: \"1.2.3.4/24\",\n\t}\n\n\t_, err := formData.ToPlatformNetworkConfig()\n\tassert.ErrorContains(t, err, \"unable to parse\")\n}\n\nfunc TestFilledFormModeStatic(t *testing.T) {\n\tformData := dashboard.NetworkConfigFormData{\n\t\tIface:     \"eth42\",\n\t\tMode:      dashboard.ModeStatic,\n\t\tAddresses: \"1.2.3.4/24 2.3.4.5/32\",\n\t\tGateway:   \"3.4.5.6\",\n\t}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, runtime.PlatformNetworkConfig{\n\t\tLinks: []network.LinkSpecSpec{\n\t\t\t{\n\t\t\t\tName:        formData.Iface,\n\t\t\t\tLogical:     false,\n\t\t\t\tUp:          true,\n\t\t\t\tType:        nethelpers.LinkEther,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t\tAddresses: []network.AddressSpecSpec{\n\t\t\t{\n\t\t\t\tAddress:     netip.MustParsePrefix(\"1.2.3.4/24\"),\n\t\t\t\tLinkName:    formData.Iface,\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t\t{\n\t\t\t\tAddress:     netip.MustParsePrefix(\"2.3.4.5/32\"),\n\t\t\t\tLinkName:    formData.Iface,\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t\tRoutes: []network.RouteSpecSpec{\n\t\t\t{\n\t\t\t\tFamily:      nethelpers.FamilyInet4,\n\t\t\t\tGateway:     netip.MustParseAddr(\"3.4.5.6\"),\n\t\t\t\tOutLinkName: \"eth42\",\n\t\t\t\tTable:       nethelpers.TableMain,\n\t\t\t\tScope:       nethelpers.ScopeGlobal,\n\t\t\t\tType:        nethelpers.TypeUnicast,\n\t\t\t\tProtocol:    nethelpers.ProtocolStatic,\n\t\t\t\tConfigLayer: network.ConfigPlatform,\n\t\t\t},\n\t\t},\n\t}, *config)\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/logdata/logdata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package logdata implements the types and the data sources for the data sourced from the Talos dmesg API.\npackage logdata\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resolver\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/util\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// Data is a log line from a node.\ntype Data struct {\n\tNode  string\n\tLog   string\n\tError string\n}\n\n// Source is a data source for Kernel (dmesg) logs.\ntype Source struct {\n\tclient *client.Client\n\n\tresolver resolver.Resolver\n\n\tlogCtxCancel context.CancelFunc\n\n\teg   errgroup.Group\n\tonce sync.Once\n\n\tLogCh chan Data\n}\n\n// NewSource initializes and returns Source data source.\nfunc NewSource(client *client.Client, resolver resolver.Resolver) *Source {\n\treturn &Source{\n\t\tclient:   client,\n\t\tresolver: resolver,\n\t\tLogCh:    make(chan Data),\n\t}\n}\n\n// Start starts the data source.\nfunc (source *Source) Start(ctx context.Context) {\n\tsource.once.Do(func() {\n\t\tsource.start(ctx)\n\t})\n}\n\n// Stop stops the data source.\nfunc (source *Source) Stop() error {\n\tsource.logCtxCancel()\n\n\treturn source.eg.Wait()\n}\n\nfunc (source *Source) start(ctx context.Context) {\n\tctx, source.logCtxCancel = context.WithCancel(ctx)\n\n\tfor _, nodeContext := range util.NodeContexts(ctx) {\n\t\tsource.eg.Go(func() error {\n\t\t\treturn source.tailNodeWithRetries(nodeContext.Ctx, nodeContext.Node)\n\t\t})\n\t}\n}\n\nfunc (source *Source) tailNodeWithRetries(ctx context.Context, node string) error {\n\tfor {\n\t\treadErr := source.readDmesg(ctx, node)\n\t\tif errors.Is(readErr, context.Canceled) || status.Code(readErr) == codes.Canceled {\n\t\t\treturn nil\n\t\t}\n\n\t\tif readErr != nil {\n\t\t\tresolved := source.resolver.Resolve(node)\n\n\t\t\tsource.LogCh <- Data{Node: resolved, Error: readErr.Error()}\n\t\t}\n\n\t\t// back off a bit before retrying\n\t\tsleepWithContext(ctx, 30*time.Second)\n\t}\n}\n\nfunc (source *Source) readDmesg(ctx context.Context, node string) error {\n\tdmesgStream, err := source.client.Dmesg(ctx, true, false)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dashboard: error opening dmesg stream: %w\", err)\n\t}\n\n\treadErr := helpers.ReadGRPCStream(dmesgStream, func(data *common.Data, _ string, _ bool) error {\n\t\tif len(data.Bytes) == 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\tline := strings.TrimSpace(string(data.Bytes))\n\t\tif line == \"\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase source.LogCh <- Data{Node: node, Log: line}:\n\t\t}\n\n\t\treturn nil\n\t})\n\tif readErr != nil {\n\t\treturn fmt.Errorf(\"error reading dmesg stream: %w\", readErr)\n\t}\n\n\treturn nil\n}\n\nfunc sleepWithContext(ctx context.Context, d time.Duration) {\n\ttimer := time.NewTimer(d)\n\tselect {\n\tcase <-ctx.Done():\n\t\tif !timer.Stop() {\n\t\t\t<-timer.C\n\t\t}\n\tcase <-timer.C:\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/monitor.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/components\"\n)\n\n// MonitorGrid represents the monitoring grid with a process table and various metrics.\ntype MonitorGrid struct {\n\ttview.Grid\n\n\tapp *tview.Application\n\n\tapiDataListeners []APIDataListener\n\n\tprocessTable *components.ProcessTable\n}\n\n// NewMonitorGrid initializes MonitorGrid.\nfunc NewMonitorGrid(app *tview.Application) *MonitorGrid {\n\twidget := &MonitorGrid{\n\t\tapp:  app,\n\t\tGrid: *tview.NewGrid(),\n\t}\n\n\twidget.SetRows(7, -1, -2).SetColumns(0)\n\n\tinfoGrid := tview.NewGrid().SetRows(0).SetColumns(-1, -2, -1, -1, -2)\n\n\tsysGauges := components.NewSystemGauges()\n\tcpuInfo := components.NewCPUInfo()\n\tloadAvgInfo := components.NewLoadAvgInfo()\n\tprocsInfo := components.NewProcsInfo()\n\tmemInfo := components.NewMemInfo()\n\n\tinfoGrid.AddItem(sysGauges, 0, 0, 1, 1, 0, 0, false)\n\tinfoGrid.AddItem(cpuInfo, 0, 1, 1, 1, 0, 0, false)\n\tinfoGrid.AddItem(loadAvgInfo, 0, 2, 1, 1, 0, 0, false)\n\tinfoGrid.AddItem(procsInfo, 0, 3, 1, 1, 0, 0, false)\n\tinfoGrid.AddItem(memInfo, 0, 4, 1, 1, 0, 0, false)\n\n\tgraphGrid := tview.NewGrid().SetRows(0).SetColumns(0, 0, 0)\n\n\tcpuGraph := components.NewCPUGraph()\n\tmemGraph := components.NewMemGraph()\n\tloadAvgGraph := components.NewLoadAvgGraph()\n\n\tgraphGrid.AddItem(cpuGraph, 0, 0, 1, 1, 0, 0, false)\n\tgraphGrid.AddItem(memGraph, 0, 1, 1, 1, 0, 0, false)\n\tgraphGrid.AddItem(loadAvgGraph, 0, 2, 1, 1, 0, 0, false)\n\n\tbottomGrid := tview.NewGrid().SetRows(0, 0).SetColumns(-1, -3)\n\n\tnetSparkline := components.NewNetSparkline()\n\tdiskSparkline := components.NewDiskSparkline()\n\n\twidget.processTable = components.NewProcessTable()\n\n\tbottomGrid.AddItem(netSparkline, 0, 0, 1, 1, 0, 0, false)\n\tbottomGrid.AddItem(diskSparkline, 1, 0, 1, 1, 0, 0, false)\n\tbottomGrid.AddItem(widget.processTable, 0, 1, 2, 1, 0, 0, false)\n\n\twidget.AddItem(infoGrid, 0, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(graphGrid, 1, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(bottomGrid, 2, 0, 1, 1, 0, 0, false)\n\n\twidget.apiDataListeners = []APIDataListener{\n\t\tsysGauges,\n\t\tcpuInfo,\n\t\tloadAvgInfo,\n\t\tprocsInfo,\n\t\tmemInfo,\n\t\tcpuGraph,\n\t\tmemGraph,\n\t\tloadAvgGraph,\n\t\tnetSparkline,\n\t\tdiskSparkline,\n\t\twidget.processTable,\n\t}\n\n\treturn widget\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *MonitorGrid) OnAPIDataChange(node string, data *apidata.Data) {\n\tfor _, dataWidget := range widget.apiDataListeners {\n\t\tdataWidget.OnAPIDataChange(node, data)\n\t}\n}\n\n// OnScreenSelect implements the screenSelectListener interface.\nfunc (widget *MonitorGrid) onScreenSelect(active bool) {\n\tif active {\n\t\twidget.processTable.ScrollToBeginning()\n\t\twidget.processTable.Select(1, 0)\n\t\twidget.app.SetFocus(widget.processTable)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/networkconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tview\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\truntimeres \"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nconst (\n\tformItemHostname    = \"Hostname\"\n\tformItemDNSServers  = \"DNS Servers\"\n\tformItemTimeServers = \"Time Servers\"\n\tformItemInterface   = \"Interface\"\n\tformItemMode        = \"Mode\"\n\tformItemAddresses   = \"Addresses\"\n\tformItemGateway     = \"Gateway\"\n)\n\ntype networkConfigData struct {\n\texistingConfig *runtime.PlatformNetworkConfig\n\tnewConfig      *runtime.PlatformNetworkConfig\n\tnewConfigError error\n\tlinkSet        map[string]struct{}\n}\n\n// NetworkConfigGrid represents the network configuration widget.\ntype NetworkConfigGrid struct {\n\ttview.Grid\n\n\tdashboard *Dashboard\n\n\tconfigForm        *tview.Form\n\thostnameField     *tview.InputField\n\tdnsServersField   *tview.InputField\n\ttimeServersField  *tview.InputField\n\tinterfaceDropdown *tview.DropDown\n\tmodeDropdown      *tview.DropDown\n\taddressesField    *tview.InputField\n\tgatewayField      *tview.InputField\n\n\tinfoView           *tview.TextView\n\texistingConfigView *tview.TextView\n\tnewConfigView      *tview.TextView\n\n\tselectedNode string\n\tnodeMap      map[string]*networkConfigData\n}\n\n// NewNetworkConfigGrid initializes NetworkConfigGrid.\nfunc NewNetworkConfigGrid(ctx context.Context, dashboard *Dashboard) *NetworkConfigGrid {\n\twidget := &NetworkConfigGrid{\n\t\tGrid:               *tview.NewGrid(),\n\t\tconfigForm:         tview.NewForm(),\n\t\tinfoView:           tview.NewTextView(),\n\t\texistingConfigView: tview.NewTextView(),\n\t\tnewConfigView:      tview.NewTextView(),\n\t\tnodeMap:            make(map[string]*networkConfigData),\n\t\tdashboard:          dashboard,\n\t}\n\n\twidget.configForm.SetBorder(true).SetTitle(\"Configure (Ctrl+Q)\")\n\twidget.SetRows(0, 3).SetColumns(0, 0, 0)\n\n\twidget.infoView.\n\t\tSetDynamicColors(true).\n\t\tSetScrollable(true).\n\t\tSetWrap(true)\n\twidget.existingConfigView.\n\t\tSetDynamicColors(true).\n\t\tSetScrollable(true).\n\t\tSetBorderPadding(0, 0, 1, 0).\n\t\tSetBorder(true).\n\t\tSetTitle(\"Existing Config (Ctrl+W)\")\n\twidget.newConfigView.\n\t\tSetDynamicColors(true).\n\t\tSetScrollable(true).\n\t\tSetBorderPadding(0, 0, 1, 0).\n\t\tSetBorder(true).\n\t\tSetTitle(\"New Config (Ctrl+E)\")\n\n\twidget.AddItem(widget.configForm, 0, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(widget.infoView, 1, 0, 1, 1, 0, 0, false)\n\twidget.AddItem(widget.existingConfigView, 0, 1, 2, 1, 0, 0, false)\n\twidget.AddItem(widget.newConfigView, 0, 2, 2, 1, 0, 0, false)\n\n\twidget.hostnameField = tview.NewInputField().SetLabel(formItemHostname)\n\twidget.hostnameField.SetBlurFunc(widget.formEdited)\n\n\twidget.dnsServersField = tview.NewInputField().SetLabel(formItemDNSServers)\n\twidget.dnsServersField.SetBlurFunc(widget.formEdited)\n\n\twidget.timeServersField = tview.NewInputField().SetLabel(formItemTimeServers)\n\twidget.timeServersField.SetBlurFunc(widget.formEdited)\n\n\twidget.interfaceDropdown = tview.NewDropDown().SetLabel(formItemInterface)\n\twidget.interfaceDropdown.SetBlurFunc(widget.formEdited)\n\twidget.interfaceDropdown.SetOptions([]string{interfaceNone}, func(_ string, _ int) {\n\t\twidget.formEdited()\n\t})\n\twidget.interfaceDropdown.SetListStyles(\n\t\ttcell.StyleDefault.Foreground(tview.Styles.PrimitiveBackgroundColor).Background(tview.Styles.MoreContrastBackgroundColor),\n\t\ttcell.StyleDefault.Foreground(tcell.ColorBlack).Background(tview.Styles.PrimaryTextColor),\n\t)\n\n\twidget.modeDropdown = tview.NewDropDown().SetLabel(formItemMode)\n\twidget.modeDropdown.SetBlurFunc(widget.formEdited)\n\twidget.modeDropdown.SetOptions([]string{ModeDHCP, ModeStatic}, func(_ string, _ int) {\n\t\twidget.formEdited()\n\t})\n\twidget.modeDropdown.SetListStyles(\n\t\ttcell.StyleDefault.Foreground(tview.Styles.PrimitiveBackgroundColor).Background(tview.Styles.MoreContrastBackgroundColor),\n\t\ttcell.StyleDefault.Foreground(tcell.ColorBlack).Background(tview.Styles.PrimaryTextColor),\n\t)\n\n\twidget.addressesField = tview.NewInputField().SetLabel(formItemAddresses)\n\twidget.addressesField.SetBlurFunc(widget.formEdited)\n\n\twidget.gatewayField = tview.NewInputField().SetLabel(formItemGateway)\n\twidget.gatewayField.SetBlurFunc(widget.formEdited)\n\n\twidget.configForm.AddFormItem(widget.hostnameField)\n\twidget.configForm.AddFormItem(widget.dnsServersField)\n\twidget.configForm.AddFormItem(widget.timeServersField)\n\twidget.configForm.AddFormItem(widget.interfaceDropdown)\n\twidget.configForm.AddFormItem(widget.modeDropdown)\n\twidget.configForm.AddFormItem(widget.addressesField)\n\twidget.configForm.AddFormItem(widget.gatewayField)\n\n\twidget.configForm.AddButton(\"Save\", func() {\n\t\twidget.save(ctx)\n\t})\n\n\tsaveButton := widget.configForm.GetButton(0)\n\tsaveButton.SetBlurFunc(widget.formEdited)\n\n\tinputCapture := func(event *tcell.EventKey) *tcell.EventKey {\n\t\tif widget.handleFocusSwitch(event) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn event\n\t}\n\n\twidget.configForm.SetInputCapture(inputCapture)\n\twidget.existingConfigView.SetInputCapture(inputCapture)\n\twidget.newConfigView.SetInputCapture(inputCapture)\n\n\twidget.interfaceDropdown.SetCurrentOption(0)\n\twidget.modeDropdown.SetCurrentOption(0)\n\n\treturn widget\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *NetworkConfigGrid) OnNodeSelect(node string) {\n\tif node != widget.selectedNode {\n\t\twidget.selectedNode = node\n\n\t\twidget.clearForm()\n\t\twidget.formEdited()\n\n\t\twidget.redraw()\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *NetworkConfigGrid) OnResourceDataChange(data resourcedata.Data) {\n\twidget.updateNodeData(data)\n\n\tif data.Node == widget.selectedNode {\n\t\twidget.redraw()\n\t}\n}\n\n//nolint:gocyclo\nfunc (widget *NetworkConfigGrid) formEdited() {\n\twidget.infoView.SetText(\"\")\n\n\tresetInputField := func(field *tview.InputField) {\n\t\t// avoid triggering another form edit if there is nothing to change\n\t\tif field.GetText() != \"\" {\n\t\t\tfield.SetText(\"\")\n\t\t}\n\t}\n\n\tresetDropdown := func(dropdown *tview.DropDown) {\n\t\t// avoid triggering another form edit if there is nothing to change\n\t\tif currentIndex, _ := dropdown.GetCurrentOption(); currentIndex != 0 {\n\t\t\tdropdown.SetCurrentOption(0)\n\t\t}\n\t}\n\n\t_, currentInterface := widget.interfaceDropdown.GetCurrentOption()\n\t_, currentMode := widget.modeDropdown.GetCurrentOption()\n\n\tifaceSelected := currentInterface != \"\" && currentInterface != interfaceNone\n\tif ifaceSelected {\n\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemMode); itemIndex == -1 {\n\t\t\twidget.configForm.AddFormItem(widget.modeDropdown)\n\t\t}\n\n\t\tswitch currentMode {\n\t\tcase ModeDHCP:\n\t\t\tresetInputField(widget.addressesField)\n\t\t\tresetInputField(widget.gatewayField)\n\n\t\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemAddresses); itemIndex != -1 {\n\t\t\t\twidget.configForm.RemoveFormItem(itemIndex)\n\t\t\t}\n\n\t\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemGateway); itemIndex != -1 {\n\t\t\t\twidget.configForm.RemoveFormItem(itemIndex)\n\t\t\t}\n\t\tcase ModeStatic:\n\t\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemAddresses); itemIndex == -1 {\n\t\t\t\twidget.configForm.AddFormItem(widget.addressesField)\n\t\t\t}\n\n\t\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemGateway); itemIndex == -1 {\n\t\t\t\twidget.configForm.AddFormItem(widget.gatewayField)\n\t\t\t}\n\t\t}\n\t} else {\n\t\tresetDropdown(widget.modeDropdown)\n\t\tresetInputField(widget.addressesField)\n\t\tresetInputField(widget.gatewayField)\n\n\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemMode); itemIndex != -1 {\n\t\t\twidget.configForm.RemoveFormItem(itemIndex)\n\t\t}\n\n\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemAddresses); itemIndex != -1 {\n\t\t\twidget.configForm.RemoveFormItem(itemIndex)\n\t\t}\n\n\t\tif itemIndex := widget.configForm.GetFormItemIndex(formItemGateway); itemIndex != -1 {\n\t\t\twidget.configForm.RemoveFormItem(itemIndex)\n\t\t}\n\t}\n\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tformData := NetworkConfigFormData{\n\t\tBase:        pointer.SafeDeref(data.existingConfig),\n\t\tHostname:    widget.hostnameField.GetText(),\n\t\tDNSServers:  widget.dnsServersField.GetText(),\n\t\tTimeServers: widget.timeServersField.GetText(),\n\t\tIface:       currentInterface,\n\t\tMode:        currentMode,\n\t\tAddresses:   widget.addressesField.GetText(),\n\t\tGateway:     widget.gatewayField.GetText(),\n\t}\n\n\tconfig, err := formData.ToPlatformNetworkConfig()\n\tif err != nil {\n\t\tdata.newConfig = nil\n\t\tdata.newConfigError = err\n\t} else {\n\t\tdata.newConfig = config\n\t\tdata.newConfigError = nil\n\t}\n\n\twidget.redraw()\n}\n\nfunc (widget *NetworkConfigGrid) redraw() {\n\tdata := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tif data.existingConfig != nil {\n\t\tvar buf strings.Builder\n\n\t\tencoder := yaml.NewEncoder(&buf)\n\t\tencoder.SetIndent(2)\n\n\t\terr := encoder.Encode(data.existingConfig)\n\t\tif err != nil {\n\t\t\twidget.existingConfigView.SetText(fmt.Sprintf(\"[red]error: %v[-]\", err))\n\t\t}\n\n\t\twidget.existingConfigView.SetText(fmt.Sprintf(\"[lightblue]%s[-]\", tview.Escape(buf.String())))\n\t} else {\n\t\twidget.existingConfigView.SetText(\"[gray]No Config[-]\")\n\t}\n\n\tif data.newConfigError != nil {\n\t\twidget.newConfigView.SetText(fmt.Sprintf(\"[red]error: %v[-]\", data.newConfigError))\n\t} else if data.newConfig != nil {\n\t\tvar buf strings.Builder\n\n\t\tencoder := yaml.NewEncoder(&buf)\n\t\tencoder.SetIndent(2)\n\n\t\terr := encoder.Encode(data.newConfig)\n\t\tif err != nil {\n\t\t\twidget.newConfigView.SetText(fmt.Sprintf(\"[red]error: %v[-]\", err))\n\t\t}\n\n\t\twidget.newConfigView.SetText(fmt.Sprintf(\"[green]%s[-]\", tview.Escape(buf.String())))\n\t}\n}\n\nfunc (widget *NetworkConfigGrid) clearForm() {\n\twidget.hostnameField.SetText(\"\")\n\twidget.dnsServersField.SetText(\"\")\n\twidget.timeServersField.SetText(\"\")\n\twidget.interfaceDropdown.SetCurrentOption(0)\n\twidget.modeDropdown.SetCurrentOption(0)\n\twidget.addressesField.SetText(\"\")\n\twidget.gatewayField.SetText(\"\")\n\twidget.infoView.SetText(\"\")\n\n\twidget.configForm.SetFocus(0)\n\n\twidget.formEdited()\n}\n\nfunc (widget *NetworkConfigGrid) updateNodeData(data resourcedata.Data) {\n\tnodeData := widget.getOrCreateNodeData(data.Node)\n\n\tswitch res := data.Resource.(type) {\n\tcase *network.LinkStatus:\n\t\tif data.Deleted {\n\t\t\tdelete(nodeData.linkSet, res.Metadata().ID())\n\t\t} else {\n\t\t\tif !res.TypedSpec().Physical() {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tnodeData.linkSet[res.Metadata().ID()] = struct{}{}\n\t\t}\n\n\t\tlinks := maps.Keys(nodeData.linkSet)\n\n\t\tslices.Sort(links)\n\n\t\tallLinks := append([]string{interfaceNone}, links...)\n\n\t\twidget.interfaceDropdown.SetOptions(allLinks, func(_ string, _ int) {\n\t\t\twidget.formEdited()\n\t\t})\n\tcase *runtimeres.MetaKey:\n\t\tif res.Metadata().ID() == runtimeres.MetaKeyTagToID(meta.MetalNetworkPlatformConfig) {\n\t\t\tif data.Deleted {\n\t\t\t\tnodeData.existingConfig = nil\n\t\t\t} else {\n\t\t\t\tcfg := runtime.PlatformNetworkConfig{}\n\n\t\t\t\tif err := yaml.Unmarshal([]byte(res.TypedSpec().Value), &cfg); err != nil {\n\t\t\t\t\twidget.existingConfigView.SetText(fmt.Sprintf(\"[red]error: %v[-]\", err))\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tnodeData.existingConfig = &cfg\n\n\t\t\t\twidget.formEdited()\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (widget *NetworkConfigGrid) getOrCreateNodeData(node string) *networkConfigData {\n\tnodeData, ok := widget.nodeMap[node]\n\tif !ok {\n\t\tnodeData = &networkConfigData{\n\t\t\tlinkSet: make(map[string]struct{}),\n\t\t}\n\n\t\twidget.nodeMap[node] = nodeData\n\t}\n\n\treturn nodeData\n}\n\n// OnScreenSelect implements the screenSelectListener interface.\nfunc (widget *NetworkConfigGrid) onScreenSelect(active bool) {\n\tif active {\n\t\twidget.dashboard.app.SetFocus(widget.configForm)\n\t}\n}\n\nfunc (widget *NetworkConfigGrid) save(ctx context.Context) {\n\tnodeData := widget.getOrCreateNodeData(widget.selectedNode)\n\n\tif nodeData.newConfig == nil {\n\t\twidget.infoView.SetText(\"[red]Error: nothing to save[-]\")\n\n\t\treturn\n\t}\n\n\tif nodeData.newConfigError != nil {\n\t\twidget.infoView.SetText(\"[red]Error: cannot save, fix the errors and try again[-]\")\n\n\t\treturn\n\t}\n\n\tconfigBytes, err := yaml.Marshal(nodeData.newConfig)\n\tif err != nil {\n\t\twidget.infoView.SetText(fmt.Sprintf(\"[red]Error: %v[-]\", err))\n\n\t\treturn\n\t}\n\n\tctx = nodeContext(ctx, widget.selectedNode)\n\n\tif err = widget.dashboard.cli.MetaWrite(ctx, meta.MetalNetworkPlatformConfig, configBytes); err != nil {\n\t\twidget.infoView.SetText(fmt.Sprintf(\"[red]Error: %v[-]\", err))\n\n\t\treturn\n\t}\n\n\twidget.infoView.SetText(\"[green]Network config saved successfully[-]\")\n\twidget.clearForm()\n\twidget.dashboard.selectScreen(ScreenSummary)\n}\n\nfunc (widget *NetworkConfigGrid) handleFocusSwitch(event *tcell.EventKey) bool {\n\tswitch event.Key() { //nolint:exhaustive\n\tcase tcell.KeyCtrlQ:\n\t\twidget.dashboard.app.SetFocus(widget.configForm)\n\n\t\treturn true\n\tcase tcell.KeyCtrlW:\n\t\twidget.dashboard.app.SetFocus(widget.existingConfigView)\n\n\t\treturn true\n\tcase tcell.KeyCtrlE:\n\t\twidget.dashboard.app.SetFocus(widget.newConfigView)\n\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"time\"\n)\n\ntype options struct {\n\tinterval      time.Duration\n\tallowExitKeys bool\n\tscreens       []Screen\n}\n\nfunc defaultOptions() *options {\n\treturn &options{\n\t\tinterval:      5 * time.Second,\n\t\tallowExitKeys: true,\n\t\tscreens: []Screen{\n\t\t\tScreenSummary,\n\t\t\tScreenMonitor,\n\t\t\tScreenNetworkConfig,\n\t\t},\n\t}\n}\n\n// Option is a functional option for Dashboard.\ntype Option func(*options)\n\n// WithInterval sets the interval for the dashboard.\nfunc WithInterval(interval time.Duration) Option {\n\treturn func(o *options) {\n\t\to.interval = interval\n\t}\n}\n\n// WithAllowExitKeys sets whether the dashboard should allow exit keys (Ctrl + C).\nfunc WithAllowExitKeys(allowExitKeys bool) Option {\n\treturn func(o *options) {\n\t\to.allowExitKeys = allowExitKeys\n\t}\n}\n\n// WithScreens sets the screens to display.\n// The order is preserved.\nfunc WithScreens(screens ...Screen) Option {\n\treturn func(o *options) {\n\t\to.screens = screens\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/resolver/resolver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package resolver resolves the node names.\npackage resolver\n\n// Resolver resolves the node names.\ntype Resolver struct {\n\tdb map[string]string\n}\n\n// New creates a new Resolver.\nfunc New(db map[string]string) Resolver {\n\treturn Resolver{\n\t\tdb: db,\n\t}\n}\n\n// Resolve attempts to resolve the node name.\nfunc (n *Resolver) Resolve(node string) string {\n\tif resolved, ok := n.db[node]; ok {\n\t\treturn resolved\n\t}\n\n\treturn node\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/resourcedata/resourcedata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package resourcedata implements the types and the data sources for the data sourced from the Talos resource API (COSI).\npackage resourcedata\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/util\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// Data contains a resource, whether it is deleted and the node it came from.\ntype Data struct {\n\tNode     string\n\tResource resource.Resource\n\tDeleted  bool\n}\n\n// Source is the data source for the Talos resources.\ntype Source struct {\n\tctxCancel context.CancelFunc\n\n\teg   errgroup.Group\n\tonce sync.Once\n\n\tCOSI state.State\n\n\tch             chan Data\n\tNodeResourceCh <-chan Data\n}\n\n// Run starts the data source.\nfunc (source *Source) Run(ctx context.Context) {\n\tsource.once.Do(func() {\n\t\tsource.run(ctx)\n\t})\n}\n\n// Stop stops the data source.\nfunc (source *Source) Stop() error {\n\tsource.ctxCancel()\n\n\treturn source.eg.Wait()\n}\n\nfunc (source *Source) run(ctx context.Context) {\n\tctx, source.ctxCancel = context.WithCancel(ctx)\n\n\tsource.ch = make(chan Data)\n\n\tsource.NodeResourceCh = source.ch\n\n\tfor _, nodeContext := range util.NodeContexts(ctx) {\n\t\tsource.eg.Go(func() error {\n\t\t\tsource.runResourceWatchWithRetries(nodeContext.Ctx, nodeContext.Node)\n\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc (source *Source) runResourceWatchWithRetries(ctx context.Context, node string) {\n\tfor {\n\t\tif err := source.runResourceWatch(ctx, node); errors.Is(err, context.Canceled) {\n\t\t\treturn\n\t\t}\n\n\t\t// wait for a second before the next retry\n\t\ttimer := time.NewTimer(1 * time.Second)\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\ttimer.Stop()\n\n\t\t\treturn\n\t\tcase <-timer.C:\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (source *Source) runResourceWatch(ctx context.Context, node string) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\teventCh := make(chan state.Event)\n\n\twatchResources := []resource.Pointer{\n\t\truntime.NewMachineStatus().Metadata(),\n\t\truntime.NewSecurityStateSpec(v1alpha1.NamespaceName).Metadata(),\n\t\tconfig.NewMachineType().Metadata(),\n\t\tk8s.NewKubeletSpec(k8s.NamespaceName, k8s.KubeletID).Metadata(),\n\t\tnetwork.NewResolverStatus(network.NamespaceName, network.ResolverID).Metadata(),\n\t\tnetwork.NewTimeServerStatus(network.NamespaceName, network.TimeServerID).Metadata(),\n\t\thardware.NewSystemInformation(hardware.SystemInformationID).Metadata(),\n\t\tcluster.NewInfo().Metadata(),\n\t\tnetwork.NewStatus(network.NamespaceName, network.StatusID).Metadata(),\n\t\tnetwork.NewHostnameStatus(network.NamespaceName, network.HostnameID).Metadata(),\n\t}\n\n\tfor _, ptr := range watchResources {\n\t\terr := source.COSI.Watch(ctx, ptr, eventCh)\n\t\tif err != nil && client.StatusCode(err) != codes.PermissionDenied {\n\t\t\treturn err\n\t\t}\n\t}\n\n\twatchKindResources := []resource.Pointer{\n\t\truntime.NewMetaKey(runtime.NamespaceName, \"\").Metadata(),\n\t\tk8s.NewStaticPodStatus(k8s.NamespaceName, \"\").Metadata(),\n\t\tnetwork.NewRouteStatus(network.NamespaceName, \"\").Metadata(),\n\t\tnetwork.NewLinkStatus(network.NamespaceName, \"\").Metadata(),\n\t\tcluster.NewMember(cluster.NamespaceName, \"\").Metadata(),\n\t\tnetwork.NewNodeAddress(network.NamespaceName, \"\").Metadata(),\n\t\tsiderolink.NewStatus().Metadata(),\n\t\truntime.NewDiagnostic(runtime.NamespaceName, \"\").Metadata(),\n\t}\n\n\tfor _, ptr := range watchKindResources {\n\t\terr := source.COSI.WatchKind(ctx, ptr, eventCh, state.WithBootstrapContents(true))\n\t\tif err != nil && client.StatusCode(err) != codes.PermissionDenied {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase event := <-eventCh:\n\t\t\tswitch event.Type {\n\t\t\tcase state.Errored:\n\t\t\t\treturn fmt.Errorf(\"watch failed: %w\", event.Error)\n\t\t\tcase state.Bootstrapped, state.Noop:\n\t\t\t\t// ignored\n\t\t\tcase state.Created, state.Updated:\n\t\t\t\tif !channel.SendWithContext(ctx, source.ch, Data{\n\t\t\t\t\tNode:     node,\n\t\t\t\t\tResource: event.Resource,\n\t\t\t\t}) {\n\t\t\t\t\treturn ctx.Err()\n\t\t\t\t}\n\t\t\tcase state.Destroyed:\n\t\t\t\tif !channel.SendWithContext(ctx, source.ch, Data{\n\t\t\t\t\tNode:     node,\n\t\t\t\t\tResource: event.Resource,\n\t\t\t\t\tDeleted:  true,\n\t\t\t\t}) {\n\t\t\t\t\treturn ctx.Err()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/summary.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dashboard\n\nimport (\n\t\"github.com/rivo/tview\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/apidata\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/components\"\n\t\"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata\"\n)\n\n// SummaryGrid represents the summary grid with the basic node information and the logs.\ntype SummaryGrid struct {\n\ttview.Grid\n\n\tapp *tview.Application\n\n\tapiDataListeners    []APIDataListener\n\tresourceListeners   []ResourceDataListener\n\tnodeSelectListeners []NodeSelectListener\n\n\tactive     bool\n\tnode       string\n\tlogViewers map[string]*components.LogViewer\n\n\tdiagnostics        *components.Diagnostics\n\tdiagnosticsVisible bool\n}\n\nconst summaryTopFixedRows = 7\n\n// NewSummaryGrid initializes SummaryGrid.\nfunc NewSummaryGrid(app *tview.Application) *SummaryGrid {\n\twidget := &SummaryGrid{\n\t\tapp:        app,\n\t\tGrid:       *tview.NewGrid(),\n\t\tlogViewers: make(map[string]*components.LogViewer),\n\t}\n\n\twidget.SetRows(summaryTopFixedRows, 0).SetColumns(-3, -2, -3)\n\n\ttalosInfo := components.NewTalosInfo()\n\twidget.AddItem(talosInfo, 0, 0, 1, 1, 0, 0, false)\n\n\tkubernetesInfo := components.NewKubernetesInfo()\n\twidget.AddItem(kubernetesInfo, 0, 1, 1, 1, 0, 0, false)\n\n\tnetworkInfo := components.NewNetworkInfo()\n\twidget.AddItem(networkInfo, 0, 2, 1, 1, 0, 0, false)\n\n\twidget.diagnostics = components.NewDiagnostics()\n\n\twidget.apiDataListeners = []APIDataListener{\n\t\tkubernetesInfo,\n\t}\n\n\twidget.resourceListeners = []ResourceDataListener{\n\t\ttalosInfo,\n\t\tkubernetesInfo,\n\t\tnetworkInfo,\n\t\twidget.diagnostics,\n\t}\n\n\twidget.nodeSelectListeners = []NodeSelectListener{\n\t\ttalosInfo,\n\t\tkubernetesInfo,\n\t\tnetworkInfo,\n\t\twidget.diagnostics,\n\t}\n\n\treturn widget\n}\n\n// OnNodeSelect implements the NodeSelectListener interface.\nfunc (widget *SummaryGrid) OnNodeSelect(node string) {\n\twidget.node = node\n\n\twidget.updateLogViewer()\n\n\tfor _, nodeSelectListener := range widget.nodeSelectListeners {\n\t\tnodeSelectListener.OnNodeSelect(node)\n\t}\n\n\twidget.updateDiagnostics()\n}\n\n// OnAPIDataChange implements the APIDataListener interface.\nfunc (widget *SummaryGrid) OnAPIDataChange(node string, data *apidata.Data) {\n\tfor _, dataWidget := range widget.apiDataListeners {\n\t\tdataWidget.OnAPIDataChange(node, data)\n\t}\n}\n\n// OnResourceDataChange implements the ResourceDataListener interface.\nfunc (widget *SummaryGrid) OnResourceDataChange(nodeResource resourcedata.Data) {\n\tfor _, resourceListener := range widget.resourceListeners {\n\t\tresourceListener.OnResourceDataChange(nodeResource)\n\t}\n\n\twidget.updateDiagnostics()\n}\n\n// OnLogDataChange implements the LogDataListener interface.\nfunc (widget *SummaryGrid) OnLogDataChange(node, logLine, logError string) {\n\twidget.logViewer(node).WriteLog(logLine, logError)\n}\n\nfunc (widget *SummaryGrid) updateDiagnostics() {\n\theight := widget.diagnostics.GetCurrentHeight()\n\n\tswitch {\n\tcase height == 0 && widget.diagnosticsVisible:\n\t\twidget.RemoveItem(widget.diagnostics)\n\t\twidget.SetRows(summaryTopFixedRows, 0)\n\t\twidget.diagnosticsVisible = false\n\tcase height > 0 && !widget.diagnosticsVisible:\n\t\twidget.SetRows(summaryTopFixedRows, 0, height)\n\t\twidget.AddItem(widget.diagnostics, 2, 0, 1, 3, 0, 0, false)\n\t\twidget.diagnosticsVisible = true\n\tcase height > 0:\n\t\twidget.SetRows(summaryTopFixedRows, 0, height)\n\t}\n}\n\nfunc (widget *SummaryGrid) updateLogViewer() {\n\tif !widget.active {\n\t\treturn\n\t}\n\n\twidget.logViewer(widget.node)\n\n\tfor currNode, logViewer := range widget.logViewers {\n\t\tif currNode == widget.node {\n\t\t\twidget.AddItem(logViewer, 1, 0, 1, 3, 0, 0, false)\n\n\t\t\twidget.app.SetFocus(logViewer)\n\n\t\t\treturn\n\t\t}\n\n\t\twidget.RemoveItem(logViewer)\n\t}\n}\n\nfunc (widget *SummaryGrid) logViewer(node string) *components.LogViewer {\n\tlogViewer, ok := widget.logViewers[node]\n\tif !ok {\n\t\tlogViewer = components.NewLogViewer()\n\n\t\twidget.logViewers[node] = logViewer\n\t}\n\n\treturn logViewer\n}\n\n// OnScreenSelect implements the screenSelectListener interface.\nfunc (widget *SummaryGrid) onScreenSelect(active bool) {\n\twidget.active = active\n\n\twidget.updateLogViewer()\n}\n"
  },
  {
    "path": "internal/pkg/dashboard/util/util.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package util provides utility functions for the dashboard.\n//\n//nolint:revive\npackage util\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// NodeContext contains the context.Context for a single node and the node name.\ntype NodeContext struct {\n\tCtx  context.Context //nolint:containedctx\n\tNode string\n}\n\n// NodeContexts returns a list of NodeContexts from the given context.\n//\n// It extracts the node names from the outgoing GRPC context metadata.\n// If the node name is not present in the metadata, context will be returned as-is with an empty node name.\nfunc NodeContexts(ctx context.Context) []NodeContext {\n\tmd, mdOk := metadata.FromOutgoingContext(ctx)\n\tif !mdOk {\n\t\treturn []NodeContext{{Ctx: ctx}}\n\t}\n\n\tnodeVal := md.Get(\"node\")\n\tif len(nodeVal) > 0 {\n\t\treturn []NodeContext{{Ctx: ctx, Node: nodeVal[0]}}\n\t}\n\n\tnodesVal := md.Get(\"nodes\")\n\tif len(nodesVal) == 0 {\n\t\treturn []NodeContext{{Ctx: ctx}}\n\t}\n\n\tnodeContexts := make([]NodeContext, 0, len(nodesVal))\n\n\tfor _, node := range nodesVal {\n\t\tnodeContexts = append(nodeContexts, NodeContext{Ctx: client.WithNode(ctx, node), Node: node})\n\t}\n\n\treturn nodeContexts\n}\n"
  },
  {
    "path": "internal/pkg/discovery/registry/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\tv1 \"k8s.io/api/core/v1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/labels\"\n\t\"k8s.io/apimachinery/pkg/types\"\n\t\"k8s.io/apimachinery/pkg/util/strategicpatch\"\n\t\"k8s.io/client-go/informers\"\n\tinformersv1 \"k8s.io/client-go/informers/core/v1\"\n\t\"k8s.io/client-go/tools/cache\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// Kubernetes defines a Kubernetes-based node discoverer.\ntype Kubernetes struct {\n\tclient *kubernetes.Client\n\n\tnodes informersv1.NodeInformer\n}\n\n// NewKubernetes creates new Kubernetes registry.\nfunc NewKubernetes(client *kubernetes.Client) *Kubernetes {\n\treturn &Kubernetes{\n\t\tclient: client,\n\t}\n}\n\n// AnnotationsFromAffiliate generates Kubernetes Node annotations from the Affiliate spec.\nfunc AnnotationsFromAffiliate(affiliate *cluster.Affiliate) map[string]string {\n\tvar kubeSpanAddress string\n\n\tif !value.IsZero(affiliate.TypedSpec().KubeSpan.Address) {\n\t\tkubeSpanAddress = affiliate.TypedSpec().KubeSpan.Address.String()\n\t}\n\n\tvar apiServerPort string\n\n\tif affiliate.TypedSpec().ControlPlane != nil {\n\t\tapiServerPort = strconv.Itoa(affiliate.TypedSpec().ControlPlane.APIServerPort)\n\t}\n\n\treturn map[string]string{\n\t\tconstants.ClusterNodeIDAnnotation:                     affiliate.Metadata().ID(),\n\t\tconstants.NetworkSelfIPsAnnotation:                    ipsToString(affiliate.TypedSpec().Addresses),\n\t\tconstants.NetworkAPIServerPortAnnotation:              apiServerPort,\n\t\tconstants.KubeSpanIPAnnotation:                        kubeSpanAddress,\n\t\tconstants.KubeSpanPublicKeyAnnotation:                 affiliate.TypedSpec().KubeSpan.PublicKey,\n\t\tconstants.KubeSpanAssignedPrefixesAnnotation:          ipPrefixesToString(affiliate.TypedSpec().KubeSpan.AdditionalAddresses),\n\t\tconstants.KubeSpanKnownEndpointsAnnotation:            ipPortsToString(affiliate.TypedSpec().KubeSpan.Endpoints),\n\t\tconstants.KubeSpanExcludeAdvertisedNetworksAnnotation: ipPrefixesToString(affiliate.TypedSpec().KubeSpan.ExcludeAdvertisedNetworks),\n\t}\n}\n\n// AffiliateFromNode converts Kubernetes Node resource to Affiliate.\n//\n// If the Node resource doesn't have cluster discovery annotations, nil is returned.\n//\n//nolint:gocyclo\nfunc AffiliateFromNode(node *v1.Node) *cluster.AffiliateSpec {\n\tnodeID, ok := node.Annotations[constants.ClusterNodeIDAnnotation]\n\tif !ok {\n\t\t// skip the node, not part of the cluster discovery process\n\t\treturn nil\n\t}\n\n\taffiliate := &cluster.AffiliateSpec{\n\t\tNodeID: nodeID,\n\t}\n\n\tif selfIPs, ok := node.Annotations[constants.NetworkSelfIPsAnnotation]; ok {\n\t\taffiliate.Addresses = parseIPs(selfIPs)\n\t}\n\n\t// Nodename and hostname are pulled from native Kubernetes fields.\n\taffiliate.Nodename = node.Name\n\n\tfor _, addr := range node.Status.Addresses {\n\t\tif addr.Type == v1.NodeHostName {\n\t\t\taffiliate.Hostname = addr.Address\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// Machine type is derived from node roles.\n\t_, labelControlPlane := node.Labels[constants.LabelNodeRoleControlPlane]\n\n\taffiliate.MachineType = machine.TypeWorker\n\n\tif labelControlPlane {\n\t\taffiliate.MachineType = machine.TypeControlPlane\n\t}\n\n\taffiliate.OperatingSystem = node.Status.NodeInfo.OSImage\n\n\t// Every other field is pulled from node annotations.\n\tif publicKey, ok := node.Annotations[constants.KubeSpanPublicKeyAnnotation]; ok {\n\t\taffiliate.KubeSpan.PublicKey = publicKey\n\t}\n\n\tif ksIP, ok := node.Annotations[constants.KubeSpanIPAnnotation]; ok {\n\t\taffiliate.KubeSpan.Address, _ = netip.ParseAddr(ksIP) //nolint:errcheck\n\t}\n\n\tif additionalAddresses, ok := node.Annotations[constants.KubeSpanAssignedPrefixesAnnotation]; ok {\n\t\taffiliate.KubeSpan.AdditionalAddresses = parseIPPrefixes(additionalAddresses)\n\t}\n\n\tif endpoints, ok := node.Annotations[constants.KubeSpanKnownEndpointsAnnotation]; ok {\n\t\taffiliate.KubeSpan.Endpoints = parseIPPorts(endpoints)\n\t}\n\n\tif apiServerPort, ok := node.Annotations[constants.NetworkAPIServerPortAnnotation]; ok {\n\t\tif port, err := strconv.Atoi(apiServerPort); err == nil {\n\t\t\taffiliate.ControlPlane = &cluster.ControlPlane{\n\t\t\t\tAPIServerPort: port,\n\t\t\t}\n\t\t}\n\t}\n\n\tif advertisedFilters, ok := node.Annotations[constants.KubeSpanExcludeAdvertisedNetworksAnnotation]; ok {\n\t\taffiliate.KubeSpan.ExcludeAdvertisedNetworks = parseIPPrefixes(advertisedFilters)\n\t}\n\n\treturn affiliate\n}\n\nfunc ipsToString(in []netip.Addr) string {\n\treturn strings.Join(xslices.Map(in, netip.Addr.String), \",\")\n}\n\nfunc ipPrefixesToString(in []netip.Prefix) string {\n\treturn strings.Join(xslices.Map(in, netip.Prefix.String), \",\")\n}\n\nfunc ipPortsToString(in []netip.AddrPort) string {\n\treturn strings.Join(xslices.Map(in, netip.AddrPort.String), \",\")\n}\n\nfunc parseIPs(in string) []netip.Addr {\n\tvar result []netip.Addr\n\n\tfor item := range strings.SplitSeq(in, \",\") {\n\t\tif ip, err := netip.ParseAddr(item); err == nil {\n\t\t\tresult = append(result, ip)\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc parseIPPrefixes(in string) []netip.Prefix {\n\tvar result []netip.Prefix\n\n\tfor item := range strings.SplitSeq(in, \",\") {\n\t\tif ip, err := netip.ParsePrefix(item); err == nil {\n\t\t\tresult = append(result, ip)\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc parseIPPorts(in string) []netip.AddrPort {\n\tvar result []netip.AddrPort\n\n\tfor item := range strings.SplitSeq(in, \",\") {\n\t\tif ip, err := netip.ParseAddrPort(item); err == nil {\n\t\t\tresult = append(result, ip)\n\t\t}\n\t}\n\n\treturn result\n}\n\n// Push updates Kubernetes Node resource to track Affiliate state.\nfunc (r *Kubernetes) Push(ctx context.Context, affiliate *cluster.Affiliate) error {\n\tnode, err := r.client.CoreV1().Nodes().Get(ctx, affiliate.TypedSpec().Nodename, metav1.GetOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get node %q: %w\", affiliate.TypedSpec().Nodename, err)\n\t}\n\n\toldData, err := json.Marshal(node)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal existing node data: %w\", err)\n\t}\n\n\tfor key, value := range AnnotationsFromAffiliate(affiliate) {\n\t\tif value == \"\" {\n\t\t\tdelete(node.Annotations, key)\n\t\t} else {\n\t\t\tnode.Annotations[key] = value\n\t\t}\n\t}\n\n\tnewData, err := json.Marshal(node)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal new data for node %q: %w\", node.Name, err)\n\t}\n\n\tpatchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create two way merge patch: %w\", err)\n\t}\n\n\tif _, err := r.client.CoreV1().Nodes().Patch(ctx, affiliate.TypedSpec().Nodename, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}); err != nil {\n\t\tif apierrors.IsConflict(err) {\n\t\t\treturn fmt.Errorf(\"unable to update node %q due to conflict: %w\", affiliate.TypedSpec().Nodename, err)\n\t\t}\n\n\t\treturn fmt.Errorf(\"error patching node %q: %w\", affiliate.TypedSpec().Nodename, err)\n\t}\n\n\treturn nil\n}\n\n// List returns list of Affiliates coming from the registry.\n//\n// Watch should be called first for the List to return data.\nfunc (r *Kubernetes) List(localNodeName string) ([]*cluster.AffiliateSpec, error) {\n\tif r.nodes == nil {\n\t\treturn nil, errors.New(\"List() called without Watch() first\")\n\t}\n\n\tnodes, err := r.nodes.Lister().List(labels.Everything())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]*cluster.AffiliateSpec, 0, len(nodes))\n\n\tfor _, node := range nodes {\n\t\t// skip this node, no need to pull itself\n\t\tif node.Name == localNodeName {\n\t\t\tcontinue\n\t\t}\n\n\t\taffiliate := AffiliateFromNode(node)\n\t\tif affiliate == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, affiliate)\n\t}\n\n\treturn result, nil\n}\n\n// Watch starts watching Node state and notifies on updates via notify channel.\nfunc (r *Kubernetes) Watch(ctx context.Context, logger *zap.Logger) (<-chan struct{}, func(), error) {\n\tinformerFactory := informers.NewSharedInformerFactory(r.client.Clientset, constants.KubernetesInformerDefaultResyncPeriod)\n\n\tnotifyCh := make(chan struct{}, 1)\n\n\tnotify := func(_ any) {\n\t\tselect {\n\t\tcase notifyCh <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}\n\n\tr.nodes = informerFactory.Core().V1().Nodes()\n\n\tif err := r.nodes.Informer().SetWatchErrorHandler(func(r *cache.Reflector, err error) {\n\t\tlogger.Error(\"kubernetes registry node watch error\", zap.Error(err))\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to set watch error handler: %w\", err)\n\t}\n\n\tif _, err := r.nodes.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc:    notify,\n\t\tDeleteFunc: notify,\n\t\tUpdateFunc: func(_, _ any) { notify(nil) },\n\t}); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to add event handler: %w\", err)\n\t}\n\n\tinformerFactory.Start(ctx.Done())\n\n\treturn notifyCh, informerFactory.Shutdown, nil\n}\n"
  },
  {
    "path": "internal/pkg/discovery/registry/kubernetes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/discovery/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc TestAnnotationsFromAffiliate(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname      string\n\t\taffiliate cluster.AffiliateSpec\n\t\texpected  map[string]string\n\t}{\n\t\t{\n\t\t\tname: \"zero\",\n\t\t\texpected: map[string]string{\n\t\t\t\t\"cluster.talos.dev/node-id\":                                 \"\",\n\t\t\t\t\"networking.talos.dev/api-server-port\":                      \"\",\n\t\t\t\t\"networking.talos.dev/assigned-prefixes\":                    \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-endpoints\":                   \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-ip\":                          \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-public-key\":                  \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-exclude-advertised-networks\": \"\",\n\t\t\t\t\"networking.talos.dev/self-ips\":                             \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\t\t\taffiliate: cluster.AffiliateSpec{\n\t\t\t\tNodeID:      \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\"), netip.MustParsePrefix(\"::/0\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"cluster.talos.dev/node-id\":                                 \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\t\"networking.talos.dev/api-server-port\":                      \"\",\n\t\t\t\t\"networking.talos.dev/assigned-prefixes\":                    \"10.244.3.1/24\",\n\t\t\t\t\"networking.talos.dev/kubespan-endpoints\":                   \"10.0.0.2:51820,192.168.3.4:51820\",\n\t\t\t\t\"networking.talos.dev/kubespan-ip\":                          \"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\",\n\t\t\t\t\"networking.talos.dev/kubespan-public-key\":                  \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\"networking.talos.dev/kubespan-exclude-advertised-networks\": \"0.0.0.0/0,::/0\",\n\t\t\t\t\"networking.talos.dev/self-ips\":                             \"10.0.0.2,192.168.3.4\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"controlplane\",\n\t\t\taffiliate: cluster.AffiliateSpec{\n\t\t\t\tNodeID:      \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tControlPlane: &cluster.ControlPlane{\n\t\t\t\t\tAPIServerPort: 443,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]string{\n\t\t\t\t\"cluster.talos.dev/node-id\":                                 \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\t\"networking.talos.dev/api-server-port\":                      \"443\",\n\t\t\t\t\"networking.talos.dev/assigned-prefixes\":                    \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-endpoints\":                   \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-ip\":                          \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-public-key\":                  \"\",\n\t\t\t\t\"networking.talos.dev/kubespan-exclude-advertised-networks\": \"\",\n\t\t\t\t\"networking.talos.dev/self-ips\":                             \"10.0.0.2,192.168.3.4\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\taffiliate := cluster.NewAffiliate(cluster.NamespaceName, tt.affiliate.NodeID)\n\t\t\t*affiliate.TypedSpec() = tt.affiliate\n\n\t\t\tassert.Equal(t, tt.expected, registry.AnnotationsFromAffiliate(affiliate))\n\t\t})\n\t}\n}\n\nfunc TestAffiliateFromNode(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tnode     v1.Node\n\t\texpected *cluster.AffiliateSpec\n\t}{\n\t\t{\n\t\t\tname: \"no annotations\",\n\t\t\tnode: v1.Node{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName:        \"worker-1\",\n\t\t\t\t\tAnnotations: map[string]string{},\n\t\t\t\t},\n\t\t\t\tSpec: v1.NodeSpec{},\n\t\t\t},\n\t\t\texpected: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"discovered\",\n\t\t\tnode: v1.Node{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName: \"bar\",\n\t\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\t\t\"cluster.talos.dev/node-id\":                                 \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\t\t\t\"networking.talos.dev/assigned-prefixes\":                    \"10.244.3.1/24\",\n\t\t\t\t\t\t\"networking.talos.dev/kubespan-endpoints\":                   \"10.0.0.2:51820,192.168.3.4:51820\",\n\t\t\t\t\t\t\"networking.talos.dev/kubespan-ip\":                          \"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\",\n\t\t\t\t\t\t\"networking.talos.dev/kubespan-public-key\":                  \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\t\t\"networking.talos.dev/kubespan-exclude-advertised-networks\": \"0.0.0.0/0,::/0\",\n\t\t\t\t\t\t\"networking.talos.dev/self-ips\":                             \"10.0.0.2,192.168.3.4\",\n\t\t\t\t\t},\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\tconstants.LabelNodeRoleControlPlane: \"\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: v1.NodeSpec{},\n\t\t\t\tStatus: v1.NodeStatus{\n\t\t\t\t\tAddresses: []v1.NodeAddress{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tType:    v1.NodeHostName,\n\t\t\t\t\t\t\tAddress: \"foo.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tNodeInfo: v1.NodeSystemInfo{\n\t\t\t\t\t\tOSImage: \"Talos (v1.0.0)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: &cluster.AffiliateSpec{\n\t\t\t\tNodeID:          \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\tHostname:        \"foo.com\",\n\t\t\t\tNodename:        \"bar\",\n\t\t\t\tMachineType:     machine.TypeControlPlane,\n\t\t\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\"), netip.MustParsePrefix(\"::/0\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"controlplane\",\n\t\t\tnode: v1.Node{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tName: \"bar\",\n\t\t\t\t\tAnnotations: map[string]string{\n\t\t\t\t\t\t\"cluster.talos.dev/node-id\":            \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\t\t\t\"networking.talos.dev/api-server-port\": \"6443\",\n\t\t\t\t\t\t\"networking.talos.dev/self-ips\":        \"10.0.0.2,192.168.3.4\",\n\t\t\t\t\t},\n\t\t\t\t\tLabels: map[string]string{\n\t\t\t\t\t\tconstants.LabelNodeRoleControlPlane: \"\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tSpec: v1.NodeSpec{},\n\t\t\t\tStatus: v1.NodeStatus{\n\t\t\t\t\tAddresses: []v1.NodeAddress{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tType:    v1.NodeHostName,\n\t\t\t\t\t\t\tAddress: \"foo.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tNodeInfo: v1.NodeSystemInfo{\n\t\t\t\t\t\tOSImage: \"Talos (v1.0.0)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: &cluster.AffiliateSpec{\n\t\t\t\tNodeID:          \"29QQTc97U5ZyFTIX33Dp9NqtwxqQI8QI13scCLzffrZ\",\n\t\t\t\tHostname:        \"foo.com\",\n\t\t\t\tNodename:        \"bar\",\n\t\t\t\tMachineType:     machine.TypeControlPlane,\n\t\t\t\tAddresses:       []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t\t\t\tControlPlane: &cluster.ControlPlane{\n\t\t\t\t\tAPIServerPort: 6443,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tassert.Equal(t, tt.expected, registry.AffiliateFromNode(&tt.node))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/discovery/registry/registry.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package registry provides code to push and pull Affiliates to different registries.\npackage registry\n"
  },
  {
    "path": "internal/pkg/dns/dns.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package dns provides dns server implementation.\npackage dns\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"iter\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/coredns/coredns/plugin\"\n\t\"github.com/coredns/coredns/plugin/cache\"\n\t\"github.com/coredns/coredns/plugin/pkg/dnsutil\"\n\t\"github.com/coredns/coredns/plugin/pkg/proxy\"\n\t\"github.com/coredns/coredns/request\"\n\t\"github.com/miekg/dns\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"go.uber.org/zap\"\n\t\"golang.org/x/sys/unix\"\n)\n\n// Cache is a [dns.Handler] to [plugin.Handler] adapter.\ntype Cache struct {\n\tcache  *cache.Cache\n\tlogger *zap.Logger\n}\n\n// NewCache creates a new Cache.\nfunc NewCache(next plugin.Handler, l *zap.Logger) *Cache {\n\tc := cache.NewCache(\n\t\t\"zones\",\n\t\t\"view\",\n\t\tcache.WithNegativeTTL(10*time.Second, dnsutil.MinimalDefaultTTL),\n\t)\n\tc.Next = next\n\n\treturn &Cache{cache: c, logger: l}\n}\n\n// ServeDNS implements [dns.Handler].\nfunc (c *Cache) ServeDNS(wr dns.ResponseWriter, msg *dns.Msg) {\n\twr = request.NewScrubWriter(msg, wr)\n\n\tctx, cancel := context.WithTimeout(context.Background(), 4500*time.Millisecond)\n\tdefer cancel()\n\n\tcode, err := c.cache.ServeDNS(ctx, wr, msg)\n\tif err != nil {\n\t\t// we should probably call newProxy.Healthcheck() if there are too many errors\n\t\tc.logger.Warn(\"error serving dns request\", zap.Error(err))\n\t}\n\n\tif clientWrite(code) {\n\t\treturn\n\t}\n\n\t// Something went wrong\n\tstate := request.Request{W: wr, Req: msg}\n\n\tanswer := new(dns.Msg)\n\tanswer.SetRcode(msg, code)\n\tstate.SizeAndDo(answer)\n\n\terr = wr.WriteMsg(answer)\n\tif err != nil {\n\t\tc.logger.Warn(\"error writing dns response\", zap.Error(err))\n\t}\n}\n\n// Clear clears the cache.\nfunc (c *Cache) Clear() { c.cache.Clear() }\n\n// clientWrite returns true if the response has been written to the client.\nfunc clientWrite(rcode int) bool {\n\tswitch rcode {\n\tcase dns.RcodeServerFailure, dns.RcodeRefused, dns.RcodeFormatError, dns.RcodeNotImplemented:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\n// Handler is a dns proxy selector.\ntype Handler struct {\n\tmx     sync.RWMutex\n\tdests  iter.Seq[*proxy.Proxy]\n\tlogger *zap.Logger\n}\n\n// NewHandler creates a new Handler.\nfunc NewHandler(logger *zap.Logger) *Handler {\n\treturn &Handler{\n\t\tlogger: logger,\n\t\tdests:  xiter.Empty[*proxy.Proxy],\n\t}\n}\n\n// Name implements plugin.Handler.\nfunc (h *Handler) Name() string {\n\treturn \"Handler\"\n}\n\n// ServeDNS implements plugin.Handler.\n//\n//nolint:gocyclo\nfunc (h *Handler) ServeDNS(ctx context.Context, wrt dns.ResponseWriter, msg *dns.Msg) (int, error) {\n\th.mx.RLock()\n\tdefer h.mx.RUnlock()\n\n\treq := request.Request{W: wrt, Req: msg}\n\tlogger := h.logger.With(\n\t\tzap.Stringer(\"data\", msg),\n\t\tzap.String(\"proto\", req.Proto()),\n\t\tzap.String(\"question\", req.QName()),\n\t\tzap.Stringer(\"local_addr\", wrt.LocalAddr()),\n\t\tzap.Stringer(\"remote_addr\", wrt.RemoteAddr()),\n\t)\n\n\tvar (\n\t\tcalled bool\n\t\tresp   *dns.Msg\n\t\terr    error\n\t)\n\n\tfor ups := range h.dests {\n\t\tcalled = true\n\t\topts := proxy.Options{}\n\n\t\tlogger.Debug(\"making dns request\", zap.String(\"upstream\", ups.Addr()))\n\n\t\tfor {\n\t\t\tresp, err = ups.Connect(ctx, req, opts)\n\n\t\t\tswitch {\n\t\t\tcase errors.Is(err, proxy.ErrCachedClosed): // Remote side closed conn, can only happen with TCP.\n\t\t\t\tcontinue\n\t\t\tcase resp != nil && resp.Truncated && !opts.ForceTCP: // Retry with TCP if truncated\n\t\t\t\topts.ForceTCP = true\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tif resp != nil && (resp.Rcode == dns.RcodeServerFailure || resp.Rcode == dns.RcodeRefused) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif ctx.Err() != nil || err == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcontinue\n\t}\n\n\tif !called {\n\t\treturn dns.RcodeServerFailure, errors.New(\"no destination available\")\n\t}\n\n\tif ctx.Err() != nil {\n\t\treturn dns.RcodeServerFailure, ctx.Err()\n\t} else if err != nil {\n\t\treturn dns.RcodeServerFailure, err\n\t}\n\n\tif !req.Match(resp) {\n\t\tlogger.Warn(\"dns response didn't match\", zap.Stringer(\"data\", resp))\n\n\t\treturn dns.RcodeFormatError, nil\n\t}\n\n\terr = wrt.WriteMsg(resp)\n\tif err != nil {\n\t\t// We can't do much here, but at least log the error.\n\t\tlogger.Warn(\"error writing dns response\", zap.Error(err))\n\t}\n\n\tlogger.Debug(\"dns response\", zap.Stringer(\"data\", resp))\n\n\treturn dns.RcodeSuccess, nil\n}\n\n// SetProxy sets destination dns proxy servers.\nfunc (h *Handler) SetProxy(prxs iter.Seq[*proxy.Proxy]) bool {\n\th.mx.Lock()\n\tdefer h.mx.Unlock()\n\n\tif xiter.Equal(h.dests, prxs) {\n\t\treturn false\n\t}\n\n\th.dests = prxs\n\n\treturn true\n}\n\n// Stop stops and clears dns proxy selector.\nfunc (h *Handler) Stop() { h.SetProxy(xiter.Empty) }\n\n// NewNodeHandler creates a new NodeHandler.\nfunc NewNodeHandler(next plugin.Handler, hostMapper HostMapper, logger *zap.Logger) *NodeHandler {\n\treturn &NodeHandler{next: next, mapper: hostMapper, logger: logger}\n}\n\n// HostMapper is a name to node mapper.\ntype HostMapper interface {\n\tResolveAddr(ctx context.Context, qType uint16, name string) (iter.Seq[netip.Addr], bool)\n}\n\n// NodeHandler try to resolve dns request to a node. If required node is not found, it will move to the next handler.\ntype NodeHandler struct {\n\tnext   plugin.Handler\n\tmapper HostMapper\n\tlogger *zap.Logger\n\n\tenabled atomic.Bool\n}\n\n// Name implements plugin.Handler.\nfunc (h *NodeHandler) Name() string {\n\treturn \"NodeHandler\"\n}\n\n// ServeDNS implements plugin.Handler.\nfunc (h *NodeHandler) ServeDNS(ctx context.Context, wrt dns.ResponseWriter, msg *dns.Msg) (int, error) {\n\tif !h.enabled.Load() {\n\t\treturn h.next.ServeDNS(ctx, wrt, msg)\n\t}\n\n\tidx := slices.IndexFunc(msg.Question, func(q dns.Question) bool { return q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA })\n\tif idx == -1 {\n\t\treturn h.next.ServeDNS(ctx, wrt, msg)\n\t}\n\n\treq := request.Request{W: wrt, Req: msg}\n\n\t// Check if the request is for a node.\n\tresult, ok := h.mapper.ResolveAddr(ctx, req.QType(), req.Name())\n\tif !ok {\n\t\treturn h.next.ServeDNS(ctx, wrt, msg)\n\t}\n\n\tanswers := mapAnswers(result, req.Name())\n\tif len(answers) == 0 {\n\t\treturn h.next.ServeDNS(ctx, wrt, msg)\n\t}\n\n\tresp := new(dns.Msg).SetReply(req.Req)\n\tresp.Authoritative = true\n\tresp.Answer = answers\n\n\terr := wrt.WriteMsg(resp)\n\tif err != nil {\n\t\t// We can't do much here, but at least log the error.\n\t\th.logger.Warn(\"error writing dns response in node handler\", zap.Error(err))\n\t}\n\n\treturn dns.RcodeSuccess, nil\n}\n\nfunc mapAnswers(addrs iter.Seq[netip.Addr], name string) []dns.RR {\n\tvar result []dns.RR\n\n\tfor addr := range addrs {\n\t\tswitch {\n\t\tcase addr.Is4():\n\t\t\tresult = append(result, &dns.A{\n\t\t\t\tHdr: dns.RR_Header{\n\t\t\t\t\tName:   name,\n\t\t\t\t\tRrtype: dns.TypeA,\n\t\t\t\t\tClass:  dns.ClassINET,\n\t\t\t\t\tTtl:    nodeDNSResponseTTL,\n\t\t\t\t},\n\t\t\t\tA: addr.AsSlice(),\n\t\t\t})\n\n\t\tcase addr.Is6():\n\t\t\tresult = append(result, &dns.AAAA{\n\t\t\t\tHdr: dns.RR_Header{\n\t\t\t\t\tName:   name,\n\t\t\t\t\tRrtype: dns.TypeAAAA,\n\t\t\t\t\tClass:  dns.ClassINET,\n\t\t\t\t\tTtl:    nodeDNSResponseTTL,\n\t\t\t\t},\n\t\t\t\tAAAA: addr.AsSlice(),\n\t\t\t})\n\t\t}\n\t}\n\n\treturn result\n}\n\nconst nodeDNSResponseTTL = 10\n\n// SetEnabled sets the handler enabled state.\nfunc (h *NodeHandler) SetEnabled(enabled bool) {\n\th.enabled.Store(enabled)\n}\n\n// NewTCPListener creates a new TCP listener.\nfunc NewTCPListener(network, addr string, control ControlFn) (net.Listener, error) {\n\tnetwork, ok := networkNames[network]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unsupported network: %s\", network)\n\t}\n\n\tlc := net.ListenConfig{Control: control}\n\n\treturn lc.Listen(context.Background(), network, addr)\n}\n\n// NewUDPPacketConn creates a new UDP packet connection.\nfunc NewUDPPacketConn(network, addr string, control ControlFn) (net.PacketConn, error) {\n\tnetwork, ok := networkNames[network]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unsupported network: %s\", network)\n\t}\n\n\tlc := net.ListenConfig{Control: control}\n\n\treturn lc.ListenPacket(context.Background(), network, addr)\n}\n\n// ControlFn is an alias to [net.ListenConfig.Control] function.\ntype ControlFn = func(string, string, syscall.RawConn) error\n\n// MakeControl creates a control function for setting socket options.\nfunc MakeControl(network string, forwardEnabled bool) (ControlFn, error) {\n\tmaxHops := 1\n\n\tif forwardEnabled {\n\t\tmaxHops = 2\n\t}\n\n\tvar options []controlOptions\n\n\tswitch network {\n\tcase \"tcp\", \"tcp4\":\n\t\toptions = []controlOptions{\n\t\t\t{unix.IPPROTO_IP, unix.IP_RECVTTL, maxHops, \"failed to set IP_RECVTTL\"},\n\t\t\t{unix.IPPROTO_TCP, unix.TCP_FASTOPEN, 5, \"failed to set TCP_FASTOPEN\"}, // tcp specific stuff from systemd\n\t\t\t{unix.IPPROTO_TCP, unix.TCP_NODELAY, 1, \"failed to set TCP_NODELAY\"},   // tcp specific stuff from systemd\n\t\t\t{unix.IPPROTO_IP, unix.IP_TTL, maxHops, \"failed to set IP_TTL\"},\n\t\t}\n\tcase \"tcp6\":\n\t\toptions = []controlOptions{\n\t\t\t{unix.IPPROTO_IPV6, unix.IPV6_RECVHOPLIMIT, maxHops, \"failed to set IPV6_RECVHOPLIMIT\"},\n\t\t\t{unix.IPPROTO_TCP, unix.TCP_FASTOPEN, 5, \"failed to set TCP_FASTOPEN\"}, // tcp specific stuff from systemd\n\t\t\t{unix.IPPROTO_TCP, unix.TCP_NODELAY, 1, \"failed to set TCP_NODELAY\"},   // tcp specific stuff from systemd\n\t\t\t{unix.IPPROTO_IPV6, unix.IPV6_UNICAST_HOPS, maxHops, \"failed to set IPV6_UNICAST_HOPS\"},\n\t\t}\n\tcase \"udp\", \"udp4\":\n\t\toptions = []controlOptions{\n\t\t\t{unix.IPPROTO_IP, unix.IP_RECVTTL, maxHops, \"failed to set IP_RECVTTL\"},\n\t\t\t{unix.IPPROTO_IP, unix.IP_TTL, maxHops, \"failed to set IP_TTL\"},\n\t\t}\n\tcase \"udp6\":\n\t\toptions = []controlOptions{\n\t\t\t{unix.IPPROTO_IPV6, unix.IPV6_RECVHOPLIMIT, maxHops, \"failed to set IPV6_RECVHOPLIMIT\"},\n\t\t\t{unix.IPPROTO_IPV6, unix.IPV6_UNICAST_HOPS, maxHops, \"failed to set IPV6_UNICAST_HOPS\"},\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported network: %s\", network)\n\t}\n\n\treturn func(_ string, _ string, c syscall.RawConn) error {\n\t\tvar resErr error\n\n\t\terr := c.Control(func(fd uintptr) {\n\t\t\tfor _, opt := range options {\n\t\t\t\topErr := unix.SetsockoptInt(int(fd), opt.level, opt.opt, opt.val)\n\t\t\t\tif opErr != nil {\n\t\t\t\t\tresErr = fmt.Errorf(opt.errorMessage+\": %w\", opErr)\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed in control call: %w\", err)\n\t\t}\n\n\t\tif resErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to set socket options: %w\", resErr)\n\t\t}\n\n\t\treturn nil\n\t}, nil\n}\n\ntype controlOptions struct {\n\tlevel        int\n\topt          int\n\tval          int\n\terrorMessage string\n}\n\nvar networkNames = map[string]string{\n\t\"tcp\":  \"tcp4\",\n\t\"tcp4\": \"tcp4\",\n\t\"tcp6\": \"tcp6\",\n\t\"udp\":  \"udp4\",\n\t\"udp4\": \"udp4\",\n\t\"udp6\": \"udp6\",\n}\n"
  },
  {
    "path": "internal/pkg/dns/dns_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dns_test\n\nimport (\n\t\"context\"\n\t\"iter\"\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/coredns/coredns/plugin/pkg/proxy\"\n\tdnssrv \"github.com/miekg/dns\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/gen/xtesting/check\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/thejerf/suture/v4\"\n\t\"go.uber.org/goleak\"\n\t\"go.uber.org/zap/zaptest\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/dns\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc TestDNS(t *testing.T) {\n\tt.Cleanup(func() { goleak.VerifyNone(t) })\n\n\ttests := []struct {\n\t\tname         string\n\t\thostname     string\n\t\tnameservers  []string\n\t\texpectedCode int\n\t\terrCheck     check.Check\n\t}{\n\t\t{\n\t\t\tname:         \"success\",\n\t\t\thostname:     \"google.com\",\n\t\t\tnameservers:  []string{\"8.8.8.8\"},\n\t\t\texpectedCode: dnssrv.RcodeSuccess,\n\t\t\terrCheck:     check.NoError(),\n\t\t},\n\t\t{\n\t\t\tname:        \"failure\",\n\t\t\thostname:    \"google-fail.com\",\n\t\t\tnameservers: []string{\"242.242.242.242\"},\n\t\t\terrCheck:    check.ErrorContains(\"i/o timeout\"),\n\t\t},\n\t\t{\n\t\t\tname:         \"empty destinations\",\n\t\t\thostname:     \"google.com\",\n\t\t\tnameservers:  nil,\n\t\t\texpectedCode: dnssrv.RcodeServerFailure,\n\t\t\terrCheck:     check.NoError(),\n\t\t},\n\t\t{\n\t\t\tname:         \"empty destinations but node exists\",\n\t\t\thostname:     \"talos-default-worker-1\",\n\t\t\tnameservers:  nil,\n\t\t\texpectedCode: dnssrv.RcodeSuccess,\n\t\t\terrCheck:     check.NoError(),\n\t\t},\n\t\t{\n\t\t\tname:         \"empty destinations but node doesn't exists\",\n\t\t\thostname:     \"talos-default-worker-2\",\n\t\t\tnameservers:  []string{\"8.8.8.8\"},\n\t\t\texpectedCode: dnssrv.RcodeNameError,\n\t\t\terrCheck:     check.NoError(),\n\t\t},\n\t\t{\n\t\t\t// The first one will return SERVFAIL and the second will return REFUSED. We should try both.\n\t\t\tname:         `should return \"refused\"`,\n\t\t\thostname:     \"dnssec-failed.org\",\n\t\t\tnameservers:  []string{\"1.1.1.1\", \"ns-1098.awsdns-09.org.\"},\n\t\t\texpectedCode: dnssrv.RcodeRefused,\n\t\t\terrCheck:     check.NoError(),\n\t\t},\n\t}\n\n\tfor _, dnsAddr := range []string{\"127.0.0.1:10700\"} {\n\t\tfor _, test := range tests {\n\t\t\tt.Run(dnsAddr+\"/\"+test.name, func(t *testing.T) {\n\t\t\t\tstop := newManager(t, test.nameservers...)\n\t\t\t\tt.Cleanup(stop)\n\n\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\n\t\t\t\tc := dnssrv.Client{\n\t\t\t\t\tTimeout: time.Second,\n\t\t\t\t}\n\n\t\t\t\tr, _, err := c.Exchange(createQuery(test.hostname), dnsAddr)\n\t\t\t\ttest.errCheck(t, err)\n\n\t\t\t\tif r != nil {\n\t\t\t\t\trequire.Equal(t, test.expectedCode, r.Rcode, r)\n\t\t\t\t}\n\n\t\t\t\tt.Logf(\"r: %s\", r)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestDNSEmptyDestinations(t *testing.T) {\n\tt.Cleanup(func() { goleak.VerifyNone(t) })\n\n\tstop := newManager(t)\n\tdefer stop()\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tr, err := dnssrv.Exchange(createQuery(\"google.com\"), \"127.0.0.1:10700\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, dnssrv.RcodeServerFailure, r.Rcode, r)\n\n\tr, err = dnssrv.Exchange(createQuery(\"google.com\"), \"127.0.0.1:10700\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, dnssrv.RcodeServerFailure, r.Rcode, r)\n\n\tstop()\n}\n\nfunc Test_ServeBackground(t *testing.T) {\n\tt.Cleanup(func() { goleak.VerifyNone(t) })\n\n\tm := dns.NewManager(&testReader{}, func(e suture.Event) { t.Log(\"dns-runners event:\", e) }, zaptest.NewLogger(t))\n\n\tm.ServeBackground(t.Context())\n\n\t// should not panic since ServeBackground is called with the same context\n\tm.ServeBackground(t.Context())\n\n\t// should panic since ServeBackground is called with a different context\n\trequire.Panics(t, func() { m.ServeBackground(context.TODO()) }) //nolint:usetesting\n\n\tfor _, err := range m.RunAll(slices.Values([]dns.AddressPair{\n\t\t{Network: \"udp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10700\")},\n\t\t{Network: \"udp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10701\")},\n\t}), false) {\n\t\trequire.NoError(t, err)\n\t}\n\n\trequire.NoError(t, m.ClearAll(false))\n}\n\nfunc newManager(t *testing.T, nameservers ...string) func() {\n\tm := dns.NewManager(\n\t\t&testReader{},\n\t\tfunc(e suture.Event) { t.Log(\"dns-runners event:\", e) },\n\t\tzaptest.NewLogger(t),\n\t)\n\n\tm.AllowNodeResolving(true)\n\n\tt.Cleanup(func() {\n\t\tif err := m.ClearAll(false); err != nil {\n\t\t\tt.Logf(\"error stopping dns runners: %v\", err)\n\t\t}\n\t})\n\n\tpxs := xslices.Map(nameservers, func(ns string) *proxy.Proxy {\n\t\tp := proxy.NewProxy(ns, net.JoinHostPort(ns, \"53\"), \"dns\")\n\t\tp.Start(500 * time.Millisecond)\n\n\t\treturn p\n\t})\n\n\tt.Cleanup(func() {\n\t\tfor _, p := range pxs {\n\t\t\tp.Close() // We had to manually add this method to the coredns Proxy type.\n\t\t}\n\t})\n\n\tctx, cancel := context.WithCancel(context.Background()) //nolint:usetesting\n\tt.Cleanup(cancel)\n\n\tm.SetUpstreams(slices.Values(pxs))\n\n\tm.ServeBackground(ctx)\n\tm.ServeBackground(ctx)\n\n\tfor _, err := range m.RunAll(slices.Values([]dns.AddressPair{\n\t\t{Network: \"udp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10700\")},\n\t\t{Network: \"udp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10701\")},\n\t\t{Network: \"tcp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10700\")},\n\t}), false) {\n\t\tif err != nil && strings.Contains(err.Error(), \"failed to set TCP_FASTOPEN\") {\n\t\t\tcontinue\n\t\t}\n\n\t\trequire.NoError(t, err)\n\t}\n\n\tfor _, err := range m.RunAll(slices.Values([]dns.AddressPair{\n\t\t{Network: \"udp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10700\")},\n\t\t{Network: \"tcp\", Addr: netip.MustParseAddrPort(\"127.0.0.1:10700\")},\n\t}), false) {\n\t\tif err != nil && strings.Contains(err.Error(), \"failed to set TCP_FASTOPEN\") {\n\t\t\tcontinue\n\t\t}\n\n\t\trequire.NoError(t, err)\n\t}\n\n\treturn func() {\n\t\tif err := m.ClearAll(false); err != nil {\n\t\t\tt.Logf(\"error stopping dns runners: %v\", err)\n\t\t}\n\t}\n}\n\nfunc createQuery(name string) *dnssrv.Msg {\n\treturn &dnssrv.Msg{\n\t\tMsgHdr: dnssrv.MsgHdr{\n\t\t\tId:               dnssrv.Id(),\n\t\t\tRecursionDesired: true,\n\t\t},\n\t\tQuestion: []dnssrv.Question{\n\t\t\t{\n\t\t\t\tName:   dnssrv.Fqdn(name),\n\t\t\t\tQtype:  dnssrv.TypeA,\n\t\t\t\tQclass: dnssrv.ClassINET,\n\t\t\t},\n\t\t},\n\t}\n}\n\ntype testReader struct{}\n\nfunc (r *testReader) ReadMembers(context.Context) (iter.Seq[*cluster.Member], error) {\n\tnamesToAddresses := map[string][]netip.Addr{\n\t\t\"talos-default-controlplane-1\": {netip.MustParseAddr(\"172.20.0.2\")},\n\t\t\"talos-default-worker-1\":       {netip.MustParseAddr(\"172.20.0.3\")},\n\t}\n\n\tresult := maps.ToSlice(namesToAddresses, func(k string, v []netip.Addr) *cluster.Member {\n\t\tresult := cluster.NewMember(cluster.NamespaceName, k)\n\n\t\tresult.TypedSpec().Addresses = v\n\n\t\treturn result\n\t})\n\n\treturn slices.Values(result), nil\n}\n"
  },
  {
    "path": "internal/pkg/dns/manager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dns\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"iter\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/coredns/coredns/plugin/pkg/proxy\"\n\t\"github.com/hashicorp/go-multierror\"\n\tdnssrv \"github.com/miekg/dns\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/thejerf/suture/v4\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// ErrCreatingRunner is an error that occurs when creating a runner.\nvar ErrCreatingRunner = errors.New(\"error creating runner\")\n\n// Manager manages DNS runners.\ntype Manager struct {\n\toriginalCtx  context.Context //nolint:containedctx\n\thandler      *Handler\n\tnodeHandler  *NodeHandler\n\trootHandler  *Cache\n\ts            *suture.Supervisor\n\tsupervisorCh <-chan error\n\tlogger       *zap.Logger\n\trunners      map[AddressPair]suture.ServiceToken\n}\n\n// NewManager creates a new manager.\nfunc NewManager(mr MemberReader, hook suture.EventHook, logger *zap.Logger) *Manager {\n\thandler := NewHandler(logger)\n\tnodeHandler := NewNodeHandler(handler, &addrResolver{mr: mr}, logger)\n\trootHandler := NewCache(nodeHandler, logger)\n\n\tm := &Manager{\n\t\thandler:     handler,\n\t\tnodeHandler: nodeHandler,\n\t\trootHandler: rootHandler,\n\t\ts:           suture.New(\"dns-resolve-cache-runners\", suture.Spec{EventHook: hook}),\n\t\tlogger:      logger,\n\t\trunners:     map[AddressPair]suture.ServiceToken{},\n\t}\n\n\treturn m\n}\n\n// ServeBackground starts the manager in the background. It panics if the manager is not initialized or if it's called\n// more than once.\nfunc (m *Manager) ServeBackground(ctx context.Context) {\n\tswitch {\n\tcase m.originalCtx == nil:\n\t\tm.originalCtx = ctx\n\tcase m.originalCtx != ctx:\n\t\tpanic(\"Manager.ServeBackground is called with a different context\")\n\tcase m.originalCtx == ctx:\n\t\treturn\n\t}\n\n\tm.supervisorCh = m.s.ServeBackground(ctx)\n}\n\n// AddressPair represents a network and address with port.\ntype AddressPair struct {\n\tNetwork string\n\tAddr    netip.AddrPort\n}\n\n// String returns a string representation of the address pair.\nfunc (a AddressPair) String() string { return \"Network: \" + a.Network + \", Addr: \" + a.Addr.String() }\n\n// RunAll updates and run the runners managed by the manager. It returns an iterator which yields the address pairs for\n// all running and attempted ro run configurations. It's mandatory to range over the iterator to ensure all runners are updated.\nfunc (m *Manager) RunAll(pairs iter.Seq[AddressPair], forwardEnabled bool) iter.Seq2[RunResult, error] {\n\treturn func(yield func(RunResult, error) bool) {\n\t\tpreserve := make(map[AddressPair]struct{}, len(m.runners))\n\n\t\tfor cfg := range pairs {\n\t\t\tpreserve[cfg] = struct{}{}\n\n\t\t\tif _, ok := m.runners[cfg]; ok {\n\t\t\t\tif !yield(makeResult(cfg, StatusRunning), nil) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\topts, err := newDNSRunnerOpts(cfg, m.rootHandler, forwardEnabled)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"%w: %w\", ErrCreatingRunner, err)\n\t\t\t} else {\n\t\t\t\tm.runners[cfg] = m.s.Add(NewRunner(opts, m.logger))\n\t\t\t}\n\n\t\t\tif !yield(makeResult(cfg, StatusNew), err) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tfor cfg, token := range m.runners {\n\t\t\tif _, ok := preserve[cfg]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := m.s.RemoveAndWait(token, 0)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"error removing runner: %w\", err)\n\t\t\t}\n\n\t\t\tif !yield(makeResult(cfg, StatusRemoved), err) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdelete(m.runners, cfg)\n\t\t}\n\t}\n}\n\nfunc makeResult(cfg AddressPair, s Status) RunResult { return RunResult{AddressPair: cfg, Status: s} }\n\n// AllowNodeResolving enables or disables the node resolving feature.\nfunc (m *Manager) AllowNodeResolving(enabled bool) { m.nodeHandler.SetEnabled(enabled) }\n\n// SetUpstreams sets the upstreams for the DNS handler. It returns true if the upstreams were updated, false otherwise.\nfunc (m *Manager) SetUpstreams(prxs iter.Seq[*proxy.Proxy]) bool {\n\tif !m.handler.SetProxy(prxs) {\n\t\treturn false\n\t}\n\n\t// Upstreams updated, clear cache to prevent DNS poisoning.\n\tm.rootHandler.Clear()\n\n\treturn true\n}\n\n// ClearAll stops and removes all runners. Returns all errors if any runner failed to properly stop.\nfunc (m *Manager) ClearAll(dry bool) error {\n\tif dry {\n\t\treturn nil\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor _, err := range m.clearAll() {\n\t\tif err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t}\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\nfunc (m *Manager) clearAll() iter.Seq2[AddressPair, error] {\n\treturn func(yield func(AddressPair, error) bool) {\n\t\tif len(m.runners) == 0 {\n\t\t\treturn\n\t\t}\n\n\t\tdefer m.handler.Stop()\n\n\t\tfor runData, token := range m.runners {\n\t\t\terr := m.s.RemoveAndWait(token, 0)\n\t\t\tif err != nil && !errors.Is(err, suture.ErrSupervisorNotRunning) && !errors.Is(err, suture.ErrTimeout) {\n\t\t\t\terr = fmt.Errorf(\"error removing runner: %w\", err)\n\t\t\t} else {\n\t\t\t\terr = nil\n\t\t\t}\n\n\t\t\tif !yield(runData, err) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdelete(m.runners, runData)\n\t\t}\n\t}\n}\n\n// Done reports if superwisor finished execution.\nfunc (m *Manager) Done() <-chan error {\n\treturn m.supervisorCh\n}\n\ntype addrResolver struct {\n\tmr MemberReader\n}\n\nfunc (s *addrResolver) ResolveAddr(ctx context.Context, qType uint16, name string) (iter.Seq[netip.Addr], bool) {\n\tname = strings.TrimRight(name, \".\")\n\n\titems, err := s.mr.ReadMembers(ctx)\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\n\tfound, ok := xiter.Find(func(res *cluster.Member) bool {\n\t\treturn fqdnMatch(name, res.TypedSpec().Hostname) || fqdnMatch(name, res.Metadata().ID())\n\t}, items)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\treturn xiter.Filter(\n\t\tfunc(addr netip.Addr) bool {\n\t\t\treturn (qType == dnssrv.TypeA && addr.Is4()) || (qType == dnssrv.TypeAAAA && addr.Is6())\n\t\t},\n\t\tslices.Values(found.TypedSpec().Addresses),\n\t), true\n}\n\nfunc fqdnMatch(what, where string) bool {\n\twhat = strings.TrimRight(what, \".\")\n\twhere = strings.TrimRight(where, \".\")\n\n\tif what == where {\n\t\treturn true\n\t}\n\n\tfirst, _, found := strings.Cut(where, \".\")\n\tif !found {\n\t\treturn false\n\t}\n\n\treturn what == first\n}\n\n// MemberReader is an interface to read members.\ntype MemberReader interface {\n\tReadMembers(ctx context.Context) (iter.Seq[*cluster.Member], error)\n}\n\nfunc newDNSRunnerOpts(cfg AddressPair, rootHandler dnssrv.Handler, forwardEnabled bool) (RunnerOptions, error) {\n\tif cfg.Addr.Addr().Is6() && !strings.HasSuffix(cfg.Network, \"6\") {\n\t\tcfg.Network += \"6\"\n\t}\n\n\tvar serverOpts RunnerOptions\n\n\tcontrolFn, ctrlErr := MakeControl(cfg.Network, forwardEnabled)\n\tif ctrlErr != nil {\n\t\treturn serverOpts, fmt.Errorf(\"error creating %q control function: %w\", cfg.Network, ctrlErr)\n\t}\n\n\tswitch cfg.Network {\n\tcase \"udp\", \"udp6\":\n\t\tpacketConn, err := NewUDPPacketConn(cfg.Network, cfg.Addr.String(), controlFn)\n\t\tif err != nil {\n\t\t\treturn serverOpts, fmt.Errorf(\"error creating %q packet conn: %w\", cfg.Network, err)\n\t\t}\n\n\t\tserverOpts = RunnerOptions{\n\t\t\tPacketConn: packetConn,\n\t\t\tHandler:    rootHandler,\n\t\t}\n\n\tcase \"tcp\", \"tcp6\":\n\t\tlistener, err := NewTCPListener(cfg.Network, cfg.Addr.String(), controlFn)\n\t\tif err != nil {\n\t\t\treturn serverOpts, fmt.Errorf(\"error creating %q listener: %w\", cfg.Network, err)\n\t\t}\n\n\t\tserverOpts = RunnerOptions{\n\t\t\tListener:      listener,\n\t\t\tHandler:       rootHandler,\n\t\t\tReadTimeout:   3 * time.Second,\n\t\t\tWriteTimeout:  5 * time.Second,\n\t\t\tIdleTimeout:   func() time.Duration { return 10 * time.Second },\n\t\t\tMaxTCPQueries: -1,\n\t\t}\n\t}\n\n\treturn serverOpts, nil\n}\n\n// RunResult represents the result of a RunAll iteration.\ntype RunResult struct {\n\tAddressPair\n\n\tStatus Status\n}\n\n// Status represents the status of a runner.\ntype Status int\n\nconst (\n\t// StatusNew represents a new runner.\n\tStatusNew Status = iota\n\t// StatusRunning represents a already running runner.\n\tStatusRunning\n\t// StatusRemoved represents a removed runner.\n\tStatusRemoved\n)\n"
  },
  {
    "path": "internal/pkg/dns/runnner.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dns\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/miekg/dns\"\n\t\"go.uber.org/zap\"\n)\n\n// RunnerOptions is a [Runner] options.\ntype RunnerOptions struct {\n\tListener      net.Listener\n\tPacketConn    net.PacketConn\n\tHandler       dns.Handler\n\tReadTimeout   time.Duration\n\tWriteTimeout  time.Duration\n\tIdleTimeout   func() time.Duration\n\tMaxTCPQueries int\n}\n\n// NewRunner creates a new [Runner].\nfunc NewRunner(opts RunnerOptions, l *zap.Logger) *Runner {\n\treturn &Runner{\n\t\tsrv: &dns.Server{\n\t\t\tListener:      opts.Listener,\n\t\t\tPacketConn:    opts.PacketConn,\n\t\t\tHandler:       opts.Handler,\n\t\t\tUDPSize:       dns.DefaultMsgSize, // 4096 since default is [dns.MinMsgSize] = 512 bytes, which is too small.\n\t\t\tReadTimeout:   opts.ReadTimeout,\n\t\t\tWriteTimeout:  opts.WriteTimeout,\n\t\t\tIdleTimeout:   opts.IdleTimeout,\n\t\t\tMaxTCPQueries: opts.MaxTCPQueries,\n\t\t},\n\t\tlogger: l,\n\t}\n}\n\n// Runner is a DNS server runner.\ntype Runner struct {\n\tsrv    *dns.Server\n\tlogger *zap.Logger\n}\n\n// Serve starts the DNS server. Implements [suture.Service] interface.\nfunc (r *Runner) Serve(ctx context.Context) error {\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- r.srv.ActivateAndServe()\n\t}()\n\n\tselect {\n\tcase err := <-errCh:\n\t\treturn err\n\tcase <-ctx.Done():\n\t}\n\n\tr.close()\n\n\tselect {\n\tcase err := <-errCh:\n\t\treturn err\n\tcase <-time.After(time.Second):\n\t\treturn errors.New(\"timeout waiting for server to close\")\n\t}\n}\n\nfunc (r *Runner) close() {\n\tl := r.logger\n\n\tif r.srv.Listener != nil {\n\t\tl = l.With(zap.String(\"net\", \"tcp\"), zap.String(\"local_addr\", r.srv.Listener.Addr().String()))\n\t} else if r.srv.PacketConn != nil {\n\t\tl = l.With(zap.String(\"net\", \"udp\"), zap.String(\"local_addr\", r.srv.PacketConn.LocalAddr().String()))\n\t}\n\n\tcloser := io.Closer(r.srv.Listener)\n\tif closer == nil {\n\t\tcloser = r.srv.PacketConn\n\t}\n\n\tif closer != nil {\n\t\tif err := closer.Close(); err != nil {\n\t\t\tl.Error(\"error closing dns server listener\", zap.Error(err))\n\t\t} else {\n\t\t\tl.Debug(\"dns server listener closed\")\n\t\t}\n\t}\n\n\tsCtx, sCancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer sCancel()\n\n\terr := r.srv.ShutdownContext(sCtx)\n\tif err != nil && !errors.Is(err, net.ErrClosed) {\n\t\tl.Error(\"error shutting down dns server\", zap.Error(err))\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "internal/pkg/efivarfs/README.md",
    "content": "# efivarfs\n\nThis package was copied from the upstream repository at [efivarfs](https://github.com/monogon/monogon/tree/main/osbase/efivarfs)\n\nThere were minimal changes done to comply with the linter and gofmt rules.\n\nThe major change was to remove the EFI variable file immutable attribute before writing to it.\n"
  },
  {
    "path": "internal/pkg/efivarfs/boot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage efivarfs\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n)\n\n// LoadOptionCategory defines the category of a load option. This is used to\n// differentiate between different types of boot options.\ntype LoadOptionCategory uint8\n\nconst (\n\t// LoadOptionCategoryBoot is the default category for boot entries.\n\tLoadOptionCategoryBoot LoadOptionCategory = 0x0\n\t// LoadOptionCategoryApp is the category for boot entries that are\n\t// not booted as part of the normal boot order, but are only launched via menu or hotkey.\n\t// This category is optional for bootloaders to support, before creating\n\t// new boot entries of this category firmware support needs to be\n\t// confirmed.\n\tLoadOptionCategoryApp LoadOptionCategory = 0x1\n)\n\n// LoadOption contains information on a payload to be loaded by EFI.\ntype LoadOption struct {\n\t// Human-readable description of what this load option loads.\n\t// This is what's being shown by the firmware when selecting a boot option.\n\tDescription string\n\t// If set, firmware will skip this load option when it is in BootOrder.\n\t// It is unspecificed whether this prevents the user from booting the entry\n\t// manually.\n\tInactive bool\n\t// If set, this load option will not be shown in any menu for load option\n\t// selection. This does not affect other functionality.\n\tHidden bool\n\t// Category contains the category of the load entry. The selected category\n\t// affects various firmware behaviors, see the individual value\n\t// descriptions for more information.\n\tCategory LoadOptionCategory\n\t// Path to the UEFI PE executable to execute when this load option is being\n\t// loaded.\n\tFilePath DevicePath\n\t// ExtraPaths contains additional device paths with vendor-specific\n\t// behavior. Can generally be left empty.\n\tExtraPaths []DevicePath\n\t// OptionalData gets passed as an argument to the executed PE executable.\n\t// If zero-length a NULL value is passed to the executable.\n\tOptionalData []byte\n}\n\n// Marshal encodes a LoadOption into a binary EFI_LOAD_OPTION.\nfunc (e *LoadOption) Marshal() ([]byte, error) {\n\tvar (\n\t\tdata  []byte\n\t\tattrs uint32\n\t)\n\n\tattrs |= (uint32(e.Category) & 0x1f) << 8\n\tif e.Hidden {\n\t\tattrs |= 0x08\n\t}\n\n\tif !e.Inactive {\n\t\tattrs |= 0x01\n\t}\n\n\tdata = binary.LittleEndian.AppendUint32(data, attrs)\n\n\tfilePathRaw, err := e.FilePath.Marshal()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed marshaling FilePath: %w\", err)\n\t}\n\n\tfor _, ep := range e.ExtraPaths {\n\t\tepRaw, err := ep.Marshal()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed marshaling ExtraPath: %w\", err)\n\t\t}\n\n\t\tfilePathRaw = append(filePathRaw, epRaw...)\n\t}\n\n\tif len(filePathRaw) > math.MaxUint16 {\n\t\treturn nil, fmt.Errorf(\"failed marshaling FilePath/ExtraPath: value too big (%d)\", len(filePathRaw))\n\t}\n\n\tdata = binary.LittleEndian.AppendUint16(data, uint16(len(filePathRaw)))\n\n\tif strings.IndexByte(e.Description, 0x00) != -1 {\n\t\treturn nil, fmt.Errorf(\"failed to encode Description: contains invalid null bytes\")\n\t}\n\n\tencodedDesc, err := Encoding.NewEncoder().Bytes([]byte(e.Description))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode Description: %w\", err)\n\t}\n\n\tdata = append(data, encodedDesc...)\n\tdata = append(data, 0x00, 0x00) // Final UTF-16/UCS-2 null code\n\tdata = append(data, filePathRaw...)\n\tdata = append(data, e.OptionalData...)\n\n\treturn data, nil\n}\n\n// UnmarshalLoadOption decodes a binary EFI_LOAD_OPTION into a LoadOption.\nfunc UnmarshalLoadOption(data []byte) (*LoadOption, error) {\n\tif len(data) < 6 {\n\t\treturn nil, fmt.Errorf(\"invalid load option: minimum 6 bytes are required, got %d\", len(data))\n\t}\n\n\tvar opt LoadOption\n\n\tattrs := binary.LittleEndian.Uint32(data[:4])\n\topt.Category = LoadOptionCategory((attrs >> 8) & 0x1f)\n\topt.Hidden = attrs&0x08 != 0\n\topt.Inactive = attrs&0x01 == 0\n\tlenPath := binary.LittleEndian.Uint16(data[4:6])\n\t// Search for UTF-16 null code\n\tnullIdx := bytes.Index(data[6:], []byte{0x00, 0x00})\n\tif nullIdx == -1 {\n\t\treturn nil, errors.New(\"no null code point marking end of Description found\")\n\t}\n\n\tdescriptionEnd := 6 + nullIdx + 1\n\tdescriptionRaw := data[6:descriptionEnd]\n\n\tdescription, err := Encoding.NewDecoder().Bytes(descriptionRaw)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding UTF-16 in Description: %w\", err)\n\t}\n\n\tdescriptionEnd += 2 // 2 null bytes terminating UTF-16 string\n\topt.Description = string(description)\n\n\tif descriptionEnd+int(lenPath) > len(data) {\n\t\treturn nil, fmt.Errorf(\"declared length of FilePath (%d) overruns available data (%d)\", lenPath, len(data)-descriptionEnd)\n\t}\n\n\tfilePathData := data[descriptionEnd : descriptionEnd+int(lenPath)]\n\n\topt.FilePath, filePathData, err = UnmarshalDevicePath(filePathData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed unmarshaling FilePath: %w\", err)\n\t}\n\n\tfor len(filePathData) > 0 {\n\t\tvar extraPath DevicePath\n\n\t\textraPath, filePathData, err = UnmarshalDevicePath(filePathData)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed unmarshaling ExtraPath: %w\", err)\n\t\t}\n\n\t\topt.ExtraPaths = append(opt.ExtraPaths, extraPath)\n\t}\n\n\tif descriptionEnd+int(lenPath) < len(data) {\n\t\topt.OptionalData = data[descriptionEnd+int(lenPath):]\n\t}\n\n\treturn &opt, nil\n}\n\n// BootOrder represents the contents of the BootOrder EFI variable.\ntype BootOrder []uint16\n\n// Marshal generates the binary representation of a BootOrder.\nfunc (t *BootOrder) Marshal() []byte {\n\tvar out []byte\n\n\tfor _, v := range *t {\n\t\tout = binary.LittleEndian.AppendUint16(out, v)\n\t}\n\n\treturn out\n}\n\n// UnmarshalBootOrder loads a BootOrder from its binary representation.\nfunc UnmarshalBootOrder(d []byte) (BootOrder, error) {\n\tif len(d)%2 != 0 {\n\t\treturn nil, fmt.Errorf(\"invalid length: %v bytes\", len(d))\n\t}\n\n\tl := len(d) / 2\n\n\tout := make(BootOrder, l)\n\tfor i := range l {\n\t\tout[i] = binary.LittleEndian.Uint16(d[i*2:])\n\t}\n\n\treturn out, nil\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/boot_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage efivarfs_test\n\nimport (\n\t\"encoding/hex\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n)\n\n// Generated with old working marshaler and manually double-checked\n//\n// nolint:errcheck\nvar ref, _ = hex.DecodeString(\n\t\"010000004a004500780061006d0070006c006500000004012a00010000000\" +\n\t\t\"500000000000000080000000000000014b8a76bad9dd11180b400c04fd430\" +\n\t\t\"c8020204041c005c0074006500730074005c0061002e00650066006900000\" +\n\t\t\"07fff0400\",\n)\n\nfunc TestEncoding(t *testing.T) {\n\topt := efivarfs.LoadOption{\n\t\tDescription: \"Example\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\t&efivarfs.HardDrivePath{\n\t\t\t\tPartitionNumber:     1,\n\t\t\t\tPartitionStartBlock: 5,\n\t\t\t\tPartitionSizeBlocks: 8,\n\t\t\t\tPartitionMatch: efivarfs.PartitionGPT{\n\t\t\t\t\tPartitionUUID: uuid.NameSpaceX500,\n\t\t\t\t},\n\t\t\t},\n\t\t\tefivarfs.FilePath(\"/test/a.efi\"),\n\t\t},\n\t}\n\n\tgot, err := opt.Marshal()\n\trequire.NoError(t, err, \"failed to marshal LoadOption\")\n\n\trequire.Equal(t, ref, got)\n\n\tgot2, err := efivarfs.UnmarshalLoadOption(got)\n\trequire.NoError(t, err, \"failed to unmarshal LoadOption\")\n\n\trequire.Equal(t, &opt, got2, \"unmarshaled LoadOption does not match original\")\n}\n\nfunc FuzzDecode(f *testing.F) {\n\tf.Add(ref)\n\tf.Fuzz(func(t *testing.T, a []byte) {\n\t\t// Just try to see if it crashes\n\t\t_, _ = efivarfs.UnmarshalLoadOption(a) //nolint:errcheck\n\t})\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/devicepath.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage efivarfs\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/msguid\"\n)\n\n// DevicePath represents a path consisting of one or more elements to an\n// entity implementing an EFI protocol. It's very broadly used inside EFI\n// for representing all sorts of abstract paths. In the context of this\n// package it is used to represent paths to EFI loaders.\n// See https://uefi.org/specs/UEFI/2.10/10_Protocols_Device_Path_Protocol.html\n// for more information.\ntype DevicePath []DevicePathElem\n\n// DevicePathElem is a common interface for all UEFI device path elements.\ntype DevicePathElem interface {\n\ttyp() uint8\n\tsubType() uint8\n\tdata() ([]byte, error)\n}\n\ntype pathElemUnmarshalFunc func([]byte) (DevicePathElem, error)\n\n// PartitionMBR matches a drive or partition formatted with legacy MBR\n// (Master Boot Record).\ntype PartitionMBR struct {\n\t// DiskSignature contains a 4-byte signature identifying the drive, located\n\t// just after the 440 bytes of boot sector loading code.\n\t// Note that since MBR does not have per-partition signatures, this is\n\t// combined with PartitionNumber to select a partition.\n\tDiskSignature [4]byte\n}\n\nfunc (p PartitionMBR) partitionSignature() (sig [16]byte) {\n\tcopy(sig[:4], p.DiskSignature[:])\n\n\treturn sig\n}\n\nfunc (p PartitionMBR) partitionFormat() uint8 {\n\treturn 0x01\n}\n\nfunc (p PartitionMBR) signatureType() uint8 {\n\treturn 0x01\n}\n\n// PartitionGPT matches a partition on a drive formatted with GPT.\ntype PartitionGPT struct {\n\t// UUID of the partition to be matched. Conversion into mixed-endian format\n\t// is taken care of, a standard big-endian UUID can be put in here.\n\tPartitionUUID uuid.UUID\n}\n\nfunc (p PartitionGPT) partitionSignature() [16]byte {\n\treturn msguid.From(p.PartitionUUID)\n}\n\nfunc (p PartitionGPT) partitionFormat() uint8 {\n\treturn 0x02\n}\n\nfunc (p PartitionGPT) signatureType() uint8 {\n\treturn 0x02\n}\n\n// PartitionUnknown is being used to represent unknown partitioning schemas or\n// combinations of PartitionFormat/SignatureType. It contains raw uninterpreted\n// data.\ntype PartitionUnknown struct {\n\tPartitionSignature [16]byte\n\tPartitionFormat    uint8\n\tSignatureType      uint8\n}\n\nfunc (p PartitionUnknown) partitionSignature() [16]byte {\n\treturn p.PartitionSignature\n}\n\nfunc (p PartitionUnknown) partitionFormat() uint8 {\n\treturn p.PartitionFormat\n}\n\nfunc (p PartitionUnknown) signatureType() uint8 {\n\treturn p.SignatureType\n}\n\n// PartitionMatch is an interface that defines methods for matching\n// partitions on drives or filepaths.\ntype PartitionMatch interface {\n\tpartitionSignature() [16]byte\n\tpartitionFormat() uint8\n\tsignatureType() uint8\n}\n\n// HardDrivePath matches whole drives or partitions on GPT/MBR formatted\n// drives.\ntype HardDrivePath struct {\n\t// Partition number, starting at 1. If zero or unset, the whole drive is\n\t// selected.\n\tPartitionNumber uint32\n\t// Block address at which the partition starts. Not used for matching\n\t// partitions in EDK2.\n\tPartitionStartBlock uint64\n\t// Number of blocks occupied by the partition starting from the\n\t// PartitionStartBlock. Not used for matching partitions in EDK2.\n\tPartitionSizeBlocks uint64\n\t// PartitionMatch is used to match drive or partition signatures.\n\t// Use PartitionMBR and PartitionGPT types here.\n\tPartitionMatch PartitionMatch\n}\n\nfunc (h *HardDrivePath) typ() uint8 {\n\treturn 4\n}\n\nfunc (h *HardDrivePath) subType() uint8 {\n\treturn 1\n}\n\nfunc (h *HardDrivePath) data() ([]byte, error) {\n\tout := make([]byte, 38)\n\tle := binary.LittleEndian\n\tle.PutUint32(out[0:4], h.PartitionNumber)\n\tle.PutUint64(out[4:12], h.PartitionStartBlock)\n\tle.PutUint64(out[12:20], h.PartitionSizeBlocks)\n\n\tif h.PartitionMatch == nil {\n\t\treturn nil, errors.New(\"PartitionMatch needs to be set\")\n\t}\n\n\tsig := h.PartitionMatch.partitionSignature()\n\tcopy(out[20:36], sig[:])\n\tout[36] = h.PartitionMatch.partitionFormat()\n\tout[37] = h.PartitionMatch.signatureType()\n\n\treturn out, nil\n}\n\nfunc unmarshalHardDrivePath(data []byte) (DevicePathElem, error) {\n\tvar h HardDrivePath\n\n\tif len(data) != 38 {\n\t\treturn nil, fmt.Errorf(\"invalid HardDrivePath element, expected 38 bytes, got %d\", len(data))\n\t}\n\n\tle := binary.LittleEndian\n\th.PartitionNumber = le.Uint32(data[0:4])\n\th.PartitionStartBlock = le.Uint64(data[4:12])\n\th.PartitionSizeBlocks = le.Uint64(data[12:20])\n\tpartitionFormat := data[36]\n\tsignatureType := data[37]\n\n\tvar rawSig [16]byte\n\tcopy(rawSig[:], data[20:36])\n\n\tswitch {\n\tcase partitionFormat == 1 && signatureType == 1:\n\t\t// MBR\n\t\tvar mbr PartitionMBR\n\t\tcopy(mbr.DiskSignature[:], rawSig[:4])\n\t\th.PartitionMatch = mbr\n\tcase partitionFormat == 2 && signatureType == 2:\n\t\t// GPT\n\t\th.PartitionMatch = PartitionGPT{\n\t\t\tPartitionUUID: msguid.To(rawSig),\n\t\t}\n\tdefault:\n\t\t// Unknown\n\t\th.PartitionMatch = PartitionUnknown{\n\t\t\tPartitionSignature: rawSig,\n\t\t\tPartitionFormat:    partitionFormat,\n\t\t\tSignatureType:      signatureType,\n\t\t}\n\t}\n\n\treturn &h, nil\n}\n\n// FilePath contains a backslash-separated path or part of a path to a file on\n// a filesystem.\ntype FilePath string\n\nfunc (f FilePath) typ() uint8 {\n\treturn 4\n}\n\nfunc (f FilePath) subType() uint8 {\n\treturn 4\n}\n\nfunc (f FilePath) data() ([]byte, error) {\n\tif strings.IndexByte(string(f), 0x00) != -1 {\n\t\treturn nil, fmt.Errorf(\"contains invalid null bytes\")\n\t}\n\n\twithBackslashes := bytes.ReplaceAll([]byte(f), []byte(`/`), []byte(`\\`))\n\n\tout, err := Encoding.NewEncoder().Bytes(withBackslashes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode FilePath to UTF-16: %w\", err)\n\t}\n\n\treturn append(out, 0x00, 0x00), nil\n}\n\nfunc unmarshalFilePath(data []byte) (DevicePathElem, error) {\n\tif len(data) < 2 {\n\t\treturn nil, fmt.Errorf(\"FilePath must be at least 2 bytes because of UTF-16 null terminator\")\n\t}\n\n\tout, err := Encoding.NewDecoder().Bytes(data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding FilePath UTF-16 string: %w\", err)\n\t}\n\n\tnullIdx := bytes.IndexByte(out, 0x00)\n\tif nullIdx != len(out)-1 {\n\t\treturn nil, fmt.Errorf(\"FilePath not properly null-terminated\")\n\t}\n\n\twithoutBackslashes := strings.ReplaceAll(string(out[:len(out)-1]), `\\`, `/`)\n\n\treturn FilePath(withoutBackslashes), nil\n}\n\n// Map key contains type and subtype.\nvar pathElementUnmarshalMap = map[[2]byte]pathElemUnmarshalFunc{\n\t{4, 1}: unmarshalHardDrivePath,\n\t{4, 4}: unmarshalFilePath,\n}\n\n// UnknownPath is a generic structure for all types of path elements not\n// understood by this library. The UEFI-specified set of path element\n// types is vast and mostly unused, this generic type allows for parsing as\n// well as pass-through of not-understood path elements.\ntype UnknownPath struct {\n\tTypeVal    uint8\n\tSubTypeVal uint8\n\tDataVal    []byte\n}\n\nfunc (u UnknownPath) typ() uint8 {\n\treturn u.TypeVal\n}\n\nfunc (u UnknownPath) subType() uint8 {\n\treturn u.SubTypeVal\n}\n\nfunc (u UnknownPath) data() ([]byte, error) {\n\treturn u.DataVal, nil\n}\n\n// Marshal encodes the device path in binary form.\nfunc (d DevicePath) Marshal() ([]byte, error) {\n\tvar buf []byte //nolint:prealloc\n\tfor _, p := range d {\n\t\tbuf = append(buf, p.typ(), p.subType())\n\n\t\telemBuf, err := p.data()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed marshaling path element: %w\", err)\n\t\t}\n\t\t// 4 is size of header which is included in length field\n\t\tif len(elemBuf)+4 > math.MaxUint16 {\n\t\t\treturn nil, fmt.Errorf(\"path element payload over maximum size\")\n\t\t}\n\n\t\tbuf = binary.LittleEndian.AppendUint16(buf, uint16(len(elemBuf)+4))\n\t\tbuf = append(buf, elemBuf...)\n\t}\n\t// End of device path (Type 0x7f, SubType 0xFF)\n\tbuf = append(buf, 0x7f, 0xff, 0x04, 0x00)\n\n\treturn buf, nil\n}\n\n// UnmarshalDevicePath parses a binary device path until it encounters an end\n// device path structure. It returns that device path (excluding the final end\n// device path marker) as well as all all data following the end marker.\n//\n//nolint:gocyclo\nfunc UnmarshalDevicePath(data []byte) (DevicePath, []byte, error) {\n\trest := data\n\n\tvar p DevicePath\n\n\tfor {\n\t\tif len(rest) < 4 {\n\t\t\tif len(rest) != 0 {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"dangling bytes at the end of device path: %x\", rest)\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tt := rest[0]\n\t\tsubT := rest[1]\n\n\t\tdataLen := binary.LittleEndian.Uint16(rest[2:4])\n\t\tif int(dataLen) > len(rest) {\n\t\t\treturn nil, nil, fmt.Errorf(\"path element larger than rest of buffer: %d > %d\", dataLen, len(rest))\n\t\t}\n\n\t\tif dataLen < 4 {\n\t\t\treturn nil, nil, fmt.Errorf(\"path element must be at least 4 bytes (header), length indicates %d\", dataLen)\n\t\t}\n\n\t\telemData := rest[4:dataLen]\n\t\trest = rest[dataLen:]\n\n\t\t// End of Device Path\n\t\tif t == 0x7f && subT == 0xff {\n\t\t\treturn p, rest, nil\n\t\t}\n\n\t\tunmarshal, ok := pathElementUnmarshalMap[[2]byte{t, subT}]\n\t\tif !ok {\n\t\t\tp = append(p, &UnknownPath{\n\t\t\t\tTypeVal:    t,\n\t\t\t\tSubTypeVal: subT,\n\t\t\t\tDataVal:    elemData,\n\t\t\t})\n\n\t\t\tcontinue\n\t\t}\n\n\t\telem, err := unmarshal(elemData)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed decoding path element %d: %w\", len(p), err)\n\t\t}\n\n\t\tp = append(p, elem)\n\t}\n\n\tif len(p) == 0 {\n\t\treturn nil, nil, errors.New(\"empty DevicePath without End Of Path element\")\n\t}\n\n\treturn nil, nil, fmt.Errorf(\"got DevicePath with %d elements, but without End Of Path element\", len(p))\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/devicepath_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage efivarfs_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n)\n\n// nolint:gocyclo\nfunc TestMarshalExamples(t *testing.T) {\n\tcases := []struct {\n\t\tname        string\n\t\tpath        efivarfs.DevicePath\n\t\texpected    []byte\n\t\texpectError bool\n\t}{\n\t\t{\n\t\t\tname: \"TestNone\",\n\t\t\tpath: efivarfs.DevicePath{},\n\t\t\texpected: []byte{\n\t\t\t\t0x7f, 0xff, // End of HW device path\n\t\t\t\t0x04, 0x00, // Length: 4 bytes\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// From UEFI Device Path Examples, extracted single entry\n\t\t\tname: \"TestHD\",\n\t\t\tpath: efivarfs.DevicePath{\n\t\t\t\t&efivarfs.HardDrivePath{\n\t\t\t\t\tPartitionNumber:     1,\n\t\t\t\t\tPartitionStartBlock: 0x22,\n\t\t\t\t\tPartitionSizeBlocks: 0x2710000,\n\t\t\t\t\tPartitionMatch: efivarfs.PartitionGPT{\n\t\t\t\t\t\tPartitionUUID: uuid.MustParse(\"15E39A00-1DD2-1000-8D7F-00A0C92408FC\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: []byte{\n\t\t\t\t0x04, 0x01, // Hard Disk type\n\t\t\t\t0x2a, 0x00, // Length\n\t\t\t\t0x01, 0x00, 0x00, 0x00, // Partition Number\n\t\t\t\t0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Part Start\n\t\t\t\t0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, // Part Size\n\t\t\t\t0x00, 0x9a, 0xe3, 0x15, 0xd2, 0x1d, 0x00, 0x10,\n\t\t\t\t0x8d, 0x7f, 0x00, 0xa0, 0xc9, 0x24, 0x08, 0xfc, // Signature\n\t\t\t\t0x02,       // Part Format GPT\n\t\t\t\t0x02,       // Signature GPT\n\t\t\t\t0x7f, 0xff, // End of HW device path\n\t\t\t\t0x04, 0x00, // Length: 4 bytes\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"TestFilePath\",\n\t\t\tpath: efivarfs.DevicePath{\n\t\t\t\tefivarfs.FilePath(\"asdf\"),\n\t\t\t},\n\t\t\texpected: []byte{\n\t\t\t\t0x04, 0x04, // File Path type\n\t\t\t\t0x0e, 0x00, // Length\n\t\t\t\t'a', 0x00, 's', 0x00, 'd', 0x00, 'f', 0x00,\n\t\t\t\t0x00, 0x00,\n\t\t\t\t0x7f, 0xff, // End of HW device path\n\t\t\t\t0x04, 0x00, // Length: 4 bytes\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, c := range cases {\n\t\tt.Run(c.name, func(t *testing.T) {\n\t\t\tgot, err := c.path.Marshal()\n\t\t\tif err != nil && !c.expectError {\n\t\t\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t\t\t}\n\n\t\t\tif err == nil && c.expectError {\n\t\t\t\tt.Fatalf(\"expected error, got %x\", got)\n\t\t\t}\n\n\t\t\tif err != nil && c.expectError {\n\t\t\t\t// Do not compare result in case error is expected\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !bytes.Equal(got, c.expected) {\n\t\t\t\tt.Fatalf(\"expected %x, got %x\", c.expected, got)\n\t\t\t}\n\n\t\t\t_, rest, err := efivarfs.UnmarshalDevicePath(got)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"failed to unmarshal value again: %v\", err)\n\t\t\t}\n\n\t\t\tif len(rest) != 0 {\n\t\t\t\tt.Errorf(\"rest is non-zero after single valid device path: %x\", rest)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/efivarfs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\n// Package efivarfs provides functions to read and manipulate UEFI runtime\n// variables. It uses Linux's efivarfs [1] to access the variables and all\n// functions generally require that this is mounted at\n// \"/sys/firmware/efi/efivars\".\n//\n// [1] https://www.kernel.org/doc/html/latest/filesystems/efivarfs.html\npackage efivarfs\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/g0rbe/go-chattr\"\n\t\"github.com/google/uuid\"\n\t\"golang.org/x/sys/unix\"\n\t\"golang.org/x/text/encoding/unicode\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\t// Path is the path to the efivarfs mount point.\n\tPath = \"/sys/firmware/efi/efivars\"\n)\n\nvar (\n\t// ScopeGlobal is the scope of variables defined by the EFI specification\n\t// itself.\n\tScopeGlobal = uuid.MustParse(\"8be4df61-93ca-11d2-aa0d-00e098032b8c\")\n\t// ScopeSystemd is the scope of variables defined by Systemd/bootspec.\n\tScopeSystemd = uuid.MustParse(\"4a67b082-0a4c-41cf-b6c7-440b29bb8c4f\")\n)\n\n// Encoding defines the Unicode encoding used by UEFI, which is UCS-2 Little\n// Endian. For BMP characters UTF-16 is equivalent to UCS-2. See the UEFI\n// Spec 2.9, Sections 33.2.6 and 1.8.1.\nvar Encoding = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)\n\n// Attribute contains a bitset of EFI variable attributes.\ntype Attribute uint32\n\nconst (\n\t// AttrNonVolatile is the attribute for non-volatile variables.\n\t// If set the value of the variable is is persistent across resets and\n\t// power cycles. Variables without this set cannot be created or modified\n\t// after UEFI boot services are terminated.\n\tAttrNonVolatile Attribute = 1 << iota\n\t// AttrBootserviceAccess is the attribute for variables that can be\n\t// accessed from UEFI boot services.\n\tAttrBootserviceAccess\n\t// AttrRuntimeAccess is the attribute for variables that can be accessed from\n\t// an operating system after UEFI boot services are terminated. Variables\n\t// setting this must also set AttrBootserviceAccess. This is automatically\n\t// taken care of by Write in this package.\n\tAttrRuntimeAccess\n\t// AttrHardwareErrorRecord is the attribute for variables that are used to\n\t// mark a variable as being a hardware error record. See UEFI 2.10 section\n\t// 8.2.8 for more information about this.\n\tAttrHardwareErrorRecord\n\t// AttrAuthenticatedWriteAccess is the attribute for variables that require\n\t// authenticated access to write.\n\t//\n\t// Deprecated: should not be used for new variables.\n\tAttrAuthenticatedWriteAccess\n\t// AttrTimeBasedAuthenticatedWriteAccess is the attribute for variables\n\t// that require special authentication to write. These variables\n\t// cannot be written with this package.\n\tAttrTimeBasedAuthenticatedWriteAccess\n\t// AttrAppendWrite is the attribute for variables that can be appended to.\n\t// If set in a Write() call, tries to append the data instead of replacing\n\t// it completely.\n\tAttrAppendWrite\n\t// AttrEnhancedAuthenticatedAccess is the attribute for variables that\n\t// require special authentication to access and write. These variables\n\t// cannot be accessed with this package.\n\tAttrEnhancedAuthenticatedAccess\n)\n\nfunc varPath(scope uuid.UUID, varName string) string {\n\treturn fmt.Sprintf(\"/sys/firmware/efi/efivars/%s-%s\", varName, scope.String())\n}\n\n// ReadWriter is an interface for reading and writing EFI variables.\ntype ReadWriter interface {\n\tWrite(scope uuid.UUID, varName string, attrs Attribute, value []byte) error\n\tDelete(scope uuid.UUID, varName string) error\n\tRead(scope uuid.UUID, varName string) ([]byte, Attribute, error)\n\tList(scope uuid.UUID) ([]string, error)\n}\n\n// FilesystemReaderWriter implements ReaderWriter using the efivars Linux filesystem.\ntype FilesystemReaderWriter struct {\n\twrite bool\n}\n\n// NewFilesystemReaderWriter creates a new FilesystemReaderWriter.\nfunc NewFilesystemReaderWriter(write bool) (*FilesystemReaderWriter, error) {\n\tif write {\n\t\tif err := unix.Mount(\"efivarfs\", constants.EFIVarsMountPoint, \"efivarfs\", unix.MS_REMOUNT, \"\"); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &FilesystemReaderWriter{\n\t\twrite: write,\n\t}, nil\n}\n\n// Close unmounts efivarfs if the FilesystemReaderWriter was created with write\n// access.\nfunc (rw *FilesystemReaderWriter) Close() error {\n\tif rw.write {\n\t\treturn unix.Mount(\"efivarfs\", constants.EFIVarsMountPoint, \"efivarfs\", unix.MS_REMOUNT|unix.MS_RDONLY, \"\")\n\t}\n\n\treturn nil\n}\n\n// Write writes the value of the named variable in the given scope.\nfunc (rw *FilesystemReaderWriter) Write(scope uuid.UUID, varName string, attrs Attribute, value []byte) error {\n\tif !rw.write {\n\t\treturn errors.New(\"efivarfs was opened read-only\")\n\t}\n\n\t// Ref: https://docs.kernel.org/filesystems/efivarfs.html\n\t// Remove immutable attribute from the efivarfs file if it exists\n\tif _, err := os.Stat(varPath(scope, varName)); err == nil {\n\t\tf, err := os.Open(varPath(scope, varName))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open efivarfs file %q: %w\", varPath(scope, varName), err)\n\t\t}\n\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tif err := chattr.UnsetAttr(f, chattr.FS_IMMUTABLE_FL); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to clear immutable attribute from efivarfs file %q: %w\", varPath(scope, varName), err)\n\t\t}\n\n\t\tdefer chattr.SetAttr(f, chattr.FS_IMMUTABLE_FL) //nolint:errcheck\n\t}\n\n\t// Write attributes, see @linux//Documentation/filesystems:efivarfs.rst for format\n\tf, err := os.OpenFile(varPath(scope, varName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)\n\tif err != nil {\n\t\te := err\n\t\t// Unwrap PathError here as we wrap our own parameter message around it\n\t\tvar perr *fs.PathError\n\t\tif errors.As(err, &perr) {\n\t\t\te = perr.Err\n\t\t}\n\n\t\treturn fmt.Errorf(\"writing %q in scope %s: %w\", varName, scope, e)\n\t}\n\t// Required by UEFI 2.10 Section 8.2.3:\n\t// Runtime access to a data variable implies boot service access. Attributes\n\t// that have EFI_VARIABLE_RUNTIME_ACCESS set must also have\n\t// EFI_VARIABLE_BOOTSERVICE_ACCESS set. The caller is responsible for\n\t// following this rule.\n\tif attrs&AttrRuntimeAccess != 0 {\n\t\tattrs |= AttrBootserviceAccess\n\t}\n\t// Linux wants everything in on write, so assemble an intermediate buffer\n\tbuf := make([]byte, len(value)+4)\n\tbinary.LittleEndian.PutUint32(buf[:4], uint32(attrs))\n\tcopy(buf[4:], value)\n\n\t_, err = f.Write(buf)\n\tif err1 := f.Close(); err1 != nil && err == nil {\n\t\terr = err1\n\t}\n\n\treturn err\n}\n\n// Read reads the value of the named variable in the given scope.\nfunc (rw *FilesystemReaderWriter) Read(scope uuid.UUID, varName string) ([]byte, Attribute, error) {\n\tval, err := os.ReadFile(varPath(scope, varName))\n\tif err != nil {\n\t\te := err\n\t\t// Unwrap PathError here as we wrap our own parameter message around it\n\t\tvar perr *fs.PathError\n\t\tif errors.As(err, &perr) {\n\t\t\te = perr.Err\n\t\t}\n\n\t\treturn nil, Attribute(0), fmt.Errorf(\"reading %q in scope %s: %w\", varName, scope, e)\n\t}\n\n\tif len(val) < 4 {\n\t\treturn nil, Attribute(0), fmt.Errorf(\"reading %q in scope %s: malformed, less than 4 bytes long\", varName, scope)\n\t}\n\n\treturn val[4:], Attribute(binary.LittleEndian.Uint32(val[:4])), nil\n}\n\n// List lists all variable names present for a given scope sorted by their names\n// in Go's \"native\" string sort order.\nfunc (rw *FilesystemReaderWriter) List(scope uuid.UUID) ([]string, error) {\n\tvars, err := os.ReadDir(Path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list variable directory: %w\", err)\n\t}\n\n\tvar outVarNames []string //nolint:prealloc\n\n\tsuffix := fmt.Sprintf(\"-%v\", scope)\n\n\tfor _, v := range vars {\n\t\tif v.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !strings.HasSuffix(v.Name(), suffix) {\n\t\t\tcontinue\n\t\t}\n\n\t\toutVarNames = append(outVarNames, strings.TrimSuffix(v.Name(), suffix))\n\t}\n\n\treturn outVarNames, nil\n}\n\n// Delete deletes the given variable name in the given scope. Use with care,\n// some firmware fails to boot if variables it uses are deleted.\nfunc (rw *FilesystemReaderWriter) Delete(scope uuid.UUID, varName string) error {\n\tif !rw.write {\n\t\treturn errors.New(\"efivarfs was opened read-only\")\n\t}\n\n\treturn os.Remove(varPath(scope, varName))\n}\n\n// UniqueBootOrder returns a copy of the given BootOrder with duplicate entries\n// removed, preserving the order of first appearance.\nfunc UniqueBootOrder(bootOrder BootOrder) BootOrder {\n\tseen := make(map[uint16]struct{}, len(bootOrder))\n\tj := 0\n\n\tfor _, v := range bootOrder {\n\t\tif _, ok := seen[v]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tseen[v] = struct{}{}\n\t\tbootOrder[j] = v\n\t\tj++\n\t}\n\n\treturn bootOrder[:j]\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/efivarfs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage efivarfs_test\n\nimport (\n\t\"encoding/binary\"\n\t\"io/fs\"\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/efivarfs\"\n)\n\nfunc TestBootOrder(t *testing.T) {\n\tt.Parallel()\n\n\tvar bootOrderEntries []byte\n\n\tfor _, entry := range []int{1, 0, 2, 3} {\n\t\tbootOrderEntries = binary.LittleEndian.AppendUint16(bootOrderEntries, uint16(entry))\n\t}\n\n\tefiRW := efivarfs.Mock{\n\t\tVariables: map[uuid.UUID]map[string]efivarfs.MockVariable{\n\t\t\tefivarfs.ScopeGlobal: {\n\t\t\t\t\"BootOrder\": {\n\t\t\t\t\tAttrs: 0,\n\t\t\t\t\tData:  bootOrderEntries,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tvars, err := efiRW.List(efivarfs.ScopeGlobal)\n\trequire.NoError(t, err)\n\n\trequire.Contains(t, vars, \"BootOrder\", \"variable BootOrder not found\")\n\n\tbootOrder, err := efivarfs.GetBootOrder(&efiRW)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, efivarfs.BootOrder([]uint16{1, 0, 2, 3}), bootOrder, \"BootOrder does not match expected value\")\n\n\trequire.NoError(t, efivarfs.SetBootOrder(&efiRW, efivarfs.BootOrder([]uint16{1, 0, 3})))\n\n\tbootOrder, err = efivarfs.GetBootOrder(&efiRW)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, efivarfs.BootOrder([]uint16{1, 0, 3}), bootOrder, \"BootOrder does not match expected value after SetBootOrder\")\n}\n\nfunc TestBootEntries(t *testing.T) {\n\tt.Parallel()\n\n\tefiRW := efivarfs.Mock{}\n\n\t// no entries yet\n\tentries, err := efivarfs.ListBootEntries(&efiRW)\n\trequire.NoError(t, err)\n\trequire.Empty(t, len(entries), \"expected no boot entries in empty mock\")\n\n\t// create first entry\n\tidx, err := efivarfs.AddBootEntry(&efiRW, &efivarfs.LoadOption{\n\t\tDescription: \"First Entry\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/first.efi\"),\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 0, idx, \"first boot entry index should be 0\")\n\n\t// verify first entry\n\tentry, err := efivarfs.GetBootEntry(&efiRW, idx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"First Entry\", entry.Description, \"first boot entry description does not match\")\n\trequire.Equal(t, efivarfs.DevicePath{efivarfs.FilePath(\"/first.efi\")}, entry.FilePath, \"first boot entry file path does not match\")\n\n\t// create second entry\n\trequire.NoError(t, efivarfs.SetBootEntry(&efiRW, 1, &efivarfs.LoadOption{\n\t\tDescription: \"Second Entry\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/second.efi\"),\n\t\t},\n\t}), \"failed to set second boot entry\")\n\n\t// verify second entry\n\tentry, err = efivarfs.GetBootEntry(&efiRW, 1)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"Second Entry\", entry.Description, \"second boot entry description does not match\")\n\trequire.Equal(t, efivarfs.DevicePath{efivarfs.FilePath(\"/second.efi\")}, entry.FilePath, \"second boot entry file path does not match\")\n\n\t// list all entries\n\tentries, err = efivarfs.ListBootEntries(&efiRW)\n\trequire.NoError(t, err)\n\trequire.Len(t, entries, 2, \"expected exactly two boot entries after adding two\")\n\n\t// try overwrite first entry\n\trequire.NoError(t, efivarfs.SetBootEntry(&efiRW, idx, &efivarfs.LoadOption{\n\t\tDescription: \"First Entry Overwritten\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/first_overwritten.efi\"),\n\t\t},\n\t}), \"failed to overwrite first boot entry\")\n\n\t// verify first entry after overwrite\n\tentry, err = efivarfs.GetBootEntry(&efiRW, idx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"First Entry Overwritten\", entry.Description, \"first boot entry description does not match after overwrite\")\n\trequire.Equal(t, efivarfs.DevicePath{efivarfs.FilePath(\"/first_overwritten.efi\")}, entry.FilePath, \"first boot entry file path does not match after overwrite\")\n\n\t// verify delete non-existing entry\n\trequire.ErrorIs(t, efivarfs.DeleteBootEntry(&efiRW, 42), fs.ErrNotExist, \"expected ErrNoSuchEntry when deleting non-existing entry\")\n\n\t// delete second entry\n\trequire.NoError(t, efivarfs.DeleteBootEntry(&efiRW, 1), \"failed to delete second boot entry\")\n\n\t// verify second entry is gone\n\t_, err = efivarfs.GetBootEntry(&efiRW, 1)\n\trequire.ErrorIs(t, err, fs.ErrNotExist, \"expected ErrNoSuchEntry when getting deleted entry\")\n\n\t// list entries\n\tentries, err = efivarfs.ListBootEntries(&efiRW)\n\trequire.NoError(t, err)\n\trequire.Len(t, entries, 1, \"expected exactly one boot entry after deleting one of two\")\n\n\t// set entry with a high index\n\trequire.NoError(t, efivarfs.SetBootEntry(&efiRW, 42, &efivarfs.LoadOption{\n\t\tDescription: \"High Index Entry\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/high_index.efi\"),\n\t\t},\n\t}), \"failed to set high index boot entry\")\n\n\t// make sure adding a new entry uses the lowest available index (which is 1 now)\n\tnewIdx, err := efivarfs.AddBootEntry(&efiRW, &efivarfs.LoadOption{\n\t\tDescription: \"New Entry\",\n\t\tFilePath: efivarfs.DevicePath{\n\t\t\tefivarfs.FilePath(\"/new.efi\"),\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, newIdx, \"expected new boot entry index to be 1, the lowest available index\")\n}\n\nfunc TestUniqueBootOrder(t *testing.T) {\n\tt.Parallel()\n\n\trequire.Equal(t, efivarfs.BootOrder{}, efivarfs.UniqueBootOrder(efivarfs.BootOrder{}), \"empty BootOrder should remain empty\")\n\n\trequire.Equal(t, efivarfs.BootOrder{1, 2, 3}, efivarfs.UniqueBootOrder(efivarfs.BootOrder{1, 2, 3}), \"BootOrder with unique entries should remain unchanged\")\n\n\trequire.Equal(t, efivarfs.BootOrder{1, 2, 3}, efivarfs.UniqueBootOrder(efivarfs.BootOrder{1, 2, 3, 2, 1, 3}), \"BootOrder with duplicates should have duplicates removed preserving order of first appearance\") //nolint:lll\n\n\trequire.Equal(t, efivarfs.BootOrder{0, 1, 3, 2}, efivarfs.UniqueBootOrder(efivarfs.BootOrder{0, 1, 0, 1, 0, 1, 1, 3, 2, 2, 3, 3, 1}), \"BootOrder with all entries duplicated should have duplicates removed preserving order of first appearance\") //nolint:lll\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/mock.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage efivarfs\n\nimport (\n\t\"io/fs\"\n\t\"maps\"\n\t\"slices\"\n\n\t\"github.com/google/uuid\"\n)\n\n// Mock is a mock implementation of ReaderWriter interface for testing purposes.\ntype Mock struct {\n\tVariables map[uuid.UUID]map[string]MockVariable\n}\n\n// MockVariable represents a mock EFI variable with its attributes and data.\ntype MockVariable struct {\n\tAttrs Attribute\n\tData  []byte\n}\n\n// Write writes a variable to the given scope.\nfunc (mock *Mock) Write(scope uuid.UUID, varName string, attrs Attribute, value []byte) error {\n\tif mock.Variables == nil {\n\t\tmock.Variables = make(map[uuid.UUID]map[string]MockVariable)\n\t}\n\n\tif mock.Variables[scope] == nil {\n\t\tmock.Variables[scope] = make(map[string]MockVariable)\n\t}\n\n\tmock.Variables[scope][varName] = MockVariable{\n\t\tAttrs: attrs,\n\t\tData:  value,\n\t}\n\n\treturn nil\n}\n\n// Delete deletes a variable from the given scope.\nfunc (mock *Mock) Delete(scope uuid.UUID, varName string) error {\n\tif mock.Variables == nil || mock.Variables[scope] == nil {\n\t\treturn fs.ErrNotExist\n\t}\n\n\tif _, exists := mock.Variables[scope][varName]; !exists {\n\t\treturn fs.ErrNotExist\n\t}\n\n\tdelete(mock.Variables[scope], varName)\n\n\treturn nil\n}\n\n// Read reads a variable from the given scope.\nfunc (mock *Mock) Read(scope uuid.UUID, varName string) ([]byte, Attribute, error) {\n\tif mock.Variables == nil || mock.Variables[scope] == nil {\n\t\treturn nil, 0, fs.ErrNotExist\n\t}\n\n\tvariable, exists := mock.Variables[scope][varName]\n\tif !exists {\n\t\treturn nil, 0, fs.ErrNotExist\n\t}\n\n\treturn variable.Data, variable.Attrs, nil\n}\n\n// List lists all variable names in the given scope.\nfunc (mock *Mock) List(scope uuid.UUID) ([]string, error) {\n\tif mock.Variables == nil || mock.Variables[scope] == nil {\n\t\treturn nil, nil\n\t}\n\n\treturn slices.Collect(maps.Keys(mock.Variables[scope])), nil\n}\n"
  },
  {
    "path": "internal/pkg/efivarfs/variables.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage efivarfs\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"math\"\n\t\"regexp\"\n\t\"strconv\"\n\n\t\"github.com/google/uuid\"\n)\n\nfunc decodeString(varData []byte) (string, error) {\n\tefiStringRaw, err := Encoding.NewDecoder().Bytes(varData)\n\tif err != nil {\n\t\t// Pass the decoding error unwrapped.\n\t\treturn \"\", err\n\t}\n\t// Remove the null suffix.\n\treturn string(bytes.TrimSuffix(efiStringRaw, []byte{0})), nil\n}\n\n// ReadLoaderDevicePartUUID reads the ESP UUID from an EFI variable.\nfunc ReadLoaderDevicePartUUID(rw ReadWriter) (uuid.UUID, error) {\n\tefiVar, _, err := rw.Read(ScopeSystemd, \"LoaderDevicePartUUID\")\n\tif err != nil {\n\t\treturn uuid.Nil, err\n\t}\n\n\tstrContent, err := decodeString(efiVar)\n\tif err != nil {\n\t\treturn uuid.Nil, fmt.Errorf(\"decoding string failed: %w\", err)\n\t}\n\n\tout, err := uuid.Parse(strContent)\n\tif err != nil {\n\t\treturn uuid.Nil, fmt.Errorf(\"value in LoaderDevicePartUUID could not be parsed as UUID: %w\", err)\n\t}\n\n\treturn out, nil\n}\n\n// Technically UEFI mandates that only upper-case hex indices are valid, but in\n// practice even vendors themselves ship firmware with lowercase hex indices,\n// thus accept these here as well.\nvar bootVarRegexp = regexp.MustCompile(`^Boot([0-9A-Fa-f]{4})$`)\n\n// ListBootEntries lists all EFI boot entries present in the system by their index.\nfunc ListBootEntries(rw ReadWriter) (map[int]*LoadOption, error) {\n\tbootEntries := make(map[int]*LoadOption)\n\n\tvarNames, err := rw.List(ScopeGlobal)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list EFI variables at scope %s: %w\", ScopeGlobal, err)\n\t}\n\n\tfor _, varName := range varNames {\n\t\ts := bootVarRegexp.FindStringSubmatch(varName)\n\t\tif s == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tidx, err := strconv.ParseUint(s[1], 16, 16)\n\t\tif err != nil {\n\t\t\t// This cannot be hit as all regexp matches are parseable.\n\t\t\t// A quick fuzz run agrees.\n\t\t\tpanic(err)\n\t\t}\n\n\t\tentry, err := GetBootEntry(rw, int(idx))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get boot entry %s: %w\", varName, err)\n\t\t}\n\n\t\tbootEntries[int(idx)] = entry\n\t}\n\n\treturn bootEntries, nil\n}\n\n// AddBootEntry creates an new EFI boot entry variable and returns its\n// non-negative index on success.\nfunc AddBootEntry(rw ReadWriter, be *LoadOption) (int, error) {\n\tbootEntries, err := ListBootEntries(rw)\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"failed to list boot entries: %w\", err)\n\t}\n\n\tidx := -1\n\n\tfor i := range math.MaxUint16 {\n\t\tif _, ok := bootEntries[i]; !ok {\n\t\t\tidx = i\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif idx == -1 {\n\t\treturn -1, errors.New(\"all 2^16 boot entry variables are occupied\")\n\t}\n\n\terr = SetBootEntry(rw, idx, be)\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"failed to set new boot entry: %w\", err)\n\t}\n\n\treturn idx, nil\n}\n\n// GetBootEntry returns the boot entry at the given index.\nfunc GetBootEntry(rw ReadWriter, idx int) (*LoadOption, error) {\n\traw, _, err := rw.Read(ScopeGlobal, fmt.Sprintf(\"Boot%04X\", idx))\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\t// Try non-spec-conforming lowercase entry\n\t\traw, _, err = rw.Read(ScopeGlobal, fmt.Sprintf(\"Boot%04x\", idx))\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn UnmarshalLoadOption(raw)\n}\n\n// SetBootEntry writes the given boot entry to the given index.\nfunc SetBootEntry(rw ReadWriter, idx int, be *LoadOption) error {\n\tbem, err := be.Marshal()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"while marshaling the EFI boot entry: %w\", err)\n\t}\n\n\treturn rw.Write(ScopeGlobal, fmt.Sprintf(\"Boot%04X\", idx), AttrNonVolatile|AttrRuntimeAccess, bem)\n}\n\n// DeleteBootEntry deletes the boot entry at the given index.\nfunc DeleteBootEntry(rw ReadWriter, idx int) error {\n\terr := rw.Delete(ScopeGlobal, fmt.Sprintf(\"Boot%04X\", idx))\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\t// Try non-spec-conforming lowercase entry\n\t\terr = rw.Delete(ScopeGlobal, fmt.Sprintf(\"Boot%04x\", idx))\n\t}\n\n\treturn err\n}\n\n// SetBootOrder replaces contents of the boot order variable with the order\n// specified in ord.\nfunc SetBootOrder(rw ReadWriter, ord BootOrder) error {\n\treturn rw.Write(ScopeGlobal, \"BootOrder\", AttrNonVolatile|AttrRuntimeAccess, ord.Marshal())\n}\n\n// GetBootOrder returns the current boot order of the system.\nfunc GetBootOrder(rw ReadWriter) (BootOrder, error) {\n\traw, _, err := rw.Read(ScopeGlobal, \"BootOrder\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tord, err := UnmarshalBootOrder(raw)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid boot order structure: %w\", err)\n\t}\n\n\treturn ord, nil\n}\n\n// SetBootNext sets the boot entry used for the next boot only. It automatically\n// resets after the next boot.\nfunc SetBootNext(rw ReadWriter, entryIdx uint16) error {\n\tdata := make([]byte, 2)\n\tbinary.LittleEndian.PutUint16(data, entryIdx)\n\n\treturn rw.Write(ScopeGlobal, \"BootNext\", AttrNonVolatile|AttrRuntimeAccess, data)\n}\n"
  },
  {
    "path": "internal/pkg/encryption/encryption.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package encryption provides modules for the partition encryption handling.\npackage encryption\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/luks\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\t\"go.uber.org/zap\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/keys\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nconst keyHandlerTimeout = time.Second * 10\n\n// Helpers provides helper methods for encryption handling.\ntype Helpers struct {\n\tGetSystemInformation helpers.SystemInformationGetter\n\tTPMLocker            helpers.TPMLockFunc\n\tSaltGetter           helpers.SaltGetter\n}\n\n// NewHandler creates new Handler.\nfunc NewHandler(encryptionConfig block.EncryptionSpec, volumeID string, helpers Helpers) (*Handler, error) {\n\tcipher, err := luks.ParseCipherKind(encryptionConfig.Cipher)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse cipher kind: %w\", err)\n\t}\n\n\tvar opts []luks.Option\n\n\tif encryptionConfig.KeySize != 0 {\n\t\topts = append(opts, luks.WithKeySize(encryptionConfig.KeySize))\n\t}\n\n\tif encryptionConfig.BlockSize != 0 {\n\t\topts = append(opts, luks.WithBlockSize(encryptionConfig.BlockSize))\n\t}\n\n\tif encryptionConfig.PerfOptions != nil {\n\t\tfor _, opt := range encryptionConfig.PerfOptions {\n\t\t\tif err = luks.ValidatePerfOption(opt); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid luks performance options: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\topts = append(opts, luks.WithPerfOptions(encryptionConfig.PerfOptions...))\n\t}\n\n\tkeyHandlers := make([]keys.Handler, 0, len(encryptionConfig.Keys))\n\n\tfor _, cfg := range encryptionConfig.Keys {\n\t\thandler, err := keys.NewHandler(cfg,\n\t\t\tkeys.WithVolumeID(volumeID),\n\t\t\tkeys.WithSystemInformationGetter(helpers.GetSystemInformation),\n\t\t\tkeys.WithTPMLocker(helpers.TPMLocker),\n\t\t\tkeys.WithSaltGetter(helpers.SaltGetter),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tkeyHandlers = append(keyHandlers, handler)\n\t}\n\n\t//nolint:scopelint\n\tslices.SortFunc(keyHandlers, func(a, b keys.Handler) int { return cmp.Compare(a.Slot(), b.Slot()) })\n\n\tprovider := luks.New(\n\t\tcipher,\n\t\topts...,\n\t)\n\n\treturn &Handler{\n\t\tencryptionProvider: provider,\n\t\tkeyHandlers:        keyHandlers,\n\t\tsaltGetter:         helpers.SaltGetter,\n\t}, nil\n}\n\n// Handler reads encryption config, creates appropriate\n// encryption provider, handles encrypted partition open and close.\ntype Handler struct {\n\tencryptionProvider encryption.Provider\n\tkeyHandlers        []keys.Handler\n\tsaltGetter         helpers.SaltGetter\n}\n\n// Name returns the name of the handler.\nfunc (h *Handler) Name() string {\n\treturn block.EncryptionProviderLUKS2.String()\n}\n\n// Open encrypted partition.\nfunc (h *Handler) Open(ctx context.Context, logger *zap.Logger, devicePath, mappedName string) (string, int, []string, error) {\n\tisOpen, path, err := h.encryptionProvider.IsOpen(ctx, devicePath, mappedName)\n\tif err != nil {\n\t\treturn \"\", -1, nil, err\n\t}\n\n\tvar usedKey *encryption.Key\n\n\tif !isOpen {\n\t\thandler, key, _, err := h.tryHandlers(ctx, logger, func(ctx context.Context, handler keys.Handler) (*encryption.Key, token.Token, error) {\n\t\t\tslotToken, err := h.readToken(ctx, devicePath, handler.Slot())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\tslotKey, err := handler.GetKey(ctx, slotToken)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\t// try to open with the key, if it fails, tryHandlers will try the next handler\n\t\t\tpath, err = h.encryptionProvider.Open(ctx, devicePath, mappedName, slotKey)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\treturn slotKey, slotToken, nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn \"\", -1, nil, err\n\t\t}\n\n\t\tlogger.Info(\"opened encrypted device\", zap.Int(\"slot\", handler.Slot()), zap.String(\"type\", fmt.Sprintf(\"%T\", handler)))\n\n\t\tusedKey = key\n\t}\n\n\tfailedSyncs, err := h.syncKeys(ctx, logger, devicePath, usedKey)\n\tif err != nil {\n\t\treturn \"\", -1, nil, err\n\t}\n\n\treturn path, usedKey.Slot, failedSyncs, nil\n}\n\n// Close encrypted partition.\nfunc (h *Handler) Close(ctx context.Context, encryptedPath string) error {\n\tif err := h.encryptionProvider.Close(ctx, encryptedPath); err != nil {\n\t\tif errors.Is(err, encryption.ErrDeviceNotReady) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error closing %s: %w\", encryptedPath, err)\n\t}\n\n\treturn nil\n}\n\n// FormatAndEncrypt formats and encrypts the volume.\nfunc (h *Handler) FormatAndEncrypt(ctx context.Context, logger *zap.Logger, path string) error {\n\t_, key, token, err := h.tryHandlers(ctx, logger, func(ctx context.Context, h keys.Handler) (*encryption.Key, token.Token, error) {\n\t\treturn h.NewKey(ctx)\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = h.encryptionProvider.Encrypt(ctx, path, key); err != nil {\n\t\treturn err\n\t}\n\n\tif token != nil {\n\t\tif err = h.encryptionProvider.SetToken(ctx, path, key.Slot, token); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, handler := range h.keyHandlers {\n\t\tif handler.Slot() == key.Slot {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := h.addKey(ctx, path, key, handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (h *Handler) syncKeys(ctx context.Context, logger *zap.Logger, path string, k *encryption.Key) ([]string, error) {\n\tkeyslots, err := h.encryptionProvider.ReadKeyslots(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar failedSyncs []string\n\n\tvisited := map[string]bool{}\n\n\tfor _, handler := range h.keyHandlers {\n\t\tslot := strconv.Itoa(handler.Slot())\n\t\tvisited[slot] = true\n\t\t// no need to update the key which we already detected as unchanged\n\t\tif k != nil && k.Slot == handler.Slot() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// keyslot exists\n\t\tif _, ok := keyslots.Keyslots[slot]; ok {\n\t\t\tif err = h.updateKey(ctx, path, k, handler); err != nil {\n\t\t\t\tlogger.Error(\"failed to update key\", zap.Int(\"slot\", handler.Slot()), zap.String(\"handler\", fmt.Sprintf(\"%T\", handler)), zap.Error(err))\n\n\t\t\t\tfailedSyncs = append(failedSyncs, fmt.Sprintf(\"error updating key slot %s %T: %s\", slot, handler, err))\n\t\t\t} else {\n\t\t\t\tlogger.Info(\"updated encryption key\", zap.Int(\"slot\", handler.Slot()), zap.String(\"handler\", fmt.Sprintf(\"%T\", handler)))\n\t\t\t}\n\t\t} else {\n\t\t\t// keyslot does not exist so just add the key\n\t\t\tif err = h.addKey(ctx, path, k, handler); err != nil {\n\t\t\t\tlogger.Error(\"failed to add key\", zap.Int(\"slot\", handler.Slot()), zap.String(\"handler\", fmt.Sprintf(\"%T\", handler)), zap.Error(err))\n\n\t\t\t\tfailedSyncs = append(failedSyncs, fmt.Sprintf(\"error adding key slot %s %T: %s\", slot, handler, err))\n\t\t\t} else {\n\t\t\t\tlogger.Info(\"added encryption key\", zap.Int(\"slot\", handler.Slot()), zap.String(\"handler\", fmt.Sprintf(\"%T\", handler)))\n\t\t\t}\n\t\t}\n\t}\n\n\t// cleanup deleted key slots\n\tfor slot := range keyslots.Keyslots {\n\t\tif !visited[slot] {\n\t\t\ts, err := strconv.ParseInt(slot, 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif err = h.encryptionProvider.RemoveKey(ctx, path, int(s), k); err != nil {\n\t\t\t\tlogger.Error(\"failed to remove key\", zap.Int(\"slot\", int(s)), zap.Error(err))\n\n\t\t\t\tfailedSyncs = append(failedSyncs, fmt.Sprintf(\"error removing key slot %s: %s\", slot, err))\n\t\t\t} else {\n\t\t\t\tlogger.Info(\"removed encryption key\", zap.Int(\"slot\", k.Slot))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn failedSyncs, nil\n}\n\nfunc (h *Handler) updateKey(ctx context.Context, path string, existingKey *encryption.Key, handler keys.Handler) error {\n\tvalid, err := h.checkKey(ctx, path, handler)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif valid {\n\t\treturn nil\n\t}\n\n\t// re-add the key to the slot\n\terr = h.encryptionProvider.RemoveKey(ctx, path, handler.Slot(), existingKey)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to drop old key during key update %w\", err)\n\t}\n\n\terr = h.addKey(ctx, path, existingKey, handler)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to add new key during key update %w\", err)\n\t}\n\n\treturn err\n}\n\nfunc (h *Handler) checkKey(ctx context.Context, path string, handler keys.Handler) (bool, error) {\n\ttoken, err := h.readToken(ctx, path, handler.Slot())\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tkey, err := handler.GetKey(ctx, token)\n\tif err != nil {\n\t\tif errors.Is(err, keys.ErrTokenInvalid) {\n\t\t\treturn false, nil\n\t\t}\n\n\t\treturn false, err\n\t}\n\n\treturn h.encryptionProvider.CheckKey(ctx, path, key)\n}\n\nfunc (h *Handler) addKey(ctx context.Context, path string, existingKey *encryption.Key, handler keys.Handler) error {\n\tkey, token, err := handler.NewKey(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif token != nil {\n\t\tif err = h.encryptionProvider.SetToken(ctx, path, key.Slot, token); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\terr = h.encryptionProvider.AddKey(ctx, path, existingKey, key)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to add new key during key update %w\", err)\n\t}\n\n\treturn nil\n}\n\n// tryHandlers tries to get encryption keys from all available handlers.\n//\n// It returns the first handler that successfully returns a key.\nfunc (h *Handler) tryHandlers(\n\tctx context.Context, logger *zap.Logger,\n\tcb func(ctx context.Context, h keys.Handler) (*encryption.Key, token.Token, error),\n) (\n\tkeys.Handler, *encryption.Key, token.Token, error,\n) {\n\tif len(h.keyHandlers) == 0 {\n\t\treturn nil, nil, nil, errors.New(\"no encryption keys found\")\n\t}\n\n\tcallback := func(ctx context.Context, h keys.Handler) (*encryption.Key, token.Token, error) {\n\t\tctx, cancel := context.WithTimeout(ctx, keyHandlerTimeout)\n\t\tdefer cancel()\n\n\t\treturn cb(ctx, h)\n\t}\n\n\tvar errs error\n\n\tfor _, h := range h.keyHandlers {\n\t\tkey, token, err := callback(ctx, h)\n\t\tif err != nil {\n\t\t\terrs = multierror.Append(errs, err)\n\n\t\t\tlogger.Warn(\"failed to call key handler\", zap.Int(\"slot\", h.Slot()), zap.String(\"handler\", fmt.Sprintf(\"%T\", h)), zap.Error(err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\treturn h, key, token, nil\n\t}\n\n\treturn nil, nil, nil, fmt.Errorf(\"no handlers available to get encryption keys from: %w\", errs)\n}\n\nfunc (h *Handler) readToken(ctx context.Context, path string, id int) (token.Token, error) {\n\ttoken := luks.Token[json.RawMessage]{}\n\n\terr := h.encryptionProvider.ReadToken(ctx, path, id, &token)\n\tif err != nil {\n\t\tif errors.Is(err, encryption.ErrTokenNotFound) {\n\t\t\treturn nil, nil //nolint:nilnil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tswitch token.Type {\n\tcase keys.TokenTypeKMS:\n\t\tkmsData := &keys.KMSToken{}\n\n\t\tif err = json.Unmarshal(token.UserData, &kmsData); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &luks.Token[*keys.KMSToken]{\n\t\t\tType:     token.Type,\n\t\t\tUserData: kmsData,\n\t\t}, nil\n\tcase keys.TokenTypeTPM:\n\t\ttpmData := &keys.TPMToken{}\n\n\t\tif err = json.Unmarshal(token.UserData, &tpmData); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn &luks.Token[*keys.TPMToken]{\n\t\t\tType:     token.Type,\n\t\t\tUserData: tpmData,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown token type %s\", token.Type)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/encryption/encryption_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encryption_test\n\nimport (\n\t\"testing\"\n)\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "internal/pkg/encryption/helpers/helpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package helpers defines encryption handlers.\npackage helpers\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\n// SystemInformationGetter defines the closure which can be used in key handlers to get the node UUID.\ntype SystemInformationGetter func(context.Context) (*hardware.SystemInformation, error)\n\n// TPMLockFunc is a function that ensures that the TPM is locked and PCR state is as expected.\ntype TPMLockFunc func(context.Context, func() error) error\n\n// SaltGetter defines the closure which can be used in key handlers to get the encryption salt.\ntype SaltGetter func(context.Context) ([]byte, error)\n"
  },
  {
    "path": "internal/pkg/encryption/keys/keys.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package keys contains various encryption KeyHandler implementations.\npackage keys\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nvar errNoSystemInfoGetter = errors.New(\"the UUID getter is not set\")\n\n// NewHandler key using provided config.\n//\n//nolint:gocyclo\nfunc NewHandler(cfg block.EncryptionKey, options ...KeyOption) (Handler, error) {\n\topts, err := NewDefaultOptions(options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkey := KeyHandler{slot: cfg.Slot}\n\n\tvar handler Handler\n\n\tswitch cfg.Type {\n\tcase block.EncryptionKeyStatic:\n\t\tk := cfg.StaticPassphrase\n\t\tif k == nil {\n\t\t\treturn nil, errors.New(\"static key must have key data defined\")\n\t\t}\n\n\t\thandler = NewStaticKeyHandler(key, k)\n\tcase block.EncryptionKeyNodeID:\n\t\tif opts.GetSystemInformation == nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create nodeUUID key handler at slot %d: %w\", cfg.Slot, errNoSystemInfoGetter)\n\t\t}\n\n\t\thandler = NewNodeIDKeyHandler(key, opts.VolumeID, opts.GetSystemInformation)\n\tcase block.EncryptionKeyKMS:\n\t\tif opts.GetSystemInformation == nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create KMS key handler at slot %d: %w\", cfg.Slot, errNoSystemInfoGetter)\n\t\t}\n\n\t\thandler, err = NewKMSKeyHandler(key, cfg.KMSEndpoint, opts.GetSystemInformation)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase block.EncryptionKeyTPM:\n\t\tif opts.TPMLocker == nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create TPM key handler at slot %d: no TPM lock function\", cfg.Slot)\n\t\t}\n\n\t\thandler, err = NewTPMKeyHandler(\n\t\t\tkey,\n\t\t\tcfg.TPMCheckSecurebootStatusOnEnroll,\n\t\t\tcfg.TPMPCRs,\n\t\t\topts.TPMLocker)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported key type: %s\", cfg.Type)\n\t}\n\n\tif cfg.LockToSTATE {\n\t\tif opts.SaltGetter == nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create state-locked key handler at slot %d: no salt getter\", cfg.Slot)\n\t\t}\n\n\t\thandler = NewSaltedHandler(handler, opts.SaltGetter)\n\t}\n\n\treturn handler, nil\n}\n\n// Handler manages key lifecycle.\ntype Handler interface {\n\tNewKey(context.Context) (*encryption.Key, token.Token, error)\n\tGetKey(context.Context, token.Token) (*encryption.Key, error)\n\tSlot() int\n}\n\n// KeyHandler is the base class for all key handlers.\ntype KeyHandler struct {\n\tslot int\n}\n\n// Slot implements Handler interface.\nfunc (k *KeyHandler) Slot() int {\n\treturn k.slot\n}\n\n// ErrTokenInvalid is returned by the keys handler if the supplied token is not valid.\nvar ErrTokenInvalid = errors.New(\"invalid token\")\n"
  },
  {
    "path": "internal/pkg/encryption/keys/kms.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/luks\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\t\"github.com/siderolabs/kms-client/api/kms\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/endpoint\"\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n)\n\n// KMSToken is the userdata stored in the partition token metadata.\ntype KMSToken struct {\n\tSealedData []byte `json:\"sealedData\"`\n}\n\n// KMSKeyHandler seals token using KMS service.\ntype KMSKeyHandler struct {\n\tKeyHandler\n\n\tkmsEndpoint   string\n\tgetSystemInfo helpers.SystemInformationGetter\n}\n\n// NewKMSKeyHandler creates new KMSKeyHandler.\nfunc NewKMSKeyHandler(key KeyHandler, kmsEndpoint string, getSystemInfo helpers.SystemInformationGetter) (*KMSKeyHandler, error) {\n\treturn &KMSKeyHandler{\n\t\tKeyHandler:    key,\n\t\tkmsEndpoint:   kmsEndpoint,\n\t\tgetSystemInfo: getSystemInfo,\n\t}, nil\n}\n\n// NewKey implements Handler interface.\nfunc (h *KMSKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Second)\n\tdefer cancel()\n\n\tconn, err := h.getConn()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error dialing KMS endpoint %q: %w\", h.kmsEndpoint, err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tclient := kms.NewKMSServiceClient(conn)\n\n\tkey := make([]byte, 32)\n\tif _, err = io.ReadFull(rand.Reader, key); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tsystemInformation, err := h.getSystemInfo(ctx)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tresp, err := client.Seal(ctx, &kms.Request{\n\t\tNodeUuid: systemInformation.TypedSpec().UUID,\n\t\tData:     key,\n\t})\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to seal KMS passphrase, slot %d: %w\", h.Slot(), err)\n\t}\n\n\ttoken := &luks.Token[*KMSToken]{\n\t\tType: TokenTypeKMS,\n\t\tUserData: &KMSToken{\n\t\t\tSealedData: resp.Data,\n\t\t},\n\t}\n\n\treturn encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(key))), token, nil\n}\n\n// GetKey implements Handler interface.\nfunc (h *KMSKeyHandler) GetKey(ctx context.Context, t token.Token) (*encryption.Key, error) {\n\ttoken, ok := t.(*luks.Token[*KMSToken])\n\tif !ok {\n\t\treturn nil, ErrTokenInvalid\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Second)\n\tdefer cancel()\n\n\tconn, err := h.getConn()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error dialing KMS endpoint %q: %w\", h.kmsEndpoint, err)\n\t}\n\n\tdefer conn.Close() //nolint:errcheck\n\n\tclient := kms.NewKMSServiceClient(conn)\n\n\tsystemInformation, err := h.getSystemInfo(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp, err := client.Unseal(ctx, &kms.Request{\n\t\tNodeUuid: systemInformation.TypedSpec().UUID,\n\t\tData:     token.UserData.SealedData,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unseal KMS passphrase, slot %d: %w\", h.Slot(), err)\n\t}\n\n\treturn encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(resp.Data))), nil\n}\n\nfunc (h *KMSKeyHandler) getConn() (*grpc.ClientConn, error) {\n\tvar transportCredentials credentials.TransportCredentials\n\n\tendpoint, err := endpoint.Parse(h.kmsEndpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif endpoint.Insecure {\n\t\ttransportCredentials = insecure.NewCredentials()\n\t} else {\n\t\ttransportCredentials = credentials.NewTLS(&tls.Config{\n\t\t\tRootCAs: httpdefaults.RootCAs(),\n\t\t})\n\t}\n\n\treturn grpc.NewClient(\n\t\tendpoint.Host,\n\t\tgrpc.WithTransportCredentials(transportCredentials),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t\tgrpc.WithContextDialer(dialer.DynamicProxyDialerWithTLSConfig(httpdefaults.RootCAsTLSConfig)),\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/nodeid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n)\n\n// NodeIDKeyHandler generates the key based on current node information\n// and provided template string.\ntype NodeIDKeyHandler struct {\n\tKeyHandler\n\n\tpartitionLabel string\n\tgetSystemInfo  helpers.SystemInformationGetter\n}\n\n// NewNodeIDKeyHandler creates new NodeIDKeyHandler.\nfunc NewNodeIDKeyHandler(key KeyHandler, partitionLabel string, systemInfoGetter helpers.SystemInformationGetter) *NodeIDKeyHandler {\n\treturn &NodeIDKeyHandler{\n\t\tKeyHandler:     key,\n\t\tpartitionLabel: partitionLabel,\n\t\tgetSystemInfo:  systemInfoGetter,\n\t}\n}\n\n// NewKey implements Handler interface.\nfunc (h *NodeIDKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {\n\tk, err := h.GetKey(ctx, nil)\n\n\treturn k, nil, err\n}\n\n// GetKey implements Handler interface.\nfunc (h *NodeIDKeyHandler) GetKey(ctx context.Context, _ token.Token) (*encryption.Key, error) {\n\tsystemInformation, err := h.getSystemInfo(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get UUID: %w\", err)\n\t}\n\n\tnodeUUID := systemInformation.TypedSpec().UUID\n\n\tif nodeUUID == \"\" {\n\t\treturn nil, fmt.Errorf(\"machine UUID is not populated %s\", nodeUUID)\n\t}\n\n\t// primitive entropy check\n\tcounts := map[rune]int{}\n\tfor _, s := range nodeUUID {\n\t\tcounts[s]++\n\t\tif counts[s] > len(nodeUUID)/2 {\n\t\t\treturn nil, fmt.Errorf(\"machine UUID %s entropy check failed\", nodeUUID)\n\t\t}\n\t}\n\n\treturn encryption.NewKey(h.slot, []byte(nodeUUID+h.partitionLabel)), nil\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/nodeid_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/keys\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\nfunc TestNodeID(t *testing.T) {\n\tt.Parallel()\n\n\thandler := keys.NewNodeIDKeyHandler(keys.KeyHandler{}, \"test\", func(context.Context) (*hardware.SystemInformation, error) {\n\t\tres := hardware.NewSystemInformation(hardware.SystemInformationID)\n\t\tres.TypedSpec().UUID = \"12345678-1234-5678-1234-567812345678\"\n\n\t\treturn res, nil\n\t})\n\n\tkey, token, err := handler.NewKey(t.Context())\n\trequire.NoError(t, err)\n\trequire.Nil(t, token)\n\n\tassert.Equal(t, \"12345678-1234-5678-1234-567812345678test\", string(key.Value))\n\n\tkey, err = handler.GetKey(t.Context(), nil)\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"12345678-1234-5678-1234-567812345678test\", string(key.Value))\n}\n\nfunc TestNodeIDBadEntropy(t *testing.T) {\n\tt.Parallel()\n\n\thandler := keys.NewNodeIDKeyHandler(keys.KeyHandler{}, \"test\", func(context.Context) (*hardware.SystemInformation, error) {\n\t\tres := hardware.NewSystemInformation(hardware.SystemInformationID)\n\t\tres.TypedSpec().UUID = \"11111111-0000-1111-1111-111111111111\" // bad entropy\n\n\t\treturn res, nil\n\t})\n\n\t_, _, err := handler.NewKey(t.Context())\n\trequire.Error(t, err)\n\tassert.EqualError(t, err, \"machine UUID 11111111-0000-1111-1111-111111111111 entropy check failed\")\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport \"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n\n// KeyOption represents key option callback used in KeyHandler.GetKey func.\ntype KeyOption func(o *KeyOptions) error\n\n// KeyOptions set of options to be used in KeyHandler.GetKey func.\ntype KeyOptions struct {\n\tVolumeID             string\n\tGetSystemInformation helpers.SystemInformationGetter\n\tTPMLocker            helpers.TPMLockFunc\n\tSaltGetter           helpers.SaltGetter\n}\n\n// WithVolumeID passes the partition label to the key handler.\nfunc WithVolumeID(label string) KeyOption {\n\treturn func(o *KeyOptions) error {\n\t\to.VolumeID = label\n\n\t\treturn nil\n\t}\n}\n\n// WithSystemInformationGetter passes the node UUID to the key handler.\nfunc WithSystemInformationGetter(getter helpers.SystemInformationGetter) KeyOption {\n\treturn func(o *KeyOptions) error {\n\t\to.GetSystemInformation = getter\n\n\t\treturn nil\n\t}\n}\n\n// WithTPMLocker passes the TPM locker to the key handler.\nfunc WithTPMLocker(locker helpers.TPMLockFunc) KeyOption {\n\treturn func(o *KeyOptions) error {\n\t\to.TPMLocker = locker\n\n\t\treturn nil\n\t}\n}\n\n// WithSaltGetter passes the salt getter to the key handler.\nfunc WithSaltGetter(getter helpers.SaltGetter) KeyOption {\n\treturn func(o *KeyOptions) error {\n\t\to.SaltGetter = getter\n\n\t\treturn nil\n\t}\n}\n\n// NewDefaultOptions creates new KeyOptions.\nfunc NewDefaultOptions(options []KeyOption) (*KeyOptions, error) {\n\tvar opts KeyOptions\n\n\tfor _, o := range options {\n\t\terr := o(&opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &opts, nil\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/salted.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n)\n\n// SaltedHandler is a key handler wrapper that salts the key with a provided random salt.\ntype SaltedHandler struct {\n\twrapped    Handler\n\tsaltGetter helpers.SaltGetter\n}\n\n// NewSaltedHandler creates a new handler that wraps the provided key handler and uses the provided salt getter.\nfunc NewSaltedHandler(wrapped Handler, saltGetter helpers.SaltGetter) Handler {\n\treturn &SaltedHandler{\n\t\twrapped:    wrapped,\n\t\tsaltGetter: saltGetter,\n\t}\n}\n\n// NewKey implements the keys.Handler interface.\nfunc (k *SaltedHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {\n\tkey, token, err := k.wrapped.NewKey(ctx)\n\tif err != nil {\n\t\treturn key, token, err\n\t}\n\n\tsalt, err := k.saltGetter(ctx)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"failed to get disk encryption key salt: %w\", err)\n\t}\n\n\tkey.Value = slices.Concat(key.Value, salt)\n\n\treturn key, token, nil\n}\n\n// GetKey implements the keys.Handler interface.\nfunc (k *SaltedHandler) GetKey(ctx context.Context, token token.Token) (*encryption.Key, error) {\n\tkey, err := k.wrapped.GetKey(ctx, token)\n\tif err != nil {\n\t\treturn key, err\n\t}\n\n\tsalt, err := k.saltGetter(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get disk encryption key salt: %w\", err)\n\t}\n\n\tkey.Value = slices.Concat(key.Value, salt)\n\n\treturn key, nil\n}\n\n// Slot implements the keys.Handler interface.\nfunc (k *SaltedHandler) Slot() int {\n\treturn k.wrapped.Slot()\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/salted_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/keys\"\n)\n\nfunc TestSalted(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\tsecret = \"topsecret\"\n\t\tsalt   = \"salted\"\n\t)\n\n\tinner := keys.NewStaticKeyHandler(keys.KeyHandler{}, []byte(secret))\n\n\thandler := keys.NewSaltedHandler(inner, func(context.Context) ([]byte, error) {\n\t\treturn []byte(salt), nil\n\t})\n\n\tkey, token, err := handler.NewKey(t.Context())\n\trequire.NoError(t, err)\n\trequire.Nil(t, token)\n\n\tassert.Equal(t, secret+salt, string(key.Value))\n\n\tkey, err = handler.GetKey(t.Context(), nil)\n\trequire.NoError(t, err)\n\tassert.Equal(t, secret+salt, string(key.Value))\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/static.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n)\n\n// StaticKeyHandler just handles the static key value all the time.\ntype StaticKeyHandler struct {\n\tKeyHandler\n\n\tdata []byte\n}\n\n// NewStaticKeyHandler creates new EphemeralKeyHandler.\nfunc NewStaticKeyHandler(key KeyHandler, data []byte) *StaticKeyHandler {\n\treturn &StaticKeyHandler{\n\t\tKeyHandler: key,\n\t\tdata:       data,\n\t}\n}\n\n// NewKey implements Handler interface.\nfunc (h *StaticKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {\n\tk, err := h.GetKey(ctx, nil)\n\n\treturn k, nil, err\n}\n\n// GetKey implements Handler interface.\nfunc (h *StaticKeyHandler) GetKey(context.Context, token.Token) (*encryption.Key, error) {\n\treturn encryption.NewKey(h.slot, h.data), nil\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/static_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/keys\"\n)\n\nfunc TestStatic(t *testing.T) {\n\tt.Parallel()\n\n\tconst secret = \"topsecret\"\n\n\thandler := keys.NewStaticKeyHandler(keys.KeyHandler{}, []byte(secret))\n\n\tkey, token, err := handler.NewKey(t.Context())\n\trequire.NoError(t, err)\n\trequire.Nil(t, token)\n\n\tassert.Equal(t, secret, string(key.Value))\n\n\tkey1, err := handler.GetKey(t.Context(), nil)\n\trequire.NoError(t, err)\n\tassert.Equal(t, key, key1)\n}\n"
  },
  {
    "path": "internal/pkg/encryption/keys/token.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nconst (\n\t// TokenTypeKMS is KMS assisted encryption token.\n\tTokenTypeKMS = \"sideroKMS\"\n\t// TokenTypeTPM is TPM assisted encryption token.\n\tTokenTypeTPM = \"talos-tpm2\"\n)\n"
  },
  {
    "path": "internal/pkg/encryption/keys/tpm2.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage keys\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/foxboron/go-uefi/efi\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/luks\"\n\t\"github.com/siderolabs/go-blockdevice/v2/encryption/token\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/encryption/helpers\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n)\n\n// TPMToken is the userdata stored in the partition token metadata.\ntype TPMToken struct {\n\tKeySlots          []int  `json:\"keyslots\"`\n\tSealedBlobPrivate []byte `json:\"sealed_blob_private\"`\n\tSealedBlobPublic  []byte `json:\"sealed_blob_public\"`\n\tPCRs              []int  `json:\"pcrs,omitempty\"`\n\tPubKeyPCRs        []int  `json:\"pubkey_pcrs\"`\n\tAlg               string `json:\"alg\"`\n\tEncryptionVersion string `json:\"encryption_version,omitempty\"`\n\tPolicyHash        []byte `json:\"policy_hash\"`\n\tKeyName           []byte `json:\"key_name\"`\n}\n\n// TPMKeyHandler seals token using TPM.\ntype TPMKeyHandler struct {\n\tKeyHandler\n\n\ttpmLocker               helpers.TPMLockFunc\n\tcheckSecurebootOnEnroll bool\n\ttpmPCRs                 []int\n}\n\n// NewTPMKeyHandler creates new TPMKeyHandler.\nfunc NewTPMKeyHandler(key KeyHandler, checkSecurebootOnEnroll bool, tpmPCRs []int, tpmLocker helpers.TPMLockFunc) (*TPMKeyHandler, error) {\n\treturn &TPMKeyHandler{\n\t\tKeyHandler:              key,\n\t\ttpmLocker:               tpmLocker,\n\t\tcheckSecurebootOnEnroll: checkSecurebootOnEnroll,\n\t\ttpmPCRs:                 tpmPCRs,\n\t}, nil\n}\n\n// NewKey implements Handler interface.\nfunc (h *TPMKeyHandler) NewKey(ctx context.Context) (*encryption.Key, token.Token, error) {\n\tif h.checkSecurebootOnEnroll {\n\t\tif !efi.GetSecureBoot() {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to enroll the TPM2 key, as SecureBoot is disabled (and checkSecurebootOnEnroll is enabled)\")\n\t\t}\n\n\t\tif efi.GetSetupMode() {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to enroll the TPM2 key, as the system is in SecureBoot setup mode (and checkSecurebootOnEnroll is enabled)\")\n\t\t}\n\t}\n\n\tkey := make([]byte, 32)\n\tif _, err := io.ReadFull(rand.Reader, key); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tvar resp *tpm2.SealedResponse\n\n\tif err := h.tpmLocker(ctx, func() error {\n\t\tvar err error\n\n\t\tresp, err = tpm2.Seal(key, h.tpmPCRs)\n\n\t\treturn err\n\t}); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\ttoken := &luks.Token[*TPMToken]{\n\t\tType: TokenTypeTPM,\n\t\tUserData: &TPMToken{\n\t\t\tKeySlots:          []int{h.slot},\n\t\t\tSealedBlobPrivate: resp.SealedBlobPrivate,\n\t\t\tSealedBlobPublic:  resp.SealedBlobPublic,\n\t\t\tAlg:               resp.Alg,\n\t\t\tEncryptionVersion: resp.EncryptionVersion,\n\t\t\tPubKeyPCRs:        resp.PubKeyPCRs,\n\t\t\tPCRs:              resp.PCRs,\n\t\t\tPolicyHash:        resp.PolicyDigest,\n\t\t\tKeyName:           resp.KeyName,\n\t\t},\n\t}\n\n\treturn encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(key))), token, nil\n}\n\n// GetKey implements Handler interface.\nfunc (h *TPMKeyHandler) GetKey(ctx context.Context, t token.Token) (*encryption.Key, error) {\n\ttoken, ok := t.(*luks.Token[*TPMToken])\n\tif !ok {\n\t\treturn nil, ErrTokenInvalid\n\t}\n\n\tsealed := tpm2.SealedResponse{\n\t\tSealedBlobPrivate: token.UserData.SealedBlobPrivate,\n\t\tSealedBlobPublic:  token.UserData.SealedBlobPublic,\n\t\tPolicyDigest:      token.UserData.PolicyHash,\n\t\tKeyName:           token.UserData.KeyName,\n\t\tPCRs:              token.UserData.PCRs,\n\t\tPubKeyPCRs:        token.UserData.PubKeyPCRs,\n\t\tEncryptionVersion: token.UserData.EncryptionVersion,\n\t}\n\n\tvar key []byte\n\n\tif err := h.tpmLocker(ctx, func() error {\n\t\tvar err error\n\n\t\tkey, err = tpm2.Unseal(sealed)\n\n\t\treturn err\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn encryption.NewKey(h.slot, []byte(base64.StdEncoding.EncodeToString(key))), nil\n}\n"
  },
  {
    "path": "internal/pkg/encryption/node_params.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encryption\n\n// NodeParams contains node information relevant for the encryption handler.\ntype NodeParams struct {\n\tUUID string\n}\n"
  },
  {
    "path": "internal/pkg/endpoint/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package endpoint has common tools for parsing http API endpoints.\npackage endpoint\n\nimport (\n\t\"net/url\"\n\t\"regexp\"\n)\n\nvar urlSchemeMatcher = regexp.MustCompile(`[a-zA-z]+://`)\n\n// Endpoint defines all params parsed from the API endpoint.\ntype Endpoint struct {\n\tHost     string\n\tInsecure bool\n\tparams   url.Values\n}\n\n// Parse parses the endpoint from string.\nfunc Parse(sideroLinkParam string) (Endpoint, error) {\n\tif !urlSchemeMatcher.MatchString(sideroLinkParam) {\n\t\tsideroLinkParam = \"grpc://\" + sideroLinkParam\n\t}\n\n\tu, err := url.Parse(sideroLinkParam)\n\tif err != nil {\n\t\treturn Endpoint{}, err\n\t}\n\n\tresult := Endpoint{\n\t\tHost:     u.Host,\n\t\tInsecure: u.Scheme == \"grpc\",\n\t\tparams:   u.Query(),\n\t}\n\n\tif u.Port() == \"\" && u.Scheme == \"https\" {\n\t\tresult.Host += \":443\"\n\t}\n\n\treturn result, nil\n}\n\n// GetParam reads param from the query.\nfunc (e *Endpoint) GetParam(name string) string {\n\treturn e.params.Get(name)\n}\n"
  },
  {
    "path": "internal/pkg/endpoint/endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage endpoint_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/endpoint\"\n)\n\nfunc TestParseEndpoint(t *testing.T) {\n\tt.Run(\"parses a join token from a complete URL without error\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"grpc://10.5.0.2:3445?jointoken=ttt\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:3445\", endpoint.Host)\n\t\tassert.True(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"ttt\", endpoint.GetParam(\"jointoken\"))\n\t})\n\n\tt.Run(\"parses a join token from a secure URL without error\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"https://10.5.0.2:3445?jointoken=ttt&jointoken=xxx\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:3445\", endpoint.Host)\n\t\tassert.False(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"ttt\", endpoint.GetParam(\"jointoken\"))\n\t})\n\n\tt.Run(\"parses a join token from a secure URL without port\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"https://10.5.0.2?jointoken=ttt&jointoken=xxx\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:443\", endpoint.Host)\n\t\tassert.False(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"ttt\", endpoint.GetParam(\"jointoken\"))\n\t})\n\n\tt.Run(\"parses a join token from an URL without a scheme\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"10.5.0.2:3445?jointoken=ttt\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:3445\", endpoint.Host)\n\t\tassert.True(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"ttt\", endpoint.GetParam(\"jointoken\"))\n\t})\n\n\tt.Run(\"does not error if there is no join token in a complete URL\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"grpc://10.5.0.2:3445\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:3445\", endpoint.Host)\n\t\tassert.True(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"\", endpoint.GetParam(\"jointoken\"))\n\t})\n\n\tt.Run(\"does not error if there is no join token in an URL without a scheme\", func(t *testing.T) {\n\t\t// when\n\t\tendpoint, err := endpoint.Parse(\"10.5.0.2:3445\")\n\n\t\t// then\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"10.5.0.2:3445\", endpoint.Host)\n\t\tassert.True(t, endpoint.Insecure)\n\t\tassert.Equal(t, \"\", endpoint.GetParam(\"jointoken\"))\n\t})\n}\n"
  },
  {
    "path": "internal/pkg/environment/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package environment provides a set of functions to get environment variables.\npackage environment\n\nimport (\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Get the desired set of the environment variables based on kernel cmdline and machine config.\n//\n// The returned value is a list of strings in the form of \"key=value\".\nfunc Get(cfg config.Config) []string {\n\treturn GetCmdline(procfs.ProcCmdline(), cfg)\n}\n\n// GetCmdline the desired set of the environment variables based on kernel cmdline.\nfunc GetCmdline(cmdline *procfs.Cmdline, cfg config.Config) []string {\n\tvar result []string\n\n\tparam := cmdline.Get(constants.KernelParamEnvironment)\n\n\tfor idx := 0; ; idx++ {\n\t\tval := param.Get(idx)\n\t\tif val == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tresult = append(result, *val)\n\t}\n\n\tif cfg != nil {\n\t\tif cfg.Machine() != nil {\n\t\t\tfor k, v := range cfg.Machine().Env() {\n\t\t\t\tresult = append(result, k+\"=\"+v)\n\t\t\t}\n\t\t}\n\n\t\tif cfg.Environment() != nil {\n\t\t\tfor k, v := range cfg.Environment().Variables() {\n\t\t\t\tresult = append(result, k+\"=\"+v)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/pkg/environment/environment_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage environment_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestGet(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname    string\n\t\tcmdline string\n\t\tcfg     map[string]string\n\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"machine config only\",\n\t\t\tcfg: map[string]string{\n\t\t\t\t\"http_proxy\": \"http://proxy.example.com:8080\",\n\t\t\t},\n\t\t\texpected: []string{\n\t\t\t\t\"http_proxy=http://proxy.example.com:8080\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"cmdline only\",\n\t\t\tcmdline: \"talos.environment=foo=bar talos.environment=bar=baz\",\n\t\t\texpected: []string{\n\t\t\t\t\"foo=bar\",\n\t\t\t\t\"bar=baz\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"cmdline and machine config\",\n\t\t\tcmdline: \"talos.environment=foo=bar\",\n\t\t\tcfg: map[string]string{\n\t\t\t\t\"http_proxy\": \"http://proxy.example.com:8080\",\n\t\t\t},\n\t\t\texpected: []string{\n\t\t\t\t\"foo=bar\",\n\t\t\t\t\"http_proxy=http://proxy.example.com:8080\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcmdline := procfs.NewCmdline(test.cmdline)\n\n\t\t\tvar cfg config.Config\n\n\t\t\tif test.cfg != nil {\n\t\t\t\tvar err error\n\n\t\t\t\tcfg, err = container.New(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineEnv: test.cfg,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tresult := environment.GetCmdline(cmdline, cfg)\n\n\t\t\tassert.Equal(t, test.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/etcd/certs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n// CertificateGenerator contains etcd certificate options.\ntype CertificateGenerator struct {\n\tCA *x509.PEMEncodedCertificateAndKey\n\n\tNodeAddresses  *network.NodeAddress\n\tHostnameStatus *network.HostnameStatus\n}\n\n// buildOptions set common certificate options.\nfunc (gen *CertificateGenerator) buildOptions(autoSANs, includeLocalhost bool) []x509.Option {\n\taddresses := gen.NodeAddresses.TypedSpec().IPs()\n\n\tif includeLocalhost {\n\t\taddresses = append(addresses,\n\t\t\tnetip.MustParseAddr(\"127.0.0.1\"),\n\t\t\tnetip.MustParseAddr(\"::1\"),\n\t\t)\n\t}\n\n\thostname := gen.HostnameStatus.TypedSpec().Hostname\n\tdnsNames := gen.HostnameStatus.TypedSpec().DNSNames()\n\n\tif includeLocalhost {\n\t\tdnsNames = append(dnsNames, \"localhost\")\n\t}\n\n\tresult := []x509.Option{\n\t\tx509.NotAfter(time.Now().Add(87600 * time.Hour)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature | stdlibx509.KeyUsageKeyEncipherment),\n\t}\n\n\tif autoSANs {\n\t\tresult = append(result,\n\t\t\tx509.CommonName(hostname),\n\t\t\tx509.DNSNames(dnsNames),\n\t\t\tx509.IPAddresses(xslices.Map(addresses, func(addr netip.Addr) net.IP {\n\t\t\t\treturn addr.AsSlice()\n\t\t\t})),\n\t\t)\n\t}\n\n\treturn result\n}\n\n// GeneratePeerCert generates etcd peer certificate and key from etcd CA.\nfunc (gen *CertificateGenerator) GeneratePeerCert() (*x509.PEMEncodedCertificateAndKey, error) {\n\topts := gen.buildOptions(true, false)\n\n\topts = append(opts,\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(gen.CA)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed loading CA from config: %w\", err)\n\t}\n\n\tkeyPair, err := x509.NewKeyPair(ca, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed generating peer key pair: %w\", err)\n\t}\n\n\treturn x509.NewCertificateAndKeyFromKeyPair(keyPair), nil\n}\n\n// GenerateServerCert generates server etcd certificate and key from etcd CA.\nfunc (gen *CertificateGenerator) GenerateServerCert() (*x509.PEMEncodedCertificateAndKey, error) {\n\topts := gen.buildOptions(true, true)\n\n\topts = append(opts,\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageServerAuth,\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(gen.CA)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed loading CA from config: %w\", err)\n\t}\n\n\tkeyPair, err := x509.NewKeyPair(ca, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed generating client key pair: %w\", err)\n\t}\n\n\treturn x509.NewCertificateAndKeyFromKeyPair(keyPair), nil\n}\n\n// GenerateClientCert generates client certificate and key from etcd CA.\nfunc (gen *CertificateGenerator) GenerateClientCert(commonName string) (*x509.PEMEncodedCertificateAndKey, error) {\n\topts := gen.buildOptions(false, false)\n\n\topts = append(opts, x509.CommonName(commonName))\n\topts = append(opts,\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\n\tca, err := x509.NewCertificateAuthorityFromCertificateAndKey(gen.CA)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed loading CA from config: %w\", err)\n\t}\n\n\tkeyPair, err := x509.NewKeyPair(ca, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed generating client key pair: %w\", err)\n\t}\n\n\treturn x509.NewCertificateAndKeyFromKeyPair(keyPair), nil\n}\n"
  },
  {
    "path": "internal/pkg/etcd/endpoints.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// GetEndpoints returns expected endpoints of etcd cluster members.\n//\n// It is not guaranteed that etcd is running on each listed endpoint.\nfunc GetEndpoints(ctx context.Context, resources state.State) ([]string, error) {\n\tendpointResources, err := safe.StateListAll[*k8s.Endpoint](ctx, resources)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting endpoints resources: %w\", err)\n\t}\n\n\tvar endpointAddrs k8s.EndpointList\n\n\t// merge all endpoints into a single list\n\tfor res := range endpointResources.All() {\n\t\tendpointAddrs = endpointAddrs.Merge(res)\n\t}\n\n\tif endpointAddrs.IsEmpty() {\n\t\treturn nil, errors.New(\"no controlplane endpoints discovered yet\")\n\t}\n\n\tendpoints := endpointAddrs.Strings()\n\n\t// Etcd expects host:port format.\n\tfor i := range endpoints {\n\t\tendpoints[i] = nethelpers.JoinHostPort(endpoints[i], constants.EtcdClientPort)\n\t}\n\n\treturn endpoints, nil\n}\n"
  },
  {
    "path": "internal/pkg/etcd/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand/v2\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.etcd.io/etcd/api/v3/etcdserverpb\"\n\t\"go.etcd.io/etcd/api/v3/v3rpc/rpctypes\"\n\t\"go.etcd.io/etcd/client/pkg/v3/transport\"\n\tclientv3 \"go.etcd.io/etcd/client/v3\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/system\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\tetcdresource \"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\n// QuorumCheckTimeout is the amount of time to allow for KV operations before quorum is declared invalid.\nconst QuorumCheckTimeout = 15 * time.Second\n\n// Client is a wrapper around the official etcd client.\ntype Client struct {\n\t*clientv3.Client\n}\n\n// NewClient initializes and returns an etcd client configured to talk to\n// a list of endpoints.\nfunc NewClient(ctx context.Context, endpoints []string, dialOpts ...grpc.DialOption) (client *Client, err error) {\n\ttlsInfo := transport.TLSInfo{\n\t\tCertFile:      constants.EtcdAdminCert,\n\t\tKeyFile:       constants.EtcdAdminKey,\n\t\tTrustedCAFile: constants.EtcdCACert,\n\t}\n\n\ttlsConfig, err := tlsInfo.ClientConfig()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error building etcd client TLS config: %w\", err)\n\t}\n\n\tc, err := clientv3.New(clientv3.Config{\n\t\tEndpoints:   endpoints,\n\t\tDialTimeout: 5 * time.Second,\n\t\tContext:     ctx,\n\t\tDialOptions: append(dialOpts, grpc.WithSharedWriteBuffer(true)),\n\t\tTLS:         tlsConfig,\n\t\tLogger:      zap.NewNop(),\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error building etcd client: %w\", err)\n\t}\n\n\treturn &Client{Client: c}, nil\n}\n\n// NewLocalClient initializes and returns etcd client configured to talk to localhost endpoint.\nfunc NewLocalClient(ctx context.Context, dialOpts ...grpc.DialOption) (client *Client, err error) {\n\treturn NewClient(\n\t\tctx,\n\t\t[]string{nethelpers.JoinHostPort(\"localhost\", constants.EtcdClientPort)},\n\t\tdialOpts...,\n\t)\n}\n\n// NewClientFromControlPlaneIPs initializes and returns an etcd client\n// configured to talk to all members.\nfunc NewClientFromControlPlaneIPs(ctx context.Context, resources state.State, dialOpts ...grpc.DialOption) (client *Client, err error) {\n\tendpoints, err := GetEndpoints(ctx, resources)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Shuffle endpoints to establish random order on each call to avoid patterns based on sorted IP list.\n\trand.Shuffle(len(endpoints), func(i, j int) { endpoints[i], endpoints[j] = endpoints[j], endpoints[i] })\n\n\treturn NewClient(ctx, endpoints, dialOpts...)\n}\n\n// ValidateForUpgrade validates the etcd cluster state to ensure that performing\n// an upgrade is safe.\nfunc (c *Client) ValidateForUpgrade(ctx context.Context, config config.Config) error {\n\tif config.Machine().Type() == machine.TypeWorker {\n\t\treturn nil\n\t}\n\n\tresp, err := c.MemberList(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(resp.Members) == 2 {\n\t\treturn fmt.Errorf(\"etcd member count(%d) is insufficient to maintain quorum if upgrade commences\", len(resp.Members))\n\t}\n\n\tfor _, member := range resp.Members {\n\t\t// If the member is not started, the name will be an empty string.\n\t\tif len(member.Name) == 0 {\n\t\t\treturn fmt.Errorf(\"etcd member %016x is not started, all members must be running to perform an upgrade\", member.ID)\n\t\t}\n\n\t\tif err = validateMemberHealth(ctx, member.GetClientURLs()); err != nil {\n\t\t\treturn fmt.Errorf(\"etcd member %016x is not healthy; all members must be healthy to perform an upgrade: %w\", member.ID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ValidateQuorum performs a KV operation to make certain that quorum is good.\nfunc (c *Client) ValidateQuorum(ctx context.Context) (err error) {\n\t// Get a random key. As long as we can get the response without an error, quorum is good.\n\tcheckCtx, cancel := context.WithTimeout(ctx, QuorumCheckTimeout)\n\tdefer cancel()\n\n\t_, err = c.Get(checkCtx, \"health\")\n\tif err == rpctypes.ErrPermissionDenied {\n\t\t// Permission denied is OK since proposal goes through consensus to get this error.\n\t\terr = nil\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc validateMemberHealth(ctx context.Context, memberURIs []string) (err error) {\n\tc, err := NewClient(ctx, memberURIs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create client to member: %w\", err)\n\t}\n\n\treturn c.ValidateQuorum(ctx)\n}\n\n// LeaveCluster removes the current member from the etcd cluster and nukes etcd data directory.\nfunc (c *Client) LeaveCluster(ctx context.Context, st state.State) error {\n\tmemberID, err := GetLocalMemberID(ctx, st)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := retry.Constant(5*time.Minute, retry.WithUnits(10*time.Second)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\terr := c.RemoveMemberByMemberID(ctx, memberID)\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tif errors.Is(err, rpctypes.ErrUnhealthy) {\n\t\t\t// unhealthy is returned when the member hasn't established connections with quorum other members\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif errors.Is(err, rpctypes.ErrStopped) {\n\t\t\t// retry the stopped errors as the member might be in the process of shutting down\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif errors.Is(err, rpctypes.ErrMemberNotFound) {\n\t\t\t// already removed, nothing to do\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif err := system.Services(nil).Stop(ctx, \"etcd\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to stop etcd: %w\", err)\n\t}\n\n\t// Once the member is removed, the data is no longer valid.\n\tif err := os.RemoveAll(constants.EtcdDataPath); err != nil {\n\t\treturn fmt.Errorf(\"failed to remove %s: %w\", constants.EtcdDataPath, err)\n\t}\n\n\treturn nil\n}\n\n// GetMemberID returns the member ID of the node client is connected to.\nfunc (c *Client) GetMemberID(ctx context.Context) (uint64, error) {\n\tresp, err := c.Client.Maintenance.AlarmList(ctx)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn resp.Header.MemberId, nil\n}\n\n// RemoveMemberByMemberID removes the member from the etcd cluster.\nfunc (c *Client) RemoveMemberByMemberID(ctx context.Context, memberID uint64) error {\n\t_, err := c.MemberRemove(ctx, memberID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to remove member %d: %w\", memberID, err)\n\t}\n\n\treturn nil\n}\n\n// ForfeitLeadership transfers leadership from the current member to another\n// member.\n//\n//nolint:gocyclo\nfunc (c *Client) ForfeitLeadership(ctx context.Context, memberID string) (string, error) {\n\tresp, err := c.MemberList(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to list etcd members: %w\", err)\n\t}\n\n\tif len(resp.Members) == 1 {\n\t\treturn \"\", errors.New(\"cannot forfeit leadership, only one member\")\n\t}\n\n\tvar member *etcdserverpb.Member\n\n\tmemberIDUint64, err := etcdresource.ParseMemberID(memberID)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor _, m := range resp.Members {\n\t\tif m.ID == memberIDUint64 {\n\t\t\tmember = m\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif member == nil {\n\t\treturn \"\", fmt.Errorf(\"failed to find %q in list of etcd members\", memberID)\n\t}\n\n\tfor _, ep := range member.GetClientURLs() {\n\t\tvar status *clientv3.StatusResponse\n\n\t\tstatus, err = c.Status(ctx, ep)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif status.Leader != member.GetID() {\n\t\t\treturn \"\", nil\n\t\t}\n\n\t\tfor _, m := range resp.Members {\n\t\t\tif m.GetID() != member.GetID() {\n\t\t\t\tlog.Printf(\"moving leadership from %q to %q\", member.GetName(), m.GetName())\n\n\t\t\t\tconn, err := c.Dial(ep)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\n\t\t\t\tmaintenance := clientv3.NewMaintenanceFromMaintenanceClient(clientv3.RetryMaintenanceClient(c.Client, conn), c.Client)\n\n\t\t\t\t_, err = maintenance.MoveLeader(ctx, m.GetID())\n\t\t\t\tif err != nil {\n\t\t\t\t\tif errors.Is(err, rpctypes.ErrNotLeader) {\n\t\t\t\t\t\t// this member is not a leader anymore, so nothing to be done for the forfeit leadership\n\t\t\t\t\t\treturn \"\", nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\n\t\t\t\treturn m.GetName(), nil\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "internal/pkg/etcd/local.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\n// GetLocalMemberID gets the etcd member id of the local node via resources.\nfunc GetLocalMemberID(ctx context.Context, s state.State) (uint64, error) {\n\tctx, cancel := context.WithTimeout(ctx, 3*time.Minute)\n\tdefer cancel()\n\n\tmember, err := safe.StateWatchFor[*etcd.Member](\n\t\tctx,\n\t\ts,\n\t\tetcd.NewMember(etcd.NamespaceName, etcd.LocalMemberID).Metadata(),\n\t\tstate.WithEventTypes(state.Created),\n\t)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to get local etcd member ID: %w\", err)\n\t}\n\n\treturn etcd.ParseMemberID(member.TypedSpec().MemberID)\n}\n"
  },
  {
    "path": "internal/pkg/etcd/lock.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"go.etcd.io/etcd/client/v3/concurrency\"\n\t\"go.uber.org/zap\"\n)\n\n// WithLock executes the given function exclusively by acquiring an Etcd lock with the given key.\nfunc WithLock(ctx context.Context, key string, logger *zap.Logger, f func() error) error {\n\tetcdClient, err := NewLocalClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating etcd client: %w\", err)\n\t}\n\n\tdefer etcdClient.Close() //nolint:errcheck\n\n\tsession, err := concurrency.NewSession(etcdClient.Client)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating etcd session: %w\", err)\n\t}\n\n\tdefer session.Close() //nolint:errcheck\n\n\tmutex := concurrency.NewMutex(session, key)\n\n\tlogger.Debug(\"waiting for mutex\", zap.String(\"key\", key))\n\n\tif err = mutex.Lock(ctx); err != nil {\n\t\treturn fmt.Errorf(\"error acquiring mutex for key %s: %w\", key, err)\n\t}\n\n\tlogger.Debug(\"mutex acquired\", zap.String(\"key\", key))\n\n\tdefer func() {\n\t\tlogger.Debug(\"releasing mutex\", zap.String(\"key\", key))\n\n\t\tunlockCtx, unlockCancel := context.WithTimeout(context.Background(), 30*time.Second)\n\t\tdefer unlockCancel()\n\n\t\tif err = mutex.Unlock(unlockCtx); err != nil {\n\t\t\tlogger.Error(\"error releasing mutex\", zap.String(\"key\", key), zap.Error(err))\n\t\t}\n\t}()\n\n\treturn f()\n}\n"
  },
  {
    "path": "internal/pkg/extensions/compress.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// List of globs and destinations for early CPU ucode.\n//\n// See https://www.kernel.org/doc/html/v6.1/x86/microcode.html#early-load-microcode.\n//\n// We need to repackage the ucode blobs matching the glob into the destination concatenating\n// them all together.\n// The resulting blobs should be placed into uncompressed cpio archive prepended to the normal (compressed) initramfs.\nfunc earlyCPUUcode(quirks quirks.Quirks) []struct {\n\tglob, dst string\n} {\n\tfwPath := quirks.FirmwarePath()\n\n\treturn []struct {\n\t\tglob, dst string\n\t}{\n\t\t{fwPath + \"/intel-ucode/*\", \"kernel/x86/microcode/GenuineIntel.bin\"},\n\t\t{fwPath + \"/amd-ucode/microcode_amd*.bin\", \"kernel/x86/microcode/AuthenticAMD.bin\"},\n\t}\n}\n\n// List of paths to be moved to the future initramfs.\nfunc initramfsPaths(quirks quirks.Quirks) []string {\n\treturn []string{\n\t\tquirks.FirmwarePath(),\n\t}\n}\n\n// Compress builds the squashfs image in the specified destination folder.\n//\n// Components which should be placed to the initramfs are moved to the initramfsPath.\n// Ucode components are moved into a separate designated location.\nfunc (ext *Extension) Compress(ctx context.Context, squashPath, initramfsPath string, quirks quirks.Quirks) (string, error) {\n\tif err := ext.handleUcode(initramfsPath, quirks); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor _, path := range initramfsPaths(quirks) {\n\t\tif _, err := os.Stat(filepath.Join(ext.RootfsPath(), path)); err == nil {\n\t\t\tif err = moveFiles(filepath.Join(ext.RootfsPath(), path), filepath.Join(initramfsPath, path)); err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t}\n\t}\n\n\tsquashPath = filepath.Join(squashPath, fmt.Sprintf(\"%s.sqsh\", ext.Directory()))\n\n\tvar compressArgs []string\n\n\tif quirks.UseZSTDCompression() {\n\t\tcompressArgs = []string{\"-comp\", \"zstd\", \"-Xcompression-level\", \"18\"}\n\t} else {\n\t\tcompressArgs = []string{\"-comp\", \"xz\", \"-Xdict-size\", \"100%\"}\n\t}\n\n\tcmd := exec.CommandContext(ctx, \"mksquashfs\", append([]string{ext.RootfsPath(), squashPath, \"-all-root\", \"-noappend\", \"-no-progress\"}, compressArgs...)...)\n\tcmd.Stderr = os.Stderr\n\n\treturn squashPath, cmd.Run()\n}\n\nfunc appendBlob(dst io.Writer, srcPath string) error {\n\tsrc, err := os.Open(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer src.Close() //nolint:errcheck\n\n\tif _, err = io.Copy(dst, src); err != nil {\n\t\treturn err\n\t}\n\n\tif err = src.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.Remove(srcPath)\n}\n\nfunc (ext *Extension) handleUcode(initramfsPath string, quirks quirks.Quirks) error {\n\tfor _, ucode := range earlyCPUUcode(quirks) {\n\t\tmatches, err := filepath.Glob(filepath.Join(ext.RootfsPath(), ucode.glob))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(matches) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// if some ucode is found, append it to the blob in the initramfs\n\t\tif err = os.MkdirAll(filepath.Dir(filepath.Join(initramfsPath, ucode.dst)), 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdst, err := os.OpenFile(filepath.Join(initramfsPath, ucode.dst), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer dst.Close() //nolint:errcheck\n\n\t\tfor _, match := range matches {\n\t\t\tif err = appendBlob(dst, match); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tif err = dst.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc moveFiles(srcPath, dstPath string) error {\n\treturn handleFilesOp(srcPath, dstPath, os.Remove)\n}\n\nfunc copyFiles(srcPath, dstPath string) error {\n\treturn handleFilesOp(srcPath, dstPath, nil)\n}\n\nfunc handleFilesOp(srcPath, dstPath string, op func(string) error) error {\n\tst, err := os.Stat(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif st.IsDir() {\n\t\treturn handleDirectoryOp(st, srcPath, dstPath, op)\n\t}\n\n\treturn handleFileOp(st, srcPath, dstPath, op)\n}\n\nfunc moveFile(st fs.FileInfo, srcPath, dstPath string) error {\n\treturn handleFileOp(st, srcPath, dstPath, os.Remove)\n}\n\nfunc handleFileOp(st fs.FileInfo, srcPath, dstPath string, op func(string) error) error {\n\tsrc, err := os.Open(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer src.Close() //nolint:errcheck\n\n\tdst, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY, st.Mode().Perm())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer dst.Close() //nolint:errcheck\n\n\t_, err = io.Copy(dst, src)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif op != nil {\n\t\treturn op(srcPath)\n\t}\n\n\treturn nil\n}\n\nfunc handleDirectoryOp(st fs.FileInfo, srcPath, dstPath string, op func(string) error) error {\n\tif err := os.MkdirAll(dstPath, st.Mode().Perm()); err != nil {\n\t\treturn err\n\t}\n\n\tcontents, err := os.ReadDir(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, item := range contents {\n\t\tif err = handleFilesOp(filepath.Join(srcPath, item.Name()), filepath.Join(dstPath, item.Name()), op); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif op != nil {\n\t\treturn op(srcPath)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/extensions/discarder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"errors\"\n\t\"io\"\n)\n\n// discarder is used to implement ReadAt from a Reader\n// by reading, and discarding, data until the offset\n// is reached. It can only go forward. It is designed\n// for pipe-like files.\ntype discarder struct {\n\tr   io.Reader\n\tpos int64\n}\n\n// ReadAt implements ReadAt for a discarder.\n// It is an error for the offset to be negative.\nfunc (r *discarder) ReadAt(p []byte, off int64) (int, error) {\n\tif off-r.pos < 0 {\n\t\treturn 0, errors.New(\"negative seek on discarder not allowed\")\n\t}\n\n\tif off != r.pos {\n\t\ti, err := io.Copy(io.Discard, io.LimitReader(r.r, off-r.pos))\n\t\tif err != nil || i != off-r.pos {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tr.pos += i\n\t}\n\n\tn, err := io.ReadFull(r.r, p)\n\tif err != nil {\n\t\treturn n, err\n\t}\n\n\tr.pos += int64(n)\n\n\treturn n, err\n}\n\nvar _ io.ReaderAt = &discarder{}\n"
  },
  {
    "path": "internal/pkg/extensions/extensions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package extensions provides function to manage system extensions.\npackage extensions\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n)\n\n// Extension wraps the extensions.Extension type with additional methods.\ntype Extension struct {\n\t*extensions.Extension\n}\n"
  },
  {
    "path": "internal/pkg/extensions/extensions_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions_test\n\nimport (\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nfunc TestCompress(t *testing.T) {\n\t// Compress is going to change contents of the extension, copy to some temporary directory\n\textDir := t.TempDir()\n\n\trequire.NoError(t, exec.CommandContext(t.Context(), \"cp\", \"-r\", \"testdata/good/extension1\", extDir).Run())\n\n\texts, err := extensions.List(extDir)\n\trequire.NoError(t, err)\n\n\trequire.Len(t, exts, 1)\n\n\text := exts[0]\n\n\tsquashDest, initramfsDest := t.TempDir(), t.TempDir()\n\tsquashFile, err := ext.Compress(t.Context(), squashDest, initramfsDest, quirks.New(\"\"))\n\tassert.NoError(t, err)\n\n\tassert.FileExists(t, squashFile)\n\tassert.FileExists(t, filepath.Join(initramfsDest, \"usr\", \"lib\", \"firmware\", \"amd\", \"cpu\"))\n}\n"
  },
  {
    "path": "internal/pkg/extensions/kernel_modules.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package extensions provides function to manage system extensions.\npackage extensions\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/u-root/u-root/pkg/cpio\"\n\t\"github.com/ulikunitz/xz\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// ProvidesKernelModules returns true if the extension provides kernel modules.\nfunc (ext *Extension) ProvidesKernelModules(quirks quirks.Quirks) bool {\n\tif _, err := os.Stat(ext.KernelModuleDirectory(quirks)); errors.Is(err, fs.ErrNotExist) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// KernelModuleDirectory returns the path to the kernel modules directory.\nfunc (ext *Extension) KernelModuleDirectory(quirks quirks.Quirks) string {\n\treturn filepath.Join(ext.RootfsPath(), quirks.KernelModulesPath())\n}\n\nfunc autoDecompress(r io.Reader) (io.Reader, error) {\n\tvar magic [4]byte\n\n\tif _, err := r.Read(magic[:]); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsrc := io.MultiReader(bytes.NewReader(magic[:]), r)\n\n\t// xz magic\n\tif bytes.Equal(magic[:], []byte{0xfd, '7', 'z', 'X'}) {\n\t\treturn xz.NewReader(src)\n\t}\n\n\treturn zstd.NewReader(src)\n}\n\n// GenerateKernelModuleDependencyTreeExtension generates a kernel module dependency tree extension.\n//\n//nolint:gocyclo\nfunc GenerateKernelModuleDependencyTreeExtension(\n\tctx context.Context,\n\textensionPathsWithKernelModules []string,\n\tinitramfsPath, scratchPath string,\n\tquirks quirks.Quirks,\n\tprintFunc func(format string, v ...any),\n) (*Extension, error) {\n\tprintFunc(\"preparing to run depmod to generate kernel modules dependency tree\")\n\n\ttempDir, err := os.MkdirTemp(\"\", \"ext-modules\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer logErr(\"removing temporary directory\", func() error {\n\t\treturn os.RemoveAll(tempDir)\n\t})\n\n\tinitramfsxz, err := os.Open(initramfsPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer logErr(\"closing initramfs\", func() error {\n\t\treturn initramfsxz.Close()\n\t})\n\n\tr, err := autoDecompress(initramfsxz)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttempRootfsFile := filepath.Join(tempDir, constants.RootfsAsset)\n\n\tif err = extractRootfsFromInitramfs(r, tempRootfsFile); err != nil {\n\t\treturn nil, fmt.Errorf(\"error extacting cpio: %w\", err)\n\t}\n\n\tkernelModulesPath := quirks.KernelModulesPath()\n\n\t// extract /usr/lib/modules from the squashfs under a temporary root to run depmod on it\n\ttempLibModules := filepath.Join(tempDir, \"modules\")\n\n\tif err = unsquash(ctx, tempRootfsFile, tempLibModules, kernelModulesPath); err != nil {\n\t\treturn nil, fmt.Errorf(\"error running unsquashfs: %w\", err)\n\t}\n\n\trootfsKernelModulesPath := filepath.Join(tempLibModules, kernelModulesPath)\n\n\t// under the /usr/lib/modules there should be the only path which is the kernel version\n\tcontents, err := os.ReadDir(rootfsKernelModulesPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(contents) != 1 || !contents[0].IsDir() {\n\t\treturn nil, fmt.Errorf(\"invalid kernel modules path: %s\", rootfsKernelModulesPath)\n\t}\n\n\tkernelVersionPath := contents[0].Name()\n\n\t// copy to the same location modules from all extensions\n\tfor _, path := range extensionPathsWithKernelModules {\n\t\tif err = copyFiles(filepath.Join(path, kernelVersionPath), filepath.Join(rootfsKernelModulesPath, kernelVersionPath)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"copying kernel modules from %s failed: %w\", path, err)\n\t\t}\n\t}\n\n\tprintFunc(\"running depmod to generate kernel modules dependency tree\")\n\n\tif err = depmod(ctx, rootfsKernelModulesPath, kernelVersionPath); err != nil {\n\t\treturn nil, fmt.Errorf(\"error running depmod: %w\", err)\n\t}\n\n\t// we want the extension to survive this function, so not storing in a temporary directory\n\tkernelModulesDependencyTreeStagingDir := filepath.Join(scratchPath, \"modules.dep\")\n\n\t// we want to make sure the root directory has the right permissions.\n\tif err := os.MkdirAll(kernelModulesDependencyTreeStagingDir, 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tkernelModulesDepenencyTreeDirectory := filepath.Join(kernelModulesDependencyTreeStagingDir, kernelModulesPath, kernelVersionPath)\n\n\tif err := os.MkdirAll(kernelModulesDepenencyTreeDirectory, 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := findAndMoveKernelModulesDepFiles(kernelModulesDepenencyTreeDirectory, filepath.Join(rootfsKernelModulesPath, kernelVersionPath)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tkernelModulesDepTreeExtension := extensions.New(\n\t\tkernelModulesDependencyTreeStagingDir, \"modules.dep\",\n\t\textensions.Manifest{\n\t\t\tVersion: kernelVersionPath,\n\t\t\tMetadata: extensions.Metadata{\n\t\t\t\tName:        \"modules.dep\",\n\t\t\t\tVersion:     kernelVersionPath,\n\t\t\t\tAuthor:      \"Talos Machinery\",\n\t\t\t\tDescription: \"Combined modules.dep for all extensions\",\n\t\t\t},\n\t\t},\n\t)\n\n\treturn &Extension{kernelModulesDepTreeExtension}, nil\n}\n\nfunc logErr(msg string, f func() error) {\n\t// if file is already closed, ignore the error\n\tif err := f(); err != nil && !errors.Is(err, os.ErrClosed) {\n\t\tlog.Println(msg, err)\n\t}\n}\n\nfunc extractRootfsFromInitramfs(r io.Reader, rootfsFilePath string) error {\n\trecReader := cpio.Newc.Reader(&discarder{r: r})\n\n\treturn cpio.ForEachRecord(recReader, func(r cpio.Record) error {\n\t\tif r.Name != constants.RootfsAsset {\n\t\t\treturn nil\n\t\t}\n\n\t\treader := io.NewSectionReader(r.ReaderAt, 0, int64(r.FileSize))\n\n\t\tf, err := os.Create(rootfsFilePath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer logErr(\"closing rootfs\", func() error {\n\t\t\treturn f.Close()\n\t\t})\n\n\t\t_, err = io.Copy(f, reader)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn f.Close()\n\t})\n}\n\nfunc unsquash(ctx context.Context, squashfsPath, dest, path string) error {\n\tcmd := exec.CommandContext(ctx, \"unsquashfs\", \"-no-xattrs\", \"-d\", dest, \"-f\", \"-n\", squashfsPath, path)\n\tcmd.Stderr = os.Stderr\n\n\treturn cmd.Run()\n}\n\nfunc depmod(ctx context.Context, baseDir, kernelVersionPath string) error {\n\t// Do not trim /usr, because it is needed for depmod\n\tbaseDir = strings.TrimSuffix(baseDir, \"/lib/modules\")\n\n\tcmd := exec.CommandContext(ctx, \"depmod\", \"--all\", \"--basedir\", baseDir, \"--config\", \"/etc/modules.d/10-extra-modules.conf\", kernelVersionPath)\n\tcmd.Stderr = os.Stderr\n\n\treturn cmd.Run()\n}\n\nfunc findAndMoveKernelModulesDepFiles(dest, kernelModulesPath string) error {\n\tfs, err := os.ReadDir(kernelModulesPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, f := range fs {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(f.Name(), \"modules.\") {\n\t\t\tfs, err := f.Info()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := moveFile(fs, filepath.Join(kernelModulesPath, f.Name()), filepath.Join(dest, f.Name())); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/extensions/list.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"cmp\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n)\n\n// List prepared unpacked extensions under rootPath.\nfunc List(rootPath string) ([]*Extension, error) {\n\titems, err := os.ReadDir(rootPath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tif len(items) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tslices.SortFunc(items, func(a, b os.DirEntry) int { return cmp.Compare(a.Name(), b.Name()) })\n\n\tresult := make([]*Extension, 0, len(items))\n\n\tfor _, item := range items {\n\t\tif !item.IsDir() {\n\t\t\treturn nil, fmt.Errorf(\"unexpected non-directory entry: %q\", item.Name())\n\t\t}\n\n\t\text, err := extensions.Load(filepath.Join(rootPath, item.Name()))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error loading extension %s: %w\", item.Name(), err)\n\t\t}\n\n\t\tresult = append(result, &Extension{ext})\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/pkg/extensions/list_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/extensions\"\n)\n\nfunc TestList(t *testing.T) {\n\textensions, err := extensions.List(\"testdata/good/\")\n\trequire.NoError(t, err)\n\n\trequire.Len(t, extensions, 1)\n\n\tassert.Equal(t, \"gvisor\", extensions[0].Manifest.Metadata.Name)\n}\n"
  },
  {
    "path": "internal/pkg/extensions/testdata/good/extension1/manifest.yaml",
    "content": "version: v1alpha1\nmetadata:\n  name: gvisor\n  version: 20220117.0-v1.0.0\n  author: Andrew Rynhard\n  description: >\n    This system extension provides gVisor using containerd's runtime handler.\n  compatibility:\n    talos:\n      version: \">= v1.0.0\"\n"
  },
  {
    "path": "internal/pkg/extensions/testdata/good/extension1/rootfs/usr/lib/firmware/amd/cpu",
    "content": ""
  },
  {
    "path": "internal/pkg/extensions/testdata/good/extension1/rootfs/usr/lib/ld-linux-x86-64.so.2",
    "content": ""
  },
  {
    "path": "internal/pkg/install/install.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package install provides functionality to run the installer container for Talos.\npackage install\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/cio\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/go-kmsg\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\tcontainerdrunner \"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner/containerd\"\n\t\"github.com/siderolabs/talos/internal/pkg/capability\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/console\"\n\t\"github.com/siderolabs/talos/internal/pkg/environment\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\tconfigcore \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// RunInstallerContainer performs an installation via the installer container.\n//\n//nolint:gocyclo,cyclop\nfunc RunInstallerContainer(\n\tdisk, platform, ref string,\n\tcfg configcore.Config,\n\tcfgContainer configcore.Container,\n\tresources state.State,\n\tregistryBuilder image.RegistriesBuilder,\n\topts ...Option,\n) error {\n\tconst containerID = \"upgrade\"\n\n\toptions := Options{Pull: true} //nolint:staticcheck\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tctx = namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)\n\n\tclient, err := containerd.New(constants.SystemContainerdAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\tvar done func(context.Context) error\n\n\tctx, done, err = client.WithLease(ctx)\n\tdefer done(ctx) //nolint:errcheck\n\n\tvar img containerd.Image\n\n\tif !options.Pull {\n\t\timg, err = client.GetImage(ctx, ref)\n\t}\n\n\tif img == nil || err != nil && errdefs.IsNotFound(err) {\n\t\tlog.Printf(\"pulling %q\", ref)\n\n\t\timg, err = image.Pull(ctx, registryBuilder, resources, client, ref, image.WithProgressReporter(console.NewProgressReporter))\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// See if there's previous container/snapshot to clean up\n\tvar oldcontainer containerd.Container\n\n\tif oldcontainer, err = client.LoadContainer(ctx, containerID); err == nil {\n\t\tif err = oldcontainer.Delete(ctx, containerd.WithSnapshotCleanup); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting old container instance: %w\", err)\n\t\t}\n\t}\n\n\tif err = client.SnapshotService(\"\").Remove(ctx, containerID); err != nil && !errdefs.IsNotFound(err) {\n\t\treturn fmt.Errorf(\"error cleaning up stale snapshot: %w\", err)\n\t}\n\n\tmounts := []specs.Mount{\n\t\t{Type: \"bind\", Destination: \"/dev\", Source: \"/dev\", Options: []string{\"rbind\", \"rshared\", \"rw\"}},\n\t}\n\n\t// mount the machined socket into the container for upgrade pre-checks if the socket exists\n\tif _, err = os.Stat(constants.MachineSocketPath); err == nil {\n\t\tmounts = append(mounts,\n\t\t\tspecs.Mount{Type: \"bind\", Destination: constants.MachineSocketPath, Source: constants.MachineSocketPath, Options: []string{\"rbind\", \"rshared\", \"ro\"}},\n\t\t)\n\t}\n\n\t// mount the efivars into the container if the efivars directory exists\n\tif _, err = os.Stat(constants.EFIVarsMountPoint); err == nil {\n\t\tmounts = append(mounts,\n\t\t\tspecs.Mount{Type: \"efivarfs\", Source: \"efivarfs\", Destination: constants.EFIVarsMountPoint, Options: []string{\"rw\", \"nosuid\", \"nodev\", \"noexec\", \"relatime\"}},\n\t\t)\n\t}\n\n\t// mount the /.extra directory into the container if the directory exists\n\tif _, err = os.Stat(constants.SDStubDynamicInitrdPath); err == nil {\n\t\tmounts = append(mounts,\n\t\t\tspecs.Mount{Type: \"bind\", Destination: constants.SDStubDynamicInitrdPath, Source: constants.SDStubDynamicInitrdPath, Options: []string{\"rbind\", \"rshared\", \"ro\"}},\n\t\t)\n\t}\n\n\t// TODO(andrewrynhard): To handle cases when the newer version changes the\n\t// platform name, this should be determined in the installer container.\n\tconfig := constants.ConfigNone\n\tif c := procfs.ProcCmdline().Get(constants.KernelParamConfig).First(); c != nil {\n\t\tconfig = *c\n\t}\n\n\tupgrade := strconv.FormatBool(options.Upgrade)\n\tforce := strconv.FormatBool(options.Force)\n\tzero := strconv.FormatBool(options.Zero)\n\n\targs := []string{\n\t\t\"/bin/installer\",\n\t\t\"install\",\n\t\t\"--disk=\" + disk,\n\t\t\"--platform=\" + platform,\n\t\t\"--config=\" + config,\n\t\t\"--upgrade=\" + upgrade,\n\t\t\"--force=\" + force,\n\t\t\"--zero=\" + zero,\n\t}\n\n\tfor _, arg := range options.ExtraKernelArgs {\n\t\targs = append(args, \"--extra-kernel-arg\", arg)\n\t}\n\n\tfor _, preservedArg := range []string{\n\t\tconstants.KernelParamSideroLink,\n\t\tconstants.KernelParamEventsSink,\n\t\tconstants.KernelParamLoggingKernel,\n\t\tconstants.KernelParamEquinixMetalEvents,\n\t\tconstants.KernelParamAuditdDisabled,\n\t\tconstants.KernelParamDashboardDisabled,\n\t\tconstants.KernelParamNetIfnames,\n\t\tconstants.KernelParamEnforceModuleSigVerify,\n\t} {\n\t\tif c := procfs.ProcCmdline().Get(preservedArg).First(); c != nil {\n\t\t\targs = append(args, \"--extra-kernel-arg\", fmt.Sprintf(\"%s=%s\", preservedArg, *c))\n\t\t}\n\t}\n\n\tspecOpts := []oci.SpecOpts{\n\t\toci.WithImageConfig(img),\n\t\toci.WithProcessArgs(args...),\n\t\toci.WithHostNamespace(specs.NetworkNamespace),\n\t\toci.WithHostNamespace(specs.PIDNamespace),\n\t\toci.WithMounts(mounts),\n\t\toci.WithHostHostsFile,\n\t\toci.WithHostResolvconf,\n\t\toci.WithParentCgroupDevices,\n\t\toci.WithCapabilities(capability.AllGrantableCapabilities()),\n\t\toci.WithMaskedPaths(nil),\n\t\toci.WithReadonlyPaths(nil),\n\t\toci.WithWriteableSysfs,\n\t\toci.WithWriteableCgroupfs,\n\t\toci.WithApparmorProfile(\"\"),\n\t\toci.WithSeccompUnconfined,\n\t\toci.WithAllDevicesAllowed,\n\t\toci.WithEnv(environment.Get(cfg)),\n\t}\n\n\tif selinux.IsEnabled() {\n\t\tspecOpts = append(specOpts, oci.WithSelinuxLabel(constants.SelinuxLabelInstaller))\n\t}\n\n\tcontainerOpts := []containerd.NewContainerOpts{\n\t\tcontainerd.WithImage(img),\n\t\tcontainerd.WithNewSnapshot(containerID, img),\n\t\tcontainerd.WithNewSpec(specOpts...),\n\t}\n\n\tcontainer, err := client.NewContainer(ctx, containerID, containerOpts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer container.Delete(ctx, containerd.WithSnapshotCleanup) //nolint:errcheck\n\n\tf, err := os.OpenFile(\"/dev/kmsg\", os.O_RDWR|unix.O_CLOEXEC|unix.O_NONBLOCK|unix.O_NOCTTY, 0o666)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open /dev/kmsg: %w\", err)\n\t}\n\t//nolint:errcheck\n\tdefer f.Close()\n\n\tw := &kmsg.Writer{KmsgWriter: f}\n\n\tvar r interface {\n\t\tio.Reader\n\t\tWaitAndClose(context.Context, containerd.Task)\n\t}\n\n\tif cfgContainer != nil {\n\t\tvar configBytes []byte\n\n\t\tconfigBytes, err = cfgContainer.Bytes()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr = &containerdrunner.StdinCloser{\n\t\t\tStdin:  bytes.NewReader(configBytes),\n\t\t\tCloser: make(chan struct{}),\n\t\t}\n\t}\n\n\tcreator := cio.NewCreator(cio.WithStreams(r, w, w))\n\n\tt, err := container.NewTask(ctx, creator)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif r != nil {\n\t\tgo r.WaitAndClose(ctx, t)\n\t}\n\n\tdefer t.Delete(ctx) //nolint:errcheck\n\n\tif err = t.Start(ctx); err != nil {\n\t\treturn fmt.Errorf(\"failed to start %q task: %w\", \"upgrade\", err)\n\t}\n\n\tstatusC, err := t.Wait(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed waiting for %q task: %w\", \"upgrade\", err)\n\t}\n\n\tstatus := <-statusC\n\n\tcode := status.ExitCode()\n\tif code != 0 {\n\t\treturn fmt.Errorf(\"task %q failed: exit code %d\", \"upgrade\", code)\n\t}\n\n\treturn nil\n}\n\n// OptionsFromUpgradeRequest builds installer options from upgrade request.\nfunc OptionsFromUpgradeRequest(r runtime.Runtime, in *machineapi.UpgradeRequest) []Option {\n\topts := []Option{\n\t\tWithUpgrade(true),\n\t\tWithForce(!in.GetPreserve()),\n\t}\n\n\tif r.Config() != nil && r.Config().Machine() != nil {\n\t\topts = append(opts, WithExtraKernelArgs(r.Config().Machine().Install().ExtraKernelArgs()))\n\t}\n\n\treturn opts\n}\n"
  },
  {
    "path": "internal/pkg/install/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install\n\n// Option is a functional option.\ntype Option func(o *Options) error\n\n// Options describes the install options.\ntype Options struct {\n\t// Deprecated: Pull is not used in new Lifecycle API.\n\tPull            bool\n\tForce           bool\n\tUpgrade         bool\n\tZero            bool\n\tExtraKernelArgs []string\n}\n\n// DefaultInstallOptions returns default options.\nfunc DefaultInstallOptions() Options {\n\treturn Options{}\n}\n\n// Apply list of Option.\nfunc (o *Options) Apply(opts ...Option) error {\n\tfor _, opt := range opts {\n\t\tif err := opt(o); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// WithOptions sets Options as a whole.\nfunc WithOptions(opts Options) Option {\n\treturn func(o *Options) error {\n\t\t*o = opts\n\n\t\treturn nil\n\t}\n}\n\n// WithPull sets the pull option.\n//\n// Deprecated: Pull is not used in new Lifecycle API.\nfunc WithPull(b bool) Option {\n\treturn func(o *Options) error {\n\t\to.Pull = b\n\n\t\treturn nil\n\t}\n}\n\n// WithForce sets the force option.\nfunc WithForce(b bool) Option {\n\treturn func(o *Options) error {\n\t\to.Force = b\n\n\t\treturn nil\n\t}\n}\n\n// WithUpgrade sets the upgrade option.\nfunc WithUpgrade(b bool) Option {\n\treturn func(o *Options) error {\n\t\to.Upgrade = b\n\n\t\treturn nil\n\t}\n}\n\n// WithZero sets the zero option.\nfunc WithZero(b bool) Option {\n\treturn func(o *Options) error {\n\t\to.Zero = b\n\n\t\treturn nil\n\t}\n}\n\n// WithExtraKernelArgs sets the extra args.\nfunc WithExtraKernelArgs(s []string) Option {\n\treturn func(o *Options) error {\n\t\to.ExtraKernelArgs = s\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/install/pull.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage install\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\tcontainerd \"github.com/containerd/containerd/v2/client\"\n\t\"github.com/containerd/containerd/v2/pkg/cio\"\n\t\"github.com/containerd/containerd/v2/pkg/namespaces\"\n\t\"github.com/containerd/containerd/v2/pkg/oci\"\n\t\"github.com/containerd/errdefs\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image\"\n\t\"github.com/siderolabs/talos/internal/pkg/containers/image/console\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// PullAndValidateInstallerImage pulls down the installer and validates that it can run.\n//\n//nolint:gocyclo\nfunc PullAndValidateInstallerImage(ctx context.Context, resources state.State, registryBuilder image.RegistriesBuilder, ref string) error {\n\t// Pull down specified installer image early so we can bail if it doesn't exist in the upstream registry\n\tcontainerdctx := namespaces.WithNamespace(ctx, constants.SystemContainerdNamespace)\n\n\tconst containerID = \"validate\"\n\n\tclient, err := containerd.New(constants.SystemContainerdAddress)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer client.Close() //nolint:errcheck\n\n\timg, err := image.Pull(containerdctx, registryBuilder, resources, client, ref,\n\t\timage.WithSkipIfAlreadyPulled(),\n\t\timage.WithMaxNotFoundRetries(1),\n\t\timage.WithProgressReporter(console.NewProgressReporter),\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// See if there's previous container/snapshot to clean up\n\tvar oldcontainer containerd.Container\n\n\tif oldcontainer, err = client.LoadContainer(containerdctx, containerID); err == nil {\n\t\tif err = oldcontainer.Delete(containerdctx, containerd.WithSnapshotCleanup); err != nil {\n\t\t\treturn fmt.Errorf(\"error deleting old container instance: %w\", err)\n\t\t}\n\t}\n\n\tif err = client.SnapshotService(\"\").Remove(containerdctx, containerID); err != nil && !errdefs.IsNotFound(err) {\n\t\treturn fmt.Errorf(\"error cleaning up stale snapshot: %w\", err)\n\t}\n\n\t// Launch the container with a known help command for a simple check to make sure the image is valid\n\targs := []string{\n\t\t\"/bin/installer\",\n\t\t\"--help\",\n\t}\n\n\tspecOpts := []oci.SpecOpts{\n\t\toci.WithImageConfig(img),\n\t\toci.WithProcessArgs(args...),\n\t}\n\n\tif selinux.IsEnabled() {\n\t\tspecOpts = append(specOpts, oci.WithSelinuxLabel(constants.SelinuxLabelInstaller))\n\t}\n\n\tcontainerOpts := []containerd.NewContainerOpts{\n\t\tcontainerd.WithImage(img),\n\t\tcontainerd.WithNewSnapshot(containerID, img),\n\t\tcontainerd.WithNewSpec(specOpts...),\n\t}\n\n\tcontainer, err := client.NewContainer(containerdctx, containerID, containerOpts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer container.Delete(containerdctx, containerd.WithSnapshotCleanup)\n\n\ttask, err := container.NewTask(containerdctx, cio.NullIO)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer task.Delete(containerdctx)\n\n\texitStatusC, err := task.Wait(containerdctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = task.Start(containerdctx); err != nil {\n\t\treturn err\n\t}\n\n\tstatus := <-exitStatusC\n\n\tcode, _, err := status.Result()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif code != 0 {\n\t\treturn errors.New(\"installer help returned non-zero exit. assuming invalid installer\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/logind/broker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logind\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// DBusBroker implements simplified D-Bus broker which allows to connect\n// kubelet D-Bus connection with Talos logind mock.\n//\n// Broker doesn't actually implement auth, and it is supposed that service\n// connects on one socket, while a client connects on another socket.\ntype DBusBroker struct {\n\tlistenService, listenClient net.Listener\n}\n\n// NewBroker initializes new broker.\nfunc NewBroker(ctx context.Context, serviceSocketPath, clientSocketPath string) (*DBusBroker, error) {\n\t// remove socket paths as with Docker mode paths might persist across container restarts\n\tfor _, socketPath := range []string{serviceSocketPath, clientSocketPath} {\n\t\tif err := os.RemoveAll(socketPath); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error cleaning up D-Bus socket paths: %w\", err)\n\t\t}\n\t}\n\n\tbroker := &DBusBroker{}\n\n\tvar err error\n\n\tbroker.listenService, err = (&net.ListenConfig{}).Listen(ctx, \"unix\", serviceSocketPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = selinux.SetLabel(serviceSocketPath, constants.DBusServiceSocketLabel); err != nil {\n\t\treturn nil, err\n\t}\n\n\tbroker.listenClient, err = (&net.ListenConfig{}).Listen(ctx, \"unix\", clientSocketPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = selinux.SetLabel(clientSocketPath, constants.DBusClientSocketLabel); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn broker, nil\n}\n\n// Close the listen sockets.\nfunc (broker *DBusBroker) Close() error {\n\tif err := broker.listenClient.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn broker.listenService.Close()\n}\n\n// Run the broker.\nfunc (broker *DBusBroker) Run(ctx context.Context) error {\n\teg, ctx := errgroup.WithContext(ctx)\n\n\tvar (\n\t\tconnClient, connService net.Conn\n\t\tmu                      sync.Mutex\n\t)\n\n\teg.Go(func() error { return broker.run(ctx, broker.listenService, &mu, &connService, &connClient) })\n\teg.Go(func() error { return broker.run(ctx, broker.listenClient, &mu, &connClient, &connService) })\n\n\treturn eg.Wait()\n}\n\nfunc (broker *DBusBroker) run(ctx context.Context, l net.Listener, mu *sync.Mutex, ours, theirs *net.Conn) error {\n\tfor ctx.Err() == nil {\n\t\tconn, err := l.Accept()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, net.ErrClosed) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\thandleConn(ctx, conn.(*net.UnixConn), mu, ours, theirs)\n\t}\n\n\treturn nil\n}\n\nfunc extractFiles(oob []byte) []int {\n\tif len(oob) == 0 {\n\t\treturn nil\n\t}\n\n\tvar fds []int\n\n\tscms, err := syscall.ParseSocketControlMessage(oob)\n\tif err == nil {\n\t\tfor _, scm := range scms {\n\t\t\tvar files []int\n\n\t\t\tfiles, err = syscall.ParseUnixRights(&scm)\n\t\t\tif err == nil {\n\t\t\t\tfds = append(fds, files...)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fds\n}\n\n//nolint:gocyclo\nfunc handleConn(ctx context.Context, conn *net.UnixConn, mu *sync.Mutex, ours, theirs *net.Conn) {\n\tdefer conn.Close() //nolint: errcheck\n\n\tr := bufio.NewReader(conn)\n\n\tif err := handleAuth(r, conn); err != nil {\n\t\tlog.Printf(\"auth failed: %s\", err)\n\n\t\treturn\n\t}\n\n\tmu.Lock()\n\n\t*ours = conn\n\n\tmu.Unlock()\n\n\tdefer func() {\n\t\tmu.Lock()\n\n\t\t*ours = nil\n\n\t\tmu.Unlock()\n\t}()\n\n\tbuf := make([]byte, 4096)\n\toob := make([]byte, 4096)\n\n\tfor ctx.Err() == nil {\n\t\tvar (\n\t\t\tn, oobn int\n\t\t\terr     error\n\t\t)\n\n\t\tif r.Buffered() > 0 {\n\t\t\t// read remaining buffered data\n\t\t\tn, err = r.Read(buf[:r.Buffered()])\n\t\t} else {\n\t\t\t// read the message and OOB data from the UNIX socket\n\t\t\tn, oobn, _, _, err = conn.ReadMsgUnix(buf, oob)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// capture all file descriptors in the OOB message\n\t\t// broker needs to close the file descriptors as they get passed to the other peer\n\t\tfds := extractFiles(oob[:oobn])\n\n\t\t// find the other side of the connection\n\t\tvar w net.Conn\n\n\t\tfor range 10 {\n\t\t\tmu.Lock()\n\n\t\t\tw = *theirs\n\n\t\t\tmu.Unlock()\n\n\t\t\tif w != nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-time.After(time.Second):\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif w == nil {\n\t\t\t// drop data, as there's no other connection\n\t\t\tcontinue\n\t\t}\n\n\t\t// send the message and OOB date\n\t\t// this will pass the file descriptors if they are in the OOB date\n\t\tif _, _, err = w.(*net.UnixConn).WriteMsgUnix(buf[:n], oob[:oobn], nil); err != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// close fds to make sure broker doesn't hold the fds on its side\n\t\tfor _, fd := range fds {\n\t\t\tsyscall.Close(fd) //nolint:errcheck\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc handleAuth(r *bufio.Reader, w io.Writer) error {\n\treadLine := func() (string, error) {\n\t\tl, err := r.ReadString('\\n')\n\t\tif err != nil {\n\t\t\treturn l, err\n\t\t}\n\n\t\tl = strings.TrimRight(l, \"\\r\\n\")\n\n\t\treturn l, nil\n\t}\n\n\t// first, should receive AUTH command preceded by zero byte\n\tline, err := readLine()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif line != \"\\x00AUTH\" {\n\t\treturn fmt.Errorf(\"unexpected line, expected AUTH: %q\", line)\n\t}\n\n\tif _, err = w.Write([]byte(\"REJECTED EXTERNAL\\r\\n\")); err != nil {\n\t\treturn err\n\t}\n\n\t// now real auth command\n\tline, err = readLine()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !strings.HasPrefix(line, \"AUTH EXTERNAL\") {\n\t\treturn fmt.Errorf(\"unexpected line, expected AUTH EXTERNAL: %q\", line)\n\t}\n\n\tif _, err = w.Write([]byte(\"OK 1234deadbeef\\r\\n\")); err != nil {\n\t\treturn err\n\t}\n\n\t// negotiate unix FDs\n\tline, err = readLine()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif line != \"NEGOTIATE_UNIX_FD\" {\n\t\treturn fmt.Errorf(\"unexpected line, expected NEGOTIATE_UNIX_FD: %q\", line)\n\t}\n\n\tif _, err = w.Write([]byte(\"AGREE_UNIX_FD\\r\\n\")); err != nil {\n\t\treturn err\n\t}\n\n\t// BEGIN\n\tline, err = readLine()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif line != \"BEGIN\" {\n\t\treturn fmt.Errorf(\"unexpected line, expected BEGIN: %q\", line)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/logind/dbus.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logind\n\nimport \"github.com/godbus/dbus/v5\"\n\nconst (\n\tdbusPath       = dbus.ObjectPath(\"/org/freedesktop/DBus\")\n\tdbusInterface  = \"org.freedesktop.DBus\"\n\tpropsInterface = \"org.freedesktop.DBus.Properties\"\n)\n\ntype dbusMock struct{}\n\nfunc (dbusMock) Hello() (string, *dbus.Error) {\n\treturn \"id\", nil\n}\n\nfunc (dbusMock) AddMatch(_ string) *dbus.Error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/logind/kubelet_mock_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logind_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/godbus/dbus/v5\"\n)\n\nconst (\n\tlogindService   = \"org.freedesktop.login1\"\n\tlogindObject    = dbus.ObjectPath(\"/org/freedesktop/login1\")\n\tlogindInterface = \"org.freedesktop.login1.Manager\"\n)\n\ntype dBusConnector interface {\n\tObject(dest string, path dbus.ObjectPath) dbus.BusObject\n\tAddMatchSignal(options ...dbus.MatchOption) error\n\tSignal(ch chan<- *dbus.Signal)\n\tClose() error\n}\n\n// DBusCon has functions that can be used to interact with systemd and logind over dbus.\ntype DBusCon struct {\n\tSystemBus dBusConnector\n}\n\nfunc NewDBusCon(path string) (*DBusCon, error) {\n\tconn, err := dbus.Connect(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &DBusCon{\n\t\tSystemBus: conn,\n\t}, nil\n}\n\nfunc (bus *DBusCon) Close() error {\n\treturn bus.SystemBus.Close()\n}\n\n// InhibitLock is a lock obtained after creating an systemd inhibitor by calling InhibitShutdown().\ntype InhibitLock uint32\n\n// CurrentInhibitDelay returns the current delay inhibitor timeout value as configured in logind.conf(5).\n// see https://www.freedesktop.org/software/systemd/man/logind.conf.html for more details.\nfunc (bus *DBusCon) CurrentInhibitDelay() (time.Duration, error) {\n\tobj := bus.SystemBus.Object(logindService, logindObject)\n\n\tres, err := obj.GetProperty(logindInterface + \".InhibitDelayMaxUSec\")\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed reading InhibitDelayMaxUSec property from logind: %w\", err)\n\t}\n\n\tdelay, ok := res.Value().(uint64)\n\tif !ok {\n\t\treturn 0, errors.New(\"InhibitDelayMaxUSec from logind is not a uint64 as expected\")\n\t}\n\n\t// InhibitDelayMaxUSec is in microseconds\n\tduration := time.Duration(delay) * time.Microsecond\n\n\treturn duration, nil\n}\n\n// InhibitShutdown creates an systemd inhibitor by calling logind's Inhibt() and returns the inhibitor lock\n// see https://www.freedesktop.org/wiki/Software/systemd/inhibit/ for more details.\nfunc (bus *DBusCon) InhibitShutdown() (InhibitLock, error) {\n\tobj := bus.SystemBus.Object(logindService, logindObject)\n\twhat := \"shutdown\"\n\twho := \"kubelet\"\n\twhy := \"Kubelet needs time to handle node shutdown\"\n\tmode := \"delay\"\n\n\tcall := obj.Call(\"org.freedesktop.login1.Manager.Inhibit\", 0, what, who, why, mode)\n\tif call.Err != nil {\n\t\treturn InhibitLock(0), fmt.Errorf(\"failed creating systemd inhibitor: %w\", call.Err)\n\t}\n\n\tvar fd uint32\n\n\terr := call.Store(&fd)\n\tif err != nil {\n\t\treturn InhibitLock(0), fmt.Errorf(\"failed storing inhibit lock file descriptor: %w\", err)\n\t}\n\n\treturn InhibitLock(fd), nil\n}\n\n// ReleaseInhibitLock will release the underlying inhibit lock which will cause the shutdown to start.\nfunc (bus *DBusCon) ReleaseInhibitLock(lock InhibitLock) error {\n\terr := syscall.Close(int(lock))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to close systemd inhibitor lock: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// MonitorShutdown detects the a node shutdown by watching for \"PrepareForShutdown\" logind events.\n// see https://www.freedesktop.org/wiki/Software/systemd/inhibit/ for more details.\nfunc (bus *DBusCon) MonitorShutdown() (<-chan bool, error) {\n\terr := bus.SystemBus.AddMatchSignal(dbus.WithMatchInterface(logindInterface), dbus.WithMatchMember(\"PrepareForShutdown\"), dbus.WithMatchObjectPath(\"/org/freedesktop/login1\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbusChan := make(chan *dbus.Signal, 1)\n\tbus.SystemBus.Signal(busChan)\n\n\tshutdownChan := make(chan bool, 1)\n\n\tgo func() {\n\t\tfor {\n\t\t\tevent, ok := <-busChan\n\t\t\tif !ok {\n\t\t\t\tclose(shutdownChan)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif event == nil || len(event.Body) == 0 {\n\t\t\t\tlog.Printf(\"failed obtaining shutdown event, PrepareForShutdown event was empty\")\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tshutdownActive, ok := event.Body[0].(bool)\n\t\t\tif !ok {\n\t\t\t\tlog.Printf(\"Failed obtaining shutdown event, PrepareForShutdown event was not bool type as expected\")\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tshutdownChan <- shutdownActive\n\t\t}\n\t}()\n\n\treturn shutdownChan, nil\n}\n"
  },
  {
    "path": "internal/pkg/logind/logind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package logind provides D-Bus logind mock to facilitate graceful kubelet shutdown.\npackage logind\n\nimport (\n\t\"slices\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/godbus/dbus/v5\"\n\t\"github.com/godbus/dbus/v5/prop\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tlogindService   = \"org.freedesktop.login1\"\n\tlogindObject    = dbus.ObjectPath(\"/org/freedesktop/login1\")\n\tlogindInterface = \"org.freedesktop.login1.Manager\"\n)\n\n// InhibitMaxDelay is the maximum delay for graceful shutdown.\nconst InhibitMaxDelay = 40 * constants.KubeletShutdownGracePeriod\n\ntype logindMock struct {\n\tmu          sync.Mutex\n\tinhibitPipe []int\n}\n\nfunc (mock *logindMock) Inhibit(what, who, why, mode string) (dbus.UnixFD, *dbus.Error) {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\tfor _, fd := range mock.inhibitPipe {\n\t\tsyscall.Close(fd) //nolint:errcheck\n\t}\n\n\tmock.inhibitPipe = make([]int, 2)\n\tif err := syscall.Pipe2(mock.inhibitPipe, syscall.O_CLOEXEC); err != nil {\n\t\treturn dbus.UnixFD(0), dbus.MakeFailedError(err)\n\t}\n\n\treturn dbus.UnixFD(mock.inhibitPipe[1]), nil\n}\n\nfunc (mock *logindMock) Get(iface, property string) (dbus.Variant, *dbus.Error) {\n\tif iface != logindInterface {\n\t\treturn dbus.Variant{}, prop.ErrIfaceNotFound\n\t}\n\n\tif property != \"InhibitDelayMaxUSec\" {\n\t\treturn dbus.Variant{}, prop.ErrPropNotFound\n\t}\n\n\treturn dbus.MakeVariant(uint64(InhibitMaxDelay / time.Microsecond)), nil\n}\n\nfunc (mock *logindMock) getPipe() []int {\n\tmock.mu.Lock()\n\tdefer mock.mu.Unlock()\n\n\treturn slices.Clone(mock.inhibitPipe)\n}\n"
  },
  {
    "path": "internal/pkg/logind/logind_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logind_test\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/logind\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestIntegration(t *testing.T) {\n\tdir := t.TempDir()\n\n\tsocketPathService := filepath.Join(dir, \"system_bus_service\")\n\tsocketPathClient := filepath.Join(dir, \"system_bus_client\")\n\n\tbroker, err := logind.NewBroker(t.Context(), socketPathService, socketPathClient)\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\terrCh <- broker.Run(ctx)\n\t}()\n\n\tserviceConn, err := logind.NewServiceMock(socketPathService)\n\trequire.NoError(t, err)\n\n\tdefer serviceConn.Close() //nolint:errcheck\n\n\tkubeletConn, err := NewDBusCon(\"unix:path=\" + socketPathClient)\n\trequire.NoError(t, err)\n\n\tdefer kubeletConn.Close() //nolint:errcheck\n\n\tt.Log(\"ready to go\")\n\n\td, err := kubeletConn.CurrentInhibitDelay()\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 40*constants.KubeletShutdownGracePeriod, d)\n\n\tt.Log(\"acquiring inhibit lock\")\n\n\tl, err := kubeletConn.InhibitShutdown()\n\trequire.NoError(t, err)\n\n\tt.Log(\"monitoring shutdown signal\")\n\n\tch, err := kubeletConn.MonitorShutdown()\n\trequire.NoError(t, err)\n\n\tt.Log(\"emitting shutdown signal\")\n\n\trequire.NoError(t, serviceConn.EmitShutdown())\n\n\tassert.True(t, <-ch)\n\n\tt.Log(\"releasing inhibit lock\")\n\n\trequire.NoError(t, kubeletConn.ReleaseInhibitLock(l))\n\n\tt.Log(\"waiting for inhibit lock release\")\n\n\tassert.NoError(t, serviceConn.WaitLockRelease(ctx))\n\n\tassert.NoError(t, serviceConn.Close())\n\tassert.NoError(t, kubeletConn.Close())\n\tassert.NoError(t, broker.Close())\n\n\tcancel()\n\n\tassert.NoError(t, <-errCh)\n}\n"
  },
  {
    "path": "internal/pkg/logind/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logind\n\nimport (\n\t\"context\"\n\t\"syscall\"\n\n\t\"github.com/godbus/dbus/v5\"\n)\n\n// ServiceMock connects to the broker and mocks the D-Bus and logind.\ntype ServiceMock struct {\n\tconn   *dbus.Conn\n\tlogind logindMock\n}\n\n// NewServiceMock initializes the D-Bus and logind mock.\nfunc NewServiceMock(socketPath string) (*ServiceMock, error) {\n\tvar mock ServiceMock\n\n\tconn, err := dbus.Dial(\"unix:path=\" + socketPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = conn.Auth(nil); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar dbusMock dbusMock\n\n\tif err = conn.ExportMethodTable(\n\t\tmap[string]any{\n\t\t\t\"AddMatch\": dbusMock.AddMatch,\n\t\t\t\"Hello\":    dbusMock.Hello,\n\t\t},\n\t\tdbusPath, dbusInterface,\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = conn.ExportMethodTable(\n\t\tmap[string]any{\n\t\t\t\"Inhibit\": mock.logind.Inhibit,\n\t\t},\n\t\tlogindObject, logindService,\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = conn.ExportMethodTable(\n\t\tmap[string]any{\n\t\t\t\"Inhibit\": mock.logind.Inhibit,\n\t\t},\n\t\tlogindObject, logindInterface,\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = conn.ExportMethodTable(\n\t\tmap[string]any{\n\t\t\t\"Get\": mock.logind.Get,\n\t\t},\n\t\tlogindObject, propsInterface,\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tmock.conn = conn\n\n\treturn &mock, nil\n}\n\n// Close the connection.\nfunc (mock *ServiceMock) Close() error {\n\treturn mock.conn.Close()\n}\n\n// EmitShutdown notifies about the shutdown.\nfunc (mock *ServiceMock) EmitShutdown() error {\n\treturn mock.conn.Emit(logindObject, logindService+\".PrepareForShutdown\", true)\n}\n\n// WaitLockRelease waits for the inhibit lock to be released.\nfunc (mock *ServiceMock) WaitLockRelease(ctx context.Context) error {\n\tpipe := mock.logind.getPipe()\n\n\t// no inhibit lock\n\tif len(pipe) == 0 {\n\t\treturn nil\n\t}\n\n\t// close the write side of the pipe, other fd to the write pipe is in the kubelet\n\tif err := syscall.Close(pipe[1]); err != nil {\n\t\treturn err\n\t}\n\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\t// attempt to read from the pipe, as soon as kubelet closes its end, read should return\n\t\tbuf := make([]byte, 1)\n\t\t_, err := syscall.Read(pipe[0], buf)\n\n\t\terrCh <- err\n\t}()\n\n\tselect {\n\tcase err := <-errCh:\n\t\treturn err\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/bank_data.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot\"\n\ttpm2internal \"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// RSAKey is the input for the CalculateBankData function.\ntype RSAKey interface {\n\tcrypto.Signer\n\tPublicRSAKey() *rsa.PublicKey\n}\n\n// CalculateBankData calculates the PCR bank data for a given set of UKI file sections.\n//\n// This mimics the process happening happening in the TPM when the UKI is being loaded.\n//\n//nolint:gocyclo\nfunc CalculateBankData(pcrNumber int, alg tpm2.TPMAlgID, sectionData map[string]string, rsaKey RSAKey) ([]tpm2internal.BankData, error) {\n\t// get fingerprint of public key\n\tpubKeyFingerprint := sha256.Sum256(x509.MarshalPKCS1PublicKey(rsaKey.PublicRSAKey()))\n\n\thashAlg, err := alg.Hash()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpcrSelector, err := tpm2internal.CreateSelector([]int{constants.UKIPCR})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create PCR selection: %v\", err)\n\t}\n\n\tpcrSelection := tpm2.TPMLPCRSelection{\n\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t{\n\t\t\t\tHash:      alg,\n\t\t\t\tPCRSelect: pcrSelector,\n\t\t\t},\n\t\t},\n\t}\n\n\thashData := NewDigest(hashAlg)\n\n\tfor _, section := range OrderedSections() {\n\t\tif file := sectionData[section]; file != \"\" {\n\t\t\thashData.Extend(append([]byte(section), 0))\n\n\t\t\tif err = func() error {\n\t\t\t\tf, err := os.Open(file)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tdefer f.Close() //nolint:errcheck\n\n\t\t\t\treturn hashData.ExtendFrom(f)\n\t\t\t}(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to hash section %q: %v\", section, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tbanks := make([]tpm2internal.BankData, 0)\n\n\tfor _, phaseInfo := range secureboot.OrderedPhases() {\n\t\t// extend always, but only calculate signature if requested\n\t\thashData.Extend([]byte(phaseInfo.Phase))\n\n\t\tif !phaseInfo.CalculateSignature {\n\t\t\tcontinue\n\t\t}\n\n\t\thash := hashData.Hash()\n\n\t\tpolicyPCR, err := tpm2internal.CalculatePolicy(hash, pcrSelection)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tsigData, err := Sign(policyPCR, hashAlg, rsaKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tbanks = append(banks, tpm2internal.BankData{\n\t\t\tPCRs: []int{pcrNumber},\n\t\t\tPKFP: hex.EncodeToString(pubKeyFingerprint[:]),\n\t\t\tSig:  sigData.SignatureBase64,\n\t\t\tPol:  sigData.Digest,\n\t\t})\n\t}\n\n\treturn banks, nil\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/bank_data_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr_test\n\nimport (\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure/internal/pcr\"\n\ttpm2internal \"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n)\n\ntype keyWrapper struct {\n\t*rsa.PrivateKey\n}\n\nfunc (k keyWrapper) PublicRSAKey() *rsa.PublicKey {\n\treturn &k.PrivateKey.PublicKey\n}\n\nfunc TestCalculateBankData(t *testing.T) {\n\tt.Parallel()\n\n\tpemKey, err := os.ReadFile(\"../../testdata/pcr-signing-key.pem\")\n\trequire.NoError(t, err)\n\n\tblock, _ := pem.Decode(pemKey)\n\trequire.NotNil(t, block)\n\n\tkey, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\trequire.NoError(t, err)\n\n\tbankData, err := pcr.CalculateBankData(15, tpm2.TPMAlgSHA256,\n\t\tmap[string]string{\n\t\t\t\".initrd\": \"testdata/a\",\n\t\t\t\".linux\":  \"testdata/b\",\n\t\t\t\".dtb\":    \"testdata/c\",\n\t\t},\n\t\tkeyWrapper{key})\n\trequire.NoError(t, err)\n\n\trequire.Equal(t,\n\t\t[]tpm2internal.BankData{\n\t\t\t{\n\t\t\t\tPCRs: []int{15},\n\t\t\t\tPKFP: \"58f58f625bd8a8b6681e4b40688cf99b26419b6b2c5f6e14a2c7c67a3b0b1620\",\n\t\t\t\tPol:  \"a1c9d366451c82969238eb82a5282f84b6a3d499e540430ecf792083155225dd\",\n\t\t\t\tSig:  \"bO4F/T6bio7jLJFpi4GsJHjZDj+H5Pq4stjKA5WhkzBNCmE1gQECeOALUfNJ1RW/HKhwSp7KhGFqqnjyg/eXR3c0pVuYUKuAjZz9NMXS4dAQlSLxtNWMmlX3XDst/UKfxB6Z+m2KluJpF3KeAw03tP9lru6nfzaickOs1UL83IO5QgLkCHpUcSloZcya0xS9ETCNBd5gm8K+c9gc7+CmpFLTo1uTxbBK0Mea+3fn7GAZROHPMBLosvTM5D9vplsWIXXAXSaHr/sj5bxOIR+orCQZOdYY+/8ra4oFVXzHc9kkPP3A6mWzoADKryWWIVKPx/DGLi0ExT2fpCNdUoMOacvD+dqDqjVBhcOwoAZkNqve/W/poqaLlKyFTqlmGmv+08WavtShYmCURa4Mn3UFf49BTVkktxoQ+jTMroyit1uK/ppMSjaPwQp2Dd1pRCY4hcFfLwqryy1zRMT/XmZ2e91MYe40Pr9Tom2ZH0YAigDosBPuP6RHt7IypFIgary3louW1dqNLXW8p38Y91nYDKBWI9x0tVn5ufqtk5wkHnExTjUYkTWU98+p5J7urDIhLuX1mSi57Ekq02f+lVLMs85SHfmMfzZl7l7Xi4npYbW+5xHKiAxLnaXVJCHdW0xiAD0VTLer5Oe5nf7FrjSzS39rXoryKfcHFOIxRT1XQOA=\", //nolint:lll\n\t\t\t},\n\t\t}, bankData)\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/extend.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr\n\nimport (\n\t\"bytes\"\n\t\"crypto\"\n\t\"fmt\"\n\t\"io\"\n)\n\n// Digest implements the PCR extension algorithm.\n//\n// Each time `Extend` is called, the hash of the previous data is\n// prepended to the hash of new data and hashed together.\n//\n// The initial hash value is all zeroes.\ntype Digest struct {\n\talg  crypto.Hash\n\thash []byte\n}\n\n// NewDigest creates a new Digest with the speified hash algorithm.\nfunc NewDigest(alg crypto.Hash) *Digest {\n\treturn &Digest{\n\t\talg:  alg,\n\t\thash: make([]byte, alg.Size()),\n\t}\n}\n\n// Hash returns the current hash value.\nfunc (d *Digest) Hash() []byte {\n\treturn d.hash\n}\n\n// Extend extends the current hash with the specified data.\nfunc (d *Digest) Extend(data []byte) {\n\td.ExtendFrom(bytes.NewReader(data)) //nolint:errcheck\n}\n\n// ExtendFrom extends the current hash with the specified io,WriterTo.\nfunc (d *Digest) ExtendFrom(rdr io.WriterTo) error {\n\t// create hash of incoming data\n\thash := d.alg.New()\n\n\t_, err := rdr.WriteTo(hash)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to hash data: %v\", err)\n\t}\n\n\thashSum := hash.Sum(nil)\n\n\t// extend hash with previous data and hashed incoming data\n\thash.Reset()\n\thash.Write(d.hash)\n\thash.Write(hashSum)\n\n\t// set sum as new hash\n\td.hash = hash.Sum(nil)\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/extend_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr_test\n\nimport (\n\t\"crypto\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure/internal/pcr\"\n)\n\nfunc TestExtend(t *testing.T) {\n\tt.Parallel()\n\n\thash := pcr.NewDigest(crypto.SHA256)\n\n\tassert.Equal(t, make([]byte, 32), hash.Hash())\n\n\thash.Extend([]byte(\"foo\"))\n\n\tassert.Equal(t,\n\t\t[]byte{0x42, 0x48, 0x16, 0xd0, 0x20, 0xcf, 0x3d, 0x79, 0x3a, 0xc0, 0x21, 0xda, 0x47, 0x37, 0x9b, 0xdf, 0x60, 0x80, 0x80, 0xa8, 0x3e, 0xb9, 0x36, 0x4a, 0x7f, 0xbe, 0xb, 0xdf, 0xa8, 0x71, 0x11, 0xd7},\n\t\thash.Hash(),\n\t)\n\n\thash.Extend([]byte(\"bar\"))\n\n\tassert.Equal(t,\n\t\t[]byte{0x63, 0x5c, 0x18, 0xb1, 0x5e, 0xf5, 0xc5, 0xd6, 0xc0, 0x20, 0xe7, 0x23, 0x39, 0xdd, 0xef, 0xd8, 0xb0, 0x5c, 0x4c, 0x4a, 0x44, 0xb3, 0x4e, 0xff, 0x8c, 0xef, 0x22, 0x6f, 0x89, 0x2, 0x77, 0x2},\n\t\thash.Hash(),\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/sections.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr\n\n// OrderedSections returns the sections that are measured into PCR.\n//\n// Derived from https://github.com/systemd/systemd/blob/v257.1/src/fundamental/uki.h#L6\n// .pcrsig section is omitted here since that's what we are calulating here.\nfunc OrderedSections() []string {\n\t// DO NOT REARRANGE\n\treturn []string{\n\t\t\".linux\",\n\t\t\".osrel\",\n\t\t\".cmdline\",\n\t\t\".initrd\",\n\t\t\".ucode\",\n\t\t\".splash\",\n\t\t\".dtb\",\n\t\t\".uname\",\n\t\t\".sbat\",\n\t\t\".pcrpkey\",\n\t\t\".profile\",\n\t\t\".dtbauto\",\n\t\t\".hwids\",\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/sign.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pcr contains code that handles PCR operations.\npackage pcr\n\nimport (\n\t\"crypto\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"fmt\"\n)\n\n// Signature returns the hashed signature digest and base64 encoded signature.\ntype Signature struct {\n\tDigest          string\n\tSignatureBase64 string\n}\n\n// Sign the digest using specified hash and key.\nfunc Sign(digest []byte, hash crypto.Hash, key crypto.Signer) (*Signature, error) {\n\tdigestToHash := hash.New()\n\tdigestToHash.Write(digest)\n\tdigestHashed := digestToHash.Sum(nil)\n\n\t// sign policy digest\n\tsignedData, err := key.Sign(nil, digestHashed, hash)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"signing failed: %v\", err)\n\t}\n\n\treturn &Signature{\n\t\tDigest:          hex.EncodeToString(digest),\n\t\tSignatureBase64: base64.StdEncoding.EncodeToString(signedData),\n\t}, nil\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/sign_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pcr_test\n\nimport (\n\t\"crypto\"\n\t\"crypto/x509\"\n\t\"encoding/hex\"\n\t\"encoding/pem\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure/internal/pcr\"\n)\n\nfunc TestSign(t *testing.T) {\n\tt.Parallel()\n\n\tpemKey, err := os.ReadFile(\"../../testdata/pcr-signing-key.pem\")\n\trequire.NoError(t, err)\n\n\tblock, _ := pem.Decode(pemKey)\n\trequire.NotNil(t, block)\n\n\tkey, err := x509.ParsePKCS1PrivateKey(block.Bytes)\n\trequire.NoError(t, err)\n\n\tdigest, err := hex.DecodeString(\"e9590019f04a00029bb5ac512c3d3dfff0ec0e66418cfb5035e22313af891d81\")\n\trequire.NoError(t, err)\n\n\tsignature, err := pcr.Sign(digest, crypto.SHA256, key)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t,\n\t\t&pcr.Signature{\n\t\t\tDigest:          \"e9590019f04a00029bb5ac512c3d3dfff0ec0e66418cfb5035e22313af891d81\",\n\t\t\tSignatureBase64: \"Ylam12MOrPQs2m0AsHzRYBjZwYB1B5W0N4Qq62bNjiV4KgQVpwGTnIA0Rgmdaa1bTL+9+7oZ84H1xR0Q248Yd+2P1ZU5KaSysdoi3nlvotRYUq93HQeVjSLe1WUnoZ56EovP47tPuvLqIHmjPYq3V/EVLS6fD3+mXKZr/Q7sdlUjmGtYO5H0rV39C6Oq4Pwk9WJ4oRRKWwCp4KbxOujJ2ANqJl2QdJJA4WSle8+OML+SomelSDCjwt+s+T+0ZUhCY11Els1PtKO55ySU9N67m7wMIAy7aMwF6vbqyRajFDZN8ad7huhXDpwBGBMaEX5ajm2FseUj+h0EYbAm030FwduqZ9WlTMwp9KUx6dK2uOjckKgItBQfVXFoOo8dl4Al9PDktcmuytogI7o1OdzmJAcrb8BiPLLppmNsEgKR+5+poAsSA3Z0dcREiLbvKm10m7mXHGwRg84knZGSrsbHkD9I3ngeOM3JiPLGGCp4nYjBNzKP4jiygTEgEuZ2ueV9PikwlnM5qaDdByIH+0u3LAJubzN2XyI6TGugNRzdvKRIxtl5dSwRoIptiXInN81q6pw2i27YmzvR16tCTxXFRIcHjxpq5Q4KpVohbYhh4kHiWexbqJMpUPoLVEaw+m+Kh7gMvZlud67I6ldRIjDoy/LSdnsXcjpQFkNoF0ZKhX8=\", //nolint:lll\n\t\t},\n\t\tsignature,\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/testdata/a",
    "content": "aaaa\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/testdata/b",
    "content": "bbbb\n"
  },
  {
    "path": "internal/pkg/measure/internal/pcr/testdata/c",
    "content": "cccc\n"
  },
  {
    "path": "internal/pkg/measure/measure.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package measure contains Go implementation of 'systemd-measure' command.\n//\n// This implements TPM PCR emulation, UKI signature measurement, signing the measured values.\npackage measure\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure/internal/pcr\"\n\ttpm2internal \"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// SectionsData holds a map of Section to file path to the corresponding section.\ntype SectionsData map[string]string\n\n// RSAKey is the input for the CalculateBankData function.\ntype RSAKey interface {\n\tcrypto.Signer\n\tPublicRSAKey() *rsa.PublicKey\n}\n\n// GenerateSignedPCR generates the PCR signed data for a given set of UKI file sections.\nfunc GenerateSignedPCR(sectionsData SectionsData, rsaKey RSAKey) (*tpm2internal.PCRData, error) {\n\tdata := &tpm2internal.PCRData{}\n\n\tfor _, algo := range []struct {\n\t\talg            tpm2.TPMAlgID\n\t\tbankDataSetter *[]tpm2internal.BankData\n\t}{\n\t\t{\n\t\t\talg:            tpm2.TPMAlgSHA256,\n\t\t\tbankDataSetter: &data.SHA256,\n\t\t},\n\t\t{\n\t\t\talg:            tpm2.TPMAlgSHA384,\n\t\t\tbankDataSetter: &data.SHA384,\n\t\t},\n\t\t{\n\t\t\talg:            tpm2.TPMAlgSHA512,\n\t\t\tbankDataSetter: &data.SHA512,\n\t\t},\n\t} {\n\t\tbankData, err := pcr.CalculateBankData(constants.UKIPCR, algo.alg, sectionsData, rsaKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t*algo.bankDataSetter = bankData\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "internal/pkg/measure/measure_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage measure_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n\t\"github.com/siderolabs/talos/internal/pkg/measure/internal/pcr\"\n)\n\nconst (\n\t// ExpectedSignatureJSON is pre-calculated signature.\n\t//nolint:lll\n\tExpectedSignatureJSON = `{\"sha256\":[{\"pcrs\":[11],\"pkfp\":\"58f58f625bd8a8b6681e4b40688cf99b26419b6b2c5f6e14a2c7c67a3b0b1620\",\"pol\":\"c0c4f61f8ac39267a7638cde8029b82a0ccd378b2acbfdffb77ee1f0f9d464ec\",\"sig\":\"zyyb7nNjQP6GyM1Y2TtCo2FbSDSLMYzDIw5sgsm3vWDgWK6bZnItxixA1J9pF8ccqW09VH5kQU3a5xFl1ZsNmZwSUtK1wr9jwITSW4V+G2508gt1X3t0Yq9SXfXo8JNhKhayjtcfLKEIj3NvaCEgEMwcJJWUM/fooWeoXOdlx3JfTLcL1Pog6Hy7o4nDGKGMHsxUf1RNzf2Ro+Z4lXQ1334fqLeoC2ZbQbFyjRuGMin0/QvWZQ0k8FQ6ZooZR/SrJQrUu/ouzrzyEFIOBLfituBjw6fnT40ieZUh9N/bPqrX9jtKT3eBICYoEuY5V67bpF1Ygm+sDarBvR9MYVBY4DSm1iIOtABBUKVaACXxG4dFrEAUydXv62Yd9Kl86DqoBXrQRu+dcBKa1Stw/eGhzzoaXQo4XeutnIj3QOwtOHN1Z/L02gcZdlCcRboGAiTCWs5m642oSJa8jiAKWzpgwsJpSDkHRsmjWewQMBccgDy1j6DiHp4HakgeK2pePWdD/c8pu8unThKigKy/wsH+QMXpzNufkqAq2aWyuempFDn+OdVHGE5htZuSNIa66Vj0sd1guH13K9zxNUN8JguWnk21zInAN1IpbmyxlgRYCEpuE++E5Te4tqskCHUAU4D1iLS8a73SK5wXS7AnMXK7XhQ4FFvJCaOaQiJjC30LnEk=\"}],\"sha384\":[{\"pcrs\":[11],\"pkfp\":\"58f58f625bd8a8b6681e4b40688cf99b26419b6b2c5f6e14a2c7c67a3b0b1620\",\"pol\":\"e8f6311e36f9ee038df65255ae7c471d1d1f91ce742b98a152be72337f6c937d\",\"sig\":\"SH9VntNIwbApIoTM9GksYp6fScBkjQ156rEscm9cR6hFcIy8oZeFCzaCxfl122UgNVzXMZDst4S3xF/BjwG1TiUE3SvzlvCwzvAkLVitHzD3Jj/oyy5vIfe7lhrPvSSb5ta3I5DsBE4693OlXDw/hXzoj93i/Cbztqf/N7G354tO2COx8CXu63Yz3DBijdvDN2lIA6AVv5AV+IC0koU8wuKsdOmbHoysDI/JtFi5f2qQP667qjOUJj2FgsLoH//ZvlKTZjIrGsQo9q6iQsxAEdBKdWub8mrexgalH4jzHfFyVxDDeV6+D77xFCAuaT1fVOcGKTncxAvxN2M+wg7XDEVnZm6Itmh+Qh8DKejogHTBVr1ALBzE12hSpvIlYHQ6bNrzORPX/+7eJ3nbnTfYEp9psyFbxV+21U7A7ArwDQLnhosbVFY94YSyQd13bfgWQll013HzcpiTuzg3+qU4DjPc0x764z614+K9kyJQLqhiE0Y82Qhelhu+dJa/DrmOPEXQ6Lt5YG5TPQSHkNq79vPF1JUC1OkMvnFwO10eU2zPbuVKN7mf9S2ERSGEB9oX7pYLf99gNDh+VCII1iP+Jzj7jcAdvt6VK1Cme89kzXWem66eLaDNYIibb18KJ0uArqBt8VBzsX5wUb9sQTo/f2DOPI2AvHrzWziXjUG8cWc=\"}],\"sha512\":[{\"pcrs\":[11],\"pkfp\":\"58f58f625bd8a8b6681e4b40688cf99b26419b6b2c5f6e14a2c7c67a3b0b1620\",\"pol\":\"207a8217158f9cc521dca50358a593dc61ed9308ef27da9df4ef64d634309160\",\"sig\":\"NY659iroM9POX2a75p26i8JPXd+/Tsb45Wd/FEmjb1gopY4ygRumFNn/YuOebbhxHq67SMB30Fz5R1ktLJHgiCZotg5BqiUZWKF1zVlze928LTZqS4xxU5eUlZuzFkDyokwuxzvmc1+qFotkP1FMq8LSyDpBpUKby26EOP8cLYuE6PKc3LmhvjTmOUglICyv0JAoPRARDjZEN/f1O2T9HnACYjXZIVuKkBhMyYkuIgP+kGR1ChnHZTvcOkFByZcOUWtX6ChAP+OvDYQ1lbpomTyyKLmBvA935kJCCL1cDv3u5LCCaPfLm7zAVIyOrfELUpt8I3Oe/qIRX7CiP/TzN3IaNPOzU4+rm0vLcM56T5bEfUw4ikQILykQ202hUeH9Zv5Fw/qZI2nU4ToRamtLQd28xKfod9Uq2fbfORybUU5Ab2SbXpcwMu9PUsapFpjf9hrC1jf/G26TJ1mEzhhLPgJ1UlKyFX6ba0urhudR9dr3xLHlh3gw+T1NnZVram1aYBJnOU6lxHcoD+wmop3pqu1S0VOJX9YIGKzZ5jrzJ102cAI58nihASIkaWD7JqisFBCp2jX0ETu6bJLcufLv7ekT+asw2K1C8BxH5INiRkXu1HEPLYhYBceAgEFGROI26Awy08o8axsCt2zSAi2EafnCEt8mIo5E5RDGvRbRsWk=\"}]}`\n)\n\ntype rsaWrapper struct {\n\t*rsa.PrivateKey\n}\n\nfunc (w rsaWrapper) PublicRSAKey() *rsa.PublicKey {\n\treturn &w.PrivateKey.PublicKey\n}\n\nfunc loadRSAKey(path string) (measure.RSAKey, error) {\n\tkeyData, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert private key to rsa.PrivateKey\n\trsaPrivateKeyBlock, _ := pem.Decode(keyData)\n\tif rsaPrivateKeyBlock == nil {\n\t\treturn nil, err\n\t}\n\n\trsaKey, err := x509.ParsePKCS1PrivateKey(rsaPrivateKeyBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse private key failed: %v\", err)\n\t}\n\n\treturn rsaWrapper{rsaKey}, nil\n}\n\nfunc TestMeasureMatchesExpectedOutput(t *testing.T) {\n\texpectedSignatureHex := ExpectedSignatureJSON\n\n\tif _, err := exec.LookPath(\"systemd-measure\"); err == nil {\n\t\tt.Log(\"systemd-measure binary found, using it to get expected signature\")\n\t\texpectedSignatureHex = getSignatureUsingSDMeasure(t)\n\t}\n\n\ttmpDir := t.TempDir()\n\n\tsectionsData := measure.SectionsData{}\n\n\t// create temporary files with the ordered section name and data as the section name\n\tfor _, section := range pcr.OrderedSections() {\n\t\tsectionFile := filepath.Join(tmpDir, section)\n\n\t\tif err := os.WriteFile(sectionFile, []byte(section), 0o644); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tsectionsData[section] = sectionFile\n\t}\n\n\trsaKey, err := loadRSAKey(\"testdata/pcr-signing-key.pem\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tpcrData, err := measure.GenerateSignedPCR(sectionsData, rsaKey)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tpcrDataJSON, err := json.Marshal(&pcrData)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tassert.Equal(t, expectedSignatureHex, string(pcrDataJSON))\n}\n\nfunc getSignatureUsingSDMeasure(t *testing.T) string {\n\ttmpDir := t.TempDir()\n\n\tsdMeasureArgs := make([]string, len(pcr.OrderedSections()))\n\n\t// create temporary files with the ordered section name and data as the section name\n\tfor i, section := range pcr.OrderedSections() {\n\t\tsectionFile := filepath.Join(tmpDir, section)\n\n\t\tif err := os.WriteFile(sectionFile, []byte(section), 0o644); err != nil {\n\t\t\tt.Error(err)\n\t\t}\n\n\t\tsdMeasureArgs[i] = fmt.Sprintf(\"--%s=%s\", strings.TrimPrefix(section, \".\"), sectionFile)\n\t}\n\n\tvar (\n\t\tsignature bytes.Buffer\n\t\tstderr    bytes.Buffer\n\t)\n\n\tsdCmd := exec.CommandContext(\n\t\tt.Context(),\n\t\t\"systemd-measure\",\n\t\tappend([]string{\n\t\t\t\"sign\",\n\t\t\t\"--private-key\",\n\t\t\t\"testdata/pcr-signing-key.pem\",\n\t\t\t\"--bank=sha256\",\n\t\t\t\"--bank=sha384\",\n\t\t\t\"--bank=sha512\",\n\t\t\t\"--phase=enter-initrd:leave-initrd:enter-machined\",\n\t\t\t\"--json=short\",\n\t\t},\n\t\t\tsdMeasureArgs...,\n\t\t)...)\n\n\tsdCmd.Stdout = &signature\n\tsdCmd.Stderr = &stderr\n\n\tt.Log(\"Running systemd-measure command:\", sdCmd.String())\n\n\tif err := sdCmd.Run(); err != nil {\n\t\tt.Log(\"stderr:\", stderr.String())\n\t\tt.Fatalf(\"systemd-measure failed: %v\", err)\n\t}\n\n\ts := bytes.TrimSpace(signature.Bytes())\n\n\treturn string(s)\n}\n"
  },
  {
    "path": "internal/pkg/measure/testdata/pcr-signing-key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKQIBAAKCAgEA7qhAkdtZxqkIP79DDGin9eaJBeNlJsClJTcbaXbNfk2QJGT3\nlqo9ErXQQftwYWLGo+kVd8puhnHGPkLW9apT1/ZmUJEFwxV5xws0RllGVPhUga+1\noubHUqhEiy707S4RrUEMk/o9wqmtnl2hY5FxMeQn2o7xrpcNhm8FtHpvQrT0MsbC\n1cS1ytZH/hwPy/QIB9bx+ugOha6wtQBnpgix1BhHC/NwDIYPg+ONpQSCu9gkXVtL\nGlKfmjscUANQtBuVKa5NflrjkHw7NAdKYdKpMnmzr0yu6Tn/2oNmUiJAwHz0BXpf\nb4Yn8n/IoKJQ5Tv1g6d30wxxpBd0lbwSe9MLRchIDJ5aFRybyRxaPGT17U3yEVzb\nV78kIFtocaqkc1ise8remZ0wxHzuolbTZD6oswt7C9jMLvfMAQ7JtENXrpDM//Xz\ndRLzyTWKOjhG0YmKKRY6cIrPkugM0PHGCE3RMSH1FmPMrWWBNAMwS0Zba0Wm1b7v\ndw5fKeE8txH+IpA3IaE9AytYk0ig98ZgmXmBV0sgxmJ/94scEF+sDg65LIkSEJMz\nf6q30UghbJJoP7eKOoDX9KBrR+POEsWm/EcU5jTEQTHMU+qKtj5KD6TUn8R8yi4w\nCnyZ7uJLUqm8Ou8MzEZWbrsrbMvrewPDAHn0QQvb2tDtBgn6oH192jpkzckCAwEA\nAQKCAgEAkiWcrPU7i+lVMNxqLb4lJPOQ83cmKU4Nk7WkZrgm7PKIk5D1AWGs1rla\nGB3m2uxHIncI+3uOpWwk71m1E2nDwFuWmj3E3otXMKnO0Em5RS1xap10SJa0dwyu\nNOGDgX8Vuhg8oJ28lmmb9X/25edZ/yhts2yX2ceMs8dnIfdcDOiNJk8LXycAAH+q\nRJVgoxAEnvBk7LaQthKdCap+znFCnNRlJY9lDXZHKAgAZI5XlLquwjC21B7GuAb8\nto7hK/o8JPMlZ3w3IPLCuoDAbxk3Hb7jZzU5Y39uC50t2pw5NOcP9A7VRJFOAzV3\nYc8kZMyL85xpR2e2a7slXNB4LTW3D0zy/fSO63R9cLNrlp+I9p7xDgz1mylo8FoW\nT1TyNAWo/gIa7r43Ufp/C0lrWSd5gkz2nMVWiFl8M1lpx7zDSZk8U1sKzFZswmFQ\nh5On7kxo14gUdzogb1hrJuEI9Ke52kRb4YMm094LFI/BWQ89QF0NXJ6CSkb2MyWc\nf0kyfEMRUbmHi/EfpQlKK2uhOsxXdhZN2VP4nl1Yg0xxv0cLSMcP7DdJPso5VSC/\n+wF8ni7+GMEDtntMEGjuXjq/zypyjptaRKpw4iRqxydUqa0C1PovzDoUDn7eKJBv\n2p9evDG8zWenZ7g/VYWy4ZtpwVa3SAXeeuLmdllphPp6n6uweFECggEBAPiSb2IY\nO33JRmxQeqrc6cmcv1l4AbedSr3F7X4DC+HZCkG27bZlzMBqbAQichC/pPhx544S\nCBxB7e1Qsqjw8LLNea0sQsRbVXMSQpwBqjJ2g4mCN4S/hPQHSeESODPz/OaZrQq5\niVSckrAlbgFs8HepOLxTQQVVp97m+vrnwlh7SZj/CXXi5QcZ4tHPNTFLLtwCgBUA\nX0Ausn9hpeHrud8imzQuPXJRgBMaF0BYRUxj0fjp3sty2ZfjiPjhTrdSCWOiJUSb\nonDb6kyYwN/hBEt7JNbSbC7viOM72/TwJQqDn4Bw8C7E0kiy3ZpQiCdyOYWnyDZP\nSyDhAM4nHLNYss0CggEBAPXJ+DMmLCPkE5OOElxGU+JIPM28+5jhKn+HcswAS5VV\n6tp1m8gIrmgwTpXA9aGi9BjPHzo6y3s1sNYHp3lGr5nSdgQaYuLvBR56FE0RXVP7\nbUHiN//R7a8QTkyYCqdrQNxLAzEARBNZaMIhMPfPXDDevFZWunAxIDXxC9IVRpjS\nVjmKwqLuk66uInko4qEn34NiU25x+VpDOjz0fia58VTlL9WrYy0w/QANVlg1JKRq\nwjjx4kWnmCQ1qQeagB+xqJtrEc/GK4z6qY/OC0pKZA26t6sXhkmn0zQshmwSAZem\n/QtEW3lDmsfAlvEibJUSshXz3ygWz4v21nWocF4gXu0CggEBAPgwXf43686gVSx4\n/sHzaYrgcz5F0JEhACuToJmdORP7vX33xEnGQzYsDEXkjreiYnmeYXE9F9P/EC1P\n0dNVHz+oYcFC3DdqaltG9DMIhoN0ScnWttBY2cs+K8oKgwt8phspfdmjfzd4Tg6K\nkNfjigYwdHG1Psqwx7iMMDStiyMFlmqo2y1Vqw/4DL0ogxgA1XzfEjvl7zUKazc8\nrIBy+VeOGiFzue6W6aYo+uZIPIkVceVyvf2tYw2BJpY5gHsR8kYE8+kY7Ix7R+nK\n62meJsem4RWNbG9AxBD/B5P84z8oRO3d1jMcWko0LYeSuR+JsV1+NS3k5kKh5kfw\nTXvVKFECggEACMp4fhvXaFE4AgcK0RIS3f0Hb7Raq1UiV/1YNcOs8GJqS/X45Gar\nFj7kEKceIfHaGSkPTN3deUKqWH1dmBDXJwFIB02KS+OQo05qe3crh11uwvR8XEH9\n5k0G/+ZQOzyyzS5BpvcDeE2yWX8maTaZbYYJ5myjrm+TX1qHubPZGo4rV1OHMpyl\n25GO2haERI9Qhzp1EXYyHPBanOOBv5DW+NpZo6LFoVAnPGE9vVnpPZgz6iV8mlEs\nN99TdFoqSvfnt+dUc8H6vMgaWHJeJQIUIgmTmCL3QpsmCq+s/yCFvg7S7hw7yVKJ\nrqtMusMobwyEIhTe3mgydCcX9I1Zt4Qg4QKCAQAnnNjOMflzEz+TvGNPUyVyzXef\nxRs2XBDipX/vPK7L3VvgiXGQuOAq4PYj7NdYHfIiVmFeqz7eY9gMmQyoscMwVPCm\nX+FuHepHXfcxUjQwnpFa/lAqpNxspgU09CQXW5hUkIdWblZePtRiGKvlo51CdzU5\nKlOylrIXl6opsApdrgSCduBtuR9uz2Cn3NiaG0Xe2x67VphclNaW+RATU4bUJEMn\n9aO8k+wp8CjlJ1xjSrhqIIBHGMmouyK5J0r3S3vRlTCLEjGpGq8+Z9shVkfuDk6N\nHOB2KZ1LN68eOYb4eZFKE+l2nGylFsHlOtkagX1IxtVoW+a5vDenGBNd+gC9\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "internal/pkg/meta/internal/adv/adv.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package adv provides common interfaces to access ADV data.\npackage adv\n\n// ADV describes implementation which stores tag-value data.\ntype ADV interface {\n\tReadTag(t uint8) (val string, ok bool)\n\tReadTagBytes(t uint8) (val []byte, ok bool)\n\tSetTag(t uint8, val string) (ok bool)\n\tSetTagBytes(t uint8, val []byte) (ok bool)\n\tDeleteTag(t uint8) (ok bool)\n\tListTags() (tags []uint8)\n\tBytes() ([]byte, error)\n}\n\nconst (\n\t// End is the noop tag.\n\tEnd = iota\n\t_\n\t_\n\t// Reserved1 is a reserved tag.\n\tReserved1\n\t// Reserved2 is a reserved tag.\n\tReserved2\n\t// Reserved3 is a reserved tag.\n\tReserved3\n)\n"
  },
  {
    "path": "internal/pkg/meta/internal/adv/syslinux/syslinux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package syslinux provides syslinux-compatible ADV data.\npackage syslinux\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv\"\n)\n\nconst (\n\t// AdvSize is the total size.\n\tAdvSize = 512\n\t// AdvLen is the usable data size.\n\tAdvLen = AdvSize - 3*4\n\t// AdvMagic1 is the head signature.\n\tAdvMagic1 = uint32(0x5a2d2fa5)\n\t// AdvMagic2 is the total checksum.\n\tAdvMagic2 = uint32(0xa3041767)\n\t// AdvMagic3 is the tail signature.\n\tAdvMagic3 = uint32(0xdd28bf64)\n)\n\n// ADV represents the Syslinux Auxiliary Data Vector.\ntype ADV []byte\n\n// NewADV returns the Auxiliary Data Vector.\nfunc NewADV(r io.ReadSeeker) (adv ADV, err error) {\n\tb := make([]byte, 2*AdvSize)\n\n\tif r == nil {\n\t\treturn b, nil\n\t}\n\n\t_, err = r.Seek(-2*AdvSize, io.SeekEnd)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to seek for syslinux adv: %w\", err)\n\t}\n\n\t_, err = io.ReadFull(r, b)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read syslinux adv: %w\", err)\n\t}\n\n\tadv = b\n\n\treturn adv, nil\n}\n\n// ReadTag reads a tag in the ADV.\nfunc (a ADV) ReadTag(t uint8) (val string, ok bool) {\n\tvar b []byte\n\n\tb, ok = a.ReadTagBytes(t)\n\tval = string(b)\n\n\treturn val, ok\n}\n\n// ReadTagBytes reads a tag in the ADV.\nfunc (a ADV) ReadTagBytes(t uint8) (val []byte, ok bool) {\n\t// Header is in first 8 bytes.\n\ti := 8\n\n\t// End at tail plus two bytes required for successful next tag.\n\tfor i < AdvSize-4-2 {\n\t\ttag := a[i]\n\t\tsize := int(a[i+1])\n\n\t\tif tag == adv.End {\n\t\t\tbreak\n\t\t}\n\n\t\tif tag != t {\n\t\t\t// Jump to the next tag.\n\t\t\ti += 2 + size\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlength := int(a[i+1]) + i\n\n\t\tval = a[i+2 : length+2]\n\n\t\tok = true\n\n\t\tbreak\n\t}\n\n\treturn val, ok\n}\n\n// ListTags returns a list of tags in the ADV.\nfunc (a ADV) ListTags() []uint8 {\n\t// Header is in first 8 bytes.\n\ti := 8\n\n\tvar tags []uint8\n\n\t// End at tail plus two bytes required for successful next tag.\n\tfor i < AdvSize-4-2 {\n\t\ttag := a[i]\n\t\tsize := int(a[i+1])\n\n\t\tif tag == adv.End {\n\t\t\tbreak\n\t\t}\n\n\t\ttags = append(tags, tag)\n\n\t\t// Jump to the next tag.\n\t\ti += 2 + size\n\t}\n\n\treturn tags\n}\n\n// SetTag sets a tag in the ADV.\nfunc (a ADV) SetTag(t uint8, val string) bool {\n\treturn a.SetTagBytes(t, []byte(val))\n}\n\n// SetTagBytes sets a tag in the ADV.\nfunc (a ADV) SetTagBytes(t uint8, val []byte) (ok bool) {\n\tif len(val) > 255 {\n\t\treturn false\n\t}\n\n\t// delete the tag if it exists\n\ta.DeleteTag(t)\n\n\t// Header is in first 8 bytes.\n\ti := 8\n\n\t// End at tail plus two bytes required for successful next tag.\n\tfor i < AdvSize-4-2 {\n\t\ttag := a[i]\n\t\tsize := int(a[i+1])\n\n\t\tif tag != adv.End {\n\t\t\t// Jump to the next tag.\n\t\t\ti += 2 + size\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// overflow check\n\t\tif i+2+len(val) > AdvSize-4-2 {\n\t\t\treturn false\n\t\t}\n\n\t\tlength := uint8(len(val))\n\n\t\ta[i] = t\n\t\ta[i+1] = length\n\n\t\tcopy(a[i+2:i+2+int(length)], val)\n\n\t\tok = true\n\n\t\tbreak\n\t}\n\n\tif ok {\n\t\ta.cleanup()\n\t}\n\n\treturn ok\n}\n\n// DeleteTag deletes a tag in the ADV.\nfunc (a ADV) DeleteTag(t uint8) (ok bool) {\n\t// Header is in first 8 bytes.\n\ti := 8\n\n\t// End at tail plus two bytes required for successful next tag.\n\tfor i < AdvSize-4-2 {\n\t\ttag := a[i]\n\t\tsize := int(a[i+1])\n\n\t\tif tag == adv.End {\n\t\t\tbreak\n\t\t}\n\n\t\tif tag != t {\n\t\t\t// Jump to the next tag.\n\t\t\ti += 2 + size\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Save the data after the tag that we will shift to the left by 2 + length\n\t\t// of the tag data.\n\t\tstart := i + 2 + size\n\n\t\tend := a[AdvSize-4]\n\n\t\tdata := make([]byte, len(a[start:end]))\n\n\t\tcopy(data, a[start:end])\n\n\t\t// The total size we want to zero out is the length of all the remaining\n\t\t// data we saved above.\n\t\tlength := 2 + len(data)\n\n\t\t// Zero each element to the right.\n\t\tfor j := i; j < length; j++ {\n\t\t\ta[j] = 0\n\t\t}\n\n\t\t// Shift the data.\n\t\tcopy(a[i:], data)\n\n\t\tok = true\n\n\t\tbreak\n\t}\n\n\tif ok {\n\t\ta.cleanup()\n\t}\n\n\treturn ok\n}\n\n// Bytes returns serialized contents of ADV.\nfunc (a ADV) Bytes() ([]byte, error) {\n\treturn a, nil\n}\n\nfunc (a ADV) cleanup() {\n\ta.head()\n\n\ta.total()\n\n\ta.tail()\n\n\tcopy(a[AdvSize:], a[:AdvSize])\n}\n\nfunc (a ADV) head() {\n\tbinary.LittleEndian.PutUint32(a[0:4], AdvMagic1)\n}\n\nfunc (a ADV) total() {\n\tcsum := AdvMagic2\n\tfor i := 8; i < AdvSize-4; i += 4 {\n\t\tcsum -= binary.LittleEndian.Uint32(a[i : i+4])\n\t}\n\n\tbinary.LittleEndian.PutUint32(a[4:8], csum)\n}\n\nfunc (a ADV) tail() {\n\tbinary.LittleEndian.PutUint32(a[AdvSize-4:AdvSize], AdvMagic3)\n}\n"
  },
  {
    "path": "internal/pkg/meta/internal/adv/syslinux/syslinux_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,lll,maligned,scopelint,testpackage\npackage syslinux\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\t\"slices\"\n\t\"testing\"\n)\n\nfunc TestNewADV(t *testing.T) {\n\tf, err := os.Open(\"testdata/adv.sys\")\n\tif err != nil {\n\t\tt.Errorf(\"failed to open test adv.sys: %v\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer f.Close()\n\n\ttype args struct {\n\t\tr io.ReadSeeker\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twantAdv ADV\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"valid tags\",\n\t\t\targs: args{\n\t\t\t\tr: f,\n\t\t\t},\n\t\t\twantAdv: ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantErr: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t//nolint:errcheck\n\t\t\tdefer f.Seek(0, 0)\n\n\t\t\tgotAdv, err := NewADV(tt.args.r)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"NewADV() error = %v, wantErr %v\", err, tt.wantErr)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !bytes.Equal(gotAdv, tt.wantAdv) {\n\t\t\t\tt.Errorf(\"NewADV() = %v, want %v\", gotAdv, tt.wantAdv)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_ReadTag(t *testing.T) {\n\ttype args struct {\n\t\tt uint8\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\ta       ADV\n\t\targs    args\n\t\twantVal string\n\t\twantOk  bool\n\t}{\n\t\t{\n\t\t\tname: \"bootonce\",\n\t\t\ta:    ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt: 1,\n\t\t\t},\n\t\t\twantVal: \"test me\",\n\t\t\twantOk:  true,\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 len(tt.a) != 2*AdvSize {\n\t\t\t\tt.Errorf(\"Test data is invalid, ADV size = %v, want %v\", len(tt.a), 2*AdvSize)\n\t\t\t}\n\n\t\t\tgotVal, gotOk := tt.a.ReadTag(tt.args.t)\n\t\t\tif gotVal != tt.wantVal {\n\t\t\t\tt.Errorf(\"ADV.ReadTag() gotVal = %v, want %v\", gotVal, tt.wantVal)\n\t\t\t}\n\n\t\t\tif gotOk != tt.wantOk {\n\t\t\t\tt.Errorf(\"ADV.ReadTag() gotOk = %v, want %v\", gotOk, tt.wantOk)\n\t\t\t}\n\n\t\t\ttags := tt.a.ListTags()\n\t\t\tif !slices.Equal(tags, []uint8{tt.args.t}) {\n\t\t\t\tt.Errorf(\"ADV.ListTags() got = %v, want %v\", tags, []uint8{tt.args.t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_SetTag(t *testing.T) {\n\ttype args struct {\n\t\tt   uint8\n\t\tval string\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\ta       ADV\n\t\targs    args\n\t\twantADV ADV\n\t\twantOk  bool\n\t}{\n\t\t{\n\t\t\tname: \"set test me\",\n\t\t\ta:    ADV{165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt:   1,\n\t\t\t\tval: \"test me\",\n\t\t\t},\n\t\t\twantADV: ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantOk:  true,\n\t\t},\n\t\t{\n\t\t\tname: \"set test\",\n\t\t\ta:    ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt:   6,\n\t\t\t\tval: \"add test\",\n\t\t\t},\n\t\t\twantADV: ADV{165, 47, 45, 90, 197, 189, 210, 250, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 197, 189, 210, 250, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantOk:  true,\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 len(tt.a) != 2*AdvSize {\n\t\t\t\tt.Errorf(\"Test data is invalid, source ADV size = %v, want %v\", len(tt.a), 2*AdvSize)\n\t\t\t}\n\n\t\t\tif len(tt.wantADV) != 2*AdvSize {\n\t\t\t\tt.Errorf(\"Test data is invalid, target ADV size = %v, want %v\", len(tt.wantADV), 2*AdvSize)\n\t\t\t}\n\n\t\t\tif gotOk := tt.a.SetTag(tt.args.t, tt.args.val); gotOk != tt.wantOk {\n\t\t\t\tt.Errorf(\"ADV.SetTag() = %v, want %v\", gotOk, tt.wantOk)\n\t\t\t}\n\n\t\t\tif !bytes.Equal(tt.a, tt.wantADV) {\n\t\t\t\tt.Errorf(\"ADV = %v, want %v\", tt.a, tt.wantADV)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_DeleteTag(t *testing.T) {\n\ttype args struct {\n\t\tt uint8\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\ta       ADV\n\t\targs    args\n\t\twantADV ADV\n\t\twantOk  bool\n\t}{\n\t\t{\n\t\t\tname: \"delete test me\",\n\t\t\ta:    ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt: 1,\n\t\t\t},\n\t\t\twantADV: ADV{165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantOk:  true,\n\t\t},\n\t\t{\n\t\t\tname: \"delete test\",\n\t\t\ta:    ADV{165, 47, 45, 90, 185, 209, 145, 51, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 185, 209, 145, 51, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt: 6,\n\t\t\t},\n\t\t\twantADV: ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantOk:  true,\n\t\t},\n\t\t{\n\t\t\tname: \"delete test again\",\n\t\t\ta:    ADV{165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 142, 155, 111, 208, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\targs: args{\n\t\t\t\tt: 6,\n\t\t\t},\n\t\t\twantADV: ADV{165, 47, 45, 90, 197, 189, 210, 250, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 197, 189, 210, 250, 1, 7, 116, 101, 115, 116, 32, 109, 101, 6, 8, 97, 100, 100, 32, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t\twantOk:  true,\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 len(tt.a) != 2*AdvSize {\n\t\t\t\tt.Errorf(\"Test data is invalid, source ADV size = %v, want %v\", len(tt.a), 2*AdvSize)\n\t\t\t}\n\n\t\t\tif len(tt.wantADV) != 2*AdvSize {\n\t\t\t\tt.Errorf(\"Test data is invalid, target ADV size = %v, want %v\", len(tt.wantADV), 2*AdvSize)\n\t\t\t}\n\n\t\t\tif gotOk := tt.a.DeleteTag(tt.args.t); gotOk != tt.wantOk {\n\t\t\t\tt.Errorf(\"ADV.DeleteTag() = %v, want %v\", gotOk, tt.wantOk)\n\t\t\t}\n\n\t\t\tif !bytes.Equal(tt.a, tt.wantADV) {\n\t\t\t\tt.Errorf(\"ADV = %v, want %v\", tt.a, tt.wantADV)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_cleanup(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\ta    ADV\n\t\twant ADV\n\t}{\n\t\t{\n\t\t\ta:    make(ADV, 1024),\n\t\t\twant: ADV{165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.a.cleanup()\n\n\t\t\tif !bytes.Equal(tt.a, tt.want) {\n\t\t\t\tt.Errorf(\"ADV.cleanup() = %v, want %v\", tt.a, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_head(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\ta    ADV\n\t}{\n\t\t{\n\t\t\ta: ADV{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.a.head()\n\n\t\t\t// Expecting 165, 47, 45, 90.\n\t\t\tif tt.a[0] != 165 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[0], 165)\n\t\t\t}\n\n\t\t\tif tt.a[1] != 47 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[0], 47)\n\t\t\t}\n\n\t\t\tif tt.a[2] != 45 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[0], 45)\n\t\t\t}\n\n\t\t\tif tt.a[3] != 90 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[0], 90)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_total(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\ta    ADV\n\t}{\n\t\t{\n\t\t\ta: ADV{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.a.total()\n\t\t\t// Expecting 103, 23, 4, 163.\n\t\t\tif tt.a[4] != 103 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[4], 103)\n\t\t\t}\n\n\t\t\tif tt.a[5] != 23 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[5], 23)\n\t\t\t}\n\n\t\t\tif tt.a[6] != 4 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[6], 4)\n\t\t\t}\n\n\t\t\tif tt.a[7] != 163 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[7], 163)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_tail(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\ta    ADV\n\t}{\n\t\t{\n\t\t\ta: ADV{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221, 165, 47, 45, 90, 103, 23, 4, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 191, 40, 221},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.a.tail()\n\n\t\t\t// Expecting 100, 191, 40, 221.\n\t\t\tif tt.a[len(tt.a)-4] != 100 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[len(tt.a)-4], 100)\n\t\t\t}\n\n\t\t\tif tt.a[len(tt.a)-3] != 191 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[len(tt.a)-3], 191)\n\t\t\t}\n\n\t\t\tif tt.a[len(tt.a)-2] != 40 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[len(tt.a)-2], 40)\n\t\t\t}\n\n\t\t\tif tt.a[len(tt.a)-1] != 221 {\n\t\t\t\tt.Errorf(\"head() = %v, want %v\", tt.a[len(tt.a)-1], 221)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestADV_overwrite(t *testing.T) {\n\tbuf := make([]byte, 2*AdvSize)\n\n\ta, err := NewADV(bytes.NewReader(buf))\n\tif err != nil {\n\t\tt.Errorf(\"NewADV() failed: %s\", err)\n\t}\n\n\tfor range 1024 {\n\t\tif !a.SetTag(1, \"yes\") {\n\t\t\tt.Errorf(\"SetTag() failed\")\n\t\t}\n\t}\n}\n\nfunc TestADV_many_tags(t *testing.T) {\n\tbuf := make([]byte, 2*AdvSize)\n\n\ta, err := NewADV(bytes.NewReader(buf))\n\tif err != nil {\n\t\tt.Errorf(\"NewADV() failed: %s\", err)\n\t}\n\n\tfor i := uint8(1); i < 255; i++ {\n\t\ta.SetTag(i, \"xa\")\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/meta/internal/adv/talos/talos.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos implements modern ADV which supports large size for the values and tags.\npackage talos\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv\"\n)\n\n// Basic constants configuring the ADV.\nconst (\n\tLength     = 256 * 1024 // 256KiB\n\tDataLength = Length - 40\n\tSize       = 2 * Length // Redundancy\n)\n\n// Magic constants.\nconst (\n\tMagic1 uint32 = 0x5a4b3c2d\n\tMagic2 uint32 = 0xa5b4c3d2\n)\n\n// Tag is the key.\n//\n// We use a byte here for compatibility with syslinux, but format has space for uint32.\ntype Tag uint8\n\n// Value stored for the tag.\ntype Value []byte\n\n// ADV implements the Talos extended ADV.\n//\n// Layout (all in big-endian):\n//\n//\t 0x0000   4 bytes       magic1\n//\t 0x0004   4 bytes       tag\n//\t 0x0008   4 bytes       size\n//\t 0x000c   (size) bytes  value\n//\t ... more tags\n//\t-0x0024   32 bytes      sha256 of the whole block with checksum set to zero\n//\t-0x0004   4 bytes       magic2\n//\n// Whole data structure is written twice for redundancy.\ntype ADV struct {\n\tTags map[Tag]Value\n}\n\n// NewADV loads ADV from the block device.\nfunc NewADV(r io.Reader) (*ADV, error) {\n\ta := &ADV{\n\t\tTags: make(map[Tag]Value),\n\t}\n\n\tif r == nil {\n\t\treturn a, nil\n\t}\n\n\tbuf := make([]byte, Length)\n\n\t_, err := io.ReadFull(r, buf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load first block: %w\", err)\n\t}\n\n\tif err = a.Unmarshal(buf); err == nil {\n\t\treturn a, nil\n\t}\n\n\t// try 2nd copy\n\t_, err = io.ReadFull(r, buf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load second block: %w\", err)\n\t}\n\n\tif err = a.Unmarshal(buf); err != nil {\n\t\treturn a, fmt.Errorf(\"failed to unmarshal second block: %w\", err)\n\t}\n\n\treturn a, nil\n}\n\n// Unmarshal single copy from the serialized representation.\nfunc (a *ADV) Unmarshal(buf []byte) error {\n\tmagic1 := binary.BigEndian.Uint32(buf[:4])\n\tif magic1 != Magic1 {\n\t\treturn fmt.Errorf(\"adv: unexpected magic %x, expecting %x\", magic1, Magic1)\n\t}\n\n\tmagic2 := binary.BigEndian.Uint32(buf[len(buf)-4:])\n\tif magic2 != Magic2 {\n\t\treturn fmt.Errorf(\"adv: unexpected magic %x, expecting %x\", magic2, Magic2)\n\t}\n\n\tchecksum := slices.Clone(buf[len(buf)-36 : len(buf)-4])\n\n\tcopy(buf[len(buf)-36:len(buf)-4], make([]byte, 32))\n\n\thash := sha256.New()\n\thash.Write(buf)\n\tactualChecksum := hash.Sum(nil)\n\n\tif !bytes.Equal(checksum, actualChecksum) {\n\t\treturn fmt.Errorf(\"adv: checksum mismatch: %x, expecting %x\", checksum, actualChecksum)\n\t}\n\n\tdata := buf[4 : len(buf)-36]\n\n\tfor len(data) >= 8 {\n\t\ttag := binary.BigEndian.Uint32(data[:4])\n\t\tif tag == adv.End {\n\t\t\tbreak\n\t\t}\n\n\t\tsize := binary.BigEndian.Uint32(data[4:8])\n\n\t\tif uint32(len(data)) < size+8 {\n\t\t\treturn fmt.Errorf(\"adv: value goes beyond the end of the buffer: tag %d, size %d\", tag, size)\n\t\t}\n\n\t\tvalue := data[8 : 8+size]\n\n\t\ta.Tags[Tag(tag)] = Value(value)\n\n\t\tdata = data[8+size:]\n\t}\n\n\treturn nil\n}\n\n// Marshal single copy of ADV.\nfunc (a *ADV) Marshal() ([]byte, error) {\n\tbuf := make([]byte, Length)\n\n\tbinary.BigEndian.PutUint32(buf[0:4], Magic1)\n\tbinary.BigEndian.PutUint32(buf[len(buf)-4:], Magic2)\n\n\tdata := buf[4 : len(buf)-36]\n\n\tfor tag, value := range a.Tags {\n\t\tif len(value)+8 > len(data) {\n\t\t\treturn nil, fmt.Errorf(\"adv: overflow %d bytes\", len(value)+8-len(data))\n\t\t}\n\n\t\tbinary.BigEndian.PutUint32(data[0:4], uint32(tag))\n\t\tbinary.BigEndian.PutUint32(data[4:8], uint32(len(value)))\n\t\tcopy(data[8:8+len(value)], value)\n\n\t\tdata = data[8+len(value):]\n\t}\n\n\thash := sha256.New()\n\thash.Write(buf)\n\tcopy(buf[len(buf)-36:len(buf)-4], hash.Sum(nil))\n\n\treturn buf, nil\n}\n\n// Bytes marshal full representation.\nfunc (a *ADV) Bytes() ([]byte, error) {\n\tmarshaled, err := a.Marshal()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn append(marshaled, marshaled...), nil\n}\n\n// ReadTag to get tag value.\nfunc (a *ADV) ReadTag(t uint8) (val string, ok bool) {\n\tb, ok := a.ReadTagBytes(t)\n\n\tval = string(b)\n\n\treturn val, ok\n}\n\n// ReadTagBytes to get tag value.\nfunc (a *ADV) ReadTagBytes(t uint8) (val []byte, ok bool) {\n\tval, ok = a.Tags[Tag(t)]\n\n\treturn val, ok\n}\n\n// ListTags to get list of tags.\nfunc (a *ADV) ListTags() (tags []uint8) {\n\treturn xslices.Map(maps.Keys(a.Tags), func(t Tag) uint8 { return uint8(t) })\n}\n\n// SetTag to set tag value.\nfunc (a *ADV) SetTag(t uint8, val string) (ok bool) {\n\treturn a.SetTagBytes(t, []byte(val))\n}\n\n// SetTagBytes to set tag value.\nfunc (a *ADV) SetTagBytes(t uint8, val []byte) (ok bool) {\n\tsize := 20 // magic + checksum\n\n\tfor _, v := range a.Tags {\n\t\tsize += len(v) + 8\n\t}\n\n\toldVal := a.Tags[Tag(t)]\n\n\tsize += len(Value(val)) - len(oldVal)\n\n\tif size > DataLength {\n\t\treturn false\n\t}\n\n\ta.Tags[Tag(t)] = Value(val)\n\n\treturn true\n}\n\n// DeleteTag to delete tag value.\nfunc (a *ADV) DeleteTag(t uint8) (ok bool) {\n\t_, ok = a.Tags[Tag(t)]\n\n\tdelete(a.Tags, Tag(t))\n\n\treturn ok\n}\n"
  },
  {
    "path": "internal/pkg/meta/internal/adv/talos/talos_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage talos_test\n\nimport (\n\t\"bytes\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv/talos\"\n)\n\nfunc TestMarshalUnmarshal(t *testing.T) {\n\ta, err := talos.NewADV(bytes.NewReader(make([]byte, talos.Size)))\n\tassert.Error(t, err)\n\trequire.NotNil(t, a)\n\n\tconst (\n\t\tval1 = \"value1\"\n\t\tval2 = \"value2\"\n\t\tval3 = \"value3\"\n\t)\n\n\tassert.True(t, a.SetTag(adv.Reserved1, val1))\n\tassert.True(t, a.SetTag(adv.Reserved2, val2))\n\tassert.True(t, a.SetTag(adv.Reserved3, val3))\n\n\tb, err := a.Bytes()\n\trequire.NoError(t, err)\n\tassert.Len(t, b, talos.Size)\n\n\t// test recoverable corruption\n\tfor _, c := range []struct {\n\t\tzeroOut [][2]int\n\t}{\n\t\t{},\n\t\t{\n\t\t\tzeroOut: [][2]int{\n\t\t\t\t{0, 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tzeroOut: [][2]int{\n\t\t\t\t{30, 1000},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tzeroOut: [][2]int{\n\t\t\t\t{8, 4},\n\t\t\t\t{40, 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tzeroOut: [][2]int{\n\t\t\t\t{0, talos.Length},\n\t\t\t},\n\t\t},\n\t} {\n\t\tcorrupted := slices.Clone(b)\n\n\t\tfor _, z := range c.zeroOut {\n\t\t\tcopy(corrupted[z[0]:z[0]+z[1]], make([]byte, z[1]))\n\t\t}\n\n\t\ta, err = talos.NewADV(bytes.NewReader(b))\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, a)\n\n\t\tval, ok := a.ReadTag(adv.Reserved1)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, val1, val)\n\n\t\tval, ok = a.ReadTag(adv.Reserved2)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, val2, val)\n\n\t\tval, ok = a.ReadTag(adv.Reserved3)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, val3, val)\n\n\t\ttags := a.ListTags()\n\t\tslices.Sort(tags)\n\t\tassert.Equal(t, []uint8{adv.Reserved1, adv.Reserved2, adv.Reserved3}, tags)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/meta/meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package meta provides access to META partition: key-value partition persisted across reboots.\npackage meta\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\tgoruntime \"runtime\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\tblockdev \"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv/syslinux\"\n\t\"github.com/siderolabs/talos/internal/pkg/meta/internal/adv/talos\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Meta represents the META reader/writer.\n//\n// Meta abstracts away all details about loading/storing the metadata providing an easy to use interface.\ntype Meta struct {\n\tmu sync.Mutex\n\n\tlegacy adv.ADV\n\ttalos  adv.ADV\n\tstate  state.State\n\topts   Options\n}\n\n// Options configures the META.\ntype Options struct {\n\tfixedPath string\n\tprinter   func(string, ...any)\n}\n\n// Option is a functional option.\ntype Option func(*Options)\n\n// WithFixedPath sets the fixed path to META partition.\nfunc WithFixedPath(path string) Option {\n\treturn func(o *Options) {\n\t\to.fixedPath = path\n\t}\n}\n\n// WithPrinter sets the function to print the logs, default is log.Printf.\nfunc WithPrinter(printer func(string, ...any)) Option {\n\treturn func(o *Options) {\n\t\to.printer = printer\n\t}\n}\n\n// New initializes empty META, trying to probe the existing META first.\nfunc New(ctx context.Context, st state.State, opts ...Option) (*Meta, error) {\n\tmeta := &Meta{\n\t\tstate: st,\n\t\topts: Options{\n\t\t\tprinter: log.Printf,\n\t\t},\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(&meta.opts)\n\t}\n\n\tvar err error\n\n\tmeta.legacy, err = syslinux.NewADV(nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeta.talos, err = talos.NewADV(nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = meta.Reload(ctx)\n\n\treturn meta, err\n}\n\nfunc (meta *Meta) getPath(ctx context.Context) (string, string, error) {\n\tif meta.opts.fixedPath != \"\" {\n\t\treturn meta.opts.fixedPath, \"\", nil\n\t}\n\n\tif meta.state == nil {\n\t\treturn \"\", \"\", os.ErrNotExist\n\t}\n\n\tmetaStatus, err := block.WaitForVolumePhase(ctx, meta.state, constants.MetaPartitionLabel, block.VolumePhaseReady, block.VolumePhaseMissing, block.VolumePhaseClosed)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\t// add our own finalizer for the META volume to ensure it never gets removed, even in the late stages of the reboot\n\tif err = meta.state.AddFinalizer(ctx, metaStatus.Metadata(), constants.MetaPartitionLabel); err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\tif metaStatus.TypedSpec().Phase == block.VolumePhaseMissing {\n\t\treturn \"\", \"\", os.ErrNotExist\n\t}\n\n\tif metaStatus.TypedSpec().Phase == block.VolumePhaseClosed && metaStatus.TypedSpec().MountLocation == \"\" {\n\t\treturn \"\", \"\", os.ErrNotExist\n\t}\n\n\treturn metaStatus.TypedSpec().MountLocation, metaStatus.TypedSpec().ParentLocation, nil\n}\n\n// Reload refreshes the META from the disk.\n//\n//nolint:gocyclo\nfunc (meta *Meta) Reload(ctx context.Context) error {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tpath, parentPath, err := meta.getPath(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif parentPath != \"\" {\n\t\tparentDev, err := blockdev.NewFromPath(parentPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer parentDev.Close() //nolint:errcheck\n\n\t\tif err = parentDev.RetryLock(ctx, true); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer parentDev.Unlock() //nolint:errcheck\n\t}\n\n\tmeta.opts.printer(\"META: loading from %s\", path)\n\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tif err := flock(f, unix.LOCK_SH); err != nil {\n\t\treturn err\n\t}\n\n\tadv, err := talos.NewADV(f)\n\tif adv == nil && err != nil {\n\t\t// if adv is not nil, but err is nil, it might be missing ADV, ignore it\n\t\treturn fmt.Errorf(\"failed to load Talos adv: %w\", err)\n\t}\n\n\tlegacyAdv, err := syslinux.NewADV(f)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to load syslinux adv: %w\", err)\n\t}\n\n\t// copy values from in-memory to on-disk version\n\tfor _, t := range meta.talos.ListTags() {\n\t\tval, _ := meta.talos.ReadTagBytes(t)\n\t\tadv.SetTagBytes(t, val)\n\t}\n\n\tmeta.opts.printer(\"META: loaded %d keys\", len(adv.ListTags()))\n\n\tmeta.talos = adv\n\tmeta.legacy = legacyAdv\n\n\treturn meta.syncState(ctx)\n}\n\n// syncState sync resources with adv contents.\nfunc (meta *Meta) syncState(ctx context.Context) error {\n\tif meta.state == nil {\n\t\treturn nil\n\t}\n\n\texistingTags := make(map[resource.ID]struct{})\n\n\tfor _, t := range meta.talos.ListTags() {\n\t\texistingTags[runtime.MetaKeyTagToID(t)] = struct{}{}\n\t\tval, _ := meta.talos.ReadTag(t)\n\n\t\tif err := updateTagResource(ctx, meta.state, t, val); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\titems, err := meta.state.List(ctx, runtime.NewMetaKey(runtime.NamespaceName, \"\").Metadata())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, item := range items.Items {\n\t\tif _, exists := existingTags[item.Metadata().ID()]; exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tif err = meta.state.Destroy(ctx, item.Metadata()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Flush writes the META to the disk.\n//\n//nolint:gocyclo\nfunc (meta *Meta) Flush() error {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tpath, parentPath, err := meta.getPath(context.TODO())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif parentPath != \"\" {\n\t\tparentDev, err := blockdev.NewFromPath(parentPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer parentDev.Close() //nolint:errcheck\n\n\t\tif err = parentDev.RetryLock(context.Background(), true); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer parentDev.Unlock() //nolint:errcheck\n\t}\n\n\tmeta.opts.printer(\"META: saving to %s\", path)\n\n\tf, err := os.OpenFile(path, os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tif err := flock(f, unix.LOCK_EX); err != nil {\n\t\treturn err\n\t}\n\n\tserialized, err := meta.talos.Bytes()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tn, err := f.WriteAt(serialized, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif n != len(serialized) {\n\t\treturn fmt.Errorf(\"expected to write %d bytes, wrote %d\", len(serialized), n)\n\t}\n\n\tserialized, err = meta.legacy.Bytes()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toffset, err := f.Seek(-int64(len(serialized)), io.SeekEnd)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tn, err = f.WriteAt(serialized, offset)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif n != len(serialized) {\n\t\treturn fmt.Errorf(\"expected to write %d bytes, wrote %d\", len(serialized), n)\n\t}\n\n\tmeta.opts.printer(\"META: saved %d keys\", len(meta.talos.ListTags()))\n\n\treturn f.Sync()\n}\n\n// ReadTag reads a tag from the META.\nfunc (meta *Meta) ReadTag(t uint8) (val string, ok bool) {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tval, ok = meta.talos.ReadTag(t)\n\tif !ok {\n\t\tval, ok = meta.legacy.ReadTag(t)\n\t}\n\n\treturn val, ok\n}\n\n// ReadTagBytes reads a tag from the META.\nfunc (meta *Meta) ReadTagBytes(t uint8) (val []byte, ok bool) {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tval, ok = meta.talos.ReadTagBytes(t)\n\tif !ok {\n\t\tval, ok = meta.legacy.ReadTagBytes(t)\n\t}\n\n\treturn val, ok\n}\n\n// SetTag writes a tag to the META.\nfunc (meta *Meta) SetTag(ctx context.Context, t uint8, val string) (bool, error) {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tok := meta.talos.SetTag(t, val)\n\n\tif ok {\n\t\terr := updateTagResource(ctx, meta.state, t, val)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\treturn ok, nil\n}\n\n// SetTagBytes writes a tag to the META.\nfunc (meta *Meta) SetTagBytes(ctx context.Context, t uint8, val []byte) (bool, error) {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tok := meta.talos.SetTagBytes(t, val)\n\n\tif ok {\n\t\terr := updateTagResource(ctx, meta.state, t, string(val))\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\treturn ok, nil\n}\n\n// DeleteTag deletes a tag from the META.\nfunc (meta *Meta) DeleteTag(ctx context.Context, t uint8) (bool, error) {\n\tmeta.mu.Lock()\n\tdefer meta.mu.Unlock()\n\n\tok := meta.talos.DeleteTag(t)\n\tif !ok {\n\t\tok = meta.legacy.DeleteTag(t)\n\t}\n\n\tif meta.state == nil {\n\t\treturn ok, nil\n\t}\n\n\terr := meta.state.Destroy(ctx, runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(t)).Metadata())\n\tif state.IsNotFoundError(err) {\n\t\terr = nil\n\t}\n\n\treturn ok, err\n}\n\nfunc updateTagResource(ctx context.Context, st state.State, t uint8, val string) error {\n\tif st == nil {\n\t\treturn nil\n\t}\n\n\t_, err := safe.StateUpdateWithConflicts(ctx, st, runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(t)).Metadata(), func(r *runtime.MetaKey) error {\n\t\tr.TypedSpec().Value = val\n\n\t\treturn nil\n\t})\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif state.IsNotFoundError(err) {\n\t\tr := runtime.NewMetaKey(runtime.NamespaceName, runtime.MetaKeyTagToID(t))\n\t\tr.TypedSpec().Value = val\n\n\t\treturn st.Create(ctx, r)\n\t}\n\n\treturn err\n}\n\nfunc flock(f *os.File, flag int) error {\n\tfor {\n\t\tif err := unix.Flock(int(f.Fd()), flag); !errors.Is(err, unix.EINTR) {\n\t\t\treturn err\n\t\t}\n\n\t\tgoruntime.KeepAlive(f)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/meta/meta_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package meta provides access to META partition: key-value partition persisted across reboots.\npackage meta_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/meta\"\n\tmetaconsts \"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc setupTest(t *testing.T) (*meta.Meta, string, state.State) {\n\tt.Helper()\n\n\ttmpDir := t.TempDir()\n\n\tpath := filepath.Join(tmpDir, \"meta\")\n\n\tf, err := os.Create(path)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f.Truncate(1024*1024))\n\n\trequire.NoError(t, f.Close())\n\n\tst := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\tm, err := meta.New(t.Context(), st, meta.WithFixedPath(path))\n\trequire.NoError(t, err)\n\n\treturn m, path, st\n}\n\nfunc TestFlow(t *testing.T) {\n\tt.Parallel()\n\n\tm, path, st := setupTest(t)\n\n\tctx := t.Context()\n\n\tok, err := m.SetTag(ctx, metaconsts.Upgrade, \"1.2.3\")\n\trequire.NoError(t, err)\n\tassert.True(t, ok)\n\n\tval, ok := m.ReadTag(metaconsts.Upgrade)\n\tassert.True(t, ok)\n\tassert.Equal(t, \"1.2.3\", val)\n\n\t_, ok = m.ReadTag(metaconsts.StagedUpgradeImageRef)\n\tassert.False(t, ok)\n\n\tok, err = m.DeleteTag(ctx, metaconsts.Upgrade)\n\trequire.NoError(t, err)\n\tassert.True(t, ok)\n\n\tok, err = m.SetTag(ctx, metaconsts.StagedUpgradeInstallOptions, \"install-fast\")\n\trequire.NoError(t, err)\n\tassert.True(t, ok)\n\n\tassert.NoError(t, m.Flush())\n\n\tassert.NoError(t, m.Reload(ctx))\n\n\tval, ok = m.ReadTag(metaconsts.StagedUpgradeInstallOptions)\n\tassert.True(t, ok)\n\tassert.Equal(t, \"install-fast\", val)\n\n\tm2, err := meta.New(ctx, st, meta.WithFixedPath(path))\n\trequire.NoError(t, err)\n\n\t_, ok = m2.ReadTag(metaconsts.Upgrade)\n\tassert.False(t, ok)\n\n\tval, ok = m2.ReadTag(metaconsts.StagedUpgradeInstallOptions)\n\tassert.True(t, ok)\n\tassert.Equal(t, \"install-fast\", val)\n\n\tlist, err := safe.StateList[*runtime.MetaKey](ctx, st, runtime.NewMetaKey(runtime.NamespaceName, \"\").Metadata())\n\trequire.NoError(t, err)\n\n\tfor res := range list.All() {\n\t\tassert.Equal(t, \"0x08\", res.Metadata().ID())\n\t\tassert.Equal(t, \"install-fast\", res.TypedSpec().Value)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/miniprocfs/miniprocfs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package miniprocfs contains optimized small interface to access /proc filesystem.\npackage miniprocfs\n"
  },
  {
    "path": "internal/pkg/miniprocfs/processes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage miniprocfs\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\nconst (\n\tprocsPageSize = 256\n\tprocsBufSize  = 16 * 1024\n\tuserHz        = 100\n)\n\n// Processes wraps iterative walker over processes under /proc.\ntype Processes struct {\n\tfd       *os.File\n\tdirnames []string\n\tidx      int\n\n\tbuf      []byte\n\tpagesize int\n\n\tRootPath string\n}\n\n// NewProcesses initializes process info iterator with path /proc.\nfunc NewProcesses() (*Processes, error) {\n\treturn NewProcessesWithPath(\"/proc\")\n}\n\n// NewProcessesWithPath initializes process info iterator with non-default path.\nfunc NewProcessesWithPath(rootPath string) (*Processes, error) {\n\tprocs := &Processes{\n\t\tRootPath: rootPath,\n\t\tbuf:      make([]byte, procsBufSize),\n\t}\n\n\tvar err error\n\n\tprocs.fd, err = os.Open(rootPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprocs.pagesize = os.Getpagesize()\n\n\treturn procs, nil\n}\n\n// Close the iterator.\nfunc (procs *Processes) Close() error {\n\treturn procs.fd.Close()\n}\n\n// Next returns process info until the list of processes is exhausted.\n//\n// Next returns nil, nil when all processes were processed.\n// Next skips processes which can't be analyzed.\nfunc (procs *Processes) Next() (*machine.ProcessInfo, error) {\n\tfor {\n\t\tif procs.idx >= len(procs.dirnames) {\n\t\t\tvar err error\n\n\t\t\tprocs.dirnames, err = procs.fd.Readdirnames(procsPageSize)\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tprocs.idx = 0\n\t\t}\n\n\t\tinfo, err := procs.readProc(procs.dirnames[procs.idx])\n\t\tprocs.idx++\n\n\t\t// if err != nil, this process was killed before we were able to read /proc data\n\t\tif err == nil {\n\t\t\treturn info, nil\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc (procs *Processes) readProc(pidString string) (*machine.ProcessInfo, error) {\n\tpid, err := strconv.ParseInt(pidString, 10, 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpath := procs.RootPath + \"/\" + pidString + \"/\"\n\n\texecutable, err := os.Readlink(path + \"exe\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = procs.readFileIntoBuf(path + \"comm\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\tcommand := string(bytes.TrimSpace(procs.buf))\n\n\tif err = procs.readFileIntoBuf(path + \"cmdline\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\targs := string(bytes.ReplaceAll(bytes.TrimRight(procs.buf, \"\\x00\"), []byte{0}, []byte{' '}))\n\n\tif err = procs.readFileIntoBuf(path + \"stat\"); err != nil {\n\t\treturn nil, err\n\t}\n\n\trbracket := bytes.LastIndexByte(procs.buf, ')')\n\tif rbracket == -1 {\n\t\treturn nil, errors.New(\"unexpected format\")\n\t}\n\n\tfields := bytes.Fields(procs.buf[rbracket+2:])\n\n\tstate := string(fields[0])\n\n\tppid, err := strconv.ParseInt(string(fields[1]), 10, 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnumThreads, err := strconv.ParseInt(string(fields[17]), 10, 32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tuTime, err := strconv.ParseUint(string(fields[11]), 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsTime, err := strconv.ParseUint(string(fields[12]), 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvSize, err := strconv.ParseUint(string(fields[20]), 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trss, err := strconv.ParseUint(string(fields[21]), 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar label string\n\n\tif err = procs.readFileIntoBuf(path + \"attr/current\"); err == nil {\n\t\tlabel = string(bytes.Trim(procs.buf, \"\\x00\\n\"))\n\t}\n\n\treturn &machine.ProcessInfo{\n\t\tPid:            int32(pid),\n\t\tPpid:           int32(ppid),\n\t\tState:          state,\n\t\tThreads:        int32(numThreads),\n\t\tCpuTime:        float64(uTime+sTime) / userHz,\n\t\tVirtualMemory:  vSize,\n\t\tResidentMemory: rss * uint64(procs.pagesize),\n\t\tCommand:        command,\n\t\tExecutable:     executable,\n\t\tArgs:           args,\n\t\tLabel:          label,\n\t}, nil\n}\n\nfunc (procs *Processes) readFileIntoBuf(path string) error {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tprocs.buf = procs.buf[:cap(procs.buf)]\n\n\tn, err := f.Read(procs.buf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tprocs.buf = procs.buf[:n]\n\n\treturn f.Close()\n}\n"
  },
  {
    "path": "internal/pkg/miniprocfs/processes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage miniprocfs_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/prometheus/procfs\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/miniprocfs\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n)\n\nfunc TestLive(t *testing.T) {\n\tprocesses, err := miniprocfs.NewProcesses()\n\trequire.NoError(t, err)\n\n\tcount := 0\n\n\tfor {\n\t\tproc, err := processes.Next()\n\t\trequire.NoError(t, err)\n\n\t\tif proc == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tcount++\n\t}\n\n\tassert.Greater(t, count, 0)\n\n\tassert.NoError(t, processes.Close())\n}\n\nfunc TestMock(t *testing.T) {\n\tprocesses, err := miniprocfs.NewProcessesWithPath(\"testdata/\")\n\trequire.NoError(t, err)\n\n\tgold, err := procfs.NewFS(\"testdata/\")\n\trequire.NoError(t, err)\n\n\tfor {\n\t\tproc, err := processes.Next()\n\t\trequire.NoError(t, err)\n\n\t\tif proc == nil {\n\t\t\tbreak\n\t\t}\n\n\t\tgoldInfo, err := gold.Proc(int(proc.Pid))\n\t\trequire.NoError(t, err)\n\n\t\tgoldExecutable, err := goldInfo.Executable()\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, goldExecutable, proc.Executable)\n\n\t\tgoldCommand, err := goldInfo.Comm()\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, goldCommand, proc.Command)\n\n\t\tgoldCmdline, err := goldInfo.CmdLine()\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, strings.Join(goldCmdline, \" \"), proc.Args)\n\n\t\tgoldStat, err := goldInfo.Stat()\n\t\trequire.NoError(t, err)\n\n\t\tassert.EqualValues(t, goldStat.PPID, proc.Ppid)\n\t\tassert.EqualValues(t, goldStat.NumThreads, proc.Threads)\n\t\tassert.EqualValues(t, goldStat.CPUTime(), proc.CpuTime)\n\t\tassert.EqualValues(t, goldStat.VirtualMemory(), proc.VirtualMemory)\n\t\tassert.EqualValues(t, goldStat.ResidentMemory(), proc.ResidentMemory)\n\t}\n\n\tassert.NoError(t, processes.Close())\n}\n\nfunc BenchmarkPrometheusProcfs(b *testing.B) {\n\tb.ReportAllocs()\n\n\tfor b.Loop() {\n\t\tvar resp []*machine.ProcessInfo\n\n\t\tprocs, err := procfs.AllProcs()\n\t\trequire.NoError(b, err)\n\n\t\tfor _, proc := range procs {\n\t\t\texecutable, err := proc.Executable()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcommand, err := proc.Comm()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\targs, err := proc.CmdLine()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstats, err := proc.Stat()\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tresp = append(resp, &machine.ProcessInfo{\n\t\t\t\tPid:            int32(proc.PID),\n\t\t\t\tPpid:           int32(stats.PPID),\n\t\t\t\tState:          stats.State,\n\t\t\t\tThreads:        int32(stats.NumThreads),\n\t\t\t\tCpuTime:        stats.CPUTime(),\n\t\t\t\tVirtualMemory:  uint64(stats.VirtualMemory()),\n\t\t\t\tResidentMemory: uint64(stats.ResidentMemory()),\n\t\t\t\tCommand:        command,\n\t\t\t\tExecutable:     executable,\n\t\t\t\tArgs:           strings.Join(args, \" \"),\n\t\t\t})\n\t\t}\n\n\t\t_ = resp\n\t}\n}\n\nfunc BenchmarkProcesses(b *testing.B) {\n\tb.ReportAllocs()\n\n\tfor b.Loop() {\n\t\tvar resp []*machine.ProcessInfo\n\n\t\tprocesses, err := miniprocfs.NewProcesses()\n\t\trequire.NoError(b, err)\n\n\t\tfor {\n\t\t\tproc, err := processes.Next()\n\t\t\trequire.NoError(b, err)\n\n\t\t\tif proc == nil {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tresp = append(resp, proc)\n\t\t}\n\n\t\t_ = resp\n\n\t\tassert.NoError(b, processes.Close())\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/1920080/comm",
    "content": "fish\n"
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/1920080/stat",
    "content": "1920080 (fish) S 1920079 1920080 1920080 34817 497247 4194304 290636 24169180 15 32793 1888 426 1313442 30669 20 0 2 0 127957791 465002496 5805 18446744073709551615 93935540826112 93935542596848 140726024906784 0 0 0 0 2625540 135356435 0 0 0 17 15 0 0 7 0 0 93935542601152 93935542624320 93935548821504 140726024912137 140726024912143 140726024912143 140726024912874 0\n"
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/3731034/comm",
    "content": "tail\n"
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/3731034/stat",
    "content": "3731034 (tail) S 1919986 3731034 1919986 34816 3731034 4194304 106 0 0 0 44 243 0 0 20 0 1 0 139625799 8593408 230 18446744073709551615 94174076493824 94174076538145 140729409375152 0 0 0 0 0 0 1 0 0 17 1 0 0 0 0 0 94174076561648 94174076563648 94174079950848 140729409379084 140729409379437 140729409379437 140729409380330 0\n"
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/keys",
    "content": ""
  },
  {
    "path": "internal/pkg/miniprocfs/testdata/kmsg",
    "content": ""
  },
  {
    "path": "internal/pkg/mount/switchroot/switchroot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package switchroot provides the switching root filesystem functionality.\npackage switchroot\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/go-debug\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/mount/v3\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Paths preserved in the initramfs.\nvar preservedPaths = map[string]struct{}{\n\tconstants.ExtensionsConfigFile:    {},\n\tquirks.New(\"\").FirmwarePath():     {},\n\tconstants.SDStubDynamicInitrdPath: {},\n}\n\n// Switch moves the rootfs to a specified directory. See\n// https://github.com/karelzak/util-linux/blob/master/sys-utils/switch_root.c.\n//\n//nolint:gocyclo\nfunc Switch(prefix string, mountpoints mount.Managers) (err error) {\n\tlog.Println(\"moving mounts to the new rootfs\")\n\n\tif err = mountpoints.Move(prefix); err != nil {\n\t\treturn err\n\t}\n\n\tlog.Printf(\"changing working directory into %s\", prefix)\n\n\tif err = unix.Chdir(prefix); err != nil {\n\t\treturn fmt.Errorf(\"error changing working directory to %s: %w\", prefix, err)\n\t}\n\n\tvar old *os.File\n\n\tif old, err = os.Open(\"/\"); err != nil {\n\t\treturn fmt.Errorf(\"error opening /: %w\", err)\n\t}\n\n\t//nolint:errcheck\n\tdefer old.Close()\n\n\tlog.Printf(\"moving %s to /\", prefix)\n\n\tif err = unix.Mount(prefix, \"/\", \"\", unix.MS_MOVE, \"\"); err != nil {\n\t\treturn fmt.Errorf(\"error moving /: %w\", err)\n\t}\n\n\tlog.Println(\"changing root directory\")\n\n\tif err = unix.Chroot(\".\"); err != nil {\n\t\treturn fmt.Errorf(\"error chroot: %w\", err)\n\t}\n\n\tlog.Println(\"cleaning up initramfs\")\n\n\tif _, err = recursiveDelete(int(old.Fd()), \"/\"); err != nil {\n\t\treturn fmt.Errorf(\"error deleting initramfs: %w\", err)\n\t}\n\n\tif err := selinux.Init(); err != nil {\n\t\treturn err\n\t}\n\n\t// extend PCR 11 with leave-initrd\n\tif err = tpm2.PCRExtend(constants.UKIPCR, []byte(secureboot.LeaveInitrd)); err != nil {\n\t\treturn fmt.Errorf(\"failed to extend PCR %d with leave-initrd: %v\", constants.UKIPCR, err)\n\t}\n\n\t// Note that /sbin/init is machined. We call it init since this is the\n\t// convention.\n\tlog.Println(\"executing /sbin/init\")\n\n\tenvv := []string{\n\t\tconstants.EnvGRPCEnforccceALPNEnabled,\n\t\tconstants.EnvTcellMinimizeEnvironment,\n\t}\n\n\tif debug.RaceEnabled {\n\t\tenvv = append(envv, constants.EnvGoraceHaltOnError)\n\n\t\tlog.Printf(\"race detection enabled with halt_on_error=1\")\n\t}\n\n\tif val := procfs.ProcCmdline().Get(\"talos.fips140\"); val != nil && fipsmode.Enabled() {\n\t\tif pointer.SafeDeref(val.First()) == \"strict\" {\n\t\t\tenvv = append(envv, constants.EnvFIPS140ModeStrict)\n\t\t}\n\t}\n\n\tif val := procfs.ProcCmdline().Get(\"talos.debugshell\"); val != nil {\n\t\tif err = unix.Exec(\"/bin/bash\", []string{\"/bin/bash\"}, envv); err != nil {\n\t\t\treturn fmt.Errorf(\"error executing /bin/bash: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err = unix.Exec(\"/sbin/init\", []string{\"/sbin/init\"}, envv); err != nil {\n\t\treturn fmt.Errorf(\"error executing /sbin/init: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc recursiveDelete(fd int, path string) (preserved bool, err error) {\n\tparentDev, err := getDev(fd)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tdir := os.NewFile(uintptr(fd), \"__ignored__\")\n\t//nolint:errcheck\n\tdefer dir.Close()\n\n\tnames, err := dir.Readdirnames(-1)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tpreserved = false\n\n\tfor _, name := range names {\n\t\tp, err := recusiveDeleteInner(fd, parentDev, name, filepath.Join(path, name))\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tpreserved = preserved || p\n\t}\n\n\treturn preserved, nil\n}\n\nfunc recusiveDeleteInner(parentFd int, parentDev uint64, childName, path string) (preserved bool, err error) {\n\tif _, preserved = preservedPaths[path]; preserved {\n\t\treturn preserved, nil\n\t}\n\n\tchildFd, err := unix.Openat(parentFd, childName, unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, unix.O_RDWR)\n\tif err != nil {\n\t\treturn false, unix.Unlinkat(parentFd, childName, 0)\n\t}\n\n\t//nolint:errcheck\n\tdefer unix.Close(childFd)\n\n\tvar childFdDev uint64\n\n\tif childFdDev, err = getDev(childFd); err != nil {\n\t\treturn false, err\n\t} else if childFdDev != parentDev {\n\t\treturn false, nil\n\t}\n\n\tpreserved, err = recursiveDelete(childFd, path)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif preserved {\n\t\t// some child paths got preserved, skip unlinking the parent\n\t\treturn preserved, nil\n\t}\n\n\terr = unix.Unlinkat(parentFd, childName, unix.AT_REMOVEDIR)\n\n\treturn false, err\n}\n\nfunc getDev(fd int) (dev uint64, err error) {\n\tvar stat unix.Stat_t\n\n\tif err := unix.Fstat(fd, &stat); err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn stat.Dev, nil\n}\n"
  },
  {
    "path": "internal/pkg/mount/switchroot/switchroot_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage switchroot_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/all.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc unmountWithTimeout(target string, flags int, timeout time.Duration) error {\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\terrCh <- unix.Unmount(target, flags)\n\t}()\n\n\ttimer := time.NewTimer(timeout)\n\tdefer timer.Stop()\n\n\tselect {\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"unmounting %s timed out after %s\", target, timeout)\n\tcase err := <-errCh:\n\t\treturn err\n\t}\n}\n\n// UnmountAll attempts to unmount all the mounted filesystems via \"self\" mountinfo.\nfunc UnmountAll() error {\n\t// timeout in seconds\n\tconst timeout = 10\n\n\tticker := time.NewTicker(time.Second)\n\tdefer ticker.Stop()\n\n\tfor range timeout {\n\t\tmounts, err := readMountInfo()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfailedUnmounts := 0\n\n\t\tfor _, mountInfo := range mounts {\n\t\t\tif mountInfo.MountPoint == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif strings.HasPrefix(mountInfo.MountSource, \"/dev/\") {\n\t\t\t\terr = unmountWithTimeout(mountInfo.MountPoint, 0, time.Second)\n\t\t\t\tif err == nil {\n\t\t\t\t\tlog.Printf(\"unmounted %s (%s)\", mountInfo.MountPoint, mountInfo.MountSource)\n\t\t\t\t} else {\n\t\t\t\t\tlog.Printf(\"failed unmounting %s: %s\", mountInfo.MountPoint, err)\n\n\t\t\t\t\tfailedUnmounts++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif failedUnmounts == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tlog.Printf(\"retrying %d unmount operations...\", failedUnmounts)\n\n\t\t<-ticker.C\n\t}\n\n\treturn nil\n}\n\ntype mountInfo struct {\n\tMountPoint  string\n\tMountSource string\n}\n\nfunc readMountInfo() ([]mountInfo, error) {\n\tf, err := os.Open(\"/proc/self/mountinfo\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tvar mounts []mountInfo\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\n\t\tparts := strings.SplitN(line, \" - \", 2)\n\n\t\tif len(parts) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar mntInfo mountInfo\n\n\t\tpre := strings.Fields(parts[0])\n\t\tpost := strings.Fields(parts[1])\n\n\t\tif len(pre) >= 5 {\n\t\t\tmntInfo.MountPoint = pre[4]\n\t\t}\n\n\t\tif len(post) >= 2 {\n\t\t\tmntInfo.MountSource = post[1]\n\t\t}\n\n\t\tmounts = append(mounts, mntInfo)\n\t}\n\n\treturn mounts, scanner.Err()\n}\n\nfunc getSubmounts(target string) ([]string, error) {\n\tmounts, err := readMountInfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar submounts []string\n\n\tfor _, mnt := range mounts {\n\t\tif mnt.MountPoint == target {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(mnt.MountPoint, target+\"/\") {\n\t\t\tsubmounts = append(submounts, mnt.MountPoint)\n\t\t}\n\t}\n\n\tsort.Slice(submounts, func(i, j int) bool {\n\t\treturn len(submounts[i]) > len(submounts[j])\n\t})\n\n\treturn submounts, nil\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/helpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/freddierice/go-losetup/v2\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\n//\n// NOTE: This file is a rewrite of various helpers from mount/v2.\n//\n\nfunc discard(string, ...any) {}\n\n// NewCgroup2 creates a new cgroup2 filesystem.\nfunc NewCgroup2() *Manager {\n\treturn NewManager(\n\t\tWithTarget(constants.CgroupMountPath),\n\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_RELATIME),\n\t\tWithFsopen(\n\t\t\t\"cgroup2\",\n\t\t\tfsopen.WithBoolParameter(\"nsdelegate\"),\n\t\t\tfsopen.WithBoolParameter(\"memory_recursiveprot\"),\n\t\t),\n\t)\n}\n\n// NewReadOnlyOverlay creates a new read-only overlay filesystem.\nfunc NewReadOnlyOverlay(sources []string, target string, printer func(string, ...any), options ...ManagerOption) *Manager {\n\tfsOptions := []fsopen.Option{}\n\n\tif printer != nil {\n\t\tprinter(\"mounting %d overlays: %v\", len(sources), sources)\n\t}\n\n\tif len(sources) > 1 {\n\t\tfor _, source := range sources {\n\t\t\tfsOptions = append(fsOptions, fsopen.WithStringParameter(\"lowerdir+\", source))\n\t\t}\n\t} else if len(sources) == 1 {\n\t\tfsOptions = append(fsOptions, fsopen.WithStringParameter(\"lowerdir\", sources[0]))\n\t}\n\n\toptions = append(options,\n\t\tWithPrinter(printer),\n\t\tWithTarget(target),\n\t\tWithReadOnly(),\n\t\tWithFsopen(\"overlay\", fsOptions...),\n\t)\n\n\treturn NewManager(options...)\n}\n\n// NewOverlayWithBasePath creates a new overlay filesystem with a base path.\nfunc NewOverlayWithBasePath(sources []string, target, basePath string, printer func(string, ...any), options ...ManagerOption) *Manager {\n\t_, overlayPrefix, _ := strings.Cut(target, \"/\")\n\toverlayPrefix = strings.ReplaceAll(overlayPrefix, \"/\", \"-\")\n\n\tdiff := fmt.Sprintf(filepath.Join(basePath, \"%s-diff\"), overlayPrefix)\n\tworkdir := fmt.Sprintf(filepath.Join(basePath, \"%s-workdir\"), overlayPrefix)\n\n\tfsOptions := []fsopen.Option{\n\t\tfsopen.WithStringParameter(\"upperdir\", diff),\n\t\tfsopen.WithStringParameter(\"workdir\", workdir),\n\t}\n\n\tif len(sources) > 1 {\n\t\tfor _, source := range sources {\n\t\t\tfsOptions = append(fsOptions, fsopen.WithStringParameter(\"lowerdir+\", source))\n\t\t}\n\t} else if len(sources) == 1 {\n\t\tfsOptions = append(fsOptions, fsopen.WithStringParameter(\"lowerdir\", sources[0]))\n\t}\n\n\toptions = append(options,\n\t\tWithTarget(target),\n\t\tWithExtraDirs(diff, workdir),\n\t\tWithFsopen(\"overlay\", fsOptions...),\n\t\tWithPrinter(printer),\n\t)\n\n\treturn NewManager(options...)\n}\n\n// NewVarOverlay creates a new /var overlay filesystem.\nfunc NewVarOverlay(sources []string, target string, printer func(string, ...any), options ...ManagerOption) *Manager {\n\treturn NewOverlayWithBasePath(sources, target, constants.VarSystemOverlaysPath, printer, options...)\n}\n\n// NewSystemOverlay creates a new /system overlay filesystem.\nfunc NewSystemOverlay(sources []string, target string, printer func(string, ...any), options ...ManagerOption) *Manager {\n\treturn NewOverlayWithBasePath(sources, target, constants.SystemOverlaysPath, printer, options...)\n}\n\n// Squashfs binds the squashfs to the loop device and returns the mountpoint for it to the specified target.\nfunc Squashfs(target, squashfsFile string, printer func(string, ...any)) (*Manager, error) {\n\tdev, err := losetup.Attach(squashfsFile, 0, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewManager(\n\t\tWithTarget(target),\n\t\tWithPrinter(printer),\n\t\tWithReadOnly(),\n\t\tWithShared(),\n\t\tWithExtraUnmountCallbacks(func(m *Manager) {\n\t\t\tdev.Detach() //nolint:errcheck\n\t\t}),\n\t\tWithFsopen(\n\t\t\t\"squashfs\",\n\t\t\tfsopen.WithSource(dev.Path()),\n\t\t\tfsopen.WithBoolParameter(\"ro\"),\n\t\t),\n\t), nil\n}\n\nfunc gather[T comparable](c ...func() T) []T {\n\tvar (\n\t\tzero T\n\t\tvals []T\n\t)\n\n\tfor _, f := range c {\n\t\tval := f()\n\n\t\tif val != zero {\n\t\t\tvals = append(vals, val)\n\t\t}\n\t}\n\n\treturn vals\n}\n\nfunc newManager(condition func() bool, opts ...ManagerOption) func() *Manager {\n\treturn func() *Manager {\n\t\tif !condition() {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn NewManager(opts...)\n\t}\n}\n\nfunc always() bool { return true }\n\nfunc hasEFIVars() bool {\n\t_, err := os.Stat(constants.EFIVarsMountPoint)\n\n\tif err == nil || errors.Is(err, os.ErrNotExist) {\n\t\treturn err == nil\n\t}\n\n\t// this means something else is wrong, let's panic\n\t// as this should never happen\n\tpanic(err)\n}\n\n// Pseudo creates basic filesystem mountpoint managers.\nfunc Pseudo(printer func(string, ...any)) Managers {\n\treturn gather(\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/dev\"),\n\t\t\tWithKeepOpenAfterMount(),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID),\n\t\t\tWithFsopen(\n\t\t\t\t\"devtmpfs\",\n\t\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\t),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/proc\"),\n\t\t\tWithKeepOpenAfterMount(),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV),\n\t\t\tWithFsopen(\"proc\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys\"),\n\t\t\tWithKeepOpenAfterMount(),\n\t\t\tWithFsopen(\"sysfs\"),\n\t\t),\n\t)\n}\n\n// PseudoLate creates late pseudo filesystem mountpoint managers.\nfunc PseudoLate(printer func(string, ...any)) Managers {\n\treturn gather(\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/run\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithSelinuxLabel(constants.RunSelinuxLabel),\n\t\t\tWithFsopen(\n\t\t\t\t\"tmpfs\",\n\t\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\t),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/system\"),\n\t\t\tWithSelinuxLabel(constants.SystemSelinuxLabel),\n\t\t\tWithRecursiveUnmount(),\n\t\t\tWithFsopen(\n\t\t\t\t\"tmpfs\",\n\t\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\t),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/tmp\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV),\n\t\t\tWithFsopen(\n\t\t\t\t\"tmpfs\",\n\t\t\t\tfsopen.WithStringParameter(\"mode\", \"0755\"),\n\t\t\t\tfsopen.WithStringParameter(\"size\", \"64M\"),\n\t\t\t),\n\t\t),\n\t)\n}\n\n// PseudoSub creates additional pseudo filesystem mountpoint managers.\nfunc PseudoSub(printer func(string, ...any)) Managers {\n\treturn gather(\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/dev/shm\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithFsopen(\"tmpfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/dev/pts\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC),\n\t\t\tWithFsopen(\n\t\t\t\t\"devpts\",\n\t\t\t\tfsopen.WithStringParameter(\"ptmxmode\", \"000\"),\n\t\t\t\tfsopen.WithStringParameter(\"mode\", \"620\"),\n\t\t\t\tfsopen.WithStringParameter(\"gid\", \"5\"),\n\t\t\t),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NODEV),\n\t\t\tWithTarget(\"/dev/hugepages\"),\n\t\t\tWithFsopen(\"hugetlbfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/fs/bpf\"),\n\t\t\tWithFsopen(\"bpf\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/kernel/security\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithFsopen(\"securityfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/kernel/tracing\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV),\n\t\t\tWithFsopen(\"tracefs\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/kernel/config\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithFsopen(\"configfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\talways,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/kernel/debug\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithFsopen(\"debugfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\tselinux.IsEnabled,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(\"/sys/fs/selinux\"),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_RELATIME),\n\t\t\tWithFsopen(\"selinuxfs\"),\n\t\t),\n\t\tnewManager(\n\t\t\thasEFIVars,\n\t\t\tWithPrinter(printer),\n\t\t\tWithTarget(constants.EFIVarsMountPoint),\n\t\t\tWithMountAttributes(unix.MOUNT_ATTR_NOSUID|unix.MOUNT_ATTR_NOEXEC|unix.MOUNT_ATTR_NODEV|unix.MOUNT_ATTR_RELATIME|unix.MOUNT_ATTR_RDONLY),\n\t\t\tWithFsopen(\"efivarfs\"),\n\t\t),\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/manager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\n// Manager is the filesystem manager for mounting and unmounting filesystems.\ntype Manager struct {\n\tfs xfs.FS\n\n\ttarget  string\n\tprinter func(string, ...any)\n\n\tselinuxLabel          string\n\tshared                bool\n\tskipIfMounted         bool\n\tkeepOpen              bool\n\tdetached              bool\n\tmountattr             int\n\textraDirs             []string\n\textraUnmountCallbacks []func(m *Manager)\n\trecursiveUnmount      bool\n\n\tpoint *Point\n}\n\n// NewManager creates a new Manager with the given options.\nfunc NewManager(opts ...ManagerOption) *Manager {\n\tm := &Manager{}\n\n\tfor _, opt := range opts {\n\t\topt.set(m)\n\t}\n\n\treturn m\n}\n\n// Mount mounts a filesystem with the given options.\nfunc (m *Manager) Mount() (*Point, error) {\n\tprinter := discard\n\tif m.printer != nil {\n\t\tprinter = m.printer\n\t}\n\n\tfor _, dir := range m.extraDirs {\n\t\tprinter(\"creating directory tree %q\", dir)\n\n\t\tif !filepath.IsAbs(dir) {\n\t\t\treturn nil, fmt.Errorf(\"dir %q is not absolute\", dir)\n\t\t}\n\n\t\tif err := os.MkdirAll(dir, 0o755); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating mount point directory %q: %w\", dir, err)\n\t\t}\n\t}\n\n\troot := &xfs.UnixRoot{FS: m.fs}\n\n\tif err := root.OpenFS(); err != nil {\n\t\treturn nil, fmt.Errorf(\"openfs failed: %w\", err)\n\t}\n\n\tm.point = &Point{\n\t\troot:         root,\n\t\tdetached:     m.detached,\n\t\tkeepOpen:     m.keepOpen,\n\t\ttarget:       m.target,\n\t\tselinuxLabel: m.selinuxLabel,\n\t}\n\n\topts := Options{\n\t\tPrinter:         printer,\n\t\tShared:          m.shared,\n\t\tSkipIfMounted:   m.skipIfMounted,\n\t\tMountAttributes: m.mountattr,\n\t}\n\n\tif !m.detached {\n\t\tif err := os.MkdirAll(m.target, 0o755); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create mount target %s: %w\", m.target, err)\n\t\t}\n\n\t\tprinter(\"mounting %q to %q\", m.point.Source(), m.target)\n\t}\n\n\tif err := m.point.Mount(opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to mount: %w\", err)\n\t}\n\n\treturn m.point, nil\n}\n\n// Unmount the mount point.\nfunc (m *Manager) Unmount() error {\n\tprinter := discard\n\tif m.printer != nil {\n\t\tprinter = m.printer\n\t}\n\n\topts := UnmountOptions{\n\t\tPrinter:   printer,\n\t\tRecursive: m.recursiveUnmount,\n\t}\n\n\tfor _, cb := range m.extraUnmountCallbacks {\n\t\tdefer cb(m)\n\t}\n\n\treturn m.point.Unmount(opts)\n}\n\n// Move the mount point to a new target.\nfunc (m *Manager) Move(newTarget string) error {\n\treturn m.point.Move(newTarget)\n}\n\n// ManagerOption is an option for configuring the Manager.\ntype ManagerOption struct {\n\tset func(*Manager)\n}\n\n// WithTarget sets the target mount point.\nfunc WithTarget(target string) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.target = target\n\t\t},\n\t}\n}\n\n// WithKeepOpenAfterMount assesses if the mountpoint fd should be kept open after the Mount.\nfunc WithKeepOpenAfterMount() ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.keepOpen = true\n\t\t},\n\t}\n}\n\n// WithSelinuxLabel sets the mount SELinux label.\nfunc WithSelinuxLabel(label string) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.selinuxLabel = label\n\t\t},\n\t}\n}\n\n// WithShared sets the mount as shared.\nfunc WithShared() ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.shared = true\n\t\t},\n\t}\n}\n\n// WithPrinter sets the printer function for logging.\nfunc WithPrinter(printer func(string, ...any)) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.printer = printer\n\t\t},\n\t}\n}\n\n// WithSkipIfMounted sets the option to skip mounting if already mounted.\nfunc WithSkipIfMounted() ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.skipIfMounted = true\n\t\t},\n\t}\n}\n\n// WithFsopen sets the filesystem opener with the given type and options.\nfunc WithFsopen(fstype string, opts ...fsopen.Option) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.fs = fsopen.New(fstype, opts...)\n\t\t},\n\t}\n}\n\n// WithOpentreeFromPath sets the opentree opener with the path.\nfunc WithOpentreeFromPath(path string) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.fs = opentree.NewFromPath(path)\n\t\t},\n\t}\n}\n\n// WithMountAttributes sets the mount attributes.\nfunc WithMountAttributes(flags int) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.mountattr |= flags\n\t\t},\n\t}\n}\n\n// WithDisableAccessTime sets MOUNT_ATTR_NOATIME.\nfunc WithDisableAccessTime() ManagerOption {\n\treturn WithMountAttributes(unix.MOUNT_ATTR_NOATIME)\n}\n\n// WithSecure sets MOUNT_ATTR_NOSUID and MOUNT_ATTR_NODEV.\nfunc WithSecure() ManagerOption {\n\treturn WithMountAttributes(unix.MOUNT_ATTR_NOSUID | unix.MOUNT_ATTR_NODEV)\n}\n\n// WithReadOnly sets the mount as read only.\nfunc WithReadOnly() ManagerOption {\n\treturn WithMountAttributes(unix.MOUNT_ATTR_RDONLY)\n}\n\n// WithDetached sets the mount as detached.\nfunc WithDetached() ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.detached = true\n\t\t\tm.keepOpen = true\n\t\t},\n\t}\n}\n\n// WithExtraDirs adds extra dirs to the manager that should be created prior to mounting the filesystem.\nfunc WithExtraDirs(dirs ...string) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.extraDirs = append(m.extraDirs, dirs...)\n\t\t},\n\t}\n}\n\n// WithExtraUnmountCallbacks adds extra callbacks to the unmount operation.\n// Those need to handle errors by themselves.\nfunc WithExtraUnmountCallbacks(callbacks ...func(m *Manager)) ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.extraUnmountCallbacks = append(m.extraUnmountCallbacks, callbacks...)\n\t\t},\n\t}\n}\n\n// WithRecursiveUnmount enables recursive unmounting of all child mounts before unmounting the target.\nfunc WithRecursiveUnmount() ManagerOption {\n\treturn ManagerOption{\n\t\tset: func(m *Manager) {\n\t\t\tm.recursiveUnmount = true\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/managers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"slices\"\n)\n\n// Managers is a list of mount managers.\ntype Managers []*Manager\n\n// Mount all mount points managed by managers.\nfunc (managers Managers) Mount() (func() error, error) {\n\tunmounters := make([]func() error, 0, len(managers))\n\n\tfor _, manager := range managers {\n\t\tif _, err := manager.Mount(); err != nil {\n\t\t\t// unmount what got already mounted\n\t\t\tslices.Reverse(unmounters)\n\n\t\t\tfor _, unmounter := range unmounters {\n\t\t\t\tif unmountErr := unmounter(); unmountErr != nil {\n\t\t\t\t\terr = errors.Join(err, unmountErr)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tunmounters = append(unmounters, manager.Unmount)\n\t}\n\n\t// unmount last to first\n\tslices.Reverse(unmounters)\n\n\treturn func() error {\n\t\tvar unmountErr error\n\n\t\tfor _, unmounter := range unmounters {\n\t\t\tif err := unmounter(); err != nil {\n\t\t\t\tunmountErr = errors.Join(unmountErr, err)\n\t\t\t}\n\t\t}\n\n\t\treturn unmountErr\n\t}, nil\n}\n\n// Unmount all mount points managed by managers.\nfunc (managers Managers) Unmount() error {\n\tfor i := len(managers) - 1; i >= 0; i-- {\n\t\tif err := managers[i].Unmount(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Move all mount managers to a new prefix.\nfunc (managers Managers) Move(prefix string) error {\n\tfor _, manager := range managers {\n\t\tif err := manager.Move(filepath.Join(prefix, manager.target)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/mount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package mount handles filesystem mount operations.\npackage mount\n\nimport (\n\t\"fmt\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// BindReadonly creates a common way to create a readonly bind mounted destination.\nfunc BindReadonly(src, dst string) error {\n\tsourceFD, err := unix.OpenTree(unix.AT_FDCWD, src, unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to opentree source %s: %w\", src, err)\n\t}\n\n\tdefer unix.Close(sourceFD) //nolint:errcheck\n\n\tif err := unix.MountSetattr(sourceFD, \"\", unix.AT_EMPTY_PATH, &unix.MountAttr{\n\t\tAttr_set: unix.MOUNT_ATTR_RDONLY,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to set mount attribute: %w\", err)\n\t}\n\n\tif err := unix.MoveMount(sourceFD, \"\", unix.AT_FDCWD, dst, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {\n\t\treturn fmt.Errorf(\"failed to move mount from %s to %s: %w\", src, dst, err)\n\t}\n\n\treturn nil\n}\n\n// BindReadonlyFd creates a common way to create a readonly bind mounted destination.\nfunc BindReadonlyFd(dfd int, dst string) error {\n\tsourceFD, err := unix.OpenTree(dfd, \"\", unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to opentree: %w\", err)\n\t}\n\n\tdefer unix.Close(sourceFD) //nolint:errcheck\n\n\tif err := unix.MountSetattr(sourceFD, \"\", unix.AT_EMPTY_PATH, &unix.MountAttr{\n\t\tAttr_set: unix.MOUNT_ATTR_RDONLY,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to set mount attribute: %w\", err)\n\t}\n\n\tif err := unix.MoveMount(sourceFD, \"\", unix.AT_FDCWD, dst, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {\n\t\treturn fmt.Errorf(\"failed to move mount to %s: %w\", dst, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/point.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/selinux\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// Point represents a mount point in the filesystem.\ntype Point struct {\n\troot         xfs.Root\n\tkeepOpen     bool\n\tdetached     bool\n\tfstype       string\n\tsource       string\n\ttarget       string\n\tselinuxLabel string\n}\n\n// NewPoint creates a new mount point.\nfunc NewPoint(source string, srcfd int, target string, targetfd int, fstype string) *Point {\n\treturn &Point{\n\t\tsource: source,\n\t\ttarget: target,\n\t\tfstype: fstype,\n\t}\n}\n\n// Options represents options for mounting a mount point.\ntype Options struct {\n\tSkipIfMounted   bool\n\tMountAttributes int\n\tShared          bool\n\tPrinter         func(string, ...any)\n}\n\n// Mount the mount point.\n//\n//nolint:gocyclo\nfunc (p *Point) Mount(opts Options) error {\n\tdefer p.Release(false) //nolint:errcheck\n\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\tif opts.SkipIfMounted {\n\t\tisMounted, err := p.IsMounted()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif isMounted {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn p.retry(func() error {\n\t\tif err := p.moveMount(p.target); err != nil {\n\t\t\treturn fmt.Errorf(\"error mounting %q to %q: %w\", p.Source(), p.target, err)\n\t\t}\n\n\t\tif err := p.setattr(&unix.MountAttr{\n\t\t\tAttr_set: uint64(opts.MountAttributes),\n\t\t}, 0); err != nil {\n\t\t\treturn fmt.Errorf(\"error setting mountattributes on %s: %w\", p.target, err)\n\t\t}\n\n\t\tif opts.Shared {\n\t\t\tif err := p.Share(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error making %q shared: %w\", p.target, err)\n\t\t\t}\n\t\t}\n\n\t\treturn FilterSelinuxLabelErrors(p.Target(), p.FSType(), selinux.SetLabel(p.target, p.selinuxLabel))\n\t}, false)\n}\n\n// FilterSelinuxLabelErrors filters out certain errors when setting the SELinux label on the mount point.\n//   - ENOTSUP is ignored for all filesystems, as it indicates that the filesystem does not support extended attributes.\n//   - EROFS is ignored for virtiofs, as it indicates that the underlying filesystem is read-only and does not support setting labels.\nfunc FilterSelinuxLabelErrors(target, fstype string, err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif errors.Is(err, unix.ENOTSUP) {\n\t\treturn nil\n\t}\n\n\tif fstype == \"virtiofs\" && errors.Is(err, unix.EROFS) {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"error setting selinux label on %q: %w\", target, err)\n}\n\n// Share makes the mount point shared.\nfunc (p *Point) Share() error {\n\tif p.detached {\n\t\treturn syscall.EINVAL\n\t}\n\n\treturn p.setattr(&unix.MountAttr{\n\t\tPropagation: unix.MS_SHARED,\n\t}, unix.AT_RECURSIVE)\n}\n\n// UnmountOptions represents options for unmounting a mount point.\ntype UnmountOptions struct {\n\tPrinter   func(string, ...any)\n\tRecursive bool\n}\n\n// Release closes the file descriptor of the underlying mount point.\nfunc (p *Point) Release(force bool) error {\n\tif p.keepOpen && !force {\n\t\treturn nil\n\t}\n\n\treturn p.root.Close()\n}\n\n// Unmount unmounts the mount point, retrying on certain errors.\nfunc (p *Point) Unmount(opts UnmountOptions) error {\n\tif err := p.Release(true); err != nil {\n\t\treturn err\n\t}\n\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\treturn p.retry(func() error {\n\t\treturn SafeUnmount(context.Background(), opts.Printer, p.target, opts.Recursive)\n\t}, true)\n}\n\n// IsMounted checks if the mount point is mounted by checking the mount on the target.\nfunc (p *Point) IsMounted() (bool, error) {\n\tf, err := os.Open(\"/proc/mounts\")\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tfields := strings.Fields(scanner.Text())\n\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\tmountpoint := fields[1]\n\n\t\tif mountpoint == p.target {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\n\treturn false, scanner.Err()\n}\n\n// Move the mount point to a new target.\nfunc (p *Point) Move(newTarget string) error {\n\treturn p.moveMount(newTarget)\n}\n\n//nolint:gocyclo\nfunc (p *Point) retry(f func() error, isUnmount bool) error {\n\treturn retry.Constant(5*time.Second, retry.WithUnits(50*time.Millisecond)).Retry(func() error {\n\t\tif err := f(); err != nil {\n\t\t\tswitch err {\n\t\t\tcase unix.EBUSY:\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\tcase unix.ENOENT, unix.ENXIO:\n\t\t\t\t// if udevd triggers BLKRRPART ioctl, partition device entry might disappear temporarily\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\tcase unix.EUCLEAN, unix.EIO:\n\t\t\t\tif !isUnmount {\n\t\t\t\t\tif errRepair := p.root.RepairFS(context.Background()); errRepair != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error repairing: %w\", errRepair)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\tcase unix.EINVAL:\n\t\t\t\tisMounted, checkErr := p.IsMounted()\n\t\t\t\tif checkErr != nil {\n\t\t\t\t\treturn retry.ExpectedError(checkErr)\n\t\t\t\t}\n\n\t\t\t\tif !isMounted && !isUnmount {\n\t\t\t\t\tif errRepair := p.root.RepairFS(context.Background()); errRepair != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error repairing: %w\", errRepair)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\tif !isMounted && isUnmount { // if partition is already unmounted, ignore EINVAL\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\tdefault:\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc (p *Point) moveMount(target string) error {\n\tfd, err := p.root.Fd()\n\tif err != nil {\n\t\tif p.Source() != \"\" {\n\t\t\tif err := unix.MoveMount(unix.AT_FDCWD, p.Source(), unix.AT_FDCWD, target, 0); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error moving mount from %q to %q: %w\", p.Source(), target, err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error getting root fd: %w\", err)\n\t}\n\n\tif err := unix.MoveMount(fd, \"\", unix.AT_FDCWD, target, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {\n\t\treturn fmt.Errorf(\"error moving detached mount fd=%d to %q: %w\", fd, target, err)\n\t}\n\n\treturn nil\n}\n\n// Target returns the target of the mount point.\nfunc (p *Point) Target() string {\n\treturn p.target\n}\n\n// Source returns the source of the mount point.\nfunc (p *Point) Source() string {\n\tif p.source == \"\" {\n\t\treturn p.root.Source()\n\t}\n\n\treturn p.source\n}\n\n// FSType returns the filesystem type of the mount point.\nfunc (p *Point) FSType() string {\n\tif p.fstype == \"\" {\n\t\treturn p.root.FSType()\n\t}\n\n\treturn p.fstype\n}\n\n// Root returns the underlying xfs.Root of the mount point.\nfunc (p *Point) Root() xfs.Root {\n\treturn p.root\n}\n\n// RemountReadOnly remounts the mount point as read-only.\nfunc (p *Point) RemountReadOnly() error {\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\treturn p.setattr(&unix.MountAttr{\n\t\tAttr_set: unix.MOUNT_ATTR_RDONLY,\n\t}, 0)\n}\n\n// RemountReadWrite remounts the mount point as read-write.\nfunc (p *Point) RemountReadWrite() error {\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\treturn p.setattr(&unix.MountAttr{\n\t\tAttr_clr: unix.MOUNT_ATTR_RDONLY,\n\t}, 0)\n}\n\n// SetDisableAccessTime sets or clears the noatime mount attribute.\nfunc (p *Point) SetDisableAccessTime(disable bool) error {\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\tif disable {\n\t\treturn p.setattr(&unix.MountAttr{\n\t\t\tAttr_set: unix.MOUNT_ATTR_NOATIME,\n\t\t}, 0)\n\t}\n\n\treturn p.setattr(&unix.MountAttr{\n\t\tAttr_clr: unix.MOUNT_ATTR_NOATIME,\n\t}, 0)\n}\n\n// SetSecure sets or clears the nosuid and nodev mount attributes.\nfunc (p *Point) SetSecure(secure bool) error {\n\tif p.detached {\n\t\treturn nil\n\t}\n\n\tif secure {\n\t\treturn p.setattr(&unix.MountAttr{\n\t\t\tAttr_set: unix.MOUNT_ATTR_NOSUID | unix.MOUNT_ATTR_NODEV,\n\t\t}, 0)\n\t}\n\n\treturn p.setattr(&unix.MountAttr{\n\t\tAttr_clr: unix.MOUNT_ATTR_NOSUID | unix.MOUNT_ATTR_NODEV,\n\t}, 0)\n}\n\nfunc (p *Point) setattr(attr *unix.MountAttr, flags int) error {\n\tif (attr.Attr_set&unix.MOUNT_ATTR_NOATIME) != 0 || (attr.Attr_clr&unix.MOUNT_ATTR_NOATIME) != 0 {\n\t\tattr.Attr_clr |= unix.MOUNT_ATTR__ATIME\n\t}\n\n\tfd, err := p.root.Fd()\n\tif err != nil && !errors.Is(err, os.ErrClosed) {\n\t\treturn err\n\t}\n\n\tif p.target != \"\" {\n\t\tfd = unix.AT_FDCWD\n\t} else {\n\t\tflags |= unix.AT_EMPTY_PATH\n\t}\n\n\tif err := unix.MountSetattr(fd, p.target, uint(flags), attr); err != nil {\n\t\treturn fmt.Errorf(\"setattr failed for fd=%d target=%q flags=%d attr=%#+v: %w\", fd, p.target, flags, *attr, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/mount/v3/unmount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage mount\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc trySyncMount(target string, printer func(string, ...any)) error {\n\t// open the mountpoint directory to get an fd on the fs\n\tfd, err := unix.Open(target, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open %q: %w\", target, err)\n\t}\n\tdefer unix.Close(fd) //nolint:errcheck\n\n\t// sync the filesystem backing this fd\n\tif err := unix.Syncfs(fd); err != nil {\n\t\treturn fmt.Errorf(\"SYS_SYNCFS %q: %w\", target, err)\n\t}\n\n\tprinter(\"syncfs(%s) ok\", target)\n\n\treturn nil\n}\n\nfunc unmountLoop(ctx context.Context, printer func(string, ...any), target string, flags int, timeout time.Duration, extraMessage string) (bool, error) {\n\terrCh := make(chan error, 1)\n\n\t// we need to try to sync fs before\n\tif err := trySyncMount(target, printer); err != nil {\n\t\tprinter(\"sync failed: %s\", err)\n\t}\n\n\tgo func() {\n\t\terrCh <- unix.Unmount(target, flags)\n\t}()\n\n\tstart := time.Now()\n\n\tprogressTicker := time.NewTicker(timeout / 5)\n\tdefer progressTicker.Stop()\n\nunmountLoop:\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn true, ctx.Err()\n\t\tcase err := <-errCh:\n\t\t\treturn true, err\n\t\tcase <-progressTicker.C:\n\t\t\ttimeLeft := timeout - time.Since(start)\n\n\t\t\tif timeLeft <= 0 {\n\t\t\t\tbreak unmountLoop\n\t\t\t}\n\n\t\t\tprinter(\"unmounting %s%s is taking longer than expected, still waiting for %s\", target, extraMessage, timeLeft)\n\t\t}\n\t}\n\n\treturn false, nil\n}\n\n// SafeUnmount unmounts the target path, first without force, then with force if the first attempt fails.\n//\n// It makes sure that unmounting has a finite operation timeout.\n// If recursive is true, it will first unmount all child mounts under target.\nfunc SafeUnmount(ctx context.Context, printer func(string, ...any), target string, recursive bool) error {\n\tconst (\n\t\tunmountTimeout      = 90 * time.Second\n\t\tunmountForceTimeout = 10 * time.Second\n\t)\n\n\tif printer == nil {\n\t\tprinter = discard\n\t}\n\n\tif recursive {\n\t\tsubmounts, err := getSubmounts(target)\n\t\tif err != nil {\n\t\t\tprinter(\"failed to get submounts for %s: %v\", target, err)\n\t\t} else {\n\t\t\tfor _, submount := range submounts {\n\t\t\t\tprinter(\"recursively unmounting submount %s\", submount)\n\n\t\t\t\tif err := safeUnmountSingle(ctx, printer, submount, unmountTimeout); err != nil {\n\t\t\t\t\tprinter(\"failed to unmount submount %s: %v\", submount, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tok, err := unmountLoop(ctx, printer, target, 0, unmountTimeout, \"\")\n\n\tif ok {\n\t\treturn err\n\t}\n\n\tlogSubmounts(printer, target)\n\n\tprinter(\"unmounting %s with force\", target)\n\n\tok, err = unmountLoop(ctx, printer, target, unix.MNT_FORCE, unmountForceTimeout, \" with force flag\")\n\n\tif ok {\n\t\treturn err\n\t}\n\n\tlogSubmounts(printer, target)\n\n\treturn fmt.Errorf(\"unmounting %s with force flag timed out\", target)\n}\n\nfunc safeUnmountSingle(ctx context.Context, printer func(string, ...any), target string, timeout time.Duration) error {\n\tok, err := unmountLoop(ctx, printer, target, 0, timeout, \"\")\n\tif ok {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc logSubmounts(printer func(string, ...any), target string) {\n\tsubmounts, err := getSubmounts(target)\n\tif err != nil {\n\t\tprinter(\"failed to get submounts for %s: %v\", target, err)\n\n\t\treturn\n\t}\n\n\tif len(submounts) > 0 {\n\t\tprinter(\"submounts on %s: %v\", target, submounts)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/msguid/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "internal/pkg/msguid/README.md",
    "content": "# msguid\n\nThis package was copied from the upstream repository at [msguid](https://github.com/monogon/monogon/tree/main/osbase/msguid)\n\nThere were minimal changes done to comply with the linter and gofmt rules.\n"
  },
  {
    "path": "internal/pkg/msguid/msguid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\n// Package msguid provides functions to convert UUIDs/GUIDs to and from\n// Microsoft's idiosyncratic \"mixed-endian\" format.\n// See https://uefi.org/specs/UEFI/2.10/Apx_A_GUID_and_Time_Formats.html#text-representation-relationships-apxa-guid-and-time-formats\n// for an explanation of the format.\npackage msguid\n\nimport \"github.com/google/uuid\"\n\nvar mixedEndianTranspose = []int{3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15}\n\n// From converts from a standard UUID into its mixed-endian encoding.\nfunc From(u uuid.UUID) (o [16]byte) {\n\tfor dest, from := range mixedEndianTranspose {\n\t\to[dest] = u[from]\n\t}\n\n\treturn o\n}\n\n// To converts a mixed-endian-encoded UUID to its standard format.\nfunc To(i [16]byte) (o uuid.UUID) {\n\tfor from, dest := range mixedEndianTranspose {\n\t\to[dest] = i[from]\n\t}\n\n\treturn o\n}\n"
  },
  {
    "path": "internal/pkg/msguid/msguid_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Copyright The Monogon Project Authors.\n// SPDX-License-Identifier: Apache-2.0\n\npackage msguid_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/msguid\"\n)\n\nfunc TestRoundTrip(t *testing.T) {\n\tcases := []struct {\n\t\tname     string\n\t\tuuid     string\n\t\texpected [16]byte\n\t}{\n\t\t{\n\t\t\t\"WikipediaExample1\",\n\t\t\t\"00112233-4455-6677-8899-AABBCCDDEEFF\",\n\t\t\t[16]byte{\n\t\t\t\t0x33, 0x22, 0x11, 0x00, 0x55, 0x44, 0x77, 0x66,\n\t\t\t\t0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,\n\t\t\t},\n\t\t},\n\t}\n\tfor _, c := range cases {\n\t\tt.Run(c.name, func(t *testing.T) {\n\t\t\torigUUID := uuid.MustParse(c.uuid)\n\t\t\tgot := msguid.From(origUUID)\n\n\t\t\trequire.Equal(t, c.expected, got, \"From(%q) returned unexpected result\", origUUID)\n\n\t\t\tback := msguid.To(got)\n\n\t\t\trequire.Equal(t, origUUID, back, \"From(To(%q)) did not return original value\", origUUID)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/ntp/consts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage ntp\n\nimport \"time\"\n\nconst (\n\t// MinAllowablePoll is the minimum time allowed for a client to query a time server.\n\tMinAllowablePoll = 32 * time.Second\n\t// MaxAllowablePoll is the maximum allowed interval for querying a time server.\n\tMaxAllowablePoll = 2048 * time.Second\n\t// RetryPoll is the interval between retries if the error is not Kiss-o-Death.\n\tRetryPoll = time.Second\n\t// AdjustTimeLimit is a maximum time drift to compensate via adjtimex().\n\t//\n\t// Deltas smaller than AdjustTimeLimit are gradually adjusted (slewed) to approach the network time.\n\t// Deltas larger than AdjustTimeLimit are set by letting the system time jump.\n\tAdjustTimeLimit = 400 * time.Millisecond\n\t// EpochLimit is a minimum time difference to signal that change as epoch change.\n\tEpochLimit = 15 * time.Minute\n\t// ExpectedAccuracy is the expected time sync accuracy, used to adjust poll interval.\n\tExpectedAccuracy = 200 * time.Millisecond\n)\n"
  },
  {
    "path": "internal/pkg/ntp/interfaces.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage ntp\n\nimport (\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/beevik/ntp\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/timex\"\n)\n\n// CurrentTimeFunc provides a function which returns current time.\ntype CurrentTimeFunc func() time.Time\n\n// QueryFunc provides a function which performs NTP query.\ntype QueryFunc func(server string) (*ntp.Response, error)\n\n// SetTimeFunc provides a function to set system time.\ntype SetTimeFunc func(tv *syscall.Timeval) error\n\n// AdjustTimeFunc provides a function to adjust time.\ntype AdjustTimeFunc func(buf *unix.Timex) (state timex.State, err error)\n"
  },
  {
    "path": "internal/pkg/ntp/internal/spike/spike.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package spike provides a spike detector for NTP responses.\npackage spike\n\nimport (\n\t\"math\"\n\n\t\"github.com/beevik/ntp\"\n)\n\nconst defaultCapacity = 8\n\n// Sample is a single NTP response sample.\ntype Sample struct {\n\tOffset, RTT float64 // in seconds\n}\n\n// SampleFromNTPResponse converts an NTP response to a Sample.\nfunc SampleFromNTPResponse(resp *ntp.Response) Sample {\n\treturn Sample{\n\t\tOffset: resp.ClockOffset.Seconds(),\n\t\tRTT:    resp.RTT.Seconds(),\n\t}\n}\n\n// Detector detects spikes in NTP response samples.\n//\n// Zero value is ready to use.\ntype Detector struct {\n\tpacketCount   int64\n\tsamples       []Sample\n\tsamplesIdx    int\n\tsamplesJitter float64\n}\n\n// IsSpike returns true if the given sample is a spike.\n//\n// The sample is added to the detector's internal state.\nfunc (d *Detector) IsSpike(sample Sample) bool {\n\tif d.samples == nil {\n\t\td.samples = make([]Sample, defaultCapacity)\n\t}\n\n\td.packetCount++\n\n\tif d.packetCount == 1 {\n\t\t// ignore first packet\n\t\treturn false\n\t}\n\n\tvar currentIndex int\n\n\tcurrentIndex, d.samplesIdx = d.samplesIdx, (d.samplesIdx+1)%len(d.samples)\n\n\td.samples[d.samplesIdx] = sample\n\n\tjitter := d.samplesJitter\n\n\tindexMin := currentIndex\n\n\tfor i := range d.samples {\n\t\tif d.samples[i].RTT == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif d.samples[i].RTT < d.samples[indexMin].RTT {\n\t\t\tindexMin = i\n\t\t}\n\t}\n\n\tvar j float64\n\n\tfor i := range d.samples {\n\t\toffsetDiff := d.samples[i].Offset - d.samples[indexMin].Offset\n\t\tj += offsetDiff * offsetDiff\n\t}\n\n\td.samplesJitter = math.Sqrt(j / (float64(len(d.samples)) - 1))\n\n\tif math.Abs(sample.Offset) > sample.RTT {\n\t\t// always accept clock offset if that is larger than rtt\n\t\treturn false\n\t}\n\n\tif d.packetCount < 4 {\n\t\t// need more samples to make a decision\n\t\treturn false\n\t}\n\n\t// This check was specifically removed (while it exists in systemd-timesync),\n\t// as I don't understand why it's needed (@smira).\n\t// It seems to give false positives when the RTT and Offset are close to each other,\n\t// e.g. when NTP server is on the same LAN.\n\t//\n\t// if math.Abs(sample.Offset) > d.samples[indexMin].RTT {\n\t// \t// do not accept anything worse than the maximum possible error of the best sample\n\t// \treturn true\n\t// }\n\n\t// check that diff to the last offset is not more than 3*(observed jitter)\n\treturn math.Abs(sample.Offset-d.samples[currentIndex].Offset) > 3*jitter\n}\n\n// Jitter returns the current jitter.\nfunc (d *Detector) Jitter() float64 {\n\treturn d.samplesJitter\n}\n"
  },
  {
    "path": "internal/pkg/ntp/internal/spike/spike_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage spike_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/ntp/internal/spike\"\n)\n\nfunc TestSpikeDetector(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tname    string\n\t\tsamples []spike.Sample\n\n\t\texpectedSpikes []bool\n\t}{\n\t\t{\n\t\t\tname: \"no spikes\",\n\n\t\t\tsamples: []spike.Sample{\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.05, RTT: 0.01},\n\t\t\t\t{Offset: 0.03, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.02, RTT: 0.03}, // not a spike, just a large RTT\n\t\t\t},\n\n\t\t\texpectedSpikes: []bool{\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"offset spike\",\n\n\t\t\tsamples: []spike.Sample{\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.05, RTT: 0.01},\n\t\t\t\t{Offset: 0.03, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.5, RTT: 0.7}, // spike\n\t\t\t},\n\n\t\t\texpectedSpikes: []bool{\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\ttrue,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"adjusting to higher RTT\",\n\n\t\t\tsamples: []spike.Sample{\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.05, RTT: 0.01},\n\t\t\t\t{Offset: 0.03, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.5, RTT: 0.7}, // spike\n\t\t\t\t{Offset: 0.5, RTT: 0.7},  // spike\n\t\t\t\t{Offset: -0.5, RTT: 0.7}, // spike\n\t\t\t\t{Offset: 0.5, RTT: 0.7},  // not a spike anymore, filter adjusted itself\n\t\t\t\t{Offset: -0.5, RTT: 0.7},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t},\n\n\t\t\texpectedSpikes: []bool{\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\ttrue,\n\t\t\t\ttrue,\n\t\t\t\ttrue,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"initial ignore\",\n\n\t\t\tsamples: []spike.Sample{\n\t\t\t\t{Offset: 5, RTT: 0.01}, // initial packet is ignored completely\n\t\t\t\t{Offset: 0.05, RTT: 0.05},\n\t\t\t\t{Offset: 0.5, RTT: 0.5}, // spike detection kicks in after 4 packets\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t\t{Offset: -0.01, RTT: 0.01},\n\t\t\t\t{Offset: 0.01, RTT: 0.01},\n\t\t\t},\n\n\t\t\texpectedSpikes: []bool{\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t\tfalse,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tvar detector spike.Detector\n\n\t\t\tfor i, sample := range test.samples {\n\t\t\t\tisSpike := detector.IsSpike(sample)\n\n\t\t\t\tassert.Equal(t, test.expectedSpikes[i], isSpike, \"unexpected spike: %v (position %d)\", test.expectedSpikes[i], i)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/ntp/ntp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ntp provides a time sync client via SNTP protocol.\npackage ntp\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"math/bits\"\n\t\"net\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/beevik/ntp\"\n\t\"github.com/u-root/u-root/pkg/rtc\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/ntp/internal/spike\"\n\t\"github.com/siderolabs/talos/internal/pkg/timex\"\n)\n\n// Syncer performs time sync via NTP on schedule.\ntype Syncer struct {\n\tlogger *zap.Logger\n\n\ttimeServersMu  sync.Mutex\n\ttimeServers    []string\n\tlastSyncServer string\n\n\ttimeSyncNotified bool\n\ttimeSynced       chan struct{}\n\n\trestartSyncCh chan struct{}\n\tepochChangeCh chan struct{}\n\n\tfirstSync bool\n\n\tspikeDetector spike.Detector\n\n\tMinPoll, MaxPoll, RetryPoll time.Duration\n\n\t// these functions are overridden in tests for mocking support\n\tCurrentTime CurrentTimeFunc\n\tNTPQuery    QueryFunc\n\tAdjustTime  AdjustTimeFunc\n\tDisableRTC  bool\n}\n\n// Measurement is a struct containing correction data based on a time request.\ntype Measurement struct {\n\tClockOffset time.Duration\n\tLeap        ntp.LeapIndicator\n\tSpike       bool\n}\n\n// NewSyncer creates new Syncer with default configuration.\nfunc NewSyncer(logger *zap.Logger, timeServers []string) *Syncer {\n\tsyncer := &Syncer{\n\t\tlogger: logger,\n\n\t\ttimeServers: slices.Clone(timeServers),\n\t\ttimeSynced:  make(chan struct{}),\n\n\t\trestartSyncCh: make(chan struct{}, 1),\n\t\tepochChangeCh: make(chan struct{}, 1),\n\n\t\tfirstSync: true,\n\n\t\tspikeDetector: spike.Detector{},\n\n\t\tMinPoll:   MinAllowablePoll,\n\t\tMaxPoll:   MaxAllowablePoll,\n\t\tRetryPoll: RetryPoll,\n\n\t\tCurrentTime: time.Now,\n\t\tNTPQuery:    ntp.Query,\n\t\tAdjustTime:  timex.Adjtimex,\n\t}\n\n\treturn syncer\n}\n\n// Synced returns a channel which is closed when time is in sync.\nfunc (syncer *Syncer) Synced() <-chan struct{} {\n\treturn syncer.timeSynced\n}\n\n// EpochChange returns a channel which receives a value each time jumps more than EpochLimit.\nfunc (syncer *Syncer) EpochChange() <-chan struct{} {\n\treturn syncer.epochChangeCh\n}\n\nfunc (syncer *Syncer) getTimeServers() []string {\n\tsyncer.timeServersMu.Lock()\n\tdefer syncer.timeServersMu.Unlock()\n\n\treturn syncer.timeServers\n}\n\nfunc (syncer *Syncer) getLastSyncServer() string {\n\tsyncer.timeServersMu.Lock()\n\tdefer syncer.timeServersMu.Unlock()\n\n\treturn syncer.lastSyncServer\n}\n\nfunc (syncer *Syncer) setLastSyncServer(lastSyncServer string) {\n\tsyncer.timeServersMu.Lock()\n\tdefer syncer.timeServersMu.Unlock()\n\n\tsyncer.lastSyncServer = lastSyncServer\n}\n\n// SetTimeServers sets the list of time servers to use.\nfunc (syncer *Syncer) SetTimeServers(timeServers []string) {\n\tsyncer.timeServersMu.Lock()\n\tdefer syncer.timeServersMu.Unlock()\n\n\tif slices.Equal(timeServers, syncer.timeServers) {\n\t\treturn\n\t}\n\n\tsyncer.timeServers = slices.Clone(timeServers)\n\tsyncer.lastSyncServer = \"\"\n\n\tsyncer.restartSync()\n}\n\nfunc (syncer *Syncer) restartSync() {\n\tselect {\n\tcase syncer.restartSyncCh <- struct{}{}:\n\tdefault:\n\t}\n}\n\nfunc absDuration(d time.Duration) time.Duration {\n\tif d < 0 {\n\t\treturn -d\n\t}\n\n\treturn d\n}\n\nfunc (syncer *Syncer) isSpike(resp *ntp.Response) bool {\n\treturn syncer.spikeDetector.IsSpike(spike.SampleFromNTPResponse(resp))\n}\n\n// Run runs the sync process.\n//\n// Run is usually run in a goroutine.\n// When context is canceled, sync process aborts.\n//\n//nolint:gocyclo,cyclop\nfunc (syncer *Syncer) Run(ctx context.Context) {\n\tvar (\n\t\trtcClock *rtc.RTC\n\t\terr      error\n\t)\n\n\tif !syncer.DisableRTC {\n\t\trtcClock, err = rtc.OpenRTC()\n\t\tif err != nil {\n\t\t\tsyncer.logger.Error(\"failure opening RTC, ignored\", zap.Error(err))\n\t\t} else {\n\t\t\tdefer rtcClock.Close() //nolint:errcheck\n\t\t}\n\t}\n\n\tpollInterval := time.Duration(0)\n\n\tfor {\n\t\tlastSyncServer, resp, err := syncer.query(ctx)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tspike := false\n\t\tif resp != nil {\n\t\t\tspike = resp.Spike\n\t\t}\n\n\t\tswitch {\n\t\tcase resp == nil:\n\t\t\t// if no response was ever received, consider doing short sleep to retry sooner as it's not Kiss-o-Death response\n\t\t\tpollInterval = syncer.RetryPoll\n\t\tcase pollInterval == 0:\n\t\t\t// first sync\n\t\t\tpollInterval = syncer.MinPoll\n\t\tcase !spike && absDuration(resp.ClockOffset) > ExpectedAccuracy:\n\t\t\t// huge offset, retry sync with minimum interval\n\t\t\tpollInterval = syncer.MinPoll\n\t\tcase absDuration(resp.ClockOffset) < ExpectedAccuracy*25/100: // *0.25\n\t\t\t// clock offset is within 25% of expected accuracy, increase poll interval\n\t\t\tif pollInterval < syncer.MaxPoll {\n\t\t\t\tpollInterval *= 2\n\t\t\t}\n\t\tcase spike || absDuration(resp.ClockOffset) > ExpectedAccuracy*75/100: // *0.75\n\t\t\t// spike was detected or clock offset is too large, decrease poll interval\n\t\t\tif pollInterval > syncer.MinPoll {\n\t\t\t\tpollInterval /= 2\n\t\t\t}\n\t\t}\n\n\t\tif resp != nil && pollInterval < syncer.MinPoll {\n\t\t\t// set poll interval to at least min poll if there was any response\n\t\t\tpollInterval = syncer.MinPoll\n\t\t}\n\n\t\tsyncer.logger.Debug(\"sample stats\",\n\t\t\tzap.Duration(\"jitter\", time.Duration(syncer.spikeDetector.Jitter()*float64(time.Second))),\n\t\t\tzap.Duration(\"poll_interval\", pollInterval),\n\t\t\tzap.Bool(\"spike\", spike),\n\t\t\tzap.Bool(\"resp_exists\", resp != nil),\n\t\t)\n\n\t\tif resp != nil && !spike {\n\t\t\terr = syncer.adjustTime(resp.ClockOffset, resp.Leap, lastSyncServer, pollInterval, rtcClock)\n\t\t\tif err == nil {\n\t\t\t\tif !syncer.timeSyncNotified {\n\t\t\t\t\t// successful first time sync, notify about it\n\t\t\t\t\tclose(syncer.timeSynced)\n\n\t\t\t\t\tsyncer.timeSyncNotified = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsyncer.logger.Error(\"error adjusting time\", zap.Error(err))\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase <-syncer.restartSyncCh:\n\t\t\t// time servers got changed, restart the loop immediately\n\t\tcase <-time.After(pollInterval):\n\t\t}\n\t}\n}\n\nfunc (syncer *Syncer) query(ctx context.Context) (lastSyncServer string, measurement *Measurement, err error) {\n\tlastSyncServer = syncer.getLastSyncServer()\n\tfailedServer := \"\"\n\n\tif lastSyncServer != \"\" {\n\t\tmeasurement, err = syncer.queryServer(lastSyncServer)\n\t\tif err != nil {\n\t\t\tsyncer.logger.Error(fmt.Sprintf(\"time query error with server %q\", lastSyncServer), zap.Error(err))\n\n\t\t\tfailedServer = lastSyncServer\n\t\t\tlastSyncServer = \"\"\n\t\t\terr = nil\n\t\t}\n\t}\n\n\tif lastSyncServer == \"\" {\n\t\tvar serverList []string\n\n\t\tserverList, err = syncer.resolveServers(ctx)\n\t\tif err != nil {\n\t\t\treturn lastSyncServer, measurement, err\n\t\t}\n\n\t\tfor _, server := range serverList {\n\t\t\tif server == failedServer {\n\t\t\t\t// skip server which failed in previous sync to avoid sending requests with short interval\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn lastSyncServer, measurement, ctx.Err()\n\t\t\tcase <-syncer.restartSyncCh:\n\t\t\t\tsyncer.restartSync() // re-queue restart for outer loop\n\n\t\t\t\treturn lastSyncServer, measurement, nil\n\t\t\tdefault:\n\t\t\t}\n\n\t\t\tmeasurement, err = syncer.queryServer(server)\n\t\t\tif err != nil {\n\t\t\t\tsyncer.logger.Error(fmt.Sprintf(\"time query error with server %q\", server), zap.Error(err))\n\t\t\t\terr = nil\n\t\t\t} else {\n\t\t\t\tsyncer.setLastSyncServer(server)\n\t\t\t\tlastSyncServer = server\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lastSyncServer, measurement, err\n}\n\n// IsPTPDevice checks if a given server string represents a PTP device.\nfunc IsPTPDevice(server string) bool {\n\treturn strings.HasPrefix(server, \"/dev/\")\n}\n\nfunc (syncer *Syncer) resolveServers(ctx context.Context) ([]string, error) {\n\tvar serverList []string\n\n\tfor _, server := range syncer.getTimeServers() {\n\t\tif IsPTPDevice(server) {\n\t\t\tserverList = append(serverList, server)\n\t\t} else {\n\t\t\tips, err := syncer.lookupIPAddrWithTimeout(ctx, server, 5*time.Second)\n\t\t\tif err != nil {\n\t\t\t\tsyncer.logger.Error(fmt.Sprintf(\"failed looking up %q, ignored\", server), zap.Error(err))\n\t\t\t}\n\n\t\t\tfor _, ip := range ips {\n\t\t\t\tserverList = append(serverList, ip.String())\n\t\t\t}\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tdefault:\n\t\t}\n\t}\n\n\treturn serverList, nil\n}\n\nfunc (syncer *Syncer) lookupIPAddrWithTimeout(ctx context.Context, host string, timeout time.Duration) ([]net.IPAddr, error) {\n\tctx, cancel := context.WithTimeout(ctx, timeout)\n\tdefer cancel()\n\n\treturn (&net.Resolver{}).LookupIPAddr(ctx, host)\n}\n\nfunc (syncer *Syncer) queryServer(server string) (*Measurement, error) {\n\tif IsPTPDevice(server) {\n\t\treturn syncer.queryPTP(server)\n\t}\n\n\treturn syncer.queryNTP(server)\n}\n\nfunc (syncer *Syncer) queryPTP(device string) (*Measurement, error) {\n\tts, err := QueryPTPDevice(device)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\toffset := time.Until(time.Unix(ts.Sec, ts.Nsec))\n\tsyncer.logger.Debug(\"PTP clock\",\n\t\tzap.Duration(\"clock_offset\", offset),\n\t\tzap.Int64(\"sec\", ts.Sec),\n\t\tzap.Int64(\"nsec\", ts.Nsec),\n\t\tzap.String(\"device\", device),\n\t)\n\n\tmeas := &Measurement{\n\t\tClockOffset: offset,\n\t\tLeap:        0,\n\t\tSpike:       false,\n\t}\n\n\treturn meas, err\n}\n\n// QueryPTPDevice queries PTP device for current time.\nfunc QueryPTPDevice(device string) (unix.Timespec, error) {\n\tphc, err := os.Open(device)\n\tif err != nil {\n\t\treturn unix.Timespec{}, err\n\t}\n\n\tdefer phc.Close() //nolint:errcheck\n\n\t// From clock_gettime(2):\n\t//\n\t// Using  the  appropriate  macros,  open file descriptors may be converted into clock IDs and passed to clock_gettime(), clock_settime(), and clock_adjtime(2).  The\n\t// following example shows how to convert a file descriptor into a dynamic clock ID.\n\t//\n\t// \t#define CLOCKFD 3\n\t// \t#define FD_TO_CLOCKID(fd)   ((~(clockid_t) (fd) << 3) | CLOCKFD)\n\n\tclockid := int32(3 | (^phc.Fd() << 3))\n\n\tvar ts unix.Timespec\n\n\terr = unix.ClockGettime(clockid, &ts)\n\tif err != nil {\n\t\treturn unix.Timespec{}, err\n\t}\n\n\treturn ts, err\n}\n\nfunc (syncer *Syncer) queryNTP(server string) (*Measurement, error) {\n\tresp, err := syncer.NTPQuery(server)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsyncer.logger.Debug(\"NTP response\",\n\t\tzap.Duration(\"clock_offset\", resp.ClockOffset),\n\t\tzap.Duration(\"rtt\", resp.RTT),\n\t\tzap.Uint8(\"leap\", uint8(resp.Leap)),\n\t\tzap.Uint8(\"stratum\", resp.Stratum),\n\t\tzap.Duration(\"precision\", resp.Precision),\n\t\tzap.Duration(\"root_delay\", resp.RootDelay),\n\t\tzap.Duration(\"root_dispersion\", resp.RootDispersion),\n\t\tzap.Duration(\"root_distance\", resp.RootDistance),\n\t)\n\n\tvalidationError := resp.Validate()\n\tif validationError != nil {\n\t\treturn nil, validationError\n\t}\n\n\treturn &Measurement{\n\t\tClockOffset: resp.ClockOffset,\n\t\tLeap:        resp.Leap,\n\t\tSpike:       syncer.isSpike(resp),\n\t}, nil\n}\n\n// log2i returns 0 for v == 0 and v == 1.\nfunc log2i(v uint64) int {\n\tif v == 0 {\n\t\treturn 0\n\t}\n\n\treturn 63 - bits.LeadingZeros64(v)\n}\n\n// adjustTime adds an offset to the current time.\n//\n//nolint:gocyclo\nfunc (syncer *Syncer) adjustTime(offset time.Duration, leapSecond ntp.LeapIndicator, server string, nextPollInterval time.Duration, rtcClock *rtc.RTC) error {\n\tvar (\n\t\tbuf  bytes.Buffer\n\t\treq  unix.Timex\n\t\tjump bool\n\t)\n\n\tif offset < -AdjustTimeLimit || offset > AdjustTimeLimit {\n\t\tjump = true\n\n\t\tfmt.Fprintf(&buf, \"adjusting time (jump) by %s via %s\", offset, server)\n\n\t\treq = unix.Timex{\n\t\t\tModes: unix.ADJ_SETOFFSET | unix.ADJ_NANO | unix.ADJ_STATUS | unix.ADJ_MAXERROR | unix.ADJ_ESTERROR,\n\t\t\tTime: unix.Timeval{\n\t\t\t\tSec:  int64(offset / time.Second),\n\t\t\t\tUsec: int64(offset / time.Nanosecond % time.Second),\n\t\t\t},\n\t\t\tMaxerror: 0,\n\t\t\tEsterror: 0,\n\t\t}\n\n\t\t// kernel wants tv_usec to be positive\n\t\tif req.Time.Usec < 0 {\n\t\t\treq.Time.Sec--\n\t\t\treq.Time.Usec += int64(time.Second / time.Nanosecond)\n\t\t}\n\t} else {\n\t\tfmt.Fprintf(&buf, \"adjusting time (slew) by %s via %s\", offset, server)\n\n\t\tpollSeconds := uint64(nextPollInterval / time.Second)\n\t\tlog2iPollSeconds := log2i(pollSeconds)\n\n\t\treq = unix.Timex{\n\t\t\tModes:    unix.ADJ_OFFSET | unix.ADJ_NANO | unix.ADJ_STATUS | unix.ADJ_TIMECONST | unix.ADJ_MAXERROR | unix.ADJ_ESTERROR,\n\t\t\tOffset:   int64(offset / time.Nanosecond),\n\t\t\tStatus:   unix.STA_PLL,\n\t\t\tMaxerror: 0,\n\t\t\tEsterror: 0,\n\t\t\tConstant: int64(log2iPollSeconds) - 4,\n\t\t}\n\t}\n\n\tswitch leapSecond { //nolint:exhaustive\n\tcase ntp.LeapAddSecond:\n\t\treq.Status |= unix.STA_INS\n\tcase ntp.LeapDelSecond:\n\t\treq.Status |= unix.STA_DEL\n\t}\n\n\tlogLevel := zapcore.DebugLevel\n\n\tif jump {\n\t\tlogLevel = zapcore.InfoLevel\n\t}\n\n\tstate, err := syncer.AdjustTime(&req)\n\n\tfmt.Fprintf(&buf, \", state %s, status %s\", state, timex.Status(req.Status))\n\n\tif err != nil {\n\t\tlogLevel = zapcore.WarnLevel\n\n\t\tfmt.Fprintf(&buf, \", error was %s\", err)\n\t}\n\n\tif syncer.firstSync && logLevel == zapcore.DebugLevel {\n\t\t// promote first sync to info level\n\t\tsyncer.firstSync = false\n\n\t\tlogLevel = zapcore.InfoLevel\n\t}\n\n\tif ce := syncer.logger.Check(logLevel, buf.String()); ce != nil {\n\t\tce.Write()\n\t}\n\n\tsyncer.logger.Debug(\"adjtime state\",\n\t\tzap.Int64(\"constant\", req.Constant),\n\t\tzap.Duration(\"offset\", time.Duration(req.Offset)),\n\t\tzap.Int64(\"freq_offset\", req.Freq),\n\t\tzap.Int64(\"freq_offset_ppm\", req.Freq/65536),\n\t)\n\n\tif err == nil {\n\t\tif offset < -EpochLimit || offset > EpochLimit {\n\t\t\t// notify about epoch change\n\t\t\tselect {\n\t\t\tcase syncer.epochChangeCh <- struct{}{}:\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\n\t\tif jump {\n\t\t\tif rtcClock != nil {\n\t\t\t\tif rtcErr := rtcClock.Set(time.Now().Add(offset)); rtcErr != nil {\n\t\t\t\t\tsyncer.logger.Error(\"error syncing RTC\", zap.Error(rtcErr))\n\t\t\t\t} else {\n\t\t\t\t\tsyncer.logger.Info(\"synchronized RTC with system clock\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/pkg/ntp/ntp_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage ntp_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\tbeevikntp \"github.com/beevik/ntp\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zaptest\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/ntp\"\n\t\"github.com/siderolabs/talos/internal/pkg/timex\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\ntype NTPSuite struct {\n\tsuite.Suite\n\n\tclockLock        sync.Mutex\n\tsystemClock      time.Time\n\tclockAdjustments []time.Duration\n\n\tfailingServer     int\n\tspikyServer       int\n\tkissOfDeathServer int\n}\n\nfunc TestNTPSuite(t *testing.T) {\n\tsuite.Run(t, new(NTPSuite))\n}\n\nfunc (suite *NTPSuite) SetupTest() {\n\tsuite.systemClock = time.Now().UTC()\n\tsuite.clockAdjustments = nil\n\tsuite.failingServer = 0\n\tsuite.spikyServer = 0\n\tsuite.kissOfDeathServer = 0\n}\n\nfunc (suite *NTPSuite) getSystemClock() time.Time {\n\tsuite.clockLock.Lock()\n\tdefer suite.clockLock.Unlock()\n\n\treturn suite.systemClock\n}\n\nfunc (suite *NTPSuite) adjustSystemClock(val *unix.Timex) (status timex.State, err error) {\n\tsuite.clockLock.Lock()\n\tdefer suite.clockLock.Unlock()\n\n\tif val.Modes&unix.ADJ_OFFSET == unix.ADJ_OFFSET {\n\t\tsuite.T().Logf(\"adjustment by %s\", time.Duration(val.Offset)*time.Nanosecond)\n\t\tsuite.clockAdjustments = append(suite.clockAdjustments, time.Duration(val.Offset)*time.Nanosecond)\n\t} else {\n\t\tsuite.T().Logf(\"set clock by %s\", time.Duration(val.Time.Sec)*time.Second+time.Duration(val.Time.Usec)*time.Nanosecond)\n\t\tsuite.systemClock = suite.systemClock.Add(time.Duration(val.Time.Sec)*time.Second + time.Duration(val.Time.Usec)*time.Nanosecond)\n\t}\n\n\treturn status, err\n}\n\n//nolint:gocyclo\nfunc (suite *NTPSuite) fakeQuery(host string) (resp *beevikntp.Response, err error) {\n\tswitch host {\n\tcase \"127.0.0.1\": // error\n\t\treturn nil, errors.New(\"no response\")\n\tcase \"127.0.0.2\": // invalid response\n\t\tresp = &beevikntp.Response{}\n\n\t\tsuite.Require().Error(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.3\": // adjust +1ms\n\t\tresp = &beevikntp.Response{\n\t\t\tStratum:       1,\n\t\t\tTime:          suite.systemClock,\n\t\t\tReferenceTime: suite.systemClock,\n\t\t\tClockOffset:   time.Millisecond,\n\t\t\tRTT:           time.Millisecond / 2,\n\t\t}\n\n\t\tsuite.Require().NoError(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.4\": // adjust +2ms\n\t\tresp = &beevikntp.Response{\n\t\t\tStratum:       1,\n\t\t\tTime:          suite.systemClock,\n\t\t\tReferenceTime: suite.systemClock,\n\t\t\tClockOffset:   2 * time.Millisecond,\n\t\t\tRTT:           time.Millisecond / 2,\n\t\t}\n\n\t\tsuite.Require().NoError(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.5\": // adjust +2*epoch\n\t\tresp = &beevikntp.Response{\n\t\t\tStratum:       1,\n\t\t\tTime:          suite.systemClock,\n\t\t\tReferenceTime: suite.systemClock,\n\t\t\tClockOffset:   ntp.EpochLimit * 2,\n\t\t\tRTT:           time.Millisecond,\n\t\t}\n\n\t\tsuite.Require().NoError(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.6\": // adjust 1ms/fail alternating\n\t\tsuite.failingServer++\n\n\t\tif suite.failingServer%2 == 0 {\n\t\t\treturn nil, errors.New(\"failed this time\")\n\t\t}\n\n\t\tresp = &beevikntp.Response{\n\t\t\tStratum:       1,\n\t\t\tTime:          suite.systemClock,\n\t\t\tReferenceTime: suite.systemClock,\n\t\t\tClockOffset:   time.Millisecond,\n\t\t\tRTT:           time.Millisecond / 2,\n\t\t}\n\n\t\tsuite.Require().NoError(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.7\": // server with spikes\n\t\tsuite.spikyServer++\n\n\t\tif suite.spikyServer%5 == 4 {\n\t\t\tresp = &beevikntp.Response{\n\t\t\t\tStratum:       1,\n\t\t\t\tTime:          suite.systemClock,\n\t\t\t\tReferenceTime: suite.systemClock,\n\t\t\t\tClockOffset:   time.Second,\n\t\t\t\tRTT:           2 * time.Second,\n\t\t\t}\n\t\t} else {\n\t\t\tresp = &beevikntp.Response{\n\t\t\t\tStratum:       1,\n\t\t\t\tTime:          suite.systemClock,\n\t\t\t\tReferenceTime: suite.systemClock,\n\t\t\t\tClockOffset:   time.Millisecond,\n\t\t\t\tRTT:           time.Millisecond / 2,\n\t\t\t}\n\t\t}\n\n\t\tsuite.Require().NoError(resp.Validate())\n\n\t\treturn resp, nil\n\tcase \"127.0.0.8\": // kiss of death alternating\n\t\tsuite.kissOfDeathServer++\n\n\t\tif suite.kissOfDeathServer%2 == 1 {\n\t\t\treturn &beevikntp.Response{ // kiss of death\n\t\t\t\tStratum:       0,\n\t\t\t\tTime:          suite.systemClock,\n\t\t\t\tReferenceTime: suite.systemClock,\n\t\t\t\tClockOffset:   2 * time.Millisecond,\n\t\t\t\tRTT:           time.Millisecond / 2,\n\t\t\t}, nil\n\t\t}\n\n\t\treturn &beevikntp.Response{ // normal response\n\t\t\tStratum:       1,\n\t\t\tTime:          suite.systemClock,\n\t\t\tReferenceTime: suite.systemClock,\n\t\t\tClockOffset:   time.Millisecond,\n\t\t\tRTT:           time.Millisecond / 2,\n\t\t}, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown host %q\", host)\n\t}\n}\n\nfunc (suite *NTPSuite) TestSync() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{constants.DefaultNTPServer})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.DisableRTC = true\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tcancel()\n\n\twg.Wait()\n}\n\nfunc (suite *NTPSuite) TestSyncContinuous() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.3\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tsyncer.MinPoll = time.Second\n\tsyncer.MaxPoll = time.Second\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tsuite.clockLock.Lock()\n\t\t\tdefer suite.clockLock.Unlock()\n\n\t\t\tif len(suite.clockAdjustments) < 3 {\n\t\t\t\treturn retry.ExpectedErrorf(\"not enough syncs\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tcancel()\n\n\twg.Wait()\n}\n\n//nolint:dupl\nfunc (suite *NTPSuite) TestSyncKissOfDeath() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.8\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tsyncer.MinPoll = time.Second\n\tsyncer.MaxPoll = time.Second\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tsuite.clockLock.Lock()\n\t\t\tdefer suite.clockLock.Unlock()\n\n\t\t\tif len(suite.clockAdjustments) < 2 {\n\t\t\t\treturn retry.ExpectedErrorf(\"not enough syncs\")\n\t\t\t}\n\n\t\t\tfor _, adj := range suite.clockAdjustments {\n\t\t\t\t// kiss of death syncs should be ignored\n\t\t\t\tsuite.Assert().Equal(time.Millisecond, adj)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tcancel()\n\n\twg.Wait()\n}\n\n//nolint:dupl\nfunc (suite *NTPSuite) TestSyncWithSpikes() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.7\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tsyncer.MinPoll = time.Second\n\tsyncer.MaxPoll = time.Second\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(12*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tsuite.clockLock.Lock()\n\t\t\tdefer suite.clockLock.Unlock()\n\n\t\t\tif len(suite.clockAdjustments) < 6 {\n\t\t\t\treturn retry.ExpectedErrorf(\"not enough syncs\")\n\t\t\t}\n\n\t\t\tfor _, adj := range suite.clockAdjustments {\n\t\t\t\t// 1s spike should be filtered out\n\t\t\t\tsuite.Assert().Equal(time.Millisecond, adj)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tcancel()\n\n\twg.Wait()\n}\n\nfunc (suite *NTPSuite) TestSyncChangeTimeservers() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.1\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.DisableRTC = true\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\t\tsuite.Assert().Fail(\"unexpected sync\")\n\tcase <-time.After(3 * time.Second):\n\t}\n\n\tsyncer.SetTimeServers([]string{constants.DefaultNTPServer})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tcancel()\n\n\twg.Wait()\n}\n\nfunc (suite *NTPSuite) TestSyncIterateTimeservers() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\", \"127.0.0.4\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tsyncer.MinPoll = time.Second\n\tsyncer.MaxPoll = time.Second\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tsuite.clockLock.Lock()\n\t\t\tdefer suite.clockLock.Unlock()\n\n\t\t\tif len(suite.clockAdjustments) < 3 {\n\t\t\t\treturn retry.ExpectedErrorf(\"not enough syncs\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tcancel()\n\n\twg.Wait()\n\n\t// should always sync with 127.0.0.3, and never switch to 127.0.0.4\n\tfor i := range 3 {\n\t\tsuite.Assert().Equal(time.Millisecond, suite.clockAdjustments[i])\n\t}\n}\n\nfunc (suite *NTPSuite) TestSyncEpochChange() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.5\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tselect {\n\tcase <-syncer.EpochChange():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"epoch change timeout\")\n\t}\n\n\tcancel()\n\n\twg.Wait()\n\n\tsuite.Assert().Greater(-time.Since(suite.systemClock), ntp.EpochLimit)\n}\n\nfunc (suite *NTPSuite) TestSyncSwitchTimeservers() {\n\tsyncer := ntp.NewSyncer(zaptest.NewLogger(suite.T()).With(zap.String(\"controller\", \"ntp\")), []string{\"127.0.0.6\", \"127.0.0.4\"})\n\n\tsyncer.AdjustTime = suite.adjustSystemClock\n\tsyncer.CurrentTime = suite.getSystemClock\n\tsyncer.NTPQuery = suite.fakeQuery\n\tsyncer.DisableRTC = true\n\n\tsyncer.MinPoll = time.Second\n\tsyncer.MaxPoll = time.Second\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvar wg sync.WaitGroup\n\n\twg.Go(func() {\n\t\tsyncer.Run(ctx)\n\t})\n\n\tselect {\n\tcase <-syncer.Synced():\n\tcase <-time.After(10 * time.Second):\n\t\tsuite.Assert().Fail(\"time sync timeout\")\n\t}\n\n\tsuite.Assert().NoError(\n\t\tretry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t\tsuite.clockLock.Lock()\n\t\t\tdefer suite.clockLock.Unlock()\n\n\t\t\tif len(suite.clockAdjustments) < 3 {\n\t\t\t\treturn retry.ExpectedErrorf(\"not enough syncs\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}),\n\t)\n\n\tcancel()\n\n\twg.Wait()\n\n\t// should start sync with 127.0.0.6, then switch to 127.0.0.4\n\tsuite.Assert().Equal(time.Millisecond, suite.clockAdjustments[0])\n\n\tfor i := 1; i < 3; i++ {\n\t\tsuite.Assert().Equal(2*time.Millisecond, suite.clockAdjustments[i])\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/partition/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage partition\n\n// Type in partition table.\ntype Type = string\n\n// GPT partition types.\n//\n// TODO: should be moved into the blockdevice library.\nconst (\n\tEFISystemPartition  Type = \"C12A7328-F81F-11D2-BA4B-00A0C93EC93B\"\n\tBIOSBootPartition   Type = \"21686148-6449-6E6F-744E-656564454649\"\n\tLinuxFilesystemData Type = \"0FC63DAF-8483-4772-8E79-3D69D8477DE4\"\n\tLinkSwap            Type = \"0657FD6D-A4AB-43C4-84E5-0933C84B4F4F\"\n)\n\n// FileSystemType is used to format partitions.\ntype FileSystemType = string\n\n// Filesystem types.\nconst (\n\tFilesystemTypeNone   FileSystemType = \"none\"\n\tFilesystemTypeZeroes FileSystemType = \"zeroes\"\n\tFilesystemTypeXFS    FileSystemType = \"xfs\"\n\tFilesystemTypeVFAT   FileSystemType = \"vfat\"\n\tFileSystemTypeExt4   FileSystemType = \"ext4\"\n)\n"
  },
  {
    "path": "internal/pkg/partition/format.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package partition provides common utils for system partition format.\npackage partition\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\n// FormatOptions contains format parameters.\ntype FormatOptions struct {\n\tLabel               string\n\tSourceDirectory     string\n\tFileSystemType      FileSystemType\n\tForce               bool\n\tUnsupportedFSOption bool\n\tReproducible        bool\n}\n\n// FormatOption to control options.\ntype FormatOption func(*FormatOptions)\n\n// WithSourceDirectory sets the source directory for populating the filesystem.\nfunc WithSourceDirectory(dir string) FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.SourceDirectory = dir\n\t}\n}\n\n// WithUnsupportedFSOption sets the unsupported filesystem option.\nfunc WithUnsupportedFSOption() FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.UnsupportedFSOption = true\n\t}\n}\n\n// WithForce sets the force option.\nfunc WithForce() FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.Force = true\n\t}\n}\n\n// WithLabel sets the label for the filesystem.\nfunc WithLabel(label string) FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.Label = label\n\t}\n}\n\n// WithFileSystemType sets the filesystem type.\nfunc WithFileSystemType(fsType FileSystemType) FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.FileSystemType = fsType\n\t}\n}\n\n// WithReproducible sets the reproducible option.\nfunc WithReproducible() FormatOption {\n\treturn func(o *FormatOptions) {\n\t\to.Reproducible = true\n\t}\n}\n\n// NewFormatOptions creates a new format options.\nfunc NewFormatOptions(opts ...FormatOption) *FormatOptions {\n\to := &FormatOptions{}\n\n\tfor _, opt := range opts {\n\t\topt(o)\n\t}\n\n\treturn systemPartitionsFormatOptions(*o)\n}\n\n// Format zeroes the device and formats it using filesystem type provided.\nfunc Format(ctx context.Context, devname string, t *FormatOptions, talosVersion string, printf func(string, ...any)) error {\n\topts := []makefs.Option{\n\t\tmakefs.WithForce(t.Force),\n\t\tmakefs.WithLabel(t.Label),\n\t\tmakefs.WithPrintf(printf),\n\t}\n\n\tif t.UnsupportedFSOption {\n\t\topts = append(opts, makefs.WithUnsupportedFSOption(t.UnsupportedFSOption))\n\t}\n\n\tif t.SourceDirectory != \"\" {\n\t\topts = append(opts, makefs.WithSourceDirectory(t.SourceDirectory))\n\t}\n\n\tif t.Reproducible {\n\t\topts = append(opts, makefs.WithReproducible(true))\n\t}\n\n\tprintf(\"formatting the partition %q as %q with label %q\\n\", devname, t.FileSystemType, t.Label)\n\n\tswitch t.FileSystemType {\n\tcase FilesystemTypeNone:\n\t\treturn nil\n\tcase FilesystemTypeZeroes:\n\t\treturn zeroPartition(devname)\n\tcase FilesystemTypeVFAT:\n\t\treturn makefs.VFAT(ctx, devname, opts...)\n\tcase FilesystemTypeXFS:\n\t\topts = append(opts, makefs.WithConfigFile(quirks.New(talosVersion).XFSMkfsConfig()))\n\n\t\treturn makefs.XFS(ctx, devname, opts...)\n\tcase FileSystemTypeExt4:\n\t\treturn makefs.Ext4(ctx, devname, opts...)\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported filesystem type: %q\", t.FileSystemType)\n\t}\n}\n\n// zeroPartition fills the partition with zeroes.\nfunc zeroPartition(devname string) (err error) {\n\tpart, err := block.NewFromPath(devname, block.OpenForWrite())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer part.Close() //nolint:errcheck\n\n\treturn part.FastWipe()\n}\n\n// systemPartitionsFormatOptions returns format options for system partitions.\nfunc systemPartitionsFormatOptions(opts FormatOptions) *FormatOptions {\n\tswitch opts.Label {\n\tcase constants.EFIPartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:           constants.EFIPartitionLabel,\n\t\t\tSourceDirectory: opts.SourceDirectory,\n\t\t\tReproducible:    opts.Reproducible,\n\t\t\tFileSystemType:  FilesystemTypeVFAT,\n\t\t\tForce:           true,\n\t\t}\n\tcase constants.BIOSGrubPartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:          constants.BIOSGrubPartitionLabel,\n\t\t\tFileSystemType: FilesystemTypeZeroes,\n\t\t\tForce:          true,\n\t\t}\n\tcase constants.BootPartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:           constants.BootPartitionLabel,\n\t\t\tSourceDirectory: opts.SourceDirectory,\n\t\t\tReproducible:    opts.Reproducible,\n\t\t\tFileSystemType:  FilesystemTypeXFS,\n\t\t\tForce:           true,\n\t\t}\n\tcase constants.MetaPartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:          constants.MetaPartitionLabel,\n\t\t\tFileSystemType: FilesystemTypeZeroes,\n\t\t\tForce:          true,\n\t\t}\n\tcase constants.StatePartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:          constants.StatePartitionLabel,\n\t\t\tFileSystemType: FilesystemTypeNone,\n\t\t}\n\tcase constants.EphemeralPartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:          constants.EphemeralPartitionLabel,\n\t\t\tFileSystemType: FilesystemTypeNone,\n\t\t}\n\tcase constants.ImageCachePartitionLabel:\n\t\treturn &FormatOptions{\n\t\t\tLabel:           constants.ImageCachePartitionLabel,\n\t\t\tSourceDirectory: opts.SourceDirectory,\n\t\t\tFileSystemType:  FileSystemTypeExt4,\n\t\t\tReproducible:    opts.Reproducible,\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/partition/helpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage partition\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n)\n\n// WipeWithSignatures wipes the given block device by its signatures (if available)\n// and falls back to fast wipe otherwise.\n//\n// The function assumes that the caller locked properly the block device (or the parent\n// device in case of partitions) before calling it.\n//\n// If non-nil log function is passed, it will be used to log the wipe process.\nfunc WipeWithSignatures(bd *block.Device, deviceName string, log func(string, ...any)) error {\n\tinfo, err := blkid.Probe(bd.File(), blkid.WithSkipLocking(true))\n\tif err == nil && info != nil && len(info.SignatureRanges) > 0 { // probe successful, wipe by signatures\n\t\tif err = bd.FastWipe(xslices.Map(info.SignatureRanges, func(r blkid.SignatureRange) block.Range {\n\t\t\treturn block.Range(r)\n\t\t})...); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to wipe block device %q: %v\", deviceName, err)\n\t\t}\n\n\t\tif log != nil {\n\t\t\tlog(\"block device %q wiped by ranges: %s\",\n\t\t\t\tdeviceName,\n\t\t\t\tstrings.Join(\n\t\t\t\t\txslices.Map(info.SignatureRanges,\n\t\t\t\t\t\tfunc(r blkid.SignatureRange) string {\n\t\t\t\t\t\t\treturn fmt.Sprintf(\"%d-%d\", r.Offset, r.Offset+r.Size)\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t\t\", \",\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t}\n\n\t// [TODO]: wipe the first/last 1MiB after wiping by signatures to cover somewhat unknown edge cases\n\t// What has been observed so far is that wiping VFAT signature still makes `mkfs.xfs` believe there is\n\t// a VFAT filesystem on the partition, refusing to create XFS over it without `-f` flag.\n\t//\n\t// probe failed or no signatures found, fast wipe\n\tif err = bd.FastWipe(); err != nil {\n\t\treturn fmt.Errorf(\"failed to wipe block device %q: %v\", deviceName, err)\n\t}\n\n\tif log != nil {\n\t\tlog(\"block device %q wiped with fast method\", deviceName)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/partition/partition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package partition provides common utils for system partition format.\npackage partition\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Options contains the options for creating a partition.\ntype Options struct {\n\tFormatOptions\n\n\tPartitionLabel string\n\tPartitionType  Type\n\tSize           uint64\n\tPartitionOpts  []gpt.PartitionOption\n}\n\n// NewPartitionOptions returns a new PartitionOptions.\n//\n//nolint:gocyclo\nfunc NewPartitionOptions(uki bool, quirk quirks.Quirks, formatOpts ...FormatOption) Options {\n\tformatOptions := NewFormatOptions(formatOpts...)\n\tif formatOptions == nil {\n\t\tpanic(\"empty format options, expected at least label\")\n\t}\n\n\tswitch formatOptions.Label {\n\tcase constants.EFIPartitionLabel:\n\t\tpartitionOptions := Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  EFISystemPartition,\n\t\t\tSize:           quirk.PartitionSizes().GrubEFISize(),\n\t\t}\n\n\t\tif uki {\n\t\t\tpartitionOptions.Size = quirk.PartitionSizes().UKIEFISize()\n\t\t}\n\n\t\treturn partitionOptions\n\tcase constants.BIOSGrubPartitionLabel:\n\t\tif uki {\n\t\t\tpanic(\"BIOS partition is not supported with UKI\")\n\t\t}\n\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  BIOSBootPartition,\n\t\t\tSize:           quirk.PartitionSizes().GrubBIOSSize(),\n\t\t\tPartitionOpts:  []gpt.PartitionOption{gpt.WithLegacyBIOSBootableAttribute(true)},\n\t\t}\n\tcase constants.BootPartitionLabel:\n\t\tif uki {\n\t\t\tpanic(\"BOOT partition is not supported with UKI\")\n\t\t}\n\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  LinuxFilesystemData,\n\t\t\tSize:           quirk.PartitionSizes().GrubBootSize(),\n\t\t}\n\tcase constants.MetaPartitionLabel:\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  LinuxFilesystemData,\n\t\t\tSize:           quirk.PartitionSizes().METASize(),\n\t\t}\n\tcase constants.StatePartitionLabel:\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  LinuxFilesystemData,\n\t\t\tSize:           quirk.PartitionSizes().StateSize(),\n\t\t}\n\tcase constants.EphemeralPartitionLabel:\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  LinuxFilesystemData,\n\t\t\tSize:           0,\n\t\t}\n\tcase constants.ImageCachePartitionLabel:\n\t\treturn Options{\n\t\t\tFormatOptions:  *formatOptions,\n\t\t\tPartitionLabel: formatOptions.Label,\n\t\t\tPartitionType:  LinuxFilesystemData,\n\t\t\tSize:           0,\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown partition label %q\", formatOptions.Label))\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/partition/wipe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage partition\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-blockdevice/v2/block\"\n\t\"github.com/siderolabs/go-blockdevice/v2/partitioning/gpt\"\n\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumeWipeTarget is a target for wiping a volume.\ntype VolumeWipeTarget struct {\n\tlabel string\n\n\tparentDevName, devName string\n\n\tpartitionIndex int // partitionIndex is 1-based, but decrement before using\n}\n\n// VolumeWipeTargetFromVolumeStatus creates a new VolumeWipeTarget from a VolumeStatus.\nfunc VolumeWipeTargetFromVolumeStatus(vs *blockres.VolumeStatus) *VolumeWipeTarget {\n\tparentDevName := vs.TypedSpec().ParentLocation\n\n\tif parentDevName == \"\" {\n\t\tparentDevName = vs.TypedSpec().Location\n\t}\n\n\treturn &VolumeWipeTarget{\n\t\tlabel:          vs.Metadata().ID(),\n\t\tparentDevName:  parentDevName,\n\t\tdevName:        vs.TypedSpec().Location,\n\t\tpartitionIndex: vs.TypedSpec().PartitionIndex,\n\t}\n}\n\n// VolumeWipeTargetFromDiscoveredVolume creates a new VolumeWipeTarget from a DiscoveredVolume.\nfunc VolumeWipeTargetFromDiscoveredVolume(dv *blockres.DiscoveredVolume) *VolumeWipeTarget {\n\tparentDevName := dv.TypedSpec().ParentDevPath\n\n\tif parentDevName == \"\" {\n\t\tparentDevName = dv.TypedSpec().DevPath\n\t}\n\n\treturn &VolumeWipeTarget{\n\t\tlabel:          dv.TypedSpec().PartitionLabel,\n\t\tparentDevName:  parentDevName,\n\t\tdevName:        dv.TypedSpec().DevPath,\n\t\tpartitionIndex: int(dv.TypedSpec().PartitionIndex),\n\t}\n}\n\n// GetLabel implements runtime.PartitionTarget.\nfunc (v *VolumeWipeTarget) GetLabel() string {\n\treturn v.label\n}\n\n// String implements runtime.PartitionTarget.\nfunc (v *VolumeWipeTarget) String() string {\n\treturn fmt.Sprintf(\"%s:%s\", v.label, v.devName)\n}\n\n// Wipe implements runtime.PartitionTarget.\n// Asides from wiping the device, Wipe() also drops the partition.\nfunc (v *VolumeWipeTarget) Wipe(ctx context.Context, log func(string, ...any)) error {\n\tparentBd, err := block.NewFromPath(v.parentDevName, block.OpenForWrite())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening block device %q: %w\", v.parentDevName, err)\n\t}\n\n\tdefer parentBd.Close() //nolint:errcheck\n\n\tif err = parentBd.RetryLockWithTimeout(ctx, true, time.Minute); err != nil {\n\t\treturn fmt.Errorf(\"error locking block device %q: %w\", v.parentDevName, err)\n\t}\n\n\tdefer parentBd.Unlock() //nolint:errcheck\n\n\tif err := v.wipeWithParentLocked(log); err != nil {\n\t\treturn fmt.Errorf(\"error wiping device %q: %w\", v.devName, err)\n\t}\n\n\tif parentBd == nil || v.partitionIndex == 0 {\n\t\treturn fmt.Errorf(\"missing parent block device or partition index\")\n\t}\n\n\tif err := v.dropWithParentLocked(parentBd, log); err != nil {\n\t\treturn fmt.Errorf(\"error dropping partition: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (v *VolumeWipeTarget) wipeWithParentLocked(log func(string, ...any)) error {\n\tbd, err := block.NewFromPath(v.devName, block.OpenForWrite())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening block device %q: %w\", v.devName, err)\n\t}\n\n\tdefer bd.Close() //nolint:errcheck\n\n\tlog(\"wiping volume %q (%s)\", v.GetLabel(), v.devName)\n\n\treturn WipeWithSignatures(bd, v.devName, log)\n}\n\nfunc (v *VolumeWipeTarget) dropWithParentLocked(parentBd *block.Device, log func(string, ...any)) error {\n\tlog(\"dropping partition %d from device %q\", v.partitionIndex, v.parentDevName)\n\n\tgptdev, err := gpt.DeviceFromBlockDevice(parentBd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get GPT device: %w\", err)\n\t}\n\n\tpt, err := gpt.Read(gptdev)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read GPT table: %w\", err)\n\t}\n\n\tif err = pt.DeletePartition(v.partitionIndex - 1); err != nil {\n\t\treturn fmt.Errorf(\"failed to delete partition: %w\", err)\n\t}\n\n\tif err = pt.Write(); err != nil {\n\t\treturn fmt.Errorf(\"failed to write GPT table: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/pcap/pcap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pcap implements writing packet data to pcap files.\npackage pcap\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/gopacket/gopacket\"\n)\n\n// Writer wraps an underlying io.Writer to write packet data in PCAP\n// format.  See http://wiki.wireshark.org/Development/LibpcapFileFormat\n// for information on the file format.\n//\n// For those that care, we currently write v2.4 files with nanosecond\n// or microsecond timestamp resolution and little-endian encoding.\ntype Writer struct {\n\tw   io.Writer\n\tbuf [16]byte\n}\n\nconst (\n\tmagicNanoseconds = 0xA1B23C4D\n\tversionMajor     = 2\n\tversionMinor     = 4\n)\n\n// LinkType is the link type for the pcap file.\ntype LinkType uint32\n\n// LinkType values.\nconst (\n\tLinkTypeEthernet LinkType = 1\n\tLinkTypeRaw      LinkType = 101\n)\n\n// NewWriter returns a new writer object.\n//\n// If this is a new empty writer (as opposed to\n// an append), you must call WriteFileHeader before WritePacket.  Packet\n// timestamps are written with nanosecond precision.\nfunc NewWriter(w io.Writer) *Writer {\n\treturn &Writer{w: w}\n}\n\n// WriteFileHeader writes a file header out to the writer.\n// This must be called exactly once per output.\nfunc (w *Writer) WriteFileHeader(snaplen uint32, linktype LinkType) error {\n\tvar buf [24]byte\n\n\tbinary.LittleEndian.PutUint32(buf[0:4], magicNanoseconds)\n\tbinary.LittleEndian.PutUint16(buf[4:6], versionMajor)\n\tbinary.LittleEndian.PutUint16(buf[6:8], versionMinor)\n\n\t// bytes 8:12 stay 0 (timezone = UTC)\n\t// bytes 12:16 stay 0 (sigfigs is always set to zero, according to\n\t//   http://wiki.wireshark.org/Development/LibpcapFileFormat\n\tbinary.LittleEndian.PutUint32(buf[16:20], snaplen)\n\tbinary.LittleEndian.PutUint32(buf[20:24], uint32(linktype))\n\n\t_, err := w.w.Write(buf[:])\n\n\treturn err\n}\n\nfunc (w *Writer) writePacketHeader(ci gopacket.CaptureInfo) error {\n\tt := ci.Timestamp\n\tif t.IsZero() {\n\t\tt = time.Now()\n\t}\n\n\tsecs := t.Unix()\n\tbinary.LittleEndian.PutUint32(w.buf[0:4], uint32(secs))\n\n\tusecs := t.Nanosecond()\n\tbinary.LittleEndian.PutUint32(w.buf[4:8], uint32(usecs))\n\n\tbinary.LittleEndian.PutUint32(w.buf[8:12], uint32(ci.CaptureLength))\n\tbinary.LittleEndian.PutUint32(w.buf[12:16], uint32(ci.Length))\n\n\t_, err := w.w.Write(w.buf[:])\n\n\treturn err\n}\n\n// WritePacket writes the given packet data out to the file.\nfunc (w *Writer) WritePacket(ci gopacket.CaptureInfo, data []byte) error {\n\tif ci.CaptureLength != len(data) {\n\t\treturn fmt.Errorf(\"capture length %d does not match data length %d\", ci.CaptureLength, len(data))\n\t}\n\n\tif ci.CaptureLength > ci.Length {\n\t\treturn fmt.Errorf(\"invalid capture info %+v:  capture length > length\", ci)\n\t}\n\n\tif err := w.writePacketHeader(ci); err != nil {\n\t\treturn fmt.Errorf(\"error writing packet header: %v\", err)\n\t}\n\n\t_, err := w.w.Write(data)\n\n\treturn err\n}\n"
  },
  {
    "path": "internal/pkg/pci/pci.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pci provides methods to access PCI-related data.\npackage pci\n\nimport (\n\t\"github.com/siderolabs/go-pcidb/pkg/pcidb\"\n)\n\n// Device describes PCI device.\ntype Device struct {\n\tVendorID  uint16\n\tProductID uint16\n\n\tVendor  string\n\tProduct string\n}\n\n// LookupDB looks up device info in the PCI database.\nfunc (d *Device) LookupDB() {\n\td.Vendor, _ = pcidb.LookupVendor(d.VendorID)\n\td.Product, _ = pcidb.LookupProduct(d.VendorID, d.ProductID)\n}\n"
  },
  {
    "path": "internal/pkg/pci/sysfs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pci\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"strconv\"\n)\n\nconst sysfsPath = \"/sys/bus/pci/devices/%s/%s\"\n\nfunc readID(busPath, name string) (uint16, error) {\n\tcontents, err := os.ReadFile(fmt.Sprintf(sysfsPath, busPath, name))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tv, err := strconv.ParseUint(string(bytes.TrimSpace(contents)), 0, 16)\n\n\treturn uint16(v), err\n}\n\n// SysfsDeviceInfo looks up vendor and product ID from sysfs.\nfunc SysfsDeviceInfo(busPath string) (*Device, error) {\n\tvar (\n\t\td   Device\n\t\terr error\n\t)\n\n\td.ProductID, err = readID(busPath, \"device\")\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\td.VendorID, err = readID(busPath, \"vendor\")\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\treturn &d, err\n}\n"
  },
  {
    "path": "internal/pkg/rng/pool.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage rng\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// GetPoolSize returns kernel random pool size.\nfunc GetPoolSize() (int, error) {\n\tcontents, err := os.ReadFile(\"/proc/sys/kernel/random/poolsize\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn strconv.Atoi(string(bytes.TrimSpace(contents)))\n}\n\n// WriteEntropy writes entropy data to the pool.\nfunc WriteEntropy(data []byte) error {\n\tfd, err := os.OpenFile(\"/dev/urandom\", os.O_WRONLY|unix.O_CLOEXEC|unix.O_NOCTTY, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer fd.Close() //nolint:errcheck\n\n\t_, err = fd.Write(data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing entropy: %w\", err)\n\t}\n\n\treturn fd.Close()\n}\n"
  },
  {
    "path": "internal/pkg/rng/rng.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package rng handles interaction with kernel random number generator.\npackage rng\n"
  },
  {
    "path": "internal/pkg/rng/tpm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage rng\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/tpm\"\n)\n\n// TPMSeed seeds the random entropy pool from the TPM.\n//\n//nolint:gocyclo\nfunc TPMSeed() error {\n\tt, err := tpm.Open()\n\tif err != nil {\n\t\t// if the TPM is not available we can skip seeding random pool\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\tlog.Printf(\"TPM device is not available\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error opening TPM device: %w\", err)\n\t}\n\n\tdefer t.Close() //nolint:errcheck\n\n\t// now we need to check if the TPM is a 2.0 device\n\t// we can do this by checking the manufacturer,\n\t// if it fails, we can skip trying to seed the pool\n\tcaps, err := tpm2.GetCapability{\n\t\tCapability:    tpm2.TPMCapTPMProperties,\n\t\tProperty:      uint32(tpm2.TPMPTManufacturer),\n\t\tPropertyCount: 1,\n\t}.Execute(t)\n\tif err != nil {\n\t\tlog.Printf(\"TPM device is not a TPM 2.0, skipping seeding entropy pool from TPM\")\n\n\t\treturn nil\n\t}\n\n\tprops, err := caps.CapabilityData.Data.TPMProperties()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting properties: %w\", err)\n\t}\n\n\tlog.Printf(\"TPM manufacturer ID: %08x\", props.TPMProperty[0].Value)\n\n\tpoolSize, err := GetPoolSize()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting pool size: %w\", err)\n\t}\n\n\tremaining := poolSize\n\tstart := time.Now()\n\n\tfor remaining > 0 {\n\t\tchunk := min(remaining, 32) // default to small chunk (size of AES key)\n\n\t\tcmd := tpm2.GetRandom{\n\t\t\tBytesRequested: uint16(chunk),\n\t\t}\n\n\t\tresp, err := cmd.Execute(t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error getting random data from the TPM: %w\", err)\n\t\t}\n\n\t\tif len(resp.RandomBytes.Buffer) == 0 {\n\t\t\treturn fmt.Errorf(\"received zero random bytes from the TPM: %w\", err)\n\t\t}\n\n\t\tif err = WriteEntropy(resp.RandomBytes.Buffer); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing random pool entropy: %w\", err)\n\t\t}\n\n\t\tremaining -= len(resp.RandomBytes.Buffer)\n\t}\n\n\tlog.Printf(\"seeded random pool with %d bytes from the TPM in %s\", poolSize, time.Since(start))\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/rootfs/rootfs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage rootfs_test\n\nimport (\n\t\"debug/buildinfo\"\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestPkgsGoVersionMatchesTalos(t *testing.T) {\n\tt.Parallel()\n\n\tif hostname, _ := os.Hostname(); hostname != \"buildkitsandbox\" { //nolint:errcheck\n\t\tt.Skipf(\"skipping test; only run on buildkitsandbox, got %s\", hostname)\n\t}\n\n\tconst sampleBinaryPath = \"/usr/bin/containerd\"\n\n\tinfo, err := buildinfo.ReadFile(sampleBinaryPath)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to read build info from %s: %v\", sampleBinaryPath, err)\n\t}\n\n\tbinaryGoVersion := info.GoVersion\n\truntimeGoVersion := runtime.Version()\n\n\tassert.Equal(t, runtimeGoVersion, binaryGoVersion)\n\tassert.Equal(t, runtimeGoVersion, constants.GoVersion)\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/database/database.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package database generates SecureBoot auto-enrollment database.\npackage database\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"embed\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/foxboron/go-uefi/efi/signature\"\n\t\"github.com/foxboron/go-uefi/efi/util\"\n\t\"github.com/foxboron/go-uefi/efivar\"\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Entry is a UEFI database entry.\ntype Entry struct {\n\tName     string\n\tContents []byte\n}\n\nconst (\n\tmicrosoftSignatureOwnerGUID = \"77fa9abd-0359-4d32-bd60-28f4e78f784b\"\n)\n\n// Well-known UEFI DB certificates (DER data).\n//\n//go:embed certs/db/*.der\nvar wellKnownDB embed.FS\n\n// Well-known UEFI KEK certificates (PEM data).\n//\n//go:embed certs/kek/*.der\nvar wellKnownKEK embed.FS\n\nfunc loadWellKnownCertificates(fs embed.FS, path string) ([]*x509.Certificate, error) {\n\tcerts := []*x509.Certificate{}\n\n\tfiles, err := fs.ReadDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, file := range files {\n\t\tdata, err := fs.ReadFile(filepath.Join(path, file.Name()))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcert, err := x509.ParseCertificate(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcerts = append(certs, cert)\n\t}\n\n\treturn certs, nil\n}\n\nvar wellKnownDBCertificates = sync.OnceValue(func() []*x509.Certificate {\n\tcerts, err := loadWellKnownCertificates(wellKnownDB, \"certs/db\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn certs\n})\n\nvar wellKnownKEKCertificates = sync.OnceValue(func() []*x509.Certificate {\n\tcerts, err := loadWellKnownCertificates(wellKnownKEK, \"certs/kek\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn certs\n})\n\n// Options for Generate.\ntype Options struct {\n\tIncludeWellKnownCertificates bool\n}\n\n// Option is a functional option for Generate.\ntype Option func(*Options)\n\n// IncludeWellKnownCertificates is an option to include well-known certificates.\nfunc IncludeWellKnownCertificates(v bool) Option {\n\treturn func(o *Options) {\n\t\to.IncludeWellKnownCertificates = v\n\t}\n}\n\n// Generate generates a UEFI database to enroll the signing certificate.\n//\n// ref: https://blog.hansenpartnership.com/the-meaning-of-all-the-uefi-keys/\n//\n//nolint:gocyclo\nfunc Generate(enrolledCertificate []byte, signer pesign.CertificateSigner, opts ...Option) ([]Entry, error) {\n\tvar options Options\n\n\tfor _, opt := range opts {\n\t\topt(&options)\n\t}\n\n\t// derive UUID from enrolled certificate\n\tuuid := uuid.NewHash(sha256.New(), uuid.NameSpaceX500, enrolledCertificate, 4)\n\n\tefiGUID := util.StringToGUID(uuid.String())\n\n\t// Create PK ESL\n\tpk := signature.NewSignatureDatabase()\n\tif err := pk.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, signedPK, err := signature.SignEFIVariable(efivar.PK, pk, signer.Signer(), signer.Certificate())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create KEK ESL\n\tkek := signature.NewSignatureDatabase()\n\tif err := kek.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.IncludeWellKnownCertificates {\n\t\towner := util.StringToGUID(microsoftSignatureOwnerGUID)\n\t\tfor _, cert := range wellKnownKEKCertificates() {\n\t\t\tif err := kek.Append(signature.CERT_X509_GUID, *owner, cert.Raw); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\t_, signedKEK, err := signature.SignEFIVariable(efivar.KEK, kek, signer.Signer(), signer.Certificate())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create db ESL\n\tdb := signature.NewSignatureDatabase()\n\tif err := db.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.IncludeWellKnownCertificates {\n\t\towner := util.StringToGUID(microsoftSignatureOwnerGUID)\n\t\tfor _, cert := range wellKnownDBCertificates() {\n\t\t\tif err := db.Append(signature.CERT_X509_GUID, *owner, cert.Raw); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\n\t_, signedDB, err := signature.SignEFIVariable(efivar.Db, db, signer.Signer(), signer.Certificate())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn []Entry{\n\t\t{Name: constants.SignatureKeyAsset, Contents: signedDB.Bytes()},\n\t\t{Name: constants.KeyExchangeKeyAsset, Contents: signedKEK.Bytes()},\n\t\t{Name: constants.PlatformKeyAsset, Contents: signedPK.Bytes()},\n\t}, nil\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/pesign/pesign.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pesign implements the PE (portable executable) signing.\npackage pesign\n\nimport (\n\t\"cmp\"\n\t\"crypto\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/foxboron/go-uefi/authenticode\"\n)\n\n// Signer sigs PE (portable executable) files.\ntype Signer struct {\n\tprovider CertificateSigner\n}\n\n// CertificateSigner is a provider of the certificate and the signer.\ntype CertificateSigner interface {\n\tSigner() crypto.Signer\n\tCertificate() *x509.Certificate\n}\n\n// NewSigner creates a new Signer.\nfunc NewSigner(provider CertificateSigner) (*Signer, error) {\n\treturn &Signer{\n\t\tprovider: provider,\n\t}, nil\n}\n\n// Sign signs the input file and writes the output to the output file.\nfunc (s *Signer) Sign(input, output string) error {\n\tin, err := os.Open(input)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer in.Close() //nolint:errcheck\n\n\tpecoff, err := authenticode.Parse(in)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing binary: %w\", err)\n\t}\n\n\t_, err = pecoff.Sign(s.provider.Signer(), s.provider.Certificate())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error signing binary: %w\", err)\n\t}\n\n\tf, err := os.OpenFile(output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error opening output file: %w\", err)\n\t}\n\n\tcloser := f.Close\n\n\tdefer closer() //nolint:errcheck\n\n\t_, err = io.Copy(f, pecoff.Open())\n\n\treturn cmp.Or(err, closer())\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/pesign/pesign_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pesign_test\n\nimport (\n\t\"crypto\"\n\tstdx509 \"crypto/x509\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n)\n\ntype certificateProvider struct {\n\t*x509.CertificateAuthority\n}\n\nfunc (c *certificateProvider) Signer() crypto.Signer {\n\treturn c.CertificateAuthority.Key.(crypto.Signer)\n}\n\nfunc (c *certificateProvider) Certificate() *stdx509.Certificate {\n\treturn c.CertificateAuthority.Crt\n}\n\nfunc TestSign(t *testing.T) {\n\tcurrentTime := time.Now()\n\n\topts := []x509.Option{\n\t\tx509.RSA(true),\n\t\tx509.Bits(2048),\n\t\tx509.CommonName(\"test-sign\"),\n\t\tx509.NotAfter(currentTime.Add(secrets.CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.Organization(\"test-sign\"),\n\t}\n\n\ttmpDir := t.TempDir()\n\n\tsigningKey, err := x509.NewSelfSignedCertificateAuthority(opts...)\n\trequire.NoError(t, err)\n\n\tsigner, err := pesign.NewSigner(&certificateProvider{signingKey})\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, signer.Sign(\"testdata/systemd-bootx64.efi\", filepath.Join(tmpDir, \"boot.efi\")))\n\n\tunsigned, err := os.Stat(\"testdata/systemd-bootx64.efi\")\n\trequire.NoError(t, err)\n\n\tsigned, err := os.Stat(filepath.Join(tmpDir, \"boot.efi\"))\n\trequire.NoError(t, err)\n\n\trequire.Greater(t, signed.Size(), unsigned.Size())\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/secureboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package secureboot contains base definitions for the Secure Boot process.\npackage secureboot\n\n// Phase is the phase value extended to the PCR.\ntype Phase string\n\nconst (\n\t// EnterInitrd is the phase value extended to the PCR during the initrd.\n\tEnterInitrd Phase = \"enter-initrd\"\n\t// LeaveInitrd is the phase value extended to the PCR just before switching to machined.\n\tLeaveInitrd Phase = \"leave-initrd\"\n\t// EnterMachined is the phase value extended to the PCR before starting machined.\n\t// There should be only a signed signature for the enter-machined phase.\n\tEnterMachined Phase = \"enter-machined\"\n\t// StartTheWorld is the phase value extended to the PCR before starting all services.\n\tStartTheWorld Phase = \"start-the-world\"\n)\n\n// PhaseInfo describes which phase extensions are signed/measured.\ntype PhaseInfo struct {\n\tPhase              Phase\n\tCalculateSignature bool\n}\n\n// OrderedPhases returns the phases that are measured, in order.\n//\n// Derived from https://github.com/systemd/systemd/blob/v253/src/boot/measure.c#L295-L308\n// ref: https://www.freedesktop.org/software/systemd/man/systemd-pcrphase.service.html#Description\n//\n// In the case of Talos disk decryption, happens in machined, so we need to only sign EnterMachined\n// so that machined can only decrypt the disk if the system booted with the correct kernel/initrd/cmdline\n// OrderedPhases returns the phases that are measured.\nfunc OrderedPhases() []PhaseInfo {\n\t// DO NOT REARRANGE\n\treturn []PhaseInfo{\n\t\t{\n\t\t\tPhase:              EnterInitrd,\n\t\t\tCalculateSignature: false,\n\t\t},\n\t\t{\n\t\t\tPhase:              LeaveInitrd,\n\t\t\tCalculateSignature: false,\n\t\t},\n\t\t{\n\t\t\tPhase:              EnterMachined,\n\t\t\tCalculateSignature: true,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/keys.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n)\n\n// ParsePCRSigningPubKey parses a PEM encoded RSA public key.\nfunc ParsePCRSigningPubKey(file string) (*rsa.PublicKey, error) {\n\tpcrSigningPubKey, err := os.ReadFile(file)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read pcr signing public key: %v\", err)\n\t}\n\n\tblock, _ := pem.Decode(pcrSigningPubKey)\n\tif block == nil {\n\t\treturn nil, errors.New(\"failed to decode pcr signing public key\")\n\t}\n\n\t// parse rsa public key\n\ttpm2PubKeyAny, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttpm2PubKey, ok := tpm2PubKeyAny.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, errors.New(\"failed to cast pcr signing public key to rsa\")\n\t}\n\n\treturn tpm2PubKey, nil\n}\n\n// RSAPubKeyTemplate returns a TPM2.0 public key template for RSA keys.\nfunc RSAPubKeyTemplate(bitlen, exponent int, modulus []byte) tpm2.TPMTPublic {\n\treturn tpm2.TPMTPublic{\n\t\tType:    tpm2.TPMAlgRSA,\n\t\tNameAlg: tpm2.TPMAlgSHA256,\n\t\tObjectAttributes: tpm2.TPMAObject{\n\t\t\tDecrypt:      true,\n\t\t\tSignEncrypt:  true,\n\t\t\tUserWithAuth: true,\n\t\t},\n\t\tParameters: tpm2.NewTPMUPublicParms(tpm2.TPMAlgRSA, &tpm2.TPMSRSAParms{\n\t\t\tSymmetric: tpm2.TPMTSymDefObject{\n\t\t\t\tAlgorithm: tpm2.TPMAlgNull,\n\t\t\t\tMode:      tpm2.NewTPMUSymMode(tpm2.TPMAlgRSA, tpm2.TPMAlgNull),\n\t\t\t},\n\t\t\tScheme: tpm2.TPMTRSAScheme{\n\t\t\t\tScheme: tpm2.TPMAlgNull,\n\t\t\t\tDetails: tpm2.NewTPMUAsymScheme(tpm2.TPMAlgRSA, &tpm2.TPMSSigSchemeRSASSA{\n\t\t\t\t\tHashAlg: tpm2.TPMAlgNull,\n\t\t\t\t}),\n\t\t\t},\n\t\t\tKeyBits:  tpm2.TPMKeyBits(bitlen),\n\t\t\tExponent: uint32(exponent),\n\t\t}),\n\t\tUnique: tpm2.NewTPMUPublicID(tpm2.TPMAlgRSA, &tpm2.TPM2BPublicKeyRSA{\n\t\t\tBuffer: modulus,\n\t\t}),\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/pcr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"log\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\t\"github.com/google/go-tpm/tpm2/transport\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/tpm\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// CreateSelector converts PCR  numbers into a bitmask.\nfunc CreateSelector(pcrs []int) ([]byte, error) {\n\tconst sizeOfPCRSelect = 3\n\n\tmask := make([]byte, sizeOfPCRSelect)\n\n\tfor _, n := range pcrs {\n\t\tif n >= 8*sizeOfPCRSelect {\n\t\t\treturn nil, fmt.Errorf(\"PCR index %d is out of range (exceeds maximum value %d)\", n, 8*sizeOfPCRSelect-1)\n\t\t}\n\n\t\tmask[n>>3] |= 1 << (n & 0x7)\n\t}\n\n\treturn mask, nil\n}\n\n// ReadPCR reads the value of a single PCR.\nfunc ReadPCR(t transport.TPM, pcr int) ([]byte, error) {\n\tpcrSelector, err := CreateSelector([]int{pcr})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create PCR selection: %w\", err)\n\t}\n\n\tpcrRead := tpm2.PCRRead{\n\t\tPCRSelectionIn: tpm2.TPMLPCRSelection{\n\t\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t\t{\n\t\t\t\t\tHash:      tpm2.TPMAlgSHA256,\n\t\t\t\t\tPCRSelect: pcrSelector,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tpcrValue, err := pcrRead.Execute(t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read PCR: %w\", err)\n\t}\n\n\treturn pcrValue.PCRValues.Digests[0].Buffer, nil\n}\n\n// PCRExtend hashes the input and extends the PCR with the hash.\nfunc PCRExtend(pcr int, data []byte) error {\n\tt, err := tpm.Open()\n\tif err != nil {\n\t\t// if the TPM is not available we can skip the PCR extension\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\tlog.Printf(\"TPM device is not available, skipping PCR extension\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tdefer t.Close() //nolint:errcheck\n\n\t// now we need to check if the TPM is a 2.0 device\n\t// we can do this by checking the manufacturer,\n\t// if it fails, we can skip the PCR extension\n\t_, err = tpm2.GetCapability{\n\t\tCapability:    tpm2.TPMCapTPMProperties,\n\t\tProperty:      uint32(tpm2.TPMPTManufacturer),\n\t\tPropertyCount: 1,\n\t}.Execute(t)\n\tif err != nil {\n\t\tlog.Printf(\"TPM device is not a TPM 2.0, skipping PCR extension\")\n\n\t\treturn nil\n\t}\n\n\t// since we are using SHA256, we can assume that the PCR bank is SHA256\n\tdigest := sha256.Sum256(data)\n\n\tpcrHandle := tpm2.PCRExtend{\n\t\tPCRHandle: tpm2.AuthHandle{\n\t\t\tHandle: tpm2.TPMHandle(pcr),\n\t\t\tAuth:   tpm2.PasswordAuth(nil),\n\t\t},\n\t\tDigests: tpm2.TPMLDigestValues{\n\t\t\tDigests: []tpm2.TPMTHA{\n\t\t\t\t{\n\t\t\t\t\tHashAlg: tpm2.TPMAlgSHA256,\n\t\t\t\t\tDigest:  digest[:],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif _, err = pcrHandle.Execute(t); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// PolicyPCRDigest executes policyPCR and returns the digest.\nfunc PolicyPCRDigest(t transport.TPM, policyHandle tpm2.TPMHandle, pcrSelection tpm2.TPMLPCRSelection) (*tpm2.TPM2BDigest, error) {\n\tpolicyPCR := tpm2.PolicyPCR{\n\t\tPolicySession: policyHandle,\n\t\tPcrs:          pcrSelection,\n\t}\n\n\tif _, err := policyPCR.Execute(t); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to execute policyPCR: %w\", err)\n\t}\n\n\tpolicyGetDigest := tpm2.PolicyGetDigest{\n\t\tPolicySession: policyHandle,\n\t}\n\n\tpolicyGetDigestResponse, err := policyGetDigest.Execute(t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get policy digest: %w\", err)\n\t}\n\n\treturn &policyGetDigestResponse.PolicyDigest, nil\n}\n\n//nolint:gocyclo\nfunc validatePCRBanks(t transport.TPM, tpmPCRs []int) error {\n\tpcrValue, err := ReadPCR(t, constants.UKIPCR)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read PCR: %w\", err)\n\t}\n\n\tif err = validatePCRNotZeroAndNotFilled(pcrValue, constants.UKIPCR); err != nil {\n\t\treturn err\n\t}\n\n\t// here we need to read individual PCRs and not the overall PCR state to make sure each is not empty\n\tfor _, pcr := range tpmPCRs {\n\t\tpcrValue, err = ReadPCR(t, pcr)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read PCR %d: %w\", pcr, err)\n\t\t}\n\n\t\tif err = validatePCRNotZeroAndNotFilled(pcrValue, pcr); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tcaps := tpm2.GetCapability{\n\t\tCapability:    tpm2.TPMCapPCRs,\n\t\tProperty:      0,\n\t\tPropertyCount: 1,\n\t}\n\n\tcapsResp, err := caps.Execute(t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get PCR capabilities: %w\", err)\n\t}\n\n\tassignedPCRs, err := capsResp.CapabilityData.Data.AssignedPCR()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse assigned PCRs: %w\", err)\n\t}\n\n\tfor _, s := range assignedPCRs.PCRSelections {\n\t\tif s.Hash != tpm2.TPMAlgSHA256 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// check if 24 banks are available\n\t\tif len(s.PCRSelect) != 24/8 {\n\t\t\treturn fmt.Errorf(\"unexpected number of PCR banks: %d\", len(s.PCRSelect))\n\t\t}\n\n\t\t// check if all banks are available\n\t\tif s.PCRSelect[0] != 0xff || s.PCRSelect[1] != 0xff || s.PCRSelect[2] != 0xff {\n\t\t\treturn fmt.Errorf(\"unexpected PCR banks: %v\", s.PCRSelect)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc validatePCRNotZeroAndNotFilled(pcrValue []byte, pcr int) error {\n\tif bytes.Equal(pcrValue, bytes.Repeat([]byte{0x00}, sha256.Size)) {\n\t\treturn fmt.Errorf(\"PCR bank %d is populated with all zeroes\", pcr)\n\t}\n\n\tif bytes.Equal(pcrValue, bytes.Repeat([]byte{0xFF}, sha256.Size)) {\n\t\treturn fmt.Errorf(\"PCR bank %d is populated with all 0xFF\", pcr)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/pcr_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\ttpm2internal \"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n)\n\nfunc TestGetSelection(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tpcrs     []int\n\t\texpected []byte\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\texpected: []byte{0, 0, 0},\n\t\t},\n\t\t{\n\t\t\tname:     \"1, 3, 5\",\n\t\t\tpcrs:     []int{1, 3, 5},\n\t\t\texpected: []byte{42, 0, 0},\n\t\t},\n\t\t{\n\t\t\tname:     \"21, 22, 23\",\n\t\t\tpcrs:     []int{21, 22, 23},\n\t\t\texpected: []byte{0, 0, 0xe0},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual, err := tpm2internal.CreateSelector(tt.pcrs)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, actual)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/policy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"crypto/sha256\"\n\t\"fmt\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\t\"github.com/google/go-tpm/tpm2/transport\"\n)\n\n// CalculatePolicy calculates the policy hash for a given PCR value and PCR selection.\nfunc CalculatePolicy(pcrValue []byte, pcrSelection tpm2.TPMLPCRSelection) ([]byte, error) {\n\tcalculator, err := tpm2.NewPolicyCalculator(tpm2.TPMAlgSHA256)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpcrHash := sha256.Sum256(pcrValue)\n\n\tpolicy := tpm2.PolicyPCR{\n\t\tPcrDigest: tpm2.TPM2BDigest{\n\t\t\tBuffer: pcrHash[:],\n\t\t},\n\t\tPcrs: pcrSelection,\n\t}\n\n\tif err := policy.Update(calculator); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn calculator.Hash().Digest, nil\n}\n\n// calculatePolicyAuthorize creates and updates a PolicyAuthorize for the given public key.\nfunc calculatePolicyAuthorize(calculator *tpm2.PolicyCalculator, pubKey string) error {\n\tpubKeyData, err := ParsePCRSigningPubKey(pubKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpublicKeyTemplate := RSAPubKeyTemplate(pubKeyData.N.BitLen(), pubKeyData.E, pubKeyData.N.Bytes())\n\n\tname, err := tpm2.ObjectName(&publicKeyTemplate)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to calculate name: %v\", err)\n\t}\n\n\tpolicyAuthorize := tpm2.PolicyAuthorize{\n\t\tKeySign: *name,\n\t}\n\n\treturn policyAuthorize.Update(calculator)\n}\n\n// SealingPolicyDigestInfo holds the information needed to calculate a sealing policy digest.\ntype SealingPolicyDigestInfo struct {\n\tPublicKey   string\n\tPCRs        []int\n\tReadPCRFunc func(t transport.TPM, pcr int) ([]byte, error)\n}\n\n// CalculateSealingPolicyDigest calculates the sealing policy digest for a given public key and PCRs.\nfunc CalculateSealingPolicyDigest(t transport.TPM, spInfo SealingPolicyDigestInfo) ([]byte, error) {\n\tcalculator, err := tpm2.NewPolicyCalculator(tpm2.TPMAlgSHA256)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create policy calculator: %v\", err)\n\t}\n\n\tif err := calculatePolicyAuthorize(calculator, spInfo.PublicKey); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to calculate policy authorize: %v\", err)\n\t}\n\n\tif len(spInfo.PCRs) == 0 {\n\t\treturn calculator.Hash().Digest, nil\n\t}\n\n\tpcrSelector, err := CreateSelector(spInfo.PCRs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create PCR selection for PCRs %v: %v\", spInfo.PCRs, err)\n\t}\n\n\tpcrSelection := tpm2.TPMLPCRSelection{\n\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t{\n\t\t\t\tHash:      tpm2.TPMAlgSHA256,\n\t\t\t\tPCRSelect: pcrSelector,\n\t\t\t},\n\t\t},\n\t}\n\n\thash := sha256.New()\n\n\tfor _, p := range spInfo.PCRs {\n\t\tpcrValue, err := spInfo.ReadPCRFunc(t, p)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read PCR %d: %v\", p, err)\n\t\t}\n\n\t\tif _, err := hash.Write(pcrValue); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to hash PCR value for PCR %d: %v\", p, err)\n\t\t}\n\t}\n\n\tpolicy := tpm2.PolicyPCR{\n\t\tPcrDigest: tpm2.TPM2BDigest{\n\t\t\tBuffer: hash.Sum(nil),\n\t\t},\n\t\tPcrs: pcrSelection,\n\t}\n\n\tif err := policy.Update(calculator); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to update policy digest for PCRs %v: %v\", spInfo.PCRs, err)\n\t}\n\n\treturn calculator.Hash().Digest, nil\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/policy_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\t\"github.com/google/go-tpm/tpm2/transport\"\n\t\"github.com/stretchr/testify/require\"\n\n\ttpm2internal \"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2\"\n)\n\nfunc TestCalculatePolicy(t *testing.T) {\n\tt.Parallel()\n\n\tpolicy, err := tpm2internal.CalculatePolicy([]byte{1, 3, 5}, tpm2.TPMLPCRSelection{\n\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t{\n\t\t\t\tHash:      tpm2.TPMAlgSHA256,\n\t\t\t\tPCRSelect: []byte{10, 11, 12},\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t,\n\t\t[]byte{0x84, 0xd6, 0x51, 0x47, 0xb0, 0x53, 0x94, 0xd0, 0xfa, 0xc4, 0x5e, 0x36, 0x0, 0x20, 0x3e, 0x3a, 0x11, 0x1, 0x27, 0xfb, 0xe2, 0x6f, 0xc1, 0xe3, 0x3, 0x3, 0x10, 0x21, 0x33, 0xf9, 0x15, 0xe3},\n\t\tpolicy,\n\t)\n}\n\nfunc TestCalculateSealingPolicyDigestWithNOPCRs(t *testing.T) {\n\tt.Parallel()\n\n\tcalculated, err := tpm2internal.CalculateSealingPolicyDigest(nil, tpm2internal.SealingPolicyDigestInfo{\n\t\tPublicKey: \"testdata/pcr-signing-crt.pem\",\n\t\tReadPCRFunc: func(t transport.TPM, pcr int) ([]byte, error) {\n\t\t\treturn nil, nil\n\t\t},\n\t})\n\n\trequire.NoError(t, err)\n\n\trequire.Equal(t,\n\t\t[]byte{0x86, 0xdc, 0x2b, 0x7f, 0x5a, 0xeb, 0xde, 0x57, 0xd4, 0x72, 0xdd, 0xbc, 0x3d, 0x5b, 0xd5, 0xb5, 0xb, 0x15, 0x6f, 0x4d, 0x6b, 0xa6, 0x62, 0xc2, 0x1a, 0xff, 0xbf, 0xb1, 0xb2, 0xd4, 0xb9, 0x84},\n\t\tcalculated,\n\t)\n}\n\nfunc TestCalculateSealingPolicyDigestWithPCRs(t *testing.T) {\n\tt.Parallel()\n\n\tcalculated, err := tpm2internal.CalculateSealingPolicyDigest(nil, tpm2internal.SealingPolicyDigestInfo{\n\t\tPublicKey: \"testdata/pcr-signing-crt.pem\",\n\t\tPCRs:      []int{0, 11},\n\t\tReadPCRFunc: func(t transport.TPM, pcr int) ([]byte, error) {\n\t\t\treturn []byte{0x9c, 0x9c, 0x10, 0x58, 0x77, 0x9d, 0x2b, 0xf6, 0x30, 0x1b, 0x56, 0x8, 0x5b, 0x26, 0xe9, 0xae, 0x98, 0x62, 0x2e, 0x1f, 0xa7, 0x3e, 0xad, 0xd9, 0x8b, 0x9c, 0xa3, 0xa1, 0x8, 0x29, 0xc1, 0x9c}, nil //nolint:lll\n\t\t},\n\t})\n\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, []byte{0x14, 0xff, 0x86, 0xf8, 0x6, 0x9c, 0xe4, 0xf2, 0xc9, 0x18, 0x32, 0x5e, 0x2e, 0x1b, 0x78, 0x11, 0xcf, 0xc5, 0xe6, 0x27, 0x8d, 0xd1, 0xb, 0x86, 0xa9, 0x4, 0x16, 0xc2, 0x8f, 0xe6, 0x47, 0x6a}, calculated) //nolint:lll\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/seal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/tpm\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Seal seals the key using TPM2.0.\nfunc Seal(key []byte, tpmPCRs []int) (*SealedResponse, error) {\n\tt, err := tpm.Open()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer t.Close() //nolint:errcheck\n\n\t// fail early if PCR banks are not present or filled with all zeroes or 0xff\n\tif err = validatePCRBanks(t, tpmPCRs); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsealingPolicyDigest, err := CalculateSealingPolicyDigest(t, SealingPolicyDigestInfo{\n\t\tPublicKey:   constants.PCRPublicKey,\n\t\tPCRs:        tpmPCRs,\n\t\tReadPCRFunc: ReadPCR,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to calculate sealing policy digest: %v\", err)\n\t}\n\n\tprimary := tpm2.CreatePrimary{\n\t\tPrimaryHandle: tpm2.TPMRHOwner,\n\t\tInPublic:      tpm2.New2B(tpm2.ECCSRKTemplate),\n\t}\n\n\tcreatePrimaryResponse, err := primary.Execute(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// TODO: persist SRK as per https://github.com/systemd/systemd/blob/main/src/shared/tpm2-util.c#L1039\n\n\tdefer func() {\n\t\tflush := tpm2.FlushContext{\n\t\t\tFlushHandle: createPrimaryResponse.ObjectHandle,\n\t\t}\n\n\t\t_, flushErr := flush.Execute(t)\n\t\tif flushErr != nil {\n\t\t\terr = flushErr\n\t\t}\n\t}()\n\n\toutPub, err := createPrimaryResponse.OutPublic.Contents()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcreate := tpm2.Create{\n\t\tParentHandle: tpm2.AuthHandle{\n\t\t\tHandle: createPrimaryResponse.ObjectHandle,\n\t\t\tName:   createPrimaryResponse.Name,\n\t\t\tAuth: tpm2.HMAC(\n\t\t\t\ttpm2.TPMAlgSHA256,\n\t\t\t\t20,\n\t\t\t\ttpm2.Salted(createPrimaryResponse.ObjectHandle, *outPub),\n\t\t\t\ttpm2.AESEncryption(128, tpm2.EncryptInOut),\n\t\t\t),\n\t\t},\n\t\tInSensitive: tpm2.TPM2BSensitiveCreate{\n\t\t\tSensitive: &tpm2.TPMSSensitiveCreate{\n\t\t\t\tData: tpm2.NewTPMUSensitiveCreate(&tpm2.TPM2BSensitiveData{\n\t\t\t\t\tBuffer: key,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t\tInPublic: tpm2.New2B(tpm2.TPMTPublic{\n\t\t\tType:    tpm2.TPMAlgKeyedHash,\n\t\t\tNameAlg: tpm2.TPMAlgSHA256,\n\t\t\tObjectAttributes: tpm2.TPMAObject{\n\t\t\t\tFixedTPM:    true,\n\t\t\t\tFixedParent: true,\n\t\t\t\tNoDA:        true, // see https://github.com/systemd/systemd/pull/30728\n\t\t\t},\n\t\t\tParameters: tpm2.NewTPMUPublicParms(tpm2.TPMAlgKeyedHash, &tpm2.TPMSKeyedHashParms{\n\t\t\t\tScheme: tpm2.TPMTKeyedHashScheme{\n\t\t\t\t\tScheme: tpm2.TPMAlgNull,\n\t\t\t\t},\n\t\t\t}),\n\t\t\tAuthPolicy: tpm2.TPM2BDigest{\n\t\t\t\tBuffer: sealingPolicyDigest,\n\t\t\t},\n\t\t}),\n\t}\n\n\tcreateResp, err := create.Execute(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp := SealedResponse{\n\t\tSealedBlobPrivate: tpm2.Marshal(createResp.OutPrivate),\n\t\tSealedBlobPublic:  tpm2.Marshal(createResp.OutPublic),\n\t\tKeyName:           tpm2.Marshal(createPrimaryResponse.Name),\n\t\tPolicyDigest:      sealingPolicyDigest,\n\t\tPCRs:              tpmPCRs,\n\t\tPubKeyPCRs:        []int{constants.UKIPCR},\n\t\tEncryptionVersion: EncryptionSchemaVersionErrata,\n\t\tAlg:               \"sha256\",\n\t}\n\n\treturn &resp, nil\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/signature.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// PCRData is the data structure for PCR signature json.\ntype PCRData struct {\n\tSHA1   []BankData `json:\"sha1,omitempty\"`\n\tSHA256 []BankData `json:\"sha256,omitempty\"`\n\tSHA384 []BankData `json:\"sha384,omitempty\"`\n\tSHA512 []BankData `json:\"sha512,omitempty\"`\n}\n\n// BankData constains data for a specific PCR bank.\ntype BankData struct {\n\t// list of PCR banks\n\tPCRs []int `json:\"pcrs\"`\n\t// Public key of the TPM\n\tPKFP string `json:\"pkfp\"`\n\t// Policy digest\n\tPol string `json:\"pol\"`\n\t// Signature of the policy digest in base64\n\tSig string `json:\"sig\"`\n}\n\n// ParsePCRSignature parses the PCR signature json file.\nfunc ParsePCRSignature() (*PCRData, error) {\n\tpcrSignature, err := os.ReadFile(constants.PCRSignatureJSON)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read pcr signature: %v\", err)\n\t}\n\n\tpcrData := &PCRData{}\n\n\tif err = json.Unmarshal(pcrSignature, pcrData); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal pcr signature: %v\", err)\n\t}\n\n\treturn pcrData, nil\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/testdata/pcr-signing-crt.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7qhAkdtZxqkIP79DDGin\n9eaJBeNlJsClJTcbaXbNfk2QJGT3lqo9ErXQQftwYWLGo+kVd8puhnHGPkLW9apT\n1/ZmUJEFwxV5xws0RllGVPhUga+1oubHUqhEiy707S4RrUEMk/o9wqmtnl2hY5Fx\nMeQn2o7xrpcNhm8FtHpvQrT0MsbC1cS1ytZH/hwPy/QIB9bx+ugOha6wtQBnpgix\n1BhHC/NwDIYPg+ONpQSCu9gkXVtLGlKfmjscUANQtBuVKa5NflrjkHw7NAdKYdKp\nMnmzr0yu6Tn/2oNmUiJAwHz0BXpfb4Yn8n/IoKJQ5Tv1g6d30wxxpBd0lbwSe9ML\nRchIDJ5aFRybyRxaPGT17U3yEVzbV78kIFtocaqkc1ise8remZ0wxHzuolbTZD6o\nswt7C9jMLvfMAQ7JtENXrpDM//XzdRLzyTWKOjhG0YmKKRY6cIrPkugM0PHGCE3R\nMSH1FmPMrWWBNAMwS0Zba0Wm1b7vdw5fKeE8txH+IpA3IaE9AytYk0ig98ZgmXmB\nV0sgxmJ/94scEF+sDg65LIkSEJMzf6q30UghbJJoP7eKOoDX9KBrR+POEsWm/EcU\n5jTEQTHMU+qKtj5KD6TUn8R8yi4wCnyZ7uJLUqm8Ou8MzEZWbrsrbMvrewPDAHn0\nQQvb2tDtBgn6oH192jpkzckCAwEAAQ==\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/tpm2.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nconst (\n\t// EncryptionSchemaVersionErrata is the errata for the encryption schema version.\n\t// Talos versions older than 1.12 locked to PCR 7 and PCR 11 but the luks json header only\n\t// saved the PCR 11 value, so if the version is not set or empty we can assume that the keys\n\t// are sealed to both PCR 7 and PCR 11. If the version is `1` we can be sure that the keys\n\t// are locked to PCR 11 only.\n\tEncryptionSchemaVersionErrata = \"1\"\n)\n\n// SealedResponse is the response from the TPM2.0 Seal operation.\ntype SealedResponse struct {\n\tSealedBlobPrivate []byte\n\tSealedBlobPublic  []byte\n\tKeyName           []byte\n\tPolicyDigest      []byte\n\tPCRs              []int\n\tPubKeyPCRs        []int\n\tEncryptionVersion string\n\tAlg               string\n}\n"
  },
  {
    "path": "internal/pkg/secureboot/tpm2/unseal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package tpm2 provides TPM2.0 related functionality helpers.\npackage tpm2\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/google/go-tpm/tpm2\"\n\t\"github.com/google/go-tpm/tpm2/transport\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/tpm\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Unseal unseals a sealed blob using the TPM\n//\n//nolint:gocyclo,cyclop\nfunc Unseal(sealed SealedResponse) ([]byte, error) {\n\tt, err := tpm.Open()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer t.Close() //nolint:errcheck\n\n\t// fail early if PCR banks are not present or filled with all zeroes or 0xff\n\tif err = validatePCRBanks(t, sealed.PCRs); err != nil {\n\t\treturn nil, err\n\t}\n\n\ttpmPub, err := tpm2.Unmarshal[tpm2.TPM2BPublic](sealed.SealedBlobPublic)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttpmPriv, err := tpm2.Unmarshal[tpm2.TPM2BPrivate](sealed.SealedBlobPrivate)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsrk, err := tpm2.Unmarshal[tpm2.TPM2BName](sealed.KeyName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// we need to create a primary since we don't persist the SRK\n\tprimary := tpm2.CreatePrimary{\n\t\tPrimaryHandle: tpm2.TPMRHOwner,\n\t\tInPublic:      tpm2.New2B(tpm2.ECCSRKTemplate),\n\t}\n\n\tcreatePrimaryResponse, err := primary.Execute(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer func() {\n\t\tflush := tpm2.FlushContext{\n\t\t\tFlushHandle: createPrimaryResponse.ObjectHandle,\n\t\t}\n\n\t\t_, flushErr := flush.Execute(t)\n\t\tif flushErr != nil {\n\t\t\terr = flushErr\n\t\t}\n\t}()\n\n\toutPub, err := createPrimaryResponse.OutPublic.Contents()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !bytes.Equal(createPrimaryResponse.Name.Buffer, srk.Buffer) {\n\t\t// this means the srk name does not match, possibly due to a different TPM or tpm was reset\n\t\t// could also mean the disk was used on a different machine\n\t\treturn nil, fmt.Errorf(\"srk name does not match, expected %x, got %x\", srk.Buffer, createPrimaryResponse.Name.Buffer)\n\t}\n\n\tload := tpm2.Load{\n\t\tParentHandle: tpm2.NamedHandle{\n\t\t\tHandle: createPrimaryResponse.ObjectHandle,\n\t\t\tName:   createPrimaryResponse.Name,\n\t\t},\n\t\tInPrivate: *tpmPriv,\n\t\tInPublic:  *tpmPub,\n\t}\n\n\tloadResponse, err := load.Execute(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpolicySess, policyCloseFunc, err := tpm2.PolicySession(\n\t\tt,\n\t\ttpm2.TPMAlgSHA256,\n\t\t20,\n\t\ttpm2.Salted(createPrimaryResponse.ObjectHandle, *outPub),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create policy session: %w\", err)\n\t}\n\n\tdefer policyCloseFunc() //nolint:errcheck\n\n\tpubKey, err := ParsePCRSigningPubKey(constants.PCRPublicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tloadExternal := tpm2.LoadExternal{\n\t\tHierarchy: tpm2.TPMRHOwner,\n\t\tInPublic:  tpm2.New2B(RSAPubKeyTemplate(pubKey.N.BitLen(), pubKey.E, pubKey.N.Bytes())),\n\t}\n\n\tloadExternalResponse, err := loadExternal.Execute(t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load external key: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tflush := tpm2.FlushContext{\n\t\t\tFlushHandle: loadExternalResponse.ObjectHandle,\n\t\t}\n\n\t\t_, flushErr := flush.Execute(t)\n\t\tif flushErr != nil {\n\t\t\terr = flushErr\n\t\t}\n\t}()\n\n\tpcrSelector, err := CreateSelector([]int{constants.UKIPCR})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpolicyDigest, err := PolicyPCRDigest(t, policySess.Handle(), tpm2.TPMLPCRSelection{\n\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t{\n\t\t\t\tHash:      tpm2.TPMAlgSHA256,\n\t\t\t\tPCRSelect: pcrSelector,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to retrieve policy digest: %w\", err)\n\t}\n\n\tsigJSON, err := ParsePCRSignature()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpubKeyFingerprint := sha256.Sum256(x509.MarshalPKCS1PublicKey(pubKey))\n\n\tvar signature string\n\t// TODO: maybe we should use the highest supported algorithm of the TPM\n\t// fallback to the next one if the signature is not found\n\tfor _, bank := range sigJSON.SHA256 {\n\t\tdigest, decodeErr := hex.DecodeString(bank.Pol)\n\t\tif decodeErr != nil {\n\t\t\treturn nil, decodeErr\n\t\t}\n\n\t\tif bytes.Equal(digest, policyDigest.Buffer) {\n\t\t\tsignature = bank.Sig\n\n\t\t\tif hex.EncodeToString(pubKeyFingerprint[:]) != bank.PKFP {\n\t\t\t\treturn nil, errors.New(\"certificate fingerprint does not match\")\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif signature == \"\" {\n\t\treturn nil, errors.New(\"no signatures matching PCR SHA256 digest found in signature JSON\")\n\t}\n\n\tsignatureDecoded, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Verify will only verify the RSA part of the RSA+SHA256 signature,\n\t// hence we need to do the SHA256 part ourselves\n\tpolicyDigestHash := sha256.Sum256(policyDigest.Buffer)\n\n\tverifySignature := tpm2.VerifySignature{\n\t\tKeyHandle: loadExternalResponse.ObjectHandle,\n\t\tDigest: tpm2.TPM2BDigest{\n\t\t\tBuffer: policyDigestHash[:],\n\t\t},\n\t\tSignature: tpm2.TPMTSignature{\n\t\t\tSigAlg: tpm2.TPMAlgRSASSA,\n\t\t\tSignature: tpm2.NewTPMUSignature(tpm2.TPMAlgRSASSA, &tpm2.TPMSSignatureRSA{\n\t\t\t\tHash: tpm2.TPMAlgSHA256,\n\t\t\t\tSig: tpm2.TPM2BPublicKeyRSA{\n\t\t\t\t\tBuffer: signatureDecoded,\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\t}\n\n\tverifySignatureResponse, err := verifySignature.Execute(t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to verify signature: %w\", err)\n\t}\n\n\tpolicyAuthorize := tpm2.PolicyAuthorize{\n\t\tPolicySession:  policySess.Handle(),\n\t\tApprovedPolicy: *policyDigest,\n\t\tKeySign:        loadExternalResponse.Name,\n\t\tCheckTicket:    verifySignatureResponse.Validation,\n\t}\n\n\tif _, err = policyAuthorize.Execute(t); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to execute policy authorize: %w\", err)\n\t}\n\n\t// this handles the case when talos is upgraded from pre Talos 1.12 and we had PCRs field\n\t// set to just PCR 11 but locked to PCR 7\n\t// in this case the EncryptionVersion is empty and the PubKeyPCRs field is also empty\n\t// since both EncryptionVersion and PubKeyPCRs are introduced for Talos 1.12+ only\n\tif sealed.EncryptionVersion == \"\" && len(sealed.PubKeyPCRs) == 0 {\n\t\tif len(sealed.PCRs) == 1 && sealed.PCRs[0] == constants.UKIPCR {\n\t\t\tif err := validatePCRPolicyDigest(t, policySess.Handle(), []int{constants.SecureBootStatePCR}, sealed.PolicyDigest); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to validate PCR policy digest for PCRs %v: %w\", []int{constants.SecureBootStatePCR}, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Talos 1.12+ sets the EncryptionVersion and PubKeyPCRs to PCR 11 and any other PCR used to PCRs field\n\tif sealed.EncryptionVersion != \"\" && len(sealed.PCRs) > 0 {\n\t\tif err := validatePCRPolicyDigest(t, policySess.Handle(), sealed.PCRs, sealed.PolicyDigest); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to validate PCR policy digest for PCRs %v: %w\", sealed.PCRs, err)\n\t\t}\n\t}\n\n\tunsealOp := tpm2.Unseal{\n\t\tItemHandle: tpm2.AuthHandle{\n\t\t\tHandle: loadResponse.ObjectHandle,\n\t\t\tName:   loadResponse.Name,\n\t\t\tAuth:   policySess,\n\t\t},\n\t}\n\n\tunsealResponse, err := unsealOp.Execute(t, tpm2.HMAC(\n\t\ttpm2.TPMAlgSHA256,\n\t\t20,\n\t\ttpm2.Salted(createPrimaryResponse.ObjectHandle, *outPub),\n\t\ttpm2.AESEncryption(128, tpm2.EncryptOut),\n\t\ttpm2.Bound(loadResponse.ObjectHandle, loadResponse.Name, nil),\n\t))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unseal op: %w\", err)\n\t}\n\n\treturn unsealResponse.OutData.Buffer, nil\n}\n\nfunc validatePCRPolicyDigest(t transport.TPM, handle tpm2.TPMHandle, pcrs []int, digest []byte) error {\n\tpcrSelector, err := CreateSelector(pcrs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create PCR selector for PCRs %v: %w\", pcrs, err)\n\t}\n\n\tpcrPolicyDigest, err := PolicyPCRDigest(t, handle, tpm2.TPMLPCRSelection{\n\t\tPCRSelections: []tpm2.TPMSPCRSelection{\n\t\t\t{\n\t\t\t\tHash:      tpm2.TPMAlgSHA256,\n\t\t\t\tPCRSelect: pcrSelector,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to calculate policy PCR digest: %w\", err)\n\t}\n\n\tif !bytes.Equal(pcrPolicyDigest.Buffer, digest) {\n\t\treturn fmt.Errorf(\"sealing policy digest does not match, expected %x, got %x\", digest, pcrPolicyDigest.Buffer)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/selinux/policy/file_contexts",
    "content": "/etc(/.*)?\tsystem_u:object_r:etc_t:s0\n/opt(/.*)?\tsystem_u:object_r:opt_t:s0\n/usr(/.*)?\tsystem_u:object_r:usr_t:s0\n/etc/cni(/.*)?\tsystem_u:object_r:cni_conf_t:s0\n/opt/cni(/.*)?\tsystem_u:object_r:cni_plugin_t:s0\n/usr/bin(/.*)?\tsystem_u:object_r:bin_exec_t:s0\n/usr/lib(/.*)?\tsystem_u:object_r:lib_t:s0\n/usr/lib/udev(/.*)?\tsystem_u:object_r:udev_exec_t:s0\n/etc/kubernetes(/.*)?\tsystem_u:object_r:k8s_conf_t:s0\n/opt/containerd(/.*)?\tsystem_u:object_r:containerd_plugin_t:s0\n/usr/lib/modules(/.*)?\tsystem_u:object_r:module_t:s0\n/usr/share/zoneinfo(/.*)?\tsystem_u:object_r:etc_t:s0\n/usr/lib/udev/rules.d(/.*)?\tsystem_u:object_r:udev_rules_t:s0\n/usr/libexec/kubernetes(/.*)?\tsystem_u:object_r:k8s_plugin_t:s0\n/usr/local/lib/kubelet/credentialproviders(/.*)?\tsystem_u:object_r:k8s_credentialproviders_t:s0\n/\tsystem_u:object_r:rootfs_t:s0\n/bin\tsystem_u:object_r:bin_exec_t:s0\n/lib\tsystem_u:object_r:lib_t:s0\n/sbin\tsystem_u:object_r:bin_exec_t:s0\n/lib64\tsystem_u:object_r:lib_t:s0\n/usr/sbin\tsystem_u:object_r:bin_exec_t:s0\n/usr/lib64\tsystem_u:object_r:lib_t:s0\n/lib/modules\tsystem_u:object_r:module_t:s0\n/usr/bin/runc\tsystem_u:object_r:containerd_exec_t:s0\n/usr/bin/init\t--\tsystem_u:object_r:init_exec_t:s0\n/usr/bin/udevadm\t--\tsystem_u:object_r:udev_exec_t:s0\n/usr/bin/poweroff\tsystem_u:object_r:init_exec_t:s0\n/usr/bin/shutdown\tsystem_u:object_r:init_exec_t:s0\n/usr/bin/modprobe\t--\tsystem_u:object_r:modprobe_exec_t:s0\n/usr/bin/dashboard\tsystem_u:object_r:init_exec_t:s0\n/usr/bin/containerd\tsystem_u:object_r:containerd_exec_t:s0\n/usr/bin/systemd-udevd\t--\tsystem_u:object_r:udev_exec_t:s0\n/usr/bin/containerd-shim-runc-v2\tsystem_u:object_r:containerd_exec_t:s0\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/common/classmaps.cil",
    "content": "; Access to all file classes\n(classmap fs_classes (getattr ioctl relabelfrom relabelto mounton rw ro))\n; getattr\n(classmapping fs_classes relabelfrom (filesystem (getattr)))\n(classmapping fs_classes getattr (file (getattr)))\n(classmapping fs_classes getattr (dir (getattr)))\n(classmapping fs_classes getattr (lnk_file (getattr)))\n(classmapping fs_classes getattr (chr_file (getattr)))\n(classmapping fs_classes getattr (blk_file (getattr)))\n(classmapping fs_classes getattr (sock_file (getattr)))\n(classmapping fs_classes getattr (fifo_file (getattr)))\n; ioctl\n(classmapping fs_classes ioctl (file (ioctl)))\n(classmapping fs_classes ioctl (dir (ioctl)))\n(classmapping fs_classes ioctl (lnk_file (ioctl)))\n(classmapping fs_classes ioctl (chr_file (ioctl)))\n(classmapping fs_classes ioctl (blk_file (ioctl)))\n(classmapping fs_classes ioctl (sock_file (ioctl)))\n(classmapping fs_classes ioctl (fifo_file (ioctl)))\n; relabelfrom\n(classmapping fs_classes relabelfrom (filesystem (relabelfrom)))\n(classmapping fs_classes relabelfrom (file (relabelfrom)))\n(classmapping fs_classes relabelfrom (dir (relabelfrom)))\n(classmapping fs_classes relabelfrom (lnk_file (relabelfrom)))\n(classmapping fs_classes relabelfrom (chr_file (relabelfrom)))\n(classmapping fs_classes relabelfrom (blk_file (relabelfrom)))\n(classmapping fs_classes relabelfrom (sock_file (relabelfrom)))\n(classmapping fs_classes relabelfrom (fifo_file (relabelfrom)))\n; relabelto\n(classmapping fs_classes relabelto (filesystem (relabelto)))\n(classmapping fs_classes relabelto (file (relabelto)))\n(classmapping fs_classes relabelto (dir (relabelto)))\n(classmapping fs_classes relabelto (lnk_file (relabelto)))\n(classmapping fs_classes relabelto (chr_file (relabelto)))\n(classmapping fs_classes relabelto (blk_file (relabelto)))\n(classmapping fs_classes relabelto (sock_file (relabelto)))\n(classmapping fs_classes relabelto (fifo_file (relabelto)))\n; mounton\n(classmapping fs_classes mounton (file (mounton)))\n(classmapping fs_classes mounton (dir (mounton)))\n(classmapping fs_classes mounton (lnk_file (mounton)))\n(classmapping fs_classes mounton (chr_file (mounton)))\n(classmapping fs_classes mounton (blk_file (mounton)))\n(classmapping fs_classes mounton (sock_file (mounton)))\n(classmapping fs_classes mounton (fifo_file (mounton)))\n; rw is full without SELinux management\n(classmapping fs_classes rw (filesystem (\n    associate\n    getattr\n    mount\n    quotaget\n    quotamod\n    remount\n    unmount\n    watch\n)))\n(classmapping fs_classes rw (file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n(classmapping fs_classes rw (dir (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n    add_name remove_name reparent rmdir search\n)))\n(classmapping fs_classes rw (lnk_file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n(classmapping fs_classes rw (chr_file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n(classmapping fs_classes rw (blk_file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n(classmapping fs_classes rw (sock_file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n(classmapping fs_classes rw (fifo_file (\n    append create execmod getattr ioctl link lock map mounton open quotaon read rename setattr unlink watch watch_mount watch_reads watch_sb watch_with_perm write\n)))\n; ro is rw without write and configure\n(classmapping fs_classes ro (filesystem (\n    associate\n    getattr\n    quotaget\n    watch\n)))\n(classmapping fs_classes ro (file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n(classmapping fs_classes ro (dir (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n    search\n)))\n(classmapping fs_classes ro (lnk_file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n(classmapping fs_classes ro (chr_file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n(classmapping fs_classes ro (blk_file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n(classmapping fs_classes ro (sock_file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n(classmapping fs_classes ro (fifo_file (\n    execmod getattr lock map open read watch watch_mount watch_reads watch_sb watch_with_perm\n)))\n\n; Netlink socket access\n(classmap netlink_classes (full))\n; Full means any access except relabeling\n(classmapping netlink_classes full (netlink_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_route_socket (\n    accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write\n    nlmsg_read nlmsg_write\n)))\n(classmapping netlink_classes full (netlink_tcpdiag_socket (\n    accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write\n    nlmsg_read nlmsg_write\n)))\n(classmapping netlink_classes full (netlink_nflog_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_xfrm_socket (\n    accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write\n    nlmsg_read nlmsg_write\n)))\n(classmapping netlink_classes full (netlink_selinux_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_audit_socket (\n    accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write\n    nlmsg_read nlmsg_write nlmsg_relay nlmsg_readpriv nlmsg_tty_audit\n)))\n(classmapping netlink_classes full (netlink_dnrt_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n; Used by eBPF performance utilities\n(classmapping netlink_classes full (netlink_kobject_uevent_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_iscsi_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_fib_lookup_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_connector_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_netfilter_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_generic_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_scsitransport_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_rdma_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(classmapping netlink_classes full (netlink_crypto_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n\n; Everything except ptrace\n(classmap process_classes (full signal))\n(classmapping process_classes full (process (\n    dyntransition\n    execheap\n    execmem\n    execstack\n    fork\n    getattr\n    getcap\n    getpgid\n    getsched\n    getsession\n    getrlimit\n    noatsecure\n    rlimitinh\n    setcap\n    setcurrent\n    setexec\n    setfscreate\n    setkeycreate\n    setpgid\n    setrlimit\n    setsched\n    setsockcreate\n    share\n    sigchld\n    siginh\n    sigkill\n    signal\n    signull\n    sigstop\n    transition\n)))\n(classmapping process_classes signal (process (\n    sigchld\n    siginh\n    sigkill\n    signal\n    signull\n    sigstop\n)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/common/files.cil",
    "content": "; Runtime and mounted filesystems\n(type system_t)\n(call filesystem_f (system_t))\n(allow system_t tmpfs_t (filesystem (associate)))\n\n(type system_run_t)\n(call system_f (system_run_t))\n(allow system_run_t tmpfs_t (filesystem (associate)))\n\n(type system_run_containerd_t)\n(call system_f (system_run_containerd_t))\n(allow system_run_containerd_t tmpfs_t (filesystem (associate)))\n\n(type run_containerd_t)\n(call system_f (run_containerd_t))\n(allow run_containerd_t tmpfs_t (filesystem (associate)))\n\n(type etc_t)\n(call system_f (etc_t))\n(allow etc_t fs_t (filesystem (associate)))\n(allow etc_t tmpfs_t (filesystem (associate)))\n(context etc_t (system_u object_r etc_t (systemLow systemLow)))\n(filecon \"/etc(/.*)?\" any etc_t)\n(filecon \"/usr/share/zoneinfo(/.*)?\" any etc_t)\n\n(type system_var_t)\n(call system_f (system_var_t))\n(allow system_var_t fs_t (filesystem (associate)))\n(allow system_var_t tmpfs_t (filesystem (associate)))\n\n(type ephemeral_t)\n(call filesystem_f (ephemeral_t))\n(type system_state_t)\n(call filesystem_f (system_state_t))\n\n(type run_t)\n(call filesystem_f (run_t))\n(allow run_t tmpfs_t (filesystem (associate)))\n\n(type opt_t)\n(call filesystem_f (opt_t))\n(filecon \"/opt(/.*)?\" any (system_u object_r opt_t (systemLow systemLow)))\n\n(type usr_t)\n(call system_f (usr_t))\n(filecon \"/usr(/.*)?\" any (system_u object_r usr_t (systemLow systemLow)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/common/network.cil",
    "content": "(allow any_p port_t (dccp_socket (name_connect)))\n(allow any_p port_t (sctp_socket (name_bind name_connect)))\n(allow any_p port_t (tcp_socket (name_bind name_connect)))\n(allow any_p port_t (udp_socket (name_bind)))\n(allow any_p port_t (rawip_socket (name_bind)))\n(allow any_p node_t (dccp_socket (node_bind)))\n(allow any_p node_t (tcp_socket (node_bind)))\n(allow any_p node_t (udp_socket (node_bind)))\n(allow any_p node_t (rawip_socket (node_bind)))\n(allow any_p node_t (sctp_socket (node_bind)))\n(allow any_p node_t (icmp_socket (node_bind)))\n\n(allow any_p netif_t (netif (egress ingress)))\n\n; Network sockets, except relabeling\n(allow any_p any_p (socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (dccp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (tcp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (udp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (rawip_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (packet_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (key_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (appletalk_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (tun_socket (\n    accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write\n    attach_queue\n)))\n(allow any_p any_p (sctp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (icmp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (ax25_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (ipx_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (netrom_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (atmpvc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (x25_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (rose_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (decnet_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (atmsvc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (rds_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (irda_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (pppox_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (llc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (can_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (tipc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (bluetooth_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (iucv_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (rxrpc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (isdn_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (phonet_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (ieee802154_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (caif_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (alg_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (nfc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (vsock_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (kcm_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (qipcrtr_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (smc_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p any_p (xdp_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n\n; UDS within any domain is always allowed\n(allow any_p self (unix_stream_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n(allow any_p self (unix_dgram_socket (accept append bind connect create getattr getopt ioctl listen lock map name_bind read recvfrom sendto setattr setopt shutdown write)))\n\n; Netlink\n(allow any_p self (netlink_classes (full)))\n(allow system_p any_p (netlink_classes (full)))\n\n; IPsec\n(allow any_p self (association (sendto recvfrom setcontext polmatch)))\n(allow any_p unlabeled_t (association (sendto recvfrom setcontext polmatch)))\n\n; InfiniBand\n(allow any_p unlabeled_t (infiniband_pkey (access)))\n(allow any_p unlabeled_t (infiniband_endport (manage_subnet)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/common/processes.cil",
    "content": "; Query procfs about self, plus OOM adj and similar writes (controlled by other access control and caps)\n; Also FIFO/socket writes for own stuff\n(allow any_p self (fs_classes (rw)))\n; Read process info\n(allow any_p procfs_t (fs_classes (ro)))\n; Allow all process actions but ptrace, set* will be guarded by transitions\n(allow any_p self (process_classes (full)))\n; Read various parameters like hugepages\n(allow any_p sysfs_t (fs_classes (ro)))\n(allow any_p proc_cmdline_t (fs_classes (ro)))\n\n; Pseudo devices\n(allow any_p null_device_t (fs_classes (rw)))\n\n; All caps, except sys_boot and sys_modules\n(allow any_p self (capability (\n    audit_control\n    audit_write\n    chown\n    dac_override\n    dac_read_search\n    fowner\n    fsetid\n    ipc_lock\n    ipc_owner\n    kill\n    lease\n    linux_immutable\n    mknod\n    net_admin\n    net_bind_service\n    net_broadcast\n    net_raw\n    setfcap\n    setgid\n    setpcap\n    setuid\n    sys_admin\n    sys_chroot\n    sys_nice\n    sys_pacct\n    sys_ptrace\n    sys_rawio\n    sys_resource\n    sys_time\n    sys_tty_config\n)))\n(allow any_p self (cap_userns (\n    audit_control\n    audit_write\n    chown\n    dac_override\n    dac_read_search\n    fowner\n    fsetid\n    ipc_lock\n    ipc_owner\n    kill\n    lease\n    linux_immutable\n    mknod\n    net_admin\n    net_bind_service\n    net_broadcast\n    net_raw\n    setfcap\n    setgid\n    setpcap\n    setuid\n    sys_admin\n    sys_chroot\n    sys_nice\n    sys_pacct\n    sys_ptrace\n    sys_rawio\n    sys_resource\n    sys_time\n    sys_tty_config\n)))\n; All but mac_admin, mac_override and syslog\n(allow any_p self (capability2 (\n    audit_read\n    block_suspend\n    bpf\n    checkpoint_restore\n    perfmon\n    wake_alarm\n)))\n(allow any_p self (cap2_userns (\n    audit_read\n    block_suspend\n    bpf\n    checkpoint_restore\n    perfmon\n    wake_alarm\n)))\n\n; Enable (e)BPF for all processes\n(allow any_p self (bpf (map_create map_read map_write prog_load prog_run)))\n\n; Allow init to manage processes\n(allow init_t service_p (fs_classes (rw)))\n(allow init_t service_p (process_classes (full)))\n\n; kernel cmdline\n(allow system_p proc_cmdline_t (fs_classes (ro)))\n(allow system_container_p proc_cmdline_t (fs_classes (ro)))\n\n; These only run binaries from the squashfs so this shouldn't do harm.\n; TODO: eliminate such common permissions\n(allow system_p any_f (fs_classes (ro)))\n(allow system_container_p any_f (fs_classes (ro)))\n\n; By default, allow any process to access any device except special ones\n(allow any_p common_device_f (fs_classes (rw)))\n; CNI, containerd, many different services read and write sysctl parameters\n(allow any_p proc_sysctl_t (fs_classes (rw)))\n; Unconfined FS and files\n(allow any_p unconfined_f (fs_classes (rw)))\n; Kernel threads can access anything\n(allow kernel_t any_f (fs_classes (rw)))\n\n; Own sockets\n(allow any_p self (unix_stream_socket (connectto)))\n\n; allow reading cgroup info\n(allow any_p cgroup_t (fs_classes (ro)))\n\n; ; cilium-agent\n; (allow any_p self (perf_event (all)))\n; (allow any_p bpf_t (fs_classes (rw)))\n\n; fio\n(allow any_p self (shm (all)))\n\n; /run/flannel, created by containerd\n(allow any_p pod_containerd_run_t (fs_classes (rw)))\n\n; Mayastor\n(allow any_p hugetlbfs_t (fs_classes (rw)))\n\n; ceph-osd accesses io_uring\n(allow any_p self (anon_inode (map read write create)))\n\n; ; cilium lock, socket and misc runtime files\n; (allow any_p run_t (fs_classes (rw)))\n\n; time data, LVM config\n(allow any_p etc_t (fs_classes (ro)))\n\n; ; OpenEBS manages volumes, ceph\n; (allow any_p sysfs_t (fs_classes (rw)))\n; (allow any_p udev_run_t (fs_classes (ro ioctl)))\n\n; ; pods also run CNI, LVM and other host binaries\n; (allow any_p bin_exec_t (fs_classes (ro)))\n; (allow pod_p bin_exec_t (file (execute execute_no_trans)))\n\n; pf-2-proto-262-type-1\n; refpolicy allows it for spc_t\n(allow any_p kernel_t (system (module_request)))\n\n; debug transitions:\n; (auditallow any_f_any_p any_f_any_p (process (dyntransition fork ptrace setcurrent setexec setfscreate setkeycreate transition)))\n; (auditallow any_f_any_p any_f_any_p (process2 (nnp_transition nosuid_transition)))\n; (auditallow any_f_any_p any_f_any_p (file (entrypoint execute execute_no_trans)))\n\n; HACK: this happens in a process cloned from containerd for running CNI:\n; [   77.042515] audit: type=1400 audit(1741862615.446:4227): avc:  granted  { execute } for  pid=3136 comm=\"containerd\" name=\"loopback\" dev=\"loop0\" ino=68 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:cni_plugin_t:s0 tclass=file\n; [   77.043500] audit: type=1400 audit(1741862615.446:4227): avc:  granted  { execute } for  pid=3136 comm=\"containerd\" name=\"loopback\" dev=\"overlay\" ino=68 scontext=system_u:system_r:pod_containerd_t:s0 tcontext=system_u:object_r:cni_plugin_t:s0 tclass=file\n; [   77.044528] audit: type=1400 audit(1741862615.446:4227): avc:  granted  { execute_no_trans } for  pid=3136 comm=\"containerd\" path=\"/opt/cni/bin/loopback\" dev=\"overlay\" ino=68 scontext=system_u:system_r:pod_containerd_t:s0 tcontext=system_u:object_r:cni_plugin_t:s0 tclass=file\n; [   77.045739] audit: type=1400 audit(1741862615.446:4227): avc:  granted  { execute } for  pid=3136 comm=\"loopback\" path=\"/opt/cni/bin/loopback\" dev=\"overlay\" ino=68 scontext=system_u:system_r:pod_containerd_t:s0 tcontext=system_u:object_r:cni_plugin_t:s0 tclass=file\n; This is being researched as a kernel bug since a process gains init_t context without the policy allowing it.\n(allow init_t cni_plugin_t (file (execute)))\n\n; Let ls and other path walking work, esp. for tests\n(allow any_p any_f (dir (search)))\n(allow any_p any_f (fs_classes (getattr)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/common/typeattributes.cil",
    "content": "(typeattribute common_f)\n(macro common_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset common_f ARG1)\n)\n\n(typeattribute protected_f)\n(macro protected_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset protected_f ARG1)\n)\n\n(typeattribute system_f)\n(macro system_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset system_f ARG1)\n)\n\n(typeattribute system_socket_f)\n(macro system_socket_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset system_socket_f ARG1)\n)\n\n(allow system_socket_f tmpfs_t (filesystem (associate)))\n\n(typeattribute common_device_f)\n(macro common_device_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset common_device_f ARG1)\n)\n\n(typeattribute protected_device_f)\n(macro protected_device_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset protected_device_f ARG1)\n)\n\n(typeattributeset common_device_f device_t)\n\n(typeattribute device_f)\n(typeattributeset device_f common_device_f)\n(typeattributeset device_f protected_device_f)\n\n(typeattribute any_f)\n(typeattributeset any_f filesystem_f)\n(typeattributeset any_f common_f)\n(typeattributeset any_f protected_f)\n(typeattributeset any_f system_f)\n(typeattributeset any_f system_socket_f)\n(typeattributeset any_f device_f)\n\n(typeattribute unconfined_f)\n(typeattributeset unconfined_f tmpfs_t)\n(typeattributeset unconfined_f common_f)\n(typeattributeset unconfined_f common_device_f)\n\n(typeattribute filesystem_f)\n(macro filesystem_f ((type ARG1))\n    (roletype object_r ARG1)\n    (typeattributeset filesystem_f ARG1)\n)\n\n(allow filesystem_f self (filesystem (associate)))\n(allow any_f fs_t (filesystem (associate)))\n(allow filesystem_f fs_t (filesystem (associate)))\n\n(typeattribute service_exec_f)\n\n(typeattribute service_p)\n; (process_t, exec_t)\n(macro service_p ((type process_label) (type executable_label))\n    (roletype system_r process_label)\n    (typeattributeset service_p process_label)\n    (typeattributeset service_exec_f executable_label)\n    (allow process_label executable_label (fs_classes (ro)))\n    (allow process_label executable_label (file (entrypoint execute execute_no_trans)))\n)\n\n(typeattribute system_container_p)\n(macro system_container_p ((type ARG1))\n    (roletype system_r ARG1)\n    (typeattributeset system_container_p ARG1)\n)\n\n(typeattribute pod_p)\n(macro pod_p ((type ARG1))\n    (roletype system_r ARG1)\n    (typeattributeset pod_p ARG1)\n)\n\n(typeattribute system_p)\n(typeattributeset system_p kernel_t)\n(typeattributeset system_p initramfs_t)\n(typeattributeset system_p init_t)\n(typeattributeset system_p service_p)\n\n(typeattribute any_p)\n(typeattributeset any_p system_p)\n(typeattributeset any_p system_container_p)\n(typeattributeset any_p pod_p)\n\n(typeattribute any_f_any_p)\n(typeattributeset any_f_any_p any_f)\n(typeattributeset any_f_any_p any_p)\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/immutable/classes.cil",
    "content": "(class security (\n    check_context\n    compute_av\n    compute_create\n    compute_member\n    compute_relabel\n    compute_user\n    load_policy\n    read_policy\n    setbool\n    setcheckreqprot\n    setenforce\n    setsecparam\n    validate_trans\n))\n(class filesystem (\n    associate\n    getattr\n    mount\n    quotaget\n    quotamod\n    relabelfrom\n    relabelto\n    remount\n    unmount\n    watch\n))\n\n(common file_common (\n    append\n    audit_access\n    create\n    execmod\n    execute\n    getattr\n    ioctl\n    link\n    lock\n    map\n    mounton\n    open\n    quotaon\n    read\n    relabelfrom\n    relabelto\n    rename\n    setattr\n    unlink\n    watch\n    watch_mount\n    watch_reads\n    watch_sb\n    watch_with_perm\n    write\n))\n(class file (entrypoint execute_no_trans))\n(classcommon file file_common)\n(class dir (add_name remove_name reparent rmdir search))\n(classcommon dir file_common)\n(class lnk_file ())\n(classcommon lnk_file file_common)\n(class chr_file ())\n(classcommon chr_file file_common)\n(class blk_file ())\n(classcommon blk_file file_common)\n(class sock_file ())\n(classcommon sock_file file_common)\n(class fifo_file ())\n(classcommon fifo_file file_common)\n\n(common socket_common (\n    accept\n    append\n    bind\n    connect\n    create\n    getattr\n    getopt\n    ioctl\n    listen\n    lock\n    map\n    name_bind\n    read\n    recvfrom\n    relabelfrom\n    relabelto\n    sendto\n    setattr\n    setopt\n    shutdown\n    write\n))\n(class socket ())\n(classcommon socket socket_common)\n(class tcp_socket (name_connect node_bind))\n(classcommon tcp_socket socket_common)\n(class udp_socket (node_bind))\n(classcommon udp_socket socket_common)\n(class rawip_socket (node_bind))\n(classcommon rawip_socket socket_common)\n(class packet_socket ())\n(classcommon packet_socket socket_common)\n(class key_socket ())\n(classcommon key_socket socket_common)\n(class unix_stream_socket (connectto))\n(classcommon unix_stream_socket socket_common)\n(class unix_dgram_socket ())\n(classcommon unix_dgram_socket socket_common)\n\n(class netif (egress ingress))\n\n(class process (\n    dyntransition\n    execheap\n    execmem\n    execstack\n    fork\n    getattr\n    getcap\n    getpgid\n    getrlimit\n    getsched\n    getsession\n    noatsecure\n    ptrace\n    rlimitinh\n    setcap\n    setcurrent\n    setexec\n    setfscreate\n    setkeycreate\n    setpgid\n    setrlimit\n    setsched\n    setsockcreate\n    share\n    sigchld\n    siginh\n    sigkill\n    signal\n    signull\n    sigstop\n    transition\n))\n(class system (\n    ipc_info\n    module_load\n    module_request\n    syslog_console\n    syslog_mod\n    syslog_read\n    firmware_load\n    kexec_image_load\n    kexec_initramfs_load\n))\n(class process2 (nnp_transition nosuid_transition))\n(class fd (use))\n(class node (recvfrom sendto))\n\n(class bpf (map_create map_read map_write prog_load prog_run))\n\n(common capability_common (\n    audit_control\n    audit_write\n    chown\n    dac_override\n    dac_read_search\n    fowner\n    fsetid\n    ipc_lock\n    ipc_owner\n    kill\n    lease\n    linux_immutable\n    mknod\n    net_admin\n    net_bind_service\n    net_broadcast\n    net_raw\n    setfcap\n    setgid\n    setpcap\n    setuid\n    sys_admin\n    sys_boot\n    sys_chroot\n    sys_module\n    sys_nice\n    sys_pacct\n    sys_ptrace\n    sys_rawio\n    sys_resource\n    sys_time\n    sys_tty_config\n))\n(class capability ())\n(class cap_userns ())\n(classcommon capability capability_common)\n(classcommon cap_userns capability_common)\n\n(common capability2_common (\n    audit_read\n    block_suspend\n    bpf\n    checkpoint_restore\n    mac_admin\n    mac_override\n    perfmon\n    syslog\n    wake_alarm\n))\n(class capability2 ())\n(class cap2_userns ())\n(classcommon capability2 capability2_common)\n(classcommon cap2_userns capability2_common)\n\n(class netlink_socket ())\n(classcommon netlink_socket socket_common)\n(class netlink_route_socket (nlmsg_read nlmsg_write))\n(classcommon netlink_route_socket socket_common)\n(class netlink_tcpdiag_socket (nlmsg_read nlmsg_write))\n(classcommon netlink_tcpdiag_socket socket_common)\n(class netlink_nflog_socket ())\n(classcommon netlink_nflog_socket socket_common)\n(class netlink_selinux_socket ())\n(classcommon netlink_selinux_socket socket_common)\n(class netlink_audit_socket (\n    nlmsg_read\n    nlmsg_readpriv\n    nlmsg_relay\n    nlmsg_tty_audit\n    nlmsg_write\n))\n(classcommon netlink_audit_socket socket_common)\n(class netlink_dnrt_socket ())\n(classcommon netlink_dnrt_socket socket_common)\n(class netlink_kobject_uevent_socket ())\n(classcommon netlink_kobject_uevent_socket socket_common)\n(class netlink_iscsi_socket ())\n(classcommon netlink_iscsi_socket socket_common)\n(class netlink_fib_lookup_socket ())\n(classcommon netlink_fib_lookup_socket socket_common)\n(class netlink_connector_socket ())\n(classcommon netlink_connector_socket socket_common)\n(class netlink_netfilter_socket ())\n(classcommon netlink_netfilter_socket socket_common)\n(class netlink_generic_socket ())\n(classcommon netlink_generic_socket socket_common)\n(class netlink_scsitransport_socket ())\n(classcommon netlink_scsitransport_socket socket_common)\n(class netlink_rdma_socket ())\n(classcommon netlink_rdma_socket socket_common)\n(class netlink_crypto_socket ())\n(classcommon netlink_crypto_socket socket_common)\n(class netlink_xfrm_socket (nlmsg_read nlmsg_write))\n(classcommon netlink_xfrm_socket socket_common)\n\n(class obsolete_netlink_firewall_socket (nlmsg_read nlmsg_write))\n(classcommon obsolete_netlink_firewall_socket socket_common)\n(class obsolete_netlink_ip6fw_socket (nlmsg_read nlmsg_write))\n(classcommon obsolete_netlink_ip6fw_socket socket_common)\n\n(class key (view read write search link setattr create))\n\n(common ipc_common (\n    associate\n    create\n    destroy\n    getattr\n    read\n    setattr\n    unix_read\n    unix_write\n    write\n))\n; Deprecated\n(class ipc ())\n(classcommon ipc ipc_common)\n(class sem ())\n(classcommon sem ipc_common)\n(class msgq (enqueue))\n(classcommon msgq ipc_common)\n(class msg (send receive))\n(classcommon msg ipc_common)\n(class shm (lock))\n(classcommon shm ipc_common)\n\n(class appletalk_socket ())\n(classcommon appletalk_socket socket_common)\n\n(class packet (send recv relabelto forward_in forward_out))\n(class association (sendto recvfrom setcontext polmatch))\n\n(class dccp_socket (node_bind name_connect))\n(classcommon dccp_socket socket_common)\n(class memprotect (mmap_zero))\n(class peer (recv))\n\n(class kernel_service (use_as_override create_files_as))\n(class tun_socket (attach_queue))\n(classcommon tun_socket socket_common)\n(class binder (impersonate call set_context_mgr transfer))\n\n(class infiniband_pkey (access))\n(class infiniband_endport (manage_subnet))\n\n(class sctp_socket (node_bind name_connect association))\n(classcommon sctp_socket socket_common)\n(class icmp_socket (node_bind))\n(classcommon icmp_socket socket_common)\n(class ax25_socket ())\n(classcommon ax25_socket socket_common)\n(class ipx_socket ())\n(classcommon ipx_socket socket_common)\n(class netrom_socket ())\n(classcommon netrom_socket socket_common)\n(class atmpvc_socket ())\n(classcommon atmpvc_socket socket_common)\n(class x25_socket ())\n(classcommon x25_socket socket_common)\n(class rose_socket ())\n(classcommon rose_socket socket_common)\n(class decnet_socket ())\n(classcommon decnet_socket socket_common)\n(class atmsvc_socket ())\n(classcommon atmsvc_socket socket_common)\n(class rds_socket ())\n(classcommon rds_socket socket_common)\n(class irda_socket ())\n(classcommon irda_socket socket_common)\n(class pppox_socket ())\n(classcommon pppox_socket socket_common)\n(class llc_socket ())\n(classcommon llc_socket socket_common)\n(class can_socket ())\n(classcommon can_socket socket_common)\n(class tipc_socket ())\n(classcommon tipc_socket socket_common)\n(class bluetooth_socket ())\n(classcommon bluetooth_socket socket_common)\n(class iucv_socket ())\n(classcommon iucv_socket socket_common)\n(class rxrpc_socket ())\n(classcommon rxrpc_socket socket_common)\n(class isdn_socket ())\n(classcommon isdn_socket socket_common)\n(class phonet_socket ())\n(classcommon phonet_socket socket_common)\n(class ieee802154_socket ())\n(classcommon ieee802154_socket socket_common)\n(class caif_socket ())\n(classcommon caif_socket socket_common)\n(class alg_socket ())\n(classcommon alg_socket socket_common)\n(class nfc_socket ())\n(classcommon nfc_socket socket_common)\n(class vsock_socket ())\n(classcommon vsock_socket socket_common)\n(class kcm_socket ())\n(classcommon kcm_socket socket_common)\n(class qipcrtr_socket ())\n(classcommon qipcrtr_socket socket_common)\n(class smc_socket ())\n(classcommon smc_socket socket_common)\n(class xdp_socket ())\n(classcommon xdp_socket socket_common)\n(class mctp_socket ())\n(classcommon mctp_socket socket_common)\n\n(class perf_event (open cpu kernel tracepoint read write))\n; Deprecated in 5.16, no longer checked by kernel\n(class lockdown (integrity confidentiality))\n(class anon_inode ())\n(classcommon anon_inode file_common)\n(class io_uring (override_creds sqpoll cmd))\n(class user_namespace (create))\n\n(classorder (\n    security\n    process\n    system\n    capability\n    filesystem\n    file\n    dir\n    fd\n    lnk_file\n    chr_file\n    blk_file\n    sock_file\n    fifo_file\n    socket\n    tcp_socket\n    udp_socket\n    rawip_socket\n    node\n    netif\n    netlink_socket\n    packet_socket\n    key_socket\n    unix_stream_socket\n    unix_dgram_socket\n    sem\n    msg\n    msgq\n    shm\n    ipc\n    netlink_route_socket\n    obsolete_netlink_firewall_socket\n    netlink_tcpdiag_socket\n    netlink_nflog_socket\n    netlink_xfrm_socket\n    netlink_selinux_socket\n    netlink_audit_socket\n    obsolete_netlink_ip6fw_socket\n    netlink_dnrt_socket\n    association\n    netlink_kobject_uevent_socket\n    appletalk_socket\n    packet\n    key\n    dccp_socket\n    memprotect\n    peer\n    capability2\n    kernel_service\n    tun_socket\n    binder\n    netlink_iscsi_socket\n    netlink_fib_lookup_socket\n    netlink_connector_socket\n    netlink_netfilter_socket\n    netlink_generic_socket\n    netlink_scsitransport_socket\n    netlink_rdma_socket\n    netlink_crypto_socket\n    infiniband_pkey\n    infiniband_endport\n    cap_userns\n    cap2_userns\n    sctp_socket\n    icmp_socket\n    ax25_socket\n    ipx_socket\n    netrom_socket\n    atmpvc_socket\n    x25_socket\n    rose_socket\n    decnet_socket\n    atmsvc_socket\n    rds_socket\n    irda_socket\n    pppox_socket\n    llc_socket\n    can_socket\n    tipc_socket\n    bluetooth_socket\n    iucv_socket\n    rxrpc_socket\n    isdn_socket\n    phonet_socket\n    ieee802154_socket\n    caif_socket\n    alg_socket\n    nfc_socket\n    vsock_socket\n    kcm_socket\n    qipcrtr_socket\n    smc_socket\n    process2\n    bpf\n    xdp_socket\n    mctp_socket\n    perf_event\n    lockdown\n    anon_inode\n    io_uring\n    user_namespace\n))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/immutable/fs.cil",
    "content": "(type devpts_t)\n(call filesystem_f (devpts_t))\n(fsuse trans devpts (system_u object_r devpts_t (systemLow systemLow)))\n\n(type tmpfs_t)\n(call filesystem_f (tmpfs_t))\n(fsuse trans tmpfs (system_u object_r tmpfs_t (systemLow systemLow)))\n(fsuse trans shm (system_u object_r tmpfs_t (systemLow systemLow)))\n(fsuse trans mqueue (system_u object_r tmpfs_t (systemLow systemLow)))\n\n(type ramfs_t)\n(call filesystem_f (ramfs_t))\n(fsuse trans ramfs (system_u object_r ramfs_t (systemLow systemLow)))\n\n(type hugetlbfs_t)\n(call filesystem_f (hugetlbfs_t))\n(fsuse trans hugetlbfs (system_u object_r hugetlbfs_t (systemLow systemLow)))\n\n(type rootfs_t)\n(call filesystem_f (rootfs_t))\n(genfscon rootfs \"/\" (system_u object_r rootfs_t (systemLow systemLow)))\n(filecon \"/\" any (system_u object_r rootfs_t (systemLow systemLow)))\n\n(type sysfs_t)\n(call filesystem_f (sysfs_t))\n(type sys_module_t)\n(call filesystem_f (sys_module_t))\n(allow sys_module_t sysfs_t (filesystem (associate)))\n\n(genfscon sysfs \"/\" (system_u object_r sysfs_t (systemLow systemLow)))\n(genfscon sysfs \"/module\" (system_u object_r sys_module_t (systemLow systemLow)))\n\n(type bpf_t)\n(call filesystem_f (bpf_t))\n(genfscon bpf \"/\" (system_u object_r bpf_t (systemLow systemLow)))\n\n(type debugfs_t)\n(call filesystem_f (debugfs_t))\n(genfscon debugfs \"/\" (system_u object_r debugfs_t (systemLow systemLow)))\n\n(type cgroup_t)\n(call filesystem_f (cgroup_t))\n(genfscon cgroup \"/\" (system_u object_r cgroup_t (systemLow systemLow)))\n(genfscon cgroup2 \"/\" (system_u object_r cgroup_t (systemLow systemLow)))\n\n(type selinuxfs_t)\n(call filesystem_f (selinuxfs_t))\n(genfscon selinuxfs \"/\" (system_u object_r selinuxfs_t (systemLow systemLow)))\n\n(type procfs_t)\n(call filesystem_f (procfs_t))\n(context procfs_t (system_u object_r procfs_t (systemLow systemLow)))\n(genfscon proc \"/\" procfs_t)\n(genfscon proc \"/sysvipc\" procfs_t)\n\n(type proc_cmdline_t)\n(call filesystem_f (proc_cmdline_t))\n(genfscon proc \"/cmdline\" (system_u object_r proc_cmdline_t (systemLow systemLow)))\n\n(type proc_sysctl_t)\n(call filesystem_f (proc_sysctl_t))\n(genfscon proc \"/sys\" (system_u object_r proc_sysctl_t (systemLow systemLow)))\n; It matches /sys, yet should not have the same context\n(genfscon proc \"/sysrq-trigger\" procfs_t)\n\n(type securityfs_t)\n(call filesystem_f (securityfs_t))\n(genfscon securityfs \"/\" (system_u object_r securityfs_t (systemLow systemLow)))\n\n(type tracefs_t)\n(call filesystem_f (tracefs_t))\n(genfscon tracefs \"/\" (system_u object_r tracefs_t (systemLow systemLow)))\n\n(type efivarfs_t)\n(call filesystem_f (efivarfs_t))\n(genfscon efivarfs \"/\" (system_u object_r efivarfs_t (systemLow systemLow)))\n\n(type anon_inodefs_t)\n(call filesystem_f (anon_inodefs_t))\n(genfscon anon_inodefs \"/\" (system_u object_r anon_inodefs_t (systemLow systemLow)))\n\n(type binfmt_misc_t)\n(call filesystem_f (binfmt_misc_t))\n(genfscon binfmt_misc \"/\" (system_u object_r binfmt_misc_t (systemLow systemLow)))\n\n(type bdev_t)\n(call filesystem_f (bdev_t))\n(genfscon bdev \"/\" (system_u object_r bdev_t (systemLow systemLow)))\n\n(type autofs_t)\n(call filesystem_f (autofs_t))\n(context autofs_t (system_u object_r autofs_t (systemLow systemLow)))\n(genfscon autofs \"/\" autofs_t)\n(genfscon automount \"/\" autofs_t)\n\n(type fuse_fs_t)\n(call filesystem_f (fuse_fs_t))\n(context fuse_fs_t (system_u object_r fuse_fs_t (systemLow systemLow)))\n(genfscon fuse \"/\" fuse_fs_t)\n(genfscon fuseblk \"/\" fuse_fs_t)\n(genfscon fusectl \"/\" fuse_fs_t)\n\n(type foreign_fs_t)\n(call filesystem_f (foreign_fs_t))\n(context foreign_fs_t (system_u object_r foreign_fs_t (systemLow systemLow)))\n(genfscon fat \"/\" foreign_fs_t)\n(genfscon hfs \"/\" foreign_fs_t)\n(genfscon hfsplus \"/\" foreign_fs_t)\n(genfscon msdos \"/\" foreign_fs_t)\n(genfscon ntfs \"/\" foreign_fs_t)\n(genfscon ntfs-3g \"/\" foreign_fs_t)\n(genfscon vfat \"/\" foreign_fs_t)\n\n(type iso_fs_t)\n(call filesystem_f (iso_fs_t))\n(context iso_fs_t (system_u object_r iso_fs_t (systemLow systemLow)))\n(genfscon iso9660 \"/\" iso_fs_t)\n(genfscon udf \"/\" iso_fs_t)\n\n(type sysv_fs_t)\n(call filesystem_f (sysv_fs_t))\n(context sysv_fs_t (system_u object_r sysv_fs_t (systemLow systemLow)))\n(genfscon sysv \"/\" sysv_fs_t)\n(genfscon v7 \"/\" sysv_fs_t)\n\n(type network_fs_t)\n(call filesystem_f (network_fs_t))\n(context network_fs_t (system_u object_r network_fs_t (systemLow systemLow)))\n(genfscon afs \"/\" network_fs_t)\n(genfscon cifs \"/\" network_fs_t)\n(genfscon coda \"/\" network_fs_t)\n(genfscon dazukofs \"/\" network_fs_t)\n(genfscon lustre \"/\" network_fs_t)\n(genfscon ncpfs \"/\" network_fs_t)\n(genfscon nfs \"/\" network_fs_t)\n(genfscon nfs4 \"/\" network_fs_t)\n(genfscon panfs \"/\" network_fs_t)\n(genfscon smbfs \"/\" network_fs_t)\n\n(type vmblock_fs_t)\n(call filesystem_f (vmblock_fs_t))\n(context vmblock_fs_t (system_u object_r vmblock_fs_t (systemLow systemLow)))\n(genfscon vboxsf \"/\" vmblock_fs_t)\n(genfscon virtiofs \"/\" vmblock_fs_t)\n(genfscon vmblock \"/\" vmblock_fs_t)\n(genfscon vmhgfs \"/\" vmblock_fs_t)\n(genfscon xenfs \"/\" vmblock_fs_t)\n\n(type configfs_t)\n(call filesystem_f (configfs_t))\n(genfscon configfs \"/\" (system_u object_r configfs_t (systemLow systemLow)))\n\n(type futexfs_t)\n(call filesystem_f (futexfs_t))\n(genfscon futexfs \"/\" (system_u object_r futexfs_t (systemLow systemLow)))\n\n(type infinibandeventfs_t)\n(call filesystem_f (infinibandeventfs_t))\n(genfscon infinibandeventfs \"/\" (system_u object_r infinibandeventfs_t (systemLow systemLow)))\n\n(type inotifyfs_t)\n(call filesystem_f (inotifyfs_t))\n(genfscon inotifyfs \"/\" (system_u object_r inotifyfs_t (systemLow systemLow)))\n\n(type nfsd_t)\n(call filesystem_f (nfsd_t))\n(genfscon nfsd \"/\" (system_u object_r nfsd_t (systemLow systemLow)))\n\n(type nsfs_t)\n(call filesystem_f (nsfs_t))\n(genfscon nsfs \"/\" (system_u object_r nsfs_t (systemLow systemLow)))\n\n(type pstore_t)\n(call filesystem_f (pstore_t))\n(genfscon pstore \"/\" (system_u object_r pstore_t (systemLow systemLow)))\n\n(type rpc_pipefs_t)\n(call filesystem_f (rpc_pipefs_t))\n(genfscon rpc_pipefs \"/\" (system_u object_r rpc_pipefs_t (systemLow systemLow)))\n\n(type usbfs_t)\n(call filesystem_f (usbfs_t))\n(context usbfs_t (system_u object_r usbfs_t (systemLow systemLow)))\n(genfscon functionfs \"/\" usbfs_t)\n(genfscon gadgetfs \"/\" usbfs_t)\n(genfscon usbdevfs \"/\" usbfs_t)\n(genfscon usbfs \"/\" usbfs_t)\n\n(fsuse task sockfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse task pipefs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse task eventpollfs (system_u object_r fs_t (systemLow systemLow)))\n\n(fsuse xattr zfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr xfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr virtiofs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr ubifs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr squashfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr overlay (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr lustre (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr jfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr jffs2 (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr gpfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr gfs2 (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr gfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr f2fs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr ext4dev (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr ext4 (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr ext3 (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr ext2 (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr erofs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr encfs (system_u object_r fs_t (systemLow systemLow)))\n(fsuse xattr btrfs (system_u object_r fs_t (systemLow systemLow)))\n\n(type device_t)\n(call filesystem_f (device_t))\n(fsuse trans devtmpfs (system_u object_r device_t (systemLow systemLow)))\n\n; files on pseudo-FS's\n(allow any_p procfs_t (filesystem (associate)))\n(allow device_f device_t (filesystem (associate)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/immutable/preamble.cil",
    "content": "(sensitivity s0)\n(sensitivityorder (s0))\n(level systemLow (s0))\n(handleunknown deny)\n(mls true)\n(policycap open_perms)\n(policycap extended_socket_class)\n(policycap cgroup_seclabel)\n(policycap nnp_nosuid_transition)\n(policycap ioctl_skip_cloexec)\n(policycap userspace_initial_context)\n(policycap genfs_seclabel_symlinks)\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/immutable/roles.cil",
    "content": "(role object_r)\n(type object_r)\n(roletype object_r object_r)\n\n(role system_r)\n(type system_r)\n(roletype system_r system_r)\n\n(user system_u)\n(userrange system_u (systemLow systemLow))\n(userlevel system_u systemLow)\n(userrole system_u object_r)\n(userrole system_u system_r)\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/immutable/sids.cil",
    "content": "(type null_device_t)\n(call common_device_f (null_device_t))\n(sid devnull)\n(sidcontext devnull (system_u object_r null_device_t (systemLow systemLow)))\n\n(sid igmp_packet)\n(sidcontext igmp_packet (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid icmp_socket)\n(sidcontext icmp_socket (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid tcp_socket)\n(sidcontext tcp_socket (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_modprobe)\n(sidcontext sysctl_modprobe (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl)\n(sidcontext sysctl (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_fs)\n(sidcontext sysctl_fs (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_kernel)\n(sidcontext sysctl_kernel (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_net)\n(sidcontext sysctl_net (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_net_unix)\n(sidcontext sysctl_net_unix (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_vm)\n(sidcontext sysctl_vm (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid sysctl_dev)\n(sidcontext sysctl_dev (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid kmod)\n(sidcontext kmod (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid policy)\n(sidcontext policy (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid scmp_packet)\n(sidcontext scmp_packet (system_u object_r unlabeled_t (systemLow systemLow)))\n\n(type unlabeled_t)\n(call system_f (unlabeled_t))\n(type fs_t)\n(call filesystem_f (fs_t))\n(allow unlabeled_t fs_t (filesystem (associate)))\n\n(type node_t)\n(roletype object_r node_t)\n(sid node)\n(sidcontext node (system_u object_r node_t (systemLow systemLow)))\n\n(type netlabel_peer_t)\n(roletype object_r netlabel_peer_t)\n(sid netmsg)\n(sidcontext netmsg (system_u object_r netlabel_peer_t (systemLow systemLow)))\n\n(type netif_t)\n(roletype object_r netif_t)\n(sid netif)\n(sidcontext netif (system_u object_r netif_t (systemLow systemLow)))\n\n(type port_t)\n(roletype object_r port_t)\n(sid port)\n(sidcontext port (system_u object_r port_t (systemLow systemLow)))\n\n(sid any_socket)\n(sidcontext any_socket (system_u object_r unlabeled_t (systemLow systemLow)))\n\n(type initramfs_t)\n(roletype system_r initramfs_t)\n(sid init)\n(sidcontext init (system_u system_r initramfs_t (systemLow systemLow)))\n\n(sid file_labels)\n(sidcontext file_labels (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid file)\n(sidcontext file (system_u object_r unlabeled_t (systemLow systemLow)))\n(sid fs)\n(sidcontext fs (system_u object_r fs_t (systemLow systemLow)))\n\n(sid unlabeled)\n(sidcontext unlabeled (system_u object_r unlabeled_t (systemLow systemLow)))\n\n(type security_t)\n(roletype object_r security_t)\n(sid security)\n(sidcontext security (system_u object_r security_t (systemLow systemLow)))\n\n(type kernel_t)\n(roletype system_r kernel_t)\n(sid kernel)\n(sidcontext kernel (system_u system_r kernel_t (systemLow systemLow)))\n\n(sidorder (\n    kernel\n    security\n    unlabeled\n    fs\n    file\n    file_labels\n    init\n    any_socket\n    port\n    netif\n    netmsg\n    node\n    igmp_packet\n    icmp_socket\n    tcp_socket\n    sysctl_modprobe\n    sysctl\n    sysctl_fs\n    sysctl_kernel\n    sysctl_net\n    sysctl_net_unix\n    sysctl_vm\n    sysctl_dev\n    kmod\n    policy\n    scmp_packet\n    devnull\n))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/cri.cil",
    "content": "; Pod (CRI) containerd\n(type pod_containerd_t)\n(call service_p (pod_containerd_t containerd_exec_t))\n\n(type pod_containerd_socket_t)\n(call system_socket_f (pod_containerd_socket_t))\n; Shim and client sockets\n(allow pod_containerd_t run_t (fs_classes (rw)))\n(typeattribute not_pod_containerd_socket_t)\n(typeattributeset not_pod_containerd_socket_t (not pod_containerd_socket_t))\n(typetransition pod_containerd_t not_pod_containerd_socket_t sock_file pod_containerd_socket_t)\n\n(type pod_containerd_run_t)\n(call system_f (pod_containerd_run_t))\n(allow pod_containerd_run_t tmpfs_t (filesystem (associate)))\n\n(typetransition pod_containerd_t run_t file pod_containerd_run_t)\n(typetransition pod_containerd_t run_t dir pod_containerd_run_t)\n(typetransition pod_containerd_t run_t lnk_file pod_containerd_run_t)\n(typetransition pod_containerd_t run_t chr_file pod_containerd_run_t)\n(typetransition pod_containerd_t run_t blk_file pod_containerd_run_t)\n(typetransition pod_containerd_t run_t fifo_file pod_containerd_run_t)\n\n(allow pod_containerd_t pod_containerd_run_t (fs_classes (rw)))\n\n; Transition to pod contexts\n(allow pod_containerd_t pod_p (process2 (nnp_transition nosuid_transition)))\n(allow pod_containerd_t pod_p (process (transition)))\n\n; Containerd storage\n(allow pod_containerd_t containerd_state_t (fs_classes (rw)))\n(allow pod_containerd_t containerd_state_t (file (entrypoint execute execute_no_trans)))\n(allow pod_containerd_t containerd_state_t (fs_classes (relabelto relabelfrom)))\n\n; Manage procfs & processes\n(allow pod_containerd_t pod_p (fs_classes (rw)))\n(allow pod_containerd_t pod_p (process_classes (full)))\n(allow pod_p pod_containerd_t (fd (use)))\n(allow pod_p pod_containerd_t (fifo_file (append getattr ioctl map open read rename setattr watch write)))\n\n; CNI\n(allow pod_containerd_t cni_plugin_t (file (execute_no_trans execute)))\n(allow pod_containerd_t cni_plugin_t (fs_classes (ro)))\n; iptables used by CNI\n(allow pod_containerd_t bin_exec_t (file (execute_no_trans execute)))\n(allow pod_containerd_t bin_exec_t (fs_classes (ro)))\n; (allow pod_p cni_conf_t (fs_classes (rw)))\n(allow pod_containerd_t cni_state_t (fs_classes (rw)))\n\n; Logs\n(allow pod_containerd_t pods_log_t (fs_classes (rw)))\n\n(allow pod_containerd_t pod_p (key (view read write search link setattr create)))\n\n; Shim socket\n(allow pod_containerd_t pod_containerd_socket_t (fs_classes (rw)))\n\n; System containers, not k8s pods\n\n(type etcd_t)\n(call pod_p (etcd_t))\n; FIXME: insecure as anyone with access to the pod containerd may obtain this domain\n(allow etcd_t containerd_state_t (file (entrypoint)))\n\n(type etcd_pki_t)\n(call protected_f (etcd_pki_t))\n(allow etcd_pki_t tmpfs_t (filesystem (associate)))\n(allow etcd_t etcd_pki_t (fs_classes (ro)))\n\n(type etcd_data_t)\n(call protected_f (etcd_data_t))\n(allow etcd_t etcd_data_t (fs_classes (rw)))\n\n(type cni_conf_t)\n(call filesystem_f (cni_conf_t))\n(filecon \"/etc/cni(/.*)?\" any (system_u object_r cni_conf_t (systemLow systemLow)))\n\n(type cni_plugin_t)\n(call filesystem_f (cni_plugin_t))\n(filecon \"/opt/cni(/.*)?\" any (system_u object_r cni_plugin_t (systemLow systemLow)))\n\n(type containerd_plugin_t)\n(call filesystem_f (containerd_plugin_t))\n(filecon \"/opt/containerd(/.*)?\" any (system_u object_r containerd_plugin_t (systemLow systemLow)))\n\n(type containerd_state_t)\n(call common_f (containerd_state_t))\n\n(type kube_apiserver_config_t)\n(call protected_f (kube_apiserver_config_t))\n(allow kube_apiserver_config_t tmpfs_t (filesystem (associate)))\n(type kube_scheduler_config_t)\n(call protected_f (kube_scheduler_config_t))\n(allow kube_scheduler_config_t tmpfs_t (filesystem (associate)))\n(type kube_apiserver_secret_t)\n(call protected_f (kube_apiserver_secret_t))\n(allow kube_apiserver_secret_t tmpfs_t (filesystem (associate)))\n(type kube_controller_manager_secret_t)\n(call protected_f (kube_controller_manager_secret_t))\n(allow kube_controller_manager_secret_t tmpfs_t (filesystem (associate)))\n(type kube_scheduler_secret_t)\n(call protected_f (kube_scheduler_secret_t))\n(allow kube_scheduler_secret_t tmpfs_t (filesystem (associate)))\n\n(typeattribute kube_secret_f)\n(typeattributeset kube_secret_f kube_apiserver_config_t)\n(typeattributeset kube_secret_f kube_scheduler_config_t)\n(typeattributeset kube_secret_f kube_apiserver_secret_t)\n(typeattributeset kube_secret_f kube_controller_manager_secret_t)\n(typeattributeset kube_secret_f kube_scheduler_secret_t)\n\n; Allow kubernetes pods to access their configuration and secrets\n; FIXME: insecure as anyone with access to the pod containerd may obtain these domains\n; TODO: label static pods with the correct domains\n(allow pod_p kube_secret_f (fs_classes (ro)))\n\n(type var_log_t)\n(call protected_f (var_log_t))\n(type audit_log_t)\n(call protected_f (audit_log_t))\n(type containers_log_t)\n(call protected_f (containers_log_t))\n(type pods_log_t)\n(call protected_f (pods_log_t))\n(type var_lock_t)\n(call protected_f (var_lock_t))\n(allow var_lock_t tmpfs_t (filesystem (associate)))\n(type seccomp_profile_t)\n(call protected_f (seccomp_profile_t))\n(type kube_log_t)\n(call protected_f (kube_log_t))\n\n(typeattribute log_f)\n(typeattributeset log_f var_log_t)\n(typeattributeset log_f audit_log_t)\n(typeattributeset log_f containers_log_t)\n(typeattributeset log_f pods_log_t)\n(typeattributeset log_f var_lock_t)\n(typeattributeset log_f seccomp_profile_t)\n(typeattributeset log_f kube_log_t)\n\n; FIXME: insecure as anyone with access to the pod containerd may obtain these domains\n; TODO: label static pods with the correct domains\n(allow pod_p log_f (fs_classes (rw)))\n\n(type cni_state_t)\n(call protected_f (cni_state_t))\n\n; All pods\n\n; local-path-provisioner\n(allow pod_containerd_t ephemeral_t (fs_classes (rw)))\n(allow pod_p ephemeral_t (fs_classes (rw)))\n\n; userns mode\n; https://github.com/containerd/containerd/blob/9b552d441582d71b7fd322c0b9f2c7c23b26b729/pkg/sys/unshare_linux.go#L59\n; https://github.com/containerd/containerd/blob/9b552d441582d71b7fd322c0b9f2c7c23b26b729/core/mount/mount_idmapped_utils_linux.go#L51\n(allow pod_containerd_t self (process (ptrace)))\n(allow pod_containerd_t self (user_namespace (create)))\n\n; Manage pseudo-terminals for containers, Kubernetes Conformance needs this\n(allow pod_containerd_t devpts_t (fs_classes (rw)))\n(allow pod_p devpts_t (fs_classes (rw)))\n\n; ; cilium\n; (allow pod_containerd_t pod_p (unix_stream_socket (connectto)))\n\n; pkg/flannel\n(allow pod_p cni_conf_t (fs_classes (rw)))\n\n; Common rules for containerd accessing system\n(typeattributeset containerd_p pod_containerd_t)\n\n(type pod_t)\n(call pod_p (pod_t))\n(typeattribute not_containerd_exec_t)\n(typeattributeset not_containerd_exec_t (not containerd_exec_t))\n(typetransition pod_containerd_t containerd_state_t process pod_t)\n(allow pod_p containerd_state_t (fs_classes (rw)))\n(allow pod_p containerd_state_t (file (entrypoint execute execute_no_trans)))\n\n; ; allow configuring CNI\n; (allow pod_p cni_conf_t (fs_classes (rw)))\n\n; ; CNI plugins access netns\n; (allow pod_p nsfs_t (fs_classes (rw)))\n\n; Flannel calls modprobe\n(allow pod_p module_t (fs_classes (ro)))\n\n; emptyDir volumes, used e.g. by hydrophone cts\n; TODO: label\n(allow pod_p kubelet_state_t (fs_classes (rw)))\n\n; getattr, unmount called by containers and should be guarded by their mount namespaces\n(allow pod_p fs_t (filesystem (\n    ; associate\n    getattr\n    mount\n    quotaget\n    quotamod\n    ; relabelfrom\n    ; relabelto\n    remount\n    unmount\n    watch\n)))\n\n; Calico and basically any CNI installing plugins\n(allow pod_t cni_plugin_t (fs_classes (rw)))\n; `install` also seems to test the plugin\n(allow pod_t cni_plugin_t (file (execute execute_no_trans)))\n\n; TinK is an example of what needs this. Docker in a pod will also require this.\n(allow pod_p cgroup_t (fs_classes (rw)))\n(allow pod_p nsfs_t (fs_classes (ro)))\n(allow pod_p self (key (all)))\n(allow pod_p self (capability2 (syslog)))\n(allow pod_p procfs_t (filesystem (mount remount unmount)))\n(allow pod_p kernel_t (system (syslog_read)))\n; Mainly ephemeral, but basically run anything without transitioning\n(allow pod_p any_f (file (execute execute_no_trans)))\n; /sys/firmware\n(allow pod_p sysfs_t (filesystem (mount remount unmount)))\n(allow pod_p sysfs_t (fs_classes (mounton)))\n; TinK\n(allow pod_p sysfs_t (filesystem (mount remount unmount)))\n(allow pod_p nsfs_t (filesystem (mount remount unmount)))\n(allow pod_p devpts_t (filesystem (mount remount unmount)))\n; /proc/bus\n(allow pod_p procfs_t (filesystem (mount remount unmount)))\n(allow pod_p procfs_t (fs_classes (mounton)))\n; module params (used e.g. by containerd)\n(allow pod_p sys_module_t (fs_classes (ro)))\n\n; TinK\n; [  110.873621] audit: type=1400 audit(1742647858.928:213): avc:  denied  { relabelfrom } for  pid=4732 comm=\"containerd\" name=\"etc\" dev=\"vda4\" ino=122484 scontext=system_u:system_r:pod_t:s0 tcontext=system_u:object_r:ephemeral_t:s0 tclass=dir permissive=1\n; [  110.875762] audit: type=1400 audit(1742647858.928:213): avc:  denied  { relabelto } for  pid=4732 comm=\"containerd\" name=\"etc\" dev=\"vda4\" ino=122484 scontext=system_u:system_r:pod_t:s0 tcontext=system_u:object_r:ephemeral_t:s0 tclass=dir permissive=1\n(allow pod_p ephemeral_t (fs_classes (relabelfrom relabelto)))\n\n; CRI containerd should talk machined API to call machine.ImageService/Verify API\n(allow pod_containerd_t machine_socket_t (fs_classes (rw)))\n(allow pod_containerd_t init_t (unix_stream_socket (connectto)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/dashboard.cil",
    "content": "(type dashboard_t)\n(call service_p (dashboard_t init_exec_t))\n\n; TTY\n(allow dashboard_t device_t (fs_classes (rw)))\n; machine ID and similar\n(allow dashboard_t etc_t (fs_classes (ro)))\n\n; socket\n(allow dashboard_t machine_socket_t (fs_classes (rw)))\n(allow dashboard_t init_t (unix_stream_socket (connectto)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/kubelet.cil",
    "content": "(type kubelet_t)\n(call pod_p (kubelet_t))\n; FIXME: insecure as anyone with access to the pod containerd may obtain this domain\n(allow kubelet_t containerd_state_t (file (entrypoint execute execute_no_trans)))\n\n(type k8s_conf_t)\n(call system_f (k8s_conf_t))\n(filecon \"/etc/kubernetes(/.*)?\" any (system_u object_r k8s_conf_t (systemLow systemLow)))\n\n(type k8s_plugin_t)\n(call system_f (k8s_plugin_t))\n(filecon \"/usr/libexec/kubernetes(/.*)?\" any (system_u object_r k8s_plugin_t (systemLow systemLow)))\n\n(type k8s_credentialproviders_t)\n(call system_f (k8s_credentialproviders_t))\n(filecon \"/usr/local/lib/kubelet/credentialproviders(/.*)?\" any (system_u object_r k8s_credentialproviders_t (systemLow systemLow)))\n\n(type kubelet_state_t)\n(call system_f (kubelet_state_t))\n(allow init_t kubelet_state_t (fs_classes (rw)))\n(allow pod_containerd_t kubelet_state_t (fs_classes (rw)))\n\n; FIXME: insecure as anyone with access to the pod containerd may obtain this domain\n; TODO: Secure kubelet launch labeling\n\n; Manage processes & cgroups\n(allow kubelet_t cgroup_t (fs_classes (rw)))\n(allow kubelet_t any_p (fs_classes (ro)))\n\n; D-Bus for notifying kubelet of system power events\n(allow kubelet_t dbus_client_socket_t (fs_classes (rw)))\n\n; Kubelet reads many attrs, handles mounts\n(allow kubelet_t fs_t (filesystem (getattr remount)))\n(allow kubelet_t any_f (fs_classes (getattr)))\n\n; Config and state access\n(allow kubelet_t etc_t (fs_classes (ro)))\n(allow kubelet_t k8s_conf_t (fs_classes (rw)))\n(allow kubelet_t kubelet_state_t (fs_classes (rw)))\n\n; Some mount/umount calls, xtables lock\n; TODO: label more precisely?\n(allow kubelet_t run_t (fs_classes (rw)))\n\n; Communication with init via pipes and sockets\n(allow kubelet_t init_t (fd (use)))\n(allow kubelet_t init_t (fifo_file (write)))\n(allow kubelet_t init_t (unix_stream_socket (connectto)))\n\n; Run pods\n(allow kubelet_t pod_containerd_socket_t (fs_classes (rw)))\n(allow kubelet_t pod_containerd_t (unix_stream_socket (connectto)))\n\n; Miscelaneous admin permissions\n(allow kubelet_t securityfs_t (fs_classes (ro)))\n(allow kubelet_t self (capability2 (syslog)))\n(allow kubelet_t kernel_t (system (syslog_read)))\n\n; Manage system configuration\n(allow kubelet_t sysfs_t (fs_classes (rw)))\n\n; CNI config, /etc/hosts written by kubelet\n(allow pod_p kubelet_state_t (fs_classes (ro)))\n\n(allow kubelet_t k8s_plugin_t (fs_classes (rw)))\n(allow kubelet_t k8s_plugin_t (file (entrypoint execute execute_no_trans)))\n\n; kubelet sends sigkill to pod processes\n(allow kubelet_t pod_p (process_classes (signal)))\n\n; ; Used when Mayastor/OpenEBS is enabled\n; (allow kubelet_t hugetlbfs_t (fs_classes (rw)))\n\n; ; /registration/rook-ceph.cephfs.csi.ceph.com-reg.sock and similar when using Rook-Ceph\n; (allow kubelet_t pod_p (unix_stream_socket (connectto)))\n\n; local-path-provisioner\n(allow kubelet_t ephemeral_t (fs_classes (rw)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/machined.cil",
    "content": "(type init_exec_t)\n(call system_f (init_exec_t))\n(context init_exec_t (system_u object_r init_exec_t (systemLow systemLow)))\n(filecon \"/usr/bin/init\" file init_exec_t)\n(filecon \"/usr/bin/poweroff\" any init_exec_t)\n(filecon \"/usr/bin/shutdown\" any init_exec_t)\n(filecon \"/usr/bin/dashboard\" any init_exec_t)\n\n(type init_t)\n(roletype system_r init_t)\n(allow init_t init_exec_t (file (execute entrypoint)))\n\n; System daemon sockets\n(type machine_socket_t)\n(call system_socket_f (machine_socket_t))\n(type dbus_service_socket_t)\n(call system_socket_f (dbus_service_socket_t))\n(type dbus_client_socket_t)\n(call system_socket_f (dbus_client_socket_t))\n\n(allow init_t service_p (process (transition)))\n; Manage processes\n(allow init_t any_p (fs_classes (rw)))\n(allow init_t any_p (process_classes (full)))\n(allow init_t service_exec_f (file (execute)))\n(allow init_t service_exec_f (fs_classes (ro)))\n(allow init_t service_p (key (view read write search link setattr create)))\n\n; Libraries must also pass the exceutable check to be used\n; Allow their use by all host services\n(type lib_t)\n(call system_f (lib_t))\n(context lib_t (system_u object_r lib_t (systemLow systemLow)))\n(filecon \"/usr/lib(/.*)?\" any lib_t)\n(filecon \"/usr/lib64\" any lib_t)\n(filecon \"/lib\" any lib_t)\n(filecon \"/lib64\" any lib_t)\n(allow system_p lib_t (file (execute)))\n(allow system_p lib_t (fs_classes (ro)))\n\n; Should not occur unless misconfigured by machined\n(type unconfined_service_t)\n(roletype system_r unconfined_service_t)\n(typeattributeset service_p unconfined_service_t)\n\n(type bin_exec_t)\n(call system_f (bin_exec_t))\n(context bin_exec_t (system_u object_r bin_exec_t (systemLow systemLow)))\n(filecon \"/usr/bin(/.*)?\" any bin_exec_t)\n(filecon \"/usr/sbin\" any bin_exec_t)\n(filecon \"/bin\" any bin_exec_t)\n(filecon \"/sbin\" any bin_exec_t)\n; Typically machined executes LVM, cryptsetup and similar utilities\n; They are short-running, come from the rootfs and do not accept user input, so can be started in init_t domain\n(allow init_t bin_exec_t (file (execute execute_no_trans)))\n(allow init_t bin_exec_t (fs_classes (ro)))\n\n; Access kernel module parameters\n(allow init_t sys_module_t (fs_classes (rw)))\n\n; Configure kubelet\n(allow init_t kubelet_state_t (fs_classes (rw)))\n\n(allow udev_t device_f (fs_classes (rw)))\n\n; Access containerd sockets for running containers\n(allow init_t sys_containerd_socket_t (sock_file (write)))\n(allow init_t sys_containerd_t (unix_stream_socket (connectto)))\n(allow init_t pod_containerd_socket_t (sock_file (write)))\n(allow init_t pod_containerd_t (unix_stream_socket (connectto)))\n\n; Allow access to any file for machined, for ls\n(allow init_t any_f (fs_classes (rw)))\n\n; /dev/console\n(allow init_t kernel_t (system (syslog_console syslog_mod syslog_read)))\n(allow init_t self (capability2 (syslog)))\n(allow init_t kernel_t (fd (use)))\n\n; reboot & kexec\n(allow init_t self (capability (sys_boot)))\n(allow init_t tmpfs_t (system (kexec_image_load kexec_initramfs_load)))\n\n; labeling FS\n(allow init_t any_f (fs_classes (relabelfrom relabelto)))\n\n; rootfs.sqsh\n(allow kernel_t rootfs_t (file (read)))\n\n; initramfs init before switching root\n(allow initramfs_t device_t (fs_classes (rw)))\n(allow initramfs_t rootfs_t (fs_classes (ro)))\n(allow initramfs_t self (process_classes (full)))\n(allow kernel_t initramfs_t (fd (use)))\n; Make machined go into proper context\n(allow initramfs_t bin_exec_t (fs_classes (ro))) ; Find init\n(allow initramfs_t init_exec_t (fs_classes (ro)))\n(allow initramfs_t init_exec_t (file (execute)))\n(typetransition initramfs_t init_exec_t process init_t)\n(allow initramfs_t init_t (process_classes (full)))\n(allow init_t initramfs_t (fd (use)))\n\n; Direct child processes\n(allow system_p init_t (fd (use)))\n(allow system_p init_t (fifo_file (append getattr ioctl map open read rename setattr watch write)))\n\n; cryptsetup\n(allow init_t self (sem (associate create destroy getattr read setattr unix_read unix_write write)))\n(allow init_t kernel_t (key (search)))\n(allow init_t self (key (all)))\n(allow init_t kernel_t (system (ipc_info)))\n\n; Modules loaded via machined\n(allow init_t module_t (system (module_load)))\n(allow init_t self (capability (sys_module)))\n\n(allow init_t apid_t (unix_stream_socket (connectto)))\n; CNI\n(allow init_t pod_containerd_t (fd (use)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/selinux.cil",
    "content": "(allow initramfs_t security_t (security (setbool setsecparam)))\n(allow init_t security_t (security (setbool setsecparam)))\n; Policy is loaded by initramfs init and mustn't be modified\n; The only way to set mode to permissive is setting enforcing=0 in kernel cmdline\n(neverallow any_p security_t (security (load_policy setenforce)))\n(allow any_p security_t (security (\n    check_context\n    compute_av\n    compute_create\n    compute_member\n    compute_relabel\n    compute_user\n    read_policy\n    setcheckreqprot\n    validate_trans\n)))\n(allow any_p selinuxfs_t (fs_classes (ro)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/system-containerd.cil",
    "content": "(type containerd_exec_t)\n(call system_f (containerd_exec_t))\n(context containerd_exec_t (system_u object_r containerd_exec_t (systemLow systemLow)))\n(filecon \"/usr/bin/containerd\" any containerd_exec_t)\n(filecon \"/usr/bin/containerd-shim-runc-v2\" any containerd_exec_t)\n(filecon \"/usr/bin/runc\" any containerd_exec_t)\n\n; System containerd\n(type sys_containerd_t)\n(call service_p (sys_containerd_t containerd_exec_t))\n\n(type sys_containerd_socket_t)\n(call system_socket_f (sys_containerd_socket_t))\n; Shim sockets\n(typetransition sys_containerd_t run_t sock_file sys_containerd_socket_t)\n; Client socket\n(typetransition sys_containerd_t system_t sock_file sys_containerd_socket_t)\n\n(type sys_containerd_run_t)\n(call system_f (sys_containerd_run_t))\n(allow sys_containerd_run_t tmpfs_t (filesystem (associate)))\n\n(typetransition sys_containerd_t run_t file sys_containerd_run_t)\n(typetransition sys_containerd_t run_t dir sys_containerd_run_t)\n(typetransition sys_containerd_t run_t lnk_file sys_containerd_run_t)\n(typetransition sys_containerd_t run_t chr_file sys_containerd_run_t)\n(typetransition sys_containerd_t run_t blk_file sys_containerd_run_t)\n(typetransition sys_containerd_t run_t fifo_file sys_containerd_run_t)\n\n(allow sys_containerd_t system_t (fs_classes (rw)))\n(allow sys_containerd_t system_var_t (fs_classes (rw)))\n; failed to create task: \\\"apid\\\": failed to create shim task: OCI runtime create failed: unable to retrieve\n; OCI runtime error (open /system/run/containerd/io.containerd.runtime.v2.task/system/apid/log.json:\n; no such file or directory): runc did not terminate successfully\n(allow sys_containerd_t system_run_t (fs_classes (rw)))\n(allow sys_containerd_t run_t (fs_classes (rw)))\n(allow sys_containerd_t system_var_t (fs_classes (relabelto relabelfrom)))\n(allow sys_containerd_t sys_containerd_run_t (fs_classes (rw)))\n(allow sys_containerd_t pod_containerd_run_t (fs_classes (rw))) ; shim sockets\n\n; Transition to system container contexts\n(allow sys_containerd_t system_container_p (process2 (nnp_transition nosuid_transition)))\n(allow sys_containerd_t system_container_p (process (transition)))\n\n; Manage procfs & processes\n(allow sys_containerd_t system_container_p (fs_classes (rw)))\n(allow sys_containerd_t system_container_p (process_classes (full)))\n(allow system_container_p sys_containerd_t (fd (use)))\n(allow system_container_p sys_containerd_t (fifo_file (append getattr ioctl map open read rename setattr watch write)))\n\n(allow sys_containerd_t system_container_p (key (view read write search link setattr create)))\n\n; Shim sockets\n(allow sys_containerd_t sys_containerd_socket_t (fs_classes (rw)))\n\n(typeattribute containerd_p)\n(typeattributeset containerd_p sys_containerd_t)\n\n; Access overlayfs parameters\n(allow containerd_p sys_module_t (fs_classes (ro)))\n\n; manage cgroups & namespaces\n(allow containerd_p cgroup_t (fs_classes (rw)))\n(allow containerd_p nsfs_t (fs_classes (rw)))\n\n; mounts\n(allow containerd_p filesystem_f (filesystem (unmount remount mount)))\n\n; mounton for masking\n(allow containerd_p any_f (fs_classes (mounton)))\n\n; Shim sockets\n(allow containerd_p self (unix_stream_socket (connectto)))\n\n; logs\n(allow sys_containerd_t system_t (fs_classes (rw)))\n\n; Typically a system extension\n; Possibly a service misconfigured by machined\n(type unconfined_container_t)\n(call system_container_p (unconfined_container_t))\n\n; logs\n(allow sys_containerd_t system_t (fs_classes (rw)))\n\n; Manage keys\n(allow containerd_p self (key (view read write search link setattr create)))\n\n; Containerd uses igzip on amd64 and pigz on arm64 when pulling images\n(allow sys_containerd_t bin_exec_t (file (execute_no_trans execute)))\n(allow sys_containerd_t bin_exec_t (fs_classes (ro)))\n\n; PTYs are allocated for talosctl debug\n(allow sys_containerd_t devpts_t (fs_classes (rw)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/system-containers.cil",
    "content": "(allow sys_containerd_t init_exec_t (file (execute)))\n(allow sys_containerd_t init_exec_t (fs_classes (ro)))\n\n; apid\n(type apid_t)\n(call system_container_p (apid_t))\n(allow apid_t init_exec_t (file (entrypoint execute)))\n\n(type apid_socket_t)\n(call system_socket_f (apid_socket_t))\n(type apid_runtime_socket_t)\n(call system_socket_f (apid_runtime_socket_t))\n\n; create the socket\n(allow apid_t system_t (fs_classes (rw)))\n(allow apid_t system_t (sock_file (relabelfrom)))\n(allow apid_t system_run_t (fs_classes (rw)))\n(allow apid_t system_run_t (sock_file (relabelfrom)))\n(allow apid_t apid_socket_t (sock_file (relabelto)))\n(allow apid_t apid_socket_t (fs_classes (rw)))\n(allow apid_t apid_runtime_socket_t (sock_file (relabelto)))\n(allow apid_t apid_runtime_socket_t (fs_classes (rw)))\n\n; Talk to machined\n(allow apid_t machine_socket_t (fs_classes (rw)))\n(allow apid_t init_t (unix_stream_socket (connectto)))\n\n; trustd\n(type trustd_t)\n(call system_container_p (trustd_t))\n(allow trustd_t init_exec_t (file (entrypoint execute)))\n\n(type trustd_runtime_socket_t)\n(call system_socket_f (trustd_runtime_socket_t))\n(allow trustd_t trustd_runtime_socket_t (sock_file (write)))\n; Trustd socket is created and owned by machined\n(allow trustd_t init_t (unix_stream_socket (connectto)))\n\n; Talos installer\n(type installer_t)\n(call system_container_p (installer_t))\n(allow sys_containerd_t system_var_t (file (execute)))\n(allow installer_t system_var_t (file (entrypoint execute execute_no_trans)))\n(allow installer_t system_var_t (fs_classes (rw)))\n\n; /boot(/EFI)\n(allow installer_t foreign_fs_t (fs_classes (rw)))\n(allow installer_t unlabeled_t (fs_classes (rw)))\n(allow installer_t fs_t (filesystem (unmount mount)))\n\n; efibootmgr used for installing in UEFI mode\n(allow installer_t efivarfs_t (fs_classes (rw)))\n\n; Talk to machined\n(allow installer_t machine_socket_t (sock_file (write)))\n(allow installer_t init_t (unix_stream_socket (connectto)))\n\n; talosctl debug container, automatically transition to it\n(type debug_t)\n(call system_container_p (debug_t))\n(typetransition sys_containerd_t system_var_t process debug_t)\n(allow debug_t system_var_t (file (entrypoint execute execute_no_trans)))\n(allow debug_t system_var_t (fs_classes (rw)))\n(allow debug_t log_f (fs_classes (rw)))\n(allow debug_t ephemeral_t (fs_classes (rw)))\n(allow debug_t devpts_t (fs_classes (rw)))\n(allow debug_t cni_conf_t (fs_classes (rw)))\n(allow debug_t module_t (fs_classes (ro)))\n(allow debug_t kubelet_state_t (fs_classes (rw)))\n(allow debug_t fs_t (filesystem (\n    getattr\n    mount\n    quotaget\n    quotamod\n    remount\n    unmount\n    watch\n)))\n(allow debug_t cgroup_t (fs_classes (rw)))\n(allow debug_t nsfs_t (fs_classes (ro)))\n(allow debug_t self (key (all)))\n(allow debug_t self (capability2 (syslog)))\n(allow debug_t kernel_t (system (syslog_read)))\n(allow debug_t sys_module_t (fs_classes (ro)))\n\n; Navigate procfs and monitor processes\n(allow debug_t any_p (fs_classes (ro)))\n(allow debug_t kernel_t (fs_classes (ro)))\n"
  },
  {
    "path": "internal/pkg/selinux/policy/selinux/services/udev.cil",
    "content": "(type udev_exec_t)\n(call system_f (udev_exec_t))\n(context udev_exec_t (system_u object_r udev_exec_t (systemLow systemLow)))\n(filecon \"/usr/bin/systemd-udevd\" file udev_exec_t)\n(filecon \"/usr/bin/udevadm\" file udev_exec_t)\n\n; Do not reorder: label non-executable rules files as executable\n(type udev_rules_t)\n(call system_f (udev_rules_t))\n(filecon \"/usr/lib/udev/rules.d(/.*)?\" any (system_u object_r udev_rules_t (systemLow systemLow)))\n(filecon \"/usr/lib/udev(/.*)?\" any udev_exec_t)\n; Some rules are on tmpfs\n(allow udev_rules_t tmpfs_t (filesystem (associate)))\n(allow udev_t lib_t (fs_classes (ioctl)))\n\n(type module_t)\n(call system_f (module_t))\n(filecon \"/usr/lib/modules(/.*)?\" any (system_u object_r module_t (systemLow systemLow)))\n(filecon \"/lib/modules\" any (system_u object_r module_t (systemLow systemLow)))\n\n(type udev_t)\n(call service_p (udev_t udev_exec_t))\n\n(type udev_socket_t)\n(call system_socket_f (udev_socket_t))\n(typeattribute not_udev_socket_t)\n(typeattributeset not_udev_socket_t (not udev_socket_t))\n(typetransition udev_t not_udev_socket_t sock_file udev_socket_t)\n\n; udevadm called by machined in its context\n(allow init_t udev_exec_t (file (execute_no_trans)))\n(allow init_t udev_t (unix_stream_socket (connectto)))\n\n; Device subsystems, labeled by udev rules\n; RTC is important for security verification\n(type rtc_device_t)\n(call protected_device_f (rtc_device_t))\n; Could be exposed firmware storage\n(type mtd_device_t)\n(call protected_device_f (mtd_device_t))\n; Could reset the system\n(type wdt_device_t)\n(call protected_device_f (wdt_device_t))\n; Typically client pods must not access TPM\n(type tpm_device_t)\n(call protected_device_f (tpm_device_t))\n; TODO: label and restrict block devices\n\n(type modprobe_exec_t)\n(call system_f (modprobe_exec_t))\n(filecon \"/usr/bin/modprobe\" file (system_u object_r modprobe_exec_t (systemLow systemLow)))\n; If modprobe is called by machined or kernel do a transition to udev context which has module permissions\n(allow udev_t modprobe_exec_t (file (execute execute_no_trans)))\n(allow udev_t modprobe_exec_t (fs_classes (ro)))\n(typetransition kernel_t modprobe_exec_t process udev_t)\n(typetransition init_t modprobe_exec_t process udev_t)\n\n(allow udev_t kernel_t (fd (use)))\n(allow udev_t modprobe_exec_t (file (entrypoint)))\n\n(allow kernel_t modprobe_exec_t (file (execute)))\n(allow kernel_t udev_t (process (all))) ; including transition\n\n(allow init_t modprobe_exec_t (file (execute)))\n(allow init_t udev_t (process (all))) ; including transition\n\n(allow kernel_t module_t (system (module_load module_request)))\n(allow udev_t module_t (fs_classes (ro)))\n(allow udev_t module_t (system (module_load module_request)))\n(allow udev_t self (capability (sys_module)))\n(allow udev_t self (cap_userns (sys_module)))\n(allow udev_t kernel_t (system (module_load module_request)))\n(allow kernel_t self (system (module_request)))\n\n; Allow udev to read rules files\n(allow udev_t udev_rules_t (fs_classes (ro ioctl)))\n\n; udev rules can set module parameters\n(allow udev_t sys_module_t (fs_classes (rw)))\n\n(allow udev_t device_t (fs_classes (relabelfrom)))\n(allow udev_t device_f (fs_classes (rw relabelto)))\n\n; socket and runtime files\n(type udev_run_t)\n(call system_f (udev_run_t))\n(allow udev_run_t tmpfs_t (filesystem (associate)))\n\n(typetransition udev_t run_t file udev_run_t)\n(typetransition udev_t run_t dir udev_run_t)\n(typetransition udev_t run_t lnk_file udev_run_t)\n(typetransition udev_t run_t chr_file udev_run_t)\n(typetransition udev_t run_t blk_file udev_run_t)\n(typetransition udev_t run_t fifo_file udev_run_t)\n\n(allow udev_t run_t (dir (add_name write))) ; before transition\n(allow udev_t udev_run_t (fs_classes (rw)))\n(allow udev_t udev_socket_t (fs_classes (rw)))\n\n; manage properties from rules\n(allow udev_t sysfs_t (fs_classes (rw)))\n\n; Container detection\n(allow udev_t init_t (fs_classes (ro ioctl)))\n\n; exec-invoke managed stuff\n(allow udev_t cgroup_t (fs_classes (rw ioctl)))\n(allow udev_t kernel_t (key (search)))\n\n; dmsetup\n; TODO: label more specifically?\n(allow udev_t bin_exec_t (file (execute execute_no_trans)))\n(allow udev_t kernel_t (system (ipc_info)))\n(allow udev_t any_p (sem (all)))\n"
  },
  {
    "path": "internal/pkg/selinux/selinux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package selinux provides generic code for managing SELinux.\npackage selinux\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"sync\"\n\n\t\"github.com/pkg/xattr\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/containermode\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n//go:embed policy/policy.33\nvar policy []byte\n\n// IsEnabled checks if SELinux is enabled on the system by reading\n// the kernel command line. It returns true if SELinux is enabled,\n// otherwise it returns false. It also ensures we're not in a container.\n// By default SELinux is disabled.\nvar IsEnabled = sync.OnceValue(func() bool {\n\tif containermode.InContainer() {\n\t\treturn false\n\t}\n\n\tval := procfs.ProcCmdline().Get(constants.KernelParamSELinux).First()\n\n\tvar selinuxFSPresent bool\n\n\tif _, err := os.Stat(\"/sys/fs/selinux\"); err == nil {\n\t\tselinuxFSPresent = true\n\t}\n\n\treturn val != nil && *val == \"1\" && selinuxFSPresent\n})\n\n// IsEnforcing checks if SELinux is enabled and the mode should be enforcing.\n// By default if SELinux is enabled we consider it to be permissive.\nvar IsEnforcing = sync.OnceValue(func() bool {\n\tif !IsEnabled() {\n\t\treturn false\n\t}\n\n\tval := procfs.ProcCmdline().Get(constants.KernelParamSELinuxEnforcing).First()\n\n\treturn val != nil && *val == \"1\"\n})\n\n// GetLabel gets label for file, directory or symlink (not following symlinks)\n// It does not perform the operation in case SELinux is disabled.\nfunc GetLabel(filename string) (string, error) {\n\tif !IsEnabled() {\n\t\treturn \"\", nil\n\t}\n\n\tlabel, err := xattr.LGet(filename, \"security.selinux\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif label == nil {\n\t\treturn \"\", nil\n\t}\n\n\treturn string(bytes.Trim(label, \"\\x00\\n\")), nil\n}\n\n// SetLabel sets label for file, directory or symlink (not following symlinks)\n// It does not perform the operation in case SELinux is disabled, provided label is empty or already set.\nfunc SetLabel(filename string, label string, excludeLabels ...string) error {\n\tif label == \"\" || !IsEnabled() {\n\t\treturn nil\n\t}\n\n\tcurrentLabel, err := GetLabel(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Skip extra FS transactions when labels are okay.\n\tif currentLabel == label {\n\t\treturn nil\n\t}\n\n\t// Skip setting label if it's in excludeLabels.\n\tif currentLabel != \"\" && slices.Contains(excludeLabels, currentLabel) {\n\t\treturn nil\n\t}\n\n\t// We use LGet/LSet so that we manipulate label on the exact path, not the symlink target.\n\tif err := xattr.LSet(filename, \"security.selinux\", []byte(label)); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// FGetLabel gets label for file, directory or symlink (not following symlinks) using provided root.\n// It does not perform the operation in case SELinux is disabled.\nfunc FGetLabel(root xfs.Root, filename string) (string, error) {\n\tif !IsEnabled() {\n\t\treturn \"\", nil\n\t}\n\n\tf, err := xfs.OpenFile(root, filename, unix.O_RDONLY|unix.O_NOFOLLOW, 0)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tosf, err := xfs.AsOSFile(f, filename)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer osf.Close() //nolint:errcheck\n\n\tlabel, err := xattr.FGet(osf, \"security.selinux\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif label == nil {\n\t\treturn \"\", nil\n\t}\n\n\treturn string(bytes.Trim(label, \"\\x00\\n\")), nil\n}\n\n// FSetLabel sets label for file, directory or symlink (not following symlinks) using provided root.\n// It does not perform the operation in case SELinux is disabled, provided label is empty or already set.\nfunc FSetLabel(root xfs.Root, filename string, label string, excludeLabels ...string) error {\n\tif label == \"\" || !IsEnabled() {\n\t\treturn nil\n\t}\n\n\tcurrentLabel, err := FGetLabel(root, filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Skip extra FS transactions when labels are okay.\n\tif currentLabel == label {\n\t\treturn nil\n\t}\n\n\t// Skip setting label if it's in excludeLabels.\n\tif currentLabel != \"\" && slices.Contains(excludeLabels, currentLabel) {\n\t\treturn nil\n\t}\n\n\tf, err := xfs.Open(root, filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tosf, err := xfs.AsOSFile(f, filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer osf.Close() //nolint:errcheck\n\n\t// We use FGet/FSet so that we manipulate label on the exact path, not the symlink target.\n\tif err := xattr.FSet(osf, \"security.selinux\", []byte(label)); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// SetLabelRecursive sets label for directory and its content recursively.\n// It does not perform the operation in case SELinux is disabled, provided label is empty or already set.\nfunc SetLabelRecursive(dir string, label string, excludeLabels ...string) error {\n\tif label == \"\" || !IsEnabled() {\n\t\treturn nil\n\t}\n\n\treturn filepath.Walk(dir, func(path string, _ os.FileInfo, err error) error {\n\t\treturn SetLabel(path, label, excludeLabels...)\n\t})\n}\n\n// Init initializes SELinux based on the configured mode.\n// It loads the policy and enforces it if necessary.\nfunc Init() error {\n\tif !IsEnabled() {\n\t\tlog.Println(\"selinux: disabled, not loading policy\")\n\n\t\treturn nil\n\t}\n\n\tif IsEnforcing() {\n\t\tlog.Println(\"selinux: running in enforcing mode, policy will be applied as soon as it's loaded\")\n\t}\n\n\tlog.Println(\"selinux: loading policy\")\n\n\tif err := os.WriteFile(\"/sys/fs/selinux/load\", policy, 0o777); err != nil {\n\t\treturn err\n\t}\n\n\tlog.Println(\"selinux: policy loaded\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/smbios/oem.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage smbios\n\nimport (\n\t\"strings\"\n)\n\n// ReadOEMVariable reads the OEM variable from SMBIOS and returns its value.\nfunc ReadOEMVariable(name string) ([]string, error) {\n\tsmbiosInfo, err := GetSMBIOSInfo()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result []string\n\n\tfor _, str := range smbiosInfo.OEMStrings.Strings {\n\t\tkey, val, ok := strings.Cut(str, \"=\")\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif key == name {\n\t\t\tresult = append(result, val)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/pkg/smbios/smbios.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package smbios provides access to SMBIOS information.\npackage smbios\n\nimport (\n\t\"sync\"\n\n\t\"github.com/siderolabs/go-smbios/smbios\"\n)\n\nvar (\n\tsyncSMBIOS sync.Once\n\tconnSMBIOS *smbios.SMBIOS\n\terrSMBIOS  error\n)\n\n// GetSMBIOSInfo returns the SMBIOS info.\nfunc GetSMBIOSInfo() (*smbios.SMBIOS, error) {\n\tsyncSMBIOS.Do(func() {\n\t\tconnSMBIOS, errSMBIOS = smbios.New()\n\t})\n\n\treturn connSMBIOS, errSMBIOS\n}\n"
  },
  {
    "path": "internal/pkg/timex/timex.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package timex provides a simple wrapper around adjtimex syscall.\npackage timex\n\nimport (\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// Status is bitmask field of statuses.\ntype Status int32\n\nfunc (status Status) String() string {\n\tvar labels []string\n\n\tfor _, item := range []struct {\n\t\tbit   Status\n\t\tlabel string\n\t}{\n\t\t{unix.STA_PLL, \"STA_PLL\"},             /* enable PLL updates (rw) */\n\t\t{unix.STA_PPSFREQ, \"STA_PPSFREQ\"},     /* enable PPS freq discipline (rw) */\n\t\t{unix.STA_PPSTIME, \"STA_PPSTIME\"},     /* enable PPS time discipline (rw) */\n\t\t{unix.STA_FLL, \"STA_FLL\"},             /* select frequency-lock mode (rw) */\n\t\t{unix.STA_INS, \"STA_INS\"},             /* insert leap (rw) */\n\t\t{unix.STA_DEL, \"STA_DEL\"},             /* delete leap (rw) */\n\t\t{unix.STA_UNSYNC, \"STA_UNSYNC\"},       /* clock unsynchronized (rw) */\n\t\t{unix.STA_FREQHOLD, \"STA_FREQHOLD\"},   /* hold frequency (rw) */\n\t\t{unix.STA_PPSSIGNAL, \"STA_PPSSIGNAL\"}, /* PPS signal present (ro) */\n\t\t{unix.STA_PPSJITTER, \"STA_PPSJITTER\"}, /* PPS signal jitter exceeded (ro) */\n\t\t{unix.STA_PPSWANDER, \"STA_PPSWANDER\"}, /* PPS signal wander exceeded (ro) */\n\t\t{unix.STA_PPSERROR, \"STA_PPSERROR\"},   /* PPS signal calibration error (ro) */\n\t\t{unix.STA_CLOCKERR, \"STA_CLOCKERR\"},   /* clock hardware fault (ro) */\n\t\t{unix.STA_NANO, \"STA_NANO\"},           /* resolution (0 = us, 1 = ns) (ro) */\n\t\t{unix.STA_MODE, \"STA_MODE\"},           /* mode (0 = PLL, 1 = FLL) (ro) */\n\t\t{unix.STA_CLK, \"STA_CLK\"},             /* clock source (0 = A, 1 = B) (ro) */\n\t} {\n\t\tif (status & item.bit) == item.bit {\n\t\t\tlabels = append(labels, item.label)\n\t\t}\n\t}\n\n\treturn strings.Join(labels, \" | \")\n}\n\n// State is clock state.\ntype State int\n\nfunc (state State) String() string {\n\tswitch state {\n\tcase unix.TIME_OK:\n\t\treturn \"TIME_OK\"\n\tcase unix.TIME_INS:\n\t\treturn \"TIME_INS\"\n\tcase unix.TIME_DEL:\n\t\treturn \"TIME_DEL\"\n\tcase unix.TIME_OOP:\n\t\treturn \"TIME_OOP\"\n\tcase unix.TIME_WAIT:\n\t\treturn \"TIME_WAIT\"\n\tcase unix.TIME_ERROR:\n\t\treturn \"TIME_ERROR\"\n\tdefault:\n\t\treturn \"TIME_UNKNOWN\"\n\t}\n}\n\n// Adjtimex provides a wrapper around syscall.Adjtimex.\nfunc Adjtimex(buf *unix.Timex) (state State, err error) {\n\tst, err := unix.ClockAdjtime(unix.CLOCK_REALTIME, buf)\n\n\treturn State(st), err\n}\n"
  },
  {
    "path": "internal/pkg/toml/merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage toml\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/pelletier/go-toml/v2\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n)\n\n// tomlDecodeFile decodes a TOML file into the provided destination, and returns a sha256 hash of the file content.\nfunc tomlDecodeFile(path string, dest any) ([]byte, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\thash := sha256.New()\n\n\terr = toml.NewDecoder(io.TeeReader(f, hash)).Decode(dest)\n\n\treturn hash.Sum(nil), err\n}\n\n// Merge several TOML documents in files into one.\n//\n// Merge process relies on generic map[string]any merge which might not always be correct.\n//\n// Merge returns a sha256 checksum of each file merged.\nfunc Merge(parts []string) ([]byte, map[string][]byte, error) {\n\tmerged := map[string]any{}\n\tchecksums := make(map[string][]byte, len(parts))\n\n\tvar header []byte\n\n\tfor _, part := range parts {\n\t\tpartial := map[string]any{}\n\n\t\thash, err := tomlDecodeFile(part, &partial)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"error decoding %q: %w\", part, err)\n\t\t}\n\n\t\tif err := merge.Merge(merged, partial); err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"error merging %q: %w\", part, err)\n\t\t}\n\n\t\theader = fmt.Appendf(header, \"## %s (sha256:%s)\\n\", part, hex.EncodeToString(hash))\n\t\tchecksums[part] = hash\n\t}\n\n\tvar out bytes.Buffer\n\n\t_, _ = out.Write(header)\n\t_ = out.WriteByte('\\n')\n\n\tif err := toml.NewEncoder(&out).SetIndentTables(true).Encode(merged); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error encoding merged config: %w\", err)\n\t}\n\n\treturn out.Bytes(), checksums, nil\n}\n"
  },
  {
    "path": "internal/pkg/toml/merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage toml_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/toml\"\n)\n\n//go:embed testdata/expected.toml\nvar expected []byte\n\nfunc TestMerge(t *testing.T) {\n\tout, checksums, err := toml.Merge([]string{\n\t\t\"testdata/1.toml\",\n\t\t\"testdata/2.toml\",\n\t\t\"testdata/3.toml\",\n\t})\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, string(expected), string(out))\n\tassert.Contains(t, checksums, \"testdata/1.toml\")\n\tassert.Contains(t, checksums, \"testdata/2.toml\")\n\tassert.Contains(t, checksums, \"testdata/3.toml\")\n}\n"
  },
  {
    "path": "internal/pkg/toml/testdata/1.toml",
    "content": "version = 2\n\n[plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc]\n    runtime_type = \"io.containerd.runc.v2\"\n    discard_unpacked_layers = true\n"
  },
  {
    "path": "internal/pkg/toml/testdata/2.toml",
    "content": "[plugins]\n  [plugins.\"io.containerd.grpc.v1.cri\"]\n    [plugins.\"io.containerd.grpc.v1.cri\".registry]\n      config_path = \"/etc/cri/conf.d/hosts\"\n      [plugins.\"io.containerd.grpc.v1.cri\".registry.configs]\n"
  },
  {
    "path": "internal/pkg/toml/testdata/3.toml",
    "content": "[metrics]\n  address = \"0.0.0.0:11234\"\n\n[plugins]\n   [plugins.\"io.containerd.grpc.v1.cri\"]\n    sandbox_image = \"registry.k8s.io/pause:3.8\"\n"
  },
  {
    "path": "internal/pkg/toml/testdata/expected.toml",
    "content": "## testdata/1.toml (sha256:2eac71621235f8666c54ad3f29a77b2e8483bbd7f0717f8613af591fb5609b44)\n## testdata/2.toml (sha256:47ae85a638a291b04518413a12b19c51883a17c8f5064193462d3527b4495e36)\n## testdata/3.toml (sha256:159608dffd674e5fe351d47166eab59ee93f6523ff336602364edfd7be25c796)\n\nversion = 2\n\n[metrics]\n  address = '0.0.0.0:11234'\n\n[plugins]\n  [plugins.'io.containerd.grpc.v1.cri']\n    sandbox_image = 'registry.k8s.io/pause:3.8'\n\n    [plugins.'io.containerd.grpc.v1.cri'.containerd]\n      [plugins.'io.containerd.grpc.v1.cri'.containerd.runtimes]\n        [plugins.'io.containerd.grpc.v1.cri'.containerd.runtimes.runc]\n          discard_unpacked_layers = true\n          runtime_type = 'io.containerd.runc.v2'\n\n    [plugins.'io.containerd.grpc.v1.cri'.registry]\n      config_path = '/etc/cri/conf.d/hosts'\n\n      [plugins.'io.containerd.grpc.v1.cri'.registry.configs]\n"
  },
  {
    "path": "internal/pkg/toml/toml.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package toml provides utility functions for TOML handling.\npackage toml\n"
  },
  {
    "path": "internal/pkg/tpm/tpm_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\n// Package tpm provides TPM 2.0 support.\npackage tpm\n\nimport (\n\t\"errors\"\n\t\"os\"\n\n\t\"github.com/google/go-tpm/tpm2/transport\"\n\t\"github.com/google/go-tpm/tpm2/transport/linuxtpm\"\n)\n\n// Open a TPM device.\n//\n// Tries first /dev/tpmrm0 and then /dev/tpm0.\nfunc Open() (transport.TPMCloser, error) {\n\ttpm, err := linuxtpm.Open(\"/dev/tpmrm0\")\n\tif errors.Is(err, os.ErrNotExist) {\n\t\ttpm, err = linuxtpm.Open(\"/dev/tpm0\")\n\t}\n\n\treturn tpm, err\n}\n"
  },
  {
    "path": "internal/pkg/tpm/tpm_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\n// Package tpm provides TPM 2.0 support.\npackage tpm\n\nimport (\n\t\"errors\"\n\n\t\"github.com/google/go-tpm/tpm2/transport\"\n)\n\n// Open a TPM device.\nfunc Open() (transport.TPMCloser, error) {\n\treturn nil, errors.New(\"TPM device is not available\")\n}\n"
  },
  {
    "path": "internal/pkg/uki/assemble.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/uki/internal/pe\"\n)\n\n// assemble the UKI file out of sections.\nfunc (builder *Builder) assemble() error {\n\tbuilder.unsignedUKIPath = filepath.Join(builder.scratchDir, \"unsigned.uki\")\n\n\treturn pe.AssembleNative(builder.SdStubPath, builder.unsignedUKIPath, builder.sections)\n}\n"
  },
  {
    "path": "internal/pkg/uki/generate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki\n\nimport (\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\ttalosx509 \"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/splash\"\n)\n\nfunc (builder *Builder) generateOSRel() error {\n\tosRelease, err := version.OSReleaseFor(version.Name, builder.Version)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpath := filepath.Join(builder.scratchDir, \"os-release\")\n\n\tif err = os.WriteFile(path, osRelease, 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionOSRel.String(),\n\t\t\tPath:    path,\n\t\t\tMeasure: true,\n\t\t\tAppend:  true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateCmdline() error {\n\tpath := filepath.Join(builder.scratchDir, \"cmdline\")\n\n\tif err := os.WriteFile(path, []byte(builder.Cmdline), 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionCmdline.String(),\n\t\t\tPath:    path,\n\t\t\tMeasure: true,\n\t\t\tAppend:  true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateInitrd() error {\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionInitrd.String(),\n\t\t\tPath:    builder.InitrdPath,\n\t\t\tMeasure: true,\n\t\t\tAppend:  true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateSplash() error {\n\tpath := filepath.Join(builder.scratchDir, \"splash.bmp\")\n\n\tif err := os.WriteFile(path, splash.GetBootImage(), 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionSplash.String(),\n\t\t\tPath:    path,\n\t\t\tMeasure: true,\n\t\t\tAppend:  true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateUname() error {\n\t// it is not always possible to get the kernel version from the kernel image, so we\n\t// do a bit of pre-checks\n\tvar kernelVersion string\n\n\tif builder.Version == version.Tag {\n\t\t// if building from the same version of Talos, use default kernel version\n\t\tkernelVersion = constants.DefaultKernelVersion\n\t} else {\n\t\t// otherwise, try to get the kernel version from the kernel image\n\t\tkernelVersion, _ = DiscoverKernelVersion(builder.KernelPath) //nolint:errcheck\n\t}\n\n\tif kernelVersion == \"\" {\n\t\t// we haven't got the kernel version, skip the uname section\n\t\treturn nil\n\t}\n\n\tpath := filepath.Join(builder.scratchDir, \"uname\")\n\n\tif err := os.WriteFile(path, []byte(kernelVersion), 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionUname.String(),\n\t\t\tPath:    path,\n\t\t\tMeasure: true,\n\t\t\tAppend:  true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateSBAT() error {\n\tsbat, err := GetSBAT(builder.SdStubPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpath := filepath.Join(builder.scratchDir, \"sbat\")\n\n\tif err = os.WriteFile(path, sbat, 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionSBAT.String(),\n\t\t\tPath:    path,\n\t\t\tMeasure: true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc (builder *Builder) generatePCRPublicKey() error {\n\tpublicKeyBytes, err := x509.MarshalPKIXPublicKey(builder.PCRSigner.PublicRSAKey())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpublicKeyPEM := pem.EncodeToMemory(&pem.Block{\n\t\tType:  talosx509.PEMTypeRSAPublic,\n\t\tBytes: publicKeyBytes,\n\t})\n\n\tpath := filepath.Join(builder.scratchDir, \"pcr-public.pem\")\n\n\tif err = os.WriteFile(path, publicKeyPEM, 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionPCRPKey.String(),\n\t\t\tPath:    path,\n\t\t\tAppend:  true,\n\t\t\tMeasure: true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\nfunc defaultProfiles() []Profile {\n\treturn []Profile{\n\t\t{\n\t\t\tID: \"main\",\n\t\t},\n\t}\n}\n\nfunc (builder *Builder) generateProfiles() error {\n\tif !quirks.New(builder.Version).SupportsUKIProfiles() {\n\t\treturn nil\n\t}\n\n\tif slices.ContainsFunc(builder.Profiles, func(p Profile) bool {\n\t\treturn p.ID == \"main\"\n\t}) {\n\t\treturn fmt.Errorf(\"profile with ID 'main' is reserved\")\n\t}\n\n\tfor _, profile := range slices.Concat(defaultProfiles(), builder.Profiles) {\n\t\tpath := filepath.Join(builder.scratchDir, fmt.Sprintf(\"profile-%s\", profile.ID))\n\n\t\tif err := os.WriteFile(path, []byte(profile.String()), 0o600); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbuilder.sections = append(builder.sections,\n\t\t\tsection{\n\t\t\t\tName:    SectionProfile.String(),\n\t\t\t\tPath:    path,\n\t\t\t\tAppend:  true,\n\t\t\t\tMeasure: true,\n\t\t\t},\n\t\t)\n\n\t\tif profile.Cmdline != \"\" {\n\t\t\tpath = filepath.Join(builder.scratchDir, fmt.Sprintf(\"profile-%s-cmdline\", profile.ID))\n\n\t\t\tif err := os.WriteFile(path, []byte(profile.Cmdline), 0o600); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbuilder.sections = append(builder.sections,\n\t\t\t\tsection{\n\t\t\t\t\tName:    SectionCmdline.String(),\n\t\t\t\t\tPath:    path,\n\t\t\t\t\tAppend:  true,\n\t\t\t\t\tMeasure: true,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (builder *Builder) generateKernel() error {\n\tpath := builder.KernelPath\n\n\tif builder.peSigner != nil {\n\t\tpath := filepath.Join(builder.scratchDir, \"kernel\")\n\n\t\tif err := builder.peSigner.Sign(builder.KernelPath, path); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tbuilder.sections = append(builder.sections,\n\t\tsection{\n\t\t\tName:    SectionLinux.String(),\n\t\t\tPath:    path,\n\t\t\tAppend:  true,\n\t\t\tMeasure: true,\n\t\t},\n\t)\n\n\treturn nil\n}\n\ntype profileIndex struct {\n\tStart int\n\tEnd   int\n}\n\nfunc (builder *Builder) generatePCRSig() error {\n\ttoMeasure := xslices.Filter(builder.sections, func(s section) bool {\n\t\treturn s.Measure\n\t})\n\n\tif quirks.New(builder.Version).SupportsUKIProfiles() {\n\t\tprofileIndexes := []profileIndex{}\n\n\t\tvar previousProfileIndex int\n\n\t\tfor i, s := range toMeasure {\n\t\t\tif s.Name == SectionProfile.String() {\n\t\t\t\tif previousProfileIndex != 0 {\n\t\t\t\t\tprofileIndexes[len(profileIndexes)-1].End = i\n\t\t\t\t}\n\n\t\t\t\tprofileIndexes = append(profileIndexes, profileIndex{Start: i})\n\t\t\t\tpreviousProfileIndex = i\n\t\t\t}\n\t\t}\n\n\t\tif previousProfileIndex != 0 {\n\t\t\tprofileIndexes[len(profileIndexes)-1].End = len(toMeasure)\n\t\t}\n\n\t\tfor i, profileIndex := range profileIndexes {\n\t\t\tprofileData := xslices.ToMap(\n\t\t\t\tslices.Concat(toMeasure[:profileIndexes[0].Start], toMeasure[profileIndex.Start:profileIndex.End]),\n\t\t\t\tfunc(s section) (string, string) {\n\t\t\t\t\treturn s.Name, s.Path\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif err := builder.writePCRSignature(profileData, fmt.Sprintf(\"pcrpsig-%d\", i), profileIndex.End+i); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tsectionData := xslices.ToMap(toMeasure, func(s section) (string, string) {\n\t\treturn s.Name, s.Path\n\t})\n\n\treturn builder.writePCRSignature(sectionData, \"pcrpsig\", len(builder.sections))\n}\n\nfunc (builder *Builder) writePCRSignature(data map[string]string, filename string, insertIndex int) error {\n\tpcrData, err := measure.GenerateSignedPCR(data, builder.PCRSigner)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpcrSignatureData, err := json.Marshal(pcrData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpath := filepath.Join(builder.scratchDir, filename)\n\n\tif err = os.WriteFile(path, pcrSignatureData, 0o600); err != nil {\n\t\treturn err\n\t}\n\n\tbuilder.sections = slices.Insert(builder.sections, insertIndex, section{\n\t\tName:   SectionPCRSig.String(),\n\t\tPath:   path,\n\t\tAppend: true,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/extract.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pe\n\nimport (\n\t\"debug/pe\"\n\t\"fmt\"\n\t\"io\"\n)\n\n// AssetInfo contains the kernel, initrd, and cmdline from a PE file.\ntype AssetInfo struct {\n\tio.Closer\n\n\tKernel  io.Reader\n\tInitrd  io.Reader\n\tCmdline io.Reader\n}\n\n// Extract extracts the kernel, initrd, and cmdline from a PE file.\nfunc Extract(ukiPath string) (assetInfo AssetInfo, err error) {\n\tpeFile, err := pe.Open(ukiPath)\n\tif err != nil {\n\t\treturn assetInfo, fmt.Errorf(\"failed to open PE file: %w\", err)\n\t}\n\n\tassetInfo.Closer = peFile\n\n\tsectionMap := map[string]*io.Reader{\n\t\t\".initrd\":  &assetInfo.Initrd,\n\t\t\".cmdline\": &assetInfo.Cmdline,\n\t\t\".linux\":   &assetInfo.Kernel,\n\t}\n\n\tfor _, section := range peFile.Sections {\n\t\tif reader, exists := sectionMap[section.Name]; exists && *reader == nil {\n\t\t\t*reader = io.LimitReader(section.Open(), int64(section.VirtualSize))\n\t\t}\n\t}\n\n\tfor name, reader := range sectionMap {\n\t\tif *reader == nil {\n\t\t\treturn assetInfo, fmt.Errorf(\"%s not found in PE file\", name)\n\t\t}\n\t}\n\n\treturn assetInfo, nil\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/extract_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pe_test\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/uki/internal/pe\"\n)\n\nfunc TestUKIExtract(t *testing.T) {\n\tsrcFile := \"testdata/linuxx64.efi.stub\"\n\n\tdestDir := t.TempDir()\n\n\tdestFile := filepath.Join(destDir, \"vmlinuz.efi\")\n\n\tfor _, section := range []string{\"linux\", \"initrd\", \"cmdline\", \"profile-default\", \"profile-reset\", \"cmdline-reset\"} {\n\t\tassert.NoError(t, os.WriteFile(filepath.Join(destDir, section), []byte(section), 0o644))\n\t}\n\n\tassert.NoError(t, pe.AssembleNative(srcFile, destFile, []pe.Section{\n\t\t{\n\t\t\tName:    \".linux\",\n\t\t\tPath:    filepath.Join(destDir, \"linux\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t\t{\n\t\t\tName:    \".initrd\",\n\t\t\tPath:    filepath.Join(destDir, \"initrd\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t\t{\n\t\t\tName:    \".cmdline\",\n\t\t\tPath:    filepath.Join(destDir, \"cmdline\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t\t{\n\t\t\tName:    \".profile\",\n\t\t\tPath:    filepath.Join(destDir, \"profile-default\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t\t{\n\t\t\tName:    \".profile\",\n\t\t\tPath:    filepath.Join(destDir, \"profile-reset\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t\t{\n\t\t\tName:    \".cmdline\",\n\t\t\tPath:    filepath.Join(destDir, \"cmdline-reset\"),\n\t\t\tMeasure: false,\n\t\t\tAppend:  true,\n\t\t},\n\t}))\n\n\tukiData, err := pe.Extract(destFile)\n\tassert.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, ukiData.Close())\n\t})\n\n\tvar kernel, initrd, cmdline strings.Builder\n\n\t_, err = io.Copy(&kernel, ukiData.Kernel)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"linux\", kernel.String())\n\n\t_, err = io.Copy(&initrd, ukiData.Initrd)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"initrd\", initrd.String())\n\n\t_, err = io.Copy(&cmdline, ukiData.Cmdline)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"cmdline\", cmdline.String())\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/native.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pe\n\nimport (\n\t\"debug/pe\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n)\n\nconst (\n\tdosHeaderLength  = 0x40\n\tdosHeaderPadding = 0x40\n)\n\n// AssembleNative is a helper function to assemble the PE file without external programs.\n//\n//nolint:gocyclo,cyclop\nfunc AssembleNative(srcPath, dstPath string, sections []Section) error {\n\tin, err := os.Open(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpeFile, err := pe.NewFile(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer in.Close() //nolint: errcheck\n\n\tif peFile.COFFSymbols != nil {\n\t\treturn errors.New(\"COFF symbols are not supported\")\n\t}\n\n\tif peFile.StringTable != nil {\n\t\treturn errors.New(\"COFF string table is not supported\")\n\t}\n\n\tif peFile.Symbols != nil {\n\t\treturn errors.New(\"symbols are not supported\")\n\t}\n\n\t_, err = in.Seek(0, io.SeekStart)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tout, err := os.Create(dstPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create output: %w\", err)\n\t}\n\n\tdefer out.Close() //nolint: errcheck\n\n\t// 1. DOS header\n\tvar dosheader [dosHeaderLength]byte\n\n\t_, err = in.ReadAt(dosheader[:], 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read DOS header: %w\", err)\n\t}\n\n\tbinary.LittleEndian.PutUint32(dosheader[dosHeaderLength-4:], dosHeaderLength+dosHeaderPadding)\n\n\t_, err = out.Write(append(append(dosheader[:], make([]byte, dosHeaderPadding)...), []byte(\"PE\\x00\\x00\")...))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to write DOS header: %w\", err)\n\t}\n\n\t// 2. PE header and optional header\n\tnewFileHeader := peFile.FileHeader\n\n\ttimestamp, ok, err := utils.SourceDateEpoch()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get SOURCE_DATE_EPOCH: %w\", err)\n\t}\n\n\tif !ok {\n\t\ttimestamp = time.Now().Unix()\n\t}\n\n\tnewFileHeader.TimeDateStamp = uint32(timestamp)\n\n\t// find the first VMA address\n\tlastSection := peFile.Sections[len(peFile.Sections)-1]\n\n\theader, ok := peFile.OptionalHeader.(*pe.OptionalHeader64)\n\tif !ok {\n\t\treturn errors.New(\"failed to get optional header\")\n\t}\n\n\tsectionAlignment := uint64(header.SectionAlignment - 1)\n\tfileAlignment := uint64(header.FileAlignment - 1)\n\n\tbaseVirtualAddress := uint64(lastSection.VirtualAddress) + uint64(lastSection.VirtualSize)\n\tbaseVirtualAddress = (baseVirtualAddress + sectionAlignment) &^ sectionAlignment\n\n\tnewHeader := *header\n\tnewHeader.MajorLinkerVersion = 0\n\tnewHeader.MinorLinkerVersion = 0\n\tnewHeader.CheckSum = 0\n\n\ttype peSectionWithPath struct {\n\t\tpe.Section\n\n\t\tSourcePath string\n\t}\n\n\tnewSections := xslices.Map(peFile.Sections, func(section *pe.Section) *peSectionWithPath {\n\t\treturn &peSectionWithPath{\n\t\t\tSection: *section,\n\t\t}\n\t})\n\n\t// calculate sections size and VMA\n\tfor i := range sections {\n\t\tif !sections[i].Append {\n\t\t\tcontinue\n\t\t}\n\n\t\tst, err := os.Stat(sections[i].Path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsections[i].virtualSize = uint64(st.Size())\n\t\tsections[i].virtualAddress = baseVirtualAddress\n\n\t\tbaseVirtualAddress += sections[i].virtualSize\n\t\tbaseVirtualAddress = (baseVirtualAddress + sectionAlignment) &^ sectionAlignment\n\n\t\tnewFileHeader.NumberOfSections++\n\n\t\tnewSections = append(newSections, &peSectionWithPath{\n\t\t\tSection: pe.Section{\n\t\t\t\tSectionHeader: pe.SectionHeader{\n\t\t\t\t\tName:            sections[i].Name,\n\t\t\t\t\tVirtualSize:     uint32(sections[i].virtualSize),\n\t\t\t\t\tVirtualAddress:  uint32(sections[i].virtualAddress),\n\t\t\t\t\tSize:            uint32((sections[i].virtualSize + fileAlignment) &^ fileAlignment),\n\t\t\t\t\tCharacteristics: pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ,\n\t\t\t\t},\n\t\t\t},\n\t\t\tSourcePath: sections[i].Path,\n\t\t})\n\t}\n\n\tnewHeader.SizeOfInitializedData = 0\n\tnewHeader.SizeOfCode = 0\n\tnewHeader.SizeOfHeaders = 0x80 /* DOS header */ + uint32(binary.Size(pe.FileHeader{})+binary.Size(pe.OptionalHeader64{})+binary.Size(pe.SectionHeader32{})*len(newSections))\n\tnewHeader.SizeOfHeaders = (newHeader.SizeOfHeaders + uint32(fileAlignment)) &^ uint32(fileAlignment)\n\n\tlastNewSection := newSections[len(newSections)-1]\n\n\tlastSectionPointer := uint64(lastNewSection.VirtualAddress) + uint64(lastNewSection.VirtualSize) + newHeader.ImageBase\n\tlastSectionPointer = (lastSectionPointer + sectionAlignment) &^ sectionAlignment\n\n\tnewHeader.SizeOfImage = uint32(lastSectionPointer - newHeader.ImageBase)\n\n\tfor _, section := range newSections {\n\t\tif section.Characteristics&pe.IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {\n\t\t\tnewHeader.SizeOfInitializedData += section.Size\n\t\t} else {\n\t\t\tnewHeader.SizeOfCode += section.Size\n\t\t}\n\t}\n\n\t// write the new file header\n\tif err = binary.Write(out, binary.LittleEndian, newFileHeader); err != nil {\n\t\treturn fmt.Errorf(\"failed to write file header: %w\", err)\n\t}\n\n\tif err = binary.Write(out, binary.LittleEndian, newHeader); err != nil {\n\t\treturn fmt.Errorf(\"failed to write optional header: %w\", err)\n\t}\n\n\t// 3. Section headers\n\trawSections := xslices.Map(newSections, func(section *peSectionWithPath) pe.SectionHeader32 {\n\t\tvar rawName [8]byte\n\n\t\tcopy(rawName[:], section.Name)\n\n\t\treturn pe.SectionHeader32{\n\t\t\tName:            rawName,\n\t\t\tVirtualSize:     section.VirtualSize,\n\t\t\tVirtualAddress:  section.VirtualAddress,\n\t\t\tSizeOfRawData:   section.Size,\n\t\t\tCharacteristics: section.Characteristics,\n\t\t}\n\t},\n\t)\n\n\tsectionOffset := newHeader.SizeOfHeaders\n\n\tfor i := range rawSections {\n\t\trawSections[i].PointerToRawData = sectionOffset\n\n\t\tsectionOffset += rawSections[i].SizeOfRawData\n\t}\n\n\tfor _, rawSection := range rawSections {\n\t\tif err = binary.Write(out, binary.LittleEndian, rawSection); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write section header: %w\", err)\n\t\t}\n\t}\n\n\t// 4. Section data\n\tfor i, rawSection := range rawSections {\n\t\tname := newSections[i].Name\n\t\tsourcePath := newSections[i].SourcePath\n\n\t\tif err := func(rawSection pe.SectionHeader32, name, sourcePath string) error {\n\t\t\t// the section might come either from the input PE file or from a separate file\n\t\t\tvar sectionData io.ReadCloser\n\n\t\t\tif sourcePath != \"\" {\n\t\t\t\tsectionData, err = os.Open(sourcePath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to open section data: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tdefer sectionData.Close() //nolint: errcheck\n\t\t\t}\n\n\t\t\tif sectionData == nil {\n\t\t\t\tfor _, section := range peFile.Sections {\n\t\t\t\t\tif section.Name == name {\n\t\t\t\t\t\tsectionData = io.NopCloser(section.Open())\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif sectionData == nil {\n\t\t\t\treturn fmt.Errorf(\"failed to find section data for %q\", name)\n\t\t\t}\n\n\t\t\t_, err = out.Seek(int64(rawSection.PointerToRawData), io.SeekStart)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to seek to section data: %w\", err)\n\t\t\t}\n\n\t\t\tn, err := io.Copy(out, sectionData)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to copy section data: %w\", err)\n\t\t\t}\n\n\t\t\tif n > int64(rawSection.SizeOfRawData) {\n\t\t\t\treturn fmt.Errorf(\"section data is too large: %d > %d\", n, rawSection.SizeOfRawData)\n\t\t\t}\n\n\t\t\tif n < int64(rawSection.SizeOfRawData) {\n\t\t\t\t_, err = io.CopyN(out, zeroReader{}, int64(rawSection.SizeOfRawData)-n)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to zero-fill section data: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}(rawSection, name, sourcePath); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write section data %s: %w\", name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\ntype zeroReader struct{}\n\nfunc (zeroReader) Read(p []byte) (int, error) {\n\tfor i := range p {\n\t\tp[i] = 0\n\t}\n\n\treturn len(p), nil\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/objcopy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pe\n\nimport (\n\t\"context\"\n\t\"debug/pe\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n)\n\n// AssembleObjcopy is a helper function to assemble the PE file using objcopy.\nfunc AssembleObjcopy(ctx context.Context, srcPath, dstPath string, sections []Section) error {\n\tpeFile, err := pe.Open(srcPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer peFile.Close() //nolint: errcheck\n\n\t// find the first VMA address\n\tlastSection := peFile.Sections[len(peFile.Sections)-1]\n\n\theader, ok := peFile.OptionalHeader.(*pe.OptionalHeader64)\n\tif !ok {\n\t\treturn errors.New(\"failed to get optional header\")\n\t}\n\n\tsectionAlignment := uint64(header.SectionAlignment - 1)\n\n\tbaseVMA := header.ImageBase + uint64(lastSection.VirtualAddress) + uint64(lastSection.VirtualSize)\n\tbaseVMA = (baseVMA + sectionAlignment) &^ sectionAlignment\n\n\t// calculate sections size and VMA\n\tfor i := range sections {\n\t\tif !sections[i].Append {\n\t\t\tcontinue\n\t\t}\n\n\t\tst, err := os.Stat(sections[i].Path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsections[i].virtualSize = uint64(st.Size())\n\t\tsections[i].virtualAddress = baseVMA\n\n\t\tbaseVMA += sections[i].virtualSize\n\t\tbaseVMA = (baseVMA + sectionAlignment) &^ sectionAlignment\n\t}\n\n\t// create the output file\n\targs := make([]string, 0, len(sections)+2)\n\n\tfor _, section := range sections {\n\t\tif !section.Append {\n\t\t\tcontinue\n\t\t}\n\n\t\targs = append(args, \"--add-section\", fmt.Sprintf(\"%s=%s\", section.Name, section.Path), \"--change-section-vma\", fmt.Sprintf(\"%s=0x%x\", section.Name, section.virtualAddress))\n\t}\n\n\targs = append(args, srcPath, dstPath)\n\n\tcmd := exec.CommandContext(ctx, \"objcopy\", args...)\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\treturn cmd.Run()\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/pe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package pe handles appending sections to PE files.\npackage pe\n\n// Section is a UKI file section.\ntype Section struct {\n\t// Section name.\n\tName string\n\t// Path to the contents of the section.\n\tPath string\n\t// Should the section be measured to the TPM?\n\tMeasure bool\n\t// Should the section be appended, or is it already in the PE file.\n\tAppend bool\n\t// Virtual virtualSize & VMA of the section.\n\tvirtualSize    uint64\n\tvirtualAddress uint64\n}\n"
  },
  {
    "path": "internal/pkg/uki/internal/pe/pe_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage pe_test\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/uki/internal/pe\"\n)\n\nfunc assertToolsPresent(t *testing.T) {\n\tt.Helper()\n\n\tfor _, tool := range []string{\n\t\t\"objcopy\",\n\t\t\"objdump\",\n\t\t\"xxd\",\n\t} {\n\t\t_, err := exec.LookPath(tool)\n\t\tif err != nil {\n\t\t\tt.Skipf(\"missing tool: %s\", tool)\n\t\t}\n\t}\n}\n\nfunc TestAssembleNative(t *testing.T) {\n\tassertToolsPresent(t)\n\n\tt.Setenv(\"SOURCE_DATE_EPOCH\", \"1609459200\")\n\n\ttmpDir := t.TempDir()\n\n\toutNative := filepath.Join(tmpDir, \"uki-native.bin\")\n\toutObjcopy := filepath.Join(tmpDir, \"uki-objcopy.bin\")\n\n\tunamePath := filepath.Join(tmpDir, \"uname\")\n\trequire.NoError(t, os.WriteFile(unamePath, []byte(\"Talos\"), 0o644))\n\n\tlinuxPath := filepath.Join(tmpDir, \"linux\")\n\trequire.NoError(t, os.WriteFile(linuxPath, bytes.Repeat([]byte{0xde, 0xad, 0xbe, 0xef}, 1048576), 0o644))\n\n\tsections := func() []pe.Section {\n\t\treturn []pe.Section{\n\t\t\t{\n\t\t\t\tName: \".text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \".uname\",\n\t\t\t\tAppend: true,\n\n\t\t\t\tPath: unamePath,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \".linux\",\n\t\t\t\tAppend: true,\n\n\t\t\t\tPath: linuxPath,\n\t\t\t},\n\t\t}\n\t}\n\n\trequire.NoError(t, pe.AssembleNative(\"testdata/linuxx64.efi.stub\", outNative, sections()))\n\n\trequire.NoError(t, pe.AssembleObjcopy(t.Context(), \"testdata/linuxx64.efi.stub\", outObjcopy, sections()))\n\n\theadersNative := dumpHeaders(t, outNative)\n\theadersObjcopy := dumpHeaders(t, outObjcopy)\n\n\t// we don't compute the checksums, so ignore these fields\n\theadersObjcopy = regexp.MustCompile(`(CheckSum\\s+)[0-9a-fA-F]+`).ReplaceAllString(headersObjcopy, \"${1}00000000\")\n\t// we don't set linker version\n\theadersObjcopy = regexp.MustCompile(`((Major|Minor)LinkerVersion\\s+)[0-9.]+`).ReplaceAllString(headersObjcopy, \"${1}0\")\n\n\tassert.Equal(t, headersObjcopy, headersNative)\n\n\tfor _, sectionName := range []string{\n\t\t\".text\",\n\t\t\".rodata\",\n\t\t\".data\",\n\t\t\".sbat\",\n\t\t\".sdmagic\",\n\t\t\".reloc\",\n\t\t\".uname\",\n\t\t\".linux\",\n\t} {\n\t\tsectionObjcopy := extractSection(t, outObjcopy, sectionName)\n\t\tsectionNative := extractSection(t, outNative, sectionName)\n\n\t\tassert.Equal(t, sectionObjcopy, sectionNative)\n\t}\n\n\tif false {\n\t\t// deep binary comparison, disabled by default, as there will be some difference always\n\t\tbinaryObjcopy := binaryDump(t, outObjcopy)\n\t\tbinaryNative := binaryDump(t, outNative)\n\n\t\tassert.Equal(t, binaryObjcopy, binaryNative)\n\t}\n}\n\nfunc dumpHeaders(t *testing.T, path string) string {\n\tt.Helper()\n\n\toutput, err := exec.CommandContext(t.Context(), \"objdump\", \"-x\", path).CombinedOutput()\n\trequire.NoError(t, err, string(output))\n\n\toutput = bytes.ReplaceAll(output, []byte(path), []byte(\"uki.bin\"))\n\n\treturn string(output)\n}\n\nfunc binaryDump(t *testing.T, path string) string {\n\tt.Helper()\n\n\toutput, err := exec.CommandContext(t.Context(), \"xxd\", path).CombinedOutput()\n\trequire.NoError(t, err, string(output))\n\n\treturn string(output)\n}\n\nfunc extractSection(t *testing.T, path, section string) string {\n\tt.Helper()\n\n\toutput, err := exec.CommandContext(t.Context(), \"objdump\", \"-s\", \"--section\", section, path).CombinedOutput()\n\trequire.NoError(t, err, string(output))\n\n\toutput = bytes.ReplaceAll(output, []byte(path), []byte(\"uki.bin\"))\n\n\treturn string(output)\n}\n\nfunc TestMultipleSections(t *testing.T) {\n\tassertToolsPresent(t)\n\n\ttmpDir := t.TempDir()\n\n\tunamePath := filepath.Join(tmpDir, \"uname\")\n\trequire.NoError(t, os.WriteFile(unamePath, []byte(\"Talos\"), 0o644))\n\n\tunameNewPath := filepath.Join(tmpDir, \"uname-new\")\n\trequire.NoError(t, os.WriteFile(unameNewPath, []byte(\"Talos-new\"), 0o644))\n\n\toutNative := filepath.Join(tmpDir, \"uki-native.bin\")\n\n\tsections := func() []pe.Section {\n\t\treturn []pe.Section{\n\t\t\t{\n\t\t\t\tName: \".text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \".uname\",\n\t\t\t\tAppend: true,\n\t\t\t\tPath:   unamePath,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \".uname\",\n\t\t\t\tAppend: true,\n\t\t\t\tPath:   unameNewPath,\n\t\t\t},\n\t\t}\n\t}\n\n\trequire.NoError(t, pe.AssembleNative(\"testdata/linuxx64.efi.stub\", outNative, sections()))\n\n\tsectionContents := extractSection(t, outNative, \".uname\")\n\n\tassert.Contains(t, sectionContents, \"Talos\")\n\tassert.Contains(t, sectionContents, \"Talos-new\")\n}\n"
  },
  {
    "path": "internal/pkg/uki/kernel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"os\"\n\t\"strings\"\n)\n\n// DiscoverKernelVersion reads kernel version from the kernel image.\n//\n// This only works for x86 kernel images.\n//\n// Based on https://www.kernel.org/doc/html/v5.6/x86/boot.html.\nfunc DiscoverKernelVersion(kernelPath string) (string, error) {\n\tf, err := os.Open(kernelPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\theader := make([]byte, 1024)\n\n\t_, err = f.Read(header)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// check header magic\n\tif string(header[0x202:0x206]) != \"HdrS\" {\n\t\treturn \"\", errors.New(\"invalid kernel image\")\n\t}\n\n\tsetupSects := header[0x1f1]\n\tversionOffset := binary.LittleEndian.Uint16(header[0x20e:0x210])\n\n\tif versionOffset == 0 {\n\t\treturn \"\", errors.New(\"no kernel version\")\n\t}\n\n\tif versionOffset > uint16(setupSects)*0x200 {\n\t\treturn \"\", errors.New(\"invalid kernel version offset\")\n\t}\n\n\tversionOffset += 0x200\n\n\tversion := make([]byte, 256)\n\n\t_, err = f.ReadAt(version, int64(versionOffset))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tidx := bytes.IndexByte(version, 0) //nolint:modernize // this way is better\n\tif idx == -1 {\n\t\treturn \"\", errors.New(\"invalid kernel version\")\n\t}\n\n\tversionString := string(version[:idx])\n\tversionString, _, _ = strings.Cut(versionString, \" \")\n\n\treturn versionString, nil\n}\n"
  },
  {
    "path": "internal/pkg/uki/kernel_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n)\n\nfunc TestKernelVersion(t *testing.T) {\n\tversion, err := uki.DiscoverKernelVersion(\"testdata/kernel\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"6.1.58-talos\", version)\n}\n"
  },
  {
    "path": "internal/pkg/uki/sbat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki\n\nimport (\n\t\"debug/pe\"\n\t\"errors\"\n)\n\n// GetSBAT returns the SBAT section from the PE file.\nfunc GetSBAT(path string) ([]byte, error) {\n\tpefile, err := pe.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer pefile.Close() //nolint:errcheck\n\n\tif sectionData := pefile.Section(SectionSBAT.String()); sectionData != nil {\n\t\tdata, err := sectionData.Data()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn data[:sectionData.VirtualSize], nil\n\t}\n\n\treturn nil, errors.New(\"could not find SBAT section\")\n}\n"
  },
  {
    "path": "internal/pkg/uki/sbat_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n)\n\nfunc TestGetSBAT(t *testing.T) {\n\tt.Parallel()\n\n\tdata, err := uki.GetSBAT(\"internal/pe/testdata/linuxx64.efi.stub\")\n\trequire.NoError(t, err)\n\n\trequire.Equal(t,\n\t\t\"sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md\\nsystemd-stub,1,The systemd Developers,systemd,257,https://systemd.io/\\nsystemd-stub.talos,1,Talos Linux,systemd,257.2257.2,https://github.com/siderolabs/tools/issues\\n\", //nolint:lll\n\t\tstring(data),\n\t)\n}\n"
  },
  {
    "path": "internal/pkg/uki/uki.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package uki creates the UKI file out of the sd-stub and other sections.\npackage uki\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n\t\"github.com/siderolabs/talos/internal/pkg/uki/internal/pe\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n)\n\n// Section is a name of a PE file section (UEFI binary).\ntype Section string\n\n// List of well-known section names.\nconst (\n\tSectionLinux   Section = \".linux\"\n\tSectionOSRel   Section = \".osrel\"\n\tSectionCmdline Section = \".cmdline\"\n\tSectionInitrd  Section = \".initrd\"\n\tSectionUcode   Section = \".ucode\"\n\tSectionSplash  Section = \".splash\"\n\tSectionDTB     Section = \".dtb\"\n\tSectionUname   Section = \".uname\"\n\tSectionSBAT    Section = \".sbat\"\n\tSectionPCRSig  Section = \".pcrsig\"\n\tSectionPCRPKey Section = \".pcrpkey\"\n\tSectionProfile Section = \".profile\"\n\tSectionDTBAuto Section = \".dtbauto\"\n\tSectionHWIDS   Section = \".hwids\"\n)\n\n// String returns the string representation of the section.\nfunc (s Section) String() string {\n\treturn string(s)\n}\n\ntype section = pe.Section\n\n// Builder is a UKI file builder.\ntype Builder struct {\n\t// Source options.\n\t//\n\t// Arch of the UKI file.\n\tArch string\n\t// Version of Talos.\n\tVersion string\n\t// Path to the sd-stub.\n\tSdStubPath string\n\t// Path to the sd-boot.\n\tSdBootPath string\n\t// Path to the kernel image.\n\tKernelPath string\n\t// Path to the initrd image.\n\tInitrdPath string\n\t// Kernel cmdline.\n\tCmdline string\n\t// SecureBoot certificate and signer.\n\tSecureBootSigner pesign.CertificateSigner\n\t// PCR signer.\n\tPCRSigner measure.RSAKey\n\t// Profiles to include in the UKI.\n\tProfiles []Profile\n\n\t// Output options:\n\t//\n\t// Path to the signed sd-boot.\n\tOutSdBootPath string\n\t// Path to the output UKI file.\n\tOutUKIPath string\n\n\t// fields initialized during build\n\tsections        []section\n\tscratchDir      string\n\tpeSigner        *pesign.Signer\n\tunsignedUKIPath string\n}\n\n// Profile is a UKI Profile.\n// For now only cmdline is supported.\ntype Profile struct {\n\tID    string\n\tTitle string\n\n\tCmdline string\n}\n\n// String returns the string representation of the profile that gets adds to the `.profile` section.\nfunc (p Profile) String() string {\n\ts := fmt.Sprintf(\"ID=%s\", p.ID)\n\n\tif p.Title != \"\" {\n\t\ts += fmt.Sprintf(\"\\nTITLE=%s\", p.Title)\n\t}\n\n\treturn s\n}\n\n// Build the unsigned UKI file.\n//\n// Build process is as follows:\n//   - build ephemeral sections (uname, os-release), and other proposed sections\n//   - assemble the final UKI file starting from sd-stub and appending generated section.\nfunc (builder *Builder) Build(printf func(string, ...any)) error {\n\tvar err error\n\n\tbuilder.scratchDir, err = os.MkdirTemp(\"\", \"talos-uki\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif err = os.RemoveAll(builder.scratchDir); err != nil {\n\t\t\tlog.Printf(\"failed to remove scratch dir: %v\", err)\n\t\t}\n\t}()\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(builder.SdBootPath, builder.OutSdBootPath)); err != nil {\n\t\treturn err\n\t}\n\n\tprintf(\"generating UKI sections\")\n\n\t// generate and build list of all sections\n\tfor _, generateSection := range []func() error{\n\t\tbuilder.generateSBAT,\n\t\tbuilder.generateOSRel,\n\t\tbuilder.generateCmdline,\n\t\tbuilder.generateUname,\n\t\tbuilder.generateSplash,\n\t\tbuilder.generateKernel,\n\t\tbuilder.generateInitrd,\n\t\tbuilder.generateProfiles,\n\t} {\n\t\tif err = generateSection(); err != nil {\n\t\t\treturn fmt.Errorf(\"error generating sections: %w\", err)\n\t\t}\n\t}\n\n\tprintf(\"assembling UKI\")\n\n\t// assemble the final UKI file\n\tif err = builder.assemble(); err != nil {\n\t\treturn fmt.Errorf(\"error assembling UKI: %w\", err)\n\t}\n\n\treturn utils.CopyFiles(printf, utils.SourceDestination(builder.unsignedUKIPath, builder.OutUKIPath))\n}\n\n// BuildSigned the UKI file.\n//\n// BuildSigned process is as follows:\n//   - sign the sd-boot EFI binary, and write it to the OutSdBootPath\n//   - build ephemeral sections (uname, os-release), and other proposed sections\n//   - measure sections, generate signature, and append to the list of sections\n//   - assemble the final UKI file starting from sd-stub and appending generated section.\nfunc (builder *Builder) BuildSigned(printf func(string, ...any)) error {\n\tvar err error\n\n\tbuilder.scratchDir, err = os.MkdirTemp(\"\", \"talos-uki\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif err = os.RemoveAll(builder.scratchDir); err != nil {\n\t\t\tlog.Printf(\"failed to remove scratch dir: %v\", err)\n\t\t}\n\t}()\n\n\tprintf(\"signing systemd-boot\")\n\n\tbuilder.peSigner, err = pesign.NewSigner(builder.SecureBootSigner)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing signer: %w\", err)\n\t}\n\n\t// sign sd-boot\n\tif err = builder.peSigner.Sign(builder.SdBootPath, builder.OutSdBootPath); err != nil {\n\t\treturn fmt.Errorf(\"error signing sd-boot: %w\", err)\n\t}\n\n\tprintf(\"generating UKI sections\")\n\n\t// generate and build list of all sections\n\tfor _, generateSection := range []func() error{\n\t\tbuilder.generateSBAT,\n\t\tbuilder.generateOSRel,\n\t\tbuilder.generateCmdline,\n\t\tbuilder.generateUname,\n\t\tbuilder.generateSplash,\n\t\tbuilder.generatePCRPublicKey,\n\t\tbuilder.generateKernel,\n\t\tbuilder.generateInitrd,\n\t\tbuilder.generateProfiles,\n\t\tbuilder.generatePCRSig,\n\t} {\n\t\tif err = generateSection(); err != nil {\n\t\t\treturn fmt.Errorf(\"error generating sections: %w\", err)\n\t\t}\n\t}\n\n\tprintf(\"assembling UKI\")\n\n\t// assemble the final UKI file\n\tif err = builder.assemble(); err != nil {\n\t\treturn fmt.Errorf(\"error assembling UKI: %w\", err)\n\t}\n\n\tprintf(\"signing UKI\")\n\n\t// sign the UKI file\n\treturn builder.peSigner.Sign(builder.unsignedUKIPath, builder.OutUKIPath)\n}\n\n// Extract extracts the kernel, initrd, and cmdline from the UKI file.\nfunc Extract(ukiPath string) (asset pe.AssetInfo, err error) {\n\treturn pe.Extract(ukiPath)\n}\n"
  },
  {
    "path": "internal/pkg/uki/uki_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage uki_test\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\tstdx509 \"crypto/x509\"\n\t\"debug/pe\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/splash\"\n)\n\ntype certificateProvider struct {\n\t*x509.CertificateAuthority\n}\n\nfunc (c *certificateProvider) Signer() crypto.Signer {\n\treturn c.CertificateAuthority.Key.(crypto.Signer)\n}\n\nfunc (c *certificateProvider) Certificate() *stdx509.Certificate {\n\treturn c.CertificateAuthority.Crt\n}\n\ntype rsaWrapper struct {\n\t*rsa.PrivateKey\n}\n\nfunc (w rsaWrapper) PublicRSAKey() *rsa.PublicKey {\n\treturn &w.PrivateKey.PublicKey\n}\n\nfunc loadRSAKey(path string) (measure.RSAKey, error) {\n\tkeyData, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert private key to rsa.PrivateKey\n\trsaPrivateKeyBlock, _ := pem.Decode(keyData)\n\tif rsaPrivateKeyBlock == nil {\n\t\treturn nil, err\n\t}\n\n\trsaKey, err := stdx509.ParsePKCS1PrivateKey(rsaPrivateKeyBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parse private key failed: %v\", err)\n\t}\n\n\treturn rsaWrapper{rsaKey}, nil\n}\n\n// TestBuildUKI tests the UKI build process for both normal and signed UKI with and without multi profile ukis.\n// It uses the UKI build process from the uki package and the ukify tool to\n// generate a UKI file and then compares the generated UKI file with the UKI\n// file generated by the ukify tool.\n// This test requires a patched version of ukify that allows `enter-machined` as a phase and drop the trailing null character from sbat\n// since Talos UKI generation doesn't update sbat\n// diff --git src/ukify/ukify.py src/ukify/ukify.py\n// index 639301bdb6..0ab9394c2b 100755\n// --- src/ukify/ukify.py\n// +++ src/ukify/ukify.py\n// @@ -622,6 +622,7 @@ def parse_banks(s: str) -> list[str]:\n//\n//\t\tKNOWN_PHASES = (\n//\t\t    'enter-initrd',\n//\t\t    'leave-initrd',\n//\t  - 'enter-machined',\n//\t    'sysinit',\n//\t    'ready',\n//\t    'shutdown',\n//\n// @@ -1046,7 +1047,7 @@ def merge_sbat(input_pe: list[Path], input_text: list[str]) -> str:\n//\n//\t\treturn (\n//\t\t    'sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md\\n'\n//\t\t    + '\\n'.join(sbat)\n//\t  - + '\\n\\x00'\n//\t  - + '\\n'\n//\t    )\nfunc TestBuildUKI(t *testing.T) {\n\trequiredTools := []string{\n\t\t\"ukify\",\n\t\t\"sbverify\",\n\t\t\"sbsign\",\n\t\t\"systemd-measure\",\n\t}\n\n\tallToolsFound := true\n\n\tfor _, tool := range requiredTools {\n\t\tif _, err := exec.LookPath(tool); err != nil {\n\t\t\tt.Logf(\"tool %s not found\", tool)\n\n\t\t\tallToolsFound = false\n\t\t}\n\t}\n\n\tif !allToolsFound {\n\t\tt.Skipf(\"skipping test as some required tools %s not found\", strings.Join(requiredTools, \", \"))\n\t}\n\n\tcurrentTime := time.Now()\n\n\topts := []x509.Option{\n\t\tx509.RSA(true),\n\t\tx509.Bits(2048),\n\t\tx509.CommonName(\"test-sign\"),\n\t\tx509.NotAfter(currentTime.Add(secrets.CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.Organization(\"test-sign\"),\n\t}\n\n\tsigningKey, err := x509.NewSelfSignedCertificateAuthority(opts...)\n\trequire.NoError(t, err)\n\n\tpcrSigningKey := \"../measure/testdata/pcr-signing-key.pem\"\n\n\trsaKey, err := loadRSAKey(pcrSigningKey)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\ttempDir := t.TempDir()\n\n\tpublicKeyBytes, err := stdx509.MarshalPKIXPublicKey(rsaKey.PublicRSAKey())\n\trequire.NoError(t, err)\n\n\tpublicKeyPEM := pem.EncodeToMemory(&pem.Block{\n\t\tType:  x509.PEMTypeRSAPublic,\n\t\tBytes: publicKeyBytes,\n\t})\n\n\tpcrPubKey := filepath.Join(tempDir, \"pcr-public.pem\")\n\n\trequire.NoError(t, os.WriteFile(pcrPubKey, publicKeyPEM, 0o600))\n\n\tsdBootSigned := filepath.Join(tempDir, \"sd-boot-signed.efi\")\n\tkernel := \"testdata/kernel\"\n\tinitrd := \"testdata/kernel\" // we don't have a real initrd file, so we use the kernel file\n\tcmdline := \"console=ttyS0\"\n\tsplashImage := filepath.Join(tempDir, \"splash\")\n\tosReleaseFile := filepath.Join(tempDir, \"os-release\")\n\tsecureBootSingingKey := filepath.Join(tempDir, \"sb-key.pem\")\n\tsecureBootCertificate := filepath.Join(tempDir, \"sb-cert.pem\")\n\tsdStubPath := \"internal/pe/testdata/linuxx64.efi.stub\"\n\taddonStubPath := \"internal/pe/testdata/addonx64.efi.stub\"\n\n\tukiProfiles := []uki.Profile{\n\t\t{\n\t\t\tID:    \"reset-maintenance\",\n\t\t\tTitle: \"Reset to maintenance mode\",\n\n\t\t\tCmdline: cmdline + fmt.Sprintf(\" %s=system:EPHEMERAL,STATE\", constants.KernelParamWipe),\n\t\t},\n\t\t{\n\t\t\tID:      \"reset\",\n\t\t\tTitle:   \"Reset system disk\",\n\t\t\tCmdline: cmdline + fmt.Sprintf(\" %s=system\", constants.KernelParamWipe),\n\t\t},\n\t}\n\n\tfor _, talosVersion := range []string{\"1.9.0\", \"1.10.0\"} {\n\t\tukiUnsigned := filepath.Join(tempDir, fmt.Sprintf(\"uki-%s.efi\", talosVersion))\n\t\tukiSigned := filepath.Join(tempDir, fmt.Sprintf(\"uki-%s-signed.efi\", talosVersion))\n\t\tukifyUKIUnsigned := filepath.Join(tempDir, fmt.Sprintf(\"uki-ukify-%s.efi\", talosVersion))\n\t\tukifyUKISigned := filepath.Join(tempDir, fmt.Sprintf(\"uki-ukify-signed-%s.efi\", talosVersion))\n\n\t\tbuilder := &uki.Builder{\n\t\t\tArch:       \"amd64\",\n\t\t\tVersion:    talosVersion,\n\t\t\tSdStubPath: sdStubPath,\n\t\t\tSdBootPath: sdStubPath, // this doesn't matter for the test\n\t\t\tKernelPath: kernel,\n\t\t\tInitrdPath: initrd,\n\t\t\tCmdline:    cmdline,\n\t\t\tProfiles:   ukiProfiles,\n\n\t\t\tOutSdBootPath: sdBootSigned,\n\t\t\tOutUKIPath:    ukiUnsigned,\n\t\t}\n\n\t\trequire.NoError(t, builder.Build(t.Logf))\n\n\t\tsignedBuilder := &uki.Builder{\n\t\t\tArch:             \"amd64\",\n\t\t\tVersion:          talosVersion,\n\t\t\tSdStubPath:       sdStubPath,\n\t\t\tSdBootPath:       sdStubPath, // this doesn't matter for the test\n\t\t\tKernelPath:       kernel,\n\t\t\tInitrdPath:       initrd,\n\t\t\tCmdline:          cmdline,\n\t\t\tSecureBootSigner: &certificateProvider{signingKey},\n\t\t\tPCRSigner:        rsaKey,\n\t\t\tProfiles:         ukiProfiles,\n\n\t\t\tOutSdBootPath: sdBootSigned,\n\t\t\tOutUKIPath:    ukiSigned,\n\t\t}\n\n\t\trequire.NoError(t, signedBuilder.BuildSigned(t.Logf))\n\n\t\trequire.NoError(t, os.WriteFile(splashImage, splash.GetBootImage(), 0o600))\n\n\t\tosRelease, err := version.OSReleaseFor(version.Name, builder.Version)\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, os.WriteFile(osReleaseFile, osRelease, 0o600))\n\n\t\tkernelVersion, err := uki.DiscoverKernelVersion(builder.KernelPath)\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, os.WriteFile(secureBootCertificate, signingKey.CrtPEM, 0o600))\n\t\trequire.NoError(t, os.WriteFile(secureBootSingingKey, signingKey.KeyPEM, 0o600))\n\n\t\tukifyCmdArgs := []string{\n\t\t\t\"build\",\n\t\t\t\"--stub\",\n\t\t\tbuilder.SdStubPath,\n\t\t\t\"--sbat\",\n\t\t\t\"sbat,\", // this is a hack so that ukify doesn't add extra sbat info\n\t\t\t\"--splash\",\n\t\t\tsplashImage,\n\t\t\t\"--linux\",\n\t\t\tkernel,\n\t\t\t\"--initrd\",\n\t\t\tinitrd,\n\t\t\t\"--os-release\",\n\t\t\t\"@\" + osReleaseFile,\n\t\t\t\"--uname\",\n\t\t\tkernelVersion,\n\t\t\t\"--cmdline\",\n\t\t\tcmdline,\n\t\t\t\"--output\",\n\t\t\tukifyUKIUnsigned,\n\t\t}\n\n\t\tukifySignedCmdArgs := []string{\n\t\t\t\"build\",\n\t\t\t\"--stub\",\n\t\t\tsignedBuilder.SdStubPath,\n\t\t\t\"--sbat\",\n\t\t\t\"sbat,\", // this is a hack so that ukify doesn't add extra sbat info\n\t\t\t\"--splash\",\n\t\t\tsplashImage,\n\t\t\t\"--linux\",\n\t\t\tkernel,\n\t\t\t\"--initrd\",\n\t\t\tinitrd,\n\t\t\t\"--os-release\",\n\t\t\t\"@\" + osReleaseFile,\n\t\t\t\"--uname\",\n\t\t\tkernelVersion,\n\t\t\t\"--cmdline\",\n\t\t\tcmdline,\n\t\t\t\"--pcr-private-key\",\n\t\t\tpcrSigningKey,\n\t\t\t\"--pcrpkey\",\n\t\t\tpcrPubKey,\n\t\t\t\"--secureboot-private-key\",\n\t\t\tsecureBootSingingKey,\n\t\t\t\"--secureboot-certificate\",\n\t\t\tsecureBootCertificate,\n\t\t\t\"--pcr-banks\",\n\t\t\t\"sha256,sha384,sha512\",\n\t\t\t\"--phases\",\n\t\t\t\"enter-initrd:leave-initrd:enter-machined\",\n\t\t\t\"--output\",\n\t\t\tukifyUKISigned,\n\t\t}\n\n\t\tif quirks.New(talosVersion).SupportsUKIProfiles() {\n\t\t\tresetMaintenanceProfile := filepath.Join(tempDir, \"profile0.efi\")\n\t\t\tresetProfile := filepath.Join(tempDir, \"profile1.efi\")\n\n\t\t\tukifyResetMaintenanceProfileCmd := exec.CommandContext(\n\t\t\t\tt.Context(),\n\t\t\t\t\"ukify\",\n\t\t\t\t[]string{\n\t\t\t\t\t\"build\",\n\t\t\t\t\t\"--stub\",\n\t\t\t\t\taddonStubPath,\n\t\t\t\t\t\"--profile\",\n\t\t\t\t\t\"ID=reset-maintenance\\nTITLE=Reset to maintenance mode\",\n\t\t\t\t\t\"--cmdline\",\n\t\t\t\t\tcmdline + fmt.Sprintf(\" %s=system:EPHEMERAL,STATE\", constants.KernelParamWipe),\n\t\t\t\t\t\"--output\",\n\t\t\t\t\tresetMaintenanceProfile,\n\t\t\t\t}...,\n\t\t\t)\n\n\t\t\tukifyResetMaintenanceProfileCmd.Stderr = os.Stderr\n\t\t\tukifyResetMaintenanceProfileCmd.Stdout = os.Stdout\n\n\t\t\tt.Log(\"Running ukify command:\", ukifyResetMaintenanceProfileCmd.String())\n\n\t\t\trequire.NoError(t, ukifyResetMaintenanceProfileCmd.Run())\n\n\t\t\tukifyResetProfileCmd := exec.CommandContext(\n\t\t\t\tt.Context(),\n\t\t\t\t\"ukify\",\n\t\t\t\t[]string{\n\t\t\t\t\t\"build\",\n\t\t\t\t\t\"--stub\",\n\t\t\t\t\taddonStubPath,\n\t\t\t\t\t\"--profile\",\n\t\t\t\t\t\"ID=reset\\nTITLE=Reset system disk\",\n\t\t\t\t\t\"--cmdline\",\n\t\t\t\t\tcmdline + fmt.Sprintf(\" %s=system\", constants.KernelParamWipe),\n\t\t\t\t\t\"--output\",\n\t\t\t\t\tresetProfile,\n\t\t\t\t}...,\n\t\t\t)\n\n\t\t\tukifyResetProfileCmd.Stderr = os.Stderr\n\t\t\tukifyResetProfileCmd.Stdout = os.Stdout\n\n\t\t\tt.Log(\"Running ukify command:\", ukifyResetProfileCmd.String())\n\n\t\t\trequire.NoError(t, ukifyResetProfileCmd.Run())\n\n\t\t\tukifyCmdArgs = append(ukifyCmdArgs,\n\t\t\t\t\"--join-profile\",\n\t\t\t\tresetMaintenanceProfile,\n\t\t\t\t\"--join-profile\",\n\t\t\t\tresetProfile,\n\t\t\t)\n\n\t\t\tukifySignedCmdArgs = append(ukifySignedCmdArgs,\n\t\t\t\t\"--join-profile\",\n\t\t\t\tresetMaintenanceProfile,\n\t\t\t\t\"--join-profile\",\n\t\t\t\tresetProfile,\n\t\t\t)\n\t\t}\n\n\t\tukifyCmd := exec.CommandContext(\n\t\t\tt.Context(),\n\t\t\t\"ukify\",\n\t\t\tukifyCmdArgs...,\n\t\t)\n\n\t\tukifyCmd.Stderr = os.Stderr\n\t\tukifyCmd.Stdout = os.Stdout\n\n\t\tt.Log(\"Running ukify command:\", ukifyCmd.String())\n\n\t\trequire.NoError(t, ukifyCmd.Run())\n\n\t\tcompareUKIFiles(t, ukiUnsigned, ukifyUKIUnsigned)\n\n\t\tukifySignedCmd := exec.CommandContext(\n\t\t\tt.Context(),\n\t\t\t\"ukify\",\n\t\t\tukifySignedCmdArgs...,\n\t\t)\n\n\t\tukifySignedCmd.Stderr = os.Stderr\n\t\tukifySignedCmd.Stdout = os.Stdout\n\n\t\tt.Log(\"Running ukify command:\", ukifySignedCmd.String())\n\n\t\trequire.NoError(t, ukifySignedCmd.Run())\n\n\t\tcompareUKIFiles(t, ukiSigned, ukifyUKISigned)\n\t}\n}\n\nfunc compareUKIFiles(t *testing.T, ukiNative, ukiUKIFY string) {\n\tukiData, err := pe.Open(ukiNative)\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, ukiData.Close())\n\t})\n\n\tukiDataUKIFY, err := pe.Open(ukiUKIFY)\n\trequire.NoError(t, err)\n\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, ukiDataUKIFY.Close())\n\t})\n\n\tif len(ukiData.Sections) != len(ukiDataUKIFY.Sections) {\n\t\tt.Fatalf(\"sections count mismatch: %d != %d\", len(ukiData.Sections), len(ukiDataUKIFY.Sections))\n\t}\n\n\tfor i, section := range ukiData.Sections {\n\t\tsectionUKIFY := ukiDataUKIFY.Sections[i]\n\n\t\tif section.Name != sectionUKIFY.Name {\n\t\t\tt.Fatalf(\"section name mismatch: %s != %s\", section.Name, sectionUKIFY.Name)\n\t\t}\n\n\t\tsectionReader := io.LimitReader(section.Open(), int64(section.VirtualSize))\n\n\t\tsectionReaderUKIFY := io.LimitReader(sectionUKIFY.Open(), int64(sectionUKIFY.VirtualSize))\n\n\t\tvar sectionData, sectionDataUKIFY strings.Builder\n\n\t\t_, err := io.Copy(&sectionData, sectionReader)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = io.Copy(&sectionDataUKIFY, sectionReaderUKIFY)\n\t\trequire.NoError(t, err)\n\n\t\texpected := sectionData.String()\n\t\tactual := sectionDataUKIFY.String()\n\n\t\tif section.Name == \".pcrsig\" {\n\t\t\texpected = strings.ReplaceAll(expected, \" \", \"\")\n\t\t\tactual = strings.ReplaceAll(actual, \" \", \"\")\n\t\t}\n\n\t\trequire.Equal(t, expected, actual, \"section %s at index %d differs\", section.Name, i)\n\t}\n}\n"
  },
  {
    "path": "internal/pkg/zboot/zboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package zboot provides a function to extract the kernel from a Zboot image.\npackage zboot\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/klauspost/compress/zstd\"\n\t\"golang.org/x/sys/unix\"\n)\n\n// Extract extracts the kernel from a Zboot image and returns a file descriptor of the extracted kernel.\nfunc Extract(kernel *os.File) (int, io.Closer, error) {\n\t// https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/tree/include/kexec-pe-zboot.h\n\tvar peZbootheaderData [28]byte\n\n\tif _, err := io.ReadFull(kernel, peZbootheaderData[:]); err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\t// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/firmware/efi/libstub/zboot-header.S\n\t// https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/pe.h#n42\n\tif !bytes.Equal(peZbootheaderData[:2], []byte(\"MZ\")) {\n\t\treturn 0, nil, fmt.Errorf(\"invalid PE Zboot header\")\n\t}\n\n\t// not a Zboot image, return\n\tif !bytes.Equal(peZbootheaderData[4:8], []byte(\"zimg\")) {\n\t\treturn int(kernel.Fd()), nil, nil\n\t}\n\n\tpayloadOffset := binary.LittleEndian.Uint32(peZbootheaderData[8:12])\n\n\tpayloadSize := binary.LittleEndian.Uint32(peZbootheaderData[12:16])\n\n\tif _, err := kernel.Seek(int64(payloadOffset), io.SeekStart); err != nil {\n\t\treturn 0, nil, fmt.Errorf(\"failed to seek to kernel zstd data from vmlinuz.efi: %w\", err)\n\t}\n\n\tz, err := zstd.NewReader(io.LimitReader(kernel, int64(payloadSize)))\n\tif err != nil {\n\t\treturn 0, nil, fmt.Errorf(\"failed to create zstd reader: %w\", err)\n\t}\n\n\tdefer z.Close()\n\n\tfd, err := unix.MemfdCreate(\"vmlinux\", 0)\n\tif err != nil {\n\t\treturn 0, nil, fmt.Errorf(\"memfdCreate: %v\", err)\n\t}\n\n\tkernelMemfd := os.NewFile(uintptr(fd), \"vmlinux\")\n\n\tif _, err := io.Copy(kernelMemfd, z); err != nil {\n\t\tkernelMemfd.Close() //nolint:errcheck\n\n\t\treturn 0, nil, fmt.Errorf(\"failed to copy zstd data to memfd: %w\", err)\n\t}\n\n\tif _, err := kernelMemfd.Seek(0, io.SeekStart); err != nil {\n\t\tkernelMemfd.Close() //nolint:errcheck\n\n\t\treturn 0, nil, fmt.Errorf(\"failed to seek to start of memfd: %w\", err)\n\t}\n\n\treturn fd, kernelMemfd, nil\n}\n"
  },
  {
    "path": "pkg/archiver/archiver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package archiver provides a service to archive part of the filesystem into tar archive.\npackage archiver\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"io\"\n)\n\n// TarGz produces .tar.gz archive of filesystem starting at rootPath.\nfunc TarGz(ctx context.Context, rootPath string, output io.Writer, walkerOptions ...WalkerOption) error {\n\tpaths, err := Walker(ctx, rootPath, append(walkerOptions, WithSkipRoot())...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tzw := gzip.NewWriter(output)\n\t//nolint:errcheck\n\tdefer zw.Close()\n\n\terr = Tar(ctx, paths, zw)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn zw.Close()\n}\n\n// UntarGz extracts .tar.gz archive to the rootPath.\nfunc UntarGz(ctx context.Context, input io.Reader, rootPath string) error {\n\tzr, err := gzip.NewReader(input)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t//nolint:errcheck\n\tdefer zr.Close()\n\n\terr = Untar(ctx, zr, rootPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn zr.Close()\n}\n"
  },
  {
    "path": "pkg/archiver/archiver_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver_test\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/stretchr/testify/suite\"\n)\n\ntype CommonSuite struct {\n\tsuite.Suite\n\n\ttmpDir string\n}\n\nvar filesFixture = []struct {\n\tPath     string\n\tMode     os.FileMode\n\tContents []byte\n\tSize     int\n}{\n\t{\n\t\tPath:     \"/etc/hostname\",\n\t\tMode:     0o644,\n\t\tContents: []byte(\"localhost\"),\n\t},\n\t{\n\t\tPath:     \"/etc/certs/ca.crt\",\n\t\tMode:     0o600,\n\t\tContents: []byte(\"-- CA PEM CERT -- VERY SECRET\"),\n\t},\n\t{\n\t\tPath: \"/dev/random\",\n\t\tMode: 0o600 | os.ModeDevice | os.ModeCharDevice,\n\t},\n\t{\n\t\tPath:     \"/usr/bin/cp\",\n\t\tMode:     0o755,\n\t\tContents: []byte(\"ELF EXECUTABLE IIRC\"),\n\t},\n\t{\n\t\tPath:     \"/usr/bin/mv\",\n\t\tMode:     0o644 | os.ModeSymlink,\n\t\tContents: []byte(\"/usr/bin/cp\"),\n\t},\n\t{\n\t\tPath:     \"/lib/dynalib.so\",\n\t\tMode:     0o644,\n\t\tContents: []byte(\"SOME LIBRARY OUT THERE\"),\n\t\tSize:     20 * 1024,\n\t},\n}\n\nfunc (suite *CommonSuite) SetupSuite() {\n\tsuite.tmpDir = suite.T().TempDir()\n\n\tfor _, file := range filesFixture {\n\t\tsuite.Require().NoError(os.MkdirAll(filepath.Join(suite.tmpDir, filepath.Dir(file.Path)), 0o777))\n\n\t\tif file.Mode&os.ModeSymlink != 0 {\n\t\t\tsuite.Require().NoError(os.Symlink(string(file.Contents), filepath.Join(suite.tmpDir, file.Path)))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tf, err := os.OpenFile(filepath.Join(suite.tmpDir, file.Path), os.O_CREATE|os.O_WRONLY, file.Mode)\n\t\tsuite.Require().NoError(err)\n\n\t\tvar contents []byte\n\n\t\tif file.Size > 0 {\n\t\t\tcontents = slices.Concat(\n\t\t\t\tbytes.Repeat(file.Contents, file.Size/len(file.Contents)),\n\t\t\t\tfile.Contents[:file.Size-file.Size/len(file.Contents)*len(file.Contents)],\n\t\t\t)\n\t\t} else {\n\t\t\tcontents = file.Contents\n\t\t}\n\n\t\t_, err = f.Write(contents)\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().NoError(f.Close())\n\t}\n}\n"
  },
  {
    "path": "pkg/archiver/tar.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"slices\"\n\t\"syscall\"\n\n\tmultierror \"github.com/hashicorp/go-multierror\"\n)\n\n// Tar creates .tar archive and writes it to output for every item in paths channel.\nfunc Tar(ctx context.Context, paths <-chan FileItem, output io.Writer) error {\n\ttw := tar.NewWriter(output)\n\t//nolint:errcheck\n\tdefer tw.Close()\n\n\tvar multiErr *multierror.Error\n\n\tbuf := make([]byte, 4096)\n\n\tfor fi := range paths {\n\t\tif fi.Error != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"skipping %q: %s\", fi.FullPath, fi.Error))\n\n\t\t\tcontinue\n\t\t}\n\n\t\terr := processFile(ctx, tw, fi, buf)\n\t\tif err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"skipping %q: %s\", fi.FullPath, err))\n\t\t}\n\t}\n\n\tif err := tw.Close(); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n//nolint:gocyclo\nfunc processFile(ctx context.Context, tw *tar.Writer, fi FileItem, buf []byte) error {\n\theader, err := tar.FileInfoHeader(fi.FileInfo, fi.Link)\n\tif err != nil {\n\t\t// not supported by tar\n\t\treturn err\n\t}\n\n\theader.Name = fi.RelPath\n\tif fi.FileInfo.IsDir() {\n\t\theader.Name += string(os.PathSeparator)\n\t}\n\n\tskipData := false\n\n\tswitch header.Typeflag {\n\tcase tar.TypeLink, tar.TypeSymlink, tar.TypeChar, tar.TypeBlock, tar.TypeDir, tar.TypeFifo:\n\t\t// no data for these types, move on\n\t\tskipData = true\n\t}\n\n\tvar r io.Reader\n\n\tif !skipData {\n\t\tvar fp *os.File\n\n\t\tfp, err = os.Open(fi.FullPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer fp.Close() //nolint:errcheck\n\n\t\tr = fp\n\t}\n\n\tif !skipData && header.Size == 0 {\n\t\t// Linux reports /proc files as zero length, but they might have data,\n\t\t// so we try to read limited amount of data from it to determine the size\n\t\tvar n int\n\n\t\tn, err = r.Read(buf)\n\n\t\tswitch {\n\t\tcase err == io.EOF:\n\t\t\t// file is empty for real\n\t\t\tskipData = true\n\t\tcase err != nil:\n\t\t\t// error reading from the file\n\t\t\tif errors.Is(err, syscall.EINVAL) {\n\t\t\t\t// some files are not supported by os.Open, e.g. /proc/sys/net/ipv4/conf/all/accept_local\n\t\t\t\tskipData = true\n\t\t\t} else {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase n < len(buf):\n\t\t\theader.Size = int64(n)\n\t\t\tr = bytes.NewReader(slices.Clone(buf[:n]))\n\t\tdefault:\n\t\t\t// none matched so the file is bigger than we expected, ignore it and copy as zero size\n\t\t\tskipData = true\n\t\t}\n\t}\n\n\terr = tw.WriteHeader(header)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif skipData {\n\t\treturn nil\n\t}\n\n\treturn archiveFile(ctx, tw, fi, r, buf)\n}\n\nfunc archiveFile(ctx context.Context, tw io.Writer, fi FileItem, r io.Reader, buf []byte) error {\n\tfor {\n\t\tn, err := r.Read(buf)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\t_, err = tw.Write(buf[:n])\n\t\tif err != nil {\n\t\t\tif err == tar.ErrWriteTooLong {\n\t\t\t\tlog.Printf(\"ignoring long write for %q\", fi.FullPath)\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/archiver/tar_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver_test\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/archiver\"\n)\n\ntype TarSuite struct {\n\tCommonSuite\n}\n\nfunc (suite *TarSuite) TestArchiveDir() {\n\tch, err := archiver.Walker(context.Background(), suite.tmpDir)\n\tsuite.Require().NoError(err)\n\n\tvar buf bytes.Buffer\n\n\terr = archiver.Tar(context.Background(), ch, &buf)\n\tsuite.Require().NoError(err)\n\n\tpathsSeen := map[string]struct{}{}\n\n\ttr := tar.NewReader(&buf)\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tsuite.Require().NoError(err)\n\n\t\tif hdr.Typeflag == tar.TypeDir {\n\t\t\tcontinue\n\t\t}\n\n\t\tcontents, err := io.ReadAll(tr)\n\t\tsuite.Require().NoError(err)\n\n\t\tfound := false\n\n\t\tfor _, fi := range filesFixture {\n\t\t\tif fi.Path[1:] == hdr.Name {\n\t\t\t\tfound = true\n\t\t\t\tpathsSeen[fi.Path] = struct{}{}\n\n\t\t\t\tswitch {\n\t\t\t\tcase fi.Mode&os.ModeSymlink != 0:\n\t\t\t\t\tsuite.Require().Equal(string(fi.Contents), hdr.Linkname)\n\t\t\t\tcase fi.Size > 0:\n\t\t\t\t\tsuite.Require().Len(contents, fi.Size)\n\t\t\t\tcase fi.Contents != nil:\n\t\t\t\t\tsuite.Require().EqualValues(fi.Contents, contents)\n\t\t\t\tdefault:\n\t\t\t\t\tsuite.Require().Len(contents, 0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsuite.Require().True(found, \"file %q\", hdr.Name)\n\t}\n\n\tfor _, fi := range filesFixture {\n\t\t_, ok := pathsSeen[fi.Path]\n\t\tsuite.Require().True(ok, \"path %q\", fi.Path)\n\t}\n}\n\nfunc (suite *TarSuite) TestArchiveFile() {\n\tch, err := archiver.Walker(context.Background(), filepath.Join(suite.tmpDir, \"/usr/bin/cp\"))\n\tsuite.Require().NoError(err)\n\n\tvar buf bytes.Buffer\n\n\terr = archiver.Tar(context.Background(), ch, &buf)\n\tsuite.Require().NoError(err)\n\n\ttr := tar.NewReader(&buf)\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tsuite.Require().NoError(err)\n\n\t\texpectedContents := []byte(\"ELF EXECUTABLE IIRC\")\n\n\t\tsuite.Require().EqualValues(hdr.Typeflag, tar.TypeReg)\n\t\tsuite.Require().EqualValues(hdr.Name, \"cp\")\n\t\tsuite.Require().EqualValues(hdr.Size, len(expectedContents))\n\n\t\tcontents, err := io.ReadAll(tr)\n\t\tsuite.Require().NoError(err)\n\n\t\tsuite.Require().Equal(expectedContents, contents)\n\t}\n}\n\nfunc (suite *TarSuite) TestArchiveProcfs() {\n\tch, err := archiver.Walker(context.Background(), \"/proc/self/\", archiver.WithMaxRecurseDepth(0))\n\tsuite.Require().NoError(err)\n\n\tvar buf bytes.Buffer\n\n\t// it's okay to have some errors here, as some files are not readable\n\tarchiver.Tar(context.Background(), ch, &buf) //nolint:errcheck\n\n\ttr := tar.NewReader(&buf)\n\n\texpectedNonZeroFiles := map[string]struct{}{\n\t\t\"cmdline\": {},\n\t\t\"environ\": {},\n\t\t\"limits\":  {},\n\t\t\"io\":      {},\n\t\t\"stat\":    {},\n\t}\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tsuite.Require().NoError(err)\n\n\t\tif _, expected := expectedNonZeroFiles[hdr.Name]; !expected {\n\t\t\tcontinue\n\t\t}\n\n\t\tsuite.Assert().EqualValues(hdr.Typeflag, tar.TypeReg)\n\t\tsuite.Assert().NotZero(hdr.Size)\n\n\t\tdelete(expectedNonZeroFiles, hdr.Name)\n\t}\n\n\tsuite.Assert().Empty(expectedNonZeroFiles)\n}\n\nfunc TestTarSuite(t *testing.T) {\n\tsuite.Run(t, new(TarSuite))\n}\n"
  },
  {
    "path": "pkg/archiver/untar.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver\n\nimport (\n\t\"archive/tar\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/pkg/xattr\"\n\n\t\"github.com/siderolabs/talos/pkg/safepath\"\n)\n\n// Untar extracts .tar archive from r into filesystem under rootPath.\n//\n//nolint:gocyclo\nfunc Untar(ctx context.Context, r io.Reader, rootPath string) error {\n\ttr := tar.NewReader(r)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\thdr, err := tr.Next()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error reading tar header: %s\", err)\n\t\t}\n\n\t\thdrPath := safepath.CleanPath(hdr.Name)\n\t\tif hdrPath == \"\" {\n\t\t\treturn errors.New(\"empty tar header path\")\n\t\t}\n\n\t\tpath := filepath.Join(rootPath, hdrPath)\n\n\t\tswitch hdr.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tmode := hdr.FileInfo().Mode() & os.ModePerm\n\t\t\tmode |= 0o700 // make rwx for the owner\n\n\t\t\tif err = os.Mkdir(path, mode); err != nil && !os.IsExist(err) {\n\t\t\t\treturn fmt.Errorf(\"error creating directory %q mode %s: %w\", path, mode, err)\n\t\t\t}\n\n\t\t\tif err = os.Chmod(path, mode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating mode %s for %q: %w\", mode, path, err)\n\t\t\t}\n\n\t\tcase tar.TypeSymlink:\n\t\t\tif err = os.Symlink(hdr.Linkname, path); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating symlink %q -> %q: %w\", path, hdr.Linkname, err)\n\t\t\t}\n\n\t\tdefault:\n\t\t\tmode := hdr.FileInfo().Mode()\n\n\t\t\tfp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_EXCL, mode)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating file %q mode %s: %w\", path, mode, err)\n\t\t\t}\n\n\t\t\t_, err = io.Copy(fp, tr)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error copying data to %q: %w\", path, err)\n\t\t\t}\n\n\t\t\tif err = fp.Close(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error closing %q: %w\", path, err)\n\t\t\t}\n\n\t\t\tif err = os.Chmod(path, mode); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error updating mode %s for %q: %w\", mode, path, err)\n\t\t\t}\n\t\t}\n\n\t\tif hdr.PAXRecords[\"SCHILY.xattr.security.selinux\"] != \"\" {\n\t\t\tif err = xattr.LSet(path, \"security.selinux\", []byte(hdr.PAXRecords[\"SCHILY.xattr.security.selinux\"])); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error setting selinux xattr for %q: %w\", path, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/archiver/walker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// FileItem is unit of work for archive.\ntype FileItem struct {\n\tFullPath string\n\tRelPath  string\n\tFileInfo os.FileInfo\n\tLink     string\n\tError    error\n}\n\n// FileType is a file type.\ntype FileType int\n\n// File types.\nconst (\n\tRegularFileType FileType = iota\n\tDirectoryFileType\n\tSymlinkFileType\n)\n\ntype walkerOptions struct {\n\tskipRoot        bool\n\tmaxRecurseDepth int\n\tfnmatchPatterns []string\n\ttypes           map[FileType]struct{}\n}\n\n// WalkerOption configures Walker.\ntype WalkerOption func(*walkerOptions)\n\n// WithSkipRoot skips root path if it's a directory.\nfunc WithSkipRoot() WalkerOption {\n\treturn func(o *walkerOptions) {\n\t\to.skipRoot = true\n\t}\n}\n\n// WithMaxRecurseDepth controls maximum recursion depth while walking file tree.\n//\n// Value of -1 disables depth control.\nfunc WithMaxRecurseDepth(maxDepth int) WalkerOption {\n\treturn func(o *walkerOptions) {\n\t\to.maxRecurseDepth = maxDepth\n\t}\n}\n\n// WithFnmatchPatterns filters results to match the patterns.\n//\n// Default is not to do any filtering.\nfunc WithFnmatchPatterns(patterns ...string) WalkerOption {\n\treturn func(o *walkerOptions) {\n\t\to.fnmatchPatterns = append(o.fnmatchPatterns, patterns...)\n\t}\n}\n\n// WithFileTypes filters results by file types.\n//\n// Default is not to do any filtering.\nfunc WithFileTypes(fileType ...FileType) WalkerOption {\n\treturn func(o *walkerOptions) {\n\t\to.types = make(map[FileType]struct{}, len(fileType))\n\t\tfor _, t := range fileType {\n\t\t\to.types[t] = struct{}{}\n\t\t}\n\t}\n}\n\n// Walker provides a channel of file info/paths for archival.\n//\n//nolint:gocyclo,cyclop\nfunc Walker(ctx context.Context, rootPath string, options ...WalkerOption) (<-chan FileItem, error) {\n\tvar opts walkerOptions\n\n\topts.maxRecurseDepth = -1\n\n\tfor _, o := range options {\n\t\to(&opts)\n\t}\n\n\tinfo, err := os.Lstat(rootPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif info.Mode()&os.ModeSymlink == os.ModeSymlink {\n\t\trootPath, err = filepath.EvalSymlinks(rootPath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tch := make(chan FileItem)\n\n\tgo func() {\n\t\tdefer close(ch)\n\n\t\terr := filepath.Walk(rootPath, func(path string, fileInfo os.FileInfo, walkErr error) error {\n\t\t\titem := FileItem{\n\t\t\t\tFullPath: path,\n\t\t\t\tFileInfo: fileInfo,\n\t\t\t\tError:    walkErr,\n\t\t\t}\n\t\t\tif path == rootPath && !fileInfo.IsDir() {\n\t\t\t\t// only one file\n\t\t\t\titem.RelPath = filepath.Base(path)\n\t\t\t} else if item.Error == nil {\n\t\t\t\titem.RelPath, item.Error = filepath.Rel(rootPath, path)\n\t\t\t}\n\n\t\t\t// TODO: refactor all those `if item.Error == nil &&` conditions\n\n\t\t\tif item.Error == nil && len(opts.types) > 0 {\n\t\t\t\tvar matches bool\n\n\t\t\t\tfor t := range opts.types {\n\t\t\t\t\tswitch t {\n\t\t\t\t\tcase RegularFileType:\n\t\t\t\t\t\tmatches = fileInfo.Mode()&os.ModeType == 0\n\t\t\t\t\tcase DirectoryFileType:\n\t\t\t\t\t\tmatches = fileInfo.Mode()&os.ModeDir != 0\n\t\t\t\t\tcase SymlinkFileType:\n\t\t\t\t\t\tmatches = fileInfo.Mode()&os.ModeSymlink != 0\n\t\t\t\t\t}\n\n\t\t\t\t\tif matches {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif !matches {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif item.Error == nil && path == rootPath && opts.skipRoot && fileInfo.IsDir() {\n\t\t\t\t// skip containing directory\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif item.Error == nil && fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {\n\t\t\t\titem.Link, item.Error = os.Readlink(path)\n\t\t\t}\n\n\t\t\tif item.Error == nil && len(opts.fnmatchPatterns) > 0 {\n\t\t\t\tvar matches bool\n\n\t\t\t\tfor _, pattern := range opts.fnmatchPatterns {\n\t\t\t\t\tif matches, _ = filepath.Match(pattern, item.RelPath); matches { //nolint:errcheck\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif !matches {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase ch <- item:\n\t\t\t}\n\n\t\t\tif item.Error == nil && fileInfo.IsDir() && atMaxDepth(opts.maxRecurseDepth, rootPath, path) {\n\t\t\t\treturn filepath.SkipDir\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\tcase ch <- FileItem{Error: err}:\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn ch, nil\n}\n\n// OSPathSeparator is the string version of the os.PathSeparator.\nconst OSPathSeparator = string(os.PathSeparator)\n\nfunc atMaxDepth(maximum int, root, cur string) bool {\n\tif maximum < 0 {\n\t\treturn false\n\t}\n\n\tif root == cur {\n\t\t// always recurse the root directory\n\t\treturn false\n\t}\n\n\treturn (strings.Count(cur, OSPathSeparator) - strings.Count(root, OSPathSeparator)) >= maximum\n}\n"
  },
  {
    "path": "pkg/archiver/walker_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage archiver_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/archiver\"\n)\n\ntype WalkerSuite struct {\n\tCommonSuite\n}\n\nfunc (suite *WalkerSuite) TestIterationDir() {\n\tch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithSkipRoot())\n\tsuite.Require().NoError(err)\n\n\trelPaths := []string(nil) //nolint:prealloc // this is a test\n\n\tfor fi := range ch {\n\t\tsuite.Require().NoError(fi.Error)\n\t\trelPaths = append(relPaths, fi.RelPath)\n\n\t\tif fi.RelPath == \"usr/bin/mv\" {\n\t\t\tsuite.Assert().Equal(\"/usr/bin/cp\", fi.Link)\n\t\t}\n\t}\n\n\tsuite.Assert().Equal([]string{\n\t\t\"dev\", \"dev/random\",\n\t\t\"etc\", \"etc/certs\", \"etc/certs/ca.crt\", \"etc/hostname\",\n\t\t\"lib\", \"lib/dynalib.so\",\n\t\t\"usr\", \"usr/bin\", \"usr/bin/cp\", \"usr/bin/mv\",\n\t},\n\t\trelPaths)\n}\n\nfunc (suite *WalkerSuite) TestIterationFilter() {\n\tch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithSkipRoot(), archiver.WithFnmatchPatterns(\"dev/*\", \"lib\"))\n\tsuite.Require().NoError(err)\n\n\trelPaths := []string(nil) //nolint:prealloc // this is a test\n\n\tfor fi := range ch {\n\t\tsuite.Require().NoError(fi.Error)\n\t\trelPaths = append(relPaths, fi.RelPath)\n\n\t\tif fi.RelPath == \"usr/bin/mv\" {\n\t\t\tsuite.Assert().Equal(\"/usr/bin/cp\", fi.Link)\n\t\t}\n\t}\n\n\tsuite.Assert().Equal([]string{\n\t\t\"dev/random\",\n\t\t\"lib\",\n\t},\n\t\trelPaths)\n}\n\nfunc (suite *WalkerSuite) TestIterationMaxRecurseDepth() {\n\tfor _, test := range []struct {\n\t\tmaxDepth int\n\t\tresult   []string\n\t}{\n\t\t{\n\t\t\tmaxDepth: -1,\n\t\t\tresult:   []string{\".\", \"dev\", \"dev/random\", \"etc\", \"etc/certs\", \"etc/certs/ca.crt\", \"etc/hostname\", \"lib\", \"lib/dynalib.so\", \"usr\", \"usr/bin\", \"usr/bin/cp\", \"usr/bin/mv\"},\n\t\t},\n\t\t{\n\t\t\t// confusing case\n\t\t\tmaxDepth: 0,\n\t\t\tresult:   []string{\".\", \"dev\", \"etc\", \"lib\", \"usr\"},\n\t\t},\n\t\t{\n\t\t\tmaxDepth: 1,\n\t\t\tresult:   []string{\".\", \"dev\", \"etc\", \"lib\", \"usr\"},\n\t\t},\n\t\t{\n\t\t\tmaxDepth: 2,\n\t\t\tresult:   []string{\".\", \"dev\", \"dev/random\", \"etc\", \"etc/certs\", \"etc/hostname\", \"lib\", \"lib/dynalib.so\", \"usr\", \"usr/bin\"},\n\t\t},\n\t\t{\n\t\t\tmaxDepth: 3,\n\t\t\tresult:   []string{\".\", \"dev\", \"dev/random\", \"etc\", \"etc/certs\", \"etc/certs/ca.crt\", \"etc/hostname\", \"lib\", \"lib/dynalib.so\", \"usr\", \"usr/bin\", \"usr/bin/cp\", \"usr/bin/mv\"},\n\t\t},\n\t\t{\n\t\t\tmaxDepth: 4,\n\t\t\tresult:   []string{\".\", \"dev\", \"dev/random\", \"etc\", \"etc/certs\", \"etc/certs/ca.crt\", \"etc/hostname\", \"lib\", \"lib/dynalib.so\", \"usr\", \"usr/bin\", \"usr/bin/cp\", \"usr/bin/mv\"},\n\t\t},\n\t} {\n\t\tsuite.Run(strconv.Itoa(test.maxDepth), func() {\n\t\t\tsuite.T().Parallel()\n\n\t\t\tch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithMaxRecurseDepth(test.maxDepth))\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tvar result []string //nolint:prealloc // this is a test\n\n\t\t\tfor fi := range ch {\n\t\t\t\tsuite.Require().NoError(fi.Error)\n\t\t\t\tresult = append(result, fi.RelPath)\n\t\t\t}\n\n\t\t\tsuite.Equal(test.result, result)\n\t\t})\n\t}\n}\n\nfunc (suite *WalkerSuite) TestIterationFile() {\n\tch, err := archiver.Walker(context.Background(), filepath.Join(suite.tmpDir, \"usr/bin/cp\"))\n\tsuite.Require().NoError(err)\n\n\trelPaths := []string(nil) //nolint:prealloc // this is a test\n\n\tfor fi := range ch {\n\t\tsuite.Require().NoError(fi.Error)\n\t\trelPaths = append(relPaths, fi.RelPath)\n\t}\n\n\tsuite.Assert().Equal([]string{\"cp\"},\n\t\trelPaths)\n}\n\nfunc (suite *WalkerSuite) TestIterationSymlink() {\n\toriginal := filepath.Join(suite.tmpDir, \"original\")\n\terr := os.Mkdir(original, 0o755)\n\tsuite.Require().NoError(err)\n\n\tdefer func() {\n\t\terr = os.RemoveAll(original)\n\t\tsuite.Require().NoError(err)\n\t}()\n\n\t// NB: We make this a relative symlink to make the test more complete.\n\tnewname := filepath.Join(suite.tmpDir, \"new\")\n\terr = os.Symlink(\"original\", newname)\n\tsuite.Require().NoError(err)\n\n\tdefer func() {\n\t\terr = os.Remove(newname)\n\t\tsuite.Require().NoError(err)\n\t}()\n\n\terr = os.WriteFile(filepath.Join(original, \"original.txt\"), []byte{}, 0o666)\n\tsuite.Require().NoError(err)\n\n\tch, err := archiver.Walker(context.Background(), newname)\n\tsuite.Require().NoError(err)\n\n\trelPaths := []string(nil) //nolint:prealloc // this is a test\n\n\tfor fi := range ch {\n\t\tsuite.Require().NoError(fi.Error)\n\t\trelPaths = append(relPaths, fi.RelPath)\n\t}\n\n\tsuite.Assert().Equal([]string{\".\", \"original.txt\"}, relPaths)\n}\n\nfunc (suite *WalkerSuite) TestIterationNotFound() {\n\t_, err := archiver.Walker(context.Background(), filepath.Join(suite.tmpDir, \"doesntlivehere\"))\n\tsuite.Require().Error(err)\n}\n\nfunc (suite *WalkerSuite) TestIterationTypes() {\n\tch, err := archiver.Walker(context.Background(), suite.tmpDir, archiver.WithFileTypes(archiver.DirectoryFileType))\n\tsuite.Require().NoError(err)\n\n\trelPaths := []string(nil) //nolint:prealloc // this is a test\n\n\tfor fi := range ch {\n\t\tsuite.Require().NoError(fi.Error)\n\t\trelPaths = append(relPaths, fi.RelPath)\n\t}\n\n\tsuite.Assert().Equal([]string{\n\t\t\".\", \"dev\", \"etc\", \"etc/certs\", \"lib\", \"usr\", \"usr/bin\",\n\t},\n\t\trelPaths)\n}\n\nfunc TestWalkerSuite(t *testing.T) {\n\tsuite.Run(t, new(WalkerSuite))\n}\n"
  },
  {
    "path": "pkg/argsbuilder/argsbuilder_args.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage argsbuilder\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n)\n\n// Key represents an arg key.\ntype Key = string\n\n// Value represents an arg value.\ntype Value = []string\n\n// Args represents a set of args.\ntype Args map[Key]Value\n\n// MustMerge implements the ArgsBuilder interface.\nfunc (a Args) MustMerge(args Args, setters ...MergeOption) {\n\tif err := a.Merge(args, setters...); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Merge implements the ArgsBuilder interface.\n//\n//nolint:gocyclo\nfunc (a Args) Merge(args Args, setters ...MergeOption) error {\n\tvar opts MergeOptions\n\n\tfor _, s := range setters {\n\t\ts(&opts)\n\t}\n\n\tpolicies := opts.Policies\n\tif policies == nil {\n\t\tpolicies = MergePolicies{}\n\t}\n\n\tfor key, val := range args {\n\t\tpolicy := policies[key]\n\n\t\tswitch policy {\n\t\tcase MergeDenied:\n\t\t\treturn NewDenylistError(key)\n\n\t\tcase MergeOverwrite:\n\t\t\ta[key] = slices.Clone(val)\n\n\t\tcase MergeAppend:\n\t\t\texisting := make([]string, 0, len(val)+len(a[key]))\n\t\t\texisting = append(existing, a[key]...)\n\t\t\texisting = append(existing, val...)\n\t\t\ta[key] = existing\n\n\t\tcase MergePrepend:\n\t\t\texisting := make([]string, 0, len(val)+len(a[key]))\n\t\t\texisting = append(existing, val...)\n\t\t\texisting = append(existing, a[key]...)\n\t\t\ta[key] = existing\n\n\t\tcase MergeAdditive:\n\t\t\t// 1. Join the existing []string slice into one string so we can Split it.\n\t\t\t//    This handles cases where a[key] might be [\"a\", \"b\"] or [\"a,b\"].\n\t\t\trawExisting := strings.Join(a[key], \",\")\n\t\t\tvalues := strings.Split(rawExisting, \",\")\n\n\t\t\tdefinedValues := map[string]struct{}{}\n\t\t\ti := 0\n\n\t\t\tfor _, v := range values {\n\t\t\t\tcleanV := strings.TrimSpace(v)\n\t\t\t\tif cleanV != \"\" {\n\t\t\t\t\t// Only keep if unique\n\t\t\t\t\tif _, seen := definedValues[cleanV]; !seen {\n\t\t\t\t\t\tdefinedValues[cleanV] = struct{}{}\n\t\t\t\t\t\tvalues[i] = cleanV\n\t\t\t\t\t\ti++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvalues = values[:i]\n\n\t\t\t// 2. Join the incoming 'val' slice so we can SplitSeq over it.\n\t\t\trawIncoming := strings.Join(val, \",\")\n\n\t\t\tfor v := range strings.SplitSeq(rawIncoming, \",\") {\n\t\t\t\tv = strings.TrimSpace(v)\n\t\t\t\tif v != \"\" {\n\t\t\t\t\tif _, defined := definedValues[v]; !defined {\n\t\t\t\t\t\tvalues = append(values, v)\n\t\t\t\t\t\t// Mark as defined to prevent duplicates within the incoming values too\n\t\t\t\t\t\tdefinedValues[v] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 3. Join the results and wrap in a []string to satisfy the type.\n\t\t\ta[key] = []string{strings.Join(values, \",\")}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Set implements the ArgsBuilder interface.\nfunc (a Args) Set(k Key, v Value) ArgsBuilder {\n\ta[k] = v\n\n\treturn a\n}\n\n// Args implements the ArgsBuilder interface.\nfunc (a Args) Args() []string {\n\tkeys := maps.Keys(a)\n\tslices.Sort(keys)\n\n\targs := make([]string, 0, len(a))\n\n\tfor _, key := range keys {\n\t\tvals := a[key]\n\n\t\tfor _, val := range vals {\n\t\t\targs = append(\n\t\t\t\targs,\n\t\t\t\tfmt.Sprintf(\"--%s=%s\", key, val),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn args\n}\n\n// Get returns an args value.\nfunc (a Args) Get(k Key) Value {\n\treturn a[k]\n}\n\n// Contains checks if an arg key exists.\nfunc (a Args) Contains(k Key) bool {\n\t_, ok := a[k]\n\n\treturn ok\n}\n\n// DenyListError represents an error indicating that an argument was supplied\n// that is not allowed.\ntype DenyListError struct {\n\ts string\n}\n\n// NewDenylistError returns a DenyListError.\nfunc NewDenylistError(s string) error {\n\treturn &DenyListError{s}\n}\n\n// Error implements the Error interface.\nfunc (b *DenyListError) Error() string {\n\treturn fmt.Sprintf(\"extra arg %q is not allowed\", b.s)\n}\n"
  },
  {
    "path": "pkg/argsbuilder/argsbuilder_interface.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage argsbuilder\n\n// MergePolicy defines args builder args merging policy.\ntype MergePolicy int\n\nconst (\n\t// MergeOverwrite overwrite arg when merging.\n\tMergeOverwrite = iota\n\t// MergeAdditive concat argument lists.\n\tMergeAdditive\n\t// MergeDenied fail merge if another object has the arg defined.\n\tMergeDenied\n\t// MergePrepend prepends new values before existing ones.\n\tMergePrepend\n\t// MergeAppend appends new values after existing ones.\n\tMergeAppend\n)\n\n// MergePolicies merge policy map.\ntype MergePolicies map[string]MergePolicy\n\n// MergeOptions provides optional arguments for merge.\ntype MergeOptions struct {\n\tPolicies MergePolicies\n}\n\n// MergeOption optional merge argument setter.\ntype MergeOption func(*MergeOptions)\n\n// WithMergePolicies set merge policies during merge.\nfunc WithMergePolicies(policies MergePolicies) MergeOption {\n\treturn func(o *MergeOptions) {\n\t\to.Policies = policies\n\t}\n}\n\n// WithDenyList disable merge for all keys in map.\nfunc WithDenyList(denyList Args) MergeOption {\n\treturn func(o *MergeOptions) {\n\t\tif o.Policies == nil {\n\t\t\to.Policies = MergePolicies{}\n\t\t}\n\n\t\tfor k := range denyList {\n\t\t\to.Policies[k] = MergeDenied\n\t\t}\n\t}\n}\n\n// ArgsBuilder defines the requirements to build and manage a set of args.\ntype ArgsBuilder interface {\n\tMustMerge(Args, ...MergeOption)\n\tMerge(Args, ...MergeOption) error\n\tSet(string, []string) ArgsBuilder\n\tArgs() []string\n}\n"
  },
  {
    "path": "pkg/argsbuilder/argsbuilder_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage argsbuilder_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/argsbuilder\"\n)\n\ntype ArgsbuilderSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *ArgsbuilderSuite) TestMergeAdditive() {\n\targs := argsbuilder.Args{\n\t\t\"param\":  {\"value1,value2,value3\"},\n\t\t\"param2\": {\"\"},\n\t}\n\n\tsuite.Require().NoError(\n\t\targs.Merge(\n\t\t\targsbuilder.Args{\n\t\t\t\t\"param\": {\"value2, value10\"},\n\t\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergeAdditive,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value1,value2,value3,value10\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value1,value2,value3,value10\", \"--param2=\"}, args.Args())\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param2\": {\"value1, value5\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param2\": argsbuilder.MergeAdditive,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value1,value5\"}, args[\"param2\"])\n\tsuite.Assert().Equal([]string{\"--param=value1,value2,value3,value10\", \"--param2=value1,value5\"}, args.Args())\n}\n\nfunc (suite *ArgsbuilderSuite) TestMergeOverwrite() {\n\targs := argsbuilder.Args{\n\t\t\"param\": {\"value1,value2\"},\n\t}\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value10\"},\n\t\t}),\n\t)\n\n\tsuite.Require().Equal([]string{\"value10\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value10\"}, args.Args())\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value10\", \"value11\"},\n\t\t}),\n\t)\n\n\tsuite.Require().Equal([]string{\"value10\", \"value11\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value10\", \"--param=value11\"}, args.Args())\n}\n\n//nolint:dupl\nfunc (suite *ArgsbuilderSuite) TestMergePrepend() {\n\targs := argsbuilder.Args{\n\t\t\"param\": {\"value1\"},\n\t}\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value2\", \"value3\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergePrepend,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value2\", \"value3\", \"value1\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value2\", \"--param=value3\", \"--param=value1\"}, args.Args())\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value4\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergePrepend,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value4\", \"value2\", \"value3\", \"value1\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value4\", \"--param=value2\", \"--param=value3\", \"--param=value1\"}, args.Args())\n}\n\n//nolint:dupl\nfunc (suite *ArgsbuilderSuite) TestMergeAppend() {\n\targs := argsbuilder.Args{\n\t\t\"param\": {\"value1\"},\n\t}\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value2\", \"value3\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergeAppend,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value1\", \"value2\", \"value3\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value1\", \"--param=value2\", \"--param=value3\"}, args.Args())\n\n\tsuite.Require().NoError(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value4\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergeAppend,\n\t\t\t}),\n\t\t),\n\t)\n\n\tsuite.Require().Equal([]string{\"value1\", \"value2\", \"value3\", \"value4\"}, args[\"param\"])\n\tsuite.Assert().Equal([]string{\"--param=value1\", \"--param=value2\", \"--param=value3\", \"--param=value4\"}, args.Args())\n}\n\nfunc (suite *ArgsbuilderSuite) TestMergeDenied() {\n\targs := argsbuilder.Args{\n\t\t\"param\": {\"value1,value2\"},\n\t}\n\n\tsuite.Require().Error(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param\": {\"value10\"},\n\t\t},\n\t\t\targsbuilder.WithMergePolicies(argsbuilder.MergePolicies{\n\t\t\t\t\"param\": argsbuilder.MergeDenied,\n\t\t\t}),\n\t\t),\n\t)\n}\n\nfunc (suite *ArgsbuilderSuite) TestMergeDenyList() {\n\targs := argsbuilder.Args{\n\t\t\"param\": {\"value1,value2\"},\n\t}\n\n\tdenyList := argsbuilder.Args{\n\t\t\"param1\": {\"\"},\n\t\t\"param2\": {\"\"},\n\t\t\"param3\": {\"\"},\n\t}\n\n\tsuite.Require().Error(\n\t\targs.Merge(argsbuilder.Args{\n\t\t\t\"param2\": {\"value10\"},\n\t\t},\n\t\t\targsbuilder.WithDenyList(denyList),\n\t\t),\n\t)\n}\n\nfunc TestArgsbuilderSuite(t *testing.T) {\n\tsuite.Run(t, &ArgsbuilderSuite{})\n}\n"
  },
  {
    "path": "pkg/bytesize/bytesize.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package bytesize adds logic to help parse byte sizes in various forms such as gb, mb, GiB, etc.\npackage bytesize\n\nimport (\n\t\"fmt\"\n\t\"unicode\"\n\n\t\"github.com/dustin/go-humanize\"\n)\n\n// ByteSize implements pflag.Value interface and is meant to be used with flags specifying a size in bytes.\n// A value can be set before assigning to a flag to function as a default value.\ntype ByteSize struct {\n\tvalBytes    uint64\n\tval         string\n\tdefaultUnit string\n}\n\n// WithDefaultUnit creates a New ByteSize with a default unit.\nfunc WithDefaultUnit(unit string) *ByteSize {\n\treturn &ByteSize{defaultUnit: unit}\n}\n\n// New creates a New ByteSize without a default unit.\nfunc New() *ByteSize {\n\treturn &ByteSize{}\n}\n\n// Bytes returns the value in bytes.\nfunc (bs *ByteSize) Bytes() uint64 {\n\treturn bs.valBytes\n}\n\n// Megabytes returns the value in megabytes.\nfunc (bs *ByteSize) Megabytes() uint64 {\n\treturn bs.valBytes / (1000 * 1000)\n}\n\n// Gigabytes returns the value in gigabytes.\nfunc (bs *ByteSize) Gigabytes() uint64 {\n\treturn bs.valBytes / (1000 * 1000 * 1000)\n}\n\n// Mebibytetes returns the value in binary megabytes.\nfunc (bs *ByteSize) Mebibytetes() uint64 {\n\treturn bs.valBytes / (1024 * 1024)\n}\n\n// Gibibytes returns the value in binary gigabytes.\nfunc (bs *ByteSize) Gibibytes() uint64 {\n\treturn bs.valBytes / (1024 * 1024 * 1024)\n}\n\n// String returns the string representation of the value with the default unit if set.\nfunc (bs *ByteSize) String() string {\n\treturn bs.val\n}\n\n// SetDefaultUnit sets the default unit to use in case one wasn't specifies.\nfunc (bs *ByteSize) SetDefaultUnit(unit string) {\n\tbs.defaultUnit = unit\n}\n\n// Set implements pflag.Value interface.\nfunc (bs *ByteSize) Set(in string) error {\n\tif in == \"\" || in == \"0\" {\n\t\tbs.val = \"0\"\n\t\tbs.valBytes = 0\n\n\t\treturn nil\n\t}\n\n\t// if no unit is specified\n\tif unicode.IsDigit(rune(in[len(in)-1])) {\n\t\tif bs.defaultUnit == \"\" {\n\t\t\treturn fmt.Errorf(\"no unit specified for %q\", in)\n\t\t}\n\n\t\tin += bs.defaultUnit\n\t}\n\n\tvalBytes, err := humanize.ParseBytes(in)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbs.val = in\n\tbs.valBytes = valBytes\n\n\treturn nil\n}\n\n// Type implements pflag.Value interface (this will show up as the type next to the flag description).\nfunc (bs *ByteSize) Type() string { return \"string(mb,gb)\" }\n"
  },
  {
    "path": "pkg/bytesize/bytesize_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage bytesize_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/bytesize\"\n)\n\nfunc TestBytesizeNoDefaultUnit(t *testing.T) {\n\tt.Run(\"empty input\", func(t *testing.T) {\n\t\tbs := bytesize.New()\n\t\tassert.NoError(t, bs.Set(\"\"))\n\n\t\tassert.EqualValues(t, 0, bs.Bytes())\n\t\tassert.Equal(t, \"0\", bs.String())\n\n\t\tassert.NoError(t, bs.Set(\"0\"))\n\t\tassert.EqualValues(t, 0, bs.Bytes())\n\t\tassert.Equal(t, \"0\", bs.String())\n\t})\n\n\tt.Run(\"no unit specified\", func(t *testing.T) {\n\t\tbs := bytesize.New()\n\t\tassert.ErrorContains(t, bs.Set(\"10\"), \"no unit specified\")\n\t})\n\n\tt.Run(\"explicit unit provided\", func(t *testing.T) {\n\t\tbs := bytesize.New()\n\t\tassert.NoError(t, bs.Set(\"0.5mb\"))\n\t\tassert.Equal(t, \"0.5mb\", bs.String())\n\t\tassert.Equal(t, uint64(500000), bs.Bytes())\n\t})\n}\n\nfunc TestBytesizeWithDefaultUnit(t *testing.T) {\n\tt.Run(\"empty input\", func(t *testing.T) {\n\t\tbs := bytesize.WithDefaultUnit(\"mb\")\n\t\tassert.NoError(t, bs.Set(\"\"))\n\n\t\tassert.EqualValues(t, 0, bs.Bytes())\n\t\tassert.Equal(t, \"0\", bs.String())\n\n\t\tassert.NoError(t, bs.Set(\"0\"))\n\t\tassert.EqualValues(t, 0, bs.Bytes())\n\t\tassert.Equal(t, \"0\", bs.String())\n\t})\n\n\tt.Run(\"no unit specified\", func(t *testing.T) {\n\t\tbs := bytesize.WithDefaultUnit(\"mb\")\n\t\tassert.NoError(t, bs.Set(\"10\"))\n\n\t\tassert.Equal(t, \"10mb\", bs.String())\n\t\tassert.EqualValues(t, 10*1000*1000, bs.Bytes())\n\t})\n\n\tt.Run(\"explicit unit provided\", func(t *testing.T) {\n\t\tbs := bytesize.WithDefaultUnit(\"mb\")\n\t\tassert.NoError(t, bs.Set(\"0.5gb\"))\n\n\t\tassert.Equal(t, \"0.5gb\", bs.String())\n\t\tassert.EqualValues(t, 500000000, bs.Bytes())\n\t})\n}\n\nfunc TestByteSizeUnits(t *testing.T) {\n\tbs := bytesize.New()\n\tassert.NoError(t, bs.Set(\"3000000000b\"))\n\n\tassert.EqualValues(t, 3000, bs.Megabytes())\n\tassert.EqualValues(t, 3, bs.Gigabytes())\n\n\tassert.EqualValues(t, 2861, bs.Mebibytetes()) // 3,000,000,000 / 1024^2 = 2861 MiB\n\tassert.EqualValues(t, 2, bs.Gibibytes())      // 3,000,000,000 / 1024^3 = 2 GiB\n}\n"
  },
  {
    "path": "pkg/chunker/chunker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage chunker\n\n// Chunker is an interface for embedding all chunking interfaces under one name.\ntype Chunker = ChunkReader\n\n// ChunkReader is an interface describing a reader that streams data in []byte\n// chunks.\ntype ChunkReader interface {\n\tRead() <-chan []byte\n}\n"
  },
  {
    "path": "pkg/chunker/file/file.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage file\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/chunker\"\n\t\"github.com/siderolabs/talos/pkg/chunker/stream\"\n\t\"github.com/siderolabs/talos/pkg/follow\"\n)\n\n// Options is the functional options struct.\ntype Options struct {\n\tSize   int\n\tFollow bool\n}\n\n// Option is the functional option func.\ntype Option func(*Options)\n\n// WithSize sets the chunk size of the Chunker.\nfunc WithSize(s int) Option {\n\treturn func(args *Options) {\n\t\targs.Size = s\n\t}\n}\n\n// WithFollow file updates using inotify().\nfunc WithFollow() Option {\n\treturn func(args *Options) {\n\t\targs.Follow = true\n\t}\n}\n\n// Source is an interface describing the source of a File.\ntype Source = *os.File\n\n// NewChunker initializes a Chunker with default values.\nfunc NewChunker(ctx context.Context, source Source, setters ...Option) chunker.Chunker {\n\topts := &Options{\n\t\tSize: 1024,\n\t}\n\n\tfor _, setter := range setters {\n\t\tsetter(opts)\n\t}\n\n\tvar r io.ReadCloser = source\n\n\tif opts.Follow {\n\t\tr = follow.NewReader(ctx, source)\n\t}\n\n\treturn stream.NewChunker(ctx, r, stream.Size(opts.Size))\n}\n"
  },
  {
    "path": "pkg/chunker/file/file_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage file_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/chunker/file\"\n)\n\ntype FileChunkerSuite struct {\n\tsuite.Suite\n\n\ttmpDir         string\n\tno             int\n\treader, writer *os.File\n}\n\nfunc (suite *FileChunkerSuite) SetupSuite() {\n\tsuite.tmpDir = suite.T().TempDir()\n}\n\nfunc (suite *FileChunkerSuite) SetupTest() {\n\tsuite.no++\n\n\tvar err error\n\n\tsuite.writer, err = os.Create(filepath.Join(suite.tmpDir, fmt.Sprintf(\"%d.log\", suite.no)))\n\tsuite.Require().NoError(err)\n\n\tsuite.reader, err = os.Open(suite.writer.Name())\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *FileChunkerSuite) TearDownTest() {\n\tsuite.Require().NoError(suite.writer.Close())\n\tsuite.reader.Close() //nolint:errcheck\n}\n\nfunc collectChunks(chunksCh <-chan []byte) <-chan []byte {\n\tcombinedCh := make(chan []byte)\n\n\tgo func() {\n\t\tres := []byte(nil)\n\n\t\tfor chunk := range chunksCh {\n\t\t\tres = append(res, chunk...)\n\t\t}\n\n\t\tcombinedCh <- res\n\t}()\n\n\treturn combinedCh\n}\n\nfunc (suite *FileChunkerSuite) TestStreaming() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := file.NewChunker(ctx, suite.reader, file.WithFollow())\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\ttime.Sleep(50 * time.Millisecond)\n\n\tctxCancel()\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FileChunkerSuite) TestStreamingWithSomeHead() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := file.NewChunker(ctx, suite.reader, file.WithFollow())\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\ttime.Sleep(50 * time.Millisecond)\n\n\tctxCancel()\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FileChunkerSuite) TestStreamingSmallBuffer() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := file.NewChunker(ctx, suite.reader, file.WithSize(1), file.WithFollow())\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\n\t// create extra file to try to confuse watch\n\t_, err := os.Create(filepath.Join(suite.tmpDir, \"x.log\"))\n\tsuite.Require().NoError(err)\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tctxCancel()\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FileChunkerSuite) TestStreamingDeleted() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := file.NewChunker(ctx, suite.reader, file.WithFollow())\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// chunker should terminate when file is removed\n\tsuite.Require().NoError(os.Remove(suite.writer.Name()))\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FileChunkerSuite) TestNoFollow() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := file.NewChunker(ctx, suite.reader)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\tsuite.Require().Equal([]byte(\"abcdefghi\"), <-combinedCh)\n}\n\nfunc TestFileChunkerSuite(t *testing.T) {\n\tsuite.Run(t, new(FileChunkerSuite))\n}\n"
  },
  {
    "path": "pkg/chunker/stream/stream.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage stream\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-circular\"\n\n\t\"github.com/siderolabs/talos/pkg/chunker\"\n)\n\n// Options is the functional options struct.\ntype Options struct {\n\tSize int\n}\n\n// Option is the functional option func.\ntype Option func(*Options)\n\n// Size sets the chunk size of the Chunker.\nfunc Size(s int) Option {\n\treturn func(args *Options) {\n\t\targs.Size = s\n\t}\n}\n\n// Stream is a conecrete type that implements the chunker.Chunker interface.\ntype Stream struct {\n\tsource  Source\n\toptions *Options\n\n\tctx context.Context //nolint:containedctx\n}\n\n// Source is an interface describing the source of a Stream.\ntype Source interface {\n\tio.ReadCloser\n}\n\n// NewChunker initializes a Chunker with default values.\nfunc NewChunker(ctx context.Context, source Source, setters ...Option) chunker.Chunker {\n\topts := &Options{\n\t\tSize: 1024,\n\t}\n\n\tfor _, setter := range setters {\n\t\tsetter(opts)\n\t}\n\n\treturn &Stream{\n\t\tsource,\n\t\topts,\n\t\tctx,\n\t}\n}\n\n// Read implements ChunkReader.\n//\n//nolint:gocyclo\nfunc (c *Stream) Read() <-chan []byte {\n\t// Create a buffered channel of length 1.\n\tch := make(chan []byte, 1)\n\n\tgo func(ch chan []byte) {\n\t\tdefer close(ch)\n\n\t\tctx, cancel := context.WithCancel(c.ctx)\n\t\tdefer cancel()\n\n\t\tgo func() {\n\t\t\t<-ctx.Done()\n\t\t\tc.source.Close() //nolint:errcheck\n\t\t}()\n\n\t\tbuf := make([]byte, c.options.Size)\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\tdefault:\n\t\t\t}\n\n\t\t\tn, err := c.source.Read(buf)\n\t\t\tif err != nil {\n\t\t\t\tif !(errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, os.ErrClosed) || errors.Is(err, circular.ErrClosed)) {\n\t\t\t\t\tfmt.Printf(\"read error: %s\\n\", err.Error())\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif n != 0 {\n\t\t\t\t// Copy the buffer since we will modify it in the next loop.\n\t\t\t\tb := xslices.CopyN(buf, n)\n\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase ch <- b:\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}(ch)\n\n\treturn ch\n}\n"
  },
  {
    "path": "pkg/chunker/stream/stream_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage stream_test\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/chunker/stream\"\n)\n\ntype StreamChunkerSuite struct {\n\tsuite.Suite\n\n\treader *io.PipeReader\n\twriter *io.PipeWriter\n}\n\nfunc (suite *StreamChunkerSuite) SetupTest() {\n\tsuite.reader, suite.writer = io.Pipe()\n}\n\nfunc (suite *StreamChunkerSuite) TearDownTest() {\n\tsuite.Require().NoError(suite.writer.Close())\n\tsuite.Require().NoError(suite.reader.Close())\n}\n\nfunc collectChunks(chunksCh <-chan []byte) <-chan []byte {\n\tcombinedCh := make(chan []byte)\n\n\tgo func() {\n\t\tres := []byte(nil)\n\n\t\tfor chunk := range chunksCh {\n\t\t\tres = append(res, chunk...)\n\t\t}\n\n\t\tcombinedCh <- res\n\t}()\n\n\treturn combinedCh\n}\n\nfunc (suite *StreamChunkerSuite) TestStreaming() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := stream.NewChunker(ctx, suite.reader)\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"abc\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"def\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"ghi\"))\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"jkl\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"mno\"))\n\n\tsuite.Require().NoError(suite.writer.Close())\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *StreamChunkerSuite) TestStreamingSmallBuf() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := stream.NewChunker(ctx, suite.reader, stream.Size(1))\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"abc\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"def\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"ghi\"))\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"jkl\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"mno\"))\n\n\tsuite.Require().NoError(suite.writer.Close())\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *StreamChunkerSuite) TestStreamingCancel() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tchunker := stream.NewChunker(ctx, suite.reader)\n\n\tchunksCh := chunker.Read()\n\tcombinedCh := collectChunks(chunksCh)\n\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"abc\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"def\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"ghi\"))\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"jkl\"))\n\t//nolint:errcheck\n\tsuite.writer.Write([]byte(\"mno\"))\n\ttime.Sleep(50 * time.Millisecond)\n\n\tctxCancel()\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc TestStreamChunkerSuite(t *testing.T) {\n\tsuite.Run(t, new(StreamChunkerSuite))\n}\n"
  },
  {
    "path": "pkg/cli/cli.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cli provides utilities for CLI tools.\npackage cli\n"
  },
  {
    "path": "pkg/cli/context.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n)\n\n// WithContext wraps function call to provide a context cancellable with ^C.\nfunc WithContext(ctx context.Context, f func(context.Context) error) error {\n\twrappedCtx, wrappedCtxCancel := context.WithCancel(ctx)\n\tdefer wrappedCtxCancel()\n\n\t// listen for ^C and SIGTERM and abort context\n\tsigCh := make(chan os.Signal, 1)\n\tsignal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)\n\n\texited := make(chan struct{})\n\tdefer close(exited)\n\n\tgo func() {\n\t\tselect {\n\t\tcase <-sigCh:\n\t\t\twrappedCtxCancel()\n\n\t\t\tsignal.Stop(sigCh)\n\t\t\tfmt.Fprintln(os.Stderr, \"Signal received, aborting, press Ctrl+C once again to abort immediately...\")\n\t\tcase <-wrappedCtx.Done():\n\t\t\treturn\n\t\tcase <-exited:\n\t\t}\n\t}()\n\n\treturn f(wrappedCtx)\n}\n"
  },
  {
    "path": "pkg/cli/output.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n)\n\n// Fatalf prints formatted message to stderr and aborts execution.\nfunc Fatalf(message string, args ...any) {\n\tif !strings.HasSuffix(message, \"\\n\") {\n\t\tmessage += \"\\n\"\n\t}\n\n\tfmt.Fprintf(os.Stderr, message, args...)\n\tos.Exit(1)\n}\n\n// Warning prints formatted message to stderr.\nfunc Warning(message string, args ...any) {\n\tif !strings.HasSuffix(message, \"\\n\") {\n\t\tmessage += \"\\n\"\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"WARNING: \"+message, args...)\n}\n"
  },
  {
    "path": "pkg/cli/should.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cli\n\n// Should panics if err != nil\n//\n// Should is useful when error should never happen in customer environment,\n// it can only be development error.\nfunc Should(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/apply-config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// ApplyConfigClient client to apply config.\ntype ApplyConfigClient struct {\n\tClientProvider\n\tInfo\n}\n\n// ApplyConfig on the node via the API using insecure mode.\nfunc (s *APIBootstrapper) ApplyConfig(ctx context.Context, nodes []provision.NodeRequest, sl provision.SiderolinkRequest, out io.Writer) error {\n\tfor _, node := range nodes {\n\t\tconfigureNode := func(ctx context.Context) error {\n\t\t\tep := node.IPs[0].String()\n\n\t\t\tif addr, ok := sl.GetAddr(node.UUID); ok {\n\t\t\t\tfmt.Fprintln(out, \"using SideroLink node address for 'with-apply-config'\", node.UUID, \"=\", addr.String())\n\n\t\t\t\tep = addr.String()\n\t\t\t}\n\n\t\t\tc, err := client.New(ctx, client.WithTLSConfig(&tls.Config{\n\t\t\t\tInsecureSkipVerify: true,\n\t\t\t}), client.WithEndpoints(ep))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcfgBytes, err := node.Config.Bytes()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t_, err = c.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{\n\t\t\t\tData: cfgBytes,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t\tif err := retry.Constant(2*time.Minute, retry.WithUnits(250*time.Millisecond), retry.WithJitter(50*time.Millisecond)).RetryWithContext(ctx, configureNode); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/bootstrap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"google.golang.org/grpc/backoff\"\n\t\"google.golang.org/grpc/codes\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// APIBootstrapper bootstraps cluster via Talos API.\ntype APIBootstrapper struct {\n\tClientProvider\n\tInfo\n}\n\n// Bootstrap the cluster via the API.\n//\n// Bootstrap implements Bootstrapper interface.\n//\n//nolint:gocyclo\nfunc (s *APIBootstrapper) Bootstrap(ctx context.Context, out io.Writer) error {\n\tcli, err := s.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontrolPlaneNodes := s.NodesByType(machine.TypeControlPlane)\n\n\tif len(controlPlaneNodes) == 0 {\n\t\treturn errors.New(\"no control plane nodes to bootstrap\")\n\t}\n\n\tslices.SortFunc(controlPlaneNodes, func(a, b NodeInfo) int { return strings.Compare(a.IPs[0].String(), b.IPs[0].String()) })\n\n\tnodeIP := controlPlaneNodes[0].IPs[0]\n\tnodeCtx := client.WithNode(ctx, nodeIP.String())\n\n\tfmt.Fprintln(out, \"waiting for Talos API (to bootstrap the cluster)\")\n\n\terr = retry.Constant(10*time.Minute, retry.WithUnits(500*time.Millisecond)).RetryWithContext(nodeCtx, func(nodeCtx context.Context) error {\n\t\tretryCtx, cancel := context.WithTimeout(nodeCtx, 2*time.Second)\n\t\tdefer cancel()\n\n\t\tif _, err = cli.Version(retryCtx); err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tmachineStatus, err := safe.ReaderGetByID[*runtime.MachineStatus](retryCtx, cli.COSI, runtime.MachineStatusID)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tswitch machineStatus.TypedSpec().Stage {\n\t\tcase runtime.MachineStageBooting, runtime.MachineStageRunning:\n\t\t\treturn nil\n\t\tcase runtime.MachineStageUnknown, runtime.MachineStageMaintenance, runtime.MachineStageInstalling,\n\t\t\truntime.MachineStageRebooting, runtime.MachineStageShuttingDown, runtime.MachineStageResetting, runtime.MachineStageUpgrading:\n\t\t\treturn retry.ExpectedError(fmt.Errorf(\"machine in unexpected stage %s\", machineStatus.TypedSpec().Stage))\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(out, \"bootstrapping cluster\")\n\n\treturn retry.Constant(backoff.DefaultConfig.MaxDelay, retry.WithUnits(100*time.Millisecond)).RetryWithContext(nodeCtx, func(nodeCtx context.Context) error {\n\t\tretryCtx, cancel := context.WithTimeout(nodeCtx, 2*time.Second)\n\t\tdefer cancel()\n\n\t\tif err = cli.Bootstrap(retryCtx, &machineapi.BootstrapRequest{}); err != nil {\n\t\t\tswitch {\n\t\t\t// deadline exceeded in case it's verbatim context error\n\t\t\tcase errors.Is(err, context.DeadlineExceeded):\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t// FailedPrecondition when time is not in sync yet on the server\n\t\t\t// DeadlineExceeded when the call fails in the gRPC stack either on the server or client side\n\t\t\t// Canceled is when apid restarts on transitioning maintenance -> ready\n\t\t\tcase client.StatusCode(err) == codes.FailedPrecondition || client.StatusCode(err) == codes.DeadlineExceeded || client.StatusCode(err) == codes.Canceled:\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t// connection refused, including proxied connection refused via the endpoint to the node\n\t\t\tcase strings.Contains(err.Error(), \"connection refused\"):\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t// connection timeout\n\t\t\tcase strings.Contains(err.Error(), \"error reading from server: EOF\"):\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "pkg/cluster/check/apid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package check provides set of checks to verify cluster readiness.\npackage check\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// ApidReadyAssertion checks whether apid is responsive on all the nodes.\nfunc ApidReadyAssertion(ctx context.Context, cluster ClusterInfo) error {\n\tcli, err := cluster.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes := cluster.Nodes()\n\n\tnodeIPs := mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))\n\tnodesCtx := client.WithNodes(ctx, nodeIPs...)\n\n\t_, err = cli.Version(nodesCtx)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/cluster/check/check.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package check provides set of checks to verify cluster readiness.\npackage check\n\nimport (\n\t\"context\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\nconst updateInterval = 100 * time.Millisecond\n\n// ClusterInfo is interface requires by checks.\ntype ClusterInfo interface {\n\tcluster.ClientProvider\n\tcluster.K8sProvider\n\tcluster.Info\n}\n\n// ClusterCheck implements a function which returns condition based on ClusterAccess.\ntype ClusterCheck func(ClusterInfo) conditions.Condition\n\n// Reporter presents wait progress.\n//\n// It is supposed that reporter drops duplicate messages.\ntype Reporter interface {\n\tUpdate(condition conditions.Condition)\n}\n\n// Wait run the checks against the cluster and waits for the full set to succeed.\n//\n// Context ctx might have a timeout set to limit overall wait time.\n// Each check might define its own timeout.\nfunc Wait(ctx context.Context, cluster ClusterInfo, checks []ClusterCheck, reporter Reporter) error {\n\tfor _, check := range checks {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\tcondition := check(cluster)\n\n\t\terrCh := make(chan error, 1)\n\n\t\tgo func(condition conditions.Condition) {\n\t\t\terrCh <- condition.Wait(ctx)\n\t\t}(condition)\n\n\t\tvar err error\n\n\t\tfunc() {\n\t\t\tticker := time.NewTicker(updateInterval)\n\t\t\tdefer ticker.Stop()\n\n\t\t\t// report initial state\n\t\t\treporter.Update(condition)\n\n\t\t\t// report last state\n\t\t\tdefer reporter.Update(condition)\n\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase err = <-errCh:\n\t\t\t\t\treturn\n\t\t\t\tcase <-ticker.C:\n\t\t\t\t\treporter.Update(condition)\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc flatMapNodeInfosToIPs(nodes []cluster.NodeInfo) []netip.Addr {\n\treturn xslices.FlatMap(nodes, func(node cluster.NodeInfo) []netip.Addr { return node.IPs })\n}\n\nfunc mapNodeInfosToInternalIPs(nodes []cluster.NodeInfo) []netip.Addr {\n\treturn xslices.Map(nodes, func(node cluster.NodeInfo) netip.Addr { return node.InternalIP })\n}\n\nfunc mapIPsToStrings(input []netip.Addr) []string {\n\treturn xslices.Map(input, func(ip netip.Addr) string { return ip.String() })\n}\n"
  },
  {
    "path": "pkg/cluster/check/check_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/cluster/check/default.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// DefaultClusterChecks returns a set of default Talos cluster readiness checks.\nfunc DefaultClusterChecks() []ClusterCheck {\n\treturn slices.Concat(\n\t\tPreBootSequenceChecks(),\n\t\tK8sComponentsReadinessChecks(),\n\t\t[]ClusterCheck{\n\t\t\t// wait for all the nodes to report ready at k8s level\n\t\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\t\treturn conditions.PollingCondition(\"all k8s nodes to report ready\", func(ctx context.Context) error {\n\t\t\t\t\tif cniDisabled, err := cniDisabledStatus(ctx, cluster); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t} else if cniDisabled {\n\t\t\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t\t\t}\n\n\t\t\t\t\treturn K8sAllNodesReadyAssertion(ctx, cluster)\n\t\t\t\t}, 5*time.Second)\n\t\t\t},\n\n\t\t\t// wait for kube-proxy to report ready\n\t\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\t\treturn conditions.PollingCondition(\"kube-proxy to report ready\", func(ctx context.Context) error {\n\t\t\t\t\tpresent, replicas, err := DaemonSetPresent(ctx, cluster, \"kube-system\", \"k8s-app=kube-proxy\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tif !present {\n\t\t\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t\t\t}\n\n\t\t\t\t\treturn K8sPodReadyAssertion(ctx, cluster, replicas, \"kube-system\", \"k8s-app=kube-proxy\")\n\t\t\t\t}, 5*time.Second)\n\t\t\t},\n\n\t\t\t// wait for coredns to report ready\n\t\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\t\treturn conditions.PollingCondition(\"coredns to report ready\", func(ctx context.Context) error {\n\t\t\t\t\tif cniDisabled, err := cniDisabledStatus(ctx, cluster); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t} else if cniDisabled {\n\t\t\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t\t\t}\n\n\t\t\t\t\tpresent, replicas, err := DeploymentPresent(ctx, cluster, \"kube-system\", \"k8s-app=kube-dns\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tif !present {\n\t\t\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t\t\t}\n\n\t\t\t\t\treturn K8sPodReadyAssertion(ctx, cluster, replicas, \"kube-system\", \"k8s-app=kube-dns\")\n\t\t\t\t}, 5*time.Second)\n\t\t\t},\n\n\t\t\t// wait for all the nodes to be schedulable\n\t\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\t\treturn conditions.PollingCondition(\"all k8s nodes to report schedulable\", func(ctx context.Context) error {\n\t\t\t\t\treturn K8sAllNodesSchedulableAssertion(ctx, cluster)\n\t\t\t\t}, 5*time.Second)\n\t\t\t},\n\t\t},\n\t)\n}\n\nfunc cniDisabledStatus(ctx context.Context, cluster ClusterInfo) (bool, error) {\n\tcli, err := cluster.Client()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tbmc, err := safe.ReaderGetByID[*k8s.BootstrapManifestsConfig](ctx, cli.COSI, k8s.BootstrapManifestsConfigID)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn bmc.TypedSpec().CNIName == \"none\", nil\n}\n\n// K8sComponentsReadinessChecks returns a set of K8s cluster readiness checks which are specific to the k8s components\n// being up and running. This test can be skipped if the cluster is set to use a custom CNI, as the checks won't be healthy\n// until the CNI is up and running.\nfunc K8sComponentsReadinessChecks() []ClusterCheck {\n\treturn []ClusterCheck{\n\t\t// wait for all the nodes to report in at k8s level\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all k8s nodes to report\", func(ctx context.Context) error {\n\t\t\t\treturn K8sAllNodesReportedAssertion(ctx, cluster)\n\t\t\t}, 30*time.Second) // give more time per each attempt, as this check is going to build and cache kubeconfig\n\t\t},\n\n\t\t// wait for k8s control plane static pods\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all control plane static pods to be running\", func(ctx context.Context) error {\n\t\t\t\treturn K8sControlPlaneStaticPods(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for HA k8s control plane\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all control plane components to be ready\", func(ctx context.Context) error {\n\t\t\t\treturn K8sFullControlPlaneAssertion(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\t}\n}\n\n// ExtraClusterChecks returns a set of additional Talos cluster readiness checks which work only for newer versions of Talos.\n//\n// ExtraClusterChecks can't be used reliably in upgrade tests, as older versions might not pass the checks.\nfunc ExtraClusterChecks() []ClusterCheck {\n\treturn []ClusterCheck{}\n}\n\n// PreBootSequenceChecks returns a set of Talos cluster readiness checks which are run before boot sequence.\nfunc PreBootSequenceChecks() []ClusterCheck {\n\treturn []ClusterCheck{\n\t\t// wait for etcd to be healthy on all control plane nodes\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"etcd to be healthy\", func(ctx context.Context) error {\n\t\t\t\treturn ServiceHealthAssertion(ctx, cluster, \"etcd\", WithNodeTypes(machine.TypeInit, machine.TypeControlPlane))\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for etcd members to be consistent across nodes\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"etcd members to be consistent across nodes\", func(ctx context.Context) error {\n\t\t\t\treturn EtcdConsistentAssertion(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for etcd members to be the control plane nodes\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"etcd members to be control plane nodes\", func(ctx context.Context) error {\n\t\t\t\treturn EtcdControlPlaneNodesAssertion(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for apid to be ready on all the nodes\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"apid to be ready\", func(ctx context.Context) error {\n\t\t\t\treturn ApidReadyAssertion(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for all nodes to report their memory size\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all nodes memory sizes\", func(ctx context.Context) error {\n\t\t\t\treturn AllNodesMemorySizes(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for all nodes to report their disk size\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all nodes disk sizes\", func(ctx context.Context) error {\n\t\t\t\treturn AllNodesDiskSizes(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// check diagnostics\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"no diagnostics\", func(ctx context.Context) error {\n\t\t\t\treturn NoDiagnostics(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for kubelet to be healthy on all\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"kubelet to be healthy\", func(ctx context.Context) error {\n\t\t\t\treturn ServiceHealthAssertion(ctx, cluster, \"kubelet\", WithNodeTypes(machine.TypeInit, machine.TypeControlPlane))\n\t\t\t}, 5*time.Second)\n\t\t},\n\n\t\t// wait for all nodes to finish booting\n\t\tfunc(cluster ClusterInfo) conditions.Condition {\n\t\t\treturn conditions.PollingCondition(\"all nodes to finish boot sequence\", func(ctx context.Context) error {\n\t\t\t\treturn AllNodesBootedAssertion(ctx, cluster)\n\t\t\t}, 5*time.Second)\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/check/diagnostics.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// NoDiagnostics checks whether there are no diagnostic warnings.\nfunc NoDiagnostics(ctx context.Context, cluster ClusterInfo) error {\n\tcli, err := cluster.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes := cluster.Nodes()\n\tnodeInternalIPs := mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))\n\n\twarningsByNode := map[string][]*runtime.Diagnostic{}\n\n\tfor _, nodeIP := range nodeInternalIPs {\n\t\twarnings, err := safe.StateListAll[*runtime.Diagnostic](client.WithNode(ctx, nodeIP), cli.COSI)\n\t\tif err != nil {\n\t\t\tif client.StatusCode(err) == codes.PermissionDenied {\n\t\t\t\t// not supported, skip\n\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t}\n\n\t\t\treturn err\n\t\t}\n\n\t\tfor res := range warnings.All() {\n\t\t\twarningsByNode[nodeIP] = append(warningsByNode[nodeIP], res)\n\t\t}\n\t}\n\n\tif len(warningsByNode) == 0 {\n\t\treturn nil\n\t}\n\n\tnodesWithWarnings := maps.Keys(warningsByNode)\n\tslices.Sort(nodesWithWarnings)\n\n\treturn fmt.Errorf(\"active diagnostics: %s\", strings.Join(xslices.Map(nodesWithWarnings, func(node string) string {\n\t\treturn node + \": \" + strings.Join(xslices.Map(warningsByNode[node], func(warning *runtime.Diagnostic) string {\n\t\t\treturn warning.TypedSpec().Message\n\t\t}), \", \")\n\t}), \"; \"))\n}\n"
  },
  {
    "path": "pkg/cluster/check/discovery.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tclussterres \"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\n// DiscoveredClusterInfo represents a cluster.Info populated using the discovery service.\ntype DiscoveredClusterInfo struct {\n\tnodes       []cluster.NodeInfo\n\tnodesByType map[machine.Type][]cluster.NodeInfo\n}\n\n// Nodes returns list of all node infos.\nfunc (d *DiscoveredClusterInfo) Nodes() []cluster.NodeInfo {\n\treturn d.nodes\n}\n\n// NodesByType return list of node endpoints by type.\nfunc (d *DiscoveredClusterInfo) NodesByType(m machine.Type) []cluster.NodeInfo {\n\treturn d.nodesByType[m]\n}\n\n// NewDiscoveredClusterInfo returns a new cluster.Info populated from the discovery service.\nfunc NewDiscoveredClusterInfo(members []*clussterres.Member) (cluster.Info, error) {\n\tm, err := membersToNodeInfoMap(members)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodes := xslices.FlatMap(maps.Values(m), func(t []cluster.NodeInfo) []cluster.NodeInfo { return t })\n\n\treturn &DiscoveredClusterInfo{\n\t\tnodes:       nodes,\n\t\tnodesByType: m,\n\t}, nil\n}\n\nfunc membersToNodeInfoMap(members []*clussterres.Member) (map[machine.Type][]cluster.NodeInfo, error) {\n\tresult := make(map[machine.Type][]cluster.NodeInfo)\n\n\tfor _, member := range members {\n\t\tspec := member.TypedSpec()\n\n\t\tmachineType := spec.MachineType\n\n\t\tnodeInfo, err := memberToNodeInfo(member)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult[machineType] = append(result[machineType], nodeInfo)\n\t}\n\n\treturn result, nil\n}\n\nfunc memberToNodeInfo(member *clussterres.Member) (cluster.NodeInfo, error) {\n\tips, err := stringsToNetipAddrs(xslices.Map(member.TypedSpec().Addresses, func(ip netip.Addr) string {\n\t\treturn ip.String()\n\t}))\n\tif err != nil {\n\t\treturn cluster.NodeInfo{}, err\n\t}\n\n\tif len(ips) == 0 {\n\t\treturn cluster.NodeInfo{}, fmt.Errorf(\"no IP address found for member: %s\", member.Metadata().ID())\n\t}\n\n\treturn cluster.NodeInfo{\n\t\tInternalIP: ips[0],\n\t\tIPs:        ips,\n\t}, nil\n}\n\nfunc stringsToNetipAddrs(ips []string) ([]netip.Addr, error) {\n\tresult := make([]netip.Addr, 0, len(ips))\n\n\tfor _, ip := range ips {\n\t\tparsed, err := netip.ParseAddr(ip)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, parsed)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/cluster/check/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// EtcdConsistentAssertion checks that etcd membership is consistent across nodes.\nfunc EtcdConsistentAssertion(ctx context.Context, cl ClusterInfo) error {\n\tcli, err := cl.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar nodes []cluster.NodeInfo //nolint:prealloc // dynamic\n\n\tinitNodes := cl.NodesByType(machine.TypeInit)\n\tnodes = append(nodes, initNodes...)\n\tcontrolPlaneNodes := cl.NodesByType(machine.TypeControlPlane)\n\n\tnodes = append(nodes, controlPlaneNodes...)\n\n\tnodesCtx := client.WithNodes(ctx, mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))...)\n\n\tresp, err := cli.EtcdMemberList(nodesCtx, &machineapi.EtcdMemberListRequest{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttype data struct {\n\t\thostname  string\n\t\tid        uint64\n\t\tisLearner bool\n\t}\n\n\tknownMembers := map[data]struct{}{}\n\n\tmessages := resp.GetMessages()\n\tif len(messages) == 0 {\n\t\treturn errors.New(\"no messages returned\")\n\t}\n\n\tslices.SortFunc(messages, func(a, b *machineapi.EtcdMembers) int {\n\t\treturn cmp.Compare(a.GetMetadata().GetHostname(), b.GetMetadata().GetHostname())\n\t})\n\n\tfor i, message := range messages {\n\t\tif i == 0 {\n\t\t\t// Fill data using first message\n\t\t\tfor _, member := range message.Members {\n\t\t\t\tknownMembers[data{member.Hostname, member.Id, member.IsLearner}] = struct{}{}\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tnode := message.Metadata.GetHostname()\n\n\t\tif len(message.Members) != len(knownMembers) {\n\t\t\texpected := maps.ToSlice(knownMembers, func(k data, v struct{}) string { return k.hostname })\n\t\t\tactual := xslices.Map(message.Members, (*machineapi.EtcdMember).GetHostname)\n\n\t\t\treturn fmt.Errorf(\"%s: expected to have %v members, got %v\", node, expected, actual)\n\t\t}\n\n\t\t// check that member list is the same on all nodes\n\t\tfor _, member := range message.Members {\n\t\t\tif _, found := knownMembers[data{member.Hostname, member.Id, member.IsLearner}]; !found {\n\t\t\t\treturn fmt.Errorf(\"%s: found unexpected etcd member %s\", node, member.Hostname)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// EtcdControlPlaneNodesAssertion checks that etcd nodes are control plane nodes.\nfunc EtcdControlPlaneNodesAssertion(ctx context.Context, cl ClusterInfo) error {\n\tcli, err := cl.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes := append(cl.NodesByType(machine.TypeInit), cl.NodesByType(machine.TypeControlPlane)...)\n\n\tresp, err := cli.EtcdMemberList(ctx, &machineapi.EtcdMemberListRequest{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmembers := resp.GetMessages()[0].GetMembers()\n\n\tvar memberIPs []string\n\n\tfor _, member := range members {\n\t\tfor _, peerURL := range member.GetPeerUrls() {\n\t\t\tparsed, err2 := url.Parse(peerURL)\n\t\t\tif err2 != nil {\n\t\t\t\treturn err2\n\t\t\t}\n\n\t\t\tmemberIP := parsed.Hostname()\n\t\t\tmemberIPs = append(memberIPs, memberIP)\n\t\t}\n\t}\n\n\tcontrolPlaneNodeIPs := mapIPsToStrings(flatMapNodeInfosToIPs(nodes))\n\tif !maps.Contains(xslices.ToSet(controlPlaneNodeIPs), memberIPs) {\n\t\treturn fmt.Errorf(\"etcd member ips %q are not subset of control plane node ips %q\",\n\t\t\tmemberIPs, controlPlaneNodeIPs)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/check/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// AllNodesBootedAssertion checks whether nodes reached end of 'Boot' sequence.\n//\n//nolint:gocyclo\nfunc AllNodesBootedAssertion(ctx context.Context, cluster ClusterInfo) error {\n\tcli, err := cluster.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes := cluster.Nodes()\n\tnodeInternalIPs := mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\ttype eventWithNode struct {\n\t\tnode  string\n\t\tevent state.Event\n\t}\n\n\teventCh := make(chan eventWithNode)\n\n\tfor _, nodeIP := range nodeInternalIPs {\n\t\tnodeEventCh := make(chan state.Event)\n\n\t\tif err = cli.COSI.Watch(client.WithNode(ctx, nodeIP), runtime.NewMachineStatus().Metadata(), nodeEventCh); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tgo func(nodeIP string) {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn\n\t\t\t\tcase ev := <-nodeEventCh:\n\t\t\t\t\tchannel.SendWithContext(ctx, eventCh, eventWithNode{node: nodeIP, event: ev})\n\t\t\t\t}\n\t\t\t}\n\t\t}(nodeIP)\n\t}\n\n\tnodeStages := make(map[string]runtime.MachineStage, len(nodeInternalIPs))\n\n\tfor _, nodeIP := range nodeInternalIPs {\n\t\tnodeStages[nodeIP] = runtime.MachineStageUnknown\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase ev := <-eventCh:\n\t\t\tswitch ev.event.Type {\n\t\t\tcase state.Created, state.Updated:\n\t\t\t\tmachineStatus, ok := ev.event.Resource.(*runtime.MachineStatus)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"unexpected resource type: %T\", ev.event.Resource)\n\t\t\t\t}\n\n\t\t\t\tnodeStages[ev.node] = machineStatus.TypedSpec().Stage\n\t\t\tcase state.Destroyed, state.Bootstrapped, state.Noop:\n\t\t\t\t// nothing\n\t\t\tcase state.Errored:\n\t\t\t\treturn fmt.Errorf(\"error watching machine %s status: %w\", ev.node, ev.event.Error)\n\t\t\t}\n\t\t}\n\n\t\tallNodesRunning := true\n\t\tallNodesReported := true\n\t\tstageWithNodes := map[runtime.MachineStage][]string{}\n\n\t\tfor nodeIP, stage := range nodeStages {\n\t\t\tif stage != runtime.MachineStageRunning {\n\t\t\t\tallNodesRunning = false\n\t\t\t}\n\n\t\t\tif stage == runtime.MachineStageUnknown {\n\t\t\t\tallNodesReported = false\n\t\t\t}\n\n\t\t\tstageWithNodes[stage] = append(stageWithNodes[stage], nodeIP)\n\t\t}\n\n\t\tif !allNodesReported {\n\t\t\t// keep waiting for data from all nodes\n\t\t\tcontinue\n\t\t}\n\n\t\tif allNodesRunning {\n\t\t\treturn nil\n\t\t}\n\n\t\t// if we're here, not all nodes are running\n\t\tdelete(stageWithNodes, runtime.MachineStageRunning)\n\n\t\tstages := maps.Keys(stageWithNodes)\n\t\tslices.Sort(stages)\n\n\t\tmessage := xslices.Map(stages, func(stage runtime.MachineStage) string {\n\t\t\tnodeIPs := stageWithNodes[stage]\n\t\t\tslices.Sort(nodeIPs)\n\n\t\t\treturn fmt.Sprintf(\"%s: %v\", stage, nodeIPs)\n\t\t})\n\n\t\treturn fmt.Errorf(\"nodes are not running: %s\", strings.Join(message, \", \"))\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/check/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package check provides set of checks to verify cluster readiness.\npackage check\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"google.golang.org/grpc/codes\"\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// K8sAllNodesReportedAssertion checks whether all the nodes show up in node list.\nfunc K8sAllNodesReportedAssertion(ctx context.Context, cl ClusterInfo) error {\n\tclientset, err := cl.K8sClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texpectedNodeInfos := cl.Nodes()\n\n\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tactualNodeInfos := make([]cluster.NodeInfo, 0, len(nodes.Items))\n\n\tfor _, node := range nodes.Items {\n\t\tvar internalIP netip.Addr\n\n\t\tvar ips []netip.Addr\n\n\t\tfor _, nodeAddress := range node.Status.Addresses {\n\t\t\tswitch nodeAddress.Type { //nolint:exhaustive\n\t\t\tcase v1.NodeInternalIP:\n\t\t\t\tinternalIP, err = netip.ParseAddr(nodeAddress.Address)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tips = append(ips, internalIP)\n\t\t\tcase v1.NodeExternalIP:\n\t\t\t\texternalIP, err := netip.ParseAddr(nodeAddress.Address)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tips = append(ips, externalIP)\n\t\t\t}\n\t\t}\n\n\t\tactualNodeInfo := cluster.NodeInfo{\n\t\t\tInternalIP: internalIP,\n\t\t\tIPs:        ips,\n\t\t}\n\n\t\tactualNodeInfos = append(actualNodeInfos, actualNodeInfo)\n\t}\n\n\treturn cluster.NodesMatch(expectedNodeInfos, actualNodeInfos)\n}\n\n// K8sFullControlPlaneAssertion checks whether all the controlplane nodes are k8s controlplane nodes.\n//\n//nolint:gocyclo,cyclop\nfunc K8sFullControlPlaneAssertion(ctx context.Context, cl ClusterInfo) error {\n\tclientset, err := cl.K8sClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\texpectedNodes := append(cl.NodesByType(machine.TypeInit), cl.NodesByType(machine.TypeControlPlane)...)\n\n\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tactualNodes := make([]cluster.NodeInfo, 0, len(nodes.Items))\n\n\tfor _, node := range nodes.Items {\n\t\tfor label := range node.Labels {\n\t\t\tif label == constants.LabelNodeRoleControlPlane {\n\t\t\t\tvar internalIP netip.Addr\n\n\t\t\t\tvar ips []netip.Addr\n\n\t\t\t\tfor _, nodeAddress := range node.Status.Addresses {\n\t\t\t\t\tswitch nodeAddress.Type { //nolint:exhaustive\n\t\t\t\t\tcase v1.NodeInternalIP:\n\t\t\t\t\t\tinternalIP, err = netip.ParseAddr(nodeAddress.Address)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tips = append(ips, internalIP)\n\t\t\t\t\tcase v1.NodeExternalIP:\n\t\t\t\t\t\texternalIP, err2 := netip.ParseAddr(nodeAddress.Address)\n\t\t\t\t\t\tif err2 != nil {\n\t\t\t\t\t\t\treturn err2\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tips = append(ips, externalIP)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tactualNodeInfo := cluster.NodeInfo{\n\t\t\t\t\tInternalIP: internalIP,\n\t\t\t\t\tIPs:        ips,\n\t\t\t\t}\n\n\t\t\t\tactualNodes = append(actualNodes, actualNodeInfo)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\terr = cluster.NodesMatch(expectedNodes, actualNodes)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// NB: We run the control plane check after node readiness check in order to\n\t// ensure that all control plane nodes have been labeled with the controlplane\n\t// label.\n\n\t// daemonset check only there for pre-0.9 clusters with self-hosted control plane\n\tdaemonsets, err := clientset.AppsV1().DaemonSets(\"kube-system\").List(ctx, metav1.ListOptions{\n\t\tLabelSelector: \"k8s-app in (kube-apiserver,kube-scheduler,kube-controller-manager)\",\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, ds := range daemonsets.Items {\n\t\tif ds.Status.CurrentNumberScheduled != ds.Status.DesiredNumberScheduled {\n\t\t\treturn fmt.Errorf(\"expected current number scheduled for %s to be %d, got %d\", ds.GetName(), ds.Status.DesiredNumberScheduled, ds.Status.CurrentNumberScheduled)\n\t\t}\n\n\t\tif ds.Status.NumberAvailable != ds.Status.DesiredNumberScheduled {\n\t\t\treturn fmt.Errorf(\"expected number available for %s to be %d, got %d\", ds.GetName(), ds.Status.DesiredNumberScheduled, ds.Status.NumberAvailable)\n\t\t}\n\n\t\tif ds.Status.NumberReady != ds.Status.DesiredNumberScheduled {\n\t\t\treturn fmt.Errorf(\"expected number ready for %s to be %d, got %d\", ds.GetName(), ds.Status.DesiredNumberScheduled, ds.Status.NumberReady)\n\t\t}\n\t}\n\n\tfor _, k8sApp := range []string{\"kube-apiserver\", \"kube-scheduler\", \"kube-controller-manager\"} {\n\t\t// list pods to verify that daemonset status is updated properly\n\t\tpods, err := clientset.CoreV1().Pods(\"kube-system\").List(ctx, metav1.ListOptions{\n\t\t\tLabelSelector: fmt.Sprintf(\"k8s-app = %s\", k8sApp),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error listing pods for app %s: %w\", k8sApp, err)\n\t\t}\n\n\t\t// filter out pod checkpoints\n\t\tn := 0\n\n\t\tfor _, pod := range pods.Items {\n\t\t\tif _, exists := pod.Annotations[\"checkpointer.alpha.coreos.com/checkpoint-of\"]; !exists {\n\t\t\t\tpods.Items[n] = pod\n\t\t\t\tn++\n\t\t\t}\n\t\t}\n\n\t\tpods.Items = pods.Items[:n]\n\n\t\tif len(pods.Items) != len(actualNodes) {\n\t\t\treturn fmt.Errorf(\"expected number of pods for %s to be %d, got %d\",\n\t\t\t\tk8sApp, len(actualNodes), len(pods.Items))\n\t\t}\n\n\t\tvar notReadyPods []string\n\n\t\tfor _, pod := range pods.Items {\n\t\t\tfor _, cond := range pod.Status.Conditions {\n\t\t\t\tif cond.Type == v1.PodReady {\n\t\t\t\t\tif cond.Status != v1.ConditionTrue {\n\t\t\t\t\t\tnotReadyPods = append(notReadyPods, pod.Name)\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif len(notReadyPods) > 0 {\n\t\t\treturn fmt.Errorf(\"some pods are not ready for %s: %v\", k8sApp, notReadyPods)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// K8sAllNodesReadyAssertion checks whether all the nodes are Ready.\nfunc K8sAllNodesReadyAssertion(ctx context.Context, cluster cluster.K8sProvider) error {\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar notReadyNodes []string\n\n\tfor _, node := range nodes.Items {\n\t\tfor _, cond := range node.Status.Conditions {\n\t\t\tif cond.Type == v1.NodeReady {\n\t\t\t\tif cond.Status != v1.ConditionTrue {\n\t\t\t\t\tnotReadyNodes = append(notReadyNodes, node.Name)\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(notReadyNodes) == 0 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"some nodes are not ready: %v\", notReadyNodes)\n}\n\n// K8sAllNodesSchedulableAssertion checks whether all the nodes are schedulable (not cordoned).\nfunc K8sAllNodesSchedulableAssertion(ctx context.Context, cluster cluster.K8sProvider) error {\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar notSchedulableNodes []string\n\n\tfor _, node := range nodes.Items {\n\t\tif node.Spec.Unschedulable {\n\t\t\tnotSchedulableNodes = append(notSchedulableNodes, node.Name)\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif len(notSchedulableNodes) == 0 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"some nodes are not schedulable: %v\", notSchedulableNodes)\n}\n\n// K8sPodReadyAssertion checks whether all the pods matching label selector are Ready, and there is at least one.\n//\n//nolint:gocyclo\nfunc K8sPodReadyAssertion(ctx context.Context, cluster cluster.K8sProvider, replicas int, namespace, labelSelector string) error {\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tpods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: labelSelector,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(pods.Items) == 0 {\n\t\treturn fmt.Errorf(\"no pods found for namespace %q and label selector %q\", namespace, labelSelector)\n\t}\n\n\tvar notReadyPods, readyPods []string\n\n\tfor _, pod := range pods.Items {\n\t\t// skip deleted pods\n\t\tif pod.DeletionTimestamp != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\t// skip failed pods\n\t\tif pod.Status.Phase == v1.PodFailed {\n\t\t\tcontinue\n\t\t}\n\n\t\t// skip pods which `kubectl get pods` marks as 'Completed':\n\t\t// * these pods have a phase 'Running', but all containers are terminated\n\t\t// * such pods appear after a graceful kubelet shutdown\n\t\tallContainersTerminated := true\n\n\t\tfor _, containerStatus := range pod.Status.ContainerStatuses {\n\t\t\tif containerStatus.State.Terminated == nil {\n\t\t\t\tallContainersTerminated = false\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif allContainersTerminated {\n\t\t\tcontinue\n\t\t}\n\n\t\tready := false\n\n\t\tfor _, cond := range pod.Status.Conditions {\n\t\t\tif cond.Type == v1.PodReady {\n\t\t\t\tif cond.Status == v1.ConditionTrue {\n\t\t\t\t\tready = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !ready {\n\t\t\tnotReadyPods = append(notReadyPods, pod.Name)\n\t\t} else {\n\t\t\treadyPods = append(readyPods, pod.Name)\n\t\t}\n\t}\n\n\tif len(readyPods) == 0 {\n\t\treturn fmt.Errorf(\"no ready pods found for namespace %q and label selector %q\", namespace, labelSelector)\n\t}\n\n\tif len(notReadyPods) == 0 {\n\t\tif len(readyPods) != replicas {\n\t\t\treturn fmt.Errorf(\"expected %d ready pods, got %d\", replicas, len(readyPods))\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"some pods are not ready: %v\", notReadyPods)\n}\n\n// DaemonSetPresent returns true if there is at least one DaemonSet matching given label selector.\nfunc DaemonSetPresent(ctx context.Context, cluster cluster.K8sProvider, namespace, labelSelector string) (bool, int, error) {\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn false, 0, err\n\t}\n\n\tdss, err := clientset.AppsV1().DaemonSets(namespace).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: labelSelector,\n\t})\n\tif err != nil {\n\t\treturn false, 0, err\n\t}\n\n\tif len(dss.Items) == 0 {\n\t\treturn false, 0, nil\n\t}\n\n\treturn true, int(dss.Items[0].Status.DesiredNumberScheduled), nil\n}\n\n// DeploymentPresent returns true if there is at least one ReplicaSet matching given label selector.\nfunc DeploymentPresent(ctx context.Context, cluster cluster.K8sProvider, namespace, labelSelector string) (bool, int, error) {\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn false, 0, err\n\t}\n\n\tdeployments, err := clientset.AppsV1().Deployments(namespace).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: labelSelector,\n\t})\n\tif err != nil {\n\t\treturn false, 0, err\n\t}\n\n\tif len(deployments.Items) == 0 {\n\t\treturn false, 0, nil\n\t}\n\n\tdeployment := deployments.Items[0]\n\n\treturn true, int(pointer.SafeDeref(deployment.Spec.Replicas)), nil\n}\n\n// K8sControlPlaneStaticPods checks whether all the controlplane nodes are running required Kubernetes static pods.\nfunc K8sControlPlaneStaticPods(ctx context.Context, cl ClusterInfo) error {\n\texpectedNodes := append(cl.NodesByType(machine.TypeInit), cl.NodesByType(machine.TypeControlPlane)...)\n\n\t// using here new Talos COSI API, Talos 1.2+ required\n\tc, err := cl.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, node := range expectedNodes {\n\t\texpectedStaticPods := map[string]struct{}{\n\t\t\t\"kube-system/kube-apiserver\":          {},\n\t\t\t\"kube-system/kube-controller-manager\": {},\n\t\t\t\"kube-system/kube-scheduler\":          {},\n\t\t}\n\n\t\titems, err := safe.StateListAll[*k8s.StaticPodStatus](client.WithNode(ctx, node.InternalIP.String()), c.COSI)\n\t\tif err != nil {\n\t\t\tif client.StatusCode(err) == codes.Unimplemented {\n\t\t\t\t// old version of Talos without COSI API\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"error listing static pods on node %s: %w\", node.InternalIP, err)\n\t\t}\n\n\t\tfor res := range items.All() {\n\t\t\tfor expectedStaticPod := range expectedStaticPods {\n\t\t\t\tif strings.HasPrefix(res.Metadata().ID(), expectedStaticPod) {\n\t\t\t\t\tdelete(expectedStaticPods, expectedStaticPod)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif len(expectedStaticPods) > 0 {\n\t\t\tmissingStaticPods := maps.Keys(expectedStaticPods)\n\t\t\tslices.Sort(missingStaticPods)\n\n\t\t\treturn fmt.Errorf(\"missing static pods on node %s: %v\", node.InternalIP, missingStaticPods)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/check/nodes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"context\"\n\t\"errors\"\n\tfmt \"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n\t\"github.com/siderolabs/talos/pkg/minimal\"\n)\n\n// AllNodesMemorySizes checks that all nodes have enough memory.\nfunc AllNodesMemorySizes(ctx context.Context, cluster ClusterInfo) error {\n\tcl, err := cluster.Client()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting client: %w\", err)\n\t}\n\n\tnodesIP, err := getNonContainerNodes(\n\t\tclient.WithNodes(\n\t\t\tctx,\n\t\t\tmapIPsToStrings(mapNodeInfosToInternalIPs(cluster.Nodes()))...,\n\t\t),\n\t\tcl,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(nodesIP) == 0 {\n\t\treturn nil\n\t}\n\n\tresp, err := cl.Memory(client.WithNodes(ctx, nodesIP...))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting nodes memory: %w\", err)\n\t}\n\n\tvar resultErr error\n\n\tnodeToType := getNodesTypes(cluster, machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker)\n\n\tfor _, msg := range resp.Messages {\n\t\tif msg.Metadata == nil {\n\t\t\treturn errors.New(\"no metadata in the response\")\n\t\t}\n\n\t\thostname := msg.Metadata.Hostname\n\n\t\ttyp, ok := nodeToType[hostname]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected node %q in response\", hostname)\n\t\t}\n\n\t\tminimum, _, err := minimal.Memory(typ)\n\t\tif err != nil {\n\t\t\tresultErr = multierror.Append(resultErr, err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif totalMemory := msg.Meminfo.Memtotal * humanize.KiByte; totalMemory < minimum {\n\t\t\tresultErr = multierror.Append(\n\t\t\t\tresultErr,\n\t\t\t\tfmt.Errorf(\n\t\t\t\t\t\"node %q does not meet memory requirements: expected at least %d MiB, actual %d MiB\",\n\t\t\t\t\thostname,\n\t\t\t\t\tminimum/humanize.MiByte,\n\t\t\t\t\ttotalMemory/humanize.MiByte,\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn resultErr\n}\n\nfunc getNodesTypes(cluster ClusterInfo, nodeTypes ...machine.Type) map[string]machine.Type {\n\tresult := map[string]machine.Type{}\n\n\tfor _, typ := range nodeTypes {\n\t\tfor _, node := range cluster.NodesByType(typ) {\n\t\t\tresult[node.InternalIP.String()] = typ\n\t\t}\n\t}\n\n\treturn result\n}\n\n// AllNodesDiskSizes checks that all nodes have enough disk space.\n//\n//nolint:gocyclo\nfunc AllNodesDiskSizes(ctx context.Context, cluster ClusterInfo) error {\n\tcl, err := cluster.Client()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting client: %w\", err)\n\t}\n\n\tnodesIP, err := getNonContainerNodes(\n\t\tclient.WithNodes(\n\t\t\tctx,\n\t\t\tmapIPsToStrings(mapNodeInfosToInternalIPs(cluster.Nodes()))...,\n\t\t),\n\t\tcl,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(nodesIP) == 0 {\n\t\treturn nil\n\t}\n\n\tvar resultErr error\n\n\tslices.Sort(nodesIP)\n\n\tfor _, nodeIP := range nodesIP {\n\t\tvs, err := safe.StateGetByID[*block.VolumeStatus](client.WithNode(ctx, nodeIP), cl.COSI, constants.EphemeralPartitionLabel)\n\t\tif err != nil {\n\t\t\tif client.StatusCode(err) == codes.PermissionDenied {\n\t\t\t\t// old Talos versions don't support this resource\n\t\t\t\treturn conditions.ErrSkipAssertion\n\t\t\t}\n\n\t\t\tresultErr = multierror.Append(resultErr, fmt.Errorf(\"error getting volume status for node %q: %w\", nodeIP, err))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tactualSize := vs.TypedSpec().Size\n\n\t\t// calculate EPHEMERAL by subtracting the size of all other partitions and GPT overhead\n\t\tps := quirks.New(\"\").PartitionSizes()\n\t\tminimalEphemeralSize := minimal.DiskSize() - (ps.UKIEFISize() + ps.StateSize() + ps.METASize() + 10*1048576 /* GPT overhead, including alignment */)\n\n\t\tif actualSize < minimalEphemeralSize {\n\t\t\tresultErr = multierror.Append(resultErr, fmt.Errorf(\n\t\t\t\t\"ephemeral partition %q for node %q is too small, expected at least %s, actual %s\",\n\t\t\t\tvs.TypedSpec().Location,\n\t\t\t\tnodeIP,\n\t\t\t\thumanize.IBytes(minimalEphemeralSize),\n\t\t\t\thumanize.IBytes(actualSize),\n\t\t\t))\n\t\t}\n\t}\n\n\treturn resultErr\n}\n\nfunc getNonContainerNodes(ctx context.Context, cl *client.Client) ([]string, error) {\n\tresp, err := cl.Version(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting version: %w\", err)\n\t}\n\n\tresult := make([]string, 0, len(resp.Messages))\n\n\tfor _, msg := range resp.Messages {\n\t\tif msg.Metadata == nil {\n\t\t\treturn nil, errors.New(\"got empty metadata\")\n\t\t}\n\n\t\tif msg.Platform.Mode == \"container\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, msg.Metadata.Hostname)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/cluster/check/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport \"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\n// Option represents functional option.\ntype Option func(o *Options) error\n\n// WithNodeTypes sets the node types for a check.\nfunc WithNodeTypes(t ...machine.Type) Option {\n\treturn func(o *Options) error {\n\t\to.Types = t\n\n\t\treturn nil\n\t}\n}\n\n// Options describes ClusterCheck parameters.\ntype Options struct {\n\tTypes []machine.Type\n}\n\n// DefaultOptions returns the default options.\nfunc DefaultOptions() *Options {\n\treturn &Options{}\n}\n"
  },
  {
    "path": "pkg/cluster/check/reporter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage check\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// ConditionReporter is a reporter that reports conditions to a reporter.Reporter.\ntype ConditionReporter struct {\n\tw *reporter.Reporter\n}\n\n// Update reports a condition to the reporter.\nfunc (r *ConditionReporter) Update(condition conditions.Condition) {\n\tr.w.Report(conditionToUpdate(condition))\n}\n\n// StderrReporter returns console reporter with stderr output.\nfunc StderrReporter() *ConditionReporter {\n\treturn &ConditionReporter{\n\t\tw: reporter.New(),\n\t}\n}\n\nfunc conditionToUpdate(condition conditions.Condition) reporter.Update {\n\tline := strings.TrimSpace(fmt.Sprintf(\"waiting for %s\", condition.String()))\n\n\tswitch {\n\tcase strings.HasSuffix(line, \"...\"):\n\t\treturn reporter.Update{\n\t\t\tMessage: line,\n\t\t\tStatus:  reporter.StatusRunning,\n\t\t}\n\tcase strings.HasSuffix(line, conditions.OK):\n\t\treturn reporter.Update{\n\t\t\tMessage: line,\n\t\t\tStatus:  reporter.StatusSucceeded,\n\t\t}\n\tcase strings.HasSuffix(line, conditions.ErrSkipAssertion.Error()):\n\t\treturn reporter.Update{\n\t\t\tMessage: line,\n\t\t\tStatus:  reporter.StatusSkip,\n\t\t}\n\tdefault:\n\t\treturn reporter.Update{\n\t\t\tMessage: line,\n\t\t\tStatus:  reporter.StatusError,\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/check/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package check provides set of checks to verify cluster readiness.\npackage check\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// ErrServiceNotFound is an error that indicates that a service was not found.\nvar ErrServiceNotFound = errors.New(\"service not found\")\n\n// ServiceStateAssertion checks whether service reached some specified state.\nfunc ServiceStateAssertion(ctx context.Context, cl ClusterInfo, service string, states ...string) error {\n\tcli, err := cl.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// by default, we check all control plane nodes. if some nodes don't have that service running,\n\t// it won't be returned in the response\n\tnodes := append(cl.NodesByType(machine.TypeInit), cl.NodesByType(machine.TypeControlPlane)...)\n\n\tnodesCtx := client.WithNodes(ctx, mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))...)\n\n\tservicesInfo, err := cli.ServiceInfo(nodesCtx, service)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(servicesInfo) == 0 {\n\t\treturn ErrServiceNotFound\n\t}\n\n\tacceptedStates := map[string]struct{}{}\n\tfor _, state := range states {\n\t\tacceptedStates[state] = struct{}{}\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor _, serviceInfo := range servicesInfo {\n\t\tnode := serviceInfo.Metadata.GetHostname()\n\n\t\tif len(serviceInfo.Service.Events.Events) == 0 {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"%s: no events recorded yet for service %q\", node, service))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlastEvent := serviceInfo.Service.Events.Events[len(serviceInfo.Service.Events.Events)-1]\n\t\tif _, ok := acceptedStates[lastEvent.State]; !ok {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"%s: service %q not in expected state %q: current state [%s] %s\", node, service, states, lastEvent.State, lastEvent.Msg))\n\t\t}\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// ServiceHealthAssertion checks whether service reached some specified state.\n//\n//nolint:gocyclo\nfunc ServiceHealthAssertion(ctx context.Context, cl ClusterInfo, service string, setters ...Option) error {\n\topts := DefaultOptions()\n\n\tfor _, setter := range setters {\n\t\tif err := setter(opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tcli, err := cl.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar nodes []cluster.NodeInfo\n\n\tif len(opts.Types) > 0 {\n\t\tfor _, t := range opts.Types {\n\t\t\tnodes = append(nodes, cl.NodesByType(t)...)\n\t\t}\n\t} else {\n\t\tnodes = cl.Nodes()\n\t}\n\n\tcount := len(nodes)\n\n\tnodesCtx := client.WithNodes(ctx, mapIPsToStrings(mapNodeInfosToInternalIPs(nodes))...)\n\n\tservicesInfo, err := cli.ServiceInfo(nodesCtx, service)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(servicesInfo) != count {\n\t\treturn fmt.Errorf(\"expected a response with %d node(s), got %d\", count, len(servicesInfo))\n\t}\n\n\tvar multiErr *multierror.Error\n\n\t// sort service info list so that errors returned are consistent\n\tslices.SortFunc(servicesInfo, func(a, b client.ServiceInfo) int {\n\t\treturn cmp.Compare(a.Metadata.GetHostname(), b.Metadata.GetHostname())\n\t})\n\n\tfor _, serviceInfo := range servicesInfo {\n\t\tnode := serviceInfo.Metadata.GetHostname()\n\n\t\tif len(serviceInfo.Service.Events.Events) == 0 {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"%s: no events recorded yet for service %q\", node, service))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlastEvent := serviceInfo.Service.Events.Events[len(serviceInfo.Service.Events.Events)-1]\n\t\tif lastEvent.State != \"Running\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"%s: service %q not in expected state %q: current state [%s] %s\", node, service, \"Running\", lastEvent.State, lastEvent.Msg))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !serviceInfo.Service.GetHealth().GetHealthy() {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"%s: service is not healthy: %s\", node, service))\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "pkg/cluster/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cluster provides functions to access, check and inspect Talos clusters.\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\n\tk8s \"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// ClientProvider builds Talos client by endpoint.\n//\n// Client instance should be cached and closed when Close() is called.\ntype ClientProvider interface {\n\t// Client returns Talos client instance for default (if no endpoints are given) or\n\t// specific endpoint.\n\tClient(endpoints ...string) (*client.Client, error)\n\t// Close client connections.\n\tClose() error\n}\n\n// K8sProvider builds Kubernetes client to access Talos cluster.\ntype K8sProvider interface {\n\tKubeconfig(ctx context.Context) ([]byte, error)\n\tK8sRestConfig(ctx context.Context) (*rest.Config, error)\n\tK8sClient(ctx context.Context) (*kubernetes.Clientset, error)\n\tK8sHelper(ctx context.Context) (*k8s.Client, error)\n\tK8sClose() error\n}\n\n// CrashDumper captures Talos cluster state to the specified writer for debugging.\ntype CrashDumper interface {\n\tCrashDump(ctx context.Context, out io.Writer)\n}\n\n// NodeInfo describes a Talos node.\ntype NodeInfo struct {\n\tInternalIP netip.Addr\n\tIPs        []netip.Addr\n}\n\n// Info describes the Talos cluster.\ntype Info interface {\n\t// Nodes returns list of all node infos.\n\tNodes() []NodeInfo\n\t// NodesByType return list of node endpoints by type.\n\tNodesByType(machine.Type) []NodeInfo\n}\n\n// Bootstrapper performs Talos cluster bootstrap.\ntype Bootstrapper interface {\n\tBootstrap(ctx context.Context, out io.Writer) error\n}\n\n// IPsToNodeInfos converts list of IPs to a list of NodeInfos.\nfunc IPsToNodeInfos(ips []string) ([]NodeInfo, error) {\n\tresult := make([]NodeInfo, len(ips))\n\n\tfor i, ip := range ips {\n\t\tinfo, err := IPToNodeInfo(ip)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult[i] = *info\n\t}\n\n\treturn result, nil\n}\n\n// IPToNodeInfo converts a node internal IP to a NodeInfo.\nfunc IPToNodeInfo(ip string) (*NodeInfo, error) {\n\tparsed, err := netip.ParseAddr(ip)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &NodeInfo{\n\t\tInternalIP: parsed,\n\t\tIPs:        []netip.Addr{parsed},\n\t}, nil\n}\n\n// NodesMatch asserts that the provided expected set of nodes match the actual set of nodes.\n//\n// Each expectedNode IPs should have a non-empty intersection with actualNode IPs.\nfunc NodesMatch(expected, actual []NodeInfo) error {\n\tactualNodes := xslices.ToMap(actual, func(n NodeInfo) (*NodeInfo, struct{}) { return &n, struct{}{} })\n\n\tfor _, expectedNodeInfo := range expected {\n\t\tfound := false\n\n\t\tfor actualNodeInfo := range actualNodes {\n\t\t\t// expectedNodeInfo.IPs intersection with actualNodeInfo.IPs is not empty\n\t\t\tif len(maps.Intersect(xslices.ToSet(actualNodeInfo.IPs), xslices.ToSet(expectedNodeInfo.IPs))) > 0 {\n\t\t\t\tdelete(actualNodes, actualNodeInfo)\n\n\t\t\t\tfound = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\treturn fmt.Errorf(\"can't find expected node with IPs %q\", expectedNodeInfo.IPs)\n\t\t}\n\t}\n\n\tif len(actualNodes) > 0 {\n\t\tunexpectedIPs := xslices.FlatMap(maps.Keys(actualNodes), func(n *NodeInfo) []netip.Addr { return n.IPs })\n\n\t\tslices.SortFunc(unexpectedIPs, func(a, b netip.Addr) int { return a.Compare(b) })\n\n\t\treturn fmt.Errorf(\"unexpected nodes with IPs %q\", unexpectedIPs)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/cluster_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n)\n\nfunc TestAssertNodes(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname          string\n\t\texpectedNodes []cluster.NodeInfo\n\t\tactualNodes   []cluster.NodeInfo\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"aws+discovery\",\n\t\t\texpectedNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"1.2.3.4\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"5.6.7.8\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tactualNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"5.6.7.8\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"1.2.3.4\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"aws+private\",\n\t\t\texpectedNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tactualNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"5.6.7.8\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"1.2.3.4\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"more internal IPs\",\n\t\t\texpectedNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"ff::1\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"ff::2\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tactualNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"extra node expected\",\n\t\t\texpectedNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.4\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tactualNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"1.2.3.4\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"5.6.7.8\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: `can't find expected node with IPs [\"172.23.1.4\"]`,\n\t\t},\n\t\t{\n\t\t\tname: \"extra node actual\",\n\t\t\texpectedNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tactualNodes: []cluster.NodeInfo{\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"1.2.3.4\"), netip.MustParseAddr(\"172.23.1.2\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"5.6.7.8\"), netip.MustParseAddr(\"172.23.1.3\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.4\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tIPs: []netip.Addr{netip.MustParseAddr(\"172.23.1.5\"), netip.MustParseAddr(\"9.10.11.12\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"unexpected nodes with IPs [\\\"9.10.11.12\\\" \\\"172.23.1.4\\\" \\\"172.23.1.5\\\"]\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := cluster.NodesMatch(tt.expectedNodes, tt.actualNodes)\n\n\t\t\tif tt.expectedError == \"\" {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.EqualError(t, err, tt.expectedError)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// ConfigClientProvider builds Talos client from client config.\ntype ConfigClientProvider struct {\n\t// DefaultClient to be used when using default endpoints.\n\t//\n\t// Not required, if missing client will be constructed from the config.\n\tDefaultClient *client.Client\n\n\t// TalosConfig is a client Talos configuration.\n\tTalosConfig *clientconfig.Config\n\n\tclients map[string]*client.Client\n}\n\n// Client returns Talos client instance for default (if no endpoints are given) or\n// specific endpoints.\n//\n// Client implements ClientProvider interface.\nfunc (c *ConfigClientProvider) Client(endpoints ...string) (*client.Client, error) {\n\tkey := strings.Join(endpoints, \",\")\n\n\tif c.clients == nil {\n\t\tc.clients = make(map[string]*client.Client)\n\t}\n\n\tif cli := c.clients[key]; cli != nil {\n\t\treturn cli, nil\n\t}\n\n\tif len(endpoints) == 0 && c.DefaultClient != nil {\n\t\treturn c.DefaultClient, nil\n\t}\n\n\topts := []client.OptionFunc{\n\t\tclient.WithConfig(c.TalosConfig),\n\t}\n\n\tif len(endpoints) > 0 {\n\t\topts = append(opts, client.WithEndpoints(endpoints...))\n\t}\n\n\treturn client.New(context.TODO(), opts...)\n}\n\n// Close all the client connections.\nfunc (c *ConfigClientProvider) Close() error {\n\tfor _, cli := range c.clients {\n\t\tif err := cli.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tc.clients = nil\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/crashdump.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-talos-support/support\"\n\t\"github.com/siderolabs/go-talos-support/support/bundle\"\n\t\"github.com/siderolabs/go-talos-support/support/collectors\"\n\tv1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\tk8s \"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Crashdump creates a support.zip for the cluster.\nfunc Crashdump(ctx context.Context, cluster provision.Cluster, logWriter io.Writer, zipFilePath string) {\n\tsupportFile, err := os.Create(zipFilePath)\n\tif err != nil {\n\t\tfmt.Fprintf(logWriter, \"error creating crashdump file: %s\\n\", err)\n\n\t\treturn\n\t}\n\n\tdefer supportFile.Close() //nolint:errcheck\n\n\t// limit support bundle generation time\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\tdefer cancel()\n\n\tc, err := client.New(ctx, client.WithDefaultConfig())\n\tif err != nil {\n\t\tfmt.Fprintf(logWriter, \"error creating crashdump: %s\\n\", err)\n\n\t\treturn\n\t}\n\n\tnodes := xslices.Map(cluster.Info().Nodes, func(nodeInfo provision.NodeInfo) string {\n\t\treturn nodeInfo.IPs[0].String()\n\t})\n\n\tcontrolplane := nodes[0]\n\n\topts := []bundle.Option{\n\t\tbundle.WithArchiveOutput(supportFile),\n\t\tbundle.WithTalosClient(c),\n\t\tbundle.WithNodes(nodes...),\n\t\tbundle.WithNumWorkers(4),\n\t\tbundle.WithLogOutput(io.Discard),\n\t}\n\n\tkubeclient, err := getKubernetesClient(ctx, c, controlplane)\n\t// ignore error if we can't get a k8s client\n\tif err == nil {\n\t\topts = append(opts, bundle.WithKubernetesClient(kubeclient))\n\t}\n\n\toptions := bundle.NewOptions(opts...)\n\n\tcollectors, err := collectors.GetForOptions(ctx, options)\n\tif err != nil {\n\t\tfmt.Fprintf(logWriter, \"error creating crashdump collector options: %s\\n\", err)\n\n\t\treturn\n\t}\n\n\tif err := support.CreateSupportBundle(ctx, options, collectors...); err != nil {\n\t\tfmt.Fprintf(logWriter, \"error creating crashdump: %s\\n\", err)\n\n\t\treturn\n\t}\n}\n\nfunc getKubernetesClient(ctx context.Context, c *client.Client, endpoint string) (*k8s.Clientset, error) {\n\tkubeconfig, err := c.Kubeconfig(client.WithNodes(ctx, endpoint))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig, err := clientcmd.NewClientConfigFromBytes(kubeconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\trestconfig, err := config.ClientConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclientset, err := k8s.NewForConfig(restconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// just checking that k8s responds\n\t_, err = clientset.CoreV1().Namespaces().Get(ctx, \"kube-system\", v1.GetOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn clientset, nil\n}\n"
  },
  {
    "path": "pkg/cluster/hydrophone/hydrophone.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package hydrophone provides functions to run Kubernetes e2e tests.\npackage hydrophone\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/blang/semver/v4\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\t\"sigs.k8s.io/hydrophone/pkg/common\"\n\t\"sigs.k8s.io/hydrophone/pkg/conformance\"\n\t\"sigs.k8s.io/hydrophone/pkg/conformance/client\"\n\t\"sigs.k8s.io/hydrophone/pkg/types\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Options for the tests.\ntype Options struct {\n\tRunTests []string\n\tSkip     string\n\tParallel int\n\n\tRunTimeout    time.Duration\n\tDeleteTimeout time.Duration\n\n\tKubernetesVersion string\n\n\tUseSpinner      bool\n\tRetrieveResults bool\n\n\tResultsPath string\n}\n\n// DefaultOptions with hand-picked tests, timeouts, etc.\nfunc DefaultOptions() *Options {\n\treturn &Options{\n\t\tRunTests: []string{ // list of tests to cover basic kubernetes operations\n\t\t\t\"Pods should be submitted and removed\",\n\t\t\t\"Services should serve a basic endpoint from pods\",\n\t\t\t\"Services should be able to change the type from ExternalName to ClusterIP\",\n\t\t},\n\t\tParallel: 2,\n\n\t\tRunTimeout:    10 * time.Minute,\n\t\tDeleteTimeout: 3 * time.Minute,\n\n\t\tKubernetesVersion: constants.DefaultKubernetesVersion,\n\t}\n}\n\n// NetworkPolicies runs only network policy related tests.\nfunc NetworkPolicies(ctx context.Context, cluster cluster.K8sProvider) error {\n\toptions := Options{\n\t\tRunTests: []string{\n\t\t\t`\\[Feature:NetworkPolicy\\]`,\n\t\t},\n\t\tParallel: 4,\n\n\t\tRunTimeout:    15 * time.Minute,\n\t\tDeleteTimeout: 3 * time.Minute,\n\n\t\tKubernetesVersion: constants.DefaultKubernetesVersion,\n\t}\n\n\treturn Run(ctx, cluster, &options)\n}\n\n// FastConformance runs conformance suite in two passes: parallel + serial for non parallel-safe tests.\nfunc FastConformance(ctx context.Context, cluster cluster.K8sProvider) error {\n\toptionsList := []Options{\n\t\t{\n\t\t\tRunTests: []string{`\\[Conformance\\]`},\n\t\t\tSkip:     `\\[Serial\\]`,\n\t\t\tParallel: 16,\n\n\t\t\tRunTimeout:    time.Hour,\n\t\t\tDeleteTimeout: 5 * time.Minute,\n\n\t\t\tKubernetesVersion: constants.DefaultKubernetesVersion,\n\n\t\t\tUseSpinner: true,\n\t\t},\n\t\t{\n\t\t\tRunTests: []string{`\\[Serial\\].*\\[Conformance\\]`},\n\n\t\t\tRunTimeout:    time.Hour,\n\t\t\tDeleteTimeout: 5 * time.Minute,\n\n\t\t\tKubernetesVersion: constants.DefaultKubernetesVersion,\n\n\t\t\tUseSpinner: true,\n\t\t},\n\t}\n\n\tfor _, options := range optionsList {\n\t\tif err := Run(ctx, cluster, &options); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// CertifiedConformance runs conformance suite in certified mode collecting all the results.\nfunc CertifiedConformance(ctx context.Context, cluster cluster.K8sProvider) error {\n\toptions := Options{\n\t\tRunTests: []string{`\\[Conformance\\]`},\n\n\t\tRunTimeout:    2 * time.Hour,\n\t\tDeleteTimeout: 5 * time.Minute,\n\n\t\tKubernetesVersion: constants.DefaultKubernetesVersion,\n\t\tRetrieveResults:   true,\n\n\t\tUseSpinner: true,\n\t}\n\n\tk8sVersion, err := semver.ParseTolerant(options.KubernetesVersion)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toptions.ResultsPath = fmt.Sprintf(\"v%d.%d/talos\", k8sVersion.Major, k8sVersion.Minor)\n\n\tif err = os.MkdirAll(options.ResultsPath, 0o755); err != nil {\n\t\treturn err\n\t}\n\n\treturn Run(ctx, cluster, &options)\n}\n\n// Run the e2e test against cluster with provided options.\n//\n//nolint:gocyclo\nfunc Run(ctx context.Context, cluster cluster.K8sProvider, options *Options) error {\n\tcfg, err := cluster.K8sRestConfig(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting kubernetes config: %w\", err)\n\t}\n\n\t// reset timeout to prevent log streaming from timing out\n\tcfg.Timeout = 0\n\n\tconfig := types.NewDefaultConfiguration()\n\tconfig.ConformanceImage = fmt.Sprintf(\"registry.k8s.io/conformance:v%s\", options.KubernetesVersion)\n\tconfig.OutputDir = options.ResultsPath\n\tconfig.Parallel = options.Parallel\n\tconfig.Skip = options.Skip\n\n\tclientset, err := cluster.K8sClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting kubernetes client: %w\", err)\n\t}\n\n\ttestRunner := conformance.NewTestRunner(config, clientset)\n\ttestClient := client.NewClient(cfg, clientset, config.Namespace)\n\n\tcleanup := func() error {\n\t\tif err := testRunner.Cleanup(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to cleanup: %w\", err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tdefer cleanup() //nolint:errcheck\n\n\tif err = cleanup(); err != nil {\n\t\treturn err\n\t}\n\n\tverboseGinkgo := config.Verbosity >= 6\n\tshowSpinner := !verboseGinkgo && config.Verbosity > 2 && options.UseSpinner && os.Getenv(\"CI\") == \"\"\n\n\tfmt.Printf(\"running conformance tests version %s\\n\", options.KubernetesVersion)\n\tfmt.Printf(\"running tests: %s\\n\", strings.Join(options.RunTests, \"|\"))\n\n\tif err := testRunner.Deploy(ctx, strings.Join(options.RunTests, \"|\"), \"\", verboseGinkgo, config.StartupTimeout); err != nil {\n\t\treturn fmt.Errorf(\"failed to deploy tests: %w\", err)\n\t}\n\n\tbefore := time.Now()\n\n\tvar spinner *common.Spinner\n\n\tif showSpinner {\n\t\tspinner = common.NewSpinner(os.Stdout)\n\t\tspinner.Start()\n\t}\n\n\t// PrintE2ELogs is a long running method\n\tif err := testClient.PrintE2ELogs(ctx); err != nil {\n\t\treturn fmt.Errorf(\"failed to get test logs: %w\", err)\n\t}\n\n\tif showSpinner {\n\t\tspinner.Stop()\n\t}\n\n\tfmt.Printf(\"tests finished after %v.\\n\", time.Since(before).Round(time.Second))\n\n\texitCode, err := testClient.FetchExitCode(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to determine exit code: %w\", err)\n\t}\n\n\tif exitCode == 0 {\n\t\tfmt.Println(\"tests completed successfully\")\n\t} else {\n\t\treturn fmt.Errorf(\"tests failed: code %d\", exitCode)\n\t}\n\n\tif options.RetrieveResults {\n\t\tif err := testClient.FetchFiles(ctx, config.OutputDir); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to download results: %w\", err)\n\t\t}\n\n\t\tproductInfo, err := yaml.Marshal(talos)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error marshaling product info: %w\", err)\n\t\t}\n\n\t\tif err = os.WriteFile(filepath.Join(options.ResultsPath, \"PRODUCT.yaml\"), productInfo, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn cleanup()\n}\n"
  },
  {
    "path": "pkg/cluster/hydrophone/product.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hydrophone\n\nimport \"github.com/siderolabs/talos/pkg/machinery/version\"\n\ntype product struct {\n\tVendor           string `yaml:\"vendor\"`\n\tName             string `yaml:\"name\"`\n\tVersion          string `yaml:\"version\"`\n\tWebsiteURL       string `yaml:\"website_url\"`\n\tRepoURL          string `yaml:\"repo_url\"`\n\tDocumentationURL string `yaml:\"documentation_url\"`\n\tProductLogoURL   string `yaml:\"product_logo_url\"`\n\tType             string `yaml:\"type\"`\n\tDescription      string `yaml:\"description\"`\n\tContactEmail     string `yaml:\"contact_email_address\"`\n}\n\nvar talos = product{\n\tVendor:           \"Sidero Labs\",\n\tName:             \"Talos Linux\",\n\tVersion:          version.Tag,\n\tWebsiteURL:       \"https://www.siderolabs.com/\",\n\tRepoURL:          \"https://github.com/siderolabs/talos\",\n\tDocumentationURL: \"https://www.talos.dev\",\n\tProductLogoURL:   \"https://www.talos.dev/images/Sidero_stacked_darkbkgd_RGB.svg\",\n\tType:             \"installer\",\n\tDescription:      \"Talos Linux is Linux designed for Kubernetes - secure, immutable, and minimal.\",\n\tContactEmail:     \"developers@siderolabs.com\",\n}\n"
  },
  {
    "path": "pkg/cluster/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\n\tk8s \"k8s.io/client-go/kubernetes\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n)\n\n// KubernetesFromKubeletClient provides Kubernetes client built from local kubelet config.\ntype KubernetesFromKubeletClient struct {\n\tKubeHelper *kubernetes.Client\n\tclientset  *k8s.Clientset\n}\n\n// K8sClient builds Kubernetes client from local kubelet config.\n//\n// Kubernetes client instance is cached.\nfunc (k *KubernetesFromKubeletClient) K8sClient(ctx context.Context) (*k8s.Clientset, error) {\n\tif k.clientset != nil {\n\t\treturn k.clientset, nil\n\t}\n\n\tvar err error\n\tif k.KubeHelper, err = kubernetes.NewClientFromKubeletKubeconfig(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tk.clientset = k.KubeHelper.Clientset\n\n\treturn k.clientset, nil\n}\n\n// K8sHelper returns wrapper around K8sClient.\nfunc (k *KubernetesFromKubeletClient) K8sHelper(ctx context.Context) (*kubernetes.Client, error) {\n\tif k.KubeHelper != nil {\n\t\treturn k.KubeHelper, nil\n\t}\n\n\t_, err := k.K8sClient(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn k.KubeHelper, nil\n}\n\n// K8sClose closes Kubernetes client.\nfunc (k *KubernetesFromKubeletClient) K8sClose() error {\n\tif k.KubeHelper == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KubeHelper.Close()\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/compat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n)\n\n// NodeVersion holds the node identifier along with its Talos version.\ntype NodeVersion struct {\n\tNode    string\n\tVersion *compatibility.TalosVersion\n}\n\n// GetNodesTalosVersions retrieves the Talos versions for the specified nodes.\nfunc GetNodesTalosVersions(ctx context.Context, talosClient *client.Client, nodes []string) ([]NodeVersion, error) {\n\teg, ctx := errgroup.WithContext(ctx)\n\tversions := make([]NodeVersion, len(nodes))\n\n\tfor i, node := range nodes {\n\t\teg.Go(func() error {\n\t\t\tnodeCtx := client.WithNode(ctx, node)\n\n\t\t\tresp, err := talosClient.Version(nodeCtx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"node %q: %w\", node, err)\n\t\t\t}\n\n\t\t\tv, err := compatibility.ParseTalosVersion(resp.Messages[0].GetVersion())\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"node %q: %w\", node, err)\n\t\t\t}\n\n\t\t\tversions[i] = NodeVersion{Node: node, Version: v}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif err := eg.Wait(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn versions, nil\n}\n\n// GetMinimumTalosVersion returns the minimum Talos version from the provided list of NodeVersion.\nfunc GetMinimumTalosVersion(versions []NodeVersion) (*compatibility.TalosVersion, error) {\n\tif len(versions) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tsemvers := make([]struct {\n\t\tIndex   int\n\t\tVersion semver.Version\n\t}, len(versions))\n\n\tfor i, nv := range versions {\n\t\tsemverV, err := semver.ParseTolerant(nv.Version.String())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse talos version %q for node %q: %w\", nv.Version.String(), nv.Node, err)\n\t\t}\n\n\t\tsemvers[i] = struct {\n\t\t\tIndex   int\n\t\t\tVersion semver.Version\n\t\t}{\n\t\t\tIndex:   i,\n\t\t\tVersion: semverV,\n\t\t}\n\t}\n\n\tsort.Slice(semvers, func(i, j int) bool {\n\t\treturn semvers[i].Version.Compare(semvers[j].Version) < 0\n\t})\n\n\treturn versions[semvers[0].Index].Version, nil\n}\n\n// CheckCompatibility checks if all provided Talos versions are compatible with the given Kubernetes version.\nfunc CheckCompatibility(k8sVersion string, versions []NodeVersion) error {\n\tparsedK8s, err := compatibility.ParseKubernetesVersion(k8sVersion)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, nv := range versions {\n\t\tif err := parsedK8s.SupportedWith(nv.Version); err != nil {\n\t\t\treturn fmt.Errorf(\"node %q: %w\", nv.Node, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// VerifyVersionCompatibility retrieves Talos versions for the specified nodes and checks their compatibility with the given Kubernetes version.\nfunc VerifyVersionCompatibility(ctx context.Context, talosClient *client.Client, nodes []string, k8sVersion string, logger func(string, ...any)) (\n\t*compatibility.TalosVersion, error,\n) {\n\tversions, err := GetNodesTalosVersions(ctx, talosClient, nodes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := CheckCompatibility(k8sVersion, versions); err != nil {\n\t\treturn nil, err\n\t}\n\n\tminV, err := GetMinimumTalosVersion(versions)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, nv := range versions {\n\t\tlogger(\"> %q: Talos version %s is compatible with Kubernetes version %s\", nv.Node, nv.Version, k8sVersion)\n\t}\n\n\treturn minV, nil\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/compat_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n)\n\nfunc TestGetMinimumTalosVersion(t *testing.T) {\n\tv100, err := compatibility.ParseTalosVersion(&machine.VersionInfo{Tag: \"v1.0.0\"})\n\trequire.NoError(t, err)\n\n\tv110, err := compatibility.ParseTalosVersion(&machine.VersionInfo{Tag: \"v1.1.0\"})\n\trequire.NoError(t, err)\n\n\tv120, err := compatibility.ParseTalosVersion(&machine.VersionInfo{Tag: \"v1.2.0\"})\n\trequire.NoError(t, err)\n\n\tv130Dirty, err := compatibility.ParseTalosVersion(&machine.VersionInfo{Tag: \"1.3.0-alpha.2-93-gcd04c3dde-dirty\"})\n\trequire.NoError(t, err)\n\n\ttests := []struct {\n\t\tname     string\n\t\tversions []kubernetes.NodeVersion\n\t\twant     *compatibility.TalosVersion\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tversions: []kubernetes.NodeVersion{},\n\t\t\twant:     nil,\n\t\t\twantErr:  false,\n\t\t},\n\t\t{\n\t\t\tname: \"single version\",\n\t\t\tversions: []kubernetes.NodeVersion{\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node1\",\n\t\t\t\t\tVersion: v100,\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    v100,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"single dirty version\",\n\t\t\tversions: []kubernetes.NodeVersion{\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node1\",\n\t\t\t\t\tVersion: v130Dirty,\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    v130Dirty,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple versions, sorted\",\n\t\t\tversions: []kubernetes.NodeVersion{\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node1\",\n\t\t\t\t\tVersion: v100,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node2\",\n\t\t\t\t\tVersion: v110,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node3\",\n\t\t\t\t\tVersion: v120,\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    v100,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple versions, unsorted\",\n\t\t\tversions: []kubernetes.NodeVersion{\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node2\",\n\t\t\t\t\tVersion: v110,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node1\",\n\t\t\t\t\tVersion: v100,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node3\",\n\t\t\t\t\tVersion: v120,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node4dirty\",\n\t\t\t\t\tVersion: v130Dirty,\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    v100,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple versions, same version\",\n\t\t\tversions: []kubernetes.NodeVersion{\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node1\",\n\t\t\t\t\tVersion: v110,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tNode:    \"node2\",\n\t\t\t\t\tVersion: v110,\n\t\t\t\t},\n\t\t\t},\n\t\t\twant:    v110,\n\t\t\twantErr: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tgot, err := kubernetes.GetMinimumTalosVersion(tt.versions)\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tt.want, got)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/detect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/blang/semver/v4\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n// DetectLowestVersion returns lowest Kubernetes components versions in the cluster.\n//\n//nolint:gocyclo\nfunc DetectLowestVersion(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions) (string, error) {\n\tk8sClient, err := cluster.K8sHelper(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t}\n\n\tapps := map[string]struct{}{\n\t\t\"kube-apiserver\":          {},\n\t\t\"kube-controller-manager\": {},\n\t\t\"kube-proxy\":              {},\n\t\t\"kube-scheduler\":          {},\n\t}\n\n\tpods, err := k8sClient.CoreV1().Pods(\"kube-system\").List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tvar version *semver.Version\n\n\tfor _, pod := range pods.Items {\n\t\tapp := pod.GetObjectMeta().GetLabels()[\"k8s-app\"]\n\t\tif _, ok := apps[app]; !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, container := range pod.Spec.Containers {\n\t\t\tif container.Name != app {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\timage, _, _ := strings.Cut(container.Image, \"@\")\n\n\t\t\t_, imageTag, ok := strings.Cut(image, \":\")\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tv, err := semver.ParseTolerant(strings.TrimLeft(imageTag, \"v\"))\n\t\t\tif err != nil {\n\t\t\t\toptions.Log(\"failed to parse %s container version %s\", app, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif version == nil || v.LT(*version) {\n\t\t\t\tversion = &v\n\t\t\t}\n\t\t}\n\t}\n\n\tif version == nil {\n\t\treturn \"\", errors.New(\"failed to detect lowest Kubernetes version\")\n\t}\n\n\treturn version.String(), nil\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tv1alpha1config \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nconst kubelet = \"kubelet\"\n\nfunc upgradeKubelet(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions) error {\n\tif !options.UpgradeKubelet {\n\t\toptions.Log(\"skipped updating kubelet\")\n\n\t\treturn nil\n\t}\n\n\toptions.Log(\"updating kubelet to version %q\", options.Path.ToVersion())\n\n\tfor node := range xiter.Concat(slices.Values(options.controlPlaneNodes), slices.Values(options.workerNodes)) {\n\t\tif err := upgradeKubeletOnNode(ctx, cluster, options, node); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating node %q: %w\", node, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc upgradeKubeletOnNode(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions, node string) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tc, err := cluster.Client()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Talos API client: %w\", err)\n\t}\n\n\tctx = client.WithNode(ctx, node)\n\n\toptions.Log(\" > %q: starting update\", node)\n\n\twatchCh := make(chan safe.WrappedStateEvent[*v1alpha1.Service])\n\n\tif err = safe.StateWatch(ctx, c.COSI, resource.NewMetadata(v1alpha1.NamespaceName, v1alpha1.ServiceType, kubelet, resource.VersionUndefined), watchCh); err != nil {\n\t\treturn fmt.Errorf(\"error watching service: %w\", err)\n\t}\n\n\tvar ev safe.WrappedStateEvent[*v1alpha1.Service]\n\n\tselect {\n\tcase ev = <-watchCh:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\tif ev.Type() != state.Created {\n\t\treturn fmt.Errorf(\"unexpected event type: %s\", ev.Type())\n\t}\n\n\tinitialService, err := ev.Resource()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error inspecting service: %w\", err)\n\t}\n\n\tif !initialService.TypedSpec().Running || !initialService.TypedSpec().Healthy {\n\t\treturn errors.New(\"kubelet is not healthy\")\n\t}\n\n\t// find out current kubelet version, as the machine config might have a missing image field,\n\t// look it up from the kubelet spec\n\n\tkubeletSpec, err := safe.StateGet[*k8s.KubeletSpec](ctx, c.COSI, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, kubelet, resource.VersionUndefined))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching kubelet spec: %w\", err)\n\t}\n\n\tskipWait := false\n\n\terr = patchNodeConfig(ctx, cluster, node, options.EncoderOpt, upgradeKubeletPatcher(options, kubeletSpec))\n\tif err != nil {\n\t\tif errors.Is(err, errUpdateSkipped) {\n\t\t\tskipWait = true\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"error patching node config: %w\", err)\n\t\t}\n\t}\n\n\tif options.DryRun {\n\t\treturn nil\n\t}\n\n\toptions.Log(\" > %q: machine configuration patched\", node)\n\n\tif !skipWait {\n\t\toptions.Log(\" > %q: waiting for kubelet restart\", node)\n\n\t\t// first, wait for kubelet to go down\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase ev = <-watchCh:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\t}\n\n\t\t\tif ev.Type() == state.Destroyed {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// now wait for kubelet to go up & healthy\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase ev = <-watchCh:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\t}\n\n\t\t\tif ev.Type() == state.Created || ev.Type() == state.Updated {\n\t\t\t\tvar service *v1alpha1.Service\n\n\t\t\t\tservice, err = ev.Resource()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error inspecting service: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif service.TypedSpec().Running && service.TypedSpec().Healthy {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toptions.Log(\" > %q: waiting for node update\", node)\n\n\tif err = retry.Constant(3*time.Minute, retry.WithUnits(10*time.Second)).Retry(\n\t\tfunc() error {\n\t\t\treturn checkNodeKubeletVersion(ctx, cluster, node, \"v\"+options.Path.ToVersion())\n\t\t},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\toptions.Log(\" < %q: successfully updated\", node)\n\n\treturn nil\n}\n\nfunc extractKubeletVersionSuffix(imageRef string) string {\n\tfor _, suffix := range []string{\"-fat\", \"-slim\"} {\n\t\tif strings.HasSuffix(imageRef, suffix) {\n\t\t\treturn suffix\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\nfunc upgradeKubeletPatcher(\n\toptions UpgradeOptions,\n\tkubeletSpec *k8s.KubeletSpec,\n) func(config *v1alpha1config.Config) error {\n\treturn func(config *v1alpha1config.Config) error {\n\t\tif config.MachineConfig == nil {\n\t\t\tconfig.MachineConfig = &v1alpha1config.MachineConfig{}\n\t\t}\n\n\t\tif config.MachineConfig.MachineKubelet == nil {\n\t\t\tconfig.MachineConfig.MachineKubelet = &v1alpha1config.KubeletConfig{}\n\t\t}\n\n\t\toldImage := kubeletSpec.TypedSpec().Image\n\t\toldImage, _, _ = strings.Cut(oldImage, \"@\") // ignore digest if present\n\n\t\toldSuffix := extractKubeletVersionSuffix(oldImage)\n\t\tnewVersion := options.Path.ToVersion() + oldSuffix\n\n\t\tlogUpdate := func(oldImage string) {\n\t\t\t_, version, _ := strings.Cut(oldImage, \":\")\n\t\t\tif version == \"\" {\n\t\t\t\tversion = options.Path.FromVersion()\n\t\t\t}\n\n\t\t\tversion = strings.TrimLeft(version, \"v\")\n\n\t\t\toptions.Log(\" > update %s: %s -> %s\", kubelet, version, newVersion)\n\n\t\t\tif options.DryRun {\n\t\t\t\toptions.Log(\" > skipped in dry-run\")\n\t\t\t}\n\t\t}\n\n\t\timage := fmt.Sprintf(\"%s:v%s\", options.KubeletImage, newVersion)\n\n\t\tif oldImage == image {\n\t\t\treturn errUpdateSkipped\n\t\t}\n\n\t\tlogUpdate(oldImage)\n\n\t\tif options.DryRun {\n\t\t\treturn errUpdateSkipped\n\t\t}\n\n\t\tconfig.MachineConfig.MachineKubelet.KubeletImage = image\n\n\t\treturn nil\n\t}\n}\n\n//nolint:gocyclo\nfunc checkNodeKubeletVersion(ctx context.Context, cluster UpgradeProvider, nodeToCheck, version string) error {\n\tk8sClient, err := cluster.K8sHelper(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t}\n\n\tnodes, err := k8sClient.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\tif kubernetes.IsRetryableError(err) {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\treturn err\n\t}\n\n\tnodeFound := false\n\n\tfor _, node := range nodes.Items {\n\t\tmatchingNode := false\n\n\t\tfor _, address := range node.Status.Addresses {\n\t\t\tif address.Address == nodeToCheck {\n\t\t\t\tmatchingNode = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !matchingNode {\n\t\t\tcontinue\n\t\t}\n\n\t\tnodeFound = true\n\n\t\tif node.Status.NodeInfo.KubeletVersion != version {\n\t\t\treturn retry.ExpectedErrorf(\n\t\t\t\t\"node version mismatch: got %q, expected %q\",\n\t\t\t\tnode.Status.NodeInfo.KubeletVersion,\n\t\t\t\tversion,\n\t\t\t)\n\t\t}\n\n\t\tready := false\n\n\t\tfor _, condition := range node.Status.Conditions {\n\t\t\tif condition.Type != v1.NodeReady {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif condition.Status == v1.ConditionTrue {\n\t\t\t\tready = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !ready {\n\t\t\treturn retry.ExpectedErrorf(\"node is not ready\")\n\t\t}\n\n\t\tbreak\n\t}\n\n\tif !nodeFound {\n\t\treturn retry.ExpectedErrorf(\"node %q not found\", nodeToCheck)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubernetes provides cluster-wide kubernetes utilities.\npackage kubernetes\n"
  },
  {
    "path": "pkg/cluster/kubernetes/kubernetes_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/upgrade\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestUpgradePath(t *testing.T) {\n\t// ensure that upgrade path is available for n-5 supported Kubernetes versions\n\tlatestVersion, err := semver.ParseTolerant(constants.DefaultKubernetesVersion)\n\trequire.NoError(t, err)\n\n\tfor minorVersion := latestVersion.Minor - constants.SupportedKubernetesVersions + 1; minorVersion <= latestVersion.Minor; minorVersion++ {\n\t\tthisVersion := fmt.Sprintf(\"%d.%d\", latestVersion.Major, minorVersion)\n\n\t\tpath, err := upgrade.NewPath(thisVersion, thisVersion)\n\t\trequire.NoError(t, err)\n\n\t\tassert.True(t, path.IsSupported(), \"upgrade path %s is not supported\", path.String())\n\n\t\tif minorVersion != latestVersion.Minor {\n\t\t\tnextVersion := fmt.Sprintf(\"%d.%d\", latestVersion.Major, minorVersion+1)\n\n\t\t\tpath, err = upgrade.NewPath(thisVersion, nextVersion)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.True(t, path.IsSupported(), \"upgrade path %s is not supported\", path.String())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/patch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\tv1alpha1config \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// patchNodeConfig updates node configuration by means of patch function.\nfunc patchNodeConfig(ctx context.Context, cluster UpgradeProvider, node string, encoderOpt encoder.Option, patchFunc func(config *v1alpha1config.Config) error) error {\n\tc, err := cluster.Client()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Talos API client: %w\", err)\n\t}\n\n\tctx = client.WithNode(ctx, node)\n\n\tmc, err := safe.StateGetByID[*config.MachineConfig](ctx, c.COSI, config.ActiveID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching config resource: %w\", err)\n\t}\n\n\tprovider := mc.Provider()\n\n\tnewProvider, err := provider.PatchV1Alpha1(patchFunc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error patching config: %w\", err)\n\t}\n\n\tcfgBytes, err := newProvider.EncodeBytes(encoderOpt)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error serializing config: %w\", err)\n\t}\n\n\t_, err = c.ApplyConfiguration(ctx, &machine.ApplyConfigurationRequest{\n\t\tData: cfgBytes,\n\t\tMode: machine.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error applying config: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/talos_managed.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\t\"github.com/siderolabs/gen/channel\"\n\t\"github.com/siderolabs/gen/xiter\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/manifests\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa\"\n\tssacli \"github.com/siderolabs/go-kubernetes/kubernetes/ssa/cli\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/upgrade\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/client-go/informers\"\n\t\"k8s.io/client-go/tools/cache\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tmachinetype \"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tv1alpha1config \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// UpgradeProvider are the cluster interfaces required by upgrade process.\ntype UpgradeProvider interface {\n\tcluster.ClientProvider\n\tcluster.K8sProvider\n}\n\n// ValidateImageReference validates if the provided string is a valid Docker image reference.\nfunc ValidateImageReference(ref string) error {\n\t_, err := name.ParseReference(ref)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid image reference: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Validate checks all image references in the upgrade options.\nfunc (options *UpgradeOptions) Validate() error {\n\timages := map[string]string{\n\t\t\"kubelet\":            options.KubeletImage,\n\t\t\"apiserver\":          options.APIServerImage,\n\t\t\"controller-manager\": options.ControllerManagerImage,\n\t\t\"scheduler\":          options.SchedulerImage,\n\t\t\"proxy\":              options.ProxyImage,\n\t}\n\n\tfor name, image := range images {\n\t\tif err := ValidateImageReference(image); err != nil {\n\t\t\treturn fmt.Errorf(\"%s: %w\", name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Upgrade the Kubernetes control plane components, manifests, kubelets.\n//\n//nolint:gocyclo,cyclop\nfunc Upgrade(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions) error {\n\tif err := options.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"invalid upgrade options: %w\", err)\n\t}\n\n\tif !options.Path.IsSupported() {\n\t\treturn fmt.Errorf(\"unsupported upgrade path %s (from %q to %q)\", options.Path, options.Path.FromVersion(), options.Path.ToVersion())\n\t}\n\n\tk8sClient, err := cluster.K8sHelper(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t}\n\n\tdefer k8sClient.Close() //nolint:errcheck\n\n\toptions.controlPlaneNodes, err = k8sClient.NodeIPs(ctx, machinetype.TypeControlPlane)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching controlplane nodes: %w\", err)\n\t}\n\n\tif len(options.controlPlaneNodes) == 0 {\n\t\treturn errors.New(\"no controlplane nodes discovered\")\n\t}\n\n\toptions.Log(\"discovered controlplane nodes %q\", options.controlPlaneNodes)\n\n\tif options.UpgradeKubelet {\n\t\toptions.workerNodes, err = k8sClient.NodeIPs(ctx, machinetype.TypeWorker)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching worker nodes: %w\", err)\n\t\t}\n\n\t\toptions.Log(\"discovered worker nodes %q\", options.workerNodes)\n\t}\n\n\ttalosClient, err := cluster.Client()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tk8sConfig, err := cluster.K8sRestConfig(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tminTalosVersion, err := VerifyVersionCompatibility(ctx, talosClient, slices.Concat(options.controlPlaneNodes, options.workerNodes), options.Path.ToVersion(), options.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tupgradeChecks, err := upgrade.NewChecks(options.Path, talosClient.COSI, k8sConfig, options.controlPlaneNodes, options.workerNodes, options.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = upgradeChecks.Run(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif options.PrePullImages {\n\t\tif err = prePullImages(ctx, talosClient, options); err != nil {\n\t\t\treturn fmt.Errorf(\"failed pre-pulling images: %w\", err)\n\t\t}\n\t}\n\n\tfor _, service := range []string{kubeAPIServer, kubeControllerManager, kubeScheduler} {\n\t\tif err = upgradeStaticPod(ctx, cluster, options, service); err != nil {\n\t\t\treturn fmt.Errorf(\"failed updating service %q: %w\", service, err)\n\t\t}\n\t}\n\n\tif err = upgradeKubeProxy(ctx, cluster, options); err != nil {\n\t\treturn fmt.Errorf(\"failed updating kube-proxy: %w\", err)\n\t}\n\n\tif options.UpgradeKubelet {\n\t\tif err = upgradeKubelet(ctx, cluster, options); err != nil {\n\t\t\treturn fmt.Errorf(\"failed upgrading kubelet: %w\", err)\n\t\t}\n\t}\n\n\tuseSSA := minTalosVersion.SupportsSSAManifestSync()\n\n\treturn PerformManifestsSync(ctx, cluster, useSSA, options)\n}\n\nfunc prePullImages(ctx context.Context, talosClient *client.Client, options UpgradeOptions) error {\n\tfor _, imageRef := range []string{\n\t\tfmt.Sprintf(\"%s:v%s\", options.APIServerImage, options.Path.ToVersion()),\n\t\tfmt.Sprintf(\"%s:v%s\", options.ControllerManagerImage, options.Path.ToVersion()),\n\t\tfmt.Sprintf(\"%s:v%s\", options.SchedulerImage, options.Path.ToVersion()),\n\t} {\n\t\tfor _, node := range options.controlPlaneNodes {\n\t\t\toptions.Log(\" > %q: pre-pulling %s\", node, imageRef)\n\n\t\t\t//nolint:staticcheck // using legacy method, but should be refactored\n\t\t\terr := talosClient.ImagePull(client.WithNode(ctx, node), common.ContainerdNamespace_NS_CRI, imageRef)\n\t\t\tif err != nil {\n\t\t\t\tif status.Code(err) == codes.Unimplemented {\n\t\t\t\t\toptions.Log(\" < %q: not implemented, skipping\", node)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"error pre-pulling %s on %s: %w\", imageRef, node, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif !options.UpgradeKubelet {\n\t\treturn nil\n\t}\n\n\tfor node := range xiter.Concat(slices.Values(options.controlPlaneNodes), slices.Values(options.workerNodes)) {\n\t\tkubeletSpec, err := safe.StateGet[*k8s.KubeletSpec](client.WithNode(ctx, node), talosClient.COSI, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, kubelet, resource.VersionUndefined))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error fetching kubelet spec on node %s: %w\", node, err)\n\t\t}\n\n\t\timageSuffix := extractKubeletVersionSuffix(kubeletSpec.TypedSpec().Image)\n\t\timageRef := fmt.Sprintf(\"%s:v%s%s\", options.KubeletImage, options.Path.ToVersion(), imageSuffix)\n\n\t\toptions.Log(\" > %q: pre-pulling %s\", node, imageRef)\n\n\t\t//nolint:staticcheck // using legacy method, but should be refactored\n\t\terr = talosClient.ImagePull(client.WithNode(ctx, node), common.ContainerdNamespace_NS_SYSTEM, imageRef)\n\t\tif err != nil {\n\t\t\tif status.Code(err) == codes.Unimplemented {\n\t\t\t\toptions.Log(\" < %q: not implemented, skipping\", node)\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"error pre-pulling %s on %s: %w\", imageRef, node, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc upgradeStaticPod(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions, service string) error {\n\toptions.Log(\"updating %q to version %q\", service, options.Path.ToVersion())\n\n\tfor _, node := range options.controlPlaneNodes {\n\t\tif err := upgradeStaticPodOnNode(ctx, cluster, options, service, node); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating node %q: %w\", node, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc upgradeKubeProxy(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions) error {\n\toptions.Log(\"updating kube-proxy to version %q\", options.Path.ToVersion())\n\n\tfor _, node := range options.controlPlaneNodes {\n\t\toptions.Log(\" > %q: starting update\", node)\n\n\t\tif err := patchNodeConfig(ctx, cluster, node, options.EncoderOpt, patchKubeProxy(options)); err != nil {\n\t\t\treturn fmt.Errorf(\"error updating node %q: %w\", node, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc patchKubeProxy(options UpgradeOptions) func(config *v1alpha1config.Config) error {\n\treturn func(config *v1alpha1config.Config) error {\n\t\tif options.DryRun {\n\t\t\toptions.Log(\" > skipped in dry-run\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif config.ClusterConfig == nil {\n\t\t\tconfig.ClusterConfig = &v1alpha1config.ClusterConfig{}\n\t\t}\n\n\t\tif config.ClusterConfig.ProxyConfig == nil {\n\t\t\tconfig.ClusterConfig.ProxyConfig = &v1alpha1config.ProxyConfig{}\n\t\t}\n\n\t\tconfig.ClusterConfig.ProxyConfig.ContainerImage = fmt.Sprintf(\"%s:v%s\", options.ProxyImage, options.Path.ToVersion())\n\n\t\treturn nil\n\t}\n}\n\nfunc controlplaneConfigResourceType(service string) resource.Type {\n\tswitch service {\n\tcase kubeAPIServer:\n\t\treturn k8s.APIServerConfigType\n\tcase kubeControllerManager:\n\t\treturn k8s.ControllerManagerConfigType\n\tcase kubeScheduler:\n\t\treturn k8s.SchedulerConfigType\n\t}\n\n\tpanic(fmt.Sprintf(\"unknown service ID %q\", service))\n}\n\n//nolint:gocyclo\nfunc upgradeStaticPodOnNode(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions, service, node string) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tc, err := cluster.Client()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Talos API client: %w\", err)\n\t}\n\n\tctx = client.WithNode(ctx, node)\n\n\toptions.Log(\" > %q: starting update\", node)\n\n\twatchCh := make(chan state.Event)\n\n\tif err = c.COSI.Watch(ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, controlplaneConfigResourceType(service), service, resource.VersionUndefined), watchCh); err != nil {\n\t\treturn fmt.Errorf(\"error watching service configuration: %w\", err)\n\t}\n\n\tvar (\n\t\texpectedConfigVersion string\n\t\tinitialConfig         resource.Resource\n\t)\n\n\tselect {\n\tcase ev := <-watchCh:\n\t\tif ev.Type != state.Created {\n\t\t\treturn fmt.Errorf(\"unexpected event type: %d\", ev.Type)\n\t\t}\n\n\t\texpectedConfigVersion = ev.Resource.Metadata().Version().String()\n\t\tinitialConfig = ev.Resource\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\tskipConfigWait := false\n\n\terr = patchNodeConfig(ctx, cluster, node, options.EncoderOpt, upgradeStaticPodPatcher(options, service, initialConfig))\n\tif err != nil {\n\t\tif errors.Is(err, errUpdateSkipped) {\n\t\t\tskipConfigWait = true\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"error patching node config: %w\", err)\n\t\t}\n\t}\n\n\tif options.DryRun {\n\t\treturn nil\n\t}\n\n\toptions.Log(\" > %q: machine configuration patched\", node)\n\toptions.Log(\" > %q: waiting for %s pod update\", node, service)\n\n\tif !skipConfigWait {\n\t\tselect {\n\t\tcase ev := <-watchCh:\n\t\t\tif ev.Type != state.Updated {\n\t\t\t\treturn fmt.Errorf(\"unexpected event type: %d\", ev.Type)\n\t\t\t}\n\n\t\t\texpectedConfigVersion = ev.Resource.Metadata().Version().String()\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\t}\n\n\tif err = checkPodStatus(ctx, cluster, options, service, node, expectedConfigVersion); err != nil {\n\t\treturn err\n\t}\n\n\toptions.Log(\" < %q: successfully updated\", node)\n\n\treturn nil\n}\n\nvar errUpdateSkipped = errors.New(\"update skipped\")\n\nfunc staticPodImage(logUpdate func(oldImage string), imageName, containerImage, configImage string, options UpgradeOptions) (string, error) {\n\timage := fmt.Sprintf(\"%s:v%s\", imageName, options.Path.ToVersion())\n\n\tif containerImage == image || configImage == image {\n\t\treturn \"\", errUpdateSkipped\n\t}\n\n\tlogUpdate(containerImage)\n\n\tif options.DryRun {\n\t\treturn \"\", errUpdateSkipped\n\t}\n\n\treturn image, nil\n}\n\n//nolint:gocyclo\nfunc upgradeStaticPodPatcher(options UpgradeOptions, service string, configResource resource.Resource) func(config *v1alpha1config.Config) error {\n\treturn func(config *v1alpha1config.Config) error {\n\t\tif config.ClusterConfig == nil {\n\t\t\tconfig.ClusterConfig = &v1alpha1config.ClusterConfig{}\n\t\t}\n\n\t\tvar configImage string\n\n\t\tswitch r := configResource.(type) {\n\t\tcase *k8s.APIServerConfig:\n\t\t\tconfigImage = r.TypedSpec().Image\n\t\tcase *k8s.ControllerManagerConfig:\n\t\t\tconfigImage = r.TypedSpec().Image\n\t\tcase *k8s.SchedulerConfig:\n\t\t\tconfigImage = r.TypedSpec().Image\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported service config %T\", configResource)\n\t\t}\n\n\t\tlogUpdate := func(oldImage string) {\n\t\t\toldImage, _, _ = strings.Cut(oldImage, \"@\") // ignore digest if present\n\t\t\t_, version, _ := strings.Cut(oldImage, \":\")\n\n\t\t\tif version == \"\" {\n\t\t\t\tversion = options.Path.FromVersion()\n\t\t\t}\n\n\t\t\toptions.Log(\" > update %s: %s -> %s\", service, version, options.Path.ToVersion())\n\n\t\t\tif options.DryRun {\n\t\t\t\toptions.Log(\" > skipped in dry-run\")\n\t\t\t}\n\t\t}\n\n\t\tswitch service {\n\t\tcase kubeAPIServer:\n\t\t\tif config.ClusterConfig.APIServerConfig == nil {\n\t\t\t\tconfig.ClusterConfig.APIServerConfig = &v1alpha1config.APIServerConfig{}\n\t\t\t}\n\n\t\t\timage, err := staticPodImage(logUpdate,\n\t\t\t\toptions.APIServerImage,\n\t\t\t\tconfig.ClusterConfig.APIServerConfig.ContainerImage,\n\t\t\t\tconfigImage,\n\t\t\t\toptions)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfig.ClusterConfig.APIServerConfig.ContainerImage = image\n\t\tcase kubeControllerManager:\n\t\t\tif config.ClusterConfig.ControllerManagerConfig == nil {\n\t\t\t\tconfig.ClusterConfig.ControllerManagerConfig = &v1alpha1config.ControllerManagerConfig{}\n\t\t\t}\n\n\t\t\timage, err := staticPodImage(logUpdate,\n\t\t\t\toptions.ControllerManagerImage,\n\t\t\t\tconfig.ClusterConfig.ControllerManagerConfig.ContainerImage,\n\t\t\t\tconfigImage,\n\t\t\t\toptions)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfig.ClusterConfig.ControllerManagerConfig.ContainerImage = image\n\t\tcase kubeScheduler:\n\t\t\tif config.ClusterConfig.SchedulerConfig == nil {\n\t\t\t\tconfig.ClusterConfig.SchedulerConfig = &v1alpha1config.SchedulerConfig{}\n\t\t\t}\n\n\t\t\timage, err := staticPodImage(logUpdate,\n\t\t\t\toptions.SchedulerImage,\n\t\t\t\tconfig.ClusterConfig.SchedulerConfig.ContainerImage,\n\t\t\t\tconfigImage,\n\t\t\t\toptions)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfig.ClusterConfig.SchedulerConfig.ContainerImage = image\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported service %q\", service)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// PerformManifestsSync performs manifests sync from Talos manifest list to Kubernetes.\nfunc PerformManifestsSync(\n\tctx context.Context,\n\tcluster UpgradeProvider,\n\tuseSSA bool,\n\toptions UpgradeOptions,\n) error {\n\tobjects, err := getManifests(ctx, cluster)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Use server-side apply for Talos versions >= v1.13.0\n\tif useSSA {\n\t\treturn syncManifestsSSA(ctx, objects, cluster, options)\n\t}\n\n\treturn syncManifests(ctx, objects, cluster, options)\n}\n\nfunc getManifests(ctx context.Context, cluster UpgradeProvider) ([]*unstructured.Unstructured, error) {\n\ttalosclient, err := cluster.Client()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer cluster.Close() //nolint:errcheck\n\n\tmd, _ := metadata.FromOutgoingContext(ctx)\n\tif nodes := md[\"nodes\"]; len(nodes) > 0 {\n\t\tctx = client.WithNode(ctx, nodes[0])\n\t}\n\n\treturn manifests.GetBootstrapManifests(ctx, talosclient.COSI, nil)\n}\n\n// syncManifests is the legacy non SSA manifests sync function.\n// It should be removed once Talos v1.12 is no longer supported.\nfunc syncManifests(ctx context.Context, objects []*unstructured.Unstructured, cluster UpgradeProvider, options UpgradeOptions) error {\n\tconfig, err := cluster.K8sRestConfig(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn manifests.SyncWithLog(ctx, objects, config, options.DryRun, options.Log)\n}\n\n//nolint:gocyclo\nfunc syncManifestsSSA(ctx context.Context, objects []*unstructured.Unstructured, cluster UpgradeProvider, options UpgradeOptions) error {\n\tconfig, err := cluster.K8sRestConfig(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tupdatingManifestsLogline := \"updating manifests\"\n\tif options.DryRun {\n\t\tupdatingManifestsLogline += \" (dry run)\"\n\t}\n\n\toptions.Log(\"%s\", updatingManifestsLogline)\n\n\tmanager, err := ssa.NewManager(ctx, config,\n\t\tconstants.KubernetesFieldManagerName,\n\t\tconstants.KubernetesInventoryNamespace,\n\t\tconstants.KubernetesBootstrapManifestsInventoryName,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating SSA manager: %w\", err)\n\t}\n\n\tdefer manager.Close()\n\n\tif options.DryRun {\n\t\t// only do the diff in dry-run mode\n\t\tchanges, err := manager.Diff(ctx, objects, ssa.DiffOptions{\n\t\t\tNoPrune:         options.NoPrune,\n\t\t\tInventoryPolicy: options.InventoryPolicy,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error diffing manifests: %w\", err)\n\t\t}\n\n\t\tfor _, change := range changes {\n\t\t\toptions.Log(\" < %s %s\", change.Action, change.Subject)\n\n\t\t\tif change.Diff != \"\" {\n\t\t\t\toptions.Log(\"%s\", change.Diff)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tchanges, err := manager.Apply(ctx, objects, ssa.ApplyOptions{\n\t\tInventoryPolicy: options.InventoryPolicy,\n\t\tWaitTimeout:     options.ReconcileTimeout,\n\t\tNoPrune:         options.NoPrune,\n\t\tForce:           options.ForceManifests,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error applying manifests: %w\", err)\n\t}\n\n\tssacli.LogApplyResults(ctx, changes, manager, options.Log)\n\n\tif options.SkipManifestWait {\n\t\toptions.Log(\"skipping waiting for manifest reconciliation\")\n\n\t\treturn nil\n\t}\n\n\twaitOptions := ssa.WaitOptions{\n\t\tInterval: 2 * time.Second,\n\t\tTimeout:  options.ReconcileTimeout,\n\t\tFailFast: true,\n\t}\n\n\treturn ssacli.Wait(ctx, changes, options.Log, manager, waitOptions)\n}\n\n//nolint:gocyclo\nfunc checkPodStatus(ctx context.Context, cluster UpgradeProvider, options UpgradeOptions, service, node, configVersion string) error {\n\tctx, cancel := context.WithTimeout(ctx, 5*time.Minute)\n\tdefer cancel()\n\n\tk8sClient, err := cluster.K8sHelper(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building kubernetes client: %w\", err)\n\t}\n\n\tdefer k8sClient.Close() //nolint:errcheck\n\n\tinformerFactory := informers.NewSharedInformerFactoryWithOptions(\n\t\tk8sClient, 10*time.Second,\n\t\tinformers.WithNamespace(namespace),\n\t\tinformers.WithTweakListOptions(func(options *metav1.ListOptions) {\n\t\t\toptions.LabelSelector = fmt.Sprintf(\"k8s-app = %s\", service)\n\t\t}),\n\t)\n\n\tnotifyCh := make(chan *v1.Pod)\n\n\tinformer := informerFactory.Core().V1().Pods().Informer()\n\n\tif err := informer.SetWatchErrorHandler(func(r *cache.Reflector, err error) {\n\t\toptions.Log(\"kubernetes endpoint watch error: %s\", err)\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error setting watch error handler: %w\", err)\n\t}\n\n\tif _, err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{\n\t\tAddFunc:    func(obj any) { channel.SendWithContext(ctx, notifyCh, obj.(*v1.Pod)) },\n\t\tDeleteFunc: func(_ any) {},\n\t\tUpdateFunc: func(_, obj any) { channel.SendWithContext(ctx, notifyCh, obj.(*v1.Pod)) },\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error adding watch event handler: %w\", err)\n\t}\n\n\tinformerFactory.Start(ctx.Done())\n\n\tdefer func() {\n\t\tcancel()\n\t\tinformerFactory.Shutdown()\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase pod := <-notifyCh:\n\t\t\tif pod.Status.HostIP != node {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif pod.Annotations[constants.AnnotationStaticPodConfigVersion] != configVersion {\n\t\t\t\toptions.Log(\" > %q: %s: waiting, config version mismatch: got %q, expected %q\", node, service, pod.Annotations[constants.AnnotationStaticPodConfigVersion], configVersion)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tready := false\n\n\t\t\tfor _, condition := range pod.Status.Conditions {\n\t\t\t\tif condition.Type != v1.PodReady {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif condition.Status == v1.ConditionTrue {\n\t\t\t\t\tready = true\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !ready {\n\t\t\t\toptions.Log(\" > %q: %s: pod is not ready, waiting\", node, service)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/upgrade.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/ssa\"\n\t\"github.com/siderolabs/go-kubernetes/kubernetes/upgrade\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nconst (\n\tnamespace = \"kube-system\"\n\n\tkubeAPIServer         = \"kube-apiserver\"\n\tkubeControllerManager = \"kube-controller-manager\"\n\tkubeScheduler         = \"kube-scheduler\"\n)\n\n// UpgradeOptions represents Kubernetes control plane upgrade settings.\ntype UpgradeOptions struct {\n\tPath *upgrade.Path\n\n\tDryRun               bool\n\tControlPlaneEndpoint string\n\tLogOutput            io.Writer\n\tPrePullImages        bool\n\tUpgradeKubelet       bool\n\tEncoderOpt           encoder.Option\n\n\tKubeletImage           string\n\tAPIServerImage         string\n\tControllerManagerImage string\n\tSchedulerImage         string\n\tProxyImage             string\n\n\tNoPrune          bool\n\tForceManifests   bool\n\tReconcileTimeout time.Duration\n\tInventoryPolicy  ssa.InventoryPolicy\n\tSkipManifestWait bool\n\n\tcontrolPlaneNodes []string\n\tworkerNodes       []string\n}\n\n// Log writes the line to logger or to stdout if no logger was provided.\nfunc (options *UpgradeOptions) Log(line string, args ...any) {\n\tif options.LogOutput != nil {\n\t\tfmt.Fprintf(options.LogOutput, line, args...) //nolint:errcheck\n\n\t\treturn\n\t}\n\n\tfmt.Printf(line+\"\\n\", args...)\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes/upgrade_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster/kubernetes\"\n)\n\nfunc TestValidateImageReference(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tref     string\n\t\twantErr bool\n\t\terrMsg  string\n\t}{\n\t\t{\n\t\t\tname:    \"valid simple image\",\n\t\t\tref:     \"k8s.gcr.io/kube-apiserver:v1.23.0\",\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"valid image with digest\",\n\t\t\tref:     \"k8s.gcr.io/kube-apiserver@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"valid image with port\",\n\t\t\tref:     \"localhost:5000/kube-apiserver:latest\",\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid image reference\",\n\t\t\tref:     \"invalid/image@sha256:invalid\",\n\t\t\twantErr: true,\n\t\t\terrMsg:  \"invalid image reference\",\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid image reference v2\",\n\t\t\tref:     \":v1.32.1\",\n\t\t\twantErr: true,\n\t\t\terrMsg:  \"invalid image reference\",\n\t\t},\n\t\t{\n\t\t\tname:    \"empty image reference\",\n\t\t\tref:     \"\",\n\t\t\twantErr: true,\n\t\t\terrMsg:  \"invalid image reference\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := kubernetes.ValidateImageReference(tt.ref)\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\n\t\t\t\tif tt.errMsg != \"\" {\n\t\t\t\t\tassert.Contains(t, err.Error(), tt.errMsg)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestUpgradeOptions_validate(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\toptions kubernetes.UpgradeOptions\n\t\twantErr bool\n\t\terrMsg  string\n\t}{\n\t\t{\n\t\t\tname: \"valid images\",\n\t\t\toptions: kubernetes.UpgradeOptions{\n\t\t\t\tKubeletImage:           \"k8s.gcr.io/kubelet:v1.23.0\",\n\t\t\t\tAPIServerImage:         \"k8s.gcr.io/kube-apiserver:v1.23.0\",\n\t\t\t\tControllerManagerImage: \"k8s.gcr.io/kube-controller-manager:v1.23.0\",\n\t\t\t\tSchedulerImage:         \"k8s.gcr.io/kube-scheduler:v1.23.0\",\n\t\t\t\tProxyImage:             \"k8s.gcr.io/kube-proxy:v1.23.0\",\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid kubelet image\",\n\t\t\toptions: kubernetes.UpgradeOptions{\n\t\t\t\tKubeletImage:           \"invalid/image@sha256:invalid\",\n\t\t\t\tAPIServerImage:         \"k8s.gcr.io/kube-apiserver:v1.23.0\",\n\t\t\t\tControllerManagerImage: \"k8s.gcr.io/kube-controller-manager:v1.23.0\",\n\t\t\t\tSchedulerImage:         \"k8s.gcr.io/kube-scheduler:v1.23.0\",\n\t\t\t\tProxyImage:             \"k8s.gcr.io/kube-proxy:v1.23.0\",\n\t\t\t},\n\t\t\twantErr: true,\n\t\t\terrMsg:  \"kubelet: invalid image reference\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid apiserver image\",\n\t\t\toptions: kubernetes.UpgradeOptions{\n\t\t\t\tKubeletImage:           \"k8s.gcr.io/kubelet:v1.23.0\",\n\t\t\t\tAPIServerImage:         \":v1.23.0\",\n\t\t\t\tControllerManagerImage: \"k8s.gcr.io/kube-controller-manager:v1.23.0\",\n\t\t\t\tSchedulerImage:         \"k8s.gcr.io/kube-scheduler:v1.23.0\",\n\t\t\t\tProxyImage:             \"k8s.gcr.io/kube-proxy:v1.23.0\",\n\t\t\t},\n\t\t\twantErr: true,\n\t\t\terrMsg:  \"apiserver: invalid image reference\",\n\t\t},\n\t\t{\n\t\t\tname: \"image with digest\",\n\t\t\toptions: kubernetes.UpgradeOptions{\n\t\t\t\tKubeletImage:           \"k8s.gcr.io/kubelet@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\t\tAPIServerImage:         \"k8s.gcr.io/kube-apiserver:v1.23.0@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\t\tControllerManagerImage: \"k8s.gcr.io/kube-controller-manager:v1.23.0\",\n\t\t\t\tSchedulerImage:         \"k8s.gcr.io/kube-scheduler:v1.23.0\",\n\t\t\t\tProxyImage:             \"k8s.gcr.io/kube-proxy:v1.23.0\",\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"image with port number\",\n\t\t\toptions: kubernetes.UpgradeOptions{\n\t\t\t\tKubeletImage:           \"localhost:5000/kubelet:latest\",\n\t\t\t\tAPIServerImage:         \"k8s.gcr.io/kube-apiserver:v1.23.0\",\n\t\t\t\tControllerManagerImage: \"k8s.gcr.io/kube-controller-manager:v1.23.0\",\n\t\t\t\tSchedulerImage:         \"k8s.gcr.io/kube-scheduler:v1.23.0\",\n\t\t\t\tProxyImage:             \"k8s.gcr.io/kube-proxy:v1.23.0\",\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.options.Validate()\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\n\t\t\t\tif tt.errMsg != \"\" {\n\t\t\t\t\tassert.Contains(t, err.Error(), tt.errMsg)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/cluster/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\tk8s \"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// KubernetesClient provides Kubernetes client built via Talos API Kubeconfig.\ntype KubernetesClient struct {\n\t// Base Talos client provider.\n\tClientProvider\n\n\t// ForceEndpoint overrides default Kubernetes API endpoint.\n\tForceEndpoint string\n\n\tKubeHelper *k8s.Client\n\n\tkubeconfig []byte\n\tclientset  *kubernetes.Clientset\n}\n\n// Kubeconfig returns raw kubeconfig.\n//\n// Kubeconfig is cached.\nfunc (k *KubernetesClient) Kubeconfig(ctx context.Context) ([]byte, error) {\n\tif k.kubeconfig != nil {\n\t\treturn k.kubeconfig, nil\n\t}\n\n\tclient, err := k.Client()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tk.kubeconfig, err = client.Kubeconfig(ctx)\n\n\treturn k.kubeconfig, err\n}\n\n// K8sRestConfig returns *rest.Config (parsed kubeconfig).\nfunc (k *KubernetesClient) K8sRestConfig(ctx context.Context) (*rest.Config, error) {\n\tkubeconfig, err := k.Kubeconfig(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig, err := clientcmd.BuildConfigFromKubeconfigGetter(\"\", func() (*clientcmdapi.Config, error) {\n\t\treturn clientcmd.Load(kubeconfig)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif k.ForceEndpoint != \"\" {\n\t\tforceEndpoint, _ := strings.CutPrefix(k.ForceEndpoint, \"https://\")\n\n\t\thost, port, err := net.SplitHostPort(forceEndpoint)\n\t\tif err != nil {\n\t\t\thost = forceEndpoint\n\t\t\tport = strconv.Itoa(constants.DefaultControlPlanePort)\n\t\t}\n\n\t\tconfig.Host = net.JoinHostPort(host, port)\n\t}\n\n\treturn config, nil\n}\n\n// K8sClient builds Kubernetes client via Talos Kubeconfig API.\n//\n// Kubernetes client instance is cached.\nfunc (k *KubernetesClient) K8sClient(ctx context.Context) (*kubernetes.Clientset, error) {\n\tif k.clientset != nil {\n\t\treturn k.clientset, nil\n\t}\n\n\tconfig, err := k.K8sRestConfig(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif k.KubeHelper, err = k8s.NewForConfig(config); err != nil {\n\t\treturn nil, err\n\t}\n\n\tk.clientset = k.KubeHelper.Clientset\n\n\treturn k.clientset, nil\n}\n\n// K8sHelper returns wrapper around K8sClient.\nfunc (k *KubernetesClient) K8sHelper(ctx context.Context) (*k8s.Client, error) {\n\tif k.KubeHelper != nil {\n\t\treturn k.KubeHelper, nil\n\t}\n\n\t_, err := k.K8sClient(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn k.KubeHelper, nil\n}\n\n// K8sClose closes Kubernetes client.\nfunc (k *KubernetesClient) K8sClose() error {\n\tif k.KubeHelper == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KubeHelper.Close()\n}\n"
  },
  {
    "path": "pkg/cluster/local.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\tsecretsgen \"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// LocalClientProvider builds Talos client to connect to same-node apid instance over file socket.\ntype LocalClientProvider struct {\n\tclient    *client.Client\n\tresources state.State\n\troles     role.Set\n}\n\n// NewLocalClientProvider creates a new LocalClientProvider instance.\n//\n// This provider only works on controlplane nodes, as it relies on the\n// root Talos API certificate being available.\nfunc NewLocalClientProvider(resources state.State, roles role.Set) *LocalClientProvider {\n\treturn &LocalClientProvider{\n\t\tresources: resources,\n\t\troles:     roles,\n\t}\n}\n\n// Client returns Talos client instance for default (if no endpoints are given) or\n// specific endpoints.\n//\n// Client implements ClientProvider interface.\nfunc (c *LocalClientProvider) Client(endpoints ...string) (*client.Client, error) {\n\tif c.client != nil {\n\t\treturn c.client, nil\n\t}\n\n\tctx := context.TODO()\n\n\trootSecrets, err := safe.StateGetByID[*secrets.OSRoot](ctx, c.resources, secrets.OSRootID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get OS root secrets: %w\", err)\n\t}\n\n\tnodeAddress, err := safe.StateGetByID[*network.NodeAddress](ctx, c.resources, network.NodeAddressDefaultID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get node address: %w\", err)\n\t}\n\n\tif len(nodeAddress.TypedSpec().IPs()) == 0 {\n\t\treturn nil, fmt.Errorf(\"no node IPs found in node address\")\n\t}\n\n\tif len(endpoints) == 0 {\n\t\tendpoints = []string{nodeAddress.TypedSpec().IPs()[0].String()}\n\t}\n\n\t// use a short-lived certificate, as we need to connect once\n\tconst certificateTTL = 10 * time.Minute\n\n\tcert, err := secretsgen.NewAdminCertificateAndKey(\n\t\ttime.Now(),\n\t\trootSecrets.TypedSpec().IssuingCA,\n\t\tc.roles,\n\t\tcertificateTTL,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate client certificate: %w\", err)\n\t}\n\n\ttalosconfig := clientconfig.NewConfig(\"local\", endpoints, rootSecrets.TypedSpec().IssuingCA.Crt, cert)\n\n\tc.client, err = client.New(\n\t\tctx,\n\t\tclient.WithConfig(talosconfig),\n\t)\n\n\treturn c.client, err\n}\n\n// Close all the client connections.\nfunc (c *LocalClientProvider) Close() error {\n\tif c.client != nil {\n\t\tif err := c.client.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tc.client = nil\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/logsaarchive.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/filemap\"\n)\n\n// SaveClusterLogsArchive saves all logs from the cluster state directory to a gzip archive.\nfunc SaveClusterLogsArchive(statePath, archivePath string) {\n\tif err := saveClusterLogsArchive(statePath, archivePath); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"error saving cluster logs archive: %v\\n\", err)\n\t}\n}\n\nfunc saveClusterLogsArchive(statePath, archivePath string) error {\n\tvar logFileMap []filemap.File\n\n\tif err := filepath.WalkDir(statePath, func(path string, d os.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !strings.HasSuffix(path, \".log\") {\n\t\t\treturn nil\n\t\t}\n\n\t\trel, err := filepath.Rel(statePath, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif d.IsDir() && rel == \".\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tstatInfo, err := d.Info()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlogFileMap = append(logFileMap, filemap.File{\n\t\t\tImagePath:  rel,\n\t\t\tSourcePath: path,\n\t\t\tImageMode:  int64(statInfo.Mode().Perm()),\n\t\t})\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error building filemap: %w\", err)\n\t}\n\n\tlogFile, err := os.Create(archivePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating log archive: %w\", err)\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tgzipWriter := gzip.NewWriter(logFile)\n\tdefer gzipWriter.Close() //nolint:errcheck\n\n\tr := filemap.Build(logFileMap)\n\n\tif _, err := io.Copy(gzipWriter, r); err != nil {\n\t\treturn fmt.Errorf(\"error writing log archive: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/cluster/provision.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// MapProvisionNodeInfosToClusterNodeInfos maps provision.NodeInfos to cluster.NodeInfos.\nfunc MapProvisionNodeInfosToClusterNodeInfos(nodes []provision.NodeInfo) ([]NodeInfo, error) {\n\tresult := make([]NodeInfo, len(nodes))\n\n\tfor i, info := range nodes {\n\t\tclusterNodeInfo, err := toClusterNodeInfo(info)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult[i] = *clusterNodeInfo\n\t}\n\n\treturn result, nil\n}\n\n// MapProvisionNodeInfosToNodeInfosByType maps provision.NodeInfos\n// to cluster.NodeInfos, grouping them by machine type.\nfunc MapProvisionNodeInfosToNodeInfosByType(nodes []provision.NodeInfo) (map[machine.Type][]NodeInfo, error) {\n\tresult := make(map[machine.Type][]NodeInfo)\n\n\tfor _, info := range nodes {\n\t\tclusterNodeInfo, err := toClusterNodeInfo(info)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult[info.Type] = append(result[info.Type], *clusterNodeInfo)\n\t}\n\n\treturn result, nil\n}\n\nfunc toClusterNodeInfo(info provision.NodeInfo) (*NodeInfo, error) {\n\tips := make([]netip.Addr, len(info.IPs))\n\n\tfor i, ip := range info.IPs {\n\t\tparsed, err := netip.ParseAddr(ip.String())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tips[i] = parsed\n\t}\n\n\treturn &NodeInfo{\n\t\tInternalIP: ips[0],\n\t\tIPs:        ips,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/conditions/all.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package conditions provides a set of conditions which can be used to wait for some condition to be met.\npackage conditions\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-multierror\"\n)\n\ntype all struct {\n\tmu sync.Mutex\n\n\tconditions []Condition\n}\n\ntype waitResult struct {\n\ti   int\n\terr error\n}\n\nfunc (a *all) Wait(ctx context.Context) error {\n\terrCh := make(chan waitResult)\n\n\ta.mu.Lock()\n\n\tfor i := range a.conditions {\n\t\tgo func(i int) {\n\t\t\terrCh <- waitResult{\n\t\t\t\terr: a.conditions[i].Wait(ctx),\n\t\t\t\ti:   i,\n\t\t\t}\n\t\t}(i)\n\t}\n\n\ta.mu.Unlock()\n\n\terr := (*multierror.Error)(nil)\n\n\tfor range a.conditions {\n\t\tres := <-errCh\n\n\t\ta.mu.Lock()\n\t\ta.conditions[res.i] = nil\n\t\ta.mu.Unlock()\n\n\t\terr = multierror.Append(err, res.err)\n\t}\n\n\t// collapse errors if any of them is context canceled\n\tif err != nil {\n\t\tfor _, e := range err.Errors {\n\t\t\tif e == context.Canceled {\n\t\t\t\treturn e\n\t\t\t}\n\t\t}\n\t}\n\n\treturn err.ErrorOrNil()\n}\n\nfunc (a *all) String() string {\n\tdescriptions := []string(nil)\n\n\ta.mu.Lock()\n\n\tfor _, c := range a.conditions {\n\t\tif c != nil {\n\t\t\tdescriptions = append(descriptions, c.String())\n\t\t}\n\t}\n\n\ta.mu.Unlock()\n\n\treturn strings.Join(descriptions, \", \")\n}\n\n// WaitForAll creates a condition which waits for all the conditions to be successful.\n//\n// If the condition is nil, it is ignored.\n// WaitForAll(nil) return nil.\nfunc WaitForAll(conditions ...Condition) Condition {\n\tres := &all{}\n\n\tfor _, c := range conditions {\n\t\tif c == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif multi, ok := c.(*all); ok {\n\t\t\t// flatten lists\n\t\t\tres.conditions = append(res.conditions, multi.conditions...)\n\t\t} else {\n\t\t\tres.conditions = append(res.conditions, c)\n\t\t}\n\t}\n\n\treturn res\n}\n"
  },
  {
    "path": "pkg/conditions/all_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\ntype AllSuite struct {\n\tsuite.Suite\n}\n\ntype MockCondition struct {\n\tdescription string\n\terrCh       chan error\n}\n\nfunc (mc *MockCondition) String() string {\n\treturn mc.description\n}\n\nfunc (mc *MockCondition) Wait(ctx context.Context) error {\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase err := <-mc.errCh:\n\t\treturn err\n\t}\n}\n\nfunc (suite *AllSuite) TestString() {\n\tsuite.Require().Equal(\"A, B\", conditions.WaitForAll(\n\t\t&MockCondition{description: \"A\"},\n\t\t&MockCondition{description: \"B\"},\n\t).String())\n\n\tsuite.Require().Equal(\"A\", conditions.WaitForAll(\n\t\t&MockCondition{description: \"A\"},\n\t).String())\n\n\tconds := []conditions.Condition{\n\t\t&MockCondition{description: \"A\", errCh: make(chan error)},\n\t\t&MockCondition{description: \"B\", errCh: make(chan error)},\n\t}\n\n\twaiter := conditions.WaitForAll(conds...)\n\n\tdone := make(chan error)\n\n\tgo func() {\n\t\tdone <- waiter.Wait(context.Background())\n\t}()\n\n\tsuite.Require().Equal(\"A, B\", waiter.String())\n\n\tconds[0].(*MockCondition).errCh <- nil\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// done waiting for 'A', so description should now be shorter\n\tsuite.Require().Equal(\"B\", waiter.String())\n\n\tconds[1].(*MockCondition).errCh <- nil\n\n\t<-done\n}\n\nfunc (suite *AllSuite) TestFlatten() {\n\tconds1 := []conditions.Condition{\n\t\t&MockCondition{description: \"A\", errCh: make(chan error)},\n\t\t&MockCondition{description: \"B\", errCh: make(chan error)},\n\t}\n\tconds2 := []conditions.Condition{\n\t\t&MockCondition{description: \"C\", errCh: make(chan error)},\n\t\t&MockCondition{description: \"D\", errCh: make(chan error)},\n\t}\n\n\twaiter := conditions.WaitForAll(conditions.WaitForAll(conds1...), conditions.WaitForAll(conds2...))\n\tsuite.Require().Equal(\"A, B, C, D\", waiter.String())\n\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tdone := make(chan error)\n\n\tgo func() {\n\t\tdone <- waiter.Wait(ctx)\n\t}()\n\n\tconds1[0].(*MockCondition).errCh <- nil\n\n\tconds2[1].(*MockCondition).errCh <- nil\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tsuite.Require().Equal(\"B, C\", waiter.String())\n\n\tctxCancel()\n\n\tsuite.Require().Equal(context.Canceled, <-done)\n}\n\nfunc TestAllSuite(t *testing.T) {\n\tsuite.Run(t, new(AllSuite))\n}\n"
  },
  {
    "path": "pkg/conditions/conditions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// OK is returned by the String method of the passed Condition.\nconst OK = \"OK\"\n\n// Condition is a object which Wait()s for some condition to become true.\n//\n// Condition can describe itself via String() method.\ntype Condition interface {\n\tfmt.Stringer\n\tWait(ctx context.Context) error\n}\n"
  },
  {
    "path": "pkg/conditions/files.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\ntype file string\n\nfunc (filename file) Wait(ctx context.Context) error {\n\tticker := time.NewTicker(time.Second)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\t_, err := os.Stat(string(filename))\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t}\n\t}\n}\n\nfunc (filename file) String() string {\n\treturn fmt.Sprintf(\"file %q to exist\", string(filename))\n}\n\n// WaitForFileToExist is a service condition that will wait for the existence of\n// a file.\nfunc WaitForFileToExist(filename string) Condition {\n\treturn file(filename)\n}\n\n// WaitForFilesToExist is a service condition that will wait for the existence of all the files.\nfunc WaitForFilesToExist(filenames ...string) Condition {\n\tconditions := xslices.Map(filenames, WaitForFileToExist)\n\n\treturn WaitForAll(conditions...)\n}\n"
  },
  {
    "path": "pkg/conditions/files_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\ntype FilesSuite struct {\n\tsuite.Suite\n\n\ttempDir string\n}\n\nfunc (suite *FilesSuite) SetupSuite() {\n\tsuite.tempDir = suite.T().TempDir()\n}\n\nfunc (suite *FilesSuite) createFile(name string) (path string) {\n\tpath = filepath.Join(suite.tempDir, name)\n\tf, err := os.Create(path)\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(f.Close())\n\n\treturn path\n}\n\nfunc (suite *FilesSuite) TestString() {\n\tsuite.Require().Equal(\"file \\\"abc.txt\\\" to exist\", conditions.WaitForFileToExist(\"abc.txt\").String())\n}\n\nfunc (suite *FilesSuite) TestWaitForFileToExist() {\n\tpath := suite.createFile(\"w.txt\")\n\n\terr := conditions.WaitForFileToExist(path).Wait(context.Background())\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(os.Remove(path))\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- conditions.WaitForFileToExist(path).Wait(context.Background())\n\t}()\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Fail(\"unexpected return\")\n\tdefault:\n\t}\n\n\tsuite.createFile(\"w.txt\")\n\n\tsuite.Require().NoError(<-errCh)\n\n\tsuite.Require().NoError(os.Remove(path))\n\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tgo func() {\n\t\terrCh <- conditions.WaitForFileToExist(path).Wait(ctx)\n\t}()\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Fail(\"unexpected return\")\n\tdefault:\n\t}\n\n\tctxCancel()\n\n\tsuite.Require().EqualError(<-errCh, context.Canceled.Error())\n}\n\nfunc (suite *FilesSuite) TestWaitForAllFilesToExist() {\n\tpathA := suite.createFile(\"wA.txt\")\n\tpathB := suite.createFile(\"wB.txt\")\n\n\terr := conditions.WaitForFilesToExist(pathA, pathB).Wait(context.Background())\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().NoError(os.Remove(pathB))\n\n\terrCh := make(chan error)\n\n\tgo func() {\n\t\terrCh <- conditions.WaitForFilesToExist(pathA, pathB).Wait(context.Background())\n\t}()\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Fail(\"unexpected return\")\n\tdefault:\n\t}\n\n\tsuite.createFile(\"wB.txt\")\n\n\tsuite.Require().NoError(<-errCh)\n\n\tsuite.Require().NoError(os.Remove(pathA))\n\tsuite.Require().NoError(os.Remove(pathB))\n\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tgo func() {\n\t\terrCh <- conditions.WaitForFilesToExist(pathA, pathB).Wait(ctx)\n\t}()\n\n\ttime.Sleep(50 * time.Millisecond)\n\n\tselect {\n\tcase <-errCh:\n\t\tsuite.Fail(\"unexpected return\")\n\tdefault:\n\t}\n\n\tctxCancel()\n\n\tsuite.Require().EqualError(<-errCh, context.Canceled.Error())\n}\n\nfunc TestFilesSuite(t *testing.T) {\n\tsuite.Run(t, new(FilesSuite))\n}\n"
  },
  {
    "path": "pkg/conditions/kubeconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"time\"\n\n\t\"k8s.io/client-go/tools/clientcmd\"\n)\n\ntype kubeconfig string\n\nfunc (filename kubeconfig) Wait(ctx context.Context) error {\n\tticker := time.NewTicker(time.Second)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\t_, err := os.Stat(string(filename))\n\t\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = clientcmd.BuildConfigFromFlags(\"\", string(filename))\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\t// TODO: we can't check for specific error here (looking for file not found for client key/cert):\n\t\t//       https://github.com/kubernetes/kubernetes/pull/105080\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t}\n\t}\n}\n\nfunc (filename kubeconfig) String() string {\n\treturn fmt.Sprintf(\"kubeconfig %q to be ready\", string(filename))\n}\n\n// WaitForKubeconfigReady is a condition that will wait for the kubeconfig to be ready.\nfunc WaitForKubeconfigReady(filename string) Condition {\n\treturn kubeconfig(filename)\n}\n"
  },
  {
    "path": "pkg/conditions/none.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions\n\nimport \"context\"\n\ntype condition struct{}\n\nfunc (condition) Wait(ctx context.Context) error {\n\treturn nil\n}\n\nfunc (condition) String() string {\n\treturn \"nothing\"\n}\n\n// None is a service condition that has no conditions.\nfunc None() Condition {\n\treturn condition{}\n}\n"
  },
  {
    "path": "pkg/conditions/poll.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\n// ErrSkipAssertion is used as a return value from AssertionFunc to indicate that this assertion\n// (and, by extension, condition, and check) is to be skipped.\n// It is not returned as an error by any Condition's Wait method\n// but recorded as description and returned by String method.\nvar ErrSkipAssertion = errors.New(\"SKIP\")\n\n// AssertionFunc is called every poll interval until it returns nil.\ntype AssertionFunc func(ctx context.Context) error\n\ntype pollingCondition struct {\n\tlastErrMu  sync.Mutex\n\tlastErr    error\n\tlastErrSet bool\n\n\tassertion   AssertionFunc\n\tdescription string\n\tinterval    time.Duration\n}\n\nfunc (p *pollingCondition) String() string {\n\tlastErr := \"...\"\n\n\tp.lastErrMu.Lock()\n\n\tif p.lastErrSet {\n\t\tif p.lastErr != nil {\n\t\t\tlastErr = p.lastErr.Error()\n\t\t} else {\n\t\t\tlastErr = OK\n\t\t}\n\t}\n\n\tp.lastErrMu.Unlock()\n\n\treturn fmt.Sprintf(\"%s: %s\", p.description, lastErr)\n}\n\nfunc (p *pollingCondition) Wait(ctx context.Context) error {\n\tticker := time.NewTicker(p.interval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\terr := func() error {\n\t\t\trunCtx, runCtxCancel := context.WithTimeout(ctx, p.interval)\n\t\t\tdefer runCtxCancel()\n\n\t\t\terr := p.assertion(runCtx)\n\n\t\t\tp.lastErrMu.Lock()\n\t\t\tp.lastErr = err\n\t\t\tp.lastErrSet = true\n\t\t\tp.lastErrMu.Unlock()\n\n\t\t\treturn err\n\t\t}()\n\t\tif err == nil || err == ErrSkipAssertion {\n\t\t\treturn nil\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-ticker.C:\n\t\t}\n\t}\n}\n\n// PollingCondition converts AssertionFunc into Condition by calling it every interval until\n// it completes or the context is canceled.\nfunc PollingCondition(description string, assertion AssertionFunc, interval time.Duration) Condition {\n\treturn &pollingCondition{\n\t\tassertion:   assertion,\n\t\tdescription: description,\n\t\tinterval:    interval,\n\t}\n}\n"
  },
  {
    "path": "pkg/conditions/poll_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage conditions_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/conditions\"\n)\n\nfunc TestPollingCondition(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"OK\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar calls int\n\n\t\tcond := conditions.PollingCondition(\"Test condition\", func(ctx context.Context) error {\n\t\t\tcalls++\n\n\t\t\tif calls < 2 {\n\t\t\t\treturn errors.New(\"failed\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}, time.Millisecond)\n\n\t\terr := cond.Wait(t.Context())\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"Test condition: OK\", cond.String())\n\t\tassert.Equal(t, 2, calls)\n\t})\n\n\tt.Run(\"Skip\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar calls int\n\n\t\tcond := conditions.PollingCondition(\"Test condition\", func(ctx context.Context) error {\n\t\t\tcalls++\n\n\t\t\tif calls < 2 {\n\t\t\t\treturn errors.New(\"failed\")\n\t\t\t}\n\n\t\t\treturn conditions.ErrSkipAssertion\n\t\t}, time.Millisecond)\n\n\t\terr := cond.Wait(t.Context())\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"Test condition: SKIP\", cond.String())\n\t\tassert.Equal(t, 2, calls)\n\t})\n\n\tt.Run(\"Fatal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar calls int\n\n\t\tcond := conditions.PollingCondition(\"Test condition\", func(ctx context.Context) error {\n\t\t\tcalls++\n\n\t\t\treturn errors.New(\"failed\")\n\t\t}, 750*time.Millisecond)\n\n\t\tctx, cancel := context.WithTimeout(t.Context(), 1400*time.Millisecond)\n\t\tdefer cancel()\n\n\t\terr := cond.Wait(ctx)\n\t\tassert.Equal(t, context.DeadlineExceeded, err)\n\t\tassert.Equal(t, \"Test condition: failed\", cond.String())\n\t\tassert.Equal(t, 2, calls)\n\t})\n}\n"
  },
  {
    "path": "pkg/download/download.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package download provides a download with retries for machine configuration and userdata.\npackage download\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"maps\"\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-cleanhttp\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n)\n\nconst b64 = \"base64\"\n\ntype downloadOptions struct {\n\tHeaders    map[string]string\n\tFormat     string\n\tLowSrcPort bool\n\n\tEndpointFunc func(context.Context) (string, error)\n\n\tErrorOnNotFound      error\n\tErrorOnBadRequest    error\n\tErrorOnEmptyResponse error\n\n\tTimeout      time.Duration\n\tRetryOptions []retry.Option\n}\n\n// Option configures the download options.\ntype Option func(*downloadOptions)\n\nfunc downloadDefaults(endpoint string) *downloadOptions {\n\treturn &downloadOptions{\n\t\tEndpointFunc: func(context.Context) (string, error) {\n\t\t\treturn endpoint, nil\n\t\t},\n\t\tHeaders: make(map[string]string),\n\t\tTimeout: 3 * time.Minute,\n\t}\n}\n\n// WithFormat specifies the source format. This ultimately will be a yaml\n// but may be represented in different formats. For example, the config\n// may be base64 encoded.\nfunc WithFormat(format string) Option {\n\treturn func(d *downloadOptions) {\n\t\tswitch format {\n\t\tcase b64:\n\t\t\td.Format = b64\n\t\tdefault:\n\t\t\td.Format = \"yaml\"\n\t\t}\n\t}\n}\n\n// WithHeaders specifies any http headers that are needed for downloading\n// the config.\nfunc WithHeaders(headers map[string]string) Option {\n\treturn func(d *downloadOptions) {\n\t\tif headers == nil {\n\t\t\treturn\n\t\t}\n\n\t\tif d.Headers == nil {\n\t\t\td.Headers = map[string]string{}\n\t\t}\n\n\t\tmaps.Copy(d.Headers, headers)\n\t}\n}\n\n// WithLowSrcPort sets low source port to download\n// the config.\nfunc WithLowSrcPort() Option {\n\treturn func(d *downloadOptions) {\n\t\td.LowSrcPort = true\n\t}\n}\n\n// WithErrorOnNotFound provides specific error to return when response has HTTP 404 error.\nfunc WithErrorOnNotFound(e error) Option {\n\treturn func(d *downloadOptions) {\n\t\td.ErrorOnNotFound = e\n\t}\n}\n\n// WithErrorOnEmptyResponse provides specific error to return when response is empty.\nfunc WithErrorOnEmptyResponse(e error) Option {\n\treturn func(d *downloadOptions) {\n\t\td.ErrorOnEmptyResponse = e\n\t}\n}\n\n// WithErrorOnBadRequest provides specific error to return when response has HTTP 400 error.\nfunc WithErrorOnBadRequest(e error) Option {\n\treturn func(d *downloadOptions) {\n\t\td.ErrorOnBadRequest = e\n\t}\n}\n\n// WithEndpointFunc provides a function that sets the endpoint of the download options.\nfunc WithEndpointFunc(endpointFunc func(context.Context) (string, error)) Option {\n\treturn func(d *downloadOptions) {\n\t\td.EndpointFunc = endpointFunc\n\t}\n}\n\n// WithTimeout sets the timeout for the download.\nfunc WithTimeout(timeout time.Duration) Option {\n\treturn func(d *downloadOptions) {\n\t\td.Timeout = timeout\n\t}\n}\n\n// WithRetryOptions sets the retry options for the download.\nfunc WithRetryOptions(opts ...retry.Option) Option {\n\treturn func(d *downloadOptions) {\n\t\td.RetryOptions = append(d.RetryOptions, opts...)\n\t}\n}\n\n// Download downloads a config.\n//\n//nolint:gocyclo\nfunc Download(ctx context.Context, endpoint string, opts ...Option) (b []byte, err error) {\n\toptions := downloadDefaults(endpoint)\n\n\tfor _, opt := range opts {\n\t\topt(options)\n\t}\n\n\terr = retry.Exponential(\n\t\toptions.Timeout,\n\t\tappend([]retry.Option{\n\t\t\tretry.WithUnits(time.Second),\n\t\t\tretry.WithJitter(time.Second),\n\t\t\tretry.WithErrorLogging(true),\n\t\t},\n\t\t\toptions.RetryOptions...,\n\t\t)...,\n\t).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tvar attemptEndpoint string\n\n\t\tattemptEndpoint, err = options.EndpointFunc(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = func() error {\n\t\t\tvar u *url.URL\n\n\t\t\tu, err = url.Parse(attemptEndpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif u.Scheme == \"file\" {\n\t\t\t\tvar fileContent []byte\n\n\t\t\t\tfileContent, err = os.ReadFile(u.Path)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tb = fileContent\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tvar req *http.Request\n\n\t\t\tif req, err = http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor k, v := range options.Headers {\n\t\t\t\treq.Header.Set(k, v)\n\t\t\t}\n\n\t\t\tb, err = download(req, options)\n\n\t\t\treturn err\n\t\t}(); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to download config from %q: %w\", endpoint, err)\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.Format == b64 {\n\t\tvar b64 []byte\n\n\t\tb64, err = base64.StdEncoding.DecodeString(string(b))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tb = b64\n\t}\n\n\treturn b, nil\n}\n\n//nolint:gocyclo\nfunc download(req *http.Request, options *downloadOptions) (data []byte, err error) {\n\ttransport := httpdefaults.PatchTransport(cleanhttp.DefaultTransport())\n\ttransport.RegisterProtocol(\"tftp\", NewTFTPTransport())\n\n\tif options.LowSrcPort {\n\t\tport := 100 + rand.IntN(512)\n\n\t\tlocalTCPAddr, tcperr := net.ResolveTCPAddr(\"tcp\", \":\"+strconv.Itoa(port))\n\t\tif tcperr != nil {\n\t\t\treturn nil, retry.ExpectedErrorf(\"resolving source tcp address: %s\", tcperr.Error())\n\t\t}\n\n\t\td := (&net.Dialer{\n\t\t\tTimeout:   30 * time.Second,\n\t\t\tKeepAlive: 30 * time.Second,\n\t\t\tDualStack: true,\n\t\t\tLocalAddr: localTCPAddr,\n\t\t}).DialContext\n\n\t\ttransport.DialContext = d\n\t}\n\n\tclient := &http.Client{\n\t\tTransport: transport,\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn data, retry.ExpectedError(err)\n\t}\n\t//nolint:errcheck\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusNotFound && options.ErrorOnNotFound != nil {\n\t\treturn data, options.ErrorOnNotFound\n\t}\n\n\tif resp.StatusCode == http.StatusBadRequest && options.ErrorOnBadRequest != nil {\n\t\treturn data, options.ErrorOnBadRequest\n\t}\n\n\t// 204 - StatusNoContent is also a successful response, signaling  that there is no body\n\tif resp.StatusCode == http.StatusNoContent {\n\t\treturn data, options.ErrorOnEmptyResponse\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\t// try to read first 32 bytes of the response body\n\t\t// to provide more context in case of error\n\t\tdata, _ = io.ReadAll(io.LimitReader(resp.Body, 32)) //nolint:errcheck // as error already happened, we don't care much about this one\n\t\tdata = bytes.ToValidUTF8(data, nil)\n\n\t\treturn data, retry.ExpectedErrorf(\"failed to download config, status code %d, body %q\", resp.StatusCode, string(data))\n\t}\n\n\tdata, err = io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn data, retry.ExpectedErrorf(\"read config: %s\", err.Error())\n\t}\n\n\tif len(data) == 0 && options.ErrorOnEmptyResponse != nil {\n\t\treturn data, options.ErrorOnEmptyResponse\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "pkg/download/download_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage download_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/download\"\n)\n\ntype flipper struct {\n\tsrv   *httptest.Server\n\tval   int\n\tsleep time.Duration\n}\n\nfunc (f *flipper) EndpointFunc() func(context.Context) (string, error) {\n\treturn func(context.Context) (string, error) {\n\t\ttime.Sleep(f.sleep)\n\n\t\tf.val++\n\n\t\tif f.val%2 == 1 {\n\t\t\treturn f.srv.URL + \"/404\", nil\n\t\t}\n\n\t\treturn f.srv.URL + \"/data\", nil\n\t}\n}\n\nfunc TestDownload(t *testing.T) {\n\tt.Parallel()\n\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/empty\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\tcase \"/data\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Write([]byte(\"data\")) //nolint:errcheck\n\t\tcase \"/base64\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tw.Write([]byte(\"ZGF0YQ==\")) //nolint:errcheck\n\t\tcase \"/400\":\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\tfmt.Fprintln(w, \"bad request\")\n\t\tcase \"/404\":\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tfmt.Fprintln(w, \"not found\")\n\t\tcase \"/204\":\n\t\t\tw.WriteHeader(http.StatusNoContent)\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t}\n\t}))\n\tt.Cleanup(srv.Close)\n\n\tflip := flipper{\n\t\tsrv: srv,\n\t}\n\n\tsleepingFlip := flipper{\n\t\tsrv:   srv,\n\t\tsleep: 100 * time.Millisecond,\n\t}\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tpath string\n\t\topts []download.Option\n\n\t\texpected      string\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:     \"empty download\",\n\t\t\tpath:     \"/empty\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty download with 204\",\n\t\t\tpath:     \"/204\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"some data\",\n\t\t\tpath:     \"/data\",\n\t\t\texpected: \"data\",\n\t\t},\n\t\t{\n\t\t\tname:     \"base64\",\n\t\t\tpath:     \"/base64\",\n\t\t\topts:     []download.Option{download.WithFormat(\"base64\")},\n\t\t\texpected: \"data\",\n\t\t},\n\t\t{\n\t\t\tname:          \"empty error\",\n\t\t\tpath:          \"/empty\",\n\t\t\topts:          []download.Option{download.WithErrorOnEmptyResponse(errors.New(\"empty response\"))},\n\t\t\texpectedError: \"empty response\",\n\t\t},\n\t\t{\n\t\t\tname:          \"empty error by 204\",\n\t\t\tpath:          \"/204\",\n\t\t\topts:          []download.Option{download.WithErrorOnEmptyResponse(errors.New(\"empty response\"))},\n\t\t\texpectedError: \"empty response\",\n\t\t},\n\t\t{\n\t\t\tname:          \"not found error\",\n\t\t\tpath:          \"/404\",\n\t\t\topts:          []download.Option{download.WithErrorOnNotFound(errors.New(\"gone forever\"))},\n\t\t\texpectedError: \"gone forever\",\n\t\t},\n\t\t{\n\t\t\tname:          \"bad request error\",\n\t\t\tpath:          \"/400\",\n\t\t\topts:          []download.Option{download.WithErrorOnBadRequest(errors.New(\"bad req\"))},\n\t\t\texpectedError: \"bad req\",\n\t\t},\n\t\t{\n\t\t\tname:          \"failure 404\",\n\t\t\tpath:          \"/404\",\n\t\t\topts:          []download.Option{download.WithTimeout(2 * time.Second)},\n\t\t\texpectedError: \"failed to download config, status code 404, body \\\"not found\\\\n\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:          \"failure 400\",\n\t\t\tpath:          \"/400\",\n\t\t\topts:          []download.Option{download.WithTimeout(2 * time.Second)},\n\t\t\texpectedError: \"failed to download config, status code 400, body \\\"bad request\\\\n\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"retry endpoint change\",\n\t\t\topts: []download.Option{\n\t\t\t\tdownload.WithTimeout(2 * time.Second),\n\t\t\t\tdownload.WithEndpointFunc(flip.EndpointFunc()),\n\t\t\t},\n\t\t\texpected: \"data\",\n\t\t},\n\t\t{\n\t\t\tname: \"retry with attempt timeout\",\n\t\t\topts: []download.Option{\n\t\t\t\tdownload.WithTimeout(2 * time.Second),\n\t\t\t\tdownload.WithEndpointFunc(sleepingFlip.EndpointFunc()),\n\t\t\t\tdownload.WithRetryOptions(retry.WithAttemptTimeout(200 * time.Millisecond)),\n\t\t\t},\n\t\t\texpected: \"data\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tb, err := download.Download(ctx, srv.URL+test.path, test.opts...)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, test.expected, string(b))\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/download/tftp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage download\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/pin/tftp/v3\"\n)\n\n// NewTFTPTransport returns an http.RoundTripper capable of handling the TFTP\n// protocol.\nfunc NewTFTPTransport() http.RoundTripper {\n\treturn tftpRoundTripper{}\n}\n\ntype tftpRoundTripper struct{}\n\nfunc (t tftpRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {\n\taddr := req.URL.Host\n\n\tif req.URL.Port() == \"\" {\n\t\taddr += \":69\"\n\t}\n\n\tc, err := tftp.NewClient(addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tw, err := c.Receive(req.URL.Path, \"octet\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbuf := &bytes.Buffer{}\n\n\twritten, err := w.WriteTo(buf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif expected, ok := w.(tftp.IncomingTransfer).Size(); ok {\n\t\tif written != expected {\n\t\t\treturn nil, fmt.Errorf(\"expected %d bytes, got %d\", expected, written)\n\t\t}\n\t}\n\n\treturn &http.Response{\n\t\tStatus:        \"200 OK\",\n\t\tStatusCode:    http.StatusOK,\n\t\tProto:         \"TFTP/1.0\",\n\t\tProtoMajor:    1,\n\t\tProtoMinor:    0,\n\t\tBody:          io.NopCloser(buf),\n\t\tContentLength: -1,\n\t\tRequest:       req,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/filetree/chown.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage filetree\n\nimport (\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n)\n\n// ChownRecursive changes file ownership recursively from the specified root.\nfunc ChownRecursive(root string, uid, gid uint32) error {\n\treturn filepath.Walk(root, func(path string, info fs.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif info.Sys().(*syscall.Stat_t).Uid != uid || info.Sys().(*syscall.Stat_t).Gid != gid {\n\t\t\treturn os.Chown(path, int(uid), int(gid))\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "pkg/filetree/filetree.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package filetree provides file tree operations.\npackage filetree\n"
  },
  {
    "path": "pkg/flags/flags.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package flags provides custom pflag.Value implementations for common use cases.\npackage flags\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/spf13/pflag\"\n)\n\ntype choiceValue struct {\n\tvalue    string\n\tvalidate func(string) error\n}\n\n// Set implements pflag.Value interface.\nfunc (v *choiceValue) Set(s string) error {\n\terr := v.validate(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tv.value = s\n\n\treturn nil\n}\n\n// Type implements pflag.Value interface.\nfunc (v *choiceValue) Type() string { return \"string\" }\n\n// String implements pflag.Value interface.\nfunc (v *choiceValue) String() string { return v.value }\n\n// StringChoice returns a [choiceValue] that validates the value against a set\n// of choices. Only the last value will be used if multiple values are set.\nfunc StringChoice(defaultValue string, otherChoices ...string) pflag.Value {\n\treturn &choiceValue{\n\t\tvalue: defaultValue,\n\t\tvalidate: func(s string) error {\n\t\t\tchoices := slices.Concat(otherChoices, []string{defaultValue})\n\n\t\t\tif slices.Contains(choices, s) {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"must be one of %v\", choices)\n\t\t},\n\t}\n}\n\ntype semverValue struct {\n\tvalue      semver.Version\n\tvalidators []SemverValidateFunc\n}\n\n// SemverValidateFunc allows setting restrictions on the version.\ntype SemverValidateFunc func(v semver.Version) error\n\n// Set implements pflag.Value interface.\nfunc (v *semverValue) Set(s string) error {\n\tvers, err := semver.ParseTolerant(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, validator := range v.validators {\n\t\tif err := validator(vers); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tv.value = vers\n\n\treturn nil\n}\n\n// Type implements pflag.Value interface.\nfunc (v *semverValue) Type() string { return \"semver\" }\n\n// String implements pflag.Value interface.\nfunc (v *semverValue) String() string { return \"v\" + v.value.String() }\n\n// Semver returns a pflag.Value that parses and stores a semantic version.\n//\n// Parsing is performed using semver.ParseTolerant. After parsing, any provided\n// SemverValidateFunc validators are applied in order and may reject the version.\n//\n// The returned value is initialized with defaultValue, which is used until Set\n// is called successfully.\nfunc Semver(defaultValue string, validators ...SemverValidateFunc) pflag.Value {\n\tv, err := semver.ParseTolerant(defaultValue)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn &semverValue{\n\t\tvalue:      v,\n\t\tvalidators: validators,\n\t}\n}\n\ntype comparableStringer interface {\n\t~int32\n\tcomparable\n\tfmt.Stringer\n}\n\n// PflagExtended extends pflag.Value with additional methods for retrieving the value as type T and getting valid string values.\ntype PflagExtended[T any] interface {\n\tpflag.Value\n\n\tValue() T\n\tOptions() []string\n}\n\ntype protoEnumValue[T comparableStringer] struct {\n\tvalue  T\n\tvalues map[string]int32\n\tnames  map[int32]string\n}\n\n// Set implements pflag.Value interface.\nfunc (v *protoEnumValue[T]) Set(s string) error {\n\tvalue, ok := v.values[strings.ToUpper(s)]\n\tif !ok {\n\t\treturn fmt.Errorf(\"must be one of %v\", v.Options())\n\t}\n\n\tv.value = T(value)\n\n\treturn nil\n}\n\n// Type implements pflag.Value interface.\nfunc (v *protoEnumValue[T]) Type() string { return \"string\" }\n\n// String implements pflag.Value interface.\nfunc (v *protoEnumValue[T]) String() string { return strings.ToLower(v.value.String()) }\n\n// Value returns the enum value as the type T.\nfunc (v *protoEnumValue[T]) Value() T {\n\treturn v.value\n}\n\n// Options returns the valid string values for the enum.\nfunc (v *protoEnumValue[T]) Options() []string {\n\topts := xslices.Map(maps.Keys(v.values), strings.ToLower)\n\n\tslices.Sort(opts)\n\n\treturn opts\n}\n\n// ProtoEnum returns a [protoEnumValue] that validates the value is correct.\n// Only the last value will be used if multiple values are set.\nfunc ProtoEnum[T comparableStringer](defaultValue T, values map[string]int32, names map[int32]string) PflagExtended[T] {\n\treturn &protoEnumValue[T]{\n\t\tvalue:  defaultValue,\n\t\tvalues: values,\n\t\tnames:  names,\n\t}\n}\n"
  },
  {
    "path": "pkg/follow/follow.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package follow provides Reader which follows file updates and turns it into a stream.\npackage follow\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/fsnotify/fsnotify\"\n)\n\n// Reader implements io.ReadCloser over regular file following file contents.\n//\n// This makes file similar to the stream in semantics.\ntype Reader struct {\n\tsource *os.File\n\n\t//nolint:containedctx\n\tctx       context.Context\n\tctxCancel context.CancelFunc\n\n\tnotifyCh chan error\n\n\tmu            sync.Mutex\n\tclosed        bool\n\tnotifyStarted bool\n}\n\n// NewReader wraps io.File as follow.Reader.\nfunc NewReader(readCtx context.Context, source *os.File) *Reader {\n\tctx, ctxCancel := context.WithCancel(readCtx)\n\n\treturn &Reader{\n\t\tsource: source,\n\n\t\tnotifyCh: make(chan error, 1),\n\n\t\tctx:       ctx,\n\t\tctxCancel: ctxCancel,\n\t}\n}\n\n// Read implements io.Reader interface.\nfunc (r *Reader) Read(p []byte) (n int, err error) {\n\tr.mu.Lock()\n\n\tif r.closed {\n\t\terr = io.ErrClosedPipe\n\n\t\tr.mu.Unlock()\n\n\t\treturn n, err\n\t}\n\n\tif !r.notifyStarted {\n\t\tr.startNotify()\n\t}\n\n\tr.mu.Unlock()\n\n\tselect {\n\tcase <-r.ctx.Done():\n\t\terr = io.EOF\n\n\t\treturn n, err\n\tdefault:\n\t}\n\n\tfor {\n\t\tn, err = r.source.Read(p)\n\t\tif err == nil || err != io.EOF {\n\t\t\treturn n, err\n\t\t}\n\n\t\tselect {\n\t\tcase <-r.ctx.Done():\n\t\t\terr = io.EOF\n\n\t\t\treturn n, err\n\t\tcase err = <-r.notifyCh:\n\t\t\tif err != nil {\n\t\t\t\treturn n, err\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Close implements io.Closer interface.\nfunc (r *Reader) Close() error {\n\tr.mu.Lock()\n\n\tif r.closed {\n\t\tr.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\tr.closed = true\n\n\tr.mu.Unlock()\n\n\tr.ctxCancel()\n\n\treturn r.source.Close()\n}\n\nfunc (r *Reader) startNotify() {\n\tr.notifyStarted = true\n\n\tgo r.notify()\n}\n\n//nolint:gocyclo\nfunc (r *Reader) notify() {\n\twatcher, err := fsnotify.NewWatcher()\n\tif err != nil {\n\t\tselect {\n\t\tcase r.notifyCh <- fmt.Errorf(\"failed to watch: %w\", err):\n\t\tcase <-r.ctx.Done():\n\t\t}\n\n\t\treturn\n\t}\n\n\t//nolint:errcheck\n\tdefer watcher.Close()\n\n\tfilename := r.source.Name()\n\n\tif err = watcher.Add(filepath.Dir(filename)); err != nil {\n\t\tselect {\n\t\tcase r.notifyCh <- fmt.Errorf(\"failed to add dir watch: %w\", err):\n\t\tcase <-r.ctx.Done():\n\t\t}\n\n\t\treturn\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-r.ctx.Done():\n\t\t\treturn\n\t\tcase event := <-watcher.Events:\n\t\t\tif event.Name != filename {\n\t\t\t\t// ignore events for other files\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch event.Op { //nolint:exhaustive\n\t\t\tcase fsnotify.Write:\n\t\t\t\t// non-blocking send, we need to keep processing fsnotify events\n\t\t\t\t// at least signal message is in r.notifyCh which will allow Read to wake up\n\t\t\t\tselect {\n\t\t\t\tcase r.notifyCh <- nil:\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\tcase fsnotify.Remove:\n\t\t\t\tselect {\n\t\t\t\tcase r.notifyCh <- errors.New(\"file was removed while watching\"):\n\t\t\t\tcase <-r.ctx.Done():\n\t\t\t\t}\n\n\t\t\t\treturn\n\t\t\t}\n\t\tcase err := <-watcher.Errors:\n\t\t\tselect {\n\t\t\tcase r.notifyCh <- fmt.Errorf(\"failed to watch: %w\", err):\n\t\t\tcase <-r.ctx.Done():\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/follow/follow_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage follow_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/follow\"\n)\n\ntype FollowSuite struct {\n\tsuite.Suite\n\n\ttmpDir         string\n\tno             int\n\treader, writer *os.File\n\n\tr *follow.Reader\n}\n\nfunc (suite *FollowSuite) SetupSuite() {\n\tsuite.tmpDir = suite.T().TempDir()\n}\n\nfunc (suite *FollowSuite) SetupTest() {\n\tsuite.no++\n\n\tvar err error\n\n\tsuite.writer, err = os.Create(filepath.Join(suite.tmpDir, fmt.Sprintf(\"%d.log\", suite.no)))\n\tsuite.Require().NoError(err)\n\n\tsuite.reader, err = os.Open(suite.writer.Name())\n\tsuite.Require().NoError(err)\n}\n\nfunc (suite *FollowSuite) TearDownTest() {\n\tsuite.Require().NoError(suite.writer.Close())\n\n\tsuite.reader.Close() //nolint:errcheck\n}\n\n//nolint:unparam\nfunc (suite *FollowSuite) readAll(ctx context.Context, expectedError string, sizeHint int, timeout time.Duration) <-chan []byte {\n\tcombinedCh := make(chan []byte)\n\n\tctx, ctxCancel := context.WithTimeout(ctx, timeout)\n\tsuite.r = follow.NewReader(ctx, suite.reader)\n\n\tgo func() {\n\t\tdefer ctxCancel()\n\t\tdefer suite.r.Close() //nolint:errcheck\n\n\t\tcontents := make([]byte, sizeHint)\n\n\t\tn, err := io.ReadFull(suite.r, contents)\n\n\t\tif expectedError == \"\" {\n\t\t\tsuite.Assert().NoError(err)\n\t\t} else {\n\t\t\tsuite.Assert().EqualError(err, expectedError)\n\t\t}\n\n\t\tcombinedCh <- contents[:n]\n\t}()\n\n\treturn combinedCh\n}\n\nfunc (suite *FollowSuite) smallReadAll(ctx context.Context, sizeHint int, timeout time.Duration) <-chan []byte {\n\tcombinedCh := make(chan []byte)\n\n\tctx, ctxCancel := context.WithTimeout(ctx, timeout)\n\tsuite.r = follow.NewReader(ctx, suite.reader)\n\n\tgo func() {\n\t\tdefer ctxCancel()\n\t\tdefer suite.r.Close() //nolint:errcheck\n\n\t\tbuf := make([]byte, 1)\n\n\t\tvar output bytes.Buffer\n\n\t\t_, err := io.CopyBuffer(&output, io.LimitReader(suite.r, int64(sizeHint)), buf)\n\n\t\tsuite.Assert().NoError(err)\n\n\t\tcombinedCh <- output.Bytes()\n\t}()\n\n\treturn combinedCh\n}\n\nfunc (suite *FollowSuite) TestStreaming() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tcombinedCh := suite.readAll(ctx, \"\", 15, time.Second)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FollowSuite) TestStreamingClose() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tcombinedCh := suite.readAll(ctx, \"\", 15, time.Second)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\ttime.Sleep(150 * time.Millisecond)\n\n\tsuite.Require().NoError(suite.r.Close())\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FollowSuite) TestStreamingWithSomeHead() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\n\tcombinedCh := suite.readAll(ctx, \"\", 15, time.Second)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FollowSuite) TestStreamingSmallBuffer() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tcombinedCh := suite.smallReadAll(ctx, 15, time.Second)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\ttime.Sleep(50 * time.Millisecond)\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\n\t// create extra file to try to confuse watch\n\t_, err := os.Create(filepath.Join(suite.tmpDir, \"x.log\"))\n\tsuite.Require().NoError(err)\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FollowSuite) TestDeleted() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\t// pass sizeHint as 15+1 to make code read beyond the end and encounter file removed\n\tcombinedCh := suite.readAll(ctx, \"file was removed while watching\", 16, time.Second)\n\n\ttime.Sleep(150 * time.Millisecond)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"jkl\")\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"mno\")\n\ttime.Sleep(150 * time.Millisecond)\n\n\t// chunker should terminate when file is removed\n\tsuite.Require().NoError(os.Remove(suite.writer.Name()))\n\n\tsuite.Require().Equal([]byte(\"abcdefghijklmno\"), <-combinedCh)\n}\n\nfunc (suite *FollowSuite) TestReadWrite() {\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\tdefer ctxCancel()\n\n\tr := follow.NewReader(ctx, suite.reader)\n\n\tbuf := make([]byte, 256)\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"abc\")\n\n\tn, err := r.Read(buf)\n\tsuite.Require().NoError(err)\n\tsuite.Require().Equal(3, n)\n\tsuite.Require().Equal([]byte(\"abc\"), buf[:n])\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"def\")\n\n\tn, err = r.Read(buf)\n\tsuite.Require().NoError(err)\n\tsuite.Require().Equal(3, n)\n\tsuite.Require().Equal([]byte(\"def\"), buf[:n])\n\n\tch := make(chan []byte)\n\n\tgo func() {\n\t\tn, err = r.Read(buf)\n\t\tsuite.Require().NoError(err)\n\t\tsuite.Require().Equal(3, n)\n\n\t\tch <- buf[:n]\n\t}()\n\n\t// Read should block on no new data\n\tselect {\n\tcase <-ch:\n\t\tsuite.Require().Fail(\"should block on read\")\n\tcase <-time.After(50 * time.Millisecond):\n\t}\n\n\t//nolint:errcheck\n\tsuite.writer.WriteString(\"ghi\")\n\tsuite.Require().Equal([]byte(\"ghi\"), <-ch)\n}\n\nfunc TestFollowSuite(t *testing.T) {\n\tsuite.Run(t, new(FollowSuite))\n}\n"
  },
  {
    "path": "pkg/grpc/factory/factory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage factory\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime/debug\"\n\t\"strconv\"\n\n\tgrpc_recovery \"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery\"\n\t_ \"github.com/siderolabs/proto-codec/codec\" // register codec v2\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/reflection\"\n\t\"google.golang.org/grpc/status\"\n\n\tgrpclog \"github.com/siderolabs/talos/pkg/grpc/middleware/log\"\n)\n\n// Registrator describes the set of methods required in order for a concrete\n// type to be used with the Listen function.\ntype Registrator interface {\n\tRegister(*grpc.Server)\n}\n\n// Options is the functional options struct.\ntype Options struct {\n\tAddress            string\n\tPort               int\n\tSocketPath         string\n\tNetwork            string\n\tServerOptions      []grpc.ServerOption\n\tUnaryInterceptors  []grpc.UnaryServerInterceptor\n\tStreamInterceptors []grpc.StreamServerInterceptor\n\tReflection         bool\n\tlogPrefix          string\n\tlogDestination     io.Writer\n}\n\n// Option is the functional option func.\ntype Option func(*Options)\n\n// Address sets the listen address of the server.\nfunc Address(a string) Option {\n\treturn func(args *Options) {\n\t\targs.Address = a\n\t}\n}\n\n// Port sets the listen port of the server.\nfunc Port(o int) Option {\n\treturn func(args *Options) {\n\t\targs.Port = o\n\t}\n}\n\n// SocketPath sets the listen unix file socket path of the server.\nfunc SocketPath(o string) Option {\n\treturn func(args *Options) {\n\t\targs.SocketPath = o\n\t}\n}\n\n// Network sets the network type of the listener.\nfunc Network(o string) Option {\n\treturn func(args *Options) {\n\t\targs.Network = o\n\t}\n}\n\n// ServerOptions appends to the gRPC server options of the server.\nfunc ServerOptions(o ...grpc.ServerOption) Option {\n\treturn func(args *Options) {\n\t\targs.ServerOptions = append(args.ServerOptions, o...)\n\t}\n}\n\n// WithUnaryInterceptor appends to the list of gRPC server unary interceptors.\nfunc WithUnaryInterceptor(i grpc.UnaryServerInterceptor) Option {\n\treturn func(args *Options) {\n\t\targs.UnaryInterceptors = append(args.UnaryInterceptors, i)\n\t}\n}\n\n// WithStreamInterceptor appends to the list of gRPC server stream interceptors.\nfunc WithStreamInterceptor(i grpc.StreamServerInterceptor) Option {\n\treturn func(args *Options) {\n\t\targs.StreamInterceptors = append(args.StreamInterceptors, i)\n\t}\n}\n\n// WithLog sets up request logging to specified destination.\nfunc WithLog(prefix string, w io.Writer) Option {\n\treturn func(args *Options) {\n\t\targs.logPrefix = prefix\n\t\targs.logDestination = w\n\t}\n}\n\n// WithDefaultLog sets up request logging to default destination.\nfunc WithDefaultLog() Option {\n\treturn func(args *Options) {\n\t\targs.logDestination = log.Writer()\n\t}\n}\n\n// WithReflection enables gRPC reflection APIs: https://github.com/grpc/grpc/blob/master/doc/server-reflection.md\nfunc WithReflection() Option {\n\treturn func(args *Options) {\n\t\targs.Reflection = true\n\t}\n}\n\nfunc recoveryHandler(logger *log.Logger) grpc_recovery.RecoveryHandlerFunc {\n\treturn func(p any) error {\n\t\tif logger != nil {\n\t\t\tlogger.Printf(\"panic: %v\\n%s\", p, string(debug.Stack()))\n\t\t}\n\n\t\treturn status.Errorf(codes.Internal, \"%v\", p)\n\t}\n}\n\n// NewDefaultOptions initializes the Options struct with default values.\nfunc NewDefaultOptions(setters ...Option) *Options {\n\topts := &Options{\n\t\tNetwork:    \"tcp\",\n\t\tSocketPath: \"/run/factory/factory.sock\",\n\t}\n\n\tfor _, setter := range setters {\n\t\tsetter(opts)\n\t}\n\n\tvar logger *log.Logger\n\n\tif opts.logDestination != nil {\n\t\tlogger = log.New(opts.logDestination, opts.logPrefix, log.Flags())\n\t}\n\n\t// Recovery is installed as the first middleware in the chain to handle panics (via defer and recover()) in all subsequent middlewares.\n\trecoveryOpt := grpc_recovery.WithRecoveryHandler(recoveryHandler(logger))\n\topts.UnaryInterceptors = append(\n\t\t[]grpc.UnaryServerInterceptor{grpc_recovery.UnaryServerInterceptor(recoveryOpt)},\n\t\topts.UnaryInterceptors...,\n\t)\n\topts.StreamInterceptors = append(\n\t\t[]grpc.StreamServerInterceptor{grpc_recovery.StreamServerInterceptor(recoveryOpt)},\n\t\topts.StreamInterceptors...,\n\t)\n\n\tif logger != nil {\n\t\t// Logging is installed as the first middleware (even before recovery middleware) in the chain\n\t\t// so that request in the form it was received and status sent on the wire is logged (error/success).\n\t\t// It also tracks the whole duration of the request, including other middleware overhead.\n\t\tlogMiddleware := grpclog.NewMiddleware(logger)\n\t\topts.UnaryInterceptors = append(\n\t\t\t[]grpc.UnaryServerInterceptor{logMiddleware.UnaryInterceptor()},\n\t\t\topts.UnaryInterceptors...,\n\t\t)\n\t\topts.StreamInterceptors = append(\n\t\t\t[]grpc.StreamServerInterceptor{logMiddleware.StreamInterceptor()},\n\t\t\topts.StreamInterceptors...,\n\t\t)\n\t}\n\n\topts.ServerOptions = append(\n\t\topts.ServerOptions,\n\t\tgrpc.InitialWindowSize(65535*32),\n\t\tgrpc.InitialConnWindowSize(65535*16),\n\t\tgrpc.ChainUnaryInterceptor(opts.UnaryInterceptors...),\n\t\tgrpc.ChainStreamInterceptor(opts.StreamInterceptors...),\n\t\tgrpc.SharedWriteBuffer(true),\n\t)\n\n\treturn opts\n}\n\n// NewServer builds grpc server and binds it to the Registrator.\nfunc NewServer(r Registrator, setters ...Option) *grpc.Server {\n\topts := NewDefaultOptions(setters...)\n\n\tserver := grpc.NewServer(opts.ServerOptions...)\n\tr.Register(server)\n\n\tif opts.Reflection {\n\t\treflection.Register(server)\n\t}\n\n\treturn server\n}\n\n// NewListener builds listener for grpc server.\nfunc NewListener(ctx context.Context, setters ...Option) (net.Listener, error) {\n\topts := NewDefaultOptions(setters...)\n\n\tif opts.Network == \"tcp\" && opts.Port == 0 {\n\t\treturn nil, errors.New(\"a port is required for TCP listener\")\n\t}\n\n\tvar address string\n\n\tswitch opts.Network {\n\tcase \"unix\":\n\t\taddress = opts.SocketPath\n\n\t\t// Unlink the address or we will get the error:\n\t\t// bind: address already in use.\n\t\tif _, err := os.Stat(address); err == nil {\n\t\t\tif err := os.Remove(address); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\t// Make any dirs on the path to the listening socket.\n\t\tif err := os.MkdirAll(filepath.Dir(address), 0o700); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating containing directory for the file socket; %w\", err)\n\t\t}\n\tcase \"tcp\":\n\t\taddress = net.JoinHostPort(opts.Address, strconv.Itoa(opts.Port))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown network: %s\", opts.Network)\n\t}\n\n\treturn (&net.ListenConfig{}).Listen(ctx, opts.Network, address)\n}\n\n// ListenAndServe configures TLS for mutual authentication by loading the CA into a\n// CertPool and configuring the server's policy for TLS Client Authentication.\n// Once TLS is configured, the gRPC options are built to make use of the TLS\n// configuration and the receiver (Server) is registered to the gRPC server.\n// Finally the gRPC server is started.\nfunc ListenAndServe(ctx context.Context, r Registrator, setters ...Option) (err error) {\n\tserver := NewServer(r, setters...)\n\n\tlistener, err := NewListener(ctx, setters...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn server.Serve(listener)\n}\n\n// ServerGracefulStop the server with a timeout.\n//\n// Core gRPC doesn't support timeouts.\nfunc ServerGracefulStop(server *grpc.Server, shutdownCtx context.Context) { //nolint:revive\n\tstopped := make(chan struct{})\n\n\tgo func() {\n\t\tdefer close(stopped)\n\n\t\tserver.GracefulStop()\n\t}()\n\n\tselect {\n\tcase <-shutdownCtx.Done():\n\t\tserver.Stop()\n\tcase <-stopped:\n\t\tserver.Stop()\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/factory/factory_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage factory_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/grpc/gen/gen_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/grpc/gen/local.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// LocalGenerator represents the OS identity generator.\ntype LocalGenerator struct {\n\tcaKey []byte\n\tcaCrt []byte\n}\n\n// NewLocalGenerator initializes a LocalGenerator.\nfunc NewLocalGenerator(caKey, caCrt []byte) (g *LocalGenerator, err error) {\n\tg = &LocalGenerator{caKey, caCrt}\n\n\treturn g, nil\n}\n\n// Identity creates an identity certificate using a local root CA.\nfunc (g *LocalGenerator) Identity(csr *x509.CertificateSigningRequest) (ca, crt []byte, err error) {\n\tvar c *x509.Certificate\n\n\tc, err = x509.NewCertificateFromCSRBytes(g.caCrt, g.caKey, csr.X509CertificateRequestPEM)\n\tif err != nil {\n\t\treturn ca, crt, err\n\t}\n\n\tcrt = c.X509CertificatePEM\n\n\treturn g.caCrt, crt, nil\n}\n"
  },
  {
    "path": "pkg/grpc/gen/remote.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage gen\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime/pprof\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"google.golang.org/grpc\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/auth/basic\"\n\tsecurityapi \"github.com/siderolabs/talos/pkg/machinery/api/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/resolver\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar remoteGeneratorPprof = pprof.NewProfile(\"pkg/grpc/gen.RemoteGenerator\")\n\n// RemoteGenerator represents the OS identity generator.\ntype RemoteGenerator struct {\n\tconn   *grpc.ClientConn\n\tclient securityapi.SecurityServiceClient\n}\n\n// NewRemoteGenerator initializes a RemoteGenerator with a preconfigured grpc.ClientConn.\nfunc NewRemoteGenerator(token string, endpoints []string, acceptedCAs []*x509.PEMEncodedCertificate) (g *RemoteGenerator, err error) {\n\tif len(endpoints) == 0 {\n\t\treturn nil, errors.New(\"at least one root of trust endpoint is required\")\n\t}\n\n\tendpoints = resolver.EnsureEndpointsHavePorts(endpoints, constants.TrustdPort)\n\n\tg = &RemoteGenerator{}\n\n\tremoteGeneratorPprof.Add(g, 1)\n\n\tconn, err := basic.NewConnection(fmt.Sprintf(\"%s:///%s\", resolver.RoundRobinResolverScheme, strings.Join(endpoints, \",\")), basic.NewTokenCredentials(token), acceptedCAs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tg.conn = conn\n\tg.client = securityapi.NewSecurityServiceClient(g.conn)\n\n\treturn g, nil\n}\n\n// Identity creates an identity certificate via the security API.\nfunc (g *RemoteGenerator) Identity(csr *x509.CertificateSigningRequest) (ca, crt []byte, err error) {\n\treturn g.IdentityContext(context.Background(), csr)\n}\n\n// IdentityContext creates an identity certificate via the security API.\nfunc (g *RemoteGenerator) IdentityContext(ctx context.Context, csr *x509.CertificateSigningRequest) (ca, crt []byte, err error) {\n\treq := &securityapi.CertificateRequest{\n\t\tCsr: csr.X509CertificateRequestPEM,\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, time.Minute)\n\tdefer cancel()\n\n\tif err = retry.Exponential(time.Minute,\n\t\tretry.WithAttemptTimeout(10*time.Second),\n\t\tretry.WithUnits(time.Second),\n\t\tretry.WithJitter(100*time.Millisecond),\n\t).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tvar resp *securityapi.CertificateResponse\n\n\t\tresp, err = g.client.Certificate(ctx, req)\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tca = resp.Ca\n\t\tcrt = resp.Crt\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn ca, crt, nil\n}\n\n// Close closes the gRPC client connection.\nfunc (g *RemoteGenerator) Close() error {\n\tremoteGeneratorPprof.Remove(g)\n\n\treturn g.conn.Close()\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/auth/basic/basic.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage basic\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\tstdx509 \"crypto/x509\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\n\t\"github.com/siderolabs/talos/pkg/httpdefaults\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n)\n\n// Credentials describes an authorization method.\ntype Credentials interface {\n\tcredentials.PerRPCCredentials\n\n\tUnaryInterceptor() grpc.UnaryServerInterceptor\n}\n\n// NewConnection initializes a grpc.ClientConn configured for basic\n// authentication.\nfunc NewConnection(address string, creds credentials.PerRPCCredentials, acceptedCAs []*x509.PEMEncodedCertificate) (conn *grpc.ClientConn, err error) {\n\ttlsConfig := &tls.Config{}\n\n\ttlsConfig.RootCAs = stdx509.NewCertPool()\n\ttlsConfig.RootCAs.AppendCertsFromPEM(bytes.Join(\n\t\txslices.Map(\n\t\t\tacceptedCAs,\n\t\t\tfunc(cert *x509.PEMEncodedCertificate) []byte {\n\t\t\t\treturn cert.Crt\n\t\t\t},\n\t\t),\n\t\tnil,\n\t))\n\n\tgrpcOpts := []grpc.DialOption{\n\t\tgrpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),\n\t\tgrpc.WithPerRPCCredentials(creds),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t\tgrpc.WithContextDialer(dialer.DynamicProxyDialerWithTLSConfig(httpdefaults.RootCAsTLSConfig)),\n\t}\n\n\tconn, err = grpc.NewClient(address, grpcOpts...)\n\tif err != nil {\n\t\treturn conn, err\n\t}\n\n\treturn conn, nil\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/auth/basic/token.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage basic\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\n// TokenGetterFunc is the function to dynamically retrieve the token.\ntype TokenGetterFunc func(context.Context) (string, error)\n\n// TokenCredentials implements credentials.PerRPCCredentials. It uses a basic\n// token lookup to authenticate users.\ntype TokenCredentials struct {\n\ttokenGetter TokenGetterFunc\n}\n\n// NewTokenCredentials initializes ClientCredentials with the token.\nfunc NewTokenCredentials(token string) (creds Credentials) {\n\tcreds = &TokenCredentials{\n\t\ttokenGetter: func(context.Context) (string, error) {\n\t\t\treturn token, nil\n\t\t},\n\t}\n\n\treturn creds\n}\n\n// NewTokenCredentialsDynamic initializes ClientCredentials with the dynamic token token.\nfunc NewTokenCredentialsDynamic(f TokenGetterFunc) (creds Credentials) {\n\tcreds = &TokenCredentials{\n\t\ttokenGetter: f,\n\t}\n\n\treturn creds\n}\n\n// GetRequestMetadata sets the value for the \"token\" key.\nfunc (b *TokenCredentials) GetRequestMetadata(ctx context.Context, s ...string) (map[string]string, error) {\n\ttoken, err := b.tokenGetter(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn map[string]string{\n\t\t\"token\": token,\n\t}, nil\n}\n\n// RequireTransportSecurity is set to true in order to encrypt the\n// communication.\nfunc (b *TokenCredentials) RequireTransportSecurity() bool {\n\treturn true\n}\n\nfunc (b *TokenCredentials) authenticate(ctx context.Context) error {\n\ttoken, err := b.tokenGetter(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif md, ok := metadata.FromIncomingContext(ctx); ok {\n\t\tif len(md[\"token\"]) > 0 && md[\"token\"][0] == token {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"%s\", codes.Unauthenticated.String())\n}\n\n// UnaryInterceptor sets the UnaryServerInterceptor for the server and enforces\n// basic authentication.\nfunc (b *TokenCredentials) UnaryInterceptor() grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\t\tif err := b.authenticate(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn handler(ctx, req)\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/auth/basic/username_and_password.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage basic\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"time\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\n// UsernameAndPasswordCredentials implements credentials.PerRPCCredentials. It uses a basic\n// username and password lookup to authenticate users.\ntype UsernameAndPasswordCredentials struct {\n\tUsername string\n\tPassword string\n}\n\n// NewUsernameAndPasswordCredentials initializes username and password\n// Credentials.\nfunc NewUsernameAndPasswordCredentials(username, password string) (creds Credentials) {\n\tcreds = &UsernameAndPasswordCredentials{\n\t\tUsername: username,\n\t\tPassword: password,\n\t}\n\n\treturn creds\n}\n\n// GetRequestMetadata sets the value for the username and password.\nfunc (b *UsernameAndPasswordCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {\n\treturn map[string]string{\n\t\t\"username\": b.Username,\n\t\t\"password\": b.Password,\n\t}, nil\n}\n\n// RequireTransportSecurity is set to true in order to encrypt the\n// communication.\nfunc (b *UsernameAndPasswordCredentials) RequireTransportSecurity() bool {\n\treturn true\n}\n\nfunc (b *UsernameAndPasswordCredentials) authorize(ctx context.Context) error {\n\tif md, ok := metadata.FromIncomingContext(ctx); ok {\n\t\tif len(md[\"username\"]) > 0 && md[\"username\"][0] == b.Username &&\n\t\t\tlen(md[\"password\"]) > 0 && md[\"password\"][0] == b.Password {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"%s\", codes.Unauthenticated.String())\n\t}\n\n\treturn nil\n}\n\n// UnaryInterceptor sets the UnaryServerInterceptor for the server and enforces\n// basic authentication.\nfunc (b *UsernameAndPasswordCredentials) UnaryInterceptor() grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\t\tstart := time.Now()\n\n\t\tif err := b.authorize(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\th, err := handler(ctx, req)\n\n\t\tlog.Printf(\"request - Method:%s\\tDuration:%s\\tError:%v\\n\",\n\t\t\tinfo.FullMethod,\n\t\t\ttime.Since(start),\n\t\t\terr,\n\t\t)\n\n\t\treturn h, err\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/auth/basic/username_and_password_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage basic_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/authz/authorizer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage authz\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// ErrNotAuthorized should be returned to the client when they are not authorized.\nvar ErrNotAuthorized = status.Error(codes.PermissionDenied, \"not authorized\")\n\n// Authorizer checks that the user is authorized (has a valid role) to call intercepted gRPC method.\n// User roles should be set the Injector interceptor.\ntype Authorizer struct {\n\t// Maps full gRPC method names to roles. The user should have at least one of them.\n\tRules map[string]role.Set\n\n\t// Defines roles for gRPC methods not present in Rules.\n\tFallbackRoles role.Set\n\n\t// Logger.\n\tLogger func(format string, v ...any)\n}\n\nfunc (a *Authorizer) logf(format string, v ...any) {\n\tif a.Logger != nil {\n\t\ta.Logger(format, v...)\n\t}\n}\n\n// authorize returns error if the user is not authorized (doesn't have a valid role) to call the given gRPC method.\n// User roles should be previously set the Injector interceptor.\nfunc (a *Authorizer) authorize(ctx context.Context, method string) error {\n\tallowedRoles, found := a.Rules[method]\n\tif !found {\n\t\ta.logf(\"no explicit rule found for %q, falling back to %v\", method, a.FallbackRoles.Strings())\n\t\tallowedRoles = a.FallbackRoles\n\t}\n\n\tclientRoles := GetRoles(ctx)\n\tif allowedRoles.IncludesAny(clientRoles) {\n\t\ta.logf(\"authorized (%v includes %v)\", allowedRoles.Strings(), clientRoles.Strings())\n\n\t\treturn nil\n\t}\n\n\ta.logf(\"not authorized (%v doesn't include %v)\", allowedRoles.Strings(), clientRoles.Strings())\n\n\treturn ErrNotAuthorized\n}\n\n// UnaryInterceptor returns grpc UnaryServerInterceptor.\nfunc (a *Authorizer) UnaryInterceptor() grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\t\tif err := a.authorize(ctx, info.FullMethod); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn handler(ctx, req)\n\t}\n}\n\n// StreamInterceptor returns grpc StreamServerInterceptor.\nfunc (a *Authorizer) StreamInterceptor() grpc.StreamServerInterceptor {\n\treturn func(srv any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\t\tif err := a.authorize(stream.Context(), info.FullMethod); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn handler(srv, stream)\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/authz/authorizer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage authz_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/authz/context.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage authz\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// ctxKey is used to store parsed roles in the context.\n// Should be used only in this file.\ntype ctxKey struct{}\n\n// GetRoles returns roles stored in the context by the Injector interceptor.\n// May be used for additional checks in the API method handler.\nfunc GetRoles(ctx context.Context) role.Set {\n\tset, ok := getFromContext(ctx)\n\n\tif !ok {\n\t\tpanic(\"no roles in the context\")\n\t}\n\n\treturn set\n}\n\n// HasRole returns true if the context includes the given role.\nfunc HasRole(ctx context.Context, r role.Role) bool {\n\treturn GetRoles(ctx).Includes(r)\n}\n\n// getFromContext returns roles stored in the context.\nfunc getFromContext(ctx context.Context) (role.Set, bool) {\n\tset, ok := ctx.Value(ctxKey{}).(role.Set)\n\n\treturn set, ok\n}\n\n// ContextWithRoles returns derived context with roles set.\nfunc ContextWithRoles(ctx context.Context, roles role.Set) context.Context {\n\t// sanity check\n\tif ctx.Value(ctxKey{}) != nil {\n\t\tpanic(\"roles already stored in the context\")\n\t}\n\n\treturn context.WithValue(ctx, ctxKey{}, roles)\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/authz/injector.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage authz\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\n\tgrpc_middleware \"github.com/grpc-ecosystem/go-grpc-middleware/v2\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// InjectorMode specifies how roles are extracted.\ntype InjectorMode int\n\nconst (\n\t// Disabled is used when RBAC is disabled in the machine configuration. All roles are assumed.\n\tDisabled InjectorMode = iota\n\n\t// ReadOnly is used to inject only the Reader role.\n\tReadOnly\n\n\t// ReadOnlyWithAdminOnSiderolink is used to inject the Admin role if the peer is a SideroLink peer.\n\t// Otherwise, the Reader role is injected.\n\tReadOnlyWithAdminOnSiderolink\n\n\t// MetadataOnly is used internally. Checks only metadata.\n\tMetadataOnly\n\n\t// Enabled is used when RBAC is enabled in the machine configuration. Roles are extracted normally.\n\tEnabled\n)\n\nvar (\n\tadminRoleSet  = role.MakeSet(role.Admin)\n\treaderRoleSet = role.MakeSet(role.Reader)\n)\n\n// SideroLinkPeerCheckFunc checks if the peer is a SideroLink peer.\ntype SideroLinkPeerCheckFunc func(ctx context.Context) (netip.Addr, bool)\n\n// Injector sets roles to the context.\ntype Injector struct {\n\t// Mode.\n\tMode InjectorMode\n\n\t// SideroLinkPeerCheckFunc checks if the peer is a SideroLink peer.\n\t// When not specified, it defaults to isSideroLinkPeer.\n\tSideroLinkPeerCheckFunc SideroLinkPeerCheckFunc\n\n\t// Logger.\n\tLogger func(format string, v ...any)\n}\n\nfunc (i *Injector) logf(format string, v ...any) {\n\tif i.Logger != nil {\n\t\ti.Logger(format, v...)\n\t}\n}\n\n// extractRoles returns roles extracted from the user's certificate (in case of the first apid instance),\n// or from gRPC metadata (in case of subsequent apid instances, machined, or user with impersonator role).\n//\n//nolint:gocyclo\nfunc (i *Injector) extractRoles(ctx context.Context) role.Set {\n\t// sanity check\n\tif _, ok := getFromContext(ctx); ok {\n\t\tpanic(\"roles should not be present in the context at this point\")\n\t}\n\n\tswitch i.Mode {\n\tcase Disabled:\n\t\ti.logf(\"RBAC is disabled, injecting all roles\")\n\n\t\treturn role.All\n\n\tcase ReadOnly:\n\t\treturn readerRoleSet\n\n\tcase ReadOnlyWithAdminOnSiderolink:\n\t\tcheck := i.SideroLinkPeerCheckFunc\n\t\tif check == nil {\n\t\t\tcheck = isSideroLinkPeer\n\t\t}\n\n\t\tif siderolinkPeerAddr, siderolinkPeer := check(ctx); siderolinkPeer {\n\t\t\ti.logf(\"inject admin role for SideroLink peer %q\", siderolinkPeerAddr)\n\n\t\t\treturn adminRoleSet\n\t\t}\n\n\t\treturn readerRoleSet\n\n\tcase MetadataOnly:\n\t\troles, _ := getFromMetadata(ctx, i.logf)\n\n\t\treturn roles\n\n\tcase Enabled:\n\t\tp, ok := peer.FromContext(ctx)\n\t\tif !ok {\n\t\t\tpanic(\"can't get peer information\")\n\t\t}\n\n\t\ttlsInfo, ok := p.AuthInfo.(credentials.TLSInfo)\n\t\tif !ok {\n\t\t\tpanic(fmt.Sprintf(\"expected credentials.TLSInfo, got %T\", p.AuthInfo))\n\t\t}\n\n\t\tif len(tlsInfo.State.PeerCertificates) == 0 {\n\t\t\tpanic(\"expected at least one certificate\")\n\t\t}\n\n\t\t// PeerCertificates[0] is the leaf certificate the connection was verified against, so this\n\t\t// is the client cert. Other certificates in the chain might be CAs or intermediates.\n\t\tstrings := tlsInfo.State.PeerCertificates[0].Subject.Organization\n\n\t\t// TODO validate cert.KeyUsage, cert.ExtKeyUsage, cert.Issuer.Organization, other fields there?\n\n\t\troles, unknownRoles := role.Parse(strings)\n\t\ti.logf(\"parsed peer's certificate orgs %v as %v (unknownRoles = %v)\", strings, roles.Strings(), unknownRoles)\n\n\t\t// trust gRPC metadata from clients with impersonator role if present\n\t\t// (including requests proxied from other apid instances)\n\t\tif roles.Includes(role.Impersonator) {\n\t\t\tmetadataRoles, ok := getFromMetadata(ctx, i.logf)\n\t\t\tif ok {\n\t\t\t\treturn metadataRoles\n\t\t\t}\n\n\t\t\t// that's a real user with impersonator role then\n\t\t\ti.logf(\"no roles in metadadata, returning parsed roles\")\n\t\t}\n\n\t\treturn roles\n\t}\n\n\tpanic(\"unreachable\")\n}\n\n// UnaryInterceptor returns grpc UnaryServerInterceptor.\nfunc (i *Injector) UnaryInterceptor() grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\t\tctx = ContextWithRoles(ctx, i.extractRoles(ctx))\n\n\t\treturn handler(ctx, req)\n\t}\n}\n\n// StreamInterceptor returns grpc StreamServerInterceptor.\nfunc (i *Injector) StreamInterceptor() grpc.StreamServerInterceptor {\n\treturn func(srv any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\t\tctx := stream.Context()\n\t\tctx = ContextWithRoles(ctx, i.extractRoles(ctx))\n\n\t\twrapped := grpc_middleware.WrapServerStream(stream)\n\t\twrapped.WrappedContext = ctx\n\n\t\treturn handler(srv, wrapped)\n\t}\n}\n\nfunc isSideroLinkPeer(ctx context.Context) (netip.Addr, bool) {\n\taddr, ok := peerAddress(ctx)\n\tif !ok {\n\t\treturn netip.Addr{}, false\n\t}\n\n\treturn addr, network.IsULA(addr, network.ULASideroLink)\n}\n\nfunc peerAddress(ctx context.Context) (netip.Addr, bool) {\n\tremotePeer, ok := peer.FromContext(ctx)\n\tif !ok {\n\t\treturn netip.Addr{}, false\n\t}\n\n\tip, _, err := net.SplitHostPort(remotePeer.Addr.String())\n\tif err != nil {\n\t\treturn netip.Addr{}, false\n\t}\n\n\taddr, err := netip.ParseAddr(ip)\n\tif err != nil {\n\t\treturn netip.Addr{}, false\n\t}\n\n\treturn addr, true\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/authz/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage authz\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// mdKey is used to store roles in gRPC metadata.\n// Should be used only in this file.\nconst mdKey = constants.APIAuthzRoleMetadataKey\n\n// SetMetadata sets given roles in gRPC metadata.\nfunc SetMetadata(md metadata.MD, roles role.Set) {\n\tmd.Set(mdKey, roles.Strings()...)\n}\n\n// getFromMetadata returns roles extracted from gRPC metadata.\nfunc getFromMetadata(ctx context.Context, logf func(format string, v ...any)) (role.Set, bool) {\n\tmd, ok := metadata.FromIncomingContext(ctx)\n\tif !ok {\n\t\tpanic(\"no request metadata\")\n\t}\n\n\tstrings := md.Get(mdKey)\n\tif len(strings) == 0 {\n\t\tif logf != nil {\n\t\t\tlogf(\"no roles in metadata\")\n\t\t}\n\n\t\treturn role.Zero, false\n\t}\n\n\troles, unknownRoles := role.Parse(strings)\n\tif logf != nil {\n\t\tlogf(\"parsed metadata %v as %v (unknownRoles = %v)\", strings, roles.Strings(), unknownRoles)\n\t}\n\n\treturn roles, true\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/log/log.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package log provides simple grpc logging middleware\npackage log\n\nimport (\n\t\"context\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/maps\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// Middleware provides grpc logging middleware.\ntype Middleware struct {\n\tlogger Logger\n}\n\n// Logger is the interface that the Middleware expects for logging.\ntype Logger interface {\n\tPrintf(format string, v ...any)\n}\n\n// NewMiddleware creates new logging middleware.\nfunc NewMiddleware(logger Logger) *Middleware {\n\treturn &Middleware{\n\t\tlogger: logger,\n\t}\n}\n\nvar sensitiveFields = map[string]struct{}{\n\t\"token\": {},\n}\n\n// ExtractMetadata formats metadata from incoming grpc context as string for the log.\nfunc ExtractMetadata(ctx context.Context) string {\n\tmd, _ := metadata.FromIncomingContext(ctx)\n\tkeys := maps.Keys(md)\n\tslices.Sort(keys)\n\n\tpairs := make([]string, 0, len(keys))\n\n\tfor _, key := range keys {\n\t\tvalue := strings.Join(md[key], \",\")\n\n\t\tif _, sensitive := sensitiveFields[key]; sensitive {\n\t\t\tvalue = \"<hidden>\"\n\t\t}\n\n\t\tpairs = append(pairs, key+\"=\"+value)\n\t}\n\n\treturn strings.Join(pairs, \";\")\n}\n\n// UnaryInterceptor returns grpc UnaryServerInterceptor.\nfunc (m *Middleware) UnaryInterceptor() grpc.UnaryServerInterceptor {\n\treturn func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {\n\t\tstartTime := time.Now()\n\n\t\tresp, err := handler(ctx, req)\n\n\t\tduration := time.Since(startTime)\n\t\tcode := status.Code(err)\n\n\t\tmsg := \"Success\"\n\t\tif err != nil {\n\t\t\tmsg = err.Error()\n\t\t}\n\n\t\tm.logger.Printf(\"%s [%s] %s unary %s (%s)\", code, info.FullMethod, duration, msg, ExtractMetadata(ctx))\n\n\t\treturn resp, err\n\t}\n}\n\n// StreamInterceptor returns grpc StreamServerInterceptor.\nfunc (m *Middleware) StreamInterceptor() grpc.StreamServerInterceptor {\n\treturn func(srv any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {\n\t\tstartTime := time.Now()\n\n\t\terr := handler(srv, stream)\n\n\t\tduration := time.Since(startTime)\n\t\tcode := status.Code(err)\n\n\t\tmsg := \"Success\"\n\t\tif err != nil {\n\t\t\tmsg = err.Error()\n\t\t}\n\n\t\tm.logger.Printf(\"%s [%s] %s stream %s (%s)\", code, info.FullMethod, duration, msg, ExtractMetadata(stream.Context()))\n\n\t\treturn err\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/middleware/log/log_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage log_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\tmetadata \"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/log\"\n)\n\nfunc TestExtractMetadata(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tname     string\n\t\tmd       metadata.MD\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tmd:       metadata.MD{},\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"regular\",\n\t\t\tmd:       metadata.Pairs(\"foo\", \"bar\", \"one\", \"two\", \"a\", \"b\"),\n\t\t\texpected: \"a=b;foo=bar;one=two\",\n\t\t},\n\t\t{\n\t\t\tname:     \"sensitive\",\n\t\t\tmd:       metadata.Pairs(\"foo\", \"bar\", \"token\", \"secret\"),\n\t\t\texpected: \"foo=bar;token=<hidden>\",\n\t\t},\n\t} {\n\t\tctx := t.Context()\n\t\tctx = metadata.NewIncomingContext(ctx, test.md)\n\n\t\tassert.Equal(t, test.expected, log.ExtractMetadata(ctx), test.name)\n\t}\n}\n"
  },
  {
    "path": "pkg/grpc/proxy/backend/backend.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package backend implements common proxy backends satisfying proxy.Backend interface\npackage backend\n"
  },
  {
    "path": "pkg/grpc/proxy/backend/local.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/grpc-proxy/proxy\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar _ proxy.Backend = (*Local)(nil)\n\n// Local implements local backend (proxying one2one to local service).\ntype Local struct {\n\tname       string\n\tsocketPath string\n\n\tmu   sync.Mutex\n\tconn *grpc.ClientConn\n}\n\n// NewLocal builds new Local backend.\nfunc NewLocal(name, socketPath string) *Local {\n\treturn &Local{\n\t\tname:       name,\n\t\tsocketPath: socketPath,\n\t}\n}\n\nfunc (l *Local) String() string {\n\treturn l.name\n}\n\n// GetConnection returns a grpc connection to the backend.\nfunc (l *Local) GetConnection(ctx context.Context, _ string) (context.Context, *grpc.ClientConn, error) {\n\tmd, _ := metadata.FromIncomingContext(ctx)\n\tmd = md.Copy()\n\n\tauthz.SetMetadata(md, authz.GetRoles(ctx))\n\n\toutCtx := metadata.NewOutgoingContext(ctx, md)\n\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tif l.conn != nil {\n\t\treturn outCtx, l.conn, nil\n\t}\n\n\tvar err error\n\n\tl.conn, err = grpc.NewClient(\n\t\t\"unix:\"+l.socketPath,\n\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\tgrpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallRecvMsgSize(constants.GRPCMaxMessageSize),\n\t\t\tgrpc.ForceCodecV2(proxy.Codec()),\n\t\t),\n\t\tgrpc.WithSharedWriteBuffer(true),\n\t\tgrpc.WithNoProxy(),\n\t)\n\n\treturn outCtx, l.conn, err\n}\n\n// AppendInfo is called to enhance response from the backend with additional data.\nfunc (l *Local) AppendInfo(_ bool, resp []byte) ([]byte, error) {\n\treturn resp, nil\n}\n\n// BuildError is called to convert error from upstream into response field.\nfunc (l *Local) BuildError(bool, error) ([]byte, error) {\n\treturn nil, nil\n}\n\n// Close the backend connection.\nfunc (l *Local) Close() error {\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tif l.conn == nil {\n\t\treturn nil\n\t}\n\n\terr := l.conn.Close()\n\tl.conn = nil\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/grpc/proxy/backend/local_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage backend_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"google.golang.org/grpc/metadata\"\n\n\t\"github.com/siderolabs/talos/pkg/grpc/middleware/authz\"\n\t\"github.com/siderolabs/talos/pkg/grpc/proxy/backend\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nfunc TestLocalGetConnection(t *testing.T) {\n\tt.Parallel()\n\n\tl := backend.NewLocal(\"test\", \"/tmp/test.sock\")\n\n\tmd1 := metadata.New(nil)\n\tmd1.Set(\"key\", \"value1\", \"value2\")\n\tctx1 := metadata.NewIncomingContext(authz.ContextWithRoles(t.Context(), role.MakeSet(role.Admin)), md1)\n\n\toutCtx1, conn1, err1 := l.GetConnection(ctx1, \"\")\n\tassert.NoError(t, err1)\n\tassert.NotNil(t, conn1)\n\tassert.Equal(t, role.MakeSet(role.Admin), authz.GetRoles(outCtx1))\n\n\tmdOut1, ok1 := metadata.FromOutgoingContext(outCtx1)\n\tassert.True(t, ok1)\n\tassert.Equal(t, []string{\"value1\", \"value2\"}, mdOut1.Get(\"key\"))\n\tassert.Equal(t, []string{\"os:admin\"}, mdOut1.Get(\"talos-role\"))\n\n\tt.Run(\"Same context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx2 := ctx1\n\t\toutCtx2, conn2, err2 := l.GetConnection(ctx2, \"\")\n\t\tassert.NoError(t, err2)\n\t\tassert.Equal(t, conn1, conn2) // connection is cached\n\t\tassert.Equal(t, role.MakeSet(role.Admin), authz.GetRoles(outCtx2))\n\n\t\tmdOut2, ok2 := metadata.FromOutgoingContext(outCtx2)\n\t\tassert.True(t, ok2)\n\t\tassert.Equal(t, []string{\"value1\", \"value2\"}, mdOut2.Get(\"key\"))\n\t\tassert.Equal(t, []string{\"os:admin\"}, mdOut2.Get(\"talos-role\"))\n\t})\n\n\tt.Run(\"Other context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tmd3 := metadata.New(nil)\n\t\tmd3.Set(\"key\", \"value3\", \"value4\")\n\t\tctx3 := metadata.NewIncomingContext(authz.ContextWithRoles(t.Context(), role.MakeSet(role.Reader)), md3)\n\n\t\toutCtx3, conn3, err3 := l.GetConnection(ctx3, \"\")\n\t\tassert.NoError(t, err3)\n\t\tassert.Equal(t, conn1, conn3) // connection is cached\n\t\tassert.Equal(t, role.MakeSet(role.Reader), authz.GetRoles(outCtx3))\n\n\t\tmdOut3, ok3 := metadata.FromOutgoingContext(outCtx3)\n\t\tassert.True(t, ok3)\n\t\tassert.Equal(t, []string{\"value3\", \"value4\"}, mdOut3.Get(\"key\"))\n\t\tassert.Equal(t, []string{\"os:reader\"}, mdOut3.Get(\"talos-role\"))\n\t})\n}\n"
  },
  {
    "path": "pkg/httpdefaults/httpdefaults.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package httpdefaults provides default HTTP client settings for Talos.\npackage httpdefaults\n\nimport (\n\t\"crypto/tls\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/http/httpproxy\"\n)\n\n// PatchTransport updates *http.Transport with Talos-specific settings.\n//\n// Settings applied here only make sense when running in Talos root filesystem.\nfunc PatchTransport(transport *http.Transport) *http.Transport {\n\t// Explicitly set the Proxy function to work around proxy.Do\n\t// once: the environment variables will be reread/initialized each time the\n\t// http call is made.\n\ttransport.Proxy = func(req *http.Request) (*url.URL, error) {\n\t\treturn httpproxy.FromEnvironment().ProxyFunc()(req.URL)\n\t}\n\n\t// Override the TLS config to allow refreshing CA list which might be updated\n\t// via the machine config on the fly.\n\ttransport.TLSClientConfig = &tls.Config{\n\t\tRootCAs: RootCAs(),\n\t}\n\n\treturn transport\n}\n"
  },
  {
    "path": "pkg/httpdefaults/tls.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage httpdefaults\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"io/fs\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar (\n\tcachedPool *x509.CertPool\n\tcachedSt   fs.FileInfo\n\tcacheMu    sync.Mutex\n)\n\n// RootCAs provides a cached, but refreshed, list of root CAs.\n//\n// If loading certificates fails for any reason, function returns nil.\nfunc RootCAs() *x509.CertPool {\n\tst, err := os.Stat(constants.DefaultTrustedCAFile)\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\t// check if the file hasn't changed\n\tcacheMu.Lock()\n\tdefer cacheMu.Unlock()\n\n\tif cachedPool != nil && cachedSt != nil {\n\t\tif cachedSt.ModTime().Equal(st.ModTime()) && cachedSt.Size() == st.Size() {\n\t\t\treturn cachedPool\n\t\t}\n\t}\n\n\tpool := x509.NewCertPool()\n\n\tcontents, err := os.ReadFile(constants.DefaultTrustedCAFile)\n\tif err == nil {\n\t\tif pool.AppendCertsFromPEM(contents) {\n\t\t\tcachedPool = pool\n\t\t\tcachedSt = st\n\t\t}\n\t}\n\n\tif cachedPool == nil {\n\t\treturn nil\n\t}\n\n\treturn cachedPool.Clone()\n}\n\n// RootCAsTLSConfig provides a TLS configuration with the root CAs.\nfunc RootCAsTLSConfig() *tls.Config {\n\treturn &tls.Config{\n\t\tRootCAs: RootCAs(),\n\t}\n}\n"
  },
  {
    "path": "pkg/httpdefaults/useragent.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage httpdefaults\n\nimport \"github.com/siderolabs/talos/pkg/machinery/version\"\n\n// UserAgent is the default User-Agent header value for HTTP requests made by Talos.\nfunc UserAgent() string {\n\treturn version.Name + \"/\" + version.Tag\n}\n"
  },
  {
    "path": "pkg/imager/cache/cache.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cache provides facilities for generating a cache tarball from images.\npackage cache\n\nimport (\n\t\"cmp\"\n\t\"crypto/sha256\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/google/go-containerregistry/pkg/authn\"\n\t\"github.com/google/go-containerregistry/pkg/authn/github\"\n\t\"github.com/google/go-containerregistry/pkg/crane\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/cache\"\n\t\"github.com/google/go-containerregistry/pkg/v1/empty\"\n\t\"github.com/google/go-containerregistry/pkg/v1/google\"\n\t\"github.com/google/go-containerregistry/pkg/v1/layout\"\n\t\"github.com/google/go-containerregistry/pkg/v1/mutate\"\n\t\"github.com/google/go-containerregistry/pkg/v1/remote\"\n\t\"github.com/google/go-containerregistry/pkg/v1/remote/transport\"\n\t\"github.com/google/go-containerregistry/pkg/v1/types\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/filemap\"\n)\n\nconst (\n\tblobsDir     = \"blob\"\n\tmanifestsDir = \"manifests\"\n)\n\n// rewriteRegistry name back to workaround https://github.com/google/go-containerregistry/pull/69.\nfunc rewriteRegistry(registryName, origRef string) string {\n\tif registryName == name.DefaultRegistry && !strings.HasPrefix(origRef, name.DefaultRegistry+\"/\") {\n\t\treturn \"docker.io\"\n\t}\n\n\t// convert :port to _port_ to support copying image-cache to vfat filesystems\n\tidx := strings.LastIndex(registryName, \":\")\n\tif idx > 0 {\n\t\treturn registryName[:idx] + \"_\" + registryName[idx+1:] + \"_\"\n\t}\n\n\treturn registryName\n}\n\n// Generate generates a cache tarball from the given images.\n//\n//nolint:gocyclo,cyclop\nfunc Generate(images []string, platforms []string, insecure bool, imageLayerCachePath, dest string, flat bool, withCosignSignatures bool) error {\n\ttmpDir, err := os.MkdirTemp(\"\", \"talos-image-cache-gen\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating temporary directory: %w\", err)\n\t}\n\n\tif imageLayerCachePath != \"\" {\n\t\tif err := os.MkdirAll(imageLayerCachePath, 0o755); err != nil {\n\t\t\treturn fmt.Errorf(\"creating image layer cache directory: %w\", err)\n\t\t}\n\t}\n\n\tremoveAll := sync.OnceValue(func() error { return os.RemoveAll(tmpDir) })\n\tdefer removeAll() //nolint:errcheck\n\n\tif len(platforms) < 1 {\n\t\treturn fmt.Errorf(\"must specify at least one platform\")\n\t}\n\n\tfor _, platform := range platforms {\n\t\tv1Platform, err := v1.ParsePlatform(platform)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing platform: %w\", err)\n\t\t}\n\n\t\tif err := os.MkdirAll(filepath.Join(tmpDir, blobsDir), 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar nameOptions []name.Option\n\n\t\tkeychain := authn.NewMultiKeychain(\n\t\t\tauthn.DefaultKeychain,\n\t\t\tgithub.Keychain,\n\t\t\tgoogle.Keychain,\n\t\t)\n\n\t\tcraneOpts := []crane.Option{\n\t\t\tcrane.WithAuthFromKeychain(keychain),\n\t\t}\n\n\t\tremoteOpts := []remote.Option{\n\t\t\tremote.WithAuthFromKeychain(keychain),\n\t\t\tremote.WithPlatform(*v1Platform),\n\t\t}\n\n\t\t// sigRemoteOpts is used for fetching cosign signatures - no platform resolution\n\t\t// since signatures are platform-independent and may be stored as OCI image indexes.\n\t\tsigRemoteOpts := []remote.Option{\n\t\t\tremote.WithAuthFromKeychain(keychain),\n\t\t}\n\n\t\tif insecure {\n\t\t\tcraneOpts = append(craneOpts, crane.Insecure)\n\t\t\tnameOptions = append(nameOptions, name.Insecure)\n\t\t}\n\n\t\tfor _, src := range images {\n\t\t\tr := retry.Exponential(\n\t\t\t\t30*time.Minute,\n\t\t\t\tretry.WithUnits(time.Second),\n\t\t\t\tretry.WithJitter(time.Second),\n\t\t\t\tretry.WithErrorLogging(true),\n\t\t\t)\n\n\t\t\terr := r.Retry(func() error {\n\t\t\t\tif err := processImage(src, tmpDir, imageLayerCachePath, nameOptions, craneOpts, remoteOpts, sigRemoteOpts, withCosignSignatures); err != nil {\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase errors.Is(err, new(name.ErrBadName)):\n\t\t\t\t\t\treturn err\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to prcess image: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif flat {\n\t\treturn move(tmpDir, dest)\n\t}\n\n\tnewImg := mutate.MediaType(empty.Image, types.OCIManifestSchema1)\n\tnewImg = mutate.ConfigMediaType(newImg, types.OCIConfigJSON)\n\n\tnewImg, err = mutate.CreatedAt(newImg, v1.Time{Time: time.Now()})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"setting created at: %w\", err)\n\t}\n\n\tartifacts, err := filemap.Walk(tmpDir, \"\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"walking filesystem: %w\", err)\n\t}\n\n\tartifactsLayer, err := filemap.Layer(artifacts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating artifacts layer: %w\", err)\n\t}\n\n\tnewImg, err = mutate.AppendLayers(newImg, artifactsLayer)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"appending artifacts layer: %w\", err)\n\t}\n\n\t// we can always write an empty index, since dest is always a new empty directory\n\tociLayout, err := layout.Write(dest, empty.Index)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating layout: %w\", err)\n\t}\n\n\timagePlatform, err := v1.ParsePlatform(platforms[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing platform: %w\", err)\n\t}\n\n\tif err := ociLayout.AppendImage(newImg, layout.WithPlatform(*imagePlatform)); err != nil {\n\t\treturn fmt.Errorf(\"appending image: %w\", err)\n\t}\n\n\treturn removeAll()\n}\n\nfunc move(src, dest string) error {\n\tif err := os.Rename(src, dest); err == nil {\n\t\treturn nil\n\t} else if !errors.Is(err, syscall.EXDEV) {\n\t\t// not a cross-device error - return it\n\t\treturn err\n\t}\n\n\t// cross-device: must copy+remove\n\tinfo, err := os.Stat(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif info.IsDir() {\n\t\tif err := copyDir(src, dest); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tif err := copyFile(src, dest, info.Mode()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn os.RemoveAll(src)\n}\n\nfunc copyFile(src, dest string, perm fs.FileMode) error {\n\tin, err := os.Open(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer in.Close() //nolint:errcheck\n\n\t// Ensure destination directory exists\n\tif err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tout, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer out.Close() //nolint:errcheck\n\n\tif _, err = io.Copy(out, in); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc copyDir(src, dest string) error {\n\treturn filepath.Walk(src, func(path string, info fs.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trel, err := filepath.Rel(src, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttarget := filepath.Join(dest, rel)\n\n\t\tif info.IsDir() {\n\t\t\treturn os.MkdirAll(target, info.Mode())\n\t\t}\n\n\t\treturn copyFile(path, target, info.Mode())\n\t})\n}\n\n//nolint:gocyclo,cyclop\nfunc processImage(\n\tsrc, tmpDir, imageLayerCachePath string,\n\tnameOptions []name.Option,\n\tcraneOpts []crane.Option,\n\tremoteOpts []remote.Option,\n\tsigRemoteOpts []remote.Option,\n\twithCosignSignatures bool,\n) error {\n\tfmt.Fprintf(os.Stderr, \"fetching image %q\\n\", src)\n\n\tref, err := name.ParseReference(src, nameOptions...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing reference %q: %w\", src, err)\n\t}\n\n\treferenceDir := filepath.Join(tmpDir, manifestsDir, rewriteRegistry(ref.Context().RegistryStr(), src), filepath.FromSlash(ref.Context().RepositoryStr()), \"reference\")\n\tdigestDir := filepath.Join(tmpDir, manifestsDir, rewriteRegistry(ref.Context().RegistryStr(), src), filepath.FromSlash(ref.Context().RepositoryStr()), \"digest\")\n\n\t// if the reference was parsed as a tag, use it\n\ttag, ok := ref.(name.Tag)\n\n\tif !ok {\n\t\tif base, _, ok := strings.Cut(src, \"@\"); ok {\n\t\t\t// if the reference was a digest, but contained a tag, re-parse it\n\t\t\ttag, _ = name.NewTag(base, nameOptions...) //nolint:errcheck\n\t\t}\n\t}\n\n\tif err = os.MkdirAll(referenceDir, 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.MkdirAll(digestDir, 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tmanifest, err := crane.Manifest(\n\t\tref.String(),\n\t\tcraneOpts...,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetching manifest %q: %w\", ref.String(), err)\n\t}\n\n\trmt, err := remote.Get(\n\t\tref,\n\t\tremoteOpts...,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetching image %q: %w\", ref.String(), err)\n\t}\n\n\tif tag.TagStr() != \"\" {\n\t\tif err := os.WriteFile(filepath.Join(referenceDir, tag.TagStr()), manifest, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := os.WriteFile(filepath.Join(digestDir, strings.ReplaceAll(rmt.Digest.String(), \"sha256:\", \"sha256-\")), manifest, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tif withCosignSignatures {\n\t\tif err := processCosignSignature(src, rmt.Digest, tmpDir, nameOptions, craneOpts, sigRemoteOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\timg, err := rmt.Image()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"converting image to index: %w\", err)\n\t}\n\n\tif imageLayerCachePath != \"\" {\n\t\timg = cache.Image(img, cache.NewFilesystemCache(imageLayerCachePath))\n\t}\n\n\tlayers, err := img.Layers()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting image layers: %w\", err)\n\t}\n\n\tconfig, err := img.RawConfigFile()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting image config: %w\", err)\n\t}\n\n\tplatformManifest, err := img.RawManifest()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting image platform manifest: %w\", err)\n\t}\n\n\th := sha256.New()\n\tif _, err := h.Write(platformManifest); err != nil {\n\t\treturn fmt.Errorf(\"platform manifest hash: %w\", err)\n\t}\n\n\tif err := os.WriteFile(filepath.Join(digestDir, fmt.Sprintf(\"sha256-%x\", h.Sum(nil))), platformManifest, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tconfigHash, err := img.ConfigName()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting image config hash: %w\", err)\n\t}\n\n\tif err := os.WriteFile(filepath.Join(tmpDir, blobsDir, strings.ReplaceAll(configHash.String(), \"sha256:\", \"sha256-\")), config, 0o644); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, layer := range layers {\n\t\tif err = processLayer(layer, tmpDir); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo,cyclop\nfunc processCosignSignature(\n\tsrc string,\n\tdigest v1.Hash,\n\ttmpDir string,\n\tnameOptions []name.Option,\n\tcraneOpts []crane.Option,\n\tremoteOpts []remote.Option,\n) error {\n\tref, err := name.ParseReference(src, nameOptions...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing reference for cosign %q: %w\", src, err)\n\t}\n\n\tbaseTag := strings.ReplaceAll(digest.String(), \"sha256:\", \"sha256-\")\n\n\tfor _, sigTagStr := range []string{baseTag + \".sig\", baseTag} {\n\t\tsigRef, err := name.NewTag(ref.Context().String()+\":\"+sigTagStr, nameOptions...)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"fetching cosign signature %q\\n\", sigRef.String())\n\n\t\tsigManifest, err := crane.Manifest(sigRef.String(), craneOpts...)\n\t\tif err != nil {\n\t\t\tvar transportErr *transport.Error\n\t\t\tif errors.As(err, &transportErr) && transportErr.StatusCode == http.StatusNotFound {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"fetching cosign manifest %q: %w\", sigRef.String(), err)\n\t\t}\n\n\t\tsigRmt, err := remote.Get(sigRef, remoteOpts...)\n\t\tif err != nil {\n\t\t\tvar transportErr *transport.Error\n\t\t\tif errors.As(err, &transportErr) && transportErr.StatusCode == http.StatusNotFound {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"fetching cosign image %q: %w\", sigRef.String(), err)\n\t\t}\n\n\t\treferenceDir := filepath.Join(tmpDir, manifestsDir, rewriteRegistry(sigRef.Context().RegistryStr(), src), filepath.FromSlash(sigRef.Context().RepositoryStr()), \"reference\")\n\t\tdigestDir := filepath.Join(tmpDir, manifestsDir, rewriteRegistry(sigRef.Context().RegistryStr(), src), filepath.FromSlash(sigRef.Context().RepositoryStr()), \"digest\")\n\n\t\tif err = os.MkdirAll(referenceDir, 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = os.MkdirAll(digestDir, 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(filepath.Join(referenceDir, sigTagStr), sigManifest, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(filepath.Join(digestDir, strings.ReplaceAll(sigRmt.Digest.String(), \"sha256:\", \"sha256-\")), sigManifest, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch sigRmt.MediaType { //nolint:exhaustive\n\t\tcase types.OCIImageIndex, types.DockerManifestList:\n\t\t\t// Signature is an OCI image index - process each child manifest.\n\t\t\tidx, err := sigRmt.ImageIndex()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign image index: %w\", err)\n\t\t\t}\n\n\t\t\tidxManifest, err := idx.IndexManifest()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign index manifest: %w\", err)\n\t\t\t}\n\n\t\t\tfor _, descriptor := range idxManifest.Manifests {\n\t\t\t\tchildImg, err := idx.Image(descriptor.Digest)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child image %s: %w\", descriptor.Digest, err)\n\t\t\t\t}\n\n\t\t\t\tchildManifest, err := childImg.RawManifest()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child manifest: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tchildDigest, err := childImg.Digest()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child digest: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err := os.WriteFile(filepath.Join(digestDir, strings.ReplaceAll(childDigest.String(), \"sha256:\", \"sha256-\")), childManifest, 0o644); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tconfig, err := childImg.RawConfigFile()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child config: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tconfigHash, err := childImg.ConfigName()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child config hash: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err := os.WriteFile(filepath.Join(tmpDir, blobsDir, strings.ReplaceAll(configHash.String(), \"sha256:\", \"sha256-\")), config, 0o644); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tlayers, err := childImg.Layers()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"getting cosign child layers: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tfor _, layer := range layers {\n\t\t\t\t\tif err = processLayer(layer, tmpDir); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\t// Signature is a single image manifest.\n\t\t\timg, err := sigRmt.Image()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign image: %w\", err)\n\t\t\t}\n\n\t\t\tconfig, err := img.RawConfigFile()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign config: %w\", err)\n\t\t\t}\n\n\t\t\tconfigHash, err := img.ConfigName()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign config hash: %w\", err)\n\t\t\t}\n\n\t\t\tif err := os.WriteFile(filepath.Join(tmpDir, blobsDir, strings.ReplaceAll(configHash.String(), \"sha256:\", \"sha256-\")), config, 0o644); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tlayers, err := img.Layers()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"getting cosign layers: %w\", err)\n\t\t\t}\n\n\t\t\tfor _, layer := range layers {\n\t\t\t\tif err = processLayer(layer, tmpDir); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\treturn nil\n}\n\nfunc processLayer(layer v1.Layer, dstDir string) error {\n\tdigest, err := layer.Digest()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting layer digest: %w\", err)\n\t}\n\n\tblobPath := filepath.Join(dstDir, blobsDir, strings.ReplaceAll(digest.String(), \"sha256:\", \"sha256-\"))\n\n\tif _, err := os.Stat(blobPath); err == nil {\n\t\t// we already have this blob, skip it\n\t\treturn nil\n\t}\n\n\tsize, err := layer.Size()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting layer size: %w\", err)\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"> layer %q (size %s)...\\n\", digest, humanize.Bytes(uint64(size)))\n\n\treader, err := layer.Compressed()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"getting layer reader: %w\", err)\n\t}\n\n\trdrCloser := sync.OnceValue(reader.Close)\n\tdefer rdrCloser() //nolint:errcheck\n\n\tfile, err := os.Create(blobPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfileCloser := sync.OnceValue(file.Close)\n\tdefer fileCloser() //nolint:errcheck\n\n\tif _, err := io.Copy(file, reader); err != nil {\n\t\treturn err\n\t}\n\n\treturn cmp.Or(rdrCloser(), fileCloser())\n}\n"
  },
  {
    "path": "pkg/imager/embed.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n)\n\nfunc (i *Imager) handleEmbeddedConfig() error {\n\tif len(i.prof.Customization.EmbeddedMachineConfiguration) == 0 {\n\t\treturn nil\n\t}\n\n\tcontents, err := BuildEmbeddedConfigExtension([]byte(i.prof.Customization.EmbeddedMachineConfiguration))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build embedded config extension: %w\", err)\n\t}\n\n\ttmpPath := filepath.Join(i.tempDir, \"embedded-config.tar\")\n\n\tf, err := os.Create(tmpPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create temporary file: %w\", err)\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tif _, err := io.Copy(f, contents); err != nil {\n\t\treturn fmt.Errorf(\"failed to write embedded config to temporary file: %w\", err)\n\t}\n\n\ti.prof.Input.SystemExtensions = append(i.prof.Input.SystemExtensions,\n\t\tprofile.ContainerAsset{\n\t\t\tTarballPath: tmpPath,\n\t\t},\n\t)\n\n\treturn nil\n}\n\n// BuildEmbeddedConfigExtension builds a tarball containing the embedded machine configuration as a virtual extension.\nfunc BuildEmbeddedConfigExtension(machineConfig []byte) (io.Reader, error) {\n\tsha256sum := sha256.Sum256(machineConfig)\n\textensionVersion := hex.EncodeToString(sha256sum[:])\n\n\tmanifest := extensions.Manifest{\n\t\tVersion: \"v1alpha1\",\n\t\tMetadata: extensions.Metadata{\n\t\t\tName:        \"embedded-config\",\n\t\t\tVersion:     extensionVersion,\n\t\t\tAuthor:      \"Imager\",\n\t\t\tDescription: \"Virtual extension which embeds the machine configuration.\",\n\t\t\tCompatibility: extensions.Compatibility{\n\t\t\t\tTalos: extensions.Constraint{\n\t\t\t\t\tVersion: \">= 1.0.0\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmanifestBytes, err := yaml.Marshal(manifest)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal manifest: %w\", err)\n\t}\n\n\tvar buf bytes.Buffer\n\n\ttw := tar.NewWriter(&buf)\n\n\tif err = tw.WriteHeader(&tar.Header{\n\t\tName:     \"manifest.yaml\",\n\t\tTypeflag: tar.TypeReg,\n\t\tMode:     0o644,\n\t\tSize:     int64(len(manifestBytes)),\n\t}); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write manifest header: %w\", err)\n\t}\n\n\tif _, err = tw.Write(manifestBytes); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write manifest: %w\", err)\n\t}\n\n\tpath := strings.Split(strings.TrimRight(constants.EmbeddedConfigDirectory, \"/\"), \"/\")\n\n\tfor i := range path {\n\t\tdir := filepath.Join(\"rootfs\", strings.Join(path[:i+1], \"/\"))\n\n\t\tif err = tw.WriteHeader(&tar.Header{\n\t\t\tName:     dir,\n\t\t\tTypeflag: tar.TypeDir,\n\t\t\tMode:     0o755,\n\t\t}); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to write rootfs header: %w\", err)\n\t\t}\n\t}\n\n\tif err = tw.WriteHeader(&tar.Header{\n\t\tName:     filepath.Join(\"rootfs\", constants.EmbeddedConfigDirectory, constants.ConfigFilename),\n\t\tTypeflag: tar.TypeReg,\n\t\tMode:     0o000,\n\t\tSize:     int64(len(machineConfig)),\n\t\tPAXRecords: map[string]string{\n\t\t\t\"SCHILY.xattr.security.selinux\": constants.StateSelinuxLabel,\n\t\t},\n\t}); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write embedded header: %w\", err)\n\t}\n\n\tif _, err = tw.Write(machineConfig); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write embedded config: %w\", err)\n\t}\n\n\tif err = tw.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to close tar writer: %w\", err)\n\t}\n\n\treturn &buf, nil\n}\n"
  },
  {
    "path": "pkg/imager/embed_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager_test\n\nimport (\n\t\"archive/tar\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager\"\n)\n\nfunc TestBuildEmbeddedConfigExtension(t *testing.T) {\n\tt.Parallel()\n\n\tout, err := imager.BuildEmbeddedConfigExtension([]byte(\"test\"))\n\trequire.NoError(t, err)\n\n\ttr := tar.NewReader(out)\n\n\tvar paths []string\n\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\trequire.NoError(t, err)\n\n\t\tpaths = append(paths, hdr.Name)\n\t}\n\n\tassert.Equal(t, []string{\n\t\t\"manifest.yaml\",\n\t\t\"rootfs\",\n\t\t\"rootfs/usr\",\n\t\t\"rootfs/usr/local\",\n\t\t\"rootfs/usr/local/etc\",\n\t\t\"rootfs/usr/local/etc/talos\",\n\t\t\"rootfs/usr/local/etc/talos/config.yaml\",\n\t}, paths)\n}\n"
  },
  {
    "path": "pkg/imager/extensions/contents.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nfunc findExtensionsWithKernelModules(extensions []*extensions.Extension, quirks quirks.Quirks) []string {\n\tvar modulesPath []string\n\n\tfor _, ext := range extensions {\n\t\tif ext.ProvidesKernelModules(quirks) {\n\t\t\tmodulesPath = append(modulesPath, ext.KernelModuleDirectory(quirks))\n\t\t}\n\t}\n\n\treturn modulesPath\n}\n\n// buildInitramfsContents builds a list of files to be included into initramfs directly, bypassing extensions squashfs.\n//\n// Two listings are returned:\n// - uncompressedListing is a list of files that should be included into initramfs uncompressed prepended as a first section\n// - compressedListing is a list of files that should be included into initramfs compressed.\nfunc buildInitramfsContents(path string) (compressedListing, uncompressedListing []byte, err error) {\n\tvar compressedBuffer, uncompressedBuffer bytes.Buffer\n\n\tif err := buildInitramfsContentsRecursive(path, \"\", &compressedBuffer, &uncompressedBuffer); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn compressedBuffer.Bytes(), uncompressedBuffer.Bytes(), nil\n}\n\nfunc buildInitramfsContentsRecursive(basePath, path string, compressedW, uncompressedW io.Writer) error {\n\tif path != \"\" {\n\t\tif path == \"kernel\" || strings.HasPrefix(path, \"kernel/\") {\n\t\t\tfmt.Fprintf(uncompressedW, \"%s\\n\", path)\n\t\t} else {\n\t\t\tfmt.Fprintf(compressedW, \"%s\\n\", path)\n\t\t}\n\t}\n\n\tst, err := os.Stat(filepath.Join(basePath, path))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !st.IsDir() {\n\t\treturn nil\n\t}\n\n\tcontents, err := os.ReadDir(filepath.Join(basePath, path))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, item := range contents {\n\t\tif err = buildInitramfsContentsRecursive(basePath, filepath.Join(path, item.Name()), compressedW, uncompressedW); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/extensions/extensions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package extensions provides facilities for building initramfs.xz with extensions.\npackage extensions\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\textinterface \"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Builder rebuilds initramfs.xz with extensions.\ntype Builder struct {\n\t// The initramfs will be rebuilt in-place.\n\tInitramfsPath string\n\t// Architecture of the initramfs.\n\tArch string\n\t// ExtensionTreePath is a path to the extracted extension tree.\n\tExtensionTreePath string\n\t// ExtensionValidateContents enables validation of the extension contents.\n\tExtensionValidateContents bool\n\t// Printf is used for logging.\n\tPrintf func(format string, v ...any)\n\t// Quirks for the Talos version being used.\n\tQuirks quirks.Quirks\n}\n\n// Build rebuilds the initramfs.xz with extensions.\n//\n//nolint:gocyclo\nfunc (builder *Builder) Build(ctx context.Context) error {\n\textensionsList, err := extensions.List(builder.ExtensionTreePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error listing extensions: %w\", err)\n\t}\n\n\tif len(extensionsList) == 0 {\n\t\treturn nil\n\t}\n\n\tif err = builder.printExtensions(extensionsList); err != nil {\n\t\treturn err\n\t}\n\n\tif err = builder.validateExtensions(extensionsList); err != nil {\n\t\treturn err\n\t}\n\n\textensionPathsWithKernelModules := findExtensionsWithKernelModules(extensionsList, builder.Quirks)\n\n\tif len(extensionPathsWithKernelModules) > 0 {\n\t\tvar scratchPath string\n\n\t\t// create a temporary directory to store 'modules.dep' extension\n\t\tscratchPath, err = os.MkdirTemp(\"\", \"ext-modules\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer os.RemoveAll(scratchPath) //nolint:errcheck\n\n\t\tkernelModuleDepExtension, genErr := extensions.GenerateKernelModuleDependencyTreeExtension(ctx, extensionPathsWithKernelModules, builder.InitramfsPath, scratchPath, builder.Quirks, builder.Printf)\n\t\tif genErr != nil {\n\t\t\treturn genErr\n\t\t}\n\n\t\textensionsList = append(extensionsList, kernelModuleDepExtension)\n\t}\n\n\ttempDir, err := os.MkdirTemp(\"\", \"ext\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer os.RemoveAll(tempDir) //nolint:errcheck\n\n\tvar cfg *extinterface.Config\n\n\tif cfg, err = builder.compressExtensions(ctx, extensionsList, tempDir); err != nil {\n\t\treturn err\n\t}\n\n\tif err = cfg.Write(filepath.Join(tempDir, constants.ExtensionsConfigFile)); err != nil {\n\t\treturn err\n\t}\n\n\treturn builder.rebuildInitramfs(ctx, tempDir, builder.Quirks)\n}\n\nfunc (builder *Builder) validateExtensions(extensions []*extensions.Extension) error {\n\tbuilder.Printf(\"validating system extensions\")\n\n\topts := []extinterface.ValidationOption{\n\t\textinterface.WithValidateConstraints(),\n\t\textinterface.WithTalosVersion(builder.Quirks.Version()),\n\t}\n\n\tif builder.ExtensionValidateContents {\n\t\topts = append(opts, extinterface.WithValidateContents())\n\t}\n\n\tfor _, ext := range extensions {\n\t\tif err := ext.Validate(opts...); err != nil {\n\t\t\treturn fmt.Errorf(\"error validating extension %q: %w\", ext.Manifest.Metadata.Name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (builder *Builder) compressExtensions(ctx context.Context, extensions []*extensions.Extension, tempDir string) (*extinterface.Config, error) {\n\tcfg := &extinterface.Config{}\n\n\tbuilder.Printf(\"compressing system extensions\")\n\n\tfor _, ext := range extensions {\n\t\tpath, err := ext.Compress(ctx, tempDir, tempDir, builder.Quirks)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error compressing extension %q: %w\", ext.Manifest.Metadata.Name, err)\n\t\t}\n\n\t\tcfg.Layers = append(cfg.Layers, &extinterface.Layer{\n\t\t\tImage:    filepath.Base(path),\n\t\t\tMetadata: ext.Manifest.Metadata,\n\t\t})\n\t}\n\n\treturn cfg, nil\n}\n"
  },
  {
    "path": "pkg/imager/extensions/printer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"text/tabwriter\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/extensions\"\n)\n\nfunc (builder *Builder) printExtensions(extensions []*extensions.Extension) error {\n\tbuilder.Printf(\"discovered system extensions:\")\n\n\tvar b bytes.Buffer\n\n\tw := tabwriter.NewWriter(&b, 0, 0, 3, ' ', 0)\n\n\tfmt.Fprint(w, \"NAME\\tVERSION\\tAUTHOR\\n\")\n\n\tfor _, ext := range extensions {\n\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\n\", ext.Manifest.Metadata.Name, ext.Manifest.Metadata.Version, ext.Manifest.Metadata.Author)\n\t}\n\n\tif err := w.Flush(); err != nil {\n\t\treturn err\n\t}\n\n\tfor {\n\t\tline, err := b.ReadString('\\n')\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\n\t\tbuilder.Printf(\"%s\", line)\n\t}\n\n\treturn nil //nolint:nilerr\n}\n"
  },
  {
    "path": "pkg/imager/extensions/rebuild.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// rebuildInitramfs rebuilds finalized initramfs with extensions.\n//\n// If uncompressedListing is not empty, contents will be prepended to the initramfs uncompressed.\n// Contents from compressedListing will be appended to the initramfs compressed (xz/zstd) as a second block.\n// Original initramfs.xz contents will stay without changes.\nfunc (builder *Builder) rebuildInitramfs(ctx context.Context, tempDir string, quirks quirks.Quirks) error {\n\tcompressedListing, uncompressedListing, err := buildInitramfsContents(tempDir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(uncompressedListing) > 0 {\n\t\tif err = builder.prependUncompressedInitramfs(ctx, tempDir, uncompressedListing); err != nil {\n\t\t\treturn fmt.Errorf(\"error prepending uncompressed initramfs: %w\", err)\n\t\t}\n\t}\n\n\tif err = builder.appendCompressedInitramfs(ctx, tempDir, compressedListing, quirks); err != nil {\n\t\treturn fmt.Errorf(\"error appending compressed initramfs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (builder *Builder) appendCompressedInitramfs(ctx context.Context, tempDir string, compressedListing []byte, quirks quirks.Quirks) error {\n\tbuilder.Printf(\"creating system extensions initramfs archive and compressing it\")\n\n\t// the code below runs the equivalent of:\n\t//   find $tempDir -print | cpio -H newc --create --reproducible | { xz -v -C crc32 -0 -e -T 0 -z || zstd -T0 -18 -c --quiet }\n\n\tpipeR, pipeW, err := os.Pipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer pipeR.Close() //nolint:errcheck\n\tdefer pipeW.Close() //nolint:errcheck\n\n\t// build cpio image which contains .sqsh images and extensions.yaml\n\tcmd1 := exec.CommandContext(ctx, \"cpio\", \"-H\", \"newc\", \"--create\", \"--reproducible\", \"--quiet\", \"-R\", \"+0:+0\")\n\tcmd1.Dir = tempDir\n\tcmd1.Stdin = bytes.NewReader(compressedListing)\n\tcmd1.Stdout = pipeW\n\tcmd1.Stderr = os.Stderr\n\n\tif err = cmd1.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = pipeW.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tdestination, err := os.OpenFile(builder.InitramfsPath, os.O_APPEND|os.O_WRONLY, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer destination.Close() //nolint:errcheck\n\n\t// append compressed initramfs.sysext to the original initramfs.xz, kernel can read such format\n\tvar cmd2 *exec.Cmd\n\n\tif quirks.UseZSTDCompression() {\n\t\tcmd2 = exec.CommandContext(ctx, \"zstd\", \"-T0\", \"-18\", \"-c\", \"--quiet\")\n\t} else {\n\t\tcmd2 = exec.CommandContext(ctx, \"xz\", \"-v\", \"-C\", \"crc32\", \"-0\", \"-e\", \"-T\", \"0\", \"-z\", \"--quiet\")\n\t}\n\n\tcmd2.Dir = tempDir\n\tcmd2.Stdin = pipeR\n\tcmd2.Stdout = destination\n\tcmd2.Stderr = os.Stderr\n\n\tif err = cmd2.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = pipeR.Close(); err != nil {\n\t\treturn err\n\t}\n\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\terrCh <- cmd1.Wait()\n\t}()\n\n\tgo func() {\n\t\terrCh <- cmd2.Wait()\n\t}()\n\n\tfor range 2 {\n\t\tif err = <-errCh; err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn destination.Sync()\n}\n\nfunc (builder *Builder) prependUncompressedInitramfs(ctx context.Context, tempDir string, uncompressedListing []byte) error {\n\tbuilder.Printf(\"creating uncompressed initramfs archive\")\n\n\t// the code below runs the equivalent of:\n\t//   mv initramfs.xz initramfs.xz-old\n\t//   find $tempDir -print | cpio -H newc --create --reproducible > initramfs.xz\n\t//   cat initramfs.xz-old >> initramfs.xz\n\t//   rm initramfs.xz-old\n\n\tinitramfsOld := builder.InitramfsPath + \"-old\"\n\n\tif err := os.Rename(builder.InitramfsPath, initramfsOld); err != nil {\n\t\treturn err\n\t}\n\n\tdestination, err := os.OpenFile(builder.InitramfsPath, os.O_CREATE|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer destination.Close() //nolint:errcheck\n\n\tcmd := exec.CommandContext(ctx, \"cpio\", \"-H\", \"newc\", \"--create\", \"--reproducible\", \"--quiet\", \"-R\", \"+0:+0\")\n\tcmd.Dir = tempDir\n\tcmd.Stdin = bytes.NewReader(uncompressedListing)\n\tcmd.Stdout = destination\n\tcmd.Stderr = os.Stderr\n\n\tif err = cmd.Run(); err != nil {\n\t\treturn err\n\t}\n\n\told, err := os.Open(initramfsOld)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer old.Close() //nolint:errcheck\n\n\tif _, err = io.Copy(destination, old); err != nil {\n\t\treturn err\n\t}\n\n\tif err = destination.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = old.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.Remove(initramfsOld)\n}\n"
  },
  {
    "path": "pkg/imager/filemap/filemap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package filemap provides a way to create reproducible layers from a file system.\npackage filemap\n\nimport (\n\t\"archive/tar\"\n\t\"cmp\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\tstdpath \"path\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/tarball\"\n\t\"github.com/google/go-containerregistry/pkg/v1/types\"\n)\n\n// File is a path -> file content map representing a file system.\ntype File struct {\n\tImagePath  string\n\tSourcePath string\n\tImageMode  int64\n}\n\n// Walk the filesystem generating a filemap.\nfunc Walk(sourceBasePath, imageBasePath string) ([]File, error) {\n\tvar filemap []File\n\n\terr := filepath.WalkDir(sourceBasePath, func(path string, d os.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trel, err := filepath.Rel(sourceBasePath, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif d.IsDir() && rel == \".\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tstatInfo, err := d.Info()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfilemap = append(filemap, File{\n\t\t\tImagePath:  stdpath.Join(imageBasePath, filepath.ToSlash(rel)),\n\t\t\tSourcePath: path,\n\t\t\tImageMode:  int64(statInfo.Mode().Perm()),\n\t\t})\n\n\t\treturn nil\n\t})\n\n\treturn filemap, err\n}\n\n// Build a tarball from a filemap.\nfunc Build(filemap []File) io.ReadCloser {\n\tpr, pw := io.Pipe()\n\n\tgo func() {\n\t\tpw.CloseWithError(func() error {\n\t\t\tw := tar.NewWriter(pw)\n\n\t\t\tfor _, entry := range filemap {\n\t\t\t\tif err := func(entry File) error {\n\t\t\t\t\tin, err := os.Open(entry.SourcePath)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error opening %q: %w\", entry.SourcePath, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tdefer in.Close() //nolint:errcheck\n\n\t\t\t\t\tst, err := in.Stat()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error stating file %s: %w\", entry.SourcePath, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif st.IsDir() {\n\t\t\t\t\t\tif err := handleDir(w, entry.ImagePath, entry.ImageMode); err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"error handling directory %s: %w\", entry.SourcePath, err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn in.Close()\n\t\t\t\t\t}\n\n\t\t\t\t\tif err := handleFile(w, in, entry.ImagePath, entry.ImageMode, st.Size()); err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error handling file %s: %w\", entry.SourcePath, err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn in.Close()\n\t\t\t\t}(entry); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"error processing %s: %w\", entry.SourcePath, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn w.Close()\n\t\t}())\n\t}()\n\n\treturn pr\n}\n\nfunc handleFile(w *tar.Writer, r io.Reader, path string, mode, size int64) error {\n\theader := &tar.Header{\n\t\tName: path,\n\t\tMode: mode,\n\t\tSize: size,\n\t}\n\n\tif err := w.WriteHeader(header); err != nil {\n\t\treturn fmt.Errorf(\"error writing tar header for %s: %w\", path, err)\n\t}\n\n\tif _, err := io.Copy(w, r); err != nil {\n\t\treturn fmt.Errorf(\"error writing tar data for %s: %w\", path, err)\n\t}\n\n\treturn nil\n}\n\nfunc handleDir(w *tar.Writer, path string, mode int64) error {\n\theader := &tar.Header{\n\t\tName:     path,\n\t\tMode:     mode,\n\t\tTypeflag: tar.TypeDir,\n\t}\n\n\tif err := w.WriteHeader(header); err != nil {\n\t\treturn fmt.Errorf(\"error writing tar header for %s: %w\", path, err)\n\t}\n\n\treturn nil\n}\n\n// Layer creates a layer from a single file map.\n//\n// These layers are reproducible and consistent.\n//\n// A filemap is a path -> file content map representing a file system.\nfunc Layer(filemap []File) (v1.Layer, error) {\n\tslices.SortFunc(filemap, func(a, b File) int { return cmp.Compare(a.ImagePath, b.ImagePath) })\n\n\t// Return a new copy of the buffer each time it's opened.\n\treturn tarball.LayerFromOpener(func() (io.ReadCloser, error) {\n\t\treturn Build(filemap), nil\n\t}, tarball.WithMediaType(types.OCILayer))\n}\n"
  },
  {
    "path": "pkg/imager/filemap/filemap_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage filemap_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/filemap\"\n)\n\nfunc TestFileMap(t *testing.T) {\n\ttempDir := t.TempDir()\n\n\tassert.NoError(t, os.MkdirAll(filepath.Join(tempDir, \"foo/a/b\"), 0o755))\n\tassert.NoError(t, os.MkdirAll(filepath.Join(tempDir, \"foo/c\"), 0o755))\n\tassert.NoError(t, os.MkdirAll(filepath.Join(tempDir, \"foo/d\"), 0o750))\n\n\tassert.NoError(t, os.WriteFile(filepath.Join(tempDir, \"foo/a/b/normal\"), nil, 0o644))\n\tassert.NoError(t, os.WriteFile(filepath.Join(tempDir, \"foo/c/executable\"), []byte(\"world\"), 0o755))\n\n\tartifacts, err := filemap.Walk(tempDir, \"\")\n\tassert.NoError(t, err)\n\n\tassert.Equal(\n\t\tt,\n\t\t[]filemap.File{\n\t\t\t{\n\t\t\t\tImagePath:  \"foo\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo\"),\n\t\t\t\tImageMode:  0o755,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/a\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/a\"),\n\t\t\t\tImageMode:  0o755,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/a/b\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/a/b\"),\n\t\t\t\tImageMode:  0o755,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/a/b/normal\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/a/b/normal\"),\n\t\t\t\tImageMode:  0o644,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/c\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/c\"),\n\t\t\t\tImageMode:  0o755,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/c/executable\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/c/executable\"),\n\t\t\t\tImageMode:  0o755,\n\t\t\t},\n\t\t\t{\n\t\t\t\tImagePath:  \"foo/d\",\n\t\t\t\tSourcePath: filepath.Join(tempDir, \"foo/d\"),\n\t\t\t\tImageMode:  0o750,\n\t\t\t},\n\t\t},\n\t\tartifacts,\n\t)\n}\n"
  },
  {
    "path": "pkg/imager/imager.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package imager contains code related to generation of different boot assets for Talos Linux.\npackage imager\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/platform\"\n\t\"github.com/siderolabs/talos/internal/pkg/uki\"\n\t\"github.com/siderolabs/talos/pkg/imager/extensions\"\n\t\"github.com/siderolabs/talos/pkg/imager/overlay/executor\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// Imager is an interface for image generation.\ntype Imager struct {\n\tprof profile.Profile\n\n\toverlayInstaller overlay.Installer[overlay.ExtraOptions]\n\textraProfiles    map[string]profile.Profile\n\n\ttempDir string\n\n\t// boot assets\n\tinitramfsPath string\n\tcmdline       string\n\n\tsdBootPath string\n\tukiPath    string\n}\n\n// New creates a new Imager.\nfunc New(prof profile.Profile) (*Imager, error) {\n\treturn &Imager{\n\t\tprof: prof,\n\t}, nil\n}\n\n// Execute image generation.\n//\n//nolint:gocyclo,cyclop\nfunc (i *Imager) Execute(ctx context.Context, outputPath string, report *reporter.Reporter) (outputAssetPath string, err error) {\n\ti.tempDir, err = os.MkdirTemp(\"\", \"imager\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create temporary directory: %w\", err)\n\t}\n\n\tdefer os.RemoveAll(i.tempDir) //nolint:errcheck\n\n\t// 0. Handle overlays first\n\tif err = i.handleOverlay(ctx, report); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = i.handleProf(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = i.handleEmbeddedConfig(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{\n\t\tMessage: \"profile ready:\",\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\t// 1. Dump the profile.\n\tif err = i.prof.Dump(os.Stderr); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// 2. Transform `initramfs.xz` with system extensions\n\tif err = i.buildInitramfs(ctx, report); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// 3. Prepare kernel arguments.\n\tif err = i.buildCmdline(ctx); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{\n\t\tMessage: fmt.Sprintf(\"kernel command line: %s\", i.cmdline),\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\t// 4. Build UKI if needed\n\tneedBuildUKI := quirks.New(i.prof.Version).SupportsUKI()\n\n\tswitch i.prof.Output.Kind {\n\tcase profile.OutKindUKI:\n\t\tif !needBuildUKI {\n\t\t\treturn \"\", fmt.Errorf(\"UKI output is not supported in this Talos version\")\n\t\t}\n\tcase profile.OutKindISO, profile.OutKindInstaller, profile.OutKindImage:\n\t\tneedBuildUKI = needBuildUKI || quirks.New(i.prof.Version).UseSDBootForUEFI()\n\tcase profile.OutKindCmdline, profile.OutKindKernel, profile.OutKindInitramfs:\n\t\tneedBuildUKI = false\n\tcase profile.OutKindUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown output kind: %s\", i.prof.Output.Kind)\n\t}\n\n\tif needBuildUKI {\n\t\tif err = i.buildUKI(ctx, report); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\t// 5. Build the output.\n\toutputAssetPath = filepath.Join(outputPath, i.prof.OutputPath())\n\n\tswitch i.prof.Output.Kind {\n\tcase profile.OutKindISO:\n\t\terr = i.outISO(ctx, outputAssetPath, report)\n\tcase profile.OutKindKernel:\n\t\terr = i.outKernel(outputAssetPath, report)\n\tcase profile.OutKindUKI:\n\t\terr = i.outUKI(outputAssetPath, report)\n\tcase profile.OutKindInitramfs:\n\t\terr = i.outInitramfs(outputAssetPath, report)\n\tcase profile.OutKindCmdline:\n\t\terr = i.outCmdline(outputAssetPath)\n\tcase profile.OutKindImage:\n\t\terr = i.outImage(ctx, outputAssetPath, report)\n\tcase profile.OutKindInstaller:\n\t\terr = i.outInstaller(ctx, outputAssetPath, report)\n\tcase profile.OutKindUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown output kind: %s\", i.prof.Output.Kind)\n\t}\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{\n\t\tMessage: fmt.Sprintf(\"output asset path: %s\", outputAssetPath),\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\t// 6. Post-process the output.\n\tswitch i.prof.Output.OutFormat {\n\tcase profile.OutFormatRaw:\n\t\t// do nothing\n\t\treturn outputAssetPath, nil\n\tcase profile.OutFormatXZ:\n\t\treturn i.postProcessXz(ctx, outputAssetPath, report)\n\tcase profile.OutFormatGZ:\n\t\treturn i.postProcessGz(ctx, outputAssetPath, report)\n\tcase profile.OutFormatZSTD:\n\t\treturn i.postProcessZstd(ctx, outputAssetPath, report)\n\tcase profile.OutFormatTar:\n\t\treturn i.postProcessTar(ctx, outputAssetPath, report)\n\tcase profile.OutFormatUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown output format: %s\", i.prof.Output.OutFormat)\n\t}\n}\n\nfunc (i *Imager) handleOverlay(ctx context.Context, report *reporter.Reporter) error {\n\tif i.prof.Overlay == nil {\n\t\treport.Report(reporter.Update{\n\t\t\tMessage: \"skipped pulling overlay (no overlay)\",\n\t\t\tStatus:  reporter.StatusSkip,\n\t\t})\n\n\t\treturn nil\n\t}\n\n\ttempOverlayPath := filepath.Join(i.tempDir, constants.ImagerOverlayBasePath)\n\n\tif err := os.MkdirAll(tempOverlayPath, 0o755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create overlay directory: %w\", err)\n\t}\n\n\tif err := i.prof.Overlay.Image.Extract(ctx, tempOverlayPath, runtime.GOARCH, progressPrintf(report, reporter.Update{Message: \"pulling overlay...\", Status: reporter.StatusRunning})); err != nil {\n\t\treturn err\n\t}\n\n\t// find all *.yaml files in the overlay/profiles/ directory\n\tprofileYAMLs, err := filepath.Glob(filepath.Join(i.tempDir, constants.ImagerOverlayProfilesPath, \"*.yaml\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find profiles: %w\", err)\n\t}\n\n\tif i.prof.Overlay.Name == \"\" {\n\t\ti.prof.Overlay.Name = constants.ImagerOverlayInstallerDefault\n\t}\n\n\ti.overlayInstaller = executor.New(filepath.Join(i.tempDir, constants.ImagerOverlayInstallersPath, i.prof.Overlay.Name))\n\n\tif i.extraProfiles == nil {\n\t\ti.extraProfiles = make(map[string]profile.Profile)\n\t}\n\n\tfor _, profilePath := range profileYAMLs {\n\t\tprofileName := strings.TrimSuffix(filepath.Base(profilePath), \".yaml\")\n\n\t\tvar overlayProfile profile.Profile\n\n\t\tprofileDataBytes, err := os.ReadFile(profilePath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read profile: %w\", err)\n\t\t}\n\n\t\tif err := yaml.Unmarshal(profileDataBytes, &overlayProfile); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal profile: %w\", err)\n\t\t}\n\n\t\ti.extraProfiles[profileName] = overlayProfile\n\t}\n\n\treturn nil\n}\n\nfunc (i *Imager) handleProf() error {\n\t// resolve the profile if it contains a base name\n\tif i.prof.BaseProfileName != \"\" {\n\t\tbaseProfile, ok := i.extraProfiles[i.prof.BaseProfileName]\n\n\t\tif !ok {\n\t\t\tbaseProfile, ok = profile.Default[i.prof.BaseProfileName]\n\t\t}\n\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unknown base profile: %s\", i.prof.BaseProfileName)\n\t\t}\n\n\t\tbaseProfile = baseProfile.DeepCopy()\n\n\t\t// merge the profiles\n\t\tif err := merge.Merge(&baseProfile, &i.prof); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ti.prof = baseProfile\n\t\ti.prof.BaseProfileName = \"\"\n\t}\n\n\tif i.prof.Version == \"\" {\n\t\ti.prof.Version = version.Tag\n\t}\n\n\ti.prof.Input.FillDefaults(i.prof.Arch, i.prof.Version, i.prof.SecureBootEnabled())\n\ti.prof.Output.FillDefaults(i.prof.Arch, i.prof.Version, i.prof.SecureBootEnabled())\n\n\tif err := i.prof.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"profile is invalid: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// buildInitramfs transforms `initramfs.xz` with system extensions.\nfunc (i *Imager) buildInitramfs(ctx context.Context, report *reporter.Reporter) error {\n\tif len(i.prof.Input.SystemExtensions) == 0 {\n\t\treport.Report(reporter.Update{\n\t\t\tMessage: \"skipped initramfs rebuild (no system extensions)\",\n\t\t\tStatus:  reporter.StatusSkip,\n\t\t})\n\n\t\t// no system extensions, happy path\n\t\ti.initramfsPath = i.prof.Input.Initramfs.Path\n\n\t\treturn nil\n\t}\n\n\tif i.prof.Output.Kind == profile.OutKindCmdline || i.prof.Output.Kind == profile.OutKindKernel {\n\t\t// these outputs don't use initramfs image\n\t\treturn nil\n\t}\n\n\tprintf := progressPrintf(report, reporter.Update{Message: \"rebuilding initramfs with system extensions...\", Status: reporter.StatusRunning})\n\n\t// copy the initramfs to a temporary location, as it's going to be modified during the extension build process\n\ttempInitramfsPath := filepath.Join(i.tempDir, \"initramfs.xz\")\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(i.prof.Input.Initramfs.Path, tempInitramfsPath)); err != nil {\n\t\treturn fmt.Errorf(\"failed to copy initramfs: %w\", err)\n\t}\n\n\ti.initramfsPath = tempInitramfsPath\n\n\textensionsCheckoutDir := filepath.Join(i.tempDir, \"extensions\")\n\n\t// pull every extension to a temporary location\n\tfor j, ext := range i.prof.Input.SystemExtensions {\n\t\textensionDir := filepath.Join(extensionsCheckoutDir, strconv.Itoa(j))\n\n\t\tif err := os.MkdirAll(extensionDir, 0o755); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create extension directory: %w\", err)\n\t\t}\n\n\t\tif err := ext.Extract(ctx, extensionDir, i.prof.Arch, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// rebuild initramfs\n\tbuilder := extensions.Builder{\n\t\tInitramfsPath:     i.initramfsPath,\n\t\tArch:              i.prof.Arch,\n\t\tExtensionTreePath: extensionsCheckoutDir,\n\t\tPrintf:            printf,\n\t\tQuirks:            quirks.New(i.prof.Version),\n\t}\n\n\tif err := builder.Build(ctx); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{\n\t\tMessage: \"initramfs ready\",\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\treturn nil\n}\n\n// buildCmdline builds the kernel command line.\n//\n//nolint:gocyclo\nfunc (i *Imager) buildCmdline(ctx context.Context) error {\n\tp, err := platform.NewPlatform(i.prof.Platform)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tq := quirks.New(i.prof.Version)\n\n\tcmdline := procfs.NewCmdline(\"\")\n\n\t// platform kernel args\n\tcmdline.Append(constants.KernelParamPlatform, p.Name())\n\n\tcmdline.SetAll(p.KernelArgs(i.prof.Arch, q).Strings())\n\n\tif q.SupportsHaltIfInstalled() && i.prof.Output.Kind == profile.OutKindISO {\n\t\tcmdline.Append(constants.KernelParamHaltIfInstalled, \"1\")\n\t}\n\n\t// overlay kernel args\n\tif i.overlayInstaller != nil {\n\t\toptions, optsErr := i.overlayInstaller.GetOptions(ctx, i.prof.Overlay.ExtraOptions)\n\t\tif optsErr != nil {\n\t\t\treturn optsErr\n\t\t}\n\n\t\tcmdline.SetAll(options.KernelArgs)\n\t}\n\n\t// first defaults, then extra kernel args to allow extra kernel args to override defaults\n\tif err = cmdline.AppendAll(kernel.DefaultArgs(q)); err != nil {\n\t\treturn err\n\t}\n\n\tif i.prof.SecureBootEnabled() {\n\t\tif err = cmdline.AppendAll(kernel.SecureBootArgs(q)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// meta values can be written only to the \"image\" output\n\tif len(i.prof.Customization.MetaContents) > 0 && i.prof.Output.Kind != profile.OutKindImage {\n\t\t// pass META values as kernel talos.environment args which will be passed via the environment to the installer\n\t\tcmdline.Append(\n\t\t\tconstants.KernelParamEnvironment,\n\t\t\tconstants.MetaValuesEnvVar+\"=\"+i.prof.Customization.MetaContents.Encode(quirks.New(i.prof.Version).SupportsCompressedEncodedMETA()),\n\t\t)\n\t}\n\n\t// apply customization\n\tif err = cmdline.AppendAll(\n\t\ti.prof.Customization.ExtraKernelArgs,\n\t\tprocfs.WithOverwriteArgs(\"console\"),\n\t\tprocfs.WithOverwriteArgs(constants.KernelParamPlatform),\n\t\tprocfs.WithDeleteNegatedArgs(),\n\t); err != nil {\n\t\treturn err\n\t}\n\n\ti.cmdline = cmdline.String()\n\n\treturn nil\n}\n\n// buildUKI assembles the UKI and signs it.\nfunc (i *Imager) buildUKI(ctx context.Context, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"building UKI...\", Status: reporter.StatusRunning})\n\n\ti.sdBootPath = filepath.Join(i.tempDir, \"systemd-boot.efi\")\n\ti.ukiPath = filepath.Join(i.tempDir, \"vmlinuz.efi\")\n\n\tbuilder := uki.Builder{\n\t\tArch:       i.prof.Arch,\n\t\tVersion:    i.prof.Version,\n\t\tSdStubPath: i.prof.Input.SDStub.Path,\n\t\tSdBootPath: i.prof.Input.SDBoot.Path,\n\t\tKernelPath: i.prof.Input.Kernel.Path,\n\t\tInitrdPath: i.initramfsPath,\n\t\tCmdline:    i.cmdline,\n\n\t\tOutSdBootPath: i.sdBootPath,\n\t\tOutUKIPath:    i.ukiPath,\n\t}\n\n\tswitch i.prof.Output.Kind { //nolint:exhaustive\n\tcase profile.OutKindISO:\n\t\tbuilder.Profiles = append(builder.Profiles, uki.Profile{\n\t\t\tID:      \"reset\",\n\t\t\tTitle:   \"Reset system disk\",\n\t\t\tCmdline: builder.Cmdline + fmt.Sprintf(\" %s=system\", constants.KernelParamWipe),\n\t\t})\n\tcase profile.OutKindImage, profile.OutKindInstaller:\n\t\tbuilder.Profiles = append(builder.Profiles, uki.Profile{\n\t\t\tID:    \"reset-maintenance\",\n\t\t\tTitle: \"Reset to maintenance mode\",\n\n\t\t\tCmdline: builder.Cmdline + fmt.Sprintf(\" %s=system:EPHEMERAL,STATE\", constants.KernelParamWipe),\n\t\t})\n\t}\n\n\tbuildFunc := builder.Build\n\n\tif i.prof.SecureBootEnabled() {\n\t\ti.sdBootPath = filepath.Join(i.tempDir, \"systemd-boot.efi.signed\")\n\t\ti.ukiPath = filepath.Join(i.tempDir, \"vmlinuz.efi.signed\")\n\n\t\tbuilder.OutSdBootPath = i.sdBootPath\n\t\tbuilder.OutUKIPath = i.ukiPath\n\n\t\tpcrSigner, err := i.prof.Input.SecureBoot.PCRSigner.GetSigner(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get PCR signer: %w\", err)\n\t\t}\n\n\t\tsecurebootSigner, err := i.prof.Input.SecureBoot.SecureBootSigner.GetSigner(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get SecureBoot signer: %w\", err)\n\t\t}\n\n\t\tbuilder.SecureBootSigner = securebootSigner\n\t\tbuilder.PCRSigner = pcrSigner\n\n\t\tbuildFunc = builder.BuildSigned\n\t}\n\n\tif err := buildFunc(printf); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{\n\t\tMessage: \"UKI ready\",\n\t\tStatus:  reporter.StatusSucceeded,\n\t})\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/imager_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nfunc TestImager(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tprof profile.Profile\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"cmdline-pre1.8-amd64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"amd64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.7.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=ttyS0 console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-pre1.8-arm64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"arm64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.7.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=ttyAMA0 console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.8-amd64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"amd64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.8.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.8-arm64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"arm64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.8.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=ttyAMA0 console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.10-amd64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"amd64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.10.1\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512 selinux=1\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.10-arm64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"arm64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.10.1\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=ttyAMA0 console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on ima_template=ima-ng ima_appraise=fix ima_hash=sha512 selinux=1\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.11-amd64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"amd64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.11.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on selinux=1\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"cmdline-1.11-arm64\",\n\n\t\t\tprof: profile.Profile{\n\t\t\t\tBaseProfileName: \"metal\",\n\t\t\t\tArch:            \"arm64\",\n\t\t\t\tOutput: profile.Output{\n\t\t\t\t\tKind:      profile.OutKindCmdline,\n\t\t\t\t\tOutFormat: profile.OutFormatRaw,\n\t\t\t\t},\n\t\t\t\tVersion: \"1.11.0\",\n\t\t\t},\n\n\t\t\texpected: \"talos.platform=metal console=ttyAMA0 console=tty0 init_on_alloc=1 slab_nomerge pti=on consoleblank=0 nvme_core.io_timeout=4294967295 printk.devkmsg=on selinux=1\", //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx, cancel := context.WithTimeout(t.Context(), 10*time.Second)\n\t\t\tt.Cleanup(cancel)\n\n\t\t\timgr, err := imager.New(test.prof)\n\t\t\trequire.NoError(t, err)\n\n\t\t\toutPath := t.TempDir()\n\n\t\t\toutputPath, err := imgr.Execute(ctx, outPath, reporter.New())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tout, err := os.ReadFile(outputPath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, string(out))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/iso/grub.cfg",
    "content": "set default=0\nset timeout=3\n\ninsmod all_video\n\nterminal_input console\nterminal_output console\n\nmenuentry \"Talos ISO\" {\n\tset gfxmode=auto\n\tset gfxpayload=text\n\tlinux /boot/vmlinuz {{ quote .Cmdline }}\n\tinitrd /boot/initramfs.xz\n}\n\n{{ if .AddResetOption -}}\nmenuentry \"Reset Talos installation\" {\n\tset gfxmode=auto\n\tset gfxpayload=text\n\tlinux /boot/vmlinuz {{ quote .Cmdline }} talos.experimental.wipe=system\n\tinitrd /boot/initramfs.xz\n}\n{{ end -}}\n"
  },
  {
    "path": "pkg/imager/iso/grub.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage iso\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"text/template\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n//go:embed grub.cfg\nvar grubCfgTemplate string\n\n// CreateGRUB creates a GRUB-based ISO image.\n//\n// This iso supports both BIOS and UEFI booting.\nfunc (options Options) CreateGRUB(printf func(string, ...any)) (Generator, error) {\n\tif err := utils.CopyFiles(\n\t\tprintf,\n\t\tutils.SourceDestination(options.KernelPath, filepath.Join(options.ScratchDir, \"boot\", \"vmlinuz\")),\n\t\tutils.SourceDestination(options.InitramfsPath, filepath.Join(options.ScratchDir, \"boot\", \"initramfs.xz\")),\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprintf(\"creating grub.cfg\")\n\n\tvar grubCfg bytes.Buffer\n\n\ttmpl, err := template.New(\"grub.cfg\").\n\t\tFuncs(template.FuncMap{\n\t\t\t\"quote\": grub.Quote,\n\t\t}).\n\t\tParse(grubCfgTemplate)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = tmpl.Execute(&grubCfg, struct {\n\t\tCmdline        string\n\t\tAddResetOption bool\n\t}{\n\t\tCmdline:        options.Cmdline,\n\t\tAddResetOption: quirks.New(options.Version).SupportsResetGRUBOption(),\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tcfgPath := filepath.Join(options.ScratchDir, \"boot/grub/grub.cfg\")\n\n\tif err = os.MkdirAll(filepath.Dir(cfgPath), 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = os.WriteFile(cfgPath, grubCfg.Bytes(), 0o666); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = utils.TouchFiles(printf, options.ScratchDir); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprintf(\"creating ISO image\")\n\n\treturn &ExecutorOptions{\n\t\tCommand: \"grub-mkrescue\",\n\t\tVersion: options.Version,\n\t\tArguments: []string{\n\t\t\t\"--compress=xz\",\n\t\t\t\"--output=\" + options.OutPath,\n\t\t\t\"--verbose\",\n\t\t\toptions.ScratchDir,\n\t\t\t\"-iso-level\", \"3\",\n\t\t\t\"--\",\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/iso/hybrid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage iso\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n)\n\n// CreateHybrid creates an ISO image that supports both BIOS and UEFI booting.\nfunc (options Options) CreateHybrid(ctx context.Context, printf func(string, ...any)) (Generator, error) {\n\tif _, err := options.CreateGRUB(printf); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif _, err := options.CreateUEFI(ctx, printf); err != nil {\n\t\treturn nil, err\n\t}\n\n\tefiBootImg := filepath.Join(options.ScratchDir, \"efiboot.img\")\n\n\treturn &ExecutorOptions{\n\t\tCommand: \"grub-mkrescue\",\n\t\tVersion: options.Version,\n\t\tArguments: []string{\n\t\t\t\"--compress=xz\",\n\t\t\t\"--output=\" + options.OutPath,\n\t\t\t\"--verbose\",\n\t\t\t\"--directory=/usr/lib/grub/i386-pc\", // only for BIOS boot\n\t\t\t\"-m\", \"efiboot.img\",                 // exclude the EFI boot image from the ISO\n\t\t\t\"-iso-level\", \"3\",\n\t\t\toptions.ScratchDir,\n\t\t\t\"-eltorito-alt-boot\",\n\t\t\t\"-e\", \"--interval:appended_partition_2:all::\", // use appended partition 2 for EFI\n\t\t\t\"-append_partition\", \"2\", \"0xef\", efiBootImg,\n\t\t\t\"-appended_part_as_gpt\",\n\t\t\t\"-partition_cyl_align\", // pad partition to cylinder boundary\n\t\t\t\"all\",\n\t\t\t\"-partition_offset\", \"16\", // support booting from USB\n\t\t\t\"-iso_mbr_part_type\", \"0x83\", // just to have more clear info when doing a fdisk -l\n\t\t\t\"-no-emul-boot\",\n\t\t\t\"--\",\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/iso/iso.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package iso contains functions for creating ISO images.\npackage iso\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// VolumeID returns a valid volume ID for the given label.\nfunc VolumeID(label string) string {\n\t// builds a valid volume ID: 32 chars out of [A-Z0-9_]\n\tlabel = strings.ToUpper(label)\n\tlabel = strings.Map(func(r rune) rune {\n\t\tswitch {\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn r\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn r\n\t\tcase r == '_' || r == '-' || r == '.':\n\t\t\treturn '_'\n\t\tdefault:\n\t\t\treturn -1\n\t\t}\n\t}, label)\n\n\tif len(label) > 32 {\n\t\tlabel = label[:32]\n\t}\n\n\treturn label\n}\n\n// Label returns an ISO full label for a given version.\nfunc Label(version string, secureboot bool) string {\n\tlabel := \"Talos-\"\n\n\tif secureboot {\n\t\tlabel += \"SB-\"\n\t}\n\n\treturn label + version\n}\n\n// ExecutorOptions defines the iso generation options.\ntype ExecutorOptions struct {\n\tCommand   string\n\tVersion   string\n\tArguments []string\n}\n\n// Generator is an interface for executing the iso generation.\ntype Generator interface {\n\tGenerate(ctx context.Context) error\n}\n\n// Options describe the input generating different types of ISOs.\ntype Options struct {\n\tKernelPath    string\n\tInitramfsPath string\n\tCmdline       string\n\n\tUKIPath    string\n\tSDBootPath string\n\n\tArch    string\n\tVersion string\n\n\t// A value in loader.conf secure-boot-enroll: off, manual, if-safe, force.\n\tSDBootSecureBootEnrollKeys string\n\n\t// UKISigningCertDer is the DER encoded UKI signing certificate.\n\tUKISigningCertDerPath string\n\n\t// optional, for auto-enrolling secureboot keys\n\tPlatformKeyPath    string\n\tKeyExchangeKeyPath string\n\tSignatureKeyPath   string\n\n\tScratchDir string\n\tOutPath    string\n}\n\n// Generate creates an ISO image.\nfunc (e *ExecutorOptions) Generate(ctx context.Context) error {\n\tif epoch, ok, err := utils.SourceDateEpoch(); err != nil {\n\t\treturn err\n\t} else if ok {\n\t\t// set EFI FAT image serial number\n\t\tif err := os.Setenv(\"GRUB_FAT_SERIAL_NUMBER\", fmt.Sprintf(\"%x\", uint32(epoch))); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\te.Arguments = append(e.Arguments,\n\t\t\t\"-volume_date\", \"all_file_dates\", fmt.Sprintf(\"=%d\", epoch),\n\t\t\t\"-volume_date\", \"uuid\", time.Unix(epoch, 0).Format(\"2006010215040500\"),\n\t\t)\n\t}\n\n\tif quirks.New(e.Version).SupportsISOLabel() {\n\t\tlabel := Label(e.Version, false)\n\n\t\te.Arguments = append(e.Arguments,\n\t\t\t\"-volid\", VolumeID(label),\n\t\t\t\"-volset-id\", label,\n\t\t)\n\t}\n\n\t_, err := cmd.RunWithOptions(ctx, e.Command, e.Arguments)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create ISO: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/iso/iso_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage iso_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/iso\"\n)\n\nfunc TestVolumeID(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tin string\n\n\t\tout string\n\t}{\n\t\t{\n\t\t\tin: \"Talos-v1.7.6\",\n\n\t\t\tout: \"TALOS_V1_7_6\",\n\t\t},\n\t\t{\n\t\t\tin: \"Talos-v1.7.6-beta.0\",\n\n\t\t\tout: \"TALOS_V1_7_6_BETA_0\",\n\t\t},\n\t} {\n\t\tt.Run(test.in, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.out, iso.VolumeID(test.in))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/iso/loader.conf.tmpl",
    "content": "# systemd-boot configuration\n\ntimeout 10\n\nsecure-boot-enroll {{ .SecureBootEnroll }}\n"
  },
  {
    "path": "pkg/imager/iso/uefi.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage iso\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"text/template\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"github.com/siderolabs/go-copy/copy\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\nconst (\n\t// mib is the size of a megabyte.\n\tmib = 1024 * 1024\n)\n\n//go:embed loader.conf.tmpl\nvar loaderConfigTemplate string\n\n// CreateUEFI creates an iso using a UKI, systemd-boot.\n//\n// The ISO created supports only booting in UEFI mode, and supports SecureBoot.\n//\n//nolint:gocyclo,cyclop\nfunc (options Options) CreateUEFI(ctx context.Context, printf func(string, ...any)) (Generator, error) {\n\tif err := os.MkdirAll(options.ScratchDir, 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprintf(\"preparing raw image\")\n\n\tefiBootImg := filepath.Join(options.ScratchDir, \"efiboot.img\")\n\n\t// initial size\n\tisoSize := int64(10 * mib)\n\n\tfor _, path := range []string{\n\t\toptions.SDBootPath,\n\t\toptions.UKIPath,\n\t} {\n\t\tst, err := os.Stat(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tisoSize += (st.Size() + mib - 1) / mib * mib\n\t}\n\n\tif err := utils.CreateRawDisk(printf, efiBootImg, isoSize, true); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprintf(\"preparing loader.conf\")\n\n\tvar loaderConfigOut bytes.Buffer\n\n\tif err := template.Must(template.New(\"loader.conf\").Parse(loaderConfigTemplate)).Execute(&loaderConfigOut, struct {\n\t\tSecureBootEnroll string\n\t}{\n\t\tSecureBootEnroll: options.SDBootSecureBootEnrollKeys,\n\t}); err != nil {\n\t\treturn nil, fmt.Errorf(\"error rendering loader.conf: %w\", err)\n\t}\n\n\tprintf(\"creating vFAT EFI image\")\n\n\tfopts := []makefs.Option{\n\t\tmakefs.WithLabel(constants.EFIPartitionLabel),\n\t\tmakefs.WithReproducible(true),\n\t}\n\n\tif err := makefs.VFAT(ctx, efiBootImg, fopts...); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := os.MkdirAll(filepath.Join(options.ScratchDir, \"EFI/Linux\"), 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := os.MkdirAll(filepath.Join(options.ScratchDir, \"EFI/BOOT\"), 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := os.MkdirAll(filepath.Join(options.ScratchDir, \"loader\"), 0o755); err != nil {\n\t\treturn nil, err\n\t}\n\n\tefiBootPath := \"EFI/BOOT/BOOTX64.EFI\"\n\n\tif options.Arch == \"arm64\" {\n\t\tefiBootPath = \"EFI/BOOT/BOOTAA64.EFI\"\n\t}\n\n\tif err := copy.File(options.SDBootPath, filepath.Join(options.ScratchDir, efiBootPath)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := copy.File(options.UKIPath, filepath.Join(options.ScratchDir, fmt.Sprintf(\"EFI/Linux/Talos-%s.efi\", options.Version))); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := os.WriteFile(filepath.Join(options.ScratchDir, \"loader/loader.conf\"), loaderConfigOut.Bytes(), 0o644); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.UKISigningCertDerPath != \"\" {\n\t\tif err := os.MkdirAll(filepath.Join(options.ScratchDir, \"EFI/keys\"), 0o755); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := copy.File(options.UKISigningCertDerPath, filepath.Join(options.ScratchDir, \"EFI/keys/uki-signing-cert.der\")); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif options.PlatformKeyPath != \"\" || options.KeyExchangeKeyPath != \"\" || options.SignatureKeyPath != \"\" {\n\t\tif err := os.MkdirAll(filepath.Join(options.ScratchDir, \"loader/keys/auto\"), 0o755); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif options.PlatformKeyPath != \"\" {\n\t\tif err := copy.File(options.PlatformKeyPath, filepath.Join(options.ScratchDir, \"loader/keys/auto\", constants.PlatformKeyAsset)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif options.KeyExchangeKeyPath != \"\" {\n\t\tif err := copy.File(options.KeyExchangeKeyPath, filepath.Join(options.ScratchDir, \"loader/keys/auto\", constants.KeyExchangeKeyAsset)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif options.SignatureKeyPath != \"\" {\n\t\tif err := copy.File(options.SignatureKeyPath, filepath.Join(options.ScratchDir, \"loader/keys/auto\", constants.SignatureKeyAsset)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// fixup directory timestamps recursively\n\tif err := utils.TouchFiles(printf, options.ScratchDir); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif _, err := cmd.RunWithOptions(\n\t\tctx,\n\t\t\"mcopy\",\n\t\t[]string{\n\t\t\t\"-s\", // recursive\n\t\t\t\"-p\", // preserve attributes\n\t\t\t\"-Q\", // quit on error\n\t\t\t\"-m\", // preserve modification time\n\t\t\t\"-i\",\n\t\t\tefiBootImg,\n\t\t\tfilepath.Join(options.ScratchDir, \"EFI\"),\n\t\t\tfilepath.Join(options.ScratchDir, \"loader\"),\n\t\t\t\"::\",\n\t\t},\n\t); err != nil {\n\t\treturn nil, err\n\t}\n\n\tprintf(\"creating ISO image\")\n\n\treturn &ExecutorOptions{\n\t\tCommand: \"xorrisofs\",\n\t\tVersion: options.Version,\n\t\tArguments: []string{\n\t\t\t\"-e\", \"--interval:appended_partition_2:all::\", // use appended partition 2 for EFI\n\t\t\t\"-append_partition\", \"2\", \"0xef\", efiBootImg,\n\t\t\t\"-partition_cyl_align\", // pad partition to cylinder boundary\n\t\t\t\"all\",\n\t\t\t\"-partition_offset\", \"16\", // support booting from USB\n\t\t\t\"-iso_mbr_part_type\", \"0x83\", // just to have more clear info when doing a fdisk -l\n\t\t\t\"-no-emul-boot\",\n\t\t\t\"-m\", \"efiboot.img\", // exclude the EFI boot image from the ISO\n\t\t\t\"-iso-level\", \"3\",\n\t\t\t\"-o\", options.OutPath,\n\t\t\toptions.ScratchDir,\n\t\t\t\"--\",\n\t\t},\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/out.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager\n\nimport (\n\t\"context\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/empty\"\n\t\"github.com/google/go-containerregistry/pkg/v1/mutate\"\n\t\"github.com/google/go-containerregistry/pkg/v1/tarball\"\n\t\"github.com/google/go-containerregistry/pkg/v1/types\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/cmd/installer/pkg/install\"\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/database\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n\t\"github.com/siderolabs/talos/pkg/imager/filemap\"\n\t\"github.com/siderolabs/talos/pkg/imager/iso\"\n\t\"github.com/siderolabs/talos/pkg/imager/ova\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/imager/qemuimg\"\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\nfunc (i *Imager) outInitramfs(path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"copying initramfs...\", Status: reporter.StatusRunning})\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(i.initramfsPath, path)); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{Message: \"initramfs output ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n\nfunc (i *Imager) outKernel(path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"copying kernel...\", Status: reporter.StatusRunning})\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(i.prof.Input.Kernel.Path, path)); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{Message: \"kernel output ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n\nfunc (i *Imager) outUKI(path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"copying kernel...\", Status: reporter.StatusRunning})\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(i.ukiPath, path)); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{Message: \"UKI output ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n\nfunc (i *Imager) outCmdline(path string) error {\n\treturn os.WriteFile(path, []byte(i.cmdline), 0o644)\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *Imager) outISO(ctx context.Context, path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"building ISO...\", Status: reporter.StatusRunning})\n\n\tscratchSpace := filepath.Join(i.tempDir, \"iso\")\n\n\tvar (\n\t\terr                error\n\t\tzeroContainerAsset profile.ContainerAsset\n\t)\n\n\tif i.prof.Input.ImageCache != zeroContainerAsset {\n\t\tif err := os.MkdirAll(filepath.Join(scratchSpace, \"imagecache\"), 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := i.prof.Input.ImageCache.Extract(ctx, filepath.Join(scratchSpace, \"imagecache\"), i.prof.Arch, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tvar generator iso.Generator\n\n\tswitch {\n\tcase i.prof.SecureBootEnabled():\n\t\tisoOptions := pointer.SafeDeref(i.prof.Output.ISOOptions)\n\n\t\tvar signer pesign.CertificateSigner\n\n\t\tsigner, err = i.prof.Input.SecureBoot.SecureBootSigner.GetSigner(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get SecureBoot signer: %w\", err)\n\t\t}\n\n\t\tderCrtPath := filepath.Join(i.tempDir, \"uki.der\")\n\n\t\tif err = os.WriteFile(derCrtPath, signer.Certificate().Raw, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write uki.der: %w\", err)\n\t\t}\n\n\t\toptions := iso.Options{\n\t\t\tUKIPath:    i.ukiPath,\n\t\t\tSDBootPath: i.sdBootPath,\n\n\t\t\tSDBootSecureBootEnrollKeys: isoOptions.SDBootEnrollKeys.String(),\n\n\t\t\tUKISigningCertDerPath: derCrtPath,\n\n\t\t\tPlatformKeyPath:    i.prof.Input.SecureBoot.PlatformKeyPath,\n\t\t\tKeyExchangeKeyPath: i.prof.Input.SecureBoot.KeyExchangeKeyPath,\n\t\t\tSignatureKeyPath:   i.prof.Input.SecureBoot.SignatureKeyPath,\n\n\t\t\tArch:    i.prof.Arch,\n\t\t\tVersion: i.prof.Version,\n\n\t\t\tScratchDir: scratchSpace,\n\t\t\tOutPath:    path,\n\t\t}\n\n\t\tif i.prof.Input.SecureBoot.PlatformKeyPath == \"\" {\n\t\t\treport.Report(reporter.Update{Message: \"generating SecureBoot database...\", Status: reporter.StatusRunning})\n\n\t\t\t// generate the database automatically from provided values\n\t\t\tenrolledPEM := pem.EncodeToMemory(&pem.Block{\n\t\t\t\tType:  \"CERTIFICATE\",\n\t\t\t\tBytes: signer.Certificate().Raw,\n\t\t\t})\n\n\t\t\tvar entries []database.Entry\n\n\t\t\tentries, err = database.Generate(enrolledPEM, signer, database.IncludeWellKnownCertificates(i.prof.Input.SecureBoot.IncludeWellKnownCerts))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to generate database: %w\", err)\n\t\t\t}\n\n\t\t\tfor _, entry := range entries {\n\t\t\t\tentryPath := filepath.Join(i.tempDir, entry.Name)\n\n\t\t\t\tif err = os.WriteFile(entryPath, entry.Contents, 0o600); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tswitch entry.Name {\n\t\t\t\tcase constants.PlatformKeyAsset:\n\t\t\t\t\toptions.PlatformKeyPath = entryPath\n\t\t\t\tcase constants.KeyExchangeKeyAsset:\n\t\t\t\t\toptions.KeyExchangeKeyPath = entryPath\n\t\t\t\tcase constants.SignatureKeyAsset:\n\t\t\t\t\toptions.SignatureKeyPath = entryPath\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unknown database entry: %s\", entry.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\toptions.PlatformKeyPath = i.prof.Input.SecureBoot.PlatformKeyPath\n\t\t\toptions.KeyExchangeKeyPath = i.prof.Input.SecureBoot.KeyExchangeKeyPath\n\t\t\toptions.SignatureKeyPath = i.prof.Input.SecureBoot.SignatureKeyPath\n\t\t}\n\n\t\tgenerator, err = options.CreateUEFI(ctx, printf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tcase quirks.New(i.prof.Version).ISOSupportsSettingBootloader():\n\t\toptions := iso.Options{\n\t\t\tKernelPath:    i.prof.Input.Kernel.Path,\n\t\t\tInitramfsPath: i.initramfsPath,\n\t\t\tCmdline:       i.cmdline,\n\n\t\t\tUKIPath:    i.ukiPath,\n\t\t\tSDBootPath: i.sdBootPath,\n\n\t\t\tSDBootSecureBootEnrollKeys: \"off\",\n\n\t\t\tArch:    i.prof.Arch,\n\t\t\tVersion: i.prof.Version,\n\n\t\t\tScratchDir: scratchSpace,\n\t\t\tOutPath:    path,\n\t\t}\n\n\t\tswitch i.prof.Output.ISOOptions.Bootloader {\n\t\tcase profile.BootLoaderKindDualBoot:\n\t\t\tgenerator, err = options.CreateHybrid(ctx, printf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase profile.BootLoaderKindSDBoot:\n\t\t\tgenerator, err = options.CreateUEFI(ctx, printf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase profile.BootLoaderKindGrub:\n\t\t\tgenerator, err = options.CreateGRUB(printf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase profile.BootLoaderKindNone:\n\t\t\treturn fmt.Errorf(\"cannot create ISO with no bootloader\")\n\t\t}\n\tcase quirks.New(i.prof.Version).UseSDBootForUEFI():\n\t\toptions := iso.Options{\n\t\t\tKernelPath:    i.prof.Input.Kernel.Path,\n\t\t\tInitramfsPath: i.initramfsPath,\n\t\t\tCmdline:       i.cmdline,\n\n\t\t\tUKIPath:    i.ukiPath,\n\t\t\tSDBootPath: i.sdBootPath,\n\n\t\t\tSDBootSecureBootEnrollKeys: \"off\",\n\n\t\t\tArch:    i.prof.Arch,\n\t\t\tVersion: i.prof.Version,\n\n\t\t\tScratchDir: scratchSpace,\n\t\t\tOutPath:    path,\n\t\t}\n\n\t\tgenerator, err = options.CreateHybrid(ctx, printf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\toptions := iso.Options{\n\t\t\tKernelPath:    i.prof.Input.Kernel.Path,\n\t\t\tInitramfsPath: i.initramfsPath,\n\t\t\tCmdline:       i.cmdline,\n\n\t\t\tArch:    i.prof.Arch,\n\t\t\tVersion: i.prof.Version,\n\n\t\t\tScratchDir: scratchSpace,\n\t\t\tOutPath:    path,\n\t\t}\n\n\t\tgenerator, err = options.CreateGRUB(printf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := generator.Generate(ctx); err != nil {\n\t\treturn err\n\t}\n\n\treport.Report(reporter.Update{Message: \"ISO ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n\nfunc (i *Imager) outImage(ctx context.Context, path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"creating disk image...\", Status: reporter.StatusRunning})\n\n\tif err := i.buildImage(ctx, path, printf); err != nil {\n\t\treturn err\n\t}\n\n\tswitch i.prof.Output.ImageOptions.DiskFormat {\n\tcase profile.DiskFormatRaw:\n\t\t// nothing to do\n\tcase profile.DiskFormatQCOW2:\n\t\tif err := qemuimg.Convert(ctx, \"raw\", \"qcow2\", i.prof.Output.ImageOptions.DiskFormatOptions, path, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase profile.DiskFormatVPC:\n\t\tif err := qemuimg.Convert(ctx, \"raw\", \"vpc\", i.prof.Output.ImageOptions.DiskFormatOptions, path, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase profile.DiskFormatOVA:\n\t\tscratchPath := filepath.Join(i.tempDir, \"ova\")\n\n\t\tif err := ova.CreateOVAFromRAW(ctx, path, i.prof.Arch, scratchPath, i.prof.Output.ImageOptions.DiskSize, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase profile.DiskFormatUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported disk format: %s\", i.prof.Output.ImageOptions.DiskFormat)\n\t}\n\n\treport.Report(reporter.Update{Message: \"disk image ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc (i *Imager) buildImage(ctx context.Context, path string, printf func(string, ...any)) error {\n\tvar zeroContainerAsset profile.ContainerAsset\n\n\tcmdline := procfs.NewCmdline(i.cmdline)\n\n\tscratchSpace := filepath.Join(i.tempDir, \"image\")\n\n\tmetaContents := slices.Clone(i.prof.Customization.MetaContents)\n\n\tif i.prof.Arch == \"amd64\" && !i.prof.SecureBootEnabled() && quirks.New(i.prof.Version).UseSDBootForUEFI() {\n\t\t// allow overriding the bootloader if provided\n\t\tif i.prof.Output.ImageOptions.Bootloader == profile.BootLoaderKindDualBoot {\n\t\t\tmetaContents = append(metaContents, meta.Value{\n\t\t\t\tKey:   meta.DiskImageBootloader,\n\t\t\t\tValue: profile.BootLoaderKindDualBoot.String(),\n\t\t\t})\n\t\t}\n\t}\n\n\topts := &install.Options{\n\t\tDiskPath:   path,\n\t\tPlatform:   i.prof.Platform,\n\t\tArch:       i.prof.Arch,\n\t\tMetaValues: install.FromMeta(metaContents),\n\n\t\tImageSecureboot:     i.prof.SecureBootEnabled(),\n\t\tDiskImageBootloader: i.prof.Output.ImageOptions.Bootloader.String(),\n\t\tVersion:             i.prof.Version,\n\t\tBootAssets: options.BootAssets{\n\t\t\tKernelPath:    i.prof.Input.Kernel.Path,\n\t\t\tInitramfsPath: i.initramfsPath,\n\t\t\tUKIPath:       i.ukiPath,\n\t\t\tSDBootPath:    i.sdBootPath,\n\t\t},\n\t\tMountPrefix: scratchSpace,\n\t\tPrintf:      printf,\n\t}\n\n\tif i.overlayInstaller != nil {\n\t\topts.OverlayInstaller = i.overlayInstaller\n\t\topts.ExtraOptions = i.prof.Overlay.ExtraOptions\n\t\topts.OverlayExtractedDir = i.tempDir\n\t}\n\n\tif i.prof.Input.ImageCache != zeroContainerAsset {\n\t\timageCacheDir := filepath.Join(i.tempDir, \"imagecache\")\n\n\t\tif err := os.MkdirAll(imageCacheDir, 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := i.prof.Input.ImageCache.Extract(ctx, imageCacheDir, i.prof.Arch, printf); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\topts.ImageCachePath = imageCacheDir\n\n\t\timageCacheSize, err := calculateDirectorySizeWithOverhead(imageCacheDir, 20)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to calculate image cache size: %w\", err)\n\t\t}\n\n\t\t// Align to a 1MiB boundary so both 512 and 4K sector sizes are covered.\n\t\t// miBMinusOne is a bit mask with all low bits set for a 1MiB boundary\n\t\t// (for 1MiB this is 0xFFFFF). Adding this mask and then clearing those\n\t\t// low bits with &^ effectively rounds imageCacheSize up to the next\n\t\t// multiple of 1MiB, while leaving already aligned sizes unchanged.\n\t\tmiBMinusOne := int64(1024*1024) - 1\n\t\timageCacheSize = (imageCacheSize + miBMinusOne) &^ miBMinusOne\n\n\t\topts.ImageCacheSize = imageCacheSize\n\n\t\tprintf(\"updating image size to accommodate image cache: +%s\", humanize.Bytes(uint64(imageCacheSize)))\n\n\t\ti.prof.Output.ImageOptions.DiskSize += imageCacheSize\n\t}\n\n\tif err := utils.CreateRawDisk(printf, path, i.prof.Output.ImageOptions.DiskSize, false); err != nil {\n\t\treturn err\n\t}\n\n\tinstaller, err := install.NewInstaller(ctx, cmdline, install.ModeImage, opts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create installer: %w\", err)\n\t}\n\n\tif err := installer.Install(ctx, install.ModeImage); err != nil {\n\t\treturn fmt.Errorf(\"failed to install: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc calculateDirectorySizeWithOverhead(dir string, overheadPercentage int) (int64, error) {\n\tvar totalSize int64\n\n\terr := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !info.IsDir() {\n\t\t\ttotalSize += info.Size()\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\toverhead := (totalSize * int64(overheadPercentage)) / 100\n\ttotalSize += overhead\n\n\treturn totalSize, nil\n}\n\n//nolint:gocyclo,cyclop\nfunc (i *Imager) outInstaller(ctx context.Context, path string, report *reporter.Reporter) error {\n\tprintf := progressPrintf(report, reporter.Update{Message: \"building installer...\", Status: reporter.StatusRunning})\n\n\tbaseInstallerImg, err := i.prof.Input.BaseInstaller.Pull(ctx, i.prof.Arch, printf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbaseLayers, err := baseInstallerImg.Layers()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get layers: %w\", err)\n\t}\n\n\tconfigFile, err := baseInstallerImg.ConfigFile()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get config file: %w\", err)\n\t}\n\n\tconfig := *configFile.Config.DeepCopy()\n\n\tprintf(\"creating empty image\")\n\n\tnewInstallerImg := mutate.MediaType(empty.Image, types.OCIManifestSchema1)\n\tnewInstallerImg = mutate.ConfigMediaType(newInstallerImg, types.OCIConfigJSON)\n\n\t// `empty.Image` won't error, so no need to check\n\tnewCfgFile, _ := empty.Image.ConfigFile() //nolint:errcheck\n\tnewCfgFile.Architecture = i.prof.Arch\n\tnewCfgFile.OS = \"linux\"\n\n\tnewInstallerImg, err = mutate.ConfigFile(newInstallerImg, newCfgFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set image architecture: %w\", err)\n\t}\n\n\tnewInstallerImg, err = mutate.Config(newInstallerImg, config)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set config: %w\", err)\n\t}\n\n\tnewInstallerImg, err = mutate.CreatedAt(newInstallerImg, v1.Time{Time: time.Now()})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to set created at: %w\", err)\n\t}\n\n\t// Talos v1.5+ optimizes the install layers to be easily replaceable with new artifacts\n\t// other Talos versions will have an overhead of artifacts being stored twice\n\tif len(baseLayers) == 2 {\n\t\t// optimized for installer image for artifacts replacements\n\t\tbaseLayers = baseLayers[:1]\n\t}\n\n\tnewInstallerImg, err = mutate.AppendLayers(newInstallerImg, baseLayers...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to append layers: %w\", err)\n\t}\n\n\tvar artifacts []filemap.File\n\n\tprintf(\"generating artifacts layer\")\n\n\tukiPath := strings.TrimLeft(fmt.Sprintf(constants.UKIAssetPath, i.prof.Arch), \"/\")\n\n\tquirks := quirks.New(i.prof.Version)\n\n\tif i.prof.SecureBootEnabled() && !quirks.UseSDBootForUEFI() {\n\t\tukiPath += \".signed\" // support for older secureboot installers\n\t}\n\n\tif quirks.UseSDBootForUEFI() || i.prof.SecureBootEnabled() {\n\t\tartifacts = append(artifacts,\n\t\t\tfilemap.File{\n\t\t\t\tImagePath:  strings.TrimLeft(fmt.Sprintf(constants.SDBootAssetPath, i.prof.Arch), \"/\"),\n\t\t\t\tSourcePath: i.sdBootPath,\n\t\t\t},\n\t\t\tfilemap.File{\n\t\t\t\tImagePath:  ukiPath,\n\t\t\t\tSourcePath: i.ukiPath,\n\t\t\t},\n\t\t)\n\t} else {\n\t\tartifacts = append(artifacts,\n\t\t\tfilemap.File{\n\t\t\t\tImagePath:  strings.TrimLeft(fmt.Sprintf(constants.KernelAssetPath, i.prof.Arch), \"/\"),\n\t\t\t\tSourcePath: i.prof.Input.Kernel.Path,\n\t\t\t},\n\t\t\tfilemap.File{\n\t\t\t\tImagePath:  strings.TrimLeft(fmt.Sprintf(constants.InitramfsAssetPath, i.prof.Arch), \"/\"),\n\t\t\t\tSourcePath: i.initramfsPath,\n\t\t\t},\n\t\t)\n\t}\n\n\tartifactsLayer, err := filemap.Layer(artifacts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create artifacts layer: %w\", err)\n\t}\n\n\tnewInstallerImg, err = mutate.AppendLayers(newInstallerImg, artifactsLayer)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to append artifacts layer: %w\", err)\n\t}\n\n\tif i.overlayInstaller != nil {\n\t\ttempOverlayPath := filepath.Join(i.tempDir, \"overlay-installer\", constants.ImagerOverlayBasePath)\n\n\t\tif err := os.MkdirAll(tempOverlayPath, 0o755); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create overlay directory: %w\", err)\n\t\t}\n\n\t\tif err := i.prof.Input.OverlayInstaller.Extract(\n\t\t\tctx,\n\t\t\ttempOverlayPath,\n\t\t\ti.prof.Arch,\n\t\t\tprogressPrintf(report, reporter.Update{Message: \"pulling overlay for installer...\", Status: reporter.StatusRunning}),\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\textraOpts, internalErr := yaml.Marshal(i.prof.Overlay.ExtraOptions)\n\t\tif internalErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to marshal extra options: %w\", internalErr)\n\t\t}\n\n\t\tif internalErr = os.WriteFile(filepath.Join(i.tempDir, constants.ImagerOverlayExtraOptionsPath), extraOpts, 0o644); internalErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to write extra options yaml: %w\", internalErr)\n\t\t}\n\n\t\tprintf(\"generating overlay installer layer\")\n\n\t\tvar overlayArtifacts []filemap.File\n\n\t\tfor _, extraArtifact := range []struct {\n\t\t\tsourcePath string\n\t\t\timagePath  string\n\t\t}{\n\t\t\t{\n\t\t\t\tsourcePath: filepath.Join(i.tempDir, \"overlay-installer\", constants.ImagerOverlayArtifactsPath),\n\t\t\t\timagePath:  strings.TrimLeft(constants.ImagerOverlayArtifactsPath, \"/\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tsourcePath: filepath.Join(i.tempDir, \"overlay-installer\", constants.ImagerOverlayInstallersPath, i.prof.Overlay.Name),\n\t\t\t\timagePath:  strings.TrimLeft(constants.ImagerOverlayInstallerDefaultPath, \"/\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tsourcePath: filepath.Join(i.tempDir, constants.ImagerOverlayExtraOptionsPath),\n\t\t\t\timagePath:  strings.TrimLeft(constants.ImagerOverlayExtraOptionsPath, \"/\"),\n\t\t\t},\n\t\t} {\n\t\t\tvar extraFiles []filemap.File\n\n\t\t\textraFiles, err = filemap.Walk(extraArtifact.sourcePath, extraArtifact.imagePath)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to walk extra artifact %s: %w\", extraArtifact.sourcePath, err)\n\t\t\t}\n\n\t\t\toverlayArtifacts = append(overlayArtifacts, extraFiles...)\n\t\t}\n\n\t\toverlayArtifactsLayer, internalErr := filemap.Layer(overlayArtifacts)\n\t\tif internalErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to create overlay artifacts layer: %w\", internalErr)\n\t\t}\n\n\t\tnewInstallerImg, internalErr = mutate.AppendLayers(newInstallerImg, overlayArtifactsLayer)\n\t\tif internalErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to append overlay artifacts layer: %w\", internalErr)\n\t\t}\n\t}\n\n\tref, err := name.ParseReference(i.prof.Input.BaseInstaller.ImageRef)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse image reference: %w\", err)\n\t}\n\n\tprintf(\"writing image tarball\")\n\n\tif err := tarball.WriteToFile(path, ref, newInstallerImg); err != nil {\n\t\treturn fmt.Errorf(\"failed to write image tarball: %w\", err)\n\t}\n\n\treport.Report(reporter.Update{Message: \"installer container image ready\", Status: reporter.StatusSucceeded})\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/ova/ova.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ova implements OVA creation.\npackage ova\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/imager/vmdkconvert\"\n)\n\nconst mfTpl = `SHA256({{ .VMDK }})= {{ .VMDKSHA }}\nSHA256({{ .OVF }})= {{ .OVFSHA }}\n`\n\n// OVF format reference: https://www.dmtf.org/standards/ovf.\n//\n//nolint:lll\nconst ovfTpl = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--Generated by VMware ovftool 4.3.0 (build-7948156), UTC time: 2019-10-31T01:41:10.540841Z-->\n<!-- Edited by Talos -->\n<Envelope vmw:buildId=\"build-7948156\" xmlns=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:cim=\"http://schemas.dmtf.org/wbem/wscim/1/common\" xmlns:ovf=\"http://schemas.dmtf.org/ovf/envelope/1\" xmlns:rasd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData\" xmlns:vmw=\"http://www.vmware.com/schema/ovf\" xmlns:vssd=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <References>\n    <File ovf:href=\"{{ .VMDK }}\" ovf:id=\"file1\" ovf:size=\"{{ .Size }}\"/>\n  </References>\n  <DiskSection>\n    <Info>Virtual disk information</Info>\n    <Disk ovf:capacity=\"{{ .Capacity }}\" ovf:capacityAllocationUnits=\"byte * 2^20\" ovf:diskId=\"vmdisk1\" ovf:fileRef=\"file1\" ovf:format=\"http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized\"/>\n  </DiskSection>\n  <NetworkSection>\n    <Info>The list of logical networks</Info>\n    <Network ovf:name=\"VM Network\">\n      <Description>The VM Network network</Description>\n    </Network>\n  </NetworkSection>\n  <VirtualSystem ovf:id=\"vm\">\n    <Info>A virtual machine</Info>\n    <Name>talos</Name>\n    <ProductSection ovf:required=\"false\">\n      <Info>Talos Virtual Appliance</Info>\n      <Property ovf:userConfigurable=\"true\" ovf:type=\"string\"\n                ovf:key=\"talos.config\" ovf:value=\"\">\n        <Label>Talos config data</Label>\n        <Description>Inline Talos config</Description>\n      </Property>\n    </ProductSection>\n    <OperatingSystemSection ovf:id=\"101\" vmw:osType=\"other3xLinux64Guest\">\n      <Info>The kind of installed guest operating system</Info>\n    </OperatingSystemSection>\n    <VirtualHardwareSection ovf:transport=\"com.vmware.guestInfo\">\n      <Info>Virtual hardware requirements</Info>\n      <System>\n        <vssd:ElementName>Virtual Hardware Family</vssd:ElementName>\n        <vssd:InstanceID>0</vssd:InstanceID>\n        <vssd:VirtualSystemIdentifier>talos</vssd:VirtualSystemIdentifier>\n        <vssd:VirtualSystemType>vmx-15</vssd:VirtualSystemType>\n      </System>\n      <Item>\n        <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>\n        <rasd:Description>Number of Virtual CPUs</rasd:Description>\n        <rasd:ElementName>2 virtual CPU(s)</rasd:ElementName>\n        <rasd:InstanceID>1</rasd:InstanceID>\n        <rasd:ResourceType>3</rasd:ResourceType>\n        <rasd:VirtualQuantity>2</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>\n        <rasd:Description>Memory Size</rasd:Description>\n        <rasd:ElementName>2048MB of memory</rasd:ElementName>\n        <rasd:InstanceID>2</rasd:InstanceID>\n        <rasd:ResourceType>4</rasd:ResourceType>\n        <rasd:VirtualQuantity>2048</rasd:VirtualQuantity>\n      </Item>\n      <Item>\n        <rasd:Address>0</rasd:Address>\n        <rasd:Description>SCSI Controller</rasd:Description>\n        <rasd:ElementName>scsiController0</rasd:ElementName>\n        <rasd:InstanceID>3</rasd:InstanceID>\n        <rasd:ResourceSubType>VirtualSCSI</rasd:ResourceSubType>\n        <rasd:ResourceType>6</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>0</rasd:AddressOnParent>\n        <rasd:ElementName>disk0</rasd:ElementName>\n        <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>\n        <rasd:InstanceID>4</rasd:InstanceID>\n        <rasd:Parent>3</rasd:Parent>\n        <rasd:ResourceType>17</rasd:ResourceType>\n      </Item>\n      <Item>\n        <rasd:AddressOnParent>2</rasd:AddressOnParent>\n        <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>\n        <rasd:Connection>VM Network</rasd:Connection>\n        <rasd:Description>VmxNet3 ethernet adapter on &quot;VM Network&quot;</rasd:Description>\n        <rasd:ElementName>ethernet0</rasd:ElementName>\n        <rasd:InstanceID>5</rasd:InstanceID>\n        <rasd:ResourceSubType>VmxNet3</rasd:ResourceSubType>\n        <rasd:ResourceType>10</rasd:ResourceType>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"slotInfo.pciSlotNumber\" vmw:value=\"32\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"wakeOnLanEnabled\" vmw:value=\"false\"/>\n        <vmw:Config ovf:required=\"false\" vmw:key=\"connectable.allowGuestControl\" vmw:value=\"false\"/>\n      </Item>\n      <Item ovf:required=\"false\">\n        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n        <rasd:ElementName>video</rasd:ElementName>\n        <rasd:InstanceID>6</rasd:InstanceID>\n        <rasd:ResourceType>24</rasd:ResourceType>\n      </Item>\n      <Item ovf:required=\"false\">\n        <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>\n        <rasd:ElementName>vmci</rasd:ElementName>\n        <rasd:InstanceID>7</rasd:InstanceID>\n        <rasd:ResourceSubType>vmware.vmci</rasd:ResourceSubType>\n        <rasd:ResourceType>1</rasd:ResourceType>\n      </Item>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.syncTimeWithHost\" vmw:value=\"false\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.afterPowerOn\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.afterResume\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.beforeGuestShutdown\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.beforeGuestStandby\" vmw:value=\"true\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"tools.toolsUpgradePolicy\" vmw:value=\"manual\"/>\n      <vmw:Config ovf:required=\"false\" vmw:key=\"powerOpInfo.suspendType\" vmw:value=\"soft\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"nvram\" vmw:value=\"talos.nvram\"/>\n      <vmw:ExtraConfig ovf:required=\"false\" vmw:key=\"disk.EnableUUID\" vmw:value=\"true\"/>\n    </VirtualHardwareSection>\n  </VirtualSystem>\n</Envelope>\n`\n\n// CreateOVAFromRAW creates an OVA from a RAW disk.\n//\n//nolint:gocyclo\nfunc CreateOVAFromRAW(ctx context.Context, outPath, arch, scratchPath string, diskSize int64, printf func(string, ...any)) error {\n\tif err := os.MkdirAll(scratchPath, 0o755); err != nil {\n\t\treturn err\n\t}\n\n\tvmdkPath := filepath.Join(scratchPath, \"disk.vmdk\")\n\n\tif err := utils.CopyFiles(printf, utils.SourceDestination(outPath, vmdkPath)); err != nil {\n\t\treturn err\n\t}\n\n\tif err := vmdkconvert.ConvertToStreamOptimizedVMDK(ctx, vmdkPath, printf); err != nil {\n\t\treturn err\n\t}\n\n\tf, err := os.Stat(vmdkPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\timageSize := f.Size()\n\n\tovf, err := renderOVF(imageSize, diskSize)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tinput, err := os.Open(vmdkPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer input.Close() //nolint:errcheck\n\n\tvmdkSHA25Sum, err := sha256sum(input)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tovfSHA25Sum, err := sha256sum(strings.NewReader(ovf))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmf, err := renderMF(vmdkSHA25Sum, ovfSHA25Sum)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(filepath.Join(scratchPath, \"disk.mf\"), []byte(mf), 0o666); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(filepath.Join(scratchPath, \"disk.ovf\"), []byte(ovf), 0o666); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err = cmd.RunWithOptions(ctx, \"tar\", []string{\"-cvf\", outPath, \"-C\", scratchPath, \"disk.ovf\", \"disk.mf\", \"disk.vmdk\"}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc sha256sum(input io.Reader) (string, error) {\n\thash := sha256.New()\n\n\tif _, err := io.Copy(hash, input); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsum := hash.Sum(nil)\n\n\treturn hex.EncodeToString(sum), nil\n}\n\nfunc renderMF(vmdkSHA25Sum, ovfSHA25Sum string) (string, error) {\n\tcfg := struct {\n\t\tVMDK    string\n\t\tVMDKSHA string\n\t\tOVF     string\n\t\tOVFSHA  string\n\t}{\n\t\tVMDK:    \"disk.vmdk\",\n\t\tVMDKSHA: vmdkSHA25Sum,\n\t\tOVF:     \"disk.ovf\",\n\t\tOVFSHA:  ovfSHA25Sum,\n\t}\n\n\ttempl := template.Must(template.New(\"mf\").Parse(mfTpl))\n\n\tvar buf bytes.Buffer\n\n\tif err := templ.Execute(&buf, cfg); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn buf.String(), nil\n}\n\nfunc renderOVF(imageSize, diskSize int64) (string, error) {\n\tcfg := struct {\n\t\tVMDK     string\n\t\tSize     int64\n\t\tCapacity int64\n\t}{\n\t\tVMDK:     \"disk.vmdk\",\n\t\tSize:     imageSize,\n\t\tCapacity: diskSize / (1 << 20),\n\t}\n\n\ttempl := template.Must(template.New(\"ovf\").Parse(ovfTpl))\n\n\tvar buf bytes.Buffer\n\n\tif err := templ.Execute(&buf, cfg); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn buf.String(), nil\n}\n"
  },
  {
    "path": "pkg/imager/overlay/executor/executor.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package executor implements overlay.Installer\npackage executor\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os/exec\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n)\n\nvar _ overlay.Installer[overlay.ExtraOptions] = (*Options)(nil)\n\n// Options executor options.\ntype Options struct {\n\tcommandPath string\n}\n\n// New returns a new overlay installer executor.\nfunc New(commandPath string) *Options {\n\treturn &Options{\n\t\tcommandPath: commandPath,\n\t}\n}\n\n// GetOptions returns the options for the overlay installer.\nfunc (o *Options) GetOptions(ctx context.Context, extra overlay.ExtraOptions) (overlay.Options, error) {\n\t// parse extra as yaml\n\textraYAML, err := yaml.Marshal(extra)\n\tif err != nil {\n\t\treturn overlay.Options{}, fmt.Errorf(\"failed to marshal extra: %w\", err)\n\t}\n\n\tout, err := o.execute(ctx, bytes.NewReader(extraYAML), \"get-options\")\n\tif err != nil {\n\t\treturn overlay.Options{}, err\n\t}\n\n\tvar options overlay.Options\n\n\tif err := yaml.Unmarshal(out, &options); err != nil {\n\t\treturn overlay.Options{}, fmt.Errorf(\"failed to unmarshal overlay options: %w\", err)\n\t}\n\n\treturn options, nil\n}\n\n// Install installs the overlay.\nfunc (o *Options) Install(ctx context.Context, options overlay.InstallOptions[overlay.ExtraOptions]) error {\n\toptionsBytes, err := yaml.Marshal(&options)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal options: %w\", err)\n\t}\n\n\tif _, err := o.execute(ctx, bytes.NewReader(optionsBytes), \"install\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (o *Options) execute(ctx context.Context, stdin io.Reader, args ...string) ([]byte, error) {\n\tcmd := exec.CommandContext(ctx, o.commandPath, args...)\n\tcmd.Stdin = stdin\n\n\tvar stdOut, stdErr bytes.Buffer\n\n\tcmd.Stdout = &stdOut\n\tcmd.Stderr = &stdErr\n\n\tif err := cmd.Run(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to run overlay installer: %w, stdErr: %s\", err, stdErr.Bytes())\n\t}\n\n\treturn stdOut.Bytes(), nil\n}\n"
  },
  {
    "path": "pkg/imager/post.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n//nolint:gocyclo\nfunc (i *Imager) postProcessTar(ctx context.Context, filename string, report *reporter.Reporter) (string, error) {\n\treport.Report(reporter.Update{Message: \"processing .tar.gz\", Status: reporter.StatusRunning})\n\n\tdir := filepath.Dir(filename)\n\tsrc := \"disk.raw\"\n\n\tif err := os.Rename(filename, filepath.Join(dir, src)); err != nil {\n\t\treturn \"\", err\n\t}\n\n\toutPath := filename + \".tar.gz\"\n\n\tpipeR, pipeW, err := os.Pipe()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\ttimestamp, ok, err := utils.SourceDateEpoch()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to get SOURCE_DATE_EPOCH: %w\", err)\n\t}\n\n\tif !ok {\n\t\ttimestamp = time.Now().Unix()\n\t}\n\n\tcmd1 := exec.CommandContext(\n\t\tctx,\n\t\t\"tar\",\n\t\t\"-cvf\",\n\t\t\"-\",\n\t\t\"-C\",\n\t\tdir,\n\t\t\"--sparse\",\n\t\t\"--sort=name\",\n\t\t\"--owner=0\",\n\t\t\"--group=0\",\n\t\t\"--numeric-owner\",\n\t\t\"--mtime=@\"+strconv.FormatInt(timestamp, 10),\n\t\tsrc,\n\t)\n\n\tcmd1.Stdout = pipeW\n\tcmd1.Stderr = os.Stderr\n\n\tif err := cmd1.Start(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = pipeW.Close(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdestination, err := os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer destination.Close() //nolint:errcheck\n\n\tcmd2 := exec.CommandContext(ctx, \"pigz\", \"-6\", \"-f\", \"--no-time\", \"-\")\n\tcmd2.Stdin = pipeR\n\tcmd2.Stdout = destination\n\tcmd2.Stderr = os.Stderr\n\n\tif err := cmd2.Start(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = pipeR.Close(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\terrCh := make(chan error, 1)\n\n\tgo func() {\n\t\terrCh <- cmd1.Wait()\n\t}()\n\n\tgo func() {\n\t\terrCh <- cmd2.Wait()\n\t}()\n\n\tfor range 2 {\n\t\tif err = <-errCh; err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\tif err := destination.Sync(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err := os.Remove(filepath.Join(dir, src)); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{Message: fmt.Sprintf(\"archive is ready: %s\", outPath), Status: reporter.StatusSucceeded})\n\n\treturn outPath, nil\n}\n\nfunc (i *Imager) postProcessGz(ctx context.Context, filename string, report *reporter.Reporter) (string, error) {\n\treport.Report(reporter.Update{Message: \"compressing .gz\", Status: reporter.StatusRunning})\n\n\tif _, err := cmd.RunWithOptions(ctx, \"pigz\", []string{\"-6\", \"--no-time\", \"-f\", filename}); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{Message: fmt.Sprintf(\"compression done: %s.gz\", filename), Status: reporter.StatusSucceeded})\n\n\treturn filename + \".gz\", nil\n}\n\nfunc (i *Imager) postProcessXz(ctx context.Context, filename string, report *reporter.Reporter) (string, error) {\n\treport.Report(reporter.Update{Message: \"compressing .xz\", Status: reporter.StatusRunning})\n\n\tif _, err := cmd.RunWithOptions(ctx, \"xz\", []string{\"-0\", \"-f\", \"-T\", \"0\", filename}); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{Message: fmt.Sprintf(\"compression done: %s.xz\", filename), Status: reporter.StatusSucceeded})\n\n\treturn filename + \".xz\", nil\n}\n\nfunc (i *Imager) postProcessZstd(ctx context.Context, filename string, report *reporter.Reporter) (string, error) {\n\treport.Report(reporter.Update{Message: \"compressing .zst\", Status: reporter.StatusRunning})\n\n\tout := filename + \".zst\"\n\n\tif _, err := cmd.RunWithOptions(ctx, \"zstd\", []string{\"-T0\", \"--rm\", \"-18\", \"--quiet\", \"--force\", \"-o\", out, filename}); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treport.Report(reporter.Update{Message: fmt.Sprintf(\"compression done: %s\", out), Status: reporter.StatusSucceeded})\n\n\treturn filename + \".zst\", nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/customization.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n)\n\n// CustomizationProfile describes customizations that can be applied to the image.\ntype CustomizationProfile struct {\n\t// ExtraKernelArgs is a list of extra kernel arguments.\n\tExtraKernelArgs []string `yaml:\"extraKernelArgs,omitempty\"`\n\t// MetaContents is a list of META partition contents.\n\tMetaContents meta.Values `yaml:\"metaContents,omitempty\"`\n\t// EmbeddedMachineConfiguration is the machine configuration to embed into the image.\n\tEmbeddedMachineConfiguration string `yaml:\"embeddedMachineConfiguration,omitempty\"`\n}\n"
  },
  {
    "path": "pkg/imager/profile/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type Profile -type SecureBootAssets -header-file ../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage profile\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n)\n\n// DeepCopy generates a deep copy of Profile.\nfunc (o Profile) DeepCopy() Profile {\n\tvar cp Profile = o\n\tif o.SecureBoot != nil {\n\t\tcp.SecureBoot = new(bool)\n\t\t*cp.SecureBoot = *o.SecureBoot\n\t}\n\tif o.Customization.ExtraKernelArgs != nil {\n\t\tcp.Customization.ExtraKernelArgs = make([]string, len(o.Customization.ExtraKernelArgs))\n\t\tcopy(cp.Customization.ExtraKernelArgs, o.Customization.ExtraKernelArgs)\n\t}\n\tif o.Customization.MetaContents != nil {\n\t\tcp.Customization.MetaContents = make([]meta.Value, len(o.Customization.MetaContents))\n\t\tcopy(cp.Customization.MetaContents, o.Customization.MetaContents)\n\t}\n\tif o.Input.SecureBoot != nil {\n\t\tretV := o.Input.SecureBoot.DeepCopy()\n\t\tcp.Input.SecureBoot = &retV\n\t}\n\tif o.Input.SystemExtensions != nil {\n\t\tcp.Input.SystemExtensions = make([]ContainerAsset, len(o.Input.SystemExtensions))\n\t\tcopy(cp.Input.SystemExtensions, o.Input.SystemExtensions)\n\t}\n\tif o.Overlay != nil {\n\t\tcp.Overlay = new(OverlayOptions)\n\t\t*cp.Overlay = *o.Overlay\n\t\tif o.Overlay.ExtraOptions != nil {\n\t\t\tcp.Overlay.ExtraOptions = make(map[string]any, len(o.Overlay.ExtraOptions))\n\t\t\tfor k4, v4 := range o.Overlay.ExtraOptions {\n\t\t\t\tcp.Overlay.ExtraOptions[k4] = v4\n\t\t\t}\n\t\t}\n\t}\n\tif o.Output.ImageOptions != nil {\n\t\tcp.Output.ImageOptions = new(ImageOptions)\n\t\t*cp.Output.ImageOptions = *o.Output.ImageOptions\n\t}\n\tif o.Output.ISOOptions != nil {\n\t\tcp.Output.ISOOptions = new(ISOOptions)\n\t\t*cp.Output.ISOOptions = *o.Output.ISOOptions\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SecureBootAssets.\nfunc (o SecureBootAssets) DeepCopy() SecureBootAssets {\n\tvar cp SecureBootAssets = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/imager/profile/default.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tmib = 1024 * 1024\n\n\t// MinRAWDiskSize is the minimum size disk we can create. Used for metal images.\n\tMinRAWDiskSize = 1246 * mib\n\n\t// DefaultRAWDiskSize is the value we use for any non-metal images by default.\n\tDefaultRAWDiskSize = 8192 * mib\n)\n\n// Default describes built-in profiles.\nvar Default = map[string]Profile{\n\t// ISO\n\t\"iso\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindISO,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t},\n\t},\n\t\"secureboot-iso\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(true),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindISO,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t\tISOOptions: &ISOOptions{\n\t\t\t\tSDBootEnrollKeys: SDBootEnrollKeysIfSafe,\n\t\t\t},\n\t\t},\n\t},\n\t// Metal images\n\t\"metal\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"metal-uki\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindUKI,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t},\n\t},\n\t\"secureboot-metal-uki\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(true),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindUKI,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t},\n\t},\n\t\"secureboot-metal\": {\n\t\tPlatform:   constants.PlatformMetal,\n\t\tSecureBoot: new(true),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"installer\": {\n\t\tPlatform:   \"metal\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindInstaller,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t},\n\t},\n\t\"secureboot-installer\": {\n\t\tPlatform:   \"metal\",\n\t\tSecureBoot: new(true),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindInstaller,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t},\n\t},\n\t// Clouds\n\t\"akamai\": {\n\t\tPlatform:   \"akamai\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatGZ,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"aws\": {\n\t\tPlatform:   \"aws\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"azure\": {\n\t\tPlatform:   \"azure\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:          DefaultRAWDiskSize,\n\t\t\t\tDiskFormat:        DiskFormatVPC,\n\t\t\t\tDiskFormatOptions: \"subformat=fixed,force_size\",\n\t\t\t},\n\t\t},\n\t},\n\t\"cloudstack\": {\n\t\tPlatform:   \"cloudstack\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"digital-ocean\": {\n\t\tPlatform:   \"digital-ocean\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatGZ,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"exoscale\": {\n\t\tPlatform:   \"exoscale\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:          10 * 1024 * mib,\n\t\t\t\tDiskFormat:        DiskFormatQCOW2,\n\t\t\t\tDiskFormatOptions: \"cluster_size=8k\",\n\t\t\t},\n\t\t},\n\t},\n\t\"gcp\": {\n\t\tPlatform:   \"gcp\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatTar,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"hcloud\": {\n\t\tPlatform:   \"hcloud\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"nocloud\": {\n\t\tPlatform:   \"nocloud\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"opennebula\": {\n\t\tPlatform:   \"opennebula\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"openstack\": {\n\t\tPlatform:   \"openstack\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"oracle\": {\n\t\tPlatform:   \"oracle\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:          DefaultRAWDiskSize,\n\t\t\t\tDiskFormat:        DiskFormatQCOW2,\n\t\t\t\tDiskFormatOptions: \"cluster_size=8k\",\n\t\t\t},\n\t\t},\n\t},\n\t\"scaleway\": {\n\t\tPlatform:   \"scaleway\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   MinRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"upcloud\": {\n\t\tPlatform:   \"upcloud\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n\t\"vmware\": {\n\t\tPlatform:   \"vmware\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatRaw,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatOVA,\n\t\t\t},\n\t\t},\n\t},\n\t\"vultr\": {\n\t\tPlatform:   \"vultr\",\n\t\tSecureBoot: new(false),\n\t\tOutput: Output{\n\t\t\tKind:      OutKindImage,\n\t\t\tOutFormat: OutFormatZSTD,\n\t\t\tImageOptions: &ImageOptions{\n\t\t\t\tDiskSize:   DefaultRAWDiskSize,\n\t\t\t\tDiskFormat: DiskFormatRaw,\n\t\t\t},\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "pkg/imager/profile/input.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/google/go-containerregistry/pkg/authn\"\n\t\"github.com/google/go-containerregistry/pkg/authn/github\"\n\t\"github.com/google/go-containerregistry/pkg/crane\"\n\tv1 \"github.com/google/go-containerregistry/pkg/v1\"\n\t\"github.com/google/go-containerregistry/pkg/v1/google\"\n\t\"github.com/google/go-containerregistry/pkg/v1/layout\"\n\t\"github.com/siderolabs/gen/value\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n\t\"github.com/siderolabs/talos/pkg/archiver\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile/internal/signer/aws\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile/internal/signer/azure\"\n\t\"github.com/siderolabs/talos/pkg/imager/profile/internal/signer/file\"\n\t\"github.com/siderolabs/talos/pkg/images\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nconst (\n\tarm64 = \"arm64\"\n\tamd64 = \"amd64\"\n)\n\n// Input describes inputs for image generation.\ntype Input struct {\n\t// Kernel is a vmlinuz file.\n\tKernel FileAsset `yaml:\"kernel\"`\n\t// Initramfs is a initramfs file (without system extensions).\n\tInitramfs FileAsset `yaml:\"initramfs\"`\n\t// SDStub is a sd-stub file (only for SecureBoot).\n\tSDStub FileAsset `yaml:\"sdStub,omitempty\"`\n\t// SDBoot is a sd-boot file (only for SecureBoot).\n\tSDBoot FileAsset `yaml:\"sdBoot,omitempty\"`\n\t// Base installer image to mutate.\n\tBaseInstaller ContainerAsset `yaml:\"baseInstaller,omitempty\"`\n\t// ImageCache is an image cache to inject into the asset.\n\tImageCache ContainerAsset `yaml:\"imageCache,omitempty\"`\n\t// OverlayInstaller is an overlay image to inject into the installer.\n\t//\n\t// OverlayInstaller architecture should match the output installer architecture.\n\tOverlayInstaller ContainerAsset `yaml:\"overlayInstaller,omitempty\"`\n\t// SecureBoot is a section with secureboot keys, only for SecureBoot enabled builds.\n\tSecureBoot *SecureBootAssets `yaml:\"secureboot,omitempty\"`\n\t// SystemExtensions is a list of system extensions to install.\n\tSystemExtensions []ContainerAsset `yaml:\"systemExtensions,omitempty\"`\n}\n\n// FileAsset describes a file asset.\ntype FileAsset struct {\n\t// Path to the file.\n\tPath string `yaml:\"path\"`\n}\n\n// ContainerAsset describes a container asset.\ntype ContainerAsset struct {\n\t// ImageRef is a reference to the container image.\n\tImageRef string `yaml:\"imageRef\"`\n\t// ForceInsecure forces insecure registry communication.\n\tForceInsecure bool `yaml:\"forceInsecure,omitempty\"`\n\t// TarballPath is a path to the .tar format container image contents.\n\t//\n\t// If TarballPath is set, ImageRef is ignored.\n\tTarballPath string `yaml:\"tarballPath,omitempty\"`\n\t// OCIPath is a path to the OCI format container image contents.\n\t//\n\t// If OCIPath is set, ImageRef is ignored.\n\tOCIPath string `yaml:\"ociPath,omitempty\"`\n}\n\n// SecureBootAssets describes secureboot assets.\ntype SecureBootAssets struct {\n\t// SecureBoot signing key & cert.\n\tSecureBootSigner SigningKeyAndCertificate `yaml:\"secureBootSigner\"`\n\t// PCR signing key.\n\tPCRSigner SigningKey `yaml:\"pcrSigner\"`\n\t// Optional, auto-enrollment paths.\n\tPlatformKeyPath    string `yaml:\"platformKeyPath,omitempty\"`\n\tKeyExchangeKeyPath string `yaml:\"keyExchangeKeyPath,omitempty\"`\n\tSignatureKeyPath   string `yaml:\"signatureKeyPath,omitempty\"`\n\t// Optional, auto-enrollment include well-known UEFI (Microsoft) certs.\n\tIncludeWellKnownCerts bool `yaml:\"includeWellKnownCerts,omitempty\"`\n}\n\n// SigningKeyAndCertificate describes a signing key & certificate.\ntype SigningKeyAndCertificate struct {\n\t// File-based.\n\t//\n\t// Static key and certificate paths.\n\tKeyPath  string `yaml:\"keyPath,omitempty\"`\n\tCertPath string `yaml:\"certPath,omitempty\"`\n\t// Azure.\n\t//\n\t// Azure Vault URL and certificate ID, key will be found from the certificate.\n\tAzureVaultURL      string `yaml:\"azureVaultURL,omitempty\"`\n\tAzureCertificateID string `yaml:\"azureCertificateID,omitempty\"`\n\t// AWS.\n\t//\n\t// AWS KMS Key ID, ACM certificate ARN, and region.\n\t// Support local cert file for legacy use cases.\n\tAwsKMSKeyID string `yaml:\"awsKMSKeyID,omitempty\"`\n\tAwsRegion   string `yaml:\"awsRegion,omitempty\"`\n\tAwsCertPath string `yaml:\"awsCertPath,omitempty\"`\n\tAwsCertARN  string `yaml:\"awsCertARN,omitempty\"`\n}\n\n// SigningKey describes a signing key.\ntype SigningKey struct {\n\t// File-based.\n\t//\n\t// Static key path.\n\tKeyPath string `yaml:\"keyPath,omitempty\"`\n\t// Azure.\n\t//\n\t// Azure Vault URL and key ID.\n\t// AzureKeyVersion might be left empty to use the latest key version.\n\tAzureVaultURL   string `yaml:\"azureVaultURL,omitempty\"`\n\tAzureKeyID      string `yaml:\"azureKeyID,omitempty\"`\n\tAzureKeyVersion string `yaml:\"azureKeyVersion,omitempty\"`\n\t// AWS.\n\t//\n\t// AWS KMS Key ID and region.\n\tAwsKMSKeyID string `yaml:\"awsKMSKeyID,omitempty\"`\n\tAwsRegion   string `yaml:\"awsRegion,omitempty\"`\n}\n\n// GetSigner returns the signer.\nfunc (key SigningKey) GetSigner(ctx context.Context) (measure.RSAKey, error) {\n\tswitch {\n\tcase key.KeyPath != \"\":\n\t\treturn file.NewPCRSigner(key.KeyPath)\n\tcase key.AzureVaultURL != \"\" && key.AzureKeyID != \"\":\n\t\treturn azure.NewPCRSigner(ctx, key.AzureVaultURL, key.AzureKeyID, key.AzureKeyVersion)\n\tcase key.AwsKMSKeyID != \"\":\n\t\treturn aws.NewPCRSigner(ctx, key.AwsKMSKeyID, key.AwsRegion)\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported PCR signer\")\n\t}\n}\n\n// GetSigner returns the signer.\nfunc (keyAndCert SigningKeyAndCertificate) GetSigner(ctx context.Context) (pesign.CertificateSigner, error) {\n\tswitch {\n\tcase keyAndCert.KeyPath != \"\" && keyAndCert.CertPath != \"\":\n\t\treturn file.NewSecureBootSigner(keyAndCert.CertPath, keyAndCert.KeyPath)\n\tcase keyAndCert.AzureVaultURL != \"\" && keyAndCert.AzureCertificateID != \"\":\n\t\treturn azure.NewSecureBootSigner(ctx, keyAndCert.AzureVaultURL, keyAndCert.AzureCertificateID, keyAndCert.AzureCertificateID)\n\tcase keyAndCert.AwsKMSKeyID != \"\" && keyAndCert.AwsCertARN != \"\":\n\t\treturn aws.NewSecureBootACMSigner(ctx, keyAndCert.AwsKMSKeyID, keyAndCert.AwsRegion, keyAndCert.AwsCertARN)\n\tcase keyAndCert.AwsKMSKeyID != \"\" && keyAndCert.AwsCertPath != \"\":\n\t\treturn aws.NewSecureBootSigner(ctx, keyAndCert.AwsKMSKeyID, keyAndCert.AwsRegion, keyAndCert.AwsCertPath)\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported PCR signer\")\n\t}\n}\n\nconst defaultSecureBootPrefix = \"/secureboot\"\n\n// FillDefaults fills default values for the input.\n//\n//nolint:gocyclo,cyclop\nfunc (i *Input) FillDefaults(arch, version string, secureboot bool) {\n\tvar (\n\t\tzeroFileAsset      FileAsset\n\t\tzeroContainerAsset ContainerAsset\n\t)\n\n\tif i.Kernel == zeroFileAsset {\n\t\ti.Kernel.Path = fmt.Sprintf(constants.KernelAssetPath, arch)\n\t}\n\n\tif i.Initramfs == zeroFileAsset {\n\t\ti.Initramfs.Path = fmt.Sprintf(constants.InitramfsAssetPath, arch)\n\t}\n\n\tif i.BaseInstaller == zeroContainerAsset {\n\t\ti.BaseInstaller.ImageRef = fmt.Sprintf(\"%s:%s\", images.DefaultInstallerImageRepository, version)\n\n\t\tif quirks.New(version).SupportsUnifiedInstaller() {\n\t\t\ti.BaseInstaller.ImageRef = fmt.Sprintf(\"%s-base:%s\", images.DefaultInstallerImageRepository, version)\n\t\t}\n\t}\n\n\tif i.SDStub == zeroFileAsset {\n\t\ti.SDStub.Path = fmt.Sprintf(constants.SDStubAssetPath, arch)\n\t}\n\n\tif i.SDBoot == zeroFileAsset {\n\t\ti.SDBoot.Path = fmt.Sprintf(constants.SDBootAssetPath, arch)\n\t}\n\n\tif secureboot {\n\t\tif i.SecureBoot == nil {\n\t\t\ti.SecureBoot = &SecureBootAssets{}\n\t\t}\n\n\t\tif value.IsZero(i.SecureBoot.SecureBootSigner) {\n\t\t\ti.SecureBoot.SecureBootSigner.KeyPath = filepath.Join(defaultSecureBootPrefix, constants.SecureBootSigningKeyAsset)\n\t\t\ti.SecureBoot.SecureBootSigner.CertPath = filepath.Join(defaultSecureBootPrefix, constants.SecureBootSigningCertAsset)\n\t\t}\n\n\t\tif value.IsZero(i.SecureBoot.PCRSigner) {\n\t\t\ti.SecureBoot.PCRSigner.KeyPath = filepath.Join(defaultSecureBootPrefix, constants.PCRSigningKeyAsset)\n\t\t}\n\n\t\tif i.SecureBoot.PlatformKeyPath == \"\" {\n\t\t\tif platformKeyPath := filepath.Join(defaultSecureBootPrefix, constants.PlatformKeyAsset); fileExists(platformKeyPath) {\n\t\t\t\ti.SecureBoot.PlatformKeyPath = platformKeyPath\n\t\t\t}\n\t\t}\n\n\t\tif i.SecureBoot.KeyExchangeKeyPath == \"\" {\n\t\t\tif keyExchangeKeyPath := filepath.Join(defaultSecureBootPrefix, constants.KeyExchangeKeyAsset); fileExists(keyExchangeKeyPath) {\n\t\t\t\ti.SecureBoot.KeyExchangeKeyPath = keyExchangeKeyPath\n\t\t\t}\n\t\t}\n\n\t\tif i.SecureBoot.SignatureKeyPath == \"\" {\n\t\t\tif signatureKeyPath := filepath.Join(defaultSecureBootPrefix, constants.SignatureKeyAsset); fileExists(signatureKeyPath) {\n\t\t\t\ti.SecureBoot.SignatureKeyPath = signatureKeyPath\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc fileExists(path string) bool {\n\t_, err := os.Stat(path)\n\n\treturn err == nil\n}\n\n// Pull the container asset to the path.\nfunc (c *ContainerAsset) Pull(ctx context.Context, arch string, printf func(string, ...any)) (v1.Image, error) {\n\tif c.TarballPath != \"\" {\n\t\treturn nil, errors.New(\"pulling tarball container image is not supported\")\n\t}\n\n\tif c.OCIPath != \"\" {\n\t\tprintf(\"using OCI image from %s...\", c.OCIPath)\n\n\t\treturn c.pullFromOCI(arch)\n\t}\n\n\tprintf(\"pulling %s...\", c.ImageRef)\n\n\topts := []crane.Option{\n\t\tcrane.WithPlatform(&v1.Platform{\n\t\t\tArchitecture: arch,\n\t\t\tOS:           \"linux\",\n\t\t}),\n\t\tcrane.WithContext(ctx),\n\t\tcrane.WithAuthFromKeychain(\n\t\t\tauthn.NewMultiKeychain(\n\t\t\t\tauthn.DefaultKeychain,\n\t\t\t\tgithub.Keychain,\n\t\t\t\tgoogle.Keychain,\n\t\t\t),\n\t\t),\n\t}\n\n\tif c.ForceInsecure {\n\t\topts = append(opts, crane.Insecure)\n\t}\n\n\timg, err := crane.Pull(c.ImageRef, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error pulling image %s: %w\", c.ImageRef, err)\n\t}\n\n\treturn img, nil\n}\n\nfunc (c *ContainerAsset) pullFromOCI(arch string) (v1.Image, error) {\n\tociLayout, err := layout.FromPath(c.OCIPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error opening OCI layout: %w\", err)\n\t}\n\n\tociIndex, err := ociLayout.ImageIndex()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error opening OCI index: %w\", err)\n\t}\n\n\tociManifest, err := ociIndex.IndexManifest()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error opening OCI manifest: %w\", err)\n\t}\n\n\tfor _, manifest := range ociManifest.Manifests {\n\t\tif manifest.Platform == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif manifest.Platform.OS == \"linux\" && manifest.Platform.Architecture == arch {\n\t\t\timg, err := ociLayout.Image(manifest.Digest)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error opening OCI image: %w\", err)\n\t\t\t}\n\n\t\t\treturn img, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"no OCI image found for %s\", arch)\n}\n\n// Extract the container asset to the path.\nfunc (c *ContainerAsset) Extract(ctx context.Context, destination, arch string, printf func(string, ...any)) error {\n\tif c.TarballPath != \"\" {\n\t\tin, err := os.Open(c.TarballPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer in.Close() //nolint:errcheck\n\n\t\tprintf(\"extracting %s...\", c.TarballPath)\n\n\t\treturn archiver.Untar(ctx, in, destination)\n\t}\n\n\timg, err := c.Pull(ctx, arch, printf)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr, w := io.Pipe()\n\n\teg, ctx := errgroup.WithContext(ctx)\n\n\teg.Go(func() error {\n\t\tif exportErr := crane.Export(img, w); exportErr != nil {\n\t\t\tw.CloseWithError(exportErr)\n\n\t\t\treturn exportErr\n\t\t}\n\n\t\tw.Close() //nolint:errcheck\n\n\t\treturn nil\n\t})\n\n\teg.Go(func() error {\n\t\tif untarErr := archiver.Untar(ctx, r, destination); untarErr != nil {\n\t\t\tr.CloseWithError(untarErr)\n\n\t\t\treturn untarErr\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn eg.Wait()\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/aws/aws.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package aws implements SecureBoot/PCR signers via AWS Key Management Service.\npackage aws\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/service/acm\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kms\"\n)\n\nfunc getKmsClient(ctx context.Context, awsRegion string) (*kms.Client, error) {\n\tawsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error initializing AWS default config: %w\", err)\n\t}\n\n\treturn kms.NewFromConfig(awsCfg), nil\n}\n\nfunc getAcmClient(ctx context.Context, awsRegion string) (*acm.Client, error) {\n\tawsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error initializing AWS default config: %w\", err)\n\t}\n\n\treturn acm.NewFromConfig(awsCfg), nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/aws/aws_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage aws_test\n\nimport (\n\t\"crypto/sha256\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/profile/internal/signer/aws\"\n)\n\nfunc TestIntegration(t *testing.T) {\n\tfor _, envVar := range []string{\"AWS_KMS_KEY_ID\", \"AWS_REGION\", \"AWS_CERT_PATH\", \"AWS_CERT_ARN\"} {\n\t\tif os.Getenv(envVar) == \"\" {\n\t\t\tt.Skipf(\"%s not set\", envVar)\n\t\t}\n\t}\n\n\tsigner, err := aws.NewPCRSigner(t.Context(), os.Getenv(\"AWS_KMS_KEY_ID\"), os.Getenv(\"AWS_REGION\"))\n\trequire.NoError(t, err)\n\n\tdigest := sha256.Sum256(nil)\n\n\t_, err = signer.Sign(nil, digest[:], nil)\n\trequire.NoError(t, err)\n\n\tsbSigner, err := aws.NewSecureBootSigner(t.Context(), os.Getenv(\"AWS_KMS_KEY_ID\"), os.Getenv(\"AWS_REGION\"), os.Getenv(\"AWS_CERT_PATH\"))\n\trequire.NoError(t, err)\n\n\t_, err = sbSigner.Signer().Sign(nil, digest[:], nil)\n\trequire.NoError(t, err)\n\n\tsbAcmSigner, err := aws.NewSecureBootACMSigner(t.Context(), os.Getenv(\"AWS_KMS_KEY_ID\"), os.Getenv(\"AWS_REGION\"), os.Getenv(\"AWS_CERT_ARN\"))\n\trequire.NoError(t, err)\n\n\t_, err = sbAcmSigner.Signer().Sign(nil, digest[:], nil)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/aws/pcr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage aws\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/big\"\n\n\t\"github.com/aws/aws-sdk-go-v2/service/kms\"\n\t\"github.com/aws/aws-sdk-go-v2/service/kms/types\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n)\n\n// KeySigner implements measure.RSAKey interface.\n//\n// KeySigner wraps Azure APIs to provide public key and crypto.Signer interface out of Azure Key Vault RSA key.\ntype KeySigner struct {\n\tkeyName string\n\tmode    mode\n\n\tclient    *kms.Client\n\tpublicKey *rsa.PublicKey\n}\n\nvar algMap = map[mode]map[crypto.Hash]types.SigningAlgorithmSpec{\n\trsaPKCS1v15: {\n\t\tcrypto.SHA256: types.SigningAlgorithmSpecRsassaPkcs1V15Sha256,\n\t\tcrypto.SHA384: types.SigningAlgorithmSpecRsassaPkcs1V15Sha384,\n\t\tcrypto.SHA512: types.SigningAlgorithmSpecRsassaPkcs1V15Sha512,\n\t},\n\trsaPSS: {\n\t\tcrypto.SHA256: types.SigningAlgorithmSpecRsassaPssSha256,\n\t\tcrypto.SHA384: types.SigningAlgorithmSpecRsassaPssSha384,\n\t\tcrypto.SHA512: types.SigningAlgorithmSpecRsassaPssSha512,\n\t},\n\tecdsa: {\n\t\tcrypto.SHA256: types.SigningAlgorithmSpecEcdsaSha256,\n\t\tcrypto.SHA384: types.SigningAlgorithmSpecEcdsaSha384,\n\t\tcrypto.SHA512: types.SigningAlgorithmSpecEcdsaSha512,\n\t},\n}\n\ntype mode string\n\nconst (\n\trsaPKCS1v15 mode = \"pkcs1v15\"\n\trsaPSS      mode = \"pss\"\n\tecdsa       mode = \"ecdsa\"\n)\n\n// PublicRSAKey returns the public key.\nfunc (s *KeySigner) PublicRSAKey() *rsa.PublicKey {\n\treturn s.publicKey\n}\n\n// Public returns the public key.\nfunc (s *KeySigner) Public() crypto.PublicKey {\n\treturn s.PublicRSAKey()\n}\n\n// Sign implements the crypto.Signer interface.\nfunc (s *KeySigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {\n\tmode := s.mode\n\n\tinner := algMap[mode]\n\tif inner == nil {\n\t\treturn nil, fmt.Errorf(\"mode not supported\")\n\t}\n\n\thf := crypto.SHA256\n\n\tif opts != nil {\n\t\thf = opts.HashFunc()\n\t}\n\n\talgorithm := inner[hf]\n\tif algorithm == \"\" {\n\t\treturn nil, fmt.Errorf(\"algorithm not supported\")\n\t}\n\n\tresp, err := s.client.Sign(context.Background(), &kms.SignInput{\n\t\tKeyId:            &s.keyName,\n\t\tMessage:          digest,\n\t\tMessageType:      types.MessageTypeDigest,\n\t\tSigningAlgorithm: algorithm,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn resp.Signature, nil\n}\n\n// Verify interface.\nvar _ measure.RSAKey = (*KeySigner)(nil)\n\n// NewPCRSigner creates a new PCR signer from AWS settings.\nfunc NewPCRSigner(ctx context.Context, kmsKeyID, awsRegion string) (*KeySigner, error) {\n\tclient, err := getKmsClient(ctx, awsRegion)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build AWS kms client: %w\", err)\n\t}\n\n\tkeyResponse, err := client.GetPublicKey(ctx, &kms.GetPublicKeyInput{\n\t\tKeyId: &kmsKeyID,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get key: %w\", err)\n\t}\n\n\tif keyResponse.KeyUsage != \"SIGN_VERIFY\" {\n\t\treturn nil, fmt.Errorf(\"key usage is not SIGN_VERIFY\")\n\t}\n\n\tswitch keyResponse.KeySpec { //nolint:exhaustive\n\tcase types.KeySpecRsa2048, types.KeySpecRsa3072, types.KeySpecRsa4096:\n\t\t// expected, continue\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"key type is not RSA\")\n\t}\n\n\tparsedKey, err := x509.ParsePKIXPublicKey(keyResponse.PublicKey)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Public key is not valid: %w\", err)\n\t}\n\n\trsaKey := parsedKey.(*rsa.PublicKey)\n\tif rsaKey.E == 0 {\n\t\treturn nil, fmt.Errorf(\"property e is empty\")\n\t}\n\n\tif rsaKey.N.Cmp(big.NewInt(0)) == 0 {\n\t\treturn nil, fmt.Errorf(\"property N is empty\")\n\t}\n\n\treturn &KeySigner{\n\t\tkeyName: kmsKeyID,\n\t\tmode:    rsaPKCS1v15, // TODO: make this configurable\n\n\t\tpublicKey: rsaKey,\n\t\tclient:    client,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/aws/secureboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage aws\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/aws/aws-sdk-go-v2/service/acm\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n)\n\n// SecureBootSigner implements pesign.CertificateSigner interface.\ntype SecureBootSigner struct {\n\tkeySigner *KeySigner\n\tcert      *x509.Certificate\n}\n\n// Verify interface.\nvar _ pesign.CertificateSigner = (*SecureBootSigner)(nil)\n\n// Signer returns the signer.\nfunc (s *SecureBootSigner) Signer() crypto.Signer {\n\treturn s.keySigner\n}\n\n// Certificate returns the certificate.\nfunc (s *SecureBootSigner) Certificate() *x509.Certificate {\n\treturn s.cert\n}\n\n// NewSecureBootSigner creates a new SecureBootSigner.\nfunc NewSecureBootSigner(ctx context.Context, kmsKeyID, awsRegion, certPath string) (*SecureBootSigner, error) {\n\tkeySigner, err := NewPCRSigner(ctx, kmsKeyID, awsRegion)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize certificate key signer (kms): %w\", err)\n\t}\n\n\tcertData, err := os.ReadFile(certPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcertBlock, _ := pem.Decode(certData)\n\tif certBlock == nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode certificate\")\n\t}\n\n\tcert, err := x509.ParseCertificate(certBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse certificate: %w\", err)\n\t}\n\n\treturn &SecureBootSigner{\n\t\tkeySigner: keySigner,\n\t\tcert:      cert,\n\t}, nil\n}\n\n// NewSecureBootACMSigner creates a new SecureBootSigner using an ACM certificate.\nfunc NewSecureBootACMSigner(ctx context.Context, kmsKeyID, awsRegion, acmCertificateARN string) (*SecureBootSigner, error) {\n\tkeySigner, err := NewPCRSigner(ctx, kmsKeyID, awsRegion)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize certificate key signer (kms): %w\", err)\n\t}\n\n\tacmClient, err := getAcmClient(ctx, awsRegion)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build ACM client: %w\", err)\n\t}\n\n\tresp, err := acmClient.GetCertificate(ctx, &acm.GetCertificateInput{\n\t\tCertificateArn: &acmCertificateARN,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get certificate: %w\", err)\n\t}\n\n\tcertBlock, _ := pem.Decode([]byte(pointer.SafeDeref(resp.Certificate)))\n\tif certBlock == nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode certificate\")\n\t}\n\n\tcert, err := x509.ParseCertificate(certBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode certificate: %w\", err)\n\t}\n\n\treturn &SecureBootSigner{\n\t\tkeySigner: keySigner,\n\t\tcert:      cert,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/azure/azure.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package azure implements SecureBoot/PCR signers via Azure Key Vault.\npackage azure\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/azidentity\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates\"\n\t\"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys\"\n)\n\ntype authenticationMethod string\n\nconst (\n\tunknownAuthenticationMethod     = \"unknown\"\n\tenvironmentAuthenticationMethod = \"environment\"\n\tcliAuthenticationMethod         = \"cli\"\n)\n\nconst azureClientID = \"AZURE_CLIENT_ID\"\n\n// getAuthenticationMethod returns an authenticationMethod to use to get an Azure Authorizer.\n// If no environment variables are set, unknownAuthMethod will be used.\n// If the environment variable 'AZURE_AUTH_METHOD' is set to either environment or cli, use it.\n// If the environment variables 'AZURE_TENANT_ID', 'AZURE_CLIENT_ID' and 'AZURE_CLIENT_SECRET' are set, use environment.\nfunc getAuthenticationMethod() authenticationMethod {\n\ttenantID := os.Getenv(\"AZURE_TENANT_ID\")\n\tclientID := os.Getenv(\"AZURE_CLIENT_ID\")\n\tclientSecret := os.Getenv(\"AZURE_CLIENT_SECRET\")\n\tauthMethod := os.Getenv(\"AZURE_AUTH_METHOD\")\n\n\tif authMethod != \"\" {\n\t\tswitch strings.ToLower(authMethod) {\n\t\tcase \"environment\":\n\t\t\treturn environmentAuthenticationMethod\n\t\tcase \"cli\":\n\t\t\treturn cliAuthenticationMethod\n\t\t}\n\t}\n\n\tif tenantID != \"\" && clientID != \"\" && clientSecret != \"\" {\n\t\treturn environmentAuthenticationMethod\n\t}\n\n\treturn unknownAuthenticationMethod\n}\n\ntype azureCredential interface {\n\tGetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error)\n}\n\nfunc getAzClientOpts() azcore.ClientOptions {\n\tenvName := os.Getenv(\"AZURE_ENVIRONMENT\")\n\tswitch envName {\n\tcase \"AZUREUSGOVERNMENT\", \"AZUREUSGOVERNMENTCLOUD\":\n\t\treturn azcore.ClientOptions{Cloud: cloud.AzureGovernment}\n\tcase \"AZURECHINACLOUD\":\n\t\treturn azcore.ClientOptions{Cloud: cloud.AzureChina}\n\tcase \"AZURECLOUD\", \"AZUREPUBLICCLOUD\":\n\t\treturn azcore.ClientOptions{Cloud: cloud.AzurePublic}\n\tdefault:\n\t\treturn azcore.ClientOptions{Cloud: cloud.AzurePublic}\n\t}\n}\n\n// getAzureCredential takes an authenticationMethod and returns an Azure credential or an error.\n//\n// If the method is unknown, Environment will be tested and if it returns an error CLI will be tested.\n// If the method is specified, the specified method will be used and no other will be tested.\n// This means the following default order of methods will be used if nothing else is defined:\n// 1. Client credentials (FromEnvironment)\n// 2. Client certificate (FromEnvironment)\n// 3. Username password (FromEnvironment)\n// 4. MSI (FromEnvironment)\n// 5. CLI (FromCLI).\nfunc getAzureCredential(method authenticationMethod) (azureCredential, error) {\n\tclientOpts := getAzClientOpts()\n\n\tswitch method {\n\tcase environmentAuthenticationMethod:\n\t\tenvCred, err := azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOpts})\n\t\tif err == nil {\n\t\t\treturn envCred, nil\n\t\t}\n\n\t\to := &azidentity.ManagedIdentityCredentialOptions{ClientOptions: clientOpts}\n\t\tif ID, ok := os.LookupEnv(azureClientID); ok {\n\t\t\to.ID = azidentity.ClientID(ID)\n\t\t}\n\n\t\tmsiCred, err := azidentity.NewManagedIdentityCredential(o)\n\t\tif err == nil {\n\t\t\treturn msiCred, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to create default azure credential from env auth method: %w\", err)\n\tcase cliAuthenticationMethod:\n\t\tcred, err := azidentity.NewAzureCLICredential(nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create default Azure credential from env auth method: %w\", err)\n\t\t}\n\n\t\treturn cred, nil\n\tcase unknownAuthenticationMethod:\n\t\tbreak\n\tdefault:\n\t\treturn nil, errors.New(\"you should never reach this\")\n\t}\n\n\tenvCreds, err := azidentity.NewEnvironmentCredential(&azidentity.EnvironmentCredentialOptions{ClientOptions: clientOpts})\n\tif err == nil {\n\t\treturn envCreds, nil\n\t}\n\n\tcliCreds, err := azidentity.NewAzureCLICredential(nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create default Azure credential from env auth method: %w\", err)\n\t}\n\n\treturn cliCreds, nil\n}\n\ntype azureCredentialAndError struct {\n\tcred azureCredential\n\terr  error\n}\n\nvar azureCredentialsOnce = sync.OnceValue(func() azureCredentialAndError {\n\tauthMethod := getAuthenticationMethod()\n\n\tcred, err := getAzureCredential(authMethod)\n\n\treturn azureCredentialAndError{cred, err}\n})\n\nfunc getKeysClient(vaultURL string) (*azkeys.Client, error) {\n\tcredAndError := azureCredentialsOnce()\n\tif credAndError.err != nil {\n\t\treturn nil, credAndError.err\n\t}\n\n\treturn azkeys.NewClient(vaultURL, credAndError.cred, nil)\n}\n\nfunc getCertsClient(vaultURL string) (*azcertificates.Client, error) {\n\tcredAndError := azureCredentialsOnce()\n\tif credAndError.err != nil {\n\t\treturn nil, credAndError.err\n\t}\n\n\treturn azcertificates.NewClient(vaultURL, credAndError.cred, nil)\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/azure/azure_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure_test\n\nimport (\n\t\"crypto/sha256\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/profile/internal/signer/azure\"\n)\n\nfunc TestIntegration(t *testing.T) {\n\tfor _, envVar := range []string{\"AZURE_VAULT_URL\", \"AZURE_KEY_ID\", \"AZURE_CERT_ID\", \"AZURE_TENANT_ID\", \"AZURE_CLIENT_ID\", \"AZURE_CLIENT_SECRET\"} {\n\t\tif os.Getenv(envVar) == \"\" {\n\t\t\tt.Skipf(\"%s not set\", envVar)\n\t\t}\n\t}\n\n\tsigner, err := azure.NewPCRSigner(t.Context(), os.Getenv(\"AZURE_VAULT_URL\"), os.Getenv(\"AZURE_KEY_ID\"), \"\")\n\trequire.NoError(t, err)\n\n\tdigest := sha256.Sum256(nil)\n\n\t_, err = signer.Sign(nil, digest[:], nil)\n\trequire.NoError(t, err)\n\n\tsbSigner, err := azure.NewSecureBootSigner(t.Context(), os.Getenv(\"AZURE_VAULT_URL\"), os.Getenv(\"AZURE_CERT_ID\"), \"\")\n\trequire.NoError(t, err)\n\n\t_, err = sbSigner.Signer().Sign(nil, digest[:], nil)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/azure/pcr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/big\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n)\n\n// KeySigner implements measure.RSAKey interface.\n//\n// KeySigner wraps Azure APIs to provide public key and crypto.Signer interface out of Azure Key Vault RSA key.\ntype KeySigner struct {\n\tkeyName, keyVersion string\n\n\tclient    *azkeys.Client\n\tpublicKey *rsa.PublicKey\n}\n\n// PublicRSAKey returns the public key.\nfunc (s *KeySigner) PublicRSAKey() *rsa.PublicKey {\n\treturn s.publicKey\n}\n\n// Public returns the public key.\nfunc (s *KeySigner) Public() crypto.PublicKey {\n\treturn s.PublicRSAKey()\n}\n\n// Sign implements the crypto.Signer interface.\nfunc (s *KeySigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {\n\tparams := azkeys.SignParameters{\n\t\tValue: digest,\n\t}\n\n\thf := crypto.SHA256\n\n\tif opts != nil {\n\t\thf = opts.HashFunc()\n\t}\n\n\tswitch hf { //nolint:exhaustive\n\tcase crypto.SHA256:\n\t\tparams.Algorithm = new(azkeys.SignatureAlgorithmRS256)\n\tcase crypto.SHA384:\n\t\tparams.Algorithm = new(azkeys.SignatureAlgorithmRS384)\n\tcase crypto.SHA512:\n\t\tparams.Algorithm = new(azkeys.SignatureAlgorithmRS512)\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported hashing function\")\n\t}\n\n\tresp, err := s.client.Sign(context.Background(), s.keyName, s.keyVersion, params, &azkeys.SignOptions{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to sign: %w\", err)\n\t}\n\n\treturn resp.Result, nil\n}\n\n// Verify interface.\nvar _ measure.RSAKey = (*KeySigner)(nil)\n\n// NewPCRSigner creates a new PCR signer from Azure settings.\nfunc NewPCRSigner(ctx context.Context, vaultURL, keyID, keyVersion string) (*KeySigner, error) {\n\tclient, err := getKeysClient(vaultURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build Azure client: %w\", err)\n\t}\n\n\tkeyResponse, err := client.GetKey(ctx, keyID, keyVersion, &azkeys.GetKeyOptions{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get key: %w\", err)\n\t}\n\n\tif keyResponse.Key.Kty == nil {\n\t\treturn nil, errors.New(\"key type is nil\")\n\t}\n\n\tswitch *keyResponse.Key.Kty { //nolint:exhaustive\n\tcase azkeys.KeyTypeRSA, azkeys.KeyTypeRSAHSM:\n\t\t// expected, continue\n\tdefault:\n\t\treturn nil, errors.New(\"key type is not RSA\")\n\t}\n\n\tvar publicKey rsa.PublicKey\n\n\t// N = modulus\n\tif len(keyResponse.Key.N) == 0 {\n\t\treturn nil, errors.New(\"property N is empty\")\n\t}\n\n\tpublicKey.N = &big.Int{}\n\tpublicKey.N.SetBytes(keyResponse.Key.N)\n\n\t// e = public exponent\n\tif len(keyResponse.Key.E) == 0 {\n\t\treturn nil, errors.New(\"property e is empty\")\n\t}\n\n\tpublicKey.E = int(big.NewInt(0).SetBytes(keyResponse.Key.E).Uint64())\n\n\treturn &KeySigner{\n\t\tkeyName:    keyID,\n\t\tkeyVersion: keyVersion,\n\n\t\tpublicKey: &publicKey,\n\t\tclient:    client,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/azure/secureboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage azure\n\nimport (\n\t\"context\"\n\t\"crypto\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\n\t\"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azcertificates\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n)\n\n// SecureBootSigner implements pesign.CertificateSigner interface.\ntype SecureBootSigner struct {\n\tkeySigner *KeySigner\n\tcert      *x509.Certificate\n}\n\n// Verify interface.\nvar _ pesign.CertificateSigner = (*SecureBootSigner)(nil)\n\n// Signer returns the signer.\nfunc (s *SecureBootSigner) Signer() crypto.Signer {\n\treturn s.keySigner\n}\n\n// Certificate returns the certificate.\nfunc (s *SecureBootSigner) Certificate() *x509.Certificate {\n\treturn s.cert\n}\n\n// NewSecureBootSigner creates a new SecureBootSigner.\nfunc NewSecureBootSigner(ctx context.Context, vaultURL, certificateID, certificateVersion string) (*SecureBootSigner, error) {\n\tcertsClient, err := getCertsClient(vaultURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build Azure certificates client: %w\", err)\n\t}\n\n\tresp, err := certsClient.GetCertificate(ctx, certificateID, certificateVersion, &azcertificates.GetCertificateOptions{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get certificate: %w\", err)\n\t}\n\n\tcert, err := x509.ParseCertificate(resp.CER)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode certificate: %w\", err)\n\t}\n\n\t// initialize key signer via existing implementation\n\tKID := pointer.SafeDeref(resp.KID)\n\n\tkeySigner, err := NewPCRSigner(ctx, vaultURL, KID.Name(), KID.Version())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize certificate key signer: %w\", err)\n\t}\n\n\treturn &SecureBootSigner{\n\t\tcert:      cert,\n\t\tkeySigner: keySigner,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/file/pcr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package file implements SecureBoot/PCR signers via plain filesystem files.\npackage file\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/measure\"\n)\n\n// PCRSigner implements measure.RSAKey interface.\ntype PCRSigner struct {\n\tkey *rsa.PrivateKey\n}\n\n// Verify interface.\nvar _ measure.RSAKey = (*PCRSigner)(nil)\n\n// PublicRSAKey returns the public key.\nfunc (s *PCRSigner) PublicRSAKey() *rsa.PublicKey {\n\treturn &s.key.PublicKey\n}\n\n// Public returns the public key.\nfunc (s *PCRSigner) Public() crypto.PublicKey {\n\treturn s.PublicRSAKey()\n}\n\n// Sign implements the crypto.Signer interface.\nfunc (s *PCRSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {\n\treturn s.key.Sign(rand, digest, opts)\n}\n\n// NewPCRSigner creates a new PCR signer from the private key file.\nfunc NewPCRSigner(keyPath string) (*PCRSigner, error) {\n\tkeyData, err := os.ReadFile(keyPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert private key to rsa.PrivateKey\n\trsaPrivateKeyBlock, _ := pem.Decode(keyData)\n\tif rsaPrivateKeyBlock == nil {\n\t\treturn nil, errors.New(\"failed to decode private key\")\n\t}\n\n\trsaKey, err := x509.ParsePKCS1PrivateKey(rsaPrivateKeyBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse private RSA key: %v\", err)\n\t}\n\n\treturn &PCRSigner{rsaKey}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/internal/signer/file/secureboot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage file\n\nimport (\n\t\"crypto\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/internal/pkg/secureboot/pesign\"\n)\n\n// SecureBootSigner implements pesign.CertificateSigner interface.\ntype SecureBootSigner struct {\n\tkey  *rsa.PrivateKey\n\tcert *x509.Certificate\n}\n\n// Verify interface.\nvar _ pesign.CertificateSigner = (*SecureBootSigner)(nil)\n\n// Signer returns the signer.\nfunc (s *SecureBootSigner) Signer() crypto.Signer {\n\treturn s.key\n}\n\n// Certificate returns the certificate.\nfunc (s *SecureBootSigner) Certificate() *x509.Certificate {\n\treturn s.cert\n}\n\n// NewSecureBootSigner creates a new SecureBootSigner.\nfunc NewSecureBootSigner(certPath, keyPath string) (*SecureBootSigner, error) {\n\tkeyData, err := os.ReadFile(keyPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// convert private key to rsa.PrivateKey\n\trsaPrivateKeyBlock, _ := pem.Decode(keyData)\n\tif rsaPrivateKeyBlock == nil {\n\t\treturn nil, errors.New(\"failed to decode private key\")\n\t}\n\n\trsaKey, err := x509.ParsePKCS1PrivateKey(rsaPrivateKeyBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse private RSA key: %w\", err)\n\t}\n\n\tcertData, err := os.ReadFile(certPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcertBlock, _ := pem.Decode(certData)\n\tif certBlock == nil {\n\t\treturn nil, errors.New(\"failed to decode certificate\")\n\t}\n\n\tcert, err := x509.ParseCertificate(certBlock.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse certificate: %w\", err)\n\t}\n\n\treturn &SecureBootSigner{\n\t\tkey:  rsaKey,\n\t\tcert: cert,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/imager/profile/output.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/imageropts\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// Output describes image generation result.\ntype Output struct {\n\t// Kind of the output:\n\t//  * iso - ISO image\n\t//  * image - disk image (Talos pre-installed)\n\t//  * installer - installer container\n\t//  * kernel - Linux kernel\n\t//  * initramfs - initramfs image\n\tKind OutputKind `yaml:\"kind\"`\n\t// Options for the 'image' output.\n\tImageOptions *ImageOptions `yaml:\"imageOptions,omitempty\"`\n\t// Options for the 'iso' output.\n\tISOOptions *ISOOptions `yaml:\"isoOptions,omitempty\"`\n\t// OutFormat is the format for the output:\n\t//  * raw - output raw file\n\t//  * .tar.gz - output tar.gz archive\n\t//  * .xz - output xz archive\n\t//  * .gz - output gz archive\n\tOutFormat OutFormat `yaml:\"outFormat\"`\n}\n\n// ImageOptions describes options for the 'image' output.\ntype ImageOptions struct {\n\t// DiskSize is the size of the disk image (bytes).\n\tDiskSize int64 `yaml:\"diskSize\"`\n\t// DiskFormat is the format of the disk image:\n\t//  * raw - raw disk image\n\t//  * qcow2 - qcow2 disk image\n\t//  * vhd - VPC disk image\n\t//  * ova - VMWare disk image\n\tDiskFormat DiskFormat `yaml:\"diskFormat,omitempty\"`\n\t// DiskFormatOptions are additional options for the disk format\n\tDiskFormatOptions string `yaml:\"diskFormatOptions,omitempty\"`\n\t// Bootloader is the bootloader to use for the disk image.\n\t// If not set, it defaults to dual-boot.\n\tBootloader BootloaderKind `yaml:\"bootloader,omitempty\"`\n}\n\n// ISOOptions describes options for the 'iso' output.\ntype ISOOptions struct {\n\t// SDBootEnrollKeys is a value in loader.conf secure-boot-enroll: off, manual, if-safe, force.\n\t//\n\t// If not set, it defaults to if-safe.\n\tSDBootEnrollKeys SDBootEnrollKeys `yaml:\"sdBootEnrollKeys\"`\n\t// Bootloader is the bootloader to use for the iso image.\n\t// If not set, it defaults to dual-boot.\n\tBootloader BootloaderKind `yaml:\"bootloader,omitempty\"`\n}\n\n// OutputKind is output specification.\ntype OutputKind int\n\n// OutputKind values.\nconst (\n\tOutKindUnknown   OutputKind = iota // unknown\n\tOutKindISO                         // iso\n\tOutKindImage                       // image\n\tOutKindInstaller                   // installer\n\tOutKindKernel                      // kernel\n\tOutKindInitramfs                   // initramfs\n\tOutKindUKI                         // uki\n\tOutKindCmdline                     // cmdline\n)\n\n// OutFormat is output format specification.\ntype OutFormat int\n\n// OutFormat values.\nconst (\n\tOutFormatUnknown OutFormat = iota // unknown\n\tOutFormatRaw                      // raw\n\tOutFormatTar                      // .tar.gz\n\tOutFormatXZ                       // .xz\n\tOutFormatGZ                       // .gz\n\tOutFormatZSTD                     // .zst\n)\n\n// DiskFormat is disk format specification.\ntype DiskFormat int\n\n// DiskFormat values.\nconst (\n\tDiskFormatUnknown DiskFormat = iota // unknown\n\tDiskFormatRaw                       // raw\n\tDiskFormatQCOW2                     // qcow2\n\tDiskFormatVPC                       // vhd\n\tDiskFormatOVA                       // ova\n)\n\n// SDBootEnrollKeys is a value in loader.conf secure-boot-enroll: off, manual, if-safe, force.\ntype SDBootEnrollKeys int\n\n// SDBootEnrollKeys values.\nconst (\n\tSDBootEnrollKeysIfSafe SDBootEnrollKeys = iota // if-safe\n\tSDBootEnrollKeysManual                         // manual\n\tSDBootEnrollKeysForce                          // force\n\tSDBootEnrollKeysOff                            // off\n)\n\n// BootloaderKind is a bootloader for the disk image.\ntype BootloaderKind = imageropts.BootloaderKind\n\n// BootloaderKind values re-exported from imageropts.\nconst (\n\tBootLoaderKindNone     = imageropts.BootLoaderKindNone\n\tBootLoaderKindDualBoot = imageropts.BootLoaderKindDualBoot\n\tBootLoaderKindSDBoot   = imageropts.BootLoaderKindSDBoot\n\tBootLoaderKindGrub     = imageropts.BootLoaderKindGrub\n)\n\n// FillDefaults fills default values for the output.\nfunc (o *Output) FillDefaults(arch, version string, secureboot bool) {\n\tswitch o.Kind { //nolint:exhaustive\n\tcase OutKindImage:\n\t\tif o.ImageOptions == nil {\n\t\t\to.ImageOptions = &ImageOptions{}\n\t\t}\n\n\t\to.ImageOptions.Bootloader = o.selectBootloader(o.ImageOptions.Bootloader, arch, version, secureboot)\n\n\t\tps := quirks.New(version).PartitionSizes()\n\n\t\t// bump default image size for expanded boot\n\t\to.ImageOptions.DiskSize += int64(ps.GrubBootSize()) - 1000*1024*1024 // 1000 MiB\n\n\t\tif o.ImageOptions.Bootloader == BootLoaderKindDualBoot {\n\t\t\t// add extra space for BIOS and BOOT partitions\n\t\t\to.ImageOptions.DiskSize += int64(ps.GrubBIOSSize()) + int64(ps.GrubBootSize())\n\t\t}\n\n\tcase OutKindISO:\n\t\tif !quirks.New(version).ISOSupportsSettingBootloader() {\n\t\t\treturn\n\t\t}\n\n\t\tif o.ISOOptions == nil {\n\t\t\to.ISOOptions = &ISOOptions{}\n\t\t}\n\n\t\to.ISOOptions.Bootloader = o.selectBootloader(o.ISOOptions.Bootloader, arch, version, secureboot)\n\t}\n}\n\nfunc (o *Output) selectBootloader(current BootloaderKind, arch, version string, secureboot bool) BootloaderKind {\n\t// If already set, return the current value, secureboot shouldn't allow changing it.\n\tif current != BootLoaderKindNone && !secureboot {\n\t\treturn current\n\t}\n\n\tuseSDBoot := quirks.New(version).UseSDBootForUEFI()\n\n\tswitch {\n\tcase secureboot:\n\t\t// secureboot is always using sd-boot\n\t\treturn BootLoaderKindSDBoot\n\tcase arch == \"arm64\" && useSDBoot:\n\t\t// arm64 always uses sd-boot for Talos >= 1.10\n\t\treturn BootLoaderKindSDBoot\n\tcase !useSDBoot:\n\t\t// legacy versions of Talos use GRUB for BIOS/UEFI\n\t\treturn BootLoaderKindGrub\n\tdefault:\n\t\t// Default to dual-boot if not overridden.\n\t\treturn BootLoaderKindDualBoot\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/profile/output_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nfunc createOutputWithDefaults(kind profile.OutputKind, arch, version string, secureBoot bool) profile.Output {\n\tout := profile.Output{\n\t\tKind: kind,\n\t}\n\n\tout.FillDefaults(arch, version, secureBoot)\n\n\treturn out\n}\n\nfunc createOutputWithOverride(kind profile.OutputKind, bootloader profile.BootloaderKind, secureBoot bool) profile.Output {\n\tout := profile.Output{\n\t\tKind: kind,\n\t}\n\n\tswitch kind { //nolint:exhaustive\n\tcase profile.OutKindImage:\n\t\tout.ImageOptions = &profile.ImageOptions{\n\t\t\tBootloader: bootloader,\n\t\t}\n\tcase profile.OutKindISO:\n\t\tout.ISOOptions = &profile.ISOOptions{\n\t\t\tBootloader: bootloader,\n\t\t}\n\t}\n\n\tout.FillDefaults(\"amd64\", \"v1.12.0\", secureBoot)\n\n\treturn out\n}\n\nfunc TestBootloaderSetting(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tarch       string\n\t\tversion    string\n\t\tsecureBoot bool\n\t\twantImage  profile.BootloaderKind\n\t}{\n\t\t// Talos < 1.10: GRUB for both amd64/arm64, ISO options not supported\n\t\t{\"amd64\", \"1.9.0\", false, profile.BootLoaderKindGrub},\n\t\t{\"amd64\", \"1.9.0\", true, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.9.0\", false, profile.BootLoaderKindGrub},\n\t\t{\"arm64\", \"1.9.0\", true, profile.BootLoaderKindSDBoot},\n\n\t\t// Talos 1.10-1.11: amd64=dual-boot, arm64=sd-boot, ISO options not supported\n\t\t{\"amd64\", \"1.10.0\", false, profile.BootLoaderKindDualBoot},\n\t\t{\"amd64\", \"1.10.0\", true, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.10.0\", false, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.10.0\", true, profile.BootLoaderKindSDBoot},\n\t\t{\"amd64\", \"1.11.0\", false, profile.BootLoaderKindDualBoot},\n\t\t{\"amd64\", \"1.11.0\", true, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.11.0\", false, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.11.0\", true, profile.BootLoaderKindSDBoot},\n\n\t\t// Talos >= 1.12: amd64=dual-boot, arm64=sd-boot, ISO options supported\n\t\t{\"amd64\", \"1.12.0\", false, profile.BootLoaderKindDualBoot},\n\t\t{\"amd64\", \"1.12.0\", true, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.12.0\", false, profile.BootLoaderKindSDBoot},\n\t\t{\"arm64\", \"1.12.0\", true, profile.BootLoaderKindSDBoot},\n\t}\n\n\tfor _, tt := range tests {\n\t\tname := tt.arch + \"-\" + tt.version\n\t\tif tt.secureBoot {\n\t\t\tname += \"-secureboot\"\n\t\t}\n\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// Test Image output\n\t\t\timg := createOutputWithDefaults(profile.OutKindImage, tt.arch, tt.version, tt.secureBoot)\n\t\t\trequire.NotNil(t, img.ImageOptions)\n\t\t\trequire.Equal(t, tt.wantImage, img.ImageOptions.Bootloader)\n\n\t\t\t// Test ISO output\n\t\t\tiso := createOutputWithDefaults(profile.OutKindISO, tt.arch, tt.version, tt.secureBoot)\n\t\t\tif quirks.New(tt.version).ISOSupportsSettingBootloader() {\n\t\t\t\trequire.NotNil(t, iso.ISOOptions)\n\t\t\t\trequire.Equal(t, tt.wantImage, iso.ISOOptions.Bootloader)\n\t\t\t} else {\n\t\t\t\trequire.Nil(t, iso.ISOOptions)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestBootloaderOverride(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname               string\n\t\tsecureBoot         bool\n\t\toverride           profile.BootloaderKind\n\t\texpectedBootloader profile.BootloaderKind\n\t}{\n\t\t{\n\t\t\t\"non-secureboot override to sd-boot\",\n\t\t\tfalse,\n\t\t\tprofile.BootLoaderKindSDBoot,\n\t\t\tprofile.BootLoaderKindSDBoot,\n\t\t},\n\t\t{\n\t\t\t\"secureboot override to grub\",\n\t\t\ttrue,\n\t\t\tprofile.BootLoaderKindGrub,\n\t\t\tprofile.BootLoaderKindSDBoot,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// Test Image output with override\n\t\t\timg := createOutputWithOverride(profile.OutKindImage, tt.override, tt.secureBoot)\n\t\t\trequire.NotNil(t, img.ImageOptions)\n\t\t\trequire.Equal(t, tt.expectedBootloader, img.ImageOptions.Bootloader)\n\n\t\t\t// Test ISO output with override\n\t\t\tiso := createOutputWithOverride(profile.OutKindISO, tt.override, tt.secureBoot)\n\t\t\trequire.Equal(t, tt.expectedBootloader, iso.ISOOptions.Bootloader)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/profile/outputkind_enumer.go",
    "content": "// Code generated by \"enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys -linecomment -text\"; DO NOT EDIT.\n\npackage profile\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _OutputKindName = \"unknownisoimageinstallerkernelinitramfsukicmdline\"\n\nvar _OutputKindIndex = [...]uint8{0, 7, 10, 15, 24, 30, 39, 42, 49}\n\nconst _OutputKindLowerName = \"unknownisoimageinstallerkernelinitramfsukicmdline\"\n\nfunc (i OutputKind) String() string {\n\tif i < 0 || i >= OutputKind(len(_OutputKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"OutputKind(%d)\", i)\n\t}\n\treturn _OutputKindName[_OutputKindIndex[i]:_OutputKindIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _OutputKindNoOp() {\n\tvar x [1]struct{}\n\t_ = x[OutKindUnknown-(0)]\n\t_ = x[OutKindISO-(1)]\n\t_ = x[OutKindImage-(2)]\n\t_ = x[OutKindInstaller-(3)]\n\t_ = x[OutKindKernel-(4)]\n\t_ = x[OutKindInitramfs-(5)]\n\t_ = x[OutKindUKI-(6)]\n\t_ = x[OutKindCmdline-(7)]\n}\n\nvar _OutputKindValues = []OutputKind{OutKindUnknown, OutKindISO, OutKindImage, OutKindInstaller, OutKindKernel, OutKindInitramfs, OutKindUKI, OutKindCmdline}\n\nvar _OutputKindNameToValueMap = map[string]OutputKind{\n\t_OutputKindName[0:7]:        OutKindUnknown,\n\t_OutputKindLowerName[0:7]:   OutKindUnknown,\n\t_OutputKindName[7:10]:       OutKindISO,\n\t_OutputKindLowerName[7:10]:  OutKindISO,\n\t_OutputKindName[10:15]:      OutKindImage,\n\t_OutputKindLowerName[10:15]: OutKindImage,\n\t_OutputKindName[15:24]:      OutKindInstaller,\n\t_OutputKindLowerName[15:24]: OutKindInstaller,\n\t_OutputKindName[24:30]:      OutKindKernel,\n\t_OutputKindLowerName[24:30]: OutKindKernel,\n\t_OutputKindName[30:39]:      OutKindInitramfs,\n\t_OutputKindLowerName[30:39]: OutKindInitramfs,\n\t_OutputKindName[39:42]:      OutKindUKI,\n\t_OutputKindLowerName[39:42]: OutKindUKI,\n\t_OutputKindName[42:49]:      OutKindCmdline,\n\t_OutputKindLowerName[42:49]: OutKindCmdline,\n}\n\nvar _OutputKindNames = []string{\n\t_OutputKindName[0:7],\n\t_OutputKindName[7:10],\n\t_OutputKindName[10:15],\n\t_OutputKindName[15:24],\n\t_OutputKindName[24:30],\n\t_OutputKindName[30:39],\n\t_OutputKindName[39:42],\n\t_OutputKindName[42:49],\n}\n\n// OutputKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc OutputKindString(s string) (OutputKind, error) {\n\tif val, ok := _OutputKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _OutputKindNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to OutputKind values\", s)\n}\n\n// OutputKindValues returns all values of the enum\nfunc OutputKindValues() []OutputKind {\n\treturn _OutputKindValues\n}\n\n// OutputKindStrings returns a slice of all String values of the enum\nfunc OutputKindStrings() []string {\n\tstrs := make([]string, len(_OutputKindNames))\n\tcopy(strs, _OutputKindNames)\n\treturn strs\n}\n\n// IsAOutputKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i OutputKind) IsAOutputKind() bool {\n\tfor _, v := range _OutputKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for OutputKind\nfunc (i OutputKind) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for OutputKind\nfunc (i *OutputKind) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = OutputKindString(string(text))\n\treturn err\n}\n\nconst _OutFormatName = \"unknownraw.tar.gz.xz.gz.zst\"\n\nvar _OutFormatIndex = [...]uint8{0, 7, 10, 17, 20, 23, 27}\n\nconst _OutFormatLowerName = \"unknownraw.tar.gz.xz.gz.zst\"\n\nfunc (i OutFormat) String() string {\n\tif i < 0 || i >= OutFormat(len(_OutFormatIndex)-1) {\n\t\treturn fmt.Sprintf(\"OutFormat(%d)\", i)\n\t}\n\treturn _OutFormatName[_OutFormatIndex[i]:_OutFormatIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _OutFormatNoOp() {\n\tvar x [1]struct{}\n\t_ = x[OutFormatUnknown-(0)]\n\t_ = x[OutFormatRaw-(1)]\n\t_ = x[OutFormatTar-(2)]\n\t_ = x[OutFormatXZ-(3)]\n\t_ = x[OutFormatGZ-(4)]\n\t_ = x[OutFormatZSTD-(5)]\n}\n\nvar _OutFormatValues = []OutFormat{OutFormatUnknown, OutFormatRaw, OutFormatTar, OutFormatXZ, OutFormatGZ, OutFormatZSTD}\n\nvar _OutFormatNameToValueMap = map[string]OutFormat{\n\t_OutFormatName[0:7]:        OutFormatUnknown,\n\t_OutFormatLowerName[0:7]:   OutFormatUnknown,\n\t_OutFormatName[7:10]:       OutFormatRaw,\n\t_OutFormatLowerName[7:10]:  OutFormatRaw,\n\t_OutFormatName[10:17]:      OutFormatTar,\n\t_OutFormatLowerName[10:17]: OutFormatTar,\n\t_OutFormatName[17:20]:      OutFormatXZ,\n\t_OutFormatLowerName[17:20]: OutFormatXZ,\n\t_OutFormatName[20:23]:      OutFormatGZ,\n\t_OutFormatLowerName[20:23]: OutFormatGZ,\n\t_OutFormatName[23:27]:      OutFormatZSTD,\n\t_OutFormatLowerName[23:27]: OutFormatZSTD,\n}\n\nvar _OutFormatNames = []string{\n\t_OutFormatName[0:7],\n\t_OutFormatName[7:10],\n\t_OutFormatName[10:17],\n\t_OutFormatName[17:20],\n\t_OutFormatName[20:23],\n\t_OutFormatName[23:27],\n}\n\n// OutFormatString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc OutFormatString(s string) (OutFormat, error) {\n\tif val, ok := _OutFormatNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _OutFormatNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to OutFormat values\", s)\n}\n\n// OutFormatValues returns all values of the enum\nfunc OutFormatValues() []OutFormat {\n\treturn _OutFormatValues\n}\n\n// OutFormatStrings returns a slice of all String values of the enum\nfunc OutFormatStrings() []string {\n\tstrs := make([]string, len(_OutFormatNames))\n\tcopy(strs, _OutFormatNames)\n\treturn strs\n}\n\n// IsAOutFormat returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i OutFormat) IsAOutFormat() bool {\n\tfor _, v := range _OutFormatValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for OutFormat\nfunc (i OutFormat) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for OutFormat\nfunc (i *OutFormat) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = OutFormatString(string(text))\n\treturn err\n}\n\nconst _DiskFormatName = \"unknownrawqcow2vhdova\"\n\nvar _DiskFormatIndex = [...]uint8{0, 7, 10, 15, 18, 21}\n\nconst _DiskFormatLowerName = \"unknownrawqcow2vhdova\"\n\nfunc (i DiskFormat) String() string {\n\tif i < 0 || i >= DiskFormat(len(_DiskFormatIndex)-1) {\n\t\treturn fmt.Sprintf(\"DiskFormat(%d)\", i)\n\t}\n\treturn _DiskFormatName[_DiskFormatIndex[i]:_DiskFormatIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _DiskFormatNoOp() {\n\tvar x [1]struct{}\n\t_ = x[DiskFormatUnknown-(0)]\n\t_ = x[DiskFormatRaw-(1)]\n\t_ = x[DiskFormatQCOW2-(2)]\n\t_ = x[DiskFormatVPC-(3)]\n\t_ = x[DiskFormatOVA-(4)]\n}\n\nvar _DiskFormatValues = []DiskFormat{DiskFormatUnknown, DiskFormatRaw, DiskFormatQCOW2, DiskFormatVPC, DiskFormatOVA}\n\nvar _DiskFormatNameToValueMap = map[string]DiskFormat{\n\t_DiskFormatName[0:7]:        DiskFormatUnknown,\n\t_DiskFormatLowerName[0:7]:   DiskFormatUnknown,\n\t_DiskFormatName[7:10]:       DiskFormatRaw,\n\t_DiskFormatLowerName[7:10]:  DiskFormatRaw,\n\t_DiskFormatName[10:15]:      DiskFormatQCOW2,\n\t_DiskFormatLowerName[10:15]: DiskFormatQCOW2,\n\t_DiskFormatName[15:18]:      DiskFormatVPC,\n\t_DiskFormatLowerName[15:18]: DiskFormatVPC,\n\t_DiskFormatName[18:21]:      DiskFormatOVA,\n\t_DiskFormatLowerName[18:21]: DiskFormatOVA,\n}\n\nvar _DiskFormatNames = []string{\n\t_DiskFormatName[0:7],\n\t_DiskFormatName[7:10],\n\t_DiskFormatName[10:15],\n\t_DiskFormatName[15:18],\n\t_DiskFormatName[18:21],\n}\n\n// DiskFormatString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc DiskFormatString(s string) (DiskFormat, error) {\n\tif val, ok := _DiskFormatNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _DiskFormatNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to DiskFormat values\", s)\n}\n\n// DiskFormatValues returns all values of the enum\nfunc DiskFormatValues() []DiskFormat {\n\treturn _DiskFormatValues\n}\n\n// DiskFormatStrings returns a slice of all String values of the enum\nfunc DiskFormatStrings() []string {\n\tstrs := make([]string, len(_DiskFormatNames))\n\tcopy(strs, _DiskFormatNames)\n\treturn strs\n}\n\n// IsADiskFormat returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i DiskFormat) IsADiskFormat() bool {\n\tfor _, v := range _DiskFormatValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for DiskFormat\nfunc (i DiskFormat) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for DiskFormat\nfunc (i *DiskFormat) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = DiskFormatString(string(text))\n\treturn err\n}\n\nconst _SDBootEnrollKeysName = \"if-safemanualforceoff\"\n\nvar _SDBootEnrollKeysIndex = [...]uint8{0, 7, 13, 18, 21}\n\nconst _SDBootEnrollKeysLowerName = \"if-safemanualforceoff\"\n\nfunc (i SDBootEnrollKeys) String() string {\n\tif i < 0 || i >= SDBootEnrollKeys(len(_SDBootEnrollKeysIndex)-1) {\n\t\treturn fmt.Sprintf(\"SDBootEnrollKeys(%d)\", i)\n\t}\n\treturn _SDBootEnrollKeysName[_SDBootEnrollKeysIndex[i]:_SDBootEnrollKeysIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _SDBootEnrollKeysNoOp() {\n\tvar x [1]struct{}\n\t_ = x[SDBootEnrollKeysIfSafe-(0)]\n\t_ = x[SDBootEnrollKeysManual-(1)]\n\t_ = x[SDBootEnrollKeysForce-(2)]\n\t_ = x[SDBootEnrollKeysOff-(3)]\n}\n\nvar _SDBootEnrollKeysValues = []SDBootEnrollKeys{SDBootEnrollKeysIfSafe, SDBootEnrollKeysManual, SDBootEnrollKeysForce, SDBootEnrollKeysOff}\n\nvar _SDBootEnrollKeysNameToValueMap = map[string]SDBootEnrollKeys{\n\t_SDBootEnrollKeysName[0:7]:        SDBootEnrollKeysIfSafe,\n\t_SDBootEnrollKeysLowerName[0:7]:   SDBootEnrollKeysIfSafe,\n\t_SDBootEnrollKeysName[7:13]:       SDBootEnrollKeysManual,\n\t_SDBootEnrollKeysLowerName[7:13]:  SDBootEnrollKeysManual,\n\t_SDBootEnrollKeysName[13:18]:      SDBootEnrollKeysForce,\n\t_SDBootEnrollKeysLowerName[13:18]: SDBootEnrollKeysForce,\n\t_SDBootEnrollKeysName[18:21]:      SDBootEnrollKeysOff,\n\t_SDBootEnrollKeysLowerName[18:21]: SDBootEnrollKeysOff,\n}\n\nvar _SDBootEnrollKeysNames = []string{\n\t_SDBootEnrollKeysName[0:7],\n\t_SDBootEnrollKeysName[7:13],\n\t_SDBootEnrollKeysName[13:18],\n\t_SDBootEnrollKeysName[18:21],\n}\n\n// SDBootEnrollKeysString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc SDBootEnrollKeysString(s string) (SDBootEnrollKeys, error) {\n\tif val, ok := _SDBootEnrollKeysNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _SDBootEnrollKeysNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to SDBootEnrollKeys values\", s)\n}\n\n// SDBootEnrollKeysValues returns all values of the enum\nfunc SDBootEnrollKeysValues() []SDBootEnrollKeys {\n\treturn _SDBootEnrollKeysValues\n}\n\n// SDBootEnrollKeysStrings returns a slice of all String values of the enum\nfunc SDBootEnrollKeysStrings() []string {\n\tstrs := make([]string, len(_SDBootEnrollKeysNames))\n\tcopy(strs, _SDBootEnrollKeysNames)\n\treturn strs\n}\n\n// IsASDBootEnrollKeys returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i SDBootEnrollKeys) IsASDBootEnrollKeys() bool {\n\tfor _, v := range _SDBootEnrollKeysValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for SDBootEnrollKeys\nfunc (i SDBootEnrollKeys) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for SDBootEnrollKeys\nfunc (i *SDBootEnrollKeys) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = SDBootEnrollKeysString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/imager/profile/profile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package profile contains definition of the image generation profile.\npackage profile\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type Profile -type SecureBootAssets -header-file ../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n//go:generate go tool github.com/dmarkham/enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys -linecomment -text\n\n// Profile describes image generation result.\ntype Profile struct {\n\t// BaseProfileName is the profile name to inherit from.\n\tBaseProfileName string `yaml:\"baseProfileName,omitempty\"`\n\t// Architecture of the image: amd64 or arm64.\n\tArch string `yaml:\"arch\"`\n\t// Platform name of the image: qemu, aws, gcp, etc.\n\tPlatform string `yaml:\"platform\"`\n\t// SecureBoot enables SecureBoot (only for UEFI build).\n\tSecureBoot *bool `yaml:\"secureboot\"`\n\t// Version is Talos version.\n\tVersion string `yaml:\"version\"`\n\t// Various customizations than can be applied to the image.\n\tCustomization CustomizationProfile `yaml:\"customization,omitempty\"`\n\n\t// Input describes inputs for image generation.\n\tInput Input `yaml:\"input\"`\n\t// Overlay describes overlay options for image generation.\n\tOverlay *OverlayOptions `yaml:\"overlay,omitempty\"`\n\t// Output describes image generation result.\n\tOutput Output `yaml:\"output\"`\n}\n\n// OverlayOptions describes overlay options for image generation.\ntype OverlayOptions struct {\n\t// Name of the overlay installer, defaults to `default` if not set.\n\tName string `yaml:\"name\"`\n\t// Image to use for the overlay.\n\tImage ContainerAsset `yaml:\"image\"`\n\t// Options for the overlay.\n\toverlay.ExtraOptions `yaml:\"options,omitempty\"` //nolint:embeddedstructfieldcheck\n}\n\n// SecureBootEnabled derefences SecureBoot.\nfunc (p *Profile) SecureBootEnabled() bool {\n\treturn pointer.SafeDeref(p.SecureBoot)\n}\n\n// Validate the profile.\n//\n//nolint:gocyclo,cyclop\nfunc (p *Profile) Validate() error {\n\tif p.Arch != amd64 && p.Arch != arm64 {\n\t\treturn fmt.Errorf(\"invalid arch %q\", p.Arch)\n\t}\n\n\tif p.Platform == \"\" {\n\t\treturn errors.New(\"platform is required\")\n\t}\n\n\tif p.SecureBootEnabled() && !quirks.New(p.Version).SupportsUKI() {\n\t\treturn fmt.Errorf(\"secureboot is not supported for Talos version %q\", p.Version)\n\t}\n\n\tswitch p.Output.Kind {\n\tcase OutKindUnknown:\n\t\treturn errors.New(\"unknown output kind\")\n\tcase OutKindISO:\n\t\t// ISO supports all kinds of customization\n\t\tif quirks.New(p.Version).ISOSupportsSettingBootloader() {\n\t\t\tif p.Output.ISOOptions != nil && p.Output.ISOOptions.Bootloader == BootLoaderKindNone {\n\t\t\t\treturn errors.New(\"bootloader cannot be 'none' for ISO output\")\n\t\t\t}\n\t\t}\n\tcase OutKindCmdline:\n\t\t// cmdline supports all kinds of customization\n\tcase OutKindImage:\n\t\t// Image supports all kinds of customization\n\t\tif p.Output.ImageOptions == nil {\n\t\t\treturn errors.New(\"image options are required for image output\")\n\t\t}\n\n\t\tif p.Output.ImageOptions.DiskSize == 0 {\n\t\t\treturn errors.New(\"disk size is required for image output\")\n\t\t}\n\n\t\tif p.Output.ImageOptions.Bootloader == BootLoaderKindNone {\n\t\t\treturn errors.New(\"bootloader cannot be 'none' for disk image output\")\n\t\t}\n\tcase OutKindInstaller:\n\t\tif len(p.Customization.MetaContents) > 0 {\n\t\t\treturn fmt.Errorf(\"customization of meta partition is not supported for %s output\", p.Output.Kind)\n\t\t}\n\tcase OutKindKernel, OutKindInitramfs:\n\t\tif p.SecureBootEnabled() {\n\t\t\treturn fmt.Errorf(\"secureboot is not supported for %s output\", p.Output.Kind)\n\t\t}\n\n\t\tif len(p.Customization.ExtraKernelArgs) > 0 {\n\t\t\treturn fmt.Errorf(\"customization of kernel args is not supported for %s output\", p.Output.Kind)\n\t\t}\n\n\t\tif len(p.Customization.MetaContents) > 0 {\n\t\t\treturn fmt.Errorf(\"customization of meta partition is not supported for %s output\", p.Output.Kind)\n\t\t}\n\tcase OutKindUKI:\n\t}\n\n\treturn nil\n}\n\n// OutputPath generates the output path for the profile.\n//\n//nolint:gocyclo\nfunc (p *Profile) OutputPath() string {\n\tpath := p.Platform\n\n\tpath += \"-\" + p.Arch\n\n\tif p.SecureBootEnabled() {\n\t\tpath += \"-secureboot\"\n\t}\n\n\tswitch p.Output.Kind {\n\tcase OutKindUnknown:\n\t\tpanic(\"unknown output kind\")\n\tcase OutKindISO:\n\t\tpath += \".iso\"\n\tcase OutKindImage:\n\t\tpath += \".\" + p.Output.ImageOptions.DiskFormat.String()\n\tcase OutKindInstaller:\n\t\tpath = \"installer-\" + p.Arch\n\n\t\tif p.SecureBootEnabled() {\n\t\t\tpath += \"-secureboot\"\n\t\t}\n\n\t\tpath += \".tar\"\n\tcase OutKindKernel:\n\t\tpath = \"kernel-\" + p.Arch\n\tcase OutKindInitramfs:\n\t\tpath = \"initramfs-\" + path + \".xz\"\n\tcase OutKindUKI:\n\t\tpath += \"-uki.efi\"\n\tcase OutKindCmdline:\n\t\tpath = \"cmdline-\" + path\n\t}\n\n\treturn path\n}\n\n// Dump the profile as YAML.\nfunc (p *Profile) Dump(w io.Writer) error {\n\tencoder := yaml.NewEncoder(w)\n\tencoder.SetIndent(2)\n\n\treturn encoder.Encode(p)\n}\n"
  },
  {
    "path": "pkg/imager/profile/profile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage profile_test\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/maps\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/profile\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nfunc TestFillDefaults(t *testing.T) {\n\tt.Parallel()\n\n\tarches := []string{\"amd64\", \"arm64\"}\n\tversions := []string{\"1.9.0\", \"1.10.0\", \"1.11.0\", \"1.12.0\", \"1.13.0\"}\n\n\tlastVersion := semver.MustParse(versions[len(versions)-1])\n\n\tcurrentVersion, err := semver.ParseTolerant(version.Tag)\n\trequire.NoError(t, err)\n\n\tcurrentVersion.Patch = 0\n\tcurrentVersion.Pre = nil\n\n\trequire.True(t, lastVersion.GTE(currentVersion), \"last version %s should be greater or equal to current version %s\", lastVersion, currentVersion)\n\n\tprofiles := maps.Keys(profile.Default)\n\n\tsort.Strings(profiles)\n\n\t// flip this to true to generate missing testdata files\n\tconst recordMissing = false\n\n\tif recordMissing {\n\t\tt.Logf(\"recording missing testdata files, failing the test\")\n\t\tt.Fail()\n\t}\n\n\tfor _, prof := range profiles {\n\t\tt.Run(prof, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar secureBoot bool\n\n\t\t\tif strings.HasPrefix(prof, \"secureboot\") {\n\t\t\t\tsecureBoot = true\n\t\t\t}\n\n\t\t\tfor _, arch := range arches {\n\t\t\t\tt.Run(arch, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\n\t\t\t\t\tfor _, version := range versions {\n\t\t\t\t\t\tt.Run(version, func(t *testing.T) {\n\t\t\t\t\t\t\tt.Parallel()\n\n\t\t\t\t\t\t\tp := profile.Default[prof].DeepCopy()\n\n\t\t\t\t\t\t\tp.Arch = arch\n\t\t\t\t\t\t\tp.Version = version\n\n\t\t\t\t\t\t\tp.Input.FillDefaults(arch, version, secureBoot)\n\t\t\t\t\t\t\tp.Output.FillDefaults(arch, version, secureBoot)\n\n\t\t\t\t\t\t\trequire.NoError(t, p.Validate())\n\n\t\t\t\t\t\t\tvar profileData strings.Builder\n\n\t\t\t\t\t\t\trequire.NoError(t, p.Dump(&profileData))\n\n\t\t\t\t\t\t\texpectedData, err := os.ReadFile(\"testdata/\" + prof + \"-\" + arch + \"-\" + version + \".yaml\")\n\t\t\t\t\t\t\tif errors.Is(err, fs.ErrNotExist) && recordMissing {\n\t\t\t\t\t\t\t\trequire.NoError(t, os.WriteFile(\"testdata/\"+prof+\"-\"+arch+\"-\"+version+\".yaml\", []byte(profileData.String()), 0o644))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\t\trequire.Equal(t, string(expectedData), profileData.String(), \"profile: %s, platform: %s, version: %s\", prof, arch, version)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: akamai\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: akamai\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: akamai\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: akamai\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: akamai\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: akamai\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: akamai\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: akamai\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: akamai\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/akamai-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: akamai\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: aws\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: aws\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: aws\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: aws\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: aws\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: aws\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: aws\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: aws\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: aws\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/aws-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: aws\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: azure\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: azure\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: azure\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: azure\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: azure\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: azure\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: azure\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: azure\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: azure\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/azure-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: azure\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: vhd\n    diskFormatOptions: subformat=fixed,force_size\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: cloudstack\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: cloudstack\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: cloudstack\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: cloudstack\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: cloudstack\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: cloudstack\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: cloudstack\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: cloudstack\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: cloudstack\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/cloudstack-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: cloudstack\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/digital-ocean-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: digital-ocean\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: exoscale\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11787042816\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: exoscale\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 13884194816\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: exoscale\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 13884194816\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: exoscale\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 13884194816\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: exoscale\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 10737418240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: exoscale\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 10737418240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: exoscale\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11785994240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: exoscale\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11785994240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: exoscale\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11785994240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/exoscale-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: exoscale\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 10737418240\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: gcp\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: gcp\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: gcp\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: gcp\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: gcp\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: gcp\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: gcp\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: gcp\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: gcp\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/gcp-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: gcp\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .tar.gz\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: hcloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: hcloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: hcloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: hcloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: hcloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: hcloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: hcloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: hcloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: hcloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/hcloud-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: hcloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/installer-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/iso-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: iso\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/metal-uki-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: nocloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: nocloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: nocloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: nocloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: nocloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: nocloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: nocloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: nocloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: nocloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/nocloud-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: nocloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: opennebula\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: opennebula\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: opennebula\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: opennebula\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: opennebula\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: opennebula\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: opennebula\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: opennebula\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: opennebula\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/opennebula-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: opennebula\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: openstack\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: openstack\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: openstack\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: openstack\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: openstack\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: openstack\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: openstack\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: openstack\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: openstack\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/openstack-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: openstack\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: oracle\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: oracle\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: oracle\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: oracle\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: oracle\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: oracle\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: oracle\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: oracle\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: oracle\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/oracle-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: oracle\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: qcow2\n    diskFormatOptions: cluster_size=8k\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: scaleway\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2356150272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: scaleway\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: scaleway\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: scaleway\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 4453302272\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: scaleway\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: scaleway\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: scaleway\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: scaleway\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: scaleway\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/scaleway-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: scaleway\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-installer-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: installer\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-iso-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: iso\n  isoOptions:\n    sdBootEnrollKeys: if-safe\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 2355101696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 1306525696\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/secureboot-metal-uki-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: metal\nsecureboot: true\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\n  secureboot:\n    secureBootSigner:\n      keyPath: /secureboot/uki-signing-key.pem\n      certPath: /secureboot/uki-signing-cert.pem\n    pcrSigner:\n      keyPath: /secureboot/pcr-signing-key.pem\noutput:\n  kind: uki\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: upcloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: upcloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: upcloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: upcloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: upcloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: upcloud\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: upcloud\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: upcloud\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: upcloud\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/upcloud-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: upcloud\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: vmware\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: ova\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: vmware\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: ova\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: vmware\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: ova\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: vmware\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: ova\n    bootloader: dual-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: vmware\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: ova\n    bootloader: grub\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: vmware\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: ova\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: vmware\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: ova\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: vmware\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: ova\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: vmware\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: ova\n    bootloader: sd-boot\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vmware-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: vmware\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: ova\n    bootloader: grub\n  outFormat: raw\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-amd64-1.10.0.yaml",
    "content": "arch: amd64\nplatform: vultr\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9639559168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-amd64-1.11.0.yaml",
    "content": "arch: amd64\nplatform: vultr\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-amd64-1.12.0.yaml",
    "content": "arch: amd64\nplatform: vultr\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-amd64-1.13.0.yaml",
    "content": "arch: amd64\nplatform: vultr\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 11736711168\n    diskFormat: raw\n    bootloader: dual-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-amd64-1.9.0.yaml",
    "content": "arch: amd64\nplatform: vultr\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/amd64/vmlinuz\n  initramfs:\n    path: /usr/install/amd64/initramfs.xz\n  sdStub:\n    path: /usr/install/amd64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/amd64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-arm64-1.10.0.yaml",
    "content": "arch: arm64\nplatform: vultr\nsecureboot: false\nversion: 1.10.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.10.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-arm64-1.11.0.yaml",
    "content": "arch: arm64\nplatform: vultr\nsecureboot: false\nversion: 1.11.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.11.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-arm64-1.12.0.yaml",
    "content": "arch: arm64\nplatform: vultr\nsecureboot: false\nversion: 1.12.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.12.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-arm64-1.13.0.yaml",
    "content": "arch: arm64\nplatform: vultr\nsecureboot: false\nversion: 1.13.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer-base:1.13.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 9638510592\n    diskFormat: raw\n    bootloader: sd-boot\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/profile/testdata/vultr-arm64-1.9.0.yaml",
    "content": "arch: arm64\nplatform: vultr\nsecureboot: false\nversion: 1.9.0\ninput:\n  kernel:\n    path: /usr/install/arm64/vmlinuz\n  initramfs:\n    path: /usr/install/arm64/initramfs.xz\n  sdStub:\n    path: /usr/install/arm64/systemd-stub.efi\n  sdBoot:\n    path: /usr/install/arm64/systemd-boot.efi\n  baseInstaller:\n    imageRef: ghcr.io/siderolabs/installer:1.9.0\noutput:\n  kind: image\n  imageOptions:\n    diskSize: 8589934592\n    diskFormat: raw\n    bootloader: grub\n  outFormat: .zst\n"
  },
  {
    "path": "pkg/imager/progress.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage imager\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/reporter\"\n)\n\n// progressPrintf wraps a reporter.Reporter to report progress via Printf logging.\nfunc progressPrintf(report *reporter.Reporter, status reporter.Update) func(format string, args ...any) {\n\treturn func(format string, args ...any) {\n\t\tmsg := status.Message\n\t\textra := fmt.Sprintf(format, args...)\n\n\t\tif extra != \"\" {\n\t\t\tmsg += \"\\n\\t\" + extra\n\t\t}\n\n\t\treport.Report(reporter.Update{\n\t\t\tMessage: msg,\n\t\t\tStatus:  status.Status,\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/imager/qemuimg/qemuimg.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package qemuimg provides a wrapper around qemu-img.\npackage qemuimg\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n)\n\n// Convert converts an image from one format to another.\nfunc Convert(ctx context.Context, inputFmt, outputFmt, options, path string, printf func(string, ...any)) error {\n\tsrc := path + \".in\"\n\tdest := path\n\n\tprintf(\"converting %s to %s\", inputFmt, outputFmt)\n\n\tif err := os.Rename(path, src); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := cmd.RunWithOptions(ctx, \"qemu-img\", []string{\"convert\", \"-f\", inputFmt, \"-O\", outputFmt, \"-o\", options, src, dest}); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.Remove(src)\n}\n\n// Resize an image.\nfunc Resize(ctx context.Context, file, size string) error {\n\tif _, err := cmd.RunWithOptions(ctx, \"qemu-img\", []string{\"resize\", file, size}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/utils/copy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/gen/pair/ordered\"\n)\n\n// CopyInstruction describes a file copy operation.\ntype CopyInstruction = ordered.Pair[string, string]\n\n// SourceDestination returns a CopyInstruction that copies src to dest.\nfunc SourceDestination(src, dest string) CopyInstruction {\n\treturn ordered.MakePair(src, dest)\n}\n\n// CopyFiles copies files according to the given instructions.\nfunc CopyFiles(printf func(string, ...any), instructions ...CopyInstruction) error {\n\tfor _, instruction := range instructions {\n\t\tif err := func(instruction CopyInstruction) error {\n\t\t\tsrc, dest := instruction.F1, instruction.F2\n\n\t\t\tif err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tprintf(\"copying %s to %s\", src, dest)\n\n\t\t\tfrom, err := os.Open(src)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t//nolint:errcheck\n\t\t\tdefer from.Close()\n\n\t\t\tto, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o666)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t//nolint:errcheck\n\t\t\tdefer to.Close()\n\n\t\t\t_, err = io.Copy(to, from)\n\n\t\t\treturn err\n\t\t}(instruction); err != nil {\n\t\t\treturn fmt.Errorf(\"error copying %s -> %s: %w\", instruction.F1, instruction.F2, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// CopyReaderInstruction describes a reader copy operation.\ntype CopyReaderInstruction struct {\n\tReader io.Reader\n\tDest   string\n}\n\n// ReaderDestination returns a CopyReaderInstruction that copies reader to dest.\nfunc ReaderDestination(reader io.Reader, dest string) CopyReaderInstruction {\n\treturn CopyReaderInstruction{Reader: reader, Dest: dest}\n}\n\n// CopyReader copies readers according to the given instructions.\nfunc CopyReader(printf func(string, ...any), instructions ...CopyReaderInstruction) error {\n\tfor _, instruction := range instructions {\n\t\tif err := func(instruction CopyReaderInstruction) error {\n\t\t\tdest := instruction.Dest\n\n\t\t\tif err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tprintf(\"copying from io reader to %s\", dest)\n\n\t\t\tto, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o666)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t//nolint:errcheck\n\t\t\tdefer to.Close()\n\n\t\t\t_, err = io.Copy(to, instruction.Reader)\n\n\t\t\treturn err\n\t\t}(instruction); err != nil {\n\t\t\treturn fmt.Errorf(\"error copying reader -> %s: %w\", instruction.Dest, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/imager/utils/epoch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage utils\n\nimport (\n\t\"os\"\n\t\"strconv\"\n)\n\n// SourceDateEpoch returns parsed value of SOURCE_DATE_EPOCH.\nfunc SourceDateEpoch() (int64, bool, error) {\n\tepoch, ok := os.LookupEnv(\"SOURCE_DATE_EPOCH\")\n\tif !ok {\n\t\treturn 0, false, nil\n\t}\n\n\tepochInt, err := strconv.ParseInt(epoch, 10, 64)\n\tif err != nil {\n\t\treturn 0, false, err\n\t}\n\n\treturn epochInt, true, nil\n}\n"
  },
  {
    "path": "pkg/imager/utils/raw.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage utils\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\n\t\"github.com/dustin/go-humanize\"\n)\n\n// CreateRawDisk creates a raw disk image of the specified size.\nfunc CreateRawDisk(printf func(string, ...any), path string, diskSize int64, allocate bool) error {\n\tprintf(\"creating raw disk of size %s\", humanize.Bytes(uint64(diskSize)))\n\n\tf, err := os.Create(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create raw disk: %w\", err)\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tif err = f.Truncate(diskSize); err != nil {\n\t\treturn fmt.Errorf(\"failed to create raw disk: %w\", err)\n\t}\n\n\tif allocate {\n\t\tif err = syscall.Fallocate(int(f.Fd()), 0, 0, diskSize); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"WARNING: failed to preallocate disk space for %q (size %d): %s\", path, diskSize, err)\n\t\t}\n\t}\n\n\treturn f.Close()\n}\n"
  },
  {
    "path": "pkg/imager/utils/touch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage utils\n\nimport (\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n)\n\n// TouchFiles updates mtime for all the files under root if SOURCE_DATE_EPOCH is set.\nfunc TouchFiles(printf func(string, ...any), root string) error {\n\tepochInt, ok, err := SourceDateEpoch()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !ok {\n\t\treturn nil\n\t}\n\n\ttimestamp := time.Unix(epochInt, 0)\n\n\tprintf(\"changing timestamps under %q to %s\", root, timestamp)\n\n\treturn filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn os.Chtimes(path, timestamp, timestamp)\n\t})\n}\n"
  },
  {
    "path": "pkg/imager/utils/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package utils contains small utilities used by the imager.\n//\n//nolint:revive\npackage utils\n"
  },
  {
    "path": "pkg/imager/vmdkconvert/vmdkconvert.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vmdkconvert provides a wrapper around the vmdk-convert tool from open-vmdk.\npackage vmdkconvert\n\nimport (\n\t\"context\"\n\t\"os\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n)\n\n// ConvertToStreamOptimizedVMDK converts a raw / flat / sparse disk image to a stream optimized VMDK.\nfunc ConvertToStreamOptimizedVMDK(ctx context.Context, path string, printf func(string, ...any)) error {\n\tsrc := path + \".in\"\n\tdest := path\n\n\tprintf(\"converting disk image to stream optimized vmdk\")\n\n\tif err := os.Rename(path, src); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := cmd.RunWithOptions(ctx, \"vmdk-convert\", []string{src, dest}); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.Remove(src)\n}\n"
  },
  {
    "path": "pkg/images/images.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package images provides some default images.\npackage images\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/gendata\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nvar (\n\t// Username is the default registry username.\n\tUsername = gendata.ImagesUsername\n\n\t// Registry is the default registry.\n\tRegistry = gendata.ImagesRegistry\n\n\t// DefaultInstallerImageName is the default container image name for\n\t// the installer.\n\tDefaultInstallerImageName = Username + \"/installer\"\n\n\t// DefaultInstallerImageRepository is the default container repository for\n\t// the installer.\n\tDefaultInstallerImageRepository = Registry + \"/\" + DefaultInstallerImageName\n\n\t// DefaultInstallerImage is the default installer image.\n\tDefaultInstallerImage = DefaultInstallerImageRepository + \":\" + version.Tag\n\n\t// DefaultTalosImageName is the default container image name for\n\t// the talos image.\n\tDefaultTalosImageName = Username + \"/talos\"\n\n\t// DefaultTalosImageRepository is the default container repository for\n\t// the talos image.\n\tDefaultTalosImageRepository = Registry + \"/\" + DefaultTalosImageName\n\n\t// DefaultTalosImage is the default talos image.\n\tDefaultTalosImage = DefaultTalosImageRepository + \":\" + version.Tag\n\n\t// DefaultInstallerBaseImageRepository is the default container repository for\n\t// installer-base image.\n\tDefaultInstallerBaseImageRepository = Registry + \"/\" + Username + \"/installer-base\"\n\n\t// DefaultImagerImageRepository is the default container repository for\n\t// imager image.\n\tDefaultImagerImageRepository = Registry + \"/\" + Username + \"/imager\"\n\n\t// DefaultTalosctlAllImageRepository is the default container repository for\n\t// talosctl-all image.\n\tDefaultTalosctlAllImageRepository = Registry + \"/\" + Username + \"/talosctl-all\"\n\n\t// DefaultOverlaysManifestName is the default container manifest name for\n\t// the overlays.\n\tDefaultOverlaysManifestName = Username + \"/overlays\"\n\n\t// DefaultOverlaysManifestRepository is the default container repository for\n\t// overlays manifest.\n\tDefaultOverlaysManifestRepository = Registry + \"/\" + DefaultOverlaysManifestName\n\n\t// DefaultExtensionsManifestName is the default container manifest name for\n\t// the extensions.\n\tDefaultExtensionsManifestName = Username + \"/extensions\"\n\n\t// DefaultExtensionsManifestRepository is the default container repository for\n\t// extensions manifest.\n\tDefaultExtensionsManifestRepository = Registry + \"/\" + DefaultExtensionsManifestName\n)\n"
  },
  {
    "path": "pkg/images/list.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage images\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/google/go-containerregistry/pkg/name\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Versions holds all the images (and their versions) that are used in Talos.\ntype Versions struct {\n\tEtcd    name.Tag\n\tFlannel name.Tag\n\tCoreDNS name.Tag\n\n\tKubelet               name.Tag\n\tKubeAPIServer         name.Tag\n\tKubeControllerManager name.Tag\n\tKubeNetworkPolicies   name.Tag\n\tKubeProxy             name.Tag\n\tKubeScheduler         name.Tag\n\n\tPause name.Tag\n}\n\n// DefaultSandboxImage is defined as a constant in cri package of containerd, and it's not exported.\n//\n// The integration test verifies that our constant is accurate.\nconst DefaultSandboxImage = \"registry.k8s.io/pause:3.10.1\"\n\n// List returns default image versions.\nfunc List(config config.Config) Versions {\n\tvar images Versions\n\n\timages.Etcd = mustParseTag(config.Cluster().Etcd().Image())\n\timages.CoreDNS = mustParseTag(config.Cluster().CoreDNS().Image())\n\timages.Flannel = mustParseTag(fmt.Sprintf(\"ghcr.io/siderolabs/flannel:%s\", constants.FlannelVersion)) // mirrored from docker.io/flannelcni/flannel\n\timages.Kubelet = mustParseTag(config.Machine().Kubelet().Image())\n\timages.KubeAPIServer = mustParseTag(config.Cluster().APIServer().Image())\n\timages.KubeControllerManager = mustParseTag(config.Cluster().ControllerManager().Image())\n\timages.KubeNetworkPolicies = mustParseTag(fmt.Sprintf(\"registry.k8s.io/networking/kube-network-policies:%s\", constants.KubeNetworkPoliciesVersion))\n\timages.KubeProxy = mustParseTag(config.Cluster().Proxy().Image())\n\timages.KubeScheduler = mustParseTag(config.Cluster().Scheduler().Image())\n\n\timages.Pause = mustParseTag(DefaultSandboxImage)\n\n\treturn images\n}\n\n// VersionsListOptions allows overriding the default component versions\n// displayed to the user.\n//\n// Any non-empty field value replaces the corresponding default version\n// when presenting available or selected versions. Fields left empty\n// will fall back to their built-in defaults.\ntype VersionsListOptions struct {\n\t// KubernetesVersion overrides the default Kubernetes version.\n\tKubernetesVersion string\n\n\t// CoreDNSVersion overrides the default CoreDNS version.\n\tCoreDNSVersion string\n\n\t// EtcdVersion overrides the default etcd version.\n\tEtcdVersion string\n\n\t// FlannelVersion overrides the default Flannel version.\n\tFlannelVersion string\n\n\t// PauseVersion overrides the default pause container image version.\n\tPauseVersion string\n\n\t// KubeNetworkPoliciesVersion overrides the default kube-network-policies version.\n\tKubeNetworkPoliciesVersion string\n}\n\n// ListWithOptions returns image versions with overrides.\nfunc ListWithOptions(config config.Config, opts VersionsListOptions) Versions {\n\timages := List(config)\n\n\tif opts.CoreDNSVersion != \"\" {\n\t\timages.CoreDNS = images.CoreDNS.Tag(opts.CoreDNSVersion)\n\t}\n\n\tif opts.EtcdVersion != \"\" {\n\t\timages.Etcd = images.Etcd.Tag(opts.EtcdVersion)\n\t}\n\n\tif opts.FlannelVersion != \"\" {\n\t\timages.Flannel = images.Flannel.Tag(opts.FlannelVersion)\n\t}\n\n\tif opts.PauseVersion != \"\" {\n\t\timages.Pause = images.Pause.Tag(opts.PauseVersion)\n\t}\n\n\tif opts.KubernetesVersion != \"\" {\n\t\timages.Kubelet = images.Kubelet.Tag(opts.KubernetesVersion)\n\t\timages.KubeAPIServer = images.KubeAPIServer.Tag(opts.KubernetesVersion)\n\t\timages.KubeControllerManager = images.KubeControllerManager.Tag(opts.KubernetesVersion)\n\t\timages.KubeProxy = images.KubeProxy.Tag(opts.KubernetesVersion)\n\t\timages.KubeScheduler = images.KubeScheduler.Tag(opts.KubernetesVersion)\n\t}\n\n\tif opts.KubeNetworkPoliciesVersion != \"\" {\n\t\timages.KubeNetworkPolicies = images.KubeNetworkPolicies.Tag(opts.KubeNetworkPoliciesVersion)\n\t}\n\n\treturn images\n}\n\nfunc mustParseTag(s string) name.Tag {\n\ts, _, _ = strings.Cut(s, \"@\") // ignore digest if present\n\n\tr, err := name.ParseReference(s)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tt, ok := r.(name.Tag)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"%T is not name.Tag: %#+v\", r, r))\n\t}\n\n\treturn t\n}\n\nfunc mustParseReferenceWithTag(ref, tag string) name.Tag {\n\tr, err := name.ParseReference(ref)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn r.Context().Tag(tag)\n}\n\n// TalosBundle holds the core images (and their versions) that are used to build Talos.\ntype TalosBundle struct {\n\tInstaller     name.Tag\n\tInstallerBase name.Tag\n\tImager        name.Tag\n\tTalos         name.Tag\n\tTalosctlAll   name.Tag\n\n\tOverlays   name.Tag\n\tExtensions name.Tag\n}\n\n// ListSourcesFor returns source bundle for specific version.\nfunc ListSourcesFor(tag string) TalosBundle {\n\tvar bundle TalosBundle\n\n\tbundle.Installer = mustParseReferenceWithTag(DefaultInstallerImageRepository, tag)\n\tbundle.InstallerBase = mustParseReferenceWithTag(DefaultInstallerBaseImageRepository, tag)\n\tbundle.Imager = mustParseReferenceWithTag(DefaultImagerImageRepository, tag)\n\tbundle.Talos = mustParseReferenceWithTag(DefaultTalosImageRepository, tag)\n\tbundle.TalosctlAll = mustParseReferenceWithTag(DefaultTalosctlAllImageRepository, tag)\n\n\tbundle.Overlays = mustParseReferenceWithTag(DefaultOverlaysManifestRepository, tag)\n\tbundle.Extensions = mustParseReferenceWithTag(DefaultExtensionsManifestRepository, tag)\n\n\treturn bundle\n}\n"
  },
  {
    "path": "pkg/kernel/kernel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kernel provides the utilities to interact with the kernel.\npackage kernel\n\nimport (\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n)\n\n// WriteParam writes a value to a key under /proc/sys.\nfunc WriteParam(prop *kernel.Param) error {\n\treturn os.WriteFile(prop.Path(), []byte(prop.Value), 0o644)\n}\n\n// ReadParam reads a value from a key under /proc/sys.\nfunc ReadParam(prop *kernel.Param) ([]byte, error) {\n\treturn os.ReadFile(prop.Path())\n}\n\n// DeleteParam deletes a value from a key under /proc/sys.\nfunc DeleteParam(prop *kernel.Param) error {\n\treturn os.Remove(prop.Path())\n}\n"
  },
  {
    "path": "pkg/kernel/kspp/kspp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kspp implements KSPP kernel parameters enforcement.\npackage kspp\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n)\n\n// RequiredKSPPKernelParameters is the set of kernel parameters required to\n// satisfy the KSPP.\nvar RequiredKSPPKernelParameters = procfs.Parameters{\n\t// init_on_alloc and init_on_free are not enforced, as they default to '1' in kernel config\n\t// this way they can be overridden via installer extra args in case of severe performance issues\n\t// procfs.NewParameter(\"init_on_alloc\").Append(\"1\"),\n\t// procfs.NewParameter(\"init_on_free\").Append(\"1\"),\n\tprocfs.NewParameter(\"slab_nomerge\").Append(\"\"),\n\tprocfs.NewParameter(\"pti\").Append(\"on\"),\n}\n\n// EnforceKSPPKernelParameters verifies that all required KSPP kernel\n// parameters are present with the right value.\nfunc EnforceKSPPKernelParameters() error {\n\tvar result *multierror.Error\n\n\tfor _, values := range RequiredKSPPKernelParameters {\n\t\tvar val *string\n\t\tif val = procfs.ProcCmdline().Get(values.Key()).First(); val == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"KSPP kernel parameter %s is required\", values.Key()))\n\n\t\t\tcontinue\n\t\t}\n\n\t\texpected := values.First()\n\t\tif *val != *expected {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"KSPP kernel parameter %s was found with value %s, expected %s\", values.Key(), *val, *expected))\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\n// GetKernelParams returns the list of KSPP kernel parameters.\nfunc GetKernelParams() []*kernel.Param {\n\treturn []*kernel.Param{\n\t\t{\n\t\t\tKey:   \"proc.sys.dev.tty.ldisc_autoload\",\n\t\t\tValue: \"0\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.dev.tty.legacy_tiocsti\",\n\t\t\tValue: \"0\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.protected_symlinks\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.protected_hardlinks\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.protected_fifos\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.protected_regular\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.fs.suid_dumpable\",\n\t\t\tValue: \"0\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.dmesg_restrict\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.perf_event_paranoid\",\n\t\t\tValue: \"3\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.randomize_va_space\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\t// Bumping this to 3 (https://www.kernel.org/doc/Documentation/security/Yama.txt)\n\t\t\t// breaks Kubernetes pods with user namespaces, which are not enabled by default, but still supported.\n\t\t\tKey:   \"proc.sys.kernel.yama.ptrace_scope\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.user.max_user_namespaces\",\n\t\t\tValue: \"0\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.kernel.unprivileged_bpf_disabled\",\n\t\t\tValue: \"1\",\n\t\t},\n\t\t{\n\t\t\tKey:   \"proc.sys.net.core.bpf_jit_harden\",\n\t\t\tValue: \"2\",\n\t\t},\n\t\t{\n\t\t\t// Disable dangerous userfaultfd usage.\n\t\t\tKey:   \"proc.sys.vm.unprivileged_userfaultfd\",\n\t\t\tValue: \"0\",\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/kubeconfig/generate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeconfig\n\nimport (\n\t\"bytes\"\n\tstdlibx509 \"crypto/x509\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\tclientcmdapi \"k8s.io/client-go/tools/clientcmd/api\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n// GenerateAdminInput is the interface for the GenerateAdmin function.\n//\n// This interface is implemented by config.Cluster().\ntype GenerateAdminInput interface {\n\tName() string\n\tEndpoint() *url.URL\n\tIssuingCA() *x509.PEMEncodedCertificateAndKey\n\tAcceptedCAs() []*x509.PEMEncodedCertificate\n\tAdminKubeconfig() config.AdminKubeconfig\n}\n\n// GenerateAdmin generates admin kubeconfig for the cluster.\nfunc GenerateAdmin(config GenerateAdminInput, out io.Writer) error {\n\tacceptedCAs := config.AcceptedCAs()\n\n\tif config.IssuingCA() != nil {\n\t\tacceptedCAs = append(acceptedCAs, &x509.PEMEncodedCertificate{Crt: config.IssuingCA().Crt})\n\t}\n\n\treturn Generate(\n\t\t&GenerateInput{\n\t\t\tClusterName:         config.Name(),\n\t\t\tIssuingCA:           config.IssuingCA(),\n\t\t\tAcceptedCAs:         acceptedCAs,\n\t\t\tCertificateLifetime: config.AdminKubeconfig().CertLifetime(),\n\n\t\t\tCommonName:   config.AdminKubeconfig().CommonName(),\n\t\t\tOrganization: config.AdminKubeconfig().CertOrganization(),\n\n\t\t\tEndpoint:    config.Endpoint().String(),\n\t\t\tUsername:    \"admin\",\n\t\t\tContextName: \"admin\",\n\t\t},\n\t\tout,\n\t)\n}\n\n// GenerateInput are input parameters for Generate.\ntype GenerateInput struct {\n\tClusterName string\n\n\tIssuingCA           *x509.PEMEncodedCertificateAndKey\n\tAcceptedCAs         []*x509.PEMEncodedCertificate\n\tCertificateLifetime time.Duration\n\n\tCommonName   string\n\tOrganization string\n\n\tEndpoint    string\n\tUsername    string\n\tContextName string\n}\n\nconst allowedTimeSkew = 10 * time.Second\n\n// Generate a kubeconfig for the cluster from the given Input.\nfunc Generate(in *GenerateInput, out io.Writer) error {\n\tk8sCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(in.IssuingCA)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error getting Kubernetes CA: %w\", err)\n\t}\n\n\tclientCert, err := x509.NewKeyPair(k8sCA,\n\t\tx509.CommonName(in.CommonName),\n\t\tx509.Organization(in.Organization),\n\t\tx509.NotBefore(time.Now().Add(-allowedTimeSkew)),\n\t\tx509.NotAfter(time.Now().Add(in.CertificateLifetime)),\n\t\tx509.KeyUsage(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment),\n\t\tx509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{\n\t\t\tstdlibx509.ExtKeyUsageClientAuth,\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating Kubernetes client certificate: %w\", err)\n\t}\n\n\tclientCertPEM := x509.NewCertificateAndKeyFromKeyPair(clientCert)\n\n\tserverCAs := bytes.Join(xslices.Map(in.AcceptedCAs, func(ca *x509.PEMEncodedCertificate) []byte { return ca.Crt }), nil)\n\n\tcfg := clientcmdapi.Config{\n\t\tAPIVersion: \"v1\",\n\t\tKind:       \"Config\",\n\t\tClusters: map[string]*clientcmdapi.Cluster{\n\t\t\tin.ClusterName: {\n\t\t\t\tServer:                   in.Endpoint,\n\t\t\t\tCertificateAuthorityData: serverCAs,\n\t\t\t},\n\t\t},\n\t\tAuthInfos: map[string]*clientcmdapi.AuthInfo{\n\t\t\tin.Username + \"@\" + in.ClusterName: {\n\t\t\t\tClientCertificateData: clientCertPEM.Crt,\n\t\t\t\tClientKeyData:         clientCertPEM.Key,\n\t\t\t},\n\t\t},\n\t\tContexts: map[string]*clientcmdapi.Context{\n\t\t\tin.ContextName + \"@\" + in.ClusterName: {\n\t\t\t\tCluster:   in.ClusterName,\n\t\t\t\tNamespace: \"default\",\n\t\t\t\tAuthInfo:  in.Username + \"@\" + in.ClusterName,\n\t\t\t},\n\t\t},\n\t\tCurrentContext: in.ContextName + \"@\" + in.ClusterName,\n\t}\n\n\tmarshaled, err := clientcmd.Write(cfg)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = out.Write(marshaled)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/kubeconfig/generate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeconfig_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/suite\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/pkg/kubeconfig\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\ntype GenerateSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *GenerateSuite) TestGenerateAdmin() {\n\tfor _, rsa := range []bool{true, false} {\n\t\tsuite.Run(fmt.Sprintf(\"RSA=%v\", rsa), func() {\n\t\t\tca, err := x509.NewSelfSignedCertificateAuthority(x509.RSA(rsa))\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tu, err := url.Parse(\"http://localhost:3333/api\")\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tcfg := &v1alpha1.ClusterConfig{\n\t\t\t\tClusterName: \"talos1\",\n\t\t\t\tClusterCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\tCrt: ca.CrtPEM,\n\t\t\t\t\tKey: ca.KeyPEM,\n\t\t\t\t},\n\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\tURL: u,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAdminKubeconfigConfig: &v1alpha1.AdminKubeconfigConfig{\n\t\t\t\t\tAdminKubeconfigCertLifetime: time.Hour,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tvar buf bytes.Buffer\n\n\t\t\tsuite.Require().NoError(kubeconfig.GenerateAdmin(cfg, &buf))\n\n\t\t\t// verify config via k8s client\n\t\t\tconfig, err := clientcmd.Load(buf.Bytes())\n\t\t\tsuite.Require().NoError(err)\n\n\t\t\tsuite.Assert().NoError(clientcmd.ConfirmUsable(*config, fmt.Sprintf(\"admin@%s\", cfg.ClusterName)))\n\t\t})\n\t}\n}\n\nfunc (suite *GenerateSuite) TestGenerate() {\n\tca, err := x509.NewSelfSignedCertificateAuthority(x509.RSA(false))\n\tsuite.Require().NoError(err)\n\n\tk8sCA := x509.NewCertificateAndKeyFromCertificateAuthority(ca)\n\n\tinput := kubeconfig.GenerateInput{\n\t\tClusterName: \"foo\",\n\n\t\tIssuingCA:           k8sCA,\n\t\tAcceptedCAs:         []*x509.PEMEncodedCertificate{{Crt: k8sCA.Crt}},\n\t\tCertificateLifetime: time.Hour,\n\n\t\tCommonName:   \"system:kube-controller-manager\",\n\t\tOrganization: \"system:kube-controller-manager\",\n\n\t\tEndpoint:    \"https://localhost:6443/\",\n\t\tUsername:    \"kube-controller-manager\",\n\t\tContextName: \"kube-controller-manager\",\n\t}\n\n\tvar buf bytes.Buffer\n\n\tsuite.Require().NoError(kubeconfig.Generate(&input, &buf))\n\n\tsuite.T().Logf(\"Generated kubeconfig:\\n%s\", buf.String())\n\n\t// verify config via k8s client\n\tconfig, err := clientcmd.Load(buf.Bytes())\n\tsuite.Require().NoError(err)\n\n\tsuite.Assert().NoError(clientcmd.ConfirmUsable(*config, \"kube-controller-manager@foo\"))\n}\n\nfunc TestGenerateSuite(t *testing.T) {\n\tsuite.Run(t, new(GenerateSuite))\n}\n"
  },
  {
    "path": "pkg/kubeconfig/kubeconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubeconfig provides Kubernetes config file generation.\npackage kubeconfig\n"
  },
  {
    "path": "pkg/kubernetes/errors.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"github.com/siderolabs/go-kubernetes/kubernetes\"\n)\n\n// IsRetryableError returns true if this Kubernetes API should be retried.\nfunc IsRetryableError(err error) bool {\n\treturn kubernetes.IsRetryableError(err)\n}\n"
  },
  {
    "path": "pkg/kubernetes/inject/serviceaccount.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage inject\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v4\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tbatchv1 \"k8s.io/api/batch/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured\"\n\t\"k8s.io/apimachinery/pkg/runtime\"\n\t\"k8s.io/apimachinery/pkg/runtime/serializer/json\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nconst (\n\tinjectToEnv = false\n\tvolumeName  = \"talos-secrets\"\n\n\tnameSuffix = \"-talos-secrets\"\n\n\tapiVersionField = \"apiVersion\"\n\tkindField       = \"kind\"\n\tmetadataField   = \"metadata\"\n\tnamespaceField  = \"namespace\"\n\tnameField       = \"name\"\n\n\tyamlSeparator = \"---\\n\"\n)\n\n// ServiceAccount takes a YAML with Kubernetes manifests and requested Talos roles as input\n// and injects Talos service accounts into them.\n//\n//nolint:gocyclo\nfunc ServiceAccount(reader io.Reader, roles []string) ([]byte, error) {\n\tvar err error\n\n\tobjectSerializer := json.NewSerializerWithOptions(\n\t\tjson.DefaultMetaFactory,\n\t\tnil,\n\t\tnil,\n\t\tjson.SerializerOptions{\n\t\t\tYaml:   true,\n\t\t\tPretty: true,\n\t\t\tStrict: true,\n\t\t},\n\t)\n\n\tseenResourceIDs := make(map[string]struct{})\n\n\tvar buf bytes.Buffer\n\n\tdecoder := yaml.NewDecoder(reader)\n\n\t// loop over all documents in a possibly YAML with multiple documents separated by ---\n\tfor {\n\t\tvar raw map[string]any\n\n\t\terr = decoder.Decode(&raw)\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif raw == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar injected metav1.Object\n\n\t\tinjected, err = injectToObject(raw)\n\t\tif err != nil { // not a known resource with a PodSpec\n\t\t\t// if this is already a Talos ServiceAccount resource we have seen,\n\t\t\t// we keep it only if we have not seen it yet (means it belongs to the user, not injected by us)\n\t\t\tid := readResourceIDFromServiceAccount(raw)\n\t\t\tif id != \"\" {\n\t\t\t\tif _, ok := seenResourceIDs[id]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tseenResourceIDs[id] = struct{}{}\n\t\t\t}\n\n\t\t\terr = yaml.NewEncoder(&buf).Encode(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tbuf.WriteString(yamlSeparator)\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// injectable resource type which contains a PodSpec\n\n\t\truntimeObject, ok := injected.(runtime.Object)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"injected object is not a runtime.Object\")\n\t\t}\n\n\t\terr = objectSerializer.Encode(runtimeObject, &buf)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tbuf.WriteString(yamlSeparator)\n\n\t\tid := readResourceIDFromObject(injected)\n\n\t\t// inject service account for the resource\n\t\tif _, ok = seenResourceIDs[id]; !ok {\n\t\t\tsa := buildServiceAccount(injected.GetNamespace(), fmt.Sprintf(\"%s%s\", injected.GetName(), nameSuffix), roles)\n\n\t\t\terr = yaml.NewEncoder(&buf).Encode(sa)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tbuf.WriteString(yamlSeparator)\n\n\t\t\t// mark resource as seen\n\t\t\tseenResourceIDs[id] = struct{}{}\n\t\t}\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\nfunc buildServiceAccount(namespace string, name string, roles []string) map[string]any {\n\tmetadata := map[string]any{\n\t\tnameField: name,\n\t}\n\n\tif namespace != \"\" {\n\t\tmetadata[namespaceField] = namespace\n\t}\n\n\treturn map[string]any{\n\t\tapiVersionField: fmt.Sprintf(\n\t\t\t\"%s/%s\",\n\t\t\tconstants.ServiceAccountResourceGroup,\n\t\t\tconstants.ServiceAccountResourceVersion,\n\t\t),\n\t\tkindField:     constants.ServiceAccountResourceKind,\n\t\tmetadataField: metadata,\n\t\t\"spec\": map[string]any{\n\t\t\t\"roles\": roles,\n\t\t},\n\t}\n}\n\nfunc isServiceAccount(raw map[string]any) bool {\n\tapiVersionKind, err := readResourceAPIVersionKind(raw)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn apiVersionKind == fmt.Sprintf(\n\t\t\"%s/%s/%s\",\n\t\tconstants.ServiceAccountResourceGroup,\n\t\tconstants.ServiceAccountResourceVersion,\n\t\tconstants.ServiceAccountResourceKind,\n\t)\n}\n\n// injectToDocument takes a single YAML document and attempts to inject a ServiceAccount\n// into it if it is a known Kubernetes resource type which contains a corev1.PodSpec.\nfunc injectToObject(raw map[string]any) (metav1.Object, error) {\n\tvar err error\n\n\tapiVersionKind, err := readResourceAPIVersionKind(raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch apiVersionKind {\n\tcase \"v1/Pod\":\n\t\treturn injectToPodSpecObject[corev1.Pod](raw, func(obj *corev1.Pod) *corev1.PodSpec {\n\t\t\treturn &obj.Spec\n\t\t})\n\n\tcase \"apps/v1/Deployment\":\n\t\treturn injectToPodSpecObject[appsv1.Deployment](raw, func(obj *appsv1.Deployment) *corev1.PodSpec {\n\t\t\treturn &obj.Spec.Template.Spec\n\t\t})\n\n\tcase \"apps/v1/StatefulSet\":\n\t\treturn injectToPodSpecObject[appsv1.StatefulSet](raw, func(obj *appsv1.StatefulSet) *corev1.PodSpec {\n\t\t\treturn &obj.Spec.Template.Spec\n\t\t})\n\n\tcase \"apps/v1/DaemonSet\":\n\t\treturn injectToPodSpecObject[appsv1.DaemonSet](raw, func(obj *appsv1.DaemonSet) *corev1.PodSpec {\n\t\t\treturn &obj.Spec.Template.Spec\n\t\t})\n\n\tcase \"batch/v1/Job\":\n\t\treturn injectToPodSpecObject[batchv1.Job](raw, func(obj *batchv1.Job) *corev1.PodSpec {\n\t\t\treturn &obj.Spec.Template.Spec\n\t\t})\n\n\tcase \"batch/v1/CronJob\":\n\t\treturn injectToPodSpecObject[batchv1.CronJob](raw, func(obj *batchv1.CronJob) *corev1.PodSpec {\n\t\t\treturn &obj.Spec.JobTemplate.Spec.Template.Spec\n\t\t})\n\t}\n\n\treturn nil, fmt.Errorf(\"unsupported object type: %s\", apiVersionKind)\n}\n\nfunc injectToPodSpecObject[T any](raw map[string]any, podSpecFunc func(*T) *corev1.PodSpec) (*T, error) {\n\tobjectName, nameFound, err := unstructured.NestedString(raw, metadataField, nameField)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !nameFound {\n\t\treturn nil, errors.New(\"object has no name\")\n\t}\n\n\tvar obj T\n\n\terr = runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(raw, &obj, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinjectToPodSpec(fmt.Sprintf(\"%s%s\", objectName, nameSuffix), podSpecFunc(&obj))\n\n\treturn &obj, nil\n}\n\nfunc readResourceAPIVersionKind(raw map[string]any) (string, error) {\n\tapiVersion, found, err := unstructured.NestedString(raw, apiVersionField)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif !found {\n\t\treturn \"\", fmt.Errorf(\"%s not found\", apiVersionField)\n\t}\n\n\tkind, found, err := unstructured.NestedString(raw, kindField)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif !found {\n\t\treturn \"\", fmt.Errorf(\"%s not found\", kindField)\n\t}\n\n\treturn fmt.Sprintf(\"%s/%s\", apiVersion, kind), nil\n}\n\nfunc readResourceIDFromObject(obj metav1.Object) string {\n\tif obj.GetNamespace() == \"\" {\n\t\treturn obj.GetName()\n\t}\n\n\treturn fmt.Sprintf(\"%s/%s\", obj.GetNamespace(), obj.GetName())\n}\n\nfunc readResourceIDFromServiceAccount(raw map[string]any) string {\n\tif !isServiceAccount(raw) {\n\t\treturn \"\"\n\t}\n\n\tname, nameFound, err := unstructured.NestedString(raw, metadataField, nameField)\n\tif err != nil || !nameFound {\n\t\treturn \"\"\n\t}\n\n\tnameTrimmed := strings.TrimSuffix(name, nameSuffix)\n\n\tns, nsFound, err := unstructured.NestedString(raw, metadataField, namespaceField)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tif nsFound {\n\t\treturn fmt.Sprintf(\"%s/%s\", ns, nameTrimmed)\n\t}\n\n\treturn nameTrimmed\n}\n\nfunc injectToPodSpec(secretName string, podSpec *corev1.PodSpec) {\n\tpodSpec.Volumes = injectToVolumes(secretName, podSpec.Volumes)\n\tpodSpec.InitContainers = injectToContainers(podSpec.InitContainers)\n\tpodSpec.Containers = injectToContainers(podSpec.Containers)\n}\n\nfunc injectToVolumes(name string, volumes []corev1.Volume) []corev1.Volume {\n\tresult := make([]corev1.Volume, 0, len(volumes))\n\n\tfor _, volume := range volumes {\n\t\tif volume.Name != volumeName {\n\t\t\tresult = append(result, volume)\n\t\t}\n\t}\n\n\tresult = append(result, corev1.Volume{\n\t\tName: volumeName,\n\t\tVolumeSource: corev1.VolumeSource{\n\t\t\tSecret: &corev1.SecretVolumeSource{\n\t\t\t\tSecretName: name,\n\t\t\t},\n\t\t},\n\t})\n\n\treturn result\n}\n\nfunc injectToContainers(containers []corev1.Container) []corev1.Container {\n\tresult := make([]corev1.Container, 0, len(containers))\n\n\tfor _, container := range containers {\n\t\tinjectToContainer(&container)\n\n\t\tresult = append(result, container)\n\t}\n\n\treturn result\n}\n\nfunc injectToContainer(container *corev1.Container) {\n\tvolumeMounts := make([]corev1.VolumeMount, 0, len(container.VolumeMounts))\n\n\tfor _, mount := range container.VolumeMounts {\n\t\tif mount.Name != volumeName {\n\t\t\tvolumeMounts = append(volumeMounts, mount)\n\t\t}\n\t}\n\n\tvolumeMounts = append(volumeMounts, corev1.VolumeMount{\n\t\tName:      volumeName,\n\t\tMountPath: constants.ServiceAccountMountPath,\n\t})\n\n\tcontainer.VolumeMounts = volumeMounts\n\n\tif injectToEnv {\n\t\tcontainer.Env = injectToContainerEnv(container.Env)\n\t}\n}\n\nfunc injectToContainerEnv(env []corev1.EnvVar) []corev1.EnvVar {\n\tresult := make([]corev1.EnvVar, 0, len(env))\n\n\tfor _, envVar := range env {\n\t\tif envVar.Name != constants.TalosConfigEnvVar {\n\t\t\tresult = append(result, envVar)\n\t\t}\n\t}\n\n\tresult = append(result, corev1.EnvVar{\n\t\tName:  constants.TalosConfigEnvVar,\n\t\tValue: filepath.Join(constants.ServiceAccountMountPath, constants.TalosconfigFilename),\n\t})\n\n\treturn result\n}\n"
  },
  {
    "path": "pkg/kubernetes/klog.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"io\"\n\n\t\"k8s.io/klog/v2\"\n)\n\nfunc init() {\n\t// Kubernetes client likes to do calls to `klog` in random places which are not configurable.\n\t// For Talos this means those logs are going to the console which doesn't look good.\n\tklog.EnableContextualLogging(false)\n\tklog.SetOutput(io.Discard)\n\tklog.LogToStderr(false)\n}\n"
  },
  {
    "path": "pkg/kubernetes/kubelet/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubelet provides minimal client for the kubelet API.\npackage kubelet\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\tv1 \"k8s.io/api/core/v1\"\n\t\"k8s.io/apimachinery/pkg/runtime/serializer\"\n\t\"k8s.io/client-go/kubernetes/scheme\"\n\t\"k8s.io/client-go/rest\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Client is a kubelet API client.\n//\n// Client can only talk to the local kubelet on the same node.\ntype Client struct {\n\tclient *rest.RESTClient\n}\n\n// NewClient creates new kubelet API client.\nfunc NewClient(nodename string, clientCert, clientKey, caPEM []byte) (*Client, error) {\n\tconfig := &rest.Config{\n\t\tHost: fmt.Sprintf(\"https://127.0.0.1:%d/\", constants.KubeletPort),\n\t\tContentConfig: rest.ContentConfig{\n\t\t\tNegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: scheme.Codecs},\n\t\t},\n\n\t\tTLSClientConfig: rest.TLSClientConfig{\n\t\t\tCertData:   clientCert,\n\t\t\tKeyData:    clientKey,\n\t\t\tCAData:     caPEM,\n\t\t\tServerName: nodename,\n\t\t},\n\t}\n\n\tkubeletCert, err := os.ReadFile(filepath.Join(constants.KubeletPKIDir, \"kubelet.crt\"))\n\tif err == nil {\n\t\tconfig.CAData = append(config.CAData, kubeletCert...)\n\t} else if err != nil {\n\t\t// ignore if file doesn't exist, assume cert isn't self-signed\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, fmt.Errorf(\"error reading kubelet certificate: %w\", err)\n\t\t}\n\t}\n\n\tclient := &Client{}\n\n\tclient.client, err = rest.UnversionedRESTClientFor(config)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error building REST client: %w\", err)\n\t}\n\n\treturn client, nil\n}\n\n// Pods returns list of pods running on the kubelet.\nfunc (c *Client) Pods(ctx context.Context) (*PodList, error) {\n\tvar podList PodList\n\n\tbytes, err := c.client.Get().AbsPath(\"/pods/\").Timeout(30 * time.Second).Do(ctx).Raw()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = json.Unmarshal(bytes, &podList)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &podList, nil\n}\n\n// PodList is a list of pods.\ntype PodList struct {\n\tItems []Pod `json:\"items\"`\n}\n\n// Pod returns pod details.\ntype Pod struct {\n\tMetadata Metadata     `json:\"metadata\"`\n\tStatus   v1.PodStatus `json:\"status\"`\n}\n\n// Metadata is a pod metadata.\ntype Metadata struct {\n\tName        string      `json:\"name\"`\n\tNamespace   string      `json:\"namespace\"`\n\tAnnotations Annotations `json:\"annotations\"`\n}\n\n// Annotations are the annotations on a pod.\ntype Annotations struct {\n\t// ConfigMapSource indicates where the resource is coming from.\n\t// Its value is \"file\"/\"http\" for static pods and \"api\" for resources came from kube-apiserver.\n\tConfigSource string `json:\"kubernetes.io/config.source\"`\n}\n"
  },
  {
    "path": "pkg/kubernetes/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/url\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/controller\"\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/crypto/x509\"\n\ttaloskubernetes \"github.com/siderolabs/go-kubernetes/kubernetes\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"golang.org/x/sync/errgroup\"\n\tappsv1 \"k8s.io/api/apps/v1\"\n\tcorev1 \"k8s.io/api/core/v1\"\n\tpolicy \"k8s.io/api/policy/v1beta1\"\n\tapierrors \"k8s.io/apimachinery/pkg/api/errors\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/apimachinery/pkg/fields\"\n\trestclient \"k8s.io/client-go/rest\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nconst (\n\t// DrainTimeout is maximum time to wait for the node to be drained.\n\tDrainTimeout = 5 * time.Minute\n)\n\n// Client represents a set of helper methods for interacting with the\n// Kubernetes API.\ntype Client struct {\n\t*taloskubernetes.Client\n}\n\n// NewClientFromKubeletKubeconfig initializes and returns a Client.\nfunc NewClientFromKubeletKubeconfig() (*Client, error) {\n\tconfig, err := clientcmd.BuildConfigFromFlags(\"\", constants.KubeletKubeconfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewForConfig(config)\n}\n\nfunc loadPKIIntoVariable(data *[]byte, path *string) error {\n\tif len(*data) > 0 {\n\t\treturn nil\n\t}\n\n\tif *path == \"\" {\n\t\treturn fmt.Errorf(\"no certificate data or file provided\")\n\t}\n\n\tpkiData, err := os.ReadFile(*path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read certificate file: %w\", err)\n\t}\n\n\t*data = pkiData\n\t*path = \"\"\n\n\treturn nil\n}\n\n// NewForConfig initializes and returns a client using the provided config.\nfunc NewForConfig(config *restclient.Config) (*Client, error) {\n\t// read the certificates into byte slices to prevent the client from launching automatic\n\t// certificate reload\n\tif err := loadPKIIntoVariable(&config.TLSClientConfig.CAData, &config.TLSClientConfig.CAFile); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load CA certificate: %w\", err)\n\t}\n\n\tif err := loadPKIIntoVariable(&config.TLSClientConfig.CertData, &config.TLSClientConfig.CertFile); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load client certificate: %w\", err)\n\t}\n\n\tif err := loadPKIIntoVariable(&config.TLSClientConfig.KeyData, &config.TLSClientConfig.KeyFile); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load client key: %w\", err)\n\t}\n\n\t// now, initialize the client using the standard method\n\tclient, err := taloskubernetes.NewForConfig(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Client{\n\t\tClient: client,\n\t}, nil\n}\n\n// NewClientFromPKI initializes and returns a Client.\n//\n//nolint:interfacer\nfunc NewClientFromPKI(ca, crt, key []byte, endpoint *url.URL) (*Client, error) {\n\ttlsClientConfig := restclient.TLSClientConfig{\n\t\tCAData:   ca,\n\t\tCertData: crt,\n\t\tKeyData:  key,\n\t}\n\n\tconfig := &restclient.Config{\n\t\tHost:            endpoint.String(),\n\t\tTLSClientConfig: tlsClientConfig,\n\t\tTimeout:         30 * time.Second,\n\t}\n\n\treturn NewForConfig(config)\n}\n\n// NewTemporaryClientControlPlane initializes a Kubernetes client for a controlplane node\n// using PKI information.\n//\n// The client uses \"localhost\" endpoint, so it doesn't depend on the loadbalancer to be ready.\nfunc NewTemporaryClientControlPlane(ctx context.Context, r controller.Reader) (client *Client, err error) {\n\tk8sRoot, err := safe.ReaderGet[*secrets.KubernetesRoot](ctx, r, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesRootType, secrets.KubernetesRootID, resource.VersionUndefined))\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to get kubernetes config: %w\", err)\n\t}\n\n\tk8sRootSpec := k8sRoot.TypedSpec()\n\n\treturn NewTemporaryClientFromPKI(k8sRootSpec.IssuingCA, k8sRootSpec.LocalEndpoint)\n}\n\n// NewTemporaryClientFromPKI initializes a Kubernetes client using a certificate\n// with a TTL of 10 minutes.\nfunc NewTemporaryClientFromPKI(ca *x509.PEMEncodedCertificateAndKey, endpoint *url.URL) (client *Client, err error) {\n\topts := []x509.Option{\n\t\tx509.CommonName(constants.KubernetesAdminCertCommonName),\n\t\tx509.Organization(constants.KubernetesAdminCertOrganization),\n\t\tx509.NotBefore(time.Now().Add(-time.Minute)), // allow for a minute for the time to be not in sync across nodes\n\t\tx509.NotAfter(time.Now().Add(10 * time.Minute)),\n\t}\n\n\tk8sCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(ca)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed decoding Kubernetes CA: %w\", err)\n\t}\n\n\tkeyPair, err := x509.NewKeyPair(k8sCA, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed generating temporary cert: %w\", err)\n\t}\n\n\th, err := NewClientFromPKI(ca.Crt, keyPair.CrtPEM, keyPair.KeyPEM, endpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create client: %w\", err)\n\t}\n\n\treturn h, nil\n}\n\n// NodeIPs returns list of node IP addresses by machine type.\n//\n//nolint:gocyclo\nfunc (h *Client) NodeIPs(ctx context.Context, machineType machine.Type) (addrs []string, err error) {\n\tresp, err := h.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taddrs = []string{}\n\n\tfor _, node := range resp.Items {\n\t\t_, labelControlPlane := node.Labels[constants.LabelNodeRoleControlPlane]\n\n\t\tvar skip, foundInternalIP bool\n\n\t\tswitch machineType {\n\t\tcase machine.TypeInit, machine.TypeControlPlane:\n\t\t\tskip = !labelControlPlane\n\t\tcase machine.TypeWorker:\n\t\t\tskip = labelControlPlane\n\t\tcase machine.TypeUnknown:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"unexpected machine type %v\", machineType))\n\t\t}\n\n\t\tif skip {\n\t\t\tcontinue\n\t\t}\n\n\t\t// try to get the internal IP address\n\t\tfor _, nodeAddress := range node.Status.Addresses {\n\t\t\tif nodeAddress.Type == corev1.NodeInternalIP {\n\t\t\t\taddrs = append(addrs, nodeAddress.Address)\n\t\t\t\tfoundInternalIP = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !foundInternalIP {\n\t\t\t// no internal IP, fallback to external IP\n\t\t\tfor _, nodeAddress := range node.Status.Addresses {\n\t\t\t\tif nodeAddress.Type == corev1.NodeExternalIP {\n\t\t\t\t\taddrs = append(addrs, nodeAddress.Address)\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn addrs, nil\n}\n\n// Drain evicts all pods on a given node.\nfunc (h *Client) Drain(ctx context.Context, node string) error {\n\tctx, cancel := context.WithTimeout(ctx, DrainTimeout)\n\tdefer cancel()\n\n\topts := metav1.ListOptions{\n\t\tFieldSelector: fields.SelectorFromSet(fields.Set{\"spec.nodeName\": node}).String(),\n\t}\n\n\tpods, err := h.CoreV1().Pods(metav1.NamespaceAll).List(ctx, opts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get pods for node %s: %w\", node, err)\n\t}\n\n\tvar eg errgroup.Group\n\n\t// Evict each pod.\n\n\tfor _, pod := range pods.Items {\n\t\teg.Go(func() error {\n\t\t\tif _, ok := pod.ObjectMeta.Annotations[corev1.MirrorPodAnnotationKey]; ok {\n\t\t\t\tlog.Printf(\"skipping mirror pod %s/%s\\n\", pod.GetNamespace(), pod.GetName())\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tcontrollerRef := metav1.GetControllerOf(&pod)\n\n\t\t\tif controllerRef == nil {\n\t\t\t\tlog.Printf(\"skipping unmanaged pod %s/%s\\n\", pod.GetNamespace(), pod.GetName())\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif controllerRef.Kind == appsv1.SchemeGroupVersion.WithKind(\"DaemonSet\").Kind {\n\t\t\t\tlog.Printf(\"skipping DaemonSet pod %s/%s\\n\", pod.GetNamespace(), pod.GetName())\n\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tif !pod.DeletionTimestamp.IsZero() {\n\t\t\t\tlog.Printf(\"skipping deleted pod %s/%s\\n\", pod.GetNamespace(), pod.GetName())\n\t\t\t}\n\n\t\t\tif err := h.evict(ctx, pod, int64(60)); err != nil {\n\t\t\t\tlog.Printf(\"WARNING: failed to evict pod: %v\", err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\treturn eg.Wait()\n}\n\nfunc (h *Client) evict(ctx context.Context, p corev1.Pod, gracePeriod int64) error {\n\tfor {\n\t\tpol := &policy.Eviction{\n\t\t\tObjectMeta:    metav1.ObjectMeta{Namespace: p.GetNamespace(), Name: p.GetName()},\n\t\t\tDeleteOptions: &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod},\n\t\t}\n\t\terr := h.CoreV1().Pods(p.GetNamespace()).Evict(ctx, pol)\n\n\t\tswitch {\n\t\tcase apierrors.IsTooManyRequests(err):\n\t\t\ttime.Sleep(5 * time.Second)\n\t\tcase apierrors.IsNotFound(err):\n\t\t\treturn nil\n\t\tcase err != nil:\n\t\t\treturn fmt.Errorf(\"failed to evict pod %s/%s: %w\", p.GetNamespace(), p.GetName(), err)\n\t\tdefault:\n\t\t\tif err = h.waitForPodDeleted(ctx, &p); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed waiting on pod %s/%s to be deleted: %w\", p.GetNamespace(), p.GetName(), err)\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (h *Client) waitForPodDeleted(ctx context.Context, p *corev1.Pod) error {\n\treturn retry.Constant(time.Minute, retry.WithUnits(3*time.Second)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\tpod, err := h.CoreV1().Pods(p.GetNamespace()).Get(ctx, p.GetName(), metav1.GetOptions{})\n\n\t\tswitch {\n\t\tcase apierrors.IsNotFound(err):\n\t\t\treturn nil\n\t\tcase apierrors.IsForbidden(err):\n\t\t\t// in Kubernetes 1.32+, NodeRestriction plugin won't let us list a pod which is not on our node, including deleted ones\n\t\t\treturn nil\n\t\tcase err != nil:\n\t\t\tif IsRetryableError(err) {\n\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to get pod %s/%s: %w\", p.GetNamespace(), p.GetName(), err)\n\t\t}\n\n\t\tif pod.GetUID() != p.GetUID() {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn retry.ExpectedErrorf(\"pod is still running on the node\")\n\t})\n}\n"
  },
  {
    "path": "pkg/kubernetes/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes\n\nimport (\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/distribution/reference\"\n)\n\n// VersionGTE returns true if the version of the image is greater than or equal to the provided version.\n//\n// It supports any kind of image reference, but requires the tag to be present.\nfunc VersionGTE(image string, version semver.Version) bool {\n\timageRef, err := reference.ParseNormalizedNamed(image)\n\tif err != nil {\n\t\t// couldn't parse the reference, so we can't compare\n\t\treturn false\n\t}\n\n\ttaggedRef, ok := imageRef.(reference.Tagged)\n\tif !ok {\n\t\t// tag is missing\n\t\treturn false\n\t}\n\n\tvers, err := semver.ParseTolerant(taggedRef.Tag())\n\tif err != nil {\n\t\t// invalid version\n\t\treturn false\n\t}\n\n\tvers.Pre = nil // reset the pre-release version to compare only the version\n\n\treturn vers.GTE(version)\n}\n"
  },
  {
    "path": "pkg/kubernetes/version_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubernetes_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/kubernetes\"\n)\n\nfunc TestVersionGTE(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\timage   string\n\t\tversion semver.Version\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tname:    \"tagged image\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver:v1.30.0\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:    \"tagged image, not less\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver:v1.29.8\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"tagged image, alpha\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver:v1.30.0-alpha.3\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:    \"tagged and digested image\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver:v1.30.0@sha256:9efd51eb47ecdd66b9426d9361edca2cbed38d57c4fe9d81213867310a1fdd99\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid tag\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver:latest\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tname:    \"only digest\",\n\t\t\timage:   \"registry.k8s.io/kube-apiserver@sha256:9efd51eb47ecdd66b9426d9361edca2cbed38d57c4fe9d81213867310a1fdd99\",\n\t\t\tversion: semver.MustParse(\"1.30.0\"),\n\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\trequire.Equal(t, test.expected, kubernetes.VersionGTE(test.image, test.version))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/logging/error_suppress.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"sync/atomic\"\n\n\t\"go.uber.org/zap/zapcore\"\n)\n\n// NewControllerErrorSuppressor creates a new controller error suppressor.\n//\n// It suppresses error logs for a given controller unless it logs >= threshold errors.\n// The idea is that all controllers reconcile errors, so if the error is not transient,\n// it will be reported enough time to hit the threshold, but transient errors will be\n// suppressed.\n//\n// The suppressor records the controller name by inspecting a log field named \"controller\"\n// passed via `logger.With()` call.\nfunc NewControllerErrorSuppressor(core zapcore.Core, threshold int64) zapcore.Core {\n\treturn &consoleSampler{\n\t\tCore:      core,\n\t\tthreshold: threshold,\n\t}\n}\n\ntype consoleSampler struct {\n\tzapcore.Core\n\n\thits       *atomic.Int64\n\tthreshold  int64\n\tcontroller string\n}\n\nvar _ zapcore.Core = (*consoleSampler)(nil)\n\nfunc (s *consoleSampler) Level() zapcore.Level {\n\treturn zapcore.LevelOf(s.Core)\n}\n\nfunc (s *consoleSampler) With(fields []zapcore.Field) zapcore.Core {\n\tcontroller := s.controller\n\tnum := s.hits\n\n\tfor _, field := range fields {\n\t\tif field.Key == \"controller\" {\n\t\t\tif field.String != controller {\n\t\t\t\tcontroller = field.String\n\t\t\t\tnum = new(atomic.Int64)\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn &consoleSampler{\n\t\tthreshold:  s.threshold,\n\t\tcontroller: controller,\n\t\thits:       num,\n\t\tCore:       s.Core.With(fields),\n\t}\n}\n\nfunc (s *consoleSampler) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {\n\tif !s.Enabled(ent.Level) {\n\t\treturn ce\n\t}\n\n\tif ent.Level == zapcore.ErrorLevel && s.controller != \"\" {\n\t\tif s.hits.Add(1) <= s.threshold {\n\t\t\t// suppress the log\n\t\t\treturn ce\n\t\t}\n\t}\n\n\treturn s.Core.Check(ent, ce)\n}\n"
  },
  {
    "path": "pkg/logging/error_suppress_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.uber.org/zap/zapcore\"\n\t\"go.uber.org/zap/zaptest/observer\"\n\n\t\"github.com/siderolabs/talos/pkg/logging\"\n)\n\nfunc assertLogged(t *testing.T, core zapcore.Core, logs *observer.ObservedLogs, entries []zapcore.Entry, expectedCount int) {\n\tt.Helper()\n\n\tfor _, entry := range entries {\n\t\tif ce := core.Check(entry, nil); ce != nil {\n\t\t\tce.Write()\n\t\t}\n\t}\n\n\tassert.Len(t, logs.TakeAll(), expectedCount)\n}\n\nfunc TestErrorSuppressor(t *testing.T) {\n\tt.Parallel()\n\n\tcore, logs := observer.New(zapcore.InfoLevel)\n\n\tconst threshold = 2\n\n\tcore = logging.NewControllerErrorSuppressor(core, threshold)\n\n\t// warn/info messages are not affected\n\tassertLogged(t, core, logs, []zapcore.Entry{\n\t\t{Level: zapcore.InfoLevel, Message: \"abc\"},\n\t\t{Level: zapcore.WarnLevel, Message: \"def\"},\n\t\t{Level: zapcore.DebugLevel, Message: \"message\"}, // below level\n\t}, 2)\n\n\t// different controllers, suppress counters are independent\n\tcontrollerCore1 := core.With([]zapcore.Field{{Key: \"controller\", String: \"c1\"}})\n\tcontrollerCore2 := core.With([]zapcore.Field{{Key: \"controller\", String: \"c2\"}})\n\n\tassertLogged(t, controllerCore1, logs, []zapcore.Entry{\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // suppressed\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // suppressed\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"},\n\t}, 1)\n\n\tassertLogged(t, controllerCore2, logs, []zapcore.Entry{\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // suppressed\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // suppressed\n\t}, 0)\n\n\tassertLogged(t, controllerCore1, logs, []zapcore.Entry{\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // not suppressed, over threshold\n\t}, 1)\n\n\tassertLogged(t, controllerCore1.With([]zapcore.Field{{Key: \"foo\", String: \"bar\"}}), logs, []zapcore.Entry{\n\t\t{Level: zapcore.ErrorLevel, Message: \"controller failed\"}, // .With() without 'controller' field keeps the counter value from the parent\n\t}, 1)\n}\n"
  },
  {
    "path": "pkg/logging/logging.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package logging provides logging primitives.\npackage logging\n"
  },
  {
    "path": "pkg/logging/zap.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage logging\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n)\n\n// LogWriter is a wrapper around zap.Logger that implements io.Writer interface.\ntype LogWriter struct {\n\tdest  *zap.Logger\n\tlevel zapcore.Level\n}\n\n// NewWriter creates new log zap log writer.\nfunc NewWriter(l *zap.Logger, level zapcore.Level) io.Writer {\n\treturn &LogWriter{\n\t\tdest:  l,\n\t\tlevel: level,\n\t}\n}\n\n// Write implements io.Writer interface.\nfunc (lw *LogWriter) Write(line []byte) (int, error) {\n\tchecked := lw.dest.Check(lw.level, strings.TrimSpace(string(line)))\n\tif checked == nil {\n\t\treturn 0, nil\n\t}\n\n\tchecked.Write()\n\n\treturn len(line), nil\n}\n\n// logWrapper wraps around standard logger.\ntype logWrapper struct {\n\tlog *log.Logger\n}\n\n// Write implements io.Writer interface.\nfunc (lw *logWrapper) Write(line []byte) (int, error) {\n\tif lw.log == nil {\n\t\tlog.Print(string(line))\n\t} else {\n\t\tlw.log.Print(string(line))\n\t}\n\n\treturn len(line), nil\n}\n\n// StdWriter creates a sync writer that writes all logs to the std logger.\nvar StdWriter = &logWrapper{nil}\n\n// LogDestination defines logging destination Config.\ntype LogDestination struct {\n\t// Level log level.\n\tlevel             zapcore.LevelEnabler\n\twriter            io.Writer\n\tconfig            zapcore.EncoderConfig\n\tsuppressThreshold int64\n}\n\n// LogDestinationOption defines a log destination encoder config setter.\ntype LogDestinationOption func(dest *LogDestination)\n\n// WithoutTimestamp disables timestamp.\nfunc WithoutTimestamp() LogDestinationOption {\n\treturn func(dest *LogDestination) {\n\t\tdest.config.EncodeTime = nil\n\t}\n}\n\n// WithoutLogLevels disable log level.\nfunc WithoutLogLevels() LogDestinationOption {\n\treturn func(dest *LogDestination) {\n\t\tdest.config.EncodeLevel = nil\n\t}\n}\n\n// WithColoredLevels enables log level colored output.\nfunc WithColoredLevels() LogDestinationOption {\n\treturn func(dest *LogDestination) {\n\t\tdest.config.EncodeLevel = zapcore.CapitalColorLevelEncoder\n\t}\n}\n\n// WithControllerErrorSuppressor creates a new console log controller error suppressor.\nfunc WithControllerErrorSuppressor(threshold int64) LogDestinationOption {\n\treturn func(dest *LogDestination) {\n\t\tdest.suppressThreshold = threshold\n\t}\n}\n\n// NewLogDestination creates new log destination.\nfunc NewLogDestination(writer io.Writer, logLevel zapcore.LevelEnabler, options ...LogDestinationOption) *LogDestination {\n\tconfig := zap.NewDevelopmentEncoderConfig()\n\tconfig.ConsoleSeparator = \" \"\n\tconfig.StacktraceKey = \"error\"\n\n\tdest := &LogDestination{\n\t\tlevel:  logLevel,\n\t\tconfig: config,\n\t\twriter: writer,\n\t}\n\n\tfor _, option := range options {\n\t\toption(dest)\n\t}\n\n\treturn dest\n}\n\n// Wrap is a simple helper to wrap io.Writer with default arguments.\nfunc Wrap(writer io.Writer) *zap.Logger {\n\treturn ZapLogger(\n\t\tNewLogDestination(writer, zapcore.DebugLevel),\n\t)\n}\n\n// ZapLogger creates new default Zap Logger.\nfunc ZapLogger(dests ...*LogDestination) *zap.Logger {\n\tif len(dests) == 0 {\n\t\tpanic(\"at least one writer must be defined\")\n\t}\n\n\tcores := xslices.Map(dests, func(dest *LogDestination) zapcore.Core {\n\t\tcore := zapcore.NewCore(\n\t\t\tzapcore.NewConsoleEncoder(dest.config),\n\t\t\tzapcore.AddSync(dest.writer),\n\t\t\tdest.level,\n\t\t)\n\n\t\tif dest.suppressThreshold > 0 {\n\t\t\tcore = NewControllerErrorSuppressor(core, dest.suppressThreshold)\n\t\t}\n\n\t\treturn core\n\t})\n\n\treturn zap.New(zapcore.NewTee(cores...))\n}\n\n// Component helper for creating zap.Field.\nfunc Component(name string) zapcore.Field {\n\treturn zap.String(\"component\", name)\n}\n"
  },
  {
    "path": "pkg/machinery/api/api.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package api contains API definitions for Talos Linux.\n//\n//nolint:revive\npackage api\n\nimport (\n\tcosi \"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/time\"\n)\n\n// TalosAPIdOne2ManyAPIs returns a list of API services that support one-to-many\n// communication pattern served by apid.\n//\n// Note: we are moving to one-to-one APIs, so this list should not grow.\nfunc TalosAPIdOne2ManyAPIs() []protoreflect.FileDescriptor {\n\treturn []protoreflect.FileDescriptor{\n\t\tcommon.File_common_common_proto,\n\t\tcluster.File_cluster_cluster_proto,\n\t\tinspect.File_inspect_inspect_proto,\n\t\tmachine.File_machine_machine_proto,\n\t\tstorage.File_storage_storage_proto,\n\t\ttime.File_time_time_proto,\n\t}\n}\n\n// TalosAPIdAllAPIs returns a list of all API services served by apid.\n//\n// This includes legacy one-to-many APIs as well as newer one-to-one APIs.\nfunc TalosAPIdAllAPIs() []protoreflect.FileDescriptor {\n\treturn append(TalosAPIdOne2ManyAPIs(),\n\t\tcosi.File_v1alpha1_state_proto,\n\t\tmachine.File_machine_debug_proto,\n\t\tmachine.File_machine_image_proto,\n\t\tmachine.File_machine_lifecycle_proto,\n\t)\n}\n\n// AllAPIs returns a list of all API services served by Talos components.\n//\n// This includes Talos apid and trustd APIs.\nfunc AllAPIs() []protoreflect.FileDescriptor {\n\treturn append(TalosAPIdAllAPIs(),\n\t\tsecurity.File_security_security_proto,\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/api/cluster/cluster.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: cluster/cluster.proto\n\npackage cluster\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype HealthCheckRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tWaitTimeout   *durationpb.Duration   `protobuf:\"bytes,1,opt,name=wait_timeout,json=waitTimeout,proto3\" json:\"wait_timeout,omitempty\"`\n\tClusterInfo   *ClusterInfo           `protobuf:\"bytes,2,opt,name=cluster_info,json=clusterInfo,proto3\" json:\"cluster_info,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HealthCheckRequest) Reset() {\n\t*x = HealthCheckRequest{}\n\tmi := &file_cluster_cluster_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HealthCheckRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HealthCheckRequest) ProtoMessage() {}\n\nfunc (x *HealthCheckRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_cluster_cluster_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead.\nfunc (*HealthCheckRequest) Descriptor() ([]byte, []int) {\n\treturn file_cluster_cluster_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *HealthCheckRequest) GetWaitTimeout() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.WaitTimeout\n\t}\n\treturn nil\n}\n\nfunc (x *HealthCheckRequest) GetClusterInfo() *ClusterInfo {\n\tif x != nil {\n\t\treturn x.ClusterInfo\n\t}\n\treturn nil\n}\n\ntype ClusterInfo struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tControlPlaneNodes []string               `protobuf:\"bytes,1,rep,name=control_plane_nodes,json=controlPlaneNodes,proto3\" json:\"control_plane_nodes,omitempty\"`\n\tWorkerNodes       []string               `protobuf:\"bytes,2,rep,name=worker_nodes,json=workerNodes,proto3\" json:\"worker_nodes,omitempty\"`\n\tForceEndpoint     string                 `protobuf:\"bytes,3,opt,name=force_endpoint,json=forceEndpoint,proto3\" json:\"force_endpoint,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *ClusterInfo) Reset() {\n\t*x = ClusterInfo{}\n\tmi := &file_cluster_cluster_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ClusterInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClusterInfo) ProtoMessage() {}\n\nfunc (x *ClusterInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_cluster_cluster_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClusterInfo.ProtoReflect.Descriptor instead.\nfunc (*ClusterInfo) Descriptor() ([]byte, []int) {\n\treturn file_cluster_cluster_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ClusterInfo) GetControlPlaneNodes() []string {\n\tif x != nil {\n\t\treturn x.ControlPlaneNodes\n\t}\n\treturn nil\n}\n\nfunc (x *ClusterInfo) GetWorkerNodes() []string {\n\tif x != nil {\n\t\treturn x.WorkerNodes\n\t}\n\treturn nil\n}\n\nfunc (x *ClusterInfo) GetForceEndpoint() string {\n\tif x != nil {\n\t\treturn x.ForceEndpoint\n\t}\n\treturn \"\"\n}\n\ntype HealthCheckProgress struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMessage       string                 `protobuf:\"bytes,2,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HealthCheckProgress) Reset() {\n\t*x = HealthCheckProgress{}\n\tmi := &file_cluster_cluster_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HealthCheckProgress) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HealthCheckProgress) ProtoMessage() {}\n\nfunc (x *HealthCheckProgress) ProtoReflect() protoreflect.Message {\n\tmi := &file_cluster_cluster_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HealthCheckProgress.ProtoReflect.Descriptor instead.\nfunc (*HealthCheckProgress) Descriptor() ([]byte, []int) {\n\treturn file_cluster_cluster_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *HealthCheckProgress) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *HealthCheckProgress) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nvar File_cluster_cluster_proto protoreflect.FileDescriptor\n\nconst file_cluster_cluster_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x15cluster/cluster.proto\\x12\\acluster\\x1a\\x13common/common.proto\\x1a\\x1egoogle/protobuf/duration.proto\\\"\\x8b\\x01\\n\" +\n\t\"\\x12HealthCheckRequest\\x12<\\n\" +\n\t\"\\fwait_timeout\\x18\\x01 \\x01(\\v2\\x19.google.protobuf.DurationR\\vwaitTimeout\\x127\\n\" +\n\t\"\\fcluster_info\\x18\\x02 \\x01(\\v2\\x14.cluster.ClusterInfoR\\vclusterInfo\\\"\\x87\\x01\\n\" +\n\t\"\\vClusterInfo\\x12.\\n\" +\n\t\"\\x13control_plane_nodes\\x18\\x01 \\x03(\\tR\\x11controlPlaneNodes\\x12!\\n\" +\n\t\"\\fworker_nodes\\x18\\x02 \\x03(\\tR\\vworkerNodes\\x12%\\n\" +\n\t\"\\x0eforce_endpoint\\x18\\x03 \\x01(\\tR\\rforceEndpoint\\\"]\\n\" +\n\t\"\\x13HealthCheckProgress\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x18\\n\" +\n\t\"\\amessage\\x18\\x02 \\x01(\\tR\\amessage2\\\\\\n\" +\n\t\"\\x0eClusterService\\x12J\\n\" +\n\t\"\\vHealthCheck\\x12\\x1b.cluster.HealthCheckRequest\\x1a\\x1c.cluster.HealthCheckProgress0\\x01BN\\n\" +\n\t\"\\x15dev.talos.api.clusterZ5github.com/siderolabs/talos/pkg/machinery/api/clusterb\\x06proto3\"\n\nvar (\n\tfile_cluster_cluster_proto_rawDescOnce sync.Once\n\tfile_cluster_cluster_proto_rawDescData []byte\n)\n\nfunc file_cluster_cluster_proto_rawDescGZIP() []byte {\n\tfile_cluster_cluster_proto_rawDescOnce.Do(func() {\n\t\tfile_cluster_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_cluster_cluster_proto_rawDesc), len(file_cluster_cluster_proto_rawDesc)))\n\t})\n\treturn file_cluster_cluster_proto_rawDescData\n}\n\nvar file_cluster_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_cluster_cluster_proto_goTypes = []any{\n\t(*HealthCheckRequest)(nil),  // 0: cluster.HealthCheckRequest\n\t(*ClusterInfo)(nil),         // 1: cluster.ClusterInfo\n\t(*HealthCheckProgress)(nil), // 2: cluster.HealthCheckProgress\n\t(*durationpb.Duration)(nil), // 3: google.protobuf.Duration\n\t(*common.Metadata)(nil),     // 4: common.Metadata\n}\nvar file_cluster_cluster_proto_depIdxs = []int32{\n\t3, // 0: cluster.HealthCheckRequest.wait_timeout:type_name -> google.protobuf.Duration\n\t1, // 1: cluster.HealthCheckRequest.cluster_info:type_name -> cluster.ClusterInfo\n\t4, // 2: cluster.HealthCheckProgress.metadata:type_name -> common.Metadata\n\t0, // 3: cluster.ClusterService.HealthCheck:input_type -> cluster.HealthCheckRequest\n\t2, // 4: cluster.ClusterService.HealthCheck:output_type -> cluster.HealthCheckProgress\n\t4, // [4:5] is the sub-list for method output_type\n\t3, // [3:4] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_cluster_cluster_proto_init() }\nfunc file_cluster_cluster_proto_init() {\n\tif File_cluster_cluster_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_cluster_cluster_proto_rawDesc), len(file_cluster_cluster_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_cluster_cluster_proto_goTypes,\n\t\tDependencyIndexes: file_cluster_cluster_proto_depIdxs,\n\t\tMessageInfos:      file_cluster_cluster_proto_msgTypes,\n\t}.Build()\n\tFile_cluster_cluster_proto = out.File\n\tfile_cluster_cluster_proto_goTypes = nil\n\tfile_cluster_cluster_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/cluster/cluster_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: cluster/cluster.proto\n\npackage cluster\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tClusterService_HealthCheck_FullMethodName = \"/cluster.ClusterService/HealthCheck\"\n)\n\n// ClusterServiceClient is the client API for ClusterService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The cluster service definition.\ntype ClusterServiceClient interface {\n\tHealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[HealthCheckProgress], error)\n}\n\ntype clusterServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewClusterServiceClient(cc grpc.ClientConnInterface) ClusterServiceClient {\n\treturn &clusterServiceClient{cc}\n}\n\nfunc (c *clusterServiceClient) HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[HealthCheckProgress], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &ClusterService_ServiceDesc.Streams[0], ClusterService_HealthCheck_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[HealthCheckRequest, HealthCheckProgress]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ClusterService_HealthCheckClient = grpc.ServerStreamingClient[HealthCheckProgress]\n\n// ClusterServiceServer is the server API for ClusterService service.\n// All implementations must embed UnimplementedClusterServiceServer\n// for forward compatibility.\n//\n// The cluster service definition.\ntype ClusterServiceServer interface {\n\tHealthCheck(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckProgress]) error\n\tmustEmbedUnimplementedClusterServiceServer()\n}\n\n// UnimplementedClusterServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedClusterServiceServer struct{}\n\nfunc (UnimplementedClusterServiceServer) HealthCheck(*HealthCheckRequest, grpc.ServerStreamingServer[HealthCheckProgress]) error {\n\treturn status.Error(codes.Unimplemented, \"method HealthCheck not implemented\")\n}\nfunc (UnimplementedClusterServiceServer) mustEmbedUnimplementedClusterServiceServer() {}\nfunc (UnimplementedClusterServiceServer) testEmbeddedByValue()                        {}\n\n// UnsafeClusterServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to ClusterServiceServer will\n// result in compilation errors.\ntype UnsafeClusterServiceServer interface {\n\tmustEmbedUnimplementedClusterServiceServer()\n}\n\nfunc RegisterClusterServiceServer(s grpc.ServiceRegistrar, srv ClusterServiceServer) {\n\t// If the following call panics, it indicates UnimplementedClusterServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&ClusterService_ServiceDesc, srv)\n}\n\nfunc _ClusterService_HealthCheck_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(HealthCheckRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(ClusterServiceServer).HealthCheck(m, &grpc.GenericServerStream[HealthCheckRequest, HealthCheckProgress]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ClusterService_HealthCheckServer = grpc.ServerStreamingServer[HealthCheckProgress]\n\n// ClusterService_ServiceDesc is the grpc.ServiceDesc for ClusterService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar ClusterService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"cluster.ClusterService\",\n\tHandlerType: (*ClusterServiceServer)(nil),\n\tMethods:     []grpc.MethodDesc{},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"HealthCheck\",\n\t\t\tHandler:       _ClusterService_HealthCheck_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"cluster/cluster.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/cluster/cluster_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: cluster/cluster.proto\n\npackage cluster\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *HealthCheckRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HealthCheckRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HealthCheckRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClusterInfo != nil {\n\t\tsize, err := m.ClusterInfo.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.WaitTimeout != nil {\n\t\tsize, err := (*durationpb.Duration)(m.WaitTimeout).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ClusterInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ClusterInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ClusterInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ForceEndpoint) > 0 {\n\t\ti -= len(m.ForceEndpoint)\n\t\tcopy(dAtA[i:], m.ForceEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ForceEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.WorkerNodes) > 0 {\n\t\tfor iNdEx := len(m.WorkerNodes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.WorkerNodes[iNdEx])\n\t\t\tcopy(dAtA[i:], m.WorkerNodes[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.WorkerNodes[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.ControlPlaneNodes) > 0 {\n\t\tfor iNdEx := len(m.ControlPlaneNodes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ControlPlaneNodes[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ControlPlaneNodes[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ControlPlaneNodes[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HealthCheckProgress) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HealthCheckProgress) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HealthCheckProgress) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Message) > 0 {\n\t\ti -= len(m.Message)\n\t\tcopy(dAtA[i:], m.Message)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HealthCheckRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.WaitTimeout != nil {\n\t\tl = (*durationpb.Duration)(m.WaitTimeout).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClusterInfo != nil {\n\t\tl = m.ClusterInfo.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ClusterInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.ControlPlaneNodes) > 0 {\n\t\tfor _, s := range m.ControlPlaneNodes {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.WorkerNodes) > 0 {\n\t\tfor _, s := range m.WorkerNodes {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.ForceEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HealthCheckProgress) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Message)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HealthCheckRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HealthCheckRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HealthCheckRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WaitTimeout\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.WaitTimeout == nil {\n\t\t\t\tm.WaitTimeout = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.WaitTimeout).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterInfo\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClusterInfo == nil {\n\t\t\t\tm.ClusterInfo = &ClusterInfo{}\n\t\t\t}\n\t\t\tif err := m.ClusterInfo.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ClusterInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControlPlaneNodes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ControlPlaneNodes = append(m.ControlPlaneNodes, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WorkerNodes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.WorkerNodes = append(m.WorkerNodes, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ForceEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ForceEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HealthCheckProgress) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HealthCheckProgress: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HealthCheckProgress: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Message = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/common/common.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: common/common.proto\n\npackage common\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tstatus \"google.golang.org/genproto/googleapis/rpc/status\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdescriptorpb \"google.golang.org/protobuf/types/descriptorpb\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype Code int32\n\nconst (\n\tCode_FATAL    Code = 0\n\tCode_LOCKED   Code = 1\n\tCode_CANCELED Code = 2\n)\n\n// Enum value maps for Code.\nvar (\n\tCode_name = map[int32]string{\n\t\t0: \"FATAL\",\n\t\t1: \"LOCKED\",\n\t\t2: \"CANCELED\",\n\t}\n\tCode_value = map[string]int32{\n\t\t\"FATAL\":    0,\n\t\t\"LOCKED\":   1,\n\t\t\"CANCELED\": 2,\n\t}\n)\n\nfunc (x Code) Enum() *Code {\n\tp := new(Code)\n\t*p = x\n\treturn p\n}\n\nfunc (x Code) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Code) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_common_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Code) Type() protoreflect.EnumType {\n\treturn &file_common_common_proto_enumTypes[0]\n}\n\nfunc (x Code) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Code.Descriptor instead.\nfunc (Code) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{0}\n}\n\ntype ContainerDriver int32\n\nconst (\n\tContainerDriver_CONTAINERD ContainerDriver = 0\n\tContainerDriver_CRI        ContainerDriver = 1\n)\n\n// Enum value maps for ContainerDriver.\nvar (\n\tContainerDriver_name = map[int32]string{\n\t\t0: \"CONTAINERD\",\n\t\t1: \"CRI\",\n\t}\n\tContainerDriver_value = map[string]int32{\n\t\t\"CONTAINERD\": 0,\n\t\t\"CRI\":        1,\n\t}\n)\n\nfunc (x ContainerDriver) Enum() *ContainerDriver {\n\tp := new(ContainerDriver)\n\t*p = x\n\treturn p\n}\n\nfunc (x ContainerDriver) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ContainerDriver) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_common_proto_enumTypes[1].Descriptor()\n}\n\nfunc (ContainerDriver) Type() protoreflect.EnumType {\n\treturn &file_common_common_proto_enumTypes[1]\n}\n\nfunc (x ContainerDriver) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ContainerDriver.Descriptor instead.\nfunc (ContainerDriver) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{1}\n}\n\ntype ContainerdNamespace int32\n\nconst (\n\tContainerdNamespace_NS_UNKNOWN ContainerdNamespace = 0\n\tContainerdNamespace_NS_SYSTEM  ContainerdNamespace = 1\n\tContainerdNamespace_NS_CRI     ContainerdNamespace = 2\n)\n\n// Enum value maps for ContainerdNamespace.\nvar (\n\tContainerdNamespace_name = map[int32]string{\n\t\t0: \"NS_UNKNOWN\",\n\t\t1: \"NS_SYSTEM\",\n\t\t2: \"NS_CRI\",\n\t}\n\tContainerdNamespace_value = map[string]int32{\n\t\t\"NS_UNKNOWN\": 0,\n\t\t\"NS_SYSTEM\":  1,\n\t\t\"NS_CRI\":     2,\n\t}\n)\n\nfunc (x ContainerdNamespace) Enum() *ContainerdNamespace {\n\tp := new(ContainerdNamespace)\n\t*p = x\n\treturn p\n}\n\nfunc (x ContainerdNamespace) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ContainerdNamespace) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_common_common_proto_enumTypes[2].Descriptor()\n}\n\nfunc (ContainerdNamespace) Type() protoreflect.EnumType {\n\treturn &file_common_common_proto_enumTypes[2]\n}\n\nfunc (x ContainerdNamespace) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ContainerdNamespace.Descriptor instead.\nfunc (ContainerdNamespace) EnumDescriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{2}\n}\n\ntype Error struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCode          Code                   `protobuf:\"varint,1,opt,name=code,proto3,enum=common.Code\" json:\"code,omitempty\"`\n\tMessage       string                 `protobuf:\"bytes,2,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tDetails       []*anypb.Any           `protobuf:\"bytes,3,rep,name=details,proto3\" json:\"details,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Error) Reset() {\n\t*x = Error{}\n\tmi := &file_common_common_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Error) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Error) ProtoMessage() {}\n\nfunc (x *Error) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Error.ProtoReflect.Descriptor instead.\nfunc (*Error) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Error) GetCode() Code {\n\tif x != nil {\n\t\treturn x.Code\n\t}\n\treturn Code_FATAL\n}\n\nfunc (x *Error) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nfunc (x *Error) GetDetails() []*anypb.Any {\n\tif x != nil {\n\t\treturn x.Details\n\t}\n\treturn nil\n}\n\n// Common metadata message nested in all reply message types\ntype Metadata struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// hostname of the server response comes from (injected by proxy)\n\tHostname string `protobuf:\"bytes,1,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\t// error is set if request failed to the upstream (rest of response is\n\t// undefined)\n\tError string `protobuf:\"bytes,2,opt,name=error,proto3\" json:\"error,omitempty\"`\n\t// error as gRPC Status\n\tStatus        *status.Status `protobuf:\"bytes,3,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Metadata) Reset() {\n\t*x = Metadata{}\n\tmi := &file_common_common_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Metadata) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Metadata) ProtoMessage() {}\n\nfunc (x *Metadata) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.\nfunc (*Metadata) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Metadata) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetStatus() *status.Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\ntype Data struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *Metadata              `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tBytes         []byte                 `protobuf:\"bytes,2,opt,name=bytes,proto3\" json:\"bytes,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Data) Reset() {\n\t*x = Data{}\n\tmi := &file_common_common_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Data) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Data) ProtoMessage() {}\n\nfunc (x *Data) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Data.ProtoReflect.Descriptor instead.\nfunc (*Data) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Data) GetMetadata() *Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Data) GetBytes() []byte {\n\tif x != nil {\n\t\treturn x.Bytes\n\t}\n\treturn nil\n}\n\ntype DataResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Data                `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DataResponse) Reset() {\n\t*x = DataResponse{}\n\tmi := &file_common_common_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DataResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DataResponse) ProtoMessage() {}\n\nfunc (x *DataResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DataResponse.ProtoReflect.Descriptor instead.\nfunc (*DataResponse) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *DataResponse) GetMessages() []*Data {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype Empty struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *Metadata              `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Empty) Reset() {\n\t*x = Empty{}\n\tmi := &file_common_common_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Empty) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Empty) ProtoMessage() {}\n\nfunc (x *Empty) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Empty.ProtoReflect.Descriptor instead.\nfunc (*Empty) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *Empty) GetMetadata() *Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EmptyResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Empty               `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EmptyResponse) Reset() {\n\t*x = EmptyResponse{}\n\tmi := &file_common_common_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EmptyResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EmptyResponse) ProtoMessage() {}\n\nfunc (x *EmptyResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EmptyResponse.ProtoReflect.Descriptor instead.\nfunc (*EmptyResponse) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *EmptyResponse) GetMessages() []*Empty {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ContainerdInstance struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Containerd instance to use.\n\tDriver ContainerDriver `protobuf:\"varint,1,opt,name=driver,proto3,enum=common.ContainerDriver\" json:\"driver,omitempty\"`\n\t// Containerd namespace to use.\n\tNamespace     ContainerdNamespace `protobuf:\"varint,2,opt,name=namespace,proto3,enum=common.ContainerdNamespace\" json:\"namespace,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ContainerdInstance) Reset() {\n\t*x = ContainerdInstance{}\n\tmi := &file_common_common_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ContainerdInstance) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ContainerdInstance) ProtoMessage() {}\n\nfunc (x *ContainerdInstance) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ContainerdInstance.ProtoReflect.Descriptor instead.\nfunc (*ContainerdInstance) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ContainerdInstance) GetDriver() ContainerDriver {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn ContainerDriver_CONTAINERD\n}\n\nfunc (x *ContainerdInstance) GetNamespace() ContainerdNamespace {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn ContainerdNamespace_NS_UNKNOWN\n}\n\ntype URL struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tFullPath      string                 `protobuf:\"bytes,1,opt,name=full_path,json=fullPath,proto3\" json:\"full_path,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *URL) Reset() {\n\t*x = URL{}\n\tmi := &file_common_common_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *URL) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*URL) ProtoMessage() {}\n\nfunc (x *URL) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use URL.ProtoReflect.Descriptor instead.\nfunc (*URL) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *URL) GetFullPath() string {\n\tif x != nil {\n\t\treturn x.FullPath\n\t}\n\treturn \"\"\n}\n\ntype PEMEncodedCertificateAndKey struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCrt           []byte                 `protobuf:\"bytes,1,opt,name=crt,proto3\" json:\"crt,omitempty\"`\n\tKey           []byte                 `protobuf:\"bytes,2,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PEMEncodedCertificateAndKey) Reset() {\n\t*x = PEMEncodedCertificateAndKey{}\n\tmi := &file_common_common_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PEMEncodedCertificateAndKey) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PEMEncodedCertificateAndKey) ProtoMessage() {}\n\nfunc (x *PEMEncodedCertificateAndKey) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PEMEncodedCertificateAndKey.ProtoReflect.Descriptor instead.\nfunc (*PEMEncodedCertificateAndKey) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *PEMEncodedCertificateAndKey) GetCrt() []byte {\n\tif x != nil {\n\t\treturn x.Crt\n\t}\n\treturn nil\n}\n\nfunc (x *PEMEncodedCertificateAndKey) GetKey() []byte {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn nil\n}\n\ntype PEMEncodedKey struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           []byte                 `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PEMEncodedKey) Reset() {\n\t*x = PEMEncodedKey{}\n\tmi := &file_common_common_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PEMEncodedKey) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PEMEncodedKey) ProtoMessage() {}\n\nfunc (x *PEMEncodedKey) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PEMEncodedKey.ProtoReflect.Descriptor instead.\nfunc (*PEMEncodedKey) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *PEMEncodedKey) GetKey() []byte {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn nil\n}\n\ntype PEMEncodedCertificate struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCrt           []byte                 `protobuf:\"bytes,1,opt,name=crt,proto3\" json:\"crt,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PEMEncodedCertificate) Reset() {\n\t*x = PEMEncodedCertificate{}\n\tmi := &file_common_common_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PEMEncodedCertificate) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PEMEncodedCertificate) ProtoMessage() {}\n\nfunc (x *PEMEncodedCertificate) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PEMEncodedCertificate.ProtoReflect.Descriptor instead.\nfunc (*PEMEncodedCertificate) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *PEMEncodedCertificate) GetCrt() []byte {\n\tif x != nil {\n\t\treturn x.Crt\n\t}\n\treturn nil\n}\n\ntype NetIP struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIp            []byte                 `protobuf:\"bytes,1,opt,name=ip,proto3\" json:\"ip,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetIP) Reset() {\n\t*x = NetIP{}\n\tmi := &file_common_common_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetIP) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetIP) ProtoMessage() {}\n\nfunc (x *NetIP) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetIP.ProtoReflect.Descriptor instead.\nfunc (*NetIP) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *NetIP) GetIp() []byte {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\ntype NetIPPort struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIp            []byte                 `protobuf:\"bytes,1,opt,name=ip,proto3\" json:\"ip,omitempty\"`\n\tPort          int32                  `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetIPPort) Reset() {\n\t*x = NetIPPort{}\n\tmi := &file_common_common_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetIPPort) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetIPPort) ProtoMessage() {}\n\nfunc (x *NetIPPort) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetIPPort.ProtoReflect.Descriptor instead.\nfunc (*NetIPPort) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *NetIPPort) GetIp() []byte {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *NetIPPort) GetPort() int32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\ntype NetIPPrefix struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIp            []byte                 `protobuf:\"bytes,1,opt,name=ip,proto3\" json:\"ip,omitempty\"`\n\tPrefixLength  int32                  `protobuf:\"varint,2,opt,name=prefix_length,json=prefixLength,proto3\" json:\"prefix_length,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetIPPrefix) Reset() {\n\t*x = NetIPPrefix{}\n\tmi := &file_common_common_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetIPPrefix) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetIPPrefix) ProtoMessage() {}\n\nfunc (x *NetIPPrefix) ProtoReflect() protoreflect.Message {\n\tmi := &file_common_common_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetIPPrefix.ProtoReflect.Descriptor instead.\nfunc (*NetIPPrefix) Descriptor() ([]byte, []int) {\n\treturn file_common_common_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *NetIPPrefix) GetIp() []byte {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *NetIPPrefix) GetPrefixLength() int32 {\n\tif x != nil {\n\t\treturn x.PrefixLength\n\t}\n\treturn 0\n}\n\nvar file_common_common_proto_extTypes = []protoimpl.ExtensionInfo{\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_message\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_message\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_field\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_field\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_enum\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_enum\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumValueOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_enum_value\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_enum_value\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MethodOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_method\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_method\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.ServiceOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         93117,\n\t\tName:          \"common.remove_deprecated_service\",\n\t\tTag:           \"bytes,93117,opt,name=remove_deprecated_service\",\n\t\tFilename:      \"common/common.proto\",\n\t},\n}\n\n// Extension fields to descriptorpb.MessageOptions.\nvar (\n\t// Indicates the Talos version when this deprecated message will be removed from API.\n\t//\n\t// optional string remove_deprecated_message = 93117;\n\tE_RemoveDeprecatedMessage = &file_common_common_proto_extTypes[0]\n)\n\n// Extension fields to descriptorpb.FieldOptions.\nvar (\n\t// Indicates the Talos version when this deprecated filed will be removed from API.\n\t//\n\t// optional string remove_deprecated_field = 93117;\n\tE_RemoveDeprecatedField = &file_common_common_proto_extTypes[1]\n)\n\n// Extension fields to descriptorpb.EnumOptions.\nvar (\n\t// Indicates the Talos version when this deprecated enum will be removed from API.\n\t//\n\t// optional string remove_deprecated_enum = 93117;\n\tE_RemoveDeprecatedEnum = &file_common_common_proto_extTypes[2]\n)\n\n// Extension fields to descriptorpb.EnumValueOptions.\nvar (\n\t// Indicates the Talos version when this deprecated enum value will be removed from API.\n\t//\n\t// optional string remove_deprecated_enum_value = 93117;\n\tE_RemoveDeprecatedEnumValue = &file_common_common_proto_extTypes[3]\n)\n\n// Extension fields to descriptorpb.MethodOptions.\nvar (\n\t// Indicates the Talos version when this deprecated method will be removed from API.\n\t//\n\t// optional string remove_deprecated_method = 93117;\n\tE_RemoveDeprecatedMethod = &file_common_common_proto_extTypes[4]\n)\n\n// Extension fields to descriptorpb.ServiceOptions.\nvar (\n\t// Indicates the Talos version when this deprecated service will be removed from API.\n\t//\n\t// optional string remove_deprecated_service = 93117;\n\tE_RemoveDeprecatedService = &file_common_common_proto_extTypes[5]\n)\n\nvar File_common_common_proto protoreflect.FileDescriptor\n\nconst file_common_common_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x13common/common.proto\\x12\\x06common\\x1a\\x19google/protobuf/any.proto\\x1a google/protobuf/descriptor.proto\\x1a\\x17google/rpc/status.proto\\\"s\\n\" +\n\t\"\\x05Error\\x12 \\n\" +\n\t\"\\x04code\\x18\\x01 \\x01(\\x0e2\\f.common.CodeR\\x04code\\x12\\x18\\n\" +\n\t\"\\amessage\\x18\\x02 \\x01(\\tR\\amessage\\x12.\\n\" +\n\t\"\\adetails\\x18\\x03 \\x03(\\v2\\x14.google.protobuf.AnyR\\adetails\\\"h\\n\" +\n\t\"\\bMetadata\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x01 \\x01(\\tR\\bhostname\\x12\\x14\\n\" +\n\t\"\\x05error\\x18\\x02 \\x01(\\tR\\x05error\\x12*\\n\" +\n\t\"\\x06status\\x18\\x03 \\x01(\\v2\\x12.google.rpc.StatusR\\x06status\\\"J\\n\" +\n\t\"\\x04Data\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x14\\n\" +\n\t\"\\x05bytes\\x18\\x02 \\x01(\\fR\\x05bytes\\\"8\\n\" +\n\t\"\\fDataResponse\\x12(\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\f.common.DataR\\bmessages\\\"5\\n\" +\n\t\"\\x05Empty\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\":\\n\" +\n\t\"\\rEmptyResponse\\x12)\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\r.common.EmptyR\\bmessages\\\"\\x80\\x01\\n\" +\n\t\"\\x12ContainerdInstance\\x12/\\n\" +\n\t\"\\x06driver\\x18\\x01 \\x01(\\x0e2\\x17.common.ContainerDriverR\\x06driver\\x129\\n\" +\n\t\"\\tnamespace\\x18\\x02 \\x01(\\x0e2\\x1b.common.ContainerdNamespaceR\\tnamespace\\\"\\\"\\n\" +\n\t\"\\x03URL\\x12\\x1b\\n\" +\n\t\"\\tfull_path\\x18\\x01 \\x01(\\tR\\bfullPath\\\"A\\n\" +\n\t\"\\x1bPEMEncodedCertificateAndKey\\x12\\x10\\n\" +\n\t\"\\x03crt\\x18\\x01 \\x01(\\fR\\x03crt\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x02 \\x01(\\fR\\x03key\\\"!\\n\" +\n\t\"\\rPEMEncodedKey\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\fR\\x03key\\\")\\n\" +\n\t\"\\x15PEMEncodedCertificate\\x12\\x10\\n\" +\n\t\"\\x03crt\\x18\\x01 \\x01(\\fR\\x03crt\\\"\\x17\\n\" +\n\t\"\\x05NetIP\\x12\\x0e\\n\" +\n\t\"\\x02ip\\x18\\x01 \\x01(\\fR\\x02ip\\\"/\\n\" +\n\t\"\\tNetIPPort\\x12\\x0e\\n\" +\n\t\"\\x02ip\\x18\\x01 \\x01(\\fR\\x02ip\\x12\\x12\\n\" +\n\t\"\\x04port\\x18\\x02 \\x01(\\x05R\\x04port\\\"B\\n\" +\n\t\"\\vNetIPPrefix\\x12\\x0e\\n\" +\n\t\"\\x02ip\\x18\\x01 \\x01(\\fR\\x02ip\\x12#\\n\" +\n\t\"\\rprefix_length\\x18\\x02 \\x01(\\x05R\\fprefixLength*+\\n\" +\n\t\"\\x04Code\\x12\\t\\n\" +\n\t\"\\x05FATAL\\x10\\x00\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06LOCKED\\x10\\x01\\x12\\f\\n\" +\n\t\"\\bCANCELED\\x10\\x02**\\n\" +\n\t\"\\x0fContainerDriver\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"CONTAINERD\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03CRI\\x10\\x01*@\\n\" +\n\t\"\\x13ContainerdNamespace\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"NS_UNKNOWN\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tNS_SYSTEM\\x10\\x01\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06NS_CRI\\x10\\x02:]\\n\" +\n\t\"\\x19remove_deprecated_message\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x17removeDeprecatedMessage:W\\n\" +\n\t\"\\x17remove_deprecated_field\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x15removeDeprecatedField:T\\n\" +\n\t\"\\x16remove_deprecated_enum\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x14removeDeprecatedEnum:d\\n\" +\n\t\"\\x1cremove_deprecated_enum_value\\x12!.google.protobuf.EnumValueOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x19removeDeprecatedEnumValue:Z\\n\" +\n\t\"\\x18remove_deprecated_method\\x12\\x1e.google.protobuf.MethodOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x16removeDeprecatedMethod:]\\n\" +\n\t\"\\x19remove_deprecated_service\\x12\\x1f.google.protobuf.ServiceOptions\\x18\\xbd\\xd7\\x05 \\x01(\\tR\\x17removeDeprecatedServiceBL\\n\" +\n\t\"\\x14dev.talos.api.commonZ4github.com/siderolabs/talos/pkg/machinery/api/commonb\\x06proto3\"\n\nvar (\n\tfile_common_common_proto_rawDescOnce sync.Once\n\tfile_common_common_proto_rawDescData []byte\n)\n\nfunc file_common_common_proto_rawDescGZIP() []byte {\n\tfile_common_common_proto_rawDescOnce.Do(func() {\n\t\tfile_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_common_common_proto_rawDesc), len(file_common_common_proto_rawDesc)))\n\t})\n\treturn file_common_common_proto_rawDescData\n}\n\nvar file_common_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3)\nvar file_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 14)\nvar file_common_common_proto_goTypes = []any{\n\t(Code)(0),                             // 0: common.Code\n\t(ContainerDriver)(0),                  // 1: common.ContainerDriver\n\t(ContainerdNamespace)(0),              // 2: common.ContainerdNamespace\n\t(*Error)(nil),                         // 3: common.Error\n\t(*Metadata)(nil),                      // 4: common.Metadata\n\t(*Data)(nil),                          // 5: common.Data\n\t(*DataResponse)(nil),                  // 6: common.DataResponse\n\t(*Empty)(nil),                         // 7: common.Empty\n\t(*EmptyResponse)(nil),                 // 8: common.EmptyResponse\n\t(*ContainerdInstance)(nil),            // 9: common.ContainerdInstance\n\t(*URL)(nil),                           // 10: common.URL\n\t(*PEMEncodedCertificateAndKey)(nil),   // 11: common.PEMEncodedCertificateAndKey\n\t(*PEMEncodedKey)(nil),                 // 12: common.PEMEncodedKey\n\t(*PEMEncodedCertificate)(nil),         // 13: common.PEMEncodedCertificate\n\t(*NetIP)(nil),                         // 14: common.NetIP\n\t(*NetIPPort)(nil),                     // 15: common.NetIPPort\n\t(*NetIPPrefix)(nil),                   // 16: common.NetIPPrefix\n\t(*anypb.Any)(nil),                     // 17: google.protobuf.Any\n\t(*status.Status)(nil),                 // 18: google.rpc.Status\n\t(*descriptorpb.MessageOptions)(nil),   // 19: google.protobuf.MessageOptions\n\t(*descriptorpb.FieldOptions)(nil),     // 20: google.protobuf.FieldOptions\n\t(*descriptorpb.EnumOptions)(nil),      // 21: google.protobuf.EnumOptions\n\t(*descriptorpb.EnumValueOptions)(nil), // 22: google.protobuf.EnumValueOptions\n\t(*descriptorpb.MethodOptions)(nil),    // 23: google.protobuf.MethodOptions\n\t(*descriptorpb.ServiceOptions)(nil),   // 24: google.protobuf.ServiceOptions\n}\nvar file_common_common_proto_depIdxs = []int32{\n\t0,  // 0: common.Error.code:type_name -> common.Code\n\t17, // 1: common.Error.details:type_name -> google.protobuf.Any\n\t18, // 2: common.Metadata.status:type_name -> google.rpc.Status\n\t4,  // 3: common.Data.metadata:type_name -> common.Metadata\n\t5,  // 4: common.DataResponse.messages:type_name -> common.Data\n\t4,  // 5: common.Empty.metadata:type_name -> common.Metadata\n\t7,  // 6: common.EmptyResponse.messages:type_name -> common.Empty\n\t1,  // 7: common.ContainerdInstance.driver:type_name -> common.ContainerDriver\n\t2,  // 8: common.ContainerdInstance.namespace:type_name -> common.ContainerdNamespace\n\t19, // 9: common.remove_deprecated_message:extendee -> google.protobuf.MessageOptions\n\t20, // 10: common.remove_deprecated_field:extendee -> google.protobuf.FieldOptions\n\t21, // 11: common.remove_deprecated_enum:extendee -> google.protobuf.EnumOptions\n\t22, // 12: common.remove_deprecated_enum_value:extendee -> google.protobuf.EnumValueOptions\n\t23, // 13: common.remove_deprecated_method:extendee -> google.protobuf.MethodOptions\n\t24, // 14: common.remove_deprecated_service:extendee -> google.protobuf.ServiceOptions\n\t15, // [15:15] is the sub-list for method output_type\n\t15, // [15:15] is the sub-list for method input_type\n\t15, // [15:15] is the sub-list for extension type_name\n\t9,  // [9:15] is the sub-list for extension extendee\n\t0,  // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_common_common_proto_init() }\nfunc file_common_common_proto_init() {\n\tif File_common_common_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_common_common_proto_rawDesc), len(file_common_common_proto_rawDesc)),\n\t\t\tNumEnums:      3,\n\t\t\tNumMessages:   14,\n\t\t\tNumExtensions: 6,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_common_common_proto_goTypes,\n\t\tDependencyIndexes: file_common_common_proto_depIdxs,\n\t\tEnumInfos:         file_common_common_proto_enumTypes,\n\t\tMessageInfos:      file_common_common_proto_msgTypes,\n\t\tExtensionInfos:    file_common_common_proto_extTypes,\n\t}.Build()\n\tFile_common_common_proto = out.File\n\tfile_common_common_proto_goTypes = nil\n\tfile_common_common_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/common/common_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: common/common.proto\n\npackage common\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tanypb \"github.com/planetscale/vtprotobuf/types/known/anypb\"\n\tstatus \"google.golang.org/genproto/googleapis/rpc/status\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb1 \"google.golang.org/protobuf/types/known/anypb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *Error) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Error) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Error) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Details) > 0 {\n\t\tfor iNdEx := len(m.Details) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := (*anypb.Any)(m.Details[iNdEx]).MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.Message) > 0 {\n\t\ti -= len(m.Message)\n\t\tcopy(dAtA[i:], m.Message)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Code != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Code))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Metadata) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Metadata) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Metadata) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Status != nil {\n\t\tif vtmsg, ok := interface{}(m.Status).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Status)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Data) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Data) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Data) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Bytes) > 0 {\n\t\ti -= len(m.Bytes)\n\t\tcopy(dAtA[i:], m.Bytes)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Bytes)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tsize, err := m.Metadata.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DataResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DataResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DataResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Empty) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Empty) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Empty) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tsize, err := m.Metadata.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EmptyResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EmptyResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EmptyResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ContainerdInstance) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ContainerdInstance) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ContainerdInstance) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Namespace != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Namespace))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Driver != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Driver))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *URL) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *URL) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *URL) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.FullPath) > 0 {\n\t\ti -= len(m.FullPath)\n\t\tcopy(dAtA[i:], m.FullPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FullPath)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PEMEncodedCertificateAndKey) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PEMEncodedCertificateAndKey) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PEMEncodedCertificateAndKey) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Crt) > 0 {\n\t\ti -= len(m.Crt)\n\t\tcopy(dAtA[i:], m.Crt)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Crt)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PEMEncodedKey) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PEMEncodedKey) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PEMEncodedKey) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PEMEncodedCertificate) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PEMEncodedCertificate) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PEMEncodedCertificate) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Crt) > 0 {\n\t\ti -= len(m.Crt)\n\t\tcopy(dAtA[i:], m.Crt)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Crt)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetIP) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetIP) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetIP) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Ip) > 0 {\n\t\ti -= len(m.Ip)\n\t\tcopy(dAtA[i:], m.Ip)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ip)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetIPPort) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetIPPort) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetIPPort) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Port != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Port))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Ip) > 0 {\n\t\ti -= len(m.Ip)\n\t\tcopy(dAtA[i:], m.Ip)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ip)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetIPPrefix) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetIPPrefix) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetIPPrefix) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.PrefixLength != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PrefixLength))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Ip) > 0 {\n\t\ti -= len(m.Ip)\n\t\tcopy(dAtA[i:], m.Ip)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ip)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Error) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Code != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Code))\n\t}\n\tl = len(m.Message)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Details) > 0 {\n\t\tfor _, e := range m.Details {\n\t\t\tl = (*anypb.Any)(e).SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Metadata) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Status != nil {\n\t\tif size, ok := interface{}(m.Status).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Status)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Data) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tl = m.Metadata.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Bytes)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DataResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Empty) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tl = m.Metadata.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EmptyResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ContainerdInstance) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Driver != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Driver))\n\t}\n\tif m.Namespace != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Namespace))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *URL) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.FullPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PEMEncodedCertificateAndKey) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Crt)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PEMEncodedKey) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PEMEncodedCertificate) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Crt)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetIP) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Ip)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetIPPort) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Ip)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Port != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Port))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetIPPrefix) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Ip)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PrefixLength != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PrefixLength))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Error) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Error: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Error: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Code\", wireType)\n\t\t\t}\n\t\t\tm.Code = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Code |= Code(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Message = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Details\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Details = append(m.Details, &anypb1.Any{})\n\t\t\tif err := (*anypb.Any)(m.Details[len(m.Details)-1]).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Metadata) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Metadata: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Metadata: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Status == nil {\n\t\t\t\tm.Status = &status.Status{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Status).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Status); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Data) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Data: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Data: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &Metadata{}\n\t\t\t}\n\t\t\tif err := m.Metadata.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Bytes\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Bytes = append(m.Bytes[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Bytes == nil {\n\t\t\t\tm.Bytes = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DataResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DataResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DataResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Data{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Empty) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Empty: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Empty: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &Metadata{}\n\t\t\t}\n\t\t\tif err := m.Metadata.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EmptyResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EmptyResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EmptyResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Empty{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ContainerdInstance) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ContainerdInstance: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ContainerdInstance: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tm.Driver = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Driver |= ContainerDriver(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tm.Namespace = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Namespace |= ContainerdNamespace(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *URL) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: URL: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: URL: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FullPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FullPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PEMEncodedCertificateAndKey) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedCertificateAndKey: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedCertificateAndKey: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Crt\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Crt = append(m.Crt[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Crt == nil {\n\t\t\t\tm.Crt = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Key == nil {\n\t\t\t\tm.Key = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PEMEncodedKey) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedKey: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedKey: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Key == nil {\n\t\t\t\tm.Key = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PEMEncodedCertificate) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedCertificate: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PEMEncodedCertificate: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Crt\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Crt = append(m.Crt[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Crt == nil {\n\t\t\t\tm.Crt = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetIP) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetIP: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetIP: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ip\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ip = append(m.Ip[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Ip == nil {\n\t\t\t\tm.Ip = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetIPPort) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetIPPort: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetIPPort: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ip\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ip = append(m.Ip[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Ip == nil {\n\t\t\t\tm.Ip = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Port\", wireType)\n\t\t\t}\n\t\t\tm.Port = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Port |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetIPPrefix) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetIPPrefix: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetIPPrefix: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ip\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ip = append(m.Ip[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Ip == nil {\n\t\t\t\tm.Ip = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrefixLength\", wireType)\n\t\t\t}\n\t\t\tm.PrefixLength = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PrefixLength |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/inspect/inspect.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: inspect/inspect.proto\n\npackage inspect\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype DependencyEdgeType int32\n\nconst (\n\tDependencyEdgeType_OUTPUT_EXCLUSIVE    DependencyEdgeType = 0\n\tDependencyEdgeType_OUTPUT_SHARED       DependencyEdgeType = 3\n\tDependencyEdgeType_INPUT_STRONG        DependencyEdgeType = 1\n\tDependencyEdgeType_INPUT_WEAK          DependencyEdgeType = 2\n\tDependencyEdgeType_INPUT_DESTROY_READY DependencyEdgeType = 4\n)\n\n// Enum value maps for DependencyEdgeType.\nvar (\n\tDependencyEdgeType_name = map[int32]string{\n\t\t0: \"OUTPUT_EXCLUSIVE\",\n\t\t3: \"OUTPUT_SHARED\",\n\t\t1: \"INPUT_STRONG\",\n\t\t2: \"INPUT_WEAK\",\n\t\t4: \"INPUT_DESTROY_READY\",\n\t}\n\tDependencyEdgeType_value = map[string]int32{\n\t\t\"OUTPUT_EXCLUSIVE\":    0,\n\t\t\"OUTPUT_SHARED\":       3,\n\t\t\"INPUT_STRONG\":        1,\n\t\t\"INPUT_WEAK\":          2,\n\t\t\"INPUT_DESTROY_READY\": 4,\n\t}\n)\n\nfunc (x DependencyEdgeType) Enum() *DependencyEdgeType {\n\tp := new(DependencyEdgeType)\n\t*p = x\n\treturn p\n}\n\nfunc (x DependencyEdgeType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (DependencyEdgeType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_inspect_inspect_proto_enumTypes[0].Descriptor()\n}\n\nfunc (DependencyEdgeType) Type() protoreflect.EnumType {\n\treturn &file_inspect_inspect_proto_enumTypes[0]\n}\n\nfunc (x DependencyEdgeType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use DependencyEdgeType.Descriptor instead.\nfunc (DependencyEdgeType) EnumDescriptor() ([]byte, []int) {\n\treturn file_inspect_inspect_proto_rawDescGZIP(), []int{0}\n}\n\n// The ControllerRuntimeDependency message contains the graph of controller-resource dependencies.\ntype ControllerRuntimeDependency struct {\n\tstate         protoimpl.MessageState      `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata            `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tEdges         []*ControllerDependencyEdge `protobuf:\"bytes,2,rep,name=edges,proto3\" json:\"edges,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ControllerRuntimeDependency) Reset() {\n\t*x = ControllerRuntimeDependency{}\n\tmi := &file_inspect_inspect_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControllerRuntimeDependency) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControllerRuntimeDependency) ProtoMessage() {}\n\nfunc (x *ControllerRuntimeDependency) ProtoReflect() protoreflect.Message {\n\tmi := &file_inspect_inspect_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControllerRuntimeDependency.ProtoReflect.Descriptor instead.\nfunc (*ControllerRuntimeDependency) Descriptor() ([]byte, []int) {\n\treturn file_inspect_inspect_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ControllerRuntimeDependency) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerRuntimeDependency) GetEdges() []*ControllerDependencyEdge {\n\tif x != nil {\n\t\treturn x.Edges\n\t}\n\treturn nil\n}\n\ntype ControllerRuntimeDependenciesResponse struct {\n\tstate         protoimpl.MessageState         `protogen:\"open.v1\"`\n\tMessages      []*ControllerRuntimeDependency `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ControllerRuntimeDependenciesResponse) Reset() {\n\t*x = ControllerRuntimeDependenciesResponse{}\n\tmi := &file_inspect_inspect_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControllerRuntimeDependenciesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControllerRuntimeDependenciesResponse) ProtoMessage() {}\n\nfunc (x *ControllerRuntimeDependenciesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_inspect_inspect_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControllerRuntimeDependenciesResponse.ProtoReflect.Descriptor instead.\nfunc (*ControllerRuntimeDependenciesResponse) Descriptor() ([]byte, []int) {\n\treturn file_inspect_inspect_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ControllerRuntimeDependenciesResponse) GetMessages() []*ControllerRuntimeDependency {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ControllerDependencyEdge struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tControllerName    string                 `protobuf:\"bytes,1,opt,name=controller_name,json=controllerName,proto3\" json:\"controller_name,omitempty\"`\n\tEdgeType          DependencyEdgeType     `protobuf:\"varint,2,opt,name=edge_type,json=edgeType,proto3,enum=inspect.DependencyEdgeType\" json:\"edge_type,omitempty\"`\n\tResourceNamespace string                 `protobuf:\"bytes,3,opt,name=resource_namespace,json=resourceNamespace,proto3\" json:\"resource_namespace,omitempty\"`\n\tResourceType      string                 `protobuf:\"bytes,4,opt,name=resource_type,json=resourceType,proto3\" json:\"resource_type,omitempty\"`\n\tResourceId        string                 `protobuf:\"bytes,5,opt,name=resource_id,json=resourceId,proto3\" json:\"resource_id,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *ControllerDependencyEdge) Reset() {\n\t*x = ControllerDependencyEdge{}\n\tmi := &file_inspect_inspect_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControllerDependencyEdge) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControllerDependencyEdge) ProtoMessage() {}\n\nfunc (x *ControllerDependencyEdge) ProtoReflect() protoreflect.Message {\n\tmi := &file_inspect_inspect_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControllerDependencyEdge.ProtoReflect.Descriptor instead.\nfunc (*ControllerDependencyEdge) Descriptor() ([]byte, []int) {\n\treturn file_inspect_inspect_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ControllerDependencyEdge) GetControllerName() string {\n\tif x != nil {\n\t\treturn x.ControllerName\n\t}\n\treturn \"\"\n}\n\nfunc (x *ControllerDependencyEdge) GetEdgeType() DependencyEdgeType {\n\tif x != nil {\n\t\treturn x.EdgeType\n\t}\n\treturn DependencyEdgeType_OUTPUT_EXCLUSIVE\n}\n\nfunc (x *ControllerDependencyEdge) GetResourceNamespace() string {\n\tif x != nil {\n\t\treturn x.ResourceNamespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *ControllerDependencyEdge) GetResourceType() string {\n\tif x != nil {\n\t\treturn x.ResourceType\n\t}\n\treturn \"\"\n}\n\nfunc (x *ControllerDependencyEdge) GetResourceId() string {\n\tif x != nil {\n\t\treturn x.ResourceId\n\t}\n\treturn \"\"\n}\n\nvar File_inspect_inspect_proto protoreflect.FileDescriptor\n\nconst file_inspect_inspect_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x15inspect/inspect.proto\\x12\\ainspect\\x1a\\x13common/common.proto\\x1a\\x1bgoogle/protobuf/empty.proto\\\"\\x84\\x01\\n\" +\n\t\"\\x1bControllerRuntimeDependency\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x127\\n\" +\n\t\"\\x05edges\\x18\\x02 \\x03(\\v2!.inspect.ControllerDependencyEdgeR\\x05edges\\\"i\\n\" +\n\t\"%ControllerRuntimeDependenciesResponse\\x12@\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2$.inspect.ControllerRuntimeDependencyR\\bmessages\\\"\\xf2\\x01\\n\" +\n\t\"\\x18ControllerDependencyEdge\\x12'\\n\" +\n\t\"\\x0fcontroller_name\\x18\\x01 \\x01(\\tR\\x0econtrollerName\\x128\\n\" +\n\t\"\\tedge_type\\x18\\x02 \\x01(\\x0e2\\x1b.inspect.DependencyEdgeTypeR\\bedgeType\\x12-\\n\" +\n\t\"\\x12resource_namespace\\x18\\x03 \\x01(\\tR\\x11resourceNamespace\\x12#\\n\" +\n\t\"\\rresource_type\\x18\\x04 \\x01(\\tR\\fresourceType\\x12\\x1f\\n\" +\n\t\"\\vresource_id\\x18\\x05 \\x01(\\tR\\n\" +\n\t\"resourceId*x\\n\" +\n\t\"\\x12DependencyEdgeType\\x12\\x14\\n\" +\n\t\"\\x10OUTPUT_EXCLUSIVE\\x10\\x00\\x12\\x11\\n\" +\n\t\"\\rOUTPUT_SHARED\\x10\\x03\\x12\\x10\\n\" +\n\t\"\\fINPUT_STRONG\\x10\\x01\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"INPUT_WEAK\\x10\\x02\\x12\\x17\\n\" +\n\t\"\\x13INPUT_DESTROY_READY\\x10\\x042y\\n\" +\n\t\"\\x0eInspectService\\x12g\\n\" +\n\t\"\\x1dControllerRuntimeDependencies\\x12\\x16.google.protobuf.Empty\\x1a..inspect.ControllerRuntimeDependenciesResponseBN\\n\" +\n\t\"\\x15dev.talos.api.inspectZ5github.com/siderolabs/talos/pkg/machinery/api/inspectb\\x06proto3\"\n\nvar (\n\tfile_inspect_inspect_proto_rawDescOnce sync.Once\n\tfile_inspect_inspect_proto_rawDescData []byte\n)\n\nfunc file_inspect_inspect_proto_rawDescGZIP() []byte {\n\tfile_inspect_inspect_proto_rawDescOnce.Do(func() {\n\t\tfile_inspect_inspect_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_inspect_inspect_proto_rawDesc), len(file_inspect_inspect_proto_rawDesc)))\n\t})\n\treturn file_inspect_inspect_proto_rawDescData\n}\n\nvar file_inspect_inspect_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_inspect_inspect_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_inspect_inspect_proto_goTypes = []any{\n\t(DependencyEdgeType)(0),                       // 0: inspect.DependencyEdgeType\n\t(*ControllerRuntimeDependency)(nil),           // 1: inspect.ControllerRuntimeDependency\n\t(*ControllerRuntimeDependenciesResponse)(nil), // 2: inspect.ControllerRuntimeDependenciesResponse\n\t(*ControllerDependencyEdge)(nil),              // 3: inspect.ControllerDependencyEdge\n\t(*common.Metadata)(nil),                       // 4: common.Metadata\n\t(*emptypb.Empty)(nil),                         // 5: google.protobuf.Empty\n}\nvar file_inspect_inspect_proto_depIdxs = []int32{\n\t4, // 0: inspect.ControllerRuntimeDependency.metadata:type_name -> common.Metadata\n\t3, // 1: inspect.ControllerRuntimeDependency.edges:type_name -> inspect.ControllerDependencyEdge\n\t1, // 2: inspect.ControllerRuntimeDependenciesResponse.messages:type_name -> inspect.ControllerRuntimeDependency\n\t0, // 3: inspect.ControllerDependencyEdge.edge_type:type_name -> inspect.DependencyEdgeType\n\t5, // 4: inspect.InspectService.ControllerRuntimeDependencies:input_type -> google.protobuf.Empty\n\t2, // 5: inspect.InspectService.ControllerRuntimeDependencies:output_type -> inspect.ControllerRuntimeDependenciesResponse\n\t5, // [5:6] is the sub-list for method output_type\n\t4, // [4:5] is the sub-list for method input_type\n\t4, // [4:4] is the sub-list for extension type_name\n\t4, // [4:4] is the sub-list for extension extendee\n\t0, // [0:4] is the sub-list for field type_name\n}\n\nfunc init() { file_inspect_inspect_proto_init() }\nfunc file_inspect_inspect_proto_init() {\n\tif File_inspect_inspect_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_inspect_inspect_proto_rawDesc), len(file_inspect_inspect_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_inspect_inspect_proto_goTypes,\n\t\tDependencyIndexes: file_inspect_inspect_proto_depIdxs,\n\t\tEnumInfos:         file_inspect_inspect_proto_enumTypes,\n\t\tMessageInfos:      file_inspect_inspect_proto_msgTypes,\n\t}.Build()\n\tFile_inspect_inspect_proto = out.File\n\tfile_inspect_inspect_proto_goTypes = nil\n\tfile_inspect_inspect_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/inspect/inspect_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: inspect/inspect.proto\n\npackage inspect\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tInspectService_ControllerRuntimeDependencies_FullMethodName = \"/inspect.InspectService/ControllerRuntimeDependencies\"\n)\n\n// InspectServiceClient is the client API for InspectService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The inspect service definition.\n//\n// InspectService provides auxiliary API to inspect OS internals.\ntype InspectServiceClient interface {\n\tControllerRuntimeDependencies(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ControllerRuntimeDependenciesResponse, error)\n}\n\ntype inspectServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewInspectServiceClient(cc grpc.ClientConnInterface) InspectServiceClient {\n\treturn &inspectServiceClient{cc}\n}\n\nfunc (c *inspectServiceClient) ControllerRuntimeDependencies(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ControllerRuntimeDependenciesResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ControllerRuntimeDependenciesResponse)\n\terr := c.cc.Invoke(ctx, InspectService_ControllerRuntimeDependencies_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// InspectServiceServer is the server API for InspectService service.\n// All implementations must embed UnimplementedInspectServiceServer\n// for forward compatibility.\n//\n// The inspect service definition.\n//\n// InspectService provides auxiliary API to inspect OS internals.\ntype InspectServiceServer interface {\n\tControllerRuntimeDependencies(context.Context, *emptypb.Empty) (*ControllerRuntimeDependenciesResponse, error)\n\tmustEmbedUnimplementedInspectServiceServer()\n}\n\n// UnimplementedInspectServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedInspectServiceServer struct{}\n\nfunc (UnimplementedInspectServiceServer) ControllerRuntimeDependencies(context.Context, *emptypb.Empty) (*ControllerRuntimeDependenciesResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ControllerRuntimeDependencies not implemented\")\n}\nfunc (UnimplementedInspectServiceServer) mustEmbedUnimplementedInspectServiceServer() {}\nfunc (UnimplementedInspectServiceServer) testEmbeddedByValue()                        {}\n\n// UnsafeInspectServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to InspectServiceServer will\n// result in compilation errors.\ntype UnsafeInspectServiceServer interface {\n\tmustEmbedUnimplementedInspectServiceServer()\n}\n\nfunc RegisterInspectServiceServer(s grpc.ServiceRegistrar, srv InspectServiceServer) {\n\t// If the following call panics, it indicates UnimplementedInspectServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&InspectService_ServiceDesc, srv)\n}\n\nfunc _InspectService_ControllerRuntimeDependencies_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(InspectServiceServer).ControllerRuntimeDependencies(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: InspectService_ControllerRuntimeDependencies_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(InspectServiceServer).ControllerRuntimeDependencies(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// InspectService_ServiceDesc is the grpc.ServiceDesc for InspectService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar InspectService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"inspect.InspectService\",\n\tHandlerType: (*InspectServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"ControllerRuntimeDependencies\",\n\t\t\tHandler:    _InspectService_ControllerRuntimeDependencies_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"inspect/inspect.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/inspect/inspect_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: inspect/inspect.proto\n\npackage inspect\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ControllerRuntimeDependency) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControllerRuntimeDependency) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControllerRuntimeDependency) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Edges) > 0 {\n\t\tfor iNdEx := len(m.Edges) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Edges[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControllerRuntimeDependenciesResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControllerRuntimeDependenciesResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControllerRuntimeDependenciesResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControllerDependencyEdge) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControllerDependencyEdge) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControllerDependencyEdge) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ResourceId) > 0 {\n\t\ti -= len(m.ResourceId)\n\t\tcopy(dAtA[i:], m.ResourceId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ResourceId)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.ResourceType) > 0 {\n\t\ti -= len(m.ResourceType)\n\t\tcopy(dAtA[i:], m.ResourceType)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ResourceType)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.ResourceNamespace) > 0 {\n\t\ti -= len(m.ResourceNamespace)\n\t\tcopy(dAtA[i:], m.ResourceNamespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ResourceNamespace)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.EdgeType != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.EdgeType))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.ControllerName) > 0 {\n\t\ti -= len(m.ControllerName)\n\t\tcopy(dAtA[i:], m.ControllerName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ControllerName)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControllerRuntimeDependency) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Edges) > 0 {\n\t\tfor _, e := range m.Edges {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControllerRuntimeDependenciesResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControllerDependencyEdge) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ControllerName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EdgeType != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.EdgeType))\n\t}\n\tl = len(m.ResourceNamespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ResourceType)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ResourceId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControllerRuntimeDependency) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerRuntimeDependency: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerRuntimeDependency: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Edges\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Edges = append(m.Edges, &ControllerDependencyEdge{})\n\t\t\tif err := m.Edges[len(m.Edges)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ControllerRuntimeDependenciesResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerRuntimeDependenciesResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerRuntimeDependenciesResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ControllerRuntimeDependency{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ControllerDependencyEdge) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerDependencyEdge: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerDependencyEdge: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControllerName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ControllerName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EdgeType\", wireType)\n\t\t\t}\n\t\t\tm.EdgeType = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EdgeType |= DependencyEdgeType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResourceNamespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ResourceNamespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResourceType\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ResourceType = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResourceId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ResourceId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/debug.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: machine/debug.proto\n\npackage machine\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype DebugContainerRunRequestSpec_Profile int32\n\nconst (\n\tDebugContainerRunRequestSpec_PROFILE_UNSPECIFIED DebugContainerRunRequestSpec_Profile = 0\n\tDebugContainerRunRequestSpec_PROFILE_PRIVILEGED  DebugContainerRunRequestSpec_Profile = 1\n)\n\n// Enum value maps for DebugContainerRunRequestSpec_Profile.\nvar (\n\tDebugContainerRunRequestSpec_Profile_name = map[int32]string{\n\t\t0: \"PROFILE_UNSPECIFIED\",\n\t\t1: \"PROFILE_PRIVILEGED\",\n\t}\n\tDebugContainerRunRequestSpec_Profile_value = map[string]int32{\n\t\t\"PROFILE_UNSPECIFIED\": 0,\n\t\t\"PROFILE_PRIVILEGED\":  1,\n\t}\n)\n\nfunc (x DebugContainerRunRequestSpec_Profile) Enum() *DebugContainerRunRequestSpec_Profile {\n\tp := new(DebugContainerRunRequestSpec_Profile)\n\t*p = x\n\treturn p\n}\n\nfunc (x DebugContainerRunRequestSpec_Profile) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (DebugContainerRunRequestSpec_Profile) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_debug_proto_enumTypes[0].Descriptor()\n}\n\nfunc (DebugContainerRunRequestSpec_Profile) Type() protoreflect.EnumType {\n\treturn &file_machine_debug_proto_enumTypes[0]\n}\n\nfunc (x DebugContainerRunRequestSpec_Profile) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use DebugContainerRunRequestSpec_Profile.Descriptor instead.\nfunc (DebugContainerRunRequestSpec_Profile) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_debug_proto_rawDescGZIP(), []int{1, 0}\n}\n\ntype DebugContainerRunRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Request:\n\t//\n\t//\t*DebugContainerRunRequest_Spec\n\t//\t*DebugContainerRunRequest_StdinData\n\t//\t*DebugContainerRunRequest_Signal\n\t//\t*DebugContainerRunRequest_TermResize\n\tRequest       isDebugContainerRunRequest_Request `protobuf_oneof:\"request\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DebugContainerRunRequest) Reset() {\n\t*x = DebugContainerRunRequest{}\n\tmi := &file_machine_debug_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DebugContainerRunRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DebugContainerRunRequest) ProtoMessage() {}\n\nfunc (x *DebugContainerRunRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_debug_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DebugContainerRunRequest.ProtoReflect.Descriptor instead.\nfunc (*DebugContainerRunRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_debug_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DebugContainerRunRequest) GetRequest() isDebugContainerRunRequest_Request {\n\tif x != nil {\n\t\treturn x.Request\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequest) GetSpec() *DebugContainerRunRequestSpec {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*DebugContainerRunRequest_Spec); ok {\n\t\t\treturn x.Spec\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequest) GetStdinData() []byte {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*DebugContainerRunRequest_StdinData); ok {\n\t\t\treturn x.StdinData\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequest) GetSignal() int32 {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*DebugContainerRunRequest_Signal); ok {\n\t\t\treturn x.Signal\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *DebugContainerRunRequest) GetTermResize() *DebugContainerTerminalResize {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*DebugContainerRunRequest_TermResize); ok {\n\t\t\treturn x.TermResize\n\t\t}\n\t}\n\treturn nil\n}\n\ntype isDebugContainerRunRequest_Request interface {\n\tisDebugContainerRunRequest_Request()\n}\n\ntype DebugContainerRunRequest_Spec struct {\n\t// 1. send the container spec\n\tSpec *DebugContainerRunRequestSpec `protobuf:\"bytes,1,opt,name=spec,proto3,oneof\"`\n}\n\ntype DebugContainerRunRequest_StdinData struct {\n\t// 2. send either of the three below to interact with the running container\n\tStdinData []byte `protobuf:\"bytes,2,opt,name=stdin_data,json=stdinData,proto3,oneof\"`\n}\n\ntype DebugContainerRunRequest_Signal struct {\n\tSignal int32 `protobuf:\"varint,3,opt,name=signal,proto3,oneof\"`\n}\n\ntype DebugContainerRunRequest_TermResize struct {\n\tTermResize *DebugContainerTerminalResize `protobuf:\"bytes,4,opt,name=term_resize,json=termResize,proto3,oneof\"`\n}\n\nfunc (*DebugContainerRunRequest_Spec) isDebugContainerRunRequest_Request() {}\n\nfunc (*DebugContainerRunRequest_StdinData) isDebugContainerRunRequest_Request() {}\n\nfunc (*DebugContainerRunRequest_Signal) isDebugContainerRunRequest_Request() {}\n\nfunc (*DebugContainerRunRequest_TermResize) isDebugContainerRunRequest_Request() {}\n\ntype DebugContainerRunRequestSpec struct {\n\tstate         protoimpl.MessageState               `protogen:\"open.v1\"`\n\tContainerd    *common.ContainerdInstance           `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\tImageName     string                               `protobuf:\"bytes,2,opt,name=image_name,json=imageName,proto3\" json:\"image_name,omitempty\"`\n\tArgs          []string                             `protobuf:\"bytes,3,rep,name=args,proto3\" json:\"args,omitempty\"`\n\tEnv           map[string]string                    `protobuf:\"bytes,4,rep,name=env,proto3\" json:\"env,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tProfile       DebugContainerRunRequestSpec_Profile `protobuf:\"varint,5,opt,name=profile,proto3,enum=machine.DebugContainerRunRequestSpec_Profile\" json:\"profile,omitempty\"`\n\tTty           bool                                 `protobuf:\"varint,6,opt,name=tty,proto3\" json:\"tty,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DebugContainerRunRequestSpec) Reset() {\n\t*x = DebugContainerRunRequestSpec{}\n\tmi := &file_machine_debug_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DebugContainerRunRequestSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DebugContainerRunRequestSpec) ProtoMessage() {}\n\nfunc (x *DebugContainerRunRequestSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_debug_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DebugContainerRunRequestSpec.ProtoReflect.Descriptor instead.\nfunc (*DebugContainerRunRequestSpec) Descriptor() ([]byte, []int) {\n\treturn file_machine_debug_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetImageName() string {\n\tif x != nil {\n\t\treturn x.ImageName\n\t}\n\treturn \"\"\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetArgs() []string {\n\tif x != nil {\n\t\treturn x.Args\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetEnv() map[string]string {\n\tif x != nil {\n\t\treturn x.Env\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetProfile() DebugContainerRunRequestSpec_Profile {\n\tif x != nil {\n\t\treturn x.Profile\n\t}\n\treturn DebugContainerRunRequestSpec_PROFILE_UNSPECIFIED\n}\n\nfunc (x *DebugContainerRunRequestSpec) GetTty() bool {\n\tif x != nil {\n\t\treturn x.Tty\n\t}\n\treturn false\n}\n\ntype DebugContainerTerminalResize struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tWidth         int32                  `protobuf:\"varint,1,opt,name=width,proto3\" json:\"width,omitempty\"`\n\tHeight        int32                  `protobuf:\"varint,2,opt,name=height,proto3\" json:\"height,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DebugContainerTerminalResize) Reset() {\n\t*x = DebugContainerTerminalResize{}\n\tmi := &file_machine_debug_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DebugContainerTerminalResize) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DebugContainerTerminalResize) ProtoMessage() {}\n\nfunc (x *DebugContainerTerminalResize) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_debug_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DebugContainerTerminalResize.ProtoReflect.Descriptor instead.\nfunc (*DebugContainerTerminalResize) Descriptor() ([]byte, []int) {\n\treturn file_machine_debug_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *DebugContainerTerminalResize) GetWidth() int32 {\n\tif x != nil {\n\t\treturn x.Width\n\t}\n\treturn 0\n}\n\nfunc (x *DebugContainerTerminalResize) GetHeight() int32 {\n\tif x != nil {\n\t\treturn x.Height\n\t}\n\treturn 0\n}\n\ntype DebugContainerRunResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Resp:\n\t//\n\t//\t*DebugContainerRunResponse_StdoutData\n\t//\t*DebugContainerRunResponse_ExitCode\n\tResp          isDebugContainerRunResponse_Resp `protobuf_oneof:\"resp\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DebugContainerRunResponse) Reset() {\n\t*x = DebugContainerRunResponse{}\n\tmi := &file_machine_debug_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DebugContainerRunResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DebugContainerRunResponse) ProtoMessage() {}\n\nfunc (x *DebugContainerRunResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_debug_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DebugContainerRunResponse.ProtoReflect.Descriptor instead.\nfunc (*DebugContainerRunResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_debug_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *DebugContainerRunResponse) GetResp() isDebugContainerRunResponse_Resp {\n\tif x != nil {\n\t\treturn x.Resp\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunResponse) GetStdoutData() []byte {\n\tif x != nil {\n\t\tif x, ok := x.Resp.(*DebugContainerRunResponse_StdoutData); ok {\n\t\t\treturn x.StdoutData\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *DebugContainerRunResponse) GetExitCode() int32 {\n\tif x != nil {\n\t\tif x, ok := x.Resp.(*DebugContainerRunResponse_ExitCode); ok {\n\t\t\treturn x.ExitCode\n\t\t}\n\t}\n\treturn 0\n}\n\ntype isDebugContainerRunResponse_Resp interface {\n\tisDebugContainerRunResponse_Resp()\n}\n\ntype DebugContainerRunResponse_StdoutData struct {\n\tStdoutData []byte `protobuf:\"bytes,2,opt,name=stdout_data,json=stdoutData,proto3,oneof\"`\n}\n\ntype DebugContainerRunResponse_ExitCode struct {\n\tExitCode int32 `protobuf:\"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof\"`\n}\n\nfunc (*DebugContainerRunResponse_StdoutData) isDebugContainerRunResponse_Resp() {}\n\nfunc (*DebugContainerRunResponse_ExitCode) isDebugContainerRunResponse_Resp() {}\n\nvar File_machine_debug_proto protoreflect.FileDescriptor\n\nconst file_machine_debug_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x13machine/debug.proto\\x12\\amachine\\x1a\\x13common/common.proto\\\"\\xe7\\x01\\n\" +\n\t\"\\x18DebugContainerRunRequest\\x12;\\n\" +\n\t\"\\x04spec\\x18\\x01 \\x01(\\v2%.machine.DebugContainerRunRequestSpecH\\x00R\\x04spec\\x12\\x1f\\n\" +\n\t\"\\n\" +\n\t\"stdin_data\\x18\\x02 \\x01(\\fH\\x00R\\tstdinData\\x12\\x18\\n\" +\n\t\"\\x06signal\\x18\\x03 \\x01(\\x05H\\x00R\\x06signal\\x12H\\n\" +\n\t\"\\vterm_resize\\x18\\x04 \\x01(\\v2%.machine.DebugContainerTerminalResizeH\\x00R\\n\" +\n\t\"termResizeB\\t\\n\" +\n\t\"\\arequest\\\"\\x9e\\x03\\n\" +\n\t\"\\x1cDebugContainerRunRequestSpec\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"image_name\\x18\\x02 \\x01(\\tR\\timageName\\x12\\x12\\n\" +\n\t\"\\x04args\\x18\\x03 \\x03(\\tR\\x04args\\x12@\\n\" +\n\t\"\\x03env\\x18\\x04 \\x03(\\v2..machine.DebugContainerRunRequestSpec.EnvEntryR\\x03env\\x12G\\n\" +\n\t\"\\aprofile\\x18\\x05 \\x01(\\x0e2-.machine.DebugContainerRunRequestSpec.ProfileR\\aprofile\\x12\\x10\\n\" +\n\t\"\\x03tty\\x18\\x06 \\x01(\\bR\\x03tty\\x1a6\\n\" +\n\t\"\\bEnvEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\":\\n\" +\n\t\"\\aProfile\\x12\\x17\\n\" +\n\t\"\\x13PROFILE_UNSPECIFIED\\x10\\x00\\x12\\x16\\n\" +\n\t\"\\x12PROFILE_PRIVILEGED\\x10\\x01\\\"L\\n\" +\n\t\"\\x1cDebugContainerTerminalResize\\x12\\x14\\n\" +\n\t\"\\x05width\\x18\\x01 \\x01(\\x05R\\x05width\\x12\\x16\\n\" +\n\t\"\\x06height\\x18\\x02 \\x01(\\x05R\\x06height\\\"e\\n\" +\n\t\"\\x19DebugContainerRunResponse\\x12!\\n\" +\n\t\"\\vstdout_data\\x18\\x02 \\x01(\\fH\\x00R\\n\" +\n\t\"stdoutData\\x12\\x1d\\n\" +\n\t\"\\texit_code\\x18\\x03 \\x01(\\x05H\\x00R\\bexitCodeB\\x06\\n\" +\n\t\"\\x04resp2i\\n\" +\n\t\"\\fDebugService\\x12Y\\n\" +\n\t\"\\fContainerRun\\x12!.machine.DebugContainerRunRequest\\x1a\\\".machine.DebugContainerRunResponse(\\x010\\x01BN\\n\" +\n\t\"\\x15dev.talos.api.machineZ5github.com/siderolabs/talos/pkg/machinery/api/machineb\\x06proto3\"\n\nvar (\n\tfile_machine_debug_proto_rawDescOnce sync.Once\n\tfile_machine_debug_proto_rawDescData []byte\n)\n\nfunc file_machine_debug_proto_rawDescGZIP() []byte {\n\tfile_machine_debug_proto_rawDescOnce.Do(func() {\n\t\tfile_machine_debug_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_machine_debug_proto_rawDesc), len(file_machine_debug_proto_rawDesc)))\n\t})\n\treturn file_machine_debug_proto_rawDescData\n}\n\nvar file_machine_debug_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_machine_debug_proto_msgTypes = make([]protoimpl.MessageInfo, 5)\nvar file_machine_debug_proto_goTypes = []any{\n\t(DebugContainerRunRequestSpec_Profile)(0), // 0: machine.DebugContainerRunRequestSpec.Profile\n\t(*DebugContainerRunRequest)(nil),          // 1: machine.DebugContainerRunRequest\n\t(*DebugContainerRunRequestSpec)(nil),      // 2: machine.DebugContainerRunRequestSpec\n\t(*DebugContainerTerminalResize)(nil),      // 3: machine.DebugContainerTerminalResize\n\t(*DebugContainerRunResponse)(nil),         // 4: machine.DebugContainerRunResponse\n\tnil,                                       // 5: machine.DebugContainerRunRequestSpec.EnvEntry\n\t(*common.ContainerdInstance)(nil),         // 6: common.ContainerdInstance\n}\nvar file_machine_debug_proto_depIdxs = []int32{\n\t2, // 0: machine.DebugContainerRunRequest.spec:type_name -> machine.DebugContainerRunRequestSpec\n\t3, // 1: machine.DebugContainerRunRequest.term_resize:type_name -> machine.DebugContainerTerminalResize\n\t6, // 2: machine.DebugContainerRunRequestSpec.containerd:type_name -> common.ContainerdInstance\n\t5, // 3: machine.DebugContainerRunRequestSpec.env:type_name -> machine.DebugContainerRunRequestSpec.EnvEntry\n\t0, // 4: machine.DebugContainerRunRequestSpec.profile:type_name -> machine.DebugContainerRunRequestSpec.Profile\n\t1, // 5: machine.DebugService.ContainerRun:input_type -> machine.DebugContainerRunRequest\n\t4, // 6: machine.DebugService.ContainerRun:output_type -> machine.DebugContainerRunResponse\n\t6, // [6:7] is the sub-list for method output_type\n\t5, // [5:6] is the sub-list for method input_type\n\t5, // [5:5] is the sub-list for extension type_name\n\t5, // [5:5] is the sub-list for extension extendee\n\t0, // [0:5] is the sub-list for field type_name\n}\n\nfunc init() { file_machine_debug_proto_init() }\nfunc file_machine_debug_proto_init() {\n\tif File_machine_debug_proto != nil {\n\t\treturn\n\t}\n\tfile_machine_debug_proto_msgTypes[0].OneofWrappers = []any{\n\t\t(*DebugContainerRunRequest_Spec)(nil),\n\t\t(*DebugContainerRunRequest_StdinData)(nil),\n\t\t(*DebugContainerRunRequest_Signal)(nil),\n\t\t(*DebugContainerRunRequest_TermResize)(nil),\n\t}\n\tfile_machine_debug_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*DebugContainerRunResponse_StdoutData)(nil),\n\t\t(*DebugContainerRunResponse_ExitCode)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_machine_debug_proto_rawDesc), len(file_machine_debug_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   5,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_machine_debug_proto_goTypes,\n\t\tDependencyIndexes: file_machine_debug_proto_depIdxs,\n\t\tEnumInfos:         file_machine_debug_proto_enumTypes,\n\t\tMessageInfos:      file_machine_debug_proto_msgTypes,\n\t}.Build()\n\tFile_machine_debug_proto = out.File\n\tfile_machine_debug_proto_goTypes = nil\n\tfile_machine_debug_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/debug_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: machine/debug.proto\n\npackage machine\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tDebugService_ContainerRun_FullMethodName = \"/machine.DebugService/ContainerRun\"\n)\n\n// DebugServiceClient is the client API for DebugService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// DebugService provides debugging and inspection capabilities for a Talos node.\ntype DebugServiceClient interface {\n\t// ContainerRun runs a debug container, attaches to it, and streams I/O.\n\tContainerRun(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[DebugContainerRunRequest, DebugContainerRunResponse], error)\n}\n\ntype debugServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewDebugServiceClient(cc grpc.ClientConnInterface) DebugServiceClient {\n\treturn &debugServiceClient{cc}\n}\n\nfunc (c *debugServiceClient) ContainerRun(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[DebugContainerRunRequest, DebugContainerRunResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &DebugService_ServiceDesc.Streams[0], DebugService_ContainerRun_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[DebugContainerRunRequest, DebugContainerRunResponse]{ClientStream: stream}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype DebugService_ContainerRunClient = grpc.BidiStreamingClient[DebugContainerRunRequest, DebugContainerRunResponse]\n\n// DebugServiceServer is the server API for DebugService service.\n// All implementations must embed UnimplementedDebugServiceServer\n// for forward compatibility.\n//\n// DebugService provides debugging and inspection capabilities for a Talos node.\ntype DebugServiceServer interface {\n\t// ContainerRun runs a debug container, attaches to it, and streams I/O.\n\tContainerRun(grpc.BidiStreamingServer[DebugContainerRunRequest, DebugContainerRunResponse]) error\n\tmustEmbedUnimplementedDebugServiceServer()\n}\n\n// UnimplementedDebugServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedDebugServiceServer struct{}\n\nfunc (UnimplementedDebugServiceServer) ContainerRun(grpc.BidiStreamingServer[DebugContainerRunRequest, DebugContainerRunResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method ContainerRun not implemented\")\n}\nfunc (UnimplementedDebugServiceServer) mustEmbedUnimplementedDebugServiceServer() {}\nfunc (UnimplementedDebugServiceServer) testEmbeddedByValue()                      {}\n\n// UnsafeDebugServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to DebugServiceServer will\n// result in compilation errors.\ntype UnsafeDebugServiceServer interface {\n\tmustEmbedUnimplementedDebugServiceServer()\n}\n\nfunc RegisterDebugServiceServer(s grpc.ServiceRegistrar, srv DebugServiceServer) {\n\t// If the following call panics, it indicates UnimplementedDebugServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&DebugService_ServiceDesc, srv)\n}\n\nfunc _DebugService_ContainerRun_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(DebugServiceServer).ContainerRun(&grpc.GenericServerStream[DebugContainerRunRequest, DebugContainerRunResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype DebugService_ContainerRunServer = grpc.BidiStreamingServer[DebugContainerRunRequest, DebugContainerRunResponse]\n\n// DebugService_ServiceDesc is the grpc.ServiceDesc for DebugService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar DebugService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"machine.DebugService\",\n\tHandlerType: (*DebugServiceServer)(nil),\n\tMethods:     []grpc.MethodDesc{},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"ContainerRun\",\n\t\t\tHandler:       _DebugService_ContainerRun_Handler,\n\t\t\tServerStreams: true,\n\t\t\tClientStreams: true,\n\t\t},\n\t},\n\tMetadata: \"machine/debug.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/debug_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: machine/debug.proto\n\npackage machine\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *DebugContainerRunRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DebugContainerRunRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif vtmsg, ok := m.Request.(interface {\n\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t}); ok {\n\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DebugContainerRunRequest_Spec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequest_Spec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\tif m.Spec != nil {\n\t\tsize, err := m.Spec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t} else {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, 0)\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunRequest_StdinData) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequest_StdinData) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti -= len(m.StdinData)\n\tcopy(dAtA[i:], m.StdinData)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StdinData)))\n\ti--\n\tdAtA[i] = 0x12\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunRequest_Signal) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequest_Signal) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Signal))\n\ti--\n\tdAtA[i] = 0x18\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunRequest_TermResize) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequest_TermResize) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\tif m.TermResize != nil {\n\t\tsize, err := m.TermResize.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t} else {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, 0)\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunRequestSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DebugContainerRunRequestSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunRequestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Tty {\n\t\ti--\n\t\tif m.Tty {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Profile != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Profile))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Env) > 0 {\n\t\tfor k := range m.Env {\n\t\t\tv := m.Env[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Args) > 0 {\n\t\tfor iNdEx := len(m.Args) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Args[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Args[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Args[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.ImageName) > 0 {\n\t\ti -= len(m.ImageName)\n\t\tcopy(dAtA[i:], m.ImageName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImageName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DebugContainerTerminalResize) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DebugContainerTerminalResize) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerTerminalResize) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Height != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Height))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Width != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Width))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DebugContainerRunResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DebugContainerRunResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif vtmsg, ok := m.Resp.(interface {\n\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t}); ok {\n\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DebugContainerRunResponse_StdoutData) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunResponse_StdoutData) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti -= len(m.StdoutData)\n\tcopy(dAtA[i:], m.StdoutData)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StdoutData)))\n\ti--\n\tdAtA[i] = 0x12\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunResponse_ExitCode) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DebugContainerRunResponse_ExitCode) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExitCode))\n\ti--\n\tdAtA[i] = 0x18\n\treturn len(dAtA) - i, nil\n}\nfunc (m *DebugContainerRunRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif vtmsg, ok := m.Request.(interface{ SizeVT() int }); ok {\n\t\tn += vtmsg.SizeVT()\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DebugContainerRunRequest_Spec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Spec != nil {\n\t\tl = m.Spec.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t} else {\n\t\tn += 2\n\t}\n\treturn n\n}\nfunc (m *DebugContainerRunRequest_StdinData) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.StdinData)\n\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\treturn n\n}\nfunc (m *DebugContainerRunRequest_Signal) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Signal))\n\treturn n\n}\nfunc (m *DebugContainerRunRequest_TermResize) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.TermResize != nil {\n\t\tl = m.TermResize.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t} else {\n\t\tn += 2\n\t}\n\treturn n\n}\nfunc (m *DebugContainerRunRequestSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ImageName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Args) > 0 {\n\t\tfor _, s := range m.Args {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Env) > 0 {\n\t\tfor k, v := range m.Env {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif m.Profile != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Profile))\n\t}\n\tif m.Tty {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DebugContainerTerminalResize) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Width != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Width))\n\t}\n\tif m.Height != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Height))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DebugContainerRunResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif vtmsg, ok := m.Resp.(interface{ SizeVT() int }); ok {\n\t\tn += vtmsg.SizeVT()\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DebugContainerRunResponse_StdoutData) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.StdoutData)\n\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\treturn n\n}\nfunc (m *DebugContainerRunResponse_ExitCode) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ExitCode))\n\treturn n\n}\nfunc (m *DebugContainerRunRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Spec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif oneof, ok := m.Request.(*DebugContainerRunRequest_Spec); ok {\n\t\t\t\tif err := oneof.Spec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tv := &DebugContainerRunRequestSpec{}\n\t\t\t\tif err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tm.Request = &DebugContainerRunRequest_Spec{Spec: v}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StdinData\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv := make([]byte, postIndex-iNdEx)\n\t\t\tcopy(v, dAtA[iNdEx:postIndex])\n\t\t\tm.Request = &DebugContainerRunRequest_StdinData{StdinData: v}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Signal\", wireType)\n\t\t\t}\n\t\t\tvar v int32\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Request = &DebugContainerRunRequest_Signal{Signal: v}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TermResize\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif oneof, ok := m.Request.(*DebugContainerRunRequest_TermResize); ok {\n\t\t\t\tif err := oneof.TermResize.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tv := &DebugContainerTerminalResize{}\n\t\t\t\tif err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tm.Request = &DebugContainerRunRequest_TermResize{TermResize: v}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DebugContainerRunRequestSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunRequestSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunRequestSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImageName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Args\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Args = append(m.Args, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Env\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Env == nil {\n\t\t\t\tm.Env = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Env[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Profile\", wireType)\n\t\t\t}\n\t\t\tm.Profile = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Profile |= DebugContainerRunRequestSpec_Profile(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tty\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tty = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DebugContainerTerminalResize) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerTerminalResize: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerTerminalResize: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Width\", wireType)\n\t\t\t}\n\t\t\tm.Width = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Width |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Height\", wireType)\n\t\t\t}\n\t\t\tm.Height = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Height |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DebugContainerRunResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DebugContainerRunResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StdoutData\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv := make([]byte, postIndex-iNdEx)\n\t\t\tcopy(v, dAtA[iNdEx:postIndex])\n\t\t\tm.Resp = &DebugContainerRunResponse_StdoutData{StdoutData: v}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExitCode\", wireType)\n\t\t\t}\n\t\t\tvar v int32\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Resp = &DebugContainerRunResponse_ExitCode{ExitCode: v}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package machine contains the machine service API definitions.\npackage machine\n\nimport (\n\tfmt \"fmt\"\n\n\t\"github.com/dustin/go-humanize\"\n)\n\n// Fmt formats the pull progress status into a human-readable string.\nfunc (s *ImageServicePullLayerProgress) Fmt() string {\n\tswitch s.GetStatus() {\n\tcase ImageServicePullLayerProgress_DOWNLOADING:\n\t\treturn fmt.Sprintf(\"downloading layer %s/%s (%.1f%%)\",\n\t\t\thumanize.IBytes(uint64(s.GetOffset())),\n\t\t\thumanize.IBytes(uint64(s.GetTotal())),\n\t\t\tfloat64(s.GetOffset())/float64(s.GetTotal())*100.0,\n\t\t)\n\n\tcase ImageServicePullLayerProgress_DOWNLOAD_COMPLETE:\n\t\treturn \"layer download complete\"\n\n\tcase ImageServicePullLayerProgress_EXTRACTING:\n\t\treturn fmt.Sprintf(\"extracting layer (%s)\", s.Elapsed.AsDuration())\n\n\tcase ImageServicePullLayerProgress_EXTRACT_COMPLETE:\n\t\treturn \"layer pull complete\"\n\n\tcase ImageServicePullLayerProgress_ALREADY_EXISTS:\n\t\treturn \"layer already exists\"\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/image.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: machine/image.proto\n\npackage machine\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype ImageServicePullLayerProgress_Status int32\n\nconst (\n\t// Keep this in sync with ImagePullLayerProgress.Status.\n\tImageServicePullLayerProgress_DOWNLOADING       ImageServicePullLayerProgress_Status = 0\n\tImageServicePullLayerProgress_DOWNLOAD_COMPLETE ImageServicePullLayerProgress_Status = 1\n\tImageServicePullLayerProgress_EXTRACTING        ImageServicePullLayerProgress_Status = 2\n\tImageServicePullLayerProgress_EXTRACT_COMPLETE  ImageServicePullLayerProgress_Status = 3\n\tImageServicePullLayerProgress_ALREADY_EXISTS    ImageServicePullLayerProgress_Status = 4\n)\n\n// Enum value maps for ImageServicePullLayerProgress_Status.\nvar (\n\tImageServicePullLayerProgress_Status_name = map[int32]string{\n\t\t0: \"DOWNLOADING\",\n\t\t1: \"DOWNLOAD_COMPLETE\",\n\t\t2: \"EXTRACTING\",\n\t\t3: \"EXTRACT_COMPLETE\",\n\t\t4: \"ALREADY_EXISTS\",\n\t}\n\tImageServicePullLayerProgress_Status_value = map[string]int32{\n\t\t\"DOWNLOADING\":       0,\n\t\t\"DOWNLOAD_COMPLETE\": 1,\n\t\t\"EXTRACTING\":        2,\n\t\t\"EXTRACT_COMPLETE\":  3,\n\t\t\"ALREADY_EXISTS\":    4,\n\t}\n)\n\nfunc (x ImageServicePullLayerProgress_Status) Enum() *ImageServicePullLayerProgress_Status {\n\tp := new(ImageServicePullLayerProgress_Status)\n\t*p = x\n\treturn p\n}\n\nfunc (x ImageServicePullLayerProgress_Status) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ImageServicePullLayerProgress_Status) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_image_proto_enumTypes[0].Descriptor()\n}\n\nfunc (ImageServicePullLayerProgress_Status) Type() protoreflect.EnumType {\n\treturn &file_machine_image_proto_enumTypes[0]\n}\n\nfunc (x ImageServicePullLayerProgress_Status) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ImageServicePullLayerProgress_Status.Descriptor instead.\nfunc (ImageServicePullLayerProgress_Status) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{6, 0}\n}\n\ntype ImageServiceListRequest struct {\n\tstate         protoimpl.MessageState     `protogen:\"open.v1\"`\n\tContainerd    *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceListRequest) Reset() {\n\t*x = ImageServiceListRequest{}\n\tmi := &file_machine_image_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceListRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceListRequest) ProtoMessage() {}\n\nfunc (x *ImageServiceListRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceListRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceListRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ImageServiceListRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\ntype ImageServiceListResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tDigest        string                 `protobuf:\"bytes,2,opt,name=digest,proto3\" json:\"digest,omitempty\"`\n\tSize          int64                  `protobuf:\"varint,3,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tCreatedAt     *timestamppb.Timestamp `protobuf:\"bytes,4,opt,name=created_at,json=createdAt,proto3\" json:\"created_at,omitempty\"`\n\tLabels        map[string]string      `protobuf:\"bytes,5,rep,name=labels,proto3\" json:\"labels,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceListResponse) Reset() {\n\t*x = ImageServiceListResponse{}\n\tmi := &file_machine_image_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceListResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceListResponse) ProtoMessage() {}\n\nfunc (x *ImageServiceListResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceListResponse.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceListResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ImageServiceListResponse) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceListResponse) GetDigest() string {\n\tif x != nil {\n\t\treturn x.Digest\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceListResponse) GetSize() int64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *ImageServiceListResponse) GetCreatedAt() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.CreatedAt\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServiceListResponse) GetLabels() map[string]string {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\ntype ImageServicePullRequest struct {\n\tstate      protoimpl.MessageState     `protogen:\"open.v1\"`\n\tContainerd *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\t// Image reference to pull.\n\tImageRef      string `protobuf:\"bytes,3,opt,name=image_ref,json=imageRef,proto3\" json:\"image_ref,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServicePullRequest) Reset() {\n\t*x = ImageServicePullRequest{}\n\tmi := &file_machine_image_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServicePullRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServicePullRequest) ProtoMessage() {}\n\nfunc (x *ImageServicePullRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServicePullRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageServicePullRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ImageServicePullRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServicePullRequest) GetImageRef() string {\n\tif x != nil {\n\t\treturn x.ImageRef\n\t}\n\treturn \"\"\n}\n\ntype ImageServicePullResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Response:\n\t//\n\t//\t*ImageServicePullResponse_Name\n\t//\t*ImageServicePullResponse_PullProgress\n\tResponse      isImageServicePullResponse_Response `protobuf_oneof:\"response\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServicePullResponse) Reset() {\n\t*x = ImageServicePullResponse{}\n\tmi := &file_machine_image_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServicePullResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServicePullResponse) ProtoMessage() {}\n\nfunc (x *ImageServicePullResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServicePullResponse.ProtoReflect.Descriptor instead.\nfunc (*ImageServicePullResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *ImageServicePullResponse) GetResponse() isImageServicePullResponse_Response {\n\tif x != nil {\n\t\treturn x.Response\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServicePullResponse) GetName() string {\n\tif x != nil {\n\t\tif x, ok := x.Response.(*ImageServicePullResponse_Name); ok {\n\t\t\treturn x.Name\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServicePullResponse) GetPullProgress() *ImageServicePullProgress {\n\tif x != nil {\n\t\tif x, ok := x.Response.(*ImageServicePullResponse_PullProgress); ok {\n\t\t\treturn x.PullProgress\n\t\t}\n\t}\n\treturn nil\n}\n\ntype isImageServicePullResponse_Response interface {\n\tisImageServicePullResponse_Response()\n}\n\ntype ImageServicePullResponse_Name struct {\n\t// Name of the pulled image (when done).\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3,oneof\"`\n}\n\ntype ImageServicePullResponse_PullProgress struct {\n\t// Progress of the image pull (intermediate updates).\n\tPullProgress *ImageServicePullProgress `protobuf:\"bytes,2,opt,name=pull_progress,json=pullProgress,proto3,oneof\"`\n}\n\nfunc (*ImageServicePullResponse_Name) isImageServicePullResponse_Response() {}\n\nfunc (*ImageServicePullResponse_PullProgress) isImageServicePullResponse_Response() {}\n\ntype ImageServiceImportRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Request:\n\t//\n\t//\t*ImageServiceImportRequest_Containerd\n\t//\t*ImageServiceImportRequest_ImageChunk\n\tRequest       isImageServiceImportRequest_Request `protobuf_oneof:\"request\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceImportRequest) Reset() {\n\t*x = ImageServiceImportRequest{}\n\tmi := &file_machine_image_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceImportRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceImportRequest) ProtoMessage() {}\n\nfunc (x *ImageServiceImportRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceImportRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceImportRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *ImageServiceImportRequest) GetRequest() isImageServiceImportRequest_Request {\n\tif x != nil {\n\t\treturn x.Request\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServiceImportRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*ImageServiceImportRequest_Containerd); ok {\n\t\t\treturn x.Containerd\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServiceImportRequest) GetImageChunk() *common.Data {\n\tif x != nil {\n\t\tif x, ok := x.Request.(*ImageServiceImportRequest_ImageChunk); ok {\n\t\t\treturn x.ImageChunk\n\t\t}\n\t}\n\treturn nil\n}\n\ntype isImageServiceImportRequest_Request interface {\n\tisImageServiceImportRequest_Request()\n}\n\ntype ImageServiceImportRequest_Containerd struct {\n\t// Containerd instance to use.\n\tContainerd *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3,oneof\"`\n}\n\ntype ImageServiceImportRequest_ImageChunk struct {\n\t// Chunk of the image tarball.\n\tImageChunk *common.Data `protobuf:\"bytes,2,opt,name=image_chunk,json=imageChunk,proto3,oneof\"`\n}\n\nfunc (*ImageServiceImportRequest_Containerd) isImageServiceImportRequest_Request() {}\n\nfunc (*ImageServiceImportRequest_ImageChunk) isImageServiceImportRequest_Request() {}\n\ntype ImageServiceImportResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Name of the imported image.\n\tName          string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceImportResponse) Reset() {\n\t*x = ImageServiceImportResponse{}\n\tmi := &file_machine_image_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceImportResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceImportResponse) ProtoMessage() {}\n\nfunc (x *ImageServiceImportResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceImportResponse.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceImportResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *ImageServiceImportResponse) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\ntype ImageServicePullLayerProgress struct {\n\tstate         protoimpl.MessageState               `protogen:\"open.v1\"`\n\tStatus        ImageServicePullLayerProgress_Status `protobuf:\"varint,1,opt,name=status,proto3,enum=machine.ImageServicePullLayerProgress_Status\" json:\"status,omitempty\"`\n\tElapsed       *durationpb.Duration                 `protobuf:\"bytes,2,opt,name=elapsed,proto3\" json:\"elapsed,omitempty\"`\n\tOffset        int64                                `protobuf:\"varint,3,opt,name=offset,proto3\" json:\"offset,omitempty\"`\n\tTotal         int64                                `protobuf:\"varint,4,opt,name=total,proto3\" json:\"total,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServicePullLayerProgress) Reset() {\n\t*x = ImageServicePullLayerProgress{}\n\tmi := &file_machine_image_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServicePullLayerProgress) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServicePullLayerProgress) ProtoMessage() {}\n\nfunc (x *ImageServicePullLayerProgress) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServicePullLayerProgress.ProtoReflect.Descriptor instead.\nfunc (*ImageServicePullLayerProgress) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ImageServicePullLayerProgress) GetStatus() ImageServicePullLayerProgress_Status {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn ImageServicePullLayerProgress_DOWNLOADING\n}\n\nfunc (x *ImageServicePullLayerProgress) GetElapsed() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Elapsed\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServicePullLayerProgress) GetOffset() int64 {\n\tif x != nil {\n\t\treturn x.Offset\n\t}\n\treturn 0\n}\n\nfunc (x *ImageServicePullLayerProgress) GetTotal() int64 {\n\tif x != nil {\n\t\treturn x.Total\n\t}\n\treturn 0\n}\n\ntype ImageServicePullProgress struct {\n\tstate         protoimpl.MessageState         `protogen:\"open.v1\"`\n\tLayerId       string                         `protobuf:\"bytes,1,opt,name=layer_id,json=layerId,proto3\" json:\"layer_id,omitempty\"`\n\tProgress      *ImageServicePullLayerProgress `protobuf:\"bytes,2,opt,name=progress,proto3\" json:\"progress,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServicePullProgress) Reset() {\n\t*x = ImageServicePullProgress{}\n\tmi := &file_machine_image_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServicePullProgress) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServicePullProgress) ProtoMessage() {}\n\nfunc (x *ImageServicePullProgress) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServicePullProgress.ProtoReflect.Descriptor instead.\nfunc (*ImageServicePullProgress) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *ImageServicePullProgress) GetLayerId() string {\n\tif x != nil {\n\t\treturn x.LayerId\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServicePullProgress) GetProgress() *ImageServicePullLayerProgress {\n\tif x != nil {\n\t\treturn x.Progress\n\t}\n\treturn nil\n}\n\ntype ImageServiceRemoveRequest struct {\n\tstate      protoimpl.MessageState     `protogen:\"open.v1\"`\n\tContainerd *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\t// Image reference to remove.\n\tImageRef      string `protobuf:\"bytes,2,opt,name=image_ref,json=imageRef,proto3\" json:\"image_ref,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceRemoveRequest) Reset() {\n\t*x = ImageServiceRemoveRequest{}\n\tmi := &file_machine_image_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceRemoveRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceRemoveRequest) ProtoMessage() {}\n\nfunc (x *ImageServiceRemoveRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceRemoveRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceRemoveRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *ImageServiceRemoveRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\nfunc (x *ImageServiceRemoveRequest) GetImageRef() string {\n\tif x != nil {\n\t\treturn x.ImageRef\n\t}\n\treturn \"\"\n}\n\ntype ImageServiceVerifyRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Image reference to verify.\n\t//\n\t// The image reference could be either in:\n\t//   - the digest form (e.g. \"docker.io/library/nginx@sha256:abc123...\") to ensure that the exact image is verified.\n\t//   - the tag form (e.g. \"docker.io/library/nginx:latest\") to verify the image currently pointed by the tag, and the resolved\n\t//     digested will be returned in the response.\n\t//\n\t// Any other format will cause the error.\n\tImageRef string `protobuf:\"bytes,1,opt,name=image_ref,json=imageRef,proto3\" json:\"image_ref,omitempty\"`\n\t// Authentication credentials for the registry (if needed).\n\t//\n\t// By default Talos will use configured auth, but additional\n\t// image pull secret can be submitted here.\n\tCredentials   *ImageServiceCredentials `protobuf:\"bytes,2,opt,name=credentials,proto3\" json:\"credentials,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceVerifyRequest) Reset() {\n\t*x = ImageServiceVerifyRequest{}\n\tmi := &file_machine_image_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceVerifyRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceVerifyRequest) ProtoMessage() {}\n\nfunc (x *ImageServiceVerifyRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceVerifyRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceVerifyRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *ImageServiceVerifyRequest) GetImageRef() string {\n\tif x != nil {\n\t\treturn x.ImageRef\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceVerifyRequest) GetCredentials() *ImageServiceCredentials {\n\tif x != nil {\n\t\treturn x.Credentials\n\t}\n\treturn nil\n}\n\ntype ImageServiceCredentials struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Host of the registry (e.g. \"docker.io\").\n\tHost string `protobuf:\"bytes,1,opt,name=host,proto3\" json:\"host,omitempty\"`\n\t// Username for the registry.\n\tUsername string `protobuf:\"bytes,2,opt,name=username,proto3\" json:\"username,omitempty\"`\n\t// Password (token) for the registry.\n\tPassword      string `protobuf:\"bytes,3,opt,name=password,proto3\" json:\"password,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceCredentials) Reset() {\n\t*x = ImageServiceCredentials{}\n\tmi := &file_machine_image_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceCredentials) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceCredentials) ProtoMessage() {}\n\nfunc (x *ImageServiceCredentials) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceCredentials.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceCredentials) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *ImageServiceCredentials) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceCredentials) GetUsername() string {\n\tif x != nil {\n\t\treturn x.Username\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceCredentials) GetPassword() string {\n\tif x != nil {\n\t\treturn x.Password\n\t}\n\treturn \"\"\n}\n\ntype ImageServiceVerifyResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Was the image verified: if it didn't match any verify rule, false will be returned.\n\t// If the image matched the rule, but the verification failed, an error will be returned.\n\tVerified bool `protobuf:\"varint,1,opt,name=verified,proto3\" json:\"verified,omitempty\"`\n\t// Free-form verification result message, e.g. with details about the matched rule and how the image was verified.\n\tMessage string `protobuf:\"bytes,2,opt,name=message,proto3\" json:\"message,omitempty\"`\n\t// The pinned image reference with resolved digest that was verified (e.g. \"docker.io/library/nginx@sha256:abc123...\").\n\t//\n\t// This is only set if verified=true.\n\tDigestedImageRef string `protobuf:\"bytes,3,opt,name=digested_image_ref,json=digestedImageRef,proto3\" json:\"digested_image_ref,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ImageServiceVerifyResponse) Reset() {\n\t*x = ImageServiceVerifyResponse{}\n\tmi := &file_machine_image_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageServiceVerifyResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageServiceVerifyResponse) ProtoMessage() {}\n\nfunc (x *ImageServiceVerifyResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_image_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageServiceVerifyResponse.ProtoReflect.Descriptor instead.\nfunc (*ImageServiceVerifyResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_image_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *ImageServiceVerifyResponse) GetVerified() bool {\n\tif x != nil {\n\t\treturn x.Verified\n\t}\n\treturn false\n}\n\nfunc (x *ImageServiceVerifyResponse) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageServiceVerifyResponse) GetDigestedImageRef() string {\n\tif x != nil {\n\t\treturn x.DigestedImageRef\n\t}\n\treturn \"\"\n}\n\nvar File_machine_image_proto protoreflect.FileDescriptor\n\nconst file_machine_image_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x13machine/image.proto\\x12\\amachine\\x1a\\x13common/common.proto\\x1a\\x1egoogle/protobuf/duration.proto\\x1a\\x1bgoogle/protobuf/empty.proto\\x1a\\x1fgoogle/protobuf/timestamp.proto\\\"U\\n\" +\n\t\"\\x17ImageServiceListRequest\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\\"\\x97\\x02\\n\" +\n\t\"\\x18ImageServiceListResponse\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06digest\\x18\\x02 \\x01(\\tR\\x06digest\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x03 \\x01(\\x03R\\x04size\\x129\\n\" +\n\t\"\\n\" +\n\t\"created_at\\x18\\x04 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\tcreatedAt\\x12E\\n\" +\n\t\"\\x06labels\\x18\\x05 \\x03(\\v2-.machine.ImageServiceListResponse.LabelsEntryR\\x06labels\\x1a9\\n\" +\n\t\"\\vLabelsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"r\\n\" +\n\t\"\\x17ImageServicePullRequest\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\x12\\x1b\\n\" +\n\t\"\\timage_ref\\x18\\x03 \\x01(\\tR\\bimageRef\\\"\\x86\\x01\\n\" +\n\t\"\\x18ImageServicePullResponse\\x12\\x14\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tH\\x00R\\x04name\\x12H\\n\" +\n\t\"\\rpull_progress\\x18\\x02 \\x01(\\v2!.machine.ImageServicePullProgressH\\x00R\\fpullProgressB\\n\" +\n\t\"\\n\" +\n\t\"\\bresponse\\\"\\x95\\x01\\n\" +\n\t\"\\x19ImageServiceImportRequest\\x12<\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceH\\x00R\\n\" +\n\t\"containerd\\x12/\\n\" +\n\t\"\\vimage_chunk\\x18\\x02 \\x01(\\v2\\f.common.DataH\\x00R\\n\" +\n\t\"imageChunkB\\t\\n\" +\n\t\"\\arequest\\\"0\\n\" +\n\t\"\\x1aImageServiceImportResponse\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\\"\\xb5\\x02\\n\" +\n\t\"\\x1dImageServicePullLayerProgress\\x12E\\n\" +\n\t\"\\x06status\\x18\\x01 \\x01(\\x0e2-.machine.ImageServicePullLayerProgress.StatusR\\x06status\\x123\\n\" +\n\t\"\\aelapsed\\x18\\x02 \\x01(\\v2\\x19.google.protobuf.DurationR\\aelapsed\\x12\\x16\\n\" +\n\t\"\\x06offset\\x18\\x03 \\x01(\\x03R\\x06offset\\x12\\x14\\n\" +\n\t\"\\x05total\\x18\\x04 \\x01(\\x03R\\x05total\\\"j\\n\" +\n\t\"\\x06Status\\x12\\x0f\\n\" +\n\t\"\\vDOWNLOADING\\x10\\x00\\x12\\x15\\n\" +\n\t\"\\x11DOWNLOAD_COMPLETE\\x10\\x01\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"EXTRACTING\\x10\\x02\\x12\\x14\\n\" +\n\t\"\\x10EXTRACT_COMPLETE\\x10\\x03\\x12\\x12\\n\" +\n\t\"\\x0eALREADY_EXISTS\\x10\\x04\\\"y\\n\" +\n\t\"\\x18ImageServicePullProgress\\x12\\x19\\n\" +\n\t\"\\blayer_id\\x18\\x01 \\x01(\\tR\\alayerId\\x12B\\n\" +\n\t\"\\bprogress\\x18\\x02 \\x01(\\v2&.machine.ImageServicePullLayerProgressR\\bprogress\\\"t\\n\" +\n\t\"\\x19ImageServiceRemoveRequest\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\x12\\x1b\\n\" +\n\t\"\\timage_ref\\x18\\x02 \\x01(\\tR\\bimageRef\\\"|\\n\" +\n\t\"\\x19ImageServiceVerifyRequest\\x12\\x1b\\n\" +\n\t\"\\timage_ref\\x18\\x01 \\x01(\\tR\\bimageRef\\x12B\\n\" +\n\t\"\\vcredentials\\x18\\x02 \\x01(\\v2 .machine.ImageServiceCredentialsR\\vcredentials\\\"e\\n\" +\n\t\"\\x17ImageServiceCredentials\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x01 \\x01(\\tR\\x04host\\x12\\x1a\\n\" +\n\t\"\\busername\\x18\\x02 \\x01(\\tR\\busername\\x12\\x1a\\n\" +\n\t\"\\bpassword\\x18\\x03 \\x01(\\tR\\bpassword\\\"\\x80\\x01\\n\" +\n\t\"\\x1aImageServiceVerifyResponse\\x12\\x1a\\n\" +\n\t\"\\bverified\\x18\\x01 \\x01(\\bR\\bverified\\x12\\x18\\n\" +\n\t\"\\amessage\\x18\\x02 \\x01(\\tR\\amessage\\x12,\\n\" +\n\t\"\\x12digested_image_ref\\x18\\x03 \\x01(\\tR\\x10digestedImageRef2\\x9a\\x03\\n\" +\n\t\"\\fImageService\\x12M\\n\" +\n\t\"\\x04List\\x12 .machine.ImageServiceListRequest\\x1a!.machine.ImageServiceListResponse0\\x01\\x12M\\n\" +\n\t\"\\x04Pull\\x12 .machine.ImageServicePullRequest\\x1a!.machine.ImageServicePullResponse0\\x01\\x12S\\n\" +\n\t\"\\x06Import\\x12\\\".machine.ImageServiceImportRequest\\x1a#.machine.ImageServiceImportResponse(\\x01\\x12D\\n\" +\n\t\"\\x06Remove\\x12\\\".machine.ImageServiceRemoveRequest\\x1a\\x16.google.protobuf.Empty\\x12Q\\n\" +\n\t\"\\x06Verify\\x12\\\".machine.ImageServiceVerifyRequest\\x1a#.machine.ImageServiceVerifyResponseBN\\n\" +\n\t\"\\x15dev.talos.api.machineZ5github.com/siderolabs/talos/pkg/machinery/api/machineb\\x06proto3\"\n\nvar (\n\tfile_machine_image_proto_rawDescOnce sync.Once\n\tfile_machine_image_proto_rawDescData []byte\n)\n\nfunc file_machine_image_proto_rawDescGZIP() []byte {\n\tfile_machine_image_proto_rawDescOnce.Do(func() {\n\t\tfile_machine_image_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_machine_image_proto_rawDesc), len(file_machine_image_proto_rawDesc)))\n\t})\n\treturn file_machine_image_proto_rawDescData\n}\n\nvar file_machine_image_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_machine_image_proto_msgTypes = make([]protoimpl.MessageInfo, 13)\nvar file_machine_image_proto_goTypes = []any{\n\t(ImageServicePullLayerProgress_Status)(0), // 0: machine.ImageServicePullLayerProgress.Status\n\t(*ImageServiceListRequest)(nil),           // 1: machine.ImageServiceListRequest\n\t(*ImageServiceListResponse)(nil),          // 2: machine.ImageServiceListResponse\n\t(*ImageServicePullRequest)(nil),           // 3: machine.ImageServicePullRequest\n\t(*ImageServicePullResponse)(nil),          // 4: machine.ImageServicePullResponse\n\t(*ImageServiceImportRequest)(nil),         // 5: machine.ImageServiceImportRequest\n\t(*ImageServiceImportResponse)(nil),        // 6: machine.ImageServiceImportResponse\n\t(*ImageServicePullLayerProgress)(nil),     // 7: machine.ImageServicePullLayerProgress\n\t(*ImageServicePullProgress)(nil),          // 8: machine.ImageServicePullProgress\n\t(*ImageServiceRemoveRequest)(nil),         // 9: machine.ImageServiceRemoveRequest\n\t(*ImageServiceVerifyRequest)(nil),         // 10: machine.ImageServiceVerifyRequest\n\t(*ImageServiceCredentials)(nil),           // 11: machine.ImageServiceCredentials\n\t(*ImageServiceVerifyResponse)(nil),        // 12: machine.ImageServiceVerifyResponse\n\tnil,                                       // 13: machine.ImageServiceListResponse.LabelsEntry\n\t(*common.ContainerdInstance)(nil),         // 14: common.ContainerdInstance\n\t(*timestamppb.Timestamp)(nil),             // 15: google.protobuf.Timestamp\n\t(*common.Data)(nil),                       // 16: common.Data\n\t(*durationpb.Duration)(nil),               // 17: google.protobuf.Duration\n\t(*emptypb.Empty)(nil),                     // 18: google.protobuf.Empty\n}\nvar file_machine_image_proto_depIdxs = []int32{\n\t14, // 0: machine.ImageServiceListRequest.containerd:type_name -> common.ContainerdInstance\n\t15, // 1: machine.ImageServiceListResponse.created_at:type_name -> google.protobuf.Timestamp\n\t13, // 2: machine.ImageServiceListResponse.labels:type_name -> machine.ImageServiceListResponse.LabelsEntry\n\t14, // 3: machine.ImageServicePullRequest.containerd:type_name -> common.ContainerdInstance\n\t8,  // 4: machine.ImageServicePullResponse.pull_progress:type_name -> machine.ImageServicePullProgress\n\t14, // 5: machine.ImageServiceImportRequest.containerd:type_name -> common.ContainerdInstance\n\t16, // 6: machine.ImageServiceImportRequest.image_chunk:type_name -> common.Data\n\t0,  // 7: machine.ImageServicePullLayerProgress.status:type_name -> machine.ImageServicePullLayerProgress.Status\n\t17, // 8: machine.ImageServicePullLayerProgress.elapsed:type_name -> google.protobuf.Duration\n\t7,  // 9: machine.ImageServicePullProgress.progress:type_name -> machine.ImageServicePullLayerProgress\n\t14, // 10: machine.ImageServiceRemoveRequest.containerd:type_name -> common.ContainerdInstance\n\t11, // 11: machine.ImageServiceVerifyRequest.credentials:type_name -> machine.ImageServiceCredentials\n\t1,  // 12: machine.ImageService.List:input_type -> machine.ImageServiceListRequest\n\t3,  // 13: machine.ImageService.Pull:input_type -> machine.ImageServicePullRequest\n\t5,  // 14: machine.ImageService.Import:input_type -> machine.ImageServiceImportRequest\n\t9,  // 15: machine.ImageService.Remove:input_type -> machine.ImageServiceRemoveRequest\n\t10, // 16: machine.ImageService.Verify:input_type -> machine.ImageServiceVerifyRequest\n\t2,  // 17: machine.ImageService.List:output_type -> machine.ImageServiceListResponse\n\t4,  // 18: machine.ImageService.Pull:output_type -> machine.ImageServicePullResponse\n\t6,  // 19: machine.ImageService.Import:output_type -> machine.ImageServiceImportResponse\n\t18, // 20: machine.ImageService.Remove:output_type -> google.protobuf.Empty\n\t12, // 21: machine.ImageService.Verify:output_type -> machine.ImageServiceVerifyResponse\n\t17, // [17:22] is the sub-list for method output_type\n\t12, // [12:17] is the sub-list for method input_type\n\t12, // [12:12] is the sub-list for extension type_name\n\t12, // [12:12] is the sub-list for extension extendee\n\t0,  // [0:12] is the sub-list for field type_name\n}\n\nfunc init() { file_machine_image_proto_init() }\nfunc file_machine_image_proto_init() {\n\tif File_machine_image_proto != nil {\n\t\treturn\n\t}\n\tfile_machine_image_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*ImageServicePullResponse_Name)(nil),\n\t\t(*ImageServicePullResponse_PullProgress)(nil),\n\t}\n\tfile_machine_image_proto_msgTypes[4].OneofWrappers = []any{\n\t\t(*ImageServiceImportRequest_Containerd)(nil),\n\t\t(*ImageServiceImportRequest_ImageChunk)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_machine_image_proto_rawDesc), len(file_machine_image_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   13,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_machine_image_proto_goTypes,\n\t\tDependencyIndexes: file_machine_image_proto_depIdxs,\n\t\tEnumInfos:         file_machine_image_proto_enumTypes,\n\t\tMessageInfos:      file_machine_image_proto_msgTypes,\n\t}.Build()\n\tFile_machine_image_proto = out.File\n\tfile_machine_image_proto_goTypes = nil\n\tfile_machine_image_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/image_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: machine/image.proto\n\npackage machine\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tImageService_List_FullMethodName   = \"/machine.ImageService/List\"\n\tImageService_Pull_FullMethodName   = \"/machine.ImageService/Pull\"\n\tImageService_Import_FullMethodName = \"/machine.ImageService/Import\"\n\tImageService_Remove_FullMethodName = \"/machine.ImageService/Remove\"\n\tImageService_Verify_FullMethodName = \"/machine.ImageService/Verify\"\n)\n\n// ImageServiceClient is the client API for ImageService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The machine service definition.\ntype ImageServiceClient interface {\n\t// List images in the containerd.\n\tList(ctx context.Context, in *ImageServiceListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageServiceListResponse], error)\n\t// Pull an image into the containerd.\n\tPull(ctx context.Context, in *ImageServicePullRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageServicePullResponse], error)\n\t// Import an image from a stream (tarball).\n\tImport(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[ImageServiceImportRequest, ImageServiceImportResponse], error)\n\t// Remove an image from the containerd.\n\tRemove(ctx context.Context, in *ImageServiceRemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)\n\t// Verify an image signature.\n\tVerify(ctx context.Context, in *ImageServiceVerifyRequest, opts ...grpc.CallOption) (*ImageServiceVerifyResponse, error)\n}\n\ntype imageServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewImageServiceClient(cc grpc.ClientConnInterface) ImageServiceClient {\n\treturn &imageServiceClient{cc}\n}\n\nfunc (c *imageServiceClient) List(ctx context.Context, in *ImageServiceListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageServiceListResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &ImageService_ServiceDesc.Streams[0], ImageService_List_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ImageServiceListRequest, ImageServiceListResponse]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_ListClient = grpc.ServerStreamingClient[ImageServiceListResponse]\n\nfunc (c *imageServiceClient) Pull(ctx context.Context, in *ImageServicePullRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageServicePullResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &ImageService_ServiceDesc.Streams[1], ImageService_Pull_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ImageServicePullRequest, ImageServicePullResponse]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_PullClient = grpc.ServerStreamingClient[ImageServicePullResponse]\n\nfunc (c *imageServiceClient) Import(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[ImageServiceImportRequest, ImageServiceImportResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &ImageService_ServiceDesc.Streams[2], ImageService_Import_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ImageServiceImportRequest, ImageServiceImportResponse]{ClientStream: stream}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_ImportClient = grpc.ClientStreamingClient[ImageServiceImportRequest, ImageServiceImportResponse]\n\nfunc (c *imageServiceClient) Remove(ctx context.Context, in *ImageServiceRemoveRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(emptypb.Empty)\n\terr := c.cc.Invoke(ctx, ImageService_Remove_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *imageServiceClient) Verify(ctx context.Context, in *ImageServiceVerifyRequest, opts ...grpc.CallOption) (*ImageServiceVerifyResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ImageServiceVerifyResponse)\n\terr := c.cc.Invoke(ctx, ImageService_Verify_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// ImageServiceServer is the server API for ImageService service.\n// All implementations must embed UnimplementedImageServiceServer\n// for forward compatibility.\n//\n// The machine service definition.\ntype ImageServiceServer interface {\n\t// List images in the containerd.\n\tList(*ImageServiceListRequest, grpc.ServerStreamingServer[ImageServiceListResponse]) error\n\t// Pull an image into the containerd.\n\tPull(*ImageServicePullRequest, grpc.ServerStreamingServer[ImageServicePullResponse]) error\n\t// Import an image from a stream (tarball).\n\tImport(grpc.ClientStreamingServer[ImageServiceImportRequest, ImageServiceImportResponse]) error\n\t// Remove an image from the containerd.\n\tRemove(context.Context, *ImageServiceRemoveRequest) (*emptypb.Empty, error)\n\t// Verify an image signature.\n\tVerify(context.Context, *ImageServiceVerifyRequest) (*ImageServiceVerifyResponse, error)\n\tmustEmbedUnimplementedImageServiceServer()\n}\n\n// UnimplementedImageServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedImageServiceServer struct{}\n\nfunc (UnimplementedImageServiceServer) List(*ImageServiceListRequest, grpc.ServerStreamingServer[ImageServiceListResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method List not implemented\")\n}\nfunc (UnimplementedImageServiceServer) Pull(*ImageServicePullRequest, grpc.ServerStreamingServer[ImageServicePullResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method Pull not implemented\")\n}\nfunc (UnimplementedImageServiceServer) Import(grpc.ClientStreamingServer[ImageServiceImportRequest, ImageServiceImportResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method Import not implemented\")\n}\nfunc (UnimplementedImageServiceServer) Remove(context.Context, *ImageServiceRemoveRequest) (*emptypb.Empty, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Remove not implemented\")\n}\nfunc (UnimplementedImageServiceServer) Verify(context.Context, *ImageServiceVerifyRequest) (*ImageServiceVerifyResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Verify not implemented\")\n}\nfunc (UnimplementedImageServiceServer) mustEmbedUnimplementedImageServiceServer() {}\nfunc (UnimplementedImageServiceServer) testEmbeddedByValue()                      {}\n\n// UnsafeImageServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to ImageServiceServer will\n// result in compilation errors.\ntype UnsafeImageServiceServer interface {\n\tmustEmbedUnimplementedImageServiceServer()\n}\n\nfunc RegisterImageServiceServer(s grpc.ServiceRegistrar, srv ImageServiceServer) {\n\t// If the following call panics, it indicates UnimplementedImageServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&ImageService_ServiceDesc, srv)\n}\n\nfunc _ImageService_List_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(ImageServiceListRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(ImageServiceServer).List(m, &grpc.GenericServerStream[ImageServiceListRequest, ImageServiceListResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_ListServer = grpc.ServerStreamingServer[ImageServiceListResponse]\n\nfunc _ImageService_Pull_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(ImageServicePullRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(ImageServiceServer).Pull(m, &grpc.GenericServerStream[ImageServicePullRequest, ImageServicePullResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_PullServer = grpc.ServerStreamingServer[ImageServicePullResponse]\n\nfunc _ImageService_Import_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(ImageServiceServer).Import(&grpc.GenericServerStream[ImageServiceImportRequest, ImageServiceImportResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype ImageService_ImportServer = grpc.ClientStreamingServer[ImageServiceImportRequest, ImageServiceImportResponse]\n\nfunc _ImageService_Remove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ImageServiceRemoveRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ImageServiceServer).Remove(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: ImageService_Remove_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ImageServiceServer).Remove(ctx, req.(*ImageServiceRemoveRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _ImageService_Verify_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ImageServiceVerifyRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ImageServiceServer).Verify(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: ImageService_Verify_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ImageServiceServer).Verify(ctx, req.(*ImageServiceVerifyRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// ImageService_ServiceDesc is the grpc.ServiceDesc for ImageService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar ImageService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"machine.ImageService\",\n\tHandlerType: (*ImageServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Remove\",\n\t\t\tHandler:    _ImageService_Remove_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Verify\",\n\t\t\tHandler:    _ImageService_Verify_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"List\",\n\t\t\tHandler:       _ImageService_List_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Pull\",\n\t\t\tHandler:       _ImageService_Pull_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Import\",\n\t\t\tHandler:       _ImageService_Import_Handler,\n\t\t\tClientStreams: true,\n\t\t},\n\t},\n\tMetadata: \"machine/image.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/image_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: machine/image.proto\n\npackage machine\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\ttimestamppb \"github.com/planetscale/vtprotobuf/types/known/timestamppb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n\ttimestamppb1 \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ImageServiceListRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceListRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceListRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceListResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceListResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceListResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Labels) > 0 {\n\t\tfor k := range m.Labels {\n\t\t\tv := m.Labels[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif m.CreatedAt != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.CreatedAt).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Digest) > 0 {\n\t\ti -= len(m.Digest)\n\t\tcopy(dAtA[i:], m.Digest)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Digest)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServicePullRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServicePullRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ImageRef) > 0 {\n\t\ti -= len(m.ImageRef)\n\t\tcopy(dAtA[i:], m.ImageRef)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImageRef)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServicePullResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServicePullResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif vtmsg, ok := m.Response.(interface {\n\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t}); ok {\n\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServicePullResponse_Name) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullResponse_Name) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti -= len(m.Name)\n\tcopy(dAtA[i:], m.Name)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\ti--\n\tdAtA[i] = 0xa\n\treturn len(dAtA) - i, nil\n}\nfunc (m *ImageServicePullResponse_PullProgress) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullResponse_PullProgress) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\tif m.PullProgress != nil {\n\t\tsize, err := m.PullProgress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t} else {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, 0)\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\treturn len(dAtA) - i, nil\n}\nfunc (m *ImageServiceImportRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceImportRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceImportRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif vtmsg, ok := m.Request.(interface {\n\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t}); ok {\n\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceImportRequest_Containerd) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceImportRequest_Containerd) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t} else {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, 0)\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\nfunc (m *ImageServiceImportRequest_ImageChunk) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceImportRequest_ImageChunk) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\tif m.ImageChunk != nil {\n\t\tif vtmsg, ok := interface{}(m.ImageChunk).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.ImageChunk)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t} else {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, 0)\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\treturn len(dAtA) - i, nil\n}\nfunc (m *ImageServiceImportResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceImportResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceImportResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServicePullLayerProgress) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServicePullLayerProgress) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullLayerProgress) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Total != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Total))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Offset != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Offset))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Elapsed != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Elapsed).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Status != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServicePullProgress) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServicePullProgress) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServicePullProgress) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Progress != nil {\n\t\tsize, err := m.Progress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.LayerId) > 0 {\n\t\ti -= len(m.LayerId)\n\t\tcopy(dAtA[i:], m.LayerId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LayerId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceRemoveRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceRemoveRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceRemoveRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ImageRef) > 0 {\n\t\ti -= len(m.ImageRef)\n\t\tcopy(dAtA[i:], m.ImageRef)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImageRef)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceVerifyRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceVerifyRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceVerifyRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Credentials != nil {\n\t\tsize, err := m.Credentials.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.ImageRef) > 0 {\n\t\ti -= len(m.ImageRef)\n\t\tcopy(dAtA[i:], m.ImageRef)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImageRef)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceCredentials) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceCredentials) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceCredentials) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Password) > 0 {\n\t\ti -= len(m.Password)\n\t\tcopy(dAtA[i:], m.Password)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Password)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Username) > 0 {\n\t\ti -= len(m.Username)\n\t\tcopy(dAtA[i:], m.Username)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Username)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceVerifyResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageServiceVerifyResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageServiceVerifyResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.DigestedImageRef) > 0 {\n\t\ti -= len(m.DigestedImageRef)\n\t\tcopy(dAtA[i:], m.DigestedImageRef)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DigestedImageRef)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Message) > 0 {\n\t\ti -= len(m.Message)\n\t\tcopy(dAtA[i:], m.Message)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Verified {\n\t\ti--\n\t\tif m.Verified {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageServiceListRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceListResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Digest)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.CreatedAt != nil {\n\t\tl = (*timestamppb.Timestamp)(m.CreatedAt).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Labels) > 0 {\n\t\tfor k, v := range m.Labels {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServicePullRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ImageRef)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServicePullResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif vtmsg, ok := m.Response.(interface{ SizeVT() int }); ok {\n\t\tn += vtmsg.SizeVT()\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServicePullResponse_Name) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\treturn n\n}\nfunc (m *ImageServicePullResponse_PullProgress) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.PullProgress != nil {\n\t\tl = m.PullProgress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t} else {\n\t\tn += 2\n\t}\n\treturn n\n}\nfunc (m *ImageServiceImportRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif vtmsg, ok := m.Request.(interface{ SizeVT() int }); ok {\n\t\tn += vtmsg.SizeVT()\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceImportRequest_Containerd) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t} else {\n\t\tn += 2\n\t}\n\treturn n\n}\nfunc (m *ImageServiceImportRequest_ImageChunk) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.ImageChunk != nil {\n\t\tif size, ok := interface{}(m.ImageChunk).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.ImageChunk)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t} else {\n\t\tn += 2\n\t}\n\treturn n\n}\nfunc (m *ImageServiceImportResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServicePullLayerProgress) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Status != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Status))\n\t}\n\tif m.Elapsed != nil {\n\t\tl = (*durationpb.Duration)(m.Elapsed).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Offset != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Offset))\n\t}\n\tif m.Total != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Total))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServicePullProgress) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.LayerId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Progress != nil {\n\t\tl = m.Progress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceRemoveRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ImageRef)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceVerifyRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ImageRef)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Credentials != nil {\n\t\tl = m.Credentials.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceCredentials) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Username)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Password)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceVerifyResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Verified {\n\t\tn += 2\n\t}\n\tl = len(m.Message)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DigestedImageRef)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageServiceListRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceListRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceListRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceListResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceListResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceListResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Digest\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Digest = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CreatedAt\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CreatedAt == nil {\n\t\t\t\tm.CreatedAt = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.CreatedAt).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Labels\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Labels == nil {\n\t\t\t\tm.Labels = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Labels[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServicePullRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageRef\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImageRef = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServicePullResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Response = &ImageServicePullResponse_Name{Name: string(dAtA[iNdEx:postIndex])}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PullProgress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif oneof, ok := m.Response.(*ImageServicePullResponse_PullProgress); ok {\n\t\t\t\tif err := oneof.PullProgress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tv := &ImageServicePullProgress{}\n\t\t\t\tif err := v.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tm.Response = &ImageServicePullResponse_PullProgress{PullProgress: v}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceImportRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceImportRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceImportRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif oneof, ok := m.Request.(*ImageServiceImportRequest_Containerd); ok {\n\t\t\t\tif unmarshal, ok := interface{}(oneof.Containerd).(interface {\n\t\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t\t}); ok {\n\t\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], oneof.Containerd); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tv := &common.ContainerdInstance{}\n\t\t\t\tif unmarshal, ok := interface{}(v).(interface {\n\t\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t\t}); ok {\n\t\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], v); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.Request = &ImageServiceImportRequest_Containerd{Containerd: v}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageChunk\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif oneof, ok := m.Request.(*ImageServiceImportRequest_ImageChunk); ok {\n\t\t\t\tif unmarshal, ok := interface{}(oneof.ImageChunk).(interface {\n\t\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t\t}); ok {\n\t\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], oneof.ImageChunk); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tv := &common.Data{}\n\t\t\t\tif unmarshal, ok := interface{}(v).(interface {\n\t\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t\t}); ok {\n\t\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], v); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.Request = &ImageServiceImportRequest_ImageChunk{ImageChunk: v}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceImportResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceImportResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceImportResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServicePullLayerProgress) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullLayerProgress: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullLayerProgress: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tm.Status = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Status |= ImageServicePullLayerProgress_Status(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Elapsed\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Elapsed == nil {\n\t\t\t\tm.Elapsed = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Elapsed).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Offset\", wireType)\n\t\t\t}\n\t\t\tm.Offset = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Offset |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Total\", wireType)\n\t\t\t}\n\t\t\tm.Total = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Total |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServicePullProgress) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullProgress: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServicePullProgress: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LayerId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LayerId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Progress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Progress == nil {\n\t\t\t\tm.Progress = &ImageServicePullLayerProgress{}\n\t\t\t}\n\t\t\tif err := m.Progress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceRemoveRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceRemoveRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceRemoveRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageRef\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImageRef = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceVerifyRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceVerifyRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceVerifyRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageRef\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImageRef = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Credentials\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Credentials == nil {\n\t\t\t\tm.Credentials = &ImageServiceCredentials{}\n\t\t\t}\n\t\t\tif err := m.Credentials.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceCredentials) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceCredentials: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceCredentials: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Username\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Username = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Password\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Password = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageServiceVerifyResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceVerifyResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageServiceVerifyResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Verified\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Verified = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Message = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DigestedImageRef\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DigestedImageRef = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/lifecycle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package machine contains the machine service API definitions.\npackage machine\n\nimport \"fmt\"\n\n// Fmt formats the pull progress status into a human-readable string.\nfunc (s *LifecycleServiceInstallProgress) Fmt() string {\n\tswitch msg := s.GetResponse().(type) {\n\tcase *LifecycleServiceInstallProgress_Message:\n\t\treturn msg.Message\n\tcase *LifecycleServiceInstallProgress_ExitCode:\n\t\treturn fmt.Sprintf(\"Exit code: %d\", msg.ExitCode)\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/lifecycle.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: machine/lifecycle.proto\n\npackage machine\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// InstallArtifactsSource specifies the source of the installation artifacts.\ntype InstallArtifactsSource struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The reference name of the image, as returned by `talosctl image pull`.\n\tImageName     string `protobuf:\"bytes,1,opt,name=image_name,json=imageName,proto3\" json:\"image_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *InstallArtifactsSource) Reset() {\n\t*x = InstallArtifactsSource{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *InstallArtifactsSource) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InstallArtifactsSource) ProtoMessage() {}\n\nfunc (x *InstallArtifactsSource) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InstallArtifactsSource.ProtoReflect.Descriptor instead.\nfunc (*InstallArtifactsSource) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *InstallArtifactsSource) GetImageName() string {\n\tif x != nil {\n\t\treturn x.ImageName\n\t}\n\treturn \"\"\n}\n\n// InstallDestination specifies the target for installation.\ntype InstallDestination struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The disk to which Talos should be installed, e.g. \"/dev/sda\".\n\tDisk          string `protobuf:\"bytes,1,opt,name=disk,proto3\" json:\"disk,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *InstallDestination) Reset() {\n\t*x = InstallDestination{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *InstallDestination) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InstallDestination) ProtoMessage() {}\n\nfunc (x *InstallDestination) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InstallDestination.ProtoReflect.Descriptor instead.\nfunc (*InstallDestination) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *InstallDestination) GetDisk() string {\n\tif x != nil {\n\t\treturn x.Disk\n\t}\n\treturn \"\"\n}\n\n// LifecycleServiceInstallRequest contains the necessary information to perform an installation.\ntype LifecycleServiceInstallRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The containerd instance to use for pulling the installation artifacts.\n\tContainerd *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\t// The source of the installation artifacts.\n\tSource *InstallArtifactsSource `protobuf:\"bytes,2,opt,name=source,proto3\" json:\"source,omitempty\"`\n\t// The destination for the installation.\n\tDestination   *InstallDestination `protobuf:\"bytes,3,opt,name=destination,proto3\" json:\"destination,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LifecycleServiceInstallRequest) Reset() {\n\t*x = LifecycleServiceInstallRequest{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LifecycleServiceInstallRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LifecycleServiceInstallRequest) ProtoMessage() {}\n\nfunc (x *LifecycleServiceInstallRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LifecycleServiceInstallRequest.ProtoReflect.Descriptor instead.\nfunc (*LifecycleServiceInstallRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *LifecycleServiceInstallRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\nfunc (x *LifecycleServiceInstallRequest) GetSource() *InstallArtifactsSource {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn nil\n}\n\nfunc (x *LifecycleServiceInstallRequest) GetDestination() *InstallDestination {\n\tif x != nil {\n\t\treturn x.Destination\n\t}\n\treturn nil\n}\n\n// LifecycleServiceInstallProgress represents the progress of the installation or upgrade process.\ntype LifecycleServiceInstallProgress struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Types that are valid to be assigned to Response:\n\t//\n\t//\t*LifecycleServiceInstallProgress_Message\n\t//\t*LifecycleServiceInstallProgress_ExitCode\n\tResponse      isLifecycleServiceInstallProgress_Response `protobuf_oneof:\"response\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LifecycleServiceInstallProgress) Reset() {\n\t*x = LifecycleServiceInstallProgress{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LifecycleServiceInstallProgress) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LifecycleServiceInstallProgress) ProtoMessage() {}\n\nfunc (x *LifecycleServiceInstallProgress) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LifecycleServiceInstallProgress.ProtoReflect.Descriptor instead.\nfunc (*LifecycleServiceInstallProgress) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *LifecycleServiceInstallProgress) GetResponse() isLifecycleServiceInstallProgress_Response {\n\tif x != nil {\n\t\treturn x.Response\n\t}\n\treturn nil\n}\n\nfunc (x *LifecycleServiceInstallProgress) GetMessage() string {\n\tif x != nil {\n\t\tif x, ok := x.Response.(*LifecycleServiceInstallProgress_Message); ok {\n\t\t\treturn x.Message\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc (x *LifecycleServiceInstallProgress) GetExitCode() int32 {\n\tif x != nil {\n\t\tif x, ok := x.Response.(*LifecycleServiceInstallProgress_ExitCode); ok {\n\t\t\treturn x.ExitCode\n\t\t}\n\t}\n\treturn 0\n}\n\ntype isLifecycleServiceInstallProgress_Response interface {\n\tisLifecycleServiceInstallProgress_Response()\n}\n\ntype LifecycleServiceInstallProgress_Message struct {\n\t// A message indicating the current progress of the installation or upgrade.\n\tMessage string `protobuf:\"bytes,1,opt,name=message,proto3,oneof\"`\n}\n\ntype LifecycleServiceInstallProgress_ExitCode struct {\n\t// An exit code indicating the result of the installation or upgrade process.\n\t// A non-zero value indicates an error.\n\t// Server SHOULD NOT respond with error, even if the value is non-zero.\n\t// It's responsibility of the client to handle the exit code appropriately.\n\tExitCode int32 `protobuf:\"varint,2,opt,name=exit_code,json=exitCode,proto3,oneof\"`\n}\n\nfunc (*LifecycleServiceInstallProgress_Message) isLifecycleServiceInstallProgress_Response() {}\n\nfunc (*LifecycleServiceInstallProgress_ExitCode) isLifecycleServiceInstallProgress_Response() {}\n\n// LifecycleServiceInstallResponse is the response message for the Install RPC, containing progress updates.\ntype LifecycleServiceInstallResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The progress of the installation process.\n\tProgress      *LifecycleServiceInstallProgress `protobuf:\"bytes,1,opt,name=progress,proto3\" json:\"progress,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LifecycleServiceInstallResponse) Reset() {\n\t*x = LifecycleServiceInstallResponse{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LifecycleServiceInstallResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LifecycleServiceInstallResponse) ProtoMessage() {}\n\nfunc (x *LifecycleServiceInstallResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LifecycleServiceInstallResponse.ProtoReflect.Descriptor instead.\nfunc (*LifecycleServiceInstallResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *LifecycleServiceInstallResponse) GetProgress() *LifecycleServiceInstallProgress {\n\tif x != nil {\n\t\treturn x.Progress\n\t}\n\treturn nil\n}\n\n// LifecycleServiceUpgradeRequest contains the necessary information to perform an upgrade.\ntype LifecycleServiceUpgradeRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The containerd instance to use for pulling the installation artifacts.\n\tContainerd *common.ContainerdInstance `protobuf:\"bytes,1,opt,name=containerd,proto3\" json:\"containerd,omitempty\"`\n\t// The source of the installation artifacts for the upgrade.\n\tSource        *InstallArtifactsSource `protobuf:\"bytes,2,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LifecycleServiceUpgradeRequest) Reset() {\n\t*x = LifecycleServiceUpgradeRequest{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LifecycleServiceUpgradeRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LifecycleServiceUpgradeRequest) ProtoMessage() {}\n\nfunc (x *LifecycleServiceUpgradeRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LifecycleServiceUpgradeRequest.ProtoReflect.Descriptor instead.\nfunc (*LifecycleServiceUpgradeRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *LifecycleServiceUpgradeRequest) GetContainerd() *common.ContainerdInstance {\n\tif x != nil {\n\t\treturn x.Containerd\n\t}\n\treturn nil\n}\n\nfunc (x *LifecycleServiceUpgradeRequest) GetSource() *InstallArtifactsSource {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn nil\n}\n\n// LifecycleServiceUpgradeResponse is the response message for the Upgrade RPC, containing progress updates.\ntype LifecycleServiceUpgradeResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// The progress of the upgrade process.\n\tProgress      *LifecycleServiceInstallProgress `protobuf:\"bytes,1,opt,name=progress,proto3\" json:\"progress,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LifecycleServiceUpgradeResponse) Reset() {\n\t*x = LifecycleServiceUpgradeResponse{}\n\tmi := &file_machine_lifecycle_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LifecycleServiceUpgradeResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LifecycleServiceUpgradeResponse) ProtoMessage() {}\n\nfunc (x *LifecycleServiceUpgradeResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_lifecycle_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LifecycleServiceUpgradeResponse.ProtoReflect.Descriptor instead.\nfunc (*LifecycleServiceUpgradeResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_lifecycle_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *LifecycleServiceUpgradeResponse) GetProgress() *LifecycleServiceInstallProgress {\n\tif x != nil {\n\t\treturn x.Progress\n\t}\n\treturn nil\n}\n\nvar File_machine_lifecycle_proto protoreflect.FileDescriptor\n\nconst file_machine_lifecycle_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x17machine/lifecycle.proto\\x12\\amachine\\x1a\\x13common/common.proto\\\"7\\n\" +\n\t\"\\x16InstallArtifactsSource\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"image_name\\x18\\x01 \\x01(\\tR\\timageName\\\"(\\n\" +\n\t\"\\x12InstallDestination\\x12\\x12\\n\" +\n\t\"\\x04disk\\x18\\x01 \\x01(\\tR\\x04disk\\\"\\xd4\\x01\\n\" +\n\t\"\\x1eLifecycleServiceInstallRequest\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\x127\\n\" +\n\t\"\\x06source\\x18\\x02 \\x01(\\v2\\x1f.machine.InstallArtifactsSourceR\\x06source\\x12=\\n\" +\n\t\"\\vdestination\\x18\\x03 \\x01(\\v2\\x1b.machine.InstallDestinationR\\vdestination\\\"h\\n\" +\n\t\"\\x1fLifecycleServiceInstallProgress\\x12\\x1a\\n\" +\n\t\"\\amessage\\x18\\x01 \\x01(\\tH\\x00R\\amessage\\x12\\x1d\\n\" +\n\t\"\\texit_code\\x18\\x02 \\x01(\\x05H\\x00R\\bexitCodeB\\n\" +\n\t\"\\n\" +\n\t\"\\bresponse\\\"g\\n\" +\n\t\"\\x1fLifecycleServiceInstallResponse\\x12D\\n\" +\n\t\"\\bprogress\\x18\\x01 \\x01(\\v2(.machine.LifecycleServiceInstallProgressR\\bprogress\\\"\\x95\\x01\\n\" +\n\t\"\\x1eLifecycleServiceUpgradeRequest\\x12:\\n\" +\n\t\"\\n\" +\n\t\"containerd\\x18\\x01 \\x01(\\v2\\x1a.common.ContainerdInstanceR\\n\" +\n\t\"containerd\\x127\\n\" +\n\t\"\\x06source\\x18\\x02 \\x01(\\v2\\x1f.machine.InstallArtifactsSourceR\\x06source\\\"g\\n\" +\n\t\"\\x1fLifecycleServiceUpgradeResponse\\x12D\\n\" +\n\t\"\\bprogress\\x18\\x01 \\x01(\\v2(.machine.LifecycleServiceInstallProgressR\\bprogress2\\xd2\\x01\\n\" +\n\t\"\\x10LifecycleService\\x12^\\n\" +\n\t\"\\aInstall\\x12'.machine.LifecycleServiceInstallRequest\\x1a(.machine.LifecycleServiceInstallResponse0\\x01\\x12^\\n\" +\n\t\"\\aUpgrade\\x12'.machine.LifecycleServiceUpgradeRequest\\x1a(.machine.LifecycleServiceUpgradeResponse0\\x01BN\\n\" +\n\t\"\\x15dev.talos.api.machineZ5github.com/siderolabs/talos/pkg/machinery/api/machineb\\x06proto3\"\n\nvar (\n\tfile_machine_lifecycle_proto_rawDescOnce sync.Once\n\tfile_machine_lifecycle_proto_rawDescData []byte\n)\n\nfunc file_machine_lifecycle_proto_rawDescGZIP() []byte {\n\tfile_machine_lifecycle_proto_rawDescOnce.Do(func() {\n\t\tfile_machine_lifecycle_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_machine_lifecycle_proto_rawDesc), len(file_machine_lifecycle_proto_rawDesc)))\n\t})\n\treturn file_machine_lifecycle_proto_rawDescData\n}\n\nvar file_machine_lifecycle_proto_msgTypes = make([]protoimpl.MessageInfo, 7)\nvar file_machine_lifecycle_proto_goTypes = []any{\n\t(*InstallArtifactsSource)(nil),          // 0: machine.InstallArtifactsSource\n\t(*InstallDestination)(nil),              // 1: machine.InstallDestination\n\t(*LifecycleServiceInstallRequest)(nil),  // 2: machine.LifecycleServiceInstallRequest\n\t(*LifecycleServiceInstallProgress)(nil), // 3: machine.LifecycleServiceInstallProgress\n\t(*LifecycleServiceInstallResponse)(nil), // 4: machine.LifecycleServiceInstallResponse\n\t(*LifecycleServiceUpgradeRequest)(nil),  // 5: machine.LifecycleServiceUpgradeRequest\n\t(*LifecycleServiceUpgradeResponse)(nil), // 6: machine.LifecycleServiceUpgradeResponse\n\t(*common.ContainerdInstance)(nil),       // 7: common.ContainerdInstance\n}\nvar file_machine_lifecycle_proto_depIdxs = []int32{\n\t7, // 0: machine.LifecycleServiceInstallRequest.containerd:type_name -> common.ContainerdInstance\n\t0, // 1: machine.LifecycleServiceInstallRequest.source:type_name -> machine.InstallArtifactsSource\n\t1, // 2: machine.LifecycleServiceInstallRequest.destination:type_name -> machine.InstallDestination\n\t3, // 3: machine.LifecycleServiceInstallResponse.progress:type_name -> machine.LifecycleServiceInstallProgress\n\t7, // 4: machine.LifecycleServiceUpgradeRequest.containerd:type_name -> common.ContainerdInstance\n\t0, // 5: machine.LifecycleServiceUpgradeRequest.source:type_name -> machine.InstallArtifactsSource\n\t3, // 6: machine.LifecycleServiceUpgradeResponse.progress:type_name -> machine.LifecycleServiceInstallProgress\n\t2, // 7: machine.LifecycleService.Install:input_type -> machine.LifecycleServiceInstallRequest\n\t5, // 8: machine.LifecycleService.Upgrade:input_type -> machine.LifecycleServiceUpgradeRequest\n\t4, // 9: machine.LifecycleService.Install:output_type -> machine.LifecycleServiceInstallResponse\n\t6, // 10: machine.LifecycleService.Upgrade:output_type -> machine.LifecycleServiceUpgradeResponse\n\t9, // [9:11] is the sub-list for method output_type\n\t7, // [7:9] is the sub-list for method input_type\n\t7, // [7:7] is the sub-list for extension type_name\n\t7, // [7:7] is the sub-list for extension extendee\n\t0, // [0:7] is the sub-list for field type_name\n}\n\nfunc init() { file_machine_lifecycle_proto_init() }\nfunc file_machine_lifecycle_proto_init() {\n\tif File_machine_lifecycle_proto != nil {\n\t\treturn\n\t}\n\tfile_machine_lifecycle_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*LifecycleServiceInstallProgress_Message)(nil),\n\t\t(*LifecycleServiceInstallProgress_ExitCode)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_machine_lifecycle_proto_rawDesc), len(file_machine_lifecycle_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   7,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_machine_lifecycle_proto_goTypes,\n\t\tDependencyIndexes: file_machine_lifecycle_proto_depIdxs,\n\t\tMessageInfos:      file_machine_lifecycle_proto_msgTypes,\n\t}.Build()\n\tFile_machine_lifecycle_proto = out.File\n\tfile_machine_lifecycle_proto_goTypes = nil\n\tfile_machine_lifecycle_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/lifecycle_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: machine/lifecycle.proto\n\npackage machine\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tLifecycleService_Install_FullMethodName = \"/machine.LifecycleService/Install\"\n\tLifecycleService_Upgrade_FullMethodName = \"/machine.LifecycleService/Upgrade\"\n)\n\n// LifecycleServiceClient is the client API for LifecycleService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The LifecycleService handles installation and upgrade operations.\ntype LifecycleServiceClient interface {\n\t// Install Talos to disk.\n\t// The RPC should fail if the Talos is already installed on the target disk.\n\tInstall(ctx context.Context, in *LifecycleServiceInstallRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LifecycleServiceInstallResponse], error)\n\t// Upgrade Talos to a new version.\n\t// The RPC should fail if Talos is not already installed on the target disk.\n\tUpgrade(ctx context.Context, in *LifecycleServiceUpgradeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LifecycleServiceUpgradeResponse], error)\n}\n\ntype lifecycleServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewLifecycleServiceClient(cc grpc.ClientConnInterface) LifecycleServiceClient {\n\treturn &lifecycleServiceClient{cc}\n}\n\nfunc (c *lifecycleServiceClient) Install(ctx context.Context, in *LifecycleServiceInstallRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LifecycleServiceInstallResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &LifecycleService_ServiceDesc.Streams[0], LifecycleService_Install_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[LifecycleServiceInstallRequest, LifecycleServiceInstallResponse]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype LifecycleService_InstallClient = grpc.ServerStreamingClient[LifecycleServiceInstallResponse]\n\nfunc (c *lifecycleServiceClient) Upgrade(ctx context.Context, in *LifecycleServiceUpgradeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[LifecycleServiceUpgradeResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &LifecycleService_ServiceDesc.Streams[1], LifecycleService_Upgrade_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[LifecycleServiceUpgradeRequest, LifecycleServiceUpgradeResponse]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype LifecycleService_UpgradeClient = grpc.ServerStreamingClient[LifecycleServiceUpgradeResponse]\n\n// LifecycleServiceServer is the server API for LifecycleService service.\n// All implementations must embed UnimplementedLifecycleServiceServer\n// for forward compatibility.\n//\n// The LifecycleService handles installation and upgrade operations.\ntype LifecycleServiceServer interface {\n\t// Install Talos to disk.\n\t// The RPC should fail if the Talos is already installed on the target disk.\n\tInstall(*LifecycleServiceInstallRequest, grpc.ServerStreamingServer[LifecycleServiceInstallResponse]) error\n\t// Upgrade Talos to a new version.\n\t// The RPC should fail if Talos is not already installed on the target disk.\n\tUpgrade(*LifecycleServiceUpgradeRequest, grpc.ServerStreamingServer[LifecycleServiceUpgradeResponse]) error\n\tmustEmbedUnimplementedLifecycleServiceServer()\n}\n\n// UnimplementedLifecycleServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedLifecycleServiceServer struct{}\n\nfunc (UnimplementedLifecycleServiceServer) Install(*LifecycleServiceInstallRequest, grpc.ServerStreamingServer[LifecycleServiceInstallResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method Install not implemented\")\n}\nfunc (UnimplementedLifecycleServiceServer) Upgrade(*LifecycleServiceUpgradeRequest, grpc.ServerStreamingServer[LifecycleServiceUpgradeResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method Upgrade not implemented\")\n}\nfunc (UnimplementedLifecycleServiceServer) mustEmbedUnimplementedLifecycleServiceServer() {}\nfunc (UnimplementedLifecycleServiceServer) testEmbeddedByValue()                          {}\n\n// UnsafeLifecycleServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to LifecycleServiceServer will\n// result in compilation errors.\ntype UnsafeLifecycleServiceServer interface {\n\tmustEmbedUnimplementedLifecycleServiceServer()\n}\n\nfunc RegisterLifecycleServiceServer(s grpc.ServiceRegistrar, srv LifecycleServiceServer) {\n\t// If the following call panics, it indicates UnimplementedLifecycleServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&LifecycleService_ServiceDesc, srv)\n}\n\nfunc _LifecycleService_Install_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(LifecycleServiceInstallRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(LifecycleServiceServer).Install(m, &grpc.GenericServerStream[LifecycleServiceInstallRequest, LifecycleServiceInstallResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype LifecycleService_InstallServer = grpc.ServerStreamingServer[LifecycleServiceInstallResponse]\n\nfunc _LifecycleService_Upgrade_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(LifecycleServiceUpgradeRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(LifecycleServiceServer).Upgrade(m, &grpc.GenericServerStream[LifecycleServiceUpgradeRequest, LifecycleServiceUpgradeResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype LifecycleService_UpgradeServer = grpc.ServerStreamingServer[LifecycleServiceUpgradeResponse]\n\n// LifecycleService_ServiceDesc is the grpc.ServiceDesc for LifecycleService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar LifecycleService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"machine.LifecycleService\",\n\tHandlerType: (*LifecycleServiceServer)(nil),\n\tMethods:     []grpc.MethodDesc{},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"Install\",\n\t\t\tHandler:       _LifecycleService_Install_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Upgrade\",\n\t\t\tHandler:       _LifecycleService_Upgrade_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"machine/lifecycle.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/lifecycle_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: machine/lifecycle.proto\n\npackage machine\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *InstallArtifactsSource) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *InstallArtifactsSource) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *InstallArtifactsSource) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ImageName) > 0 {\n\t\ti -= len(m.ImageName)\n\t\tcopy(dAtA[i:], m.ImageName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImageName)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *InstallDestination) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *InstallDestination) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *InstallDestination) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Disk) > 0 {\n\t\ti -= len(m.Disk)\n\t\tcopy(dAtA[i:], m.Disk)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Disk)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LifecycleServiceInstallRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LifecycleServiceInstallRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceInstallRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Destination != nil {\n\t\tsize, err := m.Destination.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Source != nil {\n\t\tsize, err := m.Source.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LifecycleServiceInstallProgress) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LifecycleServiceInstallProgress) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceInstallProgress) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif vtmsg, ok := m.Response.(interface {\n\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t}); ok {\n\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LifecycleServiceInstallProgress_Message) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceInstallProgress_Message) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti -= len(m.Message)\n\tcopy(dAtA[i:], m.Message)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\ti--\n\tdAtA[i] = 0xa\n\treturn len(dAtA) - i, nil\n}\nfunc (m *LifecycleServiceInstallProgress_ExitCode) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceInstallProgress_ExitCode) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\ti := len(dAtA)\n\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ExitCode))\n\ti--\n\tdAtA[i] = 0x10\n\treturn len(dAtA) - i, nil\n}\nfunc (m *LifecycleServiceInstallResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LifecycleServiceInstallResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceInstallResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Progress != nil {\n\t\tsize, err := m.Progress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LifecycleServiceUpgradeRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LifecycleServiceUpgradeRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceUpgradeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Source != nil {\n\t\tsize, err := m.Source.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Containerd != nil {\n\t\tif vtmsg, ok := interface{}(m.Containerd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Containerd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LifecycleServiceUpgradeResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LifecycleServiceUpgradeResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LifecycleServiceUpgradeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Progress != nil {\n\t\tsize, err := m.Progress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *InstallArtifactsSource) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ImageName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *InstallDestination) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Disk)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LifecycleServiceInstallRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Source != nil {\n\t\tl = m.Source.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Destination != nil {\n\t\tl = m.Destination.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LifecycleServiceInstallProgress) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif vtmsg, ok := m.Response.(interface{ SizeVT() int }); ok {\n\t\tn += vtmsg.SizeVT()\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LifecycleServiceInstallProgress_Message) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Message)\n\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\treturn n\n}\nfunc (m *LifecycleServiceInstallProgress_ExitCode) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ExitCode))\n\treturn n\n}\nfunc (m *LifecycleServiceInstallResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Progress != nil {\n\t\tl = m.Progress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LifecycleServiceUpgradeRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Containerd != nil {\n\t\tif size, ok := interface{}(m.Containerd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Containerd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Source != nil {\n\t\tl = m.Source.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LifecycleServiceUpgradeResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Progress != nil {\n\t\tl = m.Progress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *InstallArtifactsSource) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: InstallArtifactsSource: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: InstallArtifactsSource: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImageName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImageName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *InstallDestination) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: InstallDestination: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: InstallDestination: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Disk\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Disk = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LifecycleServiceInstallRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Source == nil {\n\t\t\t\tm.Source = &InstallArtifactsSource{}\n\t\t\t}\n\t\t\tif err := m.Source.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Destination\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Destination == nil {\n\t\t\t\tm.Destination = &InstallDestination{}\n\t\t\t}\n\t\t\tif err := m.Destination.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LifecycleServiceInstallProgress) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallProgress: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallProgress: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Response = &LifecycleServiceInstallProgress_Message{Message: string(dAtA[iNdEx:postIndex])}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExitCode\", wireType)\n\t\t\t}\n\t\t\tvar v int32\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Response = &LifecycleServiceInstallProgress_ExitCode{ExitCode: v}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LifecycleServiceInstallResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceInstallResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Progress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Progress == nil {\n\t\t\t\tm.Progress = &LifecycleServiceInstallProgress{}\n\t\t\t}\n\t\t\tif err := m.Progress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LifecycleServiceUpgradeRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceUpgradeRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceUpgradeRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containerd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Containerd == nil {\n\t\t\t\tm.Containerd = &common.ContainerdInstance{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Containerd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Containerd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Source == nil {\n\t\t\t\tm.Source = &InstallArtifactsSource{}\n\t\t\t}\n\t\t\tif err := m.Source.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LifecycleServiceUpgradeResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceUpgradeResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LifecycleServiceUpgradeResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Progress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Progress == nil {\n\t\t\t\tm.Progress = &LifecycleServiceInstallProgress{}\n\t\t\t}\n\t\t\tif err := m.Progress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/machine.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: machine/machine.proto\n\npackage machine\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype ApplyConfigurationRequest_Mode int32\n\nconst (\n\tApplyConfigurationRequest_REBOOT    ApplyConfigurationRequest_Mode = 0\n\tApplyConfigurationRequest_AUTO      ApplyConfigurationRequest_Mode = 1\n\tApplyConfigurationRequest_NO_REBOOT ApplyConfigurationRequest_Mode = 2\n\tApplyConfigurationRequest_STAGED    ApplyConfigurationRequest_Mode = 3\n\tApplyConfigurationRequest_TRY       ApplyConfigurationRequest_Mode = 4\n)\n\n// Enum value maps for ApplyConfigurationRequest_Mode.\nvar (\n\tApplyConfigurationRequest_Mode_name = map[int32]string{\n\t\t0: \"REBOOT\",\n\t\t1: \"AUTO\",\n\t\t2: \"NO_REBOOT\",\n\t\t3: \"STAGED\",\n\t\t4: \"TRY\",\n\t}\n\tApplyConfigurationRequest_Mode_value = map[string]int32{\n\t\t\"REBOOT\":    0,\n\t\t\"AUTO\":      1,\n\t\t\"NO_REBOOT\": 2,\n\t\t\"STAGED\":    3,\n\t\t\"TRY\":       4,\n\t}\n)\n\nfunc (x ApplyConfigurationRequest_Mode) Enum() *ApplyConfigurationRequest_Mode {\n\tp := new(ApplyConfigurationRequest_Mode)\n\t*p = x\n\treturn p\n}\n\nfunc (x ApplyConfigurationRequest_Mode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ApplyConfigurationRequest_Mode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[0].Descriptor()\n}\n\nfunc (ApplyConfigurationRequest_Mode) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[0]\n}\n\nfunc (x ApplyConfigurationRequest_Mode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ApplyConfigurationRequest_Mode.Descriptor instead.\nfunc (ApplyConfigurationRequest_Mode) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype RebootRequest_Mode int32\n\nconst (\n\tRebootRequest_DEFAULT    RebootRequest_Mode = 0\n\tRebootRequest_POWERCYCLE RebootRequest_Mode = 1\n\tRebootRequest_FORCE      RebootRequest_Mode = 2\n)\n\n// Enum value maps for RebootRequest_Mode.\nvar (\n\tRebootRequest_Mode_name = map[int32]string{\n\t\t0: \"DEFAULT\",\n\t\t1: \"POWERCYCLE\",\n\t\t2: \"FORCE\",\n\t}\n\tRebootRequest_Mode_value = map[string]int32{\n\t\t\"DEFAULT\":    0,\n\t\t\"POWERCYCLE\": 1,\n\t\t\"FORCE\":      2,\n\t}\n)\n\nfunc (x RebootRequest_Mode) Enum() *RebootRequest_Mode {\n\tp := new(RebootRequest_Mode)\n\t*p = x\n\treturn p\n}\n\nfunc (x RebootRequest_Mode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RebootRequest_Mode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[1].Descriptor()\n}\n\nfunc (RebootRequest_Mode) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[1]\n}\n\nfunc (x RebootRequest_Mode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RebootRequest_Mode.Descriptor instead.\nfunc (RebootRequest_Mode) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{3, 0}\n}\n\ntype SequenceEvent_Action int32\n\nconst (\n\tSequenceEvent_NOOP  SequenceEvent_Action = 0\n\tSequenceEvent_START SequenceEvent_Action = 1\n\tSequenceEvent_STOP  SequenceEvent_Action = 2\n)\n\n// Enum value maps for SequenceEvent_Action.\nvar (\n\tSequenceEvent_Action_name = map[int32]string{\n\t\t0: \"NOOP\",\n\t\t1: \"START\",\n\t\t2: \"STOP\",\n\t}\n\tSequenceEvent_Action_value = map[string]int32{\n\t\t\"NOOP\":  0,\n\t\t\"START\": 1,\n\t\t\"STOP\":  2,\n\t}\n)\n\nfunc (x SequenceEvent_Action) Enum() *SequenceEvent_Action {\n\tp := new(SequenceEvent_Action)\n\t*p = x\n\treturn p\n}\n\nfunc (x SequenceEvent_Action) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SequenceEvent_Action) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[2].Descriptor()\n}\n\nfunc (SequenceEvent_Action) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[2]\n}\n\nfunc (x SequenceEvent_Action) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SequenceEvent_Action.Descriptor instead.\nfunc (SequenceEvent_Action) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{9, 0}\n}\n\ntype PhaseEvent_Action int32\n\nconst (\n\tPhaseEvent_START PhaseEvent_Action = 0\n\tPhaseEvent_STOP  PhaseEvent_Action = 1\n)\n\n// Enum value maps for PhaseEvent_Action.\nvar (\n\tPhaseEvent_Action_name = map[int32]string{\n\t\t0: \"START\",\n\t\t1: \"STOP\",\n\t}\n\tPhaseEvent_Action_value = map[string]int32{\n\t\t\"START\": 0,\n\t\t\"STOP\":  1,\n\t}\n)\n\nfunc (x PhaseEvent_Action) Enum() *PhaseEvent_Action {\n\tp := new(PhaseEvent_Action)\n\t*p = x\n\treturn p\n}\n\nfunc (x PhaseEvent_Action) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (PhaseEvent_Action) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[3].Descriptor()\n}\n\nfunc (PhaseEvent_Action) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[3]\n}\n\nfunc (x PhaseEvent_Action) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use PhaseEvent_Action.Descriptor instead.\nfunc (PhaseEvent_Action) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{10, 0}\n}\n\ntype TaskEvent_Action int32\n\nconst (\n\tTaskEvent_START TaskEvent_Action = 0\n\tTaskEvent_STOP  TaskEvent_Action = 1\n)\n\n// Enum value maps for TaskEvent_Action.\nvar (\n\tTaskEvent_Action_name = map[int32]string{\n\t\t0: \"START\",\n\t\t1: \"STOP\",\n\t}\n\tTaskEvent_Action_value = map[string]int32{\n\t\t\"START\": 0,\n\t\t\"STOP\":  1,\n\t}\n)\n\nfunc (x TaskEvent_Action) Enum() *TaskEvent_Action {\n\tp := new(TaskEvent_Action)\n\t*p = x\n\treturn p\n}\n\nfunc (x TaskEvent_Action) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (TaskEvent_Action) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[4].Descriptor()\n}\n\nfunc (TaskEvent_Action) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[4]\n}\n\nfunc (x TaskEvent_Action) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use TaskEvent_Action.Descriptor instead.\nfunc (TaskEvent_Action) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{11, 0}\n}\n\ntype ServiceStateEvent_Action int32\n\nconst (\n\tServiceStateEvent_INITIALIZED ServiceStateEvent_Action = 0\n\tServiceStateEvent_PREPARING   ServiceStateEvent_Action = 1\n\tServiceStateEvent_WAITING     ServiceStateEvent_Action = 2\n\tServiceStateEvent_RUNNING     ServiceStateEvent_Action = 3\n\tServiceStateEvent_STOPPING    ServiceStateEvent_Action = 4\n\tServiceStateEvent_FINISHED    ServiceStateEvent_Action = 5\n\tServiceStateEvent_FAILED      ServiceStateEvent_Action = 6\n\tServiceStateEvent_SKIPPED     ServiceStateEvent_Action = 7\n\tServiceStateEvent_STARTING    ServiceStateEvent_Action = 8\n)\n\n// Enum value maps for ServiceStateEvent_Action.\nvar (\n\tServiceStateEvent_Action_name = map[int32]string{\n\t\t0: \"INITIALIZED\",\n\t\t1: \"PREPARING\",\n\t\t2: \"WAITING\",\n\t\t3: \"RUNNING\",\n\t\t4: \"STOPPING\",\n\t\t5: \"FINISHED\",\n\t\t6: \"FAILED\",\n\t\t7: \"SKIPPED\",\n\t\t8: \"STARTING\",\n\t}\n\tServiceStateEvent_Action_value = map[string]int32{\n\t\t\"INITIALIZED\": 0,\n\t\t\"PREPARING\":   1,\n\t\t\"WAITING\":     2,\n\t\t\"RUNNING\":     3,\n\t\t\"STOPPING\":    4,\n\t\t\"FINISHED\":    5,\n\t\t\"FAILED\":      6,\n\t\t\"SKIPPED\":     7,\n\t\t\"STARTING\":    8,\n\t}\n)\n\nfunc (x ServiceStateEvent_Action) Enum() *ServiceStateEvent_Action {\n\tp := new(ServiceStateEvent_Action)\n\t*p = x\n\treturn p\n}\n\nfunc (x ServiceStateEvent_Action) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ServiceStateEvent_Action) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[5].Descriptor()\n}\n\nfunc (ServiceStateEvent_Action) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[5]\n}\n\nfunc (x ServiceStateEvent_Action) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ServiceStateEvent_Action.Descriptor instead.\nfunc (ServiceStateEvent_Action) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{12, 0}\n}\n\ntype MachineStatusEvent_MachineStage int32\n\nconst (\n\tMachineStatusEvent_UNKNOWN       MachineStatusEvent_MachineStage = 0\n\tMachineStatusEvent_BOOTING       MachineStatusEvent_MachineStage = 1\n\tMachineStatusEvent_INSTALLING    MachineStatusEvent_MachineStage = 2\n\tMachineStatusEvent_MAINTENANCE   MachineStatusEvent_MachineStage = 3\n\tMachineStatusEvent_RUNNING       MachineStatusEvent_MachineStage = 4\n\tMachineStatusEvent_REBOOTING     MachineStatusEvent_MachineStage = 5\n\tMachineStatusEvent_SHUTTING_DOWN MachineStatusEvent_MachineStage = 6\n\tMachineStatusEvent_RESETTING     MachineStatusEvent_MachineStage = 7\n\tMachineStatusEvent_UPGRADING     MachineStatusEvent_MachineStage = 8\n)\n\n// Enum value maps for MachineStatusEvent_MachineStage.\nvar (\n\tMachineStatusEvent_MachineStage_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"BOOTING\",\n\t\t2: \"INSTALLING\",\n\t\t3: \"MAINTENANCE\",\n\t\t4: \"RUNNING\",\n\t\t5: \"REBOOTING\",\n\t\t6: \"SHUTTING_DOWN\",\n\t\t7: \"RESETTING\",\n\t\t8: \"UPGRADING\",\n\t}\n\tMachineStatusEvent_MachineStage_value = map[string]int32{\n\t\t\"UNKNOWN\":       0,\n\t\t\"BOOTING\":       1,\n\t\t\"INSTALLING\":    2,\n\t\t\"MAINTENANCE\":   3,\n\t\t\"RUNNING\":       4,\n\t\t\"REBOOTING\":     5,\n\t\t\"SHUTTING_DOWN\": 6,\n\t\t\"RESETTING\":     7,\n\t\t\"UPGRADING\":     8,\n\t}\n)\n\nfunc (x MachineStatusEvent_MachineStage) Enum() *MachineStatusEvent_MachineStage {\n\tp := new(MachineStatusEvent_MachineStage)\n\t*p = x\n\treturn p\n}\n\nfunc (x MachineStatusEvent_MachineStage) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MachineStatusEvent_MachineStage) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[6].Descriptor()\n}\n\nfunc (MachineStatusEvent_MachineStage) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[6]\n}\n\nfunc (x MachineStatusEvent_MachineStage) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use MachineStatusEvent_MachineStage.Descriptor instead.\nfunc (MachineStatusEvent_MachineStage) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{17, 0}\n}\n\ntype ResetRequest_WipeMode int32\n\nconst (\n\tResetRequest_ALL         ResetRequest_WipeMode = 0\n\tResetRequest_SYSTEM_DISK ResetRequest_WipeMode = 1\n\tResetRequest_USER_DISKS  ResetRequest_WipeMode = 2\n)\n\n// Enum value maps for ResetRequest_WipeMode.\nvar (\n\tResetRequest_WipeMode_name = map[int32]string{\n\t\t0: \"ALL\",\n\t\t1: \"SYSTEM_DISK\",\n\t\t2: \"USER_DISKS\",\n\t}\n\tResetRequest_WipeMode_value = map[string]int32{\n\t\t\"ALL\":         0,\n\t\t\"SYSTEM_DISK\": 1,\n\t\t\"USER_DISKS\":  2,\n\t}\n)\n\nfunc (x ResetRequest_WipeMode) Enum() *ResetRequest_WipeMode {\n\tp := new(ResetRequest_WipeMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x ResetRequest_WipeMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ResetRequest_WipeMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[7].Descriptor()\n}\n\nfunc (ResetRequest_WipeMode) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[7]\n}\n\nfunc (x ResetRequest_WipeMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ResetRequest_WipeMode.Descriptor instead.\nfunc (ResetRequest_WipeMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{21, 0}\n}\n\ntype UpgradeRequest_RebootMode int32\n\nconst (\n\tUpgradeRequest_DEFAULT    UpgradeRequest_RebootMode = 0\n\tUpgradeRequest_POWERCYCLE UpgradeRequest_RebootMode = 1\n)\n\n// Enum value maps for UpgradeRequest_RebootMode.\nvar (\n\tUpgradeRequest_RebootMode_name = map[int32]string{\n\t\t0: \"DEFAULT\",\n\t\t1: \"POWERCYCLE\",\n\t}\n\tUpgradeRequest_RebootMode_value = map[string]int32{\n\t\t\"DEFAULT\":    0,\n\t\t\"POWERCYCLE\": 1,\n\t}\n)\n\nfunc (x UpgradeRequest_RebootMode) Enum() *UpgradeRequest_RebootMode {\n\tp := new(UpgradeRequest_RebootMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x UpgradeRequest_RebootMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (UpgradeRequest_RebootMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[8].Descriptor()\n}\n\nfunc (UpgradeRequest_RebootMode) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[8]\n}\n\nfunc (x UpgradeRequest_RebootMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use UpgradeRequest_RebootMode.Descriptor instead.\nfunc (UpgradeRequest_RebootMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{27, 0}\n}\n\n// File type.\ntype ListRequest_Type int32\n\nconst (\n\t// Regular file (not directory, symlink, etc).\n\tListRequest_REGULAR ListRequest_Type = 0\n\t// Directory.\n\tListRequest_DIRECTORY ListRequest_Type = 1\n\t// Symbolic link.\n\tListRequest_SYMLINK ListRequest_Type = 2\n)\n\n// Enum value maps for ListRequest_Type.\nvar (\n\tListRequest_Type_name = map[int32]string{\n\t\t0: \"REGULAR\",\n\t\t1: \"DIRECTORY\",\n\t\t2: \"SYMLINK\",\n\t}\n\tListRequest_Type_value = map[string]int32{\n\t\t\"REGULAR\":   0,\n\t\t\"DIRECTORY\": 1,\n\t\t\"SYMLINK\":   2,\n\t}\n)\n\nfunc (x ListRequest_Type) Enum() *ListRequest_Type {\n\tp := new(ListRequest_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x ListRequest_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ListRequest_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[9].Descriptor()\n}\n\nfunc (ListRequest_Type) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[9]\n}\n\nfunc (x ListRequest_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ListRequest_Type.Descriptor instead.\nfunc (ListRequest_Type) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{46, 0}\n}\n\ntype EtcdMemberAlarm_AlarmType int32\n\nconst (\n\tEtcdMemberAlarm_NONE    EtcdMemberAlarm_AlarmType = 0\n\tEtcdMemberAlarm_NOSPACE EtcdMemberAlarm_AlarmType = 1\n\tEtcdMemberAlarm_CORRUPT EtcdMemberAlarm_AlarmType = 2\n)\n\n// Enum value maps for EtcdMemberAlarm_AlarmType.\nvar (\n\tEtcdMemberAlarm_AlarmType_name = map[int32]string{\n\t\t0: \"NONE\",\n\t\t1: \"NOSPACE\",\n\t\t2: \"CORRUPT\",\n\t}\n\tEtcdMemberAlarm_AlarmType_value = map[string]int32{\n\t\t\"NONE\":    0,\n\t\t\"NOSPACE\": 1,\n\t\t\"CORRUPT\": 2,\n\t}\n)\n\nfunc (x EtcdMemberAlarm_AlarmType) Enum() *EtcdMemberAlarm_AlarmType {\n\tp := new(EtcdMemberAlarm_AlarmType)\n\t*p = x\n\treturn p\n}\n\nfunc (x EtcdMemberAlarm_AlarmType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (EtcdMemberAlarm_AlarmType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[10].Descriptor()\n}\n\nfunc (EtcdMemberAlarm_AlarmType) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[10]\n}\n\nfunc (x EtcdMemberAlarm_AlarmType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use EtcdMemberAlarm_AlarmType.Descriptor instead.\nfunc (EtcdMemberAlarm_AlarmType) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{125, 0}\n}\n\ntype MachineConfig_MachineType int32\n\nconst (\n\tMachineConfig_TYPE_UNKNOWN       MachineConfig_MachineType = 0\n\tMachineConfig_TYPE_INIT          MachineConfig_MachineType = 1\n\tMachineConfig_TYPE_CONTROL_PLANE MachineConfig_MachineType = 2\n\tMachineConfig_TYPE_WORKER        MachineConfig_MachineType = 3\n)\n\n// Enum value maps for MachineConfig_MachineType.\nvar (\n\tMachineConfig_MachineType_name = map[int32]string{\n\t\t0: \"TYPE_UNKNOWN\",\n\t\t1: \"TYPE_INIT\",\n\t\t2: \"TYPE_CONTROL_PLANE\",\n\t\t3: \"TYPE_WORKER\",\n\t}\n\tMachineConfig_MachineType_value = map[string]int32{\n\t\t\"TYPE_UNKNOWN\":       0,\n\t\t\"TYPE_INIT\":          1,\n\t\t\"TYPE_CONTROL_PLANE\": 2,\n\t\t\"TYPE_WORKER\":        3,\n\t}\n)\n\nfunc (x MachineConfig_MachineType) Enum() *MachineConfig_MachineType {\n\tp := new(MachineConfig_MachineType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MachineConfig_MachineType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MachineConfig_MachineType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[11].Descriptor()\n}\n\nfunc (MachineConfig_MachineType) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[11]\n}\n\nfunc (x MachineConfig_MachineType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use MachineConfig_MachineType.Descriptor instead.\nfunc (MachineConfig_MachineType) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{147, 0}\n}\n\ntype NetstatRequest_Filter int32\n\nconst (\n\tNetstatRequest_ALL       NetstatRequest_Filter = 0\n\tNetstatRequest_CONNECTED NetstatRequest_Filter = 1\n\tNetstatRequest_LISTENING NetstatRequest_Filter = 2\n)\n\n// Enum value maps for NetstatRequest_Filter.\nvar (\n\tNetstatRequest_Filter_name = map[int32]string{\n\t\t0: \"ALL\",\n\t\t1: \"CONNECTED\",\n\t\t2: \"LISTENING\",\n\t}\n\tNetstatRequest_Filter_value = map[string]int32{\n\t\t\"ALL\":       0,\n\t\t\"CONNECTED\": 1,\n\t\t\"LISTENING\": 2,\n\t}\n)\n\nfunc (x NetstatRequest_Filter) Enum() *NetstatRequest_Filter {\n\tp := new(NetstatRequest_Filter)\n\t*p = x\n\treturn p\n}\n\nfunc (x NetstatRequest_Filter) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NetstatRequest_Filter) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[12].Descriptor()\n}\n\nfunc (NetstatRequest_Filter) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[12]\n}\n\nfunc (x NetstatRequest_Filter) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NetstatRequest_Filter.Descriptor instead.\nfunc (NetstatRequest_Filter) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{157, 0}\n}\n\ntype ConnectRecord_State int32\n\nconst (\n\tConnectRecord_RESERVED    ConnectRecord_State = 0\n\tConnectRecord_ESTABLISHED ConnectRecord_State = 1\n\tConnectRecord_SYN_SENT    ConnectRecord_State = 2\n\tConnectRecord_SYN_RECV    ConnectRecord_State = 3\n\tConnectRecord_FIN_WAIT1   ConnectRecord_State = 4\n\tConnectRecord_FIN_WAIT2   ConnectRecord_State = 5\n\tConnectRecord_TIME_WAIT   ConnectRecord_State = 6\n\tConnectRecord_CLOSE       ConnectRecord_State = 7\n\tConnectRecord_CLOSEWAIT   ConnectRecord_State = 8\n\tConnectRecord_LASTACK     ConnectRecord_State = 9\n\tConnectRecord_LISTEN      ConnectRecord_State = 10\n\tConnectRecord_CLOSING     ConnectRecord_State = 11\n)\n\n// Enum value maps for ConnectRecord_State.\nvar (\n\tConnectRecord_State_name = map[int32]string{\n\t\t0:  \"RESERVED\",\n\t\t1:  \"ESTABLISHED\",\n\t\t2:  \"SYN_SENT\",\n\t\t3:  \"SYN_RECV\",\n\t\t4:  \"FIN_WAIT1\",\n\t\t5:  \"FIN_WAIT2\",\n\t\t6:  \"TIME_WAIT\",\n\t\t7:  \"CLOSE\",\n\t\t8:  \"CLOSEWAIT\",\n\t\t9:  \"LASTACK\",\n\t\t10: \"LISTEN\",\n\t\t11: \"CLOSING\",\n\t}\n\tConnectRecord_State_value = map[string]int32{\n\t\t\"RESERVED\":    0,\n\t\t\"ESTABLISHED\": 1,\n\t\t\"SYN_SENT\":    2,\n\t\t\"SYN_RECV\":    3,\n\t\t\"FIN_WAIT1\":   4,\n\t\t\"FIN_WAIT2\":   5,\n\t\t\"TIME_WAIT\":   6,\n\t\t\"CLOSE\":       7,\n\t\t\"CLOSEWAIT\":   8,\n\t\t\"LASTACK\":     9,\n\t\t\"LISTEN\":      10,\n\t\t\"CLOSING\":     11,\n\t}\n)\n\nfunc (x ConnectRecord_State) Enum() *ConnectRecord_State {\n\tp := new(ConnectRecord_State)\n\t*p = x\n\treturn p\n}\n\nfunc (x ConnectRecord_State) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ConnectRecord_State) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[13].Descriptor()\n}\n\nfunc (ConnectRecord_State) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[13]\n}\n\nfunc (x ConnectRecord_State) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ConnectRecord_State.Descriptor instead.\nfunc (ConnectRecord_State) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{158, 0}\n}\n\ntype ConnectRecord_TimerActive int32\n\nconst (\n\tConnectRecord_OFF       ConnectRecord_TimerActive = 0\n\tConnectRecord_ON        ConnectRecord_TimerActive = 1\n\tConnectRecord_KEEPALIVE ConnectRecord_TimerActive = 2\n\tConnectRecord_TIMEWAIT  ConnectRecord_TimerActive = 3\n\tConnectRecord_PROBE     ConnectRecord_TimerActive = 4\n)\n\n// Enum value maps for ConnectRecord_TimerActive.\nvar (\n\tConnectRecord_TimerActive_name = map[int32]string{\n\t\t0: \"OFF\",\n\t\t1: \"ON\",\n\t\t2: \"KEEPALIVE\",\n\t\t3: \"TIMEWAIT\",\n\t\t4: \"PROBE\",\n\t}\n\tConnectRecord_TimerActive_value = map[string]int32{\n\t\t\"OFF\":       0,\n\t\t\"ON\":        1,\n\t\t\"KEEPALIVE\": 2,\n\t\t\"TIMEWAIT\":  3,\n\t\t\"PROBE\":     4,\n\t}\n)\n\nfunc (x ConnectRecord_TimerActive) Enum() *ConnectRecord_TimerActive {\n\tp := new(ConnectRecord_TimerActive)\n\t*p = x\n\treturn p\n}\n\nfunc (x ConnectRecord_TimerActive) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ConnectRecord_TimerActive) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_machine_machine_proto_enumTypes[14].Descriptor()\n}\n\nfunc (ConnectRecord_TimerActive) Type() protoreflect.EnumType {\n\treturn &file_machine_machine_proto_enumTypes[14]\n}\n\nfunc (x ConnectRecord_TimerActive) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use ConnectRecord_TimerActive.Descriptor instead.\nfunc (ConnectRecord_TimerActive) EnumDescriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{158, 1}\n}\n\n// rpc applyConfiguration\n// ApplyConfiguration describes a request to assert a new configuration upon a\n// node.\ntype ApplyConfigurationRequest struct {\n\tstate          protoimpl.MessageState         `protogen:\"open.v1\"`\n\tData           []byte                         `protobuf:\"bytes,1,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tMode           ApplyConfigurationRequest_Mode `protobuf:\"varint,4,opt,name=mode,proto3,enum=machine.ApplyConfigurationRequest_Mode\" json:\"mode,omitempty\"`\n\tDryRun         bool                           `protobuf:\"varint,5,opt,name=dry_run,json=dryRun,proto3\" json:\"dry_run,omitempty\"`\n\tTryModeTimeout *durationpb.Duration           `protobuf:\"bytes,6,opt,name=try_mode_timeout,json=tryModeTimeout,proto3\" json:\"try_mode_timeout,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ApplyConfigurationRequest) Reset() {\n\t*x = ApplyConfigurationRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ApplyConfigurationRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ApplyConfigurationRequest) ProtoMessage() {}\n\nfunc (x *ApplyConfigurationRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ApplyConfigurationRequest.ProtoReflect.Descriptor instead.\nfunc (*ApplyConfigurationRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ApplyConfigurationRequest) GetData() []byte {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\nfunc (x *ApplyConfigurationRequest) GetMode() ApplyConfigurationRequest_Mode {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn ApplyConfigurationRequest_REBOOT\n}\n\nfunc (x *ApplyConfigurationRequest) GetDryRun() bool {\n\tif x != nil {\n\t\treturn x.DryRun\n\t}\n\treturn false\n}\n\nfunc (x *ApplyConfigurationRequest) GetTryModeTimeout() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.TryModeTimeout\n\t}\n\treturn nil\n}\n\n// ApplyConfigurationResponse describes the response to a configuration request.\ntype ApplyConfiguration struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\t// Configuration validation warnings.\n\tWarnings []string `protobuf:\"bytes,2,rep,name=warnings,proto3\" json:\"warnings,omitempty\"`\n\t// States which mode was actually chosen.\n\tMode ApplyConfigurationRequest_Mode `protobuf:\"varint,3,opt,name=mode,proto3,enum=machine.ApplyConfigurationRequest_Mode\" json:\"mode,omitempty\"`\n\t// Human-readable message explaining the result of the apply configuration call.\n\tModeDetails   string `protobuf:\"bytes,4,opt,name=mode_details,json=modeDetails,proto3\" json:\"mode_details,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ApplyConfiguration) Reset() {\n\t*x = ApplyConfiguration{}\n\tmi := &file_machine_machine_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ApplyConfiguration) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ApplyConfiguration) ProtoMessage() {}\n\nfunc (x *ApplyConfiguration) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ApplyConfiguration.ProtoReflect.Descriptor instead.\nfunc (*ApplyConfiguration) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ApplyConfiguration) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ApplyConfiguration) GetWarnings() []string {\n\tif x != nil {\n\t\treturn x.Warnings\n\t}\n\treturn nil\n}\n\nfunc (x *ApplyConfiguration) GetMode() ApplyConfigurationRequest_Mode {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn ApplyConfigurationRequest_REBOOT\n}\n\nfunc (x *ApplyConfiguration) GetModeDetails() string {\n\tif x != nil {\n\t\treturn x.ModeDetails\n\t}\n\treturn \"\"\n}\n\ntype ApplyConfigurationResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ApplyConfiguration  `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ApplyConfigurationResponse) Reset() {\n\t*x = ApplyConfigurationResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ApplyConfigurationResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ApplyConfigurationResponse) ProtoMessage() {}\n\nfunc (x *ApplyConfigurationResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ApplyConfigurationResponse.ProtoReflect.Descriptor instead.\nfunc (*ApplyConfigurationResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ApplyConfigurationResponse) GetMessages() []*ApplyConfiguration {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc reboot\ntype RebootRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMode          RebootRequest_Mode     `protobuf:\"varint,1,opt,name=mode,proto3,enum=machine.RebootRequest_Mode\" json:\"mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RebootRequest) Reset() {\n\t*x = RebootRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RebootRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RebootRequest) ProtoMessage() {}\n\nfunc (x *RebootRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RebootRequest.ProtoReflect.Descriptor instead.\nfunc (*RebootRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RebootRequest) GetMode() RebootRequest_Mode {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn RebootRequest_DEFAULT\n}\n\n// The reboot message containing the reboot status.\ntype Reboot struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tActorId       string                 `protobuf:\"bytes,2,opt,name=actor_id,json=actorId,proto3\" json:\"actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Reboot) Reset() {\n\t*x = Reboot{}\n\tmi := &file_machine_machine_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Reboot) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Reboot) ProtoMessage() {}\n\nfunc (x *Reboot) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Reboot.ProtoReflect.Descriptor instead.\nfunc (*Reboot) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *Reboot) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Reboot) GetActorId() string {\n\tif x != nil {\n\t\treturn x.ActorId\n\t}\n\treturn \"\"\n}\n\ntype RebootResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Reboot              `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RebootResponse) Reset() {\n\t*x = RebootResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RebootResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RebootResponse) ProtoMessage() {}\n\nfunc (x *RebootResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RebootResponse.ProtoReflect.Descriptor instead.\nfunc (*RebootResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *RebootResponse) GetMessages() []*Reboot {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc Bootstrap\ntype BootstrapRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Enable etcd recovery from the snapshot.\n\t// Snapshot should be uploaded before this call via EtcdRecover RPC.\n\tRecoverEtcd bool `protobuf:\"varint,1,opt,name=recover_etcd,json=recoverEtcd,proto3\" json:\"recover_etcd,omitempty\"`\n\t// Skip hash check on the snapshot (etcd).\n\t// Enable this when recovering from data directory copy to skip integrity check.\n\tRecoverSkipHashCheck bool `protobuf:\"varint,2,opt,name=recover_skip_hash_check,json=recoverSkipHashCheck,proto3\" json:\"recover_skip_hash_check,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *BootstrapRequest) Reset() {\n\t*x = BootstrapRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BootstrapRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BootstrapRequest) ProtoMessage() {}\n\nfunc (x *BootstrapRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BootstrapRequest.ProtoReflect.Descriptor instead.\nfunc (*BootstrapRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *BootstrapRequest) GetRecoverEtcd() bool {\n\tif x != nil {\n\t\treturn x.RecoverEtcd\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapRequest) GetRecoverSkipHashCheck() bool {\n\tif x != nil {\n\t\treturn x.RecoverSkipHashCheck\n\t}\n\treturn false\n}\n\n// The bootstrap message containing the bootstrap status.\ntype Bootstrap struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Bootstrap) Reset() {\n\t*x = Bootstrap{}\n\tmi := &file_machine_machine_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Bootstrap) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Bootstrap) ProtoMessage() {}\n\nfunc (x *Bootstrap) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Bootstrap.ProtoReflect.Descriptor instead.\nfunc (*Bootstrap) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *Bootstrap) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype BootstrapResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Bootstrap           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BootstrapResponse) Reset() {\n\t*x = BootstrapResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BootstrapResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BootstrapResponse) ProtoMessage() {}\n\nfunc (x *BootstrapResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BootstrapResponse.ProtoReflect.Descriptor instead.\nfunc (*BootstrapResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *BootstrapResponse) GetMessages() []*Bootstrap {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc events\ntype SequenceEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSequence      string                 `protobuf:\"bytes,1,opt,name=sequence,proto3\" json:\"sequence,omitempty\"`\n\tAction        SequenceEvent_Action   `protobuf:\"varint,2,opt,name=action,proto3,enum=machine.SequenceEvent_Action\" json:\"action,omitempty\"`\n\tError         *common.Error          `protobuf:\"bytes,3,opt,name=error,proto3\" json:\"error,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SequenceEvent) Reset() {\n\t*x = SequenceEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SequenceEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SequenceEvent) ProtoMessage() {}\n\nfunc (x *SequenceEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SequenceEvent.ProtoReflect.Descriptor instead.\nfunc (*SequenceEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *SequenceEvent) GetSequence() string {\n\tif x != nil {\n\t\treturn x.Sequence\n\t}\n\treturn \"\"\n}\n\nfunc (x *SequenceEvent) GetAction() SequenceEvent_Action {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn SequenceEvent_NOOP\n}\n\nfunc (x *SequenceEvent) GetError() *common.Error {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn nil\n}\n\ntype PhaseEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPhase         string                 `protobuf:\"bytes,1,opt,name=phase,proto3\" json:\"phase,omitempty\"`\n\tAction        PhaseEvent_Action      `protobuf:\"varint,2,opt,name=action,proto3,enum=machine.PhaseEvent_Action\" json:\"action,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PhaseEvent) Reset() {\n\t*x = PhaseEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PhaseEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PhaseEvent) ProtoMessage() {}\n\nfunc (x *PhaseEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PhaseEvent.ProtoReflect.Descriptor instead.\nfunc (*PhaseEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *PhaseEvent) GetPhase() string {\n\tif x != nil {\n\t\treturn x.Phase\n\t}\n\treturn \"\"\n}\n\nfunc (x *PhaseEvent) GetAction() PhaseEvent_Action {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn PhaseEvent_START\n}\n\ntype TaskEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTask          string                 `protobuf:\"bytes,1,opt,name=task,proto3\" json:\"task,omitempty\"`\n\tAction        TaskEvent_Action       `protobuf:\"varint,2,opt,name=action,proto3,enum=machine.TaskEvent_Action\" json:\"action,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TaskEvent) Reset() {\n\t*x = TaskEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TaskEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TaskEvent) ProtoMessage() {}\n\nfunc (x *TaskEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TaskEvent.ProtoReflect.Descriptor instead.\nfunc (*TaskEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *TaskEvent) GetTask() string {\n\tif x != nil {\n\t\treturn x.Task\n\t}\n\treturn \"\"\n}\n\nfunc (x *TaskEvent) GetAction() TaskEvent_Action {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn TaskEvent_START\n}\n\ntype ServiceStateEvent struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tService       string                   `protobuf:\"bytes,1,opt,name=service,proto3\" json:\"service,omitempty\"`\n\tAction        ServiceStateEvent_Action `protobuf:\"varint,2,opt,name=action,proto3,enum=machine.ServiceStateEvent_Action\" json:\"action,omitempty\"`\n\tMessage       string                   `protobuf:\"bytes,3,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tHealth        *ServiceHealth           `protobuf:\"bytes,4,opt,name=health,proto3\" json:\"health,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStateEvent) Reset() {\n\t*x = ServiceStateEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStateEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStateEvent) ProtoMessage() {}\n\nfunc (x *ServiceStateEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStateEvent.ProtoReflect.Descriptor instead.\nfunc (*ServiceStateEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *ServiceStateEvent) GetService() string {\n\tif x != nil {\n\t\treturn x.Service\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceStateEvent) GetAction() ServiceStateEvent_Action {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn ServiceStateEvent_INITIALIZED\n}\n\nfunc (x *ServiceStateEvent) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceStateEvent) GetHealth() *ServiceHealth {\n\tif x != nil {\n\t\treturn x.Health\n\t}\n\treturn nil\n}\n\ntype RestartEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCmd           int64                  `protobuf:\"varint,1,opt,name=cmd,proto3\" json:\"cmd,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RestartEvent) Reset() {\n\t*x = RestartEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RestartEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestartEvent) ProtoMessage() {}\n\nfunc (x *RestartEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestartEvent.ProtoReflect.Descriptor instead.\nfunc (*RestartEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *RestartEvent) GetCmd() int64 {\n\tif x != nil {\n\t\treturn x.Cmd\n\t}\n\treturn 0\n}\n\n// ConfigLoadErrorEvent is reported when the config loading has failed.\ntype ConfigLoadErrorEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tError         string                 `protobuf:\"bytes,1,opt,name=error,proto3\" json:\"error,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConfigLoadErrorEvent) Reset() {\n\t*x = ConfigLoadErrorEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigLoadErrorEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigLoadErrorEvent) ProtoMessage() {}\n\nfunc (x *ConfigLoadErrorEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigLoadErrorEvent.ProtoReflect.Descriptor instead.\nfunc (*ConfigLoadErrorEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *ConfigLoadErrorEvent) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\n// ConfigValidationErrorEvent is reported when config validation has failed.\ntype ConfigValidationErrorEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tError         string                 `protobuf:\"bytes,1,opt,name=error,proto3\" json:\"error,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConfigValidationErrorEvent) Reset() {\n\t*x = ConfigValidationErrorEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[15]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigValidationErrorEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigValidationErrorEvent) ProtoMessage() {}\n\nfunc (x *ConfigValidationErrorEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[15]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigValidationErrorEvent.ProtoReflect.Descriptor instead.\nfunc (*ConfigValidationErrorEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *ConfigValidationErrorEvent) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\n// AddressEvent reports node endpoints aggregated from k8s.Endpoints and network.Hostname.\ntype AddressEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHostname      string                 `protobuf:\"bytes,1,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tAddresses     []string               `protobuf:\"bytes,2,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AddressEvent) Reset() {\n\t*x = AddressEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[16]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AddressEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddressEvent) ProtoMessage() {}\n\nfunc (x *AddressEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[16]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddressEvent.ProtoReflect.Descriptor instead.\nfunc (*AddressEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *AddressEvent) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddressEvent) GetAddresses() []string {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\n// MachineStatusEvent reports changes to the MachineStatus resource.\ntype MachineStatusEvent struct {\n\tstate         protoimpl.MessageState            `protogen:\"open.v1\"`\n\tStage         MachineStatusEvent_MachineStage   `protobuf:\"varint,1,opt,name=stage,proto3,enum=machine.MachineStatusEvent_MachineStage\" json:\"stage,omitempty\"`\n\tStatus        *MachineStatusEvent_MachineStatus `protobuf:\"bytes,2,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MachineStatusEvent) Reset() {\n\t*x = MachineStatusEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[17]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineStatusEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineStatusEvent) ProtoMessage() {}\n\nfunc (x *MachineStatusEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[17]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineStatusEvent.ProtoReflect.Descriptor instead.\nfunc (*MachineStatusEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *MachineStatusEvent) GetStage() MachineStatusEvent_MachineStage {\n\tif x != nil {\n\t\treturn x.Stage\n\t}\n\treturn MachineStatusEvent_UNKNOWN\n}\n\nfunc (x *MachineStatusEvent) GetStatus() *MachineStatusEvent_MachineStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\ntype EventsRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTailEvents    int32                  `protobuf:\"varint,1,opt,name=tail_events,json=tailEvents,proto3\" json:\"tail_events,omitempty\"`\n\tTailId        string                 `protobuf:\"bytes,2,opt,name=tail_id,json=tailId,proto3\" json:\"tail_id,omitempty\"`\n\tTailSeconds   int32                  `protobuf:\"varint,3,opt,name=tail_seconds,json=tailSeconds,proto3\" json:\"tail_seconds,omitempty\"`\n\tWithActorId   string                 `protobuf:\"bytes,4,opt,name=with_actor_id,json=withActorId,proto3\" json:\"with_actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EventsRequest) Reset() {\n\t*x = EventsRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[18]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EventsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EventsRequest) ProtoMessage() {}\n\nfunc (x *EventsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[18]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EventsRequest.ProtoReflect.Descriptor instead.\nfunc (*EventsRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *EventsRequest) GetTailEvents() int32 {\n\tif x != nil {\n\t\treturn x.TailEvents\n\t}\n\treturn 0\n}\n\nfunc (x *EventsRequest) GetTailId() string {\n\tif x != nil {\n\t\treturn x.TailId\n\t}\n\treturn \"\"\n}\n\nfunc (x *EventsRequest) GetTailSeconds() int32 {\n\tif x != nil {\n\t\treturn x.TailSeconds\n\t}\n\treturn 0\n}\n\nfunc (x *EventsRequest) GetWithActorId() string {\n\tif x != nil {\n\t\treturn x.WithActorId\n\t}\n\treturn \"\"\n}\n\ntype Event struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tData          *anypb.Any             `protobuf:\"bytes,2,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tId            string                 `protobuf:\"bytes,3,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tActorId       string                 `protobuf:\"bytes,4,opt,name=actor_id,json=actorId,proto3\" json:\"actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Event) Reset() {\n\t*x = Event{}\n\tmi := &file_machine_machine_proto_msgTypes[19]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Event) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Event) ProtoMessage() {}\n\nfunc (x *Event) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[19]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Event.ProtoReflect.Descriptor instead.\nfunc (*Event) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *Event) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Event) GetData() *anypb.Any {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\nfunc (x *Event) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *Event) GetActorId() string {\n\tif x != nil {\n\t\treturn x.ActorId\n\t}\n\treturn \"\"\n}\n\n// rpc reset\ntype ResetPartitionSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tLabel         string                 `protobuf:\"bytes,1,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tWipe          bool                   `protobuf:\"varint,2,opt,name=wipe,proto3\" json:\"wipe,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ResetPartitionSpec) Reset() {\n\t*x = ResetPartitionSpec{}\n\tmi := &file_machine_machine_proto_msgTypes[20]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResetPartitionSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResetPartitionSpec) ProtoMessage() {}\n\nfunc (x *ResetPartitionSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[20]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResetPartitionSpec.ProtoReflect.Descriptor instead.\nfunc (*ResetPartitionSpec) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *ResetPartitionSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\nfunc (x *ResetPartitionSpec) GetWipe() bool {\n\tif x != nil {\n\t\treturn x.Wipe\n\t}\n\treturn false\n}\n\ntype ResetRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Graceful indicates whether node should leave etcd before the upgrade, it also\n\t// enforces etcd checks before leaving.\n\tGraceful bool `protobuf:\"varint,1,opt,name=graceful,proto3\" json:\"graceful,omitempty\"`\n\t// Reboot indicates whether node should reboot or halt after resetting.\n\tReboot bool `protobuf:\"varint,2,opt,name=reboot,proto3\" json:\"reboot,omitempty\"`\n\t// System_partitions_to_wipe lists specific system disk partitions to be reset (wiped).\n\t// If system_partitions_to_wipe is empty, all the partitions are erased.\n\tSystemPartitionsToWipe []*ResetPartitionSpec `protobuf:\"bytes,3,rep,name=system_partitions_to_wipe,json=systemPartitionsToWipe,proto3\" json:\"system_partitions_to_wipe,omitempty\"`\n\t// UserDisksToWipe lists specific connected block devices to be reset (wiped).\n\tUserDisksToWipe []string `protobuf:\"bytes,4,rep,name=user_disks_to_wipe,json=userDisksToWipe,proto3\" json:\"user_disks_to_wipe,omitempty\"`\n\t// WipeMode defines which devices should be wiped.\n\tMode          ResetRequest_WipeMode `protobuf:\"varint,5,opt,name=mode,proto3,enum=machine.ResetRequest_WipeMode\" json:\"mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ResetRequest) Reset() {\n\t*x = ResetRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[21]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResetRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResetRequest) ProtoMessage() {}\n\nfunc (x *ResetRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[21]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResetRequest.ProtoReflect.Descriptor instead.\nfunc (*ResetRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *ResetRequest) GetGraceful() bool {\n\tif x != nil {\n\t\treturn x.Graceful\n\t}\n\treturn false\n}\n\nfunc (x *ResetRequest) GetReboot() bool {\n\tif x != nil {\n\t\treturn x.Reboot\n\t}\n\treturn false\n}\n\nfunc (x *ResetRequest) GetSystemPartitionsToWipe() []*ResetPartitionSpec {\n\tif x != nil {\n\t\treturn x.SystemPartitionsToWipe\n\t}\n\treturn nil\n}\n\nfunc (x *ResetRequest) GetUserDisksToWipe() []string {\n\tif x != nil {\n\t\treturn x.UserDisksToWipe\n\t}\n\treturn nil\n}\n\nfunc (x *ResetRequest) GetMode() ResetRequest_WipeMode {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn ResetRequest_ALL\n}\n\n// The reset message containing the restart status.\ntype Reset struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tActorId       string                 `protobuf:\"bytes,2,opt,name=actor_id,json=actorId,proto3\" json:\"actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Reset) Reset() {\n\t*x = Reset{}\n\tmi := &file_machine_machine_proto_msgTypes[22]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Reset) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Reset) ProtoMessage() {}\n\nfunc (x *Reset) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[22]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Reset.ProtoReflect.Descriptor instead.\nfunc (*Reset) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *Reset) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Reset) GetActorId() string {\n\tif x != nil {\n\t\treturn x.ActorId\n\t}\n\treturn \"\"\n}\n\ntype ResetResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Reset               `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ResetResponse) Reset() {\n\t*x = ResetResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[23]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResetResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResetResponse) ProtoMessage() {}\n\nfunc (x *ResetResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[23]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResetResponse.ProtoReflect.Descriptor instead.\nfunc (*ResetResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *ResetResponse) GetMessages() []*Reset {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc shutdown\n// The messages message containing the shutdown status.\ntype Shutdown struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tActorId       string                 `protobuf:\"bytes,2,opt,name=actor_id,json=actorId,proto3\" json:\"actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Shutdown) Reset() {\n\t*x = Shutdown{}\n\tmi := &file_machine_machine_proto_msgTypes[24]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Shutdown) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Shutdown) ProtoMessage() {}\n\nfunc (x *Shutdown) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[24]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Shutdown.ProtoReflect.Descriptor instead.\nfunc (*Shutdown) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *Shutdown) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Shutdown) GetActorId() string {\n\tif x != nil {\n\t\treturn x.ActorId\n\t}\n\treturn \"\"\n}\n\ntype ShutdownRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Force indicates whether node should shutdown without first cordening and draining\n\tForce         bool `protobuf:\"varint,1,opt,name=force,proto3\" json:\"force,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ShutdownRequest) Reset() {\n\t*x = ShutdownRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[25]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ShutdownRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShutdownRequest) ProtoMessage() {}\n\nfunc (x *ShutdownRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[25]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead.\nfunc (*ShutdownRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *ShutdownRequest) GetForce() bool {\n\tif x != nil {\n\t\treturn x.Force\n\t}\n\treturn false\n}\n\ntype ShutdownResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Shutdown            `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ShutdownResponse) Reset() {\n\t*x = ShutdownResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[26]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ShutdownResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ShutdownResponse) ProtoMessage() {}\n\nfunc (x *ShutdownResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[26]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ShutdownResponse.ProtoReflect.Descriptor instead.\nfunc (*ShutdownResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{26}\n}\n\nfunc (x *ShutdownResponse) GetMessages() []*Shutdown {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc upgrade\ntype UpgradeRequest struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tImage         string                    `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tPreserve      bool                      `protobuf:\"varint,2,opt,name=preserve,proto3\" json:\"preserve,omitempty\"`\n\tStage         bool                      `protobuf:\"varint,3,opt,name=stage,proto3\" json:\"stage,omitempty\"`\n\tForce         bool                      `protobuf:\"varint,4,opt,name=force,proto3\" json:\"force,omitempty\"`\n\tRebootMode    UpgradeRequest_RebootMode `protobuf:\"varint,5,opt,name=reboot_mode,json=rebootMode,proto3,enum=machine.UpgradeRequest_RebootMode\" json:\"reboot_mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *UpgradeRequest) Reset() {\n\t*x = UpgradeRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[27]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *UpgradeRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UpgradeRequest) ProtoMessage() {}\n\nfunc (x *UpgradeRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[27]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UpgradeRequest.ProtoReflect.Descriptor instead.\nfunc (*UpgradeRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{27}\n}\n\nfunc (x *UpgradeRequest) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *UpgradeRequest) GetPreserve() bool {\n\tif x != nil {\n\t\treturn x.Preserve\n\t}\n\treturn false\n}\n\nfunc (x *UpgradeRequest) GetStage() bool {\n\tif x != nil {\n\t\treturn x.Stage\n\t}\n\treturn false\n}\n\nfunc (x *UpgradeRequest) GetForce() bool {\n\tif x != nil {\n\t\treturn x.Force\n\t}\n\treturn false\n}\n\nfunc (x *UpgradeRequest) GetRebootMode() UpgradeRequest_RebootMode {\n\tif x != nil {\n\t\treturn x.RebootMode\n\t}\n\treturn UpgradeRequest_DEFAULT\n}\n\ntype Upgrade struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tAck           string                 `protobuf:\"bytes,2,opt,name=ack,proto3\" json:\"ack,omitempty\"`\n\tActorId       string                 `protobuf:\"bytes,3,opt,name=actor_id,json=actorId,proto3\" json:\"actor_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Upgrade) Reset() {\n\t*x = Upgrade{}\n\tmi := &file_machine_machine_proto_msgTypes[28]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Upgrade) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Upgrade) ProtoMessage() {}\n\nfunc (x *Upgrade) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[28]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Upgrade.ProtoReflect.Descriptor instead.\nfunc (*Upgrade) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{28}\n}\n\nfunc (x *Upgrade) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Upgrade) GetAck() string {\n\tif x != nil {\n\t\treturn x.Ack\n\t}\n\treturn \"\"\n}\n\nfunc (x *Upgrade) GetActorId() string {\n\tif x != nil {\n\t\treturn x.ActorId\n\t}\n\treturn \"\"\n}\n\ntype UpgradeResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Upgrade             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *UpgradeResponse) Reset() {\n\t*x = UpgradeResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[29]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *UpgradeResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UpgradeResponse) ProtoMessage() {}\n\nfunc (x *UpgradeResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[29]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UpgradeResponse.ProtoReflect.Descriptor instead.\nfunc (*UpgradeResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{29}\n}\n\nfunc (x *UpgradeResponse) GetMessages() []*Upgrade {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc servicelist\ntype ServiceList struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tServices      []*ServiceInfo         `protobuf:\"bytes,2,rep,name=services,proto3\" json:\"services,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceList) Reset() {\n\t*x = ServiceList{}\n\tmi := &file_machine_machine_proto_msgTypes[30]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceList) ProtoMessage() {}\n\nfunc (x *ServiceList) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[30]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceList.ProtoReflect.Descriptor instead.\nfunc (*ServiceList) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{30}\n}\n\nfunc (x *ServiceList) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ServiceList) GetServices() []*ServiceInfo {\n\tif x != nil {\n\t\treturn x.Services\n\t}\n\treturn nil\n}\n\ntype ServiceListResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ServiceList         `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceListResponse) Reset() {\n\t*x = ServiceListResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[31]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceListResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceListResponse) ProtoMessage() {}\n\nfunc (x *ServiceListResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[31]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceListResponse.ProtoReflect.Descriptor instead.\nfunc (*ServiceListResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{31}\n}\n\nfunc (x *ServiceListResponse) GetMessages() []*ServiceList {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ServiceInfo struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tId            string                 `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tState         string                 `protobuf:\"bytes,2,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tEvents        *ServiceEvents         `protobuf:\"bytes,3,opt,name=events,proto3\" json:\"events,omitempty\"`\n\tHealth        *ServiceHealth         `protobuf:\"bytes,4,opt,name=health,proto3\" json:\"health,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceInfo) Reset() {\n\t*x = ServiceInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[32]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceInfo) ProtoMessage() {}\n\nfunc (x *ServiceInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[32]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceInfo.ProtoReflect.Descriptor instead.\nfunc (*ServiceInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{32}\n}\n\nfunc (x *ServiceInfo) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceInfo) GetState() string {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceInfo) GetEvents() *ServiceEvents {\n\tif x != nil {\n\t\treturn x.Events\n\t}\n\treturn nil\n}\n\nfunc (x *ServiceInfo) GetHealth() *ServiceHealth {\n\tif x != nil {\n\t\treturn x.Health\n\t}\n\treturn nil\n}\n\ntype ServiceEvents struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEvents        []*ServiceEvent        `protobuf:\"bytes,1,rep,name=events,proto3\" json:\"events,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceEvents) Reset() {\n\t*x = ServiceEvents{}\n\tmi := &file_machine_machine_proto_msgTypes[33]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceEvents) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceEvents) ProtoMessage() {}\n\nfunc (x *ServiceEvents) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[33]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceEvents.ProtoReflect.Descriptor instead.\nfunc (*ServiceEvents) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{33}\n}\n\nfunc (x *ServiceEvents) GetEvents() []*ServiceEvent {\n\tif x != nil {\n\t\treturn x.Events\n\t}\n\treturn nil\n}\n\ntype ServiceEvent struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMsg           string                 `protobuf:\"bytes,1,opt,name=msg,proto3\" json:\"msg,omitempty\"`\n\tState         string                 `protobuf:\"bytes,2,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tTs            *timestamppb.Timestamp `protobuf:\"bytes,3,opt,name=ts,proto3\" json:\"ts,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceEvent) Reset() {\n\t*x = ServiceEvent{}\n\tmi := &file_machine_machine_proto_msgTypes[34]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceEvent) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceEvent) ProtoMessage() {}\n\nfunc (x *ServiceEvent) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[34]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceEvent.ProtoReflect.Descriptor instead.\nfunc (*ServiceEvent) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{34}\n}\n\nfunc (x *ServiceEvent) GetMsg() string {\n\tif x != nil {\n\t\treturn x.Msg\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceEvent) GetState() string {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceEvent) GetTs() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Ts\n\t}\n\treturn nil\n}\n\ntype ServiceHealth struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tUnknown       bool                   `protobuf:\"varint,1,opt,name=unknown,proto3\" json:\"unknown,omitempty\"`\n\tHealthy       bool                   `protobuf:\"varint,2,opt,name=healthy,proto3\" json:\"healthy,omitempty\"`\n\tLastMessage   string                 `protobuf:\"bytes,3,opt,name=last_message,json=lastMessage,proto3\" json:\"last_message,omitempty\"`\n\tLastChange    *timestamppb.Timestamp `protobuf:\"bytes,4,opt,name=last_change,json=lastChange,proto3\" json:\"last_change,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceHealth) Reset() {\n\t*x = ServiceHealth{}\n\tmi := &file_machine_machine_proto_msgTypes[35]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceHealth) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceHealth) ProtoMessage() {}\n\nfunc (x *ServiceHealth) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[35]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceHealth.ProtoReflect.Descriptor instead.\nfunc (*ServiceHealth) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{35}\n}\n\nfunc (x *ServiceHealth) GetUnknown() bool {\n\tif x != nil {\n\t\treturn x.Unknown\n\t}\n\treturn false\n}\n\nfunc (x *ServiceHealth) GetHealthy() bool {\n\tif x != nil {\n\t\treturn x.Healthy\n\t}\n\treturn false\n}\n\nfunc (x *ServiceHealth) GetLastMessage() string {\n\tif x != nil {\n\t\treturn x.LastMessage\n\t}\n\treturn \"\"\n}\n\nfunc (x *ServiceHealth) GetLastChange() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.LastChange\n\t}\n\treturn nil\n}\n\n// rpc servicestart\ntype ServiceStartRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tId            string                 `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStartRequest) Reset() {\n\t*x = ServiceStartRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[36]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStartRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStartRequest) ProtoMessage() {}\n\nfunc (x *ServiceStartRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[36]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStartRequest.ProtoReflect.Descriptor instead.\nfunc (*ServiceStartRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{36}\n}\n\nfunc (x *ServiceStartRequest) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\ntype ServiceStart struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tResp          string                 `protobuf:\"bytes,2,opt,name=resp,proto3\" json:\"resp,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStart) Reset() {\n\t*x = ServiceStart{}\n\tmi := &file_machine_machine_proto_msgTypes[37]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStart) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStart) ProtoMessage() {}\n\nfunc (x *ServiceStart) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[37]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStart.ProtoReflect.Descriptor instead.\nfunc (*ServiceStart) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{37}\n}\n\nfunc (x *ServiceStart) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ServiceStart) GetResp() string {\n\tif x != nil {\n\t\treturn x.Resp\n\t}\n\treturn \"\"\n}\n\ntype ServiceStartResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ServiceStart        `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStartResponse) Reset() {\n\t*x = ServiceStartResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[38]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStartResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStartResponse) ProtoMessage() {}\n\nfunc (x *ServiceStartResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[38]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStartResponse.ProtoReflect.Descriptor instead.\nfunc (*ServiceStartResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{38}\n}\n\nfunc (x *ServiceStartResponse) GetMessages() []*ServiceStart {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ServiceStopRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tId            string                 `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStopRequest) Reset() {\n\t*x = ServiceStopRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[39]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStopRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStopRequest) ProtoMessage() {}\n\nfunc (x *ServiceStopRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[39]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStopRequest.ProtoReflect.Descriptor instead.\nfunc (*ServiceStopRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{39}\n}\n\nfunc (x *ServiceStopRequest) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\ntype ServiceStop struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tResp          string                 `protobuf:\"bytes,2,opt,name=resp,proto3\" json:\"resp,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStop) Reset() {\n\t*x = ServiceStop{}\n\tmi := &file_machine_machine_proto_msgTypes[40]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStop) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStop) ProtoMessage() {}\n\nfunc (x *ServiceStop) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[40]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStop.ProtoReflect.Descriptor instead.\nfunc (*ServiceStop) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{40}\n}\n\nfunc (x *ServiceStop) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ServiceStop) GetResp() string {\n\tif x != nil {\n\t\treturn x.Resp\n\t}\n\treturn \"\"\n}\n\ntype ServiceStopResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ServiceStop         `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceStopResponse) Reset() {\n\t*x = ServiceStopResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[41]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceStopResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceStopResponse) ProtoMessage() {}\n\nfunc (x *ServiceStopResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[41]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceStopResponse.ProtoReflect.Descriptor instead.\nfunc (*ServiceStopResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{41}\n}\n\nfunc (x *ServiceStopResponse) GetMessages() []*ServiceStop {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ServiceRestartRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tId            string                 `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceRestartRequest) Reset() {\n\t*x = ServiceRestartRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[42]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceRestartRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceRestartRequest) ProtoMessage() {}\n\nfunc (x *ServiceRestartRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[42]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceRestartRequest.ProtoReflect.Descriptor instead.\nfunc (*ServiceRestartRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{42}\n}\n\nfunc (x *ServiceRestartRequest) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\ntype ServiceRestart struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tResp          string                 `protobuf:\"bytes,2,opt,name=resp,proto3\" json:\"resp,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceRestart) Reset() {\n\t*x = ServiceRestart{}\n\tmi := &file_machine_machine_proto_msgTypes[43]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceRestart) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceRestart) ProtoMessage() {}\n\nfunc (x *ServiceRestart) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[43]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceRestart.ProtoReflect.Descriptor instead.\nfunc (*ServiceRestart) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{43}\n}\n\nfunc (x *ServiceRestart) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ServiceRestart) GetResp() string {\n\tif x != nil {\n\t\treturn x.Resp\n\t}\n\treturn \"\"\n}\n\ntype ServiceRestartResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ServiceRestart      `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceRestartResponse) Reset() {\n\t*x = ServiceRestartResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[44]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceRestartResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceRestartResponse) ProtoMessage() {}\n\nfunc (x *ServiceRestartResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[44]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceRestartResponse.ProtoReflect.Descriptor instead.\nfunc (*ServiceRestartResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{44}\n}\n\nfunc (x *ServiceRestartResponse) GetMessages() []*ServiceRestart {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// CopyRequest describes a request to copy data out of Talos node\n//\n// Copy produces .tar.gz archive which is streamed back to the caller\ntype CopyRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Root path to start copying data out, it might be either a file or directory\n\tRootPath      string `protobuf:\"bytes,1,opt,name=root_path,json=rootPath,proto3\" json:\"root_path,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CopyRequest) Reset() {\n\t*x = CopyRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[45]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CopyRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CopyRequest) ProtoMessage() {}\n\nfunc (x *CopyRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[45]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CopyRequest.ProtoReflect.Descriptor instead.\nfunc (*CopyRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{45}\n}\n\nfunc (x *CopyRequest) GetRootPath() string {\n\tif x != nil {\n\t\treturn x.RootPath\n\t}\n\treturn \"\"\n}\n\n// ListRequest describes a request to list the contents of a directory.\ntype ListRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Root indicates the root directory for the list. If not indicated, '/' is\n\t// presumed.\n\tRoot string `protobuf:\"bytes,1,opt,name=root,proto3\" json:\"root,omitempty\"`\n\t// Recurse indicates that subdirectories should be recursed.\n\tRecurse bool `protobuf:\"varint,2,opt,name=recurse,proto3\" json:\"recurse,omitempty\"`\n\t// RecursionDepth indicates how many levels of subdirectories should be\n\t// recursed. The default (0) indicates that no limit should be enforced.\n\tRecursionDepth int32 `protobuf:\"varint,3,opt,name=recursion_depth,json=recursionDepth,proto3\" json:\"recursion_depth,omitempty\"`\n\t// Types indicates what file type should be returned. If not indicated,\n\t// all files will be returned.\n\tTypes []ListRequest_Type `protobuf:\"varint,4,rep,packed,name=types,proto3,enum=machine.ListRequest_Type\" json:\"types,omitempty\"`\n\t// Report xattrs\n\tReportXattrs  bool `protobuf:\"varint,5,opt,name=report_xattrs,json=reportXattrs,proto3\" json:\"report_xattrs,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ListRequest) Reset() {\n\t*x = ListRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[46]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ListRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ListRequest) ProtoMessage() {}\n\nfunc (x *ListRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[46]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead.\nfunc (*ListRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{46}\n}\n\nfunc (x *ListRequest) GetRoot() string {\n\tif x != nil {\n\t\treturn x.Root\n\t}\n\treturn \"\"\n}\n\nfunc (x *ListRequest) GetRecurse() bool {\n\tif x != nil {\n\t\treturn x.Recurse\n\t}\n\treturn false\n}\n\nfunc (x *ListRequest) GetRecursionDepth() int32 {\n\tif x != nil {\n\t\treturn x.RecursionDepth\n\t}\n\treturn 0\n}\n\nfunc (x *ListRequest) GetTypes() []ListRequest_Type {\n\tif x != nil {\n\t\treturn x.Types\n\t}\n\treturn nil\n}\n\nfunc (x *ListRequest) GetReportXattrs() bool {\n\tif x != nil {\n\t\treturn x.ReportXattrs\n\t}\n\treturn false\n}\n\n// DiskUsageRequest describes a request to list disk usage of directories and regular files\ntype DiskUsageRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// RecursionDepth indicates how many levels of subdirectories should be\n\t// recursed. The default (0) indicates that no limit should be enforced.\n\tRecursionDepth int32 `protobuf:\"varint,1,opt,name=recursion_depth,json=recursionDepth,proto3\" json:\"recursion_depth,omitempty\"`\n\t// All write sizes for all files, not just directories.\n\tAll bool `protobuf:\"varint,2,opt,name=all,proto3\" json:\"all,omitempty\"`\n\t// Threshold exclude entries smaller than SIZE if positive,\n\t// or entries greater than SIZE if negative.\n\tThreshold int64 `protobuf:\"varint,3,opt,name=threshold,proto3\" json:\"threshold,omitempty\"`\n\t// DiskUsagePaths is the list of directories to calculate disk usage for.\n\tPaths         []string `protobuf:\"bytes,4,rep,name=paths,proto3\" json:\"paths,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiskUsageRequest) Reset() {\n\t*x = DiskUsageRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[47]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskUsageRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskUsageRequest) ProtoMessage() {}\n\nfunc (x *DiskUsageRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[47]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskUsageRequest.ProtoReflect.Descriptor instead.\nfunc (*DiskUsageRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{47}\n}\n\nfunc (x *DiskUsageRequest) GetRecursionDepth() int32 {\n\tif x != nil {\n\t\treturn x.RecursionDepth\n\t}\n\treturn 0\n}\n\nfunc (x *DiskUsageRequest) GetAll() bool {\n\tif x != nil {\n\t\treturn x.All\n\t}\n\treturn false\n}\n\nfunc (x *DiskUsageRequest) GetThreshold() int64 {\n\tif x != nil {\n\t\treturn x.Threshold\n\t}\n\treturn 0\n}\n\nfunc (x *DiskUsageRequest) GetPaths() []string {\n\tif x != nil {\n\t\treturn x.Paths\n\t}\n\treturn nil\n}\n\n// FileInfo describes a file or directory's information\ntype FileInfo struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\t// Name is the name (including prefixed path) of the file or directory\n\tName string `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Size indicates the number of bytes contained within the file\n\tSize int64 `protobuf:\"varint,3,opt,name=size,proto3\" json:\"size,omitempty\"`\n\t// Mode is the bitmap of UNIX mode/permission flags of the file\n\tMode uint32 `protobuf:\"varint,4,opt,name=mode,proto3\" json:\"mode,omitempty\"`\n\t// Modified indicates the UNIX timestamp at which the file was last modified\n\tModified int64 `protobuf:\"varint,5,opt,name=modified,proto3\" json:\"modified,omitempty\"`\n\t// IsDir indicates that the file is a directory\n\tIsDir bool `protobuf:\"varint,6,opt,name=is_dir,json=isDir,proto3\" json:\"is_dir,omitempty\"`\n\t// Error describes any error encountered while trying to read the file\n\t// information.\n\tError string `protobuf:\"bytes,7,opt,name=error,proto3\" json:\"error,omitempty\"`\n\t// Link is filled with symlink target\n\tLink string `protobuf:\"bytes,8,opt,name=link,proto3\" json:\"link,omitempty\"`\n\t// RelativeName is the name of the file or directory relative to the RootPath\n\tRelativeName string `protobuf:\"bytes,9,opt,name=relative_name,json=relativeName,proto3\" json:\"relative_name,omitempty\"`\n\t// Owner uid\n\tUid uint32 `protobuf:\"varint,10,opt,name=uid,proto3\" json:\"uid,omitempty\"`\n\t// Owner gid\n\tGid uint32 `protobuf:\"varint,11,opt,name=gid,proto3\" json:\"gid,omitempty\"`\n\t// Extended attributes (if present and requested)\n\tXattrs        []*Xattr `protobuf:\"bytes,12,rep,name=xattrs,proto3\" json:\"xattrs,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *FileInfo) Reset() {\n\t*x = FileInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[48]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *FileInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FileInfo) ProtoMessage() {}\n\nfunc (x *FileInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[48]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FileInfo.ProtoReflect.Descriptor instead.\nfunc (*FileInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{48}\n}\n\nfunc (x *FileInfo) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *FileInfo) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileInfo) GetSize() int64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *FileInfo) GetMode() uint32 {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn 0\n}\n\nfunc (x *FileInfo) GetModified() int64 {\n\tif x != nil {\n\t\treturn x.Modified\n\t}\n\treturn 0\n}\n\nfunc (x *FileInfo) GetIsDir() bool {\n\tif x != nil {\n\t\treturn x.IsDir\n\t}\n\treturn false\n}\n\nfunc (x *FileInfo) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileInfo) GetLink() string {\n\tif x != nil {\n\t\treturn x.Link\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileInfo) GetRelativeName() string {\n\tif x != nil {\n\t\treturn x.RelativeName\n\t}\n\treturn \"\"\n}\n\nfunc (x *FileInfo) GetUid() uint32 {\n\tif x != nil {\n\t\treturn x.Uid\n\t}\n\treturn 0\n}\n\nfunc (x *FileInfo) GetGid() uint32 {\n\tif x != nil {\n\t\treturn x.Gid\n\t}\n\treturn 0\n}\n\nfunc (x *FileInfo) GetXattrs() []*Xattr {\n\tif x != nil {\n\t\treturn x.Xattrs\n\t}\n\treturn nil\n}\n\ntype Xattr struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tData          []byte                 `protobuf:\"bytes,2,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Xattr) Reset() {\n\t*x = Xattr{}\n\tmi := &file_machine_machine_proto_msgTypes[49]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Xattr) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Xattr) ProtoMessage() {}\n\nfunc (x *Xattr) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[49]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Xattr.ProtoReflect.Descriptor instead.\nfunc (*Xattr) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{49}\n}\n\nfunc (x *Xattr) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Xattr) GetData() []byte {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\n// DiskUsageInfo describes a file or directory's information for du command\ntype DiskUsageInfo struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\t// Name is the name (including prefixed path) of the file or directory\n\tName string `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Size indicates the number of bytes contained within the file\n\tSize int64 `protobuf:\"varint,3,opt,name=size,proto3\" json:\"size,omitempty\"`\n\t// Error describes any error encountered while trying to read the file\n\t// information.\n\tError string `protobuf:\"bytes,4,opt,name=error,proto3\" json:\"error,omitempty\"`\n\t// RelativeName is the name of the file or directory relative to the RootPath\n\tRelativeName  string `protobuf:\"bytes,5,opt,name=relative_name,json=relativeName,proto3\" json:\"relative_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiskUsageInfo) Reset() {\n\t*x = DiskUsageInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[50]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskUsageInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskUsageInfo) ProtoMessage() {}\n\nfunc (x *DiskUsageInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[50]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskUsageInfo.ProtoReflect.Descriptor instead.\nfunc (*DiskUsageInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{50}\n}\n\nfunc (x *DiskUsageInfo) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *DiskUsageInfo) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskUsageInfo) GetSize() int64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *DiskUsageInfo) GetError() string {\n\tif x != nil {\n\t\treturn x.Error\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskUsageInfo) GetRelativeName() string {\n\tif x != nil {\n\t\treturn x.RelativeName\n\t}\n\treturn \"\"\n}\n\n// The messages message containing the requested df stats.\ntype Mounts struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tStats         []*MountStat           `protobuf:\"bytes,2,rep,name=stats,proto3\" json:\"stats,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Mounts) Reset() {\n\t*x = Mounts{}\n\tmi := &file_machine_machine_proto_msgTypes[51]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Mounts) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Mounts) ProtoMessage() {}\n\nfunc (x *Mounts) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[51]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Mounts.ProtoReflect.Descriptor instead.\nfunc (*Mounts) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{51}\n}\n\nfunc (x *Mounts) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Mounts) GetStats() []*MountStat {\n\tif x != nil {\n\t\treturn x.Stats\n\t}\n\treturn nil\n}\n\ntype MountsResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Mounts              `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MountsResponse) Reset() {\n\t*x = MountsResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[52]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountsResponse) ProtoMessage() {}\n\nfunc (x *MountsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[52]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountsResponse.ProtoReflect.Descriptor instead.\nfunc (*MountsResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{52}\n}\n\nfunc (x *MountsResponse) GetMessages() []*Mounts {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// The messages message containing the requested processes.\ntype MountStat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tFilesystem    string                 `protobuf:\"bytes,1,opt,name=filesystem,proto3\" json:\"filesystem,omitempty\"`\n\tSize          uint64                 `protobuf:\"varint,2,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tAvailable     uint64                 `protobuf:\"varint,3,opt,name=available,proto3\" json:\"available,omitempty\"`\n\tMountedOn     string                 `protobuf:\"bytes,4,opt,name=mounted_on,json=mountedOn,proto3\" json:\"mounted_on,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MountStat) Reset() {\n\t*x = MountStat{}\n\tmi := &file_machine_machine_proto_msgTypes[53]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountStat) ProtoMessage() {}\n\nfunc (x *MountStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[53]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountStat.ProtoReflect.Descriptor instead.\nfunc (*MountStat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{53}\n}\n\nfunc (x *MountStat) GetFilesystem() string {\n\tif x != nil {\n\t\treturn x.Filesystem\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStat) GetSize() uint64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *MountStat) GetAvailable() uint64 {\n\tif x != nil {\n\t\treturn x.Available\n\t}\n\treturn 0\n}\n\nfunc (x *MountStat) GetMountedOn() string {\n\tif x != nil {\n\t\treturn x.MountedOn\n\t}\n\treturn \"\"\n}\n\ntype Version struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tVersion  *VersionInfo           `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tPlatform *PlatformInfo          `protobuf:\"bytes,3,opt,name=platform,proto3\" json:\"platform,omitempty\"`\n\t// Features describe individual Talos features that can be switched on or off.\n\tFeatures      *FeaturesInfo `protobuf:\"bytes,4,opt,name=features,proto3\" json:\"features,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Version) Reset() {\n\t*x = Version{}\n\tmi := &file_machine_machine_proto_msgTypes[54]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Version) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Version) ProtoMessage() {}\n\nfunc (x *Version) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[54]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Version.ProtoReflect.Descriptor instead.\nfunc (*Version) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{54}\n}\n\nfunc (x *Version) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Version) GetVersion() *VersionInfo {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn nil\n}\n\nfunc (x *Version) GetPlatform() *PlatformInfo {\n\tif x != nil {\n\t\treturn x.Platform\n\t}\n\treturn nil\n}\n\nfunc (x *Version) GetFeatures() *FeaturesInfo {\n\tif x != nil {\n\t\treturn x.Features\n\t}\n\treturn nil\n}\n\ntype VersionResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Version             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VersionResponse) Reset() {\n\t*x = VersionResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[55]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VersionResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VersionResponse) ProtoMessage() {}\n\nfunc (x *VersionResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[55]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead.\nfunc (*VersionResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{55}\n}\n\nfunc (x *VersionResponse) GetMessages() []*Version {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype VersionInfo struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTag           string                 `protobuf:\"bytes,1,opt,name=tag,proto3\" json:\"tag,omitempty\"`\n\tSha           string                 `protobuf:\"bytes,2,opt,name=sha,proto3\" json:\"sha,omitempty\"`\n\tBuilt         string                 `protobuf:\"bytes,3,opt,name=built,proto3\" json:\"built,omitempty\"`\n\tGoVersion     string                 `protobuf:\"bytes,4,opt,name=go_version,json=goVersion,proto3\" json:\"go_version,omitempty\"`\n\tOs            string                 `protobuf:\"bytes,5,opt,name=os,proto3\" json:\"os,omitempty\"`\n\tArch          string                 `protobuf:\"bytes,6,opt,name=arch,proto3\" json:\"arch,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VersionInfo) Reset() {\n\t*x = VersionInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[56]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VersionInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VersionInfo) ProtoMessage() {}\n\nfunc (x *VersionInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[56]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VersionInfo.ProtoReflect.Descriptor instead.\nfunc (*VersionInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{56}\n}\n\nfunc (x *VersionInfo) GetTag() string {\n\tif x != nil {\n\t\treturn x.Tag\n\t}\n\treturn \"\"\n}\n\nfunc (x *VersionInfo) GetSha() string {\n\tif x != nil {\n\t\treturn x.Sha\n\t}\n\treturn \"\"\n}\n\nfunc (x *VersionInfo) GetBuilt() string {\n\tif x != nil {\n\t\treturn x.Built\n\t}\n\treturn \"\"\n}\n\nfunc (x *VersionInfo) GetGoVersion() string {\n\tif x != nil {\n\t\treturn x.GoVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *VersionInfo) GetOs() string {\n\tif x != nil {\n\t\treturn x.Os\n\t}\n\treturn \"\"\n}\n\nfunc (x *VersionInfo) GetArch() string {\n\tif x != nil {\n\t\treturn x.Arch\n\t}\n\treturn \"\"\n}\n\ntype PlatformInfo struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tMode          string                 `protobuf:\"bytes,2,opt,name=mode,proto3\" json:\"mode,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PlatformInfo) Reset() {\n\t*x = PlatformInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[57]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PlatformInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PlatformInfo) ProtoMessage() {}\n\nfunc (x *PlatformInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[57]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PlatformInfo.ProtoReflect.Descriptor instead.\nfunc (*PlatformInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{57}\n}\n\nfunc (x *PlatformInfo) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformInfo) GetMode() string {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn \"\"\n}\n\n// FeaturesInfo describes individual Talos features that can be switched on or off.\ntype FeaturesInfo struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// RBAC is true if role-based access control is enabled.\n\tRbac          bool `protobuf:\"varint,1,opt,name=rbac,proto3\" json:\"rbac,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *FeaturesInfo) Reset() {\n\t*x = FeaturesInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[58]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *FeaturesInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FeaturesInfo) ProtoMessage() {}\n\nfunc (x *FeaturesInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[58]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FeaturesInfo.ProtoReflect.Descriptor instead.\nfunc (*FeaturesInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{58}\n}\n\nfunc (x *FeaturesInfo) GetRbac() bool {\n\tif x != nil {\n\t\treturn x.Rbac\n\t}\n\treturn false\n}\n\n// rpc logs\n// The request message containing the process name.\ntype LogsRequest struct {\n\tstate     protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\tId        string                 `protobuf:\"bytes,2,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// driver might be default \"containerd\" or \"cri\"\n\tDriver        common.ContainerDriver `protobuf:\"varint,3,opt,name=driver,proto3,enum=common.ContainerDriver\" json:\"driver,omitempty\"`\n\tFollow        bool                   `protobuf:\"varint,4,opt,name=follow,proto3\" json:\"follow,omitempty\"`\n\tTailLines     int32                  `protobuf:\"varint,5,opt,name=tail_lines,json=tailLines,proto3\" json:\"tail_lines,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LogsRequest) Reset() {\n\t*x = LogsRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[59]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LogsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LogsRequest) ProtoMessage() {}\n\nfunc (x *LogsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[59]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LogsRequest.ProtoReflect.Descriptor instead.\nfunc (*LogsRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{59}\n}\n\nfunc (x *LogsRequest) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *LogsRequest) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *LogsRequest) GetDriver() common.ContainerDriver {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn common.ContainerDriver(0)\n}\n\nfunc (x *LogsRequest) GetFollow() bool {\n\tif x != nil {\n\t\treturn x.Follow\n\t}\n\treturn false\n}\n\nfunc (x *LogsRequest) GetTailLines() int32 {\n\tif x != nil {\n\t\treturn x.TailLines\n\t}\n\treturn 0\n}\n\ntype ReadRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPath          string                 `protobuf:\"bytes,1,opt,name=path,proto3\" json:\"path,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ReadRequest) Reset() {\n\t*x = ReadRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[60]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadRequest) ProtoMessage() {}\n\nfunc (x *ReadRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[60]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead.\nfunc (*ReadRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{60}\n}\n\nfunc (x *ReadRequest) GetPath() string {\n\tif x != nil {\n\t\treturn x.Path\n\t}\n\treturn \"\"\n}\n\n// LogsContainer describes all available registered log containers.\ntype LogsContainer struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tIds           []string               `protobuf:\"bytes,2,rep,name=ids,proto3\" json:\"ids,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LogsContainer) Reset() {\n\t*x = LogsContainer{}\n\tmi := &file_machine_machine_proto_msgTypes[61]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LogsContainer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LogsContainer) ProtoMessage() {}\n\nfunc (x *LogsContainer) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[61]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LogsContainer.ProtoReflect.Descriptor instead.\nfunc (*LogsContainer) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{61}\n}\n\nfunc (x *LogsContainer) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *LogsContainer) GetIds() []string {\n\tif x != nil {\n\t\treturn x.Ids\n\t}\n\treturn nil\n}\n\ntype LogsContainersResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*LogsContainer       `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LogsContainersResponse) Reset() {\n\t*x = LogsContainersResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[62]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LogsContainersResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LogsContainersResponse) ProtoMessage() {}\n\nfunc (x *LogsContainersResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[62]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LogsContainersResponse.ProtoReflect.Descriptor instead.\nfunc (*LogsContainersResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{62}\n}\n\nfunc (x *LogsContainersResponse) GetMessages() []*LogsContainer {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// rpc rollback\ntype RollbackRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RollbackRequest) Reset() {\n\t*x = RollbackRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[63]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RollbackRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RollbackRequest) ProtoMessage() {}\n\nfunc (x *RollbackRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[63]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RollbackRequest.ProtoReflect.Descriptor instead.\nfunc (*RollbackRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{63}\n}\n\ntype Rollback struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Rollback) Reset() {\n\t*x = Rollback{}\n\tmi := &file_machine_machine_proto_msgTypes[64]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Rollback) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Rollback) ProtoMessage() {}\n\nfunc (x *Rollback) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[64]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Rollback.ProtoReflect.Descriptor instead.\nfunc (*Rollback) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{64}\n}\n\nfunc (x *Rollback) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype RollbackResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Rollback            `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RollbackResponse) Reset() {\n\t*x = RollbackResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[65]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RollbackResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RollbackResponse) ProtoMessage() {}\n\nfunc (x *RollbackResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[65]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RollbackResponse.ProtoReflect.Descriptor instead.\nfunc (*RollbackResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{65}\n}\n\nfunc (x *RollbackResponse) GetMessages() []*Rollback {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ContainersRequest struct {\n\tstate     protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\t// driver might be default \"containerd\" or \"cri\"\n\tDriver        common.ContainerDriver `protobuf:\"varint,2,opt,name=driver,proto3,enum=common.ContainerDriver\" json:\"driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ContainersRequest) Reset() {\n\t*x = ContainersRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[66]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ContainersRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ContainersRequest) ProtoMessage() {}\n\nfunc (x *ContainersRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[66]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ContainersRequest.ProtoReflect.Descriptor instead.\nfunc (*ContainersRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{66}\n}\n\nfunc (x *ContainersRequest) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainersRequest) GetDriver() common.ContainerDriver {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn common.ContainerDriver(0)\n}\n\n// The messages message containing the requested containers.\ntype ContainerInfo struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace        string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\tId               string                 `protobuf:\"bytes,2,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tUid              string                 `protobuf:\"bytes,10,opt,name=uid,proto3\" json:\"uid,omitempty\"`\n\tInternalId       string                 `protobuf:\"bytes,9,opt,name=internal_id,json=internalId,proto3\" json:\"internal_id,omitempty\"`\n\tImage            string                 `protobuf:\"bytes,3,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tPid              uint32                 `protobuf:\"varint,4,opt,name=pid,proto3\" json:\"pid,omitempty\"`\n\tStatus           string                 `protobuf:\"bytes,5,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tPodId            string                 `protobuf:\"bytes,6,opt,name=pod_id,json=podId,proto3\" json:\"pod_id,omitempty\"`\n\tName             string                 `protobuf:\"bytes,7,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tNetworkNamespace string                 `protobuf:\"bytes,8,opt,name=network_namespace,json=networkNamespace,proto3\" json:\"network_namespace,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ContainerInfo) Reset() {\n\t*x = ContainerInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[67]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ContainerInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ContainerInfo) ProtoMessage() {}\n\nfunc (x *ContainerInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[67]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ContainerInfo.ProtoReflect.Descriptor instead.\nfunc (*ContainerInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{67}\n}\n\nfunc (x *ContainerInfo) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetUid() string {\n\tif x != nil {\n\t\treturn x.Uid\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetInternalId() string {\n\tif x != nil {\n\t\treturn x.InternalId\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetPid() uint32 {\n\tif x != nil {\n\t\treturn x.Pid\n\t}\n\treturn 0\n}\n\nfunc (x *ContainerInfo) GetStatus() string {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetPodId() string {\n\tif x != nil {\n\t\treturn x.PodId\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ContainerInfo) GetNetworkNamespace() string {\n\tif x != nil {\n\t\treturn x.NetworkNamespace\n\t}\n\treturn \"\"\n}\n\n// The messages message containing the requested containers.\ntype Container struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tContainers    []*ContainerInfo       `protobuf:\"bytes,2,rep,name=containers,proto3\" json:\"containers,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Container) Reset() {\n\t*x = Container{}\n\tmi := &file_machine_machine_proto_msgTypes[68]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Container) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Container) ProtoMessage() {}\n\nfunc (x *Container) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[68]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Container.ProtoReflect.Descriptor instead.\nfunc (*Container) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{68}\n}\n\nfunc (x *Container) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Container) GetContainers() []*ContainerInfo {\n\tif x != nil {\n\t\treturn x.Containers\n\t}\n\treturn nil\n}\n\ntype ContainersResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Container           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ContainersResponse) Reset() {\n\t*x = ContainersResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[69]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ContainersResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ContainersResponse) ProtoMessage() {}\n\nfunc (x *ContainersResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[69]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ContainersResponse.ProtoReflect.Descriptor instead.\nfunc (*ContainersResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{69}\n}\n\nfunc (x *ContainersResponse) GetMessages() []*Container {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// dmesg\ntype DmesgRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tFollow        bool                   `protobuf:\"varint,1,opt,name=follow,proto3\" json:\"follow,omitempty\"`\n\tTail          bool                   `protobuf:\"varint,2,opt,name=tail,proto3\" json:\"tail,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DmesgRequest) Reset() {\n\t*x = DmesgRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[70]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DmesgRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DmesgRequest) ProtoMessage() {}\n\nfunc (x *DmesgRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[70]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DmesgRequest.ProtoReflect.Descriptor instead.\nfunc (*DmesgRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{70}\n}\n\nfunc (x *DmesgRequest) GetFollow() bool {\n\tif x != nil {\n\t\treturn x.Follow\n\t}\n\treturn false\n}\n\nfunc (x *DmesgRequest) GetTail() bool {\n\tif x != nil {\n\t\treturn x.Tail\n\t}\n\treturn false\n}\n\n// rpc processes\ntype ProcessesResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Process             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ProcessesResponse) Reset() {\n\t*x = ProcessesResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[71]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProcessesResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProcessesResponse) ProtoMessage() {}\n\nfunc (x *ProcessesResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[71]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProcessesResponse.ProtoReflect.Descriptor instead.\nfunc (*ProcessesResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{71}\n}\n\nfunc (x *ProcessesResponse) GetMessages() []*Process {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype Process struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tProcesses     []*ProcessInfo         `protobuf:\"bytes,2,rep,name=processes,proto3\" json:\"processes,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Process) Reset() {\n\t*x = Process{}\n\tmi := &file_machine_machine_proto_msgTypes[72]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Process) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Process) ProtoMessage() {}\n\nfunc (x *Process) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[72]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Process.ProtoReflect.Descriptor instead.\nfunc (*Process) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{72}\n}\n\nfunc (x *Process) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Process) GetProcesses() []*ProcessInfo {\n\tif x != nil {\n\t\treturn x.Processes\n\t}\n\treturn nil\n}\n\ntype ProcessInfo struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tPid            int32                  `protobuf:\"varint,1,opt,name=pid,proto3\" json:\"pid,omitempty\"`\n\tPpid           int32                  `protobuf:\"varint,2,opt,name=ppid,proto3\" json:\"ppid,omitempty\"`\n\tState          string                 `protobuf:\"bytes,3,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tThreads        int32                  `protobuf:\"varint,4,opt,name=threads,proto3\" json:\"threads,omitempty\"`\n\tCpuTime        float64                `protobuf:\"fixed64,5,opt,name=cpu_time,json=cpuTime,proto3\" json:\"cpu_time,omitempty\"`\n\tVirtualMemory  uint64                 `protobuf:\"varint,6,opt,name=virtual_memory,json=virtualMemory,proto3\" json:\"virtual_memory,omitempty\"`\n\tResidentMemory uint64                 `protobuf:\"varint,7,opt,name=resident_memory,json=residentMemory,proto3\" json:\"resident_memory,omitempty\"`\n\tCommand        string                 `protobuf:\"bytes,8,opt,name=command,proto3\" json:\"command,omitempty\"`\n\tExecutable     string                 `protobuf:\"bytes,9,opt,name=executable,proto3\" json:\"executable,omitempty\"`\n\tArgs           string                 `protobuf:\"bytes,10,opt,name=args,proto3\" json:\"args,omitempty\"`\n\tLabel          string                 `protobuf:\"bytes,11,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ProcessInfo) Reset() {\n\t*x = ProcessInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[73]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProcessInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProcessInfo) ProtoMessage() {}\n\nfunc (x *ProcessInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[73]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProcessInfo.ProtoReflect.Descriptor instead.\nfunc (*ProcessInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{73}\n}\n\nfunc (x *ProcessInfo) GetPid() int32 {\n\tif x != nil {\n\t\treturn x.Pid\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetPpid() int32 {\n\tif x != nil {\n\t\treturn x.Ppid\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetState() string {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessInfo) GetThreads() int32 {\n\tif x != nil {\n\t\treturn x.Threads\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetCpuTime() float64 {\n\tif x != nil {\n\t\treturn x.CpuTime\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetVirtualMemory() uint64 {\n\tif x != nil {\n\t\treturn x.VirtualMemory\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetResidentMemory() uint64 {\n\tif x != nil {\n\t\treturn x.ResidentMemory\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessInfo) GetCommand() string {\n\tif x != nil {\n\t\treturn x.Command\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessInfo) GetExecutable() string {\n\tif x != nil {\n\t\treturn x.Executable\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessInfo) GetArgs() string {\n\tif x != nil {\n\t\treturn x.Args\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessInfo) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\n// rpc restart\n// The request message containing the process to restart.\ntype RestartRequest struct {\n\tstate     protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\tId        string                 `protobuf:\"bytes,2,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// driver might be default \"containerd\" or \"cri\"\n\tDriver        common.ContainerDriver `protobuf:\"varint,3,opt,name=driver,proto3,enum=common.ContainerDriver\" json:\"driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RestartRequest) Reset() {\n\t*x = RestartRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[74]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RestartRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestartRequest) ProtoMessage() {}\n\nfunc (x *RestartRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[74]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestartRequest.ProtoReflect.Descriptor instead.\nfunc (*RestartRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{74}\n}\n\nfunc (x *RestartRequest) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *RestartRequest) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *RestartRequest) GetDriver() common.ContainerDriver {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn common.ContainerDriver(0)\n}\n\ntype Restart struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Restart) Reset() {\n\t*x = Restart{}\n\tmi := &file_machine_machine_proto_msgTypes[75]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Restart) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Restart) ProtoMessage() {}\n\nfunc (x *Restart) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[75]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Restart.ProtoReflect.Descriptor instead.\nfunc (*Restart) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{75}\n}\n\nfunc (x *Restart) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\n// The messages message containing the restart status.\ntype RestartResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Restart             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RestartResponse) Reset() {\n\t*x = RestartResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[76]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RestartResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RestartResponse) ProtoMessage() {}\n\nfunc (x *RestartResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[76]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RestartResponse.ProtoReflect.Descriptor instead.\nfunc (*RestartResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{76}\n}\n\nfunc (x *RestartResponse) GetMessages() []*Restart {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// The request message containing the containerd namespace.\ntype StatsRequest struct {\n\tstate     protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\t// driver might be default \"containerd\" or \"cri\"\n\tDriver        common.ContainerDriver `protobuf:\"varint,2,opt,name=driver,proto3,enum=common.ContainerDriver\" json:\"driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StatsRequest) Reset() {\n\t*x = StatsRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[77]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StatsRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StatsRequest) ProtoMessage() {}\n\nfunc (x *StatsRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[77]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StatsRequest.ProtoReflect.Descriptor instead.\nfunc (*StatsRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{77}\n}\n\nfunc (x *StatsRequest) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *StatsRequest) GetDriver() common.ContainerDriver {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn common.ContainerDriver(0)\n}\n\n// The messages message containing the requested stats.\ntype Stats struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tStats         []*Stat                `protobuf:\"bytes,2,rep,name=stats,proto3\" json:\"stats,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Stats) Reset() {\n\t*x = Stats{}\n\tmi := &file_machine_machine_proto_msgTypes[78]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Stats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Stats) ProtoMessage() {}\n\nfunc (x *Stats) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[78]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Stats.ProtoReflect.Descriptor instead.\nfunc (*Stats) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{78}\n}\n\nfunc (x *Stats) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Stats) GetStats() []*Stat {\n\tif x != nil {\n\t\treturn x.Stats\n\t}\n\treturn nil\n}\n\ntype StatsResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Stats               `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StatsResponse) Reset() {\n\t*x = StatsResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[79]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StatsResponse) ProtoMessage() {}\n\nfunc (x *StatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[79]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StatsResponse.ProtoReflect.Descriptor instead.\nfunc (*StatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{79}\n}\n\nfunc (x *StatsResponse) GetMessages() []*Stats {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\n// The messages message containing the requested stat.\ntype Stat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tNamespace     string                 `protobuf:\"bytes,1,opt,name=namespace,proto3\" json:\"namespace,omitempty\"`\n\tId            string                 `protobuf:\"bytes,2,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tMemoryUsage   uint64                 `protobuf:\"varint,4,opt,name=memory_usage,json=memoryUsage,proto3\" json:\"memory_usage,omitempty\"`\n\tCpuUsage      uint64                 `protobuf:\"varint,5,opt,name=cpu_usage,json=cpuUsage,proto3\" json:\"cpu_usage,omitempty\"`\n\tPodId         string                 `protobuf:\"bytes,6,opt,name=pod_id,json=podId,proto3\" json:\"pod_id,omitempty\"`\n\tName          string                 `protobuf:\"bytes,7,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Stat) Reset() {\n\t*x = Stat{}\n\tmi := &file_machine_machine_proto_msgTypes[80]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Stat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Stat) ProtoMessage() {}\n\nfunc (x *Stat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[80]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Stat.ProtoReflect.Descriptor instead.\nfunc (*Stat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{80}\n}\n\nfunc (x *Stat) GetNamespace() string {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn \"\"\n}\n\nfunc (x *Stat) GetId() string {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn \"\"\n}\n\nfunc (x *Stat) GetMemoryUsage() uint64 {\n\tif x != nil {\n\t\treturn x.MemoryUsage\n\t}\n\treturn 0\n}\n\nfunc (x *Stat) GetCpuUsage() uint64 {\n\tif x != nil {\n\t\treturn x.CpuUsage\n\t}\n\treturn 0\n}\n\nfunc (x *Stat) GetPodId() string {\n\tif x != nil {\n\t\treturn x.PodId\n\t}\n\treturn \"\"\n}\n\nfunc (x *Stat) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\ntype Memory struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMeminfo       *MemInfo               `protobuf:\"bytes,2,opt,name=meminfo,proto3\" json:\"meminfo,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Memory) Reset() {\n\t*x = Memory{}\n\tmi := &file_machine_machine_proto_msgTypes[81]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Memory) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Memory) ProtoMessage() {}\n\nfunc (x *Memory) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[81]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Memory.ProtoReflect.Descriptor instead.\nfunc (*Memory) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{81}\n}\n\nfunc (x *Memory) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Memory) GetMeminfo() *MemInfo {\n\tif x != nil {\n\t\treturn x.Meminfo\n\t}\n\treturn nil\n}\n\ntype MemoryResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Memory              `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MemoryResponse) Reset() {\n\t*x = MemoryResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[82]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemoryResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemoryResponse) ProtoMessage() {}\n\nfunc (x *MemoryResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[82]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemoryResponse.ProtoReflect.Descriptor instead.\nfunc (*MemoryResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{82}\n}\n\nfunc (x *MemoryResponse) GetMessages() []*Memory {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype MemInfo struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tMemtotal          uint64                 `protobuf:\"varint,1,opt,name=memtotal,proto3\" json:\"memtotal,omitempty\"`\n\tMemfree           uint64                 `protobuf:\"varint,2,opt,name=memfree,proto3\" json:\"memfree,omitempty\"`\n\tMemavailable      uint64                 `protobuf:\"varint,3,opt,name=memavailable,proto3\" json:\"memavailable,omitempty\"`\n\tBuffers           uint64                 `protobuf:\"varint,4,opt,name=buffers,proto3\" json:\"buffers,omitempty\"`\n\tCached            uint64                 `protobuf:\"varint,5,opt,name=cached,proto3\" json:\"cached,omitempty\"`\n\tSwapcached        uint64                 `protobuf:\"varint,6,opt,name=swapcached,proto3\" json:\"swapcached,omitempty\"`\n\tActive            uint64                 `protobuf:\"varint,7,opt,name=active,proto3\" json:\"active,omitempty\"`\n\tInactive          uint64                 `protobuf:\"varint,8,opt,name=inactive,proto3\" json:\"inactive,omitempty\"`\n\tActiveanon        uint64                 `protobuf:\"varint,9,opt,name=activeanon,proto3\" json:\"activeanon,omitempty\"`\n\tInactiveanon      uint64                 `protobuf:\"varint,10,opt,name=inactiveanon,proto3\" json:\"inactiveanon,omitempty\"`\n\tActivefile        uint64                 `protobuf:\"varint,11,opt,name=activefile,proto3\" json:\"activefile,omitempty\"`\n\tInactivefile      uint64                 `protobuf:\"varint,12,opt,name=inactivefile,proto3\" json:\"inactivefile,omitempty\"`\n\tUnevictable       uint64                 `protobuf:\"varint,13,opt,name=unevictable,proto3\" json:\"unevictable,omitempty\"`\n\tMlocked           uint64                 `protobuf:\"varint,14,opt,name=mlocked,proto3\" json:\"mlocked,omitempty\"`\n\tSwaptotal         uint64                 `protobuf:\"varint,15,opt,name=swaptotal,proto3\" json:\"swaptotal,omitempty\"`\n\tSwapfree          uint64                 `protobuf:\"varint,16,opt,name=swapfree,proto3\" json:\"swapfree,omitempty\"`\n\tDirty             uint64                 `protobuf:\"varint,17,opt,name=dirty,proto3\" json:\"dirty,omitempty\"`\n\tWriteback         uint64                 `protobuf:\"varint,18,opt,name=writeback,proto3\" json:\"writeback,omitempty\"`\n\tAnonpages         uint64                 `protobuf:\"varint,19,opt,name=anonpages,proto3\" json:\"anonpages,omitempty\"`\n\tMapped            uint64                 `protobuf:\"varint,20,opt,name=mapped,proto3\" json:\"mapped,omitempty\"`\n\tShmem             uint64                 `protobuf:\"varint,21,opt,name=shmem,proto3\" json:\"shmem,omitempty\"`\n\tSlab              uint64                 `protobuf:\"varint,22,opt,name=slab,proto3\" json:\"slab,omitempty\"`\n\tSreclaimable      uint64                 `protobuf:\"varint,23,opt,name=sreclaimable,proto3\" json:\"sreclaimable,omitempty\"`\n\tSunreclaim        uint64                 `protobuf:\"varint,24,opt,name=sunreclaim,proto3\" json:\"sunreclaim,omitempty\"`\n\tKernelstack       uint64                 `protobuf:\"varint,25,opt,name=kernelstack,proto3\" json:\"kernelstack,omitempty\"`\n\tPagetables        uint64                 `protobuf:\"varint,26,opt,name=pagetables,proto3\" json:\"pagetables,omitempty\"`\n\tNfsunstable       uint64                 `protobuf:\"varint,27,opt,name=nfsunstable,proto3\" json:\"nfsunstable,omitempty\"`\n\tBounce            uint64                 `protobuf:\"varint,28,opt,name=bounce,proto3\" json:\"bounce,omitempty\"`\n\tWritebacktmp      uint64                 `protobuf:\"varint,29,opt,name=writebacktmp,proto3\" json:\"writebacktmp,omitempty\"`\n\tCommitlimit       uint64                 `protobuf:\"varint,30,opt,name=commitlimit,proto3\" json:\"commitlimit,omitempty\"`\n\tCommittedas       uint64                 `protobuf:\"varint,31,opt,name=committedas,proto3\" json:\"committedas,omitempty\"`\n\tVmalloctotal      uint64                 `protobuf:\"varint,32,opt,name=vmalloctotal,proto3\" json:\"vmalloctotal,omitempty\"`\n\tVmallocused       uint64                 `protobuf:\"varint,33,opt,name=vmallocused,proto3\" json:\"vmallocused,omitempty\"`\n\tVmallocchunk      uint64                 `protobuf:\"varint,34,opt,name=vmallocchunk,proto3\" json:\"vmallocchunk,omitempty\"`\n\tHardwarecorrupted uint64                 `protobuf:\"varint,35,opt,name=hardwarecorrupted,proto3\" json:\"hardwarecorrupted,omitempty\"`\n\tAnonhugepages     uint64                 `protobuf:\"varint,36,opt,name=anonhugepages,proto3\" json:\"anonhugepages,omitempty\"`\n\tShmemhugepages    uint64                 `protobuf:\"varint,37,opt,name=shmemhugepages,proto3\" json:\"shmemhugepages,omitempty\"`\n\tShmempmdmapped    uint64                 `protobuf:\"varint,38,opt,name=shmempmdmapped,proto3\" json:\"shmempmdmapped,omitempty\"`\n\tCmatotal          uint64                 `protobuf:\"varint,39,opt,name=cmatotal,proto3\" json:\"cmatotal,omitempty\"`\n\tCmafree           uint64                 `protobuf:\"varint,40,opt,name=cmafree,proto3\" json:\"cmafree,omitempty\"`\n\tHugepagestotal    uint64                 `protobuf:\"varint,41,opt,name=hugepagestotal,proto3\" json:\"hugepagestotal,omitempty\"`\n\tHugepagesfree     uint64                 `protobuf:\"varint,42,opt,name=hugepagesfree,proto3\" json:\"hugepagesfree,omitempty\"`\n\tHugepagesrsvd     uint64                 `protobuf:\"varint,43,opt,name=hugepagesrsvd,proto3\" json:\"hugepagesrsvd,omitempty\"`\n\tHugepagessurp     uint64                 `protobuf:\"varint,44,opt,name=hugepagessurp,proto3\" json:\"hugepagessurp,omitempty\"`\n\tHugepagesize      uint64                 `protobuf:\"varint,45,opt,name=hugepagesize,proto3\" json:\"hugepagesize,omitempty\"`\n\tDirectmap4K       uint64                 `protobuf:\"varint,46,opt,name=directmap4k,proto3\" json:\"directmap4k,omitempty\"`\n\tDirectmap2M       uint64                 `protobuf:\"varint,47,opt,name=directmap2m,proto3\" json:\"directmap2m,omitempty\"`\n\tDirectmap1G       uint64                 `protobuf:\"varint,48,opt,name=directmap1g,proto3\" json:\"directmap1g,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *MemInfo) Reset() {\n\t*x = MemInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[83]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemInfo) ProtoMessage() {}\n\nfunc (x *MemInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[83]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemInfo.ProtoReflect.Descriptor instead.\nfunc (*MemInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{83}\n}\n\nfunc (x *MemInfo) GetMemtotal() uint64 {\n\tif x != nil {\n\t\treturn x.Memtotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetMemfree() uint64 {\n\tif x != nil {\n\t\treturn x.Memfree\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetMemavailable() uint64 {\n\tif x != nil {\n\t\treturn x.Memavailable\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetBuffers() uint64 {\n\tif x != nil {\n\t\treturn x.Buffers\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetCached() uint64 {\n\tif x != nil {\n\t\treturn x.Cached\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSwapcached() uint64 {\n\tif x != nil {\n\t\treturn x.Swapcached\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetActive() uint64 {\n\tif x != nil {\n\t\treturn x.Active\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetInactive() uint64 {\n\tif x != nil {\n\t\treturn x.Inactive\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetActiveanon() uint64 {\n\tif x != nil {\n\t\treturn x.Activeanon\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetInactiveanon() uint64 {\n\tif x != nil {\n\t\treturn x.Inactiveanon\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetActivefile() uint64 {\n\tif x != nil {\n\t\treturn x.Activefile\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetInactivefile() uint64 {\n\tif x != nil {\n\t\treturn x.Inactivefile\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetUnevictable() uint64 {\n\tif x != nil {\n\t\treturn x.Unevictable\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetMlocked() uint64 {\n\tif x != nil {\n\t\treturn x.Mlocked\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSwaptotal() uint64 {\n\tif x != nil {\n\t\treturn x.Swaptotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSwapfree() uint64 {\n\tif x != nil {\n\t\treturn x.Swapfree\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetDirty() uint64 {\n\tif x != nil {\n\t\treturn x.Dirty\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetWriteback() uint64 {\n\tif x != nil {\n\t\treturn x.Writeback\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetAnonpages() uint64 {\n\tif x != nil {\n\t\treturn x.Anonpages\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetMapped() uint64 {\n\tif x != nil {\n\t\treturn x.Mapped\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetShmem() uint64 {\n\tif x != nil {\n\t\treturn x.Shmem\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSlab() uint64 {\n\tif x != nil {\n\t\treturn x.Slab\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSreclaimable() uint64 {\n\tif x != nil {\n\t\treturn x.Sreclaimable\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetSunreclaim() uint64 {\n\tif x != nil {\n\t\treturn x.Sunreclaim\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetKernelstack() uint64 {\n\tif x != nil {\n\t\treturn x.Kernelstack\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetPagetables() uint64 {\n\tif x != nil {\n\t\treturn x.Pagetables\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetNfsunstable() uint64 {\n\tif x != nil {\n\t\treturn x.Nfsunstable\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetBounce() uint64 {\n\tif x != nil {\n\t\treturn x.Bounce\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetWritebacktmp() uint64 {\n\tif x != nil {\n\t\treturn x.Writebacktmp\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetCommitlimit() uint64 {\n\tif x != nil {\n\t\treturn x.Commitlimit\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetCommittedas() uint64 {\n\tif x != nil {\n\t\treturn x.Committedas\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetVmalloctotal() uint64 {\n\tif x != nil {\n\t\treturn x.Vmalloctotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetVmallocused() uint64 {\n\tif x != nil {\n\t\treturn x.Vmallocused\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetVmallocchunk() uint64 {\n\tif x != nil {\n\t\treturn x.Vmallocchunk\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHardwarecorrupted() uint64 {\n\tif x != nil {\n\t\treturn x.Hardwarecorrupted\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetAnonhugepages() uint64 {\n\tif x != nil {\n\t\treturn x.Anonhugepages\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetShmemhugepages() uint64 {\n\tif x != nil {\n\t\treturn x.Shmemhugepages\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetShmempmdmapped() uint64 {\n\tif x != nil {\n\t\treturn x.Shmempmdmapped\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetCmatotal() uint64 {\n\tif x != nil {\n\t\treturn x.Cmatotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetCmafree() uint64 {\n\tif x != nil {\n\t\treturn x.Cmafree\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHugepagestotal() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagestotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHugepagesfree() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagesfree\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHugepagesrsvd() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagesrsvd\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHugepagessurp() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagessurp\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetHugepagesize() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagesize\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetDirectmap4K() uint64 {\n\tif x != nil {\n\t\treturn x.Directmap4K\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetDirectmap2M() uint64 {\n\tif x != nil {\n\t\treturn x.Directmap2M\n\t}\n\treturn 0\n}\n\nfunc (x *MemInfo) GetDirectmap1G() uint64 {\n\tif x != nil {\n\t\treturn x.Directmap1G\n\t}\n\treturn 0\n}\n\ntype HostnameResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Hostname            `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HostnameResponse) Reset() {\n\t*x = HostnameResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[84]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HostnameResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HostnameResponse) ProtoMessage() {}\n\nfunc (x *HostnameResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[84]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HostnameResponse.ProtoReflect.Descriptor instead.\nfunc (*HostnameResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{84}\n}\n\nfunc (x *HostnameResponse) GetMessages() []*Hostname {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype Hostname struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tHostname      string                 `protobuf:\"bytes,2,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Hostname) Reset() {\n\t*x = Hostname{}\n\tmi := &file_machine_machine_proto_msgTypes[85]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Hostname) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Hostname) ProtoMessage() {}\n\nfunc (x *Hostname) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[85]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Hostname.ProtoReflect.Descriptor instead.\nfunc (*Hostname) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{85}\n}\n\nfunc (x *Hostname) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Hostname) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\ntype LoadAvgResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*LoadAvg             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LoadAvgResponse) Reset() {\n\t*x = LoadAvgResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[86]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LoadAvgResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LoadAvgResponse) ProtoMessage() {}\n\nfunc (x *LoadAvgResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[86]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LoadAvgResponse.ProtoReflect.Descriptor instead.\nfunc (*LoadAvgResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{86}\n}\n\nfunc (x *LoadAvgResponse) GetMessages() []*LoadAvg {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype LoadAvg struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tLoad1         float64                `protobuf:\"fixed64,2,opt,name=load1,proto3\" json:\"load1,omitempty\"`\n\tLoad5         float64                `protobuf:\"fixed64,3,opt,name=load5,proto3\" json:\"load5,omitempty\"`\n\tLoad15        float64                `protobuf:\"fixed64,4,opt,name=load15,proto3\" json:\"load15,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LoadAvg) Reset() {\n\t*x = LoadAvg{}\n\tmi := &file_machine_machine_proto_msgTypes[87]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LoadAvg) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LoadAvg) ProtoMessage() {}\n\nfunc (x *LoadAvg) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[87]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LoadAvg.ProtoReflect.Descriptor instead.\nfunc (*LoadAvg) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{87}\n}\n\nfunc (x *LoadAvg) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *LoadAvg) GetLoad1() float64 {\n\tif x != nil {\n\t\treturn x.Load1\n\t}\n\treturn 0\n}\n\nfunc (x *LoadAvg) GetLoad5() float64 {\n\tif x != nil {\n\t\treturn x.Load5\n\t}\n\treturn 0\n}\n\nfunc (x *LoadAvg) GetLoad15() float64 {\n\tif x != nil {\n\t\treturn x.Load15\n\t}\n\treturn 0\n}\n\ntype SystemStatResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*SystemStat          `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SystemStatResponse) Reset() {\n\t*x = SystemStatResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[88]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SystemStatResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemStatResponse) ProtoMessage() {}\n\nfunc (x *SystemStatResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[88]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemStatResponse.ProtoReflect.Descriptor instead.\nfunc (*SystemStatResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{88}\n}\n\nfunc (x *SystemStatResponse) GetMessages() []*SystemStat {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype SystemStat struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata        *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tBootTime        uint64                 `protobuf:\"varint,2,opt,name=boot_time,json=bootTime,proto3\" json:\"boot_time,omitempty\"`\n\tCpuTotal        *CPUStat               `protobuf:\"bytes,3,opt,name=cpu_total,json=cpuTotal,proto3\" json:\"cpu_total,omitempty\"`\n\tCpu             []*CPUStat             `protobuf:\"bytes,4,rep,name=cpu,proto3\" json:\"cpu,omitempty\"`\n\tIrqTotal        uint64                 `protobuf:\"varint,5,opt,name=irq_total,json=irqTotal,proto3\" json:\"irq_total,omitempty\"`\n\tIrq             []uint64               `protobuf:\"varint,6,rep,packed,name=irq,proto3\" json:\"irq,omitempty\"`\n\tContextSwitches uint64                 `protobuf:\"varint,7,opt,name=context_switches,json=contextSwitches,proto3\" json:\"context_switches,omitempty\"`\n\tProcessCreated  uint64                 `protobuf:\"varint,8,opt,name=process_created,json=processCreated,proto3\" json:\"process_created,omitempty\"`\n\tProcessRunning  uint64                 `protobuf:\"varint,9,opt,name=process_running,json=processRunning,proto3\" json:\"process_running,omitempty\"`\n\tProcessBlocked  uint64                 `protobuf:\"varint,10,opt,name=process_blocked,json=processBlocked,proto3\" json:\"process_blocked,omitempty\"`\n\tSoftIrqTotal    uint64                 `protobuf:\"varint,11,opt,name=soft_irq_total,json=softIrqTotal,proto3\" json:\"soft_irq_total,omitempty\"`\n\tSoftIrq         *SoftIRQStat           `protobuf:\"bytes,12,opt,name=soft_irq,json=softIrq,proto3\" json:\"soft_irq,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *SystemStat) Reset() {\n\t*x = SystemStat{}\n\tmi := &file_machine_machine_proto_msgTypes[89]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SystemStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemStat) ProtoMessage() {}\n\nfunc (x *SystemStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[89]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemStat.ProtoReflect.Descriptor instead.\nfunc (*SystemStat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{89}\n}\n\nfunc (x *SystemStat) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *SystemStat) GetBootTime() uint64 {\n\tif x != nil {\n\t\treturn x.BootTime\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetCpuTotal() *CPUStat {\n\tif x != nil {\n\t\treturn x.CpuTotal\n\t}\n\treturn nil\n}\n\nfunc (x *SystemStat) GetCpu() []*CPUStat {\n\tif x != nil {\n\t\treturn x.Cpu\n\t}\n\treturn nil\n}\n\nfunc (x *SystemStat) GetIrqTotal() uint64 {\n\tif x != nil {\n\t\treturn x.IrqTotal\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetIrq() []uint64 {\n\tif x != nil {\n\t\treturn x.Irq\n\t}\n\treturn nil\n}\n\nfunc (x *SystemStat) GetContextSwitches() uint64 {\n\tif x != nil {\n\t\treturn x.ContextSwitches\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetProcessCreated() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessCreated\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetProcessRunning() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessRunning\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetProcessBlocked() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessBlocked\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetSoftIrqTotal() uint64 {\n\tif x != nil {\n\t\treturn x.SoftIrqTotal\n\t}\n\treturn 0\n}\n\nfunc (x *SystemStat) GetSoftIrq() *SoftIRQStat {\n\tif x != nil {\n\t\treturn x.SoftIrq\n\t}\n\treturn nil\n}\n\ntype CPUStat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tUser          float64                `protobuf:\"fixed64,1,opt,name=user,proto3\" json:\"user,omitempty\"`\n\tNice          float64                `protobuf:\"fixed64,2,opt,name=nice,proto3\" json:\"nice,omitempty\"`\n\tSystem        float64                `protobuf:\"fixed64,3,opt,name=system,proto3\" json:\"system,omitempty\"`\n\tIdle          float64                `protobuf:\"fixed64,4,opt,name=idle,proto3\" json:\"idle,omitempty\"`\n\tIowait        float64                `protobuf:\"fixed64,5,opt,name=iowait,proto3\" json:\"iowait,omitempty\"`\n\tIrq           float64                `protobuf:\"fixed64,6,opt,name=irq,proto3\" json:\"irq,omitempty\"`\n\tSoftIrq       float64                `protobuf:\"fixed64,7,opt,name=soft_irq,json=softIrq,proto3\" json:\"soft_irq,omitempty\"`\n\tSteal         float64                `protobuf:\"fixed64,8,opt,name=steal,proto3\" json:\"steal,omitempty\"`\n\tGuest         float64                `protobuf:\"fixed64,9,opt,name=guest,proto3\" json:\"guest,omitempty\"`\n\tGuestNice     float64                `protobuf:\"fixed64,10,opt,name=guest_nice,json=guestNice,proto3\" json:\"guest_nice,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUStat) Reset() {\n\t*x = CPUStat{}\n\tmi := &file_machine_machine_proto_msgTypes[90]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUStat) ProtoMessage() {}\n\nfunc (x *CPUStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[90]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUStat.ProtoReflect.Descriptor instead.\nfunc (*CPUStat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{90}\n}\n\nfunc (x *CPUStat) GetUser() float64 {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetNice() float64 {\n\tif x != nil {\n\t\treturn x.Nice\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSystem() float64 {\n\tif x != nil {\n\t\treturn x.System\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIdle() float64 {\n\tif x != nil {\n\t\treturn x.Idle\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIowait() float64 {\n\tif x != nil {\n\t\treturn x.Iowait\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIrq() float64 {\n\tif x != nil {\n\t\treturn x.Irq\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSoftIrq() float64 {\n\tif x != nil {\n\t\treturn x.SoftIrq\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSteal() float64 {\n\tif x != nil {\n\t\treturn x.Steal\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetGuest() float64 {\n\tif x != nil {\n\t\treturn x.Guest\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetGuestNice() float64 {\n\tif x != nil {\n\t\treturn x.GuestNice\n\t}\n\treturn 0\n}\n\ntype SoftIRQStat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHi            uint64                 `protobuf:\"varint,1,opt,name=hi,proto3\" json:\"hi,omitempty\"`\n\tTimer         uint64                 `protobuf:\"varint,2,opt,name=timer,proto3\" json:\"timer,omitempty\"`\n\tNetTx         uint64                 `protobuf:\"varint,3,opt,name=net_tx,json=netTx,proto3\" json:\"net_tx,omitempty\"`\n\tNetRx         uint64                 `protobuf:\"varint,4,opt,name=net_rx,json=netRx,proto3\" json:\"net_rx,omitempty\"`\n\tBlock         uint64                 `protobuf:\"varint,5,opt,name=block,proto3\" json:\"block,omitempty\"`\n\tBlockIoPoll   uint64                 `protobuf:\"varint,6,opt,name=block_io_poll,json=blockIoPoll,proto3\" json:\"block_io_poll,omitempty\"`\n\tTasklet       uint64                 `protobuf:\"varint,7,opt,name=tasklet,proto3\" json:\"tasklet,omitempty\"`\n\tSched         uint64                 `protobuf:\"varint,8,opt,name=sched,proto3\" json:\"sched,omitempty\"`\n\tHrtimer       uint64                 `protobuf:\"varint,9,opt,name=hrtimer,proto3\" json:\"hrtimer,omitempty\"`\n\tRcu           uint64                 `protobuf:\"varint,10,opt,name=rcu,proto3\" json:\"rcu,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SoftIRQStat) Reset() {\n\t*x = SoftIRQStat{}\n\tmi := &file_machine_machine_proto_msgTypes[91]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SoftIRQStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SoftIRQStat) ProtoMessage() {}\n\nfunc (x *SoftIRQStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[91]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SoftIRQStat.ProtoReflect.Descriptor instead.\nfunc (*SoftIRQStat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{91}\n}\n\nfunc (x *SoftIRQStat) GetHi() uint64 {\n\tif x != nil {\n\t\treturn x.Hi\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetTimer() uint64 {\n\tif x != nil {\n\t\treturn x.Timer\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetNetTx() uint64 {\n\tif x != nil {\n\t\treturn x.NetTx\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetNetRx() uint64 {\n\tif x != nil {\n\t\treturn x.NetRx\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetBlock() uint64 {\n\tif x != nil {\n\t\treturn x.Block\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetBlockIoPoll() uint64 {\n\tif x != nil {\n\t\treturn x.BlockIoPoll\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetTasklet() uint64 {\n\tif x != nil {\n\t\treturn x.Tasklet\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetSched() uint64 {\n\tif x != nil {\n\t\treturn x.Sched\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetHrtimer() uint64 {\n\tif x != nil {\n\t\treturn x.Hrtimer\n\t}\n\treturn 0\n}\n\nfunc (x *SoftIRQStat) GetRcu() uint64 {\n\tif x != nil {\n\t\treturn x.Rcu\n\t}\n\treturn 0\n}\n\ntype CPUFreqStatsResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*CPUsFreqStats       `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUFreqStatsResponse) Reset() {\n\t*x = CPUFreqStatsResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[92]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUFreqStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUFreqStatsResponse) ProtoMessage() {}\n\nfunc (x *CPUFreqStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[92]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUFreqStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*CPUFreqStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{92}\n}\n\nfunc (x *CPUFreqStatsResponse) GetMessages() []*CPUsFreqStats {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype CPUsFreqStats struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tCpuFreqStats  []*CPUFreqStats        `protobuf:\"bytes,2,rep,name=cpu_freq_stats,json=cpuFreqStats,proto3\" json:\"cpu_freq_stats,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUsFreqStats) Reset() {\n\t*x = CPUsFreqStats{}\n\tmi := &file_machine_machine_proto_msgTypes[93]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUsFreqStats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUsFreqStats) ProtoMessage() {}\n\nfunc (x *CPUsFreqStats) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[93]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUsFreqStats.ProtoReflect.Descriptor instead.\nfunc (*CPUsFreqStats) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{93}\n}\n\nfunc (x *CPUsFreqStats) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *CPUsFreqStats) GetCpuFreqStats() []*CPUFreqStats {\n\tif x != nil {\n\t\treturn x.CpuFreqStats\n\t}\n\treturn nil\n}\n\ntype CPUFreqStats struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tCurrentFrequency uint64                 `protobuf:\"varint,1,opt,name=current_frequency,json=currentFrequency,proto3\" json:\"current_frequency,omitempty\"`\n\tMinimumFrequency uint64                 `protobuf:\"varint,2,opt,name=minimum_frequency,json=minimumFrequency,proto3\" json:\"minimum_frequency,omitempty\"`\n\tMaximumFrequency uint64                 `protobuf:\"varint,3,opt,name=maximum_frequency,json=maximumFrequency,proto3\" json:\"maximum_frequency,omitempty\"`\n\tGovernor         string                 `protobuf:\"bytes,4,opt,name=governor,proto3\" json:\"governor,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *CPUFreqStats) Reset() {\n\t*x = CPUFreqStats{}\n\tmi := &file_machine_machine_proto_msgTypes[94]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUFreqStats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUFreqStats) ProtoMessage() {}\n\nfunc (x *CPUFreqStats) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[94]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUFreqStats.ProtoReflect.Descriptor instead.\nfunc (*CPUFreqStats) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{94}\n}\n\nfunc (x *CPUFreqStats) GetCurrentFrequency() uint64 {\n\tif x != nil {\n\t\treturn x.CurrentFrequency\n\t}\n\treturn 0\n}\n\nfunc (x *CPUFreqStats) GetMinimumFrequency() uint64 {\n\tif x != nil {\n\t\treturn x.MinimumFrequency\n\t}\n\treturn 0\n}\n\nfunc (x *CPUFreqStats) GetMaximumFrequency() uint64 {\n\tif x != nil {\n\t\treturn x.MaximumFrequency\n\t}\n\treturn 0\n}\n\nfunc (x *CPUFreqStats) GetGovernor() string {\n\tif x != nil {\n\t\treturn x.Governor\n\t}\n\treturn \"\"\n}\n\ntype CPUInfoResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*CPUsInfo            `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUInfoResponse) Reset() {\n\t*x = CPUInfoResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[95]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUInfoResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUInfoResponse) ProtoMessage() {}\n\nfunc (x *CPUInfoResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[95]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUInfoResponse.ProtoReflect.Descriptor instead.\nfunc (*CPUInfoResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{95}\n}\n\nfunc (x *CPUInfoResponse) GetMessages() []*CPUsInfo {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype CPUsInfo struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tCpuInfo       []*CPUInfo             `protobuf:\"bytes,2,rep,name=cpu_info,json=cpuInfo,proto3\" json:\"cpu_info,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUsInfo) Reset() {\n\t*x = CPUsInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[96]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUsInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUsInfo) ProtoMessage() {}\n\nfunc (x *CPUsInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[96]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUsInfo.ProtoReflect.Descriptor instead.\nfunc (*CPUsInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{96}\n}\n\nfunc (x *CPUsInfo) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *CPUsInfo) GetCpuInfo() []*CPUInfo {\n\tif x != nil {\n\t\treturn x.CpuInfo\n\t}\n\treturn nil\n}\n\ntype CPUInfo struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tProcessor       uint32                 `protobuf:\"varint,1,opt,name=processor,proto3\" json:\"processor,omitempty\"`\n\tVendorId        string                 `protobuf:\"bytes,2,opt,name=vendor_id,json=vendorId,proto3\" json:\"vendor_id,omitempty\"`\n\tCpuFamily       string                 `protobuf:\"bytes,3,opt,name=cpu_family,json=cpuFamily,proto3\" json:\"cpu_family,omitempty\"`\n\tModel           string                 `protobuf:\"bytes,4,opt,name=model,proto3\" json:\"model,omitempty\"`\n\tModelName       string                 `protobuf:\"bytes,5,opt,name=model_name,json=modelName,proto3\" json:\"model_name,omitempty\"`\n\tStepping        string                 `protobuf:\"bytes,6,opt,name=stepping,proto3\" json:\"stepping,omitempty\"`\n\tMicrocode       string                 `protobuf:\"bytes,7,opt,name=microcode,proto3\" json:\"microcode,omitempty\"`\n\tCpuMhz          float64                `protobuf:\"fixed64,8,opt,name=cpu_mhz,json=cpuMhz,proto3\" json:\"cpu_mhz,omitempty\"`\n\tCacheSize       string                 `protobuf:\"bytes,9,opt,name=cache_size,json=cacheSize,proto3\" json:\"cache_size,omitempty\"`\n\tPhysicalId      string                 `protobuf:\"bytes,10,opt,name=physical_id,json=physicalId,proto3\" json:\"physical_id,omitempty\"`\n\tSiblings        uint32                 `protobuf:\"varint,11,opt,name=siblings,proto3\" json:\"siblings,omitempty\"`\n\tCoreId          string                 `protobuf:\"bytes,12,opt,name=core_id,json=coreId,proto3\" json:\"core_id,omitempty\"`\n\tCpuCores        uint32                 `protobuf:\"varint,13,opt,name=cpu_cores,json=cpuCores,proto3\" json:\"cpu_cores,omitempty\"`\n\tApicId          string                 `protobuf:\"bytes,14,opt,name=apic_id,json=apicId,proto3\" json:\"apic_id,omitempty\"`\n\tInitialApicId   string                 `protobuf:\"bytes,15,opt,name=initial_apic_id,json=initialApicId,proto3\" json:\"initial_apic_id,omitempty\"`\n\tFpu             string                 `protobuf:\"bytes,16,opt,name=fpu,proto3\" json:\"fpu,omitempty\"`\n\tFpuException    string                 `protobuf:\"bytes,17,opt,name=fpu_exception,json=fpuException,proto3\" json:\"fpu_exception,omitempty\"`\n\tCpuIdLevel      uint32                 `protobuf:\"varint,18,opt,name=cpu_id_level,json=cpuIdLevel,proto3\" json:\"cpu_id_level,omitempty\"`\n\tWp              string                 `protobuf:\"bytes,19,opt,name=wp,proto3\" json:\"wp,omitempty\"`\n\tFlags           []string               `protobuf:\"bytes,20,rep,name=flags,proto3\" json:\"flags,omitempty\"`\n\tBugs            []string               `protobuf:\"bytes,21,rep,name=bugs,proto3\" json:\"bugs,omitempty\"`\n\tBogoMips        float64                `protobuf:\"fixed64,22,opt,name=bogo_mips,json=bogoMips,proto3\" json:\"bogo_mips,omitempty\"`\n\tClFlushSize     uint32                 `protobuf:\"varint,23,opt,name=cl_flush_size,json=clFlushSize,proto3\" json:\"cl_flush_size,omitempty\"`\n\tCacheAlignment  uint32                 `protobuf:\"varint,24,opt,name=cache_alignment,json=cacheAlignment,proto3\" json:\"cache_alignment,omitempty\"`\n\tAddressSizes    string                 `protobuf:\"bytes,25,opt,name=address_sizes,json=addressSizes,proto3\" json:\"address_sizes,omitempty\"`\n\tPowerManagement string                 `protobuf:\"bytes,26,opt,name=power_management,json=powerManagement,proto3\" json:\"power_management,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *CPUInfo) Reset() {\n\t*x = CPUInfo{}\n\tmi := &file_machine_machine_proto_msgTypes[97]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUInfo) ProtoMessage() {}\n\nfunc (x *CPUInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[97]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUInfo.ProtoReflect.Descriptor instead.\nfunc (*CPUInfo) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{97}\n}\n\nfunc (x *CPUInfo) GetProcessor() uint32 {\n\tif x != nil {\n\t\treturn x.Processor\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetVendorId() string {\n\tif x != nil {\n\t\treturn x.VendorId\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetCpuFamily() string {\n\tif x != nil {\n\t\treturn x.CpuFamily\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetModel() string {\n\tif x != nil {\n\t\treturn x.Model\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetModelName() string {\n\tif x != nil {\n\t\treturn x.ModelName\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetStepping() string {\n\tif x != nil {\n\t\treturn x.Stepping\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetMicrocode() string {\n\tif x != nil {\n\t\treturn x.Microcode\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetCpuMhz() float64 {\n\tif x != nil {\n\t\treturn x.CpuMhz\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetCacheSize() string {\n\tif x != nil {\n\t\treturn x.CacheSize\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetPhysicalId() string {\n\tif x != nil {\n\t\treturn x.PhysicalId\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetSiblings() uint32 {\n\tif x != nil {\n\t\treturn x.Siblings\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetCoreId() string {\n\tif x != nil {\n\t\treturn x.CoreId\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetCpuCores() uint32 {\n\tif x != nil {\n\t\treturn x.CpuCores\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetApicId() string {\n\tif x != nil {\n\t\treturn x.ApicId\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetInitialApicId() string {\n\tif x != nil {\n\t\treturn x.InitialApicId\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetFpu() string {\n\tif x != nil {\n\t\treturn x.Fpu\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetFpuException() string {\n\tif x != nil {\n\t\treturn x.FpuException\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetCpuIdLevel() uint32 {\n\tif x != nil {\n\t\treturn x.CpuIdLevel\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetWp() string {\n\tif x != nil {\n\t\treturn x.Wp\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetFlags() []string {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn nil\n}\n\nfunc (x *CPUInfo) GetBugs() []string {\n\tif x != nil {\n\t\treturn x.Bugs\n\t}\n\treturn nil\n}\n\nfunc (x *CPUInfo) GetBogoMips() float64 {\n\tif x != nil {\n\t\treturn x.BogoMips\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetClFlushSize() uint32 {\n\tif x != nil {\n\t\treturn x.ClFlushSize\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetCacheAlignment() uint32 {\n\tif x != nil {\n\t\treturn x.CacheAlignment\n\t}\n\treturn 0\n}\n\nfunc (x *CPUInfo) GetAddressSizes() string {\n\tif x != nil {\n\t\treturn x.AddressSizes\n\t}\n\treturn \"\"\n}\n\nfunc (x *CPUInfo) GetPowerManagement() string {\n\tif x != nil {\n\t\treturn x.PowerManagement\n\t}\n\treturn \"\"\n}\n\ntype NetworkDeviceStatsResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*NetworkDeviceStats  `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetworkDeviceStatsResponse) Reset() {\n\t*x = NetworkDeviceStatsResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[98]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetworkDeviceStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetworkDeviceStatsResponse) ProtoMessage() {}\n\nfunc (x *NetworkDeviceStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[98]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetworkDeviceStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*NetworkDeviceStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{98}\n}\n\nfunc (x *NetworkDeviceStatsResponse) GetMessages() []*NetworkDeviceStats {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype NetworkDeviceStats struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tTotal         *NetDev                `protobuf:\"bytes,2,opt,name=total,proto3\" json:\"total,omitempty\"`\n\tDevices       []*NetDev              `protobuf:\"bytes,3,rep,name=devices,proto3\" json:\"devices,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetworkDeviceStats) Reset() {\n\t*x = NetworkDeviceStats{}\n\tmi := &file_machine_machine_proto_msgTypes[99]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetworkDeviceStats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetworkDeviceStats) ProtoMessage() {}\n\nfunc (x *NetworkDeviceStats) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[99]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetworkDeviceStats.ProtoReflect.Descriptor instead.\nfunc (*NetworkDeviceStats) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{99}\n}\n\nfunc (x *NetworkDeviceStats) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *NetworkDeviceStats) GetTotal() *NetDev {\n\tif x != nil {\n\t\treturn x.Total\n\t}\n\treturn nil\n}\n\nfunc (x *NetworkDeviceStats) GetDevices() []*NetDev {\n\tif x != nil {\n\t\treturn x.Devices\n\t}\n\treturn nil\n}\n\ntype NetDev struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tRxBytes       uint64                 `protobuf:\"varint,2,opt,name=rx_bytes,json=rxBytes,proto3\" json:\"rx_bytes,omitempty\"`\n\tRxPackets     uint64                 `protobuf:\"varint,3,opt,name=rx_packets,json=rxPackets,proto3\" json:\"rx_packets,omitempty\"`\n\tRxErrors      uint64                 `protobuf:\"varint,4,opt,name=rx_errors,json=rxErrors,proto3\" json:\"rx_errors,omitempty\"`\n\tRxDropped     uint64                 `protobuf:\"varint,5,opt,name=rx_dropped,json=rxDropped,proto3\" json:\"rx_dropped,omitempty\"`\n\tRxFifo        uint64                 `protobuf:\"varint,6,opt,name=rx_fifo,json=rxFifo,proto3\" json:\"rx_fifo,omitempty\"`\n\tRxFrame       uint64                 `protobuf:\"varint,7,opt,name=rx_frame,json=rxFrame,proto3\" json:\"rx_frame,omitempty\"`\n\tRxCompressed  uint64                 `protobuf:\"varint,8,opt,name=rx_compressed,json=rxCompressed,proto3\" json:\"rx_compressed,omitempty\"`\n\tRxMulticast   uint64                 `protobuf:\"varint,9,opt,name=rx_multicast,json=rxMulticast,proto3\" json:\"rx_multicast,omitempty\"`\n\tTxBytes       uint64                 `protobuf:\"varint,10,opt,name=tx_bytes,json=txBytes,proto3\" json:\"tx_bytes,omitempty\"`\n\tTxPackets     uint64                 `protobuf:\"varint,11,opt,name=tx_packets,json=txPackets,proto3\" json:\"tx_packets,omitempty\"`\n\tTxErrors      uint64                 `protobuf:\"varint,12,opt,name=tx_errors,json=txErrors,proto3\" json:\"tx_errors,omitempty\"`\n\tTxDropped     uint64                 `protobuf:\"varint,13,opt,name=tx_dropped,json=txDropped,proto3\" json:\"tx_dropped,omitempty\"`\n\tTxFifo        uint64                 `protobuf:\"varint,14,opt,name=tx_fifo,json=txFifo,proto3\" json:\"tx_fifo,omitempty\"`\n\tTxCollisions  uint64                 `protobuf:\"varint,15,opt,name=tx_collisions,json=txCollisions,proto3\" json:\"tx_collisions,omitempty\"`\n\tTxCarrier     uint64                 `protobuf:\"varint,16,opt,name=tx_carrier,json=txCarrier,proto3\" json:\"tx_carrier,omitempty\"`\n\tTxCompressed  uint64                 `protobuf:\"varint,17,opt,name=tx_compressed,json=txCompressed,proto3\" json:\"tx_compressed,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetDev) Reset() {\n\t*x = NetDev{}\n\tmi := &file_machine_machine_proto_msgTypes[100]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetDev) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetDev) ProtoMessage() {}\n\nfunc (x *NetDev) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[100]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetDev.ProtoReflect.Descriptor instead.\nfunc (*NetDev) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{100}\n}\n\nfunc (x *NetDev) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *NetDev) GetRxBytes() uint64 {\n\tif x != nil {\n\t\treturn x.RxBytes\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxPackets() uint64 {\n\tif x != nil {\n\t\treturn x.RxPackets\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxErrors() uint64 {\n\tif x != nil {\n\t\treturn x.RxErrors\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxDropped() uint64 {\n\tif x != nil {\n\t\treturn x.RxDropped\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxFifo() uint64 {\n\tif x != nil {\n\t\treturn x.RxFifo\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxFrame() uint64 {\n\tif x != nil {\n\t\treturn x.RxFrame\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxCompressed() uint64 {\n\tif x != nil {\n\t\treturn x.RxCompressed\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetRxMulticast() uint64 {\n\tif x != nil {\n\t\treturn x.RxMulticast\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxBytes() uint64 {\n\tif x != nil {\n\t\treturn x.TxBytes\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxPackets() uint64 {\n\tif x != nil {\n\t\treturn x.TxPackets\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxErrors() uint64 {\n\tif x != nil {\n\t\treturn x.TxErrors\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxDropped() uint64 {\n\tif x != nil {\n\t\treturn x.TxDropped\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxFifo() uint64 {\n\tif x != nil {\n\t\treturn x.TxFifo\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxCollisions() uint64 {\n\tif x != nil {\n\t\treturn x.TxCollisions\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxCarrier() uint64 {\n\tif x != nil {\n\t\treturn x.TxCarrier\n\t}\n\treturn 0\n}\n\nfunc (x *NetDev) GetTxCompressed() uint64 {\n\tif x != nil {\n\t\treturn x.TxCompressed\n\t}\n\treturn 0\n}\n\ntype DiskStatsResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*DiskStats           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiskStatsResponse) Reset() {\n\t*x = DiskStatsResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[101]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskStatsResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskStatsResponse) ProtoMessage() {}\n\nfunc (x *DiskStatsResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[101]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskStatsResponse.ProtoReflect.Descriptor instead.\nfunc (*DiskStatsResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{101}\n}\n\nfunc (x *DiskStatsResponse) GetMessages() []*DiskStats {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype DiskStats struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tTotal         *DiskStat              `protobuf:\"bytes,2,opt,name=total,proto3\" json:\"total,omitempty\"`\n\tDevices       []*DiskStat            `protobuf:\"bytes,3,rep,name=devices,proto3\" json:\"devices,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiskStats) Reset() {\n\t*x = DiskStats{}\n\tmi := &file_machine_machine_proto_msgTypes[102]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskStats) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskStats) ProtoMessage() {}\n\nfunc (x *DiskStats) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[102]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskStats.ProtoReflect.Descriptor instead.\nfunc (*DiskStats) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{102}\n}\n\nfunc (x *DiskStats) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *DiskStats) GetTotal() *DiskStat {\n\tif x != nil {\n\t\treturn x.Total\n\t}\n\treturn nil\n}\n\nfunc (x *DiskStats) GetDevices() []*DiskStat {\n\tif x != nil {\n\t\treturn x.Devices\n\t}\n\treturn nil\n}\n\ntype DiskStat struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tName             string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tReadCompleted    uint64                 `protobuf:\"varint,2,opt,name=read_completed,json=readCompleted,proto3\" json:\"read_completed,omitempty\"`\n\tReadMerged       uint64                 `protobuf:\"varint,3,opt,name=read_merged,json=readMerged,proto3\" json:\"read_merged,omitempty\"`\n\tReadSectors      uint64                 `protobuf:\"varint,4,opt,name=read_sectors,json=readSectors,proto3\" json:\"read_sectors,omitempty\"`\n\tReadTimeMs       uint64                 `protobuf:\"varint,5,opt,name=read_time_ms,json=readTimeMs,proto3\" json:\"read_time_ms,omitempty\"`\n\tWriteCompleted   uint64                 `protobuf:\"varint,6,opt,name=write_completed,json=writeCompleted,proto3\" json:\"write_completed,omitempty\"`\n\tWriteMerged      uint64                 `protobuf:\"varint,7,opt,name=write_merged,json=writeMerged,proto3\" json:\"write_merged,omitempty\"`\n\tWriteSectors     uint64                 `protobuf:\"varint,8,opt,name=write_sectors,json=writeSectors,proto3\" json:\"write_sectors,omitempty\"`\n\tWriteTimeMs      uint64                 `protobuf:\"varint,9,opt,name=write_time_ms,json=writeTimeMs,proto3\" json:\"write_time_ms,omitempty\"`\n\tIoInProgress     uint64                 `protobuf:\"varint,10,opt,name=io_in_progress,json=ioInProgress,proto3\" json:\"io_in_progress,omitempty\"`\n\tIoTimeMs         uint64                 `protobuf:\"varint,11,opt,name=io_time_ms,json=ioTimeMs,proto3\" json:\"io_time_ms,omitempty\"`\n\tIoTimeWeightedMs uint64                 `protobuf:\"varint,12,opt,name=io_time_weighted_ms,json=ioTimeWeightedMs,proto3\" json:\"io_time_weighted_ms,omitempty\"`\n\tDiscardCompleted uint64                 `protobuf:\"varint,13,opt,name=discard_completed,json=discardCompleted,proto3\" json:\"discard_completed,omitempty\"`\n\tDiscardMerged    uint64                 `protobuf:\"varint,14,opt,name=discard_merged,json=discardMerged,proto3\" json:\"discard_merged,omitempty\"`\n\tDiscardSectors   uint64                 `protobuf:\"varint,15,opt,name=discard_sectors,json=discardSectors,proto3\" json:\"discard_sectors,omitempty\"`\n\tDiscardTimeMs    uint64                 `protobuf:\"varint,16,opt,name=discard_time_ms,json=discardTimeMs,proto3\" json:\"discard_time_ms,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *DiskStat) Reset() {\n\t*x = DiskStat{}\n\tmi := &file_machine_machine_proto_msgTypes[103]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskStat) ProtoMessage() {}\n\nfunc (x *DiskStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[103]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskStat.ProtoReflect.Descriptor instead.\nfunc (*DiskStat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{103}\n}\n\nfunc (x *DiskStat) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskStat) GetReadCompleted() uint64 {\n\tif x != nil {\n\t\treturn x.ReadCompleted\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetReadMerged() uint64 {\n\tif x != nil {\n\t\treturn x.ReadMerged\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetReadSectors() uint64 {\n\tif x != nil {\n\t\treturn x.ReadSectors\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetReadTimeMs() uint64 {\n\tif x != nil {\n\t\treturn x.ReadTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetWriteCompleted() uint64 {\n\tif x != nil {\n\t\treturn x.WriteCompleted\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetWriteMerged() uint64 {\n\tif x != nil {\n\t\treturn x.WriteMerged\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetWriteSectors() uint64 {\n\tif x != nil {\n\t\treturn x.WriteSectors\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetWriteTimeMs() uint64 {\n\tif x != nil {\n\t\treturn x.WriteTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetIoInProgress() uint64 {\n\tif x != nil {\n\t\treturn x.IoInProgress\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetIoTimeMs() uint64 {\n\tif x != nil {\n\t\treturn x.IoTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetIoTimeWeightedMs() uint64 {\n\tif x != nil {\n\t\treturn x.IoTimeWeightedMs\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetDiscardCompleted() uint64 {\n\tif x != nil {\n\t\treturn x.DiscardCompleted\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetDiscardMerged() uint64 {\n\tif x != nil {\n\t\treturn x.DiscardMerged\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetDiscardSectors() uint64 {\n\tif x != nil {\n\t\treturn x.DiscardSectors\n\t}\n\treturn 0\n}\n\nfunc (x *DiskStat) GetDiscardTimeMs() uint64 {\n\tif x != nil {\n\t\treturn x.DiscardTimeMs\n\t}\n\treturn 0\n}\n\ntype EtcdLeaveClusterRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdLeaveClusterRequest) Reset() {\n\t*x = EtcdLeaveClusterRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[104]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdLeaveClusterRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdLeaveClusterRequest) ProtoMessage() {}\n\nfunc (x *EtcdLeaveClusterRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[104]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdLeaveClusterRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdLeaveClusterRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{104}\n}\n\ntype EtcdLeaveCluster struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdLeaveCluster) Reset() {\n\t*x = EtcdLeaveCluster{}\n\tmi := &file_machine_machine_proto_msgTypes[105]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdLeaveCluster) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdLeaveCluster) ProtoMessage() {}\n\nfunc (x *EtcdLeaveCluster) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[105]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdLeaveCluster.ProtoReflect.Descriptor instead.\nfunc (*EtcdLeaveCluster) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{105}\n}\n\nfunc (x *EtcdLeaveCluster) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EtcdLeaveClusterResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdLeaveCluster    `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdLeaveClusterResponse) Reset() {\n\t*x = EtcdLeaveClusterResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[106]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdLeaveClusterResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdLeaveClusterResponse) ProtoMessage() {}\n\nfunc (x *EtcdLeaveClusterResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[106]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdLeaveClusterResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdLeaveClusterResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{106}\n}\n\nfunc (x *EtcdLeaveClusterResponse) GetMessages() []*EtcdLeaveCluster {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdRemoveMemberRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMember        string                 `protobuf:\"bytes,1,opt,name=member,proto3\" json:\"member,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMemberRequest) Reset() {\n\t*x = EtcdRemoveMemberRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[107]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMemberRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMemberRequest) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMemberRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[107]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMemberRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMemberRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{107}\n}\n\nfunc (x *EtcdRemoveMemberRequest) GetMember() string {\n\tif x != nil {\n\t\treturn x.Member\n\t}\n\treturn \"\"\n}\n\ntype EtcdRemoveMember struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMember) Reset() {\n\t*x = EtcdRemoveMember{}\n\tmi := &file_machine_machine_proto_msgTypes[108]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMember) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMember) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMember) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[108]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMember.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMember) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{108}\n}\n\nfunc (x *EtcdRemoveMember) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EtcdRemoveMemberResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdRemoveMember    `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMemberResponse) Reset() {\n\t*x = EtcdRemoveMemberResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[109]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMemberResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMemberResponse) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMemberResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[109]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMemberResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMemberResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{109}\n}\n\nfunc (x *EtcdRemoveMemberResponse) GetMessages() []*EtcdRemoveMember {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdRemoveMemberByIDRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMemberId      uint64                 `protobuf:\"varint,1,opt,name=member_id,json=memberId,proto3\" json:\"member_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMemberByIDRequest) Reset() {\n\t*x = EtcdRemoveMemberByIDRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[110]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMemberByIDRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMemberByIDRequest) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMemberByIDRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[110]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMemberByIDRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMemberByIDRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{110}\n}\n\nfunc (x *EtcdRemoveMemberByIDRequest) GetMemberId() uint64 {\n\tif x != nil {\n\t\treturn x.MemberId\n\t}\n\treturn 0\n}\n\ntype EtcdRemoveMemberByID struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMemberByID) Reset() {\n\t*x = EtcdRemoveMemberByID{}\n\tmi := &file_machine_machine_proto_msgTypes[111]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMemberByID) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMemberByID) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMemberByID) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[111]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMemberByID.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMemberByID) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{111}\n}\n\nfunc (x *EtcdRemoveMemberByID) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EtcdRemoveMemberByIDResponse struct {\n\tstate         protoimpl.MessageState  `protogen:\"open.v1\"`\n\tMessages      []*EtcdRemoveMemberByID `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRemoveMemberByIDResponse) Reset() {\n\t*x = EtcdRemoveMemberByIDResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[112]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRemoveMemberByIDResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRemoveMemberByIDResponse) ProtoMessage() {}\n\nfunc (x *EtcdRemoveMemberByIDResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[112]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRemoveMemberByIDResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdRemoveMemberByIDResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{112}\n}\n\nfunc (x *EtcdRemoveMemberByIDResponse) GetMessages() []*EtcdRemoveMemberByID {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdForfeitLeadershipRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdForfeitLeadershipRequest) Reset() {\n\t*x = EtcdForfeitLeadershipRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[113]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdForfeitLeadershipRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdForfeitLeadershipRequest) ProtoMessage() {}\n\nfunc (x *EtcdForfeitLeadershipRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[113]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdForfeitLeadershipRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdForfeitLeadershipRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{113}\n}\n\ntype EtcdForfeitLeadership struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMember        string                 `protobuf:\"bytes,2,opt,name=member,proto3\" json:\"member,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdForfeitLeadership) Reset() {\n\t*x = EtcdForfeitLeadership{}\n\tmi := &file_machine_machine_proto_msgTypes[114]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdForfeitLeadership) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdForfeitLeadership) ProtoMessage() {}\n\nfunc (x *EtcdForfeitLeadership) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[114]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdForfeitLeadership.ProtoReflect.Descriptor instead.\nfunc (*EtcdForfeitLeadership) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{114}\n}\n\nfunc (x *EtcdForfeitLeadership) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdForfeitLeadership) GetMember() string {\n\tif x != nil {\n\t\treturn x.Member\n\t}\n\treturn \"\"\n}\n\ntype EtcdForfeitLeadershipResponse struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tMessages      []*EtcdForfeitLeadership `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdForfeitLeadershipResponse) Reset() {\n\t*x = EtcdForfeitLeadershipResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[115]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdForfeitLeadershipResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdForfeitLeadershipResponse) ProtoMessage() {}\n\nfunc (x *EtcdForfeitLeadershipResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[115]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdForfeitLeadershipResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdForfeitLeadershipResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{115}\n}\n\nfunc (x *EtcdForfeitLeadershipResponse) GetMessages() []*EtcdForfeitLeadership {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdMemberListRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tQueryLocal    bool                   `protobuf:\"varint,1,opt,name=query_local,json=queryLocal,proto3\" json:\"query_local,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdMemberListRequest) Reset() {\n\t*x = EtcdMemberListRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[116]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMemberListRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMemberListRequest) ProtoMessage() {}\n\nfunc (x *EtcdMemberListRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[116]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMemberListRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdMemberListRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{116}\n}\n\nfunc (x *EtcdMemberListRequest) GetQueryLocal() bool {\n\tif x != nil {\n\t\treturn x.QueryLocal\n\t}\n\treturn false\n}\n\n// EtcdMember describes a single etcd member.\ntype EtcdMember struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// member ID.\n\tId uint64 `protobuf:\"varint,2,opt,name=id,proto3\" json:\"id,omitempty\"`\n\t// human-readable name of the member.\n\tHostname string `protobuf:\"bytes,3,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\t// the list of URLs the member exposes to clients for communication.\n\tPeerUrls []string `protobuf:\"bytes,4,rep,name=peer_urls,json=peerUrls,proto3\" json:\"peer_urls,omitempty\"`\n\t// the list of URLs the member exposes to the cluster for communication.\n\tClientUrls []string `protobuf:\"bytes,5,rep,name=client_urls,json=clientUrls,proto3\" json:\"client_urls,omitempty\"`\n\t// learner flag\n\tIsLearner     bool `protobuf:\"varint,6,opt,name=is_learner,json=isLearner,proto3\" json:\"is_learner,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdMember) Reset() {\n\t*x = EtcdMember{}\n\tmi := &file_machine_machine_proto_msgTypes[117]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMember) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMember) ProtoMessage() {}\n\nfunc (x *EtcdMember) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[117]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMember.ProtoReflect.Descriptor instead.\nfunc (*EtcdMember) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{117}\n}\n\nfunc (x *EtcdMember) GetId() uint64 {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMember) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *EtcdMember) GetPeerUrls() []string {\n\tif x != nil {\n\t\treturn x.PeerUrls\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdMember) GetClientUrls() []string {\n\tif x != nil {\n\t\treturn x.ClientUrls\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdMember) GetIsLearner() bool {\n\tif x != nil {\n\t\treturn x.IsLearner\n\t}\n\treturn false\n}\n\n// EtcdMembers contains the list of members registered on the host.\ntype EtcdMembers struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\t// list of member hostnames.\n\tLegacyMembers []string `protobuf:\"bytes,2,rep,name=legacy_members,json=legacyMembers,proto3\" json:\"legacy_members,omitempty\"`\n\t// the list of etcd members registered on the node.\n\tMembers       []*EtcdMember `protobuf:\"bytes,3,rep,name=members,proto3\" json:\"members,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdMembers) Reset() {\n\t*x = EtcdMembers{}\n\tmi := &file_machine_machine_proto_msgTypes[118]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMembers) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMembers) ProtoMessage() {}\n\nfunc (x *EtcdMembers) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[118]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMembers.ProtoReflect.Descriptor instead.\nfunc (*EtcdMembers) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{118}\n}\n\nfunc (x *EtcdMembers) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdMembers) GetLegacyMembers() []string {\n\tif x != nil {\n\t\treturn x.LegacyMembers\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdMembers) GetMembers() []*EtcdMember {\n\tif x != nil {\n\t\treturn x.Members\n\t}\n\treturn nil\n}\n\ntype EtcdMemberListResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdMembers         `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdMemberListResponse) Reset() {\n\t*x = EtcdMemberListResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[119]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMemberListResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMemberListResponse) ProtoMessage() {}\n\nfunc (x *EtcdMemberListResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[119]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMemberListResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdMemberListResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{119}\n}\n\nfunc (x *EtcdMemberListResponse) GetMessages() []*EtcdMembers {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdSnapshotRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdSnapshotRequest) Reset() {\n\t*x = EtcdSnapshotRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[120]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdSnapshotRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdSnapshotRequest) ProtoMessage() {}\n\nfunc (x *EtcdSnapshotRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[120]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdSnapshotRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdSnapshotRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{120}\n}\n\ntype EtcdRecover struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRecover) Reset() {\n\t*x = EtcdRecover{}\n\tmi := &file_machine_machine_proto_msgTypes[121]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRecover) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRecover) ProtoMessage() {}\n\nfunc (x *EtcdRecover) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[121]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRecover.ProtoReflect.Descriptor instead.\nfunc (*EtcdRecover) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{121}\n}\n\nfunc (x *EtcdRecover) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EtcdRecoverResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdRecover         `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRecoverResponse) Reset() {\n\t*x = EtcdRecoverResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[122]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRecoverResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRecoverResponse) ProtoMessage() {}\n\nfunc (x *EtcdRecoverResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[122]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRecoverResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdRecoverResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{122}\n}\n\nfunc (x *EtcdRecoverResponse) GetMessages() []*EtcdRecover {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdAlarmListResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdAlarm           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdAlarmListResponse) Reset() {\n\t*x = EtcdAlarmListResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[123]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdAlarmListResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdAlarmListResponse) ProtoMessage() {}\n\nfunc (x *EtcdAlarmListResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[123]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdAlarmListResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdAlarmListResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{123}\n}\n\nfunc (x *EtcdAlarmListResponse) GetMessages() []*EtcdAlarm {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdAlarm struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMemberAlarms  []*EtcdMemberAlarm     `protobuf:\"bytes,2,rep,name=member_alarms,json=memberAlarms,proto3\" json:\"member_alarms,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdAlarm) Reset() {\n\t*x = EtcdAlarm{}\n\tmi := &file_machine_machine_proto_msgTypes[124]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdAlarm) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdAlarm) ProtoMessage() {}\n\nfunc (x *EtcdAlarm) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[124]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdAlarm.ProtoReflect.Descriptor instead.\nfunc (*EtcdAlarm) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{124}\n}\n\nfunc (x *EtcdAlarm) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdAlarm) GetMemberAlarms() []*EtcdMemberAlarm {\n\tif x != nil {\n\t\treturn x.MemberAlarms\n\t}\n\treturn nil\n}\n\ntype EtcdMemberAlarm struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tMemberId      uint64                    `protobuf:\"varint,1,opt,name=member_id,json=memberId,proto3\" json:\"member_id,omitempty\"`\n\tAlarm         EtcdMemberAlarm_AlarmType `protobuf:\"varint,2,opt,name=alarm,proto3,enum=machine.EtcdMemberAlarm_AlarmType\" json:\"alarm,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdMemberAlarm) Reset() {\n\t*x = EtcdMemberAlarm{}\n\tmi := &file_machine_machine_proto_msgTypes[125]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMemberAlarm) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMemberAlarm) ProtoMessage() {}\n\nfunc (x *EtcdMemberAlarm) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[125]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMemberAlarm.ProtoReflect.Descriptor instead.\nfunc (*EtcdMemberAlarm) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{125}\n}\n\nfunc (x *EtcdMemberAlarm) GetMemberId() uint64 {\n\tif x != nil {\n\t\treturn x.MemberId\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberAlarm) GetAlarm() EtcdMemberAlarm_AlarmType {\n\tif x != nil {\n\t\treturn x.Alarm\n\t}\n\treturn EtcdMemberAlarm_NONE\n}\n\ntype EtcdAlarmDisarmResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdAlarmDisarm     `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdAlarmDisarmResponse) Reset() {\n\t*x = EtcdAlarmDisarmResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[126]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdAlarmDisarmResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdAlarmDisarmResponse) ProtoMessage() {}\n\nfunc (x *EtcdAlarmDisarmResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[126]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdAlarmDisarmResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdAlarmDisarmResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{126}\n}\n\nfunc (x *EtcdAlarmDisarmResponse) GetMessages() []*EtcdAlarmDisarm {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdAlarmDisarm struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMemberAlarms  []*EtcdMemberAlarm     `protobuf:\"bytes,2,rep,name=member_alarms,json=memberAlarms,proto3\" json:\"member_alarms,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdAlarmDisarm) Reset() {\n\t*x = EtcdAlarmDisarm{}\n\tmi := &file_machine_machine_proto_msgTypes[127]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdAlarmDisarm) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdAlarmDisarm) ProtoMessage() {}\n\nfunc (x *EtcdAlarmDisarm) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[127]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdAlarmDisarm.ProtoReflect.Descriptor instead.\nfunc (*EtcdAlarmDisarm) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{127}\n}\n\nfunc (x *EtcdAlarmDisarm) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdAlarmDisarm) GetMemberAlarms() []*EtcdMemberAlarm {\n\tif x != nil {\n\t\treturn x.MemberAlarms\n\t}\n\treturn nil\n}\n\ntype EtcdDefragmentResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdDefragment      `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDefragmentResponse) Reset() {\n\t*x = EtcdDefragmentResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[128]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDefragmentResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDefragmentResponse) ProtoMessage() {}\n\nfunc (x *EtcdDefragmentResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[128]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDefragmentResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdDefragmentResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{128}\n}\n\nfunc (x *EtcdDefragmentResponse) GetMessages() []*EtcdDefragment {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdDefragment struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDefragment) Reset() {\n\t*x = EtcdDefragment{}\n\tmi := &file_machine_machine_proto_msgTypes[129]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDefragment) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDefragment) ProtoMessage() {}\n\nfunc (x *EtcdDefragment) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[129]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDefragment.ProtoReflect.Descriptor instead.\nfunc (*EtcdDefragment) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{129}\n}\n\nfunc (x *EtcdDefragment) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype EtcdStatusResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdStatus          `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdStatusResponse) Reset() {\n\t*x = EtcdStatusResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[130]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdStatusResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdStatusResponse) ProtoMessage() {}\n\nfunc (x *EtcdStatusResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[130]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdStatusResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdStatusResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{130}\n}\n\nfunc (x *EtcdStatusResponse) GetMessages() []*EtcdStatus {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdStatus struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tMemberStatus  *EtcdMemberStatus      `protobuf:\"bytes,2,opt,name=member_status,json=memberStatus,proto3\" json:\"member_status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdStatus) Reset() {\n\t*x = EtcdStatus{}\n\tmi := &file_machine_machine_proto_msgTypes[131]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdStatus) ProtoMessage() {}\n\nfunc (x *EtcdStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[131]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdStatus.ProtoReflect.Descriptor instead.\nfunc (*EtcdStatus) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{131}\n}\n\nfunc (x *EtcdStatus) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdStatus) GetMemberStatus() *EtcdMemberStatus {\n\tif x != nil {\n\t\treturn x.MemberStatus\n\t}\n\treturn nil\n}\n\ntype EtcdMemberStatus struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tStorageVersion   string                 `protobuf:\"bytes,11,opt,name=storage_version,json=storageVersion,proto3\" json:\"storage_version,omitempty\"`\n\tMemberId         uint64                 `protobuf:\"varint,10,opt,name=member_id,json=memberId,proto3\" json:\"member_id,omitempty\"`\n\tProtocolVersion  string                 `protobuf:\"bytes,1,opt,name=protocol_version,json=protocolVersion,proto3\" json:\"protocol_version,omitempty\"`\n\tDbSize           int64                  `protobuf:\"varint,2,opt,name=db_size,json=dbSize,proto3\" json:\"db_size,omitempty\"`\n\tDbSizeInUse      int64                  `protobuf:\"varint,3,opt,name=db_size_in_use,json=dbSizeInUse,proto3\" json:\"db_size_in_use,omitempty\"`\n\tLeader           uint64                 `protobuf:\"varint,4,opt,name=leader,proto3\" json:\"leader,omitempty\"`\n\tRaftIndex        uint64                 `protobuf:\"varint,5,opt,name=raft_index,json=raftIndex,proto3\" json:\"raft_index,omitempty\"`\n\tRaftTerm         uint64                 `protobuf:\"varint,6,opt,name=raft_term,json=raftTerm,proto3\" json:\"raft_term,omitempty\"`\n\tRaftAppliedIndex uint64                 `protobuf:\"varint,7,opt,name=raft_applied_index,json=raftAppliedIndex,proto3\" json:\"raft_applied_index,omitempty\"`\n\tErrors           []string               `protobuf:\"bytes,8,rep,name=errors,proto3\" json:\"errors,omitempty\"`\n\tIsLearner        bool                   `protobuf:\"varint,9,opt,name=is_learner,json=isLearner,proto3\" json:\"is_learner,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *EtcdMemberStatus) Reset() {\n\t*x = EtcdMemberStatus{}\n\tmi := &file_machine_machine_proto_msgTypes[132]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdMemberStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdMemberStatus) ProtoMessage() {}\n\nfunc (x *EtcdMemberStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[132]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdMemberStatus.ProtoReflect.Descriptor instead.\nfunc (*EtcdMemberStatus) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{132}\n}\n\nfunc (x *EtcdMemberStatus) GetStorageVersion() string {\n\tif x != nil {\n\t\treturn x.StorageVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *EtcdMemberStatus) GetMemberId() uint64 {\n\tif x != nil {\n\t\treturn x.MemberId\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetProtocolVersion() string {\n\tif x != nil {\n\t\treturn x.ProtocolVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *EtcdMemberStatus) GetDbSize() int64 {\n\tif x != nil {\n\t\treturn x.DbSize\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetDbSizeInUse() int64 {\n\tif x != nil {\n\t\treturn x.DbSizeInUse\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetLeader() uint64 {\n\tif x != nil {\n\t\treturn x.Leader\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetRaftIndex() uint64 {\n\tif x != nil {\n\t\treturn x.RaftIndex\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetRaftTerm() uint64 {\n\tif x != nil {\n\t\treturn x.RaftTerm\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetRaftAppliedIndex() uint64 {\n\tif x != nil {\n\t\treturn x.RaftAppliedIndex\n\t}\n\treturn 0\n}\n\nfunc (x *EtcdMemberStatus) GetErrors() []string {\n\tif x != nil {\n\t\treturn x.Errors\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdMemberStatus) GetIsLearner() bool {\n\tif x != nil {\n\t\treturn x.IsLearner\n\t}\n\treturn false\n}\n\ntype EtcdDowngradeValidateRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tVersion       string                 `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeValidateRequest) Reset() {\n\t*x = EtcdDowngradeValidateRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[133]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeValidateRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeValidateRequest) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeValidateRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[133]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeValidateRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeValidateRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{133}\n}\n\nfunc (x *EtcdDowngradeValidateRequest) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\ntype EtcdDowngradeValidateResponse struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tMessages      []*EtcdDowngradeValidate `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeValidateResponse) Reset() {\n\t*x = EtcdDowngradeValidateResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[134]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeValidateResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeValidateResponse) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeValidateResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[134]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeValidateResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeValidateResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{134}\n}\n\nfunc (x *EtcdDowngradeValidateResponse) GetMessages() []*EtcdDowngradeValidate {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdDowngradeValidate struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata         *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tClusterDowngrade *EtcdClusterDowngrade  `protobuf:\"bytes,2,opt,name=cluster_downgrade,json=clusterDowngrade,proto3\" json:\"cluster_downgrade,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeValidate) Reset() {\n\t*x = EtcdDowngradeValidate{}\n\tmi := &file_machine_machine_proto_msgTypes[135]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeValidate) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeValidate) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeValidate) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[135]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeValidate.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeValidate) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{135}\n}\n\nfunc (x *EtcdDowngradeValidate) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdDowngradeValidate) GetClusterDowngrade() *EtcdClusterDowngrade {\n\tif x != nil {\n\t\treturn x.ClusterDowngrade\n\t}\n\treturn nil\n}\n\ntype EtcdDowngradeEnableRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tVersion       string                 `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeEnableRequest) Reset() {\n\t*x = EtcdDowngradeEnableRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[136]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeEnableRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeEnableRequest) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeEnableRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[136]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeEnableRequest.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeEnableRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{136}\n}\n\nfunc (x *EtcdDowngradeEnableRequest) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\ntype EtcdDowngradeEnableResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdDowngradeEnable `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeEnableResponse) Reset() {\n\t*x = EtcdDowngradeEnableResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[137]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeEnableResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeEnableResponse) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeEnableResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[137]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeEnableResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeEnableResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{137}\n}\n\nfunc (x *EtcdDowngradeEnableResponse) GetMessages() []*EtcdDowngradeEnable {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdDowngradeEnable struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata         *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tClusterDowngrade *EtcdClusterDowngrade  `protobuf:\"bytes,2,opt,name=cluster_downgrade,json=clusterDowngrade,proto3\" json:\"cluster_downgrade,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeEnable) Reset() {\n\t*x = EtcdDowngradeEnable{}\n\tmi := &file_machine_machine_proto_msgTypes[138]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeEnable) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeEnable) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeEnable) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[138]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeEnable.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeEnable) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{138}\n}\n\nfunc (x *EtcdDowngradeEnable) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdDowngradeEnable) GetClusterDowngrade() *EtcdClusterDowngrade {\n\tif x != nil {\n\t\treturn x.ClusterDowngrade\n\t}\n\treturn nil\n}\n\ntype EtcdDowngradeCancelResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*EtcdDowngradeCancel `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeCancelResponse) Reset() {\n\t*x = EtcdDowngradeCancelResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[139]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeCancelResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeCancelResponse) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeCancelResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[139]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeCancelResponse.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeCancelResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{139}\n}\n\nfunc (x *EtcdDowngradeCancelResponse) GetMessages() []*EtcdDowngradeCancel {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype EtcdDowngradeCancel struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata         *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tClusterDowngrade *EtcdClusterDowngrade  `protobuf:\"bytes,2,opt,name=cluster_downgrade,json=clusterDowngrade,proto3\" json:\"cluster_downgrade,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *EtcdDowngradeCancel) Reset() {\n\t*x = EtcdDowngradeCancel{}\n\tmi := &file_machine_machine_proto_msgTypes[140]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdDowngradeCancel) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdDowngradeCancel) ProtoMessage() {}\n\nfunc (x *EtcdDowngradeCancel) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[140]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdDowngradeCancel.ProtoReflect.Descriptor instead.\nfunc (*EtcdDowngradeCancel) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{140}\n}\n\nfunc (x *EtcdDowngradeCancel) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdDowngradeCancel) GetClusterDowngrade() *EtcdClusterDowngrade {\n\tif x != nil {\n\t\treturn x.ClusterDowngrade\n\t}\n\treturn nil\n}\n\ntype EtcdClusterDowngrade struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tClusterVersion string                 `protobuf:\"bytes,1,opt,name=cluster_version,json=clusterVersion,proto3\" json:\"cluster_version,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *EtcdClusterDowngrade) Reset() {\n\t*x = EtcdClusterDowngrade{}\n\tmi := &file_machine_machine_proto_msgTypes[141]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdClusterDowngrade) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdClusterDowngrade) ProtoMessage() {}\n\nfunc (x *EtcdClusterDowngrade) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[141]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdClusterDowngrade.ProtoReflect.Descriptor instead.\nfunc (*EtcdClusterDowngrade) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{141}\n}\n\nfunc (x *EtcdClusterDowngrade) GetClusterVersion() string {\n\tif x != nil {\n\t\treturn x.ClusterVersion\n\t}\n\treturn \"\"\n}\n\ntype RouteConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tNetwork       string                 `protobuf:\"bytes,1,opt,name=network,proto3\" json:\"network,omitempty\"`\n\tGateway       string                 `protobuf:\"bytes,2,opt,name=gateway,proto3\" json:\"gateway,omitempty\"`\n\tMetric        uint32                 `protobuf:\"varint,3,opt,name=metric,proto3\" json:\"metric,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RouteConfig) Reset() {\n\t*x = RouteConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[142]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RouteConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RouteConfig) ProtoMessage() {}\n\nfunc (x *RouteConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[142]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RouteConfig.ProtoReflect.Descriptor instead.\nfunc (*RouteConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{142}\n}\n\nfunc (x *RouteConfig) GetNetwork() string {\n\tif x != nil {\n\t\treturn x.Network\n\t}\n\treturn \"\"\n}\n\nfunc (x *RouteConfig) GetGateway() string {\n\tif x != nil {\n\t\treturn x.Gateway\n\t}\n\treturn \"\"\n}\n\nfunc (x *RouteConfig) GetMetric() uint32 {\n\tif x != nil {\n\t\treturn x.Metric\n\t}\n\treturn 0\n}\n\ntype DHCPOptionsConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRouteMetric   uint32                 `protobuf:\"varint,1,opt,name=route_metric,json=routeMetric,proto3\" json:\"route_metric,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DHCPOptionsConfig) Reset() {\n\t*x = DHCPOptionsConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[143]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DHCPOptionsConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DHCPOptionsConfig) ProtoMessage() {}\n\nfunc (x *DHCPOptionsConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[143]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DHCPOptionsConfig.ProtoReflect.Descriptor instead.\nfunc (*DHCPOptionsConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{143}\n}\n\nfunc (x *DHCPOptionsConfig) GetRouteMetric() uint32 {\n\tif x != nil {\n\t\treturn x.RouteMetric\n\t}\n\treturn 0\n}\n\ntype NetworkDeviceConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tInterface     string                 `protobuf:\"bytes,1,opt,name=interface,proto3\" json:\"interface,omitempty\"`\n\tCidr          string                 `protobuf:\"bytes,2,opt,name=cidr,proto3\" json:\"cidr,omitempty\"`\n\tMtu           int32                  `protobuf:\"varint,3,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tDhcp          bool                   `protobuf:\"varint,4,opt,name=dhcp,proto3\" json:\"dhcp,omitempty\"`\n\tIgnore        bool                   `protobuf:\"varint,5,opt,name=ignore,proto3\" json:\"ignore,omitempty\"`\n\tDhcpOptions   *DHCPOptionsConfig     `protobuf:\"bytes,6,opt,name=dhcp_options,json=dhcpOptions,proto3\" json:\"dhcp_options,omitempty\"`\n\tRoutes        []*RouteConfig         `protobuf:\"bytes,7,rep,name=routes,proto3\" json:\"routes,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetworkDeviceConfig) Reset() {\n\t*x = NetworkDeviceConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[144]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetworkDeviceConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetworkDeviceConfig) ProtoMessage() {}\n\nfunc (x *NetworkDeviceConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[144]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetworkDeviceConfig.ProtoReflect.Descriptor instead.\nfunc (*NetworkDeviceConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{144}\n}\n\nfunc (x *NetworkDeviceConfig) GetInterface() string {\n\tif x != nil {\n\t\treturn x.Interface\n\t}\n\treturn \"\"\n}\n\nfunc (x *NetworkDeviceConfig) GetCidr() string {\n\tif x != nil {\n\t\treturn x.Cidr\n\t}\n\treturn \"\"\n}\n\nfunc (x *NetworkDeviceConfig) GetMtu() int32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\nfunc (x *NetworkDeviceConfig) GetDhcp() bool {\n\tif x != nil {\n\t\treturn x.Dhcp\n\t}\n\treturn false\n}\n\nfunc (x *NetworkDeviceConfig) GetIgnore() bool {\n\tif x != nil {\n\t\treturn x.Ignore\n\t}\n\treturn false\n}\n\nfunc (x *NetworkDeviceConfig) GetDhcpOptions() *DHCPOptionsConfig {\n\tif x != nil {\n\t\treturn x.DhcpOptions\n\t}\n\treturn nil\n}\n\nfunc (x *NetworkDeviceConfig) GetRoutes() []*RouteConfig {\n\tif x != nil {\n\t\treturn x.Routes\n\t}\n\treturn nil\n}\n\ntype NetworkConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHostname      string                 `protobuf:\"bytes,1,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tInterfaces    []*NetworkDeviceConfig `protobuf:\"bytes,2,rep,name=interfaces,proto3\" json:\"interfaces,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetworkConfig) Reset() {\n\t*x = NetworkConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[145]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetworkConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetworkConfig) ProtoMessage() {}\n\nfunc (x *NetworkConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[145]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetworkConfig.ProtoReflect.Descriptor instead.\nfunc (*NetworkConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{145}\n}\n\nfunc (x *NetworkConfig) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *NetworkConfig) GetInterfaces() []*NetworkDeviceConfig {\n\tif x != nil {\n\t\treturn x.Interfaces\n\t}\n\treturn nil\n}\n\ntype InstallConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tInstallDisk   string                 `protobuf:\"bytes,1,opt,name=install_disk,json=installDisk,proto3\" json:\"install_disk,omitempty\"`\n\tInstallImage  string                 `protobuf:\"bytes,2,opt,name=install_image,json=installImage,proto3\" json:\"install_image,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *InstallConfig) Reset() {\n\t*x = InstallConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[146]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *InstallConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InstallConfig) ProtoMessage() {}\n\nfunc (x *InstallConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[146]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InstallConfig.ProtoReflect.Descriptor instead.\nfunc (*InstallConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{146}\n}\n\nfunc (x *InstallConfig) GetInstallDisk() string {\n\tif x != nil {\n\t\treturn x.InstallDisk\n\t}\n\treturn \"\"\n}\n\nfunc (x *InstallConfig) GetInstallImage() string {\n\tif x != nil {\n\t\treturn x.InstallImage\n\t}\n\treturn \"\"\n}\n\ntype MachineConfig struct {\n\tstate             protoimpl.MessageState    `protogen:\"open.v1\"`\n\tType              MachineConfig_MachineType `protobuf:\"varint,1,opt,name=type,proto3,enum=machine.MachineConfig_MachineType\" json:\"type,omitempty\"`\n\tInstallConfig     *InstallConfig            `protobuf:\"bytes,2,opt,name=install_config,json=installConfig,proto3\" json:\"install_config,omitempty\"`\n\tNetworkConfig     *NetworkConfig            `protobuf:\"bytes,3,opt,name=network_config,json=networkConfig,proto3\" json:\"network_config,omitempty\"`\n\tKubernetesVersion string                    `protobuf:\"bytes,4,opt,name=kubernetes_version,json=kubernetesVersion,proto3\" json:\"kubernetes_version,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *MachineConfig) Reset() {\n\t*x = MachineConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[147]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineConfig) ProtoMessage() {}\n\nfunc (x *MachineConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[147]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineConfig.ProtoReflect.Descriptor instead.\nfunc (*MachineConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{147}\n}\n\nfunc (x *MachineConfig) GetType() MachineConfig_MachineType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn MachineConfig_TYPE_UNKNOWN\n}\n\nfunc (x *MachineConfig) GetInstallConfig() *InstallConfig {\n\tif x != nil {\n\t\treturn x.InstallConfig\n\t}\n\treturn nil\n}\n\nfunc (x *MachineConfig) GetNetworkConfig() *NetworkConfig {\n\tif x != nil {\n\t\treturn x.NetworkConfig\n\t}\n\treturn nil\n}\n\nfunc (x *MachineConfig) GetKubernetesVersion() string {\n\tif x != nil {\n\t\treturn x.KubernetesVersion\n\t}\n\treturn \"\"\n}\n\ntype ControlPlaneConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEndpoint      string                 `protobuf:\"bytes,1,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ControlPlaneConfig) Reset() {\n\t*x = ControlPlaneConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[148]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControlPlaneConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControlPlaneConfig) ProtoMessage() {}\n\nfunc (x *ControlPlaneConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[148]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControlPlaneConfig.ProtoReflect.Descriptor instead.\nfunc (*ControlPlaneConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{148}\n}\n\nfunc (x *ControlPlaneConfig) GetEndpoint() string {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn \"\"\n}\n\ntype CNIConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tUrls          []string               `protobuf:\"bytes,2,rep,name=urls,proto3\" json:\"urls,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CNIConfig) Reset() {\n\t*x = CNIConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[149]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CNIConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CNIConfig) ProtoMessage() {}\n\nfunc (x *CNIConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[149]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CNIConfig.ProtoReflect.Descriptor instead.\nfunc (*CNIConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{149}\n}\n\nfunc (x *CNIConfig) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *CNIConfig) GetUrls() []string {\n\tif x != nil {\n\t\treturn x.Urls\n\t}\n\treturn nil\n}\n\ntype ClusterNetworkConfig struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDnsDomain     string                 `protobuf:\"bytes,1,opt,name=dns_domain,json=dnsDomain,proto3\" json:\"dns_domain,omitempty\"`\n\tCniConfig     *CNIConfig             `protobuf:\"bytes,2,opt,name=cni_config,json=cniConfig,proto3\" json:\"cni_config,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ClusterNetworkConfig) Reset() {\n\t*x = ClusterNetworkConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[150]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ClusterNetworkConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClusterNetworkConfig) ProtoMessage() {}\n\nfunc (x *ClusterNetworkConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[150]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClusterNetworkConfig.ProtoReflect.Descriptor instead.\nfunc (*ClusterNetworkConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{150}\n}\n\nfunc (x *ClusterNetworkConfig) GetDnsDomain() string {\n\tif x != nil {\n\t\treturn x.DnsDomain\n\t}\n\treturn \"\"\n}\n\nfunc (x *ClusterNetworkConfig) GetCniConfig() *CNIConfig {\n\tif x != nil {\n\t\treturn x.CniConfig\n\t}\n\treturn nil\n}\n\ntype ClusterConfig struct {\n\tstate                          protoimpl.MessageState `protogen:\"open.v1\"`\n\tName                           string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tControlPlane                   *ControlPlaneConfig    `protobuf:\"bytes,2,opt,name=control_plane,json=controlPlane,proto3\" json:\"control_plane,omitempty\"`\n\tClusterNetwork                 *ClusterNetworkConfig  `protobuf:\"bytes,3,opt,name=cluster_network,json=clusterNetwork,proto3\" json:\"cluster_network,omitempty\"`\n\tAllowSchedulingOnControlPlanes bool                   `protobuf:\"varint,4,opt,name=allow_scheduling_on_control_planes,json=allowSchedulingOnControlPlanes,proto3\" json:\"allow_scheduling_on_control_planes,omitempty\"`\n\tunknownFields                  protoimpl.UnknownFields\n\tsizeCache                      protoimpl.SizeCache\n}\n\nfunc (x *ClusterConfig) Reset() {\n\t*x = ClusterConfig{}\n\tmi := &file_machine_machine_proto_msgTypes[151]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ClusterConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClusterConfig) ProtoMessage() {}\n\nfunc (x *ClusterConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[151]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClusterConfig.ProtoReflect.Descriptor instead.\nfunc (*ClusterConfig) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{151}\n}\n\nfunc (x *ClusterConfig) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ClusterConfig) GetControlPlane() *ControlPlaneConfig {\n\tif x != nil {\n\t\treturn x.ControlPlane\n\t}\n\treturn nil\n}\n\nfunc (x *ClusterConfig) GetClusterNetwork() *ClusterNetworkConfig {\n\tif x != nil {\n\t\treturn x.ClusterNetwork\n\t}\n\treturn nil\n}\n\nfunc (x *ClusterConfig) GetAllowSchedulingOnControlPlanes() bool {\n\tif x != nil {\n\t\treturn x.AllowSchedulingOnControlPlanes\n\t}\n\treturn false\n}\n\ntype GenerateClientConfigurationRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Roles in the generated client certificate.\n\tRoles []string `protobuf:\"bytes,1,rep,name=roles,proto3\" json:\"roles,omitempty\"`\n\t// Client certificate TTL.\n\tCrtTtl        *durationpb.Duration `protobuf:\"bytes,2,opt,name=crt_ttl,json=crtTtl,proto3\" json:\"crt_ttl,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *GenerateClientConfigurationRequest) Reset() {\n\t*x = GenerateClientConfigurationRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[152]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *GenerateClientConfigurationRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateClientConfigurationRequest) ProtoMessage() {}\n\nfunc (x *GenerateClientConfigurationRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[152]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateClientConfigurationRequest.ProtoReflect.Descriptor instead.\nfunc (*GenerateClientConfigurationRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{152}\n}\n\nfunc (x *GenerateClientConfigurationRequest) GetRoles() []string {\n\tif x != nil {\n\t\treturn x.Roles\n\t}\n\treturn nil\n}\n\nfunc (x *GenerateClientConfigurationRequest) GetCrtTtl() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.CrtTtl\n\t}\n\treturn nil\n}\n\ntype GenerateClientConfiguration struct {\n\tstate    protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\t// PEM-encoded CA certificate.\n\tCa []byte `protobuf:\"bytes,2,opt,name=ca,proto3\" json:\"ca,omitempty\"`\n\t// PEM-encoded generated client certificate.\n\tCrt []byte `protobuf:\"bytes,3,opt,name=crt,proto3\" json:\"crt,omitempty\"`\n\t// PEM-encoded generated client key.\n\tKey []byte `protobuf:\"bytes,4,opt,name=key,proto3\" json:\"key,omitempty\"`\n\t// Client configuration (talosconfig) file content.\n\tTalosconfig   []byte `protobuf:\"bytes,5,opt,name=talosconfig,proto3\" json:\"talosconfig,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *GenerateClientConfiguration) Reset() {\n\t*x = GenerateClientConfiguration{}\n\tmi := &file_machine_machine_proto_msgTypes[153]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *GenerateClientConfiguration) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateClientConfiguration) ProtoMessage() {}\n\nfunc (x *GenerateClientConfiguration) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[153]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateClientConfiguration.ProtoReflect.Descriptor instead.\nfunc (*GenerateClientConfiguration) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{153}\n}\n\nfunc (x *GenerateClientConfiguration) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *GenerateClientConfiguration) GetCa() []byte {\n\tif x != nil {\n\t\treturn x.Ca\n\t}\n\treturn nil\n}\n\nfunc (x *GenerateClientConfiguration) GetCrt() []byte {\n\tif x != nil {\n\t\treturn x.Crt\n\t}\n\treturn nil\n}\n\nfunc (x *GenerateClientConfiguration) GetKey() []byte {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn nil\n}\n\nfunc (x *GenerateClientConfiguration) GetTalosconfig() []byte {\n\tif x != nil {\n\t\treturn x.Talosconfig\n\t}\n\treturn nil\n}\n\ntype GenerateClientConfigurationResponse struct {\n\tstate         protoimpl.MessageState         `protogen:\"open.v1\"`\n\tMessages      []*GenerateClientConfiguration `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *GenerateClientConfigurationResponse) Reset() {\n\t*x = GenerateClientConfigurationResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[154]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *GenerateClientConfigurationResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GenerateClientConfigurationResponse) ProtoMessage() {}\n\nfunc (x *GenerateClientConfigurationResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[154]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GenerateClientConfigurationResponse.ProtoReflect.Descriptor instead.\nfunc (*GenerateClientConfigurationResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{154}\n}\n\nfunc (x *GenerateClientConfigurationResponse) GetMessages() []*GenerateClientConfiguration {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype PacketCaptureRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Interface name to perform packet capture on.\n\tInterface string `protobuf:\"bytes,1,opt,name=interface,proto3\" json:\"interface,omitempty\"`\n\t// Enable promiscuous mode.\n\tPromiscuous bool `protobuf:\"varint,2,opt,name=promiscuous,proto3\" json:\"promiscuous,omitempty\"`\n\t// Snap length in bytes.\n\tSnapLen uint32 `protobuf:\"varint,3,opt,name=snap_len,json=snapLen,proto3\" json:\"snap_len,omitempty\"`\n\t// BPF filter.\n\tBpfFilter     []*BPFInstruction `protobuf:\"bytes,4,rep,name=bpf_filter,json=bpfFilter,proto3\" json:\"bpf_filter,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PacketCaptureRequest) Reset() {\n\t*x = PacketCaptureRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[155]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PacketCaptureRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PacketCaptureRequest) ProtoMessage() {}\n\nfunc (x *PacketCaptureRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[155]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PacketCaptureRequest.ProtoReflect.Descriptor instead.\nfunc (*PacketCaptureRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{155}\n}\n\nfunc (x *PacketCaptureRequest) GetInterface() string {\n\tif x != nil {\n\t\treturn x.Interface\n\t}\n\treturn \"\"\n}\n\nfunc (x *PacketCaptureRequest) GetPromiscuous() bool {\n\tif x != nil {\n\t\treturn x.Promiscuous\n\t}\n\treturn false\n}\n\nfunc (x *PacketCaptureRequest) GetSnapLen() uint32 {\n\tif x != nil {\n\t\treturn x.SnapLen\n\t}\n\treturn 0\n}\n\nfunc (x *PacketCaptureRequest) GetBpfFilter() []*BPFInstruction {\n\tif x != nil {\n\t\treturn x.BpfFilter\n\t}\n\treturn nil\n}\n\ntype BPFInstruction struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tOp            uint32                 `protobuf:\"varint,1,opt,name=op,proto3\" json:\"op,omitempty\"`\n\tJt            uint32                 `protobuf:\"varint,2,opt,name=jt,proto3\" json:\"jt,omitempty\"`\n\tJf            uint32                 `protobuf:\"varint,3,opt,name=jf,proto3\" json:\"jf,omitempty\"`\n\tK             uint32                 `protobuf:\"varint,4,opt,name=k,proto3\" json:\"k,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BPFInstruction) Reset() {\n\t*x = BPFInstruction{}\n\tmi := &file_machine_machine_proto_msgTypes[156]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BPFInstruction) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BPFInstruction) ProtoMessage() {}\n\nfunc (x *BPFInstruction) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[156]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BPFInstruction.ProtoReflect.Descriptor instead.\nfunc (*BPFInstruction) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{156}\n}\n\nfunc (x *BPFInstruction) GetOp() uint32 {\n\tif x != nil {\n\t\treturn x.Op\n\t}\n\treturn 0\n}\n\nfunc (x *BPFInstruction) GetJt() uint32 {\n\tif x != nil {\n\t\treturn x.Jt\n\t}\n\treturn 0\n}\n\nfunc (x *BPFInstruction) GetJf() uint32 {\n\tif x != nil {\n\t\treturn x.Jf\n\t}\n\treturn 0\n}\n\nfunc (x *BPFInstruction) GetK() uint32 {\n\tif x != nil {\n\t\treturn x.K\n\t}\n\treturn 0\n}\n\ntype NetstatRequest struct {\n\tstate         protoimpl.MessageState  `protogen:\"open.v1\"`\n\tFilter        NetstatRequest_Filter   `protobuf:\"varint,1,opt,name=filter,proto3,enum=machine.NetstatRequest_Filter\" json:\"filter,omitempty\"`\n\tFeature       *NetstatRequest_Feature `protobuf:\"bytes,2,opt,name=feature,proto3\" json:\"feature,omitempty\"`\n\tL4Proto       *NetstatRequest_L4Proto `protobuf:\"bytes,3,opt,name=l4proto,proto3\" json:\"l4proto,omitempty\"`\n\tNetns         *NetstatRequest_NetNS   `protobuf:\"bytes,4,opt,name=netns,proto3\" json:\"netns,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetstatRequest) Reset() {\n\t*x = NetstatRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[157]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetstatRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetstatRequest) ProtoMessage() {}\n\nfunc (x *NetstatRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[157]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetstatRequest.ProtoReflect.Descriptor instead.\nfunc (*NetstatRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{157}\n}\n\nfunc (x *NetstatRequest) GetFilter() NetstatRequest_Filter {\n\tif x != nil {\n\t\treturn x.Filter\n\t}\n\treturn NetstatRequest_ALL\n}\n\nfunc (x *NetstatRequest) GetFeature() *NetstatRequest_Feature {\n\tif x != nil {\n\t\treturn x.Feature\n\t}\n\treturn nil\n}\n\nfunc (x *NetstatRequest) GetL4Proto() *NetstatRequest_L4Proto {\n\tif x != nil {\n\t\treturn x.L4Proto\n\t}\n\treturn nil\n}\n\nfunc (x *NetstatRequest) GetNetns() *NetstatRequest_NetNS {\n\tif x != nil {\n\t\treturn x.Netns\n\t}\n\treturn nil\n}\n\ntype ConnectRecord struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tL4Proto       string                    `protobuf:\"bytes,1,opt,name=l4proto,proto3\" json:\"l4proto,omitempty\"`\n\tLocalip       string                    `protobuf:\"bytes,2,opt,name=localip,proto3\" json:\"localip,omitempty\"`\n\tLocalport     uint32                    `protobuf:\"varint,3,opt,name=localport,proto3\" json:\"localport,omitempty\"`\n\tRemoteip      string                    `protobuf:\"bytes,4,opt,name=remoteip,proto3\" json:\"remoteip,omitempty\"`\n\tRemoteport    uint32                    `protobuf:\"varint,5,opt,name=remoteport,proto3\" json:\"remoteport,omitempty\"`\n\tState         ConnectRecord_State       `protobuf:\"varint,6,opt,name=state,proto3,enum=machine.ConnectRecord_State\" json:\"state,omitempty\"`\n\tTxqueue       uint64                    `protobuf:\"varint,7,opt,name=txqueue,proto3\" json:\"txqueue,omitempty\"`\n\tRxqueue       uint64                    `protobuf:\"varint,8,opt,name=rxqueue,proto3\" json:\"rxqueue,omitempty\"`\n\tTr            ConnectRecord_TimerActive `protobuf:\"varint,9,opt,name=tr,proto3,enum=machine.ConnectRecord_TimerActive\" json:\"tr,omitempty\"`\n\tTimerwhen     uint64                    `protobuf:\"varint,10,opt,name=timerwhen,proto3\" json:\"timerwhen,omitempty\"`\n\tRetrnsmt      uint64                    `protobuf:\"varint,11,opt,name=retrnsmt,proto3\" json:\"retrnsmt,omitempty\"`\n\tUid           uint32                    `protobuf:\"varint,12,opt,name=uid,proto3\" json:\"uid,omitempty\"`\n\tTimeout       uint64                    `protobuf:\"varint,13,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tInode         uint64                    `protobuf:\"varint,14,opt,name=inode,proto3\" json:\"inode,omitempty\"`\n\tRef           uint64                    `protobuf:\"varint,15,opt,name=ref,proto3\" json:\"ref,omitempty\"`\n\tPointer       uint64                    `protobuf:\"varint,16,opt,name=pointer,proto3\" json:\"pointer,omitempty\"`\n\tProcess       *ConnectRecord_Process    `protobuf:\"bytes,17,opt,name=process,proto3\" json:\"process,omitempty\"`\n\tNetns         string                    `protobuf:\"bytes,18,opt,name=netns,proto3\" json:\"netns,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConnectRecord) Reset() {\n\t*x = ConnectRecord{}\n\tmi := &file_machine_machine_proto_msgTypes[158]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConnectRecord) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConnectRecord) ProtoMessage() {}\n\nfunc (x *ConnectRecord) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[158]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConnectRecord.ProtoReflect.Descriptor instead.\nfunc (*ConnectRecord) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{158}\n}\n\nfunc (x *ConnectRecord) GetL4Proto() string {\n\tif x != nil {\n\t\treturn x.L4Proto\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConnectRecord) GetLocalip() string {\n\tif x != nil {\n\t\treturn x.Localip\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConnectRecord) GetLocalport() uint32 {\n\tif x != nil {\n\t\treturn x.Localport\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetRemoteip() string {\n\tif x != nil {\n\t\treturn x.Remoteip\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConnectRecord) GetRemoteport() uint32 {\n\tif x != nil {\n\t\treturn x.Remoteport\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetState() ConnectRecord_State {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn ConnectRecord_RESERVED\n}\n\nfunc (x *ConnectRecord) GetTxqueue() uint64 {\n\tif x != nil {\n\t\treturn x.Txqueue\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetRxqueue() uint64 {\n\tif x != nil {\n\t\treturn x.Rxqueue\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetTr() ConnectRecord_TimerActive {\n\tif x != nil {\n\t\treturn x.Tr\n\t}\n\treturn ConnectRecord_OFF\n}\n\nfunc (x *ConnectRecord) GetTimerwhen() uint64 {\n\tif x != nil {\n\t\treturn x.Timerwhen\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetRetrnsmt() uint64 {\n\tif x != nil {\n\t\treturn x.Retrnsmt\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetUid() uint32 {\n\tif x != nil {\n\t\treturn x.Uid\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetTimeout() uint64 {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetInode() uint64 {\n\tif x != nil {\n\t\treturn x.Inode\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetRef() uint64 {\n\tif x != nil {\n\t\treturn x.Ref\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetPointer() uint64 {\n\tif x != nil {\n\t\treturn x.Pointer\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord) GetProcess() *ConnectRecord_Process {\n\tif x != nil {\n\t\treturn x.Process\n\t}\n\treturn nil\n}\n\nfunc (x *ConnectRecord) GetNetns() string {\n\tif x != nil {\n\t\treturn x.Netns\n\t}\n\treturn \"\"\n}\n\ntype Netstat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tConnectrecord []*ConnectRecord       `protobuf:\"bytes,2,rep,name=connectrecord,proto3\" json:\"connectrecord,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Netstat) Reset() {\n\t*x = Netstat{}\n\tmi := &file_machine_machine_proto_msgTypes[159]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Netstat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Netstat) ProtoMessage() {}\n\nfunc (x *Netstat) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[159]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Netstat.ProtoReflect.Descriptor instead.\nfunc (*Netstat) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{159}\n}\n\nfunc (x *Netstat) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Netstat) GetConnectrecord() []*ConnectRecord {\n\tif x != nil {\n\t\treturn x.Connectrecord\n\t}\n\treturn nil\n}\n\ntype NetstatResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Netstat             `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetstatResponse) Reset() {\n\t*x = NetstatResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[160]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetstatResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetstatResponse) ProtoMessage() {}\n\nfunc (x *NetstatResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[160]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetstatResponse.ProtoReflect.Descriptor instead.\nfunc (*NetstatResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{160}\n}\n\nfunc (x *NetstatResponse) GetMessages() []*Netstat {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype MetaWriteRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           uint32                 `protobuf:\"varint,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue         []byte                 `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaWriteRequest) Reset() {\n\t*x = MetaWriteRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[161]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaWriteRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaWriteRequest) ProtoMessage() {}\n\nfunc (x *MetaWriteRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[161]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaWriteRequest.ProtoReflect.Descriptor instead.\nfunc (*MetaWriteRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{161}\n}\n\nfunc (x *MetaWriteRequest) GetKey() uint32 {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn 0\n}\n\nfunc (x *MetaWriteRequest) GetValue() []byte {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\ntype MetaWrite struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaWrite) Reset() {\n\t*x = MetaWrite{}\n\tmi := &file_machine_machine_proto_msgTypes[162]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaWrite) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaWrite) ProtoMessage() {}\n\nfunc (x *MetaWrite) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[162]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaWrite.ProtoReflect.Descriptor instead.\nfunc (*MetaWrite) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{162}\n}\n\nfunc (x *MetaWrite) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype MetaWriteResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*MetaWrite           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaWriteResponse) Reset() {\n\t*x = MetaWriteResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[163]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaWriteResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaWriteResponse) ProtoMessage() {}\n\nfunc (x *MetaWriteResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[163]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaWriteResponse.ProtoReflect.Descriptor instead.\nfunc (*MetaWriteResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{163}\n}\n\nfunc (x *MetaWriteResponse) GetMessages() []*MetaWrite {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype MetaDeleteRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           uint32                 `protobuf:\"varint,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaDeleteRequest) Reset() {\n\t*x = MetaDeleteRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[164]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaDeleteRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaDeleteRequest) ProtoMessage() {}\n\nfunc (x *MetaDeleteRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[164]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaDeleteRequest.ProtoReflect.Descriptor instead.\nfunc (*MetaDeleteRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{164}\n}\n\nfunc (x *MetaDeleteRequest) GetKey() uint32 {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn 0\n}\n\ntype MetaDelete struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaDelete) Reset() {\n\t*x = MetaDelete{}\n\tmi := &file_machine_machine_proto_msgTypes[165]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaDelete) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaDelete) ProtoMessage() {}\n\nfunc (x *MetaDelete) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[165]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaDelete.ProtoReflect.Descriptor instead.\nfunc (*MetaDelete) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{165}\n}\n\nfunc (x *MetaDelete) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype MetaDeleteResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*MetaDelete          `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaDeleteResponse) Reset() {\n\t*x = MetaDeleteResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[166]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaDeleteResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaDeleteResponse) ProtoMessage() {}\n\nfunc (x *MetaDeleteResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[166]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaDeleteResponse.ProtoReflect.Descriptor instead.\nfunc (*MetaDeleteResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{166}\n}\n\nfunc (x *MetaDeleteResponse) GetMessages() []*MetaDelete {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype ImageListRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Containerd namespace to use.\n\tNamespace     common.ContainerdNamespace `protobuf:\"varint,1,opt,name=namespace,proto3,enum=common.ContainerdNamespace\" json:\"namespace,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageListRequest) Reset() {\n\t*x = ImageListRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[167]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageListRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageListRequest) ProtoMessage() {}\n\nfunc (x *ImageListRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[167]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageListRequest.ProtoReflect.Descriptor instead.\nfunc (*ImageListRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{167}\n}\n\nfunc (x *ImageListRequest) GetNamespace() common.ContainerdNamespace {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn common.ContainerdNamespace(0)\n}\n\ntype ImageListResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tName          string                 `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tDigest        string                 `protobuf:\"bytes,3,opt,name=digest,proto3\" json:\"digest,omitempty\"`\n\tSize          int64                  `protobuf:\"varint,4,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tCreatedAt     *timestamppb.Timestamp `protobuf:\"bytes,5,opt,name=created_at,json=createdAt,proto3\" json:\"created_at,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageListResponse) Reset() {\n\t*x = ImageListResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[168]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageListResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageListResponse) ProtoMessage() {}\n\nfunc (x *ImageListResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[168]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageListResponse.ProtoReflect.Descriptor instead.\nfunc (*ImageListResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{168}\n}\n\nfunc (x *ImageListResponse) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *ImageListResponse) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageListResponse) GetDigest() string {\n\tif x != nil {\n\t\treturn x.Digest\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageListResponse) GetSize() int64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *ImageListResponse) GetCreatedAt() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.CreatedAt\n\t}\n\treturn nil\n}\n\ntype ImagePullRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Containerd namespace to use.\n\tNamespace common.ContainerdNamespace `protobuf:\"varint,1,opt,name=namespace,proto3,enum=common.ContainerdNamespace\" json:\"namespace,omitempty\"`\n\t// Image reference to pull.\n\tReference     string `protobuf:\"bytes,2,opt,name=reference,proto3\" json:\"reference,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImagePullRequest) Reset() {\n\t*x = ImagePullRequest{}\n\tmi := &file_machine_machine_proto_msgTypes[169]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImagePullRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImagePullRequest) ProtoMessage() {}\n\nfunc (x *ImagePullRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[169]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImagePullRequest.ProtoReflect.Descriptor instead.\nfunc (*ImagePullRequest) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{169}\n}\n\nfunc (x *ImagePullRequest) GetNamespace() common.ContainerdNamespace {\n\tif x != nil {\n\t\treturn x.Namespace\n\t}\n\treturn common.ContainerdNamespace(0)\n}\n\nfunc (x *ImagePullRequest) GetReference() string {\n\tif x != nil {\n\t\treturn x.Reference\n\t}\n\treturn \"\"\n}\n\ntype ImagePull struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImagePull) Reset() {\n\t*x = ImagePull{}\n\tmi := &file_machine_machine_proto_msgTypes[170]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImagePull) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImagePull) ProtoMessage() {}\n\nfunc (x *ImagePull) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[170]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImagePull.ProtoReflect.Descriptor instead.\nfunc (*ImagePull) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{170}\n}\n\nfunc (x *ImagePull) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\ntype ImagePullResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*ImagePull           `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImagePullResponse) Reset() {\n\t*x = ImagePullResponse{}\n\tmi := &file_machine_machine_proto_msgTypes[171]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImagePullResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImagePullResponse) ProtoMessage() {}\n\nfunc (x *ImagePullResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[171]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImagePullResponse.ProtoReflect.Descriptor instead.\nfunc (*ImagePullResponse) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{171}\n}\n\nfunc (x *ImagePullResponse) GetMessages() []*ImagePull {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype MachineStatusEvent_MachineStatus struct {\n\tstate           protoimpl.MessageState                             `protogen:\"open.v1\"`\n\tReady           bool                                               `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tUnmetConditions []*MachineStatusEvent_MachineStatus_UnmetCondition `protobuf:\"bytes,2,rep,name=unmet_conditions,json=unmetConditions,proto3\" json:\"unmet_conditions,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *MachineStatusEvent_MachineStatus) Reset() {\n\t*x = MachineStatusEvent_MachineStatus{}\n\tmi := &file_machine_machine_proto_msgTypes[172]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineStatusEvent_MachineStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineStatusEvent_MachineStatus) ProtoMessage() {}\n\nfunc (x *MachineStatusEvent_MachineStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[172]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineStatusEvent_MachineStatus.ProtoReflect.Descriptor instead.\nfunc (*MachineStatusEvent_MachineStatus) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{17, 0}\n}\n\nfunc (x *MachineStatusEvent_MachineStatus) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *MachineStatusEvent_MachineStatus) GetUnmetConditions() []*MachineStatusEvent_MachineStatus_UnmetCondition {\n\tif x != nil {\n\t\treturn x.UnmetConditions\n\t}\n\treturn nil\n}\n\ntype MachineStatusEvent_MachineStatus_UnmetCondition struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tReason        string                 `protobuf:\"bytes,2,opt,name=reason,proto3\" json:\"reason,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MachineStatusEvent_MachineStatus_UnmetCondition) Reset() {\n\t*x = MachineStatusEvent_MachineStatus_UnmetCondition{}\n\tmi := &file_machine_machine_proto_msgTypes[173]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineStatusEvent_MachineStatus_UnmetCondition) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineStatusEvent_MachineStatus_UnmetCondition) ProtoMessage() {}\n\nfunc (x *MachineStatusEvent_MachineStatus_UnmetCondition) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[173]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineStatusEvent_MachineStatus_UnmetCondition.ProtoReflect.Descriptor instead.\nfunc (*MachineStatusEvent_MachineStatus_UnmetCondition) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{17, 0, 0}\n}\n\nfunc (x *MachineStatusEvent_MachineStatus_UnmetCondition) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *MachineStatusEvent_MachineStatus_UnmetCondition) GetReason() string {\n\tif x != nil {\n\t\treturn x.Reason\n\t}\n\treturn \"\"\n}\n\ntype NetstatRequest_Feature struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPid           bool                   `protobuf:\"varint,1,opt,name=pid,proto3\" json:\"pid,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetstatRequest_Feature) Reset() {\n\t*x = NetstatRequest_Feature{}\n\tmi := &file_machine_machine_proto_msgTypes[174]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetstatRequest_Feature) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetstatRequest_Feature) ProtoMessage() {}\n\nfunc (x *NetstatRequest_Feature) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[174]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetstatRequest_Feature.ProtoReflect.Descriptor instead.\nfunc (*NetstatRequest_Feature) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{157, 0}\n}\n\nfunc (x *NetstatRequest_Feature) GetPid() bool {\n\tif x != nil {\n\t\treturn x.Pid\n\t}\n\treturn false\n}\n\ntype NetstatRequest_L4Proto struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTcp           bool                   `protobuf:\"varint,1,opt,name=tcp,proto3\" json:\"tcp,omitempty\"`\n\tTcp6          bool                   `protobuf:\"varint,2,opt,name=tcp6,proto3\" json:\"tcp6,omitempty\"`\n\tUdp           bool                   `protobuf:\"varint,3,opt,name=udp,proto3\" json:\"udp,omitempty\"`\n\tUdp6          bool                   `protobuf:\"varint,4,opt,name=udp6,proto3\" json:\"udp6,omitempty\"`\n\tUdplite       bool                   `protobuf:\"varint,5,opt,name=udplite,proto3\" json:\"udplite,omitempty\"`\n\tUdplite6      bool                   `protobuf:\"varint,6,opt,name=udplite6,proto3\" json:\"udplite6,omitempty\"`\n\tRaw           bool                   `protobuf:\"varint,7,opt,name=raw,proto3\" json:\"raw,omitempty\"`\n\tRaw6          bool                   `protobuf:\"varint,8,opt,name=raw6,proto3\" json:\"raw6,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetstatRequest_L4Proto) Reset() {\n\t*x = NetstatRequest_L4Proto{}\n\tmi := &file_machine_machine_proto_msgTypes[175]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetstatRequest_L4Proto) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetstatRequest_L4Proto) ProtoMessage() {}\n\nfunc (x *NetstatRequest_L4Proto) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[175]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetstatRequest_L4Proto.ProtoReflect.Descriptor instead.\nfunc (*NetstatRequest_L4Proto) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{157, 1}\n}\n\nfunc (x *NetstatRequest_L4Proto) GetTcp() bool {\n\tif x != nil {\n\t\treturn x.Tcp\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetTcp6() bool {\n\tif x != nil {\n\t\treturn x.Tcp6\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetUdp() bool {\n\tif x != nil {\n\t\treturn x.Udp\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetUdp6() bool {\n\tif x != nil {\n\t\treturn x.Udp6\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetUdplite() bool {\n\tif x != nil {\n\t\treturn x.Udplite\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetUdplite6() bool {\n\tif x != nil {\n\t\treturn x.Udplite6\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetRaw() bool {\n\tif x != nil {\n\t\treturn x.Raw\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_L4Proto) GetRaw6() bool {\n\tif x != nil {\n\t\treturn x.Raw6\n\t}\n\treturn false\n}\n\ntype NetstatRequest_NetNS struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHostnetwork   bool                   `protobuf:\"varint,1,opt,name=hostnetwork,proto3\" json:\"hostnetwork,omitempty\"`\n\tNetns         []string               `protobuf:\"bytes,2,rep,name=netns,proto3\" json:\"netns,omitempty\"`\n\tAllnetns      bool                   `protobuf:\"varint,3,opt,name=allnetns,proto3\" json:\"allnetns,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NetstatRequest_NetNS) Reset() {\n\t*x = NetstatRequest_NetNS{}\n\tmi := &file_machine_machine_proto_msgTypes[176]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NetstatRequest_NetNS) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NetstatRequest_NetNS) ProtoMessage() {}\n\nfunc (x *NetstatRequest_NetNS) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[176]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NetstatRequest_NetNS.ProtoReflect.Descriptor instead.\nfunc (*NetstatRequest_NetNS) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{157, 2}\n}\n\nfunc (x *NetstatRequest_NetNS) GetHostnetwork() bool {\n\tif x != nil {\n\t\treturn x.Hostnetwork\n\t}\n\treturn false\n}\n\nfunc (x *NetstatRequest_NetNS) GetNetns() []string {\n\tif x != nil {\n\t\treturn x.Netns\n\t}\n\treturn nil\n}\n\nfunc (x *NetstatRequest_NetNS) GetAllnetns() bool {\n\tif x != nil {\n\t\treturn x.Allnetns\n\t}\n\treturn false\n}\n\ntype ConnectRecord_Process struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPid           uint32                 `protobuf:\"varint,1,opt,name=pid,proto3\" json:\"pid,omitempty\"`\n\tName          string                 `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConnectRecord_Process) Reset() {\n\t*x = ConnectRecord_Process{}\n\tmi := &file_machine_machine_proto_msgTypes[177]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConnectRecord_Process) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConnectRecord_Process) ProtoMessage() {}\n\nfunc (x *ConnectRecord_Process) ProtoReflect() protoreflect.Message {\n\tmi := &file_machine_machine_proto_msgTypes[177]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConnectRecord_Process.ProtoReflect.Descriptor instead.\nfunc (*ConnectRecord_Process) Descriptor() ([]byte, []int) {\n\treturn file_machine_machine_proto_rawDescGZIP(), []int{158, 0}\n}\n\nfunc (x *ConnectRecord_Process) GetPid() uint32 {\n\tif x != nil {\n\t\treturn x.Pid\n\t}\n\treturn 0\n}\n\nfunc (x *ConnectRecord_Process) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nvar File_machine_machine_proto protoreflect.FileDescriptor\n\nconst file_machine_machine_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x15machine/machine.proto\\x12\\amachine\\x1a\\x13common/common.proto\\x1a\\x19google/protobuf/any.proto\\x1a\\x1egoogle/protobuf/duration.proto\\x1a\\x1bgoogle/protobuf/empty.proto\\x1a\\x1fgoogle/protobuf/timestamp.proto\\\"\\x8c\\x02\\n\" +\n\t\"\\x19ApplyConfigurationRequest\\x12\\x12\\n\" +\n\t\"\\x04data\\x18\\x01 \\x01(\\fR\\x04data\\x12;\\n\" +\n\t\"\\x04mode\\x18\\x04 \\x01(\\x0e2'.machine.ApplyConfigurationRequest.ModeR\\x04mode\\x12\\x17\\n\" +\n\t\"\\adry_run\\x18\\x05 \\x01(\\bR\\x06dryRun\\x12C\\n\" +\n\t\"\\x10try_mode_timeout\\x18\\x06 \\x01(\\v2\\x19.google.protobuf.DurationR\\x0etryModeTimeout\\\"@\\n\" +\n\t\"\\x04Mode\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06REBOOT\\x10\\x00\\x12\\b\\n\" +\n\t\"\\x04AUTO\\x10\\x01\\x12\\r\\n\" +\n\t\"\\tNO_REBOOT\\x10\\x02\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06STAGED\\x10\\x03\\x12\\a\\n\" +\n\t\"\\x03TRY\\x10\\x04\\\"\\xbe\\x01\\n\" +\n\t\"\\x12ApplyConfiguration\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x1a\\n\" +\n\t\"\\bwarnings\\x18\\x02 \\x03(\\tR\\bwarnings\\x12;\\n\" +\n\t\"\\x04mode\\x18\\x03 \\x01(\\x0e2'.machine.ApplyConfigurationRequest.ModeR\\x04mode\\x12!\\n\" +\n\t\"\\fmode_details\\x18\\x04 \\x01(\\tR\\vmodeDetails\\\"U\\n\" +\n\t\"\\x1aApplyConfigurationResponse\\x127\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1b.machine.ApplyConfigurationR\\bmessages\\\"p\\n\" +\n\t\"\\rRebootRequest\\x12/\\n\" +\n\t\"\\x04mode\\x18\\x01 \\x01(\\x0e2\\x1b.machine.RebootRequest.ModeR\\x04mode\\\".\\n\" +\n\t\"\\x04Mode\\x12\\v\\n\" +\n\t\"\\aDEFAULT\\x10\\x00\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"POWERCYCLE\\x10\\x01\\x12\\t\\n\" +\n\t\"\\x05FORCE\\x10\\x02\\\"Q\\n\" +\n\t\"\\x06Reboot\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x19\\n\" +\n\t\"\\bactor_id\\x18\\x02 \\x01(\\tR\\aactorId\\\"=\\n\" +\n\t\"\\x0eRebootResponse\\x12+\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0f.machine.RebootR\\bmessages\\\"l\\n\" +\n\t\"\\x10BootstrapRequest\\x12!\\n\" +\n\t\"\\frecover_etcd\\x18\\x01 \\x01(\\bR\\vrecoverEtcd\\x125\\n\" +\n\t\"\\x17recover_skip_hash_check\\x18\\x02 \\x01(\\bR\\x14recoverSkipHashCheck\\\"9\\n\" +\n\t\"\\tBootstrap\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"C\\n\" +\n\t\"\\x11BootstrapResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.BootstrapR\\bmessages\\\"\\xb0\\x01\\n\" +\n\t\"\\rSequenceEvent\\x12\\x1a\\n\" +\n\t\"\\bsequence\\x18\\x01 \\x01(\\tR\\bsequence\\x125\\n\" +\n\t\"\\x06action\\x18\\x02 \\x01(\\x0e2\\x1d.machine.SequenceEvent.ActionR\\x06action\\x12#\\n\" +\n\t\"\\x05error\\x18\\x03 \\x01(\\v2\\r.common.ErrorR\\x05error\\\"'\\n\" +\n\t\"\\x06Action\\x12\\b\\n\" +\n\t\"\\x04NOOP\\x10\\x00\\x12\\t\\n\" +\n\t\"\\x05START\\x10\\x01\\x12\\b\\n\" +\n\t\"\\x04STOP\\x10\\x02\\\"u\\n\" +\n\t\"\\n\" +\n\t\"PhaseEvent\\x12\\x14\\n\" +\n\t\"\\x05phase\\x18\\x01 \\x01(\\tR\\x05phase\\x122\\n\" +\n\t\"\\x06action\\x18\\x02 \\x01(\\x0e2\\x1a.machine.PhaseEvent.ActionR\\x06action\\\"\\x1d\\n\" +\n\t\"\\x06Action\\x12\\t\\n\" +\n\t\"\\x05START\\x10\\x00\\x12\\b\\n\" +\n\t\"\\x04STOP\\x10\\x01\\\"q\\n\" +\n\t\"\\tTaskEvent\\x12\\x12\\n\" +\n\t\"\\x04task\\x18\\x01 \\x01(\\tR\\x04task\\x121\\n\" +\n\t\"\\x06action\\x18\\x02 \\x01(\\x0e2\\x19.machine.TaskEvent.ActionR\\x06action\\\"\\x1d\\n\" +\n\t\"\\x06Action\\x12\\t\\n\" +\n\t\"\\x05START\\x10\\x00\\x12\\b\\n\" +\n\t\"\\x04STOP\\x10\\x01\\\"\\xba\\x02\\n\" +\n\t\"\\x11ServiceStateEvent\\x12\\x18\\n\" +\n\t\"\\aservice\\x18\\x01 \\x01(\\tR\\aservice\\x129\\n\" +\n\t\"\\x06action\\x18\\x02 \\x01(\\x0e2!.machine.ServiceStateEvent.ActionR\\x06action\\x12\\x18\\n\" +\n\t\"\\amessage\\x18\\x03 \\x01(\\tR\\amessage\\x12.\\n\" +\n\t\"\\x06health\\x18\\x04 \\x01(\\v2\\x16.machine.ServiceHealthR\\x06health\\\"\\x85\\x01\\n\" +\n\t\"\\x06Action\\x12\\x0f\\n\" +\n\t\"\\vINITIALIZED\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tPREPARING\\x10\\x01\\x12\\v\\n\" +\n\t\"\\aWAITING\\x10\\x02\\x12\\v\\n\" +\n\t\"\\aRUNNING\\x10\\x03\\x12\\f\\n\" +\n\t\"\\bSTOPPING\\x10\\x04\\x12\\f\\n\" +\n\t\"\\bFINISHED\\x10\\x05\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06FAILED\\x10\\x06\\x12\\v\\n\" +\n\t\"\\aSKIPPED\\x10\\a\\x12\\f\\n\" +\n\t\"\\bSTARTING\\x10\\b\\\" \\n\" +\n\t\"\\fRestartEvent\\x12\\x10\\n\" +\n\t\"\\x03cmd\\x18\\x01 \\x01(\\x03R\\x03cmd\\\",\\n\" +\n\t\"\\x14ConfigLoadErrorEvent\\x12\\x14\\n\" +\n\t\"\\x05error\\x18\\x01 \\x01(\\tR\\x05error\\\"2\\n\" +\n\t\"\\x1aConfigValidationErrorEvent\\x12\\x14\\n\" +\n\t\"\\x05error\\x18\\x01 \\x01(\\tR\\x05error\\\"H\\n\" +\n\t\"\\fAddressEvent\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x01 \\x01(\\tR\\bhostname\\x12\\x1c\\n\" +\n\t\"\\taddresses\\x18\\x02 \\x03(\\tR\\taddresses\\\"\\xfb\\x03\\n\" +\n\t\"\\x12MachineStatusEvent\\x12>\\n\" +\n\t\"\\x05stage\\x18\\x01 \\x01(\\x0e2(.machine.MachineStatusEvent.MachineStageR\\x05stage\\x12A\\n\" +\n\t\"\\x06status\\x18\\x02 \\x01(\\v2).machine.MachineStatusEvent.MachineStatusR\\x06status\\x1a\\xc8\\x01\\n\" +\n\t\"\\rMachineStatus\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12c\\n\" +\n\t\"\\x10unmet_conditions\\x18\\x02 \\x03(\\v28.machine.MachineStatusEvent.MachineStatus.UnmetConditionR\\x0funmetConditions\\x1a<\\n\" +\n\t\"\\x0eUnmetCondition\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06reason\\x18\\x02 \\x01(\\tR\\x06reason\\\"\\x96\\x01\\n\" +\n\t\"\\fMachineStage\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\v\\n\" +\n\t\"\\aBOOTING\\x10\\x01\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"INSTALLING\\x10\\x02\\x12\\x0f\\n\" +\n\t\"\\vMAINTENANCE\\x10\\x03\\x12\\v\\n\" +\n\t\"\\aRUNNING\\x10\\x04\\x12\\r\\n\" +\n\t\"\\tREBOOTING\\x10\\x05\\x12\\x11\\n\" +\n\t\"\\rSHUTTING_DOWN\\x10\\x06\\x12\\r\\n\" +\n\t\"\\tRESETTING\\x10\\a\\x12\\r\\n\" +\n\t\"\\tUPGRADING\\x10\\b\\\"\\x90\\x01\\n\" +\n\t\"\\rEventsRequest\\x12\\x1f\\n\" +\n\t\"\\vtail_events\\x18\\x01 \\x01(\\x05R\\n\" +\n\t\"tailEvents\\x12\\x17\\n\" +\n\t\"\\atail_id\\x18\\x02 \\x01(\\tR\\x06tailId\\x12!\\n\" +\n\t\"\\ftail_seconds\\x18\\x03 \\x01(\\x05R\\vtailSeconds\\x12\\\"\\n\" +\n\t\"\\rwith_actor_id\\x18\\x04 \\x01(\\tR\\vwithActorId\\\"\\x8a\\x01\\n\" +\n\t\"\\x05Event\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12(\\n\" +\n\t\"\\x04data\\x18\\x02 \\x01(\\v2\\x14.google.protobuf.AnyR\\x04data\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x03 \\x01(\\tR\\x02id\\x12\\x19\\n\" +\n\t\"\\bactor_id\\x18\\x04 \\x01(\\tR\\aactorId\\\">\\n\" +\n\t\"\\x12ResetPartitionSpec\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x01 \\x01(\\tR\\x05label\\x12\\x12\\n\" +\n\t\"\\x04wipe\\x18\\x02 \\x01(\\bR\\x04wipe\\\"\\xb1\\x02\\n\" +\n\t\"\\fResetRequest\\x12\\x1a\\n\" +\n\t\"\\bgraceful\\x18\\x01 \\x01(\\bR\\bgraceful\\x12\\x16\\n\" +\n\t\"\\x06reboot\\x18\\x02 \\x01(\\bR\\x06reboot\\x12V\\n\" +\n\t\"\\x19system_partitions_to_wipe\\x18\\x03 \\x03(\\v2\\x1b.machine.ResetPartitionSpecR\\x16systemPartitionsToWipe\\x12+\\n\" +\n\t\"\\x12user_disks_to_wipe\\x18\\x04 \\x03(\\tR\\x0fuserDisksToWipe\\x122\\n\" +\n\t\"\\x04mode\\x18\\x05 \\x01(\\x0e2\\x1e.machine.ResetRequest.WipeModeR\\x04mode\\\"4\\n\" +\n\t\"\\bWipeMode\\x12\\a\\n\" +\n\t\"\\x03ALL\\x10\\x00\\x12\\x0f\\n\" +\n\t\"\\vSYSTEM_DISK\\x10\\x01\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"USER_DISKS\\x10\\x02\\\"P\\n\" +\n\t\"\\x05Reset\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x19\\n\" +\n\t\"\\bactor_id\\x18\\x02 \\x01(\\tR\\aactorId\\\";\\n\" +\n\t\"\\rResetResponse\\x12*\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0e.machine.ResetR\\bmessages\\\"S\\n\" +\n\t\"\\bShutdown\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x19\\n\" +\n\t\"\\bactor_id\\x18\\x02 \\x01(\\tR\\aactorId\\\"'\\n\" +\n\t\"\\x0fShutdownRequest\\x12\\x14\\n\" +\n\t\"\\x05force\\x18\\x01 \\x01(\\bR\\x05force\\\"A\\n\" +\n\t\"\\x10ShutdownResponse\\x12-\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x11.machine.ShutdownR\\bmessages\\\"\\xde\\x01\\n\" +\n\t\"\\x0eUpgradeRequest\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12\\x1a\\n\" +\n\t\"\\bpreserve\\x18\\x02 \\x01(\\bR\\bpreserve\\x12\\x14\\n\" +\n\t\"\\x05stage\\x18\\x03 \\x01(\\bR\\x05stage\\x12\\x14\\n\" +\n\t\"\\x05force\\x18\\x04 \\x01(\\bR\\x05force\\x12C\\n\" +\n\t\"\\vreboot_mode\\x18\\x05 \\x01(\\x0e2\\\".machine.UpgradeRequest.RebootModeR\\n\" +\n\t\"rebootMode\\\")\\n\" +\n\t\"\\n\" +\n\t\"RebootMode\\x12\\v\\n\" +\n\t\"\\aDEFAULT\\x10\\x00\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"POWERCYCLE\\x10\\x01\\\"d\\n\" +\n\t\"\\aUpgrade\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x10\\n\" +\n\t\"\\x03ack\\x18\\x02 \\x01(\\tR\\x03ack\\x12\\x19\\n\" +\n\t\"\\bactor_id\\x18\\x03 \\x01(\\tR\\aactorId\\\"?\\n\" +\n\t\"\\x0fUpgradeResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.UpgradeR\\bmessages\\\"m\\n\" +\n\t\"\\vServiceList\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x120\\n\" +\n\t\"\\bservices\\x18\\x02 \\x03(\\v2\\x14.machine.ServiceInfoR\\bservices\\\"G\\n\" +\n\t\"\\x13ServiceListResponse\\x120\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x14.machine.ServiceListR\\bmessages\\\"\\x93\\x01\\n\" +\n\t\"\\vServiceInfo\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x01 \\x01(\\tR\\x02id\\x12\\x14\\n\" +\n\t\"\\x05state\\x18\\x02 \\x01(\\tR\\x05state\\x12.\\n\" +\n\t\"\\x06events\\x18\\x03 \\x01(\\v2\\x16.machine.ServiceEventsR\\x06events\\x12.\\n\" +\n\t\"\\x06health\\x18\\x04 \\x01(\\v2\\x16.machine.ServiceHealthR\\x06health\\\">\\n\" +\n\t\"\\rServiceEvents\\x12-\\n\" +\n\t\"\\x06events\\x18\\x01 \\x03(\\v2\\x15.machine.ServiceEventR\\x06events\\\"b\\n\" +\n\t\"\\fServiceEvent\\x12\\x10\\n\" +\n\t\"\\x03msg\\x18\\x01 \\x01(\\tR\\x03msg\\x12\\x14\\n\" +\n\t\"\\x05state\\x18\\x02 \\x01(\\tR\\x05state\\x12*\\n\" +\n\t\"\\x02ts\\x18\\x03 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\x02ts\\\"\\xa3\\x01\\n\" +\n\t\"\\rServiceHealth\\x12\\x18\\n\" +\n\t\"\\aunknown\\x18\\x01 \\x01(\\bR\\aunknown\\x12\\x18\\n\" +\n\t\"\\ahealthy\\x18\\x02 \\x01(\\bR\\ahealthy\\x12!\\n\" +\n\t\"\\flast_message\\x18\\x03 \\x01(\\tR\\vlastMessage\\x12;\\n\" +\n\t\"\\vlast_change\\x18\\x04 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\n\" +\n\t\"lastChange\\\"%\\n\" +\n\t\"\\x13ServiceStartRequest\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x01 \\x01(\\tR\\x02id\\\"P\\n\" +\n\t\"\\fServiceStart\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04resp\\x18\\x02 \\x01(\\tR\\x04resp\\\"I\\n\" +\n\t\"\\x14ServiceStartResponse\\x121\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x15.machine.ServiceStartR\\bmessages\\\"$\\n\" +\n\t\"\\x12ServiceStopRequest\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x01 \\x01(\\tR\\x02id\\\"O\\n\" +\n\t\"\\vServiceStop\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04resp\\x18\\x02 \\x01(\\tR\\x04resp\\\"G\\n\" +\n\t\"\\x13ServiceStopResponse\\x120\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x14.machine.ServiceStopR\\bmessages\\\"'\\n\" +\n\t\"\\x15ServiceRestartRequest\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x01 \\x01(\\tR\\x02id\\\"R\\n\" +\n\t\"\\x0eServiceRestart\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04resp\\x18\\x02 \\x01(\\tR\\x04resp\\\"M\\n\" +\n\t\"\\x16ServiceRestartResponse\\x123\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x17.machine.ServiceRestartR\\bmessages\\\"*\\n\" +\n\t\"\\vCopyRequest\\x12\\x1b\\n\" +\n\t\"\\troot_path\\x18\\x01 \\x01(\\tR\\brootPath\\\"\\xeb\\x01\\n\" +\n\t\"\\vListRequest\\x12\\x12\\n\" +\n\t\"\\x04root\\x18\\x01 \\x01(\\tR\\x04root\\x12\\x18\\n\" +\n\t\"\\arecurse\\x18\\x02 \\x01(\\bR\\arecurse\\x12'\\n\" +\n\t\"\\x0frecursion_depth\\x18\\x03 \\x01(\\x05R\\x0erecursionDepth\\x12/\\n\" +\n\t\"\\x05types\\x18\\x04 \\x03(\\x0e2\\x19.machine.ListRequest.TypeR\\x05types\\x12#\\n\" +\n\t\"\\rreport_xattrs\\x18\\x05 \\x01(\\bR\\freportXattrs\\\"/\\n\" +\n\t\"\\x04Type\\x12\\v\\n\" +\n\t\"\\aREGULAR\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tDIRECTORY\\x10\\x01\\x12\\v\\n\" +\n\t\"\\aSYMLINK\\x10\\x02\\\"\\x81\\x01\\n\" +\n\t\"\\x10DiskUsageRequest\\x12'\\n\" +\n\t\"\\x0frecursion_depth\\x18\\x01 \\x01(\\x05R\\x0erecursionDepth\\x12\\x10\\n\" +\n\t\"\\x03all\\x18\\x02 \\x01(\\bR\\x03all\\x12\\x1c\\n\" +\n\t\"\\tthreshold\\x18\\x03 \\x01(\\x03R\\tthreshold\\x12\\x14\\n\" +\n\t\"\\x05paths\\x18\\x04 \\x03(\\tR\\x05paths\\\"\\xc2\\x02\\n\" +\n\t\"\\bFileInfo\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x03 \\x01(\\x03R\\x04size\\x12\\x12\\n\" +\n\t\"\\x04mode\\x18\\x04 \\x01(\\rR\\x04mode\\x12\\x1a\\n\" +\n\t\"\\bmodified\\x18\\x05 \\x01(\\x03R\\bmodified\\x12\\x15\\n\" +\n\t\"\\x06is_dir\\x18\\x06 \\x01(\\bR\\x05isDir\\x12\\x14\\n\" +\n\t\"\\x05error\\x18\\a \\x01(\\tR\\x05error\\x12\\x12\\n\" +\n\t\"\\x04link\\x18\\b \\x01(\\tR\\x04link\\x12#\\n\" +\n\t\"\\rrelative_name\\x18\\t \\x01(\\tR\\frelativeName\\x12\\x10\\n\" +\n\t\"\\x03uid\\x18\\n\" +\n\t\" \\x01(\\rR\\x03uid\\x12\\x10\\n\" +\n\t\"\\x03gid\\x18\\v \\x01(\\rR\\x03gid\\x12&\\n\" +\n\t\"\\x06xattrs\\x18\\f \\x03(\\v2\\x0e.machine.XattrR\\x06xattrs\\\"/\\n\" +\n\t\"\\x05Xattr\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04data\\x18\\x02 \\x01(\\fR\\x04data\\\"\\xa0\\x01\\n\" +\n\t\"\\rDiskUsageInfo\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x03 \\x01(\\x03R\\x04size\\x12\\x14\\n\" +\n\t\"\\x05error\\x18\\x04 \\x01(\\tR\\x05error\\x12#\\n\" +\n\t\"\\rrelative_name\\x18\\x05 \\x01(\\tR\\frelativeName\\\"`\\n\" +\n\t\"\\x06Mounts\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12(\\n\" +\n\t\"\\x05stats\\x18\\x02 \\x03(\\v2\\x12.machine.MountStatR\\x05stats\\\"=\\n\" +\n\t\"\\x0eMountsResponse\\x12+\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0f.machine.MountsR\\bmessages\\\"|\\n\" +\n\t\"\\tMountStat\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"filesystem\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"filesystem\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x02 \\x01(\\x04R\\x04size\\x12\\x1c\\n\" +\n\t\"\\tavailable\\x18\\x03 \\x01(\\x04R\\tavailable\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"mounted_on\\x18\\x04 \\x01(\\tR\\tmountedOn\\\"\\xcd\\x01\\n\" +\n\t\"\\aVersion\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12.\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\v2\\x14.machine.VersionInfoR\\aversion\\x121\\n\" +\n\t\"\\bplatform\\x18\\x03 \\x01(\\v2\\x15.machine.PlatformInfoR\\bplatform\\x121\\n\" +\n\t\"\\bfeatures\\x18\\x04 \\x01(\\v2\\x15.machine.FeaturesInfoR\\bfeatures\\\"?\\n\" +\n\t\"\\x0fVersionResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.VersionR\\bmessages\\\"\\x8a\\x01\\n\" +\n\t\"\\vVersionInfo\\x12\\x10\\n\" +\n\t\"\\x03tag\\x18\\x01 \\x01(\\tR\\x03tag\\x12\\x10\\n\" +\n\t\"\\x03sha\\x18\\x02 \\x01(\\tR\\x03sha\\x12\\x14\\n\" +\n\t\"\\x05built\\x18\\x03 \\x01(\\tR\\x05built\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"go_version\\x18\\x04 \\x01(\\tR\\tgoVersion\\x12\\x0e\\n\" +\n\t\"\\x02os\\x18\\x05 \\x01(\\tR\\x02os\\x12\\x12\\n\" +\n\t\"\\x04arch\\x18\\x06 \\x01(\\tR\\x04arch\\\"6\\n\" +\n\t\"\\fPlatformInfo\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04mode\\x18\\x02 \\x01(\\tR\\x04mode\\\"\\\"\\n\" +\n\t\"\\fFeaturesInfo\\x12\\x12\\n\" +\n\t\"\\x04rbac\\x18\\x01 \\x01(\\bR\\x04rbac\\\"\\xa3\\x01\\n\" +\n\t\"\\vLogsRequest\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x02 \\x01(\\tR\\x02id\\x12/\\n\" +\n\t\"\\x06driver\\x18\\x03 \\x01(\\x0e2\\x17.common.ContainerDriverR\\x06driver\\x12\\x16\\n\" +\n\t\"\\x06follow\\x18\\x04 \\x01(\\bR\\x06follow\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"tail_lines\\x18\\x05 \\x01(\\x05R\\ttailLines\\\"!\\n\" +\n\t\"\\vReadRequest\\x12\\x12\\n\" +\n\t\"\\x04path\\x18\\x01 \\x01(\\tR\\x04path\\\"O\\n\" +\n\t\"\\rLogsContainer\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x10\\n\" +\n\t\"\\x03ids\\x18\\x02 \\x03(\\tR\\x03ids\\\"L\\n\" +\n\t\"\\x16LogsContainersResponse\\x122\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x16.machine.LogsContainerR\\bmessages\\\"\\x11\\n\" +\n\t\"\\x0fRollbackRequest\\\"8\\n\" +\n\t\"\\bRollback\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"A\\n\" +\n\t\"\\x10RollbackResponse\\x12-\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x11.machine.RollbackR\\bmessages\\\"b\\n\" +\n\t\"\\x11ContainersRequest\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12/\\n\" +\n\t\"\\x06driver\\x18\\x02 \\x01(\\x0e2\\x17.common.ContainerDriverR\\x06driver\\\"\\x88\\x02\\n\" +\n\t\"\\rContainerInfo\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x02 \\x01(\\tR\\x02id\\x12\\x10\\n\" +\n\t\"\\x03uid\\x18\\n\" +\n\t\" \\x01(\\tR\\x03uid\\x12\\x1f\\n\" +\n\t\"\\vinternal_id\\x18\\t \\x01(\\tR\\n\" +\n\t\"internalId\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x03 \\x01(\\tR\\x05image\\x12\\x10\\n\" +\n\t\"\\x03pid\\x18\\x04 \\x01(\\rR\\x03pid\\x12\\x16\\n\" +\n\t\"\\x06status\\x18\\x05 \\x01(\\tR\\x06status\\x12\\x15\\n\" +\n\t\"\\x06pod_id\\x18\\x06 \\x01(\\tR\\x05podId\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\a \\x01(\\tR\\x04name\\x12+\\n\" +\n\t\"\\x11network_namespace\\x18\\b \\x01(\\tR\\x10networkNamespace\\\"q\\n\" +\n\t\"\\tContainer\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x126\\n\" +\n\t\"\\n\" +\n\t\"containers\\x18\\x02 \\x03(\\v2\\x16.machine.ContainerInfoR\\n\" +\n\t\"containers\\\"D\\n\" +\n\t\"\\x12ContainersResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.ContainerR\\bmessages\\\":\\n\" +\n\t\"\\fDmesgRequest\\x12\\x16\\n\" +\n\t\"\\x06follow\\x18\\x01 \\x01(\\bR\\x06follow\\x12\\x12\\n\" +\n\t\"\\x04tail\\x18\\x02 \\x01(\\bR\\x04tail\\\"A\\n\" +\n\t\"\\x11ProcessesResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.ProcessR\\bmessages\\\"k\\n\" +\n\t\"\\aProcess\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x122\\n\" +\n\t\"\\tprocesses\\x18\\x02 \\x03(\\v2\\x14.machine.ProcessInfoR\\tprocesses\\\"\\xb2\\x02\\n\" +\n\t\"\\vProcessInfo\\x12\\x10\\n\" +\n\t\"\\x03pid\\x18\\x01 \\x01(\\x05R\\x03pid\\x12\\x12\\n\" +\n\t\"\\x04ppid\\x18\\x02 \\x01(\\x05R\\x04ppid\\x12\\x14\\n\" +\n\t\"\\x05state\\x18\\x03 \\x01(\\tR\\x05state\\x12\\x18\\n\" +\n\t\"\\athreads\\x18\\x04 \\x01(\\x05R\\athreads\\x12\\x19\\n\" +\n\t\"\\bcpu_time\\x18\\x05 \\x01(\\x01R\\acpuTime\\x12%\\n\" +\n\t\"\\x0evirtual_memory\\x18\\x06 \\x01(\\x04R\\rvirtualMemory\\x12'\\n\" +\n\t\"\\x0fresident_memory\\x18\\a \\x01(\\x04R\\x0eresidentMemory\\x12\\x18\\n\" +\n\t\"\\acommand\\x18\\b \\x01(\\tR\\acommand\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"executable\\x18\\t \\x01(\\tR\\n\" +\n\t\"executable\\x12\\x12\\n\" +\n\t\"\\x04args\\x18\\n\" +\n\t\" \\x01(\\tR\\x04args\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\v \\x01(\\tR\\x05label\\\"o\\n\" +\n\t\"\\x0eRestartRequest\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x02 \\x01(\\tR\\x02id\\x12/\\n\" +\n\t\"\\x06driver\\x18\\x03 \\x01(\\x0e2\\x17.common.ContainerDriverR\\x06driver\\\"7\\n\" +\n\t\"\\aRestart\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"?\\n\" +\n\t\"\\x0fRestartResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.RestartR\\bmessages\\\"]\\n\" +\n\t\"\\fStatsRequest\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12/\\n\" +\n\t\"\\x06driver\\x18\\x02 \\x01(\\x0e2\\x17.common.ContainerDriverR\\x06driver\\\"Z\\n\" +\n\t\"\\x05Stats\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12#\\n\" +\n\t\"\\x05stats\\x18\\x02 \\x03(\\v2\\r.machine.StatR\\x05stats\\\";\\n\" +\n\t\"\\rStatsResponse\\x12*\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0e.machine.StatsR\\bmessages\\\"\\x9f\\x01\\n\" +\n\t\"\\x04Stat\\x12\\x1c\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\tR\\tnamespace\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x02 \\x01(\\tR\\x02id\\x12!\\n\" +\n\t\"\\fmemory_usage\\x18\\x04 \\x01(\\x04R\\vmemoryUsage\\x12\\x1b\\n\" +\n\t\"\\tcpu_usage\\x18\\x05 \\x01(\\x04R\\bcpuUsage\\x12\\x15\\n\" +\n\t\"\\x06pod_id\\x18\\x06 \\x01(\\tR\\x05podId\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\a \\x01(\\tR\\x04name\\\"b\\n\" +\n\t\"\\x06Memory\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12*\\n\" +\n\t\"\\ameminfo\\x18\\x02 \\x01(\\v2\\x10.machine.MemInfoR\\ameminfo\\\"=\\n\" +\n\t\"\\x0eMemoryResponse\\x12+\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0f.machine.MemoryR\\bmessages\\\"\\x8b\\f\\n\" +\n\t\"\\aMemInfo\\x12\\x1a\\n\" +\n\t\"\\bmemtotal\\x18\\x01 \\x01(\\x04R\\bmemtotal\\x12\\x18\\n\" +\n\t\"\\amemfree\\x18\\x02 \\x01(\\x04R\\amemfree\\x12\\\"\\n\" +\n\t\"\\fmemavailable\\x18\\x03 \\x01(\\x04R\\fmemavailable\\x12\\x18\\n\" +\n\t\"\\abuffers\\x18\\x04 \\x01(\\x04R\\abuffers\\x12\\x16\\n\" +\n\t\"\\x06cached\\x18\\x05 \\x01(\\x04R\\x06cached\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"swapcached\\x18\\x06 \\x01(\\x04R\\n\" +\n\t\"swapcached\\x12\\x16\\n\" +\n\t\"\\x06active\\x18\\a \\x01(\\x04R\\x06active\\x12\\x1a\\n\" +\n\t\"\\binactive\\x18\\b \\x01(\\x04R\\binactive\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"activeanon\\x18\\t \\x01(\\x04R\\n\" +\n\t\"activeanon\\x12\\\"\\n\" +\n\t\"\\finactiveanon\\x18\\n\" +\n\t\" \\x01(\\x04R\\finactiveanon\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"activefile\\x18\\v \\x01(\\x04R\\n\" +\n\t\"activefile\\x12\\\"\\n\" +\n\t\"\\finactivefile\\x18\\f \\x01(\\x04R\\finactivefile\\x12 \\n\" +\n\t\"\\vunevictable\\x18\\r \\x01(\\x04R\\vunevictable\\x12\\x18\\n\" +\n\t\"\\amlocked\\x18\\x0e \\x01(\\x04R\\amlocked\\x12\\x1c\\n\" +\n\t\"\\tswaptotal\\x18\\x0f \\x01(\\x04R\\tswaptotal\\x12\\x1a\\n\" +\n\t\"\\bswapfree\\x18\\x10 \\x01(\\x04R\\bswapfree\\x12\\x14\\n\" +\n\t\"\\x05dirty\\x18\\x11 \\x01(\\x04R\\x05dirty\\x12\\x1c\\n\" +\n\t\"\\twriteback\\x18\\x12 \\x01(\\x04R\\twriteback\\x12\\x1c\\n\" +\n\t\"\\tanonpages\\x18\\x13 \\x01(\\x04R\\tanonpages\\x12\\x16\\n\" +\n\t\"\\x06mapped\\x18\\x14 \\x01(\\x04R\\x06mapped\\x12\\x14\\n\" +\n\t\"\\x05shmem\\x18\\x15 \\x01(\\x04R\\x05shmem\\x12\\x12\\n\" +\n\t\"\\x04slab\\x18\\x16 \\x01(\\x04R\\x04slab\\x12\\\"\\n\" +\n\t\"\\fsreclaimable\\x18\\x17 \\x01(\\x04R\\fsreclaimable\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"sunreclaim\\x18\\x18 \\x01(\\x04R\\n\" +\n\t\"sunreclaim\\x12 \\n\" +\n\t\"\\vkernelstack\\x18\\x19 \\x01(\\x04R\\vkernelstack\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"pagetables\\x18\\x1a \\x01(\\x04R\\n\" +\n\t\"pagetables\\x12 \\n\" +\n\t\"\\vnfsunstable\\x18\\x1b \\x01(\\x04R\\vnfsunstable\\x12\\x16\\n\" +\n\t\"\\x06bounce\\x18\\x1c \\x01(\\x04R\\x06bounce\\x12\\\"\\n\" +\n\t\"\\fwritebacktmp\\x18\\x1d \\x01(\\x04R\\fwritebacktmp\\x12 \\n\" +\n\t\"\\vcommitlimit\\x18\\x1e \\x01(\\x04R\\vcommitlimit\\x12 \\n\" +\n\t\"\\vcommittedas\\x18\\x1f \\x01(\\x04R\\vcommittedas\\x12\\\"\\n\" +\n\t\"\\fvmalloctotal\\x18  \\x01(\\x04R\\fvmalloctotal\\x12 \\n\" +\n\t\"\\vvmallocused\\x18! \\x01(\\x04R\\vvmallocused\\x12\\\"\\n\" +\n\t\"\\fvmallocchunk\\x18\\\" \\x01(\\x04R\\fvmallocchunk\\x12,\\n\" +\n\t\"\\x11hardwarecorrupted\\x18# \\x01(\\x04R\\x11hardwarecorrupted\\x12$\\n\" +\n\t\"\\ranonhugepages\\x18$ \\x01(\\x04R\\ranonhugepages\\x12&\\n\" +\n\t\"\\x0eshmemhugepages\\x18% \\x01(\\x04R\\x0eshmemhugepages\\x12&\\n\" +\n\t\"\\x0eshmempmdmapped\\x18& \\x01(\\x04R\\x0eshmempmdmapped\\x12\\x1a\\n\" +\n\t\"\\bcmatotal\\x18' \\x01(\\x04R\\bcmatotal\\x12\\x18\\n\" +\n\t\"\\acmafree\\x18( \\x01(\\x04R\\acmafree\\x12&\\n\" +\n\t\"\\x0ehugepagestotal\\x18) \\x01(\\x04R\\x0ehugepagestotal\\x12$\\n\" +\n\t\"\\rhugepagesfree\\x18* \\x01(\\x04R\\rhugepagesfree\\x12$\\n\" +\n\t\"\\rhugepagesrsvd\\x18+ \\x01(\\x04R\\rhugepagesrsvd\\x12$\\n\" +\n\t\"\\rhugepagessurp\\x18, \\x01(\\x04R\\rhugepagessurp\\x12\\\"\\n\" +\n\t\"\\fhugepagesize\\x18- \\x01(\\x04R\\fhugepagesize\\x12 \\n\" +\n\t\"\\vdirectmap4k\\x18. \\x01(\\x04R\\vdirectmap4k\\x12 \\n\" +\n\t\"\\vdirectmap2m\\x18/ \\x01(\\x04R\\vdirectmap2m\\x12 \\n\" +\n\t\"\\vdirectmap1g\\x180 \\x01(\\x04R\\vdirectmap1g\\\"A\\n\" +\n\t\"\\x10HostnameResponse\\x12-\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x11.machine.HostnameR\\bmessages\\\"T\\n\" +\n\t\"\\bHostname\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x02 \\x01(\\tR\\bhostname\\\"?\\n\" +\n\t\"\\x0fLoadAvgResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.LoadAvgR\\bmessages\\\"{\\n\" +\n\t\"\\aLoadAvg\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x14\\n\" +\n\t\"\\x05load1\\x18\\x02 \\x01(\\x01R\\x05load1\\x12\\x14\\n\" +\n\t\"\\x05load5\\x18\\x03 \\x01(\\x01R\\x05load5\\x12\\x16\\n\" +\n\t\"\\x06load15\\x18\\x04 \\x01(\\x01R\\x06load15\\\"E\\n\" +\n\t\"\\x12SystemStatResponse\\x12/\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x13.machine.SystemStatR\\bmessages\\\"\\xd6\\x03\\n\" +\n\t\"\\n\" +\n\t\"SystemStat\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x1b\\n\" +\n\t\"\\tboot_time\\x18\\x02 \\x01(\\x04R\\bbootTime\\x12-\\n\" +\n\t\"\\tcpu_total\\x18\\x03 \\x01(\\v2\\x10.machine.CPUStatR\\bcpuTotal\\x12\\\"\\n\" +\n\t\"\\x03cpu\\x18\\x04 \\x03(\\v2\\x10.machine.CPUStatR\\x03cpu\\x12\\x1b\\n\" +\n\t\"\\tirq_total\\x18\\x05 \\x01(\\x04R\\birqTotal\\x12\\x10\\n\" +\n\t\"\\x03irq\\x18\\x06 \\x03(\\x04R\\x03irq\\x12)\\n\" +\n\t\"\\x10context_switches\\x18\\a \\x01(\\x04R\\x0fcontextSwitches\\x12'\\n\" +\n\t\"\\x0fprocess_created\\x18\\b \\x01(\\x04R\\x0eprocessCreated\\x12'\\n\" +\n\t\"\\x0fprocess_running\\x18\\t \\x01(\\x04R\\x0eprocessRunning\\x12'\\n\" +\n\t\"\\x0fprocess_blocked\\x18\\n\" +\n\t\" \\x01(\\x04R\\x0eprocessBlocked\\x12$\\n\" +\n\t\"\\x0esoft_irq_total\\x18\\v \\x01(\\x04R\\fsoftIrqTotal\\x12/\\n\" +\n\t\"\\bsoft_irq\\x18\\f \\x01(\\v2\\x14.machine.SoftIRQStatR\\asoftIrq\\\"\\xed\\x01\\n\" +\n\t\"\\aCPUStat\\x12\\x12\\n\" +\n\t\"\\x04user\\x18\\x01 \\x01(\\x01R\\x04user\\x12\\x12\\n\" +\n\t\"\\x04nice\\x18\\x02 \\x01(\\x01R\\x04nice\\x12\\x16\\n\" +\n\t\"\\x06system\\x18\\x03 \\x01(\\x01R\\x06system\\x12\\x12\\n\" +\n\t\"\\x04idle\\x18\\x04 \\x01(\\x01R\\x04idle\\x12\\x16\\n\" +\n\t\"\\x06iowait\\x18\\x05 \\x01(\\x01R\\x06iowait\\x12\\x10\\n\" +\n\t\"\\x03irq\\x18\\x06 \\x01(\\x01R\\x03irq\\x12\\x19\\n\" +\n\t\"\\bsoft_irq\\x18\\a \\x01(\\x01R\\asoftIrq\\x12\\x14\\n\" +\n\t\"\\x05steal\\x18\\b \\x01(\\x01R\\x05steal\\x12\\x14\\n\" +\n\t\"\\x05guest\\x18\\t \\x01(\\x01R\\x05guest\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"guest_nice\\x18\\n\" +\n\t\" \\x01(\\x01R\\tguestNice\\\"\\xf7\\x01\\n\" +\n\t\"\\vSoftIRQStat\\x12\\x0e\\n\" +\n\t\"\\x02hi\\x18\\x01 \\x01(\\x04R\\x02hi\\x12\\x14\\n\" +\n\t\"\\x05timer\\x18\\x02 \\x01(\\x04R\\x05timer\\x12\\x15\\n\" +\n\t\"\\x06net_tx\\x18\\x03 \\x01(\\x04R\\x05netTx\\x12\\x15\\n\" +\n\t\"\\x06net_rx\\x18\\x04 \\x01(\\x04R\\x05netRx\\x12\\x14\\n\" +\n\t\"\\x05block\\x18\\x05 \\x01(\\x04R\\x05block\\x12\\\"\\n\" +\n\t\"\\rblock_io_poll\\x18\\x06 \\x01(\\x04R\\vblockIoPoll\\x12\\x18\\n\" +\n\t\"\\atasklet\\x18\\a \\x01(\\x04R\\atasklet\\x12\\x14\\n\" +\n\t\"\\x05sched\\x18\\b \\x01(\\x04R\\x05sched\\x12\\x18\\n\" +\n\t\"\\ahrtimer\\x18\\t \\x01(\\x04R\\ahrtimer\\x12\\x10\\n\" +\n\t\"\\x03rcu\\x18\\n\" +\n\t\" \\x01(\\x04R\\x03rcu\\\"J\\n\" +\n\t\"\\x14CPUFreqStatsResponse\\x122\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x16.machine.CPUsFreqStatsR\\bmessages\\\"z\\n\" +\n\t\"\\rCPUsFreqStats\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12;\\n\" +\n\t\"\\x0ecpu_freq_stats\\x18\\x02 \\x03(\\v2\\x15.machine.CPUFreqStatsR\\fcpuFreqStats\\\"\\xb1\\x01\\n\" +\n\t\"\\fCPUFreqStats\\x12+\\n\" +\n\t\"\\x11current_frequency\\x18\\x01 \\x01(\\x04R\\x10currentFrequency\\x12+\\n\" +\n\t\"\\x11minimum_frequency\\x18\\x02 \\x01(\\x04R\\x10minimumFrequency\\x12+\\n\" +\n\t\"\\x11maximum_frequency\\x18\\x03 \\x01(\\x04R\\x10maximumFrequency\\x12\\x1a\\n\" +\n\t\"\\bgovernor\\x18\\x04 \\x01(\\tR\\bgovernor\\\"@\\n\" +\n\t\"\\x0fCPUInfoResponse\\x12-\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x11.machine.CPUsInfoR\\bmessages\\\"e\\n\" +\n\t\"\\bCPUsInfo\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12+\\n\" +\n\t\"\\bcpu_info\\x18\\x02 \\x03(\\v2\\x10.machine.CPUInfoR\\acpuInfo\\\"\\x8b\\x06\\n\" +\n\t\"\\aCPUInfo\\x12\\x1c\\n\" +\n\t\"\\tprocessor\\x18\\x01 \\x01(\\rR\\tprocessor\\x12\\x1b\\n\" +\n\t\"\\tvendor_id\\x18\\x02 \\x01(\\tR\\bvendorId\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"cpu_family\\x18\\x03 \\x01(\\tR\\tcpuFamily\\x12\\x14\\n\" +\n\t\"\\x05model\\x18\\x04 \\x01(\\tR\\x05model\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"model_name\\x18\\x05 \\x01(\\tR\\tmodelName\\x12\\x1a\\n\" +\n\t\"\\bstepping\\x18\\x06 \\x01(\\tR\\bstepping\\x12\\x1c\\n\" +\n\t\"\\tmicrocode\\x18\\a \\x01(\\tR\\tmicrocode\\x12\\x17\\n\" +\n\t\"\\acpu_mhz\\x18\\b \\x01(\\x01R\\x06cpuMhz\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"cache_size\\x18\\t \\x01(\\tR\\tcacheSize\\x12\\x1f\\n\" +\n\t\"\\vphysical_id\\x18\\n\" +\n\t\" \\x01(\\tR\\n\" +\n\t\"physicalId\\x12\\x1a\\n\" +\n\t\"\\bsiblings\\x18\\v \\x01(\\rR\\bsiblings\\x12\\x17\\n\" +\n\t\"\\acore_id\\x18\\f \\x01(\\tR\\x06coreId\\x12\\x1b\\n\" +\n\t\"\\tcpu_cores\\x18\\r \\x01(\\rR\\bcpuCores\\x12\\x17\\n\" +\n\t\"\\aapic_id\\x18\\x0e \\x01(\\tR\\x06apicId\\x12&\\n\" +\n\t\"\\x0finitial_apic_id\\x18\\x0f \\x01(\\tR\\rinitialApicId\\x12\\x10\\n\" +\n\t\"\\x03fpu\\x18\\x10 \\x01(\\tR\\x03fpu\\x12#\\n\" +\n\t\"\\rfpu_exception\\x18\\x11 \\x01(\\tR\\ffpuException\\x12 \\n\" +\n\t\"\\fcpu_id_level\\x18\\x12 \\x01(\\rR\\n\" +\n\t\"cpuIdLevel\\x12\\x0e\\n\" +\n\t\"\\x02wp\\x18\\x13 \\x01(\\tR\\x02wp\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\x14 \\x03(\\tR\\x05flags\\x12\\x12\\n\" +\n\t\"\\x04bugs\\x18\\x15 \\x03(\\tR\\x04bugs\\x12\\x1b\\n\" +\n\t\"\\tbogo_mips\\x18\\x16 \\x01(\\x01R\\bbogoMips\\x12\\\"\\n\" +\n\t\"\\rcl_flush_size\\x18\\x17 \\x01(\\rR\\vclFlushSize\\x12'\\n\" +\n\t\"\\x0fcache_alignment\\x18\\x18 \\x01(\\rR\\x0ecacheAlignment\\x12#\\n\" +\n\t\"\\raddress_sizes\\x18\\x19 \\x01(\\tR\\faddressSizes\\x12)\\n\" +\n\t\"\\x10power_management\\x18\\x1a \\x01(\\tR\\x0fpowerManagement\\\"U\\n\" +\n\t\"\\x1aNetworkDeviceStatsResponse\\x127\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1b.machine.NetworkDeviceStatsR\\bmessages\\\"\\x94\\x01\\n\" +\n\t\"\\x12NetworkDeviceStats\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12%\\n\" +\n\t\"\\x05total\\x18\\x02 \\x01(\\v2\\x0f.machine.NetDevR\\x05total\\x12)\\n\" +\n\t\"\\adevices\\x18\\x03 \\x03(\\v2\\x0f.machine.NetDevR\\adevices\\\"\\x86\\x04\\n\" +\n\t\"\\x06NetDev\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x19\\n\" +\n\t\"\\brx_bytes\\x18\\x02 \\x01(\\x04R\\arxBytes\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"rx_packets\\x18\\x03 \\x01(\\x04R\\trxPackets\\x12\\x1b\\n\" +\n\t\"\\trx_errors\\x18\\x04 \\x01(\\x04R\\brxErrors\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"rx_dropped\\x18\\x05 \\x01(\\x04R\\trxDropped\\x12\\x17\\n\" +\n\t\"\\arx_fifo\\x18\\x06 \\x01(\\x04R\\x06rxFifo\\x12\\x19\\n\" +\n\t\"\\brx_frame\\x18\\a \\x01(\\x04R\\arxFrame\\x12#\\n\" +\n\t\"\\rrx_compressed\\x18\\b \\x01(\\x04R\\frxCompressed\\x12!\\n\" +\n\t\"\\frx_multicast\\x18\\t \\x01(\\x04R\\vrxMulticast\\x12\\x19\\n\" +\n\t\"\\btx_bytes\\x18\\n\" +\n\t\" \\x01(\\x04R\\atxBytes\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"tx_packets\\x18\\v \\x01(\\x04R\\ttxPackets\\x12\\x1b\\n\" +\n\t\"\\ttx_errors\\x18\\f \\x01(\\x04R\\btxErrors\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"tx_dropped\\x18\\r \\x01(\\x04R\\ttxDropped\\x12\\x17\\n\" +\n\t\"\\atx_fifo\\x18\\x0e \\x01(\\x04R\\x06txFifo\\x12#\\n\" +\n\t\"\\rtx_collisions\\x18\\x0f \\x01(\\x04R\\ftxCollisions\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"tx_carrier\\x18\\x10 \\x01(\\x04R\\ttxCarrier\\x12#\\n\" +\n\t\"\\rtx_compressed\\x18\\x11 \\x01(\\x04R\\ftxCompressed\\\"C\\n\" +\n\t\"\\x11DiskStatsResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.DiskStatsR\\bmessages\\\"\\x8f\\x01\\n\" +\n\t\"\\tDiskStats\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12'\\n\" +\n\t\"\\x05total\\x18\\x02 \\x01(\\v2\\x11.machine.DiskStatR\\x05total\\x12+\\n\" +\n\t\"\\adevices\\x18\\x03 \\x03(\\v2\\x11.machine.DiskStatR\\adevices\\\"\\xd8\\x04\\n\" +\n\t\"\\bDiskStat\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12%\\n\" +\n\t\"\\x0eread_completed\\x18\\x02 \\x01(\\x04R\\rreadCompleted\\x12\\x1f\\n\" +\n\t\"\\vread_merged\\x18\\x03 \\x01(\\x04R\\n\" +\n\t\"readMerged\\x12!\\n\" +\n\t\"\\fread_sectors\\x18\\x04 \\x01(\\x04R\\vreadSectors\\x12 \\n\" +\n\t\"\\fread_time_ms\\x18\\x05 \\x01(\\x04R\\n\" +\n\t\"readTimeMs\\x12'\\n\" +\n\t\"\\x0fwrite_completed\\x18\\x06 \\x01(\\x04R\\x0ewriteCompleted\\x12!\\n\" +\n\t\"\\fwrite_merged\\x18\\a \\x01(\\x04R\\vwriteMerged\\x12#\\n\" +\n\t\"\\rwrite_sectors\\x18\\b \\x01(\\x04R\\fwriteSectors\\x12\\\"\\n\" +\n\t\"\\rwrite_time_ms\\x18\\t \\x01(\\x04R\\vwriteTimeMs\\x12$\\n\" +\n\t\"\\x0eio_in_progress\\x18\\n\" +\n\t\" \\x01(\\x04R\\fioInProgress\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"io_time_ms\\x18\\v \\x01(\\x04R\\bioTimeMs\\x12-\\n\" +\n\t\"\\x13io_time_weighted_ms\\x18\\f \\x01(\\x04R\\x10ioTimeWeightedMs\\x12+\\n\" +\n\t\"\\x11discard_completed\\x18\\r \\x01(\\x04R\\x10discardCompleted\\x12%\\n\" +\n\t\"\\x0ediscard_merged\\x18\\x0e \\x01(\\x04R\\rdiscardMerged\\x12'\\n\" +\n\t\"\\x0fdiscard_sectors\\x18\\x0f \\x01(\\x04R\\x0ediscardSectors\\x12&\\n\" +\n\t\"\\x0fdiscard_time_ms\\x18\\x10 \\x01(\\x04R\\rdiscardTimeMs\\\"\\x19\\n\" +\n\t\"\\x17EtcdLeaveClusterRequest\\\"@\\n\" +\n\t\"\\x10EtcdLeaveCluster\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"Q\\n\" +\n\t\"\\x18EtcdLeaveClusterResponse\\x125\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x19.machine.EtcdLeaveClusterR\\bmessages\\\"1\\n\" +\n\t\"\\x17EtcdRemoveMemberRequest\\x12\\x16\\n\" +\n\t\"\\x06member\\x18\\x01 \\x01(\\tR\\x06member\\\"@\\n\" +\n\t\"\\x10EtcdRemoveMember\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"Q\\n\" +\n\t\"\\x18EtcdRemoveMemberResponse\\x125\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x19.machine.EtcdRemoveMemberR\\bmessages\\\":\\n\" +\n\t\"\\x1bEtcdRemoveMemberByIDRequest\\x12\\x1b\\n\" +\n\t\"\\tmember_id\\x18\\x01 \\x01(\\x04R\\bmemberId\\\"D\\n\" +\n\t\"\\x14EtcdRemoveMemberByID\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"Y\\n\" +\n\t\"\\x1cEtcdRemoveMemberByIDResponse\\x129\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1d.machine.EtcdRemoveMemberByIDR\\bmessages\\\"\\x1e\\n\" +\n\t\"\\x1cEtcdForfeitLeadershipRequest\\\"]\\n\" +\n\t\"\\x15EtcdForfeitLeadership\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x16\\n\" +\n\t\"\\x06member\\x18\\x02 \\x01(\\tR\\x06member\\\"[\\n\" +\n\t\"\\x1dEtcdForfeitLeadershipResponse\\x12:\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1e.machine.EtcdForfeitLeadershipR\\bmessages\\\"8\\n\" +\n\t\"\\x15EtcdMemberListRequest\\x12\\x1f\\n\" +\n\t\"\\vquery_local\\x18\\x01 \\x01(\\bR\\n\" +\n\t\"queryLocal\\\"\\x95\\x01\\n\" +\n\t\"\\n\" +\n\t\"EtcdMember\\x12\\x0e\\n\" +\n\t\"\\x02id\\x18\\x02 \\x01(\\x04R\\x02id\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x03 \\x01(\\tR\\bhostname\\x12\\x1b\\n\" +\n\t\"\\tpeer_urls\\x18\\x04 \\x03(\\tR\\bpeerUrls\\x12\\x1f\\n\" +\n\t\"\\vclient_urls\\x18\\x05 \\x03(\\tR\\n\" +\n\t\"clientUrls\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"is_learner\\x18\\x06 \\x01(\\bR\\tisLearner\\\"\\x91\\x01\\n\" +\n\t\"\\vEtcdMembers\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12%\\n\" +\n\t\"\\x0elegacy_members\\x18\\x02 \\x03(\\tR\\rlegacyMembers\\x12-\\n\" +\n\t\"\\amembers\\x18\\x03 \\x03(\\v2\\x13.machine.EtcdMemberR\\amembers\\\"J\\n\" +\n\t\"\\x16EtcdMemberListResponse\\x120\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x14.machine.EtcdMembersR\\bmessages\\\"\\x15\\n\" +\n\t\"\\x13EtcdSnapshotRequest\\\";\\n\" +\n\t\"\\vEtcdRecover\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"G\\n\" +\n\t\"\\x13EtcdRecoverResponse\\x120\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x14.machine.EtcdRecoverR\\bmessages\\\"G\\n\" +\n\t\"\\x15EtcdAlarmListResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.EtcdAlarmR\\bmessages\\\"x\\n\" +\n\t\"\\tEtcdAlarm\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12=\\n\" +\n\t\"\\rmember_alarms\\x18\\x02 \\x03(\\v2\\x18.machine.EtcdMemberAlarmR\\fmemberAlarms\\\"\\x99\\x01\\n\" +\n\t\"\\x0fEtcdMemberAlarm\\x12\\x1b\\n\" +\n\t\"\\tmember_id\\x18\\x01 \\x01(\\x04R\\bmemberId\\x128\\n\" +\n\t\"\\x05alarm\\x18\\x02 \\x01(\\x0e2\\\".machine.EtcdMemberAlarm.AlarmTypeR\\x05alarm\\\"/\\n\" +\n\t\"\\tAlarmType\\x12\\b\\n\" +\n\t\"\\x04NONE\\x10\\x00\\x12\\v\\n\" +\n\t\"\\aNOSPACE\\x10\\x01\\x12\\v\\n\" +\n\t\"\\aCORRUPT\\x10\\x02\\\"O\\n\" +\n\t\"\\x17EtcdAlarmDisarmResponse\\x124\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x18.machine.EtcdAlarmDisarmR\\bmessages\\\"~\\n\" +\n\t\"\\x0fEtcdAlarmDisarm\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12=\\n\" +\n\t\"\\rmember_alarms\\x18\\x02 \\x03(\\v2\\x18.machine.EtcdMemberAlarmR\\fmemberAlarms\\\"M\\n\" +\n\t\"\\x16EtcdDefragmentResponse\\x123\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x17.machine.EtcdDefragmentR\\bmessages\\\">\\n\" +\n\t\"\\x0eEtcdDefragment\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"E\\n\" +\n\t\"\\x12EtcdStatusResponse\\x12/\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x13.machine.EtcdStatusR\\bmessages\\\"z\\n\" +\n\t\"\\n\" +\n\t\"EtcdStatus\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12>\\n\" +\n\t\"\\rmember_status\\x18\\x02 \\x01(\\v2\\x19.machine.EtcdMemberStatusR\\fmemberStatus\\\"\\xfa\\x02\\n\" +\n\t\"\\x10EtcdMemberStatus\\x12'\\n\" +\n\t\"\\x0fstorage_version\\x18\\v \\x01(\\tR\\x0estorageVersion\\x12\\x1b\\n\" +\n\t\"\\tmember_id\\x18\\n\" +\n\t\" \\x01(\\x04R\\bmemberId\\x12)\\n\" +\n\t\"\\x10protocol_version\\x18\\x01 \\x01(\\tR\\x0fprotocolVersion\\x12\\x17\\n\" +\n\t\"\\adb_size\\x18\\x02 \\x01(\\x03R\\x06dbSize\\x12#\\n\" +\n\t\"\\x0edb_size_in_use\\x18\\x03 \\x01(\\x03R\\vdbSizeInUse\\x12\\x16\\n\" +\n\t\"\\x06leader\\x18\\x04 \\x01(\\x04R\\x06leader\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"raft_index\\x18\\x05 \\x01(\\x04R\\traftIndex\\x12\\x1b\\n\" +\n\t\"\\traft_term\\x18\\x06 \\x01(\\x04R\\braftTerm\\x12,\\n\" +\n\t\"\\x12raft_applied_index\\x18\\a \\x01(\\x04R\\x10raftAppliedIndex\\x12\\x16\\n\" +\n\t\"\\x06errors\\x18\\b \\x03(\\tR\\x06errors\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"is_learner\\x18\\t \\x01(\\bR\\tisLearner\\\"8\\n\" +\n\t\"\\x1cEtcdDowngradeValidateRequest\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x01 \\x01(\\tR\\aversion\\\"[\\n\" +\n\t\"\\x1dEtcdDowngradeValidateResponse\\x12:\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1e.machine.EtcdDowngradeValidateR\\bmessages\\\"\\x91\\x01\\n\" +\n\t\"\\x15EtcdDowngradeValidate\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12J\\n\" +\n\t\"\\x11cluster_downgrade\\x18\\x02 \\x01(\\v2\\x1d.machine.EtcdClusterDowngradeR\\x10clusterDowngrade\\\"6\\n\" +\n\t\"\\x1aEtcdDowngradeEnableRequest\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x01 \\x01(\\tR\\aversion\\\"W\\n\" +\n\t\"\\x1bEtcdDowngradeEnableResponse\\x128\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1c.machine.EtcdDowngradeEnableR\\bmessages\\\"\\x8f\\x01\\n\" +\n\t\"\\x13EtcdDowngradeEnable\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12J\\n\" +\n\t\"\\x11cluster_downgrade\\x18\\x02 \\x01(\\v2\\x1d.machine.EtcdClusterDowngradeR\\x10clusterDowngrade\\\"W\\n\" +\n\t\"\\x1bEtcdDowngradeCancelResponse\\x128\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x1c.machine.EtcdDowngradeCancelR\\bmessages\\\"\\x8f\\x01\\n\" +\n\t\"\\x13EtcdDowngradeCancel\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12J\\n\" +\n\t\"\\x11cluster_downgrade\\x18\\x02 \\x01(\\v2\\x1d.machine.EtcdClusterDowngradeR\\x10clusterDowngrade\\\"?\\n\" +\n\t\"\\x14EtcdClusterDowngrade\\x12'\\n\" +\n\t\"\\x0fcluster_version\\x18\\x01 \\x01(\\tR\\x0eclusterVersion\\\"Y\\n\" +\n\t\"\\vRouteConfig\\x12\\x18\\n\" +\n\t\"\\anetwork\\x18\\x01 \\x01(\\tR\\anetwork\\x12\\x18\\n\" +\n\t\"\\agateway\\x18\\x02 \\x01(\\tR\\agateway\\x12\\x16\\n\" +\n\t\"\\x06metric\\x18\\x03 \\x01(\\rR\\x06metric\\\"6\\n\" +\n\t\"\\x11DHCPOptionsConfig\\x12!\\n\" +\n\t\"\\froute_metric\\x18\\x01 \\x01(\\rR\\vrouteMetric\\\"\\xf2\\x01\\n\" +\n\t\"\\x13NetworkDeviceConfig\\x12\\x1c\\n\" +\n\t\"\\tinterface\\x18\\x01 \\x01(\\tR\\tinterface\\x12\\x12\\n\" +\n\t\"\\x04cidr\\x18\\x02 \\x01(\\tR\\x04cidr\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\x03 \\x01(\\x05R\\x03mtu\\x12\\x12\\n\" +\n\t\"\\x04dhcp\\x18\\x04 \\x01(\\bR\\x04dhcp\\x12\\x16\\n\" +\n\t\"\\x06ignore\\x18\\x05 \\x01(\\bR\\x06ignore\\x12=\\n\" +\n\t\"\\fdhcp_options\\x18\\x06 \\x01(\\v2\\x1a.machine.DHCPOptionsConfigR\\vdhcpOptions\\x12,\\n\" +\n\t\"\\x06routes\\x18\\a \\x03(\\v2\\x14.machine.RouteConfigR\\x06routes\\\"i\\n\" +\n\t\"\\rNetworkConfig\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x01 \\x01(\\tR\\bhostname\\x12<\\n\" +\n\t\"\\n\" +\n\t\"interfaces\\x18\\x02 \\x03(\\v2\\x1c.machine.NetworkDeviceConfigR\\n\" +\n\t\"interfaces\\\"W\\n\" +\n\t\"\\rInstallConfig\\x12!\\n\" +\n\t\"\\finstall_disk\\x18\\x01 \\x01(\\tR\\vinstallDisk\\x12#\\n\" +\n\t\"\\rinstall_image\\x18\\x02 \\x01(\\tR\\finstallImage\\\"\\xcd\\x02\\n\" +\n\t\"\\rMachineConfig\\x126\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e2\\\".machine.MachineConfig.MachineTypeR\\x04type\\x12=\\n\" +\n\t\"\\x0einstall_config\\x18\\x02 \\x01(\\v2\\x16.machine.InstallConfigR\\rinstallConfig\\x12=\\n\" +\n\t\"\\x0enetwork_config\\x18\\x03 \\x01(\\v2\\x16.machine.NetworkConfigR\\rnetworkConfig\\x12-\\n\" +\n\t\"\\x12kubernetes_version\\x18\\x04 \\x01(\\tR\\x11kubernetesVersion\\\"W\\n\" +\n\t\"\\vMachineType\\x12\\x10\\n\" +\n\t\"\\fTYPE_UNKNOWN\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tTYPE_INIT\\x10\\x01\\x12\\x16\\n\" +\n\t\"\\x12TYPE_CONTROL_PLANE\\x10\\x02\\x12\\x0f\\n\" +\n\t\"\\vTYPE_WORKER\\x10\\x03\\\"0\\n\" +\n\t\"\\x12ControlPlaneConfig\\x12\\x1a\\n\" +\n\t\"\\bendpoint\\x18\\x01 \\x01(\\tR\\bendpoint\\\"3\\n\" +\n\t\"\\tCNIConfig\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04urls\\x18\\x02 \\x03(\\tR\\x04urls\\\"h\\n\" +\n\t\"\\x14ClusterNetworkConfig\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"dns_domain\\x18\\x01 \\x01(\\tR\\tdnsDomain\\x121\\n\" +\n\t\"\\n\" +\n\t\"cni_config\\x18\\x02 \\x01(\\v2\\x12.machine.CNIConfigR\\tcniConfig\\\"\\xf9\\x01\\n\" +\n\t\"\\rClusterConfig\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12@\\n\" +\n\t\"\\rcontrol_plane\\x18\\x02 \\x01(\\v2\\x1b.machine.ControlPlaneConfigR\\fcontrolPlane\\x12F\\n\" +\n\t\"\\x0fcluster_network\\x18\\x03 \\x01(\\v2\\x1d.machine.ClusterNetworkConfigR\\x0eclusterNetwork\\x12J\\n\" +\n\t\"\\\"allow_scheduling_on_control_planes\\x18\\x04 \\x01(\\bR\\x1eallowSchedulingOnControlPlanes\\\"n\\n\" +\n\t\"\\\"GenerateClientConfigurationRequest\\x12\\x14\\n\" +\n\t\"\\x05roles\\x18\\x01 \\x03(\\tR\\x05roles\\x122\\n\" +\n\t\"\\acrt_ttl\\x18\\x02 \\x01(\\v2\\x19.google.protobuf.DurationR\\x06crtTtl\\\"\\xa1\\x01\\n\" +\n\t\"\\x1bGenerateClientConfiguration\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x0e\\n\" +\n\t\"\\x02ca\\x18\\x02 \\x01(\\fR\\x02ca\\x12\\x10\\n\" +\n\t\"\\x03crt\\x18\\x03 \\x01(\\fR\\x03crt\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x04 \\x01(\\fR\\x03key\\x12 \\n\" +\n\t\"\\vtalosconfig\\x18\\x05 \\x01(\\fR\\vtalosconfig\\\"g\\n\" +\n\t\"#GenerateClientConfigurationResponse\\x12@\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2$.machine.GenerateClientConfigurationR\\bmessages\\\"\\xa9\\x01\\n\" +\n\t\"\\x14PacketCaptureRequest\\x12\\x1c\\n\" +\n\t\"\\tinterface\\x18\\x01 \\x01(\\tR\\tinterface\\x12 \\n\" +\n\t\"\\vpromiscuous\\x18\\x02 \\x01(\\bR\\vpromiscuous\\x12\\x19\\n\" +\n\t\"\\bsnap_len\\x18\\x03 \\x01(\\rR\\asnapLen\\x126\\n\" +\n\t\"\\n\" +\n\t\"bpf_filter\\x18\\x04 \\x03(\\v2\\x17.machine.BPFInstructionR\\tbpfFilter\\\"N\\n\" +\n\t\"\\x0eBPFInstruction\\x12\\x0e\\n\" +\n\t\"\\x02op\\x18\\x01 \\x01(\\rR\\x02op\\x12\\x0e\\n\" +\n\t\"\\x02jt\\x18\\x02 \\x01(\\rR\\x02jt\\x12\\x0e\\n\" +\n\t\"\\x02jf\\x18\\x03 \\x01(\\rR\\x02jf\\x12\\f\\n\" +\n\t\"\\x01k\\x18\\x04 \\x01(\\rR\\x01k\\\"\\xd2\\x04\\n\" +\n\t\"\\x0eNetstatRequest\\x126\\n\" +\n\t\"\\x06filter\\x18\\x01 \\x01(\\x0e2\\x1e.machine.NetstatRequest.FilterR\\x06filter\\x129\\n\" +\n\t\"\\afeature\\x18\\x02 \\x01(\\v2\\x1f.machine.NetstatRequest.FeatureR\\afeature\\x129\\n\" +\n\t\"\\al4proto\\x18\\x03 \\x01(\\v2\\x1f.machine.NetstatRequest.L4protoR\\al4proto\\x123\\n\" +\n\t\"\\x05netns\\x18\\x04 \\x01(\\v2\\x1d.machine.NetstatRequest.NetNSR\\x05netns\\x1a\\x1b\\n\" +\n\t\"\\aFeature\\x12\\x10\\n\" +\n\t\"\\x03pid\\x18\\x01 \\x01(\\bR\\x03pid\\x1a\\xb1\\x01\\n\" +\n\t\"\\aL4proto\\x12\\x10\\n\" +\n\t\"\\x03tcp\\x18\\x01 \\x01(\\bR\\x03tcp\\x12\\x12\\n\" +\n\t\"\\x04tcp6\\x18\\x02 \\x01(\\bR\\x04tcp6\\x12\\x10\\n\" +\n\t\"\\x03udp\\x18\\x03 \\x01(\\bR\\x03udp\\x12\\x12\\n\" +\n\t\"\\x04udp6\\x18\\x04 \\x01(\\bR\\x04udp6\\x12\\x18\\n\" +\n\t\"\\audplite\\x18\\x05 \\x01(\\bR\\audplite\\x12\\x1a\\n\" +\n\t\"\\budplite6\\x18\\x06 \\x01(\\bR\\budplite6\\x12\\x10\\n\" +\n\t\"\\x03raw\\x18\\a \\x01(\\bR\\x03raw\\x12\\x12\\n\" +\n\t\"\\x04raw6\\x18\\b \\x01(\\bR\\x04raw6\\x1a[\\n\" +\n\t\"\\x05NetNS\\x12 \\n\" +\n\t\"\\vhostnetwork\\x18\\x01 \\x01(\\bR\\vhostnetwork\\x12\\x14\\n\" +\n\t\"\\x05netns\\x18\\x02 \\x03(\\tR\\x05netns\\x12\\x1a\\n\" +\n\t\"\\ballnetns\\x18\\x03 \\x01(\\bR\\ballnetns\\\"/\\n\" +\n\t\"\\x06Filter\\x12\\a\\n\" +\n\t\"\\x03ALL\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tCONNECTED\\x10\\x01\\x12\\r\\n\" +\n\t\"\\tLISTENING\\x10\\x02\\\"\\xdc\\x06\\n\" +\n\t\"\\rConnectRecord\\x12\\x18\\n\" +\n\t\"\\al4proto\\x18\\x01 \\x01(\\tR\\al4proto\\x12\\x18\\n\" +\n\t\"\\alocalip\\x18\\x02 \\x01(\\tR\\alocalip\\x12\\x1c\\n\" +\n\t\"\\tlocalport\\x18\\x03 \\x01(\\rR\\tlocalport\\x12\\x1a\\n\" +\n\t\"\\bremoteip\\x18\\x04 \\x01(\\tR\\bremoteip\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"remoteport\\x18\\x05 \\x01(\\rR\\n\" +\n\t\"remoteport\\x122\\n\" +\n\t\"\\x05state\\x18\\x06 \\x01(\\x0e2\\x1c.machine.ConnectRecord.StateR\\x05state\\x12\\x18\\n\" +\n\t\"\\atxqueue\\x18\\a \\x01(\\x04R\\atxqueue\\x12\\x18\\n\" +\n\t\"\\arxqueue\\x18\\b \\x01(\\x04R\\arxqueue\\x122\\n\" +\n\t\"\\x02tr\\x18\\t \\x01(\\x0e2\\\".machine.ConnectRecord.TimerActiveR\\x02tr\\x12\\x1c\\n\" +\n\t\"\\ttimerwhen\\x18\\n\" +\n\t\" \\x01(\\x04R\\ttimerwhen\\x12\\x1a\\n\" +\n\t\"\\bretrnsmt\\x18\\v \\x01(\\x04R\\bretrnsmt\\x12\\x10\\n\" +\n\t\"\\x03uid\\x18\\f \\x01(\\rR\\x03uid\\x12\\x18\\n\" +\n\t\"\\atimeout\\x18\\r \\x01(\\x04R\\atimeout\\x12\\x14\\n\" +\n\t\"\\x05inode\\x18\\x0e \\x01(\\x04R\\x05inode\\x12\\x10\\n\" +\n\t\"\\x03ref\\x18\\x0f \\x01(\\x04R\\x03ref\\x12\\x18\\n\" +\n\t\"\\apointer\\x18\\x10 \\x01(\\x04R\\apointer\\x128\\n\" +\n\t\"\\aprocess\\x18\\x11 \\x01(\\v2\\x1e.machine.ConnectRecord.ProcessR\\aprocess\\x12\\x14\\n\" +\n\t\"\\x05netns\\x18\\x12 \\x01(\\tR\\x05netns\\x1a/\\n\" +\n\t\"\\aProcess\\x12\\x10\\n\" +\n\t\"\\x03pid\\x18\\x01 \\x01(\\rR\\x03pid\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\\"\\xaf\\x01\\n\" +\n\t\"\\x05State\\x12\\f\\n\" +\n\t\"\\bRESERVED\\x10\\x00\\x12\\x0f\\n\" +\n\t\"\\vESTABLISHED\\x10\\x01\\x12\\f\\n\" +\n\t\"\\bSYN_SENT\\x10\\x02\\x12\\f\\n\" +\n\t\"\\bSYN_RECV\\x10\\x03\\x12\\r\\n\" +\n\t\"\\tFIN_WAIT1\\x10\\x04\\x12\\r\\n\" +\n\t\"\\tFIN_WAIT2\\x10\\x05\\x12\\r\\n\" +\n\t\"\\tTIME_WAIT\\x10\\x06\\x12\\t\\n\" +\n\t\"\\x05CLOSE\\x10\\a\\x12\\r\\n\" +\n\t\"\\tCLOSEWAIT\\x10\\b\\x12\\v\\n\" +\n\t\"\\aLASTACK\\x10\\t\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06LISTEN\\x10\\n\" +\n\t\"\\x12\\v\\n\" +\n\t\"\\aCLOSING\\x10\\v\\\"F\\n\" +\n\t\"\\vTimerActive\\x12\\a\\n\" +\n\t\"\\x03OFF\\x10\\x00\\x12\\x06\\n\" +\n\t\"\\x02ON\\x10\\x01\\x12\\r\\n\" +\n\t\"\\tKEEPALIVE\\x10\\x02\\x12\\f\\n\" +\n\t\"\\bTIMEWAIT\\x10\\x03\\x12\\t\\n\" +\n\t\"\\x05PROBE\\x10\\x04\\\"u\\n\" +\n\t\"\\aNetstat\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12<\\n\" +\n\t\"\\rconnectrecord\\x18\\x02 \\x03(\\v2\\x16.machine.ConnectRecordR\\rconnectrecord\\\"?\\n\" +\n\t\"\\x0fNetstatResponse\\x12,\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x10.machine.NetstatR\\bmessages\\\":\\n\" +\n\t\"\\x10MetaWriteRequest\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\rR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\fR\\x05value\\\"9\\n\" +\n\t\"\\tMetaWrite\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"C\\n\" +\n\t\"\\x11MetaWriteResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.MetaWriteR\\bmessages\\\"%\\n\" +\n\t\"\\x11MetaDeleteRequest\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\rR\\x03key\\\":\\n\" +\n\t\"\\n\" +\n\t\"MetaDelete\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"E\\n\" +\n\t\"\\x12MetaDeleteResponse\\x12/\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x13.machine.MetaDeleteR\\bmessages\\\"M\\n\" +\n\t\"\\x10ImageListRequest\\x129\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\x0e2\\x1b.common.ContainerdNamespaceR\\tnamespace\\\"\\xbc\\x01\\n\" +\n\t\"\\x11ImageListResponse\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06digest\\x18\\x03 \\x01(\\tR\\x06digest\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x04 \\x01(\\x03R\\x04size\\x129\\n\" +\n\t\"\\n\" +\n\t\"created_at\\x18\\x05 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\tcreatedAt\\\"k\\n\" +\n\t\"\\x10ImagePullRequest\\x129\\n\" +\n\t\"\\tnamespace\\x18\\x01 \\x01(\\x0e2\\x1b.common.ContainerdNamespaceR\\tnamespace\\x12\\x1c\\n\" +\n\t\"\\treference\\x18\\x02 \\x01(\\tR\\treference\\\"9\\n\" +\n\t\"\\tImagePull\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\\"C\\n\" +\n\t\"\\x11ImagePullResponse\\x12.\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x12.machine.ImagePullR\\bmessages2\\xef\\x1d\\n\" +\n\t\"\\x0eMachineService\\x12]\\n\" +\n\t\"\\x12ApplyConfiguration\\x12\\\".machine.ApplyConfigurationRequest\\x1a#.machine.ApplyConfigurationResponse\\x12B\\n\" +\n\t\"\\tBootstrap\\x12\\x19.machine.BootstrapRequest\\x1a\\x1a.machine.BootstrapResponse\\x12E\\n\" +\n\t\"\\n\" +\n\t\"Containers\\x12\\x1a.machine.ContainersRequest\\x1a\\x1b.machine.ContainersResponse\\x12,\\n\" +\n\t\"\\x04Copy\\x12\\x14.machine.CopyRequest\\x1a\\f.common.Data0\\x01\\x12E\\n\" +\n\t\"\\fCPUFreqStats\\x12\\x16.google.protobuf.Empty\\x1a\\x1d.machine.CPUFreqStatsResponse\\x12;\\n\" +\n\t\"\\aCPUInfo\\x12\\x16.google.protobuf.Empty\\x1a\\x18.machine.CPUInfoResponse\\x12?\\n\" +\n\t\"\\tDiskStats\\x12\\x16.google.protobuf.Empty\\x1a\\x1a.machine.DiskStatsResponse\\x12.\\n\" +\n\t\"\\x05Dmesg\\x12\\x15.machine.DmesgRequest\\x1a\\f.common.Data0\\x01\\x122\\n\" +\n\t\"\\x06Events\\x12\\x16.machine.EventsRequest\\x1a\\x0e.machine.Event0\\x01\\x12Q\\n\" +\n\t\"\\x0eEtcdMemberList\\x12\\x1e.machine.EtcdMemberListRequest\\x1a\\x1f.machine.EtcdMemberListResponse\\x12c\\n\" +\n\t\"\\x14EtcdRemoveMemberByID\\x12$.machine.EtcdRemoveMemberByIDRequest\\x1a%.machine.EtcdRemoveMemberByIDResponse\\x12W\\n\" +\n\t\"\\x10EtcdLeaveCluster\\x12 .machine.EtcdLeaveClusterRequest\\x1a!.machine.EtcdLeaveClusterResponse\\x12f\\n\" +\n\t\"\\x15EtcdForfeitLeadership\\x12%.machine.EtcdForfeitLeadershipRequest\\x1a&.machine.EtcdForfeitLeadershipResponse\\x12;\\n\" +\n\t\"\\vEtcdRecover\\x12\\f.common.Data\\x1a\\x1c.machine.EtcdRecoverResponse(\\x01\\x12<\\n\" +\n\t\"\\fEtcdSnapshot\\x12\\x1c.machine.EtcdSnapshotRequest\\x1a\\f.common.Data0\\x01\\x12G\\n\" +\n\t\"\\rEtcdAlarmList\\x12\\x16.google.protobuf.Empty\\x1a\\x1e.machine.EtcdAlarmListResponse\\x12K\\n\" +\n\t\"\\x0fEtcdAlarmDisarm\\x12\\x16.google.protobuf.Empty\\x1a .machine.EtcdAlarmDisarmResponse\\x12I\\n\" +\n\t\"\\x0eEtcdDefragment\\x12\\x16.google.protobuf.Empty\\x1a\\x1f.machine.EtcdDefragmentResponse\\x12A\\n\" +\n\t\"\\n\" +\n\t\"EtcdStatus\\x12\\x16.google.protobuf.Empty\\x1a\\x1b.machine.EtcdStatusResponse\\x12f\\n\" +\n\t\"\\x15EtcdDowngradeValidate\\x12%.machine.EtcdDowngradeValidateRequest\\x1a&.machine.EtcdDowngradeValidateResponse\\x12`\\n\" +\n\t\"\\x13EtcdDowngradeEnable\\x12#.machine.EtcdDowngradeEnableRequest\\x1a$.machine.EtcdDowngradeEnableResponse\\x12S\\n\" +\n\t\"\\x13EtcdDowngradeCancel\\x12\\x16.google.protobuf.Empty\\x1a$.machine.EtcdDowngradeCancelResponse\\x12=\\n\" +\n\t\"\\bHostname\\x12\\x16.google.protobuf.Empty\\x1a\\x19.machine.HostnameResponse\\x124\\n\" +\n\t\"\\n\" +\n\t\"Kubeconfig\\x12\\x16.google.protobuf.Empty\\x1a\\f.common.Data0\\x01\\x121\\n\" +\n\t\"\\x04List\\x12\\x14.machine.ListRequest\\x1a\\x11.machine.FileInfo0\\x01\\x12@\\n\" +\n\t\"\\tDiskUsage\\x12\\x19.machine.DiskUsageRequest\\x1a\\x16.machine.DiskUsageInfo0\\x01\\x12;\\n\" +\n\t\"\\aLoadAvg\\x12\\x16.google.protobuf.Empty\\x1a\\x18.machine.LoadAvgResponse\\x12,\\n\" +\n\t\"\\x04Logs\\x12\\x14.machine.LogsRequest\\x1a\\f.common.Data0\\x01\\x12I\\n\" +\n\t\"\\x0eLogsContainers\\x12\\x16.google.protobuf.Empty\\x1a\\x1f.machine.LogsContainersResponse\\x129\\n\" +\n\t\"\\x06Memory\\x12\\x16.google.protobuf.Empty\\x1a\\x17.machine.MemoryResponse\\x129\\n\" +\n\t\"\\x06Mounts\\x12\\x16.google.protobuf.Empty\\x1a\\x17.machine.MountsResponse\\x12Q\\n\" +\n\t\"\\x12NetworkDeviceStats\\x12\\x16.google.protobuf.Empty\\x1a#.machine.NetworkDeviceStatsResponse\\x12?\\n\" +\n\t\"\\tProcesses\\x12\\x16.google.protobuf.Empty\\x1a\\x1a.machine.ProcessesResponse\\x12,\\n\" +\n\t\"\\x04Read\\x12\\x14.machine.ReadRequest\\x1a\\f.common.Data0\\x01\\x129\\n\" +\n\t\"\\x06Reboot\\x12\\x16.machine.RebootRequest\\x1a\\x17.machine.RebootResponse\\x12<\\n\" +\n\t\"\\aRestart\\x12\\x17.machine.RestartRequest\\x1a\\x18.machine.RestartResponse\\x12?\\n\" +\n\t\"\\bRollback\\x12\\x18.machine.RollbackRequest\\x1a\\x19.machine.RollbackResponse\\x126\\n\" +\n\t\"\\x05Reset\\x12\\x15.machine.ResetRequest\\x1a\\x16.machine.ResetResponse\\x12C\\n\" +\n\t\"\\vServiceList\\x12\\x16.google.protobuf.Empty\\x1a\\x1c.machine.ServiceListResponse\\x12Q\\n\" +\n\t\"\\x0eServiceRestart\\x12\\x1e.machine.ServiceRestartRequest\\x1a\\x1f.machine.ServiceRestartResponse\\x12K\\n\" +\n\t\"\\fServiceStart\\x12\\x1c.machine.ServiceStartRequest\\x1a\\x1d.machine.ServiceStartResponse\\x12H\\n\" +\n\t\"\\vServiceStop\\x12\\x1b.machine.ServiceStopRequest\\x1a\\x1c.machine.ServiceStopResponse\\x12?\\n\" +\n\t\"\\bShutdown\\x12\\x18.machine.ShutdownRequest\\x1a\\x19.machine.ShutdownResponse\\x126\\n\" +\n\t\"\\x05Stats\\x12\\x15.machine.StatsRequest\\x1a\\x16.machine.StatsResponse\\x12A\\n\" +\n\t\"\\n\" +\n\t\"SystemStat\\x12\\x16.google.protobuf.Empty\\x1a\\x1b.machine.SystemStatResponse\\x12J\\n\" +\n\t\"\\aUpgrade\\x12\\x17.machine.UpgradeRequest\\x1a\\x18.machine.UpgradeResponse\\\"\\f\\xea\\xbb-\\x05v1.18\\x88\\x02\\x01\\x12;\\n\" +\n\t\"\\aVersion\\x12\\x16.google.protobuf.Empty\\x1a\\x18.machine.VersionResponse\\x12x\\n\" +\n\t\"\\x1bGenerateClientConfiguration\\x12+.machine.GenerateClientConfigurationRequest\\x1a,.machine.GenerateClientConfigurationResponse\\x12>\\n\" +\n\t\"\\rPacketCapture\\x12\\x1d.machine.PacketCaptureRequest\\x1a\\f.common.Data0\\x01\\x12<\\n\" +\n\t\"\\aNetstat\\x12\\x17.machine.NetstatRequest\\x1a\\x18.machine.NetstatResponse\\x12B\\n\" +\n\t\"\\tMetaWrite\\x12\\x19.machine.MetaWriteRequest\\x1a\\x1a.machine.MetaWriteResponse\\x12E\\n\" +\n\t\"\\n\" +\n\t\"MetaDelete\\x12\\x1a.machine.MetaDeleteRequest\\x1a\\x1b.machine.MetaDeleteResponse\\x12R\\n\" +\n\t\"\\tImageList\\x12\\x19.machine.ImageListRequest\\x1a\\x1a.machine.ImageListResponse\\\"\\f\\xea\\xbb-\\x05v1.18\\x88\\x02\\x010\\x01\\x12P\\n\" +\n\t\"\\tImagePull\\x12\\x19.machine.ImagePullRequest\\x1a\\x1a.machine.ImagePullResponse\\\"\\f\\xea\\xbb-\\x05v1.18\\x88\\x02\\x01BN\\n\" +\n\t\"\\x15dev.talos.api.machineZ5github.com/siderolabs/talos/pkg/machinery/api/machineb\\x06proto3\"\n\nvar (\n\tfile_machine_machine_proto_rawDescOnce sync.Once\n\tfile_machine_machine_proto_rawDescData []byte\n)\n\nfunc file_machine_machine_proto_rawDescGZIP() []byte {\n\tfile_machine_machine_proto_rawDescOnce.Do(func() {\n\t\tfile_machine_machine_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_machine_machine_proto_rawDesc), len(file_machine_machine_proto_rawDesc)))\n\t})\n\treturn file_machine_machine_proto_rawDescData\n}\n\nvar file_machine_machine_proto_enumTypes = make([]protoimpl.EnumInfo, 15)\nvar file_machine_machine_proto_msgTypes = make([]protoimpl.MessageInfo, 178)\nvar file_machine_machine_proto_goTypes = []any{\n\t(ApplyConfigurationRequest_Mode)(0),                     // 0: machine.ApplyConfigurationRequest.Mode\n\t(RebootRequest_Mode)(0),                                 // 1: machine.RebootRequest.Mode\n\t(SequenceEvent_Action)(0),                               // 2: machine.SequenceEvent.Action\n\t(PhaseEvent_Action)(0),                                  // 3: machine.PhaseEvent.Action\n\t(TaskEvent_Action)(0),                                   // 4: machine.TaskEvent.Action\n\t(ServiceStateEvent_Action)(0),                           // 5: machine.ServiceStateEvent.Action\n\t(MachineStatusEvent_MachineStage)(0),                    // 6: machine.MachineStatusEvent.MachineStage\n\t(ResetRequest_WipeMode)(0),                              // 7: machine.ResetRequest.WipeMode\n\t(UpgradeRequest_RebootMode)(0),                          // 8: machine.UpgradeRequest.RebootMode\n\t(ListRequest_Type)(0),                                   // 9: machine.ListRequest.Type\n\t(EtcdMemberAlarm_AlarmType)(0),                          // 10: machine.EtcdMemberAlarm.AlarmType\n\t(MachineConfig_MachineType)(0),                          // 11: machine.MachineConfig.MachineType\n\t(NetstatRequest_Filter)(0),                              // 12: machine.NetstatRequest.Filter\n\t(ConnectRecord_State)(0),                                // 13: machine.ConnectRecord.State\n\t(ConnectRecord_TimerActive)(0),                          // 14: machine.ConnectRecord.TimerActive\n\t(*ApplyConfigurationRequest)(nil),                       // 15: machine.ApplyConfigurationRequest\n\t(*ApplyConfiguration)(nil),                              // 16: machine.ApplyConfiguration\n\t(*ApplyConfigurationResponse)(nil),                      // 17: machine.ApplyConfigurationResponse\n\t(*RebootRequest)(nil),                                   // 18: machine.RebootRequest\n\t(*Reboot)(nil),                                          // 19: machine.Reboot\n\t(*RebootResponse)(nil),                                  // 20: machine.RebootResponse\n\t(*BootstrapRequest)(nil),                                // 21: machine.BootstrapRequest\n\t(*Bootstrap)(nil),                                       // 22: machine.Bootstrap\n\t(*BootstrapResponse)(nil),                               // 23: machine.BootstrapResponse\n\t(*SequenceEvent)(nil),                                   // 24: machine.SequenceEvent\n\t(*PhaseEvent)(nil),                                      // 25: machine.PhaseEvent\n\t(*TaskEvent)(nil),                                       // 26: machine.TaskEvent\n\t(*ServiceStateEvent)(nil),                               // 27: machine.ServiceStateEvent\n\t(*RestartEvent)(nil),                                    // 28: machine.RestartEvent\n\t(*ConfigLoadErrorEvent)(nil),                            // 29: machine.ConfigLoadErrorEvent\n\t(*ConfigValidationErrorEvent)(nil),                      // 30: machine.ConfigValidationErrorEvent\n\t(*AddressEvent)(nil),                                    // 31: machine.AddressEvent\n\t(*MachineStatusEvent)(nil),                              // 32: machine.MachineStatusEvent\n\t(*EventsRequest)(nil),                                   // 33: machine.EventsRequest\n\t(*Event)(nil),                                           // 34: machine.Event\n\t(*ResetPartitionSpec)(nil),                              // 35: machine.ResetPartitionSpec\n\t(*ResetRequest)(nil),                                    // 36: machine.ResetRequest\n\t(*Reset)(nil),                                           // 37: machine.Reset\n\t(*ResetResponse)(nil),                                   // 38: machine.ResetResponse\n\t(*Shutdown)(nil),                                        // 39: machine.Shutdown\n\t(*ShutdownRequest)(nil),                                 // 40: machine.ShutdownRequest\n\t(*ShutdownResponse)(nil),                                // 41: machine.ShutdownResponse\n\t(*UpgradeRequest)(nil),                                  // 42: machine.UpgradeRequest\n\t(*Upgrade)(nil),                                         // 43: machine.Upgrade\n\t(*UpgradeResponse)(nil),                                 // 44: machine.UpgradeResponse\n\t(*ServiceList)(nil),                                     // 45: machine.ServiceList\n\t(*ServiceListResponse)(nil),                             // 46: machine.ServiceListResponse\n\t(*ServiceInfo)(nil),                                     // 47: machine.ServiceInfo\n\t(*ServiceEvents)(nil),                                   // 48: machine.ServiceEvents\n\t(*ServiceEvent)(nil),                                    // 49: machine.ServiceEvent\n\t(*ServiceHealth)(nil),                                   // 50: machine.ServiceHealth\n\t(*ServiceStartRequest)(nil),                             // 51: machine.ServiceStartRequest\n\t(*ServiceStart)(nil),                                    // 52: machine.ServiceStart\n\t(*ServiceStartResponse)(nil),                            // 53: machine.ServiceStartResponse\n\t(*ServiceStopRequest)(nil),                              // 54: machine.ServiceStopRequest\n\t(*ServiceStop)(nil),                                     // 55: machine.ServiceStop\n\t(*ServiceStopResponse)(nil),                             // 56: machine.ServiceStopResponse\n\t(*ServiceRestartRequest)(nil),                           // 57: machine.ServiceRestartRequest\n\t(*ServiceRestart)(nil),                                  // 58: machine.ServiceRestart\n\t(*ServiceRestartResponse)(nil),                          // 59: machine.ServiceRestartResponse\n\t(*CopyRequest)(nil),                                     // 60: machine.CopyRequest\n\t(*ListRequest)(nil),                                     // 61: machine.ListRequest\n\t(*DiskUsageRequest)(nil),                                // 62: machine.DiskUsageRequest\n\t(*FileInfo)(nil),                                        // 63: machine.FileInfo\n\t(*Xattr)(nil),                                           // 64: machine.Xattr\n\t(*DiskUsageInfo)(nil),                                   // 65: machine.DiskUsageInfo\n\t(*Mounts)(nil),                                          // 66: machine.Mounts\n\t(*MountsResponse)(nil),                                  // 67: machine.MountsResponse\n\t(*MountStat)(nil),                                       // 68: machine.MountStat\n\t(*Version)(nil),                                         // 69: machine.Version\n\t(*VersionResponse)(nil),                                 // 70: machine.VersionResponse\n\t(*VersionInfo)(nil),                                     // 71: machine.VersionInfo\n\t(*PlatformInfo)(nil),                                    // 72: machine.PlatformInfo\n\t(*FeaturesInfo)(nil),                                    // 73: machine.FeaturesInfo\n\t(*LogsRequest)(nil),                                     // 74: machine.LogsRequest\n\t(*ReadRequest)(nil),                                     // 75: machine.ReadRequest\n\t(*LogsContainer)(nil),                                   // 76: machine.LogsContainer\n\t(*LogsContainersResponse)(nil),                          // 77: machine.LogsContainersResponse\n\t(*RollbackRequest)(nil),                                 // 78: machine.RollbackRequest\n\t(*Rollback)(nil),                                        // 79: machine.Rollback\n\t(*RollbackResponse)(nil),                                // 80: machine.RollbackResponse\n\t(*ContainersRequest)(nil),                               // 81: machine.ContainersRequest\n\t(*ContainerInfo)(nil),                                   // 82: machine.ContainerInfo\n\t(*Container)(nil),                                       // 83: machine.Container\n\t(*ContainersResponse)(nil),                              // 84: machine.ContainersResponse\n\t(*DmesgRequest)(nil),                                    // 85: machine.DmesgRequest\n\t(*ProcessesResponse)(nil),                               // 86: machine.ProcessesResponse\n\t(*Process)(nil),                                         // 87: machine.Process\n\t(*ProcessInfo)(nil),                                     // 88: machine.ProcessInfo\n\t(*RestartRequest)(nil),                                  // 89: machine.RestartRequest\n\t(*Restart)(nil),                                         // 90: machine.Restart\n\t(*RestartResponse)(nil),                                 // 91: machine.RestartResponse\n\t(*StatsRequest)(nil),                                    // 92: machine.StatsRequest\n\t(*Stats)(nil),                                           // 93: machine.Stats\n\t(*StatsResponse)(nil),                                   // 94: machine.StatsResponse\n\t(*Stat)(nil),                                            // 95: machine.Stat\n\t(*Memory)(nil),                                          // 96: machine.Memory\n\t(*MemoryResponse)(nil),                                  // 97: machine.MemoryResponse\n\t(*MemInfo)(nil),                                         // 98: machine.MemInfo\n\t(*HostnameResponse)(nil),                                // 99: machine.HostnameResponse\n\t(*Hostname)(nil),                                        // 100: machine.Hostname\n\t(*LoadAvgResponse)(nil),                                 // 101: machine.LoadAvgResponse\n\t(*LoadAvg)(nil),                                         // 102: machine.LoadAvg\n\t(*SystemStatResponse)(nil),                              // 103: machine.SystemStatResponse\n\t(*SystemStat)(nil),                                      // 104: machine.SystemStat\n\t(*CPUStat)(nil),                                         // 105: machine.CPUStat\n\t(*SoftIRQStat)(nil),                                     // 106: machine.SoftIRQStat\n\t(*CPUFreqStatsResponse)(nil),                            // 107: machine.CPUFreqStatsResponse\n\t(*CPUsFreqStats)(nil),                                   // 108: machine.CPUsFreqStats\n\t(*CPUFreqStats)(nil),                                    // 109: machine.CPUFreqStats\n\t(*CPUInfoResponse)(nil),                                 // 110: machine.CPUInfoResponse\n\t(*CPUsInfo)(nil),                                        // 111: machine.CPUsInfo\n\t(*CPUInfo)(nil),                                         // 112: machine.CPUInfo\n\t(*NetworkDeviceStatsResponse)(nil),                      // 113: machine.NetworkDeviceStatsResponse\n\t(*NetworkDeviceStats)(nil),                              // 114: machine.NetworkDeviceStats\n\t(*NetDev)(nil),                                          // 115: machine.NetDev\n\t(*DiskStatsResponse)(nil),                               // 116: machine.DiskStatsResponse\n\t(*DiskStats)(nil),                                       // 117: machine.DiskStats\n\t(*DiskStat)(nil),                                        // 118: machine.DiskStat\n\t(*EtcdLeaveClusterRequest)(nil),                         // 119: machine.EtcdLeaveClusterRequest\n\t(*EtcdLeaveCluster)(nil),                                // 120: machine.EtcdLeaveCluster\n\t(*EtcdLeaveClusterResponse)(nil),                        // 121: machine.EtcdLeaveClusterResponse\n\t(*EtcdRemoveMemberRequest)(nil),                         // 122: machine.EtcdRemoveMemberRequest\n\t(*EtcdRemoveMember)(nil),                                // 123: machine.EtcdRemoveMember\n\t(*EtcdRemoveMemberResponse)(nil),                        // 124: machine.EtcdRemoveMemberResponse\n\t(*EtcdRemoveMemberByIDRequest)(nil),                     // 125: machine.EtcdRemoveMemberByIDRequest\n\t(*EtcdRemoveMemberByID)(nil),                            // 126: machine.EtcdRemoveMemberByID\n\t(*EtcdRemoveMemberByIDResponse)(nil),                    // 127: machine.EtcdRemoveMemberByIDResponse\n\t(*EtcdForfeitLeadershipRequest)(nil),                    // 128: machine.EtcdForfeitLeadershipRequest\n\t(*EtcdForfeitLeadership)(nil),                           // 129: machine.EtcdForfeitLeadership\n\t(*EtcdForfeitLeadershipResponse)(nil),                   // 130: machine.EtcdForfeitLeadershipResponse\n\t(*EtcdMemberListRequest)(nil),                           // 131: machine.EtcdMemberListRequest\n\t(*EtcdMember)(nil),                                      // 132: machine.EtcdMember\n\t(*EtcdMembers)(nil),                                     // 133: machine.EtcdMembers\n\t(*EtcdMemberListResponse)(nil),                          // 134: machine.EtcdMemberListResponse\n\t(*EtcdSnapshotRequest)(nil),                             // 135: machine.EtcdSnapshotRequest\n\t(*EtcdRecover)(nil),                                     // 136: machine.EtcdRecover\n\t(*EtcdRecoverResponse)(nil),                             // 137: machine.EtcdRecoverResponse\n\t(*EtcdAlarmListResponse)(nil),                           // 138: machine.EtcdAlarmListResponse\n\t(*EtcdAlarm)(nil),                                       // 139: machine.EtcdAlarm\n\t(*EtcdMemberAlarm)(nil),                                 // 140: machine.EtcdMemberAlarm\n\t(*EtcdAlarmDisarmResponse)(nil),                         // 141: machine.EtcdAlarmDisarmResponse\n\t(*EtcdAlarmDisarm)(nil),                                 // 142: machine.EtcdAlarmDisarm\n\t(*EtcdDefragmentResponse)(nil),                          // 143: machine.EtcdDefragmentResponse\n\t(*EtcdDefragment)(nil),                                  // 144: machine.EtcdDefragment\n\t(*EtcdStatusResponse)(nil),                              // 145: machine.EtcdStatusResponse\n\t(*EtcdStatus)(nil),                                      // 146: machine.EtcdStatus\n\t(*EtcdMemberStatus)(nil),                                // 147: machine.EtcdMemberStatus\n\t(*EtcdDowngradeValidateRequest)(nil),                    // 148: machine.EtcdDowngradeValidateRequest\n\t(*EtcdDowngradeValidateResponse)(nil),                   // 149: machine.EtcdDowngradeValidateResponse\n\t(*EtcdDowngradeValidate)(nil),                           // 150: machine.EtcdDowngradeValidate\n\t(*EtcdDowngradeEnableRequest)(nil),                      // 151: machine.EtcdDowngradeEnableRequest\n\t(*EtcdDowngradeEnableResponse)(nil),                     // 152: machine.EtcdDowngradeEnableResponse\n\t(*EtcdDowngradeEnable)(nil),                             // 153: machine.EtcdDowngradeEnable\n\t(*EtcdDowngradeCancelResponse)(nil),                     // 154: machine.EtcdDowngradeCancelResponse\n\t(*EtcdDowngradeCancel)(nil),                             // 155: machine.EtcdDowngradeCancel\n\t(*EtcdClusterDowngrade)(nil),                            // 156: machine.EtcdClusterDowngrade\n\t(*RouteConfig)(nil),                                     // 157: machine.RouteConfig\n\t(*DHCPOptionsConfig)(nil),                               // 158: machine.DHCPOptionsConfig\n\t(*NetworkDeviceConfig)(nil),                             // 159: machine.NetworkDeviceConfig\n\t(*NetworkConfig)(nil),                                   // 160: machine.NetworkConfig\n\t(*InstallConfig)(nil),                                   // 161: machine.InstallConfig\n\t(*MachineConfig)(nil),                                   // 162: machine.MachineConfig\n\t(*ControlPlaneConfig)(nil),                              // 163: machine.ControlPlaneConfig\n\t(*CNIConfig)(nil),                                       // 164: machine.CNIConfig\n\t(*ClusterNetworkConfig)(nil),                            // 165: machine.ClusterNetworkConfig\n\t(*ClusterConfig)(nil),                                   // 166: machine.ClusterConfig\n\t(*GenerateClientConfigurationRequest)(nil),              // 167: machine.GenerateClientConfigurationRequest\n\t(*GenerateClientConfiguration)(nil),                     // 168: machine.GenerateClientConfiguration\n\t(*GenerateClientConfigurationResponse)(nil),             // 169: machine.GenerateClientConfigurationResponse\n\t(*PacketCaptureRequest)(nil),                            // 170: machine.PacketCaptureRequest\n\t(*BPFInstruction)(nil),                                  // 171: machine.BPFInstruction\n\t(*NetstatRequest)(nil),                                  // 172: machine.NetstatRequest\n\t(*ConnectRecord)(nil),                                   // 173: machine.ConnectRecord\n\t(*Netstat)(nil),                                         // 174: machine.Netstat\n\t(*NetstatResponse)(nil),                                 // 175: machine.NetstatResponse\n\t(*MetaWriteRequest)(nil),                                // 176: machine.MetaWriteRequest\n\t(*MetaWrite)(nil),                                       // 177: machine.MetaWrite\n\t(*MetaWriteResponse)(nil),                               // 178: machine.MetaWriteResponse\n\t(*MetaDeleteRequest)(nil),                               // 179: machine.MetaDeleteRequest\n\t(*MetaDelete)(nil),                                      // 180: machine.MetaDelete\n\t(*MetaDeleteResponse)(nil),                              // 181: machine.MetaDeleteResponse\n\t(*ImageListRequest)(nil),                                // 182: machine.ImageListRequest\n\t(*ImageListResponse)(nil),                               // 183: machine.ImageListResponse\n\t(*ImagePullRequest)(nil),                                // 184: machine.ImagePullRequest\n\t(*ImagePull)(nil),                                       // 185: machine.ImagePull\n\t(*ImagePullResponse)(nil),                               // 186: machine.ImagePullResponse\n\t(*MachineStatusEvent_MachineStatus)(nil),                // 187: machine.MachineStatusEvent.MachineStatus\n\t(*MachineStatusEvent_MachineStatus_UnmetCondition)(nil), // 188: machine.MachineStatusEvent.MachineStatus.UnmetCondition\n\t(*NetstatRequest_Feature)(nil),                          // 189: machine.NetstatRequest.Feature\n\t(*NetstatRequest_L4Proto)(nil),                          // 190: machine.NetstatRequest.L4proto\n\t(*NetstatRequest_NetNS)(nil),                            // 191: machine.NetstatRequest.NetNS\n\t(*ConnectRecord_Process)(nil),                           // 192: machine.ConnectRecord.Process\n\t(*durationpb.Duration)(nil),                             // 193: google.protobuf.Duration\n\t(*common.Metadata)(nil),                                 // 194: common.Metadata\n\t(*common.Error)(nil),                                    // 195: common.Error\n\t(*anypb.Any)(nil),                                       // 196: google.protobuf.Any\n\t(*timestamppb.Timestamp)(nil),                           // 197: google.protobuf.Timestamp\n\t(common.ContainerDriver)(0),                             // 198: common.ContainerDriver\n\t(common.ContainerdNamespace)(0),                         // 199: common.ContainerdNamespace\n\t(*emptypb.Empty)(nil),                                   // 200: google.protobuf.Empty\n\t(*common.Data)(nil),                                     // 201: common.Data\n}\nvar file_machine_machine_proto_depIdxs = []int32{\n\t0,   // 0: machine.ApplyConfigurationRequest.mode:type_name -> machine.ApplyConfigurationRequest.Mode\n\t193, // 1: machine.ApplyConfigurationRequest.try_mode_timeout:type_name -> google.protobuf.Duration\n\t194, // 2: machine.ApplyConfiguration.metadata:type_name -> common.Metadata\n\t0,   // 3: machine.ApplyConfiguration.mode:type_name -> machine.ApplyConfigurationRequest.Mode\n\t16,  // 4: machine.ApplyConfigurationResponse.messages:type_name -> machine.ApplyConfiguration\n\t1,   // 5: machine.RebootRequest.mode:type_name -> machine.RebootRequest.Mode\n\t194, // 6: machine.Reboot.metadata:type_name -> common.Metadata\n\t19,  // 7: machine.RebootResponse.messages:type_name -> machine.Reboot\n\t194, // 8: machine.Bootstrap.metadata:type_name -> common.Metadata\n\t22,  // 9: machine.BootstrapResponse.messages:type_name -> machine.Bootstrap\n\t2,   // 10: machine.SequenceEvent.action:type_name -> machine.SequenceEvent.Action\n\t195, // 11: machine.SequenceEvent.error:type_name -> common.Error\n\t3,   // 12: machine.PhaseEvent.action:type_name -> machine.PhaseEvent.Action\n\t4,   // 13: machine.TaskEvent.action:type_name -> machine.TaskEvent.Action\n\t5,   // 14: machine.ServiceStateEvent.action:type_name -> machine.ServiceStateEvent.Action\n\t50,  // 15: machine.ServiceStateEvent.health:type_name -> machine.ServiceHealth\n\t6,   // 16: machine.MachineStatusEvent.stage:type_name -> machine.MachineStatusEvent.MachineStage\n\t187, // 17: machine.MachineStatusEvent.status:type_name -> machine.MachineStatusEvent.MachineStatus\n\t194, // 18: machine.Event.metadata:type_name -> common.Metadata\n\t196, // 19: machine.Event.data:type_name -> google.protobuf.Any\n\t35,  // 20: machine.ResetRequest.system_partitions_to_wipe:type_name -> machine.ResetPartitionSpec\n\t7,   // 21: machine.ResetRequest.mode:type_name -> machine.ResetRequest.WipeMode\n\t194, // 22: machine.Reset.metadata:type_name -> common.Metadata\n\t37,  // 23: machine.ResetResponse.messages:type_name -> machine.Reset\n\t194, // 24: machine.Shutdown.metadata:type_name -> common.Metadata\n\t39,  // 25: machine.ShutdownResponse.messages:type_name -> machine.Shutdown\n\t8,   // 26: machine.UpgradeRequest.reboot_mode:type_name -> machine.UpgradeRequest.RebootMode\n\t194, // 27: machine.Upgrade.metadata:type_name -> common.Metadata\n\t43,  // 28: machine.UpgradeResponse.messages:type_name -> machine.Upgrade\n\t194, // 29: machine.ServiceList.metadata:type_name -> common.Metadata\n\t47,  // 30: machine.ServiceList.services:type_name -> machine.ServiceInfo\n\t45,  // 31: machine.ServiceListResponse.messages:type_name -> machine.ServiceList\n\t48,  // 32: machine.ServiceInfo.events:type_name -> machine.ServiceEvents\n\t50,  // 33: machine.ServiceInfo.health:type_name -> machine.ServiceHealth\n\t49,  // 34: machine.ServiceEvents.events:type_name -> machine.ServiceEvent\n\t197, // 35: machine.ServiceEvent.ts:type_name -> google.protobuf.Timestamp\n\t197, // 36: machine.ServiceHealth.last_change:type_name -> google.protobuf.Timestamp\n\t194, // 37: machine.ServiceStart.metadata:type_name -> common.Metadata\n\t52,  // 38: machine.ServiceStartResponse.messages:type_name -> machine.ServiceStart\n\t194, // 39: machine.ServiceStop.metadata:type_name -> common.Metadata\n\t55,  // 40: machine.ServiceStopResponse.messages:type_name -> machine.ServiceStop\n\t194, // 41: machine.ServiceRestart.metadata:type_name -> common.Metadata\n\t58,  // 42: machine.ServiceRestartResponse.messages:type_name -> machine.ServiceRestart\n\t9,   // 43: machine.ListRequest.types:type_name -> machine.ListRequest.Type\n\t194, // 44: machine.FileInfo.metadata:type_name -> common.Metadata\n\t64,  // 45: machine.FileInfo.xattrs:type_name -> machine.Xattr\n\t194, // 46: machine.DiskUsageInfo.metadata:type_name -> common.Metadata\n\t194, // 47: machine.Mounts.metadata:type_name -> common.Metadata\n\t68,  // 48: machine.Mounts.stats:type_name -> machine.MountStat\n\t66,  // 49: machine.MountsResponse.messages:type_name -> machine.Mounts\n\t194, // 50: machine.Version.metadata:type_name -> common.Metadata\n\t71,  // 51: machine.Version.version:type_name -> machine.VersionInfo\n\t72,  // 52: machine.Version.platform:type_name -> machine.PlatformInfo\n\t73,  // 53: machine.Version.features:type_name -> machine.FeaturesInfo\n\t69,  // 54: machine.VersionResponse.messages:type_name -> machine.Version\n\t198, // 55: machine.LogsRequest.driver:type_name -> common.ContainerDriver\n\t194, // 56: machine.LogsContainer.metadata:type_name -> common.Metadata\n\t76,  // 57: machine.LogsContainersResponse.messages:type_name -> machine.LogsContainer\n\t194, // 58: machine.Rollback.metadata:type_name -> common.Metadata\n\t79,  // 59: machine.RollbackResponse.messages:type_name -> machine.Rollback\n\t198, // 60: machine.ContainersRequest.driver:type_name -> common.ContainerDriver\n\t194, // 61: machine.Container.metadata:type_name -> common.Metadata\n\t82,  // 62: machine.Container.containers:type_name -> machine.ContainerInfo\n\t83,  // 63: machine.ContainersResponse.messages:type_name -> machine.Container\n\t87,  // 64: machine.ProcessesResponse.messages:type_name -> machine.Process\n\t194, // 65: machine.Process.metadata:type_name -> common.Metadata\n\t88,  // 66: machine.Process.processes:type_name -> machine.ProcessInfo\n\t198, // 67: machine.RestartRequest.driver:type_name -> common.ContainerDriver\n\t194, // 68: machine.Restart.metadata:type_name -> common.Metadata\n\t90,  // 69: machine.RestartResponse.messages:type_name -> machine.Restart\n\t198, // 70: machine.StatsRequest.driver:type_name -> common.ContainerDriver\n\t194, // 71: machine.Stats.metadata:type_name -> common.Metadata\n\t95,  // 72: machine.Stats.stats:type_name -> machine.Stat\n\t93,  // 73: machine.StatsResponse.messages:type_name -> machine.Stats\n\t194, // 74: machine.Memory.metadata:type_name -> common.Metadata\n\t98,  // 75: machine.Memory.meminfo:type_name -> machine.MemInfo\n\t96,  // 76: machine.MemoryResponse.messages:type_name -> machine.Memory\n\t100, // 77: machine.HostnameResponse.messages:type_name -> machine.Hostname\n\t194, // 78: machine.Hostname.metadata:type_name -> common.Metadata\n\t102, // 79: machine.LoadAvgResponse.messages:type_name -> machine.LoadAvg\n\t194, // 80: machine.LoadAvg.metadata:type_name -> common.Metadata\n\t104, // 81: machine.SystemStatResponse.messages:type_name -> machine.SystemStat\n\t194, // 82: machine.SystemStat.metadata:type_name -> common.Metadata\n\t105, // 83: machine.SystemStat.cpu_total:type_name -> machine.CPUStat\n\t105, // 84: machine.SystemStat.cpu:type_name -> machine.CPUStat\n\t106, // 85: machine.SystemStat.soft_irq:type_name -> machine.SoftIRQStat\n\t108, // 86: machine.CPUFreqStatsResponse.messages:type_name -> machine.CPUsFreqStats\n\t194, // 87: machine.CPUsFreqStats.metadata:type_name -> common.Metadata\n\t109, // 88: machine.CPUsFreqStats.cpu_freq_stats:type_name -> machine.CPUFreqStats\n\t111, // 89: machine.CPUInfoResponse.messages:type_name -> machine.CPUsInfo\n\t194, // 90: machine.CPUsInfo.metadata:type_name -> common.Metadata\n\t112, // 91: machine.CPUsInfo.cpu_info:type_name -> machine.CPUInfo\n\t114, // 92: machine.NetworkDeviceStatsResponse.messages:type_name -> machine.NetworkDeviceStats\n\t194, // 93: machine.NetworkDeviceStats.metadata:type_name -> common.Metadata\n\t115, // 94: machine.NetworkDeviceStats.total:type_name -> machine.NetDev\n\t115, // 95: machine.NetworkDeviceStats.devices:type_name -> machine.NetDev\n\t117, // 96: machine.DiskStatsResponse.messages:type_name -> machine.DiskStats\n\t194, // 97: machine.DiskStats.metadata:type_name -> common.Metadata\n\t118, // 98: machine.DiskStats.total:type_name -> machine.DiskStat\n\t118, // 99: machine.DiskStats.devices:type_name -> machine.DiskStat\n\t194, // 100: machine.EtcdLeaveCluster.metadata:type_name -> common.Metadata\n\t120, // 101: machine.EtcdLeaveClusterResponse.messages:type_name -> machine.EtcdLeaveCluster\n\t194, // 102: machine.EtcdRemoveMember.metadata:type_name -> common.Metadata\n\t123, // 103: machine.EtcdRemoveMemberResponse.messages:type_name -> machine.EtcdRemoveMember\n\t194, // 104: machine.EtcdRemoveMemberByID.metadata:type_name -> common.Metadata\n\t126, // 105: machine.EtcdRemoveMemberByIDResponse.messages:type_name -> machine.EtcdRemoveMemberByID\n\t194, // 106: machine.EtcdForfeitLeadership.metadata:type_name -> common.Metadata\n\t129, // 107: machine.EtcdForfeitLeadershipResponse.messages:type_name -> machine.EtcdForfeitLeadership\n\t194, // 108: machine.EtcdMembers.metadata:type_name -> common.Metadata\n\t132, // 109: machine.EtcdMembers.members:type_name -> machine.EtcdMember\n\t133, // 110: machine.EtcdMemberListResponse.messages:type_name -> machine.EtcdMembers\n\t194, // 111: machine.EtcdRecover.metadata:type_name -> common.Metadata\n\t136, // 112: machine.EtcdRecoverResponse.messages:type_name -> machine.EtcdRecover\n\t139, // 113: machine.EtcdAlarmListResponse.messages:type_name -> machine.EtcdAlarm\n\t194, // 114: machine.EtcdAlarm.metadata:type_name -> common.Metadata\n\t140, // 115: machine.EtcdAlarm.member_alarms:type_name -> machine.EtcdMemberAlarm\n\t10,  // 116: machine.EtcdMemberAlarm.alarm:type_name -> machine.EtcdMemberAlarm.AlarmType\n\t142, // 117: machine.EtcdAlarmDisarmResponse.messages:type_name -> machine.EtcdAlarmDisarm\n\t194, // 118: machine.EtcdAlarmDisarm.metadata:type_name -> common.Metadata\n\t140, // 119: machine.EtcdAlarmDisarm.member_alarms:type_name -> machine.EtcdMemberAlarm\n\t144, // 120: machine.EtcdDefragmentResponse.messages:type_name -> machine.EtcdDefragment\n\t194, // 121: machine.EtcdDefragment.metadata:type_name -> common.Metadata\n\t146, // 122: machine.EtcdStatusResponse.messages:type_name -> machine.EtcdStatus\n\t194, // 123: machine.EtcdStatus.metadata:type_name -> common.Metadata\n\t147, // 124: machine.EtcdStatus.member_status:type_name -> machine.EtcdMemberStatus\n\t150, // 125: machine.EtcdDowngradeValidateResponse.messages:type_name -> machine.EtcdDowngradeValidate\n\t194, // 126: machine.EtcdDowngradeValidate.metadata:type_name -> common.Metadata\n\t156, // 127: machine.EtcdDowngradeValidate.cluster_downgrade:type_name -> machine.EtcdClusterDowngrade\n\t153, // 128: machine.EtcdDowngradeEnableResponse.messages:type_name -> machine.EtcdDowngradeEnable\n\t194, // 129: machine.EtcdDowngradeEnable.metadata:type_name -> common.Metadata\n\t156, // 130: machine.EtcdDowngradeEnable.cluster_downgrade:type_name -> machine.EtcdClusterDowngrade\n\t155, // 131: machine.EtcdDowngradeCancelResponse.messages:type_name -> machine.EtcdDowngradeCancel\n\t194, // 132: machine.EtcdDowngradeCancel.metadata:type_name -> common.Metadata\n\t156, // 133: machine.EtcdDowngradeCancel.cluster_downgrade:type_name -> machine.EtcdClusterDowngrade\n\t158, // 134: machine.NetworkDeviceConfig.dhcp_options:type_name -> machine.DHCPOptionsConfig\n\t157, // 135: machine.NetworkDeviceConfig.routes:type_name -> machine.RouteConfig\n\t159, // 136: machine.NetworkConfig.interfaces:type_name -> machine.NetworkDeviceConfig\n\t11,  // 137: machine.MachineConfig.type:type_name -> machine.MachineConfig.MachineType\n\t161, // 138: machine.MachineConfig.install_config:type_name -> machine.InstallConfig\n\t160, // 139: machine.MachineConfig.network_config:type_name -> machine.NetworkConfig\n\t164, // 140: machine.ClusterNetworkConfig.cni_config:type_name -> machine.CNIConfig\n\t163, // 141: machine.ClusterConfig.control_plane:type_name -> machine.ControlPlaneConfig\n\t165, // 142: machine.ClusterConfig.cluster_network:type_name -> machine.ClusterNetworkConfig\n\t193, // 143: machine.GenerateClientConfigurationRequest.crt_ttl:type_name -> google.protobuf.Duration\n\t194, // 144: machine.GenerateClientConfiguration.metadata:type_name -> common.Metadata\n\t168, // 145: machine.GenerateClientConfigurationResponse.messages:type_name -> machine.GenerateClientConfiguration\n\t171, // 146: machine.PacketCaptureRequest.bpf_filter:type_name -> machine.BPFInstruction\n\t12,  // 147: machine.NetstatRequest.filter:type_name -> machine.NetstatRequest.Filter\n\t189, // 148: machine.NetstatRequest.feature:type_name -> machine.NetstatRequest.Feature\n\t190, // 149: machine.NetstatRequest.l4proto:type_name -> machine.NetstatRequest.L4proto\n\t191, // 150: machine.NetstatRequest.netns:type_name -> machine.NetstatRequest.NetNS\n\t13,  // 151: machine.ConnectRecord.state:type_name -> machine.ConnectRecord.State\n\t14,  // 152: machine.ConnectRecord.tr:type_name -> machine.ConnectRecord.TimerActive\n\t192, // 153: machine.ConnectRecord.process:type_name -> machine.ConnectRecord.Process\n\t194, // 154: machine.Netstat.metadata:type_name -> common.Metadata\n\t173, // 155: machine.Netstat.connectrecord:type_name -> machine.ConnectRecord\n\t174, // 156: machine.NetstatResponse.messages:type_name -> machine.Netstat\n\t194, // 157: machine.MetaWrite.metadata:type_name -> common.Metadata\n\t177, // 158: machine.MetaWriteResponse.messages:type_name -> machine.MetaWrite\n\t194, // 159: machine.MetaDelete.metadata:type_name -> common.Metadata\n\t180, // 160: machine.MetaDeleteResponse.messages:type_name -> machine.MetaDelete\n\t199, // 161: machine.ImageListRequest.namespace:type_name -> common.ContainerdNamespace\n\t194, // 162: machine.ImageListResponse.metadata:type_name -> common.Metadata\n\t197, // 163: machine.ImageListResponse.created_at:type_name -> google.protobuf.Timestamp\n\t199, // 164: machine.ImagePullRequest.namespace:type_name -> common.ContainerdNamespace\n\t194, // 165: machine.ImagePull.metadata:type_name -> common.Metadata\n\t185, // 166: machine.ImagePullResponse.messages:type_name -> machine.ImagePull\n\t188, // 167: machine.MachineStatusEvent.MachineStatus.unmet_conditions:type_name -> machine.MachineStatusEvent.MachineStatus.UnmetCondition\n\t15,  // 168: machine.MachineService.ApplyConfiguration:input_type -> machine.ApplyConfigurationRequest\n\t21,  // 169: machine.MachineService.Bootstrap:input_type -> machine.BootstrapRequest\n\t81,  // 170: machine.MachineService.Containers:input_type -> machine.ContainersRequest\n\t60,  // 171: machine.MachineService.Copy:input_type -> machine.CopyRequest\n\t200, // 172: machine.MachineService.CPUFreqStats:input_type -> google.protobuf.Empty\n\t200, // 173: machine.MachineService.CPUInfo:input_type -> google.protobuf.Empty\n\t200, // 174: machine.MachineService.DiskStats:input_type -> google.protobuf.Empty\n\t85,  // 175: machine.MachineService.Dmesg:input_type -> machine.DmesgRequest\n\t33,  // 176: machine.MachineService.Events:input_type -> machine.EventsRequest\n\t131, // 177: machine.MachineService.EtcdMemberList:input_type -> machine.EtcdMemberListRequest\n\t125, // 178: machine.MachineService.EtcdRemoveMemberByID:input_type -> machine.EtcdRemoveMemberByIDRequest\n\t119, // 179: machine.MachineService.EtcdLeaveCluster:input_type -> machine.EtcdLeaveClusterRequest\n\t128, // 180: machine.MachineService.EtcdForfeitLeadership:input_type -> machine.EtcdForfeitLeadershipRequest\n\t201, // 181: machine.MachineService.EtcdRecover:input_type -> common.Data\n\t135, // 182: machine.MachineService.EtcdSnapshot:input_type -> machine.EtcdSnapshotRequest\n\t200, // 183: machine.MachineService.EtcdAlarmList:input_type -> google.protobuf.Empty\n\t200, // 184: machine.MachineService.EtcdAlarmDisarm:input_type -> google.protobuf.Empty\n\t200, // 185: machine.MachineService.EtcdDefragment:input_type -> google.protobuf.Empty\n\t200, // 186: machine.MachineService.EtcdStatus:input_type -> google.protobuf.Empty\n\t148, // 187: machine.MachineService.EtcdDowngradeValidate:input_type -> machine.EtcdDowngradeValidateRequest\n\t151, // 188: machine.MachineService.EtcdDowngradeEnable:input_type -> machine.EtcdDowngradeEnableRequest\n\t200, // 189: machine.MachineService.EtcdDowngradeCancel:input_type -> google.protobuf.Empty\n\t200, // 190: machine.MachineService.Hostname:input_type -> google.protobuf.Empty\n\t200, // 191: machine.MachineService.Kubeconfig:input_type -> google.protobuf.Empty\n\t61,  // 192: machine.MachineService.List:input_type -> machine.ListRequest\n\t62,  // 193: machine.MachineService.DiskUsage:input_type -> machine.DiskUsageRequest\n\t200, // 194: machine.MachineService.LoadAvg:input_type -> google.protobuf.Empty\n\t74,  // 195: machine.MachineService.Logs:input_type -> machine.LogsRequest\n\t200, // 196: machine.MachineService.LogsContainers:input_type -> google.protobuf.Empty\n\t200, // 197: machine.MachineService.Memory:input_type -> google.protobuf.Empty\n\t200, // 198: machine.MachineService.Mounts:input_type -> google.protobuf.Empty\n\t200, // 199: machine.MachineService.NetworkDeviceStats:input_type -> google.protobuf.Empty\n\t200, // 200: machine.MachineService.Processes:input_type -> google.protobuf.Empty\n\t75,  // 201: machine.MachineService.Read:input_type -> machine.ReadRequest\n\t18,  // 202: machine.MachineService.Reboot:input_type -> machine.RebootRequest\n\t89,  // 203: machine.MachineService.Restart:input_type -> machine.RestartRequest\n\t78,  // 204: machine.MachineService.Rollback:input_type -> machine.RollbackRequest\n\t36,  // 205: machine.MachineService.Reset:input_type -> machine.ResetRequest\n\t200, // 206: machine.MachineService.ServiceList:input_type -> google.protobuf.Empty\n\t57,  // 207: machine.MachineService.ServiceRestart:input_type -> machine.ServiceRestartRequest\n\t51,  // 208: machine.MachineService.ServiceStart:input_type -> machine.ServiceStartRequest\n\t54,  // 209: machine.MachineService.ServiceStop:input_type -> machine.ServiceStopRequest\n\t40,  // 210: machine.MachineService.Shutdown:input_type -> machine.ShutdownRequest\n\t92,  // 211: machine.MachineService.Stats:input_type -> machine.StatsRequest\n\t200, // 212: machine.MachineService.SystemStat:input_type -> google.protobuf.Empty\n\t42,  // 213: machine.MachineService.Upgrade:input_type -> machine.UpgradeRequest\n\t200, // 214: machine.MachineService.Version:input_type -> google.protobuf.Empty\n\t167, // 215: machine.MachineService.GenerateClientConfiguration:input_type -> machine.GenerateClientConfigurationRequest\n\t170, // 216: machine.MachineService.PacketCapture:input_type -> machine.PacketCaptureRequest\n\t172, // 217: machine.MachineService.Netstat:input_type -> machine.NetstatRequest\n\t176, // 218: machine.MachineService.MetaWrite:input_type -> machine.MetaWriteRequest\n\t179, // 219: machine.MachineService.MetaDelete:input_type -> machine.MetaDeleteRequest\n\t182, // 220: machine.MachineService.ImageList:input_type -> machine.ImageListRequest\n\t184, // 221: machine.MachineService.ImagePull:input_type -> machine.ImagePullRequest\n\t17,  // 222: machine.MachineService.ApplyConfiguration:output_type -> machine.ApplyConfigurationResponse\n\t23,  // 223: machine.MachineService.Bootstrap:output_type -> machine.BootstrapResponse\n\t84,  // 224: machine.MachineService.Containers:output_type -> machine.ContainersResponse\n\t201, // 225: machine.MachineService.Copy:output_type -> common.Data\n\t107, // 226: machine.MachineService.CPUFreqStats:output_type -> machine.CPUFreqStatsResponse\n\t110, // 227: machine.MachineService.CPUInfo:output_type -> machine.CPUInfoResponse\n\t116, // 228: machine.MachineService.DiskStats:output_type -> machine.DiskStatsResponse\n\t201, // 229: machine.MachineService.Dmesg:output_type -> common.Data\n\t34,  // 230: machine.MachineService.Events:output_type -> machine.Event\n\t134, // 231: machine.MachineService.EtcdMemberList:output_type -> machine.EtcdMemberListResponse\n\t127, // 232: machine.MachineService.EtcdRemoveMemberByID:output_type -> machine.EtcdRemoveMemberByIDResponse\n\t121, // 233: machine.MachineService.EtcdLeaveCluster:output_type -> machine.EtcdLeaveClusterResponse\n\t130, // 234: machine.MachineService.EtcdForfeitLeadership:output_type -> machine.EtcdForfeitLeadershipResponse\n\t137, // 235: machine.MachineService.EtcdRecover:output_type -> machine.EtcdRecoverResponse\n\t201, // 236: machine.MachineService.EtcdSnapshot:output_type -> common.Data\n\t138, // 237: machine.MachineService.EtcdAlarmList:output_type -> machine.EtcdAlarmListResponse\n\t141, // 238: machine.MachineService.EtcdAlarmDisarm:output_type -> machine.EtcdAlarmDisarmResponse\n\t143, // 239: machine.MachineService.EtcdDefragment:output_type -> machine.EtcdDefragmentResponse\n\t145, // 240: machine.MachineService.EtcdStatus:output_type -> machine.EtcdStatusResponse\n\t149, // 241: machine.MachineService.EtcdDowngradeValidate:output_type -> machine.EtcdDowngradeValidateResponse\n\t152, // 242: machine.MachineService.EtcdDowngradeEnable:output_type -> machine.EtcdDowngradeEnableResponse\n\t154, // 243: machine.MachineService.EtcdDowngradeCancel:output_type -> machine.EtcdDowngradeCancelResponse\n\t99,  // 244: machine.MachineService.Hostname:output_type -> machine.HostnameResponse\n\t201, // 245: machine.MachineService.Kubeconfig:output_type -> common.Data\n\t63,  // 246: machine.MachineService.List:output_type -> machine.FileInfo\n\t65,  // 247: machine.MachineService.DiskUsage:output_type -> machine.DiskUsageInfo\n\t101, // 248: machine.MachineService.LoadAvg:output_type -> machine.LoadAvgResponse\n\t201, // 249: machine.MachineService.Logs:output_type -> common.Data\n\t77,  // 250: machine.MachineService.LogsContainers:output_type -> machine.LogsContainersResponse\n\t97,  // 251: machine.MachineService.Memory:output_type -> machine.MemoryResponse\n\t67,  // 252: machine.MachineService.Mounts:output_type -> machine.MountsResponse\n\t113, // 253: machine.MachineService.NetworkDeviceStats:output_type -> machine.NetworkDeviceStatsResponse\n\t86,  // 254: machine.MachineService.Processes:output_type -> machine.ProcessesResponse\n\t201, // 255: machine.MachineService.Read:output_type -> common.Data\n\t20,  // 256: machine.MachineService.Reboot:output_type -> machine.RebootResponse\n\t91,  // 257: machine.MachineService.Restart:output_type -> machine.RestartResponse\n\t80,  // 258: machine.MachineService.Rollback:output_type -> machine.RollbackResponse\n\t38,  // 259: machine.MachineService.Reset:output_type -> machine.ResetResponse\n\t46,  // 260: machine.MachineService.ServiceList:output_type -> machine.ServiceListResponse\n\t59,  // 261: machine.MachineService.ServiceRestart:output_type -> machine.ServiceRestartResponse\n\t53,  // 262: machine.MachineService.ServiceStart:output_type -> machine.ServiceStartResponse\n\t56,  // 263: machine.MachineService.ServiceStop:output_type -> machine.ServiceStopResponse\n\t41,  // 264: machine.MachineService.Shutdown:output_type -> machine.ShutdownResponse\n\t94,  // 265: machine.MachineService.Stats:output_type -> machine.StatsResponse\n\t103, // 266: machine.MachineService.SystemStat:output_type -> machine.SystemStatResponse\n\t44,  // 267: machine.MachineService.Upgrade:output_type -> machine.UpgradeResponse\n\t70,  // 268: machine.MachineService.Version:output_type -> machine.VersionResponse\n\t169, // 269: machine.MachineService.GenerateClientConfiguration:output_type -> machine.GenerateClientConfigurationResponse\n\t201, // 270: machine.MachineService.PacketCapture:output_type -> common.Data\n\t175, // 271: machine.MachineService.Netstat:output_type -> machine.NetstatResponse\n\t178, // 272: machine.MachineService.MetaWrite:output_type -> machine.MetaWriteResponse\n\t181, // 273: machine.MachineService.MetaDelete:output_type -> machine.MetaDeleteResponse\n\t183, // 274: machine.MachineService.ImageList:output_type -> machine.ImageListResponse\n\t186, // 275: machine.MachineService.ImagePull:output_type -> machine.ImagePullResponse\n\t222, // [222:276] is the sub-list for method output_type\n\t168, // [168:222] is the sub-list for method input_type\n\t168, // [168:168] is the sub-list for extension type_name\n\t168, // [168:168] is the sub-list for extension extendee\n\t0,   // [0:168] is the sub-list for field type_name\n}\n\nfunc init() { file_machine_machine_proto_init() }\nfunc file_machine_machine_proto_init() {\n\tif File_machine_machine_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_machine_machine_proto_rawDesc), len(file_machine_machine_proto_rawDesc)),\n\t\t\tNumEnums:      15,\n\t\t\tNumMessages:   178,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_machine_machine_proto_goTypes,\n\t\tDependencyIndexes: file_machine_machine_proto_depIdxs,\n\t\tEnumInfos:         file_machine_machine_proto_enumTypes,\n\t\tMessageInfos:      file_machine_machine_proto_msgTypes,\n\t}.Build()\n\tFile_machine_machine_proto = out.File\n\tfile_machine_machine_proto_goTypes = nil\n\tfile_machine_machine_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/machine_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: machine/machine.proto\n\npackage machine\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tMachineService_ApplyConfiguration_FullMethodName          = \"/machine.MachineService/ApplyConfiguration\"\n\tMachineService_Bootstrap_FullMethodName                   = \"/machine.MachineService/Bootstrap\"\n\tMachineService_Containers_FullMethodName                  = \"/machine.MachineService/Containers\"\n\tMachineService_Copy_FullMethodName                        = \"/machine.MachineService/Copy\"\n\tMachineService_CPUFreqStats_FullMethodName                = \"/machine.MachineService/CPUFreqStats\"\n\tMachineService_CPUInfo_FullMethodName                     = \"/machine.MachineService/CPUInfo\"\n\tMachineService_DiskStats_FullMethodName                   = \"/machine.MachineService/DiskStats\"\n\tMachineService_Dmesg_FullMethodName                       = \"/machine.MachineService/Dmesg\"\n\tMachineService_Events_FullMethodName                      = \"/machine.MachineService/Events\"\n\tMachineService_EtcdMemberList_FullMethodName              = \"/machine.MachineService/EtcdMemberList\"\n\tMachineService_EtcdRemoveMemberByID_FullMethodName        = \"/machine.MachineService/EtcdRemoveMemberByID\"\n\tMachineService_EtcdLeaveCluster_FullMethodName            = \"/machine.MachineService/EtcdLeaveCluster\"\n\tMachineService_EtcdForfeitLeadership_FullMethodName       = \"/machine.MachineService/EtcdForfeitLeadership\"\n\tMachineService_EtcdRecover_FullMethodName                 = \"/machine.MachineService/EtcdRecover\"\n\tMachineService_EtcdSnapshot_FullMethodName                = \"/machine.MachineService/EtcdSnapshot\"\n\tMachineService_EtcdAlarmList_FullMethodName               = \"/machine.MachineService/EtcdAlarmList\"\n\tMachineService_EtcdAlarmDisarm_FullMethodName             = \"/machine.MachineService/EtcdAlarmDisarm\"\n\tMachineService_EtcdDefragment_FullMethodName              = \"/machine.MachineService/EtcdDefragment\"\n\tMachineService_EtcdStatus_FullMethodName                  = \"/machine.MachineService/EtcdStatus\"\n\tMachineService_EtcdDowngradeValidate_FullMethodName       = \"/machine.MachineService/EtcdDowngradeValidate\"\n\tMachineService_EtcdDowngradeEnable_FullMethodName         = \"/machine.MachineService/EtcdDowngradeEnable\"\n\tMachineService_EtcdDowngradeCancel_FullMethodName         = \"/machine.MachineService/EtcdDowngradeCancel\"\n\tMachineService_Hostname_FullMethodName                    = \"/machine.MachineService/Hostname\"\n\tMachineService_Kubeconfig_FullMethodName                  = \"/machine.MachineService/Kubeconfig\"\n\tMachineService_List_FullMethodName                        = \"/machine.MachineService/List\"\n\tMachineService_DiskUsage_FullMethodName                   = \"/machine.MachineService/DiskUsage\"\n\tMachineService_LoadAvg_FullMethodName                     = \"/machine.MachineService/LoadAvg\"\n\tMachineService_Logs_FullMethodName                        = \"/machine.MachineService/Logs\"\n\tMachineService_LogsContainers_FullMethodName              = \"/machine.MachineService/LogsContainers\"\n\tMachineService_Memory_FullMethodName                      = \"/machine.MachineService/Memory\"\n\tMachineService_Mounts_FullMethodName                      = \"/machine.MachineService/Mounts\"\n\tMachineService_NetworkDeviceStats_FullMethodName          = \"/machine.MachineService/NetworkDeviceStats\"\n\tMachineService_Processes_FullMethodName                   = \"/machine.MachineService/Processes\"\n\tMachineService_Read_FullMethodName                        = \"/machine.MachineService/Read\"\n\tMachineService_Reboot_FullMethodName                      = \"/machine.MachineService/Reboot\"\n\tMachineService_Restart_FullMethodName                     = \"/machine.MachineService/Restart\"\n\tMachineService_Rollback_FullMethodName                    = \"/machine.MachineService/Rollback\"\n\tMachineService_Reset_FullMethodName                       = \"/machine.MachineService/Reset\"\n\tMachineService_ServiceList_FullMethodName                 = \"/machine.MachineService/ServiceList\"\n\tMachineService_ServiceRestart_FullMethodName              = \"/machine.MachineService/ServiceRestart\"\n\tMachineService_ServiceStart_FullMethodName                = \"/machine.MachineService/ServiceStart\"\n\tMachineService_ServiceStop_FullMethodName                 = \"/machine.MachineService/ServiceStop\"\n\tMachineService_Shutdown_FullMethodName                    = \"/machine.MachineService/Shutdown\"\n\tMachineService_Stats_FullMethodName                       = \"/machine.MachineService/Stats\"\n\tMachineService_SystemStat_FullMethodName                  = \"/machine.MachineService/SystemStat\"\n\tMachineService_Upgrade_FullMethodName                     = \"/machine.MachineService/Upgrade\"\n\tMachineService_Version_FullMethodName                     = \"/machine.MachineService/Version\"\n\tMachineService_GenerateClientConfiguration_FullMethodName = \"/machine.MachineService/GenerateClientConfiguration\"\n\tMachineService_PacketCapture_FullMethodName               = \"/machine.MachineService/PacketCapture\"\n\tMachineService_Netstat_FullMethodName                     = \"/machine.MachineService/Netstat\"\n\tMachineService_MetaWrite_FullMethodName                   = \"/machine.MachineService/MetaWrite\"\n\tMachineService_MetaDelete_FullMethodName                  = \"/machine.MachineService/MetaDelete\"\n\tMachineService_ImageList_FullMethodName                   = \"/machine.MachineService/ImageList\"\n\tMachineService_ImagePull_FullMethodName                   = \"/machine.MachineService/ImagePull\"\n)\n\n// MachineServiceClient is the client API for MachineService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The machine service definition.\ntype MachineServiceClient interface {\n\tApplyConfiguration(ctx context.Context, in *ApplyConfigurationRequest, opts ...grpc.CallOption) (*ApplyConfigurationResponse, error)\n\t// Bootstrap method makes control plane node enter etcd bootstrap mode.\n\t// Node aborts etcd join sequence and creates single-node etcd cluster.\n\t// If recover_etcd argument is specified, etcd is recovered from a snapshot\n\t// uploaded with EtcdRecover.\n\tBootstrap(ctx context.Context, in *BootstrapRequest, opts ...grpc.CallOption) (*BootstrapResponse, error)\n\tContainers(ctx context.Context, in *ContainersRequest, opts ...grpc.CallOption) (*ContainersResponse, error)\n\tCopy(ctx context.Context, in *CopyRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\tCPUFreqStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUFreqStatsResponse, error)\n\tCPUInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUInfoResponse, error)\n\tDiskStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DiskStatsResponse, error)\n\tDmesg(ctx context.Context, in *DmesgRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\tEvents(ctx context.Context, in *EventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error)\n\tEtcdMemberList(ctx context.Context, in *EtcdMemberListRequest, opts ...grpc.CallOption) (*EtcdMemberListResponse, error)\n\t// EtcdRemoveMemberByID removes a member from the etcd cluster identified by member ID.\n\t// This API should be used to remove members which don't have an associated Talos node anymore.\n\t// To remove a member with a running Talos node, use EtcdLeaveCluster API on the node to be removed.\n\tEtcdRemoveMemberByID(ctx context.Context, in *EtcdRemoveMemberByIDRequest, opts ...grpc.CallOption) (*EtcdRemoveMemberByIDResponse, error)\n\tEtcdLeaveCluster(ctx context.Context, in *EtcdLeaveClusterRequest, opts ...grpc.CallOption) (*EtcdLeaveClusterResponse, error)\n\tEtcdForfeitLeadership(ctx context.Context, in *EtcdForfeitLeadershipRequest, opts ...grpc.CallOption) (*EtcdForfeitLeadershipResponse, error)\n\t// EtcdRecover method uploads etcd data snapshot created with EtcdSnapshot\n\t// to the node.\n\t// Snapshot can be later used to recover the cluster via Bootstrap method.\n\tEtcdRecover(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[common.Data, EtcdRecoverResponse], error)\n\t// EtcdSnapshot method creates etcd data snapshot (backup) from the local etcd instance\n\t// and streams it back to the client.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdSnapshot(ctx context.Context, in *EtcdSnapshotRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\t// EtcdAlarmList lists etcd alarms for the current node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdAlarmList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdAlarmListResponse, error)\n\t// EtcdAlarmDisarm disarms etcd alarms for the current node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdAlarmDisarm(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdAlarmDisarmResponse, error)\n\t// EtcdDefragment defragments etcd data directory for the current node.\n\t// Defragmentation is a resource-heavy operation, so it should only run on a specific\n\t// node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDefragment(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdDefragmentResponse, error)\n\t// EtcdStatus returns etcd status for the current member.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdStatusResponse, error)\n\t// EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeValidate(ctx context.Context, in *EtcdDowngradeValidateRequest, opts ...grpc.CallOption) (*EtcdDowngradeValidateResponse, error)\n\t// EtcdDowngradeEnable enables etcd cluster downgrade to a specific version.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeEnable(ctx context.Context, in *EtcdDowngradeEnableRequest, opts ...grpc.CallOption) (*EtcdDowngradeEnableResponse, error)\n\t// EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeCancel(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdDowngradeCancelResponse, error)\n\tHostname(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HostnameResponse, error)\n\tKubeconfig(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\tList(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[FileInfo], error)\n\tDiskUsage(ctx context.Context, in *DiskUsageRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DiskUsageInfo], error)\n\tLoadAvg(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*LoadAvgResponse, error)\n\tLogs(ctx context.Context, in *LogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\tLogsContainers(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*LogsContainersResponse, error)\n\tMemory(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MemoryResponse, error)\n\tMounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MountsResponse, error)\n\tNetworkDeviceStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*NetworkDeviceStatsResponse, error)\n\tProcesses(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ProcessesResponse, error)\n\tRead(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\tReboot(ctx context.Context, in *RebootRequest, opts ...grpc.CallOption) (*RebootResponse, error)\n\tRestart(ctx context.Context, in *RestartRequest, opts ...grpc.CallOption) (*RestartResponse, error)\n\tRollback(ctx context.Context, in *RollbackRequest, opts ...grpc.CallOption) (*RollbackResponse, error)\n\tReset(ctx context.Context, in *ResetRequest, opts ...grpc.CallOption) (*ResetResponse, error)\n\tServiceList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ServiceListResponse, error)\n\tServiceRestart(ctx context.Context, in *ServiceRestartRequest, opts ...grpc.CallOption) (*ServiceRestartResponse, error)\n\tServiceStart(ctx context.Context, in *ServiceStartRequest, opts ...grpc.CallOption) (*ServiceStartResponse, error)\n\tServiceStop(ctx context.Context, in *ServiceStopRequest, opts ...grpc.CallOption) (*ServiceStopResponse, error)\n\tShutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error)\n\tStats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error)\n\tSystemStat(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SystemStatResponse, error)\n\t// Deprecated: Do not use.\n\t// Upgrade initiates the upgrade of the node to a new version of Talos.\n\t//\n\t// Use LifecycleService Upgrade RPC instead.\n\tUpgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (*UpgradeResponse, error)\n\tVersion(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error)\n\t// GenerateClientConfiguration generates talosctl client configuration (talosconfig).\n\tGenerateClientConfiguration(ctx context.Context, in *GenerateClientConfigurationRequest, opts ...grpc.CallOption) (*GenerateClientConfigurationResponse, error)\n\t// PacketCapture performs packet capture and streams back pcap file.\n\tPacketCapture(ctx context.Context, in *PacketCaptureRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error)\n\t// Netstat provides information about network connections.\n\tNetstat(ctx context.Context, in *NetstatRequest, opts ...grpc.CallOption) (*NetstatResponse, error)\n\t// MetaWrite writes a META key-value pair.\n\tMetaWrite(ctx context.Context, in *MetaWriteRequest, opts ...grpc.CallOption) (*MetaWriteResponse, error)\n\t// MetaDelete deletes a META key.\n\tMetaDelete(ctx context.Context, in *MetaDeleteRequest, opts ...grpc.CallOption) (*MetaDeleteResponse, error)\n\t// Deprecated: Do not use.\n\t// ImageList lists images in the CRI.\n\t//\n\t// Use ImageService List RPC instead.\n\tImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageListResponse], error)\n\t// Deprecated: Do not use.\n\t// ImagePull pulls an image into the CRI.\n\t//\n\t// Use ImageService Pull RPC instead.\n\tImagePull(ctx context.Context, in *ImagePullRequest, opts ...grpc.CallOption) (*ImagePullResponse, error)\n}\n\ntype machineServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewMachineServiceClient(cc grpc.ClientConnInterface) MachineServiceClient {\n\treturn &machineServiceClient{cc}\n}\n\nfunc (c *machineServiceClient) ApplyConfiguration(ctx context.Context, in *ApplyConfigurationRequest, opts ...grpc.CallOption) (*ApplyConfigurationResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ApplyConfigurationResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ApplyConfiguration_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Bootstrap(ctx context.Context, in *BootstrapRequest, opts ...grpc.CallOption) (*BootstrapResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(BootstrapResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Bootstrap_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Containers(ctx context.Context, in *ContainersRequest, opts ...grpc.CallOption) (*ContainersResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ContainersResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Containers_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Copy(ctx context.Context, in *CopyRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[0], MachineService_Copy_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[CopyRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_CopyClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) CPUFreqStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUFreqStatsResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(CPUFreqStatsResponse)\n\terr := c.cc.Invoke(ctx, MachineService_CPUFreqStats_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) CPUInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*CPUInfoResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(CPUInfoResponse)\n\terr := c.cc.Invoke(ctx, MachineService_CPUInfo_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) DiskStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DiskStatsResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(DiskStatsResponse)\n\terr := c.cc.Invoke(ctx, MachineService_DiskStats_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Dmesg(ctx context.Context, in *DmesgRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[1], MachineService_Dmesg_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[DmesgRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_DmesgClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) Events(ctx context.Context, in *EventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[2], MachineService_Events_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[EventsRequest, Event]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EventsClient = grpc.ServerStreamingClient[Event]\n\nfunc (c *machineServiceClient) EtcdMemberList(ctx context.Context, in *EtcdMemberListRequest, opts ...grpc.CallOption) (*EtcdMemberListResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdMemberListResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdMemberList_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdRemoveMemberByID(ctx context.Context, in *EtcdRemoveMemberByIDRequest, opts ...grpc.CallOption) (*EtcdRemoveMemberByIDResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdRemoveMemberByIDResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdRemoveMemberByID_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdLeaveCluster(ctx context.Context, in *EtcdLeaveClusterRequest, opts ...grpc.CallOption) (*EtcdLeaveClusterResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdLeaveClusterResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdLeaveCluster_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdForfeitLeadership(ctx context.Context, in *EtcdForfeitLeadershipRequest, opts ...grpc.CallOption) (*EtcdForfeitLeadershipResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdForfeitLeadershipResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdForfeitLeadership_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdRecover(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[common.Data, EtcdRecoverResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[3], MachineService_EtcdRecover_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[common.Data, EtcdRecoverResponse]{ClientStream: stream}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EtcdRecoverClient = grpc.ClientStreamingClient[common.Data, EtcdRecoverResponse]\n\nfunc (c *machineServiceClient) EtcdSnapshot(ctx context.Context, in *EtcdSnapshotRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[4], MachineService_EtcdSnapshot_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[EtcdSnapshotRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EtcdSnapshotClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) EtcdAlarmList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdAlarmListResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdAlarmListResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdAlarmList_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdAlarmDisarm(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdAlarmDisarmResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdAlarmDisarmResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdAlarmDisarm_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdDefragment(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdDefragmentResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdDefragmentResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdDefragment_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdStatusResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdStatusResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdStatus_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdDowngradeValidate(ctx context.Context, in *EtcdDowngradeValidateRequest, opts ...grpc.CallOption) (*EtcdDowngradeValidateResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdDowngradeValidateResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdDowngradeValidate_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdDowngradeEnable(ctx context.Context, in *EtcdDowngradeEnableRequest, opts ...grpc.CallOption) (*EtcdDowngradeEnableResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdDowngradeEnableResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdDowngradeEnable_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) EtcdDowngradeCancel(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*EtcdDowngradeCancelResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(EtcdDowngradeCancelResponse)\n\terr := c.cc.Invoke(ctx, MachineService_EtcdDowngradeCancel_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Hostname(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HostnameResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(HostnameResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Hostname_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Kubeconfig(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[5], MachineService_Kubeconfig_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[emptypb.Empty, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_KubeconfigClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[FileInfo], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[6], MachineService_List_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ListRequest, FileInfo]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ListClient = grpc.ServerStreamingClient[FileInfo]\n\nfunc (c *machineServiceClient) DiskUsage(ctx context.Context, in *DiskUsageRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DiskUsageInfo], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[7], MachineService_DiskUsage_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[DiskUsageRequest, DiskUsageInfo]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_DiskUsageClient = grpc.ServerStreamingClient[DiskUsageInfo]\n\nfunc (c *machineServiceClient) LoadAvg(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*LoadAvgResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(LoadAvgResponse)\n\terr := c.cc.Invoke(ctx, MachineService_LoadAvg_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Logs(ctx context.Context, in *LogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[8], MachineService_Logs_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[LogsRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_LogsClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) LogsContainers(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*LogsContainersResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(LogsContainersResponse)\n\terr := c.cc.Invoke(ctx, MachineService_LogsContainers_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Memory(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MemoryResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(MemoryResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Memory_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Mounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MountsResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(MountsResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Mounts_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) NetworkDeviceStats(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*NetworkDeviceStatsResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(NetworkDeviceStatsResponse)\n\terr := c.cc.Invoke(ctx, MachineService_NetworkDeviceStats_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Processes(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ProcessesResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ProcessesResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Processes_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[9], MachineService_Read_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ReadRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ReadClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) Reboot(ctx context.Context, in *RebootRequest, opts ...grpc.CallOption) (*RebootResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(RebootResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Reboot_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Restart(ctx context.Context, in *RestartRequest, opts ...grpc.CallOption) (*RestartResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(RestartResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Restart_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Rollback(ctx context.Context, in *RollbackRequest, opts ...grpc.CallOption) (*RollbackResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(RollbackResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Rollback_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Reset(ctx context.Context, in *ResetRequest, opts ...grpc.CallOption) (*ResetResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ResetResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Reset_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) ServiceList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ServiceListResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ServiceListResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ServiceList_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) ServiceRestart(ctx context.Context, in *ServiceRestartRequest, opts ...grpc.CallOption) (*ServiceRestartResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ServiceRestartResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ServiceRestart_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) ServiceStart(ctx context.Context, in *ServiceStartRequest, opts ...grpc.CallOption) (*ServiceStartResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ServiceStartResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ServiceStart_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) ServiceStop(ctx context.Context, in *ServiceStopRequest, opts ...grpc.CallOption) (*ServiceStopResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ServiceStopResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ServiceStop_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ShutdownResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Shutdown_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(StatsResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Stats_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) SystemStat(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*SystemStatResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(SystemStatResponse)\n\terr := c.cc.Invoke(ctx, MachineService_SystemStat_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// Deprecated: Do not use.\nfunc (c *machineServiceClient) Upgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (*UpgradeResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(UpgradeResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Upgrade_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(VersionResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Version_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) GenerateClientConfiguration(ctx context.Context, in *GenerateClientConfigurationRequest, opts ...grpc.CallOption) (*GenerateClientConfigurationResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(GenerateClientConfigurationResponse)\n\terr := c.cc.Invoke(ctx, MachineService_GenerateClientConfiguration_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) PacketCapture(ctx context.Context, in *PacketCaptureRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[common.Data], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[10], MachineService_PacketCapture_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[PacketCaptureRequest, common.Data]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_PacketCaptureClient = grpc.ServerStreamingClient[common.Data]\n\nfunc (c *machineServiceClient) Netstat(ctx context.Context, in *NetstatRequest, opts ...grpc.CallOption) (*NetstatResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(NetstatResponse)\n\terr := c.cc.Invoke(ctx, MachineService_Netstat_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) MetaWrite(ctx context.Context, in *MetaWriteRequest, opts ...grpc.CallOption) (*MetaWriteResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(MetaWriteResponse)\n\terr := c.cc.Invoke(ctx, MachineService_MetaWrite_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *machineServiceClient) MetaDelete(ctx context.Context, in *MetaDeleteRequest, opts ...grpc.CallOption) (*MetaDeleteResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(MetaDeleteResponse)\n\terr := c.cc.Invoke(ctx, MachineService_MetaDelete_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// Deprecated: Do not use.\nfunc (c *machineServiceClient) ImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImageListResponse], error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tstream, err := c.cc.NewStream(ctx, &MachineService_ServiceDesc.Streams[11], MachineService_ImageList_FullMethodName, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &grpc.GenericClientStream[ImageListRequest, ImageListResponse]{ClientStream: stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ImageListClient = grpc.ServerStreamingClient[ImageListResponse]\n\n// Deprecated: Do not use.\nfunc (c *machineServiceClient) ImagePull(ctx context.Context, in *ImagePullRequest, opts ...grpc.CallOption) (*ImagePullResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(ImagePullResponse)\n\terr := c.cc.Invoke(ctx, MachineService_ImagePull_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// MachineServiceServer is the server API for MachineService service.\n// All implementations must embed UnimplementedMachineServiceServer\n// for forward compatibility.\n//\n// The machine service definition.\ntype MachineServiceServer interface {\n\tApplyConfiguration(context.Context, *ApplyConfigurationRequest) (*ApplyConfigurationResponse, error)\n\t// Bootstrap method makes control plane node enter etcd bootstrap mode.\n\t// Node aborts etcd join sequence and creates single-node etcd cluster.\n\t// If recover_etcd argument is specified, etcd is recovered from a snapshot\n\t// uploaded with EtcdRecover.\n\tBootstrap(context.Context, *BootstrapRequest) (*BootstrapResponse, error)\n\tContainers(context.Context, *ContainersRequest) (*ContainersResponse, error)\n\tCopy(*CopyRequest, grpc.ServerStreamingServer[common.Data]) error\n\tCPUFreqStats(context.Context, *emptypb.Empty) (*CPUFreqStatsResponse, error)\n\tCPUInfo(context.Context, *emptypb.Empty) (*CPUInfoResponse, error)\n\tDiskStats(context.Context, *emptypb.Empty) (*DiskStatsResponse, error)\n\tDmesg(*DmesgRequest, grpc.ServerStreamingServer[common.Data]) error\n\tEvents(*EventsRequest, grpc.ServerStreamingServer[Event]) error\n\tEtcdMemberList(context.Context, *EtcdMemberListRequest) (*EtcdMemberListResponse, error)\n\t// EtcdRemoveMemberByID removes a member from the etcd cluster identified by member ID.\n\t// This API should be used to remove members which don't have an associated Talos node anymore.\n\t// To remove a member with a running Talos node, use EtcdLeaveCluster API on the node to be removed.\n\tEtcdRemoveMemberByID(context.Context, *EtcdRemoveMemberByIDRequest) (*EtcdRemoveMemberByIDResponse, error)\n\tEtcdLeaveCluster(context.Context, *EtcdLeaveClusterRequest) (*EtcdLeaveClusterResponse, error)\n\tEtcdForfeitLeadership(context.Context, *EtcdForfeitLeadershipRequest) (*EtcdForfeitLeadershipResponse, error)\n\t// EtcdRecover method uploads etcd data snapshot created with EtcdSnapshot\n\t// to the node.\n\t// Snapshot can be later used to recover the cluster via Bootstrap method.\n\tEtcdRecover(grpc.ClientStreamingServer[common.Data, EtcdRecoverResponse]) error\n\t// EtcdSnapshot method creates etcd data snapshot (backup) from the local etcd instance\n\t// and streams it back to the client.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdSnapshot(*EtcdSnapshotRequest, grpc.ServerStreamingServer[common.Data]) error\n\t// EtcdAlarmList lists etcd alarms for the current node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdAlarmList(context.Context, *emptypb.Empty) (*EtcdAlarmListResponse, error)\n\t// EtcdAlarmDisarm disarms etcd alarms for the current node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdAlarmDisarm(context.Context, *emptypb.Empty) (*EtcdAlarmDisarmResponse, error)\n\t// EtcdDefragment defragments etcd data directory for the current node.\n\t// Defragmentation is a resource-heavy operation, so it should only run on a specific\n\t// node.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDefragment(context.Context, *emptypb.Empty) (*EtcdDefragmentResponse, error)\n\t// EtcdStatus returns etcd status for the current member.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdStatus(context.Context, *emptypb.Empty) (*EtcdStatusResponse, error)\n\t// EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeValidate(context.Context, *EtcdDowngradeValidateRequest) (*EtcdDowngradeValidateResponse, error)\n\t// EtcdDowngradeEnable enables etcd cluster downgrade to a specific version.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeEnable(context.Context, *EtcdDowngradeEnableRequest) (*EtcdDowngradeEnableResponse, error)\n\t// EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress.\n\t// This method is available only on control plane nodes (which run etcd).\n\tEtcdDowngradeCancel(context.Context, *emptypb.Empty) (*EtcdDowngradeCancelResponse, error)\n\tHostname(context.Context, *emptypb.Empty) (*HostnameResponse, error)\n\tKubeconfig(*emptypb.Empty, grpc.ServerStreamingServer[common.Data]) error\n\tList(*ListRequest, grpc.ServerStreamingServer[FileInfo]) error\n\tDiskUsage(*DiskUsageRequest, grpc.ServerStreamingServer[DiskUsageInfo]) error\n\tLoadAvg(context.Context, *emptypb.Empty) (*LoadAvgResponse, error)\n\tLogs(*LogsRequest, grpc.ServerStreamingServer[common.Data]) error\n\tLogsContainers(context.Context, *emptypb.Empty) (*LogsContainersResponse, error)\n\tMemory(context.Context, *emptypb.Empty) (*MemoryResponse, error)\n\tMounts(context.Context, *emptypb.Empty) (*MountsResponse, error)\n\tNetworkDeviceStats(context.Context, *emptypb.Empty) (*NetworkDeviceStatsResponse, error)\n\tProcesses(context.Context, *emptypb.Empty) (*ProcessesResponse, error)\n\tRead(*ReadRequest, grpc.ServerStreamingServer[common.Data]) error\n\tReboot(context.Context, *RebootRequest) (*RebootResponse, error)\n\tRestart(context.Context, *RestartRequest) (*RestartResponse, error)\n\tRollback(context.Context, *RollbackRequest) (*RollbackResponse, error)\n\tReset(context.Context, *ResetRequest) (*ResetResponse, error)\n\tServiceList(context.Context, *emptypb.Empty) (*ServiceListResponse, error)\n\tServiceRestart(context.Context, *ServiceRestartRequest) (*ServiceRestartResponse, error)\n\tServiceStart(context.Context, *ServiceStartRequest) (*ServiceStartResponse, error)\n\tServiceStop(context.Context, *ServiceStopRequest) (*ServiceStopResponse, error)\n\tShutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error)\n\tStats(context.Context, *StatsRequest) (*StatsResponse, error)\n\tSystemStat(context.Context, *emptypb.Empty) (*SystemStatResponse, error)\n\t// Deprecated: Do not use.\n\t// Upgrade initiates the upgrade of the node to a new version of Talos.\n\t//\n\t// Use LifecycleService Upgrade RPC instead.\n\tUpgrade(context.Context, *UpgradeRequest) (*UpgradeResponse, error)\n\tVersion(context.Context, *emptypb.Empty) (*VersionResponse, error)\n\t// GenerateClientConfiguration generates talosctl client configuration (talosconfig).\n\tGenerateClientConfiguration(context.Context, *GenerateClientConfigurationRequest) (*GenerateClientConfigurationResponse, error)\n\t// PacketCapture performs packet capture and streams back pcap file.\n\tPacketCapture(*PacketCaptureRequest, grpc.ServerStreamingServer[common.Data]) error\n\t// Netstat provides information about network connections.\n\tNetstat(context.Context, *NetstatRequest) (*NetstatResponse, error)\n\t// MetaWrite writes a META key-value pair.\n\tMetaWrite(context.Context, *MetaWriteRequest) (*MetaWriteResponse, error)\n\t// MetaDelete deletes a META key.\n\tMetaDelete(context.Context, *MetaDeleteRequest) (*MetaDeleteResponse, error)\n\t// Deprecated: Do not use.\n\t// ImageList lists images in the CRI.\n\t//\n\t// Use ImageService List RPC instead.\n\tImageList(*ImageListRequest, grpc.ServerStreamingServer[ImageListResponse]) error\n\t// Deprecated: Do not use.\n\t// ImagePull pulls an image into the CRI.\n\t//\n\t// Use ImageService Pull RPC instead.\n\tImagePull(context.Context, *ImagePullRequest) (*ImagePullResponse, error)\n\tmustEmbedUnimplementedMachineServiceServer()\n}\n\n// UnimplementedMachineServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedMachineServiceServer struct{}\n\nfunc (UnimplementedMachineServiceServer) ApplyConfiguration(context.Context, *ApplyConfigurationRequest) (*ApplyConfigurationResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ApplyConfiguration not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Bootstrap(context.Context, *BootstrapRequest) (*BootstrapResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Bootstrap not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Containers(context.Context, *ContainersRequest) (*ContainersResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Containers not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Copy(*CopyRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method Copy not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) CPUFreqStats(context.Context, *emptypb.Empty) (*CPUFreqStatsResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method CPUFreqStats not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) CPUInfo(context.Context, *emptypb.Empty) (*CPUInfoResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method CPUInfo not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) DiskStats(context.Context, *emptypb.Empty) (*DiskStatsResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method DiskStats not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Dmesg(*DmesgRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method Dmesg not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Events(*EventsRequest, grpc.ServerStreamingServer[Event]) error {\n\treturn status.Error(codes.Unimplemented, \"method Events not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdMemberList(context.Context, *EtcdMemberListRequest) (*EtcdMemberListResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdMemberList not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdRemoveMemberByID(context.Context, *EtcdRemoveMemberByIDRequest) (*EtcdRemoveMemberByIDResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdRemoveMemberByID not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdLeaveCluster(context.Context, *EtcdLeaveClusterRequest) (*EtcdLeaveClusterResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdLeaveCluster not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdForfeitLeadership(context.Context, *EtcdForfeitLeadershipRequest) (*EtcdForfeitLeadershipResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdForfeitLeadership not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdRecover(grpc.ClientStreamingServer[common.Data, EtcdRecoverResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method EtcdRecover not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdSnapshot(*EtcdSnapshotRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method EtcdSnapshot not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdAlarmList(context.Context, *emptypb.Empty) (*EtcdAlarmListResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdAlarmList not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdAlarmDisarm(context.Context, *emptypb.Empty) (*EtcdAlarmDisarmResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdAlarmDisarm not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdDefragment(context.Context, *emptypb.Empty) (*EtcdDefragmentResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdDefragment not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdStatus(context.Context, *emptypb.Empty) (*EtcdStatusResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdStatus not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdDowngradeValidate(context.Context, *EtcdDowngradeValidateRequest) (*EtcdDowngradeValidateResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdDowngradeValidate not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdDowngradeEnable(context.Context, *EtcdDowngradeEnableRequest) (*EtcdDowngradeEnableResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdDowngradeEnable not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) EtcdDowngradeCancel(context.Context, *emptypb.Empty) (*EtcdDowngradeCancelResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method EtcdDowngradeCancel not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Hostname(context.Context, *emptypb.Empty) (*HostnameResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Hostname not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Kubeconfig(*emptypb.Empty, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method Kubeconfig not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) List(*ListRequest, grpc.ServerStreamingServer[FileInfo]) error {\n\treturn status.Error(codes.Unimplemented, \"method List not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) DiskUsage(*DiskUsageRequest, grpc.ServerStreamingServer[DiskUsageInfo]) error {\n\treturn status.Error(codes.Unimplemented, \"method DiskUsage not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) LoadAvg(context.Context, *emptypb.Empty) (*LoadAvgResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method LoadAvg not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Logs(*LogsRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method Logs not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) LogsContainers(context.Context, *emptypb.Empty) (*LogsContainersResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method LogsContainers not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Memory(context.Context, *emptypb.Empty) (*MemoryResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Memory not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Mounts(context.Context, *emptypb.Empty) (*MountsResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Mounts not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) NetworkDeviceStats(context.Context, *emptypb.Empty) (*NetworkDeviceStatsResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method NetworkDeviceStats not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Processes(context.Context, *emptypb.Empty) (*ProcessesResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Processes not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Read(*ReadRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method Read not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Reboot(context.Context, *RebootRequest) (*RebootResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Reboot not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Restart(context.Context, *RestartRequest) (*RestartResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Restart not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Rollback(context.Context, *RollbackRequest) (*RollbackResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Rollback not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Reset(context.Context, *ResetRequest) (*ResetResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Reset not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ServiceList(context.Context, *emptypb.Empty) (*ServiceListResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ServiceList not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ServiceRestart(context.Context, *ServiceRestartRequest) (*ServiceRestartResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ServiceRestart not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ServiceStart(context.Context, *ServiceStartRequest) (*ServiceStartResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ServiceStart not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ServiceStop(context.Context, *ServiceStopRequest) (*ServiceStopResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ServiceStop not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Shutdown not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Stats(context.Context, *StatsRequest) (*StatsResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Stats not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) SystemStat(context.Context, *emptypb.Empty) (*SystemStatResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method SystemStat not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Upgrade(context.Context, *UpgradeRequest) (*UpgradeResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Upgrade not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Version(context.Context, *emptypb.Empty) (*VersionResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Version not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) GenerateClientConfiguration(context.Context, *GenerateClientConfigurationRequest) (*GenerateClientConfigurationResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method GenerateClientConfiguration not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) PacketCapture(*PacketCaptureRequest, grpc.ServerStreamingServer[common.Data]) error {\n\treturn status.Error(codes.Unimplemented, \"method PacketCapture not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) Netstat(context.Context, *NetstatRequest) (*NetstatResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Netstat not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) MetaWrite(context.Context, *MetaWriteRequest) (*MetaWriteResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method MetaWrite not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) MetaDelete(context.Context, *MetaDeleteRequest) (*MetaDeleteResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method MetaDelete not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ImageList(*ImageListRequest, grpc.ServerStreamingServer[ImageListResponse]) error {\n\treturn status.Error(codes.Unimplemented, \"method ImageList not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) ImagePull(context.Context, *ImagePullRequest) (*ImagePullResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method ImagePull not implemented\")\n}\nfunc (UnimplementedMachineServiceServer) mustEmbedUnimplementedMachineServiceServer() {}\nfunc (UnimplementedMachineServiceServer) testEmbeddedByValue()                        {}\n\n// UnsafeMachineServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to MachineServiceServer will\n// result in compilation errors.\ntype UnsafeMachineServiceServer interface {\n\tmustEmbedUnimplementedMachineServiceServer()\n}\n\nfunc RegisterMachineServiceServer(s grpc.ServiceRegistrar, srv MachineServiceServer) {\n\t// If the following call panics, it indicates UnimplementedMachineServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&MachineService_ServiceDesc, srv)\n}\n\nfunc _MachineService_ApplyConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ApplyConfigurationRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ApplyConfiguration(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ApplyConfiguration_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ApplyConfiguration(ctx, req.(*ApplyConfigurationRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Bootstrap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BootstrapRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Bootstrap(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Bootstrap_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Bootstrap(ctx, req.(*BootstrapRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Containers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ContainersRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Containers(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Containers_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Containers(ctx, req.(*ContainersRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Copy_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(CopyRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Copy(m, &grpc.GenericServerStream[CopyRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_CopyServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_CPUFreqStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).CPUFreqStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_CPUFreqStats_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).CPUFreqStats(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_CPUInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).CPUInfo(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_CPUInfo_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).CPUInfo(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_DiskStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).DiskStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_DiskStats_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).DiskStats(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Dmesg_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(DmesgRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Dmesg(m, &grpc.GenericServerStream[DmesgRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_DmesgServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_Events_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(EventsRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Events(m, &grpc.GenericServerStream[EventsRequest, Event]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EventsServer = grpc.ServerStreamingServer[Event]\n\nfunc _MachineService_EtcdMemberList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdMemberListRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdMemberList(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdMemberList_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdMemberList(ctx, req.(*EtcdMemberListRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdRemoveMemberByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdRemoveMemberByIDRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdRemoveMemberByID(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdRemoveMemberByID_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdRemoveMemberByID(ctx, req.(*EtcdRemoveMemberByIDRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdLeaveCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdLeaveClusterRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdLeaveCluster(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdLeaveCluster_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdLeaveCluster(ctx, req.(*EtcdLeaveClusterRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdForfeitLeadership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdForfeitLeadershipRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdForfeitLeadership(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdForfeitLeadership_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdForfeitLeadership(ctx, req.(*EtcdForfeitLeadershipRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdRecover_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(MachineServiceServer).EtcdRecover(&grpc.GenericServerStream[common.Data, EtcdRecoverResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EtcdRecoverServer = grpc.ClientStreamingServer[common.Data, EtcdRecoverResponse]\n\nfunc _MachineService_EtcdSnapshot_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(EtcdSnapshotRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).EtcdSnapshot(m, &grpc.GenericServerStream[EtcdSnapshotRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_EtcdSnapshotServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_EtcdAlarmList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdAlarmList(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdAlarmList_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdAlarmList(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdAlarmDisarm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdAlarmDisarm(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdAlarmDisarm_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdAlarmDisarm(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdDefragment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdDefragment(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdDefragment_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdDefragment(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdStatus(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdStatus_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdStatus(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdDowngradeValidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdDowngradeValidateRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeValidate(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdDowngradeValidate_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeValidate(ctx, req.(*EtcdDowngradeValidateRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdDowngradeEnable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(EtcdDowngradeEnableRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeEnable(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdDowngradeEnable_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeEnable(ctx, req.(*EtcdDowngradeEnableRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_EtcdDowngradeCancel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeCancel(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_EtcdDowngradeCancel_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).EtcdDowngradeCancel(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Hostname_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Hostname(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Hostname_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Hostname(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Kubeconfig_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(emptypb.Empty)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Kubeconfig(m, &grpc.GenericServerStream[emptypb.Empty, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_KubeconfigServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_List_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(ListRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).List(m, &grpc.GenericServerStream[ListRequest, FileInfo]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ListServer = grpc.ServerStreamingServer[FileInfo]\n\nfunc _MachineService_DiskUsage_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(DiskUsageRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).DiskUsage(m, &grpc.GenericServerStream[DiskUsageRequest, DiskUsageInfo]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_DiskUsageServer = grpc.ServerStreamingServer[DiskUsageInfo]\n\nfunc _MachineService_LoadAvg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).LoadAvg(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_LoadAvg_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).LoadAvg(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Logs_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(LogsRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Logs(m, &grpc.GenericServerStream[LogsRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_LogsServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_LogsContainers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).LogsContainers(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_LogsContainers_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).LogsContainers(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Memory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Memory(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Memory_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Memory(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Mounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Mounts(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Mounts_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Mounts(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_NetworkDeviceStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).NetworkDeviceStats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_NetworkDeviceStats_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).NetworkDeviceStats(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Processes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Processes(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Processes_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Processes(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Read_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(ReadRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).Read(m, &grpc.GenericServerStream[ReadRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ReadServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_Reboot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RebootRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Reboot(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Reboot_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Reboot(ctx, req.(*RebootRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Restart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RestartRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Restart(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Restart_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Restart(ctx, req.(*RestartRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Rollback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(RollbackRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Rollback(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Rollback_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Rollback(ctx, req.(*RollbackRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Reset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ResetRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Reset(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Reset_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Reset(ctx, req.(*ResetRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_ServiceList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ServiceList(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ServiceList_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ServiceList(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_ServiceRestart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ServiceRestartRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ServiceRestart(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ServiceRestart_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ServiceRestart(ctx, req.(*ServiceRestartRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_ServiceStart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ServiceStartRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ServiceStart(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ServiceStart_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ServiceStart(ctx, req.(*ServiceStartRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_ServiceStop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ServiceStopRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ServiceStop(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ServiceStop_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ServiceStop(ctx, req.(*ServiceStopRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Shutdown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ShutdownRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Shutdown(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Shutdown_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Shutdown(ctx, req.(*ShutdownRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(StatsRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Stats(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Stats_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Stats(ctx, req.(*StatsRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_SystemStat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).SystemStat(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_SystemStat_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).SystemStat(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Upgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(UpgradeRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Upgrade(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Upgrade_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Upgrade(ctx, req.(*UpgradeRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Version(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Version_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Version(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_GenerateClientConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GenerateClientConfigurationRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).GenerateClientConfiguration(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_GenerateClientConfiguration_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).GenerateClientConfiguration(ctx, req.(*GenerateClientConfigurationRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_PacketCapture_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(PacketCaptureRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).PacketCapture(m, &grpc.GenericServerStream[PacketCaptureRequest, common.Data]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_PacketCaptureServer = grpc.ServerStreamingServer[common.Data]\n\nfunc _MachineService_Netstat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(NetstatRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).Netstat(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_Netstat_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).Netstat(ctx, req.(*NetstatRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_MetaWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(MetaWriteRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).MetaWrite(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_MetaWrite_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).MetaWrite(ctx, req.(*MetaWriteRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_MetaDelete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(MetaDeleteRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).MetaDelete(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_MetaDelete_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).MetaDelete(ctx, req.(*MetaDeleteRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _MachineService_ImageList_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(ImageListRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(MachineServiceServer).ImageList(m, &grpc.GenericServerStream[ImageListRequest, ImageListResponse]{ServerStream: stream})\n}\n\n// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.\ntype MachineService_ImageListServer = grpc.ServerStreamingServer[ImageListResponse]\n\nfunc _MachineService_ImagePull_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ImagePullRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(MachineServiceServer).ImagePull(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: MachineService_ImagePull_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(MachineServiceServer).ImagePull(ctx, req.(*ImagePullRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// MachineService_ServiceDesc is the grpc.ServiceDesc for MachineService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar MachineService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"machine.MachineService\",\n\tHandlerType: (*MachineServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"ApplyConfiguration\",\n\t\t\tHandler:    _MachineService_ApplyConfiguration_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Bootstrap\",\n\t\t\tHandler:    _MachineService_Bootstrap_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Containers\",\n\t\t\tHandler:    _MachineService_Containers_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"CPUFreqStats\",\n\t\t\tHandler:    _MachineService_CPUFreqStats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"CPUInfo\",\n\t\t\tHandler:    _MachineService_CPUInfo_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"DiskStats\",\n\t\t\tHandler:    _MachineService_DiskStats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdMemberList\",\n\t\t\tHandler:    _MachineService_EtcdMemberList_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdRemoveMemberByID\",\n\t\t\tHandler:    _MachineService_EtcdRemoveMemberByID_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdLeaveCluster\",\n\t\t\tHandler:    _MachineService_EtcdLeaveCluster_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdForfeitLeadership\",\n\t\t\tHandler:    _MachineService_EtcdForfeitLeadership_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdAlarmList\",\n\t\t\tHandler:    _MachineService_EtcdAlarmList_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdAlarmDisarm\",\n\t\t\tHandler:    _MachineService_EtcdAlarmDisarm_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdDefragment\",\n\t\t\tHandler:    _MachineService_EtcdDefragment_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdStatus\",\n\t\t\tHandler:    _MachineService_EtcdStatus_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdDowngradeValidate\",\n\t\t\tHandler:    _MachineService_EtcdDowngradeValidate_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdDowngradeEnable\",\n\t\t\tHandler:    _MachineService_EtcdDowngradeEnable_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"EtcdDowngradeCancel\",\n\t\t\tHandler:    _MachineService_EtcdDowngradeCancel_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Hostname\",\n\t\t\tHandler:    _MachineService_Hostname_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"LoadAvg\",\n\t\t\tHandler:    _MachineService_LoadAvg_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"LogsContainers\",\n\t\t\tHandler:    _MachineService_LogsContainers_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Memory\",\n\t\t\tHandler:    _MachineService_Memory_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Mounts\",\n\t\t\tHandler:    _MachineService_Mounts_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"NetworkDeviceStats\",\n\t\t\tHandler:    _MachineService_NetworkDeviceStats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Processes\",\n\t\t\tHandler:    _MachineService_Processes_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Reboot\",\n\t\t\tHandler:    _MachineService_Reboot_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Restart\",\n\t\t\tHandler:    _MachineService_Restart_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Rollback\",\n\t\t\tHandler:    _MachineService_Rollback_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Reset\",\n\t\t\tHandler:    _MachineService_Reset_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ServiceList\",\n\t\t\tHandler:    _MachineService_ServiceList_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ServiceRestart\",\n\t\t\tHandler:    _MachineService_ServiceRestart_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ServiceStart\",\n\t\t\tHandler:    _MachineService_ServiceStart_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ServiceStop\",\n\t\t\tHandler:    _MachineService_ServiceStop_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Shutdown\",\n\t\t\tHandler:    _MachineService_Shutdown_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Stats\",\n\t\t\tHandler:    _MachineService_Stats_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"SystemStat\",\n\t\t\tHandler:    _MachineService_SystemStat_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Upgrade\",\n\t\t\tHandler:    _MachineService_Upgrade_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Version\",\n\t\t\tHandler:    _MachineService_Version_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"GenerateClientConfiguration\",\n\t\t\tHandler:    _MachineService_GenerateClientConfiguration_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Netstat\",\n\t\t\tHandler:    _MachineService_Netstat_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"MetaWrite\",\n\t\t\tHandler:    _MachineService_MetaWrite_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"MetaDelete\",\n\t\t\tHandler:    _MachineService_MetaDelete_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ImagePull\",\n\t\t\tHandler:    _MachineService_ImagePull_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"Copy\",\n\t\t\tHandler:       _MachineService_Copy_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Dmesg\",\n\t\t\tHandler:       _MachineService_Dmesg_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Events\",\n\t\t\tHandler:       _MachineService_Events_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"EtcdRecover\",\n\t\t\tHandler:       _MachineService_EtcdRecover_Handler,\n\t\t\tClientStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"EtcdSnapshot\",\n\t\t\tHandler:       _MachineService_EtcdSnapshot_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Kubeconfig\",\n\t\t\tHandler:       _MachineService_Kubeconfig_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"List\",\n\t\t\tHandler:       _MachineService_List_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"DiskUsage\",\n\t\t\tHandler:       _MachineService_DiskUsage_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Logs\",\n\t\t\tHandler:       _MachineService_Logs_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"Read\",\n\t\t\tHandler:       _MachineService_Read_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"PacketCapture\",\n\t\t\tHandler:       _MachineService_PacketCapture_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"ImageList\",\n\t\t\tHandler:       _MachineService_ImageList_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"machine/machine.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/machine/machine_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: machine/machine.proto\n\npackage machine\n\nimport (\n\tbinary \"encoding/binary\"\n\tfmt \"fmt\"\n\tio \"io\"\n\tmath \"math\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tanypb \"github.com/planetscale/vtprotobuf/types/known/anypb\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\ttimestamppb \"github.com/planetscale/vtprotobuf/types/known/timestamppb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb1 \"google.golang.org/protobuf/types/known/anypb\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n\ttimestamppb1 \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ApplyConfigurationRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ApplyConfigurationRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ApplyConfigurationRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TryModeTimeout != nil {\n\t\tsize, err := (*durationpb.Duration)(m.TryModeTimeout).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.DryRun {\n\t\ti--\n\t\tif m.DryRun {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Data) > 0 {\n\t\ti -= len(m.Data)\n\t\tcopy(dAtA[i:], m.Data)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Data)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ApplyConfiguration) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ApplyConfiguration) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ApplyConfiguration) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ModeDetails) > 0 {\n\t\ti -= len(m.ModeDetails)\n\t\tcopy(dAtA[i:], m.ModeDetails)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ModeDetails)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Warnings) > 0 {\n\t\tfor iNdEx := len(m.Warnings) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Warnings[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Warnings[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Warnings[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ApplyConfigurationResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ApplyConfigurationResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ApplyConfigurationResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RebootRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RebootRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RebootRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Reboot) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Reboot) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Reboot) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ActorId) > 0 {\n\t\ti -= len(m.ActorId)\n\t\tcopy(dAtA[i:], m.ActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RebootResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RebootResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RebootResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BootstrapRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BootstrapRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BootstrapRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.RecoverSkipHashCheck {\n\t\ti--\n\t\tif m.RecoverSkipHashCheck {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.RecoverEtcd {\n\t\ti--\n\t\tif m.RecoverEtcd {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Bootstrap) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Bootstrap) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Bootstrap) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BootstrapResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BootstrapResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BootstrapResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SequenceEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SequenceEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SequenceEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Error != nil {\n\t\tif vtmsg, ok := interface{}(m.Error).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Error)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Sequence) > 0 {\n\t\ti -= len(m.Sequence)\n\t\tcopy(dAtA[i:], m.Sequence)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Sequence)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PhaseEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PhaseEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PhaseEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Phase) > 0 {\n\t\ti -= len(m.Phase)\n\t\tcopy(dAtA[i:], m.Phase)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Phase)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TaskEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TaskEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TaskEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Task) > 0 {\n\t\ti -= len(m.Task)\n\t\tcopy(dAtA[i:], m.Task)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Task)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStateEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStateEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStateEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Health != nil {\n\t\tsize, err := m.Health.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Message) > 0 {\n\t\ti -= len(m.Message)\n\t\tcopy(dAtA[i:], m.Message)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Service) > 0 {\n\t\ti -= len(m.Service)\n\t\tcopy(dAtA[i:], m.Service)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Service)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RestartEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RestartEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RestartEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Cmd != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Cmd))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigLoadErrorEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigLoadErrorEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigLoadErrorEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigValidationErrorEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigValidationErrorEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigValidationErrorEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AddressEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AddressEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AddressEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Addresses[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Addresses[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Addresses[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineStatusEvent_MachineStatus_UnmetCondition) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineStatusEvent_MachineStatus_UnmetCondition) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineStatusEvent_MachineStatus_UnmetCondition) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Reason) > 0 {\n\t\ti -= len(m.Reason)\n\t\tcopy(dAtA[i:], m.Reason)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Reason)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineStatusEvent_MachineStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineStatusEvent_MachineStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineStatusEvent_MachineStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.UnmetConditions) > 0 {\n\t\tfor iNdEx := len(m.UnmetConditions) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.UnmetConditions[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineStatusEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineStatusEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineStatusEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Status != nil {\n\t\tsize, err := m.Status.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Stage != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Stage))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EventsRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EventsRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EventsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.WithActorId) > 0 {\n\t\ti -= len(m.WithActorId)\n\t\tcopy(dAtA[i:], m.WithActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.WithActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.TailSeconds != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TailSeconds))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.TailId) > 0 {\n\t\ti -= len(m.TailId)\n\t\tcopy(dAtA[i:], m.TailId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TailId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.TailEvents != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TailEvents))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Event) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Event) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Event) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ActorId) > 0 {\n\t\ti -= len(m.ActorId)\n\t\tcopy(dAtA[i:], m.ActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Data != nil {\n\t\tsize, err := (*anypb.Any)(m.Data).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ResetPartitionSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ResetPartitionSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ResetPartitionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Wipe {\n\t\ti--\n\t\tif m.Wipe {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ResetRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ResetRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ResetRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.UserDisksToWipe) > 0 {\n\t\tfor iNdEx := len(m.UserDisksToWipe) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.UserDisksToWipe[iNdEx])\n\t\t\tcopy(dAtA[i:], m.UserDisksToWipe[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.UserDisksToWipe[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.SystemPartitionsToWipe) > 0 {\n\t\tfor iNdEx := len(m.SystemPartitionsToWipe) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.SystemPartitionsToWipe[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Reboot {\n\t\ti--\n\t\tif m.Reboot {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Graceful {\n\t\ti--\n\t\tif m.Graceful {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Reset) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Reset) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Reset) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ActorId) > 0 {\n\t\ti -= len(m.ActorId)\n\t\tcopy(dAtA[i:], m.ActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ResetResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ResetResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ResetResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Shutdown) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Shutdown) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Shutdown) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ActorId) > 0 {\n\t\ti -= len(m.ActorId)\n\t\tcopy(dAtA[i:], m.ActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ShutdownRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ShutdownRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ShutdownRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Force {\n\t\ti--\n\t\tif m.Force {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ShutdownResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ShutdownResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ShutdownResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *UpgradeRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *UpgradeRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *UpgradeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.RebootMode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RebootMode))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Force {\n\t\ti--\n\t\tif m.Force {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Stage {\n\t\ti--\n\t\tif m.Stage {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Preserve {\n\t\ti--\n\t\tif m.Preserve {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Upgrade) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Upgrade) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Upgrade) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ActorId) > 0 {\n\t\ti -= len(m.ActorId)\n\t\tcopy(dAtA[i:], m.ActorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ActorId)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Ack) > 0 {\n\t\ti -= len(m.Ack)\n\t\tcopy(dAtA[i:], m.Ack)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ack)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *UpgradeResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *UpgradeResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *UpgradeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceList) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceList) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceList) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Services) > 0 {\n\t\tfor iNdEx := len(m.Services) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Services[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceListResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceListResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceListResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Health != nil {\n\t\tsize, err := m.Health.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Events != nil {\n\t\tsize, err := m.Events.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.State) > 0 {\n\t\ti -= len(m.State)\n\t\tcopy(dAtA[i:], m.State)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceEvents) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceEvents) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceEvents) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Events) > 0 {\n\t\tfor iNdEx := len(m.Events) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Events[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceEvent) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceEvent) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Ts != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.Ts).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.State) > 0 {\n\t\ti -= len(m.State)\n\t\tcopy(dAtA[i:], m.State)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Msg) > 0 {\n\t\ti -= len(m.Msg)\n\t\tcopy(dAtA[i:], m.Msg)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Msg)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceHealth) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceHealth) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceHealth) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.LastChange != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.LastChange).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.LastMessage) > 0 {\n\t\ti -= len(m.LastMessage)\n\t\tcopy(dAtA[i:], m.LastMessage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LastMessage)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Healthy {\n\t\ti--\n\t\tif m.Healthy {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Unknown {\n\t\ti--\n\t\tif m.Unknown {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStartRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStartRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStartRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStart) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStart) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStart) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Resp) > 0 {\n\t\ti -= len(m.Resp)\n\t\tcopy(dAtA[i:], m.Resp)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Resp)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStartResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStartResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStartResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStopRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStopRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStopRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStop) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStop) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStop) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Resp) > 0 {\n\t\ti -= len(m.Resp)\n\t\tcopy(dAtA[i:], m.Resp)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Resp)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceStopResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceStopResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceStopResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceRestartRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceRestartRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceRestartRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceRestart) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceRestart) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceRestart) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Resp) > 0 {\n\t\ti -= len(m.Resp)\n\t\tcopy(dAtA[i:], m.Resp)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Resp)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceRestartResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceRestartResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceRestartResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CopyRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CopyRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CopyRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.RootPath) > 0 {\n\t\ti -= len(m.RootPath)\n\t\tcopy(dAtA[i:], m.RootPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RootPath)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ListRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ListRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ListRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ReportXattrs {\n\t\ti--\n\t\tif m.ReportXattrs {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Types) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.Types {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.Types {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.RecursionDepth != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RecursionDepth))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Recurse {\n\t\ti--\n\t\tif m.Recurse {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Root) > 0 {\n\t\ti -= len(m.Root)\n\t\tcopy(dAtA[i:], m.Root)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Root)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskUsageRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskUsageRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskUsageRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Paths) > 0 {\n\t\tfor iNdEx := len(m.Paths) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Paths[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Paths[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Paths[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.Threshold != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Threshold))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.All {\n\t\ti--\n\t\tif m.All {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.RecursionDepth != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RecursionDepth))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *FileInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *FileInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *FileInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Xattrs) > 0 {\n\t\tfor iNdEx := len(m.Xattrs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Xattrs[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x62\n\t\t}\n\t}\n\tif m.Gid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Gid))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Uid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Uid))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif len(m.RelativeName) > 0 {\n\t\ti -= len(m.RelativeName)\n\t\tcopy(dAtA[i:], m.RelativeName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RelativeName)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.Link) > 0 {\n\t\ti -= len(m.Link)\n\t\tcopy(dAtA[i:], m.Link)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Link)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.IsDir {\n\t\ti--\n\t\tif m.IsDir {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Modified != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Modified))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Xattr) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Xattr) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Xattr) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Data) > 0 {\n\t\ti -= len(m.Data)\n\t\tcopy(dAtA[i:], m.Data)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Data)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskUsageInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskUsageInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskUsageInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.RelativeName) > 0 {\n\t\ti -= len(m.RelativeName)\n\t\tcopy(dAtA[i:], m.RelativeName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RelativeName)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Error) > 0 {\n\t\ti -= len(m.Error)\n\t\tcopy(dAtA[i:], m.Error)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Error)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Mounts) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Mounts) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Mounts) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Stats) > 0 {\n\t\tfor iNdEx := len(m.Stats) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Stats[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountsResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountsResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MountedOn) > 0 {\n\t\ti -= len(m.MountedOn)\n\t\tcopy(dAtA[i:], m.MountedOn)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MountedOn)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Available != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Available))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Filesystem) > 0 {\n\t\ti -= len(m.Filesystem)\n\t\tcopy(dAtA[i:], m.Filesystem)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Filesystem)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Version) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Version) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Version) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Features != nil {\n\t\tsize, err := m.Features.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Platform != nil {\n\t\tsize, err := m.Platform.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Version != nil {\n\t\tsize, err := m.Version.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VersionResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VersionResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VersionResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VersionInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VersionInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VersionInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Arch) > 0 {\n\t\ti -= len(m.Arch)\n\t\tcopy(dAtA[i:], m.Arch)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Arch)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Os) > 0 {\n\t\ti -= len(m.Os)\n\t\tcopy(dAtA[i:], m.Os)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Os)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.GoVersion) > 0 {\n\t\ti -= len(m.GoVersion)\n\t\tcopy(dAtA[i:], m.GoVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.GoVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Built) > 0 {\n\t\ti -= len(m.Built)\n\t\tcopy(dAtA[i:], m.Built)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Built)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Sha) > 0 {\n\t\ti -= len(m.Sha)\n\t\tcopy(dAtA[i:], m.Sha)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Sha)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Tag) > 0 {\n\t\ti -= len(m.Tag)\n\t\tcopy(dAtA[i:], m.Tag)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tag)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PlatformInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PlatformInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PlatformInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Mode) > 0 {\n\t\ti -= len(m.Mode)\n\t\tcopy(dAtA[i:], m.Mode)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Mode)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *FeaturesInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *FeaturesInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *FeaturesInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Rbac {\n\t\ti--\n\t\tif m.Rbac {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LogsRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LogsRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LogsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TailLines != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TailLines))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Follow {\n\t\ti--\n\t\tif m.Follow {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Driver != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Driver))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ReadRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ReadRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ReadRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Path) > 0 {\n\t\ti -= len(m.Path)\n\t\tcopy(dAtA[i:], m.Path)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Path)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LogsContainer) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LogsContainer) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LogsContainer) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Ids) > 0 {\n\t\tfor iNdEx := len(m.Ids) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Ids[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Ids[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ids[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LogsContainersResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LogsContainersResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LogsContainersResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RollbackRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RollbackRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RollbackRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Rollback) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Rollback) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Rollback) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RollbackResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RollbackResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RollbackResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ContainersRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ContainersRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ContainersRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Driver != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Driver))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ContainerInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ContainerInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ContainerInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Uid) > 0 {\n\t\ti -= len(m.Uid)\n\t\tcopy(dAtA[i:], m.Uid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uid)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.InternalId) > 0 {\n\t\ti -= len(m.InternalId)\n\t\tcopy(dAtA[i:], m.InternalId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InternalId)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.NetworkNamespace) > 0 {\n\t\ti -= len(m.NetworkNamespace)\n\t\tcopy(dAtA[i:], m.NetworkNamespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NetworkNamespace)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.PodId) > 0 {\n\t\ti -= len(m.PodId)\n\t\tcopy(dAtA[i:], m.PodId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PodId)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Status) > 0 {\n\t\ti -= len(m.Status)\n\t\tcopy(dAtA[i:], m.Status)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Status)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Pid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Pid))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Container) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Container) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Container) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Containers) > 0 {\n\t\tfor iNdEx := len(m.Containers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Containers[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ContainersResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ContainersResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ContainersResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DmesgRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DmesgRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DmesgRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Tail {\n\t\ti--\n\t\tif m.Tail {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Follow {\n\t\ti--\n\t\tif m.Follow {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProcessesResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProcessesResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProcessesResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Process) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Process) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Process) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Processes) > 0 {\n\t\tfor iNdEx := len(m.Processes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Processes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProcessInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProcessInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProcessInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif len(m.Args) > 0 {\n\t\ti -= len(m.Args)\n\t\tcopy(dAtA[i:], m.Args)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Args)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.Executable) > 0 {\n\t\ti -= len(m.Executable)\n\t\tcopy(dAtA[i:], m.Executable)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Executable)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.Command) > 0 {\n\t\ti -= len(m.Command)\n\t\tcopy(dAtA[i:], m.Command)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Command)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.ResidentMemory != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ResidentMemory))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.VirtualMemory != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.VirtualMemory))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.CpuTime != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.CpuTime))))\n\t\ti--\n\t\tdAtA[i] = 0x29\n\t}\n\tif m.Threads != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Threads))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.State) > 0 {\n\t\ti -= len(m.State)\n\t\tcopy(dAtA[i:], m.State)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Ppid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Ppid))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Pid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Pid))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RestartRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RestartRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RestartRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Driver != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Driver))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Restart) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Restart) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Restart) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RestartResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RestartResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RestartResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StatsRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StatsRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StatsRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Driver != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Driver))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Stats) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Stats) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Stats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Stats) > 0 {\n\t\tfor iNdEx := len(m.Stats) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Stats[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StatsResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StatsResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Stat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Stat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Stat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.PodId) > 0 {\n\t\ti -= len(m.PodId)\n\t\tcopy(dAtA[i:], m.PodId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PodId)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.CpuUsage != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CpuUsage))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.MemoryUsage != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemoryUsage))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Id) > 0 {\n\t\ti -= len(m.Id)\n\t\tcopy(dAtA[i:], m.Id)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Id)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Namespace) > 0 {\n\t\ti -= len(m.Namespace)\n\t\tcopy(dAtA[i:], m.Namespace)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Namespace)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Memory) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Memory) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Memory) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Meminfo != nil {\n\t\tsize, err := m.Meminfo.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemoryResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemoryResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemoryResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Directmap1G != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Directmap1G))\n\t\ti--\n\t\tdAtA[i] = 0x3\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.Directmap2M != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Directmap2M))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xf8\n\t}\n\tif m.Directmap4K != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Directmap4K))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xf0\n\t}\n\tif m.Hugepagesize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagesize))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xe8\n\t}\n\tif m.Hugepagessurp != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagessurp))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xe0\n\t}\n\tif m.Hugepagesrsvd != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagesrsvd))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xd8\n\t}\n\tif m.Hugepagesfree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagesfree))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xd0\n\t}\n\tif m.Hugepagestotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagestotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xc8\n\t}\n\tif m.Cmafree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Cmafree))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.Cmatotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Cmatotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.Shmempmdmapped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shmempmdmapped))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif m.Shmemhugepages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shmemhugepages))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.Anonhugepages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Anonhugepages))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif m.Hardwarecorrupted != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hardwarecorrupted))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif m.Vmallocchunk != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Vmallocchunk))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif m.Vmallocused != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Vmallocused))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.Vmalloctotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Vmalloctotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.Committedas != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Committedas))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xf8\n\t}\n\tif m.Commitlimit != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Commitlimit))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xf0\n\t}\n\tif m.Writebacktmp != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Writebacktmp))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe8\n\t}\n\tif m.Bounce != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Bounce))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe0\n\t}\n\tif m.Nfsunstable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Nfsunstable))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd8\n\t}\n\tif m.Pagetables != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Pagetables))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd0\n\t}\n\tif m.Kernelstack != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Kernelstack))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc8\n\t}\n\tif m.Sunreclaim != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Sunreclaim))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.Sreclaimable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Sreclaimable))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.Slab != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Slab))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif m.Shmem != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shmem))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.Mapped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mapped))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif m.Anonpages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Anonpages))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif m.Writeback != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Writeback))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif m.Dirty != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Dirty))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.Swapfree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Swapfree))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.Swaptotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Swaptotal))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.Mlocked != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mlocked))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.Unevictable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Unevictable))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.Inactivefile != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Inactivefile))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.Activefile != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Activefile))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Inactiveanon != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Inactiveanon))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Activeanon != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Activeanon))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Inactive != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Inactive))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Active != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Active))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Swapcached != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Swapcached))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Cached != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Cached))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Buffers != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Buffers))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Memavailable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Memavailable))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Memfree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Memfree))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Memtotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Memtotal))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HostnameResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HostnameResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HostnameResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Hostname) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Hostname) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Hostname) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LoadAvgResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LoadAvgResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LoadAvgResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LoadAvg) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LoadAvg) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LoadAvg) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Load15 != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Load15))))\n\t\ti--\n\t\tdAtA[i] = 0x21\n\t}\n\tif m.Load5 != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Load5))))\n\t\ti--\n\t\tdAtA[i] = 0x19\n\t}\n\tif m.Load1 != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Load1))))\n\t\ti--\n\t\tdAtA[i] = 0x11\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SystemStatResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SystemStatResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SystemStatResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SystemStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SystemStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SystemStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SoftIrq != nil {\n\t\tsize, err := m.SoftIrq.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif m.SoftIrqTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SoftIrqTotal))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.ProcessBlocked != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessBlocked))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.ProcessRunning != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessRunning))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.ProcessCreated != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessCreated))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.ContextSwitches != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ContextSwitches))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif len(m.Irq) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.Irq {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num := range m.Irq {\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.IrqTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IrqTotal))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Cpu) > 0 {\n\t\tfor iNdEx := len(m.Cpu) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Cpu[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.CpuTotal != nil {\n\t\tsize, err := m.CpuTotal.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.BootTime != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.BootTime))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.GuestNice != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.GuestNice))))\n\t\ti--\n\t\tdAtA[i] = 0x51\n\t}\n\tif m.Guest != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Guest))))\n\t\ti--\n\t\tdAtA[i] = 0x49\n\t}\n\tif m.Steal != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Steal))))\n\t\ti--\n\t\tdAtA[i] = 0x41\n\t}\n\tif m.SoftIrq != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.SoftIrq))))\n\t\ti--\n\t\tdAtA[i] = 0x39\n\t}\n\tif m.Irq != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Irq))))\n\t\ti--\n\t\tdAtA[i] = 0x31\n\t}\n\tif m.Iowait != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Iowait))))\n\t\ti--\n\t\tdAtA[i] = 0x29\n\t}\n\tif m.Idle != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Idle))))\n\t\ti--\n\t\tdAtA[i] = 0x21\n\t}\n\tif m.System != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.System))))\n\t\ti--\n\t\tdAtA[i] = 0x19\n\t}\n\tif m.Nice != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Nice))))\n\t\ti--\n\t\tdAtA[i] = 0x11\n\t}\n\tif m.User != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.User))))\n\t\ti--\n\t\tdAtA[i] = 0x9\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SoftIRQStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SoftIRQStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SoftIRQStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Rcu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rcu))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Hrtimer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hrtimer))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Sched != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Sched))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Tasklet != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tasklet))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.BlockIoPoll != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.BlockIoPoll))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Block != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Block))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.NetRx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.NetRx))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.NetTx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.NetTx))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Timer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timer))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Hi != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hi))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUFreqStatsResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUFreqStatsResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUFreqStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUsFreqStats) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUsFreqStats) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUsFreqStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.CpuFreqStats) > 0 {\n\t\tfor iNdEx := len(m.CpuFreqStats) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.CpuFreqStats[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUFreqStats) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUFreqStats) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUFreqStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Governor) > 0 {\n\t\ti -= len(m.Governor)\n\t\tcopy(dAtA[i:], m.Governor)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Governor)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.MaximumFrequency != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaximumFrequency))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.MinimumFrequency != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinimumFrequency))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.CurrentFrequency != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CurrentFrequency))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUInfoResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUInfoResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUInfoResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUsInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUsInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUsInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.CpuInfo) > 0 {\n\t\tfor iNdEx := len(m.CpuInfo) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.CpuInfo[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.PowerManagement) > 0 {\n\t\ti -= len(m.PowerManagement)\n\t\tcopy(dAtA[i:], m.PowerManagement)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PowerManagement)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd2\n\t}\n\tif len(m.AddressSizes) > 0 {\n\t\ti -= len(m.AddressSizes)\n\t\tcopy(dAtA[i:], m.AddressSizes)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AddressSizes)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xca\n\t}\n\tif m.CacheAlignment != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CacheAlignment))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.ClFlushSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ClFlushSize))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.BogoMips != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.BogoMips))))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb1\n\t}\n\tif len(m.Bugs) > 0 {\n\t\tfor iNdEx := len(m.Bugs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Bugs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Bugs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Bugs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0xaa\n\t\t}\n\t}\n\tif len(m.Flags) > 0 {\n\t\tfor iNdEx := len(m.Flags) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Flags[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Flags[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Flags[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa2\n\t\t}\n\t}\n\tif len(m.Wp) > 0 {\n\t\ti -= len(m.Wp)\n\t\tcopy(dAtA[i:], m.Wp)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Wp)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x9a\n\t}\n\tif m.CpuIdLevel != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CpuIdLevel))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif len(m.FpuException) > 0 {\n\t\ti -= len(m.FpuException)\n\t\tcopy(dAtA[i:], m.FpuException)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FpuException)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.Fpu) > 0 {\n\t\ti -= len(m.Fpu)\n\t\tcopy(dAtA[i:], m.Fpu)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Fpu)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x82\n\t}\n\tif len(m.InitialApicId) > 0 {\n\t\ti -= len(m.InitialApicId)\n\t\tcopy(dAtA[i:], m.InitialApicId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InitialApicId)))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif len(m.ApicId) > 0 {\n\t\ti -= len(m.ApicId)\n\t\tcopy(dAtA[i:], m.ApicId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApicId)))\n\t\ti--\n\t\tdAtA[i] = 0x72\n\t}\n\tif m.CpuCores != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CpuCores))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif len(m.CoreId) > 0 {\n\t\ti -= len(m.CoreId)\n\t\tcopy(dAtA[i:], m.CoreId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CoreId)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif m.Siblings != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Siblings))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif len(m.PhysicalId) > 0 {\n\t\ti -= len(m.PhysicalId)\n\t\tcopy(dAtA[i:], m.PhysicalId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PhysicalId)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.CacheSize) > 0 {\n\t\ti -= len(m.CacheSize)\n\t\tcopy(dAtA[i:], m.CacheSize)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CacheSize)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.CpuMhz != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.CpuMhz))))\n\t\ti--\n\t\tdAtA[i] = 0x41\n\t}\n\tif len(m.Microcode) > 0 {\n\t\ti -= len(m.Microcode)\n\t\tcopy(dAtA[i:], m.Microcode)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Microcode)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.Stepping) > 0 {\n\t\ti -= len(m.Stepping)\n\t\tcopy(dAtA[i:], m.Stepping)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Stepping)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.ModelName) > 0 {\n\t\ti -= len(m.ModelName)\n\t\tcopy(dAtA[i:], m.ModelName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ModelName)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Model) > 0 {\n\t\ti -= len(m.Model)\n\t\tcopy(dAtA[i:], m.Model)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Model)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.CpuFamily) > 0 {\n\t\ti -= len(m.CpuFamily)\n\t\tcopy(dAtA[i:], m.CpuFamily)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CpuFamily)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.VendorId) > 0 {\n\t\ti -= len(m.VendorId)\n\t\tcopy(dAtA[i:], m.VendorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VendorId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Processor != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Processor))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetworkDeviceStatsResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetworkDeviceStatsResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetworkDeviceStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetworkDeviceStats) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetworkDeviceStats) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetworkDeviceStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Devices) > 0 {\n\t\tfor iNdEx := len(m.Devices) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Devices[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Total != nil {\n\t\tsize, err := m.Total.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetDev) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetDev) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetDev) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TxCompressed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxCompressed))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.TxCarrier != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxCarrier))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.TxCollisions != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxCollisions))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.TxFifo != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxFifo))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.TxDropped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxDropped))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.TxErrors != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxErrors))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.TxPackets != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxPackets))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.TxBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxBytes))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.RxMulticast != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMulticast))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.RxCompressed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxCompressed))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.RxFrame != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxFrame))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.RxFifo != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxFifo))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.RxDropped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxDropped))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.RxErrors != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxErrors))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.RxPackets != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxPackets))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.RxBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxBytes))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskStatsResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskStatsResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskStatsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskStats) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskStats) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskStats) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Devices) > 0 {\n\t\tfor iNdEx := len(m.Devices) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Devices[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Total != nil {\n\t\tsize, err := m.Total.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.DiscardTimeMs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DiscardTimeMs))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.DiscardSectors != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DiscardSectors))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.DiscardMerged != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DiscardMerged))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.DiscardCompleted != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DiscardCompleted))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.IoTimeWeightedMs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoTimeWeightedMs))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.IoTimeMs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoTimeMs))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.IoInProgress != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoInProgress))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.WriteTimeMs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WriteTimeMs))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.WriteSectors != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WriteSectors))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.WriteMerged != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WriteMerged))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.WriteCompleted != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WriteCompleted))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.ReadTimeMs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReadTimeMs))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ReadSectors != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReadSectors))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ReadMerged != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReadMerged))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.ReadCompleted != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReadCompleted))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdLeaveClusterRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdLeaveClusterRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdLeaveClusterRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdLeaveCluster) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdLeaveCluster) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdLeaveCluster) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdLeaveClusterResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdLeaveClusterResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdLeaveClusterResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMemberRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMemberRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMemberRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Member) > 0 {\n\t\ti -= len(m.Member)\n\t\tcopy(dAtA[i:], m.Member)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Member)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMember) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMember) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMember) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMemberResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMemberResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMemberResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMemberByIDRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMemberByIDRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMemberByIDRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MemberId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemberId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMemberByID) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMemberByID) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMemberByID) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRemoveMemberByIDResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRemoveMemberByIDResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRemoveMemberByIDResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdForfeitLeadershipRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdForfeitLeadershipRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdForfeitLeadershipRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdForfeitLeadership) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdForfeitLeadership) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdForfeitLeadership) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Member) > 0 {\n\t\ti -= len(m.Member)\n\t\tcopy(dAtA[i:], m.Member)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Member)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdForfeitLeadershipResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdForfeitLeadershipResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdForfeitLeadershipResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMemberListRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMemberListRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMemberListRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.QueryLocal {\n\t\ti--\n\t\tif m.QueryLocal {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMember) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMember) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMember) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.IsLearner {\n\t\ti--\n\t\tif m.IsLearner {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.ClientUrls) > 0 {\n\t\tfor iNdEx := len(m.ClientUrls) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ClientUrls[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ClientUrls[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClientUrls[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.PeerUrls) > 0 {\n\t\tfor iNdEx := len(m.PeerUrls) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PeerUrls[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PeerUrls[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PeerUrls[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Id != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Id))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMembers) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMembers) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMembers) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Members) > 0 {\n\t\tfor iNdEx := len(m.Members) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Members[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.LegacyMembers) > 0 {\n\t\tfor iNdEx := len(m.LegacyMembers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.LegacyMembers[iNdEx])\n\t\t\tcopy(dAtA[i:], m.LegacyMembers[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LegacyMembers[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMemberListResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMemberListResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMemberListResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdSnapshotRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdSnapshotRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdSnapshotRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRecover) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRecover) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRecover) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRecoverResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRecoverResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRecoverResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdAlarmListResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdAlarmListResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdAlarmListResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdAlarm) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdAlarm) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdAlarm) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MemberAlarms) > 0 {\n\t\tfor iNdEx := len(m.MemberAlarms) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.MemberAlarms[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMemberAlarm) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMemberAlarm) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMemberAlarm) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Alarm != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Alarm))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.MemberId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemberId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdAlarmDisarmResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdAlarmDisarmResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdAlarmDisarmResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdAlarmDisarm) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdAlarmDisarm) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdAlarmDisarm) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MemberAlarms) > 0 {\n\t\tfor iNdEx := len(m.MemberAlarms) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.MemberAlarms[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDefragmentResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDefragmentResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDefragmentResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDefragment) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDefragment) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDefragment) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdStatusResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdStatusResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdStatusResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MemberStatus != nil {\n\t\tsize, err := m.MemberStatus.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdMemberStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdMemberStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdMemberStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.StorageVersion) > 0 {\n\t\ti -= len(m.StorageVersion)\n\t\tcopy(dAtA[i:], m.StorageVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StorageVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.MemberId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemberId))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.IsLearner {\n\t\ti--\n\t\tif m.IsLearner {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.Errors) > 0 {\n\t\tfor iNdEx := len(m.Errors) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Errors[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Errors[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Errors[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x42\n\t\t}\n\t}\n\tif m.RaftAppliedIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RaftAppliedIndex))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.RaftTerm != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RaftTerm))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.RaftIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RaftIndex))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Leader != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Leader))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.DbSizeInUse != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DbSizeInUse))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.DbSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DbSize))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.ProtocolVersion) > 0 {\n\t\ti -= len(m.ProtocolVersion)\n\t\tcopy(dAtA[i:], m.ProtocolVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProtocolVersion)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeValidateRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeValidateRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeValidateRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeValidateResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeValidateResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeValidateResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeValidate) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeValidate) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeValidate) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tsize, err := m.ClusterDowngrade.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeEnableRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeEnableRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeEnableRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeEnableResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeEnableResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeEnableResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeEnable) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeEnable) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeEnable) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tsize, err := m.ClusterDowngrade.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeCancelResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeCancelResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeCancelResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdDowngradeCancel) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdDowngradeCancel) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdDowngradeCancel) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tsize, err := m.ClusterDowngrade.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdClusterDowngrade) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdClusterDowngrade) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdClusterDowngrade) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ClusterVersion) > 0 {\n\t\ti -= len(m.ClusterVersion)\n\t\tcopy(dAtA[i:], m.ClusterVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterVersion)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RouteConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RouteConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RouteConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metric != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Metric))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Gateway) > 0 {\n\t\ti -= len(m.Gateway)\n\t\tcopy(dAtA[i:], m.Gateway)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Gateway)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Network) > 0 {\n\t\ti -= len(m.Network)\n\t\tcopy(dAtA[i:], m.Network)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Network)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DHCPOptionsConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DHCPOptionsConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DHCPOptionsConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.RouteMetric != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RouteMetric))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetworkDeviceConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetworkDeviceConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetworkDeviceConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Routes) > 0 {\n\t\tfor iNdEx := len(m.Routes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Routes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x3a\n\t\t}\n\t}\n\tif m.DhcpOptions != nil {\n\t\tsize, err := m.DhcpOptions.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.Ignore {\n\t\ti--\n\t\tif m.Ignore {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Dhcp {\n\t\ti--\n\t\tif m.Dhcp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Cidr) > 0 {\n\t\ti -= len(m.Cidr)\n\t\tcopy(dAtA[i:], m.Cidr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Cidr)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Interface) > 0 {\n\t\ti -= len(m.Interface)\n\t\tcopy(dAtA[i:], m.Interface)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Interface)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetworkConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetworkConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetworkConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Interfaces) > 0 {\n\t\tfor iNdEx := len(m.Interfaces) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Interfaces[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *InstallConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *InstallConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *InstallConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.InstallImage) > 0 {\n\t\ti -= len(m.InstallImage)\n\t\tcopy(dAtA[i:], m.InstallImage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InstallImage)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.InstallDisk) > 0 {\n\t\ti -= len(m.InstallDisk)\n\t\tcopy(dAtA[i:], m.InstallDisk)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InstallDisk)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.KubernetesVersion) > 0 {\n\t\ti -= len(m.KubernetesVersion)\n\t\tcopy(dAtA[i:], m.KubernetesVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.KubernetesVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.NetworkConfig != nil {\n\t\tsize, err := m.NetworkConfig.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.InstallConfig != nil {\n\t\tsize, err := m.InstallConfig.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControlPlaneConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControlPlaneConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControlPlaneConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Endpoint) > 0 {\n\t\ti -= len(m.Endpoint)\n\t\tcopy(dAtA[i:], m.Endpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Endpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CNIConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CNIConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CNIConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Urls) > 0 {\n\t\tfor iNdEx := len(m.Urls) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Urls[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Urls[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Urls[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ClusterNetworkConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ClusterNetworkConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ClusterNetworkConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.CniConfig != nil {\n\t\tsize, err := m.CniConfig.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.DnsDomain) > 0 {\n\t\ti -= len(m.DnsDomain)\n\t\tcopy(dAtA[i:], m.DnsDomain)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DnsDomain)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ClusterConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ClusterConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ClusterConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.AllowSchedulingOnControlPlanes {\n\t\ti--\n\t\tif m.AllowSchedulingOnControlPlanes {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ClusterNetwork != nil {\n\t\tsize, err := m.ClusterNetwork.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.ControlPlane != nil {\n\t\tsize, err := m.ControlPlane.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *GenerateClientConfigurationRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *GenerateClientConfigurationRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *GenerateClientConfigurationRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.CrtTtl != nil {\n\t\tsize, err := (*durationpb.Duration)(m.CrtTtl).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Roles) > 0 {\n\t\tfor iNdEx := len(m.Roles) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Roles[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Roles[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Roles[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *GenerateClientConfiguration) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *GenerateClientConfiguration) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *GenerateClientConfiguration) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Talosconfig) > 0 {\n\t\ti -= len(m.Talosconfig)\n\t\tcopy(dAtA[i:], m.Talosconfig)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Talosconfig)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Crt) > 0 {\n\t\ti -= len(m.Crt)\n\t\tcopy(dAtA[i:], m.Crt)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Crt)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Ca) > 0 {\n\t\ti -= len(m.Ca)\n\t\tcopy(dAtA[i:], m.Ca)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ca)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *GenerateClientConfigurationResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *GenerateClientConfigurationResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *GenerateClientConfigurationResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PacketCaptureRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PacketCaptureRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PacketCaptureRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.BpfFilter) > 0 {\n\t\tfor iNdEx := len(m.BpfFilter) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.BpfFilter[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.SnapLen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SnapLen))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Promiscuous {\n\t\ti--\n\t\tif m.Promiscuous {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Interface) > 0 {\n\t\ti -= len(m.Interface)\n\t\tcopy(dAtA[i:], m.Interface)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Interface)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BPFInstruction) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BPFInstruction) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BPFInstruction) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.K != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.K))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Jf != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Jf))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Jt != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Jt))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Op != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Op))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetstatRequest_Feature) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetstatRequest_Feature) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetstatRequest_Feature) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Pid {\n\t\ti--\n\t\tif m.Pid {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetstatRequest_L4Proto) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetstatRequest_L4Proto) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetstatRequest_L4Proto) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Raw6 {\n\t\ti--\n\t\tif m.Raw6 {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Raw {\n\t\ti--\n\t\tif m.Raw {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Udplite6 {\n\t\ti--\n\t\tif m.Udplite6 {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Udplite {\n\t\ti--\n\t\tif m.Udplite {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Udp6 {\n\t\ti--\n\t\tif m.Udp6 {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Udp {\n\t\ti--\n\t\tif m.Udp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Tcp6 {\n\t\ti--\n\t\tif m.Tcp6 {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Tcp {\n\t\ti--\n\t\tif m.Tcp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetstatRequest_NetNS) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetstatRequest_NetNS) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetstatRequest_NetNS) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Allnetns {\n\t\ti--\n\t\tif m.Allnetns {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Netns) > 0 {\n\t\tfor iNdEx := len(m.Netns) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Netns[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Netns[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Netns[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Hostnetwork {\n\t\ti--\n\t\tif m.Hostnetwork {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetstatRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetstatRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetstatRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Netns != nil {\n\t\tsize, err := m.Netns.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.L4Proto != nil {\n\t\tsize, err := m.L4Proto.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Feature != nil {\n\t\tsize, err := m.Feature.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Filter != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Filter))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConnectRecord_Process) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConnectRecord_Process) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConnectRecord_Process) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Pid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Pid))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConnectRecord) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConnectRecord) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConnectRecord) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Netns) > 0 {\n\t\ti -= len(m.Netns)\n\t\tcopy(dAtA[i:], m.Netns)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Netns)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif m.Process != nil {\n\t\tsize, err := m.Process.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif m.Pointer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Pointer))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.Ref != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Ref))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.Inode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Inode))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.Timeout != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timeout))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.Uid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Uid))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.Retrnsmt != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Retrnsmt))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Timerwhen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Timerwhen))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Tr != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tr))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Rxqueue != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rxqueue))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Txqueue != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Txqueue))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.State != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.State))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Remoteport != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Remoteport))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Remoteip) > 0 {\n\t\ti -= len(m.Remoteip)\n\t\tcopy(dAtA[i:], m.Remoteip)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Remoteip)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Localport != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Localport))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Localip) > 0 {\n\t\ti -= len(m.Localip)\n\t\tcopy(dAtA[i:], m.Localip)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Localip)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.L4Proto) > 0 {\n\t\ti -= len(m.L4Proto)\n\t\tcopy(dAtA[i:], m.L4Proto)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.L4Proto)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Netstat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Netstat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Netstat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Connectrecord) > 0 {\n\t\tfor iNdEx := len(m.Connectrecord) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Connectrecord[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NetstatResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NetstatResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NetstatResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaWriteRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaWriteRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaWriteRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Key != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Key))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaWrite) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaWrite) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaWrite) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaWriteResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaWriteResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaWriteResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaDeleteRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaDeleteRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaDeleteRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Key != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Key))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaDelete) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaDelete) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaDelete) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaDeleteResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaDeleteResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaDeleteResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageListRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageListRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageListRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Namespace != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Namespace))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageListResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageListResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageListResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.CreatedAt != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.CreatedAt).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Digest) > 0 {\n\t\ti -= len(m.Digest)\n\t\tcopy(dAtA[i:], m.Digest)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Digest)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImagePullRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImagePullRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImagePullRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Reference) > 0 {\n\t\ti -= len(m.Reference)\n\t\tcopy(dAtA[i:], m.Reference)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Reference)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Namespace != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Namespace))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImagePull) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImagePull) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImagePull) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImagePullResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImagePullResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImagePullResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ApplyConfigurationRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Data)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tif m.DryRun {\n\t\tn += 2\n\t}\n\tif m.TryModeTimeout != nil {\n\t\tl = (*durationpb.Duration)(m.TryModeTimeout).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ApplyConfiguration) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Warnings) > 0 {\n\t\tfor _, s := range m.Warnings {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tl = len(m.ModeDetails)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ApplyConfigurationResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RebootRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Reboot) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RebootResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BootstrapRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RecoverEtcd {\n\t\tn += 2\n\t}\n\tif m.RecoverSkipHashCheck {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Bootstrap) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BootstrapResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SequenceEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Sequence)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tif m.Error != nil {\n\t\tif size, ok := interface{}(m.Error).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Error)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PhaseEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Phase)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TaskEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Task)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStateEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Service)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tl = len(m.Message)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Health != nil {\n\t\tl = m.Health.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RestartEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Cmd != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Cmd))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigLoadErrorEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigValidationErrorEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AddressEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor _, s := range m.Addresses {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineStatusEvent_MachineStatus_UnmetCondition) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Reason)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineStatusEvent_MachineStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tif len(m.UnmetConditions) > 0 {\n\t\tfor _, e := range m.UnmetConditions {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineStatusEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Stage != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Stage))\n\t}\n\tif m.Status != nil {\n\t\tl = m.Status.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EventsRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.TailEvents != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TailEvents))\n\t}\n\tl = len(m.TailId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.TailSeconds != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TailSeconds))\n\t}\n\tl = len(m.WithActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Event) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Data != nil {\n\t\tl = (*anypb.Any)(m.Data).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ResetPartitionSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Wipe {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ResetRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Graceful {\n\t\tn += 2\n\t}\n\tif m.Reboot {\n\t\tn += 2\n\t}\n\tif len(m.SystemPartitionsToWipe) > 0 {\n\t\tfor _, e := range m.SystemPartitionsToWipe {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.UserDisksToWipe) > 0 {\n\t\tfor _, s := range m.UserDisksToWipe {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Reset) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ResetResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Shutdown) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ShutdownRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Force {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ShutdownResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *UpgradeRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Preserve {\n\t\tn += 2\n\t}\n\tif m.Stage {\n\t\tn += 2\n\t}\n\tif m.Force {\n\t\tn += 2\n\t}\n\tif m.RebootMode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RebootMode))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Upgrade) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Ack)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ActorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *UpgradeResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceList) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Services) > 0 {\n\t\tfor _, e := range m.Services {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceListResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.State)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Events != nil {\n\t\tl = m.Events.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Health != nil {\n\t\tl = m.Health.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceEvents) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Events) > 0 {\n\t\tfor _, e := range m.Events {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceEvent) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Msg)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.State)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Ts != nil {\n\t\tl = (*timestamppb.Timestamp)(m.Ts).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceHealth) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Unknown {\n\t\tn += 2\n\t}\n\tif m.Healthy {\n\t\tn += 2\n\t}\n\tl = len(m.LastMessage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LastChange != nil {\n\t\tl = (*timestamppb.Timestamp)(m.LastChange).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStartRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStart) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Resp)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStartResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStopRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStop) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Resp)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceStopResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceRestartRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceRestart) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Resp)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceRestartResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CopyRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.RootPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ListRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Root)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Recurse {\n\t\tn += 2\n\t}\n\tif m.RecursionDepth != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RecursionDepth))\n\t}\n\tif len(m.Types) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.Types {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tif m.ReportXattrs {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskUsageRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RecursionDepth != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RecursionDepth))\n\t}\n\tif m.All {\n\t\tn += 2\n\t}\n\tif m.Threshold != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Threshold))\n\t}\n\tif len(m.Paths) > 0 {\n\t\tfor _, s := range m.Paths {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *FileInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tif m.Modified != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Modified))\n\t}\n\tif m.IsDir {\n\t\tn += 2\n\t}\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Link)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.RelativeName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Uid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Uid))\n\t}\n\tif m.Gid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Gid))\n\t}\n\tif len(m.Xattrs) > 0 {\n\t\tfor _, e := range m.Xattrs {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Xattr) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Data)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskUsageInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tl = len(m.Error)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.RelativeName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Mounts) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Stats) > 0 {\n\t\tfor _, e := range m.Stats {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountsResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Filesystem)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.Available != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Available))\n\t}\n\tl = len(m.MountedOn)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Version) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Version != nil {\n\t\tl = m.Version.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Platform != nil {\n\t\tl = m.Platform.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Features != nil {\n\t\tl = m.Features.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VersionResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VersionInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Tag)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Sha)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Built)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.GoVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Os)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Arch)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PlatformInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Mode)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *FeaturesInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Rbac {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LogsRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Driver != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Driver))\n\t}\n\tif m.Follow {\n\t\tn += 2\n\t}\n\tif m.TailLines != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TailLines))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ReadRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Path)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LogsContainer) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Ids) > 0 {\n\t\tfor _, s := range m.Ids {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LogsContainersResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RollbackRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Rollback) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RollbackResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ContainersRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Driver != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Driver))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ContainerInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Pid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Pid))\n\t}\n\tl = len(m.Status)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PodId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.NetworkNamespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.InternalId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Uid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Container) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Containers) > 0 {\n\t\tfor _, e := range m.Containers {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ContainersResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DmesgRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Follow {\n\t\tn += 2\n\t}\n\tif m.Tail {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProcessesResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Process) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Processes) > 0 {\n\t\tfor _, e := range m.Processes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProcessInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Pid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Pid))\n\t}\n\tif m.Ppid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Ppid))\n\t}\n\tl = len(m.State)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Threads != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Threads))\n\t}\n\tif m.CpuTime != 0 {\n\t\tn += 9\n\t}\n\tif m.VirtualMemory != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.VirtualMemory))\n\t}\n\tif m.ResidentMemory != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ResidentMemory))\n\t}\n\tl = len(m.Command)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Executable)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Args)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RestartRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Driver != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Driver))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Restart) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RestartResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StatsRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Driver != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Driver))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Stats) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Stats) > 0 {\n\t\tfor _, e := range m.Stats {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StatsResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Stat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Namespace)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Id)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MemoryUsage != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemoryUsage))\n\t}\n\tif m.CpuUsage != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CpuUsage))\n\t}\n\tl = len(m.PodId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Memory) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Meminfo != nil {\n\t\tl = m.Meminfo.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemoryResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Memtotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Memtotal))\n\t}\n\tif m.Memfree != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Memfree))\n\t}\n\tif m.Memavailable != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Memavailable))\n\t}\n\tif m.Buffers != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Buffers))\n\t}\n\tif m.Cached != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Cached))\n\t}\n\tif m.Swapcached != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Swapcached))\n\t}\n\tif m.Active != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Active))\n\t}\n\tif m.Inactive != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Inactive))\n\t}\n\tif m.Activeanon != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Activeanon))\n\t}\n\tif m.Inactiveanon != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Inactiveanon))\n\t}\n\tif m.Activefile != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Activefile))\n\t}\n\tif m.Inactivefile != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Inactivefile))\n\t}\n\tif m.Unevictable != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Unevictable))\n\t}\n\tif m.Mlocked != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mlocked))\n\t}\n\tif m.Swaptotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Swaptotal))\n\t}\n\tif m.Swapfree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Swapfree))\n\t}\n\tif m.Dirty != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Dirty))\n\t}\n\tif m.Writeback != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Writeback))\n\t}\n\tif m.Anonpages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Anonpages))\n\t}\n\tif m.Mapped != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Mapped))\n\t}\n\tif m.Shmem != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Shmem))\n\t}\n\tif m.Slab != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Slab))\n\t}\n\tif m.Sreclaimable != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Sreclaimable))\n\t}\n\tif m.Sunreclaim != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Sunreclaim))\n\t}\n\tif m.Kernelstack != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Kernelstack))\n\t}\n\tif m.Pagetables != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Pagetables))\n\t}\n\tif m.Nfsunstable != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Nfsunstable))\n\t}\n\tif m.Bounce != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Bounce))\n\t}\n\tif m.Writebacktmp != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Writebacktmp))\n\t}\n\tif m.Commitlimit != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Commitlimit))\n\t}\n\tif m.Committedas != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Committedas))\n\t}\n\tif m.Vmalloctotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Vmalloctotal))\n\t}\n\tif m.Vmallocused != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Vmallocused))\n\t}\n\tif m.Vmallocchunk != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Vmallocchunk))\n\t}\n\tif m.Hardwarecorrupted != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hardwarecorrupted))\n\t}\n\tif m.Anonhugepages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Anonhugepages))\n\t}\n\tif m.Shmemhugepages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Shmemhugepages))\n\t}\n\tif m.Shmempmdmapped != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Shmempmdmapped))\n\t}\n\tif m.Cmatotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Cmatotal))\n\t}\n\tif m.Cmafree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Cmafree))\n\t}\n\tif m.Hugepagestotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagestotal))\n\t}\n\tif m.Hugepagesfree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagesfree))\n\t}\n\tif m.Hugepagesrsvd != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagesrsvd))\n\t}\n\tif m.Hugepagessurp != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagessurp))\n\t}\n\tif m.Hugepagesize != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagesize))\n\t}\n\tif m.Directmap4K != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Directmap4K))\n\t}\n\tif m.Directmap2M != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Directmap2M))\n\t}\n\tif m.Directmap1G != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Directmap1G))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HostnameResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Hostname) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LoadAvgResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LoadAvg) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Load1 != 0 {\n\t\tn += 9\n\t}\n\tif m.Load5 != 0 {\n\t\tn += 9\n\t}\n\tif m.Load15 != 0 {\n\t\tn += 9\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SystemStatResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SystemStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BootTime != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.BootTime))\n\t}\n\tif m.CpuTotal != nil {\n\t\tl = m.CpuTotal.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Cpu) > 0 {\n\t\tfor _, e := range m.Cpu {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.IrqTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IrqTotal))\n\t}\n\tif len(m.Irq) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.Irq {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tif m.ContextSwitches != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ContextSwitches))\n\t}\n\tif m.ProcessCreated != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessCreated))\n\t}\n\tif m.ProcessRunning != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessRunning))\n\t}\n\tif m.ProcessBlocked != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessBlocked))\n\t}\n\tif m.SoftIrqTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SoftIrqTotal))\n\t}\n\tif m.SoftIrq != nil {\n\t\tl = m.SoftIrq.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.User != 0 {\n\t\tn += 9\n\t}\n\tif m.Nice != 0 {\n\t\tn += 9\n\t}\n\tif m.System != 0 {\n\t\tn += 9\n\t}\n\tif m.Idle != 0 {\n\t\tn += 9\n\t}\n\tif m.Iowait != 0 {\n\t\tn += 9\n\t}\n\tif m.Irq != 0 {\n\t\tn += 9\n\t}\n\tif m.SoftIrq != 0 {\n\t\tn += 9\n\t}\n\tif m.Steal != 0 {\n\t\tn += 9\n\t}\n\tif m.Guest != 0 {\n\t\tn += 9\n\t}\n\tif m.GuestNice != 0 {\n\t\tn += 9\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SoftIRQStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Hi != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Hi))\n\t}\n\tif m.Timer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Timer))\n\t}\n\tif m.NetTx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.NetTx))\n\t}\n\tif m.NetRx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.NetRx))\n\t}\n\tif m.Block != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Block))\n\t}\n\tif m.BlockIoPoll != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.BlockIoPoll))\n\t}\n\tif m.Tasklet != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tasklet))\n\t}\n\tif m.Sched != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Sched))\n\t}\n\tif m.Hrtimer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Hrtimer))\n\t}\n\tif m.Rcu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rcu))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUFreqStatsResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUsFreqStats) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.CpuFreqStats) > 0 {\n\t\tfor _, e := range m.CpuFreqStats {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUFreqStats) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.CurrentFrequency != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CurrentFrequency))\n\t}\n\tif m.MinimumFrequency != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MinimumFrequency))\n\t}\n\tif m.MaximumFrequency != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MaximumFrequency))\n\t}\n\tl = len(m.Governor)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUInfoResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUsInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.CpuInfo) > 0 {\n\t\tfor _, e := range m.CpuInfo {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Processor != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Processor))\n\t}\n\tl = len(m.VendorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.CpuFamily)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Model)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ModelName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Stepping)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Microcode)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CpuMhz != 0 {\n\t\tn += 9\n\t}\n\tl = len(m.CacheSize)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PhysicalId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Siblings != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Siblings))\n\t}\n\tl = len(m.CoreId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CpuCores != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CpuCores))\n\t}\n\tl = len(m.ApicId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.InitialApicId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Fpu)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.FpuException)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CpuIdLevel != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CpuIdLevel))\n\t}\n\tl = len(m.Wp)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Flags) > 0 {\n\t\tfor _, s := range m.Flags {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Bugs) > 0 {\n\t\tfor _, s := range m.Bugs {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.BogoMips != 0 {\n\t\tn += 10\n\t}\n\tif m.ClFlushSize != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.ClFlushSize))\n\t}\n\tif m.CacheAlignment != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CacheAlignment))\n\t}\n\tl = len(m.AddressSizes)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PowerManagement)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetworkDeviceStatsResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetworkDeviceStats) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Total != nil {\n\t\tl = m.Total.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Devices) > 0 {\n\t\tfor _, e := range m.Devices {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetDev) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.RxBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxBytes))\n\t}\n\tif m.RxPackets != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxPackets))\n\t}\n\tif m.RxErrors != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxErrors))\n\t}\n\tif m.RxDropped != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxDropped))\n\t}\n\tif m.RxFifo != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxFifo))\n\t}\n\tif m.RxFrame != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxFrame))\n\t}\n\tif m.RxCompressed != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxCompressed))\n\t}\n\tif m.RxMulticast != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMulticast))\n\t}\n\tif m.TxBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxBytes))\n\t}\n\tif m.TxPackets != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxPackets))\n\t}\n\tif m.TxErrors != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxErrors))\n\t}\n\tif m.TxDropped != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxDropped))\n\t}\n\tif m.TxFifo != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxFifo))\n\t}\n\tif m.TxCollisions != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxCollisions))\n\t}\n\tif m.TxCarrier != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.TxCarrier))\n\t}\n\tif m.TxCompressed != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.TxCompressed))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskStatsResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskStats) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Total != nil {\n\t\tl = m.Total.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Devices) > 0 {\n\t\tfor _, e := range m.Devices {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ReadCompleted != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReadCompleted))\n\t}\n\tif m.ReadMerged != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReadMerged))\n\t}\n\tif m.ReadSectors != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReadSectors))\n\t}\n\tif m.ReadTimeMs != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReadTimeMs))\n\t}\n\tif m.WriteCompleted != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.WriteCompleted))\n\t}\n\tif m.WriteMerged != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.WriteMerged))\n\t}\n\tif m.WriteSectors != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.WriteSectors))\n\t}\n\tif m.WriteTimeMs != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.WriteTimeMs))\n\t}\n\tif m.IoInProgress != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IoInProgress))\n\t}\n\tif m.IoTimeMs != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IoTimeMs))\n\t}\n\tif m.IoTimeWeightedMs != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IoTimeWeightedMs))\n\t}\n\tif m.DiscardCompleted != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DiscardCompleted))\n\t}\n\tif m.DiscardMerged != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DiscardMerged))\n\t}\n\tif m.DiscardSectors != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DiscardSectors))\n\t}\n\tif m.DiscardTimeMs != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.DiscardTimeMs))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdLeaveClusterRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdLeaveCluster) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdLeaveClusterResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMemberRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Member)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMember) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMemberResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMemberByIDRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MemberId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemberId))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMemberByID) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRemoveMemberByIDResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdForfeitLeadershipRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdForfeitLeadership) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Member)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdForfeitLeadershipResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMemberListRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.QueryLocal {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMember) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Id != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Id))\n\t}\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.PeerUrls) > 0 {\n\t\tfor _, s := range m.PeerUrls {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ClientUrls) > 0 {\n\t\tfor _, s := range m.ClientUrls {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.IsLearner {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMembers) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.LegacyMembers) > 0 {\n\t\tfor _, s := range m.LegacyMembers {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Members) > 0 {\n\t\tfor _, e := range m.Members {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMemberListResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdSnapshotRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRecover) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRecoverResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdAlarmListResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdAlarm) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.MemberAlarms) > 0 {\n\t\tfor _, e := range m.MemberAlarms {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMemberAlarm) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MemberId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemberId))\n\t}\n\tif m.Alarm != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Alarm))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdAlarmDisarmResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdAlarmDisarm) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.MemberAlarms) > 0 {\n\t\tfor _, e := range m.MemberAlarms {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDefragmentResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDefragment) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdStatusResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MemberStatus != nil {\n\t\tl = m.MemberStatus.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdMemberStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ProtocolVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.DbSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DbSize))\n\t}\n\tif m.DbSizeInUse != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DbSizeInUse))\n\t}\n\tif m.Leader != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Leader))\n\t}\n\tif m.RaftIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RaftIndex))\n\t}\n\tif m.RaftTerm != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RaftTerm))\n\t}\n\tif m.RaftAppliedIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RaftAppliedIndex))\n\t}\n\tif len(m.Errors) > 0 {\n\t\tfor _, s := range m.Errors {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.IsLearner {\n\t\tn += 2\n\t}\n\tif m.MemberId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemberId))\n\t}\n\tl = len(m.StorageVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeValidateRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeValidateResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeValidate) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tl = m.ClusterDowngrade.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeEnableRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeEnableResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeEnable) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tl = m.ClusterDowngrade.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeCancelResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdDowngradeCancel) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClusterDowngrade != nil {\n\t\tl = m.ClusterDowngrade.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdClusterDowngrade) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ClusterVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RouteConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Network)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Gateway)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Metric != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Metric))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DHCPOptionsConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RouteMetric != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RouteMetric))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetworkDeviceConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Interface)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Cidr)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tif m.Dhcp {\n\t\tn += 2\n\t}\n\tif m.Ignore {\n\t\tn += 2\n\t}\n\tif m.DhcpOptions != nil {\n\t\tl = m.DhcpOptions.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Routes) > 0 {\n\t\tfor _, e := range m.Routes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetworkConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Interfaces) > 0 {\n\t\tfor _, e := range m.Interfaces {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *InstallConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.InstallDisk)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.InstallImage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif m.InstallConfig != nil {\n\t\tl = m.InstallConfig.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.NetworkConfig != nil {\n\t\tl = m.NetworkConfig.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.KubernetesVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControlPlaneConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Endpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CNIConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Urls) > 0 {\n\t\tfor _, s := range m.Urls {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ClusterNetworkConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.DnsDomain)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CniConfig != nil {\n\t\tl = m.CniConfig.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ClusterConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ControlPlane != nil {\n\t\tl = m.ControlPlane.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClusterNetwork != nil {\n\t\tl = m.ClusterNetwork.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.AllowSchedulingOnControlPlanes {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *GenerateClientConfigurationRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Roles) > 0 {\n\t\tfor _, s := range m.Roles {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.CrtTtl != nil {\n\t\tl = (*durationpb.Duration)(m.CrtTtl).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *GenerateClientConfiguration) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Ca)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Crt)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Talosconfig)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *GenerateClientConfigurationResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PacketCaptureRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Interface)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Promiscuous {\n\t\tn += 2\n\t}\n\tif m.SnapLen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SnapLen))\n\t}\n\tif len(m.BpfFilter) > 0 {\n\t\tfor _, e := range m.BpfFilter {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BPFInstruction) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Op != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Op))\n\t}\n\tif m.Jt != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Jt))\n\t}\n\tif m.Jf != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Jf))\n\t}\n\tif m.K != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.K))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetstatRequest_Feature) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Pid {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetstatRequest_L4Proto) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Tcp {\n\t\tn += 2\n\t}\n\tif m.Tcp6 {\n\t\tn += 2\n\t}\n\tif m.Udp {\n\t\tn += 2\n\t}\n\tif m.Udp6 {\n\t\tn += 2\n\t}\n\tif m.Udplite {\n\t\tn += 2\n\t}\n\tif m.Udplite6 {\n\t\tn += 2\n\t}\n\tif m.Raw {\n\t\tn += 2\n\t}\n\tif m.Raw6 {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetstatRequest_NetNS) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Hostnetwork {\n\t\tn += 2\n\t}\n\tif len(m.Netns) > 0 {\n\t\tfor _, s := range m.Netns {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Allnetns {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetstatRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Filter != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Filter))\n\t}\n\tif m.Feature != nil {\n\t\tl = m.Feature.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.L4Proto != nil {\n\t\tl = m.L4Proto.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Netns != nil {\n\t\tl = m.Netns.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConnectRecord_Process) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Pid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Pid))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConnectRecord) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.L4Proto)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Localip)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Localport != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Localport))\n\t}\n\tl = len(m.Remoteip)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Remoteport != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Remoteport))\n\t}\n\tif m.State != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.State))\n\t}\n\tif m.Txqueue != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Txqueue))\n\t}\n\tif m.Rxqueue != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rxqueue))\n\t}\n\tif m.Tr != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tr))\n\t}\n\tif m.Timerwhen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Timerwhen))\n\t}\n\tif m.Retrnsmt != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Retrnsmt))\n\t}\n\tif m.Uid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Uid))\n\t}\n\tif m.Timeout != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Timeout))\n\t}\n\tif m.Inode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Inode))\n\t}\n\tif m.Ref != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Ref))\n\t}\n\tif m.Pointer != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Pointer))\n\t}\n\tif m.Process != nil {\n\t\tl = m.Process.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Netns)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Netstat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Connectrecord) > 0 {\n\t\tfor _, e := range m.Connectrecord {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NetstatResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaWriteRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Key != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Key))\n\t}\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaWrite) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaWriteResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaDeleteRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Key != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Key))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaDelete) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaDeleteResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageListRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Namespace != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Namespace))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageListResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Digest)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.CreatedAt != nil {\n\t\tl = (*timestamppb.Timestamp)(m.CreatedAt).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImagePullRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Namespace != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Namespace))\n\t}\n\tl = len(m.Reference)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImagePull) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImagePullResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ApplyConfigurationRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfigurationRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfigurationRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Data\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Data == nil {\n\t\t\t\tm.Data = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= ApplyConfigurationRequest_Mode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DryRun\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DryRun = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TryModeTimeout\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.TryModeTimeout == nil {\n\t\t\t\tm.TryModeTimeout = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.TryModeTimeout).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ApplyConfiguration) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfiguration: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfiguration: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Warnings\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Warnings = append(m.Warnings, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= ApplyConfigurationRequest_Mode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ModeDetails\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ModeDetails = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ApplyConfigurationResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfigurationResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ApplyConfigurationResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ApplyConfiguration{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RebootRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RebootRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RebootRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= RebootRequest_Mode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Reboot) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Reboot: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Reboot: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RebootResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RebootResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RebootResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Reboot{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BootstrapRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RecoverEtcd\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RecoverEtcd = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RecoverSkipHashCheck\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RecoverSkipHashCheck = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Bootstrap) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Bootstrap: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Bootstrap: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BootstrapResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Bootstrap{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SequenceEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SequenceEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SequenceEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sequence\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Sequence = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= SequenceEvent_Action(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Error == nil {\n\t\t\t\tm.Error = &common.Error{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Error).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Error); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PhaseEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PhaseEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PhaseEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Phase\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Phase = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= PhaseEvent_Action(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TaskEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TaskEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TaskEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Task\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Task = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= TaskEvent_Action(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStateEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStateEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStateEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Service\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Service = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= ServiceStateEvent_Action(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Message = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Health\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Health == nil {\n\t\t\t\tm.Health = &ServiceHealth{}\n\t\t\t}\n\t\t\tif err := m.Health.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RestartEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RestartEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RestartEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cmd\", wireType)\n\t\t\t}\n\t\t\tm.Cmd = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Cmd |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConfigLoadErrorEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigLoadErrorEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigLoadErrorEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConfigValidationErrorEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigValidationErrorEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigValidationErrorEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AddressEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AddressEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AddressEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineStatusEvent_MachineStatus_UnmetCondition) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent_MachineStatus_UnmetCondition: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent_MachineStatus_UnmetCondition: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Reason\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Reason = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineStatusEvent_MachineStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent_MachineStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent_MachineStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UnmetConditions\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UnmetConditions = append(m.UnmetConditions, &MachineStatusEvent_MachineStatus_UnmetCondition{})\n\t\t\tif err := m.UnmetConditions[len(m.UnmetConditions)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineStatusEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stage\", wireType)\n\t\t\t}\n\t\t\tm.Stage = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Stage |= MachineStatusEvent_MachineStage(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Status == nil {\n\t\t\t\tm.Status = &MachineStatusEvent_MachineStatus{}\n\t\t\t}\n\t\t\tif err := m.Status.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EventsRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EventsRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EventsRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TailEvents\", wireType)\n\t\t\t}\n\t\t\tm.TailEvents = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TailEvents |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TailId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TailId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TailSeconds\", wireType)\n\t\t\t}\n\t\t\tm.TailSeconds = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TailSeconds |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WithActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.WithActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Event) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Event: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Event: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Data\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Data == nil {\n\t\t\t\tm.Data = &anypb1.Any{}\n\t\t\t}\n\t\t\tif err := (*anypb.Any)(m.Data).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ResetPartitionSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ResetPartitionSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ResetPartitionSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wipe\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Wipe = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ResetRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ResetRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ResetRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Graceful\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Graceful = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Reboot\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Reboot = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SystemPartitionsToWipe\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SystemPartitionsToWipe = append(m.SystemPartitionsToWipe, &ResetPartitionSpec{})\n\t\t\tif err := m.SystemPartitionsToWipe[len(m.SystemPartitionsToWipe)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UserDisksToWipe\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UserDisksToWipe = append(m.UserDisksToWipe, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= ResetRequest_WipeMode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Reset) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Reset: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Reset: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ResetResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ResetResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ResetResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Reset{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Shutdown) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Shutdown: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Shutdown: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ShutdownRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ShutdownRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ShutdownRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Force\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Force = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ShutdownResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ShutdownResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ShutdownResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Shutdown{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *UpgradeRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: UpgradeRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: UpgradeRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Preserve\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Preserve = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stage\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Stage = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Force\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Force = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RebootMode\", wireType)\n\t\t\t}\n\t\t\tm.RebootMode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RebootMode |= UpgradeRequest_RebootMode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Upgrade) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Upgrade: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Upgrade: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ack\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ack = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ActorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *UpgradeResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: UpgradeResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: UpgradeResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Upgrade{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceList) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceList: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceList: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Services\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Services = append(m.Services, &ServiceInfo{})\n\t\t\tif err := m.Services[len(m.Services)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceListResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceListResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceListResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ServiceList{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.State = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Events\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Events == nil {\n\t\t\t\tm.Events = &ServiceEvents{}\n\t\t\t}\n\t\t\tif err := m.Events.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Health\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Health == nil {\n\t\t\t\tm.Health = &ServiceHealth{}\n\t\t\t}\n\t\t\tif err := m.Health.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceEvents) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceEvents: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceEvents: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Events\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Events = append(m.Events, &ServiceEvent{})\n\t\t\tif err := m.Events[len(m.Events)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceEvent) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceEvent: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceEvent: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Msg\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Msg = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.State = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ts\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Ts == nil {\n\t\t\t\tm.Ts = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.Ts).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceHealth) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceHealth: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceHealth: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unknown\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Unknown = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Healthy\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Healthy = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastMessage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LastMessage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastChange\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LastChange == nil {\n\t\t\t\tm.LastChange = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.LastChange).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStartRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStartRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStartRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStart) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStart: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStart: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resp\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Resp = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStartResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStartResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStartResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ServiceStart{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStopRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStopRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStopRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStop) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStop: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStop: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resp\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Resp = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceStopResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStopResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceStopResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ServiceStop{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceRestartRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestartRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestartRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceRestart) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestart: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestart: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resp\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Resp = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ServiceRestartResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestartResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceRestartResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ServiceRestart{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CopyRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CopyRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CopyRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RootPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RootPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ListRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ListRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ListRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Root\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Root = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Recurse\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Recurse = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RecursionDepth\", wireType)\n\t\t\t}\n\t\t\tm.RecursionDepth = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RecursionDepth |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v ListRequest_Type\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= ListRequest_Type(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.Types = append(m.Types, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tif elementCount != 0 && len(m.Types) == 0 {\n\t\t\t\t\tm.Types = make([]ListRequest_Type, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v ListRequest_Type\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= ListRequest_Type(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.Types = append(m.Types, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Types\", wireType)\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReportXattrs\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReportXattrs = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskUsageRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskUsageRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskUsageRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RecursionDepth\", wireType)\n\t\t\t}\n\t\t\tm.RecursionDepth = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RecursionDepth |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field All\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.All = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Threshold\", wireType)\n\t\t\t}\n\t\t\tm.Threshold = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Threshold |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Paths\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Paths = append(m.Paths, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *FileInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: FileInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: FileInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Modified\", wireType)\n\t\t\t}\n\t\t\tm.Modified = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Modified |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IsDir\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.IsDir = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Link\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Link = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RelativeName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RelativeName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uid\", wireType)\n\t\t\t}\n\t\t\tm.Uid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Uid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Gid\", wireType)\n\t\t\t}\n\t\t\tm.Gid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Gid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Xattrs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Xattrs = append(m.Xattrs, &Xattr{})\n\t\t\tif err := m.Xattrs[len(m.Xattrs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Xattr) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Xattr: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Xattr: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Data\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Data == nil {\n\t\t\t\tm.Data = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskUsageInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskUsageInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskUsageInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Error\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Error = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RelativeName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RelativeName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Mounts) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Mounts: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Mounts: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stats\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Stats = append(m.Stats, &MountStat{})\n\t\t\tif err := m.Stats[len(m.Stats)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountsResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountsResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountsResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Mounts{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Filesystem\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Filesystem = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Available\", wireType)\n\t\t\t}\n\t\t\tm.Available = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Available |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MountedOn\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MountedOn = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Version) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Version: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Version: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Version == nil {\n\t\t\t\tm.Version = &VersionInfo{}\n\t\t\t}\n\t\t\tif err := m.Version.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Platform\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Platform == nil {\n\t\t\t\tm.Platform = &PlatformInfo{}\n\t\t\t}\n\t\t\tif err := m.Platform.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Features\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Features == nil {\n\t\t\t\tm.Features = &FeaturesInfo{}\n\t\t\t}\n\t\t\tif err := m.Features.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VersionResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VersionResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VersionResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Version{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VersionInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VersionInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VersionInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tag\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Tag = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sha\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Sha = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Built\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Built = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GoVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.GoVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Os\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Os = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Arch\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Arch = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PlatformInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Mode = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *FeaturesInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: FeaturesInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: FeaturesInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rbac\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Rbac = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LogsRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LogsRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LogsRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tm.Driver = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Driver |= common.ContainerDriver(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Follow\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Follow = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TailLines\", wireType)\n\t\t\t}\n\t\t\tm.TailLines = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TailLines |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ReadRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ReadRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ReadRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Path\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Path = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LogsContainer) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LogsContainer: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LogsContainer: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ids\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ids = append(m.Ids, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LogsContainersResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LogsContainersResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LogsContainersResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &LogsContainer{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RollbackRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Rollback) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Rollback: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Rollback: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RollbackResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RollbackResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Rollback{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ContainersRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ContainersRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ContainersRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tm.Driver = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Driver |= common.ContainerDriver(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ContainerInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ContainerInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ContainerInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pid\", wireType)\n\t\t\t}\n\t\t\tm.Pid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Pid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Status = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PodId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetworkNamespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NetworkNamespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InternalId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InternalId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Container) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Container: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Container: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Containers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Containers = append(m.Containers, &ContainerInfo{})\n\t\t\tif err := m.Containers[len(m.Containers)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ContainersResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ContainersResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ContainersResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Container{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DmesgRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DmesgRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DmesgRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Follow\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Follow = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tail\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tail = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProcessesResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessesResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessesResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Process{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Process) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Process: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Process: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Processes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Processes = append(m.Processes, &ProcessInfo{})\n\t\t\tif err := m.Processes[len(m.Processes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProcessInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pid\", wireType)\n\t\t\t}\n\t\t\tm.Pid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Pid |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ppid\", wireType)\n\t\t\t}\n\t\t\tm.Ppid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Ppid |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.State = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Threads\", wireType)\n\t\t\t}\n\t\t\tm.Threads = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Threads |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuTime\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.CpuTime = float64(math.Float64frombits(v))\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VirtualMemory\", wireType)\n\t\t\t}\n\t\t\tm.VirtualMemory = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.VirtualMemory |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResidentMemory\", wireType)\n\t\t\t}\n\t\t\tm.ResidentMemory = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ResidentMemory |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Command\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Command = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Executable\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Executable = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Args\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Args = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RestartRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RestartRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RestartRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tm.Driver = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Driver |= common.ContainerDriver(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Restart) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Restart: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Restart: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RestartResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RestartResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RestartResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Restart{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StatsRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StatsRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StatsRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tm.Driver = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Driver |= common.ContainerDriver(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Stats) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Stats: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Stats: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stats\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Stats = append(m.Stats, &Stat{})\n\t\t\tif err := m.Stats[len(m.Stats)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StatsResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StatsResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StatsResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Stats{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Stat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Stat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Stat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Namespace = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Id = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemoryUsage\", wireType)\n\t\t\t}\n\t\t\tm.MemoryUsage = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemoryUsage |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuUsage\", wireType)\n\t\t\t}\n\t\t\tm.CpuUsage = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CpuUsage |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PodId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Memory) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Memory: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Memory: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Meminfo\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Meminfo == nil {\n\t\t\t\tm.Meminfo = &MemInfo{}\n\t\t\t}\n\t\t\tif err := m.Meminfo.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MemoryResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemoryResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemoryResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Memory{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MemInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Memtotal\", wireType)\n\t\t\t}\n\t\t\tm.Memtotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Memtotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Memfree\", wireType)\n\t\t\t}\n\t\t\tm.Memfree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Memfree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Memavailable\", wireType)\n\t\t\t}\n\t\t\tm.Memavailable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Memavailable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Buffers\", wireType)\n\t\t\t}\n\t\t\tm.Buffers = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Buffers |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cached\", wireType)\n\t\t\t}\n\t\t\tm.Cached = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Cached |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Swapcached\", wireType)\n\t\t\t}\n\t\t\tm.Swapcached = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Swapcached |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Active\", wireType)\n\t\t\t}\n\t\t\tm.Active = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Active |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Inactive\", wireType)\n\t\t\t}\n\t\t\tm.Inactive = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Inactive |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Activeanon\", wireType)\n\t\t\t}\n\t\t\tm.Activeanon = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Activeanon |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Inactiveanon\", wireType)\n\t\t\t}\n\t\t\tm.Inactiveanon = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Inactiveanon |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Activefile\", wireType)\n\t\t\t}\n\t\t\tm.Activefile = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Activefile |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Inactivefile\", wireType)\n\t\t\t}\n\t\t\tm.Inactivefile = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Inactivefile |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unevictable\", wireType)\n\t\t\t}\n\t\t\tm.Unevictable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Unevictable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mlocked\", wireType)\n\t\t\t}\n\t\t\tm.Mlocked = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mlocked |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Swaptotal\", wireType)\n\t\t\t}\n\t\t\tm.Swaptotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Swaptotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Swapfree\", wireType)\n\t\t\t}\n\t\t\tm.Swapfree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Swapfree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dirty\", wireType)\n\t\t\t}\n\t\t\tm.Dirty = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Dirty |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 18:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Writeback\", wireType)\n\t\t\t}\n\t\t\tm.Writeback = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Writeback |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 19:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Anonpages\", wireType)\n\t\t\t}\n\t\t\tm.Anonpages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Anonpages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 20:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mapped\", wireType)\n\t\t\t}\n\t\t\tm.Mapped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mapped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 21:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Shmem\", wireType)\n\t\t\t}\n\t\t\tm.Shmem = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Shmem |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 22:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Slab\", wireType)\n\t\t\t}\n\t\t\tm.Slab = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Slab |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 23:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sreclaimable\", wireType)\n\t\t\t}\n\t\t\tm.Sreclaimable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Sreclaimable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 24:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sunreclaim\", wireType)\n\t\t\t}\n\t\t\tm.Sunreclaim = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Sunreclaim |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 25:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Kernelstack\", wireType)\n\t\t\t}\n\t\t\tm.Kernelstack = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Kernelstack |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 26:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pagetables\", wireType)\n\t\t\t}\n\t\t\tm.Pagetables = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Pagetables |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 27:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nfsunstable\", wireType)\n\t\t\t}\n\t\t\tm.Nfsunstable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Nfsunstable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 28:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Bounce\", wireType)\n\t\t\t}\n\t\t\tm.Bounce = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Bounce |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 29:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Writebacktmp\", wireType)\n\t\t\t}\n\t\t\tm.Writebacktmp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Writebacktmp |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 30:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Commitlimit\", wireType)\n\t\t\t}\n\t\t\tm.Commitlimit = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Commitlimit |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 31:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Committedas\", wireType)\n\t\t\t}\n\t\t\tm.Committedas = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Committedas |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 32:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vmalloctotal\", wireType)\n\t\t\t}\n\t\t\tm.Vmalloctotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Vmalloctotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 33:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vmallocused\", wireType)\n\t\t\t}\n\t\t\tm.Vmallocused = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Vmallocused |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 34:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vmallocchunk\", wireType)\n\t\t\t}\n\t\t\tm.Vmallocchunk = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Vmallocchunk |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 35:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hardwarecorrupted\", wireType)\n\t\t\t}\n\t\t\tm.Hardwarecorrupted = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hardwarecorrupted |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 36:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Anonhugepages\", wireType)\n\t\t\t}\n\t\t\tm.Anonhugepages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Anonhugepages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 37:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Shmemhugepages\", wireType)\n\t\t\t}\n\t\t\tm.Shmemhugepages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Shmemhugepages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 38:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Shmempmdmapped\", wireType)\n\t\t\t}\n\t\t\tm.Shmempmdmapped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Shmempmdmapped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 39:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cmatotal\", wireType)\n\t\t\t}\n\t\t\tm.Cmatotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Cmatotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 40:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cmafree\", wireType)\n\t\t\t}\n\t\t\tm.Cmafree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Cmafree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 41:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagestotal\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagestotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagestotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 42:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagesfree\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagesfree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagesfree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 43:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagesrsvd\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagesrsvd = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagesrsvd |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 44:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagessurp\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagessurp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagessurp |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 45:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagesize\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagesize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagesize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 46:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Directmap4K\", wireType)\n\t\t\t}\n\t\t\tm.Directmap4K = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Directmap4K |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 47:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Directmap2M\", wireType)\n\t\t\t}\n\t\t\tm.Directmap2M = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Directmap2M |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 48:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Directmap1G\", wireType)\n\t\t\t}\n\t\t\tm.Directmap1G = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Directmap1G |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HostnameResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Hostname{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Hostname) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Hostname: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Hostname: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LoadAvgResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LoadAvgResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LoadAvgResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &LoadAvg{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LoadAvg) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LoadAvg: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LoadAvg: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Load1\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Load1 = float64(math.Float64frombits(v))\n\t\tcase 3:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Load5\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Load5 = float64(math.Float64frombits(v))\n\t\tcase 4:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Load15\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Load15 = float64(math.Float64frombits(v))\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SystemStatResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SystemStatResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SystemStatResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &SystemStat{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SystemStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SystemStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SystemStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootTime\", wireType)\n\t\t\t}\n\t\t\tm.BootTime = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BootTime |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuTotal\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CpuTotal == nil {\n\t\t\t\tm.CpuTotal = &CPUStat{}\n\t\t\t}\n\t\t\tif err := m.CpuTotal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cpu\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Cpu = append(m.Cpu, &CPUStat{})\n\t\t\tif err := m.Cpu[len(m.Cpu)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IrqTotal\", wireType)\n\t\t\t}\n\t\t\tm.IrqTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IrqTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.Irq = append(m.Irq, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tvar count int\n\t\t\t\tfor _, integer := range dAtA[iNdEx:postIndex] {\n\t\t\t\t\tif integer < 128 {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telementCount = count\n\t\t\t\tif elementCount != 0 && len(m.Irq) == 0 {\n\t\t\t\t\tm.Irq = make([]uint64, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.Irq = append(m.Irq, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Irq\", wireType)\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ContextSwitches\", wireType)\n\t\t\t}\n\t\t\tm.ContextSwitches = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ContextSwitches |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessCreated\", wireType)\n\t\t\t}\n\t\t\tm.ProcessCreated = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessCreated |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessRunning\", wireType)\n\t\t\t}\n\t\t\tm.ProcessRunning = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessRunning |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessBlocked\", wireType)\n\t\t\t}\n\t\t\tm.ProcessBlocked = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessBlocked |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SoftIrqTotal\", wireType)\n\t\t\t}\n\t\t\tm.SoftIrqTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SoftIrqTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SoftIrq\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.SoftIrq == nil {\n\t\t\t\tm.SoftIrq = &SoftIRQStat{}\n\t\t\t}\n\t\t\tif err := m.SoftIrq.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field User\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.User = float64(math.Float64frombits(v))\n\t\tcase 2:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nice\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Nice = float64(math.Float64frombits(v))\n\t\tcase 3:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field System\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.System = float64(math.Float64frombits(v))\n\t\tcase 4:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Idle\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Idle = float64(math.Float64frombits(v))\n\t\tcase 5:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Iowait\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Iowait = float64(math.Float64frombits(v))\n\t\tcase 6:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Irq\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Irq = float64(math.Float64frombits(v))\n\t\tcase 7:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SoftIrq\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.SoftIrq = float64(math.Float64frombits(v))\n\t\tcase 8:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Steal\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Steal = float64(math.Float64frombits(v))\n\t\tcase 9:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Guest\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Guest = float64(math.Float64frombits(v))\n\t\tcase 10:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GuestNice\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.GuestNice = float64(math.Float64frombits(v))\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SoftIRQStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SoftIRQStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SoftIRQStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hi\", wireType)\n\t\t\t}\n\t\t\tm.Hi = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hi |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timer\", wireType)\n\t\t\t}\n\t\t\tm.Timer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timer |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetTx\", wireType)\n\t\t\t}\n\t\t\tm.NetTx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NetTx |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetRx\", wireType)\n\t\t\t}\n\t\t\tm.NetRx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NetRx |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Block\", wireType)\n\t\t\t}\n\t\t\tm.Block = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Block |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockIoPoll\", wireType)\n\t\t\t}\n\t\t\tm.BlockIoPoll = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockIoPoll |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tasklet\", wireType)\n\t\t\t}\n\t\t\tm.Tasklet = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tasklet |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Sched\", wireType)\n\t\t\t}\n\t\t\tm.Sched = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Sched |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hrtimer\", wireType)\n\t\t\t}\n\t\t\tm.Hrtimer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hrtimer |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rcu\", wireType)\n\t\t\t}\n\t\t\tm.Rcu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rcu |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUFreqStatsResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUFreqStatsResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUFreqStatsResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &CPUsFreqStats{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUsFreqStats) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUsFreqStats: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUsFreqStats: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuFreqStats\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CpuFreqStats = append(m.CpuFreqStats, &CPUFreqStats{})\n\t\t\tif err := m.CpuFreqStats[len(m.CpuFreqStats)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUFreqStats) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUFreqStats: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUFreqStats: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CurrentFrequency\", wireType)\n\t\t\t}\n\t\t\tm.CurrentFrequency = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CurrentFrequency |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MinimumFrequency\", wireType)\n\t\t\t}\n\t\t\tm.MinimumFrequency = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MinimumFrequency |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MaximumFrequency\", wireType)\n\t\t\t}\n\t\t\tm.MaximumFrequency = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MaximumFrequency |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Governor\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Governor = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUInfoResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUInfoResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUInfoResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &CPUsInfo{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUsInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUsInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUsInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuInfo\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CpuInfo = append(m.CpuInfo, &CPUInfo{})\n\t\t\tif err := m.CpuInfo[len(m.CpuInfo)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Processor\", wireType)\n\t\t\t}\n\t\t\tm.Processor = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Processor |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VendorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VendorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuFamily\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CpuFamily = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Model\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Model = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ModelName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ModelName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stepping\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Stepping = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Microcode\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Microcode = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuMhz\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.CpuMhz = float64(math.Float64frombits(v))\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CacheSize\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CacheSize = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PhysicalId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PhysicalId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Siblings\", wireType)\n\t\t\t}\n\t\t\tm.Siblings = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Siblings |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CoreId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CoreId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuCores\", wireType)\n\t\t\t}\n\t\t\tm.CpuCores = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CpuCores |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApicId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApicId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InitialApicId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InitialApicId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Fpu\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Fpu = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FpuException\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FpuException = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuIdLevel\", wireType)\n\t\t\t}\n\t\t\tm.CpuIdLevel = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CpuIdLevel |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 19:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wp\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Wp = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 20:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Flags = append(m.Flags, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 21:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Bugs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Bugs = append(m.Bugs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 22:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BogoMips\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.BogoMips = float64(math.Float64frombits(v))\n\t\tcase 23:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClFlushSize\", wireType)\n\t\t\t}\n\t\t\tm.ClFlushSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ClFlushSize |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 24:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CacheAlignment\", wireType)\n\t\t\t}\n\t\t\tm.CacheAlignment = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CacheAlignment |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 25:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AddressSizes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AddressSizes = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 26:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PowerManagement\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PowerManagement = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetworkDeviceStatsResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceStatsResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceStatsResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &NetworkDeviceStats{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetworkDeviceStats) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceStats: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceStats: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Total\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Total == nil {\n\t\t\t\tm.Total = &NetDev{}\n\t\t\t}\n\t\t\tif err := m.Total.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Devices\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Devices = append(m.Devices, &NetDev{})\n\t\t\tif err := m.Devices[len(m.Devices)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetDev) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetDev: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetDev: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxBytes\", wireType)\n\t\t\t}\n\t\t\tm.RxBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxBytes |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxPackets\", wireType)\n\t\t\t}\n\t\t\tm.RxPackets = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxPackets |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxErrors\", wireType)\n\t\t\t}\n\t\t\tm.RxErrors = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxErrors |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxDropped\", wireType)\n\t\t\t}\n\t\t\tm.RxDropped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxDropped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxFifo\", wireType)\n\t\t\t}\n\t\t\tm.RxFifo = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxFifo |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxFrame\", wireType)\n\t\t\t}\n\t\t\tm.RxFrame = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxFrame |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxCompressed\", wireType)\n\t\t\t}\n\t\t\tm.RxCompressed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxCompressed |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMulticast\", wireType)\n\t\t\t}\n\t\t\tm.RxMulticast = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMulticast |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxBytes\", wireType)\n\t\t\t}\n\t\t\tm.TxBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxBytes |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPackets\", wireType)\n\t\t\t}\n\t\t\tm.TxPackets = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxPackets |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxErrors\", wireType)\n\t\t\t}\n\t\t\tm.TxErrors = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxErrors |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxDropped\", wireType)\n\t\t\t}\n\t\t\tm.TxDropped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxDropped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxFifo\", wireType)\n\t\t\t}\n\t\t\tm.TxFifo = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxFifo |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxCollisions\", wireType)\n\t\t\t}\n\t\t\tm.TxCollisions = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxCollisions |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxCarrier\", wireType)\n\t\t\t}\n\t\t\tm.TxCarrier = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxCarrier |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxCompressed\", wireType)\n\t\t\t}\n\t\t\tm.TxCompressed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxCompressed |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskStatsResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStatsResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStatsResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &DiskStats{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskStats) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStats: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStats: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Total\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Total == nil {\n\t\t\t\tm.Total = &DiskStat{}\n\t\t\t}\n\t\t\tif err := m.Total.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Devices\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Devices = append(m.Devices, &DiskStat{})\n\t\t\tif err := m.Devices[len(m.Devices)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadCompleted\", wireType)\n\t\t\t}\n\t\t\tm.ReadCompleted = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReadCompleted |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadMerged\", wireType)\n\t\t\t}\n\t\t\tm.ReadMerged = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReadMerged |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadSectors\", wireType)\n\t\t\t}\n\t\t\tm.ReadSectors = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReadSectors |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadTimeMs\", wireType)\n\t\t\t}\n\t\t\tm.ReadTimeMs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReadTimeMs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WriteCompleted\", wireType)\n\t\t\t}\n\t\t\tm.WriteCompleted = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WriteCompleted |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WriteMerged\", wireType)\n\t\t\t}\n\t\t\tm.WriteMerged = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WriteMerged |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WriteSectors\", wireType)\n\t\t\t}\n\t\t\tm.WriteSectors = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WriteSectors |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WriteTimeMs\", wireType)\n\t\t\t}\n\t\t\tm.WriteTimeMs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WriteTimeMs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IoInProgress\", wireType)\n\t\t\t}\n\t\t\tm.IoInProgress = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IoInProgress |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IoTimeMs\", wireType)\n\t\t\t}\n\t\t\tm.IoTimeMs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IoTimeMs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IoTimeWeightedMs\", wireType)\n\t\t\t}\n\t\t\tm.IoTimeWeightedMs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IoTimeWeightedMs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiscardCompleted\", wireType)\n\t\t\t}\n\t\t\tm.DiscardCompleted = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DiscardCompleted |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiscardMerged\", wireType)\n\t\t\t}\n\t\t\tm.DiscardMerged = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DiscardMerged |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiscardSectors\", wireType)\n\t\t\t}\n\t\t\tm.DiscardSectors = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DiscardSectors |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiscardTimeMs\", wireType)\n\t\t\t}\n\t\t\tm.DiscardTimeMs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DiscardTimeMs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdLeaveClusterRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveClusterRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveClusterRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdLeaveCluster) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveCluster: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveCluster: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdLeaveClusterResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveClusterResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdLeaveClusterResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdLeaveCluster{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMemberRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Member\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Member = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMember) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMember: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMember: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMemberResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdRemoveMember{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMemberByIDRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByIDRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByIDRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberId\", wireType)\n\t\t\t}\n\t\t\tm.MemberId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemberId |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMemberByID) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByID: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByID: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRemoveMemberByIDResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByIDResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRemoveMemberByIDResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdRemoveMemberByID{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdForfeitLeadershipRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadershipRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadershipRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdForfeitLeadership) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadership: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadership: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Member\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Member = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdForfeitLeadershipResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadershipResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdForfeitLeadershipResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdForfeitLeadership{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMemberListRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberListRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberListRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field QueryLocal\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.QueryLocal = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMember) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMember: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMember: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Id\", wireType)\n\t\t\t}\n\t\t\tm.Id = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Id |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PeerUrls\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PeerUrls = append(m.PeerUrls, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClientUrls\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClientUrls = append(m.ClientUrls, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IsLearner\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.IsLearner = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMembers) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMembers: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMembers: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LegacyMembers\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LegacyMembers = append(m.LegacyMembers, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Members\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Members = append(m.Members, &EtcdMember{})\n\t\t\tif err := m.Members[len(m.Members)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMemberListResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberListResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberListResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdMembers{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdSnapshotRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdSnapshotRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdSnapshotRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRecover) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRecover: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRecover: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRecoverResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRecoverResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRecoverResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdRecover{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdAlarmListResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmListResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmListResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdAlarm{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdAlarm) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarm: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarm: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberAlarms\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MemberAlarms = append(m.MemberAlarms, &EtcdMemberAlarm{})\n\t\t\tif err := m.MemberAlarms[len(m.MemberAlarms)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMemberAlarm) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberAlarm: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberAlarm: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberId\", wireType)\n\t\t\t}\n\t\t\tm.MemberId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemberId |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Alarm\", wireType)\n\t\t\t}\n\t\t\tm.Alarm = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Alarm |= EtcdMemberAlarm_AlarmType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdAlarmDisarmResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmDisarmResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmDisarmResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdAlarmDisarm{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdAlarmDisarm) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmDisarm: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdAlarmDisarm: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberAlarms\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MemberAlarms = append(m.MemberAlarms, &EtcdMemberAlarm{})\n\t\t\tif err := m.MemberAlarms[len(m.MemberAlarms)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDefragmentResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDefragmentResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDefragmentResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdDefragment{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDefragment) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDefragment: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDefragment: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdStatusResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdStatusResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdStatusResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdStatus{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberStatus\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MemberStatus == nil {\n\t\t\t\tm.MemberStatus = &EtcdMemberStatus{}\n\t\t\t}\n\t\t\tif err := m.MemberStatus.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdMemberStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdMemberStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProtocolVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProtocolVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DbSize\", wireType)\n\t\t\t}\n\t\t\tm.DbSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DbSize |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DbSizeInUse\", wireType)\n\t\t\t}\n\t\t\tm.DbSizeInUse = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DbSizeInUse |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Leader\", wireType)\n\t\t\t}\n\t\t\tm.Leader = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Leader |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RaftIndex\", wireType)\n\t\t\t}\n\t\t\tm.RaftIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RaftIndex |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RaftTerm\", wireType)\n\t\t\t}\n\t\t\tm.RaftTerm = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RaftTerm |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RaftAppliedIndex\", wireType)\n\t\t\t}\n\t\t\tm.RaftAppliedIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RaftAppliedIndex |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Errors\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Errors = append(m.Errors, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IsLearner\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.IsLearner = bool(v != 0)\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberId\", wireType)\n\t\t\t}\n\t\t\tm.MemberId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemberId |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StorageVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.StorageVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeValidateRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidateRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidateRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeValidateResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidateResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidateResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdDowngradeValidate{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeValidate) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidate: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeValidate: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDowngrade\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClusterDowngrade == nil {\n\t\t\t\tm.ClusterDowngrade = &EtcdClusterDowngrade{}\n\t\t\t}\n\t\t\tif err := m.ClusterDowngrade.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeEnableRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnableRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnableRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeEnableResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnableResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnableResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdDowngradeEnable{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeEnable) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnable: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeEnable: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDowngrade\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClusterDowngrade == nil {\n\t\t\t\tm.ClusterDowngrade = &EtcdClusterDowngrade{}\n\t\t\t}\n\t\t\tif err := m.ClusterDowngrade.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeCancelResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeCancelResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeCancelResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &EtcdDowngradeCancel{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdDowngradeCancel) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeCancel: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdDowngradeCancel: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDowngrade\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClusterDowngrade == nil {\n\t\t\t\tm.ClusterDowngrade = &EtcdClusterDowngrade{}\n\t\t\t}\n\t\t\tif err := m.ClusterDowngrade.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdClusterDowngrade) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdClusterDowngrade: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdClusterDowngrade: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RouteConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RouteConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RouteConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Network\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Network = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Gateway\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Gateway = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metric\", wireType)\n\t\t\t}\n\t\t\tm.Metric = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Metric |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DHCPOptionsConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DHCPOptionsConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DHCPOptionsConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RouteMetric\", wireType)\n\t\t\t}\n\t\t\tm.RouteMetric = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RouteMetric |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetworkDeviceConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkDeviceConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Interface\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Interface = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cidr\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Cidr = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dhcp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Dhcp = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ignore\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ignore = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DhcpOptions\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.DhcpOptions == nil {\n\t\t\t\tm.DhcpOptions = &DHCPOptionsConfig{}\n\t\t\t}\n\t\t\tif err := m.DhcpOptions.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Routes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Routes = append(m.Routes, &RouteConfig{})\n\t\t\tif err := m.Routes[len(m.Routes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetworkConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetworkConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Interfaces\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Interfaces = append(m.Interfaces, &NetworkDeviceConfig{})\n\t\t\tif err := m.Interfaces[len(m.Interfaces)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *InstallConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: InstallConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: InstallConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InstallDisk\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InstallDisk = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InstallImage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InstallImage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= MachineConfig_MachineType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InstallConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.InstallConfig == nil {\n\t\t\t\tm.InstallConfig = &InstallConfig{}\n\t\t\t}\n\t\t\tif err := m.InstallConfig.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetworkConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.NetworkConfig == nil {\n\t\t\t\tm.NetworkConfig = &NetworkConfig{}\n\t\t\t}\n\t\t\tif err := m.NetworkConfig.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KubernetesVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.KubernetesVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ControlPlaneConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControlPlaneConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControlPlaneConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CNIConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CNIConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CNIConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Urls\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Urls = append(m.Urls, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ClusterNetworkConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterNetworkConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterNetworkConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsDomain\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsDomain = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CniConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CniConfig == nil {\n\t\t\t\tm.CniConfig = &CNIConfig{}\n\t\t\t}\n\t\t\tif err := m.CniConfig.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ClusterConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ClusterConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControlPlane\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ControlPlane == nil {\n\t\t\t\tm.ControlPlane = &ControlPlaneConfig{}\n\t\t\t}\n\t\t\tif err := m.ControlPlane.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterNetwork\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClusterNetwork == nil {\n\t\t\t\tm.ClusterNetwork = &ClusterNetworkConfig{}\n\t\t\t}\n\t\t\tif err := m.ClusterNetwork.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowSchedulingOnControlPlanes\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AllowSchedulingOnControlPlanes = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *GenerateClientConfigurationRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfigurationRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfigurationRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Roles\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Roles = append(m.Roles, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CrtTtl\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CrtTtl == nil {\n\t\t\t\tm.CrtTtl = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.CrtTtl).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *GenerateClientConfiguration) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfiguration: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfiguration: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ca\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ca = append(m.Ca[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Ca == nil {\n\t\t\t\tm.Ca = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Crt\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Crt = append(m.Crt[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Crt == nil {\n\t\t\t\tm.Crt = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Key == nil {\n\t\t\t\tm.Key = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Talosconfig\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Talosconfig = append(m.Talosconfig[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Talosconfig == nil {\n\t\t\t\tm.Talosconfig = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *GenerateClientConfigurationResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfigurationResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: GenerateClientConfigurationResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &GenerateClientConfiguration{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PacketCaptureRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PacketCaptureRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PacketCaptureRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Interface\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Interface = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Promiscuous\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Promiscuous = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SnapLen\", wireType)\n\t\t\t}\n\t\t\tm.SnapLen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SnapLen |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BpfFilter\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BpfFilter = append(m.BpfFilter, &BPFInstruction{})\n\t\t\tif err := m.BpfFilter[len(m.BpfFilter)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BPFInstruction) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BPFInstruction: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BPFInstruction: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Op\", wireType)\n\t\t\t}\n\t\t\tm.Op = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Op |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Jt\", wireType)\n\t\t\t}\n\t\t\tm.Jt = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Jt |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Jf\", wireType)\n\t\t\t}\n\t\t\tm.Jf = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Jf |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field K\", wireType)\n\t\t\t}\n\t\t\tm.K = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.K |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetstatRequest_Feature) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_Feature: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_Feature: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pid\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Pid = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetstatRequest_L4Proto) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_L4Proto: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_L4Proto: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tcp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tcp = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tcp6\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tcp6 = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Udp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Udp = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Udp6\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Udp6 = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Udplite\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Udplite = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Udplite6\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Udplite6 = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Raw\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Raw = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Raw6\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Raw6 = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetstatRequest_NetNS) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_NetNS: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest_NetNS: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostnetwork\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Hostnetwork = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Netns\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Netns = append(m.Netns, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Allnetns\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Allnetns = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetstatRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Filter\", wireType)\n\t\t\t}\n\t\t\tm.Filter = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Filter |= NetstatRequest_Filter(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Feature\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Feature == nil {\n\t\t\t\tm.Feature = &NetstatRequest_Feature{}\n\t\t\t}\n\t\t\tif err := m.Feature.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field L4Proto\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.L4Proto == nil {\n\t\t\t\tm.L4Proto = &NetstatRequest_L4Proto{}\n\t\t\t}\n\t\t\tif err := m.L4Proto.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Netns\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Netns == nil {\n\t\t\t\tm.Netns = &NetstatRequest_NetNS{}\n\t\t\t}\n\t\t\tif err := m.Netns.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConnectRecord_Process) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConnectRecord_Process: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConnectRecord_Process: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pid\", wireType)\n\t\t\t}\n\t\t\tm.Pid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Pid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConnectRecord) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConnectRecord: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConnectRecord: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field L4Proto\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.L4Proto = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Localip\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Localip = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Localport\", wireType)\n\t\t\t}\n\t\t\tm.Localport = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Localport |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Remoteip\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Remoteip = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Remoteport\", wireType)\n\t\t\t}\n\t\t\tm.Remoteport = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Remoteport |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tm.State = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.State |= ConnectRecord_State(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Txqueue\", wireType)\n\t\t\t}\n\t\t\tm.Txqueue = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Txqueue |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rxqueue\", wireType)\n\t\t\t}\n\t\t\tm.Rxqueue = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rxqueue |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tr\", wireType)\n\t\t\t}\n\t\t\tm.Tr = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tr |= ConnectRecord_TimerActive(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timerwhen\", wireType)\n\t\t\t}\n\t\t\tm.Timerwhen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timerwhen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Retrnsmt\", wireType)\n\t\t\t}\n\t\t\tm.Retrnsmt = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Retrnsmt |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uid\", wireType)\n\t\t\t}\n\t\t\tm.Uid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Uid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timeout\", wireType)\n\t\t\t}\n\t\t\tm.Timeout = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Timeout |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Inode\", wireType)\n\t\t\t}\n\t\t\tm.Inode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Inode |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ref\", wireType)\n\t\t\t}\n\t\t\tm.Ref = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Ref |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pointer\", wireType)\n\t\t\t}\n\t\t\tm.Pointer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Pointer |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Process\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Process == nil {\n\t\t\t\tm.Process = &ConnectRecord_Process{}\n\t\t\t}\n\t\t\tif err := m.Process.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Netns\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Netns = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Netstat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Netstat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Netstat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Connectrecord\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Connectrecord = append(m.Connectrecord, &ConnectRecord{})\n\t\t\tif err := m.Connectrecord[len(m.Connectrecord)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NetstatResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NetstatResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Netstat{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaWriteRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWriteRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWriteRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tm.Key = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Key |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Value == nil {\n\t\t\t\tm.Value = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaWrite) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWrite: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWrite: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaWriteResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWriteResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaWriteResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &MetaWrite{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaDeleteRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDeleteRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDeleteRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tm.Key = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Key |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaDelete) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDelete: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDelete: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaDeleteResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDeleteResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaDeleteResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &MetaDelete{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageListRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageListRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageListRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tm.Namespace = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Namespace |= common.ContainerdNamespace(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageListResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageListResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageListResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Digest\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Digest = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CreatedAt\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CreatedAt == nil {\n\t\t\t\tm.CreatedAt = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.CreatedAt).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImagePullRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePullRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePullRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Namespace\", wireType)\n\t\t\t}\n\t\t\tm.Namespace = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Namespace |= common.ContainerdNamespace(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Reference\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Reference = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImagePull) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePull: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePull: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImagePullResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePullResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePullResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &ImagePull{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/config/config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/config/config.proto\n\npackage config\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// MachineType matches machine.Type constants.\ntype MachineType int32\n\nconst (\n\tMachineType_UNKNOWN       MachineType = 0\n\tMachineType_INIT          MachineType = 1\n\tMachineType_CONTROL_PLANE MachineType = 2\n\tMachineType_WORKER        MachineType = 3\n)\n\n// Enum value maps for MachineType.\nvar (\n\tMachineType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"INIT\",\n\t\t2: \"CONTROL_PLANE\",\n\t\t3: \"WORKER\",\n\t}\n\tMachineType_value = map[string]int32{\n\t\t\"UNKNOWN\":       0,\n\t\t\"INIT\":          1,\n\t\t\"CONTROL_PLANE\": 2,\n\t\t\"WORKER\":        3,\n\t}\n)\n\nfunc (x MachineType) Enum() *MachineType {\n\tp := new(MachineType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MachineType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MachineType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_config_config_proto_enumTypes[0].Descriptor()\n}\n\nfunc (MachineType) Type() protoreflect.EnumType {\n\treturn &file_resource_config_config_proto_enumTypes[0]\n}\n\nfunc (x MachineType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use MachineType.Descriptor instead.\nfunc (MachineType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_config_config_proto_rawDescGZIP(), []int{0}\n}\n\n// MessageConfigSpec is the spec for the config.MachineConfig resource.\ntype MachineConfigSpec struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Contains YAML marshalled machine configuration.\n\t//\n\t// Byte representation is preserved as the machine configuration was submitted to the node.\n\tYamlMarshalled []byte `protobuf:\"bytes,1,opt,name=yaml_marshalled,json=yamlMarshalled,proto3\" json:\"yaml_marshalled,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *MachineConfigSpec) Reset() {\n\t*x = MachineConfigSpec{}\n\tmi := &file_resource_config_config_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineConfigSpec) ProtoMessage() {}\n\nfunc (x *MachineConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_config_config_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*MachineConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_config_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *MachineConfigSpec) GetYamlMarshalled() []byte {\n\tif x != nil {\n\t\treturn x.YamlMarshalled\n\t}\n\treturn nil\n}\n\n// MachineTypeSpec is the spec for the config.MachineType resource.\ntype MachineTypeSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMachineType   MachineType            `protobuf:\"varint,1,opt,name=machine_type,json=machineType,proto3,enum=resource.config.MachineType\" json:\"machine_type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MachineTypeSpec) Reset() {\n\t*x = MachineTypeSpec{}\n\tmi := &file_resource_config_config_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineTypeSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineTypeSpec) ProtoMessage() {}\n\nfunc (x *MachineTypeSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_config_config_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineTypeSpec.ProtoReflect.Descriptor instead.\nfunc (*MachineTypeSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_config_config_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *MachineTypeSpec) GetMachineType() MachineType {\n\tif x != nil {\n\t\treturn x.MachineType\n\t}\n\treturn MachineType_UNKNOWN\n}\n\nvar File_resource_config_config_proto protoreflect.FileDescriptor\n\nconst file_resource_config_config_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x1cresource/config/config.proto\\x12\\x0fresource.config\\\"<\\n\" +\n\t\"\\x11MachineConfigSpec\\x12'\\n\" +\n\t\"\\x0fyaml_marshalled\\x18\\x01 \\x01(\\fR\\x0eyamlMarshalled\\\"R\\n\" +\n\t\"\\x0fMachineTypeSpec\\x12?\\n\" +\n\t\"\\fmachine_type\\x18\\x01 \\x01(\\x0e2\\x1c.resource.config.MachineTypeR\\vmachineType*C\\n\" +\n\t\"\\vMachineType\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\b\\n\" +\n\t\"\\x04INIT\\x10\\x01\\x12\\x11\\n\" +\n\t\"\\rCONTROL_PLANE\\x10\\x02\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06WORKER\\x10\\x03B^\\n\" +\n\t\"\\x1ddev.talos.api.resource.configZ=github.com/siderolabs/talos/pkg/machinery/api/resource/configb\\x06proto3\"\n\nvar (\n\tfile_resource_config_config_proto_rawDescOnce sync.Once\n\tfile_resource_config_config_proto_rawDescData []byte\n)\n\nfunc file_resource_config_config_proto_rawDescGZIP() []byte {\n\tfile_resource_config_config_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_config_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_config_config_proto_rawDesc), len(file_resource_config_config_proto_rawDesc)))\n\t})\n\treturn file_resource_config_config_proto_rawDescData\n}\n\nvar file_resource_config_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_resource_config_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_resource_config_config_proto_goTypes = []any{\n\t(MachineType)(0),          // 0: resource.config.MachineType\n\t(*MachineConfigSpec)(nil), // 1: resource.config.MachineConfigSpec\n\t(*MachineTypeSpec)(nil),   // 2: resource.config.MachineTypeSpec\n}\nvar file_resource_config_config_proto_depIdxs = []int32{\n\t0, // 0: resource.config.MachineTypeSpec.machine_type:type_name -> resource.config.MachineType\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_config_config_proto_init() }\nfunc file_resource_config_config_proto_init() {\n\tif File_resource_config_config_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_config_config_proto_rawDesc), len(file_resource_config_config_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_config_config_proto_goTypes,\n\t\tDependencyIndexes: file_resource_config_config_proto_depIdxs,\n\t\tEnumInfos:         file_resource_config_config_proto_enumTypes,\n\t\tMessageInfos:      file_resource_config_config_proto_msgTypes,\n\t}.Build()\n\tFile_resource_config_config_proto = out.File\n\tfile_resource_config_config_proto_goTypes = nil\n\tfile_resource_config_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/config/config_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/config/config.proto\n\npackage config\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *MachineConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.YamlMarshalled) > 0 {\n\t\ti -= len(m.YamlMarshalled)\n\t\tcopy(dAtA[i:], m.YamlMarshalled)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.YamlMarshalled)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineTypeSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineTypeSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineTypeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MachineType != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MachineType))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.YamlMarshalled)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineTypeSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MachineType != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MachineType))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field YamlMarshalled\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.YamlMarshalled = append(m.YamlMarshalled[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.YamlMarshalled == nil {\n\t\t\t\tm.YamlMarshalled = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineTypeSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineTypeSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineTypeSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MachineType\", wireType)\n\t\t\t}\n\t\t\tm.MachineType = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MachineType |= MachineType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/block/block.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/block/block.proto\n\npackage block\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tv1alpha1 \"google.golang.org/genproto/googleapis/api/expr/v1alpha1\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// DeviceSpec is the spec for devices status.\ntype DeviceSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tType            string                 `protobuf:\"bytes,1,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tMajor           int64                  `protobuf:\"varint,2,opt,name=major,proto3\" json:\"major,omitempty\"`\n\tMinor           int64                  `protobuf:\"varint,3,opt,name=minor,proto3\" json:\"minor,omitempty\"`\n\tPartitionName   string                 `protobuf:\"bytes,4,opt,name=partition_name,json=partitionName,proto3\" json:\"partition_name,omitempty\"`\n\tPartitionNumber int64                  `protobuf:\"varint,5,opt,name=partition_number,json=partitionNumber,proto3\" json:\"partition_number,omitempty\"`\n\tGeneration      int64                  `protobuf:\"varint,6,opt,name=generation,proto3\" json:\"generation,omitempty\"`\n\tDevicePath      string                 `protobuf:\"bytes,7,opt,name=device_path,json=devicePath,proto3\" json:\"device_path,omitempty\"`\n\tParent          string                 `protobuf:\"bytes,8,opt,name=parent,proto3\" json:\"parent,omitempty\"`\n\tSecondaries     []string               `protobuf:\"bytes,9,rep,name=secondaries,proto3\" json:\"secondaries,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *DeviceSpec) Reset() {\n\t*x = DeviceSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DeviceSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeviceSpec) ProtoMessage() {}\n\nfunc (x *DeviceSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeviceSpec.ProtoReflect.Descriptor instead.\nfunc (*DeviceSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DeviceSpec) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *DeviceSpec) GetMajor() int64 {\n\tif x != nil {\n\t\treturn x.Major\n\t}\n\treturn 0\n}\n\nfunc (x *DeviceSpec) GetMinor() int64 {\n\tif x != nil {\n\t\treturn x.Minor\n\t}\n\treturn 0\n}\n\nfunc (x *DeviceSpec) GetPartitionName() string {\n\tif x != nil {\n\t\treturn x.PartitionName\n\t}\n\treturn \"\"\n}\n\nfunc (x *DeviceSpec) GetPartitionNumber() int64 {\n\tif x != nil {\n\t\treturn x.PartitionNumber\n\t}\n\treturn 0\n}\n\nfunc (x *DeviceSpec) GetGeneration() int64 {\n\tif x != nil {\n\t\treturn x.Generation\n\t}\n\treturn 0\n}\n\nfunc (x *DeviceSpec) GetDevicePath() string {\n\tif x != nil {\n\t\treturn x.DevicePath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DeviceSpec) GetParent() string {\n\tif x != nil {\n\t\treturn x.Parent\n\t}\n\treturn \"\"\n}\n\nfunc (x *DeviceSpec) GetSecondaries() []string {\n\tif x != nil {\n\t\treturn x.Secondaries\n\t}\n\treturn nil\n}\n\n// DiscoveredVolumeSpec is the spec for DiscoveredVolumes resource.\ntype DiscoveredVolumeSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tSize                uint64                 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tSectorSize          uint64                 `protobuf:\"varint,2,opt,name=sector_size,json=sectorSize,proto3\" json:\"sector_size,omitempty\"`\n\tIoSize              uint64                 `protobuf:\"varint,3,opt,name=io_size,json=ioSize,proto3\" json:\"io_size,omitempty\"`\n\tName                string                 `protobuf:\"bytes,4,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tUuid                string                 `protobuf:\"bytes,5,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tLabel               string                 `protobuf:\"bytes,6,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tBlockSize           uint32                 `protobuf:\"varint,7,opt,name=block_size,json=blockSize,proto3\" json:\"block_size,omitempty\"`\n\tFilesystemBlockSize uint32                 `protobuf:\"varint,8,opt,name=filesystem_block_size,json=filesystemBlockSize,proto3\" json:\"filesystem_block_size,omitempty\"`\n\tProbedSize          uint64                 `protobuf:\"varint,9,opt,name=probed_size,json=probedSize,proto3\" json:\"probed_size,omitempty\"`\n\tPartitionUuid       string                 `protobuf:\"bytes,10,opt,name=partition_uuid,json=partitionUuid,proto3\" json:\"partition_uuid,omitempty\"`\n\tPartitionType       string                 `protobuf:\"bytes,11,opt,name=partition_type,json=partitionType,proto3\" json:\"partition_type,omitempty\"`\n\tPartitionLabel      string                 `protobuf:\"bytes,12,opt,name=partition_label,json=partitionLabel,proto3\" json:\"partition_label,omitempty\"`\n\tPartitionIndex      uint64                 `protobuf:\"varint,13,opt,name=partition_index,json=partitionIndex,proto3\" json:\"partition_index,omitempty\"`\n\tType                string                 `protobuf:\"bytes,14,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tDevicePath          string                 `protobuf:\"bytes,15,opt,name=device_path,json=devicePath,proto3\" json:\"device_path,omitempty\"`\n\tParent              string                 `protobuf:\"bytes,16,opt,name=parent,proto3\" json:\"parent,omitempty\"`\n\tDevPath             string                 `protobuf:\"bytes,17,opt,name=dev_path,json=devPath,proto3\" json:\"dev_path,omitempty\"`\n\tParentDevPath       string                 `protobuf:\"bytes,18,opt,name=parent_dev_path,json=parentDevPath,proto3\" json:\"parent_dev_path,omitempty\"`\n\tPrettySize          string                 `protobuf:\"bytes,19,opt,name=pretty_size,json=prettySize,proto3\" json:\"pretty_size,omitempty\"`\n\tOffset              uint64                 `protobuf:\"varint,20,opt,name=offset,proto3\" json:\"offset,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *DiscoveredVolumeSpec) Reset() {\n\t*x = DiscoveredVolumeSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiscoveredVolumeSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiscoveredVolumeSpec) ProtoMessage() {}\n\nfunc (x *DiscoveredVolumeSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiscoveredVolumeSpec.ProtoReflect.Descriptor instead.\nfunc (*DiscoveredVolumeSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *DiscoveredVolumeSpec) GetSize() uint64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetSectorSize() uint64 {\n\tif x != nil {\n\t\treturn x.SectorSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetIoSize() uint64 {\n\tif x != nil {\n\t\treturn x.IoSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetBlockSize() uint32 {\n\tif x != nil {\n\t\treturn x.BlockSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetFilesystemBlockSize() uint32 {\n\tif x != nil {\n\t\treturn x.FilesystemBlockSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetProbedSize() uint64 {\n\tif x != nil {\n\t\treturn x.ProbedSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetPartitionUuid() string {\n\tif x != nil {\n\t\treturn x.PartitionUuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetPartitionType() string {\n\tif x != nil {\n\t\treturn x.PartitionType\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetPartitionLabel() string {\n\tif x != nil {\n\t\treturn x.PartitionLabel\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetPartitionIndex() uint64 {\n\tif x != nil {\n\t\treturn x.PartitionIndex\n\t}\n\treturn 0\n}\n\nfunc (x *DiscoveredVolumeSpec) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetDevicePath() string {\n\tif x != nil {\n\t\treturn x.DevicePath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetParent() string {\n\tif x != nil {\n\t\treturn x.Parent\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetDevPath() string {\n\tif x != nil {\n\t\treturn x.DevPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetParentDevPath() string {\n\tif x != nil {\n\t\treturn x.ParentDevPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetPrettySize() string {\n\tif x != nil {\n\t\treturn x.PrettySize\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiscoveredVolumeSpec) GetOffset() uint64 {\n\tif x != nil {\n\t\treturn x.Offset\n\t}\n\treturn 0\n}\n\n// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest.\ntype DiscoveryRefreshRequestSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRequest       int64                  `protobuf:\"varint,1,opt,name=request,proto3\" json:\"request,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiscoveryRefreshRequestSpec) Reset() {\n\t*x = DiscoveryRefreshRequestSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiscoveryRefreshRequestSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiscoveryRefreshRequestSpec) ProtoMessage() {}\n\nfunc (x *DiscoveryRefreshRequestSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiscoveryRefreshRequestSpec.ProtoReflect.Descriptor instead.\nfunc (*DiscoveryRefreshRequestSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *DiscoveryRefreshRequestSpec) GetRequest() int64 {\n\tif x != nil {\n\t\treturn x.Request\n\t}\n\treturn 0\n}\n\n// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status.\ntype DiscoveryRefreshStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRequest       int64                  `protobuf:\"varint,1,opt,name=request,proto3\" json:\"request,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiscoveryRefreshStatusSpec) Reset() {\n\t*x = DiscoveryRefreshStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiscoveryRefreshStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiscoveryRefreshStatusSpec) ProtoMessage() {}\n\nfunc (x *DiscoveryRefreshStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiscoveryRefreshStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*DiscoveryRefreshStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *DiscoveryRefreshStatusSpec) GetRequest() int64 {\n\tif x != nil {\n\t\treturn x.Request\n\t}\n\treturn 0\n}\n\n// DiskSelector selects a disk for the volume.\ntype DiskSelector struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMatch         *v1alpha1.CheckedExpr  `protobuf:\"bytes,1,opt,name=match,proto3\" json:\"match,omitempty\"`\n\tExternal      string                 `protobuf:\"bytes,2,opt,name=external,proto3\" json:\"external,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiskSelector) Reset() {\n\t*x = DiskSelector{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskSelector) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskSelector) ProtoMessage() {}\n\nfunc (x *DiskSelector) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskSelector.ProtoReflect.Descriptor instead.\nfunc (*DiskSelector) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *DiskSelector) GetMatch() *v1alpha1.CheckedExpr {\n\tif x != nil {\n\t\treturn x.Match\n\t}\n\treturn nil\n}\n\nfunc (x *DiskSelector) GetExternal() string {\n\tif x != nil {\n\t\treturn x.External\n\t}\n\treturn \"\"\n}\n\n// DiskSpec is the spec for Disks status.\ntype DiskSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tSize           uint64                 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tIoSize         uint64                 `protobuf:\"varint,2,opt,name=io_size,json=ioSize,proto3\" json:\"io_size,omitempty\"`\n\tSectorSize     uint64                 `protobuf:\"varint,3,opt,name=sector_size,json=sectorSize,proto3\" json:\"sector_size,omitempty\"`\n\tReadonly       bool                   `protobuf:\"varint,4,opt,name=readonly,proto3\" json:\"readonly,omitempty\"`\n\tModel          string                 `protobuf:\"bytes,5,opt,name=model,proto3\" json:\"model,omitempty\"`\n\tSerial         string                 `protobuf:\"bytes,6,opt,name=serial,proto3\" json:\"serial,omitempty\"`\n\tModalias       string                 `protobuf:\"bytes,7,opt,name=modalias,proto3\" json:\"modalias,omitempty\"`\n\tWwid           string                 `protobuf:\"bytes,8,opt,name=wwid,proto3\" json:\"wwid,omitempty\"`\n\tBusPath        string                 `protobuf:\"bytes,9,opt,name=bus_path,json=busPath,proto3\" json:\"bus_path,omitempty\"`\n\tSubSystem      string                 `protobuf:\"bytes,10,opt,name=sub_system,json=subSystem,proto3\" json:\"sub_system,omitempty\"`\n\tTransport      string                 `protobuf:\"bytes,11,opt,name=transport,proto3\" json:\"transport,omitempty\"`\n\tRotational     bool                   `protobuf:\"varint,12,opt,name=rotational,proto3\" json:\"rotational,omitempty\"`\n\tCdrom          bool                   `protobuf:\"varint,13,opt,name=cdrom,proto3\" json:\"cdrom,omitempty\"`\n\tDevPath        string                 `protobuf:\"bytes,14,opt,name=dev_path,json=devPath,proto3\" json:\"dev_path,omitempty\"`\n\tPrettySize     string                 `protobuf:\"bytes,15,opt,name=pretty_size,json=prettySize,proto3\" json:\"pretty_size,omitempty\"`\n\tSecondaryDisks []string               `protobuf:\"bytes,16,rep,name=secondary_disks,json=secondaryDisks,proto3\" json:\"secondary_disks,omitempty\"`\n\tUuid           string                 `protobuf:\"bytes,17,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tSymlinks       []string               `protobuf:\"bytes,18,rep,name=symlinks,proto3\" json:\"symlinks,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *DiskSpec) Reset() {\n\t*x = DiskSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiskSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiskSpec) ProtoMessage() {}\n\nfunc (x *DiskSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiskSpec.ProtoReflect.Descriptor instead.\nfunc (*DiskSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *DiskSpec) GetSize() uint64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *DiskSpec) GetIoSize() uint64 {\n\tif x != nil {\n\t\treturn x.IoSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiskSpec) GetSectorSize() uint64 {\n\tif x != nil {\n\t\treturn x.SectorSize\n\t}\n\treturn 0\n}\n\nfunc (x *DiskSpec) GetReadonly() bool {\n\tif x != nil {\n\t\treturn x.Readonly\n\t}\n\treturn false\n}\n\nfunc (x *DiskSpec) GetModel() string {\n\tif x != nil {\n\t\treturn x.Model\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetSerial() string {\n\tif x != nil {\n\t\treturn x.Serial\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetModalias() string {\n\tif x != nil {\n\t\treturn x.Modalias\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetWwid() string {\n\tif x != nil {\n\t\treturn x.Wwid\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetBusPath() string {\n\tif x != nil {\n\t\treturn x.BusPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetSubSystem() string {\n\tif x != nil {\n\t\treturn x.SubSystem\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetTransport() string {\n\tif x != nil {\n\t\treturn x.Transport\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetRotational() bool {\n\tif x != nil {\n\t\treturn x.Rotational\n\t}\n\treturn false\n}\n\nfunc (x *DiskSpec) GetCdrom() bool {\n\tif x != nil {\n\t\treturn x.Cdrom\n\t}\n\treturn false\n}\n\nfunc (x *DiskSpec) GetDevPath() string {\n\tif x != nil {\n\t\treturn x.DevPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetPrettySize() string {\n\tif x != nil {\n\t\treturn x.PrettySize\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetSecondaryDisks() []string {\n\tif x != nil {\n\t\treturn x.SecondaryDisks\n\t}\n\treturn nil\n}\n\nfunc (x *DiskSpec) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiskSpec) GetSymlinks() []string {\n\tif x != nil {\n\t\treturn x.Symlinks\n\t}\n\treturn nil\n}\n\n// EncryptionKey is the spec for volume encryption key.\ntype EncryptionKey struct {\n\tstate                            protoimpl.MessageState       `protogen:\"open.v1\"`\n\tSlot                             int64                        `protobuf:\"varint,1,opt,name=slot,proto3\" json:\"slot,omitempty\"`\n\tType                             enums.BlockEncryptionKeyType `protobuf:\"varint,2,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockEncryptionKeyType\" json:\"type,omitempty\"`\n\tStaticPassphrase                 []byte                       `protobuf:\"bytes,3,opt,name=static_passphrase,json=staticPassphrase,proto3\" json:\"static_passphrase,omitempty\"`\n\tKmsEndpoint                      string                       `protobuf:\"bytes,4,opt,name=kms_endpoint,json=kmsEndpoint,proto3\" json:\"kms_endpoint,omitempty\"`\n\tTpmCheckSecurebootStatusOnEnroll bool                         `protobuf:\"varint,5,opt,name=tpm_check_secureboot_status_on_enroll,json=tpmCheckSecurebootStatusOnEnroll,proto3\" json:\"tpm_check_secureboot_status_on_enroll,omitempty\"`\n\tLockToState                      bool                         `protobuf:\"varint,6,opt,name=lock_to_state,json=lockToState,proto3\" json:\"lock_to_state,omitempty\"`\n\tTpmpcRs                          []int64                      `protobuf:\"varint,7,rep,packed,name=tpmpc_rs,json=tpmpcRs,proto3\" json:\"tpmpc_rs,omitempty\"`\n\tTpmPubKeyPcRs                    []int64                      `protobuf:\"varint,8,rep,packed,name=tpm_pub_key_pc_rs,json=tpmPubKeyPcRs,proto3\" json:\"tpm_pub_key_pc_rs,omitempty\"`\n\tunknownFields                    protoimpl.UnknownFields\n\tsizeCache                        protoimpl.SizeCache\n}\n\nfunc (x *EncryptionKey) Reset() {\n\t*x = EncryptionKey{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EncryptionKey) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EncryptionKey) ProtoMessage() {}\n\nfunc (x *EncryptionKey) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EncryptionKey.ProtoReflect.Descriptor instead.\nfunc (*EncryptionKey) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *EncryptionKey) GetSlot() int64 {\n\tif x != nil {\n\t\treturn x.Slot\n\t}\n\treturn 0\n}\n\nfunc (x *EncryptionKey) GetType() enums.BlockEncryptionKeyType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.BlockEncryptionKeyType(0)\n}\n\nfunc (x *EncryptionKey) GetStaticPassphrase() []byte {\n\tif x != nil {\n\t\treturn x.StaticPassphrase\n\t}\n\treturn nil\n}\n\nfunc (x *EncryptionKey) GetKmsEndpoint() string {\n\tif x != nil {\n\t\treturn x.KmsEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *EncryptionKey) GetTpmCheckSecurebootStatusOnEnroll() bool {\n\tif x != nil {\n\t\treturn x.TpmCheckSecurebootStatusOnEnroll\n\t}\n\treturn false\n}\n\nfunc (x *EncryptionKey) GetLockToState() bool {\n\tif x != nil {\n\t\treturn x.LockToState\n\t}\n\treturn false\n}\n\nfunc (x *EncryptionKey) GetTpmpcRs() []int64 {\n\tif x != nil {\n\t\treturn x.TpmpcRs\n\t}\n\treturn nil\n}\n\nfunc (x *EncryptionKey) GetTpmPubKeyPcRs() []int64 {\n\tif x != nil {\n\t\treturn x.TpmPubKeyPcRs\n\t}\n\treturn nil\n}\n\n// EncryptionSpec is the spec for volume encryption.\ntype EncryptionSpec struct {\n\tstate         protoimpl.MessageState            `protogen:\"open.v1\"`\n\tProvider      enums.BlockEncryptionProviderType `protobuf:\"varint,1,opt,name=provider,proto3,enum=talos.resource.definitions.enums.BlockEncryptionProviderType\" json:\"provider,omitempty\"`\n\tKeys          []*EncryptionKey                  `protobuf:\"bytes,2,rep,name=keys,proto3\" json:\"keys,omitempty\"`\n\tCipher        string                            `protobuf:\"bytes,3,opt,name=cipher,proto3\" json:\"cipher,omitempty\"`\n\tKeySize       uint64                            `protobuf:\"varint,4,opt,name=key_size,json=keySize,proto3\" json:\"key_size,omitempty\"`\n\tBlockSize     uint64                            `protobuf:\"varint,5,opt,name=block_size,json=blockSize,proto3\" json:\"block_size,omitempty\"`\n\tPerfOptions   []string                          `protobuf:\"bytes,6,rep,name=perf_options,json=perfOptions,proto3\" json:\"perf_options,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EncryptionSpec) Reset() {\n\t*x = EncryptionSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EncryptionSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EncryptionSpec) ProtoMessage() {}\n\nfunc (x *EncryptionSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EncryptionSpec.ProtoReflect.Descriptor instead.\nfunc (*EncryptionSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *EncryptionSpec) GetProvider() enums.BlockEncryptionProviderType {\n\tif x != nil {\n\t\treturn x.Provider\n\t}\n\treturn enums.BlockEncryptionProviderType(0)\n}\n\nfunc (x *EncryptionSpec) GetKeys() []*EncryptionKey {\n\tif x != nil {\n\t\treturn x.Keys\n\t}\n\treturn nil\n}\n\nfunc (x *EncryptionSpec) GetCipher() string {\n\tif x != nil {\n\t\treturn x.Cipher\n\t}\n\treturn \"\"\n}\n\nfunc (x *EncryptionSpec) GetKeySize() uint64 {\n\tif x != nil {\n\t\treturn x.KeySize\n\t}\n\treturn 0\n}\n\nfunc (x *EncryptionSpec) GetBlockSize() uint64 {\n\tif x != nil {\n\t\treturn x.BlockSize\n\t}\n\treturn 0\n}\n\nfunc (x *EncryptionSpec) GetPerfOptions() []string {\n\tif x != nil {\n\t\treturn x.PerfOptions\n\t}\n\treturn nil\n}\n\n// FilesystemSpec is the spec for volume filesystem.\ntype FilesystemSpec struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tType          enums.BlockFilesystemType `protobuf:\"varint,1,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockFilesystemType\" json:\"type,omitempty\"`\n\tLabel         string                    `protobuf:\"bytes,2,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *FilesystemSpec) Reset() {\n\t*x = FilesystemSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *FilesystemSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*FilesystemSpec) ProtoMessage() {}\n\nfunc (x *FilesystemSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use FilesystemSpec.ProtoReflect.Descriptor instead.\nfunc (*FilesystemSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *FilesystemSpec) GetType() enums.BlockFilesystemType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.BlockFilesystemType(0)\n}\n\nfunc (x *FilesystemSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\n// LocatorSpec is the spec for volume locator.\ntype LocatorSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMatch         *v1alpha1.CheckedExpr  `protobuf:\"bytes,1,opt,name=match,proto3\" json:\"match,omitempty\"`\n\tDiskMatch     *v1alpha1.CheckedExpr  `protobuf:\"bytes,2,opt,name=disk_match,json=diskMatch,proto3\" json:\"disk_match,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LocatorSpec) Reset() {\n\t*x = LocatorSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LocatorSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LocatorSpec) ProtoMessage() {}\n\nfunc (x *LocatorSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LocatorSpec.ProtoReflect.Descriptor instead.\nfunc (*LocatorSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *LocatorSpec) GetMatch() *v1alpha1.CheckedExpr {\n\tif x != nil {\n\t\treturn x.Match\n\t}\n\treturn nil\n}\n\nfunc (x *LocatorSpec) GetDiskMatch() *v1alpha1.CheckedExpr {\n\tif x != nil {\n\t\treturn x.DiskMatch\n\t}\n\treturn nil\n}\n\n// MountRequestSpec is the spec for MountRequest.\ntype MountRequestSpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tVolumeId          string                 `protobuf:\"bytes,1,opt,name=volume_id,json=volumeId,proto3\" json:\"volume_id,omitempty\"`\n\tParentMountId     string                 `protobuf:\"bytes,2,opt,name=parent_mount_id,json=parentMountId,proto3\" json:\"parent_mount_id,omitempty\"`\n\tRequesters        []string               `protobuf:\"bytes,3,rep,name=requesters,proto3\" json:\"requesters,omitempty\"`\n\tRequesterIDs      []string               `protobuf:\"bytes,4,rep,name=requester_i_ds,json=requesterIDs,proto3\" json:\"requester_i_ds,omitempty\"`\n\tReadOnly          bool                   `protobuf:\"varint,5,opt,name=read_only,json=readOnly,proto3\" json:\"read_only,omitempty\"`\n\tDetached          bool                   `protobuf:\"varint,6,opt,name=detached,proto3\" json:\"detached,omitempty\"`\n\tDisableAccessTime bool                   `protobuf:\"varint,7,opt,name=disable_access_time,json=disableAccessTime,proto3\" json:\"disable_access_time,omitempty\"`\n\tSecure            bool                   `protobuf:\"varint,8,opt,name=secure,proto3\" json:\"secure,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *MountRequestSpec) Reset() {\n\t*x = MountRequestSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountRequestSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountRequestSpec) ProtoMessage() {}\n\nfunc (x *MountRequestSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountRequestSpec.ProtoReflect.Descriptor instead.\nfunc (*MountRequestSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *MountRequestSpec) GetVolumeId() string {\n\tif x != nil {\n\t\treturn x.VolumeId\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountRequestSpec) GetParentMountId() string {\n\tif x != nil {\n\t\treturn x.ParentMountId\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountRequestSpec) GetRequesters() []string {\n\tif x != nil {\n\t\treturn x.Requesters\n\t}\n\treturn nil\n}\n\nfunc (x *MountRequestSpec) GetRequesterIDs() []string {\n\tif x != nil {\n\t\treturn x.RequesterIDs\n\t}\n\treturn nil\n}\n\nfunc (x *MountRequestSpec) GetReadOnly() bool {\n\tif x != nil {\n\t\treturn x.ReadOnly\n\t}\n\treturn false\n}\n\nfunc (x *MountRequestSpec) GetDetached() bool {\n\tif x != nil {\n\t\treturn x.Detached\n\t}\n\treturn false\n}\n\nfunc (x *MountRequestSpec) GetDisableAccessTime() bool {\n\tif x != nil {\n\t\treturn x.DisableAccessTime\n\t}\n\treturn false\n}\n\nfunc (x *MountRequestSpec) GetSecure() bool {\n\tif x != nil {\n\t\treturn x.Secure\n\t}\n\treturn false\n}\n\n// MountSpec is the spec for volume mount.\ntype MountSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tTargetPath          string                 `protobuf:\"bytes,1,opt,name=target_path,json=targetPath,proto3\" json:\"target_path,omitempty\"`\n\tSelinuxLabel        string                 `protobuf:\"bytes,2,opt,name=selinux_label,json=selinuxLabel,proto3\" json:\"selinux_label,omitempty\"`\n\tProjectQuotaSupport bool                   `protobuf:\"varint,3,opt,name=project_quota_support,json=projectQuotaSupport,proto3\" json:\"project_quota_support,omitempty\"`\n\tParentId            string                 `protobuf:\"bytes,4,opt,name=parent_id,json=parentId,proto3\" json:\"parent_id,omitempty\"`\n\tFileMode            uint32                 `protobuf:\"varint,5,opt,name=file_mode,json=fileMode,proto3\" json:\"file_mode,omitempty\"`\n\tUid                 int64                  `protobuf:\"varint,6,opt,name=uid,proto3\" json:\"uid,omitempty\"`\n\tGid                 int64                  `protobuf:\"varint,7,opt,name=gid,proto3\" json:\"gid,omitempty\"`\n\tRecursiveRelabel    bool                   `protobuf:\"varint,8,opt,name=recursive_relabel,json=recursiveRelabel,proto3\" json:\"recursive_relabel,omitempty\"`\n\tBindTarget          string                 `protobuf:\"bytes,9,opt,name=bind_target,json=bindTarget,proto3\" json:\"bind_target,omitempty\"`\n\tParameters          []*ParameterSpec       `protobuf:\"bytes,10,rep,name=parameters,proto3\" json:\"parameters,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *MountSpec) Reset() {\n\t*x = MountSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountSpec) ProtoMessage() {}\n\nfunc (x *MountSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountSpec.ProtoReflect.Descriptor instead.\nfunc (*MountSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *MountSpec) GetTargetPath() string {\n\tif x != nil {\n\t\treturn x.TargetPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountSpec) GetSelinuxLabel() string {\n\tif x != nil {\n\t\treturn x.SelinuxLabel\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountSpec) GetProjectQuotaSupport() bool {\n\tif x != nil {\n\t\treturn x.ProjectQuotaSupport\n\t}\n\treturn false\n}\n\nfunc (x *MountSpec) GetParentId() string {\n\tif x != nil {\n\t\treturn x.ParentId\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountSpec) GetFileMode() uint32 {\n\tif x != nil {\n\t\treturn x.FileMode\n\t}\n\treturn 0\n}\n\nfunc (x *MountSpec) GetUid() int64 {\n\tif x != nil {\n\t\treturn x.Uid\n\t}\n\treturn 0\n}\n\nfunc (x *MountSpec) GetGid() int64 {\n\tif x != nil {\n\t\treturn x.Gid\n\t}\n\treturn 0\n}\n\nfunc (x *MountSpec) GetRecursiveRelabel() bool {\n\tif x != nil {\n\t\treturn x.RecursiveRelabel\n\t}\n\treturn false\n}\n\nfunc (x *MountSpec) GetBindTarget() string {\n\tif x != nil {\n\t\treturn x.BindTarget\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountSpec) GetParameters() []*ParameterSpec {\n\tif x != nil {\n\t\treturn x.Parameters\n\t}\n\treturn nil\n}\n\n// MountStatusSpec is the spec for MountStatus.\ntype MountStatusSpec struct {\n\tstate               protoimpl.MessageState            `protogen:\"open.v1\"`\n\tSpec                *MountRequestSpec                 `protobuf:\"bytes,1,opt,name=spec,proto3\" json:\"spec,omitempty\"`\n\tTarget              string                            `protobuf:\"bytes,2,opt,name=target,proto3\" json:\"target,omitempty\"`\n\tSource              string                            `protobuf:\"bytes,3,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tFilesystem          enums.BlockFilesystemType         `protobuf:\"varint,4,opt,name=filesystem,proto3,enum=talos.resource.definitions.enums.BlockFilesystemType\" json:\"filesystem,omitempty\"`\n\tReadOnly            bool                              `protobuf:\"varint,5,opt,name=read_only,json=readOnly,proto3\" json:\"read_only,omitempty\"`\n\tProjectQuotaSupport bool                              `protobuf:\"varint,6,opt,name=project_quota_support,json=projectQuotaSupport,proto3\" json:\"project_quota_support,omitempty\"`\n\tEncryptionProvider  enums.BlockEncryptionProviderType `protobuf:\"varint,7,opt,name=encryption_provider,json=encryptionProvider,proto3,enum=talos.resource.definitions.enums.BlockEncryptionProviderType\" json:\"encryption_provider,omitempty\"`\n\tDetached            bool                              `protobuf:\"varint,8,opt,name=detached,proto3\" json:\"detached,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *MountStatusSpec) Reset() {\n\t*x = MountStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountStatusSpec) ProtoMessage() {}\n\nfunc (x *MountStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*MountStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *MountStatusSpec) GetSpec() *MountRequestSpec {\n\tif x != nil {\n\t\treturn x.Spec\n\t}\n\treturn nil\n}\n\nfunc (x *MountStatusSpec) GetTarget() string {\n\tif x != nil {\n\t\treturn x.Target\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStatusSpec) GetSource() string {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStatusSpec) GetFilesystem() enums.BlockFilesystemType {\n\tif x != nil {\n\t\treturn x.Filesystem\n\t}\n\treturn enums.BlockFilesystemType(0)\n}\n\nfunc (x *MountStatusSpec) GetReadOnly() bool {\n\tif x != nil {\n\t\treturn x.ReadOnly\n\t}\n\treturn false\n}\n\nfunc (x *MountStatusSpec) GetProjectQuotaSupport() bool {\n\tif x != nil {\n\t\treturn x.ProjectQuotaSupport\n\t}\n\treturn false\n}\n\nfunc (x *MountStatusSpec) GetEncryptionProvider() enums.BlockEncryptionProviderType {\n\tif x != nil {\n\t\treturn x.EncryptionProvider\n\t}\n\treturn enums.BlockEncryptionProviderType(0)\n}\n\nfunc (x *MountStatusSpec) GetDetached() bool {\n\tif x != nil {\n\t\treturn x.Detached\n\t}\n\treturn false\n}\n\n// ParameterSpec is a mount parameter.\ntype ParameterSpec struct {\n\tstate         protoimpl.MessageState     `protogen:\"open.v1\"`\n\tType          enums.BlockFSParameterType `protobuf:\"varint,1,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockFSParameterType\" json:\"type,omitempty\"`\n\tName          string                     `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tString_       string                     `protobuf:\"bytes,3,opt,name=string,proto3\" json:\"string,omitempty\"`\n\tBinary        []byte                     `protobuf:\"bytes,5,opt,name=binary,proto3\" json:\"binary,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ParameterSpec) Reset() {\n\t*x = ParameterSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ParameterSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ParameterSpec) ProtoMessage() {}\n\nfunc (x *ParameterSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ParameterSpec.ProtoReflect.Descriptor instead.\nfunc (*ParameterSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *ParameterSpec) GetType() enums.BlockFSParameterType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.BlockFSParameterType(0)\n}\n\nfunc (x *ParameterSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ParameterSpec) GetString_() string {\n\tif x != nil {\n\t\treturn x.String_\n\t}\n\treturn \"\"\n}\n\nfunc (x *ParameterSpec) GetBinary() []byte {\n\tif x != nil {\n\t\treturn x.Binary\n\t}\n\treturn nil\n}\n\n// PartitionSpec is the spec for volume partitioning.\ntype PartitionSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tMinSize         uint64                 `protobuf:\"varint,1,opt,name=min_size,json=minSize,proto3\" json:\"min_size,omitempty\"`\n\tMaxSize         uint64                 `protobuf:\"varint,2,opt,name=max_size,json=maxSize,proto3\" json:\"max_size,omitempty\"`\n\tGrow            bool                   `protobuf:\"varint,3,opt,name=grow,proto3\" json:\"grow,omitempty\"`\n\tLabel           string                 `protobuf:\"bytes,4,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tTypeUuid        string                 `protobuf:\"bytes,5,opt,name=type_uuid,json=typeUuid,proto3\" json:\"type_uuid,omitempty\"`\n\tRelativeMaxSize uint64                 `protobuf:\"varint,6,opt,name=relative_max_size,json=relativeMaxSize,proto3\" json:\"relative_max_size,omitempty\"`\n\tNegativeMaxSize bool                   `protobuf:\"varint,7,opt,name=negative_max_size,json=negativeMaxSize,proto3\" json:\"negative_max_size,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *PartitionSpec) Reset() {\n\t*x = PartitionSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PartitionSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PartitionSpec) ProtoMessage() {}\n\nfunc (x *PartitionSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PartitionSpec.ProtoReflect.Descriptor instead.\nfunc (*PartitionSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *PartitionSpec) GetMinSize() uint64 {\n\tif x != nil {\n\t\treturn x.MinSize\n\t}\n\treturn 0\n}\n\nfunc (x *PartitionSpec) GetMaxSize() uint64 {\n\tif x != nil {\n\t\treturn x.MaxSize\n\t}\n\treturn 0\n}\n\nfunc (x *PartitionSpec) GetGrow() bool {\n\tif x != nil {\n\t\treturn x.Grow\n\t}\n\treturn false\n}\n\nfunc (x *PartitionSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\nfunc (x *PartitionSpec) GetTypeUuid() string {\n\tif x != nil {\n\t\treturn x.TypeUuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *PartitionSpec) GetRelativeMaxSize() uint64 {\n\tif x != nil {\n\t\treturn x.RelativeMaxSize\n\t}\n\treturn 0\n}\n\nfunc (x *PartitionSpec) GetNegativeMaxSize() bool {\n\tif x != nil {\n\t\treturn x.NegativeMaxSize\n\t}\n\treturn false\n}\n\n// ProvisioningSpec is the spec for volume provisioning.\ntype ProvisioningSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tDiskSelector   *DiskSelector          `protobuf:\"bytes,1,opt,name=disk_selector,json=diskSelector,proto3\" json:\"disk_selector,omitempty\"`\n\tPartitionSpec  *PartitionSpec         `protobuf:\"bytes,2,opt,name=partition_spec,json=partitionSpec,proto3\" json:\"partition_spec,omitempty\"`\n\tWave           int64                  `protobuf:\"varint,3,opt,name=wave,proto3\" json:\"wave,omitempty\"`\n\tFilesystemSpec *FilesystemSpec        `protobuf:\"bytes,4,opt,name=filesystem_spec,json=filesystemSpec,proto3\" json:\"filesystem_spec,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ProvisioningSpec) Reset() {\n\t*x = ProvisioningSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[15]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProvisioningSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProvisioningSpec) ProtoMessage() {}\n\nfunc (x *ProvisioningSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[15]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProvisioningSpec.ProtoReflect.Descriptor instead.\nfunc (*ProvisioningSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *ProvisioningSpec) GetDiskSelector() *DiskSelector {\n\tif x != nil {\n\t\treturn x.DiskSelector\n\t}\n\treturn nil\n}\n\nfunc (x *ProvisioningSpec) GetPartitionSpec() *PartitionSpec {\n\tif x != nil {\n\t\treturn x.PartitionSpec\n\t}\n\treturn nil\n}\n\nfunc (x *ProvisioningSpec) GetWave() int64 {\n\tif x != nil {\n\t\treturn x.Wave\n\t}\n\treturn 0\n}\n\nfunc (x *ProvisioningSpec) GetFilesystemSpec() *FilesystemSpec {\n\tif x != nil {\n\t\treturn x.FilesystemSpec\n\t}\n\treturn nil\n}\n\n// SwapStatusSpec is the spec for SwapStatuss resource.\ntype SwapStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDevice        string                 `protobuf:\"bytes,1,opt,name=device,proto3\" json:\"device,omitempty\"`\n\tSizeBytes     uint64                 `protobuf:\"varint,2,opt,name=size_bytes,json=sizeBytes,proto3\" json:\"size_bytes,omitempty\"`\n\tSizeHuman     string                 `protobuf:\"bytes,3,opt,name=size_human,json=sizeHuman,proto3\" json:\"size_human,omitempty\"`\n\tUsedBytes     uint64                 `protobuf:\"varint,4,opt,name=used_bytes,json=usedBytes,proto3\" json:\"used_bytes,omitempty\"`\n\tUsedHuman     string                 `protobuf:\"bytes,5,opt,name=used_human,json=usedHuman,proto3\" json:\"used_human,omitempty\"`\n\tPriority      int32                  `protobuf:\"varint,6,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tType          string                 `protobuf:\"bytes,7,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SwapStatusSpec) Reset() {\n\t*x = SwapStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[16]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SwapStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SwapStatusSpec) ProtoMessage() {}\n\nfunc (x *SwapStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[16]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SwapStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*SwapStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *SwapStatusSpec) GetDevice() string {\n\tif x != nil {\n\t\treturn x.Device\n\t}\n\treturn \"\"\n}\n\nfunc (x *SwapStatusSpec) GetSizeBytes() uint64 {\n\tif x != nil {\n\t\treturn x.SizeBytes\n\t}\n\treturn 0\n}\n\nfunc (x *SwapStatusSpec) GetSizeHuman() string {\n\tif x != nil {\n\t\treturn x.SizeHuman\n\t}\n\treturn \"\"\n}\n\nfunc (x *SwapStatusSpec) GetUsedBytes() uint64 {\n\tif x != nil {\n\t\treturn x.UsedBytes\n\t}\n\treturn 0\n}\n\nfunc (x *SwapStatusSpec) GetUsedHuman() string {\n\tif x != nil {\n\t\treturn x.UsedHuman\n\t}\n\treturn \"\"\n}\n\nfunc (x *SwapStatusSpec) GetPriority() int32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\nfunc (x *SwapStatusSpec) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\n// SymlinkProvisioningSpec is the spec for volume symlink.\ntype SymlinkProvisioningSpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tSymlinkTargetPath string                 `protobuf:\"bytes,1,opt,name=symlink_target_path,json=symlinkTargetPath,proto3\" json:\"symlink_target_path,omitempty\"`\n\tForce             bool                   `protobuf:\"varint,2,opt,name=force,proto3\" json:\"force,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *SymlinkProvisioningSpec) Reset() {\n\t*x = SymlinkProvisioningSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[17]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SymlinkProvisioningSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SymlinkProvisioningSpec) ProtoMessage() {}\n\nfunc (x *SymlinkProvisioningSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[17]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SymlinkProvisioningSpec.ProtoReflect.Descriptor instead.\nfunc (*SymlinkProvisioningSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *SymlinkProvisioningSpec) GetSymlinkTargetPath() string {\n\tif x != nil {\n\t\treturn x.SymlinkTargetPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *SymlinkProvisioningSpec) GetForce() bool {\n\tif x != nil {\n\t\treturn x.Force\n\t}\n\treturn false\n}\n\n// SymlinkSpec is the spec for Symlinks resource.\ntype SymlinkSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPaths         []string               `protobuf:\"bytes,1,rep,name=paths,proto3\" json:\"paths,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SymlinkSpec) Reset() {\n\t*x = SymlinkSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[18]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SymlinkSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SymlinkSpec) ProtoMessage() {}\n\nfunc (x *SymlinkSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[18]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SymlinkSpec.ProtoReflect.Descriptor instead.\nfunc (*SymlinkSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *SymlinkSpec) GetPaths() []string {\n\tif x != nil {\n\t\treturn x.Paths\n\t}\n\treturn nil\n}\n\n// SystemDiskSpec is the spec for SystemDisks resource.\ntype SystemDiskSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDiskId        string                 `protobuf:\"bytes,1,opt,name=disk_id,json=diskId,proto3\" json:\"disk_id,omitempty\"`\n\tDevPath       string                 `protobuf:\"bytes,2,opt,name=dev_path,json=devPath,proto3\" json:\"dev_path,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SystemDiskSpec) Reset() {\n\t*x = SystemDiskSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[19]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SystemDiskSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemDiskSpec) ProtoMessage() {}\n\nfunc (x *SystemDiskSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[19]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemDiskSpec.ProtoReflect.Descriptor instead.\nfunc (*SystemDiskSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *SystemDiskSpec) GetDiskId() string {\n\tif x != nil {\n\t\treturn x.DiskId\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemDiskSpec) GetDevPath() string {\n\tif x != nil {\n\t\treturn x.DevPath\n\t}\n\treturn \"\"\n}\n\n// TPMEncryptionOptionsInfo is the options for TPM-based encryption.\ntype TPMEncryptionOptionsInfo struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPcRs          []int64                `protobuf:\"varint,1,rep,packed,name=pc_rs,json=pcRs,proto3\" json:\"pc_rs,omitempty\"`\n\tPubKeyPcRs    []int64                `protobuf:\"varint,2,rep,packed,name=pub_key_pc_rs,json=pubKeyPcRs,proto3\" json:\"pub_key_pc_rs,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TPMEncryptionOptionsInfo) Reset() {\n\t*x = TPMEncryptionOptionsInfo{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[20]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TPMEncryptionOptionsInfo) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TPMEncryptionOptionsInfo) ProtoMessage() {}\n\nfunc (x *TPMEncryptionOptionsInfo) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[20]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TPMEncryptionOptionsInfo.ProtoReflect.Descriptor instead.\nfunc (*TPMEncryptionOptionsInfo) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *TPMEncryptionOptionsInfo) GetPcRs() []int64 {\n\tif x != nil {\n\t\treturn x.PcRs\n\t}\n\treturn nil\n}\n\nfunc (x *TPMEncryptionOptionsInfo) GetPubKeyPcRs() []int64 {\n\tif x != nil {\n\t\treturn x.PubKeyPcRs\n\t}\n\treturn nil\n}\n\n// UserDiskConfigStatusSpec is the spec for UserDiskConfigStatus resource.\ntype UserDiskConfigStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady         bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tTornDown      bool                   `protobuf:\"varint,2,opt,name=torn_down,json=tornDown,proto3\" json:\"torn_down,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *UserDiskConfigStatusSpec) Reset() {\n\t*x = UserDiskConfigStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[21]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *UserDiskConfigStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UserDiskConfigStatusSpec) ProtoMessage() {}\n\nfunc (x *UserDiskConfigStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[21]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UserDiskConfigStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*UserDiskConfigStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *UserDiskConfigStatusSpec) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *UserDiskConfigStatusSpec) GetTornDown() bool {\n\tif x != nil {\n\t\treturn x.TornDown\n\t}\n\treturn false\n}\n\n// VolumeConfigSpec is the spec for VolumeConfig resource.\ntype VolumeConfigSpec struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tParentId      string                   `protobuf:\"bytes,1,opt,name=parent_id,json=parentId,proto3\" json:\"parent_id,omitempty\"`\n\tType          enums.BlockVolumeType    `protobuf:\"varint,2,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockVolumeType\" json:\"type,omitempty\"`\n\tProvisioning  *ProvisioningSpec        `protobuf:\"bytes,3,opt,name=provisioning,proto3\" json:\"provisioning,omitempty\"`\n\tLocator       *LocatorSpec             `protobuf:\"bytes,4,opt,name=locator,proto3\" json:\"locator,omitempty\"`\n\tMount         *MountSpec               `protobuf:\"bytes,5,opt,name=mount,proto3\" json:\"mount,omitempty\"`\n\tEncryption    *EncryptionSpec          `protobuf:\"bytes,6,opt,name=encryption,proto3\" json:\"encryption,omitempty\"`\n\tSymlink       *SymlinkProvisioningSpec `protobuf:\"bytes,7,opt,name=symlink,proto3\" json:\"symlink,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VolumeConfigSpec) Reset() {\n\t*x = VolumeConfigSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[22]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VolumeConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VolumeConfigSpec) ProtoMessage() {}\n\nfunc (x *VolumeConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[22]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VolumeConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*VolumeConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *VolumeConfigSpec) GetParentId() string {\n\tif x != nil {\n\t\treturn x.ParentId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeConfigSpec) GetType() enums.BlockVolumeType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.BlockVolumeType(0)\n}\n\nfunc (x *VolumeConfigSpec) GetProvisioning() *ProvisioningSpec {\n\tif x != nil {\n\t\treturn x.Provisioning\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeConfigSpec) GetLocator() *LocatorSpec {\n\tif x != nil {\n\t\treturn x.Locator\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeConfigSpec) GetMount() *MountSpec {\n\tif x != nil {\n\t\treturn x.Mount\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeConfigSpec) GetEncryption() *EncryptionSpec {\n\tif x != nil {\n\t\treturn x.Encryption\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeConfigSpec) GetSymlink() *SymlinkProvisioningSpec {\n\tif x != nil {\n\t\treturn x.Symlink\n\t}\n\treturn nil\n}\n\n// VolumeMountRequestSpec is the spec for VolumeMountRequest.\ntype VolumeMountRequestSpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tVolumeId          string                 `protobuf:\"bytes,1,opt,name=volume_id,json=volumeId,proto3\" json:\"volume_id,omitempty\"`\n\tRequester         string                 `protobuf:\"bytes,2,opt,name=requester,proto3\" json:\"requester,omitempty\"`\n\tReadOnly          bool                   `protobuf:\"varint,3,opt,name=read_only,json=readOnly,proto3\" json:\"read_only,omitempty\"`\n\tDetached          bool                   `protobuf:\"varint,4,opt,name=detached,proto3\" json:\"detached,omitempty\"`\n\tDisableAccessTime bool                   `protobuf:\"varint,5,opt,name=disable_access_time,json=disableAccessTime,proto3\" json:\"disable_access_time,omitempty\"`\n\tSecure            bool                   `protobuf:\"varint,6,opt,name=secure,proto3\" json:\"secure,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *VolumeMountRequestSpec) Reset() {\n\t*x = VolumeMountRequestSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[23]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VolumeMountRequestSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VolumeMountRequestSpec) ProtoMessage() {}\n\nfunc (x *VolumeMountRequestSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[23]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VolumeMountRequestSpec.ProtoReflect.Descriptor instead.\nfunc (*VolumeMountRequestSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *VolumeMountRequestSpec) GetVolumeId() string {\n\tif x != nil {\n\t\treturn x.VolumeId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeMountRequestSpec) GetRequester() string {\n\tif x != nil {\n\t\treturn x.Requester\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeMountRequestSpec) GetReadOnly() bool {\n\tif x != nil {\n\t\treturn x.ReadOnly\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountRequestSpec) GetDetached() bool {\n\tif x != nil {\n\t\treturn x.Detached\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountRequestSpec) GetDisableAccessTime() bool {\n\tif x != nil {\n\t\treturn x.DisableAccessTime\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountRequestSpec) GetSecure() bool {\n\tif x != nil {\n\t\treturn x.Secure\n\t}\n\treturn false\n}\n\n// VolumeMountStatusSpec is the spec for VolumeMountStatus.\ntype VolumeMountStatusSpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tVolumeId          string                 `protobuf:\"bytes,1,opt,name=volume_id,json=volumeId,proto3\" json:\"volume_id,omitempty\"`\n\tRequester         string                 `protobuf:\"bytes,2,opt,name=requester,proto3\" json:\"requester,omitempty\"`\n\tTarget            string                 `protobuf:\"bytes,3,opt,name=target,proto3\" json:\"target,omitempty\"`\n\tReadOnly          bool                   `protobuf:\"varint,4,opt,name=read_only,json=readOnly,proto3\" json:\"read_only,omitempty\"`\n\tDetached          bool                   `protobuf:\"varint,5,opt,name=detached,proto3\" json:\"detached,omitempty\"`\n\tDisableAccessTime bool                   `protobuf:\"varint,6,opt,name=disable_access_time,json=disableAccessTime,proto3\" json:\"disable_access_time,omitempty\"`\n\tSecure            bool                   `protobuf:\"varint,7,opt,name=secure,proto3\" json:\"secure,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *VolumeMountStatusSpec) Reset() {\n\t*x = VolumeMountStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[24]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VolumeMountStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VolumeMountStatusSpec) ProtoMessage() {}\n\nfunc (x *VolumeMountStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[24]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VolumeMountStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*VolumeMountStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *VolumeMountStatusSpec) GetVolumeId() string {\n\tif x != nil {\n\t\treturn x.VolumeId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeMountStatusSpec) GetRequester() string {\n\tif x != nil {\n\t\treturn x.Requester\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeMountStatusSpec) GetTarget() string {\n\tif x != nil {\n\t\treturn x.Target\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeMountStatusSpec) GetReadOnly() bool {\n\tif x != nil {\n\t\treturn x.ReadOnly\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountStatusSpec) GetDetached() bool {\n\tif x != nil {\n\t\treturn x.Detached\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountStatusSpec) GetDisableAccessTime() bool {\n\tif x != nil {\n\t\treturn x.DisableAccessTime\n\t}\n\treturn false\n}\n\nfunc (x *VolumeMountStatusSpec) GetSecure() bool {\n\tif x != nil {\n\t\treturn x.Secure\n\t}\n\treturn false\n}\n\n// VolumeStatusSpec is the spec for VolumeStatus resource.\ntype VolumeStatusSpec struct {\n\tstate                    protoimpl.MessageState            `protogen:\"open.v1\"`\n\tPhase                    enums.BlockVolumePhase            `protobuf:\"varint,1,opt,name=phase,proto3,enum=talos.resource.definitions.enums.BlockVolumePhase\" json:\"phase,omitempty\"`\n\tLocation                 string                            `protobuf:\"bytes,2,opt,name=location,proto3\" json:\"location,omitempty\"`\n\tErrorMessage             string                            `protobuf:\"bytes,3,opt,name=error_message,json=errorMessage,proto3\" json:\"error_message,omitempty\"`\n\tUuid                     string                            `protobuf:\"bytes,4,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tPartitionUuid            string                            `protobuf:\"bytes,5,opt,name=partition_uuid,json=partitionUuid,proto3\" json:\"partition_uuid,omitempty\"`\n\tPreFailPhase             enums.BlockVolumePhase            `protobuf:\"varint,6,opt,name=pre_fail_phase,json=preFailPhase,proto3,enum=talos.resource.definitions.enums.BlockVolumePhase\" json:\"pre_fail_phase,omitempty\"`\n\tParentLocation           string                            `protobuf:\"bytes,7,opt,name=parent_location,json=parentLocation,proto3\" json:\"parent_location,omitempty\"`\n\tPartitionIndex           int64                             `protobuf:\"varint,8,opt,name=partition_index,json=partitionIndex,proto3\" json:\"partition_index,omitempty\"`\n\tSize                     uint64                            `protobuf:\"varint,9,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tFilesystem               enums.BlockFilesystemType         `protobuf:\"varint,10,opt,name=filesystem,proto3,enum=talos.resource.definitions.enums.BlockFilesystemType\" json:\"filesystem,omitempty\"`\n\tMountLocation            string                            `protobuf:\"bytes,11,opt,name=mount_location,json=mountLocation,proto3\" json:\"mount_location,omitempty\"`\n\tEncryptionProvider       enums.BlockEncryptionProviderType `protobuf:\"varint,12,opt,name=encryption_provider,json=encryptionProvider,proto3,enum=talos.resource.definitions.enums.BlockEncryptionProviderType\" json:\"encryption_provider,omitempty\"`\n\tPrettySize               string                            `protobuf:\"bytes,13,opt,name=pretty_size,json=prettySize,proto3\" json:\"pretty_size,omitempty\"`\n\tEncryptionFailedSyncs    []string                          `protobuf:\"bytes,14,rep,name=encryption_failed_syncs,json=encryptionFailedSyncs,proto3\" json:\"encryption_failed_syncs,omitempty\"`\n\tMountSpec                *MountSpec                        `protobuf:\"bytes,15,opt,name=mount_spec,json=mountSpec,proto3\" json:\"mount_spec,omitempty\"`\n\tType                     enums.BlockVolumeType             `protobuf:\"varint,16,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockVolumeType\" json:\"type,omitempty\"`\n\tConfiguredEncryptionKeys []string                          `protobuf:\"bytes,17,rep,name=configured_encryption_keys,json=configuredEncryptionKeys,proto3\" json:\"configured_encryption_keys,omitempty\"`\n\tSymlinkSpec              *SymlinkProvisioningSpec          `protobuf:\"bytes,18,opt,name=symlink_spec,json=symlinkSpec,proto3\" json:\"symlink_spec,omitempty\"`\n\tParentId                 string                            `protobuf:\"bytes,19,opt,name=parent_id,json=parentId,proto3\" json:\"parent_id,omitempty\"`\n\tEncryptionLockedToState  bool                              `protobuf:\"varint,20,opt,name=encryption_locked_to_state,json=encryptionLockedToState,proto3\" json:\"encryption_locked_to_state,omitempty\"`\n\tEncryptionSlot           int64                             `protobuf:\"varint,21,opt,name=encryption_slot,json=encryptionSlot,proto3\" json:\"encryption_slot,omitempty\"`\n\tTpmEncryptionOptions     *TPMEncryptionOptionsInfo         `protobuf:\"bytes,22,opt,name=tpm_encryption_options,json=tpmEncryptionOptions,proto3\" json:\"tpm_encryption_options,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *VolumeStatusSpec) Reset() {\n\t*x = VolumeStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[25]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VolumeStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VolumeStatusSpec) ProtoMessage() {}\n\nfunc (x *VolumeStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[25]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VolumeStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*VolumeStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *VolumeStatusSpec) GetPhase() enums.BlockVolumePhase {\n\tif x != nil {\n\t\treturn x.Phase\n\t}\n\treturn enums.BlockVolumePhase(0)\n}\n\nfunc (x *VolumeStatusSpec) GetLocation() string {\n\tif x != nil {\n\t\treturn x.Location\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetErrorMessage() string {\n\tif x != nil {\n\t\treturn x.ErrorMessage\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetPartitionUuid() string {\n\tif x != nil {\n\t\treturn x.PartitionUuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetPreFailPhase() enums.BlockVolumePhase {\n\tif x != nil {\n\t\treturn x.PreFailPhase\n\t}\n\treturn enums.BlockVolumePhase(0)\n}\n\nfunc (x *VolumeStatusSpec) GetParentLocation() string {\n\tif x != nil {\n\t\treturn x.ParentLocation\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetPartitionIndex() int64 {\n\tif x != nil {\n\t\treturn x.PartitionIndex\n\t}\n\treturn 0\n}\n\nfunc (x *VolumeStatusSpec) GetSize() uint64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *VolumeStatusSpec) GetFilesystem() enums.BlockFilesystemType {\n\tif x != nil {\n\t\treturn x.Filesystem\n\t}\n\treturn enums.BlockFilesystemType(0)\n}\n\nfunc (x *VolumeStatusSpec) GetMountLocation() string {\n\tif x != nil {\n\t\treturn x.MountLocation\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetEncryptionProvider() enums.BlockEncryptionProviderType {\n\tif x != nil {\n\t\treturn x.EncryptionProvider\n\t}\n\treturn enums.BlockEncryptionProviderType(0)\n}\n\nfunc (x *VolumeStatusSpec) GetPrettySize() string {\n\tif x != nil {\n\t\treturn x.PrettySize\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetEncryptionFailedSyncs() []string {\n\tif x != nil {\n\t\treturn x.EncryptionFailedSyncs\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeStatusSpec) GetMountSpec() *MountSpec {\n\tif x != nil {\n\t\treturn x.MountSpec\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeStatusSpec) GetType() enums.BlockVolumeType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.BlockVolumeType(0)\n}\n\nfunc (x *VolumeStatusSpec) GetConfiguredEncryptionKeys() []string {\n\tif x != nil {\n\t\treturn x.ConfiguredEncryptionKeys\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeStatusSpec) GetSymlinkSpec() *SymlinkProvisioningSpec {\n\tif x != nil {\n\t\treturn x.SymlinkSpec\n\t}\n\treturn nil\n}\n\nfunc (x *VolumeStatusSpec) GetParentId() string {\n\tif x != nil {\n\t\treturn x.ParentId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VolumeStatusSpec) GetEncryptionLockedToState() bool {\n\tif x != nil {\n\t\treturn x.EncryptionLockedToState\n\t}\n\treturn false\n}\n\nfunc (x *VolumeStatusSpec) GetEncryptionSlot() int64 {\n\tif x != nil {\n\t\treturn x.EncryptionSlot\n\t}\n\treturn 0\n}\n\nfunc (x *VolumeStatusSpec) GetTpmEncryptionOptions() *TPMEncryptionOptionsInfo {\n\tif x != nil {\n\t\treturn x.TpmEncryptionOptions\n\t}\n\treturn nil\n}\n\n// ZswapStatusSpec is the spec for ZswapStatus resource.\ntype ZswapStatusSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tTotalSizeBytes      uint64                 `protobuf:\"varint,1,opt,name=total_size_bytes,json=totalSizeBytes,proto3\" json:\"total_size_bytes,omitempty\"`\n\tTotalSizeHuman      string                 `protobuf:\"bytes,2,opt,name=total_size_human,json=totalSizeHuman,proto3\" json:\"total_size_human,omitempty\"`\n\tStoredPages         uint64                 `protobuf:\"varint,3,opt,name=stored_pages,json=storedPages,proto3\" json:\"stored_pages,omitempty\"`\n\tPoolLimitHit        uint64                 `protobuf:\"varint,4,opt,name=pool_limit_hit,json=poolLimitHit,proto3\" json:\"pool_limit_hit,omitempty\"`\n\tRejectReclaimFail   uint64                 `protobuf:\"varint,5,opt,name=reject_reclaim_fail,json=rejectReclaimFail,proto3\" json:\"reject_reclaim_fail,omitempty\"`\n\tRejectAllocFail     uint64                 `protobuf:\"varint,6,opt,name=reject_alloc_fail,json=rejectAllocFail,proto3\" json:\"reject_alloc_fail,omitempty\"`\n\tRejectKmemcacheFail uint64                 `protobuf:\"varint,7,opt,name=reject_kmemcache_fail,json=rejectKmemcacheFail,proto3\" json:\"reject_kmemcache_fail,omitempty\"`\n\tRejectCompressFail  uint64                 `protobuf:\"varint,8,opt,name=reject_compress_fail,json=rejectCompressFail,proto3\" json:\"reject_compress_fail,omitempty\"`\n\tRejectCompressPoor  uint64                 `protobuf:\"varint,9,opt,name=reject_compress_poor,json=rejectCompressPoor,proto3\" json:\"reject_compress_poor,omitempty\"`\n\tWrittenBackPages    uint64                 `protobuf:\"varint,10,opt,name=written_back_pages,json=writtenBackPages,proto3\" json:\"written_back_pages,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *ZswapStatusSpec) Reset() {\n\t*x = ZswapStatusSpec{}\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[26]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ZswapStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ZswapStatusSpec) ProtoMessage() {}\n\nfunc (x *ZswapStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_block_block_proto_msgTypes[26]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ZswapStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ZswapStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_block_block_proto_rawDescGZIP(), []int{26}\n}\n\nfunc (x *ZswapStatusSpec) GetTotalSizeBytes() uint64 {\n\tif x != nil {\n\t\treturn x.TotalSizeBytes\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetTotalSizeHuman() string {\n\tif x != nil {\n\t\treturn x.TotalSizeHuman\n\t}\n\treturn \"\"\n}\n\nfunc (x *ZswapStatusSpec) GetStoredPages() uint64 {\n\tif x != nil {\n\t\treturn x.StoredPages\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetPoolLimitHit() uint64 {\n\tif x != nil {\n\t\treturn x.PoolLimitHit\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetRejectReclaimFail() uint64 {\n\tif x != nil {\n\t\treturn x.RejectReclaimFail\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetRejectAllocFail() uint64 {\n\tif x != nil {\n\t\treturn x.RejectAllocFail\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetRejectKmemcacheFail() uint64 {\n\tif x != nil {\n\t\treturn x.RejectKmemcacheFail\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetRejectCompressFail() uint64 {\n\tif x != nil {\n\t\treturn x.RejectCompressFail\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetRejectCompressPoor() uint64 {\n\tif x != nil {\n\t\treturn x.RejectCompressPoor\n\t}\n\treturn 0\n}\n\nfunc (x *ZswapStatusSpec) GetWrittenBackPages() uint64 {\n\tif x != nil {\n\t\treturn x.WrittenBackPages\n\t}\n\treturn 0\n}\n\nvar File_resource_definitions_block_block_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_block_block_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"&resource/definitions/block/block.proto\\x12 talos.resource.definitions.block\\x1a&google/api/expr/v1alpha1/checked.proto\\x1a&resource/definitions/enums/enums.proto\\\"\\x99\\x02\\n\" +\n\t\"\\n\" +\n\t\"DeviceSpec\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\tR\\x04type\\x12\\x14\\n\" +\n\t\"\\x05major\\x18\\x02 \\x01(\\x03R\\x05major\\x12\\x14\\n\" +\n\t\"\\x05minor\\x18\\x03 \\x01(\\x03R\\x05minor\\x12%\\n\" +\n\t\"\\x0epartition_name\\x18\\x04 \\x01(\\tR\\rpartitionName\\x12)\\n\" +\n\t\"\\x10partition_number\\x18\\x05 \\x01(\\x03R\\x0fpartitionNumber\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"generation\\x18\\x06 \\x01(\\x03R\\n\" +\n\t\"generation\\x12\\x1f\\n\" +\n\t\"\\vdevice_path\\x18\\a \\x01(\\tR\\n\" +\n\t\"devicePath\\x12\\x16\\n\" +\n\t\"\\x06parent\\x18\\b \\x01(\\tR\\x06parent\\x12 \\n\" +\n\t\"\\vsecondaries\\x18\\t \\x03(\\tR\\vsecondaries\\\"\\xff\\x04\\n\" +\n\t\"\\x14DiscoveredVolumeSpec\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x01 \\x01(\\x04R\\x04size\\x12\\x1f\\n\" +\n\t\"\\vsector_size\\x18\\x02 \\x01(\\x04R\\n\" +\n\t\"sectorSize\\x12\\x17\\n\" +\n\t\"\\aio_size\\x18\\x03 \\x01(\\x04R\\x06ioSize\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x04 \\x01(\\tR\\x04name\\x12\\x12\\n\" +\n\t\"\\x04uuid\\x18\\x05 \\x01(\\tR\\x04uuid\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x06 \\x01(\\tR\\x05label\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"block_size\\x18\\a \\x01(\\rR\\tblockSize\\x122\\n\" +\n\t\"\\x15filesystem_block_size\\x18\\b \\x01(\\rR\\x13filesystemBlockSize\\x12\\x1f\\n\" +\n\t\"\\vprobed_size\\x18\\t \\x01(\\x04R\\n\" +\n\t\"probedSize\\x12%\\n\" +\n\t\"\\x0epartition_uuid\\x18\\n\" +\n\t\" \\x01(\\tR\\rpartitionUuid\\x12%\\n\" +\n\t\"\\x0epartition_type\\x18\\v \\x01(\\tR\\rpartitionType\\x12'\\n\" +\n\t\"\\x0fpartition_label\\x18\\f \\x01(\\tR\\x0epartitionLabel\\x12'\\n\" +\n\t\"\\x0fpartition_index\\x18\\r \\x01(\\x04R\\x0epartitionIndex\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\x0e \\x01(\\tR\\x04type\\x12\\x1f\\n\" +\n\t\"\\vdevice_path\\x18\\x0f \\x01(\\tR\\n\" +\n\t\"devicePath\\x12\\x16\\n\" +\n\t\"\\x06parent\\x18\\x10 \\x01(\\tR\\x06parent\\x12\\x19\\n\" +\n\t\"\\bdev_path\\x18\\x11 \\x01(\\tR\\adevPath\\x12&\\n\" +\n\t\"\\x0fparent_dev_path\\x18\\x12 \\x01(\\tR\\rparentDevPath\\x12\\x1f\\n\" +\n\t\"\\vpretty_size\\x18\\x13 \\x01(\\tR\\n\" +\n\t\"prettySize\\x12\\x16\\n\" +\n\t\"\\x06offset\\x18\\x14 \\x01(\\x04R\\x06offset\\\"7\\n\" +\n\t\"\\x1bDiscoveryRefreshRequestSpec\\x12\\x18\\n\" +\n\t\"\\arequest\\x18\\x01 \\x01(\\x03R\\arequest\\\"6\\n\" +\n\t\"\\x1aDiscoveryRefreshStatusSpec\\x12\\x18\\n\" +\n\t\"\\arequest\\x18\\x01 \\x01(\\x03R\\arequest\\\"g\\n\" +\n\t\"\\fDiskSelector\\x12;\\n\" +\n\t\"\\x05match\\x18\\x01 \\x01(\\v2%.google.api.expr.v1alpha1.CheckedExprR\\x05match\\x12\\x1a\\n\" +\n\t\"\\bexternal\\x18\\x02 \\x01(\\tR\\bexternal\\\"\\xf5\\x03\\n\" +\n\t\"\\bDiskSpec\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x01 \\x01(\\x04R\\x04size\\x12\\x17\\n\" +\n\t\"\\aio_size\\x18\\x02 \\x01(\\x04R\\x06ioSize\\x12\\x1f\\n\" +\n\t\"\\vsector_size\\x18\\x03 \\x01(\\x04R\\n\" +\n\t\"sectorSize\\x12\\x1a\\n\" +\n\t\"\\breadonly\\x18\\x04 \\x01(\\bR\\breadonly\\x12\\x14\\n\" +\n\t\"\\x05model\\x18\\x05 \\x01(\\tR\\x05model\\x12\\x16\\n\" +\n\t\"\\x06serial\\x18\\x06 \\x01(\\tR\\x06serial\\x12\\x1a\\n\" +\n\t\"\\bmodalias\\x18\\a \\x01(\\tR\\bmodalias\\x12\\x12\\n\" +\n\t\"\\x04wwid\\x18\\b \\x01(\\tR\\x04wwid\\x12\\x19\\n\" +\n\t\"\\bbus_path\\x18\\t \\x01(\\tR\\abusPath\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"sub_system\\x18\\n\" +\n\t\" \\x01(\\tR\\tsubSystem\\x12\\x1c\\n\" +\n\t\"\\ttransport\\x18\\v \\x01(\\tR\\ttransport\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"rotational\\x18\\f \\x01(\\bR\\n\" +\n\t\"rotational\\x12\\x14\\n\" +\n\t\"\\x05cdrom\\x18\\r \\x01(\\bR\\x05cdrom\\x12\\x19\\n\" +\n\t\"\\bdev_path\\x18\\x0e \\x01(\\tR\\adevPath\\x12\\x1f\\n\" +\n\t\"\\vpretty_size\\x18\\x0f \\x01(\\tR\\n\" +\n\t\"prettySize\\x12'\\n\" +\n\t\"\\x0fsecondary_disks\\x18\\x10 \\x03(\\tR\\x0esecondaryDisks\\x12\\x12\\n\" +\n\t\"\\x04uuid\\x18\\x11 \\x01(\\tR\\x04uuid\\x12\\x1a\\n\" +\n\t\"\\bsymlinks\\x18\\x12 \\x03(\\tR\\bsymlinks\\\"\\xfb\\x02\\n\" +\n\t\"\\rEncryptionKey\\x12\\x12\\n\" +\n\t\"\\x04slot\\x18\\x01 \\x01(\\x03R\\x04slot\\x12L\\n\" +\n\t\"\\x04type\\x18\\x02 \\x01(\\x0e28.talos.resource.definitions.enums.BlockEncryptionKeyTypeR\\x04type\\x12+\\n\" +\n\t\"\\x11static_passphrase\\x18\\x03 \\x01(\\fR\\x10staticPassphrase\\x12!\\n\" +\n\t\"\\fkms_endpoint\\x18\\x04 \\x01(\\tR\\vkmsEndpoint\\x12O\\n\" +\n\t\"%tpm_check_secureboot_status_on_enroll\\x18\\x05 \\x01(\\bR tpmCheckSecurebootStatusOnEnroll\\x12\\\"\\n\" +\n\t\"\\rlock_to_state\\x18\\x06 \\x01(\\bR\\vlockToState\\x12\\x19\\n\" +\n\t\"\\btpmpc_rs\\x18\\a \\x03(\\x03R\\atpmpcRs\\x12(\\n\" +\n\t\"\\x11tpm_pub_key_pc_rs\\x18\\b \\x03(\\x03R\\rtpmPubKeyPcRs\\\"\\xa5\\x02\\n\" +\n\t\"\\x0eEncryptionSpec\\x12Y\\n\" +\n\t\"\\bprovider\\x18\\x01 \\x01(\\x0e2=.talos.resource.definitions.enums.BlockEncryptionProviderTypeR\\bprovider\\x12C\\n\" +\n\t\"\\x04keys\\x18\\x02 \\x03(\\v2/.talos.resource.definitions.block.EncryptionKeyR\\x04keys\\x12\\x16\\n\" +\n\t\"\\x06cipher\\x18\\x03 \\x01(\\tR\\x06cipher\\x12\\x19\\n\" +\n\t\"\\bkey_size\\x18\\x04 \\x01(\\x04R\\akeySize\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"block_size\\x18\\x05 \\x01(\\x04R\\tblockSize\\x12!\\n\" +\n\t\"\\fperf_options\\x18\\x06 \\x03(\\tR\\vperfOptions\\\"q\\n\" +\n\t\"\\x0eFilesystemSpec\\x12I\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e25.talos.resource.definitions.enums.BlockFilesystemTypeR\\x04type\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x02 \\x01(\\tR\\x05label\\\"\\x90\\x01\\n\" +\n\t\"\\vLocatorSpec\\x12;\\n\" +\n\t\"\\x05match\\x18\\x01 \\x01(\\v2%.google.api.expr.v1alpha1.CheckedExprR\\x05match\\x12D\\n\" +\n\t\"\\n\" +\n\t\"disk_match\\x18\\x02 \\x01(\\v2%.google.api.expr.v1alpha1.CheckedExprR\\tdiskMatch\\\"\\x9e\\x02\\n\" +\n\t\"\\x10MountRequestSpec\\x12\\x1b\\n\" +\n\t\"\\tvolume_id\\x18\\x01 \\x01(\\tR\\bvolumeId\\x12&\\n\" +\n\t\"\\x0fparent_mount_id\\x18\\x02 \\x01(\\tR\\rparentMountId\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"requesters\\x18\\x03 \\x03(\\tR\\n\" +\n\t\"requesters\\x12$\\n\" +\n\t\"\\x0erequester_i_ds\\x18\\x04 \\x03(\\tR\\frequesterIDs\\x12\\x1b\\n\" +\n\t\"\\tread_only\\x18\\x05 \\x01(\\bR\\breadOnly\\x12\\x1a\\n\" +\n\t\"\\bdetached\\x18\\x06 \\x01(\\bR\\bdetached\\x12.\\n\" +\n\t\"\\x13disable_access_time\\x18\\a \\x01(\\bR\\x11disableAccessTime\\x12\\x16\\n\" +\n\t\"\\x06secure\\x18\\b \\x01(\\bR\\x06secure\\\"\\x82\\x03\\n\" +\n\t\"\\tMountSpec\\x12\\x1f\\n\" +\n\t\"\\vtarget_path\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"targetPath\\x12#\\n\" +\n\t\"\\rselinux_label\\x18\\x02 \\x01(\\tR\\fselinuxLabel\\x122\\n\" +\n\t\"\\x15project_quota_support\\x18\\x03 \\x01(\\bR\\x13projectQuotaSupport\\x12\\x1b\\n\" +\n\t\"\\tparent_id\\x18\\x04 \\x01(\\tR\\bparentId\\x12\\x1b\\n\" +\n\t\"\\tfile_mode\\x18\\x05 \\x01(\\rR\\bfileMode\\x12\\x10\\n\" +\n\t\"\\x03uid\\x18\\x06 \\x01(\\x03R\\x03uid\\x12\\x10\\n\" +\n\t\"\\x03gid\\x18\\a \\x01(\\x03R\\x03gid\\x12+\\n\" +\n\t\"\\x11recursive_relabel\\x18\\b \\x01(\\bR\\x10recursiveRelabel\\x12\\x1f\\n\" +\n\t\"\\vbind_target\\x18\\t \\x01(\\tR\\n\" +\n\t\"bindTarget\\x12O\\n\" +\n\t\"\\n\" +\n\t\"parameters\\x18\\n\" +\n\t\" \\x03(\\v2/.talos.resource.definitions.block.ParameterSpecR\\n\" +\n\t\"parameters\\\"\\xbd\\x03\\n\" +\n\t\"\\x0fMountStatusSpec\\x12F\\n\" +\n\t\"\\x04spec\\x18\\x01 \\x01(\\v22.talos.resource.definitions.block.MountRequestSpecR\\x04spec\\x12\\x16\\n\" +\n\t\"\\x06target\\x18\\x02 \\x01(\\tR\\x06target\\x12\\x16\\n\" +\n\t\"\\x06source\\x18\\x03 \\x01(\\tR\\x06source\\x12U\\n\" +\n\t\"\\n\" +\n\t\"filesystem\\x18\\x04 \\x01(\\x0e25.talos.resource.definitions.enums.BlockFilesystemTypeR\\n\" +\n\t\"filesystem\\x12\\x1b\\n\" +\n\t\"\\tread_only\\x18\\x05 \\x01(\\bR\\breadOnly\\x122\\n\" +\n\t\"\\x15project_quota_support\\x18\\x06 \\x01(\\bR\\x13projectQuotaSupport\\x12n\\n\" +\n\t\"\\x13encryption_provider\\x18\\a \\x01(\\x0e2=.talos.resource.definitions.enums.BlockEncryptionProviderTypeR\\x12encryptionProvider\\x12\\x1a\\n\" +\n\t\"\\bdetached\\x18\\b \\x01(\\bR\\bdetached\\\"\\x9f\\x01\\n\" +\n\t\"\\rParameterSpec\\x12J\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e26.talos.resource.definitions.enums.BlockFSParameterTypeR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06string\\x18\\x03 \\x01(\\tR\\x06string\\x12\\x16\\n\" +\n\t\"\\x06binary\\x18\\x05 \\x01(\\fR\\x06binary\\\"\\xe4\\x01\\n\" +\n\t\"\\rPartitionSpec\\x12\\x19\\n\" +\n\t\"\\bmin_size\\x18\\x01 \\x01(\\x04R\\aminSize\\x12\\x19\\n\" +\n\t\"\\bmax_size\\x18\\x02 \\x01(\\x04R\\amaxSize\\x12\\x12\\n\" +\n\t\"\\x04grow\\x18\\x03 \\x01(\\bR\\x04grow\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x04 \\x01(\\tR\\x05label\\x12\\x1b\\n\" +\n\t\"\\ttype_uuid\\x18\\x05 \\x01(\\tR\\btypeUuid\\x12*\\n\" +\n\t\"\\x11relative_max_size\\x18\\x06 \\x01(\\x04R\\x0frelativeMaxSize\\x12*\\n\" +\n\t\"\\x11negative_max_size\\x18\\a \\x01(\\bR\\x0fnegativeMaxSize\\\"\\xae\\x02\\n\" +\n\t\"\\x10ProvisioningSpec\\x12S\\n\" +\n\t\"\\rdisk_selector\\x18\\x01 \\x01(\\v2..talos.resource.definitions.block.DiskSelectorR\\fdiskSelector\\x12V\\n\" +\n\t\"\\x0epartition_spec\\x18\\x02 \\x01(\\v2/.talos.resource.definitions.block.PartitionSpecR\\rpartitionSpec\\x12\\x12\\n\" +\n\t\"\\x04wave\\x18\\x03 \\x01(\\x03R\\x04wave\\x12Y\\n\" +\n\t\"\\x0ffilesystem_spec\\x18\\x04 \\x01(\\v20.talos.resource.definitions.block.FilesystemSpecR\\x0efilesystemSpec\\\"\\xd4\\x01\\n\" +\n\t\"\\x0eSwapStatusSpec\\x12\\x16\\n\" +\n\t\"\\x06device\\x18\\x01 \\x01(\\tR\\x06device\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"size_bytes\\x18\\x02 \\x01(\\x04R\\tsizeBytes\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"size_human\\x18\\x03 \\x01(\\tR\\tsizeHuman\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"used_bytes\\x18\\x04 \\x01(\\x04R\\tusedBytes\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"used_human\\x18\\x05 \\x01(\\tR\\tusedHuman\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\x06 \\x01(\\x05R\\bpriority\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\a \\x01(\\tR\\x04type\\\"_\\n\" +\n\t\"\\x17SymlinkProvisioningSpec\\x12.\\n\" +\n\t\"\\x13symlink_target_path\\x18\\x01 \\x01(\\tR\\x11symlinkTargetPath\\x12\\x14\\n\" +\n\t\"\\x05force\\x18\\x02 \\x01(\\bR\\x05force\\\"#\\n\" +\n\t\"\\vSymlinkSpec\\x12\\x14\\n\" +\n\t\"\\x05paths\\x18\\x01 \\x03(\\tR\\x05paths\\\"D\\n\" +\n\t\"\\x0eSystemDiskSpec\\x12\\x17\\n\" +\n\t\"\\adisk_id\\x18\\x01 \\x01(\\tR\\x06diskId\\x12\\x19\\n\" +\n\t\"\\bdev_path\\x18\\x02 \\x01(\\tR\\adevPath\\\"R\\n\" +\n\t\"\\x18TPMEncryptionOptionsInfo\\x12\\x13\\n\" +\n\t\"\\x05pc_rs\\x18\\x01 \\x03(\\x03R\\x04pcRs\\x12!\\n\" +\n\t\"\\rpub_key_pc_rs\\x18\\x02 \\x03(\\x03R\\n\" +\n\t\"pubKeyPcRs\\\"M\\n\" +\n\t\"\\x18UserDiskConfigStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12\\x1b\\n\" +\n\t\"\\ttorn_down\\x18\\x02 \\x01(\\bR\\btornDown\\\"\\x81\\x04\\n\" +\n\t\"\\x10VolumeConfigSpec\\x12\\x1b\\n\" +\n\t\"\\tparent_id\\x18\\x01 \\x01(\\tR\\bparentId\\x12E\\n\" +\n\t\"\\x04type\\x18\\x02 \\x01(\\x0e21.talos.resource.definitions.enums.BlockVolumeTypeR\\x04type\\x12V\\n\" +\n\t\"\\fprovisioning\\x18\\x03 \\x01(\\v22.talos.resource.definitions.block.ProvisioningSpecR\\fprovisioning\\x12G\\n\" +\n\t\"\\alocator\\x18\\x04 \\x01(\\v2-.talos.resource.definitions.block.LocatorSpecR\\alocator\\x12A\\n\" +\n\t\"\\x05mount\\x18\\x05 \\x01(\\v2+.talos.resource.definitions.block.MountSpecR\\x05mount\\x12P\\n\" +\n\t\"\\n\" +\n\t\"encryption\\x18\\x06 \\x01(\\v20.talos.resource.definitions.block.EncryptionSpecR\\n\" +\n\t\"encryption\\x12S\\n\" +\n\t\"\\asymlink\\x18\\a \\x01(\\v29.talos.resource.definitions.block.SymlinkProvisioningSpecR\\asymlink\\\"\\xd4\\x01\\n\" +\n\t\"\\x16VolumeMountRequestSpec\\x12\\x1b\\n\" +\n\t\"\\tvolume_id\\x18\\x01 \\x01(\\tR\\bvolumeId\\x12\\x1c\\n\" +\n\t\"\\trequester\\x18\\x02 \\x01(\\tR\\trequester\\x12\\x1b\\n\" +\n\t\"\\tread_only\\x18\\x03 \\x01(\\bR\\breadOnly\\x12\\x1a\\n\" +\n\t\"\\bdetached\\x18\\x04 \\x01(\\bR\\bdetached\\x12.\\n\" +\n\t\"\\x13disable_access_time\\x18\\x05 \\x01(\\bR\\x11disableAccessTime\\x12\\x16\\n\" +\n\t\"\\x06secure\\x18\\x06 \\x01(\\bR\\x06secure\\\"\\xeb\\x01\\n\" +\n\t\"\\x15VolumeMountStatusSpec\\x12\\x1b\\n\" +\n\t\"\\tvolume_id\\x18\\x01 \\x01(\\tR\\bvolumeId\\x12\\x1c\\n\" +\n\t\"\\trequester\\x18\\x02 \\x01(\\tR\\trequester\\x12\\x16\\n\" +\n\t\"\\x06target\\x18\\x03 \\x01(\\tR\\x06target\\x12\\x1b\\n\" +\n\t\"\\tread_only\\x18\\x04 \\x01(\\bR\\breadOnly\\x12\\x1a\\n\" +\n\t\"\\bdetached\\x18\\x05 \\x01(\\bR\\bdetached\\x12.\\n\" +\n\t\"\\x13disable_access_time\\x18\\x06 \\x01(\\bR\\x11disableAccessTime\\x12\\x16\\n\" +\n\t\"\\x06secure\\x18\\a \\x01(\\bR\\x06secure\\\"\\x83\\n\" +\n\t\"\\n\" +\n\t\"\\x10VolumeStatusSpec\\x12H\\n\" +\n\t\"\\x05phase\\x18\\x01 \\x01(\\x0e22.talos.resource.definitions.enums.BlockVolumePhaseR\\x05phase\\x12\\x1a\\n\" +\n\t\"\\blocation\\x18\\x02 \\x01(\\tR\\blocation\\x12#\\n\" +\n\t\"\\rerror_message\\x18\\x03 \\x01(\\tR\\ferrorMessage\\x12\\x12\\n\" +\n\t\"\\x04uuid\\x18\\x04 \\x01(\\tR\\x04uuid\\x12%\\n\" +\n\t\"\\x0epartition_uuid\\x18\\x05 \\x01(\\tR\\rpartitionUuid\\x12X\\n\" +\n\t\"\\x0epre_fail_phase\\x18\\x06 \\x01(\\x0e22.talos.resource.definitions.enums.BlockVolumePhaseR\\fpreFailPhase\\x12'\\n\" +\n\t\"\\x0fparent_location\\x18\\a \\x01(\\tR\\x0eparentLocation\\x12'\\n\" +\n\t\"\\x0fpartition_index\\x18\\b \\x01(\\x03R\\x0epartitionIndex\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\t \\x01(\\x04R\\x04size\\x12U\\n\" +\n\t\"\\n\" +\n\t\"filesystem\\x18\\n\" +\n\t\" \\x01(\\x0e25.talos.resource.definitions.enums.BlockFilesystemTypeR\\n\" +\n\t\"filesystem\\x12%\\n\" +\n\t\"\\x0emount_location\\x18\\v \\x01(\\tR\\rmountLocation\\x12n\\n\" +\n\t\"\\x13encryption_provider\\x18\\f \\x01(\\x0e2=.talos.resource.definitions.enums.BlockEncryptionProviderTypeR\\x12encryptionProvider\\x12\\x1f\\n\" +\n\t\"\\vpretty_size\\x18\\r \\x01(\\tR\\n\" +\n\t\"prettySize\\x126\\n\" +\n\t\"\\x17encryption_failed_syncs\\x18\\x0e \\x03(\\tR\\x15encryptionFailedSyncs\\x12J\\n\" +\n\t\"\\n\" +\n\t\"mount_spec\\x18\\x0f \\x01(\\v2+.talos.resource.definitions.block.MountSpecR\\tmountSpec\\x12E\\n\" +\n\t\"\\x04type\\x18\\x10 \\x01(\\x0e21.talos.resource.definitions.enums.BlockVolumeTypeR\\x04type\\x12<\\n\" +\n\t\"\\x1aconfigured_encryption_keys\\x18\\x11 \\x03(\\tR\\x18configuredEncryptionKeys\\x12\\\\\\n\" +\n\t\"\\fsymlink_spec\\x18\\x12 \\x01(\\v29.talos.resource.definitions.block.SymlinkProvisioningSpecR\\vsymlinkSpec\\x12\\x1b\\n\" +\n\t\"\\tparent_id\\x18\\x13 \\x01(\\tR\\bparentId\\x12;\\n\" +\n\t\"\\x1aencryption_locked_to_state\\x18\\x14 \\x01(\\bR\\x17encryptionLockedToState\\x12'\\n\" +\n\t\"\\x0fencryption_slot\\x18\\x15 \\x01(\\x03R\\x0eencryptionSlot\\x12p\\n\" +\n\t\"\\x16tpm_encryption_options\\x18\\x16 \\x01(\\v2:.talos.resource.definitions.block.TPMEncryptionOptionsInfoR\\x14tpmEncryptionOptions\\\"\\xd0\\x03\\n\" +\n\t\"\\x0fZswapStatusSpec\\x12(\\n\" +\n\t\"\\x10total_size_bytes\\x18\\x01 \\x01(\\x04R\\x0etotalSizeBytes\\x12(\\n\" +\n\t\"\\x10total_size_human\\x18\\x02 \\x01(\\tR\\x0etotalSizeHuman\\x12!\\n\" +\n\t\"\\fstored_pages\\x18\\x03 \\x01(\\x04R\\vstoredPages\\x12$\\n\" +\n\t\"\\x0epool_limit_hit\\x18\\x04 \\x01(\\x04R\\fpoolLimitHit\\x12.\\n\" +\n\t\"\\x13reject_reclaim_fail\\x18\\x05 \\x01(\\x04R\\x11rejectReclaimFail\\x12*\\n\" +\n\t\"\\x11reject_alloc_fail\\x18\\x06 \\x01(\\x04R\\x0frejectAllocFail\\x122\\n\" +\n\t\"\\x15reject_kmemcache_fail\\x18\\a \\x01(\\x04R\\x13rejectKmemcacheFail\\x120\\n\" +\n\t\"\\x14reject_compress_fail\\x18\\b \\x01(\\x04R\\x12rejectCompressFail\\x120\\n\" +\n\t\"\\x14reject_compress_poor\\x18\\t \\x01(\\x04R\\x12rejectCompressPoor\\x12,\\n\" +\n\t\"\\x12written_back_pages\\x18\\n\" +\n\t\" \\x01(\\x04R\\x10writtenBackPagesBt\\n\" +\n\t\"(dev.talos.api.resource.definitions.blockZHgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/blockb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_block_block_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_block_block_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_block_block_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_block_block_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_block_block_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_block_block_proto_rawDesc), len(file_resource_definitions_block_block_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_block_block_proto_rawDescData\n}\n\nvar file_resource_definitions_block_block_proto_msgTypes = make([]protoimpl.MessageInfo, 27)\nvar file_resource_definitions_block_block_proto_goTypes = []any{\n\t(*DeviceSpec)(nil),                     // 0: talos.resource.definitions.block.DeviceSpec\n\t(*DiscoveredVolumeSpec)(nil),           // 1: talos.resource.definitions.block.DiscoveredVolumeSpec\n\t(*DiscoveryRefreshRequestSpec)(nil),    // 2: talos.resource.definitions.block.DiscoveryRefreshRequestSpec\n\t(*DiscoveryRefreshStatusSpec)(nil),     // 3: talos.resource.definitions.block.DiscoveryRefreshStatusSpec\n\t(*DiskSelector)(nil),                   // 4: talos.resource.definitions.block.DiskSelector\n\t(*DiskSpec)(nil),                       // 5: talos.resource.definitions.block.DiskSpec\n\t(*EncryptionKey)(nil),                  // 6: talos.resource.definitions.block.EncryptionKey\n\t(*EncryptionSpec)(nil),                 // 7: talos.resource.definitions.block.EncryptionSpec\n\t(*FilesystemSpec)(nil),                 // 8: talos.resource.definitions.block.FilesystemSpec\n\t(*LocatorSpec)(nil),                    // 9: talos.resource.definitions.block.LocatorSpec\n\t(*MountRequestSpec)(nil),               // 10: talos.resource.definitions.block.MountRequestSpec\n\t(*MountSpec)(nil),                      // 11: talos.resource.definitions.block.MountSpec\n\t(*MountStatusSpec)(nil),                // 12: talos.resource.definitions.block.MountStatusSpec\n\t(*ParameterSpec)(nil),                  // 13: talos.resource.definitions.block.ParameterSpec\n\t(*PartitionSpec)(nil),                  // 14: talos.resource.definitions.block.PartitionSpec\n\t(*ProvisioningSpec)(nil),               // 15: talos.resource.definitions.block.ProvisioningSpec\n\t(*SwapStatusSpec)(nil),                 // 16: talos.resource.definitions.block.SwapStatusSpec\n\t(*SymlinkProvisioningSpec)(nil),        // 17: talos.resource.definitions.block.SymlinkProvisioningSpec\n\t(*SymlinkSpec)(nil),                    // 18: talos.resource.definitions.block.SymlinkSpec\n\t(*SystemDiskSpec)(nil),                 // 19: talos.resource.definitions.block.SystemDiskSpec\n\t(*TPMEncryptionOptionsInfo)(nil),       // 20: talos.resource.definitions.block.TPMEncryptionOptionsInfo\n\t(*UserDiskConfigStatusSpec)(nil),       // 21: talos.resource.definitions.block.UserDiskConfigStatusSpec\n\t(*VolumeConfigSpec)(nil),               // 22: talos.resource.definitions.block.VolumeConfigSpec\n\t(*VolumeMountRequestSpec)(nil),         // 23: talos.resource.definitions.block.VolumeMountRequestSpec\n\t(*VolumeMountStatusSpec)(nil),          // 24: talos.resource.definitions.block.VolumeMountStatusSpec\n\t(*VolumeStatusSpec)(nil),               // 25: talos.resource.definitions.block.VolumeStatusSpec\n\t(*ZswapStatusSpec)(nil),                // 26: talos.resource.definitions.block.ZswapStatusSpec\n\t(*v1alpha1.CheckedExpr)(nil),           // 27: google.api.expr.v1alpha1.CheckedExpr\n\t(enums.BlockEncryptionKeyType)(0),      // 28: talos.resource.definitions.enums.BlockEncryptionKeyType\n\t(enums.BlockEncryptionProviderType)(0), // 29: talos.resource.definitions.enums.BlockEncryptionProviderType\n\t(enums.BlockFilesystemType)(0),         // 30: talos.resource.definitions.enums.BlockFilesystemType\n\t(enums.BlockFSParameterType)(0),        // 31: talos.resource.definitions.enums.BlockFSParameterType\n\t(enums.BlockVolumeType)(0),             // 32: talos.resource.definitions.enums.BlockVolumeType\n\t(enums.BlockVolumePhase)(0),            // 33: talos.resource.definitions.enums.BlockVolumePhase\n}\nvar file_resource_definitions_block_block_proto_depIdxs = []int32{\n\t27, // 0: talos.resource.definitions.block.DiskSelector.match:type_name -> google.api.expr.v1alpha1.CheckedExpr\n\t28, // 1: talos.resource.definitions.block.EncryptionKey.type:type_name -> talos.resource.definitions.enums.BlockEncryptionKeyType\n\t29, // 2: talos.resource.definitions.block.EncryptionSpec.provider:type_name -> talos.resource.definitions.enums.BlockEncryptionProviderType\n\t6,  // 3: talos.resource.definitions.block.EncryptionSpec.keys:type_name -> talos.resource.definitions.block.EncryptionKey\n\t30, // 4: talos.resource.definitions.block.FilesystemSpec.type:type_name -> talos.resource.definitions.enums.BlockFilesystemType\n\t27, // 5: talos.resource.definitions.block.LocatorSpec.match:type_name -> google.api.expr.v1alpha1.CheckedExpr\n\t27, // 6: talos.resource.definitions.block.LocatorSpec.disk_match:type_name -> google.api.expr.v1alpha1.CheckedExpr\n\t13, // 7: talos.resource.definitions.block.MountSpec.parameters:type_name -> talos.resource.definitions.block.ParameterSpec\n\t10, // 8: talos.resource.definitions.block.MountStatusSpec.spec:type_name -> talos.resource.definitions.block.MountRequestSpec\n\t30, // 9: talos.resource.definitions.block.MountStatusSpec.filesystem:type_name -> talos.resource.definitions.enums.BlockFilesystemType\n\t29, // 10: talos.resource.definitions.block.MountStatusSpec.encryption_provider:type_name -> talos.resource.definitions.enums.BlockEncryptionProviderType\n\t31, // 11: talos.resource.definitions.block.ParameterSpec.type:type_name -> talos.resource.definitions.enums.BlockFSParameterType\n\t4,  // 12: talos.resource.definitions.block.ProvisioningSpec.disk_selector:type_name -> talos.resource.definitions.block.DiskSelector\n\t14, // 13: talos.resource.definitions.block.ProvisioningSpec.partition_spec:type_name -> talos.resource.definitions.block.PartitionSpec\n\t8,  // 14: talos.resource.definitions.block.ProvisioningSpec.filesystem_spec:type_name -> talos.resource.definitions.block.FilesystemSpec\n\t32, // 15: talos.resource.definitions.block.VolumeConfigSpec.type:type_name -> talos.resource.definitions.enums.BlockVolumeType\n\t15, // 16: talos.resource.definitions.block.VolumeConfigSpec.provisioning:type_name -> talos.resource.definitions.block.ProvisioningSpec\n\t9,  // 17: talos.resource.definitions.block.VolumeConfigSpec.locator:type_name -> talos.resource.definitions.block.LocatorSpec\n\t11, // 18: talos.resource.definitions.block.VolumeConfigSpec.mount:type_name -> talos.resource.definitions.block.MountSpec\n\t7,  // 19: talos.resource.definitions.block.VolumeConfigSpec.encryption:type_name -> talos.resource.definitions.block.EncryptionSpec\n\t17, // 20: talos.resource.definitions.block.VolumeConfigSpec.symlink:type_name -> talos.resource.definitions.block.SymlinkProvisioningSpec\n\t33, // 21: talos.resource.definitions.block.VolumeStatusSpec.phase:type_name -> talos.resource.definitions.enums.BlockVolumePhase\n\t33, // 22: talos.resource.definitions.block.VolumeStatusSpec.pre_fail_phase:type_name -> talos.resource.definitions.enums.BlockVolumePhase\n\t30, // 23: talos.resource.definitions.block.VolumeStatusSpec.filesystem:type_name -> talos.resource.definitions.enums.BlockFilesystemType\n\t29, // 24: talos.resource.definitions.block.VolumeStatusSpec.encryption_provider:type_name -> talos.resource.definitions.enums.BlockEncryptionProviderType\n\t11, // 25: talos.resource.definitions.block.VolumeStatusSpec.mount_spec:type_name -> talos.resource.definitions.block.MountSpec\n\t32, // 26: talos.resource.definitions.block.VolumeStatusSpec.type:type_name -> talos.resource.definitions.enums.BlockVolumeType\n\t17, // 27: talos.resource.definitions.block.VolumeStatusSpec.symlink_spec:type_name -> talos.resource.definitions.block.SymlinkProvisioningSpec\n\t20, // 28: talos.resource.definitions.block.VolumeStatusSpec.tpm_encryption_options:type_name -> talos.resource.definitions.block.TPMEncryptionOptionsInfo\n\t29, // [29:29] is the sub-list for method output_type\n\t29, // [29:29] is the sub-list for method input_type\n\t29, // [29:29] is the sub-list for extension type_name\n\t29, // [29:29] is the sub-list for extension extendee\n\t0,  // [0:29] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_block_block_proto_init() }\nfunc file_resource_definitions_block_block_proto_init() {\n\tif File_resource_definitions_block_block_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_block_block_proto_rawDesc), len(file_resource_definitions_block_block_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   27,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_block_block_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_block_block_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_block_block_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_block_block_proto = out.File\n\tfile_resource_definitions_block_block_proto_goTypes = nil\n\tfile_resource_definitions_block_block_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/block/block.proto\n\npackage block\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tv1alpha1 \"google.golang.org/genproto/googleapis/api/expr/v1alpha1\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *DeviceSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DeviceSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DeviceSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Secondaries) > 0 {\n\t\tfor iNdEx := len(m.Secondaries) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Secondaries[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Secondaries[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Secondaries[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x4a\n\t\t}\n\t}\n\tif len(m.Parent) > 0 {\n\t\ti -= len(m.Parent)\n\t\tcopy(dAtA[i:], m.Parent)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Parent)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.DevicePath) > 0 {\n\t\ti -= len(m.DevicePath)\n\t\tcopy(dAtA[i:], m.DevicePath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevicePath)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Generation != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.PartitionNumber != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PartitionNumber))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.PartitionName) > 0 {\n\t\ti -= len(m.PartitionName)\n\t\tcopy(dAtA[i:], m.PartitionName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionName)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Minor != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Minor))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Major != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Major))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiscoveredVolumeSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiscoveredVolumeSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiscoveredVolumeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Offset != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Offset))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif len(m.PrettySize) > 0 {\n\t\ti -= len(m.PrettySize)\n\t\tcopy(dAtA[i:], m.PrettySize)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrettySize)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x9a\n\t}\n\tif len(m.ParentDevPath) > 0 {\n\t\ti -= len(m.ParentDevPath)\n\t\tcopy(dAtA[i:], m.ParentDevPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentDevPath)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif len(m.DevPath) > 0 {\n\t\ti -= len(m.DevPath)\n\t\tcopy(dAtA[i:], m.DevPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevPath)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.Parent) > 0 {\n\t\ti -= len(m.Parent)\n\t\tcopy(dAtA[i:], m.Parent)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Parent)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x82\n\t}\n\tif len(m.DevicePath) > 0 {\n\t\ti -= len(m.DevicePath)\n\t\tcopy(dAtA[i:], m.DevicePath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevicePath)))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0x72\n\t}\n\tif m.PartitionIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PartitionIndex))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif len(m.PartitionLabel) > 0 {\n\t\ti -= len(m.PartitionLabel)\n\t\tcopy(dAtA[i:], m.PartitionLabel)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionLabel)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif len(m.PartitionType) > 0 {\n\t\ti -= len(m.PartitionType)\n\t\tcopy(dAtA[i:], m.PartitionType)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionType)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif len(m.PartitionUuid) > 0 {\n\t\ti -= len(m.PartitionUuid)\n\t\tcopy(dAtA[i:], m.PartitionUuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionUuid)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.ProbedSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProbedSize))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.FilesystemBlockSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FilesystemBlockSize))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.BlockSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.BlockSize))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Uuid) > 0 {\n\t\ti -= len(m.Uuid)\n\t\tcopy(dAtA[i:], m.Uuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.IoSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoSize))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.SectorSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SectorSize))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiscoveryRefreshRequestSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiscoveryRefreshRequestSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiscoveryRefreshRequestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Request != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Request))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiscoveryRefreshStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiscoveryRefreshStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiscoveryRefreshStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Request != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Request))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskSelector) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskSelector) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskSelector) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.External) > 0 {\n\t\ti -= len(m.External)\n\t\tcopy(dAtA[i:], m.External)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.External)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Match != nil {\n\t\tif vtmsg, ok := interface{}(m.Match).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Match)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiskSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiskSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Symlinks) > 0 {\n\t\tfor iNdEx := len(m.Symlinks) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Symlinks[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Symlinks[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Symlinks[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0x92\n\t\t}\n\t}\n\tif len(m.Uuid) > 0 {\n\t\ti -= len(m.Uuid)\n\t\tcopy(dAtA[i:], m.Uuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.SecondaryDisks) > 0 {\n\t\tfor iNdEx := len(m.SecondaryDisks) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.SecondaryDisks[iNdEx])\n\t\t\tcopy(dAtA[i:], m.SecondaryDisks[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SecondaryDisks[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0x82\n\t\t}\n\t}\n\tif len(m.PrettySize) > 0 {\n\t\ti -= len(m.PrettySize)\n\t\tcopy(dAtA[i:], m.PrettySize)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrettySize)))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif len(m.DevPath) > 0 {\n\t\ti -= len(m.DevPath)\n\t\tcopy(dAtA[i:], m.DevPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevPath)))\n\t\ti--\n\t\tdAtA[i] = 0x72\n\t}\n\tif m.Cdrom {\n\t\ti--\n\t\tif m.Cdrom {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.Rotational {\n\t\ti--\n\t\tif m.Rotational {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif len(m.Transport) > 0 {\n\t\ti -= len(m.Transport)\n\t\tcopy(dAtA[i:], m.Transport)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Transport)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif len(m.SubSystem) > 0 {\n\t\ti -= len(m.SubSystem)\n\t\tcopy(dAtA[i:], m.SubSystem)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SubSystem)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.BusPath) > 0 {\n\t\ti -= len(m.BusPath)\n\t\tcopy(dAtA[i:], m.BusPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BusPath)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.Wwid) > 0 {\n\t\ti -= len(m.Wwid)\n\t\tcopy(dAtA[i:], m.Wwid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Wwid)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.Modalias) > 0 {\n\t\ti -= len(m.Modalias)\n\t\tcopy(dAtA[i:], m.Modalias)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Modalias)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.Serial) > 0 {\n\t\ti -= len(m.Serial)\n\t\tcopy(dAtA[i:], m.Serial)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Serial)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Model) > 0 {\n\t\ti -= len(m.Model)\n\t\tcopy(dAtA[i:], m.Model)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Model)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Readonly {\n\t\ti--\n\t\tif m.Readonly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.SectorSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SectorSize))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.IoSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IoSize))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EncryptionKey) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EncryptionKey) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EncryptionKey) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.TpmPubKeyPcRs) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.TpmPubKeyPcRs {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.TpmPubKeyPcRs {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.TpmpcRs) > 0 {\n\t\tvar pksize4 int\n\t\tfor _, num := range m.TpmpcRs {\n\t\t\tpksize4 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize4\n\t\tj3 := i\n\t\tfor _, num1 := range m.TpmpcRs {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j3] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj3++\n\t\t\t}\n\t\t\tdAtA[j3] = uint8(num)\n\t\t\tj3++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.LockToState {\n\t\ti--\n\t\tif m.LockToState {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.TpmCheckSecurebootStatusOnEnroll {\n\t\ti--\n\t\tif m.TpmCheckSecurebootStatusOnEnroll {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.KmsEndpoint) > 0 {\n\t\ti -= len(m.KmsEndpoint)\n\t\tcopy(dAtA[i:], m.KmsEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.KmsEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.StaticPassphrase) > 0 {\n\t\ti -= len(m.StaticPassphrase)\n\t\tcopy(dAtA[i:], m.StaticPassphrase)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StaticPassphrase)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Slot != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Slot))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EncryptionSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EncryptionSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EncryptionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.PerfOptions) > 0 {\n\t\tfor iNdEx := len(m.PerfOptions) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PerfOptions[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PerfOptions[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PerfOptions[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif m.BlockSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.BlockSize))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.KeySize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.KeySize))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Cipher) > 0 {\n\t\ti -= len(m.Cipher)\n\t\tcopy(dAtA[i:], m.Cipher)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Cipher)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Keys) > 0 {\n\t\tfor iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Keys[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Provider != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Provider))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *FilesystemSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *FilesystemSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *FilesystemSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LocatorSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LocatorSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LocatorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.DiskMatch != nil {\n\t\tif vtmsg, ok := interface{}(m.DiskMatch).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.DiskMatch)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Match != nil {\n\t\tif vtmsg, ok := interface{}(m.Match).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Match)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountRequestSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountRequestSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountRequestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Secure {\n\t\ti--\n\t\tif m.Secure {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.DisableAccessTime {\n\t\ti--\n\t\tif m.DisableAccessTime {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Detached {\n\t\ti--\n\t\tif m.Detached {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.ReadOnly {\n\t\ti--\n\t\tif m.ReadOnly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.RequesterIDs) > 0 {\n\t\tfor iNdEx := len(m.RequesterIDs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.RequesterIDs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.RequesterIDs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RequesterIDs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Requesters) > 0 {\n\t\tfor iNdEx := len(m.Requesters) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Requesters[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Requesters[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Requesters[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.ParentMountId) > 0 {\n\t\ti -= len(m.ParentMountId)\n\t\tcopy(dAtA[i:], m.ParentMountId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentMountId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.VolumeId) > 0 {\n\t\ti -= len(m.VolumeId)\n\t\tcopy(dAtA[i:], m.VolumeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VolumeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Parameters) > 0 {\n\t\tfor iNdEx := len(m.Parameters) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Parameters[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x52\n\t\t}\n\t}\n\tif len(m.BindTarget) > 0 {\n\t\ti -= len(m.BindTarget)\n\t\tcopy(dAtA[i:], m.BindTarget)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BindTarget)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.RecursiveRelabel {\n\t\ti--\n\t\tif m.RecursiveRelabel {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Gid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Gid))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Uid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Uid))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.FileMode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FileMode))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.ParentId) > 0 {\n\t\ti -= len(m.ParentId)\n\t\tcopy(dAtA[i:], m.ParentId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentId)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.ProjectQuotaSupport {\n\t\ti--\n\t\tif m.ProjectQuotaSupport {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.SelinuxLabel) > 0 {\n\t\ti -= len(m.SelinuxLabel)\n\t\tcopy(dAtA[i:], m.SelinuxLabel)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SelinuxLabel)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.TargetPath) > 0 {\n\t\ti -= len(m.TargetPath)\n\t\tcopy(dAtA[i:], m.TargetPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TargetPath)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Detached {\n\t\ti--\n\t\tif m.Detached {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.EncryptionProvider != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.EncryptionProvider))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.ProjectQuotaSupport {\n\t\ti--\n\t\tif m.ProjectQuotaSupport {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.ReadOnly {\n\t\ti--\n\t\tif m.ReadOnly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Filesystem != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Filesystem))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Source) > 0 {\n\t\ti -= len(m.Source)\n\t\tcopy(dAtA[i:], m.Source)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Source)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Target) > 0 {\n\t\ti -= len(m.Target)\n\t\tcopy(dAtA[i:], m.Target)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Target)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Spec != nil {\n\t\tsize, err := m.Spec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ParameterSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ParameterSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ParameterSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Binary) > 0 {\n\t\ti -= len(m.Binary)\n\t\tcopy(dAtA[i:], m.Binary)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Binary)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.String_) > 0 {\n\t\ti -= len(m.String_)\n\t\tcopy(dAtA[i:], m.String_)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.String_)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PartitionSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PartitionSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PartitionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.NegativeMaxSize {\n\t\ti--\n\t\tif m.NegativeMaxSize {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.RelativeMaxSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RelativeMaxSize))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.TypeUuid) > 0 {\n\t\ti -= len(m.TypeUuid)\n\t\tcopy(dAtA[i:], m.TypeUuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TypeUuid)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Grow {\n\t\ti--\n\t\tif m.Grow {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.MaxSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxSize))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.MinSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinSize))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProvisioningSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProvisioningSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProvisioningSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.FilesystemSpec != nil {\n\t\tsize, err := m.FilesystemSpec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Wave != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Wave))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.PartitionSpec != nil {\n\t\tsize, err := m.PartitionSpec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.DiskSelector != nil {\n\t\tsize, err := m.DiskSelector.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SwapStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SwapStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SwapStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.UsedHuman) > 0 {\n\t\ti -= len(m.UsedHuman)\n\t\tcopy(dAtA[i:], m.UsedHuman)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.UsedHuman)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.UsedBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.UsedBytes))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.SizeHuman) > 0 {\n\t\ti -= len(m.SizeHuman)\n\t\tcopy(dAtA[i:], m.SizeHuman)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SizeHuman)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.SizeBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SizeBytes))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Device) > 0 {\n\t\ti -= len(m.Device)\n\t\tcopy(dAtA[i:], m.Device)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Device)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SymlinkProvisioningSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SymlinkProvisioningSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SymlinkProvisioningSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Force {\n\t\ti--\n\t\tif m.Force {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.SymlinkTargetPath) > 0 {\n\t\ti -= len(m.SymlinkTargetPath)\n\t\tcopy(dAtA[i:], m.SymlinkTargetPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SymlinkTargetPath)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SymlinkSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SymlinkSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SymlinkSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Paths) > 0 {\n\t\tfor iNdEx := len(m.Paths) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Paths[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Paths[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Paths[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SystemDiskSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SystemDiskSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SystemDiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.DevPath) > 0 {\n\t\ti -= len(m.DevPath)\n\t\tcopy(dAtA[i:], m.DevPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevPath)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.DiskId) > 0 {\n\t\ti -= len(m.DiskId)\n\t\tcopy(dAtA[i:], m.DiskId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TPMEncryptionOptionsInfo) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TPMEncryptionOptionsInfo) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TPMEncryptionOptionsInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.PubKeyPcRs) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.PubKeyPcRs {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.PubKeyPcRs {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.PcRs) > 0 {\n\t\tvar pksize4 int\n\t\tfor _, num := range m.PcRs {\n\t\t\tpksize4 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize4\n\t\tj3 := i\n\t\tfor _, num1 := range m.PcRs {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j3] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj3++\n\t\t\t}\n\t\t\tdAtA[j3] = uint8(num)\n\t\t\tj3++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize4))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *UserDiskConfigStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *UserDiskConfigStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *UserDiskConfigStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TornDown {\n\t\ti--\n\t\tif m.TornDown {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VolumeConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VolumeConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VolumeConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Symlink != nil {\n\t\tsize, err := m.Symlink.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Encryption != nil {\n\t\tsize, err := m.Encryption.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.Mount != nil {\n\t\tsize, err := m.Mount.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Locator != nil {\n\t\tsize, err := m.Locator.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Provisioning != nil {\n\t\tsize, err := m.Provisioning.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.ParentId) > 0 {\n\t\ti -= len(m.ParentId)\n\t\tcopy(dAtA[i:], m.ParentId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VolumeMountRequestSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VolumeMountRequestSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VolumeMountRequestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Secure {\n\t\ti--\n\t\tif m.Secure {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.DisableAccessTime {\n\t\ti--\n\t\tif m.DisableAccessTime {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Detached {\n\t\ti--\n\t\tif m.Detached {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ReadOnly {\n\t\ti--\n\t\tif m.ReadOnly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Requester) > 0 {\n\t\ti -= len(m.Requester)\n\t\tcopy(dAtA[i:], m.Requester)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Requester)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.VolumeId) > 0 {\n\t\ti -= len(m.VolumeId)\n\t\tcopy(dAtA[i:], m.VolumeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VolumeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VolumeMountStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VolumeMountStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VolumeMountStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Secure {\n\t\ti--\n\t\tif m.Secure {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.DisableAccessTime {\n\t\ti--\n\t\tif m.DisableAccessTime {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Detached {\n\t\ti--\n\t\tif m.Detached {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ReadOnly {\n\t\ti--\n\t\tif m.ReadOnly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Target) > 0 {\n\t\ti -= len(m.Target)\n\t\tcopy(dAtA[i:], m.Target)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Target)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Requester) > 0 {\n\t\ti -= len(m.Requester)\n\t\tcopy(dAtA[i:], m.Requester)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Requester)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.VolumeId) > 0 {\n\t\ti -= len(m.VolumeId)\n\t\tcopy(dAtA[i:], m.VolumeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VolumeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VolumeStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VolumeStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VolumeStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TpmEncryptionOptions != nil {\n\t\tsize, err := m.TpmEncryptionOptions.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb2\n\t}\n\tif m.EncryptionSlot != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.EncryptionSlot))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.EncryptionLockedToState {\n\t\ti--\n\t\tif m.EncryptionLockedToState {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif len(m.ParentId) > 0 {\n\t\ti -= len(m.ParentId)\n\t\tcopy(dAtA[i:], m.ParentId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentId)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x9a\n\t}\n\tif m.SymlinkSpec != nil {\n\t\tsize, err := m.SymlinkSpec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif len(m.ConfiguredEncryptionKeys) > 0 {\n\t\tfor iNdEx := len(m.ConfiguredEncryptionKeys) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ConfiguredEncryptionKeys[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ConfiguredEncryptionKeys[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ConfiguredEncryptionKeys[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0x8a\n\t\t}\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.MountSpec != nil {\n\t\tsize, err := m.MountSpec.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif len(m.EncryptionFailedSyncs) > 0 {\n\t\tfor iNdEx := len(m.EncryptionFailedSyncs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.EncryptionFailedSyncs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.EncryptionFailedSyncs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.EncryptionFailedSyncs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x72\n\t\t}\n\t}\n\tif len(m.PrettySize) > 0 {\n\t\ti -= len(m.PrettySize)\n\t\tcopy(dAtA[i:], m.PrettySize)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrettySize)))\n\t\ti--\n\t\tdAtA[i] = 0x6a\n\t}\n\tif m.EncryptionProvider != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.EncryptionProvider))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif len(m.MountLocation) > 0 {\n\t\ti -= len(m.MountLocation)\n\t\tcopy(dAtA[i:], m.MountLocation)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MountLocation)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.Filesystem != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Filesystem))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.PartitionIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PartitionIndex))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif len(m.ParentLocation) > 0 {\n\t\ti -= len(m.ParentLocation)\n\t\tcopy(dAtA[i:], m.ParentLocation)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentLocation)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.PreFailPhase != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PreFailPhase))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.PartitionUuid) > 0 {\n\t\ti -= len(m.PartitionUuid)\n\t\tcopy(dAtA[i:], m.PartitionUuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionUuid)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Uuid) > 0 {\n\t\ti -= len(m.Uuid)\n\t\tcopy(dAtA[i:], m.Uuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.ErrorMessage) > 0 {\n\t\ti -= len(m.ErrorMessage)\n\t\tcopy(dAtA[i:], m.ErrorMessage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ErrorMessage)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Location) > 0 {\n\t\ti -= len(m.Location)\n\t\tcopy(dAtA[i:], m.Location)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Location)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Phase != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Phase))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ZswapStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ZswapStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ZswapStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.WrittenBackPages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WrittenBackPages))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.RejectCompressPoor != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RejectCompressPoor))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.RejectCompressFail != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RejectCompressFail))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.RejectKmemcacheFail != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RejectKmemcacheFail))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.RejectAllocFail != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RejectAllocFail))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.RejectReclaimFail != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RejectReclaimFail))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.PoolLimitHit != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PoolLimitHit))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.StoredPages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.StoredPages))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.TotalSizeHuman) > 0 {\n\t\ti -= len(m.TotalSizeHuman)\n\t\tcopy(dAtA[i:], m.TotalSizeHuman)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TotalSizeHuman)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.TotalSizeBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TotalSizeBytes))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DeviceSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Major != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Major))\n\t}\n\tif m.Minor != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Minor))\n\t}\n\tl = len(m.PartitionName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PartitionNumber != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionNumber))\n\t}\n\tif m.Generation != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Generation))\n\t}\n\tl = len(m.DevicePath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Parent)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Secondaries) > 0 {\n\t\tfor _, s := range m.Secondaries {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiscoveredVolumeSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.SectorSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize))\n\t}\n\tif m.IoSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Uuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BlockSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.BlockSize))\n\t}\n\tif m.FilesystemBlockSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FilesystemBlockSize))\n\t}\n\tif m.ProbedSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProbedSize))\n\t}\n\tl = len(m.PartitionUuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PartitionType)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PartitionLabel)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PartitionIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionIndex))\n\t}\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DevicePath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Parent)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DevPath)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ParentDevPath)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PrettySize)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Offset != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Offset))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiscoveryRefreshRequestSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Request != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Request))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiscoveryRefreshStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Request != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Request))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskSelector) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Match != nil {\n\t\tif size, ok := interface{}(m.Match).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Match)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.External)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiskSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.IoSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize))\n\t}\n\tif m.SectorSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize))\n\t}\n\tif m.Readonly {\n\t\tn += 2\n\t}\n\tl = len(m.Model)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Serial)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Modalias)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Wwid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BusPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SubSystem)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Transport)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Rotational {\n\t\tn += 2\n\t}\n\tif m.Cdrom {\n\t\tn += 2\n\t}\n\tl = len(m.DevPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PrettySize)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.SecondaryDisks) > 0 {\n\t\tfor _, s := range m.SecondaryDisks {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Uuid)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Symlinks) > 0 {\n\t\tfor _, s := range m.Symlinks {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EncryptionKey) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Slot != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Slot))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tl = len(m.StaticPassphrase)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.KmsEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.TpmCheckSecurebootStatusOnEnroll {\n\t\tn += 2\n\t}\n\tif m.LockToState {\n\t\tn += 2\n\t}\n\tif len(m.TpmpcRs) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.TpmpcRs {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tif len(m.TpmPubKeyPcRs) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.TpmPubKeyPcRs {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EncryptionSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Provider != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Provider))\n\t}\n\tif len(m.Keys) > 0 {\n\t\tfor _, e := range m.Keys {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Cipher)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.KeySize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.KeySize))\n\t}\n\tif m.BlockSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.BlockSize))\n\t}\n\tif len(m.PerfOptions) > 0 {\n\t\tfor _, s := range m.PerfOptions {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *FilesystemSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LocatorSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Match != nil {\n\t\tif size, ok := interface{}(m.Match).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Match)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.DiskMatch != nil {\n\t\tif size, ok := interface{}(m.DiskMatch).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.DiskMatch)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountRequestSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.VolumeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ParentMountId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Requesters) > 0 {\n\t\tfor _, s := range m.Requesters {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.RequesterIDs) > 0 {\n\t\tfor _, s := range m.RequesterIDs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ReadOnly {\n\t\tn += 2\n\t}\n\tif m.Detached {\n\t\tn += 2\n\t}\n\tif m.DisableAccessTime {\n\t\tn += 2\n\t}\n\tif m.Secure {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.TargetPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SelinuxLabel)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ProjectQuotaSupport {\n\t\tn += 2\n\t}\n\tl = len(m.ParentId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FileMode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FileMode))\n\t}\n\tif m.Uid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Uid))\n\t}\n\tif m.Gid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Gid))\n\t}\n\tif m.RecursiveRelabel {\n\t\tn += 2\n\t}\n\tl = len(m.BindTarget)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Parameters) > 0 {\n\t\tfor _, e := range m.Parameters {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Spec != nil {\n\t\tl = m.Spec.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Target)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Source)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Filesystem != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Filesystem))\n\t}\n\tif m.ReadOnly {\n\t\tn += 2\n\t}\n\tif m.ProjectQuotaSupport {\n\t\tn += 2\n\t}\n\tif m.EncryptionProvider != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.EncryptionProvider))\n\t}\n\tif m.Detached {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ParameterSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.String_)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Binary)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PartitionSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MinSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MinSize))\n\t}\n\tif m.MaxSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MaxSize))\n\t}\n\tif m.Grow {\n\t\tn += 2\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.TypeUuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.RelativeMaxSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RelativeMaxSize))\n\t}\n\tif m.NegativeMaxSize {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProvisioningSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.DiskSelector != nil {\n\t\tl = m.DiskSelector.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PartitionSpec != nil {\n\t\tl = m.PartitionSpec.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Wave != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Wave))\n\t}\n\tif m.FilesystemSpec != nil {\n\t\tl = m.FilesystemSpec.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SwapStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Device)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SizeBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SizeBytes))\n\t}\n\tl = len(m.SizeHuman)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.UsedBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.UsedBytes))\n\t}\n\tl = len(m.UsedHuman)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SymlinkProvisioningSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.SymlinkTargetPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Force {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SymlinkSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Paths) > 0 {\n\t\tfor _, s := range m.Paths {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SystemDiskSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.DiskId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DevPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TPMEncryptionOptionsInfo) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.PcRs) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.PcRs {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tif len(m.PubKeyPcRs) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.PubKeyPcRs {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *UserDiskConfigStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tif m.TornDown {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VolumeConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ParentId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif m.Provisioning != nil {\n\t\tl = m.Provisioning.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Locator != nil {\n\t\tl = m.Locator.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mount != nil {\n\t\tl = m.Mount.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Encryption != nil {\n\t\tl = m.Encryption.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Symlink != nil {\n\t\tl = m.Symlink.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VolumeMountRequestSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.VolumeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Requester)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ReadOnly {\n\t\tn += 2\n\t}\n\tif m.Detached {\n\t\tn += 2\n\t}\n\tif m.DisableAccessTime {\n\t\tn += 2\n\t}\n\tif m.Secure {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VolumeMountStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.VolumeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Requester)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Target)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ReadOnly {\n\t\tn += 2\n\t}\n\tif m.Detached {\n\t\tn += 2\n\t}\n\tif m.DisableAccessTime {\n\t\tn += 2\n\t}\n\tif m.Secure {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VolumeStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Phase != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Phase))\n\t}\n\tl = len(m.Location)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ErrorMessage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Uuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PartitionUuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PreFailPhase != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PreFailPhase))\n\t}\n\tl = len(m.ParentLocation)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PartitionIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionIndex))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.Filesystem != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Filesystem))\n\t}\n\tl = len(m.MountLocation)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EncryptionProvider != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.EncryptionProvider))\n\t}\n\tl = len(m.PrettySize)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.EncryptionFailedSyncs) > 0 {\n\t\tfor _, s := range m.EncryptionFailedSyncs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.MountSpec != nil {\n\t\tl = m.MountSpec.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Type != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif len(m.ConfiguredEncryptionKeys) > 0 {\n\t\tfor _, s := range m.ConfiguredEncryptionKeys {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.SymlinkSpec != nil {\n\t\tl = m.SymlinkSpec.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ParentId)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EncryptionLockedToState {\n\t\tn += 3\n\t}\n\tif m.EncryptionSlot != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.EncryptionSlot))\n\t}\n\tif m.TpmEncryptionOptions != nil {\n\t\tl = m.TpmEncryptionOptions.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ZswapStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.TotalSizeBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TotalSizeBytes))\n\t}\n\tl = len(m.TotalSizeHuman)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.StoredPages != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.StoredPages))\n\t}\n\tif m.PoolLimitHit != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PoolLimitHit))\n\t}\n\tif m.RejectReclaimFail != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RejectReclaimFail))\n\t}\n\tif m.RejectAllocFail != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RejectAllocFail))\n\t}\n\tif m.RejectKmemcacheFail != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RejectKmemcacheFail))\n\t}\n\tif m.RejectCompressFail != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RejectCompressFail))\n\t}\n\tif m.RejectCompressPoor != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RejectCompressPoor))\n\t}\n\tif m.WrittenBackPages != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.WrittenBackPages))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DeviceSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DeviceSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DeviceSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Major\", wireType)\n\t\t\t}\n\t\t\tm.Major = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Major |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Minor\", wireType)\n\t\t\t}\n\t\t\tm.Minor = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Minor |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartitionName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionNumber\", wireType)\n\t\t\t}\n\t\t\tm.PartitionNumber = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PartitionNumber |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Generation\", wireType)\n\t\t\t}\n\t\t\tm.Generation = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Generation |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DevicePath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DevicePath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Parent\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Parent = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Secondaries\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Secondaries = append(m.Secondaries, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveredVolumeSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveredVolumeSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SectorSize\", wireType)\n\t\t\t}\n\t\t\tm.SectorSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SectorSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IoSize\", wireType)\n\t\t\t}\n\t\t\tm.IoSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IoSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockSize\", wireType)\n\t\t\t}\n\t\t\tm.BlockSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockSize |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FilesystemBlockSize\", wireType)\n\t\t\t}\n\t\t\tm.FilesystemBlockSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FilesystemBlockSize |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProbedSize\", wireType)\n\t\t\t}\n\t\t\tm.ProbedSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProbedSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionUuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartitionUuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionType\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartitionType = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionLabel\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartitionLabel = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionIndex\", wireType)\n\t\t\t}\n\t\t\tm.PartitionIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PartitionIndex |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DevicePath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DevicePath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Parent\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Parent = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DevPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DevPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentDevPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentDevPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 19:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrettySize\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PrettySize = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 20:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Offset\", wireType)\n\t\t\t}\n\t\t\tm.Offset = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Offset |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiscoveryRefreshRequestSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveryRefreshRequestSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveryRefreshRequestSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Request\", wireType)\n\t\t\t}\n\t\t\tm.Request = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Request |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiscoveryRefreshStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveryRefreshStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiscoveryRefreshStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Request\", wireType)\n\t\t\t}\n\t\t\tm.Request = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Request |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskSelector) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskSelector: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskSelector: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Match\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Match == nil {\n\t\t\t\tm.Match = &v1alpha1.CheckedExpr{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Match).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Match); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field External\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.External = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiskSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiskSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiskSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IoSize\", wireType)\n\t\t\t}\n\t\t\tm.IoSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IoSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SectorSize\", wireType)\n\t\t\t}\n\t\t\tm.SectorSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SectorSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Readonly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Readonly = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Model\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Model = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Serial\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Serial = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Modalias\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Modalias = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wwid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Wwid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BusPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BusPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SubSystem\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SubSystem = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Transport\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Transport = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rotational\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Rotational = bool(v != 0)\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cdrom\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Cdrom = bool(v != 0)\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DevPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DevPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrettySize\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PrettySize = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SecondaryDisks\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SecondaryDisks = append(m.SecondaryDisks, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Symlinks\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Symlinks = append(m.Symlinks, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EncryptionKey) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionKey: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionKey: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Slot\", wireType)\n\t\t\t}\n\t\t\tm.Slot = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Slot |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.BlockEncryptionKeyType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StaticPassphrase\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.StaticPassphrase = append(m.StaticPassphrase[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.StaticPassphrase == nil {\n\t\t\t\tm.StaticPassphrase = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KmsEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.KmsEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TpmCheckSecurebootStatusOnEnroll\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TpmCheckSecurebootStatusOnEnroll = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LockToState\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.LockToState = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v int64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.TpmpcRs = append(m.TpmpcRs, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tvar count int\n\t\t\t\tfor _, integer := range dAtA[iNdEx:postIndex] {\n\t\t\t\t\tif integer < 128 {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telementCount = count\n\t\t\t\tif elementCount != 0 && len(m.TpmpcRs) == 0 {\n\t\t\t\t\tm.TpmpcRs = make([]int64, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v int64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.TpmpcRs = append(m.TpmpcRs, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TpmpcRs\", wireType)\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v int64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.TpmPubKeyPcRs = append(m.TpmPubKeyPcRs, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tvar count int\n\t\t\t\tfor _, integer := range dAtA[iNdEx:postIndex] {\n\t\t\t\t\tif integer < 128 {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telementCount = count\n\t\t\t\tif elementCount != 0 && len(m.TpmPubKeyPcRs) == 0 {\n\t\t\t\t\tm.TpmPubKeyPcRs = make([]int64, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v int64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.TpmPubKeyPcRs = append(m.TpmPubKeyPcRs, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TpmPubKeyPcRs\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EncryptionSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Provider\", wireType)\n\t\t\t}\n\t\t\tm.Provider = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Provider |= enums.BlockEncryptionProviderType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Keys\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Keys = append(m.Keys, &EncryptionKey{})\n\t\t\tif err := m.Keys[len(m.Keys)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cipher\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Cipher = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KeySize\", wireType)\n\t\t\t}\n\t\t\tm.KeySize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.KeySize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BlockSize\", wireType)\n\t\t\t}\n\t\t\tm.BlockSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BlockSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PerfOptions\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PerfOptions = append(m.PerfOptions, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *FilesystemSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: FilesystemSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: FilesystemSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.BlockFilesystemType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LocatorSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LocatorSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LocatorSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Match\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Match == nil {\n\t\t\t\tm.Match = &v1alpha1.CheckedExpr{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Match).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Match); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiskMatch\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.DiskMatch == nil {\n\t\t\t\tm.DiskMatch = &v1alpha1.CheckedExpr{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.DiskMatch).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.DiskMatch); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountRequestSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountRequestSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountRequestSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VolumeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VolumeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentMountId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentMountId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Requesters\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Requesters = append(m.Requesters, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RequesterIDs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RequesterIDs = append(m.RequesterIDs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadOnly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadOnly = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Detached\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Detached = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DisableAccessTime\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DisableAccessTime = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Secure\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Secure = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TargetPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TargetPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SelinuxLabel\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SelinuxLabel = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProjectQuotaSupport\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ProjectQuotaSupport = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FileMode\", wireType)\n\t\t\t}\n\t\t\tm.FileMode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FileMode |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uid\", wireType)\n\t\t\t}\n\t\t\tm.Uid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Uid |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Gid\", wireType)\n\t\t\t}\n\t\t\tm.Gid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Gid |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RecursiveRelabel\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RecursiveRelabel = bool(v != 0)\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BindTarget\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BindTarget = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Parameters\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Parameters = append(m.Parameters, &ParameterSpec{})\n\t\t\tif err := m.Parameters[len(m.Parameters)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Spec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Spec == nil {\n\t\t\t\tm.Spec = &MountRequestSpec{}\n\t\t\t}\n\t\t\tif err := m.Spec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Target\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Target = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Source = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Filesystem\", wireType)\n\t\t\t}\n\t\t\tm.Filesystem = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Filesystem |= enums.BlockFilesystemType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadOnly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadOnly = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProjectQuotaSupport\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ProjectQuotaSupport = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionProvider\", wireType)\n\t\t\t}\n\t\t\tm.EncryptionProvider = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EncryptionProvider |= enums.BlockEncryptionProviderType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Detached\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Detached = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ParameterSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ParameterSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ParameterSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.BlockFSParameterType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field String_\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.String_ = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Binary\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Binary = append(m.Binary[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Binary == nil {\n\t\t\t\tm.Binary = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PartitionSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PartitionSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PartitionSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MinSize\", wireType)\n\t\t\t}\n\t\t\tm.MinSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MinSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MaxSize\", wireType)\n\t\t\t}\n\t\t\tm.MaxSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MaxSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Grow\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Grow = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TypeUuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TypeUuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RelativeMaxSize\", wireType)\n\t\t\t}\n\t\t\tm.RelativeMaxSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RelativeMaxSize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NegativeMaxSize\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.NegativeMaxSize = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProvisioningSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProvisioningSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProvisioningSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiskSelector\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.DiskSelector == nil {\n\t\t\t\tm.DiskSelector = &DiskSelector{}\n\t\t\t}\n\t\t\tif err := m.DiskSelector.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionSpec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.PartitionSpec == nil {\n\t\t\t\tm.PartitionSpec = &PartitionSpec{}\n\t\t\t}\n\t\t\tif err := m.PartitionSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wave\", wireType)\n\t\t\t}\n\t\t\tm.Wave = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Wave |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FilesystemSpec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.FilesystemSpec == nil {\n\t\t\t\tm.FilesystemSpec = &FilesystemSpec{}\n\t\t\t}\n\t\t\tif err := m.FilesystemSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SwapStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SwapStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SwapStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Device\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Device = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SizeBytes\", wireType)\n\t\t\t}\n\t\t\tm.SizeBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SizeBytes |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SizeHuman\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SizeHuman = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UsedBytes\", wireType)\n\t\t\t}\n\t\t\tm.UsedBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.UsedBytes |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UsedHuman\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UsedHuman = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= int32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SymlinkProvisioningSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SymlinkProvisioningSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SymlinkProvisioningSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SymlinkTargetPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SymlinkTargetPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Force\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Force = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SymlinkSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SymlinkSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SymlinkSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Paths\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Paths = append(m.Paths, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SystemDiskSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SystemDiskSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SystemDiskSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiskId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DiskId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DevPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DevPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TPMEncryptionOptionsInfo) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TPMEncryptionOptionsInfo: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TPMEncryptionOptionsInfo: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v int64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.PcRs = append(m.PcRs, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tvar count int\n\t\t\t\tfor _, integer := range dAtA[iNdEx:postIndex] {\n\t\t\t\t\tif integer < 128 {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telementCount = count\n\t\t\t\tif elementCount != 0 && len(m.PcRs) == 0 {\n\t\t\t\t\tm.PcRs = make([]int64, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v int64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.PcRs = append(m.PcRs, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PcRs\", wireType)\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v int64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.PubKeyPcRs = append(m.PubKeyPcRs, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tvar count int\n\t\t\t\tfor _, integer := range dAtA[iNdEx:postIndex] {\n\t\t\t\t\tif integer < 128 {\n\t\t\t\t\t\tcount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telementCount = count\n\t\t\t\tif elementCount != 0 && len(m.PubKeyPcRs) == 0 {\n\t\t\t\t\tm.PubKeyPcRs = make([]int64, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v int64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= int64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.PubKeyPcRs = append(m.PubKeyPcRs, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PubKeyPcRs\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *UserDiskConfigStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: UserDiskConfigStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: UserDiskConfigStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TornDown\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TornDown = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VolumeConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.BlockVolumeType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Provisioning\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Provisioning == nil {\n\t\t\t\tm.Provisioning = &ProvisioningSpec{}\n\t\t\t}\n\t\t\tif err := m.Provisioning.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Locator\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Locator == nil {\n\t\t\t\tm.Locator = &LocatorSpec{}\n\t\t\t}\n\t\t\tif err := m.Locator.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mount\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Mount == nil {\n\t\t\t\tm.Mount = &MountSpec{}\n\t\t\t}\n\t\t\tif err := m.Mount.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Encryption\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Encryption == nil {\n\t\t\t\tm.Encryption = &EncryptionSpec{}\n\t\t\t}\n\t\t\tif err := m.Encryption.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Symlink\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Symlink == nil {\n\t\t\t\tm.Symlink = &SymlinkProvisioningSpec{}\n\t\t\t}\n\t\t\tif err := m.Symlink.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VolumeMountRequestSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeMountRequestSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeMountRequestSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VolumeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VolumeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Requester\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Requester = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadOnly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadOnly = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Detached\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Detached = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DisableAccessTime\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DisableAccessTime = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Secure\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Secure = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VolumeMountStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeMountStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeMountStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VolumeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VolumeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Requester\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Requester = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Target\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Target = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadOnly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadOnly = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Detached\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Detached = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DisableAccessTime\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DisableAccessTime = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Secure\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Secure = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VolumeStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VolumeStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Phase\", wireType)\n\t\t\t}\n\t\t\tm.Phase = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Phase |= enums.BlockVolumePhase(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Location\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Location = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ErrorMessage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ErrorMessage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionUuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartitionUuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PreFailPhase\", wireType)\n\t\t\t}\n\t\t\tm.PreFailPhase = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PreFailPhase |= enums.BlockVolumePhase(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentLocation\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentLocation = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartitionIndex\", wireType)\n\t\t\t}\n\t\t\tm.PartitionIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PartitionIndex |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Filesystem\", wireType)\n\t\t\t}\n\t\t\tm.Filesystem = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Filesystem |= enums.BlockFilesystemType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MountLocation\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MountLocation = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionProvider\", wireType)\n\t\t\t}\n\t\t\tm.EncryptionProvider = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EncryptionProvider |= enums.BlockEncryptionProviderType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrettySize\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PrettySize = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionFailedSyncs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.EncryptionFailedSyncs = append(m.EncryptionFailedSyncs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MountSpec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MountSpec == nil {\n\t\t\t\tm.MountSpec = &MountSpec{}\n\t\t\t}\n\t\t\tif err := m.MountSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.BlockVolumeType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfiguredEncryptionKeys\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ConfiguredEncryptionKeys = append(m.ConfiguredEncryptionKeys, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SymlinkSpec\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.SymlinkSpec == nil {\n\t\t\t\tm.SymlinkSpec = &SymlinkProvisioningSpec{}\n\t\t\t}\n\t\t\tif err := m.SymlinkSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 19:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 20:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionLockedToState\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EncryptionLockedToState = bool(v != 0)\n\t\tcase 21:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionSlot\", wireType)\n\t\t\t}\n\t\t\tm.EncryptionSlot = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.EncryptionSlot |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 22:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TpmEncryptionOptions\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.TpmEncryptionOptions == nil {\n\t\t\t\tm.TpmEncryptionOptions = &TPMEncryptionOptionsInfo{}\n\t\t\t}\n\t\t\tif err := m.TpmEncryptionOptions.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ZswapStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ZswapStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ZswapStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TotalSizeBytes\", wireType)\n\t\t\t}\n\t\t\tm.TotalSizeBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TotalSizeBytes |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TotalSizeHuman\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TotalSizeHuman = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StoredPages\", wireType)\n\t\t\t}\n\t\t\tm.StoredPages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.StoredPages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PoolLimitHit\", wireType)\n\t\t\t}\n\t\t\tm.PoolLimitHit = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PoolLimitHit |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RejectReclaimFail\", wireType)\n\t\t\t}\n\t\t\tm.RejectReclaimFail = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RejectReclaimFail |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RejectAllocFail\", wireType)\n\t\t\t}\n\t\t\tm.RejectAllocFail = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RejectAllocFail |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RejectKmemcacheFail\", wireType)\n\t\t\t}\n\t\t\tm.RejectKmemcacheFail = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RejectKmemcacheFail |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RejectCompressFail\", wireType)\n\t\t\t}\n\t\t\tm.RejectCompressFail = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RejectCompressFail |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RejectCompressPoor\", wireType)\n\t\t\t}\n\t\t\tm.RejectCompressPoor = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RejectCompressPoor |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WrittenBackPages\", wireType)\n\t\t\t}\n\t\t\tm.WrittenBackPages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WrittenBackPages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/cluster/cluster.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/cluster/cluster.proto\n\npackage cluster\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// AffiliateSpec describes Affiliate state.\ntype AffiliateSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodeId          string                 `protobuf:\"bytes,1,opt,name=node_id,json=nodeId,proto3\" json:\"node_id,omitempty\"`\n\tAddresses       []*common.NetIP        `protobuf:\"bytes,2,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tHostname        string                 `protobuf:\"bytes,3,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tNodename        string                 `protobuf:\"bytes,4,opt,name=nodename,proto3\" json:\"nodename,omitempty\"`\n\tOperatingSystem string                 `protobuf:\"bytes,5,opt,name=operating_system,json=operatingSystem,proto3\" json:\"operating_system,omitempty\"`\n\tMachineType     enums.MachineType      `protobuf:\"varint,6,opt,name=machine_type,json=machineType,proto3,enum=talos.resource.definitions.enums.MachineType\" json:\"machine_type,omitempty\"`\n\tKubeSpan        *KubeSpanAffiliateSpec `protobuf:\"bytes,7,opt,name=kube_span,json=kubeSpan,proto3\" json:\"kube_span,omitempty\"`\n\tControlPlane    *ControlPlane          `protobuf:\"bytes,8,opt,name=control_plane,json=controlPlane,proto3\" json:\"control_plane,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *AffiliateSpec) Reset() {\n\t*x = AffiliateSpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AffiliateSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AffiliateSpec) ProtoMessage() {}\n\nfunc (x *AffiliateSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AffiliateSpec.ProtoReflect.Descriptor instead.\nfunc (*AffiliateSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *AffiliateSpec) GetNodeId() string {\n\tif x != nil {\n\t\treturn x.NodeId\n\t}\n\treturn \"\"\n}\n\nfunc (x *AffiliateSpec) GetAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *AffiliateSpec) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *AffiliateSpec) GetNodename() string {\n\tif x != nil {\n\t\treturn x.Nodename\n\t}\n\treturn \"\"\n}\n\nfunc (x *AffiliateSpec) GetOperatingSystem() string {\n\tif x != nil {\n\t\treturn x.OperatingSystem\n\t}\n\treturn \"\"\n}\n\nfunc (x *AffiliateSpec) GetMachineType() enums.MachineType {\n\tif x != nil {\n\t\treturn x.MachineType\n\t}\n\treturn enums.MachineType(0)\n}\n\nfunc (x *AffiliateSpec) GetKubeSpan() *KubeSpanAffiliateSpec {\n\tif x != nil {\n\t\treturn x.KubeSpan\n\t}\n\treturn nil\n}\n\nfunc (x *AffiliateSpec) GetControlPlane() *ControlPlane {\n\tif x != nil {\n\t\treturn x.ControlPlane\n\t}\n\treturn nil\n}\n\n// ConfigSpec describes KubeSpan configuration.\ntype ConfigSpec struct {\n\tstate                     protoimpl.MessageState `protogen:\"open.v1\"`\n\tDiscoveryEnabled          bool                   `protobuf:\"varint,1,opt,name=discovery_enabled,json=discoveryEnabled,proto3\" json:\"discovery_enabled,omitempty\"`\n\tRegistryKubernetesEnabled bool                   `protobuf:\"varint,2,opt,name=registry_kubernetes_enabled,json=registryKubernetesEnabled,proto3\" json:\"registry_kubernetes_enabled,omitempty\"`\n\tRegistryServiceEnabled    bool                   `protobuf:\"varint,3,opt,name=registry_service_enabled,json=registryServiceEnabled,proto3\" json:\"registry_service_enabled,omitempty\"`\n\tServiceEndpoint           string                 `protobuf:\"bytes,4,opt,name=service_endpoint,json=serviceEndpoint,proto3\" json:\"service_endpoint,omitempty\"`\n\tServiceEndpointInsecure   bool                   `protobuf:\"varint,5,opt,name=service_endpoint_insecure,json=serviceEndpointInsecure,proto3\" json:\"service_endpoint_insecure,omitempty\"`\n\tServiceEncryptionKey      []byte                 `protobuf:\"bytes,6,opt,name=service_encryption_key,json=serviceEncryptionKey,proto3\" json:\"service_encryption_key,omitempty\"`\n\tServiceClusterId          string                 `protobuf:\"bytes,7,opt,name=service_cluster_id,json=serviceClusterId,proto3\" json:\"service_cluster_id,omitempty\"`\n\tunknownFields             protoimpl.UnknownFields\n\tsizeCache                 protoimpl.SizeCache\n}\n\nfunc (x *ConfigSpec) Reset() {\n\t*x = ConfigSpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigSpec) ProtoMessage() {}\n\nfunc (x *ConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ConfigSpec) GetDiscoveryEnabled() bool {\n\tif x != nil {\n\t\treturn x.DiscoveryEnabled\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetRegistryKubernetesEnabled() bool {\n\tif x != nil {\n\t\treturn x.RegistryKubernetesEnabled\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetRegistryServiceEnabled() bool {\n\tif x != nil {\n\t\treturn x.RegistryServiceEnabled\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetServiceEndpoint() string {\n\tif x != nil {\n\t\treturn x.ServiceEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetServiceEndpointInsecure() bool {\n\tif x != nil {\n\t\treturn x.ServiceEndpointInsecure\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetServiceEncryptionKey() []byte {\n\tif x != nil {\n\t\treturn x.ServiceEncryptionKey\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetServiceClusterId() string {\n\tif x != nil {\n\t\treturn x.ServiceClusterId\n\t}\n\treturn \"\"\n}\n\n// ControlPlane describes ControlPlane data if any.\ntype ControlPlane struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tApiServerPort int64                  `protobuf:\"varint,1,opt,name=api_server_port,json=apiServerPort,proto3\" json:\"api_server_port,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ControlPlane) Reset() {\n\t*x = ControlPlane{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControlPlane) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControlPlane) ProtoMessage() {}\n\nfunc (x *ControlPlane) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControlPlane.ProtoReflect.Descriptor instead.\nfunc (*ControlPlane) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ControlPlane) GetApiServerPort() int64 {\n\tif x != nil {\n\t\treturn x.ApiServerPort\n\t}\n\treturn 0\n}\n\n// IdentitySpec describes status of rendered secrets.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\ntype IdentitySpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodeId        string                 `protobuf:\"bytes,1,opt,name=node_id,json=nodeId,proto3\" json:\"node_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *IdentitySpec) Reset() {\n\t*x = IdentitySpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *IdentitySpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*IdentitySpec) ProtoMessage() {}\n\nfunc (x *IdentitySpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use IdentitySpec.ProtoReflect.Descriptor instead.\nfunc (*IdentitySpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *IdentitySpec) GetNodeId() string {\n\tif x != nil {\n\t\treturn x.NodeId\n\t}\n\treturn \"\"\n}\n\n// InfoSpec describes cluster information.\ntype InfoSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tClusterId     string                 `protobuf:\"bytes,1,opt,name=cluster_id,json=clusterId,proto3\" json:\"cluster_id,omitempty\"`\n\tClusterName   string                 `protobuf:\"bytes,2,opt,name=cluster_name,json=clusterName,proto3\" json:\"cluster_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *InfoSpec) Reset() {\n\t*x = InfoSpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *InfoSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*InfoSpec) ProtoMessage() {}\n\nfunc (x *InfoSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use InfoSpec.ProtoReflect.Descriptor instead.\nfunc (*InfoSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *InfoSpec) GetClusterId() string {\n\tif x != nil {\n\t\treturn x.ClusterId\n\t}\n\treturn \"\"\n}\n\nfunc (x *InfoSpec) GetClusterName() string {\n\tif x != nil {\n\t\treturn x.ClusterName\n\t}\n\treturn \"\"\n}\n\n// KubeSpanAffiliateSpec describes additional information specific for the KubeSpan.\ntype KubeSpanAffiliateSpec struct {\n\tstate                     protoimpl.MessageState `protogen:\"open.v1\"`\n\tPublicKey                 string                 `protobuf:\"bytes,1,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tAddress                   *common.NetIP          `protobuf:\"bytes,2,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tAdditionalAddresses       []*common.NetIPPrefix  `protobuf:\"bytes,3,rep,name=additional_addresses,json=additionalAddresses,proto3\" json:\"additional_addresses,omitempty\"`\n\tEndpoints                 []*common.NetIPPort    `protobuf:\"bytes,4,rep,name=endpoints,proto3\" json:\"endpoints,omitempty\"`\n\tExcludeAdvertisedNetworks []*common.NetIPPrefix  `protobuf:\"bytes,5,rep,name=exclude_advertised_networks,json=excludeAdvertisedNetworks,proto3\" json:\"exclude_advertised_networks,omitempty\"`\n\tunknownFields             protoimpl.UnknownFields\n\tsizeCache                 protoimpl.SizeCache\n}\n\nfunc (x *KubeSpanAffiliateSpec) Reset() {\n\t*x = KubeSpanAffiliateSpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubeSpanAffiliateSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubeSpanAffiliateSpec) ProtoMessage() {}\n\nfunc (x *KubeSpanAffiliateSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubeSpanAffiliateSpec.ProtoReflect.Descriptor instead.\nfunc (*KubeSpanAffiliateSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *KubeSpanAffiliateSpec) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeSpanAffiliateSpec) GetAddress() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *KubeSpanAffiliateSpec) GetAdditionalAddresses() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.AdditionalAddresses\n\t}\n\treturn nil\n}\n\nfunc (x *KubeSpanAffiliateSpec) GetEndpoints() []*common.NetIPPort {\n\tif x != nil {\n\t\treturn x.Endpoints\n\t}\n\treturn nil\n}\n\nfunc (x *KubeSpanAffiliateSpec) GetExcludeAdvertisedNetworks() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.ExcludeAdvertisedNetworks\n\t}\n\treturn nil\n}\n\n// MemberSpec describes Member state.\ntype MemberSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodeId          string                 `protobuf:\"bytes,1,opt,name=node_id,json=nodeId,proto3\" json:\"node_id,omitempty\"`\n\tAddresses       []*common.NetIP        `protobuf:\"bytes,2,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tHostname        string                 `protobuf:\"bytes,3,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tMachineType     enums.MachineType      `protobuf:\"varint,4,opt,name=machine_type,json=machineType,proto3,enum=talos.resource.definitions.enums.MachineType\" json:\"machine_type,omitempty\"`\n\tOperatingSystem string                 `protobuf:\"bytes,5,opt,name=operating_system,json=operatingSystem,proto3\" json:\"operating_system,omitempty\"`\n\tControlPlane    *ControlPlane          `protobuf:\"bytes,6,opt,name=control_plane,json=controlPlane,proto3\" json:\"control_plane,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *MemberSpec) Reset() {\n\t*x = MemberSpec{}\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemberSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemberSpec) ProtoMessage() {}\n\nfunc (x *MemberSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cluster_cluster_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemberSpec.ProtoReflect.Descriptor instead.\nfunc (*MemberSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *MemberSpec) GetNodeId() string {\n\tif x != nil {\n\t\treturn x.NodeId\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemberSpec) GetAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *MemberSpec) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemberSpec) GetMachineType() enums.MachineType {\n\tif x != nil {\n\t\treturn x.MachineType\n\t}\n\treturn enums.MachineType(0)\n}\n\nfunc (x *MemberSpec) GetOperatingSystem() string {\n\tif x != nil {\n\t\treturn x.OperatingSystem\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemberSpec) GetControlPlane() *ControlPlane {\n\tif x != nil {\n\t\treturn x.ControlPlane\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_cluster_cluster_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_cluster_cluster_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"*resource/definitions/cluster/cluster.proto\\x12\\\"talos.resource.definitions.cluster\\x1a\\x13common/common.proto\\x1a&resource/definitions/enums/enums.proto\\\"\\xb9\\x03\\n\" +\n\t\"\\rAffiliateSpec\\x12\\x17\\n\" +\n\t\"\\anode_id\\x18\\x01 \\x01(\\tR\\x06nodeId\\x12+\\n\" +\n\t\"\\taddresses\\x18\\x02 \\x03(\\v2\\r.common.NetIPR\\taddresses\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x03 \\x01(\\tR\\bhostname\\x12\\x1a\\n\" +\n\t\"\\bnodename\\x18\\x04 \\x01(\\tR\\bnodename\\x12)\\n\" +\n\t\"\\x10operating_system\\x18\\x05 \\x01(\\tR\\x0foperatingSystem\\x12P\\n\" +\n\t\"\\fmachine_type\\x18\\x06 \\x01(\\x0e2-.talos.resource.definitions.enums.MachineTypeR\\vmachineType\\x12V\\n\" +\n\t\"\\tkube_span\\x18\\a \\x01(\\v29.talos.resource.definitions.cluster.KubeSpanAffiliateSpecR\\bkubeSpan\\x12U\\n\" +\n\t\"\\rcontrol_plane\\x18\\b \\x01(\\v20.talos.resource.definitions.cluster.ControlPlaneR\\fcontrolPlane\\\"\\xfe\\x02\\n\" +\n\t\"\\n\" +\n\t\"ConfigSpec\\x12+\\n\" +\n\t\"\\x11discovery_enabled\\x18\\x01 \\x01(\\bR\\x10discoveryEnabled\\x12>\\n\" +\n\t\"\\x1bregistry_kubernetes_enabled\\x18\\x02 \\x01(\\bR\\x19registryKubernetesEnabled\\x128\\n\" +\n\t\"\\x18registry_service_enabled\\x18\\x03 \\x01(\\bR\\x16registryServiceEnabled\\x12)\\n\" +\n\t\"\\x10service_endpoint\\x18\\x04 \\x01(\\tR\\x0fserviceEndpoint\\x12:\\n\" +\n\t\"\\x19service_endpoint_insecure\\x18\\x05 \\x01(\\bR\\x17serviceEndpointInsecure\\x124\\n\" +\n\t\"\\x16service_encryption_key\\x18\\x06 \\x01(\\fR\\x14serviceEncryptionKey\\x12,\\n\" +\n\t\"\\x12service_cluster_id\\x18\\a \\x01(\\tR\\x10serviceClusterId\\\"6\\n\" +\n\t\"\\fControlPlane\\x12&\\n\" +\n\t\"\\x0fapi_server_port\\x18\\x01 \\x01(\\x03R\\rapiServerPort\\\"'\\n\" +\n\t\"\\fIdentitySpec\\x12\\x17\\n\" +\n\t\"\\anode_id\\x18\\x01 \\x01(\\tR\\x06nodeId\\\"L\\n\" +\n\t\"\\bInfoSpec\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"cluster_id\\x18\\x01 \\x01(\\tR\\tclusterId\\x12!\\n\" +\n\t\"\\fcluster_name\\x18\\x02 \\x01(\\tR\\vclusterName\\\"\\xad\\x02\\n\" +\n\t\"\\x15KubeSpanAffiliateSpec\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"public_key\\x18\\x01 \\x01(\\tR\\tpublicKey\\x12'\\n\" +\n\t\"\\aaddress\\x18\\x02 \\x01(\\v2\\r.common.NetIPR\\aaddress\\x12F\\n\" +\n\t\"\\x14additional_addresses\\x18\\x03 \\x03(\\v2\\x13.common.NetIPPrefixR\\x13additionalAddresses\\x12/\\n\" +\n\t\"\\tendpoints\\x18\\x04 \\x03(\\v2\\x11.common.NetIPPortR\\tendpoints\\x12S\\n\" +\n\t\"\\x1bexclude_advertised_networks\\x18\\x05 \\x03(\\v2\\x13.common.NetIPPrefixR\\x19excludeAdvertisedNetworks\\\"\\xc2\\x02\\n\" +\n\t\"\\n\" +\n\t\"MemberSpec\\x12\\x17\\n\" +\n\t\"\\anode_id\\x18\\x01 \\x01(\\tR\\x06nodeId\\x12+\\n\" +\n\t\"\\taddresses\\x18\\x02 \\x03(\\v2\\r.common.NetIPR\\taddresses\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x03 \\x01(\\tR\\bhostname\\x12P\\n\" +\n\t\"\\fmachine_type\\x18\\x04 \\x01(\\x0e2-.talos.resource.definitions.enums.MachineTypeR\\vmachineType\\x12)\\n\" +\n\t\"\\x10operating_system\\x18\\x05 \\x01(\\tR\\x0foperatingSystem\\x12U\\n\" +\n\t\"\\rcontrol_plane\\x18\\x06 \\x01(\\v20.talos.resource.definitions.cluster.ControlPlaneR\\fcontrolPlaneBx\\n\" +\n\t\"*dev.talos.api.resource.definitions.clusterZJgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/clusterb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_cluster_cluster_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_cluster_cluster_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_cluster_cluster_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_cluster_cluster_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_cluster_cluster_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_cluster_cluster_proto_rawDesc), len(file_resource_definitions_cluster_cluster_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_cluster_cluster_proto_rawDescData\n}\n\nvar file_resource_definitions_cluster_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 7)\nvar file_resource_definitions_cluster_cluster_proto_goTypes = []any{\n\t(*AffiliateSpec)(nil),         // 0: talos.resource.definitions.cluster.AffiliateSpec\n\t(*ConfigSpec)(nil),            // 1: talos.resource.definitions.cluster.ConfigSpec\n\t(*ControlPlane)(nil),          // 2: talos.resource.definitions.cluster.ControlPlane\n\t(*IdentitySpec)(nil),          // 3: talos.resource.definitions.cluster.IdentitySpec\n\t(*InfoSpec)(nil),              // 4: talos.resource.definitions.cluster.InfoSpec\n\t(*KubeSpanAffiliateSpec)(nil), // 5: talos.resource.definitions.cluster.KubeSpanAffiliateSpec\n\t(*MemberSpec)(nil),            // 6: talos.resource.definitions.cluster.MemberSpec\n\t(*common.NetIP)(nil),          // 7: common.NetIP\n\t(enums.MachineType)(0),        // 8: talos.resource.definitions.enums.MachineType\n\t(*common.NetIPPrefix)(nil),    // 9: common.NetIPPrefix\n\t(*common.NetIPPort)(nil),      // 10: common.NetIPPort\n}\nvar file_resource_definitions_cluster_cluster_proto_depIdxs = []int32{\n\t7,  // 0: talos.resource.definitions.cluster.AffiliateSpec.addresses:type_name -> common.NetIP\n\t8,  // 1: talos.resource.definitions.cluster.AffiliateSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType\n\t5,  // 2: talos.resource.definitions.cluster.AffiliateSpec.kube_span:type_name -> talos.resource.definitions.cluster.KubeSpanAffiliateSpec\n\t2,  // 3: talos.resource.definitions.cluster.AffiliateSpec.control_plane:type_name -> talos.resource.definitions.cluster.ControlPlane\n\t7,  // 4: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.address:type_name -> common.NetIP\n\t9,  // 5: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.additional_addresses:type_name -> common.NetIPPrefix\n\t10, // 6: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.endpoints:type_name -> common.NetIPPort\n\t9,  // 7: talos.resource.definitions.cluster.KubeSpanAffiliateSpec.exclude_advertised_networks:type_name -> common.NetIPPrefix\n\t7,  // 8: talos.resource.definitions.cluster.MemberSpec.addresses:type_name -> common.NetIP\n\t8,  // 9: talos.resource.definitions.cluster.MemberSpec.machine_type:type_name -> talos.resource.definitions.enums.MachineType\n\t2,  // 10: talos.resource.definitions.cluster.MemberSpec.control_plane:type_name -> talos.resource.definitions.cluster.ControlPlane\n\t11, // [11:11] is the sub-list for method output_type\n\t11, // [11:11] is the sub-list for method input_type\n\t11, // [11:11] is the sub-list for extension type_name\n\t11, // [11:11] is the sub-list for extension extendee\n\t0,  // [0:11] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_cluster_cluster_proto_init() }\nfunc file_resource_definitions_cluster_cluster_proto_init() {\n\tif File_resource_definitions_cluster_cluster_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_cluster_cluster_proto_rawDesc), len(file_resource_definitions_cluster_cluster_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   7,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_cluster_cluster_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_cluster_cluster_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_cluster_cluster_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_cluster_cluster_proto = out.File\n\tfile_resource_definitions_cluster_cluster_proto_goTypes = nil\n\tfile_resource_definitions_cluster_cluster_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/cluster/cluster_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/cluster/cluster.proto\n\npackage cluster\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *AffiliateSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AffiliateSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AffiliateSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ControlPlane != nil {\n\t\tsize, err := m.ControlPlane.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.KubeSpan != nil {\n\t\tsize, err := m.KubeSpan.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.MachineType != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MachineType))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.OperatingSystem) > 0 {\n\t\ti -= len(m.OperatingSystem)\n\t\tcopy(dAtA[i:], m.OperatingSystem)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OperatingSystem)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Nodename) > 0 {\n\t\ti -= len(m.Nodename)\n\t\tcopy(dAtA[i:], m.Nodename)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Nodename)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Addresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Addresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.NodeId) > 0 {\n\t\ti -= len(m.NodeId)\n\t\tcopy(dAtA[i:], m.NodeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NodeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ServiceClusterId) > 0 {\n\t\ti -= len(m.ServiceClusterId)\n\t\tcopy(dAtA[i:], m.ServiceClusterId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServiceClusterId)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.ServiceEncryptionKey) > 0 {\n\t\ti -= len(m.ServiceEncryptionKey)\n\t\tcopy(dAtA[i:], m.ServiceEncryptionKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServiceEncryptionKey)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.ServiceEndpointInsecure {\n\t\ti--\n\t\tif m.ServiceEndpointInsecure {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.ServiceEndpoint) > 0 {\n\t\ti -= len(m.ServiceEndpoint)\n\t\tcopy(dAtA[i:], m.ServiceEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServiceEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.RegistryServiceEnabled {\n\t\ti--\n\t\tif m.RegistryServiceEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.RegistryKubernetesEnabled {\n\t\ti--\n\t\tif m.RegistryKubernetesEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.DiscoveryEnabled {\n\t\ti--\n\t\tif m.DiscoveryEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControlPlane) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControlPlane) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControlPlane) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ApiServerPort != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ApiServerPort))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *IdentitySpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *IdentitySpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *IdentitySpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.NodeId) > 0 {\n\t\ti -= len(m.NodeId)\n\t\tcopy(dAtA[i:], m.NodeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NodeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *InfoSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *InfoSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *InfoSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ClusterName) > 0 {\n\t\ti -= len(m.ClusterName)\n\t\tcopy(dAtA[i:], m.ClusterName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.ClusterId) > 0 {\n\t\ti -= len(m.ClusterId)\n\t\tcopy(dAtA[i:], m.ClusterId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubeSpanAffiliateSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubeSpanAffiliateSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubeSpanAffiliateSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExcludeAdvertisedNetworks) > 0 {\n\t\tfor iNdEx := len(m.ExcludeAdvertisedNetworks) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExcludeAdvertisedNetworks[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExcludeAdvertisedNetworks[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor iNdEx := len(m.Endpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Endpoints[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Endpoints[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.AdditionalAddresses) > 0 {\n\t\tfor iNdEx := len(m.AdditionalAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AdditionalAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AdditionalAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Address != nil {\n\t\tif vtmsg, ok := interface{}(m.Address).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.PublicKey) > 0 {\n\t\ti -= len(m.PublicKey)\n\t\tcopy(dAtA[i:], m.PublicKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemberSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemberSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemberSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ControlPlane != nil {\n\t\tsize, err := m.ControlPlane.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.OperatingSystem) > 0 {\n\t\ti -= len(m.OperatingSystem)\n\t\tcopy(dAtA[i:], m.OperatingSystem)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OperatingSystem)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.MachineType != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MachineType))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Addresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Addresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.NodeId) > 0 {\n\t\ti -= len(m.NodeId)\n\t\tcopy(dAtA[i:], m.NodeId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NodeId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AffiliateSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.NodeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Nodename)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.OperatingSystem)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MachineType != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MachineType))\n\t}\n\tif m.KubeSpan != nil {\n\t\tl = m.KubeSpan.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ControlPlane != nil {\n\t\tl = m.ControlPlane.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.DiscoveryEnabled {\n\t\tn += 2\n\t}\n\tif m.RegistryKubernetesEnabled {\n\t\tn += 2\n\t}\n\tif m.RegistryServiceEnabled {\n\t\tn += 2\n\t}\n\tl = len(m.ServiceEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ServiceEndpointInsecure {\n\t\tn += 2\n\t}\n\tl = len(m.ServiceEncryptionKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ServiceClusterId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControlPlane) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.ApiServerPort != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ApiServerPort))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *IdentitySpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.NodeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *InfoSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ClusterId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ClusterName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubeSpanAffiliateSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.PublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Address != nil {\n\t\tif size, ok := interface{}(m.Address).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Address)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AdditionalAddresses) > 0 {\n\t\tfor _, e := range m.AdditionalAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor _, e := range m.Endpoints {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExcludeAdvertisedNetworks) > 0 {\n\t\tfor _, e := range m.ExcludeAdvertisedNetworks {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemberSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.NodeId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MachineType != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MachineType))\n\t}\n\tl = len(m.OperatingSystem)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ControlPlane != nil {\n\t\tl = m.ControlPlane.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AffiliateSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AffiliateSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AffiliateSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NodeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.Addresses[len(m.Addresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Addresses[len(m.Addresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nodename\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Nodename = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OperatingSystem\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OperatingSystem = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MachineType\", wireType)\n\t\t\t}\n\t\t\tm.MachineType = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MachineType |= enums.MachineType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KubeSpan\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.KubeSpan == nil {\n\t\t\t\tm.KubeSpan = &KubeSpanAffiliateSpec{}\n\t\t\t}\n\t\t\tif err := m.KubeSpan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControlPlane\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ControlPlane == nil {\n\t\t\t\tm.ControlPlane = &ControlPlane{}\n\t\t\t}\n\t\t\tif err := m.ControlPlane.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiscoveryEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DiscoveryEnabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryKubernetesEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RegistryKubernetesEnabled = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryServiceEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RegistryServiceEnabled = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ServiceEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceEndpointInsecure\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ServiceEndpointInsecure = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceEncryptionKey\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ServiceEncryptionKey = append(m.ServiceEncryptionKey[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.ServiceEncryptionKey == nil {\n\t\t\t\tm.ServiceEncryptionKey = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceClusterId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ServiceClusterId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ControlPlane) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControlPlane: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControlPlane: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiServerPort\", wireType)\n\t\t\t}\n\t\t\tm.ApiServerPort = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ApiServerPort |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *IdentitySpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: IdentitySpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: IdentitySpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NodeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *InfoSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: InfoSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: InfoSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubeSpanAffiliateSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubeSpanAffiliateSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubeSpanAffiliateSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PublicKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Address == nil {\n\t\t\t\tm.Address = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Address).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Address); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdditionalAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdditionalAddresses = append(m.AdditionalAddresses, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.AdditionalAddresses[len(m.AdditionalAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AdditionalAddresses[len(m.AdditionalAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoints = append(m.Endpoints, &common.NetIPPort{})\n\t\t\tif unmarshal, ok := interface{}(m.Endpoints[len(m.Endpoints)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoints[len(m.Endpoints)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExcludeAdvertisedNetworks\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExcludeAdvertisedNetworks = append(m.ExcludeAdvertisedNetworks, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.ExcludeAdvertisedNetworks[len(m.ExcludeAdvertisedNetworks)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExcludeAdvertisedNetworks[len(m.ExcludeAdvertisedNetworks)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MemberSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemberSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemberSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NodeId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.Addresses[len(m.Addresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Addresses[len(m.Addresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MachineType\", wireType)\n\t\t\t}\n\t\t\tm.MachineType = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MachineType |= enums.MachineType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OperatingSystem\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OperatingSystem = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControlPlane\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ControlPlane == nil {\n\t\t\t\tm.ControlPlane = &ControlPlane{}\n\t\t\t}\n\t\t\tif err := m.ControlPlane.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/cri/cri.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/cri/cri.proto\n\npackage cri\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tstructpb \"google.golang.org/protobuf/types/known/structpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ImageCacheConfigSpec represents the ImageCacheConfig.\ntype ImageCacheConfigSpec struct {\n\tstate         protoimpl.MessageState        `protogen:\"open.v1\"`\n\tStatus        enums.CriImageCacheStatus     `protobuf:\"varint,1,opt,name=status,proto3,enum=talos.resource.definitions.enums.CriImageCacheStatus\" json:\"status,omitempty\"`\n\tRoots         []string                      `protobuf:\"bytes,2,rep,name=roots,proto3\" json:\"roots,omitempty\"`\n\tCopyStatus    enums.CriImageCacheCopyStatus `protobuf:\"varint,3,opt,name=copy_status,json=copyStatus,proto3,enum=talos.resource.definitions.enums.CriImageCacheCopyStatus\" json:\"copy_status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageCacheConfigSpec) Reset() {\n\t*x = ImageCacheConfigSpec{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageCacheConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageCacheConfigSpec) ProtoMessage() {}\n\nfunc (x *ImageCacheConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageCacheConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ImageCacheConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ImageCacheConfigSpec) GetStatus() enums.CriImageCacheStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn enums.CriImageCacheStatus(0)\n}\n\nfunc (x *ImageCacheConfigSpec) GetRoots() []string {\n\tif x != nil {\n\t\treturn x.Roots\n\t}\n\treturn nil\n}\n\nfunc (x *ImageCacheConfigSpec) GetCopyStatus() enums.CriImageCacheCopyStatus {\n\tif x != nil {\n\t\treturn x.CopyStatus\n\t}\n\treturn enums.CriImageCacheCopyStatus(0)\n}\n\n// RegistriesConfigSpec describes status of rendered secrets.\ntype RegistriesConfigSpec struct {\n\tstate           protoimpl.MessageState           `protogen:\"open.v1\"`\n\tRegistryMirrors map[string]*RegistryMirrorConfig `protobuf:\"bytes,1,rep,name=registry_mirrors,json=registryMirrors,proto3\" json:\"registry_mirrors,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tRegistryAuths   map[string]*RegistryAuthConfig   `protobuf:\"bytes,2,rep,name=registry_auths,json=registryAuths,proto3\" json:\"registry_auths,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tRegistryTlSs    map[string]*RegistryTLSConfig    `protobuf:\"bytes,3,rep,name=registry_tl_ss,json=registryTlSs,proto3\" json:\"registry_tl_ss,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *RegistriesConfigSpec) Reset() {\n\t*x = RegistriesConfigSpec{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RegistriesConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RegistriesConfigSpec) ProtoMessage() {}\n\nfunc (x *RegistriesConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RegistriesConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*RegistriesConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *RegistriesConfigSpec) GetRegistryMirrors() map[string]*RegistryMirrorConfig {\n\tif x != nil {\n\t\treturn x.RegistryMirrors\n\t}\n\treturn nil\n}\n\nfunc (x *RegistriesConfigSpec) GetRegistryAuths() map[string]*RegistryAuthConfig {\n\tif x != nil {\n\t\treturn x.RegistryAuths\n\t}\n\treturn nil\n}\n\nfunc (x *RegistriesConfigSpec) GetRegistryTlSs() map[string]*RegistryTLSConfig {\n\tif x != nil {\n\t\treturn x.RegistryTlSs\n\t}\n\treturn nil\n}\n\n// RegistryAuthConfig specifies authentication configuration for a registry.\ntype RegistryAuthConfig struct {\n\tstate                 protoimpl.MessageState `protogen:\"open.v1\"`\n\tRegistryUsername      string                 `protobuf:\"bytes,1,opt,name=registry_username,json=registryUsername,proto3\" json:\"registry_username,omitempty\"`\n\tRegistryPassword      string                 `protobuf:\"bytes,2,opt,name=registry_password,json=registryPassword,proto3\" json:\"registry_password,omitempty\"`\n\tRegistryAuth          string                 `protobuf:\"bytes,3,opt,name=registry_auth,json=registryAuth,proto3\" json:\"registry_auth,omitempty\"`\n\tRegistryIdentityToken string                 `protobuf:\"bytes,4,opt,name=registry_identity_token,json=registryIdentityToken,proto3\" json:\"registry_identity_token,omitempty\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *RegistryAuthConfig) Reset() {\n\t*x = RegistryAuthConfig{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RegistryAuthConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RegistryAuthConfig) ProtoMessage() {}\n\nfunc (x *RegistryAuthConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RegistryAuthConfig.ProtoReflect.Descriptor instead.\nfunc (*RegistryAuthConfig) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *RegistryAuthConfig) GetRegistryUsername() string {\n\tif x != nil {\n\t\treturn x.RegistryUsername\n\t}\n\treturn \"\"\n}\n\nfunc (x *RegistryAuthConfig) GetRegistryPassword() string {\n\tif x != nil {\n\t\treturn x.RegistryPassword\n\t}\n\treturn \"\"\n}\n\nfunc (x *RegistryAuthConfig) GetRegistryAuth() string {\n\tif x != nil {\n\t\treturn x.RegistryAuth\n\t}\n\treturn \"\"\n}\n\nfunc (x *RegistryAuthConfig) GetRegistryIdentityToken() string {\n\tif x != nil {\n\t\treturn x.RegistryIdentityToken\n\t}\n\treturn \"\"\n}\n\n// RegistryEndpointConfig represents a single registry endpoint.\ntype RegistryEndpointConfig struct {\n\tstate                protoimpl.MessageState `protogen:\"open.v1\"`\n\tEndpointEndpoint     string                 `protobuf:\"bytes,1,opt,name=endpoint_endpoint,json=endpointEndpoint,proto3\" json:\"endpoint_endpoint,omitempty\"`\n\tEndpointOverridePath bool                   `protobuf:\"varint,2,opt,name=endpoint_override_path,json=endpointOverridePath,proto3\" json:\"endpoint_override_path,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *RegistryEndpointConfig) Reset() {\n\t*x = RegistryEndpointConfig{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RegistryEndpointConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RegistryEndpointConfig) ProtoMessage() {}\n\nfunc (x *RegistryEndpointConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RegistryEndpointConfig.ProtoReflect.Descriptor instead.\nfunc (*RegistryEndpointConfig) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RegistryEndpointConfig) GetEndpointEndpoint() string {\n\tif x != nil {\n\t\treturn x.EndpointEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *RegistryEndpointConfig) GetEndpointOverridePath() bool {\n\tif x != nil {\n\t\treturn x.EndpointOverridePath\n\t}\n\treturn false\n}\n\n// RegistryMirrorConfig represents mirror configuration for a registry.\ntype RegistryMirrorConfig struct {\n\tstate              protoimpl.MessageState    `protogen:\"open.v1\"`\n\tMirrorEndpoints    []*RegistryEndpointConfig `protobuf:\"bytes,1,rep,name=mirror_endpoints,json=mirrorEndpoints,proto3\" json:\"mirror_endpoints,omitempty\"`\n\tMirrorSkipFallback bool                      `protobuf:\"varint,3,opt,name=mirror_skip_fallback,json=mirrorSkipFallback,proto3\" json:\"mirror_skip_fallback,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *RegistryMirrorConfig) Reset() {\n\t*x = RegistryMirrorConfig{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RegistryMirrorConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RegistryMirrorConfig) ProtoMessage() {}\n\nfunc (x *RegistryMirrorConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RegistryMirrorConfig.ProtoReflect.Descriptor instead.\nfunc (*RegistryMirrorConfig) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *RegistryMirrorConfig) GetMirrorEndpoints() []*RegistryEndpointConfig {\n\tif x != nil {\n\t\treturn x.MirrorEndpoints\n\t}\n\treturn nil\n}\n\nfunc (x *RegistryMirrorConfig) GetMirrorSkipFallback() bool {\n\tif x != nil {\n\t\treturn x.MirrorSkipFallback\n\t}\n\treturn false\n}\n\n// RegistryTLSConfig specifies TLS config for HTTPS registries.\ntype RegistryTLSConfig struct {\n\tstate                 protoimpl.MessageState              `protogen:\"open.v1\"`\n\tTlsClientIdentity     *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=tls_client_identity,json=tlsClientIdentity,proto3\" json:\"tls_client_identity,omitempty\"`\n\tTlsca                 []byte                              `protobuf:\"bytes,2,opt,name=tlsca,proto3\" json:\"tlsca,omitempty\"`\n\tTlsInsecureSkipVerify bool                                `protobuf:\"varint,3,opt,name=tls_insecure_skip_verify,json=tlsInsecureSkipVerify,proto3\" json:\"tls_insecure_skip_verify,omitempty\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *RegistryTLSConfig) Reset() {\n\t*x = RegistryTLSConfig{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RegistryTLSConfig) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RegistryTLSConfig) ProtoMessage() {}\n\nfunc (x *RegistryTLSConfig) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RegistryTLSConfig.ProtoReflect.Descriptor instead.\nfunc (*RegistryTLSConfig) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *RegistryTLSConfig) GetTlsClientIdentity() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.TlsClientIdentity\n\t}\n\treturn nil\n}\n\nfunc (x *RegistryTLSConfig) GetTlsca() []byte {\n\tif x != nil {\n\t\treturn x.Tlsca\n\t}\n\treturn nil\n}\n\nfunc (x *RegistryTLSConfig) GetTlsInsecureSkipVerify() bool {\n\tif x != nil {\n\t\treturn x.TlsInsecureSkipVerify\n\t}\n\treturn false\n}\n\n// SeccompProfileSpec represents the SeccompProfile.\ntype SeccompProfileSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tValue         *structpb.Struct       `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SeccompProfileSpec) Reset() {\n\t*x = SeccompProfileSpec{}\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SeccompProfileSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SeccompProfileSpec) ProtoMessage() {}\n\nfunc (x *SeccompProfileSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_cri_cri_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SeccompProfileSpec.ProtoReflect.Descriptor instead.\nfunc (*SeccompProfileSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_cri_cri_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *SeccompProfileSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *SeccompProfileSpec) GetValue() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_cri_cri_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_cri_cri_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\\"resource/definitions/cri/cri.proto\\x12\\x1etalos.resource.definitions.cri\\x1a\\x13common/common.proto\\x1a\\x1cgoogle/protobuf/struct.proto\\x1a&resource/definitions/enums/enums.proto\\\"\\xd7\\x01\\n\" +\n\t\"\\x14ImageCacheConfigSpec\\x12M\\n\" +\n\t\"\\x06status\\x18\\x01 \\x01(\\x0e25.talos.resource.definitions.enums.CriImageCacheStatusR\\x06status\\x12\\x14\\n\" +\n\t\"\\x05roots\\x18\\x02 \\x03(\\tR\\x05roots\\x12Z\\n\" +\n\t\"\\vcopy_status\\x18\\x03 \\x01(\\x0e29.talos.resource.definitions.enums.CriImageCacheCopyStatusR\\n\" +\n\t\"copyStatus\\\"\\xce\\x05\\n\" +\n\t\"\\x14RegistriesConfigSpec\\x12t\\n\" +\n\t\"\\x10registry_mirrors\\x18\\x01 \\x03(\\v2I.talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntryR\\x0fregistryMirrors\\x12n\\n\" +\n\t\"\\x0eregistry_auths\\x18\\x02 \\x03(\\v2G.talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntryR\\rregistryAuths\\x12l\\n\" +\n\t\"\\x0eregistry_tl_ss\\x18\\x03 \\x03(\\v2F.talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntryR\\fregistryTlSs\\x1ax\\n\" +\n\t\"\\x14RegistryMirrorsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12J\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v24.talos.resource.definitions.cri.RegistryMirrorConfigR\\x05value:\\x028\\x01\\x1at\\n\" +\n\t\"\\x12RegistryAuthsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12H\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v22.talos.resource.definitions.cri.RegistryAuthConfigR\\x05value:\\x028\\x01\\x1ar\\n\" +\n\t\"\\x11RegistryTlSsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12G\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v21.talos.resource.definitions.cri.RegistryTLSConfigR\\x05value:\\x028\\x01\\\"\\xcb\\x01\\n\" +\n\t\"\\x12RegistryAuthConfig\\x12+\\n\" +\n\t\"\\x11registry_username\\x18\\x01 \\x01(\\tR\\x10registryUsername\\x12+\\n\" +\n\t\"\\x11registry_password\\x18\\x02 \\x01(\\tR\\x10registryPassword\\x12#\\n\" +\n\t\"\\rregistry_auth\\x18\\x03 \\x01(\\tR\\fregistryAuth\\x126\\n\" +\n\t\"\\x17registry_identity_token\\x18\\x04 \\x01(\\tR\\x15registryIdentityToken\\\"{\\n\" +\n\t\"\\x16RegistryEndpointConfig\\x12+\\n\" +\n\t\"\\x11endpoint_endpoint\\x18\\x01 \\x01(\\tR\\x10endpointEndpoint\\x124\\n\" +\n\t\"\\x16endpoint_override_path\\x18\\x02 \\x01(\\bR\\x14endpointOverridePath\\\"\\xab\\x01\\n\" +\n\t\"\\x14RegistryMirrorConfig\\x12a\\n\" +\n\t\"\\x10mirror_endpoints\\x18\\x01 \\x03(\\v26.talos.resource.definitions.cri.RegistryEndpointConfigR\\x0fmirrorEndpoints\\x120\\n\" +\n\t\"\\x14mirror_skip_fallback\\x18\\x03 \\x01(\\bR\\x12mirrorSkipFallback\\\"\\xb7\\x01\\n\" +\n\t\"\\x11RegistryTLSConfig\\x12S\\n\" +\n\t\"\\x13tls_client_identity\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x11tlsClientIdentity\\x12\\x14\\n\" +\n\t\"\\x05tlsca\\x18\\x02 \\x01(\\fR\\x05tlsca\\x127\\n\" +\n\t\"\\x18tls_insecure_skip_verify\\x18\\x03 \\x01(\\bR\\x15tlsInsecureSkipVerify\\\"W\\n\" +\n\t\"\\x12SeccompProfileSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12-\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2\\x17.google.protobuf.StructR\\x05valueBp\\n\" +\n\t\"&dev.talos.api.resource.definitions.criZFgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/crib\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_cri_cri_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_cri_cri_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_cri_cri_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_cri_cri_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_cri_cri_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_cri_cri_proto_rawDesc), len(file_resource_definitions_cri_cri_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_cri_cri_proto_rawDescData\n}\n\nvar file_resource_definitions_cri_cri_proto_msgTypes = make([]protoimpl.MessageInfo, 10)\nvar file_resource_definitions_cri_cri_proto_goTypes = []any{\n\t(*ImageCacheConfigSpec)(nil),       // 0: talos.resource.definitions.cri.ImageCacheConfigSpec\n\t(*RegistriesConfigSpec)(nil),       // 1: talos.resource.definitions.cri.RegistriesConfigSpec\n\t(*RegistryAuthConfig)(nil),         // 2: talos.resource.definitions.cri.RegistryAuthConfig\n\t(*RegistryEndpointConfig)(nil),     // 3: talos.resource.definitions.cri.RegistryEndpointConfig\n\t(*RegistryMirrorConfig)(nil),       // 4: talos.resource.definitions.cri.RegistryMirrorConfig\n\t(*RegistryTLSConfig)(nil),          // 5: talos.resource.definitions.cri.RegistryTLSConfig\n\t(*SeccompProfileSpec)(nil),         // 6: talos.resource.definitions.cri.SeccompProfileSpec\n\tnil,                                // 7: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry\n\tnil,                                // 8: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry\n\tnil,                                // 9: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry\n\t(enums.CriImageCacheStatus)(0),     // 10: talos.resource.definitions.enums.CriImageCacheStatus\n\t(enums.CriImageCacheCopyStatus)(0), // 11: talos.resource.definitions.enums.CriImageCacheCopyStatus\n\t(*common.PEMEncodedCertificateAndKey)(nil), // 12: common.PEMEncodedCertificateAndKey\n\t(*structpb.Struct)(nil),                    // 13: google.protobuf.Struct\n}\nvar file_resource_definitions_cri_cri_proto_depIdxs = []int32{\n\t10, // 0: talos.resource.definitions.cri.ImageCacheConfigSpec.status:type_name -> talos.resource.definitions.enums.CriImageCacheStatus\n\t11, // 1: talos.resource.definitions.cri.ImageCacheConfigSpec.copy_status:type_name -> talos.resource.definitions.enums.CriImageCacheCopyStatus\n\t7,  // 2: talos.resource.definitions.cri.RegistriesConfigSpec.registry_mirrors:type_name -> talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry\n\t8,  // 3: talos.resource.definitions.cri.RegistriesConfigSpec.registry_auths:type_name -> talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry\n\t9,  // 4: talos.resource.definitions.cri.RegistriesConfigSpec.registry_tl_ss:type_name -> talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry\n\t3,  // 5: talos.resource.definitions.cri.RegistryMirrorConfig.mirror_endpoints:type_name -> talos.resource.definitions.cri.RegistryEndpointConfig\n\t12, // 6: talos.resource.definitions.cri.RegistryTLSConfig.tls_client_identity:type_name -> common.PEMEncodedCertificateAndKey\n\t13, // 7: talos.resource.definitions.cri.SeccompProfileSpec.value:type_name -> google.protobuf.Struct\n\t4,  // 8: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry.value:type_name -> talos.resource.definitions.cri.RegistryMirrorConfig\n\t2,  // 9: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry.value:type_name -> talos.resource.definitions.cri.RegistryAuthConfig\n\t5,  // 10: talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry.value:type_name -> talos.resource.definitions.cri.RegistryTLSConfig\n\t11, // [11:11] is the sub-list for method output_type\n\t11, // [11:11] is the sub-list for method input_type\n\t11, // [11:11] is the sub-list for extension type_name\n\t11, // [11:11] is the sub-list for extension extendee\n\t0,  // [0:11] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_cri_cri_proto_init() }\nfunc file_resource_definitions_cri_cri_proto_init() {\n\tif File_resource_definitions_cri_cri_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_cri_cri_proto_rawDesc), len(file_resource_definitions_cri_cri_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   10,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_cri_cri_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_cri_cri_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_cri_cri_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_cri_cri_proto = out.File\n\tfile_resource_definitions_cri_cri_proto_goTypes = nil\n\tfile_resource_definitions_cri_cri_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/cri/cri_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/cri/cri.proto\n\npackage cri\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tstructpb \"github.com/planetscale/vtprotobuf/types/known/structpb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tstructpb1 \"google.golang.org/protobuf/types/known/structpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ImageCacheConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageCacheConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageCacheConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.CopyStatus != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CopyStatus))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Roots) > 0 {\n\t\tfor iNdEx := len(m.Roots) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Roots[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Roots[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Roots[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Status != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RegistriesConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RegistriesConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RegistriesConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.RegistryTlSs) > 0 {\n\t\tfor k := range m.RegistryTlSs {\n\t\t\tv := m.RegistryTlSs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.RegistryAuths) > 0 {\n\t\tfor k := range m.RegistryAuths {\n\t\t\tv := m.RegistryAuths[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.RegistryMirrors) > 0 {\n\t\tfor k := range m.RegistryMirrors {\n\t\t\tv := m.RegistryMirrors[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RegistryAuthConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RegistryAuthConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RegistryAuthConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.RegistryIdentityToken) > 0 {\n\t\ti -= len(m.RegistryIdentityToken)\n\t\tcopy(dAtA[i:], m.RegistryIdentityToken)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RegistryIdentityToken)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.RegistryAuth) > 0 {\n\t\ti -= len(m.RegistryAuth)\n\t\tcopy(dAtA[i:], m.RegistryAuth)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RegistryAuth)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.RegistryPassword) > 0 {\n\t\ti -= len(m.RegistryPassword)\n\t\tcopy(dAtA[i:], m.RegistryPassword)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RegistryPassword)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.RegistryUsername) > 0 {\n\t\ti -= len(m.RegistryUsername)\n\t\tcopy(dAtA[i:], m.RegistryUsername)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.RegistryUsername)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RegistryEndpointConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RegistryEndpointConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RegistryEndpointConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.EndpointOverridePath {\n\t\ti--\n\t\tif m.EndpointOverridePath {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.EndpointEndpoint) > 0 {\n\t\ti -= len(m.EndpointEndpoint)\n\t\tcopy(dAtA[i:], m.EndpointEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.EndpointEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RegistryMirrorConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RegistryMirrorConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RegistryMirrorConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MirrorSkipFallback {\n\t\ti--\n\t\tif m.MirrorSkipFallback {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.MirrorEndpoints) > 0 {\n\t\tfor iNdEx := len(m.MirrorEndpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.MirrorEndpoints[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RegistryTLSConfig) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RegistryTLSConfig) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RegistryTLSConfig) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TlsInsecureSkipVerify {\n\t\ti--\n\t\tif m.TlsInsecureSkipVerify {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Tlsca) > 0 {\n\t\ti -= len(m.Tlsca)\n\t\tcopy(dAtA[i:], m.Tlsca)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Tlsca)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.TlsClientIdentity != nil {\n\t\tif vtmsg, ok := interface{}(m.TlsClientIdentity).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.TlsClientIdentity)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SeccompProfileSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SeccompProfileSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SeccompProfileSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Value != nil {\n\t\tsize, err := (*structpb.Struct)(m.Value).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageCacheConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Status != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Status))\n\t}\n\tif len(m.Roots) > 0 {\n\t\tfor _, s := range m.Roots {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.CopyStatus != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CopyStatus))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RegistriesConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.RegistryMirrors) > 0 {\n\t\tfor k, v := range m.RegistryMirrors {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.RegistryAuths) > 0 {\n\t\tfor k, v := range m.RegistryAuths {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.RegistryTlSs) > 0 {\n\t\tfor k, v := range m.RegistryTlSs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RegistryAuthConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.RegistryUsername)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.RegistryPassword)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.RegistryAuth)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.RegistryIdentityToken)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RegistryEndpointConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.EndpointEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EndpointOverridePath {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RegistryMirrorConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.MirrorEndpoints) > 0 {\n\t\tfor _, e := range m.MirrorEndpoints {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.MirrorSkipFallback {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RegistryTLSConfig) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.TlsClientIdentity != nil {\n\t\tif size, ok := interface{}(m.TlsClientIdentity).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.TlsClientIdentity)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Tlsca)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.TlsInsecureSkipVerify {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SeccompProfileSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Value != nil {\n\t\tl = (*structpb.Struct)(m.Value).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageCacheConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageCacheConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageCacheConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tm.Status = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Status |= enums.CriImageCacheStatus(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Roots\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Roots = append(m.Roots, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CopyStatus\", wireType)\n\t\t\t}\n\t\t\tm.CopyStatus = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CopyStatus |= enums.CriImageCacheCopyStatus(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RegistriesConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RegistriesConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RegistriesConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryMirrors\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.RegistryMirrors == nil {\n\t\t\t\tm.RegistryMirrors = make(map[string]*RegistryMirrorConfig)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *RegistryMirrorConfig\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &RegistryMirrorConfig{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RegistryMirrors[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryAuths\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.RegistryAuths == nil {\n\t\t\t\tm.RegistryAuths = make(map[string]*RegistryAuthConfig)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *RegistryAuthConfig\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &RegistryAuthConfig{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RegistryAuths[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryTlSs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.RegistryTlSs == nil {\n\t\t\t\tm.RegistryTlSs = make(map[string]*RegistryTLSConfig)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *RegistryTLSConfig\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &RegistryTLSConfig{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RegistryTlSs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RegistryAuthConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryAuthConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryAuthConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryUsername\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RegistryUsername = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryPassword\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RegistryPassword = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryAuth\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RegistryAuth = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RegistryIdentityToken\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.RegistryIdentityToken = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RegistryEndpointConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryEndpointConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryEndpointConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EndpointEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.EndpointEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EndpointOverridePath\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EndpointOverridePath = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RegistryMirrorConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryMirrorConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryMirrorConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MirrorEndpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MirrorEndpoints = append(m.MirrorEndpoints, &RegistryEndpointConfig{})\n\t\t\tif err := m.MirrorEndpoints[len(m.MirrorEndpoints)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MirrorSkipFallback\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.MirrorSkipFallback = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RegistryTLSConfig) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryTLSConfig: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RegistryTLSConfig: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TlsClientIdentity\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.TlsClientIdentity == nil {\n\t\t\t\tm.TlsClientIdentity = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.TlsClientIdentity).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.TlsClientIdentity); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tlsca\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Tlsca = append(m.Tlsca[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Tlsca == nil {\n\t\t\t\tm.Tlsca = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TlsInsecureSkipVerify\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TlsInsecureSkipVerify = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SeccompProfileSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SeccompProfileSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SeccompProfileSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Value == nil {\n\t\t\t\tm.Value = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Value).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/enums/enums.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/enums/enums.proto\n\npackage enums\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// RuntimeMachineStage describes the stage of the machine boot/run process.\ntype RuntimeMachineStage int32\n\nconst (\n\tRuntimeMachineStage_MACHINE_STAGE_UNKNOWN       RuntimeMachineStage = 0\n\tRuntimeMachineStage_MACHINE_STAGE_BOOTING       RuntimeMachineStage = 1\n\tRuntimeMachineStage_MACHINE_STAGE_INSTALLING    RuntimeMachineStage = 2\n\tRuntimeMachineStage_MACHINE_STAGE_MAINTENANCE   RuntimeMachineStage = 3\n\tRuntimeMachineStage_MACHINE_STAGE_RUNNING       RuntimeMachineStage = 4\n\tRuntimeMachineStage_MACHINE_STAGE_REBOOTING     RuntimeMachineStage = 5\n\tRuntimeMachineStage_MACHINE_STAGE_SHUTTING_DOWN RuntimeMachineStage = 6\n\tRuntimeMachineStage_MACHINE_STAGE_RESETTING     RuntimeMachineStage = 7\n\tRuntimeMachineStage_MACHINE_STAGE_UPGRADING     RuntimeMachineStage = 8\n)\n\n// Enum value maps for RuntimeMachineStage.\nvar (\n\tRuntimeMachineStage_name = map[int32]string{\n\t\t0: \"MACHINE_STAGE_UNKNOWN\",\n\t\t1: \"MACHINE_STAGE_BOOTING\",\n\t\t2: \"MACHINE_STAGE_INSTALLING\",\n\t\t3: \"MACHINE_STAGE_MAINTENANCE\",\n\t\t4: \"MACHINE_STAGE_RUNNING\",\n\t\t5: \"MACHINE_STAGE_REBOOTING\",\n\t\t6: \"MACHINE_STAGE_SHUTTING_DOWN\",\n\t\t7: \"MACHINE_STAGE_RESETTING\",\n\t\t8: \"MACHINE_STAGE_UPGRADING\",\n\t}\n\tRuntimeMachineStage_value = map[string]int32{\n\t\t\"MACHINE_STAGE_UNKNOWN\":       0,\n\t\t\"MACHINE_STAGE_BOOTING\":       1,\n\t\t\"MACHINE_STAGE_INSTALLING\":    2,\n\t\t\"MACHINE_STAGE_MAINTENANCE\":   3,\n\t\t\"MACHINE_STAGE_RUNNING\":       4,\n\t\t\"MACHINE_STAGE_REBOOTING\":     5,\n\t\t\"MACHINE_STAGE_SHUTTING_DOWN\": 6,\n\t\t\"MACHINE_STAGE_RESETTING\":     7,\n\t\t\"MACHINE_STAGE_UPGRADING\":     8,\n\t}\n)\n\nfunc (x RuntimeMachineStage) Enum() *RuntimeMachineStage {\n\tp := new(RuntimeMachineStage)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeMachineStage) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeMachineStage) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[0].Descriptor()\n}\n\nfunc (RuntimeMachineStage) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[0]\n}\n\nfunc (x RuntimeMachineStage) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeMachineStage.Descriptor instead.\nfunc (RuntimeMachineStage) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{0}\n}\n\n// RuntimeSELinuxState describes the current SELinux status.\ntype RuntimeSELinuxState int32\n\nconst (\n\tRuntimeSELinuxState_SE_LINUX_STATE_DISABLED   RuntimeSELinuxState = 0\n\tRuntimeSELinuxState_SE_LINUX_STATE_PERMISSIVE RuntimeSELinuxState = 1\n\tRuntimeSELinuxState_SE_LINUX_STATE_ENFORCING  RuntimeSELinuxState = 2\n)\n\n// Enum value maps for RuntimeSELinuxState.\nvar (\n\tRuntimeSELinuxState_name = map[int32]string{\n\t\t0: \"SE_LINUX_STATE_DISABLED\",\n\t\t1: \"SE_LINUX_STATE_PERMISSIVE\",\n\t\t2: \"SE_LINUX_STATE_ENFORCING\",\n\t}\n\tRuntimeSELinuxState_value = map[string]int32{\n\t\t\"SE_LINUX_STATE_DISABLED\":   0,\n\t\t\"SE_LINUX_STATE_PERMISSIVE\": 1,\n\t\t\"SE_LINUX_STATE_ENFORCING\":  2,\n\t}\n)\n\nfunc (x RuntimeSELinuxState) Enum() *RuntimeSELinuxState {\n\tp := new(RuntimeSELinuxState)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeSELinuxState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeSELinuxState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[1].Descriptor()\n}\n\nfunc (RuntimeSELinuxState) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[1]\n}\n\nfunc (x RuntimeSELinuxState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeSELinuxState.Descriptor instead.\nfunc (RuntimeSELinuxState) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{1}\n}\n\n// RuntimeFIPSState describes the current FIPS status.\ntype RuntimeFIPSState int32\n\nconst (\n\tRuntimeFIPSState_FIPS_STATE_DISABLED RuntimeFIPSState = 0\n\tRuntimeFIPSState_FIPS_STATE_ENABLED  RuntimeFIPSState = 1\n\tRuntimeFIPSState_FIPS_STATE_STRICT   RuntimeFIPSState = 2\n)\n\n// Enum value maps for RuntimeFIPSState.\nvar (\n\tRuntimeFIPSState_name = map[int32]string{\n\t\t0: \"FIPS_STATE_DISABLED\",\n\t\t1: \"FIPS_STATE_ENABLED\",\n\t\t2: \"FIPS_STATE_STRICT\",\n\t}\n\tRuntimeFIPSState_value = map[string]int32{\n\t\t\"FIPS_STATE_DISABLED\": 0,\n\t\t\"FIPS_STATE_ENABLED\":  1,\n\t\t\"FIPS_STATE_STRICT\":   2,\n\t}\n)\n\nfunc (x RuntimeFIPSState) Enum() *RuntimeFIPSState {\n\tp := new(RuntimeFIPSState)\n\t*p = x\n\treturn p\n}\n\nfunc (x RuntimeFIPSState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (RuntimeFIPSState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[2].Descriptor()\n}\n\nfunc (RuntimeFIPSState) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[2]\n}\n\nfunc (x RuntimeFIPSState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use RuntimeFIPSState.Descriptor instead.\nfunc (RuntimeFIPSState) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{2}\n}\n\n// MachineType represents a machine type.\ntype MachineType int32\n\nconst (\n\t// TypeUnknown represents undefined node type, when there is no machine configuration yet.\n\tMachineType_TYPE_UNKNOWN MachineType = 0\n\t// TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node.\n\t// This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc.\n\tMachineType_TYPE_INIT MachineType = 1\n\t// TypeControlPlane designates the node as a control plane member.\n\t// This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\n\tMachineType_TYPE_CONTROL_PLANE MachineType = 2\n\t// TypeWorker designates the node as a worker node.\n\t// This means it will be an available compute node for scheduling workloads.\n\tMachineType_TYPE_WORKER MachineType = 3\n)\n\n// Enum value maps for MachineType.\nvar (\n\tMachineType_name = map[int32]string{\n\t\t0: \"TYPE_UNKNOWN\",\n\t\t1: \"TYPE_INIT\",\n\t\t2: \"TYPE_CONTROL_PLANE\",\n\t\t3: \"TYPE_WORKER\",\n\t}\n\tMachineType_value = map[string]int32{\n\t\t\"TYPE_UNKNOWN\":       0,\n\t\t\"TYPE_INIT\":          1,\n\t\t\"TYPE_CONTROL_PLANE\": 2,\n\t\t\"TYPE_WORKER\":        3,\n\t}\n)\n\nfunc (x MachineType) Enum() *MachineType {\n\tp := new(MachineType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MachineType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MachineType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[3].Descriptor()\n}\n\nfunc (MachineType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[3]\n}\n\nfunc (x MachineType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use MachineType.Descriptor instead.\nfunc (MachineType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{3}\n}\n\n// NethelpersAddressFlag wraps IFF_* constants.\ntype NethelpersAddressFlag int32\n\nconst (\n\tNethelpersAddressFlag_NETHELPERS_ADDRESSFLAG_UNSPECIFIED NethelpersAddressFlag = 0\n\tNethelpersAddressFlag_ADDRESS_TEMPORARY                  NethelpersAddressFlag = 1\n\tNethelpersAddressFlag_ADDRESS_NO_DAD                     NethelpersAddressFlag = 2\n\tNethelpersAddressFlag_ADDRESS_OPTIMISTIC                 NethelpersAddressFlag = 4\n\tNethelpersAddressFlag_ADDRESS_DAD_FAILED                 NethelpersAddressFlag = 8\n\tNethelpersAddressFlag_ADDRESS_HOME                       NethelpersAddressFlag = 16\n\tNethelpersAddressFlag_ADDRESS_DEPRECATED                 NethelpersAddressFlag = 32\n\tNethelpersAddressFlag_ADDRESS_TENTATIVE                  NethelpersAddressFlag = 64\n\tNethelpersAddressFlag_ADDRESS_PERMANENT                  NethelpersAddressFlag = 128\n\tNethelpersAddressFlag_ADDRESS_MANAGEMENT_TEMP            NethelpersAddressFlag = 256\n\tNethelpersAddressFlag_ADDRESS_NO_PREFIX_ROUTE            NethelpersAddressFlag = 512\n\tNethelpersAddressFlag_ADDRESS_MC_AUTO_JOIN               NethelpersAddressFlag = 1024\n\tNethelpersAddressFlag_ADDRESS_STABLE_PRIVACY             NethelpersAddressFlag = 2048\n)\n\n// Enum value maps for NethelpersAddressFlag.\nvar (\n\tNethelpersAddressFlag_name = map[int32]string{\n\t\t0:    \"NETHELPERS_ADDRESSFLAG_UNSPECIFIED\",\n\t\t1:    \"ADDRESS_TEMPORARY\",\n\t\t2:    \"ADDRESS_NO_DAD\",\n\t\t4:    \"ADDRESS_OPTIMISTIC\",\n\t\t8:    \"ADDRESS_DAD_FAILED\",\n\t\t16:   \"ADDRESS_HOME\",\n\t\t32:   \"ADDRESS_DEPRECATED\",\n\t\t64:   \"ADDRESS_TENTATIVE\",\n\t\t128:  \"ADDRESS_PERMANENT\",\n\t\t256:  \"ADDRESS_MANAGEMENT_TEMP\",\n\t\t512:  \"ADDRESS_NO_PREFIX_ROUTE\",\n\t\t1024: \"ADDRESS_MC_AUTO_JOIN\",\n\t\t2048: \"ADDRESS_STABLE_PRIVACY\",\n\t}\n\tNethelpersAddressFlag_value = map[string]int32{\n\t\t\"NETHELPERS_ADDRESSFLAG_UNSPECIFIED\": 0,\n\t\t\"ADDRESS_TEMPORARY\":                  1,\n\t\t\"ADDRESS_NO_DAD\":                     2,\n\t\t\"ADDRESS_OPTIMISTIC\":                 4,\n\t\t\"ADDRESS_DAD_FAILED\":                 8,\n\t\t\"ADDRESS_HOME\":                       16,\n\t\t\"ADDRESS_DEPRECATED\":                 32,\n\t\t\"ADDRESS_TENTATIVE\":                  64,\n\t\t\"ADDRESS_PERMANENT\":                  128,\n\t\t\"ADDRESS_MANAGEMENT_TEMP\":            256,\n\t\t\"ADDRESS_NO_PREFIX_ROUTE\":            512,\n\t\t\"ADDRESS_MC_AUTO_JOIN\":               1024,\n\t\t\"ADDRESS_STABLE_PRIVACY\":             2048,\n\t}\n)\n\nfunc (x NethelpersAddressFlag) Enum() *NethelpersAddressFlag {\n\tp := new(NethelpersAddressFlag)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersAddressFlag) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersAddressFlag) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[4].Descriptor()\n}\n\nfunc (NethelpersAddressFlag) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[4]\n}\n\nfunc (x NethelpersAddressFlag) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersAddressFlag.Descriptor instead.\nfunc (NethelpersAddressFlag) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{4}\n}\n\n// NethelpersAddressSortAlgorithm is an internal address sorting algorithm.\ntype NethelpersAddressSortAlgorithm int32\n\nconst (\n\tNethelpersAddressSortAlgorithm_ADDRESS_SORT_ALGORITHM_V1 NethelpersAddressSortAlgorithm = 0\n\tNethelpersAddressSortAlgorithm_ADDRESS_SORT_ALGORITHM_V2 NethelpersAddressSortAlgorithm = 1\n)\n\n// Enum value maps for NethelpersAddressSortAlgorithm.\nvar (\n\tNethelpersAddressSortAlgorithm_name = map[int32]string{\n\t\t0: \"ADDRESS_SORT_ALGORITHM_V1\",\n\t\t1: \"ADDRESS_SORT_ALGORITHM_V2\",\n\t}\n\tNethelpersAddressSortAlgorithm_value = map[string]int32{\n\t\t\"ADDRESS_SORT_ALGORITHM_V1\": 0,\n\t\t\"ADDRESS_SORT_ALGORITHM_V2\": 1,\n\t}\n)\n\nfunc (x NethelpersAddressSortAlgorithm) Enum() *NethelpersAddressSortAlgorithm {\n\tp := new(NethelpersAddressSortAlgorithm)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersAddressSortAlgorithm) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersAddressSortAlgorithm) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[5].Descriptor()\n}\n\nfunc (NethelpersAddressSortAlgorithm) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[5]\n}\n\nfunc (x NethelpersAddressSortAlgorithm) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersAddressSortAlgorithm.Descriptor instead.\nfunc (NethelpersAddressSortAlgorithm) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{5}\n}\n\n// NethelpersADLACPActive is ADLACPActive.\ntype NethelpersADLACPActive int32\n\nconst (\n\tNethelpersADLACPActive_ADLACP_ACTIVE_OFF NethelpersADLACPActive = 0\n\tNethelpersADLACPActive_ADLACP_ACTIVE_ON  NethelpersADLACPActive = 1\n)\n\n// Enum value maps for NethelpersADLACPActive.\nvar (\n\tNethelpersADLACPActive_name = map[int32]string{\n\t\t0: \"ADLACP_ACTIVE_OFF\",\n\t\t1: \"ADLACP_ACTIVE_ON\",\n\t}\n\tNethelpersADLACPActive_value = map[string]int32{\n\t\t\"ADLACP_ACTIVE_OFF\": 0,\n\t\t\"ADLACP_ACTIVE_ON\":  1,\n\t}\n)\n\nfunc (x NethelpersADLACPActive) Enum() *NethelpersADLACPActive {\n\tp := new(NethelpersADLACPActive)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersADLACPActive) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersADLACPActive) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[6].Descriptor()\n}\n\nfunc (NethelpersADLACPActive) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[6]\n}\n\nfunc (x NethelpersADLACPActive) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersADLACPActive.Descriptor instead.\nfunc (NethelpersADLACPActive) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{6}\n}\n\n// NethelpersADSelect is ADSelect.\ntype NethelpersADSelect int32\n\nconst (\n\tNethelpersADSelect_AD_SELECT_STABLE    NethelpersADSelect = 0\n\tNethelpersADSelect_AD_SELECT_BANDWIDTH NethelpersADSelect = 1\n\tNethelpersADSelect_AD_SELECT_COUNT     NethelpersADSelect = 2\n)\n\n// Enum value maps for NethelpersADSelect.\nvar (\n\tNethelpersADSelect_name = map[int32]string{\n\t\t0: \"AD_SELECT_STABLE\",\n\t\t1: \"AD_SELECT_BANDWIDTH\",\n\t\t2: \"AD_SELECT_COUNT\",\n\t}\n\tNethelpersADSelect_value = map[string]int32{\n\t\t\"AD_SELECT_STABLE\":    0,\n\t\t\"AD_SELECT_BANDWIDTH\": 1,\n\t\t\"AD_SELECT_COUNT\":     2,\n\t}\n)\n\nfunc (x NethelpersADSelect) Enum() *NethelpersADSelect {\n\tp := new(NethelpersADSelect)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersADSelect) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersADSelect) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[7].Descriptor()\n}\n\nfunc (NethelpersADSelect) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[7]\n}\n\nfunc (x NethelpersADSelect) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersADSelect.Descriptor instead.\nfunc (NethelpersADSelect) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{7}\n}\n\n// NethelpersARPAllTargets is an ARP targets mode.\ntype NethelpersARPAllTargets int32\n\nconst (\n\tNethelpersARPAllTargets_ARP_ALL_TARGETS_ANY NethelpersARPAllTargets = 0\n\tNethelpersARPAllTargets_ARP_ALL_TARGETS_ALL NethelpersARPAllTargets = 1\n)\n\n// Enum value maps for NethelpersARPAllTargets.\nvar (\n\tNethelpersARPAllTargets_name = map[int32]string{\n\t\t0: \"ARP_ALL_TARGETS_ANY\",\n\t\t1: \"ARP_ALL_TARGETS_ALL\",\n\t}\n\tNethelpersARPAllTargets_value = map[string]int32{\n\t\t\"ARP_ALL_TARGETS_ANY\": 0,\n\t\t\"ARP_ALL_TARGETS_ALL\": 1,\n\t}\n)\n\nfunc (x NethelpersARPAllTargets) Enum() *NethelpersARPAllTargets {\n\tp := new(NethelpersARPAllTargets)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersARPAllTargets) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersARPAllTargets) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[8].Descriptor()\n}\n\nfunc (NethelpersARPAllTargets) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[8]\n}\n\nfunc (x NethelpersARPAllTargets) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersARPAllTargets.Descriptor instead.\nfunc (NethelpersARPAllTargets) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{8}\n}\n\n// NethelpersARPValidate is an ARP Validation mode.\ntype NethelpersARPValidate int32\n\nconst (\n\tNethelpersARPValidate_ARP_VALIDATE_NONE          NethelpersARPValidate = 0\n\tNethelpersARPValidate_ARP_VALIDATE_ACTIVE        NethelpersARPValidate = 1\n\tNethelpersARPValidate_ARP_VALIDATE_BACKUP        NethelpersARPValidate = 2\n\tNethelpersARPValidate_ARP_VALIDATE_ALL           NethelpersARPValidate = 3\n\tNethelpersARPValidate_ARP_VALIDATE_FILTER        NethelpersARPValidate = 4\n\tNethelpersARPValidate_ARP_VALIDATE_FILTER_ACTIVE NethelpersARPValidate = 5\n\tNethelpersARPValidate_ARP_VALIDATE_FILTER_BACKUP NethelpersARPValidate = 6\n)\n\n// Enum value maps for NethelpersARPValidate.\nvar (\n\tNethelpersARPValidate_name = map[int32]string{\n\t\t0: \"ARP_VALIDATE_NONE\",\n\t\t1: \"ARP_VALIDATE_ACTIVE\",\n\t\t2: \"ARP_VALIDATE_BACKUP\",\n\t\t3: \"ARP_VALIDATE_ALL\",\n\t\t4: \"ARP_VALIDATE_FILTER\",\n\t\t5: \"ARP_VALIDATE_FILTER_ACTIVE\",\n\t\t6: \"ARP_VALIDATE_FILTER_BACKUP\",\n\t}\n\tNethelpersARPValidate_value = map[string]int32{\n\t\t\"ARP_VALIDATE_NONE\":          0,\n\t\t\"ARP_VALIDATE_ACTIVE\":        1,\n\t\t\"ARP_VALIDATE_BACKUP\":        2,\n\t\t\"ARP_VALIDATE_ALL\":           3,\n\t\t\"ARP_VALIDATE_FILTER\":        4,\n\t\t\"ARP_VALIDATE_FILTER_ACTIVE\": 5,\n\t\t\"ARP_VALIDATE_FILTER_BACKUP\": 6,\n\t}\n)\n\nfunc (x NethelpersARPValidate) Enum() *NethelpersARPValidate {\n\tp := new(NethelpersARPValidate)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersARPValidate) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersARPValidate) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[9].Descriptor()\n}\n\nfunc (NethelpersARPValidate) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[9]\n}\n\nfunc (x NethelpersARPValidate) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersARPValidate.Descriptor instead.\nfunc (NethelpersARPValidate) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{9}\n}\n\n// NethelpersAutoHostnameKind is a kind of automatically generated hostname.\ntype NethelpersAutoHostnameKind int32\n\nconst (\n\tNethelpersAutoHostnameKind_AUTO_HOSTNAME_KIND_OFF    NethelpersAutoHostnameKind = 0\n\tNethelpersAutoHostnameKind_AUTO_HOSTNAME_KIND_ADDR   NethelpersAutoHostnameKind = 1\n\tNethelpersAutoHostnameKind_AUTO_HOSTNAME_KIND_STABLE NethelpersAutoHostnameKind = 2\n)\n\n// Enum value maps for NethelpersAutoHostnameKind.\nvar (\n\tNethelpersAutoHostnameKind_name = map[int32]string{\n\t\t0: \"AUTO_HOSTNAME_KIND_OFF\",\n\t\t1: \"AUTO_HOSTNAME_KIND_ADDR\",\n\t\t2: \"AUTO_HOSTNAME_KIND_STABLE\",\n\t}\n\tNethelpersAutoHostnameKind_value = map[string]int32{\n\t\t\"AUTO_HOSTNAME_KIND_OFF\":    0,\n\t\t\"AUTO_HOSTNAME_KIND_ADDR\":   1,\n\t\t\"AUTO_HOSTNAME_KIND_STABLE\": 2,\n\t}\n)\n\nfunc (x NethelpersAutoHostnameKind) Enum() *NethelpersAutoHostnameKind {\n\tp := new(NethelpersAutoHostnameKind)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersAutoHostnameKind) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersAutoHostnameKind) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[10].Descriptor()\n}\n\nfunc (NethelpersAutoHostnameKind) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[10]\n}\n\nfunc (x NethelpersAutoHostnameKind) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersAutoHostnameKind.Descriptor instead.\nfunc (NethelpersAutoHostnameKind) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{10}\n}\n\n// NethelpersBondMode is a bond mode.\ntype NethelpersBondMode int32\n\nconst (\n\tNethelpersBondMode_BOND_MODE_ROUNDROBIN    NethelpersBondMode = 0\n\tNethelpersBondMode_BOND_MODE_ACTIVE_BACKUP NethelpersBondMode = 1\n\tNethelpersBondMode_BOND_MODE_XOR           NethelpersBondMode = 2\n\tNethelpersBondMode_BOND_MODE_BROADCAST     NethelpersBondMode = 3\n\tNethelpersBondMode_BOND_MODE8023_AD        NethelpersBondMode = 4\n\tNethelpersBondMode_BOND_MODE_TLB           NethelpersBondMode = 5\n\tNethelpersBondMode_BOND_MODE_ALB           NethelpersBondMode = 6\n)\n\n// Enum value maps for NethelpersBondMode.\nvar (\n\tNethelpersBondMode_name = map[int32]string{\n\t\t0: \"BOND_MODE_ROUNDROBIN\",\n\t\t1: \"BOND_MODE_ACTIVE_BACKUP\",\n\t\t2: \"BOND_MODE_XOR\",\n\t\t3: \"BOND_MODE_BROADCAST\",\n\t\t4: \"BOND_MODE8023_AD\",\n\t\t5: \"BOND_MODE_TLB\",\n\t\t6: \"BOND_MODE_ALB\",\n\t}\n\tNethelpersBondMode_value = map[string]int32{\n\t\t\"BOND_MODE_ROUNDROBIN\":    0,\n\t\t\"BOND_MODE_ACTIVE_BACKUP\": 1,\n\t\t\"BOND_MODE_XOR\":           2,\n\t\t\"BOND_MODE_BROADCAST\":     3,\n\t\t\"BOND_MODE8023_AD\":        4,\n\t\t\"BOND_MODE_TLB\":           5,\n\t\t\"BOND_MODE_ALB\":           6,\n\t}\n)\n\nfunc (x NethelpersBondMode) Enum() *NethelpersBondMode {\n\tp := new(NethelpersBondMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersBondMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersBondMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[11].Descriptor()\n}\n\nfunc (NethelpersBondMode) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[11]\n}\n\nfunc (x NethelpersBondMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersBondMode.Descriptor instead.\nfunc (NethelpersBondMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{11}\n}\n\n// NethelpersBondXmitHashPolicy is a bond hash policy.\ntype NethelpersBondXmitHashPolicy int32\n\nconst (\n\tNethelpersBondXmitHashPolicy_BOND_XMIT_POLICY_LAYER2  NethelpersBondXmitHashPolicy = 0\n\tNethelpersBondXmitHashPolicy_BOND_XMIT_POLICY_LAYER34 NethelpersBondXmitHashPolicy = 1\n\tNethelpersBondXmitHashPolicy_BOND_XMIT_POLICY_LAYER23 NethelpersBondXmitHashPolicy = 2\n\tNethelpersBondXmitHashPolicy_BOND_XMIT_POLICY_ENCAP23 NethelpersBondXmitHashPolicy = 3\n\tNethelpersBondXmitHashPolicy_BOND_XMIT_POLICY_ENCAP34 NethelpersBondXmitHashPolicy = 4\n)\n\n// Enum value maps for NethelpersBondXmitHashPolicy.\nvar (\n\tNethelpersBondXmitHashPolicy_name = map[int32]string{\n\t\t0: \"BOND_XMIT_POLICY_LAYER2\",\n\t\t1: \"BOND_XMIT_POLICY_LAYER34\",\n\t\t2: \"BOND_XMIT_POLICY_LAYER23\",\n\t\t3: \"BOND_XMIT_POLICY_ENCAP23\",\n\t\t4: \"BOND_XMIT_POLICY_ENCAP34\",\n\t}\n\tNethelpersBondXmitHashPolicy_value = map[string]int32{\n\t\t\"BOND_XMIT_POLICY_LAYER2\":  0,\n\t\t\"BOND_XMIT_POLICY_LAYER34\": 1,\n\t\t\"BOND_XMIT_POLICY_LAYER23\": 2,\n\t\t\"BOND_XMIT_POLICY_ENCAP23\": 3,\n\t\t\"BOND_XMIT_POLICY_ENCAP34\": 4,\n\t}\n)\n\nfunc (x NethelpersBondXmitHashPolicy) Enum() *NethelpersBondXmitHashPolicy {\n\tp := new(NethelpersBondXmitHashPolicy)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersBondXmitHashPolicy) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersBondXmitHashPolicy) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[12].Descriptor()\n}\n\nfunc (NethelpersBondXmitHashPolicy) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[12]\n}\n\nfunc (x NethelpersBondXmitHashPolicy) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersBondXmitHashPolicy.Descriptor instead.\nfunc (NethelpersBondXmitHashPolicy) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{12}\n}\n\n// NethelpersClientIdentifier is a DHCP client identifier.\ntype NethelpersClientIdentifier int32\n\nconst (\n\tNethelpersClientIdentifier_CLIENT_IDENTIFIER_NONE NethelpersClientIdentifier = 0\n\tNethelpersClientIdentifier_CLIENT_IDENTIFIER_MAC  NethelpersClientIdentifier = 1\n\tNethelpersClientIdentifier_CLIENT_IDENTIFIER_DUID NethelpersClientIdentifier = 2\n)\n\n// Enum value maps for NethelpersClientIdentifier.\nvar (\n\tNethelpersClientIdentifier_name = map[int32]string{\n\t\t0: \"CLIENT_IDENTIFIER_NONE\",\n\t\t1: \"CLIENT_IDENTIFIER_MAC\",\n\t\t2: \"CLIENT_IDENTIFIER_DUID\",\n\t}\n\tNethelpersClientIdentifier_value = map[string]int32{\n\t\t\"CLIENT_IDENTIFIER_NONE\": 0,\n\t\t\"CLIENT_IDENTIFIER_MAC\":  1,\n\t\t\"CLIENT_IDENTIFIER_DUID\": 2,\n\t}\n)\n\nfunc (x NethelpersClientIdentifier) Enum() *NethelpersClientIdentifier {\n\tp := new(NethelpersClientIdentifier)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersClientIdentifier) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersClientIdentifier) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[13].Descriptor()\n}\n\nfunc (NethelpersClientIdentifier) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[13]\n}\n\nfunc (x NethelpersClientIdentifier) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersClientIdentifier.Descriptor instead.\nfunc (NethelpersClientIdentifier) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{13}\n}\n\n// NethelpersConntrackState is a conntrack state.\ntype NethelpersConntrackState int32\n\nconst (\n\tNethelpersConntrackState_NETHELPERS_CONNTRACKSTATE_UNSPECIFIED NethelpersConntrackState = 0\n\tNethelpersConntrackState_CONNTRACK_STATE_NEW                   NethelpersConntrackState = 8\n\tNethelpersConntrackState_CONNTRACK_STATE_RELATED               NethelpersConntrackState = 4\n\tNethelpersConntrackState_CONNTRACK_STATE_ESTABLISHED           NethelpersConntrackState = 2\n\tNethelpersConntrackState_CONNTRACK_STATE_INVALID               NethelpersConntrackState = 1\n)\n\n// Enum value maps for NethelpersConntrackState.\nvar (\n\tNethelpersConntrackState_name = map[int32]string{\n\t\t0: \"NETHELPERS_CONNTRACKSTATE_UNSPECIFIED\",\n\t\t8: \"CONNTRACK_STATE_NEW\",\n\t\t4: \"CONNTRACK_STATE_RELATED\",\n\t\t2: \"CONNTRACK_STATE_ESTABLISHED\",\n\t\t1: \"CONNTRACK_STATE_INVALID\",\n\t}\n\tNethelpersConntrackState_value = map[string]int32{\n\t\t\"NETHELPERS_CONNTRACKSTATE_UNSPECIFIED\": 0,\n\t\t\"CONNTRACK_STATE_NEW\":                   8,\n\t\t\"CONNTRACK_STATE_RELATED\":               4,\n\t\t\"CONNTRACK_STATE_ESTABLISHED\":           2,\n\t\t\"CONNTRACK_STATE_INVALID\":               1,\n\t}\n)\n\nfunc (x NethelpersConntrackState) Enum() *NethelpersConntrackState {\n\tp := new(NethelpersConntrackState)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersConntrackState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersConntrackState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[14].Descriptor()\n}\n\nfunc (NethelpersConntrackState) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[14]\n}\n\nfunc (x NethelpersConntrackState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersConntrackState.Descriptor instead.\nfunc (NethelpersConntrackState) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{14}\n}\n\n// NethelpersDuplex wraps ethtool.Duplex for YAML marshaling.\ntype NethelpersDuplex int32\n\nconst (\n\tNethelpersDuplex_HALF    NethelpersDuplex = 0\n\tNethelpersDuplex_FULL    NethelpersDuplex = 1\n\tNethelpersDuplex_UNKNOWN NethelpersDuplex = 255\n)\n\n// Enum value maps for NethelpersDuplex.\nvar (\n\tNethelpersDuplex_name = map[int32]string{\n\t\t0:   \"HALF\",\n\t\t1:   \"FULL\",\n\t\t255: \"UNKNOWN\",\n\t}\n\tNethelpersDuplex_value = map[string]int32{\n\t\t\"HALF\":    0,\n\t\t\"FULL\":    1,\n\t\t\"UNKNOWN\": 255,\n\t}\n)\n\nfunc (x NethelpersDuplex) Enum() *NethelpersDuplex {\n\tp := new(NethelpersDuplex)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersDuplex) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersDuplex) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[15].Descriptor()\n}\n\nfunc (NethelpersDuplex) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[15]\n}\n\nfunc (x NethelpersDuplex) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersDuplex.Descriptor instead.\nfunc (NethelpersDuplex) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{15}\n}\n\n// NethelpersFailOverMAC is a MAC failover mode.\ntype NethelpersFailOverMAC int32\n\nconst (\n\tNethelpersFailOverMAC_FAIL_OVER_MAC_NONE   NethelpersFailOverMAC = 0\n\tNethelpersFailOverMAC_FAIL_OVER_MAC_ACTIVE NethelpersFailOverMAC = 1\n\tNethelpersFailOverMAC_FAIL_OVER_MAC_FOLLOW NethelpersFailOverMAC = 2\n)\n\n// Enum value maps for NethelpersFailOverMAC.\nvar (\n\tNethelpersFailOverMAC_name = map[int32]string{\n\t\t0: \"FAIL_OVER_MAC_NONE\",\n\t\t1: \"FAIL_OVER_MAC_ACTIVE\",\n\t\t2: \"FAIL_OVER_MAC_FOLLOW\",\n\t}\n\tNethelpersFailOverMAC_value = map[string]int32{\n\t\t\"FAIL_OVER_MAC_NONE\":   0,\n\t\t\"FAIL_OVER_MAC_ACTIVE\": 1,\n\t\t\"FAIL_OVER_MAC_FOLLOW\": 2,\n\t}\n)\n\nfunc (x NethelpersFailOverMAC) Enum() *NethelpersFailOverMAC {\n\tp := new(NethelpersFailOverMAC)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersFailOverMAC) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersFailOverMAC) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[16].Descriptor()\n}\n\nfunc (NethelpersFailOverMAC) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[16]\n}\n\nfunc (x NethelpersFailOverMAC) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersFailOverMAC.Descriptor instead.\nfunc (NethelpersFailOverMAC) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{16}\n}\n\n// NethelpersFamily is a network family.\ntype NethelpersFamily int32\n\nconst (\n\tNethelpersFamily_NETHELPERS_FAMILY_UNSPECIFIED NethelpersFamily = 0\n\tNethelpersFamily_FAMILY_INET4                  NethelpersFamily = 2\n\tNethelpersFamily_FAMILY_INET6                  NethelpersFamily = 10\n)\n\n// Enum value maps for NethelpersFamily.\nvar (\n\tNethelpersFamily_name = map[int32]string{\n\t\t0:  \"NETHELPERS_FAMILY_UNSPECIFIED\",\n\t\t2:  \"FAMILY_INET4\",\n\t\t10: \"FAMILY_INET6\",\n\t}\n\tNethelpersFamily_value = map[string]int32{\n\t\t\"NETHELPERS_FAMILY_UNSPECIFIED\": 0,\n\t\t\"FAMILY_INET4\":                  2,\n\t\t\"FAMILY_INET6\":                  10,\n\t}\n)\n\nfunc (x NethelpersFamily) Enum() *NethelpersFamily {\n\tp := new(NethelpersFamily)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersFamily) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersFamily) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[17].Descriptor()\n}\n\nfunc (NethelpersFamily) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[17]\n}\n\nfunc (x NethelpersFamily) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersFamily.Descriptor instead.\nfunc (NethelpersFamily) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{17}\n}\n\n// NethelpersICMPType is a ICMP packet type.\ntype NethelpersICMPType int32\n\nconst (\n\tNethelpersICMPType_NETHELPERS_ICMPTYPE_UNSPECIFIED NethelpersICMPType = 0\n\tNethelpersICMPType_ICMP_TYPE_TIMESTAMP_REQUEST     NethelpersICMPType = 13\n\tNethelpersICMPType_ICMP_TYPE_TIMESTAMP_REPLY       NethelpersICMPType = 14\n\tNethelpersICMPType_ICMP_TYPE_ADDRESS_MASK_REQUEST  NethelpersICMPType = 17\n\tNethelpersICMPType_ICMP_TYPE_ADDRESS_MASK_REPLY    NethelpersICMPType = 18\n)\n\n// Enum value maps for NethelpersICMPType.\nvar (\n\tNethelpersICMPType_name = map[int32]string{\n\t\t0:  \"NETHELPERS_ICMPTYPE_UNSPECIFIED\",\n\t\t13: \"ICMP_TYPE_TIMESTAMP_REQUEST\",\n\t\t14: \"ICMP_TYPE_TIMESTAMP_REPLY\",\n\t\t17: \"ICMP_TYPE_ADDRESS_MASK_REQUEST\",\n\t\t18: \"ICMP_TYPE_ADDRESS_MASK_REPLY\",\n\t}\n\tNethelpersICMPType_value = map[string]int32{\n\t\t\"NETHELPERS_ICMPTYPE_UNSPECIFIED\": 0,\n\t\t\"ICMP_TYPE_TIMESTAMP_REQUEST\":     13,\n\t\t\"ICMP_TYPE_TIMESTAMP_REPLY\":       14,\n\t\t\"ICMP_TYPE_ADDRESS_MASK_REQUEST\":  17,\n\t\t\"ICMP_TYPE_ADDRESS_MASK_REPLY\":    18,\n\t}\n)\n\nfunc (x NethelpersICMPType) Enum() *NethelpersICMPType {\n\tp := new(NethelpersICMPType)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersICMPType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersICMPType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[18].Descriptor()\n}\n\nfunc (NethelpersICMPType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[18]\n}\n\nfunc (x NethelpersICMPType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersICMPType.Descriptor instead.\nfunc (NethelpersICMPType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{18}\n}\n\n// NethelpersLACPRate is a LACP rate.\ntype NethelpersLACPRate int32\n\nconst (\n\tNethelpersLACPRate_LACP_RATE_SLOW NethelpersLACPRate = 0\n\tNethelpersLACPRate_LACP_RATE_FAST NethelpersLACPRate = 1\n)\n\n// Enum value maps for NethelpersLACPRate.\nvar (\n\tNethelpersLACPRate_name = map[int32]string{\n\t\t0: \"LACP_RATE_SLOW\",\n\t\t1: \"LACP_RATE_FAST\",\n\t}\n\tNethelpersLACPRate_value = map[string]int32{\n\t\t\"LACP_RATE_SLOW\": 0,\n\t\t\"LACP_RATE_FAST\": 1,\n\t}\n)\n\nfunc (x NethelpersLACPRate) Enum() *NethelpersLACPRate {\n\tp := new(NethelpersLACPRate)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersLACPRate) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersLACPRate) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[19].Descriptor()\n}\n\nfunc (NethelpersLACPRate) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[19]\n}\n\nfunc (x NethelpersLACPRate) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersLACPRate.Descriptor instead.\nfunc (NethelpersLACPRate) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{19}\n}\n\n// NethelpersLinkType is a link type.\ntype NethelpersLinkType int32\n\nconst (\n\tNethelpersLinkType_LINK_NETROM            NethelpersLinkType = 0\n\tNethelpersLinkType_LINK_ETHER             NethelpersLinkType = 1\n\tNethelpersLinkType_LINK_EETHER            NethelpersLinkType = 2\n\tNethelpersLinkType_LINK_AX25              NethelpersLinkType = 3\n\tNethelpersLinkType_LINK_PRONET            NethelpersLinkType = 4\n\tNethelpersLinkType_LINK_CHAOS             NethelpersLinkType = 5\n\tNethelpersLinkType_LINK_IEE802            NethelpersLinkType = 6\n\tNethelpersLinkType_LINK_ARCNET            NethelpersLinkType = 7\n\tNethelpersLinkType_LINK_ATALK             NethelpersLinkType = 8\n\tNethelpersLinkType_LINK_DLCI              NethelpersLinkType = 15\n\tNethelpersLinkType_LINK_ATM               NethelpersLinkType = 19\n\tNethelpersLinkType_LINK_METRICOM          NethelpersLinkType = 23\n\tNethelpersLinkType_LINK_IEEE1394          NethelpersLinkType = 24\n\tNethelpersLinkType_LINK_EUI64             NethelpersLinkType = 27\n\tNethelpersLinkType_LINK_INFINIBAND        NethelpersLinkType = 32\n\tNethelpersLinkType_LINK_SLIP              NethelpersLinkType = 256\n\tNethelpersLinkType_LINK_CSLIP             NethelpersLinkType = 257\n\tNethelpersLinkType_LINK_SLIP6             NethelpersLinkType = 258\n\tNethelpersLinkType_LINK_CSLIP6            NethelpersLinkType = 259\n\tNethelpersLinkType_LINK_RSRVD             NethelpersLinkType = 260\n\tNethelpersLinkType_LINK_ADAPT             NethelpersLinkType = 264\n\tNethelpersLinkType_LINK_ROSE              NethelpersLinkType = 270\n\tNethelpersLinkType_LINK_X25               NethelpersLinkType = 271\n\tNethelpersLinkType_LINK_HWX25             NethelpersLinkType = 272\n\tNethelpersLinkType_LINK_CAN               NethelpersLinkType = 280\n\tNethelpersLinkType_LINK_PPP               NethelpersLinkType = 512\n\tNethelpersLinkType_LINK_CISCO             NethelpersLinkType = 513\n\tNethelpersLinkType_LINK_HDLC              NethelpersLinkType = 513\n\tNethelpersLinkType_LINK_LAPB              NethelpersLinkType = 516\n\tNethelpersLinkType_LINK_DDCMP             NethelpersLinkType = 517\n\tNethelpersLinkType_LINK_RAWHDLC           NethelpersLinkType = 518\n\tNethelpersLinkType_LINK_TUNNEL            NethelpersLinkType = 768\n\tNethelpersLinkType_LINK_TUNNEL6           NethelpersLinkType = 769\n\tNethelpersLinkType_LINK_FRAD              NethelpersLinkType = 770\n\tNethelpersLinkType_LINK_SKIP              NethelpersLinkType = 771\n\tNethelpersLinkType_LINK_LOOPBCK           NethelpersLinkType = 772\n\tNethelpersLinkType_LINK_LOCALTLK          NethelpersLinkType = 773\n\tNethelpersLinkType_LINK_FDDI              NethelpersLinkType = 774\n\tNethelpersLinkType_LINK_BIF               NethelpersLinkType = 775\n\tNethelpersLinkType_LINK_SIT               NethelpersLinkType = 776\n\tNethelpersLinkType_LINK_IPDDP             NethelpersLinkType = 777\n\tNethelpersLinkType_LINK_IPGRE             NethelpersLinkType = 778\n\tNethelpersLinkType_LINK_PIMREG            NethelpersLinkType = 779\n\tNethelpersLinkType_LINK_HIPPI             NethelpersLinkType = 780\n\tNethelpersLinkType_LINK_ASH               NethelpersLinkType = 781\n\tNethelpersLinkType_LINK_ECONET            NethelpersLinkType = 782\n\tNethelpersLinkType_LINK_IRDA              NethelpersLinkType = 783\n\tNethelpersLinkType_LINK_FCPP              NethelpersLinkType = 784\n\tNethelpersLinkType_LINK_FCAL              NethelpersLinkType = 785\n\tNethelpersLinkType_LINK_FCPL              NethelpersLinkType = 786\n\tNethelpersLinkType_LINK_FCFABRIC          NethelpersLinkType = 787\n\tNethelpersLinkType_LINK_FCFABRIC1         NethelpersLinkType = 788\n\tNethelpersLinkType_LINK_FCFABRIC2         NethelpersLinkType = 789\n\tNethelpersLinkType_LINK_FCFABRIC3         NethelpersLinkType = 790\n\tNethelpersLinkType_LINK_FCFABRIC4         NethelpersLinkType = 791\n\tNethelpersLinkType_LINK_FCFABRIC5         NethelpersLinkType = 792\n\tNethelpersLinkType_LINK_FCFABRIC6         NethelpersLinkType = 793\n\tNethelpersLinkType_LINK_FCFABRIC7         NethelpersLinkType = 794\n\tNethelpersLinkType_LINK_FCFABRIC8         NethelpersLinkType = 795\n\tNethelpersLinkType_LINK_FCFABRIC9         NethelpersLinkType = 796\n\tNethelpersLinkType_LINK_FCFABRIC10        NethelpersLinkType = 797\n\tNethelpersLinkType_LINK_FCFABRIC11        NethelpersLinkType = 798\n\tNethelpersLinkType_LINK_FCFABRIC12        NethelpersLinkType = 799\n\tNethelpersLinkType_LINK_IEE802TR          NethelpersLinkType = 800\n\tNethelpersLinkType_LINK_IEE80211          NethelpersLinkType = 801\n\tNethelpersLinkType_LINK_IEE80211PRISM     NethelpersLinkType = 802\n\tNethelpersLinkType_LINK_IEE80211_RADIOTAP NethelpersLinkType = 803\n\tNethelpersLinkType_LINK_IEE8021154        NethelpersLinkType = 804\n\tNethelpersLinkType_LINK_IEE8021154MONITOR NethelpersLinkType = 805\n\tNethelpersLinkType_LINK_PHONET            NethelpersLinkType = 820\n\tNethelpersLinkType_LINK_PHONETPIPE        NethelpersLinkType = 821\n\tNethelpersLinkType_LINK_CAIF              NethelpersLinkType = 822\n\tNethelpersLinkType_LINK_IP6GRE            NethelpersLinkType = 823\n\tNethelpersLinkType_LINK_NETLINK           NethelpersLinkType = 824\n\tNethelpersLinkType_LINK6_LOWPAN           NethelpersLinkType = 825\n\tNethelpersLinkType_LINK_VOID              NethelpersLinkType = 65535\n\tNethelpersLinkType_LINK_NONE              NethelpersLinkType = 65534\n)\n\n// Enum value maps for NethelpersLinkType.\nvar (\n\tNethelpersLinkType_name = map[int32]string{\n\t\t0:   \"LINK_NETROM\",\n\t\t1:   \"LINK_ETHER\",\n\t\t2:   \"LINK_EETHER\",\n\t\t3:   \"LINK_AX25\",\n\t\t4:   \"LINK_PRONET\",\n\t\t5:   \"LINK_CHAOS\",\n\t\t6:   \"LINK_IEE802\",\n\t\t7:   \"LINK_ARCNET\",\n\t\t8:   \"LINK_ATALK\",\n\t\t15:  \"LINK_DLCI\",\n\t\t19:  \"LINK_ATM\",\n\t\t23:  \"LINK_METRICOM\",\n\t\t24:  \"LINK_IEEE1394\",\n\t\t27:  \"LINK_EUI64\",\n\t\t32:  \"LINK_INFINIBAND\",\n\t\t256: \"LINK_SLIP\",\n\t\t257: \"LINK_CSLIP\",\n\t\t258: \"LINK_SLIP6\",\n\t\t259: \"LINK_CSLIP6\",\n\t\t260: \"LINK_RSRVD\",\n\t\t264: \"LINK_ADAPT\",\n\t\t270: \"LINK_ROSE\",\n\t\t271: \"LINK_X25\",\n\t\t272: \"LINK_HWX25\",\n\t\t280: \"LINK_CAN\",\n\t\t512: \"LINK_PPP\",\n\t\t513: \"LINK_CISCO\",\n\t\t// Duplicate value: 513: \"LINK_HDLC\",\n\t\t516:   \"LINK_LAPB\",\n\t\t517:   \"LINK_DDCMP\",\n\t\t518:   \"LINK_RAWHDLC\",\n\t\t768:   \"LINK_TUNNEL\",\n\t\t769:   \"LINK_TUNNEL6\",\n\t\t770:   \"LINK_FRAD\",\n\t\t771:   \"LINK_SKIP\",\n\t\t772:   \"LINK_LOOPBCK\",\n\t\t773:   \"LINK_LOCALTLK\",\n\t\t774:   \"LINK_FDDI\",\n\t\t775:   \"LINK_BIF\",\n\t\t776:   \"LINK_SIT\",\n\t\t777:   \"LINK_IPDDP\",\n\t\t778:   \"LINK_IPGRE\",\n\t\t779:   \"LINK_PIMREG\",\n\t\t780:   \"LINK_HIPPI\",\n\t\t781:   \"LINK_ASH\",\n\t\t782:   \"LINK_ECONET\",\n\t\t783:   \"LINK_IRDA\",\n\t\t784:   \"LINK_FCPP\",\n\t\t785:   \"LINK_FCAL\",\n\t\t786:   \"LINK_FCPL\",\n\t\t787:   \"LINK_FCFABRIC\",\n\t\t788:   \"LINK_FCFABRIC1\",\n\t\t789:   \"LINK_FCFABRIC2\",\n\t\t790:   \"LINK_FCFABRIC3\",\n\t\t791:   \"LINK_FCFABRIC4\",\n\t\t792:   \"LINK_FCFABRIC5\",\n\t\t793:   \"LINK_FCFABRIC6\",\n\t\t794:   \"LINK_FCFABRIC7\",\n\t\t795:   \"LINK_FCFABRIC8\",\n\t\t796:   \"LINK_FCFABRIC9\",\n\t\t797:   \"LINK_FCFABRIC10\",\n\t\t798:   \"LINK_FCFABRIC11\",\n\t\t799:   \"LINK_FCFABRIC12\",\n\t\t800:   \"LINK_IEE802TR\",\n\t\t801:   \"LINK_IEE80211\",\n\t\t802:   \"LINK_IEE80211PRISM\",\n\t\t803:   \"LINK_IEE80211_RADIOTAP\",\n\t\t804:   \"LINK_IEE8021154\",\n\t\t805:   \"LINK_IEE8021154MONITOR\",\n\t\t820:   \"LINK_PHONET\",\n\t\t821:   \"LINK_PHONETPIPE\",\n\t\t822:   \"LINK_CAIF\",\n\t\t823:   \"LINK_IP6GRE\",\n\t\t824:   \"LINK_NETLINK\",\n\t\t825:   \"LINK6_LOWPAN\",\n\t\t65535: \"LINK_VOID\",\n\t\t65534: \"LINK_NONE\",\n\t}\n\tNethelpersLinkType_value = map[string]int32{\n\t\t\"LINK_NETROM\":            0,\n\t\t\"LINK_ETHER\":             1,\n\t\t\"LINK_EETHER\":            2,\n\t\t\"LINK_AX25\":              3,\n\t\t\"LINK_PRONET\":            4,\n\t\t\"LINK_CHAOS\":             5,\n\t\t\"LINK_IEE802\":            6,\n\t\t\"LINK_ARCNET\":            7,\n\t\t\"LINK_ATALK\":             8,\n\t\t\"LINK_DLCI\":              15,\n\t\t\"LINK_ATM\":               19,\n\t\t\"LINK_METRICOM\":          23,\n\t\t\"LINK_IEEE1394\":          24,\n\t\t\"LINK_EUI64\":             27,\n\t\t\"LINK_INFINIBAND\":        32,\n\t\t\"LINK_SLIP\":              256,\n\t\t\"LINK_CSLIP\":             257,\n\t\t\"LINK_SLIP6\":             258,\n\t\t\"LINK_CSLIP6\":            259,\n\t\t\"LINK_RSRVD\":             260,\n\t\t\"LINK_ADAPT\":             264,\n\t\t\"LINK_ROSE\":              270,\n\t\t\"LINK_X25\":               271,\n\t\t\"LINK_HWX25\":             272,\n\t\t\"LINK_CAN\":               280,\n\t\t\"LINK_PPP\":               512,\n\t\t\"LINK_CISCO\":             513,\n\t\t\"LINK_HDLC\":              513,\n\t\t\"LINK_LAPB\":              516,\n\t\t\"LINK_DDCMP\":             517,\n\t\t\"LINK_RAWHDLC\":           518,\n\t\t\"LINK_TUNNEL\":            768,\n\t\t\"LINK_TUNNEL6\":           769,\n\t\t\"LINK_FRAD\":              770,\n\t\t\"LINK_SKIP\":              771,\n\t\t\"LINK_LOOPBCK\":           772,\n\t\t\"LINK_LOCALTLK\":          773,\n\t\t\"LINK_FDDI\":              774,\n\t\t\"LINK_BIF\":               775,\n\t\t\"LINK_SIT\":               776,\n\t\t\"LINK_IPDDP\":             777,\n\t\t\"LINK_IPGRE\":             778,\n\t\t\"LINK_PIMREG\":            779,\n\t\t\"LINK_HIPPI\":             780,\n\t\t\"LINK_ASH\":               781,\n\t\t\"LINK_ECONET\":            782,\n\t\t\"LINK_IRDA\":              783,\n\t\t\"LINK_FCPP\":              784,\n\t\t\"LINK_FCAL\":              785,\n\t\t\"LINK_FCPL\":              786,\n\t\t\"LINK_FCFABRIC\":          787,\n\t\t\"LINK_FCFABRIC1\":         788,\n\t\t\"LINK_FCFABRIC2\":         789,\n\t\t\"LINK_FCFABRIC3\":         790,\n\t\t\"LINK_FCFABRIC4\":         791,\n\t\t\"LINK_FCFABRIC5\":         792,\n\t\t\"LINK_FCFABRIC6\":         793,\n\t\t\"LINK_FCFABRIC7\":         794,\n\t\t\"LINK_FCFABRIC8\":         795,\n\t\t\"LINK_FCFABRIC9\":         796,\n\t\t\"LINK_FCFABRIC10\":        797,\n\t\t\"LINK_FCFABRIC11\":        798,\n\t\t\"LINK_FCFABRIC12\":        799,\n\t\t\"LINK_IEE802TR\":          800,\n\t\t\"LINK_IEE80211\":          801,\n\t\t\"LINK_IEE80211PRISM\":     802,\n\t\t\"LINK_IEE80211_RADIOTAP\": 803,\n\t\t\"LINK_IEE8021154\":        804,\n\t\t\"LINK_IEE8021154MONITOR\": 805,\n\t\t\"LINK_PHONET\":            820,\n\t\t\"LINK_PHONETPIPE\":        821,\n\t\t\"LINK_CAIF\":              822,\n\t\t\"LINK_IP6GRE\":            823,\n\t\t\"LINK_NETLINK\":           824,\n\t\t\"LINK6_LOWPAN\":           825,\n\t\t\"LINK_VOID\":              65535,\n\t\t\"LINK_NONE\":              65534,\n\t}\n)\n\nfunc (x NethelpersLinkType) Enum() *NethelpersLinkType {\n\tp := new(NethelpersLinkType)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersLinkType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersLinkType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[20].Descriptor()\n}\n\nfunc (NethelpersLinkType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[20]\n}\n\nfunc (x NethelpersLinkType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersLinkType.Descriptor instead.\nfunc (NethelpersLinkType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{20}\n}\n\n// NethelpersMatchOperator is a netfilter match operator.\ntype NethelpersMatchOperator int32\n\nconst (\n\tNethelpersMatchOperator_OPERATOR_EQUAL     NethelpersMatchOperator = 0\n\tNethelpersMatchOperator_OPERATOR_NOT_EQUAL NethelpersMatchOperator = 1\n)\n\n// Enum value maps for NethelpersMatchOperator.\nvar (\n\tNethelpersMatchOperator_name = map[int32]string{\n\t\t0: \"OPERATOR_EQUAL\",\n\t\t1: \"OPERATOR_NOT_EQUAL\",\n\t}\n\tNethelpersMatchOperator_value = map[string]int32{\n\t\t\"OPERATOR_EQUAL\":     0,\n\t\t\"OPERATOR_NOT_EQUAL\": 1,\n\t}\n)\n\nfunc (x NethelpersMatchOperator) Enum() *NethelpersMatchOperator {\n\tp := new(NethelpersMatchOperator)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersMatchOperator) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersMatchOperator) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[21].Descriptor()\n}\n\nfunc (NethelpersMatchOperator) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[21]\n}\n\nfunc (x NethelpersMatchOperator) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersMatchOperator.Descriptor instead.\nfunc (NethelpersMatchOperator) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{21}\n}\n\n// NethelpersNfTablesChainHook wraps nftables.ChainHook for YAML marshaling.\ntype NethelpersNfTablesChainHook int32\n\nconst (\n\tNethelpersNfTablesChainHook_CHAIN_HOOK_PREROUTING  NethelpersNfTablesChainHook = 0\n\tNethelpersNfTablesChainHook_CHAIN_HOOK_INPUT       NethelpersNfTablesChainHook = 1\n\tNethelpersNfTablesChainHook_CHAIN_HOOK_FORWARD     NethelpersNfTablesChainHook = 2\n\tNethelpersNfTablesChainHook_CHAIN_HOOK_OUTPUT      NethelpersNfTablesChainHook = 3\n\tNethelpersNfTablesChainHook_CHAIN_HOOK_POSTROUTING NethelpersNfTablesChainHook = 4\n)\n\n// Enum value maps for NethelpersNfTablesChainHook.\nvar (\n\tNethelpersNfTablesChainHook_name = map[int32]string{\n\t\t0: \"CHAIN_HOOK_PREROUTING\",\n\t\t1: \"CHAIN_HOOK_INPUT\",\n\t\t2: \"CHAIN_HOOK_FORWARD\",\n\t\t3: \"CHAIN_HOOK_OUTPUT\",\n\t\t4: \"CHAIN_HOOK_POSTROUTING\",\n\t}\n\tNethelpersNfTablesChainHook_value = map[string]int32{\n\t\t\"CHAIN_HOOK_PREROUTING\":  0,\n\t\t\"CHAIN_HOOK_INPUT\":       1,\n\t\t\"CHAIN_HOOK_FORWARD\":     2,\n\t\t\"CHAIN_HOOK_OUTPUT\":      3,\n\t\t\"CHAIN_HOOK_POSTROUTING\": 4,\n\t}\n)\n\nfunc (x NethelpersNfTablesChainHook) Enum() *NethelpersNfTablesChainHook {\n\tp := new(NethelpersNfTablesChainHook)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersNfTablesChainHook) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersNfTablesChainHook) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[22].Descriptor()\n}\n\nfunc (NethelpersNfTablesChainHook) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[22]\n}\n\nfunc (x NethelpersNfTablesChainHook) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersNfTablesChainHook.Descriptor instead.\nfunc (NethelpersNfTablesChainHook) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{22}\n}\n\n// NethelpersNfTablesChainPriority wraps nftables.ChainPriority for YAML marshaling.\ntype NethelpersNfTablesChainPriority int32\n\nconst (\n\tNethelpersNfTablesChainPriority_NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED NethelpersNfTablesChainPriority = 0\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_FIRST                         NethelpersNfTablesChainPriority = -2147483648\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_CONNTRACK_DEFRAG              NethelpersNfTablesChainPriority = -400\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_RAW                           NethelpersNfTablesChainPriority = -300\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_SE_LINUX_FIRST                NethelpersNfTablesChainPriority = -225\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_CONNTRACK                     NethelpersNfTablesChainPriority = -200\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_MANGLE                        NethelpersNfTablesChainPriority = -150\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_NAT_DEST                      NethelpersNfTablesChainPriority = -100\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_FILTER                        NethelpersNfTablesChainPriority = 0\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_SECURITY                      NethelpersNfTablesChainPriority = 50\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_NAT_SOURCE                    NethelpersNfTablesChainPriority = 100\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_SE_LINUX_LAST                 NethelpersNfTablesChainPriority = 225\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_CONNTRACK_HELPER              NethelpersNfTablesChainPriority = 300\n\tNethelpersNfTablesChainPriority_CHAIN_PRIORITY_LAST                          NethelpersNfTablesChainPriority = 2147483647\n)\n\n// Enum value maps for NethelpersNfTablesChainPriority.\nvar (\n\tNethelpersNfTablesChainPriority_name = map[int32]string{\n\t\t0:           \"NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED\",\n\t\t-2147483648: \"CHAIN_PRIORITY_FIRST\",\n\t\t-400:        \"CHAIN_PRIORITY_CONNTRACK_DEFRAG\",\n\t\t-300:        \"CHAIN_PRIORITY_RAW\",\n\t\t-225:        \"CHAIN_PRIORITY_SE_LINUX_FIRST\",\n\t\t-200:        \"CHAIN_PRIORITY_CONNTRACK\",\n\t\t-150:        \"CHAIN_PRIORITY_MANGLE\",\n\t\t-100:        \"CHAIN_PRIORITY_NAT_DEST\",\n\t\t// Duplicate value: 0: \"CHAIN_PRIORITY_FILTER\",\n\t\t50:         \"CHAIN_PRIORITY_SECURITY\",\n\t\t100:        \"CHAIN_PRIORITY_NAT_SOURCE\",\n\t\t225:        \"CHAIN_PRIORITY_SE_LINUX_LAST\",\n\t\t300:        \"CHAIN_PRIORITY_CONNTRACK_HELPER\",\n\t\t2147483647: \"CHAIN_PRIORITY_LAST\",\n\t}\n\tNethelpersNfTablesChainPriority_value = map[string]int32{\n\t\t\"NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED\": 0,\n\t\t\"CHAIN_PRIORITY_FIRST\":                         -2147483648,\n\t\t\"CHAIN_PRIORITY_CONNTRACK_DEFRAG\":              -400,\n\t\t\"CHAIN_PRIORITY_RAW\":                           -300,\n\t\t\"CHAIN_PRIORITY_SE_LINUX_FIRST\":                -225,\n\t\t\"CHAIN_PRIORITY_CONNTRACK\":                     -200,\n\t\t\"CHAIN_PRIORITY_MANGLE\":                        -150,\n\t\t\"CHAIN_PRIORITY_NAT_DEST\":                      -100,\n\t\t\"CHAIN_PRIORITY_FILTER\":                        0,\n\t\t\"CHAIN_PRIORITY_SECURITY\":                      50,\n\t\t\"CHAIN_PRIORITY_NAT_SOURCE\":                    100,\n\t\t\"CHAIN_PRIORITY_SE_LINUX_LAST\":                 225,\n\t\t\"CHAIN_PRIORITY_CONNTRACK_HELPER\":              300,\n\t\t\"CHAIN_PRIORITY_LAST\":                          2147483647,\n\t}\n)\n\nfunc (x NethelpersNfTablesChainPriority) Enum() *NethelpersNfTablesChainPriority {\n\tp := new(NethelpersNfTablesChainPriority)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersNfTablesChainPriority) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersNfTablesChainPriority) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[23].Descriptor()\n}\n\nfunc (NethelpersNfTablesChainPriority) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[23]\n}\n\nfunc (x NethelpersNfTablesChainPriority) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersNfTablesChainPriority.Descriptor instead.\nfunc (NethelpersNfTablesChainPriority) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{23}\n}\n\n// NethelpersNfTablesVerdict wraps nftables.Verdict for YAML marshaling.\ntype NethelpersNfTablesVerdict int32\n\nconst (\n\tNethelpersNfTablesVerdict_VERDICT_DROP   NethelpersNfTablesVerdict = 0\n\tNethelpersNfTablesVerdict_VERDICT_ACCEPT NethelpersNfTablesVerdict = 1\n)\n\n// Enum value maps for NethelpersNfTablesVerdict.\nvar (\n\tNethelpersNfTablesVerdict_name = map[int32]string{\n\t\t0: \"VERDICT_DROP\",\n\t\t1: \"VERDICT_ACCEPT\",\n\t}\n\tNethelpersNfTablesVerdict_value = map[string]int32{\n\t\t\"VERDICT_DROP\":   0,\n\t\t\"VERDICT_ACCEPT\": 1,\n\t}\n)\n\nfunc (x NethelpersNfTablesVerdict) Enum() *NethelpersNfTablesVerdict {\n\tp := new(NethelpersNfTablesVerdict)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersNfTablesVerdict) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersNfTablesVerdict) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[24].Descriptor()\n}\n\nfunc (NethelpersNfTablesVerdict) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[24]\n}\n\nfunc (x NethelpersNfTablesVerdict) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersNfTablesVerdict.Descriptor instead.\nfunc (NethelpersNfTablesVerdict) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{24}\n}\n\n// NethelpersOperationalState wraps rtnetlink.OperationalState for YAML marshaling.\ntype NethelpersOperationalState int32\n\nconst (\n\tNethelpersOperationalState_OPER_STATE_UNKNOWN          NethelpersOperationalState = 0\n\tNethelpersOperationalState_OPER_STATE_NOT_PRESENT      NethelpersOperationalState = 1\n\tNethelpersOperationalState_OPER_STATE_DOWN             NethelpersOperationalState = 2\n\tNethelpersOperationalState_OPER_STATE_LOWER_LAYER_DOWN NethelpersOperationalState = 3\n\tNethelpersOperationalState_OPER_STATE_TESTING          NethelpersOperationalState = 4\n\tNethelpersOperationalState_OPER_STATE_DORMANT          NethelpersOperationalState = 5\n\tNethelpersOperationalState_OPER_STATE_UP               NethelpersOperationalState = 6\n)\n\n// Enum value maps for NethelpersOperationalState.\nvar (\n\tNethelpersOperationalState_name = map[int32]string{\n\t\t0: \"OPER_STATE_UNKNOWN\",\n\t\t1: \"OPER_STATE_NOT_PRESENT\",\n\t\t2: \"OPER_STATE_DOWN\",\n\t\t3: \"OPER_STATE_LOWER_LAYER_DOWN\",\n\t\t4: \"OPER_STATE_TESTING\",\n\t\t5: \"OPER_STATE_DORMANT\",\n\t\t6: \"OPER_STATE_UP\",\n\t}\n\tNethelpersOperationalState_value = map[string]int32{\n\t\t\"OPER_STATE_UNKNOWN\":          0,\n\t\t\"OPER_STATE_NOT_PRESENT\":      1,\n\t\t\"OPER_STATE_DOWN\":             2,\n\t\t\"OPER_STATE_LOWER_LAYER_DOWN\": 3,\n\t\t\"OPER_STATE_TESTING\":          4,\n\t\t\"OPER_STATE_DORMANT\":          5,\n\t\t\"OPER_STATE_UP\":               6,\n\t}\n)\n\nfunc (x NethelpersOperationalState) Enum() *NethelpersOperationalState {\n\tp := new(NethelpersOperationalState)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersOperationalState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersOperationalState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[25].Descriptor()\n}\n\nfunc (NethelpersOperationalState) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[25]\n}\n\nfunc (x NethelpersOperationalState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersOperationalState.Descriptor instead.\nfunc (NethelpersOperationalState) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{25}\n}\n\n// NethelpersPort wraps ethtool.Port for YAML marshaling.\ntype NethelpersPort int32\n\nconst (\n\tNethelpersPort_TWISTED_PAIR  NethelpersPort = 0\n\tNethelpersPort_AUI           NethelpersPort = 1\n\tNethelpersPort_MII           NethelpersPort = 2\n\tNethelpersPort_FIBRE         NethelpersPort = 3\n\tNethelpersPort_BNC           NethelpersPort = 4\n\tNethelpersPort_DIRECT_ATTACH NethelpersPort = 5\n\tNethelpersPort_NONE          NethelpersPort = 239\n\tNethelpersPort_OTHER         NethelpersPort = 255\n)\n\n// Enum value maps for NethelpersPort.\nvar (\n\tNethelpersPort_name = map[int32]string{\n\t\t0:   \"TWISTED_PAIR\",\n\t\t1:   \"AUI\",\n\t\t2:   \"MII\",\n\t\t3:   \"FIBRE\",\n\t\t4:   \"BNC\",\n\t\t5:   \"DIRECT_ATTACH\",\n\t\t239: \"NONE\",\n\t\t255: \"OTHER\",\n\t}\n\tNethelpersPort_value = map[string]int32{\n\t\t\"TWISTED_PAIR\":  0,\n\t\t\"AUI\":           1,\n\t\t\"MII\":           2,\n\t\t\"FIBRE\":         3,\n\t\t\"BNC\":           4,\n\t\t\"DIRECT_ATTACH\": 5,\n\t\t\"NONE\":          239,\n\t\t\"OTHER\":         255,\n\t}\n)\n\nfunc (x NethelpersPort) Enum() *NethelpersPort {\n\tp := new(NethelpersPort)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersPort) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersPort) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[26].Descriptor()\n}\n\nfunc (NethelpersPort) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[26]\n}\n\nfunc (x NethelpersPort) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersPort.Descriptor instead.\nfunc (NethelpersPort) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{26}\n}\n\n// NethelpersPrimaryReselect is an ARP targets mode.\ntype NethelpersPrimaryReselect int32\n\nconst (\n\tNethelpersPrimaryReselect_PRIMARY_RESELECT_ALWAYS  NethelpersPrimaryReselect = 0\n\tNethelpersPrimaryReselect_PRIMARY_RESELECT_BETTER  NethelpersPrimaryReselect = 1\n\tNethelpersPrimaryReselect_PRIMARY_RESELECT_FAILURE NethelpersPrimaryReselect = 2\n)\n\n// Enum value maps for NethelpersPrimaryReselect.\nvar (\n\tNethelpersPrimaryReselect_name = map[int32]string{\n\t\t0: \"PRIMARY_RESELECT_ALWAYS\",\n\t\t1: \"PRIMARY_RESELECT_BETTER\",\n\t\t2: \"PRIMARY_RESELECT_FAILURE\",\n\t}\n\tNethelpersPrimaryReselect_value = map[string]int32{\n\t\t\"PRIMARY_RESELECT_ALWAYS\":  0,\n\t\t\"PRIMARY_RESELECT_BETTER\":  1,\n\t\t\"PRIMARY_RESELECT_FAILURE\": 2,\n\t}\n)\n\nfunc (x NethelpersPrimaryReselect) Enum() *NethelpersPrimaryReselect {\n\tp := new(NethelpersPrimaryReselect)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersPrimaryReselect) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersPrimaryReselect) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[27].Descriptor()\n}\n\nfunc (NethelpersPrimaryReselect) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[27]\n}\n\nfunc (x NethelpersPrimaryReselect) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersPrimaryReselect.Descriptor instead.\nfunc (NethelpersPrimaryReselect) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{27}\n}\n\n// NethelpersProtocol is a inet protocol.\ntype NethelpersProtocol int32\n\nconst (\n\tNethelpersProtocol_NETHELPERS_PROTOCOL_UNSPECIFIED NethelpersProtocol = 0\n\tNethelpersProtocol_PROTOCOL_ICMP                   NethelpersProtocol = 1\n\tNethelpersProtocol_PROTOCOL_TCP                    NethelpersProtocol = 6\n\tNethelpersProtocol_PROTOCOL_UDP                    NethelpersProtocol = 17\n\tNethelpersProtocol_PROTOCOL_ICM_PV6                NethelpersProtocol = 58\n)\n\n// Enum value maps for NethelpersProtocol.\nvar (\n\tNethelpersProtocol_name = map[int32]string{\n\t\t0:  \"NETHELPERS_PROTOCOL_UNSPECIFIED\",\n\t\t1:  \"PROTOCOL_ICMP\",\n\t\t6:  \"PROTOCOL_TCP\",\n\t\t17: \"PROTOCOL_UDP\",\n\t\t58: \"PROTOCOL_ICM_PV6\",\n\t}\n\tNethelpersProtocol_value = map[string]int32{\n\t\t\"NETHELPERS_PROTOCOL_UNSPECIFIED\": 0,\n\t\t\"PROTOCOL_ICMP\":                   1,\n\t\t\"PROTOCOL_TCP\":                    6,\n\t\t\"PROTOCOL_UDP\":                    17,\n\t\t\"PROTOCOL_ICM_PV6\":                58,\n\t}\n)\n\nfunc (x NethelpersProtocol) Enum() *NethelpersProtocol {\n\tp := new(NethelpersProtocol)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersProtocol) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersProtocol) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[28].Descriptor()\n}\n\nfunc (NethelpersProtocol) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[28]\n}\n\nfunc (x NethelpersProtocol) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersProtocol.Descriptor instead.\nfunc (NethelpersProtocol) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{28}\n}\n\n// NethelpersRouteFlag wraps RTM_F_* constants.\ntype NethelpersRouteFlag int32\n\nconst (\n\tNethelpersRouteFlag_NETHELPERS_ROUTEFLAG_UNSPECIFIED NethelpersRouteFlag = 0\n\tNethelpersRouteFlag_ROUTE_NOTIFY                     NethelpersRouteFlag = 256\n\tNethelpersRouteFlag_ROUTE_CLONED                     NethelpersRouteFlag = 512\n\tNethelpersRouteFlag_ROUTE_EQUALIZE                   NethelpersRouteFlag = 1024\n\tNethelpersRouteFlag_ROUTE_PREFIX                     NethelpersRouteFlag = 2048\n\tNethelpersRouteFlag_ROUTE_LOOKUP_TABLE               NethelpersRouteFlag = 4096\n\tNethelpersRouteFlag_ROUTE_FIB_MATCH                  NethelpersRouteFlag = 8192\n\tNethelpersRouteFlag_ROUTE_OFFLOAD                    NethelpersRouteFlag = 16384\n\tNethelpersRouteFlag_ROUTE_TRAP                       NethelpersRouteFlag = 32768\n)\n\n// Enum value maps for NethelpersRouteFlag.\nvar (\n\tNethelpersRouteFlag_name = map[int32]string{\n\t\t0:     \"NETHELPERS_ROUTEFLAG_UNSPECIFIED\",\n\t\t256:   \"ROUTE_NOTIFY\",\n\t\t512:   \"ROUTE_CLONED\",\n\t\t1024:  \"ROUTE_EQUALIZE\",\n\t\t2048:  \"ROUTE_PREFIX\",\n\t\t4096:  \"ROUTE_LOOKUP_TABLE\",\n\t\t8192:  \"ROUTE_FIB_MATCH\",\n\t\t16384: \"ROUTE_OFFLOAD\",\n\t\t32768: \"ROUTE_TRAP\",\n\t}\n\tNethelpersRouteFlag_value = map[string]int32{\n\t\t\"NETHELPERS_ROUTEFLAG_UNSPECIFIED\": 0,\n\t\t\"ROUTE_NOTIFY\":                     256,\n\t\t\"ROUTE_CLONED\":                     512,\n\t\t\"ROUTE_EQUALIZE\":                   1024,\n\t\t\"ROUTE_PREFIX\":                     2048,\n\t\t\"ROUTE_LOOKUP_TABLE\":               4096,\n\t\t\"ROUTE_FIB_MATCH\":                  8192,\n\t\t\"ROUTE_OFFLOAD\":                    16384,\n\t\t\"ROUTE_TRAP\":                       32768,\n\t}\n)\n\nfunc (x NethelpersRouteFlag) Enum() *NethelpersRouteFlag {\n\tp := new(NethelpersRouteFlag)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersRouteFlag) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersRouteFlag) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[29].Descriptor()\n}\n\nfunc (NethelpersRouteFlag) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[29]\n}\n\nfunc (x NethelpersRouteFlag) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersRouteFlag.Descriptor instead.\nfunc (NethelpersRouteFlag) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{29}\n}\n\n// NethelpersRouteProtocol is a routing protocol.\ntype NethelpersRouteProtocol int32\n\nconst (\n\tNethelpersRouteProtocol_PROTOCOL_UNSPEC     NethelpersRouteProtocol = 0\n\tNethelpersRouteProtocol_PROTOCOL_REDIRECT   NethelpersRouteProtocol = 1\n\tNethelpersRouteProtocol_PROTOCOL_KERNEL     NethelpersRouteProtocol = 2\n\tNethelpersRouteProtocol_PROTOCOL_BOOT       NethelpersRouteProtocol = 3\n\tNethelpersRouteProtocol_PROTOCOL_STATIC     NethelpersRouteProtocol = 4\n\tNethelpersRouteProtocol_PROTOCOL_RA         NethelpersRouteProtocol = 9\n\tNethelpersRouteProtocol_PROTOCOL_MRT        NethelpersRouteProtocol = 10\n\tNethelpersRouteProtocol_PROTOCOL_ZEBRA      NethelpersRouteProtocol = 11\n\tNethelpersRouteProtocol_PROTOCOL_BIRD       NethelpersRouteProtocol = 12\n\tNethelpersRouteProtocol_PROTOCOL_DNROUTED   NethelpersRouteProtocol = 13\n\tNethelpersRouteProtocol_PROTOCOL_XORP       NethelpersRouteProtocol = 14\n\tNethelpersRouteProtocol_PROTOCOL_NTK        NethelpersRouteProtocol = 15\n\tNethelpersRouteProtocol_PROTOCOL_DHCP       NethelpersRouteProtocol = 16\n\tNethelpersRouteProtocol_PROTOCOL_MRTD       NethelpersRouteProtocol = 17\n\tNethelpersRouteProtocol_PROTOCOL_KEEPALIVED NethelpersRouteProtocol = 18\n\tNethelpersRouteProtocol_PROTOCOL_BABEL      NethelpersRouteProtocol = 42\n\tNethelpersRouteProtocol_PROTOCOL_OPENR      NethelpersRouteProtocol = 99\n\tNethelpersRouteProtocol_PROTOCOL_BGP        NethelpersRouteProtocol = 186\n\tNethelpersRouteProtocol_PROTOCOL_ISIS       NethelpersRouteProtocol = 187\n\tNethelpersRouteProtocol_PROTOCOL_OSPF       NethelpersRouteProtocol = 188\n\tNethelpersRouteProtocol_PROTOCOL_RIP        NethelpersRouteProtocol = 189\n\tNethelpersRouteProtocol_PROTOCOL_EIGRP      NethelpersRouteProtocol = 192\n)\n\n// Enum value maps for NethelpersRouteProtocol.\nvar (\n\tNethelpersRouteProtocol_name = map[int32]string{\n\t\t0:   \"PROTOCOL_UNSPEC\",\n\t\t1:   \"PROTOCOL_REDIRECT\",\n\t\t2:   \"PROTOCOL_KERNEL\",\n\t\t3:   \"PROTOCOL_BOOT\",\n\t\t4:   \"PROTOCOL_STATIC\",\n\t\t9:   \"PROTOCOL_RA\",\n\t\t10:  \"PROTOCOL_MRT\",\n\t\t11:  \"PROTOCOL_ZEBRA\",\n\t\t12:  \"PROTOCOL_BIRD\",\n\t\t13:  \"PROTOCOL_DNROUTED\",\n\t\t14:  \"PROTOCOL_XORP\",\n\t\t15:  \"PROTOCOL_NTK\",\n\t\t16:  \"PROTOCOL_DHCP\",\n\t\t17:  \"PROTOCOL_MRTD\",\n\t\t18:  \"PROTOCOL_KEEPALIVED\",\n\t\t42:  \"PROTOCOL_BABEL\",\n\t\t99:  \"PROTOCOL_OPENR\",\n\t\t186: \"PROTOCOL_BGP\",\n\t\t187: \"PROTOCOL_ISIS\",\n\t\t188: \"PROTOCOL_OSPF\",\n\t\t189: \"PROTOCOL_RIP\",\n\t\t192: \"PROTOCOL_EIGRP\",\n\t}\n\tNethelpersRouteProtocol_value = map[string]int32{\n\t\t\"PROTOCOL_UNSPEC\":     0,\n\t\t\"PROTOCOL_REDIRECT\":   1,\n\t\t\"PROTOCOL_KERNEL\":     2,\n\t\t\"PROTOCOL_BOOT\":       3,\n\t\t\"PROTOCOL_STATIC\":     4,\n\t\t\"PROTOCOL_RA\":         9,\n\t\t\"PROTOCOL_MRT\":        10,\n\t\t\"PROTOCOL_ZEBRA\":      11,\n\t\t\"PROTOCOL_BIRD\":       12,\n\t\t\"PROTOCOL_DNROUTED\":   13,\n\t\t\"PROTOCOL_XORP\":       14,\n\t\t\"PROTOCOL_NTK\":        15,\n\t\t\"PROTOCOL_DHCP\":       16,\n\t\t\"PROTOCOL_MRTD\":       17,\n\t\t\"PROTOCOL_KEEPALIVED\": 18,\n\t\t\"PROTOCOL_BABEL\":      42,\n\t\t\"PROTOCOL_OPENR\":      99,\n\t\t\"PROTOCOL_BGP\":        186,\n\t\t\"PROTOCOL_ISIS\":       187,\n\t\t\"PROTOCOL_OSPF\":       188,\n\t\t\"PROTOCOL_RIP\":        189,\n\t\t\"PROTOCOL_EIGRP\":      192,\n\t}\n)\n\nfunc (x NethelpersRouteProtocol) Enum() *NethelpersRouteProtocol {\n\tp := new(NethelpersRouteProtocol)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersRouteProtocol) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersRouteProtocol) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[30].Descriptor()\n}\n\nfunc (NethelpersRouteProtocol) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[30]\n}\n\nfunc (x NethelpersRouteProtocol) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersRouteProtocol.Descriptor instead.\nfunc (NethelpersRouteProtocol) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{30}\n}\n\n// NethelpersRouteType is a route type.\ntype NethelpersRouteType int32\n\nconst (\n\tNethelpersRouteType_TYPE_UNSPEC      NethelpersRouteType = 0\n\tNethelpersRouteType_TYPE_UNICAST     NethelpersRouteType = 1\n\tNethelpersRouteType_TYPE_LOCAL       NethelpersRouteType = 2\n\tNethelpersRouteType_TYPE_BROADCAST   NethelpersRouteType = 3\n\tNethelpersRouteType_TYPE_ANYCAST     NethelpersRouteType = 4\n\tNethelpersRouteType_TYPE_MULTICAST   NethelpersRouteType = 5\n\tNethelpersRouteType_TYPE_BLACKHOLE   NethelpersRouteType = 6\n\tNethelpersRouteType_TYPE_UNREACHABLE NethelpersRouteType = 7\n\tNethelpersRouteType_TYPE_PROHIBIT    NethelpersRouteType = 8\n\tNethelpersRouteType_TYPE_THROW       NethelpersRouteType = 9\n\tNethelpersRouteType_TYPE_NAT         NethelpersRouteType = 10\n\tNethelpersRouteType_TYPE_X_RESOLVE   NethelpersRouteType = 11\n)\n\n// Enum value maps for NethelpersRouteType.\nvar (\n\tNethelpersRouteType_name = map[int32]string{\n\t\t0:  \"TYPE_UNSPEC\",\n\t\t1:  \"TYPE_UNICAST\",\n\t\t2:  \"TYPE_LOCAL\",\n\t\t3:  \"TYPE_BROADCAST\",\n\t\t4:  \"TYPE_ANYCAST\",\n\t\t5:  \"TYPE_MULTICAST\",\n\t\t6:  \"TYPE_BLACKHOLE\",\n\t\t7:  \"TYPE_UNREACHABLE\",\n\t\t8:  \"TYPE_PROHIBIT\",\n\t\t9:  \"TYPE_THROW\",\n\t\t10: \"TYPE_NAT\",\n\t\t11: \"TYPE_X_RESOLVE\",\n\t}\n\tNethelpersRouteType_value = map[string]int32{\n\t\t\"TYPE_UNSPEC\":      0,\n\t\t\"TYPE_UNICAST\":     1,\n\t\t\"TYPE_LOCAL\":       2,\n\t\t\"TYPE_BROADCAST\":   3,\n\t\t\"TYPE_ANYCAST\":     4,\n\t\t\"TYPE_MULTICAST\":   5,\n\t\t\"TYPE_BLACKHOLE\":   6,\n\t\t\"TYPE_UNREACHABLE\": 7,\n\t\t\"TYPE_PROHIBIT\":    8,\n\t\t\"TYPE_THROW\":       9,\n\t\t\"TYPE_NAT\":         10,\n\t\t\"TYPE_X_RESOLVE\":   11,\n\t}\n)\n\nfunc (x NethelpersRouteType) Enum() *NethelpersRouteType {\n\tp := new(NethelpersRouteType)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersRouteType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersRouteType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[31].Descriptor()\n}\n\nfunc (NethelpersRouteType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[31]\n}\n\nfunc (x NethelpersRouteType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersRouteType.Descriptor instead.\nfunc (NethelpersRouteType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{31}\n}\n\n// NethelpersRoutingRuleAction is a routing rule action.\ntype NethelpersRoutingRuleAction int32\n\nconst (\n\tNethelpersRoutingRuleAction_ROUTING_RULE_ACTION_UNSPEC      NethelpersRoutingRuleAction = 0\n\tNethelpersRoutingRuleAction_ROUTING_RULE_ACTION_UNICAST     NethelpersRoutingRuleAction = 1\n\tNethelpersRoutingRuleAction_ROUTING_RULE_ACTION_BLACKHOLE   NethelpersRoutingRuleAction = 6\n\tNethelpersRoutingRuleAction_ROUTING_RULE_ACTION_UNREACHABLE NethelpersRoutingRuleAction = 7\n\tNethelpersRoutingRuleAction_ROUTING_RULE_ACTION_PROHIBIT    NethelpersRoutingRuleAction = 8\n)\n\n// Enum value maps for NethelpersRoutingRuleAction.\nvar (\n\tNethelpersRoutingRuleAction_name = map[int32]string{\n\t\t0: \"ROUTING_RULE_ACTION_UNSPEC\",\n\t\t1: \"ROUTING_RULE_ACTION_UNICAST\",\n\t\t6: \"ROUTING_RULE_ACTION_BLACKHOLE\",\n\t\t7: \"ROUTING_RULE_ACTION_UNREACHABLE\",\n\t\t8: \"ROUTING_RULE_ACTION_PROHIBIT\",\n\t}\n\tNethelpersRoutingRuleAction_value = map[string]int32{\n\t\t\"ROUTING_RULE_ACTION_UNSPEC\":      0,\n\t\t\"ROUTING_RULE_ACTION_UNICAST\":     1,\n\t\t\"ROUTING_RULE_ACTION_BLACKHOLE\":   6,\n\t\t\"ROUTING_RULE_ACTION_UNREACHABLE\": 7,\n\t\t\"ROUTING_RULE_ACTION_PROHIBIT\":    8,\n\t}\n)\n\nfunc (x NethelpersRoutingRuleAction) Enum() *NethelpersRoutingRuleAction {\n\tp := new(NethelpersRoutingRuleAction)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersRoutingRuleAction) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersRoutingRuleAction) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[32].Descriptor()\n}\n\nfunc (NethelpersRoutingRuleAction) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[32]\n}\n\nfunc (x NethelpersRoutingRuleAction) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersRoutingRuleAction.Descriptor instead.\nfunc (NethelpersRoutingRuleAction) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{32}\n}\n\n// NethelpersRoutingTable is a routing table ID.\ntype NethelpersRoutingTable int32\n\nconst (\n\tNethelpersRoutingTable_TABLE_UNSPEC  NethelpersRoutingTable = 0\n\tNethelpersRoutingTable_TABLE1        NethelpersRoutingTable = 1\n\tNethelpersRoutingTable_TABLE2        NethelpersRoutingTable = 2\n\tNethelpersRoutingTable_TABLE3        NethelpersRoutingTable = 3\n\tNethelpersRoutingTable_TABLE4        NethelpersRoutingTable = 4\n\tNethelpersRoutingTable_TABLE5        NethelpersRoutingTable = 5\n\tNethelpersRoutingTable_TABLE6        NethelpersRoutingTable = 6\n\tNethelpersRoutingTable_TABLE7        NethelpersRoutingTable = 7\n\tNethelpersRoutingTable_TABLE8        NethelpersRoutingTable = 8\n\tNethelpersRoutingTable_TABLE9        NethelpersRoutingTable = 9\n\tNethelpersRoutingTable_TABLE10       NethelpersRoutingTable = 10\n\tNethelpersRoutingTable_TABLE11       NethelpersRoutingTable = 11\n\tNethelpersRoutingTable_TABLE12       NethelpersRoutingTable = 12\n\tNethelpersRoutingTable_TABLE13       NethelpersRoutingTable = 13\n\tNethelpersRoutingTable_TABLE14       NethelpersRoutingTable = 14\n\tNethelpersRoutingTable_TABLE15       NethelpersRoutingTable = 15\n\tNethelpersRoutingTable_TABLE16       NethelpersRoutingTable = 16\n\tNethelpersRoutingTable_TABLE17       NethelpersRoutingTable = 17\n\tNethelpersRoutingTable_TABLE18       NethelpersRoutingTable = 18\n\tNethelpersRoutingTable_TABLE19       NethelpersRoutingTable = 19\n\tNethelpersRoutingTable_TABLE20       NethelpersRoutingTable = 20\n\tNethelpersRoutingTable_TABLE21       NethelpersRoutingTable = 21\n\tNethelpersRoutingTable_TABLE22       NethelpersRoutingTable = 22\n\tNethelpersRoutingTable_TABLE23       NethelpersRoutingTable = 23\n\tNethelpersRoutingTable_TABLE24       NethelpersRoutingTable = 24\n\tNethelpersRoutingTable_TABLE25       NethelpersRoutingTable = 25\n\tNethelpersRoutingTable_TABLE26       NethelpersRoutingTable = 26\n\tNethelpersRoutingTable_TABLE27       NethelpersRoutingTable = 27\n\tNethelpersRoutingTable_TABLE28       NethelpersRoutingTable = 28\n\tNethelpersRoutingTable_TABLE29       NethelpersRoutingTable = 29\n\tNethelpersRoutingTable_TABLE30       NethelpersRoutingTable = 30\n\tNethelpersRoutingTable_TABLE31       NethelpersRoutingTable = 31\n\tNethelpersRoutingTable_TABLE32       NethelpersRoutingTable = 32\n\tNethelpersRoutingTable_TABLE33       NethelpersRoutingTable = 33\n\tNethelpersRoutingTable_TABLE34       NethelpersRoutingTable = 34\n\tNethelpersRoutingTable_TABLE35       NethelpersRoutingTable = 35\n\tNethelpersRoutingTable_TABLE36       NethelpersRoutingTable = 36\n\tNethelpersRoutingTable_TABLE37       NethelpersRoutingTable = 37\n\tNethelpersRoutingTable_TABLE38       NethelpersRoutingTable = 38\n\tNethelpersRoutingTable_TABLE39       NethelpersRoutingTable = 39\n\tNethelpersRoutingTable_TABLE40       NethelpersRoutingTable = 40\n\tNethelpersRoutingTable_TABLE41       NethelpersRoutingTable = 41\n\tNethelpersRoutingTable_TABLE42       NethelpersRoutingTable = 42\n\tNethelpersRoutingTable_TABLE43       NethelpersRoutingTable = 43\n\tNethelpersRoutingTable_TABLE44       NethelpersRoutingTable = 44\n\tNethelpersRoutingTable_TABLE45       NethelpersRoutingTable = 45\n\tNethelpersRoutingTable_TABLE46       NethelpersRoutingTable = 46\n\tNethelpersRoutingTable_TABLE47       NethelpersRoutingTable = 47\n\tNethelpersRoutingTable_TABLE48       NethelpersRoutingTable = 48\n\tNethelpersRoutingTable_TABLE49       NethelpersRoutingTable = 49\n\tNethelpersRoutingTable_TABLE50       NethelpersRoutingTable = 50\n\tNethelpersRoutingTable_TABLE51       NethelpersRoutingTable = 51\n\tNethelpersRoutingTable_TABLE52       NethelpersRoutingTable = 52\n\tNethelpersRoutingTable_TABLE53       NethelpersRoutingTable = 53\n\tNethelpersRoutingTable_TABLE54       NethelpersRoutingTable = 54\n\tNethelpersRoutingTable_TABLE55       NethelpersRoutingTable = 55\n\tNethelpersRoutingTable_TABLE56       NethelpersRoutingTable = 56\n\tNethelpersRoutingTable_TABLE57       NethelpersRoutingTable = 57\n\tNethelpersRoutingTable_TABLE58       NethelpersRoutingTable = 58\n\tNethelpersRoutingTable_TABLE59       NethelpersRoutingTable = 59\n\tNethelpersRoutingTable_TABLE60       NethelpersRoutingTable = 60\n\tNethelpersRoutingTable_TABLE61       NethelpersRoutingTable = 61\n\tNethelpersRoutingTable_TABLE62       NethelpersRoutingTable = 62\n\tNethelpersRoutingTable_TABLE63       NethelpersRoutingTable = 63\n\tNethelpersRoutingTable_TABLE64       NethelpersRoutingTable = 64\n\tNethelpersRoutingTable_TABLE65       NethelpersRoutingTable = 65\n\tNethelpersRoutingTable_TABLE66       NethelpersRoutingTable = 66\n\tNethelpersRoutingTable_TABLE67       NethelpersRoutingTable = 67\n\tNethelpersRoutingTable_TABLE68       NethelpersRoutingTable = 68\n\tNethelpersRoutingTable_TABLE69       NethelpersRoutingTable = 69\n\tNethelpersRoutingTable_TABLE70       NethelpersRoutingTable = 70\n\tNethelpersRoutingTable_TABLE71       NethelpersRoutingTable = 71\n\tNethelpersRoutingTable_TABLE72       NethelpersRoutingTable = 72\n\tNethelpersRoutingTable_TABLE73       NethelpersRoutingTable = 73\n\tNethelpersRoutingTable_TABLE74       NethelpersRoutingTable = 74\n\tNethelpersRoutingTable_TABLE75       NethelpersRoutingTable = 75\n\tNethelpersRoutingTable_TABLE76       NethelpersRoutingTable = 76\n\tNethelpersRoutingTable_TABLE77       NethelpersRoutingTable = 77\n\tNethelpersRoutingTable_TABLE78       NethelpersRoutingTable = 78\n\tNethelpersRoutingTable_TABLE79       NethelpersRoutingTable = 79\n\tNethelpersRoutingTable_TABLE80       NethelpersRoutingTable = 80\n\tNethelpersRoutingTable_TABLE81       NethelpersRoutingTable = 81\n\tNethelpersRoutingTable_TABLE82       NethelpersRoutingTable = 82\n\tNethelpersRoutingTable_TABLE83       NethelpersRoutingTable = 83\n\tNethelpersRoutingTable_TABLE84       NethelpersRoutingTable = 84\n\tNethelpersRoutingTable_TABLE85       NethelpersRoutingTable = 85\n\tNethelpersRoutingTable_TABLE86       NethelpersRoutingTable = 86\n\tNethelpersRoutingTable_TABLE87       NethelpersRoutingTable = 87\n\tNethelpersRoutingTable_TABLE88       NethelpersRoutingTable = 88\n\tNethelpersRoutingTable_TABLE89       NethelpersRoutingTable = 89\n\tNethelpersRoutingTable_TABLE90       NethelpersRoutingTable = 90\n\tNethelpersRoutingTable_TABLE91       NethelpersRoutingTable = 91\n\tNethelpersRoutingTable_TABLE92       NethelpersRoutingTable = 92\n\tNethelpersRoutingTable_TABLE93       NethelpersRoutingTable = 93\n\tNethelpersRoutingTable_TABLE94       NethelpersRoutingTable = 94\n\tNethelpersRoutingTable_TABLE95       NethelpersRoutingTable = 95\n\tNethelpersRoutingTable_TABLE96       NethelpersRoutingTable = 96\n\tNethelpersRoutingTable_TABLE97       NethelpersRoutingTable = 97\n\tNethelpersRoutingTable_TABLE98       NethelpersRoutingTable = 98\n\tNethelpersRoutingTable_TABLE99       NethelpersRoutingTable = 99\n\tNethelpersRoutingTable_TABLE100      NethelpersRoutingTable = 100\n\tNethelpersRoutingTable_TABLE101      NethelpersRoutingTable = 101\n\tNethelpersRoutingTable_TABLE102      NethelpersRoutingTable = 102\n\tNethelpersRoutingTable_TABLE103      NethelpersRoutingTable = 103\n\tNethelpersRoutingTable_TABLE104      NethelpersRoutingTable = 104\n\tNethelpersRoutingTable_TABLE105      NethelpersRoutingTable = 105\n\tNethelpersRoutingTable_TABLE106      NethelpersRoutingTable = 106\n\tNethelpersRoutingTable_TABLE107      NethelpersRoutingTable = 107\n\tNethelpersRoutingTable_TABLE108      NethelpersRoutingTable = 108\n\tNethelpersRoutingTable_TABLE109      NethelpersRoutingTable = 109\n\tNethelpersRoutingTable_TABLE110      NethelpersRoutingTable = 110\n\tNethelpersRoutingTable_TABLE111      NethelpersRoutingTable = 111\n\tNethelpersRoutingTable_TABLE112      NethelpersRoutingTable = 112\n\tNethelpersRoutingTable_TABLE113      NethelpersRoutingTable = 113\n\tNethelpersRoutingTable_TABLE114      NethelpersRoutingTable = 114\n\tNethelpersRoutingTable_TABLE115      NethelpersRoutingTable = 115\n\tNethelpersRoutingTable_TABLE116      NethelpersRoutingTable = 116\n\tNethelpersRoutingTable_TABLE117      NethelpersRoutingTable = 117\n\tNethelpersRoutingTable_TABLE118      NethelpersRoutingTable = 118\n\tNethelpersRoutingTable_TABLE119      NethelpersRoutingTable = 119\n\tNethelpersRoutingTable_TABLE120      NethelpersRoutingTable = 120\n\tNethelpersRoutingTable_TABLE121      NethelpersRoutingTable = 121\n\tNethelpersRoutingTable_TABLE122      NethelpersRoutingTable = 122\n\tNethelpersRoutingTable_TABLE123      NethelpersRoutingTable = 123\n\tNethelpersRoutingTable_TABLE124      NethelpersRoutingTable = 124\n\tNethelpersRoutingTable_TABLE125      NethelpersRoutingTable = 125\n\tNethelpersRoutingTable_TABLE126      NethelpersRoutingTable = 126\n\tNethelpersRoutingTable_TABLE127      NethelpersRoutingTable = 127\n\tNethelpersRoutingTable_TABLE128      NethelpersRoutingTable = 128\n\tNethelpersRoutingTable_TABLE129      NethelpersRoutingTable = 129\n\tNethelpersRoutingTable_TABLE130      NethelpersRoutingTable = 130\n\tNethelpersRoutingTable_TABLE131      NethelpersRoutingTable = 131\n\tNethelpersRoutingTable_TABLE132      NethelpersRoutingTable = 132\n\tNethelpersRoutingTable_TABLE133      NethelpersRoutingTable = 133\n\tNethelpersRoutingTable_TABLE134      NethelpersRoutingTable = 134\n\tNethelpersRoutingTable_TABLE135      NethelpersRoutingTable = 135\n\tNethelpersRoutingTable_TABLE136      NethelpersRoutingTable = 136\n\tNethelpersRoutingTable_TABLE137      NethelpersRoutingTable = 137\n\tNethelpersRoutingTable_TABLE138      NethelpersRoutingTable = 138\n\tNethelpersRoutingTable_TABLE139      NethelpersRoutingTable = 139\n\tNethelpersRoutingTable_TABLE140      NethelpersRoutingTable = 140\n\tNethelpersRoutingTable_TABLE141      NethelpersRoutingTable = 141\n\tNethelpersRoutingTable_TABLE142      NethelpersRoutingTable = 142\n\tNethelpersRoutingTable_TABLE143      NethelpersRoutingTable = 143\n\tNethelpersRoutingTable_TABLE144      NethelpersRoutingTable = 144\n\tNethelpersRoutingTable_TABLE145      NethelpersRoutingTable = 145\n\tNethelpersRoutingTable_TABLE146      NethelpersRoutingTable = 146\n\tNethelpersRoutingTable_TABLE147      NethelpersRoutingTable = 147\n\tNethelpersRoutingTable_TABLE148      NethelpersRoutingTable = 148\n\tNethelpersRoutingTable_TABLE149      NethelpersRoutingTable = 149\n\tNethelpersRoutingTable_TABLE150      NethelpersRoutingTable = 150\n\tNethelpersRoutingTable_TABLE151      NethelpersRoutingTable = 151\n\tNethelpersRoutingTable_TABLE152      NethelpersRoutingTable = 152\n\tNethelpersRoutingTable_TABLE153      NethelpersRoutingTable = 153\n\tNethelpersRoutingTable_TABLE154      NethelpersRoutingTable = 154\n\tNethelpersRoutingTable_TABLE155      NethelpersRoutingTable = 155\n\tNethelpersRoutingTable_TABLE156      NethelpersRoutingTable = 156\n\tNethelpersRoutingTable_TABLE157      NethelpersRoutingTable = 157\n\tNethelpersRoutingTable_TABLE158      NethelpersRoutingTable = 158\n\tNethelpersRoutingTable_TABLE159      NethelpersRoutingTable = 159\n\tNethelpersRoutingTable_TABLE160      NethelpersRoutingTable = 160\n\tNethelpersRoutingTable_TABLE161      NethelpersRoutingTable = 161\n\tNethelpersRoutingTable_TABLE162      NethelpersRoutingTable = 162\n\tNethelpersRoutingTable_TABLE163      NethelpersRoutingTable = 163\n\tNethelpersRoutingTable_TABLE164      NethelpersRoutingTable = 164\n\tNethelpersRoutingTable_TABLE165      NethelpersRoutingTable = 165\n\tNethelpersRoutingTable_TABLE166      NethelpersRoutingTable = 166\n\tNethelpersRoutingTable_TABLE167      NethelpersRoutingTable = 167\n\tNethelpersRoutingTable_TABLE168      NethelpersRoutingTable = 168\n\tNethelpersRoutingTable_TABLE169      NethelpersRoutingTable = 169\n\tNethelpersRoutingTable_TABLE170      NethelpersRoutingTable = 170\n\tNethelpersRoutingTable_TABLE171      NethelpersRoutingTable = 171\n\tNethelpersRoutingTable_TABLE172      NethelpersRoutingTable = 172\n\tNethelpersRoutingTable_TABLE173      NethelpersRoutingTable = 173\n\tNethelpersRoutingTable_TABLE174      NethelpersRoutingTable = 174\n\tNethelpersRoutingTable_TABLE175      NethelpersRoutingTable = 175\n\tNethelpersRoutingTable_TABLE176      NethelpersRoutingTable = 176\n\tNethelpersRoutingTable_TABLE177      NethelpersRoutingTable = 177\n\tNethelpersRoutingTable_TABLE178      NethelpersRoutingTable = 178\n\tNethelpersRoutingTable_TABLE179      NethelpersRoutingTable = 179\n\tNethelpersRoutingTable_TABLE180      NethelpersRoutingTable = 180\n\tNethelpersRoutingTable_TABLE181      NethelpersRoutingTable = 181\n\tNethelpersRoutingTable_TABLE182      NethelpersRoutingTable = 182\n\tNethelpersRoutingTable_TABLE183      NethelpersRoutingTable = 183\n\tNethelpersRoutingTable_TABLE184      NethelpersRoutingTable = 184\n\tNethelpersRoutingTable_TABLE185      NethelpersRoutingTable = 185\n\tNethelpersRoutingTable_TABLE186      NethelpersRoutingTable = 186\n\tNethelpersRoutingTable_TABLE187      NethelpersRoutingTable = 187\n\tNethelpersRoutingTable_TABLE188      NethelpersRoutingTable = 188\n\tNethelpersRoutingTable_TABLE189      NethelpersRoutingTable = 189\n\tNethelpersRoutingTable_TABLE190      NethelpersRoutingTable = 190\n\tNethelpersRoutingTable_TABLE191      NethelpersRoutingTable = 191\n\tNethelpersRoutingTable_TABLE192      NethelpersRoutingTable = 192\n\tNethelpersRoutingTable_TABLE193      NethelpersRoutingTable = 193\n\tNethelpersRoutingTable_TABLE194      NethelpersRoutingTable = 194\n\tNethelpersRoutingTable_TABLE195      NethelpersRoutingTable = 195\n\tNethelpersRoutingTable_TABLE196      NethelpersRoutingTable = 196\n\tNethelpersRoutingTable_TABLE197      NethelpersRoutingTable = 197\n\tNethelpersRoutingTable_TABLE198      NethelpersRoutingTable = 198\n\tNethelpersRoutingTable_TABLE199      NethelpersRoutingTable = 199\n\tNethelpersRoutingTable_TABLE200      NethelpersRoutingTable = 200\n\tNethelpersRoutingTable_TABLE201      NethelpersRoutingTable = 201\n\tNethelpersRoutingTable_TABLE202      NethelpersRoutingTable = 202\n\tNethelpersRoutingTable_TABLE203      NethelpersRoutingTable = 203\n\tNethelpersRoutingTable_TABLE204      NethelpersRoutingTable = 204\n\tNethelpersRoutingTable_TABLE205      NethelpersRoutingTable = 205\n\tNethelpersRoutingTable_TABLE206      NethelpersRoutingTable = 206\n\tNethelpersRoutingTable_TABLE207      NethelpersRoutingTable = 207\n\tNethelpersRoutingTable_TABLE208      NethelpersRoutingTable = 208\n\tNethelpersRoutingTable_TABLE209      NethelpersRoutingTable = 209\n\tNethelpersRoutingTable_TABLE210      NethelpersRoutingTable = 210\n\tNethelpersRoutingTable_TABLE211      NethelpersRoutingTable = 211\n\tNethelpersRoutingTable_TABLE212      NethelpersRoutingTable = 212\n\tNethelpersRoutingTable_TABLE213      NethelpersRoutingTable = 213\n\tNethelpersRoutingTable_TABLE214      NethelpersRoutingTable = 214\n\tNethelpersRoutingTable_TABLE215      NethelpersRoutingTable = 215\n\tNethelpersRoutingTable_TABLE216      NethelpersRoutingTable = 216\n\tNethelpersRoutingTable_TABLE217      NethelpersRoutingTable = 217\n\tNethelpersRoutingTable_TABLE218      NethelpersRoutingTable = 218\n\tNethelpersRoutingTable_TABLE219      NethelpersRoutingTable = 219\n\tNethelpersRoutingTable_TABLE220      NethelpersRoutingTable = 220\n\tNethelpersRoutingTable_TABLE221      NethelpersRoutingTable = 221\n\tNethelpersRoutingTable_TABLE222      NethelpersRoutingTable = 222\n\tNethelpersRoutingTable_TABLE223      NethelpersRoutingTable = 223\n\tNethelpersRoutingTable_TABLE224      NethelpersRoutingTable = 224\n\tNethelpersRoutingTable_TABLE225      NethelpersRoutingTable = 225\n\tNethelpersRoutingTable_TABLE226      NethelpersRoutingTable = 226\n\tNethelpersRoutingTable_TABLE227      NethelpersRoutingTable = 227\n\tNethelpersRoutingTable_TABLE228      NethelpersRoutingTable = 228\n\tNethelpersRoutingTable_TABLE229      NethelpersRoutingTable = 229\n\tNethelpersRoutingTable_TABLE230      NethelpersRoutingTable = 230\n\tNethelpersRoutingTable_TABLE231      NethelpersRoutingTable = 231\n\tNethelpersRoutingTable_TABLE232      NethelpersRoutingTable = 232\n\tNethelpersRoutingTable_TABLE233      NethelpersRoutingTable = 233\n\tNethelpersRoutingTable_TABLE234      NethelpersRoutingTable = 234\n\tNethelpersRoutingTable_TABLE235      NethelpersRoutingTable = 235\n\tNethelpersRoutingTable_TABLE236      NethelpersRoutingTable = 236\n\tNethelpersRoutingTable_TABLE237      NethelpersRoutingTable = 237\n\tNethelpersRoutingTable_TABLE238      NethelpersRoutingTable = 238\n\tNethelpersRoutingTable_TABLE239      NethelpersRoutingTable = 239\n\tNethelpersRoutingTable_TABLE240      NethelpersRoutingTable = 240\n\tNethelpersRoutingTable_TABLE241      NethelpersRoutingTable = 241\n\tNethelpersRoutingTable_TABLE242      NethelpersRoutingTable = 242\n\tNethelpersRoutingTable_TABLE243      NethelpersRoutingTable = 243\n\tNethelpersRoutingTable_TABLE244      NethelpersRoutingTable = 244\n\tNethelpersRoutingTable_TABLE245      NethelpersRoutingTable = 245\n\tNethelpersRoutingTable_TABLE246      NethelpersRoutingTable = 246\n\tNethelpersRoutingTable_TABLE247      NethelpersRoutingTable = 247\n\tNethelpersRoutingTable_TABLE248      NethelpersRoutingTable = 248\n\tNethelpersRoutingTable_TABLE249      NethelpersRoutingTable = 249\n\tNethelpersRoutingTable_TABLE250      NethelpersRoutingTable = 250\n\tNethelpersRoutingTable_TABLE251      NethelpersRoutingTable = 251\n\tNethelpersRoutingTable_TABLE252      NethelpersRoutingTable = 252\n\tNethelpersRoutingTable_TABLE_DEFAULT NethelpersRoutingTable = 253\n\tNethelpersRoutingTable_TABLE_MAIN    NethelpersRoutingTable = 254\n\tNethelpersRoutingTable_TABLE_LOCAL   NethelpersRoutingTable = 255\n)\n\n// Enum value maps for NethelpersRoutingTable.\nvar (\n\tNethelpersRoutingTable_name = map[int32]string{\n\t\t0:   \"TABLE_UNSPEC\",\n\t\t1:   \"TABLE1\",\n\t\t2:   \"TABLE2\",\n\t\t3:   \"TABLE3\",\n\t\t4:   \"TABLE4\",\n\t\t5:   \"TABLE5\",\n\t\t6:   \"TABLE6\",\n\t\t7:   \"TABLE7\",\n\t\t8:   \"TABLE8\",\n\t\t9:   \"TABLE9\",\n\t\t10:  \"TABLE10\",\n\t\t11:  \"TABLE11\",\n\t\t12:  \"TABLE12\",\n\t\t13:  \"TABLE13\",\n\t\t14:  \"TABLE14\",\n\t\t15:  \"TABLE15\",\n\t\t16:  \"TABLE16\",\n\t\t17:  \"TABLE17\",\n\t\t18:  \"TABLE18\",\n\t\t19:  \"TABLE19\",\n\t\t20:  \"TABLE20\",\n\t\t21:  \"TABLE21\",\n\t\t22:  \"TABLE22\",\n\t\t23:  \"TABLE23\",\n\t\t24:  \"TABLE24\",\n\t\t25:  \"TABLE25\",\n\t\t26:  \"TABLE26\",\n\t\t27:  \"TABLE27\",\n\t\t28:  \"TABLE28\",\n\t\t29:  \"TABLE29\",\n\t\t30:  \"TABLE30\",\n\t\t31:  \"TABLE31\",\n\t\t32:  \"TABLE32\",\n\t\t33:  \"TABLE33\",\n\t\t34:  \"TABLE34\",\n\t\t35:  \"TABLE35\",\n\t\t36:  \"TABLE36\",\n\t\t37:  \"TABLE37\",\n\t\t38:  \"TABLE38\",\n\t\t39:  \"TABLE39\",\n\t\t40:  \"TABLE40\",\n\t\t41:  \"TABLE41\",\n\t\t42:  \"TABLE42\",\n\t\t43:  \"TABLE43\",\n\t\t44:  \"TABLE44\",\n\t\t45:  \"TABLE45\",\n\t\t46:  \"TABLE46\",\n\t\t47:  \"TABLE47\",\n\t\t48:  \"TABLE48\",\n\t\t49:  \"TABLE49\",\n\t\t50:  \"TABLE50\",\n\t\t51:  \"TABLE51\",\n\t\t52:  \"TABLE52\",\n\t\t53:  \"TABLE53\",\n\t\t54:  \"TABLE54\",\n\t\t55:  \"TABLE55\",\n\t\t56:  \"TABLE56\",\n\t\t57:  \"TABLE57\",\n\t\t58:  \"TABLE58\",\n\t\t59:  \"TABLE59\",\n\t\t60:  \"TABLE60\",\n\t\t61:  \"TABLE61\",\n\t\t62:  \"TABLE62\",\n\t\t63:  \"TABLE63\",\n\t\t64:  \"TABLE64\",\n\t\t65:  \"TABLE65\",\n\t\t66:  \"TABLE66\",\n\t\t67:  \"TABLE67\",\n\t\t68:  \"TABLE68\",\n\t\t69:  \"TABLE69\",\n\t\t70:  \"TABLE70\",\n\t\t71:  \"TABLE71\",\n\t\t72:  \"TABLE72\",\n\t\t73:  \"TABLE73\",\n\t\t74:  \"TABLE74\",\n\t\t75:  \"TABLE75\",\n\t\t76:  \"TABLE76\",\n\t\t77:  \"TABLE77\",\n\t\t78:  \"TABLE78\",\n\t\t79:  \"TABLE79\",\n\t\t80:  \"TABLE80\",\n\t\t81:  \"TABLE81\",\n\t\t82:  \"TABLE82\",\n\t\t83:  \"TABLE83\",\n\t\t84:  \"TABLE84\",\n\t\t85:  \"TABLE85\",\n\t\t86:  \"TABLE86\",\n\t\t87:  \"TABLE87\",\n\t\t88:  \"TABLE88\",\n\t\t89:  \"TABLE89\",\n\t\t90:  \"TABLE90\",\n\t\t91:  \"TABLE91\",\n\t\t92:  \"TABLE92\",\n\t\t93:  \"TABLE93\",\n\t\t94:  \"TABLE94\",\n\t\t95:  \"TABLE95\",\n\t\t96:  \"TABLE96\",\n\t\t97:  \"TABLE97\",\n\t\t98:  \"TABLE98\",\n\t\t99:  \"TABLE99\",\n\t\t100: \"TABLE100\",\n\t\t101: \"TABLE101\",\n\t\t102: \"TABLE102\",\n\t\t103: \"TABLE103\",\n\t\t104: \"TABLE104\",\n\t\t105: \"TABLE105\",\n\t\t106: \"TABLE106\",\n\t\t107: \"TABLE107\",\n\t\t108: \"TABLE108\",\n\t\t109: \"TABLE109\",\n\t\t110: \"TABLE110\",\n\t\t111: \"TABLE111\",\n\t\t112: \"TABLE112\",\n\t\t113: \"TABLE113\",\n\t\t114: \"TABLE114\",\n\t\t115: \"TABLE115\",\n\t\t116: \"TABLE116\",\n\t\t117: \"TABLE117\",\n\t\t118: \"TABLE118\",\n\t\t119: \"TABLE119\",\n\t\t120: \"TABLE120\",\n\t\t121: \"TABLE121\",\n\t\t122: \"TABLE122\",\n\t\t123: \"TABLE123\",\n\t\t124: \"TABLE124\",\n\t\t125: \"TABLE125\",\n\t\t126: \"TABLE126\",\n\t\t127: \"TABLE127\",\n\t\t128: \"TABLE128\",\n\t\t129: \"TABLE129\",\n\t\t130: \"TABLE130\",\n\t\t131: \"TABLE131\",\n\t\t132: \"TABLE132\",\n\t\t133: \"TABLE133\",\n\t\t134: \"TABLE134\",\n\t\t135: \"TABLE135\",\n\t\t136: \"TABLE136\",\n\t\t137: \"TABLE137\",\n\t\t138: \"TABLE138\",\n\t\t139: \"TABLE139\",\n\t\t140: \"TABLE140\",\n\t\t141: \"TABLE141\",\n\t\t142: \"TABLE142\",\n\t\t143: \"TABLE143\",\n\t\t144: \"TABLE144\",\n\t\t145: \"TABLE145\",\n\t\t146: \"TABLE146\",\n\t\t147: \"TABLE147\",\n\t\t148: \"TABLE148\",\n\t\t149: \"TABLE149\",\n\t\t150: \"TABLE150\",\n\t\t151: \"TABLE151\",\n\t\t152: \"TABLE152\",\n\t\t153: \"TABLE153\",\n\t\t154: \"TABLE154\",\n\t\t155: \"TABLE155\",\n\t\t156: \"TABLE156\",\n\t\t157: \"TABLE157\",\n\t\t158: \"TABLE158\",\n\t\t159: \"TABLE159\",\n\t\t160: \"TABLE160\",\n\t\t161: \"TABLE161\",\n\t\t162: \"TABLE162\",\n\t\t163: \"TABLE163\",\n\t\t164: \"TABLE164\",\n\t\t165: \"TABLE165\",\n\t\t166: \"TABLE166\",\n\t\t167: \"TABLE167\",\n\t\t168: \"TABLE168\",\n\t\t169: \"TABLE169\",\n\t\t170: \"TABLE170\",\n\t\t171: \"TABLE171\",\n\t\t172: \"TABLE172\",\n\t\t173: \"TABLE173\",\n\t\t174: \"TABLE174\",\n\t\t175: \"TABLE175\",\n\t\t176: \"TABLE176\",\n\t\t177: \"TABLE177\",\n\t\t178: \"TABLE178\",\n\t\t179: \"TABLE179\",\n\t\t180: \"TABLE180\",\n\t\t181: \"TABLE181\",\n\t\t182: \"TABLE182\",\n\t\t183: \"TABLE183\",\n\t\t184: \"TABLE184\",\n\t\t185: \"TABLE185\",\n\t\t186: \"TABLE186\",\n\t\t187: \"TABLE187\",\n\t\t188: \"TABLE188\",\n\t\t189: \"TABLE189\",\n\t\t190: \"TABLE190\",\n\t\t191: \"TABLE191\",\n\t\t192: \"TABLE192\",\n\t\t193: \"TABLE193\",\n\t\t194: \"TABLE194\",\n\t\t195: \"TABLE195\",\n\t\t196: \"TABLE196\",\n\t\t197: \"TABLE197\",\n\t\t198: \"TABLE198\",\n\t\t199: \"TABLE199\",\n\t\t200: \"TABLE200\",\n\t\t201: \"TABLE201\",\n\t\t202: \"TABLE202\",\n\t\t203: \"TABLE203\",\n\t\t204: \"TABLE204\",\n\t\t205: \"TABLE205\",\n\t\t206: \"TABLE206\",\n\t\t207: \"TABLE207\",\n\t\t208: \"TABLE208\",\n\t\t209: \"TABLE209\",\n\t\t210: \"TABLE210\",\n\t\t211: \"TABLE211\",\n\t\t212: \"TABLE212\",\n\t\t213: \"TABLE213\",\n\t\t214: \"TABLE214\",\n\t\t215: \"TABLE215\",\n\t\t216: \"TABLE216\",\n\t\t217: \"TABLE217\",\n\t\t218: \"TABLE218\",\n\t\t219: \"TABLE219\",\n\t\t220: \"TABLE220\",\n\t\t221: \"TABLE221\",\n\t\t222: \"TABLE222\",\n\t\t223: \"TABLE223\",\n\t\t224: \"TABLE224\",\n\t\t225: \"TABLE225\",\n\t\t226: \"TABLE226\",\n\t\t227: \"TABLE227\",\n\t\t228: \"TABLE228\",\n\t\t229: \"TABLE229\",\n\t\t230: \"TABLE230\",\n\t\t231: \"TABLE231\",\n\t\t232: \"TABLE232\",\n\t\t233: \"TABLE233\",\n\t\t234: \"TABLE234\",\n\t\t235: \"TABLE235\",\n\t\t236: \"TABLE236\",\n\t\t237: \"TABLE237\",\n\t\t238: \"TABLE238\",\n\t\t239: \"TABLE239\",\n\t\t240: \"TABLE240\",\n\t\t241: \"TABLE241\",\n\t\t242: \"TABLE242\",\n\t\t243: \"TABLE243\",\n\t\t244: \"TABLE244\",\n\t\t245: \"TABLE245\",\n\t\t246: \"TABLE246\",\n\t\t247: \"TABLE247\",\n\t\t248: \"TABLE248\",\n\t\t249: \"TABLE249\",\n\t\t250: \"TABLE250\",\n\t\t251: \"TABLE251\",\n\t\t252: \"TABLE252\",\n\t\t253: \"TABLE_DEFAULT\",\n\t\t254: \"TABLE_MAIN\",\n\t\t255: \"TABLE_LOCAL\",\n\t}\n\tNethelpersRoutingTable_value = map[string]int32{\n\t\t\"TABLE_UNSPEC\":  0,\n\t\t\"TABLE1\":        1,\n\t\t\"TABLE2\":        2,\n\t\t\"TABLE3\":        3,\n\t\t\"TABLE4\":        4,\n\t\t\"TABLE5\":        5,\n\t\t\"TABLE6\":        6,\n\t\t\"TABLE7\":        7,\n\t\t\"TABLE8\":        8,\n\t\t\"TABLE9\":        9,\n\t\t\"TABLE10\":       10,\n\t\t\"TABLE11\":       11,\n\t\t\"TABLE12\":       12,\n\t\t\"TABLE13\":       13,\n\t\t\"TABLE14\":       14,\n\t\t\"TABLE15\":       15,\n\t\t\"TABLE16\":       16,\n\t\t\"TABLE17\":       17,\n\t\t\"TABLE18\":       18,\n\t\t\"TABLE19\":       19,\n\t\t\"TABLE20\":       20,\n\t\t\"TABLE21\":       21,\n\t\t\"TABLE22\":       22,\n\t\t\"TABLE23\":       23,\n\t\t\"TABLE24\":       24,\n\t\t\"TABLE25\":       25,\n\t\t\"TABLE26\":       26,\n\t\t\"TABLE27\":       27,\n\t\t\"TABLE28\":       28,\n\t\t\"TABLE29\":       29,\n\t\t\"TABLE30\":       30,\n\t\t\"TABLE31\":       31,\n\t\t\"TABLE32\":       32,\n\t\t\"TABLE33\":       33,\n\t\t\"TABLE34\":       34,\n\t\t\"TABLE35\":       35,\n\t\t\"TABLE36\":       36,\n\t\t\"TABLE37\":       37,\n\t\t\"TABLE38\":       38,\n\t\t\"TABLE39\":       39,\n\t\t\"TABLE40\":       40,\n\t\t\"TABLE41\":       41,\n\t\t\"TABLE42\":       42,\n\t\t\"TABLE43\":       43,\n\t\t\"TABLE44\":       44,\n\t\t\"TABLE45\":       45,\n\t\t\"TABLE46\":       46,\n\t\t\"TABLE47\":       47,\n\t\t\"TABLE48\":       48,\n\t\t\"TABLE49\":       49,\n\t\t\"TABLE50\":       50,\n\t\t\"TABLE51\":       51,\n\t\t\"TABLE52\":       52,\n\t\t\"TABLE53\":       53,\n\t\t\"TABLE54\":       54,\n\t\t\"TABLE55\":       55,\n\t\t\"TABLE56\":       56,\n\t\t\"TABLE57\":       57,\n\t\t\"TABLE58\":       58,\n\t\t\"TABLE59\":       59,\n\t\t\"TABLE60\":       60,\n\t\t\"TABLE61\":       61,\n\t\t\"TABLE62\":       62,\n\t\t\"TABLE63\":       63,\n\t\t\"TABLE64\":       64,\n\t\t\"TABLE65\":       65,\n\t\t\"TABLE66\":       66,\n\t\t\"TABLE67\":       67,\n\t\t\"TABLE68\":       68,\n\t\t\"TABLE69\":       69,\n\t\t\"TABLE70\":       70,\n\t\t\"TABLE71\":       71,\n\t\t\"TABLE72\":       72,\n\t\t\"TABLE73\":       73,\n\t\t\"TABLE74\":       74,\n\t\t\"TABLE75\":       75,\n\t\t\"TABLE76\":       76,\n\t\t\"TABLE77\":       77,\n\t\t\"TABLE78\":       78,\n\t\t\"TABLE79\":       79,\n\t\t\"TABLE80\":       80,\n\t\t\"TABLE81\":       81,\n\t\t\"TABLE82\":       82,\n\t\t\"TABLE83\":       83,\n\t\t\"TABLE84\":       84,\n\t\t\"TABLE85\":       85,\n\t\t\"TABLE86\":       86,\n\t\t\"TABLE87\":       87,\n\t\t\"TABLE88\":       88,\n\t\t\"TABLE89\":       89,\n\t\t\"TABLE90\":       90,\n\t\t\"TABLE91\":       91,\n\t\t\"TABLE92\":       92,\n\t\t\"TABLE93\":       93,\n\t\t\"TABLE94\":       94,\n\t\t\"TABLE95\":       95,\n\t\t\"TABLE96\":       96,\n\t\t\"TABLE97\":       97,\n\t\t\"TABLE98\":       98,\n\t\t\"TABLE99\":       99,\n\t\t\"TABLE100\":      100,\n\t\t\"TABLE101\":      101,\n\t\t\"TABLE102\":      102,\n\t\t\"TABLE103\":      103,\n\t\t\"TABLE104\":      104,\n\t\t\"TABLE105\":      105,\n\t\t\"TABLE106\":      106,\n\t\t\"TABLE107\":      107,\n\t\t\"TABLE108\":      108,\n\t\t\"TABLE109\":      109,\n\t\t\"TABLE110\":      110,\n\t\t\"TABLE111\":      111,\n\t\t\"TABLE112\":      112,\n\t\t\"TABLE113\":      113,\n\t\t\"TABLE114\":      114,\n\t\t\"TABLE115\":      115,\n\t\t\"TABLE116\":      116,\n\t\t\"TABLE117\":      117,\n\t\t\"TABLE118\":      118,\n\t\t\"TABLE119\":      119,\n\t\t\"TABLE120\":      120,\n\t\t\"TABLE121\":      121,\n\t\t\"TABLE122\":      122,\n\t\t\"TABLE123\":      123,\n\t\t\"TABLE124\":      124,\n\t\t\"TABLE125\":      125,\n\t\t\"TABLE126\":      126,\n\t\t\"TABLE127\":      127,\n\t\t\"TABLE128\":      128,\n\t\t\"TABLE129\":      129,\n\t\t\"TABLE130\":      130,\n\t\t\"TABLE131\":      131,\n\t\t\"TABLE132\":      132,\n\t\t\"TABLE133\":      133,\n\t\t\"TABLE134\":      134,\n\t\t\"TABLE135\":      135,\n\t\t\"TABLE136\":      136,\n\t\t\"TABLE137\":      137,\n\t\t\"TABLE138\":      138,\n\t\t\"TABLE139\":      139,\n\t\t\"TABLE140\":      140,\n\t\t\"TABLE141\":      141,\n\t\t\"TABLE142\":      142,\n\t\t\"TABLE143\":      143,\n\t\t\"TABLE144\":      144,\n\t\t\"TABLE145\":      145,\n\t\t\"TABLE146\":      146,\n\t\t\"TABLE147\":      147,\n\t\t\"TABLE148\":      148,\n\t\t\"TABLE149\":      149,\n\t\t\"TABLE150\":      150,\n\t\t\"TABLE151\":      151,\n\t\t\"TABLE152\":      152,\n\t\t\"TABLE153\":      153,\n\t\t\"TABLE154\":      154,\n\t\t\"TABLE155\":      155,\n\t\t\"TABLE156\":      156,\n\t\t\"TABLE157\":      157,\n\t\t\"TABLE158\":      158,\n\t\t\"TABLE159\":      159,\n\t\t\"TABLE160\":      160,\n\t\t\"TABLE161\":      161,\n\t\t\"TABLE162\":      162,\n\t\t\"TABLE163\":      163,\n\t\t\"TABLE164\":      164,\n\t\t\"TABLE165\":      165,\n\t\t\"TABLE166\":      166,\n\t\t\"TABLE167\":      167,\n\t\t\"TABLE168\":      168,\n\t\t\"TABLE169\":      169,\n\t\t\"TABLE170\":      170,\n\t\t\"TABLE171\":      171,\n\t\t\"TABLE172\":      172,\n\t\t\"TABLE173\":      173,\n\t\t\"TABLE174\":      174,\n\t\t\"TABLE175\":      175,\n\t\t\"TABLE176\":      176,\n\t\t\"TABLE177\":      177,\n\t\t\"TABLE178\":      178,\n\t\t\"TABLE179\":      179,\n\t\t\"TABLE180\":      180,\n\t\t\"TABLE181\":      181,\n\t\t\"TABLE182\":      182,\n\t\t\"TABLE183\":      183,\n\t\t\"TABLE184\":      184,\n\t\t\"TABLE185\":      185,\n\t\t\"TABLE186\":      186,\n\t\t\"TABLE187\":      187,\n\t\t\"TABLE188\":      188,\n\t\t\"TABLE189\":      189,\n\t\t\"TABLE190\":      190,\n\t\t\"TABLE191\":      191,\n\t\t\"TABLE192\":      192,\n\t\t\"TABLE193\":      193,\n\t\t\"TABLE194\":      194,\n\t\t\"TABLE195\":      195,\n\t\t\"TABLE196\":      196,\n\t\t\"TABLE197\":      197,\n\t\t\"TABLE198\":      198,\n\t\t\"TABLE199\":      199,\n\t\t\"TABLE200\":      200,\n\t\t\"TABLE201\":      201,\n\t\t\"TABLE202\":      202,\n\t\t\"TABLE203\":      203,\n\t\t\"TABLE204\":      204,\n\t\t\"TABLE205\":      205,\n\t\t\"TABLE206\":      206,\n\t\t\"TABLE207\":      207,\n\t\t\"TABLE208\":      208,\n\t\t\"TABLE209\":      209,\n\t\t\"TABLE210\":      210,\n\t\t\"TABLE211\":      211,\n\t\t\"TABLE212\":      212,\n\t\t\"TABLE213\":      213,\n\t\t\"TABLE214\":      214,\n\t\t\"TABLE215\":      215,\n\t\t\"TABLE216\":      216,\n\t\t\"TABLE217\":      217,\n\t\t\"TABLE218\":      218,\n\t\t\"TABLE219\":      219,\n\t\t\"TABLE220\":      220,\n\t\t\"TABLE221\":      221,\n\t\t\"TABLE222\":      222,\n\t\t\"TABLE223\":      223,\n\t\t\"TABLE224\":      224,\n\t\t\"TABLE225\":      225,\n\t\t\"TABLE226\":      226,\n\t\t\"TABLE227\":      227,\n\t\t\"TABLE228\":      228,\n\t\t\"TABLE229\":      229,\n\t\t\"TABLE230\":      230,\n\t\t\"TABLE231\":      231,\n\t\t\"TABLE232\":      232,\n\t\t\"TABLE233\":      233,\n\t\t\"TABLE234\":      234,\n\t\t\"TABLE235\":      235,\n\t\t\"TABLE236\":      236,\n\t\t\"TABLE237\":      237,\n\t\t\"TABLE238\":      238,\n\t\t\"TABLE239\":      239,\n\t\t\"TABLE240\":      240,\n\t\t\"TABLE241\":      241,\n\t\t\"TABLE242\":      242,\n\t\t\"TABLE243\":      243,\n\t\t\"TABLE244\":      244,\n\t\t\"TABLE245\":      245,\n\t\t\"TABLE246\":      246,\n\t\t\"TABLE247\":      247,\n\t\t\"TABLE248\":      248,\n\t\t\"TABLE249\":      249,\n\t\t\"TABLE250\":      250,\n\t\t\"TABLE251\":      251,\n\t\t\"TABLE252\":      252,\n\t\t\"TABLE_DEFAULT\": 253,\n\t\t\"TABLE_MAIN\":    254,\n\t\t\"TABLE_LOCAL\":   255,\n\t}\n)\n\nfunc (x NethelpersRoutingTable) Enum() *NethelpersRoutingTable {\n\tp := new(NethelpersRoutingTable)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersRoutingTable) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersRoutingTable) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[33].Descriptor()\n}\n\nfunc (NethelpersRoutingTable) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[33]\n}\n\nfunc (x NethelpersRoutingTable) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersRoutingTable.Descriptor instead.\nfunc (NethelpersRoutingTable) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{33}\n}\n\n// NethelpersScope is an address scope.\ntype NethelpersScope int32\n\nconst (\n\tNethelpersScope_SCOPE_GLOBAL  NethelpersScope = 0\n\tNethelpersScope_SCOPE_SITE    NethelpersScope = 200\n\tNethelpersScope_SCOPE_LINK    NethelpersScope = 253\n\tNethelpersScope_SCOPE_HOST    NethelpersScope = 254\n\tNethelpersScope_SCOPE_NOWHERE NethelpersScope = 255\n)\n\n// Enum value maps for NethelpersScope.\nvar (\n\tNethelpersScope_name = map[int32]string{\n\t\t0:   \"SCOPE_GLOBAL\",\n\t\t200: \"SCOPE_SITE\",\n\t\t253: \"SCOPE_LINK\",\n\t\t254: \"SCOPE_HOST\",\n\t\t255: \"SCOPE_NOWHERE\",\n\t}\n\tNethelpersScope_value = map[string]int32{\n\t\t\"SCOPE_GLOBAL\":  0,\n\t\t\"SCOPE_SITE\":    200,\n\t\t\"SCOPE_LINK\":    253,\n\t\t\"SCOPE_HOST\":    254,\n\t\t\"SCOPE_NOWHERE\": 255,\n\t}\n)\n\nfunc (x NethelpersScope) Enum() *NethelpersScope {\n\tp := new(NethelpersScope)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersScope) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersScope) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[34].Descriptor()\n}\n\nfunc (NethelpersScope) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[34]\n}\n\nfunc (x NethelpersScope) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersScope.Descriptor instead.\nfunc (NethelpersScope) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{34}\n}\n\n// NethelpersVLANProtocol is a VLAN protocol.\ntype NethelpersVLANProtocol int32\n\nconst (\n\tNethelpersVLANProtocol_NETHELPERS_VLANPROTOCOL_UNSPECIFIED NethelpersVLANProtocol = 0\n\tNethelpersVLANProtocol_VLAN_PROTOCOL8021_Q                 NethelpersVLANProtocol = 33024\n\tNethelpersVLANProtocol_VLAN_PROTOCOL8021_AD                NethelpersVLANProtocol = 34984\n)\n\n// Enum value maps for NethelpersVLANProtocol.\nvar (\n\tNethelpersVLANProtocol_name = map[int32]string{\n\t\t0:     \"NETHELPERS_VLANPROTOCOL_UNSPECIFIED\",\n\t\t33024: \"VLAN_PROTOCOL8021_Q\",\n\t\t34984: \"VLAN_PROTOCOL8021_AD\",\n\t}\n\tNethelpersVLANProtocol_value = map[string]int32{\n\t\t\"NETHELPERS_VLANPROTOCOL_UNSPECIFIED\": 0,\n\t\t\"VLAN_PROTOCOL8021_Q\":                 33024,\n\t\t\"VLAN_PROTOCOL8021_AD\":                34984,\n\t}\n)\n\nfunc (x NethelpersVLANProtocol) Enum() *NethelpersVLANProtocol {\n\tp := new(NethelpersVLANProtocol)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersVLANProtocol) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersVLANProtocol) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[35].Descriptor()\n}\n\nfunc (NethelpersVLANProtocol) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[35]\n}\n\nfunc (x NethelpersVLANProtocol) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersVLANProtocol.Descriptor instead.\nfunc (NethelpersVLANProtocol) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{35}\n}\n\n// NethelpersWOLMode wraps ethtool.WOLMode for YAML marshaling.\ntype NethelpersWOLMode int32\n\nconst (\n\tNethelpersWOLMode_NETHELPERS_WOLMODE_UNSPECIFIED NethelpersWOLMode = 0\n\tNethelpersWOLMode_WOL_MODE_PHY                   NethelpersWOLMode = 1\n\tNethelpersWOLMode_WOL_MODE_UNICAST               NethelpersWOLMode = 2\n\tNethelpersWOLMode_WOL_MODE_MULTICAST             NethelpersWOLMode = 4\n\tNethelpersWOLMode_WOL_MODE_BROADCAST             NethelpersWOLMode = 8\n\tNethelpersWOLMode_WOL_MODE_MAGIC                 NethelpersWOLMode = 32\n\tNethelpersWOLMode_WOL_MODE_MAGIC_SECURE          NethelpersWOLMode = 64\n\tNethelpersWOLMode_WOL_MODE_FILTER                NethelpersWOLMode = 128\n)\n\n// Enum value maps for NethelpersWOLMode.\nvar (\n\tNethelpersWOLMode_name = map[int32]string{\n\t\t0:   \"NETHELPERS_WOLMODE_UNSPECIFIED\",\n\t\t1:   \"WOL_MODE_PHY\",\n\t\t2:   \"WOL_MODE_UNICAST\",\n\t\t4:   \"WOL_MODE_MULTICAST\",\n\t\t8:   \"WOL_MODE_BROADCAST\",\n\t\t32:  \"WOL_MODE_MAGIC\",\n\t\t64:  \"WOL_MODE_MAGIC_SECURE\",\n\t\t128: \"WOL_MODE_FILTER\",\n\t}\n\tNethelpersWOLMode_value = map[string]int32{\n\t\t\"NETHELPERS_WOLMODE_UNSPECIFIED\": 0,\n\t\t\"WOL_MODE_PHY\":                   1,\n\t\t\"WOL_MODE_UNICAST\":               2,\n\t\t\"WOL_MODE_MULTICAST\":             4,\n\t\t\"WOL_MODE_BROADCAST\":             8,\n\t\t\"WOL_MODE_MAGIC\":                 32,\n\t\t\"WOL_MODE_MAGIC_SECURE\":          64,\n\t\t\"WOL_MODE_FILTER\":                128,\n\t}\n)\n\nfunc (x NethelpersWOLMode) Enum() *NethelpersWOLMode {\n\tp := new(NethelpersWOLMode)\n\t*p = x\n\treturn p\n}\n\nfunc (x NethelpersWOLMode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NethelpersWOLMode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[36].Descriptor()\n}\n\nfunc (NethelpersWOLMode) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[36]\n}\n\nfunc (x NethelpersWOLMode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NethelpersWOLMode.Descriptor instead.\nfunc (NethelpersWOLMode) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{36}\n}\n\n// BlockEncryptionKeyType describes encryption key type.\ntype BlockEncryptionKeyType int32\n\nconst (\n\tBlockEncryptionKeyType_ENCRYPTION_KEY_STATIC  BlockEncryptionKeyType = 0\n\tBlockEncryptionKeyType_ENCRYPTION_KEY_NODE_ID BlockEncryptionKeyType = 1\n\tBlockEncryptionKeyType_ENCRYPTION_KEY_KMS     BlockEncryptionKeyType = 2\n\tBlockEncryptionKeyType_ENCRYPTION_KEY_TPM     BlockEncryptionKeyType = 3\n)\n\n// Enum value maps for BlockEncryptionKeyType.\nvar (\n\tBlockEncryptionKeyType_name = map[int32]string{\n\t\t0: \"ENCRYPTION_KEY_STATIC\",\n\t\t1: \"ENCRYPTION_KEY_NODE_ID\",\n\t\t2: \"ENCRYPTION_KEY_KMS\",\n\t\t3: \"ENCRYPTION_KEY_TPM\",\n\t}\n\tBlockEncryptionKeyType_value = map[string]int32{\n\t\t\"ENCRYPTION_KEY_STATIC\":  0,\n\t\t\"ENCRYPTION_KEY_NODE_ID\": 1,\n\t\t\"ENCRYPTION_KEY_KMS\":     2,\n\t\t\"ENCRYPTION_KEY_TPM\":     3,\n\t}\n)\n\nfunc (x BlockEncryptionKeyType) Enum() *BlockEncryptionKeyType {\n\tp := new(BlockEncryptionKeyType)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockEncryptionKeyType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockEncryptionKeyType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[37].Descriptor()\n}\n\nfunc (BlockEncryptionKeyType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[37]\n}\n\nfunc (x BlockEncryptionKeyType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockEncryptionKeyType.Descriptor instead.\nfunc (BlockEncryptionKeyType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{37}\n}\n\n// BlockEncryptionProviderType describes encryption provider type.\ntype BlockEncryptionProviderType int32\n\nconst (\n\tBlockEncryptionProviderType_ENCRYPTION_PROVIDER_NONE  BlockEncryptionProviderType = 0\n\tBlockEncryptionProviderType_ENCRYPTION_PROVIDER_LUKS2 BlockEncryptionProviderType = 1\n)\n\n// Enum value maps for BlockEncryptionProviderType.\nvar (\n\tBlockEncryptionProviderType_name = map[int32]string{\n\t\t0: \"ENCRYPTION_PROVIDER_NONE\",\n\t\t1: \"ENCRYPTION_PROVIDER_LUKS2\",\n\t}\n\tBlockEncryptionProviderType_value = map[string]int32{\n\t\t\"ENCRYPTION_PROVIDER_NONE\":  0,\n\t\t\"ENCRYPTION_PROVIDER_LUKS2\": 1,\n\t}\n)\n\nfunc (x BlockEncryptionProviderType) Enum() *BlockEncryptionProviderType {\n\tp := new(BlockEncryptionProviderType)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockEncryptionProviderType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockEncryptionProviderType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[38].Descriptor()\n}\n\nfunc (BlockEncryptionProviderType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[38]\n}\n\nfunc (x BlockEncryptionProviderType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockEncryptionProviderType.Descriptor instead.\nfunc (BlockEncryptionProviderType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{38}\n}\n\n// BlockFilesystemType describes filesystem type.\ntype BlockFilesystemType int32\n\nconst (\n\tBlockFilesystemType_FILESYSTEM_TYPE_NONE     BlockFilesystemType = 0\n\tBlockFilesystemType_FILESYSTEM_TYPE_XFS      BlockFilesystemType = 1\n\tBlockFilesystemType_FILESYSTEM_TYPE_VFAT     BlockFilesystemType = 2\n\tBlockFilesystemType_FILESYSTEM_TYPE_EXT4     BlockFilesystemType = 3\n\tBlockFilesystemType_FILESYSTEM_TYPE_ISO9660  BlockFilesystemType = 4\n\tBlockFilesystemType_FILESYSTEM_TYPE_SWAP     BlockFilesystemType = 5\n\tBlockFilesystemType_FILESYSTEM_TYPE_VIRTIOFS BlockFilesystemType = 6\n)\n\n// Enum value maps for BlockFilesystemType.\nvar (\n\tBlockFilesystemType_name = map[int32]string{\n\t\t0: \"FILESYSTEM_TYPE_NONE\",\n\t\t1: \"FILESYSTEM_TYPE_XFS\",\n\t\t2: \"FILESYSTEM_TYPE_VFAT\",\n\t\t3: \"FILESYSTEM_TYPE_EXT4\",\n\t\t4: \"FILESYSTEM_TYPE_ISO9660\",\n\t\t5: \"FILESYSTEM_TYPE_SWAP\",\n\t\t6: \"FILESYSTEM_TYPE_VIRTIOFS\",\n\t}\n\tBlockFilesystemType_value = map[string]int32{\n\t\t\"FILESYSTEM_TYPE_NONE\":     0,\n\t\t\"FILESYSTEM_TYPE_XFS\":      1,\n\t\t\"FILESYSTEM_TYPE_VFAT\":     2,\n\t\t\"FILESYSTEM_TYPE_EXT4\":     3,\n\t\t\"FILESYSTEM_TYPE_ISO9660\":  4,\n\t\t\"FILESYSTEM_TYPE_SWAP\":     5,\n\t\t\"FILESYSTEM_TYPE_VIRTIOFS\": 6,\n\t}\n)\n\nfunc (x BlockFilesystemType) Enum() *BlockFilesystemType {\n\tp := new(BlockFilesystemType)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockFilesystemType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockFilesystemType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[39].Descriptor()\n}\n\nfunc (BlockFilesystemType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[39]\n}\n\nfunc (x BlockFilesystemType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockFilesystemType.Descriptor instead.\nfunc (BlockFilesystemType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{39}\n}\n\n// BlockFSParameterType describes Filesystem Parameter type.\ntype BlockFSParameterType int32\n\nconst (\n\tBlockFSParameterType_FS_PARAMETER_TYPE_STRING_VALUE  BlockFSParameterType = 0\n\tBlockFSParameterType_FS_PARAMETER_TYPE_BOOLEAN_VALUE BlockFSParameterType = 1\n\tBlockFSParameterType_FS_PARAMETER_TYPE_BINARY_VALUE  BlockFSParameterType = 2\n)\n\n// Enum value maps for BlockFSParameterType.\nvar (\n\tBlockFSParameterType_name = map[int32]string{\n\t\t0: \"FS_PARAMETER_TYPE_STRING_VALUE\",\n\t\t1: \"FS_PARAMETER_TYPE_BOOLEAN_VALUE\",\n\t\t2: \"FS_PARAMETER_TYPE_BINARY_VALUE\",\n\t}\n\tBlockFSParameterType_value = map[string]int32{\n\t\t\"FS_PARAMETER_TYPE_STRING_VALUE\":  0,\n\t\t\"FS_PARAMETER_TYPE_BOOLEAN_VALUE\": 1,\n\t\t\"FS_PARAMETER_TYPE_BINARY_VALUE\":  2,\n\t}\n)\n\nfunc (x BlockFSParameterType) Enum() *BlockFSParameterType {\n\tp := new(BlockFSParameterType)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockFSParameterType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockFSParameterType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[40].Descriptor()\n}\n\nfunc (BlockFSParameterType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[40]\n}\n\nfunc (x BlockFSParameterType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockFSParameterType.Descriptor instead.\nfunc (BlockFSParameterType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{40}\n}\n\n// BlockVolumePhase describes volume phase.\ntype BlockVolumePhase int32\n\nconst (\n\tBlockVolumePhase_VOLUME_PHASE_WAITING     BlockVolumePhase = 0\n\tBlockVolumePhase_VOLUME_PHASE_FAILED      BlockVolumePhase = 1\n\tBlockVolumePhase_VOLUME_PHASE_MISSING     BlockVolumePhase = 2\n\tBlockVolumePhase_VOLUME_PHASE_LOCATED     BlockVolumePhase = 3\n\tBlockVolumePhase_VOLUME_PHASE_PROVISIONED BlockVolumePhase = 4\n\tBlockVolumePhase_VOLUME_PHASE_PREPARED    BlockVolumePhase = 5\n\tBlockVolumePhase_VOLUME_PHASE_READY       BlockVolumePhase = 6\n\tBlockVolumePhase_VOLUME_PHASE_CLOSED      BlockVolumePhase = 7\n)\n\n// Enum value maps for BlockVolumePhase.\nvar (\n\tBlockVolumePhase_name = map[int32]string{\n\t\t0: \"VOLUME_PHASE_WAITING\",\n\t\t1: \"VOLUME_PHASE_FAILED\",\n\t\t2: \"VOLUME_PHASE_MISSING\",\n\t\t3: \"VOLUME_PHASE_LOCATED\",\n\t\t4: \"VOLUME_PHASE_PROVISIONED\",\n\t\t5: \"VOLUME_PHASE_PREPARED\",\n\t\t6: \"VOLUME_PHASE_READY\",\n\t\t7: \"VOLUME_PHASE_CLOSED\",\n\t}\n\tBlockVolumePhase_value = map[string]int32{\n\t\t\"VOLUME_PHASE_WAITING\":     0,\n\t\t\"VOLUME_PHASE_FAILED\":      1,\n\t\t\"VOLUME_PHASE_MISSING\":     2,\n\t\t\"VOLUME_PHASE_LOCATED\":     3,\n\t\t\"VOLUME_PHASE_PROVISIONED\": 4,\n\t\t\"VOLUME_PHASE_PREPARED\":    5,\n\t\t\"VOLUME_PHASE_READY\":       6,\n\t\t\"VOLUME_PHASE_CLOSED\":      7,\n\t}\n)\n\nfunc (x BlockVolumePhase) Enum() *BlockVolumePhase {\n\tp := new(BlockVolumePhase)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockVolumePhase) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockVolumePhase) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[41].Descriptor()\n}\n\nfunc (BlockVolumePhase) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[41]\n}\n\nfunc (x BlockVolumePhase) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockVolumePhase.Descriptor instead.\nfunc (BlockVolumePhase) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{41}\n}\n\n// BlockVolumeType describes volume type.\ntype BlockVolumeType int32\n\nconst (\n\tBlockVolumeType_VOLUME_TYPE_PARTITION BlockVolumeType = 0\n\tBlockVolumeType_VOLUME_TYPE_DISK      BlockVolumeType = 1\n\tBlockVolumeType_VOLUME_TYPE_TMPFS     BlockVolumeType = 2\n\tBlockVolumeType_VOLUME_TYPE_DIRECTORY BlockVolumeType = 3\n\tBlockVolumeType_VOLUME_TYPE_SYMLINK   BlockVolumeType = 4\n\tBlockVolumeType_VOLUME_TYPE_OVERLAY   BlockVolumeType = 5\n\tBlockVolumeType_VOLUME_TYPE_EXTERNAL  BlockVolumeType = 6\n)\n\n// Enum value maps for BlockVolumeType.\nvar (\n\tBlockVolumeType_name = map[int32]string{\n\t\t0: \"VOLUME_TYPE_PARTITION\",\n\t\t1: \"VOLUME_TYPE_DISK\",\n\t\t2: \"VOLUME_TYPE_TMPFS\",\n\t\t3: \"VOLUME_TYPE_DIRECTORY\",\n\t\t4: \"VOLUME_TYPE_SYMLINK\",\n\t\t5: \"VOLUME_TYPE_OVERLAY\",\n\t\t6: \"VOLUME_TYPE_EXTERNAL\",\n\t}\n\tBlockVolumeType_value = map[string]int32{\n\t\t\"VOLUME_TYPE_PARTITION\": 0,\n\t\t\"VOLUME_TYPE_DISK\":      1,\n\t\t\"VOLUME_TYPE_TMPFS\":     2,\n\t\t\"VOLUME_TYPE_DIRECTORY\": 3,\n\t\t\"VOLUME_TYPE_SYMLINK\":   4,\n\t\t\"VOLUME_TYPE_OVERLAY\":   5,\n\t\t\"VOLUME_TYPE_EXTERNAL\":  6,\n\t}\n)\n\nfunc (x BlockVolumeType) Enum() *BlockVolumeType {\n\tp := new(BlockVolumeType)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockVolumeType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockVolumeType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[42].Descriptor()\n}\n\nfunc (BlockVolumeType) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[42]\n}\n\nfunc (x BlockVolumeType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockVolumeType.Descriptor instead.\nfunc (BlockVolumeType) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{42}\n}\n\n// CriImageCacheStatus describes image cache status type.\ntype CriImageCacheStatus int32\n\nconst (\n\tCriImageCacheStatus_IMAGE_CACHE_STATUS_UNKNOWN   CriImageCacheStatus = 0\n\tCriImageCacheStatus_IMAGE_CACHE_STATUS_DISABLED  CriImageCacheStatus = 1\n\tCriImageCacheStatus_IMAGE_CACHE_STATUS_PREPARING CriImageCacheStatus = 2\n\tCriImageCacheStatus_IMAGE_CACHE_STATUS_READY     CriImageCacheStatus = 3\n)\n\n// Enum value maps for CriImageCacheStatus.\nvar (\n\tCriImageCacheStatus_name = map[int32]string{\n\t\t0: \"IMAGE_CACHE_STATUS_UNKNOWN\",\n\t\t1: \"IMAGE_CACHE_STATUS_DISABLED\",\n\t\t2: \"IMAGE_CACHE_STATUS_PREPARING\",\n\t\t3: \"IMAGE_CACHE_STATUS_READY\",\n\t}\n\tCriImageCacheStatus_value = map[string]int32{\n\t\t\"IMAGE_CACHE_STATUS_UNKNOWN\":   0,\n\t\t\"IMAGE_CACHE_STATUS_DISABLED\":  1,\n\t\t\"IMAGE_CACHE_STATUS_PREPARING\": 2,\n\t\t\"IMAGE_CACHE_STATUS_READY\":     3,\n\t}\n)\n\nfunc (x CriImageCacheStatus) Enum() *CriImageCacheStatus {\n\tp := new(CriImageCacheStatus)\n\t*p = x\n\treturn p\n}\n\nfunc (x CriImageCacheStatus) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (CriImageCacheStatus) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[43].Descriptor()\n}\n\nfunc (CriImageCacheStatus) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[43]\n}\n\nfunc (x CriImageCacheStatus) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use CriImageCacheStatus.Descriptor instead.\nfunc (CriImageCacheStatus) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{43}\n}\n\n// CriImageCacheCopyStatus describes image cache copy status type.\ntype CriImageCacheCopyStatus int32\n\nconst (\n\tCriImageCacheCopyStatus_IMAGE_CACHE_COPY_STATUS_UNKNOWN CriImageCacheCopyStatus = 0\n\tCriImageCacheCopyStatus_IMAGE_CACHE_COPY_STATUS_SKIPPED CriImageCacheCopyStatus = 1\n\tCriImageCacheCopyStatus_IMAGE_CACHE_COPY_STATUS_PENDING CriImageCacheCopyStatus = 2\n\tCriImageCacheCopyStatus_IMAGE_CACHE_COPY_STATUS_READY   CriImageCacheCopyStatus = 3\n)\n\n// Enum value maps for CriImageCacheCopyStatus.\nvar (\n\tCriImageCacheCopyStatus_name = map[int32]string{\n\t\t0: \"IMAGE_CACHE_COPY_STATUS_UNKNOWN\",\n\t\t1: \"IMAGE_CACHE_COPY_STATUS_SKIPPED\",\n\t\t2: \"IMAGE_CACHE_COPY_STATUS_PENDING\",\n\t\t3: \"IMAGE_CACHE_COPY_STATUS_READY\",\n\t}\n\tCriImageCacheCopyStatus_value = map[string]int32{\n\t\t\"IMAGE_CACHE_COPY_STATUS_UNKNOWN\": 0,\n\t\t\"IMAGE_CACHE_COPY_STATUS_SKIPPED\": 1,\n\t\t\"IMAGE_CACHE_COPY_STATUS_PENDING\": 2,\n\t\t\"IMAGE_CACHE_COPY_STATUS_READY\":   3,\n\t}\n)\n\nfunc (x CriImageCacheCopyStatus) Enum() *CriImageCacheCopyStatus {\n\tp := new(CriImageCacheCopyStatus)\n\t*p = x\n\treturn p\n}\n\nfunc (x CriImageCacheCopyStatus) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (CriImageCacheCopyStatus) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[44].Descriptor()\n}\n\nfunc (CriImageCacheCopyStatus) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[44]\n}\n\nfunc (x CriImageCacheCopyStatus) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use CriImageCacheCopyStatus.Descriptor instead.\nfunc (CriImageCacheCopyStatus) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{44}\n}\n\n// KubespanPeerState is KubeSpan peer current state.\ntype KubespanPeerState int32\n\nconst (\n\tKubespanPeerState_PEER_STATE_UNKNOWN KubespanPeerState = 0\n\tKubespanPeerState_PEER_STATE_UP      KubespanPeerState = 1\n\tKubespanPeerState_PEER_STATE_DOWN    KubespanPeerState = 2\n)\n\n// Enum value maps for KubespanPeerState.\nvar (\n\tKubespanPeerState_name = map[int32]string{\n\t\t0: \"PEER_STATE_UNKNOWN\",\n\t\t1: \"PEER_STATE_UP\",\n\t\t2: \"PEER_STATE_DOWN\",\n\t}\n\tKubespanPeerState_value = map[string]int32{\n\t\t\"PEER_STATE_UNKNOWN\": 0,\n\t\t\"PEER_STATE_UP\":      1,\n\t\t\"PEER_STATE_DOWN\":    2,\n\t}\n)\n\nfunc (x KubespanPeerState) Enum() *KubespanPeerState {\n\tp := new(KubespanPeerState)\n\t*p = x\n\treturn p\n}\n\nfunc (x KubespanPeerState) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (KubespanPeerState) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[45].Descriptor()\n}\n\nfunc (KubespanPeerState) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[45]\n}\n\nfunc (x KubespanPeerState) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use KubespanPeerState.Descriptor instead.\nfunc (KubespanPeerState) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{45}\n}\n\n// NetworkConfigLayer describes network configuration layers, with lowest priority first.\ntype NetworkConfigLayer int32\n\nconst (\n\tNetworkConfigLayer_CONFIG_DEFAULT               NetworkConfigLayer = 0\n\tNetworkConfigLayer_CONFIG_CMDLINE               NetworkConfigLayer = 1\n\tNetworkConfigLayer_CONFIG_PLATFORM              NetworkConfigLayer = 2\n\tNetworkConfigLayer_CONFIG_OPERATOR              NetworkConfigLayer = 3\n\tNetworkConfigLayer_CONFIG_MACHINE_CONFIGURATION NetworkConfigLayer = 4\n)\n\n// Enum value maps for NetworkConfigLayer.\nvar (\n\tNetworkConfigLayer_name = map[int32]string{\n\t\t0: \"CONFIG_DEFAULT\",\n\t\t1: \"CONFIG_CMDLINE\",\n\t\t2: \"CONFIG_PLATFORM\",\n\t\t3: \"CONFIG_OPERATOR\",\n\t\t4: \"CONFIG_MACHINE_CONFIGURATION\",\n\t}\n\tNetworkConfigLayer_value = map[string]int32{\n\t\t\"CONFIG_DEFAULT\":               0,\n\t\t\"CONFIG_CMDLINE\":               1,\n\t\t\"CONFIG_PLATFORM\":              2,\n\t\t\"CONFIG_OPERATOR\":              3,\n\t\t\"CONFIG_MACHINE_CONFIGURATION\": 4,\n\t}\n)\n\nfunc (x NetworkConfigLayer) Enum() *NetworkConfigLayer {\n\tp := new(NetworkConfigLayer)\n\t*p = x\n\treturn p\n}\n\nfunc (x NetworkConfigLayer) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NetworkConfigLayer) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[46].Descriptor()\n}\n\nfunc (NetworkConfigLayer) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[46]\n}\n\nfunc (x NetworkConfigLayer) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NetworkConfigLayer.Descriptor instead.\nfunc (NetworkConfigLayer) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{46}\n}\n\n// NetworkOperator enumerates Talos network operators.\ntype NetworkOperator int32\n\nconst (\n\tNetworkOperator_OPERATOR_DHCP4 NetworkOperator = 0\n\tNetworkOperator_OPERATOR_DHCP6 NetworkOperator = 1\n\tNetworkOperator_OPERATOR_VIP   NetworkOperator = 2\n)\n\n// Enum value maps for NetworkOperator.\nvar (\n\tNetworkOperator_name = map[int32]string{\n\t\t0: \"OPERATOR_DHCP4\",\n\t\t1: \"OPERATOR_DHCP6\",\n\t\t2: \"OPERATOR_VIP\",\n\t}\n\tNetworkOperator_value = map[string]int32{\n\t\t\"OPERATOR_DHCP4\": 0,\n\t\t\"OPERATOR_DHCP6\": 1,\n\t\t\"OPERATOR_VIP\":   2,\n\t}\n)\n\nfunc (x NetworkOperator) Enum() *NetworkOperator {\n\tp := new(NetworkOperator)\n\t*p = x\n\treturn p\n}\n\nfunc (x NetworkOperator) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (NetworkOperator) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_resource_definitions_enums_enums_proto_enumTypes[47].Descriptor()\n}\n\nfunc (NetworkOperator) Type() protoreflect.EnumType {\n\treturn &file_resource_definitions_enums_enums_proto_enumTypes[47]\n}\n\nfunc (x NetworkOperator) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use NetworkOperator.Descriptor instead.\nfunc (NetworkOperator) EnumDescriptor() ([]byte, []int) {\n\treturn file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{47}\n}\n\nvar File_resource_definitions_enums_enums_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_enums_enums_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"&resource/definitions/enums/enums.proto\\x12 talos.resource.definitions.enums*\\x9b\\x02\\n\" +\n\t\"\\x13RuntimeMachineStage\\x12\\x19\\n\" +\n\t\"\\x15MACHINE_STAGE_UNKNOWN\\x10\\x00\\x12\\x19\\n\" +\n\t\"\\x15MACHINE_STAGE_BOOTING\\x10\\x01\\x12\\x1c\\n\" +\n\t\"\\x18MACHINE_STAGE_INSTALLING\\x10\\x02\\x12\\x1d\\n\" +\n\t\"\\x19MACHINE_STAGE_MAINTENANCE\\x10\\x03\\x12\\x19\\n\" +\n\t\"\\x15MACHINE_STAGE_RUNNING\\x10\\x04\\x12\\x1b\\n\" +\n\t\"\\x17MACHINE_STAGE_REBOOTING\\x10\\x05\\x12\\x1f\\n\" +\n\t\"\\x1bMACHINE_STAGE_SHUTTING_DOWN\\x10\\x06\\x12\\x1b\\n\" +\n\t\"\\x17MACHINE_STAGE_RESETTING\\x10\\a\\x12\\x1b\\n\" +\n\t\"\\x17MACHINE_STAGE_UPGRADING\\x10\\b*o\\n\" +\n\t\"\\x13RuntimeSELinuxState\\x12\\x1b\\n\" +\n\t\"\\x17SE_LINUX_STATE_DISABLED\\x10\\x00\\x12\\x1d\\n\" +\n\t\"\\x19SE_LINUX_STATE_PERMISSIVE\\x10\\x01\\x12\\x1c\\n\" +\n\t\"\\x18SE_LINUX_STATE_ENFORCING\\x10\\x02*Z\\n\" +\n\t\"\\x10RuntimeFIPSState\\x12\\x17\\n\" +\n\t\"\\x13FIPS_STATE_DISABLED\\x10\\x00\\x12\\x16\\n\" +\n\t\"\\x12FIPS_STATE_ENABLED\\x10\\x01\\x12\\x15\\n\" +\n\t\"\\x11FIPS_STATE_STRICT\\x10\\x02*W\\n\" +\n\t\"\\vMachineType\\x12\\x10\\n\" +\n\t\"\\fTYPE_UNKNOWN\\x10\\x00\\x12\\r\\n\" +\n\t\"\\tTYPE_INIT\\x10\\x01\\x12\\x16\\n\" +\n\t\"\\x12TYPE_CONTROL_PLANE\\x10\\x02\\x12\\x0f\\n\" +\n\t\"\\vTYPE_WORKER\\x10\\x03*\\xe7\\x02\\n\" +\n\t\"\\x15NethelpersAddressFlag\\x12&\\n\" +\n\t\"\\\"NETHELPERS_ADDRESSFLAG_UNSPECIFIED\\x10\\x00\\x12\\x15\\n\" +\n\t\"\\x11ADDRESS_TEMPORARY\\x10\\x01\\x12\\x12\\n\" +\n\t\"\\x0eADDRESS_NO_DAD\\x10\\x02\\x12\\x16\\n\" +\n\t\"\\x12ADDRESS_OPTIMISTIC\\x10\\x04\\x12\\x16\\n\" +\n\t\"\\x12ADDRESS_DAD_FAILED\\x10\\b\\x12\\x10\\n\" +\n\t\"\\fADDRESS_HOME\\x10\\x10\\x12\\x16\\n\" +\n\t\"\\x12ADDRESS_DEPRECATED\\x10 \\x12\\x15\\n\" +\n\t\"\\x11ADDRESS_TENTATIVE\\x10@\\x12\\x16\\n\" +\n\t\"\\x11ADDRESS_PERMANENT\\x10\\x80\\x01\\x12\\x1c\\n\" +\n\t\"\\x17ADDRESS_MANAGEMENT_TEMP\\x10\\x80\\x02\\x12\\x1c\\n\" +\n\t\"\\x17ADDRESS_NO_PREFIX_ROUTE\\x10\\x80\\x04\\x12\\x19\\n\" +\n\t\"\\x14ADDRESS_MC_AUTO_JOIN\\x10\\x80\\b\\x12\\x1b\\n\" +\n\t\"\\x16ADDRESS_STABLE_PRIVACY\\x10\\x80\\x10*^\\n\" +\n\t\"\\x1eNethelpersAddressSortAlgorithm\\x12\\x1d\\n\" +\n\t\"\\x19ADDRESS_SORT_ALGORITHM_V1\\x10\\x00\\x12\\x1d\\n\" +\n\t\"\\x19ADDRESS_SORT_ALGORITHM_V2\\x10\\x01*E\\n\" +\n\t\"\\x16NethelpersADLACPActive\\x12\\x15\\n\" +\n\t\"\\x11ADLACP_ACTIVE_OFF\\x10\\x00\\x12\\x14\\n\" +\n\t\"\\x10ADLACP_ACTIVE_ON\\x10\\x01*X\\n\" +\n\t\"\\x12NethelpersADSelect\\x12\\x14\\n\" +\n\t\"\\x10AD_SELECT_STABLE\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13AD_SELECT_BANDWIDTH\\x10\\x01\\x12\\x13\\n\" +\n\t\"\\x0fAD_SELECT_COUNT\\x10\\x02*K\\n\" +\n\t\"\\x17NethelpersARPAllTargets\\x12\\x17\\n\" +\n\t\"\\x13ARP_ALL_TARGETS_ANY\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13ARP_ALL_TARGETS_ALL\\x10\\x01*\\xcf\\x01\\n\" +\n\t\"\\x15NethelpersARPValidate\\x12\\x15\\n\" +\n\t\"\\x11ARP_VALIDATE_NONE\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13ARP_VALIDATE_ACTIVE\\x10\\x01\\x12\\x17\\n\" +\n\t\"\\x13ARP_VALIDATE_BACKUP\\x10\\x02\\x12\\x14\\n\" +\n\t\"\\x10ARP_VALIDATE_ALL\\x10\\x03\\x12\\x17\\n\" +\n\t\"\\x13ARP_VALIDATE_FILTER\\x10\\x04\\x12\\x1e\\n\" +\n\t\"\\x1aARP_VALIDATE_FILTER_ACTIVE\\x10\\x05\\x12\\x1e\\n\" +\n\t\"\\x1aARP_VALIDATE_FILTER_BACKUP\\x10\\x06*t\\n\" +\n\t\"\\x1aNethelpersAutoHostnameKind\\x12\\x1a\\n\" +\n\t\"\\x16AUTO_HOSTNAME_KIND_OFF\\x10\\x00\\x12\\x1b\\n\" +\n\t\"\\x17AUTO_HOSTNAME_KIND_ADDR\\x10\\x01\\x12\\x1d\\n\" +\n\t\"\\x19AUTO_HOSTNAME_KIND_STABLE\\x10\\x02*\\xb3\\x01\\n\" +\n\t\"\\x12NethelpersBondMode\\x12\\x18\\n\" +\n\t\"\\x14BOND_MODE_ROUNDROBIN\\x10\\x00\\x12\\x1b\\n\" +\n\t\"\\x17BOND_MODE_ACTIVE_BACKUP\\x10\\x01\\x12\\x11\\n\" +\n\t\"\\rBOND_MODE_XOR\\x10\\x02\\x12\\x17\\n\" +\n\t\"\\x13BOND_MODE_BROADCAST\\x10\\x03\\x12\\x14\\n\" +\n\t\"\\x10BOND_MODE8023_AD\\x10\\x04\\x12\\x11\\n\" +\n\t\"\\rBOND_MODE_TLB\\x10\\x05\\x12\\x11\\n\" +\n\t\"\\rBOND_MODE_ALB\\x10\\x06*\\xb3\\x01\\n\" +\n\t\"\\x1cNethelpersBondXmitHashPolicy\\x12\\x1b\\n\" +\n\t\"\\x17BOND_XMIT_POLICY_LAYER2\\x10\\x00\\x12\\x1c\\n\" +\n\t\"\\x18BOND_XMIT_POLICY_LAYER34\\x10\\x01\\x12\\x1c\\n\" +\n\t\"\\x18BOND_XMIT_POLICY_LAYER23\\x10\\x02\\x12\\x1c\\n\" +\n\t\"\\x18BOND_XMIT_POLICY_ENCAP23\\x10\\x03\\x12\\x1c\\n\" +\n\t\"\\x18BOND_XMIT_POLICY_ENCAP34\\x10\\x04*o\\n\" +\n\t\"\\x1aNethelpersClientIdentifier\\x12\\x1a\\n\" +\n\t\"\\x16CLIENT_IDENTIFIER_NONE\\x10\\x00\\x12\\x19\\n\" +\n\t\"\\x15CLIENT_IDENTIFIER_MAC\\x10\\x01\\x12\\x1a\\n\" +\n\t\"\\x16CLIENT_IDENTIFIER_DUID\\x10\\x02*\\xb9\\x01\\n\" +\n\t\"\\x18NethelpersConntrackState\\x12)\\n\" +\n\t\"%NETHELPERS_CONNTRACKSTATE_UNSPECIFIED\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13CONNTRACK_STATE_NEW\\x10\\b\\x12\\x1b\\n\" +\n\t\"\\x17CONNTRACK_STATE_RELATED\\x10\\x04\\x12\\x1f\\n\" +\n\t\"\\x1bCONNTRACK_STATE_ESTABLISHED\\x10\\x02\\x12\\x1b\\n\" +\n\t\"\\x17CONNTRACK_STATE_INVALID\\x10\\x01*4\\n\" +\n\t\"\\x10NethelpersDuplex\\x12\\b\\n\" +\n\t\"\\x04HALF\\x10\\x00\\x12\\b\\n\" +\n\t\"\\x04FULL\\x10\\x01\\x12\\f\\n\" +\n\t\"\\aUNKNOWN\\x10\\xff\\x01*c\\n\" +\n\t\"\\x15NethelpersFailOverMAC\\x12\\x16\\n\" +\n\t\"\\x12FAIL_OVER_MAC_NONE\\x10\\x00\\x12\\x18\\n\" +\n\t\"\\x14FAIL_OVER_MAC_ACTIVE\\x10\\x01\\x12\\x18\\n\" +\n\t\"\\x14FAIL_OVER_MAC_FOLLOW\\x10\\x02*Y\\n\" +\n\t\"\\x10NethelpersFamily\\x12!\\n\" +\n\t\"\\x1dNETHELPERS_FAMILY_UNSPECIFIED\\x10\\x00\\x12\\x10\\n\" +\n\t\"\\fFAMILY_INET4\\x10\\x02\\x12\\x10\\n\" +\n\t\"\\fFAMILY_INET6\\x10\\n\" +\n\t\"*\\xbf\\x01\\n\" +\n\t\"\\x12NethelpersICMPType\\x12#\\n\" +\n\t\"\\x1fNETHELPERS_ICMPTYPE_UNSPECIFIED\\x10\\x00\\x12\\x1f\\n\" +\n\t\"\\x1bICMP_TYPE_TIMESTAMP_REQUEST\\x10\\r\\x12\\x1d\\n\" +\n\t\"\\x19ICMP_TYPE_TIMESTAMP_REPLY\\x10\\x0e\\x12\\\"\\n\" +\n\t\"\\x1eICMP_TYPE_ADDRESS_MASK_REQUEST\\x10\\x11\\x12 \\n\" +\n\t\"\\x1cICMP_TYPE_ADDRESS_MASK_REPLY\\x10\\x12*<\\n\" +\n\t\"\\x12NethelpersLACPRate\\x12\\x12\\n\" +\n\t\"\\x0eLACP_RATE_SLOW\\x10\\x00\\x12\\x12\\n\" +\n\t\"\\x0eLACP_RATE_FAST\\x10\\x01*\\x93\\v\\n\" +\n\t\"\\x12NethelpersLinkType\\x12\\x0f\\n\" +\n\t\"\\vLINK_NETROM\\x10\\x00\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"LINK_ETHER\\x10\\x01\\x12\\x0f\\n\" +\n\t\"\\vLINK_EETHER\\x10\\x02\\x12\\r\\n\" +\n\t\"\\tLINK_AX25\\x10\\x03\\x12\\x0f\\n\" +\n\t\"\\vLINK_PRONET\\x10\\x04\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"LINK_CHAOS\\x10\\x05\\x12\\x0f\\n\" +\n\t\"\\vLINK_IEE802\\x10\\x06\\x12\\x0f\\n\" +\n\t\"\\vLINK_ARCNET\\x10\\a\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"LINK_ATALK\\x10\\b\\x12\\r\\n\" +\n\t\"\\tLINK_DLCI\\x10\\x0f\\x12\\f\\n\" +\n\t\"\\bLINK_ATM\\x10\\x13\\x12\\x11\\n\" +\n\t\"\\rLINK_METRICOM\\x10\\x17\\x12\\x11\\n\" +\n\t\"\\rLINK_IEEE1394\\x10\\x18\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"LINK_EUI64\\x10\\x1b\\x12\\x13\\n\" +\n\t\"\\x0fLINK_INFINIBAND\\x10 \\x12\\x0e\\n\" +\n\t\"\\tLINK_SLIP\\x10\\x80\\x02\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_CSLIP\\x10\\x81\\x02\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_SLIP6\\x10\\x82\\x02\\x12\\x10\\n\" +\n\t\"\\vLINK_CSLIP6\\x10\\x83\\x02\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_RSRVD\\x10\\x84\\x02\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_ADAPT\\x10\\x88\\x02\\x12\\x0e\\n\" +\n\t\"\\tLINK_ROSE\\x10\\x8e\\x02\\x12\\r\\n\" +\n\t\"\\bLINK_X25\\x10\\x8f\\x02\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_HWX25\\x10\\x90\\x02\\x12\\r\\n\" +\n\t\"\\bLINK_CAN\\x10\\x98\\x02\\x12\\r\\n\" +\n\t\"\\bLINK_PPP\\x10\\x80\\x04\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_CISCO\\x10\\x81\\x04\\x12\\x0e\\n\" +\n\t\"\\tLINK_HDLC\\x10\\x81\\x04\\x12\\x0e\\n\" +\n\t\"\\tLINK_LAPB\\x10\\x84\\x04\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_DDCMP\\x10\\x85\\x04\\x12\\x11\\n\" +\n\t\"\\fLINK_RAWHDLC\\x10\\x86\\x04\\x12\\x10\\n\" +\n\t\"\\vLINK_TUNNEL\\x10\\x80\\x06\\x12\\x11\\n\" +\n\t\"\\fLINK_TUNNEL6\\x10\\x81\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_FRAD\\x10\\x82\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_SKIP\\x10\\x83\\x06\\x12\\x11\\n\" +\n\t\"\\fLINK_LOOPBCK\\x10\\x84\\x06\\x12\\x12\\n\" +\n\t\"\\rLINK_LOCALTLK\\x10\\x85\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_FDDI\\x10\\x86\\x06\\x12\\r\\n\" +\n\t\"\\bLINK_BIF\\x10\\x87\\x06\\x12\\r\\n\" +\n\t\"\\bLINK_SIT\\x10\\x88\\x06\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_IPDDP\\x10\\x89\\x06\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_IPGRE\\x10\\x8a\\x06\\x12\\x10\\n\" +\n\t\"\\vLINK_PIMREG\\x10\\x8b\\x06\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"LINK_HIPPI\\x10\\x8c\\x06\\x12\\r\\n\" +\n\t\"\\bLINK_ASH\\x10\\x8d\\x06\\x12\\x10\\n\" +\n\t\"\\vLINK_ECONET\\x10\\x8e\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_IRDA\\x10\\x8f\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_FCPP\\x10\\x90\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_FCAL\\x10\\x91\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_FCPL\\x10\\x92\\x06\\x12\\x12\\n\" +\n\t\"\\rLINK_FCFABRIC\\x10\\x93\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC1\\x10\\x94\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC2\\x10\\x95\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC3\\x10\\x96\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC4\\x10\\x97\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC5\\x10\\x98\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC6\\x10\\x99\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC7\\x10\\x9a\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC8\\x10\\x9b\\x06\\x12\\x13\\n\" +\n\t\"\\x0eLINK_FCFABRIC9\\x10\\x9c\\x06\\x12\\x14\\n\" +\n\t\"\\x0fLINK_FCFABRIC10\\x10\\x9d\\x06\\x12\\x14\\n\" +\n\t\"\\x0fLINK_FCFABRIC11\\x10\\x9e\\x06\\x12\\x14\\n\" +\n\t\"\\x0fLINK_FCFABRIC12\\x10\\x9f\\x06\\x12\\x12\\n\" +\n\t\"\\rLINK_IEE802TR\\x10\\xa0\\x06\\x12\\x12\\n\" +\n\t\"\\rLINK_IEE80211\\x10\\xa1\\x06\\x12\\x17\\n\" +\n\t\"\\x12LINK_IEE80211PRISM\\x10\\xa2\\x06\\x12\\x1b\\n\" +\n\t\"\\x16LINK_IEE80211_RADIOTAP\\x10\\xa3\\x06\\x12\\x14\\n\" +\n\t\"\\x0fLINK_IEE8021154\\x10\\xa4\\x06\\x12\\x1b\\n\" +\n\t\"\\x16LINK_IEE8021154MONITOR\\x10\\xa5\\x06\\x12\\x10\\n\" +\n\t\"\\vLINK_PHONET\\x10\\xb4\\x06\\x12\\x14\\n\" +\n\t\"\\x0fLINK_PHONETPIPE\\x10\\xb5\\x06\\x12\\x0e\\n\" +\n\t\"\\tLINK_CAIF\\x10\\xb6\\x06\\x12\\x10\\n\" +\n\t\"\\vLINK_IP6GRE\\x10\\xb7\\x06\\x12\\x11\\n\" +\n\t\"\\fLINK_NETLINK\\x10\\xb8\\x06\\x12\\x11\\n\" +\n\t\"\\fLINK6_LOWPAN\\x10\\xb9\\x06\\x12\\x0f\\n\" +\n\t\"\\tLINK_VOID\\x10\\xff\\xff\\x03\\x12\\x0f\\n\" +\n\t\"\\tLINK_NONE\\x10\\xfe\\xff\\x03\\x1a\\x02\\x10\\x01*E\\n\" +\n\t\"\\x17NethelpersMatchOperator\\x12\\x12\\n\" +\n\t\"\\x0eOPERATOR_EQUAL\\x10\\x00\\x12\\x16\\n\" +\n\t\"\\x12OPERATOR_NOT_EQUAL\\x10\\x01*\\x99\\x01\\n\" +\n\t\"\\x1bNethelpersNfTablesChainHook\\x12\\x19\\n\" +\n\t\"\\x15CHAIN_HOOK_PREROUTING\\x10\\x00\\x12\\x14\\n\" +\n\t\"\\x10CHAIN_HOOK_INPUT\\x10\\x01\\x12\\x16\\n\" +\n\t\"\\x12CHAIN_HOOK_FORWARD\\x10\\x02\\x12\\x15\\n\" +\n\t\"\\x11CHAIN_HOOK_OUTPUT\\x10\\x03\\x12\\x1a\\n\" +\n\t\"\\x16CHAIN_HOOK_POSTROUTING\\x10\\x04*\\xa3\\x04\\n\" +\n\t\"\\x1fNethelpersNfTablesChainPriority\\x120\\n\" +\n\t\",NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED\\x10\\x00\\x12!\\n\" +\n\t\"\\x14CHAIN_PRIORITY_FIRST\\x10\\x80\\x80\\x80\\x80\\xf8\\xff\\xff\\xff\\xff\\x01\\x12,\\n\" +\n\t\"\\x1fCHAIN_PRIORITY_CONNTRACK_DEFRAG\\x10\\xf0\\xfc\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12\\x1f\\n\" +\n\t\"\\x12CHAIN_PRIORITY_RAW\\x10\\xd4\\xfd\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12*\\n\" +\n\t\"\\x1dCHAIN_PRIORITY_SE_LINUX_FIRST\\x10\\x9f\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12%\\n\" +\n\t\"\\x18CHAIN_PRIORITY_CONNTRACK\\x10\\xb8\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12\\\"\\n\" +\n\t\"\\x15CHAIN_PRIORITY_MANGLE\\x10\\xea\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12$\\n\" +\n\t\"\\x17CHAIN_PRIORITY_NAT_DEST\\x10\\x9c\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x01\\x12\\x19\\n\" +\n\t\"\\x15CHAIN_PRIORITY_FILTER\\x10\\x00\\x12\\x1b\\n\" +\n\t\"\\x17CHAIN_PRIORITY_SECURITY\\x102\\x12\\x1d\\n\" +\n\t\"\\x19CHAIN_PRIORITY_NAT_SOURCE\\x10d\\x12!\\n\" +\n\t\"\\x1cCHAIN_PRIORITY_SE_LINUX_LAST\\x10\\xe1\\x01\\x12$\\n\" +\n\t\"\\x1fCHAIN_PRIORITY_CONNTRACK_HELPER\\x10\\xac\\x02\\x12\\x1b\\n\" +\n\t\"\\x13CHAIN_PRIORITY_LAST\\x10\\xff\\xff\\xff\\xff\\a\\x1a\\x02\\x10\\x01*A\\n\" +\n\t\"\\x19NethelpersNfTablesVerdict\\x12\\x10\\n\" +\n\t\"\\fVERDICT_DROP\\x10\\x00\\x12\\x12\\n\" +\n\t\"\\x0eVERDICT_ACCEPT\\x10\\x01*\\xc9\\x01\\n\" +\n\t\"\\x1aNethelpersOperationalState\\x12\\x16\\n\" +\n\t\"\\x12OPER_STATE_UNKNOWN\\x10\\x00\\x12\\x1a\\n\" +\n\t\"\\x16OPER_STATE_NOT_PRESENT\\x10\\x01\\x12\\x13\\n\" +\n\t\"\\x0fOPER_STATE_DOWN\\x10\\x02\\x12\\x1f\\n\" +\n\t\"\\x1bOPER_STATE_LOWER_LAYER_DOWN\\x10\\x03\\x12\\x16\\n\" +\n\t\"\\x12OPER_STATE_TESTING\\x10\\x04\\x12\\x16\\n\" +\n\t\"\\x12OPER_STATE_DORMANT\\x10\\x05\\x12\\x11\\n\" +\n\t\"\\rOPER_STATE_UP\\x10\\x06*r\\n\" +\n\t\"\\x0eNethelpersPort\\x12\\x10\\n\" +\n\t\"\\fTWISTED_PAIR\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03AUI\\x10\\x01\\x12\\a\\n\" +\n\t\"\\x03MII\\x10\\x02\\x12\\t\\n\" +\n\t\"\\x05FIBRE\\x10\\x03\\x12\\a\\n\" +\n\t\"\\x03BNC\\x10\\x04\\x12\\x11\\n\" +\n\t\"\\rDIRECT_ATTACH\\x10\\x05\\x12\\t\\n\" +\n\t\"\\x04NONE\\x10\\xef\\x01\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x05OTHER\\x10\\xff\\x01*s\\n\" +\n\t\"\\x19NethelpersPrimaryReselect\\x12\\x1b\\n\" +\n\t\"\\x17PRIMARY_RESELECT_ALWAYS\\x10\\x00\\x12\\x1b\\n\" +\n\t\"\\x17PRIMARY_RESELECT_BETTER\\x10\\x01\\x12\\x1c\\n\" +\n\t\"\\x18PRIMARY_RESELECT_FAILURE\\x10\\x02*\\x86\\x01\\n\" +\n\t\"\\x12NethelpersProtocol\\x12#\\n\" +\n\t\"\\x1fNETHELPERS_PROTOCOL_UNSPECIFIED\\x10\\x00\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_ICMP\\x10\\x01\\x12\\x10\\n\" +\n\t\"\\fPROTOCOL_TCP\\x10\\x06\\x12\\x10\\n\" +\n\t\"\\fPROTOCOL_UDP\\x10\\x11\\x12\\x14\\n\" +\n\t\"\\x10PROTOCOL_ICM_PV6\\x10:*\\xdf\\x01\\n\" +\n\t\"\\x13NethelpersRouteFlag\\x12$\\n\" +\n\t\" NETHELPERS_ROUTEFLAG_UNSPECIFIED\\x10\\x00\\x12\\x11\\n\" +\n\t\"\\fROUTE_NOTIFY\\x10\\x80\\x02\\x12\\x11\\n\" +\n\t\"\\fROUTE_CLONED\\x10\\x80\\x04\\x12\\x13\\n\" +\n\t\"\\x0eROUTE_EQUALIZE\\x10\\x80\\b\\x12\\x11\\n\" +\n\t\"\\fROUTE_PREFIX\\x10\\x80\\x10\\x12\\x17\\n\" +\n\t\"\\x12ROUTE_LOOKUP_TABLE\\x10\\x80 \\x12\\x14\\n\" +\n\t\"\\x0fROUTE_FIB_MATCH\\x10\\x80@\\x12\\x13\\n\" +\n\t\"\\rROUTE_OFFLOAD\\x10\\x80\\x80\\x01\\x12\\x10\\n\" +\n\t\"\\n\" +\n\t\"ROUTE_TRAP\\x10\\x80\\x80\\x02*\\xd2\\x03\\n\" +\n\t\"\\x17NethelpersRouteProtocol\\x12\\x13\\n\" +\n\t\"\\x0fPROTOCOL_UNSPEC\\x10\\x00\\x12\\x15\\n\" +\n\t\"\\x11PROTOCOL_REDIRECT\\x10\\x01\\x12\\x13\\n\" +\n\t\"\\x0fPROTOCOL_KERNEL\\x10\\x02\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_BOOT\\x10\\x03\\x12\\x13\\n\" +\n\t\"\\x0fPROTOCOL_STATIC\\x10\\x04\\x12\\x0f\\n\" +\n\t\"\\vPROTOCOL_RA\\x10\\t\\x12\\x10\\n\" +\n\t\"\\fPROTOCOL_MRT\\x10\\n\" +\n\t\"\\x12\\x12\\n\" +\n\t\"\\x0ePROTOCOL_ZEBRA\\x10\\v\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_BIRD\\x10\\f\\x12\\x15\\n\" +\n\t\"\\x11PROTOCOL_DNROUTED\\x10\\r\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_XORP\\x10\\x0e\\x12\\x10\\n\" +\n\t\"\\fPROTOCOL_NTK\\x10\\x0f\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_DHCP\\x10\\x10\\x12\\x11\\n\" +\n\t\"\\rPROTOCOL_MRTD\\x10\\x11\\x12\\x17\\n\" +\n\t\"\\x13PROTOCOL_KEEPALIVED\\x10\\x12\\x12\\x12\\n\" +\n\t\"\\x0ePROTOCOL_BABEL\\x10*\\x12\\x12\\n\" +\n\t\"\\x0ePROTOCOL_OPENR\\x10c\\x12\\x11\\n\" +\n\t\"\\fPROTOCOL_BGP\\x10\\xba\\x01\\x12\\x12\\n\" +\n\t\"\\rPROTOCOL_ISIS\\x10\\xbb\\x01\\x12\\x12\\n\" +\n\t\"\\rPROTOCOL_OSPF\\x10\\xbc\\x01\\x12\\x11\\n\" +\n\t\"\\fPROTOCOL_RIP\\x10\\xbd\\x01\\x12\\x13\\n\" +\n\t\"\\x0ePROTOCOL_EIGRP\\x10\\xc0\\x01*\\xf1\\x01\\n\" +\n\t\"\\x13NethelpersRouteType\\x12\\x0f\\n\" +\n\t\"\\vTYPE_UNSPEC\\x10\\x00\\x12\\x10\\n\" +\n\t\"\\fTYPE_UNICAST\\x10\\x01\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"TYPE_LOCAL\\x10\\x02\\x12\\x12\\n\" +\n\t\"\\x0eTYPE_BROADCAST\\x10\\x03\\x12\\x10\\n\" +\n\t\"\\fTYPE_ANYCAST\\x10\\x04\\x12\\x12\\n\" +\n\t\"\\x0eTYPE_MULTICAST\\x10\\x05\\x12\\x12\\n\" +\n\t\"\\x0eTYPE_BLACKHOLE\\x10\\x06\\x12\\x14\\n\" +\n\t\"\\x10TYPE_UNREACHABLE\\x10\\a\\x12\\x11\\n\" +\n\t\"\\rTYPE_PROHIBIT\\x10\\b\\x12\\x0e\\n\" +\n\t\"\\n\" +\n\t\"TYPE_THROW\\x10\\t\\x12\\f\\n\" +\n\t\"\\bTYPE_NAT\\x10\\n\" +\n\t\"\\x12\\x12\\n\" +\n\t\"\\x0eTYPE_X_RESOLVE\\x10\\v*\\xc8\\x01\\n\" +\n\t\"\\x1bNethelpersRoutingRuleAction\\x12\\x1e\\n\" +\n\t\"\\x1aROUTING_RULE_ACTION_UNSPEC\\x10\\x00\\x12\\x1f\\n\" +\n\t\"\\x1bROUTING_RULE_ACTION_UNICAST\\x10\\x01\\x12!\\n\" +\n\t\"\\x1dROUTING_RULE_ACTION_BLACKHOLE\\x10\\x06\\x12#\\n\" +\n\t\"\\x1fROUTING_RULE_ACTION_UNREACHABLE\\x10\\a\\x12 \\n\" +\n\t\"\\x1cROUTING_RULE_ACTION_PROHIBIT\\x10\\b*\\xba\\x1c\\n\" +\n\t\"\\x16NethelpersRoutingTable\\x12\\x10\\n\" +\n\t\"\\fTABLE_UNSPEC\\x10\\x00\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE1\\x10\\x01\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE2\\x10\\x02\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE3\\x10\\x03\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE4\\x10\\x04\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE5\\x10\\x05\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE6\\x10\\x06\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE7\\x10\\a\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE8\\x10\\b\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06TABLE9\\x10\\t\\x12\\v\\n\" +\n\t\"\\aTABLE10\\x10\\n\" +\n\t\"\\x12\\v\\n\" +\n\t\"\\aTABLE11\\x10\\v\\x12\\v\\n\" +\n\t\"\\aTABLE12\\x10\\f\\x12\\v\\n\" +\n\t\"\\aTABLE13\\x10\\r\\x12\\v\\n\" +\n\t\"\\aTABLE14\\x10\\x0e\\x12\\v\\n\" +\n\t\"\\aTABLE15\\x10\\x0f\\x12\\v\\n\" +\n\t\"\\aTABLE16\\x10\\x10\\x12\\v\\n\" +\n\t\"\\aTABLE17\\x10\\x11\\x12\\v\\n\" +\n\t\"\\aTABLE18\\x10\\x12\\x12\\v\\n\" +\n\t\"\\aTABLE19\\x10\\x13\\x12\\v\\n\" +\n\t\"\\aTABLE20\\x10\\x14\\x12\\v\\n\" +\n\t\"\\aTABLE21\\x10\\x15\\x12\\v\\n\" +\n\t\"\\aTABLE22\\x10\\x16\\x12\\v\\n\" +\n\t\"\\aTABLE23\\x10\\x17\\x12\\v\\n\" +\n\t\"\\aTABLE24\\x10\\x18\\x12\\v\\n\" +\n\t\"\\aTABLE25\\x10\\x19\\x12\\v\\n\" +\n\t\"\\aTABLE26\\x10\\x1a\\x12\\v\\n\" +\n\t\"\\aTABLE27\\x10\\x1b\\x12\\v\\n\" +\n\t\"\\aTABLE28\\x10\\x1c\\x12\\v\\n\" +\n\t\"\\aTABLE29\\x10\\x1d\\x12\\v\\n\" +\n\t\"\\aTABLE30\\x10\\x1e\\x12\\v\\n\" +\n\t\"\\aTABLE31\\x10\\x1f\\x12\\v\\n\" +\n\t\"\\aTABLE32\\x10 \\x12\\v\\n\" +\n\t\"\\aTABLE33\\x10!\\x12\\v\\n\" +\n\t\"\\aTABLE34\\x10\\\"\\x12\\v\\n\" +\n\t\"\\aTABLE35\\x10#\\x12\\v\\n\" +\n\t\"\\aTABLE36\\x10$\\x12\\v\\n\" +\n\t\"\\aTABLE37\\x10%\\x12\\v\\n\" +\n\t\"\\aTABLE38\\x10&\\x12\\v\\n\" +\n\t\"\\aTABLE39\\x10'\\x12\\v\\n\" +\n\t\"\\aTABLE40\\x10(\\x12\\v\\n\" +\n\t\"\\aTABLE41\\x10)\\x12\\v\\n\" +\n\t\"\\aTABLE42\\x10*\\x12\\v\\n\" +\n\t\"\\aTABLE43\\x10+\\x12\\v\\n\" +\n\t\"\\aTABLE44\\x10,\\x12\\v\\n\" +\n\t\"\\aTABLE45\\x10-\\x12\\v\\n\" +\n\t\"\\aTABLE46\\x10.\\x12\\v\\n\" +\n\t\"\\aTABLE47\\x10/\\x12\\v\\n\" +\n\t\"\\aTABLE48\\x100\\x12\\v\\n\" +\n\t\"\\aTABLE49\\x101\\x12\\v\\n\" +\n\t\"\\aTABLE50\\x102\\x12\\v\\n\" +\n\t\"\\aTABLE51\\x103\\x12\\v\\n\" +\n\t\"\\aTABLE52\\x104\\x12\\v\\n\" +\n\t\"\\aTABLE53\\x105\\x12\\v\\n\" +\n\t\"\\aTABLE54\\x106\\x12\\v\\n\" +\n\t\"\\aTABLE55\\x107\\x12\\v\\n\" +\n\t\"\\aTABLE56\\x108\\x12\\v\\n\" +\n\t\"\\aTABLE57\\x109\\x12\\v\\n\" +\n\t\"\\aTABLE58\\x10:\\x12\\v\\n\" +\n\t\"\\aTABLE59\\x10;\\x12\\v\\n\" +\n\t\"\\aTABLE60\\x10<\\x12\\v\\n\" +\n\t\"\\aTABLE61\\x10=\\x12\\v\\n\" +\n\t\"\\aTABLE62\\x10>\\x12\\v\\n\" +\n\t\"\\aTABLE63\\x10?\\x12\\v\\n\" +\n\t\"\\aTABLE64\\x10@\\x12\\v\\n\" +\n\t\"\\aTABLE65\\x10A\\x12\\v\\n\" +\n\t\"\\aTABLE66\\x10B\\x12\\v\\n\" +\n\t\"\\aTABLE67\\x10C\\x12\\v\\n\" +\n\t\"\\aTABLE68\\x10D\\x12\\v\\n\" +\n\t\"\\aTABLE69\\x10E\\x12\\v\\n\" +\n\t\"\\aTABLE70\\x10F\\x12\\v\\n\" +\n\t\"\\aTABLE71\\x10G\\x12\\v\\n\" +\n\t\"\\aTABLE72\\x10H\\x12\\v\\n\" +\n\t\"\\aTABLE73\\x10I\\x12\\v\\n\" +\n\t\"\\aTABLE74\\x10J\\x12\\v\\n\" +\n\t\"\\aTABLE75\\x10K\\x12\\v\\n\" +\n\t\"\\aTABLE76\\x10L\\x12\\v\\n\" +\n\t\"\\aTABLE77\\x10M\\x12\\v\\n\" +\n\t\"\\aTABLE78\\x10N\\x12\\v\\n\" +\n\t\"\\aTABLE79\\x10O\\x12\\v\\n\" +\n\t\"\\aTABLE80\\x10P\\x12\\v\\n\" +\n\t\"\\aTABLE81\\x10Q\\x12\\v\\n\" +\n\t\"\\aTABLE82\\x10R\\x12\\v\\n\" +\n\t\"\\aTABLE83\\x10S\\x12\\v\\n\" +\n\t\"\\aTABLE84\\x10T\\x12\\v\\n\" +\n\t\"\\aTABLE85\\x10U\\x12\\v\\n\" +\n\t\"\\aTABLE86\\x10V\\x12\\v\\n\" +\n\t\"\\aTABLE87\\x10W\\x12\\v\\n\" +\n\t\"\\aTABLE88\\x10X\\x12\\v\\n\" +\n\t\"\\aTABLE89\\x10Y\\x12\\v\\n\" +\n\t\"\\aTABLE90\\x10Z\\x12\\v\\n\" +\n\t\"\\aTABLE91\\x10[\\x12\\v\\n\" +\n\t\"\\aTABLE92\\x10\\\\\\x12\\v\\n\" +\n\t\"\\aTABLE93\\x10]\\x12\\v\\n\" +\n\t\"\\aTABLE94\\x10^\\x12\\v\\n\" +\n\t\"\\aTABLE95\\x10_\\x12\\v\\n\" +\n\t\"\\aTABLE96\\x10`\\x12\\v\\n\" +\n\t\"\\aTABLE97\\x10a\\x12\\v\\n\" +\n\t\"\\aTABLE98\\x10b\\x12\\v\\n\" +\n\t\"\\aTABLE99\\x10c\\x12\\f\\n\" +\n\t\"\\bTABLE100\\x10d\\x12\\f\\n\" +\n\t\"\\bTABLE101\\x10e\\x12\\f\\n\" +\n\t\"\\bTABLE102\\x10f\\x12\\f\\n\" +\n\t\"\\bTABLE103\\x10g\\x12\\f\\n\" +\n\t\"\\bTABLE104\\x10h\\x12\\f\\n\" +\n\t\"\\bTABLE105\\x10i\\x12\\f\\n\" +\n\t\"\\bTABLE106\\x10j\\x12\\f\\n\" +\n\t\"\\bTABLE107\\x10k\\x12\\f\\n\" +\n\t\"\\bTABLE108\\x10l\\x12\\f\\n\" +\n\t\"\\bTABLE109\\x10m\\x12\\f\\n\" +\n\t\"\\bTABLE110\\x10n\\x12\\f\\n\" +\n\t\"\\bTABLE111\\x10o\\x12\\f\\n\" +\n\t\"\\bTABLE112\\x10p\\x12\\f\\n\" +\n\t\"\\bTABLE113\\x10q\\x12\\f\\n\" +\n\t\"\\bTABLE114\\x10r\\x12\\f\\n\" +\n\t\"\\bTABLE115\\x10s\\x12\\f\\n\" +\n\t\"\\bTABLE116\\x10t\\x12\\f\\n\" +\n\t\"\\bTABLE117\\x10u\\x12\\f\\n\" +\n\t\"\\bTABLE118\\x10v\\x12\\f\\n\" +\n\t\"\\bTABLE119\\x10w\\x12\\f\\n\" +\n\t\"\\bTABLE120\\x10x\\x12\\f\\n\" +\n\t\"\\bTABLE121\\x10y\\x12\\f\\n\" +\n\t\"\\bTABLE122\\x10z\\x12\\f\\n\" +\n\t\"\\bTABLE123\\x10{\\x12\\f\\n\" +\n\t\"\\bTABLE124\\x10|\\x12\\f\\n\" +\n\t\"\\bTABLE125\\x10}\\x12\\f\\n\" +\n\t\"\\bTABLE126\\x10~\\x12\\f\\n\" +\n\t\"\\bTABLE127\\x10\\x7f\\x12\\r\\n\" +\n\t\"\\bTABLE128\\x10\\x80\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE129\\x10\\x81\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE130\\x10\\x82\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE131\\x10\\x83\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE132\\x10\\x84\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE133\\x10\\x85\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE134\\x10\\x86\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE135\\x10\\x87\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE136\\x10\\x88\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE137\\x10\\x89\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE138\\x10\\x8a\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE139\\x10\\x8b\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE140\\x10\\x8c\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE141\\x10\\x8d\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE142\\x10\\x8e\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE143\\x10\\x8f\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE144\\x10\\x90\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE145\\x10\\x91\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE146\\x10\\x92\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE147\\x10\\x93\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE148\\x10\\x94\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE149\\x10\\x95\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE150\\x10\\x96\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE151\\x10\\x97\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE152\\x10\\x98\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE153\\x10\\x99\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE154\\x10\\x9a\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE155\\x10\\x9b\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE156\\x10\\x9c\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE157\\x10\\x9d\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE158\\x10\\x9e\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE159\\x10\\x9f\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE160\\x10\\xa0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE161\\x10\\xa1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE162\\x10\\xa2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE163\\x10\\xa3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE164\\x10\\xa4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE165\\x10\\xa5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE166\\x10\\xa6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE167\\x10\\xa7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE168\\x10\\xa8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE169\\x10\\xa9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE170\\x10\\xaa\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE171\\x10\\xab\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE172\\x10\\xac\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE173\\x10\\xad\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE174\\x10\\xae\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE175\\x10\\xaf\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE176\\x10\\xb0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE177\\x10\\xb1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE178\\x10\\xb2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE179\\x10\\xb3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE180\\x10\\xb4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE181\\x10\\xb5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE182\\x10\\xb6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE183\\x10\\xb7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE184\\x10\\xb8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE185\\x10\\xb9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE186\\x10\\xba\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE187\\x10\\xbb\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE188\\x10\\xbc\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE189\\x10\\xbd\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE190\\x10\\xbe\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE191\\x10\\xbf\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE192\\x10\\xc0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE193\\x10\\xc1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE194\\x10\\xc2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE195\\x10\\xc3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE196\\x10\\xc4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE197\\x10\\xc5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE198\\x10\\xc6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE199\\x10\\xc7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE200\\x10\\xc8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE201\\x10\\xc9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE202\\x10\\xca\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE203\\x10\\xcb\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE204\\x10\\xcc\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE205\\x10\\xcd\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE206\\x10\\xce\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE207\\x10\\xcf\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE208\\x10\\xd0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE209\\x10\\xd1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE210\\x10\\xd2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE211\\x10\\xd3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE212\\x10\\xd4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE213\\x10\\xd5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE214\\x10\\xd6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE215\\x10\\xd7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE216\\x10\\xd8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE217\\x10\\xd9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE218\\x10\\xda\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE219\\x10\\xdb\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE220\\x10\\xdc\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE221\\x10\\xdd\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE222\\x10\\xde\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE223\\x10\\xdf\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE224\\x10\\xe0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE225\\x10\\xe1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE226\\x10\\xe2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE227\\x10\\xe3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE228\\x10\\xe4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE229\\x10\\xe5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE230\\x10\\xe6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE231\\x10\\xe7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE232\\x10\\xe8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE233\\x10\\xe9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE234\\x10\\xea\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE235\\x10\\xeb\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE236\\x10\\xec\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE237\\x10\\xed\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE238\\x10\\xee\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE239\\x10\\xef\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE240\\x10\\xf0\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE241\\x10\\xf1\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE242\\x10\\xf2\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE243\\x10\\xf3\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE244\\x10\\xf4\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE245\\x10\\xf5\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE246\\x10\\xf6\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE247\\x10\\xf7\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE248\\x10\\xf8\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE249\\x10\\xf9\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE250\\x10\\xfa\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE251\\x10\\xfb\\x01\\x12\\r\\n\" +\n\t\"\\bTABLE252\\x10\\xfc\\x01\\x12\\x12\\n\" +\n\t\"\\rTABLE_DEFAULT\\x10\\xfd\\x01\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"TABLE_MAIN\\x10\\xfe\\x01\\x12\\x10\\n\" +\n\t\"\\vTABLE_LOCAL\\x10\\xff\\x01*j\\n\" +\n\t\"\\x0fNethelpersScope\\x12\\x10\\n\" +\n\t\"\\fSCOPE_GLOBAL\\x10\\x00\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"SCOPE_SITE\\x10\\xc8\\x01\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"SCOPE_LINK\\x10\\xfd\\x01\\x12\\x0f\\n\" +\n\t\"\\n\" +\n\t\"SCOPE_HOST\\x10\\xfe\\x01\\x12\\x12\\n\" +\n\t\"\\rSCOPE_NOWHERE\\x10\\xff\\x01*x\\n\" +\n\t\"\\x16NethelpersVLANProtocol\\x12'\\n\" +\n\t\"#NETHELPERS_VLANPROTOCOL_UNSPECIFIED\\x10\\x00\\x12\\x19\\n\" +\n\t\"\\x13VLAN_PROTOCOL8021_Q\\x10\\x80\\x82\\x02\\x12\\x1a\\n\" +\n\t\"\\x14VLAN_PROTOCOL8021_AD\\x10\\xa8\\x91\\x02*\\xd4\\x01\\n\" +\n\t\"\\x11NethelpersWOLMode\\x12\\\"\\n\" +\n\t\"\\x1eNETHELPERS_WOLMODE_UNSPECIFIED\\x10\\x00\\x12\\x10\\n\" +\n\t\"\\fWOL_MODE_PHY\\x10\\x01\\x12\\x14\\n\" +\n\t\"\\x10WOL_MODE_UNICAST\\x10\\x02\\x12\\x16\\n\" +\n\t\"\\x12WOL_MODE_MULTICAST\\x10\\x04\\x12\\x16\\n\" +\n\t\"\\x12WOL_MODE_BROADCAST\\x10\\b\\x12\\x12\\n\" +\n\t\"\\x0eWOL_MODE_MAGIC\\x10 \\x12\\x19\\n\" +\n\t\"\\x15WOL_MODE_MAGIC_SECURE\\x10@\\x12\\x14\\n\" +\n\t\"\\x0fWOL_MODE_FILTER\\x10\\x80\\x01*\\x7f\\n\" +\n\t\"\\x16BlockEncryptionKeyType\\x12\\x19\\n\" +\n\t\"\\x15ENCRYPTION_KEY_STATIC\\x10\\x00\\x12\\x1a\\n\" +\n\t\"\\x16ENCRYPTION_KEY_NODE_ID\\x10\\x01\\x12\\x16\\n\" +\n\t\"\\x12ENCRYPTION_KEY_KMS\\x10\\x02\\x12\\x16\\n\" +\n\t\"\\x12ENCRYPTION_KEY_TPM\\x10\\x03*Z\\n\" +\n\t\"\\x1bBlockEncryptionProviderType\\x12\\x1c\\n\" +\n\t\"\\x18ENCRYPTION_PROVIDER_NONE\\x10\\x00\\x12\\x1d\\n\" +\n\t\"\\x19ENCRYPTION_PROVIDER_LUKS2\\x10\\x01*\\xd1\\x01\\n\" +\n\t\"\\x13BlockFilesystemType\\x12\\x18\\n\" +\n\t\"\\x14FILESYSTEM_TYPE_NONE\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13FILESYSTEM_TYPE_XFS\\x10\\x01\\x12\\x18\\n\" +\n\t\"\\x14FILESYSTEM_TYPE_VFAT\\x10\\x02\\x12\\x18\\n\" +\n\t\"\\x14FILESYSTEM_TYPE_EXT4\\x10\\x03\\x12\\x1b\\n\" +\n\t\"\\x17FILESYSTEM_TYPE_ISO9660\\x10\\x04\\x12\\x18\\n\" +\n\t\"\\x14FILESYSTEM_TYPE_SWAP\\x10\\x05\\x12\\x1c\\n\" +\n\t\"\\x18FILESYSTEM_TYPE_VIRTIOFS\\x10\\x06*\\x83\\x01\\n\" +\n\t\"\\x14BlockFSParameterType\\x12\\\"\\n\" +\n\t\"\\x1eFS_PARAMETER_TYPE_STRING_VALUE\\x10\\x00\\x12#\\n\" +\n\t\"\\x1fFS_PARAMETER_TYPE_BOOLEAN_VALUE\\x10\\x01\\x12\\\"\\n\" +\n\t\"\\x1eFS_PARAMETER_TYPE_BINARY_VALUE\\x10\\x02*\\xe3\\x01\\n\" +\n\t\"\\x10BlockVolumePhase\\x12\\x18\\n\" +\n\t\"\\x14VOLUME_PHASE_WAITING\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13VOLUME_PHASE_FAILED\\x10\\x01\\x12\\x18\\n\" +\n\t\"\\x14VOLUME_PHASE_MISSING\\x10\\x02\\x12\\x18\\n\" +\n\t\"\\x14VOLUME_PHASE_LOCATED\\x10\\x03\\x12\\x1c\\n\" +\n\t\"\\x18VOLUME_PHASE_PROVISIONED\\x10\\x04\\x12\\x19\\n\" +\n\t\"\\x15VOLUME_PHASE_PREPARED\\x10\\x05\\x12\\x16\\n\" +\n\t\"\\x12VOLUME_PHASE_READY\\x10\\x06\\x12\\x17\\n\" +\n\t\"\\x13VOLUME_PHASE_CLOSED\\x10\\a*\\xc0\\x01\\n\" +\n\t\"\\x0fBlockVolumeType\\x12\\x19\\n\" +\n\t\"\\x15VOLUME_TYPE_PARTITION\\x10\\x00\\x12\\x14\\n\" +\n\t\"\\x10VOLUME_TYPE_DISK\\x10\\x01\\x12\\x15\\n\" +\n\t\"\\x11VOLUME_TYPE_TMPFS\\x10\\x02\\x12\\x19\\n\" +\n\t\"\\x15VOLUME_TYPE_DIRECTORY\\x10\\x03\\x12\\x17\\n\" +\n\t\"\\x13VOLUME_TYPE_SYMLINK\\x10\\x04\\x12\\x17\\n\" +\n\t\"\\x13VOLUME_TYPE_OVERLAY\\x10\\x05\\x12\\x18\\n\" +\n\t\"\\x14VOLUME_TYPE_EXTERNAL\\x10\\x06*\\x96\\x01\\n\" +\n\t\"\\x13CriImageCacheStatus\\x12\\x1e\\n\" +\n\t\"\\x1aIMAGE_CACHE_STATUS_UNKNOWN\\x10\\x00\\x12\\x1f\\n\" +\n\t\"\\x1bIMAGE_CACHE_STATUS_DISABLED\\x10\\x01\\x12 \\n\" +\n\t\"\\x1cIMAGE_CACHE_STATUS_PREPARING\\x10\\x02\\x12\\x1c\\n\" +\n\t\"\\x18IMAGE_CACHE_STATUS_READY\\x10\\x03*\\xab\\x01\\n\" +\n\t\"\\x17CriImageCacheCopyStatus\\x12#\\n\" +\n\t\"\\x1fIMAGE_CACHE_COPY_STATUS_UNKNOWN\\x10\\x00\\x12#\\n\" +\n\t\"\\x1fIMAGE_CACHE_COPY_STATUS_SKIPPED\\x10\\x01\\x12#\\n\" +\n\t\"\\x1fIMAGE_CACHE_COPY_STATUS_PENDING\\x10\\x02\\x12!\\n\" +\n\t\"\\x1dIMAGE_CACHE_COPY_STATUS_READY\\x10\\x03*S\\n\" +\n\t\"\\x11KubespanPeerState\\x12\\x16\\n\" +\n\t\"\\x12PEER_STATE_UNKNOWN\\x10\\x00\\x12\\x11\\n\" +\n\t\"\\rPEER_STATE_UP\\x10\\x01\\x12\\x13\\n\" +\n\t\"\\x0fPEER_STATE_DOWN\\x10\\x02*\\x88\\x01\\n\" +\n\t\"\\x12NetworkConfigLayer\\x12\\x12\\n\" +\n\t\"\\x0eCONFIG_DEFAULT\\x10\\x00\\x12\\x12\\n\" +\n\t\"\\x0eCONFIG_CMDLINE\\x10\\x01\\x12\\x13\\n\" +\n\t\"\\x0fCONFIG_PLATFORM\\x10\\x02\\x12\\x13\\n\" +\n\t\"\\x0fCONFIG_OPERATOR\\x10\\x03\\x12 \\n\" +\n\t\"\\x1cCONFIG_MACHINE_CONFIGURATION\\x10\\x04*K\\n\" +\n\t\"\\x0fNetworkOperator\\x12\\x12\\n\" +\n\t\"\\x0eOPERATOR_DHCP4\\x10\\x00\\x12\\x12\\n\" +\n\t\"\\x0eOPERATOR_DHCP6\\x10\\x01\\x12\\x10\\n\" +\n\t\"\\fOPERATOR_VIP\\x10\\x02Bt\\n\" +\n\t\"(dev.talos.api.resource.definitions.enumsZHgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enumsb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_enums_enums_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_enums_enums_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_enums_enums_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_enums_enums_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_enums_enums_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_enums_enums_proto_rawDesc), len(file_resource_definitions_enums_enums_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_enums_enums_proto_rawDescData\n}\n\nvar file_resource_definitions_enums_enums_proto_enumTypes = make([]protoimpl.EnumInfo, 48)\nvar file_resource_definitions_enums_enums_proto_goTypes = []any{\n\t(RuntimeMachineStage)(0),             // 0: talos.resource.definitions.enums.RuntimeMachineStage\n\t(RuntimeSELinuxState)(0),             // 1: talos.resource.definitions.enums.RuntimeSELinuxState\n\t(RuntimeFIPSState)(0),                // 2: talos.resource.definitions.enums.RuntimeFIPSState\n\t(MachineType)(0),                     // 3: talos.resource.definitions.enums.MachineType\n\t(NethelpersAddressFlag)(0),           // 4: talos.resource.definitions.enums.NethelpersAddressFlag\n\t(NethelpersAddressSortAlgorithm)(0),  // 5: talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\n\t(NethelpersADLACPActive)(0),          // 6: talos.resource.definitions.enums.NethelpersADLACPActive\n\t(NethelpersADSelect)(0),              // 7: talos.resource.definitions.enums.NethelpersADSelect\n\t(NethelpersARPAllTargets)(0),         // 8: talos.resource.definitions.enums.NethelpersARPAllTargets\n\t(NethelpersARPValidate)(0),           // 9: talos.resource.definitions.enums.NethelpersARPValidate\n\t(NethelpersAutoHostnameKind)(0),      // 10: talos.resource.definitions.enums.NethelpersAutoHostnameKind\n\t(NethelpersBondMode)(0),              // 11: talos.resource.definitions.enums.NethelpersBondMode\n\t(NethelpersBondXmitHashPolicy)(0),    // 12: talos.resource.definitions.enums.NethelpersBondXmitHashPolicy\n\t(NethelpersClientIdentifier)(0),      // 13: talos.resource.definitions.enums.NethelpersClientIdentifier\n\t(NethelpersConntrackState)(0),        // 14: talos.resource.definitions.enums.NethelpersConntrackState\n\t(NethelpersDuplex)(0),                // 15: talos.resource.definitions.enums.NethelpersDuplex\n\t(NethelpersFailOverMAC)(0),           // 16: talos.resource.definitions.enums.NethelpersFailOverMAC\n\t(NethelpersFamily)(0),                // 17: talos.resource.definitions.enums.NethelpersFamily\n\t(NethelpersICMPType)(0),              // 18: talos.resource.definitions.enums.NethelpersICMPType\n\t(NethelpersLACPRate)(0),              // 19: talos.resource.definitions.enums.NethelpersLACPRate\n\t(NethelpersLinkType)(0),              // 20: talos.resource.definitions.enums.NethelpersLinkType\n\t(NethelpersMatchOperator)(0),         // 21: talos.resource.definitions.enums.NethelpersMatchOperator\n\t(NethelpersNfTablesChainHook)(0),     // 22: talos.resource.definitions.enums.NethelpersNfTablesChainHook\n\t(NethelpersNfTablesChainPriority)(0), // 23: talos.resource.definitions.enums.NethelpersNfTablesChainPriority\n\t(NethelpersNfTablesVerdict)(0),       // 24: talos.resource.definitions.enums.NethelpersNfTablesVerdict\n\t(NethelpersOperationalState)(0),      // 25: talos.resource.definitions.enums.NethelpersOperationalState\n\t(NethelpersPort)(0),                  // 26: talos.resource.definitions.enums.NethelpersPort\n\t(NethelpersPrimaryReselect)(0),       // 27: talos.resource.definitions.enums.NethelpersPrimaryReselect\n\t(NethelpersProtocol)(0),              // 28: talos.resource.definitions.enums.NethelpersProtocol\n\t(NethelpersRouteFlag)(0),             // 29: talos.resource.definitions.enums.NethelpersRouteFlag\n\t(NethelpersRouteProtocol)(0),         // 30: talos.resource.definitions.enums.NethelpersRouteProtocol\n\t(NethelpersRouteType)(0),             // 31: talos.resource.definitions.enums.NethelpersRouteType\n\t(NethelpersRoutingRuleAction)(0),     // 32: talos.resource.definitions.enums.NethelpersRoutingRuleAction\n\t(NethelpersRoutingTable)(0),          // 33: talos.resource.definitions.enums.NethelpersRoutingTable\n\t(NethelpersScope)(0),                 // 34: talos.resource.definitions.enums.NethelpersScope\n\t(NethelpersVLANProtocol)(0),          // 35: talos.resource.definitions.enums.NethelpersVLANProtocol\n\t(NethelpersWOLMode)(0),               // 36: talos.resource.definitions.enums.NethelpersWOLMode\n\t(BlockEncryptionKeyType)(0),          // 37: talos.resource.definitions.enums.BlockEncryptionKeyType\n\t(BlockEncryptionProviderType)(0),     // 38: talos.resource.definitions.enums.BlockEncryptionProviderType\n\t(BlockFilesystemType)(0),             // 39: talos.resource.definitions.enums.BlockFilesystemType\n\t(BlockFSParameterType)(0),            // 40: talos.resource.definitions.enums.BlockFSParameterType\n\t(BlockVolumePhase)(0),                // 41: talos.resource.definitions.enums.BlockVolumePhase\n\t(BlockVolumeType)(0),                 // 42: talos.resource.definitions.enums.BlockVolumeType\n\t(CriImageCacheStatus)(0),             // 43: talos.resource.definitions.enums.CriImageCacheStatus\n\t(CriImageCacheCopyStatus)(0),         // 44: talos.resource.definitions.enums.CriImageCacheCopyStatus\n\t(KubespanPeerState)(0),               // 45: talos.resource.definitions.enums.KubespanPeerState\n\t(NetworkConfigLayer)(0),              // 46: talos.resource.definitions.enums.NetworkConfigLayer\n\t(NetworkOperator)(0),                 // 47: talos.resource.definitions.enums.NetworkOperator\n}\nvar file_resource_definitions_enums_enums_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_enums_enums_proto_init() }\nfunc file_resource_definitions_enums_enums_proto_init() {\n\tif File_resource_definitions_enums_enums_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_enums_enums_proto_rawDesc), len(file_resource_definitions_enums_enums_proto_rawDesc)),\n\t\t\tNumEnums:      48,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_enums_enums_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_enums_enums_proto_depIdxs,\n\t\tEnumInfos:         file_resource_definitions_enums_enums_proto_enumTypes,\n\t}.Build()\n\tFile_resource_definitions_enums_enums_proto = out.File\n\tfile_resource_definitions_enums_enums_proto_goTypes = nil\n\tfile_resource_definitions_enums_enums_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/etcd/etcd.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/etcd/etcd.proto\n\npackage etcd\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\ntype ArgValues struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tValues        []string               `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ArgValues) Reset() {\n\t*x = ArgValues{}\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ArgValues) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ArgValues) ProtoMessage() {}\n\nfunc (x *ArgValues) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ArgValues.ProtoReflect.Descriptor instead.\nfunc (*ArgValues) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ArgValues) GetValues() []string {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\n// ConfigSpec describes (some) configuration settings of etcd.\ntype ConfigSpec struct {\n\tstate                   protoimpl.MessageState `protogen:\"open.v1\"`\n\tAdvertiseValidSubnets   []string               `protobuf:\"bytes,1,rep,name=advertise_valid_subnets,json=advertiseValidSubnets,proto3\" json:\"advertise_valid_subnets,omitempty\"`\n\tAdvertiseExcludeSubnets []string               `protobuf:\"bytes,2,rep,name=advertise_exclude_subnets,json=advertiseExcludeSubnets,proto3\" json:\"advertise_exclude_subnets,omitempty\"`\n\tImage                   string                 `protobuf:\"bytes,3,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tExtraArgs               map[string]*ArgValues  `protobuf:\"bytes,4,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tListenValidSubnets      []string               `protobuf:\"bytes,5,rep,name=listen_valid_subnets,json=listenValidSubnets,proto3\" json:\"listen_valid_subnets,omitempty\"`\n\tListenExcludeSubnets    []string               `protobuf:\"bytes,6,rep,name=listen_exclude_subnets,json=listenExcludeSubnets,proto3\" json:\"listen_exclude_subnets,omitempty\"`\n\tunknownFields           protoimpl.UnknownFields\n\tsizeCache               protoimpl.SizeCache\n}\n\nfunc (x *ConfigSpec) Reset() {\n\t*x = ConfigSpec{}\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigSpec) ProtoMessage() {}\n\nfunc (x *ConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ConfigSpec) GetAdvertiseValidSubnets() []string {\n\tif x != nil {\n\t\treturn x.AdvertiseValidSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetAdvertiseExcludeSubnets() []string {\n\tif x != nil {\n\t\treturn x.AdvertiseExcludeSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetListenValidSubnets() []string {\n\tif x != nil {\n\t\treturn x.ListenValidSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetListenExcludeSubnets() []string {\n\tif x != nil {\n\t\treturn x.ListenExcludeSubnets\n\t}\n\treturn nil\n}\n\n// MemberSpec holds information about an etcd member.\ntype MemberSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMemberId      string                 `protobuf:\"bytes,1,opt,name=member_id,json=memberId,proto3\" json:\"member_id,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MemberSpec) Reset() {\n\t*x = MemberSpec{}\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemberSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemberSpec) ProtoMessage() {}\n\nfunc (x *MemberSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemberSpec.ProtoReflect.Descriptor instead.\nfunc (*MemberSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *MemberSpec) GetMemberId() string {\n\tif x != nil {\n\t\treturn x.MemberId\n\t}\n\treturn \"\"\n}\n\n// PKIStatusSpec describes status of rendered secrets.\ntype PKIStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady         bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PKIStatusSpec) Reset() {\n\t*x = PKIStatusSpec{}\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PKIStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PKIStatusSpec) ProtoMessage() {}\n\nfunc (x *PKIStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PKIStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*PKIStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *PKIStatusSpec) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *PKIStatusSpec) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\n// SpecSpec describes (some) Specuration settings of etcd.\ntype SpecSpec struct {\n\tstate                 protoimpl.MessageState `protogen:\"open.v1\"`\n\tName                  string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tAdvertisedAddresses   []*common.NetIP        `protobuf:\"bytes,2,rep,name=advertised_addresses,json=advertisedAddresses,proto3\" json:\"advertised_addresses,omitempty\"`\n\tImage                 string                 `protobuf:\"bytes,3,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tExtraArgs             map[string]*ArgValues  `protobuf:\"bytes,4,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tListenPeerAddresses   []*common.NetIP        `protobuf:\"bytes,5,rep,name=listen_peer_addresses,json=listenPeerAddresses,proto3\" json:\"listen_peer_addresses,omitempty\"`\n\tListenClientAddresses []*common.NetIP        `protobuf:\"bytes,6,rep,name=listen_client_addresses,json=listenClientAddresses,proto3\" json:\"listen_client_addresses,omitempty\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *SpecSpec) Reset() {\n\t*x = SpecSpec{}\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SpecSpec) ProtoMessage() {}\n\nfunc (x *SpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_etcd_etcd_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SpecSpec.ProtoReflect.Descriptor instead.\nfunc (*SpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *SpecSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *SpecSpec) GetAdvertisedAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.AdvertisedAddresses\n\t}\n\treturn nil\n}\n\nfunc (x *SpecSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *SpecSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *SpecSpec) GetListenPeerAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ListenPeerAddresses\n\t}\n\treturn nil\n}\n\nfunc (x *SpecSpec) GetListenClientAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ListenClientAddresses\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_etcd_etcd_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_etcd_etcd_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"$resource/definitions/etcd/etcd.proto\\x12\\x1ftalos.resource.definitions.etcd\\x1a\\x13common/common.proto\\\"#\\n\" +\n\t\"\\tArgValues\\x12\\x16\\n\" +\n\t\"\\x06values\\x18\\x01 \\x03(\\tR\\x06values\\\"\\xc3\\x03\\n\" +\n\t\"\\n\" +\n\t\"ConfigSpec\\x126\\n\" +\n\t\"\\x17advertise_valid_subnets\\x18\\x01 \\x03(\\tR\\x15advertiseValidSubnets\\x12:\\n\" +\n\t\"\\x19advertise_exclude_subnets\\x18\\x02 \\x03(\\tR\\x17advertiseExcludeSubnets\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x03 \\x01(\\tR\\x05image\\x12Y\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\x04 \\x03(\\v2:.talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntryR\\textraArgs\\x120\\n\" +\n\t\"\\x14listen_valid_subnets\\x18\\x05 \\x03(\\tR\\x12listenValidSubnets\\x124\\n\" +\n\t\"\\x16listen_exclude_subnets\\x18\\x06 \\x03(\\tR\\x14listenExcludeSubnets\\x1ah\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12@\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2*.talos.resource.definitions.etcd.ArgValuesR\\x05value:\\x028\\x01\\\")\\n\" +\n\t\"\\n\" +\n\t\"MemberSpec\\x12\\x1b\\n\" +\n\t\"\\tmember_id\\x18\\x01 \\x01(\\tR\\bmemberId\\\"?\\n\" +\n\t\"\\rPKIStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\tR\\aversion\\\"\\xc3\\x03\\n\" +\n\t\"\\bSpecSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12@\\n\" +\n\t\"\\x14advertised_addresses\\x18\\x02 \\x03(\\v2\\r.common.NetIPR\\x13advertisedAddresses\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x03 \\x01(\\tR\\x05image\\x12W\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\x04 \\x03(\\v28.talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntryR\\textraArgs\\x12A\\n\" +\n\t\"\\x15listen_peer_addresses\\x18\\x05 \\x03(\\v2\\r.common.NetIPR\\x13listenPeerAddresses\\x12E\\n\" +\n\t\"\\x17listen_client_addresses\\x18\\x06 \\x03(\\v2\\r.common.NetIPR\\x15listenClientAddresses\\x1ah\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12@\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2*.talos.resource.definitions.etcd.ArgValuesR\\x05value:\\x028\\x01Br\\n\" +\n\t\"'dev.talos.api.resource.definitions.etcdZGgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/etcdb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_etcd_etcd_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_etcd_etcd_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_etcd_etcd_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_etcd_etcd_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_etcd_etcd_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_etcd_etcd_proto_rawDesc), len(file_resource_definitions_etcd_etcd_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_etcd_etcd_proto_rawDescData\n}\n\nvar file_resource_definitions_etcd_etcd_proto_msgTypes = make([]protoimpl.MessageInfo, 7)\nvar file_resource_definitions_etcd_etcd_proto_goTypes = []any{\n\t(*ArgValues)(nil),     // 0: talos.resource.definitions.etcd.ArgValues\n\t(*ConfigSpec)(nil),    // 1: talos.resource.definitions.etcd.ConfigSpec\n\t(*MemberSpec)(nil),    // 2: talos.resource.definitions.etcd.MemberSpec\n\t(*PKIStatusSpec)(nil), // 3: talos.resource.definitions.etcd.PKIStatusSpec\n\t(*SpecSpec)(nil),      // 4: talos.resource.definitions.etcd.SpecSpec\n\tnil,                   // 5: talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry\n\tnil,                   // 6: talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry\n\t(*common.NetIP)(nil),  // 7: common.NetIP\n}\nvar file_resource_definitions_etcd_etcd_proto_depIdxs = []int32{\n\t5, // 0: talos.resource.definitions.etcd.ConfigSpec.extra_args:type_name -> talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry\n\t7, // 1: talos.resource.definitions.etcd.SpecSpec.advertised_addresses:type_name -> common.NetIP\n\t6, // 2: talos.resource.definitions.etcd.SpecSpec.extra_args:type_name -> talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry\n\t7, // 3: talos.resource.definitions.etcd.SpecSpec.listen_peer_addresses:type_name -> common.NetIP\n\t7, // 4: talos.resource.definitions.etcd.SpecSpec.listen_client_addresses:type_name -> common.NetIP\n\t0, // 5: talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.etcd.ArgValues\n\t0, // 6: talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.etcd.ArgValues\n\t7, // [7:7] is the sub-list for method output_type\n\t7, // [7:7] is the sub-list for method input_type\n\t7, // [7:7] is the sub-list for extension type_name\n\t7, // [7:7] is the sub-list for extension extendee\n\t0, // [0:7] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_etcd_etcd_proto_init() }\nfunc file_resource_definitions_etcd_etcd_proto_init() {\n\tif File_resource_definitions_etcd_etcd_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_etcd_etcd_proto_rawDesc), len(file_resource_definitions_etcd_etcd_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   7,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_etcd_etcd_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_etcd_etcd_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_etcd_etcd_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_etcd_etcd_proto = out.File\n\tfile_resource_definitions_etcd_etcd_proto_goTypes = nil\n\tfile_resource_definitions_etcd_etcd_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/etcd/etcd_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/etcd/etcd.proto\n\npackage etcd\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ArgValues) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ArgValues) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ArgValues) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Values) > 0 {\n\t\tfor iNdEx := len(m.Values) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Values[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Values[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Values[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ListenExcludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.ListenExcludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ListenExcludeSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ListenExcludeSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ListenExcludeSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.ListenValidSubnets) > 0 {\n\t\tfor iNdEx := len(m.ListenValidSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ListenValidSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ListenValidSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ListenValidSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.AdvertiseExcludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.AdvertiseExcludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.AdvertiseExcludeSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.AdvertiseExcludeSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AdvertiseExcludeSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.AdvertiseValidSubnets) > 0 {\n\t\tfor iNdEx := len(m.AdvertiseValidSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.AdvertiseValidSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.AdvertiseValidSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AdvertiseValidSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemberSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemberSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemberSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MemberId) > 0 {\n\t\ti -= len(m.MemberId)\n\t\tcopy(dAtA[i:], m.MemberId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MemberId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PKIStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PKIStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PKIStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ListenClientAddresses) > 0 {\n\t\tfor iNdEx := len(m.ListenClientAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ListenClientAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ListenClientAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.ListenPeerAddresses) > 0 {\n\t\tfor iNdEx := len(m.ListenPeerAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ListenPeerAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ListenPeerAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.AdvertisedAddresses) > 0 {\n\t\tfor iNdEx := len(m.AdvertisedAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AdvertisedAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AdvertisedAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ArgValues) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Values) > 0 {\n\t\tfor _, s := range m.Values {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.AdvertiseValidSubnets) > 0 {\n\t\tfor _, s := range m.AdvertiseValidSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.AdvertiseExcludeSubnets) > 0 {\n\t\tfor _, s := range m.AdvertiseExcludeSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ListenValidSubnets) > 0 {\n\t\tfor _, s := range m.ListenValidSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ListenExcludeSubnets) > 0 {\n\t\tfor _, s := range m.ListenExcludeSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemberSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.MemberId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PKIStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AdvertisedAddresses) > 0 {\n\t\tfor _, e := range m.AdvertisedAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ListenPeerAddresses) > 0 {\n\t\tfor _, e := range m.ListenPeerAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ListenClientAddresses) > 0 {\n\t\tfor _, e := range m.ListenClientAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ArgValues) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ArgValues: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ArgValues: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Values\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Values = append(m.Values, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdvertiseValidSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdvertiseValidSubnets = append(m.AdvertiseValidSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdvertiseExcludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdvertiseExcludeSubnets = append(m.AdvertiseExcludeSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenValidSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenValidSubnets = append(m.ListenValidSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenExcludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenExcludeSubnets = append(m.ListenExcludeSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MemberSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemberSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemberSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemberId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MemberId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PKIStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PKIStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PKIStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdvertisedAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdvertisedAddresses = append(m.AdvertisedAddresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.AdvertisedAddresses[len(m.AdvertisedAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AdvertisedAddresses[len(m.AdvertisedAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenPeerAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenPeerAddresses = append(m.ListenPeerAddresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ListenPeerAddresses[len(m.ListenPeerAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ListenPeerAddresses[len(m.ListenPeerAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenClientAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenClientAddresses = append(m.ListenClientAddresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ListenClientAddresses[len(m.ListenClientAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ListenClientAddresses[len(m.ListenClientAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/extensions/extensions.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/extensions/extensions.proto\n\npackage extensions\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// Compatibility describes extension compatibility.\ntype Compatibility struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tTalos         *Constraint            `protobuf:\"bytes,1,opt,name=talos,proto3\" json:\"talos,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Compatibility) Reset() {\n\t*x = Compatibility{}\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Compatibility) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Compatibility) ProtoMessage() {}\n\nfunc (x *Compatibility) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Compatibility.ProtoReflect.Descriptor instead.\nfunc (*Compatibility) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_extensions_extensions_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Compatibility) GetTalos() *Constraint {\n\tif x != nil {\n\t\treturn x.Talos\n\t}\n\treturn nil\n}\n\n// Constraint describes compatibility constraint.\ntype Constraint struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tVersion       string                 `protobuf:\"bytes,1,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Constraint) Reset() {\n\t*x = Constraint{}\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Constraint) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Constraint) ProtoMessage() {}\n\nfunc (x *Constraint) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Constraint.ProtoReflect.Descriptor instead.\nfunc (*Constraint) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_extensions_extensions_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Constraint) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\n// Layer defines overlay mount layer.\ntype Layer struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tImage         string                 `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tMetadata      *Metadata              `protobuf:\"bytes,2,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Layer) Reset() {\n\t*x = Layer{}\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Layer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Layer) ProtoMessage() {}\n\nfunc (x *Layer) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Layer.ProtoReflect.Descriptor instead.\nfunc (*Layer) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_extensions_extensions_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Layer) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *Layer) GetMetadata() *Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\n// Metadata describes base extension metadata.\ntype Metadata struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tAuthor        string                 `protobuf:\"bytes,3,opt,name=author,proto3\" json:\"author,omitempty\"`\n\tDescription   string                 `protobuf:\"bytes,4,opt,name=description,proto3\" json:\"description,omitempty\"`\n\tCompatibility *Compatibility         `protobuf:\"bytes,5,opt,name=compatibility,proto3\" json:\"compatibility,omitempty\"`\n\tExtraInfo     string                 `protobuf:\"bytes,6,opt,name=extra_info,json=extraInfo,proto3\" json:\"extra_info,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Metadata) Reset() {\n\t*x = Metadata{}\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Metadata) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Metadata) ProtoMessage() {}\n\nfunc (x *Metadata) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_extensions_extensions_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.\nfunc (*Metadata) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_extensions_extensions_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *Metadata) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetAuthor() string {\n\tif x != nil {\n\t\treturn x.Author\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetDescription() string {\n\tif x != nil {\n\t\treturn x.Description\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metadata) GetCompatibility() *Compatibility {\n\tif x != nil {\n\t\treturn x.Compatibility\n\t}\n\treturn nil\n}\n\nfunc (x *Metadata) GetExtraInfo() string {\n\tif x != nil {\n\t\treturn x.ExtraInfo\n\t}\n\treturn \"\"\n}\n\nvar File_resource_definitions_extensions_extensions_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_extensions_extensions_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"0resource/definitions/extensions/extensions.proto\\x12%talos.resource.definitions.extensions\\\"X\\n\" +\n\t\"\\rCompatibility\\x12G\\n\" +\n\t\"\\x05talos\\x18\\x01 \\x01(\\v21.talos.resource.definitions.extensions.ConstraintR\\x05talos\\\"&\\n\" +\n\t\"\\n\" +\n\t\"Constraint\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x01 \\x01(\\tR\\aversion\\\"j\\n\" +\n\t\"\\x05Layer\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12K\\n\" +\n\t\"\\bmetadata\\x18\\x02 \\x01(\\v2/.talos.resource.definitions.extensions.MetadataR\\bmetadata\\\"\\xed\\x01\\n\" +\n\t\"\\bMetadata\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\tR\\aversion\\x12\\x16\\n\" +\n\t\"\\x06author\\x18\\x03 \\x01(\\tR\\x06author\\x12 \\n\" +\n\t\"\\vdescription\\x18\\x04 \\x01(\\tR\\vdescription\\x12Z\\n\" +\n\t\"\\rcompatibility\\x18\\x05 \\x01(\\v24.talos.resource.definitions.extensions.CompatibilityR\\rcompatibility\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"extra_info\\x18\\x06 \\x01(\\tR\\textraInfoB~\\n\" +\n\t\"-dev.talos.api.resource.definitions.extensionsZMgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/extensionsb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_extensions_extensions_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_extensions_extensions_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_extensions_extensions_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_extensions_extensions_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_extensions_extensions_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_extensions_extensions_proto_rawDesc), len(file_resource_definitions_extensions_extensions_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_extensions_extensions_proto_rawDescData\n}\n\nvar file_resource_definitions_extensions_extensions_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_resource_definitions_extensions_extensions_proto_goTypes = []any{\n\t(*Compatibility)(nil), // 0: talos.resource.definitions.extensions.Compatibility\n\t(*Constraint)(nil),    // 1: talos.resource.definitions.extensions.Constraint\n\t(*Layer)(nil),         // 2: talos.resource.definitions.extensions.Layer\n\t(*Metadata)(nil),      // 3: talos.resource.definitions.extensions.Metadata\n}\nvar file_resource_definitions_extensions_extensions_proto_depIdxs = []int32{\n\t1, // 0: talos.resource.definitions.extensions.Compatibility.talos:type_name -> talos.resource.definitions.extensions.Constraint\n\t3, // 1: talos.resource.definitions.extensions.Layer.metadata:type_name -> talos.resource.definitions.extensions.Metadata\n\t0, // 2: talos.resource.definitions.extensions.Metadata.compatibility:type_name -> talos.resource.definitions.extensions.Compatibility\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_extensions_extensions_proto_init() }\nfunc file_resource_definitions_extensions_extensions_proto_init() {\n\tif File_resource_definitions_extensions_extensions_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_extensions_extensions_proto_rawDesc), len(file_resource_definitions_extensions_extensions_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_extensions_extensions_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_extensions_extensions_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_extensions_extensions_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_extensions_extensions_proto = out.File\n\tfile_resource_definitions_extensions_extensions_proto_goTypes = nil\n\tfile_resource_definitions_extensions_extensions_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/extensions/extensions_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/extensions/extensions.proto\n\npackage extensions\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *Compatibility) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Compatibility) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Compatibility) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Talos != nil {\n\t\tsize, err := m.Talos.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Constraint) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Constraint) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Constraint) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Layer) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Layer) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Layer) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tsize, err := m.Metadata.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Metadata) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Metadata) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Metadata) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExtraInfo) > 0 {\n\t\ti -= len(m.ExtraInfo)\n\t\tcopy(dAtA[i:], m.ExtraInfo)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ExtraInfo)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.Compatibility != nil {\n\t\tsize, err := m.Compatibility.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Description) > 0 {\n\t\ti -= len(m.Description)\n\t\tcopy(dAtA[i:], m.Description)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Description)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Author) > 0 {\n\t\ti -= len(m.Author)\n\t\tcopy(dAtA[i:], m.Author)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Author)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Compatibility) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Talos != nil {\n\t\tl = m.Talos.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Constraint) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Layer) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Metadata != nil {\n\t\tl = m.Metadata.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Metadata) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Author)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Description)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Compatibility != nil {\n\t\tl = m.Compatibility.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ExtraInfo)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Compatibility) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Compatibility: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Compatibility: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Talos\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Talos == nil {\n\t\t\t\tm.Talos = &Constraint{}\n\t\t\t}\n\t\t\tif err := m.Talos.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Constraint) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Constraint: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Constraint: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Layer) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Layer: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Layer: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &Metadata{}\n\t\t\t}\n\t\t\tif err := m.Metadata.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Metadata) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Metadata: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Metadata: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Author\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Author = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Description\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Description = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Compatibility\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Compatibility == nil {\n\t\t\t\tm.Compatibility = &Compatibility{}\n\t\t\t}\n\t\t\tif err := m.Compatibility.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraInfo\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraInfo = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/files/files.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/files/files.proto\n\npackage files\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// EtcFileSpecSpec describes status of rendered secrets.\ntype EtcFileSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tContents      []byte                 `protobuf:\"bytes,1,opt,name=contents,proto3\" json:\"contents,omitempty\"`\n\tMode          uint32                 `protobuf:\"varint,2,opt,name=mode,proto3\" json:\"mode,omitempty\"`\n\tSelinuxLabel  string                 `protobuf:\"bytes,3,opt,name=selinux_label,json=selinuxLabel,proto3\" json:\"selinux_label,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcFileSpecSpec) Reset() {\n\t*x = EtcFileSpecSpec{}\n\tmi := &file_resource_definitions_files_files_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcFileSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcFileSpecSpec) ProtoMessage() {}\n\nfunc (x *EtcFileSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_files_files_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcFileSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*EtcFileSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_files_files_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *EtcFileSpecSpec) GetContents() []byte {\n\tif x != nil {\n\t\treturn x.Contents\n\t}\n\treturn nil\n}\n\nfunc (x *EtcFileSpecSpec) GetMode() uint32 {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn 0\n}\n\nfunc (x *EtcFileSpecSpec) GetSelinuxLabel() string {\n\tif x != nil {\n\t\treturn x.SelinuxLabel\n\t}\n\treturn \"\"\n}\n\n// EtcFileStatusSpec describes status of rendered secrets.\ntype EtcFileStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSpecVersion   string                 `protobuf:\"bytes,1,opt,name=spec_version,json=specVersion,proto3\" json:\"spec_version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcFileStatusSpec) Reset() {\n\t*x = EtcFileStatusSpec{}\n\tmi := &file_resource_definitions_files_files_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcFileStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcFileStatusSpec) ProtoMessage() {}\n\nfunc (x *EtcFileStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_files_files_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcFileStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*EtcFileStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_files_files_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *EtcFileStatusSpec) GetSpecVersion() string {\n\tif x != nil {\n\t\treturn x.SpecVersion\n\t}\n\treturn \"\"\n}\n\nvar File_resource_definitions_files_files_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_files_files_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"&resource/definitions/files/files.proto\\x12 talos.resource.definitions.files\\\"f\\n\" +\n\t\"\\x0fEtcFileSpecSpec\\x12\\x1a\\n\" +\n\t\"\\bcontents\\x18\\x01 \\x01(\\fR\\bcontents\\x12\\x12\\n\" +\n\t\"\\x04mode\\x18\\x02 \\x01(\\rR\\x04mode\\x12#\\n\" +\n\t\"\\rselinux_label\\x18\\x03 \\x01(\\tR\\fselinuxLabel\\\"6\\n\" +\n\t\"\\x11EtcFileStatusSpec\\x12!\\n\" +\n\t\"\\fspec_version\\x18\\x01 \\x01(\\tR\\vspecVersionBt\\n\" +\n\t\"(dev.talos.api.resource.definitions.filesZHgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/filesb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_files_files_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_files_files_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_files_files_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_files_files_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_files_files_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_files_files_proto_rawDesc), len(file_resource_definitions_files_files_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_files_files_proto_rawDescData\n}\n\nvar file_resource_definitions_files_files_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_resource_definitions_files_files_proto_goTypes = []any{\n\t(*EtcFileSpecSpec)(nil),   // 0: talos.resource.definitions.files.EtcFileSpecSpec\n\t(*EtcFileStatusSpec)(nil), // 1: talos.resource.definitions.files.EtcFileStatusSpec\n}\nvar file_resource_definitions_files_files_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_files_files_proto_init() }\nfunc file_resource_definitions_files_files_proto_init() {\n\tif File_resource_definitions_files_files_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_files_files_proto_rawDesc), len(file_resource_definitions_files_files_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_files_files_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_files_files_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_files_files_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_files_files_proto = out.File\n\tfile_resource_definitions_files_files_proto_goTypes = nil\n\tfile_resource_definitions_files_files_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/files/files_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/files/files.proto\n\npackage files\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *EtcFileSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcFileSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcFileSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SelinuxLabel) > 0 {\n\t\ti -= len(m.SelinuxLabel)\n\t\tcopy(dAtA[i:], m.SelinuxLabel)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SelinuxLabel)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Contents) > 0 {\n\t\ti -= len(m.Contents)\n\t\tcopy(dAtA[i:], m.Contents)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Contents)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcFileStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcFileStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcFileStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SpecVersion) > 0 {\n\t\ti -= len(m.SpecVersion)\n\t\tcopy(dAtA[i:], m.SpecVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpecVersion)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcFileSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Contents)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tl = len(m.SelinuxLabel)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcFileStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.SpecVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcFileSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcFileSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcFileSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Contents\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Contents = append(m.Contents[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Contents == nil {\n\t\t\t\tm.Contents = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SelinuxLabel\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SelinuxLabel = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcFileStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcFileStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcFileStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SpecVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SpecVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/hardware/hardware.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/hardware/hardware.proto\n\npackage hardware\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// MemoryModuleSpec represents a single Memory.\ntype MemoryModuleSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSize          uint32                 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tDeviceLocator string                 `protobuf:\"bytes,2,opt,name=device_locator,json=deviceLocator,proto3\" json:\"device_locator,omitempty\"`\n\tBankLocator   string                 `protobuf:\"bytes,3,opt,name=bank_locator,json=bankLocator,proto3\" json:\"bank_locator,omitempty\"`\n\tSpeed         uint32                 `protobuf:\"varint,4,opt,name=speed,proto3\" json:\"speed,omitempty\"`\n\tManufacturer  string                 `protobuf:\"bytes,5,opt,name=manufacturer,proto3\" json:\"manufacturer,omitempty\"`\n\tSerialNumber  string                 `protobuf:\"bytes,6,opt,name=serial_number,json=serialNumber,proto3\" json:\"serial_number,omitempty\"`\n\tAssetTag      string                 `protobuf:\"bytes,7,opt,name=asset_tag,json=assetTag,proto3\" json:\"asset_tag,omitempty\"`\n\tProductName   string                 `protobuf:\"bytes,8,opt,name=product_name,json=productName,proto3\" json:\"product_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MemoryModuleSpec) Reset() {\n\t*x = MemoryModuleSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemoryModuleSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemoryModuleSpec) ProtoMessage() {}\n\nfunc (x *MemoryModuleSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemoryModuleSpec.ProtoReflect.Descriptor instead.\nfunc (*MemoryModuleSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *MemoryModuleSpec) GetSize() uint32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *MemoryModuleSpec) GetDeviceLocator() string {\n\tif x != nil {\n\t\treturn x.DeviceLocator\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemoryModuleSpec) GetBankLocator() string {\n\tif x != nil {\n\t\treturn x.BankLocator\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemoryModuleSpec) GetSpeed() uint32 {\n\tif x != nil {\n\t\treturn x.Speed\n\t}\n\treturn 0\n}\n\nfunc (x *MemoryModuleSpec) GetManufacturer() string {\n\tif x != nil {\n\t\treturn x.Manufacturer\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemoryModuleSpec) GetSerialNumber() string {\n\tif x != nil {\n\t\treturn x.SerialNumber\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemoryModuleSpec) GetAssetTag() string {\n\tif x != nil {\n\t\treturn x.AssetTag\n\t}\n\treturn \"\"\n}\n\nfunc (x *MemoryModuleSpec) GetProductName() string {\n\tif x != nil {\n\t\treturn x.ProductName\n\t}\n\treturn \"\"\n}\n\n// PCIDeviceSpec represents a single processor.\ntype PCIDeviceSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tClass         string                 `protobuf:\"bytes,1,opt,name=class,proto3\" json:\"class,omitempty\"`\n\tSubclass      string                 `protobuf:\"bytes,2,opt,name=subclass,proto3\" json:\"subclass,omitempty\"`\n\tVendor        string                 `protobuf:\"bytes,3,opt,name=vendor,proto3\" json:\"vendor,omitempty\"`\n\tProduct       string                 `protobuf:\"bytes,4,opt,name=product,proto3\" json:\"product,omitempty\"`\n\tClassId       string                 `protobuf:\"bytes,5,opt,name=class_id,json=classId,proto3\" json:\"class_id,omitempty\"`\n\tSubclassId    string                 `protobuf:\"bytes,6,opt,name=subclass_id,json=subclassId,proto3\" json:\"subclass_id,omitempty\"`\n\tVendorId      string                 `protobuf:\"bytes,7,opt,name=vendor_id,json=vendorId,proto3\" json:\"vendor_id,omitempty\"`\n\tProductId     string                 `protobuf:\"bytes,8,opt,name=product_id,json=productId,proto3\" json:\"product_id,omitempty\"`\n\tDriver        string                 `protobuf:\"bytes,9,opt,name=driver,proto3\" json:\"driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PCIDeviceSpec) Reset() {\n\t*x = PCIDeviceSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PCIDeviceSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PCIDeviceSpec) ProtoMessage() {}\n\nfunc (x *PCIDeviceSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PCIDeviceSpec.ProtoReflect.Descriptor instead.\nfunc (*PCIDeviceSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *PCIDeviceSpec) GetClass() string {\n\tif x != nil {\n\t\treturn x.Class\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetSubclass() string {\n\tif x != nil {\n\t\treturn x.Subclass\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetVendor() string {\n\tif x != nil {\n\t\treturn x.Vendor\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetProduct() string {\n\tif x != nil {\n\t\treturn x.Product\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetClassId() string {\n\tif x != nil {\n\t\treturn x.ClassId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetSubclassId() string {\n\tif x != nil {\n\t\treturn x.SubclassId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetVendorId() string {\n\tif x != nil {\n\t\treturn x.VendorId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetProductId() string {\n\tif x != nil {\n\t\treturn x.ProductId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDeviceSpec) GetDriver() string {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn \"\"\n}\n\n// PCIDriverRebindConfigSpec describes PCI rebind configuration.\ntype PCIDriverRebindConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPciid         string                 `protobuf:\"bytes,1,opt,name=pciid,proto3\" json:\"pciid,omitempty\"`\n\tTargetDriver  string                 `protobuf:\"bytes,2,opt,name=target_driver,json=targetDriver,proto3\" json:\"target_driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PCIDriverRebindConfigSpec) Reset() {\n\t*x = PCIDriverRebindConfigSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PCIDriverRebindConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PCIDriverRebindConfigSpec) ProtoMessage() {}\n\nfunc (x *PCIDriverRebindConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PCIDriverRebindConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*PCIDriverRebindConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *PCIDriverRebindConfigSpec) GetPciid() string {\n\tif x != nil {\n\t\treturn x.Pciid\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDriverRebindConfigSpec) GetTargetDriver() string {\n\tif x != nil {\n\t\treturn x.TargetDriver\n\t}\n\treturn \"\"\n}\n\n// PCIDriverRebindStatusSpec describes status of rebinded drivers.\ntype PCIDriverRebindStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPciid         string                 `protobuf:\"bytes,1,opt,name=pciid,proto3\" json:\"pciid,omitempty\"`\n\tTargetDriver  string                 `protobuf:\"bytes,2,opt,name=target_driver,json=targetDriver,proto3\" json:\"target_driver,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PCIDriverRebindStatusSpec) Reset() {\n\t*x = PCIDriverRebindStatusSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PCIDriverRebindStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PCIDriverRebindStatusSpec) ProtoMessage() {}\n\nfunc (x *PCIDriverRebindStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PCIDriverRebindStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*PCIDriverRebindStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *PCIDriverRebindStatusSpec) GetPciid() string {\n\tif x != nil {\n\t\treturn x.Pciid\n\t}\n\treturn \"\"\n}\n\nfunc (x *PCIDriverRebindStatusSpec) GetTargetDriver() string {\n\tif x != nil {\n\t\treturn x.TargetDriver\n\t}\n\treturn \"\"\n}\n\n// ProcessorSpec represents a single processor.\ntype ProcessorSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSocket        string                 `protobuf:\"bytes,1,opt,name=socket,proto3\" json:\"socket,omitempty\"`\n\tManufacturer  string                 `protobuf:\"bytes,2,opt,name=manufacturer,proto3\" json:\"manufacturer,omitempty\"`\n\tProductName   string                 `protobuf:\"bytes,3,opt,name=product_name,json=productName,proto3\" json:\"product_name,omitempty\"`\n\tMaxSpeed      uint32                 `protobuf:\"varint,4,opt,name=max_speed,json=maxSpeed,proto3\" json:\"max_speed,omitempty\"`\n\tBootSpeed     uint32                 `protobuf:\"varint,5,opt,name=boot_speed,json=bootSpeed,proto3\" json:\"boot_speed,omitempty\"`\n\tStatus        uint32                 `protobuf:\"varint,6,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tSerialNumber  string                 `protobuf:\"bytes,7,opt,name=serial_number,json=serialNumber,proto3\" json:\"serial_number,omitempty\"`\n\tAssetTag      string                 `protobuf:\"bytes,8,opt,name=asset_tag,json=assetTag,proto3\" json:\"asset_tag,omitempty\"`\n\tPartNumber    string                 `protobuf:\"bytes,9,opt,name=part_number,json=partNumber,proto3\" json:\"part_number,omitempty\"`\n\tCoreCount     uint32                 `protobuf:\"varint,10,opt,name=core_count,json=coreCount,proto3\" json:\"core_count,omitempty\"`\n\tCoreEnabled   uint32                 `protobuf:\"varint,11,opt,name=core_enabled,json=coreEnabled,proto3\" json:\"core_enabled,omitempty\"`\n\tThreadCount   uint32                 `protobuf:\"varint,12,opt,name=thread_count,json=threadCount,proto3\" json:\"thread_count,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ProcessorSpec) Reset() {\n\t*x = ProcessorSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProcessorSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProcessorSpec) ProtoMessage() {}\n\nfunc (x *ProcessorSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProcessorSpec.ProtoReflect.Descriptor instead.\nfunc (*ProcessorSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *ProcessorSpec) GetSocket() string {\n\tif x != nil {\n\t\treturn x.Socket\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetManufacturer() string {\n\tif x != nil {\n\t\treturn x.Manufacturer\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetProductName() string {\n\tif x != nil {\n\t\treturn x.ProductName\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetMaxSpeed() uint32 {\n\tif x != nil {\n\t\treturn x.MaxSpeed\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessorSpec) GetBootSpeed() uint32 {\n\tif x != nil {\n\t\treturn x.BootSpeed\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessorSpec) GetStatus() uint32 {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessorSpec) GetSerialNumber() string {\n\tif x != nil {\n\t\treturn x.SerialNumber\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetAssetTag() string {\n\tif x != nil {\n\t\treturn x.AssetTag\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetPartNumber() string {\n\tif x != nil {\n\t\treturn x.PartNumber\n\t}\n\treturn \"\"\n}\n\nfunc (x *ProcessorSpec) GetCoreCount() uint32 {\n\tif x != nil {\n\t\treturn x.CoreCount\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessorSpec) GetCoreEnabled() uint32 {\n\tif x != nil {\n\t\treturn x.CoreEnabled\n\t}\n\treturn 0\n}\n\nfunc (x *ProcessorSpec) GetThreadCount() uint32 {\n\tif x != nil {\n\t\treturn x.ThreadCount\n\t}\n\treturn 0\n}\n\n// SystemInformationSpec represents the system information obtained from smbios.\ntype SystemInformationSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tManufacturer  string                 `protobuf:\"bytes,1,opt,name=manufacturer,proto3\" json:\"manufacturer,omitempty\"`\n\tProductName   string                 `protobuf:\"bytes,2,opt,name=product_name,json=productName,proto3\" json:\"product_name,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,3,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tSerialNumber  string                 `protobuf:\"bytes,4,opt,name=serial_number,json=serialNumber,proto3\" json:\"serial_number,omitempty\"`\n\tUuid          string                 `protobuf:\"bytes,5,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\tWakeUpType    string                 `protobuf:\"bytes,6,opt,name=wake_up_type,json=wakeUpType,proto3\" json:\"wake_up_type,omitempty\"`\n\tSkuNumber     string                 `protobuf:\"bytes,7,opt,name=sku_number,json=skuNumber,proto3\" json:\"sku_number,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SystemInformationSpec) Reset() {\n\t*x = SystemInformationSpec{}\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SystemInformationSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SystemInformationSpec) ProtoMessage() {}\n\nfunc (x *SystemInformationSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_hardware_hardware_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SystemInformationSpec.ProtoReflect.Descriptor instead.\nfunc (*SystemInformationSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *SystemInformationSpec) GetManufacturer() string {\n\tif x != nil {\n\t\treturn x.Manufacturer\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetProductName() string {\n\tif x != nil {\n\t\treturn x.ProductName\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetSerialNumber() string {\n\tif x != nil {\n\t\treturn x.SerialNumber\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetWakeUpType() string {\n\tif x != nil {\n\t\treturn x.WakeUpType\n\t}\n\treturn \"\"\n}\n\nfunc (x *SystemInformationSpec) GetSkuNumber() string {\n\tif x != nil {\n\t\treturn x.SkuNumber\n\t}\n\treturn \"\"\n}\n\nvar File_resource_definitions_hardware_hardware_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_hardware_hardware_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\",resource/definitions/hardware/hardware.proto\\x12#talos.resource.definitions.hardware\\\"\\x8f\\x02\\n\" +\n\t\"\\x10MemoryModuleSpec\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x01 \\x01(\\rR\\x04size\\x12%\\n\" +\n\t\"\\x0edevice_locator\\x18\\x02 \\x01(\\tR\\rdeviceLocator\\x12!\\n\" +\n\t\"\\fbank_locator\\x18\\x03 \\x01(\\tR\\vbankLocator\\x12\\x14\\n\" +\n\t\"\\x05speed\\x18\\x04 \\x01(\\rR\\x05speed\\x12\\\"\\n\" +\n\t\"\\fmanufacturer\\x18\\x05 \\x01(\\tR\\fmanufacturer\\x12#\\n\" +\n\t\"\\rserial_number\\x18\\x06 \\x01(\\tR\\fserialNumber\\x12\\x1b\\n\" +\n\t\"\\tasset_tag\\x18\\a \\x01(\\tR\\bassetTag\\x12!\\n\" +\n\t\"\\fproduct_name\\x18\\b \\x01(\\tR\\vproductName\\\"\\x83\\x02\\n\" +\n\t\"\\rPCIDeviceSpec\\x12\\x14\\n\" +\n\t\"\\x05class\\x18\\x01 \\x01(\\tR\\x05class\\x12\\x1a\\n\" +\n\t\"\\bsubclass\\x18\\x02 \\x01(\\tR\\bsubclass\\x12\\x16\\n\" +\n\t\"\\x06vendor\\x18\\x03 \\x01(\\tR\\x06vendor\\x12\\x18\\n\" +\n\t\"\\aproduct\\x18\\x04 \\x01(\\tR\\aproduct\\x12\\x19\\n\" +\n\t\"\\bclass_id\\x18\\x05 \\x01(\\tR\\aclassId\\x12\\x1f\\n\" +\n\t\"\\vsubclass_id\\x18\\x06 \\x01(\\tR\\n\" +\n\t\"subclassId\\x12\\x1b\\n\" +\n\t\"\\tvendor_id\\x18\\a \\x01(\\tR\\bvendorId\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"product_id\\x18\\b \\x01(\\tR\\tproductId\\x12\\x16\\n\" +\n\t\"\\x06driver\\x18\\t \\x01(\\tR\\x06driver\\\"V\\n\" +\n\t\"\\x19PCIDriverRebindConfigSpec\\x12\\x14\\n\" +\n\t\"\\x05pciid\\x18\\x01 \\x01(\\tR\\x05pciid\\x12#\\n\" +\n\t\"\\rtarget_driver\\x18\\x02 \\x01(\\tR\\ftargetDriver\\\"V\\n\" +\n\t\"\\x19PCIDriverRebindStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05pciid\\x18\\x01 \\x01(\\tR\\x05pciid\\x12#\\n\" +\n\t\"\\rtarget_driver\\x18\\x02 \\x01(\\tR\\ftargetDriver\\\"\\x8a\\x03\\n\" +\n\t\"\\rProcessorSpec\\x12\\x16\\n\" +\n\t\"\\x06socket\\x18\\x01 \\x01(\\tR\\x06socket\\x12\\\"\\n\" +\n\t\"\\fmanufacturer\\x18\\x02 \\x01(\\tR\\fmanufacturer\\x12!\\n\" +\n\t\"\\fproduct_name\\x18\\x03 \\x01(\\tR\\vproductName\\x12\\x1b\\n\" +\n\t\"\\tmax_speed\\x18\\x04 \\x01(\\rR\\bmaxSpeed\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"boot_speed\\x18\\x05 \\x01(\\rR\\tbootSpeed\\x12\\x16\\n\" +\n\t\"\\x06status\\x18\\x06 \\x01(\\rR\\x06status\\x12#\\n\" +\n\t\"\\rserial_number\\x18\\a \\x01(\\tR\\fserialNumber\\x12\\x1b\\n\" +\n\t\"\\tasset_tag\\x18\\b \\x01(\\tR\\bassetTag\\x12\\x1f\\n\" +\n\t\"\\vpart_number\\x18\\t \\x01(\\tR\\n\" +\n\t\"partNumber\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"core_count\\x18\\n\" +\n\t\" \\x01(\\rR\\tcoreCount\\x12!\\n\" +\n\t\"\\fcore_enabled\\x18\\v \\x01(\\rR\\vcoreEnabled\\x12!\\n\" +\n\t\"\\fthread_count\\x18\\f \\x01(\\rR\\vthreadCount\\\"\\xf2\\x01\\n\" +\n\t\"\\x15SystemInformationSpec\\x12\\\"\\n\" +\n\t\"\\fmanufacturer\\x18\\x01 \\x01(\\tR\\fmanufacturer\\x12!\\n\" +\n\t\"\\fproduct_name\\x18\\x02 \\x01(\\tR\\vproductName\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x03 \\x01(\\tR\\aversion\\x12#\\n\" +\n\t\"\\rserial_number\\x18\\x04 \\x01(\\tR\\fserialNumber\\x12\\x12\\n\" +\n\t\"\\x04uuid\\x18\\x05 \\x01(\\tR\\x04uuid\\x12 \\n\" +\n\t\"\\fwake_up_type\\x18\\x06 \\x01(\\tR\\n\" +\n\t\"wakeUpType\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"sku_number\\x18\\a \\x01(\\tR\\tskuNumberBz\\n\" +\n\t\"+dev.talos.api.resource.definitions.hardwareZKgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/hardwareb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_hardware_hardware_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_hardware_hardware_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_hardware_hardware_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_hardware_hardware_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_hardware_hardware_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_hardware_hardware_proto_rawDesc), len(file_resource_definitions_hardware_hardware_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_hardware_hardware_proto_rawDescData\n}\n\nvar file_resource_definitions_hardware_hardware_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_resource_definitions_hardware_hardware_proto_goTypes = []any{\n\t(*MemoryModuleSpec)(nil),          // 0: talos.resource.definitions.hardware.MemoryModuleSpec\n\t(*PCIDeviceSpec)(nil),             // 1: talos.resource.definitions.hardware.PCIDeviceSpec\n\t(*PCIDriverRebindConfigSpec)(nil), // 2: talos.resource.definitions.hardware.PCIDriverRebindConfigSpec\n\t(*PCIDriverRebindStatusSpec)(nil), // 3: talos.resource.definitions.hardware.PCIDriverRebindStatusSpec\n\t(*ProcessorSpec)(nil),             // 4: talos.resource.definitions.hardware.ProcessorSpec\n\t(*SystemInformationSpec)(nil),     // 5: talos.resource.definitions.hardware.SystemInformationSpec\n}\nvar file_resource_definitions_hardware_hardware_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_hardware_hardware_proto_init() }\nfunc file_resource_definitions_hardware_hardware_proto_init() {\n\tif File_resource_definitions_hardware_hardware_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_hardware_hardware_proto_rawDesc), len(file_resource_definitions_hardware_hardware_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_hardware_hardware_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_hardware_hardware_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_hardware_hardware_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_hardware_hardware_proto = out.File\n\tfile_resource_definitions_hardware_hardware_proto_goTypes = nil\n\tfile_resource_definitions_hardware_hardware_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/hardware/hardware_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/hardware/hardware.proto\n\npackage hardware\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *MemoryModuleSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemoryModuleSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemoryModuleSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ProductName) > 0 {\n\t\ti -= len(m.ProductName)\n\t\tcopy(dAtA[i:], m.ProductName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProductName)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.AssetTag) > 0 {\n\t\ti -= len(m.AssetTag)\n\t\tcopy(dAtA[i:], m.AssetTag)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AssetTag)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.SerialNumber) > 0 {\n\t\ti -= len(m.SerialNumber)\n\t\tcopy(dAtA[i:], m.SerialNumber)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SerialNumber)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Manufacturer) > 0 {\n\t\ti -= len(m.Manufacturer)\n\t\tcopy(dAtA[i:], m.Manufacturer)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Manufacturer)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Speed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Speed))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.BankLocator) > 0 {\n\t\ti -= len(m.BankLocator)\n\t\tcopy(dAtA[i:], m.BankLocator)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BankLocator)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.DeviceLocator) > 0 {\n\t\ti -= len(m.DeviceLocator)\n\t\tcopy(dAtA[i:], m.DeviceLocator)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DeviceLocator)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PCIDeviceSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PCIDeviceSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PCIDeviceSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Driver) > 0 {\n\t\ti -= len(m.Driver)\n\t\tcopy(dAtA[i:], m.Driver)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Driver)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.ProductId) > 0 {\n\t\ti -= len(m.ProductId)\n\t\tcopy(dAtA[i:], m.ProductId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProductId)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.VendorId) > 0 {\n\t\ti -= len(m.VendorId)\n\t\tcopy(dAtA[i:], m.VendorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VendorId)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.SubclassId) > 0 {\n\t\ti -= len(m.SubclassId)\n\t\tcopy(dAtA[i:], m.SubclassId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SubclassId)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.ClassId) > 0 {\n\t\ti -= len(m.ClassId)\n\t\tcopy(dAtA[i:], m.ClassId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClassId)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Product) > 0 {\n\t\ti -= len(m.Product)\n\t\tcopy(dAtA[i:], m.Product)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Product)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Vendor) > 0 {\n\t\ti -= len(m.Vendor)\n\t\tcopy(dAtA[i:], m.Vendor)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Vendor)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Subclass) > 0 {\n\t\ti -= len(m.Subclass)\n\t\tcopy(dAtA[i:], m.Subclass)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Subclass)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Class) > 0 {\n\t\ti -= len(m.Class)\n\t\tcopy(dAtA[i:], m.Class)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Class)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PCIDriverRebindConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PCIDriverRebindConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PCIDriverRebindConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.TargetDriver) > 0 {\n\t\ti -= len(m.TargetDriver)\n\t\tcopy(dAtA[i:], m.TargetDriver)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TargetDriver)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Pciid) > 0 {\n\t\ti -= len(m.Pciid)\n\t\tcopy(dAtA[i:], m.Pciid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Pciid)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PCIDriverRebindStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PCIDriverRebindStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PCIDriverRebindStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.TargetDriver) > 0 {\n\t\ti -= len(m.TargetDriver)\n\t\tcopy(dAtA[i:], m.TargetDriver)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TargetDriver)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Pciid) > 0 {\n\t\ti -= len(m.Pciid)\n\t\tcopy(dAtA[i:], m.Pciid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Pciid)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProcessorSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProcessorSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProcessorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ThreadCount != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ThreadCount))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.CoreEnabled != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CoreEnabled))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.CoreCount != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CoreCount))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif len(m.PartNumber) > 0 {\n\t\ti -= len(m.PartNumber)\n\t\tcopy(dAtA[i:], m.PartNumber)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartNumber)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.AssetTag) > 0 {\n\t\ti -= len(m.AssetTag)\n\t\tcopy(dAtA[i:], m.AssetTag)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AssetTag)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.SerialNumber) > 0 {\n\t\ti -= len(m.SerialNumber)\n\t\tcopy(dAtA[i:], m.SerialNumber)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SerialNumber)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Status != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Status))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.BootSpeed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.BootSpeed))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.MaxSpeed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxSpeed))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.ProductName) > 0 {\n\t\ti -= len(m.ProductName)\n\t\tcopy(dAtA[i:], m.ProductName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProductName)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Manufacturer) > 0 {\n\t\ti -= len(m.Manufacturer)\n\t\tcopy(dAtA[i:], m.Manufacturer)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Manufacturer)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Socket) > 0 {\n\t\ti -= len(m.Socket)\n\t\tcopy(dAtA[i:], m.Socket)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Socket)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SystemInformationSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SystemInformationSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SystemInformationSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SkuNumber) > 0 {\n\t\ti -= len(m.SkuNumber)\n\t\tcopy(dAtA[i:], m.SkuNumber)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SkuNumber)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.WakeUpType) > 0 {\n\t\ti -= len(m.WakeUpType)\n\t\tcopy(dAtA[i:], m.WakeUpType)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.WakeUpType)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Uuid) > 0 {\n\t\ti -= len(m.Uuid)\n\t\tcopy(dAtA[i:], m.Uuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.SerialNumber) > 0 {\n\t\ti -= len(m.SerialNumber)\n\t\tcopy(dAtA[i:], m.SerialNumber)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SerialNumber)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.ProductName) > 0 {\n\t\ti -= len(m.ProductName)\n\t\tcopy(dAtA[i:], m.ProductName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProductName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Manufacturer) > 0 {\n\t\ti -= len(m.Manufacturer)\n\t\tcopy(dAtA[i:], m.Manufacturer)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Manufacturer)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemoryModuleSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tl = len(m.DeviceLocator)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BankLocator)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Speed != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Speed))\n\t}\n\tl = len(m.Manufacturer)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SerialNumber)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.AssetTag)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProductName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PCIDeviceSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Class)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Subclass)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Vendor)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Product)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ClassId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SubclassId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.VendorId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProductId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Driver)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PCIDriverRebindConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Pciid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.TargetDriver)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PCIDriverRebindStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Pciid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.TargetDriver)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProcessorSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Socket)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Manufacturer)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProductName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MaxSpeed != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MaxSpeed))\n\t}\n\tif m.BootSpeed != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.BootSpeed))\n\t}\n\tif m.Status != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Status))\n\t}\n\tl = len(m.SerialNumber)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.AssetTag)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PartNumber)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CoreCount != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CoreCount))\n\t}\n\tif m.CoreEnabled != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CoreEnabled))\n\t}\n\tif m.ThreadCount != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ThreadCount))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SystemInformationSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Manufacturer)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProductName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SerialNumber)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Uuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.WakeUpType)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SkuNumber)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemoryModuleSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemoryModuleSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemoryModuleSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DeviceLocator\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DeviceLocator = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BankLocator\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BankLocator = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Speed\", wireType)\n\t\t\t}\n\t\t\tm.Speed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Speed |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Manufacturer\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Manufacturer = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SerialNumber\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SerialNumber = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AssetTag\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AssetTag = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProductName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProductName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PCIDeviceSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDeviceSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDeviceSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Class\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Class = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Subclass\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Subclass = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vendor\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Vendor = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Product\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Product = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClassId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClassId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SubclassId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SubclassId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VendorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VendorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProductId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProductId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Driver = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PCIDriverRebindConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDriverRebindConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDriverRebindConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pciid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Pciid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TargetDriver\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TargetDriver = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PCIDriverRebindStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDriverRebindStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PCIDriverRebindStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pciid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Pciid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TargetDriver\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TargetDriver = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProcessorSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessorSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProcessorSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Socket\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Socket = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Manufacturer\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Manufacturer = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProductName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProductName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MaxSpeed\", wireType)\n\t\t\t}\n\t\t\tm.MaxSpeed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MaxSpeed |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootSpeed\", wireType)\n\t\t\t}\n\t\t\tm.BootSpeed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.BootSpeed |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tm.Status = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Status |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SerialNumber\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SerialNumber = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AssetTag\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AssetTag = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PartNumber\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PartNumber = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CoreCount\", wireType)\n\t\t\t}\n\t\t\tm.CoreCount = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CoreCount |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CoreEnabled\", wireType)\n\t\t\t}\n\t\t\tm.CoreEnabled = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CoreEnabled |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ThreadCount\", wireType)\n\t\t\t}\n\t\t\tm.ThreadCount = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ThreadCount |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SystemInformationSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SystemInformationSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SystemInformationSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Manufacturer\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Manufacturer = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProductName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProductName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SerialNumber\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SerialNumber = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WakeUpType\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.WakeUpType = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkuNumber\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SkuNumber = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/k8s/k8s.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/k8s/k8s.proto\n\npackage k8s\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tstructpb \"google.golang.org/protobuf/types/known/structpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tproto \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/proto\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// APIServerConfigSpec is configuration for kube-apiserver.\ntype APIServerConfigSpec struct {\n\tstate                protoimpl.MessageState `protogen:\"open.v1\"`\n\tImage                string                 `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tCloudProvider        string                 `protobuf:\"bytes,2,opt,name=cloud_provider,json=cloudProvider,proto3\" json:\"cloud_provider,omitempty\"`\n\tControlPlaneEndpoint string                 `protobuf:\"bytes,3,opt,name=control_plane_endpoint,json=controlPlaneEndpoint,proto3\" json:\"control_plane_endpoint,omitempty\"`\n\tEtcdServers          []string               `protobuf:\"bytes,4,rep,name=etcd_servers,json=etcdServers,proto3\" json:\"etcd_servers,omitempty\"`\n\tLocalPort            int64                  `protobuf:\"varint,5,opt,name=local_port,json=localPort,proto3\" json:\"local_port,omitempty\"`\n\tServiceCidRs         []string               `protobuf:\"bytes,6,rep,name=service_cid_rs,json=serviceCidRs,proto3\" json:\"service_cid_rs,omitempty\"`\n\tExtraArgs            map[string]*ArgValues  `protobuf:\"bytes,7,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tExtraVolumes         []*ExtraVolume         `protobuf:\"bytes,8,rep,name=extra_volumes,json=extraVolumes,proto3\" json:\"extra_volumes,omitempty\"`\n\tEnvironmentVariables map[string]string      `protobuf:\"bytes,9,rep,name=environment_variables,json=environmentVariables,proto3\" json:\"environment_variables,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tAdvertisedAddress    string                 `protobuf:\"bytes,11,opt,name=advertised_address,json=advertisedAddress,proto3\" json:\"advertised_address,omitempty\"`\n\tResources            *Resources             `protobuf:\"bytes,12,opt,name=resources,proto3\" json:\"resources,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *APIServerConfigSpec) Reset() {\n\t*x = APIServerConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *APIServerConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*APIServerConfigSpec) ProtoMessage() {}\n\nfunc (x *APIServerConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use APIServerConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*APIServerConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *APIServerConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *APIServerConfigSpec) GetCloudProvider() string {\n\tif x != nil {\n\t\treturn x.CloudProvider\n\t}\n\treturn \"\"\n}\n\nfunc (x *APIServerConfigSpec) GetControlPlaneEndpoint() string {\n\tif x != nil {\n\t\treturn x.ControlPlaneEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *APIServerConfigSpec) GetEtcdServers() []string {\n\tif x != nil {\n\t\treturn x.EtcdServers\n\t}\n\treturn nil\n}\n\nfunc (x *APIServerConfigSpec) GetLocalPort() int64 {\n\tif x != nil {\n\t\treturn x.LocalPort\n\t}\n\treturn 0\n}\n\nfunc (x *APIServerConfigSpec) GetServiceCidRs() []string {\n\tif x != nil {\n\t\treturn x.ServiceCidRs\n\t}\n\treturn nil\n}\n\nfunc (x *APIServerConfigSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *APIServerConfigSpec) GetExtraVolumes() []*ExtraVolume {\n\tif x != nil {\n\t\treturn x.ExtraVolumes\n\t}\n\treturn nil\n}\n\nfunc (x *APIServerConfigSpec) GetEnvironmentVariables() map[string]string {\n\tif x != nil {\n\t\treturn x.EnvironmentVariables\n\t}\n\treturn nil\n}\n\nfunc (x *APIServerConfigSpec) GetAdvertisedAddress() string {\n\tif x != nil {\n\t\treturn x.AdvertisedAddress\n\t}\n\treturn \"\"\n}\n\nfunc (x *APIServerConfigSpec) GetResources() *Resources {\n\tif x != nil {\n\t\treturn x.Resources\n\t}\n\treturn nil\n}\n\n// AdmissionControlConfigSpec is configuration for kube-apiserver.\ntype AdmissionControlConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tConfig        []*AdmissionPluginSpec `protobuf:\"bytes,1,rep,name=config,proto3\" json:\"config,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AdmissionControlConfigSpec) Reset() {\n\t*x = AdmissionControlConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AdmissionControlConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AdmissionControlConfigSpec) ProtoMessage() {}\n\nfunc (x *AdmissionControlConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AdmissionControlConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*AdmissionControlConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *AdmissionControlConfigSpec) GetConfig() []*AdmissionPluginSpec {\n\tif x != nil {\n\t\treturn x.Config\n\t}\n\treturn nil\n}\n\n// AdmissionPluginSpec is a single admission plugin configuration Admission Control plugins.\ntype AdmissionPluginSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tConfiguration *structpb.Struct       `protobuf:\"bytes,2,opt,name=configuration,proto3\" json:\"configuration,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AdmissionPluginSpec) Reset() {\n\t*x = AdmissionPluginSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AdmissionPluginSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AdmissionPluginSpec) ProtoMessage() {}\n\nfunc (x *AdmissionPluginSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AdmissionPluginSpec.ProtoReflect.Descriptor instead.\nfunc (*AdmissionPluginSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *AdmissionPluginSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *AdmissionPluginSpec) GetConfiguration() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Configuration\n\t}\n\treturn nil\n}\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\ntype ArgValues struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tValues        []string               `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ArgValues) Reset() {\n\t*x = ArgValues{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ArgValues) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ArgValues) ProtoMessage() {}\n\nfunc (x *ArgValues) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ArgValues.ProtoReflect.Descriptor instead.\nfunc (*ArgValues) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *ArgValues) GetValues() []string {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\n// AuditPolicyConfigSpec is audit policy configuration for kube-apiserver.\ntype AuditPolicyConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tConfig        *structpb.Struct       `protobuf:\"bytes,1,opt,name=config,proto3\" json:\"config,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AuditPolicyConfigSpec) Reset() {\n\t*x = AuditPolicyConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AuditPolicyConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AuditPolicyConfigSpec) ProtoMessage() {}\n\nfunc (x *AuditPolicyConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AuditPolicyConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*AuditPolicyConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *AuditPolicyConfigSpec) GetConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Config\n\t}\n\treturn nil\n}\n\n// AuthorizationAuthorizersSpec is a configuration of authorization authorizers.\ntype AuthorizationAuthorizersSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tType          string                 `protobuf:\"bytes,1,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tName          string                 `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tWebhook       *structpb.Struct       `protobuf:\"bytes,3,opt,name=webhook,proto3\" json:\"webhook,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AuthorizationAuthorizersSpec) Reset() {\n\t*x = AuthorizationAuthorizersSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AuthorizationAuthorizersSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AuthorizationAuthorizersSpec) ProtoMessage() {}\n\nfunc (x *AuthorizationAuthorizersSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AuthorizationAuthorizersSpec.ProtoReflect.Descriptor instead.\nfunc (*AuthorizationAuthorizersSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *AuthorizationAuthorizersSpec) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *AuthorizationAuthorizersSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *AuthorizationAuthorizersSpec) GetWebhook() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Webhook\n\t}\n\treturn nil\n}\n\n// AuthorizationConfigSpec is authorization configuration for kube-apiserver.\ntype AuthorizationConfigSpec struct {\n\tstate         protoimpl.MessageState          `protogen:\"open.v1\"`\n\tImage         string                          `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tConfig        []*AuthorizationAuthorizersSpec `protobuf:\"bytes,2,rep,name=config,proto3\" json:\"config,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AuthorizationConfigSpec) Reset() {\n\t*x = AuthorizationConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AuthorizationConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AuthorizationConfigSpec) ProtoMessage() {}\n\nfunc (x *AuthorizationConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AuthorizationConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*AuthorizationConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *AuthorizationConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *AuthorizationConfigSpec) GetConfig() []*AuthorizationAuthorizersSpec {\n\tif x != nil {\n\t\treturn x.Config\n\t}\n\treturn nil\n}\n\n// BootstrapManifestsConfigSpec is configuration for bootstrap manifests.\ntype BootstrapManifestsConfigSpec struct {\n\tstate                             protoimpl.MessageState `protogen:\"open.v1\"`\n\tServer                            string                 `protobuf:\"bytes,1,opt,name=server,proto3\" json:\"server,omitempty\"`\n\tClusterDomain                     string                 `protobuf:\"bytes,2,opt,name=cluster_domain,json=clusterDomain,proto3\" json:\"cluster_domain,omitempty\"`\n\tPodCidRs                          []string               `protobuf:\"bytes,3,rep,name=pod_cid_rs,json=podCidRs,proto3\" json:\"pod_cid_rs,omitempty\"`\n\tProxyEnabled                      bool                   `protobuf:\"varint,4,opt,name=proxy_enabled,json=proxyEnabled,proto3\" json:\"proxy_enabled,omitempty\"`\n\tProxyImage                        string                 `protobuf:\"bytes,5,opt,name=proxy_image,json=proxyImage,proto3\" json:\"proxy_image,omitempty\"`\n\tProxyArgs                         []string               `protobuf:\"bytes,6,rep,name=proxy_args,json=proxyArgs,proto3\" json:\"proxy_args,omitempty\"`\n\tCoreDnsEnabled                    bool                   `protobuf:\"varint,7,opt,name=core_dns_enabled,json=coreDnsEnabled,proto3\" json:\"core_dns_enabled,omitempty\"`\n\tCoreDnsImage                      string                 `protobuf:\"bytes,8,opt,name=core_dns_image,json=coreDnsImage,proto3\" json:\"core_dns_image,omitempty\"`\n\tDnsServiceIp                      string                 `protobuf:\"bytes,9,opt,name=dns_service_ip,json=dnsServiceIp,proto3\" json:\"dns_service_ip,omitempty\"`\n\tDnsServiceIPv6                    string                 `protobuf:\"bytes,10,opt,name=dns_service_i_pv6,json=dnsServiceIPv6,proto3\" json:\"dns_service_i_pv6,omitempty\"`\n\tFlannelEnabled                    bool                   `protobuf:\"varint,11,opt,name=flannel_enabled,json=flannelEnabled,proto3\" json:\"flannel_enabled,omitempty\"`\n\tFlannelImage                      string                 `protobuf:\"bytes,12,opt,name=flannel_image,json=flannelImage,proto3\" json:\"flannel_image,omitempty\"`\n\tPodSecurityPolicyEnabled          bool                   `protobuf:\"varint,14,opt,name=pod_security_policy_enabled,json=podSecurityPolicyEnabled,proto3\" json:\"pod_security_policy_enabled,omitempty\"`\n\tTalosApiServiceEnabled            bool                   `protobuf:\"varint,15,opt,name=talos_api_service_enabled,json=talosApiServiceEnabled,proto3\" json:\"talos_api_service_enabled,omitempty\"`\n\tFlannelExtraArgs                  []string               `protobuf:\"bytes,16,rep,name=flannel_extra_args,json=flannelExtraArgs,proto3\" json:\"flannel_extra_args,omitempty\"`\n\tFlannelKubeServiceHost            string                 `protobuf:\"bytes,17,opt,name=flannel_kube_service_host,json=flannelKubeServiceHost,proto3\" json:\"flannel_kube_service_host,omitempty\"`\n\tFlannelKubeServicePort            string                 `protobuf:\"bytes,18,opt,name=flannel_kube_service_port,json=flannelKubeServicePort,proto3\" json:\"flannel_kube_service_port,omitempty\"`\n\tFlannelKubeNetworkPoliciesEnabled bool                   `protobuf:\"varint,19,opt,name=flannel_kube_network_policies_enabled,json=flannelKubeNetworkPoliciesEnabled,proto3\" json:\"flannel_kube_network_policies_enabled,omitempty\"`\n\tFlannelKubeNetworkPoliciesImage   string                 `protobuf:\"bytes,20,opt,name=flannel_kube_network_policies_image,json=flannelKubeNetworkPoliciesImage,proto3\" json:\"flannel_kube_network_policies_image,omitempty\"`\n\tCniName                           string                 `protobuf:\"bytes,21,opt,name=cni_name,json=cniName,proto3\" json:\"cni_name,omitempty\"`\n\tunknownFields                     protoimpl.UnknownFields\n\tsizeCache                         protoimpl.SizeCache\n}\n\nfunc (x *BootstrapManifestsConfigSpec) Reset() {\n\t*x = BootstrapManifestsConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BootstrapManifestsConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BootstrapManifestsConfigSpec) ProtoMessage() {}\n\nfunc (x *BootstrapManifestsConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BootstrapManifestsConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*BootstrapManifestsConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetServer() string {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetClusterDomain() string {\n\tif x != nil {\n\t\treturn x.ClusterDomain\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetPodCidRs() []string {\n\tif x != nil {\n\t\treturn x.PodCidRs\n\t}\n\treturn nil\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetProxyEnabled() bool {\n\tif x != nil {\n\t\treturn x.ProxyEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetProxyImage() string {\n\tif x != nil {\n\t\treturn x.ProxyImage\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetProxyArgs() []string {\n\tif x != nil {\n\t\treturn x.ProxyArgs\n\t}\n\treturn nil\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetCoreDnsEnabled() bool {\n\tif x != nil {\n\t\treturn x.CoreDnsEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetCoreDnsImage() string {\n\tif x != nil {\n\t\treturn x.CoreDnsImage\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetDnsServiceIp() string {\n\tif x != nil {\n\t\treturn x.DnsServiceIp\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetDnsServiceIPv6() string {\n\tif x != nil {\n\t\treturn x.DnsServiceIPv6\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelEnabled() bool {\n\tif x != nil {\n\t\treturn x.FlannelEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelImage() string {\n\tif x != nil {\n\t\treturn x.FlannelImage\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetPodSecurityPolicyEnabled() bool {\n\tif x != nil {\n\t\treturn x.PodSecurityPolicyEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetTalosApiServiceEnabled() bool {\n\tif x != nil {\n\t\treturn x.TalosApiServiceEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelExtraArgs() []string {\n\tif x != nil {\n\t\treturn x.FlannelExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelKubeServiceHost() string {\n\tif x != nil {\n\t\treturn x.FlannelKubeServiceHost\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelKubeServicePort() string {\n\tif x != nil {\n\t\treturn x.FlannelKubeServicePort\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelKubeNetworkPoliciesEnabled() bool {\n\tif x != nil {\n\t\treturn x.FlannelKubeNetworkPoliciesEnabled\n\t}\n\treturn false\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetFlannelKubeNetworkPoliciesImage() string {\n\tif x != nil {\n\t\treturn x.FlannelKubeNetworkPoliciesImage\n\t}\n\treturn \"\"\n}\n\nfunc (x *BootstrapManifestsConfigSpec) GetCniName() string {\n\tif x != nil {\n\t\treturn x.CniName\n\t}\n\treturn \"\"\n}\n\n// ConfigStatusSpec describes status of rendered secrets.\ntype ConfigStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady         bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConfigStatusSpec) Reset() {\n\t*x = ConfigStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigStatusSpec) ProtoMessage() {}\n\nfunc (x *ConfigStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *ConfigStatusSpec) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *ConfigStatusSpec) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\n// ControllerManagerConfigSpec is configuration for kube-controller-manager.\ntype ControllerManagerConfigSpec struct {\n\tstate                protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled              bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tImage                string                 `protobuf:\"bytes,2,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tCloudProvider        string                 `protobuf:\"bytes,3,opt,name=cloud_provider,json=cloudProvider,proto3\" json:\"cloud_provider,omitempty\"`\n\tPodCidRs             []string               `protobuf:\"bytes,4,rep,name=pod_cid_rs,json=podCidRs,proto3\" json:\"pod_cid_rs,omitempty\"`\n\tServiceCidRs         []string               `protobuf:\"bytes,5,rep,name=service_cid_rs,json=serviceCidRs,proto3\" json:\"service_cid_rs,omitempty\"`\n\tExtraArgs            map[string]*ArgValues  `protobuf:\"bytes,6,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tExtraVolumes         []*ExtraVolume         `protobuf:\"bytes,7,rep,name=extra_volumes,json=extraVolumes,proto3\" json:\"extra_volumes,omitempty\"`\n\tEnvironmentVariables map[string]string      `protobuf:\"bytes,8,rep,name=environment_variables,json=environmentVariables,proto3\" json:\"environment_variables,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tResources            *Resources             `protobuf:\"bytes,9,opt,name=resources,proto3\" json:\"resources,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *ControllerManagerConfigSpec) Reset() {\n\t*x = ControllerManagerConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ControllerManagerConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ControllerManagerConfigSpec) ProtoMessage() {}\n\nfunc (x *ControllerManagerConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ControllerManagerConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ControllerManagerConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *ControllerManagerConfigSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *ControllerManagerConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *ControllerManagerConfigSpec) GetCloudProvider() string {\n\tif x != nil {\n\t\treturn x.CloudProvider\n\t}\n\treturn \"\"\n}\n\nfunc (x *ControllerManagerConfigSpec) GetPodCidRs() []string {\n\tif x != nil {\n\t\treturn x.PodCidRs\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerManagerConfigSpec) GetServiceCidRs() []string {\n\tif x != nil {\n\t\treturn x.ServiceCidRs\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerManagerConfigSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerManagerConfigSpec) GetExtraVolumes() []*ExtraVolume {\n\tif x != nil {\n\t\treturn x.ExtraVolumes\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerManagerConfigSpec) GetEnvironmentVariables() map[string]string {\n\tif x != nil {\n\t\treturn x.EnvironmentVariables\n\t}\n\treturn nil\n}\n\nfunc (x *ControllerManagerConfigSpec) GetResources() *Resources {\n\tif x != nil {\n\t\treturn x.Resources\n\t}\n\treturn nil\n}\n\n// EndpointSpec describes a list of endpoints to connect to.\ntype EndpointSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddresses     []*common.NetIP        `protobuf:\"bytes,1,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tHosts         []string               `protobuf:\"bytes,2,rep,name=hosts,proto3\" json:\"hosts,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EndpointSpec) Reset() {\n\t*x = EndpointSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EndpointSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EndpointSpec) ProtoMessage() {}\n\nfunc (x *EndpointSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EndpointSpec.ProtoReflect.Descriptor instead.\nfunc (*EndpointSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *EndpointSpec) GetAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *EndpointSpec) GetHosts() []string {\n\tif x != nil {\n\t\treturn x.Hosts\n\t}\n\treturn nil\n}\n\n// ExtraManifest defines a single extra manifest to download.\ntype ExtraManifest struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tName           string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tUrl            string                 `protobuf:\"bytes,2,opt,name=url,proto3\" json:\"url,omitempty\"`\n\tPriority       string                 `protobuf:\"bytes,3,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tExtraHeaders   map[string]string      `protobuf:\"bytes,4,rep,name=extra_headers,json=extraHeaders,proto3\" json:\"extra_headers,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tInlineManifest string                 `protobuf:\"bytes,5,opt,name=inline_manifest,json=inlineManifest,proto3\" json:\"inline_manifest,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ExtraManifest) Reset() {\n\t*x = ExtraManifest{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtraManifest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtraManifest) ProtoMessage() {}\n\nfunc (x *ExtraManifest) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtraManifest.ProtoReflect.Descriptor instead.\nfunc (*ExtraManifest) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *ExtraManifest) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraManifest) GetUrl() string {\n\tif x != nil {\n\t\treturn x.Url\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraManifest) GetPriority() string {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraManifest) GetExtraHeaders() map[string]string {\n\tif x != nil {\n\t\treturn x.ExtraHeaders\n\t}\n\treturn nil\n}\n\nfunc (x *ExtraManifest) GetInlineManifest() string {\n\tif x != nil {\n\t\treturn x.InlineManifest\n\t}\n\treturn \"\"\n}\n\n// ExtraManifestsConfigSpec is configuration for extra bootstrap manifests.\ntype ExtraManifestsConfigSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tExtraManifests []*ExtraManifest       `protobuf:\"bytes,1,rep,name=extra_manifests,json=extraManifests,proto3\" json:\"extra_manifests,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *ExtraManifestsConfigSpec) Reset() {\n\t*x = ExtraManifestsConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtraManifestsConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtraManifestsConfigSpec) ProtoMessage() {}\n\nfunc (x *ExtraManifestsConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtraManifestsConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ExtraManifestsConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *ExtraManifestsConfigSpec) GetExtraManifests() []*ExtraManifest {\n\tif x != nil {\n\t\treturn x.ExtraManifests\n\t}\n\treturn nil\n}\n\n// ExtraVolume is a configuration of extra volume.\ntype ExtraVolume struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tHostPath      string                 `protobuf:\"bytes,2,opt,name=host_path,json=hostPath,proto3\" json:\"host_path,omitempty\"`\n\tMountPath     string                 `protobuf:\"bytes,3,opt,name=mount_path,json=mountPath,proto3\" json:\"mount_path,omitempty\"`\n\tReadOnly      bool                   `protobuf:\"varint,4,opt,name=read_only,json=readOnly,proto3\" json:\"read_only,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExtraVolume) Reset() {\n\t*x = ExtraVolume{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtraVolume) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtraVolume) ProtoMessage() {}\n\nfunc (x *ExtraVolume) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtraVolume.ProtoReflect.Descriptor instead.\nfunc (*ExtraVolume) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *ExtraVolume) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraVolume) GetHostPath() string {\n\tif x != nil {\n\t\treturn x.HostPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraVolume) GetMountPath() string {\n\tif x != nil {\n\t\treturn x.MountPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtraVolume) GetReadOnly() bool {\n\tif x != nil {\n\t\treturn x.ReadOnly\n\t}\n\treturn false\n}\n\n// KubePrismConfigSpec describes KubePrismConfig data.\ntype KubePrismConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHost          string                 `protobuf:\"bytes,1,opt,name=host,proto3\" json:\"host,omitempty\"`\n\tPort          int64                  `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n\tEndpoints     []*KubePrismEndpoint   `protobuf:\"bytes,3,rep,name=endpoints,proto3\" json:\"endpoints,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KubePrismConfigSpec) Reset() {\n\t*x = KubePrismConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubePrismConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubePrismConfigSpec) ProtoMessage() {}\n\nfunc (x *KubePrismConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubePrismConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*KubePrismConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *KubePrismConfigSpec) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubePrismConfigSpec) GetPort() int64 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\nfunc (x *KubePrismConfigSpec) GetEndpoints() []*KubePrismEndpoint {\n\tif x != nil {\n\t\treturn x.Endpoints\n\t}\n\treturn nil\n}\n\n// KubePrismEndpoint holds data for control plane endpoint.\ntype KubePrismEndpoint struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHost          string                 `protobuf:\"bytes,1,opt,name=host,proto3\" json:\"host,omitempty\"`\n\tPort          uint32                 `protobuf:\"varint,2,opt,name=port,proto3\" json:\"port,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KubePrismEndpoint) Reset() {\n\t*x = KubePrismEndpoint{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[15]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubePrismEndpoint) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubePrismEndpoint) ProtoMessage() {}\n\nfunc (x *KubePrismEndpoint) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[15]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubePrismEndpoint.ProtoReflect.Descriptor instead.\nfunc (*KubePrismEndpoint) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *KubePrismEndpoint) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubePrismEndpoint) GetPort() uint32 {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn 0\n}\n\n// KubePrismEndpointsSpec describes KubePrismEndpoints configuration.\ntype KubePrismEndpointsSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEndpoints     []*KubePrismEndpoint   `protobuf:\"bytes,1,rep,name=endpoints,proto3\" json:\"endpoints,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KubePrismEndpointsSpec) Reset() {\n\t*x = KubePrismEndpointsSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[16]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubePrismEndpointsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubePrismEndpointsSpec) ProtoMessage() {}\n\nfunc (x *KubePrismEndpointsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[16]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubePrismEndpointsSpec.ProtoReflect.Descriptor instead.\nfunc (*KubePrismEndpointsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *KubePrismEndpointsSpec) GetEndpoints() []*KubePrismEndpoint {\n\tif x != nil {\n\t\treturn x.Endpoints\n\t}\n\treturn nil\n}\n\n// KubePrismStatusesSpec describes KubePrismStatuses data.\ntype KubePrismStatusesSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHost          string                 `protobuf:\"bytes,1,opt,name=host,proto3\" json:\"host,omitempty\"`\n\tHealthy       bool                   `protobuf:\"varint,2,opt,name=healthy,proto3\" json:\"healthy,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KubePrismStatusesSpec) Reset() {\n\t*x = KubePrismStatusesSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubePrismStatusesSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubePrismStatusesSpec) ProtoMessage() {}\n\nfunc (x *KubePrismStatusesSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[17]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubePrismStatusesSpec.ProtoReflect.Descriptor instead.\nfunc (*KubePrismStatusesSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *KubePrismStatusesSpec) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubePrismStatusesSpec) GetHealthy() bool {\n\tif x != nil {\n\t\treturn x.Healthy\n\t}\n\treturn false\n}\n\n// KubeletConfigSpec holds the source of kubelet configuration.\ntype KubeletConfigSpec struct {\n\tstate                         protoimpl.MessageState `protogen:\"open.v1\"`\n\tImage                         string                 `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tClusterDns                    []string               `protobuf:\"bytes,2,rep,name=cluster_dns,json=clusterDns,proto3\" json:\"cluster_dns,omitempty\"`\n\tClusterDomain                 string                 `protobuf:\"bytes,3,opt,name=cluster_domain,json=clusterDomain,proto3\" json:\"cluster_domain,omitempty\"`\n\tExtraArgs                     map[string]*ArgValues  `protobuf:\"bytes,4,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tExtraMounts                   []*proto.Mount         `protobuf:\"bytes,5,rep,name=extra_mounts,json=extraMounts,proto3\" json:\"extra_mounts,omitempty\"`\n\tExtraConfig                   *structpb.Struct       `protobuf:\"bytes,6,opt,name=extra_config,json=extraConfig,proto3\" json:\"extra_config,omitempty\"`\n\tCloudProviderExternal         bool                   `protobuf:\"varint,7,opt,name=cloud_provider_external,json=cloudProviderExternal,proto3\" json:\"cloud_provider_external,omitempty\"`\n\tDefaultRuntimeSeccompEnabled  bool                   `protobuf:\"varint,8,opt,name=default_runtime_seccomp_enabled,json=defaultRuntimeSeccompEnabled,proto3\" json:\"default_runtime_seccomp_enabled,omitempty\"`\n\tSkipNodeRegistration          bool                   `protobuf:\"varint,9,opt,name=skip_node_registration,json=skipNodeRegistration,proto3\" json:\"skip_node_registration,omitempty\"`\n\tStaticPodListUrl              string                 `protobuf:\"bytes,10,opt,name=static_pod_list_url,json=staticPodListUrl,proto3\" json:\"static_pod_list_url,omitempty\"`\n\tDisableManifestsDirectory     bool                   `protobuf:\"varint,11,opt,name=disable_manifests_directory,json=disableManifestsDirectory,proto3\" json:\"disable_manifests_directory,omitempty\"`\n\tEnableFsQuotaMonitoring       bool                   `protobuf:\"varint,12,opt,name=enable_fs_quota_monitoring,json=enableFsQuotaMonitoring,proto3\" json:\"enable_fs_quota_monitoring,omitempty\"`\n\tCredentialProviderConfig      *structpb.Struct       `protobuf:\"bytes,13,opt,name=credential_provider_config,json=credentialProviderConfig,proto3\" json:\"credential_provider_config,omitempty\"`\n\tAllowSchedulingOnControlPlane bool                   `protobuf:\"varint,14,opt,name=allow_scheduling_on_control_plane,json=allowSchedulingOnControlPlane,proto3\" json:\"allow_scheduling_on_control_plane,omitempty\"`\n\tunknownFields                 protoimpl.UnknownFields\n\tsizeCache                     protoimpl.SizeCache\n}\n\nfunc (x *KubeletConfigSpec) Reset() {\n\t*x = KubeletConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubeletConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubeletConfigSpec) ProtoMessage() {}\n\nfunc (x *KubeletConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[18]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubeletConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*KubeletConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *KubeletConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletConfigSpec) GetClusterDns() []string {\n\tif x != nil {\n\t\treturn x.ClusterDns\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletConfigSpec) GetClusterDomain() string {\n\tif x != nil {\n\t\treturn x.ClusterDomain\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletConfigSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletConfigSpec) GetExtraMounts() []*proto.Mount {\n\tif x != nil {\n\t\treturn x.ExtraMounts\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletConfigSpec) GetExtraConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.ExtraConfig\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletConfigSpec) GetCloudProviderExternal() bool {\n\tif x != nil {\n\t\treturn x.CloudProviderExternal\n\t}\n\treturn false\n}\n\nfunc (x *KubeletConfigSpec) GetDefaultRuntimeSeccompEnabled() bool {\n\tif x != nil {\n\t\treturn x.DefaultRuntimeSeccompEnabled\n\t}\n\treturn false\n}\n\nfunc (x *KubeletConfigSpec) GetSkipNodeRegistration() bool {\n\tif x != nil {\n\t\treturn x.SkipNodeRegistration\n\t}\n\treturn false\n}\n\nfunc (x *KubeletConfigSpec) GetStaticPodListUrl() string {\n\tif x != nil {\n\t\treturn x.StaticPodListUrl\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletConfigSpec) GetDisableManifestsDirectory() bool {\n\tif x != nil {\n\t\treturn x.DisableManifestsDirectory\n\t}\n\treturn false\n}\n\nfunc (x *KubeletConfigSpec) GetEnableFsQuotaMonitoring() bool {\n\tif x != nil {\n\t\treturn x.EnableFsQuotaMonitoring\n\t}\n\treturn false\n}\n\nfunc (x *KubeletConfigSpec) GetCredentialProviderConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.CredentialProviderConfig\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletConfigSpec) GetAllowSchedulingOnControlPlane() bool {\n\tif x != nil {\n\t\treturn x.AllowSchedulingOnControlPlane\n\t}\n\treturn false\n}\n\n// KubeletSpecSpec holds the source of kubelet configuration.\ntype KubeletSpecSpec struct {\n\tstate                    protoimpl.MessageState `protogen:\"open.v1\"`\n\tImage                    string                 `protobuf:\"bytes,1,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tArgs                     []string               `protobuf:\"bytes,2,rep,name=args,proto3\" json:\"args,omitempty\"`\n\tExtraMounts              []*proto.Mount         `protobuf:\"bytes,3,rep,name=extra_mounts,json=extraMounts,proto3\" json:\"extra_mounts,omitempty\"`\n\tExpectedNodename         string                 `protobuf:\"bytes,4,opt,name=expected_nodename,json=expectedNodename,proto3\" json:\"expected_nodename,omitempty\"`\n\tConfig                   *structpb.Struct       `protobuf:\"bytes,5,opt,name=config,proto3\" json:\"config,omitempty\"`\n\tCredentialProviderConfig *structpb.Struct       `protobuf:\"bytes,6,opt,name=credential_provider_config,json=credentialProviderConfig,proto3\" json:\"credential_provider_config,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *KubeletSpecSpec) Reset() {\n\t*x = KubeletSpecSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubeletSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubeletSpecSpec) ProtoMessage() {}\n\nfunc (x *KubeletSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[19]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubeletSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*KubeletSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *KubeletSpecSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletSpecSpec) GetArgs() []string {\n\tif x != nil {\n\t\treturn x.Args\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletSpecSpec) GetExtraMounts() []*proto.Mount {\n\tif x != nil {\n\t\treturn x.ExtraMounts\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletSpecSpec) GetExpectedNodename() string {\n\tif x != nil {\n\t\treturn x.ExpectedNodename\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletSpecSpec) GetConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Config\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletSpecSpec) GetCredentialProviderConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.CredentialProviderConfig\n\t}\n\treturn nil\n}\n\n// ManifestSpec holds the Kubernetes resources spec.\ntype ManifestSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tItems         []*SingleManifest      `protobuf:\"bytes,1,rep,name=items,proto3\" json:\"items,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ManifestSpec) Reset() {\n\t*x = ManifestSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ManifestSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ManifestSpec) ProtoMessage() {}\n\nfunc (x *ManifestSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[20]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ManifestSpec.ProtoReflect.Descriptor instead.\nfunc (*ManifestSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *ManifestSpec) GetItems() []*SingleManifest {\n\tif x != nil {\n\t\treturn x.Items\n\t}\n\treturn nil\n}\n\n// ManifestStatusSpec describes manifest application status.\ntype ManifestStatusSpec struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tManifestsApplied []string               `protobuf:\"bytes,1,rep,name=manifests_applied,json=manifestsApplied,proto3\" json:\"manifests_applied,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ManifestStatusSpec) Reset() {\n\t*x = ManifestStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ManifestStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ManifestStatusSpec) ProtoMessage() {}\n\nfunc (x *ManifestStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[21]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ManifestStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ManifestStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *ManifestStatusSpec) GetManifestsApplied() []string {\n\tif x != nil {\n\t\treturn x.ManifestsApplied\n\t}\n\treturn nil\n}\n\n// NodeAnnotationSpecSpec represents an annoation that's attached to a Talos node.\ntype NodeAnnotationSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           string                 `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue         string                 `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeAnnotationSpecSpec) Reset() {\n\t*x = NodeAnnotationSpecSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeAnnotationSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeAnnotationSpecSpec) ProtoMessage() {}\n\nfunc (x *NodeAnnotationSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[22]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeAnnotationSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeAnnotationSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *NodeAnnotationSpecSpec) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodeAnnotationSpecSpec) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// NodeIPConfigSpec holds the Node IP specification.\ntype NodeIPConfigSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tValidSubnets   []string               `protobuf:\"bytes,1,rep,name=valid_subnets,json=validSubnets,proto3\" json:\"valid_subnets,omitempty\"`\n\tExcludeSubnets []string               `protobuf:\"bytes,2,rep,name=exclude_subnets,json=excludeSubnets,proto3\" json:\"exclude_subnets,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *NodeIPConfigSpec) Reset() {\n\t*x = NodeIPConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeIPConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeIPConfigSpec) ProtoMessage() {}\n\nfunc (x *NodeIPConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[23]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeIPConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeIPConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *NodeIPConfigSpec) GetValidSubnets() []string {\n\tif x != nil {\n\t\treturn x.ValidSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *NodeIPConfigSpec) GetExcludeSubnets() []string {\n\tif x != nil {\n\t\treturn x.ExcludeSubnets\n\t}\n\treturn nil\n}\n\n// NodeIPSpec holds the Node IP specification.\ntype NodeIPSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddresses     []*common.NetIP        `protobuf:\"bytes,1,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeIPSpec) Reset() {\n\t*x = NodeIPSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[24]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeIPSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeIPSpec) ProtoMessage() {}\n\nfunc (x *NodeIPSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[24]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeIPSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeIPSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *NodeIPSpec) GetAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\n// NodeLabelSpecSpec represents a label that's attached to a Talos node.\ntype NodeLabelSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           string                 `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue         string                 `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeLabelSpecSpec) Reset() {\n\t*x = NodeLabelSpecSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[25]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeLabelSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeLabelSpecSpec) ProtoMessage() {}\n\nfunc (x *NodeLabelSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[25]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeLabelSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeLabelSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *NodeLabelSpecSpec) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodeLabelSpecSpec) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// NodeStatusSpec describes Kubernetes NodeStatus.\ntype NodeStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodename      string                 `protobuf:\"bytes,1,opt,name=nodename,proto3\" json:\"nodename,omitempty\"`\n\tNodeReady     bool                   `protobuf:\"varint,2,opt,name=node_ready,json=nodeReady,proto3\" json:\"node_ready,omitempty\"`\n\tUnschedulable bool                   `protobuf:\"varint,3,opt,name=unschedulable,proto3\" json:\"unschedulable,omitempty\"`\n\tLabels        map[string]string      `protobuf:\"bytes,4,rep,name=labels,proto3\" json:\"labels,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tAnnotations   map[string]string      `protobuf:\"bytes,5,rep,name=annotations,proto3\" json:\"annotations,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tPodCidRs      []*common.NetIPPrefix  `protobuf:\"bytes,6,rep,name=pod_cid_rs,json=podCidRs,proto3\" json:\"pod_cid_rs,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeStatusSpec) Reset() {\n\t*x = NodeStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[26]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeStatusSpec) ProtoMessage() {}\n\nfunc (x *NodeStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[26]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{26}\n}\n\nfunc (x *NodeStatusSpec) GetNodename() string {\n\tif x != nil {\n\t\treturn x.Nodename\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodeStatusSpec) GetNodeReady() bool {\n\tif x != nil {\n\t\treturn x.NodeReady\n\t}\n\treturn false\n}\n\nfunc (x *NodeStatusSpec) GetUnschedulable() bool {\n\tif x != nil {\n\t\treturn x.Unschedulable\n\t}\n\treturn false\n}\n\nfunc (x *NodeStatusSpec) GetLabels() map[string]string {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (x *NodeStatusSpec) GetAnnotations() map[string]string {\n\tif x != nil {\n\t\treturn x.Annotations\n\t}\n\treturn nil\n}\n\nfunc (x *NodeStatusSpec) GetPodCidRs() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.PodCidRs\n\t}\n\treturn nil\n}\n\n// NodeTaintSpecSpec represents a label that's attached to a Talos node.\ntype NodeTaintSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tKey           string                 `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tEffect        string                 `protobuf:\"bytes,2,opt,name=effect,proto3\" json:\"effect,omitempty\"`\n\tValue         string                 `protobuf:\"bytes,3,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeTaintSpecSpec) Reset() {\n\t*x = NodeTaintSpecSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[27]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeTaintSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeTaintSpecSpec) ProtoMessage() {}\n\nfunc (x *NodeTaintSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[27]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeTaintSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeTaintSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{27}\n}\n\nfunc (x *NodeTaintSpecSpec) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodeTaintSpecSpec) GetEffect() string {\n\tif x != nil {\n\t\treturn x.Effect\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodeTaintSpecSpec) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// NodenameSpec describes Kubernetes nodename.\ntype NodenameSpec struct {\n\tstate                protoimpl.MessageState `protogen:\"open.v1\"`\n\tNodename             string                 `protobuf:\"bytes,1,opt,name=nodename,proto3\" json:\"nodename,omitempty\"`\n\tHostnameVersion      string                 `protobuf:\"bytes,2,opt,name=hostname_version,json=hostnameVersion,proto3\" json:\"hostname_version,omitempty\"`\n\tSkipNodeRegistration bool                   `protobuf:\"varint,3,opt,name=skip_node_registration,json=skipNodeRegistration,proto3\" json:\"skip_node_registration,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *NodenameSpec) Reset() {\n\t*x = NodenameSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[28]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodenameSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodenameSpec) ProtoMessage() {}\n\nfunc (x *NodenameSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[28]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodenameSpec.ProtoReflect.Descriptor instead.\nfunc (*NodenameSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{28}\n}\n\nfunc (x *NodenameSpec) GetNodename() string {\n\tif x != nil {\n\t\treturn x.Nodename\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodenameSpec) GetHostnameVersion() string {\n\tif x != nil {\n\t\treturn x.HostnameVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *NodenameSpec) GetSkipNodeRegistration() bool {\n\tif x != nil {\n\t\treturn x.SkipNodeRegistration\n\t}\n\treturn false\n}\n\n// Resources is a configuration of cpu and memory resources.\ntype Resources struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRequests      map[string]string      `protobuf:\"bytes,1,rep,name=requests,proto3\" json:\"requests,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tLimits        map[string]string      `protobuf:\"bytes,2,rep,name=limits,proto3\" json:\"limits,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Resources) Reset() {\n\t*x = Resources{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[29]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Resources) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Resources) ProtoMessage() {}\n\nfunc (x *Resources) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[29]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Resources.ProtoReflect.Descriptor instead.\nfunc (*Resources) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{29}\n}\n\nfunc (x *Resources) GetRequests() map[string]string {\n\tif x != nil {\n\t\treturn x.Requests\n\t}\n\treturn nil\n}\n\nfunc (x *Resources) GetLimits() map[string]string {\n\tif x != nil {\n\t\treturn x.Limits\n\t}\n\treturn nil\n}\n\n// SchedulerConfigSpec is configuration for kube-scheduler.\ntype SchedulerConfigSpec struct {\n\tstate                protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled              bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tImage                string                 `protobuf:\"bytes,2,opt,name=image,proto3\" json:\"image,omitempty\"`\n\tExtraArgs            map[string]*ArgValues  `protobuf:\"bytes,3,rep,name=extra_args,json=extraArgs,proto3\" json:\"extra_args,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tExtraVolumes         []*ExtraVolume         `protobuf:\"bytes,4,rep,name=extra_volumes,json=extraVolumes,proto3\" json:\"extra_volumes,omitempty\"`\n\tEnvironmentVariables map[string]string      `protobuf:\"bytes,5,rep,name=environment_variables,json=environmentVariables,proto3\" json:\"environment_variables,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tResources            *Resources             `protobuf:\"bytes,6,opt,name=resources,proto3\" json:\"resources,omitempty\"`\n\tConfig               *structpb.Struct       `protobuf:\"bytes,7,opt,name=config,proto3\" json:\"config,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *SchedulerConfigSpec) Reset() {\n\t*x = SchedulerConfigSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[30]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SchedulerConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SchedulerConfigSpec) ProtoMessage() {}\n\nfunc (x *SchedulerConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[30]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SchedulerConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*SchedulerConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{30}\n}\n\nfunc (x *SchedulerConfigSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *SchedulerConfigSpec) GetImage() string {\n\tif x != nil {\n\t\treturn x.Image\n\t}\n\treturn \"\"\n}\n\nfunc (x *SchedulerConfigSpec) GetExtraArgs() map[string]*ArgValues {\n\tif x != nil {\n\t\treturn x.ExtraArgs\n\t}\n\treturn nil\n}\n\nfunc (x *SchedulerConfigSpec) GetExtraVolumes() []*ExtraVolume {\n\tif x != nil {\n\t\treturn x.ExtraVolumes\n\t}\n\treturn nil\n}\n\nfunc (x *SchedulerConfigSpec) GetEnvironmentVariables() map[string]string {\n\tif x != nil {\n\t\treturn x.EnvironmentVariables\n\t}\n\treturn nil\n}\n\nfunc (x *SchedulerConfigSpec) GetResources() *Resources {\n\tif x != nil {\n\t\treturn x.Resources\n\t}\n\treturn nil\n}\n\nfunc (x *SchedulerConfigSpec) GetConfig() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Config\n\t}\n\treturn nil\n}\n\n// SecretsStatusSpec describes status of rendered secrets.\ntype SecretsStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady         bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SecretsStatusSpec) Reset() {\n\t*x = SecretsStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[31]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SecretsStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SecretsStatusSpec) ProtoMessage() {}\n\nfunc (x *SecretsStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[31]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SecretsStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*SecretsStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{31}\n}\n\nfunc (x *SecretsStatusSpec) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *SecretsStatusSpec) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\n// SingleManifest is a single manifest.\ntype SingleManifest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tObject        *structpb.Struct       `protobuf:\"bytes,1,opt,name=object,proto3\" json:\"object,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SingleManifest) Reset() {\n\t*x = SingleManifest{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[32]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SingleManifest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SingleManifest) ProtoMessage() {}\n\nfunc (x *SingleManifest) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[32]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SingleManifest.ProtoReflect.Descriptor instead.\nfunc (*SingleManifest) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{32}\n}\n\nfunc (x *SingleManifest) GetObject() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Object\n\t}\n\treturn nil\n}\n\n// StaticPodServerStatusSpec describes static pod spec, it contains marshaled *v1.Pod spec.\ntype StaticPodServerStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tUrl           string                 `protobuf:\"bytes,1,opt,name=url,proto3\" json:\"url,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StaticPodServerStatusSpec) Reset() {\n\t*x = StaticPodServerStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[33]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StaticPodServerStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StaticPodServerStatusSpec) ProtoMessage() {}\n\nfunc (x *StaticPodServerStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[33]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StaticPodServerStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*StaticPodServerStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{33}\n}\n\nfunc (x *StaticPodServerStatusSpec) GetUrl() string {\n\tif x != nil {\n\t\treturn x.Url\n\t}\n\treturn \"\"\n}\n\n// StaticPodSpec describes static pod spec, it contains marshaled *v1.Pod spec.\ntype StaticPodSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPod           *structpb.Struct       `protobuf:\"bytes,1,opt,name=pod,proto3\" json:\"pod,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StaticPodSpec) Reset() {\n\t*x = StaticPodSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[34]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StaticPodSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StaticPodSpec) ProtoMessage() {}\n\nfunc (x *StaticPodSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[34]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StaticPodSpec.ProtoReflect.Descriptor instead.\nfunc (*StaticPodSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{34}\n}\n\nfunc (x *StaticPodSpec) GetPod() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.Pod\n\t}\n\treturn nil\n}\n\n// StaticPodStatusSpec describes kubelet static pod status.\ntype StaticPodStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPodStatus     *structpb.Struct       `protobuf:\"bytes,1,opt,name=pod_status,json=podStatus,proto3\" json:\"pod_status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StaticPodStatusSpec) Reset() {\n\t*x = StaticPodStatusSpec{}\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[35]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StaticPodStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StaticPodStatusSpec) ProtoMessage() {}\n\nfunc (x *StaticPodStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_k8s_k8s_proto_msgTypes[35]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StaticPodStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*StaticPodStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescGZIP(), []int{35}\n}\n\nfunc (x *StaticPodStatusSpec) GetPodStatus() *structpb.Struct {\n\tif x != nil {\n\t\treturn x.PodStatus\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_k8s_k8s_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_k8s_k8s_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\\"resource/definitions/k8s/k8s.proto\\x12\\x1etalos.resource.definitions.k8s\\x1a\\x13common/common.proto\\x1a\\x1cgoogle/protobuf/struct.proto\\x1a&resource/definitions/proto/proto.proto\\\"\\xd4\\x06\\n\" +\n\t\"\\x13APIServerConfigSpec\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12%\\n\" +\n\t\"\\x0ecloud_provider\\x18\\x02 \\x01(\\tR\\rcloudProvider\\x124\\n\" +\n\t\"\\x16control_plane_endpoint\\x18\\x03 \\x01(\\tR\\x14controlPlaneEndpoint\\x12!\\n\" +\n\t\"\\fetcd_servers\\x18\\x04 \\x03(\\tR\\vetcdServers\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"local_port\\x18\\x05 \\x01(\\x03R\\tlocalPort\\x12$\\n\" +\n\t\"\\x0eservice_cid_rs\\x18\\x06 \\x03(\\tR\\fserviceCidRs\\x12a\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\a \\x03(\\v2B.talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntryR\\textraArgs\\x12P\\n\" +\n\t\"\\rextra_volumes\\x18\\b \\x03(\\v2+.talos.resource.definitions.k8s.ExtraVolumeR\\fextraVolumes\\x12\\x82\\x01\\n\" +\n\t\"\\x15environment_variables\\x18\\t \\x03(\\v2M.talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntryR\\x14environmentVariables\\x12-\\n\" +\n\t\"\\x12advertised_address\\x18\\v \\x01(\\tR\\x11advertisedAddress\\x12G\\n\" +\n\t\"\\tresources\\x18\\f \\x01(\\v2).talos.resource.definitions.k8s.ResourcesR\\tresources\\x1ag\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12?\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2).talos.resource.definitions.k8s.ArgValuesR\\x05value:\\x028\\x01\\x1aG\\n\" +\n\t\"\\x19EnvironmentVariablesEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"i\\n\" +\n\t\"\\x1aAdmissionControlConfigSpec\\x12K\\n\" +\n\t\"\\x06config\\x18\\x01 \\x03(\\v23.talos.resource.definitions.k8s.AdmissionPluginSpecR\\x06config\\\"h\\n\" +\n\t\"\\x13AdmissionPluginSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12=\\n\" +\n\t\"\\rconfiguration\\x18\\x02 \\x01(\\v2\\x17.google.protobuf.StructR\\rconfiguration\\\"#\\n\" +\n\t\"\\tArgValues\\x12\\x16\\n\" +\n\t\"\\x06values\\x18\\x01 \\x03(\\tR\\x06values\\\"H\\n\" +\n\t\"\\x15AuditPolicyConfigSpec\\x12/\\n\" +\n\t\"\\x06config\\x18\\x01 \\x01(\\v2\\x17.google.protobuf.StructR\\x06config\\\"y\\n\" +\n\t\"\\x1cAuthorizationAuthorizersSpec\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\tR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x121\\n\" +\n\t\"\\awebhook\\x18\\x03 \\x01(\\v2\\x17.google.protobuf.StructR\\awebhook\\\"\\x85\\x01\\n\" +\n\t\"\\x17AuthorizationConfigSpec\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12T\\n\" +\n\t\"\\x06config\\x18\\x02 \\x03(\\v2<.talos.resource.definitions.k8s.AuthorizationAuthorizersSpecR\\x06config\\\"\\xa8\\a\\n\" +\n\t\"\\x1cBootstrapManifestsConfigSpec\\x12\\x16\\n\" +\n\t\"\\x06server\\x18\\x01 \\x01(\\tR\\x06server\\x12%\\n\" +\n\t\"\\x0ecluster_domain\\x18\\x02 \\x01(\\tR\\rclusterDomain\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"pod_cid_rs\\x18\\x03 \\x03(\\tR\\bpodCidRs\\x12#\\n\" +\n\t\"\\rproxy_enabled\\x18\\x04 \\x01(\\bR\\fproxyEnabled\\x12\\x1f\\n\" +\n\t\"\\vproxy_image\\x18\\x05 \\x01(\\tR\\n\" +\n\t\"proxyImage\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"proxy_args\\x18\\x06 \\x03(\\tR\\tproxyArgs\\x12(\\n\" +\n\t\"\\x10core_dns_enabled\\x18\\a \\x01(\\bR\\x0ecoreDnsEnabled\\x12$\\n\" +\n\t\"\\x0ecore_dns_image\\x18\\b \\x01(\\tR\\fcoreDnsImage\\x12$\\n\" +\n\t\"\\x0edns_service_ip\\x18\\t \\x01(\\tR\\fdnsServiceIp\\x12)\\n\" +\n\t\"\\x11dns_service_i_pv6\\x18\\n\" +\n\t\" \\x01(\\tR\\x0ednsServiceIPv6\\x12'\\n\" +\n\t\"\\x0fflannel_enabled\\x18\\v \\x01(\\bR\\x0eflannelEnabled\\x12#\\n\" +\n\t\"\\rflannel_image\\x18\\f \\x01(\\tR\\fflannelImage\\x12=\\n\" +\n\t\"\\x1bpod_security_policy_enabled\\x18\\x0e \\x01(\\bR\\x18podSecurityPolicyEnabled\\x129\\n\" +\n\t\"\\x19talos_api_service_enabled\\x18\\x0f \\x01(\\bR\\x16talosApiServiceEnabled\\x12,\\n\" +\n\t\"\\x12flannel_extra_args\\x18\\x10 \\x03(\\tR\\x10flannelExtraArgs\\x129\\n\" +\n\t\"\\x19flannel_kube_service_host\\x18\\x11 \\x01(\\tR\\x16flannelKubeServiceHost\\x129\\n\" +\n\t\"\\x19flannel_kube_service_port\\x18\\x12 \\x01(\\tR\\x16flannelKubeServicePort\\x12P\\n\" +\n\t\"%flannel_kube_network_policies_enabled\\x18\\x13 \\x01(\\bR!flannelKubeNetworkPoliciesEnabled\\x12L\\n\" +\n\t\"#flannel_kube_network_policies_image\\x18\\x14 \\x01(\\tR\\x1fflannelKubeNetworkPoliciesImage\\x12\\x19\\n\" +\n\t\"\\bcni_name\\x18\\x15 \\x01(\\tR\\acniName\\\"B\\n\" +\n\t\"\\x10ConfigStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\tR\\aversion\\\"\\xfd\\x05\\n\" +\n\t\"\\x1bControllerManagerConfigSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x02 \\x01(\\tR\\x05image\\x12%\\n\" +\n\t\"\\x0ecloud_provider\\x18\\x03 \\x01(\\tR\\rcloudProvider\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"pod_cid_rs\\x18\\x04 \\x03(\\tR\\bpodCidRs\\x12$\\n\" +\n\t\"\\x0eservice_cid_rs\\x18\\x05 \\x03(\\tR\\fserviceCidRs\\x12i\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\x06 \\x03(\\v2J.talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntryR\\textraArgs\\x12P\\n\" +\n\t\"\\rextra_volumes\\x18\\a \\x03(\\v2+.talos.resource.definitions.k8s.ExtraVolumeR\\fextraVolumes\\x12\\x8a\\x01\\n\" +\n\t\"\\x15environment_variables\\x18\\b \\x03(\\v2U.talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntryR\\x14environmentVariables\\x12G\\n\" +\n\t\"\\tresources\\x18\\t \\x01(\\v2).talos.resource.definitions.k8s.ResourcesR\\tresources\\x1ag\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12?\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2).talos.resource.definitions.k8s.ArgValuesR\\x05value:\\x028\\x01\\x1aG\\n\" +\n\t\"\\x19EnvironmentVariablesEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"Q\\n\" +\n\t\"\\fEndpointSpec\\x12+\\n\" +\n\t\"\\taddresses\\x18\\x01 \\x03(\\v2\\r.common.NetIPR\\taddresses\\x12\\x14\\n\" +\n\t\"\\x05hosts\\x18\\x02 \\x03(\\tR\\x05hosts\\\"\\xa1\\x02\\n\" +\n\t\"\\rExtraManifest\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x10\\n\" +\n\t\"\\x03url\\x18\\x02 \\x01(\\tR\\x03url\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\x03 \\x01(\\tR\\bpriority\\x12d\\n\" +\n\t\"\\rextra_headers\\x18\\x04 \\x03(\\v2?.talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntryR\\fextraHeaders\\x12'\\n\" +\n\t\"\\x0finline_manifest\\x18\\x05 \\x01(\\tR\\x0einlineManifest\\x1a?\\n\" +\n\t\"\\x11ExtraHeadersEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"r\\n\" +\n\t\"\\x18ExtraManifestsConfigSpec\\x12V\\n\" +\n\t\"\\x0fextra_manifests\\x18\\x01 \\x03(\\v2-.talos.resource.definitions.k8s.ExtraManifestR\\x0eextraManifests\\\"z\\n\" +\n\t\"\\vExtraVolume\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x1b\\n\" +\n\t\"\\thost_path\\x18\\x02 \\x01(\\tR\\bhostPath\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"mount_path\\x18\\x03 \\x01(\\tR\\tmountPath\\x12\\x1b\\n\" +\n\t\"\\tread_only\\x18\\x04 \\x01(\\bR\\breadOnly\\\"\\x8e\\x01\\n\" +\n\t\"\\x13KubePrismConfigSpec\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x01 \\x01(\\tR\\x04host\\x12\\x12\\n\" +\n\t\"\\x04port\\x18\\x02 \\x01(\\x03R\\x04port\\x12O\\n\" +\n\t\"\\tendpoints\\x18\\x03 \\x03(\\v21.talos.resource.definitions.k8s.KubePrismEndpointR\\tendpoints\\\";\\n\" +\n\t\"\\x11KubePrismEndpoint\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x01 \\x01(\\tR\\x04host\\x12\\x12\\n\" +\n\t\"\\x04port\\x18\\x02 \\x01(\\rR\\x04port\\\"i\\n\" +\n\t\"\\x16KubePrismEndpointsSpec\\x12O\\n\" +\n\t\"\\tendpoints\\x18\\x01 \\x03(\\v21.talos.resource.definitions.k8s.KubePrismEndpointR\\tendpoints\\\"E\\n\" +\n\t\"\\x15KubePrismStatusesSpec\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x01 \\x01(\\tR\\x04host\\x12\\x18\\n\" +\n\t\"\\ahealthy\\x18\\x02 \\x01(\\bR\\ahealthy\\\"\\xc5\\a\\n\" +\n\t\"\\x11KubeletConfigSpec\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12\\x1f\\n\" +\n\t\"\\vcluster_dns\\x18\\x02 \\x03(\\tR\\n\" +\n\t\"clusterDns\\x12%\\n\" +\n\t\"\\x0ecluster_domain\\x18\\x03 \\x01(\\tR\\rclusterDomain\\x12_\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\x04 \\x03(\\v2@.talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntryR\\textraArgs\\x12J\\n\" +\n\t\"\\fextra_mounts\\x18\\x05 \\x03(\\v2'.talos.resource.definitions.proto.MountR\\vextraMounts\\x12:\\n\" +\n\t\"\\fextra_config\\x18\\x06 \\x01(\\v2\\x17.google.protobuf.StructR\\vextraConfig\\x126\\n\" +\n\t\"\\x17cloud_provider_external\\x18\\a \\x01(\\bR\\x15cloudProviderExternal\\x12E\\n\" +\n\t\"\\x1fdefault_runtime_seccomp_enabled\\x18\\b \\x01(\\bR\\x1cdefaultRuntimeSeccompEnabled\\x124\\n\" +\n\t\"\\x16skip_node_registration\\x18\\t \\x01(\\bR\\x14skipNodeRegistration\\x12-\\n\" +\n\t\"\\x13static_pod_list_url\\x18\\n\" +\n\t\" \\x01(\\tR\\x10staticPodListUrl\\x12>\\n\" +\n\t\"\\x1bdisable_manifests_directory\\x18\\v \\x01(\\bR\\x19disableManifestsDirectory\\x12;\\n\" +\n\t\"\\x1aenable_fs_quota_monitoring\\x18\\f \\x01(\\bR\\x17enableFsQuotaMonitoring\\x12U\\n\" +\n\t\"\\x1acredential_provider_config\\x18\\r \\x01(\\v2\\x17.google.protobuf.StructR\\x18credentialProviderConfig\\x12H\\n\" +\n\t\"!allow_scheduling_on_control_plane\\x18\\x0e \\x01(\\bR\\x1dallowSchedulingOnControlPlane\\x1ag\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12?\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2).talos.resource.definitions.k8s.ArgValuesR\\x05value:\\x028\\x01\\\"\\xbc\\x02\\n\" +\n\t\"\\x0fKubeletSpecSpec\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x01 \\x01(\\tR\\x05image\\x12\\x12\\n\" +\n\t\"\\x04args\\x18\\x02 \\x03(\\tR\\x04args\\x12J\\n\" +\n\t\"\\fextra_mounts\\x18\\x03 \\x03(\\v2'.talos.resource.definitions.proto.MountR\\vextraMounts\\x12+\\n\" +\n\t\"\\x11expected_nodename\\x18\\x04 \\x01(\\tR\\x10expectedNodename\\x12/\\n\" +\n\t\"\\x06config\\x18\\x05 \\x01(\\v2\\x17.google.protobuf.StructR\\x06config\\x12U\\n\" +\n\t\"\\x1acredential_provider_config\\x18\\x06 \\x01(\\v2\\x17.google.protobuf.StructR\\x18credentialProviderConfig\\\"T\\n\" +\n\t\"\\fManifestSpec\\x12D\\n\" +\n\t\"\\x05items\\x18\\x01 \\x03(\\v2..talos.resource.definitions.k8s.SingleManifestR\\x05items\\\"A\\n\" +\n\t\"\\x12ManifestStatusSpec\\x12+\\n\" +\n\t\"\\x11manifests_applied\\x18\\x01 \\x03(\\tR\\x10manifestsApplied\\\"@\\n\" +\n\t\"\\x16NodeAnnotationSpecSpec\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value\\\"`\\n\" +\n\t\"\\x10NodeIPConfigSpec\\x12#\\n\" +\n\t\"\\rvalid_subnets\\x18\\x01 \\x03(\\tR\\fvalidSubnets\\x12'\\n\" +\n\t\"\\x0fexclude_subnets\\x18\\x02 \\x03(\\tR\\x0eexcludeSubnets\\\"9\\n\" +\n\t\"\\n\" +\n\t\"NodeIPSpec\\x12+\\n\" +\n\t\"\\taddresses\\x18\\x01 \\x03(\\v2\\r.common.NetIPR\\taddresses\\\";\\n\" +\n\t\"\\x11NodeLabelSpecSpec\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value\\\"\\xd6\\x03\\n\" +\n\t\"\\x0eNodeStatusSpec\\x12\\x1a\\n\" +\n\t\"\\bnodename\\x18\\x01 \\x01(\\tR\\bnodename\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"node_ready\\x18\\x02 \\x01(\\bR\\tnodeReady\\x12$\\n\" +\n\t\"\\runschedulable\\x18\\x03 \\x01(\\bR\\runschedulable\\x12R\\n\" +\n\t\"\\x06labels\\x18\\x04 \\x03(\\v2:.talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntryR\\x06labels\\x12a\\n\" +\n\t\"\\vannotations\\x18\\x05 \\x03(\\v2?.talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntryR\\vannotations\\x121\\n\" +\n\t\"\\n\" +\n\t\"pod_cid_rs\\x18\\x06 \\x03(\\v2\\x13.common.NetIPPrefixR\\bpodCidRs\\x1a9\\n\" +\n\t\"\\vLabelsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\x1a>\\n\" +\n\t\"\\x10AnnotationsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"S\\n\" +\n\t\"\\x11NodeTaintSpecSpec\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x16\\n\" +\n\t\"\\x06effect\\x18\\x02 \\x01(\\tR\\x06effect\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x03 \\x01(\\tR\\x05value\\\"\\x8b\\x01\\n\" +\n\t\"\\fNodenameSpec\\x12\\x1a\\n\" +\n\t\"\\bnodename\\x18\\x01 \\x01(\\tR\\bnodename\\x12)\\n\" +\n\t\"\\x10hostname_version\\x18\\x02 \\x01(\\tR\\x0fhostnameVersion\\x124\\n\" +\n\t\"\\x16skip_node_registration\\x18\\x03 \\x01(\\bR\\x14skipNodeRegistration\\\"\\xa7\\x02\\n\" +\n\t\"\\tResources\\x12S\\n\" +\n\t\"\\brequests\\x18\\x01 \\x03(\\v27.talos.resource.definitions.k8s.Resources.RequestsEntryR\\brequests\\x12M\\n\" +\n\t\"\\x06limits\\x18\\x02 \\x03(\\v25.talos.resource.definitions.k8s.Resources.LimitsEntryR\\x06limits\\x1a;\\n\" +\n\t\"\\rRequestsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\x1a9\\n\" +\n\t\"\\vLimitsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"\\xab\\x05\\n\" +\n\t\"\\x13SchedulerConfigSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\x12\\x14\\n\" +\n\t\"\\x05image\\x18\\x02 \\x01(\\tR\\x05image\\x12a\\n\" +\n\t\"\\n\" +\n\t\"extra_args\\x18\\x03 \\x03(\\v2B.talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntryR\\textraArgs\\x12P\\n\" +\n\t\"\\rextra_volumes\\x18\\x04 \\x03(\\v2+.talos.resource.definitions.k8s.ExtraVolumeR\\fextraVolumes\\x12\\x82\\x01\\n\" +\n\t\"\\x15environment_variables\\x18\\x05 \\x03(\\v2M.talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntryR\\x14environmentVariables\\x12G\\n\" +\n\t\"\\tresources\\x18\\x06 \\x01(\\v2).talos.resource.definitions.k8s.ResourcesR\\tresources\\x12/\\n\" +\n\t\"\\x06config\\x18\\a \\x01(\\v2\\x17.google.protobuf.StructR\\x06config\\x1ag\\n\" +\n\t\"\\x0eExtraArgsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12?\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\v2).talos.resource.definitions.k8s.ArgValuesR\\x05value:\\x028\\x01\\x1aG\\n\" +\n\t\"\\x19EnvironmentVariablesEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"C\\n\" +\n\t\"\\x11SecretsStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\tR\\aversion\\\"A\\n\" +\n\t\"\\x0eSingleManifest\\x12/\\n\" +\n\t\"\\x06object\\x18\\x01 \\x01(\\v2\\x17.google.protobuf.StructR\\x06object\\\"-\\n\" +\n\t\"\\x19StaticPodServerStatusSpec\\x12\\x10\\n\" +\n\t\"\\x03url\\x18\\x01 \\x01(\\tR\\x03url\\\":\\n\" +\n\t\"\\rStaticPodSpec\\x12)\\n\" +\n\t\"\\x03pod\\x18\\x01 \\x01(\\v2\\x17.google.protobuf.StructR\\x03pod\\\"M\\n\" +\n\t\"\\x13StaticPodStatusSpec\\x126\\n\" +\n\t\"\\n\" +\n\t\"pod_status\\x18\\x01 \\x01(\\v2\\x17.google.protobuf.StructR\\tpodStatusBp\\n\" +\n\t\"&dev.talos.api.resource.definitions.k8sZFgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/k8sb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_k8s_k8s_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_k8s_k8s_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_k8s_k8s_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_k8s_k8s_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_k8s_k8s_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_k8s_k8s_proto_rawDesc), len(file_resource_definitions_k8s_k8s_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_k8s_k8s_proto_rawDescData\n}\n\nvar file_resource_definitions_k8s_k8s_proto_msgTypes = make([]protoimpl.MessageInfo, 48)\nvar file_resource_definitions_k8s_k8s_proto_goTypes = []any{\n\t(*APIServerConfigSpec)(nil),          // 0: talos.resource.definitions.k8s.APIServerConfigSpec\n\t(*AdmissionControlConfigSpec)(nil),   // 1: talos.resource.definitions.k8s.AdmissionControlConfigSpec\n\t(*AdmissionPluginSpec)(nil),          // 2: talos.resource.definitions.k8s.AdmissionPluginSpec\n\t(*ArgValues)(nil),                    // 3: talos.resource.definitions.k8s.ArgValues\n\t(*AuditPolicyConfigSpec)(nil),        // 4: talos.resource.definitions.k8s.AuditPolicyConfigSpec\n\t(*AuthorizationAuthorizersSpec)(nil), // 5: talos.resource.definitions.k8s.AuthorizationAuthorizersSpec\n\t(*AuthorizationConfigSpec)(nil),      // 6: talos.resource.definitions.k8s.AuthorizationConfigSpec\n\t(*BootstrapManifestsConfigSpec)(nil), // 7: talos.resource.definitions.k8s.BootstrapManifestsConfigSpec\n\t(*ConfigStatusSpec)(nil),             // 8: talos.resource.definitions.k8s.ConfigStatusSpec\n\t(*ControllerManagerConfigSpec)(nil),  // 9: talos.resource.definitions.k8s.ControllerManagerConfigSpec\n\t(*EndpointSpec)(nil),                 // 10: talos.resource.definitions.k8s.EndpointSpec\n\t(*ExtraManifest)(nil),                // 11: talos.resource.definitions.k8s.ExtraManifest\n\t(*ExtraManifestsConfigSpec)(nil),     // 12: talos.resource.definitions.k8s.ExtraManifestsConfigSpec\n\t(*ExtraVolume)(nil),                  // 13: talos.resource.definitions.k8s.ExtraVolume\n\t(*KubePrismConfigSpec)(nil),          // 14: talos.resource.definitions.k8s.KubePrismConfigSpec\n\t(*KubePrismEndpoint)(nil),            // 15: talos.resource.definitions.k8s.KubePrismEndpoint\n\t(*KubePrismEndpointsSpec)(nil),       // 16: talos.resource.definitions.k8s.KubePrismEndpointsSpec\n\t(*KubePrismStatusesSpec)(nil),        // 17: talos.resource.definitions.k8s.KubePrismStatusesSpec\n\t(*KubeletConfigSpec)(nil),            // 18: talos.resource.definitions.k8s.KubeletConfigSpec\n\t(*KubeletSpecSpec)(nil),              // 19: talos.resource.definitions.k8s.KubeletSpecSpec\n\t(*ManifestSpec)(nil),                 // 20: talos.resource.definitions.k8s.ManifestSpec\n\t(*ManifestStatusSpec)(nil),           // 21: talos.resource.definitions.k8s.ManifestStatusSpec\n\t(*NodeAnnotationSpecSpec)(nil),       // 22: talos.resource.definitions.k8s.NodeAnnotationSpecSpec\n\t(*NodeIPConfigSpec)(nil),             // 23: talos.resource.definitions.k8s.NodeIPConfigSpec\n\t(*NodeIPSpec)(nil),                   // 24: talos.resource.definitions.k8s.NodeIPSpec\n\t(*NodeLabelSpecSpec)(nil),            // 25: talos.resource.definitions.k8s.NodeLabelSpecSpec\n\t(*NodeStatusSpec)(nil),               // 26: talos.resource.definitions.k8s.NodeStatusSpec\n\t(*NodeTaintSpecSpec)(nil),            // 27: talos.resource.definitions.k8s.NodeTaintSpecSpec\n\t(*NodenameSpec)(nil),                 // 28: talos.resource.definitions.k8s.NodenameSpec\n\t(*Resources)(nil),                    // 29: talos.resource.definitions.k8s.Resources\n\t(*SchedulerConfigSpec)(nil),          // 30: talos.resource.definitions.k8s.SchedulerConfigSpec\n\t(*SecretsStatusSpec)(nil),            // 31: talos.resource.definitions.k8s.SecretsStatusSpec\n\t(*SingleManifest)(nil),               // 32: talos.resource.definitions.k8s.SingleManifest\n\t(*StaticPodServerStatusSpec)(nil),    // 33: talos.resource.definitions.k8s.StaticPodServerStatusSpec\n\t(*StaticPodSpec)(nil),                // 34: talos.resource.definitions.k8s.StaticPodSpec\n\t(*StaticPodStatusSpec)(nil),          // 35: talos.resource.definitions.k8s.StaticPodStatusSpec\n\tnil,                                  // 36: talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry\n\tnil,                                  // 37: talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry\n\tnil,                                  // 38: talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry\n\tnil,                                  // 39: talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry\n\tnil,                                  // 40: talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry\n\tnil,                                  // 41: talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry\n\tnil,                                  // 42: talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntry\n\tnil,                                  // 43: talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntry\n\tnil,                                  // 44: talos.resource.definitions.k8s.Resources.RequestsEntry\n\tnil,                                  // 45: talos.resource.definitions.k8s.Resources.LimitsEntry\n\tnil,                                  // 46: talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry\n\tnil,                                  // 47: talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry\n\t(*structpb.Struct)(nil),              // 48: google.protobuf.Struct\n\t(*common.NetIP)(nil),                 // 49: common.NetIP\n\t(*proto.Mount)(nil),                  // 50: talos.resource.definitions.proto.Mount\n\t(*common.NetIPPrefix)(nil),           // 51: common.NetIPPrefix\n}\nvar file_resource_definitions_k8s_k8s_proto_depIdxs = []int32{\n\t36, // 0: talos.resource.definitions.k8s.APIServerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry\n\t13, // 1: talos.resource.definitions.k8s.APIServerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume\n\t37, // 2: talos.resource.definitions.k8s.APIServerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry\n\t29, // 3: talos.resource.definitions.k8s.APIServerConfigSpec.resources:type_name -> talos.resource.definitions.k8s.Resources\n\t2,  // 4: talos.resource.definitions.k8s.AdmissionControlConfigSpec.config:type_name -> talos.resource.definitions.k8s.AdmissionPluginSpec\n\t48, // 5: talos.resource.definitions.k8s.AdmissionPluginSpec.configuration:type_name -> google.protobuf.Struct\n\t48, // 6: talos.resource.definitions.k8s.AuditPolicyConfigSpec.config:type_name -> google.protobuf.Struct\n\t48, // 7: talos.resource.definitions.k8s.AuthorizationAuthorizersSpec.webhook:type_name -> google.protobuf.Struct\n\t5,  // 8: talos.resource.definitions.k8s.AuthorizationConfigSpec.config:type_name -> talos.resource.definitions.k8s.AuthorizationAuthorizersSpec\n\t38, // 9: talos.resource.definitions.k8s.ControllerManagerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry\n\t13, // 10: talos.resource.definitions.k8s.ControllerManagerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume\n\t39, // 11: talos.resource.definitions.k8s.ControllerManagerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry\n\t29, // 12: talos.resource.definitions.k8s.ControllerManagerConfigSpec.resources:type_name -> talos.resource.definitions.k8s.Resources\n\t49, // 13: talos.resource.definitions.k8s.EndpointSpec.addresses:type_name -> common.NetIP\n\t40, // 14: talos.resource.definitions.k8s.ExtraManifest.extra_headers:type_name -> talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry\n\t11, // 15: talos.resource.definitions.k8s.ExtraManifestsConfigSpec.extra_manifests:type_name -> talos.resource.definitions.k8s.ExtraManifest\n\t15, // 16: talos.resource.definitions.k8s.KubePrismConfigSpec.endpoints:type_name -> talos.resource.definitions.k8s.KubePrismEndpoint\n\t15, // 17: talos.resource.definitions.k8s.KubePrismEndpointsSpec.endpoints:type_name -> talos.resource.definitions.k8s.KubePrismEndpoint\n\t41, // 18: talos.resource.definitions.k8s.KubeletConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry\n\t50, // 19: talos.resource.definitions.k8s.KubeletConfigSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount\n\t48, // 20: talos.resource.definitions.k8s.KubeletConfigSpec.extra_config:type_name -> google.protobuf.Struct\n\t48, // 21: talos.resource.definitions.k8s.KubeletConfigSpec.credential_provider_config:type_name -> google.protobuf.Struct\n\t50, // 22: talos.resource.definitions.k8s.KubeletSpecSpec.extra_mounts:type_name -> talos.resource.definitions.proto.Mount\n\t48, // 23: talos.resource.definitions.k8s.KubeletSpecSpec.config:type_name -> google.protobuf.Struct\n\t48, // 24: talos.resource.definitions.k8s.KubeletSpecSpec.credential_provider_config:type_name -> google.protobuf.Struct\n\t32, // 25: talos.resource.definitions.k8s.ManifestSpec.items:type_name -> talos.resource.definitions.k8s.SingleManifest\n\t49, // 26: talos.resource.definitions.k8s.NodeIPSpec.addresses:type_name -> common.NetIP\n\t42, // 27: talos.resource.definitions.k8s.NodeStatusSpec.labels:type_name -> talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntry\n\t43, // 28: talos.resource.definitions.k8s.NodeStatusSpec.annotations:type_name -> talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntry\n\t51, // 29: talos.resource.definitions.k8s.NodeStatusSpec.pod_cid_rs:type_name -> common.NetIPPrefix\n\t44, // 30: talos.resource.definitions.k8s.Resources.requests:type_name -> talos.resource.definitions.k8s.Resources.RequestsEntry\n\t45, // 31: talos.resource.definitions.k8s.Resources.limits:type_name -> talos.resource.definitions.k8s.Resources.LimitsEntry\n\t46, // 32: talos.resource.definitions.k8s.SchedulerConfigSpec.extra_args:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry\n\t13, // 33: talos.resource.definitions.k8s.SchedulerConfigSpec.extra_volumes:type_name -> talos.resource.definitions.k8s.ExtraVolume\n\t47, // 34: talos.resource.definitions.k8s.SchedulerConfigSpec.environment_variables:type_name -> talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry\n\t29, // 35: talos.resource.definitions.k8s.SchedulerConfigSpec.resources:type_name -> talos.resource.definitions.k8s.Resources\n\t48, // 36: talos.resource.definitions.k8s.SchedulerConfigSpec.config:type_name -> google.protobuf.Struct\n\t48, // 37: talos.resource.definitions.k8s.SingleManifest.object:type_name -> google.protobuf.Struct\n\t48, // 38: talos.resource.definitions.k8s.StaticPodSpec.pod:type_name -> google.protobuf.Struct\n\t48, // 39: talos.resource.definitions.k8s.StaticPodStatusSpec.pod_status:type_name -> google.protobuf.Struct\n\t3,  // 40: talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.k8s.ArgValues\n\t3,  // 41: talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.k8s.ArgValues\n\t3,  // 42: talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.k8s.ArgValues\n\t3,  // 43: talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry.value:type_name -> talos.resource.definitions.k8s.ArgValues\n\t44, // [44:44] is the sub-list for method output_type\n\t44, // [44:44] is the sub-list for method input_type\n\t44, // [44:44] is the sub-list for extension type_name\n\t44, // [44:44] is the sub-list for extension extendee\n\t0,  // [0:44] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_k8s_k8s_proto_init() }\nfunc file_resource_definitions_k8s_k8s_proto_init() {\n\tif File_resource_definitions_k8s_k8s_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_k8s_k8s_proto_rawDesc), len(file_resource_definitions_k8s_k8s_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   48,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_k8s_k8s_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_k8s_k8s_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_k8s_k8s_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_k8s_k8s_proto = out.File\n\tfile_resource_definitions_k8s_k8s_proto_goTypes = nil\n\tfile_resource_definitions_k8s_k8s_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/k8s/k8s_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/k8s/k8s.proto\n\npackage k8s\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tstructpb \"github.com/planetscale/vtprotobuf/types/known/structpb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tstructpb1 \"google.golang.org/protobuf/types/known/structpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tproto1 \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/proto\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *APIServerConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *APIServerConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *APIServerConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Resources != nil {\n\t\tsize, err := m.Resources.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif len(m.AdvertisedAddress) > 0 {\n\t\ti -= len(m.AdvertisedAddress)\n\t\tcopy(dAtA[i:], m.AdvertisedAddress)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AdvertisedAddress)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k := range m.EnvironmentVariables {\n\t\t\tv := m.EnvironmentVariables[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x4a\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor iNdEx := len(m.ExtraVolumes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.ExtraVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x42\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x3a\n\t\t}\n\t}\n\tif len(m.ServiceCidRs) > 0 {\n\t\tfor iNdEx := len(m.ServiceCidRs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ServiceCidRs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ServiceCidRs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServiceCidRs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif m.LocalPort != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.LocalPort))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.EtcdServers) > 0 {\n\t\tfor iNdEx := len(m.EtcdServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.EtcdServers[iNdEx])\n\t\t\tcopy(dAtA[i:], m.EtcdServers[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.EtcdServers[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.ControlPlaneEndpoint) > 0 {\n\t\ti -= len(m.ControlPlaneEndpoint)\n\t\tcopy(dAtA[i:], m.ControlPlaneEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ControlPlaneEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.CloudProvider) > 0 {\n\t\ti -= len(m.CloudProvider)\n\t\tcopy(dAtA[i:], m.CloudProvider)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CloudProvider)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AdmissionControlConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AdmissionControlConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AdmissionControlConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Config) > 0 {\n\t\tfor iNdEx := len(m.Config) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Config[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AdmissionPluginSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AdmissionPluginSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AdmissionPluginSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Configuration != nil {\n\t\tsize, err := (*structpb.Struct)(m.Configuration).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ArgValues) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ArgValues) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ArgValues) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Values) > 0 {\n\t\tfor iNdEx := len(m.Values) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Values[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Values[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Values[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AuditPolicyConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AuditPolicyConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AuditPolicyConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Config != nil {\n\t\tsize, err := (*structpb.Struct)(m.Config).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AuthorizationAuthorizersSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AuthorizationAuthorizersSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AuthorizationAuthorizersSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Webhook != nil {\n\t\tsize, err := (*structpb.Struct)(m.Webhook).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AuthorizationConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AuthorizationConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AuthorizationConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Config) > 0 {\n\t\tfor iNdEx := len(m.Config) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Config[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BootstrapManifestsConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BootstrapManifestsConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BootstrapManifestsConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.CniName) > 0 {\n\t\ti -= len(m.CniName)\n\t\tcopy(dAtA[i:], m.CniName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CniName)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xaa\n\t}\n\tif len(m.FlannelKubeNetworkPoliciesImage) > 0 {\n\t\ti -= len(m.FlannelKubeNetworkPoliciesImage)\n\t\tcopy(dAtA[i:], m.FlannelKubeNetworkPoliciesImage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlannelKubeNetworkPoliciesImage)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa2\n\t}\n\tif m.FlannelKubeNetworkPoliciesEnabled {\n\t\ti--\n\t\tif m.FlannelKubeNetworkPoliciesEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif len(m.FlannelKubeServicePort) > 0 {\n\t\ti -= len(m.FlannelKubeServicePort)\n\t\tcopy(dAtA[i:], m.FlannelKubeServicePort)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlannelKubeServicePort)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif len(m.FlannelKubeServiceHost) > 0 {\n\t\ti -= len(m.FlannelKubeServiceHost)\n\t\tcopy(dAtA[i:], m.FlannelKubeServiceHost)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlannelKubeServiceHost)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.FlannelExtraArgs) > 0 {\n\t\tfor iNdEx := len(m.FlannelExtraArgs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.FlannelExtraArgs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.FlannelExtraArgs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlannelExtraArgs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0x82\n\t\t}\n\t}\n\tif m.TalosApiServiceEnabled {\n\t\ti--\n\t\tif m.TalosApiServiceEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.PodSecurityPolicyEnabled {\n\t\ti--\n\t\tif m.PodSecurityPolicyEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif len(m.FlannelImage) > 0 {\n\t\ti -= len(m.FlannelImage)\n\t\tcopy(dAtA[i:], m.FlannelImage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FlannelImage)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif m.FlannelEnabled {\n\t\ti--\n\t\tif m.FlannelEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif len(m.DnsServiceIPv6) > 0 {\n\t\ti -= len(m.DnsServiceIPv6)\n\t\tcopy(dAtA[i:], m.DnsServiceIPv6)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DnsServiceIPv6)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.DnsServiceIp) > 0 {\n\t\ti -= len(m.DnsServiceIp)\n\t\tcopy(dAtA[i:], m.DnsServiceIp)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DnsServiceIp)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.CoreDnsImage) > 0 {\n\t\ti -= len(m.CoreDnsImage)\n\t\tcopy(dAtA[i:], m.CoreDnsImage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CoreDnsImage)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.CoreDnsEnabled {\n\t\ti--\n\t\tif m.CoreDnsEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif len(m.ProxyArgs) > 0 {\n\t\tfor iNdEx := len(m.ProxyArgs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ProxyArgs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ProxyArgs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProxyArgs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.ProxyImage) > 0 {\n\t\ti -= len(m.ProxyImage)\n\t\tcopy(dAtA[i:], m.ProxyImage)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProxyImage)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.ProxyEnabled {\n\t\ti--\n\t\tif m.ProxyEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor iNdEx := len(m.PodCidRs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PodCidRs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PodCidRs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PodCidRs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.ClusterDomain) > 0 {\n\t\ti -= len(m.ClusterDomain)\n\t\tcopy(dAtA[i:], m.ClusterDomain)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterDomain)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Server) > 0 {\n\t\ti -= len(m.Server)\n\t\tcopy(dAtA[i:], m.Server)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Server)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ControllerManagerConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ControllerManagerConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ControllerManagerConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Resources != nil {\n\t\tsize, err := m.Resources.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k := range m.EnvironmentVariables {\n\t\t\tv := m.EnvironmentVariables[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x42\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor iNdEx := len(m.ExtraVolumes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.ExtraVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x3a\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.ServiceCidRs) > 0 {\n\t\tfor iNdEx := len(m.ServiceCidRs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ServiceCidRs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ServiceCidRs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ServiceCidRs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor iNdEx := len(m.PodCidRs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PodCidRs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PodCidRs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PodCidRs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.CloudProvider) > 0 {\n\t\ti -= len(m.CloudProvider)\n\t\tcopy(dAtA[i:], m.CloudProvider)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CloudProvider)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EndpointSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EndpointSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EndpointSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Hosts) > 0 {\n\t\tfor iNdEx := len(m.Hosts) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Hosts[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Hosts[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hosts[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Addresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Addresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtraManifest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtraManifest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtraManifest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.InlineManifest) > 0 {\n\t\ti -= len(m.InlineManifest)\n\t\tcopy(dAtA[i:], m.InlineManifest)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InlineManifest)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.ExtraHeaders) > 0 {\n\t\tfor k := range m.ExtraHeaders {\n\t\t\tv := m.ExtraHeaders[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Priority) > 0 {\n\t\ti -= len(m.Priority)\n\t\tcopy(dAtA[i:], m.Priority)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Priority)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Url) > 0 {\n\t\ti -= len(m.Url)\n\t\tcopy(dAtA[i:], m.Url)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Url)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtraManifestsConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtraManifestsConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtraManifestsConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExtraManifests) > 0 {\n\t\tfor iNdEx := len(m.ExtraManifests) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.ExtraManifests[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtraVolume) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtraVolume) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtraVolume) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ReadOnly {\n\t\ti--\n\t\tif m.ReadOnly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.MountPath) > 0 {\n\t\ti -= len(m.MountPath)\n\t\tcopy(dAtA[i:], m.MountPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MountPath)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.HostPath) > 0 {\n\t\ti -= len(m.HostPath)\n\t\tcopy(dAtA[i:], m.HostPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.HostPath)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubePrismConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubePrismConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubePrismConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor iNdEx := len(m.Endpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Endpoints[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Port != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Port))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubePrismEndpoint) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubePrismEndpoint) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubePrismEndpoint) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Port != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Port))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubePrismEndpointsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubePrismEndpointsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubePrismEndpointsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor iNdEx := len(m.Endpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Endpoints[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubePrismStatusesSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubePrismStatusesSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubePrismStatusesSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Healthy {\n\t\ti--\n\t\tif m.Healthy {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubeletConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubeletConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubeletConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.AllowSchedulingOnControlPlane {\n\t\ti--\n\t\tif m.AllowSchedulingOnControlPlane {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.CredentialProviderConfig != nil {\n\t\tsize, err := (*structpb.Struct)(m.CredentialProviderConfig).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x6a\n\t}\n\tif m.EnableFsQuotaMonitoring {\n\t\ti--\n\t\tif m.EnableFsQuotaMonitoring {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.DisableManifestsDirectory {\n\t\ti--\n\t\tif m.DisableManifestsDirectory {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif len(m.StaticPodListUrl) > 0 {\n\t\ti -= len(m.StaticPodListUrl)\n\t\tcopy(dAtA[i:], m.StaticPodListUrl)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.StaticPodListUrl)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.SkipNodeRegistration {\n\t\ti--\n\t\tif m.SkipNodeRegistration {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.DefaultRuntimeSeccompEnabled {\n\t\ti--\n\t\tif m.DefaultRuntimeSeccompEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.CloudProviderExternal {\n\t\ti--\n\t\tif m.CloudProviderExternal {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.ExtraConfig != nil {\n\t\tsize, err := (*structpb.Struct)(m.ExtraConfig).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.ExtraMounts) > 0 {\n\t\tfor iNdEx := len(m.ExtraMounts) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExtraMounts[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExtraMounts[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.ClusterDomain) > 0 {\n\t\ti -= len(m.ClusterDomain)\n\t\tcopy(dAtA[i:], m.ClusterDomain)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterDomain)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.ClusterDns) > 0 {\n\t\tfor iNdEx := len(m.ClusterDns) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ClusterDns[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ClusterDns[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterDns[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubeletSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubeletSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubeletSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.CredentialProviderConfig != nil {\n\t\tsize, err := (*structpb.Struct)(m.CredentialProviderConfig).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.Config != nil {\n\t\tsize, err := (*structpb.Struct)(m.Config).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.ExpectedNodename) > 0 {\n\t\ti -= len(m.ExpectedNodename)\n\t\tcopy(dAtA[i:], m.ExpectedNodename)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ExpectedNodename)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.ExtraMounts) > 0 {\n\t\tfor iNdEx := len(m.ExtraMounts) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExtraMounts[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExtraMounts[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.Args) > 0 {\n\t\tfor iNdEx := len(m.Args) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Args[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Args[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Args[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ManifestSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ManifestSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ManifestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Items) > 0 {\n\t\tfor iNdEx := len(m.Items) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Items[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ManifestStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ManifestStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ManifestStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ManifestsApplied) > 0 {\n\t\tfor iNdEx := len(m.ManifestsApplied) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ManifestsApplied[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ManifestsApplied[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ManifestsApplied[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeAnnotationSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeAnnotationSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeAnnotationSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeIPConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeIPConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeIPConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.ExcludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ExcludeSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ExcludeSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ExcludeSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.ValidSubnets) > 0 {\n\t\tfor iNdEx := len(m.ValidSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.ValidSubnets[iNdEx])\n\t\t\tcopy(dAtA[i:], m.ValidSubnets[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ValidSubnets[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeIPSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeIPSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeIPSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Addresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Addresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeLabelSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeLabelSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeLabelSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor iNdEx := len(m.PodCidRs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.PodCidRs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.PodCidRs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.Annotations) > 0 {\n\t\tfor k := range m.Annotations {\n\t\t\tv := m.Annotations[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.Labels) > 0 {\n\t\tfor k := range m.Labels {\n\t\t\tv := m.Labels[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.Unschedulable {\n\t\ti--\n\t\tif m.Unschedulable {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.NodeReady {\n\t\ti--\n\t\tif m.NodeReady {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Nodename) > 0 {\n\t\ti -= len(m.Nodename)\n\t\tcopy(dAtA[i:], m.Nodename)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Nodename)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeTaintSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeTaintSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeTaintSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Effect) > 0 {\n\t\ti -= len(m.Effect)\n\t\tcopy(dAtA[i:], m.Effect)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Effect)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Key) > 0 {\n\t\ti -= len(m.Key)\n\t\tcopy(dAtA[i:], m.Key)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Key)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodenameSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodenameSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodenameSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SkipNodeRegistration {\n\t\ti--\n\t\tif m.SkipNodeRegistration {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.HostnameVersion) > 0 {\n\t\ti -= len(m.HostnameVersion)\n\t\tcopy(dAtA[i:], m.HostnameVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.HostnameVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Nodename) > 0 {\n\t\ti -= len(m.Nodename)\n\t\tcopy(dAtA[i:], m.Nodename)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Nodename)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Resources) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Resources) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Resources) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Limits) > 0 {\n\t\tfor k := range m.Limits {\n\t\t\tv := m.Limits[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Requests) > 0 {\n\t\tfor k := range m.Requests {\n\t\t\tv := m.Requests[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SchedulerConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SchedulerConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SchedulerConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Config != nil {\n\t\tsize, err := (*structpb.Struct)(m.Config).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Resources != nil {\n\t\tsize, err := m.Resources.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k := range m.EnvironmentVariables {\n\t\t\tv := m.EnvironmentVariables[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor iNdEx := len(m.ExtraVolumes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.ExtraVolumes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k := range m.ExtraArgs {\n\t\t\tv := m.ExtraArgs[k]\n\t\t\tbaseI := i\n\t\t\tsize, err := v.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.Image) > 0 {\n\t\ti -= len(m.Image)\n\t\tcopy(dAtA[i:], m.Image)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Image)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SecretsStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SecretsStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SecretsStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SingleManifest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SingleManifest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SingleManifest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Object != nil {\n\t\tsize, err := (*structpb.Struct)(m.Object).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StaticPodServerStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StaticPodServerStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StaticPodServerStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Url) > 0 {\n\t\ti -= len(m.Url)\n\t\tcopy(dAtA[i:], m.Url)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Url)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StaticPodSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StaticPodSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StaticPodSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Pod != nil {\n\t\tsize, err := (*structpb.Struct)(m.Pod).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StaticPodStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StaticPodStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StaticPodStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.PodStatus != nil {\n\t\tsize, err := (*structpb.Struct)(m.PodStatus).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *APIServerConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.CloudProvider)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ControlPlaneEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.EtcdServers) > 0 {\n\t\tfor _, s := range m.EtcdServers {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.LocalPort != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.LocalPort))\n\t}\n\tif len(m.ServiceCidRs) > 0 {\n\t\tfor _, s := range m.ServiceCidRs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor _, e := range m.ExtraVolumes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k, v := range m.EnvironmentVariables {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tl = len(m.AdvertisedAddress)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Resources != nil {\n\t\tl = m.Resources.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AdmissionControlConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Config) > 0 {\n\t\tfor _, e := range m.Config {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AdmissionPluginSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Configuration != nil {\n\t\tl = (*structpb.Struct)(m.Configuration).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ArgValues) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Values) > 0 {\n\t\tfor _, s := range m.Values {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AuditPolicyConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Config != nil {\n\t\tl = (*structpb.Struct)(m.Config).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AuthorizationAuthorizersSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Webhook != nil {\n\t\tl = (*structpb.Struct)(m.Webhook).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AuthorizationConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Config) > 0 {\n\t\tfor _, e := range m.Config {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BootstrapManifestsConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Server)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ClusterDomain)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor _, s := range m.PodCidRs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ProxyEnabled {\n\t\tn += 2\n\t}\n\tl = len(m.ProxyImage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ProxyArgs) > 0 {\n\t\tfor _, s := range m.ProxyArgs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.CoreDnsEnabled {\n\t\tn += 2\n\t}\n\tl = len(m.CoreDnsImage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DnsServiceIp)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DnsServiceIPv6)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FlannelEnabled {\n\t\tn += 2\n\t}\n\tl = len(m.FlannelImage)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PodSecurityPolicyEnabled {\n\t\tn += 2\n\t}\n\tif m.TalosApiServiceEnabled {\n\t\tn += 2\n\t}\n\tif len(m.FlannelExtraArgs) > 0 {\n\t\tfor _, s := range m.FlannelExtraArgs {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.FlannelKubeServiceHost)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.FlannelKubeServicePort)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FlannelKubeNetworkPoliciesEnabled {\n\t\tn += 3\n\t}\n\tl = len(m.FlannelKubeNetworkPoliciesImage)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.CniName)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ControllerManagerConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.CloudProvider)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor _, s := range m.PodCidRs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ServiceCidRs) > 0 {\n\t\tfor _, s := range m.ServiceCidRs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor _, e := range m.ExtraVolumes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k, v := range m.EnvironmentVariables {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif m.Resources != nil {\n\t\tl = m.Resources.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EndpointSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Hosts) > 0 {\n\t\tfor _, s := range m.Hosts {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtraManifest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Url)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Priority)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ExtraHeaders) > 0 {\n\t\tfor k, v := range m.ExtraHeaders {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tl = len(m.InlineManifest)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtraManifestsConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.ExtraManifests) > 0 {\n\t\tfor _, e := range m.ExtraManifests {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtraVolume) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.HostPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.MountPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ReadOnly {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubePrismConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Port != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Port))\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor _, e := range m.Endpoints {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubePrismEndpoint) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Port != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Port))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubePrismEndpointsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Endpoints) > 0 {\n\t\tfor _, e := range m.Endpoints {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubePrismStatusesSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Healthy {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubeletConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ClusterDns) > 0 {\n\t\tfor _, s := range m.ClusterDns {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.ClusterDomain)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ExtraMounts) > 0 {\n\t\tfor _, e := range m.ExtraMounts {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ExtraConfig != nil {\n\t\tl = (*structpb.Struct)(m.ExtraConfig).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CloudProviderExternal {\n\t\tn += 2\n\t}\n\tif m.DefaultRuntimeSeccompEnabled {\n\t\tn += 2\n\t}\n\tif m.SkipNodeRegistration {\n\t\tn += 2\n\t}\n\tl = len(m.StaticPodListUrl)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.DisableManifestsDirectory {\n\t\tn += 2\n\t}\n\tif m.EnableFsQuotaMonitoring {\n\t\tn += 2\n\t}\n\tif m.CredentialProviderConfig != nil {\n\t\tl = (*structpb.Struct)(m.CredentialProviderConfig).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.AllowSchedulingOnControlPlane {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubeletSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Args) > 0 {\n\t\tfor _, s := range m.Args {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExtraMounts) > 0 {\n\t\tfor _, e := range m.ExtraMounts {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.ExpectedNodename)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Config != nil {\n\t\tl = (*structpb.Struct)(m.Config).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.CredentialProviderConfig != nil {\n\t\tl = (*structpb.Struct)(m.CredentialProviderConfig).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ManifestSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Items) > 0 {\n\t\tfor _, e := range m.Items {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ManifestStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.ManifestsApplied) > 0 {\n\t\tfor _, s := range m.ManifestsApplied {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeAnnotationSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeIPConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.ValidSubnets) > 0 {\n\t\tfor _, s := range m.ValidSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor _, s := range m.ExcludeSubnets {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeIPSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeLabelSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Nodename)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.NodeReady {\n\t\tn += 2\n\t}\n\tif m.Unschedulable {\n\t\tn += 2\n\t}\n\tif len(m.Labels) > 0 {\n\t\tfor k, v := range m.Labels {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.Annotations) > 0 {\n\t\tfor k, v := range m.Annotations {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.PodCidRs) > 0 {\n\t\tfor _, e := range m.PodCidRs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeTaintSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Key)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Effect)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodenameSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Nodename)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.HostnameVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SkipNodeRegistration {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Resources) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Requests) > 0 {\n\t\tfor k, v := range m.Requests {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.Limits) > 0 {\n\t\tfor k, v := range m.Limits {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SchedulerConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tl = len(m.Image)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ExtraArgs) > 0 {\n\t\tfor k, v := range m.ExtraArgs {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tl = 0\n\t\t\tif v != nil {\n\t\t\t\tl = v.SizeVT()\n\t\t\t}\n\t\t\tl += 1 + protohelpers.SizeOfVarint(uint64(l))\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + l\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif len(m.ExtraVolumes) > 0 {\n\t\tfor _, e := range m.ExtraVolumes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.EnvironmentVariables) > 0 {\n\t\tfor k, v := range m.EnvironmentVariables {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif m.Resources != nil {\n\t\tl = m.Resources.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Config != nil {\n\t\tl = (*structpb.Struct)(m.Config).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SecretsStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SingleManifest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Object != nil {\n\t\tl = (*structpb.Struct)(m.Object).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StaticPodServerStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Url)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StaticPodSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Pod != nil {\n\t\tl = (*structpb.Struct)(m.Pod).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StaticPodStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.PodStatus != nil {\n\t\tl = (*structpb.Struct)(m.PodStatus).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *APIServerConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: APIServerConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: APIServerConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CloudProvider\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CloudProvider = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControlPlaneEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ControlPlaneEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcdServers\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.EtcdServers = append(m.EtcdServers, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LocalPort\", wireType)\n\t\t\t}\n\t\t\tm.LocalPort = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.LocalPort |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceCidRs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ServiceCidRs = append(m.ServiceCidRs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraVolumes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraVolumes = append(m.ExtraVolumes, &ExtraVolume{})\n\t\t\tif err := m.ExtraVolumes[len(m.ExtraVolumes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EnvironmentVariables\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EnvironmentVariables == nil {\n\t\t\t\tm.EnvironmentVariables = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EnvironmentVariables[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdvertisedAddress\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdvertisedAddress = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resources\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Resources == nil {\n\t\t\t\tm.Resources = &Resources{}\n\t\t\t}\n\t\t\tif err := m.Resources.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AdmissionControlConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AdmissionControlConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AdmissionControlConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Config\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Config = append(m.Config, &AdmissionPluginSpec{})\n\t\t\tif err := m.Config[len(m.Config)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AdmissionPluginSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AdmissionPluginSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AdmissionPluginSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Configuration\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Configuration == nil {\n\t\t\t\tm.Configuration = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Configuration).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ArgValues) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ArgValues: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ArgValues: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Values\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Values = append(m.Values, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AuditPolicyConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AuditPolicyConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AuditPolicyConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Config\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Config == nil {\n\t\t\t\tm.Config = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Config).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AuthorizationAuthorizersSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AuthorizationAuthorizersSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AuthorizationAuthorizersSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Webhook\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Webhook == nil {\n\t\t\t\tm.Webhook = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Webhook).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AuthorizationConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AuthorizationConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AuthorizationConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Config\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Config = append(m.Config, &AuthorizationAuthorizersSpec{})\n\t\t\tif err := m.Config[len(m.Config)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BootstrapManifestsConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapManifestsConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BootstrapManifestsConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Server\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Server = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDomain\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterDomain = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodCidRs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PodCidRs = append(m.PodCidRs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProxyEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ProxyEnabled = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProxyImage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProxyImage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProxyArgs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProxyArgs = append(m.ProxyArgs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CoreDnsEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.CoreDnsEnabled = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CoreDnsImage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CoreDnsImage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsServiceIp\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsServiceIp = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsServiceIPv6\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsServiceIPv6 = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.FlannelEnabled = bool(v != 0)\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelImage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FlannelImage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodSecurityPolicyEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.PodSecurityPolicyEnabled = bool(v != 0)\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TalosApiServiceEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TalosApiServiceEnabled = bool(v != 0)\n\t\tcase 16:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FlannelExtraArgs = append(m.FlannelExtraArgs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelKubeServiceHost\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FlannelKubeServiceHost = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelKubeServicePort\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FlannelKubeServicePort = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 19:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelKubeNetworkPoliciesEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.FlannelKubeNetworkPoliciesEnabled = bool(v != 0)\n\t\tcase 20:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FlannelKubeNetworkPoliciesImage\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FlannelKubeNetworkPoliciesImage = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 21:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CniName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CniName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ConfigStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ControllerManagerConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerManagerConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ControllerManagerConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CloudProvider\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CloudProvider = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodCidRs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PodCidRs = append(m.PodCidRs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceCidRs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ServiceCidRs = append(m.ServiceCidRs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraVolumes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraVolumes = append(m.ExtraVolumes, &ExtraVolume{})\n\t\t\tif err := m.ExtraVolumes[len(m.ExtraVolumes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EnvironmentVariables\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EnvironmentVariables == nil {\n\t\t\t\tm.EnvironmentVariables = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EnvironmentVariables[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resources\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Resources == nil {\n\t\t\t\tm.Resources = &Resources{}\n\t\t\t}\n\t\t\tif err := m.Resources.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EndpointSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EndpointSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EndpointSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.Addresses[len(m.Addresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Addresses[len(m.Addresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hosts\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hosts = append(m.Hosts, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtraManifest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraManifest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraManifest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Url\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Url = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Priority = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraHeaders\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraHeaders == nil {\n\t\t\t\tm.ExtraHeaders = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraHeaders[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InlineManifest\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InlineManifest = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtraManifestsConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraManifestsConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraManifestsConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraManifests\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraManifests = append(m.ExtraManifests, &ExtraManifest{})\n\t\t\tif err := m.ExtraManifests[len(m.ExtraManifests)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtraVolume) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraVolume: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtraVolume: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HostPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.HostPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MountPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MountPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadOnly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadOnly = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubePrismConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Port\", wireType)\n\t\t\t}\n\t\t\tm.Port = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Port |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoints = append(m.Endpoints, &KubePrismEndpoint{})\n\t\t\tif err := m.Endpoints[len(m.Endpoints)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubePrismEndpoint) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismEndpoint: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismEndpoint: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Port\", wireType)\n\t\t\t}\n\t\t\tm.Port = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Port |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubePrismEndpointsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismEndpointsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismEndpointsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoints = append(m.Endpoints, &KubePrismEndpoint{})\n\t\t\tif err := m.Endpoints[len(m.Endpoints)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubePrismStatusesSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismStatusesSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubePrismStatusesSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Healthy\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Healthy = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubeletConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDns\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterDns = append(m.ClusterDns, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterDomain\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterDomain = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraMounts\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraMounts = append(m.ExtraMounts, &proto1.Mount{})\n\t\t\tif unmarshal, ok := interface{}(m.ExtraMounts[len(m.ExtraMounts)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExtraMounts[len(m.ExtraMounts)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraConfig == nil {\n\t\t\t\tm.ExtraConfig = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.ExtraConfig).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CloudProviderExternal\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.CloudProviderExternal = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DefaultRuntimeSeccompEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DefaultRuntimeSeccompEnabled = bool(v != 0)\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipNodeRegistration\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipNodeRegistration = bool(v != 0)\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field StaticPodListUrl\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.StaticPodListUrl = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DisableManifestsDirectory\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DisableManifestsDirectory = bool(v != 0)\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EnableFsQuotaMonitoring\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EnableFsQuotaMonitoring = bool(v != 0)\n\t\tcase 13:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CredentialProviderConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CredentialProviderConfig == nil {\n\t\t\t\tm.CredentialProviderConfig = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.CredentialProviderConfig).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowSchedulingOnControlPlane\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AllowSchedulingOnControlPlane = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubeletSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Args\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Args = append(m.Args, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraMounts\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraMounts = append(m.ExtraMounts, &proto1.Mount{})\n\t\t\tif unmarshal, ok := interface{}(m.ExtraMounts[len(m.ExtraMounts)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExtraMounts[len(m.ExtraMounts)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExpectedNodename\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExpectedNodename = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Config\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Config == nil {\n\t\t\t\tm.Config = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Config).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CredentialProviderConfig\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CredentialProviderConfig == nil {\n\t\t\t\tm.CredentialProviderConfig = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.CredentialProviderConfig).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ManifestSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ManifestSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ManifestSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Items\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Items = append(m.Items, &SingleManifest{})\n\t\t\tif err := m.Items[len(m.Items)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ManifestStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ManifestStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ManifestStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ManifestsApplied\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ManifestsApplied = append(m.ManifestsApplied, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeAnnotationSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAnnotationSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAnnotationSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeIPConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeIPConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeIPConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ValidSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ValidSubnets = append(m.ValidSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExcludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExcludeSubnets = append(m.ExcludeSubnets, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeIPSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeIPSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeIPSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.Addresses[len(m.Addresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Addresses[len(m.Addresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeLabelSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeLabelSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeLabelSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nodename\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Nodename = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeReady\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.NodeReady = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unschedulable\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Unschedulable = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Labels\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Labels == nil {\n\t\t\t\tm.Labels = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Labels[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Annotations\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Annotations == nil {\n\t\t\t\tm.Annotations = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Annotations[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodCidRs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PodCidRs = append(m.PodCidRs, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.PodCidRs[len(m.PodCidRs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.PodCidRs[len(m.PodCidRs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeTaintSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeTaintSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeTaintSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Key\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Key = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Effect\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Effect = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodenameSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodenameSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodenameSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nodename\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Nodename = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HostnameVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.HostnameVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipNodeRegistration\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipNodeRegistration = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Resources) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Resources: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Resources: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Requests\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Requests == nil {\n\t\t\t\tm.Requests = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Requests[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Limits\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Limits == nil {\n\t\t\t\tm.Limits = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Limits[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SchedulerConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SchedulerConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SchedulerConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Image\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Image = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraArgs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ExtraArgs == nil {\n\t\t\t\tm.ExtraArgs = make(map[string]*ArgValues)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue *ArgValues\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapmsglen int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapmsglen |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif mapmsglen < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostmsgIndex := iNdEx + mapmsglen\n\t\t\t\t\tif postmsgIndex < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postmsgIndex > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = &ArgValues{}\n\t\t\t\t\tif err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx = postmsgIndex\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ExtraArgs[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraVolumes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraVolumes = append(m.ExtraVolumes, &ExtraVolume{})\n\t\t\tif err := m.ExtraVolumes[len(m.ExtraVolumes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EnvironmentVariables\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EnvironmentVariables == nil {\n\t\t\t\tm.EnvironmentVariables = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EnvironmentVariables[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resources\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Resources == nil {\n\t\t\t\tm.Resources = &Resources{}\n\t\t\t}\n\t\t\tif err := m.Resources.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Config\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Config == nil {\n\t\t\t\tm.Config = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Config).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SecretsStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SecretsStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SecretsStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SingleManifest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SingleManifest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SingleManifest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Object\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Object == nil {\n\t\t\t\tm.Object = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Object).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StaticPodServerStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodServerStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodServerStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Url\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Url = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StaticPodSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pod\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Pod == nil {\n\t\t\t\tm.Pod = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.Pod).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StaticPodStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StaticPodStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PodStatus\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.PodStatus == nil {\n\t\t\t\tm.PodStatus = &structpb1.Struct{}\n\t\t\t}\n\t\t\tif err := (*structpb.Struct)(m.PodStatus).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/kubeaccess/kubeaccess.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/kubeaccess/kubeaccess.proto\n\npackage kubeaccess\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ConfigSpec describes KubeSpan configuration..\ntype ConfigSpec struct {\n\tstate                       protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled                     bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tAllowedApiRoles             []string               `protobuf:\"bytes,2,rep,name=allowed_api_roles,json=allowedApiRoles,proto3\" json:\"allowed_api_roles,omitempty\"`\n\tAllowedKubernetesNamespaces []string               `protobuf:\"bytes,3,rep,name=allowed_kubernetes_namespaces,json=allowedKubernetesNamespaces,proto3\" json:\"allowed_kubernetes_namespaces,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *ConfigSpec) Reset() {\n\t*x = ConfigSpec{}\n\tmi := &file_resource_definitions_kubeaccess_kubeaccess_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigSpec) ProtoMessage() {}\n\nfunc (x *ConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubeaccess_kubeaccess_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubeaccess_kubeaccess_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ConfigSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetAllowedApiRoles() []string {\n\tif x != nil {\n\t\treturn x.AllowedApiRoles\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetAllowedKubernetesNamespaces() []string {\n\tif x != nil {\n\t\treturn x.AllowedKubernetesNamespaces\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_kubeaccess_kubeaccess_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_kubeaccess_kubeaccess_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"0resource/definitions/kubeaccess/kubeaccess.proto\\x12%talos.resource.definitions.kubeaccess\\\"\\x96\\x01\\n\" +\n\t\"\\n\" +\n\t\"ConfigSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\x12*\\n\" +\n\t\"\\x11allowed_api_roles\\x18\\x02 \\x03(\\tR\\x0fallowedApiRoles\\x12B\\n\" +\n\t\"\\x1dallowed_kubernetes_namespaces\\x18\\x03 \\x03(\\tR\\x1ballowedKubernetesNamespacesB~\\n\" +\n\t\"-dev.talos.api.resource.definitions.kubeaccessZMgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/kubeaccessb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_kubeaccess_kubeaccess_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_kubeaccess_kubeaccess_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_kubeaccess_kubeaccess_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_kubeaccess_kubeaccess_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_kubeaccess_kubeaccess_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_kubeaccess_kubeaccess_proto_rawDesc), len(file_resource_definitions_kubeaccess_kubeaccess_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_kubeaccess_kubeaccess_proto_rawDescData\n}\n\nvar file_resource_definitions_kubeaccess_kubeaccess_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_resource_definitions_kubeaccess_kubeaccess_proto_goTypes = []any{\n\t(*ConfigSpec)(nil), // 0: talos.resource.definitions.kubeaccess.ConfigSpec\n}\nvar file_resource_definitions_kubeaccess_kubeaccess_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_kubeaccess_kubeaccess_proto_init() }\nfunc file_resource_definitions_kubeaccess_kubeaccess_proto_init() {\n\tif File_resource_definitions_kubeaccess_kubeaccess_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_kubeaccess_kubeaccess_proto_rawDesc), len(file_resource_definitions_kubeaccess_kubeaccess_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_kubeaccess_kubeaccess_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_kubeaccess_kubeaccess_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_kubeaccess_kubeaccess_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_kubeaccess_kubeaccess_proto = out.File\n\tfile_resource_definitions_kubeaccess_kubeaccess_proto_goTypes = nil\n\tfile_resource_definitions_kubeaccess_kubeaccess_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/kubeaccess/kubeaccess_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/kubeaccess/kubeaccess.proto\n\npackage kubeaccess\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AllowedKubernetesNamespaces) > 0 {\n\t\tfor iNdEx := len(m.AllowedKubernetesNamespaces) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.AllowedKubernetesNamespaces[iNdEx])\n\t\t\tcopy(dAtA[i:], m.AllowedKubernetesNamespaces[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AllowedKubernetesNamespaces[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.AllowedApiRoles) > 0 {\n\t\tfor iNdEx := len(m.AllowedApiRoles) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.AllowedApiRoles[iNdEx])\n\t\t\tcopy(dAtA[i:], m.AllowedApiRoles[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AllowedApiRoles[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tif len(m.AllowedApiRoles) > 0 {\n\t\tfor _, s := range m.AllowedApiRoles {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.AllowedKubernetesNamespaces) > 0 {\n\t\tfor _, s := range m.AllowedKubernetesNamespaces {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowedApiRoles\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AllowedApiRoles = append(m.AllowedApiRoles, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowedKubernetesNamespaces\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AllowedKubernetesNamespaces = append(m.AllowedKubernetesNamespaces, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/kubespan/kubespan.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/kubespan/kubespan.proto\n\npackage kubespan\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ConfigSpec describes KubeSpan configuration..\ntype ConfigSpec struct {\n\tstate                       protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled                     bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tClusterId                   string                 `protobuf:\"bytes,2,opt,name=cluster_id,json=clusterId,proto3\" json:\"cluster_id,omitempty\"`\n\tSharedSecret                string                 `protobuf:\"bytes,3,opt,name=shared_secret,json=sharedSecret,proto3\" json:\"shared_secret,omitempty\"`\n\tForceRouting                bool                   `protobuf:\"varint,4,opt,name=force_routing,json=forceRouting,proto3\" json:\"force_routing,omitempty\"`\n\tAdvertiseKubernetesNetworks bool                   `protobuf:\"varint,5,opt,name=advertise_kubernetes_networks,json=advertiseKubernetesNetworks,proto3\" json:\"advertise_kubernetes_networks,omitempty\"`\n\tMtu                         uint32                 `protobuf:\"varint,6,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tEndpointFilters             []string               `protobuf:\"bytes,7,rep,name=endpoint_filters,json=endpointFilters,proto3\" json:\"endpoint_filters,omitempty\"`\n\tHarvestExtraEndpoints       bool                   `protobuf:\"varint,8,opt,name=harvest_extra_endpoints,json=harvestExtraEndpoints,proto3\" json:\"harvest_extra_endpoints,omitempty\"`\n\tExtraEndpoints              []*common.NetIPPort    `protobuf:\"bytes,9,rep,name=extra_endpoints,json=extraEndpoints,proto3\" json:\"extra_endpoints,omitempty\"`\n\tExcludeAdvertisedNetworks   []*common.NetIPPrefix  `protobuf:\"bytes,10,rep,name=exclude_advertised_networks,json=excludeAdvertisedNetworks,proto3\" json:\"exclude_advertised_networks,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *ConfigSpec) Reset() {\n\t*x = ConfigSpec{}\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigSpec) ProtoMessage() {}\n\nfunc (x *ConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ConfigSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetClusterId() string {\n\tif x != nil {\n\t\treturn x.ClusterId\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetSharedSecret() string {\n\tif x != nil {\n\t\treturn x.SharedSecret\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetForceRouting() bool {\n\tif x != nil {\n\t\treturn x.ForceRouting\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetAdvertiseKubernetesNetworks() bool {\n\tif x != nil {\n\t\treturn x.AdvertiseKubernetesNetworks\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\nfunc (x *ConfigSpec) GetEndpointFilters() []string {\n\tif x != nil {\n\t\treturn x.EndpointFilters\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetHarvestExtraEndpoints() bool {\n\tif x != nil {\n\t\treturn x.HarvestExtraEndpoints\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetExtraEndpoints() []*common.NetIPPort {\n\tif x != nil {\n\t\treturn x.ExtraEndpoints\n\t}\n\treturn nil\n}\n\nfunc (x *ConfigSpec) GetExcludeAdvertisedNetworks() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.ExcludeAdvertisedNetworks\n\t}\n\treturn nil\n}\n\n// EndpointSpec describes Endpoint state.\ntype EndpointSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAffiliateId   string                 `protobuf:\"bytes,1,opt,name=affiliate_id,json=affiliateId,proto3\" json:\"affiliate_id,omitempty\"`\n\tEndpoint      *common.NetIPPort      `protobuf:\"bytes,2,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EndpointSpec) Reset() {\n\t*x = EndpointSpec{}\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EndpointSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EndpointSpec) ProtoMessage() {}\n\nfunc (x *EndpointSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EndpointSpec.ProtoReflect.Descriptor instead.\nfunc (*EndpointSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *EndpointSpec) GetAffiliateId() string {\n\tif x != nil {\n\t\treturn x.AffiliateId\n\t}\n\treturn \"\"\n}\n\nfunc (x *EndpointSpec) GetEndpoint() *common.NetIPPort {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn nil\n}\n\n// IdentitySpec describes KubeSpan keys and address.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\ntype IdentitySpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddress       *common.NetIPPrefix    `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tSubnet        *common.NetIPPrefix    `protobuf:\"bytes,2,opt,name=subnet,proto3\" json:\"subnet,omitempty\"`\n\tPrivateKey    string                 `protobuf:\"bytes,3,opt,name=private_key,json=privateKey,proto3\" json:\"private_key,omitempty\"`\n\tPublicKey     string                 `protobuf:\"bytes,4,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *IdentitySpec) Reset() {\n\t*x = IdentitySpec{}\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *IdentitySpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*IdentitySpec) ProtoMessage() {}\n\nfunc (x *IdentitySpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use IdentitySpec.ProtoReflect.Descriptor instead.\nfunc (*IdentitySpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *IdentitySpec) GetAddress() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *IdentitySpec) GetSubnet() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Subnet\n\t}\n\treturn nil\n}\n\nfunc (x *IdentitySpec) GetPrivateKey() string {\n\tif x != nil {\n\t\treturn x.PrivateKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *IdentitySpec) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\n// PeerSpecSpec describes PeerSpec state.\ntype PeerSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddress       *common.NetIP          `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tAllowedIps    []*common.NetIPPrefix  `protobuf:\"bytes,2,rep,name=allowed_ips,json=allowedIps,proto3\" json:\"allowed_ips,omitempty\"`\n\tEndpoints     []*common.NetIPPort    `protobuf:\"bytes,3,rep,name=endpoints,proto3\" json:\"endpoints,omitempty\"`\n\tLabel         string                 `protobuf:\"bytes,4,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PeerSpecSpec) Reset() {\n\t*x = PeerSpecSpec{}\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PeerSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PeerSpecSpec) ProtoMessage() {}\n\nfunc (x *PeerSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PeerSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*PeerSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *PeerSpecSpec) GetAddress() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *PeerSpecSpec) GetAllowedIps() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.AllowedIps\n\t}\n\treturn nil\n}\n\nfunc (x *PeerSpecSpec) GetEndpoints() []*common.NetIPPort {\n\tif x != nil {\n\t\treturn x.Endpoints\n\t}\n\treturn nil\n}\n\nfunc (x *PeerSpecSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\n// PeerStatusSpec describes PeerStatus state.\ntype PeerStatusSpec struct {\n\tstate              protoimpl.MessageState  `protogen:\"open.v1\"`\n\tEndpoint           *common.NetIPPort       `protobuf:\"bytes,1,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tLabel              string                  `protobuf:\"bytes,2,opt,name=label,proto3\" json:\"label,omitempty\"`\n\tState              enums.KubespanPeerState `protobuf:\"varint,3,opt,name=state,proto3,enum=talos.resource.definitions.enums.KubespanPeerState\" json:\"state,omitempty\"`\n\tReceiveBytes       int64                   `protobuf:\"varint,4,opt,name=receive_bytes,json=receiveBytes,proto3\" json:\"receive_bytes,omitempty\"`\n\tTransmitBytes      int64                   `protobuf:\"varint,5,opt,name=transmit_bytes,json=transmitBytes,proto3\" json:\"transmit_bytes,omitempty\"`\n\tLastHandshakeTime  *timestamppb.Timestamp  `protobuf:\"bytes,6,opt,name=last_handshake_time,json=lastHandshakeTime,proto3\" json:\"last_handshake_time,omitempty\"`\n\tLastUsedEndpoint   *common.NetIPPort       `protobuf:\"bytes,7,opt,name=last_used_endpoint,json=lastUsedEndpoint,proto3\" json:\"last_used_endpoint,omitempty\"`\n\tLastEndpointChange *timestamppb.Timestamp  `protobuf:\"bytes,8,opt,name=last_endpoint_change,json=lastEndpointChange,proto3\" json:\"last_endpoint_change,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *PeerStatusSpec) Reset() {\n\t*x = PeerStatusSpec{}\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PeerStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PeerStatusSpec) ProtoMessage() {}\n\nfunc (x *PeerStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_kubespan_kubespan_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PeerStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*PeerStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *PeerStatusSpec) GetEndpoint() *common.NetIPPort {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn nil\n}\n\nfunc (x *PeerStatusSpec) GetLabel() string {\n\tif x != nil {\n\t\treturn x.Label\n\t}\n\treturn \"\"\n}\n\nfunc (x *PeerStatusSpec) GetState() enums.KubespanPeerState {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn enums.KubespanPeerState(0)\n}\n\nfunc (x *PeerStatusSpec) GetReceiveBytes() int64 {\n\tif x != nil {\n\t\treturn x.ReceiveBytes\n\t}\n\treturn 0\n}\n\nfunc (x *PeerStatusSpec) GetTransmitBytes() int64 {\n\tif x != nil {\n\t\treturn x.TransmitBytes\n\t}\n\treturn 0\n}\n\nfunc (x *PeerStatusSpec) GetLastHandshakeTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.LastHandshakeTime\n\t}\n\treturn nil\n}\n\nfunc (x *PeerStatusSpec) GetLastUsedEndpoint() *common.NetIPPort {\n\tif x != nil {\n\t\treturn x.LastUsedEndpoint\n\t}\n\treturn nil\n}\n\nfunc (x *PeerStatusSpec) GetLastEndpointChange() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.LastEndpointChange\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_kubespan_kubespan_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_kubespan_kubespan_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\",resource/definitions/kubespan/kubespan.proto\\x12#talos.resource.definitions.kubespan\\x1a\\x13common/common.proto\\x1a\\x1fgoogle/protobuf/timestamp.proto\\x1a&resource/definitions/enums/enums.proto\\\"\\xd9\\x03\\n\" +\n\t\"\\n\" +\n\t\"ConfigSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"cluster_id\\x18\\x02 \\x01(\\tR\\tclusterId\\x12#\\n\" +\n\t\"\\rshared_secret\\x18\\x03 \\x01(\\tR\\fsharedSecret\\x12#\\n\" +\n\t\"\\rforce_routing\\x18\\x04 \\x01(\\bR\\fforceRouting\\x12B\\n\" +\n\t\"\\x1dadvertise_kubernetes_networks\\x18\\x05 \\x01(\\bR\\x1badvertiseKubernetesNetworks\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\x06 \\x01(\\rR\\x03mtu\\x12)\\n\" +\n\t\"\\x10endpoint_filters\\x18\\a \\x03(\\tR\\x0fendpointFilters\\x126\\n\" +\n\t\"\\x17harvest_extra_endpoints\\x18\\b \\x01(\\bR\\x15harvestExtraEndpoints\\x12:\\n\" +\n\t\"\\x0fextra_endpoints\\x18\\t \\x03(\\v2\\x11.common.NetIPPortR\\x0eextraEndpoints\\x12S\\n\" +\n\t\"\\x1bexclude_advertised_networks\\x18\\n\" +\n\t\" \\x03(\\v2\\x13.common.NetIPPrefixR\\x19excludeAdvertisedNetworks\\\"`\\n\" +\n\t\"\\fEndpointSpec\\x12!\\n\" +\n\t\"\\faffiliate_id\\x18\\x01 \\x01(\\tR\\vaffiliateId\\x12-\\n\" +\n\t\"\\bendpoint\\x18\\x02 \\x01(\\v2\\x11.common.NetIPPortR\\bendpoint\\\"\\xaa\\x01\\n\" +\n\t\"\\fIdentitySpec\\x12-\\n\" +\n\t\"\\aaddress\\x18\\x01 \\x01(\\v2\\x13.common.NetIPPrefixR\\aaddress\\x12+\\n\" +\n\t\"\\x06subnet\\x18\\x02 \\x01(\\v2\\x13.common.NetIPPrefixR\\x06subnet\\x12\\x1f\\n\" +\n\t\"\\vprivate_key\\x18\\x03 \\x01(\\tR\\n\" +\n\t\"privateKey\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"public_key\\x18\\x04 \\x01(\\tR\\tpublicKey\\\"\\xb4\\x01\\n\" +\n\t\"\\fPeerSpecSpec\\x12'\\n\" +\n\t\"\\aaddress\\x18\\x01 \\x01(\\v2\\r.common.NetIPR\\aaddress\\x124\\n\" +\n\t\"\\vallowed_ips\\x18\\x02 \\x03(\\v2\\x13.common.NetIPPrefixR\\n\" +\n\t\"allowedIps\\x12/\\n\" +\n\t\"\\tendpoints\\x18\\x03 \\x03(\\v2\\x11.common.NetIPPortR\\tendpoints\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x04 \\x01(\\tR\\x05label\\\"\\xc7\\x03\\n\" +\n\t\"\\x0ePeerStatusSpec\\x12-\\n\" +\n\t\"\\bendpoint\\x18\\x01 \\x01(\\v2\\x11.common.NetIPPortR\\bendpoint\\x12\\x14\\n\" +\n\t\"\\x05label\\x18\\x02 \\x01(\\tR\\x05label\\x12I\\n\" +\n\t\"\\x05state\\x18\\x03 \\x01(\\x0e23.talos.resource.definitions.enums.KubespanPeerStateR\\x05state\\x12#\\n\" +\n\t\"\\rreceive_bytes\\x18\\x04 \\x01(\\x03R\\freceiveBytes\\x12%\\n\" +\n\t\"\\x0etransmit_bytes\\x18\\x05 \\x01(\\x03R\\rtransmitBytes\\x12J\\n\" +\n\t\"\\x13last_handshake_time\\x18\\x06 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\x11lastHandshakeTime\\x12?\\n\" +\n\t\"\\x12last_used_endpoint\\x18\\a \\x01(\\v2\\x11.common.NetIPPortR\\x10lastUsedEndpoint\\x12L\\n\" +\n\t\"\\x14last_endpoint_change\\x18\\b \\x01(\\v2\\x1a.google.protobuf.TimestampR\\x12lastEndpointChangeBz\\n\" +\n\t\"+dev.talos.api.resource.definitions.kubespanZKgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/kubespanb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_kubespan_kubespan_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_kubespan_kubespan_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_kubespan_kubespan_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_kubespan_kubespan_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_kubespan_kubespan_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_kubespan_kubespan_proto_rawDesc), len(file_resource_definitions_kubespan_kubespan_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_kubespan_kubespan_proto_rawDescData\n}\n\nvar file_resource_definitions_kubespan_kubespan_proto_msgTypes = make([]protoimpl.MessageInfo, 5)\nvar file_resource_definitions_kubespan_kubespan_proto_goTypes = []any{\n\t(*ConfigSpec)(nil),            // 0: talos.resource.definitions.kubespan.ConfigSpec\n\t(*EndpointSpec)(nil),          // 1: talos.resource.definitions.kubespan.EndpointSpec\n\t(*IdentitySpec)(nil),          // 2: talos.resource.definitions.kubespan.IdentitySpec\n\t(*PeerSpecSpec)(nil),          // 3: talos.resource.definitions.kubespan.PeerSpecSpec\n\t(*PeerStatusSpec)(nil),        // 4: talos.resource.definitions.kubespan.PeerStatusSpec\n\t(*common.NetIPPort)(nil),      // 5: common.NetIPPort\n\t(*common.NetIPPrefix)(nil),    // 6: common.NetIPPrefix\n\t(*common.NetIP)(nil),          // 7: common.NetIP\n\t(enums.KubespanPeerState)(0),  // 8: talos.resource.definitions.enums.KubespanPeerState\n\t(*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp\n}\nvar file_resource_definitions_kubespan_kubespan_proto_depIdxs = []int32{\n\t5,  // 0: talos.resource.definitions.kubespan.ConfigSpec.extra_endpoints:type_name -> common.NetIPPort\n\t6,  // 1: talos.resource.definitions.kubespan.ConfigSpec.exclude_advertised_networks:type_name -> common.NetIPPrefix\n\t5,  // 2: talos.resource.definitions.kubespan.EndpointSpec.endpoint:type_name -> common.NetIPPort\n\t6,  // 3: talos.resource.definitions.kubespan.IdentitySpec.address:type_name -> common.NetIPPrefix\n\t6,  // 4: talos.resource.definitions.kubespan.IdentitySpec.subnet:type_name -> common.NetIPPrefix\n\t7,  // 5: talos.resource.definitions.kubespan.PeerSpecSpec.address:type_name -> common.NetIP\n\t6,  // 6: talos.resource.definitions.kubespan.PeerSpecSpec.allowed_ips:type_name -> common.NetIPPrefix\n\t5,  // 7: talos.resource.definitions.kubespan.PeerSpecSpec.endpoints:type_name -> common.NetIPPort\n\t5,  // 8: talos.resource.definitions.kubespan.PeerStatusSpec.endpoint:type_name -> common.NetIPPort\n\t8,  // 9: talos.resource.definitions.kubespan.PeerStatusSpec.state:type_name -> talos.resource.definitions.enums.KubespanPeerState\n\t9,  // 10: talos.resource.definitions.kubespan.PeerStatusSpec.last_handshake_time:type_name -> google.protobuf.Timestamp\n\t5,  // 11: talos.resource.definitions.kubespan.PeerStatusSpec.last_used_endpoint:type_name -> common.NetIPPort\n\t9,  // 12: talos.resource.definitions.kubespan.PeerStatusSpec.last_endpoint_change:type_name -> google.protobuf.Timestamp\n\t13, // [13:13] is the sub-list for method output_type\n\t13, // [13:13] is the sub-list for method input_type\n\t13, // [13:13] is the sub-list for extension type_name\n\t13, // [13:13] is the sub-list for extension extendee\n\t0,  // [0:13] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_kubespan_kubespan_proto_init() }\nfunc file_resource_definitions_kubespan_kubespan_proto_init() {\n\tif File_resource_definitions_kubespan_kubespan_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_kubespan_kubespan_proto_rawDesc), len(file_resource_definitions_kubespan_kubespan_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   5,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_kubespan_kubespan_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_kubespan_kubespan_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_kubespan_kubespan_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_kubespan_kubespan_proto = out.File\n\tfile_resource_definitions_kubespan_kubespan_proto_goTypes = nil\n\tfile_resource_definitions_kubespan_kubespan_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/kubespan/kubespan_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/kubespan/kubespan.proto\n\npackage kubespan\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\ttimestamppb \"github.com/planetscale/vtprotobuf/types/known/timestamppb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb1 \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExcludeAdvertisedNetworks) > 0 {\n\t\tfor iNdEx := len(m.ExcludeAdvertisedNetworks) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExcludeAdvertisedNetworks[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExcludeAdvertisedNetworks[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x52\n\t\t}\n\t}\n\tif len(m.ExtraEndpoints) > 0 {\n\t\tfor iNdEx := len(m.ExtraEndpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExtraEndpoints[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExtraEndpoints[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x4a\n\t\t}\n\t}\n\tif m.HarvestExtraEndpoints {\n\t\ti--\n\t\tif m.HarvestExtraEndpoints {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif len(m.EndpointFilters) > 0 {\n\t\tfor iNdEx := len(m.EndpointFilters) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.EndpointFilters[iNdEx])\n\t\t\tcopy(dAtA[i:], m.EndpointFilters[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.EndpointFilters[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x3a\n\t\t}\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.AdvertiseKubernetesNetworks {\n\t\ti--\n\t\tif m.AdvertiseKubernetesNetworks {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ForceRouting {\n\t\ti--\n\t\tif m.ForceRouting {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.SharedSecret) > 0 {\n\t\ti -= len(m.SharedSecret)\n\t\tcopy(dAtA[i:], m.SharedSecret)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SharedSecret)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.ClusterId) > 0 {\n\t\ti -= len(m.ClusterId)\n\t\tcopy(dAtA[i:], m.ClusterId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ClusterId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EndpointSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EndpointSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EndpointSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Endpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.Endpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Endpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.AffiliateId) > 0 {\n\t\ti -= len(m.AffiliateId)\n\t\tcopy(dAtA[i:], m.AffiliateId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AffiliateId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *IdentitySpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *IdentitySpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *IdentitySpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.PublicKey) > 0 {\n\t\ti -= len(m.PublicKey)\n\t\tcopy(dAtA[i:], m.PublicKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.PrivateKey) > 0 {\n\t\ti -= len(m.PrivateKey)\n\t\tcopy(dAtA[i:], m.PrivateKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrivateKey)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Subnet != nil {\n\t\tif vtmsg, ok := interface{}(m.Subnet).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Subnet)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Address != nil {\n\t\tif vtmsg, ok := interface{}(m.Address).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PeerSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PeerSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PeerSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor iNdEx := len(m.Endpoints) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Endpoints[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Endpoints[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.AllowedIps) > 0 {\n\t\tfor iNdEx := len(m.AllowedIps) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AllowedIps[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AllowedIps[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Address != nil {\n\t\tif vtmsg, ok := interface{}(m.Address).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PeerStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PeerStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PeerStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.LastEndpointChange != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.LastEndpointChange).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.LastUsedEndpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.LastUsedEndpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.LastUsedEndpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.LastHandshakeTime != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.LastHandshakeTime).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.TransmitBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TransmitBytes))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ReceiveBytes != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReceiveBytes))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.State != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.State))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Label) > 0 {\n\t\ti -= len(m.Label)\n\t\tcopy(dAtA[i:], m.Label)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Endpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.Endpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Endpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tl = len(m.ClusterId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SharedSecret)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ForceRouting {\n\t\tn += 2\n\t}\n\tif m.AdvertiseKubernetesNetworks {\n\t\tn += 2\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tif len(m.EndpointFilters) > 0 {\n\t\tfor _, s := range m.EndpointFilters {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.HarvestExtraEndpoints {\n\t\tn += 2\n\t}\n\tif len(m.ExtraEndpoints) > 0 {\n\t\tfor _, e := range m.ExtraEndpoints {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExcludeAdvertisedNetworks) > 0 {\n\t\tfor _, e := range m.ExcludeAdvertisedNetworks {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EndpointSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.AffiliateId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Endpoint != nil {\n\t\tif size, ok := interface{}(m.Endpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Endpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *IdentitySpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Address != nil {\n\t\tif size, ok := interface{}(m.Address).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Address)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Subnet != nil {\n\t\tif size, ok := interface{}(m.Subnet).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Subnet)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PrivateKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PeerSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Address != nil {\n\t\tif size, ok := interface{}(m.Address).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Address)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AllowedIps) > 0 {\n\t\tfor _, e := range m.AllowedIps {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Endpoints) > 0 {\n\t\tfor _, e := range m.Endpoints {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PeerStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Endpoint != nil {\n\t\tif size, ok := interface{}(m.Endpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Endpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Label)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.State != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.State))\n\t}\n\tif m.ReceiveBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReceiveBytes))\n\t}\n\tif m.TransmitBytes != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TransmitBytes))\n\t}\n\tif m.LastHandshakeTime != nil {\n\t\tl = (*timestamppb.Timestamp)(m.LastHandshakeTime).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LastUsedEndpoint != nil {\n\t\tif size, ok := interface{}(m.LastUsedEndpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.LastUsedEndpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LastEndpointChange != nil {\n\t\tl = (*timestamppb.Timestamp)(m.LastEndpointChange).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClusterId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ClusterId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SharedSecret\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SharedSecret = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ForceRouting\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ForceRouting = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdvertiseKubernetesNetworks\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AdvertiseKubernetesNetworks = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EndpointFilters\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.EndpointFilters = append(m.EndpointFilters, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HarvestExtraEndpoints\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.HarvestExtraEndpoints = bool(v != 0)\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExtraEndpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExtraEndpoints = append(m.ExtraEndpoints, &common.NetIPPort{})\n\t\t\tif unmarshal, ok := interface{}(m.ExtraEndpoints[len(m.ExtraEndpoints)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExtraEndpoints[len(m.ExtraEndpoints)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExcludeAdvertisedNetworks\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExcludeAdvertisedNetworks = append(m.ExcludeAdvertisedNetworks, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.ExcludeAdvertisedNetworks[len(m.ExcludeAdvertisedNetworks)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExcludeAdvertisedNetworks[len(m.ExcludeAdvertisedNetworks)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EndpointSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EndpointSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EndpointSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AffiliateId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AffiliateId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Endpoint == nil {\n\t\t\t\tm.Endpoint = &common.NetIPPort{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Endpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *IdentitySpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: IdentitySpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: IdentitySpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Address == nil {\n\t\t\t\tm.Address = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Address).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Address); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Subnet\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Subnet == nil {\n\t\t\t\tm.Subnet = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Subnet).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Subnet); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrivateKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PrivateKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PublicKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PeerSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PeerSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PeerSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Address == nil {\n\t\t\t\tm.Address = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Address).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Address); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowedIps\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AllowedIps = append(m.AllowedIps, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.AllowedIps[len(m.AllowedIps)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AllowedIps[len(m.AllowedIps)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoints\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoints = append(m.Endpoints, &common.NetIPPort{})\n\t\t\tif unmarshal, ok := interface{}(m.Endpoints[len(m.Endpoints)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoints[len(m.Endpoints)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PeerStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PeerStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PeerStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Endpoint == nil {\n\t\t\t\tm.Endpoint = &common.NetIPPort{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Endpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Label\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Label = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tm.State = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.State |= enums.KubespanPeerState(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReceiveBytes\", wireType)\n\t\t\t}\n\t\t\tm.ReceiveBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReceiveBytes |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TransmitBytes\", wireType)\n\t\t\t}\n\t\t\tm.TransmitBytes = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TransmitBytes |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastHandshakeTime\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LastHandshakeTime == nil {\n\t\t\t\tm.LastHandshakeTime = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.LastHandshakeTime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastUsedEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LastUsedEndpoint == nil {\n\t\t\t\tm.LastUsedEndpoint = &common.NetIPPort{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.LastUsedEndpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.LastUsedEndpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastEndpointChange\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LastEndpointChange == nil {\n\t\t\t\tm.LastEndpointChange = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.LastEndpointChange).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/network/network.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/network/network.proto\n\npackage network\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n\truntime \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/runtime\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// AddressSpecSpec describes status of rendered secrets.\ntype AddressSpecSpec struct {\n\tstate           protoimpl.MessageState   `protogen:\"open.v1\"`\n\tAddress         *common.NetIPPrefix      `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tLinkName        string                   `protobuf:\"bytes,2,opt,name=link_name,json=linkName,proto3\" json:\"link_name,omitempty\"`\n\tFamily          enums.NethelpersFamily   `protobuf:\"varint,3,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tScope           enums.NethelpersScope    `protobuf:\"varint,4,opt,name=scope,proto3,enum=talos.resource.definitions.enums.NethelpersScope\" json:\"scope,omitempty\"`\n\tFlags           uint32                   `protobuf:\"varint,5,opt,name=flags,proto3\" json:\"flags,omitempty\"`\n\tAnnounceWithArp bool                     `protobuf:\"varint,6,opt,name=announce_with_arp,json=announceWithArp,proto3\" json:\"announce_with_arp,omitempty\"`\n\tConfigLayer     enums.NetworkConfigLayer `protobuf:\"varint,7,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tPriority        uint32                   `protobuf:\"varint,8,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *AddressSpecSpec) Reset() {\n\t*x = AddressSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AddressSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddressSpecSpec) ProtoMessage() {}\n\nfunc (x *AddressSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddressSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*AddressSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *AddressSpecSpec) GetAddress() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *AddressSpecSpec) GetLinkName() string {\n\tif x != nil {\n\t\treturn x.LinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddressSpecSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *AddressSpecSpec) GetScope() enums.NethelpersScope {\n\tif x != nil {\n\t\treturn x.Scope\n\t}\n\treturn enums.NethelpersScope(0)\n}\n\nfunc (x *AddressSpecSpec) GetFlags() uint32 {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn 0\n}\n\nfunc (x *AddressSpecSpec) GetAnnounceWithArp() bool {\n\tif x != nil {\n\t\treturn x.AnnounceWithArp\n\t}\n\treturn false\n}\n\nfunc (x *AddressSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\nfunc (x *AddressSpecSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\n// AddressStatusSpec describes status of rendered secrets.\ntype AddressStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddress       *common.NetIPPrefix    `protobuf:\"bytes,1,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tLocal         *common.NetIP          `protobuf:\"bytes,2,opt,name=local,proto3\" json:\"local,omitempty\"`\n\tBroadcast     *common.NetIP          `protobuf:\"bytes,3,opt,name=broadcast,proto3\" json:\"broadcast,omitempty\"`\n\tAnycast       *common.NetIP          `protobuf:\"bytes,4,opt,name=anycast,proto3\" json:\"anycast,omitempty\"`\n\tMulticast     *common.NetIP          `protobuf:\"bytes,5,opt,name=multicast,proto3\" json:\"multicast,omitempty\"`\n\tLinkIndex     uint32                 `protobuf:\"varint,6,opt,name=link_index,json=linkIndex,proto3\" json:\"link_index,omitempty\"`\n\tLinkName      string                 `protobuf:\"bytes,7,opt,name=link_name,json=linkName,proto3\" json:\"link_name,omitempty\"`\n\tFamily        enums.NethelpersFamily `protobuf:\"varint,8,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tScope         enums.NethelpersScope  `protobuf:\"varint,9,opt,name=scope,proto3,enum=talos.resource.definitions.enums.NethelpersScope\" json:\"scope,omitempty\"`\n\tFlags         uint32                 `protobuf:\"varint,10,opt,name=flags,proto3\" json:\"flags,omitempty\"`\n\tPriority      uint32                 `protobuf:\"varint,11,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *AddressStatusSpec) Reset() {\n\t*x = AddressStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AddressStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AddressStatusSpec) ProtoMessage() {}\n\nfunc (x *AddressStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AddressStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*AddressStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *AddressStatusSpec) GetAddress() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn nil\n}\n\nfunc (x *AddressStatusSpec) GetLocal() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Local\n\t}\n\treturn nil\n}\n\nfunc (x *AddressStatusSpec) GetBroadcast() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Broadcast\n\t}\n\treturn nil\n}\n\nfunc (x *AddressStatusSpec) GetAnycast() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Anycast\n\t}\n\treturn nil\n}\n\nfunc (x *AddressStatusSpec) GetMulticast() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Multicast\n\t}\n\treturn nil\n}\n\nfunc (x *AddressStatusSpec) GetLinkIndex() uint32 {\n\tif x != nil {\n\t\treturn x.LinkIndex\n\t}\n\treturn 0\n}\n\nfunc (x *AddressStatusSpec) GetLinkName() string {\n\tif x != nil {\n\t\treturn x.LinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *AddressStatusSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *AddressStatusSpec) GetScope() enums.NethelpersScope {\n\tif x != nil {\n\t\treturn x.Scope\n\t}\n\treturn enums.NethelpersScope(0)\n}\n\nfunc (x *AddressStatusSpec) GetFlags() uint32 {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn 0\n}\n\nfunc (x *AddressStatusSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\n// BondMasterSpec describes bond settings if Kind == \"bond\".\ntype BondMasterSpec struct {\n\tstate           protoimpl.MessageState             `protogen:\"open.v1\"`\n\tMode            enums.NethelpersBondMode           `protobuf:\"varint,1,opt,name=mode,proto3,enum=talos.resource.definitions.enums.NethelpersBondMode\" json:\"mode,omitempty\"`\n\tHashPolicy      enums.NethelpersBondXmitHashPolicy `protobuf:\"varint,2,opt,name=hash_policy,json=hashPolicy,proto3,enum=talos.resource.definitions.enums.NethelpersBondXmitHashPolicy\" json:\"hash_policy,omitempty\"`\n\tLacpRate        enums.NethelpersLACPRate           `protobuf:\"varint,3,opt,name=lacp_rate,json=lacpRate,proto3,enum=talos.resource.definitions.enums.NethelpersLACPRate\" json:\"lacp_rate,omitempty\"`\n\tArpValidate     enums.NethelpersARPValidate        `protobuf:\"varint,4,opt,name=arp_validate,json=arpValidate,proto3,enum=talos.resource.definitions.enums.NethelpersARPValidate\" json:\"arp_validate,omitempty\"`\n\tArpAllTargets   enums.NethelpersARPAllTargets      `protobuf:\"varint,5,opt,name=arp_all_targets,json=arpAllTargets,proto3,enum=talos.resource.definitions.enums.NethelpersARPAllTargets\" json:\"arp_all_targets,omitempty\"`\n\tPrimaryIndex    uint32                             `protobuf:\"varint,6,opt,name=primary_index,json=primaryIndex,proto3\" json:\"primary_index,omitempty\"`\n\tPrimaryReselect enums.NethelpersPrimaryReselect    `protobuf:\"varint,7,opt,name=primary_reselect,json=primaryReselect,proto3,enum=talos.resource.definitions.enums.NethelpersPrimaryReselect\" json:\"primary_reselect,omitempty\"`\n\tFailOverMac     enums.NethelpersFailOverMAC        `protobuf:\"varint,8,opt,name=fail_over_mac,json=failOverMac,proto3,enum=talos.resource.definitions.enums.NethelpersFailOverMAC\" json:\"fail_over_mac,omitempty\"`\n\tAdSelect        enums.NethelpersADSelect           `protobuf:\"varint,9,opt,name=ad_select,json=adSelect,proto3,enum=talos.resource.definitions.enums.NethelpersADSelect\" json:\"ad_select,omitempty\"`\n\tMiiMon          uint32                             `protobuf:\"varint,10,opt,name=mii_mon,json=miiMon,proto3\" json:\"mii_mon,omitempty\"`\n\tUpDelay         uint32                             `protobuf:\"varint,11,opt,name=up_delay,json=upDelay,proto3\" json:\"up_delay,omitempty\"`\n\tDownDelay       uint32                             `protobuf:\"varint,12,opt,name=down_delay,json=downDelay,proto3\" json:\"down_delay,omitempty\"`\n\tArpInterval     uint32                             `protobuf:\"varint,13,opt,name=arp_interval,json=arpInterval,proto3\" json:\"arp_interval,omitempty\"`\n\tResendIgmp      uint32                             `protobuf:\"varint,14,opt,name=resend_igmp,json=resendIgmp,proto3\" json:\"resend_igmp,omitempty\"`\n\tMinLinks        uint32                             `protobuf:\"varint,15,opt,name=min_links,json=minLinks,proto3\" json:\"min_links,omitempty\"`\n\tLpInterval      uint32                             `protobuf:\"varint,16,opt,name=lp_interval,json=lpInterval,proto3\" json:\"lp_interval,omitempty\"`\n\tPacketsPerSlave uint32                             `protobuf:\"varint,17,opt,name=packets_per_slave,json=packetsPerSlave,proto3\" json:\"packets_per_slave,omitempty\"`\n\tNumPeerNotif    uint32                             `protobuf:\"varint,18,opt,name=num_peer_notif,json=numPeerNotif,proto3\" json:\"num_peer_notif,omitempty\"`\n\tTlbDynamicLb    uint32                             `protobuf:\"varint,19,opt,name=tlb_dynamic_lb,json=tlbDynamicLb,proto3\" json:\"tlb_dynamic_lb,omitempty\"`\n\tAllSlavesActive uint32                             `protobuf:\"varint,20,opt,name=all_slaves_active,json=allSlavesActive,proto3\" json:\"all_slaves_active,omitempty\"`\n\tUseCarrier      bool                               `protobuf:\"varint,21,opt,name=use_carrier,json=useCarrier,proto3\" json:\"use_carrier,omitempty\"`\n\tAdActorSysPrio  uint32                             `protobuf:\"varint,22,opt,name=ad_actor_sys_prio,json=adActorSysPrio,proto3\" json:\"ad_actor_sys_prio,omitempty\"`\n\tAdUserPortKey   uint32                             `protobuf:\"varint,23,opt,name=ad_user_port_key,json=adUserPortKey,proto3\" json:\"ad_user_port_key,omitempty\"`\n\tPeerNotifyDelay uint32                             `protobuf:\"varint,24,opt,name=peer_notify_delay,json=peerNotifyDelay,proto3\" json:\"peer_notify_delay,omitempty\"`\n\tArpipTargets    []*common.NetIP                    `protobuf:\"bytes,25,rep,name=arpip_targets,json=arpipTargets,proto3\" json:\"arpip_targets,omitempty\"`\n\tNsip6Targets    []*common.NetIP                    `protobuf:\"bytes,26,rep,name=nsip6_targets,json=nsip6Targets,proto3\" json:\"nsip6_targets,omitempty\"`\n\tAdlacpActive    enums.NethelpersADLACPActive       `protobuf:\"varint,27,opt,name=adlacp_active,json=adlacpActive,proto3,enum=talos.resource.definitions.enums.NethelpersADLACPActive\" json:\"adlacp_active,omitempty\"`\n\tMissedMax       uint32                             `protobuf:\"varint,28,opt,name=missed_max,json=missedMax,proto3\" json:\"missed_max,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *BondMasterSpec) Reset() {\n\t*x = BondMasterSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BondMasterSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BondMasterSpec) ProtoMessage() {}\n\nfunc (x *BondMasterSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BondMasterSpec.ProtoReflect.Descriptor instead.\nfunc (*BondMasterSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *BondMasterSpec) GetMode() enums.NethelpersBondMode {\n\tif x != nil {\n\t\treturn x.Mode\n\t}\n\treturn enums.NethelpersBondMode(0)\n}\n\nfunc (x *BondMasterSpec) GetHashPolicy() enums.NethelpersBondXmitHashPolicy {\n\tif x != nil {\n\t\treturn x.HashPolicy\n\t}\n\treturn enums.NethelpersBondXmitHashPolicy(0)\n}\n\nfunc (x *BondMasterSpec) GetLacpRate() enums.NethelpersLACPRate {\n\tif x != nil {\n\t\treturn x.LacpRate\n\t}\n\treturn enums.NethelpersLACPRate(0)\n}\n\nfunc (x *BondMasterSpec) GetArpValidate() enums.NethelpersARPValidate {\n\tif x != nil {\n\t\treturn x.ArpValidate\n\t}\n\treturn enums.NethelpersARPValidate(0)\n}\n\nfunc (x *BondMasterSpec) GetArpAllTargets() enums.NethelpersARPAllTargets {\n\tif x != nil {\n\t\treturn x.ArpAllTargets\n\t}\n\treturn enums.NethelpersARPAllTargets(0)\n}\n\nfunc (x *BondMasterSpec) GetPrimaryIndex() uint32 {\n\tif x != nil {\n\t\treturn x.PrimaryIndex\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetPrimaryReselect() enums.NethelpersPrimaryReselect {\n\tif x != nil {\n\t\treturn x.PrimaryReselect\n\t}\n\treturn enums.NethelpersPrimaryReselect(0)\n}\n\nfunc (x *BondMasterSpec) GetFailOverMac() enums.NethelpersFailOverMAC {\n\tif x != nil {\n\t\treturn x.FailOverMac\n\t}\n\treturn enums.NethelpersFailOverMAC(0)\n}\n\nfunc (x *BondMasterSpec) GetAdSelect() enums.NethelpersADSelect {\n\tif x != nil {\n\t\treturn x.AdSelect\n\t}\n\treturn enums.NethelpersADSelect(0)\n}\n\nfunc (x *BondMasterSpec) GetMiiMon() uint32 {\n\tif x != nil {\n\t\treturn x.MiiMon\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetUpDelay() uint32 {\n\tif x != nil {\n\t\treturn x.UpDelay\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetDownDelay() uint32 {\n\tif x != nil {\n\t\treturn x.DownDelay\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetArpInterval() uint32 {\n\tif x != nil {\n\t\treturn x.ArpInterval\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetResendIgmp() uint32 {\n\tif x != nil {\n\t\treturn x.ResendIgmp\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetMinLinks() uint32 {\n\tif x != nil {\n\t\treturn x.MinLinks\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetLpInterval() uint32 {\n\tif x != nil {\n\t\treturn x.LpInterval\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetPacketsPerSlave() uint32 {\n\tif x != nil {\n\t\treturn x.PacketsPerSlave\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetNumPeerNotif() uint32 {\n\tif x != nil {\n\t\treturn x.NumPeerNotif\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetTlbDynamicLb() uint32 {\n\tif x != nil {\n\t\treturn x.TlbDynamicLb\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetAllSlavesActive() uint32 {\n\tif x != nil {\n\t\treturn x.AllSlavesActive\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetUseCarrier() bool {\n\tif x != nil {\n\t\treturn x.UseCarrier\n\t}\n\treturn false\n}\n\nfunc (x *BondMasterSpec) GetAdActorSysPrio() uint32 {\n\tif x != nil {\n\t\treturn x.AdActorSysPrio\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetAdUserPortKey() uint32 {\n\tif x != nil {\n\t\treturn x.AdUserPortKey\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetPeerNotifyDelay() uint32 {\n\tif x != nil {\n\t\treturn x.PeerNotifyDelay\n\t}\n\treturn 0\n}\n\nfunc (x *BondMasterSpec) GetArpipTargets() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ArpipTargets\n\t}\n\treturn nil\n}\n\nfunc (x *BondMasterSpec) GetNsip6Targets() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.Nsip6Targets\n\t}\n\treturn nil\n}\n\nfunc (x *BondMasterSpec) GetAdlacpActive() enums.NethelpersADLACPActive {\n\tif x != nil {\n\t\treturn x.AdlacpActive\n\t}\n\treturn enums.NethelpersADLACPActive(0)\n}\n\nfunc (x *BondMasterSpec) GetMissedMax() uint32 {\n\tif x != nil {\n\t\treturn x.MissedMax\n\t}\n\treturn 0\n}\n\n// BondSlave contains a bond's master name and slave index.\ntype BondSlave struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMasterName    string                 `protobuf:\"bytes,1,opt,name=master_name,json=masterName,proto3\" json:\"master_name,omitempty\"`\n\tSlaveIndex    int64                  `protobuf:\"varint,2,opt,name=slave_index,json=slaveIndex,proto3\" json:\"slave_index,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BondSlave) Reset() {\n\t*x = BondSlave{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BondSlave) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BondSlave) ProtoMessage() {}\n\nfunc (x *BondSlave) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BondSlave.ProtoReflect.Descriptor instead.\nfunc (*BondSlave) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *BondSlave) GetMasterName() string {\n\tif x != nil {\n\t\treturn x.MasterName\n\t}\n\treturn \"\"\n}\n\nfunc (x *BondSlave) GetSlaveIndex() int64 {\n\tif x != nil {\n\t\treturn x.SlaveIndex\n\t}\n\treturn 0\n}\n\n// BridgeMasterSpec describes bridge settings if Kind == \"bridge\".\ntype BridgeMasterSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tStp           *STPSpec               `protobuf:\"bytes,1,opt,name=stp,proto3\" json:\"stp,omitempty\"`\n\tVlan          *BridgeVLANSpec        `protobuf:\"bytes,2,opt,name=vlan,proto3\" json:\"vlan,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BridgeMasterSpec) Reset() {\n\t*x = BridgeMasterSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BridgeMasterSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BridgeMasterSpec) ProtoMessage() {}\n\nfunc (x *BridgeMasterSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BridgeMasterSpec.ProtoReflect.Descriptor instead.\nfunc (*BridgeMasterSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *BridgeMasterSpec) GetStp() *STPSpec {\n\tif x != nil {\n\t\treturn x.Stp\n\t}\n\treturn nil\n}\n\nfunc (x *BridgeMasterSpec) GetVlan() *BridgeVLANSpec {\n\tif x != nil {\n\t\treturn x.Vlan\n\t}\n\treturn nil\n}\n\n// BridgeSlave contains the name of the master bridge of a bridged interface\ntype BridgeSlave struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMasterName    string                 `protobuf:\"bytes,1,opt,name=master_name,json=masterName,proto3\" json:\"master_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BridgeSlave) Reset() {\n\t*x = BridgeSlave{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BridgeSlave) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BridgeSlave) ProtoMessage() {}\n\nfunc (x *BridgeSlave) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BridgeSlave.ProtoReflect.Descriptor instead.\nfunc (*BridgeSlave) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *BridgeSlave) GetMasterName() string {\n\tif x != nil {\n\t\treturn x.MasterName\n\t}\n\treturn \"\"\n}\n\n// BridgeVLANSpec describes VLAN settings of a bridge.\ntype BridgeVLANSpec struct {\n\tstate            protoimpl.MessageState `protogen:\"open.v1\"`\n\tFilteringEnabled bool                   `protobuf:\"varint,1,opt,name=filtering_enabled,json=filteringEnabled,proto3\" json:\"filtering_enabled,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *BridgeVLANSpec) Reset() {\n\t*x = BridgeVLANSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BridgeVLANSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BridgeVLANSpec) ProtoMessage() {}\n\nfunc (x *BridgeVLANSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BridgeVLANSpec.ProtoReflect.Descriptor instead.\nfunc (*BridgeVLANSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *BridgeVLANSpec) GetFilteringEnabled() bool {\n\tif x != nil {\n\t\treturn x.FilteringEnabled\n\t}\n\treturn false\n}\n\n// ClientIdentifierSpec is a shared DHCP4/DHCP6 client identifier spec.\ntype ClientIdentifierSpec struct {\n\tstate            protoimpl.MessageState           `protogen:\"open.v1\"`\n\tClientIdentifier enums.NethelpersClientIdentifier `protobuf:\"varint,1,opt,name=client_identifier,json=clientIdentifier,proto3,enum=talos.resource.definitions.enums.NethelpersClientIdentifier\" json:\"client_identifier,omitempty\"`\n\tDuidRawHex       string                           `protobuf:\"bytes,2,opt,name=duid_raw_hex,json=duidRawHex,proto3\" json:\"duid_raw_hex,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ClientIdentifierSpec) Reset() {\n\t*x = ClientIdentifierSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ClientIdentifierSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ClientIdentifierSpec) ProtoMessage() {}\n\nfunc (x *ClientIdentifierSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ClientIdentifierSpec.ProtoReflect.Descriptor instead.\nfunc (*ClientIdentifierSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *ClientIdentifierSpec) GetClientIdentifier() enums.NethelpersClientIdentifier {\n\tif x != nil {\n\t\treturn x.ClientIdentifier\n\t}\n\treturn enums.NethelpersClientIdentifier(0)\n}\n\nfunc (x *ClientIdentifierSpec) GetDuidRawHex() string {\n\tif x != nil {\n\t\treturn x.DuidRawHex\n\t}\n\treturn \"\"\n}\n\n// DHCP4OperatorSpec describes DHCP4 operator options.\ntype DHCP4OperatorSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tRouteMetric         uint32                 `protobuf:\"varint,1,opt,name=route_metric,json=routeMetric,proto3\" json:\"route_metric,omitempty\"`\n\tSkipHostnameRequest bool                   `protobuf:\"varint,2,opt,name=skip_hostname_request,json=skipHostnameRequest,proto3\" json:\"skip_hostname_request,omitempty\"`\n\tClientIdentifier    *ClientIdentifierSpec  `protobuf:\"bytes,3,opt,name=client_identifier,json=clientIdentifier,proto3\" json:\"client_identifier,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *DHCP4OperatorSpec) Reset() {\n\t*x = DHCP4OperatorSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DHCP4OperatorSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DHCP4OperatorSpec) ProtoMessage() {}\n\nfunc (x *DHCP4OperatorSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DHCP4OperatorSpec.ProtoReflect.Descriptor instead.\nfunc (*DHCP4OperatorSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *DHCP4OperatorSpec) GetRouteMetric() uint32 {\n\tif x != nil {\n\t\treturn x.RouteMetric\n\t}\n\treturn 0\n}\n\nfunc (x *DHCP4OperatorSpec) GetSkipHostnameRequest() bool {\n\tif x != nil {\n\t\treturn x.SkipHostnameRequest\n\t}\n\treturn false\n}\n\nfunc (x *DHCP4OperatorSpec) GetClientIdentifier() *ClientIdentifierSpec {\n\tif x != nil {\n\t\treturn x.ClientIdentifier\n\t}\n\treturn nil\n}\n\n// DHCP6OperatorSpec describes DHCP6 operator options.\ntype DHCP6OperatorSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tRouteMetric         uint32                 `protobuf:\"varint,2,opt,name=route_metric,json=routeMetric,proto3\" json:\"route_metric,omitempty\"`\n\tSkipHostnameRequest bool                   `protobuf:\"varint,3,opt,name=skip_hostname_request,json=skipHostnameRequest,proto3\" json:\"skip_hostname_request,omitempty\"`\n\tClientIdentifier    *ClientIdentifierSpec  `protobuf:\"bytes,4,opt,name=client_identifier,json=clientIdentifier,proto3\" json:\"client_identifier,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *DHCP6OperatorSpec) Reset() {\n\t*x = DHCP6OperatorSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DHCP6OperatorSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DHCP6OperatorSpec) ProtoMessage() {}\n\nfunc (x *DHCP6OperatorSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DHCP6OperatorSpec.ProtoReflect.Descriptor instead.\nfunc (*DHCP6OperatorSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *DHCP6OperatorSpec) GetRouteMetric() uint32 {\n\tif x != nil {\n\t\treturn x.RouteMetric\n\t}\n\treturn 0\n}\n\nfunc (x *DHCP6OperatorSpec) GetSkipHostnameRequest() bool {\n\tif x != nil {\n\t\treturn x.SkipHostnameRequest\n\t}\n\treturn false\n}\n\nfunc (x *DHCP6OperatorSpec) GetClientIdentifier() *ClientIdentifierSpec {\n\tif x != nil {\n\t\treturn x.ClientIdentifier\n\t}\n\treturn nil\n}\n\n// DNSResolveCacheSpec describes DNS servers status.\ntype DNSResolveCacheSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tStatus        string                 `protobuf:\"bytes,1,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DNSResolveCacheSpec) Reset() {\n\t*x = DNSResolveCacheSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DNSResolveCacheSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DNSResolveCacheSpec) ProtoMessage() {}\n\nfunc (x *DNSResolveCacheSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DNSResolveCacheSpec.ProtoReflect.Descriptor instead.\nfunc (*DNSResolveCacheSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *DNSResolveCacheSpec) GetStatus() string {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn \"\"\n}\n\n// EthernetChannelsSpec describes config of Ethernet channels.\ntype EthernetChannelsSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRx            uint32                 `protobuf:\"varint,1,opt,name=rx,proto3\" json:\"rx,omitempty\"`\n\tTx            uint32                 `protobuf:\"varint,2,opt,name=tx,proto3\" json:\"tx,omitempty\"`\n\tOther         uint32                 `protobuf:\"varint,3,opt,name=other,proto3\" json:\"other,omitempty\"`\n\tCombined      uint32                 `protobuf:\"varint,4,opt,name=combined,proto3\" json:\"combined,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetChannelsSpec) Reset() {\n\t*x = EthernetChannelsSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetChannelsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetChannelsSpec) ProtoMessage() {}\n\nfunc (x *EthernetChannelsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetChannelsSpec.ProtoReflect.Descriptor instead.\nfunc (*EthernetChannelsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *EthernetChannelsSpec) GetRx() uint32 {\n\tif x != nil {\n\t\treturn x.Rx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsSpec) GetTx() uint32 {\n\tif x != nil {\n\t\treturn x.Tx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsSpec) GetOther() uint32 {\n\tif x != nil {\n\t\treturn x.Other\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsSpec) GetCombined() uint32 {\n\tif x != nil {\n\t\treturn x.Combined\n\t}\n\treturn 0\n}\n\n// EthernetChannelsStatus describes status of Ethernet channels.\ntype EthernetChannelsStatus struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRxMax         uint32                 `protobuf:\"varint,1,opt,name=rx_max,json=rxMax,proto3\" json:\"rx_max,omitempty\"`\n\tTxMax         uint32                 `protobuf:\"varint,2,opt,name=tx_max,json=txMax,proto3\" json:\"tx_max,omitempty\"`\n\tOtherMax      uint32                 `protobuf:\"varint,3,opt,name=other_max,json=otherMax,proto3\" json:\"other_max,omitempty\"`\n\tCombinedMax   uint32                 `protobuf:\"varint,4,opt,name=combined_max,json=combinedMax,proto3\" json:\"combined_max,omitempty\"`\n\tRx            uint32                 `protobuf:\"varint,5,opt,name=rx,proto3\" json:\"rx,omitempty\"`\n\tTx            uint32                 `protobuf:\"varint,6,opt,name=tx,proto3\" json:\"tx,omitempty\"`\n\tOther         uint32                 `protobuf:\"varint,7,opt,name=other,proto3\" json:\"other,omitempty\"`\n\tCombined      uint32                 `protobuf:\"varint,8,opt,name=combined,proto3\" json:\"combined,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetChannelsStatus) Reset() {\n\t*x = EthernetChannelsStatus{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetChannelsStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetChannelsStatus) ProtoMessage() {}\n\nfunc (x *EthernetChannelsStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetChannelsStatus.ProtoReflect.Descriptor instead.\nfunc (*EthernetChannelsStatus) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *EthernetChannelsStatus) GetRxMax() uint32 {\n\tif x != nil {\n\t\treturn x.RxMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetTxMax() uint32 {\n\tif x != nil {\n\t\treturn x.TxMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetOtherMax() uint32 {\n\tif x != nil {\n\t\treturn x.OtherMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetCombinedMax() uint32 {\n\tif x != nil {\n\t\treturn x.CombinedMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetRx() uint32 {\n\tif x != nil {\n\t\treturn x.Rx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetTx() uint32 {\n\tif x != nil {\n\t\treturn x.Tx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetOther() uint32 {\n\tif x != nil {\n\t\treturn x.Other\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetChannelsStatus) GetCombined() uint32 {\n\tif x != nil {\n\t\treturn x.Combined\n\t}\n\treturn 0\n}\n\n// EthernetFeatureStatus describes status of Ethernet features.\ntype EthernetFeatureStatus struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tStatus        string                 `protobuf:\"bytes,2,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetFeatureStatus) Reset() {\n\t*x = EthernetFeatureStatus{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetFeatureStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetFeatureStatus) ProtoMessage() {}\n\nfunc (x *EthernetFeatureStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetFeatureStatus.ProtoReflect.Descriptor instead.\nfunc (*EthernetFeatureStatus) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *EthernetFeatureStatus) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *EthernetFeatureStatus) GetStatus() string {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn \"\"\n}\n\n// EthernetRingsSpec describes config of Ethernet rings.\ntype EthernetRingsSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRx            uint32                 `protobuf:\"varint,1,opt,name=rx,proto3\" json:\"rx,omitempty\"`\n\tRxMini        uint32                 `protobuf:\"varint,2,opt,name=rx_mini,json=rxMini,proto3\" json:\"rx_mini,omitempty\"`\n\tRxJumbo       uint32                 `protobuf:\"varint,3,opt,name=rx_jumbo,json=rxJumbo,proto3\" json:\"rx_jumbo,omitempty\"`\n\tTx            uint32                 `protobuf:\"varint,4,opt,name=tx,proto3\" json:\"tx,omitempty\"`\n\tRxBufLen      uint32                 `protobuf:\"varint,5,opt,name=rx_buf_len,json=rxBufLen,proto3\" json:\"rx_buf_len,omitempty\"`\n\tCqeSize       uint32                 `protobuf:\"varint,6,opt,name=cqe_size,json=cqeSize,proto3\" json:\"cqe_size,omitempty\"`\n\tTxPush        bool                   `protobuf:\"varint,7,opt,name=tx_push,json=txPush,proto3\" json:\"tx_push,omitempty\"`\n\tRxPush        bool                   `protobuf:\"varint,8,opt,name=rx_push,json=rxPush,proto3\" json:\"rx_push,omitempty\"`\n\tTxPushBufLen  uint32                 `protobuf:\"varint,9,opt,name=tx_push_buf_len,json=txPushBufLen,proto3\" json:\"tx_push_buf_len,omitempty\"`\n\tTcpDataSplit  bool                   `protobuf:\"varint,10,opt,name=tcp_data_split,json=tcpDataSplit,proto3\" json:\"tcp_data_split,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetRingsSpec) Reset() {\n\t*x = EthernetRingsSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetRingsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetRingsSpec) ProtoMessage() {}\n\nfunc (x *EthernetRingsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetRingsSpec.ProtoReflect.Descriptor instead.\nfunc (*EthernetRingsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *EthernetRingsSpec) GetRx() uint32 {\n\tif x != nil {\n\t\treturn x.Rx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetRxMini() uint32 {\n\tif x != nil {\n\t\treturn x.RxMini\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetRxJumbo() uint32 {\n\tif x != nil {\n\t\treturn x.RxJumbo\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetTx() uint32 {\n\tif x != nil {\n\t\treturn x.Tx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetRxBufLen() uint32 {\n\tif x != nil {\n\t\treturn x.RxBufLen\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetCqeSize() uint32 {\n\tif x != nil {\n\t\treturn x.CqeSize\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetTxPush() bool {\n\tif x != nil {\n\t\treturn x.TxPush\n\t}\n\treturn false\n}\n\nfunc (x *EthernetRingsSpec) GetRxPush() bool {\n\tif x != nil {\n\t\treturn x.RxPush\n\t}\n\treturn false\n}\n\nfunc (x *EthernetRingsSpec) GetTxPushBufLen() uint32 {\n\tif x != nil {\n\t\treturn x.TxPushBufLen\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsSpec) GetTcpDataSplit() bool {\n\tif x != nil {\n\t\treturn x.TcpDataSplit\n\t}\n\treturn false\n}\n\n// EthernetRingsStatus describes status of Ethernet rings.\ntype EthernetRingsStatus struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tRxMax           uint32                 `protobuf:\"varint,1,opt,name=rx_max,json=rxMax,proto3\" json:\"rx_max,omitempty\"`\n\tRxMiniMax       uint32                 `protobuf:\"varint,2,opt,name=rx_mini_max,json=rxMiniMax,proto3\" json:\"rx_mini_max,omitempty\"`\n\tRxJumboMax      uint32                 `protobuf:\"varint,3,opt,name=rx_jumbo_max,json=rxJumboMax,proto3\" json:\"rx_jumbo_max,omitempty\"`\n\tTxMax           uint32                 `protobuf:\"varint,4,opt,name=tx_max,json=txMax,proto3\" json:\"tx_max,omitempty\"`\n\tTxPushBufLenMax uint32                 `protobuf:\"varint,5,opt,name=tx_push_buf_len_max,json=txPushBufLenMax,proto3\" json:\"tx_push_buf_len_max,omitempty\"`\n\tRx              uint32                 `protobuf:\"varint,6,opt,name=rx,proto3\" json:\"rx,omitempty\"`\n\tRxMini          uint32                 `protobuf:\"varint,7,opt,name=rx_mini,json=rxMini,proto3\" json:\"rx_mini,omitempty\"`\n\tRxJumbo         uint32                 `protobuf:\"varint,8,opt,name=rx_jumbo,json=rxJumbo,proto3\" json:\"rx_jumbo,omitempty\"`\n\tTx              uint32                 `protobuf:\"varint,9,opt,name=tx,proto3\" json:\"tx,omitempty\"`\n\tRxBufLen        uint32                 `protobuf:\"varint,10,opt,name=rx_buf_len,json=rxBufLen,proto3\" json:\"rx_buf_len,omitempty\"`\n\tCqeSize         uint32                 `protobuf:\"varint,11,opt,name=cqe_size,json=cqeSize,proto3\" json:\"cqe_size,omitempty\"`\n\tTxPush          bool                   `protobuf:\"varint,12,opt,name=tx_push,json=txPush,proto3\" json:\"tx_push,omitempty\"`\n\tRxPush          bool                   `protobuf:\"varint,13,opt,name=rx_push,json=rxPush,proto3\" json:\"rx_push,omitempty\"`\n\tTxPushBufLen    uint32                 `protobuf:\"varint,14,opt,name=tx_push_buf_len,json=txPushBufLen,proto3\" json:\"tx_push_buf_len,omitempty\"`\n\tTcpDataSplit    bool                   `protobuf:\"varint,15,opt,name=tcp_data_split,json=tcpDataSplit,proto3\" json:\"tcp_data_split,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *EthernetRingsStatus) Reset() {\n\t*x = EthernetRingsStatus{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[15]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetRingsStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetRingsStatus) ProtoMessage() {}\n\nfunc (x *EthernetRingsStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[15]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetRingsStatus.ProtoReflect.Descriptor instead.\nfunc (*EthernetRingsStatus) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *EthernetRingsStatus) GetRxMax() uint32 {\n\tif x != nil {\n\t\treturn x.RxMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRxMiniMax() uint32 {\n\tif x != nil {\n\t\treturn x.RxMiniMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRxJumboMax() uint32 {\n\tif x != nil {\n\t\treturn x.RxJumboMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetTxMax() uint32 {\n\tif x != nil {\n\t\treturn x.TxMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetTxPushBufLenMax() uint32 {\n\tif x != nil {\n\t\treturn x.TxPushBufLenMax\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRx() uint32 {\n\tif x != nil {\n\t\treturn x.Rx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRxMini() uint32 {\n\tif x != nil {\n\t\treturn x.RxMini\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRxJumbo() uint32 {\n\tif x != nil {\n\t\treturn x.RxJumbo\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetTx() uint32 {\n\tif x != nil {\n\t\treturn x.Tx\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetRxBufLen() uint32 {\n\tif x != nil {\n\t\treturn x.RxBufLen\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetCqeSize() uint32 {\n\tif x != nil {\n\t\treturn x.CqeSize\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetTxPush() bool {\n\tif x != nil {\n\t\treturn x.TxPush\n\t}\n\treturn false\n}\n\nfunc (x *EthernetRingsStatus) GetRxPush() bool {\n\tif x != nil {\n\t\treturn x.RxPush\n\t}\n\treturn false\n}\n\nfunc (x *EthernetRingsStatus) GetTxPushBufLen() uint32 {\n\tif x != nil {\n\t\treturn x.TxPushBufLen\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetRingsStatus) GetTcpDataSplit() bool {\n\tif x != nil {\n\t\treturn x.TcpDataSplit\n\t}\n\treturn false\n}\n\n// EthernetSpecSpec describes config of Ethernet link.\ntype EthernetSpecSpec struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tRings         *EthernetRingsSpec        `protobuf:\"bytes,1,opt,name=rings,proto3\" json:\"rings,omitempty\"`\n\tFeatures      map[string]bool           `protobuf:\"bytes,2,rep,name=features,proto3\" json:\"features,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"varint,2,opt,name=value\"`\n\tChannels      *EthernetChannelsSpec     `protobuf:\"bytes,3,opt,name=channels,proto3\" json:\"channels,omitempty\"`\n\tWakeOnLan     []enums.NethelpersWOLMode `protobuf:\"varint,4,rep,packed,name=wake_on_lan,json=wakeOnLan,proto3,enum=talos.resource.definitions.enums.NethelpersWOLMode\" json:\"wake_on_lan,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetSpecSpec) Reset() {\n\t*x = EthernetSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[16]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetSpecSpec) ProtoMessage() {}\n\nfunc (x *EthernetSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[16]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*EthernetSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *EthernetSpecSpec) GetRings() *EthernetRingsSpec {\n\tif x != nil {\n\t\treturn x.Rings\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetSpecSpec) GetFeatures() map[string]bool {\n\tif x != nil {\n\t\treturn x.Features\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetSpecSpec) GetChannels() *EthernetChannelsSpec {\n\tif x != nil {\n\t\treturn x.Channels\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetSpecSpec) GetWakeOnLan() []enums.NethelpersWOLMode {\n\tif x != nil {\n\t\treturn x.WakeOnLan\n\t}\n\treturn nil\n}\n\n// EthernetStatusSpec describes status of rendered secrets.\ntype EthernetStatusSpec struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tLinkState     bool                      `protobuf:\"varint,1,opt,name=link_state,json=linkState,proto3\" json:\"link_state,omitempty\"`\n\tSpeedMegabits int64                     `protobuf:\"varint,2,opt,name=speed_megabits,json=speedMegabits,proto3\" json:\"speed_megabits,omitempty\"`\n\tPort          enums.NethelpersPort      `protobuf:\"varint,3,opt,name=port,proto3,enum=talos.resource.definitions.enums.NethelpersPort\" json:\"port,omitempty\"`\n\tDuplex        enums.NethelpersDuplex    `protobuf:\"varint,4,opt,name=duplex,proto3,enum=talos.resource.definitions.enums.NethelpersDuplex\" json:\"duplex,omitempty\"`\n\tOurModes      []string                  `protobuf:\"bytes,5,rep,name=our_modes,json=ourModes,proto3\" json:\"our_modes,omitempty\"`\n\tPeerModes     []string                  `protobuf:\"bytes,6,rep,name=peer_modes,json=peerModes,proto3\" json:\"peer_modes,omitempty\"`\n\tRings         *EthernetRingsStatus      `protobuf:\"bytes,7,opt,name=rings,proto3\" json:\"rings,omitempty\"`\n\tFeatures      []*EthernetFeatureStatus  `protobuf:\"bytes,8,rep,name=features,proto3\" json:\"features,omitempty\"`\n\tChannels      *EthernetChannelsStatus   `protobuf:\"bytes,9,opt,name=channels,proto3\" json:\"channels,omitempty\"`\n\tWakeOnLan     []enums.NethelpersWOLMode `protobuf:\"varint,10,rep,packed,name=wake_on_lan,json=wakeOnLan,proto3,enum=talos.resource.definitions.enums.NethelpersWOLMode\" json:\"wake_on_lan,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EthernetStatusSpec) Reset() {\n\t*x = EthernetStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[17]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EthernetStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EthernetStatusSpec) ProtoMessage() {}\n\nfunc (x *EthernetStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[17]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EthernetStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*EthernetStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *EthernetStatusSpec) GetLinkState() bool {\n\tif x != nil {\n\t\treturn x.LinkState\n\t}\n\treturn false\n}\n\nfunc (x *EthernetStatusSpec) GetSpeedMegabits() int64 {\n\tif x != nil {\n\t\treturn x.SpeedMegabits\n\t}\n\treturn 0\n}\n\nfunc (x *EthernetStatusSpec) GetPort() enums.NethelpersPort {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn enums.NethelpersPort(0)\n}\n\nfunc (x *EthernetStatusSpec) GetDuplex() enums.NethelpersDuplex {\n\tif x != nil {\n\t\treturn x.Duplex\n\t}\n\treturn enums.NethelpersDuplex(0)\n}\n\nfunc (x *EthernetStatusSpec) GetOurModes() []string {\n\tif x != nil {\n\t\treturn x.OurModes\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetStatusSpec) GetPeerModes() []string {\n\tif x != nil {\n\t\treturn x.PeerModes\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetStatusSpec) GetRings() *EthernetRingsStatus {\n\tif x != nil {\n\t\treturn x.Rings\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetStatusSpec) GetFeatures() []*EthernetFeatureStatus {\n\tif x != nil {\n\t\treturn x.Features\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetStatusSpec) GetChannels() *EthernetChannelsStatus {\n\tif x != nil {\n\t\treturn x.Channels\n\t}\n\treturn nil\n}\n\nfunc (x *EthernetStatusSpec) GetWakeOnLan() []enums.NethelpersWOLMode {\n\tif x != nil {\n\t\treturn x.WakeOnLan\n\t}\n\treturn nil\n}\n\n// HardwareAddrSpec describes spec for the link.\ntype HardwareAddrSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tHardwareAddr  []byte                 `protobuf:\"bytes,2,opt,name=hardware_addr,json=hardwareAddr,proto3\" json:\"hardware_addr,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HardwareAddrSpec) Reset() {\n\t*x = HardwareAddrSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[18]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HardwareAddrSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HardwareAddrSpec) ProtoMessage() {}\n\nfunc (x *HardwareAddrSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[18]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HardwareAddrSpec.ProtoReflect.Descriptor instead.\nfunc (*HardwareAddrSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *HardwareAddrSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *HardwareAddrSpec) GetHardwareAddr() []byte {\n\tif x != nil {\n\t\treturn x.HardwareAddr\n\t}\n\treturn nil\n}\n\n// HostDNSConfigSpec describes host DNS config.\ntype HostDNSConfigSpec struct {\n\tstate                 protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled               bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tListenAddresses       []*common.NetIPPort    `protobuf:\"bytes,2,rep,name=listen_addresses,json=listenAddresses,proto3\" json:\"listen_addresses,omitempty\"`\n\tServiceHostDnsAddress *common.NetIP          `protobuf:\"bytes,3,opt,name=service_host_dns_address,json=serviceHostDnsAddress,proto3\" json:\"service_host_dns_address,omitempty\"`\n\tResolveMemberNames    bool                   `protobuf:\"varint,4,opt,name=resolve_member_names,json=resolveMemberNames,proto3\" json:\"resolve_member_names,omitempty\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *HostDNSConfigSpec) Reset() {\n\t*x = HostDNSConfigSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[19]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HostDNSConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HostDNSConfigSpec) ProtoMessage() {}\n\nfunc (x *HostDNSConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[19]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HostDNSConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*HostDNSConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *HostDNSConfigSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\nfunc (x *HostDNSConfigSpec) GetListenAddresses() []*common.NetIPPort {\n\tif x != nil {\n\t\treturn x.ListenAddresses\n\t}\n\treturn nil\n}\n\nfunc (x *HostDNSConfigSpec) GetServiceHostDnsAddress() *common.NetIP {\n\tif x != nil {\n\t\treturn x.ServiceHostDnsAddress\n\t}\n\treturn nil\n}\n\nfunc (x *HostDNSConfigSpec) GetResolveMemberNames() bool {\n\tif x != nil {\n\t\treturn x.ResolveMemberNames\n\t}\n\treturn false\n}\n\n// HostnameSpecSpec describes node hostname.\ntype HostnameSpecSpec struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tHostname      string                   `protobuf:\"bytes,1,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tDomainname    string                   `protobuf:\"bytes,2,opt,name=domainname,proto3\" json:\"domainname,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer `protobuf:\"varint,3,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HostnameSpecSpec) Reset() {\n\t*x = HostnameSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[20]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HostnameSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HostnameSpecSpec) ProtoMessage() {}\n\nfunc (x *HostnameSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[20]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HostnameSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*HostnameSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *HostnameSpecSpec) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *HostnameSpecSpec) GetDomainname() string {\n\tif x != nil {\n\t\treturn x.Domainname\n\t}\n\treturn \"\"\n}\n\nfunc (x *HostnameSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\n// HostnameStatusSpec describes node hostname.\ntype HostnameStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHostname      string                 `protobuf:\"bytes,1,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tDomainname    string                 `protobuf:\"bytes,2,opt,name=domainname,proto3\" json:\"domainname,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *HostnameStatusSpec) Reset() {\n\t*x = HostnameStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[21]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *HostnameStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HostnameStatusSpec) ProtoMessage() {}\n\nfunc (x *HostnameStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[21]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HostnameStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*HostnameStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *HostnameStatusSpec) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *HostnameStatusSpec) GetDomainname() string {\n\tif x != nil {\n\t\treturn x.Domainname\n\t}\n\treturn \"\"\n}\n\n// LinkAliasSpecSpec describes status of rendered secrets.\ntype LinkAliasSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tAlias         string                 `protobuf:\"bytes,1,opt,name=alias,proto3\" json:\"alias,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LinkAliasSpecSpec) Reset() {\n\t*x = LinkAliasSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[22]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinkAliasSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinkAliasSpecSpec) ProtoMessage() {}\n\nfunc (x *LinkAliasSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[22]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinkAliasSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*LinkAliasSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *LinkAliasSpecSpec) GetAlias() string {\n\tif x != nil {\n\t\treturn x.Alias\n\t}\n\treturn \"\"\n}\n\n// LinkRefreshSpec describes status of rendered secrets.\ntype LinkRefreshSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tGeneration    int64                  `protobuf:\"varint,1,opt,name=generation,proto3\" json:\"generation,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LinkRefreshSpec) Reset() {\n\t*x = LinkRefreshSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[23]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinkRefreshSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinkRefreshSpec) ProtoMessage() {}\n\nfunc (x *LinkRefreshSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[23]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinkRefreshSpec.ProtoReflect.Descriptor instead.\nfunc (*LinkRefreshSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *LinkRefreshSpec) GetGeneration() int64 {\n\tif x != nil {\n\t\treturn x.Generation\n\t}\n\treturn 0\n}\n\n// LinkSpecSpec describes spec for the link.\ntype LinkSpecSpec struct {\n\tstate           protoimpl.MessageState   `protogen:\"open.v1\"`\n\tName            string                   `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tLogical         bool                     `protobuf:\"varint,2,opt,name=logical,proto3\" json:\"logical,omitempty\"`\n\tUp              bool                     `protobuf:\"varint,3,opt,name=up,proto3\" json:\"up,omitempty\"`\n\tMtu             uint32                   `protobuf:\"varint,4,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tKind            string                   `protobuf:\"bytes,5,opt,name=kind,proto3\" json:\"kind,omitempty\"`\n\tType            enums.NethelpersLinkType `protobuf:\"varint,6,opt,name=type,proto3,enum=talos.resource.definitions.enums.NethelpersLinkType\" json:\"type,omitempty\"`\n\tParentName      string                   `protobuf:\"bytes,7,opt,name=parent_name,json=parentName,proto3\" json:\"parent_name,omitempty\"`\n\tBondSlave       *BondSlave               `protobuf:\"bytes,8,opt,name=bond_slave,json=bondSlave,proto3\" json:\"bond_slave,omitempty\"`\n\tBridgeSlave     *BridgeSlave             `protobuf:\"bytes,9,opt,name=bridge_slave,json=bridgeSlave,proto3\" json:\"bridge_slave,omitempty\"`\n\tVlan            *VLANSpec                `protobuf:\"bytes,10,opt,name=vlan,proto3\" json:\"vlan,omitempty\"`\n\tBondMaster      *BondMasterSpec          `protobuf:\"bytes,11,opt,name=bond_master,json=bondMaster,proto3\" json:\"bond_master,omitempty\"`\n\tBridgeMaster    *BridgeMasterSpec        `protobuf:\"bytes,12,opt,name=bridge_master,json=bridgeMaster,proto3\" json:\"bridge_master,omitempty\"`\n\tWireguard       *WireguardSpec           `protobuf:\"bytes,13,opt,name=wireguard,proto3\" json:\"wireguard,omitempty\"`\n\tConfigLayer     enums.NetworkConfigLayer `protobuf:\"varint,14,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tHardwareAddress []byte                   `protobuf:\"bytes,15,opt,name=hardware_address,json=hardwareAddress,proto3\" json:\"hardware_address,omitempty\"`\n\tMulticast       bool                     `protobuf:\"varint,16,opt,name=multicast,proto3\" json:\"multicast,omitempty\"`\n\tVrfMaster       *VRFMasterSpec           `protobuf:\"bytes,17,opt,name=vrf_master,json=vrfMaster,proto3\" json:\"vrf_master,omitempty\"`\n\tVrfSlave        *VRFSlave                `protobuf:\"bytes,18,opt,name=vrf_slave,json=vrfSlave,proto3\" json:\"vrf_slave,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *LinkSpecSpec) Reset() {\n\t*x = LinkSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[24]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinkSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinkSpecSpec) ProtoMessage() {}\n\nfunc (x *LinkSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[24]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinkSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*LinkSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *LinkSpecSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkSpecSpec) GetLogical() bool {\n\tif x != nil {\n\t\treturn x.Logical\n\t}\n\treturn false\n}\n\nfunc (x *LinkSpecSpec) GetUp() bool {\n\tif x != nil {\n\t\treturn x.Up\n\t}\n\treturn false\n}\n\nfunc (x *LinkSpecSpec) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\nfunc (x *LinkSpecSpec) GetKind() string {\n\tif x != nil {\n\t\treturn x.Kind\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkSpecSpec) GetType() enums.NethelpersLinkType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.NethelpersLinkType(0)\n}\n\nfunc (x *LinkSpecSpec) GetParentName() string {\n\tif x != nil {\n\t\treturn x.ParentName\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkSpecSpec) GetBondSlave() *BondSlave {\n\tif x != nil {\n\t\treturn x.BondSlave\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetBridgeSlave() *BridgeSlave {\n\tif x != nil {\n\t\treturn x.BridgeSlave\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetVlan() *VLANSpec {\n\tif x != nil {\n\t\treturn x.Vlan\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetBondMaster() *BondMasterSpec {\n\tif x != nil {\n\t\treturn x.BondMaster\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetBridgeMaster() *BridgeMasterSpec {\n\tif x != nil {\n\t\treturn x.BridgeMaster\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetWireguard() *WireguardSpec {\n\tif x != nil {\n\t\treturn x.Wireguard\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\nfunc (x *LinkSpecSpec) GetHardwareAddress() []byte {\n\tif x != nil {\n\t\treturn x.HardwareAddress\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetMulticast() bool {\n\tif x != nil {\n\t\treturn x.Multicast\n\t}\n\treturn false\n}\n\nfunc (x *LinkSpecSpec) GetVrfMaster() *VRFMasterSpec {\n\tif x != nil {\n\t\treturn x.VrfMaster\n\t}\n\treturn nil\n}\n\nfunc (x *LinkSpecSpec) GetVrfSlave() *VRFSlave {\n\tif x != nil {\n\t\treturn x.VrfSlave\n\t}\n\treturn nil\n}\n\n// LinkStatusSpec describes status of rendered secrets.\ntype LinkStatusSpec struct {\n\tstate            protoimpl.MessageState           `protogen:\"open.v1\"`\n\tIndex            uint32                           `protobuf:\"varint,1,opt,name=index,proto3\" json:\"index,omitempty\"`\n\tType             enums.NethelpersLinkType         `protobuf:\"varint,2,opt,name=type,proto3,enum=talos.resource.definitions.enums.NethelpersLinkType\" json:\"type,omitempty\"`\n\tLinkIndex        uint32                           `protobuf:\"varint,3,opt,name=link_index,json=linkIndex,proto3\" json:\"link_index,omitempty\"`\n\tFlags            uint32                           `protobuf:\"varint,4,opt,name=flags,proto3\" json:\"flags,omitempty\"`\n\tHardwareAddr     []byte                           `protobuf:\"bytes,5,opt,name=hardware_addr,json=hardwareAddr,proto3\" json:\"hardware_addr,omitempty\"`\n\tBroadcastAddr    []byte                           `protobuf:\"bytes,6,opt,name=broadcast_addr,json=broadcastAddr,proto3\" json:\"broadcast_addr,omitempty\"`\n\tMtu              uint32                           `protobuf:\"varint,7,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tQueueDisc        string                           `protobuf:\"bytes,8,opt,name=queue_disc,json=queueDisc,proto3\" json:\"queue_disc,omitempty\"`\n\tMasterIndex      uint32                           `protobuf:\"varint,9,opt,name=master_index,json=masterIndex,proto3\" json:\"master_index,omitempty\"`\n\tOperationalState enums.NethelpersOperationalState `protobuf:\"varint,10,opt,name=operational_state,json=operationalState,proto3,enum=talos.resource.definitions.enums.NethelpersOperationalState\" json:\"operational_state,omitempty\"`\n\tKind             string                           `protobuf:\"bytes,11,opt,name=kind,proto3\" json:\"kind,omitempty\"`\n\tSlaveKind        string                           `protobuf:\"bytes,12,opt,name=slave_kind,json=slaveKind,proto3\" json:\"slave_kind,omitempty\"`\n\tBusPath          string                           `protobuf:\"bytes,13,opt,name=bus_path,json=busPath,proto3\" json:\"bus_path,omitempty\"`\n\tPciid            string                           `protobuf:\"bytes,14,opt,name=pciid,proto3\" json:\"pciid,omitempty\"`\n\tDriver           string                           `protobuf:\"bytes,15,opt,name=driver,proto3\" json:\"driver,omitempty\"`\n\tDriverVersion    string                           `protobuf:\"bytes,16,opt,name=driver_version,json=driverVersion,proto3\" json:\"driver_version,omitempty\"`\n\tFirmwareVersion  string                           `protobuf:\"bytes,17,opt,name=firmware_version,json=firmwareVersion,proto3\" json:\"firmware_version,omitempty\"`\n\tProductId        string                           `protobuf:\"bytes,18,opt,name=product_id,json=productId,proto3\" json:\"product_id,omitempty\"`\n\tVendorId         string                           `protobuf:\"bytes,19,opt,name=vendor_id,json=vendorId,proto3\" json:\"vendor_id,omitempty\"`\n\tProduct          string                           `protobuf:\"bytes,20,opt,name=product,proto3\" json:\"product,omitempty\"`\n\tVendor           string                           `protobuf:\"bytes,21,opt,name=vendor,proto3\" json:\"vendor,omitempty\"`\n\tLinkState        bool                             `protobuf:\"varint,22,opt,name=link_state,json=linkState,proto3\" json:\"link_state,omitempty\"`\n\tSpeedMegabits    int64                            `protobuf:\"varint,23,opt,name=speed_megabits,json=speedMegabits,proto3\" json:\"speed_megabits,omitempty\"`\n\tPort             enums.NethelpersPort             `protobuf:\"varint,24,opt,name=port,proto3,enum=talos.resource.definitions.enums.NethelpersPort\" json:\"port,omitempty\"`\n\tDuplex           enums.NethelpersDuplex           `protobuf:\"varint,25,opt,name=duplex,proto3,enum=talos.resource.definitions.enums.NethelpersDuplex\" json:\"duplex,omitempty\"`\n\tVlan             *VLANSpec                        `protobuf:\"bytes,26,opt,name=vlan,proto3\" json:\"vlan,omitempty\"`\n\tBridgeMaster     *BridgeMasterSpec                `protobuf:\"bytes,27,opt,name=bridge_master,json=bridgeMaster,proto3\" json:\"bridge_master,omitempty\"`\n\tBondMaster       *BondMasterSpec                  `protobuf:\"bytes,28,opt,name=bond_master,json=bondMaster,proto3\" json:\"bond_master,omitempty\"`\n\tWireguard        *WireguardSpec                   `protobuf:\"bytes,29,opt,name=wireguard,proto3\" json:\"wireguard,omitempty\"`\n\tPermanentAddr    []byte                           `protobuf:\"bytes,30,opt,name=permanent_addr,json=permanentAddr,proto3\" json:\"permanent_addr,omitempty\"`\n\tAlias            string                           `protobuf:\"bytes,31,opt,name=alias,proto3\" json:\"alias,omitempty\"`\n\tAltNames         []string                         `protobuf:\"bytes,32,rep,name=alt_names,json=altNames,proto3\" json:\"alt_names,omitempty\"`\n\tVrfMaster        *VRFMasterSpec                   `protobuf:\"bytes,33,opt,name=vrf_master,json=vrfMaster,proto3\" json:\"vrf_master,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *LinkStatusSpec) Reset() {\n\t*x = LinkStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[25]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinkStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinkStatusSpec) ProtoMessage() {}\n\nfunc (x *LinkStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[25]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinkStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*LinkStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *LinkStatusSpec) GetIndex() uint32 {\n\tif x != nil {\n\t\treturn x.Index\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetType() enums.NethelpersLinkType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.NethelpersLinkType(0)\n}\n\nfunc (x *LinkStatusSpec) GetLinkIndex() uint32 {\n\tif x != nil {\n\t\treturn x.LinkIndex\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetFlags() uint32 {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetHardwareAddr() []byte {\n\tif x != nil {\n\t\treturn x.HardwareAddr\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetBroadcastAddr() []byte {\n\tif x != nil {\n\t\treturn x.BroadcastAddr\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetQueueDisc() string {\n\tif x != nil {\n\t\treturn x.QueueDisc\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetMasterIndex() uint32 {\n\tif x != nil {\n\t\treturn x.MasterIndex\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetOperationalState() enums.NethelpersOperationalState {\n\tif x != nil {\n\t\treturn x.OperationalState\n\t}\n\treturn enums.NethelpersOperationalState(0)\n}\n\nfunc (x *LinkStatusSpec) GetKind() string {\n\tif x != nil {\n\t\treturn x.Kind\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetSlaveKind() string {\n\tif x != nil {\n\t\treturn x.SlaveKind\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetBusPath() string {\n\tif x != nil {\n\t\treturn x.BusPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetPciid() string {\n\tif x != nil {\n\t\treturn x.Pciid\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetDriver() string {\n\tif x != nil {\n\t\treturn x.Driver\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetDriverVersion() string {\n\tif x != nil {\n\t\treturn x.DriverVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetFirmwareVersion() string {\n\tif x != nil {\n\t\treturn x.FirmwareVersion\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetProductId() string {\n\tif x != nil {\n\t\treturn x.ProductId\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetVendorId() string {\n\tif x != nil {\n\t\treturn x.VendorId\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetProduct() string {\n\tif x != nil {\n\t\treturn x.Product\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetVendor() string {\n\tif x != nil {\n\t\treturn x.Vendor\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetLinkState() bool {\n\tif x != nil {\n\t\treturn x.LinkState\n\t}\n\treturn false\n}\n\nfunc (x *LinkStatusSpec) GetSpeedMegabits() int64 {\n\tif x != nil {\n\t\treturn x.SpeedMegabits\n\t}\n\treturn 0\n}\n\nfunc (x *LinkStatusSpec) GetPort() enums.NethelpersPort {\n\tif x != nil {\n\t\treturn x.Port\n\t}\n\treturn enums.NethelpersPort(0)\n}\n\nfunc (x *LinkStatusSpec) GetDuplex() enums.NethelpersDuplex {\n\tif x != nil {\n\t\treturn x.Duplex\n\t}\n\treturn enums.NethelpersDuplex(0)\n}\n\nfunc (x *LinkStatusSpec) GetVlan() *VLANSpec {\n\tif x != nil {\n\t\treturn x.Vlan\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetBridgeMaster() *BridgeMasterSpec {\n\tif x != nil {\n\t\treturn x.BridgeMaster\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetBondMaster() *BondMasterSpec {\n\tif x != nil {\n\t\treturn x.BondMaster\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetWireguard() *WireguardSpec {\n\tif x != nil {\n\t\treturn x.Wireguard\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetPermanentAddr() []byte {\n\tif x != nil {\n\t\treturn x.PermanentAddr\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetAlias() string {\n\tif x != nil {\n\t\treturn x.Alias\n\t}\n\treturn \"\"\n}\n\nfunc (x *LinkStatusSpec) GetAltNames() []string {\n\tif x != nil {\n\t\treturn x.AltNames\n\t}\n\treturn nil\n}\n\nfunc (x *LinkStatusSpec) GetVrfMaster() *VRFMasterSpec {\n\tif x != nil {\n\t\treturn x.VrfMaster\n\t}\n\treturn nil\n}\n\n// NfTablesAddressMatch describes the match on the IP address.\ntype NfTablesAddressMatch struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tIncludeSubnets []*common.NetIPPrefix  `protobuf:\"bytes,1,rep,name=include_subnets,json=includeSubnets,proto3\" json:\"include_subnets,omitempty\"`\n\tExcludeSubnets []*common.NetIPPrefix  `protobuf:\"bytes,2,rep,name=exclude_subnets,json=excludeSubnets,proto3\" json:\"exclude_subnets,omitempty\"`\n\tInvert         bool                   `protobuf:\"varint,3,opt,name=invert,proto3\" json:\"invert,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *NfTablesAddressMatch) Reset() {\n\t*x = NfTablesAddressMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[26]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesAddressMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesAddressMatch) ProtoMessage() {}\n\nfunc (x *NfTablesAddressMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[26]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesAddressMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesAddressMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{26}\n}\n\nfunc (x *NfTablesAddressMatch) GetIncludeSubnets() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.IncludeSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesAddressMatch) GetExcludeSubnets() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.ExcludeSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesAddressMatch) GetInvert() bool {\n\tif x != nil {\n\t\treturn x.Invert\n\t}\n\treturn false\n}\n\n// NfTablesChainSpec describes status of rendered secrets.\ntype NfTablesChainSpec struct {\n\tstate         protoimpl.MessageState                `protogen:\"open.v1\"`\n\tType          string                                `protobuf:\"bytes,1,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tHook          enums.NethelpersNfTablesChainHook     `protobuf:\"varint,2,opt,name=hook,proto3,enum=talos.resource.definitions.enums.NethelpersNfTablesChainHook\" json:\"hook,omitempty\"`\n\tPriority      enums.NethelpersNfTablesChainPriority `protobuf:\"varint,3,opt,name=priority,proto3,enum=talos.resource.definitions.enums.NethelpersNfTablesChainPriority\" json:\"priority,omitempty\"`\n\tRules         []*NfTablesRule                       `protobuf:\"bytes,4,rep,name=rules,proto3\" json:\"rules,omitempty\"`\n\tPolicy        enums.NethelpersNfTablesVerdict       `protobuf:\"varint,5,opt,name=policy,proto3,enum=talos.resource.definitions.enums.NethelpersNfTablesVerdict\" json:\"policy,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesChainSpec) Reset() {\n\t*x = NfTablesChainSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[27]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesChainSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesChainSpec) ProtoMessage() {}\n\nfunc (x *NfTablesChainSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[27]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesChainSpec.ProtoReflect.Descriptor instead.\nfunc (*NfTablesChainSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{27}\n}\n\nfunc (x *NfTablesChainSpec) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *NfTablesChainSpec) GetHook() enums.NethelpersNfTablesChainHook {\n\tif x != nil {\n\t\treturn x.Hook\n\t}\n\treturn enums.NethelpersNfTablesChainHook(0)\n}\n\nfunc (x *NfTablesChainSpec) GetPriority() enums.NethelpersNfTablesChainPriority {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn enums.NethelpersNfTablesChainPriority(0)\n}\n\nfunc (x *NfTablesChainSpec) GetRules() []*NfTablesRule {\n\tif x != nil {\n\t\treturn x.Rules\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesChainSpec) GetPolicy() enums.NethelpersNfTablesVerdict {\n\tif x != nil {\n\t\treturn x.Policy\n\t}\n\treturn enums.NethelpersNfTablesVerdict(0)\n}\n\n// NfTablesClampMSS describes the TCP MSS clamping operation.\n//\n// MSS is limited by the `MaxMTU` so that:\n// - IPv4: MSS = MaxMTU - 40\n// - IPv6: MSS = MaxMTU - 60.\ntype NfTablesClampMSS struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMtu           uint32                 `protobuf:\"varint,1,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesClampMSS) Reset() {\n\t*x = NfTablesClampMSS{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[28]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesClampMSS) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesClampMSS) ProtoMessage() {}\n\nfunc (x *NfTablesClampMSS) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[28]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesClampMSS.ProtoReflect.Descriptor instead.\nfunc (*NfTablesClampMSS) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{28}\n}\n\nfunc (x *NfTablesClampMSS) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\n// NfTablesConntrackStateMatch describes the match on the connection tracking state.\ntype NfTablesConntrackStateMatch struct {\n\tstate         protoimpl.MessageState           `protogen:\"open.v1\"`\n\tStates        []enums.NethelpersConntrackState `protobuf:\"varint,1,rep,packed,name=states,proto3,enum=talos.resource.definitions.enums.NethelpersConntrackState\" json:\"states,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesConntrackStateMatch) Reset() {\n\t*x = NfTablesConntrackStateMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[29]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesConntrackStateMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesConntrackStateMatch) ProtoMessage() {}\n\nfunc (x *NfTablesConntrackStateMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[29]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesConntrackStateMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesConntrackStateMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{29}\n}\n\nfunc (x *NfTablesConntrackStateMatch) GetStates() []enums.NethelpersConntrackState {\n\tif x != nil {\n\t\treturn x.States\n\t}\n\treturn nil\n}\n\n// NfTablesICMPTypeMatch describes the match on the ICMP type.\ntype NfTablesICMPTypeMatch struct {\n\tstate         protoimpl.MessageState     `protogen:\"open.v1\"`\n\tTypes         []enums.NethelpersICMPType `protobuf:\"varint,1,rep,packed,name=types,proto3,enum=talos.resource.definitions.enums.NethelpersICMPType\" json:\"types,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesICMPTypeMatch) Reset() {\n\t*x = NfTablesICMPTypeMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[30]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesICMPTypeMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesICMPTypeMatch) ProtoMessage() {}\n\nfunc (x *NfTablesICMPTypeMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[30]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesICMPTypeMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesICMPTypeMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{30}\n}\n\nfunc (x *NfTablesICMPTypeMatch) GetTypes() []enums.NethelpersICMPType {\n\tif x != nil {\n\t\treturn x.Types\n\t}\n\treturn nil\n}\n\n// NfTablesIfNameMatch describes the match on the interface name.\ntype NfTablesIfNameMatch struct {\n\tstate          protoimpl.MessageState        `protogen:\"open.v1\"`\n\tOperator       enums.NethelpersMatchOperator `protobuf:\"varint,2,opt,name=operator,proto3,enum=talos.resource.definitions.enums.NethelpersMatchOperator\" json:\"operator,omitempty\"`\n\tInterfaceNames []string                      `protobuf:\"bytes,3,rep,name=interface_names,json=interfaceNames,proto3\" json:\"interface_names,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *NfTablesIfNameMatch) Reset() {\n\t*x = NfTablesIfNameMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[31]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesIfNameMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesIfNameMatch) ProtoMessage() {}\n\nfunc (x *NfTablesIfNameMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[31]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesIfNameMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesIfNameMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{31}\n}\n\nfunc (x *NfTablesIfNameMatch) GetOperator() enums.NethelpersMatchOperator {\n\tif x != nil {\n\t\treturn x.Operator\n\t}\n\treturn enums.NethelpersMatchOperator(0)\n}\n\nfunc (x *NfTablesIfNameMatch) GetInterfaceNames() []string {\n\tif x != nil {\n\t\treturn x.InterfaceNames\n\t}\n\treturn nil\n}\n\n// NfTablesLayer4Match describes the match on the transport layer protocol.\ntype NfTablesLayer4Match struct {\n\tstate                protoimpl.MessageState   `protogen:\"open.v1\"`\n\tProtocol             enums.NethelpersProtocol `protobuf:\"varint,1,opt,name=protocol,proto3,enum=talos.resource.definitions.enums.NethelpersProtocol\" json:\"protocol,omitempty\"`\n\tMatchSourcePort      *NfTablesPortMatch       `protobuf:\"bytes,2,opt,name=match_source_port,json=matchSourcePort,proto3\" json:\"match_source_port,omitempty\"`\n\tMatchDestinationPort *NfTablesPortMatch       `protobuf:\"bytes,3,opt,name=match_destination_port,json=matchDestinationPort,proto3\" json:\"match_destination_port,omitempty\"`\n\tMatchIcmpType        *NfTablesICMPTypeMatch   `protobuf:\"bytes,4,opt,name=match_icmp_type,json=matchIcmpType,proto3\" json:\"match_icmp_type,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *NfTablesLayer4Match) Reset() {\n\t*x = NfTablesLayer4Match{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[32]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesLayer4Match) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesLayer4Match) ProtoMessage() {}\n\nfunc (x *NfTablesLayer4Match) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[32]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesLayer4Match.ProtoReflect.Descriptor instead.\nfunc (*NfTablesLayer4Match) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{32}\n}\n\nfunc (x *NfTablesLayer4Match) GetProtocol() enums.NethelpersProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn enums.NethelpersProtocol(0)\n}\n\nfunc (x *NfTablesLayer4Match) GetMatchSourcePort() *NfTablesPortMatch {\n\tif x != nil {\n\t\treturn x.MatchSourcePort\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesLayer4Match) GetMatchDestinationPort() *NfTablesPortMatch {\n\tif x != nil {\n\t\treturn x.MatchDestinationPort\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesLayer4Match) GetMatchIcmpType() *NfTablesICMPTypeMatch {\n\tif x != nil {\n\t\treturn x.MatchIcmpType\n\t}\n\treturn nil\n}\n\n// NfTablesLimitMatch describes the match on the packet rate.\ntype NfTablesLimitMatch struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tPacketRatePerSecond uint64                 `protobuf:\"varint,1,opt,name=packet_rate_per_second,json=packetRatePerSecond,proto3\" json:\"packet_rate_per_second,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *NfTablesLimitMatch) Reset() {\n\t*x = NfTablesLimitMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[33]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesLimitMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesLimitMatch) ProtoMessage() {}\n\nfunc (x *NfTablesLimitMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[33]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesLimitMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesLimitMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{33}\n}\n\nfunc (x *NfTablesLimitMatch) GetPacketRatePerSecond() uint64 {\n\tif x != nil {\n\t\treturn x.PacketRatePerSecond\n\t}\n\treturn 0\n}\n\n// NfTablesMark encodes packet mark match/update operation.\n//\n// When used as a match computes the following condition:\n// (mark & mask) ^ xor == value\n//\n// When used as an update computes the following operation:\n// mark = (mark & mask) ^ xor.\ntype NfTablesMark struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMask          uint32                 `protobuf:\"varint,1,opt,name=mask,proto3\" json:\"mask,omitempty\"`\n\tXor           uint32                 `protobuf:\"varint,2,opt,name=xor,proto3\" json:\"xor,omitempty\"`\n\tValue         uint32                 `protobuf:\"varint,3,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesMark) Reset() {\n\t*x = NfTablesMark{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[34]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesMark) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesMark) ProtoMessage() {}\n\nfunc (x *NfTablesMark) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[34]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesMark.ProtoReflect.Descriptor instead.\nfunc (*NfTablesMark) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{34}\n}\n\nfunc (x *NfTablesMark) GetMask() uint32 {\n\tif x != nil {\n\t\treturn x.Mask\n\t}\n\treturn 0\n}\n\nfunc (x *NfTablesMark) GetXor() uint32 {\n\tif x != nil {\n\t\treturn x.Xor\n\t}\n\treturn 0\n}\n\nfunc (x *NfTablesMark) GetValue() uint32 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\n// NfTablesPortMatch describes the match on the transport layer port.\ntype NfTablesPortMatch struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRanges        []*PortRange           `protobuf:\"bytes,1,rep,name=ranges,proto3\" json:\"ranges,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NfTablesPortMatch) Reset() {\n\t*x = NfTablesPortMatch{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[35]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesPortMatch) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesPortMatch) ProtoMessage() {}\n\nfunc (x *NfTablesPortMatch) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[35]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesPortMatch.ProtoReflect.Descriptor instead.\nfunc (*NfTablesPortMatch) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{35}\n}\n\nfunc (x *NfTablesPortMatch) GetRanges() []*PortRange {\n\tif x != nil {\n\t\treturn x.Ranges\n\t}\n\treturn nil\n}\n\n// NfTablesRule describes a single rule in the nftables chain.\ntype NfTablesRule struct {\n\tstate                   protoimpl.MessageState          `protogen:\"open.v1\"`\n\tMatchOIfName            *NfTablesIfNameMatch            `protobuf:\"bytes,1,opt,name=match_o_if_name,json=matchOIfName,proto3\" json:\"match_o_if_name,omitempty\"`\n\tVerdict                 enums.NethelpersNfTablesVerdict `protobuf:\"varint,2,opt,name=verdict,proto3,enum=talos.resource.definitions.enums.NethelpersNfTablesVerdict\" json:\"verdict,omitempty\"`\n\tMatchMark               *NfTablesMark                   `protobuf:\"bytes,3,opt,name=match_mark,json=matchMark,proto3\" json:\"match_mark,omitempty\"`\n\tSetMark                 *NfTablesMark                   `protobuf:\"bytes,4,opt,name=set_mark,json=setMark,proto3\" json:\"set_mark,omitempty\"`\n\tMatchSourceAddress      *NfTablesAddressMatch           `protobuf:\"bytes,5,opt,name=match_source_address,json=matchSourceAddress,proto3\" json:\"match_source_address,omitempty\"`\n\tMatchDestinationAddress *NfTablesAddressMatch           `protobuf:\"bytes,6,opt,name=match_destination_address,json=matchDestinationAddress,proto3\" json:\"match_destination_address,omitempty\"`\n\tMatchLayer4             *NfTablesLayer4Match            `protobuf:\"bytes,7,opt,name=match_layer4,json=matchLayer4,proto3\" json:\"match_layer4,omitempty\"`\n\tMatchIIfName            *NfTablesIfNameMatch            `protobuf:\"bytes,8,opt,name=match_i_if_name,json=matchIIfName,proto3\" json:\"match_i_if_name,omitempty\"`\n\tClampMss                *NfTablesClampMSS               `protobuf:\"bytes,9,opt,name=clamp_mss,json=clampMss,proto3\" json:\"clamp_mss,omitempty\"`\n\tMatchLimit              *NfTablesLimitMatch             `protobuf:\"bytes,10,opt,name=match_limit,json=matchLimit,proto3\" json:\"match_limit,omitempty\"`\n\tMatchConntrackState     *NfTablesConntrackStateMatch    `protobuf:\"bytes,11,opt,name=match_conntrack_state,json=matchConntrackState,proto3\" json:\"match_conntrack_state,omitempty\"`\n\tAnonCounter             bool                            `protobuf:\"varint,12,opt,name=anon_counter,json=anonCounter,proto3\" json:\"anon_counter,omitempty\"`\n\tunknownFields           protoimpl.UnknownFields\n\tsizeCache               protoimpl.SizeCache\n}\n\nfunc (x *NfTablesRule) Reset() {\n\t*x = NfTablesRule{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[36]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NfTablesRule) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NfTablesRule) ProtoMessage() {}\n\nfunc (x *NfTablesRule) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[36]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NfTablesRule.ProtoReflect.Descriptor instead.\nfunc (*NfTablesRule) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{36}\n}\n\nfunc (x *NfTablesRule) GetMatchOIfName() *NfTablesIfNameMatch {\n\tif x != nil {\n\t\treturn x.MatchOIfName\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetVerdict() enums.NethelpersNfTablesVerdict {\n\tif x != nil {\n\t\treturn x.Verdict\n\t}\n\treturn enums.NethelpersNfTablesVerdict(0)\n}\n\nfunc (x *NfTablesRule) GetMatchMark() *NfTablesMark {\n\tif x != nil {\n\t\treturn x.MatchMark\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetSetMark() *NfTablesMark {\n\tif x != nil {\n\t\treturn x.SetMark\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchSourceAddress() *NfTablesAddressMatch {\n\tif x != nil {\n\t\treturn x.MatchSourceAddress\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchDestinationAddress() *NfTablesAddressMatch {\n\tif x != nil {\n\t\treturn x.MatchDestinationAddress\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchLayer4() *NfTablesLayer4Match {\n\tif x != nil {\n\t\treturn x.MatchLayer4\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchIIfName() *NfTablesIfNameMatch {\n\tif x != nil {\n\t\treturn x.MatchIIfName\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetClampMss() *NfTablesClampMSS {\n\tif x != nil {\n\t\treturn x.ClampMss\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchLimit() *NfTablesLimitMatch {\n\tif x != nil {\n\t\treturn x.MatchLimit\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetMatchConntrackState() *NfTablesConntrackStateMatch {\n\tif x != nil {\n\t\treturn x.MatchConntrackState\n\t}\n\treturn nil\n}\n\nfunc (x *NfTablesRule) GetAnonCounter() bool {\n\tif x != nil {\n\t\treturn x.AnonCounter\n\t}\n\treturn false\n}\n\n// NodeAddressFilterSpec describes a filter for NodeAddresses.\ntype NodeAddressFilterSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tIncludeSubnets []*common.NetIPPrefix  `protobuf:\"bytes,1,rep,name=include_subnets,json=includeSubnets,proto3\" json:\"include_subnets,omitempty\"`\n\tExcludeSubnets []*common.NetIPPrefix  `protobuf:\"bytes,2,rep,name=exclude_subnets,json=excludeSubnets,proto3\" json:\"exclude_subnets,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *NodeAddressFilterSpec) Reset() {\n\t*x = NodeAddressFilterSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[37]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeAddressFilterSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeAddressFilterSpec) ProtoMessage() {}\n\nfunc (x *NodeAddressFilterSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[37]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeAddressFilterSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeAddressFilterSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{37}\n}\n\nfunc (x *NodeAddressFilterSpec) GetIncludeSubnets() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.IncludeSubnets\n\t}\n\treturn nil\n}\n\nfunc (x *NodeAddressFilterSpec) GetExcludeSubnets() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.ExcludeSubnets\n\t}\n\treturn nil\n}\n\n// NodeAddressSortAlgorithmSpec describes a filter for NodeAddresses.\ntype NodeAddressSortAlgorithmSpec struct {\n\tstate         protoimpl.MessageState               `protogen:\"open.v1\"`\n\tAlgorithm     enums.NethelpersAddressSortAlgorithm `protobuf:\"varint,1,opt,name=algorithm,proto3,enum=talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\" json:\"algorithm,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeAddressSortAlgorithmSpec) Reset() {\n\t*x = NodeAddressSortAlgorithmSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[38]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeAddressSortAlgorithmSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeAddressSortAlgorithmSpec) ProtoMessage() {}\n\nfunc (x *NodeAddressSortAlgorithmSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[38]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeAddressSortAlgorithmSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeAddressSortAlgorithmSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{38}\n}\n\nfunc (x *NodeAddressSortAlgorithmSpec) GetAlgorithm() enums.NethelpersAddressSortAlgorithm {\n\tif x != nil {\n\t\treturn x.Algorithm\n\t}\n\treturn enums.NethelpersAddressSortAlgorithm(0)\n}\n\n// NodeAddressSpec describes a set of node addresses.\ntype NodeAddressSpec struct {\n\tstate         protoimpl.MessageState               `protogen:\"open.v1\"`\n\tAddresses     []*common.NetIPPrefix                `protobuf:\"bytes,1,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tSortAlgorithm enums.NethelpersAddressSortAlgorithm `protobuf:\"varint,2,opt,name=sort_algorithm,json=sortAlgorithm,proto3,enum=talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\" json:\"sort_algorithm,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *NodeAddressSpec) Reset() {\n\t*x = NodeAddressSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[39]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *NodeAddressSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*NodeAddressSpec) ProtoMessage() {}\n\nfunc (x *NodeAddressSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[39]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use NodeAddressSpec.ProtoReflect.Descriptor instead.\nfunc (*NodeAddressSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{39}\n}\n\nfunc (x *NodeAddressSpec) GetAddresses() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *NodeAddressSpec) GetSortAlgorithm() enums.NethelpersAddressSortAlgorithm {\n\tif x != nil {\n\t\treturn x.SortAlgorithm\n\t}\n\treturn enums.NethelpersAddressSortAlgorithm(0)\n}\n\n// OperatorSpecSpec describes operator specification.\ntype OperatorSpecSpec struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tOperator      enums.NetworkOperator    `protobuf:\"varint,1,opt,name=operator,proto3,enum=talos.resource.definitions.enums.NetworkOperator\" json:\"operator,omitempty\"`\n\tLinkName      string                   `protobuf:\"bytes,2,opt,name=link_name,json=linkName,proto3\" json:\"link_name,omitempty\"`\n\tRequireUp     bool                     `protobuf:\"varint,3,opt,name=require_up,json=requireUp,proto3\" json:\"require_up,omitempty\"`\n\tDhcp4         *DHCP4OperatorSpec       `protobuf:\"bytes,4,opt,name=dhcp4,proto3\" json:\"dhcp4,omitempty\"`\n\tDhcp6         *DHCP6OperatorSpec       `protobuf:\"bytes,5,opt,name=dhcp6,proto3\" json:\"dhcp6,omitempty\"`\n\tVip           *VIPOperatorSpec         `protobuf:\"bytes,6,opt,name=vip,proto3\" json:\"vip,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer `protobuf:\"varint,7,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *OperatorSpecSpec) Reset() {\n\t*x = OperatorSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[40]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OperatorSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OperatorSpecSpec) ProtoMessage() {}\n\nfunc (x *OperatorSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[40]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OperatorSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*OperatorSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{40}\n}\n\nfunc (x *OperatorSpecSpec) GetOperator() enums.NetworkOperator {\n\tif x != nil {\n\t\treturn x.Operator\n\t}\n\treturn enums.NetworkOperator(0)\n}\n\nfunc (x *OperatorSpecSpec) GetLinkName() string {\n\tif x != nil {\n\t\treturn x.LinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *OperatorSpecSpec) GetRequireUp() bool {\n\tif x != nil {\n\t\treturn x.RequireUp\n\t}\n\treturn false\n}\n\nfunc (x *OperatorSpecSpec) GetDhcp4() *DHCP4OperatorSpec {\n\tif x != nil {\n\t\treturn x.Dhcp4\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorSpecSpec) GetDhcp6() *DHCP6OperatorSpec {\n\tif x != nil {\n\t\treturn x.Dhcp6\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorSpecSpec) GetVip() *VIPOperatorSpec {\n\tif x != nil {\n\t\treturn x.Vip\n\t}\n\treturn nil\n}\n\nfunc (x *OperatorSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\n// PlatformConfigSpec describes platform network configuration.\n//\n// This structure is marshaled to STATE partition to persist cached network configuration across\n// reboots.\ntype PlatformConfigSpec struct {\n\tstate         protoimpl.MessageState        `protogen:\"open.v1\"`\n\tAddresses     []*AddressSpecSpec            `protobuf:\"bytes,1,rep,name=addresses,proto3\" json:\"addresses,omitempty\"`\n\tLinks         []*LinkSpecSpec               `protobuf:\"bytes,2,rep,name=links,proto3\" json:\"links,omitempty\"`\n\tRoutes        []*RouteSpecSpec              `protobuf:\"bytes,3,rep,name=routes,proto3\" json:\"routes,omitempty\"`\n\tHostnames     []*HostnameSpecSpec           `protobuf:\"bytes,4,rep,name=hostnames,proto3\" json:\"hostnames,omitempty\"`\n\tResolvers     []*ResolverSpecSpec           `protobuf:\"bytes,5,rep,name=resolvers,proto3\" json:\"resolvers,omitempty\"`\n\tTimeServers   []*TimeServerSpecSpec         `protobuf:\"bytes,6,rep,name=time_servers,json=timeServers,proto3\" json:\"time_servers,omitempty\"`\n\tOperators     []*OperatorSpecSpec           `protobuf:\"bytes,7,rep,name=operators,proto3\" json:\"operators,omitempty\"`\n\tExternalIps   []*common.NetIP               `protobuf:\"bytes,8,rep,name=external_ips,json=externalIps,proto3\" json:\"external_ips,omitempty\"`\n\tProbes        []*ProbeSpecSpec              `protobuf:\"bytes,9,rep,name=probes,proto3\" json:\"probes,omitempty\"`\n\tMetadata      *runtime.PlatformMetadataSpec `protobuf:\"bytes,10,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PlatformConfigSpec) Reset() {\n\t*x = PlatformConfigSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[41]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PlatformConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PlatformConfigSpec) ProtoMessage() {}\n\nfunc (x *PlatformConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[41]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PlatformConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*PlatformConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{41}\n}\n\nfunc (x *PlatformConfigSpec) GetAddresses() []*AddressSpecSpec {\n\tif x != nil {\n\t\treturn x.Addresses\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetLinks() []*LinkSpecSpec {\n\tif x != nil {\n\t\treturn x.Links\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetRoutes() []*RouteSpecSpec {\n\tif x != nil {\n\t\treturn x.Routes\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetHostnames() []*HostnameSpecSpec {\n\tif x != nil {\n\t\treturn x.Hostnames\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetResolvers() []*ResolverSpecSpec {\n\tif x != nil {\n\t\treturn x.Resolvers\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetTimeServers() []*TimeServerSpecSpec {\n\tif x != nil {\n\t\treturn x.TimeServers\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetOperators() []*OperatorSpecSpec {\n\tif x != nil {\n\t\treturn x.Operators\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetExternalIps() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ExternalIps\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetProbes() []*ProbeSpecSpec {\n\tif x != nil {\n\t\treturn x.Probes\n\t}\n\treturn nil\n}\n\nfunc (x *PlatformConfigSpec) GetMetadata() *runtime.PlatformMetadataSpec {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\n// PortRange describes a range of ports.\n//\n// Range is [lo, hi].\ntype PortRange struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tLo            uint32                 `protobuf:\"varint,1,opt,name=lo,proto3\" json:\"lo,omitempty\"`\n\tHi            uint32                 `protobuf:\"varint,2,opt,name=hi,proto3\" json:\"hi,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PortRange) Reset() {\n\t*x = PortRange{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[42]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PortRange) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PortRange) ProtoMessage() {}\n\nfunc (x *PortRange) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[42]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PortRange.ProtoReflect.Descriptor instead.\nfunc (*PortRange) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{42}\n}\n\nfunc (x *PortRange) GetLo() uint32 {\n\tif x != nil {\n\t\treturn x.Lo\n\t}\n\treturn 0\n}\n\nfunc (x *PortRange) GetHi() uint32 {\n\tif x != nil {\n\t\treturn x.Hi\n\t}\n\treturn 0\n}\n\n// ProbeSpecSpec describes the Probe.\ntype ProbeSpecSpec struct {\n\tstate            protoimpl.MessageState   `protogen:\"open.v1\"`\n\tInterval         *durationpb.Duration     `protobuf:\"bytes,1,opt,name=interval,proto3\" json:\"interval,omitempty\"`\n\tFailureThreshold int64                    `protobuf:\"varint,2,opt,name=failure_threshold,json=failureThreshold,proto3\" json:\"failure_threshold,omitempty\"`\n\tTcp              *TCPProbeSpec            `protobuf:\"bytes,3,opt,name=tcp,proto3\" json:\"tcp,omitempty\"`\n\tConfigLayer      enums.NetworkConfigLayer `protobuf:\"varint,4,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *ProbeSpecSpec) Reset() {\n\t*x = ProbeSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[43]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProbeSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProbeSpecSpec) ProtoMessage() {}\n\nfunc (x *ProbeSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[43]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProbeSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*ProbeSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{43}\n}\n\nfunc (x *ProbeSpecSpec) GetInterval() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Interval\n\t}\n\treturn nil\n}\n\nfunc (x *ProbeSpecSpec) GetFailureThreshold() int64 {\n\tif x != nil {\n\t\treturn x.FailureThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *ProbeSpecSpec) GetTcp() *TCPProbeSpec {\n\tif x != nil {\n\t\treturn x.Tcp\n\t}\n\treturn nil\n}\n\nfunc (x *ProbeSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\n// ProbeStatusSpec describes the Probe.\ntype ProbeStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSuccess       bool                   `protobuf:\"varint,1,opt,name=success,proto3\" json:\"success,omitempty\"`\n\tLastError     string                 `protobuf:\"bytes,2,opt,name=last_error,json=lastError,proto3\" json:\"last_error,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ProbeStatusSpec) Reset() {\n\t*x = ProbeStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[44]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ProbeStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ProbeStatusSpec) ProtoMessage() {}\n\nfunc (x *ProbeStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[44]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ProbeStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ProbeStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{44}\n}\n\nfunc (x *ProbeStatusSpec) GetSuccess() bool {\n\tif x != nil {\n\t\treturn x.Success\n\t}\n\treturn false\n}\n\nfunc (x *ProbeStatusSpec) GetLastError() string {\n\tif x != nil {\n\t\treturn x.LastError\n\t}\n\treturn \"\"\n}\n\n// ResolverSpecSpec describes DNS resolvers.\ntype ResolverSpecSpec struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tDnsServers    []*common.NetIP          `protobuf:\"bytes,1,rep,name=dns_servers,json=dnsServers,proto3\" json:\"dns_servers,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer `protobuf:\"varint,2,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tSearchDomains []string                 `protobuf:\"bytes,3,rep,name=search_domains,json=searchDomains,proto3\" json:\"search_domains,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ResolverSpecSpec) Reset() {\n\t*x = ResolverSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[45]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResolverSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResolverSpecSpec) ProtoMessage() {}\n\nfunc (x *ResolverSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[45]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResolverSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*ResolverSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{45}\n}\n\nfunc (x *ResolverSpecSpec) GetDnsServers() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.DnsServers\n\t}\n\treturn nil\n}\n\nfunc (x *ResolverSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\nfunc (x *ResolverSpecSpec) GetSearchDomains() []string {\n\tif x != nil {\n\t\treturn x.SearchDomains\n\t}\n\treturn nil\n}\n\n// ResolverStatusSpec describes DNS resolvers.\ntype ResolverStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDnsServers    []*common.NetIP        `protobuf:\"bytes,1,rep,name=dns_servers,json=dnsServers,proto3\" json:\"dns_servers,omitempty\"`\n\tSearchDomains []string               `protobuf:\"bytes,2,rep,name=search_domains,json=searchDomains,proto3\" json:\"search_domains,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ResolverStatusSpec) Reset() {\n\t*x = ResolverStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[46]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ResolverStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResolverStatusSpec) ProtoMessage() {}\n\nfunc (x *ResolverStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[46]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResolverStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ResolverStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{46}\n}\n\nfunc (x *ResolverStatusSpec) GetDnsServers() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.DnsServers\n\t}\n\treturn nil\n}\n\nfunc (x *ResolverStatusSpec) GetSearchDomains() []string {\n\tif x != nil {\n\t\treturn x.SearchDomains\n\t}\n\treturn nil\n}\n\n// RouteSpecSpec describes the route.\ntype RouteSpecSpec struct {\n\tstate         protoimpl.MessageState        `protogen:\"open.v1\"`\n\tFamily        enums.NethelpersFamily        `protobuf:\"varint,1,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tDestination   *common.NetIPPrefix           `protobuf:\"bytes,2,opt,name=destination,proto3\" json:\"destination,omitempty\"`\n\tSource        *common.NetIP                 `protobuf:\"bytes,3,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tGateway       *common.NetIP                 `protobuf:\"bytes,4,opt,name=gateway,proto3\" json:\"gateway,omitempty\"`\n\tOutLinkName   string                        `protobuf:\"bytes,5,opt,name=out_link_name,json=outLinkName,proto3\" json:\"out_link_name,omitempty\"`\n\tTable         enums.NethelpersRoutingTable  `protobuf:\"varint,6,opt,name=table,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingTable\" json:\"table,omitempty\"`\n\tPriority      uint32                        `protobuf:\"varint,7,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tScope         enums.NethelpersScope         `protobuf:\"varint,8,opt,name=scope,proto3,enum=talos.resource.definitions.enums.NethelpersScope\" json:\"scope,omitempty\"`\n\tType          enums.NethelpersRouteType     `protobuf:\"varint,9,opt,name=type,proto3,enum=talos.resource.definitions.enums.NethelpersRouteType\" json:\"type,omitempty\"`\n\tFlags         uint32                        `protobuf:\"varint,10,opt,name=flags,proto3\" json:\"flags,omitempty\"`\n\tProtocol      enums.NethelpersRouteProtocol `protobuf:\"varint,11,opt,name=protocol,proto3,enum=talos.resource.definitions.enums.NethelpersRouteProtocol\" json:\"protocol,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer      `protobuf:\"varint,12,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tMtu           uint32                        `protobuf:\"varint,13,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RouteSpecSpec) Reset() {\n\t*x = RouteSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[47]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RouteSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RouteSpecSpec) ProtoMessage() {}\n\nfunc (x *RouteSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[47]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RouteSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*RouteSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{47}\n}\n\nfunc (x *RouteSpecSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *RouteSpecSpec) GetDestination() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Destination\n\t}\n\treturn nil\n}\n\nfunc (x *RouteSpecSpec) GetSource() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn nil\n}\n\nfunc (x *RouteSpecSpec) GetGateway() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Gateway\n\t}\n\treturn nil\n}\n\nfunc (x *RouteSpecSpec) GetOutLinkName() string {\n\tif x != nil {\n\t\treturn x.OutLinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RouteSpecSpec) GetTable() enums.NethelpersRoutingTable {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn enums.NethelpersRoutingTable(0)\n}\n\nfunc (x *RouteSpecSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\nfunc (x *RouteSpecSpec) GetScope() enums.NethelpersScope {\n\tif x != nil {\n\t\treturn x.Scope\n\t}\n\treturn enums.NethelpersScope(0)\n}\n\nfunc (x *RouteSpecSpec) GetType() enums.NethelpersRouteType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.NethelpersRouteType(0)\n}\n\nfunc (x *RouteSpecSpec) GetFlags() uint32 {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn 0\n}\n\nfunc (x *RouteSpecSpec) GetProtocol() enums.NethelpersRouteProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn enums.NethelpersRouteProtocol(0)\n}\n\nfunc (x *RouteSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\nfunc (x *RouteSpecSpec) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\n// RouteStatusSpec describes status of rendered secrets.\ntype RouteStatusSpec struct {\n\tstate         protoimpl.MessageState        `protogen:\"open.v1\"`\n\tFamily        enums.NethelpersFamily        `protobuf:\"varint,1,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tDestination   *common.NetIPPrefix           `protobuf:\"bytes,2,opt,name=destination,proto3\" json:\"destination,omitempty\"`\n\tSource        *common.NetIP                 `protobuf:\"bytes,3,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tGateway       *common.NetIP                 `protobuf:\"bytes,4,opt,name=gateway,proto3\" json:\"gateway,omitempty\"`\n\tOutLinkIndex  uint32                        `protobuf:\"varint,5,opt,name=out_link_index,json=outLinkIndex,proto3\" json:\"out_link_index,omitempty\"`\n\tOutLinkName   string                        `protobuf:\"bytes,6,opt,name=out_link_name,json=outLinkName,proto3\" json:\"out_link_name,omitempty\"`\n\tTable         enums.NethelpersRoutingTable  `protobuf:\"varint,7,opt,name=table,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingTable\" json:\"table,omitempty\"`\n\tPriority      uint32                        `protobuf:\"varint,8,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tScope         enums.NethelpersScope         `protobuf:\"varint,9,opt,name=scope,proto3,enum=talos.resource.definitions.enums.NethelpersScope\" json:\"scope,omitempty\"`\n\tType          enums.NethelpersRouteType     `protobuf:\"varint,10,opt,name=type,proto3,enum=talos.resource.definitions.enums.NethelpersRouteType\" json:\"type,omitempty\"`\n\tFlags         uint32                        `protobuf:\"varint,11,opt,name=flags,proto3\" json:\"flags,omitempty\"`\n\tProtocol      enums.NethelpersRouteProtocol `protobuf:\"varint,12,opt,name=protocol,proto3,enum=talos.resource.definitions.enums.NethelpersRouteProtocol\" json:\"protocol,omitempty\"`\n\tMtu           uint32                        `protobuf:\"varint,13,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RouteStatusSpec) Reset() {\n\t*x = RouteStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[48]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RouteStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RouteStatusSpec) ProtoMessage() {}\n\nfunc (x *RouteStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[48]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RouteStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*RouteStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{48}\n}\n\nfunc (x *RouteStatusSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *RouteStatusSpec) GetDestination() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Destination\n\t}\n\treturn nil\n}\n\nfunc (x *RouteStatusSpec) GetSource() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn nil\n}\n\nfunc (x *RouteStatusSpec) GetGateway() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Gateway\n\t}\n\treturn nil\n}\n\nfunc (x *RouteStatusSpec) GetOutLinkIndex() uint32 {\n\tif x != nil {\n\t\treturn x.OutLinkIndex\n\t}\n\treturn 0\n}\n\nfunc (x *RouteStatusSpec) GetOutLinkName() string {\n\tif x != nil {\n\t\treturn x.OutLinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RouteStatusSpec) GetTable() enums.NethelpersRoutingTable {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn enums.NethelpersRoutingTable(0)\n}\n\nfunc (x *RouteStatusSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\nfunc (x *RouteStatusSpec) GetScope() enums.NethelpersScope {\n\tif x != nil {\n\t\treturn x.Scope\n\t}\n\treturn enums.NethelpersScope(0)\n}\n\nfunc (x *RouteStatusSpec) GetType() enums.NethelpersRouteType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn enums.NethelpersRouteType(0)\n}\n\nfunc (x *RouteStatusSpec) GetFlags() uint32 {\n\tif x != nil {\n\t\treturn x.Flags\n\t}\n\treturn 0\n}\n\nfunc (x *RouteStatusSpec) GetProtocol() enums.NethelpersRouteProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn enums.NethelpersRouteProtocol(0)\n}\n\nfunc (x *RouteStatusSpec) GetMtu() uint32 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\n// RoutingRuleSpecSpec describes the routing rule.\ntype RoutingRuleSpecSpec struct {\n\tstate         protoimpl.MessageState            `protogen:\"open.v1\"`\n\tFamily        enums.NethelpersFamily            `protobuf:\"varint,1,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tSrc           *common.NetIPPrefix               `protobuf:\"bytes,2,opt,name=src,proto3\" json:\"src,omitempty\"`\n\tDst           *common.NetIPPrefix               `protobuf:\"bytes,3,opt,name=dst,proto3\" json:\"dst,omitempty\"`\n\tTable         enums.NethelpersRoutingTable      `protobuf:\"varint,4,opt,name=table,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingTable\" json:\"table,omitempty\"`\n\tPriority      uint32                            `protobuf:\"varint,5,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tAction        enums.NethelpersRoutingRuleAction `protobuf:\"varint,6,opt,name=action,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingRuleAction\" json:\"action,omitempty\"`\n\tIifName       string                            `protobuf:\"bytes,7,opt,name=iif_name,json=iifName,proto3\" json:\"iif_name,omitempty\"`\n\tOifName       string                            `protobuf:\"bytes,8,opt,name=oif_name,json=oifName,proto3\" json:\"oif_name,omitempty\"`\n\tFwMark        uint32                            `protobuf:\"varint,9,opt,name=fw_mark,json=fwMark,proto3\" json:\"fw_mark,omitempty\"`\n\tFwMask        uint32                            `protobuf:\"varint,10,opt,name=fw_mask,json=fwMask,proto3\" json:\"fw_mask,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer          `protobuf:\"varint,11,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RoutingRuleSpecSpec) Reset() {\n\t*x = RoutingRuleSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[49]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RoutingRuleSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RoutingRuleSpecSpec) ProtoMessage() {}\n\nfunc (x *RoutingRuleSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[49]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RoutingRuleSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*RoutingRuleSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{49}\n}\n\nfunc (x *RoutingRuleSpecSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *RoutingRuleSpecSpec) GetSrc() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Src\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRuleSpecSpec) GetDst() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Dst\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRuleSpecSpec) GetTable() enums.NethelpersRoutingTable {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn enums.NethelpersRoutingTable(0)\n}\n\nfunc (x *RoutingRuleSpecSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingRuleSpecSpec) GetAction() enums.NethelpersRoutingRuleAction {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn enums.NethelpersRoutingRuleAction(0)\n}\n\nfunc (x *RoutingRuleSpecSpec) GetIifName() string {\n\tif x != nil {\n\t\treturn x.IifName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRuleSpecSpec) GetOifName() string {\n\tif x != nil {\n\t\treturn x.OifName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRuleSpecSpec) GetFwMark() uint32 {\n\tif x != nil {\n\t\treturn x.FwMark\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingRuleSpecSpec) GetFwMask() uint32 {\n\tif x != nil {\n\t\treturn x.FwMask\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingRuleSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\n// RoutingRuleStatusSpec describes the observed routing rule state.\ntype RoutingRuleStatusSpec struct {\n\tstate         protoimpl.MessageState            `protogen:\"open.v1\"`\n\tFamily        enums.NethelpersFamily            `protobuf:\"varint,1,opt,name=family,proto3,enum=talos.resource.definitions.enums.NethelpersFamily\" json:\"family,omitempty\"`\n\tSrc           *common.NetIPPrefix               `protobuf:\"bytes,2,opt,name=src,proto3\" json:\"src,omitempty\"`\n\tDst           *common.NetIPPrefix               `protobuf:\"bytes,3,opt,name=dst,proto3\" json:\"dst,omitempty\"`\n\tTable         enums.NethelpersRoutingTable      `protobuf:\"varint,4,opt,name=table,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingTable\" json:\"table,omitempty\"`\n\tPriority      uint32                            `protobuf:\"varint,5,opt,name=priority,proto3\" json:\"priority,omitempty\"`\n\tAction        enums.NethelpersRoutingRuleAction `protobuf:\"varint,6,opt,name=action,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingRuleAction\" json:\"action,omitempty\"`\n\tIifName       string                            `protobuf:\"bytes,7,opt,name=iif_name,json=iifName,proto3\" json:\"iif_name,omitempty\"`\n\tOifName       string                            `protobuf:\"bytes,8,opt,name=oif_name,json=oifName,proto3\" json:\"oif_name,omitempty\"`\n\tFwMark        uint32                            `protobuf:\"varint,9,opt,name=fw_mark,json=fwMark,proto3\" json:\"fw_mark,omitempty\"`\n\tFwMask        uint32                            `protobuf:\"varint,10,opt,name=fw_mask,json=fwMask,proto3\" json:\"fw_mask,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *RoutingRuleStatusSpec) Reset() {\n\t*x = RoutingRuleStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[50]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *RoutingRuleStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RoutingRuleStatusSpec) ProtoMessage() {}\n\nfunc (x *RoutingRuleStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[50]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RoutingRuleStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*RoutingRuleStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{50}\n}\n\nfunc (x *RoutingRuleStatusSpec) GetFamily() enums.NethelpersFamily {\n\tif x != nil {\n\t\treturn x.Family\n\t}\n\treturn enums.NethelpersFamily(0)\n}\n\nfunc (x *RoutingRuleStatusSpec) GetSrc() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Src\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRuleStatusSpec) GetDst() *common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.Dst\n\t}\n\treturn nil\n}\n\nfunc (x *RoutingRuleStatusSpec) GetTable() enums.NethelpersRoutingTable {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn enums.NethelpersRoutingTable(0)\n}\n\nfunc (x *RoutingRuleStatusSpec) GetPriority() uint32 {\n\tif x != nil {\n\t\treturn x.Priority\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingRuleStatusSpec) GetAction() enums.NethelpersRoutingRuleAction {\n\tif x != nil {\n\t\treturn x.Action\n\t}\n\treturn enums.NethelpersRoutingRuleAction(0)\n}\n\nfunc (x *RoutingRuleStatusSpec) GetIifName() string {\n\tif x != nil {\n\t\treturn x.IifName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRuleStatusSpec) GetOifName() string {\n\tif x != nil {\n\t\treturn x.OifName\n\t}\n\treturn \"\"\n}\n\nfunc (x *RoutingRuleStatusSpec) GetFwMark() uint32 {\n\tif x != nil {\n\t\treturn x.FwMark\n\t}\n\treturn 0\n}\n\nfunc (x *RoutingRuleStatusSpec) GetFwMask() uint32 {\n\tif x != nil {\n\t\treturn x.FwMask\n\t}\n\treturn 0\n}\n\n// STPSpec describes Spanning Tree Protocol (STP) settings of a bridge.\ntype STPSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEnabled       bool                   `protobuf:\"varint,1,opt,name=enabled,proto3\" json:\"enabled,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *STPSpec) Reset() {\n\t*x = STPSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[51]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *STPSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*STPSpec) ProtoMessage() {}\n\nfunc (x *STPSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[51]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use STPSpec.ProtoReflect.Descriptor instead.\nfunc (*STPSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{51}\n}\n\nfunc (x *STPSpec) GetEnabled() bool {\n\tif x != nil {\n\t\treturn x.Enabled\n\t}\n\treturn false\n}\n\n// StatusSpec describes network state.\ntype StatusSpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tAddressReady      bool                   `protobuf:\"varint,1,opt,name=address_ready,json=addressReady,proto3\" json:\"address_ready,omitempty\"`\n\tConnectivityReady bool                   `protobuf:\"varint,2,opt,name=connectivity_ready,json=connectivityReady,proto3\" json:\"connectivity_ready,omitempty\"`\n\tHostnameReady     bool                   `protobuf:\"varint,3,opt,name=hostname_ready,json=hostnameReady,proto3\" json:\"hostname_ready,omitempty\"`\n\tEtcFilesReady     bool                   `protobuf:\"varint,4,opt,name=etc_files_ready,json=etcFilesReady,proto3\" json:\"etc_files_ready,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *StatusSpec) Reset() {\n\t*x = StatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[52]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StatusSpec) ProtoMessage() {}\n\nfunc (x *StatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[52]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StatusSpec.ProtoReflect.Descriptor instead.\nfunc (*StatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{52}\n}\n\nfunc (x *StatusSpec) GetAddressReady() bool {\n\tif x != nil {\n\t\treturn x.AddressReady\n\t}\n\treturn false\n}\n\nfunc (x *StatusSpec) GetConnectivityReady() bool {\n\tif x != nil {\n\t\treturn x.ConnectivityReady\n\t}\n\treturn false\n}\n\nfunc (x *StatusSpec) GetHostnameReady() bool {\n\tif x != nil {\n\t\treturn x.HostnameReady\n\t}\n\treturn false\n}\n\nfunc (x *StatusSpec) GetEtcFilesReady() bool {\n\tif x != nil {\n\t\treturn x.EtcFilesReady\n\t}\n\treturn false\n}\n\n// TCPProbeSpec describes the TCP Probe.\ntype TCPProbeSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEndpoint      string                 `protobuf:\"bytes,1,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tTimeout       *durationpb.Duration   `protobuf:\"bytes,2,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TCPProbeSpec) Reset() {\n\t*x = TCPProbeSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[53]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TCPProbeSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TCPProbeSpec) ProtoMessage() {}\n\nfunc (x *TCPProbeSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[53]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TCPProbeSpec.ProtoReflect.Descriptor instead.\nfunc (*TCPProbeSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{53}\n}\n\nfunc (x *TCPProbeSpec) GetEndpoint() string {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *TCPProbeSpec) GetTimeout() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn nil\n}\n\n// TimeServerSpecSpec describes NTP servers.\ntype TimeServerSpecSpec struct {\n\tstate         protoimpl.MessageState   `protogen:\"open.v1\"`\n\tNtpServers    []string                 `protobuf:\"bytes,1,rep,name=ntp_servers,json=ntpServers,proto3\" json:\"ntp_servers,omitempty\"`\n\tConfigLayer   enums.NetworkConfigLayer `protobuf:\"varint,2,opt,name=config_layer,json=configLayer,proto3,enum=talos.resource.definitions.enums.NetworkConfigLayer\" json:\"config_layer,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TimeServerSpecSpec) Reset() {\n\t*x = TimeServerSpecSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[54]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeServerSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeServerSpecSpec) ProtoMessage() {}\n\nfunc (x *TimeServerSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[54]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TimeServerSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*TimeServerSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{54}\n}\n\nfunc (x *TimeServerSpecSpec) GetNtpServers() []string {\n\tif x != nil {\n\t\treturn x.NtpServers\n\t}\n\treturn nil\n}\n\nfunc (x *TimeServerSpecSpec) GetConfigLayer() enums.NetworkConfigLayer {\n\tif x != nil {\n\t\treturn x.ConfigLayer\n\t}\n\treturn enums.NetworkConfigLayer(0)\n}\n\n// TimeServerStatusSpec describes NTP servers.\ntype TimeServerStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tNtpServers    []string               `protobuf:\"bytes,1,rep,name=ntp_servers,json=ntpServers,proto3\" json:\"ntp_servers,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TimeServerStatusSpec) Reset() {\n\t*x = TimeServerStatusSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[55]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeServerStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeServerStatusSpec) ProtoMessage() {}\n\nfunc (x *TimeServerStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[55]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TimeServerStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*TimeServerStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{55}\n}\n\nfunc (x *TimeServerStatusSpec) GetNtpServers() []string {\n\tif x != nil {\n\t\treturn x.NtpServers\n\t}\n\treturn nil\n}\n\n// VIPEquinixMetalSpec describes virtual (elastic) IP settings for Equinix Metal.\ntype VIPEquinixMetalSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tProjectId     string                 `protobuf:\"bytes,1,opt,name=project_id,json=projectId,proto3\" json:\"project_id,omitempty\"`\n\tDeviceId      string                 `protobuf:\"bytes,2,opt,name=device_id,json=deviceId,proto3\" json:\"device_id,omitempty\"`\n\tApiToken      string                 `protobuf:\"bytes,3,opt,name=api_token,json=apiToken,proto3\" json:\"api_token,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VIPEquinixMetalSpec) Reset() {\n\t*x = VIPEquinixMetalSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[56]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VIPEquinixMetalSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VIPEquinixMetalSpec) ProtoMessage() {}\n\nfunc (x *VIPEquinixMetalSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[56]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VIPEquinixMetalSpec.ProtoReflect.Descriptor instead.\nfunc (*VIPEquinixMetalSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{56}\n}\n\nfunc (x *VIPEquinixMetalSpec) GetProjectId() string {\n\tif x != nil {\n\t\treturn x.ProjectId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VIPEquinixMetalSpec) GetDeviceId() string {\n\tif x != nil {\n\t\treturn x.DeviceId\n\t}\n\treturn \"\"\n}\n\nfunc (x *VIPEquinixMetalSpec) GetApiToken() string {\n\tif x != nil {\n\t\treturn x.ApiToken\n\t}\n\treturn \"\"\n}\n\n// VIPHCloudSpec describes virtual (elastic) IP settings for Hetzner Cloud.\ntype VIPHCloudSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDeviceId      int64                  `protobuf:\"varint,1,opt,name=device_id,json=deviceId,proto3\" json:\"device_id,omitempty\"`\n\tNetworkId     int64                  `protobuf:\"varint,2,opt,name=network_id,json=networkId,proto3\" json:\"network_id,omitempty\"`\n\tApiToken      string                 `protobuf:\"bytes,3,opt,name=api_token,json=apiToken,proto3\" json:\"api_token,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VIPHCloudSpec) Reset() {\n\t*x = VIPHCloudSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[57]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VIPHCloudSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VIPHCloudSpec) ProtoMessage() {}\n\nfunc (x *VIPHCloudSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[57]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VIPHCloudSpec.ProtoReflect.Descriptor instead.\nfunc (*VIPHCloudSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{57}\n}\n\nfunc (x *VIPHCloudSpec) GetDeviceId() int64 {\n\tif x != nil {\n\t\treturn x.DeviceId\n\t}\n\treturn 0\n}\n\nfunc (x *VIPHCloudSpec) GetNetworkId() int64 {\n\tif x != nil {\n\t\treturn x.NetworkId\n\t}\n\treturn 0\n}\n\nfunc (x *VIPHCloudSpec) GetApiToken() string {\n\tif x != nil {\n\t\treturn x.ApiToken\n\t}\n\treturn \"\"\n}\n\n// VIPOperatorSpec describes virtual IP operator options.\ntype VIPOperatorSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIp            *common.NetIP          `protobuf:\"bytes,1,opt,name=ip,proto3\" json:\"ip,omitempty\"`\n\tGratuitousArp bool                   `protobuf:\"varint,2,opt,name=gratuitous_arp,json=gratuitousArp,proto3\" json:\"gratuitous_arp,omitempty\"`\n\tEquinixMetal  *VIPEquinixMetalSpec   `protobuf:\"bytes,3,opt,name=equinix_metal,json=equinixMetal,proto3\" json:\"equinix_metal,omitempty\"`\n\tHCloud        *VIPHCloudSpec         `protobuf:\"bytes,4,opt,name=h_cloud,json=hCloud,proto3\" json:\"h_cloud,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VIPOperatorSpec) Reset() {\n\t*x = VIPOperatorSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[58]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VIPOperatorSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VIPOperatorSpec) ProtoMessage() {}\n\nfunc (x *VIPOperatorSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[58]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VIPOperatorSpec.ProtoReflect.Descriptor instead.\nfunc (*VIPOperatorSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{58}\n}\n\nfunc (x *VIPOperatorSpec) GetIp() *common.NetIP {\n\tif x != nil {\n\t\treturn x.Ip\n\t}\n\treturn nil\n}\n\nfunc (x *VIPOperatorSpec) GetGratuitousArp() bool {\n\tif x != nil {\n\t\treturn x.GratuitousArp\n\t}\n\treturn false\n}\n\nfunc (x *VIPOperatorSpec) GetEquinixMetal() *VIPEquinixMetalSpec {\n\tif x != nil {\n\t\treturn x.EquinixMetal\n\t}\n\treturn nil\n}\n\nfunc (x *VIPOperatorSpec) GetHCloud() *VIPHCloudSpec {\n\tif x != nil {\n\t\treturn x.HCloud\n\t}\n\treturn nil\n}\n\n// VLANSpec describes VLAN settings if Kind == \"vlan\".\ntype VLANSpec struct {\n\tstate         protoimpl.MessageState       `protogen:\"open.v1\"`\n\tVid           uint32                       `protobuf:\"varint,1,opt,name=vid,proto3\" json:\"vid,omitempty\"`\n\tProtocol      enums.NethelpersVLANProtocol `protobuf:\"varint,2,opt,name=protocol,proto3,enum=talos.resource.definitions.enums.NethelpersVLANProtocol\" json:\"protocol,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VLANSpec) Reset() {\n\t*x = VLANSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[59]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VLANSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VLANSpec) ProtoMessage() {}\n\nfunc (x *VLANSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[59]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VLANSpec.ProtoReflect.Descriptor instead.\nfunc (*VLANSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{59}\n}\n\nfunc (x *VLANSpec) GetVid() uint32 {\n\tif x != nil {\n\t\treturn x.Vid\n\t}\n\treturn 0\n}\n\nfunc (x *VLANSpec) GetProtocol() enums.NethelpersVLANProtocol {\n\tif x != nil {\n\t\treturn x.Protocol\n\t}\n\treturn enums.NethelpersVLANProtocol(0)\n}\n\n// VRFMasterSpec describes vrf settings if Kind == \"vrf\".\ntype VRFMasterSpec struct {\n\tstate         protoimpl.MessageState       `protogen:\"open.v1\"`\n\tTable         enums.NethelpersRoutingTable `protobuf:\"varint,1,opt,name=table,proto3,enum=talos.resource.definitions.enums.NethelpersRoutingTable\" json:\"table,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VRFMasterSpec) Reset() {\n\t*x = VRFMasterSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[60]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VRFMasterSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VRFMasterSpec) ProtoMessage() {}\n\nfunc (x *VRFMasterSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[60]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VRFMasterSpec.ProtoReflect.Descriptor instead.\nfunc (*VRFMasterSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{60}\n}\n\nfunc (x *VRFMasterSpec) GetTable() enums.NethelpersRoutingTable {\n\tif x != nil {\n\t\treturn x.Table\n\t}\n\treturn enums.NethelpersRoutingTable(0)\n}\n\n// VRFSlave contains the name of the master vrf for an interface\ntype VRFSlave struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMasterName    string                 `protobuf:\"bytes,1,opt,name=master_name,json=masterName,proto3\" json:\"master_name,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *VRFSlave) Reset() {\n\t*x = VRFSlave{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[61]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *VRFSlave) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*VRFSlave) ProtoMessage() {}\n\nfunc (x *VRFSlave) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[61]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use VRFSlave.ProtoReflect.Descriptor instead.\nfunc (*VRFSlave) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{61}\n}\n\nfunc (x *VRFSlave) GetMasterName() string {\n\tif x != nil {\n\t\treturn x.MasterName\n\t}\n\treturn \"\"\n}\n\n// WireguardPeer describes a single peer.\ntype WireguardPeer struct {\n\tstate                       protoimpl.MessageState `protogen:\"open.v1\"`\n\tPublicKey                   string                 `protobuf:\"bytes,1,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tPresharedKey                string                 `protobuf:\"bytes,2,opt,name=preshared_key,json=presharedKey,proto3\" json:\"preshared_key,omitempty\"`\n\tEndpoint                    string                 `protobuf:\"bytes,3,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tPersistentKeepaliveInterval *durationpb.Duration   `protobuf:\"bytes,4,opt,name=persistent_keepalive_interval,json=persistentKeepaliveInterval,proto3\" json:\"persistent_keepalive_interval,omitempty\"`\n\tAllowedIps                  []*common.NetIPPrefix  `protobuf:\"bytes,5,rep,name=allowed_ips,json=allowedIps,proto3\" json:\"allowed_ips,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *WireguardPeer) Reset() {\n\t*x = WireguardPeer{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[62]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WireguardPeer) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WireguardPeer) ProtoMessage() {}\n\nfunc (x *WireguardPeer) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[62]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WireguardPeer.ProtoReflect.Descriptor instead.\nfunc (*WireguardPeer) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{62}\n}\n\nfunc (x *WireguardPeer) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *WireguardPeer) GetPresharedKey() string {\n\tif x != nil {\n\t\treturn x.PresharedKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *WireguardPeer) GetEndpoint() string {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *WireguardPeer) GetPersistentKeepaliveInterval() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.PersistentKeepaliveInterval\n\t}\n\treturn nil\n}\n\nfunc (x *WireguardPeer) GetAllowedIps() []*common.NetIPPrefix {\n\tif x != nil {\n\t\treturn x.AllowedIps\n\t}\n\treturn nil\n}\n\n// WireguardSpec describes Wireguard settings if Kind == \"wireguard\".\ntype WireguardSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPrivateKey    string                 `protobuf:\"bytes,1,opt,name=private_key,json=privateKey,proto3\" json:\"private_key,omitempty\"`\n\tPublicKey     string                 `protobuf:\"bytes,2,opt,name=public_key,json=publicKey,proto3\" json:\"public_key,omitempty\"`\n\tListenPort    int64                  `protobuf:\"varint,3,opt,name=listen_port,json=listenPort,proto3\" json:\"listen_port,omitempty\"`\n\tFirewallMark  int64                  `protobuf:\"varint,4,opt,name=firewall_mark,json=firewallMark,proto3\" json:\"firewall_mark,omitempty\"`\n\tPeers         []*WireguardPeer       `protobuf:\"bytes,5,rep,name=peers,proto3\" json:\"peers,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *WireguardSpec) Reset() {\n\t*x = WireguardSpec{}\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[63]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WireguardSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WireguardSpec) ProtoMessage() {}\n\nfunc (x *WireguardSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_network_network_proto_msgTypes[63]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WireguardSpec.ProtoReflect.Descriptor instead.\nfunc (*WireguardSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_network_network_proto_rawDescGZIP(), []int{63}\n}\n\nfunc (x *WireguardSpec) GetPrivateKey() string {\n\tif x != nil {\n\t\treturn x.PrivateKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *WireguardSpec) GetPublicKey() string {\n\tif x != nil {\n\t\treturn x.PublicKey\n\t}\n\treturn \"\"\n}\n\nfunc (x *WireguardSpec) GetListenPort() int64 {\n\tif x != nil {\n\t\treturn x.ListenPort\n\t}\n\treturn 0\n}\n\nfunc (x *WireguardSpec) GetFirewallMark() int64 {\n\tif x != nil {\n\t\treturn x.FirewallMark\n\t}\n\treturn 0\n}\n\nfunc (x *WireguardSpec) GetPeers() []*WireguardPeer {\n\tif x != nil {\n\t\treturn x.Peers\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_network_network_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_network_network_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"*resource/definitions/network/network.proto\\x12\\\"talos.resource.definitions.network\\x1a\\x13common/common.proto\\x1a\\x1egoogle/protobuf/duration.proto\\x1a&resource/definitions/enums/enums.proto\\x1a*resource/definitions/runtime/runtime.proto\\\"\\xa9\\x03\\n\" +\n\t\"\\x0fAddressSpecSpec\\x12-\\n\" +\n\t\"\\aaddress\\x18\\x01 \\x01(\\v2\\x13.common.NetIPPrefixR\\aaddress\\x12\\x1b\\n\" +\n\t\"\\tlink_name\\x18\\x02 \\x01(\\tR\\blinkName\\x12J\\n\" +\n\t\"\\x06family\\x18\\x03 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x12G\\n\" +\n\t\"\\x05scope\\x18\\x04 \\x01(\\x0e21.talos.resource.definitions.enums.NethelpersScopeR\\x05scope\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\x05 \\x01(\\rR\\x05flags\\x12*\\n\" +\n\t\"\\x11announce_with_arp\\x18\\x06 \\x01(\\bR\\x0fannounceWithArp\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\a \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\b \\x01(\\rR\\bpriority\\\"\\xed\\x03\\n\" +\n\t\"\\x11AddressStatusSpec\\x12-\\n\" +\n\t\"\\aaddress\\x18\\x01 \\x01(\\v2\\x13.common.NetIPPrefixR\\aaddress\\x12#\\n\" +\n\t\"\\x05local\\x18\\x02 \\x01(\\v2\\r.common.NetIPR\\x05local\\x12+\\n\" +\n\t\"\\tbroadcast\\x18\\x03 \\x01(\\v2\\r.common.NetIPR\\tbroadcast\\x12'\\n\" +\n\t\"\\aanycast\\x18\\x04 \\x01(\\v2\\r.common.NetIPR\\aanycast\\x12+\\n\" +\n\t\"\\tmulticast\\x18\\x05 \\x01(\\v2\\r.common.NetIPR\\tmulticast\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"link_index\\x18\\x06 \\x01(\\rR\\tlinkIndex\\x12\\x1b\\n\" +\n\t\"\\tlink_name\\x18\\a \\x01(\\tR\\blinkName\\x12J\\n\" +\n\t\"\\x06family\\x18\\b \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x12G\\n\" +\n\t\"\\x05scope\\x18\\t \\x01(\\x0e21.talos.resource.definitions.enums.NethelpersScopeR\\x05scope\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\n\" +\n\t\" \\x01(\\rR\\x05flags\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\v \\x01(\\rR\\bpriority\\\"\\x8a\\f\\n\" +\n\t\"\\x0eBondMasterSpec\\x12H\\n\" +\n\t\"\\x04mode\\x18\\x01 \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersBondModeR\\x04mode\\x12_\\n\" +\n\t\"\\vhash_policy\\x18\\x02 \\x01(\\x0e2>.talos.resource.definitions.enums.NethelpersBondXmitHashPolicyR\\n\" +\n\t\"hashPolicy\\x12Q\\n\" +\n\t\"\\tlacp_rate\\x18\\x03 \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersLACPRateR\\blacpRate\\x12Z\\n\" +\n\t\"\\farp_validate\\x18\\x04 \\x01(\\x0e27.talos.resource.definitions.enums.NethelpersARPValidateR\\varpValidate\\x12a\\n\" +\n\t\"\\x0farp_all_targets\\x18\\x05 \\x01(\\x0e29.talos.resource.definitions.enums.NethelpersARPAllTargetsR\\rarpAllTargets\\x12#\\n\" +\n\t\"\\rprimary_index\\x18\\x06 \\x01(\\rR\\fprimaryIndex\\x12f\\n\" +\n\t\"\\x10primary_reselect\\x18\\a \\x01(\\x0e2;.talos.resource.definitions.enums.NethelpersPrimaryReselectR\\x0fprimaryReselect\\x12[\\n\" +\n\t\"\\rfail_over_mac\\x18\\b \\x01(\\x0e27.talos.resource.definitions.enums.NethelpersFailOverMACR\\vfailOverMac\\x12Q\\n\" +\n\t\"\\tad_select\\x18\\t \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersADSelectR\\badSelect\\x12\\x17\\n\" +\n\t\"\\amii_mon\\x18\\n\" +\n\t\" \\x01(\\rR\\x06miiMon\\x12\\x19\\n\" +\n\t\"\\bup_delay\\x18\\v \\x01(\\rR\\aupDelay\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"down_delay\\x18\\f \\x01(\\rR\\tdownDelay\\x12!\\n\" +\n\t\"\\farp_interval\\x18\\r \\x01(\\rR\\varpInterval\\x12\\x1f\\n\" +\n\t\"\\vresend_igmp\\x18\\x0e \\x01(\\rR\\n\" +\n\t\"resendIgmp\\x12\\x1b\\n\" +\n\t\"\\tmin_links\\x18\\x0f \\x01(\\rR\\bminLinks\\x12\\x1f\\n\" +\n\t\"\\vlp_interval\\x18\\x10 \\x01(\\rR\\n\" +\n\t\"lpInterval\\x12*\\n\" +\n\t\"\\x11packets_per_slave\\x18\\x11 \\x01(\\rR\\x0fpacketsPerSlave\\x12$\\n\" +\n\t\"\\x0enum_peer_notif\\x18\\x12 \\x01(\\rR\\fnumPeerNotif\\x12$\\n\" +\n\t\"\\x0etlb_dynamic_lb\\x18\\x13 \\x01(\\rR\\ftlbDynamicLb\\x12*\\n\" +\n\t\"\\x11all_slaves_active\\x18\\x14 \\x01(\\rR\\x0fallSlavesActive\\x12\\x1f\\n\" +\n\t\"\\vuse_carrier\\x18\\x15 \\x01(\\bR\\n\" +\n\t\"useCarrier\\x12)\\n\" +\n\t\"\\x11ad_actor_sys_prio\\x18\\x16 \\x01(\\rR\\x0eadActorSysPrio\\x12'\\n\" +\n\t\"\\x10ad_user_port_key\\x18\\x17 \\x01(\\rR\\radUserPortKey\\x12*\\n\" +\n\t\"\\x11peer_notify_delay\\x18\\x18 \\x01(\\rR\\x0fpeerNotifyDelay\\x122\\n\" +\n\t\"\\rarpip_targets\\x18\\x19 \\x03(\\v2\\r.common.NetIPR\\farpipTargets\\x122\\n\" +\n\t\"\\rnsip6_targets\\x18\\x1a \\x03(\\v2\\r.common.NetIPR\\fnsip6Targets\\x12]\\n\" +\n\t\"\\radlacp_active\\x18\\x1b \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersADLACPActiveR\\fadlacpActive\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"missed_max\\x18\\x1c \\x01(\\rR\\tmissedMax\\\"M\\n\" +\n\t\"\\tBondSlave\\x12\\x1f\\n\" +\n\t\"\\vmaster_name\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"masterName\\x12\\x1f\\n\" +\n\t\"\\vslave_index\\x18\\x02 \\x01(\\x03R\\n\" +\n\t\"slaveIndex\\\"\\x99\\x01\\n\" +\n\t\"\\x10BridgeMasterSpec\\x12=\\n\" +\n\t\"\\x03stp\\x18\\x01 \\x01(\\v2+.talos.resource.definitions.network.STPSpecR\\x03stp\\x12F\\n\" +\n\t\"\\x04vlan\\x18\\x02 \\x01(\\v22.talos.resource.definitions.network.BridgeVLANSpecR\\x04vlan\\\".\\n\" +\n\t\"\\vBridgeSlave\\x12\\x1f\\n\" +\n\t\"\\vmaster_name\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"masterName\\\"=\\n\" +\n\t\"\\x0eBridgeVLANSpec\\x12+\\n\" +\n\t\"\\x11filtering_enabled\\x18\\x01 \\x01(\\bR\\x10filteringEnabled\\\"\\xa3\\x01\\n\" +\n\t\"\\x14ClientIdentifierSpec\\x12i\\n\" +\n\t\"\\x11client_identifier\\x18\\x01 \\x01(\\x0e2<.talos.resource.definitions.enums.NethelpersClientIdentifierR\\x10clientIdentifier\\x12 \\n\" +\n\t\"\\fduid_raw_hex\\x18\\x02 \\x01(\\tR\\n\" +\n\t\"duidRawHex\\\"\\xd1\\x01\\n\" +\n\t\"\\x11DHCP4OperatorSpec\\x12!\\n\" +\n\t\"\\froute_metric\\x18\\x01 \\x01(\\rR\\vrouteMetric\\x122\\n\" +\n\t\"\\x15skip_hostname_request\\x18\\x02 \\x01(\\bR\\x13skipHostnameRequest\\x12e\\n\" +\n\t\"\\x11client_identifier\\x18\\x03 \\x01(\\v28.talos.resource.definitions.network.ClientIdentifierSpecR\\x10clientIdentifier\\\"\\xd1\\x01\\n\" +\n\t\"\\x11DHCP6OperatorSpec\\x12!\\n\" +\n\t\"\\froute_metric\\x18\\x02 \\x01(\\rR\\vrouteMetric\\x122\\n\" +\n\t\"\\x15skip_hostname_request\\x18\\x03 \\x01(\\bR\\x13skipHostnameRequest\\x12e\\n\" +\n\t\"\\x11client_identifier\\x18\\x04 \\x01(\\v28.talos.resource.definitions.network.ClientIdentifierSpecR\\x10clientIdentifier\\\"-\\n\" +\n\t\"\\x13DNSResolveCacheSpec\\x12\\x16\\n\" +\n\t\"\\x06status\\x18\\x01 \\x01(\\tR\\x06status\\\"h\\n\" +\n\t\"\\x14EthernetChannelsSpec\\x12\\x0e\\n\" +\n\t\"\\x02rx\\x18\\x01 \\x01(\\rR\\x02rx\\x12\\x0e\\n\" +\n\t\"\\x02tx\\x18\\x02 \\x01(\\rR\\x02tx\\x12\\x14\\n\" +\n\t\"\\x05other\\x18\\x03 \\x01(\\rR\\x05other\\x12\\x1a\\n\" +\n\t\"\\bcombined\\x18\\x04 \\x01(\\rR\\bcombined\\\"\\xd8\\x01\\n\" +\n\t\"\\x16EthernetChannelsStatus\\x12\\x15\\n\" +\n\t\"\\x06rx_max\\x18\\x01 \\x01(\\rR\\x05rxMax\\x12\\x15\\n\" +\n\t\"\\x06tx_max\\x18\\x02 \\x01(\\rR\\x05txMax\\x12\\x1b\\n\" +\n\t\"\\tother_max\\x18\\x03 \\x01(\\rR\\botherMax\\x12!\\n\" +\n\t\"\\fcombined_max\\x18\\x04 \\x01(\\rR\\vcombinedMax\\x12\\x0e\\n\" +\n\t\"\\x02rx\\x18\\x05 \\x01(\\rR\\x02rx\\x12\\x0e\\n\" +\n\t\"\\x02tx\\x18\\x06 \\x01(\\rR\\x02tx\\x12\\x14\\n\" +\n\t\"\\x05other\\x18\\a \\x01(\\rR\\x05other\\x12\\x1a\\n\" +\n\t\"\\bcombined\\x18\\b \\x01(\\rR\\bcombined\\\"C\\n\" +\n\t\"\\x15EthernetFeatureStatus\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06status\\x18\\x02 \\x01(\\tR\\x06status\\\"\\x9f\\x02\\n\" +\n\t\"\\x11EthernetRingsSpec\\x12\\x0e\\n\" +\n\t\"\\x02rx\\x18\\x01 \\x01(\\rR\\x02rx\\x12\\x17\\n\" +\n\t\"\\arx_mini\\x18\\x02 \\x01(\\rR\\x06rxMini\\x12\\x19\\n\" +\n\t\"\\brx_jumbo\\x18\\x03 \\x01(\\rR\\arxJumbo\\x12\\x0e\\n\" +\n\t\"\\x02tx\\x18\\x04 \\x01(\\rR\\x02tx\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"rx_buf_len\\x18\\x05 \\x01(\\rR\\brxBufLen\\x12\\x19\\n\" +\n\t\"\\bcqe_size\\x18\\x06 \\x01(\\rR\\acqeSize\\x12\\x17\\n\" +\n\t\"\\atx_push\\x18\\a \\x01(\\bR\\x06txPush\\x12\\x17\\n\" +\n\t\"\\arx_push\\x18\\b \\x01(\\bR\\x06rxPush\\x12%\\n\" +\n\t\"\\x0ftx_push_buf_len\\x18\\t \\x01(\\rR\\ftxPushBufLen\\x12$\\n\" +\n\t\"\\x0etcp_data_split\\x18\\n\" +\n\t\" \\x01(\\bR\\ftcpDataSplit\\\"\\xbf\\x03\\n\" +\n\t\"\\x13EthernetRingsStatus\\x12\\x15\\n\" +\n\t\"\\x06rx_max\\x18\\x01 \\x01(\\rR\\x05rxMax\\x12\\x1e\\n\" +\n\t\"\\vrx_mini_max\\x18\\x02 \\x01(\\rR\\trxMiniMax\\x12 \\n\" +\n\t\"\\frx_jumbo_max\\x18\\x03 \\x01(\\rR\\n\" +\n\t\"rxJumboMax\\x12\\x15\\n\" +\n\t\"\\x06tx_max\\x18\\x04 \\x01(\\rR\\x05txMax\\x12,\\n\" +\n\t\"\\x13tx_push_buf_len_max\\x18\\x05 \\x01(\\rR\\x0ftxPushBufLenMax\\x12\\x0e\\n\" +\n\t\"\\x02rx\\x18\\x06 \\x01(\\rR\\x02rx\\x12\\x17\\n\" +\n\t\"\\arx_mini\\x18\\a \\x01(\\rR\\x06rxMini\\x12\\x19\\n\" +\n\t\"\\brx_jumbo\\x18\\b \\x01(\\rR\\arxJumbo\\x12\\x0e\\n\" +\n\t\"\\x02tx\\x18\\t \\x01(\\rR\\x02tx\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"rx_buf_len\\x18\\n\" +\n\t\" \\x01(\\rR\\brxBufLen\\x12\\x19\\n\" +\n\t\"\\bcqe_size\\x18\\v \\x01(\\rR\\acqeSize\\x12\\x17\\n\" +\n\t\"\\atx_push\\x18\\f \\x01(\\bR\\x06txPush\\x12\\x17\\n\" +\n\t\"\\arx_push\\x18\\r \\x01(\\bR\\x06rxPush\\x12%\\n\" +\n\t\"\\x0ftx_push_buf_len\\x18\\x0e \\x01(\\rR\\ftxPushBufLen\\x12$\\n\" +\n\t\"\\x0etcp_data_split\\x18\\x0f \\x01(\\bR\\ftcpDataSplit\\\"\\xa7\\x03\\n\" +\n\t\"\\x10EthernetSpecSpec\\x12K\\n\" +\n\t\"\\x05rings\\x18\\x01 \\x01(\\v25.talos.resource.definitions.network.EthernetRingsSpecR\\x05rings\\x12^\\n\" +\n\t\"\\bfeatures\\x18\\x02 \\x03(\\v2B.talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntryR\\bfeatures\\x12T\\n\" +\n\t\"\\bchannels\\x18\\x03 \\x01(\\v28.talos.resource.definitions.network.EthernetChannelsSpecR\\bchannels\\x12S\\n\" +\n\t\"\\vwake_on_lan\\x18\\x04 \\x03(\\x0e23.talos.resource.definitions.enums.NethelpersWOLModeR\\twakeOnLan\\x1a;\\n\" +\n\t\"\\rFeaturesEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\bR\\x05value:\\x028\\x01\\\"\\xfb\\x04\\n\" +\n\t\"\\x12EthernetStatusSpec\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"link_state\\x18\\x01 \\x01(\\bR\\tlinkState\\x12%\\n\" +\n\t\"\\x0espeed_megabits\\x18\\x02 \\x01(\\x03R\\rspeedMegabits\\x12D\\n\" +\n\t\"\\x04port\\x18\\x03 \\x01(\\x0e20.talos.resource.definitions.enums.NethelpersPortR\\x04port\\x12J\\n\" +\n\t\"\\x06duplex\\x18\\x04 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersDuplexR\\x06duplex\\x12\\x1b\\n\" +\n\t\"\\tour_modes\\x18\\x05 \\x03(\\tR\\bourModes\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"peer_modes\\x18\\x06 \\x03(\\tR\\tpeerModes\\x12M\\n\" +\n\t\"\\x05rings\\x18\\a \\x01(\\v27.talos.resource.definitions.network.EthernetRingsStatusR\\x05rings\\x12U\\n\" +\n\t\"\\bfeatures\\x18\\b \\x03(\\v29.talos.resource.definitions.network.EthernetFeatureStatusR\\bfeatures\\x12V\\n\" +\n\t\"\\bchannels\\x18\\t \\x01(\\v2:.talos.resource.definitions.network.EthernetChannelsStatusR\\bchannels\\x12S\\n\" +\n\t\"\\vwake_on_lan\\x18\\n\" +\n\t\" \\x03(\\x0e23.talos.resource.definitions.enums.NethelpersWOLModeR\\twakeOnLan\\\"K\\n\" +\n\t\"\\x10HardwareAddrSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12#\\n\" +\n\t\"\\rhardware_addr\\x18\\x02 \\x01(\\fR\\fhardwareAddr\\\"\\xe5\\x01\\n\" +\n\t\"\\x11HostDNSConfigSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\x12<\\n\" +\n\t\"\\x10listen_addresses\\x18\\x02 \\x03(\\v2\\x11.common.NetIPPortR\\x0flistenAddresses\\x12F\\n\" +\n\t\"\\x18service_host_dns_address\\x18\\x03 \\x01(\\v2\\r.common.NetIPR\\x15serviceHostDnsAddress\\x120\\n\" +\n\t\"\\x14resolve_member_names\\x18\\x04 \\x01(\\bR\\x12resolveMemberNames\\\"\\xa7\\x01\\n\" +\n\t\"\\x10HostnameSpecSpec\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x01 \\x01(\\tR\\bhostname\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"domainname\\x18\\x02 \\x01(\\tR\\n\" +\n\t\"domainname\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\x03 \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\\"P\\n\" +\n\t\"\\x12HostnameStatusSpec\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x01 \\x01(\\tR\\bhostname\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"domainname\\x18\\x02 \\x01(\\tR\\n\" +\n\t\"domainname\\\")\\n\" +\n\t\"\\x11LinkAliasSpecSpec\\x12\\x14\\n\" +\n\t\"\\x05alias\\x18\\x01 \\x01(\\tR\\x05alias\\\"1\\n\" +\n\t\"\\x0fLinkRefreshSpec\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"generation\\x18\\x01 \\x01(\\x03R\\n\" +\n\t\"generation\\\"\\x81\\b\\n\" +\n\t\"\\fLinkSpecSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x18\\n\" +\n\t\"\\alogical\\x18\\x02 \\x01(\\bR\\alogical\\x12\\x0e\\n\" +\n\t\"\\x02up\\x18\\x03 \\x01(\\bR\\x02up\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\x04 \\x01(\\rR\\x03mtu\\x12\\x12\\n\" +\n\t\"\\x04kind\\x18\\x05 \\x01(\\tR\\x04kind\\x12H\\n\" +\n\t\"\\x04type\\x18\\x06 \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersLinkTypeR\\x04type\\x12\\x1f\\n\" +\n\t\"\\vparent_name\\x18\\a \\x01(\\tR\\n\" +\n\t\"parentName\\x12L\\n\" +\n\t\"\\n\" +\n\t\"bond_slave\\x18\\b \\x01(\\v2-.talos.resource.definitions.network.BondSlaveR\\tbondSlave\\x12R\\n\" +\n\t\"\\fbridge_slave\\x18\\t \\x01(\\v2/.talos.resource.definitions.network.BridgeSlaveR\\vbridgeSlave\\x12@\\n\" +\n\t\"\\x04vlan\\x18\\n\" +\n\t\" \\x01(\\v2,.talos.resource.definitions.network.VLANSpecR\\x04vlan\\x12S\\n\" +\n\t\"\\vbond_master\\x18\\v \\x01(\\v22.talos.resource.definitions.network.BondMasterSpecR\\n\" +\n\t\"bondMaster\\x12Y\\n\" +\n\t\"\\rbridge_master\\x18\\f \\x01(\\v24.talos.resource.definitions.network.BridgeMasterSpecR\\fbridgeMaster\\x12O\\n\" +\n\t\"\\twireguard\\x18\\r \\x01(\\v21.talos.resource.definitions.network.WireguardSpecR\\twireguard\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\x0e \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\x12)\\n\" +\n\t\"\\x10hardware_address\\x18\\x0f \\x01(\\fR\\x0fhardwareAddress\\x12\\x1c\\n\" +\n\t\"\\tmulticast\\x18\\x10 \\x01(\\bR\\tmulticast\\x12P\\n\" +\n\t\"\\n\" +\n\t\"vrf_master\\x18\\x11 \\x01(\\v21.talos.resource.definitions.network.VRFMasterSpecR\\tvrfMaster\\x12I\\n\" +\n\t\"\\tvrf_slave\\x18\\x12 \\x01(\\v2,.talos.resource.definitions.network.VRFSlaveR\\bvrfSlave\\\"\\xb3\\v\\n\" +\n\t\"\\x0eLinkStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05index\\x18\\x01 \\x01(\\rR\\x05index\\x12H\\n\" +\n\t\"\\x04type\\x18\\x02 \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersLinkTypeR\\x04type\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"link_index\\x18\\x03 \\x01(\\rR\\tlinkIndex\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\x04 \\x01(\\rR\\x05flags\\x12#\\n\" +\n\t\"\\rhardware_addr\\x18\\x05 \\x01(\\fR\\fhardwareAddr\\x12%\\n\" +\n\t\"\\x0ebroadcast_addr\\x18\\x06 \\x01(\\fR\\rbroadcastAddr\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\a \\x01(\\rR\\x03mtu\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"queue_disc\\x18\\b \\x01(\\tR\\tqueueDisc\\x12!\\n\" +\n\t\"\\fmaster_index\\x18\\t \\x01(\\rR\\vmasterIndex\\x12i\\n\" +\n\t\"\\x11operational_state\\x18\\n\" +\n\t\" \\x01(\\x0e2<.talos.resource.definitions.enums.NethelpersOperationalStateR\\x10operationalState\\x12\\x12\\n\" +\n\t\"\\x04kind\\x18\\v \\x01(\\tR\\x04kind\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"slave_kind\\x18\\f \\x01(\\tR\\tslaveKind\\x12\\x19\\n\" +\n\t\"\\bbus_path\\x18\\r \\x01(\\tR\\abusPath\\x12\\x14\\n\" +\n\t\"\\x05pciid\\x18\\x0e \\x01(\\tR\\x05pciid\\x12\\x16\\n\" +\n\t\"\\x06driver\\x18\\x0f \\x01(\\tR\\x06driver\\x12%\\n\" +\n\t\"\\x0edriver_version\\x18\\x10 \\x01(\\tR\\rdriverVersion\\x12)\\n\" +\n\t\"\\x10firmware_version\\x18\\x11 \\x01(\\tR\\x0ffirmwareVersion\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"product_id\\x18\\x12 \\x01(\\tR\\tproductId\\x12\\x1b\\n\" +\n\t\"\\tvendor_id\\x18\\x13 \\x01(\\tR\\bvendorId\\x12\\x18\\n\" +\n\t\"\\aproduct\\x18\\x14 \\x01(\\tR\\aproduct\\x12\\x16\\n\" +\n\t\"\\x06vendor\\x18\\x15 \\x01(\\tR\\x06vendor\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"link_state\\x18\\x16 \\x01(\\bR\\tlinkState\\x12%\\n\" +\n\t\"\\x0espeed_megabits\\x18\\x17 \\x01(\\x03R\\rspeedMegabits\\x12D\\n\" +\n\t\"\\x04port\\x18\\x18 \\x01(\\x0e20.talos.resource.definitions.enums.NethelpersPortR\\x04port\\x12J\\n\" +\n\t\"\\x06duplex\\x18\\x19 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersDuplexR\\x06duplex\\x12@\\n\" +\n\t\"\\x04vlan\\x18\\x1a \\x01(\\v2,.talos.resource.definitions.network.VLANSpecR\\x04vlan\\x12Y\\n\" +\n\t\"\\rbridge_master\\x18\\x1b \\x01(\\v24.talos.resource.definitions.network.BridgeMasterSpecR\\fbridgeMaster\\x12S\\n\" +\n\t\"\\vbond_master\\x18\\x1c \\x01(\\v22.talos.resource.definitions.network.BondMasterSpecR\\n\" +\n\t\"bondMaster\\x12O\\n\" +\n\t\"\\twireguard\\x18\\x1d \\x01(\\v21.talos.resource.definitions.network.WireguardSpecR\\twireguard\\x12%\\n\" +\n\t\"\\x0epermanent_addr\\x18\\x1e \\x01(\\fR\\rpermanentAddr\\x12\\x14\\n\" +\n\t\"\\x05alias\\x18\\x1f \\x01(\\tR\\x05alias\\x12\\x1b\\n\" +\n\t\"\\talt_names\\x18  \\x03(\\tR\\baltNames\\x12P\\n\" +\n\t\"\\n\" +\n\t\"vrf_master\\x18! \\x01(\\v21.talos.resource.definitions.network.VRFMasterSpecR\\tvrfMaster\\\"\\xaa\\x01\\n\" +\n\t\"\\x14NfTablesAddressMatch\\x12<\\n\" +\n\t\"\\x0finclude_subnets\\x18\\x01 \\x03(\\v2\\x13.common.NetIPPrefixR\\x0eincludeSubnets\\x12<\\n\" +\n\t\"\\x0fexclude_subnets\\x18\\x02 \\x03(\\v2\\x13.common.NetIPPrefixR\\x0eexcludeSubnets\\x12\\x16\\n\" +\n\t\"\\x06invert\\x18\\x03 \\x01(\\bR\\x06invert\\\"\\xf6\\x02\\n\" +\n\t\"\\x11NfTablesChainSpec\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\tR\\x04type\\x12Q\\n\" +\n\t\"\\x04hook\\x18\\x02 \\x01(\\x0e2=.talos.resource.definitions.enums.NethelpersNfTablesChainHookR\\x04hook\\x12]\\n\" +\n\t\"\\bpriority\\x18\\x03 \\x01(\\x0e2A.talos.resource.definitions.enums.NethelpersNfTablesChainPriorityR\\bpriority\\x12F\\n\" +\n\t\"\\x05rules\\x18\\x04 \\x03(\\v20.talos.resource.definitions.network.NfTablesRuleR\\x05rules\\x12S\\n\" +\n\t\"\\x06policy\\x18\\x05 \\x01(\\x0e2;.talos.resource.definitions.enums.NethelpersNfTablesVerdictR\\x06policy\\\"$\\n\" +\n\t\"\\x10NfTablesClampMSS\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\x01 \\x01(\\rR\\x03mtu\\\"q\\n\" +\n\t\"\\x1bNfTablesConntrackStateMatch\\x12R\\n\" +\n\t\"\\x06states\\x18\\x01 \\x03(\\x0e2:.talos.resource.definitions.enums.NethelpersConntrackStateR\\x06states\\\"c\\n\" +\n\t\"\\x15NfTablesICMPTypeMatch\\x12J\\n\" +\n\t\"\\x05types\\x18\\x01 \\x03(\\x0e24.talos.resource.definitions.enums.NethelpersICMPTypeR\\x05types\\\"\\x95\\x01\\n\" +\n\t\"\\x13NfTablesIfNameMatch\\x12U\\n\" +\n\t\"\\boperator\\x18\\x02 \\x01(\\x0e29.talos.resource.definitions.enums.NethelpersMatchOperatorR\\boperator\\x12'\\n\" +\n\t\"\\x0finterface_names\\x18\\x03 \\x03(\\tR\\x0einterfaceNames\\\"\\x9a\\x03\\n\" +\n\t\"\\x13NfTablesLayer4Match\\x12P\\n\" +\n\t\"\\bprotocol\\x18\\x01 \\x01(\\x0e24.talos.resource.definitions.enums.NethelpersProtocolR\\bprotocol\\x12a\\n\" +\n\t\"\\x11match_source_port\\x18\\x02 \\x01(\\v25.talos.resource.definitions.network.NfTablesPortMatchR\\x0fmatchSourcePort\\x12k\\n\" +\n\t\"\\x16match_destination_port\\x18\\x03 \\x01(\\v25.talos.resource.definitions.network.NfTablesPortMatchR\\x14matchDestinationPort\\x12a\\n\" +\n\t\"\\x0fmatch_icmp_type\\x18\\x04 \\x01(\\v29.talos.resource.definitions.network.NfTablesICMPTypeMatchR\\rmatchIcmpType\\\"I\\n\" +\n\t\"\\x12NfTablesLimitMatch\\x123\\n\" +\n\t\"\\x16packet_rate_per_second\\x18\\x01 \\x01(\\x04R\\x13packetRatePerSecond\\\"J\\n\" +\n\t\"\\fNfTablesMark\\x12\\x12\\n\" +\n\t\"\\x04mask\\x18\\x01 \\x01(\\rR\\x04mask\\x12\\x10\\n\" +\n\t\"\\x03xor\\x18\\x02 \\x01(\\rR\\x03xor\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x03 \\x01(\\rR\\x05value\\\"Z\\n\" +\n\t\"\\x11NfTablesPortMatch\\x12E\\n\" +\n\t\"\\x06ranges\\x18\\x01 \\x03(\\v2-.talos.resource.definitions.network.PortRangeR\\x06ranges\\\"\\xc5\\b\\n\" +\n\t\"\\fNfTablesRule\\x12^\\n\" +\n\t\"\\x0fmatch_o_if_name\\x18\\x01 \\x01(\\v27.talos.resource.definitions.network.NfTablesIfNameMatchR\\fmatchOIfName\\x12U\\n\" +\n\t\"\\averdict\\x18\\x02 \\x01(\\x0e2;.talos.resource.definitions.enums.NethelpersNfTablesVerdictR\\averdict\\x12O\\n\" +\n\t\"\\n\" +\n\t\"match_mark\\x18\\x03 \\x01(\\v20.talos.resource.definitions.network.NfTablesMarkR\\tmatchMark\\x12K\\n\" +\n\t\"\\bset_mark\\x18\\x04 \\x01(\\v20.talos.resource.definitions.network.NfTablesMarkR\\asetMark\\x12j\\n\" +\n\t\"\\x14match_source_address\\x18\\x05 \\x01(\\v28.talos.resource.definitions.network.NfTablesAddressMatchR\\x12matchSourceAddress\\x12t\\n\" +\n\t\"\\x19match_destination_address\\x18\\x06 \\x01(\\v28.talos.resource.definitions.network.NfTablesAddressMatchR\\x17matchDestinationAddress\\x12Z\\n\" +\n\t\"\\fmatch_layer4\\x18\\a \\x01(\\v27.talos.resource.definitions.network.NfTablesLayer4MatchR\\vmatchLayer4\\x12^\\n\" +\n\t\"\\x0fmatch_i_if_name\\x18\\b \\x01(\\v27.talos.resource.definitions.network.NfTablesIfNameMatchR\\fmatchIIfName\\x12Q\\n\" +\n\t\"\\tclamp_mss\\x18\\t \\x01(\\v24.talos.resource.definitions.network.NfTablesClampMSSR\\bclampMss\\x12W\\n\" +\n\t\"\\vmatch_limit\\x18\\n\" +\n\t\" \\x01(\\v26.talos.resource.definitions.network.NfTablesLimitMatchR\\n\" +\n\t\"matchLimit\\x12s\\n\" +\n\t\"\\x15match_conntrack_state\\x18\\v \\x01(\\v2?.talos.resource.definitions.network.NfTablesConntrackStateMatchR\\x13matchConntrackState\\x12!\\n\" +\n\t\"\\fanon_counter\\x18\\f \\x01(\\bR\\vanonCounter\\\"\\x93\\x01\\n\" +\n\t\"\\x15NodeAddressFilterSpec\\x12<\\n\" +\n\t\"\\x0finclude_subnets\\x18\\x01 \\x03(\\v2\\x13.common.NetIPPrefixR\\x0eincludeSubnets\\x12<\\n\" +\n\t\"\\x0fexclude_subnets\\x18\\x02 \\x03(\\v2\\x13.common.NetIPPrefixR\\x0eexcludeSubnets\\\"~\\n\" +\n\t\"\\x1cNodeAddressSortAlgorithmSpec\\x12^\\n\" +\n\t\"\\talgorithm\\x18\\x01 \\x01(\\x0e2@.talos.resource.definitions.enums.NethelpersAddressSortAlgorithmR\\talgorithm\\\"\\xad\\x01\\n\" +\n\t\"\\x0fNodeAddressSpec\\x121\\n\" +\n\t\"\\taddresses\\x18\\x01 \\x03(\\v2\\x13.common.NetIPPrefixR\\taddresses\\x12g\\n\" +\n\t\"\\x0esort_algorithm\\x18\\x02 \\x01(\\x0e2@.talos.resource.definitions.enums.NethelpersAddressSortAlgorithmR\\rsortAlgorithm\\\"\\xd7\\x03\\n\" +\n\t\"\\x10OperatorSpecSpec\\x12M\\n\" +\n\t\"\\boperator\\x18\\x01 \\x01(\\x0e21.talos.resource.definitions.enums.NetworkOperatorR\\boperator\\x12\\x1b\\n\" +\n\t\"\\tlink_name\\x18\\x02 \\x01(\\tR\\blinkName\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"require_up\\x18\\x03 \\x01(\\bR\\trequireUp\\x12K\\n\" +\n\t\"\\x05dhcp4\\x18\\x04 \\x01(\\v25.talos.resource.definitions.network.DHCP4OperatorSpecR\\x05dhcp4\\x12K\\n\" +\n\t\"\\x05dhcp6\\x18\\x05 \\x01(\\v25.talos.resource.definitions.network.DHCP6OperatorSpecR\\x05dhcp6\\x12E\\n\" +\n\t\"\\x03vip\\x18\\x06 \\x01(\\v23.talos.resource.definitions.network.VIPOperatorSpecR\\x03vip\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\a \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\\"\\xa4\\x06\\n\" +\n\t\"\\x12PlatformConfigSpec\\x12Q\\n\" +\n\t\"\\taddresses\\x18\\x01 \\x03(\\v23.talos.resource.definitions.network.AddressSpecSpecR\\taddresses\\x12F\\n\" +\n\t\"\\x05links\\x18\\x02 \\x03(\\v20.talos.resource.definitions.network.LinkSpecSpecR\\x05links\\x12I\\n\" +\n\t\"\\x06routes\\x18\\x03 \\x03(\\v21.talos.resource.definitions.network.RouteSpecSpecR\\x06routes\\x12R\\n\" +\n\t\"\\thostnames\\x18\\x04 \\x03(\\v24.talos.resource.definitions.network.HostnameSpecSpecR\\thostnames\\x12R\\n\" +\n\t\"\\tresolvers\\x18\\x05 \\x03(\\v24.talos.resource.definitions.network.ResolverSpecSpecR\\tresolvers\\x12Y\\n\" +\n\t\"\\ftime_servers\\x18\\x06 \\x03(\\v26.talos.resource.definitions.network.TimeServerSpecSpecR\\vtimeServers\\x12R\\n\" +\n\t\"\\toperators\\x18\\a \\x03(\\v24.talos.resource.definitions.network.OperatorSpecSpecR\\toperators\\x120\\n\" +\n\t\"\\fexternal_ips\\x18\\b \\x03(\\v2\\r.common.NetIPR\\vexternalIps\\x12I\\n\" +\n\t\"\\x06probes\\x18\\t \\x03(\\v21.talos.resource.definitions.network.ProbeSpecSpecR\\x06probes\\x12T\\n\" +\n\t\"\\bmetadata\\x18\\n\" +\n\t\" \\x01(\\v28.talos.resource.definitions.runtime.PlatformMetadataSpecR\\bmetadata\\\"+\\n\" +\n\t\"\\tPortRange\\x12\\x0e\\n\" +\n\t\"\\x02lo\\x18\\x01 \\x01(\\rR\\x02lo\\x12\\x0e\\n\" +\n\t\"\\x02hi\\x18\\x02 \\x01(\\rR\\x02hi\\\"\\x90\\x02\\n\" +\n\t\"\\rProbeSpecSpec\\x125\\n\" +\n\t\"\\binterval\\x18\\x01 \\x01(\\v2\\x19.google.protobuf.DurationR\\binterval\\x12+\\n\" +\n\t\"\\x11failure_threshold\\x18\\x02 \\x01(\\x03R\\x10failureThreshold\\x12B\\n\" +\n\t\"\\x03tcp\\x18\\x03 \\x01(\\v20.talos.resource.definitions.network.TCPProbeSpecR\\x03tcp\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\x04 \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\\"J\\n\" +\n\t\"\\x0fProbeStatusSpec\\x12\\x18\\n\" +\n\t\"\\asuccess\\x18\\x01 \\x01(\\bR\\asuccess\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"last_error\\x18\\x02 \\x01(\\tR\\tlastError\\\"\\xc2\\x01\\n\" +\n\t\"\\x10ResolverSpecSpec\\x12.\\n\" +\n\t\"\\vdns_servers\\x18\\x01 \\x03(\\v2\\r.common.NetIPR\\n\" +\n\t\"dnsServers\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\x02 \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\x12%\\n\" +\n\t\"\\x0esearch_domains\\x18\\x03 \\x03(\\tR\\rsearchDomains\\\"k\\n\" +\n\t\"\\x12ResolverStatusSpec\\x12.\\n\" +\n\t\"\\vdns_servers\\x18\\x01 \\x03(\\v2\\r.common.NetIPR\\n\" +\n\t\"dnsServers\\x12%\\n\" +\n\t\"\\x0esearch_domains\\x18\\x02 \\x03(\\tR\\rsearchDomains\\\"\\xde\\x05\\n\" +\n\t\"\\rRouteSpecSpec\\x12J\\n\" +\n\t\"\\x06family\\x18\\x01 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x125\\n\" +\n\t\"\\vdestination\\x18\\x02 \\x01(\\v2\\x13.common.NetIPPrefixR\\vdestination\\x12%\\n\" +\n\t\"\\x06source\\x18\\x03 \\x01(\\v2\\r.common.NetIPR\\x06source\\x12'\\n\" +\n\t\"\\agateway\\x18\\x04 \\x01(\\v2\\r.common.NetIPR\\agateway\\x12\\\"\\n\" +\n\t\"\\rout_link_name\\x18\\x05 \\x01(\\tR\\voutLinkName\\x12N\\n\" +\n\t\"\\x05table\\x18\\x06 \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersRoutingTableR\\x05table\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\a \\x01(\\rR\\bpriority\\x12G\\n\" +\n\t\"\\x05scope\\x18\\b \\x01(\\x0e21.talos.resource.definitions.enums.NethelpersScopeR\\x05scope\\x12I\\n\" +\n\t\"\\x04type\\x18\\t \\x01(\\x0e25.talos.resource.definitions.enums.NethelpersRouteTypeR\\x04type\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\n\" +\n\t\" \\x01(\\rR\\x05flags\\x12U\\n\" +\n\t\"\\bprotocol\\x18\\v \\x01(\\x0e29.talos.resource.definitions.enums.NethelpersRouteProtocolR\\bprotocol\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\f \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\r \\x01(\\rR\\x03mtu\\\"\\xad\\x05\\n\" +\n\t\"\\x0fRouteStatusSpec\\x12J\\n\" +\n\t\"\\x06family\\x18\\x01 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x125\\n\" +\n\t\"\\vdestination\\x18\\x02 \\x01(\\v2\\x13.common.NetIPPrefixR\\vdestination\\x12%\\n\" +\n\t\"\\x06source\\x18\\x03 \\x01(\\v2\\r.common.NetIPR\\x06source\\x12'\\n\" +\n\t\"\\agateway\\x18\\x04 \\x01(\\v2\\r.common.NetIPR\\agateway\\x12$\\n\" +\n\t\"\\x0eout_link_index\\x18\\x05 \\x01(\\rR\\foutLinkIndex\\x12\\\"\\n\" +\n\t\"\\rout_link_name\\x18\\x06 \\x01(\\tR\\voutLinkName\\x12N\\n\" +\n\t\"\\x05table\\x18\\a \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersRoutingTableR\\x05table\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\b \\x01(\\rR\\bpriority\\x12G\\n\" +\n\t\"\\x05scope\\x18\\t \\x01(\\x0e21.talos.resource.definitions.enums.NethelpersScopeR\\x05scope\\x12I\\n\" +\n\t\"\\x04type\\x18\\n\" +\n\t\" \\x01(\\x0e25.talos.resource.definitions.enums.NethelpersRouteTypeR\\x04type\\x12\\x14\\n\" +\n\t\"\\x05flags\\x18\\v \\x01(\\rR\\x05flags\\x12U\\n\" +\n\t\"\\bprotocol\\x18\\f \\x01(\\x0e29.talos.resource.definitions.enums.NethelpersRouteProtocolR\\bprotocol\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\r \\x01(\\rR\\x03mtu\\\"\\xb3\\x04\\n\" +\n\t\"\\x13RoutingRuleSpecSpec\\x12J\\n\" +\n\t\"\\x06family\\x18\\x01 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x12%\\n\" +\n\t\"\\x03src\\x18\\x02 \\x01(\\v2\\x13.common.NetIPPrefixR\\x03src\\x12%\\n\" +\n\t\"\\x03dst\\x18\\x03 \\x01(\\v2\\x13.common.NetIPPrefixR\\x03dst\\x12N\\n\" +\n\t\"\\x05table\\x18\\x04 \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersRoutingTableR\\x05table\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\x05 \\x01(\\rR\\bpriority\\x12U\\n\" +\n\t\"\\x06action\\x18\\x06 \\x01(\\x0e2=.talos.resource.definitions.enums.NethelpersRoutingRuleActionR\\x06action\\x12\\x19\\n\" +\n\t\"\\biif_name\\x18\\a \\x01(\\tR\\aiifName\\x12\\x19\\n\" +\n\t\"\\boif_name\\x18\\b \\x01(\\tR\\aoifName\\x12\\x17\\n\" +\n\t\"\\afw_mark\\x18\\t \\x01(\\rR\\x06fwMark\\x12\\x17\\n\" +\n\t\"\\afw_mask\\x18\\n\" +\n\t\" \\x01(\\rR\\x06fwMask\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\v \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\\"\\xdc\\x03\\n\" +\n\t\"\\x15RoutingRuleStatusSpec\\x12J\\n\" +\n\t\"\\x06family\\x18\\x01 \\x01(\\x0e22.talos.resource.definitions.enums.NethelpersFamilyR\\x06family\\x12%\\n\" +\n\t\"\\x03src\\x18\\x02 \\x01(\\v2\\x13.common.NetIPPrefixR\\x03src\\x12%\\n\" +\n\t\"\\x03dst\\x18\\x03 \\x01(\\v2\\x13.common.NetIPPrefixR\\x03dst\\x12N\\n\" +\n\t\"\\x05table\\x18\\x04 \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersRoutingTableR\\x05table\\x12\\x1a\\n\" +\n\t\"\\bpriority\\x18\\x05 \\x01(\\rR\\bpriority\\x12U\\n\" +\n\t\"\\x06action\\x18\\x06 \\x01(\\x0e2=.talos.resource.definitions.enums.NethelpersRoutingRuleActionR\\x06action\\x12\\x19\\n\" +\n\t\"\\biif_name\\x18\\a \\x01(\\tR\\aiifName\\x12\\x19\\n\" +\n\t\"\\boif_name\\x18\\b \\x01(\\tR\\aoifName\\x12\\x17\\n\" +\n\t\"\\afw_mark\\x18\\t \\x01(\\rR\\x06fwMark\\x12\\x17\\n\" +\n\t\"\\afw_mask\\x18\\n\" +\n\t\" \\x01(\\rR\\x06fwMask\\\"#\\n\" +\n\t\"\\aSTPSpec\\x12\\x18\\n\" +\n\t\"\\aenabled\\x18\\x01 \\x01(\\bR\\aenabled\\\"\\xaf\\x01\\n\" +\n\t\"\\n\" +\n\t\"StatusSpec\\x12#\\n\" +\n\t\"\\raddress_ready\\x18\\x01 \\x01(\\bR\\faddressReady\\x12-\\n\" +\n\t\"\\x12connectivity_ready\\x18\\x02 \\x01(\\bR\\x11connectivityReady\\x12%\\n\" +\n\t\"\\x0ehostname_ready\\x18\\x03 \\x01(\\bR\\rhostnameReady\\x12&\\n\" +\n\t\"\\x0fetc_files_ready\\x18\\x04 \\x01(\\bR\\retcFilesReady\\\"_\\n\" +\n\t\"\\fTCPProbeSpec\\x12\\x1a\\n\" +\n\t\"\\bendpoint\\x18\\x01 \\x01(\\tR\\bendpoint\\x123\\n\" +\n\t\"\\atimeout\\x18\\x02 \\x01(\\v2\\x19.google.protobuf.DurationR\\atimeout\\\"\\x8e\\x01\\n\" +\n\t\"\\x12TimeServerSpecSpec\\x12\\x1f\\n\" +\n\t\"\\vntp_servers\\x18\\x01 \\x03(\\tR\\n\" +\n\t\"ntpServers\\x12W\\n\" +\n\t\"\\fconfig_layer\\x18\\x02 \\x01(\\x0e24.talos.resource.definitions.enums.NetworkConfigLayerR\\vconfigLayer\\\"7\\n\" +\n\t\"\\x14TimeServerStatusSpec\\x12\\x1f\\n\" +\n\t\"\\vntp_servers\\x18\\x01 \\x03(\\tR\\n\" +\n\t\"ntpServers\\\"n\\n\" +\n\t\"\\x13VIPEquinixMetalSpec\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"project_id\\x18\\x01 \\x01(\\tR\\tprojectId\\x12\\x1b\\n\" +\n\t\"\\tdevice_id\\x18\\x02 \\x01(\\tR\\bdeviceId\\x12\\x1b\\n\" +\n\t\"\\tapi_token\\x18\\x03 \\x01(\\tR\\bapiToken\\\"h\\n\" +\n\t\"\\rVIPHCloudSpec\\x12\\x1b\\n\" +\n\t\"\\tdevice_id\\x18\\x01 \\x01(\\x03R\\bdeviceId\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"network_id\\x18\\x02 \\x01(\\x03R\\tnetworkId\\x12\\x1b\\n\" +\n\t\"\\tapi_token\\x18\\x03 \\x01(\\tR\\bapiToken\\\"\\x81\\x02\\n\" +\n\t\"\\x0fVIPOperatorSpec\\x12\\x1d\\n\" +\n\t\"\\x02ip\\x18\\x01 \\x01(\\v2\\r.common.NetIPR\\x02ip\\x12%\\n\" +\n\t\"\\x0egratuitous_arp\\x18\\x02 \\x01(\\bR\\rgratuitousArp\\x12\\\\\\n\" +\n\t\"\\requinix_metal\\x18\\x03 \\x01(\\v27.talos.resource.definitions.network.VIPEquinixMetalSpecR\\fequinixMetal\\x12J\\n\" +\n\t\"\\ah_cloud\\x18\\x04 \\x01(\\v21.talos.resource.definitions.network.VIPHCloudSpecR\\x06hCloud\\\"r\\n\" +\n\t\"\\bVLANSpec\\x12\\x10\\n\" +\n\t\"\\x03vid\\x18\\x01 \\x01(\\rR\\x03vid\\x12T\\n\" +\n\t\"\\bprotocol\\x18\\x02 \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersVLANProtocolR\\bprotocol\\\"_\\n\" +\n\t\"\\rVRFMasterSpec\\x12N\\n\" +\n\t\"\\x05table\\x18\\x01 \\x01(\\x0e28.talos.resource.definitions.enums.NethelpersRoutingTableR\\x05table\\\"+\\n\" +\n\t\"\\bVRFSlave\\x12\\x1f\\n\" +\n\t\"\\vmaster_name\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"masterName\\\"\\x84\\x02\\n\" +\n\t\"\\rWireguardPeer\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"public_key\\x18\\x01 \\x01(\\tR\\tpublicKey\\x12#\\n\" +\n\t\"\\rpreshared_key\\x18\\x02 \\x01(\\tR\\fpresharedKey\\x12\\x1a\\n\" +\n\t\"\\bendpoint\\x18\\x03 \\x01(\\tR\\bendpoint\\x12]\\n\" +\n\t\"\\x1dpersistent_keepalive_interval\\x18\\x04 \\x01(\\v2\\x19.google.protobuf.DurationR\\x1bpersistentKeepaliveInterval\\x124\\n\" +\n\t\"\\vallowed_ips\\x18\\x05 \\x03(\\v2\\x13.common.NetIPPrefixR\\n\" +\n\t\"allowedIps\\\"\\xde\\x01\\n\" +\n\t\"\\rWireguardSpec\\x12\\x1f\\n\" +\n\t\"\\vprivate_key\\x18\\x01 \\x01(\\tR\\n\" +\n\t\"privateKey\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"public_key\\x18\\x02 \\x01(\\tR\\tpublicKey\\x12\\x1f\\n\" +\n\t\"\\vlisten_port\\x18\\x03 \\x01(\\x03R\\n\" +\n\t\"listenPort\\x12#\\n\" +\n\t\"\\rfirewall_mark\\x18\\x04 \\x01(\\x03R\\ffirewallMark\\x12G\\n\" +\n\t\"\\x05peers\\x18\\x05 \\x03(\\v21.talos.resource.definitions.network.WireguardPeerR\\x05peersBx\\n\" +\n\t\"*dev.talos.api.resource.definitions.networkZJgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/networkb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_network_network_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_network_network_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_network_network_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_network_network_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_network_network_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_network_network_proto_rawDesc), len(file_resource_definitions_network_network_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_network_network_proto_rawDescData\n}\n\nvar file_resource_definitions_network_network_proto_msgTypes = make([]protoimpl.MessageInfo, 65)\nvar file_resource_definitions_network_network_proto_goTypes = []any{\n\t(*AddressSpecSpec)(nil),                    // 0: talos.resource.definitions.network.AddressSpecSpec\n\t(*AddressStatusSpec)(nil),                  // 1: talos.resource.definitions.network.AddressStatusSpec\n\t(*BondMasterSpec)(nil),                     // 2: talos.resource.definitions.network.BondMasterSpec\n\t(*BondSlave)(nil),                          // 3: talos.resource.definitions.network.BondSlave\n\t(*BridgeMasterSpec)(nil),                   // 4: talos.resource.definitions.network.BridgeMasterSpec\n\t(*BridgeSlave)(nil),                        // 5: talos.resource.definitions.network.BridgeSlave\n\t(*BridgeVLANSpec)(nil),                     // 6: talos.resource.definitions.network.BridgeVLANSpec\n\t(*ClientIdentifierSpec)(nil),               // 7: talos.resource.definitions.network.ClientIdentifierSpec\n\t(*DHCP4OperatorSpec)(nil),                  // 8: talos.resource.definitions.network.DHCP4OperatorSpec\n\t(*DHCP6OperatorSpec)(nil),                  // 9: talos.resource.definitions.network.DHCP6OperatorSpec\n\t(*DNSResolveCacheSpec)(nil),                // 10: talos.resource.definitions.network.DNSResolveCacheSpec\n\t(*EthernetChannelsSpec)(nil),               // 11: talos.resource.definitions.network.EthernetChannelsSpec\n\t(*EthernetChannelsStatus)(nil),             // 12: talos.resource.definitions.network.EthernetChannelsStatus\n\t(*EthernetFeatureStatus)(nil),              // 13: talos.resource.definitions.network.EthernetFeatureStatus\n\t(*EthernetRingsSpec)(nil),                  // 14: talos.resource.definitions.network.EthernetRingsSpec\n\t(*EthernetRingsStatus)(nil),                // 15: talos.resource.definitions.network.EthernetRingsStatus\n\t(*EthernetSpecSpec)(nil),                   // 16: talos.resource.definitions.network.EthernetSpecSpec\n\t(*EthernetStatusSpec)(nil),                 // 17: talos.resource.definitions.network.EthernetStatusSpec\n\t(*HardwareAddrSpec)(nil),                   // 18: talos.resource.definitions.network.HardwareAddrSpec\n\t(*HostDNSConfigSpec)(nil),                  // 19: talos.resource.definitions.network.HostDNSConfigSpec\n\t(*HostnameSpecSpec)(nil),                   // 20: talos.resource.definitions.network.HostnameSpecSpec\n\t(*HostnameStatusSpec)(nil),                 // 21: talos.resource.definitions.network.HostnameStatusSpec\n\t(*LinkAliasSpecSpec)(nil),                  // 22: talos.resource.definitions.network.LinkAliasSpecSpec\n\t(*LinkRefreshSpec)(nil),                    // 23: talos.resource.definitions.network.LinkRefreshSpec\n\t(*LinkSpecSpec)(nil),                       // 24: talos.resource.definitions.network.LinkSpecSpec\n\t(*LinkStatusSpec)(nil),                     // 25: talos.resource.definitions.network.LinkStatusSpec\n\t(*NfTablesAddressMatch)(nil),               // 26: talos.resource.definitions.network.NfTablesAddressMatch\n\t(*NfTablesChainSpec)(nil),                  // 27: talos.resource.definitions.network.NfTablesChainSpec\n\t(*NfTablesClampMSS)(nil),                   // 28: talos.resource.definitions.network.NfTablesClampMSS\n\t(*NfTablesConntrackStateMatch)(nil),        // 29: talos.resource.definitions.network.NfTablesConntrackStateMatch\n\t(*NfTablesICMPTypeMatch)(nil),              // 30: talos.resource.definitions.network.NfTablesICMPTypeMatch\n\t(*NfTablesIfNameMatch)(nil),                // 31: talos.resource.definitions.network.NfTablesIfNameMatch\n\t(*NfTablesLayer4Match)(nil),                // 32: talos.resource.definitions.network.NfTablesLayer4Match\n\t(*NfTablesLimitMatch)(nil),                 // 33: talos.resource.definitions.network.NfTablesLimitMatch\n\t(*NfTablesMark)(nil),                       // 34: talos.resource.definitions.network.NfTablesMark\n\t(*NfTablesPortMatch)(nil),                  // 35: talos.resource.definitions.network.NfTablesPortMatch\n\t(*NfTablesRule)(nil),                       // 36: talos.resource.definitions.network.NfTablesRule\n\t(*NodeAddressFilterSpec)(nil),              // 37: talos.resource.definitions.network.NodeAddressFilterSpec\n\t(*NodeAddressSortAlgorithmSpec)(nil),       // 38: talos.resource.definitions.network.NodeAddressSortAlgorithmSpec\n\t(*NodeAddressSpec)(nil),                    // 39: talos.resource.definitions.network.NodeAddressSpec\n\t(*OperatorSpecSpec)(nil),                   // 40: talos.resource.definitions.network.OperatorSpecSpec\n\t(*PlatformConfigSpec)(nil),                 // 41: talos.resource.definitions.network.PlatformConfigSpec\n\t(*PortRange)(nil),                          // 42: talos.resource.definitions.network.PortRange\n\t(*ProbeSpecSpec)(nil),                      // 43: talos.resource.definitions.network.ProbeSpecSpec\n\t(*ProbeStatusSpec)(nil),                    // 44: talos.resource.definitions.network.ProbeStatusSpec\n\t(*ResolverSpecSpec)(nil),                   // 45: talos.resource.definitions.network.ResolverSpecSpec\n\t(*ResolverStatusSpec)(nil),                 // 46: talos.resource.definitions.network.ResolverStatusSpec\n\t(*RouteSpecSpec)(nil),                      // 47: talos.resource.definitions.network.RouteSpecSpec\n\t(*RouteStatusSpec)(nil),                    // 48: talos.resource.definitions.network.RouteStatusSpec\n\t(*RoutingRuleSpecSpec)(nil),                // 49: talos.resource.definitions.network.RoutingRuleSpecSpec\n\t(*RoutingRuleStatusSpec)(nil),              // 50: talos.resource.definitions.network.RoutingRuleStatusSpec\n\t(*STPSpec)(nil),                            // 51: talos.resource.definitions.network.STPSpec\n\t(*StatusSpec)(nil),                         // 52: talos.resource.definitions.network.StatusSpec\n\t(*TCPProbeSpec)(nil),                       // 53: talos.resource.definitions.network.TCPProbeSpec\n\t(*TimeServerSpecSpec)(nil),                 // 54: talos.resource.definitions.network.TimeServerSpecSpec\n\t(*TimeServerStatusSpec)(nil),               // 55: talos.resource.definitions.network.TimeServerStatusSpec\n\t(*VIPEquinixMetalSpec)(nil),                // 56: talos.resource.definitions.network.VIPEquinixMetalSpec\n\t(*VIPHCloudSpec)(nil),                      // 57: talos.resource.definitions.network.VIPHCloudSpec\n\t(*VIPOperatorSpec)(nil),                    // 58: talos.resource.definitions.network.VIPOperatorSpec\n\t(*VLANSpec)(nil),                           // 59: talos.resource.definitions.network.VLANSpec\n\t(*VRFMasterSpec)(nil),                      // 60: talos.resource.definitions.network.VRFMasterSpec\n\t(*VRFSlave)(nil),                           // 61: talos.resource.definitions.network.VRFSlave\n\t(*WireguardPeer)(nil),                      // 62: talos.resource.definitions.network.WireguardPeer\n\t(*WireguardSpec)(nil),                      // 63: talos.resource.definitions.network.WireguardSpec\n\tnil,                                        // 64: talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntry\n\t(*common.NetIPPrefix)(nil),                 // 65: common.NetIPPrefix\n\t(enums.NethelpersFamily)(0),                // 66: talos.resource.definitions.enums.NethelpersFamily\n\t(enums.NethelpersScope)(0),                 // 67: talos.resource.definitions.enums.NethelpersScope\n\t(enums.NetworkConfigLayer)(0),              // 68: talos.resource.definitions.enums.NetworkConfigLayer\n\t(*common.NetIP)(nil),                       // 69: common.NetIP\n\t(enums.NethelpersBondMode)(0),              // 70: talos.resource.definitions.enums.NethelpersBondMode\n\t(enums.NethelpersBondXmitHashPolicy)(0),    // 71: talos.resource.definitions.enums.NethelpersBondXmitHashPolicy\n\t(enums.NethelpersLACPRate)(0),              // 72: talos.resource.definitions.enums.NethelpersLACPRate\n\t(enums.NethelpersARPValidate)(0),           // 73: talos.resource.definitions.enums.NethelpersARPValidate\n\t(enums.NethelpersARPAllTargets)(0),         // 74: talos.resource.definitions.enums.NethelpersARPAllTargets\n\t(enums.NethelpersPrimaryReselect)(0),       // 75: talos.resource.definitions.enums.NethelpersPrimaryReselect\n\t(enums.NethelpersFailOverMAC)(0),           // 76: talos.resource.definitions.enums.NethelpersFailOverMAC\n\t(enums.NethelpersADSelect)(0),              // 77: talos.resource.definitions.enums.NethelpersADSelect\n\t(enums.NethelpersADLACPActive)(0),          // 78: talos.resource.definitions.enums.NethelpersADLACPActive\n\t(enums.NethelpersClientIdentifier)(0),      // 79: talos.resource.definitions.enums.NethelpersClientIdentifier\n\t(enums.NethelpersWOLMode)(0),               // 80: talos.resource.definitions.enums.NethelpersWOLMode\n\t(enums.NethelpersPort)(0),                  // 81: talos.resource.definitions.enums.NethelpersPort\n\t(enums.NethelpersDuplex)(0),                // 82: talos.resource.definitions.enums.NethelpersDuplex\n\t(*common.NetIPPort)(nil),                   // 83: common.NetIPPort\n\t(enums.NethelpersLinkType)(0),              // 84: talos.resource.definitions.enums.NethelpersLinkType\n\t(enums.NethelpersOperationalState)(0),      // 85: talos.resource.definitions.enums.NethelpersOperationalState\n\t(enums.NethelpersNfTablesChainHook)(0),     // 86: talos.resource.definitions.enums.NethelpersNfTablesChainHook\n\t(enums.NethelpersNfTablesChainPriority)(0), // 87: talos.resource.definitions.enums.NethelpersNfTablesChainPriority\n\t(enums.NethelpersNfTablesVerdict)(0),       // 88: talos.resource.definitions.enums.NethelpersNfTablesVerdict\n\t(enums.NethelpersConntrackState)(0),        // 89: talos.resource.definitions.enums.NethelpersConntrackState\n\t(enums.NethelpersICMPType)(0),              // 90: talos.resource.definitions.enums.NethelpersICMPType\n\t(enums.NethelpersMatchOperator)(0),         // 91: talos.resource.definitions.enums.NethelpersMatchOperator\n\t(enums.NethelpersProtocol)(0),              // 92: talos.resource.definitions.enums.NethelpersProtocol\n\t(enums.NethelpersAddressSortAlgorithm)(0),  // 93: talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\n\t(enums.NetworkOperator)(0),                 // 94: talos.resource.definitions.enums.NetworkOperator\n\t(*runtime.PlatformMetadataSpec)(nil),       // 95: talos.resource.definitions.runtime.PlatformMetadataSpec\n\t(*durationpb.Duration)(nil),                // 96: google.protobuf.Duration\n\t(enums.NethelpersRoutingTable)(0),          // 97: talos.resource.definitions.enums.NethelpersRoutingTable\n\t(enums.NethelpersRouteType)(0),             // 98: talos.resource.definitions.enums.NethelpersRouteType\n\t(enums.NethelpersRouteProtocol)(0),         // 99: talos.resource.definitions.enums.NethelpersRouteProtocol\n\t(enums.NethelpersRoutingRuleAction)(0),     // 100: talos.resource.definitions.enums.NethelpersRoutingRuleAction\n\t(enums.NethelpersVLANProtocol)(0),          // 101: talos.resource.definitions.enums.NethelpersVLANProtocol\n}\nvar file_resource_definitions_network_network_proto_depIdxs = []int32{\n\t65,  // 0: talos.resource.definitions.network.AddressSpecSpec.address:type_name -> common.NetIPPrefix\n\t66,  // 1: talos.resource.definitions.network.AddressSpecSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t67,  // 2: talos.resource.definitions.network.AddressSpecSpec.scope:type_name -> talos.resource.definitions.enums.NethelpersScope\n\t68,  // 3: talos.resource.definitions.network.AddressSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t65,  // 4: talos.resource.definitions.network.AddressStatusSpec.address:type_name -> common.NetIPPrefix\n\t69,  // 5: talos.resource.definitions.network.AddressStatusSpec.local:type_name -> common.NetIP\n\t69,  // 6: talos.resource.definitions.network.AddressStatusSpec.broadcast:type_name -> common.NetIP\n\t69,  // 7: talos.resource.definitions.network.AddressStatusSpec.anycast:type_name -> common.NetIP\n\t69,  // 8: talos.resource.definitions.network.AddressStatusSpec.multicast:type_name -> common.NetIP\n\t66,  // 9: talos.resource.definitions.network.AddressStatusSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t67,  // 10: talos.resource.definitions.network.AddressStatusSpec.scope:type_name -> talos.resource.definitions.enums.NethelpersScope\n\t70,  // 11: talos.resource.definitions.network.BondMasterSpec.mode:type_name -> talos.resource.definitions.enums.NethelpersBondMode\n\t71,  // 12: talos.resource.definitions.network.BondMasterSpec.hash_policy:type_name -> talos.resource.definitions.enums.NethelpersBondXmitHashPolicy\n\t72,  // 13: talos.resource.definitions.network.BondMasterSpec.lacp_rate:type_name -> talos.resource.definitions.enums.NethelpersLACPRate\n\t73,  // 14: talos.resource.definitions.network.BondMasterSpec.arp_validate:type_name -> talos.resource.definitions.enums.NethelpersARPValidate\n\t74,  // 15: talos.resource.definitions.network.BondMasterSpec.arp_all_targets:type_name -> talos.resource.definitions.enums.NethelpersARPAllTargets\n\t75,  // 16: talos.resource.definitions.network.BondMasterSpec.primary_reselect:type_name -> talos.resource.definitions.enums.NethelpersPrimaryReselect\n\t76,  // 17: talos.resource.definitions.network.BondMasterSpec.fail_over_mac:type_name -> talos.resource.definitions.enums.NethelpersFailOverMAC\n\t77,  // 18: talos.resource.definitions.network.BondMasterSpec.ad_select:type_name -> talos.resource.definitions.enums.NethelpersADSelect\n\t69,  // 19: talos.resource.definitions.network.BondMasterSpec.arpip_targets:type_name -> common.NetIP\n\t69,  // 20: talos.resource.definitions.network.BondMasterSpec.nsip6_targets:type_name -> common.NetIP\n\t78,  // 21: talos.resource.definitions.network.BondMasterSpec.adlacp_active:type_name -> talos.resource.definitions.enums.NethelpersADLACPActive\n\t51,  // 22: talos.resource.definitions.network.BridgeMasterSpec.stp:type_name -> talos.resource.definitions.network.STPSpec\n\t6,   // 23: talos.resource.definitions.network.BridgeMasterSpec.vlan:type_name -> talos.resource.definitions.network.BridgeVLANSpec\n\t79,  // 24: talos.resource.definitions.network.ClientIdentifierSpec.client_identifier:type_name -> talos.resource.definitions.enums.NethelpersClientIdentifier\n\t7,   // 25: talos.resource.definitions.network.DHCP4OperatorSpec.client_identifier:type_name -> talos.resource.definitions.network.ClientIdentifierSpec\n\t7,   // 26: talos.resource.definitions.network.DHCP6OperatorSpec.client_identifier:type_name -> talos.resource.definitions.network.ClientIdentifierSpec\n\t14,  // 27: talos.resource.definitions.network.EthernetSpecSpec.rings:type_name -> talos.resource.definitions.network.EthernetRingsSpec\n\t64,  // 28: talos.resource.definitions.network.EthernetSpecSpec.features:type_name -> talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntry\n\t11,  // 29: talos.resource.definitions.network.EthernetSpecSpec.channels:type_name -> talos.resource.definitions.network.EthernetChannelsSpec\n\t80,  // 30: talos.resource.definitions.network.EthernetSpecSpec.wake_on_lan:type_name -> talos.resource.definitions.enums.NethelpersWOLMode\n\t81,  // 31: talos.resource.definitions.network.EthernetStatusSpec.port:type_name -> talos.resource.definitions.enums.NethelpersPort\n\t82,  // 32: talos.resource.definitions.network.EthernetStatusSpec.duplex:type_name -> talos.resource.definitions.enums.NethelpersDuplex\n\t15,  // 33: talos.resource.definitions.network.EthernetStatusSpec.rings:type_name -> talos.resource.definitions.network.EthernetRingsStatus\n\t13,  // 34: talos.resource.definitions.network.EthernetStatusSpec.features:type_name -> talos.resource.definitions.network.EthernetFeatureStatus\n\t12,  // 35: talos.resource.definitions.network.EthernetStatusSpec.channels:type_name -> talos.resource.definitions.network.EthernetChannelsStatus\n\t80,  // 36: talos.resource.definitions.network.EthernetStatusSpec.wake_on_lan:type_name -> talos.resource.definitions.enums.NethelpersWOLMode\n\t83,  // 37: talos.resource.definitions.network.HostDNSConfigSpec.listen_addresses:type_name -> common.NetIPPort\n\t69,  // 38: talos.resource.definitions.network.HostDNSConfigSpec.service_host_dns_address:type_name -> common.NetIP\n\t68,  // 39: talos.resource.definitions.network.HostnameSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t84,  // 40: talos.resource.definitions.network.LinkSpecSpec.type:type_name -> talos.resource.definitions.enums.NethelpersLinkType\n\t3,   // 41: talos.resource.definitions.network.LinkSpecSpec.bond_slave:type_name -> talos.resource.definitions.network.BondSlave\n\t5,   // 42: talos.resource.definitions.network.LinkSpecSpec.bridge_slave:type_name -> talos.resource.definitions.network.BridgeSlave\n\t59,  // 43: talos.resource.definitions.network.LinkSpecSpec.vlan:type_name -> talos.resource.definitions.network.VLANSpec\n\t2,   // 44: talos.resource.definitions.network.LinkSpecSpec.bond_master:type_name -> talos.resource.definitions.network.BondMasterSpec\n\t4,   // 45: talos.resource.definitions.network.LinkSpecSpec.bridge_master:type_name -> talos.resource.definitions.network.BridgeMasterSpec\n\t63,  // 46: talos.resource.definitions.network.LinkSpecSpec.wireguard:type_name -> talos.resource.definitions.network.WireguardSpec\n\t68,  // 47: talos.resource.definitions.network.LinkSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t60,  // 48: talos.resource.definitions.network.LinkSpecSpec.vrf_master:type_name -> talos.resource.definitions.network.VRFMasterSpec\n\t61,  // 49: talos.resource.definitions.network.LinkSpecSpec.vrf_slave:type_name -> talos.resource.definitions.network.VRFSlave\n\t84,  // 50: talos.resource.definitions.network.LinkStatusSpec.type:type_name -> talos.resource.definitions.enums.NethelpersLinkType\n\t85,  // 51: talos.resource.definitions.network.LinkStatusSpec.operational_state:type_name -> talos.resource.definitions.enums.NethelpersOperationalState\n\t81,  // 52: talos.resource.definitions.network.LinkStatusSpec.port:type_name -> talos.resource.definitions.enums.NethelpersPort\n\t82,  // 53: talos.resource.definitions.network.LinkStatusSpec.duplex:type_name -> talos.resource.definitions.enums.NethelpersDuplex\n\t59,  // 54: talos.resource.definitions.network.LinkStatusSpec.vlan:type_name -> talos.resource.definitions.network.VLANSpec\n\t4,   // 55: talos.resource.definitions.network.LinkStatusSpec.bridge_master:type_name -> talos.resource.definitions.network.BridgeMasterSpec\n\t2,   // 56: talos.resource.definitions.network.LinkStatusSpec.bond_master:type_name -> talos.resource.definitions.network.BondMasterSpec\n\t63,  // 57: talos.resource.definitions.network.LinkStatusSpec.wireguard:type_name -> talos.resource.definitions.network.WireguardSpec\n\t60,  // 58: talos.resource.definitions.network.LinkStatusSpec.vrf_master:type_name -> talos.resource.definitions.network.VRFMasterSpec\n\t65,  // 59: talos.resource.definitions.network.NfTablesAddressMatch.include_subnets:type_name -> common.NetIPPrefix\n\t65,  // 60: talos.resource.definitions.network.NfTablesAddressMatch.exclude_subnets:type_name -> common.NetIPPrefix\n\t86,  // 61: talos.resource.definitions.network.NfTablesChainSpec.hook:type_name -> talos.resource.definitions.enums.NethelpersNfTablesChainHook\n\t87,  // 62: talos.resource.definitions.network.NfTablesChainSpec.priority:type_name -> talos.resource.definitions.enums.NethelpersNfTablesChainPriority\n\t36,  // 63: talos.resource.definitions.network.NfTablesChainSpec.rules:type_name -> talos.resource.definitions.network.NfTablesRule\n\t88,  // 64: talos.resource.definitions.network.NfTablesChainSpec.policy:type_name -> talos.resource.definitions.enums.NethelpersNfTablesVerdict\n\t89,  // 65: talos.resource.definitions.network.NfTablesConntrackStateMatch.states:type_name -> talos.resource.definitions.enums.NethelpersConntrackState\n\t90,  // 66: talos.resource.definitions.network.NfTablesICMPTypeMatch.types:type_name -> talos.resource.definitions.enums.NethelpersICMPType\n\t91,  // 67: talos.resource.definitions.network.NfTablesIfNameMatch.operator:type_name -> talos.resource.definitions.enums.NethelpersMatchOperator\n\t92,  // 68: talos.resource.definitions.network.NfTablesLayer4Match.protocol:type_name -> talos.resource.definitions.enums.NethelpersProtocol\n\t35,  // 69: talos.resource.definitions.network.NfTablesLayer4Match.match_source_port:type_name -> talos.resource.definitions.network.NfTablesPortMatch\n\t35,  // 70: talos.resource.definitions.network.NfTablesLayer4Match.match_destination_port:type_name -> talos.resource.definitions.network.NfTablesPortMatch\n\t30,  // 71: talos.resource.definitions.network.NfTablesLayer4Match.match_icmp_type:type_name -> talos.resource.definitions.network.NfTablesICMPTypeMatch\n\t42,  // 72: talos.resource.definitions.network.NfTablesPortMatch.ranges:type_name -> talos.resource.definitions.network.PortRange\n\t31,  // 73: talos.resource.definitions.network.NfTablesRule.match_o_if_name:type_name -> talos.resource.definitions.network.NfTablesIfNameMatch\n\t88,  // 74: talos.resource.definitions.network.NfTablesRule.verdict:type_name -> talos.resource.definitions.enums.NethelpersNfTablesVerdict\n\t34,  // 75: talos.resource.definitions.network.NfTablesRule.match_mark:type_name -> talos.resource.definitions.network.NfTablesMark\n\t34,  // 76: talos.resource.definitions.network.NfTablesRule.set_mark:type_name -> talos.resource.definitions.network.NfTablesMark\n\t26,  // 77: talos.resource.definitions.network.NfTablesRule.match_source_address:type_name -> talos.resource.definitions.network.NfTablesAddressMatch\n\t26,  // 78: talos.resource.definitions.network.NfTablesRule.match_destination_address:type_name -> talos.resource.definitions.network.NfTablesAddressMatch\n\t32,  // 79: talos.resource.definitions.network.NfTablesRule.match_layer4:type_name -> talos.resource.definitions.network.NfTablesLayer4Match\n\t31,  // 80: talos.resource.definitions.network.NfTablesRule.match_i_if_name:type_name -> talos.resource.definitions.network.NfTablesIfNameMatch\n\t28,  // 81: talos.resource.definitions.network.NfTablesRule.clamp_mss:type_name -> talos.resource.definitions.network.NfTablesClampMSS\n\t33,  // 82: talos.resource.definitions.network.NfTablesRule.match_limit:type_name -> talos.resource.definitions.network.NfTablesLimitMatch\n\t29,  // 83: talos.resource.definitions.network.NfTablesRule.match_conntrack_state:type_name -> talos.resource.definitions.network.NfTablesConntrackStateMatch\n\t65,  // 84: talos.resource.definitions.network.NodeAddressFilterSpec.include_subnets:type_name -> common.NetIPPrefix\n\t65,  // 85: talos.resource.definitions.network.NodeAddressFilterSpec.exclude_subnets:type_name -> common.NetIPPrefix\n\t93,  // 86: talos.resource.definitions.network.NodeAddressSortAlgorithmSpec.algorithm:type_name -> talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\n\t65,  // 87: talos.resource.definitions.network.NodeAddressSpec.addresses:type_name -> common.NetIPPrefix\n\t93,  // 88: talos.resource.definitions.network.NodeAddressSpec.sort_algorithm:type_name -> talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\n\t94,  // 89: talos.resource.definitions.network.OperatorSpecSpec.operator:type_name -> talos.resource.definitions.enums.NetworkOperator\n\t8,   // 90: talos.resource.definitions.network.OperatorSpecSpec.dhcp4:type_name -> talos.resource.definitions.network.DHCP4OperatorSpec\n\t9,   // 91: talos.resource.definitions.network.OperatorSpecSpec.dhcp6:type_name -> talos.resource.definitions.network.DHCP6OperatorSpec\n\t58,  // 92: talos.resource.definitions.network.OperatorSpecSpec.vip:type_name -> talos.resource.definitions.network.VIPOperatorSpec\n\t68,  // 93: talos.resource.definitions.network.OperatorSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t0,   // 94: talos.resource.definitions.network.PlatformConfigSpec.addresses:type_name -> talos.resource.definitions.network.AddressSpecSpec\n\t24,  // 95: talos.resource.definitions.network.PlatformConfigSpec.links:type_name -> talos.resource.definitions.network.LinkSpecSpec\n\t47,  // 96: talos.resource.definitions.network.PlatformConfigSpec.routes:type_name -> talos.resource.definitions.network.RouteSpecSpec\n\t20,  // 97: talos.resource.definitions.network.PlatformConfigSpec.hostnames:type_name -> talos.resource.definitions.network.HostnameSpecSpec\n\t45,  // 98: talos.resource.definitions.network.PlatformConfigSpec.resolvers:type_name -> talos.resource.definitions.network.ResolverSpecSpec\n\t54,  // 99: talos.resource.definitions.network.PlatformConfigSpec.time_servers:type_name -> talos.resource.definitions.network.TimeServerSpecSpec\n\t40,  // 100: talos.resource.definitions.network.PlatformConfigSpec.operators:type_name -> talos.resource.definitions.network.OperatorSpecSpec\n\t69,  // 101: talos.resource.definitions.network.PlatformConfigSpec.external_ips:type_name -> common.NetIP\n\t43,  // 102: talos.resource.definitions.network.PlatformConfigSpec.probes:type_name -> talos.resource.definitions.network.ProbeSpecSpec\n\t95,  // 103: talos.resource.definitions.network.PlatformConfigSpec.metadata:type_name -> talos.resource.definitions.runtime.PlatformMetadataSpec\n\t96,  // 104: talos.resource.definitions.network.ProbeSpecSpec.interval:type_name -> google.protobuf.Duration\n\t53,  // 105: talos.resource.definitions.network.ProbeSpecSpec.tcp:type_name -> talos.resource.definitions.network.TCPProbeSpec\n\t68,  // 106: talos.resource.definitions.network.ProbeSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t69,  // 107: talos.resource.definitions.network.ResolverSpecSpec.dns_servers:type_name -> common.NetIP\n\t68,  // 108: talos.resource.definitions.network.ResolverSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t69,  // 109: talos.resource.definitions.network.ResolverStatusSpec.dns_servers:type_name -> common.NetIP\n\t66,  // 110: talos.resource.definitions.network.RouteSpecSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t65,  // 111: talos.resource.definitions.network.RouteSpecSpec.destination:type_name -> common.NetIPPrefix\n\t69,  // 112: talos.resource.definitions.network.RouteSpecSpec.source:type_name -> common.NetIP\n\t69,  // 113: talos.resource.definitions.network.RouteSpecSpec.gateway:type_name -> common.NetIP\n\t97,  // 114: talos.resource.definitions.network.RouteSpecSpec.table:type_name -> talos.resource.definitions.enums.NethelpersRoutingTable\n\t67,  // 115: talos.resource.definitions.network.RouteSpecSpec.scope:type_name -> talos.resource.definitions.enums.NethelpersScope\n\t98,  // 116: talos.resource.definitions.network.RouteSpecSpec.type:type_name -> talos.resource.definitions.enums.NethelpersRouteType\n\t99,  // 117: talos.resource.definitions.network.RouteSpecSpec.protocol:type_name -> talos.resource.definitions.enums.NethelpersRouteProtocol\n\t68,  // 118: talos.resource.definitions.network.RouteSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t66,  // 119: talos.resource.definitions.network.RouteStatusSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t65,  // 120: talos.resource.definitions.network.RouteStatusSpec.destination:type_name -> common.NetIPPrefix\n\t69,  // 121: talos.resource.definitions.network.RouteStatusSpec.source:type_name -> common.NetIP\n\t69,  // 122: talos.resource.definitions.network.RouteStatusSpec.gateway:type_name -> common.NetIP\n\t97,  // 123: talos.resource.definitions.network.RouteStatusSpec.table:type_name -> talos.resource.definitions.enums.NethelpersRoutingTable\n\t67,  // 124: talos.resource.definitions.network.RouteStatusSpec.scope:type_name -> talos.resource.definitions.enums.NethelpersScope\n\t98,  // 125: talos.resource.definitions.network.RouteStatusSpec.type:type_name -> talos.resource.definitions.enums.NethelpersRouteType\n\t99,  // 126: talos.resource.definitions.network.RouteStatusSpec.protocol:type_name -> talos.resource.definitions.enums.NethelpersRouteProtocol\n\t66,  // 127: talos.resource.definitions.network.RoutingRuleSpecSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t65,  // 128: talos.resource.definitions.network.RoutingRuleSpecSpec.src:type_name -> common.NetIPPrefix\n\t65,  // 129: talos.resource.definitions.network.RoutingRuleSpecSpec.dst:type_name -> common.NetIPPrefix\n\t97,  // 130: talos.resource.definitions.network.RoutingRuleSpecSpec.table:type_name -> talos.resource.definitions.enums.NethelpersRoutingTable\n\t100, // 131: talos.resource.definitions.network.RoutingRuleSpecSpec.action:type_name -> talos.resource.definitions.enums.NethelpersRoutingRuleAction\n\t68,  // 132: talos.resource.definitions.network.RoutingRuleSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t66,  // 133: talos.resource.definitions.network.RoutingRuleStatusSpec.family:type_name -> talos.resource.definitions.enums.NethelpersFamily\n\t65,  // 134: talos.resource.definitions.network.RoutingRuleStatusSpec.src:type_name -> common.NetIPPrefix\n\t65,  // 135: talos.resource.definitions.network.RoutingRuleStatusSpec.dst:type_name -> common.NetIPPrefix\n\t97,  // 136: talos.resource.definitions.network.RoutingRuleStatusSpec.table:type_name -> talos.resource.definitions.enums.NethelpersRoutingTable\n\t100, // 137: talos.resource.definitions.network.RoutingRuleStatusSpec.action:type_name -> talos.resource.definitions.enums.NethelpersRoutingRuleAction\n\t96,  // 138: talos.resource.definitions.network.TCPProbeSpec.timeout:type_name -> google.protobuf.Duration\n\t68,  // 139: talos.resource.definitions.network.TimeServerSpecSpec.config_layer:type_name -> talos.resource.definitions.enums.NetworkConfigLayer\n\t69,  // 140: talos.resource.definitions.network.VIPOperatorSpec.ip:type_name -> common.NetIP\n\t56,  // 141: talos.resource.definitions.network.VIPOperatorSpec.equinix_metal:type_name -> talos.resource.definitions.network.VIPEquinixMetalSpec\n\t57,  // 142: talos.resource.definitions.network.VIPOperatorSpec.h_cloud:type_name -> talos.resource.definitions.network.VIPHCloudSpec\n\t101, // 143: talos.resource.definitions.network.VLANSpec.protocol:type_name -> talos.resource.definitions.enums.NethelpersVLANProtocol\n\t97,  // 144: talos.resource.definitions.network.VRFMasterSpec.table:type_name -> talos.resource.definitions.enums.NethelpersRoutingTable\n\t96,  // 145: talos.resource.definitions.network.WireguardPeer.persistent_keepalive_interval:type_name -> google.protobuf.Duration\n\t65,  // 146: talos.resource.definitions.network.WireguardPeer.allowed_ips:type_name -> common.NetIPPrefix\n\t62,  // 147: talos.resource.definitions.network.WireguardSpec.peers:type_name -> talos.resource.definitions.network.WireguardPeer\n\t148, // [148:148] is the sub-list for method output_type\n\t148, // [148:148] is the sub-list for method input_type\n\t148, // [148:148] is the sub-list for extension type_name\n\t148, // [148:148] is the sub-list for extension extendee\n\t0,   // [0:148] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_network_network_proto_init() }\nfunc file_resource_definitions_network_network_proto_init() {\n\tif File_resource_definitions_network_network_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_network_network_proto_rawDesc), len(file_resource_definitions_network_network_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   65,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_network_network_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_network_network_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_network_network_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_network_network_proto = out.File\n\tfile_resource_definitions_network_network_proto_goTypes = nil\n\tfile_resource_definitions_network_network_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/network/network_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/network/network.proto\n\npackage network\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n\truntime \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/runtime\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *AddressSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AddressSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AddressSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.AnnounceWithArp {\n\t\ti--\n\t\tif m.AnnounceWithArp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Flags != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Scope != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Scope))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.LinkName) > 0 {\n\t\ti -= len(m.LinkName)\n\t\tcopy(dAtA[i:], m.LinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Address != nil {\n\t\tif vtmsg, ok := interface{}(m.Address).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AddressStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AddressStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AddressStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Flags != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Scope != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Scope))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif len(m.LinkName) > 0 {\n\t\ti -= len(m.LinkName)\n\t\tcopy(dAtA[i:], m.LinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.LinkIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.LinkIndex))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Multicast != nil {\n\t\tif vtmsg, ok := interface{}(m.Multicast).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Multicast)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Anycast != nil {\n\t\tif vtmsg, ok := interface{}(m.Anycast).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Anycast)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Broadcast != nil {\n\t\tif vtmsg, ok := interface{}(m.Broadcast).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Broadcast)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Local != nil {\n\t\tif vtmsg, ok := interface{}(m.Local).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Local)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Address != nil {\n\t\tif vtmsg, ok := interface{}(m.Address).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BondMasterSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BondMasterSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BondMasterSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MissedMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MissedMax))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe0\n\t}\n\tif m.AdlacpActive != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AdlacpActive))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd8\n\t}\n\tif len(m.Nsip6Targets) > 0 {\n\t\tfor iNdEx := len(m.Nsip6Targets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Nsip6Targets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Nsip6Targets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0xd2\n\t\t}\n\t}\n\tif len(m.ArpipTargets) > 0 {\n\t\tfor iNdEx := len(m.ArpipTargets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ArpipTargets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ArpipTargets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1\n\t\t\ti--\n\t\t\tdAtA[i] = 0xca\n\t\t}\n\t}\n\tif m.PeerNotifyDelay != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PeerNotifyDelay))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.AdUserPortKey != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AdUserPortKey))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.AdActorSysPrio != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AdActorSysPrio))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif m.UseCarrier {\n\t\ti--\n\t\tif m.UseCarrier {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.AllSlavesActive != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AllSlavesActive))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif m.TlbDynamicLb != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TlbDynamicLb))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif m.NumPeerNotif != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.NumPeerNotif))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif m.PacketsPerSlave != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PacketsPerSlave))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.LpInterval != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.LpInterval))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.MinLinks != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinLinks))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.ResendIgmp != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ResendIgmp))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.ArpInterval != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ArpInterval))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.DownDelay != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DownDelay))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.UpDelay != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.UpDelay))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.MiiMon != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MiiMon))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.AdSelect != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AdSelect))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.FailOverMac != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FailOverMac))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.PrimaryReselect != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PrimaryReselect))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.PrimaryIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PrimaryIndex))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.ArpAllTargets != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ArpAllTargets))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ArpValidate != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ArpValidate))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.LacpRate != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.LacpRate))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.HashPolicy != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HashPolicy))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Mode != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mode))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BondSlave) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BondSlave) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BondSlave) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SlaveIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SlaveIndex))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.MasterName) > 0 {\n\t\ti -= len(m.MasterName)\n\t\tcopy(dAtA[i:], m.MasterName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MasterName)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BridgeMasterSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BridgeMasterSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BridgeMasterSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Vlan != nil {\n\t\tsize, err := m.Vlan.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Stp != nil {\n\t\tsize, err := m.Stp.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BridgeSlave) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BridgeSlave) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BridgeSlave) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MasterName) > 0 {\n\t\ti -= len(m.MasterName)\n\t\tcopy(dAtA[i:], m.MasterName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MasterName)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BridgeVLANSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BridgeVLANSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BridgeVLANSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.FilteringEnabled {\n\t\ti--\n\t\tif m.FilteringEnabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ClientIdentifierSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ClientIdentifierSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ClientIdentifierSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.DuidRawHex) > 0 {\n\t\ti -= len(m.DuidRawHex)\n\t\tcopy(dAtA[i:], m.DuidRawHex)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DuidRawHex)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.ClientIdentifier != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ClientIdentifier))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DHCP4OperatorSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DHCP4OperatorSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DHCP4OperatorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClientIdentifier != nil {\n\t\tsize, err := m.ClientIdentifier.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.SkipHostnameRequest {\n\t\ti--\n\t\tif m.SkipHostnameRequest {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.RouteMetric != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RouteMetric))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DHCP6OperatorSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DHCP6OperatorSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DHCP6OperatorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ClientIdentifier != nil {\n\t\tsize, err := m.ClientIdentifier.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.SkipHostnameRequest {\n\t\ti--\n\t\tif m.SkipHostnameRequest {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.RouteMetric != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RouteMetric))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DNSResolveCacheSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DNSResolveCacheSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DNSResolveCacheSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Status) > 0 {\n\t\ti -= len(m.Status)\n\t\tcopy(dAtA[i:], m.Status)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Status)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetChannelsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetChannelsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetChannelsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Combined != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Combined))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Other != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Other))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Tx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tx))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Rx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rx))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetChannelsStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetChannelsStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetChannelsStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Combined != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Combined))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Other != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Other))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Tx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tx))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Rx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rx))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.CombinedMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CombinedMax))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.OtherMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.OtherMax))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.TxMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxMax))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.RxMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMax))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetFeatureStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetFeatureStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetFeatureStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Status) > 0 {\n\t\ti -= len(m.Status)\n\t\tcopy(dAtA[i:], m.Status)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Status)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetRingsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetRingsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetRingsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TcpDataSplit {\n\t\ti--\n\t\tif m.TcpDataSplit {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.TxPushBufLen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxPushBufLen))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.RxPush {\n\t\ti--\n\t\tif m.RxPush {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.TxPush {\n\t\ti--\n\t\tif m.TxPush {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.CqeSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CqeSize))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.RxBufLen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxBufLen))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Tx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tx))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.RxJumbo != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxJumbo))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.RxMini != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMini))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Rx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rx))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetRingsStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetRingsStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetRingsStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.TcpDataSplit {\n\t\ti--\n\t\tif m.TcpDataSplit {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.TxPushBufLen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxPushBufLen))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.RxPush {\n\t\ti--\n\t\tif m.RxPush {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.TxPush {\n\t\ti--\n\t\tif m.TxPush {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.CqeSize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CqeSize))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.RxBufLen != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxBufLen))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Tx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Tx))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.RxJumbo != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxJumbo))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.RxMini != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMini))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Rx != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Rx))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.TxPushBufLenMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxPushBufLenMax))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.TxMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.TxMax))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.RxJumboMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxJumboMax))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.RxMiniMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMiniMax))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.RxMax != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.RxMax))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.WakeOnLan) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.WakeOnLan {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.WakeOnLan {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Channels != nil {\n\t\tsize, err := m.Channels.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Features) > 0 {\n\t\tfor k := range m.Features {\n\t\t\tv := m.Features[k]\n\t\t\tbaseI := i\n\t\t\ti--\n\t\t\tif v {\n\t\t\t\tdAtA[i] = 1\n\t\t\t} else {\n\t\t\t\tdAtA[i] = 0\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x10\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Rings != nil {\n\t\tsize, err := m.Rings.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EthernetStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EthernetStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EthernetStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.WakeOnLan) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.WakeOnLan {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.WakeOnLan {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.Channels != nil {\n\t\tsize, err := m.Channels.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif len(m.Features) > 0 {\n\t\tfor iNdEx := len(m.Features) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Features[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x42\n\t\t}\n\t}\n\tif m.Rings != nil {\n\t\tsize, err := m.Rings.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.PeerModes) > 0 {\n\t\tfor iNdEx := len(m.PeerModes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PeerModes[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PeerModes[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PeerModes[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.OurModes) > 0 {\n\t\tfor iNdEx := len(m.OurModes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.OurModes[iNdEx])\n\t\t\tcopy(dAtA[i:], m.OurModes[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OurModes[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif m.Duplex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Duplex))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Port != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Port))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.SpeedMegabits != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SpeedMegabits))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.LinkState {\n\t\ti--\n\t\tif m.LinkState {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HardwareAddrSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HardwareAddrSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HardwareAddrSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.HardwareAddr) > 0 {\n\t\ti -= len(m.HardwareAddr)\n\t\tcopy(dAtA[i:], m.HardwareAddr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.HardwareAddr)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HostDNSConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HostDNSConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HostDNSConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ResolveMemberNames {\n\t\ti--\n\t\tif m.ResolveMemberNames {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ServiceHostDnsAddress != nil {\n\t\tif vtmsg, ok := interface{}(m.ServiceHostDnsAddress).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.ServiceHostDnsAddress)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.ListenAddresses) > 0 {\n\t\tfor iNdEx := len(m.ListenAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ListenAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ListenAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HostnameSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HostnameSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HostnameSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Domainname) > 0 {\n\t\ti -= len(m.Domainname)\n\t\tcopy(dAtA[i:], m.Domainname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Domainname)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *HostnameStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *HostnameStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *HostnameStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Domainname) > 0 {\n\t\ti -= len(m.Domainname)\n\t\tcopy(dAtA[i:], m.Domainname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Domainname)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LinkAliasSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LinkAliasSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LinkAliasSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Alias) > 0 {\n\t\ti -= len(m.Alias)\n\t\tcopy(dAtA[i:], m.Alias)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Alias)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LinkRefreshSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LinkRefreshSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LinkRefreshSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Generation != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Generation))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LinkSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LinkSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LinkSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.VrfSlave != nil {\n\t\tsize, err := m.VrfSlave.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif m.VrfMaster != nil {\n\t\tsize, err := m.VrfMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif m.Multicast {\n\t\ti--\n\t\tif m.Multicast {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif len(m.HardwareAddress) > 0 {\n\t\ti -= len(m.HardwareAddress)\n\t\tcopy(dAtA[i:], m.HardwareAddress)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.HardwareAddress)))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.Wireguard != nil {\n\t\tsize, err := m.Wireguard.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x6a\n\t}\n\tif m.BridgeMaster != nil {\n\t\tsize, err := m.BridgeMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif m.BondMaster != nil {\n\t\tsize, err := m.BondMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.Vlan != nil {\n\t\tsize, err := m.Vlan.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.BridgeSlave != nil {\n\t\tsize, err := m.BridgeSlave.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.BondSlave != nil {\n\t\tsize, err := m.BondSlave.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.ParentName) > 0 {\n\t\ti -= len(m.ParentName)\n\t\tcopy(dAtA[i:], m.ParentName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentName)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.Kind) > 0 {\n\t\ti -= len(m.Kind)\n\t\tcopy(dAtA[i:], m.Kind)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Kind)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Up {\n\t\ti--\n\t\tif m.Up {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Logical {\n\t\ti--\n\t\tif m.Logical {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LinkStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LinkStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LinkStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.VrfMaster != nil {\n\t\tsize, err := m.VrfMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.AltNames) > 0 {\n\t\tfor iNdEx := len(m.AltNames) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.AltNames[iNdEx])\n\t\t\tcopy(dAtA[i:], m.AltNames[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AltNames[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2\n\t\t\ti--\n\t\t\tdAtA[i] = 0x82\n\t\t}\n\t}\n\tif len(m.Alias) > 0 {\n\t\ti -= len(m.Alias)\n\t\tcopy(dAtA[i:], m.Alias)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Alias)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xfa\n\t}\n\tif len(m.PermanentAddr) > 0 {\n\t\ti -= len(m.PermanentAddr)\n\t\tcopy(dAtA[i:], m.PermanentAddr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PermanentAddr)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xf2\n\t}\n\tif m.Wireguard != nil {\n\t\tsize, err := m.Wireguard.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xea\n\t}\n\tif m.BondMaster != nil {\n\t\tsize, err := m.BondMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe2\n\t}\n\tif m.BridgeMaster != nil {\n\t\tsize, err := m.BridgeMaster.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xda\n\t}\n\tif m.Vlan != nil {\n\t\tsize, err := m.Vlan.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd2\n\t}\n\tif m.Duplex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Duplex))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc8\n\t}\n\tif m.Port != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Port))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.SpeedMegabits != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SpeedMegabits))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.LinkState {\n\t\ti--\n\t\tif m.LinkState {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif len(m.Vendor) > 0 {\n\t\ti -= len(m.Vendor)\n\t\tcopy(dAtA[i:], m.Vendor)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Vendor)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xaa\n\t}\n\tif len(m.Product) > 0 {\n\t\ti -= len(m.Product)\n\t\tcopy(dAtA[i:], m.Product)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Product)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa2\n\t}\n\tif len(m.VendorId) > 0 {\n\t\ti -= len(m.VendorId)\n\t\tcopy(dAtA[i:], m.VendorId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.VendorId)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x9a\n\t}\n\tif len(m.ProductId) > 0 {\n\t\ti -= len(m.ProductId)\n\t\tcopy(dAtA[i:], m.ProductId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProductId)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x92\n\t}\n\tif len(m.FirmwareVersion) > 0 {\n\t\ti -= len(m.FirmwareVersion)\n\t\tcopy(dAtA[i:], m.FirmwareVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FirmwareVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x8a\n\t}\n\tif len(m.DriverVersion) > 0 {\n\t\ti -= len(m.DriverVersion)\n\t\tcopy(dAtA[i:], m.DriverVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DriverVersion)))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x82\n\t}\n\tif len(m.Driver) > 0 {\n\t\ti -= len(m.Driver)\n\t\tcopy(dAtA[i:], m.Driver)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Driver)))\n\t\ti--\n\t\tdAtA[i] = 0x7a\n\t}\n\tif len(m.Pciid) > 0 {\n\t\ti -= len(m.Pciid)\n\t\tcopy(dAtA[i:], m.Pciid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Pciid)))\n\t\ti--\n\t\tdAtA[i] = 0x72\n\t}\n\tif len(m.BusPath) > 0 {\n\t\ti -= len(m.BusPath)\n\t\tcopy(dAtA[i:], m.BusPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BusPath)))\n\t\ti--\n\t\tdAtA[i] = 0x6a\n\t}\n\tif len(m.SlaveKind) > 0 {\n\t\ti -= len(m.SlaveKind)\n\t\tcopy(dAtA[i:], m.SlaveKind)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SlaveKind)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif len(m.Kind) > 0 {\n\t\ti -= len(m.Kind)\n\t\tcopy(dAtA[i:], m.Kind)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Kind)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.OperationalState != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.OperationalState))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.MasterIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MasterIndex))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.QueueDisc) > 0 {\n\t\ti -= len(m.QueueDisc)\n\t\tcopy(dAtA[i:], m.QueueDisc)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.QueueDisc)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif len(m.BroadcastAddr) > 0 {\n\t\ti -= len(m.BroadcastAddr)\n\t\tcopy(dAtA[i:], m.BroadcastAddr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BroadcastAddr)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.HardwareAddr) > 0 {\n\t\ti -= len(m.HardwareAddr)\n\t\tcopy(dAtA[i:], m.HardwareAddr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.HardwareAddr)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Flags != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.LinkIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.LinkIndex))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Index != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Index))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesAddressMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesAddressMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesAddressMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Invert {\n\t\ti--\n\t\tif m.Invert {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.ExcludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExcludeSubnets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExcludeSubnets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.IncludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.IncludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.IncludeSubnets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.IncludeSubnets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesChainSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesChainSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesChainSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Policy != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Policy))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Rules) > 0 {\n\t\tfor iNdEx := len(m.Rules) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Rules[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Hook != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hook))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesClampMSS) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesClampMSS) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesClampMSS) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesConntrackStateMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesConntrackStateMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesConntrackStateMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.States) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.States {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.States {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesICMPTypeMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesICMPTypeMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesICMPTypeMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Types) > 0 {\n\t\tvar pksize2 int\n\t\tfor _, num := range m.Types {\n\t\t\tpksize2 += protohelpers.SizeOfVarint(uint64(num))\n\t\t}\n\t\ti -= pksize2\n\t\tj1 := i\n\t\tfor _, num1 := range m.Types {\n\t\t\tnum := uint64(num1)\n\t\t\tfor num >= 1<<7 {\n\t\t\t\tdAtA[j1] = uint8(uint64(num)&0x7f | 0x80)\n\t\t\t\tnum >>= 7\n\t\t\t\tj1++\n\t\t\t}\n\t\t\tdAtA[j1] = uint8(num)\n\t\t\tj1++\n\t\t}\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(pksize2))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesIfNameMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesIfNameMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesIfNameMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.InterfaceNames) > 0 {\n\t\tfor iNdEx := len(m.InterfaceNames) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.InterfaceNames[iNdEx])\n\t\t\tcopy(dAtA[i:], m.InterfaceNames[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InterfaceNames[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Operator != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Operator))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesLayer4Match) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesLayer4Match) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesLayer4Match) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.MatchIcmpType != nil {\n\t\tsize, err := m.MatchIcmpType.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.MatchDestinationPort != nil {\n\t\tsize, err := m.MatchDestinationPort.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.MatchSourcePort != nil {\n\t\tsize, err := m.MatchSourcePort.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Protocol != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Protocol))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesLimitMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesLimitMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesLimitMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.PacketRatePerSecond != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PacketRatePerSecond))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesMark) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesMark) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesMark) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Value != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Value))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Xor != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Xor))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Mask != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mask))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesPortMatch) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesPortMatch) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesPortMatch) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Ranges) > 0 {\n\t\tfor iNdEx := len(m.Ranges) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Ranges[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NfTablesRule) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NfTablesRule) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NfTablesRule) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.AnonCounter {\n\t\ti--\n\t\tif m.AnonCounter {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.MatchConntrackState != nil {\n\t\tsize, err := m.MatchConntrackState.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif m.MatchLimit != nil {\n\t\tsize, err := m.MatchLimit.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.ClampMss != nil {\n\t\tsize, err := m.ClampMss.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.MatchIIfName != nil {\n\t\tsize, err := m.MatchIIfName.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.MatchLayer4 != nil {\n\t\tsize, err := m.MatchLayer4.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.MatchDestinationAddress != nil {\n\t\tsize, err := m.MatchDestinationAddress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.MatchSourceAddress != nil {\n\t\tsize, err := m.MatchSourceAddress.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.SetMark != nil {\n\t\tsize, err := m.SetMark.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.MatchMark != nil {\n\t\tsize, err := m.MatchMark.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Verdict != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Verdict))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.MatchOIfName != nil {\n\t\tsize, err := m.MatchOIfName.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeAddressFilterSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeAddressFilterSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeAddressFilterSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.ExcludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExcludeSubnets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExcludeSubnets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.IncludeSubnets) > 0 {\n\t\tfor iNdEx := len(m.IncludeSubnets) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.IncludeSubnets[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.IncludeSubnets[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeAddressSortAlgorithmSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeAddressSortAlgorithmSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeAddressSortAlgorithmSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Algorithm != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Algorithm))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *NodeAddressSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *NodeAddressSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *NodeAddressSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SortAlgorithm != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SortAlgorithm))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Addresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Addresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *OperatorSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *OperatorSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *OperatorSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Vip != nil {\n\t\tsize, err := m.Vip.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.Dhcp6 != nil {\n\t\tsize, err := m.Dhcp6.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Dhcp4 != nil {\n\t\tsize, err := m.Dhcp4.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.RequireUp {\n\t\ti--\n\t\tif m.RequireUp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.LinkName) > 0 {\n\t\ti -= len(m.LinkName)\n\t\tcopy(dAtA[i:], m.LinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Operator != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Operator))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PlatformConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PlatformConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PlatformConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.Probes) > 0 {\n\t\tfor iNdEx := len(m.Probes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Probes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x4a\n\t\t}\n\t}\n\tif len(m.ExternalIps) > 0 {\n\t\tfor iNdEx := len(m.ExternalIps) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ExternalIps[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ExternalIps[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x42\n\t\t}\n\t}\n\tif len(m.Operators) > 0 {\n\t\tfor iNdEx := len(m.Operators) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Operators[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x3a\n\t\t}\n\t}\n\tif len(m.TimeServers) > 0 {\n\t\tfor iNdEx := len(m.TimeServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.TimeServers[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.Resolvers) > 0 {\n\t\tfor iNdEx := len(m.Resolvers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Resolvers[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.Hostnames) > 0 {\n\t\tfor iNdEx := len(m.Hostnames) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Hostnames[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Routes) > 0 {\n\t\tfor iNdEx := len(m.Routes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Routes[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.Links) > 0 {\n\t\tfor iNdEx := len(m.Links) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Links[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Addresses) > 0 {\n\t\tfor iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Addresses[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PortRange) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PortRange) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PortRange) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Hi != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hi))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Lo != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Lo))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProbeSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProbeSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProbeSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Tcp != nil {\n\t\tsize, err := m.Tcp.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.FailureThreshold != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FailureThreshold))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Interval != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Interval).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ProbeStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ProbeStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ProbeStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.LastError) > 0 {\n\t\ti -= len(m.LastError)\n\t\tcopy(dAtA[i:], m.LastError)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LastError)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Success {\n\t\ti--\n\t\tif m.Success {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ResolverSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ResolverSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ResolverSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SearchDomains) > 0 {\n\t\tfor iNdEx := len(m.SearchDomains) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.SearchDomains[iNdEx])\n\t\t\tcopy(dAtA[i:], m.SearchDomains[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SearchDomains[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.DnsServers) > 0 {\n\t\tfor iNdEx := len(m.DnsServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.DnsServers[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.DnsServers[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ResolverStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ResolverStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ResolverStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SearchDomains) > 0 {\n\t\tfor iNdEx := len(m.SearchDomains) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.SearchDomains[iNdEx])\n\t\t\tcopy(dAtA[i:], m.SearchDomains[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SearchDomains[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.DnsServers) > 0 {\n\t\tfor iNdEx := len(m.DnsServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.DnsServers[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.DnsServers[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RouteSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RouteSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RouteSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.Protocol != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Protocol))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Flags != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Scope != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Scope))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Table != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Table))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.OutLinkName) > 0 {\n\t\ti -= len(m.OutLinkName)\n\t\tcopy(dAtA[i:], m.OutLinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OutLinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Gateway != nil {\n\t\tif vtmsg, ok := interface{}(m.Gateway).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Gateway)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Source != nil {\n\t\tif vtmsg, ok := interface{}(m.Source).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Source)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Destination != nil {\n\t\tif vtmsg, ok := interface{}(m.Destination).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Destination)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RouteStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RouteStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RouteStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.Protocol != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Protocol))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.Flags != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Flags))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.Scope != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Scope))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Table != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Table))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif len(m.OutLinkName) > 0 {\n\t\ti -= len(m.OutLinkName)\n\t\tcopy(dAtA[i:], m.OutLinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OutLinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.OutLinkIndex != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.OutLinkIndex))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Gateway != nil {\n\t\tif vtmsg, ok := interface{}(m.Gateway).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Gateway)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Source != nil {\n\t\tif vtmsg, ok := interface{}(m.Source).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Source)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Destination != nil {\n\t\tif vtmsg, ok := interface{}(m.Destination).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Destination)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RoutingRuleSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RoutingRuleSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RoutingRuleSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.FwMask != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FwMask))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.FwMark != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FwMark))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.OifName) > 0 {\n\t\ti -= len(m.OifName)\n\t\tcopy(dAtA[i:], m.OifName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OifName)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.IifName) > 0 {\n\t\ti -= len(m.IifName)\n\t\tcopy(dAtA[i:], m.IifName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.IifName)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Table != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Table))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Dst != nil {\n\t\tif vtmsg, ok := interface{}(m.Dst).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Dst)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Src != nil {\n\t\tif vtmsg, ok := interface{}(m.Src).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Src)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *RoutingRuleStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *RoutingRuleStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *RoutingRuleStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.FwMask != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FwMask))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.FwMark != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FwMark))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.OifName) > 0 {\n\t\ti -= len(m.OifName)\n\t\tcopy(dAtA[i:], m.OifName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.OifName)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.IifName) > 0 {\n\t\ti -= len(m.IifName)\n\t\tcopy(dAtA[i:], m.IifName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.IifName)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif m.Action != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Action))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Priority != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Priority))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Table != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Table))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Dst != nil {\n\t\tif vtmsg, ok := interface{}(m.Dst).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Dst)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Src != nil {\n\t\tif vtmsg, ok := interface{}(m.Src).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Src)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Family != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Family))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *STPSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *STPSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *STPSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Enabled {\n\t\ti--\n\t\tif m.Enabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.EtcFilesReady {\n\t\ti--\n\t\tif m.EtcFilesReady {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.HostnameReady {\n\t\ti--\n\t\tif m.HostnameReady {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.ConnectivityReady {\n\t\ti--\n\t\tif m.ConnectivityReady {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.AddressReady {\n\t\ti--\n\t\tif m.AddressReady {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TCPProbeSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TCPProbeSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TCPProbeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Timeout != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Timeout).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Endpoint) > 0 {\n\t\ti -= len(m.Endpoint)\n\t\tcopy(dAtA[i:], m.Endpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Endpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TimeServerSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TimeServerSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TimeServerSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ConfigLayer != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ConfigLayer))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.NtpServers) > 0 {\n\t\tfor iNdEx := len(m.NtpServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.NtpServers[iNdEx])\n\t\t\tcopy(dAtA[i:], m.NtpServers[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NtpServers[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TimeServerStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TimeServerStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TimeServerStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.NtpServers) > 0 {\n\t\tfor iNdEx := len(m.NtpServers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.NtpServers[iNdEx])\n\t\t\tcopy(dAtA[i:], m.NtpServers[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.NtpServers[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VIPEquinixMetalSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VIPEquinixMetalSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VIPEquinixMetalSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ApiToken) > 0 {\n\t\ti -= len(m.ApiToken)\n\t\tcopy(dAtA[i:], m.ApiToken)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApiToken)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.DeviceId) > 0 {\n\t\ti -= len(m.DeviceId)\n\t\tcopy(dAtA[i:], m.DeviceId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DeviceId)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.ProjectId) > 0 {\n\t\ti -= len(m.ProjectId)\n\t\tcopy(dAtA[i:], m.ProjectId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProjectId)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VIPHCloudSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VIPHCloudSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VIPHCloudSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ApiToken) > 0 {\n\t\ti -= len(m.ApiToken)\n\t\tcopy(dAtA[i:], m.ApiToken)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApiToken)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.NetworkId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.NetworkId))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.DeviceId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DeviceId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VIPOperatorSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VIPOperatorSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VIPOperatorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.HCloud != nil {\n\t\tsize, err := m.HCloud.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.EquinixMetal != nil {\n\t\tsize, err := m.EquinixMetal.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.GratuitousArp {\n\t\ti--\n\t\tif m.GratuitousArp {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Ip != nil {\n\t\tif vtmsg, ok := interface{}(m.Ip).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Ip)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VLANSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VLANSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VLANSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Protocol != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Protocol))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Vid != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Vid))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VRFMasterSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VRFMasterSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VRFMasterSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Table != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Table))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *VRFSlave) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *VRFSlave) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *VRFSlave) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MasterName) > 0 {\n\t\ti -= len(m.MasterName)\n\t\tcopy(dAtA[i:], m.MasterName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MasterName)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *WireguardPeer) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *WireguardPeer) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *WireguardPeer) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AllowedIps) > 0 {\n\t\tfor iNdEx := len(m.AllowedIps) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AllowedIps[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AllowedIps[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif m.PersistentKeepaliveInterval != nil {\n\t\tsize, err := (*durationpb.Duration)(m.PersistentKeepaliveInterval).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Endpoint) > 0 {\n\t\ti -= len(m.Endpoint)\n\t\tcopy(dAtA[i:], m.Endpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Endpoint)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.PresharedKey) > 0 {\n\t\ti -= len(m.PresharedKey)\n\t\tcopy(dAtA[i:], m.PresharedKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PresharedKey)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.PublicKey) > 0 {\n\t\ti -= len(m.PublicKey)\n\t\tcopy(dAtA[i:], m.PublicKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *WireguardSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *WireguardSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *WireguardSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Peers) > 0 {\n\t\tfor iNdEx := len(m.Peers) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Peers[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif m.FirewallMark != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FirewallMark))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ListenPort != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ListenPort))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.PublicKey) > 0 {\n\t\ti -= len(m.PublicKey)\n\t\tcopy(dAtA[i:], m.PublicKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PublicKey)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.PrivateKey) > 0 {\n\t\ti -= len(m.PrivateKey)\n\t\tcopy(dAtA[i:], m.PrivateKey)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PrivateKey)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AddressSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Address != nil {\n\t\tif size, ok := interface{}(m.Address).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Address)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.LinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Scope != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Scope))\n\t}\n\tif m.Flags != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Flags))\n\t}\n\tif m.AnnounceWithArp {\n\t\tn += 2\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AddressStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Address != nil {\n\t\tif size, ok := interface{}(m.Address).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Address)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Local != nil {\n\t\tif size, ok := interface{}(m.Local).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Local)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Broadcast != nil {\n\t\tif size, ok := interface{}(m.Broadcast).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Broadcast)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Anycast != nil {\n\t\tif size, ok := interface{}(m.Anycast).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Anycast)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Multicast != nil {\n\t\tif size, ok := interface{}(m.Multicast).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Multicast)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LinkIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.LinkIndex))\n\t}\n\tl = len(m.LinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Scope != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Scope))\n\t}\n\tif m.Flags != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Flags))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BondMasterSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Mode != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mode))\n\t}\n\tif m.HashPolicy != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.HashPolicy))\n\t}\n\tif m.LacpRate != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.LacpRate))\n\t}\n\tif m.ArpValidate != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ArpValidate))\n\t}\n\tif m.ArpAllTargets != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ArpAllTargets))\n\t}\n\tif m.PrimaryIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PrimaryIndex))\n\t}\n\tif m.PrimaryReselect != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PrimaryReselect))\n\t}\n\tif m.FailOverMac != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FailOverMac))\n\t}\n\tif m.AdSelect != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.AdSelect))\n\t}\n\tif m.MiiMon != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MiiMon))\n\t}\n\tif m.UpDelay != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.UpDelay))\n\t}\n\tif m.DownDelay != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DownDelay))\n\t}\n\tif m.ArpInterval != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ArpInterval))\n\t}\n\tif m.ResendIgmp != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ResendIgmp))\n\t}\n\tif m.MinLinks != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MinLinks))\n\t}\n\tif m.LpInterval != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.LpInterval))\n\t}\n\tif m.PacketsPerSlave != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.PacketsPerSlave))\n\t}\n\tif m.NumPeerNotif != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.NumPeerNotif))\n\t}\n\tif m.TlbDynamicLb != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.TlbDynamicLb))\n\t}\n\tif m.AllSlavesActive != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AllSlavesActive))\n\t}\n\tif m.UseCarrier {\n\t\tn += 3\n\t}\n\tif m.AdActorSysPrio != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AdActorSysPrio))\n\t}\n\tif m.AdUserPortKey != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AdUserPortKey))\n\t}\n\tif m.PeerNotifyDelay != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.PeerNotifyDelay))\n\t}\n\tif len(m.ArpipTargets) > 0 {\n\t\tfor _, e := range m.ArpipTargets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Nsip6Targets) > 0 {\n\t\tfor _, e := range m.Nsip6Targets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.AdlacpActive != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AdlacpActive))\n\t}\n\tif m.MissedMax != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.MissedMax))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BondSlave) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.MasterName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SlaveIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SlaveIndex))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BridgeMasterSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Stp != nil {\n\t\tl = m.Stp.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Vlan != nil {\n\t\tl = m.Vlan.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BridgeSlave) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.MasterName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BridgeVLANSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.FilteringEnabled {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ClientIdentifierSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.ClientIdentifier != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ClientIdentifier))\n\t}\n\tl = len(m.DuidRawHex)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DHCP4OperatorSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RouteMetric != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RouteMetric))\n\t}\n\tif m.SkipHostnameRequest {\n\t\tn += 2\n\t}\n\tif m.ClientIdentifier != nil {\n\t\tl = m.ClientIdentifier.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DHCP6OperatorSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RouteMetric != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RouteMetric))\n\t}\n\tif m.SkipHostnameRequest {\n\t\tn += 2\n\t}\n\tif m.ClientIdentifier != nil {\n\t\tl = m.ClientIdentifier.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DNSResolveCacheSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Status)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetChannelsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Rx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rx))\n\t}\n\tif m.Tx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tx))\n\t}\n\tif m.Other != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Other))\n\t}\n\tif m.Combined != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Combined))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetChannelsStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RxMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMax))\n\t}\n\tif m.TxMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxMax))\n\t}\n\tif m.OtherMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.OtherMax))\n\t}\n\tif m.CombinedMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CombinedMax))\n\t}\n\tif m.Rx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rx))\n\t}\n\tif m.Tx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tx))\n\t}\n\tif m.Other != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Other))\n\t}\n\tif m.Combined != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Combined))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetFeatureStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Status)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetRingsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Rx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rx))\n\t}\n\tif m.RxMini != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMini))\n\t}\n\tif m.RxJumbo != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxJumbo))\n\t}\n\tif m.Tx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tx))\n\t}\n\tif m.RxBufLen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxBufLen))\n\t}\n\tif m.CqeSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CqeSize))\n\t}\n\tif m.TxPush {\n\t\tn += 2\n\t}\n\tif m.RxPush {\n\t\tn += 2\n\t}\n\tif m.TxPushBufLen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxPushBufLen))\n\t}\n\tif m.TcpDataSplit {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetRingsStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.RxMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMax))\n\t}\n\tif m.RxMiniMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMiniMax))\n\t}\n\tif m.RxJumboMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxJumboMax))\n\t}\n\tif m.TxMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxMax))\n\t}\n\tif m.TxPushBufLenMax != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxPushBufLenMax))\n\t}\n\tif m.Rx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Rx))\n\t}\n\tif m.RxMini != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxMini))\n\t}\n\tif m.RxJumbo != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxJumbo))\n\t}\n\tif m.Tx != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Tx))\n\t}\n\tif m.RxBufLen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.RxBufLen))\n\t}\n\tif m.CqeSize != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.CqeSize))\n\t}\n\tif m.TxPush {\n\t\tn += 2\n\t}\n\tif m.RxPush {\n\t\tn += 2\n\t}\n\tif m.TxPushBufLen != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.TxPushBufLen))\n\t}\n\tif m.TcpDataSplit {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Rings != nil {\n\t\tl = m.Rings.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Features) > 0 {\n\t\tfor k, v := range m.Features {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + 1\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tif m.Channels != nil {\n\t\tl = m.Channels.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.WakeOnLan) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.WakeOnLan {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EthernetStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.LinkState {\n\t\tn += 2\n\t}\n\tif m.SpeedMegabits != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SpeedMegabits))\n\t}\n\tif m.Port != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Port))\n\t}\n\tif m.Duplex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Duplex))\n\t}\n\tif len(m.OurModes) > 0 {\n\t\tfor _, s := range m.OurModes {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.PeerModes) > 0 {\n\t\tfor _, s := range m.PeerModes {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Rings != nil {\n\t\tl = m.Rings.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Features) > 0 {\n\t\tfor _, e := range m.Features {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Channels != nil {\n\t\tl = m.Channels.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.WakeOnLan) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.WakeOnLan {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HardwareAddrSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.HardwareAddr)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HostDNSConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tif len(m.ListenAddresses) > 0 {\n\t\tfor _, e := range m.ListenAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ServiceHostDnsAddress != nil {\n\t\tif size, ok := interface{}(m.ServiceHostDnsAddress).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.ServiceHostDnsAddress)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ResolveMemberNames {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HostnameSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Domainname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *HostnameStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Domainname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LinkAliasSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Alias)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LinkRefreshSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Generation != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Generation))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LinkSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Logical {\n\t\tn += 2\n\t}\n\tif m.Up {\n\t\tn += 2\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tl = len(m.Kind)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tl = len(m.ParentName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BondSlave != nil {\n\t\tl = m.BondSlave.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BridgeSlave != nil {\n\t\tl = m.BridgeSlave.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Vlan != nil {\n\t\tl = m.Vlan.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BondMaster != nil {\n\t\tl = m.BondMaster.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BridgeMaster != nil {\n\t\tl = m.BridgeMaster.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Wireguard != nil {\n\t\tl = m.Wireguard.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tl = len(m.HardwareAddress)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Multicast {\n\t\tn += 3\n\t}\n\tif m.VrfMaster != nil {\n\t\tl = m.VrfMaster.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.VrfSlave != nil {\n\t\tl = m.VrfSlave.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LinkStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Index != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Index))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif m.LinkIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.LinkIndex))\n\t}\n\tif m.Flags != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Flags))\n\t}\n\tl = len(m.HardwareAddr)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BroadcastAddr)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tl = len(m.QueueDisc)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MasterIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MasterIndex))\n\t}\n\tif m.OperationalState != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.OperationalState))\n\t}\n\tl = len(m.Kind)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SlaveKind)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BusPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Pciid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Driver)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DriverVersion)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.FirmwareVersion)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProductId)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.VendorId)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Product)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Vendor)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LinkState {\n\t\tn += 3\n\t}\n\tif m.SpeedMegabits != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.SpeedMegabits))\n\t}\n\tif m.Port != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Port))\n\t}\n\tif m.Duplex != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Duplex))\n\t}\n\tif m.Vlan != nil {\n\t\tl = m.Vlan.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BridgeMaster != nil {\n\t\tl = m.BridgeMaster.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.BondMaster != nil {\n\t\tl = m.BondMaster.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Wireguard != nil {\n\t\tl = m.Wireguard.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PermanentAddr)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Alias)\n\tif l > 0 {\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AltNames) > 0 {\n\t\tfor _, s := range m.AltNames {\n\t\t\tl = len(s)\n\t\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.VrfMaster != nil {\n\t\tl = m.VrfMaster.SizeVT()\n\t\tn += 2 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesAddressMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.IncludeSubnets) > 0 {\n\t\tfor _, e := range m.IncludeSubnets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor _, e := range m.ExcludeSubnets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Invert {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesChainSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Hook != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Hook))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tif len(m.Rules) > 0 {\n\t\tfor _, e := range m.Rules {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Policy != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Policy))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesClampMSS) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesConntrackStateMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.States) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.States {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesICMPTypeMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Types) > 0 {\n\t\tl = 0\n\t\tfor _, e := range m.Types {\n\t\t\tl += protohelpers.SizeOfVarint(uint64(e))\n\t\t}\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(l)) + l\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesIfNameMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Operator != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Operator))\n\t}\n\tif len(m.InterfaceNames) > 0 {\n\t\tfor _, s := range m.InterfaceNames {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesLayer4Match) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Protocol != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Protocol))\n\t}\n\tif m.MatchSourcePort != nil {\n\t\tl = m.MatchSourcePort.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchDestinationPort != nil {\n\t\tl = m.MatchDestinationPort.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchIcmpType != nil {\n\t\tl = m.MatchIcmpType.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesLimitMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.PacketRatePerSecond != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.PacketRatePerSecond))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesMark) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Mask != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mask))\n\t}\n\tif m.Xor != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Xor))\n\t}\n\tif m.Value != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Value))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesPortMatch) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Ranges) > 0 {\n\t\tfor _, e := range m.Ranges {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NfTablesRule) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MatchOIfName != nil {\n\t\tl = m.MatchOIfName.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Verdict != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Verdict))\n\t}\n\tif m.MatchMark != nil {\n\t\tl = m.MatchMark.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SetMark != nil {\n\t\tl = m.SetMark.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchSourceAddress != nil {\n\t\tl = m.MatchSourceAddress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchDestinationAddress != nil {\n\t\tl = m.MatchDestinationAddress.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchLayer4 != nil {\n\t\tl = m.MatchLayer4.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchIIfName != nil {\n\t\tl = m.MatchIIfName.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ClampMss != nil {\n\t\tl = m.ClampMss.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchLimit != nil {\n\t\tl = m.MatchLimit.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.MatchConntrackState != nil {\n\t\tl = m.MatchConntrackState.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.AnonCounter {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeAddressFilterSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.IncludeSubnets) > 0 {\n\t\tfor _, e := range m.IncludeSubnets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExcludeSubnets) > 0 {\n\t\tfor _, e := range m.ExcludeSubnets {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeAddressSortAlgorithmSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Algorithm != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Algorithm))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *NodeAddressSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.SortAlgorithm != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SortAlgorithm))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *OperatorSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Operator != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Operator))\n\t}\n\tl = len(m.LinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.RequireUp {\n\t\tn += 2\n\t}\n\tif m.Dhcp4 != nil {\n\t\tl = m.Dhcp4.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Dhcp6 != nil {\n\t\tl = m.Dhcp6.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Vip != nil {\n\t\tl = m.Vip.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PlatformConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Addresses) > 0 {\n\t\tfor _, e := range m.Addresses {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Links) > 0 {\n\t\tfor _, e := range m.Links {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Routes) > 0 {\n\t\tfor _, e := range m.Routes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Hostnames) > 0 {\n\t\tfor _, e := range m.Hostnames {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Resolvers) > 0 {\n\t\tfor _, e := range m.Resolvers {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.TimeServers) > 0 {\n\t\tfor _, e := range m.TimeServers {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Operators) > 0 {\n\t\tfor _, e := range m.Operators {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.ExternalIps) > 0 {\n\t\tfor _, e := range m.ExternalIps {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Probes) > 0 {\n\t\tfor _, e := range m.Probes {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PortRange) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Lo != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Lo))\n\t}\n\tif m.Hi != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Hi))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProbeSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Interval != nil {\n\t\tl = (*durationpb.Duration)(m.Interval).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FailureThreshold != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FailureThreshold))\n\t}\n\tif m.Tcp != nil {\n\t\tl = m.Tcp.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ProbeStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Success {\n\t\tn += 2\n\t}\n\tl = len(m.LastError)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ResolverSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.DnsServers) > 0 {\n\t\tfor _, e := range m.DnsServers {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tif len(m.SearchDomains) > 0 {\n\t\tfor _, s := range m.SearchDomains {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ResolverStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.DnsServers) > 0 {\n\t\tfor _, e := range m.DnsServers {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.SearchDomains) > 0 {\n\t\tfor _, s := range m.SearchDomains {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RouteSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Destination != nil {\n\t\tif size, ok := interface{}(m.Destination).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Destination)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Source != nil {\n\t\tif size, ok := interface{}(m.Source).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Source)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Gateway != nil {\n\t\tif size, ok := interface{}(m.Gateway).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Gateway)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.OutLinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Table != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Table))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tif m.Scope != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Scope))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif m.Flags != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Flags))\n\t}\n\tif m.Protocol != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Protocol))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RouteStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Destination != nil {\n\t\tif size, ok := interface{}(m.Destination).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Destination)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Source != nil {\n\t\tif size, ok := interface{}(m.Source).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Source)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Gateway != nil {\n\t\tif size, ok := interface{}(m.Gateway).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Gateway)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.OutLinkIndex != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.OutLinkIndex))\n\t}\n\tl = len(m.OutLinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Table != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Table))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tif m.Scope != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Scope))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tif m.Flags != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Flags))\n\t}\n\tif m.Protocol != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Protocol))\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RoutingRuleSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Src != nil {\n\t\tif size, ok := interface{}(m.Src).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Src)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Dst != nil {\n\t\tif size, ok := interface{}(m.Dst).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Dst)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Table != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Table))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tl = len(m.IifName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.OifName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FwMark != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FwMark))\n\t}\n\tif m.FwMask != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FwMask))\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *RoutingRuleStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Family != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Family))\n\t}\n\tif m.Src != nil {\n\t\tif size, ok := interface{}(m.Src).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Src)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Dst != nil {\n\t\tif size, ok := interface{}(m.Dst).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Dst)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Table != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Table))\n\t}\n\tif m.Priority != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Priority))\n\t}\n\tif m.Action != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Action))\n\t}\n\tl = len(m.IifName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.OifName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FwMark != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FwMark))\n\t}\n\tif m.FwMask != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FwMask))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *STPSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Enabled {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.AddressReady {\n\t\tn += 2\n\t}\n\tif m.ConnectivityReady {\n\t\tn += 2\n\t}\n\tif m.HostnameReady {\n\t\tn += 2\n\t}\n\tif m.EtcFilesReady {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TCPProbeSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Endpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Timeout != nil {\n\t\tl = (*durationpb.Duration)(m.Timeout).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TimeServerSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.NtpServers) > 0 {\n\t\tfor _, s := range m.NtpServers {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.ConfigLayer != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ConfigLayer))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TimeServerStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.NtpServers) > 0 {\n\t\tfor _, s := range m.NtpServers {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VIPEquinixMetalSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ProjectId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DeviceId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ApiToken)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VIPHCloudSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.DeviceId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.DeviceId))\n\t}\n\tif m.NetworkId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.NetworkId))\n\t}\n\tl = len(m.ApiToken)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VIPOperatorSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ip != nil {\n\t\tif size, ok := interface{}(m.Ip).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Ip)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.GratuitousArp {\n\t\tn += 2\n\t}\n\tif m.EquinixMetal != nil {\n\t\tl = m.EquinixMetal.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.HCloud != nil {\n\t\tl = m.HCloud.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VLANSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Vid != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Vid))\n\t}\n\tif m.Protocol != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Protocol))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VRFMasterSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Table != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Table))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *VRFSlave) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.MasterName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *WireguardPeer) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.PublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PresharedKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Endpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PersistentKeepaliveInterval != nil {\n\t\tl = (*durationpb.Duration)(m.PersistentKeepaliveInterval).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AllowedIps) > 0 {\n\t\tfor _, e := range m.AllowedIps {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *WireguardSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.PrivateKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PublicKey)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ListenPort != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ListenPort))\n\t}\n\tif m.FirewallMark != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FirewallMark))\n\t}\n\tif len(m.Peers) > 0 {\n\t\tfor _, e := range m.Peers {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AddressSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AddressSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AddressSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Address == nil {\n\t\t\t\tm.Address = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Address).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Address); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Scope\", wireType)\n\t\t\t}\n\t\t\tm.Scope = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Scope |= enums.NethelpersScope(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tm.Flags = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Flags |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AnnounceWithArp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AnnounceWithArp = bool(v != 0)\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *AddressStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AddressStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AddressStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Address == nil {\n\t\t\t\tm.Address = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Address).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Address); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Local\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Local == nil {\n\t\t\t\tm.Local = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Local).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Local); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Broadcast\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Broadcast == nil {\n\t\t\t\tm.Broadcast = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Broadcast).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Broadcast); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Anycast\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Anycast == nil {\n\t\t\t\tm.Anycast = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Anycast).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Anycast); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Multicast\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Multicast == nil {\n\t\t\t\tm.Multicast = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Multicast).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Multicast); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkIndex\", wireType)\n\t\t\t}\n\t\t\tm.LinkIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.LinkIndex |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Scope\", wireType)\n\t\t\t}\n\t\t\tm.Scope = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Scope |= enums.NethelpersScope(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tm.Flags = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Flags |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BondMasterSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BondMasterSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BondMasterSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mode\", wireType)\n\t\t\t}\n\t\t\tm.Mode = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mode |= enums.NethelpersBondMode(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HashPolicy\", wireType)\n\t\t\t}\n\t\t\tm.HashPolicy = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HashPolicy |= enums.NethelpersBondXmitHashPolicy(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LacpRate\", wireType)\n\t\t\t}\n\t\t\tm.LacpRate = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.LacpRate |= enums.NethelpersLACPRate(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ArpValidate\", wireType)\n\t\t\t}\n\t\t\tm.ArpValidate = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ArpValidate |= enums.NethelpersARPValidate(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ArpAllTargets\", wireType)\n\t\t\t}\n\t\t\tm.ArpAllTargets = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ArpAllTargets |= enums.NethelpersARPAllTargets(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrimaryIndex\", wireType)\n\t\t\t}\n\t\t\tm.PrimaryIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PrimaryIndex |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrimaryReselect\", wireType)\n\t\t\t}\n\t\t\tm.PrimaryReselect = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PrimaryReselect |= enums.NethelpersPrimaryReselect(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FailOverMac\", wireType)\n\t\t\t}\n\t\t\tm.FailOverMac = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FailOverMac |= enums.NethelpersFailOverMAC(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdSelect\", wireType)\n\t\t\t}\n\t\t\tm.AdSelect = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AdSelect |= enums.NethelpersADSelect(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MiiMon\", wireType)\n\t\t\t}\n\t\t\tm.MiiMon = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MiiMon |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UpDelay\", wireType)\n\t\t\t}\n\t\t\tm.UpDelay = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.UpDelay |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DownDelay\", wireType)\n\t\t\t}\n\t\t\tm.DownDelay = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DownDelay |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ArpInterval\", wireType)\n\t\t\t}\n\t\t\tm.ArpInterval = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ArpInterval |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResendIgmp\", wireType)\n\t\t\t}\n\t\t\tm.ResendIgmp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ResendIgmp |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MinLinks\", wireType)\n\t\t\t}\n\t\t\tm.MinLinks = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MinLinks |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LpInterval\", wireType)\n\t\t\t}\n\t\t\tm.LpInterval = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.LpInterval |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PacketsPerSlave\", wireType)\n\t\t\t}\n\t\t\tm.PacketsPerSlave = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PacketsPerSlave |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 18:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NumPeerNotif\", wireType)\n\t\t\t}\n\t\t\tm.NumPeerNotif = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NumPeerNotif |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 19:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TlbDynamicLb\", wireType)\n\t\t\t}\n\t\t\tm.TlbDynamicLb = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TlbDynamicLb |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 20:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllSlavesActive\", wireType)\n\t\t\t}\n\t\t\tm.AllSlavesActive = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AllSlavesActive |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 21:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UseCarrier\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.UseCarrier = bool(v != 0)\n\t\tcase 22:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdActorSysPrio\", wireType)\n\t\t\t}\n\t\t\tm.AdActorSysPrio = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AdActorSysPrio |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 23:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdUserPortKey\", wireType)\n\t\t\t}\n\t\t\tm.AdUserPortKey = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AdUserPortKey |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 24:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PeerNotifyDelay\", wireType)\n\t\t\t}\n\t\t\tm.PeerNotifyDelay = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PeerNotifyDelay |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 25:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ArpipTargets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ArpipTargets = append(m.ArpipTargets, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ArpipTargets[len(m.ArpipTargets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ArpipTargets[len(m.ArpipTargets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 26:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nsip6Targets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Nsip6Targets = append(m.Nsip6Targets, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.Nsip6Targets[len(m.Nsip6Targets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Nsip6Targets[len(m.Nsip6Targets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 27:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdlacpActive\", wireType)\n\t\t\t}\n\t\t\tm.AdlacpActive = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AdlacpActive |= enums.NethelpersADLACPActive(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 28:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MissedMax\", wireType)\n\t\t\t}\n\t\t\tm.MissedMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MissedMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BondSlave) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BondSlave: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BondSlave: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MasterName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MasterName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SlaveIndex\", wireType)\n\t\t\t}\n\t\t\tm.SlaveIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SlaveIndex |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BridgeMasterSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeMasterSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeMasterSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stp\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Stp == nil {\n\t\t\t\tm.Stp = &STPSpec{}\n\t\t\t}\n\t\t\tif err := m.Stp.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vlan\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Vlan == nil {\n\t\t\t\tm.Vlan = &BridgeVLANSpec{}\n\t\t\t}\n\t\t\tif err := m.Vlan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BridgeSlave) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeSlave: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeSlave: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MasterName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MasterName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BridgeVLANSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeVLANSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BridgeVLANSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FilteringEnabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.FilteringEnabled = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ClientIdentifierSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ClientIdentifierSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ClientIdentifierSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClientIdentifier\", wireType)\n\t\t\t}\n\t\t\tm.ClientIdentifier = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ClientIdentifier |= enums.NethelpersClientIdentifier(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DuidRawHex\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DuidRawHex = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DHCP4OperatorSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DHCP4OperatorSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DHCP4OperatorSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RouteMetric\", wireType)\n\t\t\t}\n\t\t\tm.RouteMetric = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RouteMetric |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipHostnameRequest\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipHostnameRequest = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClientIdentifier\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClientIdentifier == nil {\n\t\t\t\tm.ClientIdentifier = &ClientIdentifierSpec{}\n\t\t\t}\n\t\t\tif err := m.ClientIdentifier.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DHCP6OperatorSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DHCP6OperatorSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DHCP6OperatorSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RouteMetric\", wireType)\n\t\t\t}\n\t\t\tm.RouteMetric = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RouteMetric |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipHostnameRequest\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipHostnameRequest = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClientIdentifier\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClientIdentifier == nil {\n\t\t\t\tm.ClientIdentifier = &ClientIdentifierSpec{}\n\t\t\t}\n\t\t\tif err := m.ClientIdentifier.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DNSResolveCacheSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DNSResolveCacheSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DNSResolveCacheSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Status = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetChannelsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetChannelsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetChannelsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rx\", wireType)\n\t\t\t}\n\t\t\tm.Rx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tx\", wireType)\n\t\t\t}\n\t\t\tm.Tx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Other\", wireType)\n\t\t\t}\n\t\t\tm.Other = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Other |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Combined\", wireType)\n\t\t\t}\n\t\t\tm.Combined = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Combined |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetChannelsStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetChannelsStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetChannelsStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMax\", wireType)\n\t\t\t}\n\t\t\tm.RxMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxMax\", wireType)\n\t\t\t}\n\t\t\tm.TxMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OtherMax\", wireType)\n\t\t\t}\n\t\t\tm.OtherMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.OtherMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CombinedMax\", wireType)\n\t\t\t}\n\t\t\tm.CombinedMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CombinedMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rx\", wireType)\n\t\t\t}\n\t\t\tm.Rx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tx\", wireType)\n\t\t\t}\n\t\t\tm.Tx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Other\", wireType)\n\t\t\t}\n\t\t\tm.Other = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Other |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Combined\", wireType)\n\t\t\t}\n\t\t\tm.Combined = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Combined |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetFeatureStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetFeatureStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetFeatureStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Status = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetRingsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetRingsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetRingsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rx\", wireType)\n\t\t\t}\n\t\t\tm.Rx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMini\", wireType)\n\t\t\t}\n\t\t\tm.RxMini = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMini |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxJumbo\", wireType)\n\t\t\t}\n\t\t\tm.RxJumbo = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxJumbo |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tx\", wireType)\n\t\t\t}\n\t\t\tm.Tx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxBufLen\", wireType)\n\t\t\t}\n\t\t\tm.RxBufLen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxBufLen |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CqeSize\", wireType)\n\t\t\t}\n\t\t\tm.CqeSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CqeSize |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPush\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TxPush = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxPush\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RxPush = bool(v != 0)\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPushBufLen\", wireType)\n\t\t\t}\n\t\t\tm.TxPushBufLen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxPushBufLen |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TcpDataSplit\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TcpDataSplit = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetRingsStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetRingsStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetRingsStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMax\", wireType)\n\t\t\t}\n\t\t\tm.RxMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMiniMax\", wireType)\n\t\t\t}\n\t\t\tm.RxMiniMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMiniMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxJumboMax\", wireType)\n\t\t\t}\n\t\t\tm.RxJumboMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxJumboMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxMax\", wireType)\n\t\t\t}\n\t\t\tm.TxMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPushBufLenMax\", wireType)\n\t\t\t}\n\t\t\tm.TxPushBufLenMax = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxPushBufLenMax |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rx\", wireType)\n\t\t\t}\n\t\t\tm.Rx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Rx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxMini\", wireType)\n\t\t\t}\n\t\t\tm.RxMini = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxMini |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxJumbo\", wireType)\n\t\t\t}\n\t\t\tm.RxJumbo = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxJumbo |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tx\", wireType)\n\t\t\t}\n\t\t\tm.Tx = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Tx |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxBufLen\", wireType)\n\t\t\t}\n\t\t\tm.RxBufLen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.RxBufLen |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CqeSize\", wireType)\n\t\t\t}\n\t\t\tm.CqeSize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CqeSize |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPush\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TxPush = bool(v != 0)\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RxPush\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RxPush = bool(v != 0)\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TxPushBufLen\", wireType)\n\t\t\t}\n\t\t\tm.TxPushBufLen = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.TxPushBufLen |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TcpDataSplit\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.TcpDataSplit = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rings\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Rings == nil {\n\t\t\t\tm.Rings = &EthernetRingsSpec{}\n\t\t\t}\n\t\t\tif err := m.Rings.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Features\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Features == nil {\n\t\t\t\tm.Features = make(map[string]bool)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue bool\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar mapvaluetemp int\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tmapvaluetemp |= int(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = bool(mapvaluetemp != 0)\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Features[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Channels\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Channels == nil {\n\t\t\t\tm.Channels = &EthernetChannelsSpec{}\n\t\t\t}\n\t\t\tif err := m.Channels.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v enums.NethelpersWOLMode\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= enums.NethelpersWOLMode(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.WakeOnLan = append(m.WakeOnLan, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tif elementCount != 0 && len(m.WakeOnLan) == 0 {\n\t\t\t\t\tm.WakeOnLan = make([]enums.NethelpersWOLMode, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v enums.NethelpersWOLMode\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= enums.NethelpersWOLMode(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.WakeOnLan = append(m.WakeOnLan, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WakeOnLan\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EthernetStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EthernetStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkState\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.LinkState = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SpeedMegabits\", wireType)\n\t\t\t}\n\t\t\tm.SpeedMegabits = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SpeedMegabits |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Port\", wireType)\n\t\t\t}\n\t\t\tm.Port = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Port |= enums.NethelpersPort(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Duplex\", wireType)\n\t\t\t}\n\t\t\tm.Duplex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Duplex |= enums.NethelpersDuplex(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OurModes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OurModes = append(m.OurModes, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PeerModes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PeerModes = append(m.PeerModes, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rings\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Rings == nil {\n\t\t\t\tm.Rings = &EthernetRingsStatus{}\n\t\t\t}\n\t\t\tif err := m.Rings.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Features\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Features = append(m.Features, &EthernetFeatureStatus{})\n\t\t\tif err := m.Features[len(m.Features)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Channels\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Channels == nil {\n\t\t\t\tm.Channels = &EthernetChannelsStatus{}\n\t\t\t}\n\t\t\tif err := m.Channels.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v enums.NethelpersWOLMode\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= enums.NethelpersWOLMode(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.WakeOnLan = append(m.WakeOnLan, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tif elementCount != 0 && len(m.WakeOnLan) == 0 {\n\t\t\t\t\tm.WakeOnLan = make([]enums.NethelpersWOLMode, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v enums.NethelpersWOLMode\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= enums.NethelpersWOLMode(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.WakeOnLan = append(m.WakeOnLan, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WakeOnLan\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HardwareAddrSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HardwareAddrSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HardwareAddrSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HardwareAddr\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.HardwareAddr = append(m.HardwareAddr[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.HardwareAddr == nil {\n\t\t\t\tm.HardwareAddr = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HostDNSConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HostDNSConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HostDNSConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenAddresses = append(m.ListenAddresses, &common.NetIPPort{})\n\t\t\tif unmarshal, ok := interface{}(m.ListenAddresses[len(m.ListenAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ListenAddresses[len(m.ListenAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceHostDnsAddress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ServiceHostDnsAddress == nil {\n\t\t\t\tm.ServiceHostDnsAddress = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.ServiceHostDnsAddress).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ServiceHostDnsAddress); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ResolveMemberNames\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ResolveMemberNames = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HostnameSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Domainname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Domainname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *HostnameStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: HostnameStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Domainname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Domainname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LinkAliasSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LinkAliasSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LinkAliasSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Alias\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Alias = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LinkRefreshSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LinkRefreshSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LinkRefreshSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Generation\", wireType)\n\t\t\t}\n\t\t\tm.Generation = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Generation |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LinkSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LinkSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LinkSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Logical\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Logical = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Up\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Up = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Kind\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Kind = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.NethelpersLinkType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ParentName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ParentName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BondSlave\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BondSlave == nil {\n\t\t\t\tm.BondSlave = &BondSlave{}\n\t\t\t}\n\t\t\tif err := m.BondSlave.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BridgeSlave\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BridgeSlave == nil {\n\t\t\t\tm.BridgeSlave = &BridgeSlave{}\n\t\t\t}\n\t\t\tif err := m.BridgeSlave.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vlan\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Vlan == nil {\n\t\t\t\tm.Vlan = &VLANSpec{}\n\t\t\t}\n\t\t\tif err := m.Vlan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BondMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BondMaster == nil {\n\t\t\t\tm.BondMaster = &BondMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.BondMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BridgeMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BridgeMaster == nil {\n\t\t\t\tm.BridgeMaster = &BridgeMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.BridgeMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wireguard\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Wireguard == nil {\n\t\t\t\tm.Wireguard = &WireguardSpec{}\n\t\t\t}\n\t\t\tif err := m.Wireguard.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HardwareAddress\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.HardwareAddress = append(m.HardwareAddress[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.HardwareAddress == nil {\n\t\t\t\tm.HardwareAddress = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Multicast\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Multicast = bool(v != 0)\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VrfMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.VrfMaster == nil {\n\t\t\t\tm.VrfMaster = &VRFMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.VrfMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VrfSlave\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.VrfSlave == nil {\n\t\t\t\tm.VrfSlave = &VRFSlave{}\n\t\t\t}\n\t\t\tif err := m.VrfSlave.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LinkStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LinkStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LinkStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Index\", wireType)\n\t\t\t}\n\t\t\tm.Index = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Index |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.NethelpersLinkType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkIndex\", wireType)\n\t\t\t}\n\t\t\tm.LinkIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.LinkIndex |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tm.Flags = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Flags |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HardwareAddr\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.HardwareAddr = append(m.HardwareAddr[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.HardwareAddr == nil {\n\t\t\t\tm.HardwareAddr = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BroadcastAddr\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BroadcastAddr = append(m.BroadcastAddr[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.BroadcastAddr == nil {\n\t\t\t\tm.BroadcastAddr = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field QueueDisc\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.QueueDisc = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MasterIndex\", wireType)\n\t\t\t}\n\t\t\tm.MasterIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MasterIndex |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OperationalState\", wireType)\n\t\t\t}\n\t\t\tm.OperationalState = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.OperationalState |= enums.NethelpersOperationalState(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Kind\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Kind = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SlaveKind\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SlaveKind = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BusPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BusPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Pciid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Pciid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Driver\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Driver = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 16:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DriverVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DriverVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 17:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FirmwareVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FirmwareVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 18:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProductId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProductId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 19:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VendorId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.VendorId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 20:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Product\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Product = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 21:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vendor\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Vendor = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 22:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkState\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.LinkState = bool(v != 0)\n\t\tcase 23:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SpeedMegabits\", wireType)\n\t\t\t}\n\t\t\tm.SpeedMegabits = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SpeedMegabits |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 24:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Port\", wireType)\n\t\t\t}\n\t\t\tm.Port = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Port |= enums.NethelpersPort(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 25:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Duplex\", wireType)\n\t\t\t}\n\t\t\tm.Duplex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Duplex |= enums.NethelpersDuplex(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 26:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vlan\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Vlan == nil {\n\t\t\t\tm.Vlan = &VLANSpec{}\n\t\t\t}\n\t\t\tif err := m.Vlan.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 27:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BridgeMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BridgeMaster == nil {\n\t\t\t\tm.BridgeMaster = &BridgeMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.BridgeMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 28:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BondMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.BondMaster == nil {\n\t\t\t\tm.BondMaster = &BondMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.BondMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 29:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wireguard\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Wireguard == nil {\n\t\t\t\tm.Wireguard = &WireguardSpec{}\n\t\t\t}\n\t\t\tif err := m.Wireguard.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 30:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PermanentAddr\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PermanentAddr = append(m.PermanentAddr[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.PermanentAddr == nil {\n\t\t\t\tm.PermanentAddr = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 31:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Alias\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Alias = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 32:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AltNames\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AltNames = append(m.AltNames, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 33:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VrfMaster\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.VrfMaster == nil {\n\t\t\t\tm.VrfMaster = &VRFMasterSpec{}\n\t\t\t}\n\t\t\tif err := m.VrfMaster.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesAddressMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesAddressMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesAddressMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IncludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.IncludeSubnets = append(m.IncludeSubnets, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.IncludeSubnets[len(m.IncludeSubnets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.IncludeSubnets[len(m.IncludeSubnets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExcludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExcludeSubnets = append(m.ExcludeSubnets, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.ExcludeSubnets[len(m.ExcludeSubnets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExcludeSubnets[len(m.ExcludeSubnets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Invert\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Invert = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesChainSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesChainSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesChainSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hook\", wireType)\n\t\t\t}\n\t\t\tm.Hook = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hook |= enums.NethelpersNfTablesChainHook(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= enums.NethelpersNfTablesChainPriority(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Rules\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Rules = append(m.Rules, &NfTablesRule{})\n\t\t\tif err := m.Rules[len(m.Rules)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Policy\", wireType)\n\t\t\t}\n\t\t\tm.Policy = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Policy |= enums.NethelpersNfTablesVerdict(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesClampMSS) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesClampMSS: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesClampMSS: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesConntrackStateMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesConntrackStateMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesConntrackStateMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v enums.NethelpersConntrackState\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= enums.NethelpersConntrackState(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.States = append(m.States, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tif elementCount != 0 && len(m.States) == 0 {\n\t\t\t\t\tm.States = make([]enums.NethelpersConntrackState, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v enums.NethelpersConntrackState\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= enums.NethelpersConntrackState(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.States = append(m.States, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field States\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesICMPTypeMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesICMPTypeMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesICMPTypeMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType == 0 {\n\t\t\t\tvar v enums.NethelpersICMPType\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tv |= enums.NethelpersICMPType(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tm.Types = append(m.Types, v)\n\t\t\t} else if wireType == 2 {\n\t\t\t\tvar packedLen int\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\tpackedLen |= int(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif packedLen < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tpostIndex := iNdEx + packedLen\n\t\t\t\tif postIndex < 0 {\n\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t}\n\t\t\t\tif postIndex > l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tvar elementCount int\n\t\t\t\tif elementCount != 0 && len(m.Types) == 0 {\n\t\t\t\t\tm.Types = make([]enums.NethelpersICMPType, 0, elementCount)\n\t\t\t\t}\n\t\t\t\tfor iNdEx < postIndex {\n\t\t\t\t\tvar v enums.NethelpersICMPType\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tv |= enums.NethelpersICMPType(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm.Types = append(m.Types, v)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Types\", wireType)\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesIfNameMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesIfNameMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesIfNameMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Operator\", wireType)\n\t\t\t}\n\t\t\tm.Operator = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Operator |= enums.NethelpersMatchOperator(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InterfaceNames\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InterfaceNames = append(m.InterfaceNames, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesLayer4Match) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesLayer4Match: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesLayer4Match: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Protocol\", wireType)\n\t\t\t}\n\t\t\tm.Protocol = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Protocol |= enums.NethelpersProtocol(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchSourcePort\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchSourcePort == nil {\n\t\t\t\tm.MatchSourcePort = &NfTablesPortMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchSourcePort.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchDestinationPort\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchDestinationPort == nil {\n\t\t\t\tm.MatchDestinationPort = &NfTablesPortMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchDestinationPort.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchIcmpType\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchIcmpType == nil {\n\t\t\t\tm.MatchIcmpType = &NfTablesICMPTypeMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchIcmpType.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesLimitMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesLimitMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesLimitMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PacketRatePerSecond\", wireType)\n\t\t\t}\n\t\t\tm.PacketRatePerSecond = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PacketRatePerSecond |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesMark) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesMark: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesMark: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mask\", wireType)\n\t\t\t}\n\t\t\tm.Mask = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mask |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Xor\", wireType)\n\t\t\t}\n\t\t\tm.Xor = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Xor |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tm.Value = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Value |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesPortMatch) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesPortMatch: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesPortMatch: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ranges\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ranges = append(m.Ranges, &PortRange{})\n\t\t\tif err := m.Ranges[len(m.Ranges)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NfTablesRule) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesRule: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NfTablesRule: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchOIfName\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchOIfName == nil {\n\t\t\t\tm.MatchOIfName = &NfTablesIfNameMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchOIfName.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Verdict\", wireType)\n\t\t\t}\n\t\t\tm.Verdict = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Verdict |= enums.NethelpersNfTablesVerdict(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchMark\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchMark == nil {\n\t\t\t\tm.MatchMark = &NfTablesMark{}\n\t\t\t}\n\t\t\tif err := m.MatchMark.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SetMark\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.SetMark == nil {\n\t\t\t\tm.SetMark = &NfTablesMark{}\n\t\t\t}\n\t\t\tif err := m.SetMark.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchSourceAddress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchSourceAddress == nil {\n\t\t\t\tm.MatchSourceAddress = &NfTablesAddressMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchSourceAddress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchDestinationAddress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchDestinationAddress == nil {\n\t\t\t\tm.MatchDestinationAddress = &NfTablesAddressMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchDestinationAddress.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchLayer4\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchLayer4 == nil {\n\t\t\t\tm.MatchLayer4 = &NfTablesLayer4Match{}\n\t\t\t}\n\t\t\tif err := m.MatchLayer4.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchIIfName\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchIIfName == nil {\n\t\t\t\tm.MatchIIfName = &NfTablesIfNameMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchIIfName.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ClampMss\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ClampMss == nil {\n\t\t\t\tm.ClampMss = &NfTablesClampMSS{}\n\t\t\t}\n\t\t\tif err := m.ClampMss.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchLimit\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchLimit == nil {\n\t\t\t\tm.MatchLimit = &NfTablesLimitMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchLimit.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MatchConntrackState\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MatchConntrackState == nil {\n\t\t\t\tm.MatchConntrackState = &NfTablesConntrackStateMatch{}\n\t\t\t}\n\t\t\tif err := m.MatchConntrackState.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AnonCounter\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AnonCounter = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeAddressFilterSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressFilterSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressFilterSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IncludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.IncludeSubnets = append(m.IncludeSubnets, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.IncludeSubnets[len(m.IncludeSubnets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.IncludeSubnets[len(m.IncludeSubnets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExcludeSubnets\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExcludeSubnets = append(m.ExcludeSubnets, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.ExcludeSubnets[len(m.ExcludeSubnets)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExcludeSubnets[len(m.ExcludeSubnets)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeAddressSortAlgorithmSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressSortAlgorithmSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressSortAlgorithmSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Algorithm\", wireType)\n\t\t\t}\n\t\t\tm.Algorithm = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Algorithm |= enums.NethelpersAddressSortAlgorithm(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *NodeAddressSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: NodeAddressSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.Addresses[len(m.Addresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Addresses[len(m.Addresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SortAlgorithm\", wireType)\n\t\t\t}\n\t\t\tm.SortAlgorithm = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SortAlgorithm |= enums.NethelpersAddressSortAlgorithm(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *OperatorSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: OperatorSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: OperatorSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Operator\", wireType)\n\t\t\t}\n\t\t\tm.Operator = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Operator |= enums.NetworkOperator(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field RequireUp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.RequireUp = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dhcp4\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Dhcp4 == nil {\n\t\t\t\tm.Dhcp4 = &DHCP4OperatorSpec{}\n\t\t\t}\n\t\t\tif err := m.Dhcp4.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dhcp6\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Dhcp6 == nil {\n\t\t\t\tm.Dhcp6 = &DHCP6OperatorSpec{}\n\t\t\t}\n\t\t\tif err := m.Dhcp6.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vip\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Vip == nil {\n\t\t\t\tm.Vip = &VIPOperatorSpec{}\n\t\t\t}\n\t\t\tif err := m.Vip.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PlatformConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Addresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Addresses = append(m.Addresses, &AddressSpecSpec{})\n\t\t\tif err := m.Addresses[len(m.Addresses)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Links\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Links = append(m.Links, &LinkSpecSpec{})\n\t\t\tif err := m.Links[len(m.Links)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Routes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Routes = append(m.Routes, &RouteSpecSpec{})\n\t\t\tif err := m.Routes[len(m.Routes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostnames\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostnames = append(m.Hostnames, &HostnameSpecSpec{})\n\t\t\tif err := m.Hostnames[len(m.Hostnames)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Resolvers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Resolvers = append(m.Resolvers, &ResolverSpecSpec{})\n\t\t\tif err := m.Resolvers[len(m.Resolvers)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TimeServers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TimeServers = append(m.TimeServers, &TimeServerSpecSpec{})\n\t\t\tif err := m.TimeServers[len(m.TimeServers)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Operators\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Operators = append(m.Operators, &OperatorSpecSpec{})\n\t\t\tif err := m.Operators[len(m.Operators)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExternalIps\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExternalIps = append(m.ExternalIps, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ExternalIps[len(m.ExternalIps)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ExternalIps[len(m.ExternalIps)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Probes\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Probes = append(m.Probes, &ProbeSpecSpec{})\n\t\t\tif err := m.Probes[len(m.Probes)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &runtime.PlatformMetadataSpec{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PortRange) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PortRange: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PortRange: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Lo\", wireType)\n\t\t\t}\n\t\t\tm.Lo = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Lo |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hi\", wireType)\n\t\t\t}\n\t\t\tm.Hi = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hi |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProbeSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProbeSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProbeSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Interval\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Interval == nil {\n\t\t\t\tm.Interval = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Interval).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FailureThreshold\", wireType)\n\t\t\t}\n\t\t\tm.FailureThreshold = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FailureThreshold |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tcp\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Tcp == nil {\n\t\t\t\tm.Tcp = &TCPProbeSpec{}\n\t\t\t}\n\t\t\tif err := m.Tcp.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ProbeStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ProbeStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ProbeStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Success\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Success = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastError\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LastError = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ResolverSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ResolverSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ResolverSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsServers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsServers = append(m.DnsServers, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.DnsServers[len(m.DnsServers)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.DnsServers[len(m.DnsServers)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SearchDomains\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SearchDomains = append(m.SearchDomains, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ResolverStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ResolverStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ResolverStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsServers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsServers = append(m.DnsServers, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.DnsServers[len(m.DnsServers)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.DnsServers[len(m.DnsServers)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SearchDomains\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SearchDomains = append(m.SearchDomains, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RouteSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RouteSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RouteSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Destination\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Destination == nil {\n\t\t\t\tm.Destination = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Destination).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Destination); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Source == nil {\n\t\t\t\tm.Source = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Source).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Source); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Gateway\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Gateway == nil {\n\t\t\t\tm.Gateway = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Gateway).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Gateway); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OutLinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OutLinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Table\", wireType)\n\t\t\t}\n\t\t\tm.Table = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Table |= enums.NethelpersRoutingTable(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Scope\", wireType)\n\t\t\t}\n\t\t\tm.Scope = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Scope |= enums.NethelpersScope(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.NethelpersRouteType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tm.Flags = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Flags |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Protocol\", wireType)\n\t\t\t}\n\t\t\tm.Protocol = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Protocol |= enums.NethelpersRouteProtocol(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RouteStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RouteStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RouteStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Destination\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Destination == nil {\n\t\t\t\tm.Destination = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Destination).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Destination); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Source == nil {\n\t\t\t\tm.Source = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Source).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Source); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Gateway\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Gateway == nil {\n\t\t\t\tm.Gateway = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Gateway).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Gateway); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OutLinkIndex\", wireType)\n\t\t\t}\n\t\t\tm.OutLinkIndex = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.OutLinkIndex |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OutLinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OutLinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Table\", wireType)\n\t\t\t}\n\t\t\tm.Table = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Table |= enums.NethelpersRoutingTable(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Scope\", wireType)\n\t\t\t}\n\t\t\tm.Scope = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Scope |= enums.NethelpersScope(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= enums.NethelpersRouteType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Flags\", wireType)\n\t\t\t}\n\t\t\tm.Flags = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Flags |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Protocol\", wireType)\n\t\t\t}\n\t\t\tm.Protocol = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Protocol |= enums.NethelpersRouteProtocol(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RoutingRuleSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RoutingRuleSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RoutingRuleSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Src\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Src == nil {\n\t\t\t\tm.Src = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Src).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Src); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dst\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Dst == nil {\n\t\t\t\tm.Dst = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Dst).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Dst); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Table\", wireType)\n\t\t\t}\n\t\t\tm.Table = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Table |= enums.NethelpersRoutingTable(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= enums.NethelpersRoutingRuleAction(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IifName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.IifName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OifName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OifName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FwMark\", wireType)\n\t\t\t}\n\t\t\tm.FwMark = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FwMark |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FwMask\", wireType)\n\t\t\t}\n\t\t\tm.FwMask = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FwMask |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *RoutingRuleStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: RoutingRuleStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: RoutingRuleStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Family\", wireType)\n\t\t\t}\n\t\t\tm.Family = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Family |= enums.NethelpersFamily(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Src\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Src == nil {\n\t\t\t\tm.Src = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Src).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Src); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dst\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Dst == nil {\n\t\t\t\tm.Dst = &common.NetIPPrefix{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Dst).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Dst); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Table\", wireType)\n\t\t\t}\n\t\t\tm.Table = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Table |= enums.NethelpersRoutingTable(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Priority\", wireType)\n\t\t\t}\n\t\t\tm.Priority = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Priority |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Action\", wireType)\n\t\t\t}\n\t\t\tm.Action = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Action |= enums.NethelpersRoutingRuleAction(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IifName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.IifName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field OifName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.OifName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FwMark\", wireType)\n\t\t\t}\n\t\t\tm.FwMark = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FwMark |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FwMask\", wireType)\n\t\t\t}\n\t\t\tm.FwMask = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FwMask |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *STPSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: STPSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: STPSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Enabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Enabled = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AddressReady\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.AddressReady = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConnectivityReady\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ConnectivityReady = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HostnameReady\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.HostnameReady = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcFilesReady\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.EtcFilesReady = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TCPProbeSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TCPProbeSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TCPProbeSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timeout\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Timeout == nil {\n\t\t\t\tm.Timeout = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Timeout).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TimeServerSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TimeServerSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TimeServerSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NtpServers\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NtpServers = append(m.NtpServers, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ConfigLayer\", wireType)\n\t\t\t}\n\t\t\tm.ConfigLayer = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ConfigLayer |= enums.NetworkConfigLayer(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TimeServerStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TimeServerStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TimeServerStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NtpServers\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.NtpServers = append(m.NtpServers, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VIPEquinixMetalSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VIPEquinixMetalSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VIPEquinixMetalSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProjectId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProjectId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DeviceId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DeviceId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiToken\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApiToken = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VIPHCloudSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VIPHCloudSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VIPHCloudSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DeviceId\", wireType)\n\t\t\t}\n\t\t\tm.DeviceId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DeviceId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NetworkId\", wireType)\n\t\t\t}\n\t\t\tm.NetworkId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NetworkId |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiToken\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApiToken = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VIPOperatorSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VIPOperatorSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VIPOperatorSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ip\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Ip == nil {\n\t\t\t\tm.Ip = &common.NetIP{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Ip).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Ip); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GratuitousArp\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.GratuitousArp = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EquinixMetal\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EquinixMetal == nil {\n\t\t\t\tm.EquinixMetal = &VIPEquinixMetalSpec{}\n\t\t\t}\n\t\t\tif err := m.EquinixMetal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HCloud\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.HCloud == nil {\n\t\t\t\tm.HCloud = &VIPHCloudSpec{}\n\t\t\t}\n\t\t\tif err := m.HCloud.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VLANSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VLANSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VLANSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Vid\", wireType)\n\t\t\t}\n\t\t\tm.Vid = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Vid |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Protocol\", wireType)\n\t\t\t}\n\t\t\tm.Protocol = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Protocol |= enums.NethelpersVLANProtocol(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VRFMasterSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VRFMasterSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VRFMasterSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Table\", wireType)\n\t\t\t}\n\t\t\tm.Table = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Table |= enums.NethelpersRoutingTable(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *VRFSlave) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: VRFSlave: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: VRFSlave: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MasterName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MasterName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *WireguardPeer) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: WireguardPeer: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: WireguardPeer: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PublicKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PresharedKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PresharedKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PersistentKeepaliveInterval\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.PersistentKeepaliveInterval == nil {\n\t\t\t\tm.PersistentKeepaliveInterval = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.PersistentKeepaliveInterval).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AllowedIps\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AllowedIps = append(m.AllowedIps, &common.NetIPPrefix{})\n\t\t\tif unmarshal, ok := interface{}(m.AllowedIps[len(m.AllowedIps)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AllowedIps[len(m.AllowedIps)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *WireguardSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: WireguardSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: WireguardSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PrivateKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PrivateKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKey\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PublicKey = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenPort\", wireType)\n\t\t\t}\n\t\t\tm.ListenPort = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ListenPort |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FirewallMark\", wireType)\n\t\t\t}\n\t\t\tm.FirewallMark = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FirewallMark |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Peers\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Peers = append(m.Peers, &WireguardPeer{})\n\t\t\tif err := m.Peers[len(m.Peers)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/perf/perf.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/perf/perf.proto\n\npackage perf\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// CPUSpec represents the last CPU stats snapshot.\ntype CPUSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tCpu             []*CPUStat             `protobuf:\"bytes,1,rep,name=cpu,proto3\" json:\"cpu,omitempty\"`\n\tCpuTotal        *CPUStat               `protobuf:\"bytes,2,opt,name=cpu_total,json=cpuTotal,proto3\" json:\"cpu_total,omitempty\"`\n\tIrqTotal        uint64                 `protobuf:\"varint,3,opt,name=irq_total,json=irqTotal,proto3\" json:\"irq_total,omitempty\"`\n\tContextSwitches uint64                 `protobuf:\"varint,4,opt,name=context_switches,json=contextSwitches,proto3\" json:\"context_switches,omitempty\"`\n\tProcessCreated  uint64                 `protobuf:\"varint,5,opt,name=process_created,json=processCreated,proto3\" json:\"process_created,omitempty\"`\n\tProcessRunning  uint64                 `protobuf:\"varint,6,opt,name=process_running,json=processRunning,proto3\" json:\"process_running,omitempty\"`\n\tProcessBlocked  uint64                 `protobuf:\"varint,7,opt,name=process_blocked,json=processBlocked,proto3\" json:\"process_blocked,omitempty\"`\n\tSoftIrqTotal    uint64                 `protobuf:\"varint,8,opt,name=soft_irq_total,json=softIrqTotal,proto3\" json:\"soft_irq_total,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *CPUSpec) Reset() {\n\t*x = CPUSpec{}\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUSpec) ProtoMessage() {}\n\nfunc (x *CPUSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUSpec.ProtoReflect.Descriptor instead.\nfunc (*CPUSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_perf_perf_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *CPUSpec) GetCpu() []*CPUStat {\n\tif x != nil {\n\t\treturn x.Cpu\n\t}\n\treturn nil\n}\n\nfunc (x *CPUSpec) GetCpuTotal() *CPUStat {\n\tif x != nil {\n\t\treturn x.CpuTotal\n\t}\n\treturn nil\n}\n\nfunc (x *CPUSpec) GetIrqTotal() uint64 {\n\tif x != nil {\n\t\treturn x.IrqTotal\n\t}\n\treturn 0\n}\n\nfunc (x *CPUSpec) GetContextSwitches() uint64 {\n\tif x != nil {\n\t\treturn x.ContextSwitches\n\t}\n\treturn 0\n}\n\nfunc (x *CPUSpec) GetProcessCreated() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessCreated\n\t}\n\treturn 0\n}\n\nfunc (x *CPUSpec) GetProcessRunning() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessRunning\n\t}\n\treturn 0\n}\n\nfunc (x *CPUSpec) GetProcessBlocked() uint64 {\n\tif x != nil {\n\t\treturn x.ProcessBlocked\n\t}\n\treturn 0\n}\n\nfunc (x *CPUSpec) GetSoftIrqTotal() uint64 {\n\tif x != nil {\n\t\treturn x.SoftIrqTotal\n\t}\n\treturn 0\n}\n\n// CPUStat represents a single cpu stat.\ntype CPUStat struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tUser          float64                `protobuf:\"fixed64,1,opt,name=user,proto3\" json:\"user,omitempty\"`\n\tNice          float64                `protobuf:\"fixed64,2,opt,name=nice,proto3\" json:\"nice,omitempty\"`\n\tSystem        float64                `protobuf:\"fixed64,3,opt,name=system,proto3\" json:\"system,omitempty\"`\n\tIdle          float64                `protobuf:\"fixed64,4,opt,name=idle,proto3\" json:\"idle,omitempty\"`\n\tIowait        float64                `protobuf:\"fixed64,5,opt,name=iowait,proto3\" json:\"iowait,omitempty\"`\n\tIrq           float64                `protobuf:\"fixed64,6,opt,name=irq,proto3\" json:\"irq,omitempty\"`\n\tSoftIrq       float64                `protobuf:\"fixed64,7,opt,name=soft_irq,json=softIrq,proto3\" json:\"soft_irq,omitempty\"`\n\tSteal         float64                `protobuf:\"fixed64,8,opt,name=steal,proto3\" json:\"steal,omitempty\"`\n\tGuest         float64                `protobuf:\"fixed64,9,opt,name=guest,proto3\" json:\"guest,omitempty\"`\n\tGuestNice     float64                `protobuf:\"fixed64,10,opt,name=guest_nice,json=guestNice,proto3\" json:\"guest_nice,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CPUStat) Reset() {\n\t*x = CPUStat{}\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CPUStat) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CPUStat) ProtoMessage() {}\n\nfunc (x *CPUStat) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CPUStat.ProtoReflect.Descriptor instead.\nfunc (*CPUStat) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_perf_perf_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *CPUStat) GetUser() float64 {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetNice() float64 {\n\tif x != nil {\n\t\treturn x.Nice\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSystem() float64 {\n\tif x != nil {\n\t\treturn x.System\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIdle() float64 {\n\tif x != nil {\n\t\treturn x.Idle\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIowait() float64 {\n\tif x != nil {\n\t\treturn x.Iowait\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetIrq() float64 {\n\tif x != nil {\n\t\treturn x.Irq\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSoftIrq() float64 {\n\tif x != nil {\n\t\treturn x.SoftIrq\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetSteal() float64 {\n\tif x != nil {\n\t\treturn x.Steal\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetGuest() float64 {\n\tif x != nil {\n\t\treturn x.Guest\n\t}\n\treturn 0\n}\n\nfunc (x *CPUStat) GetGuestNice() float64 {\n\tif x != nil {\n\t\treturn x.GuestNice\n\t}\n\treturn 0\n}\n\n// MemorySpec represents the last Memory stats snapshot.\ntype MemorySpec struct {\n\tstate             protoimpl.MessageState `protogen:\"open.v1\"`\n\tMemTotal          uint64                 `protobuf:\"varint,1,opt,name=mem_total,json=memTotal,proto3\" json:\"mem_total,omitempty\"`\n\tMemUsed           uint64                 `protobuf:\"varint,2,opt,name=mem_used,json=memUsed,proto3\" json:\"mem_used,omitempty\"`\n\tMemAvailable      uint64                 `protobuf:\"varint,3,opt,name=mem_available,json=memAvailable,proto3\" json:\"mem_available,omitempty\"`\n\tBuffers           uint64                 `protobuf:\"varint,4,opt,name=buffers,proto3\" json:\"buffers,omitempty\"`\n\tCached            uint64                 `protobuf:\"varint,5,opt,name=cached,proto3\" json:\"cached,omitempty\"`\n\tSwapCached        uint64                 `protobuf:\"varint,6,opt,name=swap_cached,json=swapCached,proto3\" json:\"swap_cached,omitempty\"`\n\tActive            uint64                 `protobuf:\"varint,7,opt,name=active,proto3\" json:\"active,omitempty\"`\n\tInactive          uint64                 `protobuf:\"varint,8,opt,name=inactive,proto3\" json:\"inactive,omitempty\"`\n\tActiveAnon        uint64                 `protobuf:\"varint,9,opt,name=active_anon,json=activeAnon,proto3\" json:\"active_anon,omitempty\"`\n\tInactiveAnon      uint64                 `protobuf:\"varint,10,opt,name=inactive_anon,json=inactiveAnon,proto3\" json:\"inactive_anon,omitempty\"`\n\tActiveFile        uint64                 `protobuf:\"varint,11,opt,name=active_file,json=activeFile,proto3\" json:\"active_file,omitempty\"`\n\tInactiveFile      uint64                 `protobuf:\"varint,12,opt,name=inactive_file,json=inactiveFile,proto3\" json:\"inactive_file,omitempty\"`\n\tUnevictable       uint64                 `protobuf:\"varint,13,opt,name=unevictable,proto3\" json:\"unevictable,omitempty\"`\n\tMlocked           uint64                 `protobuf:\"varint,14,opt,name=mlocked,proto3\" json:\"mlocked,omitempty\"`\n\tSwapTotal         uint64                 `protobuf:\"varint,15,opt,name=swap_total,json=swapTotal,proto3\" json:\"swap_total,omitempty\"`\n\tSwapFree          uint64                 `protobuf:\"varint,16,opt,name=swap_free,json=swapFree,proto3\" json:\"swap_free,omitempty\"`\n\tDirty             uint64                 `protobuf:\"varint,17,opt,name=dirty,proto3\" json:\"dirty,omitempty\"`\n\tWriteback         uint64                 `protobuf:\"varint,18,opt,name=writeback,proto3\" json:\"writeback,omitempty\"`\n\tAnonPages         uint64                 `protobuf:\"varint,19,opt,name=anon_pages,json=anonPages,proto3\" json:\"anon_pages,omitempty\"`\n\tMapped            uint64                 `protobuf:\"varint,20,opt,name=mapped,proto3\" json:\"mapped,omitempty\"`\n\tShmem             uint64                 `protobuf:\"varint,21,opt,name=shmem,proto3\" json:\"shmem,omitempty\"`\n\tSlab              uint64                 `protobuf:\"varint,22,opt,name=slab,proto3\" json:\"slab,omitempty\"`\n\tSReclaimable      uint64                 `protobuf:\"varint,23,opt,name=s_reclaimable,json=sReclaimable,proto3\" json:\"s_reclaimable,omitempty\"`\n\tSUnreclaim        uint64                 `protobuf:\"varint,24,opt,name=s_unreclaim,json=sUnreclaim,proto3\" json:\"s_unreclaim,omitempty\"`\n\tKernelStack       uint64                 `protobuf:\"varint,25,opt,name=kernel_stack,json=kernelStack,proto3\" json:\"kernel_stack,omitempty\"`\n\tPageTables        uint64                 `protobuf:\"varint,26,opt,name=page_tables,json=pageTables,proto3\" json:\"page_tables,omitempty\"`\n\tNfSunstable       uint64                 `protobuf:\"varint,27,opt,name=nf_sunstable,json=nfSunstable,proto3\" json:\"nf_sunstable,omitempty\"`\n\tBounce            uint64                 `protobuf:\"varint,28,opt,name=bounce,proto3\" json:\"bounce,omitempty\"`\n\tWritebackTmp      uint64                 `protobuf:\"varint,29,opt,name=writeback_tmp,json=writebackTmp,proto3\" json:\"writeback_tmp,omitempty\"`\n\tCommitLimit       uint64                 `protobuf:\"varint,30,opt,name=commit_limit,json=commitLimit,proto3\" json:\"commit_limit,omitempty\"`\n\tCommittedAs       uint64                 `protobuf:\"varint,31,opt,name=committed_as,json=committedAs,proto3\" json:\"committed_as,omitempty\"`\n\tVmallocTotal      uint64                 `protobuf:\"varint,32,opt,name=vmalloc_total,json=vmallocTotal,proto3\" json:\"vmalloc_total,omitempty\"`\n\tVmallocUsed       uint64                 `protobuf:\"varint,33,opt,name=vmalloc_used,json=vmallocUsed,proto3\" json:\"vmalloc_used,omitempty\"`\n\tVmallocChunk      uint64                 `protobuf:\"varint,34,opt,name=vmalloc_chunk,json=vmallocChunk,proto3\" json:\"vmalloc_chunk,omitempty\"`\n\tHardwareCorrupted uint64                 `protobuf:\"varint,35,opt,name=hardware_corrupted,json=hardwareCorrupted,proto3\" json:\"hardware_corrupted,omitempty\"`\n\tAnonHugePages     uint64                 `protobuf:\"varint,36,opt,name=anon_huge_pages,json=anonHugePages,proto3\" json:\"anon_huge_pages,omitempty\"`\n\tShmemHugePages    uint64                 `protobuf:\"varint,37,opt,name=shmem_huge_pages,json=shmemHugePages,proto3\" json:\"shmem_huge_pages,omitempty\"`\n\tShmemPmdMapped    uint64                 `protobuf:\"varint,38,opt,name=shmem_pmd_mapped,json=shmemPmdMapped,proto3\" json:\"shmem_pmd_mapped,omitempty\"`\n\tCmaTotal          uint64                 `protobuf:\"varint,39,opt,name=cma_total,json=cmaTotal,proto3\" json:\"cma_total,omitempty\"`\n\tCmaFree           uint64                 `protobuf:\"varint,40,opt,name=cma_free,json=cmaFree,proto3\" json:\"cma_free,omitempty\"`\n\tHugePagesTotal    uint64                 `protobuf:\"varint,41,opt,name=huge_pages_total,json=hugePagesTotal,proto3\" json:\"huge_pages_total,omitempty\"`\n\tHugePagesFree     uint64                 `protobuf:\"varint,42,opt,name=huge_pages_free,json=hugePagesFree,proto3\" json:\"huge_pages_free,omitempty\"`\n\tHugePagesRsvd     uint64                 `protobuf:\"varint,43,opt,name=huge_pages_rsvd,json=hugePagesRsvd,proto3\" json:\"huge_pages_rsvd,omitempty\"`\n\tHugePagesSurp     uint64                 `protobuf:\"varint,44,opt,name=huge_pages_surp,json=hugePagesSurp,proto3\" json:\"huge_pages_surp,omitempty\"`\n\tHugepagesize      uint64                 `protobuf:\"varint,45,opt,name=hugepagesize,proto3\" json:\"hugepagesize,omitempty\"`\n\tDirectMap4K       uint64                 `protobuf:\"varint,46,opt,name=direct_map4k,json=directMap4k,proto3\" json:\"direct_map4k,omitempty\"`\n\tDirectMap2M       uint64                 `protobuf:\"varint,47,opt,name=direct_map2m,json=directMap2m,proto3\" json:\"direct_map2m,omitempty\"`\n\tDirectMap1G       uint64                 `protobuf:\"varint,48,opt,name=direct_map1g,json=directMap1g,proto3\" json:\"direct_map1g,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *MemorySpec) Reset() {\n\t*x = MemorySpec{}\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MemorySpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MemorySpec) ProtoMessage() {}\n\nfunc (x *MemorySpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_perf_perf_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MemorySpec.ProtoReflect.Descriptor instead.\nfunc (*MemorySpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_perf_perf_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *MemorySpec) GetMemTotal() uint64 {\n\tif x != nil {\n\t\treturn x.MemTotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetMemUsed() uint64 {\n\tif x != nil {\n\t\treturn x.MemUsed\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetMemAvailable() uint64 {\n\tif x != nil {\n\t\treturn x.MemAvailable\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetBuffers() uint64 {\n\tif x != nil {\n\t\treturn x.Buffers\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetCached() uint64 {\n\tif x != nil {\n\t\treturn x.Cached\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSwapCached() uint64 {\n\tif x != nil {\n\t\treturn x.SwapCached\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetActive() uint64 {\n\tif x != nil {\n\t\treturn x.Active\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetInactive() uint64 {\n\tif x != nil {\n\t\treturn x.Inactive\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetActiveAnon() uint64 {\n\tif x != nil {\n\t\treturn x.ActiveAnon\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetInactiveAnon() uint64 {\n\tif x != nil {\n\t\treturn x.InactiveAnon\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetActiveFile() uint64 {\n\tif x != nil {\n\t\treturn x.ActiveFile\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetInactiveFile() uint64 {\n\tif x != nil {\n\t\treturn x.InactiveFile\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetUnevictable() uint64 {\n\tif x != nil {\n\t\treturn x.Unevictable\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetMlocked() uint64 {\n\tif x != nil {\n\t\treturn x.Mlocked\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSwapTotal() uint64 {\n\tif x != nil {\n\t\treturn x.SwapTotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSwapFree() uint64 {\n\tif x != nil {\n\t\treturn x.SwapFree\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetDirty() uint64 {\n\tif x != nil {\n\t\treturn x.Dirty\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetWriteback() uint64 {\n\tif x != nil {\n\t\treturn x.Writeback\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetAnonPages() uint64 {\n\tif x != nil {\n\t\treturn x.AnonPages\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetMapped() uint64 {\n\tif x != nil {\n\t\treturn x.Mapped\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetShmem() uint64 {\n\tif x != nil {\n\t\treturn x.Shmem\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSlab() uint64 {\n\tif x != nil {\n\t\treturn x.Slab\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSReclaimable() uint64 {\n\tif x != nil {\n\t\treturn x.SReclaimable\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetSUnreclaim() uint64 {\n\tif x != nil {\n\t\treturn x.SUnreclaim\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetKernelStack() uint64 {\n\tif x != nil {\n\t\treturn x.KernelStack\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetPageTables() uint64 {\n\tif x != nil {\n\t\treturn x.PageTables\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetNfSunstable() uint64 {\n\tif x != nil {\n\t\treturn x.NfSunstable\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetBounce() uint64 {\n\tif x != nil {\n\t\treturn x.Bounce\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetWritebackTmp() uint64 {\n\tif x != nil {\n\t\treturn x.WritebackTmp\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetCommitLimit() uint64 {\n\tif x != nil {\n\t\treturn x.CommitLimit\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetCommittedAs() uint64 {\n\tif x != nil {\n\t\treturn x.CommittedAs\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetVmallocTotal() uint64 {\n\tif x != nil {\n\t\treturn x.VmallocTotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetVmallocUsed() uint64 {\n\tif x != nil {\n\t\treturn x.VmallocUsed\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetVmallocChunk() uint64 {\n\tif x != nil {\n\t\treturn x.VmallocChunk\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHardwareCorrupted() uint64 {\n\tif x != nil {\n\t\treturn x.HardwareCorrupted\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetAnonHugePages() uint64 {\n\tif x != nil {\n\t\treturn x.AnonHugePages\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetShmemHugePages() uint64 {\n\tif x != nil {\n\t\treturn x.ShmemHugePages\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetShmemPmdMapped() uint64 {\n\tif x != nil {\n\t\treturn x.ShmemPmdMapped\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetCmaTotal() uint64 {\n\tif x != nil {\n\t\treturn x.CmaTotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetCmaFree() uint64 {\n\tif x != nil {\n\t\treturn x.CmaFree\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHugePagesTotal() uint64 {\n\tif x != nil {\n\t\treturn x.HugePagesTotal\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHugePagesFree() uint64 {\n\tif x != nil {\n\t\treturn x.HugePagesFree\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHugePagesRsvd() uint64 {\n\tif x != nil {\n\t\treturn x.HugePagesRsvd\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHugePagesSurp() uint64 {\n\tif x != nil {\n\t\treturn x.HugePagesSurp\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetHugepagesize() uint64 {\n\tif x != nil {\n\t\treturn x.Hugepagesize\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetDirectMap4K() uint64 {\n\tif x != nil {\n\t\treturn x.DirectMap4K\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetDirectMap2M() uint64 {\n\tif x != nil {\n\t\treturn x.DirectMap2M\n\t}\n\treturn 0\n}\n\nfunc (x *MemorySpec) GetDirectMap1G() uint64 {\n\tif x != nil {\n\t\treturn x.DirectMap1G\n\t}\n\treturn 0\n}\n\nvar File_resource_definitions_perf_perf_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_perf_perf_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"$resource/definitions/perf/perf.proto\\x12\\x1ftalos.resource.definitions.perf\\\"\\xf5\\x02\\n\" +\n\t\"\\aCPUSpec\\x12:\\n\" +\n\t\"\\x03cpu\\x18\\x01 \\x03(\\v2(.talos.resource.definitions.perf.CPUStatR\\x03cpu\\x12E\\n\" +\n\t\"\\tcpu_total\\x18\\x02 \\x01(\\v2(.talos.resource.definitions.perf.CPUStatR\\bcpuTotal\\x12\\x1b\\n\" +\n\t\"\\tirq_total\\x18\\x03 \\x01(\\x04R\\birqTotal\\x12)\\n\" +\n\t\"\\x10context_switches\\x18\\x04 \\x01(\\x04R\\x0fcontextSwitches\\x12'\\n\" +\n\t\"\\x0fprocess_created\\x18\\x05 \\x01(\\x04R\\x0eprocessCreated\\x12'\\n\" +\n\t\"\\x0fprocess_running\\x18\\x06 \\x01(\\x04R\\x0eprocessRunning\\x12'\\n\" +\n\t\"\\x0fprocess_blocked\\x18\\a \\x01(\\x04R\\x0eprocessBlocked\\x12$\\n\" +\n\t\"\\x0esoft_irq_total\\x18\\b \\x01(\\x04R\\fsoftIrqTotal\\\"\\xed\\x01\\n\" +\n\t\"\\aCPUStat\\x12\\x12\\n\" +\n\t\"\\x04user\\x18\\x01 \\x01(\\x01R\\x04user\\x12\\x12\\n\" +\n\t\"\\x04nice\\x18\\x02 \\x01(\\x01R\\x04nice\\x12\\x16\\n\" +\n\t\"\\x06system\\x18\\x03 \\x01(\\x01R\\x06system\\x12\\x12\\n\" +\n\t\"\\x04idle\\x18\\x04 \\x01(\\x01R\\x04idle\\x12\\x16\\n\" +\n\t\"\\x06iowait\\x18\\x05 \\x01(\\x01R\\x06iowait\\x12\\x10\\n\" +\n\t\"\\x03irq\\x18\\x06 \\x01(\\x01R\\x03irq\\x12\\x19\\n\" +\n\t\"\\bsoft_irq\\x18\\a \\x01(\\x01R\\asoftIrq\\x12\\x14\\n\" +\n\t\"\\x05steal\\x18\\b \\x01(\\x01R\\x05steal\\x12\\x14\\n\" +\n\t\"\\x05guest\\x18\\t \\x01(\\x01R\\x05guest\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"guest_nice\\x18\\n\" +\n\t\" \\x01(\\x01R\\tguestNice\\\"\\xb8\\f\\n\" +\n\t\"\\n\" +\n\t\"MemorySpec\\x12\\x1b\\n\" +\n\t\"\\tmem_total\\x18\\x01 \\x01(\\x04R\\bmemTotal\\x12\\x19\\n\" +\n\t\"\\bmem_used\\x18\\x02 \\x01(\\x04R\\amemUsed\\x12#\\n\" +\n\t\"\\rmem_available\\x18\\x03 \\x01(\\x04R\\fmemAvailable\\x12\\x18\\n\" +\n\t\"\\abuffers\\x18\\x04 \\x01(\\x04R\\abuffers\\x12\\x16\\n\" +\n\t\"\\x06cached\\x18\\x05 \\x01(\\x04R\\x06cached\\x12\\x1f\\n\" +\n\t\"\\vswap_cached\\x18\\x06 \\x01(\\x04R\\n\" +\n\t\"swapCached\\x12\\x16\\n\" +\n\t\"\\x06active\\x18\\a \\x01(\\x04R\\x06active\\x12\\x1a\\n\" +\n\t\"\\binactive\\x18\\b \\x01(\\x04R\\binactive\\x12\\x1f\\n\" +\n\t\"\\vactive_anon\\x18\\t \\x01(\\x04R\\n\" +\n\t\"activeAnon\\x12#\\n\" +\n\t\"\\rinactive_anon\\x18\\n\" +\n\t\" \\x01(\\x04R\\finactiveAnon\\x12\\x1f\\n\" +\n\t\"\\vactive_file\\x18\\v \\x01(\\x04R\\n\" +\n\t\"activeFile\\x12#\\n\" +\n\t\"\\rinactive_file\\x18\\f \\x01(\\x04R\\finactiveFile\\x12 \\n\" +\n\t\"\\vunevictable\\x18\\r \\x01(\\x04R\\vunevictable\\x12\\x18\\n\" +\n\t\"\\amlocked\\x18\\x0e \\x01(\\x04R\\amlocked\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"swap_total\\x18\\x0f \\x01(\\x04R\\tswapTotal\\x12\\x1b\\n\" +\n\t\"\\tswap_free\\x18\\x10 \\x01(\\x04R\\bswapFree\\x12\\x14\\n\" +\n\t\"\\x05dirty\\x18\\x11 \\x01(\\x04R\\x05dirty\\x12\\x1c\\n\" +\n\t\"\\twriteback\\x18\\x12 \\x01(\\x04R\\twriteback\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"anon_pages\\x18\\x13 \\x01(\\x04R\\tanonPages\\x12\\x16\\n\" +\n\t\"\\x06mapped\\x18\\x14 \\x01(\\x04R\\x06mapped\\x12\\x14\\n\" +\n\t\"\\x05shmem\\x18\\x15 \\x01(\\x04R\\x05shmem\\x12\\x12\\n\" +\n\t\"\\x04slab\\x18\\x16 \\x01(\\x04R\\x04slab\\x12#\\n\" +\n\t\"\\rs_reclaimable\\x18\\x17 \\x01(\\x04R\\fsReclaimable\\x12\\x1f\\n\" +\n\t\"\\vs_unreclaim\\x18\\x18 \\x01(\\x04R\\n\" +\n\t\"sUnreclaim\\x12!\\n\" +\n\t\"\\fkernel_stack\\x18\\x19 \\x01(\\x04R\\vkernelStack\\x12\\x1f\\n\" +\n\t\"\\vpage_tables\\x18\\x1a \\x01(\\x04R\\n\" +\n\t\"pageTables\\x12!\\n\" +\n\t\"\\fnf_sunstable\\x18\\x1b \\x01(\\x04R\\vnfSunstable\\x12\\x16\\n\" +\n\t\"\\x06bounce\\x18\\x1c \\x01(\\x04R\\x06bounce\\x12#\\n\" +\n\t\"\\rwriteback_tmp\\x18\\x1d \\x01(\\x04R\\fwritebackTmp\\x12!\\n\" +\n\t\"\\fcommit_limit\\x18\\x1e \\x01(\\x04R\\vcommitLimit\\x12!\\n\" +\n\t\"\\fcommitted_as\\x18\\x1f \\x01(\\x04R\\vcommittedAs\\x12#\\n\" +\n\t\"\\rvmalloc_total\\x18  \\x01(\\x04R\\fvmallocTotal\\x12!\\n\" +\n\t\"\\fvmalloc_used\\x18! \\x01(\\x04R\\vvmallocUsed\\x12#\\n\" +\n\t\"\\rvmalloc_chunk\\x18\\\" \\x01(\\x04R\\fvmallocChunk\\x12-\\n\" +\n\t\"\\x12hardware_corrupted\\x18# \\x01(\\x04R\\x11hardwareCorrupted\\x12&\\n\" +\n\t\"\\x0fanon_huge_pages\\x18$ \\x01(\\x04R\\ranonHugePages\\x12(\\n\" +\n\t\"\\x10shmem_huge_pages\\x18% \\x01(\\x04R\\x0eshmemHugePages\\x12(\\n\" +\n\t\"\\x10shmem_pmd_mapped\\x18& \\x01(\\x04R\\x0eshmemPmdMapped\\x12\\x1b\\n\" +\n\t\"\\tcma_total\\x18' \\x01(\\x04R\\bcmaTotal\\x12\\x19\\n\" +\n\t\"\\bcma_free\\x18( \\x01(\\x04R\\acmaFree\\x12(\\n\" +\n\t\"\\x10huge_pages_total\\x18) \\x01(\\x04R\\x0ehugePagesTotal\\x12&\\n\" +\n\t\"\\x0fhuge_pages_free\\x18* \\x01(\\x04R\\rhugePagesFree\\x12&\\n\" +\n\t\"\\x0fhuge_pages_rsvd\\x18+ \\x01(\\x04R\\rhugePagesRsvd\\x12&\\n\" +\n\t\"\\x0fhuge_pages_surp\\x18, \\x01(\\x04R\\rhugePagesSurp\\x12\\\"\\n\" +\n\t\"\\fhugepagesize\\x18- \\x01(\\x04R\\fhugepagesize\\x12!\\n\" +\n\t\"\\fdirect_map4k\\x18. \\x01(\\x04R\\vdirectMap4k\\x12!\\n\" +\n\t\"\\fdirect_map2m\\x18/ \\x01(\\x04R\\vdirectMap2m\\x12!\\n\" +\n\t\"\\fdirect_map1g\\x180 \\x01(\\x04R\\vdirectMap1gBr\\n\" +\n\t\"'dev.talos.api.resource.definitions.perfZGgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/perfb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_perf_perf_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_perf_perf_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_perf_perf_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_perf_perf_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_perf_perf_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_perf_perf_proto_rawDesc), len(file_resource_definitions_perf_perf_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_perf_perf_proto_rawDescData\n}\n\nvar file_resource_definitions_perf_perf_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_resource_definitions_perf_perf_proto_goTypes = []any{\n\t(*CPUSpec)(nil),    // 0: talos.resource.definitions.perf.CPUSpec\n\t(*CPUStat)(nil),    // 1: talos.resource.definitions.perf.CPUStat\n\t(*MemorySpec)(nil), // 2: talos.resource.definitions.perf.MemorySpec\n}\nvar file_resource_definitions_perf_perf_proto_depIdxs = []int32{\n\t1, // 0: talos.resource.definitions.perf.CPUSpec.cpu:type_name -> talos.resource.definitions.perf.CPUStat\n\t1, // 1: talos.resource.definitions.perf.CPUSpec.cpu_total:type_name -> talos.resource.definitions.perf.CPUStat\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_perf_perf_proto_init() }\nfunc file_resource_definitions_perf_perf_proto_init() {\n\tif File_resource_definitions_perf_perf_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_perf_perf_proto_rawDesc), len(file_resource_definitions_perf_perf_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_perf_perf_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_perf_perf_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_perf_perf_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_perf_perf_proto = out.File\n\tfile_resource_definitions_perf_perf_proto_goTypes = nil\n\tfile_resource_definitions_perf_perf_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/perf/perf_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/perf/perf.proto\n\npackage perf\n\nimport (\n\tbinary \"encoding/binary\"\n\tfmt \"fmt\"\n\tio \"io\"\n\tmath \"math\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *CPUSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SoftIrqTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SoftIrqTotal))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.ProcessBlocked != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessBlocked))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.ProcessRunning != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessRunning))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.ProcessCreated != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ProcessCreated))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.ContextSwitches != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ContextSwitches))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.IrqTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.IrqTotal))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.CpuTotal != nil {\n\t\tsize, err := m.CpuTotal.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Cpu) > 0 {\n\t\tfor iNdEx := len(m.Cpu) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Cpu[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUStat) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CPUStat) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CPUStat) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.GuestNice != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.GuestNice))))\n\t\ti--\n\t\tdAtA[i] = 0x51\n\t}\n\tif m.Guest != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Guest))))\n\t\ti--\n\t\tdAtA[i] = 0x49\n\t}\n\tif m.Steal != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Steal))))\n\t\ti--\n\t\tdAtA[i] = 0x41\n\t}\n\tif m.SoftIrq != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.SoftIrq))))\n\t\ti--\n\t\tdAtA[i] = 0x39\n\t}\n\tif m.Irq != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Irq))))\n\t\ti--\n\t\tdAtA[i] = 0x31\n\t}\n\tif m.Iowait != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Iowait))))\n\t\ti--\n\t\tdAtA[i] = 0x29\n\t}\n\tif m.Idle != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Idle))))\n\t\ti--\n\t\tdAtA[i] = 0x21\n\t}\n\tif m.System != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.System))))\n\t\ti--\n\t\tdAtA[i] = 0x19\n\t}\n\tif m.Nice != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Nice))))\n\t\ti--\n\t\tdAtA[i] = 0x11\n\t}\n\tif m.User != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.User))))\n\t\ti--\n\t\tdAtA[i] = 0x9\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MemorySpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MemorySpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MemorySpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.DirectMap1G != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DirectMap1G))\n\t\ti--\n\t\tdAtA[i] = 0x3\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.DirectMap2M != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DirectMap2M))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xf8\n\t}\n\tif m.DirectMap4K != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.DirectMap4K))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xf0\n\t}\n\tif m.Hugepagesize != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Hugepagesize))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xe8\n\t}\n\tif m.HugePagesSurp != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HugePagesSurp))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xe0\n\t}\n\tif m.HugePagesRsvd != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HugePagesRsvd))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xd8\n\t}\n\tif m.HugePagesFree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HugePagesFree))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xd0\n\t}\n\tif m.HugePagesTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HugePagesTotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xc8\n\t}\n\tif m.CmaFree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CmaFree))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.CmaTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CmaTotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.ShmemPmdMapped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ShmemPmdMapped))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif m.ShmemHugePages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ShmemHugePages))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.AnonHugePages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AnonHugePages))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif m.HardwareCorrupted != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HardwareCorrupted))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif m.VmallocChunk != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.VmallocChunk))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif m.VmallocUsed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.VmallocUsed))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.VmallocTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.VmallocTotal))\n\t\ti--\n\t\tdAtA[i] = 0x2\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.CommittedAs != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CommittedAs))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xf8\n\t}\n\tif m.CommitLimit != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.CommitLimit))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xf0\n\t}\n\tif m.WritebackTmp != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.WritebackTmp))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe8\n\t}\n\tif m.Bounce != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Bounce))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xe0\n\t}\n\tif m.NfSunstable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.NfSunstable))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd8\n\t}\n\tif m.PageTables != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.PageTables))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xd0\n\t}\n\tif m.KernelStack != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.KernelStack))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc8\n\t}\n\tif m.SUnreclaim != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SUnreclaim))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xc0\n\t}\n\tif m.SReclaimable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SReclaimable))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb8\n\t}\n\tif m.Slab != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Slab))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xb0\n\t}\n\tif m.Shmem != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Shmem))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa8\n\t}\n\tif m.Mapped != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mapped))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0xa0\n\t}\n\tif m.AnonPages != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.AnonPages))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x98\n\t}\n\tif m.Writeback != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Writeback))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x90\n\t}\n\tif m.Dirty != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Dirty))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x88\n\t}\n\tif m.SwapFree != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SwapFree))\n\t\ti--\n\t\tdAtA[i] = 0x1\n\t\ti--\n\t\tdAtA[i] = 0x80\n\t}\n\tif m.SwapTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SwapTotal))\n\t\ti--\n\t\tdAtA[i] = 0x78\n\t}\n\tif m.Mlocked != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mlocked))\n\t\ti--\n\t\tdAtA[i] = 0x70\n\t}\n\tif m.Unevictable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Unevictable))\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif m.InactiveFile != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.InactiveFile))\n\t\ti--\n\t\tdAtA[i] = 0x60\n\t}\n\tif m.ActiveFile != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ActiveFile))\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif m.InactiveAnon != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.InactiveAnon))\n\t\ti--\n\t\tdAtA[i] = 0x50\n\t}\n\tif m.ActiveAnon != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ActiveAnon))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif m.Inactive != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Inactive))\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif m.Active != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Active))\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.SwapCached != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SwapCached))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.Cached != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Cached))\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Buffers != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Buffers))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.MemAvailable != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemAvailable))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.MemUsed != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemUsed))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.MemTotal != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.MemTotal))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CPUSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Cpu) > 0 {\n\t\tfor _, e := range m.Cpu {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.CpuTotal != nil {\n\t\tl = m.CpuTotal.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.IrqTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.IrqTotal))\n\t}\n\tif m.ContextSwitches != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ContextSwitches))\n\t}\n\tif m.ProcessCreated != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessCreated))\n\t}\n\tif m.ProcessRunning != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessRunning))\n\t}\n\tif m.ProcessBlocked != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ProcessBlocked))\n\t}\n\tif m.SoftIrqTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SoftIrqTotal))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUStat) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.User != 0 {\n\t\tn += 9\n\t}\n\tif m.Nice != 0 {\n\t\tn += 9\n\t}\n\tif m.System != 0 {\n\t\tn += 9\n\t}\n\tif m.Idle != 0 {\n\t\tn += 9\n\t}\n\tif m.Iowait != 0 {\n\t\tn += 9\n\t}\n\tif m.Irq != 0 {\n\t\tn += 9\n\t}\n\tif m.SoftIrq != 0 {\n\t\tn += 9\n\t}\n\tif m.Steal != 0 {\n\t\tn += 9\n\t}\n\tif m.Guest != 0 {\n\t\tn += 9\n\t}\n\tif m.GuestNice != 0 {\n\t\tn += 9\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MemorySpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.MemTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemTotal))\n\t}\n\tif m.MemUsed != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemUsed))\n\t}\n\tif m.MemAvailable != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.MemAvailable))\n\t}\n\tif m.Buffers != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Buffers))\n\t}\n\tif m.Cached != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Cached))\n\t}\n\tif m.SwapCached != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SwapCached))\n\t}\n\tif m.Active != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Active))\n\t}\n\tif m.Inactive != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Inactive))\n\t}\n\tif m.ActiveAnon != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ActiveAnon))\n\t}\n\tif m.InactiveAnon != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.InactiveAnon))\n\t}\n\tif m.ActiveFile != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ActiveFile))\n\t}\n\tif m.InactiveFile != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.InactiveFile))\n\t}\n\tif m.Unevictable != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Unevictable))\n\t}\n\tif m.Mlocked != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mlocked))\n\t}\n\tif m.SwapTotal != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SwapTotal))\n\t}\n\tif m.SwapFree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.SwapFree))\n\t}\n\tif m.Dirty != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Dirty))\n\t}\n\tif m.Writeback != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Writeback))\n\t}\n\tif m.AnonPages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AnonPages))\n\t}\n\tif m.Mapped != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Mapped))\n\t}\n\tif m.Shmem != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Shmem))\n\t}\n\tif m.Slab != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Slab))\n\t}\n\tif m.SReclaimable != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.SReclaimable))\n\t}\n\tif m.SUnreclaim != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.SUnreclaim))\n\t}\n\tif m.KernelStack != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.KernelStack))\n\t}\n\tif m.PageTables != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.PageTables))\n\t}\n\tif m.NfSunstable != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.NfSunstable))\n\t}\n\tif m.Bounce != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Bounce))\n\t}\n\tif m.WritebackTmp != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.WritebackTmp))\n\t}\n\tif m.CommitLimit != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CommitLimit))\n\t}\n\tif m.CommittedAs != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CommittedAs))\n\t}\n\tif m.VmallocTotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.VmallocTotal))\n\t}\n\tif m.VmallocUsed != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.VmallocUsed))\n\t}\n\tif m.VmallocChunk != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.VmallocChunk))\n\t}\n\tif m.HardwareCorrupted != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.HardwareCorrupted))\n\t}\n\tif m.AnonHugePages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.AnonHugePages))\n\t}\n\tif m.ShmemHugePages != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.ShmemHugePages))\n\t}\n\tif m.ShmemPmdMapped != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.ShmemPmdMapped))\n\t}\n\tif m.CmaTotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CmaTotal))\n\t}\n\tif m.CmaFree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.CmaFree))\n\t}\n\tif m.HugePagesTotal != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.HugePagesTotal))\n\t}\n\tif m.HugePagesFree != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.HugePagesFree))\n\t}\n\tif m.HugePagesRsvd != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.HugePagesRsvd))\n\t}\n\tif m.HugePagesSurp != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.HugePagesSurp))\n\t}\n\tif m.Hugepagesize != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.Hugepagesize))\n\t}\n\tif m.DirectMap4K != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.DirectMap4K))\n\t}\n\tif m.DirectMap2M != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.DirectMap2M))\n\t}\n\tif m.DirectMap1G != 0 {\n\t\tn += 2 + protohelpers.SizeOfVarint(uint64(m.DirectMap1G))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CPUSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cpu\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Cpu = append(m.Cpu, &CPUStat{})\n\t\t\tif err := m.Cpu[len(m.Cpu)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpuTotal\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.CpuTotal == nil {\n\t\t\t\tm.CpuTotal = &CPUStat{}\n\t\t\t}\n\t\t\tif err := m.CpuTotal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IrqTotal\", wireType)\n\t\t\t}\n\t\t\tm.IrqTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.IrqTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ContextSwitches\", wireType)\n\t\t\t}\n\t\t\tm.ContextSwitches = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ContextSwitches |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessCreated\", wireType)\n\t\t\t}\n\t\t\tm.ProcessCreated = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessCreated |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessRunning\", wireType)\n\t\t\t}\n\t\t\tm.ProcessRunning = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessRunning |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProcessBlocked\", wireType)\n\t\t\t}\n\t\t\tm.ProcessBlocked = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ProcessBlocked |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SoftIrqTotal\", wireType)\n\t\t\t}\n\t\t\tm.SoftIrqTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SoftIrqTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CPUStat) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CPUStat: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CPUStat: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field User\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.User = float64(math.Float64frombits(v))\n\t\tcase 2:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Nice\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Nice = float64(math.Float64frombits(v))\n\t\tcase 3:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field System\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.System = float64(math.Float64frombits(v))\n\t\tcase 4:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Idle\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Idle = float64(math.Float64frombits(v))\n\t\tcase 5:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Iowait\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Iowait = float64(math.Float64frombits(v))\n\t\tcase 6:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Irq\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Irq = float64(math.Float64frombits(v))\n\t\tcase 7:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SoftIrq\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.SoftIrq = float64(math.Float64frombits(v))\n\t\tcase 8:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Steal\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Steal = float64(math.Float64frombits(v))\n\t\tcase 9:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Guest\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Guest = float64(math.Float64frombits(v))\n\t\tcase 10:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GuestNice\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.GuestNice = float64(math.Float64frombits(v))\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MemorySpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MemorySpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MemorySpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemTotal\", wireType)\n\t\t\t}\n\t\t\tm.MemTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemUsed\", wireType)\n\t\t\t}\n\t\t\tm.MemUsed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemUsed |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MemAvailable\", wireType)\n\t\t\t}\n\t\t\tm.MemAvailable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.MemAvailable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Buffers\", wireType)\n\t\t\t}\n\t\t\tm.Buffers = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Buffers |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cached\", wireType)\n\t\t\t}\n\t\t\tm.Cached = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Cached |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SwapCached\", wireType)\n\t\t\t}\n\t\t\tm.SwapCached = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SwapCached |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Active\", wireType)\n\t\t\t}\n\t\t\tm.Active = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Active |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Inactive\", wireType)\n\t\t\t}\n\t\t\tm.Inactive = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Inactive |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActiveAnon\", wireType)\n\t\t\t}\n\t\t\tm.ActiveAnon = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ActiveAnon |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InactiveAnon\", wireType)\n\t\t\t}\n\t\t\tm.InactiveAnon = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.InactiveAnon |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ActiveFile\", wireType)\n\t\t\t}\n\t\t\tm.ActiveFile = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ActiveFile |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 12:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InactiveFile\", wireType)\n\t\t\t}\n\t\t\tm.InactiveFile = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.InactiveFile |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unevictable\", wireType)\n\t\t\t}\n\t\t\tm.Unevictable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Unevictable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 14:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mlocked\", wireType)\n\t\t\t}\n\t\t\tm.Mlocked = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mlocked |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 15:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SwapTotal\", wireType)\n\t\t\t}\n\t\t\tm.SwapTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SwapTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 16:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SwapFree\", wireType)\n\t\t\t}\n\t\t\tm.SwapFree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SwapFree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 17:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dirty\", wireType)\n\t\t\t}\n\t\t\tm.Dirty = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Dirty |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 18:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Writeback\", wireType)\n\t\t\t}\n\t\t\tm.Writeback = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Writeback |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 19:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AnonPages\", wireType)\n\t\t\t}\n\t\t\tm.AnonPages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AnonPages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 20:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mapped\", wireType)\n\t\t\t}\n\t\t\tm.Mapped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mapped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 21:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Shmem\", wireType)\n\t\t\t}\n\t\t\tm.Shmem = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Shmem |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 22:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Slab\", wireType)\n\t\t\t}\n\t\t\tm.Slab = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Slab |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 23:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SReclaimable\", wireType)\n\t\t\t}\n\t\t\tm.SReclaimable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SReclaimable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 24:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SUnreclaim\", wireType)\n\t\t\t}\n\t\t\tm.SUnreclaim = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SUnreclaim |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 25:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KernelStack\", wireType)\n\t\t\t}\n\t\t\tm.KernelStack = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.KernelStack |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 26:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PageTables\", wireType)\n\t\t\t}\n\t\t\tm.PageTables = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.PageTables |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 27:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NfSunstable\", wireType)\n\t\t\t}\n\t\t\tm.NfSunstable = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.NfSunstable |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 28:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Bounce\", wireType)\n\t\t\t}\n\t\t\tm.Bounce = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Bounce |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 29:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field WritebackTmp\", wireType)\n\t\t\t}\n\t\t\tm.WritebackTmp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.WritebackTmp |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 30:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CommitLimit\", wireType)\n\t\t\t}\n\t\t\tm.CommitLimit = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CommitLimit |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 31:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CommittedAs\", wireType)\n\t\t\t}\n\t\t\tm.CommittedAs = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CommittedAs |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 32:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VmallocTotal\", wireType)\n\t\t\t}\n\t\t\tm.VmallocTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.VmallocTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 33:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VmallocUsed\", wireType)\n\t\t\t}\n\t\t\tm.VmallocUsed = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.VmallocUsed |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 34:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field VmallocChunk\", wireType)\n\t\t\t}\n\t\t\tm.VmallocChunk = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.VmallocChunk |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 35:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HardwareCorrupted\", wireType)\n\t\t\t}\n\t\t\tm.HardwareCorrupted = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HardwareCorrupted |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 36:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AnonHugePages\", wireType)\n\t\t\t}\n\t\t\tm.AnonHugePages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.AnonHugePages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 37:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ShmemHugePages\", wireType)\n\t\t\t}\n\t\t\tm.ShmemHugePages = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ShmemHugePages |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 38:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ShmemPmdMapped\", wireType)\n\t\t\t}\n\t\t\tm.ShmemPmdMapped = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ShmemPmdMapped |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 39:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CmaTotal\", wireType)\n\t\t\t}\n\t\t\tm.CmaTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CmaTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 40:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CmaFree\", wireType)\n\t\t\t}\n\t\t\tm.CmaFree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.CmaFree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 41:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HugePagesTotal\", wireType)\n\t\t\t}\n\t\t\tm.HugePagesTotal = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HugePagesTotal |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 42:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HugePagesFree\", wireType)\n\t\t\t}\n\t\t\tm.HugePagesFree = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HugePagesFree |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 43:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HugePagesRsvd\", wireType)\n\t\t\t}\n\t\t\tm.HugePagesRsvd = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HugePagesRsvd |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 44:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HugePagesSurp\", wireType)\n\t\t\t}\n\t\t\tm.HugePagesSurp = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HugePagesSurp |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 45:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hugepagesize\", wireType)\n\t\t\t}\n\t\t\tm.Hugepagesize = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Hugepagesize |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 46:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DirectMap4K\", wireType)\n\t\t\t}\n\t\t\tm.DirectMap4K = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DirectMap4K |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 47:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DirectMap2M\", wireType)\n\t\t\t}\n\t\t\tm.DirectMap2M = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DirectMap2M |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 48:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DirectMap1G\", wireType)\n\t\t\t}\n\t\t\tm.DirectMap1G = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.DirectMap1G |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/proto/proto.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/proto/proto.proto\n\npackage proto\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// LinuxIDMapping specifies UID/GID mappings.\ntype LinuxIDMapping struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tContainerId   uint32                 `protobuf:\"varint,1,opt,name=container_id,json=containerId,proto3\" json:\"container_id,omitempty\"`\n\tHostId        uint32                 `protobuf:\"varint,2,opt,name=host_id,json=hostId,proto3\" json:\"host_id,omitempty\"`\n\tSize          uint32                 `protobuf:\"varint,3,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LinuxIDMapping) Reset() {\n\t*x = LinuxIDMapping{}\n\tmi := &file_resource_definitions_proto_proto_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LinuxIDMapping) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LinuxIDMapping) ProtoMessage() {}\n\nfunc (x *LinuxIDMapping) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_proto_proto_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LinuxIDMapping.ProtoReflect.Descriptor instead.\nfunc (*LinuxIDMapping) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_proto_proto_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *LinuxIDMapping) GetContainerId() uint32 {\n\tif x != nil {\n\t\treturn x.ContainerId\n\t}\n\treturn 0\n}\n\nfunc (x *LinuxIDMapping) GetHostId() uint32 {\n\tif x != nil {\n\t\treturn x.HostId\n\t}\n\treturn 0\n}\n\nfunc (x *LinuxIDMapping) GetSize() uint32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\n// Mount specifies a mount for a container.\ntype Mount struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDestination   string                 `protobuf:\"bytes,1,opt,name=destination,proto3\" json:\"destination,omitempty\"`\n\tType          string                 `protobuf:\"bytes,2,opt,name=type,proto3\" json:\"type,omitempty\"`\n\tSource        string                 `protobuf:\"bytes,3,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tOptions       []string               `protobuf:\"bytes,4,rep,name=options,proto3\" json:\"options,omitempty\"`\n\tUidMappings   []*LinuxIDMapping      `protobuf:\"bytes,5,rep,name=uid_mappings,json=uidMappings,proto3\" json:\"uid_mappings,omitempty\"`\n\tGidMappings   []*LinuxIDMapping      `protobuf:\"bytes,6,rep,name=gid_mappings,json=gidMappings,proto3\" json:\"gid_mappings,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Mount) Reset() {\n\t*x = Mount{}\n\tmi := &file_resource_definitions_proto_proto_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Mount) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Mount) ProtoMessage() {}\n\nfunc (x *Mount) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_proto_proto_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Mount.ProtoReflect.Descriptor instead.\nfunc (*Mount) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_proto_proto_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Mount) GetDestination() string {\n\tif x != nil {\n\t\treturn x.Destination\n\t}\n\treturn \"\"\n}\n\nfunc (x *Mount) GetType() string {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn \"\"\n}\n\nfunc (x *Mount) GetSource() string {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn \"\"\n}\n\nfunc (x *Mount) GetOptions() []string {\n\tif x != nil {\n\t\treturn x.Options\n\t}\n\treturn nil\n}\n\nfunc (x *Mount) GetUidMappings() []*LinuxIDMapping {\n\tif x != nil {\n\t\treturn x.UidMappings\n\t}\n\treturn nil\n}\n\nfunc (x *Mount) GetGidMappings() []*LinuxIDMapping {\n\tif x != nil {\n\t\treturn x.GidMappings\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_proto_proto_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_proto_proto_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"&resource/definitions/proto/proto.proto\\x12 talos.resource.definitions.proto\\\"`\\n\" +\n\t\"\\x0eLinuxIDMapping\\x12!\\n\" +\n\t\"\\fcontainer_id\\x18\\x01 \\x01(\\rR\\vcontainerId\\x12\\x17\\n\" +\n\t\"\\ahost_id\\x18\\x02 \\x01(\\rR\\x06hostId\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x03 \\x01(\\rR\\x04size\\\"\\x99\\x02\\n\" +\n\t\"\\x05Mount\\x12 \\n\" +\n\t\"\\vdestination\\x18\\x01 \\x01(\\tR\\vdestination\\x12\\x12\\n\" +\n\t\"\\x04type\\x18\\x02 \\x01(\\tR\\x04type\\x12\\x16\\n\" +\n\t\"\\x06source\\x18\\x03 \\x01(\\tR\\x06source\\x12\\x18\\n\" +\n\t\"\\aoptions\\x18\\x04 \\x03(\\tR\\aoptions\\x12S\\n\" +\n\t\"\\fuid_mappings\\x18\\x05 \\x03(\\v20.talos.resource.definitions.proto.LinuxIDMappingR\\vuidMappings\\x12S\\n\" +\n\t\"\\fgid_mappings\\x18\\x06 \\x03(\\v20.talos.resource.definitions.proto.LinuxIDMappingR\\vgidMappingsBt\\n\" +\n\t\"(dev.talos.api.resource.definitions.protoZHgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/protob\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_proto_proto_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_proto_proto_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_proto_proto_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_proto_proto_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_proto_proto_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_proto_proto_proto_rawDesc), len(file_resource_definitions_proto_proto_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_proto_proto_proto_rawDescData\n}\n\nvar file_resource_definitions_proto_proto_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_resource_definitions_proto_proto_proto_goTypes = []any{\n\t(*LinuxIDMapping)(nil), // 0: talos.resource.definitions.proto.LinuxIDMapping\n\t(*Mount)(nil),          // 1: talos.resource.definitions.proto.Mount\n}\nvar file_resource_definitions_proto_proto_proto_depIdxs = []int32{\n\t0, // 0: talos.resource.definitions.proto.Mount.uid_mappings:type_name -> talos.resource.definitions.proto.LinuxIDMapping\n\t0, // 1: talos.resource.definitions.proto.Mount.gid_mappings:type_name -> talos.resource.definitions.proto.LinuxIDMapping\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_proto_proto_proto_init() }\nfunc file_resource_definitions_proto_proto_proto_init() {\n\tif File_resource_definitions_proto_proto_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_proto_proto_proto_rawDesc), len(file_resource_definitions_proto_proto_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_proto_proto_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_proto_proto_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_proto_proto_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_proto_proto_proto = out.File\n\tfile_resource_definitions_proto_proto_proto_goTypes = nil\n\tfile_resource_definitions_proto_proto_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/proto/proto_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/proto/proto.proto\n\npackage proto\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *LinuxIDMapping) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LinuxIDMapping) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LinuxIDMapping) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.HostId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.HostId))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.ContainerId != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ContainerId))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Mount) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Mount) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Mount) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.GidMappings) > 0 {\n\t\tfor iNdEx := len(m.GidMappings) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.GidMappings[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif len(m.UidMappings) > 0 {\n\t\tfor iNdEx := len(m.UidMappings) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.UidMappings[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.Options) > 0 {\n\t\tfor iNdEx := len(m.Options) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Options[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Options[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Options[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.Source) > 0 {\n\t\ti -= len(m.Source)\n\t\tcopy(dAtA[i:], m.Source)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Source)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Type) > 0 {\n\t\ti -= len(m.Type)\n\t\tcopy(dAtA[i:], m.Type)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Type)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Destination) > 0 {\n\t\ti -= len(m.Destination)\n\t\tcopy(dAtA[i:], m.Destination)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Destination)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LinuxIDMapping) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.ContainerId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ContainerId))\n\t}\n\tif m.HostId != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.HostId))\n\t}\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Mount) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Destination)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Type)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Source)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Options) > 0 {\n\t\tfor _, s := range m.Options {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.UidMappings) > 0 {\n\t\tfor _, e := range m.UidMappings {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.GidMappings) > 0 {\n\t\tfor _, e := range m.GidMappings {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LinuxIDMapping) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LinuxIDMapping: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LinuxIDMapping: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ContainerId\", wireType)\n\t\t\t}\n\t\t\tm.ContainerId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ContainerId |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field HostId\", wireType)\n\t\t\t}\n\t\t\tm.HostId = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.HostId |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint32(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Mount) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Mount: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Mount: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Destination\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Destination = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Type = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Source = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Options\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Options = append(m.Options, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UidMappings\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UidMappings = append(m.UidMappings, &LinuxIDMapping{})\n\t\t\tif err := m.UidMappings[len(m.UidMappings)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GidMappings\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.GidMappings = append(m.GidMappings, &LinuxIDMapping{})\n\t\t\tif err := m.GidMappings[len(m.GidMappings)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/runtime/runtime.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/runtime/runtime.proto\n\npackage runtime\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// APIServiceConfigSpec describes configuration for Talos API service (apid).\ntype APIServiceConfigSpec struct {\n\tstate                   protoimpl.MessageState `protogen:\"open.v1\"`\n\tListenAddress           string                 `protobuf:\"bytes,1,opt,name=listen_address,json=listenAddress,proto3\" json:\"listen_address,omitempty\"`\n\tNodeRoutingDisabled     bool                   `protobuf:\"varint,2,opt,name=node_routing_disabled,json=nodeRoutingDisabled,proto3\" json:\"node_routing_disabled,omitempty\"`\n\tReadonlyRoleMode        bool                   `protobuf:\"varint,3,opt,name=readonly_role_mode,json=readonlyRoleMode,proto3\" json:\"readonly_role_mode,omitempty\"`\n\tSkipVerifyingClientCert bool                   `protobuf:\"varint,4,opt,name=skip_verifying_client_cert,json=skipVerifyingClientCert,proto3\" json:\"skip_verifying_client_cert,omitempty\"`\n\tunknownFields           protoimpl.UnknownFields\n\tsizeCache               protoimpl.SizeCache\n}\n\nfunc (x *APIServiceConfigSpec) Reset() {\n\t*x = APIServiceConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *APIServiceConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*APIServiceConfigSpec) ProtoMessage() {}\n\nfunc (x *APIServiceConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use APIServiceConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*APIServiceConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *APIServiceConfigSpec) GetListenAddress() string {\n\tif x != nil {\n\t\treturn x.ListenAddress\n\t}\n\treturn \"\"\n}\n\nfunc (x *APIServiceConfigSpec) GetNodeRoutingDisabled() bool {\n\tif x != nil {\n\t\treturn x.NodeRoutingDisabled\n\t}\n\treturn false\n}\n\nfunc (x *APIServiceConfigSpec) GetReadonlyRoleMode() bool {\n\tif x != nil {\n\t\treturn x.ReadonlyRoleMode\n\t}\n\treturn false\n}\n\nfunc (x *APIServiceConfigSpec) GetSkipVerifyingClientCert() bool {\n\tif x != nil {\n\t\treturn x.SkipVerifyingClientCert\n\t}\n\treturn false\n}\n\n// BootedEntrySpec describes the booted entry resource properties.\ntype BootedEntrySpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tBootedEntry   string                 `protobuf:\"bytes,1,opt,name=booted_entry,json=bootedEntry,proto3\" json:\"booted_entry,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BootedEntrySpec) Reset() {\n\t*x = BootedEntrySpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BootedEntrySpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BootedEntrySpec) ProtoMessage() {}\n\nfunc (x *BootedEntrySpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BootedEntrySpec.ProtoReflect.Descriptor instead.\nfunc (*BootedEntrySpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *BootedEntrySpec) GetBootedEntry() string {\n\tif x != nil {\n\t\treturn x.BootedEntry\n\t}\n\treturn \"\"\n}\n\n// DevicesStatusSpec is the spec for devices status.\ntype DevicesStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady         bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DevicesStatusSpec) Reset() {\n\t*x = DevicesStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DevicesStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DevicesStatusSpec) ProtoMessage() {}\n\nfunc (x *DevicesStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DevicesStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*DevicesStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *DevicesStatusSpec) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\n// DiagnosticSpec is the spec for devices status.\ntype DiagnosticSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessage       string                 `protobuf:\"bytes,1,opt,name=message,proto3\" json:\"message,omitempty\"`\n\tDetails       []string               `protobuf:\"bytes,2,rep,name=details,proto3\" json:\"details,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DiagnosticSpec) Reset() {\n\t*x = DiagnosticSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DiagnosticSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DiagnosticSpec) ProtoMessage() {}\n\nfunc (x *DiagnosticSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DiagnosticSpec.ProtoReflect.Descriptor instead.\nfunc (*DiagnosticSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *DiagnosticSpec) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\nfunc (x *DiagnosticSpec) GetDetails() []string {\n\tif x != nil {\n\t\treturn x.Details\n\t}\n\treturn nil\n}\n\n// EnvironmentSpec describes the specification of Environment resource.\ntype EnvironmentSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tVariables     []string               `protobuf:\"bytes,1,rep,name=variables,proto3\" json:\"variables,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EnvironmentSpec) Reset() {\n\t*x = EnvironmentSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EnvironmentSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EnvironmentSpec) ProtoMessage() {}\n\nfunc (x *EnvironmentSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EnvironmentSpec.ProtoReflect.Descriptor instead.\nfunc (*EnvironmentSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *EnvironmentSpec) GetVariables() []string {\n\tif x != nil {\n\t\treturn x.Variables\n\t}\n\treturn nil\n}\n\n// EventSinkConfigSpec describes configuration of Talos event log streaming.\ntype EventSinkConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tEndpoint      string                 `protobuf:\"bytes,1,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EventSinkConfigSpec) Reset() {\n\t*x = EventSinkConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EventSinkConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EventSinkConfigSpec) ProtoMessage() {}\n\nfunc (x *EventSinkConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EventSinkConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*EventSinkConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *EventSinkConfigSpec) GetEndpoint() string {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn \"\"\n}\n\n// ExtensionServiceConfigFile describes extensions service config files.\ntype ExtensionServiceConfigFile struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tContent       string                 `protobuf:\"bytes,1,opt,name=content,proto3\" json:\"content,omitempty\"`\n\tMountPath     string                 `protobuf:\"bytes,2,opt,name=mount_path,json=mountPath,proto3\" json:\"mount_path,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExtensionServiceConfigFile) Reset() {\n\t*x = ExtensionServiceConfigFile{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtensionServiceConfigFile) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtensionServiceConfigFile) ProtoMessage() {}\n\nfunc (x *ExtensionServiceConfigFile) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtensionServiceConfigFile.ProtoReflect.Descriptor instead.\nfunc (*ExtensionServiceConfigFile) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ExtensionServiceConfigFile) GetContent() string {\n\tif x != nil {\n\t\treturn x.Content\n\t}\n\treturn \"\"\n}\n\nfunc (x *ExtensionServiceConfigFile) GetMountPath() string {\n\tif x != nil {\n\t\treturn x.MountPath\n\t}\n\treturn \"\"\n}\n\n// ExtensionServiceConfigSpec describes status of rendered extensions service config files.\ntype ExtensionServiceConfigSpec struct {\n\tstate         protoimpl.MessageState        `protogen:\"open.v1\"`\n\tFiles         []*ExtensionServiceConfigFile `protobuf:\"bytes,1,rep,name=files,proto3\" json:\"files,omitempty\"`\n\tEnvironment   []string                      `protobuf:\"bytes,2,rep,name=environment,proto3\" json:\"environment,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExtensionServiceConfigSpec) Reset() {\n\t*x = ExtensionServiceConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtensionServiceConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtensionServiceConfigSpec) ProtoMessage() {}\n\nfunc (x *ExtensionServiceConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtensionServiceConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ExtensionServiceConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *ExtensionServiceConfigSpec) GetFiles() []*ExtensionServiceConfigFile {\n\tif x != nil {\n\t\treturn x.Files\n\t}\n\treturn nil\n}\n\nfunc (x *ExtensionServiceConfigSpec) GetEnvironment() []string {\n\tif x != nil {\n\t\treturn x.Environment\n\t}\n\treturn nil\n}\n\n// ExtensionServiceConfigStatusSpec describes status of rendered extensions service config files.\ntype ExtensionServiceConfigStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSpecVersion   string                 `protobuf:\"bytes,1,opt,name=spec_version,json=specVersion,proto3\" json:\"spec_version,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ExtensionServiceConfigStatusSpec) Reset() {\n\t*x = ExtensionServiceConfigStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ExtensionServiceConfigStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ExtensionServiceConfigStatusSpec) ProtoMessage() {}\n\nfunc (x *ExtensionServiceConfigStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ExtensionServiceConfigStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*ExtensionServiceConfigStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *ExtensionServiceConfigStatusSpec) GetSpecVersion() string {\n\tif x != nil {\n\t\treturn x.SpecVersion\n\t}\n\treturn \"\"\n}\n\n// KernelCmdlineSpec presents kernel command line (contents of /proc/cmdline).\ntype KernelCmdlineSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCmdline       string                 `protobuf:\"bytes,1,opt,name=cmdline,proto3\" json:\"cmdline,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KernelCmdlineSpec) Reset() {\n\t*x = KernelCmdlineSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KernelCmdlineSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KernelCmdlineSpec) ProtoMessage() {}\n\nfunc (x *KernelCmdlineSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KernelCmdlineSpec.ProtoReflect.Descriptor instead.\nfunc (*KernelCmdlineSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *KernelCmdlineSpec) GetCmdline() string {\n\tif x != nil {\n\t\treturn x.Cmdline\n\t}\n\treturn \"\"\n}\n\n// KernelModuleSpecSpec describes Linux kernel module to load.\ntype KernelModuleSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tParameters    []string               `protobuf:\"bytes,2,rep,name=parameters,proto3\" json:\"parameters,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KernelModuleSpecSpec) Reset() {\n\t*x = KernelModuleSpecSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KernelModuleSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KernelModuleSpecSpec) ProtoMessage() {}\n\nfunc (x *KernelModuleSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KernelModuleSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*KernelModuleSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *KernelModuleSpecSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *KernelModuleSpecSpec) GetParameters() []string {\n\tif x != nil {\n\t\treturn x.Parameters\n\t}\n\treturn nil\n}\n\n// KernelParamSpecSpec describes status of the defined sysctls.\ntype KernelParamSpecSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tValue         string                 `protobuf:\"bytes,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tIgnoreErrors  bool                   `protobuf:\"varint,2,opt,name=ignore_errors,json=ignoreErrors,proto3\" json:\"ignore_errors,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KernelParamSpecSpec) Reset() {\n\t*x = KernelParamSpecSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KernelParamSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KernelParamSpecSpec) ProtoMessage() {}\n\nfunc (x *KernelParamSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KernelParamSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*KernelParamSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *KernelParamSpecSpec) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *KernelParamSpecSpec) GetIgnoreErrors() bool {\n\tif x != nil {\n\t\treturn x.IgnoreErrors\n\t}\n\treturn false\n}\n\n// KernelParamStatusSpec describes status of the defined sysctls.\ntype KernelParamStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCurrent       string                 `protobuf:\"bytes,1,opt,name=current,proto3\" json:\"current,omitempty\"`\n\tDefault       string                 `protobuf:\"bytes,2,opt,name=default,proto3\" json:\"default,omitempty\"`\n\tUnsupported   bool                   `protobuf:\"varint,3,opt,name=unsupported,proto3\" json:\"unsupported,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KernelParamStatusSpec) Reset() {\n\t*x = KernelParamStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[12]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KernelParamStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KernelParamStatusSpec) ProtoMessage() {}\n\nfunc (x *KernelParamStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[12]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KernelParamStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*KernelParamStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *KernelParamStatusSpec) GetCurrent() string {\n\tif x != nil {\n\t\treturn x.Current\n\t}\n\treturn \"\"\n}\n\nfunc (x *KernelParamStatusSpec) GetDefault() string {\n\tif x != nil {\n\t\treturn x.Default\n\t}\n\treturn \"\"\n}\n\nfunc (x *KernelParamStatusSpec) GetUnsupported() bool {\n\tif x != nil {\n\t\treturn x.Unsupported\n\t}\n\treturn false\n}\n\n// KmsgLogConfigSpec describes configuration for kmsg log streaming.\ntype KmsgLogConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDestinations  []*common.URL          `protobuf:\"bytes,1,rep,name=destinations,proto3\" json:\"destinations,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *KmsgLogConfigSpec) Reset() {\n\t*x = KmsgLogConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[13]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KmsgLogConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KmsgLogConfigSpec) ProtoMessage() {}\n\nfunc (x *KmsgLogConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[13]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KmsgLogConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*KmsgLogConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{13}\n}\n\nfunc (x *KmsgLogConfigSpec) GetDestinations() []*common.URL {\n\tif x != nil {\n\t\treturn x.Destinations\n\t}\n\treturn nil\n}\n\n// LoadedKernelModuleSpec describes Linux kernel module to load.\ntype LoadedKernelModuleSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tSize           int64                  `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\tReferenceCount int64                  `protobuf:\"varint,2,opt,name=reference_count,json=referenceCount,proto3\" json:\"reference_count,omitempty\"`\n\tDependencies   []string               `protobuf:\"bytes,3,rep,name=dependencies,proto3\" json:\"dependencies,omitempty\"`\n\tState          string                 `protobuf:\"bytes,4,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tAddress        string                 `protobuf:\"bytes,5,opt,name=address,proto3\" json:\"address,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *LoadedKernelModuleSpec) Reset() {\n\t*x = LoadedKernelModuleSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[14]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LoadedKernelModuleSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LoadedKernelModuleSpec) ProtoMessage() {}\n\nfunc (x *LoadedKernelModuleSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[14]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use LoadedKernelModuleSpec.ProtoReflect.Descriptor instead.\nfunc (*LoadedKernelModuleSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{14}\n}\n\nfunc (x *LoadedKernelModuleSpec) GetSize() int64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *LoadedKernelModuleSpec) GetReferenceCount() int64 {\n\tif x != nil {\n\t\treturn x.ReferenceCount\n\t}\n\treturn 0\n}\n\nfunc (x *LoadedKernelModuleSpec) GetDependencies() []string {\n\tif x != nil {\n\t\treturn x.Dependencies\n\t}\n\treturn nil\n}\n\nfunc (x *LoadedKernelModuleSpec) GetState() string {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn \"\"\n}\n\nfunc (x *LoadedKernelModuleSpec) GetAddress() string {\n\tif x != nil {\n\t\treturn x.Address\n\t}\n\treturn \"\"\n}\n\n// MachineStatusSpec describes status of the defined sysctls.\ntype MachineStatusSpec struct {\n\tstate         protoimpl.MessageState    `protogen:\"open.v1\"`\n\tStage         enums.RuntimeMachineStage `protobuf:\"varint,1,opt,name=stage,proto3,enum=talos.resource.definitions.enums.RuntimeMachineStage\" json:\"stage,omitempty\"`\n\tStatus        *MachineStatusStatus      `protobuf:\"bytes,2,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MachineStatusSpec) Reset() {\n\t*x = MachineStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[15]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineStatusSpec) ProtoMessage() {}\n\nfunc (x *MachineStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[15]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*MachineStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{15}\n}\n\nfunc (x *MachineStatusSpec) GetStage() enums.RuntimeMachineStage {\n\tif x != nil {\n\t\treturn x.Stage\n\t}\n\treturn enums.RuntimeMachineStage(0)\n}\n\nfunc (x *MachineStatusSpec) GetStatus() *MachineStatusStatus {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn nil\n}\n\n// MachineStatusStatus describes machine current status at the stage.\ntype MachineStatusStatus struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tReady           bool                   `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tUnmetConditions []*UnmetCondition      `protobuf:\"bytes,2,rep,name=unmet_conditions,json=unmetConditions,proto3\" json:\"unmet_conditions,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *MachineStatusStatus) Reset() {\n\t*x = MachineStatusStatus{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[16]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MachineStatusStatus) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MachineStatusStatus) ProtoMessage() {}\n\nfunc (x *MachineStatusStatus) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[16]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MachineStatusStatus.ProtoReflect.Descriptor instead.\nfunc (*MachineStatusStatus) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{16}\n}\n\nfunc (x *MachineStatusStatus) GetReady() bool {\n\tif x != nil {\n\t\treturn x.Ready\n\t}\n\treturn false\n}\n\nfunc (x *MachineStatusStatus) GetUnmetConditions() []*UnmetCondition {\n\tif x != nil {\n\t\treturn x.UnmetConditions\n\t}\n\treturn nil\n}\n\n// MaintenanceServiceConfigSpec describes configuration for maintenance service API.\ntype MaintenanceServiceConfigSpec struct {\n\tstate              protoimpl.MessageState `protogen:\"open.v1\"`\n\tListenAddress      string                 `protobuf:\"bytes,1,opt,name=listen_address,json=listenAddress,proto3\" json:\"listen_address,omitempty\"`\n\tReachableAddresses []*common.NetIP        `protobuf:\"bytes,2,rep,name=reachable_addresses,json=reachableAddresses,proto3\" json:\"reachable_addresses,omitempty\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *MaintenanceServiceConfigSpec) Reset() {\n\t*x = MaintenanceServiceConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[17]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MaintenanceServiceConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MaintenanceServiceConfigSpec) ProtoMessage() {}\n\nfunc (x *MaintenanceServiceConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[17]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MaintenanceServiceConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*MaintenanceServiceConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{17}\n}\n\nfunc (x *MaintenanceServiceConfigSpec) GetListenAddress() string {\n\tif x != nil {\n\t\treturn x.ListenAddress\n\t}\n\treturn \"\"\n}\n\nfunc (x *MaintenanceServiceConfigSpec) GetReachableAddresses() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ReachableAddresses\n\t}\n\treturn nil\n}\n\n// MetaKeySpec describes status of the defined sysctls.\ntype MetaKeySpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tValue         string                 `protobuf:\"bytes,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaKeySpec) Reset() {\n\t*x = MetaKeySpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[18]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaKeySpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaKeySpec) ProtoMessage() {}\n\nfunc (x *MetaKeySpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[18]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaKeySpec.ProtoReflect.Descriptor instead.\nfunc (*MetaKeySpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{18}\n}\n\nfunc (x *MetaKeySpec) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// MetaLoadedSpec is the spec for meta loaded. The Done field is always true when resource exists.\ntype MetaLoadedSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDone          bool                   `protobuf:\"varint,1,opt,name=done,proto3\" json:\"done,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MetaLoadedSpec) Reset() {\n\t*x = MetaLoadedSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[19]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetaLoadedSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetaLoadedSpec) ProtoMessage() {}\n\nfunc (x *MetaLoadedSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[19]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetaLoadedSpec.ProtoReflect.Descriptor instead.\nfunc (*MetaLoadedSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{19}\n}\n\nfunc (x *MetaLoadedSpec) GetDone() bool {\n\tif x != nil {\n\t\treturn x.Done\n\t}\n\treturn false\n}\n\n// MountStatusSpec describes status of the defined sysctls.\ntype MountStatusSpec struct {\n\tstate               protoimpl.MessageState `protogen:\"open.v1\"`\n\tSource              string                 `protobuf:\"bytes,1,opt,name=source,proto3\" json:\"source,omitempty\"`\n\tTarget              string                 `protobuf:\"bytes,2,opt,name=target,proto3\" json:\"target,omitempty\"`\n\tFilesystemType      string                 `protobuf:\"bytes,3,opt,name=filesystem_type,json=filesystemType,proto3\" json:\"filesystem_type,omitempty\"`\n\tOptions             []string               `protobuf:\"bytes,4,rep,name=options,proto3\" json:\"options,omitempty\"`\n\tEncrypted           bool                   `protobuf:\"varint,5,opt,name=encrypted,proto3\" json:\"encrypted,omitempty\"`\n\tEncryptionProviders []string               `protobuf:\"bytes,6,rep,name=encryption_providers,json=encryptionProviders,proto3\" json:\"encryption_providers,omitempty\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *MountStatusSpec) Reset() {\n\t*x = MountStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[20]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MountStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MountStatusSpec) ProtoMessage() {}\n\nfunc (x *MountStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[20]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MountStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*MountStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{20}\n}\n\nfunc (x *MountStatusSpec) GetSource() string {\n\tif x != nil {\n\t\treturn x.Source\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStatusSpec) GetTarget() string {\n\tif x != nil {\n\t\treturn x.Target\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStatusSpec) GetFilesystemType() string {\n\tif x != nil {\n\t\treturn x.FilesystemType\n\t}\n\treturn \"\"\n}\n\nfunc (x *MountStatusSpec) GetOptions() []string {\n\tif x != nil {\n\t\treturn x.Options\n\t}\n\treturn nil\n}\n\nfunc (x *MountStatusSpec) GetEncrypted() bool {\n\tif x != nil {\n\t\treturn x.Encrypted\n\t}\n\treturn false\n}\n\nfunc (x *MountStatusSpec) GetEncryptionProviders() []string {\n\tif x != nil {\n\t\treturn x.EncryptionProviders\n\t}\n\treturn nil\n}\n\n// OOMActionSpec describes the OOM action record resource properties.\ntype OOMActionSpec struct {\n\tstate          protoimpl.MessageState `protogen:\"open.v1\"`\n\tTriggerContext string                 `protobuf:\"bytes,1,opt,name=trigger_context,json=triggerContext,proto3\" json:\"trigger_context,omitempty\"`\n\tScore          float64                `protobuf:\"fixed64,2,opt,name=score,proto3\" json:\"score,omitempty\"`\n\tProcesses      []string               `protobuf:\"bytes,3,rep,name=processes,proto3\" json:\"processes,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *OOMActionSpec) Reset() {\n\t*x = OOMActionSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[21]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OOMActionSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OOMActionSpec) ProtoMessage() {}\n\nfunc (x *OOMActionSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[21]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OOMActionSpec.ProtoReflect.Descriptor instead.\nfunc (*OOMActionSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{21}\n}\n\nfunc (x *OOMActionSpec) GetTriggerContext() string {\n\tif x != nil {\n\t\treturn x.TriggerContext\n\t}\n\treturn \"\"\n}\n\nfunc (x *OOMActionSpec) GetScore() float64 {\n\tif x != nil {\n\t\treturn x.Score\n\t}\n\treturn 0\n}\n\nfunc (x *OOMActionSpec) GetProcesses() []string {\n\tif x != nil {\n\t\treturn x.Processes\n\t}\n\treturn nil\n}\n\n// PlatformMetadataSpec describes platform metadata properties.\ntype PlatformMetadataSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tPlatform      string                 `protobuf:\"bytes,1,opt,name=platform,proto3\" json:\"platform,omitempty\"`\n\tHostname      string                 `protobuf:\"bytes,2,opt,name=hostname,proto3\" json:\"hostname,omitempty\"`\n\tRegion        string                 `protobuf:\"bytes,3,opt,name=region,proto3\" json:\"region,omitempty\"`\n\tZone          string                 `protobuf:\"bytes,4,opt,name=zone,proto3\" json:\"zone,omitempty\"`\n\tInstanceType  string                 `protobuf:\"bytes,5,opt,name=instance_type,json=instanceType,proto3\" json:\"instance_type,omitempty\"`\n\tInstanceId    string                 `protobuf:\"bytes,6,opt,name=instance_id,json=instanceId,proto3\" json:\"instance_id,omitempty\"`\n\tProviderId    string                 `protobuf:\"bytes,7,opt,name=provider_id,json=providerId,proto3\" json:\"provider_id,omitempty\"`\n\tSpot          bool                   `protobuf:\"varint,8,opt,name=spot,proto3\" json:\"spot,omitempty\"`\n\tInternalDns   string                 `protobuf:\"bytes,9,opt,name=internal_dns,json=internalDns,proto3\" json:\"internal_dns,omitempty\"`\n\tExternalDns   string                 `protobuf:\"bytes,10,opt,name=external_dns,json=externalDns,proto3\" json:\"external_dns,omitempty\"`\n\tTags          map[string]string      `protobuf:\"bytes,11,rep,name=tags,proto3\" json:\"tags,omitempty\" protobuf_key:\"bytes,1,opt,name=key\" protobuf_val:\"bytes,2,opt,name=value\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *PlatformMetadataSpec) Reset() {\n\t*x = PlatformMetadataSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[22]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *PlatformMetadataSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*PlatformMetadataSpec) ProtoMessage() {}\n\nfunc (x *PlatformMetadataSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[22]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use PlatformMetadataSpec.ProtoReflect.Descriptor instead.\nfunc (*PlatformMetadataSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{22}\n}\n\nfunc (x *PlatformMetadataSpec) GetPlatform() string {\n\tif x != nil {\n\t\treturn x.Platform\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetHostname() string {\n\tif x != nil {\n\t\treturn x.Hostname\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetRegion() string {\n\tif x != nil {\n\t\treturn x.Region\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetZone() string {\n\tif x != nil {\n\t\treturn x.Zone\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetInstanceType() string {\n\tif x != nil {\n\t\treturn x.InstanceType\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetInstanceId() string {\n\tif x != nil {\n\t\treturn x.InstanceId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetProviderId() string {\n\tif x != nil {\n\t\treturn x.ProviderId\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetSpot() bool {\n\tif x != nil {\n\t\treturn x.Spot\n\t}\n\treturn false\n}\n\nfunc (x *PlatformMetadataSpec) GetInternalDns() string {\n\tif x != nil {\n\t\treturn x.InternalDns\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetExternalDns() string {\n\tif x != nil {\n\t\treturn x.ExternalDns\n\t}\n\treturn \"\"\n}\n\nfunc (x *PlatformMetadataSpec) GetTags() map[string]string {\n\tif x != nil {\n\t\treturn x.Tags\n\t}\n\treturn nil\n}\n\n// SBOMItemSpec describes the SBOM item resource properties.\ntype SBOMItemSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tVersion       string                 `protobuf:\"bytes,2,opt,name=version,proto3\" json:\"version,omitempty\"`\n\tLicense       string                 `protobuf:\"bytes,3,opt,name=license,proto3\" json:\"license,omitempty\"`\n\tCpEs          []string               `protobuf:\"bytes,4,rep,name=cp_es,json=cpEs,proto3\" json:\"cp_es,omitempty\"`\n\tPurLs         []string               `protobuf:\"bytes,5,rep,name=pur_ls,json=purLs,proto3\" json:\"pur_ls,omitempty\"`\n\tExtension     bool                   `protobuf:\"varint,6,opt,name=extension,proto3\" json:\"extension,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *SBOMItemSpec) Reset() {\n\t*x = SBOMItemSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[23]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SBOMItemSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SBOMItemSpec) ProtoMessage() {}\n\nfunc (x *SBOMItemSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[23]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SBOMItemSpec.ProtoReflect.Descriptor instead.\nfunc (*SBOMItemSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{23}\n}\n\nfunc (x *SBOMItemSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *SBOMItemSpec) GetVersion() string {\n\tif x != nil {\n\t\treturn x.Version\n\t}\n\treturn \"\"\n}\n\nfunc (x *SBOMItemSpec) GetLicense() string {\n\tif x != nil {\n\t\treturn x.License\n\t}\n\treturn \"\"\n}\n\nfunc (x *SBOMItemSpec) GetCpEs() []string {\n\tif x != nil {\n\t\treturn x.CpEs\n\t}\n\treturn nil\n}\n\nfunc (x *SBOMItemSpec) GetPurLs() []string {\n\tif x != nil {\n\t\treturn x.PurLs\n\t}\n\treturn nil\n}\n\nfunc (x *SBOMItemSpec) GetExtension() bool {\n\tif x != nil {\n\t\treturn x.Extension\n\t}\n\treturn false\n}\n\n// SecurityStateSpec describes the security state resource properties.\ntype SecurityStateSpec struct {\n\tstate                    protoimpl.MessageState    `protogen:\"open.v1\"`\n\tSecureBoot               bool                      `protobuf:\"varint,1,opt,name=secure_boot,json=secureBoot,proto3\" json:\"secure_boot,omitempty\"`\n\tUkiSigningKeyFingerprint string                    `protobuf:\"bytes,2,opt,name=uki_signing_key_fingerprint,json=ukiSigningKeyFingerprint,proto3\" json:\"uki_signing_key_fingerprint,omitempty\"`\n\tPcrSigningKeyFingerprint string                    `protobuf:\"bytes,3,opt,name=pcr_signing_key_fingerprint,json=pcrSigningKeyFingerprint,proto3\" json:\"pcr_signing_key_fingerprint,omitempty\"`\n\tSeLinuxState             enums.RuntimeSELinuxState `protobuf:\"varint,4,opt,name=se_linux_state,json=seLinuxState,proto3,enum=talos.resource.definitions.enums.RuntimeSELinuxState\" json:\"se_linux_state,omitempty\"`\n\tBootedWithUki            bool                      `protobuf:\"varint,5,opt,name=booted_with_uki,json=bootedWithUki,proto3\" json:\"booted_with_uki,omitempty\"`\n\tFipsState                enums.RuntimeFIPSState    `protobuf:\"varint,6,opt,name=fips_state,json=fipsState,proto3,enum=talos.resource.definitions.enums.RuntimeFIPSState\" json:\"fips_state,omitempty\"`\n\tModuleSignatureEnforced  bool                      `protobuf:\"varint,7,opt,name=module_signature_enforced,json=moduleSignatureEnforced,proto3\" json:\"module_signature_enforced,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *SecurityStateSpec) Reset() {\n\t*x = SecurityStateSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[24]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *SecurityStateSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SecurityStateSpec) ProtoMessage() {}\n\nfunc (x *SecurityStateSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[24]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SecurityStateSpec.ProtoReflect.Descriptor instead.\nfunc (*SecurityStateSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{24}\n}\n\nfunc (x *SecurityStateSpec) GetSecureBoot() bool {\n\tif x != nil {\n\t\treturn x.SecureBoot\n\t}\n\treturn false\n}\n\nfunc (x *SecurityStateSpec) GetUkiSigningKeyFingerprint() string {\n\tif x != nil {\n\t\treturn x.UkiSigningKeyFingerprint\n\t}\n\treturn \"\"\n}\n\nfunc (x *SecurityStateSpec) GetPcrSigningKeyFingerprint() string {\n\tif x != nil {\n\t\treturn x.PcrSigningKeyFingerprint\n\t}\n\treturn \"\"\n}\n\nfunc (x *SecurityStateSpec) GetSeLinuxState() enums.RuntimeSELinuxState {\n\tif x != nil {\n\t\treturn x.SeLinuxState\n\t}\n\treturn enums.RuntimeSELinuxState(0)\n}\n\nfunc (x *SecurityStateSpec) GetBootedWithUki() bool {\n\tif x != nil {\n\t\treturn x.BootedWithUki\n\t}\n\treturn false\n}\n\nfunc (x *SecurityStateSpec) GetFipsState() enums.RuntimeFIPSState {\n\tif x != nil {\n\t\treturn x.FipsState\n\t}\n\treturn enums.RuntimeFIPSState(0)\n}\n\nfunc (x *SecurityStateSpec) GetModuleSignatureEnforced() bool {\n\tif x != nil {\n\t\treturn x.ModuleSignatureEnforced\n\t}\n\treturn false\n}\n\n// UniqueMachineTokenSpec is the spec for the machine unique token. Token can be empty if machine wasn't assigned any.\ntype UniqueMachineTokenSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tToken         string                 `protobuf:\"bytes,1,opt,name=token,proto3\" json:\"token,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *UniqueMachineTokenSpec) Reset() {\n\t*x = UniqueMachineTokenSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[25]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *UniqueMachineTokenSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UniqueMachineTokenSpec) ProtoMessage() {}\n\nfunc (x *UniqueMachineTokenSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[25]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UniqueMachineTokenSpec.ProtoReflect.Descriptor instead.\nfunc (*UniqueMachineTokenSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{25}\n}\n\nfunc (x *UniqueMachineTokenSpec) GetToken() string {\n\tif x != nil {\n\t\treturn x.Token\n\t}\n\treturn \"\"\n}\n\n// UnmetCondition is a failure which prevents machine from being ready at the stage.\ntype UnmetCondition struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tReason        string                 `protobuf:\"bytes,2,opt,name=reason,proto3\" json:\"reason,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *UnmetCondition) Reset() {\n\t*x = UnmetCondition{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[26]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *UnmetCondition) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UnmetCondition) ProtoMessage() {}\n\nfunc (x *UnmetCondition) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[26]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UnmetCondition.ProtoReflect.Descriptor instead.\nfunc (*UnmetCondition) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{26}\n}\n\nfunc (x *UnmetCondition) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *UnmetCondition) GetReason() string {\n\tif x != nil {\n\t\treturn x.Reason\n\t}\n\treturn \"\"\n}\n\n// WatchdogTimerConfigSpec describes configuration of watchdog timer.\ntype WatchdogTimerConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDevice        string                 `protobuf:\"bytes,1,opt,name=device,proto3\" json:\"device,omitempty\"`\n\tTimeout       *durationpb.Duration   `protobuf:\"bytes,2,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *WatchdogTimerConfigSpec) Reset() {\n\t*x = WatchdogTimerConfigSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[27]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WatchdogTimerConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WatchdogTimerConfigSpec) ProtoMessage() {}\n\nfunc (x *WatchdogTimerConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[27]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WatchdogTimerConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*WatchdogTimerConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{27}\n}\n\nfunc (x *WatchdogTimerConfigSpec) GetDevice() string {\n\tif x != nil {\n\t\treturn x.Device\n\t}\n\treturn \"\"\n}\n\nfunc (x *WatchdogTimerConfigSpec) GetTimeout() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn nil\n}\n\n// WatchdogTimerStatusSpec describes configuration of watchdog timer.\ntype WatchdogTimerStatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDevice        string                 `protobuf:\"bytes,1,opt,name=device,proto3\" json:\"device,omitempty\"`\n\tTimeout       *durationpb.Duration   `protobuf:\"bytes,2,opt,name=timeout,proto3\" json:\"timeout,omitempty\"`\n\tFeedInterval  *durationpb.Duration   `protobuf:\"bytes,3,opt,name=feed_interval,json=feedInterval,proto3\" json:\"feed_interval,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *WatchdogTimerStatusSpec) Reset() {\n\t*x = WatchdogTimerStatusSpec{}\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[28]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WatchdogTimerStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WatchdogTimerStatusSpec) ProtoMessage() {}\n\nfunc (x *WatchdogTimerStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_runtime_runtime_proto_msgTypes[28]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use WatchdogTimerStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*WatchdogTimerStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescGZIP(), []int{28}\n}\n\nfunc (x *WatchdogTimerStatusSpec) GetDevice() string {\n\tif x != nil {\n\t\treturn x.Device\n\t}\n\treturn \"\"\n}\n\nfunc (x *WatchdogTimerStatusSpec) GetTimeout() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Timeout\n\t}\n\treturn nil\n}\n\nfunc (x *WatchdogTimerStatusSpec) GetFeedInterval() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.FeedInterval\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_runtime_runtime_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_runtime_runtime_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"*resource/definitions/runtime/runtime.proto\\x12\\\"talos.resource.definitions.runtime\\x1a\\x13common/common.proto\\x1a\\x1egoogle/protobuf/duration.proto\\x1a&resource/definitions/enums/enums.proto\\\"\\xdc\\x01\\n\" +\n\t\"\\x14APIServiceConfigSpec\\x12%\\n\" +\n\t\"\\x0elisten_address\\x18\\x01 \\x01(\\tR\\rlistenAddress\\x122\\n\" +\n\t\"\\x15node_routing_disabled\\x18\\x02 \\x01(\\bR\\x13nodeRoutingDisabled\\x12,\\n\" +\n\t\"\\x12readonly_role_mode\\x18\\x03 \\x01(\\bR\\x10readonlyRoleMode\\x12;\\n\" +\n\t\"\\x1askip_verifying_client_cert\\x18\\x04 \\x01(\\bR\\x17skipVerifyingClientCert\\\"4\\n\" +\n\t\"\\x0fBootedEntrySpec\\x12!\\n\" +\n\t\"\\fbooted_entry\\x18\\x01 \\x01(\\tR\\vbootedEntry\\\")\\n\" +\n\t\"\\x11DevicesStatusSpec\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\\"D\\n\" +\n\t\"\\x0eDiagnosticSpec\\x12\\x18\\n\" +\n\t\"\\amessage\\x18\\x01 \\x01(\\tR\\amessage\\x12\\x18\\n\" +\n\t\"\\adetails\\x18\\x02 \\x03(\\tR\\adetails\\\"/\\n\" +\n\t\"\\x0fEnvironmentSpec\\x12\\x1c\\n\" +\n\t\"\\tvariables\\x18\\x01 \\x03(\\tR\\tvariables\\\"1\\n\" +\n\t\"\\x13EventSinkConfigSpec\\x12\\x1a\\n\" +\n\t\"\\bendpoint\\x18\\x01 \\x01(\\tR\\bendpoint\\\"U\\n\" +\n\t\"\\x1aExtensionServiceConfigFile\\x12\\x18\\n\" +\n\t\"\\acontent\\x18\\x01 \\x01(\\tR\\acontent\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"mount_path\\x18\\x02 \\x01(\\tR\\tmountPath\\\"\\x94\\x01\\n\" +\n\t\"\\x1aExtensionServiceConfigSpec\\x12T\\n\" +\n\t\"\\x05files\\x18\\x01 \\x03(\\v2>.talos.resource.definitions.runtime.ExtensionServiceConfigFileR\\x05files\\x12 \\n\" +\n\t\"\\venvironment\\x18\\x02 \\x03(\\tR\\venvironment\\\"E\\n\" +\n\t\" ExtensionServiceConfigStatusSpec\\x12!\\n\" +\n\t\"\\fspec_version\\x18\\x01 \\x01(\\tR\\vspecVersion\\\"-\\n\" +\n\t\"\\x11KernelCmdlineSpec\\x12\\x18\\n\" +\n\t\"\\acmdline\\x18\\x01 \\x01(\\tR\\acmdline\\\"J\\n\" +\n\t\"\\x14KernelModuleSpecSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x1e\\n\" +\n\t\"\\n\" +\n\t\"parameters\\x18\\x02 \\x03(\\tR\\n\" +\n\t\"parameters\\\"P\\n\" +\n\t\"\\x13KernelParamSpecSpec\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x01 \\x01(\\tR\\x05value\\x12#\\n\" +\n\t\"\\rignore_errors\\x18\\x02 \\x01(\\bR\\fignoreErrors\\\"m\\n\" +\n\t\"\\x15KernelParamStatusSpec\\x12\\x18\\n\" +\n\t\"\\acurrent\\x18\\x01 \\x01(\\tR\\acurrent\\x12\\x18\\n\" +\n\t\"\\adefault\\x18\\x02 \\x01(\\tR\\adefault\\x12 \\n\" +\n\t\"\\vunsupported\\x18\\x03 \\x01(\\bR\\vunsupported\\\"D\\n\" +\n\t\"\\x11KmsgLogConfigSpec\\x12/\\n\" +\n\t\"\\fdestinations\\x18\\x01 \\x03(\\v2\\v.common.URLR\\fdestinations\\\"\\xa9\\x01\\n\" +\n\t\"\\x16LoadedKernelModuleSpec\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x01 \\x01(\\x03R\\x04size\\x12'\\n\" +\n\t\"\\x0freference_count\\x18\\x02 \\x01(\\x03R\\x0ereferenceCount\\x12\\\"\\n\" +\n\t\"\\fdependencies\\x18\\x03 \\x03(\\tR\\fdependencies\\x12\\x14\\n\" +\n\t\"\\x05state\\x18\\x04 \\x01(\\tR\\x05state\\x12\\x18\\n\" +\n\t\"\\aaddress\\x18\\x05 \\x01(\\tR\\aaddress\\\"\\xb1\\x01\\n\" +\n\t\"\\x11MachineStatusSpec\\x12K\\n\" +\n\t\"\\x05stage\\x18\\x01 \\x01(\\x0e25.talos.resource.definitions.enums.RuntimeMachineStageR\\x05stage\\x12O\\n\" +\n\t\"\\x06status\\x18\\x02 \\x01(\\v27.talos.resource.definitions.runtime.MachineStatusStatusR\\x06status\\\"\\x8a\\x01\\n\" +\n\t\"\\x13MachineStatusStatus\\x12\\x14\\n\" +\n\t\"\\x05ready\\x18\\x01 \\x01(\\bR\\x05ready\\x12]\\n\" +\n\t\"\\x10unmet_conditions\\x18\\x02 \\x03(\\v22.talos.resource.definitions.runtime.UnmetConditionR\\x0funmetConditions\\\"\\x85\\x01\\n\" +\n\t\"\\x1cMaintenanceServiceConfigSpec\\x12%\\n\" +\n\t\"\\x0elisten_address\\x18\\x01 \\x01(\\tR\\rlistenAddress\\x12>\\n\" +\n\t\"\\x13reachable_addresses\\x18\\x02 \\x03(\\v2\\r.common.NetIPR\\x12reachableAddresses\\\"#\\n\" +\n\t\"\\vMetaKeySpec\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x01 \\x01(\\tR\\x05value\\\"$\\n\" +\n\t\"\\x0eMetaLoadedSpec\\x12\\x12\\n\" +\n\t\"\\x04done\\x18\\x01 \\x01(\\bR\\x04done\\\"\\xd5\\x01\\n\" +\n\t\"\\x0fMountStatusSpec\\x12\\x16\\n\" +\n\t\"\\x06source\\x18\\x01 \\x01(\\tR\\x06source\\x12\\x16\\n\" +\n\t\"\\x06target\\x18\\x02 \\x01(\\tR\\x06target\\x12'\\n\" +\n\t\"\\x0ffilesystem_type\\x18\\x03 \\x01(\\tR\\x0efilesystemType\\x12\\x18\\n\" +\n\t\"\\aoptions\\x18\\x04 \\x03(\\tR\\aoptions\\x12\\x1c\\n\" +\n\t\"\\tencrypted\\x18\\x05 \\x01(\\bR\\tencrypted\\x121\\n\" +\n\t\"\\x14encryption_providers\\x18\\x06 \\x03(\\tR\\x13encryptionProviders\\\"l\\n\" +\n\t\"\\rOOMActionSpec\\x12'\\n\" +\n\t\"\\x0ftrigger_context\\x18\\x01 \\x01(\\tR\\x0etriggerContext\\x12\\x14\\n\" +\n\t\"\\x05score\\x18\\x02 \\x01(\\x01R\\x05score\\x12\\x1c\\n\" +\n\t\"\\tprocesses\\x18\\x03 \\x03(\\tR\\tprocesses\\\"\\xcc\\x03\\n\" +\n\t\"\\x14PlatformMetadataSpec\\x12\\x1a\\n\" +\n\t\"\\bplatform\\x18\\x01 \\x01(\\tR\\bplatform\\x12\\x1a\\n\" +\n\t\"\\bhostname\\x18\\x02 \\x01(\\tR\\bhostname\\x12\\x16\\n\" +\n\t\"\\x06region\\x18\\x03 \\x01(\\tR\\x06region\\x12\\x12\\n\" +\n\t\"\\x04zone\\x18\\x04 \\x01(\\tR\\x04zone\\x12#\\n\" +\n\t\"\\rinstance_type\\x18\\x05 \\x01(\\tR\\finstanceType\\x12\\x1f\\n\" +\n\t\"\\vinstance_id\\x18\\x06 \\x01(\\tR\\n\" +\n\t\"instanceId\\x12\\x1f\\n\" +\n\t\"\\vprovider_id\\x18\\a \\x01(\\tR\\n\" +\n\t\"providerId\\x12\\x12\\n\" +\n\t\"\\x04spot\\x18\\b \\x01(\\bR\\x04spot\\x12!\\n\" +\n\t\"\\finternal_dns\\x18\\t \\x01(\\tR\\vinternalDns\\x12!\\n\" +\n\t\"\\fexternal_dns\\x18\\n\" +\n\t\" \\x01(\\tR\\vexternalDns\\x12V\\n\" +\n\t\"\\x04tags\\x18\\v \\x03(\\v2B.talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntryR\\x04tags\\x1a7\\n\" +\n\t\"\\tTagsEntry\\x12\\x10\\n\" +\n\t\"\\x03key\\x18\\x01 \\x01(\\tR\\x03key\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value:\\x028\\x01\\\"\\xa0\\x01\\n\" +\n\t\"\\fSBOMItemSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x18\\n\" +\n\t\"\\aversion\\x18\\x02 \\x01(\\tR\\aversion\\x12\\x18\\n\" +\n\t\"\\alicense\\x18\\x03 \\x01(\\tR\\alicense\\x12\\x13\\n\" +\n\t\"\\x05cp_es\\x18\\x04 \\x03(\\tR\\x04cpEs\\x12\\x15\\n\" +\n\t\"\\x06pur_ls\\x18\\x05 \\x03(\\tR\\x05purLs\\x12\\x1c\\n\" +\n\t\"\\textension\\x18\\x06 \\x01(\\bR\\textension\\\"\\xc6\\x03\\n\" +\n\t\"\\x11SecurityStateSpec\\x12\\x1f\\n\" +\n\t\"\\vsecure_boot\\x18\\x01 \\x01(\\bR\\n\" +\n\t\"secureBoot\\x12=\\n\" +\n\t\"\\x1buki_signing_key_fingerprint\\x18\\x02 \\x01(\\tR\\x18ukiSigningKeyFingerprint\\x12=\\n\" +\n\t\"\\x1bpcr_signing_key_fingerprint\\x18\\x03 \\x01(\\tR\\x18pcrSigningKeyFingerprint\\x12[\\n\" +\n\t\"\\x0ese_linux_state\\x18\\x04 \\x01(\\x0e25.talos.resource.definitions.enums.RuntimeSELinuxStateR\\fseLinuxState\\x12&\\n\" +\n\t\"\\x0fbooted_with_uki\\x18\\x05 \\x01(\\bR\\rbootedWithUki\\x12Q\\n\" +\n\t\"\\n\" +\n\t\"fips_state\\x18\\x06 \\x01(\\x0e22.talos.resource.definitions.enums.RuntimeFIPSStateR\\tfipsState\\x12:\\n\" +\n\t\"\\x19module_signature_enforced\\x18\\a \\x01(\\bR\\x17moduleSignatureEnforced\\\".\\n\" +\n\t\"\\x16UniqueMachineTokenSpec\\x12\\x14\\n\" +\n\t\"\\x05token\\x18\\x01 \\x01(\\tR\\x05token\\\"<\\n\" +\n\t\"\\x0eUnmetCondition\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06reason\\x18\\x02 \\x01(\\tR\\x06reason\\\"f\\n\" +\n\t\"\\x17WatchdogTimerConfigSpec\\x12\\x16\\n\" +\n\t\"\\x06device\\x18\\x01 \\x01(\\tR\\x06device\\x123\\n\" +\n\t\"\\atimeout\\x18\\x02 \\x01(\\v2\\x19.google.protobuf.DurationR\\atimeout\\\"\\xa6\\x01\\n\" +\n\t\"\\x17WatchdogTimerStatusSpec\\x12\\x16\\n\" +\n\t\"\\x06device\\x18\\x01 \\x01(\\tR\\x06device\\x123\\n\" +\n\t\"\\atimeout\\x18\\x02 \\x01(\\v2\\x19.google.protobuf.DurationR\\atimeout\\x12>\\n\" +\n\t\"\\rfeed_interval\\x18\\x03 \\x01(\\v2\\x19.google.protobuf.DurationR\\ffeedIntervalBx\\n\" +\n\t\"*dev.talos.api.resource.definitions.runtimeZJgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/runtimeb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_runtime_runtime_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_runtime_runtime_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_runtime_runtime_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_runtime_runtime_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_runtime_runtime_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_runtime_runtime_proto_rawDesc), len(file_resource_definitions_runtime_runtime_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_runtime_runtime_proto_rawDescData\n}\n\nvar file_resource_definitions_runtime_runtime_proto_msgTypes = make([]protoimpl.MessageInfo, 30)\nvar file_resource_definitions_runtime_runtime_proto_goTypes = []any{\n\t(*APIServiceConfigSpec)(nil),             // 0: talos.resource.definitions.runtime.APIServiceConfigSpec\n\t(*BootedEntrySpec)(nil),                  // 1: talos.resource.definitions.runtime.BootedEntrySpec\n\t(*DevicesStatusSpec)(nil),                // 2: talos.resource.definitions.runtime.DevicesStatusSpec\n\t(*DiagnosticSpec)(nil),                   // 3: talos.resource.definitions.runtime.DiagnosticSpec\n\t(*EnvironmentSpec)(nil),                  // 4: talos.resource.definitions.runtime.EnvironmentSpec\n\t(*EventSinkConfigSpec)(nil),              // 5: talos.resource.definitions.runtime.EventSinkConfigSpec\n\t(*ExtensionServiceConfigFile)(nil),       // 6: talos.resource.definitions.runtime.ExtensionServiceConfigFile\n\t(*ExtensionServiceConfigSpec)(nil),       // 7: talos.resource.definitions.runtime.ExtensionServiceConfigSpec\n\t(*ExtensionServiceConfigStatusSpec)(nil), // 8: talos.resource.definitions.runtime.ExtensionServiceConfigStatusSpec\n\t(*KernelCmdlineSpec)(nil),                // 9: talos.resource.definitions.runtime.KernelCmdlineSpec\n\t(*KernelModuleSpecSpec)(nil),             // 10: talos.resource.definitions.runtime.KernelModuleSpecSpec\n\t(*KernelParamSpecSpec)(nil),              // 11: talos.resource.definitions.runtime.KernelParamSpecSpec\n\t(*KernelParamStatusSpec)(nil),            // 12: talos.resource.definitions.runtime.KernelParamStatusSpec\n\t(*KmsgLogConfigSpec)(nil),                // 13: talos.resource.definitions.runtime.KmsgLogConfigSpec\n\t(*LoadedKernelModuleSpec)(nil),           // 14: talos.resource.definitions.runtime.LoadedKernelModuleSpec\n\t(*MachineStatusSpec)(nil),                // 15: talos.resource.definitions.runtime.MachineStatusSpec\n\t(*MachineStatusStatus)(nil),              // 16: talos.resource.definitions.runtime.MachineStatusStatus\n\t(*MaintenanceServiceConfigSpec)(nil),     // 17: talos.resource.definitions.runtime.MaintenanceServiceConfigSpec\n\t(*MetaKeySpec)(nil),                      // 18: talos.resource.definitions.runtime.MetaKeySpec\n\t(*MetaLoadedSpec)(nil),                   // 19: talos.resource.definitions.runtime.MetaLoadedSpec\n\t(*MountStatusSpec)(nil),                  // 20: talos.resource.definitions.runtime.MountStatusSpec\n\t(*OOMActionSpec)(nil),                    // 21: talos.resource.definitions.runtime.OOMActionSpec\n\t(*PlatformMetadataSpec)(nil),             // 22: talos.resource.definitions.runtime.PlatformMetadataSpec\n\t(*SBOMItemSpec)(nil),                     // 23: talos.resource.definitions.runtime.SBOMItemSpec\n\t(*SecurityStateSpec)(nil),                // 24: talos.resource.definitions.runtime.SecurityStateSpec\n\t(*UniqueMachineTokenSpec)(nil),           // 25: talos.resource.definitions.runtime.UniqueMachineTokenSpec\n\t(*UnmetCondition)(nil),                   // 26: talos.resource.definitions.runtime.UnmetCondition\n\t(*WatchdogTimerConfigSpec)(nil),          // 27: talos.resource.definitions.runtime.WatchdogTimerConfigSpec\n\t(*WatchdogTimerStatusSpec)(nil),          // 28: talos.resource.definitions.runtime.WatchdogTimerStatusSpec\n\tnil,                                      // 29: talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntry\n\t(*common.URL)(nil),                       // 30: common.URL\n\t(enums.RuntimeMachineStage)(0),           // 31: talos.resource.definitions.enums.RuntimeMachineStage\n\t(*common.NetIP)(nil),                     // 32: common.NetIP\n\t(enums.RuntimeSELinuxState)(0),           // 33: talos.resource.definitions.enums.RuntimeSELinuxState\n\t(enums.RuntimeFIPSState)(0),              // 34: talos.resource.definitions.enums.RuntimeFIPSState\n\t(*durationpb.Duration)(nil),              // 35: google.protobuf.Duration\n}\nvar file_resource_definitions_runtime_runtime_proto_depIdxs = []int32{\n\t6,  // 0: talos.resource.definitions.runtime.ExtensionServiceConfigSpec.files:type_name -> talos.resource.definitions.runtime.ExtensionServiceConfigFile\n\t30, // 1: talos.resource.definitions.runtime.KmsgLogConfigSpec.destinations:type_name -> common.URL\n\t31, // 2: talos.resource.definitions.runtime.MachineStatusSpec.stage:type_name -> talos.resource.definitions.enums.RuntimeMachineStage\n\t16, // 3: talos.resource.definitions.runtime.MachineStatusSpec.status:type_name -> talos.resource.definitions.runtime.MachineStatusStatus\n\t26, // 4: talos.resource.definitions.runtime.MachineStatusStatus.unmet_conditions:type_name -> talos.resource.definitions.runtime.UnmetCondition\n\t32, // 5: talos.resource.definitions.runtime.MaintenanceServiceConfigSpec.reachable_addresses:type_name -> common.NetIP\n\t29, // 6: talos.resource.definitions.runtime.PlatformMetadataSpec.tags:type_name -> talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntry\n\t33, // 7: talos.resource.definitions.runtime.SecurityStateSpec.se_linux_state:type_name -> talos.resource.definitions.enums.RuntimeSELinuxState\n\t34, // 8: talos.resource.definitions.runtime.SecurityStateSpec.fips_state:type_name -> talos.resource.definitions.enums.RuntimeFIPSState\n\t35, // 9: talos.resource.definitions.runtime.WatchdogTimerConfigSpec.timeout:type_name -> google.protobuf.Duration\n\t35, // 10: talos.resource.definitions.runtime.WatchdogTimerStatusSpec.timeout:type_name -> google.protobuf.Duration\n\t35, // 11: talos.resource.definitions.runtime.WatchdogTimerStatusSpec.feed_interval:type_name -> google.protobuf.Duration\n\t12, // [12:12] is the sub-list for method output_type\n\t12, // [12:12] is the sub-list for method input_type\n\t12, // [12:12] is the sub-list for extension type_name\n\t12, // [12:12] is the sub-list for extension extendee\n\t0,  // [0:12] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_runtime_runtime_proto_init() }\nfunc file_resource_definitions_runtime_runtime_proto_init() {\n\tif File_resource_definitions_runtime_runtime_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_runtime_runtime_proto_rawDesc), len(file_resource_definitions_runtime_runtime_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   30,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_runtime_runtime_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_runtime_runtime_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_runtime_runtime_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_runtime_runtime_proto = out.File\n\tfile_resource_definitions_runtime_runtime_proto_goTypes = nil\n\tfile_resource_definitions_runtime_runtime_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/runtime/runtime_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/runtime/runtime.proto\n\npackage runtime\n\nimport (\n\tbinary \"encoding/binary\"\n\tfmt \"fmt\"\n\tio \"io\"\n\tmath \"math\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tenums \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *APIServiceConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *APIServiceConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *APIServiceConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SkipVerifyingClientCert {\n\t\ti--\n\t\tif m.SkipVerifyingClientCert {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.ReadonlyRoleMode {\n\t\ti--\n\t\tif m.ReadonlyRoleMode {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.NodeRoutingDisabled {\n\t\ti--\n\t\tif m.NodeRoutingDisabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.ListenAddress) > 0 {\n\t\ti -= len(m.ListenAddress)\n\t\tcopy(dAtA[i:], m.ListenAddress)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ListenAddress)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BootedEntrySpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BootedEntrySpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BootedEntrySpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.BootedEntry) > 0 {\n\t\ti -= len(m.BootedEntry)\n\t\tcopy(dAtA[i:], m.BootedEntry)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BootedEntry)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DevicesStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DevicesStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DevicesStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DiagnosticSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DiagnosticSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DiagnosticSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Details) > 0 {\n\t\tfor iNdEx := len(m.Details) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Details[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Details[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Details[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Message) > 0 {\n\t\ti -= len(m.Message)\n\t\tcopy(dAtA[i:], m.Message)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Message)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EnvironmentSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EnvironmentSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EnvironmentSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Variables) > 0 {\n\t\tfor iNdEx := len(m.Variables) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Variables[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Variables[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Variables[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EventSinkConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EventSinkConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EventSinkConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Endpoint) > 0 {\n\t\ti -= len(m.Endpoint)\n\t\tcopy(dAtA[i:], m.Endpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Endpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtensionServiceConfigFile) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtensionServiceConfigFile) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtensionServiceConfigFile) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.MountPath) > 0 {\n\t\ti -= len(m.MountPath)\n\t\tcopy(dAtA[i:], m.MountPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MountPath)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Content) > 0 {\n\t\ti -= len(m.Content)\n\t\tcopy(dAtA[i:], m.Content)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Content)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtensionServiceConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtensionServiceConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtensionServiceConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Environment) > 0 {\n\t\tfor iNdEx := len(m.Environment) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Environment[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Environment[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Environment[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Files) > 0 {\n\t\tfor iNdEx := len(m.Files) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Files[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ExtensionServiceConfigStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ExtensionServiceConfigStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ExtensionServiceConfigStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SpecVersion) > 0 {\n\t\ti -= len(m.SpecVersion)\n\t\tcopy(dAtA[i:], m.SpecVersion)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SpecVersion)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KernelCmdlineSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KernelCmdlineSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KernelCmdlineSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Cmdline) > 0 {\n\t\ti -= len(m.Cmdline)\n\t\tcopy(dAtA[i:], m.Cmdline)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Cmdline)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KernelModuleSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KernelModuleSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KernelModuleSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Parameters) > 0 {\n\t\tfor iNdEx := len(m.Parameters) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Parameters[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Parameters[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Parameters[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KernelParamSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KernelParamSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KernelParamSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.IgnoreErrors {\n\t\ti--\n\t\tif m.IgnoreErrors {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KernelParamStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KernelParamStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KernelParamStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Unsupported {\n\t\ti--\n\t\tif m.Unsupported {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.Default) > 0 {\n\t\ti -= len(m.Default)\n\t\tcopy(dAtA[i:], m.Default)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Default)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Current) > 0 {\n\t\ti -= len(m.Current)\n\t\tcopy(dAtA[i:], m.Current)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Current)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KmsgLogConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KmsgLogConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KmsgLogConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Destinations) > 0 {\n\t\tfor iNdEx := len(m.Destinations) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.Destinations[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.Destinations[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *LoadedKernelModuleSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *LoadedKernelModuleSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *LoadedKernelModuleSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Address) > 0 {\n\t\ti -= len(m.Address)\n\t\tcopy(dAtA[i:], m.Address)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Address)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.State) > 0 {\n\t\ti -= len(m.State)\n\t\tcopy(dAtA[i:], m.State)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Dependencies) > 0 {\n\t\tfor iNdEx := len(m.Dependencies) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Dependencies[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Dependencies[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Dependencies[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.ReferenceCount != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.ReferenceCount))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Status != nil {\n\t\tsize, err := m.Status.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Stage != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Stage))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MachineStatusStatus) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MachineStatusStatus) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MachineStatusStatus) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.UnmetConditions) > 0 {\n\t\tfor iNdEx := len(m.UnmetConditions) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.UnmetConditions[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Ready {\n\t\ti--\n\t\tif m.Ready {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MaintenanceServiceConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MaintenanceServiceConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MaintenanceServiceConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.ReachableAddresses) > 0 {\n\t\tfor iNdEx := len(m.ReachableAddresses) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ReachableAddresses[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ReachableAddresses[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.ListenAddress) > 0 {\n\t\ti -= len(m.ListenAddress)\n\t\tcopy(dAtA[i:], m.ListenAddress)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ListenAddress)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaKeySpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaKeySpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaKeySpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Value) > 0 {\n\t\ti -= len(m.Value)\n\t\tcopy(dAtA[i:], m.Value)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Value)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MetaLoadedSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MetaLoadedSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MetaLoadedSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Done {\n\t\ti--\n\t\tif m.Done {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MountStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MountStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MountStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.EncryptionProviders) > 0 {\n\t\tfor iNdEx := len(m.EncryptionProviders) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.EncryptionProviders[iNdEx])\n\t\t\tcopy(dAtA[i:], m.EncryptionProviders[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.EncryptionProviders[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x32\n\t\t}\n\t}\n\tif m.Encrypted {\n\t\ti--\n\t\tif m.Encrypted {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.Options) > 0 {\n\t\tfor iNdEx := len(m.Options) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Options[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Options[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Options[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.FilesystemType) > 0 {\n\t\ti -= len(m.FilesystemType)\n\t\tcopy(dAtA[i:], m.FilesystemType)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.FilesystemType)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Target) > 0 {\n\t\ti -= len(m.Target)\n\t\tcopy(dAtA[i:], m.Target)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Target)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Source) > 0 {\n\t\ti -= len(m.Source)\n\t\tcopy(dAtA[i:], m.Source)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Source)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *OOMActionSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *OOMActionSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *OOMActionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Processes) > 0 {\n\t\tfor iNdEx := len(m.Processes) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.Processes[iNdEx])\n\t\t\tcopy(dAtA[i:], m.Processes[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Processes[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Score != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Score))))\n\t\ti--\n\t\tdAtA[i] = 0x11\n\t}\n\tif len(m.TriggerContext) > 0 {\n\t\ti -= len(m.TriggerContext)\n\t\tcopy(dAtA[i:], m.TriggerContext)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TriggerContext)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *PlatformMetadataSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *PlatformMetadataSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *PlatformMetadataSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Tags) > 0 {\n\t\tfor k := range m.Tags {\n\t\t\tv := m.Tags[k]\n\t\t\tbaseI := i\n\t\t\ti -= len(v)\n\t\t\tcopy(dAtA[i:], v)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(v)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t\ti -= len(k)\n\t\t\tcopy(dAtA[i:], k)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(k)))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(baseI-i))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x5a\n\t\t}\n\t}\n\tif len(m.ExternalDns) > 0 {\n\t\ti -= len(m.ExternalDns)\n\t\tcopy(dAtA[i:], m.ExternalDns)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ExternalDns)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif len(m.InternalDns) > 0 {\n\t\ti -= len(m.InternalDns)\n\t\tcopy(dAtA[i:], m.InternalDns)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InternalDns)))\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.Spot {\n\t\ti--\n\t\tif m.Spot {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x40\n\t}\n\tif len(m.ProviderId) > 0 {\n\t\ti -= len(m.ProviderId)\n\t\tcopy(dAtA[i:], m.ProviderId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ProviderId)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.InstanceId) > 0 {\n\t\ti -= len(m.InstanceId)\n\t\tcopy(dAtA[i:], m.InstanceId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InstanceId)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.InstanceType) > 0 {\n\t\ti -= len(m.InstanceType)\n\t\tcopy(dAtA[i:], m.InstanceType)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.InstanceType)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Zone) > 0 {\n\t\ti -= len(m.Zone)\n\t\tcopy(dAtA[i:], m.Zone)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Zone)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.Region) > 0 {\n\t\ti -= len(m.Region)\n\t\tcopy(dAtA[i:], m.Region)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Region)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Hostname) > 0 {\n\t\ti -= len(m.Hostname)\n\t\tcopy(dAtA[i:], m.Hostname)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Hostname)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Platform) > 0 {\n\t\ti -= len(m.Platform)\n\t\tcopy(dAtA[i:], m.Platform)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Platform)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SBOMItemSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SBOMItemSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SBOMItemSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Extension {\n\t\ti--\n\t\tif m.Extension {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.PurLs) > 0 {\n\t\tfor iNdEx := len(m.PurLs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.PurLs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.PurLs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PurLs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.CpEs) > 0 {\n\t\tfor iNdEx := len(m.CpEs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.CpEs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.CpEs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CpEs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif len(m.License) > 0 {\n\t\ti -= len(m.License)\n\t\tcopy(dAtA[i:], m.License)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.License)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Version) > 0 {\n\t\ti -= len(m.Version)\n\t\tcopy(dAtA[i:], m.Version)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Version)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *SecurityStateSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *SecurityStateSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *SecurityStateSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.ModuleSignatureEnforced {\n\t\ti--\n\t\tif m.ModuleSignatureEnforced {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.FipsState != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.FipsState))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif m.BootedWithUki {\n\t\ti--\n\t\tif m.BootedWithUki {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.SeLinuxState != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.SeLinuxState))\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.PcrSigningKeyFingerprint) > 0 {\n\t\ti -= len(m.PcrSigningKeyFingerprint)\n\t\tcopy(dAtA[i:], m.PcrSigningKeyFingerprint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PcrSigningKeyFingerprint)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.UkiSigningKeyFingerprint) > 0 {\n\t\ti -= len(m.UkiSigningKeyFingerprint)\n\t\tcopy(dAtA[i:], m.UkiSigningKeyFingerprint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.UkiSigningKeyFingerprint)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.SecureBoot {\n\t\ti--\n\t\tif m.SecureBoot {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *UniqueMachineTokenSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *UniqueMachineTokenSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *UniqueMachineTokenSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Token) > 0 {\n\t\ti -= len(m.Token)\n\t\tcopy(dAtA[i:], m.Token)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Token)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *UnmetCondition) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *UnmetCondition) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *UnmetCondition) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Reason) > 0 {\n\t\ti -= len(m.Reason)\n\t\tcopy(dAtA[i:], m.Reason)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Reason)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *WatchdogTimerConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *WatchdogTimerConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *WatchdogTimerConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Timeout != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Timeout).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Device) > 0 {\n\t\ti -= len(m.Device)\n\t\tcopy(dAtA[i:], m.Device)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Device)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *WatchdogTimerStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *WatchdogTimerStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *WatchdogTimerStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.FeedInterval != nil {\n\t\tsize, err := (*durationpb.Duration)(m.FeedInterval).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Timeout != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Timeout).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Device) > 0 {\n\t\ti -= len(m.Device)\n\t\tcopy(dAtA[i:], m.Device)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Device)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *APIServiceConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ListenAddress)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.NodeRoutingDisabled {\n\t\tn += 2\n\t}\n\tif m.ReadonlyRoleMode {\n\t\tn += 2\n\t}\n\tif m.SkipVerifyingClientCert {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BootedEntrySpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.BootedEntry)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DevicesStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DiagnosticSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Message)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Details) > 0 {\n\t\tfor _, s := range m.Details {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EnvironmentSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Variables) > 0 {\n\t\tfor _, s := range m.Variables {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EventSinkConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Endpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtensionServiceConfigFile) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Content)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.MountPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtensionServiceConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Files) > 0 {\n\t\tfor _, e := range m.Files {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.Environment) > 0 {\n\t\tfor _, s := range m.Environment {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ExtensionServiceConfigStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.SpecVersion)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KernelCmdlineSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Cmdline)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KernelModuleSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Parameters) > 0 {\n\t\tfor _, s := range m.Parameters {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KernelParamSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.IgnoreErrors {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KernelParamStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Current)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Default)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Unsupported {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KmsgLogConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Destinations) > 0 {\n\t\tfor _, e := range m.Destinations {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *LoadedKernelModuleSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tif m.ReferenceCount != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.ReferenceCount))\n\t}\n\tif len(m.Dependencies) > 0 {\n\t\tfor _, s := range m.Dependencies {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.State)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Address)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Stage != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Stage))\n\t}\n\tif m.Status != nil {\n\t\tl = m.Status.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MachineStatusStatus) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ready {\n\t\tn += 2\n\t}\n\tif len(m.UnmetConditions) > 0 {\n\t\tfor _, e := range m.UnmetConditions {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MaintenanceServiceConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ListenAddress)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ReachableAddresses) > 0 {\n\t\tfor _, e := range m.ReachableAddresses {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaKeySpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Value)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MetaLoadedSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Done {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MountStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Source)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Target)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.FilesystemType)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Options) > 0 {\n\t\tfor _, s := range m.Options {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Encrypted {\n\t\tn += 2\n\t}\n\tif len(m.EncryptionProviders) > 0 {\n\t\tfor _, s := range m.EncryptionProviders {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *OOMActionSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.TriggerContext)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Score != 0 {\n\t\tn += 9\n\t}\n\tif len(m.Processes) > 0 {\n\t\tfor _, s := range m.Processes {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *PlatformMetadataSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Platform)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Hostname)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Region)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Zone)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.InstanceType)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.InstanceId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ProviderId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Spot {\n\t\tn += 2\n\t}\n\tl = len(m.InternalDns)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ExternalDns)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Tags) > 0 {\n\t\tfor k, v := range m.Tags {\n\t\t\t_ = k\n\t\t\t_ = v\n\t\t\tmapEntrySize := 1 + len(k) + protohelpers.SizeOfVarint(uint64(len(k))) + 1 + len(v) + protohelpers.SizeOfVarint(uint64(len(v)))\n\t\t\tn += mapEntrySize + 1 + protohelpers.SizeOfVarint(uint64(mapEntrySize))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SBOMItemSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Version)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.License)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.CpEs) > 0 {\n\t\tfor _, s := range m.CpEs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.PurLs) > 0 {\n\t\tfor _, s := range m.PurLs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.Extension {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *SecurityStateSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.SecureBoot {\n\t\tn += 2\n\t}\n\tl = len(m.UkiSigningKeyFingerprint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.PcrSigningKeyFingerprint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SeLinuxState != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.SeLinuxState))\n\t}\n\tif m.BootedWithUki {\n\t\tn += 2\n\t}\n\tif m.FipsState != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.FipsState))\n\t}\n\tif m.ModuleSignatureEnforced {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *UniqueMachineTokenSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Token)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *UnmetCondition) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Reason)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *WatchdogTimerConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Device)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Timeout != nil {\n\t\tl = (*durationpb.Duration)(m.Timeout).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *WatchdogTimerStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Device)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Timeout != nil {\n\t\tl = (*durationpb.Duration)(m.Timeout).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FeedInterval != nil {\n\t\tl = (*durationpb.Duration)(m.FeedInterval).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *APIServiceConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: APIServiceConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: APIServiceConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenAddress\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenAddress = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeRoutingDisabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.NodeRoutingDisabled = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReadonlyRoleMode\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ReadonlyRoleMode = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipVerifyingClientCert\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipVerifyingClientCert = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BootedEntrySpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BootedEntrySpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BootedEntrySpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootedEntry\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BootedEntry = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DevicesStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DevicesStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DevicesStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DiagnosticSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DiagnosticSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DiagnosticSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Message\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Message = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Details\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Details = append(m.Details, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EnvironmentSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EnvironmentSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EnvironmentSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Variables\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Variables = append(m.Variables, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EventSinkConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EventSinkConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EventSinkConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Endpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtensionServiceConfigFile) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigFile: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigFile: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Content\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Content = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MountPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.MountPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtensionServiceConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Files\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Files = append(m.Files, &ExtensionServiceConfigFile{})\n\t\t\tif err := m.Files[len(m.Files)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Environment\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Environment = append(m.Environment, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ExtensionServiceConfigStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ExtensionServiceConfigStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SpecVersion\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SpecVersion = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KernelCmdlineSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KernelCmdlineSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KernelCmdlineSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Cmdline\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Cmdline = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KernelModuleSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KernelModuleSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KernelModuleSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Parameters\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Parameters = append(m.Parameters, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KernelParamSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KernelParamSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KernelParamSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IgnoreErrors\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.IgnoreErrors = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KernelParamStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KernelParamStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KernelParamStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Current\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Current = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Default\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Default = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unsupported\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Unsupported = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KmsgLogConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KmsgLogConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KmsgLogConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Destinations\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Destinations = append(m.Destinations, &common.URL{})\n\t\t\tif unmarshal, ok := interface{}(m.Destinations[len(m.Destinations)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Destinations[len(m.Destinations)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *LoadedKernelModuleSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: LoadedKernelModuleSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: LoadedKernelModuleSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReferenceCount\", wireType)\n\t\t\t}\n\t\t\tm.ReferenceCount = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.ReferenceCount |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Dependencies\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Dependencies = append(m.Dependencies, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.State = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Address\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Address = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Stage\", wireType)\n\t\t\t}\n\t\t\tm.Stage = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Stage |= enums.RuntimeMachineStage(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Status == nil {\n\t\t\t\tm.Status = &MachineStatusStatus{}\n\t\t\t}\n\t\t\tif err := m.Status.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MachineStatusStatus) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusStatus: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MachineStatusStatus: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ready\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Ready = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UnmetConditions\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UnmetConditions = append(m.UnmetConditions, &UnmetCondition{})\n\t\t\tif err := m.UnmetConditions[len(m.UnmetConditions)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MaintenanceServiceConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MaintenanceServiceConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MaintenanceServiceConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ListenAddress\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ListenAddress = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ReachableAddresses\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ReachableAddresses = append(m.ReachableAddresses, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ReachableAddresses[len(m.ReachableAddresses)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ReachableAddresses[len(m.ReachableAddresses)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaKeySpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaKeySpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaKeySpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Value\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Value = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MetaLoadedSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MetaLoadedSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MetaLoadedSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Done\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Done = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MountStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MountStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MountStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Source\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Source = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Target\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Target = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FilesystemType\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.FilesystemType = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Options\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Options = append(m.Options, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Encrypted\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Encrypted = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EncryptionProviders\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.EncryptionProviders = append(m.EncryptionProviders, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *OOMActionSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: OOMActionSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: OOMActionSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field TriggerContext\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.TriggerContext = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Score\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.Score = float64(math.Float64frombits(v))\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Processes\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Processes = append(m.Processes, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *PlatformMetadataSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformMetadataSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: PlatformMetadataSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Platform\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Platform = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Hostname\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Hostname = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Region\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Region = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Zone\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Zone = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InstanceType\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InstanceType = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InstanceId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InstanceId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ProviderId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ProviderId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Spot\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Spot = bool(v != 0)\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field InternalDns\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.InternalDns = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ExternalDns\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ExternalDns = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tags\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Tags == nil {\n\t\t\t\tm.Tags = make(map[string]string)\n\t\t\t}\n\t\t\tvar mapkey string\n\t\t\tvar mapvalue string\n\t\t\tfor iNdEx < postIndex {\n\t\t\t\tentryPreIndex := iNdEx\n\t\t\t\tvar wire uint64\n\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t}\n\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\tiNdEx++\n\t\t\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfieldNum := int32(wire >> 3)\n\t\t\t\tif fieldNum == 1 {\n\t\t\t\t\tvar stringLenmapkey uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapkey |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapkey := int(stringLenmapkey)\n\t\t\t\t\tif intStringLenmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapkey := iNdEx + intStringLenmapkey\n\t\t\t\t\tif postStringIndexmapkey < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapkey > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapkey = string(dAtA[iNdEx:postStringIndexmapkey])\n\t\t\t\t\tiNdEx = postStringIndexmapkey\n\t\t\t\t} else if fieldNum == 2 {\n\t\t\t\t\tvar stringLenmapvalue uint64\n\t\t\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\t\t\tif shift >= 64 {\n\t\t\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif iNdEx >= l {\n\t\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t\t}\n\t\t\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\t\t\tiNdEx++\n\t\t\t\t\t\tstringLenmapvalue |= uint64(b&0x7F) << shift\n\t\t\t\t\t\tif b < 0x80 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tintStringLenmapvalue := int(stringLenmapvalue)\n\t\t\t\t\tif intStringLenmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tpostStringIndexmapvalue := iNdEx + intStringLenmapvalue\n\t\t\t\t\tif postStringIndexmapvalue < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif postStringIndexmapvalue > l {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tmapvalue = string(dAtA[iNdEx:postStringIndexmapvalue])\n\t\t\t\t\tiNdEx = postStringIndexmapvalue\n\t\t\t\t} else {\n\t\t\t\t\tiNdEx = entryPreIndex\n\t\t\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t\t\t}\n\t\t\t\t\tif (iNdEx + skippy) > postIndex {\n\t\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t\t}\n\t\t\t\t\tiNdEx += skippy\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tags[mapkey] = mapvalue\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SBOMItemSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SBOMItemSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SBOMItemSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Version\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Version = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field License\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.License = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CpEs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CpEs = append(m.CpEs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PurLs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PurLs = append(m.PurLs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Extension\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Extension = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *SecurityStateSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: SecurityStateSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: SecurityStateSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SecureBoot\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SecureBoot = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field UkiSigningKeyFingerprint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.UkiSigningKeyFingerprint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PcrSigningKeyFingerprint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.PcrSigningKeyFingerprint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SeLinuxState\", wireType)\n\t\t\t}\n\t\t\tm.SeLinuxState = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.SeLinuxState |= enums.RuntimeSELinuxState(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootedWithUki\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.BootedWithUki = bool(v != 0)\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FipsState\", wireType)\n\t\t\t}\n\t\t\tm.FipsState = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.FipsState |= enums.RuntimeFIPSState(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ModuleSignatureEnforced\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.ModuleSignatureEnforced = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *UniqueMachineTokenSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: UniqueMachineTokenSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: UniqueMachineTokenSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Token\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Token = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *UnmetCondition) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: UnmetCondition: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: UnmetCondition: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Reason\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Reason = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *WatchdogTimerConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: WatchdogTimerConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: WatchdogTimerConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Device\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Device = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timeout\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Timeout == nil {\n\t\t\t\tm.Timeout = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Timeout).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *WatchdogTimerStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: WatchdogTimerStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: WatchdogTimerStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Device\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Device = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Timeout\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Timeout == nil {\n\t\t\t\tm.Timeout = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Timeout).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FeedInterval\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.FeedInterval == nil {\n\t\t\t\tm.FeedInterval = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.FeedInterval).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/secrets/secrets.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/secrets/secrets.proto\n\npackage secrets\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// APICertsSpec describes etcd certs secrets.\ntype APICertsSpec struct {\n\tstate                   protoimpl.MessageState              `protogen:\"open.v1\"`\n\tClient                  *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,2,opt,name=client,proto3\" json:\"client,omitempty\"`\n\tServer                  *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,3,opt,name=server,proto3\" json:\"server,omitempty\"`\n\tAcceptedCAs             []*common.PEMEncodedCertificate     `protobuf:\"bytes,4,rep,name=accepted_c_as,json=acceptedCAs,proto3\" json:\"accepted_c_as,omitempty\"`\n\tSkipVerifyingClientCert bool                                `protobuf:\"varint,5,opt,name=skip_verifying_client_cert,json=skipVerifyingClientCert,proto3\" json:\"skip_verifying_client_cert,omitempty\"`\n\tunknownFields           protoimpl.UnknownFields\n\tsizeCache               protoimpl.SizeCache\n}\n\nfunc (x *APICertsSpec) Reset() {\n\t*x = APICertsSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *APICertsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*APICertsSpec) ProtoMessage() {}\n\nfunc (x *APICertsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use APICertsSpec.ProtoReflect.Descriptor instead.\nfunc (*APICertsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *APICertsSpec) GetClient() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.Client\n\t}\n\treturn nil\n}\n\nfunc (x *APICertsSpec) GetServer() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nfunc (x *APICertsSpec) GetAcceptedCAs() []*common.PEMEncodedCertificate {\n\tif x != nil {\n\t\treturn x.AcceptedCAs\n\t}\n\treturn nil\n}\n\nfunc (x *APICertsSpec) GetSkipVerifyingClientCert() bool {\n\tif x != nil {\n\t\treturn x.SkipVerifyingClientCert\n\t}\n\treturn false\n}\n\n// CertSANSpec describes fields of the cert SANs.\ntype CertSANSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIPs           []*common.NetIP        `protobuf:\"bytes,1,rep,name=i_ps,json=iPs,proto3\" json:\"i_ps,omitempty\"`\n\tDnsNames      []string               `protobuf:\"bytes,2,rep,name=dns_names,json=dnsNames,proto3\" json:\"dns_names,omitempty\"`\n\tFqdn          string                 `protobuf:\"bytes,3,opt,name=fqdn,proto3\" json:\"fqdn,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CertSANSpec) Reset() {\n\t*x = CertSANSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CertSANSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CertSANSpec) ProtoMessage() {}\n\nfunc (x *CertSANSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CertSANSpec.ProtoReflect.Descriptor instead.\nfunc (*CertSANSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *CertSANSpec) GetIPs() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.IPs\n\t}\n\treturn nil\n}\n\nfunc (x *CertSANSpec) GetDnsNames() []string {\n\tif x != nil {\n\t\treturn x.DnsNames\n\t}\n\treturn nil\n}\n\nfunc (x *CertSANSpec) GetFqdn() string {\n\tif x != nil {\n\t\treturn x.Fqdn\n\t}\n\treturn \"\"\n}\n\n// EncryptionSaltSpec describes the salt.\ntype EncryptionSaltSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tDiskSalt      []byte                 `protobuf:\"bytes,1,opt,name=disk_salt,json=diskSalt,proto3\" json:\"disk_salt,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EncryptionSaltSpec) Reset() {\n\t*x = EncryptionSaltSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EncryptionSaltSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EncryptionSaltSpec) ProtoMessage() {}\n\nfunc (x *EncryptionSaltSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EncryptionSaltSpec.ProtoReflect.Descriptor instead.\nfunc (*EncryptionSaltSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *EncryptionSaltSpec) GetDiskSalt() []byte {\n\tif x != nil {\n\t\treturn x.DiskSalt\n\t}\n\treturn nil\n}\n\n// EtcdCertsSpec describes etcd certs secrets.\ntype EtcdCertsSpec struct {\n\tstate         protoimpl.MessageState              `protogen:\"open.v1\"`\n\tEtcd          *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=etcd,proto3\" json:\"etcd,omitempty\"`\n\tEtcdPeer      *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,2,opt,name=etcd_peer,json=etcdPeer,proto3\" json:\"etcd_peer,omitempty\"`\n\tEtcdAdmin     *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,3,opt,name=etcd_admin,json=etcdAdmin,proto3\" json:\"etcd_admin,omitempty\"`\n\tEtcdApiServer *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,4,opt,name=etcd_api_server,json=etcdApiServer,proto3\" json:\"etcd_api_server,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdCertsSpec) Reset() {\n\t*x = EtcdCertsSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdCertsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdCertsSpec) ProtoMessage() {}\n\nfunc (x *EtcdCertsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdCertsSpec.ProtoReflect.Descriptor instead.\nfunc (*EtcdCertsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *EtcdCertsSpec) GetEtcd() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.Etcd\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdCertsSpec) GetEtcdPeer() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.EtcdPeer\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdCertsSpec) GetEtcdAdmin() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.EtcdAdmin\n\t}\n\treturn nil\n}\n\nfunc (x *EtcdCertsSpec) GetEtcdApiServer() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.EtcdApiServer\n\t}\n\treturn nil\n}\n\n// EtcdRootSpec describes etcd CA secrets.\ntype EtcdRootSpec struct {\n\tstate         protoimpl.MessageState              `protogen:\"open.v1\"`\n\tEtcdCa        *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=etcd_ca,json=etcdCa,proto3\" json:\"etcd_ca,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *EtcdRootSpec) Reset() {\n\t*x = EtcdRootSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *EtcdRootSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*EtcdRootSpec) ProtoMessage() {}\n\nfunc (x *EtcdRootSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use EtcdRootSpec.ProtoReflect.Descriptor instead.\nfunc (*EtcdRootSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *EtcdRootSpec) GetEtcdCa() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.EtcdCa\n\t}\n\treturn nil\n}\n\n// KubeletSpec describes root Kubernetes secrets.\ntype KubeletSpec struct {\n\tstate                protoimpl.MessageState          `protogen:\"open.v1\"`\n\tEndpoint             *common.URL                     `protobuf:\"bytes,1,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tBootstrapTokenId     string                          `protobuf:\"bytes,3,opt,name=bootstrap_token_id,json=bootstrapTokenId,proto3\" json:\"bootstrap_token_id,omitempty\"`\n\tBootstrapTokenSecret string                          `protobuf:\"bytes,4,opt,name=bootstrap_token_secret,json=bootstrapTokenSecret,proto3\" json:\"bootstrap_token_secret,omitempty\"`\n\tAcceptedCAs          []*common.PEMEncodedCertificate `protobuf:\"bytes,5,rep,name=accepted_c_as,json=acceptedCAs,proto3\" json:\"accepted_c_as,omitempty\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *KubeletSpec) Reset() {\n\t*x = KubeletSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubeletSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubeletSpec) ProtoMessage() {}\n\nfunc (x *KubeletSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubeletSpec.ProtoReflect.Descriptor instead.\nfunc (*KubeletSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *KubeletSpec) GetEndpoint() *common.URL {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn nil\n}\n\nfunc (x *KubeletSpec) GetBootstrapTokenId() string {\n\tif x != nil {\n\t\treturn x.BootstrapTokenId\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletSpec) GetBootstrapTokenSecret() string {\n\tif x != nil {\n\t\treturn x.BootstrapTokenSecret\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubeletSpec) GetAcceptedCAs() []*common.PEMEncodedCertificate {\n\tif x != nil {\n\t\treturn x.AcceptedCAs\n\t}\n\treturn nil\n}\n\n// KubernetesCertsSpec describes generated Kubernetes certificates.\ntype KubernetesCertsSpec struct {\n\tstate                       protoimpl.MessageState `protogen:\"open.v1\"`\n\tSchedulerKubeconfig         string                 `protobuf:\"bytes,4,opt,name=scheduler_kubeconfig,json=schedulerKubeconfig,proto3\" json:\"scheduler_kubeconfig,omitempty\"`\n\tControllerManagerKubeconfig string                 `protobuf:\"bytes,5,opt,name=controller_manager_kubeconfig,json=controllerManagerKubeconfig,proto3\" json:\"controller_manager_kubeconfig,omitempty\"`\n\tLocalhostAdminKubeconfig    string                 `protobuf:\"bytes,6,opt,name=localhost_admin_kubeconfig,json=localhostAdminKubeconfig,proto3\" json:\"localhost_admin_kubeconfig,omitempty\"`\n\tAdminKubeconfig             string                 `protobuf:\"bytes,7,opt,name=admin_kubeconfig,json=adminKubeconfig,proto3\" json:\"admin_kubeconfig,omitempty\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *KubernetesCertsSpec) Reset() {\n\t*x = KubernetesCertsSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubernetesCertsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubernetesCertsSpec) ProtoMessage() {}\n\nfunc (x *KubernetesCertsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubernetesCertsSpec.ProtoReflect.Descriptor instead.\nfunc (*KubernetesCertsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *KubernetesCertsSpec) GetSchedulerKubeconfig() string {\n\tif x != nil {\n\t\treturn x.SchedulerKubeconfig\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesCertsSpec) GetControllerManagerKubeconfig() string {\n\tif x != nil {\n\t\treturn x.ControllerManagerKubeconfig\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesCertsSpec) GetLocalhostAdminKubeconfig() string {\n\tif x != nil {\n\t\treturn x.LocalhostAdminKubeconfig\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesCertsSpec) GetAdminKubeconfig() string {\n\tif x != nil {\n\t\treturn x.AdminKubeconfig\n\t}\n\treturn \"\"\n}\n\n// KubernetesDynamicCertsSpec describes generated KubernetesCerts certificates.\ntype KubernetesDynamicCertsSpec struct {\n\tstate                  protoimpl.MessageState              `protogen:\"open.v1\"`\n\tApiServer              *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=api_server,json=apiServer,proto3\" json:\"api_server,omitempty\"`\n\tApiServerKubeletClient *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,2,opt,name=api_server_kubelet_client,json=apiServerKubeletClient,proto3\" json:\"api_server_kubelet_client,omitempty\"`\n\tFrontProxy             *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,3,opt,name=front_proxy,json=frontProxy,proto3\" json:\"front_proxy,omitempty\"`\n\tunknownFields          protoimpl.UnknownFields\n\tsizeCache              protoimpl.SizeCache\n}\n\nfunc (x *KubernetesDynamicCertsSpec) Reset() {\n\t*x = KubernetesDynamicCertsSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubernetesDynamicCertsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubernetesDynamicCertsSpec) ProtoMessage() {}\n\nfunc (x *KubernetesDynamicCertsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubernetesDynamicCertsSpec.ProtoReflect.Descriptor instead.\nfunc (*KubernetesDynamicCertsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *KubernetesDynamicCertsSpec) GetApiServer() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.ApiServer\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesDynamicCertsSpec) GetApiServerKubeletClient() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.ApiServerKubeletClient\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesDynamicCertsSpec) GetFrontProxy() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.FrontProxy\n\t}\n\treturn nil\n}\n\n// KubernetesRootSpec describes root Kubernetes secrets.\ntype KubernetesRootSpec struct {\n\tstate                     protoimpl.MessageState              `protogen:\"open.v1\"`\n\tName                      string                              `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tEndpoint                  *common.URL                         `protobuf:\"bytes,2,opt,name=endpoint,proto3\" json:\"endpoint,omitempty\"`\n\tLocalEndpoint             *common.URL                         `protobuf:\"bytes,3,opt,name=local_endpoint,json=localEndpoint,proto3\" json:\"local_endpoint,omitempty\"`\n\tCertSaNs                  []string                            `protobuf:\"bytes,4,rep,name=cert_sa_ns,json=certSaNs,proto3\" json:\"cert_sa_ns,omitempty\"`\n\tDnsDomain                 string                              `protobuf:\"bytes,6,opt,name=dns_domain,json=dnsDomain,proto3\" json:\"dns_domain,omitempty\"`\n\tIssuingCa                 *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,7,opt,name=issuing_ca,json=issuingCa,proto3\" json:\"issuing_ca,omitempty\"`\n\tServiceAccount            *common.PEMEncodedKey               `protobuf:\"bytes,8,opt,name=service_account,json=serviceAccount,proto3\" json:\"service_account,omitempty\"`\n\tAggregatorCa              *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,9,opt,name=aggregator_ca,json=aggregatorCa,proto3\" json:\"aggregator_ca,omitempty\"`\n\tAescbcEncryptionSecret    string                              `protobuf:\"bytes,10,opt,name=aescbc_encryption_secret,json=aescbcEncryptionSecret,proto3\" json:\"aescbc_encryption_secret,omitempty\"`\n\tBootstrapTokenId          string                              `protobuf:\"bytes,11,opt,name=bootstrap_token_id,json=bootstrapTokenId,proto3\" json:\"bootstrap_token_id,omitempty\"`\n\tBootstrapTokenSecret      string                              `protobuf:\"bytes,12,opt,name=bootstrap_token_secret,json=bootstrapTokenSecret,proto3\" json:\"bootstrap_token_secret,omitempty\"`\n\tSecretboxEncryptionSecret string                              `protobuf:\"bytes,13,opt,name=secretbox_encryption_secret,json=secretboxEncryptionSecret,proto3\" json:\"secretbox_encryption_secret,omitempty\"`\n\tApiServerIps              []*common.NetIP                     `protobuf:\"bytes,14,rep,name=api_server_ips,json=apiServerIps,proto3\" json:\"api_server_ips,omitempty\"`\n\tAcceptedCAs               []*common.PEMEncodedCertificate     `protobuf:\"bytes,15,rep,name=accepted_c_as,json=acceptedCAs,proto3\" json:\"accepted_c_as,omitempty\"`\n\tunknownFields             protoimpl.UnknownFields\n\tsizeCache                 protoimpl.SizeCache\n}\n\nfunc (x *KubernetesRootSpec) Reset() {\n\t*x = KubernetesRootSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *KubernetesRootSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KubernetesRootSpec) ProtoMessage() {}\n\nfunc (x *KubernetesRootSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KubernetesRootSpec.ProtoReflect.Descriptor instead.\nfunc (*KubernetesRootSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *KubernetesRootSpec) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetEndpoint() *common.URL {\n\tif x != nil {\n\t\treturn x.Endpoint\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetLocalEndpoint() *common.URL {\n\tif x != nil {\n\t\treturn x.LocalEndpoint\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetCertSaNs() []string {\n\tif x != nil {\n\t\treturn x.CertSaNs\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetDnsDomain() string {\n\tif x != nil {\n\t\treturn x.DnsDomain\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetIssuingCa() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.IssuingCa\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetServiceAccount() *common.PEMEncodedKey {\n\tif x != nil {\n\t\treturn x.ServiceAccount\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetAggregatorCa() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.AggregatorCa\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetAescbcEncryptionSecret() string {\n\tif x != nil {\n\t\treturn x.AescbcEncryptionSecret\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetBootstrapTokenId() string {\n\tif x != nil {\n\t\treturn x.BootstrapTokenId\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetBootstrapTokenSecret() string {\n\tif x != nil {\n\t\treturn x.BootstrapTokenSecret\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetSecretboxEncryptionSecret() string {\n\tif x != nil {\n\t\treturn x.SecretboxEncryptionSecret\n\t}\n\treturn \"\"\n}\n\nfunc (x *KubernetesRootSpec) GetApiServerIps() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.ApiServerIps\n\t}\n\treturn nil\n}\n\nfunc (x *KubernetesRootSpec) GetAcceptedCAs() []*common.PEMEncodedCertificate {\n\tif x != nil {\n\t\treturn x.AcceptedCAs\n\t}\n\treturn nil\n}\n\n// MaintenanceRootSpec describes maintenance service CA.\ntype MaintenanceRootSpec struct {\n\tstate         protoimpl.MessageState              `protogen:\"open.v1\"`\n\tCa            *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=ca,proto3\" json:\"ca,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *MaintenanceRootSpec) Reset() {\n\t*x = MaintenanceRootSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MaintenanceRootSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MaintenanceRootSpec) ProtoMessage() {}\n\nfunc (x *MaintenanceRootSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MaintenanceRootSpec.ProtoReflect.Descriptor instead.\nfunc (*MaintenanceRootSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *MaintenanceRootSpec) GetCa() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.Ca\n\t}\n\treturn nil\n}\n\n// OSRootSpec describes operating system CA.\ntype OSRootSpec struct {\n\tstate           protoimpl.MessageState              `protogen:\"open.v1\"`\n\tIssuingCa       *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,1,opt,name=issuing_ca,json=issuingCa,proto3\" json:\"issuing_ca,omitempty\"`\n\tCertSaniPs      []*common.NetIP                     `protobuf:\"bytes,2,rep,name=cert_sani_ps,json=certSaniPs,proto3\" json:\"cert_sani_ps,omitempty\"`\n\tCertSandnsNames []string                            `protobuf:\"bytes,3,rep,name=cert_sandns_names,json=certSandnsNames,proto3\" json:\"cert_sandns_names,omitempty\"`\n\tToken           string                              `protobuf:\"bytes,4,opt,name=token,proto3\" json:\"token,omitempty\"`\n\tAcceptedCAs     []*common.PEMEncodedCertificate     `protobuf:\"bytes,5,rep,name=accepted_c_as,json=acceptedCAs,proto3\" json:\"accepted_c_as,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *OSRootSpec) Reset() {\n\t*x = OSRootSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *OSRootSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*OSRootSpec) ProtoMessage() {}\n\nfunc (x *OSRootSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use OSRootSpec.ProtoReflect.Descriptor instead.\nfunc (*OSRootSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *OSRootSpec) GetIssuingCa() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.IssuingCa\n\t}\n\treturn nil\n}\n\nfunc (x *OSRootSpec) GetCertSaniPs() []*common.NetIP {\n\tif x != nil {\n\t\treturn x.CertSaniPs\n\t}\n\treturn nil\n}\n\nfunc (x *OSRootSpec) GetCertSandnsNames() []string {\n\tif x != nil {\n\t\treturn x.CertSandnsNames\n\t}\n\treturn nil\n}\n\nfunc (x *OSRootSpec) GetToken() string {\n\tif x != nil {\n\t\treturn x.Token\n\t}\n\treturn \"\"\n}\n\nfunc (x *OSRootSpec) GetAcceptedCAs() []*common.PEMEncodedCertificate {\n\tif x != nil {\n\t\treturn x.AcceptedCAs\n\t}\n\treturn nil\n}\n\n// TrustdCertsSpec describes etcd certs secrets.\ntype TrustdCertsSpec struct {\n\tstate         protoimpl.MessageState              `protogen:\"open.v1\"`\n\tServer        *common.PEMEncodedCertificateAndKey `protobuf:\"bytes,2,opt,name=server,proto3\" json:\"server,omitempty\"`\n\tAcceptedCAs   []*common.PEMEncodedCertificate     `protobuf:\"bytes,3,rep,name=accepted_c_as,json=acceptedCAs,proto3\" json:\"accepted_c_as,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TrustdCertsSpec) Reset() {\n\t*x = TrustdCertsSpec{}\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TrustdCertsSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TrustdCertsSpec) ProtoMessage() {}\n\nfunc (x *TrustdCertsSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_secrets_secrets_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TrustdCertsSpec.ProtoReflect.Descriptor instead.\nfunc (*TrustdCertsSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *TrustdCertsSpec) GetServer() *common.PEMEncodedCertificateAndKey {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn nil\n}\n\nfunc (x *TrustdCertsSpec) GetAcceptedCAs() []*common.PEMEncodedCertificate {\n\tif x != nil {\n\t\treturn x.AcceptedCAs\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_secrets_secrets_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_secrets_secrets_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"*resource/definitions/secrets/secrets.proto\\x12\\\"talos.resource.definitions.secrets\\x1a\\x13common/common.proto\\\"\\x88\\x02\\n\" +\n\t\"\\fAPICertsSpec\\x12;\\n\" +\n\t\"\\x06client\\x18\\x02 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x06client\\x12;\\n\" +\n\t\"\\x06server\\x18\\x03 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x06server\\x12A\\n\" +\n\t\"\\raccepted_c_as\\x18\\x04 \\x03(\\v2\\x1d.common.PEMEncodedCertificateR\\vacceptedCAs\\x12;\\n\" +\n\t\"\\x1askip_verifying_client_cert\\x18\\x05 \\x01(\\bR\\x17skipVerifyingClientCert\\\"`\\n\" +\n\t\"\\vCertSANSpec\\x12 \\n\" +\n\t\"\\x04i_ps\\x18\\x01 \\x03(\\v2\\r.common.NetIPR\\x03iPs\\x12\\x1b\\n\" +\n\t\"\\tdns_names\\x18\\x02 \\x03(\\tR\\bdnsNames\\x12\\x12\\n\" +\n\t\"\\x04fqdn\\x18\\x03 \\x01(\\tR\\x04fqdn\\\"1\\n\" +\n\t\"\\x12EncryptionSaltSpec\\x12\\x1b\\n\" +\n\t\"\\tdisk_salt\\x18\\x01 \\x01(\\fR\\bdiskSalt\\\"\\x9b\\x02\\n\" +\n\t\"\\rEtcdCertsSpec\\x127\\n\" +\n\t\"\\x04etcd\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x04etcd\\x12@\\n\" +\n\t\"\\tetcd_peer\\x18\\x02 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\betcdPeer\\x12B\\n\" +\n\t\"\\n\" +\n\t\"etcd_admin\\x18\\x03 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\tetcdAdmin\\x12K\\n\" +\n\t\"\\x0fetcd_api_server\\x18\\x04 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\retcdApiServer\\\"L\\n\" +\n\t\"\\fEtcdRootSpec\\x12<\\n\" +\n\t\"\\aetcd_ca\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x06etcdCa\\\"\\xdd\\x01\\n\" +\n\t\"\\vKubeletSpec\\x12'\\n\" +\n\t\"\\bendpoint\\x18\\x01 \\x01(\\v2\\v.common.URLR\\bendpoint\\x12,\\n\" +\n\t\"\\x12bootstrap_token_id\\x18\\x03 \\x01(\\tR\\x10bootstrapTokenId\\x124\\n\" +\n\t\"\\x16bootstrap_token_secret\\x18\\x04 \\x01(\\tR\\x14bootstrapTokenSecret\\x12A\\n\" +\n\t\"\\raccepted_c_as\\x18\\x05 \\x03(\\v2\\x1d.common.PEMEncodedCertificateR\\vacceptedCAs\\\"\\xf5\\x01\\n\" +\n\t\"\\x13KubernetesCertsSpec\\x121\\n\" +\n\t\"\\x14scheduler_kubeconfig\\x18\\x04 \\x01(\\tR\\x13schedulerKubeconfig\\x12B\\n\" +\n\t\"\\x1dcontroller_manager_kubeconfig\\x18\\x05 \\x01(\\tR\\x1bcontrollerManagerKubeconfig\\x12<\\n\" +\n\t\"\\x1alocalhost_admin_kubeconfig\\x18\\x06 \\x01(\\tR\\x18localhostAdminKubeconfig\\x12)\\n\" +\n\t\"\\x10admin_kubeconfig\\x18\\a \\x01(\\tR\\x0fadminKubeconfig\\\"\\x86\\x02\\n\" +\n\t\"\\x1aKubernetesDynamicCertsSpec\\x12B\\n\" +\n\t\"\\n\" +\n\t\"api_server\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\tapiServer\\x12^\\n\" +\n\t\"\\x19api_server_kubelet_client\\x18\\x02 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x16apiServerKubeletClient\\x12D\\n\" +\n\t\"\\vfront_proxy\\x18\\x03 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\n\" +\n\t\"frontProxy\\\"\\xe6\\x05\\n\" +\n\t\"\\x12KubernetesRootSpec\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12'\\n\" +\n\t\"\\bendpoint\\x18\\x02 \\x01(\\v2\\v.common.URLR\\bendpoint\\x122\\n\" +\n\t\"\\x0elocal_endpoint\\x18\\x03 \\x01(\\v2\\v.common.URLR\\rlocalEndpoint\\x12\\x1c\\n\" +\n\t\"\\n\" +\n\t\"cert_sa_ns\\x18\\x04 \\x03(\\tR\\bcertSaNs\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"dns_domain\\x18\\x06 \\x01(\\tR\\tdnsDomain\\x12B\\n\" +\n\t\"\\n\" +\n\t\"issuing_ca\\x18\\a \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\tissuingCa\\x12>\\n\" +\n\t\"\\x0fservice_account\\x18\\b \\x01(\\v2\\x15.common.PEMEncodedKeyR\\x0eserviceAccount\\x12H\\n\" +\n\t\"\\raggregator_ca\\x18\\t \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\faggregatorCa\\x128\\n\" +\n\t\"\\x18aescbc_encryption_secret\\x18\\n\" +\n\t\" \\x01(\\tR\\x16aescbcEncryptionSecret\\x12,\\n\" +\n\t\"\\x12bootstrap_token_id\\x18\\v \\x01(\\tR\\x10bootstrapTokenId\\x124\\n\" +\n\t\"\\x16bootstrap_token_secret\\x18\\f \\x01(\\tR\\x14bootstrapTokenSecret\\x12>\\n\" +\n\t\"\\x1bsecretbox_encryption_secret\\x18\\r \\x01(\\tR\\x19secretboxEncryptionSecret\\x123\\n\" +\n\t\"\\x0eapi_server_ips\\x18\\x0e \\x03(\\v2\\r.common.NetIPR\\fapiServerIps\\x12A\\n\" +\n\t\"\\raccepted_c_as\\x18\\x0f \\x03(\\v2\\x1d.common.PEMEncodedCertificateR\\vacceptedCAs\\\"J\\n\" +\n\t\"\\x13MaintenanceRootSpec\\x123\\n\" +\n\t\"\\x02ca\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x02ca\\\"\\x86\\x02\\n\" +\n\t\"\\n\" +\n\t\"OSRootSpec\\x12B\\n\" +\n\t\"\\n\" +\n\t\"issuing_ca\\x18\\x01 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\tissuingCa\\x12/\\n\" +\n\t\"\\fcert_sani_ps\\x18\\x02 \\x03(\\v2\\r.common.NetIPR\\n\" +\n\t\"certSaniPs\\x12*\\n\" +\n\t\"\\x11cert_sandns_names\\x18\\x03 \\x03(\\tR\\x0fcertSandnsNames\\x12\\x14\\n\" +\n\t\"\\x05token\\x18\\x04 \\x01(\\tR\\x05token\\x12A\\n\" +\n\t\"\\raccepted_c_as\\x18\\x05 \\x03(\\v2\\x1d.common.PEMEncodedCertificateR\\vacceptedCAs\\\"\\x91\\x01\\n\" +\n\t\"\\x0fTrustdCertsSpec\\x12;\\n\" +\n\t\"\\x06server\\x18\\x02 \\x01(\\v2#.common.PEMEncodedCertificateAndKeyR\\x06server\\x12A\\n\" +\n\t\"\\raccepted_c_as\\x18\\x03 \\x03(\\v2\\x1d.common.PEMEncodedCertificateR\\vacceptedCAsBx\\n\" +\n\t\"*dev.talos.api.resource.definitions.secretsZJgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/secretsb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_secrets_secrets_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_secrets_secrets_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_secrets_secrets_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_secrets_secrets_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_secrets_secrets_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_secrets_secrets_proto_rawDesc), len(file_resource_definitions_secrets_secrets_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_secrets_secrets_proto_rawDescData\n}\n\nvar file_resource_definitions_secrets_secrets_proto_msgTypes = make([]protoimpl.MessageInfo, 12)\nvar file_resource_definitions_secrets_secrets_proto_goTypes = []any{\n\t(*APICertsSpec)(nil),                       // 0: talos.resource.definitions.secrets.APICertsSpec\n\t(*CertSANSpec)(nil),                        // 1: talos.resource.definitions.secrets.CertSANSpec\n\t(*EncryptionSaltSpec)(nil),                 // 2: talos.resource.definitions.secrets.EncryptionSaltSpec\n\t(*EtcdCertsSpec)(nil),                      // 3: talos.resource.definitions.secrets.EtcdCertsSpec\n\t(*EtcdRootSpec)(nil),                       // 4: talos.resource.definitions.secrets.EtcdRootSpec\n\t(*KubeletSpec)(nil),                        // 5: talos.resource.definitions.secrets.KubeletSpec\n\t(*KubernetesCertsSpec)(nil),                // 6: talos.resource.definitions.secrets.KubernetesCertsSpec\n\t(*KubernetesDynamicCertsSpec)(nil),         // 7: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec\n\t(*KubernetesRootSpec)(nil),                 // 8: talos.resource.definitions.secrets.KubernetesRootSpec\n\t(*MaintenanceRootSpec)(nil),                // 9: talos.resource.definitions.secrets.MaintenanceRootSpec\n\t(*OSRootSpec)(nil),                         // 10: talos.resource.definitions.secrets.OSRootSpec\n\t(*TrustdCertsSpec)(nil),                    // 11: talos.resource.definitions.secrets.TrustdCertsSpec\n\t(*common.PEMEncodedCertificateAndKey)(nil), // 12: common.PEMEncodedCertificateAndKey\n\t(*common.PEMEncodedCertificate)(nil),       // 13: common.PEMEncodedCertificate\n\t(*common.NetIP)(nil),                       // 14: common.NetIP\n\t(*common.URL)(nil),                         // 15: common.URL\n\t(*common.PEMEncodedKey)(nil),               // 16: common.PEMEncodedKey\n}\nvar file_resource_definitions_secrets_secrets_proto_depIdxs = []int32{\n\t12, // 0: talos.resource.definitions.secrets.APICertsSpec.client:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 1: talos.resource.definitions.secrets.APICertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey\n\t13, // 2: talos.resource.definitions.secrets.APICertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate\n\t14, // 3: talos.resource.definitions.secrets.CertSANSpec.i_ps:type_name -> common.NetIP\n\t12, // 4: talos.resource.definitions.secrets.EtcdCertsSpec.etcd:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 5: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_peer:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 6: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_admin:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 7: talos.resource.definitions.secrets.EtcdCertsSpec.etcd_api_server:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 8: talos.resource.definitions.secrets.EtcdRootSpec.etcd_ca:type_name -> common.PEMEncodedCertificateAndKey\n\t15, // 9: talos.resource.definitions.secrets.KubeletSpec.endpoint:type_name -> common.URL\n\t13, // 10: talos.resource.definitions.secrets.KubeletSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate\n\t12, // 11: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 12: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.api_server_kubelet_client:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 13: talos.resource.definitions.secrets.KubernetesDynamicCertsSpec.front_proxy:type_name -> common.PEMEncodedCertificateAndKey\n\t15, // 14: talos.resource.definitions.secrets.KubernetesRootSpec.endpoint:type_name -> common.URL\n\t15, // 15: talos.resource.definitions.secrets.KubernetesRootSpec.local_endpoint:type_name -> common.URL\n\t12, // 16: talos.resource.definitions.secrets.KubernetesRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey\n\t16, // 17: talos.resource.definitions.secrets.KubernetesRootSpec.service_account:type_name -> common.PEMEncodedKey\n\t12, // 18: talos.resource.definitions.secrets.KubernetesRootSpec.aggregator_ca:type_name -> common.PEMEncodedCertificateAndKey\n\t14, // 19: talos.resource.definitions.secrets.KubernetesRootSpec.api_server_ips:type_name -> common.NetIP\n\t13, // 20: talos.resource.definitions.secrets.KubernetesRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate\n\t12, // 21: talos.resource.definitions.secrets.MaintenanceRootSpec.ca:type_name -> common.PEMEncodedCertificateAndKey\n\t12, // 22: talos.resource.definitions.secrets.OSRootSpec.issuing_ca:type_name -> common.PEMEncodedCertificateAndKey\n\t14, // 23: talos.resource.definitions.secrets.OSRootSpec.cert_sani_ps:type_name -> common.NetIP\n\t13, // 24: talos.resource.definitions.secrets.OSRootSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate\n\t12, // 25: talos.resource.definitions.secrets.TrustdCertsSpec.server:type_name -> common.PEMEncodedCertificateAndKey\n\t13, // 26: talos.resource.definitions.secrets.TrustdCertsSpec.accepted_c_as:type_name -> common.PEMEncodedCertificate\n\t27, // [27:27] is the sub-list for method output_type\n\t27, // [27:27] is the sub-list for method input_type\n\t27, // [27:27] is the sub-list for extension type_name\n\t27, // [27:27] is the sub-list for extension extendee\n\t0,  // [0:27] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_secrets_secrets_proto_init() }\nfunc file_resource_definitions_secrets_secrets_proto_init() {\n\tif File_resource_definitions_secrets_secrets_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_secrets_secrets_proto_rawDesc), len(file_resource_definitions_secrets_secrets_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   12,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_secrets_secrets_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_secrets_secrets_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_secrets_secrets_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_secrets_secrets_proto = out.File\n\tfile_resource_definitions_secrets_secrets_proto_goTypes = nil\n\tfile_resource_definitions_secrets_secrets_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/secrets/secrets_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/secrets/secrets.proto\n\npackage secrets\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *APICertsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *APICertsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *APICertsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SkipVerifyingClientCert {\n\t\ti--\n\t\tif m.SkipVerifyingClientCert {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor iNdEx := len(m.AcceptedCAs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AcceptedCAs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AcceptedCAs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.Server != nil {\n\t\tif vtmsg, ok := interface{}(m.Server).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Server)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Client != nil {\n\t\tif vtmsg, ok := interface{}(m.Client).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Client)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CertSANSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CertSANSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CertSANSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Fqdn) > 0 {\n\t\ti -= len(m.Fqdn)\n\t\tcopy(dAtA[i:], m.Fqdn)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Fqdn)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.DnsNames) > 0 {\n\t\tfor iNdEx := len(m.DnsNames) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.DnsNames[iNdEx])\n\t\t\tcopy(dAtA[i:], m.DnsNames[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DnsNames[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif len(m.IPs) > 0 {\n\t\tfor iNdEx := len(m.IPs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.IPs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.IPs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EncryptionSaltSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EncryptionSaltSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EncryptionSaltSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.DiskSalt) > 0 {\n\t\ti -= len(m.DiskSalt)\n\t\tcopy(dAtA[i:], m.DiskSalt)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskSalt)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdCertsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdCertsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdCertsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.EtcdApiServer != nil {\n\t\tif vtmsg, ok := interface{}(m.EtcdApiServer).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.EtcdApiServer)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.EtcdAdmin != nil {\n\t\tif vtmsg, ok := interface{}(m.EtcdAdmin).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.EtcdAdmin)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.EtcdPeer != nil {\n\t\tif vtmsg, ok := interface{}(m.EtcdPeer).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.EtcdPeer)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Etcd != nil {\n\t\tif vtmsg, ok := interface{}(m.Etcd).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Etcd)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *EtcdRootSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *EtcdRootSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *EtcdRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.EtcdCa != nil {\n\t\tif vtmsg, ok := interface{}(m.EtcdCa).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.EtcdCa)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubeletSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubeletSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubeletSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor iNdEx := len(m.AcceptedCAs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AcceptedCAs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AcceptedCAs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.BootstrapTokenSecret) > 0 {\n\t\ti -= len(m.BootstrapTokenSecret)\n\t\tcopy(dAtA[i:], m.BootstrapTokenSecret)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BootstrapTokenSecret)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.BootstrapTokenId) > 0 {\n\t\ti -= len(m.BootstrapTokenId)\n\t\tcopy(dAtA[i:], m.BootstrapTokenId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BootstrapTokenId)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Endpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.Endpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Endpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubernetesCertsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubernetesCertsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubernetesCertsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AdminKubeconfig) > 0 {\n\t\ti -= len(m.AdminKubeconfig)\n\t\tcopy(dAtA[i:], m.AdminKubeconfig)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AdminKubeconfig)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.LocalhostAdminKubeconfig) > 0 {\n\t\ti -= len(m.LocalhostAdminKubeconfig)\n\t\tcopy(dAtA[i:], m.LocalhostAdminKubeconfig)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LocalhostAdminKubeconfig)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.ControllerManagerKubeconfig) > 0 {\n\t\ti -= len(m.ControllerManagerKubeconfig)\n\t\tcopy(dAtA[i:], m.ControllerManagerKubeconfig)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ControllerManagerKubeconfig)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.SchedulerKubeconfig) > 0 {\n\t\ti -= len(m.SchedulerKubeconfig)\n\t\tcopy(dAtA[i:], m.SchedulerKubeconfig)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SchedulerKubeconfig)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubernetesDynamicCertsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubernetesDynamicCertsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubernetesDynamicCertsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.FrontProxy != nil {\n\t\tif vtmsg, ok := interface{}(m.FrontProxy).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.FrontProxy)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.ApiServerKubeletClient != nil {\n\t\tif vtmsg, ok := interface{}(m.ApiServerKubeletClient).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.ApiServerKubeletClient)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.ApiServer != nil {\n\t\tif vtmsg, ok := interface{}(m.ApiServer).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.ApiServer)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *KubernetesRootSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *KubernetesRootSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *KubernetesRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor iNdEx := len(m.AcceptedCAs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AcceptedCAs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AcceptedCAs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x7a\n\t\t}\n\t}\n\tif len(m.ApiServerIps) > 0 {\n\t\tfor iNdEx := len(m.ApiServerIps) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.ApiServerIps[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.ApiServerIps[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x72\n\t\t}\n\t}\n\tif len(m.SecretboxEncryptionSecret) > 0 {\n\t\ti -= len(m.SecretboxEncryptionSecret)\n\t\tcopy(dAtA[i:], m.SecretboxEncryptionSecret)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SecretboxEncryptionSecret)))\n\t\ti--\n\t\tdAtA[i] = 0x6a\n\t}\n\tif len(m.BootstrapTokenSecret) > 0 {\n\t\ti -= len(m.BootstrapTokenSecret)\n\t\tcopy(dAtA[i:], m.BootstrapTokenSecret)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BootstrapTokenSecret)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif len(m.BootstrapTokenId) > 0 {\n\t\ti -= len(m.BootstrapTokenId)\n\t\tcopy(dAtA[i:], m.BootstrapTokenId)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BootstrapTokenId)))\n\t\ti--\n\t\tdAtA[i] = 0x5a\n\t}\n\tif len(m.AescbcEncryptionSecret) > 0 {\n\t\ti -= len(m.AescbcEncryptionSecret)\n\t\tcopy(dAtA[i:], m.AescbcEncryptionSecret)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.AescbcEncryptionSecret)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.AggregatorCa != nil {\n\t\tif vtmsg, ok := interface{}(m.AggregatorCa).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.AggregatorCa)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x4a\n\t}\n\tif m.ServiceAccount != nil {\n\t\tif vtmsg, ok := interface{}(m.ServiceAccount).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.ServiceAccount)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.IssuingCa != nil {\n\t\tif vtmsg, ok := interface{}(m.IssuingCa).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.IssuingCa)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.DnsDomain) > 0 {\n\t\ti -= len(m.DnsDomain)\n\t\tcopy(dAtA[i:], m.DnsDomain)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DnsDomain)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.CertSaNs) > 0 {\n\t\tfor iNdEx := len(m.CertSaNs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.CertSaNs[iNdEx])\n\t\t\tcopy(dAtA[i:], m.CertSaNs[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CertSaNs[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x22\n\t\t}\n\t}\n\tif m.LocalEndpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.LocalEndpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.LocalEndpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Endpoint != nil {\n\t\tif vtmsg, ok := interface{}(m.Endpoint).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Endpoint)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *MaintenanceRootSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *MaintenanceRootSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *MaintenanceRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Ca != nil {\n\t\tif vtmsg, ok := interface{}(m.Ca).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Ca)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *OSRootSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *OSRootSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *OSRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor iNdEx := len(m.AcceptedCAs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AcceptedCAs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AcceptedCAs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x2a\n\t\t}\n\t}\n\tif len(m.Token) > 0 {\n\t\ti -= len(m.Token)\n\t\tcopy(dAtA[i:], m.Token)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Token)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.CertSandnsNames) > 0 {\n\t\tfor iNdEx := len(m.CertSandnsNames) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\ti -= len(m.CertSandnsNames[iNdEx])\n\t\t\tcopy(dAtA[i:], m.CertSandnsNames[iNdEx])\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CertSandnsNames[iNdEx])))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif len(m.CertSaniPs) > 0 {\n\t\tfor iNdEx := len(m.CertSaniPs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.CertSaniPs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.CertSaniPs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.IssuingCa != nil {\n\t\tif vtmsg, ok := interface{}(m.IssuingCa).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.IssuingCa)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TrustdCertsSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TrustdCertsSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TrustdCertsSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor iNdEx := len(m.AcceptedCAs) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tif vtmsg, ok := interface{}(m.AcceptedCAs[iNdEx]).(interface {\n\t\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t\t}); ok {\n\t\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= size\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\t} else {\n\t\t\t\tencoded, err := proto.Marshal(m.AcceptedCAs[iNdEx])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 0, err\n\t\t\t\t}\n\t\t\t\ti -= len(encoded)\n\t\t\t\tcopy(dAtA[i:], encoded)\n\t\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t\t}\n\t\t\ti--\n\t\t\tdAtA[i] = 0x1a\n\t\t}\n\t}\n\tif m.Server != nil {\n\t\tif vtmsg, ok := interface{}(m.Server).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Server)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *APICertsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Client != nil {\n\t\tif size, ok := interface{}(m.Client).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Client)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Server != nil {\n\t\tif size, ok := interface{}(m.Server).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Server)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor _, e := range m.AcceptedCAs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif m.SkipVerifyingClientCert {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CertSANSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.IPs) > 0 {\n\t\tfor _, e := range m.IPs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.DnsNames) > 0 {\n\t\tfor _, s := range m.DnsNames {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Fqdn)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EncryptionSaltSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.DiskSalt)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdCertsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Etcd != nil {\n\t\tif size, ok := interface{}(m.Etcd).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Etcd)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EtcdPeer != nil {\n\t\tif size, ok := interface{}(m.EtcdPeer).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.EtcdPeer)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EtcdAdmin != nil {\n\t\tif size, ok := interface{}(m.EtcdAdmin).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.EtcdAdmin)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EtcdApiServer != nil {\n\t\tif size, ok := interface{}(m.EtcdApiServer).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.EtcdApiServer)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *EtcdRootSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.EtcdCa != nil {\n\t\tif size, ok := interface{}(m.EtcdCa).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.EtcdCa)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubeletSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Endpoint != nil {\n\t\tif size, ok := interface{}(m.Endpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Endpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BootstrapTokenId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BootstrapTokenSecret)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor _, e := range m.AcceptedCAs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubernetesCertsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.SchedulerKubeconfig)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.ControllerManagerKubeconfig)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.LocalhostAdminKubeconfig)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.AdminKubeconfig)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubernetesDynamicCertsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.ApiServer != nil {\n\t\tif size, ok := interface{}(m.ApiServer).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.ApiServer)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ApiServerKubeletClient != nil {\n\t\tif size, ok := interface{}(m.ApiServerKubeletClient).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.ApiServerKubeletClient)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FrontProxy != nil {\n\t\tif size, ok := interface{}(m.FrontProxy).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.FrontProxy)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *KubernetesRootSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Endpoint != nil {\n\t\tif size, ok := interface{}(m.Endpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Endpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.LocalEndpoint != nil {\n\t\tif size, ok := interface{}(m.LocalEndpoint).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.LocalEndpoint)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.CertSaNs) > 0 {\n\t\tfor _, s := range m.CertSaNs {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.DnsDomain)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.IssuingCa != nil {\n\t\tif size, ok := interface{}(m.IssuingCa).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.IssuingCa)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.ServiceAccount != nil {\n\t\tif size, ok := interface{}(m.ServiceAccount).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.ServiceAccount)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.AggregatorCa != nil {\n\t\tif size, ok := interface{}(m.AggregatorCa).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.AggregatorCa)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.AescbcEncryptionSecret)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BootstrapTokenId)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.BootstrapTokenSecret)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SecretboxEncryptionSecret)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.ApiServerIps) > 0 {\n\t\tfor _, e := range m.ApiServerIps {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor _, e := range m.AcceptedCAs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *MaintenanceRootSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Ca != nil {\n\t\tif size, ok := interface{}(m.Ca).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Ca)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *OSRootSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.IssuingCa != nil {\n\t\tif size, ok := interface{}(m.IssuingCa).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.IssuingCa)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.CertSaniPs) > 0 {\n\t\tfor _, e := range m.CertSaniPs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tif len(m.CertSandnsNames) > 0 {\n\t\tfor _, s := range m.CertSandnsNames {\n\t\t\tl = len(s)\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tl = len(m.Token)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor _, e := range m.AcceptedCAs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TrustdCertsSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Server != nil {\n\t\tif size, ok := interface{}(m.Server).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Server)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.AcceptedCAs) > 0 {\n\t\tfor _, e := range m.AcceptedCAs {\n\t\t\tif size, ok := interface{}(e).(interface {\n\t\t\t\tSizeVT() int\n\t\t\t}); ok {\n\t\t\t\tl = size.SizeVT()\n\t\t\t} else {\n\t\t\t\tl = proto.Size(e)\n\t\t\t}\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *APICertsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: APICertsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: APICertsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Client\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Client == nil {\n\t\t\t\tm.Client = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Client).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Client); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Server\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Server == nil {\n\t\t\t\tm.Server = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Server).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Server); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AcceptedCAs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AcceptedCAs = append(m.AcceptedCAs, &common.PEMEncodedCertificate{})\n\t\t\tif unmarshal, ok := interface{}(m.AcceptedCAs[len(m.AcceptedCAs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AcceptedCAs[len(m.AcceptedCAs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipVerifyingClientCert\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipVerifyingClientCert = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CertSANSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CertSANSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CertSANSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IPs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.IPs = append(m.IPs, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.IPs[len(m.IPs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.IPs[len(m.IPs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsNames\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsNames = append(m.DnsNames, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Fqdn\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Fqdn = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EncryptionSaltSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionSaltSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EncryptionSaltSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DiskSalt\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DiskSalt = append(m.DiskSalt[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.DiskSalt == nil {\n\t\t\t\tm.DiskSalt = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdCertsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdCertsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdCertsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Etcd\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Etcd == nil {\n\t\t\t\tm.Etcd = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Etcd).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Etcd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcdPeer\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EtcdPeer == nil {\n\t\t\t\tm.EtcdPeer = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.EtcdPeer).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.EtcdPeer); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcdAdmin\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EtcdAdmin == nil {\n\t\t\t\tm.EtcdAdmin = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.EtcdAdmin).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.EtcdAdmin); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcdApiServer\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EtcdApiServer == nil {\n\t\t\t\tm.EtcdApiServer = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.EtcdApiServer).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.EtcdApiServer); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *EtcdRootSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRootSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: EtcdRootSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EtcdCa\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EtcdCa == nil {\n\t\t\t\tm.EtcdCa = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.EtcdCa).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.EtcdCa); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubeletSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubeletSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Endpoint == nil {\n\t\t\t\tm.Endpoint = &common.URL{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Endpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootstrapTokenId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BootstrapTokenId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootstrapTokenSecret\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BootstrapTokenSecret = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AcceptedCAs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AcceptedCAs = append(m.AcceptedCAs, &common.PEMEncodedCertificate{})\n\t\t\tif unmarshal, ok := interface{}(m.AcceptedCAs[len(m.AcceptedCAs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AcceptedCAs[len(m.AcceptedCAs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubernetesCertsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesCertsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesCertsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SchedulerKubeconfig\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SchedulerKubeconfig = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ControllerManagerKubeconfig\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ControllerManagerKubeconfig = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LocalhostAdminKubeconfig\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LocalhostAdminKubeconfig = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AdminKubeconfig\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AdminKubeconfig = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubernetesDynamicCertsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesDynamicCertsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesDynamicCertsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiServer\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ApiServer == nil {\n\t\t\t\tm.ApiServer = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.ApiServer).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ApiServer); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiServerKubeletClient\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ApiServerKubeletClient == nil {\n\t\t\t\tm.ApiServerKubeletClient = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.ApiServerKubeletClient).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ApiServerKubeletClient); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FrontProxy\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.FrontProxy == nil {\n\t\t\t\tm.FrontProxy = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.FrontProxy).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.FrontProxy); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *KubernetesRootSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesRootSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: KubernetesRootSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Endpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Endpoint == nil {\n\t\t\t\tm.Endpoint = &common.URL{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Endpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Endpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LocalEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LocalEndpoint == nil {\n\t\t\t\tm.LocalEndpoint = &common.URL{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.LocalEndpoint).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.LocalEndpoint); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CertSaNs\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CertSaNs = append(m.CertSaNs, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DnsDomain\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DnsDomain = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IssuingCa\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.IssuingCa == nil {\n\t\t\t\tm.IssuingCa = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.IssuingCa).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.IssuingCa); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ServiceAccount\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.ServiceAccount == nil {\n\t\t\t\tm.ServiceAccount = &common.PEMEncodedKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.ServiceAccount).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ServiceAccount); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AggregatorCa\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.AggregatorCa == nil {\n\t\t\t\tm.AggregatorCa = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.AggregatorCa).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AggregatorCa); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AescbcEncryptionSecret\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AescbcEncryptionSecret = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootstrapTokenId\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BootstrapTokenId = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BootstrapTokenSecret\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BootstrapTokenSecret = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SecretboxEncryptionSecret\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SecretboxEncryptionSecret = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 14:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiServerIps\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApiServerIps = append(m.ApiServerIps, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.ApiServerIps[len(m.ApiServerIps)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.ApiServerIps[len(m.ApiServerIps)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 15:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AcceptedCAs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AcceptedCAs = append(m.AcceptedCAs, &common.PEMEncodedCertificate{})\n\t\t\tif unmarshal, ok := interface{}(m.AcceptedCAs[len(m.AcceptedCAs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AcceptedCAs[len(m.AcceptedCAs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *MaintenanceRootSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: MaintenanceRootSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: MaintenanceRootSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ca\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Ca == nil {\n\t\t\t\tm.Ca = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Ca).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Ca); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *OSRootSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: OSRootSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: OSRootSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field IssuingCa\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.IssuingCa == nil {\n\t\t\t\tm.IssuingCa = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.IssuingCa).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.IssuingCa); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CertSaniPs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CertSaniPs = append(m.CertSaniPs, &common.NetIP{})\n\t\t\tif unmarshal, ok := interface{}(m.CertSaniPs[len(m.CertSaniPs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.CertSaniPs[len(m.CertSaniPs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field CertSandnsNames\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.CertSandnsNames = append(m.CertSandnsNames, string(dAtA[iNdEx:postIndex]))\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Token\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Token = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AcceptedCAs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AcceptedCAs = append(m.AcceptedCAs, &common.PEMEncodedCertificate{})\n\t\t\tif unmarshal, ok := interface{}(m.AcceptedCAs[len(m.AcceptedCAs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AcceptedCAs[len(m.AcceptedCAs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TrustdCertsSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TrustdCertsSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TrustdCertsSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Server\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Server == nil {\n\t\t\t\tm.Server = &common.PEMEncodedCertificateAndKey{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Server).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Server); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field AcceptedCAs\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.AcceptedCAs = append(m.AcceptedCAs, &common.PEMEncodedCertificate{})\n\t\t\tif unmarshal, ok := interface{}(m.AcceptedCAs[len(m.AcceptedCAs)-1]).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.AcceptedCAs[len(m.AcceptedCAs)-1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/security/security.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/security/security.proto\n\npackage security\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ImageKeylessVerifierSpec represents a signature verification provider.\ntype ImageKeylessVerifierSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tIssuer        string                 `protobuf:\"bytes,1,opt,name=issuer,proto3\" json:\"issuer,omitempty\"`\n\tSubject       string                 `protobuf:\"bytes,2,opt,name=subject,proto3\" json:\"subject,omitempty\"`\n\tSubjectRegex  string                 `protobuf:\"bytes,3,opt,name=subject_regex,json=subjectRegex,proto3\" json:\"subject_regex,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImageKeylessVerifierSpec) Reset() {\n\t*x = ImageKeylessVerifierSpec{}\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageKeylessVerifierSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageKeylessVerifierSpec) ProtoMessage() {}\n\nfunc (x *ImageKeylessVerifierSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageKeylessVerifierSpec.ProtoReflect.Descriptor instead.\nfunc (*ImageKeylessVerifierSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_security_security_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ImageKeylessVerifierSpec) GetIssuer() string {\n\tif x != nil {\n\t\treturn x.Issuer\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageKeylessVerifierSpec) GetSubject() string {\n\tif x != nil {\n\t\treturn x.Subject\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageKeylessVerifierSpec) GetSubjectRegex() string {\n\tif x != nil {\n\t\treturn x.SubjectRegex\n\t}\n\treturn \"\"\n}\n\n// ImagePublicKeyVerifierSpec represents a signature verification provider with static public key.\ntype ImagePublicKeyVerifierSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tCertificate   string                 `protobuf:\"bytes,1,opt,name=certificate,proto3\" json:\"certificate,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ImagePublicKeyVerifierSpec) Reset() {\n\t*x = ImagePublicKeyVerifierSpec{}\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImagePublicKeyVerifierSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImagePublicKeyVerifierSpec) ProtoMessage() {}\n\nfunc (x *ImagePublicKeyVerifierSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImagePublicKeyVerifierSpec.ProtoReflect.Descriptor instead.\nfunc (*ImagePublicKeyVerifierSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_security_security_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ImagePublicKeyVerifierSpec) GetCertificate() string {\n\tif x != nil {\n\t\treturn x.Certificate\n\t}\n\treturn \"\"\n}\n\n// ImageVerificationRuleSpec represents a verification rule.\ntype ImageVerificationRuleSpec struct {\n\tstate             protoimpl.MessageState      `protogen:\"open.v1\"`\n\tImagePattern      string                      `protobuf:\"bytes,2,opt,name=image_pattern,json=imagePattern,proto3\" json:\"image_pattern,omitempty\"`\n\tSkip              bool                        `protobuf:\"varint,3,opt,name=skip,proto3\" json:\"skip,omitempty\"`\n\tDeny              bool                        `protobuf:\"varint,4,opt,name=deny,proto3\" json:\"deny,omitempty\"`\n\tKeylessVerifier   *ImageKeylessVerifierSpec   `protobuf:\"bytes,5,opt,name=keyless_verifier,json=keylessVerifier,proto3\" json:\"keyless_verifier,omitempty\"`\n\tPublicKeyVerifier *ImagePublicKeyVerifierSpec `protobuf:\"bytes,6,opt,name=public_key_verifier,json=publicKeyVerifier,proto3\" json:\"public_key_verifier,omitempty\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *ImageVerificationRuleSpec) Reset() {\n\t*x = ImageVerificationRuleSpec{}\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ImageVerificationRuleSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ImageVerificationRuleSpec) ProtoMessage() {}\n\nfunc (x *ImageVerificationRuleSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ImageVerificationRuleSpec.ProtoReflect.Descriptor instead.\nfunc (*ImageVerificationRuleSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_security_security_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *ImageVerificationRuleSpec) GetImagePattern() string {\n\tif x != nil {\n\t\treturn x.ImagePattern\n\t}\n\treturn \"\"\n}\n\nfunc (x *ImageVerificationRuleSpec) GetSkip() bool {\n\tif x != nil {\n\t\treturn x.Skip\n\t}\n\treturn false\n}\n\nfunc (x *ImageVerificationRuleSpec) GetDeny() bool {\n\tif x != nil {\n\t\treturn x.Deny\n\t}\n\treturn false\n}\n\nfunc (x *ImageVerificationRuleSpec) GetKeylessVerifier() *ImageKeylessVerifierSpec {\n\tif x != nil {\n\t\treturn x.KeylessVerifier\n\t}\n\treturn nil\n}\n\nfunc (x *ImageVerificationRuleSpec) GetPublicKeyVerifier() *ImagePublicKeyVerifierSpec {\n\tif x != nil {\n\t\treturn x.PublicKeyVerifier\n\t}\n\treturn nil\n}\n\n// TUFTrustedRootSpec represents a sigstore's TUF trusted root information.\ntype TUFTrustedRootSpec struct {\n\tstate           protoimpl.MessageState `protogen:\"open.v1\"`\n\tLastRefreshTime *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=last_refresh_time,json=lastRefreshTime,proto3\" json:\"last_refresh_time,omitempty\"`\n\tJsonData        string                 `protobuf:\"bytes,2,opt,name=json_data,json=jsonData,proto3\" json:\"json_data,omitempty\"`\n\tunknownFields   protoimpl.UnknownFields\n\tsizeCache       protoimpl.SizeCache\n}\n\nfunc (x *TUFTrustedRootSpec) Reset() {\n\t*x = TUFTrustedRootSpec{}\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TUFTrustedRootSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TUFTrustedRootSpec) ProtoMessage() {}\n\nfunc (x *TUFTrustedRootSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_security_security_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TUFTrustedRootSpec.ProtoReflect.Descriptor instead.\nfunc (*TUFTrustedRootSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_security_security_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *TUFTrustedRootSpec) GetLastRefreshTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.LastRefreshTime\n\t}\n\treturn nil\n}\n\nfunc (x *TUFTrustedRootSpec) GetJsonData() string {\n\tif x != nil {\n\t\treturn x.JsonData\n\t}\n\treturn \"\"\n}\n\nvar File_resource_definitions_security_security_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_security_security_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\",resource/definitions/security/security.proto\\x12#talos.resource.definitions.security\\x1a\\x1fgoogle/protobuf/timestamp.proto\\\"q\\n\" +\n\t\"\\x18ImageKeylessVerifierSpec\\x12\\x16\\n\" +\n\t\"\\x06issuer\\x18\\x01 \\x01(\\tR\\x06issuer\\x12\\x18\\n\" +\n\t\"\\asubject\\x18\\x02 \\x01(\\tR\\asubject\\x12#\\n\" +\n\t\"\\rsubject_regex\\x18\\x03 \\x01(\\tR\\fsubjectRegex\\\">\\n\" +\n\t\"\\x1aImagePublicKeyVerifierSpec\\x12 \\n\" +\n\t\"\\vcertificate\\x18\\x01 \\x01(\\tR\\vcertificate\\\"\\xc3\\x02\\n\" +\n\t\"\\x19ImageVerificationRuleSpec\\x12#\\n\" +\n\t\"\\rimage_pattern\\x18\\x02 \\x01(\\tR\\fimagePattern\\x12\\x12\\n\" +\n\t\"\\x04skip\\x18\\x03 \\x01(\\bR\\x04skip\\x12\\x12\\n\" +\n\t\"\\x04deny\\x18\\x04 \\x01(\\bR\\x04deny\\x12h\\n\" +\n\t\"\\x10keyless_verifier\\x18\\x05 \\x01(\\v2=.talos.resource.definitions.security.ImageKeylessVerifierSpecR\\x0fkeylessVerifier\\x12o\\n\" +\n\t\"\\x13public_key_verifier\\x18\\x06 \\x01(\\v2?.talos.resource.definitions.security.ImagePublicKeyVerifierSpecR\\x11publicKeyVerifier\\\"y\\n\" +\n\t\"\\x12TUFTrustedRootSpec\\x12F\\n\" +\n\t\"\\x11last_refresh_time\\x18\\x01 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\x0flastRefreshTime\\x12\\x1b\\n\" +\n\t\"\\tjson_data\\x18\\x02 \\x01(\\tR\\bjsonDataBz\\n\" +\n\t\"+dev.talos.api.resource.definitions.securityZKgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/securityb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_security_security_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_security_security_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_security_security_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_security_security_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_security_security_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_security_security_proto_rawDesc), len(file_resource_definitions_security_security_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_security_security_proto_rawDescData\n}\n\nvar file_resource_definitions_security_security_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_resource_definitions_security_security_proto_goTypes = []any{\n\t(*ImageKeylessVerifierSpec)(nil),   // 0: talos.resource.definitions.security.ImageKeylessVerifierSpec\n\t(*ImagePublicKeyVerifierSpec)(nil), // 1: talos.resource.definitions.security.ImagePublicKeyVerifierSpec\n\t(*ImageVerificationRuleSpec)(nil),  // 2: talos.resource.definitions.security.ImageVerificationRuleSpec\n\t(*TUFTrustedRootSpec)(nil),         // 3: talos.resource.definitions.security.TUFTrustedRootSpec\n\t(*timestamppb.Timestamp)(nil),      // 4: google.protobuf.Timestamp\n}\nvar file_resource_definitions_security_security_proto_depIdxs = []int32{\n\t0, // 0: talos.resource.definitions.security.ImageVerificationRuleSpec.keyless_verifier:type_name -> talos.resource.definitions.security.ImageKeylessVerifierSpec\n\t1, // 1: talos.resource.definitions.security.ImageVerificationRuleSpec.public_key_verifier:type_name -> talos.resource.definitions.security.ImagePublicKeyVerifierSpec\n\t4, // 2: talos.resource.definitions.security.TUFTrustedRootSpec.last_refresh_time:type_name -> google.protobuf.Timestamp\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_security_security_proto_init() }\nfunc file_resource_definitions_security_security_proto_init() {\n\tif File_resource_definitions_security_security_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_security_security_proto_rawDesc), len(file_resource_definitions_security_security_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_security_security_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_security_security_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_security_security_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_security_security_proto = out.File\n\tfile_resource_definitions_security_security_proto_goTypes = nil\n\tfile_resource_definitions_security_security_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/security/security_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/security/security.proto\n\npackage security\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\ttimestamppb \"github.com/planetscale/vtprotobuf/types/known/timestamppb\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb1 \"google.golang.org/protobuf/types/known/timestamppb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ImageKeylessVerifierSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageKeylessVerifierSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageKeylessVerifierSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.SubjectRegex) > 0 {\n\t\ti -= len(m.SubjectRegex)\n\t\tcopy(dAtA[i:], m.SubjectRegex)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.SubjectRegex)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Subject) > 0 {\n\t\ti -= len(m.Subject)\n\t\tcopy(dAtA[i:], m.Subject)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Subject)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Issuer) > 0 {\n\t\ti -= len(m.Issuer)\n\t\tcopy(dAtA[i:], m.Issuer)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Issuer)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImagePublicKeyVerifierSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImagePublicKeyVerifierSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImagePublicKeyVerifierSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Certificate) > 0 {\n\t\ti -= len(m.Certificate)\n\t\tcopy(dAtA[i:], m.Certificate)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Certificate)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageVerificationRuleSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ImageVerificationRuleSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ImageVerificationRuleSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.PublicKeyVerifier != nil {\n\t\tsize, err := m.PublicKeyVerifier.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif m.KeylessVerifier != nil {\n\t\tsize, err := m.KeylessVerifier.MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.Deny {\n\t\ti--\n\t\tif m.Deny {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.Skip {\n\t\ti--\n\t\tif m.Skip {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.ImagePattern) > 0 {\n\t\ti -= len(m.ImagePattern)\n\t\tcopy(dAtA[i:], m.ImagePattern)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ImagePattern)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TUFTrustedRootSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TUFTrustedRootSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TUFTrustedRootSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.JsonData) > 0 {\n\t\ti -= len(m.JsonData)\n\t\tcopy(dAtA[i:], m.JsonData)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.JsonData)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.LastRefreshTime != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.LastRefreshTime).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ImageKeylessVerifierSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Issuer)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Subject)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.SubjectRegex)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImagePublicKeyVerifierSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Certificate)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageVerificationRuleSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ImagePattern)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Skip {\n\t\tn += 2\n\t}\n\tif m.Deny {\n\t\tn += 2\n\t}\n\tif m.KeylessVerifier != nil {\n\t\tl = m.KeylessVerifier.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.PublicKeyVerifier != nil {\n\t\tl = m.PublicKeyVerifier.SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TUFTrustedRootSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.LastRefreshTime != nil {\n\t\tl = (*timestamppb.Timestamp)(m.LastRefreshTime).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.JsonData)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ImageKeylessVerifierSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageKeylessVerifierSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageKeylessVerifierSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Issuer\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Issuer = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Subject\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Subject = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SubjectRegex\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.SubjectRegex = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImagePublicKeyVerifierSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePublicKeyVerifierSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImagePublicKeyVerifierSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Certificate\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Certificate = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *ImageVerificationRuleSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ImageVerificationRuleSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ImageVerificationRuleSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ImagePattern\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ImagePattern = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Skip\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Skip = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Deny\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Deny = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field KeylessVerifier\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.KeylessVerifier == nil {\n\t\t\t\tm.KeylessVerifier = &ImageKeylessVerifierSpec{}\n\t\t\t}\n\t\t\tif err := m.KeylessVerifier.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field PublicKeyVerifier\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.PublicKeyVerifier == nil {\n\t\t\t\tm.PublicKeyVerifier = &ImagePublicKeyVerifierSpec{}\n\t\t\t}\n\t\t\tif err := m.PublicKeyVerifier.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TUFTrustedRootSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TUFTrustedRootSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TUFTrustedRootSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LastRefreshTime\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.LastRefreshTime == nil {\n\t\t\t\tm.LastRefreshTime = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.LastRefreshTime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field JsonData\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.JsonData = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/siderolink/siderolink.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/siderolink/siderolink.proto\n\npackage siderolink\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ConfigSpec describes Siderolink configuration.\ntype ConfigSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tApiEndpoint   string                 `protobuf:\"bytes,1,opt,name=api_endpoint,json=apiEndpoint,proto3\" json:\"api_endpoint,omitempty\"`\n\tHost          string                 `protobuf:\"bytes,2,opt,name=host,proto3\" json:\"host,omitempty\"`\n\tJoinToken     string                 `protobuf:\"bytes,3,opt,name=join_token,json=joinToken,proto3\" json:\"join_token,omitempty\"`\n\tInsecure      bool                   `protobuf:\"varint,4,opt,name=insecure,proto3\" json:\"insecure,omitempty\"`\n\tTunnel        bool                   `protobuf:\"varint,5,opt,name=tunnel,proto3\" json:\"tunnel,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ConfigSpec) Reset() {\n\t*x = ConfigSpec{}\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ConfigSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ConfigSpec) ProtoMessage() {}\n\nfunc (x *ConfigSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ConfigSpec.ProtoReflect.Descriptor instead.\nfunc (*ConfigSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ConfigSpec) GetApiEndpoint() string {\n\tif x != nil {\n\t\treturn x.ApiEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetJoinToken() string {\n\tif x != nil {\n\t\treturn x.JoinToken\n\t}\n\treturn \"\"\n}\n\nfunc (x *ConfigSpec) GetInsecure() bool {\n\tif x != nil {\n\t\treturn x.Insecure\n\t}\n\treturn false\n}\n\nfunc (x *ConfigSpec) GetTunnel() bool {\n\tif x != nil {\n\t\treturn x.Tunnel\n\t}\n\treturn false\n}\n\n// StatusSpec describes Siderolink status.\ntype StatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tHost          string                 `protobuf:\"bytes,1,opt,name=host,proto3\" json:\"host,omitempty\"`\n\tConnected     bool                   `protobuf:\"varint,2,opt,name=connected,proto3\" json:\"connected,omitempty\"`\n\tLinkName      string                 `protobuf:\"bytes,3,opt,name=link_name,json=linkName,proto3\" json:\"link_name,omitempty\"`\n\tGrpcTunnel    bool                   `protobuf:\"varint,4,opt,name=grpc_tunnel,json=grpcTunnel,proto3\" json:\"grpc_tunnel,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StatusSpec) Reset() {\n\t*x = StatusSpec{}\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StatusSpec) ProtoMessage() {}\n\nfunc (x *StatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StatusSpec.ProtoReflect.Descriptor instead.\nfunc (*StatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *StatusSpec) GetHost() string {\n\tif x != nil {\n\t\treturn x.Host\n\t}\n\treturn \"\"\n}\n\nfunc (x *StatusSpec) GetConnected() bool {\n\tif x != nil {\n\t\treturn x.Connected\n\t}\n\treturn false\n}\n\nfunc (x *StatusSpec) GetLinkName() string {\n\tif x != nil {\n\t\treturn x.LinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *StatusSpec) GetGrpcTunnel() bool {\n\tif x != nil {\n\t\treturn x.GrpcTunnel\n\t}\n\treturn false\n}\n\n// TunnelSpec describes Siderolink GRPC Tunnel configuration.\ntype TunnelSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tApiEndpoint   string                 `protobuf:\"bytes,1,opt,name=api_endpoint,json=apiEndpoint,proto3\" json:\"api_endpoint,omitempty\"`\n\tLinkName      string                 `protobuf:\"bytes,2,opt,name=link_name,json=linkName,proto3\" json:\"link_name,omitempty\"`\n\tMtu           int64                  `protobuf:\"varint,3,opt,name=mtu,proto3\" json:\"mtu,omitempty\"`\n\tNodeAddress   *common.NetIPPort      `protobuf:\"bytes,4,opt,name=node_address,json=nodeAddress,proto3\" json:\"node_address,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TunnelSpec) Reset() {\n\t*x = TunnelSpec{}\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TunnelSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TunnelSpec) ProtoMessage() {}\n\nfunc (x *TunnelSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_siderolink_siderolink_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TunnelSpec.ProtoReflect.Descriptor instead.\nfunc (*TunnelSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *TunnelSpec) GetApiEndpoint() string {\n\tif x != nil {\n\t\treturn x.ApiEndpoint\n\t}\n\treturn \"\"\n}\n\nfunc (x *TunnelSpec) GetLinkName() string {\n\tif x != nil {\n\t\treturn x.LinkName\n\t}\n\treturn \"\"\n}\n\nfunc (x *TunnelSpec) GetMtu() int64 {\n\tif x != nil {\n\t\treturn x.Mtu\n\t}\n\treturn 0\n}\n\nfunc (x *TunnelSpec) GetNodeAddress() *common.NetIPPort {\n\tif x != nil {\n\t\treturn x.NodeAddress\n\t}\n\treturn nil\n}\n\nvar File_resource_definitions_siderolink_siderolink_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_siderolink_siderolink_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"0resource/definitions/siderolink/siderolink.proto\\x12%talos.resource.definitions.siderolink\\x1a\\x13common/common.proto\\\"\\x96\\x01\\n\" +\n\t\"\\n\" +\n\t\"ConfigSpec\\x12!\\n\" +\n\t\"\\fapi_endpoint\\x18\\x01 \\x01(\\tR\\vapiEndpoint\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x02 \\x01(\\tR\\x04host\\x12\\x1d\\n\" +\n\t\"\\n\" +\n\t\"join_token\\x18\\x03 \\x01(\\tR\\tjoinToken\\x12\\x1a\\n\" +\n\t\"\\binsecure\\x18\\x04 \\x01(\\bR\\binsecure\\x12\\x16\\n\" +\n\t\"\\x06tunnel\\x18\\x05 \\x01(\\bR\\x06tunnel\\\"|\\n\" +\n\t\"\\n\" +\n\t\"StatusSpec\\x12\\x12\\n\" +\n\t\"\\x04host\\x18\\x01 \\x01(\\tR\\x04host\\x12\\x1c\\n\" +\n\t\"\\tconnected\\x18\\x02 \\x01(\\bR\\tconnected\\x12\\x1b\\n\" +\n\t\"\\tlink_name\\x18\\x03 \\x01(\\tR\\blinkName\\x12\\x1f\\n\" +\n\t\"\\vgrpc_tunnel\\x18\\x04 \\x01(\\bR\\n\" +\n\t\"grpcTunnel\\\"\\x94\\x01\\n\" +\n\t\"\\n\" +\n\t\"TunnelSpec\\x12!\\n\" +\n\t\"\\fapi_endpoint\\x18\\x01 \\x01(\\tR\\vapiEndpoint\\x12\\x1b\\n\" +\n\t\"\\tlink_name\\x18\\x02 \\x01(\\tR\\blinkName\\x12\\x10\\n\" +\n\t\"\\x03mtu\\x18\\x03 \\x01(\\x03R\\x03mtu\\x124\\n\" +\n\t\"\\fnode_address\\x18\\x04 \\x01(\\v2\\x11.common.NetIPPortR\\vnodeAddressB~\\n\" +\n\t\"-dev.talos.api.resource.definitions.siderolinkZMgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/siderolinkb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_siderolink_siderolink_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_siderolink_siderolink_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_siderolink_siderolink_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_siderolink_siderolink_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_siderolink_siderolink_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_siderolink_siderolink_proto_rawDesc), len(file_resource_definitions_siderolink_siderolink_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_siderolink_siderolink_proto_rawDescData\n}\n\nvar file_resource_definitions_siderolink_siderolink_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_resource_definitions_siderolink_siderolink_proto_goTypes = []any{\n\t(*ConfigSpec)(nil),       // 0: talos.resource.definitions.siderolink.ConfigSpec\n\t(*StatusSpec)(nil),       // 1: talos.resource.definitions.siderolink.StatusSpec\n\t(*TunnelSpec)(nil),       // 2: talos.resource.definitions.siderolink.TunnelSpec\n\t(*common.NetIPPort)(nil), // 3: common.NetIPPort\n}\nvar file_resource_definitions_siderolink_siderolink_proto_depIdxs = []int32{\n\t3, // 0: talos.resource.definitions.siderolink.TunnelSpec.node_address:type_name -> common.NetIPPort\n\t1, // [1:1] is the sub-list for method output_type\n\t1, // [1:1] is the sub-list for method input_type\n\t1, // [1:1] is the sub-list for extension type_name\n\t1, // [1:1] is the sub-list for extension extendee\n\t0, // [0:1] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_siderolink_siderolink_proto_init() }\nfunc file_resource_definitions_siderolink_siderolink_proto_init() {\n\tif File_resource_definitions_siderolink_siderolink_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_siderolink_siderolink_proto_rawDesc), len(file_resource_definitions_siderolink_siderolink_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_siderolink_siderolink_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_siderolink_siderolink_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_siderolink_siderolink_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_siderolink_siderolink_proto = out.File\n\tfile_resource_definitions_siderolink_siderolink_proto_goTypes = nil\n\tfile_resource_definitions_siderolink_siderolink_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/siderolink/siderolink_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/siderolink/siderolink.proto\n\npackage siderolink\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ConfigSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ConfigSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Tunnel {\n\t\ti--\n\t\tif m.Tunnel {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.Insecure {\n\t\ti--\n\t\tif m.Insecure {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.JoinToken) > 0 {\n\t\ti -= len(m.JoinToken)\n\t\tcopy(dAtA[i:], m.JoinToken)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.JoinToken)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.ApiEndpoint) > 0 {\n\t\ti -= len(m.ApiEndpoint)\n\t\tcopy(dAtA[i:], m.ApiEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApiEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.GrpcTunnel {\n\t\ti--\n\t\tif m.GrpcTunnel {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif len(m.LinkName) > 0 {\n\t\ti -= len(m.LinkName)\n\t\tcopy(dAtA[i:], m.LinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.Connected {\n\t\ti--\n\t\tif m.Connected {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Host) > 0 {\n\t\ti -= len(m.Host)\n\t\tcopy(dAtA[i:], m.Host)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Host)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TunnelSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TunnelSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TunnelSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.NodeAddress != nil {\n\t\tif vtmsg, ok := interface{}(m.NodeAddress).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.NodeAddress)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Mtu != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Mtu))\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif len(m.LinkName) > 0 {\n\t\ti -= len(m.LinkName)\n\t\tcopy(dAtA[i:], m.LinkName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.LinkName)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.ApiEndpoint) > 0 {\n\t\ti -= len(m.ApiEndpoint)\n\t\tcopy(dAtA[i:], m.ApiEndpoint)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ApiEndpoint)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ConfigSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ApiEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.JoinToken)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Insecure {\n\t\tn += 2\n\t}\n\tif m.Tunnel {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Host)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Connected {\n\t\tn += 2\n\t}\n\tl = len(m.LinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.GrpcTunnel {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TunnelSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.ApiEndpoint)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.LinkName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Mtu != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Mtu))\n\t}\n\tif m.NodeAddress != nil {\n\t\tif size, ok := interface{}(m.NodeAddress).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.NodeAddress)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ConfigSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ConfigSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApiEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field JoinToken\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.JoinToken = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Insecure\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Insecure = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Tunnel\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Tunnel = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Host\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Host = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Connected\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Connected = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field GrpcTunnel\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.GrpcTunnel = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TunnelSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TunnelSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TunnelSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field ApiEndpoint\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.ApiEndpoint = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field LinkName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.LinkName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Mtu\", wireType)\n\t\t\t}\n\t\t\tm.Mtu = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Mtu |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field NodeAddress\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.NodeAddress == nil {\n\t\t\t\tm.NodeAddress = &common.NetIPPort{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.NodeAddress).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.NodeAddress); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/time/time.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/time/time.proto\n\npackage time\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb \"google.golang.org/protobuf/types/known/durationpb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// AdjtimeStatusSpec describes Linux internal adjtime state.\ntype AdjtimeStatusSpec struct {\n\tstate                    protoimpl.MessageState `protogen:\"open.v1\"`\n\tOffset                   *durationpb.Duration   `protobuf:\"bytes,1,opt,name=offset,proto3\" json:\"offset,omitempty\"`\n\tFrequencyAdjustmentRatio float64                `protobuf:\"fixed64,2,opt,name=frequency_adjustment_ratio,json=frequencyAdjustmentRatio,proto3\" json:\"frequency_adjustment_ratio,omitempty\"`\n\tMaxError                 *durationpb.Duration   `protobuf:\"bytes,3,opt,name=max_error,json=maxError,proto3\" json:\"max_error,omitempty\"`\n\tEstError                 *durationpb.Duration   `protobuf:\"bytes,4,opt,name=est_error,json=estError,proto3\" json:\"est_error,omitempty\"`\n\tStatus                   string                 `protobuf:\"bytes,5,opt,name=status,proto3\" json:\"status,omitempty\"`\n\tConstant                 int64                  `protobuf:\"varint,6,opt,name=constant,proto3\" json:\"constant,omitempty\"`\n\tSyncStatus               bool                   `protobuf:\"varint,7,opt,name=sync_status,json=syncStatus,proto3\" json:\"sync_status,omitempty\"`\n\tState                    string                 `protobuf:\"bytes,8,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *AdjtimeStatusSpec) Reset() {\n\t*x = AdjtimeStatusSpec{}\n\tmi := &file_resource_definitions_time_time_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *AdjtimeStatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AdjtimeStatusSpec) ProtoMessage() {}\n\nfunc (x *AdjtimeStatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_time_time_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AdjtimeStatusSpec.ProtoReflect.Descriptor instead.\nfunc (*AdjtimeStatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_time_time_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *AdjtimeStatusSpec) GetOffset() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.Offset\n\t}\n\treturn nil\n}\n\nfunc (x *AdjtimeStatusSpec) GetFrequencyAdjustmentRatio() float64 {\n\tif x != nil {\n\t\treturn x.FrequencyAdjustmentRatio\n\t}\n\treturn 0\n}\n\nfunc (x *AdjtimeStatusSpec) GetMaxError() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.MaxError\n\t}\n\treturn nil\n}\n\nfunc (x *AdjtimeStatusSpec) GetEstError() *durationpb.Duration {\n\tif x != nil {\n\t\treturn x.EstError\n\t}\n\treturn nil\n}\n\nfunc (x *AdjtimeStatusSpec) GetStatus() string {\n\tif x != nil {\n\t\treturn x.Status\n\t}\n\treturn \"\"\n}\n\nfunc (x *AdjtimeStatusSpec) GetConstant() int64 {\n\tif x != nil {\n\t\treturn x.Constant\n\t}\n\treturn 0\n}\n\nfunc (x *AdjtimeStatusSpec) GetSyncStatus() bool {\n\tif x != nil {\n\t\treturn x.SyncStatus\n\t}\n\treturn false\n}\n\nfunc (x *AdjtimeStatusSpec) GetState() string {\n\tif x != nil {\n\t\treturn x.State\n\t}\n\treturn \"\"\n}\n\n// StatusSpec describes time sync state.\ntype StatusSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tSynced        bool                   `protobuf:\"varint,1,opt,name=synced,proto3\" json:\"synced,omitempty\"`\n\tEpoch         int64                  `protobuf:\"varint,2,opt,name=epoch,proto3\" json:\"epoch,omitempty\"`\n\tSyncDisabled  bool                   `protobuf:\"varint,3,opt,name=sync_disabled,json=syncDisabled,proto3\" json:\"sync_disabled,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *StatusSpec) Reset() {\n\t*x = StatusSpec{}\n\tmi := &file_resource_definitions_time_time_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *StatusSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StatusSpec) ProtoMessage() {}\n\nfunc (x *StatusSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_time_time_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StatusSpec.ProtoReflect.Descriptor instead.\nfunc (*StatusSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_time_time_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *StatusSpec) GetSynced() bool {\n\tif x != nil {\n\t\treturn x.Synced\n\t}\n\treturn false\n}\n\nfunc (x *StatusSpec) GetEpoch() int64 {\n\tif x != nil {\n\t\treturn x.Epoch\n\t}\n\treturn 0\n}\n\nfunc (x *StatusSpec) GetSyncDisabled() bool {\n\tif x != nil {\n\t\treturn x.SyncDisabled\n\t}\n\treturn false\n}\n\nvar File_resource_definitions_time_time_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_time_time_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"$resource/definitions/time/time.proto\\x12\\x1ftalos.resource.definitions.time\\x1a\\x1egoogle/protobuf/duration.proto\\\"\\xdf\\x02\\n\" +\n\t\"\\x11AdjtimeStatusSpec\\x121\\n\" +\n\t\"\\x06offset\\x18\\x01 \\x01(\\v2\\x19.google.protobuf.DurationR\\x06offset\\x12<\\n\" +\n\t\"\\x1afrequency_adjustment_ratio\\x18\\x02 \\x01(\\x01R\\x18frequencyAdjustmentRatio\\x126\\n\" +\n\t\"\\tmax_error\\x18\\x03 \\x01(\\v2\\x19.google.protobuf.DurationR\\bmaxError\\x126\\n\" +\n\t\"\\test_error\\x18\\x04 \\x01(\\v2\\x19.google.protobuf.DurationR\\bestError\\x12\\x16\\n\" +\n\t\"\\x06status\\x18\\x05 \\x01(\\tR\\x06status\\x12\\x1a\\n\" +\n\t\"\\bconstant\\x18\\x06 \\x01(\\x03R\\bconstant\\x12\\x1f\\n\" +\n\t\"\\vsync_status\\x18\\a \\x01(\\bR\\n\" +\n\t\"syncStatus\\x12\\x14\\n\" +\n\t\"\\x05state\\x18\\b \\x01(\\tR\\x05state\\\"_\\n\" +\n\t\"\\n\" +\n\t\"StatusSpec\\x12\\x16\\n\" +\n\t\"\\x06synced\\x18\\x01 \\x01(\\bR\\x06synced\\x12\\x14\\n\" +\n\t\"\\x05epoch\\x18\\x02 \\x01(\\x03R\\x05epoch\\x12#\\n\" +\n\t\"\\rsync_disabled\\x18\\x03 \\x01(\\bR\\fsyncDisabledBr\\n\" +\n\t\"'dev.talos.api.resource.definitions.timeZGgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/timeb\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_time_time_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_time_time_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_time_time_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_time_time_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_time_time_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_time_time_proto_rawDesc), len(file_resource_definitions_time_time_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_time_time_proto_rawDescData\n}\n\nvar file_resource_definitions_time_time_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_resource_definitions_time_time_proto_goTypes = []any{\n\t(*AdjtimeStatusSpec)(nil),   // 0: talos.resource.definitions.time.AdjtimeStatusSpec\n\t(*StatusSpec)(nil),          // 1: talos.resource.definitions.time.StatusSpec\n\t(*durationpb.Duration)(nil), // 2: google.protobuf.Duration\n}\nvar file_resource_definitions_time_time_proto_depIdxs = []int32{\n\t2, // 0: talos.resource.definitions.time.AdjtimeStatusSpec.offset:type_name -> google.protobuf.Duration\n\t2, // 1: talos.resource.definitions.time.AdjtimeStatusSpec.max_error:type_name -> google.protobuf.Duration\n\t2, // 2: talos.resource.definitions.time.AdjtimeStatusSpec.est_error:type_name -> google.protobuf.Duration\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_time_time_proto_init() }\nfunc file_resource_definitions_time_time_proto_init() {\n\tif File_resource_definitions_time_time_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_time_time_proto_rawDesc), len(file_resource_definitions_time_time_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_time_time_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_time_time_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_time_time_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_time_time_proto = out.File\n\tfile_resource_definitions_time_time_proto_goTypes = nil\n\tfile_resource_definitions_time_time_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/time/time_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/time/time.proto\n\npackage time\n\nimport (\n\tbinary \"encoding/binary\"\n\tfmt \"fmt\"\n\tio \"io\"\n\tmath \"math\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tdurationpb \"github.com/planetscale/vtprotobuf/types/known/durationpb\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdurationpb1 \"google.golang.org/protobuf/types/known/durationpb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *AdjtimeStatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *AdjtimeStatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *AdjtimeStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.State) > 0 {\n\t\ti -= len(m.State)\n\t\tcopy(dAtA[i:], m.State)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.State)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif m.SyncStatus {\n\t\ti--\n\t\tif m.SyncStatus {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x38\n\t}\n\tif m.Constant != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Constant))\n\t\ti--\n\t\tdAtA[i] = 0x30\n\t}\n\tif len(m.Status) > 0 {\n\t\ti -= len(m.Status)\n\t\tcopy(dAtA[i:], m.Status)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Status)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif m.EstError != nil {\n\t\tsize, err := (*durationpb.Duration)(m.EstError).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.MaxError != nil {\n\t\tsize, err := (*durationpb.Duration)(m.MaxError).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif m.FrequencyAdjustmentRatio != 0 {\n\t\ti -= 8\n\t\tbinary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.FrequencyAdjustmentRatio))))\n\t\ti--\n\t\tdAtA[i] = 0x11\n\t}\n\tif m.Offset != nil {\n\t\tsize, err := (*durationpb.Duration)(m.Offset).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *StatusSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *StatusSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *StatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SyncDisabled {\n\t\ti--\n\t\tif m.SyncDisabled {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Epoch != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Epoch))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Synced {\n\t\ti--\n\t\tif m.Synced {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *AdjtimeStatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Offset != nil {\n\t\tl = (*durationpb.Duration)(m.Offset).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.FrequencyAdjustmentRatio != 0 {\n\t\tn += 9\n\t}\n\tif m.MaxError != nil {\n\t\tl = (*durationpb.Duration)(m.MaxError).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.EstError != nil {\n\t\tl = (*durationpb.Duration)(m.EstError).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Status)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Constant != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Constant))\n\t}\n\tif m.SyncStatus {\n\t\tn += 2\n\t}\n\tl = len(m.State)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *StatusSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Synced {\n\t\tn += 2\n\t}\n\tif m.Epoch != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Epoch))\n\t}\n\tif m.SyncDisabled {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *AdjtimeStatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: AdjtimeStatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: AdjtimeStatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Offset\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Offset == nil {\n\t\t\t\tm.Offset = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.Offset).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 1 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field FrequencyAdjustmentRatio\", wireType)\n\t\t\t}\n\t\t\tvar v uint64\n\t\t\tif (iNdEx + 8) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tv = uint64(binary.LittleEndian.Uint64(dAtA[iNdEx:]))\n\t\t\tiNdEx += 8\n\t\t\tm.FrequencyAdjustmentRatio = float64(math.Float64frombits(v))\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field MaxError\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.MaxError == nil {\n\t\t\t\tm.MaxError = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.MaxError).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field EstError\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.EstError == nil {\n\t\t\t\tm.EstError = &durationpb1.Duration{}\n\t\t\t}\n\t\t\tif err := (*durationpb.Duration)(m.EstError).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Status\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Status = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Constant\", wireType)\n\t\t\t}\n\t\t\tm.Constant = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Constant |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 7:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SyncStatus\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SyncStatus = bool(v != 0)\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field State\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.State = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *StatusSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: StatusSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Synced\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Synced = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Epoch\", wireType)\n\t\t\t}\n\t\t\tm.Epoch = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Epoch |= int64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SyncDisabled\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SyncDisabled = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/v1alpha1/v1alpha1.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/definitions/v1alpha1/v1alpha1.proto\n\npackage v1alpha1\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// ServiceSpec describe service state.\ntype ServiceSpec struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tRunning       bool                   `protobuf:\"varint,1,opt,name=running,proto3\" json:\"running,omitempty\"`\n\tHealthy       bool                   `protobuf:\"varint,2,opt,name=healthy,proto3\" json:\"healthy,omitempty\"`\n\tUnknown       bool                   `protobuf:\"varint,3,opt,name=unknown,proto3\" json:\"unknown,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ServiceSpec) Reset() {\n\t*x = ServiceSpec{}\n\tmi := &file_resource_definitions_v1alpha1_v1alpha1_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ServiceSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ServiceSpec) ProtoMessage() {}\n\nfunc (x *ServiceSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_definitions_v1alpha1_v1alpha1_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ServiceSpec.ProtoReflect.Descriptor instead.\nfunc (*ServiceSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_definitions_v1alpha1_v1alpha1_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *ServiceSpec) GetRunning() bool {\n\tif x != nil {\n\t\treturn x.Running\n\t}\n\treturn false\n}\n\nfunc (x *ServiceSpec) GetHealthy() bool {\n\tif x != nil {\n\t\treturn x.Healthy\n\t}\n\treturn false\n}\n\nfunc (x *ServiceSpec) GetUnknown() bool {\n\tif x != nil {\n\t\treturn x.Unknown\n\t}\n\treturn false\n}\n\nvar File_resource_definitions_v1alpha1_v1alpha1_proto protoreflect.FileDescriptor\n\nconst file_resource_definitions_v1alpha1_v1alpha1_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\",resource/definitions/v1alpha1/v1alpha1.proto\\x12#talos.resource.definitions.v1alpha1\\\"[\\n\" +\n\t\"\\vServiceSpec\\x12\\x18\\n\" +\n\t\"\\arunning\\x18\\x01 \\x01(\\bR\\arunning\\x12\\x18\\n\" +\n\t\"\\ahealthy\\x18\\x02 \\x01(\\bR\\ahealthy\\x12\\x18\\n\" +\n\t\"\\aunknown\\x18\\x03 \\x01(\\bR\\aunknownBz\\n\" +\n\t\"+dev.talos.api.resource.definitions.v1alpha1ZKgithub.com/siderolabs/talos/pkg/machinery/api/resource/definitions/v1alpha1b\\x06proto3\"\n\nvar (\n\tfile_resource_definitions_v1alpha1_v1alpha1_proto_rawDescOnce sync.Once\n\tfile_resource_definitions_v1alpha1_v1alpha1_proto_rawDescData []byte\n)\n\nfunc file_resource_definitions_v1alpha1_v1alpha1_proto_rawDescGZIP() []byte {\n\tfile_resource_definitions_v1alpha1_v1alpha1_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_definitions_v1alpha1_v1alpha1_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_definitions_v1alpha1_v1alpha1_proto_rawDesc), len(file_resource_definitions_v1alpha1_v1alpha1_proto_rawDesc)))\n\t})\n\treturn file_resource_definitions_v1alpha1_v1alpha1_proto_rawDescData\n}\n\nvar file_resource_definitions_v1alpha1_v1alpha1_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_resource_definitions_v1alpha1_v1alpha1_proto_goTypes = []any{\n\t(*ServiceSpec)(nil), // 0: talos.resource.definitions.v1alpha1.ServiceSpec\n}\nvar file_resource_definitions_v1alpha1_v1alpha1_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_definitions_v1alpha1_v1alpha1_proto_init() }\nfunc file_resource_definitions_v1alpha1_v1alpha1_proto_init() {\n\tif File_resource_definitions_v1alpha1_v1alpha1_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_definitions_v1alpha1_v1alpha1_proto_rawDesc), len(file_resource_definitions_v1alpha1_v1alpha1_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_definitions_v1alpha1_v1alpha1_proto_goTypes,\n\t\tDependencyIndexes: file_resource_definitions_v1alpha1_v1alpha1_proto_depIdxs,\n\t\tMessageInfos:      file_resource_definitions_v1alpha1_v1alpha1_proto_msgTypes,\n\t}.Build()\n\tFile_resource_definitions_v1alpha1_v1alpha1_proto = out.File\n\tfile_resource_definitions_v1alpha1_v1alpha1_proto_goTypes = nil\n\tfile_resource_definitions_v1alpha1_v1alpha1_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/definitions/v1alpha1/v1alpha1_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/definitions/v1alpha1/v1alpha1.proto\n\npackage v1alpha1\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *ServiceSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *ServiceSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *ServiceSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Unknown {\n\t\ti--\n\t\tif m.Unknown {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Healthy {\n\t\ti--\n\t\tif m.Healthy {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif m.Running {\n\t\ti--\n\t\tif m.Running {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *ServiceSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Running {\n\t\tn += 2\n\t}\n\tif m.Healthy {\n\t\tn += 2\n\t}\n\tif m.Unknown {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *ServiceSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: ServiceSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Running\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Running = bool(v != 0)\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Healthy\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Healthy = bool(v != 0)\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Unknown\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Unknown = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/network/device_config.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: resource/network/device_config.proto\n\npackage network\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// DeviceConfigSpecSpec is the spec for the network.DeviceConfigSpec resource.\ntype DeviceConfigSpecSpec struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Contains YAML marshalled device config (as part of the machine config).\n\tYamlMarshalled []byte `protobuf:\"bytes,1,opt,name=yaml_marshalled,json=yamlMarshalled,proto3\" json:\"yaml_marshalled,omitempty\"`\n\tunknownFields  protoimpl.UnknownFields\n\tsizeCache      protoimpl.SizeCache\n}\n\nfunc (x *DeviceConfigSpecSpec) Reset() {\n\t*x = DeviceConfigSpecSpec{}\n\tmi := &file_resource_network_device_config_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DeviceConfigSpecSpec) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DeviceConfigSpecSpec) ProtoMessage() {}\n\nfunc (x *DeviceConfigSpecSpec) ProtoReflect() protoreflect.Message {\n\tmi := &file_resource_network_device_config_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DeviceConfigSpecSpec.ProtoReflect.Descriptor instead.\nfunc (*DeviceConfigSpecSpec) Descriptor() ([]byte, []int) {\n\treturn file_resource_network_device_config_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *DeviceConfigSpecSpec) GetYamlMarshalled() []byte {\n\tif x != nil {\n\t\treturn x.YamlMarshalled\n\t}\n\treturn nil\n}\n\nvar File_resource_network_device_config_proto protoreflect.FileDescriptor\n\nconst file_resource_network_device_config_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"$resource/network/device_config.proto\\x12\\x10resource.network\\\"?\\n\" +\n\t\"\\x14DeviceConfigSpecSpec\\x12'\\n\" +\n\t\"\\x0fyaml_marshalled\\x18\\x01 \\x01(\\fR\\x0eyamlMarshalledB`\\n\" +\n\t\"\\x1edev.talos.api.resource.networkZ>github.com/siderolabs/talos/pkg/machinery/api/resource/networkb\\x06proto3\"\n\nvar (\n\tfile_resource_network_device_config_proto_rawDescOnce sync.Once\n\tfile_resource_network_device_config_proto_rawDescData []byte\n)\n\nfunc file_resource_network_device_config_proto_rawDescGZIP() []byte {\n\tfile_resource_network_device_config_proto_rawDescOnce.Do(func() {\n\t\tfile_resource_network_device_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_resource_network_device_config_proto_rawDesc), len(file_resource_network_device_config_proto_rawDesc)))\n\t})\n\treturn file_resource_network_device_config_proto_rawDescData\n}\n\nvar file_resource_network_device_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_resource_network_device_config_proto_goTypes = []any{\n\t(*DeviceConfigSpecSpec)(nil), // 0: resource.network.DeviceConfigSpecSpec\n}\nvar file_resource_network_device_config_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_resource_network_device_config_proto_init() }\nfunc file_resource_network_device_config_proto_init() {\n\tif File_resource_network_device_config_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_resource_network_device_config_proto_rawDesc), len(file_resource_network_device_config_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_resource_network_device_config_proto_goTypes,\n\t\tDependencyIndexes: file_resource_network_device_config_proto_depIdxs,\n\t\tMessageInfos:      file_resource_network_device_config_proto_msgTypes,\n\t}.Build()\n\tFile_resource_network_device_config_proto = out.File\n\tfile_resource_network_device_config_proto_goTypes = nil\n\tfile_resource_network_device_config_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/resource/network/device_config_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: resource/network/device_config.proto\n\npackage network\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *DeviceConfigSpecSpec) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DeviceConfigSpecSpec) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DeviceConfigSpecSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.YamlMarshalled) > 0 {\n\t\ti -= len(m.YamlMarshalled)\n\t\tcopy(dAtA[i:], m.YamlMarshalled)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.YamlMarshalled)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DeviceConfigSpecSpec) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.YamlMarshalled)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DeviceConfigSpecSpec) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DeviceConfigSpecSpec: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DeviceConfigSpecSpec: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field YamlMarshalled\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.YamlMarshalled = append(m.YamlMarshalled[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.YamlMarshalled == nil {\n\t\t\t\tm.YamlMarshalled = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/security/security.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: security/security.proto\n\npackage security\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The request message containing the certificate signing request.\ntype CertificateRequest struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Certificate Signing Request in PEM format.\n\tCsr           []byte `protobuf:\"bytes,1,opt,name=csr,proto3\" json:\"csr,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CertificateRequest) Reset() {\n\t*x = CertificateRequest{}\n\tmi := &file_security_security_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CertificateRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CertificateRequest) ProtoMessage() {}\n\nfunc (x *CertificateRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_security_security_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CertificateRequest.ProtoReflect.Descriptor instead.\nfunc (*CertificateRequest) Descriptor() ([]byte, []int) {\n\treturn file_security_security_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *CertificateRequest) GetCsr() []byte {\n\tif x != nil {\n\t\treturn x.Csr\n\t}\n\treturn nil\n}\n\n// The response message containing signed certificate.\ntype CertificateResponse struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Certificate of the CA that signed the requested certificate in PEM format.\n\tCa []byte `protobuf:\"bytes,1,opt,name=ca,proto3\" json:\"ca,omitempty\"`\n\t// Signed X.509 requested certificate in PEM format.\n\tCrt           []byte `protobuf:\"bytes,2,opt,name=crt,proto3\" json:\"crt,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *CertificateResponse) Reset() {\n\t*x = CertificateResponse{}\n\tmi := &file_security_security_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *CertificateResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CertificateResponse) ProtoMessage() {}\n\nfunc (x *CertificateResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_security_security_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CertificateResponse.ProtoReflect.Descriptor instead.\nfunc (*CertificateResponse) Descriptor() ([]byte, []int) {\n\treturn file_security_security_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *CertificateResponse) GetCa() []byte {\n\tif x != nil {\n\t\treturn x.Ca\n\t}\n\treturn nil\n}\n\nfunc (x *CertificateResponse) GetCrt() []byte {\n\tif x != nil {\n\t\treturn x.Crt\n\t}\n\treturn nil\n}\n\nvar File_security_security_proto protoreflect.FileDescriptor\n\nconst file_security_security_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x17security/security.proto\\x12\\vsecurityapi\\\"&\\n\" +\n\t\"\\x12CertificateRequest\\x12\\x10\\n\" +\n\t\"\\x03csr\\x18\\x01 \\x01(\\fR\\x03csr\\\"7\\n\" +\n\t\"\\x13CertificateResponse\\x12\\x0e\\n\" +\n\t\"\\x02ca\\x18\\x01 \\x01(\\fR\\x02ca\\x12\\x10\\n\" +\n\t\"\\x03crt\\x18\\x02 \\x01(\\fR\\x03crt2c\\n\" +\n\t\"\\x0fSecurityService\\x12P\\n\" +\n\t\"\\vCertificate\\x12\\x1f.securityapi.CertificateRequest\\x1a .securityapi.CertificateResponseBP\\n\" +\n\t\"\\x16dev.talos.api.securityZ6github.com/siderolabs/talos/pkg/machinery/api/securityb\\x06proto3\"\n\nvar (\n\tfile_security_security_proto_rawDescOnce sync.Once\n\tfile_security_security_proto_rawDescData []byte\n)\n\nfunc file_security_security_proto_rawDescGZIP() []byte {\n\tfile_security_security_proto_rawDescOnce.Do(func() {\n\t\tfile_security_security_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_security_security_proto_rawDesc), len(file_security_security_proto_rawDesc)))\n\t})\n\treturn file_security_security_proto_rawDescData\n}\n\nvar file_security_security_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_security_security_proto_goTypes = []any{\n\t(*CertificateRequest)(nil),  // 0: securityapi.CertificateRequest\n\t(*CertificateResponse)(nil), // 1: securityapi.CertificateResponse\n}\nvar file_security_security_proto_depIdxs = []int32{\n\t0, // 0: securityapi.SecurityService.Certificate:input_type -> securityapi.CertificateRequest\n\t1, // 1: securityapi.SecurityService.Certificate:output_type -> securityapi.CertificateResponse\n\t1, // [1:2] is the sub-list for method output_type\n\t0, // [0:1] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_security_security_proto_init() }\nfunc file_security_security_proto_init() {\n\tif File_security_security_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_security_security_proto_rawDesc), len(file_security_security_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_security_security_proto_goTypes,\n\t\tDependencyIndexes: file_security_security_proto_depIdxs,\n\t\tMessageInfos:      file_security_security_proto_msgTypes,\n\t}.Build()\n\tFile_security_security_proto = out.File\n\tfile_security_security_proto_goTypes = nil\n\tfile_security_security_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/security/security_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: security/security.proto\n\npackage security\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tSecurityService_Certificate_FullMethodName = \"/securityapi.SecurityService/Certificate\"\n)\n\n// SecurityServiceClient is the client API for SecurityService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The security service definition.\ntype SecurityServiceClient interface {\n\tCertificate(ctx context.Context, in *CertificateRequest, opts ...grpc.CallOption) (*CertificateResponse, error)\n}\n\ntype securityServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewSecurityServiceClient(cc grpc.ClientConnInterface) SecurityServiceClient {\n\treturn &securityServiceClient{cc}\n}\n\nfunc (c *securityServiceClient) Certificate(ctx context.Context, in *CertificateRequest, opts ...grpc.CallOption) (*CertificateResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(CertificateResponse)\n\terr := c.cc.Invoke(ctx, SecurityService_Certificate_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// SecurityServiceServer is the server API for SecurityService service.\n// All implementations must embed UnimplementedSecurityServiceServer\n// for forward compatibility.\n//\n// The security service definition.\ntype SecurityServiceServer interface {\n\tCertificate(context.Context, *CertificateRequest) (*CertificateResponse, error)\n\tmustEmbedUnimplementedSecurityServiceServer()\n}\n\n// UnimplementedSecurityServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedSecurityServiceServer struct{}\n\nfunc (UnimplementedSecurityServiceServer) Certificate(context.Context, *CertificateRequest) (*CertificateResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Certificate not implemented\")\n}\nfunc (UnimplementedSecurityServiceServer) mustEmbedUnimplementedSecurityServiceServer() {}\nfunc (UnimplementedSecurityServiceServer) testEmbeddedByValue()                         {}\n\n// UnsafeSecurityServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to SecurityServiceServer will\n// result in compilation errors.\ntype UnsafeSecurityServiceServer interface {\n\tmustEmbedUnimplementedSecurityServiceServer()\n}\n\nfunc RegisterSecurityServiceServer(s grpc.ServiceRegistrar, srv SecurityServiceServer) {\n\t// If the following call panics, it indicates UnimplementedSecurityServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&SecurityService_ServiceDesc, srv)\n}\n\nfunc _SecurityService_Certificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(CertificateRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(SecurityServiceServer).Certificate(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: SecurityService_Certificate_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(SecurityServiceServer).Certificate(ctx, req.(*CertificateRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// SecurityService_ServiceDesc is the grpc.ServiceDesc for SecurityService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar SecurityService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"securityapi.SecurityService\",\n\tHandlerType: (*SecurityServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Certificate\",\n\t\t\tHandler:    _SecurityService_Certificate_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"security/security.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/security/security_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: security/security.proto\n\npackage security\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *CertificateRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CertificateRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CertificateRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Csr) > 0 {\n\t\ti -= len(m.Csr)\n\t\tcopy(dAtA[i:], m.Csr)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Csr)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CertificateResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *CertificateResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *CertificateResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Crt) > 0 {\n\t\ti -= len(m.Crt)\n\t\tcopy(dAtA[i:], m.Crt)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Crt)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif len(m.Ca) > 0 {\n\t\ti -= len(m.Ca)\n\t\tcopy(dAtA[i:], m.Ca)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Ca)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *CertificateRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Csr)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CertificateResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Ca)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Crt)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *CertificateRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CertificateRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CertificateRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Csr\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Csr = append(m.Csr[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Csr == nil {\n\t\t\t\tm.Csr = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *CertificateResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: CertificateResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: CertificateResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Ca\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Ca = append(m.Ca[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Ca == nil {\n\t\t\t\tm.Ca = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Crt\", wireType)\n\t\t\t}\n\t\t\tvar byteLen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tbyteLen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif byteLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + byteLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Crt = append(m.Crt[:0], dAtA[iNdEx:postIndex]...)\n\t\t\tif m.Crt == nil {\n\t\t\t\tm.Crt = []byte{}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/storage/storage.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: storage/storage.proto\n\npackage storage\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype Disk_DiskType int32\n\nconst (\n\tDisk_UNKNOWN Disk_DiskType = 0\n\tDisk_SSD     Disk_DiskType = 1\n\tDisk_HDD     Disk_DiskType = 2\n\tDisk_NVME    Disk_DiskType = 3\n\tDisk_SD      Disk_DiskType = 4\n\tDisk_CD      Disk_DiskType = 5\n)\n\n// Enum value maps for Disk_DiskType.\nvar (\n\tDisk_DiskType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"SSD\",\n\t\t2: \"HDD\",\n\t\t3: \"NVME\",\n\t\t4: \"SD\",\n\t\t5: \"CD\",\n\t}\n\tDisk_DiskType_value = map[string]int32{\n\t\t\"UNKNOWN\": 0,\n\t\t\"SSD\":     1,\n\t\t\"HDD\":     2,\n\t\t\"NVME\":    3,\n\t\t\"SD\":      4,\n\t\t\"CD\":      5,\n\t}\n)\n\nfunc (x Disk_DiskType) Enum() *Disk_DiskType {\n\tp := new(Disk_DiskType)\n\t*p = x\n\treturn p\n}\n\nfunc (x Disk_DiskType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Disk_DiskType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_storage_storage_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Disk_DiskType) Type() protoreflect.EnumType {\n\treturn &file_storage_storage_proto_enumTypes[0]\n}\n\nfunc (x Disk_DiskType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Disk_DiskType.Descriptor instead.\nfunc (Disk_DiskType) EnumDescriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{0, 0}\n}\n\ntype BlockDeviceWipeDescriptor_Method int32\n\nconst (\n\t// Fast wipe - wipe only filesystem signatures.\n\tBlockDeviceWipeDescriptor_FAST BlockDeviceWipeDescriptor_Method = 0\n\t// Zeroes wipe - wipe by overwriting with zeroes (might be slow depending on the disk size and available hardware features).\n\tBlockDeviceWipeDescriptor_ZEROES BlockDeviceWipeDescriptor_Method = 1\n)\n\n// Enum value maps for BlockDeviceWipeDescriptor_Method.\nvar (\n\tBlockDeviceWipeDescriptor_Method_name = map[int32]string{\n\t\t0: \"FAST\",\n\t\t1: \"ZEROES\",\n\t}\n\tBlockDeviceWipeDescriptor_Method_value = map[string]int32{\n\t\t\"FAST\":   0,\n\t\t\"ZEROES\": 1,\n\t}\n)\n\nfunc (x BlockDeviceWipeDescriptor_Method) Enum() *BlockDeviceWipeDescriptor_Method {\n\tp := new(BlockDeviceWipeDescriptor_Method)\n\t*p = x\n\treturn p\n}\n\nfunc (x BlockDeviceWipeDescriptor_Method) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (BlockDeviceWipeDescriptor_Method) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_storage_storage_proto_enumTypes[1].Descriptor()\n}\n\nfunc (BlockDeviceWipeDescriptor_Method) Type() protoreflect.EnumType {\n\treturn &file_storage_storage_proto_enumTypes[1]\n}\n\nfunc (x BlockDeviceWipeDescriptor_Method) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use BlockDeviceWipeDescriptor_Method.Descriptor instead.\nfunc (BlockDeviceWipeDescriptor_Method) EnumDescriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{4, 0}\n}\n\n// Disk represents a disk.\ntype Disk struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Size indicates the disk size in bytes.\n\tSize uint64 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\t// Model idicates the disk model.\n\tModel string `protobuf:\"bytes,2,opt,name=model,proto3\" json:\"model,omitempty\"`\n\t// DeviceName indicates the disk name (e.g. `sda`).\n\tDeviceName string `protobuf:\"bytes,3,opt,name=device_name,json=deviceName,proto3\" json:\"device_name,omitempty\"`\n\t// Name as in `/sys/block/<dev>/device/name`.\n\tName string `protobuf:\"bytes,4,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Serial as in `/sys/block/<dev>/device/serial`.\n\tSerial string `protobuf:\"bytes,5,opt,name=serial,proto3\" json:\"serial,omitempty\"`\n\t// Modalias as in `/sys/block/<dev>/device/modalias`.\n\tModalias string `protobuf:\"bytes,6,opt,name=modalias,proto3\" json:\"modalias,omitempty\"`\n\t// Uuid as in `/sys/block/<dev>/device/uuid`.\n\tUuid string `protobuf:\"bytes,7,opt,name=uuid,proto3\" json:\"uuid,omitempty\"`\n\t// Wwid as in `/sys/block/<dev>/device/wwid`.\n\tWwid string `protobuf:\"bytes,8,opt,name=wwid,proto3\" json:\"wwid,omitempty\"`\n\t// Type is a type of the disk: nvme, ssd, hdd, sd card.\n\tType Disk_DiskType `protobuf:\"varint,9,opt,name=type,proto3,enum=storage.Disk_DiskType\" json:\"type,omitempty\"`\n\t// BusPath is the bus path of the disk.\n\tBusPath string `protobuf:\"bytes,10,opt,name=bus_path,json=busPath,proto3\" json:\"bus_path,omitempty\"`\n\t// SystemDisk indicates that the disk is used as Talos system disk.\n\tSystemDisk bool `protobuf:\"varint,11,opt,name=system_disk,json=systemDisk,proto3\" json:\"system_disk,omitempty\"`\n\t// Subsystem is the symlink path in the `/sys/block/<dev>/subsystem`.\n\tSubsystem string `protobuf:\"bytes,12,opt,name=subsystem,proto3\" json:\"subsystem,omitempty\"`\n\t// Readonly specifies if the disk is read only.\n\tReadonly      bool `protobuf:\"varint,13,opt,name=readonly,proto3\" json:\"readonly,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Disk) Reset() {\n\t*x = Disk{}\n\tmi := &file_storage_storage_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Disk) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Disk) ProtoMessage() {}\n\nfunc (x *Disk) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Disk.ProtoReflect.Descriptor instead.\nfunc (*Disk) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Disk) GetSize() uint64 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *Disk) GetModel() string {\n\tif x != nil {\n\t\treturn x.Model\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetDeviceName() string {\n\tif x != nil {\n\t\treturn x.DeviceName\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetSerial() string {\n\tif x != nil {\n\t\treturn x.Serial\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetModalias() string {\n\tif x != nil {\n\t\treturn x.Modalias\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetUuid() string {\n\tif x != nil {\n\t\treturn x.Uuid\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetWwid() string {\n\tif x != nil {\n\t\treturn x.Wwid\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetType() Disk_DiskType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn Disk_UNKNOWN\n}\n\nfunc (x *Disk) GetBusPath() string {\n\tif x != nil {\n\t\treturn x.BusPath\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetSystemDisk() bool {\n\tif x != nil {\n\t\treturn x.SystemDisk\n\t}\n\treturn false\n}\n\nfunc (x *Disk) GetSubsystem() string {\n\tif x != nil {\n\t\treturn x.Subsystem\n\t}\n\treturn \"\"\n}\n\nfunc (x *Disk) GetReadonly() bool {\n\tif x != nil {\n\t\treturn x.Readonly\n\t}\n\treturn false\n}\n\n// DisksResponse represents the response of the `Disks` RPC.\ntype Disks struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tDisks         []*Disk                `protobuf:\"bytes,2,rep,name=disks,proto3\" json:\"disks,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Disks) Reset() {\n\t*x = Disks{}\n\tmi := &file_storage_storage_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Disks) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Disks) ProtoMessage() {}\n\nfunc (x *Disks) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Disks.ProtoReflect.Descriptor instead.\nfunc (*Disks) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Disks) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Disks) GetDisks() []*Disk {\n\tif x != nil {\n\t\treturn x.Disks\n\t}\n\treturn nil\n}\n\ntype DisksResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Disks               `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *DisksResponse) Reset() {\n\t*x = DisksResponse{}\n\tmi := &file_storage_storage_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *DisksResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*DisksResponse) ProtoMessage() {}\n\nfunc (x *DisksResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use DisksResponse.ProtoReflect.Descriptor instead.\nfunc (*DisksResponse) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *DisksResponse) GetMessages() []*Disks {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype BlockDeviceWipeRequest struct {\n\tstate         protoimpl.MessageState       `protogen:\"open.v1\"`\n\tDevices       []*BlockDeviceWipeDescriptor `protobuf:\"bytes,1,rep,name=devices,proto3\" json:\"devices,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BlockDeviceWipeRequest) Reset() {\n\t*x = BlockDeviceWipeRequest{}\n\tmi := &file_storage_storage_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BlockDeviceWipeRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BlockDeviceWipeRequest) ProtoMessage() {}\n\nfunc (x *BlockDeviceWipeRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BlockDeviceWipeRequest.ProtoReflect.Descriptor instead.\nfunc (*BlockDeviceWipeRequest) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *BlockDeviceWipeRequest) GetDevices() []*BlockDeviceWipeDescriptor {\n\tif x != nil {\n\t\treturn x.Devices\n\t}\n\treturn nil\n}\n\n// BlockDeviceWipeDescriptor represents a single block device to be wiped.\n//\n// The device can be either a full disk (e.g. vda) or a partition (vda5).\n// The device should not be used in any of active volumes.\n// The device should not be used as a secondary (e.g. part of LVM).\ntype BlockDeviceWipeDescriptor struct {\n\tstate protoimpl.MessageState `protogen:\"open.v1\"`\n\t// Device name to wipe (e.g. sda or sda5).\n\t//\n\t// The name should be submitted without `/dev/` prefix.\n\tDevice string `protobuf:\"bytes,1,opt,name=device,proto3\" json:\"device,omitempty\"`\n\t// Wipe method to use.\n\tMethod BlockDeviceWipeDescriptor_Method `protobuf:\"varint,2,opt,name=method,proto3,enum=storage.BlockDeviceWipeDescriptor_Method\" json:\"method,omitempty\"`\n\t// Skip the volume in use check.\n\tSkipVolumeCheck bool `protobuf:\"varint,3,opt,name=skip_volume_check,json=skipVolumeCheck,proto3\" json:\"skip_volume_check,omitempty\"`\n\t// Skip the secondary disk check (e.g. underlying disk for RAID or LVM).\n\tSkipSecondaryCheck bool `protobuf:\"varint,5,opt,name=skip_secondary_check,json=skipSecondaryCheck,proto3\" json:\"skip_secondary_check,omitempty\"`\n\t// Drop the partition (only applies if the device is a partition).\n\tDropPartition bool `protobuf:\"varint,4,opt,name=drop_partition,json=dropPartition,proto3\" json:\"drop_partition,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BlockDeviceWipeDescriptor) Reset() {\n\t*x = BlockDeviceWipeDescriptor{}\n\tmi := &file_storage_storage_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BlockDeviceWipeDescriptor) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BlockDeviceWipeDescriptor) ProtoMessage() {}\n\nfunc (x *BlockDeviceWipeDescriptor) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BlockDeviceWipeDescriptor.ProtoReflect.Descriptor instead.\nfunc (*BlockDeviceWipeDescriptor) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *BlockDeviceWipeDescriptor) GetDevice() string {\n\tif x != nil {\n\t\treturn x.Device\n\t}\n\treturn \"\"\n}\n\nfunc (x *BlockDeviceWipeDescriptor) GetMethod() BlockDeviceWipeDescriptor_Method {\n\tif x != nil {\n\t\treturn x.Method\n\t}\n\treturn BlockDeviceWipeDescriptor_FAST\n}\n\nfunc (x *BlockDeviceWipeDescriptor) GetSkipVolumeCheck() bool {\n\tif x != nil {\n\t\treturn x.SkipVolumeCheck\n\t}\n\treturn false\n}\n\nfunc (x *BlockDeviceWipeDescriptor) GetSkipSecondaryCheck() bool {\n\tif x != nil {\n\t\treturn x.SkipSecondaryCheck\n\t}\n\treturn false\n}\n\nfunc (x *BlockDeviceWipeDescriptor) GetDropPartition() bool {\n\tif x != nil {\n\t\treturn x.DropPartition\n\t}\n\treturn false\n}\n\ntype BlockDeviceWipeResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*BlockDeviceWipe     `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BlockDeviceWipeResponse) Reset() {\n\t*x = BlockDeviceWipeResponse{}\n\tmi := &file_storage_storage_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BlockDeviceWipeResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BlockDeviceWipeResponse) ProtoMessage() {}\n\nfunc (x *BlockDeviceWipeResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BlockDeviceWipeResponse.ProtoReflect.Descriptor instead.\nfunc (*BlockDeviceWipeResponse) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *BlockDeviceWipeResponse) GetMessages() []*BlockDeviceWipe {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\ntype BlockDeviceWipe struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BlockDeviceWipe) Reset() {\n\t*x = BlockDeviceWipe{}\n\tmi := &file_storage_storage_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BlockDeviceWipe) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BlockDeviceWipe) ProtoMessage() {}\n\nfunc (x *BlockDeviceWipe) ProtoReflect() protoreflect.Message {\n\tmi := &file_storage_storage_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BlockDeviceWipe.ProtoReflect.Descriptor instead.\nfunc (*BlockDeviceWipe) Descriptor() ([]byte, []int) {\n\treturn file_storage_storage_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *BlockDeviceWipe) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nvar File_storage_storage_proto protoreflect.FileDescriptor\n\nconst file_storage_storage_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x15storage/storage.proto\\x12\\astorage\\x1a\\x13common/common.proto\\x1a\\x1bgoogle/protobuf/empty.proto\\\"\\xa8\\x03\\n\" +\n\t\"\\x04Disk\\x12\\x12\\n\" +\n\t\"\\x04size\\x18\\x01 \\x01(\\x04R\\x04size\\x12\\x14\\n\" +\n\t\"\\x05model\\x18\\x02 \\x01(\\tR\\x05model\\x12\\x1f\\n\" +\n\t\"\\vdevice_name\\x18\\x03 \\x01(\\tR\\n\" +\n\t\"deviceName\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x04 \\x01(\\tR\\x04name\\x12\\x16\\n\" +\n\t\"\\x06serial\\x18\\x05 \\x01(\\tR\\x06serial\\x12\\x1a\\n\" +\n\t\"\\bmodalias\\x18\\x06 \\x01(\\tR\\bmodalias\\x12\\x12\\n\" +\n\t\"\\x04uuid\\x18\\a \\x01(\\tR\\x04uuid\\x12\\x12\\n\" +\n\t\"\\x04wwid\\x18\\b \\x01(\\tR\\x04wwid\\x12*\\n\" +\n\t\"\\x04type\\x18\\t \\x01(\\x0e2\\x16.storage.Disk.DiskTypeR\\x04type\\x12\\x19\\n\" +\n\t\"\\bbus_path\\x18\\n\" +\n\t\" \\x01(\\tR\\abusPath\\x12\\x1f\\n\" +\n\t\"\\vsystem_disk\\x18\\v \\x01(\\bR\\n\" +\n\t\"systemDisk\\x12\\x1c\\n\" +\n\t\"\\tsubsystem\\x18\\f \\x01(\\tR\\tsubsystem\\x12\\x1a\\n\" +\n\t\"\\breadonly\\x18\\r \\x01(\\bR\\breadonly\\\"C\\n\" +\n\t\"\\bDiskType\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03SSD\\x10\\x01\\x12\\a\\n\" +\n\t\"\\x03HDD\\x10\\x02\\x12\\b\\n\" +\n\t\"\\x04NVME\\x10\\x03\\x12\\x06\\n\" +\n\t\"\\x02SD\\x10\\x04\\x12\\x06\\n\" +\n\t\"\\x02CD\\x10\\x05\\\"Z\\n\" +\n\t\"\\x05Disks\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12#\\n\" +\n\t\"\\x05disks\\x18\\x02 \\x03(\\v2\\r.storage.DiskR\\x05disks\\\";\\n\" +\n\t\"\\rDisksResponse\\x12*\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x0e.storage.DisksR\\bmessages\\\"V\\n\" +\n\t\"\\x16BlockDeviceWipeRequest\\x12<\\n\" +\n\t\"\\adevices\\x18\\x01 \\x03(\\v2\\\".storage.BlockDeviceWipeDescriptorR\\adevices\\\"\\x9b\\x02\\n\" +\n\t\"\\x19BlockDeviceWipeDescriptor\\x12\\x16\\n\" +\n\t\"\\x06device\\x18\\x01 \\x01(\\tR\\x06device\\x12A\\n\" +\n\t\"\\x06method\\x18\\x02 \\x01(\\x0e2).storage.BlockDeviceWipeDescriptor.MethodR\\x06method\\x12*\\n\" +\n\t\"\\x11skip_volume_check\\x18\\x03 \\x01(\\bR\\x0fskipVolumeCheck\\x120\\n\" +\n\t\"\\x14skip_secondary_check\\x18\\x05 \\x01(\\bR\\x12skipSecondaryCheck\\x12%\\n\" +\n\t\"\\x0edrop_partition\\x18\\x04 \\x01(\\bR\\rdropPartition\\\"\\x1e\\n\" +\n\t\"\\x06Method\\x12\\b\\n\" +\n\t\"\\x04FAST\\x10\\x00\\x12\\n\" +\n\t\"\\n\" +\n\t\"\\x06ZEROES\\x10\\x01\\\"O\\n\" +\n\t\"\\x17BlockDeviceWipeResponse\\x124\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\x18.storage.BlockDeviceWipeR\\bmessages\\\"?\\n\" +\n\t\"\\x0fBlockDeviceWipe\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata2\\x9f\\x01\\n\" +\n\t\"\\x0eStorageService\\x127\\n\" +\n\t\"\\x05Disks\\x12\\x16.google.protobuf.Empty\\x1a\\x16.storage.DisksResponse\\x12T\\n\" +\n\t\"\\x0fBlockDeviceWipe\\x12\\x1f.storage.BlockDeviceWipeRequest\\x1a .storage.BlockDeviceWipeResponseBN\\n\" +\n\t\"\\x15dev.talos.api.storageZ5github.com/siderolabs/talos/pkg/machinery/api/storageb\\x06proto3\"\n\nvar (\n\tfile_storage_storage_proto_rawDescOnce sync.Once\n\tfile_storage_storage_proto_rawDescData []byte\n)\n\nfunc file_storage_storage_proto_rawDescGZIP() []byte {\n\tfile_storage_storage_proto_rawDescOnce.Do(func() {\n\t\tfile_storage_storage_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_storage_storage_proto_rawDesc), len(file_storage_storage_proto_rawDesc)))\n\t})\n\treturn file_storage_storage_proto_rawDescData\n}\n\nvar file_storage_storage_proto_enumTypes = make([]protoimpl.EnumInfo, 2)\nvar file_storage_storage_proto_msgTypes = make([]protoimpl.MessageInfo, 7)\nvar file_storage_storage_proto_goTypes = []any{\n\t(Disk_DiskType)(0),                    // 0: storage.Disk.DiskType\n\t(BlockDeviceWipeDescriptor_Method)(0), // 1: storage.BlockDeviceWipeDescriptor.Method\n\t(*Disk)(nil),                          // 2: storage.Disk\n\t(*Disks)(nil),                         // 3: storage.Disks\n\t(*DisksResponse)(nil),                 // 4: storage.DisksResponse\n\t(*BlockDeviceWipeRequest)(nil),        // 5: storage.BlockDeviceWipeRequest\n\t(*BlockDeviceWipeDescriptor)(nil),     // 6: storage.BlockDeviceWipeDescriptor\n\t(*BlockDeviceWipeResponse)(nil),       // 7: storage.BlockDeviceWipeResponse\n\t(*BlockDeviceWipe)(nil),               // 8: storage.BlockDeviceWipe\n\t(*common.Metadata)(nil),               // 9: common.Metadata\n\t(*emptypb.Empty)(nil),                 // 10: google.protobuf.Empty\n}\nvar file_storage_storage_proto_depIdxs = []int32{\n\t0,  // 0: storage.Disk.type:type_name -> storage.Disk.DiskType\n\t9,  // 1: storage.Disks.metadata:type_name -> common.Metadata\n\t2,  // 2: storage.Disks.disks:type_name -> storage.Disk\n\t3,  // 3: storage.DisksResponse.messages:type_name -> storage.Disks\n\t6,  // 4: storage.BlockDeviceWipeRequest.devices:type_name -> storage.BlockDeviceWipeDescriptor\n\t1,  // 5: storage.BlockDeviceWipeDescriptor.method:type_name -> storage.BlockDeviceWipeDescriptor.Method\n\t8,  // 6: storage.BlockDeviceWipeResponse.messages:type_name -> storage.BlockDeviceWipe\n\t9,  // 7: storage.BlockDeviceWipe.metadata:type_name -> common.Metadata\n\t10, // 8: storage.StorageService.Disks:input_type -> google.protobuf.Empty\n\t5,  // 9: storage.StorageService.BlockDeviceWipe:input_type -> storage.BlockDeviceWipeRequest\n\t4,  // 10: storage.StorageService.Disks:output_type -> storage.DisksResponse\n\t7,  // 11: storage.StorageService.BlockDeviceWipe:output_type -> storage.BlockDeviceWipeResponse\n\t10, // [10:12] is the sub-list for method output_type\n\t8,  // [8:10] is the sub-list for method input_type\n\t8,  // [8:8] is the sub-list for extension type_name\n\t8,  // [8:8] is the sub-list for extension extendee\n\t0,  // [0:8] is the sub-list for field type_name\n}\n\nfunc init() { file_storage_storage_proto_init() }\nfunc file_storage_storage_proto_init() {\n\tif File_storage_storage_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_storage_storage_proto_rawDesc), len(file_storage_storage_proto_rawDesc)),\n\t\t\tNumEnums:      2,\n\t\t\tNumMessages:   7,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_storage_storage_proto_goTypes,\n\t\tDependencyIndexes: file_storage_storage_proto_depIdxs,\n\t\tEnumInfos:         file_storage_storage_proto_enumTypes,\n\t\tMessageInfos:      file_storage_storage_proto_msgTypes,\n\t}.Build()\n\tFile_storage_storage_proto = out.File\n\tfile_storage_storage_proto_goTypes = nil\n\tfile_storage_storage_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/storage/storage_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: storage/storage.proto\n\npackage storage\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tStorageService_Disks_FullMethodName           = \"/storage.StorageService/Disks\"\n\tStorageService_BlockDeviceWipe_FullMethodName = \"/storage.StorageService/BlockDeviceWipe\"\n)\n\n// StorageServiceClient is the client API for StorageService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// StorageService represents the storage service.\ntype StorageServiceClient interface {\n\tDisks(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DisksResponse, error)\n\t// BlockDeviceWipe performs a wipe of the blockdevice (partition or disk).\n\t//\n\t// The method doesn't require a reboot, and it can only wipe blockdevices which are not\n\t// being used as volumes at the moment.\n\t// Wiping of volumes requires a different API.\n\tBlockDeviceWipe(ctx context.Context, in *BlockDeviceWipeRequest, opts ...grpc.CallOption) (*BlockDeviceWipeResponse, error)\n}\n\ntype storageServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewStorageServiceClient(cc grpc.ClientConnInterface) StorageServiceClient {\n\treturn &storageServiceClient{cc}\n}\n\nfunc (c *storageServiceClient) Disks(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*DisksResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(DisksResponse)\n\terr := c.cc.Invoke(ctx, StorageService_Disks_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *storageServiceClient) BlockDeviceWipe(ctx context.Context, in *BlockDeviceWipeRequest, opts ...grpc.CallOption) (*BlockDeviceWipeResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(BlockDeviceWipeResponse)\n\terr := c.cc.Invoke(ctx, StorageService_BlockDeviceWipe_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// StorageServiceServer is the server API for StorageService service.\n// All implementations must embed UnimplementedStorageServiceServer\n// for forward compatibility.\n//\n// StorageService represents the storage service.\ntype StorageServiceServer interface {\n\tDisks(context.Context, *emptypb.Empty) (*DisksResponse, error)\n\t// BlockDeviceWipe performs a wipe of the blockdevice (partition or disk).\n\t//\n\t// The method doesn't require a reboot, and it can only wipe blockdevices which are not\n\t// being used as volumes at the moment.\n\t// Wiping of volumes requires a different API.\n\tBlockDeviceWipe(context.Context, *BlockDeviceWipeRequest) (*BlockDeviceWipeResponse, error)\n\tmustEmbedUnimplementedStorageServiceServer()\n}\n\n// UnimplementedStorageServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedStorageServiceServer struct{}\n\nfunc (UnimplementedStorageServiceServer) Disks(context.Context, *emptypb.Empty) (*DisksResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Disks not implemented\")\n}\nfunc (UnimplementedStorageServiceServer) BlockDeviceWipe(context.Context, *BlockDeviceWipeRequest) (*BlockDeviceWipeResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method BlockDeviceWipe not implemented\")\n}\nfunc (UnimplementedStorageServiceServer) mustEmbedUnimplementedStorageServiceServer() {}\nfunc (UnimplementedStorageServiceServer) testEmbeddedByValue()                        {}\n\n// UnsafeStorageServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to StorageServiceServer will\n// result in compilation errors.\ntype UnsafeStorageServiceServer interface {\n\tmustEmbedUnimplementedStorageServiceServer()\n}\n\nfunc RegisterStorageServiceServer(s grpc.ServiceRegistrar, srv StorageServiceServer) {\n\t// If the following call panics, it indicates UnimplementedStorageServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&StorageService_ServiceDesc, srv)\n}\n\nfunc _StorageService_Disks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(StorageServiceServer).Disks(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: StorageService_Disks_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(StorageServiceServer).Disks(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _StorageService_BlockDeviceWipe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BlockDeviceWipeRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(StorageServiceServer).BlockDeviceWipe(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: StorageService_BlockDeviceWipe_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(StorageServiceServer).BlockDeviceWipe(ctx, req.(*BlockDeviceWipeRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// StorageService_ServiceDesc is the grpc.ServiceDesc for StorageService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar StorageService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"storage.StorageService\",\n\tHandlerType: (*StorageServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Disks\",\n\t\t\tHandler:    _StorageService_Disks_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"BlockDeviceWipe\",\n\t\t\tHandler:    _StorageService_BlockDeviceWipe_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"storage/storage.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/storage/storage_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: storage/storage.proto\n\npackage storage\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *Disk) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Disk) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Disk) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Readonly {\n\t\ti--\n\t\tif m.Readonly {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x68\n\t}\n\tif len(m.Subsystem) > 0 {\n\t\ti -= len(m.Subsystem)\n\t\tcopy(dAtA[i:], m.Subsystem)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Subsystem)))\n\t\ti--\n\t\tdAtA[i] = 0x62\n\t}\n\tif m.SystemDisk {\n\t\ti--\n\t\tif m.SystemDisk {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x58\n\t}\n\tif len(m.BusPath) > 0 {\n\t\ti -= len(m.BusPath)\n\t\tcopy(dAtA[i:], m.BusPath)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.BusPath)))\n\t\ti--\n\t\tdAtA[i] = 0x52\n\t}\n\tif m.Type != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type))\n\t\ti--\n\t\tdAtA[i] = 0x48\n\t}\n\tif len(m.Wwid) > 0 {\n\t\ti -= len(m.Wwid)\n\t\tcopy(dAtA[i:], m.Wwid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Wwid)))\n\t\ti--\n\t\tdAtA[i] = 0x42\n\t}\n\tif len(m.Uuid) > 0 {\n\t\ti -= len(m.Uuid)\n\t\tcopy(dAtA[i:], m.Uuid)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid)))\n\t\ti--\n\t\tdAtA[i] = 0x3a\n\t}\n\tif len(m.Modalias) > 0 {\n\t\ti -= len(m.Modalias)\n\t\tcopy(dAtA[i:], m.Modalias)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Modalias)))\n\t\ti--\n\t\tdAtA[i] = 0x32\n\t}\n\tif len(m.Serial) > 0 {\n\t\ti -= len(m.Serial)\n\t\tcopy(dAtA[i:], m.Serial)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Serial)))\n\t\ti--\n\t\tdAtA[i] = 0x2a\n\t}\n\tif len(m.Name) > 0 {\n\t\ti -= len(m.Name)\n\t\tcopy(dAtA[i:], m.Name)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif len(m.DeviceName) > 0 {\n\t\ti -= len(m.DeviceName)\n\t\tcopy(dAtA[i:], m.DeviceName)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DeviceName)))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Model) > 0 {\n\t\ti -= len(m.Model)\n\t\tcopy(dAtA[i:], m.Model)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Model)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Size != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size))\n\t\ti--\n\t\tdAtA[i] = 0x8\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Disks) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Disks) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Disks) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Disks) > 0 {\n\t\tfor iNdEx := len(m.Disks) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Disks[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0x12\n\t\t}\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *DisksResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *DisksResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *DisksResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BlockDeviceWipeRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockDeviceWipeRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BlockDeviceWipeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Devices) > 0 {\n\t\tfor iNdEx := len(m.Devices) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Devices[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BlockDeviceWipeDescriptor) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockDeviceWipeDescriptor) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BlockDeviceWipeDescriptor) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.SkipSecondaryCheck {\n\t\ti--\n\t\tif m.SkipSecondaryCheck {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x28\n\t}\n\tif m.DropPartition {\n\t\ti--\n\t\tif m.DropPartition {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x20\n\t}\n\tif m.SkipVolumeCheck {\n\t\ti--\n\t\tif m.SkipVolumeCheck {\n\t\t\tdAtA[i] = 1\n\t\t} else {\n\t\t\tdAtA[i] = 0\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0x18\n\t}\n\tif m.Method != 0 {\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(m.Method))\n\t\ti--\n\t\tdAtA[i] = 0x10\n\t}\n\tif len(m.Device) > 0 {\n\t\ti -= len(m.Device)\n\t\tcopy(dAtA[i:], m.Device)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Device)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BlockDeviceWipeResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockDeviceWipeResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BlockDeviceWipeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *BlockDeviceWipe) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *BlockDeviceWipe) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *BlockDeviceWipe) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Disk) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Size != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Size))\n\t}\n\tl = len(m.Model)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.DeviceName)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Name)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Serial)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Modalias)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Uuid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Wwid)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Type != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Type))\n\t}\n\tl = len(m.BusPath)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.SystemDisk {\n\t\tn += 2\n\t}\n\tl = len(m.Subsystem)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Readonly {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Disks) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif len(m.Disks) > 0 {\n\t\tfor _, e := range m.Disks {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *DisksResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BlockDeviceWipeRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Devices) > 0 {\n\t\tfor _, e := range m.Devices {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BlockDeviceWipeDescriptor) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Device)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Method != 0 {\n\t\tn += 1 + protohelpers.SizeOfVarint(uint64(m.Method))\n\t}\n\tif m.SkipVolumeCheck {\n\t\tn += 2\n\t}\n\tif m.DropPartition {\n\t\tn += 2\n\t}\n\tif m.SkipSecondaryCheck {\n\t\tn += 2\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BlockDeviceWipeResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *BlockDeviceWipe) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Disk) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Disk: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Disk: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Size\", wireType)\n\t\t\t}\n\t\t\tm.Size = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Size |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Model\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Model = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DeviceName\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.DeviceName = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Name\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Name = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 5:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Serial\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Serial = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 6:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Modalias\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Modalias = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 7:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Uuid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Uuid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 8:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Wwid\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Wwid = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 9:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Type\", wireType)\n\t\t\t}\n\t\t\tm.Type = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Type |= Disk_DiskType(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 10:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field BusPath\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.BusPath = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 11:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SystemDisk\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SystemDisk = bool(v != 0)\n\t\tcase 12:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Subsystem\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Subsystem = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 13:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Readonly\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.Readonly = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Disks) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Disks: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Disks: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Disks\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Disks = append(m.Disks, &Disk{})\n\t\t\tif err := m.Disks[len(m.Disks)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *DisksResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: DisksResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: DisksResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Disks{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BlockDeviceWipeRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Devices\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Devices = append(m.Devices, &BlockDeviceWipeDescriptor{})\n\t\t\tif err := m.Devices[len(m.Devices)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BlockDeviceWipeDescriptor) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeDescriptor: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeDescriptor: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Device\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Device = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Method\", wireType)\n\t\t\t}\n\t\t\tm.Method = 0\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tm.Method |= BlockDeviceWipeDescriptor_Method(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\tcase 3:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipVolumeCheck\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipVolumeCheck = bool(v != 0)\n\t\tcase 4:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field DropPartition\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.DropPartition = bool(v != 0)\n\t\tcase 5:\n\t\t\tif wireType != 0 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field SkipSecondaryCheck\", wireType)\n\t\t\t}\n\t\t\tvar v int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tv |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tm.SkipSecondaryCheck = bool(v != 0)\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BlockDeviceWipeResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipeResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &BlockDeviceWipe{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *BlockDeviceWipe) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipe: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: BlockDeviceWipe: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/time/time.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11-devel\n// \tprotoc        (unknown)\n// source: time/time.proto\n\npackage time\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\tunsafe \"unsafe\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The response message containing the ntp server\ntype TimeRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tServer        string                 `protobuf:\"bytes,1,opt,name=server,proto3\" json:\"server,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TimeRequest) Reset() {\n\t*x = TimeRequest{}\n\tmi := &file_time_time_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeRequest) ProtoMessage() {}\n\nfunc (x *TimeRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_time_time_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TimeRequest.ProtoReflect.Descriptor instead.\nfunc (*TimeRequest) Descriptor() ([]byte, []int) {\n\treturn file_time_time_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *TimeRequest) GetServer() string {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn \"\"\n}\n\ntype Time struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMetadata      *common.Metadata       `protobuf:\"bytes,1,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tServer        string                 `protobuf:\"bytes,2,opt,name=server,proto3\" json:\"server,omitempty\"`\n\tLocaltime     *timestamppb.Timestamp `protobuf:\"bytes,3,opt,name=localtime,proto3\" json:\"localtime,omitempty\"`\n\tRemotetime    *timestamppb.Timestamp `protobuf:\"bytes,4,opt,name=remotetime,proto3\" json:\"remotetime,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Time) Reset() {\n\t*x = Time{}\n\tmi := &file_time_time_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Time) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Time) ProtoMessage() {}\n\nfunc (x *Time) ProtoReflect() protoreflect.Message {\n\tmi := &file_time_time_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Time.ProtoReflect.Descriptor instead.\nfunc (*Time) Descriptor() ([]byte, []int) {\n\treturn file_time_time_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Time) GetMetadata() *common.Metadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *Time) GetServer() string {\n\tif x != nil {\n\t\treturn x.Server\n\t}\n\treturn \"\"\n}\n\nfunc (x *Time) GetLocaltime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Localtime\n\t}\n\treturn nil\n}\n\nfunc (x *Time) GetRemotetime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Remotetime\n\t}\n\treturn nil\n}\n\n// The response message containing the ntp server, time, and offset\ntype TimeResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"open.v1\"`\n\tMessages      []*Time                `protobuf:\"bytes,1,rep,name=messages,proto3\" json:\"messages,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TimeResponse) Reset() {\n\t*x = TimeResponse{}\n\tmi := &file_time_time_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeResponse) ProtoMessage() {}\n\nfunc (x *TimeResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_time_time_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TimeResponse.ProtoReflect.Descriptor instead.\nfunc (*TimeResponse) Descriptor() ([]byte, []int) {\n\treturn file_time_time_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *TimeResponse) GetMessages() []*Time {\n\tif x != nil {\n\t\treturn x.Messages\n\t}\n\treturn nil\n}\n\nvar File_time_time_proto protoreflect.FileDescriptor\n\nconst file_time_time_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x0ftime/time.proto\\x12\\x04time\\x1a\\x13common/common.proto\\x1a\\x1bgoogle/protobuf/empty.proto\\x1a\\x1fgoogle/protobuf/timestamp.proto\\\"%\\n\" +\n\t\"\\vTimeRequest\\x12\\x16\\n\" +\n\t\"\\x06server\\x18\\x01 \\x01(\\tR\\x06server\\\"\\xc2\\x01\\n\" +\n\t\"\\x04Time\\x12,\\n\" +\n\t\"\\bmetadata\\x18\\x01 \\x01(\\v2\\x10.common.MetadataR\\bmetadata\\x12\\x16\\n\" +\n\t\"\\x06server\\x18\\x02 \\x01(\\tR\\x06server\\x128\\n\" +\n\t\"\\tlocaltime\\x18\\x03 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\tlocaltime\\x12:\\n\" +\n\t\"\\n\" +\n\t\"remotetime\\x18\\x04 \\x01(\\v2\\x1a.google.protobuf.TimestampR\\n\" +\n\t\"remotetime\\\"6\\n\" +\n\t\"\\fTimeResponse\\x12&\\n\" +\n\t\"\\bmessages\\x18\\x01 \\x03(\\v2\\n\" +\n\t\".time.TimeR\\bmessages2u\\n\" +\n\t\"\\vTimeService\\x122\\n\" +\n\t\"\\x04Time\\x12\\x16.google.protobuf.Empty\\x1a\\x12.time.TimeResponse\\x122\\n\" +\n\t\"\\tTimeCheck\\x12\\x11.time.TimeRequest\\x1a\\x12.time.TimeResponseBH\\n\" +\n\t\"\\x12dev.talos.api.timeZ2github.com/siderolabs/talos/pkg/machinery/api/timeb\\x06proto3\"\n\nvar (\n\tfile_time_time_proto_rawDescOnce sync.Once\n\tfile_time_time_proto_rawDescData []byte\n)\n\nfunc file_time_time_proto_rawDescGZIP() []byte {\n\tfile_time_time_proto_rawDescOnce.Do(func() {\n\t\tfile_time_time_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_time_time_proto_rawDesc), len(file_time_time_proto_rawDesc)))\n\t})\n\treturn file_time_time_proto_rawDescData\n}\n\nvar file_time_time_proto_msgTypes = make([]protoimpl.MessageInfo, 3)\nvar file_time_time_proto_goTypes = []any{\n\t(*TimeRequest)(nil),           // 0: time.TimeRequest\n\t(*Time)(nil),                  // 1: time.Time\n\t(*TimeResponse)(nil),          // 2: time.TimeResponse\n\t(*common.Metadata)(nil),       // 3: common.Metadata\n\t(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp\n\t(*emptypb.Empty)(nil),         // 5: google.protobuf.Empty\n}\nvar file_time_time_proto_depIdxs = []int32{\n\t3, // 0: time.Time.metadata:type_name -> common.Metadata\n\t4, // 1: time.Time.localtime:type_name -> google.protobuf.Timestamp\n\t4, // 2: time.Time.remotetime:type_name -> google.protobuf.Timestamp\n\t1, // 3: time.TimeResponse.messages:type_name -> time.Time\n\t5, // 4: time.TimeService.Time:input_type -> google.protobuf.Empty\n\t0, // 5: time.TimeService.TimeCheck:input_type -> time.TimeRequest\n\t2, // 6: time.TimeService.Time:output_type -> time.TimeResponse\n\t2, // 7: time.TimeService.TimeCheck:output_type -> time.TimeResponse\n\t6, // [6:8] is the sub-list for method output_type\n\t4, // [4:6] is the sub-list for method input_type\n\t4, // [4:4] is the sub-list for extension type_name\n\t4, // [4:4] is the sub-list for extension extendee\n\t0, // [0:4] is the sub-list for field type_name\n}\n\nfunc init() { file_time_time_proto_init() }\nfunc file_time_time_proto_init() {\n\tif File_time_time_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_time_time_proto_rawDesc), len(file_time_time_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   3,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_time_time_proto_goTypes,\n\t\tDependencyIndexes: file_time_time_proto_depIdxs,\n\t\tMessageInfos:      file_time_time_proto_msgTypes,\n\t}.Build()\n\tFile_time_time_proto = out.File\n\tfile_time_time_proto_goTypes = nil\n\tfile_time_time_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "pkg/machinery/api/time/time_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.6.1\n// - protoc             (unknown)\n// source: time/time.proto\n\npackage time\n\nimport (\n\tcontext \"context\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\temptypb \"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.64.0 or later.\nconst _ = grpc.SupportPackageIsVersion9\n\nconst (\n\tTimeService_Time_FullMethodName      = \"/time.TimeService/Time\"\n\tTimeService_TimeCheck_FullMethodName = \"/time.TimeService/TimeCheck\"\n)\n\n// TimeServiceClient is the client API for TimeService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\n//\n// The time service definition.\ntype TimeServiceClient interface {\n\tTime(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*TimeResponse, error)\n\tTimeCheck(ctx context.Context, in *TimeRequest, opts ...grpc.CallOption) (*TimeResponse, error)\n}\n\ntype timeServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewTimeServiceClient(cc grpc.ClientConnInterface) TimeServiceClient {\n\treturn &timeServiceClient{cc}\n}\n\nfunc (c *timeServiceClient) Time(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*TimeResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(TimeResponse)\n\terr := c.cc.Invoke(ctx, TimeService_Time_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *timeServiceClient) TimeCheck(ctx context.Context, in *TimeRequest, opts ...grpc.CallOption) (*TimeResponse, error) {\n\tcOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)\n\tout := new(TimeResponse)\n\terr := c.cc.Invoke(ctx, TimeService_TimeCheck_FullMethodName, in, out, cOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// TimeServiceServer is the server API for TimeService service.\n// All implementations must embed UnimplementedTimeServiceServer\n// for forward compatibility.\n//\n// The time service definition.\ntype TimeServiceServer interface {\n\tTime(context.Context, *emptypb.Empty) (*TimeResponse, error)\n\tTimeCheck(context.Context, *TimeRequest) (*TimeResponse, error)\n\tmustEmbedUnimplementedTimeServiceServer()\n}\n\n// UnimplementedTimeServiceServer must be embedded to have\n// forward compatible implementations.\n//\n// NOTE: this should be embedded by value instead of pointer to avoid a nil\n// pointer dereference when methods are called.\ntype UnimplementedTimeServiceServer struct{}\n\nfunc (UnimplementedTimeServiceServer) Time(context.Context, *emptypb.Empty) (*TimeResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method Time not implemented\")\n}\nfunc (UnimplementedTimeServiceServer) TimeCheck(context.Context, *TimeRequest) (*TimeResponse, error) {\n\treturn nil, status.Error(codes.Unimplemented, \"method TimeCheck not implemented\")\n}\nfunc (UnimplementedTimeServiceServer) mustEmbedUnimplementedTimeServiceServer() {}\nfunc (UnimplementedTimeServiceServer) testEmbeddedByValue()                     {}\n\n// UnsafeTimeServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to TimeServiceServer will\n// result in compilation errors.\ntype UnsafeTimeServiceServer interface {\n\tmustEmbedUnimplementedTimeServiceServer()\n}\n\nfunc RegisterTimeServiceServer(s grpc.ServiceRegistrar, srv TimeServiceServer) {\n\t// If the following call panics, it indicates UnimplementedTimeServiceServer was\n\t// embedded by pointer and is nil.  This will cause panics if an\n\t// unimplemented method is ever invoked, so we test this at initialization\n\t// time to prevent it from happening at runtime later due to I/O.\n\tif t, ok := srv.(interface{ testEmbeddedByValue() }); ok {\n\t\tt.testEmbeddedByValue()\n\t}\n\ts.RegisterService(&TimeService_ServiceDesc, srv)\n}\n\nfunc _TimeService_Time_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(emptypb.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(TimeServiceServer).Time(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: TimeService_Time_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(TimeServiceServer).Time(ctx, req.(*emptypb.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _TimeService_TimeCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(TimeRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(TimeServiceServer).TimeCheck(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: TimeService_TimeCheck_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(TimeServiceServer).TimeCheck(ctx, req.(*TimeRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// TimeService_ServiceDesc is the grpc.ServiceDesc for TimeService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar TimeService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"time.TimeService\",\n\tHandlerType: (*TimeServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Time\",\n\t\t\tHandler:    _TimeService_Time_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TimeCheck\",\n\t\t\tHandler:    _TimeService_TimeCheck_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"time/time.proto\",\n}\n"
  },
  {
    "path": "pkg/machinery/api/time/time_vtproto.pb.go",
    "content": "// Code generated by protoc-gen-go-vtproto. DO NOT EDIT.\n// protoc-gen-go-vtproto version: v0.6.1-0.20250313105119-ba97887b0a25\n// source: time/time.proto\n\npackage time\n\nimport (\n\tfmt \"fmt\"\n\tio \"io\"\n\n\tprotohelpers \"github.com/planetscale/vtprotobuf/protohelpers\"\n\ttimestamppb \"github.com/planetscale/vtprotobuf/types/known/timestamppb\"\n\tproto \"google.golang.org/protobuf/proto\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb1 \"google.golang.org/protobuf/types/known/timestamppb\"\n\n\tcommon \"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nfunc (m *TimeRequest) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TimeRequest) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TimeRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Server) > 0 {\n\t\ti -= len(m.Server)\n\t\tcopy(dAtA[i:], m.Server)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Server)))\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *Time) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *Time) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *Time) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif m.Remotetime != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.Remotetime).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x22\n\t}\n\tif m.Localtime != nil {\n\t\tsize, err := (*timestamppb.Timestamp)(m.Localtime).MarshalToSizedBufferVT(dAtA[:i])\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\ti -= size\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\ti--\n\t\tdAtA[i] = 0x1a\n\t}\n\tif len(m.Server) > 0 {\n\t\ti -= len(m.Server)\n\t\tcopy(dAtA[i:], m.Server)\n\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Server)))\n\t\ti--\n\t\tdAtA[i] = 0x12\n\t}\n\tif m.Metadata != nil {\n\t\tif vtmsg, ok := interface{}(m.Metadata).(interface {\n\t\t\tMarshalToSizedBufferVT([]byte) (int, error)\n\t\t}); ok {\n\t\t\tsize, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t} else {\n\t\t\tencoded, err := proto.Marshal(m.Metadata)\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= len(encoded)\n\t\t\tcopy(dAtA[i:], encoded)\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded)))\n\t\t}\n\t\ti--\n\t\tdAtA[i] = 0xa\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TimeResponse) MarshalVT() (dAtA []byte, err error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\tsize := m.SizeVT()\n\tdAtA = make([]byte, size)\n\tn, err := m.MarshalToSizedBufferVT(dAtA[:size])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dAtA[:n], nil\n}\n\nfunc (m *TimeResponse) MarshalToVT(dAtA []byte) (int, error) {\n\tsize := m.SizeVT()\n\treturn m.MarshalToSizedBufferVT(dAtA[:size])\n}\n\nfunc (m *TimeResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {\n\tif m == nil {\n\t\treturn 0, nil\n\t}\n\ti := len(dAtA)\n\t_ = i\n\tvar l int\n\t_ = l\n\tif m.unknownFields != nil {\n\t\ti -= len(m.unknownFields)\n\t\tcopy(dAtA[i:], m.unknownFields)\n\t}\n\tif len(m.Messages) > 0 {\n\t\tfor iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- {\n\t\t\tsize, err := m.Messages[iNdEx].MarshalToSizedBufferVT(dAtA[:i])\n\t\t\tif err != nil {\n\t\t\t\treturn 0, err\n\t\t\t}\n\t\t\ti -= size\n\t\t\ti = protohelpers.EncodeVarint(dAtA, i, uint64(size))\n\t\t\ti--\n\t\t\tdAtA[i] = 0xa\n\t\t}\n\t}\n\treturn len(dAtA) - i, nil\n}\n\nfunc (m *TimeRequest) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tl = len(m.Server)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *Time) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif m.Metadata != nil {\n\t\tif size, ok := interface{}(m.Metadata).(interface {\n\t\t\tSizeVT() int\n\t\t}); ok {\n\t\t\tl = size.SizeVT()\n\t\t} else {\n\t\t\tl = proto.Size(m.Metadata)\n\t\t}\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tl = len(m.Server)\n\tif l > 0 {\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Localtime != nil {\n\t\tl = (*timestamppb.Timestamp)(m.Localtime).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tif m.Remotetime != nil {\n\t\tl = (*timestamppb.Timestamp)(m.Remotetime).SizeVT()\n\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TimeResponse) SizeVT() (n int) {\n\tif m == nil {\n\t\treturn 0\n\t}\n\tvar l int\n\t_ = l\n\tif len(m.Messages) > 0 {\n\t\tfor _, e := range m.Messages {\n\t\t\tl = e.SizeVT()\n\t\t\tn += 1 + l + protohelpers.SizeOfVarint(uint64(l))\n\t\t}\n\t}\n\tn += len(m.unknownFields)\n\treturn n\n}\n\nfunc (m *TimeRequest) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TimeRequest: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TimeRequest: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Server\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Server = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *Time) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: Time: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: Time: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Metadata\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Metadata == nil {\n\t\t\t\tm.Metadata = &common.Metadata{}\n\t\t\t}\n\t\t\tif unmarshal, ok := interface{}(m.Metadata).(interface {\n\t\t\t\tUnmarshalVT([]byte) error\n\t\t\t}); ok {\n\t\t\t\tif err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Metadata); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 2:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Server\", wireType)\n\t\t\t}\n\t\t\tvar stringLen uint64\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tstringLen |= uint64(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tintStringLen := int(stringLen)\n\t\t\tif intStringLen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + intStringLen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Server = string(dAtA[iNdEx:postIndex])\n\t\t\tiNdEx = postIndex\n\t\tcase 3:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Localtime\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Localtime == nil {\n\t\t\t\tm.Localtime = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.Localtime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tcase 4:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Remotetime\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tif m.Remotetime == nil {\n\t\t\t\tm.Remotetime = &timestamppb1.Timestamp{}\n\t\t\t}\n\t\t\tif err := (*timestamppb.Timestamp)(m.Remotetime).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\nfunc (m *TimeResponse) UnmarshalVT(dAtA []byte) error {\n\tl := len(dAtA)\n\tiNdEx := 0\n\tfor iNdEx < l {\n\t\tpreIndex := iNdEx\n\t\tvar wire uint64\n\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\tif shift >= 64 {\n\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t}\n\t\t\tif iNdEx >= l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tb := dAtA[iNdEx]\n\t\t\tiNdEx++\n\t\t\twire |= uint64(b&0x7F) << shift\n\t\t\tif b < 0x80 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tfieldNum := int32(wire >> 3)\n\t\twireType := int(wire & 0x7)\n\t\tif wireType == 4 {\n\t\t\treturn fmt.Errorf(\"proto: TimeResponse: wiretype end group for non-group\")\n\t\t}\n\t\tif fieldNum <= 0 {\n\t\t\treturn fmt.Errorf(\"proto: TimeResponse: illegal tag %d (wire type %d)\", fieldNum, wire)\n\t\t}\n\t\tswitch fieldNum {\n\t\tcase 1:\n\t\t\tif wireType != 2 {\n\t\t\t\treturn fmt.Errorf(\"proto: wrong wireType = %d for field Messages\", wireType)\n\t\t\t}\n\t\t\tvar msglen int\n\t\t\tfor shift := uint(0); ; shift += 7 {\n\t\t\t\tif shift >= 64 {\n\t\t\t\t\treturn protohelpers.ErrIntOverflow\n\t\t\t\t}\n\t\t\t\tif iNdEx >= l {\n\t\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t\t}\n\t\t\t\tb := dAtA[iNdEx]\n\t\t\t\tiNdEx++\n\t\t\t\tmsglen |= int(b&0x7F) << shift\n\t\t\t\tif b < 0x80 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif msglen < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tpostIndex := iNdEx + msglen\n\t\t\tif postIndex < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif postIndex > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.Messages = append(m.Messages, &Time{})\n\t\t\tif err := m.Messages[len(m.Messages)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tiNdEx = postIndex\n\t\tdefault:\n\t\t\tiNdEx = preIndex\n\t\t\tskippy, err := protohelpers.Skip(dAtA[iNdEx:])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif (skippy < 0) || (iNdEx+skippy) < 0 {\n\t\t\t\treturn protohelpers.ErrInvalidLength\n\t\t\t}\n\t\t\tif (iNdEx + skippy) > l {\n\t\t\t\treturn io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\tm.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)\n\t\t\tiNdEx += skippy\n\t\t}\n\t}\n\n\tif iNdEx > l {\n\t\treturn io.ErrUnexpectedEOF\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/cel/build.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cel\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/google/cel-go/common\"\n\t\"github.com/google/cel-go/common/ast\"\n\t\"github.com/google/cel-go/common/types\"\n)\n\n// Builder allows building CEL expressions programmatically.\ntype Builder struct {\n\tast.ExprFactory\n\n\tenv    *cel.Env\n\tnextID int64\n}\n\n// NewBuilder creates a new builder.\nfunc NewBuilder(env *cel.Env) *Builder {\n\treturn &Builder{\n\t\tExprFactory: ast.NewExprFactory(),\n\t\tenv:         env,\n\t}\n}\n\n// NextID returns the next unique ID.\nfunc (b *Builder) NextID() int64 {\n\tb.nextID++\n\n\treturn b.nextID\n}\n\n// ToBooleanExpression converts the AST to a boolean expression.\nfunc (b *Builder) ToBooleanExpression(expr ast.Expr) (*Expression, error) {\n\trawAst := ast.NewAST(expr, nil)\n\n\tpbAst, err := ast.ToProto(rawAst)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcelAst, err := cel.CheckedExprToAstWithSource(pbAst, common.NewTextSource(\"\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar issues *cel.Issues\n\n\tcelAst, issues = b.env.Check(celAst)\n\tif issues != nil && issues.Err() != nil {\n\t\treturn nil, issues.Err()\n\t}\n\n\tif outputType := celAst.OutputType(); !outputType.IsExactType(types.BoolType) {\n\t\treturn nil, fmt.Errorf(\"expression output type is %s, expected bool\", outputType)\n\t}\n\n\treturn &Expression{\n\t\tast: celAst,\n\t}, nil\n}\n"
  },
  {
    "path": "pkg/machinery/cel/build_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cel_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n)\n\nfunc TestBuildDiskExpression(t *testing.T) {\n\tt.Parallel()\n\n\tbuilder := cel.NewBuilder(celenv.DiskLocator())\n\n\texpr := builder.NewSelect(\n\t\tbuilder.NextID(),\n\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\"rotational\",\n\t)\n\n\tout, err := builder.ToBooleanExpression(expr)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"disk.rotational\", out.String())\n}\n"
  },
  {
    "path": "pkg/machinery/cel/cel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cel provides helpers for working with CEL expressions.\npackage cel\n\nimport (\n\t\"encoding\"\n\t\"fmt\"\n\t\"math\"\n\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/siderolabs/protoenc\"\n\t\"go.yaml.in/yaml/v4\"\n\texprpb \"google.golang.org/genproto/googleapis/api/expr/v1alpha1\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// Expression is a CEL expression that can be marshaled/unmarshaled as part of the resource.\ntype Expression struct {\n\tast        *cel.Ast\n\texpression *string\n}\n\n// Check interfaces.\nvar (\n\t_ encoding.TextMarshaler   = Expression{}\n\t_ encoding.TextUnmarshaler = (*Expression)(nil)\n\t_ yaml.IsZeroer            = Expression{}\n)\n\n// MustExpression panics if the expression cannot be parsed.\nfunc MustExpression(expr Expression, err error) Expression {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn expr\n}\n\n// ParseBooleanExpression parses the expression and asserts the result to boolean.\nfunc ParseBooleanExpression(expression string, env *cel.Env) (Expression, error) {\n\tast, err := parseExpressionWithOutputType(expression, env, types.BoolType)\n\tif err != nil {\n\t\treturn Expression{}, err\n\t}\n\n\treturn Expression{ast: ast}, nil\n}\n\n// ParseDoubleExpression parses the expression and asserts the result to float.\nfunc ParseDoubleExpression(expression string, env *cel.Env) (Expression, error) {\n\tast, err := parseExpressionWithOutputType(expression, env, types.DoubleType)\n\tif err != nil {\n\t\treturn Expression{}, err\n\t}\n\n\treturn Expression{ast: ast}, nil\n}\n\n// parseExpressionWithOutputType parses the expression and asserts the result to boolean.\nfunc parseExpressionWithOutputType(expression string, env *cel.Env, expectedType *types.Type) (*cel.Ast, error) {\n\tast, issues := env.Parse(expression)\n\tif issues != nil && issues.Err() != nil {\n\t\treturn nil, issues.Err()\n\t}\n\n\tast, issues = env.Check(ast)\n\tif issues != nil && issues.Err() != nil {\n\t\treturn nil, issues.Err()\n\t}\n\n\tif outputType := ast.OutputType(); !outputType.IsExactType(expectedType) {\n\t\treturn nil, fmt.Errorf(\"expression output type is %s, expected %s\", outputType, expectedType)\n\t}\n\n\treturn ast, nil\n}\n\n// Merge imlements merge.Mergeable.\nfunc (expr *Expression) Merge(v any) error {\n\tother, ok := v.(Expression)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for expression merge %T\", v)\n\t}\n\n\texpr.ast = other.ast\n\texpr.expression = other.expression\n\n\treturn nil\n}\n\n// ParseBool parses the expression and asserts the result to boolean.\n//\n// ParseBoolean can be used after unmarshaling the expression from text.\nfunc (expr *Expression) ParseBool(env *cel.Env) error {\n\tif expr.ast != nil {\n\t\treturn nil\n\t}\n\n\tif expr.expression == nil {\n\t\tpanic(\"expression is not set\")\n\t}\n\n\tvar err error\n\n\texpr.ast, err = parseExpressionWithOutputType(*expr.expression, env, types.BoolType)\n\n\treturn err\n}\n\n// ParseDouble parses the expression and asserts the result to float.\n//\n// ParseDouble can be used after unmarshaling the expression from text.\nfunc (expr *Expression) ParseDouble(env *cel.Env) error {\n\tif expr.ast != nil {\n\t\treturn nil\n\t}\n\n\tif expr.expression == nil {\n\t\tpanic(\"expression is not set\")\n\t}\n\n\tvar err error\n\n\texpr.ast, err = parseExpressionWithOutputType(*expr.expression, env, types.DoubleType)\n\n\treturn err\n}\n\n// EvalBool evaluates the expression in the given environment.\nfunc (expr Expression) EvalBool(env *cel.Env, values map[string]any) (bool, error) {\n\tif err := expr.ParseBool(env); err != nil {\n\t\treturn false, err\n\t}\n\n\tprog, err := env.Program(expr.ast)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tout, _, err := prog.Eval(values)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tval, ok := out.Value().(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"expression output type is %s, expected bool\", out.Type())\n\t}\n\n\treturn val, nil\n}\n\n// EvalDouble evaluates the expression in the given environment.\nfunc (expr Expression) EvalDouble(env *cel.Env, values map[string]any) (float64, error) {\n\tif err := expr.ParseDouble(env); err != nil {\n\t\treturn math.NaN(), err\n\t}\n\n\tprog, err := env.Program(expr.ast)\n\tif err != nil {\n\t\treturn math.NaN(), err\n\t}\n\n\tout, _, err := prog.Eval(values)\n\tif err != nil {\n\t\treturn math.NaN(), err\n\t}\n\n\tval, ok := out.Value().(float64)\n\tif !ok {\n\t\treturn math.NaN(), fmt.Errorf(\"expression output type is %s, expected float64\", out.Type())\n\t}\n\n\treturn val, nil\n}\n\n// MarshalText marshals the expression to text.\nfunc (expr Expression) MarshalText() ([]byte, error) {\n\tif expr.expression != nil {\n\t\treturn []byte(*expr.expression), nil\n\t}\n\n\tif expr.ast != nil {\n\t\trepr, err := cel.AstToString(expr.ast)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn []byte(repr), nil\n\t}\n\n\treturn nil, nil\n}\n\n// UnmarshalText unmarshals the expression from text.\nfunc (expr *Expression) UnmarshalText(data []byte) error {\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\n\texpr.expression = new(string(data))\n\n\treturn nil\n}\n\n// String implements fmt.Stringer.\nfunc (expr Expression) String() string {\n\tb, err := expr.MarshalText()\n\tif err != nil {\n\t\treturn \"ERROR: \" + err.Error()\n\t}\n\n\treturn string(b)\n}\n\n// IsZero returns true if the expression is zero.\nfunc (expr Expression) IsZero() bool {\n\treturn expr.ast == nil && expr.expression == nil\n}\n\n// MarshalProto marshals the expression to proto.\nfunc (expr Expression) MarshalProto() ([]byte, error) {\n\tif expr.ast == nil {\n\t\treturn nil, nil\n\t}\n\n\tpbExpr, err := cel.AstToCheckedExpr(expr.ast)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn proto.Marshal(pbExpr)\n}\n\n// UnmarshalProto unmarshals the expression from proto.\nfunc (expr *Expression) UnmarshalProto(data []byte) error {\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\n\tpbExpr := &exprpb.CheckedExpr{}\n\tif err := proto.Unmarshal(data, pbExpr); err != nil {\n\t\treturn err\n\t}\n\n\texpr.ast = cel.CheckedExprToAst(pbExpr)\n\n\treturn nil\n}\n\nfunc init() {\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v Expression) ([]byte, error) {\n\t\t\treturn v.MarshalProto()\n\t\t},\n\t\tfunc(slc []byte) (Expression, error) {\n\t\t\tvar v Expression\n\n\t\t\terr := v.UnmarshalProto(slc)\n\n\t\t\treturn v, err\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/cel/cel_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cel_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n)\n\nfunc TestCELMarshal(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.DiskLocator()\n\n\ttype yamlTest struct {\n\t\tExpr cel.Expression `yaml:\"expr,omitempty\"`\n\t}\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\texpression cel.Expression\n\n\t\texpectedYAML string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\n\t\t\texpectedYAML: \"{}\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"system disk\",\n\n\t\t\texpression: cel.MustExpression(cel.ParseBooleanExpression(\"system_disk\", env)),\n\n\t\t\texpectedYAML: \"expr: system_disk\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"disk size and rotational\",\n\n\t\t\texpression: cel.MustExpression(cel.ParseBooleanExpression(\"disk.size > 1000u && !disk.rotational\", env)),\n\n\t\t\texpectedYAML: \"expr: disk.size > 1000u && !disk.rotational\\n\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tyamlTest := yamlTest{\n\t\t\t\tExpr: test.expression,\n\t\t\t}\n\n\t\t\tyaml, err := yaml.Marshal(yamlTest)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, test.expectedYAML, string(yaml))\n\t\t})\n\t}\n}\n\nfunc TestCELEvalFromYAML(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.DiskLocator()\n\n\ttype yamlRaw struct {\n\t\tExpr string `yaml:\"expr,omitempty\"`\n\t}\n\n\ttype yamlTest struct {\n\t\tExpr cel.Expression `yaml:\"expr,omitempty\"`\n\t}\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\texpression string\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tname: \"consts\",\n\n\t\t\texpression: \"1u * GiB < 2u * GiB\",\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname: \"vars\",\n\n\t\t\texpression: \"!system_disk\",\n\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tyamlRaw := yamlRaw{\n\t\t\t\tExpr: test.expression,\n\t\t\t}\n\n\t\t\tmarshaled, err := yaml.Marshal(yamlRaw)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar yamlTest yamlTest\n\n\t\t\terr = yaml.Unmarshal(marshaled, &yamlTest)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tval, err := yamlTest.Expr.EvalBool(env, map[string]any{\n\t\t\t\t\"system_disk\": true,\n\t\t\t\t\"disk\": block.DiskSpec{\n\t\t\t\t\tSize: 1024,\n\t\t\t\t},\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, val)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/cel/celenv/celenv.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package celenv provides standard CEL environments to evaluate CEL expressions.\npackage celenv\n\nimport (\n\t\"net\"\n\t\"slices\"\n\t\"sync\"\n\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/google/cel-go/common/types/ref\"\n\t\"github.com/google/cel-go/common/types/traits\"\n\t\"github.com/ryanuber/go-glob\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// Empty is an empty CEL environment.\nvar Empty = sync.OnceValue(func() *cel.Env {\n\tenv, err := cel.NewEnv()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\n// DiskLocator is a disk locator CEL environment.\nvar DiskLocator = sync.OnceValue(func() *cel.Env {\n\tvar diskSpec block.DiskSpec\n\n\tenv, err := cel.NewEnv(\n\t\tslices.Concat(\n\t\t\t[]cel.EnvOption{\n\t\t\t\tcel.Types(&diskSpec),\n\t\t\t\tcel.Variable(\"disk\", cel.ObjectType(string(diskSpec.ProtoReflect().Descriptor().FullName()))),\n\t\t\t\tcel.Variable(\"system_disk\", types.BoolType),\n\t\t\t\tcel.Function(\"glob\", // glob(pattern, string)\n\t\t\t\t\tcel.Overload(\"glob_string_string\", []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType,\n\t\t\t\t\t\tcel.BinaryBinding(func(arg1, arg2 ref.Val) ref.Val {\n\t\t\t\t\t\t\treturn types.Bool(glob.Glob(string(arg1.(types.String)), string(arg2.(types.String))))\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t\tcelUnitMultipliersConstants(),\n\t\t)...,\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\n// VolumeLocator is a volume locator CEL environment.\nvar VolumeLocator = sync.OnceValue(func() *cel.Env {\n\tvar (\n\t\tvolumeSpec block.DiscoveredVolumeSpec\n\t\tdiskSpec   block.DiskSpec\n\t)\n\n\tenv, err := cel.NewEnv(\n\t\tslices.Concat(\n\t\t\t[]cel.EnvOption{\n\t\t\t\tcel.Types(&volumeSpec),\n\t\t\t\tcel.Types(&diskSpec),\n\t\t\t\tcel.Variable(\"volume\", cel.ObjectType(string(volumeSpec.ProtoReflect().Descriptor().FullName()))),\n\t\t\t\tcel.Variable(\"disk\", cel.ObjectType(string(diskSpec.ProtoReflect().Descriptor().FullName()))),\n\t\t\t},\n\t\t\tcelUnitMultipliersConstants(),\n\t\t)...,\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\n// OOMTrigger is a OOM Trigger Condition CEL environment.\nvar OOMTrigger = sync.OnceValue(func() *cel.Env {\n\tenv, err := cel.NewEnv(\n\t\tslices.Concat(\n\t\t\t[]cel.EnvOption{\n\t\t\t\t// root cgroup PSI memory metrics\n\t\t\t\tcel.Variable(\"memory_some_avg10\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_some_avg60\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_some_avg300\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_some_total\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_full_avg10\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_full_avg60\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_full_avg300\", types.DoubleType),\n\t\t\t\tcel.Variable(\"memory_full_total\", types.DoubleType),\n\t\t\t\t// root cgroup delta with last observation\n\t\t\t\tcel.Variable(\"d_memory_some_avg10\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_some_avg60\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_some_avg300\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_some_total\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_full_avg10\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_full_avg60\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_full_avg300\", types.DoubleType),\n\t\t\t\tcel.Variable(\"d_memory_full_total\", types.DoubleType),\n\t\t\t\t// per QoS class PSI memory metrics\n\t\t\t\tcel.Variable(\"qos_memory_some_avg10\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_some_avg60\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_some_avg300\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_some_total\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_full_avg10\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_full_avg60\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_full_avg300\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_full_total\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\t// per QoS class delta with last observation\n\t\t\t\tcel.Variable(\"d_qos_memory_some_avg10\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_some_avg60\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_some_avg300\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_some_total\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_full_avg10\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_full_avg60\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_full_avg300\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_full_total\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\t// per QoS memory usage absolute values\n\t\t\t\tcel.Variable(\"qos_memory_current\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_peak\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"qos_memory_max\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_current\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_peak\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\tcel.Variable(\"d_qos_memory_max\", types.NewMapType(types.IntType, types.DoubleType)),\n\t\t\t\t// time since last OOM trigger\n\t\t\t\tcel.Variable(\"time_since_trigger\", types.DurationType),\n\t\t\t\tcel.OptionalTypes(),\n\t\t\t\t// multiply_qos_vectors(qos_memory_some_avg_10, {Besteffort: 1.0, Burstable: 0.0, Guaranteed: 0.0, Podruntime: 1.0, System: 1.0}) -> double\n\t\t\t\t//\n\t\t\t\t// Multiplies the values of two QoS class maps and returns the sum.\n\t\t\t\tcel.Function(\"multiply_qos_vectors\",\n\t\t\t\t\tcel.Overload(\"multiply_qos_vectors_ma_map_double\",\n\t\t\t\t\t\t[]*cel.Type{\n\t\t\t\t\t\t\tcel.MapType(cel.DynType, cel.DoubleType),\n\t\t\t\t\t\t\tcel.MapType(cel.DynType, cel.DoubleType),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcel.DoubleType,\n\t\t\t\t\t\tcel.BinaryBinding(func(lhs, rhs ref.Val) ref.Val {\n\t\t\t\t\t\t\tvar result float64\n\n\t\t\t\t\t\t\tlhsMap := lhs.(traits.Mapper)\n\t\t\t\t\t\t\tlhsIter := lhsMap.Iterator()\n\t\t\t\t\t\t\trhsIndexer := rhs.(traits.Indexer)\n\n\t\t\t\t\t\t\tfor lhsIter.HasNext() == types.True {\n\t\t\t\t\t\t\t\tkey := lhsIter.Next()\n\t\t\t\t\t\t\t\tlValue := lhsMap.Get(key)\n\n\t\t\t\t\t\t\t\trValue := rhsIndexer.Get(key)\n\t\t\t\t\t\t\t\tif types.IsError(rValue) {\n\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tresult += float64(lValue.(types.Double)) * float64(rValue.(types.Double))\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn types.Double(result)\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t\tcelUnitMultipliersConstants(),\n\t\t\tcelCgroupClassConstants(),\n\t\t)...,\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\n// OOMCgroupScoring is a OOM Cgroup Scoring CEL environment.\nvar OOMCgroupScoring = sync.OnceValue(func() *cel.Env {\n\tenv, err := cel.NewEnv(\n\t\tslices.Concat(\n\t\t\t[]cel.EnvOption{\n\t\t\t\tcel.Variable(\"memory_max\", types.NewOptionalType(types.UintType)),\n\t\t\t\tcel.Variable(\"memory_current\", types.NewOptionalType(types.UintType)),\n\t\t\t\tcel.Variable(\"memory_peak\", types.NewOptionalType(types.UintType)),\n\t\t\t\tcel.Variable(\"path\", types.StringType),\n\t\t\t\tcel.Variable(\"class\", types.IntType),\n\t\t\t\tcel.OptionalTypes(),\n\t\t\t},\n\t\t\tcelUnitMultipliersConstants(),\n\t\t\tcelCgroupClassConstants(),\n\t\t)...,\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\n// LinkLocator is a network link locator CEL environment.\nvar LinkLocator = sync.OnceValue(func() *cel.Env {\n\tvar linkSpec network.LinkStatusSpec\n\n\tenv, err := cel.NewEnv(\n\t\tslices.Concat(\n\t\t\t[]cel.EnvOption{\n\t\t\t\tcel.Types(&linkSpec),\n\t\t\t\tcel.Variable(\"link\", cel.ObjectType(string(linkSpec.ProtoReflect().Descriptor().FullName()))),\n\t\t\t\tcel.Function(\"glob\", // glob(pattern, string) -> bool\n\t\t\t\t\tcel.Overload(\"glob_string_string\", []*cel.Type{cel.StringType, cel.StringType}, cel.BoolType,\n\t\t\t\t\t\tcel.BinaryBinding(func(arg1, arg2 ref.Val) ref.Val {\n\t\t\t\t\t\t\treturn types.Bool(glob.Glob(string(arg1.(types.String)), string(arg2.(types.String))))\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tcel.Function(\"mac\", // mac(bytes) -> string\n\t\t\t\t\tcel.Overload(\"mac_bytes\", []*cel.Type{cel.BytesType}, cel.StringType,\n\t\t\t\t\t\tcel.UnaryBinding(func(arg ref.Val) ref.Val {\n\t\t\t\t\t\t\treturn types.String(net.HardwareAddr([]byte(arg.(types.Bytes))).String())\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t},\n\t\t)...,\n\t)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn env\n})\n\ntype unitMultiplier struct {\n\tunit       string\n\tmultiplier uint64\n}\n\nvar unitMultipliers = []unitMultiplier{\n\t// IEC.\n\t{\"KiB\", 1024},\n\t{\"MiB\", 1024 * 1024},\n\t{\"GiB\", 1024 * 1024 * 1024},\n\t{\"TiB\", 1024 * 1024 * 1024 * 1024},\n\t{\"PiB\", 1024 * 1024 * 1024 * 1024 * 1024},\n\t{\"EiB\", 1024 * 1024 * 1024 * 1024 * 1024 * 1024},\n\t// Metric (used for disk sizes).\n\t{\"kB\", 1000},\n\t{\"MB\", 1000 * 1000},\n\t{\"GB\", 1000 * 1000 * 1000},\n\t{\"TB\", 1000 * 1000 * 1000 * 1000},\n\t{\"PB\", 1000 * 1000 * 1000 * 1000 * 1000},\n\t{\"EB\", 1000 * 1000 * 1000 * 1000 * 1000 * 1000},\n}\n\nfunc celUnitMultipliersConstants() []cel.EnvOption {\n\treturn xslices.Map(unitMultipliers, func(um unitMultiplier) cel.EnvOption {\n\t\treturn cel.Constant(um.unit, types.UintType, types.Uint(um.multiplier))\n\t})\n}\n\nfunc celCgroupClassConstants() []cel.EnvOption {\n\treturn []cel.EnvOption{\n\t\tcel.Constant(\"Besteffort\", types.IntType, types.Int(runtime.QoSCgroupClassBesteffort)),\n\t\tcel.Constant(\"Burstable\", types.IntType, types.Int(runtime.QoSCgroupClassBurstable)),\n\t\tcel.Constant(\"Guaranteed\", types.IntType, types.Int(runtime.QoSCgroupClassGuaranteed)),\n\t\tcel.Constant(\"Podruntime\", types.IntType, types.Int(runtime.QoSCgroupClassPodruntime)),\n\t\tcel.Constant(\"System\", types.IntType, types.Int(runtime.QoSCgroupClassSystem)),\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/cel/celenv/celenv_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage celenv_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestDiskLocator(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.DiskLocator()\n\n\tfor _, test := range []struct {\n\t\tname       string\n\t\texpression string\n\t}{\n\t\t{\n\t\t\tname:       \"system disk\",\n\t\t\texpression: \"system_disk\",\n\t\t},\n\t\t{\n\t\t\tname:       \"disk size\",\n\t\t\texpression: \"disk.size > 1000u * GiB && !disk.rotational\",\n\t\t},\n\t\t{\n\t\t\tname:       \"glob\",\n\t\t\texpression: \"glob('sd[a-z]', disk.dev_path)\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := cel.ParseBooleanExpression(test.expression, env)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestVolumeLocator(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.VolumeLocator()\n\n\tfor _, test := range []struct {\n\t\tname       string\n\t\texpression string\n\t}{\n\t\t{\n\t\t\tname:       \"by label\",\n\t\t\texpression: \"volume.label == 'EPHEMERAL'\",\n\t\t},\n\t\t{\n\t\t\tname:       \"by filesystem and size\",\n\t\t\texpression: \"volume.name == 'ext4' && volume.size > 1000u * TB\",\n\t\t},\n\t\t{\n\t\t\tname:       \"by filesystem and disk transport\",\n\t\t\texpression: \"volume.name == 'ext4' && disk.transport == 'nvme'\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := cel.ParseBooleanExpression(test.expression, env)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestOOMCgroupScoring(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.OOMCgroupScoring()\n\n\tfor _, test := range []struct {\n\t\tname       string\n\t\texpression string\n\t}{\n\t\t{\n\t\t\tname:       \"example 1\",\n\t\t\texpression: constants.DefaultOOMCgroupRankingExpression,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := cel.ParseDoubleExpression(test.expression, env)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestOOMTrigger(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.OOMTrigger()\n\n\tfor _, test := range []struct {\n\t\tname       string\n\t\texpression string\n\t}{\n\t\t{\n\t\t\tname:       \"example 1\",\n\t\t\texpression: constants.DefaultOOMTriggerExpression,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := cel.ParseBooleanExpression(test.expression, env)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestLinkLocator(t *testing.T) {\n\tt.Parallel()\n\n\tenv := celenv.LinkLocator()\n\n\tfor _, test := range []struct {\n\t\tname       string\n\t\texpression string\n\t}{\n\t\t{\n\t\t\tname:       \"by driver\",\n\t\t\texpression: `link.driver == \"i1000e\"`,\n\t\t},\n\t\t{\n\t\t\tname:       \"by mac\",\n\t\t\texpression: `mac(link.hardware_addr) == \"00:1a:2b:3c:4d:5e\"`,\n\t\t},\n\t\t{\n\t\t\tname:       \"by mac partial\",\n\t\t\texpression: `glob(mac(link.hardware_addr), \"00:1a:2b:*\")`,\n\t\t},\n\t\t{\n\t\t\tname:       \"by altnames\",\n\t\t\texpression: `\"enx728c41bfd443\" in link.alt_names`,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := cel.ParseBooleanExpression(test.expression, env)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/basic_auth.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"google.golang.org/grpc\"\n)\n\n// BasicAuth implements the credentials.PerRPCCredentials interface and holds credentials for Basic Auth.\ntype BasicAuth struct {\n\tauth string\n}\n\n// GetRequestMetadata implements credentials.PerGRPCCredentials.\nfunc (c BasicAuth) GetRequestMetadata(ctx context.Context, url ...string) (map[string]string, error) {\n\tenc := base64.StdEncoding.EncodeToString([]byte(c.auth))\n\n\treturn map[string]string{\n\t\t\"Authorization\": \"Basic \" + enc,\n\t}, nil\n}\n\n// WithGRPCBasicAuth returns gRPC credentials for basic auth.\nfunc WithGRPCBasicAuth(username, password string) grpc.DialOption {\n\treturn grpc.WithPerRPCCredentials(BasicAuth{\n\t\tauth: username + \":\" + password,\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/client/client.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package client provides Talos API client.\npackage client\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\tcosiv1alpha1 \"github.com/cosi-project/runtime/api/v1alpha1\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/protobuf/client\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/types/known/durationpb\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\tclusterapi \"github.com/siderolabs/talos/pkg/machinery/api/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tinspectapi \"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\tstorageapi \"github.com/siderolabs/talos/pkg/machinery/api/storage\"\n\ttimeapi \"github.com/siderolabs/talos/pkg/machinery/api/time\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// Client implements the proto.MachineServiceClient interface. It serves as the\n// concrete type with the required methods.\ntype Client struct {\n\toptions *Options\n\tconn    *grpcConnectionWrapper\n\n\tMachineClient   machineapi.MachineServiceClient\n\tTimeClient      timeapi.TimeServiceClient\n\tClusterClient   clusterapi.ClusterServiceClient\n\tStorageClient   storageapi.StorageServiceClient\n\tInspectClient   inspectapi.InspectServiceClient\n\tImageClient     machineapi.ImageServiceClient\n\tDebugClient     machineapi.DebugServiceClient\n\tLifecycleClient machineapi.LifecycleServiceClient\n\n\tCOSI state.State\n\n\tInspect *InspectClient\n}\n\nfunc (c *Client) resolveConfigContext() error {\n\tvar ok bool\n\n\tif c.options.unixSocketPath != \"\" {\n\t\treturn nil\n\t}\n\n\tif c.options.configContext != nil {\n\t\treturn nil\n\t}\n\n\tif c.options.config == nil {\n\t\tif err := WithDefaultConfig()(c.options); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to load default config: %w\", err)\n\t\t}\n\t}\n\n\tif c.options.contextOverrideSet {\n\t\tc.options.configContext, ok = c.options.config.Contexts[c.options.contextOverride]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"context %q not found in config\", c.options.contextOverride)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tc.options.configContext, ok = c.options.config.Contexts[c.options.config.Context]\n\tif !ok {\n\t\tif c.options.config.Context == \"\" && len(c.options.config.Contexts) == 0 {\n\t\t\treturn errors.New(\"talos config file is empty\")\n\t\t}\n\n\t\treturn fmt.Errorf(\"default context %q not found in config\", c.options.config.Context)\n\t}\n\n\treturn nil\n}\n\n// GetConfigContext returns resolved config context.\nfunc (c *Client) GetConfigContext() *clientconfig.Context {\n\tif err := c.resolveConfigContext(); err != nil {\n\t\treturn nil\n\t}\n\n\treturn c.options.configContext\n}\n\n// GetEndpoints returns the client's endpoints from the override set with WithEndpoints\n// or from the configuration.\nfunc (c *Client) GetEndpoints() []string {\n\tif c.options.unixSocketPath != \"\" {\n\t\treturn []string{c.options.unixSocketPath}\n\t}\n\n\tif len(c.options.endpointsOverride) > 0 {\n\t\treturn c.options.endpointsOverride\n\t}\n\n\tif c.options.configContext != nil {\n\t\treturn c.options.configContext.Endpoints\n\t}\n\n\tif c.options.config != nil {\n\t\tif err := c.resolveConfigContext(); err != nil {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn c.options.configContext.Endpoints\n\t}\n\n\treturn nil\n}\n\n// GetClusterName returns the client's cluster name from the override set with WithClustername\n// or from the configuration.\nfunc (c *Client) GetClusterName() string {\n\tif c.options.clusterNameOverride != \"\" {\n\t\treturn c.options.clusterNameOverride\n\t}\n\n\tif c.options.config != nil {\n\t\tif err := c.resolveConfigContext(); err != nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\tif c.options.configContext != nil {\n\t\t\treturn c.options.configContext.Cluster\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\n// New returns a new Client.\nfunc New(_ context.Context, opts ...OptionFunc) (c *Client, err error) {\n\tc = new(Client)\n\n\tc.options = new(Options)\n\n\tfor _, opt := range opts {\n\t\tif err = opt(c.options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif len(c.GetEndpoints()) < 1 {\n\t\treturn nil, errors.New(\"failed to determine endpoints\")\n\t}\n\n\tc.conn, err = c.getConn()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create client connection: %w\", err)\n\t}\n\n\tc.MachineClient = machineapi.NewMachineServiceClient(c.conn)\n\tc.TimeClient = timeapi.NewTimeServiceClient(c.conn)\n\tc.ClusterClient = clusterapi.NewClusterServiceClient(c.conn)\n\tc.StorageClient = storageapi.NewStorageServiceClient(c.conn)\n\tc.InspectClient = inspectapi.NewInspectServiceClient(c.conn)\n\tc.ImageClient = machineapi.NewImageServiceClient(c.conn)\n\tc.DebugClient = machineapi.NewDebugServiceClient(c.conn)\n\tc.LifecycleClient = machineapi.NewLifecycleServiceClient(c.conn)\n\n\tc.Inspect = &InspectClient{c.InspectClient}\n\tc.COSI = state.WrapCore(client.NewAdapter(cosiv1alpha1.NewStateClient(c.conn)))\n\n\treturn c, nil\n}\n\n// Close shuts down client protocol.\nfunc (c *Client) Close() error {\n\treturn c.conn.Close()\n}\n\n// KubeconfigRaw returns K8s client config (kubeconfig).\n//\n// This method doesn't support multiplexing of the result:\n// * either client.WithNodes is not used, or it contains a single node in the list.\nfunc (c *Client) KubeconfigRaw(ctx context.Context) (io.ReadCloser, error) {\n\tstream, err := c.MachineClient.Kubeconfig(ctx, &emptypb.Empty{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ReadStream(stream)\n}\n\nfunc (c *Client) extractKubeconfig(r io.ReadCloser) ([]byte, error) {\n\tdefer r.Close() //nolint:errcheck\n\n\tgzR, err := gzip.NewReader(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// returned .tar.gz should contain only single file (kubeconfig)\n\tvar kubeconfigBuf bytes.Buffer\n\n\ttar := tar.NewReader(gzR)\n\n\tfor {\n\t\t_, err = tar.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t_, err = io.Copy(&kubeconfigBuf, tar)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err = gzR.Close(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kubeconfigBuf.Bytes(), nil\n}\n\n// Kubeconfig returns K8s client config (kubeconfig).\nfunc (c *Client) Kubeconfig(ctx context.Context) ([]byte, error) {\n\tr, err := c.KubeconfigRaw(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.extractKubeconfig(r)\n}\n\n// ApplyConfiguration implements proto.MachineServiceClient interface.\nfunc (c *Client) ApplyConfiguration(ctx context.Context, req *machineapi.ApplyConfigurationRequest, callOptions ...grpc.CallOption) (resp *machineapi.ApplyConfigurationResponse, err error) {\n\tresp, err = c.MachineClient.ApplyConfiguration(ctx, req, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Disks returns the list of block devices.\nfunc (c *Client) Disks(ctx context.Context, callOptions ...grpc.CallOption) (resp *storageapi.DisksResponse, err error) {\n\tresp, err = c.StorageClient.Disks(ctx, &emptypb.Empty{}, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Stats implements the proto.MachineServiceClient interface.\nfunc (c *Client) Stats(ctx context.Context, namespace string, driver common.ContainerDriver, callOptions ...grpc.CallOption) (resp *machineapi.StatsResponse, err error) {\n\tresp, err = c.MachineClient.Stats(\n\t\tctx, &machineapi.StatsRequest{\n\t\t\tNamespace: namespace,\n\t\t\tDriver:    driver,\n\t\t},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Containers implements the proto.MachineServiceClient interface.\nfunc (c *Client) Containers(ctx context.Context, namespace string, driver common.ContainerDriver, callOptions ...grpc.CallOption) (resp *machineapi.ContainersResponse, err error) {\n\tresp, err = c.MachineClient.Containers(\n\t\tctx,\n\t\t&machineapi.ContainersRequest{\n\t\t\tNamespace: namespace,\n\t\t\tDriver:    driver,\n\t\t},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Restart implements the proto.MachineServiceClient interface.\nfunc (c *Client) Restart(ctx context.Context, namespace string, driver common.ContainerDriver, id string, callOptions ...grpc.CallOption) (err error) {\n\tresp, err := c.MachineClient.Restart(ctx, &machineapi.RestartRequest{\n\t\tId:        id,\n\t\tNamespace: namespace,\n\t\tDriver:    driver,\n\t})\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// Reset implements the proto.MachineServiceClient interface.\nfunc (c *Client) Reset(ctx context.Context, graceful, reboot bool) (err error) {\n\tresp, err := c.MachineClient.Reset(ctx, &machineapi.ResetRequest{Graceful: graceful, Reboot: reboot})\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// ResetGeneric implements the proto.MachineServiceClient interface.\nfunc (c *Client) ResetGeneric(ctx context.Context, req *machineapi.ResetRequest) error {\n\t_, err := c.ResetGenericWithResponse(ctx, req)\n\n\treturn err\n}\n\n// ResetGenericWithResponse resets the machine and returns the response.\nfunc (c *Client) ResetGenericWithResponse(ctx context.Context, req *machineapi.ResetRequest) (*machineapi.ResetResponse, error) {\n\tresp, err := c.MachineClient.Reset(ctx, req)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn resp, err\n}\n\n// RebootMode provides various mode through which the reboot process can be done.\ntype RebootMode func(*machineapi.RebootRequest)\n\n// WithRebootMode sets the reboot mode for the Reboot API call.\nfunc WithRebootMode(mode machineapi.RebootRequest_Mode) func(req *machineapi.RebootRequest) {\n\treturn func(req *machineapi.RebootRequest) {\n\t\treq.Mode = mode\n\t}\n}\n\n// WithPowerCycle option runs the Reboot fun in powercycle mode.\nfunc WithPowerCycle(req *machineapi.RebootRequest) {\n\treq.Mode = machineapi.RebootRequest_POWERCYCLE\n}\n\n// WithForce option runs the Reboot fun in force mode.\nfunc WithForce(req *machineapi.RebootRequest) {\n\treq.Mode = machineapi.RebootRequest_FORCE\n}\n\n// Reboot implements the proto.MachineServiceClient interface.\nfunc (c *Client) Reboot(ctx context.Context, opts ...RebootMode) error {\n\t_, err := c.RebootWithResponse(ctx, opts...)\n\n\treturn err\n}\n\n// RebootWithResponse reboots the machine and returns the response.\nfunc (c *Client) RebootWithResponse(ctx context.Context, opts ...RebootMode) (*machineapi.RebootResponse, error) {\n\tvar req machineapi.RebootRequest\n\tfor _, opt := range opts {\n\t\topt(&req)\n\t}\n\n\tresp, err := c.MachineClient.Reboot(ctx, &req)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn resp, err\n}\n\n// Rollback implements the proto.MachineServiceClient interface.\nfunc (c *Client) Rollback(ctx context.Context) (err error) {\n\tresp, err := c.MachineClient.Rollback(ctx, &machineapi.RollbackRequest{})\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// Bootstrap implements the proto.MachineServiceClient interface.\nfunc (c *Client) Bootstrap(ctx context.Context, req *machineapi.BootstrapRequest) (err error) {\n\tresp, err := c.MachineClient.Bootstrap(ctx, req)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// ShutdownOption provides shutdown API options.\ntype ShutdownOption func(*machineapi.ShutdownRequest)\n\n// WithShutdownForce forces the shutdown even if the Kubernetes API is down.\nfunc WithShutdownForce(force bool) ShutdownOption {\n\treturn func(req *machineapi.ShutdownRequest) {\n\t\treq.Force = force\n\t}\n}\n\n// Shutdown implements the proto.MachineServiceClient interface.\nfunc (c *Client) Shutdown(ctx context.Context, opts ...ShutdownOption) error {\n\t_, err := c.ShutdownWithResponse(ctx, opts...)\n\n\treturn err\n}\n\n// ShutdownWithResponse shuts down the machine and returns the response.\nfunc (c *Client) ShutdownWithResponse(ctx context.Context, opts ...ShutdownOption) (*machineapi.ShutdownResponse, error) {\n\tvar req machineapi.ShutdownRequest\n\n\tfor _, opt := range opts {\n\t\topt(&req)\n\t}\n\n\tresp, err := c.MachineClient.Shutdown(ctx, &req)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn resp, err\n}\n\n// Dmesg implements the proto.MachineServiceClient interface.\nfunc (c *Client) Dmesg(ctx context.Context, follow, tail bool) (machineapi.MachineService_DmesgClient, error) {\n\treturn c.MachineClient.Dmesg(ctx, &machineapi.DmesgRequest{\n\t\tFollow: follow,\n\t\tTail:   tail,\n\t})\n}\n\n// Logs implements the proto.MachineServiceClient interface.\nfunc (c *Client) Logs(ctx context.Context, namespace string, driver common.ContainerDriver, id string, follow bool, tailLines int32) (stream machineapi.MachineService_LogsClient, err error) {\n\tstream, err = c.MachineClient.Logs(ctx, &machineapi.LogsRequest{\n\t\tNamespace: namespace,\n\t\tDriver:    driver,\n\t\tId:        id,\n\t\tFollow:    follow,\n\t\tTailLines: tailLines,\n\t})\n\n\treturn stream, err\n}\n\n// LogsContainers implements the proto.MachineServiceClient interface.\nfunc (c *Client) LogsContainers(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.LogsContainersResponse, err error) {\n\tresp, err = c.MachineClient.LogsContainers(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Version implements the proto.MachineServiceClient interface.\nfunc (c *Client) Version(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.VersionResponse, err error) {\n\tresp, err = c.MachineClient.Version(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Processes implements the proto.MachineServiceClient interface.\nfunc (c *Client) Processes(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.ProcessesResponse, err error) {\n\tresp, err = c.MachineClient.Processes(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Memory implements the proto.MachineServiceClient interface.\nfunc (c *Client) Memory(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.MemoryResponse, err error) {\n\tresp, err = c.MachineClient.Memory(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Mounts implements the proto.MachineServiceClient interface.\nfunc (c *Client) Mounts(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.MountsResponse, err error) {\n\tresp, err = c.MachineClient.Mounts(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// LS implements the proto.MachineServiceClient interface.\nfunc (c *Client) LS(ctx context.Context, req *machineapi.ListRequest) (stream machineapi.MachineService_ListClient, err error) {\n\treturn c.MachineClient.List(ctx, req)\n}\n\n// DiskUsage implements the proto.MachineServiceClient interface.\nfunc (c *Client) DiskUsage(ctx context.Context, req *machineapi.DiskUsageRequest) (stream machineapi.MachineService_DiskUsageClient, err error) {\n\treturn c.MachineClient.DiskUsage(ctx, req)\n}\n\n// Copy implements the proto.MachineServiceClient interface.\n//\n// This method doesn't support multiplexing of the result:\n// * either client.WithNodes is not used, or it contains a single node in the list.\nfunc (c *Client) Copy(ctx context.Context, rootPath string) (io.ReadCloser, error) {\n\tstream, err := c.MachineClient.Copy(ctx, &machineapi.CopyRequest{\n\t\tRootPath: rootPath,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ReadStream(stream)\n}\n\n// UpgradeOptions provides upgrade API options.\ntype UpgradeOptions struct {\n\tRequest         machineapi.UpgradeRequest\n\tGRPCCallOptions []grpc.CallOption\n}\n\n// UpgradeOption provides upgrade API options.\ntype UpgradeOption func(*UpgradeOptions)\n\n// WithUpgradeImage sets the image for the upgrade.\nfunc WithUpgradeImage(image string) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.Request.Image = image\n\t}\n}\n\n// WithUpgradeRebootMode sets the reboot mode for the upgrade.\nfunc WithUpgradeRebootMode(mode machineapi.UpgradeRequest_RebootMode) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.Request.RebootMode = mode\n\t}\n}\n\n// WithUpgradePreserve sets the preserve flag for the upgrade.\nfunc WithUpgradePreserve(preserve bool) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.Request.Preserve = preserve\n\t}\n}\n\n// WithUpgradeStage sets the stage flag for the upgrade.\nfunc WithUpgradeStage(stage bool) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.Request.Stage = stage\n\t}\n}\n\n// WithUpgradeForce sets the force flag for the upgrade.\nfunc WithUpgradeForce(force bool) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.Request.Force = force\n\t}\n}\n\n// WithUpgradeGRPCCallOptions sets the gRPC call options for the upgrade.\nfunc WithUpgradeGRPCCallOptions(opts ...grpc.CallOption) UpgradeOption {\n\treturn func(req *UpgradeOptions) {\n\t\treq.GRPCCallOptions = opts\n\t}\n}\n\n// Upgrade initiates a Talos upgrade and implements the proto.MachineServiceClient interface.\n//\n// Deprecated: use LifecycleClient instead.\nfunc (c *Client) Upgrade(ctx context.Context, image string, stage, force bool, callOptions ...grpc.CallOption) (*machineapi.UpgradeResponse, error) {\n\treturn c.UpgradeWithOptions(\n\t\tctx,\n\t\tWithUpgradeImage(image),\n\t\tWithUpgradeRebootMode(machineapi.UpgradeRequest_DEFAULT),\n\t\tWithUpgradeStage(stage),\n\t\tWithUpgradeForce(force),\n\t\tWithUpgradeGRPCCallOptions(callOptions...),\n\t)\n}\n\n// UpgradeWithOptions initiates a Talos upgrade with the given options.\n//\n// Deprecated: use LifecycleClient instead.\nfunc (c *Client) UpgradeWithOptions(ctx context.Context, opts ...UpgradeOption) (*machineapi.UpgradeResponse, error) {\n\tvar options UpgradeOptions\n\n\tfor _, opt := range opts {\n\t\topt(&options)\n\t}\n\n\tresp, err := c.MachineClient.Upgrade(ctx, &options.Request, options.GRPCCallOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// ServiceList returns list of services with their state.\nfunc (c *Client) ServiceList(ctx context.Context, callOptions ...grpc.CallOption) (resp *machineapi.ServiceListResponse, err error) {\n\tresp, err = c.MachineClient.ServiceList(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// ServiceInfo provides info about a service and node metadata.\ntype ServiceInfo struct {\n\tMetadata *common.Metadata\n\tService  *machineapi.ServiceInfo\n}\n\n// ServiceInfo returns info about a single service\n//\n// This is implemented via service list API, as we don't have many services\n// If service with given id is not registered, function returns nil.\nfunc (c *Client) ServiceInfo(ctx context.Context, id string, callOptions ...grpc.CallOption) (services []ServiceInfo, err error) {\n\tvar resp *machineapi.ServiceListResponse\n\n\tresp, err = c.MachineClient.ServiceList(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\tif err != nil {\n\t\treturn services, err\n\t}\n\n\tresp, err = FilterMessages(resp, err)\n\n\t// FilterMessages might remove responses if they actually contain errors,\n\t// errors will be merged into `resp`.\n\tif resp == nil {\n\t\treturn services, err\n\t}\n\n\tfor _, resp := range resp.Messages {\n\t\tfor _, svc := range resp.Services {\n\t\t\tif svc.Id == id {\n\t\t\t\tservices = append(services, ServiceInfo{\n\t\t\t\t\tMetadata: resp.Metadata,\n\t\t\t\t\tService:  svc,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn services, err\n}\n\n// ServiceStart starts a service.\nfunc (c *Client) ServiceStart(ctx context.Context, id string, callOptions ...grpc.CallOption) (resp *machineapi.ServiceStartResponse, err error) {\n\tresp, err = c.MachineClient.ServiceStart(\n\t\tctx,\n\t\t&machineapi.ServiceStartRequest{Id: id},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// ServiceStop stops a service.\nfunc (c *Client) ServiceStop(ctx context.Context, id string, callOptions ...grpc.CallOption) (resp *machineapi.ServiceStopResponse, err error) {\n\tresp, err = c.MachineClient.ServiceStop(\n\t\tctx,\n\t\t&machineapi.ServiceStopRequest{Id: id},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// ServiceRestart restarts a service.\nfunc (c *Client) ServiceRestart(ctx context.Context, id string, callOptions ...grpc.CallOption) (resp *machineapi.ServiceRestartResponse, err error) {\n\tresp, err = c.MachineClient.ServiceRestart(\n\t\tctx,\n\t\t&machineapi.ServiceRestartRequest{Id: id},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Time returns the time.\nfunc (c *Client) Time(ctx context.Context, callOptions ...grpc.CallOption) (resp *timeapi.TimeResponse, err error) {\n\tresp, err = c.TimeClient.Time(\n\t\tctx,\n\t\t&emptypb.Empty{},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// TimeCheck returns the time compared to the specified ntp server.\nfunc (c *Client) TimeCheck(ctx context.Context, server string, callOptions ...grpc.CallOption) (resp *timeapi.TimeResponse, err error) {\n\tresp, err = c.TimeClient.TimeCheck(\n\t\tctx,\n\t\t&timeapi.TimeRequest{Server: server},\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// Read reads a file.\n//\n// This method doesn't support multiplexing of the result:\n// * either client.WithNodes is not used, or it contains a single node in the list.\nfunc (c *Client) Read(ctx context.Context, path string) (io.ReadCloser, error) {\n\tstream, err := c.MachineClient.Read(ctx, &machineapi.ReadRequest{Path: path})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ReadStream(stream)\n}\n\n// ClusterHealthCheck runs a Talos cluster health check.\nfunc (c *Client) ClusterHealthCheck(ctx context.Context, waitTimeout time.Duration, clusterInfo *clusterapi.ClusterInfo) (clusterapi.ClusterService_HealthCheckClient, error) {\n\treturn c.ClusterClient.HealthCheck(ctx, &clusterapi.HealthCheckRequest{\n\t\tWaitTimeout: durationpb.New(waitTimeout),\n\t\tClusterInfo: clusterInfo,\n\t})\n}\n\n// EtcdRemoveMemberByID removes a node from etcd cluster by etcd member ID.\nfunc (c *Client) EtcdRemoveMemberByID(ctx context.Context, req *machineapi.EtcdRemoveMemberByIDRequest, callOptions ...grpc.CallOption) error {\n\tresp, err := c.MachineClient.EtcdRemoveMemberByID(ctx, req, callOptions...)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// EtcdLeaveCluster makes node leave etcd cluster.\nfunc (c *Client) EtcdLeaveCluster(ctx context.Context, req *machineapi.EtcdLeaveClusterRequest, callOptions ...grpc.CallOption) error {\n\tresp, err := c.MachineClient.EtcdLeaveCluster(ctx, req, callOptions...)\n\tif err == nil {\n\t\t_, err = FilterMessages(resp, err)\n\t}\n\n\treturn err\n}\n\n// EtcdForfeitLeadership makes node forfeit leadership in the etcd cluster.\nfunc (c *Client) EtcdForfeitLeadership(ctx context.Context, req *machineapi.EtcdForfeitLeadershipRequest, callOptions ...grpc.CallOption) (*machineapi.EtcdForfeitLeadershipResponse, error) {\n\tresp, err := c.MachineClient.EtcdForfeitLeadership(ctx, req, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdMemberList lists etcd members of the cluster.\nfunc (c *Client) EtcdMemberList(ctx context.Context, req *machineapi.EtcdMemberListRequest, callOptions ...grpc.CallOption) (*machineapi.EtcdMemberListResponse, error) {\n\tresp, err := c.MachineClient.EtcdMemberList(ctx, req, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdSnapshot receives a snapshot of the etcd from the node.\n//\n// This method doesn't support multiplexing of the result:\n// * either client.WithNodes is not used, or it contains a single node in the list.\nfunc (c *Client) EtcdSnapshot(ctx context.Context, req *machineapi.EtcdSnapshotRequest, callOptions ...grpc.CallOption) (io.ReadCloser, error) {\n\tstream, err := c.MachineClient.EtcdSnapshot(ctx, req, callOptions...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ReadStream(stream)\n}\n\n// EtcdRecover uploads etcd snapshot created with EtcdSnapshot to the node.\nfunc (c *Client) EtcdRecover(ctx context.Context, snapshot io.Reader, callOptions ...grpc.CallOption) (*machineapi.EtcdRecoverResponse, error) {\n\tcli, err := c.MachineClient.EtcdRecover(ctx, callOptions...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbuf := make([]byte, 4096)\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\tdefault:\n\t\t}\n\n\t\tvar n int\n\n\t\tn, err = snapshot.Read(buf)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"error reading snapshot: %w\", err)\n\t\t}\n\n\t\tif err = cli.Send(&common.Data{\n\t\t\tBytes: buf[:n],\n\t\t}); err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tresp, err := cli.CloseAndRecv()\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdAlarmList lists etcd alarms for the current node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdAlarmList(ctx context.Context, opts ...grpc.CallOption) (*machineapi.EtcdAlarmListResponse, error) {\n\tresp, err := c.MachineClient.EtcdAlarmList(ctx, &emptypb.Empty{}, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdAlarmDisarm disarms etcd alarms for the current node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdAlarmDisarm(ctx context.Context, opts ...grpc.CallOption) (*machineapi.EtcdAlarmDisarmResponse, error) {\n\tresp, err := c.MachineClient.EtcdAlarmDisarm(ctx, &emptypb.Empty{}, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdDefragment defragments etcd data directory for the current node.\n//\n// Defragmentation is a resource-heavy operation, so it should only run on a specific\n// node.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdDefragment(ctx context.Context, opts ...grpc.CallOption) (*machineapi.EtcdDefragmentResponse, error) {\n\tresp, err := c.MachineClient.EtcdDefragment(ctx, &emptypb.Empty{}, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdStatus returns etcd status for the current member.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdStatus(ctx context.Context, opts ...grpc.CallOption) (*machineapi.EtcdStatusResponse, error) {\n\tresp, err := c.MachineClient.EtcdStatus(ctx, &emptypb.Empty{}, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdDowngradeCancel(ctx context.Context, opts ...grpc.CallOption) (*machineapi.EtcdDowngradeCancelResponse, error) {\n\tresp, err := c.MachineClient.EtcdDowngradeCancel(ctx, &emptypb.Empty{}, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdDowngradeEnable enables etcd cluster downgrade to a specific version.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdDowngradeEnable(ctx context.Context, req *machineapi.EtcdDowngradeEnableRequest, opts ...grpc.CallOption) (*machineapi.EtcdDowngradeEnableResponse, error) {\n\tresp, err := c.MachineClient.EtcdDowngradeEnable(ctx, req, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version.\n//\n// This method is available only on control plane nodes (which run etcd).\nfunc (c *Client) EtcdDowngradeValidate(ctx context.Context, req *machineapi.EtcdDowngradeValidateRequest, opts ...grpc.CallOption) (*machineapi.EtcdDowngradeValidateResponse, error) {\n\tresp, err := c.MachineClient.EtcdDowngradeValidate(ctx, req, opts...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// GenerateClientConfiguration implements proto.MachineServiceClient interface.\nfunc (c *Client) GenerateClientConfiguration(ctx context.Context, req *machineapi.GenerateClientConfigurationRequest, callOptions ...grpc.CallOption) (resp *machineapi.GenerateClientConfigurationResponse, err error) { //nolint:lll\n\tresp, err = c.MachineClient.GenerateClientConfiguration(ctx, req, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n\n// PacketCapture implements the proto.MachineServiceClient interface.\n//\n// This method doesn't support multiplexing of the result:\n// * either client.WithNodes is not used, or it contains a single node in the list.\nfunc (c *Client) PacketCapture(ctx context.Context, req *machineapi.PacketCaptureRequest) (io.ReadCloser, error) {\n\tstream, err := c.MachineClient.PacketCapture(ctx, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ReadStream(stream)\n}\n\n// MachineStream is a common interface for streams returned by streaming APIs.\ntype MachineStream interface {\n\tRecv() (*common.Data, error)\n\tgrpc.ClientStream\n}\n\n// ReadStream converts grpc stream into io.Reader.\nfunc ReadStream(stream MachineStream) (io.ReadCloser, error) {\n\tpr, pw := io.Pipe()\n\n\tgo func() {\n\t\t//nolint:errcheck\n\t\tdefer pw.Close()\n\n\t\tfor {\n\t\t\tdata, err := stream.Recv()\n\t\t\tif err != nil {\n\t\t\t\tif errors.Is(err, io.EOF) || StatusCode(err) == codes.Canceled || StatusCode(err) == codes.DeadlineExceeded {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tpw.CloseWithError(err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif data.Bytes != nil {\n\t\t\t\t_, err = pw.Write(data.Bytes)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif data.Metadata != nil && data.Metadata.Error != \"\" {\n\t\t\t\tpw.CloseWithError(metaToErr(data.Metadata))\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn pr, stream.CloseSend()\n}\n\nfunc metaToErr(md *common.Metadata) error {\n\tif md.Status == nil {\n\t\treturn errors.New(md.Error)\n\t}\n\n\tcode := codes.Code(md.Status.Code)\n\tif code == codes.Canceled || code == codes.DeadlineExceeded {\n\t\treturn nil\n\t}\n\n\treturn status.FromProto(md.Status).Err()\n}\n\n// Netstat lists the network sockets on the current node.\nfunc (c *Client) Netstat(ctx context.Context, req *machineapi.NetstatRequest, callOptions ...grpc.CallOption) (*machineapi.NetstatResponse, error) {\n\tresp, err := c.MachineClient.Netstat(\n\t\tctx,\n\t\treq,\n\t\tcallOptions...,\n\t)\n\n\treturn FilterMessages(resp, err)\n}\n\n// MetaWrite writes a key to META storage.\nfunc (c *Client) MetaWrite(ctx context.Context, key uint8, value []byte, callOptions ...grpc.CallOption) error {\n\tresp, err := c.MachineClient.MetaWrite(\n\t\tctx,\n\t\t&machineapi.MetaWriteRequest{\n\t\t\tKey:   uint32(key),\n\t\t\tValue: value,\n\t\t},\n\t\tcallOptions...,\n\t)\n\n\t_, err = FilterMessages(resp, err)\n\n\treturn err\n}\n\n// MetaDelete deletes a key from META storage.\nfunc (c *Client) MetaDelete(ctx context.Context, key uint8, callOptions ...grpc.CallOption) error {\n\tresp, err := c.MachineClient.MetaDelete(\n\t\tctx,\n\t\t&machineapi.MetaDeleteRequest{\n\t\t\tKey: uint32(key),\n\t\t},\n\t\tcallOptions...,\n\t)\n\n\t_, err = FilterMessages(resp, err)\n\n\treturn err\n}\n\n// ImageList lists images in the CRI.\n//\n// Deprecated: use ImageServiceClient instead.\nfunc (c *Client) ImageList(ctx context.Context, namespace common.ContainerdNamespace, callOptions ...grpc.CallOption) (machineapi.MachineService_ImageListClient, error) {\n\treturn c.MachineClient.ImageList(ctx,\n\t\t&machineapi.ImageListRequest{\n\t\t\tNamespace: namespace,\n\t\t},\n\t\tcallOptions...,\n\t)\n}\n\n// ImagePull pre-pulls an image to the CRI.\n//\n// Deprecated: use ImageServiceClient instead.\nfunc (c *Client) ImagePull(ctx context.Context, namespace common.ContainerdNamespace, imageRef string, callOptions ...grpc.CallOption) error {\n\tresp, err := c.MachineClient.ImagePull(ctx,\n\t\t&machineapi.ImagePullRequest{\n\t\t\tNamespace: namespace,\n\t\t\tReference: imageRef,\n\t\t},\n\t\tcallOptions...,\n\t)\n\n\t_, err = FilterMessages(resp, err)\n\n\treturn err\n}\n\n// BlockDeviceWipe wipes a block device which is not used as a volume.\nfunc (c *Client) BlockDeviceWipe(ctx context.Context, req *storageapi.BlockDeviceWipeRequest, callOptions ...grpc.CallOption) error {\n\tresp, err := c.StorageClient.BlockDeviceWipe(ctx, req, callOptions...)\n\n\t_, err = FilterMessages(resp, err)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/client/client_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc ExampleNew() {\n\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\tdefer cancel()\n\n\tconnPprof := pprof.Lookup(\"machinery/client/grpc.grpcConn\")\n\tif connPprof == nil {\n\t\tpanic(errors.New(\"profile machinery/client/grpc.grpcConn not found\"))\n\t}\n\n\tfmt.Println(\"before:\", connPprof.Count())\n\n\tc := ensure.Value(\n\t\tclient.New(\n\t\t\tctx,\n\t\t\tclient.WithUnixSocket(\"/path/to/socket\"),\n\t\t\tclient.WithGRPCDialOptions(\n\t\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t\t),\n\t\t),\n\t)\n\n\tfmt.Println(\"after client.New:\", connPprof.Count())\n\n\tif err := c.Close(); err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(\"after client.Close:\", connPprof.Count())\n\n\tc2 := ensure.Value(\n\t\tclient.New(\n\t\t\tctx,\n\t\t\tclient.WithUnixSocket(\"/path/to/socket\"),\n\t\t\tclient.WithGRPCDialOptions(\n\t\t\t\tgrpc.WithTransportCredentials(insecure.NewCredentials()),\n\t\t\t),\n\t\t),\n\t)\n\n\tfmt.Println(\"after client.New 2:\", connPprof.Count())\n\n\t_ = c2\n\n\truntime.GC()\n\n\tfmt.Println(\"after gc:\", connPprof.Count())\n\n\t// Output:\n\t// before: 0\n\t// after client.New: 1\n\t// after client.Close: 0\n\t// after client.New 2: 1\n\t// after gc: 1\n}\n"
  },
  {
    "path": "pkg/machinery/client/config/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"go.yaml.in/yaml/v4\"\n)\n\n// Config represents the client configuration file (talosconfig).\ntype Config struct {\n\tContext  string              `yaml:\"context\"`\n\tContexts map[string]*Context `yaml:\"contexts\"`\n\n\t// path is the config Path config is read from.\n\tpath Path\n}\n\n// NewConfig returns the client configuration file with a single context.\nfunc NewConfig(contextName string, endpoints []string, caCrt []byte, client *x509.PEMEncodedCertificateAndKey) *Config {\n\treturn &Config{\n\t\tContext: contextName,\n\t\tContexts: map[string]*Context{\n\t\t\tcontextName: {\n\t\t\t\tEndpoints: endpoints,\n\t\t\t\tCA:        base64.StdEncoding.EncodeToString(caCrt),\n\t\t\t\tCrt:       base64.StdEncoding.EncodeToString(client.Crt),\n\t\t\t\tKey:       base64.StdEncoding.EncodeToString(client.Key),\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc (c *Config) upgrade() {\n\tfor _, ctx := range c.Contexts {\n\t\tctx.upgrade()\n\t}\n}\n\n// Context represents the set of credentials required to talk to a target.\ntype Context struct {\n\tDeprecatedTarget string   `yaml:\"target,omitempty\"` // Field deprecated in favor of Endpoints\n\tEndpoints        []string `yaml:\"endpoints\"`\n\tNodes            []string `yaml:\"nodes,omitempty\"`\n\tCA               string   `yaml:\"ca,omitempty\"`\n\tCrt              string   `yaml:\"crt,omitempty\"`\n\tKey              string   `yaml:\"key,omitempty\"`\n\tAuth             Auth     `yaml:\"auth,omitempty\"`\n\tCluster          string   `yaml:\"cluster,omitempty\"`\n}\n\n// Auth may hold credentials for an authentication method such as Basic Auth.\ntype Auth struct {\n\tBasic    *Basic    `yaml:\"basic,omitempty\"`\n\tSideroV1 *SideroV1 `yaml:\"siderov1,omitempty\"`\n}\n\n// Basic holds Basic Auth credentials.\ntype Basic struct {\n\tUsername string `yaml:\"username\"`\n\tPassword string `yaml:\"password\"`\n}\n\n// SideroV1 holds information for SideroV1 API signature auth.\ntype SideroV1 struct {\n\tIdentity string `yaml:\"identity\"`\n}\n\nfunc (c *Context) upgrade() {\n\tif c.DeprecatedTarget != \"\" {\n\t\tc.Endpoints = append(c.Endpoints, c.DeprecatedTarget)\n\t\tc.DeprecatedTarget = \"\"\n\t}\n}\n\n// Open reads the config and initializes a Config struct.\n// If path is explicitly set, it will be used.\n// If not, the default path rules will be used.\nfunc Open(path string) (*Config, error) {\n\tvar (\n\t\tconfPath Path\n\t\terr      error\n\t)\n\n\tif path != \"\" { // path is explicitly specified, ensure that is created and use it\n\t\tconfPath = Path{\n\t\t\tPath:         path,\n\t\t\tWriteAllowed: true,\n\t\t}\n\n\t\terr = ensure(confPath.Path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else { // path is implicit, get the first already existing & readable path or ensure that it is created\n\t\tconfPath, err = firstValidPath()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tconfig, err := fromFile(confPath.Path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tconfig.path = confPath\n\n\treturn config, nil\n}\n\nfunc fromFile(path string) (*Config, error) {\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer file.Close() //nolint:errcheck\n\n\treturn ReadFrom(file)\n}\n\n// FromString returns a config from a string.\nfunc FromString(p string) (c *Config, err error) {\n\treturn ReadFrom(bytes.NewReader([]byte(p)))\n}\n\n// FromBytes returns a config from []byte.\nfunc FromBytes(b []byte) (c *Config, err error) {\n\treturn ReadFrom(bytes.NewReader(b))\n}\n\n// ReadFrom reads a config from io.Reader.\nfunc ReadFrom(r io.Reader) (c *Config, err error) {\n\tc = &Config{}\n\n\tif err = yaml.NewDecoder(r).Decode(c); err != nil {\n\t\treturn c, err\n\t}\n\n\tc.upgrade()\n\n\treturn c, err\n}\n\n// Save writes the config to disk.\n// If the path is not explicitly set, the default path rules will be used.\nfunc (c *Config) Save(path string) error {\n\tvar err error\n\n\tif path != \"\" { // path is explicitly specified, use it\n\t\tc.path = Path{\n\t\t\tPath:         path,\n\t\t\tWriteAllowed: true,\n\t\t}\n\t} else if c.path.Path == \"\" { // path is implicit and is not set on config, get the first already existing & writable path or create it\n\t\tc.path, err = firstValidPath()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !c.path.WriteAllowed {\n\t\treturn fmt.Errorf(\"not allowed to write to config: %s\", c.path.Path)\n\t}\n\n\tconfigBytes, err := c.Bytes()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.MkdirAll(filepath.Dir(c.path.Path), 0o700); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(c.path.Path, configBytes, 0o600)\n}\n\n// Bytes gets yaml encoded config data.\nfunc (c *Config) Bytes() ([]byte, error) {\n\treturn yaml.Marshal(c)\n}\n\n// Path returns the filesystem path config was read from.\nfunc (c *Config) Path() Path {\n\treturn c.path\n}\n\n// Rename describes context rename during merge.\ntype Rename struct {\n\tFrom string\n\tTo   string\n}\n\n// String converts to \"from\" -> \"to\".\nfunc (r *Rename) String() string {\n\treturn fmt.Sprintf(\"%q -> %q\", r.From, r.To)\n}\n\n// Merge in additional contexts from another Config.\n//\n// Current context is overridden from passed in config.\nfunc (c *Config) Merge(cfg *Config) []Rename {\n\tif c.Contexts == nil {\n\t\tc.Contexts = map[string]*Context{}\n\t}\n\n\tmappedContexts := map[string]string{}\n\n\tvar renames []Rename\n\n\tfor name, ctx := range cfg.Contexts {\n\t\tmergedName := name\n\n\t\tif _, exists := c.Contexts[mergedName]; exists {\n\t\t\tfor i := 1; ; i++ {\n\t\t\t\tmergedName = fmt.Sprintf(\"%s-%d\", name, i)\n\n\t\t\t\tif _, exists := c.Contexts[mergedName]; !exists {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmappedContexts[name] = mergedName\n\n\t\tif name != mergedName {\n\t\t\trenames = append(renames, Rename{name, mergedName})\n\t\t}\n\n\t\tc.Contexts[mergedName] = ctx\n\t}\n\n\tif cfg.Context != \"\" {\n\t\tc.Context = mappedContexts[cfg.Context]\n\t}\n\n\treturn renames\n}\n\nfunc ensure(path string) error {\n\tif _, err := os.Stat(path); errors.Is(err, fs.ErrNotExist) {\n\t\tconfig := &Config{\n\t\t\tContext:  \"\",\n\t\t\tContexts: map[string]*Context{},\n\t\t}\n\n\t\treturn config.Save(path)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/client/config/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\nfunc TestConfigMerge(t *testing.T) {\n\tcontext1 := &clientconfig.Context{}\n\tcontext2 := &clientconfig.Context{}\n\n\tfor _, tt := range []struct {\n\t\tname          string\n\t\tconfig        *clientconfig.Config\n\t\tconfigToMerge *clientconfig.Config\n\n\t\texpectedContext  string\n\t\texpectedContexts map[string]*clientconfig.Context\n\t}{\n\t\t{\n\t\t\tname:   \"IntoEmpty\",\n\t\t\tconfig: &clientconfig.Config{},\n\t\t\tconfigToMerge: &clientconfig.Config{\n\t\t\t\tContext: \"foo\",\n\t\t\t\tContexts: map[string]*clientconfig.Context{\n\t\t\t\t\t\"foo\": context1,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedContext: \"foo\",\n\t\t\texpectedContexts: map[string]*clientconfig.Context{\n\t\t\t\t\"foo\": context1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoConflict\",\n\t\t\tconfig: &clientconfig.Config{\n\t\t\t\tContext: \"bar\",\n\t\t\t\tContexts: map[string]*clientconfig.Context{\n\t\t\t\t\t\"bar\": context2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tconfigToMerge: &clientconfig.Config{\n\t\t\t\tContext: \"\",\n\t\t\t\tContexts: map[string]*clientconfig.Context{\n\t\t\t\t\t\"foo\": context1,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedContext: \"bar\",\n\t\t\texpectedContexts: map[string]*clientconfig.Context{\n\t\t\t\t\"foo\": context1,\n\t\t\t\t\"bar\": context2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"WithRename\",\n\t\t\tconfig: &clientconfig.Config{\n\t\t\t\tContext: \"bar\",\n\t\t\t\tContexts: map[string]*clientconfig.Context{\n\t\t\t\t\t\"bar\": context2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tconfigToMerge: &clientconfig.Config{\n\t\t\t\tContext: \"bar\",\n\t\t\t\tContexts: map[string]*clientconfig.Context{\n\t\t\t\t\t\"bar\": context1,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpectedContext: \"bar-1\",\n\t\t\texpectedContexts: map[string]*clientconfig.Context{\n\t\t\t\t\"bar-1\": context1,\n\t\t\t\t\"bar\":   context2,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tc := tt.config\n\t\t\tc.Merge(tt.configToMerge)\n\n\t\t\tassert.Equal(t, tt.expectedContext, c.Context)\n\t\t\tassert.Equal(t, tt.expectedContexts, c.Contexts)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/config/path.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Path represents a path to a configuration file.\ntype Path struct {\n\t// Path is the filesystem path of the config.\n\tPath string\n\t// WriteAllowed is true if the path is allowed to be written.\n\tWriteAllowed bool\n}\n\n// GetTalosDirectory returns path to Talos directory ($TALOS_HOME or ~/.talos).\nfunc GetTalosDirectory() (string, error) {\n\tif path, ok := os.LookupEnv(constants.TalosHomeEnvVar); ok && filepath.IsAbs(path) {\n\t\treturn path, nil\n\t}\n\n\thome, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn filepath.Join(home, constants.TalosDir), nil\n}\n\n// GetDefaultPaths returns the list of config file paths in order of priority.\nfunc GetDefaultPaths() ([]Path, error) {\n\ttalosDir, err := GetTalosDirectory()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := make([]Path, 0, 3)\n\n\tif path, ok := os.LookupEnv(constants.TalosConfigEnvVar); ok {\n\t\tresult = append(result, Path{\n\t\t\tPath:         path,\n\t\t\tWriteAllowed: true,\n\t\t})\n\t}\n\n\tresult = append(\n\t\tresult,\n\t\tPath{\n\t\t\tPath:         filepath.Join(talosDir, constants.TalosconfigFilename),\n\t\t\tWriteAllowed: true,\n\t\t},\n\t\tPath{\n\t\t\tPath:         filepath.Join(constants.ServiceAccountMountPath, constants.TalosconfigFilename),\n\t\t\tWriteAllowed: false,\n\t\t},\n\t)\n\n\treturn result, nil\n}\n\n// CustomSideroV1KeysDirPath returns the custom SideroV1 auth keys directory path if it's provided as command line flag or with environment variable.\nfunc CustomSideroV1KeysDirPath(customPath string) string {\n\tif path, ok := os.LookupEnv(constants.SideroV1KeysDirEnvVar); ok {\n\t\treturn path\n\t}\n\n\tif customPath != \"\" {\n\t\treturn customPath\n\t}\n\n\thome, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn filepath.Join(home, constants.TalosDir, constants.SideroV1KeysDir)\n}\n\n// firstValidPath iterates over the default paths and returns the first one that exists and readable.\n// If no path is found, it will ensure that the first path that allows writes is created and returned.\n// If no path is found that is writable, an error is returned.\nfunc firstValidPath() (Path, error) {\n\tpaths, err := GetDefaultPaths()\n\tif err != nil {\n\t\treturn Path{}, err\n\t}\n\n\tvar firstWriteAllowed Path\n\n\tfor _, path := range paths {\n\t\t_, err = os.Stat(path.Path)\n\t\tif err == nil {\n\t\t\treturn path, nil\n\t\t}\n\n\t\tif firstWriteAllowed.Path == \"\" && path.WriteAllowed {\n\t\t\tfirstWriteAllowed = path\n\t\t}\n\t}\n\n\tif firstWriteAllowed.Path == \"\" {\n\t\treturn Path{}, errors.New(\"no valid config paths found\")\n\t}\n\n\terr = ensure(firstWriteAllowed.Path)\n\tif err != nil {\n\t\treturn Path{}, err\n\t}\n\n\treturn firstWriteAllowed, nil\n}\n"
  },
  {
    "path": "pkg/machinery/client/connection.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-api-signature/pkg/client/interceptor\"\n\t\"github.com/siderolabs/go-api-signature/pkg/pgp/client\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/resolver\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Conn returns underlying client connection.\nfunc (c *Client) Conn() *grpc.ClientConn {\n\treturn c.conn.ClientConn\n}\n\n// getConn creates new gRPC connection.\nfunc (c *Client) getConn(opts ...grpc.DialOption) (*grpcConnectionWrapper, error) {\n\tendpoints := c.GetEndpoints()\n\n\ttarget := c.getTarget(\n\t\tresolver.EnsureEndpointsHavePorts(\n\t\t\treduceURLsToAddresses(endpoints),\n\t\t\tconstants.ApidPort),\n\t)\n\n\tdialOpts := slices.Concat(\n\t\t[]grpc.DialOption{\n\t\t\tgrpc.WithDefaultCallOptions( // enable compression by default\n\t\t\t\t// TODO: enable compression for Talos 1.7+\n\t\t\t\t// grpc.UseCompressor(gzip.Name),\n\t\t\t\tgrpc.MaxCallRecvMsgSize(constants.GRPCMaxMessageSize),\n\t\t\t),\n\t\t\tgrpc.WithSharedWriteBuffer(true),\n\t\t},\n\t\tc.options.grpcDialOptions,\n\t\topts,\n\t)\n\n\tif c.options.unixSocketPath != \"\" {\n\t\tdialOpts = append(dialOpts,\n\t\t\tgrpc.WithNoProxy(),\n\t\t)\n\n\t\tconn, err := grpc.NewClient(target, dialOpts...)\n\n\t\treturn newGRPCConnectionWrapper(c.GetClusterName(), conn), err\n\t}\n\n\ttlsConfig := c.options.tlsConfig\n\n\tif tlsConfig != nil {\n\t\treturn c.makeConnection(target, credentials.NewTLS(tlsConfig), dialOpts)\n\t}\n\n\tif err := c.resolveConfigContext(); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to resolve configuration context: %w\", err)\n\t}\n\n\tbasicAuth := c.options.configContext.Auth.Basic\n\tif basicAuth != nil {\n\t\tdialOpts = append(dialOpts, WithGRPCBasicAuth(basicAuth.Username, basicAuth.Password))\n\t}\n\n\tsideroV1 := c.options.configContext.Auth.SideroV1\n\tif sideroV1 != nil {\n\t\tvar contextName string\n\n\t\tif c.options.config != nil {\n\t\t\tcontextName = c.options.config.Context\n\t\t}\n\n\t\tif c.options.contextOverrideSet {\n\t\t\tcontextName = c.options.contextOverride\n\t\t}\n\n\t\tauthInterceptor := interceptor.New(interceptor.Options{\n\t\t\tUserKeyProvider:      getKeyProvider(c.options.sideroV1KeysDir),\n\t\t\tContextName:          contextName,\n\t\t\tIdentity:             sideroV1.Identity,\n\t\t\tClientName:           \"Talos\",\n\t\t\tServiceAccountBase64: c.options.serviceAccountBase64,\n\t\t})\n\n\t\tdialOpts = append(dialOpts,\n\t\t\tgrpc.WithUnaryInterceptor(authInterceptor.Unary()),\n\t\t\tgrpc.WithStreamInterceptor(authInterceptor.Stream()),\n\t\t)\n\t}\n\n\tcreds, err := buildCredentials(c.options.configContext, endpoints)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.makeConnection(target, creds, dialOpts)\n}\n\nfunc getKeyProvider(customKeysDir string) *client.KeyProvider {\n\tif customKeysDir != \"\" {\n\t\treturn client.NewKeyProviderWithFallback(\"talos/keys\", customKeysDir, \"\", true)\n\t}\n\n\ttalosDir, err := clientconfig.GetTalosDirectory()\n\tif err != nil {\n\t\t// TODO: start failing instead of falling back to XDG data directory if we can't resolve Talos directory\n\t\treturn client.NewKeyProvider(\"talos/keys\")\n\t}\n\n\treturn client.NewKeyProviderWithFallback(\"talos/keys\", talosDir, \"keys\", true)\n}\n\nfunc buildTLSConfig(configContext *clientconfig.Context) (*tls.Config, error) {\n\ttlsConfig := &tls.Config{}\n\n\tcaBytes, err := getCA(configContext)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get CA: %w\", err)\n\t}\n\n\tif len(caBytes) > 0 {\n\t\ttlsConfig.RootCAs = x509.NewCertPool()\n\n\t\tif ok := tlsConfig.RootCAs.AppendCertsFromPEM(caBytes); !ok {\n\t\t\treturn nil, errors.New(\"failed to append CA certificate to RootCAs pool\")\n\t\t}\n\t}\n\n\tcrt, err := CertificateFromConfigContext(configContext)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to acquire credentials: %w\", err)\n\t}\n\n\tif crt != nil {\n\t\ttlsConfig.ClientAuth = tls.RequireAndVerifyClientCert\n\t\ttlsConfig.Certificates = append(tlsConfig.Certificates, *crt)\n\t}\n\n\treturn tlsConfig, nil\n}\n\nfunc (c *Client) makeConnection(target string, creds credentials.TransportCredentials, dialOpts []grpc.DialOption) (*grpcConnectionWrapper, error) {\n\tdialOpts = append(dialOpts,\n\t\tgrpc.WithTransportCredentials(creds),\n\t\tgrpc.WithInitialWindowSize(65535*32),\n\t\tgrpc.WithInitialConnWindowSize(65535*16))\n\n\tconn, err := grpc.NewClient(target, dialOpts...)\n\n\treturn newGRPCConnectionWrapper(c.GetClusterName(), conn), err\n}\n\nfunc (c *Client) getTarget(endpoints []string) string {\n\tswitch {\n\tcase c.options.unixSocketPath != \"\":\n\t\treturn fmt.Sprintf(\"unix:///%s\", c.options.unixSocketPath)\n\tcase len(endpoints) > 1:\n\t\treturn fmt.Sprintf(\"%s:///%s\", resolver.RoundRobinResolverScheme, strings.Join(endpoints, \",\"))\n\tdefault:\n\t\t// NB: we use the `dns` scheme here in order to handle fancier situations\n\t\t// when there is a single endpoint.\n\t\t// Such possibilities include SRV records, multiple IPs from A and/or AAAA\n\t\t// records, and descriptive TXT records which include things like load\n\t\t// balancer specs.\n\t\treturn fmt.Sprintf(\"dns:///%s\", endpoints[0])\n\t}\n}\n\nfunc getCA(context *clientconfig.Context) ([]byte, error) {\n\tif context.CA == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tcaBytes, err := base64.StdEncoding.DecodeString(context.CA)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding CA: %w\", err)\n\t}\n\n\treturn caBytes, err\n}\n\n// CertificateFromConfigContext constructs the client Credentials from the given configuration Context.\nfunc CertificateFromConfigContext(context *clientconfig.Context) (*tls.Certificate, error) {\n\tif context.Crt == \"\" && context.Key == \"\" {\n\t\treturn nil, nil\n\t}\n\n\tcrtBytes, err := base64.StdEncoding.DecodeString(context.Crt)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding certificate: %w\", err)\n\t}\n\n\tkeyBytes, err := base64.StdEncoding.DecodeString(context.Key)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding key: %w\", err)\n\t}\n\n\tcrt, err := tls.X509KeyPair(crtBytes, keyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not load client key pair: %s\", err)\n\t}\n\n\treturn &crt, nil\n}\n\nfunc reduceURLsToAddresses(endpoints []string) []string {\n\treturn xslices.Map(endpoints, func(endpoint string) string {\n\t\tu, err := url.Parse(endpoint)\n\t\tif err != nil {\n\t\t\treturn endpoint\n\t\t}\n\n\t\tif u.Scheme == \"https\" && u.Port() == \"\" {\n\t\t\treturn net.JoinHostPort(u.Hostname(), \"443\")\n\t\t}\n\n\t\tif u.Scheme != \"\" {\n\t\t\tif u.Port() != \"\" {\n\t\t\t\treturn net.JoinHostPort(u.Hostname(), u.Port())\n\t\t\t}\n\n\t\t\tif u.Opaque == \"\" {\n\t\t\t\treturn u.Host\n\t\t\t}\n\t\t}\n\n\t\treturn endpoint\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/client/connection_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client_test\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\nfunc TestReduceURLsToAddresses(t *testing.T) {\n\tendpoints := []string{\n\t\t\"123.123.123.123\",\n\t\t\"exammple.com:111\",\n\t\t\"234.234.234.234:4000\",\n\t\t\"https://111.111.222.222:444\",\n\t\t\"localhost\",\n\t\t\"localhost:890\",\n\t\t\"https://[42a1:cfa:5458:3967:e2ce:afaa:6194:12f]:40000\",\n\t\t\"https://localhost:890\",\n\t\t\"2001:db8:0:0:0:ff00:42:8329\",\n\t\t\"https://[be4d:c25e:aca0:9366:68b7:c84:a23b:f7be]\",\n\t\t\"https://www.somecompany.com\",\n\t\t\"www.company.com\",\n\t\t\"[2001:db8:4006:812::200e]:8080\",\n\t\t\"grpc://222.22.2.1\",\n\t\t\"grpc://[794b:389:73cb:76a2:59de:62fd:ee38:7c]:111\",\n\t}\n\texpected := []string{\n\t\t\"123.123.123.123\",\n\t\t\"exammple.com:111\",\n\t\t\"234.234.234.234:4000\",\n\t\t\"111.111.222.222:444\",\n\t\t\"localhost\",\n\t\t\"localhost:890\",\n\t\t\"[42a1:cfa:5458:3967:e2ce:afaa:6194:12f]:40000\",\n\t\t\"localhost:890\",\n\t\t\"2001:db8:0:0:0:ff00:42:8329\",\n\t\t\"[be4d:c25e:aca0:9366:68b7:c84:a23b:f7be]:443\",\n\t\t\"www.somecompany.com:443\",\n\t\t\"www.company.com\",\n\t\t\"[2001:db8:4006:812::200e]:8080\",\n\t\t\"222.22.2.1\",\n\t\t\"[794b:389:73cb:76a2:59de:62fd:ee38:7c]:111\",\n\t}\n\n\tactual := client.ReduceURLsToAddresses(endpoints)\n\n\tassert.Equal(t, expected, actual)\n}\n\nfunc TestBuildTLSConfig(t *testing.T) {\n\t//nolint:lll\n\tca := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEFtbGVURnRuRVY3b3NHYTJFSU9RVUJNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1qQTRNVEl4T0RNeE1EZGFGdzB6TWpBNE1Ea3hPRE14TURkYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBVGZ3RjFMQjVwVjg2cGw4cHN2aS93R2dWWmkvTm5NME8wYUZNCjBoenZZdzZqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVWTRhSGg3UnJxRnVObFNydAo4bXY4ZHduUjRKQXdCUVlESzJWd0EwRUFTaE5jYURXMGwrU24xYSt5c21Sd2M2NGlBa3Y5dUlZNGdXU0t3RWJ4CnpYQlR3SkZWcmNPWlZNNS9pM0Y0UjFWZVkzM3QwdFBQMFBGZVF5MVRWTDlVQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==`\n\n\tcaBytes, err := base64.StdEncoding.DecodeString(ca)\n\tassert.Nil(t, err)\n\n\texpectedRootCAs := x509.NewCertPool()\n\texpectedRootCAs.AppendCertsFromPEM(caBytes)\n\n\t//nolint:lll\n\tcrt := `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJNekNCNXFBREFnRUNBaEVBZ1BscnFYWUtDeVNHRkxmazVVK2JQekFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdPREV5TVRnek1UQTNXaGNOTXpJd09EQTVNVGd6TVRBM1dqQVRNUkV3RHdZRApWUVFLRXdodmN6cGhaRzFwYmpBcU1BVUdBeXRsY0FNaEFKblVxM1V1TzNTaGg4YW50eEZzNGJnZDlXeGRtcit6CmZURkxIcGpQVWlUaG8xSXdVREFPQmdOVkhROEJBZjhFQkFNQ0I0QXdIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUgKQXdFR0NDc0dBUVVGQndNQ01COEdBMVVkSXdRWU1CYUFGR09HaDRlMGE2aGJqWlVxN2ZKci9IY0owZUNRTUFVRwpBeXRsY0FOQkFNaW1wdnlxa0RHWDhROFErMTBtVWowYXJoQUpqdHl4OHErQll2QnlWOThxYyt3VldnYlFBc3FmClV3Sy9lN2ZLak1qMi9kRUZqOCs2SGZpOVJMTE5udzQ9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K`\n\n\tkey := `LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJQ3FTdHpMTTNzaHNqMlZld2dXaVBPaDJUT01uUmM3cmNyRkczTGhNaFdkQQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K`\n\n\tkeyBytes, err := base64.StdEncoding.DecodeString(key)\n\tassert.Nil(t, err)\n\n\tcrtBytes, err := base64.StdEncoding.DecodeString(crt)\n\tassert.Nil(t, err)\n\n\texpectedCert, err := tls.X509KeyPair(crtBytes, keyBytes)\n\tassert.Nil(t, err)\n\n\texpectedCerts := []tls.Certificate{expectedCert}\n\n\tt.Run(\"Returns default tls config for empty config context.\", func(t *testing.T) {\n\t\t// given\n\t\tconfigContext := clientconfig.Context{}\n\n\t\t// when\n\t\ttlsConfig, err := client.BuildTLSConfig(&configContext)\n\t\tassert.Nil(t, err)\n\n\t\t// then\n\t\texpected := &tls.Config{}\n\t\tassert.Equal(t, expected, tlsConfig)\n\t})\n\n\tt.Run(\"Returns tls config with CA for config context with CA.\", func(t *testing.T) {\n\t\t// given\n\t\tconfigContext := clientconfig.Context{\n\t\t\tCA: ca,\n\t\t}\n\n\t\t// when\n\t\ttlsConfig, err := client.BuildTLSConfig(&configContext)\n\t\tassert.Nil(t, err)\n\n\t\t// then\n\t\tassert.True(t, expectedRootCAs.Equal(tlsConfig.RootCAs))\n\n\t\tassert.Len(t, tlsConfig.Certificates, 0)\n\t})\n\n\tt.Run(\"Returns tls config with Certificate for config context with Crt and Key.\", func(t *testing.T) {\n\t\t// given\n\t\tconfigContext := clientconfig.Context{\n\t\t\tCrt: crt,\n\t\t\tKey: key,\n\t\t}\n\n\t\t// when\n\t\ttlsConfig, err := client.BuildTLSConfig(&configContext)\n\t\tassert.Nil(t, err)\n\n\t\t// then\n\t\tassert.Equal(t, expectedCerts, tlsConfig.Certificates)\n\t\tassert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth)\n\n\t\tassert.Nil(t, tlsConfig.RootCAs)\n\t})\n\n\tt.Run(\"Returns tls config with CA and Certificate for config context with CA, Crt and Key.\", func(t *testing.T) {\n\t\t// given\n\t\tconfigContext := clientconfig.Context{\n\t\t\tCA:  ca,\n\t\t\tCrt: crt,\n\t\t\tKey: key,\n\t\t}\n\n\t\t// when\n\t\ttlsConfig, err := client.BuildTLSConfig(&configContext)\n\t\tassert.Nil(t, err)\n\n\t\t// then\n\t\tassert.True(t, expectedRootCAs.Equal(tlsConfig.RootCAs))\n\n\t\tassert.Equal(t, expectedCerts, tlsConfig.Certificates)\n\t\tassert.Equal(t, tls.RequireAndVerifyClientCert, tlsConfig.ClientAuth)\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/client/context.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc/metadata\"\n)\n\n// WithNodes wraps the context with metadata to send request to a set of nodes.\n//\n// Responses from all nodes are aggregated by the `apid` service and sent back as a single response.\nfunc WithNodes(ctx context.Context, nodes ...string) context.Context {\n\tmd, _ := metadata.FromOutgoingContext(ctx)\n\n\t// overwrite any previous nodes in the context metadata with new value\n\tmd = md.Copy()\n\tmd.Delete(\"node\")\n\tmd.Set(\"nodes\", nodes...)\n\n\treturn metadata.NewOutgoingContext(ctx, md)\n}\n\n// WithNode wraps the context with metadata to send request to a single node.\n//\n// Request will be proxied by the endpoint to the specified node without any further processing.\nfunc WithNode(ctx context.Context, node string) context.Context {\n\tmd, _ := metadata.FromOutgoingContext(ctx)\n\n\t// overwrite any previous nodes in the context metadata with new value\n\tmd = md.Copy()\n\tmd.Delete(\"nodes\")\n\tmd.Set(\"node\", node)\n\n\treturn metadata.NewOutgoingContext(ctx, md)\n}\n"
  },
  {
    "path": "pkg/machinery/client/dialer/dialer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package dialer ...\npackage dialer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n)\n\n// DialUnix is used as a parameter for 'grpc.WithContextDialer' to bypass the\n// default dialer of gRPC to ensure that proxy vars are not used.\nfunc DialUnix() func(context.Context, string) (net.Conn, error) {\n\treturn func(ctx context.Context, addr string) (net.Conn, error) {\n\t\tu, err := url.Parse(addr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif u.Scheme != \"unix\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid scheme: %q\", u.Scheme)\n\t\t}\n\n\t\treturn (&net.Dialer{}).DialContext(ctx, u.Scheme, u.Path)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/dialer/dialer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dialer_test\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n)\n\nfunc TestDynamicProxyDialer_SOCKS5(t *testing.T) {\n\tt.Setenv(\"HTTPS_PROXY\", \"socks5://localhost:12345\")\n\n\tctx, cancel := context.WithTimeout(context.Background(), time.Second)\n\tdefer cancel()\n\n\t// Expect a connection error because the port is not open\n\t_, err := dialer.DynamicProxyDialer(ctx, \"example.com:443\")\n\tif err == nil {\n\t\tt.Fatal(\"expected a SOCKS5 connection error, but no error received\")\n\t}\n\n\tif _, ok := err.(net.Error); !ok {\n\t\tt.Fatalf(\"unexpected error: %v\", err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/dialer/proxy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage dialer\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/url\"\n\n\t\"golang.org/x/net/http/httpproxy\"\n\t\"golang.org/x/net/proxy\"\n\t\"google.golang.org/grpc\"\n)\n\n/*\n * Copyright 2023 gRPC authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\nconst grpcUA = \"grpc-go/\" + grpc.Version\n\n// DynamicProxyDialer is a fork of grpc standard dialer which supports dynamic resolving of proxy settings\n// on each request (vs. caching it once per process).\n//\n// DynamicProxyDialer assumes that the address is using 'tcp' network.\nfunc DynamicProxyDialer(ctx context.Context, addr string) (net.Conn, error) {\n\treturn DynamicProxyDialerWithTLSConfig(func() *tls.Config { return &tls.Config{} })(ctx, addr)\n}\n\n// DynamicProxyDialerWithTLSConfig is like DynamicProxyDialer but allows\n// specifying custom TLS config to be used when connecting to HTTPS proxy.\nfunc DynamicProxyDialerWithTLSConfig(tlsConfigFunc func() *tls.Config) func(ctx context.Context, addr string) (net.Conn, error) {\n\treturn func(ctx context.Context, addr string) (net.Conn, error) {\n\t\tnewAddr := addr\n\n\t\tproxyURL, err := mapAddress(addr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif proxyURL != nil {\n\t\t\tnewAddr = proxyURL.Host\n\t\t}\n\n\t\tvar conn net.Conn\n\n\t\tif proxyURL != nil && proxyURL.Scheme == \"https\" {\n\t\t\tconn, err = (&tls.Dialer{\n\t\t\t\tNetDialer: NetDialerWithTCPKeepalive(),\n\t\t\t\tConfig:    tlsConfigFunc(),\n\t\t\t}).DialContext(ctx, \"tcp\", proxyURL.Host)\n\t\t} else {\n\t\t\tconn, err = NetDialerWithTCPKeepalive().DialContext(ctx, \"tcp\", newAddr)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif proxyURL == nil {\n\t\t\t// proxy is disabled if proxyURL is nil.\n\t\t\treturn conn, err\n\t\t}\n\n\t\t// Support SOCKS5\n\t\tif proxyURL.Scheme == \"socks5\" {\n\t\t\tsocks5Dialer, err := proxySocksFromURL(proxyURL)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn socks5Dialer.Dial(\"tcp\", addr)\n\t\t}\n\n\t\t// Standard HTTP/HTTPS proxy\n\t\treturn doHTTPConnectHandshake(ctx, conn, addr, proxyURL, grpcUA)\n\t}\n}\n\nfunc proxySocksFromURL(u *url.URL) (proxy.Dialer, error) {\n\tvar auth *proxy.Auth\n\n\tif u.User != nil {\n\t\tpassword, _ := u.User.Password()\n\t\tauth = &proxy.Auth{\n\t\t\tUser:     u.User.Username(),\n\t\t\tPassword: password,\n\t\t}\n\t}\n\n\treturn proxy.SOCKS5(\"tcp\", u.Host, auth, NetDialerWithTCPKeepalive())\n}\n\nconst proxyAuthHeaderKey = \"Proxy-Authorization\"\n\nfunc mapAddress(address string) (*url.URL, error) {\n\treq := &http.Request{\n\t\tURL: &url.URL{\n\t\t\tScheme: \"https\",\n\t\t\tHost:   address,\n\t\t},\n\t}\n\n\treturn httpproxy.FromEnvironment().ProxyFunc()(req.URL)\n}\n\n// To read a response from a net.Conn, http.ReadResponse() takes a bufio.Reader.\n// It's possible that this reader reads more than what's need for the response and stores\n// those bytes in the buffer.\n// bufConn wraps the original net.Conn and the bufio.Reader to make sure we don't lose the\n// bytes in the buffer.\ntype bufConn struct {\n\tnet.Conn\n\n\tr io.Reader\n}\n\nfunc (c *bufConn) Read(b []byte) (int, error) {\n\treturn c.r.Read(b)\n}\n\nfunc basicAuth(username, password string) string {\n\tauth := username + \":\" + password\n\n\treturn base64.StdEncoding.EncodeToString([]byte(auth))\n}\n\nfunc doHTTPConnectHandshake(ctx context.Context, conn net.Conn, backendAddr string, proxyURL *url.URL, grpcUA string) (_ net.Conn, err error) {\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tconn.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\treq := &http.Request{\n\t\tMethod: http.MethodConnect,\n\t\tURL:    &url.URL{Host: backendAddr},\n\t\tHeader: map[string][]string{\"User-Agent\": {grpcUA}},\n\t}\n\n\tif t := proxyURL.User; t != nil {\n\t\tu := t.Username()\n\t\tp, _ := t.Password()\n\t\treq.Header.Add(proxyAuthHeaderKey, \"Basic \"+basicAuth(u, p))\n\t}\n\n\tif err := sendHTTPRequest(ctx, req, conn); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to write the HTTP request: %v\", err)\n\t}\n\n\tr := bufio.NewReader(conn)\n\n\tresp, err := http.ReadResponse(r, req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading server HTTP response: %v\", err)\n\t}\n\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tdump, err := httputil.DumpResponse(resp, true)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to do connect handshake, status code: %s\", resp.Status)\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"failed to do connect handshake, response: %q\", dump)\n\t}\n\n\t// The buffer could contain extra bytes from the target server, so we can't\n\t// discard it. However, in many cases where the server waits for the client\n\t// to send the first message (e.g. when TLS is being used), the buffer will\n\t// be empty, so we can avoid the overhead of reading through this buffer.\n\tif r.Buffered() != 0 {\n\t\treturn &bufConn{Conn: conn, r: r}, nil\n\t}\n\n\treturn conn, nil\n}\n\nfunc sendHTTPRequest(ctx context.Context, req *http.Request, conn net.Conn) error {\n\treq = req.WithContext(ctx)\n\tif err := req.Write(conn); err != nil {\n\t\treturn fmt.Errorf(\"failed to write the HTTP request: %v\", err)\n\t}\n\n\treturn nil\n}\n\n// NetDialerWithTCPKeepalive returns a net.Dialer that enables TCP keepalives on\n// the underlying connection with OS default values for keepalive parameters.\nfunc NetDialerWithTCPKeepalive() *net.Dialer {\n\treturn &net.Dialer{\n\t\tKeepAliveConfig: net.KeepAliveConfig{\n\t\t\tEnable:   true,\n\t\t\tIdle:     -1,\n\t\t\tCount:    -1,\n\t\t\tInterval: -1,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/events.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EventNotSupportedError is returned from the event decoder when we encounter an unknown event.\ntype EventNotSupportedError struct {\n\tTypeURL string\n}\n\n// Error implements the error interface.\nfunc (e EventNotSupportedError) Error() string {\n\treturn fmt.Sprintf(\"event is not supported: %s\", e.TypeURL)\n}\n\n// EventsOptionFunc defines the options for the Events API.\ntype EventsOptionFunc func(opts *machineapi.EventsRequest)\n\n// WithTailEvents sets up Events API to return specified number of past events.\n//\n// If number is negative, all the available past events are returned.\nfunc WithTailEvents(number int32) EventsOptionFunc {\n\treturn func(opts *machineapi.EventsRequest) {\n\t\topts.TailEvents = number\n\t}\n}\n\n// WithTailID sets up Events API to return events with ID > TailID.\nfunc WithTailID(id string) EventsOptionFunc {\n\treturn func(opts *machineapi.EventsRequest) {\n\t\topts.TailId = id\n\t}\n}\n\n// WithTailDuration sets up Watcher to return events with timestamp >= (now - tailDuration).\nfunc WithTailDuration(dur time.Duration) EventsOptionFunc {\n\treturn func(opts *machineapi.EventsRequest) {\n\t\topts.TailSeconds = int32(dur / time.Second)\n\t}\n}\n\n// WithActorID sets up Watcher to return events with the specified actor ID.\nfunc WithActorID(actorID string) EventsOptionFunc {\n\treturn func(opts *machineapi.EventsRequest) {\n\t\topts.WithActorId = actorID\n\t}\n}\n\n// Events implements the proto.OSClient interface.\nfunc (c *Client) Events(ctx context.Context, opts ...EventsOptionFunc) (stream machineapi.MachineService_EventsClient, err error) {\n\tvar req machineapi.EventsRequest\n\n\tfor _, opt := range opts {\n\t\topt(&req)\n\t}\n\n\treturn c.MachineClient.Events(ctx, &req)\n}\n\n// Event as received from the API.\ntype Event struct {\n\tNode    string\n\tTypeURL string\n\tID      string\n\tActorID string\n\tPayload proto.Message\n}\n\n// EventsWatch wraps Events by providing more simple interface.\n//\n//nolint:gocyclo\nfunc (c *Client) EventsWatch(ctx context.Context, watchFunc func(<-chan Event), opts ...EventsOptionFunc) error {\n\tstream, err := c.Events(ctx, opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching events: %s\", err)\n\t}\n\n\tif err = stream.CloseSend(); err != nil {\n\t\treturn err\n\t}\n\n\tdefaultNode := RemotePeer(stream.Context()) //nolint:contextcheck\n\n\tvar wg sync.WaitGroup\n\n\tdefer wg.Wait()\n\n\tch := make(chan Event)\n\tdefer close(ch)\n\n\twg.Go(func() {\n\t\twatchFunc(ch)\n\t})\n\n\tfor {\n\t\tevent, err := stream.Recv()\n\t\tif err != nil {\n\t\t\tif err == io.EOF || StatusCode(err) == codes.Canceled {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to watch events: %w\", err)\n\t\t}\n\n\t\tev, err := UnmarshalEvent(event)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif ev.Node == \"\" {\n\t\t\tev.Node = defaultNode\n\t\t}\n\n\t\tselect {\n\t\tcase ch <- *ev:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// EventResult is the result of an event watch, containing either an Event or an error.\ntype EventResult struct {\n\t// Event is the event that was received.\n\tEvent Event\n\t// Err is the error that occurred.\n\tError error\n}\n\n// EventsWatchV2 watches events of a single node and wraps the Events by providing a simpler interface.\n// It blocks until the first (empty) event is received, then spawns a goroutine that sends events to the given channel.\n// EventResult objects sent into the channel contain either the errors or the received events.\n//\n//nolint:gocyclo\nfunc (c *Client) EventsWatchV2(ctx context.Context, ch chan<- EventResult, opts ...EventsOptionFunc) error {\n\tctx, cancel := context.WithCancel(ctx)\n\n\tstream, err := c.Events(ctx, opts...)\n\tif err != nil {\n\t\tcancel()\n\n\t\treturn fmt.Errorf(\"error fetching events: %w\", err)\n\t}\n\n\tif err = stream.CloseSend(); err != nil {\n\t\tcancel()\n\n\t\treturn err\n\t}\n\n\tdefaultNode := RemotePeer(stream.Context())\n\n\t// receive first (empty) watch event\n\t_, err = stream.Recv()\n\tif err != nil {\n\t\tcancel()\n\n\t\treturn fmt.Errorf(\"error while watching events: %w\", err)\n\t}\n\n\tgo func() {\n\t\tdefer cancel()\n\n\t\terr = func() error {\n\t\t\tfor {\n\t\t\t\tevent, eventErr := stream.Recv()\n\t\t\t\tif eventErr != nil {\n\t\t\t\t\treturn eventErr\n\t\t\t\t}\n\n\t\t\t\tif event.GetMetadata().GetError() != \"\" {\n\t\t\t\t\tvar mdErr error\n\t\t\t\t\tif event.GetMetadata().GetStatus() != nil {\n\t\t\t\t\t\tmdErr = status.FromProto(event.GetMetadata().GetStatus()).Err()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmdErr = errors.New(event.GetMetadata().GetError())\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fmt.Errorf(\"%s: %w\", event.GetMetadata().GetHostname(), mdErr)\n\t\t\t\t}\n\n\t\t\t\tev, eventErr := UnmarshalEvent(event)\n\t\t\t\tif eventErr != nil {\n\t\t\t\t\treturn eventErr\n\t\t\t\t}\n\n\t\t\t\tif ev == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif ev.Node == \"\" {\n\t\t\t\t\tev.Node = defaultNode\n\t\t\t\t}\n\n\t\t\t\tselect {\n\t\t\t\tcase ch <- EventResult{Event: *ev}:\n\t\t\t\tcase <-ctx.Done():\n\t\t\t\t\treturn ctx.Err()\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tif err != nil {\n\t\t\tselect {\n\t\t\tcase ch <- EventResult{Error: err}:\n\t\t\tcase <-ctx.Done():\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// UnmarshalEvent decodes the event coming from the gRPC stream from any to the exact type.\nfunc UnmarshalEvent(event *machineapi.Event) (*Event, error) {\n\ttypeURL := event.GetData().GetTypeUrl()\n\n\tvar msg proto.Message\n\n\tfor _, eventType := range []proto.Message{\n\t\t&machineapi.SequenceEvent{},\n\t\t&machineapi.PhaseEvent{},\n\t\t&machineapi.TaskEvent{},\n\t\t&machineapi.ServiceStateEvent{},\n\t\t&machineapi.ConfigLoadErrorEvent{},\n\t\t&machineapi.ConfigValidationErrorEvent{},\n\t\t&machineapi.AddressEvent{},\n\t\t&machineapi.MachineStatusEvent{},\n\t\t&machineapi.RestartEvent{},\n\t} {\n\t\tif typeURL == \"talos/runtime/\"+string(eventType.ProtoReflect().Descriptor().FullName()) {\n\t\t\tmsg = eventType\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif msg == nil {\n\t\t// We haven't implemented the handling of this event yet.\n\t\treturn nil, EventNotSupportedError{\n\t\t\tTypeURL: typeURL,\n\t\t}\n\t}\n\n\tif err := proto.Unmarshal(event.GetData().GetValue(), msg); err != nil {\n\t\tlog.Printf(\"failed to unmarshal message: %v\", err)\n\n\t\treturn nil, err\n\t}\n\n\tev := Event{\n\t\tTypeURL: typeURL,\n\t\tID:      event.Id,\n\t\tPayload: msg,\n\t\tActorID: event.ActorId,\n\t}\n\n\tif event.Metadata != nil {\n\t\tev.Node = event.Metadata.Hostname\n\t}\n\n\treturn &ev, nil\n}\n"
  },
  {
    "path": "pkg/machinery/client/export_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"crypto/tls\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\nfunc ReduceURLsToAddresses(endpoints []string) []string {\n\treturn reduceURLsToAddresses(endpoints)\n}\n\nfunc BuildTLSConfig(configContext *clientconfig.Context) (*tls.Config, error) {\n\treturn buildTLSConfig(configContext)\n}\n"
  },
  {
    "path": "pkg/machinery/client/grpc_connection_wrapper.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\t\"runtime/pprof\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\nvar grpcConnPprof = pprof.NewProfile(\"machinery/client/grpc.grpcConn\")\n\ntype grpcConnectionWrapper struct {\n\t*grpc.ClientConn\n\n\tclusterName string\n}\n\nfunc newGRPCConnectionWrapper(clusterName string, conn *grpc.ClientConn) *grpcConnectionWrapper {\n\tres := &grpcConnectionWrapper{\n\t\tClientConn:  conn,\n\t\tclusterName: clusterName,\n\t}\n\n\tgrpcConnPprof.Add(res, 1)\n\n\treturn res\n}\n\n// Invoke performs a unary RPC and returns after the response is received\n// into reply.\nfunc (c *grpcConnectionWrapper) Invoke(ctx context.Context, method string, args any, reply any, opts ...grpc.CallOption) error {\n\treturn c.ClientConn.Invoke(c.appendMetadata(ctx), method, args, reply, opts...)\n}\n\n// NewStream begins a streaming RPC.\nfunc (c *grpcConnectionWrapper) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) {\n\treturn c.ClientConn.NewStream(c.appendMetadata(ctx), desc, method, opts...)\n}\n\n// Close closes the connection.\nfunc (c *grpcConnectionWrapper) Close() error {\n\tgrpcConnPprof.Remove(c)\n\n\treturn c.ClientConn.Close()\n}\n\nfunc (c *grpcConnectionWrapper) appendMetadata(ctx context.Context) context.Context {\n\tctx = metadata.AppendToOutgoingContext(ctx, \"runtime\", \"Talos\")\n\n\tif c.clusterName != \"\" {\n\t\tctx = metadata.AppendToOutgoingContext(ctx, \"context\", c.clusterName)\n\t}\n\n\treturn ctx\n}\n"
  },
  {
    "path": "pkg/machinery/client/insecure_credentials.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build sidero.debug\n\npackage client\n\nimport (\n\t\"net/url\"\n\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// shouldInsecureConnectionsBeAllowed returns true if one endpoint starts with http://\nfunc shouldInsecureConnectionsBeAllowed(endpoints []string) bool {\n\tfor _, endpoint := range endpoints {\n\t\tu, _ := url.Parse(endpoint)\n\t\tif u.Scheme == \"http\" {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// RequireTransportSecurity enables basic auth with insecure gRPC transport credentials.\nfunc (c BasicAuth) RequireTransportSecurity() bool {\n\treturn false\n}\n\nfunc buildCredentials(configContext *clientconfig.Context, endpoints []string) (credentials.TransportCredentials, error) {\n\tif shouldInsecureConnectionsBeAllowed(endpoints) {\n\t\treturn insecure.NewCredentials(), nil\n\t}\n\n\ttlsConfig, err := buildTLSConfig(configContext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn credentials.NewTLS(tlsConfig), nil\n}\n"
  },
  {
    "path": "pkg/machinery/client/inspect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n\n\tinspectapi \"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n)\n\n// InspectClient provides access to inspect API.\ntype InspectClient struct {\n\tclient inspectapi.InspectServiceClient\n}\n\n// ControllerRuntimeDependencies returns graph describing dependencies between controllers.\nfunc (c *InspectClient) ControllerRuntimeDependencies(ctx context.Context, callOptions ...grpc.CallOption) (*inspectapi.ControllerRuntimeDependenciesResponse, error) {\n\tresp, err := c.client.ControllerRuntimeDependencies(ctx, &emptypb.Empty{}, callOptions...)\n\n\treturn FilterMessages(resp, err)\n}\n"
  },
  {
    "path": "pkg/machinery/client/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\n\t\"google.golang.org/grpc\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client/dialer\"\n)\n\nvar defaultDialOptions = []grpc.DialOption{\n\tgrpc.WithContextDialer(dialer.DynamicProxyDialer),\n}\n\n// Options contains the set of client configuration options.\ntype Options struct {\n\tendpointsOverride []string\n\tconfig            *clientconfig.Config\n\tconfigContext     *clientconfig.Context\n\ttlsConfig         *tls.Config\n\tgrpcDialOptions   []grpc.DialOption\n\n\tcontextOverride    string\n\tcontextOverrideSet bool\n\n\tunixSocketPath       string\n\tclusterNameOverride  string\n\tsideroV1KeysDir      string\n\tserviceAccountBase64 string\n}\n\n// OptionFunc sets an option for the creation of the Client.\ntype OptionFunc func(*Options) error\n\n// WithConfig configures the Client with the configuration provided.\n// Additionally use WithContextName to override the default context in the Config.\nfunc WithConfig(cfg *clientconfig.Config) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.config = cfg\n\n\t\treturn nil\n\t}\n}\n\n// WithContextName overrides the default context inside a provided client Config.\nfunc WithContextName(name string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.contextOverride = name\n\n\t\to.contextOverrideSet = true\n\n\t\treturn nil\n\t}\n}\n\n// WithConfigContext configures the Client with the configuration context provided.\nfunc WithConfigContext(cfg *clientconfig.Context) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.configContext = cfg\n\n\t\treturn nil\n\t}\n}\n\n// WithDefaultGRPCDialOptions adds the default grpc.DialOptions to a Client.\nfunc WithDefaultGRPCDialOptions() OptionFunc {\n\treturn func(o *Options) error {\n\t\to.grpcDialOptions = append(o.grpcDialOptions, defaultDialOptions...)\n\n\t\treturn nil\n\t}\n}\n\n// WithGRPCDialOptions adds the given grpc.DialOptions to a Client.\nfunc WithGRPCDialOptions(opts ...grpc.DialOption) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.grpcDialOptions = append(o.grpcDialOptions, opts...)\n\n\t\treturn nil\n\t}\n}\n\n// WithTLSConfig overrides the default TLS configuration with the one provided.\nfunc WithTLSConfig(tlsConfig *tls.Config) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.tlsConfig = tlsConfig\n\n\t\treturn nil\n\t}\n}\n\n// WithEndpoints overrides the default endpoints with the provided list.\nfunc WithEndpoints(endpoints ...string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.endpointsOverride = endpoints\n\n\t\treturn nil\n\t}\n}\n\n// WithDefaultConfig creates a Client with its configuration sourced from the\n// default config file location.\n// Additionally use WithContextName to select a context other than the default.\nfunc WithDefaultConfig() OptionFunc {\n\treturn func(o *Options) (err error) {\n\t\treturn WithConfigFromFile(\"\")(o)\n\t}\n}\n\n// WithConfigFromFile creates a Client with its configuration extracted from the given file.\n// Additionally use WithContextName to select a context other than the default.\nfunc WithConfigFromFile(fn string) OptionFunc {\n\treturn func(o *Options) (err error) {\n\t\tcfg, err := clientconfig.Open(fn)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read config from %q: %w\", fn, err)\n\t\t}\n\n\t\to.config = cfg\n\n\t\treturn nil\n\t}\n}\n\n// WithUnixSocket creates a Client which connects to apid over local file socket.\n//\n// This option disables config parsing and TLS.\n//\n// Connection over unix socket is only used within the Talos node.\nfunc WithUnixSocket(path string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.unixSocketPath = path\n\n\t\treturn nil\n\t}\n}\n\n// WithCluster creates a Client which connects to the named cluster.\nfunc WithCluster(cluster string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.clusterNameOverride = cluster\n\n\t\treturn nil\n\t}\n}\n\n// WithSideroV1KeysDir overrides the default SideroV1KeysDir configuration with the one provided.\nfunc WithSideroV1KeysDir(keysDir string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.sideroV1KeysDir = keysDir\n\n\t\treturn nil\n\t}\n}\n\n// WithServiceAccount sets the base64-encoded service account key for authentication.\n//\n// When set, the service account key takes priority over SIDERO_SERVICE_ACCOUNT_KEY and OMNI_SERVICE_ACCOUNT_KEY environment variables.\nfunc WithServiceAccount(serviceAccountBase64 string) OptionFunc {\n\treturn func(o *Options) error {\n\t\to.serviceAccountBase64 = serviceAccountBase64\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/peer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"google.golang.org/grpc/peer\"\n)\n\n// RemotePeer parses remote peer address from grpc stream context.\nfunc RemotePeer(ctx context.Context) (peerHost string) {\n\tpeerHost = \"unknown\"\n\n\tremote, ok := peer.FromContext(ctx)\n\tif ok {\n\t\tpeerHost = AddrFromPeer(remote)\n\t}\n\n\treturn peerHost\n}\n\n// AddrFromPeer extracts peer address from grpc Peer.\nfunc AddrFromPeer(remote *peer.Peer) (peerHost string) {\n\tpeerHost = remote.Addr.String()\n\tpeerHost, _, _ = net.SplitHostPort(peerHost) //nolint:errcheck\n\n\treturn peerHost\n}\n"
  },
  {
    "path": "pkg/machinery/client/reply.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\trpcstatus \"google.golang.org/genproto/googleapis/rpc/status\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\n// NodeError is RPC error from some node.\ntype NodeError struct {\n\tNode string\n\tErr  error\n}\n\nfunc (ne *NodeError) Error() string {\n\treturn fmt.Sprintf(\"%s: %s\", ne.Node, ne.Err)\n}\n\n// Unwrap implements errors.Unwrap interface.\nfunc (ne *NodeError) Unwrap() error {\n\treturn ne.Err\n}\n\n// Message is a generic interface for Messages.\ntype Message[T any] interface {\n\t*T\n\tproto.Message\n}\n\n// MessageResponse is a generic interface for response with Messages.\ntype MessageResponse[V any, T Message[V]] interface {\n\tproto.Message\n\tGetMessages() []T\n}\n\n// FilterMessages removes error Messages from resp and builds multierror.\nfunc FilterMessages[V any, T Message[V], MR MessageResponse[V, T]](resp MR, err error) (MR, error) {\n\tvar zero MR\n\n\tres, filteredErr := filterMessages(resp, err)\n\tif res == nil {\n\t\treturn zero, filteredErr\n\t}\n\n\treturn resp, filteredErr\n}\n\n//nolint:gocyclo,cyclop\nfunc filterMessages(resp any, err error) (any, error) {\n\tif resp == nil {\n\t\treturn nil, err\n\t}\n\n\trespStructPtr := reflect.ValueOf(resp)\n\tif respStructPtr.Kind() != reflect.Ptr {\n\t\tpanic(\"response should be pointer to struct\")\n\t}\n\n\tif respStructPtr.IsNil() {\n\t\treturn nil, err\n\t}\n\n\trespStruct := respStructPtr.Elem()\n\tif respStruct.Kind() != reflect.Struct {\n\t\tpanic(\"response should be struct\")\n\t}\n\n\tmessagesField := respStruct.FieldByName(\"Messages\")\n\tif !messagesField.IsValid() {\n\t\tpanic(\"Messages field missing\")\n\t}\n\n\tif messagesField.Kind() != reflect.Slice {\n\t\tpanic(\"Messages field should be a slice\")\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor i := 0; i < messagesField.Len(); {\n\t\tMessagesPtr := messagesField.Index(i)\n\t\tif MessagesPtr.Kind() != reflect.Ptr {\n\t\t\tpanic(\"Messages slice should container pointers\")\n\t\t}\n\n\t\tMessages := MessagesPtr.Elem()\n\t\tif Messages.Kind() != reflect.Struct {\n\t\t\tpanic(\"Messages slice should container pointers to structs\")\n\t\t}\n\n\t\tmetadataField := Messages.FieldByName(\"Metadata\")\n\t\tif !metadataField.IsValid() {\n\t\t\tpanic(\"Messages metadata field missing\")\n\t\t}\n\n\t\tif metadataField.Kind() != reflect.Ptr {\n\t\t\tpanic(\"Messages metadata field should be a pointer\")\n\t\t}\n\n\t\tif metadataField.IsNil() {\n\t\t\t// missing metadata, skip the field\n\t\t\ti++\n\n\t\t\tcontinue\n\t\t}\n\n\t\tmetadata := metadataField.Elem()\n\t\tif metadata.Kind() != reflect.Struct {\n\t\t\tpanic(\"Messages metadata should be struct\")\n\t\t}\n\n\t\terrorField := metadata.FieldByName(\"Error\")\n\t\tif !errorField.IsValid() {\n\t\t\tpanic(\"metadata.Error field missing\")\n\t\t}\n\n\t\tif errorField.Kind() != reflect.String {\n\t\t\tpanic(\"metadata.Error should be string\")\n\t\t}\n\n\t\tif errorField.IsZero() {\n\t\t\t// no error, leave it as is\n\t\t\ti++\n\n\t\t\tcontinue\n\t\t}\n\n\t\trpcError := errors.New(errorField.String())\n\n\t\tstatusField := metadata.FieldByName(\"Status\")\n\t\tif !statusField.IsValid() {\n\t\t\tpanic(\"metadata.Status field missing\")\n\t\t}\n\n\t\tif statusField.Kind() != reflect.Ptr {\n\t\t\tpanic(\"metadata.Status should be pointer\")\n\t\t}\n\n\t\tif !statusField.IsZero() {\n\t\t\tstatusValue, ok := statusField.Interface().(*rpcstatus.Status)\n\t\t\tif !ok {\n\t\t\t\tpanic(\"metadata.Status should be of type *status.Status\")\n\t\t\t}\n\n\t\t\trpcError = status.FromProto(statusValue).Err()\n\t\t}\n\n\t\thostnameField := metadata.FieldByName(\"Hostname\")\n\t\tif !hostnameField.IsValid() {\n\t\t\tpanic(\"metadata.Hostname field missing\")\n\t\t}\n\n\t\tif hostnameField.Kind() != reflect.String {\n\t\t\tpanic(\"metadata.Hostname should be string\")\n\t\t}\n\n\t\t// extract error\n\t\tnodeError := &NodeError{\n\t\t\tNode: hostnameField.String(),\n\t\t\tErr:  rpcError,\n\t\t}\n\n\t\tmultiErr = multierror.Append(multiErr, nodeError)\n\n\t\t// remove ith Messages\n\t\treflect.Copy(messagesField.Slice(i, messagesField.Len()), messagesField.Slice(i+1, messagesField.Len()))\n\t\tmessagesField.SetLen(messagesField.Len() - 1)\n\t}\n\n\t// if all the Messages were error Messages...\n\tif multiErr != nil && messagesField.Len() == 0 {\n\t\tresp = nil\n\t}\n\n\treturn resp, multiErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "pkg/machinery/client/reply_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"google.golang.org/genproto/googleapis/rpc/status\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc TestFilterMessages(t *testing.T) {\n\treply := &common.DataResponse{\n\t\tMessages: []*common.Data{\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host1\",\n\t\t\t\t},\n\t\t\t\tBytes: []byte(\"abc\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host2\",\n\t\t\t\t\tError:    \"something wrong\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tBytes: []byte(\"def\"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host4\",\n\t\t\t\t\tError:    \"even more wrong\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfiltered, err := client.FilterMessages(reply, nil)\n\tassert.EqualError(t, err, \"2 errors occurred:\\n\\t* host2: something wrong\\n\\t* host4: even more wrong\\n\\n\")\n\tassert.Equal(t, filtered,\n\t\t&common.DataResponse{\n\t\t\tMessages: []*common.Data{\n\t\t\t\t{\n\t\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\t\tHostname: \"host1\",\n\t\t\t\t\t},\n\t\t\t\t\tBytes: []byte(\"abc\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tBytes: []byte(\"def\"),\n\t\t\t\t},\n\t\t\t},\n\t\t})\n}\n\nfunc TestFilterMessagesNil(t *testing.T) {\n\te := errors.New(\"wrong\")\n\n\tfiltered, err := client.FilterMessages((*common.DataResponse)(nil), e)\n\tassert.Nil(t, filtered)\n\tassert.Equal(t, e, err)\n}\n\nfunc TestFilterMessagesOnlyErrors(t *testing.T) {\n\treply := &common.DataResponse{\n\t\tMessages: []*common.Data{\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host2\",\n\t\t\t\t\tError:    \"something wrong\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host4\",\n\t\t\t\t\tError:    \"even more wrong\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfiltered, err := client.FilterMessages(reply, nil)\n\tassert.EqualError(t, err, \"2 errors occurred:\\n\\t* host2: something wrong\\n\\t* host4: even more wrong\\n\\n\")\n\tassert.Nil(t, filtered)\n}\n\nfunc TestFilterMessagesGRPCStatus(t *testing.T) {\n\treply := &common.DataResponse{\n\t\tMessages: []*common.Data{\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host2\",\n\t\t\t\t\tError:    \"should be ignored\",\n\t\t\t\t\tStatus: &status.Status{\n\t\t\t\t\t\tCode:    int32(codes.Aborted),\n\t\t\t\t\t\tMessage: \"something aborted\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tMetadata: &common.Metadata{\n\t\t\t\t\tHostname: \"host4\",\n\t\t\t\t\tError:    \"should be ignored\",\n\t\t\t\t\tStatus: &status.Status{\n\t\t\t\t\t\tCode:    int32(codes.Unknown),\n\t\t\t\t\t\tMessage: \"something went wrong\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfiltered, err := client.FilterMessages(reply, nil)\n\tassert.EqualError(t, err, \"2 errors occurred:\\n\\t* host2: rpc error: code = Aborted desc = something aborted\\n\\t* host4: rpc error: code = Unknown desc = something went wrong\\n\\n\")\n\tassert.Nil(t, filtered)\n}\n"
  },
  {
    "path": "pkg/machinery/client/resolver/resolver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package resolver implements gRPC resolvers.\npackage resolver\n"
  },
  {
    "path": "pkg/machinery/client/resolver/roundrobin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage resolver\n\nimport (\n\t\"math/rand/v2\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc/resolver\"\n)\n\n// RoundRobinResolverScheme is a scheme to use in grpc.Dial for the round-robin gRPC resolver.\n// This resolver requires that all endpoints have a port appended.\n// To ensure this, use EnsureEndpointsHavePorts before constructing a connection string.\nconst RoundRobinResolverScheme = \"talosroundrobin\"\n\nfunc init() {\n\tresolver.Register(&roundRobinResolverBuilder{\n\t\tscheme: RoundRobinResolverScheme,\n\t})\n}\n\ntype roundRobinResolverBuilder struct {\n\tscheme string\n}\n\n// Build implements resolver.Builder.\nfunc (b *roundRobinResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {\n\tr := &roundRobinResolver{\n\t\ttarget: target,\n\t\tcc:     cc,\n\t}\n\n\tif err := r.start(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r, nil\n}\n\n// Build implements resolver.Builder.\nfunc (b *roundRobinResolverBuilder) Scheme() string {\n\treturn b.scheme\n}\n\ntype roundRobinResolver struct {\n\ttarget resolver.Target\n\tcc     resolver.ClientConn\n}\n\n// EnsureEndpointsHavePorts returns the list of endpoints with default port appended to those addresses that don't have a port.\nfunc EnsureEndpointsHavePorts(endpoints []string, defaultPort int) []string {\n\treturn xslices.Map(endpoints, func(endpoint string) string {\n\t\t_, _, err := net.SplitHostPort(endpoint)\n\t\tif err != nil {\n\t\t\treturn net.JoinHostPort(endpoint, strconv.Itoa(defaultPort))\n\t\t}\n\n\t\treturn endpoint\n\t})\n}\n\nfunc (r *roundRobinResolver) start() error {\n\tvar addrs []resolver.Address //nolint:prealloc\n\n\tendpoints := strings.SplitSeq(r.target.Endpoint(), \",\")\n\n\tfor addr := range endpoints {\n\t\tserverName := addr\n\n\t\thost, _, err := net.SplitHostPort(serverName)\n\t\tif err == nil {\n\t\t\tserverName = host\n\t\t}\n\n\t\taddrs = append(addrs, resolver.Address{\n\t\t\tServerName: serverName,\n\t\t\tAddr:       addr,\n\t\t})\n\t}\n\n\t// shuffle the list in case client does just one request\n\trand.Shuffle(len(addrs), func(i, j int) {\n\t\taddrs[i], addrs[j] = addrs[j], addrs[i]\n\t})\n\n\tserviceConfigJSON := `{\n\t\t\"loadBalancingConfig\": [{\n\t\t\t\"round_robin\": {}\n\t\t}]\n\t}`\n\n\tparsedServiceConfig := r.cc.ParseServiceConfig(serviceConfigJSON)\n\n\tif parsedServiceConfig.Err != nil {\n\t\treturn parsedServiceConfig.Err\n\t}\n\n\treturn r.cc.UpdateState(resolver.State{\n\t\tAddresses:     addrs,\n\t\tServiceConfig: parsedServiceConfig,\n\t})\n}\n\n// ResolveNow implements resolver.Resolver.\nfunc (r *roundRobinResolver) ResolveNow(o resolver.ResolveNowOptions) {}\n\n// ResolveNow implements resolver.Resolver.\nfunc (r *roundRobinResolver) Close() {}\n"
  },
  {
    "path": "pkg/machinery/client/resolver/roundrobin_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage resolver_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client/resolver\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestEnsureEndpointsHavePorts(t *testing.T) {\n\tendpoints := []string{\n\t\t\"123.123.123.123\",\n\t\t\"exammple.com:111\",\n\t\t\"234.234.234.234:4000\",\n\t\t\"localhost\",\n\t\t\"localhost:890\",\n\t\t\"2001:db8:0:0:0:ff00:42:8329\",\n\t\t\"www.company.com\",\n\t\t\"[2001:db8:4006:812::200e]:8080\",\n\t}\n\texpected := []string{\n\t\t\"123.123.123.123:50000\",\n\t\t\"exammple.com:111\",\n\t\t\"234.234.234.234:4000\",\n\t\t\"localhost:50000\",\n\t\t\"localhost:890\",\n\t\t\"[2001:db8:0:0:0:ff00:42:8329]:50000\",\n\t\t\"www.company.com:50000\",\n\t\t\"[2001:db8:4006:812::200e]:8080\",\n\t}\n\n\tactual := resolver.EnsureEndpointsHavePorts(endpoints, constants.ApidPort)\n\n\tassert.Equal(t, expected, actual)\n}\n"
  },
  {
    "path": "pkg/machinery/client/resources.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// ResolveResourceKind resolves potentially aliased 'resourceType' and replaces empty 'resourceNamespace' with the default namespace for the resource.\nfunc (c *Client) ResolveResourceKind(ctx context.Context, resourceNamespace *resource.Namespace, resourceType resource.Type) (*meta.ResourceDefinition, error) {\n\tregisteredResources, err := safe.StateListAll[*meta.ResourceDefinition](ctx, c.COSI)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar matched []*meta.ResourceDefinition\n\n\tfor rd := range registeredResources.All() {\n\t\tif strings.EqualFold(rd.Metadata().ID(), resourceType) {\n\t\t\tmatched = append(matched, rd)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tspec := rd.TypedSpec()\n\n\t\tfor _, alias := range spec.AllAliases {\n\t\t\tif strings.EqualFold(alias, resourceType) {\n\t\t\t\tmatched = append(matched, rd)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch {\n\tcase len(matched) == 1:\n\t\tif *resourceNamespace == \"\" {\n\t\t\t*resourceNamespace = matched[0].TypedSpec().DefaultNamespace\n\t\t}\n\n\t\treturn matched[0], nil\n\tcase len(matched) > 1:\n\t\tmatchedTypes := xslices.Map(matched, func(rd *meta.ResourceDefinition) string { return rd.Metadata().ID() })\n\n\t\treturn nil, status.Errorf(codes.InvalidArgument, \"resource type %q is ambiguous: %v\", resourceType, matchedTypes)\n\tdefault:\n\t\treturn nil, status.Errorf(codes.NotFound, \"resource %q is not registered\", resourceType)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/client/secure_credentials.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !sidero.debug\n\npackage client\n\nimport (\n\t\"google.golang.org/grpc/credentials\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// RequireTransportSecurity implements credentials.PerRPCCredentials.\nfunc (c BasicAuth) RequireTransportSecurity() bool {\n\treturn true\n}\n\nfunc buildCredentials(configContext *clientconfig.Context, _ []string) (credentials.TransportCredentials, error) {\n\ttlsConfig, err := buildTLSConfig(configContext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn credentials.NewTLS(tlsConfig), nil\n}\n"
  },
  {
    "path": "pkg/machinery/client/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client\n\nimport (\n\t\"errors\"\n\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// Status returns the status if it is a Status error, nil otherwise.\nfunc Status(err error) *status.Status {\n\ttype grpcStatus interface {\n\t\tGRPCStatus() *status.Status\n\t}\n\n\t// Don't use FromError to avoid allocation of OK status.\n\tvar st grpcStatus\n\n\tif errors.As(err, &st) {\n\t\treturn st.GRPCStatus()\n\t}\n\n\treturn nil\n}\n\n// StatusCode returns the Code of the error if it is a Status error, codes.OK if err\n// is nil, or codes.Unknown otherwise correctly unwrapping wrapped errors.\n//\n// StatusCode is mostly equivalent to grpc `status.Code` method, but it correctly unwraps wrapped errors\n// including `multierror.Error` used when parsing multi-node responses.\nfunc StatusCode(err error) codes.Code {\n\tif err == nil {\n\t\treturn codes.OK\n\t}\n\n\tif st := Status(err); st != nil {\n\t\treturn st.Code()\n\t}\n\n\treturn codes.Unknown\n}\n"
  },
  {
    "path": "pkg/machinery/client/status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage client_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\nfunc TestStatus(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname      string\n\t\terr       error\n\t\tnilStatus bool\n\t\tmessage   string\n\t\tcode      codes.Code\n\t}{\n\t\t{\n\t\t\tname:      \"nil\",\n\t\t\terr:       nil,\n\t\t\tnilStatus: true,\n\t\t\tcode:      codes.OK,\n\t\t},\n\t\t{\n\t\t\tname:      \"not status\",\n\t\t\terr:       errors.New(\"some error\"),\n\t\t\tnilStatus: true,\n\t\t\tcode:      codes.Unknown,\n\t\t},\n\t\t{\n\t\t\tname:    \"status\",\n\t\t\terr:     status.Error(codes.AlreadyExists, \"file already exists\"),\n\t\t\tmessage: \"file already exists\",\n\t\t\tcode:    codes.AlreadyExists,\n\t\t},\n\t\t{\n\t\t\tname:    \"status wrapped\",\n\t\t\terr:     multierror.Append(nil, status.Error(codes.AlreadyExists, \"file already exists\")).ErrorOrNil(),\n\t\t\tmessage: \"file already exists\",\n\t\t\tcode:    codes.AlreadyExists,\n\t\t},\n\t\t{\n\t\t\tname:    \"multiple wrapped\",\n\t\t\terr:     multierror.Append(nil, status.Error(codes.FailedPrecondition, \"can't be zero\"), status.Error(codes.AlreadyExists, \"file already exists\")).ErrorOrNil(),\n\t\t\tmessage: \"can't be zero\",\n\t\t\tcode:    codes.FailedPrecondition,\n\t\t},\n\t\t{\n\t\t\tname:    \"double wrapped\",\n\t\t\terr:     multierror.Append(nil, fmt.Errorf(\"127.0.0.1: %w\", status.Error(codes.AlreadyExists, \"file already exists\"))).ErrorOrNil(),\n\t\t\tmessage: \"file already exists\",\n\t\t\tcode:    codes.AlreadyExists,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tst := client.Status(tt.err)\n\t\t\tif tt.nilStatus {\n\t\t\t\tassert.Nil(t, st)\n\t\t\t} else {\n\t\t\t\tassert.Equal(t, st.Message(), tt.message)\n\t\t\t\tassert.Equal(t, st.Code(), tt.code)\n\t\t\t}\n\n\t\t\tassert.Equal(t, client.StatusCode(tt.err), tt.code)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/compatibility/compatibility.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package compatibility provides version compatibility checks for Talos.\npackage compatibility\n"
  },
  {
    "path": "pkg/machinery/compatibility/kubernetes_version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage compatibility\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos110\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos111\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos112\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos113\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos12\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos13\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos14\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos15\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos16\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos17\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos18\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos19\"\n)\n\n// KubernetesVersion embeds Kubernetes version.\ntype KubernetesVersion struct {\n\tvers semver.Version\n}\n\n// ParseKubernetesVersion parses Kubernetes version.\nfunc ParseKubernetesVersion(v string) (*KubernetesVersion, error) {\n\tparsed, err := semver.ParseTolerant(v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &KubernetesVersion{\n\t\tvers: parsed,\n\t}, nil\n}\n\nfunc (v *KubernetesVersion) String() string {\n\treturn v.vers.String()\n}\n\n// SupportedWith checks if the Kubernetes version is supported with specified version of Talos.\n//\n//nolint:gocyclo\nfunc (v *KubernetesVersion) SupportedWith(target *TalosVersion) error {\n\tvar minK8sVersion, maxK8sVersion semver.Version\n\n\tswitch target.majorMinor {\n\tcase talos12.MajorMinor: // upgrades to 1.2.x\n\t\tminK8sVersion, maxK8sVersion = talos12.MinimumKubernetesVersion, talos12.MaximumKubernetesVersion\n\tcase talos13.MajorMinor: // upgrades to 1.3.x\n\t\tminK8sVersion, maxK8sVersion = talos13.MinimumKubernetesVersion, talos13.MaximumKubernetesVersion\n\tcase talos14.MajorMinor: // upgrades to 1.4.x\n\t\tminK8sVersion, maxK8sVersion = talos14.MinimumKubernetesVersion, talos14.MaximumKubernetesVersion\n\tcase talos15.MajorMinor: // upgrades to 1.5.x\n\t\tminK8sVersion, maxK8sVersion = talos15.MinimumKubernetesVersion, talos15.MaximumKubernetesVersion\n\tcase talos16.MajorMinor: // upgrades to 1.6.x\n\t\tminK8sVersion, maxK8sVersion = talos16.MinimumKubernetesVersion, talos16.MaximumKubernetesVersion\n\tcase talos17.MajorMinor: // upgrades to 1.7.x\n\t\tminK8sVersion, maxK8sVersion = talos17.MinimumKubernetesVersion, talos17.MaximumKubernetesVersion\n\tcase talos18.MajorMinor: // upgrades to 1.8.x\n\t\tminK8sVersion, maxK8sVersion = talos18.MinimumKubernetesVersion, talos18.MaximumKubernetesVersion\n\tcase talos19.MajorMinor: // upgrades to 1.9.x\n\t\tminK8sVersion, maxK8sVersion = talos19.MinimumKubernetesVersion, talos19.MaximumKubernetesVersion\n\tcase talos110.MajorMinor: // upgrades to 1.10.x\n\t\tminK8sVersion, maxK8sVersion = talos110.MinimumKubernetesVersion, talos110.MaximumKubernetesVersion\n\tcase talos111.MajorMinor: // upgrades to 1.11.x\n\t\tminK8sVersion, maxK8sVersion = talos111.MinimumKubernetesVersion, talos111.MaximumKubernetesVersion\n\tcase talos112.MajorMinor: // upgrades to 1.12.x\n\t\tminK8sVersion, maxK8sVersion = talos112.MinimumKubernetesVersion, talos112.MaximumKubernetesVersion\n\tcase talos113.MajorMinor: // upgrades to 1.13.x\n\t\tminK8sVersion, maxK8sVersion = talos113.MinimumKubernetesVersion, talos113.MaximumKubernetesVersion\n\tdefault:\n\t\treturn fmt.Errorf(\"compatibility with version %s is not supported\", target.String())\n\t}\n\n\tcore := ordered.MakeTriple(v.vers.Major, v.vers.Minor, v.vers.Patch)\n\tminK8sVersionCore := ordered.MakeTriple(minK8sVersion.Major, minK8sVersion.Minor, minK8sVersion.Patch)\n\n\tif core.LessThan(minK8sVersionCore) {\n\t\treturn fmt.Errorf(\"version of Kubernetes %s is too old to be used with Talos %s\", v.vers.String(), target.version.String())\n\t}\n\n\tmaxK8sVersionCore := ordered.MakeTriple(maxK8sVersion.Major, maxK8sVersion.Minor, maxK8sVersion.Patch)\n\n\tif core.Compare(maxK8sVersionCore) >= 0 {\n\t\treturn fmt.Errorf(\"version of Kubernetes %s is too new to be used with Talos %s\", v.vers.String(), target.version.String())\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/compatibility/kubernetes_version_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage compatibility_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n)\n\ntype kubernetesVersionTest struct {\n\tkubernetesVersion string\n\ttarget            string\n\texpectedError     string\n}\n\nfunc runKubernetesVersionTest(t *testing.T, tt kubernetesVersionTest) {\n\tt.Run(tt.kubernetesVersion+\" -> \"+tt.target, func(t *testing.T) {\n\t\tk8sVersion, err := compatibility.ParseKubernetesVersion(tt.kubernetesVersion)\n\t\trequire.NoError(t, err)\n\n\t\ttarget, err := compatibility.ParseTalosVersion(&machine.VersionInfo{\n\t\t\tTag: tt.target,\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\terr = k8sVersion.SupportedWith(target)\n\t\tif tt.expectedError != \"\" {\n\t\t\trequire.EqualError(t, err, tt.expectedError)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n}\n\nfunc TestKubernetesCompatibility12(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.23.1\",\n\t\t\ttarget:            \"1.2.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.24.3\",\n\t\t\ttarget:            \"1.2.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.0-rc.0\",\n\t\t\ttarget:            \"1.2.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.0-alpha.0\",\n\t\t\ttarget:            \"1.2.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.26.0-alpha.0 is too new to be used with Talos 1.2.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.22.4\",\n\t\t\ttarget:            \"1.2.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.22.4 is too old to be used with Talos 1.2.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility13(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.24.1\",\n\t\t\ttarget:            \"1.3.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.3\",\n\t\t\ttarget:            \"1.3.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.0-rc.0\",\n\t\t\ttarget:            \"1.3.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.0-alpha.0\",\n\t\t\ttarget:            \"1.3.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.27.0-alpha.0 is too new to be used with Talos 1.3.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.23.4\",\n\t\t\ttarget:            \"1.3.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.23.4 is too old to be used with Talos 1.3.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility14(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.1\",\n\t\t\ttarget:            \"1.4.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.3\",\n\t\t\ttarget:            \"1.4.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.0-rc.0\",\n\t\t\ttarget:            \"1.4.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.0-alpha.0\",\n\t\t\ttarget:            \"1.4.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.28.0-alpha.0 is too new to be used with Talos 1.4.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.24.1\",\n\t\t\ttarget:            \"1.4.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.24.1 is too old to be used with Talos 1.4.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility15(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.1\",\n\t\t\ttarget:            \"1.5.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.3\",\n\t\t\ttarget:            \"1.5.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.0-rc.0\",\n\t\t\ttarget:            \"1.5.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.29.0-alpha.0\",\n\t\t\ttarget:            \"1.5.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.29.0-alpha.0 is too new to be used with Talos 1.5.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.1\",\n\t\t\ttarget:            \"1.5.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.25.1 is too old to be used with Talos 1.5.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility16(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.1\",\n\t\t\ttarget:            \"1.6.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.24.1\",\n\t\t\ttarget:            \"1.6.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.3\",\n\t\t\ttarget:            \"1.6.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.29.0-rc.0\",\n\t\t\ttarget:            \"1.6.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.0-alpha.0\",\n\t\t\ttarget:            \"1.6.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.30.0-alpha.0 is too new to be used with Talos 1.6.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.23.1\",\n\t\t\ttarget:            \"1.6.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.23.1 is too old to be used with Talos 1.6.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility17(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.1\",\n\t\t\ttarget:            \"1.7.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.1\",\n\t\t\ttarget:            \"1.7.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.3\",\n\t\t\ttarget:            \"1.7.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.0-rc.0\",\n\t\t\ttarget:            \"1.7.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.31.0-alpha.0\",\n\t\t\ttarget:            \"1.7.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.31.0-alpha.0 is too new to be used with Talos 1.7.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.24.1\",\n\t\t\ttarget:            \"1.7.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.24.1 is too old to be used with Talos 1.7.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility18(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.1\",\n\t\t\ttarget:            \"1.8.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.1\",\n\t\t\ttarget:            \"1.8.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.3\",\n\t\t\ttarget:            \"1.8.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.31.0-rc.0\",\n\t\t\ttarget:            \"1.8.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.32.0-alpha.0\",\n\t\t\ttarget:            \"1.8.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.32.0-alpha.0 is too new to be used with Talos 1.8.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.1\",\n\t\t\ttarget:            \"1.8.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.25.1 is too old to be used with Talos 1.8.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility19(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.1\",\n\t\t\ttarget:            \"1.9.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.1\",\n\t\t\ttarget:            \"1.9.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.31.3\",\n\t\t\ttarget:            \"1.9.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.32.0-rc.0\",\n\t\t\ttarget:            \"1.9.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.33.0-alpha.0\",\n\t\t\ttarget:            \"1.9.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.33.0-alpha.0 is too new to be used with Talos 1.9.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.26.1\",\n\t\t\ttarget:            \"1.9.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.26.1 is too old to be used with Talos 1.9.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility110(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.29.1\",\n\t\t\ttarget:            \"1.10.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.1\",\n\t\t\ttarget:            \"1.10.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.32.3\",\n\t\t\ttarget:            \"1.10.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.33.0-rc.0\",\n\t\t\ttarget:            \"1.10.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.34.0-alpha.0\",\n\t\t\ttarget:            \"1.10.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.34.0-alpha.0 is too new to be used with Talos 1.10.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.27.1\",\n\t\t\ttarget:            \"1.10.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.27.1 is too old to be used with Talos 1.10.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility111(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.1\",\n\t\t\ttarget:            \"1.11.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.29.1\",\n\t\t\ttarget:            \"1.11.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.33.3\",\n\t\t\ttarget:            \"1.11.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.34.0-rc.0\",\n\t\t\ttarget:            \"1.11.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.35.0-alpha.0\",\n\t\t\ttarget:            \"1.11.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.35.0-alpha.0 is too new to be used with Talos 1.11.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.28.1\",\n\t\t\ttarget:            \"1.11.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.28.1 is too old to be used with Talos 1.11.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility112(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.31.1\",\n\t\t\ttarget:            \"1.12.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.1\",\n\t\t\ttarget:            \"1.12.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.34.3\",\n\t\t\ttarget:            \"1.12.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.35.0-rc.0\",\n\t\t\ttarget:            \"1.12.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.36.0-alpha.0\",\n\t\t\ttarget:            \"1.12.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.36.0-alpha.0 is too new to be used with Talos 1.12.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.29.1\",\n\t\t\ttarget:            \"1.12.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.29.1 is too old to be used with Talos 1.12.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibility113(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.31.1\",\n\t\t\ttarget:            \"1.13.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.32.1\",\n\t\t\ttarget:            \"1.13.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.35.3\",\n\t\t\ttarget:            \"1.13.0-beta.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.36.0-rc.0\",\n\t\t\ttarget:            \"1.13.7\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.37.0-alpha.0\",\n\t\t\ttarget:            \"1.13.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.37.0-alpha.0 is too new to be used with Talos 1.13.0\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.30.1\",\n\t\t\ttarget:            \"1.13.0\",\n\t\t\texpectedError:     \"version of Kubernetes 1.30.1 is too old to be used with Talos 1.13.0\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n\nfunc TestKubernetesCompatibilityUnsupported(t *testing.T) {\n\tfor _, tt := range []kubernetesVersionTest{\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.0\",\n\t\t\ttarget:            \"1.14.0-alpha.0\",\n\t\t\texpectedError:     \"compatibility with version 1.14.0-alpha.0 is not supported\",\n\t\t},\n\t\t{\n\t\t\tkubernetesVersion: \"1.25.0\",\n\t\t\ttarget:            \"1.1.0\",\n\t\t\texpectedError:     \"compatibility with version 1.1.0 is not supported\",\n\t\t},\n\t} {\n\t\trunKubernetesVersionTest(t, tt)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos110/talos110.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos110 provides compatibility constants for Talos 1.10.\npackage talos110\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.10.\nvar MajorMinor = [2]uint64{1, 10}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.10.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.8.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.10.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.12.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.10.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.10.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.28.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.10.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.33.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos111/talos111.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos111 provides compatibility constants for Talos 1.11.\npackage talos111\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.11.\nvar MajorMinor = [2]uint64{1, 11}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.11.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.9.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.11.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.13.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.11.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.11.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.29.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.11.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.34.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos112/talos112.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos112 provides compatibility constants for Talos 1.12.\npackage talos112\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.12.\nvar MajorMinor = [2]uint64{1, 12}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.12.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.10.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.12.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.14.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.12.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.12.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.30.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.12.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.35.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos113/talos113.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos113 provides compatibility constants for Talos 1.13.\npackage talos113\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.13.\nvar MajorMinor = [2]uint64{1, 13}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.13.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.11.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.13.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.15.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.13.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.13.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.31.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.13.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.36.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos12/talos12.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos12 provides compatibility constants for Talos 1.2.\npackage talos12\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.2.\nvar MajorMinor = [2]uint64{1, 2}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.2.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.0.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.3.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.3.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.2.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.2.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.23.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.2.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.25.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos13/talos13.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos13 provides compatibility constants for Talos 1.3.\npackage talos13\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.3.\nvar MajorMinor = [2]uint64{1, 3}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.3.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.0.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.3.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.5.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.3.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.3.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.24.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.3.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.26.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos14/talos14.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos14 provides compatibility constants for Talos 1.4\npackage talos14\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.4.\nvar MajorMinor = [2]uint64{1, 4}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.4.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.0.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.4.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.6.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.4.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.4.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.25.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.4.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.27.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos15/talos15.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos15 provides compatibility constants for Talos 1.5.\npackage talos15\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.5.\nvar MajorMinor = [2]uint64{1, 5}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.5.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.2.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.5.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.7.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.5.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.5.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.26.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.5.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.28.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos16/talos16.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos16 provides compatibility constants for Talos 1.6.\npackage talos16\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.6.\nvar MajorMinor = [2]uint64{1, 6}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.6.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.3.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.6.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.8.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.6.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.6.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.24.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.6.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.29.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos17/talos17.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos17 provides compatibility constants for Talos 1.7.\npackage talos17\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.7.\nvar MajorMinor = [2]uint64{1, 7}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.7.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.4.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.7.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.9.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.7.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.7.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.25.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.7.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.30.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos18/talos18.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos18 provides compatibility constants for Talos 1.8.\npackage talos18\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.8.\nvar MajorMinor = [2]uint64{1, 8}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.8.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.5.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.8.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.10.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.8.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.8.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.26.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.8.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.31.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos19/talos19.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos19 provides compatibility constants for Talos 1.9.\npackage talos19\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// MajorMinor is the major.minor version of Talos 1.9.\nvar MajorMinor = [2]uint64{1, 9}\n\n// MinimumHostUpgradeVersion is the minimum version of Talos that can be upgraded to 1.9.\nvar MinimumHostUpgradeVersion = semver.MustParse(\"1.8.0\")\n\n// MaximumHostDowngradeVersion is the maximum (not inclusive) version of Talos that can be downgraded to 1.9.\nvar MaximumHostDowngradeVersion = semver.MustParse(\"1.11.0\")\n\n// DeniedHostUpgradeVersions are the versions of Talos that cannot be upgraded to 1.9.\nvar DeniedHostUpgradeVersions []semver.Version\n\n// MinimumKubernetesVersion is the minimum version of Kubernetes is supported with 1.9.\nvar MinimumKubernetesVersion = semver.MustParse(\"1.27.0\")\n\n// MaximumKubernetesVersion is the maximum version of Kubernetes is supported with 1.9.\nvar MaximumKubernetesVersion = semver.MustParse(\"1.32.99\")\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos_version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage compatibility\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/pair/ordered\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos110\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos111\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos112\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos113\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos12\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos13\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos14\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos15\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos16\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos17\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos18\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility/talos19\"\n)\n\n// TalosVersion embeds Talos version.\ntype TalosVersion struct {\n\tversion    semver.Version\n\tmajorMinor [2]uint64\n}\n\n// ParseTalosVersion parses Talos version.\nfunc ParseTalosVersion(v *machine.VersionInfo) (*TalosVersion, error) {\n\tparsed, err := semver.ParseTolerant(v.Tag)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &TalosVersion{\n\t\tversion:    parsed,\n\t\tmajorMinor: [2]uint64{parsed.Major, parsed.Minor},\n\t}, nil\n}\n\nfunc (v *TalosVersion) String() string {\n\treturn v.version.String()\n}\n\n// DisablePredictableNetworkInterfaces returns true if predictable network interfaces should be disabled on upgrade.\nfunc (v *TalosVersion) DisablePredictableNetworkInterfaces() bool {\n\tif v.majorMinor[0] <= talos14.MajorMinor[0] && v.majorMinor[1] <= talos14.MajorMinor[1] {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// PrecreateStatePartition returns true if running an 1.8+ installer from a version before <=1.7.x.\n//\n// Host Talos needs STATE partition to save the machine configuration.\nfunc (v *TalosVersion) PrecreateStatePartition() bool {\n\tif v.majorMinor[0] <= talos17.MajorMinor[0] && v.majorMinor[1] <= talos17.MajorMinor[1] {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// UpgradeableFrom checks if the current version of Talos can be used as an upgrade for the given host version.\n//\n//nolint:gocyclo\nfunc (v *TalosVersion) UpgradeableFrom(host *TalosVersion) error {\n\tvar (\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion semver.Version\n\t\tdeniedHostUpgradeVersions                      []semver.Version\n\t)\n\n\tswitch v.majorMinor {\n\tcase talos12.MajorMinor: // upgrades to 1.2.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos12.MinimumHostUpgradeVersion, talos12.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos12.DeniedHostUpgradeVersions\n\tcase talos13.MajorMinor: // upgrades to 1.3.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos13.MinimumHostUpgradeVersion, talos13.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos13.DeniedHostUpgradeVersions\n\tcase talos14.MajorMinor: // upgrades to 1.4.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos14.MinimumHostUpgradeVersion, talos14.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos14.DeniedHostUpgradeVersions\n\tcase talos15.MajorMinor: // upgrades to 1.5.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos15.MinimumHostUpgradeVersion, talos15.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos15.DeniedHostUpgradeVersions\n\tcase talos16.MajorMinor: // upgrades to 1.6.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos16.MinimumHostUpgradeVersion, talos16.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos16.DeniedHostUpgradeVersions\n\tcase talos17.MajorMinor: // upgrades to 1.7.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos17.MinimumHostUpgradeVersion, talos17.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos17.DeniedHostUpgradeVersions\n\tcase talos18.MajorMinor: // upgrades to 1.8.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos18.MinimumHostUpgradeVersion, talos18.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos18.DeniedHostUpgradeVersions\n\tcase talos19.MajorMinor: // upgrades to 1.9.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos19.MinimumHostUpgradeVersion, talos19.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos19.DeniedHostUpgradeVersions\n\tcase talos110.MajorMinor: // upgrades to 1.10.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos110.MinimumHostUpgradeVersion, talos110.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos110.DeniedHostUpgradeVersions\n\tcase talos111.MajorMinor: // upgrades to 1.11.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos111.MinimumHostUpgradeVersion, talos111.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos111.DeniedHostUpgradeVersions\n\tcase talos112.MajorMinor: // upgrades to 1.12.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos112.MinimumHostUpgradeVersion, talos112.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos112.DeniedHostUpgradeVersions\n\tcase talos113.MajorMinor: // upgrades to 1.13.x\n\t\tminHostUpgradeVersion, maxHostDowngradeVersion = talos113.MinimumHostUpgradeVersion, talos113.MaximumHostDowngradeVersion\n\t\tdeniedHostUpgradeVersions = talos113.DeniedHostUpgradeVersions\n\tdefault:\n\t\treturn fmt.Errorf(\"upgrades to version %s are not supported\", v.version.String())\n\t}\n\n\thostCore := ordered.MakeTriple(host.majorMinor[0], host.majorMinor[1], host.version.Patch)\n\n\tminHostUpgradeVersionCore := ordered.MakeTriple(minHostUpgradeVersion.Major, minHostUpgradeVersion.Minor, minHostUpgradeVersion.Patch)\n\n\tif hostCore.LessThan(minHostUpgradeVersionCore) {\n\t\treturn fmt.Errorf(\"host version %s is too old to upgrade to Talos %s\", host.version.String(), v.version.String())\n\t}\n\n\tmaxHostDowngradeVersionCore := ordered.MakeTriple(maxHostDowngradeVersion.Major, maxHostDowngradeVersion.Minor, maxHostDowngradeVersion.Patch)\n\n\tif hostCore.Compare(maxHostDowngradeVersionCore) >= 0 {\n\t\treturn fmt.Errorf(\"host version %s is too new to downgrade to Talos %s\", host.version.String(), v.version.String())\n\t}\n\n\tif slices.ContainsFunc(deniedHostUpgradeVersions, host.version.EQ) {\n\t\treturn fmt.Errorf(\"host version %s is denied for upgrade to Talos %s\", host.version.String(), v.version.String())\n\t}\n\n\treturn nil\n}\n\n// SupportsSSAManifestSync returns true if the Talos version supports server side apply manifest sync.\nfunc (v *TalosVersion) SupportsSSAManifestSync() bool {\n\t// supported from Talos 1.13+\n\treturn v.majorMinor[0] > talos113.MajorMinor[0] || (v.majorMinor[0] == talos113.MajorMinor[0] && v.majorMinor[1] >= talos113.MajorMinor[1])\n}\n"
  },
  {
    "path": "pkg/machinery/compatibility/talos_version_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage compatibility_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n)\n\ntype talosVersionTest struct {\n\thost          string\n\ttarget        string\n\texpectedError string\n}\n\nfunc runTalosVersionTest(t *testing.T, tt talosVersionTest) {\n\tt.Run(tt.host+\" -> \"+tt.target, func(t *testing.T) {\n\t\thost, err := compatibility.ParseTalosVersion(&machine.VersionInfo{\n\t\t\tTag: tt.host,\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\ttarget, err := compatibility.ParseTalosVersion(&machine.VersionInfo{\n\t\t\tTag: tt.target,\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\terr = target.UpgradeableFrom(host)\n\t\tif tt.expectedError != \"\" {\n\t\t\trequire.EqualError(t, err, tt.expectedError)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n}\n\nfunc TestTalosUpgradeCompatibility13(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.2.0\",\n\t\t\ttarget: \"1.3.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.0.0-alpha.0\",\n\t\t\ttarget: \"1.3.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.2.0-alpha.0\",\n\t\t\ttarget: \"1.3.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.3.0\",\n\t\t\ttarget: \"1.3.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.3.0-beta.0\",\n\t\t\ttarget: \"1.3.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.4.5\",\n\t\t\ttarget: \"1.3.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"0.14.3\",\n\t\t\ttarget:        \"1.3.0\",\n\t\t\texpectedError: `host version 0.14.3 is too old to upgrade to Talos 1.3.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.5.0-alpha.0\",\n\t\t\ttarget:        \"1.3.0\",\n\t\t\texpectedError: `host version 1.5.0-alpha.0 is too new to downgrade to Talos 1.3.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility14(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.3.0\",\n\t\t\ttarget: \"1.4.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.0.0-alpha.0\",\n\t\t\ttarget: \"1.4.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.2.0-alpha.0\",\n\t\t\ttarget: \"1.4.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.4.0\",\n\t\t\ttarget: \"1.4.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.4.0-beta.0\",\n\t\t\ttarget: \"1.4.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.5.5\",\n\t\t\ttarget: \"1.4.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"0.14.3\",\n\t\t\ttarget:        \"1.4.0\",\n\t\t\texpectedError: `host version 0.14.3 is too old to upgrade to Talos 1.4.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.6.0-alpha.0\",\n\t\t\ttarget:        \"1.4.0\",\n\t\t\texpectedError: `host version 1.6.0-alpha.0 is too new to downgrade to Talos 1.4.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility15(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.3.0\",\n\t\t\ttarget: \"1.5.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.2.0-alpha.0\",\n\t\t\ttarget: \"1.5.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.2.0\",\n\t\t\ttarget: \"1.5.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.5.0\",\n\t\t\ttarget: \"1.5.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.5.0-beta.0\",\n\t\t\ttarget: \"1.5.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.6.5\",\n\t\t\ttarget: \"1.5.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.1.0\",\n\t\t\ttarget:        \"1.5.0\",\n\t\t\texpectedError: `host version 1.1.0 is too old to upgrade to Talos 1.5.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.7.0-alpha.0\",\n\t\t\ttarget:        \"1.5.0\",\n\t\t\texpectedError: `host version 1.7.0-alpha.0 is too new to downgrade to Talos 1.5.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility16(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.4.0\",\n\t\t\ttarget: \"1.6.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.3.0-alpha.0\",\n\t\t\ttarget: \"1.6.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.3.0\",\n\t\t\ttarget: \"1.6.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.6.0\",\n\t\t\ttarget: \"1.6.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.6.0-beta.0\",\n\t\t\ttarget: \"1.6.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.7.5\",\n\t\t\ttarget: \"1.6.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.2.0\",\n\t\t\ttarget:        \"1.6.0\",\n\t\t\texpectedError: `host version 1.2.0 is too old to upgrade to Talos 1.6.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.8.0-alpha.0\",\n\t\t\ttarget:        \"1.6.0\",\n\t\t\texpectedError: `host version 1.8.0-alpha.0 is too new to downgrade to Talos 1.6.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility17(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.5.0\",\n\t\t\ttarget: \"1.7.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.4.0-alpha.0\",\n\t\t\ttarget: \"1.7.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.4.0\",\n\t\t\ttarget: \"1.7.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.6.0\",\n\t\t\ttarget: \"1.7.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.6.0-beta.0\",\n\t\t\ttarget: \"1.7.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.8.5\",\n\t\t\ttarget: \"1.7.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.3.0\",\n\t\t\ttarget:        \"1.7.0\",\n\t\t\texpectedError: `host version 1.3.0 is too old to upgrade to Talos 1.7.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.9.0-alpha.0\",\n\t\t\ttarget:        \"1.7.0\",\n\t\t\texpectedError: `host version 1.9.0-alpha.0 is too new to downgrade to Talos 1.7.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility18(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.6.0\",\n\t\t\ttarget: \"1.8.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.5.0-alpha.0\",\n\t\t\ttarget: \"1.8.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.5.0\",\n\t\t\ttarget: \"1.8.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.7.0\",\n\t\t\ttarget: \"1.8.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.7.0-beta.0\",\n\t\t\ttarget: \"1.8.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.5\",\n\t\t\ttarget: \"1.8.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.4.0\",\n\t\t\ttarget:        \"1.8.0\",\n\t\t\texpectedError: `host version 1.4.0 is too old to upgrade to Talos 1.8.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.10.0-alpha.0\",\n\t\t\ttarget:        \"1.8.0\",\n\t\t\texpectedError: `host version 1.10.0-alpha.0 is too new to downgrade to Talos 1.8.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility19(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.8.0\",\n\t\t\ttarget: \"1.9.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.8.0-alpha.0\",\n\t\t\ttarget: \"1.9.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.8.0\",\n\t\t\ttarget: \"1.9.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.8.3\",\n\t\t\ttarget: \"1.9.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.0-beta.0\",\n\t\t\ttarget: \"1.9.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.5\",\n\t\t\ttarget: \"1.9.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.7.0\",\n\t\t\ttarget:        \"1.9.0\",\n\t\t\texpectedError: `host version 1.7.0 is too old to upgrade to Talos 1.9.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.11.0-alpha.0\",\n\t\t\ttarget:        \"1.9.0\",\n\t\t\texpectedError: `host version 1.11.0-alpha.0 is too new to downgrade to Talos 1.9.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility110(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.8.0\",\n\t\t\ttarget: \"1.10.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.0-alpha.0\",\n\t\t\ttarget: \"1.10.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.8.0\",\n\t\t\ttarget: \"1.10.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.3\",\n\t\t\ttarget: \"1.10.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.10.0-beta.0\",\n\t\t\ttarget: \"1.10.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.10.5\",\n\t\t\ttarget: \"1.10.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.7.0\",\n\t\t\ttarget:        \"1.10.0\",\n\t\t\texpectedError: `host version 1.7.0 is too old to upgrade to Talos 1.10.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.12.0-alpha.0\",\n\t\t\ttarget:        \"1.10.0\",\n\t\t\texpectedError: `host version 1.12.0-alpha.0 is too new to downgrade to Talos 1.10.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility111(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.9.0\",\n\t\t\ttarget: \"1.11.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.10.0-alpha.0\",\n\t\t\ttarget: \"1.11.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.9.0\",\n\t\t\ttarget: \"1.11.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.10.3\",\n\t\t\ttarget: \"1.11.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.11.0-beta.0\",\n\t\t\ttarget: \"1.11.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.11.5\",\n\t\t\ttarget: \"1.11.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.8.0\",\n\t\t\ttarget:        \"1.11.0\",\n\t\t\texpectedError: `host version 1.8.0 is too old to upgrade to Talos 1.11.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.14.0-alpha.0\",\n\t\t\ttarget:        \"1.12.0\",\n\t\t\texpectedError: `host version 1.14.0-alpha.0 is too new to downgrade to Talos 1.12.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility112(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.10.0\",\n\t\t\ttarget: \"1.12.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.11.0-alpha.0\",\n\t\t\ttarget: \"1.12.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.10.0\",\n\t\t\ttarget: \"1.12.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.11.3\",\n\t\t\ttarget: \"1.12.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.12.0-beta.0\",\n\t\t\ttarget: \"1.12.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.12.5\",\n\t\t\ttarget: \"1.12.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.9.0\",\n\t\t\ttarget:        \"1.12.0\",\n\t\t\texpectedError: `host version 1.9.0 is too old to upgrade to Talos 1.12.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.14.0-alpha.0\",\n\t\t\ttarget:        \"1.12.0\",\n\t\t\texpectedError: `host version 1.14.0-alpha.0 is too new to downgrade to Talos 1.12.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibility113(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:   \"1.11.0\",\n\t\t\ttarget: \"1.13.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.12.0-alpha.0\",\n\t\t\ttarget: \"1.13.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.11.0\",\n\t\t\ttarget: \"1.13.0-alpha.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.12.3\",\n\t\t\ttarget: \"1.13.1\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.13.0-beta.0\",\n\t\t\ttarget: \"1.13.0\",\n\t\t},\n\t\t{\n\t\t\thost:   \"1.13.5\",\n\t\t\ttarget: \"1.13.3\",\n\t\t},\n\t\t{\n\t\t\thost:          \"1.10.0\",\n\t\t\ttarget:        \"1.13.0\",\n\t\t\texpectedError: `host version 1.10.0 is too old to upgrade to Talos 1.13.0`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.15.0-alpha.0\",\n\t\t\ttarget:        \"1.13.0\",\n\t\t\texpectedError: `host version 1.15.0-alpha.0 is too new to downgrade to Talos 1.13.0`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestTalosUpgradeCompatibilityUnsupported(t *testing.T) {\n\tfor _, tt := range []talosVersionTest{\n\t\t{\n\t\t\thost:          \"1.5.0\",\n\t\t\ttarget:        \"1.15.0-alpha.0\",\n\t\t\texpectedError: `upgrades to version 1.15.0-alpha.0 are not supported`,\n\t\t},\n\t\t{\n\t\t\thost:          \"1.4.0\",\n\t\t\ttarget:        \"1.14.0-alpha.0\",\n\t\t\texpectedError: `upgrades to version 1.14.0-alpha.0 are not supported`,\n\t\t},\n\t} {\n\t\trunTalosVersionTest(t, tt)\n\t}\n}\n\nfunc TestDisablePredictableNetworkInterfaces(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\thost     string\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\thost:     \"1.3.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\thost:     \"1.4.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\thost:     \"1.5.0\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\thost:     \"1.6.0\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\thost:     \"1.7.0\",\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(tt.host, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\thost, err := compatibility.ParseTalosVersion(&machine.VersionInfo{\n\t\t\t\tTag: tt.host,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, host.DisablePredictableNetworkInterfaces())\n\t\t})\n\t}\n}\n\nfunc TestSupportsSSAManifestSync(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tversion  string\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tversion:  \"1.12.0\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.13.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.14.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"2.0.0\",\n\t\t\texpected: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.version, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tv, err := compatibility.ParseTalosVersion(&machine.VersionInfo{\n\t\t\t\tTag: tt.version,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, tt.expected, v.SupportsSSAManifestSync())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/bundle/bundle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package bundle provides a set of machine configuration files.\npackage bundle\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// Bundle defines a set of machine configuration files.\ntype Bundle struct {\n\tInitCfg         config.Provider\n\tControlPlaneCfg config.Provider\n\tWorkerCfg       config.Provider\n\tTalosCfg        *clientconfig.Config\n}\n\n// NewBundle returns a new bundle of configuration files.\n//\n//nolint:gocyclo,cyclop\nfunc NewBundle(opts ...Option) (*Bundle, error) {\n\toptions := DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tbundle := &Bundle{}\n\n\t// Configs already exist, we'll pull them in.\n\tif options.ExistingConfigs != \"\" {\n\t\tif options.InputOptions != nil {\n\t\t\treturn bundle, errors.New(\"both existing config path and input options specified\")\n\t\t}\n\n\t\t// Pull existing machine configs of each type\n\t\tfor _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {\n\t\t\tdata, err := os.ReadFile(filepath.Join(options.ExistingConfigs, strings.ToLower(configType.String())+\".yaml\"))\n\t\t\tif err != nil {\n\t\t\t\tif configType == machine.TypeInit && errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\treturn bundle, err\n\t\t\t}\n\n\t\t\tunmarshalledConfig, err := configloader.NewFromBytes(data)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tswitch configType {\n\t\t\tcase machine.TypeInit:\n\t\t\t\tbundle.InitCfg = unmarshalledConfig\n\t\t\tcase machine.TypeControlPlane:\n\t\t\t\tbundle.ControlPlaneCfg = unmarshalledConfig\n\t\t\tcase machine.TypeWorker:\n\t\t\t\tbundle.WorkerCfg = unmarshalledConfig\n\t\t\tcase machine.TypeUnknown:\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\tpanic(\"unreachable\")\n\t\t\t}\n\t\t}\n\n\t\tif err := bundle.applyPatches(options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Pull existing talosconfig\n\t\ttalosConfig, err := os.Open(filepath.Join(options.ExistingConfigs, \"talosconfig\"))\n\t\tif errors.Is(err, fs.ErrNotExist) { // talosconfig is optional\n\t\t\treturn bundle, nil\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn bundle, err\n\t\t}\n\n\t\tdefer talosConfig.Close() //nolint:errcheck\n\n\t\tif bundle.TalosCfg, err = clientconfig.ReadFrom(talosConfig); err != nil {\n\t\t\treturn bundle, err\n\t\t}\n\n\t\treturn bundle, nil\n\t}\n\n\t// Handle generating net-new configs\n\tif options.Verbose {\n\t\tfmt.Fprintln(os.Stderr, \"generating PKI and tokens\")\n\t}\n\n\tif options.InputOptions == nil {\n\t\treturn nil, errors.New(\"no WithInputOptions is defined\")\n\t}\n\n\tinput, err := generate.NewInput(\n\t\toptions.InputOptions.ClusterName,\n\t\toptions.InputOptions.Endpoint,\n\t\toptions.InputOptions.KubeVersion,\n\t\toptions.InputOptions.GenOptions...,\n\t)\n\tif err != nil {\n\t\treturn bundle, err\n\t}\n\n\tfor _, configType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {\n\t\tvar generatedConfig config.Provider\n\n\t\tgeneratedConfig, err = input.Config(configType)\n\t\tif err != nil {\n\t\t\treturn bundle, err\n\t\t}\n\n\t\tswitch configType {\n\t\tcase machine.TypeInit:\n\t\t\tbundle.InitCfg = generatedConfig\n\t\tcase machine.TypeControlPlane:\n\t\t\tbundle.ControlPlaneCfg = generatedConfig\n\t\tcase machine.TypeWorker:\n\t\t\tbundle.WorkerCfg = generatedConfig\n\t\tcase machine.TypeUnknown:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tpanic(\"unreachable\")\n\t\t}\n\t}\n\n\tif err = bundle.applyPatches(options); err != nil {\n\t\treturn nil, err\n\t}\n\n\tbundle.TalosCfg, err = input.Talosconfig()\n\tif err != nil {\n\t\treturn bundle, err\n\t}\n\n\treturn bundle, nil\n}\n\n// Init implements the ProviderBundle interface.\nfunc (bundle *Bundle) Init() config.Provider {\n\treturn bundle.InitCfg\n}\n\n// ControlPlane implements the ProviderBundle interface.\nfunc (bundle *Bundle) ControlPlane() config.Provider {\n\treturn bundle.ControlPlaneCfg\n}\n\n// Worker implements the ProviderBundle interface.\nfunc (bundle *Bundle) Worker() config.Provider {\n\treturn bundle.WorkerCfg\n}\n\n// TalosConfig implements the ProviderBundle interface.\nfunc (bundle *Bundle) TalosConfig() *clientconfig.Config {\n\treturn bundle.TalosCfg\n}\n\n// Write config files to output directory.\nfunc (bundle *Bundle) Write(outputDir string, commentsFlags encoder.CommentsFlags, types ...machine.Type) error {\n\tfor _, t := range types {\n\t\tname := strings.ToLower(t.String()) + \".yaml\"\n\t\tfullFilePath := filepath.Join(outputDir, name)\n\n\t\tbytes, err := bundle.Serialize(commentsFlags, t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = os.WriteFile(fullFilePath, bytes, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfmt.Fprintf(os.Stderr, \"created %s\\n\", fullFilePath)\n\t}\n\n\treturn nil\n}\n\n// Serialize returns the config for the provided machine type as bytes.\nfunc (bundle *Bundle) Serialize(commentsFlags encoder.CommentsFlags, machineType machine.Type) ([]byte, error) {\n\tswitch machineType {\n\tcase machine.TypeInit:\n\t\treturn bundle.Init().EncodeBytes(encoder.WithComments(commentsFlags))\n\tcase machine.TypeControlPlane:\n\t\treturn bundle.ControlPlane().EncodeBytes(encoder.WithComments(commentsFlags))\n\tcase machine.TypeWorker:\n\t\treturn bundle.Worker().EncodeBytes(encoder.WithComments(commentsFlags))\n\tcase machine.TypeUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unexpected machine type %v\", machineType)\n\t}\n}\n\n// ApplyPatches patches every config type with a patch.\nfunc (bundle *Bundle) ApplyPatches(patches []configpatcher.Patch, patchControlPlane, patchWorker bool) error {\n\tif len(patches) == 0 {\n\t\treturn nil\n\t}\n\n\tapply := func(in config.Provider) (config.Provider, error) {\n\t\tpatched, err := configpatcher.Apply(configpatcher.WithConfig(in), patches)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn patched.Config()\n\t}\n\n\tvar err error\n\n\tif patchControlPlane {\n\t\tbundle.InitCfg, err = apply(bundle.InitCfg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.ControlPlaneCfg, err = apply(bundle.ControlPlaneCfg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif patchWorker {\n\t\tbundle.WorkerCfg, err = apply(bundle.WorkerCfg)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (bundle *Bundle) applyPatches(options Options) error {\n\tif err := bundle.ApplyPatches(options.Patches, true, true); err != nil {\n\t\treturn fmt.Errorf(\"error patching configs: %w\", err)\n\t}\n\n\tif err := bundle.ApplyPatches(options.PatchesControlPlane, true, false); err != nil {\n\t\treturn fmt.Errorf(\"error patching control plane configs: %w\", err)\n\t}\n\n\tif err := bundle.ApplyPatches(options.PatchesWorker, false, true); err != nil {\n\t\treturn fmt.Errorf(\"error patching worker config: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/bundle/bundle_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage bundle_test\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\nfunc TestGenerateConfig(t *testing.T) {\n\tconfigBundleOpts := []bundle.Option{ //nolint:prealloc // this is a test\n\t\tbundle.WithInputOptions(\n\t\t\t&bundle.InputOptions{\n\t\t\t\tClusterName: \"test-cluster\",\n\t\t\t\tEndpoint:    \"https://127.0.0.1:6443\",\n\t\t\t\tKubeVersion: \"1.222.2\",\n\t\t\t},\n\t\t),\n\t}\n\n\tpatches, err := configpatcher.LoadPatches([]string{\"cluster:\\n  clusterName: foo\\n\"})\n\trequire.NoError(t, err)\n\n\tconfigBundleOpts = append(configBundleOpts, bundle.WithPatch(patches))\n\n\tconfigBundle, err := bundle.NewBundle(configBundleOpts...)\n\trequire.NoError(t, err)\n\n\ttempDir := t.TempDir()\n\n\trequire.NoError(t, configBundle.Write(tempDir, encoder.CommentsAll, machine.TypeControlPlane, machine.TypeWorker))\n\n\tfor _, machineType := range []machine.Type{machine.TypeControlPlane, machine.TypeWorker} {\n\t\tvar cfg config.Provider\n\n\t\tswitch machineType { //nolint:exhaustive\n\t\tcase machine.TypeControlPlane:\n\t\t\tcfg, err = configloader.NewFromFile(filepath.Join(tempDir, \"controlplane.yaml\"))\n\t\tcase machine.TypeWorker:\n\t\t\tcfg, err = configloader.NewFromFile(filepath.Join(tempDir, \"worker.yaml\"))\n\t\tdefault:\n\t\t\trequire.FailNow(t, \"unexpected machine type\")\n\t\t}\n\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, \"foo\", cfg.Cluster().Name())\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/bundle/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage bundle\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n)\n\n// Option controls config options specific to config bundle generation.\ntype Option func(o *Options) error\n\n// InputOptions holds necessary params for generating an input.\ntype InputOptions struct {\n\tClusterName string\n\tEndpoint    string\n\tKubeVersion string\n\tGenOptions  []generate.Option\n}\n\n// Options describes generate parameters.\ntype Options struct {\n\tExistingConfigs string // path to existing config files\n\tVerbose         bool   // whether to write any logs during generate\n\tInputOptions    *InputOptions\n\n\tPatches             []configpatcher.Patch\n\tPatchesControlPlane []configpatcher.Patch\n\tPatchesWorker       []configpatcher.Patch\n}\n\n// DefaultOptions returns default options.\nfunc DefaultOptions() Options {\n\treturn Options{\n\t\tVerbose: true,\n\t}\n}\n\n// WithExistingConfigs sets the path to existing config files.\nfunc WithExistingConfigs(configPath string) Option {\n\treturn func(o *Options) error {\n\t\to.ExistingConfigs = configPath\n\n\t\treturn nil\n\t}\n}\n\n// WithInputOptions allows passing in of various params for net-new input generation.\nfunc WithInputOptions(inputOpts *InputOptions) Option {\n\treturn func(o *Options) error {\n\t\to.InputOptions = inputOpts\n\n\t\treturn nil\n\t}\n}\n\n// WithVerbose allows setting verbose logging.\nfunc WithVerbose(verbose bool) Option {\n\treturn func(o *Options) error {\n\t\to.Verbose = verbose\n\n\t\treturn nil\n\t}\n}\n\n// WithPatch allows patching every config in a bundle with a patch.\nfunc WithPatch(patch []configpatcher.Patch) Option {\n\treturn func(o *Options) error {\n\t\to.Patches = append(o.Patches, patch...)\n\n\t\treturn nil\n\t}\n}\n\n// WithPatchControlPlane allows patching init and controlplane config in a bundle with a patch.\nfunc WithPatchControlPlane(patch []configpatcher.Patch) Option {\n\treturn func(o *Options) error {\n\t\to.PatchesControlPlane = append(o.PatchesControlPlane, patch...)\n\n\t\treturn nil\n\t}\n}\n\n// WithPatchWorker allows patching worker config in a bundle with a patch.\nfunc WithPatchWorker(patch []configpatcher.Patch) Option {\n\treturn func(o *Options) error {\n\t\to.PatchesWorker = append(o.PatchesWorker, patch...)\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// ClusterConfig defines the requirements for a config that pertains to cluster\n// related options.\n//\n//nolint:interfacebloat\ntype ClusterConfig interface {\n\tID() string\n\tName() string\n\tSecret() string\n\tAPIServer() APIServer\n\tControllerManager() ControllerManager\n\tProxy() Proxy\n\tScheduler() Scheduler\n\tEndpoint() *url.URL\n\tToken() Token\n\tCertSANs() []string\n\tIssuingCA() *x509.PEMEncodedCertificateAndKey\n\tAcceptedCAs() []*x509.PEMEncodedCertificate\n\tAggregatorCA() *x509.PEMEncodedCertificateAndKey\n\tServiceAccount() *x509.PEMEncodedKey\n\tAESCBCEncryptionSecret() string\n\tSecretboxEncryptionSecret() string\n\tEtcd() Etcd\n\tNetwork() ClusterNetwork\n\tLocalAPIServerPort() int\n\tCoreDNS() CoreDNS\n\t// ExternalCloudProvider returns external cloud provider settings.\n\tExternalCloudProvider() ExternalCloudProvider\n\tExtraManifestURLs() []string\n\tExtraManifestHeaderMap() map[string]string\n\tInlineManifests() []InlineManifest\n\tAdminKubeconfig() AdminKubeconfig\n\tScheduleOnControlPlanes() bool\n\tDiscovery() Discovery\n}\n\n// ClusterNetwork defines the requirements for a config that pertains to cluster\n// network options.\ntype ClusterNetwork interface {\n\tCNI() CNI\n\tPodCIDRs() []string\n\tServiceCIDRs() []string\n\tDNSDomain() string\n\t// APIServerIPs returns kube-apiserver IPs in the ServiceCIDR.\n\tAPIServerIPs() ([]netip.Addr, error)\n\t// DNSServiceIPs returns DNS service IPs in the ServiceCIDR.\n\tDNSServiceIPs() ([]netip.Addr, error)\n}\n\n// CNI defines the requirements for a config that pertains to Kubernetes\n// cni.\ntype CNI interface {\n\tName() string\n\tURLs() []string\n\tFlannel() FlannelCNI\n}\n\n// FlannelCNI defines the requirements for a config that pertains to configure Flannel.\ntype FlannelCNI interface {\n\tExtraArgs() []string\n\tKubeNetworkPoliciesEnabled() bool\n}\n\n// APIServer defines the requirements for a config that pertains to apiserver related\n// options.\ntype APIServer interface {\n\tImage() string\n\tExtraArgs() map[string][]string\n\tExtraVolumes() []VolumeMount\n\tEnv() Env\n\tAdmissionControl() []AdmissionPlugin\n\tAuditPolicy() map[string]any\n\tResources() Resources\n\tAuthorizationConfig() []AuthorizationConfigAuthorizer\n}\n\n// AdmissionPlugin defines the API server Admission Plugin configuration.\ntype AdmissionPlugin interface {\n\tName() string\n\tConfiguration() map[string]any\n}\n\n// AuthorizationConfigAuthorizer defines the API server Authorization Authorizer configuration.\ntype AuthorizationConfigAuthorizer interface {\n\tType() string\n\tName() string\n\tWebhook() map[string]any\n}\n\n// ControllerManager defines the requirements for a config that pertains to controller manager related\n// options.\ntype ControllerManager interface {\n\tImage() string\n\tExtraArgs() map[string][]string\n\tExtraVolumes() []VolumeMount\n\tEnv() Env\n\tResources() Resources\n}\n\n// Proxy defines the requirements for a config that pertains to the kube-proxy\n// options.\ntype Proxy interface {\n\tEnabled() bool\n\n\tImage() string\n\n\t// Mode indicates the proxy mode for kube-proxy.  By default, this is `iptables`.  Other options include `ipvs`.\n\tMode() string\n\n\t// ExtraArgs describe an additional set of arguments to be supplied to the execution of `kube-proxy`\n\tExtraArgs() map[string][]string\n}\n\n// Scheduler defines the requirements for a config that pertains to scheduler related\n// options.\ntype Scheduler interface {\n\tImage() string\n\tExtraArgs() map[string][]string\n\tExtraVolumes() []VolumeMount\n\tEnv() Env\n\tResources() Resources\n\tConfig() map[string]any\n}\n\n// Etcd defines the requirements for a config that pertains to etcd related\n// options.\ntype Etcd interface {\n\tImage() string\n\tCA() *x509.PEMEncodedCertificateAndKey\n\tExtraArgs() map[string][]string\n\tAdvertisedSubnets() []string\n\tListenSubnets() []string\n}\n\n// Token defines the requirements for a config that pertains to Kubernetes\n// bootstrap token.\ntype Token interface {\n\tID() string\n\tSecret() string\n}\n\n// CoreDNS defines the requirements for a config that pertains to CoreDNS\n// coredns options.\ntype CoreDNS interface {\n\tEnabled() bool\n\tImage() string\n}\n\n// ExternalCloudProvider defines settings for external cloud provider.\ntype ExternalCloudProvider interface {\n\t// Enabled returns true if external cloud provider is enabled.\n\tEnabled() bool\n\t// ManifestURLs returns external cloud provider manifest URLs if it is enabled.\n\tManifestURLs() []string\n}\n\n// AdminKubeconfig defines settings for admin kubeconfig.\ntype AdminKubeconfig interface {\n\tCommonName() string\n\tCertOrganization() string\n\tCertLifetime() time.Duration\n}\n\n// VolumeMount describes extra volume mount for the static pods.\ntype VolumeMount interface {\n\tName() string\n\tHostPath() string\n\tMountPath() string\n\tReadOnly() bool\n}\n\n// Resources describes memory/cpu requests/limits for static pods.\ntype Resources interface {\n\tCPURequests() string\n\tMemoryRequests() string\n\tCPULimits() string\n\tMemoryLimits() string\n}\n\n// InlineManifest describes inline manifest for the cluster boostrap.\ntype InlineManifest interface {\n\tName() string\n\tContents() string\n}\n\n// Discovery describes cluster membership discovery.\ntype Discovery interface {\n\tEnabled() bool\n\tRegistries() DiscoveryRegistries\n}\n\n// DiscoveryRegistries describes discovery methods.\ntype DiscoveryRegistries interface {\n\tKubernetes() KubernetesRegistry\n\tService() ServiceRegistry\n}\n\n// KubernetesRegistry describes Kubernetes discovery registry.\n//\n//nolint:iface\ntype KubernetesRegistry interface {\n\tEnabled() bool\n}\n\n// ServiceRegistry describes external service discovery registry.\ntype ServiceRegistry interface {\n\tEnabled() bool\n\tEndpoint() string\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package config provides interfaces to consume machine configuration values.\npackage config\n\n// Config defines the interface to access contents of the machine configuration.\ntype Config interface { //nolint:interfacebloat\n\t// old v1alpha1 interface (to be decomposed as we move to multi-doc)\n\tDebug() bool\n\tMachine() MachineConfig\n\tCluster() ClusterConfig\n\n\t// new multi-doc interfaces:\n\t//  - network\n\tSideroLink() SideroLinkConfig\n\tNetworkRules() NetworkRuleConfig\n\tKubespanConfig() KubespanConfig\n\tEthernetConfigs() []EthernetConfig\n\tRunDefaultDHCPOperators() bool\n\tNetworkStaticHostConfig() []NetworkStaticHostConfig\n\tNetworkHostnameConfig() NetworkHostnameConfig\n\tNetworkResolverConfig() NetworkResolverConfig\n\tNetworkTimeSyncConfig() NetworkTimeSyncConfig\n\tNetworkKubeSpanConfig() NetworkKubeSpanConfig\n\tNetworkCommonLinkConfigs() []NetworkCommonLinkConfig\n\tNetworkLinkAliasConfigs() []NetworkLinkAliasConfig\n\tNetworkDHCPConfigs() []NetworkDHCPConfig\n\tNetworkDHCPv4Configs() []NetworkDHCPv4Config\n\tNetworkDHCPv6Configs() []NetworkDHCPv6Config\n\tNetworkVirtualIPConfigs() []NetworkVirtualIPConfig\n\tNetworkProbeConfigs() []NetworkCommonProbeConfig\n\tNetworkBlackholeRouteConfigs() []NetworkBlackholeRouteConfig\n\tNetworkRoutingRuleConfigs() []NetworkRoutingRuleConfig\n\n\t// - block devices/storage:\n\tVolumes() VolumesConfig\n\tUserVolumeConfigs() []UserVolumeConfig\n\tRawVolumeConfigs() []RawVolumeConfig\n\tExistingVolumeConfigs() []ExistingVolumeConfig\n\tExternalVolumeConfigs() []ExternalVolumeConfig\n\tSwapVolumeConfigs() []SwapVolumeConfig\n\tZswapConfig() ZswapConfig\n\n\t// - cri:\n\tRegistryMirrorConfigs() map[string]RegistryMirrorConfig\n\tRegistryAuthConfigs() map[string]RegistryAuthConfig\n\tRegistryTLSConfigs() map[string]RegistryTLSConfig\n\n\t// - misc:\n\tExtensionServiceConfigs() []ExtensionServiceConfig\n\tRuntime() RuntimeConfig\n\tEnvironment() EnvironmentConfig\n\tTrustedRoots() TrustedRootsConfig\n\tPCIDriverRebindConfig() PCIDriverRebindConfig\n\tOOMConfig() OOMConfig\n\tImageVerificationConfig() ImageVerificationConfig\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// RegistryMirrorConfigDocument is registry mirror configuration document.\ntype RegistryMirrorConfigDocument interface {\n\tNamedDocument\n\tRegistryMirrorConfig\n}\n\n// RegistryAuthConfigDocument is registry authentication configuration document.\ntype RegistryAuthConfigDocument interface {\n\tNamedDocument\n\tRegistryAuthConfig\n}\n\n// RegistryTLSConfigDocument is registry TLS configuration document.\ntype RegistryTLSConfigDocument interface {\n\tNamedDocument\n\tRegistryTLSConfig\n}\n\n// RegistryMirrorConfig represents mirror configuration for a registry.\ntype RegistryMirrorConfig interface {\n\tEndpoints() []RegistryEndpointConfig\n\tSkipFallback() bool\n}\n\n// RegistryEndpointConfig represents a single registry endpoint.\ntype RegistryEndpointConfig interface {\n\tEndpoint() string\n\tOverridePath() bool\n}\n\n// RegistryAuthConfig specifies authentication configuration for a registry.\ntype RegistryAuthConfig interface {\n\tUsername() string\n\tPassword() string\n\tAuth() string\n\tIdentityToken() string\n}\n\n// RegistryTLSConfig specifies TLS config for HTTPS registries.\ntype RegistryTLSConfig interface {\n\tClientIdentity() *x509.PEMEncodedCertificateAndKey\n\tCA() []byte\n\tInsecureSkipVerify() bool\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/document.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\n// Document is a configuration document.\ntype Document interface {\n\t// Clone returns a deep copy of the document.\n\tClone() Document\n\t// Kind returns the kind of the document.\n\tKind() string\n\t// APIVersion returns the API version of the document.\n\tAPIVersion() string\n}\n\n// NamedDocument is a configuration document which has a name.\ntype NamedDocument interface {\n\t// Name of the document.\n\tName() string\n}\n\n// ConflictingDocument is a configuration document which conflicts with other document.\n//\n// If the document is named, it conflicts by name, otherwise it conflicts by kind.\ntype ConflictingDocument interface {\n\tConflictsWithKinds() []string\n}\n\n// SecretDocument is a configuration document that contains secrets.\ntype SecretDocument interface {\n\t// Redact does in-place replacement of secrets with the given string.\n\tRedact(replacement string)\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/encoder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport \"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\n// Encoder provides the interface to encode configuration documents.\ntype Encoder interface {\n\t// Bytes returns source YAML representation (if available) or does default encoding.\n\tBytes() ([]byte, error)\n\n\t// Encode configuration to YAML using the provided options.\n\tEncodeString(encoderOptions ...encoder.Option) (string, error)\n\tEncodeBytes(encoderOptions ...encoder.Option) ([]byte, error)\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/extension_service_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\n// ExtensionServiceConfig is a config for extension services.\ntype ExtensionServiceConfig interface {\n\tName() string\n\tConfigFiles() []ExtensionServiceConfigFile\n\tEnvironment() []string\n}\n\n// ExtensionServiceConfigFile is a config file for extension services.\ntype ExtensionServiceConfigFile interface {\n\tContent() string\n\tMountPath() string\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/helpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"iter\"\n\t\"maps\"\n)\n\nfunc findFirstValue[T any, R comparable](documents []T, getter func(T) R) R {\n\tvar zeroR R\n\n\tfor _, document := range documents {\n\t\tif value := getter(document); value != zeroR {\n\t\t\treturn value\n\t\t}\n\t}\n\n\treturn zeroR\n}\n\nfunc aggregateValues[T any, R any](documents []T, getter func(T) []R) []R {\n\tresult := make([]R, 0, len(documents))\n\n\tfor _, document := range documents {\n\t\tresult = append(result, getter(document)...)\n\t}\n\n\tif len(result) == 0 {\n\t\treturn nil\n\t}\n\n\treturn result\n}\n\nfunc mergeMaps[T any, K comparable, V any](documents []T, getter func(T) iter.Seq2[K, V]) map[K]V {\n\tresult := make(map[K]V)\n\n\tfor _, document := range documents {\n\t\tmaps.Insert(result, getter(document))\n\t}\n\n\treturn result\n}\n\nfunc filterDocuments[T any, R any](documents []R) []T {\n\tvar result []T\n\n\tfor _, document := range documents {\n\t\tif document, ok := any(document).(T); ok {\n\t\t\tresult = append(result, document)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/kubespan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport \"net/netip\"\n\n// KubespanConfig defines the interface to access KubeSpan configuration.\ntype KubespanConfig interface {\n\tExtraAnnouncedEndpoints() []netip.AddrPort\n}\n\n// WrapKubespanConfig wraps a list of KubespanConfig into a single KubespanConfig aggregating the results.\nfunc WrapKubespanConfig(configs ...KubespanConfig) KubespanConfig {\n\treturn kubespanConfigWrapper(configs)\n}\n\ntype kubespanConfigWrapper []KubespanConfig\n\nfunc (w kubespanConfigWrapper) ExtraAnnouncedEndpoints() []netip.AddrPort {\n\treturn aggregateValues(w, func(c KubespanConfig) []netip.AddrPort {\n\t\treturn c.ExtraAnnouncedEndpoints()\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/machine.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"net/url\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// MachineConfig defines the requirements for a config that pertains to machine\n// related options.\n//\n//nolint:interfacebloat\ntype MachineConfig interface {\n\tInstall() Install\n\tSecurity() Security\n\tNetwork() MachineNetwork\n\tDisks() []Disk\n\tEnv() Env\n\tFiles() ([]File, error)\n\tType() machine.Type\n\tControlplane() MachineControlPlane\n\tPods() []map[string]any\n\tKubelet() Kubelet\n\tSysctls() map[string]string\n\tSysfs() map[string]string\n\tSystemDiskEncryption() SystemDiskEncryption\n\tFeatures() Features\n\tUdev() UdevConfig\n\tLogging() Logging\n\tKernel() Kernel\n\tSeccompProfiles() []SeccompProfile\n\tNodeLabels() NodeLabels\n\tNodeAnnotations() NodeAnnotations\n\tNodeTaints() NodeTaints\n\tBaseRuntimeSpecOverrides() map[string]any\n}\n\n// SeccompProfile defines the requirements for a config that pertains to seccomp\n// related options.\ntype SeccompProfile interface {\n\tName() string\n\tValue() map[string]any\n}\n\n// NodeLabels defines the labels that should be set on a node.\ntype NodeLabels map[string]string\n\n// NodeAnnotations defines the annotations that should be set on a node.\ntype NodeAnnotations map[string]string\n\n// NodeTaints defines the taints that should be set on a node.\ntype NodeTaints map[string]string\n\n// Disk represents the options available for partitioning, formatting, and\n// mounting extra disks.\ntype Disk interface {\n\tDevice() string\n\tPartitions() []Partition\n}\n\n// Partition represents the options for a device partition.\ntype Partition interface {\n\tSize() uint64\n\tMountPoint() string\n}\n\n// Env represents a set of environment variables.\ntype Env = map[string]string\n\n// File represents a file to write to disk.\ntype File interface {\n\tContent() string\n\tPermissions() os.FileMode\n\tPath() string\n\tOp() string\n}\n\n// Install defines the requirements for a config that pertains to install\n// related options.\ntype Install interface {\n\tImage() string\n\tExtensions() []Extension\n\tDisk() string\n\tDiskMatchExpression() (*cel.Expression, error)\n\tExtraKernelArgs() []string\n\tZero() bool\n\tLegacyBIOSSupport() bool\n\tGrubUseUKICmdline() bool\n}\n\n// Extension defines the system extension.\ntype Extension interface {\n\tImage() string\n}\n\n// Security defines the requirements for a config that pertains to security\n// related options.\ntype Security interface {\n\tIssuingCA() *x509.PEMEncodedCertificateAndKey\n\tAcceptedCAs() []*x509.PEMEncodedCertificate\n\tToken() string\n\tCertSANs() []string\n}\n\n// MachineControlPlane defines the requirements for a config that pertains to Controlplane\n// related options.\ntype MachineControlPlane interface {\n\tControllerManager() MachineControllerManager\n\tScheduler() MachineScheduler\n}\n\n// MachineControllerManager defines the requirements for a config that pertains to ControllerManager\n// related options.\n//\n//nolint:iface\ntype MachineControllerManager interface {\n\tDisabled() bool\n}\n\n// MachineScheduler defines the requirements for a config that pertains to Scheduler\n// related options.\n//\n//nolint:iface\ntype MachineScheduler interface {\n\tDisabled() bool\n}\n\n// MachineNetwork defines the requirements for a config that pertains to network\n// related options.\n//\n// This is a legacy interface which is going to be decomposed and removed in the future.\ntype MachineNetwork interface {\n\tDevices() []Device\n}\n\n// Device represents a network interface.\n//\n//nolint:interfacebloat\ntype Device interface {\n\tInterface() string\n\tAddresses() []string\n\tRoutes() []Route\n\tBond() Bond\n\tBridge() Bridge\n\tBridgePort() BridgePort\n\tVlans() []Vlan\n\tMTU() int\n\tDHCP() bool\n\tIgnore() bool\n\tDummy() bool\n\tDHCPOptions() DHCPOptions\n\tVIPConfig() VIPConfig\n\tWireguardConfig() WireguardConfig\n\tSelector() NetworkDeviceSelector\n}\n\n// DHCPOptions represents a set of DHCP options.\ntype DHCPOptions interface {\n\tRouteMetric() uint32\n\tIPv4() bool\n\tIPv6() bool\n\tDUIDv6() string\n}\n\n// VIPConfig contains settings for the Virtual (shared) IP setup.\ntype VIPConfig interface {\n\tIP() string\n\tEquinixMetal() VIPEquinixMetal\n\tHCloud() VIPHCloud\n}\n\n// VIPEquinixMetal contains Equinix Metal API VIP settings.\n//\n//nolint:iface\ntype VIPEquinixMetal interface {\n\tAPIToken() string\n}\n\n// VIPHCloud contains Hetzner Cloud API VIP settings.\n//\n//nolint:iface\ntype VIPHCloud interface {\n\tAPIToken() string\n}\n\n// WireguardConfig contains settings for configuring Wireguard network interface.\ntype WireguardConfig interface {\n\tPrivateKey() string\n\tListenPort() int\n\tFirewallMark() int\n\tPeers() []WireguardPeer\n}\n\n// WireguardPeer a WireGuard device peer configuration.\ntype WireguardPeer interface {\n\tPublicKey() string\n\tEndpoint() string\n\tPersistentKeepaliveInterval() time.Duration\n\tAllowedIPs() []string\n}\n\n// Bond contains the various options for configuring a\n// bonded interface.\n//\n//nolint:interfacebloat\ntype Bond interface {\n\tInterfaces() []string\n\tSelectors() []NetworkDeviceSelector\n\tARPIPTarget() []string\n\tMode() string\n\tHashPolicy() string\n\tLACPRate() string\n\tADActorSystem() string\n\tARPValidate() string\n\tARPAllTargets() string\n\tPrimary() string\n\tPrimaryReselect() string\n\tFailOverMac() string\n\tADSelect() string\n\tMIIMon() uint32\n\tUpDelay() uint32\n\tDownDelay() uint32\n\tARPInterval() uint32\n\tResendIGMP() uint32\n\tMinLinks() uint32\n\tLPInterval() uint32\n\tPacketsPerSlave() uint32\n\tNumPeerNotif() uint8\n\tTLBDynamicLB() uint8\n\tAllSlavesActive() uint8\n\tUseCarrier() bool\n\tADActorSysPrio() uint16\n\tADUserPortKey() uint16\n\tPeerNotifyDelay() uint32\n}\n\n// STP contains the Spanning Tree Protocol settings for a bridge.\n//\n//nolint:iface\ntype STP interface {\n\tEnabled() bool\n}\n\n// BridgeVLAN contains the VLAN settings for a bridge.\ntype BridgeVLAN interface {\n\tFilteringEnabled() bool\n}\n\n// Bridge contains the options for configuring a bridged interface.\ntype Bridge interface {\n\tInterfaces() []string\n\tSTP() STP\n\tVLAN() BridgeVLAN\n}\n\n// BridgePort contains the options for a bridge port.\ntype BridgePort interface {\n\tMaster() string\n}\n\n// Vlan represents vlan settings for a device.\ntype Vlan interface {\n\tAddresses() []string\n\tRoutes() []Route\n\tDHCP() bool\n\tID() uint16\n\tMTU() uint32\n\tMode() nethelpers.VLANProtocol\n\tVIPConfig() VIPConfig\n\tDHCPOptions() DHCPOptions\n}\n\n// Route represents a network route.\ntype Route interface {\n\tNetwork() string\n\tGateway() string\n\tSource() string\n\tMetric() uint32\n\tMTU() uint32\n}\n\n// NetworkDeviceSelector defines the set of fields that can be used to pick network a device.\ntype NetworkDeviceSelector interface {\n\tBus() string\n\tHardwareAddress() string\n\tPermanentAddress() string\n\tPCIID() string\n\tKernelDriver() string\n\tPhysical() *bool\n}\n\n// Kubelet defines the requirements for a config that pertains to kubelet\n// related options.\n//\n//nolint:interfacebloat\ntype Kubelet interface {\n\tImage() string\n\tClusterDNS() []string\n\tExtraArgs() map[string][]string\n\tExtraMounts() []specs.Mount\n\tExtraConfig() map[string]any\n\tCredentialProviderConfig() map[string]any\n\tDefaultRuntimeSeccompProfileEnabled() bool\n\tRegisterWithFQDN() bool\n\tNodeIP() KubeletNodeIP\n\tSkipNodeRegistration() bool\n\tDisableManifestsDirectory() bool\n}\n\n// KubeletNodeIP defines the way node IPs are selected for the kubelet.\ntype KubeletNodeIP interface {\n\tValidSubnets() []string\n}\n\n// EncryptionKey defines settings for the partition encryption key handling.\ntype EncryptionKey interface {\n\tStatic() EncryptionKeyStatic\n\tNodeID() EncryptionKeyNodeID\n\tKMS() EncryptionKeyKMS\n\tSlot() int\n\tTPM() EncryptionKeyTPM\n\tLockToSTATE() bool\n}\n\n// EncryptionKeyStatic ephemeral encryption key.\ntype EncryptionKeyStatic interface {\n\tKey() []byte\n\tString() string\n}\n\n// EncryptionKeyKMS encryption key sealed by KMS.\ntype EncryptionKeyKMS interface {\n\tEndpoint() string\n\tString() string\n}\n\n// EncryptionKeyNodeID deterministically generated encryption key.\ntype EncryptionKeyNodeID interface {\n\tString() string\n}\n\n// EncryptionKeyTPM encryption key sealed by TPM.\ntype EncryptionKeyTPM interface {\n\tCheckSecurebootOnEnroll() bool\n\tPCRs() []int\n\tPubKeyPCRs() []int\n\tString() string\n}\n\n// EncryptionConfig defines settings for the partition encryption.\ntype EncryptionConfig interface {\n\tProvider() block.EncryptionProviderType\n\tCipher() string\n\tKeySize() uint\n\tBlockSize() uint64\n\tOptions() []string\n\tKeys() []EncryptionKey\n}\n\n// SystemDiskEncryption accumulates settings for all system partitions encryption.\ntype SystemDiskEncryption interface {\n\tGet(label string) EncryptionConfig\n}\n\n// Features describe individual Talos features that can be switched on or off.\ntype Features interface {\n\tKubernetesTalosAPIAccess() KubernetesTalosAPIAccess\n\tDiskQuotaSupportEnabled() bool\n\tHostDNS() HostDNS\n\tKubePrism() KubePrism\n\tImageCache() ImageCache\n\tNodeAddressSortAlgorithm() nethelpers.AddressSortAlgorithm\n}\n\n// KubernetesTalosAPIAccess describes the Kubernetes Talos API access features.\ntype KubernetesTalosAPIAccess interface {\n\tEnabled() bool\n\tAllowedRoles() []string\n\tAllowedKubernetesNamespaces() []string\n}\n\n// KubePrism describes the API Server load balancer features.\ntype KubePrism interface {\n\tEnabled() bool\n\tPort() int\n}\n\n// HostDNS describes the host DNS configuration.\ntype HostDNS interface {\n\tEnabled() bool\n\tForwardKubeDNSToHost() bool\n\tResolveMemberNames() bool\n}\n\n// ImageCache describes the image cache configuration.\ntype ImageCache interface {\n\tLocalEnabled() bool\n}\n\n// UdevConfig describes configuration for udev.\ntype UdevConfig interface {\n\tRules() []string\n}\n\n// Logging describes logging configuration.\ntype Logging interface {\n\tDestinations() []LoggingDestination\n}\n\n// LoggingDestination describes logging destination.\ntype LoggingDestination interface {\n\tEndpoint() *url.URL\n\tExtraTags() map[string]string\n\tFormat() string\n}\n\n// Kernel describes Talos Linux kernel configuration.\ntype Kernel interface {\n\tModules() []KernelModule\n}\n\n// KernelModule describes Linux module to load.\ntype KernelModule interface {\n\tName() string\n\tParameters() []string\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// NetworkRuleConfig defines the interface to access network firewall configuration.\ntype NetworkRuleConfig interface {\n\tNetworkRuleConfigRules\n\tNetworkRuleConfigDefaultAction\n}\n\n// NetworkRuleConfigRules defines the interface to access network firewall configuration.\ntype NetworkRuleConfigRules interface {\n\tRules() []NetworkRule\n}\n\n// NetworkRuleConfigDefaultAction defines the interface to access network firewall configuration.\ntype NetworkRuleConfigDefaultAction interface {\n\tDefaultAction() nethelpers.DefaultAction\n}\n\n// NetworkRuleConfigSignal is used to signal documents which implement either of the NetworkRuleConfig interfaces.\ntype NetworkRuleConfigSignal interface {\n\tNetworkRuleConfigSignal()\n}\n\n// NetworkRule defines a network firewall rule.\ntype NetworkRule interface {\n\tProtocol() nethelpers.Protocol\n\tPortRanges() [][2]uint16\n\tSubnets() []netip.Prefix\n\tExceptSubnets() []netip.Prefix\n}\n\n// WrapNetworkRuleConfigList wraps a list of NetworkConfig into a single NetworkConfig aggregating the results.\nfunc WrapNetworkRuleConfigList(configs ...NetworkRuleConfigSignal) NetworkRuleConfig {\n\treturn networkRuleConfigWrapper(configs)\n}\n\ntype networkRuleConfigWrapper []NetworkRuleConfigSignal\n\nfunc (w networkRuleConfigWrapper) DefaultAction() nethelpers.DefaultAction {\n\t// DefaultAction zero value is 'accept' which is the default config value as well.\n\treturn findFirstValue(\n\t\tfilterDocuments[NetworkRuleConfigDefaultAction](w),\n\t\tfunc(c NetworkRuleConfigDefaultAction) nethelpers.DefaultAction {\n\t\t\treturn c.DefaultAction()\n\t\t},\n\t)\n}\n\nfunc (w networkRuleConfigWrapper) Rules() []NetworkRule {\n\treturn aggregateValues(\n\t\tfilterDocuments[NetworkRuleConfigRules](w),\n\t\tfunc(c NetworkRuleConfigRules) []NetworkRule {\n\t\t\treturn c.Rules()\n\t\t},\n\t)\n}\n\n// EthernetConfig defines a network interface configuration.\ntype EthernetConfig interface {\n\tNamedDocument\n\tRings() EthernetRingsConfig\n\tChannels() EthernetChannelsConfig\n\tFeatures() map[string]bool\n\tWakeOnLAN() []nethelpers.WOLMode\n}\n\n// EthernetRingsConfig defines a configuration for Ethernet link rings.\ntype EthernetRingsConfig struct {\n\tRX           *uint32\n\tTX           *uint32\n\tRXMini       *uint32\n\tRXJumbo      *uint32\n\tRXBufLen     *uint32\n\tCQESize      *uint32\n\tTXPush       *bool\n\tRXPush       *bool\n\tTXPushBufLen *uint32\n\tTCPDataSplit *bool\n}\n\n// EthernetChannelsConfig defines a configuration for Ethernet link channels.\ntype EthernetChannelsConfig struct {\n\tRX       *uint32\n\tTX       *uint32\n\tOther    *uint32\n\tCombined *uint32\n}\n\n// NetworkStaticHostConfig defines a static host configuration.\ntype NetworkStaticHostConfig interface {\n\tIP() string\n\tAliases() []string\n}\n\n// NetworkHostnameConfig defines a hostname configuration.\ntype NetworkHostnameConfig interface {\n\tHostname() string\n\tAutoHostname() nethelpers.AutoHostnameKind\n}\n\n// NetworkResolverConfig defines a resolver configuration.\ntype NetworkResolverConfig interface {\n\tResolvers() []netip.Addr\n\tSearchDomains() []string\n\tDisableSearchDomain() bool\n}\n\n// NetworkTimeSyncConfig defines the requirements for a config that pertains to time related\n// options.\ntype NetworkTimeSyncConfig interface {\n\tDisabled() bool\n\tServers() []string\n\tBootTimeout() time.Duration\n}\n\n// NetworkPhysicalLinkConfig defines a physical network link configuration.\ntype NetworkPhysicalLinkConfig interface {\n\tPhysicalLinkConfig()\n\tNetworkCommonLinkConfig\n}\n\n// NetworkDummyLinkConfig defines a dummy network link configuration.\ntype NetworkDummyLinkConfig interface {\n\tDummyLinkConfig()\n\tNetworkHardwareAddressConfig\n\tNetworkCommonLinkConfig\n}\n\n// NetworkHardwareAddressConfig defines a hardware (MAC) address configuration.\ntype NetworkHardwareAddressConfig interface {\n\tHardwareAddress() optional.Optional[nethelpers.HardwareAddr]\n}\n\n// NetworkCommonLinkConfig defines common configuration for network links.\ntype NetworkCommonLinkConfig interface {\n\tNamedDocument\n\tUp() optional.Optional[bool]\n\tMTU() optional.Optional[uint32]\n\tAddresses() []NetworkAddressConfig\n\tRoutes() []NetworkRouteConfig\n\tMulticast() optional.Optional[bool]\n}\n\n// NetworkAddressConfig defines a network address configuration.\ntype NetworkAddressConfig interface {\n\tAddress() netip.Prefix\n\tRoutePriority() optional.Optional[uint32]\n}\n\n// NetworkRouteConfig defines a network route configuration.\ntype NetworkRouteConfig interface {\n\tDestination() optional.Optional[netip.Prefix]\n\tGateway() optional.Optional[netip.Addr]\n\tSource() optional.Optional[netip.Addr]\n\tMTU() optional.Optional[uint32]\n\tMetric() optional.Optional[uint32]\n\tTable() optional.Optional[nethelpers.RoutingTable]\n}\n\n// NetworkLinkAliasConfig defines a network link alias configuration.\ntype NetworkLinkAliasConfig interface {\n\tNamedDocument\n\tLinkSelector() cel.Expression\n\tIsPatternAlias() bool\n}\n\n// NetworkDHCPConfig defines a DHCP configuration for a network link.\ntype NetworkDHCPConfig interface {\n\tNamedDocument\n\tNetworkDHCPConfig()\n}\n\n// NetworkDHCPv4Config defines a DHCPv4 configuration for a network link.\ntype NetworkDHCPv4Config interface {\n\tNamedDocument\n\tNetworkDHCPConfig\n\tNetworkDHCPv4Config() // signal method\n\tRouteMetric() optional.Optional[uint32]\n\tIgnoreHostname() optional.Optional[bool]\n\tClientIdentifier() nethelpers.ClientIdentifier\n\tDUIDRaw() optional.Optional[nethelpers.HardwareAddr]\n}\n\n// NetworkDHCPv6Config defines a DHCPv6 configuration for a network link.\ntype NetworkDHCPv6Config interface {\n\tNamedDocument\n\tNetworkDHCPConfig\n\tNetworkDHCPv6Config() // signal method\n\tRouteMetric() optional.Optional[uint32]\n\tIgnoreHostname() optional.Optional[bool]\n\tClientIdentifier() nethelpers.ClientIdentifier\n\tDUIDRaw() optional.Optional[nethelpers.HardwareAddr]\n}\n\n// NetworkVirtualIPConfig defines a common virtual IP configuration.\n//\n//nolint:iface\ntype NetworkVirtualIPConfig interface {\n\tNamedDocument\n\tLink() string\n\tVIP() netip.Addr\n}\n\n// NetworkLayer2VIPConfig defines a Layer 2 VIP configuration.\n//\n//nolint:iface\ntype NetworkLayer2VIPConfig interface {\n\tNetworkVirtualIPConfig\n}\n\n// NetworkHCloudVIPConfig defines a Hetzner Cloud VIP configuration.\ntype NetworkHCloudVIPConfig interface {\n\tNetworkVirtualIPConfig\n\tHCloudAPIToken() string\n}\n\n// NetworkVLANConfig defines a VLAN link configuration.\ntype NetworkVLANConfig interface {\n\tNamedDocument\n\tNetworkCommonLinkConfig\n\tVLANConfig()\n\tVLANID() uint16\n\tParentLink() string\n\tVLANMode() optional.Optional[nethelpers.VLANProtocol]\n}\n\n// NetworkBondConfig defines a bond link configuration.\n//\n//nolint:interfacebloat\ntype NetworkBondConfig interface {\n\tNamedDocument\n\tNetworkCommonLinkConfig\n\tNetworkHardwareAddressConfig\n\tBondConfig()\n\tLinks() []string\n\tMode() nethelpers.BondMode\n\tMIIMon() optional.Optional[uint32]\n\tUpDelay() optional.Optional[uint32]\n\tDownDelay() optional.Optional[uint32]\n\tUseCarrier() optional.Optional[bool]\n\tXmitHashPolicy() optional.Optional[nethelpers.BondXmitHashPolicy]\n\tARPInterval() optional.Optional[uint32]\n\tARPIPTargets() []netip.Addr\n\tNSIP6Targets() []netip.Addr\n\tARPValidate() optional.Optional[nethelpers.ARPValidate]\n\tARPAllTargets() optional.Optional[nethelpers.ARPAllTargets]\n\tLACPRate() optional.Optional[nethelpers.LACPRate]\n\tFailOverMAC() optional.Optional[nethelpers.FailOverMAC]\n\tADSelect() optional.Optional[nethelpers.ADSelect]\n\tADActorSysPrio() optional.Optional[uint16]\n\tADUserPortKey() optional.Optional[uint16]\n\tADLACPActive() optional.Optional[nethelpers.ADLACPActive]\n\tPrimaryReselect() optional.Optional[nethelpers.PrimaryReselect]\n\tResendIGMP() optional.Optional[uint32]\n\tMinLinks() optional.Optional[uint32]\n\tLPInterval() optional.Optional[uint32]\n\tPacketsPerSlave() optional.Optional[uint32]\n\tNumPeerNotif() optional.Optional[uint8]\n\tTLBDynamicLB() optional.Optional[uint8]\n\tAllSlavesActive() optional.Optional[uint8]\n\tPeerNotifyDelay() optional.Optional[uint32]\n\tMissedMax() optional.Optional[uint8]\n}\n\n// NetworkBridgeConfig defines a bridge link configuration.\ntype NetworkBridgeConfig interface {\n\tNamedDocument\n\tNetworkCommonLinkConfig\n\tNetworkHardwareAddressConfig\n\tBridgeConfig()\n\tLinks() []string\n\tSTP() BridgeSTPConfig\n\tVLAN() BridgeVLANConfig\n}\n\n// BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\ntype BridgeSTPConfig interface {\n\tEnabled() optional.Optional[bool]\n}\n\n// BridgeVLANConfig is a bridge VLAN configuration.\ntype BridgeVLANConfig interface {\n\tFilteringEnabled() optional.Optional[bool]\n}\n\n// NetworkVRFConfig defines a vrf link configuration.\ntype NetworkVRFConfig interface {\n\tNamedDocument\n\tNetworkCommonLinkConfig\n\tNetworkHardwareAddressConfig\n\tVRFConfig()\n\tLinks() []string\n\tTable() nethelpers.RoutingTable\n}\n\n// NetworkWireguardConfig defines a Wireguard link configuration.\ntype NetworkWireguardConfig interface {\n\tNamedDocument\n\tNetworkCommonLinkConfig\n\tWireguardConfig()\n\tPrivateKey() string\n\tListenPort() optional.Optional[int]\n\tFirewallMark() optional.Optional[int]\n\tPeers() []NetworkWireguardPeerConfig\n}\n\n// NetworkWireguardPeerConfig defines a Wireguard peer configuration.\ntype NetworkWireguardPeerConfig interface {\n\tPublicKey() string\n\tPresharedKey() optional.Optional[string]\n\tEndpoint() optional.Optional[string]\n\tAllowedIPs() []netip.Prefix\n\tPersistentKeepalive() optional.Optional[time.Duration]\n}\n\n// NetworkKubeSpanConfig configures KubeSpan feature.\ntype NetworkKubeSpanConfig interface {\n\tEnabled() bool\n\tForceRouting() bool\n\tAdvertiseKubernetesNetworks() bool\n\tHarvestExtraEndpoints() bool\n\tMTU() uint32\n\tFilters() NetworkKubeSpanFilters\n}\n\n// NetworkKubeSpanFilters configures KubeSpan filters.\ntype NetworkKubeSpanFilters interface {\n\tEndpoints() []string\n\tExcludeAdvertisedNetworks() []netip.Prefix\n}\n\n// NetworkCommonProbeConfig defines a network connectivity probe configuration.\ntype NetworkCommonProbeConfig interface {\n\tNamedDocument\n\tInterval() time.Duration\n\tFailureThreshold() int\n}\n\n// NetworkTCPProbeConfig defines a TCP probe configuration.\ntype NetworkTCPProbeConfig interface {\n\tNetworkCommonProbeConfig\n\tEndpoint() string\n\tTimeout() time.Duration\n}\n\n// NetworkBlackholeRouteConfig defines a blackhole route configuration.\ntype NetworkBlackholeRouteConfig interface {\n\tNamedDocument\n\tBlackholeRouteConfig()\n\tMetric() optional.Optional[uint32]\n}\n\n// NetworkRoutingRuleConfig defines a policy routing rule configuration.\n//\n//nolint:interfacebloat\ntype NetworkRoutingRuleConfig interface {\n\tNamedDocument\n\tRoutingRuleConfig()\n\tSrc() optional.Optional[netip.Prefix]\n\tDst() optional.Optional[netip.Prefix]\n\tTable() nethelpers.RoutingTable\n\tAction() nethelpers.RoutingRuleAction\n\tPriority() uint32\n\tIIFName() string\n\tOIFName() string\n\tFwMark() uint32\n\tFwMask() uint32\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/pci_driver_rebind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\n// PCIDriverRebindConfig defines the interface to access PCI rebind configuration.\ntype PCIDriverRebindConfig interface {\n\tPCIDriverRebindConfigs() []PCIDriverRebindConfigDriver\n}\n\n// PCIDriverRebindConfigDriver defines the interface to access PCI rebind configuration.\ntype PCIDriverRebindConfigDriver interface {\n\tPCIID() string\n\tTargetDriver() string\n}\n\n// WrapPCIDriverRebindConfig wraps a list of PCIDriverRebindConfig into a single PCIDriverRebindConfig aggregating the results.\nfunc WrapPCIDriverRebindConfig(configs ...PCIDriverRebindConfig) PCIDriverRebindConfig {\n\treturn pciDriverRebindConfigWrapper(configs)\n}\n\ntype pciDriverRebindConfigWrapper []PCIDriverRebindConfig\n\nfunc (w pciDriverRebindConfigWrapper) PCIDriverRebindConfigs() []PCIDriverRebindConfigDriver {\n\treturn aggregateValues(w, func(c PCIDriverRebindConfig) []PCIDriverRebindConfigDriver {\n\t\treturn c.PCIDriverRebindConfigs()\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"iter\"\n\t\"maps\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n)\n\n// RuntimeConfig defines the interface to access Talos runtime configuration.\ntype RuntimeConfig interface {\n\tEventsEndpoint() *string\n\tKmsgLogURLs() []*url.URL\n\tWatchdogTimer() WatchdogTimerConfig\n}\n\n// EnvironmentConfig defines the interface to access Talos environment configuration.\ntype EnvironmentConfig interface {\n\tVariables() map[string]string\n}\n\n// WrapEnvironmentConfigList wraps a list of EnvironmentConfig into a single EnvironmentConfig aggregating the results.\nfunc WrapEnvironmentConfigList(configs ...EnvironmentConfig) EnvironmentConfig {\n\treturn environmentConfigWrapper(configs)\n}\n\ntype environmentConfigWrapper []EnvironmentConfig\n\nfunc (w environmentConfigWrapper) Variables() map[string]string {\n\treturn mergeMaps(w, func(c EnvironmentConfig) iter.Seq2[string, string] {\n\t\treturn maps.All(c.Variables())\n\t})\n}\n\n// WatchdogTimerConfig defines the interface to access Talos watchdog timer configuration.\ntype WatchdogTimerConfig interface {\n\tDevice() string\n\tTimeout() time.Duration\n}\n\n// WrapRuntimeConfigList wraps a list of RuntimeConfig into a single RuntimeConfig aggregating the results.\nfunc WrapRuntimeConfigList(configs ...RuntimeConfig) RuntimeConfig {\n\treturn runtimeConfigWrapper(configs)\n}\n\ntype runtimeConfigWrapper []RuntimeConfig\n\nfunc (w runtimeConfigWrapper) EventsEndpoint() *string {\n\treturn findFirstValue(w, func(c RuntimeConfig) *string {\n\t\treturn c.EventsEndpoint()\n\t})\n}\n\nfunc (w runtimeConfigWrapper) KmsgLogURLs() []*url.URL {\n\treturn aggregateValues(w, func(c RuntimeConfig) []*url.URL {\n\t\treturn c.KmsgLogURLs()\n\t})\n}\n\nfunc (w runtimeConfigWrapper) WatchdogTimer() WatchdogTimerConfig {\n\treturn findFirstValue(w, func(c RuntimeConfig) WatchdogTimerConfig {\n\t\treturn c.WatchdogTimer()\n\t})\n}\n\n// OOMConfig defines the interface to access OOM configuration.\ntype OOMConfig interface {\n\tTriggerExpression() optional.Optional[cel.Expression]\n\tCgroupRankingExpression() optional.Optional[cel.Expression]\n\tSampleInterval() optional.Optional[time.Duration]\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/security.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\n// TrustedRootsConfig defines the interface to access trusted roots configuration.\ntype TrustedRootsConfig interface {\n\tExtraTrustedRootCertificates() []string\n}\n\n// WrapTrustedRootsConfig wraps a list of TrustedRootsConfig into a single TrustedRootsConfig aggregating the results.\nfunc WrapTrustedRootsConfig(configs ...TrustedRootsConfig) TrustedRootsConfig {\n\treturn trustedRootConfigWrapper(configs)\n}\n\ntype trustedRootConfigWrapper []TrustedRootsConfig\n\nfunc (w trustedRootConfigWrapper) ExtraTrustedRootCertificates() []string {\n\treturn aggregateValues(w, func(c TrustedRootsConfig) []string {\n\t\treturn c.ExtraTrustedRootCertificates()\n\t})\n}\n\n// ImageVerificationConfig specifies image signature verification policy.\ntype ImageVerificationConfig interface {\n\t// Rules returns the list of verification rules.\n\tRules() []ImageVerificationRule\n}\n\n// ImageVerificationRule represents a rule for image verification.\ntype ImageVerificationRule interface {\n\t// ImagePattern returns the image name pattern.\n\tImagePattern() string\n\t// Skip returns true if verification should be skipped for this rule.\n\tSkip() bool\n\t// Deny returns true if pulling images matching the pattern should be denied.\n\tDeny() bool\n\t// VerifierKeyless returns the keyless verifier to use for this rule (optional).\n\tVerifierKeyless() ImageKeylessVerifier\n\t// VerifierPublicKey returns the public key verifier to use for this rule (optional).\n\tVerifierPublicKey() ImagePublicKeyVerifier\n}\n\n// ImageKeylessVerifier represents a signature verification provider with keyless verification.\ntype ImageKeylessVerifier interface {\n\t// Issuer returns the OIDC issuer URL.\n\tIssuer() string\n\t// Subject returns the expected subject (email, URI, etc).\n\tSubject() string\n\t// SubjectRegex returns the regex pattern for subject matching.\n\tSubjectRegex() string\n}\n\n// ImagePublicKeyVerifier represents a signature verification provider with static public key.\ntype ImagePublicKeyVerifier interface {\n\t// Certificate returns a public certificate in PEM format accepted for image signature verification.\n\tCertificate() string\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/siderolink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport \"net/url\"\n\n// SideroLinkConfig defines the interface to access SideroLink configuration.\ntype SideroLinkConfig interface {\n\tAPIUrl() *url.URL\n\tUniqueToken() string\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/validate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// Validator is the interface to validate configuration.\n//\n// Validator might be implemented by a Container and a single Document.\ntype Validator interface {\n\t// Validate checks configuration and returns warnings and fatal errors (as multierror).\n\tValidate(validation.RuntimeMode, ...validation.Option) ([]string, error)\n}\n\n// RuntimeValidator is the interface to validate configuration in the runtime context.\n//\n// This interface is used by Talos itself to validate configuration on the machine (vs. the Validator interface).\n//\n// The errors reported by Validator & RuntimeValidator are different.\ntype RuntimeValidator interface {\n\t// RuntimeValidate validates the config in the runtime context.\n\t//\n\t// The method returns warnings and fatal errors (as multierror).\n\tRuntimeValidate(context.Context, state.State, validation.RuntimeMode, ...validation.Option) ([]string, error)\n}\n"
  },
  {
    "path": "pkg/machinery/config/config/volume.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumesConfig defines the interface to access volume configuration.\ntype VolumesConfig interface {\n\t// ByName returns a volume config configuration by name.\n\t//\n\t// If the configuration is missing, the method a stub which returns implements 'nothing is set' stub.\n\tByName(name string) (VolumeConfig, bool)\n}\n\n// VolumeConfig defines the interface to access volume configuration.\ntype VolumeConfig interface {\n\tNamedDocument\n\tProvisioning() VolumeProvisioningConfig\n\tEncryption() EncryptionConfig\n\tMount() VolumeMountConfig\n}\n\n// VolumeProvisioningConfig defines the interface to access volume provisioning configuration.\ntype VolumeProvisioningConfig interface {\n\tDiskSelector() optional.Optional[cel.Expression]\n\tGrow() optional.Optional[bool]\n\tMinSize() optional.Optional[uint64]\n\tMaxSize() optional.Optional[uint64]\n\tRelativeMaxSize() optional.Optional[uint64]\n\tMaxSizeNegative() bool\n}\n\n// WrapVolumesConfigList wraps a list of VolumeConfig providing access by name.\nfunc WrapVolumesConfigList(configs ...VolumeConfig) VolumesConfig {\n\treturn volumesConfigWrapper(configs)\n}\n\ntype volumesConfigWrapper []VolumeConfig\n\nfunc (w volumesConfigWrapper) ByName(name string) (VolumeConfig, bool) {\n\tfor _, doc := range w {\n\t\tif doc.Name() == name {\n\t\t\treturn doc, true\n\t\t}\n\t}\n\n\treturn emptyVolumeConfig{}, false\n}\n\ntype emptyVolumeConfig struct{}\n\nfunc (emptyVolumeConfig) Name() string {\n\treturn \"\"\n}\n\nfunc (emptyVolumeConfig) Provisioning() VolumeProvisioningConfig {\n\treturn emptyVolumeConfig{}\n}\n\nfunc (emptyVolumeConfig) Encryption() EncryptionConfig {\n\treturn nil\n}\n\nfunc (emptyVolumeConfig) DiskSelector() optional.Optional[cel.Expression] {\n\treturn optional.None[cel.Expression]()\n}\n\nfunc (emptyVolumeConfig) Grow() optional.Optional[bool] {\n\treturn optional.None[bool]()\n}\n\nfunc (emptyVolumeConfig) MinSize() optional.Optional[uint64] {\n\treturn optional.None[uint64]()\n}\n\nfunc (emptyVolumeConfig) MaxSize() optional.Optional[uint64] {\n\treturn optional.None[uint64]()\n}\n\nfunc (emptyVolumeConfig) RelativeMaxSize() optional.Optional[uint64] {\n\treturn optional.None[uint64]()\n}\n\nfunc (emptyVolumeConfig) MaxSizeNegative() bool {\n\treturn false\n}\n\nfunc (emptyVolumeConfig) Mount() VolumeMountConfig {\n\treturn emptyVolumeMountConfig{}\n}\n\ntype emptyVolumeMountConfig struct{}\n\nfunc (emptyVolumeMountConfig) DisableAccessTime() bool {\n\treturn false\n}\n\nfunc (emptyVolumeMountConfig) Secure() bool {\n\treturn true\n}\n\nfunc (emptyVolumeMountConfig) ReadOnly() bool {\n\treturn false\n}\n\n// UserVolumeConfig defines the interface to access user volume configuration.\ntype UserVolumeConfig interface {\n\tNamedDocument\n\tUserVolumeConfigSignal()\n\tType() optional.Optional[block.VolumeType]\n\tProvisioning() VolumeProvisioningConfig\n\tFilesystem() FilesystemConfig\n\tEncryption() EncryptionConfig\n\tMount() UserVolumeMountConfig\n}\n\n// RawVolumeConfig defines the interface to access raw volume configuration.\ntype RawVolumeConfig interface {\n\tNamedDocument\n\tRawVolumeConfigSignal()\n\tProvisioning() VolumeProvisioningConfig\n\tEncryption() EncryptionConfig\n}\n\n// ExistingVolumeConfig defines the interface to access existing volume configuration.\ntype ExistingVolumeConfig interface {\n\tNamedDocument\n\tExistingVolumeConfigSignal()\n\tVolumeDiscovery() VolumeDiscoveryConfig\n\tMount() ExistingVolumeMountConfig\n}\n\n// ExternalVolumeConfig defines the interface to access external volume configuration.\ntype ExternalVolumeConfig interface {\n\tNamedDocument\n\tExternalVolumeConfigSignal()\n\tType() block.FilesystemType\n\tMount() ExternalVolumeMountConfig\n}\n\n// VolumeDiscoveryConfig defines the interface to discover volumes.\ntype VolumeDiscoveryConfig interface {\n\tVolumeSelector() cel.Expression\n}\n\n// VolumeMountConfig defines the interface to access volume mount configuration.\ntype VolumeMountConfig interface {\n\tSecure() bool\n}\n\n// UserVolumeMountConfig defines the interface to access volume mount configuration.\ntype UserVolumeMountConfig interface {\n\tVolumeMountConfig\n\tDisableAccessTime() bool\n}\n\n// ExistingVolumeMountConfig defines the interface to access volume mount configuration.\ntype ExistingVolumeMountConfig interface {\n\tUserVolumeMountConfig\n\tReadOnly() bool\n}\n\n// ExternalVolumeMountConfig defines the interface to access volume mount configuration.\ntype ExternalVolumeMountConfig interface {\n\tExistingVolumeMountConfig\n\tVirtiofs() optional.Optional[ExternalVolumeMountConfigSpec]\n}\n\n// ExternalVolumeMountConfigSpec defines the interface to access external mount configuration spec.\ntype ExternalVolumeMountConfigSpec interface {\n\tSource() string\n\tParameters() ([]block.ParameterSpec, error)\n}\n\n// FilesystemConfig defines the interface to access filesystem configuration.\ntype FilesystemConfig interface {\n\t// Type returns the filesystem type.\n\tType() block.FilesystemType\n\t// ProjectQuotaSupport returns true if the filesystem should support project quotas.\n\tProjectQuotaSupport() bool\n}\n\n// SwapVolumeConfig defines the interface to access swap volume configuration.\ntype SwapVolumeConfig interface {\n\tNamedDocument\n\tSwapVolumeConfigSignal()\n\tProvisioning() VolumeProvisioningConfig\n\tEncryption() EncryptionConfig\n}\n\n// ZswapConfig defines the interface to access zswap configuration.\ntype ZswapConfig interface {\n\tZswapConfigSignal()\n\tMaxPoolPercent() int\n\tShrinkerEnabled() bool\n}\n"
  },
  {
    "path": "pkg/machinery/config/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package config provides methods to generate and consume Talos configuration.\npackage config\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -generate-schema-from-dir types/ -json-schema-output schemas/config.schema.json -version-tag-file ../gendata/data/tag\n\nimport \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\n// Config defines the interface to access contents of the machine configuration.\ntype Config = config.Config\n"
  },
  {
    "path": "pkg/machinery/config/config_schema_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\tvalidatejsonschema \"github.com/santhosh-tekuri/jsonschema/v6\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed schemas/config.schema.json\nvar schemaData string\n\nfunc TestSchemaValidation(t *testing.T) {\n\tt.Parallel()\n\n\tschemaJSON, err := validatejsonschema.UnmarshalJSON(strings.NewReader(schemaData))\n\trequire.NoError(t, err)\n\n\tcompiler := validatejsonschema.NewCompiler()\n\terr = compiler.AddResource(\"test-id\", schemaJSON)\n\trequire.NoError(t, err)\n\n\tschema, err := compiler.Compile(\"test-id\")\n\trequire.NoError(t, err)\n\n\tfor _, test := range []struct {\n\t\tname                  string\n\t\tconfig                map[string]any\n\t\texpectedErrorContains string\n\t}{\n\t\t{\n\t\t\tname:   \"v1alpha1_valid\",\n\t\t\tconfig: newV1Alpha1Config(t, nil, nil),\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1_invalid-version\",\n\t\t\tconfig: newV1Alpha1Config(t, func(config *v1alpha1.Config) {\n\t\t\t\tconfig.ConfigVersion = \"v1alpha2\"\n\t\t\t}, nil),\n\t\t\texpectedErrorContains: `value must be 'v1alpha1'`,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1_invalid-control-plane-endpoint\",\n\t\t\tconfig: newV1Alpha1Config(t, func(config *v1alpha1.Config) {\n\t\t\t\tendpointURL, urlErr := url.Parse(\"ftp://127.0.0.1:6443\")\n\t\t\t\trequire.NoError(t, urlErr)\n\n\t\t\t\tconfig.ClusterConfig.ControlPlane.Endpoint = &v1alpha1.Endpoint{\n\t\t\t\t\tURL: endpointURL,\n\t\t\t\t}\n\t\t\t}, nil),\n\t\t\texpectedErrorContains: `does not match pattern '^https://'`,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1_invalid-duration\",\n\t\t\tconfig: newV1Alpha1Config(t, nil, func(rawConfig map[string]any) {\n\t\t\t\tsetNestedField(t, rawConfig, \"100y\", \"cluster\", \"adminKubeconfig\", \"certLifetime\")\n\t\t\t}),\n\t\t\texpectedErrorContains: `does not match pattern`,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1_invalid-machine-type\",\n\t\t\tconfig: newV1Alpha1Config(t, func(config *v1alpha1.Config) {\n\t\t\t\tconfig.MachineConfig.MachineType = \"invalidtype\"\n\t\t\t}, nil),\n\t\t\texpectedErrorContains: `value must be one of 'controlplane', 'worker'`,\n\t\t},\n\t\t{\n\t\t\tname:   \"network/RuleConfigV1Alpha1_valid\",\n\t\t\tconfig: newRuleConfigV1Alpha1(t, nil, nil),\n\t\t},\n\t\t{\n\t\t\tname: \"network/RuleConfigV1Alpha1_invalid-cidr-prefix\",\n\t\t\tconfig: newRuleConfigV1Alpha1(t, nil, func(rawConfig map[string]any) {\n\t\t\t\trawConfig[\"ingress\"] = []any{\n\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\"subnet\": \"10.42.0.0/16\",\n\t\t\t\t\t\t\"except\": \"10.42.43.0/24\",\n\t\t\t\t\t},\n\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\"subnet\": \"192.168.178.0/24\",\n\t\t\t\t\t\t\"except\": \"invalid-except/12343\",\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}),\n\t\t\texpectedErrorContains: \"'/ingress/1/except': 'invalid-except/12343' does not match pattern\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestErr := schema.Validate(test.config)\n\n\t\t\tif test.expectedErrorContains != \"\" {\n\t\t\t\terrors := gatherValidationErrors(t, testErr)\n\t\t\t\terrorsStr := strings.Join(errors, \"\\n\")\n\n\t\t\t\tassert.Contains(t, errorsStr, test.expectedErrorContains)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, testErr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc gatherValidationErrors(t *testing.T, err error) []string {\n\tvar validationErr *validatejsonschema.ValidationError\n\n\trequire.ErrorAs(t, err, &validationErr)\n\n\tmessages := make([]string, 0, len(validationErr.Causes)+1)\n\tif len(validationErr.Causes) == 0 {\n\t\tmessages = append(messages, validationErr.Error())\n\t}\n\n\tfor _, cause := range validationErr.Causes {\n\t\tmessages = append(messages, gatherValidationErrors(t, cause)...)\n\t}\n\n\treturn messages\n}\n\nfunc newV1Alpha1Config(t *testing.T, modifications func(config *v1alpha1.Config), rawModifications func(rawConfig map[string]any)) map[string]any {\n\tinput, err := generate.NewInput(\"test\", \"https://doesntmatter:6443\", constants.DefaultKubernetesVersion)\n\trequire.NoError(t, err)\n\n\tconfig, err := input.Config(machine.TypeControlPlane)\n\trequire.NoError(t, err)\n\n\tif modifications != nil {\n\t\tmodifications(config.RawV1Alpha1())\n\t}\n\n\tconfigBytes, err := config.Bytes()\n\trequire.NoError(t, err)\n\n\tvar data map[string]any\n\n\trequire.NoError(t, yaml.Unmarshal(configBytes, &data))\n\n\tif rawModifications != nil {\n\t\trawModifications(data)\n\t}\n\n\t// deprecated field\n\tdelete(data, \"persist\")\n\n\treturn data\n}\n\nfunc newRuleConfigV1Alpha1(t *testing.T, modifications func(config *network.RuleConfigV1Alpha1), rawModifications func(rawConfig map[string]any)) map[string]any {\n\tconfig := network.NewRuleConfigV1Alpha1()\n\n\tconfig.MetaName = \"something\"\n\n\tconfig.PortSelector = network.RulePortSelector{\n\t\tPorts: network.PortRanges{\n\t\t\t{Lo: 1000, Hi: 2000},\n\t\t\t{Lo: 3000, Hi: 4000},\n\t\t},\n\t\tProtocol: nethelpers.ProtocolTCP,\n\t}\n\n\tconfig.Ingress = network.IngressConfig{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"10.42.0.0/16\"),\n\t\t\tExcept: network.Prefix{Prefix: netip.MustParsePrefix(\"10.42.43.0/24\")},\n\t\t},\n\t}\n\n\tif modifications != nil {\n\t\tmodifications(config)\n\t}\n\n\tconfigBytes, err := yaml.Marshal(config)\n\trequire.NoError(t, err)\n\n\tvar data map[string]any\n\n\trequire.NoError(t, yaml.Unmarshal(configBytes, &data))\n\n\tif rawModifications != nil {\n\t\trawModifications(data)\n\t}\n\n\treturn data\n}\n\nfunc setNestedField(t *testing.T, obj map[string]any, value any, fields ...string) {\n\tm := obj\n\n\tfor i, field := range fields[:len(fields)-1] {\n\t\tif val, ok := m[field]; ok {\n\t\t\tvalMap, valMapOk := val.(map[string]any)\n\n\t\t\trequire.Truef(t, valMapOk, \"value cannot be set because %v is not a map[string]any\", jsonPath(fields[:i+1]))\n\n\t\t\tm = valMap\n\t\t} else {\n\t\t\tnewVal := make(map[string]any)\n\t\t\tm[field] = newVal\n\t\t\tm = newVal\n\t\t}\n\t}\n\n\tm[fields[len(fields)-1]] = value\n}\n\nfunc jsonPath(fields []string) string {\n\treturn \".\" + strings.Join(fields, \".\")\n}\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/configdiff.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package configdiff provides a way to compare two config trees.\npackage configdiff\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/textdiff\"\n)\n\n// DiffConfigs returns a string representation of the diff between two machine configurations.\n//\n// One of the resources might be nil.\nfunc DiffConfigs(oldCfg, newCfg config.Encoder) (string, error) {\n\tvar (\n\t\toldYaml, newYaml []byte\n\t\terr              error\n\t)\n\n\tif oldCfg != nil {\n\t\toldYaml, err = oldCfg.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\tif newCfg != nil {\n\t\tnewYaml, err = newCfg.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\treturn textdiff.Diff(string(oldYaml), string(newYaml))\n}\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/configdiff_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configdiff_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configdiff\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestDiffString(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType:  \"controlplane\",\n\t\t\tMachineToken: \"foo\",\n\t\t},\n\t}\n\n\tv1alpha1CfgOther := v1alpha1Cfg.DeepCopy()\n\tv1alpha1CfgOther.MachineConfig.MachineType = \"worker\"\n\n\tsiderolinkConfig := siderolink.NewConfigV1Alpha1()\n\tsiderolinkConfig.APIUrlConfig = meta.URL{\n\t\tURL: must.Value(url.Parse(\"https://example.com\"))(t),\n\t}\n\n\tfor _, test := range []struct {\n\t\tname   string\n\t\toldCfg []config.Document\n\t\tnewCfg []config.Document\n\t\twant   string\n\t}{\n\t\t{\n\t\t\tname:   \"empty\",\n\t\t\toldCfg: nil,\n\t\t\tnewCfg: nil,\n\t\t\twant:   \"\",\n\t\t},\n\t\t{\n\t\t\tname:   \"same\",\n\t\t\toldCfg: []config.Document{v1alpha1Cfg},\n\t\t\tnewCfg: []config.Document{v1alpha1Cfg},\n\t\t\twant:   \"\",\n\t\t},\n\t\t{\n\t\t\tname:   \"new doc\",\n\t\t\toldCfg: []config.Document{v1alpha1Cfg},\n\t\t\tnewCfg: []config.Document{v1alpha1Cfg, siderolinkConfig},\n\t\t\twant:   \"--- a\\n+++ b\\n@@ -4,3 +4,7 @@\\n     token: foo\\n     certSANs: []\\n cluster: null\\n+---\\n+apiVersion: v1alpha1\\n+kind: SideroLinkConfig\\n+apiUrl: https://example.com\\n\",\n\t\t},\n\t\t{\n\t\t\tname:   \"updated field\",\n\t\t\toldCfg: []config.Document{v1alpha1Cfg, siderolinkConfig},\n\t\t\tnewCfg: []config.Document{v1alpha1CfgOther, siderolinkConfig},\n\t\t\twant:   \"--- a\\n+++ b\\n@@ -1,6 +1,6 @@\\n version: v1alpha1\\n machine:\\n-    type: controlplane\\n+    type: worker\\n     token: foo\\n     certSANs: []\\n cluster: null\\n\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\toldCfg := must.Value(container.New(test.oldCfg...))(t)\n\t\t\tnewCfg := must.Value(container.New(test.newCfg...))(t)\n\n\t\t\tgot, err := configdiff.DiffConfigs(oldCfg, newCfg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, test.want, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/mergepatch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configdiff\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"maps\"\n\t\"reflect\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\tconfigcore \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/documentid\"\n)\n\ntype unstructured map[string]any\n\n// Patch will return a slice of Patches capable of converting the original config to the modified config when applied in order.\nfunc Patch(original, modified configcore.Provider) ([]configpatcher.Patch, error) {\n\tpatches := make([]configpatcher.Patch, 0, 2)\n\n\tfirstPass, err := patch(original, modified, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif firstPass != nil {\n\t\tfirstPatch, ok := (*firstPass).(configpatcher.Patch)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"expected Patch, got %T\", *firstPass)\n\t\t}\n\n\t\tpatches = append(patches, firstPatch)\n\t}\n\n\tsecondPass, err := patch(original, modified, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif secondPass != nil {\n\t\tsecondPatch, ok := (*secondPass).(configpatcher.Patch)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"expected Patch, got %T\", *secondPass)\n\t\t}\n\n\t\tpatches = append(patches, secondPatch)\n\t}\n\n\treturn patches, nil\n}\n\n// nolint: gocyclo\nfunc patch(original, modified configcore.Provider, firstPass bool) (*configpatcher.StrategicMergePatch, error) {\n\toriginalIDToDoc := documentsToMap(original.Documents())\n\tmodifiedIDToDoc := documentsToMap(modified.Documents())\n\n\tvar removed, added, common []documentid.DocumentID // nolint:prealloc\n\n\tfor id := range originalIDToDoc {\n\t\tif _, ok := modifiedIDToDoc[id]; !ok {\n\t\t\tremoved = append(removed, id)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tcommon = append(common, id)\n\t}\n\n\tfor id := range modifiedIDToDoc {\n\t\tif _, ok := originalIDToDoc[id]; !ok {\n\t\t\tadded = append(added, id)\n\t\t}\n\t}\n\n\tunstructuredPatches := make([]unstructured, 0, len(removed)+len(added)+len(common))\n\n\tif firstPass {\n\t\tfor _, removedID := range removed {\n\t\t\tmeta := removedID.Meta()\n\t\t\tmeta[\"$patch\"] = \"delete\"\n\n\t\t\tunstructuredPatches = append(unstructuredPatches, meta)\n\t\t}\n\n\t\tfor _, addedID := range added {\n\t\t\taddedDoc := modifiedIDToDoc[addedID]\n\n\t\t\taddedUnstructured, err := documentToUnstructured(addedDoc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tunstructuredPatches = append(unstructuredPatches, addedUnstructured)\n\t\t}\n\t}\n\n\tfor _, commonID := range common {\n\t\toriginalDoc := originalIDToDoc[commonID]\n\t\tmodifiedDoc := modifiedIDToDoc[commonID]\n\n\t\toriginalUnstructured, err := documentToUnstructured(originalDoc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmodifiedUnstructured, err := documentToUnstructured(modifiedDoc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmergePatch, err := createMergePatch(originalUnstructured, modifiedUnstructured, &commonID, firstPass)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif len(mergePatch) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tunstructuredPatches = append(unstructuredPatches, mergePatch)\n\t}\n\n\tif len(unstructuredPatches) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tpatchYAML, err := encodeToYAML(unstructuredPatches)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcfg, err := configloader.NewFromBytes(patchYAML, configloader.WithAllowPatchDelete())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmergePatch := configpatcher.NewStrategicMergePatch(cfg)\n\n\treturn &mergePatch, nil\n}\n\nfunc encodeToYAML(docs []unstructured) ([]byte, error) {\n\tvar buf bytes.Buffer\n\n\tenc := yaml.NewEncoder(&buf)\n\tenc.SetIndent(2)\n\n\tfor _, doc := range docs {\n\t\tif err := enc.Encode(doc); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err := enc.Close(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\nfunc documentsToMap(docs []config.Document) map[documentid.DocumentID]config.Document {\n\tout := make(map[documentid.DocumentID]config.Document, len(docs))\n\n\tfor _, doc := range docs {\n\t\tout[documentid.Extract(doc)] = doc\n\t}\n\n\treturn out\n}\n\nfunc documentToUnstructured(doc config.Document) (unstructured, error) {\n\tc, err := container.New(doc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tunstructuredBytes, err := c.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar out unstructured\n\tif err = yaml.Unmarshal(unstructuredBytes, &out); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn out, nil\n}\n\n// nolint: gocyclo,cyclop\nfunc createMergePatch(original, modified unstructured, documentID *documentid.DocumentID, firstPass bool) (unstructured, error) {\n\tmeta := unstructured{}\n\tmergePatch := unstructured{}\n\n\t// First, handle all modified and added values\n\tfor key, modV := range modified {\n\t\t// Discover and keep meta fields obtained from documentId\n\t\tif documentID != nil {\n\t\t\tif metaV, ok := documentID.Meta()[key]; ok && metaV != \"\" {\n\t\t\t\tmeta[key] = metaV\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\torigV, ok := original[key]\n\t\tif !ok {\n\t\t\tsetValue(&mergePatch, key, modV, firstPass)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif reflect.TypeOf(origV) != reflect.TypeOf(modV) {\n\t\t\tsetValue(&mergePatch, key, modV, firstPass)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch origT := origV.(type) {\n\t\tcase unstructured:\n\t\t\tmodT := modV.(unstructured)\n\n\t\t\tpatchV, err := createMergePatch(origT, modT, nil, firstPass)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif len(patchV) > 0 {\n\t\t\t\tmergePatch[key] = patchV\n\t\t\t}\n\t\tcase []any:\n\t\t\tmodT := modV.([]any)\n\t\t\tif !reflect.DeepEqual(origT, modT) {\n\t\t\t\tif firstPass {\n\t\t\t\t\tmergePatch[key] = map[string]string{\"$patch\": \"delete\"}\n\t\t\t\t} else {\n\t\t\t\t\tsetValue(&mergePatch, key, modV, true)\n\t\t\t\t}\n\t\t\t}\n\t\tcase string, int, uint, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, bool:\n\t\t\tif !reflect.DeepEqual(origV, modV) {\n\t\t\t\tsetValue(&mergePatch, key, modV, firstPass)\n\t\t\t}\n\t\tcase nil:\n\t\t\tswitch modV.(type) {\n\t\t\tcase nil:\n\t\t\t\t// Both nil, fine.\n\t\t\tdefault:\n\t\t\t\tsetValue(&mergePatch, key, modV, firstPass)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown type:%T in key %s\", origV, key)\n\t\t}\n\t}\n\n\t// Now handle all deleted keys\n\tfor key := range original {\n\t\tif _, ok := modified[key]; !ok {\n\t\t\tsetValue(&mergePatch, key, map[string]string{\"$patch\": \"delete\"}, firstPass)\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\t// Finally, merge meta into mergePatch\n\tif len(mergePatch) > 0 && len(meta) > 0 {\n\t\tmaps.Copy(mergePatch, meta)\n\t}\n\n\treturn mergePatch, nil\n}\n\nfunc setValue(mergePatch *unstructured, key string, value any, shouldSet bool) {\n\tif shouldSet {\n\t\t(*mergePatch)[key] = value\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/mergepatch_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configdiff_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tcoreconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configdiff\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/documentid\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nvar (\n\t//go:embed testdata/original.yaml\n\toriginalYAML []byte\n\n\t//go:embed testdata/modified.yaml\n\tmodifiedYAML []byte\n)\n\nfunc TestMergePatch(t *testing.T) {\n\toriginal, err := configloader.NewFromBytes(originalYAML)\n\trequire.NoError(t, err)\n\n\tmodified, err := configloader.NewFromBytes(modifiedYAML)\n\trequire.NoError(t, err)\n\n\tpatches, err := configdiff.Patch(original, modified)\n\trequire.NoError(t, err)\n\n\tapply, err := configpatcher.Apply(configpatcher.WithConfig(original), patches)\n\trequire.NoError(t, err)\n\n\tappliedBytes, err := apply.Bytes()\n\trequire.NoError(t, err)\n\n\tmodifiedBytes, err := modified.Bytes()\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, string(modifiedBytes), string(appliedBytes))\n}\n\nvar inlineOriginal = []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`)\n\nfunc TestMergePatchInline(t *testing.T) {\n\ttests := []struct {\n\t\tname            string\n\t\toriginalAsBytes []byte\n\t\tmodifiedAsBytes []byte\n\t\tpatchesAsBytes  [][]byte\n\t}{\n\t\t{\n\t\t\tname:            \"test add field\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-config: /etc/kubernetes/cloud-config\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`machine:\n  kubelet:\n    extraArgs:\n      cloud-config: /etc/kubernetes/cloud-config\nversion: v1alpha1\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test replace field\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10001\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`cluster:\n  controlPlane:\n    endpoint: https://[fdae:41e4:649b:9303::1]:10001\nversion: v1alpha1\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test add nested field\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n    discovery:\n        registries:\n            kubernetes:\n                disabled: false\n            service: {}\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`cluster:\n  discovery:\n    registries:\n      kubernetes:\n        disabled: false\n      service: {}\nversion: v1alpha1\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test replace item in list\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - new-example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`machine:\n  certSANs:\n    $patch: delete\nversion: v1alpha1\n`),\n\n\t\t\t\t[]byte(`machine:\n  certSANs:\n    - new-example.com\nversion: v1alpha1\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test remove key\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`machine:\n  kubelet:\n    $patch: delete\nversion: v1alpha1\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test add document\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n---\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`apiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\n`),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:            \"test remove document\",\n\t\t\toriginalAsBytes: inlineOriginal,\n\t\t\tmodifiedAsBytes: []byte(`version: v1alpha1\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    certSANs:\n        - example.com\n    kubelet:\n        extraArgs:\n            cloud-provider: external\ncluster:\n    controlPlane:\n        endpoint: https://[fdae:41e4:649b:9303::1]:10000\n`),\n\t\t\tpatchesAsBytes: [][]byte{\n\t\t\t\t[]byte(`$patch: delete\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\n`),\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\toriginal, err := configloader.NewFromBytes(tt.originalAsBytes)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodified, err := configloader.NewFromBytes(tt.modifiedAsBytes)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tpatches, err := configdiff.Patch(original, modified)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor i, patch := range patches {\n\t\t\t\tprovider := patch.(configpatcher.StrategicMergePatch).Provider()\n\n\t\t\t\tpatchBytes, err := provider.Bytes()\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\trequire.Equal(t, string(patchBytes), string(tt.patchesAsBytes[i]))\n\t\t\t}\n\n\t\t\tapply, err := configpatcher.Apply(configpatcher.WithConfig(original), patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tappliedBytes, err := apply.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmodifiedBytes, err := modified.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Equal(t, string(modifiedBytes), string(appliedBytes))\n\t\t})\n\t}\n}\n\nvar dynamicPatches = [][]byte{\n\t[]byte(`machine:\n    network:\n        interfaces:\n            - interface: enp0s2\n              dhcp: true\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\n`),\n\t[]byte(`cluster:\n    apiServer:\n        certSANs:\n            - example.com\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                exemptions:\n                    namespaces:\n                        - kube-public\n                        - kube-node-lease\n`),\n\t[]byte(`cluster:\n    apiServer:\n        admissionControl:\n            - name: PrivilegedPodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: privileged\n                    audit-version: latest\n                    enforce: privileged\n                    enforce-version: latest\n                    warn: privileged\n                    warn-version: latest\n                exemptions:\n                    namespaces: []\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello-foo\n      mountPath: /etc/foo\nenvironment:\n    - FOO=BAR\n    - BAR=FOO\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: var\nconfigFiles:\n    - content: hello-var\n      mountPath: /etc/var\n    - content: hello-foo\n      mountPath: /etc/var/foo\nenvironment:\n    - FOO=BAR\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: grpc://omni.example.com:8090?jointoken=testtoken\n---\napiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: '[fdae:41e4:649b:9303::1]:8091'\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: omni-kmsg\nurl: tcp://[fdae:41e4:649b:9303::1]:8092\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\n$patch: delete\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: EthernetConfig\nname: enp0s2\nfeatures:\n    tx-tcp-segmentation: false\n`),\n\t[]byte(`apiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: var\nconfigFiles:\n    - content: hello-var\n      mountPath: /etc/var\n      $patch: delete\nenvironment:\n    - FOO=BARFOO\n`),\n}\n\nfunc TestMergePatchDynamic(t *testing.T) {\n\tbundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\trequire.NoError(t, err)\n\n\tinput, err := generate.NewInput(\"test\", \"https://localhost:6443\", constants.DefaultKubernetesVersion, generate.WithSecretsBundle(bundle))\n\trequire.NoError(t, err)\n\n\toriginal, err := input.Config(machine.TypeControlPlane)\n\trequire.NoError(t, err)\n\n\tvar modified config.Provider\n\n\tmodified = original.Clone()\n\t// Apply patches one by one to simulate real world usage\n\tfor _, patchBytes := range dynamicPatches {\n\t\tpatches, patchErr := configpatcher.LoadPatch(patchBytes)\n\t\trequire.NoError(t, patchErr)\n\n\t\tpatched, patchErr := configpatcher.Apply(configpatcher.WithConfig(modified), []configpatcher.Patch{patches})\n\t\trequire.NoError(t, patchErr)\n\n\t\tmodified, patchErr = patched.Config()\n\t\trequire.NoError(t, patchErr)\n\t}\n\n\t// Get merge patches between original and modified\n\tpatches, err := configdiff.Patch(original, modified)\n\trequire.NoError(t, err)\n\n\t// Apply the merge patches to the original config\n\tpatched, err := configpatcher.Apply(configpatcher.WithConfig(original), patches)\n\trequire.NoError(t, err)\n\n\tpatchedConfig, err := patched.Config()\n\trequire.NoError(t, err)\n\n\t// configpatcher.Apply may change the order of documents, so we need to compare them one by one\n\tmodifiedDocuments := modified.Documents()\n\tpatchedDocuments := patchedConfig.Documents()\n\n\trequire.Equal(t, len(modifiedDocuments), len(patchedDocuments))\n\n\tmodifiedDocumentsMap := xslices.ToMap(modifiedDocuments, func(doc coreconfig.Document) (documentid.DocumentID, coreconfig.Document) {\n\t\treturn documentid.Extract(doc), doc\n\t})\n\n\tpatchedDocumentsMap := xslices.ToMap(patchedDocuments, func(doc coreconfig.Document) (documentid.DocumentID, coreconfig.Document) {\n\t\treturn documentid.Extract(doc), doc\n\t})\n\n\tfor id, modifiedDoc := range modifiedDocumentsMap {\n\t\tpatchedDoc, ok := patchedDocumentsMap[id]\n\t\trequire.True(t, ok, \"document %v not found in patched config\", id)\n\n\t\tmodifiedDocContainer, docErr := container.New(modifiedDoc)\n\t\trequire.NoError(t, docErr)\n\n\t\tpatchedDocContainer, docErr := container.New(patchedDoc)\n\t\trequire.NoError(t, docErr)\n\n\t\tmodifiedBytes, docErr := modifiedDocContainer.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\trequire.NoError(t, docErr)\n\n\t\tpatchedBytes, docErr := patchedDocContainer.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\trequire.NoError(t, docErr)\n\n\t\trequire.Equal(t, string(modifiedBytes), string(patchedBytes), \"document %v does not match\", id)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/testdata/modified.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: 2to1o4.gtwik66aods4cznj\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBaCsrS0JQcURzL2EyeTgyMXhRak9CekFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qVXdPVEl5TURjek1ERTJXaGNOTXpVd09USXdNRGN6TURFMldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUU3dEthbTdaRUdsNTVUeDVzVDZWRmhKZDJVVFh1Z2g0MjlSCjZvVVk1WkxFbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkZ5dGhPT3ZpVzFYa3dHNAo1ZTdHVUtFSjhSSmtNQVVHQXl0bGNBTkJBRGhMclN0YTFlY1QwNFdVQ1YxYzZQOFVjVkpRTmNhMUl2RGxTQ3hwCm9vZzdudUJxdWxCRFdYVkFqQm9TTGU5VlV6aWQ3dTc4MDdIaHNzeFBneW03b2dRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR3BNOE1iSnplQXpYZ2xXNGRQcDFtUnMvV1lkYU1Nbjl2T0M3QUVXQU5MKwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.34.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network:\n        interfaces:\n            - interface: enp0s2\n              dhcp: true\n    install:\n        disk: /dev/vda\n        image: factory.talos.dev/metal-installer/088171816e905ec439337da75b1bafb81de8c652ee41c099f2b9ef7d90847648:v1.11.1\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: DyOHp_FdDYr54RvtQR6SKyda2dshZkiUE_y0CQH1wFY=\n    secret: Ig7Us67kfx01ascq3Q44GXA9P9b62iFKuYRV04Fntl8=\n    controlPlane:\n        endpoint: https://talos.local.oguz.pw:6443\n    clusterName: talos-default\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: ipovvu.zu2q1qef8u1ghx5p\n    secretboxEncryptionSecret: g9/DQ6uJ+MuVLcNHLmrOgfeq5kD7SoJic7U7T74PanI=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpakNDQVMrZ0F3SUJBZ0lRSkJ5azVFYTB1STRUSHc3cG5Ob0E4ekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSTFNRGt5TWpBM016QXhObG9YRFRNMU1Ea3lNREEzTXpBeApObG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQVc2ZC9BQUxOYi9tYklvYUIzUzg2Z2kzTWVrYU9RbFpGdkZ0dkZ2S29COUpzeWR3Q1E1MDlSQW1MNWcKSDFvOWhLbjBoRlVNM0NaSXBWYlppT2JoY09DallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVvWWtIOUZocFRLdlpudDdCYVlMbXhFMjF0UXN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUtINmI3cnYKMmhuT1VhUjlkcVRpdURNOGpiVVVpSFo2RStuU1YzdG9qdlhKQWlFQTdGWUZxYjZFT21TTDUwNXo0VjJtZHJYQQpnWHBzK3R5NzUxckl1RGpFY0gwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1OVTB1YnBKa1JPdnlYbndkdGNVNHFxQTdZZkdNdENiZk02SThXUnhtMkZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQmJwMzhBQXMxditac2lob0hkTHpxQ0xjeDZSbzVDVmtXOFcyOFc4cWdIMG16SjNBSkRuVAoxRUNZdm1BZldqMkVxZlNFVlF6Y0praWxWdG1JNXVGdzRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFhZ0F3SUJBZ0lSQU5sOElMcm05c1BzZ3Z5K0xKbUhWRGt3Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU5UQTVNakl3TnpNd01UWmFGdzB6TlRBNU1qQXdOek13TVRaYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVNsSFBsbk9aSFZsbkRmdUhvNE0raWpqcTY1dUkzUTY4aE45UVBlWU9ZbTlNVVE0V3hyCnA2SjdwbGw3dWQvcFZVaUNyMVBVb0gxUWNHVGs2T09JanhKaG8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGRHhaZTFEU05nUzF3SE8xK2UySTgvNkVYL2pOTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklRQ0dXK0xlMTJOUS9Dd0czVitiUWZ1andRYkZwUmNYLzhZV052TllOZS9GdlFJZ2Z6VGw0VVJZVVdvejlDMzMKdGpLaEkvOFFIKy9jczQzODFrVDkwbGNVMEtrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFGbFo3RG9acStCdldMWExmMDFwcDB3RGpUeE5pa0swQkozS2JsL3NPaEJvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFcFJ6NVp6bVIxWlp3MzdoNk9EUG9vNDZ1dWJpTjBPdklUZlVEM21EbUp2VEZFT0ZzYTZlaQplNlpaZTduZjZWVklncTlUMUtCOVVIQms1T2pqaUk4U1lRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS2dJQkFBS0NBZ0VBdGh5Q3Q5MVpPem9SdTNTaWNsOFJVTnpzdkg3T3BQZ3AvaEdqZVFzZzFWbU80N3ZLCkhOMUxvY1kvTjhEZ3plZnJqc0YzU1ZSZGl2RDd4UXB4bzZmR2pDckxDNU9YZHdyRUVCc2wzQ1QwdzdpZXE5UFUKR1lNT3ROdXZ1M1QwRGIxMVZ1QW1wZVNzUWVEdXJPeDJEY1NzaEdrK2NEVTNJS2xsb2U5VWtuOVllck5MN1JEUAp0R0wvdy9VaTA3QWJXVWkvYnM5RFN1V2QybXBmdnVWSnJaTS9icTBwQ0NBaDR1c29jcnM2OHA2ZG01akpGT3E0CnA1SlN2YWxBemhHNUdwQllyVU54WUlXejJCR3JaTis3dDhlc2V1eEVIeHVCT284dGxhY1RGWmhOVnZXSExaeUoKczFnSTJna2JBdHFyU3F2b1IrWGM0SWwxRWpTK2xscmd5a0Vvc25HaFlaK3Z5SE5VZTd3c3Ntb1lSVkRrYzBWSwpPVzA2d1FEL2lsQXZmbnptKytXcGZ6VjE2dWxzYjZuK2I0V2JBa3VHaVluVjU0SExvQlFFdENUVVk3eERUQkMwCldOSU9TODNkcjRqUVJhcHZpZE5kT25ZRUpZK3J4QVNCK0RXeW1HNkgzUVAxVWNyRW54emtrU3l6R3M0MUFFa2gKZUordnNocTlYVU1UaU5GQ2NmZUplaHV4RmtDdXloVHp3YzVvNU5qeHV4ZEkrRmRvODhRdXh6L1pwNnJzcUtBeQppUWZHRjhqZFRmOFBIZmxuWHliMFU4NmZuUjJsSEs5VjZJeHlUdEVLRGZLR0FzSHZoTEQ5UThuckVqeGhpbEFTCnNhb1NrWXcvcjV2VTRDVDdoaUR0WS91eE5mWk9JWjhBOFI0eFNoV2RGSDlxZktieVRGeWY3MUgxYUZzQ0F3RUEKQVFLQ0FnQVNpbytTaWNKS2dleUpRZVJDTWNTeEQzVTQ4YzQzUko3OTQ2elpwNVRscy9NVTQ2czl5aGdudGVmOAoxTEh1dE9TcVNhOUw4Mzk4cEhGMXk4enJKU3RWWFF3RU56Z3VJaFg1TDlKb2VnakRucG5sRTdHZUVWWmZlcGlIClJPNk9NWkp2VUc0TzZOdlM3MFJOcmR1TkprK01RYXplUHNUSW1nYWplSnNMT1ZUNFZTWHZVbzFiSjlNemo5TkcKYTBFMWsyOE9LS01JenAwR1BsdFdNOEVQSDVWUFB1a1ZEelIwQm80OU5Ddlp4T1YyRUpXMGYvdGg4RWRsVVFTcwpsbWhhdUlTV3kyMlJMcnV6VFlVK1JYczJ5R2thc05CMHZGZXBieWRzZTdDNU82THdMaHBmdmZiVklDcnlqQWZJCmdCdjlnOGduL2RMQnQ2MElOLytKam1JaHBZV3ZqVjFCSGVZT29mSG1VWlJJOGwrcld0QjhNeCtsY21SS0FoQlkKdXhwbVRDU3JJczQyQ3loaFBJMk5Uak9GRUNxcU55eUpNM3dxQTBQV3BlMWZadUVmNTFNK3ZpUEdBNWxHUW5UZgp1c05teW9rMklMWUJPVS9EK0Q3U3V3Mml0TExvV2dtNk9PeVZ5TWIrV2dOM1ZMMFp0T3VpclAvYmpaNGt4cTlHClZKcDF3bWdCZHRzQjZlRGFyTEtwNlJpSmlabk4yRWtGTkRsQld5NTFwRTMrU1BEeXdvOXFMMHNXdTdJMk5LSEgKckxxbjk4ODFCcmVNa2lZajRmVWc1U2dZZFBHVlovc25CcloxT1IwNnArWm5BYzg5YmF2dFFmQWpLc2pXWDdYZQpCYXZYNHFPTnYyNnhCaWxaSzllYnZiVWdSTWM4UEZkSGtuakFiSDZLSkJsQktrMnhBUUtDQVFFQTBNbVVCcHIvCngxbnRKZUFEQkJkSVh3UGpJUjVXR1RwTHFlRWF4RG45UGorRFhnSWc2aUxVcFowRXU3dVRIZFVGejc3Y1UyZWcKcWxxRitQRUN4dTBVdU0zbjd1SUxXMy9Bb25EUTh5RmxZRDlaYTM4QVpjSGh0QWxmQjRTMnZsTnpIZ2FQWVdXaApJVkpxbFdWVE0vdGY3Y3VQV0hUazltMnptYmdGaWsvNzYyWDBvdExneUhpWHd6UHZuOTgzR2hkaVBxak91bUNrCjlCR2Joc25kaE9YTDV3Q21HYklvZGFBRS92dVY1QUtsWFl1YitnOXFXbFFwb3dwNzU5ZE9aeldBdklHQmNwSTkKRG1BZ3NzVXBmQnhGSEhFVGg1V2Vpamtpd1lDTld3cHFYMis2UXUvMHFXR01Bc3EyUlVNR0JwWldaRlFMNmtWTAovRkZjNWpLbE82ZjFBUUtDQVFFQTMwcXhMb2ZybXJadFlidkxGOG9ZbTQ4U2ZMQk9tV1hKdHJia2dqcGxSaU1PCnZFZDZMQ2VmTW43ekZWei9Yb1N3N1ZEWFpVenZ0dEVlQnpQSy9HVHR2TU5BMGZyM0VScmE1OGUyeXg5ZFNqN2wKZGJ1QitDQjBGWW1Jc1dTemE4THZWY0lkQk5nakdGVm4vMkZEd2N4OUFvdDgyUVVhOWhralVyclZvRGVuQjlNWQpRb2RYSU5Ec0FWQXFvaHJ4b3Q0azkwcE9EYjF0MHkrNERNSnlhY2VKbW5EcnhDQnIrVlpjZnhzcFAzY0d2Uk81CjVNTXRRbVFlbHVZWnQrL3pqcEl0RXJDR3dBRnU1UVFxNndPM2ltWHE0WjVjMEhRaG5Ga21CempYcGVrbXFTaEMKVGdxZGloNjc0VllNUDBzV3FUU3FudWc5QlJZS0ZHTWFTeDEvREx4Uld3S0NBUUVBdDY0ZmhCQW9wZ0QvR1NzUwpmQzdmaEhldkFodm1NeHVPSlUzY2RuVnR6YTJpckxuQ3F6a3BTdW53bUJoVlBSR0RvMWlPRFBKRjdwams5RFZUCjlCM3U5UVp3M1VBUUxkY2VhY3BHaVI4QVNNUnlycGQwaWhFZnQzdm5GbjR6SnczVFlMNzB0UUxyMXB6akY3dWsKano2L0RqemZSenJQazl5Ky9LVmdlbVlUZ3V5WFpBZVJxY3d0OTVWaFlvekZ0VGFOUUFMU25EVVo2WDcwRElqYgpVV2U1RXVrSE4rUDhwRDY3Sm5lL1RuRGxlbjZ3SWpZZG9vb1lkMDlwNG5VUWpNd05EY29CVUFKSHBMWDlEa2xXClRkR3hHMngvZWZDdklYdFNrRm5BQWpBUGxSWitEeFY3Y09oWWZMeEp6blZBZjlzUzlnRGEycWRNU2hacVhEcUMKRXhHWUFRS0NBUUVBcnNaRzh6WGVXMFhKVGdOd3p4a1hzOE1ENUdjWHpvZldvRlo5ZTlWN2FhK05IQ0FTWjdkSApxMzJraFNjNmwxL2pJSTN6V3M0aW40VUZMUHdFT1JSQzVVb3JWWEJMcks3Smd6eFdQcDA1SnlFZDk4NGh4L2FYCkJqaVZyc3cwaC9lWDRCZEZJWUtQemI4ajNNZmtBakF0OVN6N050OEJJSG5DcFVHcWJuTEJJYVhBU21xbTd2KzQKaXJxVjlEYUV4a2Q4eGJiNmExVEhQdE1PQzZhemFVcU8wVHpydmFMbkFNM3hMbWd6SEFMdFdsZXpYSFRNMnplRQpuZlpUVVI3WEU5UWt4WWs0bjljL1ZyQ3hheXlJb0NKdis5TTVzTXdGZHR4c29LQ0VZcytndkN6UDRVZjcwWjJHCno3VExkMHN0M0psbHAyWCtSUm5nSDk4R09KOUl6ODRqR3dLQ0FRRUFxV0REby9IalYxaWZ0SGFVZHBKTWRVMXkKSjljUEtRVTVaUGw1NG9zcEc3RHo0a25OVEhwWFZBRjhCSUhmelRpd3QxOTdmdGlQaHRyRnc4aFBsYWpHdkJOKwpXZWx5eEI1MVBWbWxxOWN2enprOGVFNVJmM2t0NHl1djFyczNUb1ZZUlRKZlB4bGQ4K09xUWhXYXhZVEVHem5yCmptZ3NNaUNQUlkyemMrQ2FKeUd5S0ZFMjA3QXlXQ0VjTjVhZHhaV0gySXo2M3BZYnVHK3pJdGlhd01HODhMWEIKeDlFRGlRdjMyR05Ua1B4ODdEL2h5MThnM2d5dEhIendpQUJZZmVMUDJpeVFHb1pucC8zM0pSMzNiWWhLL3FKQQpMNU9LN25oVUR1azM3cEQ5NkhNNWxmbjRiTHhzVUt3U2xZMUJ0SmM0RW5EUmZQMG84Y2VNMzJqeUVMbzhWZz09Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.34.0\n        disablePodSecurityPolicy: true\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.34.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.34.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.34.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRYWFxck1lRnRHeEpibHM3NFo1VWhCekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEkxTURreU1qQTNNekF4TmxvWERUTTFNRGt5TURBM016QXhObG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkkzYzc3VjNlc2t5CkFvK3YyR1EweXJrZlZOVk5rVDZCNkZDS2FwOU9ZcFpPck53T2FFbFRKTGczYjh0WCtma1lFS0g1TWdTcVlvRXEKMXhnM3NCZGJLN1dqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUkRDbjhPVGJ0dnlFCktTWnZXK1ZRT0orcFFuRXdDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFL0hSckNjOXFSNWpCT3dlS2MzcWJKTG4KenU0MWNRMEd5VkFZeVRHVm9lRUNJUUNPMHEvaFpHenRyK2JRL05aSTljQW9hcVNBd1BFYUk1SWx0VC9wNE83WApQUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhvZDhtNFk3aXNNYloyTTdqQ0UxYU85MGhob3dVSHhFQnBPdi9pWTJRUGdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFamR6dnRYZDZ5VElDajYvWVpEVEt1UjlVMVUyUlBvSG9VSXBxbjA1aWxrNnMzQTVvU1ZNawp1RGR2eTFmNStSZ1FvZmt5QktwaWdTclhHRGV3RjFzcnRRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello-foo\n      mountPath: /etc/foo\nenvironment:\n    - FOO=BAR\n    - BAR=FOO\n"
  },
  {
    "path": "pkg/machinery/config/configdiff/testdata/original.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n  type: controlplane\n  token: 2to1o4.gtwik66aods4cznj\n  ca:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBaCsrS0JQcURzL2EyeTgyMXhRak9CekFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qVXdPVEl5TURjek1ERTJXaGNOTXpVd09USXdNRGN6TURFMldqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUU3dEthbTdaRUdsNTVUeDVzVDZWRmhKZDJVVFh1Z2g0MjlSCjZvVVk1WkxFbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkZ5dGhPT3ZpVzFYa3dHNAo1ZTdHVUtFSjhSSmtNQVVHQXl0bGNBTkJBRGhMclN0YTFlY1QwNFdVQ1YxYzZQOFVjVkpRTmNhMUl2RGxTQ3hwCm9vZzdudUJxdWxCRFdYVkFqQm9TTGU5VlV6aWQ3dTc4MDdIaHNzeFBneW03b2dRPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR3BNOE1iSnplQXpYZ2xXNGRQcDFtUnMvV1lkYU1Nbjl2T0M3QUVXQU5MKwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n  certSANs: []\n  kubelet:\n    image: ghcr.io/siderolabs/kubelet:v1.34.0\n    defaultRuntimeSeccompProfileEnabled: true\n    disableManifestsDirectory: true\n  network: {}\n  install:\n    wipe: false\n  features:\n    rbac: true\n    stableHostname: true\n    apidCheckExtKeyUsage: true\n    diskQuotaSupport: true\n    kubePrism:\n      enabled: true\n      port: 7445\n    hostDNS:\n      enabled: true\n      forwardKubeDNSToHost: true\n  nodeLabels:\n    node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n  id: DyOHp_FdDYr54RvtQR6SKyda2dshZkiUE_y0CQH1wFY=\n  secret: Ig7Us67kfx01ascq3Q44GXA9P9b62iFKuYRV04Fntl8=\n  controlPlane:\n    endpoint: https://[fdae:41e4:649b:9303::1]:10000\n  clusterName: talos-default\n  network:\n    dnsDomain: cluster.local\n    podSubnets:\n      - 10.244.0.0/16\n    serviceSubnets:\n      - 10.96.0.0/12\n  token: ipovvu.zu2q1qef8u1ghx5p\n  secretboxEncryptionSecret: g9/DQ6uJ+MuVLcNHLmrOgfeq5kD7SoJic7U7T74PanI=\n  ca:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpakNDQVMrZ0F3SUJBZ0lRSkJ5azVFYTB1STRUSHc3cG5Ob0E4ekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSTFNRGt5TWpBM016QXhObG9YRFRNMU1Ea3lNREEzTXpBeApObG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQVc2ZC9BQUxOYi9tYklvYUIzUzg2Z2kzTWVrYU9RbFpGdkZ0dkZ2S29COUpzeWR3Q1E1MDlSQW1MNWcKSDFvOWhLbjBoRlVNM0NaSXBWYlppT2JoY09DallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVvWWtIOUZocFRLdlpudDdCYVlMbXhFMjF0UXN3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loQUtINmI3cnYKMmhuT1VhUjlkcVRpdURNOGpiVVVpSFo2RStuU1YzdG9qdlhKQWlFQTdGWUZxYjZFT21TTDUwNXo0VjJtZHJYQQpnWHBzK3R5NzUxckl1RGpFY0gwPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1OVTB1YnBKa1JPdnlYbndkdGNVNHFxQTdZZkdNdENiZk02SThXUnhtMkZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQmJwMzhBQXMxditac2lob0hkTHpxQ0xjeDZSbzVDVmtXOFcyOFc4cWdIMG16SjNBSkRuVAoxRUNZdm1BZldqMkVxZlNFVlF6Y0praWxWdG1JNXVGdzRBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n  aggregatorCA:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFhZ0F3SUJBZ0lSQU5sOElMcm05c1BzZ3Z5K0xKbUhWRGt3Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU5UQTVNakl3TnpNd01UWmFGdzB6TlRBNU1qQXdOek13TVRaYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVNsSFBsbk9aSFZsbkRmdUhvNE0raWpqcTY1dUkzUTY4aE45UVBlWU9ZbTlNVVE0V3hyCnA2SjdwbGw3dWQvcFZVaUNyMVBVb0gxUWNHVGs2T09JanhKaG8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGRHhaZTFEU05nUzF3SE8xK2UySTgvNkVYL2pOTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklRQ0dXK0xlMTJOUS9Dd0czVitiUWZ1andRYkZwUmNYLzhZV052TllOZS9GdlFJZ2Z6VGw0VVJZVVdvejlDMzMKdGpLaEkvOFFIKy9jczQzODFrVDkwbGNVMEtrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFGbFo3RG9acStCdldMWExmMDFwcDB3RGpUeE5pa0swQkozS2JsL3NPaEJvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFcFJ6NVp6bVIxWlp3MzdoNk9EUG9vNDZ1dWJpTjBPdklUZlVEM21EbUp2VEZFT0ZzYTZlaQplNlpaZTduZjZWVklncTlUMUtCOVVIQms1T2pqaUk4U1lRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n  serviceAccount:\n    key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS2dJQkFBS0NBZ0VBdGh5Q3Q5MVpPem9SdTNTaWNsOFJVTnpzdkg3T3BQZ3AvaEdqZVFzZzFWbU80N3ZLCkhOMUxvY1kvTjhEZ3plZnJqc0YzU1ZSZGl2RDd4UXB4bzZmR2pDckxDNU9YZHdyRUVCc2wzQ1QwdzdpZXE5UFUKR1lNT3ROdXZ1M1QwRGIxMVZ1QW1wZVNzUWVEdXJPeDJEY1NzaEdrK2NEVTNJS2xsb2U5VWtuOVllck5MN1JEUAp0R0wvdy9VaTA3QWJXVWkvYnM5RFN1V2QybXBmdnVWSnJaTS9icTBwQ0NBaDR1c29jcnM2OHA2ZG01akpGT3E0CnA1SlN2YWxBemhHNUdwQllyVU54WUlXejJCR3JaTis3dDhlc2V1eEVIeHVCT284dGxhY1RGWmhOVnZXSExaeUoKczFnSTJna2JBdHFyU3F2b1IrWGM0SWwxRWpTK2xscmd5a0Vvc25HaFlaK3Z5SE5VZTd3c3Ntb1lSVkRrYzBWSwpPVzA2d1FEL2lsQXZmbnptKytXcGZ6VjE2dWxzYjZuK2I0V2JBa3VHaVluVjU0SExvQlFFdENUVVk3eERUQkMwCldOSU9TODNkcjRqUVJhcHZpZE5kT25ZRUpZK3J4QVNCK0RXeW1HNkgzUVAxVWNyRW54emtrU3l6R3M0MUFFa2gKZUordnNocTlYVU1UaU5GQ2NmZUplaHV4RmtDdXloVHp3YzVvNU5qeHV4ZEkrRmRvODhRdXh6L1pwNnJzcUtBeQppUWZHRjhqZFRmOFBIZmxuWHliMFU4NmZuUjJsSEs5VjZJeHlUdEVLRGZLR0FzSHZoTEQ5UThuckVqeGhpbEFTCnNhb1NrWXcvcjV2VTRDVDdoaUR0WS91eE5mWk9JWjhBOFI0eFNoV2RGSDlxZktieVRGeWY3MUgxYUZzQ0F3RUEKQVFLQ0FnQVNpbytTaWNKS2dleUpRZVJDTWNTeEQzVTQ4YzQzUko3OTQ2elpwNVRscy9NVTQ2czl5aGdudGVmOAoxTEh1dE9TcVNhOUw4Mzk4cEhGMXk4enJKU3RWWFF3RU56Z3VJaFg1TDlKb2VnakRucG5sRTdHZUVWWmZlcGlIClJPNk9NWkp2VUc0TzZOdlM3MFJOcmR1TkprK01RYXplUHNUSW1nYWplSnNMT1ZUNFZTWHZVbzFiSjlNemo5TkcKYTBFMWsyOE9LS01JenAwR1BsdFdNOEVQSDVWUFB1a1ZEelIwQm80OU5Ddlp4T1YyRUpXMGYvdGg4RWRsVVFTcwpsbWhhdUlTV3kyMlJMcnV6VFlVK1JYczJ5R2thc05CMHZGZXBieWRzZTdDNU82THdMaHBmdmZiVklDcnlqQWZJCmdCdjlnOGduL2RMQnQ2MElOLytKam1JaHBZV3ZqVjFCSGVZT29mSG1VWlJJOGwrcld0QjhNeCtsY21SS0FoQlkKdXhwbVRDU3JJczQyQ3loaFBJMk5Uak9GRUNxcU55eUpNM3dxQTBQV3BlMWZadUVmNTFNK3ZpUEdBNWxHUW5UZgp1c05teW9rMklMWUJPVS9EK0Q3U3V3Mml0TExvV2dtNk9PeVZ5TWIrV2dOM1ZMMFp0T3VpclAvYmpaNGt4cTlHClZKcDF3bWdCZHRzQjZlRGFyTEtwNlJpSmlabk4yRWtGTkRsQld5NTFwRTMrU1BEeXdvOXFMMHNXdTdJMk5LSEgKckxxbjk4ODFCcmVNa2lZajRmVWc1U2dZZFBHVlovc25CcloxT1IwNnArWm5BYzg5YmF2dFFmQWpLc2pXWDdYZQpCYXZYNHFPTnYyNnhCaWxaSzllYnZiVWdSTWM4UEZkSGtuakFiSDZLSkJsQktrMnhBUUtDQVFFQTBNbVVCcHIvCngxbnRKZUFEQkJkSVh3UGpJUjVXR1RwTHFlRWF4RG45UGorRFhnSWc2aUxVcFowRXU3dVRIZFVGejc3Y1UyZWcKcWxxRitQRUN4dTBVdU0zbjd1SUxXMy9Bb25EUTh5RmxZRDlaYTM4QVpjSGh0QWxmQjRTMnZsTnpIZ2FQWVdXaApJVkpxbFdWVE0vdGY3Y3VQV0hUazltMnptYmdGaWsvNzYyWDBvdExneUhpWHd6UHZuOTgzR2hkaVBxak91bUNrCjlCR2Joc25kaE9YTDV3Q21HYklvZGFBRS92dVY1QUtsWFl1YitnOXFXbFFwb3dwNzU5ZE9aeldBdklHQmNwSTkKRG1BZ3NzVXBmQnhGSEhFVGg1V2Vpamtpd1lDTld3cHFYMis2UXUvMHFXR01Bc3EyUlVNR0JwWldaRlFMNmtWTAovRkZjNWpLbE82ZjFBUUtDQVFFQTMwcXhMb2ZybXJadFlidkxGOG9ZbTQ4U2ZMQk9tV1hKdHJia2dqcGxSaU1PCnZFZDZMQ2VmTW43ekZWei9Yb1N3N1ZEWFpVenZ0dEVlQnpQSy9HVHR2TU5BMGZyM0VScmE1OGUyeXg5ZFNqN2wKZGJ1QitDQjBGWW1Jc1dTemE4THZWY0lkQk5nakdGVm4vMkZEd2N4OUFvdDgyUVVhOWhralVyclZvRGVuQjlNWQpRb2RYSU5Ec0FWQXFvaHJ4b3Q0azkwcE9EYjF0MHkrNERNSnlhY2VKbW5EcnhDQnIrVlpjZnhzcFAzY0d2Uk81CjVNTXRRbVFlbHVZWnQrL3pqcEl0RXJDR3dBRnU1UVFxNndPM2ltWHE0WjVjMEhRaG5Ga21CempYcGVrbXFTaEMKVGdxZGloNjc0VllNUDBzV3FUU3FudWc5QlJZS0ZHTWFTeDEvREx4Uld3S0NBUUVBdDY0ZmhCQW9wZ0QvR1NzUwpmQzdmaEhldkFodm1NeHVPSlUzY2RuVnR6YTJpckxuQ3F6a3BTdW53bUJoVlBSR0RvMWlPRFBKRjdwams5RFZUCjlCM3U5UVp3M1VBUUxkY2VhY3BHaVI4QVNNUnlycGQwaWhFZnQzdm5GbjR6SnczVFlMNzB0UUxyMXB6akY3dWsKano2L0RqemZSenJQazl5Ky9LVmdlbVlUZ3V5WFpBZVJxY3d0OTVWaFlvekZ0VGFOUUFMU25EVVo2WDcwRElqYgpVV2U1RXVrSE4rUDhwRDY3Sm5lL1RuRGxlbjZ3SWpZZG9vb1lkMDlwNG5VUWpNd05EY29CVUFKSHBMWDlEa2xXClRkR3hHMngvZWZDdklYdFNrRm5BQWpBUGxSWitEeFY3Y09oWWZMeEp6blZBZjlzUzlnRGEycWRNU2hacVhEcUMKRXhHWUFRS0NBUUVBcnNaRzh6WGVXMFhKVGdOd3p4a1hzOE1ENUdjWHpvZldvRlo5ZTlWN2FhK05IQ0FTWjdkSApxMzJraFNjNmwxL2pJSTN6V3M0aW40VUZMUHdFT1JSQzVVb3JWWEJMcks3Smd6eFdQcDA1SnlFZDk4NGh4L2FYCkJqaVZyc3cwaC9lWDRCZEZJWUtQemI4ajNNZmtBakF0OVN6N050OEJJSG5DcFVHcWJuTEJJYVhBU21xbTd2KzQKaXJxVjlEYUV4a2Q4eGJiNmExVEhQdE1PQzZhemFVcU8wVHpydmFMbkFNM3hMbWd6SEFMdFdsZXpYSFRNMnplRQpuZlpUVVI3WEU5UWt4WWs0bjljL1ZyQ3hheXlJb0NKdis5TTVzTXdGZHR4c29LQ0VZcytndkN6UDRVZjcwWjJHCno3VExkMHN0M0psbHAyWCtSUm5nSDk4R09KOUl6ODRqR3dLQ0FRRUFxV0REby9IalYxaWZ0SGFVZHBKTWRVMXkKSjljUEtRVTVaUGw1NG9zcEc3RHo0a25OVEhwWFZBRjhCSUhmelRpd3QxOTdmdGlQaHRyRnc4aFBsYWpHdkJOKwpXZWx5eEI1MVBWbWxxOWN2enprOGVFNVJmM2t0NHl1djFyczNUb1ZZUlRKZlB4bGQ4K09xUWhXYXhZVEVHem5yCmptZ3NNaUNQUlkyemMrQ2FKeUd5S0ZFMjA3QXlXQ0VjTjVhZHhaV0gySXo2M3BZYnVHK3pJdGlhd01HODhMWEIKeDlFRGlRdjMyR05Ua1B4ODdEL2h5MThnM2d5dEhIendpQUJZZmVMUDJpeVFHb1pucC8zM0pSMzNiWWhLL3FKQQpMNU9LN25oVUR1azM3cEQ5NkhNNWxmbjRiTHhzVUt3U2xZMUJ0SmM0RW5EUmZQMG84Y2VNMzJqeUVMbzhWZz09Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==\n  apiServer:\n    image: registry.k8s.io/kube-apiserver:v1.34.0\n    certSANs: []\n    disablePodSecurityPolicy: true\n    admissionControl:\n      - name: PodSecurity\n        configuration:\n          apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n          defaults:\n            audit: restricted\n            audit-version: latest\n            enforce: baseline\n            enforce-version: latest\n            warn: restricted\n            warn-version: latest\n          exemptions:\n            namespaces:\n              - kube-system\n            runtimeClasses: []\n            usernames: []\n          kind: PodSecurityConfiguration\n    auditPolicy:\n      apiVersion: audit.k8s.io/v1\n      kind: Policy\n      rules:\n        - level: Metadata\n  controllerManager:\n    image: registry.k8s.io/kube-controller-manager:v1.34.0\n  proxy:\n    image: registry.k8s.io/kube-proxy:v1.34.0\n  scheduler:\n    image: registry.k8s.io/kube-scheduler:v1.34.0\n  discovery:\n    enabled: true\n    registries:\n      kubernetes:\n        disabled: true\n      service: {}\n  etcd:\n    ca:\n      crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRYWFxck1lRnRHeEpibHM3NFo1VWhCekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEkxTURreU1qQTNNekF4TmxvWERUTTFNRGt5TURBM016QXhObG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkkzYzc3VjNlc2t5CkFvK3YyR1EweXJrZlZOVk5rVDZCNkZDS2FwOU9ZcFpPck53T2FFbFRKTGczYjh0WCtma1lFS0g1TWdTcVlvRXEKMXhnM3NCZGJLN1dqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUkRDbjhPVGJ0dnlFCktTWnZXK1ZRT0orcFFuRXdDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFL0hSckNjOXFSNWpCT3dlS2MzcWJKTG4KenU0MWNRMEd5VkFZeVRHVm9lRUNJUUNPMHEvaFpHenRyK2JRL05aSTljQW9hcVNBd1BFYUk1SWx0VC9wNE83WApQUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n      key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhvZDhtNFk3aXNNYloyTTdqQ0UxYU85MGhob3dVSHhFQnBPdi9pWTJRUGdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFamR6dnRYZDZ5VElDajYvWVpEVEt1UjlVMVUyUlBvSG9VSXBxbjA1aWxrNnMzQTVvU1ZNawp1RGR2eTFmNStSZ1FvZmt5QktwaWdTclhHRGV3RjFzcnRRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n  - content: hello-bar\n    mountPath: /etc/bar\n  - content: hello-foobar\n    mountPath: /etc/foobar\nenvironment:\n  - FOO=BAR\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\n"
  },
  {
    "path": "pkg/machinery/config/configloader/configloader.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package configloader provides methods to load Talos config.\npackage configloader\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader/internal/decoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types\" // import config types to register them\n)\n\n// ErrNoConfig is returned when no configuration was found in the input.\nvar ErrNoConfig = errors.New(\"config not found\")\n\n// newConfig initializes and returns a Configurator.\nfunc newConfig(r io.Reader, opt ...Opt) (config config.Provider, err error) {\n\tvar opts Opts\n\n\tfor _, o := range opt {\n\t\to(&opts)\n\t}\n\n\tdec := decoder.NewDecoder()\n\n\tvar buf bytes.Buffer\n\n\t// preserve the original contents\n\tr = io.TeeReader(r, &buf)\n\n\tmanifests, err := dec.Decode(r, opts.allowPatchDelete)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(manifests) == 0 {\n\t\treturn nil, ErrNoConfig\n\t}\n\n\treturn container.NewReadonly(buf.Bytes(), manifests...)\n}\n\n// NewFromFile will take a filepath and attempt to parse a config file from it.\nfunc NewFromFile(filepath string) (config.Provider, error) {\n\tf, err := os.Open(filepath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\treturn newConfig(f)\n}\n\n// NewFromReader will take a reader and attempt to parse a config file from it.\nfunc NewFromReader(f io.Reader) (config.Provider, error) {\n\treturn newConfig(f)\n}\n\n// NewFromStdin initializes a config provider by reading from stdin.\nfunc NewFromStdin() (config.Provider, error) {\n\treturn newConfig(os.Stdin)\n}\n\n// NewFromBytes will take a byteslice and attempt to parse a config file from it.\nfunc NewFromBytes(source []byte, o ...Opt) (config.Provider, error) {\n\treturn newConfig(bytes.NewReader(source), o...)\n}\n\n// Opts represents the options for the config loader.\ntype Opts struct {\n\tallowPatchDelete bool\n}\n\n// Opt is a functional option for the config loader.\ntype Opt func(*Opts)\n\n// WithAllowPatchDelete allows the loader to parse patch delete operations.\nfunc WithAllowPatchDelete() Opt {\n\treturn func(o *Opts) {\n\t\to.allowPatchDelete = true\n\t}\n}\n\n// Selector represents a delete selector for a document.\ntype Selector = decoder.Selector\n\n// ErrZeroedDocument is returned when the document is empty after applying the delete selector.\nvar ErrZeroedDocument = decoder.ErrZeroedDocument\n\n// ErrLookupFailed is returned when the lookup failed.\nvar ErrLookupFailed = decoder.ErrLookupFailed\n"
  },
  {
    "path": "pkg/machinery/config/configloader/configloader_fuzz_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configloader_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc FuzzConfigLoader(f *testing.F) {\n\tfiles, err := filepath.Glob(filepath.Join(\"testdata\", \"*.test\"))\n\trequire.NoError(f, err)\n\n\tfor _, file := range files {\n\t\tb, err := os.ReadFile(file)\n\t\trequire.NoError(f, err)\n\t\tf.Add(b)\n\t}\n\n\tf.Add([]byte(\":   \\xea\"))\n\tf.Add([]byte(nil))\n\tf.Add([]byte(\"\"))\n\n\tf.Fuzz(func(t *testing.T, b []byte) {\n\t\tt.Parallel()\n\n\t\ttestConfigLoaderBytes(t, b, false)\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/configloader_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configloader_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n)\n\n// callMethods calls obj's \"getter\" methods recursively and fails on panic.\n//\n//nolint:gocyclo\nfunc callMethods(t testing.TB, obj reflect.Value, chain ...string) {\n\tt.Helper()\n\n\tif (obj.Kind() == reflect.Interface || obj.Kind() == reflect.Pointer) && obj.IsNil() {\n\t\treturn\n\t}\n\n\ttyp := obj.Type()\n\n\tfor i := range obj.NumMethod() {\n\t\tmethod := obj.Method(i)\n\n\t\tif method.Type().NumIn() != 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tmethodName := typ.Method(i).Name\n\t\tnextChain := make([]string, len(chain)+1)\n\t\tcopy(nextChain, chain)\n\t\tnextChain[len(nextChain)-1] = methodName\n\t\t// t.Log(nextChain)\n\n\t\t// skip known broken methods\n\t\tswitch methodName {\n\t\tcase \"GetRSAKey\", \"GetEd25519Key\", \"GetECDSAKey\", \"GetCert\", \"GetKey\":\n\t\t\tfallthrough\n\t\tcase \"MarshalYAML\":\n\t\t\tfallthrough\n\t\tcase \"Doc\":\n\t\t\tfallthrough\n\t\tcase \"APIUrl\":\n\t\t\tfallthrough\n\t\tcase \"Endpoint\":\n\t\t\t// t.Logf(\"Skipping %v\", nextChain)\n\t\t\tcontinue\n\t\t}\n\n\t\tvar resS []reflect.Value\n\n\t\trequire.NotPanics(t, func() { resS = method.Call(nil) }, \"Method chain: %v\", nextChain)\n\n\t\tif len(resS) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tres := resS[0]\n\n\t\t// skip result if it has the same type\n\t\t// to avoid infinite recursion on methods like DeepCopy\n\t\tif res.Type() == typ {\n\t\t\tcontinue\n\t\t}\n\n\t\tcallMethods(t, res, nextChain...)\n\t}\n}\n\nfunc testConfigLoaderBytes(t testing.TB, b []byte, failOnError bool) {\n\tt.Helper()\n\n\tp, err := configloader.NewFromBytes(b)\n\tif err != nil {\n\t\tif failOnError {\n\t\t\tt.Fatalf(\"Failed to load: %s.\", err)\n\t\t} else {\n\t\t\tt.Skipf(\"Failed to load, skipping: %s.\", err)\n\t\t}\n\t}\n\n\tcallMethods(t, reflect.ValueOf(p))\n}\n\n// TODO(aleksi): maybe remove once Go 1.18 is out; see https://github.com/golang/go/issues/47413\nfunc TestConfigLoader(t *testing.T) {\n\tt.Parallel()\n\n\tfiles, err := filepath.Glob(filepath.Join(\"testdata\", \"*.test\"))\n\trequire.NoError(t, err)\n\n\tfor _, file := range files {\n\t\tt.Run(file, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tb, err := os.ReadFile(file)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestConfigLoaderBytes(t, b, true)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/decoder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package decoder provides a YAML decoder for machine configuration documents.\npackage decoder\n\nimport (\n\t\"cmp\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/siderolabs/gen/xyaml\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n)\n\n// ErrMissingKind indicates that the manifest is missing a kind.\nvar ErrMissingKind = errors.New(\"missing kind\")\n\n// ErrMissingAPIVersion indicates that the manifest is missing an apiVersion.\nvar ErrMissingAPIVersion = errors.New(\"missing apiVersion\")\n\nconst (\n\t// ManifestAPIVersionKey is the string indicating a manifest's version.\n\tManifestAPIVersionKey = \"apiVersion\"\n\t// ManifestKindKey is the string indicating a manifest's kind.\n\tManifestKindKey = \"kind\"\n\t// ManifestDeprecatedKeyMachine represents the deprecated v1alpha1 manifest.\n\tManifestDeprecatedKeyMachine = \"machine\"\n\t// ManifestDeprecatedKeyCluster represents the deprecated v1alpha1 manifest.\n\tManifestDeprecatedKeyCluster = \"cluster\"\n\t// ManifestDeprecatedKeyDebug represents the deprecated v1alpha1 manifest.\n\tManifestDeprecatedKeyDebug = \"debug\"\n\t// ManifestDeprecatedKeyPersist represents the deprecated v1alpha1 manifest.\n\tManifestDeprecatedKeyPersist = \"persist\"\n)\n\n// Decoder represents a multi-doc YAML decoder.\ntype Decoder struct{}\n\n// Decode decodes all known manifests.\nfunc (d *Decoder) Decode(r io.Reader, allowPatchDelete bool) ([]config.Document, error) {\n\treturn parse(r, allowPatchDelete)\n}\n\n// NewDecoder initializes and returns a `Decoder`.\nfunc NewDecoder() *Decoder {\n\treturn &Decoder{}\n}\n\ntype documentID struct {\n\tAPIVersion string\n\tKind       string\n\tName       string\n}\n\n//nolint:gocyclo\nfunc parse(r io.Reader, allowPatchDelete bool) (decoded []config.Document, err error) {\n\t// Recover from yaml.v3 panics because we rely on machine configuration loading _a lot_.\n\tdefer func() {\n\t\tif p := recover(); p != nil {\n\t\t\terr = fmt.Errorf(\"recovered: %v\", p)\n\t\t}\n\t}()\n\n\tdecoded = []config.Document{}\n\n\tdec := yaml.NewDecoder(r)\n\n\tdec.KnownFields(true)\n\n\tknownDocuments := map[documentID]struct{}{}\n\n\t// Iterate through all defined documents.\n\tfor i := 0; ; i++ {\n\t\tvar manifests yaml.Node\n\n\t\tif err = dec.Decode(&manifests); err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\treturn decoded, nil\n\t\t\t}\n\n\t\t\treturn nil, fmt.Errorf(\"decode error: %w\", err)\n\t\t}\n\n\t\tif manifests.Kind != yaml.DocumentNode {\n\t\t\treturn nil, fmt.Errorf(\"expected a document at line %d\", manifests.Line)\n\t\t}\n\n\t\tif allowPatchDelete {\n\t\t\tdecoded, err = AppendDeletesTo(&manifests, decoded, i)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error processing patch delete statements at line %d: %w\", manifests.Line, err)\n\t\t\t}\n\n\t\t\tif manifests.IsZero() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tfor _, manifest := range manifests.Content {\n\t\t\tswitch manifest.Kind { //nolint:exhaustive\n\t\t\tcase yaml.MappingNode:\n\t\t\t\t// expected\n\t\t\tcase yaml.ScalarNode:\n\t\t\t\tif manifest.Tag == \"!!null\" {\n\t\t\t\t\t// skip null documents\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"expected a YAML document at line %d\", manifest.Line)\n\t\t\t}\n\n\t\t\tid := documentID{\n\t\t\t\tAPIVersion: findValue(manifest, ManifestAPIVersionKey, false),\n\t\t\t\tKind:       cmp.Or(findValue(manifest, ManifestKindKey, false), \"v1alpha1\"),\n\t\t\t\tName:       findValue(manifest, \"name\", false),\n\t\t\t}\n\n\t\t\tif _, ok := knownDocuments[id]; ok {\n\t\t\t\treturn nil, fmt.Errorf(\"duplicate document %s/%s/%s is not allowed (line %d)\", id.APIVersion, id.Kind, id.Name, manifest.Line)\n\t\t\t}\n\n\t\t\tknownDocuments[id] = struct{}{}\n\n\t\t\tvar target config.Document\n\n\t\t\tif target, err = decode(manifest); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error decoding document %s/%s/%s (line %d): %w\", id.APIVersion, id.Kind, id.Name, manifest.Line, err)\n\t\t\t}\n\n\t\t\tdecoded = append(decoded, target)\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc decode(manifest *yaml.Node) (target config.Document, err error) {\n\tvar (\n\t\tversion string\n\t\tkind    string\n\t)\n\n\tfor i, node := range manifest.Content {\n\t\tswitch node.Value {\n\t\tcase ManifestKindKey:\n\t\t\tif len(manifest.Content) < i+1 {\n\t\t\t\treturn nil, errors.New(\"missing manifest content\")\n\t\t\t}\n\n\t\t\tif err = manifest.Content[i+1].Decode(&kind); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"kind decode: %w\", err)\n\t\t\t}\n\t\tcase ManifestAPIVersionKey:\n\t\t\tif len(manifest.Content) < i+1 {\n\t\t\t\treturn nil, errors.New(\"missing manifest content\")\n\t\t\t}\n\n\t\t\tif err = manifest.Content[i+1].Decode(&version); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"version decode: %w\", err)\n\t\t\t}\n\t\tcase\n\t\t\tManifestDeprecatedKeyMachine,\n\t\t\tManifestDeprecatedKeyCluster,\n\t\t\tManifestDeprecatedKeyDebug,\n\t\t\tManifestDeprecatedKeyPersist:\n\t\t\tversion = \"v1alpha1\"\n\t\t}\n\t}\n\n\tswitch {\n\tcase version == \"v1alpha1\" && kind == \"\":\n\t\ttarget, err = registry.New(\"v1alpha1\", \"\")\n\tcase kind == \"\":\n\t\terr = ErrMissingKind\n\tcase version == \"\":\n\t\terr = ErrMissingAPIVersion\n\tdefault:\n\t\ttarget, err = registry.New(kind, version)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = manifest.Decode(target); err != nil {\n\t\treturn nil, fmt.Errorf(\"error decoding %s to %T: %w\", kind, target, err)\n\t}\n\n\tif err = xyaml.CheckUnknownKeys(target, manifest); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn target, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/decoder_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage decoder_test\n\nimport (\n\t\"bytes\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader/internal/decoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\ntype Meta struct {\n\tMetaKind       string `yaml:\"kind\"`\n\tMetaAPIVersion string `yaml:\"apiVersion,omitempty\"`\n}\n\nfunc (m Meta) Kind() string {\n\treturn m.MetaKind\n}\n\nfunc (m Meta) APIVersion() string {\n\treturn m.MetaAPIVersion\n}\n\ntype Mock struct {\n\tMeta\n\n\tTest bool `yaml:\"test\"`\n}\n\nfunc (m *Mock) Clone() config.Document {\n\treturn m\n}\n\ntype MockV2 struct {\n\tMeta\n\n\tSlice []Mock           `yaml:\"slice\"`\n\tMap   map[string]*Mock `yaml:\"map\"`\n}\n\nfunc (m *MockV2) Clone() config.Document {\n\treturn m\n}\n\ntype MockV3 struct {\n\tMeta\n\n\tOmit bool `yaml:\"omit,omitempty\"`\n}\n\nfunc (m *MockV3) Clone() config.Document {\n\treturn m\n}\n\ntype KubeletConfig struct {\n\tMeta\n\tv1alpha1.KubeletConfig `yaml:\",inline\"`\n}\n\nfunc (m *KubeletConfig) Clone() config.Document {\n\treturn m\n}\n\ntype MockUnstructured struct {\n\tMeta\n\n\tPods []v1alpha1.Unstructured `yaml:\"pods,omitempty\"`\n}\n\nfunc (m *MockUnstructured) Clone() config.Document {\n\treturn m\n}\n\nfunc init() {\n\tregistry.Register(\"mock\", func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha2\":\n\t\t\treturn &MockV2{}\n\t\tcase \"v1alpha3\":\n\t\t\treturn &MockV3{}\n\t\t}\n\n\t\treturn &Mock{}\n\t})\n\n\tregistry.Register(\"kubelet\", func(string) config.Document {\n\t\treturn &KubeletConfig{}\n\t})\n\n\tregistry.Register(\"unstructured\", func(string) config.Document {\n\t\treturn &MockUnstructured{}\n\t})\n}\n\nfunc TestDecoder(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname        string\n\t\tsource      []byte\n\t\texpected    []config.Document\n\t\texpectedErr string\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha1\ntest: true\n`),\n\t\t\texpected: []config.Document{\n\t\t\t\t&Mock{\n\t\t\t\t\tTest: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty docs\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha1\ntest: true\n---\n---\n`),\n\t\t\texpected: []config.Document{\n\t\t\t\t&Mock{\n\t\t\t\t\tTest: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing kind\",\n\t\t\tsource: []byte(`---\napiVersion: v1alpha2\ntest: true\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha2/v1alpha1/ (line 2): missing kind\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty kind\",\n\t\t\tsource: []byte(`---\nkind:\napiVersion: v1alpha2\ntest: true\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha2/v1alpha1/ (line 2): missing kind\",\n\t\t},\n\t\t{\n\t\t\tname: \"tab instead of spaces\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha1\nspec:\n\ttest: true\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"decode error: yaml: while scanning for the next token at line 5: found character that cannot start any token\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra field\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha1\ntest: true\nextra: fail\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha1/mock/ (line 2): unknown keys found during decoding:\\nextra: fail\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra fields in map\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha2\nmap:\n  first:\n    test: true\n    extra: me\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha2/mock/ (line 2): unknown keys found during decoding:\\nmap:\\n    first:\\n        extra: me\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra fields in slice\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha2\nslice:\n  - test: true\n    not: working\n    more: extra\n    fields: here\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha2/mock/ (line 2): unknown keys found during decoding:\\nslice:\\n    - fields: here\\n      more: extra\\n      not: working\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra zero fields in map\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha2\nmap:\n  second:\n    a:\n      b: {}\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"error decoding document v1alpha2/mock/ (line 2): unknown keys found during decoding:\\nmap:\\n    second:\\n        a:\\n            b: {}\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid nested\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha2\nslice:\n  - test: true\nmap:\n  first:\n    test: true\n  second:\n    test: false\n`),\n\t\t\texpected: []config.Document{\n\t\t\t\t&MockV2{\n\t\t\t\t\tMap: map[string]*Mock{\n\t\t\t\t\t\t\"first\": {\n\t\t\t\t\t\t\tTest: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"second\": {\n\t\t\t\t\t\t\tTest: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSlice: []Mock{\n\t\t\t\t\t\t{Test: true},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"kubelet config\",\n\t\t\tsource: []byte(`---\nkind: kubelet\napiVersion: v1alpha1\nextraMounts:\n - destination: /var/local\n   options:\n     - rbind\n     - rshared\n     - rw\n   source: /var/local\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"omit empty test\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha3\nomit: false\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname:        \"internal error\",\n\t\t\tsource:      []byte(\":   \\xea\"),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"decode error: yaml: offset 4: incomplete UTF-8 octet sequence\",\n\t\t},\n\t\t{\n\t\t\tname: \"unstructured config\",\n\t\t\tsource: []byte(`---\nkind: unstructured\napiVersion: v1alpha1\npods:\n - destination: /var/local\n   options:\n     - rbind\n     - rw\n   source: /var/local\n   something: 1.34\n`),\n\t\t\texpected:    nil,\n\t\t\texpectedErr: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"omit empty test\",\n\t\t\tsource: []byte(`---\nkind: mock\napiVersion: v1alpha3\nomit: false\n`),\n\t\t},\n\t\t{\n\t\t\tname: \"misspelled apiVersion\",\n\t\t\tsource: []byte(`---\napiversion: v1alpha1\nkind: ExtensionServiceConfig\nconfig:\n    - name: nut-client\n      configFiles:\n          - content: MONITOR ${upsmonHost} 1 remote pass foo\n            mountPath: /usr/local/etc/nut/upsmon.conf\n`),\n\t\t\texpectedErr: \"error decoding document /ExtensionServiceConfig/ (line 2): missing apiVersion\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing apiVersion\",\n\t\t\tsource: []byte(`---\nkind: mock\ntest: true\n`),\n\t\t\texpectedErr: \"error decoding document /mock/ (line 2): missing apiVersion\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\td := decoder.NewDecoder()\n\t\t\tactual, err := d.Decode(bytes.NewReader(tt.source), false)\n\n\t\t\tif tt.expected != nil {\n\t\t\t\tassert.Equal(t, tt.expected, actual)\n\t\t\t}\n\n\t\t\tif tt.expectedErr == \"\" {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.EqualError(t, err, tt.expectedErr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDecoderV1Alpha1Config(t *testing.T) {\n\tt.Parallel()\n\n\tfiles, err := filepath.Glob(filepath.Join(\"testdata\", \"*.yaml\"))\n\trequire.NoError(t, err)\n\n\tfor _, file := range files {\n\t\tt.Run(file, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcontents, err := os.ReadFile(file)\n\t\t\trequire.NoError(t, err)\n\n\t\t\td := decoder.NewDecoder()\n\t\t\t_, err = d.Decode(bytes.NewReader(contents), false)\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestDoubleV1Alpha1(t *testing.T) {\n\tt.Parallel()\n\n\tfiles := os.DirFS(\"testdata/double\").(fs.ReadFileFS)\n\tcontents := must.Value(files.ReadFile(\"v1alpha1.yaml\"))(t)\n\n\td := decoder.NewDecoder()\n\t_, err := d.Decode(bytes.NewReader(contents), false)\n\trequire.Error(t, err)\n\trequire.ErrorContains(t, err, \"not allowed\")\n}\n\nfunc BenchmarkDecoderV1Alpha1Config(b *testing.B) {\n\tb.ReportAllocs()\n\n\tcontents, err := os.ReadFile(\"testdata/controlplane.yaml\")\n\trequire.NoError(b, err)\n\n\tfor b.Loop() {\n\t\td := decoder.NewDecoder()\n\t\t_, err = d.Decode(bytes.NewReader(contents), false)\n\n\t\tassert.NoError(b, err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/delete.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage decoder\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// AppendDeletesTo appends all delete selectors found in the given YAML node to the given destination slice.\nfunc AppendDeletesTo(n *yaml.Node, dest []config.Document, idx int) (_ []config.Document, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif re, ok := r.(error); ok {\n\t\t\t\terr = re\n\t\t\t}\n\t\t}\n\t}()\n\n\tallDeletes(n)(func(path []string, elem delElem) bool {\n\t\tswitch elem.parent.Kind {\n\t\tcase yaml.DocumentNode:\n\t\t\tdest = append(dest, makeSelector(path, n.Content[0], idx, \"\", \"\"))\n\t\tcase yaml.MappingNode:\n\t\t\tdest = append(dest, makeSelector(path, n.Content[0], idx, \"\", \"\"))\n\t\tcase yaml.SequenceNode:\n\t\t\tdest = append(dest, makeSequenceSelector(path, n.Content[0], elem.node, idx))\n\t\tcase yaml.ScalarNode, yaml.AliasNode, yaml.StreamNode:\n\t\t}\n\n\t\treturn true\n\t})\n\n\treturn dest, nil\n}\n\nfunc allDeletes(node *yaml.Node) func(yield func([]string, delElem) bool) {\n\treturn func(yield func([]string, delElem) bool) {\n\t\t_, okToDel := processNode(nil, node, make([]string, 0, 8), yield)\n\t\tif okToDel {\n\t\t\t*node = yaml.Node{}\n\t\t}\n\t}\n}\n\nfunc makeSequenceSelector(path []string, root, node *yaml.Node, i int) Selector {\n\tif node.Kind != yaml.MappingNode {\n\t\tpanic(errors.New(\"expected a mapping node\"))\n\t}\n\n\t// map node inside sequence node, collect the first key:val aside from $patch:delete as selector\n\tfor j := 0; j < len(node.Content)-1; j += 2 {\n\t\tkey := node.Content[j]\n\t\tval := node.Content[j+1]\n\n\t\tif val.Kind == yaml.ScalarNode && key.Value == \"$patch\" && val.Value == \"delete\" {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn makeSelector(path, root, i, key.Value, val.Value)\n\t}\n\n\tpanic(errors.New(\"no key:val found in sequence node for path \" + strings.Join(path, \".\")))\n}\n\nfunc makeSelector(path []string, root *yaml.Node, i int, key, val string) Selector {\n\tisRequired := len(path) == 0\n\n\tapiVersion := findValue(root, \"apiVersion\", isRequired)\n\tkind := findValue(root, \"kind\", isRequired)\n\n\tswitch {\n\tcase kind == \"\" && apiVersion == \"\":\n\t\tkind = v1alpha1.Version // legacy document\n\tcase kind != \"\" && apiVersion != \"\":\n\tdefault:\n\t\tpanic(fmt.Errorf(\"kind and apiVersion must be both set for path %s\", strings.Join(path, \".\")))\n\t}\n\n\tsel := selector{\n\t\tpath:          slices.Clone(path),\n\t\tdocIdx:        i,\n\t\tdocAPIVersion: apiVersion,\n\t\tdocKind:       kind,\n\t\tkey:           key,\n\t\tvalue:         val,\n\t}\n\n\tswitch name := findValue(root, \"name\", false); name {\n\tcase \"\":\n\t\treturn &sel\n\tdefault:\n\t\treturn &namedSelector{\n\t\t\tselector: sel,\n\t\t\tname:     name,\n\t\t}\n\t}\n}\n\ntype delElem struct {\n\tpath         []string\n\tparent, node *yaml.Node\n}\n\n// processNode recursively processes a YAML node, searching for a \"$patch: delete\" nodes and calling the yield function\n// with path for each one found.\n//\n//nolint:gocyclo,cyclop\nfunc processNode(\n\tparent, v *yaml.Node,\n\tpath []string,\n\tyield func(path []string, d delElem) bool,\n) (bool, bool) {\n\tif v.Kind != yaml.DocumentNode && parent == nil {\n\t\tpanic(errors.New(\"parent must be non-nil for non-document nodes\"))\n\t}\n\n\tswitch v.Kind {\n\tcase yaml.DocumentNode:\n\t\tokToCont, okToDel := processNode(v, v.Content[0], path, yield)\n\n\t\tswitch {\n\t\tcase !okToCont:\n\t\t\treturn false, okToDel\n\t\tcase okToDel:\n\t\t\treturn false, true\n\t\tdefault:\n\t\t\treturn false, isEmptyDoc(v.Content[0])\n\t\t}\n\n\tcase yaml.MappingNode:\n\t\tfor i := 0; i < len(v.Content)-1; i += 2 {\n\t\t\tkeyNode := v.Content[i]\n\t\t\tvalueNode := v.Content[i+1]\n\n\t\t\tif valueNode.Kind == yaml.ScalarNode && keyNode.Value == \"$patch\" && valueNode.Value == \"delete\" {\n\t\t\t\tif parent.Kind != yaml.SequenceNode {\n\t\t\t\t\tensureNoSeqInChain(path)\n\t\t\t\t}\n\n\t\t\t\treturn yield(path, delElem{path: path, parent: parent, node: v}), true\n\t\t\t}\n\n\t\t\tokToCont, okToDel := processNode(v, valueNode, append(path, keyNode.Value), yield)\n\t\t\tif !okToCont {\n\t\t\t\treturn false, okToDel\n\t\t\t} else if okToDel {\n\t\t\t\tv.Content = slices.Delete(v.Content, i, i+2)\n\t\t\t\ti -= 2\n\n\t\t\t\tif len(v.Content) == 0 {\n\t\t\t\t\treturn true, true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase yaml.SequenceNode:\n\t\tfor i := 0; i < len(v.Content); i++ {\n\t\t\tokToCont, okToDel := processNode(v, v.Content[i], append(path, \"[\"+strconv.Itoa(i)+\"]\"), yield)\n\t\t\tif !okToCont {\n\t\t\t\treturn false, okToDel\n\t\t\t} else if okToDel {\n\t\t\t\tv.Content = slices.Delete(v.Content, i, i+1)\n\t\t\t\ti--\n\n\t\t\t\tif len(v.Content) == 0 {\n\t\t\t\t\treturn true, true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase yaml.ScalarNode, yaml.AliasNode, yaml.StreamNode:\n\t}\n\n\treturn true, false\n}\n\nfunc isEmptyDoc(node *yaml.Node) bool {\n\tif node.Kind != yaml.MappingNode {\n\t\treturn false\n\t}\n\n\tfor i := 0; i < len(node.Content)-1; i += 2 {\n\t\tkeyNode := node.Content[i]\n\t\tval := node.Content[i+1]\n\n\t\tif keyNode.Kind != yaml.ScalarNode || val.Kind != yaml.ScalarNode {\n\t\t\treturn false\n\t\t}\n\n\t\tif keyNode.Value != \"version\" && keyNode.Value != \"kind\" && keyNode.Value != \"name\" {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc ensureNoSeqInChain(path []string) {\n\tfor _, p := range path {\n\t\tif p[0] == '[' {\n\t\t\tpanic(errors.New(\"cannot delete an inner key in '\" + strings.Join(path, \".\") + \"'\"))\n\t\t}\n\t}\n}\n\nfunc findValue(node *yaml.Node, key string, required bool) string {\n\tif node.Kind != yaml.MappingNode {\n\t\tpanic(errors.New(\"expected a mapping node\"))\n\t}\n\n\tfor i := 0; i < len(node.Content)-1; i += 2 {\n\t\tkeyNode := node.Content[i]\n\t\tval := node.Content[i+1]\n\n\t\tif keyNode.Kind == yaml.ScalarNode && keyNode.Value == key {\n\t\t\treturn val.Value\n\t\t}\n\t}\n\n\tif required {\n\t\tpanic(fmt.Errorf(\"missing %s in document for which $patch: delete is used\", key))\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/delete_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage decoder_test\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader/internal/decoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nvar (\n\t//go:embed testdata/delete/delete.yaml\n\tpatchDelete []byte\n\t//go:embed testdata/delete/delete_expected.yaml\n\tpatchDeleteExpected []byte\n)\n\nfunc TestExtractDeletes(t *testing.T) {\n\tresult, b := must.Values(extractDeletes(patchDelete))(t)\n\n\tdefer func() {\n\t\tif !t.Failed() {\n\t\t\treturn\n\t\t}\n\n\t\tfor _, sel := range result {\n\t\t\tt.Logf(\"%#v\", sel)\n\t\t}\n\t}()\n\n\trequire.Equal(t, string(patchDeleteExpected), string(b))\n\n\texpected := strings.Join(\n\t\t[]string{\n\t\t\t\"{apiVersion:v1alpha1, kind:SideroLinkConfig, idx:0}\",\n\t\t\t\"{path:configFiles.[0], apiVersion:v1alpha1, kind:ExtensionServiceConfig, key:content, value:hello, idx:1, name:foo}\",\n\t\t\t\"{path:machine.hostname, kind:v1alpha1, idx:2}\",\n\t\t\t\"{path:machine.network.[0], kind:v1alpha1, key:interface, value:eth0, idx:2}\",\n\t\t},\n\t\t\"\\n\",\n\t)\n\n\tactual := strings.Join(\n\t\txslices.Map(result, func(sel config.Document) string { return sel.(fmt.Stringer).String() }),\n\t\t\"\\n\",\n\t)\n\n\trequire.Equal(t, expected, actual)\n}\n\nfunc extractDeletes(in []byte) (result []config.Document, _ []byte, err error) {\n\tvar cleanedBytes [][]byte\n\n\tdec := yaml.NewDecoder(bytes.NewReader(in))\n\n\tfor i := 0; ; i++ {\n\t\tnode := &yaml.Node{}\n\n\t\terr = dec.Decode(node)\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tresult, err = decoder.AppendDeletesTo(node, result, i)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tif !node.IsZero() {\n\t\t\tb, err := encoder.NewEncoder(node, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\n\t\t\tcleanedBytes = append(cleanedBytes, b)\n\t\t}\n\t}\n\n\treturn result, bytes.Join(cleanedBytes, []byte(\"---\\n\")), nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/selector.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage decoder\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n// Selector represents a delete selector for a document.\ntype Selector interface {\n\tconfig.Document\n\tDocIdx() int\n\tApplyTo(config.Document) error\n}\n\ntype selector struct {\n\tpath          []string\n\tdocIdx        int\n\tdocAPIVersion string\n\tdocKind       string\n\tkey           string\n\tvalue         string\n}\n\nfunc (s *selector) Kind() string           { return s.docKind }\nfunc (s *selector) APIVersion() string     { return s.docAPIVersion }\nfunc (s *selector) Clone() config.Document { return new(s.clone()) }\nfunc (s *selector) DocIdx() int            { return s.docIdx }\n\nfunc (s *selector) PathAsString() string { return strings.Join(s.path, \".\") }\n\nfunc (s *selector) clone() selector {\n\treturn selector{\n\t\tpath:          slices.Clone(s.path),\n\t\tdocIdx:        s.docIdx,\n\t\tdocAPIVersion: s.docAPIVersion,\n\t\tdocKind:       s.docKind,\n\t\tkey:           s.key,\n\t\tvalue:         s.value,\n\t}\n}\n\nfunc (s *selector) String() string { return s.toString(\"\") }\n\nfunc (s *selector) toString(more string) string {\n\tvar builder strings.Builder\n\n\twriteThing := func(key, val string) {\n\t\tif val != \"\" {\n\t\t\tif builder.Len() > 1 {\n\t\t\t\tbuilder.WriteString(\", \")\n\t\t\t}\n\n\t\t\tbuilder.WriteString(key)\n\t\t\tbuilder.WriteRune(':')\n\t\t\tbuilder.WriteString(val)\n\t\t}\n\t}\n\n\tbuilder.WriteRune('{')\n\twriteThing(\"path\", s.PathAsString())\n\twriteThing(\"apiVersion\", s.docAPIVersion)\n\twriteThing(\"kind\", s.docKind)\n\twriteThing(\"key\", s.key)\n\twriteThing(\"value\", s.value)\n\twriteThing(\"idx\", strconv.Itoa(s.docIdx))\n\n\tif more != \"\" {\n\t\tbuilder.WriteString(\", \")\n\t\tbuilder.WriteString(more)\n\t}\n\n\tbuilder.WriteRune('}')\n\n\treturn builder.String()\n}\n\n// ErrZeroedDocument is returned when the document is empty after applying the delete selector.\nvar ErrZeroedDocument = errors.New(\"document is empty now\")\n\n// ApplyTo applies the delete selector to the given document.\nfunc (s *selector) ApplyTo(doc config.Document) error {\n\tif err := s.applyTo(doc); err != nil {\n\t\treturn fmt.Errorf(\"patch delete: path '%s' in document '%s/%s': %w\", s.PathAsString(), doc.APIVersion(), doc.Kind(), err)\n\t}\n\n\treturn nil\n}\n\nfunc (s *selector) applyTo(doc config.Document) error {\n\tif s.docKind != doc.Kind() || s.docAPIVersion != doc.APIVersion() {\n\t\treturn fmt.Errorf(\n\t\t\t\"incorrect document type for %s/%s\",\n\t\t\ts.docAPIVersion,\n\t\t\ts.docKind,\n\t\t)\n\t}\n\n\tval := reflect.ValueOf(doc)\n\n\tif val.Kind() != reflect.Pointer {\n\t\treturn fmt.Errorf(\"document type is not a pointer\")\n\t}\n\n\tif len(s.path) == 0 {\n\t\tif doc.Kind() == \"\" {\n\t\t\treturn errors.New(\"can't delete the root of the legacy document\")\n\t\t}\n\n\t\treturn ErrZeroedDocument\n\t}\n\n\terr := deleteForPath(val.Elem(), s.path, s.key, s.value)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete path '%s': %w\", s.PathAsString(), err)\n\t}\n\n\treturn nil\n}\n\nvar searchForType = reflect.TypeFor[string]()\n\n// ErrLookupFailed is returned when the lookup failed.\nvar ErrLookupFailed = errors.New(\"lookup failed\")\n\n//nolint:gocyclo,cyclop\nfunc deleteForPath(val reflect.Value, path []string, key, value string) error {\n\tif len(path) == 0 {\n\t\treturn errors.New(\"path is empty\")\n\t}\n\n\tif val.Kind() == reflect.Pointer || val.Kind() == reflect.Interface {\n\t\tif val.IsNil() {\n\t\t\treturn ErrLookupFailed\n\t\t}\n\n\t\treturn deleteForPath(val.Elem(), path, key, value)\n\t}\n\n\tsearchFor := path[0]\n\tpath = path[1:]\n\tvalType := val.Type()\n\n\tswitch val.Kind() { //nolint:exhaustive\n\tcase reflect.Struct:\n\t\t// Lookup using yaml tag\n\t\tfor i := range val.NumField() {\n\t\t\tstructField := valType.Field(i)\n\n\t\t\tyamlTagRaw, ok := structField.Tag.Lookup(\"yaml\")\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tyamlTags := strings.Split(yamlTagRaw, \",\")\n\t\t\tif yamlTags[0] == searchFor {\n\t\t\t\tif len(path) == 0 {\n\t\t\t\t\tval.Field(i).SetZero()\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn deleteForPath(val.Field(i), path, key, value)\n\t\t\t}\n\n\t\t\t// if there is an embedded struct, descend into it\n\t\t\tif len(yamlTags) > 1 && yamlTags[0] == \"\" && yamlTags[1] == \"inline\" {\n\t\t\t\terr := deleteForPath(val.Field(i), append([]string{searchFor}, path...), key, value)\n\t\t\t\tif err == nil {\n\t\t\t\t\t// value found & deleted\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t// ignore lookup failed errors, we can continue with other fields\n\t\t\t\tif !errors.Is(err, ErrLookupFailed) {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase reflect.Map:\n\t\tif val.IsNil() {\n\t\t\tbreak\n\t\t}\n\n\t\tkeyType := valType.Key()\n\n\t\t// Try assingable and convertible types for key search\n\t\tif searchForType.AssignableTo(keyType) || searchForType.ConvertibleTo(keyType) {\n\t\t\tsearchForVal := reflect.ValueOf(searchFor)\n\n\t\t\tif searchForType != keyType {\n\t\t\t\tsearchForVal = searchForVal.Convert(keyType)\n\t\t\t}\n\n\t\t\tif idx := val.MapIndex(searchForVal); idx.IsValid() {\n\t\t\t\tif len(path) == 0 {\n\t\t\t\t\tval.SetMapIndex(searchForVal, reflect.Value{})\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\treturn deleteForPath(idx, path, key, value)\n\t\t\t}\n\t\t}\n\tcase reflect.Slice:\n\t\treturn deleteStructFrom(val, searchFor, path, key, value)\n\t}\n\n\treturn ErrLookupFailed\n}\n\n//nolint:gocyclo\nfunc deleteStructFrom(searchIn reflect.Value, searchFor string, path []string, key, value string) error {\n\tswitch {\n\tcase len(path) != 0:\n\t\treturn errors.New(\"searching for complex paths in slices is not supported\")\n\tcase searchFor == \"\":\n\t\treturn errors.New(\"searching for '' in a slice is not supported\")\n\tcase searchFor[0] != '[':\n\t\treturn errors.New(\"searching for non-integer keys in slices is not supported\")\n\tcase searchIn.Kind() != reflect.Slice:\n\t\treturn errors.New(\"searching for a key in a non-slice\")\n\t}\n\n\tfor i := 0; i < searchIn.Len(); i++ { //nolint:intrange\n\t\telem := searchIn.Index(i)\n\n\t\tfor elem.Kind() == reflect.Pointer {\n\t\t\telem = elem.Elem()\n\t\t}\n\n\t\tif elem.Kind() != reflect.Struct && elem.Kind() != reflect.Map {\n\t\t\tcontinue\n\t\t}\n\n\t\telemType := elem.Type()\n\n\t\tif elem.Kind() == reflect.Struct {\n\t\t\tfor j := range elemType.NumField() {\n\t\t\t\tstructField := elemType.Field(j)\n\n\t\t\t\tyamlTagRaw, ok := structField.Tag.Lookup(\"yaml\")\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tyamlTags := strings.Split(yamlTagRaw, \",\")\n\t\t\t\tif yamlTags[0] != key {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfieldVal := elem.Field(j)\n\t\t\t\tfieldStr := fieldVal.String()\n\n\t\t\t\t// if the field value implements Stringer, use it for comparison instead of the default string conversion\n\t\t\t\tif fieldVal.CanInterface() {\n\t\t\t\t\tif stringer, ok := fieldVal.Interface().(fmt.Stringer); ok {\n\t\t\t\t\t\tfieldStr = stringer.String()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif fieldStr != value {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tsearchIn.Set(reflect.AppendSlice(searchIn.Slice(0, i), searchIn.Slice(i+1, searchIn.Len())))\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else {\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn ErrLookupFailed\n}\n\ntype namedSelector struct {\n\tselector\n\n\tname string\n}\n\nfunc (n *namedSelector) Name() string   { return n.name }\nfunc (n *namedSelector) String() string { return n.toString(\"name:\" + n.name) }\nfunc (n *namedSelector) Clone() config.Document {\n\treturn &namedSelector{selector: n.selector.clone(), name: n.name}\n}\n\n// ApplyTo applies the delete selector to the given document.\nfunc (n *namedSelector) ApplyTo(doc config.Document) error {\n\tif err := n.applyTo(doc); err != nil {\n\t\treturn fmt.Errorf(\"named patch delete: document %s/%s: %w\", doc.APIVersion(), doc.Kind(), err)\n\t}\n\n\treturn nil\n}\n\nfunc (n *namedSelector) applyTo(doc config.Document) error {\n\tnamedDoc, ok := doc.(config.NamedDocument)\n\tif !ok {\n\t\treturn errors.New(\"not a named document, expected \" + n.name)\n\t}\n\n\tif n.name != namedDoc.Name() {\n\t\treturn fmt.Errorf(\"name mismatch, expected %s, got %s\", n.name, namedDoc.Name())\n\t}\n\n\treturn n.selector.applyTo(doc)\n}\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/testdata/delete/delete.yaml",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\n$patch: delete\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n- content: hello\n  $patch: delete\n- content: hello2\n  mountPath: /etc/foo2\n---\nversion: v1alpha1\nmachine:\n  hostname:\n    $patch: delete\n  network:\n  - interface: eth0\n    $patch: delete\n  - interface: eth1\n    addresses: [10.3.5.5/32]\n  - interface: eth0\n    dhcp6: true\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/testdata/delete/delete_expected.yaml",
    "content": "apiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello2\n      mountPath: /etc/foo2\n---\nversion: v1alpha1\nmachine:\n    network:\n        - interface: eth1\n          addresses: [10.3.5.5/32]\n        - interface: eth0\n          dhcp6: true\n"
  },
  {
    "path": "pkg/machinery/config/configloader/internal/decoder/testdata/double/v1alpha1.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: controlplane\n---\nversion: v1alpha1\nmachine:\n    type: worker\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/controlplane.test",
    "content": "version: v1alpha1 # Indicates the schema used to decode the contents.\ndebug: false # Enable verbose logging to the console.\npersist: true # Indicates whether to pull the machine config upon every boot.\n# Provides machine specific configuration options.\nmachine:\n    type: controlplane # Defines the role of the machine within the cluster.\n    token: 7a10fa.izhckmwn5xmsjwi5 # The `token` is used by a machine to join the PKI of the cluster.\n    # The root certificate authority of the PKI.\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEFJazRNbkdRZ01HQmkrM3p6aHZsRlZNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU1UQTRNall4TWpBMU5USmFGdzB6TVRBNE1qUXhNakExTlRKYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBUzFKbXZ3WFFjTTNJVWRQb1FvTk5jVzh2bzBBenVENUIwb1hoCk9sSnpUa2VqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVL25nVE5YaG9YbkFheU5WaQp3RUREQjdGdHgvQXdCUVlESzJWd0EwRUFuTS9EMFNsZVhBcFVoWlpXQkp0djd2NnhjTFl4ekRoWmd3eFIzODFHCmNjM21XS09MSHZvOENVQU85WmpqZGV4UCtLN1dyMjhxZUxuMWwxTG83SWZWQkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJSkJpdHJaQ1VrMFl1YytsblpqZXFHeVl1MGQxTGpNV2Fvd2FQL2diaTIwQwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    # Extra certificate subject alternative names for the machine's certificate.\n    certSANs: []\n    #   # Uncomment this to enable SANs.\n    #   - 10.0.0.10\n    #   - 172.16.0.10\n    #   - 192.168.0.10\n\n    # Used to provide additional options to the kubelet.\n    kubelet: {}\n    # # The `image` field is an optional reference to an alternative kubelet image.\n    # image: ghcr.io/talos-systems/kubelet:v1.22.1\n\n    # # The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\n    # clusterDNS:\n    #     - 10.96.0.10\n    #     - 169.254.2.53\n\n    # # The `extraArgs` field is used to provide additional flags to the kubelet.\n    # extraArgs:\n    #     key: value\n\n    # # The `extraMounts` field is used to add additional mounts to the kubelet container.\n    # extraMounts:\n    #     - destination: /var/lib/example\n    #       type: bind\n    #       source: /var/lib/example\n    #       options:\n    #         - rshared\n    #         - rw\n\n    # Provides machine specific network configuration options.\n    network: {}\n    # # `interfaces` is used to define the network interface configuration.\n    # interfaces:\n    #     - interface: eth0 # The interface name.\n    #       # Assigns static IP addresses to the interface.\n    #       addresses:\n    #         - 192.168.2.0/24\n    #       # A list of routes associated with the interface.\n    #       routes:\n    #         - network: 0.0.0.0/0 # The route's network.\n    #           gateway: 192.168.2.1 # The route's gateway.\n    #           metric: 1024 # The optional metric for the route.\n    #       mtu: 1500 # The interface's MTU.\n    #\n    #       # # Bond specific options.\n    #       # bond:\n    #       #     # The interfaces that make up the bond.\n    #       #     interfaces:\n    #       #         - eth0\n    #       #         - eth1\n    #       #     mode: 802.3ad # A bond option.\n    #       #     lacpRate: fast # A bond option.\n\n    #       # # Indicates if DHCP should be used to configure the interface.\n    #       # dhcp: true\n\n    #       # # DHCP specific options.\n    #       # dhcpOptions:\n    #       #     routeMetric: 1024 # The priority of all routes received via DHCP.\n\n    #       # # Wireguard specific configuration.\n\n    #       # # wireguard server example\n    #       # wireguard:\n    #       #     privateKey: ABCDEF... # Specifies a private key configuration (base64 encoded).\n    #       #     listenPort: 51111 # Specifies a device's listening port.\n    #       #     # Specifies a list of peer configurations to apply to a device.\n    #       #     peers:\n    #       #         - publicKey: ABCDEF... # Specifies the public key of this peer.\n    #       #           endpoint: 192.168.1.3 # Specifies the endpoint of this peer entry.\n    #       #           # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n    #       #           allowedIPs:\n    #       #             - 192.168.1.0/24\n    #       # # wireguard peer example\n    #       # wireguard:\n    #       #     privateKey: ABCDEF... # Specifies a private key configuration (base64 encoded).\n    #       #     # Specifies a list of peer configurations to apply to a device.\n    #       #     peers:\n    #       #         - publicKey: ABCDEF... # Specifies the public key of this peer.\n    #       #           endpoint: 192.168.1.2 # Specifies the endpoint of this peer entry.\n    #       #           persistentKeepaliveInterval: 10s # Specifies the persistent keepalive interval for this peer.\n    #       #           # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n    #       #           allowedIPs:\n    #       #             - 192.168.1.0/24\n\n    #       # # Virtual (shared) IP address configuration.\n    #       # vip:\n    #       #     ip: 172.16.199.55 # Specifies the IP address to be used.\n\n    # # Used to statically set the nameservers for the machine.\n    # nameservers:\n    #     - 8.8.8.8\n    #     - 1.1.1.1\n\n    # # Allows for extra entries to be added to the `/etc/hosts` file\n    # extraHostEntries:\n    #     - ip: 192.168.1.100 # The IP of the host.\n    #       # The host alias.\n    #       aliases:\n    #         - example\n    #         - example.domain.tld\n\n    # Used to provide instructions for installations.\n    install:\n        disk: /dev/sda # The disk used for installations.\n        image: ghcr.io/aleksi/installer:v0.12.0-alpha.1-20-g5f5ac12f1 # Allows for supplying the image used to perform the installation.\n        bootloader: true # Indicates if a bootloader should be installed.\n        wipe: false # Indicates if the installation disk should be wiped at installation time.\n\n        # # Look up disk using disk attributes like model, size, serial and others.\n        # diskSelector:\n        #     size: 4GB # Disk size.\n        #     model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n\n        # # Allows for supplying extra kernel args via the bootloader.\n        # extraKernelArgs:\n        #     - talos.platform=metal\n        #     - reboot=k\n    # Features describe individual Talos features that can be switched on or off.\n    features:\n        rbac: true # Enable role-based access control (RBAC).\n\n    # # Used to partition, format and mount additional disks.\n\n    # # MachineDisks list example.\n    # disks:\n    #     - device: /dev/sdb # The name of the disk to use.\n    #       # A list of partitions to create on the disk.\n    #       partitions:\n    #         - mountpoint: /var/mnt/extra # Where to mount the partition.\n    #\n    #           # # The size of partition: either bytes or human readable representation. If `size:` is omitted, the partition is sized to occupy the full disk.\n\n    #           # # Human readable representation.\n    #           # size: 100 MB\n    #           # # Precise value in bytes.\n    #           # size: 1073741824\n\n    # # Allows the addition of user specified files.\n\n    # # MachineFiles usage example.\n    # files:\n    #     - content: '...' # The contents of the file.\n    #       permissions: 0o666 # The file's permissions in octal.\n    #       path: /tmp/file.txt # The path of the file.\n    #       op: append # The operation to use\n\n    # # The `env` field allows for the addition of environment variables.\n\n    # # Environment variables definition examples.\n    # env:\n    #     GRPC_GO_LOG_SEVERITY_LEVEL: info\n    #     GRPC_GO_LOG_VERBOSITY_LEVEL: \"99\"\n    #     https_proxy: http://SERVER:PORT/\n    # env:\n    #     GRPC_GO_LOG_SEVERITY_LEVEL: error\n    #     https_proxy: https://USERNAME:PASSWORD@SERVER:PORT/\n    # env:\n    #     https_proxy: http://DOMAIN\\USERNAME:PASSWORD@SERVER:PORT/\n\n    # # Used to configure the machine's time settings.\n\n    # # Example configuration for cloudflare ntp server.\n    # time:\n    #     disabled: false # Indicates if the time service is disabled for the machine.\n    #     # Specifies time (NTP) servers to use for setting the system time.\n    #     servers:\n    #         - time.cloudflare.com\n\n    # # Used to configure the machine's sysctls.\n\n    # # MachineSysctls usage example.\n    # sysctls:\n    #     kernel.domainname: talos.dev\n    #     net.ipv4.ip_forward: \"0\"\n\n    # # Used to configure the machine's container image registry mirrors.\n    # registries:\n    #     # Specifies mirror configuration for each registry.\n    #     mirrors:\n    #         ghcr.io:\n    #             # List of endpoints (URLs) for registry mirrors to use.\n    #             endpoints:\n    #                 - https://registry.insecure\n    #                 - https://ghcr.io/v2/\n    #     # Specifies TLS & auth configuration for HTTPS image registries.\n    #     config:\n    #         registry.insecure:\n    #             # The TLS configuration for the registry.\n    #             tls:\n    #                 insecureSkipVerify: true # Skip TLS server certificate verification (not recommended).\n    #\n    #                 # # Enable mutual TLS authentication with the registry.\n    #                 # clientIdentity:\n    #                 #     crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u\n    #                 #     key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n    #\n    #             # # The auth configuration for this registry.\n    #             # auth:\n    #             #     username: username # Optional registry authentication.\n    #             #     password: password # Optional registry authentication.\n\n    # # Machine system disk encryption configuration.\n    # systemDiskEncryption:\n    #     # Ephemeral partition encryption.\n    #     ephemeral:\n    #         provider: luks2 # Encryption provider to use for the encryption.\n    #         # Defines the encryption keys generation and storage method.\n    #         keys:\n    #             - # Deterministically generated key from the node UUID and PartitionLabel.\n    #               nodeID: {}\n    #               slot: 0 # Key slot number for LUKS2 encryption.\n    #\n    #         # # Cipher kind to use for the encryption. Depends on the encryption provider.\n    #         # cipher: aes-xts-plain64\n\n    #         # # Defines the encryption sector size.\n    #         # blockSize: 4096\n\n    #         # # Additional --perf parameters for the LUKS2 encryption.\n    #         # options:\n    #         #     - no_read_workqueue\n    #         #     - no_write_workqueue\n# Provides cluster specific configuration options.\ncluster:\n    id: Ahg8OEr1t2urQH2wcG2_g0-t1Rtf-QRtA3uBCIe9S3w= # Globally unique identifier for this cluster.\n    secret: y1VWsecCqtdFYWP1xsxw7p2YZJ/Bdwa+H9NzXlIfEbY= # Shared secret of cluster.\n    # Provides control plane specific configuration options.\n    controlPlane:\n        endpoint: https://1.2.3.4:6443 # Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n    clusterName: test # Configures the cluster's name.\n    # Provides cluster specific network configuration options.\n    network:\n        dnsDomain: cluster.local # The domain used by Kubernetes DNS.\n        # The pod subnet CIDR.\n        podSubnets:\n            - 10.244.0.0/16\n        # The service subnet CIDR.\n        serviceSubnets:\n            - 10.96.0.0/12\n\n        # # The CNI used.\n        # cni:\n        #     name: custom # Name of CNI to use.\n        #     # URLs containing manifests to apply for the CNI.\n        #     urls:\n        #         - https://docs.projectcalico.org/archive/v3.20/manifests/canal.yaml\n    token: y9pn8n.g7wi0m50e0wu9b9v # The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\n    aescbcEncryptionSecret: /ZaQCnD11lrRRF2OH7ez96cpn99VWhD1AXdWbZwLQrc= # The key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\n    # The base64 encoded root certificate authority used by Kubernetes.\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRRm1GY0ZiaUtCQ1dtazB5YVZUM1Z5ekFLQmdncWhrak9QUVFEQkRBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXhNRGd5TmpFeU1EVTFNbG9YRFRNeE1EZ3lOREV5TURVMQpNbG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQk1LTXBOZTkxanBmYWZxYlgzNDYyTEk1ZHBSRUpNdlY3U0t6YXZWWHRDa29oTFhpcHZMY3BiUkIyRm8KVGFzNURmSFc3Q2gwQng1S1RnOVRJelVrSGlpallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVrWG5oWUFkbXRDVG15aDVLOTNLTTA2Sk9aME13Q2dZSUtvWkl6ajBFQXdRRFNBQXdSUUlnQVZXYUkwQlUKUUt1MHRoRDNmSjBkaitqbEVxTW5nUGdQaXhJck1mdEdmU1FDSVFES3VIMWIvZzdRS1p1QmU3UEJocC9aZ2xrRgpRdTI5aHdJU0JjbE1aak9tK0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUFvV1BZTUluUThPYUVvb3NnZ2ozUE5XMzVwQ0tIZlFDNWg4TERNalI2dmNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFRXdveWsxNzNXT2w5cCtwdGZmanJZc2psMmxFUWt5OVh0SXJOcTlWZTBLU2lFdGVLbTh0eQpsdEVIWVdoTnF6a044ZGJzS0hRSEhrcE9EMU1qTlNRZUtBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    # The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFXZ0F3SUJBZ0lRRnB2RkhrM1pOOGtQQkUyTElBN2FvekFLQmdncWhrak9QUVFEQkRBQU1CNFgKRFRJeE1EZ3lOakV5TURVMU1sb1hEVE14TURneU5ERXlNRFUxTWxvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRDVDNGprWHhzVWhyb0ZwOGpzY0tkYndyaSsxWURMQm9NMDNlNTMxM2xsbUhEbWZ6dFh1CnNjdkQ2RTFyY0hHV3ljRlJmbEc0K2hVYWtrNHFUSUtRMEF5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVU0VGJqMnUvMUhySU5PSVBPeGZnZHlGeUZwVDh3Q2dZSUtvWkl6ajBFQXdRRFNRQXdSZ0loCkFKRERJZ2lMRE91cHZxWDVVdy9UakJ3NFltRXYzZVRqSHprczRBN1gwNHdWQWlFQTg3Ulo4WjlUdmRIT3BJRHUKdjBEN1ArMFdnS3pCTWpKY05KQ012L1RLSkE0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUMzUFNaMjZGekVoeEhzdGRMK1Y4Zk9vQS9WV3hsd3YzRWozVnBwaVpiaDVvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUGtMaU9SZkd4U0d1Z1dueU94d3AxdkN1TDdWZ01zR2d6VGQ3bmZYZVdXWWNPWi9PMWU2eAp5OFBvVFd0d2NaYkp3VkYrVWJqNkZScVNUaXBNZ3BEUURBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    # The base64 encoded private key for service account token generation.\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUF0eXJVdG53YmgxUk5wSThyUzdCbEl1OWhWdUFwQ2RxdXhSelVoVXJnSGdvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFKzZmd3Y2RzJvdGdNWExHa0ErS1BKbVQ4ZDJISWx1aEdJVWw2NTgyYmprMVVCR3U1SWNpQwoyanRHYnpGSTEweTlOMlZJZDl5d05Mc3dGbjV4YWRyYy9BPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    # API server specific configuration options.\n    apiServer:\n        # Extra certificate subject alternative names for the API server's certificate.\n        certSANs:\n            - 1.2.3.4\n\n        # # The container image used in the API server manifest.\n        # image: k8s.gcr.io/kube-apiserver:v1.22.1\n    # Controller manager server specific configuration options.\n    controllerManager: {}\n    # # The container image used in the controller manager manifest.\n    # image: k8s.gcr.io/kube-controller-manager:v1.22.1\n\n    # Kube-proxy server-specific configuration options\n    proxy: {}\n    # # The container image used in the kube-proxy manifest.\n    # image: k8s.gcr.io/kube-proxy:v1.22.1\n\n    # Scheduler server specific configuration options.\n    scheduler: {}\n    # # The container image used in the scheduler manifest.\n    # image: k8s.gcr.io/kube-scheduler:v1.22.1\n\n    # Etcd specific configuration options.\n    etcd:\n        # The `ca` is the root certificate authority of the PKI.\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRQTV1QkpPTG1wL3RrbEVRS0FFV1RtakFLQmdncWhrak9QUVFEQkRBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl4TURneU5qRXlNRFUxTWxvWERUTXhNRGd5TkRFeU1EVTFNbG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkdxeWR0MjZXRUpSCllyV1NJZkp3QnZHSTZTWENqcENvU1Z6U25jWDFYaUwvY2I0RFJINU5WQ3JuZU9EYjZRb3ZwUTFKaEE3RTR6RDAKTHB5dTE1TW1zM2VqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVR0lwR3JsOFpqTHV5CkFOdzR4Y0RMSGxzZ0c1Z3dDZ1lJS29aSXpqMEVBd1FEU0FBd1JRSWhBT2dsQzlZbkIxZlE4cnNDZSsyY2pQR2MKODlUT0ZXMk10bEVFcWtYdm03cWpBaUE3a3JXRjVXMWxpMmtlVEV5cnZlYjZuajBGWGZRYi9MbERUQnh5YzJicwpNZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUg3V2JCd1pHdVZUUmZkdjZDR3JDUzEzYnR5Q2dGL3JyeUV2YkJ3d0hNYThvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYXJKMjNicFlRbEZpdFpJaDhuQUc4WWpwSmNLT2tLaEpYTktkeGZWZUl2OXh2Z05FZmsxVQpLdWQ0NE52cENpK2xEVW1FRHNUak1QUXVuSzdYa3lhemR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n\n        # # The container image used to create the etcd service.\n        # image: gcr.io/etcd-development/etcd:v3.4.16\n    # A list of urls that point to additional manifests.\n    extraManifests: []\n    #   - https://www.example.com/manifest1.yaml\n    #   - https://www.example.com/manifest2.yaml\n\n    # A list of inline Kubernetes manifests.\n    inlineManifests: []\n    #   - name: namespace-ci # Name of the manifest.\n    #     contents: |- # Manifest contents as a string.\n    #       apiVersion: v1\n    #       kind: Namespace\n    #       metadata:\n    #       \tname: ci\n\n\n    # # Core DNS specific configuration options.\n    # coreDNS:\n    #     image: docker.io/coredns/coredns:1.8.4 # The `image` field is an override to the default coredns image.\n\n    # # External cloud provider configuration.\n    # externalCloudProvider:\n    #     enabled: true # Enable external cloud provider.\n    #     # A list of urls that point to additional manifests for an external cloud provider.\n    #     manifests:\n    #         - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\n    #         - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\n\n    # # A map of key value pairs that will be added while fetching the extraManifests.\n    # extraManifestHeaders:\n    #     Token: \"1234567\"\n    #     X-ExtraInfo: info\n\n    # # Settings for admin kubeconfig generation.\n    # adminKubeconfig:\n    #     certLifetime: 1h0m0s # Admin kubeconfig certificate lifetime (default is 1 year).\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/empty1.test",
    "content": "machine:\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/empty2.test",
    "content": "cluster:\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/fuzz/FuzzConfigLoader/dfd1adfe630cffc2",
    "content": "go test fuzz v1\n[]byte(\"apiVersion: v1alpha1\\nkind: SideroLinkConfig\")\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/multidoc1.test",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: grpc://172.20.0.1:4000/?jointoken=foo\n---\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: tcp://[fdae:41e4:649b:9303::1]:4001/\n---\napiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: \"[fdae:41e4:649b:9303::1]:8080\"\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/multidoc2.test",
    "content": "apiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n  - content: hello\n    mountPath: /etc/foo\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/multidoc3.test",
    "content": "apiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n---\napiVersion: v1alpha1\nkind: NetworkRuleConfig\nname: test\nportSelector:\n    ports:\n        - 53\n        - 8000-9000\n    protocol: udp\ningress:\n    - subnet: 192.168.0.0/16\n      except: 192.168.0.3/32\n    - subnet: 2001::/16\n---\napiVersion: v1alpha1\nkind: NetworkRuleConfig\nname: www\nportSelector:\n    ports:\n        - 80\n    protocol: tcp\ningress:\n    - subnet: 192.168.0.0/16\n"
  },
  {
    "path": "pkg/machinery/config/configloader/testdata/worker.test",
    "content": "---\nversion: v1alpha1 # Indicates the schema used to decode the contents.\ndebug: false # Enable verbose logging to the console.\npersist: true # Indicates whether to pull the machine config upon every boot.\n# Provides machine specific configuration options.\nmachine:\n    type: worker # Defines the role of the machine within the cluster.\n    token: 7a10fa.izhckmwn5xmsjwi5 # The `token` is used by a machine to join the PKI of the cluster.\n    # Extra certificate subject alternative names for the machine's certificate.\n    certSANs: []\n    #   # Uncomment this to enable SANs.\n    #   - 10.0.0.10\n    #   - 172.16.0.10\n    #   - 192.168.0.10\n\n    # Used to provide additional options to the kubelet.\n    kubelet: {}\n    # # The `image` field is an optional reference to an alternative kubelet image.\n    # image: ghcr.io/talos-systems/kubelet:v1.22.1\n\n    # # The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\n    # clusterDNS:\n    #     - 10.96.0.10\n    #     - 169.254.2.53\n\n    # # The `extraArgs` field is used to provide additional flags to the kubelet.\n    # extraArgs:\n    #     key: value\n\n    # # The `extraMounts` field is used to add additional mounts to the kubelet container.\n    # extraMounts:\n    #     - destination: /var/lib/example\n    #       type: bind\n    #       source: /var/lib/example\n    #       options:\n    #         - rshared\n    #         - rw\n\n    # Provides machine specific network configuration options.\n    network: {}\n    # # `interfaces` is used to define the network interface configuration.\n    # interfaces:\n    #     - interface: eth0 # The interface name.\n    #       # Assigns static IP addresses to the interface.\n    #       addresses:\n    #         - 192.168.2.0/24\n    #       # A list of routes associated with the interface.\n    #       routes:\n    #         - network: 0.0.0.0/0 # The route's network.\n    #           gateway: 192.168.2.1 # The route's gateway.\n    #           metric: 1024 # The optional metric for the route.\n    #       mtu: 1500 # The interface's MTU.\n    #\n    #       # # Bond specific options.\n    #       # bond:\n    #       #     # The interfaces that make up the bond.\n    #       #     interfaces:\n    #       #         - eth0\n    #       #         - eth1\n    #       #     mode: 802.3ad # A bond option.\n    #       #     lacpRate: fast # A bond option.\n\n    #       # # Indicates if DHCP should be used to configure the interface.\n    #       # dhcp: true\n\n    #       # # DHCP specific options.\n    #       # dhcpOptions:\n    #       #     routeMetric: 1024 # The priority of all routes received via DHCP.\n\n    #       # # Wireguard specific configuration.\n\n    #       # # wireguard server example\n    #       # wireguard:\n    #       #     privateKey: ABCDEF... # Specifies a private key configuration (base64 encoded).\n    #       #     listenPort: 51111 # Specifies a device's listening port.\n    #       #     # Specifies a list of peer configurations to apply to a device.\n    #       #     peers:\n    #       #         - publicKey: ABCDEF... # Specifies the public key of this peer.\n    #       #           endpoint: 192.168.1.3 # Specifies the endpoint of this peer entry.\n    #       #           # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n    #       #           allowedIPs:\n    #       #             - 192.168.1.0/24\n    #       # # wireguard peer example\n    #       # wireguard:\n    #       #     privateKey: ABCDEF... # Specifies a private key configuration (base64 encoded).\n    #       #     # Specifies a list of peer configurations to apply to a device.\n    #       #     peers:\n    #       #         - publicKey: ABCDEF... # Specifies the public key of this peer.\n    #       #           endpoint: 192.168.1.2 # Specifies the endpoint of this peer entry.\n    #       #           persistentKeepaliveInterval: 10s # Specifies the persistent keepalive interval for this peer.\n    #       #           # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n    #       #           allowedIPs:\n    #       #             - 192.168.1.0/24\n\n    #       # # Virtual (shared) IP address configuration.\n    #       # vip:\n    #       #     ip: 172.16.199.55 # Specifies the IP address to be used.\n\n    # # Used to statically set the nameservers for the machine.\n    # nameservers:\n    #     - 8.8.8.8\n    #     - 1.1.1.1\n\n    # # Allows for extra entries to be added to the `/etc/hosts` file\n    # extraHostEntries:\n    #     - ip: 192.168.1.100 # The IP of the host.\n    #       # The host alias.\n    #       aliases:\n    #         - example\n    #         - example.domain.tld\n\n    # Used to provide instructions for installations.\n    install:\n        disk: /dev/sda # The disk used for installations.\n        image: ghcr.io/aleksi/installer:v0.12.0-alpha.1-20-g5f5ac12f1 # Allows for supplying the image used to perform the installation.\n        bootloader: true # Indicates if a bootloader should be installed.\n        wipe: false # Indicates if the installation disk should be wiped at installation time.\n\n        # # Look up disk using disk attributes like model, size, serial and others.\n        # diskSelector:\n        #     size: 4GB # Disk size.\n        #     model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n\n        # # Allows for supplying extra kernel args via the bootloader.\n        # extraKernelArgs:\n        #     - talos.platform=metal\n        #     - reboot=k\n    # Features describe individual Talos features that can be switched on or off.\n    features:\n        rbac: true # Enable role-based access control (RBAC).\n\n    # # The root certificate authority of the PKI.\n\n    # # machine CA example\n    # ca:\n    #     crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u\n    #     key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n\n    # # Used to partition, format and mount additional disks.\n\n    # # MachineDisks list example.\n    # disks:\n    #     - device: /dev/sdb # The name of the disk to use.\n    #       # A list of partitions to create on the disk.\n    #       partitions:\n    #         - mountpoint: /var/mnt/extra # Where to mount the partition.\n    #\n    #           # # The size of partition: either bytes or human readable representation. If `size:` is omitted, the partition is sized to occupy the full disk.\n\n    #           # # Human readable representation.\n    #           # size: 100 MB\n    #           # # Precise value in bytes.\n    #           # size: 1073741824\n\n    # # Allows the addition of user specified files.\n\n    # # MachineFiles usage example.\n    # files:\n    #     - content: '...' # The contents of the file.\n    #       permissions: 0o666 # The file's permissions in octal.\n    #       path: /tmp/file.txt # The path of the file.\n    #       op: append # The operation to use\n\n    # # The `env` field allows for the addition of environment variables.\n\n    # # Environment variables definition examples.\n    # env:\n    #     GRPC_GO_LOG_SEVERITY_LEVEL: info\n    #     GRPC_GO_LOG_VERBOSITY_LEVEL: \"99\"\n    #     https_proxy: http://SERVER:PORT/\n    # env:\n    #     GRPC_GO_LOG_SEVERITY_LEVEL: error\n    #     https_proxy: https://USERNAME:PASSWORD@SERVER:PORT/\n    # env:\n    #     https_proxy: http://DOMAIN\\USERNAME:PASSWORD@SERVER:PORT/\n\n    # # Used to configure the machine's time settings.\n\n    # # Example configuration for cloudflare ntp server.\n    # time:\n    #     disabled: false # Indicates if the time service is disabled for the machine.\n    #     # Specifies time (NTP) servers to use for setting the system time.\n    #     servers:\n    #         - time.cloudflare.com\n\n    # # Used to configure the machine's sysctls.\n\n    # # MachineSysctls usage example.\n    # sysctls:\n    #     kernel.domainname: talos.dev\n    #     net.ipv4.ip_forward: \"0\"\n\n    # # Used to configure the machine's container image registry mirrors.\n    # registries:\n    #     # Specifies mirror configuration for each registry.\n    #     mirrors:\n    #         ghcr.io:\n    #             # List of endpoints (URLs) for registry mirrors to use.\n    #             endpoints:\n    #                 - https://registry.insecure\n    #                 - https://ghcr.io/v2/\n    #     # Specifies TLS & auth configuration for HTTPS image registries.\n    #     config:\n    #         registry.insecure:\n    #             # The TLS configuration for the registry.\n    #             tls:\n    #                 insecureSkipVerify: true # Skip TLS server certificate verification (not recommended).\n    #\n    #                 # # Enable mutual TLS authentication with the registry.\n    #                 # clientIdentity:\n    #                 #     crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u\n    #                 #     key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n    #\n    #             # # The auth configuration for this registry.\n    #             # auth:\n    #             #     username: username # Optional registry authentication.\n    #             #     password: password # Optional registry authentication.\n\n    # # Machine system disk encryption configuration.\n    # systemDiskEncryption:\n    #     # Ephemeral partition encryption.\n    #     ephemeral:\n    #         provider: luks2 # Encryption provider to use for the encryption.\n    #         # Defines the encryption keys generation and storage method.\n    #         keys:\n    #             - # Deterministically generated key from the node UUID and PartitionLabel.\n    #               nodeID: {}\n    #               slot: 0 # Key slot number for LUKS2 encryption.\n    #\n    #         # # Cipher kind to use for the encryption. Depends on the encryption provider.\n    #         # cipher: aes-xts-plain64\n\n    #         # # Defines the encryption sector size.\n    #         # blockSize: 4096\n\n    #         # # Additional --perf parameters for the LUKS2 encryption.\n    #         # options:\n    #         #     - no_read_workqueue\n    #         #     - no_write_workqueue\n# Provides cluster specific configuration options.\ncluster:\n    id: Ahg8OEr1t2urQH2wcG2_g0-t1Rtf-QRtA3uBCIe9S3w= # Globally unique identifier for this cluster.\n    secret: y1VWsecCqtdFYWP1xsxw7p2YZJ/Bdwa+H9NzXlIfEbY= # Shared secret of cluster.\n    # Provides control plane specific configuration options.\n    controlPlane:\n        endpoint: https://1.2.3.4:6443 # Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n    # Provides cluster specific network configuration options.\n    network:\n        dnsDomain: cluster.local # The domain used by Kubernetes DNS.\n        # The pod subnet CIDR.\n        podSubnets:\n            - 10.244.0.0/16\n        # The service subnet CIDR.\n        serviceSubnets:\n            - 10.96.0.0/12\n\n        # # The CNI used.\n        # cni:\n        #     name: custom # Name of CNI to use.\n        #     # URLs containing manifests to apply for the CNI.\n        #     urls:\n        #         - https://docs.projectcalico.org/archive/v3.20/manifests/canal.yaml\n    token: y9pn8n.g7wi0m50e0wu9b9v # The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\n    aescbcEncryptionSecret: \"\" # The key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\n    #   # Decryption secret example (do not use in production!).\n    #   z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\n\n    # The base64 encoded root certificate authority used by Kubernetes.\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRRm1GY0ZiaUtCQ1dtazB5YVZUM1Z5ekFLQmdncWhrak9QUVFEQkRBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXhNRGd5TmpFeU1EVTFNbG9YRFRNeE1EZ3lOREV5TURVMQpNbG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCQk1LTXBOZTkxanBmYWZxYlgzNDYyTEk1ZHBSRUpNdlY3U0t6YXZWWHRDa29oTFhpcHZMY3BiUkIyRm8KVGFzNURmSFc3Q2gwQng1S1RnOVRJelVrSGlpallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVrWG5oWUFkbXRDVG15aDVLOTNLTTA2Sk9aME13Q2dZSUtvWkl6ajBFQXdRRFNBQXdSUUlnQVZXYUkwQlUKUUt1MHRoRDNmSjBkaitqbEVxTW5nUGdQaXhJck1mdEdmU1FDSVFES3VIMWIvZzdRS1p1QmU3UEJocC9aZ2xrRgpRdTI5aHdJU0JjbE1aak9tK0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n\n    # # The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\n\n    # # AggregatorCA example.\n    # aggregatorCA:\n    #     crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u\n    #     key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n\n    # # The base64 encoded private key for service account token generation.\n\n    # # AggregatorCA example.\n    # serviceAccount:\n    #     key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n\n    # # API server specific configuration options.\n    # apiServer:\n    #     image: k8s.gcr.io/kube-apiserver:v1.22.1 # The container image used in the API server manifest.\n    #     # Extra arguments to supply to the API server.\n    #     extraArgs:\n    #         feature-gates: ServerSideApply=true\n    #         http2-max-streams-per-connection: \"32\"\n    #     # Extra certificate subject alternative names for the API server's certificate.\n    #     certSANs:\n    #         - 1.2.3.4\n    #         - 4.5.6.7\n\n    # # Controller manager server specific configuration options.\n    # controllerManager:\n    #     image: k8s.gcr.io/kube-controller-manager:v1.22.1 # The container image used in the controller manager manifest.\n    #     # Extra arguments to supply to the controller manager.\n    #     extraArgs:\n    #         feature-gates: ServerSideApply=true\n\n    # # Kube-proxy server-specific configuration options\n    # proxy:\n    #     image: k8s.gcr.io/kube-proxy:v1.22.1 # The container image used in the kube-proxy manifest.\n    #     mode: ipvs # proxy mode of kube-proxy.\n    #     # Extra arguments to supply to kube-proxy.\n    #     extraArgs:\n    #         proxy-mode: iptables\n\n    # # Scheduler server specific configuration options.\n    # scheduler:\n    #     image: k8s.gcr.io/kube-scheduler:v1.22.1 # The container image used in the scheduler manifest.\n    #     # Extra arguments to supply to the scheduler.\n    #     extraArgs:\n    #         feature-gates: AllBeta=true\n\n    # # Etcd specific configuration options.\n    # etcd:\n    #     image: gcr.io/etcd-development/etcd:v3.4.16 # The container image used to create the etcd service.\n    #     # The `ca` is the root certificate authority of the PKI.\n    #     ca:\n    #         crt: TFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVSklla05DTUhGLi4u\n    #         key: TFMwdExTMUNSVWRKVGlCRlJESTFOVEU1SUZCU1NWWkJWRVVnUzBWWkxTMHRMUzBLVFVNLi4u\n    #     # Extra arguments to supply to etcd.\n    #     extraArgs:\n    #         election-timeout: \"5000\"\n\n    # # Core DNS specific configuration options.\n    # coreDNS:\n    #     image: docker.io/coredns/coredns:1.8.4 # The `image` field is an override to the default coredns image.\n\n    # # External cloud provider configuration.\n    # externalCloudProvider:\n    #     enabled: true # Enable external cloud provider.\n    #     # A list of urls that point to additional manifests for an external cloud provider.\n    #     manifests:\n    #         - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\n    #         - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\n\n    # # A list of urls that point to additional manifests.\n    # extraManifests:\n    #     - https://www.example.com/manifest1.yaml\n    #     - https://www.example.com/manifest2.yaml\n\n    # # A map of key value pairs that will be added while fetching the extraManifests.\n    # extraManifestHeaders:\n    #     Token: \"1234567\"\n    #     X-ExtraInfo: info\n\n    # # A list of inline Kubernetes manifests.\n    # inlineManifests:\n    #     - name: namespace-ci # Name of the manifest.\n    #       contents: |- # Manifest contents as a string.\n    #         apiVersion: v1\n    #         kind: Namespace\n    #         metadata:\n    #         \tname: ci\n\n    # # Settings for admin kubeconfig generation.\n    # adminKubeconfig:\n    #     certLifetime: 1h0m0s # Admin kubeconfig certificate lifetime (default is 1 year).\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/apply.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher\n\nimport (\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\n// configOrBytes encapsulates either unmarshaled config or raw byte representation.\ntype configOrBytes struct {\n\tmarshaled []byte\n\tconfig    config.Provider\n}\n\nfunc (cb *configOrBytes) Bytes() ([]byte, error) {\n\tif cb.marshaled != nil {\n\t\treturn cb.marshaled, nil\n\t}\n\n\tvar err error\n\n\tcb.marshaled, err = cb.config.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcb.config = nil\n\n\treturn cb.marshaled, nil\n}\n\nfunc (cb *configOrBytes) Config() (config.Provider, error) {\n\tif cb.config != nil {\n\t\treturn cb.config, nil\n\t}\n\n\tvar err error\n\n\tcb.config, err = configloader.NewFromBytes(cb.marshaled)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcb.marshaled = nil\n\n\treturn cb.config, nil\n}\n\n// Input to the patch application process.\ntype Input interface {\n\tConfig() (config.Provider, error)\n\tBytes() ([]byte, error)\n}\n\n// WithConfig returns a new Input that wraps the given config.\nfunc WithConfig(config config.Provider) Input {\n\treturn &configOrBytes{config: config}\n}\n\n// WithBytes returns a new Input that wraps the given bytes.\nfunc WithBytes(bytes []byte) Input {\n\treturn &configOrBytes{marshaled: bytes}\n}\n\n// Output of patch application process.\ntype Output = Input\n\n// Apply config patches to Talos machine config.\n//\n// Apply either JSON6902 or StrategicMergePatch.\n//\n// This method tries to minimize conversion between byte and unmarshalled\n// config representation as much as possible.\nfunc Apply(in Input, patches []Patch) (Output, error) {\n\tfor _, patch := range patches {\n\t\tswitch p := patch.(type) {\n\t\tcase jsonpatch.Patch:\n\t\t\tbytes, err := in.Bytes()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tpatched, err := JSON6902(bytes, p)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tin = WithBytes(patched)\n\t\tcase StrategicMergePatch:\n\t\t\tcfg, err := in.Config()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tpatched, err := StrategicMerge(cfg, p)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tin = WithConfig(patched)\n\t\t}\n\t}\n\n\treturn in, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/apply_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage configpatcher_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n)\n\n//go:embed testdata/apply/config.yaml\nvar config []byte\n\n//go:embed testdata/apply/expected.yaml\nvar expected string\n\n//go:embed testdata/multidoc/config.yaml\nvar configMultidoc []byte\n\n//go:embed testdata/multidoc/expected.yaml\nvar expectedMultidoc string\n\n//go:embed testdata/apply/expected_manifests.yaml\nvar expectedManifests string\n\nfunc TestApply(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/apply/strategic1.yaml\",\n\t\t\"@testdata/apply/jsonpatch1.yaml\",\n\t\t\"@testdata/apply/jsonpatch2.yaml\",\n\t\t\"@testdata/apply/strategic2.yaml\",\n\t\t\"@testdata/apply/strategic3.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(config)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(config),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, expected, string(bytes))\n\t\t})\n\t}\n}\n\nfunc TestApplyMultiDocFail(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/multidoc/jsonpatch.yaml\",\n\t\t\"@testdata/multidoc/strategic1.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configMultidoc)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configMultidoc),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t_, err := configpatcher.Apply(tt.input, patches)\n\t\t\tassert.EqualError(t, err, \"JSON6902 patches are not supported for multi-document machine configuration\")\n\t\t})\n\t}\n}\n\nfunc TestApplyMultiDoc(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/multidoc/strategic1.yaml\",\n\t\t\"@testdata/multidoc/strategic2.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configMultidoc)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configMultidoc),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, expectedMultidoc, string(bytes))\n\t\t})\n\t}\n}\n\n//go:embed testdata/auditpolicy/config.yaml\nvar configAudit []byte\n\n//go:embed testdata/auditpolicy/expected.yaml\nvar expectedAudit []byte\n\nfunc TestApplyAuditPolicy(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/auditpolicy/patch1.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configAudit)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configAudit),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedAudit), string(bytes))\n\t\t})\n\t}\n}\n\nfunc TestApplyWithManifestNewline(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/apply/strategic4.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(config)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(config),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Verify that after all our transformations the YAML is still valid and newline is removed\n\t\t\t_, err = configloader.NewFromBytes(bytes)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, expectedManifests, string(bytes))\n\t\t})\n\t}\n}\n\n//go:embed testdata/patchdelete/config.yaml\nvar configMultidocDelete []byte\n\n//go:embed testdata/patchdelete/expected.yaml\nvar expectedMultidocDelete string\n\nfunc TestApplyMultiDocDelete(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patchdelete/strategic1.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configMultidocDelete)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configMultidocDelete),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, expectedMultidocDelete, string(bytes))\n\t\t})\n\t}\n}\n\n//go:embed testdata/patchdelete/controlplane_orig.yaml\nvar controlPlane []byte\n\n//go:embed testdata/patchdelete/controlplane_expected.yaml\nvar controlPlaneExpected string\n\nfunc TestApplyMultiDocCPDelete(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patchdelete/strategic2.yaml\",\n\t\t\"@testdata/patchdelete/strategic3.yaml\",\n\t\t\"@testdata/patchdelete/strategic4.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(controlPlane)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(controlPlane),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, controlPlaneExpected, string(bytes))\n\t\t})\n\t}\n}\n\n//go:embed testdata/patchdeletemissing/config.yaml\nvar configPatchDeleteMissing []byte\n\nfunc TestPatchDeleteMissing(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patchdeletemissing/strategic1.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configPatchDeleteMissing)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configPatchDeleteMissing),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t_, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.ErrorContains(t, err, `patch delete: path 'machine.network.hostname' in document '/v1alpha1': failed to delete path 'machine.network.hostname': lookup failed`)\n\t\t})\n\t}\n}\n\n//go:embed testdata/patchlink/base.yaml\nvar configPatchBase []byte\n\n//go:embed testdata/patchlink/expected.yaml\nvar configPatchExpected string\n\nfunc TestPatchLink(t *testing.T) {\n\tpatches, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patchlink/patch.yaml\",\n\t})\n\trequire.NoError(t, err)\n\n\tcfg, err := configloader.NewFromBytes(configPatchBase)\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tinput configpatcher.Input\n\t}{\n\t\t{\n\t\t\tname:  \"WithConfig\",\n\t\t\tinput: configpatcher.WithConfig(cfg),\n\t\t},\n\t\t{\n\t\t\tname:  \"WithBytes\",\n\t\t\tinput: configpatcher.WithBytes(configPatchBase),\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tout, err := configpatcher.Apply(tt.input, patches)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbytes, err := out.Bytes()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, configPatchExpected, string(bytes))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/configpatcher.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package configpatcher provides methods to patch Talos config.\npackage configpatcher\n\n// Patch is either JSON patch or strategic merge patch.\ntype Patch any\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/configpatcher_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n)\n\nconst dummyConfig = `machine:\n  kubelet: {}\n`\n\nconst cloudProviderPatched = `machine:\n  kubelet:\n    extraArgs:\n      cloud-provider: external\n`\n\nfunc TestJSON6902(t *testing.T) {\n\ttype args struct {\n\t\ttalosMachineConfig []byte\n\t\tpatchAsBytes       []byte\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twant    []byte\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"test add patch\",\n\t\t\targs: args{\n\t\t\t\ttalosMachineConfig: []byte(dummyConfig),\n\t\t\t\tpatchAsBytes:       []byte(`[{\"op\": \"add\", \"path\": \"/machine/kubelet/extraArgs\", \"value\": {\"cloud-provider\": \"external\"}}]`),\n\t\t\t},\n\t\t\twant: []byte(cloudProviderPatched),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tpatch, err := jsonpatch.DecodePatch(tt.args.patchAsBytes)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"JSON6902 error decoding patch: %v\", err)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tgot, err := configpatcher.JSON6902(tt.args.talosMachineConfig, patch)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"JSON6902 error: %v, but wanted: %v\", err, tt.wantErr)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif !bytes.Equal(got, tt.want) {\n\t\t\t\tt.Errorf(\"JSON6902 got: \\n%v\\n but wanted: \\n%v\", string(got), string(tt.want))\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/json6902.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\tghodssyaml \"github.com/ghodss/yaml\"\n\t\"go.yaml.in/yaml/v4\"\n)\n\n// JSON6902 is responsible for applying a JSON 6902 patch to the bootstrap data.\nfunc JSON6902(talosMachineConfig []byte, patch jsonpatch.Patch) ([]byte, error) {\n\t// check number of input documents\n\tnumDocuments, err := countYAMLDocuments(talosMachineConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif numDocuments != 1 {\n\t\treturn nil, errors.New(\"JSON6902 patches are not supported for multi-document machine configuration\")\n\t}\n\n\t// apply JSON patch\n\tjsonDecodedData, err := ghodssyaml.YAMLToJSON(talosMachineConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failure converting talos machine config to json: %s\", err)\n\t}\n\n\tjsonDecodedData, err = patch.Apply(jsonDecodedData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failure applying rfc6902 patches to talos machine config: %s\", err)\n\t}\n\n\ttalosMachineConfig, err = ghodssyaml.JSONToYAML(jsonDecodedData)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failure converting talos machine config from json to yaml: %s\", err)\n\t}\n\n\treturn talosMachineConfig, nil\n}\n\nfunc countYAMLDocuments(talosMachineConfig []byte) (int, error) {\n\tdecoder := yaml.NewDecoder(bytes.NewReader(talosMachineConfig))\n\n\tnumDocuments := 0\n\n\tfor {\n\t\tvar docs yaml.Node\n\n\t\terr := decoder.Decode(&docs)\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"failure decoding talos machine config: %s\", err)\n\t\t}\n\n\t\tif docs.Kind != yaml.DocumentNode {\n\t\t\treturn 0, errors.New(\"talos machine config is not a yaml document\")\n\t\t}\n\n\t\tnumDocuments++\n\t}\n\n\treturn numDocuments, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/load.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"os\"\n\t\"strings\"\n\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n)\n\ntype patch []map[string]any\n\n// LoadPatch loads the strategic merge patch or JSON patch (JSON/YAML for JSON patch).\nfunc LoadPatch(in []byte) (Patch, error) {\n\t// Try configloader first, as it is more strict about the config format\n\tcfg, strategicErr := configloader.NewFromBytes(in, configloader.WithAllowPatchDelete())\n\tif strategicErr == nil {\n\t\treturn NewStrategicMergePatch(cfg), nil\n\t}\n\n\tvar (\n\t\tjsonErr error\n\t\tp       jsonpatch.Patch\n\t)\n\n\t// try JSON first\n\tif p, jsonErr = jsonpatch.DecodePatch(in); jsonErr == nil {\n\t\treturn p, nil\n\t}\n\n\t// try YAML\n\tvar yamlPatch patch\n\n\tif err := yaml.Unmarshal(in, &yamlPatch); err != nil {\n\t\t// not YAML either, return previous error\n\t\t// see if input looks like JSON Patch as JSON\n\t\tif bytes.HasPrefix(bytes.TrimSpace(in), []byte(\"[\")) {\n\t\t\treturn nil, jsonErr\n\t\t}\n\n\t\t// nope, return config loading error (assume it was strategic merge patch)\n\t\treturn nil, strategicErr\n\t}\n\n\tp = make(jsonpatch.Patch, 0, len(yamlPatch))\n\n\tfor _, yp := range yamlPatch {\n\t\top := make(jsonpatch.Operation, len(yp))\n\n\t\tfor key, value := range yp {\n\t\t\tm, err := json.Marshal(value)\n\t\t\tif err != nil {\n\t\t\t\treturn p, err\n\t\t\t}\n\n\t\t\top[key] = (*json.RawMessage)(&m)\n\t\t}\n\n\t\tp = append(p, op)\n\t}\n\n\treturn p, nil\n}\n\n// LoadPatches loads the JSON patch either from value literal or from a file if the patch starts with '@'.\n//\n// It also tries to guess if the filename was given without '@' prefix.\n//\n//nolint:gocyclo\nfunc LoadPatches(in []string) ([]Patch, error) {\n\tvar result []Patch\n\n\tfor _, patchString := range in {\n\t\tvar (\n\t\t\tp        Patch\n\t\t\tcontents []byte\n\t\t\terr      error\n\t\t)\n\n\t\tswitch {\n\t\tcase strings.HasPrefix(patchString, \"@\"):\n\t\t\tfilename := patchString[1:]\n\n\t\t\tcontents, err = os.ReadFile(filename)\n\t\t\tif err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\tcase !strings.ContainsAny(patchString, \"\\n \") &&\n\t\t\t!strings.HasPrefix(patchString, \"[\") &&\n\t\t\t!strings.HasPrefix(patchString, \"{\"):\n\t\t\t// any valid patch supplied inline should contain either '\\n' or space, or start with '[' or '{'\n\t\t\t// so if none of this is true, assume it's a filename, but without '@' prefix\n\t\t\tcontents, err = os.ReadFile(patchString)\n\t\t\tif err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\tdefault:\n\t\t\tcontents = []byte(patchString)\n\t\t}\n\n\t\tp, err = LoadPatch(contents)\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\n\t\t// merge JSON patches if they come one after another\n\t\t_, isJSONPatch := p.(jsonpatch.Patch)\n\t\tlastJSONPatch := false\n\n\t\tif len(result) > 0 {\n\t\t\tif _, ok := result[len(result)-1].(jsonpatch.Patch); ok {\n\t\t\t\tlastJSONPatch = true\n\t\t\t}\n\t\t}\n\n\t\tif isJSONPatch && lastJSONPatch {\n\t\t\tresult[len(result)-1] = append(result[len(result)-1].(jsonpatch.Patch), p.(jsonpatch.Patch)...)\n\t\t} else {\n\t\t\tresult = append(result, p)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/load_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\tjsonpatch \"github.com/evanphx/json-patch\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n)\n\n//go:embed testdata/patch.json\nvar jsonPatch []byte\n\n//go:embed testdata/patch.yaml\nvar yamlPatch []byte\n\n//go:embed testdata/strategic.yaml\nvar strategicPatch []byte\n\nfunc TestLoadJSON(t *testing.T) {\n\traw, err := configpatcher.LoadPatch(jsonPatch)\n\trequire.NoError(t, err)\n\n\tp, ok := raw.(jsonpatch.Patch)\n\trequire.True(t, ok)\n\n\tassert.Len(t, p, 1)\n\tassert.Equal(t, p[0].Kind(), \"add\")\n\n\tvar path string\n\n\tpath, err = p[0].Path()\n\n\trequire.NoError(t, err)\n\tassert.Equal(t, path, \"/machine/certSANs\")\n}\n\nfunc TestLoadYAML(t *testing.T) {\n\traw, err := configpatcher.LoadPatch(yamlPatch)\n\trequire.NoError(t, err)\n\n\tp, ok := raw.(jsonpatch.Patch)\n\trequire.True(t, ok)\n\n\tassert.Len(t, p, 1)\n\tassert.Equal(t, p[0].Kind(), \"add\")\n\n\tvar path string\n\n\tpath, err = p[0].Path()\n\n\trequire.NoError(t, err)\n\tassert.Equal(t, path, \"/some/path\")\n\n\tvar v any\n\n\tv, err = p[0].ValueInterface()\n\trequire.NoError(t, err)\n\tassert.Equal(t, v, []any{\"a\", \"b\", \"c\"})\n}\n\nfunc TestLoadStrategic(t *testing.T) {\n\traw, err := configpatcher.LoadPatch(strategicPatch)\n\trequire.NoError(t, err)\n\n\tp, ok := raw.(configpatcher.StrategicMergePatch)\n\trequire.True(t, ok)\n\n\tassert.Equal(t, \"foo.bar\", p.Provider().NetworkHostnameConfig().Hostname())\n}\n\nfunc TestLoadJSONPatches(t *testing.T) {\n\tpatchList, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patch.json\",\n\t\t\"@testdata/patch.yaml\",\n\t\t`[{\"op\":\"replace\",\"path\":\"/some\",\"value\": []}]`,\n\t})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, patchList, 1)\n\n\traw := patchList[0]\n\n\tp, ok := raw.(jsonpatch.Patch)\n\trequire.True(t, ok)\n\n\tassert.Len(t, p, 3)\n\tassert.Equal(t, p[0].Kind(), \"add\")\n\tassert.Equal(t, p[1].Kind(), \"add\")\n\tassert.Equal(t, p[2].Kind(), \"replace\")\n}\n\nfunc TestLoadMixedPatches(t *testing.T) {\n\tpatchList, err := configpatcher.LoadPatches([]string{\n\t\t\"@testdata/patch.json\",\n\t\t\"@testdata/strategic.yaml\",\n\t\t\"@testdata/patch.yaml\",\n\t\t`[{\"op\":\"replace\",\"path\":\"/some\",\"value\": []}]`,\n\t})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, patchList, 3)\n\n\tassert.IsType(t, jsonpatch.Patch{}, patchList[0])\n\tassert.Implements(t, (*configpatcher.StrategicMergePatch)(nil), patchList[1])\n\tassert.IsType(t, jsonpatch.Patch{}, patchList[2])\n}\n\nfunc TestLoadStraightFilename(t *testing.T) {\n\tpatchList, err := configpatcher.LoadPatches([]string{\n\t\t\"testdata/strategic.yaml\",\n\t\t`[{\"op\":\"replace\",\"path\":\"/some\",\"value\": []}]`,\n\t})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, patchList, 2)\n\n\tassert.Implements(t, (*configpatcher.StrategicMergePatch)(nil), patchList[0])\n\tassert.IsType(t, jsonpatch.Patch{}, patchList[1])\n}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/strategic.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage configpatcher\n\nimport (\n\t\"errors\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\tcoreconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n)\n\n// StrategicMergePatch is a strategic merge config patch.\ntype StrategicMergePatch interface {\n\tDocuments() []config.Document\n\tProvider() coreconfig.Provider\n}\n\n// StrategicMerge performs strategic merge config patching.\n//\n// Strategic merge on two sets of documents - on the left hand side and on the right hand side.\n// Documents with matching tuples (apiVersion, kind, name) are merged together.\n// If the document on the right doesn't exist on the left, it is appended.\nfunc StrategicMerge(cfg coreconfig.Provider, patch StrategicMergePatch) (coreconfig.Provider, error) {\n\tleft := cfg.Clone().Documents()\n\tright := patch.Documents()\n\n\tdocumentID := func(doc config.Document) string {\n\t\tid := doc.APIVersion() + \"/\" + doc.Kind()\n\n\t\tif named, ok := doc.(config.NamedDocument); ok {\n\t\t\tid += \"/\" + named.Name()\n\t\t}\n\n\t\treturn id\n\t}\n\n\tleftIndex := xslices.ToMap(left, func(d config.Document) (string, config.Document) {\n\t\treturn documentID(d), d\n\t})\n\n\tfor _, rightDoc := range right {\n\t\tid := documentID(rightDoc)\n\n\t\tif leftDoc, ok := leftIndex[id]; ok {\n\t\t\tsel, isSel := rightDoc.(configloader.Selector)\n\t\t\tif !isSel {\n\t\t\t\tif err := merge.Merge(leftDoc, rightDoc); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr := sel.ApplyTo(leftDoc)\n\t\t\tif err != nil {\n\t\t\t\tif !errors.Is(err, configloader.ErrZeroedDocument) {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tdelete(leftIndex, id)\n\n\t\t\t\tidx := slices.Index(left, leftDoc)\n\t\t\t\tleft = slices.Delete(left, idx, idx+1)\n\t\t\t}\n\t\t} else {\n\t\t\tleft = append(left, rightDoc)\n\t\t}\n\t}\n\n\treturn container.New(left...)\n}\n\n// NewStrategicMergePatch creates a new strategic merge patch. deleteSelectors is a list of delete selectors, can be empty.\nfunc NewStrategicMergePatch(cfg coreconfig.Provider) StrategicMergePatch {\n\treturn strategicMergePatch{provider: cfg}\n}\n\ntype strategicMergePatch struct {\n\tprovider coreconfig.Provider\n}\n\nfunc (s strategicMergePatch) Documents() []config.Document {\n\treturn s.provider.Documents()\n}\n\nfunc (s strategicMergePatch) Provider() coreconfig.Provider { return s.provider }\n\nvar _ StrategicMergePatch = strategicMergePatch{}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/config.yaml",
    "content": "version: v1alpha1\nmachine:\n  network:\n    hostname: hostname1\n    interfaces:\n      - interface: eth0\n        dhcp: true\ncluster:\n  proxy:\n    extraArgs:\n       metrics-bind-address: $(POD_IP):10249\n       foo: bar\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/expected.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: \"\"\n    token: \"\"\n    certSANs: []\n    network:\n        hostname: foo\n        interfaces:\n            - interface: eth0\n              addresses:\n                - 10.1.2.3/24\n              dhcp: false\n              vip:\n                ip: 10.3.5.6\n            - interface: eth1\n              vlans:\n                - addresses:\n                    - 10.3.4.5\n                    - 10.3.4.6\n                  routes: []\n                  vlanId: 100\n                - addresses:\n                    - 10.3.4.7\n                  routes: []\n                  vlanId: 101\ncluster:\n    controlPlane: null\n    proxy:\n        extraArgs:\n            metrics-bind-address: $(POD_IP):10249\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/expected_manifests.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: \"\"\n    token: \"\"\n    certSANs: []\n    network:\n        hostname: hostname1\n        interfaces:\n            - interface: eth0\n              dhcp: true\ncluster:\n    controlPlane: null\n    proxy:\n        extraArgs:\n            foo: bar\n            metrics-bind-address: $(POD_IP):10249\n    inlineManifests:\n        - name: cilium\n          contents: |\n            ---\n            apiVersion: v1\n            kind: ServiceAccount\n            metadata:\n              name: cilium\n              namespace: kube-system\n            ---\n            apiVersion: v1\n            kind: ServiceAccount\n            metadata:\n              name: cilium-operator\n              namespace: kube-system\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/jsonpatch1.yaml",
    "content": "- op: add\n  path: /machine/network/interfaces/0/addresses\n  value:\n     - 10.1.2.3/24\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/jsonpatch2.yaml",
    "content": "- op: replace\n  path: /machine/network/hostname\n  value: foo\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/strategic1.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth0\n        dhcp: false\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/strategic2.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth0\n        vip:\n          ip: 10.3.5.6\n      - interface: eth1\n        vlans:\n          - vlanId: 100\n            addresses: [10.3.4.5]\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/strategic3.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth1\n        vlans:\n          - vlanId: 100\n            addresses: [10.3.4.6]\n          - vlanId: 101\n            addresses: [10.3.4.7]\ncluster:\n  proxy:\n    extraArgs:\n       metrics-bind-address: $(POD_IP):10249\n       foo:\n         $patch: delete\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/apply/strategic4.yaml",
    "content": "cluster:\n  inlineManifests:\n    - name: cilium\n      contents: | # the empty newline below is important\n\n        ---\n        apiVersion: v1\n        kind: ServiceAccount\n        metadata:\n          name: cilium\n          namespace: kube-system\n        ---\n        apiVersion: v1\n        kind: ServiceAccount\n        metadata:\n          name: cilium-operator\n          namespace: kube-system\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/auditpolicy/config.yaml",
    "content": "version: v1alpha1\nmachine:\n  network:\n    hostname: hostname-foo\ncluster:\n  apiServer:\n    auditPolicy:\n      apiVersion: audit.k8s.io/v1\n      kind: Policy\n      rules:\n        - level: Metadata\n  controlPlane:\n    endpoint: https://localhost:6443\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/auditpolicy/expected.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: \"\"\n    token: \"\"\n    certSANs: []\n    network:\n        hostname: hostname-foo\ncluster:\n    controlPlane:\n        endpoint: https://localhost:6443\n    apiServer:\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: None\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/auditpolicy/patch1.yaml",
    "content": "cluster:\n  apiServer:\n    auditPolicy:\n      apiVersion: audit.k8s.io/v1\n      kind: Policy\n      rules:\n        - level: None\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/multidoc/config.yaml",
    "content": "version: v1alpha1\nmachine:\n  network:\n    hostname: hostname1\n    interfaces:\n      - interface: eth0\n        dhcp: true\n---\napiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/join?jointoken=secret&user=alice\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello\n      mountPath: /etc/foo\nenvironment:\n    - FOO=BAR\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/multidoc/expected.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: \"\"\n    token: \"\"\n    certSANs: []\n    network:\n        hostname: hostname1\n        interfaces:\n            - interface: eth0\n              dhcp: false\ncluster: null\n---\napiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/join?jointoken=secret&user=bob\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello world\n      mountPath: /etc/foo\n    - content: another hello\n      mountPath: /etc/bar\nenvironment:\n    - FOO=BAR\n    - XXX=YYY\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/multidoc/jsonpatch.yaml",
    "content": "- op: add\n  path: /machine/network/interfaces/0/addresses\n  value:\n     - 10.1.2.3/24\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/multidoc/strategic1.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth0\n        dhcp: false\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/multidoc/strategic2.yaml",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/join?jointoken=secret&user=bob\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello world\n      mountPath: /etc/foo\n    - content: another hello\n      mountPath: /etc/bar\nenvironment:\n    - XXX=YYY\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patch.json",
    "content": "[\n    {\n        \"op\": \"add\",\n        \"path\": \"/machine/certSANs\",\n        \"value\": [\"foo.com\"]\n    }\n]\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patch.yaml",
    "content": "- op: add\n  path: /some/path\n  value:\n    - a\n    - b\n    - c\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/config.yaml",
    "content": "version: v1alpha1\nmachine:\n  network:\n    hostname: hostname1\n    interfaces:\n      - interface: eth0\n        dhcp: true\n      - interface: eth1\n        addresses: [10.3.5.4/32]\n---\napiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/join?jointoken=secret&user=alice\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello\n      mountPath: /etc/foo\nenvironment:\n    - FOO=BAR\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/controlplane_expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/controlplane_orig.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n  type: controlplane\n  token: d8cwfa.eyvpi0xwxyarbfid\n  ca:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n  certSANs: []\n  kubelet:\n    image: ghcr.io/siderolabs/kubelet:v1.28.0\n    defaultRuntimeSeccompProfileEnabled: true\n    disableManifestsDirectory: true\n  network: {}\n  install:\n    wipe: false\n  features:\n    rbac: true\n    stableHostname: true\n    apidCheckExtKeyUsage: true\n    diskQuotaSupport: true\n    kubePrism:\n      enabled: true\n      port: 7445\n    hostDNS:\n      enabled: true\n      forwardKubeDNSToHost: true\n  nodeLabels:\n    node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n  id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n  secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n  controlPlane:\n    endpoint: https://base:6443\n  clusterName: base\n  network:\n    dnsDomain: cluster.local\n    podSubnets:\n    - 10.244.0.0/16\n    serviceSubnets:\n    - 10.96.0.0/12\n  token: inn7ol.u4ehnti8qyls9ymo\n  secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n  ca:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n  aggregatorCA:\n    crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n    key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n  serviceAccount:\n    key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n  apiServer:\n    image: registry.k8s.io/kube-apiserver:v1.28.0\n    certSANs:\n    - base\n    disablePodSecurityPolicy: true\n    admissionControl:\n    - name: PodSecurity\n      configuration:\n        apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n        defaults:\n          audit: restricted\n          audit-version: latest\n          enforce: baseline\n          enforce-version: latest\n          warn: restricted\n          warn-version: latest\n        exemptions:\n          namespaces:\n          - kube-system\n          runtimeClasses: []\n          usernames: []\n        kind: PodSecurityConfiguration\n    auditPolicy:\n      apiVersion: audit.k8s.io/v1\n      kind: Policy\n      rules:\n      - level: Metadata\n  controllerManager:\n    image: registry.k8s.io/kube-controller-manager:v1.28.0\n  proxy:\n    image: registry.k8s.io/kube-proxy:v1.28.0\n  scheduler:\n    image: registry.k8s.io/kube-scheduler:v1.28.0\n  discovery:\n    enabled: true\n    registries:\n      kubernetes:\n        disabled: true\n      service: {}\n  etcd:\n    ca:\n      crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n      key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/expected.yaml",
    "content": "version: v1alpha1\nmachine:\n    type: \"\"\n    token: \"\"\n    certSANs: []\n    network:\n        interfaces:\n            - interface: eth1\n              addresses:\n                - 10.3.5.4/32\n                - 10.3.5.5/32\n            - interface: eth0\n              dummy: true\ncluster: null\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello2\n      mountPath: /etc/foo2\nenvironment:\n    - FOO=BAR\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/strategic1.yaml",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\n$patch: delete\n---\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n  - content: hello\n    $patch: delete\n  - content: hello2\n    mountPath: /etc/foo2\n---\nversion: v1alpha1\nmachine:\n  network:\n    hostname:\n      $patch: delete\n    interfaces:\n      - interface: eth0\n        $patch: delete\n      - interface: eth1\n        addresses: [10.3.5.5/32]\n      - interface: eth0\n        dummy: true\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/strategic2.yaml",
    "content": "version: v1alpha1\ncluster:\n  apiServer:\n    admissionControl:\n    - name: PodSecurity\n      $patch: delete\nmachine:\n  nodeLabels:\n    node.kubernetes.io/exclude-from-external-load-balancers:\n      $patch: delete\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/strategic3.yaml",
    "content": "version: v1alpha1\ncluster:\n  apiServer:\n    admissionControl:\n    - name: PodSecurity2\n      configuration:\n        apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n        defaults:\n          audit: restricted\n          audit-version: latest\n          enforce: baseline\n          enforce-version: latest\n          warn: restricted\n          warn-version: latest\n        exemptions:\n          namespaces:\n          - kube-system\n          runtimeClasses: []\n          usernames: []\n        kind: PodSecurityConfiguration\n    auditPolicy:\n      $patch: delete\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdelete/strategic4.yaml",
    "content": "version: v1alpha1\ncluster:\n  apiServer:\n    admissionControl:\n    - name: PodSecurity2\n      $patch: delete\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdeletemissing/config.yaml",
    "content": "version: v1alpha1\nmachine: {}\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchdeletemissing/strategic1.yaml",
    "content": "machine:\n  network:\n    hostname:\n      $patch: delete\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchlink/base.yaml",
    "content": "apiVersion: v1alpha1\nkind: LinkConfig\nname: eth0\naddresses:\n  - address: 10.0.42.136/24\nroutes:\n  - gateway: 10.0.42.1\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchlink/expected.yaml",
    "content": "apiVersion: v1alpha1\nkind: LinkConfig\nname: eth0\naddresses:\n    - address: 10.0.42.137/24\nroutes:\n    - gateway: 10.0.42.1\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/patchlink/patch.yaml",
    "content": "apiVersion: v1alpha1\nkind: LinkConfig\nname: eth0\naddresses:\n  - address: 10.0.42.136/24\n    $patch: delete\n  - address: 10.0.42.137/24\n"
  },
  {
    "path": "pkg/machinery/config/configpatcher/testdata/strategic.yaml",
    "content": "machine:\n  network:\n    hostname: foo.bar\n"
  },
  {
    "path": "pkg/machinery/config/container/container.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package container implements a wrapper which wraps all configuration documents into a single container.\npackage container\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\tcoreconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// V1Alpha1ConflictValidator is the interface implemented by config documents which conflict with legacy v1alpha1 config.\ntype V1Alpha1ConflictValidator interface {\n\tV1Alpha1ConflictValidate(*v1alpha1.Config) error\n}\n\n// Container wraps all configuration documents into a single container.\ntype Container struct {\n\tv1alpha1Config *v1alpha1.Config\n\tdocuments      []config.Document\n\tbytes          []byte\n\treadonly       bool\n}\n\nvar _ coreconfig.Provider = &Container{}\n\n// New creates a container out of the list of documents.\n//\n//nolint:gocyclo\nfunc New(documents ...config.Document) (*Container, error) {\n\tcontainer := &Container{\n\t\tdocuments: make([]config.Document, 0, len(documents)),\n\t}\n\n\tseenDocuments := make(map[string]struct{})\n\tconflictingDocuments := make(map[string]string)\n\n\tfor _, doc := range documents {\n\t\tswitch d := doc.(type) {\n\t\tcase *v1alpha1.Config:\n\t\t\tif container.v1alpha1Config != nil {\n\t\t\t\treturn nil, errors.New(\"duplicate v1alpha1.Config\")\n\t\t\t}\n\n\t\t\tcontainer.v1alpha1Config = d\n\t\tdefault:\n\t\t\tif _, ok := d.(selector); !ok {\n\t\t\t\tdocumentID := d.Kind() + \"/\"\n\n\t\t\t\tif named, ok := d.(config.NamedDocument); ok {\n\t\t\t\t\tdocumentID += named.Name()\n\t\t\t\t}\n\n\t\t\t\tif _, alreadySeen := seenDocuments[documentID]; alreadySeen {\n\t\t\t\t\treturn nil, fmt.Errorf(\"duplicate document: %s\", documentID)\n\t\t\t\t}\n\n\t\t\t\tseenDocuments[documentID] = struct{}{}\n\n\t\t\t\tif conflictingID, isConflicting := conflictingDocuments[documentID]; isConflicting {\n\t\t\t\t\treturn nil, fmt.Errorf(\"conflicting documents: %s and %s\", conflictingID, documentID)\n\t\t\t\t}\n\n\t\t\t\tif conflicting, ok := d.(config.ConflictingDocument); ok {\n\t\t\t\t\tfor _, kind := range conflicting.ConflictsWithKinds() {\n\t\t\t\t\t\tconflictingID := kind + \"/\"\n\n\t\t\t\t\t\tif named, ok := d.(config.NamedDocument); ok {\n\t\t\t\t\t\t\tconflictingID += named.Name()\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif _, alreadySeen := seenDocuments[conflictingID]; alreadySeen {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"conflicting documents: %s and %s\", conflictingID, documentID)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconflictingDocuments[conflictingID] = documentID\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontainer.documents = append(container.documents, d)\n\t\t}\n\t}\n\n\treturn container, nil\n}\n\n// NewReadonly creates a read-only container which preserves byte representation of contents.\nfunc NewReadonly(bytes []byte, documents ...config.Document) (*Container, error) {\n\tc, err := New(documents...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.bytes = bytes\n\tc.readonly = true\n\n\treturn c, nil\n}\n\n// NewV1Alpha1 creates a container with (only) v1alpha1.Config document.\nfunc NewV1Alpha1(config *v1alpha1.Config) *Container {\n\treturn &Container{\n\t\tv1alpha1Config: config,\n\t}\n}\n\n// Clone the container.\n//\n// Cloned container is not readonly.\nfunc (container *Container) Clone() coreconfig.Provider { return container.clone() }\n\nfunc (container *Container) clone() *Container {\n\treturn &Container{\n\t\tv1alpha1Config: container.v1alpha1Config.DeepCopy(),\n\t\tdocuments:      xslices.Map(container.documents, config.Document.Clone),\n\t}\n}\n\n// PatchV1Alpha1 patches the container's v1alpha1.Config while preserving other config documents.\nfunc (container *Container) PatchV1Alpha1(patcher func(*v1alpha1.Config) error) (coreconfig.Provider, error) {\n\tcfg := container.RawV1Alpha1()\n\tif cfg == nil {\n\t\treturn nil, fmt.Errorf(\"v1alpha1.Config is not present in the container\")\n\t}\n\n\tcfg = cfg.DeepCopy()\n\n\tif err := patcher(cfg); err != nil {\n\t\treturn nil, err\n\t}\n\n\totherDocs := xslices.Filter(container.Documents(), func(doc config.Document) bool {\n\t\t_, ok := doc.(*v1alpha1.Config)\n\n\t\treturn !ok\n\t})\n\n\treturn New(slices.Insert(otherDocs, 0, config.Document(cfg))...)\n}\n\n// Readonly implements config.Container interface.\nfunc (container *Container) Readonly() bool {\n\treturn container.readonly\n}\n\n// Debug implements config.Config interface.\nfunc (container *Container) Debug() bool {\n\tif container.v1alpha1Config == nil {\n\t\treturn false\n\t}\n\n\treturn container.v1alpha1Config.Debug()\n}\n\n// Machine implements config.Config interface.\nfunc (container *Container) Machine() config.MachineConfig {\n\tif container.v1alpha1Config == nil {\n\t\treturn nil\n\t}\n\n\treturn container.v1alpha1Config.Machine()\n}\n\n// Cluster implements config.Config interface.\nfunc (container *Container) Cluster() config.ClusterConfig {\n\tif container.v1alpha1Config == nil {\n\t\treturn nil\n\t}\n\n\treturn container.v1alpha1Config.Cluster()\n}\n\nfunc findMatchingDocs[T any](documents []config.Document) []T {\n\tvar result []T\n\n\tfor _, doc := range documents {\n\t\tif c, ok := doc.(T); ok {\n\t\t\tresult = append(result, c)\n\t\t}\n\t}\n\n\treturn result\n}\n\n// SideroLink implements config.Config interface.\nfunc (container *Container) SideroLink() config.SideroLinkConfig {\n\tmatching := findMatchingDocs[config.SideroLinkConfig](container.documents)\n\tif len(matching) == 0 {\n\t\treturn nil\n\t}\n\n\treturn matching[0]\n}\n\n// ExtensionServiceConfigs implements config.Config interface.\nfunc (container *Container) ExtensionServiceConfigs() []config.ExtensionServiceConfig {\n\treturn findMatchingDocs[config.ExtensionServiceConfig](container.documents)\n}\n\n// Runtime implements config.Config interface.\nfunc (container *Container) Runtime() config.RuntimeConfig {\n\treturn config.WrapRuntimeConfigList(findMatchingDocs[config.RuntimeConfig](container.documents)...)\n}\n\n// Environment implements config.Config interface.\nfunc (container *Container) Environment() config.EnvironmentConfig {\n\treturn config.WrapEnvironmentConfigList(findMatchingDocs[config.EnvironmentConfig](container.documents)...)\n}\n\n// NetworkRules implements config.Config interface.\nfunc (container *Container) NetworkRules() config.NetworkRuleConfig {\n\treturn config.WrapNetworkRuleConfigList(findMatchingDocs[config.NetworkRuleConfigSignal](container.documents)...)\n}\n\n// TrustedRoots implements config.Config interface.\nfunc (container *Container) TrustedRoots() config.TrustedRootsConfig {\n\treturn config.WrapTrustedRootsConfig(findMatchingDocs[config.TrustedRootsConfig](container.documents)...)\n}\n\n// Volumes implements config.Config interface.\nfunc (container *Container) Volumes() config.VolumesConfig {\n\treturn config.WrapVolumesConfigList(findMatchingDocs[config.VolumeConfig](container.documents)...)\n}\n\n// KubespanConfig implements config.Config interface.\nfunc (container *Container) KubespanConfig() config.KubespanConfig {\n\treturn config.WrapKubespanConfig(findMatchingDocs[config.KubespanConfig](container.documents)...)\n}\n\n// PCIDriverRebindConfig implements config.Config interface.\nfunc (container *Container) PCIDriverRebindConfig() config.PCIDriverRebindConfig {\n\treturn config.WrapPCIDriverRebindConfig(findMatchingDocs[config.PCIDriverRebindConfig](container.documents)...)\n}\n\n// EthernetConfigs implements config.Config interface.\nfunc (container *Container) EthernetConfigs() []config.EthernetConfig {\n\treturn findMatchingDocs[config.EthernetConfig](container.documents)\n}\n\n// UserVolumeConfigs implements config.Config interface.\nfunc (container *Container) UserVolumeConfigs() []config.UserVolumeConfig {\n\treturn findMatchingDocs[config.UserVolumeConfig](container.documents)\n}\n\n// ExternalVolumeConfigs implements config.Config interface.\nfunc (container *Container) ExternalVolumeConfigs() []config.ExternalVolumeConfig {\n\treturn findMatchingDocs[config.ExternalVolumeConfig](container.documents)\n}\n\n// RawVolumeConfigs implements config.Config interface.\nfunc (container *Container) RawVolumeConfigs() []config.RawVolumeConfig {\n\treturn findMatchingDocs[config.RawVolumeConfig](container.documents)\n}\n\n// ExistingVolumeConfigs implements config.Config interface.\nfunc (container *Container) ExistingVolumeConfigs() []config.ExistingVolumeConfig {\n\treturn findMatchingDocs[config.ExistingVolumeConfig](container.documents)\n}\n\n// SwapVolumeConfigs implements config.Config interface.\nfunc (container *Container) SwapVolumeConfigs() []config.SwapVolumeConfig {\n\treturn findMatchingDocs[config.SwapVolumeConfig](container.documents)\n}\n\n// ZswapConfig implements config.Config interface.\nfunc (container *Container) ZswapConfig() config.ZswapConfig {\n\tmatching := findMatchingDocs[config.ZswapConfig](container.documents)\n\tif len(matching) == 0 {\n\t\treturn nil\n\t}\n\n\treturn matching[0]\n}\n\n// NetworkStaticHostConfig implements config.Config interface.\nfunc (container *Container) NetworkStaticHostConfig() []config.NetworkStaticHostConfig {\n\treturn slices.Concat(\n\t\tcontainer.v1alpha1Config.NetworkStaticHostConfig(),\n\t\tfindMatchingDocs[config.NetworkStaticHostConfig](container.documents),\n\t)\n}\n\n// NetworkHostnameConfig implements config.Config interface.\nfunc (container *Container) NetworkHostnameConfig() config.NetworkHostnameConfig {\n\t// first check if we have a dedicated document\n\tmatching := findMatchingDocs[config.NetworkHostnameConfig](container.documents)\n\tif len(matching) > 0 {\n\t\treturn matching[0]\n\t}\n\n\t// fallback to v1alpha1\n\tif container.v1alpha1Config != nil {\n\t\treturn container.v1alpha1Config\n\t}\n\n\treturn nil\n}\n\n// NetworkResolverConfig implements config.Config interface.\nfunc (container *Container) NetworkResolverConfig() config.NetworkResolverConfig {\n\t// first check if we have a dedicated document\n\tmatching := findMatchingDocs[config.NetworkResolverConfig](container.documents)\n\tif len(matching) > 0 {\n\t\treturn matching[0]\n\t}\n\n\t// fallback to v1alpha1\n\tif container.v1alpha1Config != nil {\n\t\treturn container.v1alpha1Config\n\t}\n\n\treturn nil\n}\n\n// NetworkTimeSyncConfig implements config.Config interface.\nfunc (container *Container) NetworkTimeSyncConfig() config.NetworkTimeSyncConfig {\n\t// first check if we have a dedicated document\n\tmatching := findMatchingDocs[config.NetworkTimeSyncConfig](container.documents)\n\tif len(matching) > 0 {\n\t\treturn matching[0]\n\t}\n\n\t// fallback to v1alpha1\n\tif container.v1alpha1Config != nil {\n\t\treturn container.v1alpha1Config.NetworkTimeSyncConfig()\n\t}\n\n\treturn nil\n}\n\n// NetworkKubeSpanConfig implements config.Config interface.\nfunc (container *Container) NetworkKubeSpanConfig() config.NetworkKubeSpanConfig {\n\t// first check if we have a dedicated document\n\tmatching := findMatchingDocs[config.NetworkKubeSpanConfig](container.documents)\n\tif len(matching) > 0 {\n\t\treturn matching[0]\n\t}\n\n\t// fallback to v1alpha1\n\tif container.v1alpha1Config != nil {\n\t\treturn container.v1alpha1Config.NetworkKubeSpanConfig()\n\t}\n\n\treturn nil\n}\n\n// NetworkCommonLinkConfigs implements config.Config interface.\nfunc (container *Container) NetworkCommonLinkConfigs() []config.NetworkCommonLinkConfig {\n\treturn findMatchingDocs[config.NetworkCommonLinkConfig](container.documents)\n}\n\n// NetworkLinkAliasConfigs implements config.Config interface.\nfunc (container *Container) NetworkLinkAliasConfigs() []config.NetworkLinkAliasConfig {\n\treturn findMatchingDocs[config.NetworkLinkAliasConfig](container.documents)\n}\n\n// NetworkDHCPConfigs implements config.Config interface.\nfunc (container *Container) NetworkDHCPConfigs() []config.NetworkDHCPConfig {\n\treturn findMatchingDocs[config.NetworkDHCPConfig](container.documents)\n}\n\n// NetworkDHCPv4Configs implements config.Config interface.\nfunc (container *Container) NetworkDHCPv4Configs() []config.NetworkDHCPv4Config {\n\treturn findMatchingDocs[config.NetworkDHCPv4Config](container.documents)\n}\n\n// NetworkDHCPv6Configs implements config.Config interface.\nfunc (container *Container) NetworkDHCPv6Configs() []config.NetworkDHCPv6Config {\n\treturn findMatchingDocs[config.NetworkDHCPv6Config](container.documents)\n}\n\n// NetworkVirtualIPConfigs implements config.Config interface.\nfunc (container *Container) NetworkVirtualIPConfigs() []config.NetworkVirtualIPConfig {\n\treturn findMatchingDocs[config.NetworkVirtualIPConfig](container.documents)\n}\n\n// NetworkProbeConfigs implements config.Config interface.\nfunc (container *Container) NetworkProbeConfigs() []config.NetworkCommonProbeConfig {\n\treturn findMatchingDocs[config.NetworkCommonProbeConfig](container.documents)\n}\n\n// NetworkBlackholeRouteConfigs implements config.Config interface.\nfunc (container *Container) NetworkBlackholeRouteConfigs() []config.NetworkBlackholeRouteConfig {\n\treturn findMatchingDocs[config.NetworkBlackholeRouteConfig](container.documents)\n}\n\n// NetworkRoutingRuleConfigs implements config.Config interface.\nfunc (container *Container) NetworkRoutingRuleConfigs() []config.NetworkRoutingRuleConfig {\n\treturn findMatchingDocs[config.NetworkRoutingRuleConfig](container.documents)\n}\n\n// RunDefaultDHCPOperators implements config.Config interface.\n//\n// The rules for this are:\n//   - if there is a single new-style network config document for links,\n//     we immediately stop running default DHCP operators (as user is taking full control)\nfunc (container *Container) RunDefaultDHCPOperators() bool {\n\treturn len(findMatchingDocs[config.NetworkCommonLinkConfig](container.documents)) == 0 &&\n\t\tlen(findMatchingDocs[config.NetworkDHCPConfig](container.documents)) == 0\n}\n\n// OOMConfig implements config.Config interface.\nfunc (container *Container) OOMConfig() config.OOMConfig {\n\tmatching := findMatchingDocs[config.OOMConfig](container.documents)\n\tif len(matching) == 0 {\n\t\treturn nil\n\t}\n\n\treturn matching[0]\n}\n\n// RegistryMirrorConfigs implements config.Config interface.\nfunc (container *Container) RegistryMirrorConfigs() map[string]config.RegistryMirrorConfig {\n\tvar cfg map[string]config.RegistryMirrorConfig\n\n\tif container.v1alpha1Config != nil {\n\t\tcfg = container.v1alpha1Config.RegistryMirrorConfigs()\n\t}\n\n\tdocs := findMatchingDocs[config.RegistryMirrorConfigDocument](container.documents)\n\n\tif cfg == nil {\n\t\tcfg = make(map[string]config.RegistryMirrorConfig, len(docs))\n\t}\n\n\tfor _, doc := range docs {\n\t\tcfg[doc.Name()] = doc\n\t}\n\n\treturn cfg\n}\n\n// RegistryAuthConfigs implements config.Config interface.\nfunc (container *Container) RegistryAuthConfigs() map[string]config.RegistryAuthConfig {\n\tvar cfg map[string]config.RegistryAuthConfig\n\n\tif container.v1alpha1Config != nil {\n\t\tcfg = container.v1alpha1Config.RegistryAuthConfigs()\n\t}\n\n\tdocs := findMatchingDocs[config.RegistryAuthConfigDocument](container.documents)\n\n\tif cfg == nil {\n\t\tcfg = make(map[string]config.RegistryAuthConfig, len(docs))\n\t}\n\n\tfor _, doc := range docs {\n\t\tcfg[doc.Name()] = doc\n\t}\n\n\treturn cfg\n}\n\n// RegistryTLSConfigs implements config.Config interface.\nfunc (container *Container) RegistryTLSConfigs() map[string]config.RegistryTLSConfig {\n\tvar cfg map[string]config.RegistryTLSConfig\n\n\tif container.v1alpha1Config != nil {\n\t\tcfg = container.v1alpha1Config.RegistryTLSConfigs()\n\t}\n\n\tdocs := findMatchingDocs[config.RegistryTLSConfigDocument](container.documents)\n\n\tif cfg == nil {\n\t\tcfg = make(map[string]config.RegistryTLSConfig, len(docs))\n\t}\n\n\tfor _, doc := range docs {\n\t\tcfg[doc.Name()] = doc\n\t}\n\n\treturn cfg\n}\n\n// ImageVerificationConfig implements config.Config interface.\nfunc (container *Container) ImageVerificationConfig() config.ImageVerificationConfig {\n\tdocs := findMatchingDocs[config.ImageVerificationConfig](container.documents)\n\tif len(docs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn docs[0]\n}\n\n// Bytes returns source YAML representation (if available) or does default encoding.\nfunc (container *Container) Bytes() ([]byte, error) {\n\tif !container.readonly {\n\t\treturn container.EncodeBytes()\n\t}\n\n\tif container.bytes == nil {\n\t\tpanic(\"container.Bytes() called on a readonly container without bytes\")\n\t}\n\n\treturn container.bytes, nil\n}\n\n// EncodeString configuration to YAML using the provided options.\nfunc (container *Container) EncodeString(encoderOptions ...encoder.Option) (string, error) {\n\tvar buf strings.Builder\n\n\terr := container.encodeToBuf(&buf, encoderOptions...)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn buf.String(), nil\n}\n\n// EncodeBytes configuration to YAML using the provided options.\nfunc (container *Container) EncodeBytes(encoderOptions ...encoder.Option) ([]byte, error) {\n\tvar buf bytes.Buffer\n\n\terr := container.encodeToBuf(&buf, encoderOptions...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\ntype buffer interface {\n\tLen() int\n\tWrite(p []byte) (int, error)\n\tWriteString(s string) (int, error)\n}\n\nfunc (container *Container) encodeToBuf(buf buffer, encoderOptions ...encoder.Option) error {\n\tif container.v1alpha1Config != nil {\n\t\tb, err := encoder.NewEncoder(container.v1alpha1Config, encoderOptions...).Encode()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbuf.Write(b) //nolint:errcheck\n\t}\n\n\tfor _, doc := range container.documents {\n\t\tif buf.Len() > 0 {\n\t\t\tbuf.WriteString(\"---\\n\") //nolint:errcheck\n\t\t}\n\n\t\tb, err := encoder.NewEncoder(doc, encoderOptions...).Encode()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbuf.Write(b) //nolint:errcheck\n\t}\n\n\treturn nil\n}\n\nfunc docID(doc config.Document) string {\n\tid := doc.Kind()\n\n\tif named, ok := doc.(config.NamedDocument); ok {\n\t\tid += \"/\" + named.Name()\n\t}\n\n\treturn id\n}\n\n// Validate checks configuration and returns warnings and fatal errors (as multierror).\n//\n//nolint:gocyclo\nfunc (container *Container) Validate(mode validation.RuntimeMode, opt ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings []string\n\t\terr      error\n\t)\n\n\tif container.v1alpha1Config != nil {\n\t\twarnings, err = container.v1alpha1Config.Validate(mode, opt...)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"v1alpha1.Config: %w\", err)\n\t\t}\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tif err != nil {\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\tfor _, doc := range container.documents {\n\t\tif validatableDoc, ok := doc.(config.Validator); ok {\n\t\t\tdocWarnings, docErr := validatableDoc.Validate(mode, opt...)\n\t\t\tif docErr != nil {\n\t\t\t\tdocErr = fmt.Errorf(\"%s: %w\", docID(doc), docErr)\n\t\t\t}\n\n\t\t\twarnings = append(warnings, docWarnings...)\n\t\t\tmultiErr = multierror.Append(multiErr, docErr)\n\t\t}\n\t}\n\n\t// now cross-validate the config\n\tif container.v1alpha1Config != nil {\n\t\tfor _, doc := range container.documents {\n\t\t\tif conflictValidator, ok := doc.(V1Alpha1ConflictValidator); ok {\n\t\t\t\terr := conflictValidator.V1Alpha1ConflictValidate(container.v1alpha1Config)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn warnings, multiErr.ErrorOrNil()\n}\n\n// RuntimeValidate validates the config in the runtime context.\nfunc (container *Container) RuntimeValidate(ctx context.Context, st state.State, mode validation.RuntimeMode, opt ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings []string\n\t\terr      error\n\t)\n\n\tif container.v1alpha1Config != nil {\n\t\twarnings, err = container.v1alpha1Config.RuntimeValidate(ctx, st, mode, opt...)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"v1alpha1.Config: %w\", err)\n\t\t}\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tif err != nil {\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\tfor _, doc := range container.documents {\n\t\tif validatableDoc, ok := doc.(config.RuntimeValidator); ok {\n\t\t\tdocWarnings, docErr := validatableDoc.RuntimeValidate(ctx, st, mode, opt...)\n\t\t\tif docErr != nil {\n\t\t\t\tdocErr = fmt.Errorf(\"%s: %w\", docID(doc), docErr)\n\t\t\t}\n\n\t\t\twarnings = append(warnings, docWarnings...)\n\t\t\tmultiErr = multierror.Append(multiErr, docErr)\n\t\t}\n\t}\n\n\treturn warnings, multiErr.ErrorOrNil()\n}\n\n// RedactSecrets returns a copy of the Provider with all secrets replaced with the given string.\nfunc (container *Container) RedactSecrets(replacement string) coreconfig.Provider {\n\tclone := container.clone()\n\n\tif clone.v1alpha1Config != nil {\n\t\tclone.v1alpha1Config.Redact(replacement)\n\t}\n\n\tfor _, doc := range clone.documents {\n\t\tif secretDoc, ok := doc.(config.SecretDocument); ok {\n\t\t\tsecretDoc.Redact(replacement)\n\t\t}\n\t}\n\n\treturn clone\n}\n\n// RawV1Alpha1 returns internal config representation for v1alpha1.Config.\nfunc (container *Container) RawV1Alpha1() *v1alpha1.Config {\n\tif container.readonly {\n\t\treturn container.v1alpha1Config.DeepCopy()\n\t}\n\n\treturn container.v1alpha1Config\n}\n\n// Documents returns all documents in the container.\n//\n// Documents should not be modified.\nfunc (container *Container) Documents() []config.Document {\n\tresult := make([]config.Document, 0, len(container.documents)+1)\n\n\t// first we take deletes for v1alpha1\n\tfor _, doc := range container.documents {\n\t\tif _, ok := doc.(selector); ok && doc.Kind() == v1alpha1.Version {\n\t\t\tresult = append(result, doc)\n\t\t}\n\t}\n\n\t// then we take the v1alpha1 config\n\tif container.v1alpha1Config != nil {\n\t\tresult = append(result, container.v1alpha1Config)\n\t}\n\n\t// then we take the rest\n\tfor _, doc := range container.documents {\n\t\tif _, ok := doc.(selector); ok && doc.Kind() == v1alpha1.Version {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, doc)\n\t}\n\n\treturn result\n}\n\ntype selector interface{ ApplyTo(config.Document) error }\n\n// CompleteForBoot return true if the machine config is enough to proceed with the boot process.\nfunc (container *Container) CompleteForBoot() bool {\n\t// for now, v1alpha1 config is required\n\treturn container.v1alpha1Config != nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/container/container_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage container_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xtesting/must\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestNew(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\tDiskQuotaSupport: new(true),\n\t\t\t},\n\t\t},\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tClusterSecret: \"topsecret\",\n\t\t},\n\t}\n\n\tsideroLinkCfg := siderolink.NewConfigV1Alpha1()\n\tsideroLinkCfg.APIUrlConfig.URL = must.Value(url.Parse(\"https://siderolink.api/join?jointoken=secret&user=alice\"))(t)\n\n\textensionsCfg := extensions.NewServicesConfigV1Alpha1()\n\textensionsCfg.ServiceName = \"test-extension\"\n\textensionsCfg.ServiceConfigFiles = []extensions.ConfigFile{\n\t\t{\n\t\t\tConfigFileContent:   \"test\",\n\t\t\tConfigFileMountPath: \"/etc/test\",\n\t\t},\n\t}\n\n\tpciDriverRebindCfg := hardware.NewPCIDriverRebindConfigV1Alpha1()\n\tpciDriverRebindCfg.MetaName = \"0000:04:00.00\"\n\tpciDriverRebindCfg.PCITargetDriver = \"vfio-pci\"\n\n\tcfg, err := container.New(v1alpha1Cfg, sideroLinkCfg, extensionsCfg, pciDriverRebindCfg)\n\trequire.NoError(t, err)\n\n\tassert.False(t, cfg.Readonly())\n\tassert.False(t, cfg.Debug())\n\tassert.True(t, cfg.Machine().Features().DiskQuotaSupportEnabled())\n\tassert.Equal(t, \"topsecret\", cfg.Cluster().Secret())\n\tassert.Equal(t, \"https://siderolink.api/join?jointoken=secret&user=alice\", cfg.SideroLink().APIUrl().String())\n\tassert.Equal(t, \"test-extension\", cfg.ExtensionServiceConfigs()[0].Name())\n\tassert.Equal(t, \"0000:04:00.00\", cfg.PCIDriverRebindConfig().PCIDriverRebindConfigs()[0].PCIID())\n\tassert.Same(t, v1alpha1Cfg, cfg.RawV1Alpha1())\n\tassert.Equal(t, []config.Document{v1alpha1Cfg, sideroLinkCfg, extensionsCfg, pciDriverRebindCfg}, cfg.Documents())\n\n\tbytes, err := cfg.Bytes()\n\trequire.NoError(t, err)\n\n\tcfgBack, err := configloader.NewFromBytes(bytes)\n\trequire.NoError(t, err)\n\n\tassert.True(t, cfgBack.Readonly())\n\tassert.NotEqual(t, v1alpha1Cfg, cfgBack.RawV1Alpha1())\n\n\tcfgRedacted := cfg.RedactSecrets(\"REDACTED\")\n\tassert.Equal(t, \"REDACTED\", cfgRedacted.Cluster().Secret())\n\tassert.Equal(t, \"https://siderolink.api/join?jointoken=REDACTED&user=alice\", cfgRedacted.SideroLink().APIUrl().String())\n}\n\nfunc TestNewDuplicate(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg1 := &v1alpha1.Config{}\n\tv1alpha1Cfg2 := &v1alpha1.Config{}\n\n\tsiderolink1 := siderolink.NewConfigV1Alpha1()\n\tsiderolink2 := siderolink.NewConfigV1Alpha1()\n\n\t_, err := container.New(v1alpha1Cfg1, siderolink1, v1alpha1Cfg2)\n\tassert.EqualError(t, err, \"duplicate v1alpha1.Config\")\n\n\t_, err = container.New(siderolink1, siderolink2)\n\tassert.EqualError(t, err, \"duplicate document: SideroLinkConfig/\")\n}\n\nfunc TestNewConflict(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg1 := &v1alpha1.Config{}\n\tuv1 := block.NewUserVolumeConfigV1Alpha1()\n\tuv1.MetaName = \"my-user-volume-1\"\n\tuv2 := block.NewUserVolumeConfigV1Alpha1()\n\tuv2.MetaName = \"my-user-volume-2\"\n\n\tev1 := block.NewExistingVolumeConfigV1Alpha1()\n\tev1.MetaName = \"my-user-volume-1\"\n\tev2 := block.NewExistingVolumeConfigV1Alpha1()\n\tev2.MetaName = \"my-user-volume-2\"\n\n\t_, err := container.New(v1alpha1Cfg1, uv1, uv2, ev1)\n\tassert.EqualError(t, err, \"conflicting documents: UserVolumeConfig/my-user-volume-1 and ExistingVolumeConfig/my-user-volume-1\")\n\n\t_, err = container.New(uv1, uv2)\n\trequire.NoError(t, err)\n\n\t_, err = container.New(ev2, ev1, uv1, uv2)\n\tassert.EqualError(t, err, \"conflicting documents: ExistingVolumeConfig/my-user-volume-1 and UserVolumeConfig/my-user-volume-1\")\n}\n\nfunc TestPatchV1Alpha1(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"worker\",\n\t\t},\n\t}\n\n\tsideroLinkCfg := siderolink.NewConfigV1Alpha1()\n\tsideroLinkCfg.APIUrlConfig.URL = must.Value(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))(t)\n\n\tcfg, err := container.New(v1alpha1Cfg, sideroLinkCfg)\n\trequire.NoError(t, err)\n\n\tpatchedCfg, err := cfg.PatchV1Alpha1(func(cfg *v1alpha1.Config) error {\n\t\tcfg.MachineConfig.MachineType = \"controlplane\"\n\n\t\treturn nil\n\t})\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, machine.TypeWorker, cfg.Machine().Type())\n\tassert.Equal(t, machine.TypeControlPlane, patchedCfg.Machine().Type())\n\n\tassert.Equal(t, \"https://siderolink.api/?jointoken=secret&user=alice\", cfg.SideroLink().APIUrl().String())\n\tassert.Equal(t, \"https://siderolink.api/?jointoken=secret&user=alice\", patchedCfg.SideroLink().APIUrl().String())\n}\n\nfunc TestValidate(t *testing.T) {\n\tt.Parallel()\n\n\tsideroLinkCfg := siderolink.NewConfigV1Alpha1()\n\tsideroLinkCfg.APIUrlConfig.URL = must.Value(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))(t)\n\n\tinvalidSideroLinkCfg := siderolink.NewConfigV1Alpha1()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\tURL: must.Value(url.Parse(\"https://localhost:6443\"))(t),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"worker\",\n\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\tCrt: []byte(\"cert\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tinvalidV1alpha1Config := &v1alpha1.Config{}\n\n\tfor _, tt := range []struct {\n\t\tname      string\n\t\tdocuments []config.Document\n\n\t\texpectedError     string\n\t\texpecetedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname:      \"multi-doc\",\n\t\t\tdocuments: []config.Document{sideroLinkCfg, v1alpha1Cfg},\n\t\t},\n\t\t{\n\t\t\tname:      \"only siderolink\",\n\t\t\tdocuments: []config.Document{sideroLinkCfg},\n\t\t},\n\t\t{\n\t\t\tname:      \"only v1alpha1\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg},\n\t\t},\n\t\t{\n\t\t\tname:          \"invalid siderolink\",\n\t\t\tdocuments:     []config.Document{invalidSideroLinkCfg},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* SideroLinkConfig: apiUrl is required\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname:          \"invalid v1alpha1\",\n\t\t\tdocuments:     []config.Document{invalidV1alpha1Config},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* v1alpha1.Config: 1 error occurred:\\n\\t* machine instructions are required\\n\\n\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname:          \"invalid multi-doc\",\n\t\t\tdocuments:     []config.Document{invalidSideroLinkCfg, invalidV1alpha1Config},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* v1alpha1.Config: 1 error occurred:\\n\\t* machine instructions are required\\n\\n\\n\\t* SideroLinkConfig: apiUrl is required\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctr, err := container.New(tt.documents...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\twarnings, err := ctr.Validate(validationMode{})\n\n\t\t\tif tt.expectedError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.EqualError(t, err, tt.expectedError)\n\t\t\t}\n\n\t\t\trequire.Equal(t, tt.expecetedWarnings, warnings)\n\t\t})\n\t}\n}\n\nfunc TestCrossValidateEncryption(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\tURL: must.Value(url.Parse(\"https://localhost:6443\"))(t),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"worker\",\n\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\tCrt: []byte(\"cert\"),\n\t\t\t},\n\t\t\tMachineSystemDiskEncryption: &v1alpha1.SystemDiskEncryptionConfig{\n\t\t\t\tEphemeralPartition: &v1alpha1.EncryptionConfig{\n\t\t\t\t\tEncryptionKeys: []*v1alpha1.EncryptionKey{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\t\tKeyStatic: &v1alpha1.EncryptionKeyStatic{\n\t\t\t\t\t\t\t\tKeyData: \"static-key\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdefaultEphemeral := block.NewVolumeConfigV1Alpha1()\n\tdefaultEphemeral.MetaName = constants.EphemeralPartitionLabel\n\n\tencryptedEphemeral := block.NewVolumeConfigV1Alpha1()\n\tencryptedEphemeral.MetaName = constants.EphemeralPartitionLabel\n\tencryptedEphemeral.EncryptionSpec = block.EncryptionSpec{\n\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []block.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 2,\n\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"encrypted-static-key\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tencryptedState := block.NewVolumeConfigV1Alpha1()\n\tencryptedState.MetaName = constants.StatePartitionLabel\n\tencryptedState.EncryptionSpec = block.EncryptionSpec{\n\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []block.EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 3,\n\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range []struct {\n\t\tname      string\n\t\tdocuments []config.Document\n\n\t\texpectedError     string\n\t\texpecetedWarnings []string\n\t}{\n\t\t{\n\t\t\tname:      \"only v1alpha1\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg},\n\t\t},\n\t\t{\n\t\t\tname:      \"v1alpha1 with no-conflict volumes\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg, defaultEphemeral, encryptedState},\n\t\t},\n\t\t{\n\t\t\tname:      \"v1alpha1 with no-conflict volumes\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg, encryptedState},\n\t\t},\n\t\t{\n\t\t\tname:      \"no v1alpha1\",\n\t\t\tdocuments: []config.Document{encryptedEphemeral, encryptedState},\n\t\t},\n\t\t{\n\t\t\tname:          \"conflict on ephemeral encryption\",\n\t\t\tdocuments:     []config.Document{v1alpha1Cfg, encryptedEphemeral},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* system disk encryption for \\\"EPHEMERAL\\\" is configured in both v1alpha1.Config and VolumeConfig\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctr, err := container.New(tt.documents...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\twarnings, err := ctr.Validate(validationMode{})\n\n\t\t\tif tt.expectedError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.EqualError(t, err, tt.expectedError)\n\t\t\t}\n\n\t\t\trequire.Equal(t, tt.expecetedWarnings, warnings)\n\t\t})\n\t}\n}\n\nfunc TestRunDefaultDHCPOperators(t *testing.T) {\n\tt.Parallel()\n\n\tv1alpha1Cfg := &v1alpha1.Config{\n\t\tClusterConfig: &v1alpha1.ClusterConfig{},\n\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\tMachineType: \"worker\",\n\t\t},\n\t}\n\n\tdummyLinkConfig := network.NewDummyLinkConfigV1Alpha1(\"dummy1\")\n\n\tfor _, tt := range []struct {\n\t\tname      string\n\t\tdocuments []config.Document\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tname:      \"empty\",\n\t\t\tdocuments: []config.Document{},\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:      \"only v1alpha1\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg},\n\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tname:      \"has dummy link config\",\n\t\t\tdocuments: []config.Document{v1alpha1Cfg, dummyLinkConfig},\n\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tname:      \"only dummy link config\",\n\t\t\tdocuments: []config.Document{dummyLinkConfig},\n\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctr, err := container.New(tt.documents...)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expected, ctr.RunDefaultDHCPOperators())\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/contract.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// VersionContract describes Talos version to generate config for.\n//\n// Config generation only supports backwards compatibility (e.g. Talos 0.9 can generate configs for Talos 0.9 and 0.8).\n// Matching version of the machinery package is required to generate configs for the current version of Talos.\n//\n// Nil value of *VersionContract always describes current version of Talos.\ntype VersionContract struct {\n\tMajor int\n\tMinor int\n}\n\n// Well-known Talos version contracts.\nvar (\n\tTalosVersionCurrent = (*VersionContract)(nil)\n\tTalosVersion1_13    = &VersionContract{1, 13}\n\tTalosVersion1_12    = &VersionContract{1, 12}\n\tTalosVersion1_11    = &VersionContract{1, 11}\n\tTalosVersion1_10    = &VersionContract{1, 10}\n\tTalosVersion1_9     = &VersionContract{1, 9}\n\tTalosVersion1_8     = &VersionContract{1, 8}\n\tTalosVersion1_7     = &VersionContract{1, 7}\n\tTalosVersion1_6     = &VersionContract{1, 6}\n\tTalosVersion1_5     = &VersionContract{1, 5}\n\tTalosVersion1_4     = &VersionContract{1, 4}\n\tTalosVersion1_3     = &VersionContract{1, 3}\n\tTalosVersion1_2     = &VersionContract{1, 2}\n\tTalosVersion1_1     = &VersionContract{1, 1}\n\tTalosVersion1_0     = &VersionContract{1, 0}\n)\n\nvar versionRegexp = regexp.MustCompile(`^v(\\d+)\\.(\\d+)($|\\.)`)\n\n// ParseContractFromVersion parses Talos version into VersionContract.\nfunc ParseContractFromVersion(version string) (*VersionContract, error) {\n\tversion = \"v\" + strings.TrimPrefix(version, \"v\")\n\n\tmatches := versionRegexp.FindStringSubmatch(version)\n\tif len(matches) < 3 {\n\t\treturn nil, fmt.Errorf(\"error parsing version %q\", version)\n\t}\n\n\tvar contract VersionContract\n\n\tcontract.Major, _ = strconv.Atoi(matches[1]) //nolint:errcheck\n\tcontract.Minor, _ = strconv.Atoi(matches[2]) //nolint:errcheck\n\n\treturn &contract, nil\n}\n\n// String returns string representation of the contract.\nfunc (contract *VersionContract) String() string {\n\tif contract == nil {\n\t\treturn \"current\"\n\t}\n\n\treturn fmt.Sprintf(\"v%d.%d\", contract.Major, contract.Minor)\n}\n\n// Greater compares contract to another contract.\nfunc (contract *VersionContract) Greater(other *VersionContract) bool {\n\tif contract == nil {\n\t\treturn other != nil\n\t}\n\n\tif other == nil {\n\t\treturn false\n\t}\n\n\treturn contract.Major > other.Major || (contract.Major == other.Major && contract.Minor > other.Minor)\n}\n\n// PodSecurityAdmissionEnabled returns true if pod security admission should be enabled by default.\nfunc (contract *VersionContract) PodSecurityAdmissionEnabled() bool {\n\treturn contract.Greater(TalosVersion1_0)\n}\n\n// StableHostnameEnabled returns true if stable hostname generation should be enabled by default.\nfunc (contract *VersionContract) StableHostnameEnabled() bool {\n\treturn contract.Greater(TalosVersion1_1)\n}\n\n// KubeletDefaultRuntimeSeccompProfileEnabled returns true if kubelet seccomp profile should be enabled by default.\nfunc (contract *VersionContract) KubeletDefaultRuntimeSeccompProfileEnabled() bool {\n\treturn contract.Greater(TalosVersion1_1)\n}\n\n// KubernetesAlternateImageRegistries returns true if alternate image registries should be enabled by default.\n// https://github.com/kubernetes/kubernetes/pull/109938\nfunc (contract *VersionContract) KubernetesAlternateImageRegistries() bool {\n\treturn contract.Greater(TalosVersion1_1) && !contract.Greater(TalosVersion1_2)\n}\n\n// KubernetesAllowSchedulingOnControlPlanes returns true if scheduling on control planes should be enabled by default.\nfunc (contract *VersionContract) KubernetesAllowSchedulingOnControlPlanes() bool {\n\treturn contract.Greater(TalosVersion1_1)\n}\n\n// KubernetesDiscoveryBackendDisabled returns true if Kubernetes cluster discovery backend should be disabled by default.\nfunc (contract *VersionContract) KubernetesDiscoveryBackendDisabled() bool {\n\treturn contract.Greater(TalosVersion1_1)\n}\n\n// ApidExtKeyUsageCheckEnabled returns true if apid should check ext key usage of client certificates.\nfunc (contract *VersionContract) ApidExtKeyUsageCheckEnabled() bool {\n\treturn contract.Greater(TalosVersion1_2)\n}\n\n// APIServerAuditPolicySupported returns true if kube-apiserver custom audit policy is supported.\nfunc (contract *VersionContract) APIServerAuditPolicySupported() bool {\n\treturn contract.Greater(TalosVersion1_2)\n}\n\n// KubeletManifestsDirectoryDisabled returns true if the manifests directory flag is supported.\nfunc (contract *VersionContract) KubeletManifestsDirectoryDisabled() bool {\n\treturn contract.Greater(TalosVersion1_2)\n}\n\n// SecretboxEncryptionSupported returns true if encryption with secretbox is supported.\nfunc (contract *VersionContract) SecretboxEncryptionSupported() bool {\n\treturn contract.Greater(TalosVersion1_2)\n}\n\n// DiskQuotaSupportEnabled returns true if XFS filesystems should enable project quota.\nfunc (contract *VersionContract) DiskQuotaSupportEnabled() bool {\n\treturn contract.Greater(TalosVersion1_4)\n}\n\n// KubePrismEnabled returns true if KubePrism should be enabled by default.\nfunc (contract *VersionContract) KubePrismEnabled() bool {\n\treturn contract.Greater(TalosVersion1_5)\n}\n\n// HostDNSEnabled returns true if host dns router should be enabled by default.\nfunc (contract *VersionContract) HostDNSEnabled() bool {\n\treturn contract.Greater(TalosVersion1_6)\n}\n\n// UseRSAServiceAccountKey returns true if version of Talos should use RSA Service Account key for the kube-apiserver.\nfunc (contract *VersionContract) UseRSAServiceAccountKey() bool {\n\treturn contract.Greater(TalosVersion1_6)\n}\n\n// ClusterNameForWorkers returns true if version of Talos should put cluster name to the worker machine config.\nfunc (contract *VersionContract) ClusterNameForWorkers() bool {\n\treturn contract.Greater(TalosVersion1_7)\n}\n\n// HostDNSForwardKubeDNSToHost returns true if version of Talos forces host dns router to be used as upstream for Kubernetes CoreDNS pods.\nfunc (contract *VersionContract) HostDNSForwardKubeDNSToHost() bool {\n\treturn contract.Greater(TalosVersion1_7)\n}\n\n// AddExcludeFromExternalLoadBalancer returns true if the label 'node.kubernetes.io/exclude-from-external-load-balancers' is automatically added\n// for controlplane nodes.\nfunc (contract *VersionContract) AddExcludeFromExternalLoadBalancer() bool {\n\treturn contract.Greater(TalosVersion1_7)\n}\n\n// SecureBootEnrollEnforcementSupported returns true if version of Talos supports SecureBoot enforcement on enroll.\nfunc (contract *VersionContract) SecureBootEnrollEnforcementSupported() bool {\n\treturn contract.Greater(TalosVersion1_7)\n}\n\n// VolumeConfigEncryptionSupported returns true if version of Talos supports disk encryption via VolumeConfig.\nfunc (contract *VersionContract) VolumeConfigEncryptionSupported() bool {\n\treturn contract.Greater(TalosVersion1_10)\n}\n\n// MultidocNetworkConfigSupported returns true if version of Talos supports multiple NetworkConfig documents.\nfunc (contract *VersionContract) MultidocNetworkConfigSupported() bool {\n\treturn contract.Greater(TalosVersion1_11)\n}\n\n// HideDisablePSP returns true if version of Talos should hide DisablePodSecurityPolicy field from the user.\nfunc (contract *VersionContract) HideDisablePSP() bool {\n\treturn contract.Greater(TalosVersion1_11)\n}\n\n// HideRBACAndKeyUsage returns true if version of Talos should hide RBAC and ApidCheckExtKeyUsage fields from the user.\nfunc (contract *VersionContract) HideRBACAndKeyUsage() bool {\n\treturn contract.Greater(TalosVersion1_11)\n}\n\n// PopulateClusterSANsFromEndpoint returns true if version of Talos should populate cluster SANs from ControlPlaneEndpoint.\nfunc (contract *VersionContract) PopulateClusterSANsFromEndpoint() bool {\n\treturn !contract.Greater(TalosVersion1_11)\n}\n\n// GrubUseUKICmdlineDefault returns true if version of Talos should use UKI cmdline by default.\nfunc (contract *VersionContract) GrubUseUKICmdlineDefault() bool {\n\treturn contract.Greater(TalosVersion1_11)\n}\n\n// KubeSpanMultidocConfig returns true if version of Talos should use KubeSpan multi-doc config.\nfunc (contract *VersionContract) KubeSpanMultidocConfig() bool {\n\treturn contract.Greater(TalosVersion1_12)\n}\n"
  },
  {
    "path": "pkg/machinery/config/contract_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage config_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n)\n\nfunc TestContractGreater(t *testing.T) {\n\tassert.True(t, config.TalosVersion1_1.Greater(config.TalosVersion1_0))\n\tassert.True(t, config.TalosVersionCurrent.Greater(config.TalosVersion1_2))\n\tassert.True(t, config.TalosVersionCurrent.Greater(config.TalosVersion1_3))\n\n\tassert.False(t, config.TalosVersion1_2.Greater(config.TalosVersion1_3))\n\tassert.False(t, config.TalosVersion1_2.Greater(config.TalosVersion1_2))\n\tassert.False(t, config.TalosVersionCurrent.Greater(config.TalosVersionCurrent))\n}\n\nfunc TestContractParseVersion(t *testing.T) {\n\tt.Parallel()\n\n\tfor v, expected := range map[string]*config.VersionContract{\n\t\t\"v1.5\":           config.TalosVersion1_5,\n\t\t\"v1.5.\":          config.TalosVersion1_5,\n\t\t\"v1.5.1\":         config.TalosVersion1_5,\n\t\t\"v1.88\":          {1, 88},\n\t\t\"v1.5.3-alpha.4\": config.TalosVersion1_5,\n\t\t\"1.6\":            config.TalosVersion1_6,\n\t} {\n\t\tt.Run(v, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual, err := config.ParseContractFromVersion(v)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestContractCurrent(t *testing.T) {\n\tcontract := config.TalosVersionCurrent\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.True(t, contract.VolumeConfigEncryptionSupported())\n\tassert.True(t, contract.MultidocNetworkConfigSupported())\n\tassert.True(t, contract.HideDisablePSP())\n\tassert.True(t, contract.HideRBACAndKeyUsage())\n\tassert.False(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.True(t, contract.GrubUseUKICmdlineDefault())\n\tassert.True(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_13(t *testing.T) {\n\tcontract := config.TalosVersion1_13\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.True(t, contract.VolumeConfigEncryptionSupported())\n\tassert.True(t, contract.MultidocNetworkConfigSupported())\n\tassert.True(t, contract.HideDisablePSP())\n\tassert.True(t, contract.HideRBACAndKeyUsage())\n\tassert.False(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.True(t, contract.GrubUseUKICmdlineDefault())\n\tassert.True(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_12(t *testing.T) {\n\tcontract := config.TalosVersion1_12\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.True(t, contract.VolumeConfigEncryptionSupported())\n\tassert.True(t, contract.MultidocNetworkConfigSupported())\n\tassert.True(t, contract.HideDisablePSP())\n\tassert.True(t, contract.HideRBACAndKeyUsage())\n\tassert.False(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.True(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_11(t *testing.T) {\n\tcontract := config.TalosVersion1_11\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.True(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_10(t *testing.T) {\n\tcontract := config.TalosVersion1_10\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_9(t *testing.T) {\n\tcontract := config.TalosVersion1_9\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_8(t *testing.T) {\n\tcontract := config.TalosVersion1_8\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.True(t, contract.ClusterNameForWorkers())\n\tassert.True(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.True(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.True(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_7(t *testing.T) {\n\tcontract := config.TalosVersion1_7\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.True(t, contract.HostDNSEnabled())\n\tassert.True(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_6(t *testing.T) {\n\tcontract := config.TalosVersion1_6\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.True(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_5(t *testing.T) {\n\tcontract := config.TalosVersion1_5\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.True(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_4(t *testing.T) {\n\tcontract := config.TalosVersion1_4\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.False(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_3(t *testing.T) {\n\tcontract := config.TalosVersion1_3\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.True(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.True(t, contract.APIServerAuditPolicySupported())\n\tassert.True(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.True(t, contract.SecretboxEncryptionSupported())\n\tassert.False(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_2(t *testing.T) {\n\tcontract := config.TalosVersion1_2\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.True(t, contract.StableHostnameEnabled())\n\tassert.True(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.True(t, contract.KubernetesAlternateImageRegistries())\n\tassert.True(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.True(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.False(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.False(t, contract.APIServerAuditPolicySupported())\n\tassert.False(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.False(t, contract.SecretboxEncryptionSupported())\n\tassert.False(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_1(t *testing.T) {\n\tcontract := config.TalosVersion1_1\n\n\tassert.True(t, contract.PodSecurityAdmissionEnabled())\n\tassert.False(t, contract.StableHostnameEnabled())\n\tassert.False(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.False(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.False(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.False(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.False(t, contract.APIServerAuditPolicySupported())\n\tassert.False(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.False(t, contract.SecretboxEncryptionSupported())\n\tassert.False(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n\nfunc TestContract1_0(t *testing.T) {\n\tcontract := config.TalosVersion1_0\n\n\tassert.False(t, contract.PodSecurityAdmissionEnabled())\n\tassert.False(t, contract.StableHostnameEnabled())\n\tassert.False(t, contract.KubeletDefaultRuntimeSeccompProfileEnabled())\n\tassert.False(t, contract.KubernetesAlternateImageRegistries())\n\tassert.False(t, contract.KubernetesAllowSchedulingOnControlPlanes())\n\tassert.False(t, contract.KubernetesDiscoveryBackendDisabled())\n\tassert.False(t, contract.ApidExtKeyUsageCheckEnabled())\n\tassert.False(t, contract.APIServerAuditPolicySupported())\n\tassert.False(t, contract.KubeletManifestsDirectoryDisabled())\n\tassert.False(t, contract.SecretboxEncryptionSupported())\n\tassert.False(t, contract.DiskQuotaSupportEnabled())\n\tassert.False(t, contract.KubePrismEnabled())\n\tassert.False(t, contract.HostDNSEnabled())\n\tassert.False(t, contract.UseRSAServiceAccountKey())\n\tassert.False(t, contract.ClusterNameForWorkers())\n\tassert.False(t, contract.HostDNSForwardKubeDNSToHost())\n\tassert.False(t, contract.AddExcludeFromExternalLoadBalancer())\n\tassert.False(t, contract.SecureBootEnrollEnforcementSupported())\n\tassert.False(t, contract.VolumeConfigEncryptionSupported())\n\tassert.False(t, contract.MultidocNetworkConfigSupported())\n\tassert.False(t, contract.HideDisablePSP())\n\tassert.False(t, contract.HideRBACAndKeyUsage())\n\tassert.True(t, contract.PopulateClusterSANsFromEndpoint())\n\tassert.False(t, contract.GrubUseUKICmdlineDefault())\n\tassert.False(t, contract.KubeSpanMultidocConfig())\n}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/documentation.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encoder\n\nimport (\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\n\tyaml \"go.yaml.in/yaml/v4\"\n)\n\nconst (\n\t// HeadComment populates `yaml.Node` `HeadComment`.\n\tHeadComment = iota\n\t// LineComment populates `yaml.Node` `LineComment`.\n\tLineComment\n\t// FootComment populates `yaml.Node` `FootComment`.\n\tFootComment\n)\n\n// Doc represents a struct documentation rendered from comments by docgen.\ntype Doc struct {\n\t// Comments stores foot, line and head comments.\n\tComments [3]string\n\t// Fields contains fields documentation if related item is a struct.\n\tFields []Doc\n\t// Examples list of example values for the item.\n\tExamples []*Example\n\t// Values is only used to render valid values list in the documentation.\n\tValues []string\n\t// Description represents the full description for the item.\n\tDescription string\n\t// Name represents struct name or field name.\n\tName string\n\t// Type represents struct name or field type.\n\tType string\n\t// Note is rendered as a note for the example in markdown file.\n\tNote string\n\t// AppearsIn describes back references for the type.\n\tAppearsIn []Appearance\n\t// Inline indicates that this field is inlined (embedded).\n\tInline bool\n}\n\n// AddExample adds a new example snippet to the doc.\nfunc (d *Doc) AddExample(name string, value any) {\n\tif d.Examples == nil {\n\t\td.Examples = []*Example{}\n\t}\n\n\td.Examples = append(d.Examples, &Example{\n\t\tName:  name,\n\t\tvalue: value,\n\t})\n}\n\n// Describe returns a field description.\nfunc (d *Doc) Describe(field string, short bool) string {\n\tdesc := \"\"\n\n\tfor _, f := range d.Fields {\n\t\tif f.Name == field {\n\t\t\tdesc = f.Description\n\t\t}\n\t}\n\n\tif short {\n\t\tdesc = strings.Split(desc, \"\\n\")[0]\n\t}\n\n\treturn desc\n}\n\n// Example represents one example snippet for a type.\ntype Example struct {\n\tpopulate sync.Once\n\tName     string\n\n\tvalueMutex sync.RWMutex\n\tvalue      any\n}\n\n// Populate populates example value.\nfunc (e *Example) Populate(index int) {\n\te.populate.Do(func() {\n\t\tif reflect.TypeOf(e.value).Kind() != reflect.Ptr {\n\t\t\treturn\n\t\t}\n\n\t\tv := reflect.ValueOf(e.value).Elem()\n\n\t\tdefaultValue := getExample(v, getDoc(e.value), index)\n\n\t\te.valueMutex.Lock()\n\t\tdefer e.valueMutex.Unlock()\n\n\t\tif defaultValue != nil {\n\t\t\tv.Set(defaultValue.Convert(v.Type()))\n\t\t}\n\n\t\tpopulateNestedExamples(v, index)\n\t})\n}\n\n// GetValue returns example value.\nfunc (e *Example) GetValue() any {\n\te.valueMutex.RLock()\n\tdefer e.valueMutex.RUnlock()\n\n\treturn e.value\n}\n\n// Field gets field from the list of fields.\nfunc (d *Doc) Field(i int) *Doc {\n\tif i < len(d.Fields) {\n\t\treturn &d.Fields[i]\n\t}\n\n\treturn nil\n}\n\n// Appearance of a type in a different type.\ntype Appearance struct {\n\tTypeName  string\n\tFieldName string\n}\n\n// Documented is used to check if struct has any documentation defined for it.\ntype Documented interface {\n\t// Doc requests documentation object.\n\tDoc() *Doc\n}\n\nfunc mergeDoc(a, b *Doc) *Doc {\n\tvar res Doc\n\tif a != nil {\n\t\tres = *a\n\t}\n\n\tif b == nil {\n\t\treturn &res\n\t}\n\n\tfor i, comment := range b.Comments {\n\t\tif comment != \"\" {\n\t\t\tres.Comments[i] = comment\n\t\t}\n\t}\n\n\tif len(res.Examples) == 0 {\n\t\tres.Examples = b.Examples\n\t}\n\n\treturn &res\n}\n\nfunc getDoc(in any) *Doc {\n\tv := reflect.ValueOf(in)\n\tif v.Kind() == reflect.Ptr && v.IsNil() {\n\t\tin = reflect.New(v.Type().Elem()).Interface()\n\t}\n\n\tif d, ok := in.(Documented); ok {\n\t\treturn d.Doc()\n\t}\n\n\treturn nil\n}\n\nfunc addComments(node *yaml.Node, doc *Doc, comments ...int) {\n\tif doc != nil {\n\t\tdest := []*string{\n\t\t\t&node.HeadComment,\n\t\t\t&node.LineComment,\n\t\t\t&node.FootComment,\n\t\t}\n\n\t\tif len(comments) == 0 {\n\t\t\tcomments = []int{\n\t\t\t\tHeadComment,\n\t\t\t\tLineComment,\n\t\t\t\tFootComment,\n\t\t\t}\n\t\t}\n\n\t\tfor _, i := range comments {\n\t\t\tif doc.Comments[i] != \"\" {\n\t\t\t\t*dest[i] = doc.Comments[i]\n\t\t\t}\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc renderExample(key string, doc *Doc, options *Options) string {\n\tif doc == nil {\n\t\treturn \"\"\n\t}\n\n\texamples := make([]string, 0, len(doc.Examples))\n\n\tfor i, e := range doc.Examples {\n\t\tv := reflect.ValueOf(e.GetValue())\n\n\t\tif isEmpty(v) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif v.Kind() != reflect.Ptr {\n\t\t\tv = reflect.Indirect(v)\n\t\t}\n\n\t\tdefaultValue := v.Interface()\n\n\t\te.Populate(i)\n\n\t\tnode, err := toYamlNode(defaultValue, options)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif key != \"\" {\n\t\t\tnode, err = toYamlNode(map[string]*yaml.Node{\n\t\t\t\tkey: node,\n\t\t\t}, options)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif i == 0 && options.Comments.enabled(CommentsDocs) {\n\t\t\taddComments(node, doc, HeadComment, LineComment)\n\t\t}\n\n\t\t// replace head comment with line comment\n\t\tif node.HeadComment == \"\" {\n\t\t\tnode.HeadComment = node.LineComment\n\t\t}\n\n\t\tnode.LineComment = \"\"\n\t\tif e.Name != \"\" {\n\t\t\tif node.HeadComment != \"\" {\n\t\t\t\tnode.HeadComment += \"\\n\\n\"\n\t\t\t}\n\n\t\t\tnode.HeadComment = node.HeadComment + e.Name + \"\\n\"\n\t\t}\n\n\t\tdata, err := yaml.Marshal(node)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif key == \"\" {\n\t\t\t// re-indent\n\t\t\tdata = regexp.MustCompile(`(?m)^(.)`).ReplaceAll(data, []byte(\"  $1\"))\n\t\t} else {\n\t\t\t// don't collapse comment\n\t\t\tdata = regexp.MustCompile(`(?m)^#`).ReplaceAll(data, []byte(\"# #\"))\n\t\t}\n\n\t\texamples = append(examples, string(data))\n\t}\n\n\treturn strings.Join(examples, \"\")\n}\n\nfunc getExample(v reflect.Value, doc *Doc, index int) *reflect.Value {\n\tif doc == nil || len(doc.Examples) == 0 {\n\t\treturn nil\n\t}\n\n\tnumExamples := len(doc.Examples)\n\tif index >= numExamples {\n\t\tindex = numExamples - 1\n\t}\n\n\tdefaultValue := reflect.ValueOf(doc.Examples[index].GetValue())\n\tif !isEmpty(defaultValue) {\n\t\tif v.Kind() != reflect.Ptr && defaultValue.Kind() == reflect.Ptr {\n\t\t\tdefaultValue = defaultValue.Elem()\n\t\t}\n\t}\n\n\treturn &defaultValue\n}\n\n//nolint:gocyclo\nfunc populateNestedExamples(v reflect.Value, index int) {\n\t//nolint:exhaustive\n\tswitch v.Kind() {\n\tcase reflect.Struct:\n\t\tdoc := getDoc(v.Interface())\n\n\t\tfor i := range v.NumField() {\n\t\t\tfield := v.Field(i)\n\t\t\tif !field.CanInterface() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif doc != nil && i < len(doc.Fields) {\n\t\t\t\tdefaultValue := getExample(field, doc.Field(i), index)\n\n\t\t\t\tif defaultValue != nil {\n\t\t\t\t\tfield.Set(defaultValue.Convert(field.Type()))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpopulateNestedExamples(field, index)\n\t\t}\n\tcase reflect.Map:\n\t\tfor _, key := range v.MapKeys() {\n\t\t\tpopulateNestedExamples(v.MapIndex(key), index)\n\t\t}\n\tcase reflect.Slice:\n\t\tfor i := range v.Len() {\n\t\t\tpopulateNestedExamples(v.Index(i), index)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/encoder.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encoder\n\nimport (\n\t\"cmp\"\n\t\"encoding\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strings\"\n\n\tyaml \"go.yaml.in/yaml/v4\"\n)\n\n// Encoder implements config encoder.\ntype Encoder struct {\n\tvalue   any\n\toptions *Options\n}\n\n// NewEncoder initializes and returns an `Encoder`.\nfunc NewEncoder(value any, opts ...Option) *Encoder {\n\treturn &Encoder{\n\t\tvalue:   value,\n\t\toptions: newOptions(opts...),\n\t}\n}\n\n// Marshal converts value to YAML-serializable value (suitable for MarshalYAML).\nfunc (e *Encoder) Marshal() (*yaml.Node, error) {\n\tnode, err := toYamlNode(e.value, e.options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif e.options.Comments.enabled(CommentsDocs) {\n\t\taddComments(node, getDoc(e.value), HeadComment, LineComment)\n\t}\n\n\treturn node, nil\n}\n\n// Encode converts value to yaml.\n//\n//nolint:gocyclo\nfunc (e *Encoder) Encode() ([]byte, error) {\n\tif e.options.Comments == CommentsDisabled {\n\t\treturn yaml.Marshal(e.value)\n\t}\n\n\tnode, err := e.Marshal()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// special handling for case when we get an empty output\n\tif node.Kind == yaml.MappingNode && len(node.Content) == 0 && node.FootComment != \"\" && e.options.Comments.enabled(CommentsExamples) {\n\t\tres := \"\"\n\n\t\tif node.HeadComment != \"\" {\n\t\t\tres += node.HeadComment + \"\\n\"\n\t\t}\n\n\t\tlines := strings.Split(res+node.FootComment, \"\\n\")\n\t\tfor i, line := range lines {\n\t\t\tif strings.HasPrefix(line, \"#\") || strings.TrimSpace(line) == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlines[i] = \"# \" + line\n\t\t}\n\n\t\treturn []byte(strings.Join(lines, \"\\n\")), nil\n\t}\n\n\treturn yaml.Marshal(node)\n}\n\nfunc isEmpty(value reflect.Value) bool {\n\tif !value.IsValid() {\n\t\treturn true\n\t}\n\n\t//nolint:exhaustive\n\tswitch value.Kind() {\n\tcase reflect.Ptr:\n\t\treturn value.IsNil()\n\tcase reflect.Map:\n\t\treturn len(value.MapKeys()) == 0\n\tcase reflect.Slice:\n\t\treturn value.Len() == 0\n\tdefault:\n\t\treturn value.IsZero()\n\t}\n}\n\nfunc isNil(value reflect.Value) bool {\n\tif !value.IsValid() {\n\t\treturn true\n\t}\n\n\t//nolint:exhaustive\n\tswitch value.Kind() {\n\tcase reflect.Ptr, reflect.Map, reflect.Slice:\n\t\treturn value.IsNil()\n\tdefault:\n\t\treturn false\n\t}\n}\n\n//nolint:gocyclo,cyclop\nfunc toYamlNode(in any, options *Options) (*yaml.Node, error) {\n\tnode := &yaml.Node{}\n\n\tflags := options.Comments\n\n\t// do not wrap yaml.Node into yaml.Node\n\tif n, ok := in.(*yaml.Node); ok {\n\t\treturn n, nil\n\t}\n\n\t// if input implements yaml.Marshaler we should use that marshaller instead\n\t// same way as regular yaml marshal does\n\tif m, ok := in.(yaml.Marshaler); ok && !isNil(reflect.ValueOf(in)) {\n\t\tres, err := m.MarshalYAML()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif n, ok := res.(*yaml.Node); ok {\n\t\t\treturn n, nil\n\t\t}\n\n\t\tin = res\n\t}\n\n\tif _, ok := in.(encoding.TextMarshaler); ok && !isNil(reflect.ValueOf(in)) {\n\t\treturn node, node.Encode(in)\n\t}\n\n\tv := reflect.ValueOf(in)\n\tif v.Kind() == reflect.Ptr {\n\t\tv = v.Elem()\n\t}\n\n\tdoc := getDoc(in)\n\n\t//nolint:exhaustive\n\tswitch v.Kind() {\n\tcase reflect.Struct:\n\t\tnode.Kind = yaml.MappingNode\n\n\t\tt := v.Type()\n\n\t\tvar examples []string\n\n\t\tfor i := range v.NumField() {\n\t\t\t// skip unexported fields\n\t\t\tif !v.Field(i).CanInterface() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttag := t.Field(i).Tag.Get(\"yaml\")\n\t\t\tparts := strings.Split(tag, \",\")\n\t\t\tfieldName := parts[0]\n\t\t\tparts = parts[1:]\n\n\t\t\ttag = t.Field(i).Tag.Get(\"talos\")\n\t\t\tif tag != \"\" {\n\t\t\t\tparts = append(parts, strings.Split(tag, \",\")...)\n\t\t\t}\n\n\t\t\tif fieldName == \"\" {\n\t\t\t\tfieldName = strings.ToLower(t.Field(i).Name)\n\t\t\t}\n\n\t\t\tif fieldName == \"-\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar (\n\t\t\t\tempty = isEmpty(v.Field(i))\n\t\t\t\tnull  = isNil(v.Field(i))\n\n\t\t\t\tskip   bool\n\t\t\t\tinline bool\n\t\t\t\tflow   bool\n\t\t\t)\n\n\t\t\tfor _, part := range parts {\n\t\t\t\tif part == \"omitempty\" && empty && options.OmitEmpty {\n\t\t\t\t\tskip = true\n\t\t\t\t}\n\n\t\t\t\tif part == \"omitonlyifnil\" && !null {\n\t\t\t\t\tskip = false\n\t\t\t\t}\n\n\t\t\t\tif part == \"inline\" {\n\t\t\t\t\tinline = true\n\t\t\t\t}\n\n\t\t\t\tif part == \"flow\" {\n\t\t\t\t\tflow = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar value any\n\t\t\tif v.Field(i).CanInterface() {\n\t\t\t\tvalue = v.Field(i).Interface()\n\t\t\t}\n\n\t\t\t// get documentation data either from field, or from type\n\t\t\tvar fieldDoc *Doc\n\n\t\t\tif doc != nil {\n\t\t\t\tfieldDoc = mergeDoc(getDoc(value), doc.Field(i))\n\t\t\t} else {\n\t\t\t\tfieldDoc = getDoc(value)\n\t\t\t}\n\n\t\t\t// inlineExample is rendered after the value\n\t\t\tvar inlineExample string\n\n\t\t\tif empty && flags.enabled(CommentsExamples) && fieldDoc != nil {\n\t\t\t\tif skip {\n\t\t\t\t\t// render example to be appended to the end of the rendered struct\n\t\t\t\t\texample := renderExample(fieldName, fieldDoc, options)\n\n\t\t\t\t\tif example != \"\" {\n\t\t\t\t\t\texamples = append(examples, example)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// render example to be appended to the empty field\n\t\t\t\t\tfieldDocCopy := *fieldDoc\n\t\t\t\t\tfieldDocCopy.Comments = [3]string{}\n\n\t\t\t\t\tinlineExample = renderExample(\"\", &fieldDocCopy, options)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif skip {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar style yaml.Style\n\t\t\tif flow {\n\t\t\t\tstyle |= yaml.FlowStyle\n\t\t\t}\n\n\t\t\tif inline {\n\t\t\t\tchild, err := toYamlNode(value, options)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tif child.Kind == yaml.MappingNode || child.Kind == yaml.SequenceNode {\n\t\t\t\t\tappendNodes(node, child.Content...)\n\t\t\t\t}\n\t\t\t} else if err := addToMap(node, fieldDoc, fieldName, value, style, options); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif inlineExample != \"\" {\n\t\t\t\tnodeToAttach := node.Content[len(node.Content)-1]\n\n\t\t\t\tif nodeToAttach.FootComment != \"\" {\n\t\t\t\t\tnodeToAttach.FootComment += \"\\n\"\n\t\t\t\t}\n\n\t\t\t\tnodeToAttach.FootComment += inlineExample\n\t\t\t}\n\t\t}\n\n\t\tif len(examples) > 0 {\n\t\t\tcomment := strings.Join(examples, \"\\n\")\n\t\t\t// add rendered example to the foot comment of the last node\n\t\t\t// or to the foot comment of parent node\n\t\t\tif len(node.Content) > 0 {\n\t\t\t\tnode.Content[len(node.Content)-2].FootComment += \"\\n\" + comment\n\t\t\t} else {\n\t\t\t\tnode.FootComment += comment\n\t\t\t}\n\t\t}\n\tcase reflect.Map:\n\t\tnode.Kind = yaml.MappingNode\n\t\tkeys := v.MapKeys()\n\t\t// always interate keys in alphabetical order to preserve the same output for maps\n\t\tslices.SortFunc(keys, func(a, b reflect.Value) int { return cmp.Compare(a.String(), b.String()) })\n\n\t\tfor _, k := range keys {\n\t\t\telement := v.MapIndex(k)\n\t\t\tvalue := element.Interface()\n\n\t\t\tif err := addToMap(node, nil, k.Interface(), value, 0, options); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\tcase reflect.Slice:\n\t\tnode.Kind = yaml.SequenceNode\n\t\tnodes := make([]*yaml.Node, v.Len())\n\n\t\tfor i := range v.Len() {\n\t\t\telement := v.Index(i)\n\n\t\t\tvar err error\n\n\t\t\tnodes[i], err = toYamlNode(element.Interface(), options)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tappendNodes(node, nodes...)\n\n\tdefault:\n\t\tif err := node.Encode(in); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn node, nil\n}\n\nfunc appendNodes(dest *yaml.Node, nodes ...*yaml.Node) {\n\tif dest.Content == nil {\n\t\tdest.Content = []*yaml.Node{}\n\t}\n\n\tdest.Content = append(dest.Content, nodes...)\n}\n\nfunc addToMap(dest *yaml.Node, doc *Doc, fieldName, in any, style yaml.Style, options *Options) error {\n\tkey, err := toYamlNode(fieldName, options)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalue, err := toYamlNode(in, options)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvalue.Style = style\n\n\tif options.Comments.enabled(CommentsDocs) {\n\t\taddComments(key, doc, HeadComment, FootComment)\n\t\taddComments(value, doc, LineComment)\n\t}\n\n\t// override head comment with line comment for non-scalar nodes\n\tif value.Kind != yaml.ScalarNode {\n\t\tif key.HeadComment == \"\" {\n\t\t\tkey.HeadComment = value.LineComment\n\t\t}\n\n\t\tvalue.LineComment = \"\"\n\t}\n\n\tappendNodes(dest, key, value)\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/encoder_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encoder_test\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/suite\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\ntype Config struct {\n\tInteger      int                  `yaml:\"integer\"`\n\tSlice        []string             `yaml:\"slice\"`\n\tComplexSlice []*Endpoint          `yaml:\"complex_slice\"`\n\tMap          map[string]*Endpoint `yaml:\"map\"`\n\n\tSkip   string `yaml:\"-\"`\n\tOmit   int    `yaml:\",omitempty\"`\n\tInline *Mixin `yaml:\",inline\"`\n\n\tCustomMarshaller *WithCustomMarshaller `yaml:\",omitempty\"`\n\tBytes            []byte                `yaml:\"bytes,flow,omitempty\"`\n\n\tNilSlice Manifests `yaml:\"nilslice,omitempty\" talos:\"omitonlyifnil\"`\n\n\tunexported int\n}\n\ntype FakeConfig struct {\n\tMachine Machine `yaml:\"machine,omitempty\"`\n}\n\ntype Mixin struct {\n\tMixedIn string `yaml:\"mixed_in\"`\n}\n\ntype Endpoint struct {\n\tHost string\n\tPort int `yaml:\",omitempty\"`\n}\n\ntype Machine struct {\n\tState  int\n\tConfig *MachineConfig `yaml:\",omitempty\"`\n}\n\ntype MachineConfig struct {\n\tVersion      string\n\tCapabilities []string\n}\n\ntype Manifests []Manifest\n\ntype Manifest struct {\n\tName string `yaml:\"name\"`\n}\n\ntype WithCustomMarshaller struct {\n\tvalue string\n}\n\n// MarshalYAML implements custom marshaller.\nfunc (cm *WithCustomMarshaller) MarshalYAML() (any, error) {\n\tnode := &yaml.Node{}\n\n\tif err := node.Encode(map[string]string{\"value\": cm.value}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnode.HeadComment = \"completely custom\"\n\n\treturn node, nil\n}\n\n// This is manually defined documentation data for Config.\n// It is intended to be generated by `docgen` command.\nvar (\n\tconfigDoc        encoder.Doc\n\tendpointDoc      encoder.Doc\n\tmixinDoc         encoder.Doc\n\tmachineDoc       encoder.Doc\n\tmachineConfigDoc encoder.Doc\n)\n\nfunc init() {\n\tconfigDoc.Comments[encoder.LineComment] = \"test configuration\"\n\tconfigDoc.Fields = make([]encoder.Doc, 11)\n\tconfigDoc.Fields[1].Comments[encoder.LineComment] = \"<<<\"\n\tconfigDoc.Fields[2].Comments[encoder.HeadComment] = \"complex slice\"\n\tconfigDoc.Fields[3].Comments[encoder.FootComment] = \"some text example for map\"\n\n\tconfigDoc.Fields[2].AddExample(\"slice example\", []*Endpoint{{\n\t\tHost: \"127.0.0.1\",\n\t\tPort: 5554,\n\t}})\n\n\tconfigDoc.Fields[9].Comments[encoder.LineComment] = \"A nilslice field is really cool.\"\n\tconfigDoc.Fields[9].AddExample(\"nilslice example\", Manifests{{\n\t\tName: \"foo\",\n\t}})\n\n\tendpointDoc.Comments[encoder.LineComment] = \"endpoint settings\"\n\tendpointDoc.Fields = make([]encoder.Doc, 2)\n\tendpointDoc.Fields[0].Comments[encoder.LineComment] = \"endpoint host\"\n\tendpointDoc.Fields[1].Comments[encoder.LineComment] = \"custom port\"\n\n\tmixinDoc.Fields = make([]encoder.Doc, 1)\n\tmixinDoc.Fields[0].Comments[encoder.LineComment] = \"was inlined\"\n\n\tmachineDoc.AddExample(\"uncomment me\", &Machine{\n\t\tState: 100,\n\t})\n\tmachineDoc.AddExample(\"second example\", &Machine{\n\t\tState: -1,\n\t})\n\n\tmachineDoc.Fields = make([]encoder.Doc, 2)\n\tmachineDoc.Fields[1].AddExample(\"\", &MachineConfig{\n\t\tVersion: \"0.0.2\",\n\t})\n\n\tmachineConfigDoc.Fields = make([]encoder.Doc, 2)\n\tmachineConfigDoc.Fields[0].Comments[encoder.HeadComment] = \"this is some version\"\n\tmachineConfigDoc.Fields[1].AddExample(\"\",\n\t\t[]string{\n\t\t\t\"reboot\", \"upgrade\",\n\t\t},\n\t)\n}\n\nfunc (c Config) Doc() *encoder.Doc {\n\treturn &configDoc\n}\n\nfunc (c Endpoint) Doc() *encoder.Doc {\n\treturn &endpointDoc\n}\n\nfunc (c Mixin) Doc() *encoder.Doc {\n\treturn &mixinDoc\n}\n\nfunc (c Machine) Doc() *encoder.Doc {\n\treturn &machineDoc\n}\n\nfunc (c MachineConfig) Doc() *encoder.Doc {\n\treturn &machineConfigDoc\n}\n\n// tests\n\ntype EncoderSuite struct {\n\tsuite.Suite\n}\n\nfunc (suite *EncoderSuite) TestRun() {\n\te := &Endpoint{\n\t\tPort: 8080,\n\t}\n\ttests := []struct {\n\t\tname         string\n\t\tvalue        any\n\t\texpectedYAML string\n\t\tincompatible bool\n\t\toptions      []encoder.Option\n\t}{\n\t\t{\n\t\t\tname:  \"default struct with all enabled\",\n\t\t\tvalue: &Config{},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\n#   # slice example\n#   - host: 127.0.0.1 # endpoint host\n#     port: 5554 # custom port\n\nmap: {}\n# some text example for map\n# # A nilslice field is really cool.\n\n# # nilslice example\n# nilslice:\n#     - name: foo\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsAll),\n\t\t\t},\n\t\t\tincompatible: true,\n\t\t},\n\t\t{\n\t\t\tname:  \"default struct only with examples\",\n\t\t\tvalue: &Config{},\n\t\t\texpectedYAML: `integer: 0\nslice: []\ncomplex_slice: []\n#   # slice example\n#   - host: 127.0.0.1\n#     port: 5554\n\nmap: {}\n\n# # nilslice example\n# nilslice:\n#     - name: foo\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsExamples),\n\t\t\t},\n\t\t\tincompatible: true,\n\t\t},\n\t\t{\n\t\t\tname:  \"default struct\",\n\t\t\tvalue: &Config{},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap: {}\n# some text example for map\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"struct with custom marshaller\",\n\t\t\tvalue: &Config{\n\t\t\t\tCustomMarshaller: &WithCustomMarshaller{\n\t\t\t\t\tvalue: \"abcd\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap: {}\n# some text example for map\n\ncustommarshaller:\n    # completely custom\n    value: abcd\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bytes flow\",\n\t\t\tvalue: &Config{\n\t\t\t\tBytes: []byte(\"...\"),\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap: {}\n# some text example for map\n\nbytes: [46, 46, 46]\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"map check\",\n\t\t\tvalue: &Config{\n\t\t\t\tMap: map[string]*Endpoint{\n\t\t\t\t\t\"endpoint\": new(Endpoint),\n\t\t\t\t},\n\t\t\t\tunexported: -1,\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap:\n    endpoint:\n        host: \"\" # endpoint host\n# some text example for map\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"nil map element\",\n\t\t\tvalue: &Config{\n\t\t\t\tMap: map[string]*Endpoint{\n\t\t\t\t\t\"endpoint\": nil,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap:\n    endpoint: null\n# some text example for map\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"nil map element\",\n\t\t\tvalue: &Config{\n\t\t\t\tMap: map[string]*Endpoint{\n\t\t\t\t\t\"endpoint\": new(Endpoint),\n\t\t\t\t},\n\t\t\t\tComplexSlice: []*Endpoint{e},\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice:\n    - host: \"\" # endpoint host\n      port: 8080 # custom port\nmap:\n    endpoint:\n        host: \"\" # endpoint host\n# some text example for map\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"inline\",\n\t\t\tvalue: &Config{\n\t\t\t\tInline: &Mixin{\n\t\t\t\t\tMixedIn: \"a\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\nmap: {}\n# some text example for map\n\nmixed_in: a # was inlined\n`,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"comment example if zero\",\n\t\t\tvalue: &FakeConfig{},\n\t\t\texpectedYAML: `# # uncomment me\n# machine:\n#     state: 100\n#     config:\n#         # this is some version\n#         version: 0.0.2\n#         capabilities:\n#             - reboot\n#             - upgrade\n# # second example\n# machine:\n#     state: -1\n#     config:\n#         # this is some version\n#         version: 0.0.2\n#         capabilities:\n#             - reboot\n#             - upgrade\n`,\n\t\t\tincompatible: true,\n\t\t},\n\t\t{\n\t\t\tname: \"comment example if partially set\",\n\t\t\tvalue: &FakeConfig{\n\t\t\t\tMachine{\n\t\t\t\t\tState: 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `machine:\n    state: 1000\n    ` + `\n    # config:\n    #     # this is some version\n    #     version: 0.0.2\n    #     capabilities:\n    #         - reboot\n    #         - upgrade\n`,\n\t\t\tincompatible: true,\n\t\t},\n\t\t{\n\t\t\tname: \"populate map element's examples\",\n\t\t\tvalue: map[string][]*MachineConfig{\n\t\t\t\t\"first\": {\n\t\t\t\t\t{},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `first:\n    - # this is some version\n      version: \"\"\n      capabilities: []\n      #   - reboot\n      #   - upgrade\n`,\n\t\t\tincompatible: true,\n\t\t},\n\t\t{\n\t\t\tname: \"without comments\",\n\t\t\tvalue: &FakeConfig{\n\t\t\t\tMachine{\n\t\t\t\t\tState: 1000,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedYAML: `machine:\n    state: 1000\n`,\n\t\t\tincompatible: true,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDisabled),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"only with docs\",\n\t\t\tvalue: &FakeConfig{},\n\t\t\texpectedYAML: `{}\n`,\n\t\t\tincompatible: true,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsDocs),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"only with examples\",\n\t\t\tvalue: &FakeConfig{},\n\t\t\texpectedYAML: `# # uncomment me\n# machine:\n#     state: 100\n#     config:\n#         version: 0.0.2\n#         capabilities:\n#             - reboot\n#             - upgrade\n# # second example\n# machine:\n#     state: -1\n#     config:\n#         version: 0.0.2\n#         capabilities:\n#             - reboot\n#             - upgrade\n`,\n\t\t\tincompatible: true,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsExamples),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with onlyifnotnil tag\",\n\t\t\tvalue: &Config{\n\t\t\t\tNilSlice: Manifests{},\n\t\t\t},\n\t\t\texpectedYAML: `integer: 0\n# <<<\nslice: []\n# complex slice\ncomplex_slice: []\n#   # slice example\n#   - host: 127.0.0.1 # endpoint host\n#     port: 5554 # custom port\n\nmap: {}\n# some text example for map\n\n# A nilslice field is really cool.\nnilslice: []\n#   # nilslice example\n#   - name: foo\n`,\n\t\t\tincompatible: true,\n\t\t\toptions: []encoder.Option{\n\t\t\t\tencoder.WithComments(encoder.CommentsAll),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tencoder := encoder.NewEncoder(test.value, test.options...)\n\t\tdata, err := encoder.Encode()\n\t\tsuite.Assert().NoError(err)\n\n\t\t// compare with expected string output\n\t\tsuite.Assert().EqualValues(test.expectedYAML, string(data), test.name)\n\n\t\t// decode into raw map to strip all comments\n\t\tactualMap, err := decodeToMap(data)\n\t\tsuite.Assert().NoError(err)\n\n\t\t// skip if marshaller output is not the same for our encoder and vanilla one\n\t\t// note: it is only incompatible if config contains nested structs stored as value\n\t\t// and if these nested structs are documented and you try to load generated yaml into map[interface{}]interface{}\n\t\tif !test.incompatible {\n\t\t\t// compare with regular yaml.Marshal call\n\t\t\texpected, err := yaml.Marshal(test.value)\n\t\t\tsuite.Assert().NoError(err)\n\n\t\t\texpectedMap, err := decodeToMap(expected)\n\t\t\tsuite.Assert().NoError(err)\n\t\t\tsuite.Assert().EqualValues(expectedMap, actualMap)\n\t\t}\n\t}\n}\n\nfunc (suite *EncoderSuite) TestConcurrent() {\n\tvalue := &Machine{}\n\n\tvar wg sync.WaitGroup\n\n\tfor range 10 {\n\t\twg.Go(func() {\n\t\t\tencoder := encoder.NewEncoder(value)\n\t\t\t_, err := encoder.Encode()\n\t\t\tsuite.Assert().NoError(err)\n\t\t})\n\t}\n\n\twg.Wait()\n}\n\nfunc decodeToMap(data []byte) (map[any]any, error) {\n\traw := map[any]any{}\n\terr := yaml.Unmarshal(data, &raw)\n\n\treturn raw, err\n}\n\nfunc TestEncoderSuite(t *testing.T) {\n\tsuite.Run(t, &EncoderSuite{})\n}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/markdown.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encoder\n\nimport (\n\t\"bytes\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/template\"\n\n\tyaml \"go.yaml.in/yaml/v4\"\n)\n\n//go:embed \"markdown.tmpl\"\nvar markdownTemplate string\n\n// FileDoc represents a single go file documentation.\ntype FileDoc struct {\n\t// Name will be used in md file name pattern.\n\tName string\n\t// Description file description, supports markdown.\n\tDescription string\n\t// Structs structs defined in the file.\n\tStructs []*Doc\n\t// Types is map of all non-trivial types defined in the file.\n\tTypes map[string]*Doc\n}\n\n// Encode encodes file documentation as MD file.\nfunc (fd *FileDoc) Encode(root *Doc, frontmatter func(title, description string) string) ([]byte, error) {\n\tt := template.Must(template.New(\"markdown.tmpl\").\n\t\tFuncs(template.FuncMap{\n\t\t\t\"yaml\":        encodeYaml,\n\t\t\t\"fmtDesc\":     formatDescription,\n\t\t\t\"dict\":        tmplDict,\n\t\t\t\"repeat\":      strings.Repeat,\n\t\t\t\"trimPrefix\":  strings.TrimPrefix,\n\t\t\t\"add\":         func(a, b int) int { return a + b },\n\t\t\t\"frontmatter\": frontmatter,\n\t\t\t\"min\":         minInt,\n\t\t}).\n\t\tParse(markdownTemplate))\n\n\tvar buf bytes.Buffer\n\n\tif err := t.Execute(&buf, struct {\n\t\tRoot  *Doc\n\t\tTypes map[string]*Doc\n\t}{\n\t\tRoot:  root,\n\t\tTypes: fd.Types,\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buf.Bytes(), nil\n}\n\n// Write dumps documentation string to folder.\n//\n//nolint:gocyclo\nfunc (fd *FileDoc) Write(path string, frontmatter func(title, description string) string) error {\n\tif stat, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {\n\t\tif !stat.IsDir() {\n\t\t\treturn errors.New(\"destination path should be a directory\")\n\t\t}\n\t} else {\n\t\tif err := os.MkdirAll(path, 0o777); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// generate _index.md\n\tif err := os.WriteFile(filepath.Join(path, \"_index.md\"), []byte(frontmatter(fd.Name, fd.Description)), 0o666); err != nil {\n\t\treturn err\n\t}\n\n\t// find map of all types\n\tfd.Types = map[string]*Doc{}\n\n\tfor _, t := range fd.Structs {\n\t\tif t.Type == \"\" || strings.ToLower(t.Type) == t.Type {\n\t\t\tcontinue\n\t\t}\n\n\t\tfd.Types[t.Type] = t\n\t}\n\n\t// find root nodes\n\tvar roots []*Doc\n\n\tfor _, t := range fd.Structs {\n\t\tif len(t.AppearsIn) == 0 {\n\t\t\troots = append(roots, t)\n\t\t}\n\t}\n\n\tfor _, root := range roots {\n\t\tcontents, err := fd.Encode(root, frontmatter)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := os.WriteFile(filepath.Join(path, fmt.Sprintf(\"%s.%s\", strings.ToLower(root.Type), \"md\")), contents, 0o666); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n//nolint:gocyclo\nfunc encodeYaml(in any, path string) string {\n\tif path != \"\" {\n\t\tparts := strings.Split(path, \".\")\n\n\t\tparts = parts[1:] // strip first segment, it's root element\n\n\t\t// if the last element is \"\"/\"-\", it means we're at the root of the slice, so we don't need to wrap it once again\n\t\tif len(parts) > 0 && (parts[len(parts)-1] == \"\" || parts[len(parts)-1] == \"-\") {\n\t\t\tparts = parts[:len(parts)-1]\n\t\t}\n\n\t\tslices.Reverse(parts)\n\n\t\tfor _, part := range parts {\n\t\t\tswitch part {\n\t\t\tcase \"\":\n\t\t\t\tin = []any{in}\n\t\t\tcase \"-\":\n\t\t\t\tin = map[string]any{\n\t\t\t\t\t\"example.com\": in,\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tin = map[string]any{\n\t\t\t\t\tpart: in,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tnode, err := toYamlNode(in, newOptions(WithComments(CommentsAll)))\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"yaml encoding failed %s\", err)\n\t}\n\n\tdata, err := yaml.Marshal(node)\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"yaml encoding failed %s\", err)\n\t}\n\n\tlines := strings.Split(string(data), \"\\n\")\n\tfor i, line := range lines {\n\t\tlines[i] = strings.TrimRight(line, \" \")\n\t}\n\n\treturn fmt.Sprintf(\"{{< highlight yaml >}}\\n%s{{< /highlight >}}\", strings.Join(lines, \"\\n\"))\n}\n\nfunc formatDescription(description string) string {\n\treturn strings.ReplaceAll(description, \"\\n\", \"<br>\")\n}\n\nfunc tmplDict(vals ...any) (map[string]any, error) {\n\tif len(vals)%2 != 0 {\n\t\treturn nil, fmt.Errorf(\"invalid number of arguments: %d\", len(vals))\n\t}\n\n\tres := map[string]any{}\n\n\tfor i := 0; i < len(vals); i += 2 {\n\t\tkey, ok := vals[i].(string)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid key type: %T\", vals[i])\n\t\t}\n\n\t\tres[key] = vals[i+1]\n\t}\n\n\treturn res, nil\n}\n\nfunc minInt(a, b int) int {\n\treturn min(a, b)\n}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/markdown.tmpl",
    "content": "{{ frontmatter .Root.Type .Root.Description }}\n\n{{ define \"field\" -}}\n{{ if .Field.Name -}}\n|`{{ .Field.Name }}` |\n    {{- $type := index $.Types .Field.Type -}}\n        {{- if $type -}}\n            <a href=\"#{{ .Path }}.{{ .Field.Name }}\">{{ .Field.Type }}</a>\n        {{- else -}}\n            {{- $type := index .Types (trimPrefix .Field.Type \"[]\") -}}\n            {{- if $type -}}\n                <a href=\"#{{ .Path }}.{{ .Field.Name }}.\">{{ .Field.Type }}</a>\n            {{- else -}}\n                {{- $type := index .Types (trimPrefix .Field.Type \"map[string]\") -}}\n                {{- if $type -}}\n                    <a href=\"#{{ .Path }}.{{ .Field.Name }}.-\">{{ .Field.Type }}</a>\n                {{- else -}}\n                    {{ .Field.Type }}\n                {{- end -}}\n            {{- end -}}\n        {{- end }} |\n{{- fmtDesc .Field.Description }} {{ with .Field.Examples }}<details><summary>Show example(s)</summary>{{ range . }}{{ if .Name }}{{ .Name }}:{{ end }}{{ yaml .GetValue (printf \".%s\" $.Field.Name) }}{{ end }}</details>{{ end }} |\n{{- range $value := .Field.Values }}`{{ $value }}`<br />{{ end }} |\n{{ else if .Field.Inline -}}\n    {{- $struct := index .Types .Field.Type -}}\n    {{- if $struct -}}\n        {{- range $inlineField := $struct.Fields -}}\n            {{ template \"field\" dict \"Field\" $inlineField \"Types\" $.Types \"Path\" $.Path -}}\n        {{- end -}}\n    {{- end -}}\n{{ end -}}\n{{ end -}}\n\n{{ block \"struct\" dict \"Struct\" .Root \"Level\" 1 \"Name\" .Root.Type \"Path\" .Root.Type  \"Types\" .Types }}\n{{ if gt .Level 1 }}{{ repeat \"#\" (min .Level 6) }} {{ .Name }} {#{{ .Path }}}{{ end }}\n\n{{ if and .Struct.Description (gt .Level 1) -}}\n{{ .Struct.Description }}\n{{ end }}\n\n{{ range $example := .Struct.Examples }}\n{{ yaml $example.GetValue $.Path }}\n{{ end }}\n\n{{ if .Struct.Fields -}}\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n{{ range $field := $.Struct.Fields -}}\n{{ template \"field\" dict \"Field\" $field \"Types\" $.Types \"Path\" $.Path -}}\n{{ end }}\n{{ end }}\n\n{{ range $field := .Struct.Fields }}\n    {{- $struct := index $.Types $field.Type -}}\n    {{- if $field.Inline -}}\n     {{- if $struct -}}\n      {{- range $inlineField := $struct.Fields -}}\n        {{- $struct := index $.Types $inlineField.Type -}}\n        {{- if $struct -}}\n            {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" $inlineField.Name \"Types\" $.Types \"Path\" (printf \"%s.%s\" $.Path $inlineField.Name) }}\n            {{- else -}}\n                {{- $struct := index $.Types (trimPrefix $inlineField.Type \"[]\") -}}\n                {{- if $struct -}}\n                    {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" (printf \"%s[]\" $inlineField.Name) \"Types\" $.Types \"Path\" (printf \"%s.%s.\" $.Path $inlineField.Name) }}\n                {{- else -}}\n                    {{- $struct := index $.Types (trimPrefix $inlineField.Type \"map[string]\") -}}\n                    {{- if $struct -}}\n                        {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" (printf \"%s.*\" $inlineField.Name) \"Types\" $.Types \"Path\" (printf \"%s.%s.-\" $.Path $inlineField.Name) }}\n                    {{- end -}}\n                {{- end -}}\n        {{- end -}}\n       {{- end -}}\n      {{- end -}}\n    {{- else -}}\n      {{- if $struct -}}\n        {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" $field.Name \"Types\" $.Types \"Path\" (printf \"%s.%s\" $.Path $field.Name) }}\n        {{- else -}}\n            {{- $struct := index $.Types (trimPrefix $field.Type \"[]\") -}}\n            {{- if $struct -}}\n                {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" (printf \"%s[]\" $field.Name) \"Types\" $.Types \"Path\" (printf \"%s.%s.\" $.Path $field.Name) }}\n            {{- else -}}\n                {{- $struct := index $.Types (trimPrefix $field.Type \"map[string]\") -}}\n                {{- if $struct -}}\n                    {{ template \"struct\" dict \"Struct\" $struct \"Level\" (add $.Level 1) \"Name\" (printf \"%s.*\" $field.Name) \"Types\" $.Types \"Path\" (printf \"%s.%s.-\" $.Path $field.Name) }}\n                {{- end -}}\n            {{- end -}}\n      {{- end -}}\n    {{- end -}}\n{{ end }}\n\n{{ end }}\n"
  },
  {
    "path": "pkg/machinery/config/encoder/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage encoder\n\n// CommentsFlags comments encoding flags type.\ntype CommentsFlags int\n\nfunc (f CommentsFlags) enabled(flag CommentsFlags) bool {\n\treturn (f & flag) == flag\n}\n\nconst (\n\t// CommentsDisabled renders no comments.\n\tCommentsDisabled CommentsFlags = 0\n\t// CommentsExamples enables commented yaml examples rendering.\n\tCommentsExamples CommentsFlags = 1 << iota\n\t// CommentsDocs enables rendering each config field short docstring.\n\tCommentsDocs\n\t// CommentsAll renders all comments.\n\tCommentsAll = CommentsExamples | CommentsDocs\n)\n\n// Options defines encoder config.\ntype Options struct {\n\tComments  CommentsFlags\n\tOmitEmpty bool\n}\n\nfunc newOptions(opts ...Option) *Options {\n\tres := &Options{\n\t\tComments:  CommentsAll,\n\t\tOmitEmpty: true,\n\t}\n\n\tfor _, o := range opts {\n\t\to(res)\n\t}\n\n\treturn res\n}\n\n// Option gives ability to alter config encoder output settings.\ntype Option func(*Options)\n\n// WithComments enables comments and examples in the encoder.\nfunc WithComments(flags CommentsFlags) Option {\n\treturn func(o *Options) {\n\t\to.Comments = flags\n\t}\n}\n\n// WithOmitEmpty toggles omitempty handling.\nfunc WithOmitEmpty(value bool) Option {\n\treturn func(o *Options) {\n\t\to.OmitEmpty = value\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/controlplane.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc (in *Input) controlPlane() ([]config.Document, error) {\n\tdocs, err := in.init()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdocs[0].(*v1alpha1.Config).MachineConfig.MachineType = machine.TypeControlPlane.String()\n\n\treturn docs, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/example_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate_test\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n//nolint:wsl,testableexamples\nfunc Example() {\n\t// This is an example of generating a set of machine configuration files for multiple\n\t// nodes of the cluster from a single cluster-specific cluster.\n\n\t// Input values for the config generation:\n\n\t// * cluster name and Kubernetes control plane endpoint\n\tclusterName := \"test-cluster\"\n\tcontrolPlaneEndpoint := \"https://kubernetes.example.com:6443\"\n\n\t// * Kubernetes version to install, using the latest here\n\tkubernetesVersion := constants.DefaultKubernetesVersion\n\n\t// * version contract defines the version of the Talos cluster configuration is generated for\n\t//   generate package can generate machine configuration compatible with current and previous versions of Talos\n\ttargetVersion := \"v1.0\"\n\n\t// parse the version contract\n\tvar (\n\t\tversionContract = config.TalosVersionCurrent //nolint:wastedassign,ineffassign // version of the Talos machinery package\n\t\terr             error\n\t)\n\n\tversionContract, err = config.ParseContractFromVersion(targetVersion)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to parse version contract: %s\", err)\n\t}\n\n\t// generate the cluster-wide secrets once and use it for every node machine configuration\n\t// secrets can be stashed for future use by marshaling the structure to YAML or JSON\n\tsecretsBundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), versionContract)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to generate secrets bundle: %s\", err)\n\t}\n\n\tinput, err := generate.NewInput(clusterName, controlPlaneEndpoint, kubernetesVersion,\n\t\tgenerate.WithVersionContract(versionContract),\n\t\tgenerate.WithSecretsBundle(secretsBundle),\n\t\tgenerate.WithEndpointList(\n\t\t\t[]string{\"172.0.0.1\", \"172.0.0.2\", \"172.20.0.3\"}, // list of control plane node IP addresses\n\t\t),\n\t\t// there are many more generate options available which allow to tweak generated config programmatically\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to generate input: %s\", err)\n\t}\n\n\t// generate the machine config for each node of the cluster using the secrets\n\tfor _, node := range []string{\"machine1\", \"machine2\"} {\n\t\tvar cfg config.Provider\n\n\t\t// generate the machine config for the node, using the right machine type:\n\t\t// * machine.TypeConrolPlane for control plane nodes\n\t\t// * machine.TypeWorker for worker nodes\n\t\tcfg, err = input.Config(machine.TypeControlPlane)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"failed to generate config for node %q: %s\", node, err)\n\t\t}\n\n\t\t// config can be tweaked at this point to add machine-specific configuration, e.g.:\n\t\tcfg.RawV1Alpha1().MachineConfig.MachineInstall.InstallDisk = \"/dev/sdb\"\n\n\t\t// marshal the config to YAML\n\t\tvar marshaledCfg []byte\n\n\t\tmarshaledCfg, err = cfg.Bytes()\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"failed to generate config for node %q: %s\", node, err)\n\t\t}\n\n\t\t// write the config to a file\n\t\tif err = os.WriteFile(clusterName+\"-\"+node+\".yaml\", marshaledCfg, 0o600); err != nil {\n\t\t\tlog.Fatalf(\"failed to write config for node %q: %s\", node, err)\n\t\t}\n\t}\n\n\t// generate the client Talos configuration (for API access, e.g. talosctl)\n\tclientCfg, err := input.Talosconfig()\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to generate client config: %s\", err)\n\t}\n\n\tif err = clientCfg.Save(clusterName + \"-talosconfig\"); err != nil {\n\t\tlog.Fatalf(\"failed to save client config: %s\", err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/generate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package generate provides Talos machine configuration generation and client config generation.\n//\n// Please see the example for more information on using this package.\npackage generate\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"time\"\n\n\tcoreconfig \"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Input holds info about certs, ips, and node type.\n//\n//nolint:maligned\ntype Input struct {\n\tOptions Options\n\n\t// ControlplaneEndpoint is the canonical address of the kubernetes control\n\t// plane.  It can be a DNS name, the IP address of a load balancer, or\n\t// (default) the IP address of the first controlplane node.  It is NOT\n\t// multi-valued.  It may optionally specify the port.\n\tControlPlaneEndpoint string\n\n\tAdditionalSubjectAltNames []string\n\tAdditionalMachineCertSANs []string\n\n\tClusterName       string\n\tPodNet            []string\n\tServiceNet        []string\n\tKubernetesVersion string\n}\n\n// GetAPIServerSANs returns the formatted list of Subject Alt Name addresses for the API Server.\nfunc (in *Input) GetAPIServerSANs() []string {\n\tvar list []string\n\n\tif in.Options.VersionContract.PopulateClusterSANsFromEndpoint() {\n\t\tendpointURL, err := url.Parse(in.ControlPlaneEndpoint)\n\t\tif err == nil {\n\t\t\tlist = append(list, endpointURL.Hostname())\n\t\t}\n\t}\n\n\tlist = append(list, in.AdditionalSubjectAltNames...)\n\n\treturn list\n}\n\n// NewInput prepares a new Input struct to perform machine config generation.\nfunc NewInput(clustername, endpoint, kubernetesVersion string, opts ...Option) (*Input, error) {\n\tinput := &Input{}\n\tinput.Options = DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&input.Options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tvar podNet, serviceNet string\n\n\tif addr, addrErr := netip.ParseAddr(endpoint); addrErr == nil && addr.Is6() {\n\t\tpodNet = constants.DefaultIPv6PodNet\n\t\tserviceNet = constants.DefaultIPv6ServiceNet\n\t} else {\n\t\tpodNet = constants.DefaultIPv4PodNet\n\t\tserviceNet = constants.DefaultIPv4ServiceNet\n\t}\n\n\tif input.Options.SecretsBundle == nil {\n\t\tvar err error\n\n\t\tinput.Options.SecretsBundle, err = secrets.NewBundle(secrets.NewFixedClock(time.Now()), input.Options.VersionContract)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tadditionalSubjectAltNames := slices.Clone(input.Options.AdditionalSubjectAltNames)\n\n\tif input.Options.DiscoveryEnabled == nil {\n\t\tinput.Options.DiscoveryEnabled = new(true)\n\t}\n\n\tinput.ClusterName = clustername\n\tinput.KubernetesVersion = kubernetesVersion\n\tinput.AdditionalMachineCertSANs = additionalSubjectAltNames\n\tinput.AdditionalSubjectAltNames = additionalSubjectAltNames\n\tinput.PodNet = []string{podNet}\n\tinput.ServiceNet = []string{serviceNet}\n\tinput.ControlPlaneEndpoint = endpoint\n\tinput.KubernetesVersion = kubernetesVersion\n\n\treturn input, nil\n}\n\n// Config returns the talos config for a given node type.\nfunc (in *Input) Config(t machine.Type) (coreconfig.Provider, error) {\n\tvar (\n\t\tdocuments []config.Document\n\t\terr       error\n\t)\n\n\tswitch t {\n\tcase machine.TypeInit:\n\t\tdocuments, err = in.init()\n\tcase machine.TypeControlPlane:\n\t\tdocuments, err = in.controlPlane()\n\tcase machine.TypeWorker:\n\t\tdocuments, err = in.worker()\n\tcase machine.TypeUnknown:\n\t\tfallthrough\n\tdefault:\n\t\treturn nil, errors.New(\"failed to determine config type to generate\")\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn container.New(documents...)\n}\n\n// emptyIf returns empty string if the 2nd argument is empty string, otherwise returns the first argument.\nfunc emptyIf(str, check string) string {\n\tif check == \"\" {\n\t\treturn \"\"\n\t}\n\n\treturn str\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/generate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate_test\n\nimport (\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/stretchr/testify/suite\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tmc \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\ntype GenerateSuite struct {\n\tsuite.Suite\n\n\tinput      *generate.Input\n\tgenOptions []generate.Option\n\n\tversionContract *config.VersionContract\n}\n\nfunc TestGenerateSuite(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tlabel      string\n\t\tgenOptions []generate.Option\n\t}{\n\t\t{\n\t\t\tlabel: \"current\",\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.7\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_7)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.6\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_6)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.5\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_5)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.4\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_4)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.3\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_3)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.2\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_2)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.1\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_1)},\n\t\t},\n\t\t{\n\t\t\tlabel:      \"1.0\",\n\t\t\tgenOptions: []generate.Option{generate.WithVersionContract(config.TalosVersion1_0)},\n\t\t},\n\t} {\n\t\tt.Run(tt.label, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsuite.Run(t, &GenerateSuite{\n\t\t\t\tgenOptions: tt.genOptions,\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc (suite *GenerateSuite) SetupSuite() {\n\tvar err error\n\n\tsuite.input, err = generate.NewInput(\"test\", \"https://10.0.1.5\", constants.DefaultKubernetesVersion, suite.genOptions...)\n\tsuite.Require().NoError(err)\n\n\tvar opts generate.Options\n\n\tfor _, opt := range suite.genOptions {\n\t\tsuite.Require().NoError(opt(&opts))\n\t}\n\n\tsuite.versionContract = suite.input.Options.VersionContract\n}\n\nfunc (suite *GenerateSuite) TestGenerateInitSuccess() {\n\tcfg, err := suite.input.Config(machine.TypeInit)\n\tsuite.Require().NoError(err)\n\n\tsuite.NotEmpty(cfg.Machine().Security().IssuingCA())\n}\n\nfunc (suite *GenerateSuite) TestGenerateControlPlaneSuccess() {\n\tcfg, err := suite.input.Config(machine.TypeControlPlane)\n\tsuite.Require().NoError(err)\n\n\t_, err = cfg.Validate(runtimeMode{false})\n\tsuite.Require().NoError(err)\n\n\tsuite.NotEmpty(cfg.Machine().Security().IssuingCA())\n}\n\nfunc (suite *GenerateSuite) TestGenerateWorkerSuccess() {\n\tcfg, err := suite.input.Config(machine.TypeWorker)\n\tsuite.Require().NoError(err)\n\n\tsuite.NotEmpty(cfg.Machine().Security().IssuingCA())\n}\n\nfunc (suite *GenerateSuite) TestGenerateTalosconfigSuccess() {\n\tcfg, err := suite.input.Talosconfig()\n\tsuite.Require().NoError(err)\n\n\tcreds, err := client.CertificateFromConfigContext(cfg.Contexts[cfg.Context])\n\tsuite.Require().NoError(err)\n\tsuite.Require().Len(creds.Certificate, 1)\n\n\tcert, err := x509.ParseCertificate(creds.Certificate[0])\n\tsuite.Require().NoError(err)\n\n\tsuite.Equal([]string{string(role.Admin)}, cert.Subject.Organization)\n}\n\nfunc TestGenerateRegistryMirrorsOrder(t *testing.T) {\n\tt.Parallel()\n\n\tinput, err := generate.NewInput(\"test\", \"https://10.0.1.5\", constants.DefaultKubernetesVersion,\n\t\tgenerate.WithRegistryMirror(\"b.com\", \"http://127.0.0.1:5004\"),\n\t\tgenerate.WithRegistryMirror(\"a.com\", \"http://127.0.0.1:5005\"),\n\t)\n\n\trequire.NoError(t, err)\n\n\tcfg, err := input.Config(machine.TypeControlPlane)\n\n\trequire.NoError(t, err)\n\n\tnamed, ok := cfg.Documents()[1].(mc.NamedDocument)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"a.com\", named.Name())\n\n\tnamed, ok = cfg.Documents()[2].(mc.NamedDocument)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"b.com\", named.Name())\n}\n\ntype runtimeMode struct {\n\trequiresInstall bool\n}\n\nfunc (m runtimeMode) String() string {\n\treturn fmt.Sprintf(\"runtimeMode(%v)\", m.requiresInstall)\n}\n\nfunc (m runtimeMode) RequiresInstall() bool {\n\treturn m.requiresInstall\n}\n\nfunc (runtimeMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/init.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n//nolint:gocyclo,cyclop\nfunc (in *Input) init() ([]config.Document, error) {\n\tv1alpha1Config := &v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tConfigDebug:   new(in.Options.Debug),\n\t\tConfigPersist: new(true),\n\t}\n\n\tmachine := &v1alpha1.MachineConfig{\n\t\tMachineType: machine.TypeInit.String(),\n\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\tKubeletImage: emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubeletImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t},\n\t\tMachineCA:       in.Options.SecretsBundle.Certs.OS,\n\t\tMachineCertSANs: in.AdditionalMachineCertSANs,\n\t\tMachineToken:    in.Options.SecretsBundle.TrustdInfo.Token,\n\t\tMachineInstall: &v1alpha1.InstallConfig{\n\t\t\tInstallDisk:            in.Options.InstallDisk,\n\t\t\tInstallImage:           in.Options.InstallImage,\n\t\t\tInstallWipe:            new(false),\n\t\t\tInstallExtraKernelArgs: in.Options.InstallExtraKernelArgs,\n\t\t},\n\t\tMachineDisks:    in.Options.MachineDisks,\n\t\tMachineSysctls:  in.Options.Sysctls,\n\t\tMachineFeatures: &v1alpha1.FeaturesConfig{},\n\t}\n\n\tif in.Options.VersionContract.GrubUseUKICmdlineDefault() {\n\t\tmachine.MachineInstall.InstallGrubUseUKICmdline = new(true)\n\t}\n\n\tif !in.Options.VersionContract.HideRBACAndKeyUsage() {\n\t\tmachine.MachineFeatures.RBAC = new(true)\n\n\t\tif in.Options.VersionContract.ApidExtKeyUsageCheckEnabled() {\n\t\t\tmachine.MachineFeatures.ApidCheckExtKeyUsage = new(true)\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.DiskQuotaSupportEnabled() {\n\t\tmachine.MachineFeatures.DiskQuotaSupport = new(true)\n\t}\n\n\tif kubePrismPort, optionSet := in.Options.KubePrismPort.Get(); optionSet { // default to enabled, but if set explicitly, allow it to be disabled\n\t\tif kubePrismPort > 0 {\n\t\t\tmachine.MachineFeatures.KubePrismSupport = &v1alpha1.KubePrism{\n\t\t\t\tServerEnabled: new(true),\n\t\t\t\tServerPort:    kubePrismPort,\n\t\t\t}\n\t\t}\n\t} else if in.Options.VersionContract.KubePrismEnabled() {\n\t\tmachine.MachineFeatures.KubePrismSupport = &v1alpha1.KubePrism{\n\t\t\tServerEnabled: new(true),\n\t\t\tServerPort:    constants.DefaultKubePrismPort,\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() {\n\t\tmachine.MachineKubelet.KubeletDefaultRuntimeSeccompProfileEnabled = new(true)\n\t}\n\n\tif in.Options.VersionContract.KubeletManifestsDirectoryDisabled() {\n\t\tmachine.MachineKubelet.KubeletDisableManifestsDirectory = new(true)\n\t}\n\n\tif in.Options.VersionContract.HostDNSEnabled() {\n\t\tmachine.MachineFeatures.HostDNSSupport = &v1alpha1.HostDNSConfig{\n\t\t\tHostDNSEnabled:              new(true),\n\t\t\tHostDNSForwardKubeDNSToHost: ptrOrNil(in.Options.HostDNSForwardKubeDNSToHost.ValueOrZero() || in.Options.VersionContract.HostDNSForwardKubeDNSToHost()),\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.AddExcludeFromExternalLoadBalancer() {\n\t\tif machine.MachineNodeLabels == nil {\n\t\t\tmachine.MachineNodeLabels = map[string]string{}\n\t\t}\n\n\t\tmachine.MachineNodeLabels[constants.LabelExcludeFromExternalLB] = \"\"\n\t}\n\n\tcertSANs := in.GetAPIServerSANs()\n\n\tcontrolPlaneURL, err := url.Parse(in.ControlPlaneEndpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar admissionControlConfig []*v1alpha1.AdmissionPluginConfig\n\n\tif in.Options.VersionContract.PodSecurityAdmissionEnabled() {\n\t\tadmissionControlConfig = append(admissionControlConfig,\n\t\t\t&v1alpha1.AdmissionPluginConfig{\n\t\t\t\tPluginName: \"PodSecurity\",\n\t\t\t\tPluginConfiguration: v1alpha1.Unstructured{\n\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\"apiVersion\": \"pod-security.admission.config.k8s.io/v1alpha1\",\n\t\t\t\t\t\t\"kind\":       \"PodSecurityConfiguration\",\n\t\t\t\t\t\t\"defaults\": map[string]any{\n\t\t\t\t\t\t\t\"enforce\":         \"baseline\",\n\t\t\t\t\t\t\t\"enforce-version\": \"latest\",\n\t\t\t\t\t\t\t\"audit\":           \"restricted\",\n\t\t\t\t\t\t\t\"audit-version\":   \"latest\",\n\t\t\t\t\t\t\t\"warn\":            \"restricted\",\n\t\t\t\t\t\t\t\"warn-version\":    \"latest\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"exemptions\": map[string]any{\n\t\t\t\t\t\t\t\"usernames\":      []any{},\n\t\t\t\t\t\t\t\"runtimeClasses\": []any{},\n\t\t\t\t\t\t\t\"namespaces\":     []any{\"kube-system\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t}\n\n\tvar auditPolicyConfig v1alpha1.Unstructured\n\n\tif in.Options.VersionContract.APIServerAuditPolicySupported() {\n\t\tauditPolicyConfig = v1alpha1.APIServerDefaultAuditPolicy\n\t}\n\n\tcluster := &v1alpha1.ClusterConfig{\n\t\tClusterID:     in.Options.SecretsBundle.Cluster.ID,\n\t\tClusterName:   in.ClusterName,\n\t\tClusterSecret: in.Options.SecretsBundle.Cluster.Secret,\n\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\tEndpoint:           &v1alpha1.Endpoint{URL: controlPlaneURL},\n\t\t\tLocalAPIServerPort: in.Options.LocalAPIServerPort,\n\t\t},\n\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\tCertSANs:               certSANs,\n\t\t\tContainerImage:         emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubernetesAPIServerImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t\tAdmissionControlConfig: admissionControlConfig,\n\t\t\tAuditPolicyConfig:      auditPolicyConfig,\n\t\t},\n\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{\n\t\t\tContainerImage: emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubernetesControllerManagerImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t},\n\t\tProxyConfig: &v1alpha1.ProxyConfig{\n\t\t\tContainerImage: emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubeProxyImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t},\n\t\tSchedulerConfig: &v1alpha1.SchedulerConfig{\n\t\t\tContainerImage: emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubernetesSchedulerImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t},\n\t\tEtcdConfig: &v1alpha1.EtcdConfig{\n\t\t\tRootCA: in.Options.SecretsBundle.Certs.Etcd,\n\t\t},\n\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\tDNSDomain:     in.Options.DNSDomain,\n\t\t\tPodSubnet:     in.PodNet,\n\t\t\tServiceSubnet: in.ServiceNet,\n\t\t\tCNI:           in.Options.CNIConfig,\n\t\t},\n\t\tClusterCA:              in.Options.SecretsBundle.Certs.K8s,\n\t\tClusterAggregatorCA:    in.Options.SecretsBundle.Certs.K8sAggregator,\n\t\tClusterServiceAccount:  in.Options.SecretsBundle.Certs.K8sServiceAccount,\n\t\tBootstrapToken:         in.Options.SecretsBundle.Secrets.BootstrapToken,\n\t\tExtraManifests:         []string{},\n\t\tClusterInlineManifests: v1alpha1.ClusterInlineManifests{},\n\t}\n\n\tif in.Options.AllowSchedulingOnControlPlanes {\n\t\tif in.Options.VersionContract.KubernetesAllowSchedulingOnControlPlanes() {\n\t\t\tcluster.AllowSchedulingOnControlPlanes = new(in.Options.AllowSchedulingOnControlPlanes)\n\t\t} else {\n\t\t\t// backwards compatibility for Talos versions older than 1.2\n\t\t\tcluster.AllowSchedulingOnMasters = new(in.Options.AllowSchedulingOnControlPlanes) //nolint:staticcheck\n\t\t}\n\t}\n\n\tif in.Options.DiscoveryEnabled != nil {\n\t\tcluster.ClusterDiscoveryConfig = &v1alpha1.ClusterDiscoveryConfig{\n\t\t\tDiscoveryEnabled: new(*in.Options.DiscoveryEnabled),\n\t\t}\n\n\t\tif in.Options.VersionContract.KubernetesDiscoveryBackendDisabled() {\n\t\t\tcluster.ClusterDiscoveryConfig.DiscoveryRegistries.RegistryKubernetes.RegistryDisabled = new(true)\n\t\t}\n\t}\n\n\tif !in.Options.VersionContract.HideDisablePSP() {\n\t\tcluster.APIServerConfig.DisablePodSecurityPolicyConfig = new(true)\n\t}\n\n\tif in.Options.VersionContract.SecretboxEncryptionSupported() {\n\t\tcluster.ClusterSecretboxEncryptionSecret = in.Options.SecretsBundle.Secrets.SecretboxEncryptionSecret\n\t} else {\n\t\tcluster.ClusterAESCBCEncryptionSecret = in.Options.SecretsBundle.Secrets.AESCBCEncryptionSecret\n\t}\n\n\tv1alpha1Config.MachineConfig = machine\n\tv1alpha1Config.ClusterConfig = cluster\n\n\tdocuments := []config.Document{v1alpha1Config}\n\n\textraDocuments, err := in.generateRegistryConfigs(machine)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate registry configs: %w\", err)\n\t}\n\n\tdocuments = append(documents, extraDocuments...)\n\n\textraDocuments, err = in.generateNetworkConfigs(machine)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate network configs: %w\", err)\n\t}\n\n\tdocuments = append(documents, extraDocuments...)\n\n\treturn documents, nil\n}\n\nfunc ptrOrNil(b bool) *bool {\n\tif b {\n\t\treturn &b\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//nolint:gocyclo\nfunc (in *Input) generateNetworkConfigs(machine *v1alpha1.MachineConfig) ([]config.Document, error) {\n\tvar documents []config.Document\n\n\tif len(in.Options.NetworkConfigOptions) > 0 {\n\t\tnetworkConfig := &v1alpha1.NetworkConfig{} //nolint:staticcheck // using legacy NetworkConfig for older Talos versions\n\n\t\tfor _, opt := range in.Options.NetworkConfigOptions {\n\t\t\tif err := opt(machine.Type(), networkConfig); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tmachine.MachineNetwork = networkConfig //nolint:staticcheck // using legacy NetworkConfig for older Talos versions\n\t}\n\n\t// generate empty machine.network for backwards compatibility with older Talos versions\n\tif machine.MachineNetwork == nil && !in.Options.VersionContract.KubeSpanMultidocConfig() { //nolint:staticcheck // using legacy NetworkConfig for older Talos versions\n\t\tmachine.MachineNetwork = &v1alpha1.NetworkConfig{} //nolint:staticcheck // using legacy NetworkConfig for older Talos versions\n\t}\n\n\tif in.Options.VersionContract.StableHostnameEnabled() && !in.Options.VersionContract.MultidocNetworkConfigSupported() {\n\t\tmachine.MachineFeatures.StableHostname = new(true) //nolint:staticcheck // using legacy field for older Talos versions\n\t}\n\n\tif in.Options.VersionContract.MultidocNetworkConfigSupported() {\n\t\thostnameConfig := network.NewHostnameConfigV1Alpha1()\n\t\thostnameConfig.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\t\tdocuments = append(documents, hostnameConfig)\n\t}\n\n\tif kubeSpanEnabled, isSet := in.Options.KubeSpanEnabled.Get(); isSet {\n\t\tif in.Options.VersionContract.KubeSpanMultidocConfig() {\n\t\t\tkubeSpanConfig := network.NewKubeSpanV1Alpha1()\n\t\t\tkubeSpanConfig.ConfigEnabled = new(kubeSpanEnabled)\n\n\t\t\tdocuments = append(documents, kubeSpanConfig)\n\t\t} else {\n\t\t\t// for older Talos versions, set KubeSpan config in machine.network.kubespan\n\t\t\tmachine.MachineNetwork.NetworkKubeSpan = &v1alpha1.NetworkKubeSpan{ //nolint:staticcheck // using legacy NetworkKubeSpan for older Talos versions\n\t\t\t\tKubeSpanEnabled: new(kubeSpanEnabled),\n\t\t\t}\n\t\t}\n\t}\n\n\treturn documents, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"maps\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// Option controls generate options specific to input generation.\ntype Option func(o *Options) error\n\n// WithEndpointList specifies endpoints to use when accessing Talos cluster.\nfunc WithEndpointList(endpoints []string) Option {\n\treturn func(o *Options) error {\n\t\to.EndpointList = endpoints\n\n\t\treturn nil\n\t}\n}\n\n// WithLocalAPIServerPort specifies the local API server port for the cluster.\nfunc WithLocalAPIServerPort(port int) Option {\n\treturn func(o *Options) error {\n\t\to.LocalAPIServerPort = port\n\n\t\treturn nil\n\t}\n}\n\n// WithKubePrismPort specifies the KubePrism port.\n//\n// If 0, load balancer is disabled.\n// If not set, defaults to enabled with Talos 1.6+.\nfunc WithKubePrismPort(port int) Option {\n\treturn func(o *Options) error {\n\t\to.KubePrismPort = optional.Some(port)\n\n\t\treturn nil\n\t}\n}\n\n// WithInstallDisk specifies install disk to use in Talos cluster.\nfunc WithInstallDisk(disk string) Option {\n\treturn func(o *Options) error {\n\t\to.InstallDisk = disk\n\n\t\treturn nil\n\t}\n}\n\n// WithAdditionalSubjectAltNames specifies additional SANs.\nfunc WithAdditionalSubjectAltNames(sans []string) Option {\n\treturn func(o *Options) error {\n\t\to.AdditionalSubjectAltNames = append(o.AdditionalSubjectAltNames, sans...)\n\n\t\treturn nil\n\t}\n}\n\n// WithInstallImage specifies install container image to use in Talos cluster.\nfunc WithInstallImage(imageRef string) Option {\n\treturn func(o *Options) error {\n\t\to.InstallImage = imageRef\n\n\t\treturn nil\n\t}\n}\n\n// WithInstallExtraKernelArgs specifies extra kernel arguments to pass to the installer.\nfunc WithInstallExtraKernelArgs(args []string) Option {\n\treturn func(o *Options) error {\n\t\to.InstallExtraKernelArgs = append(o.InstallExtraKernelArgs, args...)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkOptions adds network config generation option.\nfunc WithNetworkOptions(opts ...v1alpha1.NetworkConfigOption) Option {\n\treturn func(o *Options) error {\n\t\to.NetworkConfigOptions = append(o.NetworkConfigOptions, opts...)\n\n\t\treturn nil\n\t}\n}\n\n// WithRegistryMirror configures registry mirror endpoint(s).\nfunc WithRegistryMirror(host string, endpoints ...string) Option {\n\treturn func(o *Options) error {\n\t\tif o.RegistryEndpoints == nil {\n\t\t\to.RegistryEndpoints = make(map[string][]string)\n\t\t}\n\n\t\to.RegistryEndpoints[host] = append(o.RegistryEndpoints[host], endpoints...)\n\n\t\treturn nil\n\t}\n}\n\n// WithRegistryCACert specifies the certificate of the certificate authority which signed certificate of the registry.\nfunc WithRegistryCACert(host, cacert string) Option {\n\treturn func(o *Options) error {\n\t\tif o.RegistryCACerts == nil {\n\t\t\to.RegistryCACerts = make(map[string]string)\n\t\t}\n\n\t\to.RegistryCACerts[host] = cacert\n\n\t\treturn nil\n\t}\n}\n\n// WithRegistryInsecureSkipVerify marks registry host to skip TLS verification.\nfunc WithRegistryInsecureSkipVerify(host string) Option {\n\treturn func(o *Options) error {\n\t\tif o.RegistryInsecure == nil {\n\t\t\to.RegistryInsecure = make(map[string]bool)\n\t\t}\n\n\t\to.RegistryInsecure[host] = true\n\n\t\treturn nil\n\t}\n}\n\n// WithDNSDomain specifies domain name to use in Talos cluster.\nfunc WithDNSDomain(dnsDomain string) Option {\n\treturn func(o *Options) error {\n\t\to.DNSDomain = dnsDomain\n\n\t\treturn nil\n\t}\n}\n\n// WithDebug enables verbose logging to console for all services.\nfunc WithDebug(enable bool) Option {\n\treturn func(o *Options) error {\n\t\to.Debug = enable\n\n\t\treturn nil\n\t}\n}\n\n// WithClusterCNIConfig specifies custom cluster CNI config.\nfunc WithClusterCNIConfig(config *v1alpha1.CNIConfig) Option {\n\treturn func(o *Options) error {\n\t\to.CNIConfig = config\n\n\t\treturn nil\n\t}\n}\n\n// WithUserDisks generates user partitions config.\n//\n// Deprecated: use block.UserVolumeConfig instead.\nfunc WithUserDisks(disks []*v1alpha1.MachineDisk) Option {\n\treturn func(o *Options) error {\n\t\to.MachineDisks = disks\n\n\t\treturn nil\n\t}\n}\n\n// WithAllowSchedulingOnControlPlanes specifies AllowSchedulingOnControlPlane flag.\nfunc WithAllowSchedulingOnControlPlanes(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.AllowSchedulingOnControlPlanes = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithVersionContract specifies version contract to use when generating.\nfunc WithVersionContract(versionContract *config.VersionContract) Option {\n\treturn func(o *Options) error {\n\t\to.VersionContract = versionContract\n\n\t\treturn nil\n\t}\n}\n\n// WithRoles specifies user roles.\nfunc WithRoles(roles role.Set) Option {\n\treturn func(o *Options) error {\n\t\to.Roles = roles\n\n\t\treturn nil\n\t}\n}\n\n// WithClusterDiscovery enables cluster discovery feature.\nfunc WithClusterDiscovery(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.DiscoveryEnabled = new(enabled)\n\n\t\treturn nil\n\t}\n}\n\n// WithSysctls merges list of sysctls with new values.\nfunc WithSysctls(params map[string]string) Option {\n\treturn func(o *Options) error {\n\t\tif o.Sysctls == nil {\n\t\t\to.Sysctls = make(map[string]string)\n\t\t}\n\n\t\tmaps.Copy(o.Sysctls, params)\n\n\t\treturn nil\n\t}\n}\n\n// WithSecretsBundle specifies custom secrets bundle.\nfunc WithSecretsBundle(bundle *secrets.Bundle) Option {\n\treturn func(o *Options) error {\n\t\to.SecretsBundle = bundle\n\n\t\treturn nil\n\t}\n}\n\n// WithHostDNSForwardKubeDNSToHost specifies whether to forward kube-dns to host.\nfunc WithHostDNSForwardKubeDNSToHost(forward bool) Option {\n\treturn func(o *Options) error {\n\t\to.HostDNSForwardKubeDNSToHost = optional.Some(forward)\n\n\t\treturn nil\n\t}\n}\n\n// WithKubeSpanEnabled specifies whether KubeSpan is enabled.\nfunc WithKubeSpanEnabled(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.KubeSpanEnabled = optional.Some(enabled)\n\n\t\treturn nil\n\t}\n}\n\n// Options describes generate parameters.\ntype Options struct {\n\tVersionContract *config.VersionContract\n\n\t// Custom secrets bundle.\n\tSecretsBundle *secrets.Bundle\n\n\t// Base settings.\n\tDebug bool\n\n\t// Machine settings: install.\n\tInstallDisk            string\n\tInstallImage           string\n\tInstallExtraKernelArgs []string\n\n\t// Machine disks.\n\tMachineDisks []*v1alpha1.MachineDisk\n\n\t// Machine network settings.\n\tNetworkConfigOptions []v1alpha1.NetworkConfigOption\n\n\t// Machine sysctls.\n\tSysctls map[string]string\n\n\t// Machine registries.\n\tRegistryEndpoints map[string][]string\n\tRegistryCACerts   map[string]string\n\tRegistryInsecure  map[string]bool\n\n\t// Cluster settings.\n\tDNSDomain                      string\n\tCNIConfig                      *v1alpha1.CNIConfig\n\tAllowSchedulingOnControlPlanes bool\n\tLocalAPIServerPort             int\n\tAdditionalSubjectAltNames      []string\n\tDiscoveryEnabled               *bool\n\n\tKubePrismPort optional.Optional[int]\n\n\tHostDNSForwardKubeDNSToHost optional.Optional[bool]\n\n\tKubeSpanEnabled optional.Optional[bool]\n\n\t// Client options.\n\tRoles        role.Set\n\tEndpointList []string\n}\n\n// DefaultOptions returns default options.\nfunc DefaultOptions() Options {\n\treturn Options{\n\t\tDNSDomain: \"cluster.local\",\n\t\tRoles:     role.MakeSet(role.Admin),\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/registry.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n//nolint:gocyclo,cyclop\nfunc (in *Input) generateRegistryConfigs(machine *v1alpha1.MachineConfig) ([]config.Document, error) {\n\tif !in.Options.VersionContract.MultidocNetworkConfigSupported() {\n\t\t// old-style registry config\n\t\tmachine.MachineRegistries = v1alpha1.RegistriesConfig{ //nolint:staticcheck // backwards compatibility\n\t\t\tRegistryMirrors: map[string]*v1alpha1.RegistryMirrorConfig{},\n\t\t\tRegistryConfig:  map[string]*v1alpha1.RegistryConfig{},\n\t\t}\n\n\t\tif in.Options.VersionContract.KubernetesAlternateImageRegistries() {\n\t\t\tif _, ok := machine.MachineRegistries.RegistryMirrors[\"k8s.gcr.io\"]; !ok { //nolint:staticcheck // backwards compatibility, Talos v1.1->1.2\n\t\t\t\tmachine.MachineRegistries.RegistryMirrors[\"k8s.gcr.io\"] = &v1alpha1.RegistryMirrorConfig{ //nolint:staticcheck // backwards compatibility, Talos v1.1->1.2\n\t\t\t\t\tMirrorEndpoints: []string{\n\t\t\t\t\t\t\"https://registry.k8s.io\",\n\t\t\t\t\t\t\"https://k8s.gcr.io\",\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor host, endpoints := range in.Options.RegistryEndpoints {\n\t\t\tmachine.MachineRegistries.RegistryMirrors[host] = &v1alpha1.RegistryMirrorConfig{ //nolint:staticcheck // backwards compatibility\n\t\t\t\tMirrorEndpoints: endpoints,\n\t\t\t}\n\t\t}\n\n\t\tfor host, cacert := range in.Options.RegistryCACerts {\n\t\t\tif _, ok := machine.MachineRegistries.RegistryConfig[host]; !ok { //nolint:staticcheck // backwards compatibility\n\t\t\t\tmachine.MachineRegistries.RegistryConfig[host] = &v1alpha1.RegistryConfig{} //nolint:staticcheck // backwards compatibility\n\t\t\t}\n\n\t\t\tif machine.MachineRegistries.RegistryConfig[host].RegistryTLS == nil { //nolint:staticcheck // backwards compatibility\n\t\t\t\tmachine.MachineRegistries.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} //nolint:staticcheck // backwards compatibility\n\t\t\t}\n\n\t\t\tmachine.MachineRegistries.RegistryConfig[host].RegistryTLS.TLSCA = v1alpha1.Base64Bytes(cacert) //nolint:staticcheck // backwards compatibility\n\t\t}\n\n\t\tfor host := range in.Options.RegistryInsecure {\n\t\t\tif _, ok := machine.MachineRegistries.RegistryConfig[host]; !ok { //nolint:staticcheck // backwards compatibility\n\t\t\t\tmachine.MachineRegistries.RegistryConfig[host] = &v1alpha1.RegistryConfig{} //nolint:staticcheck // backwards compatibility\n\t\t\t}\n\n\t\t\tif machine.MachineRegistries.RegistryConfig[host].RegistryTLS == nil { //nolint:staticcheck // backwards compatibility\n\t\t\t\tmachine.MachineRegistries.RegistryConfig[host].RegistryTLS = &v1alpha1.RegistryTLSConfig{} //nolint:staticcheck // backwards compatibility\n\t\t\t}\n\n\t\t\tmachine.MachineRegistries.RegistryConfig[host].RegistryTLS.TLSInsecureSkipVerify = new(true) //nolint:staticcheck // backwards compatibility\n\t\t}\n\n\t\treturn nil, nil\n\t}\n\n\tdocuments := make([]config.Document, 0, len(in.Options.RegistryEndpoints))\n\n\t// use new-style registry config via separate documents\n\tfor host, endpoints := range in.Options.RegistryEndpoints {\n\t\tregistryMirrorConfig := cri.NewRegistryMirrorConfigV1Alpha1(host)\n\t\tregistryMirrorConfig.RegistryEndpoints = make([]cri.RegistryEndpoint, 0, len(endpoints))\n\n\t\tfor _, ep := range endpoints {\n\t\t\tu, err := url.Parse(ep)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse registry mirror endpoint %q: %w\", ep, err)\n\t\t\t}\n\n\t\t\tregistryMirrorConfig.RegistryEndpoints = append(registryMirrorConfig.RegistryEndpoints, cri.RegistryEndpoint{\n\t\t\t\tEndpointURL: meta.URL{URL: u},\n\t\t\t})\n\t\t}\n\n\t\tdocuments = append(documents, registryMirrorConfig)\n\t}\n\n\ttlsConfigs := make(map[string]*cri.RegistryTLSConfigV1Alpha1)\n\n\tfor host, cacert := range in.Options.RegistryCACerts {\n\t\tif _, ok := tlsConfigs[host]; !ok {\n\t\t\ttlsConfigs[host] = cri.NewRegistryTLSConfigV1Alpha1(host)\n\t\t}\n\n\t\ttlsConfigs[host].TLSCA = cacert\n\t}\n\n\tfor host := range in.Options.RegistryInsecure {\n\t\tif _, ok := tlsConfigs[host]; !ok {\n\t\t\ttlsConfigs[host] = cri.NewRegistryTLSConfigV1Alpha1(host)\n\t\t}\n\n\t\ttlsConfigs[host].TLSInsecureSkipVerify = new(true)\n\t}\n\n\tfor _, tlsConfig := range tlsConfigs {\n\t\tdocuments = append(documents, tlsConfig)\n\t}\n\n\t// sort the TLS config and registry mirrors docs alphabetically by the name\n\tslices.SortStableFunc(documents, func(a, b config.Document) int {\n\t\tna, aok := a.(config.NamedDocument)\n\t\tnb, bok := b.(config.NamedDocument)\n\n\t\tif c := strings.Compare(a.Kind(), b.Kind()); c != 0 {\n\t\t\treturn c\n\t\t}\n\n\t\tif aok && bok {\n\t\t\treturn strings.Compare(na.Name(), nb.Name())\n\t\t}\n\n\t\treturn 0\n\t})\n\n\treturn documents, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/bundle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/cis\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// NewBundle creates secrets bundle generating all secrets.\nfunc NewBundle(clock Clock, versionContract *config.VersionContract) (*Bundle, error) {\n\tbundle := &Bundle{\n\t\tClock: clock,\n\t}\n\n\terr := bundle.populate(versionContract)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bundle, nil\n}\n\n// LoadBundle loads secrets bundle from the given file.\nfunc LoadBundle(path string) (*Bundle, error) {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint: errcheck\n\n\tbundle := &Bundle{\n\t\tClock: NewClock(),\n\t}\n\n\tdecoder := yaml.NewDecoder(f)\n\tif err = decoder.Decode(&bundle); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bundle, nil\n}\n\n// NewBundleFromKubernetesPKI creates secrets bundle by reading the contents\n// of a Kubernetes PKI directory (typically `/etc/kubernetes/pki`) and using the provided bootstrapToken as input.\n//\n//nolint:gocyclo\nfunc NewBundleFromKubernetesPKI(pkiDir, bootstrapToken string, versionContract *config.VersionContract) (*Bundle, error) {\n\tdirStat, err := os.Stat(pkiDir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !dirStat.IsDir() {\n\t\treturn nil, fmt.Errorf(\"%q is not a directory\", pkiDir)\n\t}\n\n\tvar (\n\t\tca           *x509.PEMEncodedCertificateAndKey\n\t\tetcdCA       *x509.PEMEncodedCertificateAndKey\n\t\taggregatorCA *x509.PEMEncodedCertificateAndKey\n\t\tsa           *x509.PEMEncodedKey\n\t)\n\n\tca, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(pkiDir, \"ca.crt\"), filepath.Join(pkiDir, \"ca.key\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = validatePEMEncodedCertificateAndKey(ca)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tetcdDir := filepath.Join(pkiDir, \"etcd\")\n\n\tetcdCA, err = x509.NewCertificateAndKeyFromFiles(filepath.Join(etcdDir, \"ca.crt\"), filepath.Join(etcdDir, \"ca.key\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = validatePEMEncodedCertificateAndKey(etcdCA)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\taggregatorCACrtPath := filepath.Join(pkiDir, \"front-proxy-ca.crt\")\n\n\taggregatorCA, err = x509.NewCertificateAndKeyFromFiles(aggregatorCACrtPath, filepath.Join(pkiDir, \"front-proxy-ca.key\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = validatePEMEncodedCertificateAndKey(aggregatorCA)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsaKeyPath := filepath.Join(pkiDir, \"sa.key\")\n\n\tvar saBytes []byte\n\n\tsaBytes, err = os.ReadFile(saKeyPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsa = &x509.PEMEncodedKey{\n\t\tKey: saBytes,\n\t}\n\n\t_, err = sa.GetKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbundle := &Bundle{\n\t\tSecrets: &Secrets{\n\t\t\tBootstrapToken: bootstrapToken,\n\t\t},\n\t\tCerts: &Certs{\n\t\t\tEtcd:              etcdCA,\n\t\t\tK8s:               ca,\n\t\t\tK8sAggregator:     aggregatorCA,\n\t\t\tK8sServiceAccount: sa,\n\t\t},\n\t}\n\n\terr = bundle.populate(versionContract)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bundle, nil\n}\n\n// NewBundleFromConfig creates secrets bundle using existing config.\nfunc NewBundleFromConfig(clock Clock, c config.Config) *Bundle {\n\tcerts := &Certs{\n\t\tK8s:               c.Cluster().IssuingCA(),\n\t\tK8sAggregator:     c.Cluster().AggregatorCA(),\n\t\tK8sServiceAccount: c.Cluster().ServiceAccount(),\n\t\tEtcd:              c.Cluster().Etcd().CA(),\n\t\tOS:                c.Machine().Security().IssuingCA(),\n\t}\n\n\tcluster := &Cluster{\n\t\tID:     c.Cluster().ID(),\n\t\tSecret: c.Cluster().Secret(),\n\t}\n\n\ttrustd := &TrustdInfo{\n\t\tToken: c.Machine().Security().Token(),\n\t}\n\n\tbootstrapToken := fmt.Sprintf(\n\t\t\"%s.%s\",\n\t\tc.Cluster().Token().ID(),\n\t\tc.Cluster().Token().Secret(),\n\t)\n\n\tsecrets := &Secrets{\n\t\tAESCBCEncryptionSecret:    c.Cluster().AESCBCEncryptionSecret(),\n\t\tSecretboxEncryptionSecret: c.Cluster().SecretboxEncryptionSecret(),\n\t\tBootstrapToken:            bootstrapToken,\n\t}\n\n\treturn &Bundle{\n\t\tClock:      clock,\n\t\tCluster:    cluster,\n\t\tSecrets:    secrets,\n\t\tTrustdInfo: trustd,\n\t\tCerts:      certs,\n\t}\n}\n\n// populate fills all the missing fields in the secrets bundle.\n//\n//nolint:gocyclo,cyclop\nfunc (bundle *Bundle) populate(versionContract *config.VersionContract) error {\n\tif bundle.Clock == nil {\n\t\tbundle.Clock = NewClock()\n\t}\n\n\tif bundle.Certs == nil {\n\t\tbundle.Certs = &Certs{}\n\t}\n\n\tif bundle.Certs.Etcd == nil {\n\t\tetcd, err := NewEtcdCA(bundle.Clock.Now(), versionContract)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.Certs.Etcd = &x509.PEMEncodedCertificateAndKey{\n\t\t\tCrt: etcd.CrtPEM,\n\t\t\tKey: etcd.KeyPEM,\n\t\t}\n\t}\n\n\tif bundle.Certs.K8s == nil {\n\t\tkubernetesCA, err := NewKubernetesCA(bundle.Clock.Now(), versionContract)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.Certs.K8s = &x509.PEMEncodedCertificateAndKey{\n\t\t\tCrt: kubernetesCA.CrtPEM,\n\t\t\tKey: kubernetesCA.KeyPEM,\n\t\t}\n\t}\n\n\tif bundle.Certs.K8sAggregator == nil {\n\t\taggregatorCA, err := NewAggregatorCA(bundle.Clock.Now(), versionContract)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.Certs.K8sAggregator = &x509.PEMEncodedCertificateAndKey{\n\t\t\tCrt: aggregatorCA.CrtPEM,\n\t\t\tKey: aggregatorCA.KeyPEM,\n\t\t}\n\t}\n\n\tif bundle.Certs.K8sServiceAccount == nil {\n\t\tif versionContract.UseRSAServiceAccountKey() {\n\t\t\tserviceAccount, err := x509.NewRSAKey()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{\n\t\t\t\tKey: serviceAccount.KeyPEM,\n\t\t\t}\n\t\t} else {\n\t\t\tserviceAccount, err := x509.NewECDSAKey()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbundle.Certs.K8sServiceAccount = &x509.PEMEncodedKey{\n\t\t\t\tKey: serviceAccount.KeyPEM,\n\t\t\t}\n\t\t}\n\t}\n\n\tif bundle.Certs.OS == nil {\n\t\ttalosCA, err := NewTalosCA(bundle.Clock.Now())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.Certs.OS = &x509.PEMEncodedCertificateAndKey{\n\t\t\tCrt: talosCA.CrtPEM,\n\t\t\tKey: talosCA.KeyPEM,\n\t\t}\n\t}\n\n\tif bundle.Secrets == nil {\n\t\tbundle.Secrets = &Secrets{}\n\t}\n\n\tif bundle.Secrets.BootstrapToken == \"\" {\n\t\ttoken, err := genToken(6, 16)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.Secrets.BootstrapToken = token\n\t}\n\n\tif versionContract.Greater(config.TalosVersion1_2) {\n\t\tif bundle.Secrets.SecretboxEncryptionSecret == \"\" {\n\t\t\tsecretboxEncryptionSecret, err := cis.CreateEncryptionToken()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbundle.Secrets.SecretboxEncryptionSecret = secretboxEncryptionSecret\n\t\t}\n\t} else {\n\t\tif bundle.Secrets.AESCBCEncryptionSecret == \"\" {\n\t\t\taesCBCEncryptionSecret, err := cis.CreateEncryptionToken()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tbundle.Secrets.AESCBCEncryptionSecret = aesCBCEncryptionSecret\n\t\t}\n\t}\n\n\tif bundle.TrustdInfo == nil {\n\t\tbundle.TrustdInfo = &TrustdInfo{}\n\t}\n\n\tif bundle.TrustdInfo.Token == \"\" {\n\t\ttoken, err := genToken(6, 16)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbundle.TrustdInfo.Token = token\n\t}\n\n\tif bundle.Cluster == nil {\n\t\tbundle.Cluster = &Cluster{}\n\t}\n\n\tif bundle.Cluster.ID == \"\" {\n\t\tclusterID, err := randBytes(constants.DefaultClusterIDSize)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate cluster ID: %w\", err)\n\t\t}\n\n\t\tbundle.Cluster.ID = base64.URLEncoding.EncodeToString(clusterID)\n\t}\n\n\tif bundle.Cluster.Secret == \"\" {\n\t\tclusterSecret, err := randBytes(constants.DefaultClusterSecretSize)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate cluster secret: %w\", err)\n\t\t}\n\n\t\tbundle.Cluster.Secret = base64.StdEncoding.EncodeToString(clusterSecret)\n\t}\n\n\treturn nil\n}\n\n// GenerateTalosAPIClientCertificate generates the admin certificate.\nfunc (bundle *Bundle) GenerateTalosAPIClientCertificate(roles role.Set) (*x509.PEMEncodedCertificateAndKey, error) {\n\treturn bundle.GenerateTalosAPIClientCertificateWithTTL(roles, constants.TalosAPIDefaultCertificateValidityDuration)\n}\n\n// GenerateTalosAPIClientCertificateWithTTL generates the admin certificate with specified TTL.\nfunc (bundle *Bundle) GenerateTalosAPIClientCertificateWithTTL(roles role.Set, crtTTL time.Duration) (*x509.PEMEncodedCertificateAndKey, error) {\n\treturn NewAdminCertificateAndKey(\n\t\tbundle.Clock.Now(),\n\t\tbundle.Certs.OS,\n\t\troles,\n\t\tcrtTTL,\n\t)\n}\n\n// Validate the bundle.\n//\n//nolint:gocyclo,cyclop\nfunc (bundle *Bundle) Validate() error {\n\tvar multiErr error\n\n\tif bundle.Cluster == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"cluster is required\"))\n\t} else {\n\t\tif bundle.Cluster.ID == \"\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"cluster.id is required\"))\n\t\t}\n\n\t\tif bundle.Cluster.Secret == \"\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"cluster.secret is required\"))\n\t\t}\n\t}\n\n\tif bundle.Secrets == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"secrets is required\"))\n\t} else {\n\t\tif bundle.Secrets.BootstrapToken == \"\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"secrets.bootstraptoken is required\"))\n\t\t}\n\n\t\tif bundle.Secrets.AESCBCEncryptionSecret == \"\" && bundle.Secrets.SecretboxEncryptionSecret == \"\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"one of [secrets.secretboxencryptionsecret, secrets.aescbcencryptionsecret] is required\"))\n\t\t}\n\n\t\tif bundle.Secrets.AESCBCEncryptionSecret != \"\" && bundle.Secrets.SecretboxEncryptionSecret != \"\" {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"only one of [secrets.secretboxencryptionsecret, secrets.aescbcencryptionsecret] is allowed\"))\n\t\t}\n\t}\n\n\tif bundle.TrustdInfo == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"trustdinfo is required\"))\n\t} else if bundle.TrustdInfo.Token == \"\" {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"trustdinfo.token is required\"))\n\t}\n\n\tif err := bundle.validateCerts(); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, err)\n\t}\n\n\treturn multiErr\n}\n\n//nolint:gocyclo,cyclop\nfunc (bundle *Bundle) validateCerts() error {\n\tif bundle.Certs == nil {\n\t\treturn errors.New(\"certs is required\")\n\t}\n\n\tvar multiErr error\n\n\tif bundle.Certs.Etcd == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.etcd is required\"))\n\t} else if err := validatePEMEncodedCertificateAndKey(bundle.Certs.Etcd); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.etcd is invalid: %w\", err))\n\t}\n\n\tif bundle.Certs.K8s == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8s is required\"))\n\t} else if err := validatePEMEncodedCertificateAndKey(bundle.Certs.K8s); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8s is invalid: %w\", err))\n\t}\n\n\tif bundle.Certs.K8sAggregator == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8saggregator is required\"))\n\t} else if err := validatePEMEncodedCertificateAndKey(bundle.Certs.K8sAggregator); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8saggregator is invalid: %w\", err))\n\t}\n\n\tif bundle.Certs.OS == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.os is required\"))\n\t} else if err := validatePEMEncodedCertificateAndKey(bundle.Certs.OS); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.os is invalid: %w\", err))\n\t}\n\n\tif bundle.Certs.K8sServiceAccount == nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8sserviceaccount is required\"))\n\t} else if _, err := bundle.Certs.K8sServiceAccount.GetKey(); err != nil {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"certs.k8sserviceaccount.key is invalid: %w\", err))\n\t}\n\n\treturn multiErr\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/ca.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\tstdx509 \"crypto/x509\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\n// NewEtcdCA generates a CA for the Etcd PKI.\nfunc NewEtcdCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) {\n\topts := []x509.Option{\n\t\tx509.Organization(\"etcd\"),\n\t\tx509.NotAfter(currentTime.Add(CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.ECDSA(true),\n\t}\n\n\treturn x509.NewSelfSignedCertificateAuthority(opts...)\n}\n\n// NewKubernetesCA generates a CA for the Kubernetes PKI.\nfunc NewKubernetesCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) {\n\topts := []x509.Option{\n\t\tx509.Organization(\"kubernetes\"),\n\t\tx509.NotAfter(currentTime.Add(CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.ECDSA(true),\n\t}\n\n\treturn x509.NewSelfSignedCertificateAuthority(opts...)\n}\n\n// NewAggregatorCA generates a CA for the Kubernetes aggregator/front-proxy.\nfunc NewAggregatorCA(currentTime time.Time, contract *config.VersionContract) (ca *x509.CertificateAuthority, err error) {\n\topts := []x509.Option{\n\t\tx509.ECDSA(true),\n\t\tx509.CommonName(\"front-proxy\"),\n\t\tx509.NotAfter(currentTime.Add(CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.ECDSA(true),\n\t}\n\n\treturn x509.NewSelfSignedCertificateAuthority(opts...)\n}\n\n// NewTalosCA generates a CA for the Talos PKI.\nfunc NewTalosCA(currentTime time.Time) (ca *x509.CertificateAuthority, err error) {\n\topts := []x509.Option{\n\t\tx509.Organization(\"talos\"),\n\t\tx509.NotAfter(currentTime.Add(CAValidityTime)),\n\t\tx509.NotBefore(currentTime),\n\t}\n\n\treturn x509.NewSelfSignedCertificateAuthority(opts...)\n}\n\n// NewAdminCertificateAndKey generates the admin Talos certificate and key.\nfunc NewAdminCertificateAndKey(currentTime time.Time, ca *x509.PEMEncodedCertificateAndKey, roles role.Set, ttl time.Duration) (p *x509.PEMEncodedCertificateAndKey, err error) {\n\topts := []x509.Option{\n\t\tx509.Organization(roles.Strings()...),\n\t\tx509.NotAfter(currentTime.Add(ttl)),\n\t\tx509.NotBefore(currentTime),\n\t\tx509.KeyUsage(stdx509.KeyUsageDigitalSignature),\n\t\tx509.ExtKeyUsage([]stdx509.ExtKeyUsage{stdx509.ExtKeyUsageClientAuth}),\n\t}\n\n\ttalosCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(ca)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkeyPair, err := x509.NewKeyPair(talosCA, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn x509.NewCertificateAndKeyFromKeyPair(keyPair), nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/clock.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport \"time\"\n\n// Clock system clock.\ntype Clock interface {\n\tNow() time.Time\n}\n\n// SystemClock is a real system clock, but the time returned can be made fixed.\ntype SystemClock struct {\n\tfixedTime time.Time\n}\n\n// NewClock creates new SystemClock.\nfunc NewClock() *SystemClock {\n\treturn &SystemClock{}\n}\n\n// NewFixedClock creates new SystemClock with fixed time.\nfunc NewFixedClock(t time.Time) *SystemClock {\n\treturn &SystemClock{\n\t\tfixedTime: t,\n\t}\n}\n\n// Now implements Clock.\nfunc (c *SystemClock) Now() time.Time {\n\tif c.fixedTime.IsZero() {\n\t\treturn time.Now()\n\t}\n\n\treturn c.fixedTime\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/generate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\tstdx509 \"crypto/x509\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestNewBundle(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname            string\n\t\tversionContract *config.VersionContract\n\t}{\n\t\t{\n\t\t\tname:            \"v1.0\",\n\t\t\tversionContract: config.TalosVersion1_0,\n\t\t},\n\t\t{\n\t\t\tname:            \"v1.3\",\n\t\t\tversionContract: config.TalosVersion1_3,\n\t\t},\n\t\t{\n\t\t\tname:            \"v1.7\",\n\t\t\tversionContract: config.TalosVersion1_7,\n\t\t},\n\t\t{\n\t\t\tname:            \"current\",\n\t\t\tversionContract: config.TalosVersionCurrent,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), test.versionContract)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestNewBundleFromConfig(t *testing.T) {\n\tt.Parallel()\n\n\tbundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\trequire.NoError(t, err)\n\n\tosCA, err := x509.NewCertificateAuthorityFromCertificateAndKey(bundle.Certs.OS)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, stdx509.Ed25519, osCA.Crt.PublicKeyAlgorithm, \"expected Ed25519 signature algorithm\")\n\n\tinput, err := generate.NewInput(\"test\", \"https://localhost:6443\", constants.DefaultKubernetesVersion, generate.WithSecretsBundle(bundle))\n\trequire.NoError(t, err)\n\n\tcfg, err := input.Config(machine.TypeControlPlane)\n\trequire.NoError(t, err)\n\n\tbundle2 := secrets.NewBundleFromConfig(bundle.Clock, cfg)\n\n\tassert.Equal(t, bundle, bundle2)\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/marshal_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n)\n\nfunc TestMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tbundle, err := secrets.NewBundle(secrets.NewFixedClock(time.Now()), config.TalosVersionCurrent)\n\trequire.NoError(t, err)\n\n\tdir := t.TempDir()\n\tpath := filepath.Join(dir, \"secrets.yaml\")\n\n\tf, err := os.Create(path)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, yaml.NewEncoder(f).Encode(bundle))\n\n\trequire.NoError(t, f.Close())\n\n\tbundle2, err := secrets.LoadBundle(path)\n\trequire.NoError(t, err)\n\n\tbundle2.Clock = bundle.Clock\n\n\tassert.Equal(t, bundle, bundle2)\n}\n\nfunc TestUnmarshalStable(t *testing.T) {\n\tt.Parallel()\n\n\tbundle, err := secrets.LoadBundle(\"testdata/secrets.yaml\")\n\trequire.NoError(t, err)\n\n\tassert.NotNil(t, bundle.Certs)\n\tassert.NotNil(t, bundle.Certs.Etcd)\n\tassert.NotNil(t, bundle.Certs.K8s)\n\tassert.NotNil(t, bundle.Certs.K8sAggregator)\n\tassert.NotNil(t, bundle.Certs.K8sServiceAccount)\n\n\tassert.NotNil(t, bundle.Cluster)\n\tassert.NotEmpty(t, bundle.Cluster.ID)\n\tassert.NotEmpty(t, bundle.Cluster.Secret)\n\n\tassert.NotNil(t, bundle.Secrets)\n\tassert.NotEmpty(t, bundle.Secrets.BootstrapToken)\n\tassert.NotEmpty(t, bundle.Secrets.SecretboxEncryptionSecret)\n\n\tassert.NotNil(t, bundle.TrustdInfo)\n\tassert.NotEmpty(t, bundle.TrustdInfo.Token)\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/secrets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package secrets provides types and methods to handle base machine configuration secrets.\npackage secrets\n\nimport (\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// CAValidityTime is the default validity time for CA certificates.\nconst CAValidityTime = 87600 * time.Hour\n\n// Bundle contains all cluster secrets required to generate machine configuration.\n//\n// NB: this structure is marhsalled/unmarshalled to/from JSON in various projects, so\n// we need to keep representation compatible.\ntype Bundle struct {\n\tClock      Clock       `yaml:\"-\" json:\"-\"`\n\tCluster    *Cluster    `json:\"Cluster\"`\n\tSecrets    *Secrets    `json:\"Secrets\"`\n\tTrustdInfo *TrustdInfo `json:\"TrustdInfo\"`\n\tCerts      *Certs      `json:\"Certs\"`\n}\n\n// Certs holds the base64 encoded keys and certificates.\ntype Certs struct {\n\t// Etcd is etcd CA certificate and key.\n\tEtcd *x509.PEMEncodedCertificateAndKey `json:\"Etcd\"`\n\t// K8s is Kubernetes CA certificate and key.\n\tK8s *x509.PEMEncodedCertificateAndKey `json:\"K8s\"`\n\t// K8sAggregator is Kubernetes aggregator CA certificate and key.\n\tK8sAggregator *x509.PEMEncodedCertificateAndKey `json:\"K8sAggregator\"`\n\t// K8sServiceAccount is Kubernetes service account key.\n\tK8sServiceAccount *x509.PEMEncodedKey `json:\"K8sServiceAccount\"`\n\t// OS is Talos API CA certificate and key.\n\tOS *x509.PEMEncodedCertificateAndKey `json:\"OS\"`\n}\n\n// Cluster holds Talos cluster-wide secrets.\ntype Cluster struct {\n\tID     string `json:\"Id\"`\n\tSecret string `json:\"Secret\"`\n}\n\n// Secrets holds the sensitive kubeadm data.\ntype Secrets struct {\n\tBootstrapToken            string `json:\"BootstrapToken\"`\n\tAESCBCEncryptionSecret    string `json:\"AESCBCEncryptionSecret,omitempty\" yaml:\",omitempty\"`\n\tSecretboxEncryptionSecret string `json:\"SecretboxEncryptionSecret,omitempty\" yaml:\",omitempty\"`\n}\n\n// TrustdInfo holds the trustd credentials.\ntype TrustdInfo struct {\n\tToken string `json:\"Token\"`\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/testdata/invalid-secrets.yaml",
    "content": "cluster:\n    id: cgvhCbucls-WqkESDTRqykFgb4hROI4cBpgB0YJLLtM=\nsecrets:\n    bootstraptoken: 2psnp2.lry8e9gycdix3bpa\ncerts:\n    etcd:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmRENDQVNPZ0F3SUJBZ0lRQ0tGUmRhOVIvY3dIQXo4U1ZHU3I5ekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TURVeU5URXlNVFEwTWxvWERUTXpNRFV5TWpFeU1UUTBNbG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkdjUEQ5S2xIa09WCkJhcTFKSXhPaE56UXpHNDgvUG1hRmNTaExZckR1WkZ2MkY3NWd2bmkrbDU5RENTR3h4S3VncnJiZlQzempjSUoKdWRQblN6VEI2eVdqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVb2ZLdXhqa0pyL3hSCkRwQmNKYmlaR3dTRVhKSXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdHZ2VzU2NmOUh0ZHRGdEVGVEJlK2pkRFgKTDZUT3UwazRaQ3lmelNtY0JGMENJSDFNeDRTUmx0TGRHaE43aitZNU00aTJzT2liZHBCN0xFOCtQRW9RM081eQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n    k8s:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRTkEvQ2JmWWRJaE5wRXVaQlgwWEFWVEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNRFV5TlRFeU1UUTBNbG9YRFRNek1EVXlNakV5TVRRMApNbG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCRUJHWDRoamtDbE5sSnBWNFJUZEVjSjJUcFVOTGlON2pQYnFzQkxIWFM2QWJBQWVDY2l0cHFLaWlUenQKaWdaTE5tdWlvL3ZOL1MxUkxaTTQ1TzFIVVBxallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVIS2NNVExRMWlCQloxL2Qvd0JBNjRsL0UrdW93Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnSFgwZXBmd3gKaUxDSGxUeks5Y0pjSjgzOGlOU3VPSmFoZllNcFJXMU5nUkVDSVFDOG5EUm9IUFRKNVpNN3lPRWNycURoR3FVVAp3YWVoMXRFTS83aDYyNWxGaHc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhteWM0SzhmN0doWlQwdkVOcUNPbDE0L3FPM0g1LytiaUM2ZU1aL3JkYzNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUUVaZmlHT1FLVTJVbWxYaEZOMFJ3blpPbFEwdUkzdU05dXF3RXNkZExvQnNBQjRKeUsybQpvcUtKUE8yS0JrczJhNktqKzgzOUxWRXRremprN1VkUStnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8sserviceaccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUY3b0ZsaXYrTVZ3Zzc4dUVla3JaMktsVS82ZVJ6RUw2OGUzTWNkWk82STZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFbHROcm00eDNpQy9vMmVGTDZyWVJjcTVtbExjTHhFVW5NQVJkVnpXeFVpbUpwZHVYeGhuSQpXSXloeTAzenUyRC9qSWlOeVlFR3llMjFUSTFVRFpwNUdRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    os:\n        key: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBaHQrSExpc1Flc2wyQVZRdDByVUpxakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qTXdOVEkxTVRJeE5EUXlXaGNOTXpNd05USXlNVEl4TkRReVdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUdFT3RQV3YvZlc5WVkyV21LVmJqcENKaStkbXhlWlBqUXpICjZvdHp0MWRYbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkxxU3UrREt1V1Jkbyt6NApMSDBjdG9mZUg4OUFNQVVHQXl0bGNBTkJBRnFabUp3ajZ6bTYrZm1SWldsaTBqQldVMElvckhxZGkrYXZzU3lxCkRPQlRPbVplYkFLQ2NqTEVMNGxoQWNhNk81ZVc1U0xVVVJxVUliUktwKzRjZ0FzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/testdata/secrets.yaml",
    "content": "cluster:\n    id: cgvhCbucls-WqkESDTRqykFgb4hROI4cBpgB0YJLLtM=\n    secret: Wiu0qx68V3MKhFDr8+OFwGCNOOPBiQCDsLpRa3MdxEQ=\nsecrets:\n    bootstraptoken: 2psnp2.lry8e9gycdix3bpa\n    secretboxencryptionsecret: 6zWBpno849HlD5jeuTmGToFYP+z8lgkJa0fhHobv7mE=\ntrustdinfo:\n    token: oamejv.9tk1nhuwnlc2nghf\ncerts:\n    etcd:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmRENDQVNPZ0F3SUJBZ0lRQ0tGUmRhOVIvY3dIQXo4U1ZHU3I5ekFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TURVeU5URXlNVFEwTWxvWERUTXpNRFV5TWpFeU1UUTBNbG93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkdjUEQ5S2xIa09WCkJhcTFKSXhPaE56UXpHNDgvUG1hRmNTaExZckR1WkZ2MkY3NWd2bmkrbDU5RENTR3h4S3VncnJiZlQzempjSUoKdWRQblN6VEI2eVdqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVb2ZLdXhqa0pyL3hSCkRwQmNKYmlaR3dTRVhKSXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdHZ2VzU2NmOUh0ZHRGdEVGVEJlK2pkRFgKTDZUT3UwazRaQ3lmelNtY0JGMENJSDFNeDRTUmx0TGRHaE43aitZNU00aTJzT2liZHBCN0xFOCtQRW9RM081eQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVLb0RIa3I4bnFHQmVsWkRYWkpoVVdySkUrNEx2L0ViZEFrbjZ3TnJ1QkNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWnc4UDBxVWVRNVVGcXJVa2pFNkUzTkRNYmp6OCtab1Z4S0V0aXNPNWtXL1lYdm1DK2VMNgpYbjBNSkliSEVxNkN1dHQ5UGZPTndnbTUwK2RMTk1IckpRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8s:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRTkEvQ2JmWWRJaE5wRXVaQlgwWEFWVEFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNRFV5TlRFeU1UUTBNbG9YRFRNek1EVXlNakV5TVRRMApNbG93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCRUJHWDRoamtDbE5sSnBWNFJUZEVjSjJUcFVOTGlON2pQYnFzQkxIWFM2QWJBQWVDY2l0cHFLaWlUenQKaWdaTE5tdWlvL3ZOL1MxUkxaTTQ1TzFIVVBxallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVVIS2NNVExRMWlCQloxL2Qvd0JBNjRsL0UrdW93Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnSFgwZXBmd3gKaUxDSGxUeks5Y0pjSjgzOGlOU3VPSmFoZllNcFJXMU5nUkVDSVFDOG5EUm9IUFRKNVpNN3lPRWNycURoR3FVVAp3YWVoMXRFTS83aDYyNWxGaHc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUhteWM0SzhmN0doWlQwdkVOcUNPbDE0L3FPM0g1LytiaUM2ZU1aL3JkYzNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUUVaZmlHT1FLVTJVbWxYaEZOMFJ3blpPbFEwdUkzdU05dXF3RXNkZExvQnNBQjRKeUsybQpvcUtKUE8yS0JrczJhNktqKzgzOUxWRXRremprN1VkUStnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8saggregator:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZRENDQVFXZ0F3SUJBZ0lRRnMwdklHTVN6MXA1TnFkdnpOY3k2VEFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1EVXlOVEV5TVRRME1sb1hEVE16TURVeU1qRXlNVFEwTWxvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCSnhZUXlKWUR1dkwvcEYwT1phbHRYc2NoQk9Oc3F3SmJUTW1HN2FMZ1NjNjZKU05yT3dmCkZrSCtSdmdiNFhoOUJiTHpsMEhaWDNTVFAzYStkancvYUJpallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV5cFJHdXVtK0lPM3pCbHJITk5KT2x2ZlhiTnd3Q2dZSUtvWkl6ajBFQXdJRFNRQXdSZ0loCkFKUWVERjhydk8yS2J4QWRlUHF0NmxoOTdDNjlDdzcvUitkY0hUZ1ZtWUFMQWlFQXJ0Yjg0TkxGejlXSzdqa3IKQ2FzR3lrSEdPUHY1THFhUFhXVUJCY3Z4MTc0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUZxQnZKQytUVWtRUTZxTTJYRU9leFE5Nklsc1VkU0NBaC9MZmJndWhzUnJvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFbkZoRElsZ082OHYra1hRNWxxVzFleHlFRTQyeXJBbHRNeVlidG91Qkp6cm9sSTJzN0I4VwpRZjVHK0J2aGVIMEZzdk9YUWRsZmRKTS9kcjUyUEQ5b0dBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8sserviceaccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUY3b0ZsaXYrTVZ3Zzc4dUVla3JaMktsVS82ZVJ6RUw2OGUzTWNkWk82STZvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFbHROcm00eDNpQy9vMmVGTDZyWVJjcTVtbExjTHhFVW5NQVJkVnpXeFVpbUpwZHVYeGhuSQpXSXloeTAzenUyRC9qSWlOeVlFR3llMjFUSTFVRFpwNUdRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    os:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBaHQrSExpc1Flc2wyQVZRdDByVUpxakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qTXdOVEkxTVRJeE5EUXlXaGNOTXpNd05USXlNVEl4TkRReVdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUdFT3RQV3YvZlc5WVkyV21LVmJqcENKaStkbXhlWlBqUXpICjZvdHp0MWRYbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkxxU3UrREt1V1Jkbyt6NApMSDBjdG9mZUg4OUFNQVVHQXl0bGNBTkJBRnFabUp3ajZ6bTYrZm1SWldsaTBqQldVMElvckhxZGkrYXZzU3lxCkRPQlRPbVplYkFLQ2NqTEVMNGxoQWNhNk81ZVc1U0xVVVJxVUliUktwKzRjZ0FzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJT0VTT0dBNjE1RktsTEJDWlVsZlhyVUFmQ3NZTFY1dE0wN0pvbjU0d1RDSwotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/utils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"bufio\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\nfunc randBytes(size int) ([]byte, error) {\n\tbuf := make([]byte, size)\n\n\tn, err := io.ReadFull(rand.Reader, buf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read from random generator: %w\", err)\n\t}\n\n\tif n != size {\n\t\treturn nil, fmt.Errorf(\"failed to generate sufficient number of random bytes (%d != %d)\", n, size)\n\t}\n\n\treturn buf, nil\n}\n\nfunc validatePEMEncodedCertificateAndKey(certs *x509.PEMEncodedCertificateAndKey) error {\n\t_, err := certs.GetKey()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = certs.GetCert()\n\n\treturn err\n}\n\n// randBootstrapTokenString returns a random string consisting of the characters in\n// validBootstrapTokenChars, with the length customized by the parameter.\nfunc randBootstrapTokenString(length int) (string, error) {\n\t// validBootstrapTokenChars defines the characters a bootstrap token can consist of\n\tconst validBootstrapTokenChars = \"0123456789abcdefghijklmnopqrstuvwxyz\"\n\n\t// len(\"0123456789abcdefghijklmnopqrstuvwxyz\") = 36 which doesn't evenly divide\n\t// the possible values of a byte: 256 mod 36 = 4. Discard any random bytes we\n\t// read that are >= 252 so the bytes we evenly divide the character set.\n\tconst maxByteValue = 252\n\n\tvar (\n\t\tb     byte\n\t\terr   error\n\t\ttoken = make([]byte, length)\n\t)\n\n\treader := bufio.NewReaderSize(rand.Reader, length*2)\n\n\tfor i := range token {\n\t\tfor {\n\t\t\tif b, err = reader.ReadByte(); err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\n\t\t\tif b < maxByteValue {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\ttoken[i] = validBootstrapTokenChars[int(b)%len(validBootstrapTokenChars)]\n\t}\n\n\treturn string(token), err\n}\n\n// genToken will generate a token of the format abc.123 (like kubeadm/trustd), where the length of the first string (before the dot)\n// and length of the second string (after dot) are specified as inputs.\nfunc genToken(lenFirst, lenSecond int) (string, error) {\n\tvar err error\n\n\ttokenTemp := make([]string, 2)\n\n\ttokenTemp[0], err = randBootstrapTokenString(lenFirst)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\ttokenTemp[1], err = randBootstrapTokenString(lenSecond)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn tokenTemp[0] + \".\" + tokenTemp[1], nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/secrets/validate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n)\n\nvar (\n\t//go:embed testdata/invalid-secrets.yaml\n\tinvalidSecrets []byte\n\t//go:embed testdata/secrets.yaml\n\tvalidSecrets []byte\n)\n\nfunc TestValidate(t *testing.T) {\n\tt.Parallel()\n\n\tvar bundle secrets.Bundle\n\trequire.NoError(t, yaml.Unmarshal(validSecrets, &bundle))\n\trequire.NoError(t, bundle.Validate())\n\n\tvar invalidBundle secrets.Bundle\n\trequire.NoError(t, yaml.Unmarshal(invalidSecrets, &invalidBundle))\n\trequire.EqualError(t, invalidBundle.Validate(), `6 errors occurred:\n\t* cluster.secret is required\n\t* one of [secrets.secretboxencryptionsecret, secrets.aescbcencryptionsecret] is required\n\t* trustdinfo is required\n\t* certs.etcd is invalid: failed to parse PEM block\n\t* certs.k8saggregator is required\n\t* certs.os is invalid: unsupported key type: \"CERTIFICATE\"\n\n`)\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/stdpatches/stdpatches.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package stdpatches contains standard patches applied to Talos machine configurations.\npackage stdpatches\n\nimport (\n\t\"fmt\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// WithStaticHostname returns a patch that sets a static hostname in the machine configuration.\nfunc WithStaticHostname(versionContract *config.VersionContract, hostname string) ([]byte, error) {\n\tif versionContract.MultidocNetworkConfigSupported() {\n\t\thostnameConfig := network.NewHostnameConfigV1Alpha1()\n\t\thostnameConfig.ConfigAuto = new(nethelpers.AutoHostnameKindOff)\n\t\thostnameConfig.ConfigHostname = hostname\n\n\t\treturn patchFromDocument(hostnameConfig)\n\t}\n\n\treturn patchFromV1Alpha1(map[string]any{\n\t\t\"machine\": map[string]any{\n\t\t\t\"network\": map[string]any{\n\t\t\t\t\"hostname\": hostname,\n\t\t\t},\n\t\t},\n\t})\n}\n\n// WithTrustedRoots returns a patch that sets trusted roots in the machine configuration.\nfunc WithTrustedRoots(versionContract *config.VersionContract, trustedRoots string) ([]byte, error) {\n\tif versionContract.MultidocNetworkConfigSupported() {\n\t\ttrustedRootsConfig := security.NewTrustedRootsConfigV1Alpha1()\n\t\ttrustedRootsConfig.Certificates = trustedRoots\n\n\t\treturn patchFromDocument(trustedRootsConfig)\n\t}\n\n\treturn nil, fmt.Errorf(\"trusted roots patch is not supported for version contract %s\", versionContract.String())\n}\n\nfunc patchFromDocument(doc configconfig.Document) ([]byte, error) {\n\tctr, err := container.New(doc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ctr.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n}\n\nfunc patchFromV1Alpha1(doc any) ([]byte, error) {\n\treturn yaml.Marshal(doc)\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/stdpatches/stdpatches_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage stdpatches_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/stdpatches\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\nfunc TestPatches(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tpatch             func(*config.VersionContract) ([]byte, error)\n\t\tversionContracts  []*config.VersionContract\n\t\tkubernetesVersion string\n\n\t\tassertion func(t *testing.T, cfg config.Config)\n\t}{\n\t\t{\n\t\t\tname: \"WithStaticHostname\",\n\n\t\t\tpatch: func(vc *config.VersionContract) ([]byte, error) {\n\t\t\t\treturn stdpatches.WithStaticHostname(vc, \"hostname-1\")\n\t\t\t},\n\n\t\t\tversionContracts: []*config.VersionContract{\n\t\t\t\tconfig.TalosVersion1_11,\n\t\t\t\tconfig.TalosVersion1_12,\n\t\t\t},\n\t\t\tkubernetesVersion: \"1.34.0\",\n\n\t\t\tassertion: func(t *testing.T, cfg config.Config) {\n\t\t\t\tassert.Equal(t, \"hostname-1\", cfg.NetworkHostnameConfig().Hostname())\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"WithTrustedRoots\",\n\n\t\t\tpatch: func(vc *config.VersionContract) ([]byte, error) {\n\t\t\t\treturn stdpatches.WithTrustedRoots(vc, \"trusted-roots-1\")\n\t\t\t},\n\n\t\t\tversionContracts: []*config.VersionContract{\n\t\t\t\tconfig.TalosVersion1_12,\n\t\t\t},\n\t\t\tkubernetesVersion: \"1.34.0\",\n\n\t\t\tassertion: func(t *testing.T, cfg config.Config) {\n\t\t\t\tassert.Len(t, cfg.TrustedRoots().ExtraTrustedRootCertificates(), 1)\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tfor _, vc := range test.versionContracts {\n\t\t\t\tt.Run(vc.String(), func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\n\t\t\t\t\tin, err := generate.NewInput(\n\t\t\t\t\t\tstrings.ToLower(test.name),\n\t\t\t\t\t\t\"https://127.0.0.1/\",\n\t\t\t\t\t\ttest.kubernetesVersion,\n\t\t\t\t\t\tgenerate.WithVersionContract(vc),\n\t\t\t\t\t)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tcfg, err := in.Config(machine.TypeControlPlane)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tbytesPatch, err := test.patch(vc)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tpatch, err := configpatcher.LoadPatch(bytesPatch)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tpatched, err := configpatcher.Apply(configpatcher.WithConfig(cfg), []configpatcher.Patch{patch})\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tpatchedCfg, err := patched.Config()\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t_, err = patchedCfg.Validate(mockValidationMode{}, validation.WithLocal())\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\ttest.assertion(t, patchedCfg)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype mockValidationMode struct{}\n\nfunc (mockValidationMode) String() string {\n\treturn \"mock\"\n}\n\nfunc (mockValidationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (mockValidationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/talosconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// Talosconfig returns the talos admin Talos config.\nfunc (in *Input) Talosconfig() (*clientconfig.Config, error) {\n\tclientcert, err := in.Options.SecretsBundle.GenerateTalosAPIClientCertificate(in.Options.Roles)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn clientconfig.NewConfig(in.ClusterName, in.Options.EndpointList, in.Options.SecretsBundle.Certs.OS.Crt, clientcert), nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/generate/worker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage generate\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\tv1alpha1 \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n//nolint:gocyclo,cyclop\nfunc (in *Input) worker() ([]config.Document, error) {\n\tv1alpha1Config := &v1alpha1.Config{\n\t\tConfigVersion: \"v1alpha1\",\n\t\tConfigDebug:   new(in.Options.Debug),\n\t\tConfigPersist: new(true),\n\t}\n\n\tmachine := &v1alpha1.MachineConfig{\n\t\tMachineType:     machine.TypeWorker.String(),\n\t\tMachineToken:    in.Options.SecretsBundle.TrustdInfo.Token,\n\t\tMachineCertSANs: in.AdditionalMachineCertSANs,\n\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\tKubeletImage: emptyIf(fmt.Sprintf(\"%s:v%s\", constants.KubeletImage, in.KubernetesVersion), in.KubernetesVersion),\n\t\t},\n\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{Crt: in.Options.SecretsBundle.Certs.OS.Crt},\n\t\tMachineInstall: &v1alpha1.InstallConfig{\n\t\t\tInstallDisk:            in.Options.InstallDisk,\n\t\t\tInstallImage:           in.Options.InstallImage,\n\t\t\tInstallWipe:            new(false),\n\t\t\tInstallExtraKernelArgs: in.Options.InstallExtraKernelArgs,\n\t\t},\n\t\tMachineDisks:    in.Options.MachineDisks,\n\t\tMachineSysctls:  in.Options.Sysctls,\n\t\tMachineFeatures: &v1alpha1.FeaturesConfig{},\n\t}\n\n\tif in.Options.VersionContract.GrubUseUKICmdlineDefault() {\n\t\tmachine.MachineInstall.InstallGrubUseUKICmdline = new(true)\n\t}\n\n\tif !in.Options.VersionContract.HideRBACAndKeyUsage() {\n\t\tmachine.MachineFeatures.RBAC = new(true)\n\n\t\tif in.Options.VersionContract.ApidExtKeyUsageCheckEnabled() {\n\t\t\tmachine.MachineFeatures.ApidCheckExtKeyUsage = new(true)\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.DiskQuotaSupportEnabled() {\n\t\tmachine.MachineFeatures.DiskQuotaSupport = new(true)\n\t}\n\n\tif kubePrismPort, optionSet := in.Options.KubePrismPort.Get(); optionSet { // default to enabled, but if set explicitly, allow it to be disabled\n\t\tif kubePrismPort > 0 {\n\t\t\tmachine.MachineFeatures.KubePrismSupport = &v1alpha1.KubePrism{\n\t\t\t\tServerEnabled: new(true),\n\t\t\t\tServerPort:    kubePrismPort,\n\t\t\t}\n\t\t}\n\t} else if in.Options.VersionContract.KubePrismEnabled() {\n\t\tmachine.MachineFeatures.KubePrismSupport = &v1alpha1.KubePrism{\n\t\t\tServerEnabled: new(true),\n\t\t\tServerPort:    constants.DefaultKubePrismPort,\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.KubeletDefaultRuntimeSeccompProfileEnabled() {\n\t\tmachine.MachineKubelet.KubeletDefaultRuntimeSeccompProfileEnabled = new(true)\n\t}\n\n\tif in.Options.VersionContract.KubeletManifestsDirectoryDisabled() {\n\t\tmachine.MachineKubelet.KubeletDisableManifestsDirectory = new(true)\n\t}\n\n\tif in.Options.VersionContract.HostDNSEnabled() {\n\t\tmachine.MachineFeatures.HostDNSSupport = &v1alpha1.HostDNSConfig{\n\t\t\tHostDNSEnabled:              new(true),\n\t\t\tHostDNSForwardKubeDNSToHost: ptrOrNil(in.Options.HostDNSForwardKubeDNSToHost.ValueOrZero() || in.Options.VersionContract.HostDNSForwardKubeDNSToHost()),\n\t\t}\n\t}\n\n\tcontrolPlaneURL, err := url.Parse(in.ControlPlaneEndpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcluster := &v1alpha1.ClusterConfig{\n\t\tClusterID:      in.Options.SecretsBundle.Cluster.ID,\n\t\tClusterSecret:  in.Options.SecretsBundle.Cluster.Secret,\n\t\tClusterCA:      &x509.PEMEncodedCertificateAndKey{Crt: in.Options.SecretsBundle.Certs.K8s.Crt},\n\t\tBootstrapToken: in.Options.SecretsBundle.Secrets.BootstrapToken,\n\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\tEndpoint: &v1alpha1.Endpoint{URL: controlPlaneURL},\n\t\t},\n\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{\n\t\t\tDNSDomain:     in.Options.DNSDomain,\n\t\t\tPodSubnet:     in.PodNet,\n\t\t\tServiceSubnet: in.ServiceNet,\n\t\t\tCNI:           in.Options.CNIConfig,\n\t\t},\n\t}\n\n\tif in.Options.DiscoveryEnabled != nil {\n\t\tcluster.ClusterDiscoveryConfig = &v1alpha1.ClusterDiscoveryConfig{\n\t\t\tDiscoveryEnabled: new(*in.Options.DiscoveryEnabled),\n\t\t}\n\n\t\tif in.Options.VersionContract.KubernetesDiscoveryBackendDisabled() {\n\t\t\tcluster.ClusterDiscoveryConfig.DiscoveryRegistries.RegistryKubernetes.RegistryDisabled = new(true)\n\t\t}\n\t}\n\n\tif machine.MachineRegistries.RegistryMirrors == nil { //nolint:staticcheck // backwards compatibility\n\t\tmachine.MachineRegistries.RegistryMirrors = map[string]*v1alpha1.RegistryMirrorConfig{} //nolint:staticcheck // backwards compatibility\n\t}\n\n\tif in.Options.VersionContract.KubernetesAlternateImageRegistries() {\n\t\tif _, ok := machine.MachineRegistries.RegistryMirrors[\"k8s.gcr.io\"]; !ok { //nolint:staticcheck // backwards compatibility Talos v1.1->1.2\n\t\t\tmachine.MachineRegistries.RegistryMirrors[\"k8s.gcr.io\"] = &v1alpha1.RegistryMirrorConfig{ //nolint:staticcheck // backwards compatibility Talos v1.1->1.2\n\t\t\t\tMirrorEndpoints: []string{\n\t\t\t\t\t\"https://registry.k8s.io\",\n\t\t\t\t\t\"https://k8s.gcr.io\",\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t}\n\n\tif in.Options.VersionContract.ClusterNameForWorkers() {\n\t\tcluster.ClusterName = in.ClusterName\n\t}\n\n\tv1alpha1Config.MachineConfig = machine\n\tv1alpha1Config.ClusterConfig = cluster\n\n\tdocuments := []config.Document{v1alpha1Config}\n\n\textraDocuments, err := in.generateRegistryConfigs(machine)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate registry configs: %w\", err)\n\t}\n\n\tdocuments = append(documents, extraDocuments...)\n\n\textraDocuments, err = in.generateNetworkConfigs(machine)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate network configs: %w\", err)\n\t}\n\n\tdocuments = append(documents, extraDocuments...)\n\n\treturn documents, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/internal/cis/cis.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cis\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n)\n\n// CreateEncryptionToken generates an encryption token to be used for secrets.\nfunc CreateEncryptionToken() (string, error) {\n\tencryptionKey := make([]byte, 32)\n\tif _, err := rand.Read(encryptionKey); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tstr := base64.StdEncoding.EncodeToString(encryptionKey)\n\n\treturn str, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/internal/cis/cis_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cis_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/machinery/config/internal/documentid/documentid.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package documentid provides methods to create and extract document IDs.\npackage documentid\n\nimport (\n\t\"cmp\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\nconst (\n\t// ManifestAPIVersionKey is the string indicating a manifest's version.\n\tManifestAPIVersionKey = \"apiVersion\"\n\t// ManifestKindKey is the string indicating a manifest's kind.\n\tManifestKindKey = \"kind\"\n\t// ManifestNameKey is the string indicating a manifest's name.\n\tManifestNameKey = \"name\"\n\t// ManifestVersionKey is the string indicating a manifest's version, used only in v1alpha1 document.\n\tManifestVersionKey = \"version\"\n)\n\n// DocumentID uniquely identifies a configuration document.\ntype DocumentID struct {\n\tAPIVersion string\n\tKind       string\n\tName       string\n}\n\n// Meta returns a map representation of the DocumentID suitable for use as metadata in configuration documents.\nfunc (id DocumentID) Meta() map[string]any {\n\tmeta := map[string]any{}\n\n\tif id.Kind == \"v1alpha1\" {\n\t\tmeta[ManifestVersionKey] = \"v1alpha1\"\n\n\t\treturn meta\n\t}\n\n\tmeta[ManifestAPIVersionKey] = id.APIVersion\n\tmeta[ManifestKindKey] = id.Kind\n\n\tif id.Name != \"\" {\n\t\tmeta[ManifestNameKey] = id.Name\n\t}\n\n\treturn meta\n}\n\n// Extract extracts a DocumentID from the given configuration document.\nfunc Extract(doc config.Document) DocumentID {\n\tvar apiVersion, kind, name string\n\n\tif doc.APIVersion() != \"\" && doc.Kind() != \"\" {\n\t\tapiVersion = doc.APIVersion()\n\t\tkind = doc.Kind()\n\t}\n\n\tif named, ok := doc.(config.NamedDocument); ok {\n\t\tname = named.Name()\n\t}\n\n\treturn DocumentID{\n\t\tAPIVersion: apiVersion,\n\t\tKind:       cmp.Or(kind, \"v1alpha1\"),\n\t\tName:       name,\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/internal/registry/registry.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package registry provides a registry for configuration documents.\npackage registry\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\nvar (\n\t// ErrNotRegistered indicates that the manifest kind is not registered.\n\tErrNotRegistered = errors.New(\"not registered\")\n\t// ErrExists indicates that the manifest is already registered.\n\tErrExists = errors.New(\"exists\")\n)\n\n// NewDocumentFunc represents a function that creates a new document by version.\ntype NewDocumentFunc func(version string) config.Document\n\nvar registry = NewRegistry()\n\n// Registry represents the document kind/version registry.\n//\n// Global registry is available via top-level functions Register and New.\ntype Registry struct {\n\tm          sync.Mutex\n\tregistered map[string]NewDocumentFunc\n}\n\n// NewRegistry creates a new registry.\nfunc NewRegistry() *Registry {\n\treturn &Registry{\n\t\tregistered: map[string]NewDocumentFunc{},\n\t}\n}\n\n// Register registers a manifests with the registry.\nfunc Register(kind string, f NewDocumentFunc) {\n\tregistry.Register(kind, f)\n}\n\n// New creates a new instance of the requested manifest.\nfunc New(kind, version string) (config.Document, error) {\n\treturn registry.New(kind, version)\n}\n\n// Register registers a document kind with the registry.\nfunc (r *Registry) Register(kind string, f NewDocumentFunc) {\n\tr.m.Lock()\n\tdefer r.m.Unlock()\n\n\tif _, ok := r.registered[kind]; ok {\n\t\tpanic(ErrExists)\n\t}\n\n\tr.registered[kind] = f\n}\n\n// New creates a new instance of the requested document.\nfunc (r *Registry) New(kind, version string) (config.Document, error) {\n\tr.m.Lock()\n\tdefer r.m.Unlock()\n\n\tf, ok := r.registered[kind]\n\tif ok {\n\t\tdoc := f(version)\n\n\t\tif doc != nil {\n\t\t\treturn doc, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"%q %q: %w\", kind, version, ErrNotRegistered)\n}\n"
  },
  {
    "path": "pkg/machinery/config/internal/registry/registry_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage registry_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n)\n\ntype mockDocument struct {\n\tkind, version string\n}\n\nfunc (d mockDocument) Clone() config.Document {\n\treturn d\n}\n\nfunc (d mockDocument) Kind() string {\n\treturn d.kind\n}\n\nfunc (d mockDocument) APIVersion() string {\n\treturn d.version\n}\n\nfunc mockFactory(kind, version string) registry.NewDocumentFunc {\n\treturn func(requestedVersion string) config.Document {\n\t\tif requestedVersion == version {\n\t\t\treturn mockDocument{kind, version}\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\nfunc TestRegistry(t *testing.T) {\n\tr := registry.NewRegistry()\n\n\t// register document types\n\tr.Register(\"kind1\", mockFactory(\"kind1\", \"v1alpha1\"))\n\tr.Register(\"kind2\", mockFactory(\"kind2\", \"v1alpha1\"))\n\n\t// register duplicate kind\n\tassert.Panics(t, func() {\n\t\tr.Register(\"kind1\", mockFactory(\"kind1\", \"v1alpha3\"))\n\t})\n\n\t// attempt to get unregistered kind\n\t_, err := r.New(\"unknownKind\", \"unknownVersion\")\n\trequire.Error(t, err)\n\tassert.ErrorIs(t, err, registry.ErrNotRegistered)\n\tassert.EqualError(t, err, \"\\\"unknownKind\\\" \\\"unknownVersion\\\": not registered\")\n\n\t// successful creation of documents\n\td, err := r.New(\"kind1\", \"v1alpha1\")\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"kind1\", d.Kind())\n\tassert.Equal(t, \"v1alpha1\", d.APIVersion())\n\n\td, err = r.New(\"kind2\", \"v1alpha1\")\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"kind2\", d.Kind())\n\tassert.Equal(t, \"v1alpha1\", d.APIVersion())\n\n\t// attempt get registered kind, but wrong version\n\t_, err = r.New(\"kind1\", \"unknownVersion\")\n\trequire.Error(t, err)\n\tassert.ErrorIs(t, err, registry.ErrNotRegistered)\n\tassert.EqualError(t, err, \"\\\"kind1\\\" \\\"unknownVersion\\\": not registered\")\n}\n"
  },
  {
    "path": "pkg/machinery/config/machine/machine.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package machine defines common machine type.\npackage machine\n\nimport (\n\t\"fmt\"\n)\n\n//go:generate go tool golang.org/x/tools/cmd/stringer -type=Type -linecomment\n\n// Type represents a machine type.\ntype Type int\n\n//structprotogen:gen_enum\nconst (\n\t// TypeUnknown represents undefined node type, when there is no machine configuration yet.\n\tTypeUnknown Type = iota // unknown\n\n\t// TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node.\n\t// This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc.\n\tTypeInit // init\n\n\t// TypeControlPlane designates the node as a control plane member.\n\t// This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\n\tTypeControlPlane // controlplane\n\n\t// TypeWorker designates the node as a worker node.\n\t// This means it will be an available compute node for scheduling workloads.\n\tTypeWorker // worker\n)\n\n// ParseType parses string constant as Type.\nfunc ParseType(s string) (Type, error) {\n\tswitch s {\n\tcase \"init\":\n\t\treturn TypeInit, nil\n\tcase \"controlplane\":\n\t\treturn TypeControlPlane, nil\n\tcase \"worker\", \"join\", \"\":\n\t\treturn TypeWorker, nil\n\tcase \"unknown\":\n\t\treturn TypeUnknown, nil\n\tdefault:\n\t\treturn TypeUnknown, fmt.Errorf(\"invalid machine type: %q\", s)\n\t}\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (t Type) MarshalText() (text []byte, err error) {\n\treturn []byte(t.String()), nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (t *Type) UnmarshalText(text []byte) error {\n\tvar err error\n\n\t*t, err = ParseType(string(text))\n\n\treturn err\n}\n\n// IsControlPlane returns true if the type is a control plane node.\nfunc (t Type) IsControlPlane() bool {\n\treturn t == TypeControlPlane || t == TypeInit\n}\n"
  },
  {
    "path": "pkg/machinery/config/machine/machine_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage machine_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\nfunc TestParseType(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Values\", func(t *testing.T) {\n\t\t// We have to use the same values as defined in proto as we use direct type conversions in many places.\n\t\tassert.EqualValues(t, machineapi.MachineConfig_TYPE_UNKNOWN, machine.TypeUnknown)\n\t\tassert.EqualValues(t, machineapi.MachineConfig_TYPE_INIT, machine.TypeInit)\n\t\tassert.EqualValues(t, machineapi.MachineConfig_TYPE_CONTROL_PLANE, machine.TypeControlPlane)\n\t\tassert.EqualValues(t, machineapi.MachineConfig_TYPE_WORKER, machine.TypeWorker)\n\t})\n\n\tvalidTests := []struct {\n\t\ts   string\n\t\ttyp machine.Type\n\t}{\n\t\t{\"init\", machine.TypeInit},\n\t\t{\"controlplane\", machine.TypeControlPlane},\n\t\t{\"worker\", machine.TypeWorker},\n\t\t{\"join\", machine.TypeWorker},\n\t\t{\"\", machine.TypeWorker},\n\t\t{\"unknown\", machine.TypeUnknown},\n\t}\n\n\tfor _, tt := range validTests {\n\t\tt.Run(tt.s, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual, err := machine.ParseType(tt.s)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.typ, actual)\n\n\t\t\t// check that constant's comment for stringer and ParseType() function are in sync\n\t\t\tactual, err = machine.ParseType(actual.String())\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.typ, actual)\n\t\t})\n\t}\n\n\tfor _, s := range []string{\n\t\t\"foo\",\n\t} {\n\t\tt.Run(s, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tactual, err := machine.ParseType(s)\n\t\t\tassert.Error(t, err)\n\t\t\tassert.Equal(t, machine.TypeUnknown, actual)\n\t\t})\n\t}\n\n\tassert.NotEmpty(t, machine.TypeUnknown.String())\n}\n"
  },
  {
    "path": "pkg/machinery/config/machine/type_string.go",
    "content": "// Code generated by \"stringer -type=Type -linecomment\"; DO NOT EDIT.\n\npackage machine\n\nimport \"strconv\"\n\nfunc _() {\n\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n\t// Re-run the stringer command to generate them again.\n\tvar x [1]struct{}\n\t_ = x[TypeUnknown-0]\n\t_ = x[TypeInit-1]\n\t_ = x[TypeControlPlane-2]\n\t_ = x[TypeWorker-3]\n}\n\nconst _Type_name = \"unknowninitcontrolplaneworker\"\n\nvar _Type_index = [...]uint8{0, 7, 11, 23, 29}\n\nfunc (i Type) String() string {\n\tif i < 0 || i >= Type(len(_Type_index)-1) {\n\t\treturn \"Type(\" + strconv.FormatInt(int64(i), 10) + \")\"\n\t}\n\treturn _Type_name[_Type_index[i]:_Type_index[i+1]]\n}\n"
  },
  {
    "path": "pkg/machinery/config/merge/merge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage merge\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n)\n\n// Merge two config trees together.\n//\n// Data in the left is replaced with data in the right unless it's zero value.\n//\n// This function is not supposed to be a generic merge function.\n// It is specifically fine-tuned to merge Talos machine configuration.\n//\n// Rules:\n//   - if it is a simple value (int, float, string, etc.), it's merged into the left unless it's zero value, but boolean false is always merged.\n//   - if it is a pointer, merged dereferencing the pointer unless the right is nil\n//   - if it is a slice, merged by concatenating the right to the left.\n//   - if the `merge:\"replace\"` struct tag is defined, a slice is replaced with the value of the right (unless it's zero value.)\n//   - slices of `[]byte` are always replaced\n//   - if it is a map, for each key value is merged recursively.\n//   - if it is a struct, merge is performed for each field of the struct.\n//   - if the type implements 'merger' interface, Merge function is called to handle the merge process.\n//   - merger interface should be implemented on the pointer to the type.\nfunc Merge(left, right any) error {\n\treturn merge(reflect.ValueOf(left), reflect.ValueOf(right), false, false)\n}\n\ntype merger interface {\n\tMerge(other any) error\n}\n\nvar (\n\tzeroValue  reflect.Value\n\tmergerType = reflect.TypeFor[merger]()\n)\n\n//nolint:gocyclo,cyclop\nfunc merge(vl, vr reflect.Value, replace, overwrite bool) error {\n\tif vl == zeroValue && vr == zeroValue {\n\t\treturn nil\n\t}\n\n\ttl, tr := vl.Type(), vr.Type()\n\n\tif tl != tr {\n\t\treturn fmt.Errorf(\"merge type mismatch left %v right %v\", tl, tr)\n\t}\n\n\tif reflect.PointerTo(tl).Implements(mergerType) {\n\t\treturn vl.Addr().Interface().(merger).Merge(vr.Interface())\n\t}\n\n\tswitch tl.Kind() { //nolint:exhaustive\n\tcase reflect.Pointer, reflect.Interface:\n\t\tif vr.IsZero() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif vl.IsZero() {\n\t\t\tvl.Set(vr)\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn merge(vl.Elem(), vr.Elem(), replace, true)\n\tcase reflect.Slice:\n\t\tif vr.IsZero() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif !vl.CanSet() {\n\t\t\treturn fmt.Errorf(\"merge not possible, left %v is not settable\", vl)\n\t\t}\n\n\t\tif replace || tl.Elem().Kind() == reflect.Uint8 {\n\t\t\tvl.Set(vr)\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif vl.IsNil() && vr.Len() == 0 {\n\t\t\tvl.Set(reflect.MakeSlice(tl, 0, 0))\n\t\t} else {\n\t\t\tvl.Set(reflect.AppendSlice(reflect.MakeSlice(tl, 0, 0), reflect.AppendSlice(vl, vr)))\n\t\t}\n\tcase reflect.Map:\n\t\tif vr.IsZero() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif replace {\n\t\t\tvl.Set(vr)\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif vl.IsNil() {\n\t\t\tvl.Set(reflect.MakeMap(tl))\n\t\t}\n\n\t\tfor _, k := range vr.MapKeys() {\n\t\t\tif !isNilOrZero(vl.MapIndex(k)) {\n\t\t\t\tvalueType := tl.Elem()\n\n\t\t\t\tvar v, rightV reflect.Value\n\n\t\t\t\tif valueType.Kind() == reflect.Interface { // special case for map[string]interface{}\n\t\t\t\t\t// here we have to instantiate the actual type behind in the `interface{}`, otherwise it's not settable\n\t\t\t\t\tvalueType = vl.MapIndex(k).Elem().Type()\n\n\t\t\t\t\tif valueType != vr.MapIndex(k).Elem().Type() {\n\t\t\t\t\t\treturn fmt.Errorf(\"merge type mismatch left %v right %v\", valueType, vr.MapIndex(k).Elem().Type())\n\t\t\t\t\t}\n\n\t\t\t\t\tv = reflect.New(valueType).Elem()\n\t\t\t\t\tv.Set(vl.MapIndex(k).Elem())\n\n\t\t\t\t\trightV = reflect.New(valueType).Elem()\n\t\t\t\t\trightV.Set(vr.MapIndex(k).Elem())\n\t\t\t\t} else { // \"normal\" maps\n\t\t\t\t\tv = reflect.New(valueType).Elem()\n\t\t\t\t\tv.Set(vl.MapIndex(k))\n\n\t\t\t\t\trightV = vr.MapIndex(k)\n\t\t\t\t}\n\n\t\t\t\tif err := merge(v, rightV, false, false); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"merge map key %v[%v]: %w\", tl, k, err)\n\t\t\t\t}\n\n\t\t\t\tvl.SetMapIndex(k, v)\n\t\t\t} else {\n\t\t\t\tvl.SetMapIndex(k, vr.MapIndex(k))\n\t\t\t}\n\t\t}\n\tcase reflect.Struct:\n\t\tif replace {\n\t\t\t// if the right-hand struct is zero value, skip replacing the left-hand struct\n\t\t\tif vr.IsZero() {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tvl.Set(vr)\n\n\t\t\treturn nil\n\t\t}\n\n\t\tfor i := range tl.NumField() {\n\t\t\tvar replace bool\n\n\t\t\tstructTag := tl.Field(i).Tag.Get(\"merge\")\n\t\t\tfor value := range strings.SplitSeq(structTag, \",\") {\n\t\t\t\tif value == \"replace\" {\n\t\t\t\t\treplace = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfl := vl.FieldByIndex(tl.Field(i).Index)\n\t\t\tfr := vr.FieldByIndex(tr.Field(i).Index)\n\n\t\t\tif err := merge(fl, fr, replace, false); err != nil {\n\t\t\t\treturn fmt.Errorf(\"merge field %v.%v: %w\", tl, tl.Field(i).Name, err)\n\t\t\t}\n\t\t}\n\tcase\n\t\treflect.String,\n\t\treflect.Int,\n\t\treflect.Uint,\n\t\treflect.Int8,\n\t\treflect.Int16,\n\t\treflect.Int32,\n\t\treflect.Int64,\n\t\treflect.Uint8,\n\t\treflect.Uint16,\n\t\treflect.Uint32,\n\t\treflect.Uint64,\n\t\treflect.Float32,\n\t\treflect.Float64,\n\t\treflect.Bool:\n\t\tif !vl.CanSet() {\n\t\t\treturn fmt.Errorf(\"merge not possible, left %v is not settable\", vl)\n\t\t}\n\n\t\tif tl.Kind() != reflect.Bool && vr.IsZero() && !overwrite {\n\t\t\treturn nil\n\t\t}\n\n\t\tvl.Set(vr)\n\tdefault:\n\t\treturn fmt.Errorf(\"merge not implemented for %v\", tl.Kind())\n\t}\n\n\treturn nil\n}\n\n// isNilOrZero returns true if the [reflect.Value] is zero [reflect.Value] or something that is nil.\n// We need it because if map contains a key with `nil` value, simply comparing that result to the `zeroValue`\n// is not enough.\nfunc isNilOrZero(idx reflect.Value) bool {\n\tif idx == zeroValue {\n\t\treturn true\n\t}\n\n\tswitch idx.Kind() { //nolint:exhaustive\n\tcase reflect.Interface, reflect.Pointer, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func:\n\t\treturn idx.IsNil()\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/merge/merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage merge_test\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n)\n\ntype Config struct {\n\tA             string\n\tB             int\n\tC             *bool\n\tD             *int\n\tSlice         []Struct\n\tReplacedSlice []string `merge:\"replace\"`\n\tMap           map[string]Struct\n\tCustomSlice   CustomSlice\n}\n\ntype Struct struct {\n\tDA bool\n\tDB *int\n}\n\ntype CustomSlice []string\n\nfunc (s *CustomSlice) Merge(other any) error {\n\totherSlice, ok := other.(CustomSlice)\n\tif !ok {\n\t\treturn fmt.Errorf(\"other is not CustomSlice: %v\", other)\n\t}\n\n\t*s = append(*s, otherSlice...)\n\tslices.Sort(*s)\n\n\treturn nil\n}\n\ntype Unstructured map[string]any\n\nfunc TestMerge(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tleft, right any\n\t\texpected    any\n\t}{\n\t\t{\n\t\t\tname: \"zero\",\n\t\t},\n\t\t{\n\t\t\tname: \"partial merge\",\n\t\t\tleft: &Config{\n\t\t\t\tA: \"a\",\n\t\t\t\tB: 3,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t\tDB: new(1),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tright: &Config{\n\t\t\t\tA: \"aa\",\n\t\t\t\tB: 4,\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDB: new(3),\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t\tDB: new(5),\n\t\t\t\t\t},\n\t\t\t\t\t\"c\": {\n\t\t\t\t\t\tDB: new(4),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tA: \"aa\",\n\t\t\t\tB: 4,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t\tDB: new(1),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDB: new(3),\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t\tDB: new(5),\n\t\t\t\t\t},\n\t\t\t\t\t\"c\": {\n\t\t\t\t\t\tDB: new(4),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"merge with zero\",\n\t\t\tleft: &Config{\n\t\t\t\tA: \"a\",\n\t\t\t\tB: 3,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tright: &Config{},\n\t\t\texpected: &Config{\n\t\t\t\tA: \"a\",\n\t\t\t\tB: 3,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"merge from zero\",\n\t\t\tleft: &Config{},\n\t\t\tright: &Config{\n\t\t\t\tA: \"a\",\n\t\t\t\tB: 3,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tA: \"a\",\n\t\t\t\tB: 3,\n\t\t\t\tC: new(true),\n\t\t\t\tSlice: []Struct{\n\t\t\t\t\t{\n\t\t\t\t\t\tDA: false,\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMap: map[string]Struct{\n\t\t\t\t\t\"a\": {\n\t\t\t\t\t\tDA: true,\n\t\t\t\t\t},\n\t\t\t\t\t\"b\": {\n\t\t\t\t\t\tDB: new(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"replace slice\",\n\t\t\tleft: &Config{\n\t\t\t\tReplacedSlice: []string{\"a\", \"b\"},\n\t\t\t},\n\t\t\tright: &Config{\n\t\t\t\tReplacedSlice: []string{\"c\", \"d\"},\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tReplacedSlice: []string{\"c\", \"d\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"zero slice\",\n\t\t\tleft: &Config{},\n\t\t\tright: &Config{\n\t\t\t\tSlice: []Struct{},\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tSlice: []Struct{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"custom slice\",\n\t\t\tleft: &Config{\n\t\t\t\tCustomSlice: []string{\"a\", \"c\"},\n\t\t\t},\n\t\t\tright: &Config{\n\t\t\t\tCustomSlice: []string{\"b\", \"d\"},\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tCustomSlice: []string{\"a\", \"b\", \"c\", \"d\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"merge with pointer override\",\n\t\t\tleft: &Config{\n\t\t\t\tD: new(1),\n\t\t\t},\n\t\t\tright: &Config{\n\t\t\t\tD: new(0),\n\t\t\t},\n\t\t\texpected: &Config{\n\t\t\t\tD: new(0),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"unstructured\",\n\t\t\tleft: &Unstructured{\n\t\t\t\t\"a\": \"aa\",\n\t\t\t\t\"map\": map[string]any{\n\t\t\t\t\t\"slice\": []any{\n\t\t\t\t\t\t\"s1\",\n\t\t\t\t\t},\n\t\t\t\t\t\"some\": \"value\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tright: &Unstructured{\n\t\t\t\t\"b\": \"bb\",\n\t\t\t\t\"map\": map[string]any{\n\t\t\t\t\t\"slice\": []any{\n\t\t\t\t\t\t\"s2\",\n\t\t\t\t\t},\n\t\t\t\t\t\"other\": \"thing\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: &Unstructured{\n\t\t\t\t\"a\": \"aa\",\n\t\t\t\t\"b\": \"bb\",\n\t\t\t\t\"map\": map[string]any{\n\t\t\t\t\t\"slice\": []any{\n\t\t\t\t\t\t\"s1\",\n\t\t\t\t\t\t\"s2\",\n\t\t\t\t\t},\n\t\t\t\t\t\"some\":  \"value\",\n\t\t\t\t\t\"other\": \"thing\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"unstructed with nil value\",\n\t\t\tleft: Unstructured{\n\t\t\t\t\"a\": nil,\n\t\t\t\t\"b\": []any{\n\t\t\t\t\t\"c\",\n\t\t\t\t\t\"d\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tright: Unstructured{\n\t\t\t\t\"a\": Unstructured{\n\t\t\t\t\t\"b\": []any{\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t\"d\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: Unstructured{\n\t\t\t\t\"a\": Unstructured{\n\t\t\t\t\t\"b\": []any{\n\t\t\t\t\t\t\"c\",\n\t\t\t\t\t\t\"d\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"b\": []any{\n\t\t\t\t\t\"c\",\n\t\t\t\t\t\"d\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := merge.Merge(tt.left, tt.right)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.expected, tt.left)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/provider.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// Encoder provides the interface to encode configuration documents.\ntype Encoder = config.Encoder\n\n// Validator provides the interface to validate configuration.\ntype Validator = config.Validator\n\n// RuntimeValidator provides the interface to validate configuration in the runtime context.\ntype RuntimeValidator = config.RuntimeValidator\n\n// Container provides the interface to access configuration documents.\n//\n// Container might contain multiple config documents, supporting encoding/decoding,\n// validation, and other operations.\ntype Container interface {\n\tEncoder\n\tValidator\n\tRuntimeValidator\n\n\tReadonly() bool\n\n\t// RawV1Alpha1 returns internal config representation.\n\tRawV1Alpha1() *v1alpha1.Config\n\n\t// Documents returns a list of config documents.\n\t//\n\t// Documents should be not be modified.\n\tDocuments() []config.Document\n}\n\n// Provider defines the configuration consumption interface combining access and encoding/decoding.\ntype Provider interface {\n\tConfig\n\tContainer\n\n\t// Clone returns a copy of the Provider.\n\tClone() Provider\n\n\t// PatchV1Alpha1 patches the container's v1alpha1.Config while preserving other config documents.\n\tPatchV1Alpha1(patcher func(*v1alpha1.Config) error) (Provider, error)\n\n\t// RedactSecrets returns a copy of the Provider with all secrets replaced with the given string.\n\tRedactSecrets(string) Provider\n\n\t// CompleteForBoot return true if the machine config is enough to proceed with the boot process.\n\tCompleteForBoot() bool\n}\n"
  },
  {
    "path": "pkg/machinery/config/schemas/README.md",
    "content": "# Deprecation Notice\n\nThe schema `v1alpha1_config.schema.json` is deprecated, kept only for backward-compatibility.\nPlease use `config.schema.json` instead.\n"
  },
  {
    "path": "pkg/machinery/config/schemas/config.schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://talos.dev/v1.13/schemas/config.schema.json\",\n  \"$defs\": {\n    \"block.DiskSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the disk.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the disk.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"DiskSelector selects a disk for the volume.\"\n    },\n    \"block.EncryptionKey\": {\n      \"properties\": {\n        \"slot\": {\n          \"type\": \"integer\",\n          \"title\": \"slot\",\n          \"description\": \"Key slot number for LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Key slot number for LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey slot number for LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"static\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyStatic\",\n          \"title\": \"static\",\n          \"description\": \"Key which value is stored in the configuration file.\\n\",\n          \"markdownDescription\": \"Key which value is stored in the configuration file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey which value is stored in the configuration file.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeID\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyNodeID\",\n          \"title\": \"nodeID\",\n          \"description\": \"Deterministically generated key from the node UUID and PartitionLabel.\\n\",\n          \"markdownDescription\": \"Deterministically generated key from the node UUID and PartitionLabel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeterministically generated key from the node UUID and PartitionLabel.\\u003c/p\\u003e\\n\"\n        },\n        \"kms\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyKMS\",\n          \"title\": \"kms\",\n          \"description\": \"KMS managed encryption key.\\n\",\n          \"markdownDescription\": \"KMS managed encryption key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS managed encryption key.\\u003c/p\\u003e\\n\"\n        },\n        \"tpm\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyTPM\",\n          \"title\": \"tpm\",\n          \"description\": \"Enable TPM based disk encryption.\\n\",\n          \"markdownDescription\": \"Enable TPM based disk encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable TPM based disk encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"lockToState\": {\n          \"type\": \"boolean\",\n          \"title\": \"lockToState\",\n          \"description\": \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\\n\",\n          \"markdownDescription\": \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKey represents configuration for disk encryption key.\"\n    },\n    \"block.EncryptionKeyKMS\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"KMS endpoint to Seal/Unseal the key.\\n\",\n          \"markdownDescription\": \"KMS endpoint to Seal/Unseal the key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS endpoint to Seal/Unseal the key.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\"\n    },\n    \"block.EncryptionKeyNodeID\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\"\n    },\n    \"block.EncryptionKeyStatic\": {\n      \"properties\": {\n        \"passphrase\": {\n          \"type\": \"string\",\n          \"title\": \"passphrase\",\n          \"description\": \"Defines the static passphrase value.\\n\",\n          \"markdownDescription\": \"Defines the static passphrase value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the static passphrase value.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyStatic represents throw away key type.\"\n    },\n    \"block.EncryptionKeyTPM\": {\n      \"properties\": {\n        \"options\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyTPMOptions\",\n          \"title\": \"options\",\n          \"description\": \"TPM options for key protection.\\n\",\n          \"markdownDescription\": \"TPM options for key protection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTPM options for key protection.\\u003c/p\\u003e\\n\"\n        },\n        \"checkSecurebootStatusOnEnroll\": {\n          \"type\": \"boolean\",\n          \"title\": \"checkSecurebootStatusOnEnroll\",\n          \"description\": \"Check that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\\n\",\n          \"markdownDescription\": \"Check that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCheck that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\"\n    },\n    \"block.EncryptionKeyTPMOptions\": {\n      \"properties\": {\n        \"pcrs\": {\n          \"items\": {\n            \"type\": \"integer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pcrs\",\n          \"description\": \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\\n\",\n          \"markdownDescription\": \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyTPMOptions represents the options for TPM-based key protection.\"\n    },\n    \"block.EncryptionSpec\": {\n      \"properties\": {\n        \"provider\": {\n          \"enum\": [\n            \"luks2\"\n          ],\n          \"title\": \"provider\",\n          \"description\": \"Encryption provider to use for the encryption.\\n\",\n          \"markdownDescription\": \"Encryption provider to use for the encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEncryption provider to use for the encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"keys\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/block.EncryptionKey\"\n          },\n          \"type\": \"array\",\n          \"title\": \"keys\",\n          \"description\": \"Defines the encryption keys generation and storage method.\\n\",\n          \"markdownDescription\": \"Defines the encryption keys generation and storage method.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption keys generation and storage method.\\u003c/p\\u003e\\n\"\n        },\n        \"cipher\": {\n          \"enum\": [\n            \"aes-xts-plain64\",\n            \"xchacha12,aes-adiantum-plain64\",\n            \"xchacha20,aes-adiantum-plain64\"\n          ],\n          \"title\": \"cipher\",\n          \"description\": \"Cipher to use for the encryption. Depends on the encryption provider.\\n\",\n          \"markdownDescription\": \"Cipher to use for the encryption. Depends on the encryption provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCipher to use for the encryption. Depends on the encryption provider.\\u003c/p\\u003e\\n\"\n        },\n        \"keySize\": {\n          \"type\": \"integer\",\n          \"title\": \"keySize\",\n          \"description\": \"Defines the encryption key length.\\n\",\n          \"markdownDescription\": \"Defines the encryption key length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption key length.\\u003c/p\\u003e\\n\"\n        },\n        \"blockSize\": {\n          \"type\": \"integer\",\n          \"title\": \"blockSize\",\n          \"description\": \"Defines the encryption sector size.\\n\",\n          \"markdownDescription\": \"Defines the encryption sector size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption sector size.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"enum\": [\n            \"no_read_workqueue\",\n            \"no_write_workqueue\",\n            \"same_cpu_crypt\"\n          ],\n          \"title\": \"options\",\n          \"description\": \"Additional –perf parameters for the LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Additional --perf parameters for the LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdditional \\u0026ndash;perf parameters for the LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionSpec represents volume encryption settings.\"\n    },\n    \"block.ExistingMountSpec\": {\n      \"properties\": {\n        \"readOnly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readOnly\",\n          \"description\": \"Mount the volume read-only.\\n\",\n          \"markdownDescription\": \"Mount the volume read-only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read-only.\\u003c/p\\u003e\\n\"\n        },\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExistingMountSpec describes how the volume is mounted.\"\n    },\n    \"block.ExistingVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExistingVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/block.VolumeDiscoverySpec\",\n          \"title\": \"discovery\",\n          \"description\": \"The discovery describes how to find a volume.\\n\",\n          \"markdownDescription\": \"The discovery describes how to find a volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe discovery describes how to find a volume.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.ExistingMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ExistingVolumeConfig is an existing volume configuration document.\\\\nExisting volumes allow to mount partitions (or whole disks) that were created\\\\noutside of Talos. Volume will be mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe existing volume config name should not conflict with user volume names.\\\\n\"\n    },\n    \"block.ExternalMountSpec\": {\n      \"properties\": {\n        \"readOnly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readOnly\",\n          \"description\": \"Mount the volume read-only.\\n\",\n          \"markdownDescription\": \"Mount the volume read-only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read-only.\\u003c/p\\u003e\\n\"\n        },\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        },\n        \"virtiofs\": {\n          \"$ref\": \"#/$defs/block.VirtiofsMountSpec\",\n          \"title\": \"virtiofs\",\n          \"description\": \"Virtiofs mount options.\\n\",\n          \"markdownDescription\": \"Virtiofs mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVirtiofs mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExternalMountSpec describes how the external volume is mounted.\"\n    },\n    \"block.ExternalVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExternalVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the mount.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the mount.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the mount.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"filesystemType\": {\n          \"enum\": [\n            \"virtiofs\",\n            \"nfs\"\n          ],\n          \"title\": \"filesystemType\",\n          \"description\": \"Filesystem type.\\n\",\n          \"markdownDescription\": \"Filesystem type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilesystem type.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.ExternalMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ExternalVolumeConfig is an external disk mount configuration document.\\\\nExternal volumes allow to mount volumes that were created outside of Talos,\\\\nover the network or API. Volume will be mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe external volume config name should not conflict with user volume names.\\\\n\"\n    },\n    \"block.FilesystemSpec\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"ext4\",\n            \"xfs\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Filesystem type. Default is xfs.\\n\",\n          \"markdownDescription\": \"Filesystem type. Default is `xfs`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilesystem type. Default is \\u003ccode\\u003exfs\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"projectQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"projectQuotaSupport\",\n          \"description\": \"Enables project quota support, valid only for ‘xfs’ filesystem.\\n\\nNote: changing this value might require a full remount of the filesystem.\\n\",\n          \"markdownDescription\": \"Enables project quota support, valid only for 'xfs' filesystem.\\n\\nNote: changing this value might require a full remount of the filesystem.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables project quota support, valid only for \\u0026lsquo;xfs\\u0026rsquo; filesystem.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: changing this value might require a full remount of the filesystem.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FilesystemSpec configures the filesystem for the volume.\"\n    },\n    \"block.MountSpec\": {\n      \"properties\": {\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MountSpec describes how the volume is mounted.\"\n    },\n    \"block.ProvisioningSpec\": {\n      \"properties\": {\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/block.DiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"The disk selector expression.\\n\",\n          \"markdownDescription\": \"The disk selector expression.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk selector expression.\\u003c/p\\u003e\\n\"\n        },\n        \"grow\": {\n          \"type\": \"boolean\",\n          \"title\": \"grow\",\n          \"description\": \"Should the volume grow to the size of the disk (if possible).\\n\",\n          \"markdownDescription\": \"Should the volume grow to the size of the disk (if possible).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShould the volume grow to the size of the disk (if possible).\\u003c/p\\u003e\\n\"\n        },\n        \"minSize\": {\n          \"type\": \"string\",\n          \"title\": \"minSize\",\n          \"description\": \"The minimum size of the volume.\\n\\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\\n\",\n          \"markdownDescription\": \"The minimum size of the volume.\\n\\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe minimum size of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\\u003c/p\\u003e\\n\"\n        },\n        \"maxSize\": {\n          \"type\": \"string\",\n          \"title\": \"maxSize\",\n          \"description\": \"The maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\n\\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\\n\",\n          \"markdownDescription\": \"The maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\n\\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ProvisioningSpec describes how the volume is provisioned.\"\n    },\n    \"block.RawVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RawVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"RawVolumeConfig is a raw volume configuration document.\\\\nRaw volumes allow to create partitions without formatting them.\\\\n If you want to use local storage, user volumes is a better choice,\\\\n raw volumes are intended to be used with CSI provisioners.\\\\nThe partition label is automatically generated as `r-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.SwapVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"SwapVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"SwapVolumeConfig is a disk swap volume configuration document.\\\\nSwap volume is automatically allocated as a partition on the specified disk\\\\nand activated as swap, removing a swap volume deactivates swap.\\\\nThe partition label is automatically generated as `s-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.UserMountSpec\": {\n      \"properties\": {\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"UserMountSpec describes how the volume is mounted.\"\n    },\n    \"block.UserVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"UserVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"volumeType\": {\n          \"enum\": [\n            \"directory\",\n            \"disk\",\n            \"partition\"\n          ],\n          \"title\": \"volumeType\",\n          \"description\": \"Volume type.\\n\",\n          \"markdownDescription\": \"Volume type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVolume type.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"filesystem\": {\n          \"$ref\": \"#/$defs/block.FilesystemSpec\",\n          \"title\": \"filesystem\",\n          \"description\": \"The filesystem describes how the volume is formatted.\\n\",\n          \"markdownDescription\": \"The filesystem describes how the volume is formatted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe filesystem describes how the volume is formatted.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.UserMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"UserVolumeConfig is a user volume configuration document.\\\\nUser volume is automatically allocated as a partition on the specified disk\\\\nand mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe partition label is automatically generated as `u-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.VirtiofsMountSpec\": {\n      \"properties\": {\n        \"tag\": {\n          \"type\": \"string\",\n          \"title\": \"tag\",\n          \"description\": \"Selector tag for the Virtiofs mount.\\n\",\n          \"markdownDescription\": \"Selector tag for the Virtiofs mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelector tag for the Virtiofs mount.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VirtiofsMountSpec describes Virtiofs mount options.\"\n    },\n    \"block.VolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\",\n          \"markdownDescription\": \"Name of the volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.MountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"VolumeConfig is a system volume configuration document.\\\\nNote: at the moment, only `STATE`, `EPHEMERAL` and `IMAGE-CACHE` system volumes are supported.\\\\n\"\n    },\n    \"block.VolumeDiscoverySpec\": {\n      \"properties\": {\n        \"volumeSelector\": {\n          \"$ref\": \"#/$defs/block.VolumeSelector\",\n          \"title\": \"volumeSelector\",\n          \"description\": \"The volume selector expression.\\n\",\n          \"markdownDescription\": \"The volume selector expression.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe volume selector expression.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeDiscoverySpec describes how the volume is discovered.\"\n    },\n    \"block.VolumeSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the volume.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the volume.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeSelector selects an existing volume.\"\n    },\n    \"block.ZswapConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ZswapConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"maxPoolPercent\": {\n          \"type\": \"integer\",\n          \"title\": \"maxPoolPercent\",\n          \"description\": \"The maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\\n\",\n          \"markdownDescription\": \"The maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\\u003c/p\\u003e\\n\"\n        },\n        \"shrinkerEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"shrinkerEnabled\",\n          \"description\": \"Enable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\\n\",\n          \"markdownDescription\": \"Enable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ZswapConfig is a zswap (compressed memory) configuration document.\\\\nWhen zswap is enabled, Linux kernel compresses pages that would otherwise be swapped out to disk.\\\\nThe compressed pages are stored in a memory pool, which is used to avoid writing to disk\\\\nwhen the system is under memory pressure.\\\\n\"\n    },\n    \"cri.RegistryAuthConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryAuthConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry endpoint to apply the authentication configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. ‘my-mirror.local:5000’ for ‘https://my-mirror.local:5000/v2/’.\\n\\nThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\n\",\n          \"markdownDescription\": \"Registry endpoint to apply the authentication configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry endpoint to apply the authentication configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. \\u0026lsquo;my-mirror.local:5000\\u0026rsquo; for \\u0026lsquo;\\u003ca href=\\\"https://my-mirror.local:5000/v2/'\\\" target=\\\"_blank\\\"\\u003ehttps://my-mirror.local:5000/v2/\\u0026rsquo;\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\u003c/p\\u003e\\n\"\n        },\n        \"username\": {\n          \"type\": \"string\",\n          \"title\": \"username\",\n          \"description\": \"Username/password authentication.\\n\",\n          \"markdownDescription\": \"Username/password authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsername/password authentication.\\u003c/p\\u003e\\n\"\n        },\n        \"password\": {\n          \"type\": \"string\",\n          \"title\": \"password\",\n          \"description\": \"Username/password authentication.\\n\",\n          \"markdownDescription\": \"Username/password authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsername/password authentication.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"type\": \"string\",\n          \"title\": \"auth\",\n          \"description\": \"Raw authentication string.\\n\",\n          \"markdownDescription\": \"Raw authentication string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw authentication string.\\u003c/p\\u003e\\n\"\n        },\n        \"identityToken\": {\n          \"type\": \"string\",\n          \"title\": \"identityToken\",\n          \"description\": \"Identity token authentication.\\n\",\n          \"markdownDescription\": \"Identity token authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIdentity token authentication.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryAuthConfig configures authentication for a registry endpoint.\"\n    },\n    \"cri.RegistryEndpoint\": {\n      \"properties\": {\n        \"url\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(http|https)://\",\n          \"title\": \"url\",\n          \"description\": \"The URL of the registry mirror endpoint.\\n\",\n          \"markdownDescription\": \"The URL of the registry mirror endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe URL of the registry mirror endpoint.\\u003c/p\\u003e\\n\"\n        },\n        \"overridePath\": {\n          \"type\": \"boolean\",\n          \"title\": \"overridePath\",\n          \"description\": \"Use endpoint path as supplied, without adding /v2/ suffix.\\n\",\n          \"markdownDescription\": \"Use endpoint path as supplied, without adding `/v2/` suffix.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse endpoint path as supplied, without adding \\u003ccode\\u003e/v2/\\u003c/code\\u003e suffix.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"url\"\n      ],\n      \"description\": \"RegistryEndpoint defines a registry mirror endpoint.\"\n    },\n    \"cri.RegistryMirrorConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryMirrorConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry name to apply the mirror configuration to.\\n\\nRegistry name is the first segment of image identifier, with ‘docker.io’\\nbeing default one.\\n\\nA special name ‘*’ can be used to define mirror configuration\\nthat applies to all registries.\\n\",\n          \"markdownDescription\": \"Registry name to apply the mirror configuration to.\\n\\nRegistry name is the first segment of image identifier, with 'docker.io'\\nbeing default one.\\n\\nA special name '*' can be used to define mirror configuration\\nthat applies to all registries.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry name to apply the mirror configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry name is the first segment of image identifier, with \\u0026lsquo;docker.io\\u0026rsquo;\\nbeing default one.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eA special name \\u0026lsquo;*\\u0026rsquo; can be used to define mirror configuration\\nthat applies to all registries.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoints\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/cri.RegistryEndpoint\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"List of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is skipFallback is not set to true.\\n\",\n          \"markdownDescription\": \"List of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is `skipFallback` is not set to true.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is \\u003ccode\\u003eskipFallback\\u003c/code\\u003e is not set to true.\\u003c/p\\u003e\\n\"\n        },\n        \"skipFallback\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipFallback\",\n          \"description\": \"Skip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\\n\",\n          \"markdownDescription\": \"Skip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryMirrorConfig configures an image registry mirror.\"\n    },\n    \"cri.RegistryTLSConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryTLSConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry endpoint to apply the TLS configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. ‘my-mirror.local:5000’ for ‘https://my-mirror.local:5000/v2/’.\\n\\nThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\n\",\n          \"markdownDescription\": \"Registry endpoint to apply the TLS configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry endpoint to apply the TLS configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. \\u0026lsquo;my-mirror.local:5000\\u0026rsquo; for \\u0026lsquo;\\u003ca href=\\\"https://my-mirror.local:5000/v2/'\\\" target=\\\"_blank\\\"\\u003ehttps://my-mirror.local:5000/v2/\\u0026rsquo;\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentity\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"clientIdentity\",\n          \"description\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\\n\",\n          \"markdownDescription\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"type\": \"string\",\n          \"title\": \"ca\",\n          \"description\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\\n\",\n          \"markdownDescription\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"insecureSkipVerify\": {\n          \"type\": \"boolean\",\n          \"title\": \"insecureSkipVerify\",\n          \"description\": \"Skip TLS server certificate verification (not recommended).\\n\",\n          \"markdownDescription\": \"Skip TLS server certificate verification (not recommended).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip TLS server certificate verification (not recommended).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryTLSConfig configures TLS for a registry endpoint.\"\n    },\n    \"extensions.ConfigFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The content of the extension service config file.\\n\",\n          \"markdownDescription\": \"The content of the extension service config file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe content of the extension service config file.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"The mount path of the extension service config file.\\n\",\n          \"markdownDescription\": \"The mount path of the extension service config file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount path of the extension service config file.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ConfigFile is a config file for extension services.\"\n    },\n    \"extensions.ServiceConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExtensionServiceConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the extension service.\\n\",\n          \"markdownDescription\": \"Name of the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the extension service.\\u003c/p\\u003e\\n\"\n        },\n        \"configFiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/extensions.ConfigFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"configFiles\",\n          \"description\": \"The config files for the extension service.\\n\",\n          \"markdownDescription\": \"The config files for the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe config files for the extension service.\\u003c/p\\u003e\\n\"\n        },\n        \"environment\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"environment\",\n          \"description\": \"The environment for the extension service.\\n\",\n          \"markdownDescription\": \"The environment for the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe environment for the extension service.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"ExtensionServiceConfig is a extensionserviceconfig document.\"\n    },\n    \"hardware.PCIDriverRebindConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"PCIDriverRebindConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"PCI device id\\n\",\n          \"markdownDescription\": \"PCI device id\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI device id\\u003c/p\\u003e\\n\"\n        },\n        \"targetDriver\": {\n          \"type\": \"string\",\n          \"title\": \"targetDriver\",\n          \"description\": \"Target driver to rebind the PCI device to.\\n\",\n          \"markdownDescription\": \"Target driver to rebind the PCI device to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTarget driver to rebind the PCI device to.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"targetDriver\"\n      ],\n      \"description\": \"PCIDriverRebindConfig allows to configure PCI driver rebinds.\"\n    },\n    \"network.AddressConfig\": {\n      \"properties\": {\n        \"address\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"address\",\n          \"description\": \"IP address to be assigned to the link.\\n\\nThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\\n\",\n          \"markdownDescription\": \"IP address to be assigned to the link.\\n\\nThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be assigned to the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\\u003c/p\\u003e\\n\"\n        },\n        \"routePriority\": {\n          \"type\": \"integer\",\n          \"title\": \"routePriority\",\n          \"description\": \"Configure the route priority (metric) for routes created for this address.\\n\\nIf not specified, the system default route priority will be used.\\n\",\n          \"markdownDescription\": \"Configure the route priority (metric) for routes created for this address.\\n\\nIf not specified, the system default route priority will be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the route priority (metric) for routes created for this address.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default route priority will be used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"address\"\n      ],\n      \"description\": \"AddressConfig represents a network address configuration.\"\n    },\n    \"network.BlackholeRouteConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BlackholeRouteConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Route destination as an address prefix.\\n\",\n          \"markdownDescription\": \"Route destination as an address prefix.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRoute destination as an address prefix.\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"BlackholeRouteConfig is a config document to configure blackhole routes.\"\n    },\n    \"network.BondConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BondConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the bond link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the bond link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the bond link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"bondMode\": {\n          \"enum\": [\n            \"balance-rr\",\n            \"active-backup\",\n            \"balance-xor\",\n            \"broadcast\",\n            \"802.3ad\",\n            \"balance-tlb\",\n            \"balance-alb\"\n          ],\n          \"title\": \"bondMode\",\n          \"description\": \"Bond mode.\\n\",\n          \"markdownDescription\": \"Bond mode.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBond mode.\\u003c/p\\u003e\\n\"\n        },\n        \"miimon\": {\n          \"type\": \"integer\",\n          \"title\": \"miimon\",\n          \"description\": \"Link monitoring frequency in milliseconds.\\n\",\n          \"markdownDescription\": \"Link monitoring frequency in milliseconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLink monitoring frequency in milliseconds.\\u003c/p\\u003e\\n\"\n        },\n        \"updelay\": {\n          \"type\": \"integer\",\n          \"title\": \"updelay\",\n          \"description\": \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\\n\",\n          \"markdownDescription\": \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\\u003c/p\\u003e\\n\"\n        },\n        \"downdelay\": {\n          \"type\": \"integer\",\n          \"title\": \"downdelay\",\n          \"description\": \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\\n\",\n          \"markdownDescription\": \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\\u003c/p\\u003e\\n\"\n        },\n        \"useCarrier\": {\n          \"type\": \"boolean\",\n          \"title\": \"useCarrier\",\n          \"description\": \"Specifies whether or not miimon should use MII or ETHTOOL.\\n\",\n          \"markdownDescription\": \"Specifies whether or not miimon should use MII or ETHTOOL.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether or not miimon should use MII or ETHTOOL.\\u003c/p\\u003e\\n\"\n        },\n        \"xmitHashPolicy\": {\n          \"enum\": [\n            \"layer2\",\n            \"layer3+4\",\n            \"layer2+3\",\n            \"encap2+3\",\n            \"encap3+4\"\n          ],\n          \"title\": \"xmitHashPolicy\",\n          \"description\": \"Selects the transmit hash policy to use for slave selection.\\n\",\n          \"markdownDescription\": \"Selects the transmit hash policy to use for slave selection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelects the transmit hash policy to use for slave selection.\\u003c/p\\u003e\\n\"\n        },\n        \"arpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"arpInterval\",\n          \"description\": \"ARP link monitoring frequency in milliseconds.\\n\",\n          \"markdownDescription\": \"ARP link monitoring frequency in milliseconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eARP link monitoring frequency in milliseconds.\\u003c/p\\u003e\\n\"\n        },\n        \"arpIpTargets\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"arpIpTargets\",\n          \"description\": \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\n\",\n          \"markdownDescription\": \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\u003c/p\\u003e\\n\"\n        },\n        \"nsIp6Targets\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nsIp6Targets\",\n          \"description\": \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\n\",\n          \"markdownDescription\": \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\u003c/p\\u003e\\n\"\n        },\n        \"arpValidate\": {\n          \"enum\": [\n            \"none\",\n            \"active\",\n            \"backup\",\n            \"all\",\n            \"filter\",\n            \"filter-active\",\n            \"filter-backup\"\n          ],\n          \"title\": \"arpValidate\",\n          \"description\": \"Specifies whether or not ARP probes and replies should be validated.\\n\",\n          \"markdownDescription\": \"Specifies whether or not ARP probes and replies should be validated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether or not ARP probes and replies should be validated.\\u003c/p\\u003e\\n\"\n        },\n        \"arpAllTargets\": {\n          \"enum\": [\n            \"any\",\n            \"all\"\n          ],\n          \"title\": \"arpAllTargets\",\n          \"description\": \"Specifies whether ARP probes should be sent to any or all targets.\\n\",\n          \"markdownDescription\": \"Specifies whether ARP probes should be sent to any or all targets.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether ARP probes should be sent to any or all targets.\\u003c/p\\u003e\\n\"\n        },\n        \"lacpRate\": {\n          \"enum\": [\n            \"slow\",\n            \"fast\"\n          ],\n          \"title\": \"lacpRate\",\n          \"description\": \"LACPDU frames periodic transmission rate.\\n\",\n          \"markdownDescription\": \"LACPDU frames periodic transmission rate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLACPDU frames periodic transmission rate.\\u003c/p\\u003e\\n\"\n        },\n        \"failOverMac\": {\n          \"enum\": [\n            \"none\",\n            \"active\",\n            \"follow\"\n          ],\n          \"title\": \"failOverMac\",\n          \"description\": \"Specifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\\n\",\n          \"markdownDescription\": \"Specifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\\u003c/p\\u003e\\n\"\n        },\n        \"adSelect\": {\n          \"enum\": [\n            \"stable\",\n            \"bandwidth\",\n            \"count\"\n          ],\n          \"title\": \"adSelect\",\n          \"description\": \"Aggregate selection policy for 802.3ad.\\n\",\n          \"markdownDescription\": \"Aggregate selection policy for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAggregate selection policy for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSysPrio\": {\n          \"type\": \"integer\",\n          \"title\": \"adActorSysPrio\",\n          \"description\": \"Actor system priority for 802.3ad.\\n\",\n          \"markdownDescription\": \"Actor system priority for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eActor system priority for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adUserPortKey\": {\n          \"type\": \"integer\",\n          \"title\": \"adUserPortKey\",\n          \"description\": \"User port key (upper 10 bits) for 802.3ad.\\n\",\n          \"markdownDescription\": \"User port key (upper 10 bits) for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUser port key (upper 10 bits) for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adLACPActive\": {\n          \"enum\": [\n            \"on\",\n            \"off\"\n          ],\n          \"title\": \"adLACPActive\",\n          \"description\": \"Whether to send LACPDU frames periodically.\\n\",\n          \"markdownDescription\": \"Whether to send LACPDU frames periodically.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether to send LACPDU frames periodically.\\u003c/p\\u003e\\n\"\n        },\n        \"primaryReselect\": {\n          \"enum\": [\n            \"always\",\n            \"better\",\n            \"failure\"\n          ],\n          \"title\": \"primaryReselect\",\n          \"description\": \"Policy under which the primary slave should be reselected.\\n\",\n          \"markdownDescription\": \"Policy under which the primary slave should be reselected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePolicy under which the primary slave should be reselected.\\u003c/p\\u003e\\n\"\n        },\n        \"resendIGMP\": {\n          \"type\": \"integer\",\n          \"title\": \"resendIGMP\",\n          \"description\": \"The number of times IGMP packets should be resent.\\n\",\n          \"markdownDescription\": \"The number of times IGMP packets should be resent.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of times IGMP packets should be resent.\\u003c/p\\u003e\\n\"\n        },\n        \"minLinks\": {\n          \"type\": \"integer\",\n          \"title\": \"minLinks\",\n          \"description\": \"The minimum number of active links required for the bond to be considered active.\\n\",\n          \"markdownDescription\": \"The minimum number of active links required for the bond to be considered active.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe minimum number of active links required for the bond to be considered active.\\u003c/p\\u003e\\n\"\n        },\n        \"lpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"lpInterval\",\n          \"description\": \"The number of seconds between instances where the bonding driver sends learning packets to each slave’s peer switch.\\n\",\n          \"markdownDescription\": \"The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of seconds between instances where the bonding driver sends learning packets to each slave\\u0026rsquo;s peer switch.\\u003c/p\\u003e\\n\"\n        },\n        \"packetsPerSlave\": {\n          \"type\": \"integer\",\n          \"title\": \"packetsPerSlave\",\n          \"description\": \"The number of packets to transmit through a slave before moving to the next one.\\n\",\n          \"markdownDescription\": \"The number of packets to transmit through a slave before moving to the next one.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of packets to transmit through a slave before moving to the next one.\\u003c/p\\u003e\\n\"\n        },\n        \"numPeerNotif\": {\n          \"type\": \"integer\",\n          \"title\": \"numPeerNotif\",\n          \"description\": \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\\n\",\n          \"markdownDescription\": \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\\u003c/p\\u003e\\n\"\n        },\n        \"tlbLogicalLb\": {\n          \"type\": \"integer\",\n          \"title\": \"tlbLogicalLb\",\n          \"description\": \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\\n\",\n          \"markdownDescription\": \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether dynamic shuffling of flows is enabled in tlb or alb mode.\\u003c/p\\u003e\\n\"\n        },\n        \"allSlavesActive\": {\n          \"type\": \"integer\",\n          \"title\": \"allSlavesActive\",\n          \"description\": \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\\n\",\n          \"markdownDescription\": \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\\u003c/p\\u003e\\n\"\n        },\n        \"peerNotifDelay\": {\n          \"type\": \"integer\",\n          \"title\": \"peerNotifDelay\",\n          \"description\": \"The delay, in milliseconds, between each peer notification.\\n\",\n          \"markdownDescription\": \"The delay, in milliseconds, between each peer notification.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe delay, in milliseconds, between each peer notification.\\u003c/p\\u003e\\n\"\n        },\n        \"missedMax\": {\n          \"type\": \"integer\",\n          \"title\": \"missedMax\",\n          \"description\": \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\\n\",\n          \"markdownDescription\": \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"bondMode\",\n        \"kind\",\n        \"links\",\n        \"name\"\n      ],\n      \"description\": \"BondConfig is a config document to create a bond (link aggregation) over a set of links.\"\n    },\n    \"network.BridgeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BridgeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the bridge link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the bridge link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the bridge link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"stp\": {\n          \"$ref\": \"#/$defs/network.BridgeSTPConfig\",\n          \"title\": \"stp\",\n          \"description\": \"Bridge STP (Spanning Tree Protocol) configuration.\\n\",\n          \"markdownDescription\": \"Bridge STP (Spanning Tree Protocol) configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge STP (Spanning Tree Protocol) configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"vlan\": {\n          \"$ref\": \"#/$defs/network.BridgeVLANConfig\",\n          \"title\": \"vlan\",\n          \"description\": \"Bridge VLAN configuration.\\n\",\n          \"markdownDescription\": \"Bridge VLAN configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge VLAN configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"links\",\n        \"name\"\n      ],\n      \"description\": \"BridgeConfig is a config document to create a Bridge (link aggregation) over a set of links.\"\n    },\n    \"network.BridgeSTPConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable or disable STP on the bridge.\\n\",\n          \"markdownDescription\": \"Enable or disable STP on the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable or disable STP on the bridge.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\"\n    },\n    \"network.BridgeVLANConfig\": {\n      \"properties\": {\n        \"filtering\": {\n          \"type\": \"boolean\",\n          \"title\": \"filtering\",\n          \"description\": \"Enable or disable VLAN filtering on the bridge.\\n\",\n          \"markdownDescription\": \"Enable or disable VLAN filtering on the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable or disable VLAN filtering on the bridge.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"BridgeVLANConfig is a bridge VLAN configuration.\"\n    },\n    \"network.CommonLinkConfig\": {\n      \"properties\": {\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CommonLinkConfig is common configuration for network links, and logical links.\"\n    },\n    \"network.CommonProbeConfig\": {\n      \"properties\": {\n        \"interval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"interval\",\n          \"description\": \"Interval between probe attempts.\\nDefaults to 1s.\\n\",\n          \"markdownDescription\": \"Interval between probe attempts.\\nDefaults to 1s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eInterval between probe attempts.\\nDefaults to 1s.\\u003c/p\\u003e\\n\"\n        },\n        \"failureThreshold\": {\n          \"type\": \"integer\",\n          \"title\": \"failureThreshold\",\n          \"description\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\n\",\n          \"markdownDescription\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CommonProbeConfig holds fields common to all probe types.\"\n    },\n    \"network.DHCPv4ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DHCPv4Config\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\\n\",\n          \"markdownDescription\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAn optional metric for the routes received from the DHCP server.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eLower values indicate higher priority.\\nDefault value is 1024.\\u003c/p\\u003e\\n\"\n        },\n        \"ignoreHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignoreHostname\",\n          \"description\": \"Ignore hostname received from the DHCP server.\\n\",\n          \"markdownDescription\": \"Ignore hostname received from the DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIgnore hostname received from the DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentifier\": {\n          \"enum\": [\n            \"none\",\n            \"mac\",\n            \"duid\"\n          ],\n          \"title\": \"clientIdentifier\",\n          \"description\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to ‘mac’ if not set.\\n\",\n          \"markdownDescription\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eClient identifier to use when communicating with DHCP servers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to \\u0026lsquo;mac\\u0026rsquo; if not set.\\u003c/p\\u003e\\n\"\n        },\n        \"duidRaw\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\",\n          \"title\": \"duidRaw\",\n          \"description\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if ‘clientIdentifier’ is set to ‘duid’.\\n\",\n          \"markdownDescription\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw value of the DUID to use as client identifier.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field is only used if \\u0026lsquo;clientIdentifier\\u0026rsquo; is set to \\u0026lsquo;duid\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DHCPv4Config is a config document to configure DHCPv4 on a network link.\"\n    },\n    \"network.DHCPv6ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DHCPv6Config\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\\n\",\n          \"markdownDescription\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAn optional metric for the routes received from the DHCP server.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eLower values indicate higher priority.\\nDefault value is 1024.\\u003c/p\\u003e\\n\"\n        },\n        \"ignoreHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignoreHostname\",\n          \"description\": \"Ignore hostname received from the DHCP server.\\n\",\n          \"markdownDescription\": \"Ignore hostname received from the DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIgnore hostname received from the DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentifier\": {\n          \"enum\": [\n            \"none\",\n            \"mac\",\n            \"duid\"\n          ],\n          \"title\": \"clientIdentifier\",\n          \"description\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to ‘mac’ if not set.\\n\",\n          \"markdownDescription\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eClient identifier to use when communicating with DHCP servers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to \\u0026lsquo;mac\\u0026rsquo; if not set.\\u003c/p\\u003e\\n\"\n        },\n        \"duidRaw\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\",\n          \"title\": \"duidRaw\",\n          \"description\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if ‘clientIdentifier’ is set to ‘duid’.\\n\",\n          \"markdownDescription\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw value of the DUID to use as client identifier.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field is only used if \\u0026lsquo;clientIdentifier\\u0026rsquo; is set to \\u0026lsquo;duid\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DHCPv6Config is a config document to configure DHCPv6 on a network link.\"\n    },\n    \"network.DefaultActionConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"NetworkDefaultActionConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"ingress\": {\n          \"enum\": [\n            \"accept\",\n            \"block\"\n          ],\n          \"title\": \"ingress\",\n          \"description\": \"Default action for all not explicitly configured ingress traffic: accept or block.\\n\",\n          \"markdownDescription\": \"Default action for all not explicitly configured ingress traffic: accept or block.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefault action for all not explicitly configured ingress traffic: accept or block.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"NetworkDefaultActionConfig is a ingress firewall default action configuration document.\"\n    },\n    \"network.DummyLinkConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DummyLinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the dummy link (interface).\\n\",\n          \"markdownDescription\": \"Name of the dummy link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the dummy link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DummyLinkConfig is a config document to create a dummy (virtual) network link.\"\n    },\n    \"network.EthernetChannelsConfig\": {\n      \"properties\": {\n        \"rx\": {\n          \"type\": \"integer\",\n          \"title\": \"rx\",\n          \"description\": \"Number of RX channels.\\n\",\n          \"markdownDescription\": \"Number of RX channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX channels.\\u003c/p\\u003e\\n\"\n        },\n        \"tx\": {\n          \"type\": \"integer\",\n          \"title\": \"tx\",\n          \"description\": \"Number of TX channels.\\n\",\n          \"markdownDescription\": \"Number of TX channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of TX channels.\\u003c/p\\u003e\\n\"\n        },\n        \"other\": {\n          \"type\": \"integer\",\n          \"title\": \"other\",\n          \"description\": \"Number of other channels.\\n\",\n          \"markdownDescription\": \"Number of other channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of other channels.\\u003c/p\\u003e\\n\"\n        },\n        \"combined\": {\n          \"type\": \"integer\",\n          \"title\": \"combined\",\n          \"description\": \"Number of combined channels.\\n\",\n          \"markdownDescription\": \"Number of combined channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of combined channels.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EthernetChannelsConfig is a configuration for Ethernet link channels.\"\n    },\n    \"network.EthernetConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EthernetConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"boolean\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"features\",\n          \"description\": \"Configuration for Ethernet features.\\n\\nSet of features available and whether they can be enabled or disabled is driver specific.\\nUse talosctl get ethernetstatus \\u0026lt;link\\u0026gt; -o yaml to get the list of available features and\\ntheir current status.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet features.\\n\\nSet of features available and whether they can be enabled or disabled is driver specific.\\nUse `talosctl get ethernetstatus \\u003clink\\u003e -o yaml` to get the list of available features and\\ntheir current status.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet features.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSet of features available and whether they can be enabled or disabled is driver specific.\\nUse \\u003ccode\\u003etalosctl get ethernetstatus \\u0026lt;link\\u0026gt; -o yaml\\u003c/code\\u003e to get the list of available features and\\ntheir current status.\\u003c/p\\u003e\\n\"\n        },\n        \"rings\": {\n          \"$ref\": \"#/$defs/network.EthernetRingsConfig\",\n          \"title\": \"rings\",\n          \"description\": \"Configuration for Ethernet link rings.\\n\\nThis is similar to ethtool -G command.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet link rings.\\n\\nThis is similar to `ethtool -G` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet link rings.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -G\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        },\n        \"channels\": {\n          \"$ref\": \"#/$defs/network.EthernetChannelsConfig\",\n          \"title\": \"channels\",\n          \"description\": \"Configuration for Ethernet link channels.\\n\\nThis is similar to ethtool -L command.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet link channels.\\n\\nThis is similar to `ethtool -L` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet link channels.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -L\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        },\n        \"wakeOnLan\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"wakeOnLan\",\n          \"description\": \"Wake-on-LAN modes to enable.\\n\\nIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\n\\nThis is similar to ethtool -s \\u0026lt;link\\u0026gt; wol \\u0026lt;options\\u0026gt; command.\\n\",\n          \"markdownDescription\": \"Wake-on-LAN modes to enable.\\n\\nIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\n\\nThis is similar to `ethtool -s \\u003clink\\u003e wol \\u003coptions\\u003e` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWake-on-LAN modes to enable.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -s \\u0026lt;link\\u0026gt; wol \\u0026lt;options\\u0026gt;\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"EthernetConfig is a config document to configure Ethernet interfaces.\"\n    },\n    \"network.EthernetRingsConfig\": {\n      \"properties\": {\n        \"rx\": {\n          \"type\": \"integer\",\n          \"title\": \"rx\",\n          \"description\": \"Number of RX rings.\\n\",\n          \"markdownDescription\": \"Number of RX rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX rings.\\u003c/p\\u003e\\n\"\n        },\n        \"tx\": {\n          \"type\": \"integer\",\n          \"title\": \"tx\",\n          \"description\": \"Number of TX rings.\\n\",\n          \"markdownDescription\": \"Number of TX rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of TX rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-mini\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-mini\",\n          \"description\": \"Number of RX mini rings.\\n\",\n          \"markdownDescription\": \"Number of RX mini rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX mini rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-jumbo\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-jumbo\",\n          \"description\": \"Number of RX jumbo rings.\\n\",\n          \"markdownDescription\": \"Number of RX jumbo rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX jumbo rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-buf-len\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-buf-len\",\n          \"description\": \"RX buffer length.\\n\",\n          \"markdownDescription\": \"RX buffer length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRX buffer length.\\u003c/p\\u003e\\n\"\n        },\n        \"cqe-size\": {\n          \"type\": \"integer\",\n          \"title\": \"cqe-size\",\n          \"description\": \"CQE size.\\n\",\n          \"markdownDescription\": \"CQE size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCQE size.\\u003c/p\\u003e\\n\"\n        },\n        \"tx-push\": {\n          \"type\": \"boolean\",\n          \"title\": \"tx-push\",\n          \"description\": \"TX push enabled.\\n\",\n          \"markdownDescription\": \"TX push enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTX push enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-push\": {\n          \"type\": \"boolean\",\n          \"title\": \"rx-push\",\n          \"description\": \"RX push enabled.\\n\",\n          \"markdownDescription\": \"RX push enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRX push enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"tx-push-buf-len\": {\n          \"type\": \"integer\",\n          \"title\": \"tx-push-buf-len\",\n          \"description\": \"TX push buffer length.\\n\",\n          \"markdownDescription\": \"TX push buffer length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTX push buffer length.\\u003c/p\\u003e\\n\"\n        },\n        \"tcp-data-split\": {\n          \"type\": \"boolean\",\n          \"title\": \"tcp-data-split\",\n          \"description\": \"TCP data split enabled.\\n\",\n          \"markdownDescription\": \"TCP data split enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTCP data split enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EthernetRingsConfig is a configuration for Ethernet link rings.\"\n    },\n    \"network.HCloudVIPConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"HCloudVIPConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address to be advertised as a Layer 2 VIP.\\n\",\n          \"markdownDescription\": \"IP address to be advertised as a Layer 2 VIP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be advertised as a Layer 2 VIP.\\u003c/p\\u003e\\n\"\n        },\n        \"link\": {\n          \"type\": \"string\",\n          \"title\": \"link\",\n          \"description\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link to assign the VIP to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        },\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Hetzner Cloud API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"HCloudVIPConfig is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\\\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\\\nAny other use cases are not supported and may lead to unexpected behavior.\\\\nVirtual IP will be announced from only one node at a time using Hetzner Cloud APIs.\\\\n\"\n    },\n    \"network.HostnameConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"HostnameConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"auto\": {\n          \"enum\": [\n            \"stable\",\n            \"off\"\n          ],\n          \"title\": \"auto\",\n          \"description\": \"A method to automatically generate a hostname for the machine.\\n\\nThere are two methods available:\\n  - stable - generates a stable hostname based on machine identity\\n  - off - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\n\\nAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with hostname field.\\n\",\n          \"markdownDescription\": \"A method to automatically generate a hostname for the machine.\\n\\nThere are two methods available:\\n  - `stable` - generates a stable hostname based on machine identity\\n  - `off` - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\n\\nAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `hostname` field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA method to automatically generate a hostname for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThere are two methods available:\\n  - \\u003ccode\\u003estable\\u003c/code\\u003e - generates a stable hostname based on machine identity\\n  - \\u003ccode\\u003eoff\\u003c/code\\u003e - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with \\u003ccode\\u003ehostname\\u003c/code\\u003e field.\\u003c/p\\u003e\\n\"\n        },\n        \"hostname\": {\n          \"type\": \"string\",\n          \"title\": \"hostname\",\n          \"description\": \"A static hostname to set for the machine.\\n\\nThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with auto field.\\n\",\n          \"markdownDescription\": \"A static hostname to set for the machine.\\n\\nThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `auto` field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA static hostname to set for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with \\u003ccode\\u003eauto\\u003c/code\\u003e field.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"HostnameConfig is a config document to configure the hostname: either a static hostname or an automatically generated hostname.\"\n    },\n    \"network.IngressRule\": {\n      \"properties\": {\n        \"subnet\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"subnet\",\n          \"description\": \"Subnet defines a source subnet.\\n\",\n          \"markdownDescription\": \"Subnet defines a source subnet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSubnet defines a source subnet.\\u003c/p\\u003e\\n\"\n        },\n        \"except\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"except\",\n          \"description\": \"Except defines a source subnet to exclude from the rule, it gets excluded from the subnet.\\n\",\n          \"markdownDescription\": \"Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExcept defines a source subnet to exclude from the rule, it gets excluded from the \\u003ccode\\u003esubnet\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"IngressRule is a ingress rule.\"\n    },\n    \"network.KubeSpanConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KubeSpanConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\\n\",\n          \"markdownDescription\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"advertiseKubernetesNetworks\": {\n          \"type\": \"boolean\",\n          \"title\": \"advertiseKubernetesNetworks\",\n          \"description\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\\n\",\n          \"markdownDescription\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eControl whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\\u003c/p\\u003e\\n\"\n        },\n        \"allowDownPeerBypass\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowDownPeerBypass\",\n          \"description\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\\n\",\n          \"markdownDescription\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\\u003c/p\\u003e\\n\"\n        },\n        \"harvestExtraEndpoints\": {\n          \"type\": \"boolean\",\n          \"title\": \"harvestExtraEndpoints\",\n          \"description\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u0026gt;50).\\n\",\n          \"markdownDescription\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u003e50).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u0026gt;50).\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"KubeSpan link MTU size.\\nDefault value is 1420.\\n\",\n          \"markdownDescription\": \"KubeSpan link MTU size.\\nDefault value is 1420.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan link MTU size.\\nDefault value is 1420.\\u003c/p\\u003e\\n\"\n        },\n        \"filters\": {\n          \"$ref\": \"#/$defs/network.KubeSpanFiltersConfig\",\n          \"title\": \"filters\",\n          \"description\": \"KubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\\n\",\n          \"markdownDescription\": \"KubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KubeSpanConfig is a config document to configure KubeSpan.\"\n    },\n    \"network.KubeSpanFiltersConfig\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        },\n        \"excludeAdvertisedNetworks\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"excludeAdvertisedNetworks\",\n          \"description\": \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\n\\nBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\n\\nNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\n\\nBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\n\\nNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeSpanFiltersConfig configures KubeSpan endpoint filters.\"\n    },\n    \"network.KubespanEndpointsConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KubeSpanEndpoints\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"extraAnnouncedEndpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraAnnouncedEndpoints\",\n          \"description\": \"A list of extra Wireguard endpoints to announce from this machine.\\n\\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\\n\",\n          \"markdownDescription\": \"A list of extra Wireguard endpoints to announce from this machine.\\n\\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of extra Wireguard endpoints to announce from this machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KubeSpanEndpointsConfig is a config document to configure KubeSpan endpoints.\"\n    },\n    \"network.Layer2VIPConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"Layer2VIPConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address to be advertised as a Layer 2 VIP.\\n\",\n          \"markdownDescription\": \"IP address to be advertised as a Layer 2 VIP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be advertised as a Layer 2 VIP.\\u003c/p\\u003e\\n\"\n        },\n        \"link\": {\n          \"type\": \"string\",\n          \"title\": \"link\",\n          \"description\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link to assign the VIP to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"Layer2VIPConfig is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\\\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\\\nAny other use cases are not supported and may lead to unexpected behavior.\\\\nVirtual IP will be announced from only one node at a time using gratuitous ARP announcements for IPv4.\\\\n\"\n    },\n    \"network.LinkAliasConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"LinkAliasConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Alias for the link.\\n\\nDon’t use system interface names like “eth0”, “ens3”, “enp0s2”, etc. as those may conflict\\nwith existing physical interfaces.\\n\\nThe name can contain a single integer format verb (%d) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. net0, net1, …) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\\n\",\n          \"markdownDescription\": \"Alias for the link.\\n\\nDon't use system interface names like \\\"eth0\\\", \\\"ens3\\\", \\\"enp0s2\\\", etc. as those may conflict\\nwith existing physical interfaces.\\n\\nThe name can contain a single integer format verb (`%d`) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. `net0`, `net1`, ...) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAlias for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDon\\u0026rsquo;t use system interface names like \\u0026ldquo;eth0\\u0026rdquo;, \\u0026ldquo;ens3\\u0026rdquo;, \\u0026ldquo;enp0s2\\u0026rdquo;, etc. as those may conflict\\nwith existing physical interfaces.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe name can contain a single integer format verb (\\u003ccode\\u003e%d\\u003c/code\\u003e) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. \\u003ccode\\u003enet0\\u003c/code\\u003e, \\u003ccode\\u003enet1\\u003c/code\\u003e, \\u0026hellip;) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\\u003c/p\\u003e\\n\"\n        },\n        \"selector\": {\n          \"$ref\": \"#/$defs/network.LinkSelector\",\n          \"title\": \"selector\",\n          \"description\": \"Selector to match the link to alias.\\n\\nWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. net%d), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Selector to match the link to alias.\\n\\nWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. `net%d`), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelector to match the link to alias.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. \\u003ccode\\u003enet%d\\u003c/code\\u003e), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"LinkAliasConfig is a config document to alias (give a different name) to a physical link.\"\n    },\n    \"network.LinkConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"LinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"LinkConfig is a config document to configure physical interfaces (network links).\"\n    },\n    \"network.LinkSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the link.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LinkSelector selects a link to alias.\"\n    },\n    \"network.NTPConfig\": {\n      \"properties\": {\n        \"servers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"servers\",\n          \"description\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to time.cloudflare.com.\\n\",\n          \"markdownDescription\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to `time.cloudflare.com`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies time (NTP) servers to use for setting the system time.\\nDefaults to \\u003ccode\\u003etime.cloudflare.com\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"NTPConfig represents a NTP server configuration.\"\n    },\n    \"network.NameserverConfig\": {\n      \"properties\": {\n        \"address\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"address\",\n          \"description\": \"The IP address of the nameserver.\\n\",\n          \"markdownDescription\": \"The IP address of the nameserver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe IP address of the nameserver.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"NameserverConfig represents a single nameserver configuration.\"\n    },\n    \"network.PTPConfig\": {\n      \"properties\": {\n        \"devices\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"devices\",\n          \"description\": \"description: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\n\\nA PTP device is typically represented as a character device file in the /dev directory,\\n\\n\\nsuch as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\\n\",\n          \"markdownDescription\": \"description: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\n\\n    A PTP device is typically represented as a character device file in the /dev directory,\\n   such as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\u003c/p\\u003e\\n\\n\\u003cpre\\u003e\\u003ccode\\u003eA PTP device is typically represented as a character device file in the /dev directory,\\n\\u003c/code\\u003e\\u003c/pre\\u003e\\n\\n\\u003cp\\u003esuch as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"PTPConfig represents a PTP (Precision Time Protocol) configuration.\"\n    },\n    \"network.ResolverConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ResolverConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"nameservers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.NameserverConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nameservers\",\n          \"description\": \"A list of nameservers (DNS servers) to use for resolving domain names.\\n\\nNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\n\\nThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\\n\",\n          \"markdownDescription\": \"A list of nameservers (DNS servers) to use for resolving domain names.\\n\\nNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\n\\nThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of nameservers (DNS servers) to use for resolving domain names.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\\u003c/p\\u003e\\n\"\n        },\n        \"searchDomains\": {\n          \"$ref\": \"#/$defs/network.SearchDomainsConfig\",\n          \"title\": \"searchDomains\",\n          \"description\": \"Configuration for search domains (in /etc/resolv.conf).\\n\\nThe default is to derive search domains from the hostname FQDN.\\n\",\n          \"markdownDescription\": \"Configuration for search domains (in /etc/resolv.conf).\\n\\nThe default is to derive search domains from the hostname FQDN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for search domains (in /etc/resolv.conf).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe default is to derive search domains from the hostname FQDN.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ResolverConfig is a config document to configure DNS resolving.\"\n    },\n    \"network.RouteConfig\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"destination\",\n          \"description\": \"The route’s destination as an address prefix.\\n\\nIf not specified, a default route will be created for the address family of the gateway.\\n\",\n          \"markdownDescription\": \"The route's destination as an address prefix.\\n\\nIf not specified, a default route will be created for the address family of the gateway.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s destination as an address prefix.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, a default route will be created for the address family of the gateway.\\u003c/p\\u003e\\n\"\n        },\n        \"gateway\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"gateway\",\n          \"description\": \"The route’s gateway (if empty, creates link scope route).\\n\",\n          \"markdownDescription\": \"The route's gateway (if empty, creates link scope route).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s gateway (if empty, creates link scope route).\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"source\",\n          \"description\": \"The route’s source address (optional).\\n\",\n          \"markdownDescription\": \"The route's source address (optional).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s source address (optional).\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The optional MTU for the route.\\n\",\n          \"markdownDescription\": \"The optional MTU for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional MTU for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"The routing table to use for the route.\\n\\nIf not specified, the main routing table will be used.\\n\",\n          \"markdownDescription\": \"The routing table to use for the route.\\n\\nIf not specified, the main routing table will be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe routing table to use for the route.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the main routing table will be used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RouteConfig represents a network route configuration.\"\n    },\n    \"network.RoutingRuleConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RoutingRuleConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Priority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\\n\",\n          \"markdownDescription\": \"Priority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePriority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"src\": {\n          \"type\": \"string\",\n          \"title\": \"src\",\n          \"description\": \"Source address prefix to match.\\nIf empty, matches all sources.\\n\",\n          \"markdownDescription\": \"Source address prefix to match.\\nIf empty, matches all sources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource address prefix to match.\\nIf empty, matches all sources.\\u003c/p\\u003e\\n\"\n        },\n        \"dst\": {\n          \"type\": \"string\",\n          \"title\": \"dst\",\n          \"description\": \"Destination address prefix to match.\\nIf empty, matches all destinations.\\n\",\n          \"markdownDescription\": \"Destination address prefix to match.\\nIf empty, matches all destinations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination address prefix to match.\\nIf empty, matches all destinations.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"The routing table to look up if the rule matches.\\n\",\n          \"markdownDescription\": \"The routing table to look up if the rule matches.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe routing table to look up if the rule matches.\\u003c/p\\u003e\\n\"\n        },\n        \"action\": {\n          \"type\": \"integer\",\n          \"title\": \"action\",\n          \"description\": \"The action to perform when the rule matches.\\nDefaults to “unicast” (table lookup).\\n\",\n          \"markdownDescription\": \"The action to perform when the rule matches.\\nDefaults to \\\"unicast\\\" (table lookup).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe action to perform when the rule matches.\\nDefaults to \\u0026ldquo;unicast\\u0026rdquo; (table lookup).\\u003c/p\\u003e\\n\"\n        },\n        \"iifName\": {\n          \"type\": \"string\",\n          \"title\": \"iifName\",\n          \"description\": \"Match packets arriving on this interface.\\n\",\n          \"markdownDescription\": \"Match packets arriving on this interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets arriving on this interface.\\u003c/p\\u003e\\n\"\n        },\n        \"oifName\": {\n          \"type\": \"string\",\n          \"title\": \"oifName\",\n          \"description\": \"Match packets going out on this interface.\\n\",\n          \"markdownDescription\": \"Match packets going out on this interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets going out on this interface.\\u003c/p\\u003e\\n\"\n        },\n        \"fwMark\": {\n          \"type\": \"integer\",\n          \"title\": \"fwMark\",\n          \"description\": \"Match packets with this firewall mark value.\\n\",\n          \"markdownDescription\": \"Match packets with this firewall mark value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets with this firewall mark value.\\u003c/p\\u003e\\n\"\n        },\n        \"fwMask\": {\n          \"type\": \"integer\",\n          \"title\": \"fwMask\",\n          \"description\": \"Mask for the firewall mark comparison.\\n\",\n          \"markdownDescription\": \"Mask for the firewall mark comparison.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMask for the firewall mark comparison.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"table\"\n      ],\n      \"description\": \"RoutingRuleConfig is a config document to configure Linux policy routing rules.\"\n    },\n    \"network.RuleConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"NetworkRuleConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"portSelector\": {\n          \"$ref\": \"#/$defs/network.RulePortSelector\",\n          \"title\": \"portSelector\",\n          \"description\": \"Port selector defines which ports and protocols on the host are affected by the rule.\\n\",\n          \"markdownDescription\": \"Port selector defines which ports and protocols on the host are affected by the rule.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePort selector defines which ports and protocols on the host are affected by the rule.\\u003c/p\\u003e\\n\"\n        },\n        \"ingress\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.IngressRule\"\n          },\n          \"type\": \"array\",\n          \"title\": \"ingress\",\n          \"description\": \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the portSelector.\\n\",\n          \"markdownDescription\": \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIngress defines which source subnets are allowed to access the host ports/protocols defined by the \\u003ccode\\u003eportSelector\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"NetworkRuleConfig is a network firewall rule config document.\"\n    },\n    \"network.RulePortSelector\": {\n      \"properties\": {\n        \"ports\": {\n          \"items\": {\n            \"oneOf\": [\n              {\n                \"type\": \"integer\"\n              },\n              {\n                \"type\": \"string\"\n              }\n            ]\n          },\n          \"type\": \"array\",\n          \"title\": \"ports\",\n          \"description\": \"Ports defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\\n\",\n          \"markdownDescription\": \"Ports defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePorts defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\\u003c/p\\u003e\\n\"\n        },\n        \"protocol\": {\n          \"enum\": [\n            \"tcp\",\n            \"udp\",\n            \"icmp\",\n            \"icmpv6\"\n          ],\n          \"title\": \"protocol\",\n          \"description\": \"Protocol defines traffic protocol (e.g. TCP or UDP).\\n\",\n          \"markdownDescription\": \"Protocol defines traffic protocol (e.g. TCP or UDP).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProtocol defines traffic protocol (e.g. TCP or UDP).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RulePortSelector is a port selector for the network rule.\"\n    },\n    \"network.SearchDomainsConfig\": {\n      \"properties\": {\n        \"domains\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"domains\",\n          \"description\": \"A list of search domains to be used for DNS resolution.\\n\\nSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if “example.com” is a search domain and a user tries to resolve\\n“host”, the system will attempt to resolve “host.example.com”.\\n\\nThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\\n\",\n          \"markdownDescription\": \"A list of search domains to be used for DNS resolution.\\n\\nSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if \\\"example.com\\\" is a search domain and a user tries to resolve\\n\\\"host\\\", the system will attempt to resolve \\\"host.example.com\\\".\\n\\nThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of search domains to be used for DNS resolution.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if \\u0026ldquo;example.com\\u0026rdquo; is a search domain and a user tries to resolve\\n\\u0026ldquo;host\\u0026rdquo;, the system will attempt to resolve \\u0026ldquo;host.example.com\\u0026rdquo;.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\\u003c/p\\u003e\\n\"\n        },\n        \"disableDefault\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableDefault\",\n          \"description\": \"Disable default search domain configuration from hostname FQDN.\\n\\nWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\\n\",\n          \"markdownDescription\": \"Disable default search domain configuration from hostname FQDN.\\n\\nWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable default search domain configuration from hostname FQDN.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"SearchDomainsConfig represents search domains configuration.\"\n    },\n    \"network.StaticHostConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"StaticHostConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address (IPv4 or IPv6) to map the hostnames to.\\n\",\n          \"markdownDescription\": \"IP address (IPv4 or IPv6) to map the hostnames to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address (IPv4 or IPv6) to map the hostnames to.\\u003c/p\\u003e\\n\"\n        },\n        \"hostnames\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"hostnames\",\n          \"description\": \"List of hostnames to map to the IP address.\\n\",\n          \"markdownDescription\": \"List of hostnames to map to the IP address.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of hostnames to map to the IP address.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"StaticHostConfig is a config document to set /etc/hosts entries.\"\n    },\n    \"network.TCPProbeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TCPProbeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the probe.\\n\",\n          \"markdownDescription\": \"Name of the probe.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the probe.\\u003c/p\\u003e\\n\"\n        },\n        \"interval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"interval\",\n          \"description\": \"Interval between probe attempts.\\nDefaults to 1s.\\n\",\n          \"markdownDescription\": \"Interval between probe attempts.\\nDefaults to 1s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eInterval between probe attempts.\\nDefaults to 1s.\\u003c/p\\u003e\\n\"\n        },\n        \"failureThreshold\": {\n          \"type\": \"integer\",\n          \"title\": \"failureThreshold\",\n          \"description\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\n\",\n          \"markdownDescription\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint to probe in the format host:port.\\n\",\n          \"markdownDescription\": \"Endpoint to probe in the format host:port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint to probe in the format host:port.\\u003c/p\\u003e\\n\"\n        },\n        \"timeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"timeout\",\n          \"description\": \"Timeout for the probe.\\nDefaults to 10s.\\n\",\n          \"markdownDescription\": \"Timeout for the probe.\\nDefaults to 10s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTimeout for the probe.\\nDefaults to 10s.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"endpoint\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"TCPProbeConfig is a config document to configure network TCP connectivity probes.\"\n    },\n    \"network.TimeSyncConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TimeSyncConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Indicates if the time synchronization is enabled for the machine.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the time synchronization is enabled for the machine.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the time synchronization is enabled for the machine.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"bootTimeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"bootTimeout\",\n          \"description\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to “infinity” (waiting forever for time sync)\\n\",\n          \"markdownDescription\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\\"infinity\\\" (waiting forever for time sync)\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\u0026ldquo;infinity\\u0026rdquo; (waiting forever for time sync)\\u003c/p\\u003e\\n\"\n        },\n        \"ntp\": {\n          \"$ref\": \"#/$defs/network.NTPConfig\",\n          \"title\": \"ntp\",\n          \"description\": \"Specifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\\n\",\n          \"markdownDescription\": \"Specifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"ptp\": {\n          \"$ref\": \"#/$defs/network.PTPConfig\",\n          \"title\": \"ptp\",\n          \"description\": \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\\n\",\n          \"markdownDescription\": \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"TimeSyncConfig is a config document to configure time synchronization (NTP).\"\n    },\n    \"network.VLANConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VLANConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the VLAN link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the VLAN link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the VLAN link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanID\": {\n          \"type\": \"integer\",\n          \"title\": \"vlanID\",\n          \"description\": \"VLAN ID to be used for the VLAN link.\\n\",\n          \"markdownDescription\": \"VLAN ID to be used for the VLAN link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVLAN ID to be used for the VLAN link.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanMode\": {\n          \"enum\": [\n            \"802.1q\",\n            \"802.1ad\"\n          ],\n          \"title\": \"vlanMode\",\n          \"description\": \"Set the VLAN mode to use.\\nIf not set, defaults to ‘802.1q’.\\n\",\n          \"markdownDescription\": \"Set the VLAN mode to use.\\nIf not set, defaults to '802.1q'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the VLAN mode to use.\\nIf not set, defaults to \\u0026lsquo;802.1q\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"parent\": {\n          \"type\": \"string\",\n          \"title\": \"parent\",\n          \"description\": \"Name of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Name of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"parent\",\n        \"vlanID\"\n      ],\n      \"description\": \"VLANConfig is a config document to create a VLAN (virtual LAN) over a parent link.\"\n    },\n    \"network.VRFConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VRFConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the vrf link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the vrf link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the vrf link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"Routing table number to use for this vrf.\\n\",\n          \"markdownDescription\": \"Routing table number to use for this vrf.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRouting table number to use for this vrf.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"links\",\n        \"name\",\n        \"table\"\n      ],\n      \"description\": \"VRFConfig is a config document to create a vrf and assign links to it.\"\n    },\n    \"network.WireguardConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"WireguardConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the Wireguard link (interface).\\n\",\n          \"markdownDescription\": \"Name of the Wireguard link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the Wireguard link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"privateKey\": {\n          \"type\": \"string\",\n          \"title\": \"privateKey\",\n          \"description\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by wg genkey.\\n\",\n          \"markdownDescription\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by `wg genkey`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a private key configuration (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genkey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"listenPort\": {\n          \"type\": \"integer\",\n          \"title\": \"listenPort\",\n          \"description\": \"Specifies a device’s listening port (UDP).\\nIf not specified, a random port will be chosen.\\n\",\n          \"markdownDescription\": \"Specifies a device's listening port (UDP).\\nIf not specified, a random port will be chosen.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s listening port (UDP).\\nIf not specified, a random port will be chosen.\\u003c/p\\u003e\\n\"\n        },\n        \"firewallMark\": {\n          \"type\": \"integer\",\n          \"title\": \"firewallMark\",\n          \"description\": \"Specifies a device’s firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\\n\",\n          \"markdownDescription\": \"Specifies a device's firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\\u003c/p\\u003e\\n\"\n        },\n        \"peers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.WireguardPeer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"peers\",\n          \"description\": \"Specifies a list of peer configurations to apply to a device.\\n\",\n          \"markdownDescription\": \"Specifies a list of peer configurations to apply to a device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a list of peer configurations to apply to a device.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"privateKey\"\n      ],\n      \"description\": \"WireguardConfig is a config document to create and configure a Wireguard network link.\"\n    },\n    \"network.WireguardPeer\": {\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\",\n          \"title\": \"publicKey\",\n          \"description\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running wg pubkey \\u0026lt; private.key.\\n\",\n          \"markdownDescription\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running `wg pubkey \\u003c private.key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the public key of this peer.\\nCan be extracted from private key by running \\u003ccode\\u003ewg pubkey \\u0026lt; private.key\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"presharedKey\": {\n          \"type\": \"string\",\n          \"title\": \"presharedKey\",\n          \"description\": \"Specifies the preshared key for this peer (base64 encoded).\\nCan be generated by wg genpsk.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\\n\",\n          \"markdownDescription\": \"Specifies the preshared key for this peer (base64 encoded).\\nCan be generated by `wg genpsk`.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the preshared key for this peer (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genpsk\\u003c/code\\u003e.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-f.:]+|\\\\[[0-9a-f:.]+\\\\]):\\\\d{1,5}$\",\n          \"title\": \"endpoint\",\n          \"description\": \"Specifies the endpoint of this peer entry.\\nFormat: :.\\nIf not set, the peer should connect to us without us connecting to it first.\\n\",\n          \"markdownDescription\": \"Specifies the endpoint of this peer entry.\\nFormat: \\u003cIP address\\u003e:\\u003cport\\u003e.\\nIf not set, the peer should connect to us without us connecting to it first.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the endpoint of this peer entry.\\nFormat: \\u003cIP address\\u003e:\\u003cport\\u003e.\\nIf not set, the peer should connect to us without us connecting to it first.\\u003c/p\\u003e\\n\"\n        },\n        \"persistentKeepaliveInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"persistentKeepaliveInterval\",\n          \"description\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        },\n        \"allowedIPs\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedIPs\",\n          \"description\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\\n\",\n          \"markdownDescription\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"publicKey\"\n      ],\n      \"description\": \"WireguardPeer describes a Wireguard peer configuration.\"\n    },\n    \"runtime.EnvironmentV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EnvironmentConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"variables\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"variables\",\n          \"description\": \"This field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore () character, and\\n  - contain only uppercase and lowercase letters, underscore () characters, and numbers.\\n\",\n          \"markdownDescription\": \"This field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore (_) character, and\\n  - contain only uppercase and lowercase letters, underscore (_) characters, and numbers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore (\\u003cem\\u003e) character, and\\n  - contain only uppercase and lowercase letters, underscore (\\u003c/em\\u003e) characters, and numbers.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"EnvironmentConfig is an environment config document.\"\n    },\n    \"runtime.EventSinkV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EventSinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"The endpoint for the event sink as ‘host:port’.\\n\",\n          \"markdownDescription\": \"The endpoint for the event sink as 'host:port'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe endpoint for the event sink as \\u0026lsquo;host:port\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"EventSinkConfig is a event sink config document.\"\n    },\n    \"runtime.KmsgLogV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KmsgLogConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"url\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(tcp|udp)://\",\n          \"title\": \"url\",\n          \"description\": \"The URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\\n\",\n          \"markdownDescription\": \"The URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KmsgLogConfig is a event sink config document.\"\n    },\n    \"runtime.OOMV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"OOMConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"triggerExpression\": {\n          \"type\": \"string\",\n          \"title\": \"triggerExpression\",\n          \"description\": \"This expression defines when to trigger OOM action.\\n\\nThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\n\\nThis expression receives the following parameters:\\n- memory{some,full}{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\\n\",\n          \"markdownDescription\": \"This expression defines when to trigger OOM action.\\n\\nThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\n\\nThis expression receives the following parameters:\\n- memory_{some,full}_{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis expression defines when to trigger OOM action.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis expression receives the following parameters:\\n- memory\\u003cem\\u003e{some,full}\\u003c/em\\u003e{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\\u003c/p\\u003e\\n\"\n        },\n        \"cgroupRankingExpression\": {\n          \"type\": \"string\",\n          \"title\": \"cgroupRankingExpression\",\n          \"description\": \"This expression defines how to rank cgroups for OOM handler.\\n\\nThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\n\\nThis expression receives the following parameters:\\n- memory_max - Optional - in bytes\\n- memory_current - Optional - in bytes\\n- memory_peak - Optional - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\\n\",\n          \"markdownDescription\": \"This expression defines how to rank cgroups for OOM handler.\\n\\nThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\n\\nThis expression receives the following parameters:\\n- memory_max - Optional\\u003cuint\\u003e - in bytes\\n- memory_current - Optional\\u003cuint\\u003e - in bytes\\n- memory_peak - Optional\\u003cuint\\u003e - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis expression defines how to rank cgroups for OOM handler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis expression receives the following parameters:\\n- memory_max - Optional\\u003cuint\\u003e - in bytes\\n- memory_current - Optional\\u003cuint\\u003e - in bytes\\n- memory_peak - Optional\\u003cuint\\u003e - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\\u003c/p\\u003e\\n\"\n        },\n        \"sampleInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"sampleInterval\",\n          \"description\": \"How often should the trigger expression be evaluated.\\n\\nThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\\n\",\n          \"markdownDescription\": \"How often should the trigger expression be evaluated.\\n\\nThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHow often should the trigger expression be evaluated.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"OOMConfig is a Out of Memory handler config document.\"\n    },\n    \"runtime.WatchdogTimerV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"WatchdogTimerConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"device\": {\n          \"type\": \"string\",\n          \"title\": \"device\",\n          \"description\": \"Path to the watchdog device.\\n\",\n          \"markdownDescription\": \"Path to the watchdog device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath to the watchdog device.\\u003c/p\\u003e\\n\"\n        },\n        \"timeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"timeout\",\n          \"description\": \"Timeout for the watchdog.\\n\\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\\n\\nDefault value is 1 minute, minimum value is 10 seconds.\\n\",\n          \"markdownDescription\": \"Timeout for the watchdog.\\n\\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\\n\\nDefault value is 1 minute, minimum value is 10 seconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTimeout for the watchdog.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf Talos is unresponsive for this duration, the watchdog will reset the system.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value is 1 minute, minimum value is 10 seconds.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"WatchdogTimerConfig is a watchdog timer config document.\"\n    },\n    \"security.TrustedRootsConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TrustedRootsConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"certificates\": {\n          \"type\": \"string\",\n          \"title\": \"certificates\",\n          \"description\": \"List of additional trusted certificate authorities (as PEM-encoded certificates).\\n\\nMultiple certificates can be provided in a single config document, separated by newline characters.\\n\",\n          \"markdownDescription\": \"List of additional trusted certificate authorities (as PEM-encoded certificates).\\n\\nMultiple certificates can be provided in a single config document, separated by newline characters.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of additional trusted certificate authorities (as PEM-encoded certificates).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eMultiple certificates can be provided in a single config document, separated by newline characters.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"TrustedRootsConfig allows to configure additional trusted CA roots.\"\n    },\n    \"siderolink.ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"SideroLinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"apiUrl\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(https|grpc)://\",\n          \"title\": \"apiUrl\",\n          \"description\": \"SideroLink API URL to connect to.\\n\",\n          \"markdownDescription\": \"SideroLink API URL to connect to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSideroLink API URL to connect to.\\u003c/p\\u003e\\n\"\n        },\n        \"uniqueToken\": {\n          \"type\": \"string\",\n          \"title\": \"uniqueToken\",\n          \"description\": \"SideroLink unique token to use for the connection (optional).\\n\\nThis value is overridden with META key UniqueMachineToken.\\n\",\n          \"markdownDescription\": \"SideroLink unique token to use for the connection (optional).\\n\\nThis value is overridden with META key UniqueMachineToken.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSideroLink unique token to use for the connection (optional).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis value is overridden with META key UniqueMachineToken.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"SideroLinkConfig is a SideroLink connection machine configuration document.\"\n    },\n    \"v1alpha1.APIServerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the API server manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the API server manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the API server manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the API server.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the API server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the API server.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the API server static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the API server static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the API server static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the API server’s certificate.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the API server's certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the API server\\u0026rsquo;s certificate.\\u003c/p\\u003e\\n\"\n        },\n        \"admissionControl\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.AdmissionPluginConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"admissionControl\",\n          \"description\": \"Configure the API server admission plugins.\\n\",\n          \"markdownDescription\": \"Configure the API server admission plugins.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server admission plugins.\\u003c/p\\u003e\\n\"\n        },\n        \"auditPolicy\": {\n          \"type\": \"object\",\n          \"title\": \"auditPolicy\",\n          \"description\": \"Configure the API server audit policy.\\n\",\n          \"markdownDescription\": \"Configure the API server audit policy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server audit policy.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the API server resources.\\n\",\n          \"markdownDescription\": \"Configure the API server resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server resources.\\u003c/p\\u003e\\n\"\n        },\n        \"authorizationConfig\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.AuthorizationConfigAuthorizerConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"authorizationConfig\",\n          \"description\": \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\\n\",\n          \"markdownDescription\": \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"APIServerConfig represents the kube apiserver configuration options.\"\n    },\n    \"v1alpha1.AdminKubeconfigConfig\": {\n      \"properties\": {\n        \"certLifetime\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"certLifetime\",\n          \"description\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdmin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AdminKubeconfigConfig contains admin kubeconfig settings.\"\n    },\n    \"v1alpha1.AdmissionPluginConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\\n\",\n          \"markdownDescription\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is the name of the admission controller.\\nIt must match the registered admission plugin name.\\u003c/p\\u003e\\n\"\n        },\n        \"configuration\": {\n          \"type\": \"object\",\n          \"title\": \"configuration\",\n          \"description\": \"Configuration is an embedded configuration object to be used as the plugin’s\\nconfiguration.\\n\",\n          \"markdownDescription\": \"Configuration is an embedded configuration object to be used as the plugin's\\nconfiguration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration is an embedded configuration object to be used as the plugin\\u0026rsquo;s\\nconfiguration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AdmissionPluginConfig represents the API server admission plugin configuration.\"\n    },\n    \"v1alpha1.AuthorizationConfigAuthorizerConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type is the name of the authorizer. Allowed values are Node, RBAC, and Webhook.\\n\",\n          \"markdownDescription\": \"Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType is the name of the authorizer. Allowed values are \\u003ccode\\u003eNode\\u003c/code\\u003e, \\u003ccode\\u003eRBAC\\u003c/code\\u003e, and \\u003ccode\\u003eWebhook\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is used to describe the authorizer.\\n\",\n          \"markdownDescription\": \"Name is used to describe the authorizer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is used to describe the authorizer.\\u003c/p\\u003e\\n\"\n        },\n        \"webhook\": {\n          \"type\": \"object\",\n          \"title\": \"webhook\",\n          \"description\": \"webhook is the configuration for the webhook authorizer.\\n\",\n          \"markdownDescription\": \"webhook is the configuration for the webhook authorizer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ewebhook is the configuration for the webhook authorizer.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\"\n    },\n    \"v1alpha1.CNIConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"enum\": [\n            \"flannel\",\n            \"custom\",\n            \"none\"\n          ],\n          \"title\": \"name\",\n          \"description\": \"Name of CNI to use.\\n\",\n          \"markdownDescription\": \"Name of CNI to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of CNI to use.\\u003c/p\\u003e\\n\"\n        },\n        \"urls\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"urls\",\n          \"description\": \"URLs containing manifests to apply for the CNI.\\nShould be present for “custom”, must be empty for “flannel” and “none”.\\n\",\n          \"markdownDescription\": \"URLs containing manifests to apply for the CNI.\\nShould be present for \\\"custom\\\", must be empty for \\\"flannel\\\" and \\\"none\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eURLs containing manifests to apply for the CNI.\\nShould be present for \\u0026ldquo;custom\\u0026rdquo;, must be empty for \\u0026ldquo;flannel\\u0026rdquo; and \\u0026ldquo;none\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"flannel\": {\n          \"$ref\": \"#/$defs/v1alpha1.FlannelCNIConfig\",\n          \"title\": \"flannel\",\n          \"description\": \"description: |\\nFlannel configuration options.\\n\",\n          \"markdownDescription\": \"description: |\\nFlannel configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\nFlannel configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CNIConfig represents the CNI configuration options.\"\n    },\n    \"v1alpha1.ClusterConfig\": {\n      \"properties\": {\n        \"id\": {\n          \"type\": \"string\",\n          \"title\": \"id\",\n          \"description\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\\n\",\n          \"markdownDescription\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eGlobally unique identifier for this cluster (base64 encoded random 32 bytes).\\u003c/p\\u003e\\n\"\n        },\n        \"secret\": {\n          \"type\": \"string\",\n          \"title\": \"secret\",\n          \"description\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\n\",\n          \"markdownDescription\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/v1alpha1.ControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides control plane specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides control plane specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides control plane specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterName\": {\n          \"type\": \"string\",\n          \"title\": \"clusterName\",\n          \"description\": \"Configures the cluster’s name.\\n\",\n          \"markdownDescription\": \"Configures the cluster's name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the cluster\\u0026rsquo;s name.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterNetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides cluster specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The bootstrap token used to join the cluster.\\n\",\n          \"markdownDescription\": \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/\\\" target=\\\"_blank\\\"\\u003ebootstrap token\\u003c/a\\u003e used to join the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"aescbcEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"aescbcEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"secretboxEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"secretboxEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The base64 encoded root certificate authority used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The base64 encoded root certificate authority used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded root certificate authority used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"acceptedCAs\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"acceptedCAs\",\n          \"description\": \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of base64 encoded accepted certificate authorities used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"aggregatorCA\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"aggregatorCA\",\n          \"description\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\\n\",\n          \"markdownDescription\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis CA can be self-signed.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceAccount\": {\n          \"properties\": {\n            \"key\": {\n              \"additionalProperties\": false,\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"serviceAccount\",\n          \"description\": \"The base64 encoded private key for service account token generation.\\n\",\n          \"markdownDescription\": \"The base64 encoded private key for service account token generation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded private key for service account token generation.\\u003c/p\\u003e\\n\"\n        },\n        \"apiServer\": {\n          \"$ref\": \"#/$defs/v1alpha1.APIServerConfig\",\n          \"title\": \"apiServer\",\n          \"description\": \"API server specific configuration options.\\n\",\n          \"markdownDescription\": \"API server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAPI server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/v1alpha1.ControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager server specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"proxy\": {\n          \"$ref\": \"#/$defs/v1alpha1.ProxyConfig\",\n          \"title\": \"proxy\",\n          \"description\": \"Kube-proxy server-specific configuration options\\n\",\n          \"markdownDescription\": \"Kube-proxy server-specific configuration options\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKube-proxy server-specific configuration options\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/v1alpha1.SchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler server specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterDiscoveryConfig\",\n          \"title\": \"discovery\",\n          \"description\": \"Configures cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configures cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures cluster member discovery.\\u003c/p\\u003e\\n\"\n        },\n        \"etcd\": {\n          \"$ref\": \"#/$defs/v1alpha1.EtcdConfig\",\n          \"title\": \"etcd\",\n          \"description\": \"Etcd specific configuration options.\\n\",\n          \"markdownDescription\": \"Etcd specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEtcd specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"coreDNS\": {\n          \"$ref\": \"#/$defs/v1alpha1.CoreDNS\",\n          \"title\": \"coreDNS\",\n          \"description\": \"Core DNS specific configuration options.\\n\",\n          \"markdownDescription\": \"Core DNS specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCore DNS specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"externalCloudProvider\": {\n          \"$ref\": \"#/$defs/v1alpha1.ExternalCloudProviderConfig\",\n          \"title\": \"externalCloudProvider\",\n          \"description\": \"External cloud provider configuration.\\n\",\n          \"markdownDescription\": \"External cloud provider configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal cloud provider configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraManifests\",\n          \"description\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifestHeaders\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraManifestHeaders\",\n          \"description\": \"A map of key value pairs that will be added while fetching the extraManifests.\\n\",\n          \"markdownDescription\": \"A map of key value pairs that will be added while fetching the extraManifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA map of key value pairs that will be added while fetching the extraManifests.\\u003c/p\\u003e\\n\"\n        },\n        \"inlineManifests\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.ClusterInlineManifest\"\n          },\n          \"type\": \"array\",\n          \"title\": \"inlineManifests\",\n          \"description\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"adminKubeconfig\": {\n          \"$ref\": \"#/$defs/v1alpha1.AdminKubeconfigConfig\",\n          \"title\": \"adminKubeconfig\",\n          \"description\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\n\",\n          \"markdownDescription\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSettings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\u003c/p\\u003e\\n\"\n        },\n        \"allowSchedulingOnControlPlanes\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowSchedulingOnControlPlanes\",\n          \"description\": \"Allows running workload on control-plane nodes.\\n\",\n          \"markdownDescription\": \"Allows running workload on control-plane nodes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows running workload on control-plane nodes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterConfig represents the cluster-wide config values.\"\n    },\n    \"v1alpha1.ClusterDiscoveryConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\n\",\n          \"markdownDescription\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/v1alpha1.DiscoveryRegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Configure registries used for cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configure registries used for cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure registries used for cluster member discovery.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterDiscoveryConfig struct configures cluster membership discovery.\"\n    },\n    \"v1alpha1.ClusterInlineManifest\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the manifest.\\nName should be unique.\\n\",\n          \"markdownDescription\": \"Name of the manifest.\\nName should be unique.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the manifest.\\nName should be unique.\\u003c/p\\u003e\\n\"\n        },\n        \"contents\": {\n          \"type\": \"string\",\n          \"title\": \"contents\",\n          \"description\": \"Manifest contents as a string.\\n\",\n          \"markdownDescription\": \"Manifest contents as a string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eManifest contents as a string.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterInlineManifest struct describes inline bootstrap manifests for the user.\"\n    },\n    \"v1alpha1.ClusterNetworkConfig\": {\n      \"properties\": {\n        \"cni\": {\n          \"$ref\": \"#/$defs/v1alpha1.CNIConfig\",\n          \"title\": \"cni\",\n          \"description\": \"The CNI used.\\nComposed of “name” and “urls”.\\nThe “name” key supports the following options: “flannel”, “custom”, and “none”.\\n“flannel” uses Talos-managed Flannel CNI, and that’s the default option.\\n“custom” uses custom manifests that should be provided in “urls”.\\n“none” indicates that Talos will not manage any CNI installation.\\n\",\n          \"markdownDescription\": \"The CNI used.\\nComposed of \\\"name\\\" and \\\"urls\\\".\\nThe \\\"name\\\" key supports the following options: \\\"flannel\\\", \\\"custom\\\", and \\\"none\\\".\\n\\\"flannel\\\" uses Talos-managed Flannel CNI, and that's the default option.\\n\\\"custom\\\" uses custom manifests that should be provided in \\\"urls\\\".\\n\\\"none\\\" indicates that Talos will not manage any CNI installation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe CNI used.\\nComposed of \\u0026ldquo;name\\u0026rdquo; and \\u0026ldquo;urls\\u0026rdquo;.\\nThe \\u0026ldquo;name\\u0026rdquo; key supports the following options: \\u0026ldquo;flannel\\u0026rdquo;, \\u0026ldquo;custom\\u0026rdquo;, and \\u0026ldquo;none\\u0026rdquo;.\\n\\u0026ldquo;flannel\\u0026rdquo; uses Talos-managed Flannel CNI, and that\\u0026rsquo;s the default option.\\n\\u0026ldquo;custom\\u0026rdquo; uses custom manifests that should be provided in \\u0026ldquo;urls\\u0026rdquo;.\\n\\u0026ldquo;none\\u0026rdquo; indicates that Talos will not manage any CNI installation.\\u003c/p\\u003e\\n\"\n        },\n        \"dnsDomain\": {\n          \"type\": \"string\",\n          \"title\": \"dnsDomain\",\n          \"description\": \"The domain used by Kubernetes DNS.\\nThe default is cluster.local\\n\",\n          \"markdownDescription\": \"The domain used by Kubernetes DNS.\\nThe default is `cluster.local`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe domain used by Kubernetes DNS.\\nThe default is \\u003ccode\\u003ecluster.local\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"podSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"podSubnets\",\n          \"description\": \"The pod subnet CIDR.\\n\",\n          \"markdownDescription\": \"The pod subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe pod subnet CIDR.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"serviceSubnets\",\n          \"description\": \"The service subnet CIDR.\\n\",\n          \"markdownDescription\": \"The service subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe service subnet CIDR.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterNetworkConfig represents kube networking configuration options.\"\n    },\n    \"v1alpha1.Config\": {\n      \"properties\": {\n        \"version\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"version\",\n          \"description\": \"Indicates the schema used to decode the contents.\\n\",\n          \"markdownDescription\": \"Indicates the schema used to decode the contents.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates the schema used to decode the contents.\\u003c/p\\u003e\\n\"\n        },\n        \"debug\": {\n          \"type\": \"boolean\",\n          \"title\": \"debug\",\n          \"description\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\nNote: To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\n\",\n          \"markdownDescription\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\n**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eNote:\\u003c/strong\\u003e To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\u003c/p\\u003e\\n\"\n        },\n        \"machine\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineConfig\",\n          \"title\": \"machine\",\n          \"description\": \"Provides machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"cluster\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterConfig\",\n          \"title\": \"cluster\",\n          \"description\": \"Provides cluster specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"Config defines the v1alpha1.Config Talos machine configuration document.\"\n    },\n    \"v1alpha1.ControlPlaneConfig\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^https://\",\n          \"format\": \"uri\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\n\",\n          \"markdownDescription\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\u003c/p\\u003e\\n\"\n        },\n        \"localAPIServerPort\": {\n          \"type\": \"integer\",\n          \"title\": \"localAPIServerPort\",\n          \"description\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is 6443.\\n\",\n          \"markdownDescription\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is `6443`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is \\u003ccode\\u003e6443\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ControlPlaneConfig represents the control plane configuration options.\"\n    },\n    \"v1alpha1.ControllerManagerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the controller manager manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the controller manager manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the controller manager manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the controller manager.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the controller manager.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the controller manager.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the controller manager static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the controller manager static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the controller manager static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the controller manager resources.\\n\",\n          \"markdownDescription\": \"Configure the controller manager resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the controller manager resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ControllerManagerConfig represents the kube controller manager configuration options.\"\n    },\n    \"v1alpha1.CoreDNS\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable coredns deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable coredns deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable coredns deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an override to the default coredns image.\\n\",\n          \"markdownDescription\": \"The `image` field is an override to the default coredns image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an override to the default coredns image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CoreDNS represents the CoreDNS config values.\"\n    },\n    \"v1alpha1.DiscoveryRegistriesConfig\": {\n      \"properties\": {\n        \"kubernetes\": {\n          \"$ref\": \"#/$defs/v1alpha1.RegistryKubernetesConfig\",\n          \"title\": \"kubernetes\",\n          \"description\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\\nThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee https://github.com/siderolabs/talos/issues/9980 for more information.\\n\",\n          \"markdownDescription\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\\nThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee https://github.com/siderolabs/talos/issues/9980 for more information.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee \\u003ca href=\\\"https://github.com/siderolabs/talos/issues/9980\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/siderolabs/talos/issues/9980\\u003c/a\\u003e for more information.\\u003c/p\\u003e\\n\"\n        },\n        \"service\": {\n          \"$ref\": \"#/$defs/v1alpha1.RegistryServiceConfig\",\n          \"title\": \"service\",\n          \"description\": \"Service registry is using an external service to push and pull information about cluster members.\\n\",\n          \"markdownDescription\": \"Service registry is using an external service to push and pull information about cluster members.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eService registry is using an external service to push and pull information about cluster members.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"DiscoveryRegistriesConfig struct configures cluster membership discovery.\"\n    },\n    \"v1alpha1.Endpoint\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"Endpoint represents the endpoint URL parsed out of the machine config.\"\n    },\n    \"v1alpha1.EtcdConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used to create the etcd service.\\n\",\n          \"markdownDescription\": \"The container image used to create the etcd service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used to create the etcd service.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The ca is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The `ca` is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eca\\u003c/code\\u003e is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n\\nname\\ndata-dir\\ninitial-cluster-state\\nlisten-peer-urls\\nlisten-client-urls\\ncert-file\\nkey-file\\ntrusted-ca-file\\npeer-client-cert-auth\\npeer-cert-file\\npeer-trusted-ca-file\\npeer-key-file\\n\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n- `name`\\n- `data-dir`\\n- `initial-cluster-state`\\n- `listen-peer-urls`\\n- `listen-client-urls`\\n- `cert-file`\\n- `key-file`\\n- `trusted-ca-file`\\n- `peer-client-cert-auth`\\n- `peer-cert-file`\\n- `peer-trusted-ca-file`\\n- `peer-key-file`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to etcd.\\nNote that the following args are not allowed:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ename\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003edata-dir\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003einitial-cluster-state\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-peer-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-client-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ecert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ekey-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003etrusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-client-cert-auth\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-cert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-trusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-key-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"advertisedSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"advertisedSubnets\",\n          \"description\": \"The advertisedSubnets field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e field configures the networks to pick etcd advertised IP from.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        },\n        \"listenSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"listenSubnets\",\n          \"description\": \"The listenSubnets field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf listenSubnets is not set, but advertisedSubnets is set, listenSubnets defaults to\\nadvertisedSubnets.\\n\\nIf neither advertisedSubnets nor listenSubnets is set, listenSubnets defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\\n`advertisedSubnets`.\\n\\nIf neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e field configures the networks for the etcd to listen for peer and client connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is not set, but \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to\\n\\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf neither \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e nor \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to listen on all addresses.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EtcdConfig represents the etcd configuration options.\"\n    },\n    \"v1alpha1.ExternalCloudProviderConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable external cloud provider.\\n\",\n          \"markdownDescription\": \"Enable external cloud provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable external cloud provider.\\u003c/p\\u003e\\n\"\n        },\n        \"manifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"manifests\",\n          \"description\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExternalCloudProviderConfig contains external cloud provider configuration.\"\n    },\n    \"v1alpha1.ExtraMount\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"title\": \"destination\",\n          \"description\": \"Destination is the absolute path where the mount will be placed in the container.\\n\",\n          \"markdownDescription\": \"Destination is the absolute path where the mount will be placed in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination is the absolute path where the mount will be placed in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type specifies the mount kind.\\n\",\n          \"markdownDescription\": \"Type specifies the mount kind.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType specifies the mount kind.\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"Source specifies the source path of the mount.\\n\",\n          \"markdownDescription\": \"Source specifies the source path of the mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource specifies the source path of the mount.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"options\",\n          \"description\": \"Options are fstab style mount options.\\n\",\n          \"markdownDescription\": \"Options are fstab style mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptions are fstab style mount options.\\u003c/p\\u003e\\n\"\n        },\n        \"uidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"uidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        },\n        \"gidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"gidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExtraMount wraps OCI Mount specification.\"\n    },\n    \"v1alpha1.FeaturesConfig\": {\n      \"properties\": {\n        \"kubernetesTalosAPIAccess\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubernetesTalosAPIAccessConfig\",\n          \"title\": \"kubernetesTalosAPIAccess\",\n          \"description\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\\n\",\n          \"markdownDescription\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is disabled if the feature config is not specified.\\u003c/p\\u003e\\n\"\n        },\n        \"diskQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"diskQuotaSupport\",\n          \"description\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\n\",\n          \"markdownDescription\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\u003c/p\\u003e\\n\"\n        },\n        \"kubePrism\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubePrism\",\n          \"title\": \"kubePrism\",\n          \"description\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\n\",\n          \"markdownDescription\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"hostDNS\": {\n          \"$ref\": \"#/$defs/v1alpha1.HostDNSConfig\",\n          \"title\": \"hostDNS\",\n          \"description\": \"Configures host DNS caching resolver.\\n\",\n          \"markdownDescription\": \"Configures host DNS caching resolver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures host DNS caching resolver.\\u003c/p\\u003e\\n\"\n        },\n        \"imageCache\": {\n          \"$ref\": \"#/$defs/v1alpha1.ImageCacheConfig\",\n          \"title\": \"imageCache\",\n          \"description\": \"Enable Image Cache feature.\\n\",\n          \"markdownDescription\": \"Enable Image Cache feature.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Image Cache feature.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeAddressSortAlgorithm\": {\n          \"type\": \"string\",\n          \"title\": \"nodeAddressSortAlgorithm\",\n          \"description\": \"Select the node address sort algorithm.\\nThe ‘v1’ algorithm sorts addresses by the address itself.\\nThe ‘v2’ algorithm prefers more specific prefixes.\\nIf unset, defaults to ‘v1’.\\n\",\n          \"markdownDescription\": \"Select the node address sort algorithm.\\nThe 'v1' algorithm sorts addresses by the address itself.\\nThe 'v2' algorithm prefers more specific prefixes.\\nIf unset, defaults to 'v1'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelect the node address sort algorithm.\\nThe \\u0026lsquo;v1\\u0026rsquo; algorithm sorts addresses by the address itself.\\nThe \\u0026lsquo;v2\\u0026rsquo; algorithm prefers more specific prefixes.\\nIf unset, defaults to \\u0026lsquo;v1\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FeaturesConfig describes individual Talos features that can be switched on or off.\"\n    },\n    \"v1alpha1.FlannelCNIConfig\": {\n      \"properties\": {\n        \"extraArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments for ‘flanneld’.\\n\",\n          \"markdownDescription\": \"Extra arguments for 'flanneld'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments for \\u0026lsquo;flanneld\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"kubeNetworkPoliciesEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"kubeNetworkPoliciesEnabled\",\n          \"description\": \"Deploys kube-network-policies along with Flannel.\\n\\nThis enables Kubernetes Network Policies support in the cluster.\\n\",\n          \"markdownDescription\": \"Deploys kube-network-policies along with Flannel.\\n\\nThis enables Kubernetes Network Policies support in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeploys kube-network-policies along with Flannel.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis enables Kubernetes Network Policies support in the cluster.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FlannelCNIConfig represents the Flannel CNI configuration options.\"\n    },\n    \"v1alpha1.HostDNSConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable host DNS caching resolver.\\n\",\n          \"markdownDescription\": \"Enable host DNS caching resolver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable host DNS caching resolver.\\u003c/p\\u003e\\n\"\n        },\n        \"forwardKubeDNSToHost\": {\n          \"type\": \"boolean\",\n          \"title\": \"forwardKubeDNSToHost\",\n          \"description\": \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\n\\nWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\\n\",\n          \"markdownDescription\": \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\n\\nWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\\u003c/p\\u003e\\n\"\n        },\n        \"resolveMemberNames\": {\n          \"type\": \"boolean\",\n          \"title\": \"resolveMemberNames\",\n          \"description\": \"Resolve member hostnames using the host DNS resolver.\\n\\nWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\\n\",\n          \"markdownDescription\": \"Resolve member hostnames using the host DNS resolver.\\n\\nWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eResolve member hostnames using the host DNS resolver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"HostDNSConfig describes the configuration for the host DNS resolver.\"\n    },\n    \"v1alpha1.ImageCacheConfig\": {\n      \"properties\": {\n        \"localEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"localEnabled\",\n          \"description\": \"Enable local image cache.\\n\",\n          \"markdownDescription\": \"Enable local image cache.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable local image cache.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ImageCacheConfig describes the configuration for the Image Cache feature.\"\n    },\n    \"v1alpha1.InstallConfig\": {\n      \"properties\": {\n        \"disk\": {\n          \"type\": \"string\",\n          \"title\": \"disk\",\n          \"description\": \"The disk used for installations.\\n\",\n          \"markdownDescription\": \"The disk used for installations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk used for installations.\\u003c/p\\u003e\\n\"\n        },\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/v1alpha1.InstallDiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over disk.\\n\",\n          \"markdownDescription\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over `disk`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLook up disk using disk attributes like model, size, serial and others.\\nAlways has priority over \\u003ccode\\u003edisk\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\nGitHub releases page.\\n\",\n          \"markdownDescription\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n[GitHub releases page](https://github.com/siderolabs/talos/releases).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n\\u003ca href=\\\"https://github.com/siderolabs/talos/releases\\\" target=\\\"_blank\\\"\\u003eGitHub releases page\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wipe\": {\n          \"type\": \"boolean\",\n          \"title\": \"wipe\",\n          \"description\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the installation disk should be wiped at installation time.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"legacyBIOSSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"legacyBIOSSupport\",\n          \"description\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn’t support GPT partitioning scheme.\\n\",\n          \"markdownDescription\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn\\u0026rsquo;t support GPT partitioning scheme.\\u003c/p\\u003e\\n\"\n        },\n        \"grubUseUKICmdline\": {\n          \"type\": \"boolean\",\n          \"title\": \"grubUseUKICmdline\",\n          \"description\": \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\\n\",\n          \"markdownDescription\": \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"InstallConfig represents the installation options for preparing a node.\"\n    },\n    \"v1alpha1.InstallDiskSelector\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"string\",\n          \"title\": \"size\",\n          \"description\": \"Disk size.\\n\",\n          \"markdownDescription\": \"Disk size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk size.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Disk name /sys/block/\\u0026lt;dev\\u0026gt;/device/name.\\n\",\n          \"markdownDescription\": \"Disk name `/sys/block/\\u003cdev\\u003e/device/name`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk name \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/name\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"model\": {\n          \"type\": \"string\",\n          \"title\": \"model\",\n          \"description\": \"Disk model /sys/block/\\u0026lt;dev\\u0026gt;/device/model.\\n\",\n          \"markdownDescription\": \"Disk model `/sys/block/\\u003cdev\\u003e/device/model`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk model \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/model\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"serial\": {\n          \"type\": \"string\",\n          \"title\": \"serial\",\n          \"description\": \"Disk serial number /sys/block/\\u0026lt;dev\\u0026gt;/serial.\\n\",\n          \"markdownDescription\": \"Disk serial number `/sys/block/\\u003cdev\\u003e/serial`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk serial number \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/serial\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"modalias\": {\n          \"type\": \"string\",\n          \"title\": \"modalias\",\n          \"description\": \"Disk modalias /sys/block/\\u0026lt;dev\\u0026gt;/device/modalias.\\n\",\n          \"markdownDescription\": \"Disk modalias `/sys/block/\\u003cdev\\u003e/device/modalias`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk modalias \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/modalias\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"uuid\": {\n          \"type\": \"string\",\n          \"title\": \"uuid\",\n          \"description\": \"Disk UUID /sys/block/\\u0026lt;dev\\u0026gt;/uuid.\\n\",\n          \"markdownDescription\": \"Disk UUID `/sys/block/\\u003cdev\\u003e/uuid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk UUID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/uuid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wwid\": {\n          \"type\": \"string\",\n          \"title\": \"wwid\",\n          \"description\": \"Disk WWID /sys/block/\\u0026lt;dev\\u0026gt;/wwid.\\n\",\n          \"markdownDescription\": \"Disk WWID `/sys/block/\\u003cdev\\u003e/wwid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk WWID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/wwid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"enum\": [\n            \"ssd\",\n            \"hdd\",\n            \"nvme\",\n            \"sd\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Disk Type.\\n\",\n          \"markdownDescription\": \"Disk Type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk Type.\\u003c/p\\u003e\\n\"\n        },\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"Disk bus path.\\n\",\n          \"markdownDescription\": \"Disk bus path.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk bus path.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"InstallDiskSelector represents a disk query parameters for the install disk lookup.\"\n    },\n    \"v1alpha1.KernelConfig\": {\n      \"properties\": {\n        \"modules\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.KernelModuleConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"modules\",\n          \"description\": \"Kernel modules to load.\\n\",\n          \"markdownDescription\": \"Kernel modules to load.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel modules to load.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KernelConfig struct configures Talos Linux kernel.\"\n    },\n    \"v1alpha1.KernelModuleConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Module name.\\n\",\n          \"markdownDescription\": \"Module name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule name.\\u003c/p\\u003e\\n\"\n        },\n        \"parameters\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"parameters\",\n          \"description\": \"Module parameters, changes applied after reboot.\\n\",\n          \"markdownDescription\": \"Module parameters, changes applied after reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule parameters, changes applied after reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KernelModuleConfig struct configures Linux kernel modules to load.\"\n    },\n    \"v1alpha1.KubePrism\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable KubePrism support - will start local load balancing proxy.\\n\",\n          \"markdownDescription\": \"Enable KubePrism support - will start local load balancing proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable KubePrism support - will start local load balancing proxy.\\u003c/p\\u003e\\n\"\n        },\n        \"port\": {\n          \"type\": \"integer\",\n          \"title\": \"port\",\n          \"description\": \"KubePrism port.\\n\",\n          \"markdownDescription\": \"KubePrism port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism port.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubePrism describes the configuration for the KubePrism load balancer.\"\n    },\n    \"v1alpha1.KubeletConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an optional reference to an alternative kubelet image.\\n\",\n          \"markdownDescription\": \"The `image` field is an optional reference to an alternative kubelet image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an optional reference to an alternative kubelet image.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterDNS\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"clusterDNS\",\n          \"description\": \"The ClusterDNS field is an optional reference to an alternative kubelet clusterDNS ip list.\\n\",\n          \"markdownDescription\": \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eClusterDNS\\u003c/code\\u003e field is an optional reference to an alternative kubelet clusterDNS ip list.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"The extraArgs field is used to provide additional flags to the kubelet.\\n\",\n          \"markdownDescription\": \"The `extraArgs` field is used to provide additional flags to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraArgs\\u003c/code\\u003e field is used to provide additional flags to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"extraMounts\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.ExtraMount\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraMounts\",\n          \"description\": \"The extraMounts field is used to add additional mounts to the kubelet container.\\nNote that either bind or rbind are required in the options.\\n\",\n          \"markdownDescription\": \"The `extraMounts` field is used to add additional mounts to the kubelet container.\\nNote that either `bind` or `rbind` are required in the `options`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraMounts\\u003c/code\\u003e field is used to add additional mounts to the kubelet container.\\nNote that either \\u003ccode\\u003ebind\\u003c/code\\u003e or \\u003ccode\\u003erbind\\u003c/code\\u003e are required in the \\u003ccode\\u003eoptions\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraConfig\": {\n          \"type\": \"object\",\n          \"title\": \"extraConfig\",\n          \"description\": \"The extraConfig field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\n\",\n          \"markdownDescription\": \"The `extraConfig` field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraConfig\\u003c/code\\u003e field is used to provide kubelet configuration overrides.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\u003c/p\\u003e\\n\"\n        },\n        \"credentialProviderConfig\": {\n          \"type\": \"object\",\n          \"title\": \"credentialProviderConfig\",\n          \"description\": \"The KubeletCredentialProviderConfig field is used to provide kubelet credential configuration.\\n\",\n          \"markdownDescription\": \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eKubeletCredentialProviderConfig\\u003c/code\\u003e field is used to provide kubelet credential configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"defaultRuntimeSeccompProfileEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"defaultRuntimeSeccompProfileEnabled\",\n          \"description\": \"Enable container runtime default Seccomp profile.\\n\",\n          \"markdownDescription\": \"Enable container runtime default Seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable container runtime default Seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"registerWithFQDN\": {\n          \"type\": \"boolean\",\n          \"title\": \"registerWithFQDN\",\n          \"description\": \"The registerWithFQDN field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\n\",\n          \"markdownDescription\": \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eregisterWithFQDN\\u003c/code\\u003e field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeIP\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubeletNodeIPConfig\",\n          \"title\": \"nodeIP\",\n          \"description\": \"The nodeIP field is used to configure --node-ip flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\n\",\n          \"markdownDescription\": \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003enodeIP\\u003c/code\\u003e field is used to configure \\u003ccode\\u003e--node-ip\\u003c/code\\u003e flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\u003c/p\\u003e\\n\"\n        },\n        \"skipNodeRegistration\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipNodeRegistration\",\n          \"description\": \"The skipNodeRegistration is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\n\",\n          \"markdownDescription\": \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eskipNodeRegistration\\u003c/code\\u003e is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\u003c/p\\u003e\\n\"\n        },\n        \"disableManifestsDirectory\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableManifestsDirectory\",\n          \"description\": \"The disableManifestsDirectory field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt’s recommended to configure static pods with the “pods” key instead.\\n\",\n          \"markdownDescription\": \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt's recommended to configure static pods with the \\\"pods\\\" key instead.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003edisableManifestsDirectory\\u003c/code\\u003e field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt\\u0026rsquo;s recommended to configure static pods with the \\u0026ldquo;pods\\u0026rdquo; key instead.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeletConfig represents the kubelet config values.\"\n    },\n    \"v1alpha1.KubeletNodeIPConfig\": {\n      \"properties\": {\n        \"validSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"validSubnets\",\n          \"description\": \"The validSubnets field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\n\",\n          \"markdownDescription\": \"The `validSubnets` field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalidSubnets\\u003c/code\\u003e field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeletNodeIPConfig represents the kubelet node IP configuration.\"\n    },\n    \"v1alpha1.KubernetesTalosAPIAccessConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable Talos API access from Kubernetes pods.\\n\",\n          \"markdownDescription\": \"Enable Talos API access from Kubernetes pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedRoles\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedRoles\",\n          \"description\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\\n\",\n          \"markdownDescription\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Talos API roles which can be granted for access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEmpty list means that no roles can be granted, so access is blocked.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedKubernetesNamespaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedKubernetesNamespaces\",\n          \"description\": \"The list of Kubernetes namespaces Talos API access is available from.\\n\",\n          \"markdownDescription\": \"The list of Kubernetes namespaces Talos API access is available from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Kubernetes namespaces Talos API access is available from.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\"\n    },\n    \"v1alpha1.LinuxIDMapping\": {\n      \"properties\": {\n        \"containerID\": {\n          \"type\": \"integer\",\n          \"title\": \"containerID\",\n          \"description\": \"ContainerID is the starting UID/GID in the container.\\n\",\n          \"markdownDescription\": \"ContainerID is the starting UID/GID in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eContainerID is the starting UID/GID in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"hostID\": {\n          \"type\": \"integer\",\n          \"title\": \"hostID\",\n          \"description\": \"HostID is the starting UID/GID on the host to be mapped to ‘ContainerID’.\\n\",\n          \"markdownDescription\": \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHostID is the starting UID/GID on the host to be mapped to \\u0026lsquo;ContainerID\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"Size is the number of IDs to be mapped.\\n\",\n          \"markdownDescription\": \"Size is the number of IDs to be mapped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSize is the number of IDs to be mapped.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LinuxIDMapping represents the Linux ID mapping.\"\n    },\n    \"v1alpha1.LoggingConfig\": {\n      \"properties\": {\n        \"destinations\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LoggingDestination\"\n          },\n          \"type\": \"array\",\n          \"title\": \"destinations\",\n          \"description\": \"Logging destination.\\n\",\n          \"markdownDescription\": \"Logging destination.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogging destination.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LoggingConfig struct configures Talos logging.\"\n    },\n    \"v1alpha1.LoggingDestination\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"$ref\": \"#/$defs/v1alpha1.Endpoint\",\n          \"title\": \"endpoint\",\n          \"description\": \"Where to send logs. Supported protocols are “tcp” and “udp”.\\n\",\n          \"markdownDescription\": \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to send logs. Supported protocols are \\u0026ldquo;tcp\\u0026rdquo; and \\u0026ldquo;udp\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"format\": {\n          \"enum\": [\n            \"json_lines\"\n          ],\n          \"title\": \"format\",\n          \"description\": \"Logs format.\\n\",\n          \"markdownDescription\": \"Logs format.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogs format.\\u003c/p\\u003e\\n\"\n        },\n        \"extraTags\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraTags\",\n          \"description\": \"Extra tags (key-value) pairs to attach to every log message sent.\\n\",\n          \"markdownDescription\": \"Extra tags (key-value) pairs to attach to every log message sent.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra tags (key-value) pairs to attach to every log message sent.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LoggingDestination struct configures Talos logging destination.\"\n    },\n    \"v1alpha1.MachineConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"controlplane\",\n            \"worker\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Defines the role of the machine within the cluster.\\n\\nControl Plane\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\nWorker\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as “join”; that value is still supported but deprecated.\\n\",\n          \"markdownDescription\": \"Defines the role of the machine within the cluster.\\n\\n**Control Plane**\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\n**Worker**\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as \\\"join\\\"; that value is still supported but deprecated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the role of the machine within the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eControl Plane\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eWorker\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis node type was previously known as \\u0026ldquo;join\\u0026rdquo;; that value is still supported but deprecated.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The token is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its’ identity.\\n\",\n          \"markdownDescription\": \"The `token` is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003etoken\\u003c/code\\u003e is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its\\u0026rsquo; identity.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"acceptedCAs\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"acceptedCAs\",\n          \"description\": \"The certificates issued by certificate authorities are accepted in addition to issuing ‘ca’.\\nIt is composed of a base64 encoded crt`.\\n\",\n          \"markdownDescription\": \"The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.\\nIt is composed of a base64 encoded `crt``.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe certificates issued by certificate authorities are accepted in addition to issuing \\u0026lsquo;ca\\u0026rsquo;.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e`.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the machine’s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate’s SANs.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the machine's certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate's SANs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the machine\\u0026rsquo;s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate\\u0026rsquo;s SANs.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides machine specific control plane configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific control plane configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific control plane configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"kubelet\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubeletConfig\",\n          \"title\": \"kubelet\",\n          \"description\": \"Used to provide additional options to the kubelet.\\n\",\n          \"markdownDescription\": \"Used to provide additional options to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide additional options to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"pods\": {\n          \"items\": {\n            \"type\": \"object\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pods\",\n          \"description\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn’t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\\n\",\n          \"markdownDescription\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn't validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn\\u0026rsquo;t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee \\u003ca href=\\\"https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\\" target=\\\"_blank\\\"\\u003ehttps://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"install\": {\n          \"$ref\": \"#/$defs/v1alpha1.InstallConfig\",\n          \"title\": \"install\",\n          \"description\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\n\",\n          \"markdownDescription\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide instructions for installations.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\u003c/p\\u003e\\n\"\n        },\n        \"files\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.MachineFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"files\",\n          \"description\": \"Allows the addition of user specified files.\\nThe value of op can be create, overwrite, or append.\\nIn the case of create, path must not exist.\\nIn the case of overwrite, and append, path must be a valid file.\\nIf an op value of append is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\n\",\n          \"markdownDescription\": \"Allows the addition of user specified files.\\nThe value of `op` can be `create`, `overwrite`, or `append`.\\nIn the case of `create`, `path` must not exist.\\nIn the case of `overwrite`, and `append`, `path` must be a valid file.\\nIf an `op` value of `append` is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows the addition of user specified files.\\nThe value of \\u003ccode\\u003eop\\u003c/code\\u003e can be \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, or \\u003ccode\\u003eappend\\u003c/code\\u003e.\\nIn the case of \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must not exist.\\nIn the case of \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, and \\u003ccode\\u003eappend\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must be a valid file.\\nIf an \\u003ccode\\u003eop\\u003c/code\\u003e value of \\u003ccode\\u003eappend\\u003c/code\\u003e is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"sysctls\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysctls\",\n          \"description\": \"Used to configure the machine’s sysctls.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysctls.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysctls.\\u003c/p\\u003e\\n\"\n        },\n        \"sysfs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysfs\",\n          \"description\": \"Used to configure the machine’s sysfs.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysfs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysfs.\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"$ref\": \"#/$defs/v1alpha1.FeaturesConfig\",\n          \"title\": \"features\",\n          \"description\": \"Features describe individual Talos features that can be switched on or off.\\n\",\n          \"markdownDescription\": \"Features describe individual Talos features that can be switched on or off.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFeatures describe individual Talos features that can be switched on or off.\\u003c/p\\u003e\\n\"\n        },\n        \"udev\": {\n          \"$ref\": \"#/$defs/v1alpha1.UdevConfig\",\n          \"title\": \"udev\",\n          \"description\": \"Configures the udev system.\\n\",\n          \"markdownDescription\": \"Configures the udev system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the udev system.\\u003c/p\\u003e\\n\"\n        },\n        \"logging\": {\n          \"$ref\": \"#/$defs/v1alpha1.LoggingConfig\",\n          \"title\": \"logging\",\n          \"description\": \"Configures the logging system.\\n\",\n          \"markdownDescription\": \"Configures the logging system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the logging system.\\u003c/p\\u003e\\n\"\n        },\n        \"kernel\": {\n          \"$ref\": \"#/$defs/v1alpha1.KernelConfig\",\n          \"title\": \"kernel\",\n          \"description\": \"Configures the kernel.\\n\",\n          \"markdownDescription\": \"Configures the kernel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the kernel.\\u003c/p\\u003e\\n\"\n        },\n        \"seccompProfiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.MachineSeccompProfile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"seccompProfiles\",\n          \"description\": \"Configures the seccomp profiles for the machine.\\n\",\n          \"markdownDescription\": \"Configures the seccomp profiles for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the seccomp profiles for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"baseRuntimeSpecOverrides\": {\n          \"type\": \"object\",\n          \"title\": \"baseRuntimeSpecOverrides\",\n          \"description\": \"Override (patch) settings in the default OCI runtime spec for CRI containers.\\n\\nIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\\n\",\n          \"markdownDescription\": \"Override (patch) settings in the default OCI runtime spec for CRI containers.\\n\\nIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride (patch) settings in the default OCI runtime spec for CRI containers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeLabels\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeLabels\",\n          \"description\": \"Configures the node labels for the machine.\\n\\nNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see NodeRestriction admission plugin).\\n\",\n          \"markdownDescription\": \"Configures the node labels for the machine.\\n\\nNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node labels for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction\\\" target=\\\"_blank\\\"\\u003eNodeRestriction\\u003c/a\\u003e admission plugin).\\u003c/p\\u003e\\n\"\n        },\n        \"nodeAnnotations\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeAnnotations\",\n          \"description\": \"Configures the node annotations for the machine.\\n\",\n          \"markdownDescription\": \"Configures the node annotations for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node annotations for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeTaints\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeTaints\",\n          \"description\": \"Configures the node taints for the machine. Effect is optional.\\n\\nNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see NodeRestriction admission plugin).\\n\",\n          \"markdownDescription\": \"Configures the node taints for the machine. Effect is optional.\\n\\nNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node taints for the machine. Effect is optional.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction\\\" target=\\\"_blank\\\"\\u003eNodeRestriction\\u003c/a\\u003e admission plugin).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineConfig represents the machine-specific config values.\"\n    },\n    \"v1alpha1.MachineControlPlaneConfig\": {\n      \"properties\": {\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineSchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler machine specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineControlPlaneConfig machine specific configuration options.\"\n    },\n    \"v1alpha1.MachineControllerManagerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-controller-manager on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-controller-manager on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-controller-manager on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineControllerManagerConfig represents the machine specific ControllerManager config values.\"\n    },\n    \"v1alpha1.MachineFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The contents of the file.\\n\",\n          \"markdownDescription\": \"The contents of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe contents of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"permissions\": {\n          \"type\": \"integer\",\n          \"title\": \"permissions\",\n          \"description\": \"The file’s permissions in octal.\\n\",\n          \"markdownDescription\": \"The file's permissions in octal.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe file\\u0026rsquo;s permissions in octal.\\u003c/p\\u003e\\n\"\n        },\n        \"path\": {\n          \"type\": \"string\",\n          \"title\": \"path\",\n          \"description\": \"The path of the file.\\n\",\n          \"markdownDescription\": \"The path of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe path of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"op\": {\n          \"enum\": [\n            \"create\",\n            \"append\",\n            \"overwrite\"\n          ],\n          \"title\": \"op\",\n          \"description\": \"The operation to use\\n\",\n          \"markdownDescription\": \"The operation to use\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe operation to use\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineFile represents a file to write to disk.\"\n    },\n    \"v1alpha1.MachineSchedulerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-scheduler on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-scheduler on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-scheduler on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineSchedulerConfig represents the machine specific Scheduler config values.\"\n    },\n    \"v1alpha1.MachineSeccompProfile\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"The name field is used to provide the file name of the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `name` field is used to provide the file name of the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003ename\\u003c/code\\u003e field is used to provide the file name of the seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"value\": {\n          \"type\": \"object\",\n          \"title\": \"value\",\n          \"description\": \"The value field is used to provide the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `value` field is used to provide the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalue\\u003c/code\\u003e field is used to provide the seccomp profile.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineSeccompProfile defines seccomp profiles for the machine.\"\n    },\n    \"v1alpha1.ProxyConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-proxy deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable kube-proxy deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-proxy deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the kube-proxy manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the kube-proxy manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the kube-proxy manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"proxy mode of kube-proxy.\\nThe default is ‘iptables’.\\n\",\n          \"markdownDescription\": \"proxy mode of kube-proxy.\\nThe default is 'iptables'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eproxy mode of kube-proxy.\\nThe default is \\u0026lsquo;iptables\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to kube-proxy.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to kube-proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to kube-proxy.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ProxyConfig represents the kube proxy configuration options.\"\n    },\n    \"v1alpha1.RegistryKubernetesConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable Kubernetes discovery registry.\\n\",\n          \"markdownDescription\": \"Disable Kubernetes discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable Kubernetes discovery registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RegistryKubernetesConfig struct configures Kubernetes discovery registry.\"\n    },\n    \"v1alpha1.RegistryServiceConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable external service discovery registry.\\n\",\n          \"markdownDescription\": \"Disable external service discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable external service discovery registry.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"External service endpoint.\\n\",\n          \"markdownDescription\": \"External service endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal service endpoint.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RegistryServiceConfig struct configures Kubernetes discovery registry.\"\n    },\n    \"v1alpha1.ResourcesConfig\": {\n      \"properties\": {\n        \"requests\": {\n          \"type\": \"object\",\n          \"title\": \"requests\",\n          \"description\": \"Requests configures the reserved cpu/memory resources.\\n\",\n          \"markdownDescription\": \"Requests configures the reserved cpu/memory resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRequests configures the reserved cpu/memory resources.\\u003c/p\\u003e\\n\"\n        },\n        \"limits\": {\n          \"type\": \"object\",\n          \"title\": \"limits\",\n          \"description\": \"Limits configures the maximum cpu/memory resources a container can use.\\n\",\n          \"markdownDescription\": \"Limits configures the maximum cpu/memory resources a container can use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLimits configures the maximum cpu/memory resources a container can use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ResourcesConfig represents the pod resources.\"\n    },\n    \"v1alpha1.SchedulerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the scheduler manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the scheduler manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the scheduler manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the scheduler.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the scheduler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the scheduler.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the scheduler static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the scheduler static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the scheduler static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the scheduler resources.\\n\",\n          \"markdownDescription\": \"Configure the scheduler resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the scheduler resources.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specify custom kube-scheduler configuration.\\n\",\n          \"markdownDescription\": \"Specify custom kube-scheduler configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecify custom kube-scheduler configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"SchedulerConfig represents the kube scheduler configuration options.\"\n    },\n    \"v1alpha1.UdevConfig\": {\n      \"properties\": {\n        \"rules\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"rules\",\n          \"description\": \"List of udev rules to apply to the udev system\\n\",\n          \"markdownDescription\": \"List of udev rules to apply to the udev system\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of udev rules to apply to the udev system\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"UdevConfig describes how the udev system should be configured.\"\n    },\n    \"v1alpha1.VolumeMountConfig\": {\n      \"properties\": {\n        \"hostPath\": {\n          \"type\": \"string\",\n          \"title\": \"hostPath\",\n          \"description\": \"Path on the host.\\n\",\n          \"markdownDescription\": \"Path on the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath on the host.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"Path in the container.\\n\",\n          \"markdownDescription\": \"Path in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"readonly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readonly\",\n          \"description\": \"Mount the volume read only.\\n\",\n          \"markdownDescription\": \"Mount the volume read only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read only.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeMountConfig struct describes extra volume mount for the static pods.\"\n    }\n  },\n  \"oneOf\": [\n    {\n      \"$ref\": \"#/$defs/block.ExistingVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.ExternalVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.RawVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.SwapVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.UserVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.VolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.ZswapConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryAuthConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryMirrorConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryTLSConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/extensions.ServiceConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/hardware.PCIDriverRebindConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BlackholeRouteConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BondConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BridgeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DefaultActionConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DHCPv4ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DHCPv6ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DummyLinkConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.EthernetConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.HCloudVIPConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.HostnameConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.KubeSpanConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.KubespanEndpointsConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.Layer2VIPConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.LinkConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.LinkAliasConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.ResolverConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.RoutingRuleConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.RuleConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.StaticHostConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.TCPProbeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.TimeSyncConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.VLANConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.VRFConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.WireguardConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.EnvironmentV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.EventSinkV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.KmsgLogV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.OOMV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.WatchdogTimerV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/security.TrustedRootsConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/siderolink.ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/v1alpha1.Config\"\n    }\n  ]\n}"
  },
  {
    "path": "pkg/machinery/config/schemas/v1alpha1_config.schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://talos.dev/v1.6/schemas/v1alpha1_config.schema.json\",\n  \"$ref\": \"#/$defs/Config\",\n  \"$defs\": {\n    \"APIServerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the API server manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the API server manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the API server manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the API server.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the API server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the API server.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the API server static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the API server static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the API server static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the API server’s certificate.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the API server's certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the API server\\u0026rsquo;s certificate.\\u003c/p\\u003e\\n\"\n        },\n        \"disablePodSecurityPolicy\": {\n          \"type\": \"boolean\",\n          \"title\": \"disablePodSecurityPolicy\",\n          \"description\": \"Disable PodSecurityPolicy in the API server and default manifests.\\n\",\n          \"markdownDescription\": \"Disable PodSecurityPolicy in the API server and default manifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable PodSecurityPolicy in the API server and default manifests.\\u003c/p\\u003e\\n\"\n        },\n        \"admissionControl\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/AdmissionPluginConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"admissionControl\",\n          \"description\": \"Configure the API server admission plugins.\\n\",\n          \"markdownDescription\": \"Configure the API server admission plugins.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server admission plugins.\\u003c/p\\u003e\\n\"\n        },\n        \"auditPolicy\": {\n          \"type\": \"object\",\n          \"title\": \"auditPolicy\",\n          \"description\": \"Configure the API server audit policy.\\n\",\n          \"markdownDescription\": \"Configure the API server audit policy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server audit policy.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the API server resources.\\n\",\n          \"markdownDescription\": \"Configure the API server resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"AdminKubeconfigConfig\": {\n      \"properties\": {\n        \"certLifetime\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"certLifetime\",\n          \"description\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdmin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"AdmissionPluginConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\\n\",\n          \"markdownDescription\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is the name of the admission controller.\\nIt must match the registered admission plugin name.\\u003c/p\\u003e\\n\"\n        },\n        \"configuration\": {\n          \"type\": \"object\",\n          \"title\": \"configuration\",\n          \"description\": \"Configuration is an embedded configuration object to be used as the plugin’s\\nconfiguration.\\n\",\n          \"markdownDescription\": \"Configuration is an embedded configuration object to be used as the plugin's\\nconfiguration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration is an embedded configuration object to be used as the plugin\\u0026rsquo;s\\nconfiguration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Bond\": {\n      \"properties\": {\n        \"interfaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"The interfaces that make up the bond.\\n\",\n          \"markdownDescription\": \"The interfaces that make up the bond.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interfaces that make up the bond.\\u003c/p\\u003e\\n\"\n        },\n        \"deviceSelectors\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/NetworkDeviceSelector\"\n          },\n          \"type\": \"array\",\n          \"title\": \"deviceSelectors\",\n          \"description\": \"Picks a network device using the selector.\\nMutually exclusive with interfaces.\\nSupports partial match using wildcard syntax.\\n\",\n          \"markdownDescription\": \"Picks a network device using the selector.\\nMutually exclusive with `interfaces`.\\nSupports partial match using wildcard syntax.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePicks a network device using the selector.\\nMutually exclusive with \\u003ccode\\u003einterfaces\\u003c/code\\u003e.\\nSupports partial match using wildcard syntax.\\u003c/p\\u003e\\n\"\n        },\n        \"arpIPTarget\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"arpIPTarget\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"xmitHashPolicy\": {\n          \"type\": \"string\",\n          \"title\": \"xmitHashPolicy\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"lacpRate\": {\n          \"type\": \"string\",\n          \"title\": \"lacpRate\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSystem\": {\n          \"type\": \"string\",\n          \"title\": \"adActorSystem\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\u003c/p\\u003e\\n\"\n        },\n        \"arpValidate\": {\n          \"type\": \"string\",\n          \"title\": \"arpValidate\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"arpAllTargets\": {\n          \"type\": \"string\",\n          \"title\": \"arpAllTargets\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"primary\": {\n          \"type\": \"string\",\n          \"title\": \"primary\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"primaryReselect\": {\n          \"type\": \"string\",\n          \"title\": \"primaryReselect\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"failOverMac\": {\n          \"type\": \"string\",\n          \"title\": \"failOverMac\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adSelect\": {\n          \"type\": \"string\",\n          \"title\": \"adSelect\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"miimon\": {\n          \"type\": \"integer\",\n          \"title\": \"miimon\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"updelay\": {\n          \"type\": \"integer\",\n          \"title\": \"updelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"downdelay\": {\n          \"type\": \"integer\",\n          \"title\": \"downdelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"arpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"arpInterval\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"resendIgmp\": {\n          \"type\": \"integer\",\n          \"title\": \"resendIgmp\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"minLinks\": {\n          \"type\": \"integer\",\n          \"title\": \"minLinks\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"lpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"lpInterval\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"packetsPerSlave\": {\n          \"type\": \"integer\",\n          \"title\": \"packetsPerSlave\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"numPeerNotif\": {\n          \"type\": \"integer\",\n          \"title\": \"numPeerNotif\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"tlbDynamicLb\": {\n          \"type\": \"integer\",\n          \"title\": \"tlbDynamicLb\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"allSlavesActive\": {\n          \"type\": \"integer\",\n          \"title\": \"allSlavesActive\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"useCarrier\": {\n          \"type\": \"boolean\",\n          \"title\": \"useCarrier\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSysPrio\": {\n          \"type\": \"integer\",\n          \"title\": \"adActorSysPrio\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adUserPortKey\": {\n          \"type\": \"integer\",\n          \"title\": \"adUserPortKey\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"peerNotifyDelay\": {\n          \"type\": \"integer\",\n          \"title\": \"peerNotifyDelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Bridge\": {\n      \"properties\": {\n        \"interfaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"The interfaces that make up the bridge.\\n\",\n          \"markdownDescription\": \"The interfaces that make up the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interfaces that make up the bridge.\\u003c/p\\u003e\\n\"\n        },\n        \"stp\": {\n          \"$ref\": \"#/$defs/STP\",\n          \"title\": \"stp\",\n          \"description\": \"A bridge option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bridge option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bridge option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"CNIConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"enum\": [\n            \"flannel\",\n            \"custom\",\n            \"none\"\n          ],\n          \"title\": \"name\",\n          \"description\": \"Name of CNI to use.\\n\",\n          \"markdownDescription\": \"Name of CNI to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of CNI to use.\\u003c/p\\u003e\\n\"\n        },\n        \"urls\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"urls\",\n          \"description\": \"URLs containing manifests to apply for the CNI.\\nShould be present for “custom”, must be empty for “flannel” and “none”.\\n\",\n          \"markdownDescription\": \"URLs containing manifests to apply for the CNI.\\nShould be present for \\\"custom\\\", must be empty for \\\"flannel\\\" and \\\"none\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eURLs containing manifests to apply for the CNI.\\nShould be present for \\u0026ldquo;custom\\u0026rdquo;, must be empty for \\u0026ldquo;flannel\\u0026rdquo; and \\u0026ldquo;none\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"flannel\": {\n          \"$ref\": \"#/$defs/FlannelCNIConfig\",\n          \"title\": \"flannel\",\n          \"description\": \"description: |\\nFlannel configuration options.\\n\",\n          \"markdownDescription\": \"description: |\\nFlannel configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\nFlannel configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterConfig\": {\n      \"properties\": {\n        \"id\": {\n          \"type\": \"string\",\n          \"title\": \"id\",\n          \"description\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\\n\",\n          \"markdownDescription\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eGlobally unique identifier for this cluster (base64 encoded random 32 bytes).\\u003c/p\\u003e\\n\"\n        },\n        \"secret\": {\n          \"type\": \"string\",\n          \"title\": \"secret\",\n          \"description\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\n\",\n          \"markdownDescription\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/ControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides control plane specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides control plane specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides control plane specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterName\": {\n          \"type\": \"string\",\n          \"title\": \"clusterName\",\n          \"description\": \"Configures the cluster’s name.\\n\",\n          \"markdownDescription\": \"Configures the cluster's name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the cluster\\u0026rsquo;s name.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/ClusterNetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides cluster specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The bootstrap token used to join the cluster.\\n\",\n          \"markdownDescription\": \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/\\\" target=\\\"_blank\\\"\\u003ebootstrap token\\u003c/a\\u003e used to join the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"aescbcEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"aescbcEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"secretboxEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"secretboxEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The base64 encoded root certificate authority used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The base64 encoded root certificate authority used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded root certificate authority used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"aggregatorCA\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"aggregatorCA\",\n          \"description\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\\n\",\n          \"markdownDescription\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis CA can be self-signed.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceAccount\": {\n          \"properties\": {\n            \"key\": {\n              \"additionalProperties\": false,\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"serviceAccount\",\n          \"description\": \"The base64 encoded private key for service account token generation.\\n\",\n          \"markdownDescription\": \"The base64 encoded private key for service account token generation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded private key for service account token generation.\\u003c/p\\u003e\\n\"\n        },\n        \"apiServer\": {\n          \"$ref\": \"#/$defs/APIServerConfig\",\n          \"title\": \"apiServer\",\n          \"description\": \"API server specific configuration options.\\n\",\n          \"markdownDescription\": \"API server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAPI server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/ControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager server specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"proxy\": {\n          \"$ref\": \"#/$defs/ProxyConfig\",\n          \"title\": \"proxy\",\n          \"description\": \"Kube-proxy server-specific configuration options\\n\",\n          \"markdownDescription\": \"Kube-proxy server-specific configuration options\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKube-proxy server-specific configuration options\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/SchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler server specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/ClusterDiscoveryConfig\",\n          \"title\": \"discovery\",\n          \"description\": \"Configures cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configures cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures cluster member discovery.\\u003c/p\\u003e\\n\"\n        },\n        \"etcd\": {\n          \"$ref\": \"#/$defs/EtcdConfig\",\n          \"title\": \"etcd\",\n          \"description\": \"Etcd specific configuration options.\\n\",\n          \"markdownDescription\": \"Etcd specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEtcd specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"coreDNS\": {\n          \"$ref\": \"#/$defs/CoreDNS\",\n          \"title\": \"coreDNS\",\n          \"description\": \"Core DNS specific configuration options.\\n\",\n          \"markdownDescription\": \"Core DNS specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCore DNS specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"externalCloudProvider\": {\n          \"$ref\": \"#/$defs/ExternalCloudProviderConfig\",\n          \"title\": \"externalCloudProvider\",\n          \"description\": \"External cloud provider configuration.\\n\",\n          \"markdownDescription\": \"External cloud provider configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal cloud provider configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraManifests\",\n          \"description\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifestHeaders\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraManifestHeaders\",\n          \"description\": \"A map of key value pairs that will be added while fetching the extraManifests.\\n\",\n          \"markdownDescription\": \"A map of key value pairs that will be added while fetching the extraManifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA map of key value pairs that will be added while fetching the extraManifests.\\u003c/p\\u003e\\n\"\n        },\n        \"inlineManifests\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ClusterInlineManifest\"\n          },\n          \"type\": \"array\",\n          \"title\": \"inlineManifests\",\n          \"description\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"adminKubeconfig\": {\n          \"$ref\": \"#/$defs/AdminKubeconfigConfig\",\n          \"title\": \"adminKubeconfig\",\n          \"description\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\n\",\n          \"markdownDescription\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSettings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\u003c/p\\u003e\\n\"\n        },\n        \"allowSchedulingOnControlPlanes\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowSchedulingOnControlPlanes\",\n          \"description\": \"Allows running workload on control-plane nodes.\\n\",\n          \"markdownDescription\": \"Allows running workload on control-plane nodes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows running workload on control-plane nodes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterDiscoveryConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\n\",\n          \"markdownDescription\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/DiscoveryRegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Configure registries used for cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configure registries used for cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure registries used for cluster member discovery.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterInlineManifest\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the manifest.\\nName should be unique.\\n\",\n          \"markdownDescription\": \"Name of the manifest.\\nName should be unique.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the manifest.\\nName should be unique.\\u003c/p\\u003e\\n\"\n        },\n        \"contents\": {\n          \"type\": \"string\",\n          \"title\": \"contents\",\n          \"description\": \"Manifest contents as a string.\\n\",\n          \"markdownDescription\": \"Manifest contents as a string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eManifest contents as a string.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterNetworkConfig\": {\n      \"properties\": {\n        \"cni\": {\n          \"$ref\": \"#/$defs/CNIConfig\",\n          \"title\": \"cni\",\n          \"description\": \"The CNI used.\\nComposed of “name” and “urls”.\\nThe “name” key supports the following options: “flannel”, “custom”, and “none”.\\n“flannel” uses Talos-managed Flannel CNI, and that’s the default option.\\n“custom” uses custom manifests that should be provided in “urls”.\\n“none” indicates that Talos will not manage any CNI installation.\\n\",\n          \"markdownDescription\": \"The CNI used.\\nComposed of \\\"name\\\" and \\\"urls\\\".\\nThe \\\"name\\\" key supports the following options: \\\"flannel\\\", \\\"custom\\\", and \\\"none\\\".\\n\\\"flannel\\\" uses Talos-managed Flannel CNI, and that's the default option.\\n\\\"custom\\\" uses custom manifests that should be provided in \\\"urls\\\".\\n\\\"none\\\" indicates that Talos will not manage any CNI installation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe CNI used.\\nComposed of \\u0026ldquo;name\\u0026rdquo; and \\u0026ldquo;urls\\u0026rdquo;.\\nThe \\u0026ldquo;name\\u0026rdquo; key supports the following options: \\u0026ldquo;flannel\\u0026rdquo;, \\u0026ldquo;custom\\u0026rdquo;, and \\u0026ldquo;none\\u0026rdquo;.\\n\\u0026ldquo;flannel\\u0026rdquo; uses Talos-managed Flannel CNI, and that\\u0026rsquo;s the default option.\\n\\u0026ldquo;custom\\u0026rdquo; uses custom manifests that should be provided in \\u0026ldquo;urls\\u0026rdquo;.\\n\\u0026ldquo;none\\u0026rdquo; indicates that Talos will not manage any CNI installation.\\u003c/p\\u003e\\n\"\n        },\n        \"dnsDomain\": {\n          \"type\": \"string\",\n          \"title\": \"dnsDomain\",\n          \"description\": \"The domain used by Kubernetes DNS.\\nThe default is cluster.local\\n\",\n          \"markdownDescription\": \"The domain used by Kubernetes DNS.\\nThe default is `cluster.local`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe domain used by Kubernetes DNS.\\nThe default is \\u003ccode\\u003ecluster.local\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"podSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"podSubnets\",\n          \"description\": \"The pod subnet CIDR.\\n\",\n          \"markdownDescription\": \"The pod subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe pod subnet CIDR.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"serviceSubnets\",\n          \"description\": \"The service subnet CIDR.\\n\",\n          \"markdownDescription\": \"The service subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe service subnet CIDR.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Config\": {\n      \"properties\": {\n        \"version\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"version\",\n          \"description\": \"Indicates the schema used to decode the contents.\\n\",\n          \"markdownDescription\": \"Indicates the schema used to decode the contents.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates the schema used to decode the contents.\\u003c/p\\u003e\\n\"\n        },\n        \"debug\": {\n          \"type\": \"boolean\",\n          \"title\": \"debug\",\n          \"description\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\nNote: To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\n\",\n          \"markdownDescription\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\n**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eNote:\\u003c/strong\\u003e To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\u003c/p\\u003e\\n\"\n        },\n        \"machine\": {\n          \"$ref\": \"#/$defs/MachineConfig\",\n          \"title\": \"machine\",\n          \"description\": \"Provides machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"cluster\": {\n          \"$ref\": \"#/$defs/ClusterConfig\",\n          \"title\": \"cluster\",\n          \"description\": \"Provides cluster specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ControlPlaneConfig\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^https://\",\n          \"format\": \"uri\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\n\",\n          \"markdownDescription\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\u003c/p\\u003e\\n\"\n        },\n        \"localAPIServerPort\": {\n          \"type\": \"integer\",\n          \"title\": \"localAPIServerPort\",\n          \"description\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is 6443.\\n\",\n          \"markdownDescription\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is `6443`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is \\u003ccode\\u003e6443\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ControllerManagerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the controller manager manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the controller manager manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the controller manager manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the controller manager.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the controller manager.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the controller manager.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the controller manager static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the controller manager static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the controller manager static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the controller manager resources.\\n\",\n          \"markdownDescription\": \"Configure the controller manager resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the controller manager resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"CoreDNS\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable coredns deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable coredns deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable coredns deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an override to the default coredns image.\\n\",\n          \"markdownDescription\": \"The `image` field is an override to the default coredns image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an override to the default coredns image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DHCPOptions\": {\n      \"properties\": {\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"The priority of all routes received via DHCP.\\n\",\n          \"markdownDescription\": \"The priority of all routes received via DHCP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe priority of all routes received via DHCP.\\u003c/p\\u003e\\n\"\n        },\n        \"ipv4\": {\n          \"type\": \"boolean\",\n          \"title\": \"ipv4\",\n          \"description\": \"Enables DHCPv4 protocol for the interface (default is enabled).\\n\",\n          \"markdownDescription\": \"Enables DHCPv4 protocol for the interface (default is enabled).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables DHCPv4 protocol for the interface (default is enabled).\\u003c/p\\u003e\\n\"\n        },\n        \"ipv6\": {\n          \"type\": \"boolean\",\n          \"title\": \"ipv6\",\n          \"description\": \"Enables DHCPv6 protocol for the interface (default is disabled).\\n\",\n          \"markdownDescription\": \"Enables DHCPv6 protocol for the interface (default is disabled).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables DHCPv6 protocol for the interface (default is disabled).\\u003c/p\\u003e\\n\"\n        },\n        \"duidv6\": {\n          \"type\": \"string\",\n          \"title\": \"duidv6\",\n          \"description\": \"Set client DUID (hex string).\\n\",\n          \"markdownDescription\": \"Set client DUID (hex string).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet client DUID (hex string).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Device\": {\n      \"properties\": {\n        \"interface\": {\n          \"type\": \"string\",\n          \"title\": \"interface\",\n          \"description\": \"The interface name.\\nMutually exclusive with deviceSelector.\\n\",\n          \"markdownDescription\": \"The interface name.\\nMutually exclusive with `deviceSelector`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interface name.\\nMutually exclusive with \\u003ccode\\u003edeviceSelector\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"deviceSelector\": {\n          \"$ref\": \"#/$defs/NetworkDeviceSelector\",\n          \"title\": \"deviceSelector\",\n          \"description\": \"Picks a network device using the selector.\\nMutually exclusive with interface.\\nSupports partial match using wildcard syntax.\\n\",\n          \"markdownDescription\": \"Picks a network device using the selector.\\nMutually exclusive with `interface`.\\nSupports partial match using wildcard syntax.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePicks a network device using the selector.\\nMutually exclusive with \\u003ccode\\u003einterface\\u003c/code\\u003e.\\nSupports partial match using wildcard syntax.\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Assigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\\n\",\n          \"markdownDescription\": \"Assigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAssigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Route\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"A list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\\n\",\n          \"markdownDescription\": \"A list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"bond\": {\n          \"$ref\": \"#/$defs/Bond\",\n          \"title\": \"bond\",\n          \"description\": \"Bond specific options.\\n\",\n          \"markdownDescription\": \"Bond specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBond specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"bridge\": {\n          \"$ref\": \"#/$defs/Bridge\",\n          \"title\": \"bridge\",\n          \"description\": \"Bridge specific options.\\n\",\n          \"markdownDescription\": \"Bridge specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"vlans\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Vlan\"\n          },\n          \"type\": \"array\",\n          \"title\": \"vlans\",\n          \"description\": \"VLAN specific options.\\n\",\n          \"markdownDescription\": \"VLAN specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVLAN specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The interface’s MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\\n\",\n          \"markdownDescription\": \"The interface's MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interface\\u0026rsquo;s MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcp\": {\n          \"type\": \"boolean\",\n          \"title\": \"dhcp\",\n          \"description\": \"Indicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\n\\n\\nOptionClasslessStaticRoute\\nOptionDomainNameServer\\nOptionDNSDomainSearchList\\nOptionHostName\\n\\n\",\n          \"markdownDescription\": \"Indicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\n\\n- `OptionClasslessStaticRoute`\\n- `OptionDomainNameServer`\\n- `OptionDNSDomainSearchList`\\n- `OptionHostName`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionClasslessStaticRoute\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionDomainNameServer\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionDNSDomainSearchList\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionHostName\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"ignore\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignore\",\n          \"description\": \"Indicates if the interface should be ignored (skips configuration).\\n\",\n          \"markdownDescription\": \"Indicates if the interface should be ignored (skips configuration).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the interface should be ignored (skips configuration).\\u003c/p\\u003e\\n\"\n        },\n        \"dummy\": {\n          \"type\": \"boolean\",\n          \"title\": \"dummy\",\n          \"description\": \"Indicates if the interface is a dummy interface.\\ndummy is used to specify that this interface should be a virtual-only, dummy interface.\\n\",\n          \"markdownDescription\": \"Indicates if the interface is a dummy interface.\\n`dummy` is used to specify that this interface should be a virtual-only, dummy interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the interface is a dummy interface.\\n\\u003ccode\\u003edummy\\u003c/code\\u003e is used to specify that this interface should be a virtual-only, dummy interface.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcpOptions\": {\n          \"$ref\": \"#/$defs/DHCPOptions\",\n          \"title\": \"dhcpOptions\",\n          \"description\": \"DHCP specific options.\\ndhcp must be set to true for these to take effect.\\n\",\n          \"markdownDescription\": \"DHCP specific options.\\n`dhcp` *must* be set to true for these to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDHCP specific options.\\n\\u003ccode\\u003edhcp\\u003c/code\\u003e \\u003cem\\u003emust\\u003c/em\\u003e be set to true for these to take effect.\\u003c/p\\u003e\\n\"\n        },\n        \"wireguard\": {\n          \"$ref\": \"#/$defs/DeviceWireguardConfig\",\n          \"title\": \"wireguard\",\n          \"description\": \"Wireguard specific configuration.\\nIncludes things like private key, listen port, peers.\\n\",\n          \"markdownDescription\": \"Wireguard specific configuration.\\nIncludes things like private key, listen port, peers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWireguard specific configuration.\\nIncludes things like private key, listen port, peers.\\u003c/p\\u003e\\n\"\n        },\n        \"vip\": {\n          \"$ref\": \"#/$defs/DeviceVIPConfig\",\n          \"title\": \"vip\",\n          \"description\": \"Virtual (shared) IP address configuration.\\n\",\n          \"markdownDescription\": \"Virtual (shared) IP address configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVirtual (shared) IP address configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceVIPConfig\": {\n      \"properties\": {\n        \"ip\": {\n          \"type\": \"string\",\n          \"title\": \"ip\",\n          \"description\": \"Specifies the IP address to be used.\\n\",\n          \"markdownDescription\": \"Specifies the IP address to be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the IP address to be used.\\u003c/p\\u003e\\n\"\n        },\n        \"equinixMetal\": {\n          \"$ref\": \"#/$defs/VIPEquinixMetalConfig\",\n          \"title\": \"equinixMetal\",\n          \"description\": \"Specifies the Equinix Metal API settings to assign VIP to the node.\\n\",\n          \"markdownDescription\": \"Specifies the Equinix Metal API settings to assign VIP to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Equinix Metal API settings to assign VIP to the node.\\u003c/p\\u003e\\n\"\n        },\n        \"hcloud\": {\n          \"$ref\": \"#/$defs/VIPHCloudConfig\",\n          \"title\": \"hcloud\",\n          \"description\": \"Specifies the Hetzner Cloud API settings to assign VIP to the node.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API settings to assign VIP to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API settings to assign VIP to the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceWireguardConfig\": {\n      \"properties\": {\n        \"privateKey\": {\n          \"type\": \"string\",\n          \"title\": \"privateKey\",\n          \"description\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by wg genkey.\\n\",\n          \"markdownDescription\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by `wg genkey`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a private key configuration (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genkey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"listenPort\": {\n          \"type\": \"integer\",\n          \"title\": \"listenPort\",\n          \"description\": \"Specifies a device’s listening port.\\n\",\n          \"markdownDescription\": \"Specifies a device's listening port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s listening port.\\u003c/p\\u003e\\n\"\n        },\n        \"firewallMark\": {\n          \"type\": \"integer\",\n          \"title\": \"firewallMark\",\n          \"description\": \"Specifies a device’s firewall mark.\\n\",\n          \"markdownDescription\": \"Specifies a device's firewall mark.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s firewall mark.\\u003c/p\\u003e\\n\"\n        },\n        \"peers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/DeviceWireguardPeer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"peers\",\n          \"description\": \"Specifies a list of peer configurations to apply to a device.\\n\",\n          \"markdownDescription\": \"Specifies a list of peer configurations to apply to a device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a list of peer configurations to apply to a device.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceWireguardPeer\": {\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\",\n          \"title\": \"publicKey\",\n          \"description\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running wg pubkey \\u0026lt; private.key \\u0026gt; public.key \\u0026amp;\\u0026amp; cat public.key.\\n\",\n          \"markdownDescription\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running `wg pubkey \\u003c private.key \\u003e public.key \\u0026\\u0026 cat public.key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the public key of this peer.\\nCan be extracted from private key by running \\u003ccode\\u003ewg pubkey \\u0026lt; private.key \\u0026gt; public.key \\u0026amp;\\u0026amp; cat public.key\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"Specifies the endpoint of this peer entry.\\n\",\n          \"markdownDescription\": \"Specifies the endpoint of this peer entry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the endpoint of this peer entry.\\u003c/p\\u003e\\n\"\n        },\n        \"persistentKeepaliveInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"persistentKeepaliveInterval\",\n          \"description\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        },\n        \"allowedIPs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedIPs\",\n          \"description\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\n\",\n          \"markdownDescription\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DiscoveryRegistriesConfig\": {\n      \"properties\": {\n        \"kubernetes\": {\n          \"$ref\": \"#/$defs/RegistryKubernetesConfig\",\n          \"title\": \"kubernetes\",\n          \"description\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\",\n          \"markdownDescription\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\u003c/p\\u003e\\n\"\n        },\n        \"service\": {\n          \"$ref\": \"#/$defs/RegistryServiceConfig\",\n          \"title\": \"service\",\n          \"description\": \"Service registry is using an external service to push and pull information about cluster members.\\n\",\n          \"markdownDescription\": \"Service registry is using an external service to push and pull information about cluster members.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eService registry is using an external service to push and pull information about cluster members.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DiskPartition\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"The size of partition: either bytes or human readable representation. If size: is omitted, the partition is sized to occupy the full disk.\\n\",\n          \"markdownDescription\": \"The size of partition: either bytes or human readable representation. If `size:` is omitted, the partition is sized to occupy the full disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe size of partition: either bytes or human readable representation. If \\u003ccode\\u003esize:\\u003c/code\\u003e is omitted, the partition is sized to occupy the full disk.\\u003c/p\\u003e\\n\"\n        },\n        \"mountpoint\": {\n          \"type\": \"string\",\n          \"title\": \"mountpoint\",\n          \"description\": \"Where to mount the partition.\\n\",\n          \"markdownDescription\": \"Where to mount the partition.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to mount the partition.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionConfig\": {\n      \"properties\": {\n        \"provider\": {\n          \"type\": \"string\",\n          \"title\": \"provider\",\n          \"description\": \"Encryption provider to use for the encryption.\\n\",\n          \"markdownDescription\": \"Encryption provider to use for the encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEncryption provider to use for the encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"keys\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/EncryptionKey\"\n          },\n          \"type\": \"array\",\n          \"title\": \"keys\",\n          \"description\": \"Defines the encryption keys generation and storage method.\\n\",\n          \"markdownDescription\": \"Defines the encryption keys generation and storage method.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption keys generation and storage method.\\u003c/p\\u003e\\n\"\n        },\n        \"cipher\": {\n          \"enum\": [\n            \"aes-xts-plain64\",\n            \"xchacha12,aes-adiantum-plain64\",\n            \"xchacha20,aes-adiantum-plain64\"\n          ],\n          \"title\": \"cipher\",\n          \"description\": \"Cipher kind to use for the encryption. Depends on the encryption provider.\\n\",\n          \"markdownDescription\": \"Cipher kind to use for the encryption. Depends on the encryption provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCipher kind to use for the encryption. Depends on the encryption provider.\\u003c/p\\u003e\\n\"\n        },\n        \"keySize\": {\n          \"type\": \"integer\",\n          \"title\": \"keySize\",\n          \"description\": \"Defines the encryption key length.\\n\",\n          \"markdownDescription\": \"Defines the encryption key length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption key length.\\u003c/p\\u003e\\n\"\n        },\n        \"blockSize\": {\n          \"type\": \"integer\",\n          \"title\": \"blockSize\",\n          \"description\": \"Defines the encryption sector size.\\n\",\n          \"markdownDescription\": \"Defines the encryption sector size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption sector size.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"enum\": [\n            \"no_read_workqueue\",\n            \"no_write_workqueue\",\n            \"same_cpu_crypt\"\n          ],\n          \"title\": \"options\",\n          \"description\": \"Additional –perf parameters for the LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Additional --perf parameters for the LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdditional \\u0026ndash;perf parameters for the LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKey\": {\n      \"properties\": {\n        \"static\": {\n          \"$ref\": \"#/$defs/EncryptionKeyStatic\",\n          \"title\": \"static\",\n          \"description\": \"Key which value is stored in the configuration file.\\n\",\n          \"markdownDescription\": \"Key which value is stored in the configuration file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey which value is stored in the configuration file.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeID\": {\n          \"$ref\": \"#/$defs/EncryptionKeyNodeID\",\n          \"title\": \"nodeID\",\n          \"description\": \"Deterministically generated key from the node UUID and PartitionLabel.\\n\",\n          \"markdownDescription\": \"Deterministically generated key from the node UUID and PartitionLabel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeterministically generated key from the node UUID and PartitionLabel.\\u003c/p\\u003e\\n\"\n        },\n        \"kms\": {\n          \"$ref\": \"#/$defs/EncryptionKeyKMS\",\n          \"title\": \"kms\",\n          \"description\": \"KMS managed encryption key.\\n\",\n          \"markdownDescription\": \"KMS managed encryption key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS managed encryption key.\\u003c/p\\u003e\\n\"\n        },\n        \"slot\": {\n          \"type\": \"integer\",\n          \"title\": \"slot\",\n          \"description\": \"Key slot number for LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Key slot number for LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey slot number for LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"tpm\": {\n          \"$ref\": \"#/$defs/EncryptionKeyTPM\",\n          \"title\": \"tpm\",\n          \"description\": \"Enable TPM based disk encryption.\\n\",\n          \"markdownDescription\": \"Enable TPM based disk encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable TPM based disk encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyKMS\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"KMS endpoint to Seal/Unseal the key.\\n\",\n          \"markdownDescription\": \"KMS endpoint to Seal/Unseal the key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS endpoint to Seal/Unseal the key.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyNodeID\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyStatic\": {\n      \"properties\": {\n        \"passphrase\": {\n          \"type\": \"string\",\n          \"title\": \"passphrase\",\n          \"description\": \"Defines the static passphrase value.\\n\",\n          \"markdownDescription\": \"Defines the static passphrase value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the static passphrase value.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyTPM\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Endpoint\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EtcdConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used to create the etcd service.\\n\",\n          \"markdownDescription\": \"The container image used to create the etcd service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used to create the etcd service.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The ca is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The `ca` is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eca\\u003c/code\\u003e is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n\\nname\\ndata-dir\\ninitial-cluster-state\\nlisten-peer-urls\\nlisten-client-urls\\ncert-file\\nkey-file\\ntrusted-ca-file\\npeer-client-cert-auth\\npeer-cert-file\\npeer-trusted-ca-file\\npeer-key-file\\n\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n- `name`\\n- `data-dir`\\n- `initial-cluster-state`\\n- `listen-peer-urls`\\n- `listen-client-urls`\\n- `cert-file`\\n- `key-file`\\n- `trusted-ca-file`\\n- `peer-client-cert-auth`\\n- `peer-cert-file`\\n- `peer-trusted-ca-file`\\n- `peer-key-file`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to etcd.\\nNote that the following args are not allowed:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ename\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003edata-dir\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003einitial-cluster-state\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-peer-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-client-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ecert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ekey-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003etrusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-client-cert-auth\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-cert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-trusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-key-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"advertisedSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"advertisedSubnets\",\n          \"description\": \"The advertisedSubnets field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e field configures the networks to pick etcd advertised IP from.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        },\n        \"listenSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"listenSubnets\",\n          \"description\": \"The listenSubnets field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf listenSubnets is not set, but advertisedSubnets is set, listenSubnets defaults to\\nadvertisedSubnets.\\n\\nIf neither advertisedSubnets nor listenSubnets is set, listenSubnets defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\\n`advertisedSubnets`.\\n\\nIf neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e field configures the networks for the etcd to listen for peer and client connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is not set, but \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to\\n\\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf neither \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e nor \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to listen on all addresses.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExternalCloudProviderConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable external cloud provider.\\n\",\n          \"markdownDescription\": \"Enable external cloud provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable external cloud provider.\\u003c/p\\u003e\\n\"\n        },\n        \"manifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"manifests\",\n          \"description\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExtraHost\": {\n      \"properties\": {\n        \"ip\": {\n          \"type\": \"string\",\n          \"title\": \"ip\",\n          \"description\": \"The IP of the host.\\n\",\n          \"markdownDescription\": \"The IP of the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe IP of the host.\\u003c/p\\u003e\\n\"\n        },\n        \"aliases\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"aliases\",\n          \"description\": \"The host alias.\\n\",\n          \"markdownDescription\": \"The host alias.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe host alias.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExtraMount\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"title\": \"destination\",\n          \"description\": \"Destination is the absolute path where the mount will be placed in the container.\\n\",\n          \"markdownDescription\": \"Destination is the absolute path where the mount will be placed in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination is the absolute path where the mount will be placed in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type specifies the mount kind.\\n\",\n          \"markdownDescription\": \"Type specifies the mount kind.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType specifies the mount kind.\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"Source specifies the source path of the mount.\\n\",\n          \"markdownDescription\": \"Source specifies the source path of the mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource specifies the source path of the mount.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"options\",\n          \"description\": \"Options are fstab style mount options.\\n\",\n          \"markdownDescription\": \"Options are fstab style mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptions are fstab style mount options.\\u003c/p\\u003e\\n\"\n        },\n        \"uidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"uidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        },\n        \"gidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"gidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"FeaturesConfig\": {\n      \"properties\": {\n        \"rbac\": {\n          \"type\": \"boolean\",\n          \"title\": \"rbac\",\n          \"description\": \"Enable role-based access control (RBAC).\\n\",\n          \"markdownDescription\": \"Enable role-based access control (RBAC).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable role-based access control (RBAC).\\u003c/p\\u003e\\n\"\n        },\n        \"stableHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"stableHostname\",\n          \"description\": \"Enable stable default hostname.\\n\",\n          \"markdownDescription\": \"Enable stable default hostname.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable stable default hostname.\\u003c/p\\u003e\\n\"\n        },\n        \"kubernetesTalosAPIAccess\": {\n          \"$ref\": \"#/$defs/KubernetesTalosAPIAccessConfig\",\n          \"title\": \"kubernetesTalosAPIAccess\",\n          \"description\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\\n\",\n          \"markdownDescription\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is disabled if the feature config is not specified.\\u003c/p\\u003e\\n\"\n        },\n        \"apidCheckExtKeyUsage\": {\n          \"type\": \"boolean\",\n          \"title\": \"apidCheckExtKeyUsage\",\n          \"description\": \"Enable checks for extended key usage of client certificates in apid.\\n\",\n          \"markdownDescription\": \"Enable checks for extended key usage of client certificates in apid.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable checks for extended key usage of client certificates in apid.\\u003c/p\\u003e\\n\"\n        },\n        \"diskQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"diskQuotaSupport\",\n          \"description\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\n\",\n          \"markdownDescription\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\u003c/p\\u003e\\n\"\n        },\n        \"kubePrism\": {\n          \"$ref\": \"#/$defs/KubePrism\",\n          \"title\": \"kubePrism\",\n          \"description\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\n\",\n          \"markdownDescription\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"FlannelCNIConfig\": {\n      \"properties\": {\n        \"extraArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments for ‘flanneld’.\\n\",\n          \"markdownDescription\": \"Extra arguments for 'flanneld'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments for \\u0026lsquo;flanneld\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallConfig\": {\n      \"properties\": {\n        \"disk\": {\n          \"type\": \"string\",\n          \"title\": \"disk\",\n          \"description\": \"The disk used for installations.\\n\",\n          \"markdownDescription\": \"The disk used for installations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk used for installations.\\u003c/p\\u003e\\n\"\n        },\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/InstallDiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over disk.\\n\",\n          \"markdownDescription\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over `disk`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLook up disk using disk attributes like model, size, serial and others.\\nAlways has priority over \\u003ccode\\u003edisk\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraKernelArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraKernelArgs\",\n          \"description\": \"Allows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a -.\\nFor example -console removes all console=\\u0026lt;value\\u0026gt; arguments, whereas -console=tty0 removes the console=tty0 default argument.\\n\",\n          \"markdownDescription\": \"Allows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a `-`.\\nFor example `-console` removes all `console=\\u003cvalue\\u003e` arguments, whereas `-console=tty0` removes the `console=tty0` default argument.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a \\u003ccode\\u003e-\\u003c/code\\u003e.\\nFor example \\u003ccode\\u003e-console\\u003c/code\\u003e removes all \\u003ccode\\u003econsole=\\u0026lt;value\\u0026gt;\\u003c/code\\u003e arguments, whereas \\u003ccode\\u003e-console=tty0\\u003c/code\\u003e removes the \\u003ccode\\u003econsole=tty0\\u003c/code\\u003e default argument.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\nGitHub releases page.\\n\",\n          \"markdownDescription\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n[GitHub releases page](https://github.com/siderolabs/talos/releases).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n\\u003ca href=\\\"https://github.com/siderolabs/talos/releases\\\" target=\\\"_blank\\\"\\u003eGitHub releases page\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extensions\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/InstallExtensionConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extensions\",\n          \"description\": \"Allows for supplying additional system extension images to install on top of base Talos image.\\n\",\n          \"markdownDescription\": \"Allows for supplying additional system extension images to install on top of base Talos image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying additional system extension images to install on top of base Talos image.\\u003c/p\\u003e\\n\"\n        },\n        \"wipe\": {\n          \"type\": \"boolean\",\n          \"title\": \"wipe\",\n          \"description\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the installation disk should be wiped at installation time.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"legacyBIOSSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"legacyBIOSSupport\",\n          \"description\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn’t support GPT partitioning scheme.\\n\",\n          \"markdownDescription\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn\\u0026rsquo;t support GPT partitioning scheme.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallDiskSelector\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"string\",\n          \"title\": \"size\",\n          \"description\": \"Disk size.\\n\",\n          \"markdownDescription\": \"Disk size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk size.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Disk name /sys/block/\\u0026lt;dev\\u0026gt;/device/name.\\n\",\n          \"markdownDescription\": \"Disk name `/sys/block/\\u003cdev\\u003e/device/name`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk name \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/name\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"model\": {\n          \"type\": \"string\",\n          \"title\": \"model\",\n          \"description\": \"Disk model /sys/block/\\u0026lt;dev\\u0026gt;/device/model.\\n\",\n          \"markdownDescription\": \"Disk model `/sys/block/\\u003cdev\\u003e/device/model`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk model \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/model\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"serial\": {\n          \"type\": \"string\",\n          \"title\": \"serial\",\n          \"description\": \"Disk serial number /sys/block/\\u0026lt;dev\\u0026gt;/serial.\\n\",\n          \"markdownDescription\": \"Disk serial number `/sys/block/\\u003cdev\\u003e/serial`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk serial number \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/serial\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"modalias\": {\n          \"type\": \"string\",\n          \"title\": \"modalias\",\n          \"description\": \"Disk modalias /sys/block/\\u0026lt;dev\\u0026gt;/device/modalias.\\n\",\n          \"markdownDescription\": \"Disk modalias `/sys/block/\\u003cdev\\u003e/device/modalias`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk modalias \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/modalias\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"uuid\": {\n          \"type\": \"string\",\n          \"title\": \"uuid\",\n          \"description\": \"Disk UUID /sys/block/\\u0026lt;dev\\u0026gt;/uuid.\\n\",\n          \"markdownDescription\": \"Disk UUID `/sys/block/\\u003cdev\\u003e/uuid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk UUID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/uuid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wwid\": {\n          \"type\": \"string\",\n          \"title\": \"wwid\",\n          \"description\": \"Disk WWID /sys/block/\\u0026lt;dev\\u0026gt;/wwid.\\n\",\n          \"markdownDescription\": \"Disk WWID `/sys/block/\\u003cdev\\u003e/wwid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk WWID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/wwid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"enum\": [\n            \"ssd\",\n            \"hdd\",\n            \"nvme\",\n            \"sd\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Disk Type.\\n\",\n          \"markdownDescription\": \"Disk Type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk Type.\\u003c/p\\u003e\\n\"\n        },\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"Disk bus path.\\n\",\n          \"markdownDescription\": \"Disk bus path.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk bus path.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallExtensionConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"System extension image.\\n\",\n          \"markdownDescription\": \"System extension image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSystem extension image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KernelConfig\": {\n      \"properties\": {\n        \"modules\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/KernelModuleConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"modules\",\n          \"description\": \"Kernel modules to load.\\n\",\n          \"markdownDescription\": \"Kernel modules to load.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel modules to load.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KernelModuleConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Module name.\\n\",\n          \"markdownDescription\": \"Module name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule name.\\u003c/p\\u003e\\n\"\n        },\n        \"parameters\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"parameters\",\n          \"description\": \"Module parameters, changes applied after reboot.\\n\",\n          \"markdownDescription\": \"Module parameters, changes applied after reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule parameters, changes applied after reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubePrism\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable KubePrism support - will start local load balacing proxy.\\n\",\n          \"markdownDescription\": \"Enable KubePrism support - will start local load balacing proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable KubePrism support - will start local load balacing proxy.\\u003c/p\\u003e\\n\"\n        },\n        \"port\": {\n          \"type\": \"integer\",\n          \"title\": \"port\",\n          \"description\": \"KubePrism port.\\n\",\n          \"markdownDescription\": \"KubePrism port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism port.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeSpanFilters\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeletConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an optional reference to an alternative kubelet image.\\n\",\n          \"markdownDescription\": \"The `image` field is an optional reference to an alternative kubelet image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an optional reference to an alternative kubelet image.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterDNS\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"clusterDNS\",\n          \"description\": \"The ClusterDNS field is an optional reference to an alternative kubelet clusterDNS ip list.\\n\",\n          \"markdownDescription\": \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eClusterDNS\\u003c/code\\u003e field is an optional reference to an alternative kubelet clusterDNS ip list.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"The extraArgs field is used to provide additional flags to the kubelet.\\n\",\n          \"markdownDescription\": \"The `extraArgs` field is used to provide additional flags to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraArgs\\u003c/code\\u003e field is used to provide additional flags to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"extraMounts\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ExtraMount\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraMounts\",\n          \"description\": \"The extraMounts field is used to add additional mounts to the kubelet container.\\nNote that either bind or rbind are required in the options.\\n\",\n          \"markdownDescription\": \"The `extraMounts` field is used to add additional mounts to the kubelet container.\\nNote that either `bind` or `rbind` are required in the `options`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraMounts\\u003c/code\\u003e field is used to add additional mounts to the kubelet container.\\nNote that either \\u003ccode\\u003ebind\\u003c/code\\u003e or \\u003ccode\\u003erbind\\u003c/code\\u003e are required in the \\u003ccode\\u003eoptions\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraConfig\": {\n          \"type\": \"object\",\n          \"title\": \"extraConfig\",\n          \"description\": \"The extraConfig field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\n\",\n          \"markdownDescription\": \"The `extraConfig` field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraConfig\\u003c/code\\u003e field is used to provide kubelet configuration overrides.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\u003c/p\\u003e\\n\"\n        },\n        \"credentialProviderConfig\": {\n          \"type\": \"object\",\n          \"title\": \"credentialProviderConfig\",\n          \"description\": \"The KubeletCredentialProviderConfig field is used to provide kubelet credential configuration.\\n\",\n          \"markdownDescription\": \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eKubeletCredentialProviderConfig\\u003c/code\\u003e field is used to provide kubelet credential configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"defaultRuntimeSeccompProfileEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"defaultRuntimeSeccompProfileEnabled\",\n          \"description\": \"Enable container runtime default Seccomp profile.\\n\",\n          \"markdownDescription\": \"Enable container runtime default Seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable container runtime default Seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"registerWithFQDN\": {\n          \"type\": \"boolean\",\n          \"title\": \"registerWithFQDN\",\n          \"description\": \"The registerWithFQDN field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\n\",\n          \"markdownDescription\": \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eregisterWithFQDN\\u003c/code\\u003e field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeIP\": {\n          \"$ref\": \"#/$defs/KubeletNodeIPConfig\",\n          \"title\": \"nodeIP\",\n          \"description\": \"The nodeIP field is used to configure --node-ip flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\n\",\n          \"markdownDescription\": \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003enodeIP\\u003c/code\\u003e field is used to configure \\u003ccode\\u003e--node-ip\\u003c/code\\u003e flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\u003c/p\\u003e\\n\"\n        },\n        \"skipNodeRegistration\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipNodeRegistration\",\n          \"description\": \"The skipNodeRegistration is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\n\",\n          \"markdownDescription\": \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eskipNodeRegistration\\u003c/code\\u003e is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\u003c/p\\u003e\\n\"\n        },\n        \"disableManifestsDirectory\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableManifestsDirectory\",\n          \"description\": \"The disableManifestsDirectory field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt’s recommended to configure static pods with the “pods” key instead.\\n\",\n          \"markdownDescription\": \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt's recommended to configure static pods with the \\\"pods\\\" key instead.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003edisableManifestsDirectory\\u003c/code\\u003e field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt\\u0026rsquo;s recommended to configure static pods with the \\u0026ldquo;pods\\u0026rdquo; key instead.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeletNodeIPConfig\": {\n      \"properties\": {\n        \"validSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"validSubnets\",\n          \"description\": \"The validSubnets field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\n\",\n          \"markdownDescription\": \"The `validSubnets` field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalidSubnets\\u003c/code\\u003e field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubernetesTalosAPIAccessConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable Talos API access from Kubernetes pods.\\n\",\n          \"markdownDescription\": \"Enable Talos API access from Kubernetes pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedRoles\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedRoles\",\n          \"description\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\\n\",\n          \"markdownDescription\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Talos API roles which can be granted for access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEmpty list means that no roles can be granted, so access is blocked.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedKubernetesNamespaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedKubernetesNamespaces\",\n          \"description\": \"The list of Kubernetes namespaces Talos API access is available from.\\n\",\n          \"markdownDescription\": \"The list of Kubernetes namespaces Talos API access is available from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Kubernetes namespaces Talos API access is available from.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LinuxIDMapping\": {\n      \"properties\": {\n        \"containerID\": {\n          \"type\": \"integer\",\n          \"title\": \"containerID\",\n          \"description\": \"ContainerID is the starting UID/GID in the container.\\n\",\n          \"markdownDescription\": \"ContainerID is the starting UID/GID in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eContainerID is the starting UID/GID in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"hostID\": {\n          \"type\": \"integer\",\n          \"title\": \"hostID\",\n          \"description\": \"HostID is the starting UID/GID on the host to be mapped to ‘ContainerID’.\\n\",\n          \"markdownDescription\": \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHostID is the starting UID/GID on the host to be mapped to \\u0026lsquo;ContainerID\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"Size is the number of IDs to be mapped.\\n\",\n          \"markdownDescription\": \"Size is the number of IDs to be mapped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSize is the number of IDs to be mapped.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LoggingConfig\": {\n      \"properties\": {\n        \"destinations\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LoggingDestination\"\n          },\n          \"type\": \"array\",\n          \"title\": \"destinations\",\n          \"description\": \"Logging destination.\\n\",\n          \"markdownDescription\": \"Logging destination.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogging destination.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LoggingDestination\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"$ref\": \"#/$defs/Endpoint\",\n          \"title\": \"endpoint\",\n          \"description\": \"Where to send logs. Supported protocols are “tcp” and “udp”.\\n\",\n          \"markdownDescription\": \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to send logs. Supported protocols are \\u0026ldquo;tcp\\u0026rdquo; and \\u0026ldquo;udp\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"format\": {\n          \"enum\": [\n            \"json_lines\"\n          ],\n          \"title\": \"format\",\n          \"description\": \"Logs format.\\n\",\n          \"markdownDescription\": \"Logs format.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogs format.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"controlplane\",\n            \"worker\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Defines the role of the machine within the cluster.\\n\\nControl Plane\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\nWorker\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as “join”; that value is still supported but deprecated.\\n\",\n          \"markdownDescription\": \"Defines the role of the machine within the cluster.\\n\\n**Control Plane**\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\n**Worker**\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as \\\"join\\\"; that value is still supported but deprecated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the role of the machine within the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eControl Plane\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eWorker\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis node type was previously known as \\u0026ldquo;join\\u0026rdquo;; that value is still supported but deprecated.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The token is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its’ identity.\\n\",\n          \"markdownDescription\": \"The `token` is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003etoken\\u003c/code\\u003e is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its\\u0026rsquo; identity.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the machine’s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate’s SANs.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the machine's certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate's SANs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the machine\\u0026rsquo;s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate\\u0026rsquo;s SANs.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/MachineControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides machine specific control plane configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific control plane configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific control plane configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"kubelet\": {\n          \"$ref\": \"#/$defs/KubeletConfig\",\n          \"title\": \"kubelet\",\n          \"description\": \"Used to provide additional options to the kubelet.\\n\",\n          \"markdownDescription\": \"Used to provide additional options to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide additional options to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"pods\": {\n          \"items\": {\n            \"type\": \"object\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pods\",\n          \"description\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn’t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\\n\",\n          \"markdownDescription\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn't validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn\\u0026rsquo;t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee \\u003ca href=\\\"https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\\" target=\\\"_blank\\\"\\u003ehttps://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/NetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides machine specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"disks\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineDisk\"\n          },\n          \"type\": \"array\",\n          \"title\": \"disks\",\n          \"description\": \"Used to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of /var, mounts are only valid if they are under /var.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf size: is omitted, the partition is sized to occupy the full disk.\\n\",\n          \"markdownDescription\": \"Used to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of `/var`, mounts are only valid if they are under `/var`.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf `size:` is omitted, the partition is sized to occupy the full disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of \\u003ccode\\u003e/var\\u003c/code\\u003e, mounts are only valid if they are under \\u003ccode\\u003e/var\\u003c/code\\u003e.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf \\u003ccode\\u003esize:\\u003c/code\\u003e is omitted, the partition is sized to occupy the full disk.\\u003c/p\\u003e\\n\"\n        },\n        \"install\": {\n          \"$ref\": \"#/$defs/InstallConfig\",\n          \"title\": \"install\",\n          \"description\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\n\",\n          \"markdownDescription\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide instructions for installations.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\u003c/p\\u003e\\n\"\n        },\n        \"files\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"files\",\n          \"description\": \"Allows the addition of user specified files.\\nThe value of op can be create, overwrite, or append.\\nIn the case of create, path must not exist.\\nIn the case of overwrite, and append, path must be a valid file.\\nIf an op value of append is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\n\",\n          \"markdownDescription\": \"Allows the addition of user specified files.\\nThe value of `op` can be `create`, `overwrite`, or `append`.\\nIn the case of `create`, `path` must not exist.\\nIn the case of `overwrite`, and `append`, `path` must be a valid file.\\nIf an `op` value of `append` is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows the addition of user specified files.\\nThe value of \\u003ccode\\u003eop\\u003c/code\\u003e can be \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, or \\u003ccode\\u003eappend\\u003c/code\\u003e.\\nIn the case of \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must not exist.\\nIn the case of \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, and \\u003ccode\\u003eappend\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must be a valid file.\\nIf an \\u003ccode\\u003eop\\u003c/code\\u003e value of \\u003ccode\\u003eappend\\u003c/code\\u003e is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\u003c/p\\u003e\\n\"\n        },\n        \"time\": {\n          \"$ref\": \"#/$defs/TimeConfig\",\n          \"title\": \"time\",\n          \"description\": \"Used to configure the machine’s time settings.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's time settings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s time settings.\\u003c/p\\u003e\\n\"\n        },\n        \"sysctls\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysctls\",\n          \"description\": \"Used to configure the machine’s sysctls.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysctls.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysctls.\\u003c/p\\u003e\\n\"\n        },\n        \"sysfs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysfs\",\n          \"description\": \"Used to configure the machine’s sysfs.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysfs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysfs.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/RegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Used to configure the machine’s container image registry mirrors.\\n\\nAutomatically generates matching CRI configuration for registry mirrors.\\n\\nThe mirrors section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\n\\nThe config section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in .docker/config.json.\\n\\nSee also matching configuration for CRI containerd plugin.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's container image registry mirrors.\\n\\nAutomatically generates matching CRI configuration for registry mirrors.\\n\\nThe `mirrors` section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\n\\nThe `config` section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\\n\\nSee also matching configuration for [CRI containerd plugin](https://github.com/containerd/cri/blob/master/docs/registry.md).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s container image registry mirrors.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eAutomatically generates matching CRI configuration for registry mirrors.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe \\u003ccode\\u003emirrors\\u003c/code\\u003e section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe \\u003ccode\\u003econfig\\u003c/code\\u003e section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee also matching configuration for \\u003ca href=\\\"https://github.com/containerd/cri/blob/master/docs/registry.md\\\" target=\\\"_blank\\\"\\u003eCRI containerd plugin\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"systemDiskEncryption\": {\n          \"$ref\": \"#/$defs/SystemDiskEncryptionConfig\",\n          \"title\": \"systemDiskEncryption\",\n          \"description\": \"Machine system disk encryption configuration.\\nDefines each system partition encryption parameters.\\n\",\n          \"markdownDescription\": \"Machine system disk encryption configuration.\\nDefines each system partition encryption parameters.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMachine system disk encryption configuration.\\nDefines each system partition encryption parameters.\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"$ref\": \"#/$defs/FeaturesConfig\",\n          \"title\": \"features\",\n          \"description\": \"Features describe individual Talos features that can be switched on or off.\\n\",\n          \"markdownDescription\": \"Features describe individual Talos features that can be switched on or off.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFeatures describe individual Talos features that can be switched on or off.\\u003c/p\\u003e\\n\"\n        },\n        \"udev\": {\n          \"$ref\": \"#/$defs/UdevConfig\",\n          \"title\": \"udev\",\n          \"description\": \"Configures the udev system.\\n\",\n          \"markdownDescription\": \"Configures the udev system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the udev system.\\u003c/p\\u003e\\n\"\n        },\n        \"logging\": {\n          \"$ref\": \"#/$defs/LoggingConfig\",\n          \"title\": \"logging\",\n          \"description\": \"Configures the logging system.\\n\",\n          \"markdownDescription\": \"Configures the logging system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the logging system.\\u003c/p\\u003e\\n\"\n        },\n        \"kernel\": {\n          \"$ref\": \"#/$defs/KernelConfig\",\n          \"title\": \"kernel\",\n          \"description\": \"Configures the kernel.\\n\",\n          \"markdownDescription\": \"Configures the kernel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the kernel.\\u003c/p\\u003e\\n\"\n        },\n        \"seccompProfiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineSeccompProfile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"seccompProfiles\",\n          \"description\": \"Configures the seccomp profiles for the machine.\\n\",\n          \"markdownDescription\": \"Configures the seccomp profiles for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the seccomp profiles for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeLabels\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeLabels\",\n          \"description\": \"Configures the node labels for the machine.\\n\",\n          \"markdownDescription\": \"Configures the node labels for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node labels for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeTaints\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeTaints\",\n          \"description\": \"Configures the node taints for the machine. Effect is optional.\\n\",\n          \"markdownDescription\": \"Configures the node taints for the machine. Effect is optional.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node taints for the machine. Effect is optional.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineControlPlaneConfig\": {\n      \"properties\": {\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/MachineControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/MachineSchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler machine specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineControllerManagerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-controller-manager on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-controller-manager on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-controller-manager on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineDisk\": {\n      \"properties\": {\n        \"device\": {\n          \"type\": \"string\",\n          \"title\": \"device\",\n          \"description\": \"The name of the disk to use.\\n\",\n          \"markdownDescription\": \"The name of the disk to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe name of the disk to use.\\u003c/p\\u003e\\n\"\n        },\n        \"partitions\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/DiskPartition\"\n          },\n          \"type\": \"array\",\n          \"title\": \"partitions\",\n          \"description\": \"A list of partitions to create on the disk.\\n\",\n          \"markdownDescription\": \"A list of partitions to create on the disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of partitions to create on the disk.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The contents of the file.\\n\",\n          \"markdownDescription\": \"The contents of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe contents of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"permissions\": {\n          \"type\": \"integer\",\n          \"title\": \"permissions\",\n          \"description\": \"The file’s permissions in octal.\\n\",\n          \"markdownDescription\": \"The file's permissions in octal.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe file\\u0026rsquo;s permissions in octal.\\u003c/p\\u003e\\n\"\n        },\n        \"path\": {\n          \"type\": \"string\",\n          \"title\": \"path\",\n          \"description\": \"The path of the file.\\n\",\n          \"markdownDescription\": \"The path of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe path of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"op\": {\n          \"enum\": [\n            \"create\",\n            \"append\",\n            \"overwrite\"\n          ],\n          \"title\": \"op\",\n          \"description\": \"The operation to use\\n\",\n          \"markdownDescription\": \"The operation to use\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe operation to use\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineSchedulerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-scheduler on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-scheduler on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-scheduler on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineSeccompProfile\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"The name field is used to provide the file name of the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `name` field is used to provide the file name of the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003ename\\u003c/code\\u003e field is used to provide the file name of the seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"value\": {\n          \"type\": \"object\",\n          \"title\": \"value\",\n          \"description\": \"The value field is used to provide the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `value` field is used to provide the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalue\\u003c/code\\u003e field is used to provide the seccomp profile.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkConfig\": {\n      \"properties\": {\n        \"hostname\": {\n          \"type\": \"string\",\n          \"title\": \"hostname\",\n          \"description\": \"Used to statically set the hostname for the machine.\\n\",\n          \"markdownDescription\": \"Used to statically set the hostname for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to statically set the hostname for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"interfaces\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Device\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"interfaces is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\\n\",\n          \"markdownDescription\": \"`interfaces` is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003e\\u003ccode\\u003einterfaces\\u003c/code\\u003e is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\\u003c/p\\u003e\\n\"\n        },\n        \"nameservers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nameservers\",\n          \"description\": \"Used to statically set the nameservers for the machine.\\nDefaults to 1.1.1.1 and 8.8.8.8\\n\",\n          \"markdownDescription\": \"Used to statically set the nameservers for the machine.\\nDefaults to `1.1.1.1` and `8.8.8.8`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to statically set the nameservers for the machine.\\nDefaults to \\u003ccode\\u003e1.1.1.1\\u003c/code\\u003e and \\u003ccode\\u003e8.8.8.8\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"extraHostEntries\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ExtraHost\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraHostEntries\",\n          \"description\": \"Allows for extra entries to be added to the /etc/hosts file\\n\",\n          \"markdownDescription\": \"Allows for extra entries to be added to the `/etc/hosts` file\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for extra entries to be added to the \\u003ccode\\u003e/etc/hosts\\u003c/code\\u003e file\\u003c/p\\u003e\\n\"\n        },\n        \"kubespan\": {\n          \"$ref\": \"#/$defs/NetworkKubeSpan\",\n          \"title\": \"kubespan\",\n          \"description\": \"Configures KubeSpan feature.\\n\",\n          \"markdownDescription\": \"Configures KubeSpan feature.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures KubeSpan feature.\\u003c/p\\u003e\\n\"\n        },\n        \"disableSearchDomain\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableSearchDomain\",\n          \"description\": \"Disable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to false.\\n\",\n          \"markdownDescription\": \"Disable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to `false`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to \\u003ccode\\u003efalse\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkDeviceSelector\": {\n      \"properties\": {\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"PCI, USB bus prefix, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"PCI, USB bus prefix, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI, USB bus prefix, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Device hardware address, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"Device hardware address, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDevice hardware address, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"pciID\": {\n          \"type\": \"string\",\n          \"title\": \"pciID\",\n          \"description\": \"PCI ID (vendor ID, product ID), supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"PCI ID (vendor ID, product ID), supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI ID (vendor ID, product ID), supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"driver\": {\n          \"type\": \"string\",\n          \"title\": \"driver\",\n          \"description\": \"Kernel driver, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"Kernel driver, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel driver, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkKubeSpan\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\\n\",\n          \"markdownDescription\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"advertiseKubernetesNetworks\": {\n          \"type\": \"boolean\",\n          \"title\": \"advertiseKubernetesNetworks\",\n          \"description\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\\n\",\n          \"markdownDescription\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eControl whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\\u003c/p\\u003e\\n\"\n        },\n        \"allowDownPeerBypass\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowDownPeerBypass\",\n          \"description\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can’t be established.\\n\",\n          \"markdownDescription\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can't be established.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can\\u0026rsquo;t be established.\\u003c/p\\u003e\\n\"\n        },\n        \"harvestExtraEndpoints\": {\n          \"type\": \"boolean\",\n          \"title\": \"harvestExtraEndpoints\",\n          \"description\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u0026gt;50) in the KubeSpan network it can cause performance issues.\\n\",\n          \"markdownDescription\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u003e50) in the KubeSpan network it can cause performance issues.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u0026gt;50) in the KubeSpan network it can cause performance issues.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"KubeSpan link MTU size.\\nDefault value is 1420.\\n\",\n          \"markdownDescription\": \"KubeSpan link MTU size.\\nDefault value is 1420.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan link MTU size.\\nDefault value is 1420.\\u003c/p\\u003e\\n\"\n        },\n        \"filters\": {\n          \"$ref\": \"#/$defs/KubeSpanFilters\",\n          \"title\": \"filters\",\n          \"description\": \"KubeSpan advanced filtering of network addresses .\\n\\nSettings in this section are optional, and settings apply only to the node.\\n\",\n          \"markdownDescription\": \"KubeSpan advanced filtering of network addresses .\\n\\nSettings in this section are optional, and settings apply only to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan advanced filtering of network addresses .\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSettings in this section are optional, and settings apply only to the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ProxyConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-proxy deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable kube-proxy deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-proxy deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the kube-proxy manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the kube-proxy manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the kube-proxy manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"proxy mode of kube-proxy.\\nThe default is ‘iptables’.\\n\",\n          \"markdownDescription\": \"proxy mode of kube-proxy.\\nThe default is 'iptables'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eproxy mode of kube-proxy.\\nThe default is \\u0026lsquo;iptables\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to kube-proxy.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to kube-proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to kube-proxy.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistriesConfig\": {\n      \"properties\": {\n        \"mirrors\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"$ref\": \"#/$defs/RegistryMirrorConfig\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"mirrors\",\n          \"description\": \"Specifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\n\\nFor example, when pulling an image with the reference example.com:123/image:v1,\\nthe example.com:123 key will be used to lookup the mirror configuration.\\n\\nOptionally the * key can be used to configure a fallback mirror.\\n\\nRegistry name is the first segment of image identifier, with ‘docker.io’\\nbeing default one.\\n\",\n          \"markdownDescription\": \"Specifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\n\\nFor example, when pulling an image with the reference `example.com:123/image:v1`,\\nthe `example.com:123` key will be used to lookup the mirror configuration.\\n\\nOptionally the `*` key can be used to configure a fallback mirror.\\n\\nRegistry name is the first segment of image identifier, with 'docker.io'\\nbeing default one.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eFor example, when pulling an image with the reference \\u003ccode\\u003eexample.com:123/image:v1\\u003c/code\\u003e,\\nthe \\u003ccode\\u003eexample.com:123\\u003c/code\\u003e key will be used to lookup the mirror configuration.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eOptionally the \\u003ccode\\u003e*\\u003c/code\\u003e key can be used to configure a fallback mirror.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry name is the first segment of image identifier, with \\u0026lsquo;docker.io\\u0026rsquo;\\nbeing default one.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"$ref\": \"#/$defs/RegistryConfig\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specifies TLS \\u0026amp; auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with ‘clientIdentity’ option.\\n\\nThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key * can’t be used for TLS configuration.\\n\\nTLS configuration can be skipped if registry has trusted\\nserver certificate.\\n\",\n          \"markdownDescription\": \"Specifies TLS \\u0026 auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with 'clientIdentity' option.\\n\\nThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key `*` can't be used for TLS configuration.\\n\\nTLS configuration can be skipped if registry has trusted\\nserver certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies TLS \\u0026amp; auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with \\u0026lsquo;clientIdentity\\u0026rsquo; option.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key \\u003ccode\\u003e*\\u003c/code\\u003e can\\u0026rsquo;t be used for TLS configuration.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eTLS configuration can be skipped if registry has trusted\\nserver certificate.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryAuthConfig\": {\n      \"properties\": {\n        \"username\": {\n          \"type\": \"string\",\n          \"title\": \"username\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"password\": {\n          \"type\": \"string\",\n          \"title\": \"password\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"type\": \"string\",\n          \"title\": \"auth\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"identityToken\": {\n          \"type\": \"string\",\n          \"title\": \"identityToken\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryConfig\": {\n      \"properties\": {\n        \"tls\": {\n          \"$ref\": \"#/$defs/RegistryTLSConfig\",\n          \"title\": \"tls\",\n          \"description\": \"The TLS configuration for the registry.\\n\",\n          \"markdownDescription\": \"The TLS configuration for the registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe TLS configuration for the registry.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"$ref\": \"#/$defs/RegistryAuthConfig\",\n          \"title\": \"auth\",\n          \"description\": \"The auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\\n\",\n          \"markdownDescription\": \"The auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryKubernetesConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable Kubernetes discovery registry.\\n\",\n          \"markdownDescription\": \"Disable Kubernetes discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable Kubernetes discovery registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryMirrorConfig\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"List of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to /v2).\\n\",\n          \"markdownDescription\": \"List of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to `/v2`).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to \\u003ccode\\u003e/v2\\u003c/code\\u003e).\\u003c/p\\u003e\\n\"\n        },\n        \"overridePath\": {\n          \"type\": \"boolean\",\n          \"title\": \"overridePath\",\n          \"description\": \"Use the exact path specified for the endpoint (don’t append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\\n\",\n          \"markdownDescription\": \"Use the exact path specified for the endpoint (don't append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse the exact path specified for the endpoint (don\\u0026rsquo;t append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryServiceConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable external service discovery registry.\\n\",\n          \"markdownDescription\": \"Disable external service discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable external service discovery registry.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"External service endpoint.\\n\",\n          \"markdownDescription\": \"External service endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal service endpoint.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryTLSConfig\": {\n      \"properties\": {\n        \"clientIdentity\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"clientIdentity\",\n          \"description\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\\n\",\n          \"markdownDescription\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"type\": \"string\",\n          \"title\": \"ca\",\n          \"description\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\\n\",\n          \"markdownDescription\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"insecureSkipVerify\": {\n          \"type\": \"boolean\",\n          \"title\": \"insecureSkipVerify\",\n          \"description\": \"Skip TLS server certificate verification (not recommended).\\n\",\n          \"markdownDescription\": \"Skip TLS server certificate verification (not recommended).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip TLS server certificate verification (not recommended).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ResourcesConfig\": {\n      \"properties\": {\n        \"requests\": {\n          \"$ref\": \"#/$defs/Unstructured\",\n          \"title\": \"requests\",\n          \"description\": \"Requests configures the reserved cpu/memory resources.\\n\",\n          \"markdownDescription\": \"Requests configures the reserved cpu/memory resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRequests configures the reserved cpu/memory resources.\\u003c/p\\u003e\\n\"\n        },\n        \"limits\": {\n          \"$ref\": \"#/$defs/Unstructured\",\n          \"title\": \"limits\",\n          \"description\": \"Limits configures the maximum cpu/memory resources a container can use.\\n\",\n          \"markdownDescription\": \"Limits configures the maximum cpu/memory resources a container can use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLimits configures the maximum cpu/memory resources a container can use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Route\": {\n      \"properties\": {\n        \"network\": {\n          \"type\": \"string\",\n          \"title\": \"network\",\n          \"description\": \"The route’s network (destination).\\n\",\n          \"markdownDescription\": \"The route's network (destination).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s network (destination).\\u003c/p\\u003e\\n\"\n        },\n        \"gateway\": {\n          \"type\": \"string\",\n          \"title\": \"gateway\",\n          \"description\": \"The route’s gateway (if empty, creates link scope route).\\n\",\n          \"markdownDescription\": \"The route's gateway (if empty, creates link scope route).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s gateway (if empty, creates link scope route).\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"The route’s source address (optional).\\n\",\n          \"markdownDescription\": \"The route's source address (optional).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s source address (optional).\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The optional MTU for the route.\\n\",\n          \"markdownDescription\": \"The optional MTU for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional MTU for the route.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"STP\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Whether Spanning Tree Protocol (STP) is enabled.\\n\",\n          \"markdownDescription\": \"Whether Spanning Tree Protocol (STP) is enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether Spanning Tree Protocol (STP) is enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"SchedulerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the scheduler manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the scheduler manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the scheduler manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the scheduler.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the scheduler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the scheduler.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the scheduler static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the scheduler static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the scheduler static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the scheduler resources.\\n\",\n          \"markdownDescription\": \"Configure the scheduler resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the scheduler resources.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specify custom kube-scheduler configuration.\\n\",\n          \"markdownDescription\": \"Specify custom kube-scheduler configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecify custom kube-scheduler configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"SystemDiskEncryptionConfig\": {\n      \"properties\": {\n        \"state\": {\n          \"$ref\": \"#/$defs/EncryptionConfig\",\n          \"title\": \"state\",\n          \"description\": \"State partition encryption.\\n\",\n          \"markdownDescription\": \"State partition encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eState partition encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"ephemeral\": {\n          \"$ref\": \"#/$defs/EncryptionConfig\",\n          \"title\": \"ephemeral\",\n          \"description\": \"Ephemeral partition encryption.\\n\",\n          \"markdownDescription\": \"Ephemeral partition encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEphemeral partition encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"TimeConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Indicates if the time service is disabled for the machine.\\nDefaults to false.\\n\",\n          \"markdownDescription\": \"Indicates if the time service is disabled for the machine.\\nDefaults to `false`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the time service is disabled for the machine.\\nDefaults to \\u003ccode\\u003efalse\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"servers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"servers\",\n          \"description\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to pool.ntp.org\\n\",\n          \"markdownDescription\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to `pool.ntp.org`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies time (NTP) servers to use for setting the system time.\\nDefaults to \\u003ccode\\u003epool.ntp.org\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"bootTimeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"bootTimeout\",\n          \"description\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to “infinity” (waiting forever for time sync)\\n\",\n          \"markdownDescription\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\\"infinity\\\" (waiting forever for time sync)\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\u0026ldquo;infinity\\u0026rdquo; (waiting forever for time sync)\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"UdevConfig\": {\n      \"properties\": {\n        \"rules\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"rules\",\n          \"description\": \"List of udev rules to apply to the udev system\\n\",\n          \"markdownDescription\": \"List of udev rules to apply to the udev system\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of udev rules to apply to the udev system\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VIPEquinixMetalConfig\": {\n      \"properties\": {\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Equinix Metal API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Equinix Metal API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Equinix Metal API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VIPHCloudConfig\": {\n      \"properties\": {\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Hetzner Cloud API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Vlan\": {\n      \"properties\": {\n        \"addresses\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"The addresses in CIDR notation or as plain IPs to use.\\n\",\n          \"markdownDescription\": \"The addresses in CIDR notation or as plain IPs to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe addresses in CIDR notation or as plain IPs to use.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Route\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"A list of routes associated with the VLAN.\\n\",\n          \"markdownDescription\": \"A list of routes associated with the VLAN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of routes associated with the VLAN.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcp\": {\n          \"type\": \"boolean\",\n          \"title\": \"dhcp\",\n          \"description\": \"Indicates if DHCP should be used.\\n\",\n          \"markdownDescription\": \"Indicates if DHCP should be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if DHCP should be used.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanId\": {\n          \"type\": \"integer\",\n          \"title\": \"vlanId\",\n          \"description\": \"The VLAN’s ID.\\n\",\n          \"markdownDescription\": \"The VLAN's ID.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s ID.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The VLAN’s MTU.\\n\",\n          \"markdownDescription\": \"The VLAN's MTU.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s MTU.\\u003c/p\\u003e\\n\"\n        },\n        \"vip\": {\n          \"$ref\": \"#/$defs/DeviceVIPConfig\",\n          \"title\": \"vip\",\n          \"description\": \"The VLAN’s virtual IP address configuration.\\n\",\n          \"markdownDescription\": \"The VLAN's virtual IP address configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s virtual IP address configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcpOptions\": {\n          \"$ref\": \"#/$defs/DHCPOptions\",\n          \"title\": \"dhcpOptions\",\n          \"description\": \"DHCP specific options.\\ndhcp must be set to true for these to take effect.\\n\",\n          \"markdownDescription\": \"DHCP specific options.\\n`dhcp` *must* be set to true for these to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDHCP specific options.\\n\\u003ccode\\u003edhcp\\u003c/code\\u003e \\u003cem\\u003emust\\u003c/em\\u003e be set to true for these to take effect.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VolumeMountConfig\": {\n      \"properties\": {\n        \"hostPath\": {\n          \"type\": \"string\",\n          \"title\": \"hostPath\",\n          \"description\": \"Path on the host.\\n\",\n          \"markdownDescription\": \"Path on the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath on the host.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"Path in the container.\\n\",\n          \"markdownDescription\": \"Path in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"readonly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readonly\",\n          \"description\": \"Mount the volume read only.\\n\",\n          \"markdownDescription\": \"Mount the volume read only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read only.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    }\n  }\n}"
  },
  {
    "path": "pkg/machinery/config/types/block/block.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package block provides block device and volume configuration documents.\npackage block\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output block_doc.go block.go encryption.go existing_volume_config.go external_volume_config.go raw_volume_config.go swap_volume_config.go user_volume_config.go volume_config.go zswap_config.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ExistingVolumeConfigV1Alpha1 -type RawVolumeConfigV1Alpha1 -type SwapVolumeConfigV1Alpha1 -type UserVolumeConfigV1Alpha1 -type ExternalVolumeConfigV1Alpha1 -type VolumeConfigV1Alpha1 -type ZswapConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/block/block_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage block\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (EncryptionSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionSpec represents volume encryption settings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionSpec represents volume encryption settings.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"RawVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"encryption\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"SwapVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"encryption\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"UserVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"encryption\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"VolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"encryption\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"provider\",\n\t\t\t\tType:        \"EncryptionProviderType\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Encryption provider to use for the encryption.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Encryption provider to use for the encryption.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"luks2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"keys\",\n\t\t\t\tType:        \"[]EncryptionKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Defines the encryption keys generation and storage method.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Defines the encryption keys generation and storage method.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"cipher\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Cipher to use for the encryption. Depends on the encryption provider.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Cipher to use for the encryption. Depends on the encryption provider.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"aes-xts-plain64\",\n\t\t\t\t\t\"xchacha12,aes-adiantum-plain64\",\n\t\t\t\t\t\"xchacha20,aes-adiantum-plain64\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"keySize\",\n\t\t\t\tType:        \"uint\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Defines the encryption key length.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Defines the encryption key length.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"blockSize\",\n\t\t\t\tType:        \"uint64\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Defines the encryption sector size.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Defines the encryption sector size.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"options\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Additional --perf parameters for the LUKS2 encryption.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Additional --perf parameters for the LUKS2 encryption.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"no_read_workqueue\",\n\t\t\t\t\t\"no_write_workqueue\",\n\t\t\t\t\t\"same_cpu_crypt\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleEncryptionSpec())\n\n\tdoc.Fields[2].AddExample(\"\", \"aes-xts-plain64\")\n\tdoc.Fields[4].AddExample(\"\", 4096)\n\tdoc.Fields[5].AddExample(\"\", []string{\"no_read_workqueue\", \"no_write_workqueue\"})\n\n\treturn doc\n}\n\nfunc (EncryptionKey) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKey\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKey represents configuration for disk encryption key.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKey represents configuration for disk encryption key.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionSpec\",\n\t\t\t\tFieldName: \"keys\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"slot\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Key slot number for LUKS2 encryption.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Key slot number for LUKS2 encryption.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"static\",\n\t\t\t\tType:        \"EncryptionKeyStatic\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Key which value is stored in the configuration file.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Key which value is stored in the configuration file.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeID\",\n\t\t\t\tType:        \"EncryptionKeyNodeID\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Deterministically generated key from the node UUID and PartitionLabel.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Deterministically generated key from the node UUID and PartitionLabel.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"kms\",\n\t\t\t\tType:        \"EncryptionKeyKMS\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KMS managed encryption key.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KMS managed encryption key.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tpm\",\n\t\t\t\tType:        \"EncryptionKeyTPM\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable TPM based disk encryption.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable TPM based disk encryption.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"lockToState\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (EncryptionKeyStatic) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKeyStatic\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKeyStatic represents throw away key type.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKeyStatic represents throw away key type.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionKey\",\n\t\t\t\tFieldName: \"static\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"passphrase\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Defines the static passphrase value.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Defines the static passphrase value.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (EncryptionKeyKMS) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKeyKMS\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionKey\",\n\t\t\t\tFieldName: \"kms\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KMS endpoint to Seal/Unseal the key.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KMS endpoint to Seal/Unseal the key.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleKMSKey())\n\n\treturn doc\n}\n\nfunc (EncryptionKeyTPM) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKeyTPM\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionKey\",\n\t\t\t\tFieldName: \"tpm\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"options\",\n\t\t\t\tType:        \"EncryptionKeyTPMOptions\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"TPM options for key protection.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TPM options for key protection.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"checkSecurebootStatusOnEnroll\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Check that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Check that Secureboot is enabled in the EFI firmware.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (EncryptionKeyTPMOptions) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKeyTPMOptions\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKeyTPMOptions represents the options for TPM-based key protection.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKeyTPMOptions represents the options for TPM-based key protection.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionKeyTPM\",\n\t\t\t\tFieldName: \"options\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"pcrs\",\n\t\t\t\tType:        \"[]int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (EncryptionKeyNodeID) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EncryptionKeyNodeID\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EncryptionKey\",\n\t\t\t\tFieldName: \"nodeID\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{},\n\t}\n\n\treturn doc\n}\n\nfunc (ExistingVolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExistingVolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExistingVolumeConfig is an existing volume configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExistingVolumeConfig is an existing volume configuration document.\\nExisting volumes allow to mount partitions (or whole disks) that were created\\noutside of Talos. Volume will be mounted under `/var/mnt/<name>`.\\nThe existing volume config name should not conflict with user volume names.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the volume.\\n\\nName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"discovery\",\n\t\t\t\tType:        \"VolumeDiscoverySpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The discovery describes how to find a volume.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The discovery describes how to find a volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mount\",\n\t\t\t\tType:        \"ExistingMountSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The mount describes additional mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The mount describes additional mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleExistingVolumeConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (VolumeDiscoverySpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VolumeDiscoverySpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VolumeDiscoverySpec describes how the volume is discovered.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VolumeDiscoverySpec describes how the volume is discovered.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ExistingVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"discovery\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"volumeSelector\",\n\t\t\t\tType:        \"VolumeSelector\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The volume selector expression.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The volume selector expression.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (VolumeSelector) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VolumeSelector\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VolumeSelector selects an existing volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VolumeSelector selects an existing volume.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"VolumeDiscoverySpec\",\n\t\t\t\tFieldName: \"volumeSelector\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"match\",\n\t\t\t\tType:        \"Expression\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The Common Expression Language (CEL) expression to match the volume.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The Common Expression Language (CEL) expression to match the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"match volumes with partition label MY-DATA\", exampleVolumeSelector1())\n\tdoc.Fields[0].AddExample(\"match xfs volume on disk with serial 'SERIAL123'\", exampleVolumeSelector2())\n\n\treturn doc\n}\n\nfunc (ExistingMountSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExistingMountSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExistingMountSpec describes how the volume is mounted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExistingMountSpec describes how the volume is mounted.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ExistingVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"mount\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"readOnly\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Mount the volume read-only.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Mount the volume read-only.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"disableAccessTime\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"If true, disable file access time updates.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"If true, disable file access time updates.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"secure\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable secure mount options (nosuid, nodev).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (ExternalVolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExternalVolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExternalVolumeConfig is an external disk mount configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExternalVolumeConfig is an external disk mount configuration document.\\nExternal volumes allow to mount volumes that were created outside of Talos,\\nover the network or API. Volume will be mounted under `/var/mnt/<name>`.\\nThe external volume config name should not conflict with user volume names.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the mount.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the mount.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"filesystemType\",\n\t\t\t\tType:        \"FilesystemType\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Filesystem type.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Filesystem type.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"virtiofs\",\n\t\t\t\t\t\"nfs\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mount\",\n\t\t\t\tType:        \"ExternalMountSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The mount describes additional mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The mount describes additional mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleExternalVolumeConfigV1Alpha1Virtiofs())\n\n\treturn doc\n}\n\nfunc (ExternalMountSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExternalMountSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExternalMountSpec describes how the external volume is mounted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExternalMountSpec describes how the external volume is mounted.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ExternalVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"mount\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"readOnly\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Mount the volume read-only.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Mount the volume read-only.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"disableAccessTime\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"If true, disable file access time updates.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"If true, disable file access time updates.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"secure\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable secure mount options (nosuid, nodev).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"virtiofs\",\n\t\t\t\tType:        \"VirtiofsMountSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Virtiofs mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Virtiofs mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (VirtiofsMountSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VirtiofsMountSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VirtiofsMountSpec describes Virtiofs mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VirtiofsMountSpec describes Virtiofs mount options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ExternalMountSpec\",\n\t\t\t\tFieldName: \"virtiofs\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"tag\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Selector tag for the Virtiofs mount.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Selector tag for the Virtiofs mount.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (RawVolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RawVolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RawVolumeConfig is a raw volume configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RawVolumeConfig is a raw volume configuration document.\\nRaw volumes allow to create partitions without formatting them.\\n If you want to use local storage, user volumes is a better choice,\\n raw volumes are intended to be used with CSI provisioners.\\nThe partition label is automatically generated as `r-<name>`.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"provisioning\",\n\t\t\t\tType:        \"ProvisioningSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The provisioning describes how the volume is provisioned.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The provisioning describes how the volume is provisioned.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"encryption\",\n\t\t\t\tType:        \"EncryptionSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The encryption describes how the volume is encrypted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The encryption describes how the volume is encrypted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRawVolumeConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (SwapVolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"SwapVolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SwapVolumeConfig is a disk swap volume configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"SwapVolumeConfig is a disk swap volume configuration document.\\nSwap volume is automatically allocated as a partition on the specified disk\\nand activated as swap, removing a swap volume deactivates swap.\\nThe partition label is automatically generated as `s-<name>`.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"provisioning\",\n\t\t\t\tType:        \"ProvisioningSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The provisioning describes how the volume is provisioned.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The provisioning describes how the volume is provisioned.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"encryption\",\n\t\t\t\tType:        \"EncryptionSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The encryption describes how the volume is encrypted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The encryption describes how the volume is encrypted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleSwapVolumeConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (UserVolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"UserVolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"UserVolumeConfig is a user volume configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"UserVolumeConfig is a user volume configuration document.\\nUser volume is automatically allocated as a partition on the specified disk\\nand mounted under `/var/mnt/<name>`.\\nThe partition label is automatically generated as `u-<name>`.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"volumeType\",\n\t\t\t\tType:        \"VolumeType\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Volume type.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Volume type.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"directory\",\n\t\t\t\t\t\"disk\",\n\t\t\t\t\t\"partition\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"provisioning\",\n\t\t\t\tType:        \"ProvisioningSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The provisioning describes how the volume is provisioned.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The provisioning describes how the volume is provisioned.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"filesystem\",\n\t\t\t\tType:        \"FilesystemSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The filesystem describes how the volume is formatted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The filesystem describes how the volume is formatted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"encryption\",\n\t\t\t\tType:        \"EncryptionSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The encryption describes how the volume is encrypted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The encryption describes how the volume is encrypted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mount\",\n\t\t\t\tType:        \"UserMountSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The mount describes additional mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The mount describes additional mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleUserVolumeConfigV1Alpha1Directory())\n\n\tdoc.AddExample(\"\", exampleUserVolumeConfigV1Alpha1Disk())\n\n\tdoc.AddExample(\"\", exampleUserVolumeConfigV1Alpha1Partition())\n\n\treturn doc\n}\n\nfunc (UserMountSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"UserMountSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"UserMountSpec describes how the volume is mounted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"UserMountSpec describes how the volume is mounted.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"UserVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"mount\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disableAccessTime\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"If true, disable file access time updates.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"If true, disable file access time updates.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"secure\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable secure mount options (nosuid, nodev).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (FilesystemSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"FilesystemSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"FilesystemSpec configures the filesystem for the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"FilesystemSpec configures the filesystem for the volume.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"UserVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"filesystem\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"type\",\n\t\t\t\tType:        \"FilesystemType\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Filesystem type. Default is `xfs`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Filesystem type. Default is `xfs`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"ext4\",\n\t\t\t\t\t\"xfs\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"projectQuotaSupport\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enables project quota support, valid only for 'xfs' filesystem.\\n\\nNote: changing this value might require a full remount of the filesystem.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enables project quota support, valid only for 'xfs' filesystem.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (VolumeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VolumeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VolumeConfig is a system volume configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VolumeConfig is a system volume configuration document.\\nNote: at the moment, only `STATE`, `EPHEMERAL` and `IMAGE-CACHE` system volumes are supported.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the volume.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"provisioning\",\n\t\t\t\tType:        \"ProvisioningSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The provisioning describes how the volume is provisioned.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The provisioning describes how the volume is provisioned.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"encryption\",\n\t\t\t\tType:        \"EncryptionSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The encryption describes how the volume is encrypted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The encryption describes how the volume is encrypted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mount\",\n\t\t\t\tType:        \"MountSpec\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The mount describes additional mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The mount describes additional mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleVolumeConfigEphemeralV1Alpha1())\n\n\treturn doc\n}\n\nfunc (MountSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MountSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MountSpec describes how the volume is mounted.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MountSpec describes how the volume is mounted.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"VolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"mount\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"secure\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable secure mount options (nosuid, nodev).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (ProvisioningSpec) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ProvisioningSpec\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ProvisioningSpec describes how the volume is provisioned.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ProvisioningSpec describes how the volume is provisioned.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"RawVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"provisioning\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"SwapVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"provisioning\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"UserVolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"provisioning\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"VolumeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"provisioning\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"diskSelector\",\n\t\t\t\tType:        \"DiskSelector\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The disk selector expression.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The disk selector expression.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"grow\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Should the volume grow to the size of the disk (if possible).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Should the volume grow to the size of the disk (if possible).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"minSize\",\n\t\t\t\tType:        \"ByteSize\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The minimum size of the volume.\\n\\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The minimum size of the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"maxSize\",\n\t\t\t\tType:        \"Size\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\n\\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The maximum size of the volume, if not specified the volume can grow to the size of the\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[2].AddExample(\"\", \"2.5GiB\")\n\tdoc.Fields[3].AddExample(\"\", \"50GiB\")\n\tdoc.Fields[3].AddExample(\"\", \"80%\")\n\n\treturn doc\n}\n\nfunc (DiskSelector) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"DiskSelector\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"DiskSelector selects a disk for the volume.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"DiskSelector selects a disk for the volume.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ProvisioningSpec\",\n\t\t\t\tFieldName: \"diskSelector\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"match\",\n\t\t\t\tType:        \"Expression\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The Common Expression Language (CEL) expression to match the disk.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The Common Expression Language (CEL) expression to match the disk.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"match disks with size between 120GB and 1TB\", exampleDiskSelector1())\n\tdoc.Fields[0].AddExample(\"match SATA disks that are not rotational and not system disks\", exampleDiskSelector2())\n\n\treturn doc\n}\n\nfunc (ZswapConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ZswapConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ZswapConfig is a zswap (compressed memory) configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ZswapConfig is a zswap (compressed memory) configuration document.\\nWhen zswap is enabled, Linux kernel compresses pages that would otherwise be swapped out to disk.\\nThe compressed pages are stored in a memory pool, which is used to avoid writing to disk\\nwhen the system is under memory pressure.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"maxPoolPercent\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The maximum percent of memory that zswap can use.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"shrinkerEnabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable the shrinker feature: kernel might move\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleZswapConfigV1Alpha1())\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file block_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"block\",\n\t\tDescription: \"Package block provides block device and volume configuration documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tEncryptionSpec{}.Doc(),\n\t\t\tEncryptionKey{}.Doc(),\n\t\t\tEncryptionKeyStatic{}.Doc(),\n\t\t\tEncryptionKeyKMS{}.Doc(),\n\t\t\tEncryptionKeyTPM{}.Doc(),\n\t\t\tEncryptionKeyTPMOptions{}.Doc(),\n\t\t\tEncryptionKeyNodeID{}.Doc(),\n\t\t\tExistingVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tVolumeDiscoverySpec{}.Doc(),\n\t\t\tVolumeSelector{}.Doc(),\n\t\t\tExistingMountSpec{}.Doc(),\n\t\t\tExternalVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tExternalMountSpec{}.Doc(),\n\t\t\tVirtiofsMountSpec{}.Doc(),\n\t\t\tRawVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tSwapVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tUserVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tUserMountSpec{}.Doc(),\n\t\t\tFilesystemSpec{}.Doc(),\n\t\t\tVolumeConfigV1Alpha1{}.Doc(),\n\t\t\tMountSpec{}.Doc(),\n\t\t\tProvisioningSpec{}.Doc(),\n\t\t\tDiskSelector{}.Doc(),\n\t\t\tZswapConfigV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/blockhelpers/blockhelpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package blockhelpers provides helper functions for working with block resources.\npackage blockhelpers\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\tblockpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// MatchDisks returns a list of disks that match the given expression.\nfunc MatchDisks(ctx context.Context, st state.State, expression *cel.Expression) ([]*block.Disk, error) {\n\tdisks, err := safe.StateListAll[*block.Disk](ctx, st)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar matchedDisks []*block.Disk\n\n\tfor disk := range disks.All() {\n\t\tspec := &blockpb.DiskSpec{}\n\n\t\tif err = proto.ResourceSpecToProto(disk, spec); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmatches, err := expression.EvalBool(celenv.DiskLocator(), map[string]any{\n\t\t\t\"disk\":        spec,\n\t\t\t\"system_disk\": false,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif matches {\n\t\t\tmatchedDisks = append(matchedDisks, disk)\n\t\t}\n\t}\n\n\treturn matchedDisks, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/byte_size.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"encoding\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/siderolabs/go-pointer\"\n\t\"go.yaml.in/yaml/v4\"\n)\n\n// Check interfaces.\nvar (\n\t_ encoding.TextMarshaler   = ByteSize{}\n\t_ encoding.TextUnmarshaler = (*ByteSize)(nil)\n\t_ yaml.IsZeroer            = ByteSize{}\n)\n\n// ByteSize is a byte size which can be conveniently represented as a human readable string\n// with IEC sizes, e.g. 100MB.\ntype ByteSize struct {\n\tvalue    *uint64\n\traw      []byte\n\tnegative bool\n}\n\n// Value returns the value.\nfunc (bs ByteSize) Value() uint64 {\n\treturn pointer.SafeDeref(bs.value)\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (bs ByteSize) MarshalText() ([]byte, error) {\n\tif bs.raw != nil {\n\t\treturn bs.raw, nil\n\t}\n\n\tnegative := \"\"\n\tif bs.negative {\n\t\tnegative = \"-\"\n\t}\n\n\tif bs.value != nil {\n\t\treturn []byte(negative + strconv.FormatUint(*bs.value, 10)), nil\n\t}\n\n\treturn nil, nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (bs *ByteSize) UnmarshalText(text []byte) error {\n\tif len(text) == 0 {\n\t\treturn nil\n\t}\n\n\traw := slices.Clone(text)\n\n\tif v, ok := bytes.CutPrefix(text, []byte(\"-\")); ok {\n\t\ttext = v\n\t\tbs.negative = true\n\t}\n\n\tvalue, err := humanize.ParseBytes(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbs.value = new(value)\n\tbs.raw = raw\n\n\treturn nil\n}\n\n// IsZero implements yaml.IsZeroer.\nfunc (bs ByteSize) IsZero() bool {\n\treturn bs.value == nil && bs.raw == nil\n}\n\n// Merge implements merger interface.\nfunc (bs *ByteSize) Merge(other any) error {\n\totherBS, ok := other.(ByteSize)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot merge %T with %T\", bs, other)\n\t}\n\n\tbs.raw = otherBS.raw\n\tbs.value = otherBS.value\n\n\treturn nil\n}\n\n// IsNegative returns true if the value is negative.\nfunc (bs ByteSize) IsNegative() bool {\n\treturn bs.negative\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ExistingVolumeConfigV1Alpha1 -type RawVolumeConfigV1Alpha1 -type SwapVolumeConfigV1Alpha1 -type UserVolumeConfigV1Alpha1 -type ExternalVolumeConfigV1Alpha1 -type VolumeConfigV1Alpha1 -type ZswapConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage block\n\n// DeepCopy generates a deep copy of *ExistingVolumeConfigV1Alpha1.\nfunc (o *ExistingVolumeConfigV1Alpha1) DeepCopy() *ExistingVolumeConfigV1Alpha1 {\n\tvar cp ExistingVolumeConfigV1Alpha1 = *o\n\tif o.MountSpec.MountReadOnly != nil {\n\t\tcp.MountSpec.MountReadOnly = new(bool)\n\t\t*cp.MountSpec.MountReadOnly = *o.MountSpec.MountReadOnly\n\t}\n\tif o.MountSpec.MountDisableAccessTime != nil {\n\t\tcp.MountSpec.MountDisableAccessTime = new(bool)\n\t\t*cp.MountSpec.MountDisableAccessTime = *o.MountSpec.MountDisableAccessTime\n\t}\n\tif o.MountSpec.MountSecure != nil {\n\t\tcp.MountSpec.MountSecure = new(bool)\n\t\t*cp.MountSpec.MountSecure = *o.MountSpec.MountSecure\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *RawVolumeConfigV1Alpha1.\nfunc (o *RawVolumeConfigV1Alpha1) DeepCopy() *RawVolumeConfigV1Alpha1 {\n\tvar cp RawVolumeConfigV1Alpha1 = *o\n\tif o.ProvisioningSpec.ProvisioningGrow != nil {\n\t\tcp.ProvisioningSpec.ProvisioningGrow = new(bool)\n\t\t*cp.ProvisioningSpec.ProvisioningGrow = *o.ProvisioningSpec.ProvisioningGrow\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.value != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.value = new(uint64)\n\t\t*cp.ProvisioningSpec.ProvisioningMinSize.value = *o.ProvisioningSpec.ProvisioningMinSize.value\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.raw != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))\n\t\tcopy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)\n\t\t}\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionKeys != nil {\n\t\tcp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))\n\t\tcopy(cp.EncryptionSpec.EncryptionKeys, o.EncryptionSpec.EncryptionKeys)\n\t\tfor i3 := range o.EncryptionSpec.EncryptionKeys {\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyStatic != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = new(EncryptionKeyStatic)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = *o.EncryptionSpec.EncryptionKeys[i3].KeyStatic\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = new(EncryptionKeyNodeID)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = *o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyKMS != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = new(EncryptionKeyKMS)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = *o.EncryptionSpec.EncryptionKeys[i3].KeyKMS\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = new(EncryptionKeyTPM)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = new(EncryptionKeyTPMOptions)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions\n\t\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs != nil {\n\t\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs = make([]int, len(o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs))\n\t\t\t\t\t\tcopy(cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs, o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = new(bool)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE\n\t\t\t}\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionPerfOptions != nil {\n\t\tcp.EncryptionSpec.EncryptionPerfOptions = make([]string, len(o.EncryptionSpec.EncryptionPerfOptions))\n\t\tcopy(cp.EncryptionSpec.EncryptionPerfOptions, o.EncryptionSpec.EncryptionPerfOptions)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *SwapVolumeConfigV1Alpha1.\nfunc (o *SwapVolumeConfigV1Alpha1) DeepCopy() *SwapVolumeConfigV1Alpha1 {\n\tvar cp SwapVolumeConfigV1Alpha1 = *o\n\tif o.ProvisioningSpec.ProvisioningGrow != nil {\n\t\tcp.ProvisioningSpec.ProvisioningGrow = new(bool)\n\t\t*cp.ProvisioningSpec.ProvisioningGrow = *o.ProvisioningSpec.ProvisioningGrow\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.value != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.value = new(uint64)\n\t\t*cp.ProvisioningSpec.ProvisioningMinSize.value = *o.ProvisioningSpec.ProvisioningMinSize.value\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.raw != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))\n\t\tcopy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)\n\t\t}\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionKeys != nil {\n\t\tcp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))\n\t\tcopy(cp.EncryptionSpec.EncryptionKeys, o.EncryptionSpec.EncryptionKeys)\n\t\tfor i3 := range o.EncryptionSpec.EncryptionKeys {\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyStatic != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = new(EncryptionKeyStatic)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = *o.EncryptionSpec.EncryptionKeys[i3].KeyStatic\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = new(EncryptionKeyNodeID)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = *o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyKMS != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = new(EncryptionKeyKMS)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = *o.EncryptionSpec.EncryptionKeys[i3].KeyKMS\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = new(EncryptionKeyTPM)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = new(EncryptionKeyTPMOptions)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions\n\t\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs != nil {\n\t\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs = make([]int, len(o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs))\n\t\t\t\t\t\tcopy(cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs, o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = new(bool)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE\n\t\t\t}\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionPerfOptions != nil {\n\t\tcp.EncryptionSpec.EncryptionPerfOptions = make([]string, len(o.EncryptionSpec.EncryptionPerfOptions))\n\t\tcopy(cp.EncryptionSpec.EncryptionPerfOptions, o.EncryptionSpec.EncryptionPerfOptions)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *UserVolumeConfigV1Alpha1.\nfunc (o *UserVolumeConfigV1Alpha1) DeepCopy() *UserVolumeConfigV1Alpha1 {\n\tvar cp UserVolumeConfigV1Alpha1 = *o\n\tif o.VolumeType != nil {\n\t\tcp.VolumeType = new(VolumeType)\n\t\t*cp.VolumeType = *o.VolumeType\n\t}\n\tif o.ProvisioningSpec.ProvisioningGrow != nil {\n\t\tcp.ProvisioningSpec.ProvisioningGrow = new(bool)\n\t\t*cp.ProvisioningSpec.ProvisioningGrow = *o.ProvisioningSpec.ProvisioningGrow\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.value != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.value = new(uint64)\n\t\t*cp.ProvisioningSpec.ProvisioningMinSize.value = *o.ProvisioningSpec.ProvisioningMinSize.value\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.raw != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))\n\t\tcopy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)\n\t\t}\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)\n\t\t}\n\t}\n\tif o.FilesystemSpec.ProjectQuotaSupportConfig != nil {\n\t\tcp.FilesystemSpec.ProjectQuotaSupportConfig = new(bool)\n\t\t*cp.FilesystemSpec.ProjectQuotaSupportConfig = *o.FilesystemSpec.ProjectQuotaSupportConfig\n\t}\n\tif o.EncryptionSpec.EncryptionKeys != nil {\n\t\tcp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))\n\t\tcopy(cp.EncryptionSpec.EncryptionKeys, o.EncryptionSpec.EncryptionKeys)\n\t\tfor i3 := range o.EncryptionSpec.EncryptionKeys {\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyStatic != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = new(EncryptionKeyStatic)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = *o.EncryptionSpec.EncryptionKeys[i3].KeyStatic\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = new(EncryptionKeyNodeID)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = *o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyKMS != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = new(EncryptionKeyKMS)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = *o.EncryptionSpec.EncryptionKeys[i3].KeyKMS\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = new(EncryptionKeyTPM)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = new(EncryptionKeyTPMOptions)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions\n\t\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs != nil {\n\t\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs = make([]int, len(o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs))\n\t\t\t\t\t\tcopy(cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs, o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = new(bool)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE\n\t\t\t}\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionPerfOptions != nil {\n\t\tcp.EncryptionSpec.EncryptionPerfOptions = make([]string, len(o.EncryptionSpec.EncryptionPerfOptions))\n\t\tcopy(cp.EncryptionSpec.EncryptionPerfOptions, o.EncryptionSpec.EncryptionPerfOptions)\n\t}\n\tif o.MountSpec.MountDisableAccessTime != nil {\n\t\tcp.MountSpec.MountDisableAccessTime = new(bool)\n\t\t*cp.MountSpec.MountDisableAccessTime = *o.MountSpec.MountDisableAccessTime\n\t}\n\tif o.MountSpec.MountSecure != nil {\n\t\tcp.MountSpec.MountSecure = new(bool)\n\t\t*cp.MountSpec.MountSecure = *o.MountSpec.MountSecure\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *ExternalVolumeConfigV1Alpha1.\nfunc (o *ExternalVolumeConfigV1Alpha1) DeepCopy() *ExternalVolumeConfigV1Alpha1 {\n\tvar cp ExternalVolumeConfigV1Alpha1 = *o\n\tif o.MountSpec.MountReadOnly != nil {\n\t\tcp.MountSpec.MountReadOnly = new(bool)\n\t\t*cp.MountSpec.MountReadOnly = *o.MountSpec.MountReadOnly\n\t}\n\tif o.MountSpec.MountDisableAccessTime != nil {\n\t\tcp.MountSpec.MountDisableAccessTime = new(bool)\n\t\t*cp.MountSpec.MountDisableAccessTime = *o.MountSpec.MountDisableAccessTime\n\t}\n\tif o.MountSpec.MountSecure != nil {\n\t\tcp.MountSpec.MountSecure = new(bool)\n\t\t*cp.MountSpec.MountSecure = *o.MountSpec.MountSecure\n\t}\n\tif o.MountSpec.MountVirtiofs != nil {\n\t\tcp.MountSpec.MountVirtiofs = new(VirtiofsMountSpec)\n\t\t*cp.MountSpec.MountVirtiofs = *o.MountSpec.MountVirtiofs\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *VolumeConfigV1Alpha1.\nfunc (o *VolumeConfigV1Alpha1) DeepCopy() *VolumeConfigV1Alpha1 {\n\tvar cp VolumeConfigV1Alpha1 = *o\n\tif o.ProvisioningSpec.ProvisioningGrow != nil {\n\t\tcp.ProvisioningSpec.ProvisioningGrow = new(bool)\n\t\t*cp.ProvisioningSpec.ProvisioningGrow = *o.ProvisioningSpec.ProvisioningGrow\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.value != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.value = new(uint64)\n\t\t*cp.ProvisioningSpec.ProvisioningMinSize.value = *o.ProvisioningSpec.ProvisioningMinSize.value\n\t}\n\tif o.ProvisioningSpec.ProvisioningMinSize.raw != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMinSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMinSize.raw))\n\t\tcopy(cp.ProvisioningSpec.ProvisioningMinSize.raw, o.ProvisioningSpec.ProvisioningMinSize.raw)\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = new(PercentageSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.PercentageSize.raw)\n\t\t}\n\t}\n\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize != nil {\n\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = new(ByteSize)\n\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = new(uint64)\n\t\t\t*cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value = *o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.value\n\t\t}\n\t\tif o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw != nil {\n\t\t\tcp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw = make([]byte, len(o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw))\n\t\t\tcopy(cp.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw, o.ProvisioningSpec.ProvisioningMaxSize.ByteSize.raw)\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionKeys != nil {\n\t\tcp.EncryptionSpec.EncryptionKeys = make([]EncryptionKey, len(o.EncryptionSpec.EncryptionKeys))\n\t\tcopy(cp.EncryptionSpec.EncryptionKeys, o.EncryptionSpec.EncryptionKeys)\n\t\tfor i3 := range o.EncryptionSpec.EncryptionKeys {\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyStatic != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = new(EncryptionKeyStatic)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyStatic = *o.EncryptionSpec.EncryptionKeys[i3].KeyStatic\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = new(EncryptionKeyNodeID)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyNodeID = *o.EncryptionSpec.EncryptionKeys[i3].KeyNodeID\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyKMS != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = new(EncryptionKeyKMS)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyKMS = *o.EncryptionSpec.EncryptionKeys[i3].KeyKMS\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = new(EncryptionKeyTPM)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = new(EncryptionKeyTPMOptions)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions\n\t\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs != nil {\n\t\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs = make([]int, len(o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs))\n\t\t\t\t\t\tcopy(cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs, o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMOptions.PCRs)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll != nil {\n\t\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = new(bool)\n\t\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll = *o.EncryptionSpec.EncryptionKeys[i3].KeyTPM.TPMCheckSecurebootStatusOnEnroll\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE != nil {\n\t\t\t\tcp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = new(bool)\n\t\t\t\t*cp.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE = *o.EncryptionSpec.EncryptionKeys[i3].KeyLockToSTATE\n\t\t\t}\n\t\t}\n\t}\n\tif o.EncryptionSpec.EncryptionPerfOptions != nil {\n\t\tcp.EncryptionSpec.EncryptionPerfOptions = make([]string, len(o.EncryptionSpec.EncryptionPerfOptions))\n\t\tcopy(cp.EncryptionSpec.EncryptionPerfOptions, o.EncryptionSpec.EncryptionPerfOptions)\n\t}\n\tif o.MountSpec.MountSecure != nil {\n\t\tcp.MountSpec.MountSecure = new(bool)\n\t\t*cp.MountSpec.MountSecure = *o.MountSpec.MountSecure\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *ZswapConfigV1Alpha1.\nfunc (o *ZswapConfigV1Alpha1) DeepCopy() *ZswapConfigV1Alpha1 {\n\tvar cp ZswapConfigV1Alpha1 = *o\n\tif o.MaxPoolPercentConfig != nil {\n\t\tcp.MaxPoolPercentConfig = new(int)\n\t\t*cp.MaxPoolPercentConfig = *o.MaxPoolPercentConfig\n\t}\n\tif o.ShrinkerEnabledConfig != nil {\n\t\tcp.ShrinkerEnabledConfig = new(bool)\n\t\t*cp.ShrinkerEnabledConfig = *o.ShrinkerEnabledConfig\n\t}\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/encryption.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n//docgen:jsonschema\n\n// EncryptionSpec represents volume encryption settings.\n//\n//\texamples:\n//\t  - value: exampleEncryptionSpec()\ntype EncryptionSpec struct {\n\t//   description: >\n\t//     Encryption provider to use for the encryption.\n\t//   values:\n\t//     - luks2\n\tEncryptionProvider block.EncryptionProviderType `yaml:\"provider\"`\n\t//   description: >\n\t//     Defines the encryption keys generation and storage method.\n\tEncryptionKeys []EncryptionKey `yaml:\"keys\"`\n\t//   description: >\n\t//     Cipher to use for the encryption.\n\t//     Depends on the encryption provider.\n\t//   values:\n\t//     - aes-xts-plain64\n\t//     - xchacha12,aes-adiantum-plain64\n\t//     - xchacha20,aes-adiantum-plain64\n\t//   examples:\n\t//     - value: '\"aes-xts-plain64\"'\n\tEncryptionCipher string `yaml:\"cipher,omitempty\"`\n\t//   description: >\n\t//     Defines the encryption key length.\n\tEncryptionKeySize uint `yaml:\"keySize,omitempty\"`\n\t//   description: >\n\t//     Defines the encryption sector size.\n\t//   examples:\n\t//     - value: '4096'\n\tEncryptionBlockSize uint64 `yaml:\"blockSize,omitempty\"`\n\t//   description: >\n\t//     Additional --perf parameters for the LUKS2 encryption.\n\t//   values:\n\t//     - no_read_workqueue\n\t//     - no_write_workqueue\n\t//     - same_cpu_crypt\n\t//   examples:\n\t//     -  value: >\n\t//          []string{\"no_read_workqueue\",\"no_write_workqueue\"}\n\tEncryptionPerfOptions []string `yaml:\"options,omitempty\"`\n}\n\nfunc exampleEncryptionSpec() *EncryptionSpec {\n\treturn &EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyStatic: &EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"exampleKey\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot: 1,\n\t\t\t\tKeyKMS: &EncryptionKeyKMS{\n\t\t\t\t\tKMSEndpoint: \"https://example-kms-endpoint.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tEncryptionCipher:    \"aes-xts-plain64\",\n\t\tEncryptionBlockSize: 4096,\n\t}\n}\n\n// IsZero checks if the encryption spec is zero.\nfunc (s EncryptionSpec) IsZero() bool {\n\treturn s.EncryptionProvider == block.EncryptionProviderNone && len(s.EncryptionKeys) == 0\n}\n\n// EncryptionKey represents configuration for disk encryption key.\ntype EncryptionKey struct {\n\t//   description: >\n\t//     Key slot number for LUKS2 encryption.\n\tKeySlot int `yaml:\"slot\"`\n\t//   description: >\n\t//     Key which value is stored in the configuration file.\n\tKeyStatic *EncryptionKeyStatic `yaml:\"static,omitempty\"`\n\t//   description: >\n\t//     Deterministically generated key from the node UUID and PartitionLabel.\n\tKeyNodeID *EncryptionKeyNodeID `yaml:\"nodeID,omitempty\"`\n\t//   description: >\n\t//     KMS managed encryption key.\n\tKeyKMS *EncryptionKeyKMS `yaml:\"kms,omitempty\"`\n\t//   description: >\n\t//     Enable TPM based disk encryption.\n\tKeyTPM *EncryptionKeyTPM `yaml:\"tpm,omitempty\"`\n\t//   description: >\n\t//     Lock the disk encryption key to the random salt stored in the STATE partition.\n\t//     This is useful to prevent the volume from being unlocked if STATE partition is compromised\n\t//     or replaced. It is recommended to use this option with TPM disk encryption for\n\t//     non-STATE volumes.\n\tKeyLockToSTATE *bool `yaml:\"lockToState,omitempty\"`\n}\n\n// EncryptionKeyStatic represents throw away key type.\ntype EncryptionKeyStatic struct {\n\t//   description: >\n\t//     Defines the static passphrase value.\n\tKeyData string `yaml:\"passphrase,omitempty\"`\n}\n\n// EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n//\n//\texamples:\n//\t  - value: exampleKMSKey()\ntype EncryptionKeyKMS struct {\n\t//   description: >\n\t//     KMS endpoint to Seal/Unseal the key.\n\tKMSEndpoint string `yaml:\"endpoint\"`\n}\n\n// EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\ntype EncryptionKeyTPM struct {\n\t//   description: >\n\t//     TPM options for key protection.\n\tTPMOptions *EncryptionKeyTPMOptions `yaml:\"options,omitempty\"`\n\n\t//   description: >\n\t//     Check that Secureboot is enabled in the EFI firmware.\n\t//\n\t//     If Secureboot is not enabled, the enrollment of the key will fail.\n\tTPMCheckSecurebootStatusOnEnroll *bool `yaml:\"checkSecurebootStatusOnEnroll,omitempty\"`\n}\n\n// EncryptionKeyTPMOptions represents the options for TPM-based key protection.\ntype EncryptionKeyTPMOptions struct {\n\t//   description: >\n\t//     List of PCRs to bind the key to.\n\t//     If not set, defaults to PCR 7, can be disabled by passing an empty list.\n\tPCRs []int `yaml:\"pcrs,omitempty\"`\n}\n\n// EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\ntype EncryptionKeyNodeID struct{}\n\nfunc exampleKMSKey() *EncryptionKeyKMS {\n\treturn &EncryptionKeyKMS{\n\t\tKMSEndpoint: \"https://192.168.88.21:4443\",\n\t}\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s EncryptionSpec) Validate() ([]string, error) {\n\tif s.IsZero() {\n\t\treturn nil, nil\n\t}\n\n\tvar errs error\n\n\tswitch s.EncryptionProvider {\n\tcase block.EncryptionProviderLUKS2:\n\tcase block.EncryptionProviderNone:\n\t\tfallthrough\n\tdefault:\n\t\terrs = errors.Join(errs, fmt.Errorf(\"unsupported encryption provider: %s\", s.EncryptionProvider))\n\t}\n\n\tif len(s.EncryptionKeys) == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"encryption keys are required\"))\n\t}\n\n\tslotsInUse := make(map[int]struct{}, len(s.EncryptionKeys))\n\n\tfor _, key := range s.EncryptionKeys {\n\t\tif _, ok := slotsInUse[key.KeySlot]; ok {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"duplicate key slot %d\", key.KeySlot))\n\t\t}\n\n\t\tslotsInUse[key.KeySlot] = struct{}{}\n\n\t\tif key.KeyStatic == nil && key.KeyNodeID == nil && key.KeyKMS == nil && key.KeyTPM == nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"at least one encryption key type must be specified for slot %d\", key.KeySlot))\n\t\t}\n\n\t\tif key.KeyTPM != nil && key.KeyTPM.TPMOptions != nil {\n\t\t\tfor _, pcr := range key.KeyTPM.TPMOptions.PCRs {\n\t\t\t\tif pcr < 0 || pcr > 23 {\n\t\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"TPM PCR %d is out of range (0-23)\", pcr))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, errs\n}\n\n// Provider implements the config.Provider interface.\nfunc (s EncryptionSpec) Provider() block.EncryptionProviderType {\n\treturn s.EncryptionProvider\n}\n\n// Cipher implements the config.Provider interface.\nfunc (s EncryptionSpec) Cipher() string {\n\treturn s.EncryptionCipher\n}\n\n// KeySize implements the config.Provider interface.\nfunc (s EncryptionSpec) KeySize() uint {\n\treturn s.EncryptionKeySize\n}\n\n// BlockSize implements the config.Provider interface.\nfunc (s EncryptionSpec) BlockSize() uint64 {\n\treturn s.EncryptionBlockSize\n}\n\n// Options implements the config.Provider interface.\nfunc (s EncryptionSpec) Options() []string {\n\treturn s.EncryptionPerfOptions\n}\n\n// Keys implements the config.Provider interface.\nfunc (s EncryptionSpec) Keys() []config.EncryptionKey {\n\treturn xslices.Map(s.EncryptionKeys, func(k EncryptionKey) config.EncryptionKey { return k })\n}\n\n// Slot implements the config.Provider interface.\nfunc (k EncryptionKey) Slot() int {\n\treturn k.KeySlot\n}\n\n// LockToSTATE implements the config.Provider interface.\nfunc (k EncryptionKey) LockToSTATE() bool {\n\treturn pointer.SafeDeref(k.KeyLockToSTATE)\n}\n\n// Static implements the config.Provider interface.\nfunc (k EncryptionKey) Static() config.EncryptionKeyStatic {\n\tif k.KeyStatic == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KeyStatic\n}\n\n// NodeID implements the config.Provider interface.\nfunc (k EncryptionKey) NodeID() config.EncryptionKeyNodeID {\n\tif k.KeyNodeID == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KeyNodeID\n}\n\n// KMS implements the config.Provider interface.\nfunc (k EncryptionKey) KMS() config.EncryptionKeyKMS {\n\tif k.KeyKMS == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KeyKMS\n}\n\n// TPM implements the config.Provider interface.\nfunc (k EncryptionKey) TPM() config.EncryptionKeyTPM {\n\tif k.KeyTPM == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KeyTPM\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyNodeID) String() string {\n\treturn \"nodeid\"\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) String() string {\n\treturn \"tpm\"\n}\n\n// CheckSecurebootOnEnroll implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) CheckSecurebootOnEnroll() bool {\n\tif e == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(e.TPMCheckSecurebootStatusOnEnroll)\n}\n\n// PCRs implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) PCRs() []int {\n\tif e == nil {\n\t\treturn []int{}\n\t}\n\n\tif e.TPMOptions == nil {\n\t\treturn []int{constants.SecureBootStatePCR}\n\t}\n\n\treturn e.TPMOptions.PCRs\n}\n\n// PubKeyPCRs implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) PubKeyPCRs() []int {\n\t// we always lock to PCR 11\n\treturn []int{constants.UKIPCR}\n}\n\n// Key implements the config.Provider interface.\nfunc (e *EncryptionKeyStatic) Key() []byte {\n\treturn []byte(e.KeyData)\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyStatic) String() string {\n\treturn \"static\"\n}\n\n// Endpoint implements the config.Provider interface.\nfunc (e *EncryptionKeyKMS) Endpoint() string {\n\treturn e.KMSEndpoint\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyKMS) String() string {\n\treturn \"kms\"\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/existing_volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// ExistingVolumeConfigKind is a config document kind.\nconst ExistingVolumeConfigKind = \"ExistingVolumeConfig\"\n\nfunc init() {\n\tregistry.Register(ExistingVolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &ExistingVolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.ExistingVolumeConfig = &ExistingVolumeConfigV1Alpha1{}\n\t_ config.ConflictingDocument  = &ExistingVolumeConfigV1Alpha1{}\n\t_ config.NamedDocument        = &ExistingVolumeConfigV1Alpha1{}\n\t_ config.Validator            = &ExistingVolumeConfigV1Alpha1{}\n)\n\n// ExistingVolumeConfigV1Alpha1 is an existing volume configuration document.\n//\n//\tdescription: |\n//\t  Existing volumes allow to mount partitions (or whole disks) that were created\n//\t  outside of Talos. Volume will be mounted under `/var/mnt/<name>`.\n//\t  The existing volume config name should not conflict with user volume names.\n//\texamples:\n//\t  - value: exampleExistingVolumeConfigV1Alpha1()\n//\talias: ExistingVolumeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ExistingVolumeConfig\ntype ExistingVolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the volume.\n\t//\n\t//     Name can only contain:\n\t//     lowercase and uppercase ASCII letters, digits, and hyphens.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The discovery describes how to find a volume.\n\tVolumeDiscoverySpec VolumeDiscoverySpec `yaml:\"discovery,omitempty\"`\n\t//   description: |\n\t//     The mount describes additional mount options.\n\tMountSpec ExistingMountSpec `yaml:\"mount,omitempty\"`\n}\n\n// VolumeDiscoverySpec describes how the volume is discovered.\ntype VolumeDiscoverySpec struct {\n\t//   description: |\n\t//     The volume selector expression.\n\tVolumeSelectorConfig VolumeSelector `yaml:\"volumeSelector,omitempty\"`\n}\n\n// VolumeSelector selects an existing volume.\ntype VolumeSelector struct {\n\t//   description: |\n\t//     The Common Expression Language (CEL) expression to match the volume.\n\t//   schema:\n\t//     type: string\n\t//   examples:\n\t//    - value: >\n\t//        exampleVolumeSelector1()\n\t//      name: match volumes with partition label MY-DATA\n\t//    - value: >\n\t//        exampleVolumeSelector2()\n\t//      name: match xfs volume on disk with serial 'SERIAL123'\n\tMatch cel.Expression `yaml:\"match,omitempty\"`\n}\n\nfunc exampleVolumeSelector1() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`volume.partition_label == \"MY-DATA\"`, celenv.VolumeLocator()))\n}\n\nfunc exampleVolumeSelector2() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`volume.name == \"xfs\" && disk.serial == \"SERIAL123\"`, celenv.VolumeLocator()))\n}\n\n// ExistingMountSpec describes how the volume is mounted.\ntype ExistingMountSpec struct {\n\t//   description: |\n\t//     Mount the volume read-only.\n\tMountReadOnly *bool `yaml:\"readOnly,omitempty\"`\n\t//   description: |\n\t//     If true, disable file access time updates.\n\tMountDisableAccessTime *bool `yaml:\"disableAccessTime,omitempty\"`\n\t//   description: |\n\t//     Enable secure mount options (nosuid, nodev).\n\t//\n\t//     Defaults to true for better security.\n\tMountSecure *bool `yaml:\"secure,omitempty\"`\n}\n\n// NewExistingVolumeConfigV1Alpha1 creates a new raw volume config document.\nfunc NewExistingVolumeConfigV1Alpha1() *ExistingVolumeConfigV1Alpha1 {\n\treturn &ExistingVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ExistingVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleExistingVolumeConfigV1Alpha1() *ExistingVolumeConfigV1Alpha1 {\n\tcfg := NewExistingVolumeConfigV1Alpha1()\n\tcfg.MetaName = \"my-existing-volume\"\n\tcfg.VolumeDiscoverySpec = VolumeDiscoverySpec{\n\t\tVolumeSelectorConfig: VolumeSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`volume.partition_label == \"MY-DATA\"`, celenv.VolumeLocator())),\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *ExistingVolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *ExistingVolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *ExistingVolumeConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn []string{UserVolumeConfigKind}\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo,dupl\nfunc (s *ExistingVolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string //nolint:prealloc\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name is required\"))\n\t}\n\n\tif strings.ContainsFunc(s.MetaName, func(r rune) bool {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\treturn false\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn false\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn false\n\t\tcase r == '-':\n\t\t\treturn false\n\t\tdefault: // invalid symbol\n\t\t\treturn true\n\t\t}\n\t}) {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\"))\n\t}\n\n\textraWarnings, extraErrors := s.VolumeDiscoverySpec.Validate(true)\n\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\treturn warnings, validationErrors\n}\n\n// ExistingVolumeConfigSignal is a signal for user volume config.\nfunc (s *ExistingVolumeConfigV1Alpha1) ExistingVolumeConfigSignal() {}\n\n// VolumeDiscovery implements config.ExistingVolumeConfig interface.\nfunc (s *ExistingVolumeConfigV1Alpha1) VolumeDiscovery() config.VolumeDiscoveryConfig {\n\treturn s.VolumeDiscoverySpec\n}\n\n// Mount implements config.ExistingVolumeConfig interface.\nfunc (s *ExistingVolumeConfigV1Alpha1) Mount() config.ExistingVolumeMountConfig {\n\treturn s.MountSpec\n}\n\n// Validate the provisioning spec.\nfunc (s VolumeDiscoverySpec) Validate(required bool) ([]string, error) {\n\tvar validationErrors error\n\n\tif !s.VolumeSelectorConfig.Match.IsZero() {\n\t\tif err := s.VolumeSelectorConfig.Match.ParseBool(celenv.VolumeLocator()); err != nil {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"volume selector is invalid: %w\", err))\n\t\t}\n\t} else {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"volume selector is required\"))\n\t}\n\n\treturn nil, validationErrors\n}\n\n// VolumeSelector implements config.VolumeDiscoveryConfig interface.\nfunc (s VolumeDiscoverySpec) VolumeSelector() cel.Expression {\n\treturn s.VolumeSelectorConfig.Match\n}\n\n// ReadOnly implements config.ExistingVolumeMountConfig interface.\nfunc (s ExistingMountSpec) ReadOnly() bool {\n\treturn pointer.SafeDeref(s.MountReadOnly)\n}\n\n// DisableAccessTime implements config.ExistingVolumeMountConfig interface.\nfunc (s ExistingMountSpec) DisableAccessTime() bool {\n\treturn pointer.SafeDeref(s.MountDisableAccessTime)\n}\n\n// Secure implements config.ExistingVolumeMountConfig interface.\nfunc (s ExistingMountSpec) Secure() bool {\n\tif s.MountSecure == nil {\n\t\treturn true\n\t}\n\n\treturn *s.MountSecure\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/existing_volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestExistingVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"with selector\",\n\t\t\tfilename: \"existingvolumeconfig_selector.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExistingVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"my-lovely-volume\"\n\n\t\t\t\trequire.NoError(t, c.VolumeDiscoverySpec.VolumeSelectorConfig.Match.UnmarshalText([]byte(`volume.partition_label == \"MY-DATA\"`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestExistingVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"no name\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExistingVolumeConfigV1Alpha1()\n\n\t\t\t\trequire.NoError(t, c.VolumeDiscoverySpec.VolumeSelectorConfig.Match.UnmarshalText([]byte(`volume.partition_label == \"MY-DATA\"`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid characters in name\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExistingVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"some/name\"\n\n\t\t\t\trequire.NoError(t, c.VolumeDiscoverySpec.VolumeSelectorConfig.Match.UnmarshalText([]byte(`volume.partition_label == \"MY-DATA\"`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid volume selector\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExistingVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.VolumeDiscoverySpec.VolumeSelectorConfig.Match.UnmarshalText([]byte(`volume.partition_label == 3`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"volume selector is invalid: ERROR: <input>:1:24: found no matching overload for '_==_' applied to '(string, int)'\\n | volume.partition_label == 3\\n | .......................^\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExistingVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExistingVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.VolumeDiscoverySpec.VolumeSelectorConfig.Match.UnmarshalText([]byte(`volume.partition_label == \"MY-DATA\"`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/external_volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// ExternalVolumeConfigKind is a config document kind.\nconst ExternalVolumeConfigKind = \"ExternalVolumeConfig\"\n\nfunc init() {\n\tregistry.Register(ExternalVolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &ExternalVolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.ExternalVolumeConfig = &ExternalVolumeConfigV1Alpha1{}\n\t_ config.NamedDocument        = &ExternalVolumeConfigV1Alpha1{}\n\t_ config.Validator            = &ExternalVolumeConfigV1Alpha1{}\n)\n\nconst maxExternalVolumeNameLength = constants.PartitionLabelLength - len(constants.ExternalVolumePrefix)\n\n// FilesystemType is an alias for block.FilesystemType.\ntype FilesystemType = block.FilesystemType\n\n// ExternalVolumeConfigV1Alpha1 is an external disk mount configuration document.\n//\n//\tdescription: |\n//\t  External volumes allow to mount volumes that were created outside of Talos,\n//\t  over the network or API. Volume will be mounted under `/var/mnt/<name>`.\n//\t  The external volume config name should not conflict with user volume names.\n//\texamples:\n//\t  - value: exampleExternalVolumeConfigV1Alpha1Virtiofs()\n//\talias: ExternalVolumeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ExternalVolumeConfig\ntype ExternalVolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the mount.\n\t//\n\t//     Name might be between 1 and 34 characters long and can only contain:\n\t//     lowercase and uppercase ASCII letters, digits, and hyphens.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Filesystem type.\n\t//   values:\n\t//     - virtiofs\n\t//     - nfs\n\t//  schema:\n\t//    type: string\n\tFilesystemType FilesystemType `yaml:\"filesystemType\"`\n\t//   description: |\n\t//     The mount describes additional mount options.\n\tMountSpec ExternalMountSpec `yaml:\"mount,omitempty\"`\n}\n\n// ExternalMountSpec describes how the external volume is mounted.\ntype ExternalMountSpec struct {\n\t//   description: |\n\t//     Mount the volume read-only.\n\tMountReadOnly *bool `yaml:\"readOnly,omitempty\"`\n\t//   description: |\n\t//     If true, disable file access time updates.\n\tMountDisableAccessTime *bool `yaml:\"disableAccessTime,omitempty\"`\n\t//   description: |\n\t//     Enable secure mount options (nosuid, nodev).\n\t//\n\t//     Defaults to true for better security.\n\tMountSecure *bool `yaml:\"secure,omitempty\"`\n\n\t//   description: |\n\t//     Virtiofs mount options.\n\tMountVirtiofs *VirtiofsMountSpec `yaml:\"virtiofs,omitempty\"`\n}\n\n// VirtiofsMountSpec describes Virtiofs mount options.\ntype VirtiofsMountSpec struct {\n\t//   description: |\n\t//     Selector tag for the Virtiofs mount.\n\tVirtiofsTag string `yaml:\"tag\"`\n}\n\n// NewExternalVolumeConfigV1Alpha1 creates a new user mount config document.\nfunc NewExternalVolumeConfigV1Alpha1() *ExternalVolumeConfigV1Alpha1 {\n\treturn &ExternalVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ExternalVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleExternalVolumeConfigV1Alpha1Virtiofs() *ExternalVolumeConfigV1Alpha1 {\n\tcfg := NewExternalVolumeConfigV1Alpha1()\n\tcfg.MetaName = \"mount1\"\n\tcfg.FilesystemType = block.FilesystemTypeVirtiofs\n\tcfg.MountSpec.MountVirtiofs = &VirtiofsMountSpec{\n\t\tVirtiofsTag: \"Data\",\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *ExternalVolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *ExternalVolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo,dupl\nfunc (s *ExternalVolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name is required\"))\n\t}\n\n\tif len(s.MetaName) < 1 || len(s.MetaName) > maxExternalVolumeNameLength {\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"name must be between 1 and %d characters long\", maxExternalVolumeNameLength))\n\t}\n\n\tif strings.ContainsFunc(s.MetaName, func(r rune) bool {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\treturn false\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn false\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn false\n\t\tcase r == '-':\n\t\t\treturn false\n\t\tdefault: // invalid symbol\n\t\t\treturn true\n\t\t}\n\t}) {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\"))\n\t}\n\n\tswitch s.FilesystemType {\n\tcase block.FilesystemTypeVirtiofs:\n\t\textraWarnings, extraErrors := s.MountSpec.MountVirtiofs.Validate()\n\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\tcase block.FilesystemTypeNone, block.FilesystemTypeXFS, block.FilesystemTypeVFAT, block.FilesystemTypeEXT4, block.FilesystemTypeISO9660, block.FilesystemTypeSwap:\n\t\tfallthrough\n\n\tdefault:\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"invalid filesystem type: %s\", s.FilesystemType))\n\t}\n\n\treturn warnings, validationErrors\n}\n\n// ExternalVolumeConfigSignal is a signal for user mount config.\nfunc (s *ExternalVolumeConfigV1Alpha1) ExternalVolumeConfigSignal() {}\n\n// Type implements config.ExternalVolumeConfig interface.\nfunc (s *ExternalVolumeConfigV1Alpha1) Type() FilesystemType {\n\treturn s.FilesystemType\n}\n\n// Mount implements config.ExternalVolumeConfig interface.\nfunc (s *ExternalVolumeConfigV1Alpha1) Mount() config.ExternalVolumeMountConfig {\n\treturn s.MountSpec\n}\n\n// ReadOnly implements config.ExternalVolumeMountConfig interface.\nfunc (s ExternalMountSpec) ReadOnly() bool {\n\treturn pointer.SafeDeref(s.MountReadOnly)\n}\n\n// DisableAccessTime implements config.ExternalVolumeMountConfig interface.\nfunc (s ExternalMountSpec) DisableAccessTime() bool {\n\treturn pointer.SafeDeref(s.MountDisableAccessTime)\n}\n\n// Secure implements config.ExternalVolumeMountConfig interface.\nfunc (s ExternalMountSpec) Secure() bool {\n\tif s.MountSecure == nil {\n\t\treturn true\n\t}\n\n\treturn *s.MountSecure\n}\n\n// Virtiofs implements config.VolumeMountConfig interface.\nfunc (s ExternalMountSpec) Virtiofs() optional.Optional[config.ExternalVolumeMountConfigSpec] {\n\tif s.MountVirtiofs == nil {\n\t\treturn optional.None[config.ExternalVolumeMountConfigSpec]()\n\t}\n\n\treturn optional.Some[config.ExternalVolumeMountConfigSpec](*s.MountVirtiofs)\n}\n\n// Source implements config.ExternalVolumeMountConfigSpec interface.\nfunc (s VirtiofsMountSpec) Source() string {\n\treturn s.VirtiofsTag\n}\n\n// Parameters implements config.NFSMountConfig interface.\nfunc (s VirtiofsMountSpec) Parameters() ([]block.ParameterSpec, error) {\n\treturn nil, nil\n}\n\n// Validate implements config.Validator interface.\nfunc (s *VirtiofsMountSpec) Validate() ([]string, error) {\n\tvar validationErrors error\n\n\tif s == nil {\n\t\treturn nil, errors.New(\"virtiofs mount spec is required\")\n\t}\n\n\tif s.VirtiofsTag == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"virtiofs tag is required\"))\n\t}\n\n\treturn nil, validationErrors\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/external_volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestExternalVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"basic virtiofs\",\n\t\t\tfilename: \"externalvolumeconfig_basicvirtiofs.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"my-virtiofs-volume\"\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeVirtiofs\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestExternalVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"no name\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeVirtiofs\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name is required\\nname must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid characters in name\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"some/name\"\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeVirtiofs\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\",\n\t\t},\n\t\t{\n\t\t\tname: \"no mount spec\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeVirtiofs\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"virtiofs mount spec is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid type\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeEXT4\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"invalid filesystem type: ext4\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty type\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"invalid filesystem type: none\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid virtiofs\",\n\n\t\t\tcfg: func(t *testing.T) *block.ExternalVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewExternalVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.FilesystemType = blockres.FilesystemTypeVirtiofs\n\t\t\t\tc.MountSpec.MountVirtiofs = new(block.VirtiofsMountSpec)\n\t\t\t\tc.MountSpec.MountVirtiofs.VirtiofsTag = \"Data\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/percentage_size.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"bytes\"\n\t\"encoding\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"gopkg.in/yaml.v3\"\n)\n\n// Check interfaces.\nvar (\n\t_ encoding.TextMarshaler   = PercentageSize{}\n\t_ encoding.TextUnmarshaler = (*PercentageSize)(nil)\n\t_ yaml.IsZeroer            = PercentageSize{}\n)\n\n// PercentageSize is a size in percents.\ntype PercentageSize struct {\n\tvalue    *uint64\n\traw      []byte\n\tnegative bool\n}\n\n// Value returns the value.\nfunc (ps PercentageSize) Value() uint64 {\n\treturn pointer.SafeDeref(ps.value)\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (ps PercentageSize) MarshalText() ([]byte, error) {\n\tif ps.raw != nil {\n\t\treturn ps.raw, nil\n\t}\n\n\tif ps.value != nil {\n\t\treturn []byte(strconv.FormatUint(*ps.value, 10)), nil\n\t}\n\n\treturn nil, nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (ps *PercentageSize) UnmarshalText(text []byte) error {\n\tif len(text) == 0 {\n\t\tps.value = nil\n\t\tps.raw = nil\n\n\t\treturn nil\n\t}\n\n\tif !bytes.HasSuffix(text, []byte(\"%\")) {\n\t\treturn fmt.Errorf(\"percentage must end with '%%'\")\n\t}\n\n\traw := slices.Clone(text)\n\n\tif v, ok := bytes.CutPrefix(text, []byte(\"-\")); ok {\n\t\ttext = v\n\t\tps.negative = true\n\t}\n\n\tnumStr := string(text[:len(text)-1])\n\n\tvalue, err := strconv.ParseFloat(numStr, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid percentage value: %w\", err)\n\t}\n\n\tif value < 0 || value > 100 {\n\t\treturn fmt.Errorf(\"percentage must be between 0 and 100, got %v\", value)\n\t}\n\n\tps.value = new(uint64(value))\n\tps.raw = raw\n\n\treturn nil\n}\n\n// IsZero implements yaml.IsZeroer.\nfunc (ps PercentageSize) IsZero() bool {\n\treturn ps.value == nil && ps.raw == nil\n}\n\n// IsNegative returns true if the value is negative.\nfunc (ps PercentageSize) IsNegative() bool {\n\treturn ps.negative\n}\n\n// Merge implements merger interface.\nfunc (ps *PercentageSize) Merge(other any) error {\n\totherPS, ok := other.(PercentageSize)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot merge %T with %T\", ps, other)\n\t}\n\n\tps.raw = otherPS.raw\n\tps.value = otherPS.value\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/raw_volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// RawVolumeConfigKind is a config document kind.\nconst RawVolumeConfigKind = \"RawVolumeConfig\"\n\nfunc init() {\n\tregistry.Register(RawVolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RawVolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RawVolumeConfig = &RawVolumeConfigV1Alpha1{}\n\t_ config.NamedDocument   = &RawVolumeConfigV1Alpha1{}\n\t_ config.Validator       = &RawVolumeConfigV1Alpha1{}\n)\n\nconst maxRawVolumeNameLength = constants.PartitionLabelLength - len(constants.RawVolumePrefix)\n\n// RawVolumeConfigV1Alpha1 is a raw volume configuration document.\n//\n//\t\tdescription: |\n//\t\t  Raw volumes allow to create partitions without formatting them.\n//\t   If you want to use local storage, user volumes is a better choice,\n//\t   raw volumes are intended to be used with CSI provisioners.\n//\t\t  The partition label is automatically generated as `r-<name>`.\n//\t\texamples:\n//\t\t  - value: exampleRawVolumeConfigV1Alpha1()\n//\t\talias: RawVolumeConfig\n//\t\tschemaRoot: true\n//\t\tschemaMeta: v1alpha1/RawVolumeConfig\ntype RawVolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the volume.\n\t//\n\t//     Name might be between 1 and 34 characters long and can only contain:\n\t//     lowercase and uppercase ASCII letters, digits, and hyphens.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The provisioning describes how the volume is provisioned.\n\tProvisioningSpec ProvisioningSpec `yaml:\"provisioning,omitempty\"`\n\t//   description: |\n\t//     The encryption describes how the volume is encrypted.\n\tEncryptionSpec EncryptionSpec `yaml:\"encryption,omitempty\"`\n}\n\n// NewRawVolumeConfigV1Alpha1 creates a new raw volume config document.\nfunc NewRawVolumeConfigV1Alpha1() *RawVolumeConfigV1Alpha1 {\n\treturn &RawVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RawVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleRawVolumeConfigV1Alpha1() *RawVolumeConfigV1Alpha1 {\n\tcfg := NewRawVolumeConfigV1Alpha1()\n\tcfg.MetaName = \"local-data\"\n\tcfg.ProvisioningSpec = ProvisioningSpec{\n\t\tDiskSelectorSpec: DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t},\n\t\tProvisioningMaxSize: MustSize(\"50GiB\"),\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *RawVolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *RawVolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo,dupl\nfunc (s *RawVolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string //nolint:prealloc\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name is required\"))\n\t}\n\n\tif len(s.MetaName) < 1 || len(s.MetaName) > maxRawVolumeNameLength {\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"name must be between 1 and %d characters long\", maxRawVolumeNameLength))\n\t}\n\n\tif strings.ContainsFunc(s.MetaName, func(r rune) bool {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\treturn false\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn false\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn false\n\t\tcase r == '-':\n\t\t\treturn false\n\t\tdefault: // invalid symbol\n\t\t\treturn true\n\t\t}\n\t}) {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\"))\n\t}\n\n\textraWarnings, extraErrors := s.ProvisioningSpec.Validate(true, true)\n\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\textraWarnings, extraErrors = s.EncryptionSpec.Validate()\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\treturn warnings, validationErrors\n}\n\n// RawVolumeConfigSignal is a signal for user volume config.\nfunc (s *RawVolumeConfigV1Alpha1) RawVolumeConfigSignal() {}\n\n// Provisioning implements config.RawVolumeConfig interface.\nfunc (s *RawVolumeConfigV1Alpha1) Provisioning() config.VolumeProvisioningConfig {\n\treturn s.ProvisioningSpec\n}\n\n// Encryption implements config.RawVolumeConfig interface.\nfunc (s *RawVolumeConfigV1Alpha1) Encryption() config.EncryptionConfig {\n\tif s.EncryptionSpec.EncryptionProvider == block.EncryptionProviderNone {\n\t\treturn nil\n\t}\n\n\treturn s.EncryptionSpec\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/raw_volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestRawVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.RawVolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"disk selector\",\n\t\t\tfilename: \"rawvolumeconfig_diskselector.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"ceph-data\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == \"nvme\" && !system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"100GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"encrypted\",\n\t\t\tfilename: \"rawvolumeconfig_encrypted.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"secret-store\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestRawVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.RawVolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"no name\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name is required\\nname must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"too long name\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = strings.Repeat(\"X\", 35)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid characters in name\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"some/name\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid disk selector\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is invalid: ERROR: <input>:1:11: found no matching overload for '_>_' applied to '(uint, int)'\\n | disk.size > 120\\n | ..........^\\nmin size or max size is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"min size greater than max size\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is required\\nmin size is greater than max size\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption provider\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"unsupported encryption provider: none\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption keys\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"encryption keys are required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid encryption key slots\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"at least one encryption key type must be specified for slot 0\\nduplicate key slot 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid encrypted\",\n\n\t\t\tcfg: func(t *testing.T) *block.RawVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewRawVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/size.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"encoding\"\n\t\"strings\"\n\n\t\"gopkg.in/yaml.v3\"\n)\n\n// Check interfaces.\nvar (\n\t_ encoding.TextMarshaler   = Size{}\n\t_ encoding.TextUnmarshaler = (*PercentageSize)(nil)\n\t_ yaml.IsZeroer            = Size{}\n)\n\n// Size is either a PercentageSize or ByteSize.\ntype Size struct {\n\tPercentageSize *PercentageSize\n\tByteSize       *ByteSize\n}\n\n// MustSize returns a new Size with the given value.\n//\n// It panics if the value is invalid.\nfunc MustSize(value string) Size {\n\tvar s Size\n\n\tif err := s.UnmarshalText([]byte(value)); err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn s\n}\n\n// MustByteSize returns a new Size with the given ByteSize value.\n//\n// It panics if the value is invalid.\nfunc MustByteSize(value string) ByteSize {\n\tvar bs ByteSize\n\n\tif err := bs.UnmarshalText([]byte(value)); err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn bs\n}\n\n// Value returns the value.\nfunc (s Size) Value() uint64 {\n\tif s.ByteSize != nil {\n\t\treturn s.ByteSize.Value()\n\t}\n\n\treturn 0\n}\n\n// RelativeValue returns the relative value.\nfunc (s Size) RelativeValue() (uint64, bool) {\n\tif s.PercentageSize != nil {\n\t\treturn s.PercentageSize.Value(), true\n\t}\n\n\treturn 0, false\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (s Size) MarshalText() ([]byte, error) {\n\tif s.ByteSize != nil {\n\t\treturn s.ByteSize.MarshalText()\n\t}\n\n\tif s.PercentageSize != nil {\n\t\treturn s.PercentageSize.MarshalText()\n\t}\n\n\treturn nil, nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (s *Size) UnmarshalText(text []byte) error {\n\tif string(text) == \"\" {\n\t\treturn nil\n\t}\n\n\tif strings.Contains(string(text), \"%\") {\n\t\tvar ps PercentageSize\n\t\tif err := ps.UnmarshalText(text); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ts.PercentageSize = &ps\n\t} else {\n\t\tvar bs ByteSize\n\t\tif err := bs.UnmarshalText(text); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ts.ByteSize = &bs\n\t}\n\n\treturn nil\n}\n\n// IsZero implements yaml.IsZeroer.\nfunc (s Size) IsZero() bool {\n\treturn (s.PercentageSize == nil || s.PercentageSize.IsZero()) && (s.ByteSize == nil || s.ByteSize.IsZero())\n}\n\n// IsRelative returns if the Size is a relative size.\nfunc (s Size) IsRelative() bool {\n\treturn (s.PercentageSize != nil && !s.PercentageSize.IsZero())\n}\n\n// IsNegative returns true if the value is negative.\nfunc (s Size) IsNegative() bool {\n\tif s.ByteSize != nil {\n\t\treturn s.ByteSize.IsNegative()\n\t}\n\n\tif s.PercentageSize != nil {\n\t\treturn s.PercentageSize.IsNegative()\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/size_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n)\n\nfunc TestSizeUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tin       string\n\t\twant     uint64\n\t\tnegative bool\n\t}{\n\t\t{in: \"\", want: 0},\n\t\t{in: \"100%\", want: 100},\n\t\t{in: \"33.4%\", want: 33},\n\t\t{in: \"33.4124%\", want: 33},\n\t\t{in: \"1048576\", want: 1048576},\n\t\t{in: \"2.5GiB\", want: 2684354560},\n\t\t{in: \"2.5GB\", want: 2500000000},\n\t\t{in: \"2.5G\", want: 2500000000},\n\t\t{in: \"1MiB\", want: 1048576},\n\t\t{in: \"-100%\", want: 100, negative: true},\n\t\t{in: \"-33.4%\", want: 33, negative: true},\n\t\t{in: \"-33.4124%\", want: 33, negative: true},\n\t\t{in: \"-1048576\", want: 1048576, negative: true},\n\t\t{in: \"-2.5GiB\", want: 2684354560, negative: true},\n\t\t{in: \"-2.5GB\", want: 2500000000, negative: true},\n\t\t{in: \"-2.5G\", want: 2500000000, negative: true},\n\t\t{in: \"-1MiB\", want: 1048576, negative: true},\n\t} {\n\t\tt.Run(test.in, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar s block.Size\n\n\t\t\trequire.NoError(t, s.UnmarshalText([]byte(test.in)))\n\n\t\t\tif strings.Contains(test.in, \"%\") {\n\t\t\t\tassert.Zero(t, s.Value())\n\n\t\t\t\tval, ok := s.RelativeValue()\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, test.want, val)\n\t\t\t\tassert.Equal(t, test.negative, s.IsNegative())\n\t\t\t} else {\n\t\t\t\tassert.Equal(t, test.want, s.Value())\n\n\t\t\t\tval, ok := s.RelativeValue()\n\t\t\t\tassert.False(t, ok)\n\t\t\t\tassert.Zero(t, val)\n\t\t\t\tassert.Equal(t, test.negative, s.IsNegative())\n\t\t\t}\n\n\t\t\tout, err := s.MarshalText()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.in, string(out))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/swap_volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// SwapVolumeConfigKind is a config document kind.\nconst SwapVolumeConfigKind = \"SwapVolumeConfig\"\n\nfunc init() {\n\tregistry.Register(SwapVolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &SwapVolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.SwapVolumeConfig = &SwapVolumeConfigV1Alpha1{}\n\t_ config.NamedDocument    = &SwapVolumeConfigV1Alpha1{}\n\t_ config.Validator        = &SwapVolumeConfigV1Alpha1{}\n)\n\nconst maxSwapVolumeNameLength = constants.PartitionLabelLength - len(constants.SwapVolumePrefix)\n\n// SwapVolumeConfigV1Alpha1 is a disk swap volume configuration document.\n//\n//\tdescription: |\n//\t  Swap volume is automatically allocated as a partition on the specified disk\n//\t  and activated as swap, removing a swap volume deactivates swap.\n//\t  The partition label is automatically generated as `s-<name>`.\n//\texamples:\n//\t  - value: exampleSwapVolumeConfigV1Alpha1()\n//\talias: SwapVolumeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/SwapVolumeConfig\ntype SwapVolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the volume.\n\t//\n\t//     Name might be between 1 and 34 characters long and can only contain:\n\t//     lowercase and uppercase ASCII letters, digits, and hyphens.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The provisioning describes how the volume is provisioned.\n\tProvisioningSpec ProvisioningSpec `yaml:\"provisioning,omitempty\"`\n\t//   description: |\n\t//     The encryption describes how the volume is encrypted.\n\tEncryptionSpec EncryptionSpec `yaml:\"encryption,omitempty\"`\n}\n\n// NewSwapVolumeConfigV1Alpha1 creates a new user volume config document.\nfunc NewSwapVolumeConfigV1Alpha1() *SwapVolumeConfigV1Alpha1 {\n\treturn &SwapVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       SwapVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleSwapVolumeConfigV1Alpha1() *SwapVolumeConfigV1Alpha1 {\n\tcfg := NewSwapVolumeConfigV1Alpha1()\n\tcfg.MetaName = \"swap1\"\n\tcfg.ProvisioningSpec = ProvisioningSpec{\n\t\tDiskSelectorSpec: DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t},\n\t\tProvisioningMinSize: MustByteSize(\"3GiB\"),\n\t\tProvisioningMaxSize: MustSize(\"4GiB\"),\n\t}\n\tcfg.EncryptionSpec = EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyStatic: &EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"swapsecret\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *SwapVolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *SwapVolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo,dupl\nfunc (s *SwapVolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string //nolint:prealloc\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name is required\"))\n\t}\n\n\tif len(s.MetaName) < 1 || len(s.MetaName) > maxSwapVolumeNameLength {\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"name must be between 1 and %d characters long\", maxSwapVolumeNameLength))\n\t}\n\n\tif strings.ContainsFunc(s.MetaName, func(r rune) bool {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\treturn false\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn false\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn false\n\t\tcase r == '-':\n\t\t\treturn false\n\t\tdefault: // invalid symbol\n\t\t\treturn true\n\t\t}\n\t}) {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\"))\n\t}\n\n\textraWarnings, extraErrors := s.ProvisioningSpec.Validate(true, true)\n\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\textraWarnings, extraErrors = s.EncryptionSpec.Validate()\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\treturn warnings, validationErrors\n}\n\n// SwapVolumeConfigSignal is a signal for swap volume config.\nfunc (s *SwapVolumeConfigV1Alpha1) SwapVolumeConfigSignal() {}\n\n// Provisioning implements config.SwapVolumeConfig interface.\nfunc (s *SwapVolumeConfigV1Alpha1) Provisioning() config.VolumeProvisioningConfig {\n\treturn s.ProvisioningSpec\n}\n\n// Encryption implements config.SwapVolumeConfig interface.\nfunc (s *SwapVolumeConfigV1Alpha1) Encryption() config.EncryptionConfig {\n\tif s.EncryptionSpec.EncryptionProvider == block.EncryptionProviderNone {\n\t\treturn nil\n\t}\n\n\treturn s.EncryptionSpec\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/swap_volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestSwapVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.SwapVolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"disk selector\",\n\t\t\tfilename: \"swapvolumeconfig_diskselector.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"big\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == \"nvme\" && !system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"100GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"encrypted\",\n\t\t\tfilename: \"swapvolumeconfig_encrypted.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"secret-swap\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestSwapVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.SwapVolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"no name\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name is required\\nname must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"too long name\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = strings.Repeat(\"X\", 35)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid characters in name\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"some/name\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid disk selector\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is invalid: ERROR: <input>:1:11: found no matching overload for '_>_' applied to '(uint, int)'\\n | disk.size > 120\\n | ..........^\\nmin size or max size is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"min size greater than max size\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is required\\nmin size is greater than max size\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption provider\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"unsupported encryption provider: none\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption keys\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"encryption keys are required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid encryption key slots\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"at least one encryption key type must be specified for slot 0\\nduplicate key slot 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid encrypted\",\n\n\t\t\tcfg: func(t *testing.T) *block.SwapVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewSwapVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/existingvolumeconfig_selector.yaml",
    "content": "apiVersion: v1alpha1\nkind: ExistingVolumeConfig\nname: my-lovely-volume\ndiscovery:\n    volumeSelector:\n        match: volume.partition_label == \"MY-DATA\"\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/externalvolumeconfig_basicvirtiofs.yaml",
    "content": "apiVersion: v1alpha1\nkind: ExternalVolumeConfig\nname: my-virtiofs-volume\nfilesystemType: virtiofs\nmount:\n    virtiofs:\n        tag: Data\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/rawvolumeconfig_diskselector.yaml",
    "content": "apiVersion: v1alpha1\nkind: RawVolumeConfig\nname: ceph-data\nprovisioning:\n    diskSelector:\n        match: disk.transport == \"nvme\" && !system_disk\n    minSize: 10GiB\n    maxSize: 100GiB\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/rawvolumeconfig_encrypted.yaml",
    "content": "apiVersion: v1alpha1\nkind: RawVolumeConfig\nname: secret-store\nprovisioning:\n    diskSelector:\n        match: '!system_disk'\n    minSize: 10GiB\nencryption:\n    provider: luks2\n    keys:\n        - slot: 0\n          tpm: {}\n        - slot: 1\n          static:\n            passphrase: topsecret\n    cipher: aes-xts-plain64\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/swapvolumeconfig_diskselector.yaml",
    "content": "apiVersion: v1alpha1\nkind: SwapVolumeConfig\nname: big\nprovisioning:\n    diskSelector:\n        match: disk.transport == \"nvme\" && !system_disk\n    minSize: 10GiB\n    maxSize: 100GiB\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/swapvolumeconfig_encrypted.yaml",
    "content": "apiVersion: v1alpha1\nkind: SwapVolumeConfig\nname: secret-swap\nprovisioning:\n    diskSelector:\n        match: '!system_disk'\n    minSize: 10GiB\nencryption:\n    provider: luks2\n    keys:\n        - slot: 0\n          tpm: {}\n        - slot: 1\n          static:\n            passphrase: topsecret\n    cipher: aes-xts-plain64\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/uservolumeconfig_diskselector.yaml",
    "content": "apiVersion: v1alpha1\nkind: UserVolumeConfig\nname: ceph-data\nprovisioning:\n    diskSelector:\n        match: disk.transport == \"nvme\" && !system_disk\n    minSize: 10GiB\n    maxSize: 100GiB\nfilesystem:\n    type: xfs\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/uservolumeconfig_encrypted.yaml",
    "content": "apiVersion: v1alpha1\nkind: UserVolumeConfig\nname: secret-store\nprovisioning:\n    diskSelector:\n        match: '!system_disk'\n    minSize: 10GiB\nencryption:\n    provider: luks2\n    keys:\n        - slot: 0\n          tpm: {}\n        - slot: 1\n          static:\n            passphrase: topsecret\n    cipher: aes-xts-plain64\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/uservolumeconfig_prjquota.yaml",
    "content": "apiVersion: v1alpha1\nkind: UserVolumeConfig\nname: secret-store\nprovisioning:\n    diskSelector:\n        match: '!system_disk'\n    minSize: 10GiB\nfilesystem:\n    type: xfs\n    projectQuotaSupport: true\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_diskselector.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\nprovisioning:\n    diskSelector:\n        match: disk.transport == \"nvme\" && !system_disk\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_empty.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_maxsize.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\nprovisioning:\n    minSize: 10GiB\n    maxSize: 2.5TiB\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_negativemaxsize.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL\nprovisioning:\n    minSize: 10GiB\n    maxSize: -10GiB\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_state.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: STATE\nencryption:\n    provider: luks2\n    keys:\n        - slot: 0\n          tpm: {}\n        - slot: 1\n          static:\n            passphrase: topsecret\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_tpm_encryption_no_options.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: STATE\nencryption:\n    provider: luks2\n    keys:\n        - tpm: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_tpm_encryption_with_pcr_settings.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: STATE\nencryption:\n    provider: luks2\n    keys:\n        - tpm:\n            options:\n                pcrs: [0,7]\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/volumeconfig_tpm_encryption_with_pcrs_disabled.yaml",
    "content": "apiVersion: v1alpha1\nkind: VolumeConfig\nname: STATE\nencryption:\n    provider: luks2\n    keys:\n        - tpm:\n            options:\n                pcrs: []\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/zswapconfig_full.yaml",
    "content": "apiVersion: v1alpha1\nkind: ZswapConfig\nmaxPoolPercent: 50\nshrinkerEnabled: true\n"
  },
  {
    "path": "pkg/machinery/config/types/block/testdata/zswapconfig_min.yaml",
    "content": "apiVersion: v1alpha1\nkind: ZswapConfig\n"
  },
  {
    "path": "pkg/machinery/config/types/block/user_volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// UserVolumeConfigKind is a config document kind.\nconst UserVolumeConfigKind = \"UserVolumeConfig\"\n\nfunc init() {\n\tregistry.Register(UserVolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &UserVolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.UserVolumeConfig    = &UserVolumeConfigV1Alpha1{}\n\t_ config.ConflictingDocument = &UserVolumeConfigV1Alpha1{}\n\t_ config.NamedDocument       = &UserVolumeConfigV1Alpha1{}\n\t_ config.Validator           = &UserVolumeConfigV1Alpha1{}\n)\n\nconst maxUserVolumeNameLength = constants.PartitionLabelLength - len(constants.UserVolumePrefix)\n\n// VolumeType is an alias for block.VolumeType.\ntype VolumeType = block.VolumeType\n\n// UserVolumeConfigV1Alpha1 is a user volume configuration document.\n//\n//\tdescription: |\n//\t  User volume is automatically allocated as a partition on the specified disk\n//\t  and mounted under `/var/mnt/<name>`.\n//\t  The partition label is automatically generated as `u-<name>`.\n//\texamples:\n//\t  - value: exampleUserVolumeConfigV1Alpha1Directory()\n//\t  - value: exampleUserVolumeConfigV1Alpha1Disk()\n//\t  - value: exampleUserVolumeConfigV1Alpha1Partition()\n//\talias: UserVolumeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/UserVolumeConfig\ntype UserVolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the volume.\n\t//\n\t//     Name might be between 1 and 34 characters long and can only contain:\n\t//     lowercase and uppercase ASCII letters, digits, and hyphens.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Volume type.\n\t//   values:\n\t//     - directory\n\t//     - disk\n\t//     - partition\n\t//  schema:\n\t//    type: string\n\tVolumeType *VolumeType `yaml:\"volumeType,omitempty\"`\n\t//   description: |\n\t//     The provisioning describes how the volume is provisioned.\n\tProvisioningSpec ProvisioningSpec `yaml:\"provisioning,omitempty\"`\n\t//   description: |\n\t//     The filesystem describes how the volume is formatted.\n\tFilesystemSpec FilesystemSpec `yaml:\"filesystem,omitempty\"`\n\t//   description: |\n\t//     The encryption describes how the volume is encrypted.\n\tEncryptionSpec EncryptionSpec `yaml:\"encryption,omitempty\"`\n\t//   description: |\n\t//     The mount describes additional mount options.\n\tMountSpec UserMountSpec `yaml:\"mount,omitempty\"`\n}\n\n// UserMountSpec describes how the volume is mounted.\ntype UserMountSpec struct {\n\t//   description: |\n\t//     If true, disable file access time updates.\n\tMountDisableAccessTime *bool `yaml:\"disableAccessTime,omitempty\"`\n\t//   description: |\n\t//     Enable secure mount options (nosuid, nodev).\n\t//\n\t//     Defaults to true for better security.\n\tMountSecure *bool `yaml:\"secure,omitempty\"`\n}\n\n// NewUserVolumeConfigV1Alpha1 creates a new user volume config document.\nfunc NewUserVolumeConfigV1Alpha1() *UserVolumeConfigV1Alpha1 {\n\treturn &UserVolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       UserVolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nconst userVolumeName = \"local-data\"\n\nfunc exampleUserVolumeConfigV1Alpha1Partition() *UserVolumeConfigV1Alpha1 {\n\tcfg := NewUserVolumeConfigV1Alpha1()\n\tcfg.MetaName = userVolumeName\n\tcfg.VolumeType = new(block.VolumeTypePartition)\n\tcfg.ProvisioningSpec = ProvisioningSpec{\n\t\tDiskSelectorSpec: DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t},\n\t\tProvisioningMaxSize: MustSize(\"50GiB\"),\n\t}\n\tcfg.FilesystemSpec = FilesystemSpec{\n\t\tFilesystemType: block.FilesystemTypeXFS,\n\t}\n\tcfg.EncryptionSpec = EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &EncryptionKeyTPM{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot: 1,\n\t\t\t\tKeyStatic: &EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\nfunc exampleUserVolumeConfigV1Alpha1Directory() *UserVolumeConfigV1Alpha1 {\n\tcfg := NewUserVolumeConfigV1Alpha1()\n\tcfg.MetaName = userVolumeName\n\tcfg.VolumeType = new(block.VolumeTypeDirectory)\n\n\treturn cfg\n}\n\nfunc exampleUserVolumeConfigV1Alpha1Disk() *UserVolumeConfigV1Alpha1 {\n\tcfg := NewUserVolumeConfigV1Alpha1()\n\tcfg.MetaName = userVolumeName\n\tcfg.VolumeType = new(block.VolumeTypeDisk)\n\tcfg.ProvisioningSpec = ProvisioningSpec{\n\t\tDiskSelectorSpec: DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t},\n\t}\n\tcfg.FilesystemSpec = FilesystemSpec{\n\t\tFilesystemType: block.FilesystemTypeXFS,\n\t}\n\tcfg.EncryptionSpec = EncryptionSpec{\n\t\tEncryptionProvider: block.EncryptionProviderLUKS2,\n\t\tEncryptionKeys: []EncryptionKey{\n\t\t\t{\n\t\t\t\tKeySlot: 0,\n\t\t\t\tKeyTPM:  &EncryptionKeyTPM{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tKeySlot: 1,\n\t\t\t\tKeyStatic: &EncryptionKeyStatic{\n\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *UserVolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *UserVolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *UserVolumeConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn []string{ExistingVolumeConfigKind}\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo,cyclop\nfunc (s *UserVolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == \"\" {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name is required\"))\n\t}\n\n\tif len(s.MetaName) < 1 || len(s.MetaName) > maxUserVolumeNameLength {\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"name must be between 1 and %d characters long\", maxUserVolumeNameLength))\n\t}\n\n\tif strings.ContainsFunc(s.MetaName, func(r rune) bool {\n\t\tswitch {\n\t\tcase r >= 'a' && r <= 'z':\n\t\t\treturn false\n\t\tcase r >= 'A' && r <= 'Z':\n\t\t\treturn false\n\t\tcase r >= '0' && r <= '9':\n\t\t\treturn false\n\t\tcase r == '-':\n\t\t\treturn false\n\t\tdefault: // invalid symbol\n\t\t\treturn true\n\t\t}\n\t}) {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\"))\n\t}\n\n\tvtype := block.VolumeTypePartition\n\tif s.VolumeType != nil {\n\t\tvtype = *s.VolumeType\n\t}\n\n\tswitch vtype {\n\tcase block.VolumeTypeDirectory:\n\t\tif !s.ProvisioningSpec.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"provisioning spec is invalid for volumeType directory\"))\n\t\t}\n\n\t\tif !s.EncryptionSpec.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"encryption spec is invalid for volumeType directory\"))\n\t\t}\n\n\t\tif !s.FilesystemSpec.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"filesystem spec is invalid for volumeType directory\"))\n\t\t}\n\n\t\tif !s.MountSpec.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"mount spec is invalid for volumeType directory\"))\n\t\t}\n\n\tcase block.VolumeTypeDisk:\n\t\textraWarnings, extraErrors := s.ProvisioningSpec.Validate(true, false)\n\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\t\textraWarnings, extraErrors = s.FilesystemSpec.Validate()\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\t\textraWarnings, extraErrors = s.EncryptionSpec.Validate()\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\tcase block.VolumeTypePartition:\n\t\textraWarnings, extraErrors := s.ProvisioningSpec.Validate(true, true)\n\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\t\textraWarnings, extraErrors = s.FilesystemSpec.Validate()\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\t\textraWarnings, extraErrors = s.EncryptionSpec.Validate()\n\t\twarnings = append(warnings, extraWarnings...)\n\t\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\tcase block.VolumeTypeTmpfs, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal:\n\t\tfallthrough\n\n\tdefault:\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"unsupported volume type %q\", vtype))\n\t}\n\n\treturn warnings, validationErrors\n}\n\n// UserVolumeConfigSignal is a signal for user volume config.\nfunc (s *UserVolumeConfigV1Alpha1) UserVolumeConfigSignal() {}\n\n// Type implements config.UserVolumeConfig interface.\nfunc (s *UserVolumeConfigV1Alpha1) Type() optional.Optional[VolumeType] {\n\tif s.VolumeType == nil {\n\t\treturn optional.None[VolumeType]()\n\t}\n\n\treturn optional.Some(*s.VolumeType)\n}\n\n// Provisioning implements config.UserVolumeConfig interface.\nfunc (s *UserVolumeConfigV1Alpha1) Provisioning() config.VolumeProvisioningConfig {\n\treturn s.ProvisioningSpec\n}\n\n// Filesystem implements config.UserVolumeConfig interface.\nfunc (s *UserVolumeConfigV1Alpha1) Filesystem() config.FilesystemConfig {\n\treturn s.FilesystemSpec\n}\n\n// Encryption implements config.UserVolumeConfig interface.\nfunc (s *UserVolumeConfigV1Alpha1) Encryption() config.EncryptionConfig {\n\tif s.EncryptionSpec.EncryptionProvider == block.EncryptionProviderNone {\n\t\treturn nil\n\t}\n\n\treturn s.EncryptionSpec\n}\n\n// Mount implements config.UserVolumeConfig interface.\nfunc (s *UserVolumeConfigV1Alpha1) Mount() config.UserVolumeMountConfig {\n\treturn s.MountSpec\n}\n\n// FilesystemSpec configures the filesystem for the volume.\ntype FilesystemSpec struct {\n\t//   description: |\n\t//     Filesystem type. Default is `xfs`.\n\t//   values:\n\t//     - ext4\n\t//     - xfs\n\tFilesystemType block.FilesystemType `yaml:\"type,omitempty\"`\n\t//   description: |\n\t//     Enables project quota support, valid only for 'xfs' filesystem.\n\t//\n\t//     Note: changing this value might require a full remount of the filesystem.\n\tProjectQuotaSupportConfig *bool `yaml:\"projectQuotaSupport,omitempty\"`\n}\n\n// IsZero checks if the filesystem spec is zero.\nfunc (s FilesystemSpec) IsZero() bool {\n\treturn s.FilesystemType == block.FilesystemTypeNone && s.ProjectQuotaSupportConfig == nil\n}\n\n// Type implements config.FilesystemConfig interface.\nfunc (s FilesystemSpec) Type() block.FilesystemType {\n\tif s.FilesystemType == block.FilesystemTypeNone {\n\t\treturn block.FilesystemTypeXFS\n\t}\n\n\treturn s.FilesystemType\n}\n\n// ProjectQuotaSupport implements config.FilesysteemConfig interface.\nfunc (s FilesystemSpec) ProjectQuotaSupport() bool {\n\treturn pointer.SafeDeref(s.ProjectQuotaSupportConfig)\n}\n\n// Validate implements config.Validator interface.\nfunc (s FilesystemSpec) Validate() ([]string, error) {\n\tswitch s.FilesystemType { //nolint:exhaustive\n\tcase block.FilesystemTypeNone:\n\tcase block.FilesystemTypeXFS:\n\tcase block.FilesystemTypeEXT4:\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported filesystem type: %s\", s.FilesystemType)\n\t}\n\n\tif pointer.SafeDeref(s.ProjectQuotaSupportConfig) && s.Type() != block.FilesystemTypeXFS {\n\t\treturn nil, fmt.Errorf(\"project quota support is only available for xfs filesystem\")\n\t}\n\n\treturn nil, nil\n}\n\n// IsZero checks if the mount spec is zero.\nfunc (s UserMountSpec) IsZero() bool {\n\treturn s.MountDisableAccessTime == nil && s.MountSecure == nil\n}\n\n// DisableAccessTime implements config.UserVolumeMountConfig interface.\nfunc (s UserMountSpec) DisableAccessTime() bool {\n\treturn pointer.SafeDeref(s.MountDisableAccessTime)\n}\n\n// Secure implements config.UserVolumeMountConfig interface.\nfunc (s UserMountSpec) Secure() bool {\n\tif s.MountSecure == nil {\n\t\treturn true\n\t}\n\n\treturn *s.MountSecure\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/user_volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestUserVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.UserVolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"disk selector\",\n\t\t\tfilename: \"uservolumeconfig_diskselector.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"ceph-data\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == \"nvme\" && !system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"100GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeXFS\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"encrypted\",\n\t\t\tfilename: \"uservolumeconfig_encrypted.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"secret-store\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"prjquota\",\n\t\t\tfilename: \"uservolumeconfig_prjquota.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"secret-store\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`!system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeXFS\n\t\t\t\tc.FilesystemSpec.ProjectQuotaSupportConfig = new(true)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestUserVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.UserVolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"no name\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name is required\\nname must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"too long name\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = strings.Repeat(\"X\", 35)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name must be between 1 and 34 characters long\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid characters in name\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"some/name\"\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 1u`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"name can only contain lowercase and uppercase ASCII letters, digits, and hyphens\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid disk selector\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is invalid: ERROR: <input>:1:11: found no matching overload for '_>_' applied to '(uint, int)'\\n | disk.size > 120\\n | ..........^\\nmin size or max size is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"min size greater than max size\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is required\\nmin size is greater than max size\",\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported filesystem type\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeISO9660\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"unsupported filesystem type: iso9660\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption provider\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"unsupported encryption provider: none\",\n\t\t},\n\t\t{\n\t\t\tname: \"no encryption keys\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"encryption keys are required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid encryption key slots\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"at least one encryption key type must be specified for slot 0\\nduplicate key slot 1\",\n\t\t},\n\t\t{\n\t\t\tname: \"prjquota not supported\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4\n\t\t\t\tc.FilesystemSpec.ProjectQuotaSupportConfig = new(true)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"project quota support is only available for xfs filesystem\",\n\t\t},\n\t\t{\n\t\t\tname: \"provisioning spec for directory\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDirectory)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"provisioning spec is invalid for volumeType directory\",\n\t\t},\n\t\t{\n\t\t\tname: \"encryption spec for directory\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDirectory)\n\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"encryption spec is invalid for volumeType directory\",\n\t\t},\n\t\t{\n\t\t\tname: \"size for disk\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDisk)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"min size, max size and grow are not supported\",\n\t\t},\n\t\t{\n\t\t\tname: \"filesystem spec for directory\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDirectory)\n\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeVFAT\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"filesystem spec is invalid for volumeType directory\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid volumeType\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeTmpfs)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"unsupported volume type \\\"tmpfs\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid partition\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypePartition)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid directory\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDirectory)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid disk\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\t\t\t\tc.VolumeType = new(blockres.VolumeTypeDisk)\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.FilesystemSpec.FilesystemType = blockres.FilesystemTypeEXT4\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid encrypted\",\n\n\t\t\tcfg: func(t *testing.T) *block.UserVolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewUserVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`system_disk`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionCipher = \"aes-xts-plain64\"\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// VolumeConfigKind is a config document kind.\nconst VolumeConfigKind = \"VolumeConfig\"\n\nfunc init() {\n\tregistry.Register(VolumeConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &VolumeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.VolumeConfig                 = &VolumeConfigV1Alpha1{}\n\t_ config.NamedDocument                = &VolumeConfigV1Alpha1{}\n\t_ config.Validator                    = &VolumeConfigV1Alpha1{}\n\t_ container.V1Alpha1ConflictValidator = &VolumeConfigV1Alpha1{}\n)\n\n// VolumeConfigV1Alpha1 is a system volume configuration document.\n//\n//\tdescription: |\n//\t  Note: at the moment, only `STATE`, `EPHEMERAL` and `IMAGE-CACHE` system volumes are supported.\n//\texamples:\n//\t  - value: exampleVolumeConfigEphemeralV1Alpha1()\n//\talias: VolumeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/VolumeConfig\ntype VolumeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the volume.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The provisioning describes how the volume is provisioned.\n\tProvisioningSpec ProvisioningSpec `yaml:\"provisioning,omitempty\"`\n\t//   description: |\n\t//     The encryption describes how the volume is encrypted.\n\tEncryptionSpec EncryptionSpec `yaml:\"encryption,omitempty\"`\n\t//   description: |\n\t//     The mount describes additional mount options.\n\tMountSpec MountSpec `yaml:\"mount,omitempty\"`\n}\n\n// MountSpec describes how the volume is mounted.\ntype MountSpec struct {\n\t//   description: |\n\t//     Enable secure mount options (nosuid, nodev).\n\t//\n\t//     Defaults to true for better security.\n\tMountSecure *bool `yaml:\"secure,omitempty\"`\n}\n\n// ProvisioningSpec describes how the volume is provisioned.\ntype ProvisioningSpec struct {\n\t//   description: |\n\t//     The disk selector expression.\n\tDiskSelectorSpec DiskSelector `yaml:\"diskSelector,omitempty\"`\n\t//   description: |\n\t//    Should the volume grow to the size of the disk (if possible).\n\tProvisioningGrow *bool `yaml:\"grow,omitempty\"`\n\t//  description: |\n\t//    The minimum size of the volume.\n\t//\n\t//    Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\n\t//  examples:\n\t//    - value: >\n\t//        \"2.5GiB\"\n\t//  schema:\n\t//    type: string\n\tProvisioningMinSize ByteSize `yaml:\"minSize,omitempty\"`\n\t//  description: |\n\t//    The maximum size of the volume, if not specified the volume can grow to the size of the\n\t//    disk.\n\t//\n\t//    Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\n\t//  examples:\n\t//    - value: >\n\t//        \"50GiB\"\n\t//    - value: >\n\t//        \"80%\"\n\t//  schema:\n\t//    type: string\n\tProvisioningMaxSize Size `yaml:\"maxSize,omitempty\"`\n}\n\n// MaxSizeNegative returns true if the maximum size is negative.\nfunc (p ProvisioningSpec) MaxSizeNegative() bool {\n\treturn p.ProvisioningMaxSize.IsNegative()\n}\n\n// DiskSelector selects a disk for the volume.\ntype DiskSelector struct {\n\t//   description: |\n\t//     The Common Expression Language (CEL) expression to match the disk.\n\t//   schema:\n\t//     type: string\n\t//   examples:\n\t//    - value: >\n\t//        exampleDiskSelector1()\n\t//      name: match disks with size between 120GB and 1TB\n\t//    - value: >\n\t//        exampleDiskSelector2()\n\t//      name: match SATA disks that are not rotational and not system disks\n\tMatch cel.Expression `yaml:\"match,omitempty\"`\n}\n\n// NewVolumeConfigV1Alpha1 creates a new volume config document.\nfunc NewVolumeConfigV1Alpha1() *VolumeConfigV1Alpha1 {\n\treturn &VolumeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       VolumeConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleVolumeConfigEphemeralV1Alpha1() *VolumeConfigV1Alpha1 {\n\tcfg := NewVolumeConfigV1Alpha1()\n\tcfg.MetaName = constants.EphemeralPartitionLabel\n\tcfg.ProvisioningSpec = ProvisioningSpec{\n\t\tDiskSelectorSpec: DiskSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"nvme\"`, celenv.DiskLocator())),\n\t\t},\n\t\tProvisioningMaxSize: MustSize(\"50GiB\"),\n\t}\n\n\treturn cfg\n}\n\nfunc exampleDiskSelector1() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`disk.size > 120u * GB && disk.size < 1u * TB`, celenv.DiskLocator()))\n}\n\nfunc exampleDiskSelector2() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`disk.transport == \"sata\" && !disk.rotational && !system_disk`, celenv.DiskLocator()))\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *VolumeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *VolumeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (s *VolumeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tallowedVolumes := []string{\n\t\tconstants.StatePartitionLabel,\n\t\tconstants.EphemeralPartitionLabel,\n\t\tconstants.ImageCachePartitionLabel,\n\t}\n\n\tif slices.Index(allowedVolumes, s.MetaName) == -1 {\n\t\treturn nil, fmt.Errorf(\"only %q volumes are supported\", allowedVolumes)\n\t}\n\n\tvar (\n\t\twarnings         []string //nolint:prealloc\n\t\tvalidationErrors error\n\t)\n\n\tif s.MetaName == constants.StatePartitionLabel {\n\t\t// no provisioning config is allowed for the state partition.\n\t\tif !s.ProvisioningSpec.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"provisioning config is not allowed for the %q volume\", s.MetaName))\n\t\t}\n\n\t\tfor _, key := range s.EncryptionSpec.EncryptionKeys {\n\t\t\tif pointer.SafeDeref(key.KeyLockToSTATE) {\n\t\t\t\t// state-locked keys are not allowed\n\t\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"state-locked key is not allowed for the %q volume\", s.MetaName))\n\t\t\t}\n\t\t}\n\t}\n\n\textraWarnings, extraErrors := s.ProvisioningSpec.Validate(false, true)\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\textraWarnings, extraErrors = s.EncryptionSpec.Validate()\n\twarnings = append(warnings, extraWarnings...)\n\tvalidationErrors = errors.Join(validationErrors, extraErrors)\n\n\treturn warnings, validationErrors\n}\n\n// Provisioning implements config.VolumeConfig interface.\nfunc (s *VolumeConfigV1Alpha1) Provisioning() config.VolumeProvisioningConfig {\n\treturn s.ProvisioningSpec\n}\n\n// Encryption implements config.VolumeConfig interface.\nfunc (s *VolumeConfigV1Alpha1) Encryption() config.EncryptionConfig {\n\tif s.EncryptionSpec.EncryptionProvider == block.EncryptionProviderNone {\n\t\treturn nil\n\t}\n\n\treturn s.EncryptionSpec\n}\n\n// Mount implements config.VolumeConfig interface.\nfunc (s *VolumeConfigV1Alpha1) Mount() config.VolumeMountConfig {\n\treturn s.MountSpec\n}\n\n// Validate the provisioning spec.\n//\n//nolint:gocyclo\nfunc (p ProvisioningSpec) Validate(required bool, sizeSupported bool) ([]string, error) {\n\tvar validationErrors error\n\n\tif !p.DiskSelectorSpec.Match.IsZero() {\n\t\tif err := p.DiskSelectorSpec.Match.ParseBool(celenv.DiskLocator()); err != nil {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"disk selector is invalid: %w\", err))\n\t\t}\n\t} else if required {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"disk selector is required\"))\n\t}\n\n\tif sizeSupported {\n\t\tif !p.ProvisioningMinSize.IsZero() && !p.ProvisioningMaxSize.IsZero() && !p.ProvisioningMaxSize.IsRelative() && !p.ProvisioningMaxSize.IsNegative() {\n\t\t\tif p.ProvisioningMinSize.Value() > p.ProvisioningMaxSize.Value() {\n\t\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"min size is greater than max size\"))\n\t\t\t}\n\t\t} else if required && p.ProvisioningMinSize.IsZero() && p.ProvisioningMaxSize.IsZero() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"min size or max size is required\"))\n\t\t}\n\n\t\tif p.ProvisioningMinSize.IsNegative() {\n\t\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"min size cannot be negative\"))\n\t\t}\n\t} else if !p.ProvisioningMinSize.IsZero() || !p.ProvisioningMaxSize.IsZero() || p.Grow().IsPresent() {\n\t\tvalidationErrors = errors.Join(validationErrors, errors.New(\"min size, max size and grow are not supported\"))\n\t}\n\n\treturn nil, validationErrors\n}\n\n// V1Alpha1ConflictValidate implements container.V1Alpha1ConflictValidator interface.\nfunc (s *VolumeConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Config *v1alpha1.Config) error {\n\tif !slices.Contains([]string{constants.StatePartitionLabel, constants.EphemeralPartitionLabel}, s.MetaName) {\n\t\t// only STATE and EPHEMERAL volumes can conflict with legacy config.\n\t\treturn nil\n\t}\n\n\tif s.Encryption() == nil {\n\t\t// no encryption configured, no conflict.\n\t\treturn nil\n\t}\n\n\tlegacy := v1alpha1Config.Machine().SystemDiskEncryption().Get(s.MetaName)\n\tif legacy != nil {\n\t\treturn fmt.Errorf(\"system disk encryption for %q is configured in both v1alpha1.Config and VolumeConfig\", s.MetaName)\n\t}\n\n\treturn nil\n}\n\n// IsZero checks if the provisioning spec is zero.\nfunc (p ProvisioningSpec) IsZero() bool {\n\treturn p.ProvisioningGrow == nil && p.ProvisioningMaxSize.IsZero() && p.ProvisioningMinSize.IsZero() && p.DiskSelectorSpec.Match.IsZero()\n}\n\n// DiskSelector implements config.VolumeProvisioningConfig interface.\nfunc (p ProvisioningSpec) DiskSelector() optional.Optional[cel.Expression] {\n\tif p.DiskSelectorSpec.Match.IsZero() {\n\t\treturn optional.None[cel.Expression]()\n\t}\n\n\treturn optional.Some(p.DiskSelectorSpec.Match)\n}\n\n// Grow implements config.VolumeProvisioningConfig interface.\nfunc (p ProvisioningSpec) Grow() optional.Optional[bool] {\n\tif p.ProvisioningGrow == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*p.ProvisioningGrow)\n}\n\n// MinSize implements config.VolumeProvisioningConfig interface.\nfunc (p ProvisioningSpec) MinSize() optional.Optional[uint64] {\n\tif p.ProvisioningMinSize.IsZero() {\n\t\treturn optional.None[uint64]()\n\t}\n\n\treturn optional.Some(p.ProvisioningMinSize.Value())\n}\n\n// MaxSize implements config.VolumeProvisioningConfig interface.\nfunc (p ProvisioningSpec) MaxSize() optional.Optional[uint64] {\n\tif p.ProvisioningMaxSize.IsZero() {\n\t\treturn optional.None[uint64]()\n\t}\n\n\treturn optional.Some(p.ProvisioningMaxSize.Value())\n}\n\n// RelativeMaxSize implements config.VolumeProvisioningConfig interface.\nfunc (p ProvisioningSpec) RelativeMaxSize() optional.Optional[uint64] {\n\tif p.ProvisioningMaxSize.IsZero() {\n\t\treturn optional.None[uint64]()\n\t}\n\n\tval, ok := p.ProvisioningMaxSize.RelativeValue()\n\tif !ok {\n\t\treturn optional.None[uint64]()\n\t}\n\n\treturn optional.Some(val)\n}\n\n// Secure implements config.VolumeMountConfig interface.\nfunc (s MountSpec) Secure() bool {\n\tif s.MountSecure == nil {\n\t\treturn true\n\t}\n\n\treturn *s.MountSecure\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\tblockres \"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestVolumeConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.VolumeConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\tfilename: \"volumeconfig_empty.yaml\",\n\t\t\tcfg: func(*testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"disk selector\",\n\t\t\tfilename: \"volumeconfig_diskselector.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.transport == \"nvme\" && !system_disk`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"max size\",\n\t\t\tfilename: \"volumeconfig_maxsize.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"negative max size\",\n\t\t\tfilename: \"volumeconfig_negativemaxsize.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"-10GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"state\",\n\t\t\tfilename: \"volumeconfig_state.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.StatePartitionLabel\n\n\t\t\t\tc.EncryptionSpec.EncryptionProvider = blockres.EncryptionProviderLUKS2\n\t\t\t\tc.EncryptionSpec.EncryptionKeys = []block.EncryptionKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\tKeyTPM:  &block.EncryptionKeyTPM{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Empty(t, warnings)\n\t\t})\n\t}\n}\n\nfunc TestVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.VolumeConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"wrong name\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = \"wrong\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"only [\\\"STATE\\\" \\\"EPHEMERAL\\\" \\\"IMAGECACHE\\\"] volumes are supported\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid disk selector\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"disk selector is invalid: ERROR: <input>:1:11: found no matching overload for '_>_' applied to '(uint, int)'\\n | disk.size > 120\\n | ..........^\",\n\t\t},\n\t\t{\n\t\t\tname: \"min size greater than max size\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"min size is greater than max size\",\n\t\t},\n\t\t{\n\t\t\tname: \"min size negative\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"-10GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"min size cannot be negative\",\n\t\t},\n\t\t{\n\t\t\tname: \"state provisioning config\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.StatePartitionLabel\n\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"2.5GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"provisioning config is not allowed for the \\\"STATE\\\" volume\",\n\t\t},\n\t\t{\n\t\t\tname: \"state encryption lock to state\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.StatePartitionLabel\n\n\t\t\t\tc.EncryptionSpec = block.EncryptionSpec{\n\t\t\t\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\t\t\t\tEncryptionKeys: []block.EncryptionKey{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\t\tKeyData: \"topsecret\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot: 1,\n\t\t\t\t\t\t\tKeyStatic: &block.EncryptionKeyStatic{\n\t\t\t\t\t\t\t\tKeyData: \"topsecret2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tKeyLockToSTATE: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"state-locked key is not allowed for the \\\"STATE\\\" volume\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid pcrs\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.StatePartitionLabel\n\n\t\t\t\tc.EncryptionSpec = block.EncryptionSpec{\n\t\t\t\t\tEncryptionProvider: blockres.EncryptionProviderLUKS2,\n\t\t\t\t\tEncryptionKeys: []block.EncryptionKey{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tKeySlot: 0,\n\t\t\t\t\t\t\tKeyTPM: &block.EncryptionKeyTPM{\n\t\t\t\t\t\t\t\tTPMOptions: &block.EncryptionKeyTPMOptions{\n\t\t\t\t\t\t\t\t\tPCRs: []int{24, 25},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"TPM PCR 24 is out of range (0-23)\\nTPM PCR 25 is out of range (0-23)\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"2.5TiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid negative\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"-2GiB\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid percentage\",\n\n\t\t\tcfg: func(t *testing.T) *block.VolumeConfigV1Alpha1 {\n\t\t\t\tc := block.NewVolumeConfigV1Alpha1()\n\t\t\t\tc.MetaName = constants.EphemeralPartitionLabel\n\n\t\t\t\trequire.NoError(t, c.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120u * GiB`)))\n\t\t\t\tc.ProvisioningSpec.ProvisioningMaxSize = block.MustSize(\"90%\")\n\t\t\t\tc.ProvisioningSpec.ProvisioningMinSize = block.MustByteSize(\"10GiB\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVolumeConfigTPMPCRsDefaults(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename     string\n\t\texpectedPCRs []int\n\t}{\n\t\t{\n\t\t\tname:     \"tpm encryption no options\",\n\t\t\tfilename: \"volumeconfig_tpm_encryption_no_options.yaml\",\n\n\t\t\texpectedPCRs: []int{7},\n\t\t},\n\t\t{\n\t\t\tname:     \"tpm encryption with pcr settings\",\n\t\t\tfilename: \"volumeconfig_tpm_encryption_with_pcr_settings.yaml\",\n\n\t\t\texpectedPCRs: []int{0, 7},\n\t\t},\n\t\t{\n\t\t\tname:     \"tpm encryption with pcrs disabled\",\n\t\t\tfilename: \"volumeconfig_tpm_encryption_with_pcrs_disabled.yaml\",\n\n\t\t\texpectedPCRs: []int{},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tprovider, err := configloader.NewFromBytes(marshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tcfg, ok := docs[0].(*block.VolumeConfigV1Alpha1)\n\t\t\trequire.True(t, ok)\n\n\t\t\tassert.Equal(t, test.expectedPCRs, cfg.Encryption().Keys()[0].TPM().PCRs())\n\t\t\tassert.Equal(t, []int{constants.UKIPCR}, cfg.Encryption().Keys()[0].TPM().PubKeyPCRs())\n\t\t})\n\t}\n}\n\nfunc TestVolumeConfigMerge(t *testing.T) {\n\tc1 := block.NewVolumeConfigV1Alpha1()\n\tc1.MetaName = constants.EphemeralPartitionLabel\n\n\trequire.NoError(t, c1.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\tc2 := block.NewVolumeConfigV1Alpha1()\n\tc2.MetaName = constants.EphemeralPartitionLabel\n\n\trequire.NoError(t, c2.ProvisioningSpec.DiskSelectorSpec.Match.UnmarshalText([]byte(`disk.size > 150`)))\n\trequire.NoError(t, c2.ProvisioningSpec.ProvisioningMaxSize.UnmarshalText([]byte(\"2.5TiB\")))\n\n\trequire.NoError(t, merge.Merge(c1, c2))\n\n\tassert.Equal(t, c1.ProvisioningSpec.DiskSelectorSpec.Match, c2.ProvisioningSpec.DiskSelectorSpec.Match)\n\tassert.Equal(t, c1.ProvisioningSpec.ProvisioningMaxSize, c2.ProvisioningSpec.ProvisioningMaxSize)\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/zswap_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// ZswapConfigKind is a config document kind.\nconst ZswapConfigKind = \"ZswapConfig\"\n\nfunc init() {\n\tregistry.Register(ZswapConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &ZswapConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.ZswapConfig = &ZswapConfigV1Alpha1{}\n\t_ config.Validator   = &ZswapConfigV1Alpha1{}\n)\n\n// ZswapConfigV1Alpha1 is a zswap (compressed memory) configuration document.\n//\n//\tdescription: |\n//\t  When zswap is enabled, Linux kernel compresses pages that would otherwise be swapped out to disk.\n//\t  The compressed pages are stored in a memory pool, which is used to avoid writing to disk\n//\t  when the system is under memory pressure.\n//\texamples:\n//\t  - value: exampleZswapConfigV1Alpha1()\n//\talias: ZswapConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ZswapConfig\ntype ZswapConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     The maximum percent of memory that zswap can use.\n\t//     This is a percentage of the total system memory.\n\t//     The value must be between 0 and 100.\n\tMaxPoolPercentConfig *int `yaml:\"maxPoolPercent,omitempty\"`\n\t//   description: |\n\t//    Enable the shrinker feature: kernel might move\n\t//    cold pages from zswap to swap device to free up memory\n\t//    for other use cases.\n\tShrinkerEnabledConfig *bool `yaml:\"shrinkerEnabled,omitempty\"`\n}\n\n// NewZswapConfigV1Alpha1 creates a new zswap config document.\nfunc NewZswapConfigV1Alpha1() *ZswapConfigV1Alpha1 {\n\treturn &ZswapConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ZswapConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleZswapConfigV1Alpha1() *ZswapConfigV1Alpha1 {\n\tcfg := NewZswapConfigV1Alpha1()\n\tcfg.MaxPoolPercentConfig = new(25)\n\tcfg.ShrinkerEnabledConfig = new(true)\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *ZswapConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s *ZswapConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings         []string\n\t\tvalidationErrors error\n\t)\n\n\tif s.MaxPoolPercentConfig != nil {\n\t\tif *s.MaxPoolPercentConfig < 0 || *s.MaxPoolPercentConfig > 100 {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"maxPoolPercent must be between 0 and 100\"))\n\t\t}\n\t}\n\n\treturn warnings, validationErrors\n}\n\n// ZswapConfigSignal is a signal for zswap config.\nfunc (s *ZswapConfigV1Alpha1) ZswapConfigSignal() {}\n\n// MaxPoolPercent implements config.ZswapConfig interface.\nfunc (s *ZswapConfigV1Alpha1) MaxPoolPercent() int {\n\tif s.MaxPoolPercentConfig == nil {\n\t\treturn 20\n\t}\n\n\treturn pointer.SafeDeref(s.MaxPoolPercentConfig)\n}\n\n// ShrinkerEnabled implements config.ZswapConfig interface.\nfunc (s *ZswapConfigV1Alpha1) ShrinkerEnabled() bool {\n\tif s.ShrinkerEnabledConfig == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(s.ShrinkerEnabledConfig)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/block/zswap_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl,goconst\npackage block_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block\"\n)\n\nfunc TestZswapConfigMarshalUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tfilename string\n\t\tcfg      func(t *testing.T) *block.ZswapConfigV1Alpha1\n\t}{\n\t\t{\n\t\t\tname:     \"full config\",\n\t\t\tfilename: \"zswapconfig_full.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.ZswapConfigV1Alpha1 {\n\t\t\t\tc := block.NewZswapConfigV1Alpha1()\n\t\t\t\tc.MaxPoolPercentConfig = new(50)\n\t\t\t\tc.ShrinkerEnabledConfig = new(true)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"min config\",\n\t\t\tfilename: \"zswapconfig_min.yaml\",\n\t\t\tcfg: func(t *testing.T) *block.ZswapConfigV1Alpha1 {\n\t\t\t\tc := block.NewZswapConfigV1Alpha1()\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, warnings)\n\n\t\t\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Log(string(marshaled))\n\n\t\t\texpectedMarshaled, err := os.ReadFile(filepath.Join(\"testdata\", test.filename))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, string(expectedMarshaled), string(marshaled))\n\n\t\t\tprovider, err := configloader.NewFromBytes(expectedMarshaled)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdocs := provider.Documents()\n\t\t\trequire.Len(t, docs, 1)\n\n\t\t\tassert.Equal(t, cfg, docs[0])\n\t\t})\n\t}\n}\n\nfunc TestZswapVolumeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(t *testing.T) *block.ZswapConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"minimal\",\n\n\t\t\tcfg: func(t *testing.T) *block.ZswapConfigV1Alpha1 {\n\t\t\t\tc := block.NewZswapConfigV1Alpha1()\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"full\",\n\n\t\t\tcfg: func(t *testing.T) *block.ZswapConfigV1Alpha1 {\n\t\t\t\tc := block.NewZswapConfigV1Alpha1()\n\t\t\t\tc.MaxPoolPercentConfig = new(50)\n\t\t\t\tc.ShrinkerEnabledConfig = new(true)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid percent\",\n\n\t\t\tcfg: func(t *testing.T) *block.ZswapConfigV1Alpha1 {\n\t\t\t\tc := block.NewZswapConfigV1Alpha1()\n\t\t\t\tc.MaxPoolPercentConfig = new(150)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"maxPoolPercent must be between 0 and 100\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\t_, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cri provides container runtime interface related config documents.\npackage cri\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output cri_doc.go registry_auth.go registry_mirror.go registry_tls.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type RegistryAuthConfigV1Alpha1 -type RegistryMirrorConfigV1Alpha1 -type RegistryTLSConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/cri_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage cri\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (RegistryAuthConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryAuthConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryAuthConfig configures authentication for a registry endpoint.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryAuthConfig configures authentication for a registry endpoint.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Registry endpoint to apply the authentication configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Registry endpoint to apply the authentication configuration to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"username\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Username/password authentication.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Username/password authentication.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"password\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Username/password authentication.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Username/password authentication.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"auth\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Raw authentication string.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Raw authentication string.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"identityToken\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Identity token authentication.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Identity token authentication.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRegistryAuthConfigVAlpha1())\n\n\treturn doc\n}\n\nfunc (RegistryMirrorConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryMirrorConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryMirrorConfig configures an image registry mirror.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryMirrorConfig configures an image registry mirror.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Registry name to apply the mirror configuration to.\\n\\nRegistry name is the first segment of image identifier, with 'docker.io'\\nbeing default one.\\n\\nA special name '*' can be used to define mirror configuration\\nthat applies to all registries.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Registry name to apply the mirror configuration to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"endpoints\",\n\t\t\t\tType:        \"[]RegistryEndpoint\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is `skipFallback` is not set to true.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of mirror endpoints for the registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"skipFallback\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Skip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Skip fallback to the original registry if none of the mirrors are available\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRegistryMirrorConfigVAlpha1())\n\n\treturn doc\n}\n\nfunc (RegistryEndpoint) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryEndpoint\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryEndpoint defines a registry mirror endpoint.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryEndpoint defines a registry mirror endpoint.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"RegistryMirrorConfigV1Alpha1\",\n\t\t\t\tFieldName: \"endpoints\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"url\",\n\t\t\t\tType:        \"URL\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The URL of the registry mirror endpoint.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The URL of the registry mirror endpoint.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"overridePath\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Use endpoint path as supplied, without adding `/v2/` suffix.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Use endpoint path as supplied, without adding `/v2/` suffix.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", \"https://my-registry-mirror.local:5000\")\n\n\treturn doc\n}\n\nfunc (RegistryTLSConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryTLSConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryTLSConfig configures TLS for a registry endpoint.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryTLSConfig configures TLS for a registry endpoint.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Registry endpoint to apply the TLS configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Registry endpoint to apply the TLS configuration to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"clientIdentity\",\n\t\t\t\tType:        \"CertificateAndKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable mutual TLS authentication with the registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ca\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CA registry certificate to add the list of trusted certificates.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"insecureSkipVerify\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Skip TLS server certificate verification (not recommended).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Skip TLS server certificate verification (not recommended).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRegistryTLSConfigVAlpha1())\n\n\tdoc.Fields[2].AddExample(\"\", exampleCertificateAndKey())\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file cri_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"cri\",\n\t\tDescription: \"\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tRegistryAuthConfigV1Alpha1{}.Doc(),\n\t\t\tRegistryMirrorConfigV1Alpha1{}.Doc(),\n\t\t\tRegistryEndpoint{}.Doc(),\n\t\t\tRegistryTLSConfigV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type RegistryAuthConfigV1Alpha1 -type RegistryMirrorConfigV1Alpha1 -type RegistryTLSConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage cri\n\nimport (\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n// DeepCopy generates a deep copy of *RegistryAuthConfigV1Alpha1.\nfunc (o *RegistryAuthConfigV1Alpha1) DeepCopy() *RegistryAuthConfigV1Alpha1 {\n\tvar cp RegistryAuthConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *RegistryMirrorConfigV1Alpha1.\nfunc (o *RegistryMirrorConfigV1Alpha1) DeepCopy() *RegistryMirrorConfigV1Alpha1 {\n\tvar cp RegistryMirrorConfigV1Alpha1 = *o\n\tif o.RegistryEndpoints != nil {\n\t\tcp.RegistryEndpoints = make([]RegistryEndpoint, len(o.RegistryEndpoints))\n\t\tcopy(cp.RegistryEndpoints, o.RegistryEndpoints)\n\t\tfor i2 := range o.RegistryEndpoints {\n\t\t\tif o.RegistryEndpoints[i2].EndpointURL.URL != nil {\n\t\t\t\tcp.RegistryEndpoints[i2].EndpointURL.URL = new(url.URL)\n\t\t\t\t*cp.RegistryEndpoints[i2].EndpointURL.URL = *o.RegistryEndpoints[i2].EndpointURL.URL\n\t\t\t\tif o.RegistryEndpoints[i2].EndpointURL.URL.User != nil {\n\t\t\t\t\tcp.RegistryEndpoints[i2].EndpointURL.URL.User = new(url.Userinfo)\n\t\t\t\t\t*cp.RegistryEndpoints[i2].EndpointURL.URL.User = *o.RegistryEndpoints[i2].EndpointURL.URL.User\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.RegistryEndpoints[i2].EndpointOverridePath != nil {\n\t\t\t\tcp.RegistryEndpoints[i2].EndpointOverridePath = new(bool)\n\t\t\t\t*cp.RegistryEndpoints[i2].EndpointOverridePath = *o.RegistryEndpoints[i2].EndpointOverridePath\n\t\t\t}\n\t\t}\n\t}\n\tif o.RegistrySkipFallback != nil {\n\t\tcp.RegistrySkipFallback = new(bool)\n\t\t*cp.RegistrySkipFallback = *o.RegistrySkipFallback\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *RegistryTLSConfigV1Alpha1.\nfunc (o *RegistryTLSConfigV1Alpha1) DeepCopy() *RegistryTLSConfigV1Alpha1 {\n\tvar cp RegistryTLSConfigV1Alpha1 = *o\n\tif o.TLSClientIdentity != nil {\n\t\tcp.TLSClientIdentity = new(meta.CertificateAndKey)\n\t\t*cp.TLSClientIdentity = *o.TLSClientIdentity\n\t}\n\tif o.TLSInsecureSkipVerify != nil {\n\t\tcp.TLSInsecureSkipVerify = new(bool)\n\t\t*cp.TLSInsecureSkipVerify = *o.TLSInsecureSkipVerify\n\t}\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_auth.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n//docgen:jsonschema\n\n// RegistryAuthConfig defines the RegistryAuthConfig configuration name.\nconst RegistryAuthConfig = \"RegistryAuthConfig\"\n\nfunc init() {\n\tregistry.Register(RegistryAuthConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RegistryAuthConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RegistryAuthConfigDocument = &RegistryAuthConfigV1Alpha1{}\n\t_ config.Validator                  = &RegistryAuthConfigV1Alpha1{}\n\t_ config.SecretDocument             = &RegistryAuthConfigV1Alpha1{}\n\t_ config.NamedDocument              = &RegistryAuthConfigV1Alpha1{}\n)\n\n// RegistryAuthConfigV1Alpha1 configures authentication for a registry endpoint.\n//\n//\texamples:\n//\t  - value: exampleRegistryAuthConfigVAlpha1()\n//\talias: RegistryAuthConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/RegistryAuthConfig\ntype RegistryAuthConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Registry endpoint to apply the authentication configuration to.\n\t//\n\t//     Registry endpoint is the hostname part of the endpoint URL,\n\t//     e.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\n\t//\n\t//     The authentication configuration will apply to all image pulls for this\n\t//     registry endpoint, by Talos or any Kubernetes workloads.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Username/password authentication.\n\tRegistryUsername string `yaml:\"username,omitempty\"`\n\t//   description: |\n\t//     Username/password authentication.\n\tRegistryPassword string `yaml:\"password,omitempty\"`\n\t//   description: |\n\t//     Raw authentication string.\n\tRegistryAuth string `yaml:\"auth,omitempty\"`\n\t//   description: |\n\t//     Identity token authentication.\n\tRegistryIdentityToken string `yaml:\"identityToken,omitempty\"`\n}\n\n// NewRegistryAuthConfigV1Alpha1 creates a new RegistryAuthConfig config document.\nfunc NewRegistryAuthConfigV1Alpha1(name string) *RegistryAuthConfigV1Alpha1 {\n\treturn &RegistryAuthConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RegistryAuthConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleRegistryAuthConfigVAlpha1() *RegistryAuthConfigV1Alpha1 {\n\tcfg := NewRegistryAuthConfigV1Alpha1(\"my-private-registry.local:5000\")\n\tcfg.RegistryUsername = \"my-username\"\n\tcfg.RegistryPassword = \"my-password\"\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.Document interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\thasUsername := s.RegistryUsername != \"\"\n\thasIdentityToken := s.RegistryIdentityToken != \"\"\n\thasAuth := s.RegistryAuth != \"\"\n\n\tif hasUsername && hasIdentityToken {\n\t\terrs = errors.Join(errs, errors.New(\"only one of username/password or identityToken authentication can be specified\"))\n\t}\n\n\tif hasAuth && (hasUsername || hasIdentityToken) {\n\t\terrs = errors.Join(errs, errors.New(\"only one of auth, username/password or identityToken authentication can be specified\"))\n\t}\n\n\treturn warnings, errs\n}\n\n// Username implements config.RegistryAuthConfig interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Username() string {\n\treturn s.RegistryUsername\n}\n\n// Password implements config.RegistryAuthConfig interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Password() string {\n\treturn s.RegistryPassword\n}\n\n// Auth implements config.RegistryAuthConfig interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Auth() string {\n\treturn s.RegistryAuth\n}\n\n// IdentityToken implements config.RegistryAuthConfig interface.\nfunc (s *RegistryAuthConfigV1Alpha1) IdentityToken() string {\n\treturn s.RegistryIdentityToken\n}\n\n// Redact implements config.SecretDocument interface.\nfunc (s *RegistryAuthConfigV1Alpha1) Redact(replacement string) {\n\tif s.RegistryPassword != \"\" {\n\t\ts.RegistryPassword = replacement\n\t}\n\n\tif s.RegistryAuth != \"\" {\n\t\ts.RegistryAuth = replacement\n\t}\n\n\tif s.RegistryIdentityToken != \"\" {\n\t\ts.RegistryIdentityToken = replacement\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_auth_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n//go:embed testdata/registryauthconfig.yaml\nvar expectedRegistryAuthConfigDocument []byte\n\nfunc TestRegistryAuthConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := cri.NewRegistryAuthConfigV1Alpha1(\"my-private-registry.io\")\n\tcfg.RegistryUsername = \"agent007\"\n\tcfg.RegistryPassword = \"topsecret\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedRegistryAuthConfigDocument, marshaled)\n}\n\nfunc TestRegistryAuthConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedRegistryAuthConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &cri.RegistryAuthConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       cri.RegistryAuthConfig,\n\t\t},\n\t\tMetaName:         \"my-private-registry.io\",\n\t\tRegistryUsername: \"agent007\",\n\t\tRegistryPassword: \"topsecret\",\n\t}, docs[0])\n}\n\nfunc TestRegistryAuthConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *cri.RegistryAuthConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *cri.RegistryAuthConfigV1Alpha1 {\n\t\t\t\treturn cri.NewRegistryAuthConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"username and identity token\",\n\t\t\tcfg: func() *cri.RegistryAuthConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryAuthConfigV1Alpha1(\"k8s.io\")\n\t\t\t\tcfg.RegistryUsername = \"user\"\n\t\t\t\tcfg.RegistryIdentityToken = \"token\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"only one of username/password or identityToken authentication can be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *cri.RegistryAuthConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryAuthConfigV1Alpha1(\"k8s.io\")\n\t\t\t\tcfg.RegistryUsername = \"user\"\n\t\t\t\tcfg.RegistryPassword = \"pass\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_mirror.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n//docgen:jsonschema\n\n// RegistryMirrorConfig defines the RegistryMirrorConfig configuration name.\nconst RegistryMirrorConfig = \"RegistryMirrorConfig\"\n\nfunc init() {\n\tregistry.Register(RegistryMirrorConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RegistryMirrorConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RegistryMirrorConfigDocument = &RegistryMirrorConfigV1Alpha1{}\n\t_ config.Validator                    = &RegistryMirrorConfigV1Alpha1{}\n\t_ config.NamedDocument                = &RegistryMirrorConfigV1Alpha1{}\n)\n\n// RegistryMirrorConfigV1Alpha1 configures an image registry mirror.\n//\n//\texamples:\n//\t  - value: exampleRegistryMirrorConfigVAlpha1()\n//\talias: RegistryMirrorConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/RegistryMirrorConfig\ntype RegistryMirrorConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Registry name to apply the mirror configuration to.\n\t//\n\t//     Registry name is the first segment of image identifier, with 'docker.io'\n\t//     being default one.\n\t//\n\t//     A special name '*' can be used to define mirror configuration\n\t//     that applies to all registries.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     List of mirror endpoints for the registry.\n\t//     Mirrors will be used in the order they are specified,\n\t//     falling back to the default registry is `skipFallback` is not set to true.\n\tRegistryEndpoints []RegistryEndpoint `yaml:\"endpoints,omitempty\"`\n\t//   description: |\n\t//     Skip fallback to the original registry if none of the mirrors are available\n\t//     or contain the requested image.\n\tRegistrySkipFallback *bool `yaml:\"skipFallback,omitempty\"`\n}\n\n// RegistryEndpoint defines a registry mirror endpoint.\ntype RegistryEndpoint struct {\n\t//   description: |\n\t//     The URL of the registry mirror endpoint.\n\t//   schemaRequired: true\n\t//   examples:\n\t//     - value: >\n\t//        \"https://my-registry-mirror.local:5000\"\n\t//   schema:\n\t//     type: string\n\t//     pattern: \"^(http|https)://\"\n\tEndpointURL meta.URL `yaml:\"url\"`\n\t//   description: |\n\t//     Use endpoint path as supplied, without adding `/v2/` suffix.\n\tEndpointOverridePath *bool `yaml:\"overridePath,omitempty\"`\n}\n\n// NewRegistryMirrorConfigV1Alpha1 creates a new RegistryMirrorConfig config document.\nfunc NewRegistryMirrorConfigV1Alpha1(name string) *RegistryMirrorConfigV1Alpha1 {\n\treturn &RegistryMirrorConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RegistryMirrorConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleRegistryMirrorConfigVAlpha1() *RegistryMirrorConfigV1Alpha1 {\n\tcfg := NewRegistryMirrorConfigV1Alpha1(\"registry.k8s.io\")\n\tcfg.RegistrySkipFallback = new(true)\n\tcfg.RegistryEndpoints = []RegistryEndpoint{\n\t\t{\n\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"https://my-private-registry.local:5000\"))},\n\t\t},\n\t\t{\n\t\t\tEndpointURL:          meta.URL{URL: ensure.Value(url.Parse(\"http://my-harbor/v2/registry-k8s.io/\"))},\n\t\t\tEndpointOverridePath: new(true),\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *RegistryMirrorConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.Document interface.\nfunc (s *RegistryMirrorConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *RegistryMirrorConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tfor idx, ep := range s.RegistryEndpoints {\n\t\tif ep.EndpointURL.URL == nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"endpoints[%d].url must be specified\", idx))\n\t\t} else {\n\t\t\tswitch ep.EndpointURL.URL.Scheme {\n\t\t\tcase \"http\", \"https\":\n\t\t\tdefault:\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"endpoints[%d].url has unsupported scheme: %q\", idx, ep.EndpointURL.URL.Scheme))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn warnings, errs\n}\n\n// Endpoints implements RegistryMirrorConfig interface.\nfunc (s *RegistryMirrorConfigV1Alpha1) Endpoints() []config.RegistryEndpointConfig {\n\treturn xslices.Map(s.RegistryEndpoints, func(ep RegistryEndpoint) config.RegistryEndpointConfig {\n\t\treturn ep\n\t})\n}\n\n// SkipFallback implements RegistryMirrorConfig interface.\nfunc (s *RegistryMirrorConfigV1Alpha1) SkipFallback() bool {\n\treturn pointer.SafeDeref(s.RegistrySkipFallback)\n}\n\n// Endpoint implements RegistryEndpointConfig interface.\nfunc (ep RegistryEndpoint) Endpoint() string {\n\treturn ep.EndpointURL.String()\n}\n\n// OverridePath implements RegistryEndpointConfig interface.\nfunc (ep RegistryEndpoint) OverridePath() bool {\n\treturn pointer.SafeDeref(ep.EndpointOverridePath)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_mirror_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t_ \"embed\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n//go:embed testdata/registrymirrorconfig.yaml\nvar expectedRegistryMirrorConfigDocument []byte\n\nfunc TestRegistryMirrorConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := cri.NewRegistryMirrorConfigV1Alpha1(\"ghcr.io\")\n\tcfg.RegistrySkipFallback = new(true)\n\tcfg.RegistryEndpoints = []cri.RegistryEndpoint{\n\t\t{\n\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"https://my-private-registry.local:5000\"))},\n\t\t},\n\t\t{\n\t\t\tEndpointURL:          meta.URL{URL: ensure.Value(url.Parse(\"http://my-harbor/v2/registry-k8s.io/\"))},\n\t\t\tEndpointOverridePath: new(true),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedRegistryMirrorConfigDocument, marshaled)\n}\n\nfunc TestRegistryMirrorConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedRegistryMirrorConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &cri.RegistryMirrorConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       cri.RegistryMirrorConfig,\n\t\t},\n\t\tMetaName:             \"ghcr.io\",\n\t\tRegistrySkipFallback: new(true),\n\t\tRegistryEndpoints: []cri.RegistryEndpoint{\n\t\t\t{\n\t\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"https://my-private-registry.local:5000\"))},\n\t\t\t},\n\t\t\t{\n\t\t\t\tEndpointURL:          meta.URL{URL: ensure.Value(url.Parse(\"http://my-harbor/v2/registry-k8s.io/\"))},\n\t\t\t\tEndpointOverridePath: new(true),\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestRegistryMirrorConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *cri.RegistryMirrorConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *cri.RegistryMirrorConfigV1Alpha1 {\n\t\t\t\treturn cri.NewRegistryMirrorConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid endpoint URL\",\n\t\t\tcfg: func() *cri.RegistryMirrorConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryMirrorConfigV1Alpha1(\"docker.io\")\n\t\t\t\tcfg.RegistryEndpoints = []cri.RegistryEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointURL: meta.URL{},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"endpoints[0].url must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported endpoint URL scheme\",\n\t\t\tcfg: func() *cri.RegistryMirrorConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryMirrorConfigV1Alpha1(\"docker.io\")\n\t\t\t\tcfg.RegistryEndpoints = []cri.RegistryEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"ftp://my-registry.local:5000\"))},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"endpoints[0].url has unsupported scheme: \\\"ftp\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid empty endpoints\",\n\t\t\tcfg: func() *cri.RegistryMirrorConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryMirrorConfigV1Alpha1(\"docker.io\")\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *cri.RegistryMirrorConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryMirrorConfigV1Alpha1(\"gcr.io\")\n\t\t\t\tcfg.RegistryEndpoints = []cri.RegistryEndpoint{\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointURL: meta.URL{URL: ensure.Value(url.Parse(\"https://my-private-registry.local:5000\"))},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tEndpointURL:          meta.URL{URL: ensure.Value(url.Parse(\"http://my-harbor/v2/registry-k8s.io/\"))},\n\t\t\t\t\t\tEndpointOverridePath: new(true),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_tls.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\tstdx509 \"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n//docgen:jsonschema\n\n// RegistryTLSConfig defines the RegistryTLSConfig configuration name.\nconst RegistryTLSConfig = \"RegistryTLSConfig\"\n\nfunc init() {\n\tregistry.Register(RegistryTLSConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RegistryTLSConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RegistryTLSConfigDocument = &RegistryTLSConfigV1Alpha1{}\n\t_ config.Validator                 = &RegistryTLSConfigV1Alpha1{}\n\t_ config.SecretDocument            = &RegistryTLSConfigV1Alpha1{}\n\t_ config.NamedDocument             = &RegistryTLSConfigV1Alpha1{}\n)\n\n// RegistryTLSConfigV1Alpha1 configures TLS for a registry endpoint.\n//\n//\texamples:\n//\t  - value: exampleRegistryTLSConfigVAlpha1()\n//\talias: RegistryTLSConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/RegistryTLSConfig\ntype RegistryTLSConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Registry endpoint to apply the TLS configuration to.\n\t//\n\t//     Registry endpoint is the hostname part of the endpoint URL,\n\t//     e.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\n\t//\n\t//     The TLS configuration makes sense only for HTTPS endpoints.\n\t//     The TLS configuration will apply to all image pulls for this\n\t//     registry endpoint, by Talos or any Kubernetes workloads.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Enable mutual TLS authentication with the registry.\n\t//     Client certificate and key should be PEM-encoded.\n\t//   examples:\n\t//     - value: exampleCertificateAndKey()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tTLSClientIdentity *meta.CertificateAndKey `yaml:\"clientIdentity,omitempty\"`\n\t//   description: |\n\t//     CA registry certificate to add the list of trusted certificates.\n\t//     Certificate should be PEM-encoded.\n\t//   schema:\n\t//     type: string\n\tTLSCA string `yaml:\"ca,omitempty\"`\n\t//   description: |\n\t//     Skip TLS server certificate verification (not recommended).\n\tTLSInsecureSkipVerify *bool `yaml:\"insecureSkipVerify,omitempty\"`\n}\n\n// NewRegistryTLSConfigV1Alpha1 creates a new RegistryTLSConfig config document.\nfunc NewRegistryTLSConfigV1Alpha1(name string) *RegistryTLSConfigV1Alpha1 {\n\treturn &RegistryTLSConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RegistryTLSConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleRegistryTLSConfigVAlpha1() *RegistryTLSConfigV1Alpha1 {\n\tcfg := NewRegistryTLSConfigV1Alpha1(\"my-private-registry.local:5000\")\n\tcfg.TLSCA = \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\"\n\n\treturn cfg\n}\n\nfunc exampleCertificateAndKey() *meta.CertificateAndKey {\n\treturn &meta.CertificateAndKey{\n\t\tCert: \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\",\n\t\tKey:  \"-----BEGIN PRIVATE KEY-----\\nMIIE...AB\\n-----END PRIVATE KEY-----\",\n\t}\n}\n\n// Clone implements config.Document interface.\nfunc (s *RegistryTLSConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.Document interface.\nfunc (s *RegistryTLSConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *RegistryTLSConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif s.TLSCA != \"\" {\n\t\tif !stdx509.NewCertPool().AppendCertsFromPEM([]byte(s.TLSCA)) {\n\t\t\terrs = errors.Join(errs, errors.New(\"ca must be a valid PEM-encoded certificate\"))\n\t\t}\n\t}\n\n\tif s.TLSClientIdentity != nil {\n\t\tkeyPair := s.ClientIdentity()\n\n\t\t_, err := keyPair.GetCert()\n\t\tif err != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"client identity certificate is invalid: %w\", err))\n\t\t}\n\n\t\t_, err = keyPair.GetPrivateKey()\n\t\tif err != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"client identity key is invalid: %w\", err))\n\t\t}\n\t}\n\n\treturn warnings, errs\n}\n\n// ClientIdentity implements config.RegistryTLSConfigDocument interface.\nfunc (s *RegistryTLSConfigV1Alpha1) ClientIdentity() *x509.PEMEncodedCertificateAndKey {\n\tif s.TLSClientIdentity == nil {\n\t\treturn nil\n\t}\n\n\treturn &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: []byte(s.TLSClientIdentity.Cert),\n\t\tKey: []byte(s.TLSClientIdentity.Key),\n\t}\n}\n\n// CA implements config.RegistryTLSConfigDocument interface.\nfunc (s *RegistryTLSConfigV1Alpha1) CA() []byte {\n\tif s.TLSCA == \"\" {\n\t\treturn nil\n\t}\n\n\treturn []byte(s.TLSCA)\n}\n\n// InsecureSkipVerify implements config.RegistryTLSConfigDocument interface.\nfunc (s *RegistryTLSConfigV1Alpha1) InsecureSkipVerify() bool {\n\treturn pointer.SafeDeref(s.TLSInsecureSkipVerify)\n}\n\n// Redact implements config.SecretDocument interface.\nfunc (s *RegistryTLSConfigV1Alpha1) Redact(replacement string) {\n\tif s.TLSClientIdentity != nil {\n\t\tif s.TLSClientIdentity.Key != \"\" {\n\t\t\ts.TLSClientIdentity.Key = replacement\n\t\t}\n\t}\n\n\tif s.TLSCA != \"\" {\n\t\ts.TLSCA = replacement\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/registry_tls_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n//go:embed testdata/registrytlsconfig.yaml\nvar expectedRegistryTLSConfigDocument []byte\n\nfunc TestRegistryTLSConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := cri.NewRegistryTLSConfigV1Alpha1(\"my-tls-registry.io\")\n\tcfg.TLSCA = \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\"\n\tcfg.TLSClientIdentity = &meta.CertificateAndKey{\n\t\tCert: \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\",\n\t\tKey:  \"-----BEGIN PRIVATE KEY-----\\nMIIE...AB\\n-----END PRIVATE KEY-----\",\n\t}\n\tcfg.TLSInsecureSkipVerify = new(true)\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedRegistryTLSConfigDocument, marshaled)\n}\n\nfunc TestRegistryTLSConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedRegistryTLSConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &cri.RegistryTLSConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       cri.RegistryTLSConfig,\n\t\t},\n\t\tMetaName: \"my-tls-registry.io\",\n\t\tTLSCA:    \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\",\n\t\tTLSClientIdentity: &meta.CertificateAndKey{\n\t\t\tCert: \"-----BEGIN CERTIFICATE-----\\nMIID...IDAQAB\\n-----END CERTIFICATE-----\",\n\t\t\tKey:  \"-----BEGIN PRIVATE KEY-----\\nMIIE...AB\\n-----END PRIVATE KEY-----\",\n\t\t},\n\t\tTLSInsecureSkipVerify: new(true),\n\t}, docs[0])\n}\n\nfunc TestRegistryTLSConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *cri.RegistryTLSConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *cri.RegistryTLSConfigV1Alpha1 {\n\t\t\t\treturn cri.NewRegistryTLSConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid small\",\n\t\t\tcfg: func() *cri.RegistryTLSConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryTLSConfigV1Alpha1(\"rr.k8s.io\")\n\t\t\t\tcfg.TLSInsecureSkipVerify = new(true)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *cri.RegistryTLSConfigV1Alpha1 {\n\t\t\t\tcfg := cri.NewRegistryTLSConfigV1Alpha1(\"k8s.io\")\n\n\t\t\t\tca, err := x509.NewSelfSignedCertificateAuthority()\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tcfg.TLSCA = string(ca.CrtPEM)\n\t\t\t\tcfg.TLSClientIdentity = &meta.CertificateAndKey{\n\t\t\t\t\tCert: string(ca.CrtPEM),\n\t\t\t\t\tKey:  string(ca.KeyPEM),\n\t\t\t\t}\n\t\t\t\tcfg.TLSInsecureSkipVerify = new(false)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/testdata/registryauthconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: RegistryAuthConfig\nname: my-private-registry.io\nusername: agent007\npassword: topsecret\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/testdata/registrymirrorconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: ghcr.io\nendpoints:\n    - url: https://my-private-registry.local:5000\n    - url: http://my-harbor/v2/registry-k8s.io/\n      overridePath: true\nskipFallback: true\n"
  },
  {
    "path": "pkg/machinery/config/types/cri/testdata/registrytlsconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: RegistryTLSConfig\nname: my-tls-registry.io\nclientIdentity:\n    cert: |-\n        -----BEGIN CERTIFICATE-----\n        MIID...IDAQAB\n        -----END CERTIFICATE-----\n    key: |-\n        -----BEGIN PRIVATE KEY-----\n        MIIE...AB\n        -----END PRIVATE KEY-----\nca: |-\n    -----BEGIN CERTIFICATE-----\n    MIID...IDAQAB\n    -----END CERTIFICATE-----\ninsecureSkipVerify: true\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type PCIDriverRebindConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage hardware\n\n// DeepCopy generates a deep copy of *PCIDriverRebindConfigV1Alpha1.\nfunc (o *PCIDriverRebindConfigV1Alpha1) DeepCopy() *PCIDriverRebindConfigV1Alpha1 {\n\tvar cp PCIDriverRebindConfigV1Alpha1 = *o\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/hardware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package hardware provides hardware related config documents.\npackage hardware\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output hardware_doc.go hardware.go pci_driver_rebind_config.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type PCIDriverRebindConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/hardware_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage hardware\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (PCIDriverRebindConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"PCIDriverRebindConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"PCIDriverRebindConfig allows to configure PCI driver rebinds.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"PCIDriverRebindConfig allows to configure PCI driver rebinds.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"PCI device id\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"PCI device id\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"targetDriver\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Target driver to rebind the PCI device to.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Target driver to rebind the PCI device to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", examplePCIDriverRebindConfigAlpha1())\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file hardware_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"hardware\",\n\t\tDescription: \"Package hardware provides hardware related config documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tPCIDriverRebindConfigV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/pci_driver_rebind_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n//docgen:jsonschema\n\n// PCIDriverRebindConfig defines the PCIDriverRebind configuration name.\nconst PCIDriverRebindConfig = \"PCIDriverRebindConfig\"\n\nfunc init() {\n\tregistry.Register(PCIDriverRebindConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\":\n\t\t\treturn &PCIDriverRebindConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.PCIDriverRebindConfig = &PCIDriverRebindConfigV1Alpha1{}\n\t_ config.NamedDocument         = &PCIDriverRebindConfigV1Alpha1{}\n)\n\n// PCIDriverRebindConfigV1Alpha1 allows to configure PCI driver rebinds.\n//\n//\texamples:\n//\t  - value: examplePCIDriverRebindConfigAlpha1()\n//\talias: PCIDriverRebindConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/PCIDriverRebindConfig\ntype PCIDriverRebindConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     PCI device id\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Target driver to rebind the PCI device to.\n\t//   schemaRequired: true\n\tPCITargetDriver string `yaml:\"targetDriver\"`\n}\n\n// NewPCIDriverRebindConfigV1Alpha1 creates a new PCIDriverRebindConfig config document.\nfunc NewPCIDriverRebindConfigV1Alpha1() *PCIDriverRebindConfigV1Alpha1 {\n\treturn &PCIDriverRebindConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       PCIDriverRebindConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc examplePCIDriverRebindConfigAlpha1() *PCIDriverRebindConfigV1Alpha1 {\n\tcfg := NewPCIDriverRebindConfigV1Alpha1()\n\tcfg.MetaName = \"0000:04:00.00\"\n\tcfg.PCITargetDriver = \"vfio-pci\"\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.Document interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// PCIDriverRebindConfigs implements config.PCIDriverRebindConfig interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) PCIDriverRebindConfigs() []config.PCIDriverRebindConfigDriver {\n\treturn []config.PCIDriverRebindConfigDriver{s}\n}\n\n// PCIID implements config.PCIDriverRebindConfigDriver interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) PCIID() string {\n\treturn s.MetaName\n}\n\n// TargetDriver implements config.PCIDriverRebindConfigDriver interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) TargetDriver() string {\n\treturn s.PCITargetDriver\n}\n\n// RuntimeValidate implements config.RuntimeValidatable interface.\nfunc (s *PCIDriverRebindConfigV1Alpha1) RuntimeValidate(ctx context.Context, st state.State, v validation.RuntimeMode, opts ...validation.Option) ([]string, error) {\n\tvar count int\n\n\tif err := filepath.WalkDir(\"/sys/class/iommu\", func(path string, d os.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\trel, err := filepath.Rel(\"/sys/class/iommu\", path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif rel == \".\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tcount++\n\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif count == 0 {\n\t\treturn []string{\"IOMMU is not enabled, this config change might not have any effect\"}, nil\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/pci_driver_rebind_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n//go:embed testdata/pcidriverrebindconfig.yaml\nvar expectedPCIDriverRebindConfigDocument []byte\n\nfunc TestPCIDriverRebindConfigMarshal(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := hardware.NewPCIDriverRebindConfigV1Alpha1()\n\tcfg.MetaName = \"0000:04:00.00\"\n\tcfg.PCITargetDriver = \"vfio-pci\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, string(expectedPCIDriverRebindConfigDocument), string(marshaled))\n}\n\nfunc TestPCIDriverRebindConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedPCIDriverRebindConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &hardware.PCIDriverRebindConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       hardware.PCIDriverRebindConfig,\n\t\t},\n\t\tMetaName:        \"0000:04:00.00\",\n\t\tPCITargetDriver: \"vfio-pci\",\n\t}, docs[0])\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/hardware/testdata/pcidriverrebindconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: PCIDriverRebindConfig\nname: \"0000:04:00.00\"\ntargetDriver: vfio-pci\n"
  },
  {
    "path": "pkg/machinery/config/types/meta/certificate_key.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage meta\n\n// CertificateAndKey represents a PEM-encoded certificate and key pair.\ntype CertificateAndKey struct {\n\tCert string `yaml:\"cert,omitempty\"`\n\tKey  string `yaml:\"key,omitempty\"`\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/meta/meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package meta provides common meta types for config documents.\npackage meta\n\n// Meta is a shared meta information for config documents.\ntype Meta struct {\n\tMetaAPIVersion string `yaml:\"apiVersion,omitempty\"`\n\tMetaKind       string `yaml:\"kind\"`\n}\n\n// Kind implements config.Document interface.\nfunc (m Meta) Kind() string {\n\treturn m.MetaKind\n}\n\n// APIVersion implements config.Document interface.\nfunc (m Meta) APIVersion() string {\n\treturn m.MetaAPIVersion\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/meta/url.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage meta\n\nimport \"net/url\"\n\n// URL wraps the URL with proper YAML marshal/unmarshal.\ntype URL struct {\n\t*url.URL\n}\n\n// UnmarshalYAML is a custom unmarshaller for `URL`.\nfunc (u *URL) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar endpoint string\n\n\tif err := unmarshal(&endpoint); err != nil {\n\t\treturn err\n\t}\n\n\tif endpoint == \"\" {\n\t\treturn nil\n\t}\n\n\turl, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*u = URL{url}\n\n\treturn nil\n}\n\n// MarshalYAML is a custom marshaller for `URL`.\nfunc (u URL) MarshalYAML() (any, error) {\n\tif u.URL == nil {\n\t\treturn \"\", nil\n\t}\n\n\treturn u.URL.String(), nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/blackhole_route.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// BlackholeRouteKind is a BlackholeRoute config document kind.\nconst BlackholeRouteKind = \"BlackholeRouteConfig\"\n\nfunc init() {\n\tregistry.Register(BlackholeRouteKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &BlackholeRouteConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkBlackholeRouteConfig = &BlackholeRouteConfigV1Alpha1{}\n\t_ config.NamedDocument               = &BlackholeRouteConfigV1Alpha1{}\n\t_ config.Validator                   = &BlackholeRouteConfigV1Alpha1{}\n)\n\n// BlackholeRouteConfigV1Alpha1 is a config document to configure blackhole routes.\n//\n//\texamples:\n//\t  - value: exampleBlackholeRouteConfigV1Alpha1()\n//\talias: BlackholeRouteConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/BlackholeRouteConfig\ntype BlackholeRouteConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Route destination as an address prefix.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"10.0.0.0/12\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The optional metric for the route.\n\tRouteMetric uint32 `yaml:\"metric,omitempty\"`\n}\n\n// NewBlackholeRouteConfigV1Alpha1 creates a new BlackholeRouteConfig config document.\nfunc NewBlackholeRouteConfigV1Alpha1(name string) *BlackholeRouteConfigV1Alpha1 {\n\treturn &BlackholeRouteConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       BlackholeRouteKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleBlackholeRouteConfigV1Alpha1() *BlackholeRouteConfigV1Alpha1 {\n\tcfg := NewBlackholeRouteConfigV1Alpha1(\"10.0.0.0/12\")\n\tcfg.RouteMetric = 100\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *BlackholeRouteConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *BlackholeRouteConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// BlackholeRouteConfig implements BlackholeRouteConfig interface.\nfunc (s *BlackholeRouteConfigV1Alpha1) BlackholeRouteConfig() {}\n\n// Validate implements config.Validator interface.\nfunc (s *BlackholeRouteConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif _, err := netip.ParsePrefix(s.MetaName); err != nil {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"name must be a valid address prefix: %w\", err))\n\t}\n\n\treturn nil, errs\n}\n\n// Metric implements NetworkRouteConfig interface.\nfunc (s *BlackholeRouteConfigV1Alpha1) Metric() optional.Optional[uint32] {\n\tif s.RouteMetric == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(s.RouteMetric)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/blackhole_route_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/blackholerouteconfig.yaml\nvar expectedBlackholeRouteConfigDocument []byte\n\nfunc TestBlackholeRouteConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewBlackholeRouteConfigV1Alpha1(\"169.254.1.1/32\")\n\tcfg.RouteMetric = 2000\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedBlackholeRouteConfigDocument, marshaled)\n}\n\nfunc TestBlackholeRouteConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedBlackholeRouteConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.BlackholeRouteConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.BlackholeRouteKind,\n\t\t},\n\t\tMetaName:    \"169.254.1.1/32\",\n\t\tRouteMetric: 2000,\n\t}, docs[0])\n}\n\nfunc TestBlackholeRouteConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.BlackholeRouteConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.BlackholeRouteConfigV1Alpha1 {\n\t\t\t\treturn network.NewBlackholeRouteConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nname must be a valid address prefix: netip.ParsePrefix(\\\"\\\"): no '/'\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid prefix\",\n\n\t\t\tcfg: func() *network.BlackholeRouteConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBlackholeRouteConfigV1Alpha1(\"no-prefix\")\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"name must be a valid address prefix: netip.ParsePrefix(\\\"no-prefix\\\"): no '/'\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\n\t\t\tcfg: func() *network.BlackholeRouteConfigV1Alpha1 {\n\t\t\t\treturn network.NewBlackholeRouteConfigV1Alpha1(\"10.0.1.2/24\")\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/bond.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// BondKind is a Bond config document kind.\nconst BondKind = \"BondConfig\"\n\nfunc init() {\n\tregistry.Register(BondKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &BondConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkBondConfig   = &BondConfigV1Alpha1{}\n\t_ config.ConflictingDocument = &BondConfigV1Alpha1{}\n\t_ config.NamedDocument       = &BondConfigV1Alpha1{}\n\t_ config.Validator           = &BondConfigV1Alpha1{}\n)\n\n// BondConfigV1Alpha1 is a config document to create a bond (link aggregation) over a set of links.\n//\n//\texamples:\n//\t  - value: exampleBondConfigV1Alpha1()\n//\talias: BondConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/BondConfig\ntype BondConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the bond link (interface) to be created.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"bond.ext\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Override the hardware (MAC) address of the link.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f:]+$\n\tHardwareAddressConfig nethelpers.HardwareAddr `yaml:\"hardwareAddr,omitempty\"`\n\t//   description: |\n\t//     Names of the links (interfaces) on which the bond will be created.\n\t//     Link aliases can be used here as well.\n\t//   examples:\n\t//    - value: >\n\t//       []string{\"enp0s3\", \"enp0s8\"}\n\t//   schemaRequired: true\n\tBondLinks []string `yaml:\"links,omitempty\"`\n\t//   description: |\n\t//     Bond mode.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"802.3ad\"\n\t//   values:\n\t//     - \"balance-rr\"\n\t//     - \"active-backup\"\n\t//     - \"balance-xor\"\n\t//     - \"broadcast\"\n\t//     - \"802.3ad\"\n\t//     - \"balance-tlb\"\n\t//     - \"balance-alb\"\n\t//   schemaRequired: true\n\tBondMode *nethelpers.BondMode `yaml:\"bondMode,omitempty\"`\n\t//   description: |\n\t//     Link monitoring frequency in milliseconds.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       200\n\tBondMIIMon *uint32 `yaml:\"miimon,omitempty\"`\n\t//   description: |\n\t//     The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       300\n\tBondUpDelay *uint32 `yaml:\"updelay,omitempty\"`\n\t//   description: |\n\t//     The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       100\n\tBondDownDelay *uint32 `yaml:\"downdelay,omitempty\"`\n\t//   description: |\n\t//     Specifies whether or not miimon should use MII or ETHTOOL.\n\tBondUseCarrier *bool `yaml:\"useCarrier,omitempty\"`\n\t//   description: |\n\t//     Selects the transmit hash policy to use for slave selection.\n\t//   examples:\n\t//    - value: >\n\t//       \"layer2\"\n\t//   values:\n\t//     - \"layer2\"\n\t//     - \"layer3+4\"\n\t//     - \"layer2+3\"\n\t//     - \"encap2+3\"\n\t//     - \"encap3+4\"\n\tBondXmitHashPolicy *nethelpers.BondXmitHashPolicy `yaml:\"xmitHashPolicy,omitempty\"`\n\t//   description: |\n\t//    ARP link monitoring frequency in milliseconds.\n\t//   examples:\n\t//    - value: >\n\t//       1000\n\tBondARPInterval *uint32 `yaml:\"arpInterval,omitempty\"`\n\t//   description: |\n\t//     The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\n\t//     Maximum of 16 targets are supported.\n\t//   examples:\n\t//    - value: >\n\t//       []netip.Addr{netip.MustParseAddr(\"10.15.0.1\")}\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\t//       pattern: ^[0-9a-f.:]+$\n\tBondARPIPTargets []netip.Addr `yaml:\"arpIpTargets,omitempty\"`\n\t//   description: |\n\t//     The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\n\t//     Maximum of 16 targets are supported.\n\t//   examples:\n\t//    - value: >\n\t//       []netip.Addr{netip.MustParseAddr(\"fd00::1\")}\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\t//       pattern: ^[0-9a-f.:]+$\n\tBondNSIP6Targets []netip.Addr `yaml:\"nsIp6Targets,omitempty\"`\n\t//   description: |\n\t//     Specifies whether or not ARP probes and replies should be validated.\n\t//   examples:\n\t//    - value: >\n\t//       \"active\"\n\t//   values:\n\t//     - \"none\"\n\t//     - \"active\"\n\t//     - \"backup\"\n\t//     - \"all\"\n\t//     - \"filter\"\n\t//     - \"filter-active\"\n\t//     - \"filter-backup\"\n\tBondARPValidate *nethelpers.ARPValidate `yaml:\"arpValidate,omitempty\"`\n\t//   description: |\n\t//     Specifies whether ARP probes should be sent to any or all targets.\n\t//   examples:\n\t//    - value: >\n\t//       \"all\"\n\t//   values:\n\t//     - \"any\"\n\t//     - \"all\"\n\tBondARPAllTargets *nethelpers.ARPAllTargets `yaml:\"arpAllTargets,omitempty\"`\n\t//   description: |\n\t//     LACPDU frames periodic transmission rate.\n\t//   examples:\n\t//    - value: >\n\t//       \"fast\"\n\t//   values:\n\t//     - \"slow\"\n\t//     - \"fast\"\n\tBondLACPRate *nethelpers.LACPRate `yaml:\"lacpRate,omitempty\"`\n\t//   description: |\n\t//     Specifies whether active-backup mode should set all slaves to the same MAC address\n\t//     at enslavement, when enabled, or perform special handling.\n\t//   examples:\n\t//    - value: >\n\t//       \"active\"\n\t//   values:\n\t//     - \"none\"\n\t//     - \"active\"\n\t//     - \"follow\"\n\tBondFailOverMAC *nethelpers.FailOverMAC `yaml:\"failOverMac,omitempty\"`\n\t//   description: |\n\t//     Aggregate selection policy for 802.3ad.\n\t//   examples:\n\t//    - value: >\n\t//       \"stable\"\n\t//   values:\n\t//     - \"stable\"\n\t//     - \"bandwidth\"\n\t//     - \"count\"\n\tBondADSelect *nethelpers.ADSelect `yaml:\"adSelect,omitempty\"`\n\t//   description: |\n\t//     Actor system priority for 802.3ad.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       65535\n\tBondADActorSysPrio *uint16 `yaml:\"adActorSysPrio,omitempty\"`\n\t//   description: |\n\t//     User port key (upper 10 bits) for 802.3ad.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       0\n\tBondADUserPortKey *uint16 `yaml:\"adUserPortKey,omitempty\"`\n\t//   description: |\n\t//     Whether to send LACPDU frames periodically.\n\t//   examples:\n\t//    - value: >\n\t//       \"on\"\n\t//   values:\n\t//     - \"on\"\n\t//     - \"off\"\n\tBondADLACPActive *nethelpers.ADLACPActive `yaml:\"adLACPActive,omitempty\"`\n\t//   description: |\n\t//     Policy under which the primary slave should be reselected.\n\t//   examples:\n\t//    - value: >\n\t//       \"always\"\n\t//   values:\n\t//     - \"always\"\n\t//     - \"better\"\n\t//     - \"failure\"\n\tBondPrimaryReselect *nethelpers.PrimaryReselect `yaml:\"primaryReselect,omitempty\"`\n\t//   description: |\n\t//     The number of times IGMP packets should be resent.\n\tBondResendIGMP *uint32 `yaml:\"resendIGMP,omitempty\"`\n\t//   description: |\n\t//     The minimum number of active links required for the bond to be considered active.\n\tBondMinLinks *uint32 `yaml:\"minLinks,omitempty\"`\n\t//   description: |\n\t//     The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\n\tBondLPInterval *uint32 `yaml:\"lpInterval,omitempty\"`\n\t//   description: |\n\t//     The number of packets to transmit through a slave before moving to the next one.\n\tBondPacketsPerSlave *uint32 `yaml:\"packetsPerSlave,omitempty\"`\n\t//   description: |\n\t//     The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\n\t//     to be issued after a failover event.\n\tBondNumPeerNotif *uint8 `yaml:\"numPeerNotif,omitempty\"`\n\t//   description: |\n\t//     Whether dynamic shuffling of flows is enabled in tlb or alb mode.\n\t//   examples:\n\t//    - value: >\n\t//       1\n\tBondTLBDynamicLB *uint8 `yaml:\"tlbLogicalLb,omitempty\"`\n\t//   description: |\n\t//     Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\n\t//   examples:\n\t//    - value: >\n\t//       0\n\tBondAllSlavesActive *uint8 `yaml:\"allSlavesActive,omitempty\"`\n\t//   description: |\n\t//     The delay, in milliseconds, between each peer notification.\n\tBondPeerNotifyDelay *uint32 `yaml:\"peerNotifDelay,omitempty\"`\n\t//   description: |\n\t//     The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\n\tBondMissedMax *uint8 `yaml:\"missedMax,omitempty\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// NewBondConfigV1Alpha1 creates a new BondConfig config document.\nfunc NewBondConfigV1Alpha1(name string) *BondConfigV1Alpha1 {\n\treturn &BondConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       BondKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleBondConfigV1Alpha1() *BondConfigV1Alpha1 {\n\tcfg := NewBondConfigV1Alpha1(\"bond.int\")\n\tcfg.BondLinks = []string{\"enp1s2\", \"enp1s2\"}\n\tcfg.BondMode = new(nethelpers.BondMode8023AD)\n\tcfg.BondXmitHashPolicy = new(nethelpers.BondXmitPolicyLayer34)\n\tcfg.BondLACPRate = new(nethelpers.LACPRateSlow)\n\tcfg.BondMIIMon = new(uint32(100))\n\tcfg.BondUpDelay = new(uint32(200))\n\tcfg.BondDownDelay = new(uint32(200))\n\tcfg.BondResendIGMP = new(uint32(1))\n\tcfg.BondPacketsPerSlave = new(uint32(1))\n\tcfg.BondADActorSysPrio = new(uint16(65535))\n\n\tcfg.LinkAddresses = []AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"10.15.0.3/16\"),\n\t\t},\n\t}\n\tcfg.LinkRoutes = []RouteConfig{\n\t\t{\n\t\t\tRouteDestination: Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")},\n\t\t\tRouteGateway:     Addr{netip.MustParseAddr(\"10.15.0.1\")},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *BondConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *BondConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// BondConfig implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) BondConfig() {}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *BondConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(BondKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *BondConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif len(s.BondLinks) == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"at least one link must be specified\"))\n\t}\n\n\tif s.BondMode == nil {\n\t\terrs = errors.Join(errs, errors.New(\"bond mode must be specified\"))\n\t} else if *s.BondMode == nethelpers.BondMode8023AD {\n\t\twarnings = append(warnings, s.validateFor8023AD()...)\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\nfunc (s *BondConfigV1Alpha1) validateFor8023AD() []string {\n\tconst warn = \" was not specified for 802.3ad bond\"\n\n\tvar warnings []string\n\n\tif s.BondMIIMon == nil {\n\t\twarnings = append(warnings, \"miimon\"+warn)\n\t}\n\n\tif s.BondUpDelay == nil {\n\t\twarnings = append(warnings, \"updelay\"+warn)\n\t}\n\n\tif s.BondDownDelay == nil {\n\t\twarnings = append(warnings, \"downdelay\"+warn)\n\t}\n\n\treturn warnings\n}\n\n// Links implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) Links() []string {\n\treturn s.BondLinks\n}\n\n// Mode implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) Mode() nethelpers.BondMode {\n\treturn pointer.SafeDeref(s.BondMode)\n}\n\n// MIIMon implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) MIIMon() optional.Optional[uint32] {\n\tif s.BondMIIMon == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondMIIMon)\n}\n\n// UpDelay implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) UpDelay() optional.Optional[uint32] {\n\tif s.BondUpDelay == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondUpDelay)\n}\n\n// DownDelay implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) DownDelay() optional.Optional[uint32] {\n\tif s.BondDownDelay == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondDownDelay)\n}\n\n// UseCarrier implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) UseCarrier() optional.Optional[bool] {\n\tif s.BondUseCarrier == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.BondUseCarrier)\n}\n\n// XmitHashPolicy implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) XmitHashPolicy() optional.Optional[nethelpers.BondXmitHashPolicy] {\n\tif s.BondXmitHashPolicy == nil {\n\t\treturn optional.None[nethelpers.BondXmitHashPolicy]()\n\t}\n\n\treturn optional.Some(*s.BondXmitHashPolicy)\n}\n\n// ARPInterval implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ARPInterval() optional.Optional[uint32] {\n\tif s.BondARPInterval == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondARPInterval)\n}\n\n// ARPIPTargets implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ARPIPTargets() []netip.Addr {\n\treturn s.BondARPIPTargets\n}\n\n// NSIP6Targets implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) NSIP6Targets() []netip.Addr {\n\treturn s.BondNSIP6Targets\n}\n\n// ARPValidate implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ARPValidate() optional.Optional[nethelpers.ARPValidate] {\n\tif s.BondARPValidate == nil {\n\t\treturn optional.None[nethelpers.ARPValidate]()\n\t}\n\n\treturn optional.Some(*s.BondARPValidate)\n}\n\n// ARPAllTargets implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ARPAllTargets() optional.Optional[nethelpers.ARPAllTargets] {\n\tif s.BondARPAllTargets == nil {\n\t\treturn optional.None[nethelpers.ARPAllTargets]()\n\t}\n\n\treturn optional.Some(*s.BondARPAllTargets)\n}\n\n// LACPRate implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) LACPRate() optional.Optional[nethelpers.LACPRate] {\n\tif s.BondLACPRate == nil {\n\t\treturn optional.None[nethelpers.LACPRate]()\n\t}\n\n\treturn optional.Some(*s.BondLACPRate)\n}\n\n// FailOverMAC implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) FailOverMAC() optional.Optional[nethelpers.FailOverMAC] {\n\tif s.BondFailOverMAC == nil {\n\t\treturn optional.None[nethelpers.FailOverMAC]()\n\t}\n\n\treturn optional.Some(*s.BondFailOverMAC)\n}\n\n// ADSelect implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ADSelect() optional.Optional[nethelpers.ADSelect] {\n\tif s.BondADSelect == nil {\n\t\treturn optional.None[nethelpers.ADSelect]()\n\t}\n\n\treturn optional.Some(*s.BondADSelect)\n}\n\n// ADActorSysPrio implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ADActorSysPrio() optional.Optional[uint16] {\n\tif s.BondADActorSysPrio == nil {\n\t\treturn optional.None[uint16]()\n\t}\n\n\treturn optional.Some(*s.BondADActorSysPrio)\n}\n\n// ADUserPortKey implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ADUserPortKey() optional.Optional[uint16] {\n\tif s.BondADUserPortKey == nil {\n\t\treturn optional.None[uint16]()\n\t}\n\n\treturn optional.Some(*s.BondADUserPortKey)\n}\n\n// ADLACPActive implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ADLACPActive() optional.Optional[nethelpers.ADLACPActive] {\n\tif s.BondADLACPActive == nil {\n\t\treturn optional.None[nethelpers.ADLACPActive]()\n\t}\n\n\treturn optional.Some(*s.BondADLACPActive)\n}\n\n// PrimaryReselect implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) PrimaryReselect() optional.Optional[nethelpers.PrimaryReselect] {\n\tif s.BondPrimaryReselect == nil {\n\t\treturn optional.None[nethelpers.PrimaryReselect]()\n\t}\n\n\treturn optional.Some(*s.BondPrimaryReselect)\n}\n\n// ResendIGMP implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) ResendIGMP() optional.Optional[uint32] {\n\tif s.BondResendIGMP == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondResendIGMP)\n}\n\n// MinLinks implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) MinLinks() optional.Optional[uint32] {\n\tif s.BondMinLinks == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondMinLinks)\n}\n\n// LPInterval implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) LPInterval() optional.Optional[uint32] {\n\tif s.BondLPInterval == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondLPInterval)\n}\n\n// PacketsPerSlave implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) PacketsPerSlave() optional.Optional[uint32] {\n\tif s.BondPacketsPerSlave == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondPacketsPerSlave)\n}\n\n// NumPeerNotif implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) NumPeerNotif() optional.Optional[uint8] {\n\tif s.BondNumPeerNotif == nil {\n\t\treturn optional.None[uint8]()\n\t}\n\n\treturn optional.Some(*s.BondNumPeerNotif)\n}\n\n// TLBDynamicLB implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) TLBDynamicLB() optional.Optional[uint8] {\n\tif s.BondTLBDynamicLB == nil {\n\t\treturn optional.None[uint8]()\n\t}\n\n\treturn optional.Some(*s.BondTLBDynamicLB)\n}\n\n// AllSlavesActive implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) AllSlavesActive() optional.Optional[uint8] {\n\tif s.BondAllSlavesActive == nil {\n\t\treturn optional.None[uint8]()\n\t}\n\n\treturn optional.Some(*s.BondAllSlavesActive)\n}\n\n// PeerNotifyDelay implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) PeerNotifyDelay() optional.Optional[uint32] {\n\tif s.BondPeerNotifyDelay == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*s.BondPeerNotifyDelay)\n}\n\n// MissedMax implements NetworkBondConfig interface.\nfunc (s *BondConfigV1Alpha1) MissedMax() optional.Optional[uint8] {\n\tif s.BondMissedMax == nil {\n\t\treturn optional.None[uint8]()\n\t}\n\n\treturn optional.Some(*s.BondMissedMax)\n}\n\n// HardwareAddress implements NetworkDummyLinkConfig interface.\nfunc (s *BondConfigV1Alpha1) HardwareAddress() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.HardwareAddressConfig) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.HardwareAddressConfig)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/bond_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/bondconfig.yaml\nvar expectedBondConfigDocument []byte\n\nfunc TestBondConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewBondConfigV1Alpha1(\"agg.0\")\n\tcfg.BondLinks = []string{\"eth0\", \"eth1\"}\n\tcfg.BondMode = new(nethelpers.BondMode8023AD)\n\tcfg.BondXmitHashPolicy = new(nethelpers.BondXmitPolicyLayer34)\n\tcfg.BondFailOverMAC = new(nethelpers.FailOverMACFollow)\n\tcfg.BondLACPRate = new(nethelpers.LACPRateSlow)\n\tcfg.BondMIIMon = new(uint32(100))\n\tcfg.BondUpDelay = new(uint32(200))\n\tcfg.BondDownDelay = new(uint32(200))\n\tcfg.BondResendIGMP = new(uint32(1))\n\tcfg.BondPacketsPerSlave = new(uint32(1))\n\tcfg.BondADActorSysPrio = new(uint16(65535))\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.4/24\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedBondConfigDocument, marshaled)\n}\n\nfunc TestBondConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedBondConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.BondConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.BondKind,\n\t\t},\n\t\tMetaName:            \"agg.0\",\n\t\tBondLinks:           []string{\"eth0\", \"eth1\"},\n\t\tBondMode:            new(nethelpers.BondMode8023AD),\n\t\tBondXmitHashPolicy:  new(nethelpers.BondXmitPolicyLayer34),\n\t\tBondFailOverMAC:     new(nethelpers.FailOverMACFollow),\n\t\tBondLACPRate:        new(nethelpers.LACPRateSlow),\n\t\tBondMIIMon:          new(uint32(100)),\n\t\tBondUpDelay:         new(uint32(200)),\n\t\tBondDownDelay:       new(uint32(200)),\n\t\tBondResendIGMP:      new(uint32(1)),\n\t\tBondPacketsPerSlave: new(uint32(1)),\n\t\tBondADActorSysPrio:  new(uint16(65535)),\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.4/24\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestBondValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.BondConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.BondConfigV1Alpha1 {\n\t\t\t\treturn network.NewBondConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nat least one link must be specified\\nbond mode must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"no links\",\n\n\t\t\tcfg: func() *network.BondConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBondConfigV1Alpha1(\"bond0\")\n\t\t\t\tcfg.BondMode = new(nethelpers.BondModeActiveBackup)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"at least one link must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"no mode\",\n\n\t\t\tcfg: func() *network.BondConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBondConfigV1Alpha1(\"bond0\")\n\t\t\t\tcfg.BondLinks = []string{\"eth0\", \"eth1\"}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"bond mode must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.BondConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBondConfigV1Alpha1(\"bond25\")\n\t\t\t\tcfg.BondLinks = []string{\"eth0\", \"eth1\"}\n\t\t\t\tcfg.BondMode = new(nethelpers.BondMode8023AD)\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedWarnings: []string{\n\t\t\t\t\"miimon was not specified for 802.3ad bond\",\n\t\t\t\t\"updelay was not specified for 802.3ad bond\",\n\t\t\t\t\"downdelay was not specified for 802.3ad bond\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/bridge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// BridgeKind is a Bridge config document kind.\nconst BridgeKind = \"BridgeConfig\"\n\nfunc init() {\n\tregistry.Register(BridgeKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &BridgeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkBridgeConfig = &BridgeConfigV1Alpha1{}\n\t_ config.ConflictingDocument = &BridgeConfigV1Alpha1{}\n\t_ config.NamedDocument       = &BridgeConfigV1Alpha1{}\n\t_ config.Validator           = &BridgeConfigV1Alpha1{}\n)\n\n// BridgeConfigV1Alpha1 is a config document to create a Bridge (link aggregation) over a set of links.\n//\n//\texamples:\n//\t  - value: exampleBridgeConfigV1Alpha1()\n//\talias: BridgeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/BridgeConfig\ntype BridgeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the bridge link (interface) to be created.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"Bridge.ext\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Override the hardware (MAC) address of the link.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f:]+$\n\tHardwareAddressConfig nethelpers.HardwareAddr `yaml:\"hardwareAddr,omitempty\"`\n\t//   description: |\n\t//     Names of the links (interfaces) to be aggregated.\n\t//     Link aliases can be used here as well.\n\t//   examples:\n\t//    - value: >\n\t//       []string{\"enp1s3\", \"enp1s2\"}\n\t//   schemaRequired: true\n\tBridgeLinks []string `yaml:\"links,omitempty\"`\n\t//   description: |\n\t//     Bridge STP (Spanning Tree Protocol) configuration.\n\tBridgeSTP BridgeSTPConfig `yaml:\"stp,omitempty\"`\n\t//   description: |\n\t//     Bridge VLAN configuration.\n\tBridgeVLAN BridgeVLANConfig `yaml:\"vlan,omitempty\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\ntype BridgeSTPConfig struct {\n\t//   description: |\n\t//     Enable or disable STP on the bridge.\n\t//\n\t//   examples:\n\t//    - value: true\n\tBridgeSTPEnabled *bool `yaml:\"enabled,omitempty\"`\n}\n\n// Enabled implements BridgeSTPConfig interface.\nfunc (s BridgeSTPConfig) Enabled() optional.Optional[bool] {\n\tif s.BridgeSTPEnabled == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.BridgeSTPEnabled)\n}\n\n// BridgeVLANConfig is a bridge VLAN configuration.\ntype BridgeVLANConfig struct {\n\t//   description: |\n\t//     Enable or disable VLAN filtering on the bridge.\n\t//\n\t//   examples:\n\t//    - value: true\n\tBridgeVLANFiltering *bool `yaml:\"filtering,omitempty\"`\n}\n\n// FilteringEnabled implements BridgeVLANConfig interface.\nfunc (s BridgeVLANConfig) FilteringEnabled() optional.Optional[bool] {\n\tif s.BridgeVLANFiltering == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.BridgeVLANFiltering)\n}\n\n// NewBridgeConfigV1Alpha1 creates a new BridgeConfig config document.\nfunc NewBridgeConfigV1Alpha1(name string) *BridgeConfigV1Alpha1 {\n\treturn &BridgeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       BridgeKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleBridgeConfigV1Alpha1() *BridgeConfigV1Alpha1 {\n\tcfg := NewBridgeConfigV1Alpha1(\"bridge.3\")\n\tcfg.BridgeLinks = []string{\"eno1\", \"eno2\"}\n\tcfg.BridgeSTP.BridgeSTPEnabled = new(true)\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *BridgeConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *BridgeConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// BridgeConfig implements NetworkBridgeConfig interface.\nfunc (s *BridgeConfigV1Alpha1) BridgeConfig() {}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *BridgeConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(BridgeKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *BridgeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\n// Links implements NetworkBridgeConfig interface.\nfunc (s *BridgeConfigV1Alpha1) Links() []string {\n\treturn s.BridgeLinks\n}\n\n// HardwareAddress implements NetworkDummyLinkConfig interface.\nfunc (s *BridgeConfigV1Alpha1) HardwareAddress() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.HardwareAddressConfig) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.HardwareAddressConfig)\n}\n\n// STP implements NetworkBridgeConfig interface.\nfunc (s *BridgeConfigV1Alpha1) STP() config.BridgeSTPConfig {\n\treturn s.BridgeSTP\n}\n\n// VLAN implements NetworkBridgeConfig interface.\nfunc (s *BridgeConfigV1Alpha1) VLAN() config.BridgeVLANConfig {\n\treturn s.BridgeVLAN\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/bridge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/bridgeconfig.yaml\nvar expectedBridgeConfigDocument []byte\n\nfunc TestBridgeConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewBridgeConfigV1Alpha1(\"bridge.1\")\n\tcfg.BridgeLinks = []string{\"eno1\", \"eno5\"}\n\tcfg.BridgeSTP.BridgeSTPEnabled = new(true)\n\tcfg.BridgeVLAN.BridgeVLANFiltering = new(false)\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.5/32\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedBridgeConfigDocument, marshaled)\n}\n\nfunc TestBridgeConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedBridgeConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.BridgeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.BridgeKind,\n\t\t},\n\t\tMetaName:    \"bridge.1\",\n\t\tBridgeLinks: []string{\"eno1\", \"eno5\"},\n\t\tBridgeSTP:   network.BridgeSTPConfig{BridgeSTPEnabled: new(true)},\n\t\tBridgeVLAN:  network.BridgeVLANConfig{BridgeVLANFiltering: new(false)},\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.5/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestBridgeValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.BridgeConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.BridgeConfigV1Alpha1 {\n\t\t\t\treturn network.NewBridgeConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"no links\",\n\n\t\t\tcfg: func() *network.BridgeConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBridgeConfigV1Alpha1(\"Bridge0\")\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.BridgeConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewBridgeConfigV1Alpha1(\"Bridge25\")\n\t\t\t\tcfg.BridgeLinks = []string{\"eth0\", \"eth1\"}\n\t\t\t\tcfg.BridgeSTP.BridgeSTPEnabled = new(true)\n\t\t\t\tcfg.BridgeVLAN.BridgeVLANFiltering = new(true)\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type BlackholeRouteConfigV1Alpha1 -type BondConfigV1Alpha1 -type BridgeConfigV1Alpha1 -type VRFConfigV1Alpha1 -type DefaultActionConfigV1Alpha1 -type DHCPv4ConfigV1Alpha1 -type DHCPv6ConfigV1Alpha1 -type DummyLinkConfigV1Alpha1 -type EthernetConfigV1Alpha1 -type HCloudVIPConfigV1Alpha1 -type HostnameConfigV1Alpha1 -type KubeSpanConfigV1Alpha1 -type KubespanEndpointsConfigV1Alpha1 -type Layer2VIPConfigV1Alpha1 -type LinkConfigV1Alpha1 -type LinkAliasConfigV1Alpha1 -type ResolverConfigV1Alpha1 -type RoutingRuleConfigV1Alpha1 -type RuleConfigV1Alpha1 -type StaticHostConfigV1Alpha1 -type TCPProbeConfigV1Alpha1 -type TimeSyncConfigV1Alpha1 -type VLANConfigV1Alpha1 -type WireguardConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DeepCopy generates a deep copy of *BlackholeRouteConfigV1Alpha1.\nfunc (o *BlackholeRouteConfigV1Alpha1) DeepCopy() *BlackholeRouteConfigV1Alpha1 {\n\tvar cp BlackholeRouteConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *BondConfigV1Alpha1.\nfunc (o *BondConfigV1Alpha1) DeepCopy() *BondConfigV1Alpha1 {\n\tvar cp BondConfigV1Alpha1 = *o\n\tif o.HardwareAddressConfig != nil {\n\t\tcp.HardwareAddressConfig = make([]byte, len(o.HardwareAddressConfig))\n\t\tcopy(cp.HardwareAddressConfig, o.HardwareAddressConfig)\n\t}\n\tif o.BondLinks != nil {\n\t\tcp.BondLinks = make([]string, len(o.BondLinks))\n\t\tcopy(cp.BondLinks, o.BondLinks)\n\t}\n\tif o.BondMode != nil {\n\t\tcp.BondMode = new(nethelpers.BondMode)\n\t\t*cp.BondMode = *o.BondMode\n\t}\n\tif o.BondMIIMon != nil {\n\t\tcp.BondMIIMon = new(uint32)\n\t\t*cp.BondMIIMon = *o.BondMIIMon\n\t}\n\tif o.BondUpDelay != nil {\n\t\tcp.BondUpDelay = new(uint32)\n\t\t*cp.BondUpDelay = *o.BondUpDelay\n\t}\n\tif o.BondDownDelay != nil {\n\t\tcp.BondDownDelay = new(uint32)\n\t\t*cp.BondDownDelay = *o.BondDownDelay\n\t}\n\tif o.BondUseCarrier != nil {\n\t\tcp.BondUseCarrier = new(bool)\n\t\t*cp.BondUseCarrier = *o.BondUseCarrier\n\t}\n\tif o.BondXmitHashPolicy != nil {\n\t\tcp.BondXmitHashPolicy = new(nethelpers.BondXmitHashPolicy)\n\t\t*cp.BondXmitHashPolicy = *o.BondXmitHashPolicy\n\t}\n\tif o.BondARPInterval != nil {\n\t\tcp.BondARPInterval = new(uint32)\n\t\t*cp.BondARPInterval = *o.BondARPInterval\n\t}\n\tif o.BondARPIPTargets != nil {\n\t\tcp.BondARPIPTargets = make([]netip.Addr, len(o.BondARPIPTargets))\n\t\tcopy(cp.BondARPIPTargets, o.BondARPIPTargets)\n\t}\n\tif o.BondNSIP6Targets != nil {\n\t\tcp.BondNSIP6Targets = make([]netip.Addr, len(o.BondNSIP6Targets))\n\t\tcopy(cp.BondNSIP6Targets, o.BondNSIP6Targets)\n\t}\n\tif o.BondARPValidate != nil {\n\t\tcp.BondARPValidate = new(nethelpers.ARPValidate)\n\t\t*cp.BondARPValidate = *o.BondARPValidate\n\t}\n\tif o.BondARPAllTargets != nil {\n\t\tcp.BondARPAllTargets = new(nethelpers.ARPAllTargets)\n\t\t*cp.BondARPAllTargets = *o.BondARPAllTargets\n\t}\n\tif o.BondLACPRate != nil {\n\t\tcp.BondLACPRate = new(nethelpers.LACPRate)\n\t\t*cp.BondLACPRate = *o.BondLACPRate\n\t}\n\tif o.BondFailOverMAC != nil {\n\t\tcp.BondFailOverMAC = new(nethelpers.FailOverMAC)\n\t\t*cp.BondFailOverMAC = *o.BondFailOverMAC\n\t}\n\tif o.BondADSelect != nil {\n\t\tcp.BondADSelect = new(nethelpers.ADSelect)\n\t\t*cp.BondADSelect = *o.BondADSelect\n\t}\n\tif o.BondADActorSysPrio != nil {\n\t\tcp.BondADActorSysPrio = new(uint16)\n\t\t*cp.BondADActorSysPrio = *o.BondADActorSysPrio\n\t}\n\tif o.BondADUserPortKey != nil {\n\t\tcp.BondADUserPortKey = new(uint16)\n\t\t*cp.BondADUserPortKey = *o.BondADUserPortKey\n\t}\n\tif o.BondADLACPActive != nil {\n\t\tcp.BondADLACPActive = new(nethelpers.ADLACPActive)\n\t\t*cp.BondADLACPActive = *o.BondADLACPActive\n\t}\n\tif o.BondPrimaryReselect != nil {\n\t\tcp.BondPrimaryReselect = new(nethelpers.PrimaryReselect)\n\t\t*cp.BondPrimaryReselect = *o.BondPrimaryReselect\n\t}\n\tif o.BondResendIGMP != nil {\n\t\tcp.BondResendIGMP = new(uint32)\n\t\t*cp.BondResendIGMP = *o.BondResendIGMP\n\t}\n\tif o.BondMinLinks != nil {\n\t\tcp.BondMinLinks = new(uint32)\n\t\t*cp.BondMinLinks = *o.BondMinLinks\n\t}\n\tif o.BondLPInterval != nil {\n\t\tcp.BondLPInterval = new(uint32)\n\t\t*cp.BondLPInterval = *o.BondLPInterval\n\t}\n\tif o.BondPacketsPerSlave != nil {\n\t\tcp.BondPacketsPerSlave = new(uint32)\n\t\t*cp.BondPacketsPerSlave = *o.BondPacketsPerSlave\n\t}\n\tif o.BondNumPeerNotif != nil {\n\t\tcp.BondNumPeerNotif = new(uint8)\n\t\t*cp.BondNumPeerNotif = *o.BondNumPeerNotif\n\t}\n\tif o.BondTLBDynamicLB != nil {\n\t\tcp.BondTLBDynamicLB = new(uint8)\n\t\t*cp.BondTLBDynamicLB = *o.BondTLBDynamicLB\n\t}\n\tif o.BondAllSlavesActive != nil {\n\t\tcp.BondAllSlavesActive = new(uint8)\n\t\t*cp.BondAllSlavesActive = *o.BondAllSlavesActive\n\t}\n\tif o.BondPeerNotifyDelay != nil {\n\t\tcp.BondPeerNotifyDelay = new(uint32)\n\t\t*cp.BondPeerNotifyDelay = *o.BondPeerNotifyDelay\n\t}\n\tif o.BondMissedMax != nil {\n\t\tcp.BondMissedMax = new(uint8)\n\t\t*cp.BondMissedMax = *o.BondMissedMax\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *BridgeConfigV1Alpha1.\nfunc (o *BridgeConfigV1Alpha1) DeepCopy() *BridgeConfigV1Alpha1 {\n\tvar cp BridgeConfigV1Alpha1 = *o\n\tif o.HardwareAddressConfig != nil {\n\t\tcp.HardwareAddressConfig = make([]byte, len(o.HardwareAddressConfig))\n\t\tcopy(cp.HardwareAddressConfig, o.HardwareAddressConfig)\n\t}\n\tif o.BridgeLinks != nil {\n\t\tcp.BridgeLinks = make([]string, len(o.BridgeLinks))\n\t\tcopy(cp.BridgeLinks, o.BridgeLinks)\n\t}\n\tif o.BridgeSTP.BridgeSTPEnabled != nil {\n\t\tcp.BridgeSTP.BridgeSTPEnabled = new(bool)\n\t\t*cp.BridgeSTP.BridgeSTPEnabled = *o.BridgeSTP.BridgeSTPEnabled\n\t}\n\tif o.BridgeVLAN.BridgeVLANFiltering != nil {\n\t\tcp.BridgeVLAN.BridgeVLANFiltering = new(bool)\n\t\t*cp.BridgeVLAN.BridgeVLANFiltering = *o.BridgeVLAN.BridgeVLANFiltering\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *VRFConfigV1Alpha1.\nfunc (o *VRFConfigV1Alpha1) DeepCopy() *VRFConfigV1Alpha1 {\n\tvar cp VRFConfigV1Alpha1 = *o\n\tif o.HardwareAddressConfig != nil {\n\t\tcp.HardwareAddressConfig = make([]byte, len(o.HardwareAddressConfig))\n\t\tcopy(cp.HardwareAddressConfig, o.HardwareAddressConfig)\n\t}\n\tif o.VRFLinks != nil {\n\t\tcp.VRFLinks = make([]string, len(o.VRFLinks))\n\t\tcopy(cp.VRFLinks, o.VRFLinks)\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *DefaultActionConfigV1Alpha1.\nfunc (o *DefaultActionConfigV1Alpha1) DeepCopy() *DefaultActionConfigV1Alpha1 {\n\tvar cp DefaultActionConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *DHCPv4ConfigV1Alpha1.\nfunc (o *DHCPv4ConfigV1Alpha1) DeepCopy() *DHCPv4ConfigV1Alpha1 {\n\tvar cp DHCPv4ConfigV1Alpha1 = *o\n\tif o.ConfigIgnoreHostname != nil {\n\t\tcp.ConfigIgnoreHostname = new(bool)\n\t\t*cp.ConfigIgnoreHostname = *o.ConfigIgnoreHostname\n\t}\n\tif o.ConfigClientIdentifier != nil {\n\t\tcp.ConfigClientIdentifier = new(nethelpers.ClientIdentifier)\n\t\t*cp.ConfigClientIdentifier = *o.ConfigClientIdentifier\n\t}\n\tif o.ConfigDUIDRaw != nil {\n\t\tcp.ConfigDUIDRaw = make([]byte, len(o.ConfigDUIDRaw))\n\t\tcopy(cp.ConfigDUIDRaw, o.ConfigDUIDRaw)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *DHCPv6ConfigV1Alpha1.\nfunc (o *DHCPv6ConfigV1Alpha1) DeepCopy() *DHCPv6ConfigV1Alpha1 {\n\tvar cp DHCPv6ConfigV1Alpha1 = *o\n\tif o.ConfigIgnoreHostname != nil {\n\t\tcp.ConfigIgnoreHostname = new(bool)\n\t\t*cp.ConfigIgnoreHostname = *o.ConfigIgnoreHostname\n\t}\n\tif o.ConfigClientIdentifier != nil {\n\t\tcp.ConfigClientIdentifier = new(nethelpers.ClientIdentifier)\n\t\t*cp.ConfigClientIdentifier = *o.ConfigClientIdentifier\n\t}\n\tif o.ConfigDUIDRaw != nil {\n\t\tcp.ConfigDUIDRaw = make([]byte, len(o.ConfigDUIDRaw))\n\t\tcopy(cp.ConfigDUIDRaw, o.ConfigDUIDRaw)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *DummyLinkConfigV1Alpha1.\nfunc (o *DummyLinkConfigV1Alpha1) DeepCopy() *DummyLinkConfigV1Alpha1 {\n\tvar cp DummyLinkConfigV1Alpha1 = *o\n\tif o.HardwareAddressConfig != nil {\n\t\tcp.HardwareAddressConfig = make([]byte, len(o.HardwareAddressConfig))\n\t\tcopy(cp.HardwareAddressConfig, o.HardwareAddressConfig)\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *EthernetConfigV1Alpha1.\nfunc (o *EthernetConfigV1Alpha1) DeepCopy() *EthernetConfigV1Alpha1 {\n\tvar cp EthernetConfigV1Alpha1 = *o\n\tif o.FeaturesConfig != nil {\n\t\tcp.FeaturesConfig = make(map[string]bool, len(o.FeaturesConfig))\n\t\tfor k2, v2 := range o.FeaturesConfig {\n\t\t\tcp.FeaturesConfig[k2] = v2\n\t\t}\n\t}\n\tif o.RingsConfig != nil {\n\t\tcp.RingsConfig = new(EthernetRingsConfig)\n\t\t*cp.RingsConfig = *o.RingsConfig\n\t\tif o.RingsConfig.RX != nil {\n\t\t\tcp.RingsConfig.RX = new(uint32)\n\t\t\t*cp.RingsConfig.RX = *o.RingsConfig.RX\n\t\t}\n\t\tif o.RingsConfig.TX != nil {\n\t\t\tcp.RingsConfig.TX = new(uint32)\n\t\t\t*cp.RingsConfig.TX = *o.RingsConfig.TX\n\t\t}\n\t\tif o.RingsConfig.RXMini != nil {\n\t\t\tcp.RingsConfig.RXMini = new(uint32)\n\t\t\t*cp.RingsConfig.RXMini = *o.RingsConfig.RXMini\n\t\t}\n\t\tif o.RingsConfig.RXJumbo != nil {\n\t\t\tcp.RingsConfig.RXJumbo = new(uint32)\n\t\t\t*cp.RingsConfig.RXJumbo = *o.RingsConfig.RXJumbo\n\t\t}\n\t\tif o.RingsConfig.RXBufLen != nil {\n\t\t\tcp.RingsConfig.RXBufLen = new(uint32)\n\t\t\t*cp.RingsConfig.RXBufLen = *o.RingsConfig.RXBufLen\n\t\t}\n\t\tif o.RingsConfig.CQESize != nil {\n\t\t\tcp.RingsConfig.CQESize = new(uint32)\n\t\t\t*cp.RingsConfig.CQESize = *o.RingsConfig.CQESize\n\t\t}\n\t\tif o.RingsConfig.TXPush != nil {\n\t\t\tcp.RingsConfig.TXPush = new(bool)\n\t\t\t*cp.RingsConfig.TXPush = *o.RingsConfig.TXPush\n\t\t}\n\t\tif o.RingsConfig.RXPush != nil {\n\t\t\tcp.RingsConfig.RXPush = new(bool)\n\t\t\t*cp.RingsConfig.RXPush = *o.RingsConfig.RXPush\n\t\t}\n\t\tif o.RingsConfig.TXPushBufLen != nil {\n\t\t\tcp.RingsConfig.TXPushBufLen = new(uint32)\n\t\t\t*cp.RingsConfig.TXPushBufLen = *o.RingsConfig.TXPushBufLen\n\t\t}\n\t\tif o.RingsConfig.TCPDataSplit != nil {\n\t\t\tcp.RingsConfig.TCPDataSplit = new(bool)\n\t\t\t*cp.RingsConfig.TCPDataSplit = *o.RingsConfig.TCPDataSplit\n\t\t}\n\t}\n\tif o.ChannelsConfig != nil {\n\t\tcp.ChannelsConfig = new(EthernetChannelsConfig)\n\t\t*cp.ChannelsConfig = *o.ChannelsConfig\n\t\tif o.ChannelsConfig.RX != nil {\n\t\t\tcp.ChannelsConfig.RX = new(uint32)\n\t\t\t*cp.ChannelsConfig.RX = *o.ChannelsConfig.RX\n\t\t}\n\t\tif o.ChannelsConfig.TX != nil {\n\t\t\tcp.ChannelsConfig.TX = new(uint32)\n\t\t\t*cp.ChannelsConfig.TX = *o.ChannelsConfig.TX\n\t\t}\n\t\tif o.ChannelsConfig.Other != nil {\n\t\t\tcp.ChannelsConfig.Other = new(uint32)\n\t\t\t*cp.ChannelsConfig.Other = *o.ChannelsConfig.Other\n\t\t}\n\t\tif o.ChannelsConfig.Combined != nil {\n\t\t\tcp.ChannelsConfig.Combined = new(uint32)\n\t\t\t*cp.ChannelsConfig.Combined = *o.ChannelsConfig.Combined\n\t\t}\n\t}\n\tif o.WakeOnLANConfig != nil {\n\t\tcp.WakeOnLANConfig = make([]nethelpers.WOLMode, len(o.WakeOnLANConfig))\n\t\tcopy(cp.WakeOnLANConfig, o.WakeOnLANConfig)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *HCloudVIPConfigV1Alpha1.\nfunc (o *HCloudVIPConfigV1Alpha1) DeepCopy() *HCloudVIPConfigV1Alpha1 {\n\tvar cp HCloudVIPConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *HostnameConfigV1Alpha1.\nfunc (o *HostnameConfigV1Alpha1) DeepCopy() *HostnameConfigV1Alpha1 {\n\tvar cp HostnameConfigV1Alpha1 = *o\n\tif o.ConfigAuto != nil {\n\t\tcp.ConfigAuto = new(nethelpers.AutoHostnameKind)\n\t\t*cp.ConfigAuto = *o.ConfigAuto\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *KubeSpanConfigV1Alpha1.\nfunc (o *KubeSpanConfigV1Alpha1) DeepCopy() *KubeSpanConfigV1Alpha1 {\n\tvar cp KubeSpanConfigV1Alpha1 = *o\n\tif o.ConfigEnabled != nil {\n\t\tcp.ConfigEnabled = new(bool)\n\t\t*cp.ConfigEnabled = *o.ConfigEnabled\n\t}\n\tif o.ConfigAdvertiseKubernetesNetworks != nil {\n\t\tcp.ConfigAdvertiseKubernetesNetworks = new(bool)\n\t\t*cp.ConfigAdvertiseKubernetesNetworks = *o.ConfigAdvertiseKubernetesNetworks\n\t}\n\tif o.ConfigAllowDownPeerBypass != nil {\n\t\tcp.ConfigAllowDownPeerBypass = new(bool)\n\t\t*cp.ConfigAllowDownPeerBypass = *o.ConfigAllowDownPeerBypass\n\t}\n\tif o.ConfigHarvestExtraEndpoints != nil {\n\t\tcp.ConfigHarvestExtraEndpoints = new(bool)\n\t\t*cp.ConfigHarvestExtraEndpoints = *o.ConfigHarvestExtraEndpoints\n\t}\n\tif o.ConfigMTU != nil {\n\t\tcp.ConfigMTU = new(uint32)\n\t\t*cp.ConfigMTU = *o.ConfigMTU\n\t}\n\tif o.ConfigFilters != nil {\n\t\tcp.ConfigFilters = new(KubeSpanFiltersConfig)\n\t\t*cp.ConfigFilters = *o.ConfigFilters\n\t\tif o.ConfigFilters.ConfigEndpoints != nil {\n\t\t\tcp.ConfigFilters.ConfigEndpoints = make([]string, len(o.ConfigFilters.ConfigEndpoints))\n\t\t\tcopy(cp.ConfigFilters.ConfigEndpoints, o.ConfigFilters.ConfigEndpoints)\n\t\t}\n\t\tif o.ConfigFilters.ConfigExcludeAdvertisedNetworks != nil {\n\t\t\tcp.ConfigFilters.ConfigExcludeAdvertisedNetworks = make([]Prefix, len(o.ConfigFilters.ConfigExcludeAdvertisedNetworks))\n\t\t\tcopy(cp.ConfigFilters.ConfigExcludeAdvertisedNetworks, o.ConfigFilters.ConfigExcludeAdvertisedNetworks)\n\t\t}\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *KubespanEndpointsConfigV1Alpha1.\nfunc (o *KubespanEndpointsConfigV1Alpha1) DeepCopy() *KubespanEndpointsConfigV1Alpha1 {\n\tvar cp KubespanEndpointsConfigV1Alpha1 = *o\n\tif o.ExtraAnnouncedEndpointsConfig != nil {\n\t\tcp.ExtraAnnouncedEndpointsConfig = make([]netip.AddrPort, len(o.ExtraAnnouncedEndpointsConfig))\n\t\tcopy(cp.ExtraAnnouncedEndpointsConfig, o.ExtraAnnouncedEndpointsConfig)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *Layer2VIPConfigV1Alpha1.\nfunc (o *Layer2VIPConfigV1Alpha1) DeepCopy() *Layer2VIPConfigV1Alpha1 {\n\tvar cp Layer2VIPConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *LinkConfigV1Alpha1.\nfunc (o *LinkConfigV1Alpha1) DeepCopy() *LinkConfigV1Alpha1 {\n\tvar cp LinkConfigV1Alpha1 = *o\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *LinkAliasConfigV1Alpha1.\nfunc (o *LinkAliasConfigV1Alpha1) DeepCopy() *LinkAliasConfigV1Alpha1 {\n\tvar cp LinkAliasConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *ResolverConfigV1Alpha1.\nfunc (o *ResolverConfigV1Alpha1) DeepCopy() *ResolverConfigV1Alpha1 {\n\tvar cp ResolverConfigV1Alpha1 = *o\n\tif o.ResolverNameservers != nil {\n\t\tcp.ResolverNameservers = make([]NameserverConfig, len(o.ResolverNameservers))\n\t\tcopy(cp.ResolverNameservers, o.ResolverNameservers)\n\t}\n\tif o.ResolverSearchDomains.SearchDomains != nil {\n\t\tcp.ResolverSearchDomains.SearchDomains = make([]string, len(o.ResolverSearchDomains.SearchDomains))\n\t\tcopy(cp.ResolverSearchDomains.SearchDomains, o.ResolverSearchDomains.SearchDomains)\n\t}\n\tif o.ResolverSearchDomains.SearchDisableDefault != nil {\n\t\tcp.ResolverSearchDomains.SearchDisableDefault = new(bool)\n\t\t*cp.ResolverSearchDomains.SearchDisableDefault = *o.ResolverSearchDomains.SearchDisableDefault\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *RoutingRuleConfigV1Alpha1.\nfunc (o *RoutingRuleConfigV1Alpha1) DeepCopy() *RoutingRuleConfigV1Alpha1 {\n\tvar cp RoutingRuleConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *RuleConfigV1Alpha1.\nfunc (o *RuleConfigV1Alpha1) DeepCopy() *RuleConfigV1Alpha1 {\n\tvar cp RuleConfigV1Alpha1 = *o\n\tif o.PortSelector.Ports != nil {\n\t\tcp.PortSelector.Ports = make([]PortRange, len(o.PortSelector.Ports))\n\t\tcopy(cp.PortSelector.Ports, o.PortSelector.Ports)\n\t}\n\tif o.Ingress != nil {\n\t\tcp.Ingress = make([]IngressRule, len(o.Ingress))\n\t\tcopy(cp.Ingress, o.Ingress)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *StaticHostConfigV1Alpha1.\nfunc (o *StaticHostConfigV1Alpha1) DeepCopy() *StaticHostConfigV1Alpha1 {\n\tvar cp StaticHostConfigV1Alpha1 = *o\n\tif o.Hostnames != nil {\n\t\tcp.Hostnames = make([]string, len(o.Hostnames))\n\t\tcopy(cp.Hostnames, o.Hostnames)\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *TCPProbeConfigV1Alpha1.\nfunc (o *TCPProbeConfigV1Alpha1) DeepCopy() *TCPProbeConfigV1Alpha1 {\n\tvar cp TCPProbeConfigV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *TimeSyncConfigV1Alpha1.\nfunc (o *TimeSyncConfigV1Alpha1) DeepCopy() *TimeSyncConfigV1Alpha1 {\n\tvar cp TimeSyncConfigV1Alpha1 = *o\n\tif o.TimeEnabled != nil {\n\t\tcp.TimeEnabled = new(bool)\n\t\t*cp.TimeEnabled = *o.TimeEnabled\n\t}\n\tif o.TimeNTP != nil {\n\t\tcp.TimeNTP = new(NTPConfig)\n\t\t*cp.TimeNTP = *o.TimeNTP\n\t\tif o.TimeNTP.Servers != nil {\n\t\t\tcp.TimeNTP.Servers = make([]string, len(o.TimeNTP.Servers))\n\t\t\tcopy(cp.TimeNTP.Servers, o.TimeNTP.Servers)\n\t\t}\n\t}\n\tif o.TimePTP != nil {\n\t\tcp.TimePTP = new(PTPConfig)\n\t\t*cp.TimePTP = *o.TimePTP\n\t\tif o.TimePTP.Devices != nil {\n\t\t\tcp.TimePTP.Devices = make([]string, len(o.TimePTP.Devices))\n\t\t\tcopy(cp.TimePTP.Devices, o.TimePTP.Devices)\n\t\t}\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *VLANConfigV1Alpha1.\nfunc (o *VLANConfigV1Alpha1) DeepCopy() *VLANConfigV1Alpha1 {\n\tvar cp VLANConfigV1Alpha1 = *o\n\tif o.VLANModeConfig != nil {\n\t\tcp.VLANModeConfig = new(nethelpers.VLANProtocol)\n\t\t*cp.VLANModeConfig = *o.VLANModeConfig\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *WireguardConfigV1Alpha1.\nfunc (o *WireguardConfigV1Alpha1) DeepCopy() *WireguardConfigV1Alpha1 {\n\tvar cp WireguardConfigV1Alpha1 = *o\n\tif o.WireguardPeers != nil {\n\t\tcp.WireguardPeers = make([]WireguardPeer, len(o.WireguardPeers))\n\t\tcopy(cp.WireguardPeers, o.WireguardPeers)\n\t\tfor i2 := range o.WireguardPeers {\n\t\t\tif o.WireguardPeers[i2].WireguardAllowedIPs != nil {\n\t\t\t\tcp.WireguardPeers[i2].WireguardAllowedIPs = make([]Prefix, len(o.WireguardPeers[i2].WireguardAllowedIPs))\n\t\t\t\tcopy(cp.WireguardPeers[i2].WireguardAllowedIPs, o.WireguardPeers[i2].WireguardAllowedIPs)\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkUp != nil {\n\t\tcp.CommonLinkConfig.LinkUp = new(bool)\n\t\t*cp.CommonLinkConfig.LinkUp = *o.CommonLinkConfig.LinkUp\n\t}\n\tif o.CommonLinkConfig.LinkAddresses != nil {\n\t\tcp.CommonLinkConfig.LinkAddresses = make([]AddressConfig, len(o.CommonLinkConfig.LinkAddresses))\n\t\tcopy(cp.CommonLinkConfig.LinkAddresses, o.CommonLinkConfig.LinkAddresses)\n\t\tfor i3 := range o.CommonLinkConfig.LinkAddresses {\n\t\t\tif o.CommonLinkConfig.LinkAddresses[i3].AddressPriority != nil {\n\t\t\t\tcp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = new(uint32)\n\t\t\t\t*cp.CommonLinkConfig.LinkAddresses[i3].AddressPriority = *o.CommonLinkConfig.LinkAddresses[i3].AddressPriority\n\t\t\t}\n\t\t}\n\t}\n\tif o.CommonLinkConfig.LinkRoutes != nil {\n\t\tcp.CommonLinkConfig.LinkRoutes = make([]RouteConfig, len(o.CommonLinkConfig.LinkRoutes))\n\t\tcopy(cp.CommonLinkConfig.LinkRoutes, o.CommonLinkConfig.LinkRoutes)\n\t}\n\tif o.CommonLinkConfig.LinkMulticast != nil {\n\t\tcp.CommonLinkConfig.LinkMulticast = new(bool)\n\t\t*cp.CommonLinkConfig.LinkMulticast = *o.CommonLinkConfig.LinkMulticast\n\t}\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/default_action_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DefaultActionConfig is a default action config document kind.\nconst DefaultActionConfig = \"NetworkDefaultActionConfig\"\n\nfunc init() {\n\tregistry.Register(DefaultActionConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &DefaultActionConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkRuleConfigDefaultAction = &DefaultActionConfigV1Alpha1{}\n\t_ config.NetworkRuleConfigSignal        = &DefaultActionConfigV1Alpha1{}\n)\n\n// DefaultActionConfigV1Alpha1 is a ingress firewall default action configuration document.\n//\n//\texamples:\n//\t  - value: exampleDefaultActionConfigV1Alpha1()\n//\talias: NetworkDefaultActionConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/NetworkDefaultActionConfig\ntype DefaultActionConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Default action for all not explicitly configured ingress traffic: accept or block.\n\t//   values:\n\t//     - \"accept\"\n\t//     - \"block\"\n\tIngress nethelpers.DefaultAction `yaml:\"ingress\"`\n}\n\n// NewDefaultActionConfigV1Alpha1 creates a new DefaultActionConfig config document.\nfunc NewDefaultActionConfigV1Alpha1() *DefaultActionConfigV1Alpha1 {\n\treturn &DefaultActionConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       DefaultActionConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleDefaultActionConfigV1Alpha1() *DefaultActionConfigV1Alpha1 {\n\tcfg := NewDefaultActionConfigV1Alpha1()\n\tcfg.Ingress = nethelpers.DefaultActionAccept\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *DefaultActionConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// NetworkRuleConfigSignal implements config.NetworkRuleConfigSignal interface.\nfunc (s *DefaultActionConfigV1Alpha1) NetworkRuleConfigSignal() {}\n\n// DefaultAction implements config.NetworkRuleConfigDefaultAction interface.\nfunc (s *DefaultActionConfigV1Alpha1) DefaultAction() nethelpers.DefaultAction {\n\treturn s.Ingress\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/default_action_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/defaultactionconfig.yaml\nvar expectedDefaultActionConfigDocument []byte\n\nfunc TestDefaultActionConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewDefaultActionConfigV1Alpha1()\n\tcfg.Ingress = nethelpers.DefaultActionBlock\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedDefaultActionConfigDocument, marshaled)\n}\n\nfunc TestDefaultActionConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedDefaultActionConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.DefaultActionConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.DefaultActionConfig,\n\t\t},\n\t\tIngress: nethelpers.DefaultActionBlock,\n\t}, docs[0])\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dhcp4.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DHCPv4Kind is a DHCPv4 config document kind.\nconst DHCPv4Kind = \"DHCPv4Config\"\n\nfunc init() {\n\tregistry.Register(DHCPv4Kind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &DHCPv4ConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkDHCPv4Config = &DHCPv4ConfigV1Alpha1{}\n\t_ config.NamedDocument       = &DHCPv4ConfigV1Alpha1{}\n\t_ config.Validator           = &DHCPv4ConfigV1Alpha1{}\n)\n\n// DHCPv4ConfigV1Alpha1 is a config document to configure DHCPv4 on a network link.\n//\n//\texamples:\n//\t  - value: exampleDHCPv4ConfigV1Alpha1()\n//\talias: DHCPv4Config\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/DHCPv4Config\ntype DHCPv4ConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the link (interface).\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"enp0s2\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     An optional metric for the routes received from the DHCP server.\n\t//\n\t//     Lower values indicate higher priority.\n\t//     Default value is 1024.\n\tConfigRouteMetric uint32 `yaml:\"routeMetric,omitempty\"`\n\t//   description: |\n\t//     Ignore hostname received from the DHCP server.\n\tConfigIgnoreHostname *bool `yaml:\"ignoreHostname,omitempty\"`\n\t//   description: |\n\t//     Client identifier to use when communicating with DHCP servers.\n\t//\n\t//     Defaults to 'mac' if not set.\n\t//   values:\n\t//     - \"none\"\n\t//     - \"mac\"\n\t//     - \"duid\"\n\tConfigClientIdentifier *nethelpers.ClientIdentifier `yaml:\"clientIdentifier,omitempty\"`\n\t//   description: |\n\t//     Raw value of the DUID to use as client identifier.\n\t//\n\t//     This field is only used if 'clientIdentifier' is set to 'duid'.\n\t//   examples:\n\t//    - value: >\n\t//       \"00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\"\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\n\tConfigDUIDRaw nethelpers.HardwareAddr `yaml:\"duidRaw,omitempty\"`\n}\n\n// NewDHCPv4ConfigV1Alpha1 creates a new DHCPv4Config config document.\nfunc NewDHCPv4ConfigV1Alpha1(name string) *DHCPv4ConfigV1Alpha1 {\n\treturn &DHCPv4ConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       DHCPv4Kind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleDHCPv4ConfigV1Alpha1() *DHCPv4ConfigV1Alpha1 {\n\tcfg := NewDHCPv4ConfigV1Alpha1(\"enp0s2\")\n\tcfg.ConfigClientIdentifier = new(nethelpers.ClientIdentifierMAC)\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *DHCPv4ConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *DHCPv4ConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// NetworkDHCPConfig implements config.NetworkDHCPConfig interface.\nfunc (s *DHCPv4ConfigV1Alpha1) NetworkDHCPConfig() {}\n\n// NetworkDHCPv4Config implements config.NetworkDHCPv4Config interface.\nfunc (s *DHCPv4ConfigV1Alpha1) NetworkDHCPv4Config() {}\n\n// RouteMetric returns the route metric.\nfunc (s *DHCPv4ConfigV1Alpha1) RouteMetric() optional.Optional[uint32] {\n\tif s.ConfigRouteMetric == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(s.ConfigRouteMetric)\n}\n\n// IgnoreHostname returns whether to ignore hostname from DHCP server.\nfunc (s *DHCPv4ConfigV1Alpha1) IgnoreHostname() optional.Optional[bool] {\n\tif s.ConfigIgnoreHostname == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.ConfigIgnoreHostname)\n}\n\n// ClientIdentifier returns the client identifier.\nfunc (s *DHCPv4ConfigV1Alpha1) ClientIdentifier() nethelpers.ClientIdentifier {\n\tif s.ConfigClientIdentifier == nil {\n\t\treturn nethelpers.ClientIdentifierMAC\n\t}\n\n\treturn *s.ConfigClientIdentifier\n}\n\n// DUIDRaw returns the DUID raw value.\nfunc (s *DHCPv4ConfigV1Alpha1) DUIDRaw() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.ConfigDUIDRaw) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.ConfigDUIDRaw)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *DHCPv4ConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif len(s.ConfigDUIDRaw) > 0 && pointer.SafeDeref(s.ConfigClientIdentifier) != nethelpers.ClientIdentifierDUID {\n\t\terrs = errors.Join(errs, errors.New(\"duidRaw can only be set if clientIdentifier is 'duid'\"))\n\t}\n\n\tif pointer.SafeDeref(s.ConfigClientIdentifier) == nethelpers.ClientIdentifierDUID && len(s.ConfigDUIDRaw) == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"duidRaw must be set if clientIdentifier is 'duid'\"))\n\t}\n\n\treturn warnings, errs\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dhcp4_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/dhcpv4config.yaml\nvar expectedDHCPv4ConfigDocument []byte\n\nfunc TestDHCPv4ConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewDHCPv4ConfigV1Alpha1(\"enp0s3\")\n\tcfg.ConfigRouteMetric = 512\n\tcfg.ConfigIgnoreHostname = new(true)\n\tcfg.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\tcfg.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedDHCPv4ConfigDocument, marshaled)\n}\n\nfunc TestDHCPv4ConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedDHCPv4ConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.DHCPv4ConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.DHCPv4Kind,\n\t\t},\n\t\tMetaName:               \"enp0s3\",\n\t\tConfigRouteMetric:      512,\n\t\tConfigIgnoreHostname:   new(true),\n\t\tConfigClientIdentifier: new(nethelpers.ClientIdentifierDUID),\n\t\tConfigDUIDRaw:          nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45},\n\t}, docs[0])\n}\n\nfunc TestDHCPv4ConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname             string\n\t\tcfg              func() *network.DHCPv4ConfigV1Alpha1\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"valid config with duidRaw\",\n\t\t\tcfg: func() *network.DHCPv4ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv4ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\t\t\t\tc.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid config missing duidRaw\",\n\t\t\tcfg: func() *network.DHCPv4ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv4ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"duidRaw must be set if clientIdentifier is 'duid'\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid config duidRaw set without duid client identifier\",\n\t\t\tcfg: func() *network.DHCPv4ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv4ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"duidRaw can only be set if clientIdentifier is 'duid'\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.DHCPv4ConfigV1Alpha1 {\n\t\t\t\treturn network.NewDHCPv4ConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dhcp6.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DHCPv6Kind is a DHCPv6 config document kind.\nconst DHCPv6Kind = \"DHCPv6Config\"\n\nfunc init() {\n\tregistry.Register(DHCPv6Kind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &DHCPv6ConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkDHCPv6Config = &DHCPv6ConfigV1Alpha1{}\n\t_ config.NamedDocument       = &DHCPv6ConfigV1Alpha1{}\n\t_ config.Validator           = &DHCPv6ConfigV1Alpha1{}\n)\n\n// DHCPv6ConfigV1Alpha1 is a config document to configure DHCPv6 on a network link.\n//\n//\texamples:\n//\t  - value: exampleDHCPv6ConfigV1Alpha1()\n//\talias: DHCPv6Config\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/DHCPv6Config\ntype DHCPv6ConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the link (interface).\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"enp0s2\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     An optional metric for the routes received from the DHCP server.\n\t//\n\t//     Lower values indicate higher priority.\n\t//     Default value is 1024.\n\tConfigRouteMetric uint32 `yaml:\"routeMetric,omitempty\"`\n\t//   description: |\n\t//     Ignore hostname received from the DHCP server.\n\tConfigIgnoreHostname *bool `yaml:\"ignoreHostname,omitempty\"`\n\t//   description: |\n\t//     Client identifier to use when communicating with DHCP servers.\n\t//\n\t//     Defaults to 'mac' if not set.\n\t//   values:\n\t//     - \"none\"\n\t//     - \"mac\"\n\t//     - \"duid\"\n\tConfigClientIdentifier *nethelpers.ClientIdentifier `yaml:\"clientIdentifier,omitempty\"`\n\t//   description: |\n\t//     Raw value of the DUID to use as client identifier.\n\t//\n\t//     This field is only used if 'clientIdentifier' is set to 'duid'.\n\t//   examples:\n\t//    - value: >\n\t//       \"00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\"\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\n\tConfigDUIDRaw nethelpers.HardwareAddr `yaml:\"duidRaw,omitempty\"`\n}\n\n// NewDHCPv6ConfigV1Alpha1 creates a new DHCPv6Config config document.\nfunc NewDHCPv6ConfigV1Alpha1(name string) *DHCPv6ConfigV1Alpha1 {\n\treturn &DHCPv6ConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       DHCPv6Kind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleDHCPv6ConfigV1Alpha1() *DHCPv6ConfigV1Alpha1 {\n\tcfg := NewDHCPv6ConfigV1Alpha1(\"enp0s2\")\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *DHCPv6ConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *DHCPv6ConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// NetworkDHCPConfig implements config.NetworkDHCPConfig interface.\nfunc (s *DHCPv6ConfigV1Alpha1) NetworkDHCPConfig() {}\n\n// NetworkDHCPv6Config implements config.NetworkDHCPv6Config interface.\nfunc (s *DHCPv6ConfigV1Alpha1) NetworkDHCPv6Config() {}\n\n// RouteMetric returns the route metric.\nfunc (s *DHCPv6ConfigV1Alpha1) RouteMetric() optional.Optional[uint32] {\n\tif s.ConfigRouteMetric == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(s.ConfigRouteMetric)\n}\n\n// IgnoreHostname returns whether to ignore hostname from DHCP server.\nfunc (s *DHCPv6ConfigV1Alpha1) IgnoreHostname() optional.Optional[bool] {\n\tif s.ConfigIgnoreHostname == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.ConfigIgnoreHostname)\n}\n\n// ClientIdentifier returns the client identifier.\nfunc (s *DHCPv6ConfigV1Alpha1) ClientIdentifier() nethelpers.ClientIdentifier {\n\tif s.ConfigClientIdentifier == nil {\n\t\treturn nethelpers.ClientIdentifierMAC\n\t}\n\n\treturn *s.ConfigClientIdentifier\n}\n\n// DUIDRaw returns the DUID raw value.\nfunc (s *DHCPv6ConfigV1Alpha1) DUIDRaw() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.ConfigDUIDRaw) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.ConfigDUIDRaw)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *DHCPv6ConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif len(s.ConfigDUIDRaw) > 0 && pointer.SafeDeref(s.ConfigClientIdentifier) != nethelpers.ClientIdentifierDUID {\n\t\terrs = errors.Join(errs, errors.New(\"duidRaw can only be set if clientIdentifier is 'duid'\"))\n\t}\n\n\tif pointer.SafeDeref(s.ConfigClientIdentifier) == nethelpers.ClientIdentifierDUID && len(s.ConfigDUIDRaw) == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"duidRaw must be set if clientIdentifier is 'duid'\"))\n\t}\n\n\treturn warnings, errs\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dhcp6_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/dhcpv6config.yaml\nvar expectedDHCPv6ConfigDocument []byte\n\nfunc TestDHCPv6ConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewDHCPv6ConfigV1Alpha1(\"enp0s3\")\n\tcfg.ConfigClientIdentifier = new(nethelpers.ClientIdentifierMAC)\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedDHCPv6ConfigDocument, marshaled)\n}\n\nfunc TestDHCPv6ConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedDHCPv6ConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.DHCPv6ConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.DHCPv6Kind,\n\t\t},\n\t\tMetaName:               \"enp0s3\",\n\t\tConfigClientIdentifier: new(nethelpers.ClientIdentifierMAC),\n\t}, docs[0])\n}\n\nfunc TestDHCPv6ConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname             string\n\t\tcfg              func() *network.DHCPv6ConfigV1Alpha1\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"valid config with duidRaw\",\n\t\t\tcfg: func() *network.DHCPv6ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv6ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\t\t\t\tc.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid config missing duidRaw\",\n\t\t\tcfg: func() *network.DHCPv6ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv6ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigClientIdentifier = new(nethelpers.ClientIdentifierDUID)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"duidRaw must be set if clientIdentifier is 'duid'\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid config duidRaw set without duid client identifier\",\n\t\t\tcfg: func() *network.DHCPv6ConfigV1Alpha1 {\n\t\t\t\tc := network.NewDHCPv6ConfigV1Alpha1(\"enp0s3\")\n\t\t\t\tc.ConfigDUIDRaw = nethelpers.HardwareAddr{0x00, 0x01, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"duidRaw can only be set if clientIdentifier is 'duid'\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.DHCPv6ConfigV1Alpha1 {\n\t\t\t\treturn network.NewDHCPv6ConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dummy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DummyLinkKind is a DummyLink config document kind.\nconst DummyLinkKind = \"DummyLinkConfig\"\n\nfunc init() {\n\tregistry.Register(DummyLinkKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &DummyLinkConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkDummyLinkConfig = &DummyLinkConfigV1Alpha1{}\n\t_ config.ConflictingDocument    = &DummyLinkConfigV1Alpha1{}\n\t_ config.NamedDocument          = &DummyLinkConfigV1Alpha1{}\n\t_ config.Validator              = &DummyLinkConfigV1Alpha1{}\n)\n\n// DummyLinkConfigV1Alpha1 is a config document to create a dummy (virtual) network link.\n//\n//\texamples:\n//\t  - value: exampleDummyLinkConfigV1Alpha1()\n//\talias: DummyLinkConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/DummyLinkConfig\ntype DummyLinkConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the dummy link (interface).\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"dummy1\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Override the hardware (MAC) address of the link.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f:]+$\n\tHardwareAddressConfig nethelpers.HardwareAddr `yaml:\"hardwareAddr,omitempty\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// NewDummyLinkConfigV1Alpha1 creates a new DummyLinkConfig config document.\nfunc NewDummyLinkConfigV1Alpha1(name string) *DummyLinkConfigV1Alpha1 {\n\treturn &DummyLinkConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       DummyLinkKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleDummyLinkConfigV1Alpha1() *DummyLinkConfigV1Alpha1 {\n\tcfg := NewDummyLinkConfigV1Alpha1(\"dummy1\")\n\tcfg.LinkAddresses = []AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *DummyLinkConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *DummyLinkConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// DummyLinkConfig implements NetworkDummyLinkConfig interface.\nfunc (s *DummyLinkConfigV1Alpha1) DummyLinkConfig() {}\n\n// HardwareAddress implements NetworkDummyLinkConfig interface.\nfunc (s *DummyLinkConfigV1Alpha1) HardwareAddress() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.HardwareAddressConfig) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.HardwareAddressConfig)\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *DummyLinkConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(DummyLinkKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *DummyLinkConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/dummy_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/dummylinkconfig.yaml\nvar expectedDummyLinkConfigDocument []byte\n\nfunc TestDummyLinkConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewDummyLinkConfigV1Alpha1(\"dummy1\")\n\tcfg.HardwareAddressConfig = nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70}\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedDummyLinkConfigDocument, marshaled)\n}\n\nfunc TestDummyLinkConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedDummyLinkConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.DummyLinkConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.DummyLinkKind,\n\t\t},\n\t\tMetaName:              \"dummy1\",\n\t\tHardwareAddressConfig: nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70},\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/ethernet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// EthernetKind is a Ethernet config document kind.\nconst EthernetKind = \"EthernetConfig\"\n\nfunc init() {\n\tregistry.Register(EthernetKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &EthernetConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.EthernetConfig = &EthernetConfigV1Alpha1{}\n\t_ config.NamedDocument  = &EthernetConfigV1Alpha1{}\n\t_ config.Validator      = &EthernetConfigV1Alpha1{}\n)\n\n// EthernetConfigV1Alpha1 is a config document to configure Ethernet interfaces.\n//\n//\texamples:\n//\t  - value: exampleEthernetConfigV1Alpha1()\n//\talias: EthernetConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/EthernetConfig\ntype EthernetConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the link (interface).\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Configuration for Ethernet features.\n\t//\n\t//     Set of features available and whether they can be enabled or disabled is driver specific.\n\t//     Use `talosctl get ethernetstatus <link> -o yaml` to get the list of available features and\n\t//     their current status.\n\tFeaturesConfig map[string]bool `yaml:\"features,omitempty\"`\n\t//   description: |\n\t//     Configuration for Ethernet link rings.\n\t//\n\t//     This is similar to `ethtool -G` command.\n\tRingsConfig *EthernetRingsConfig `yaml:\"rings,omitempty\"`\n\t//   description: |\n\t//     Configuration for Ethernet link channels.\n\t//\n\t//     This is similar to `ethtool -L` command.\n\tChannelsConfig *EthernetChannelsConfig `yaml:\"channels,omitempty\"`\n\t//   description: |\n\t//     Wake-on-LAN modes to enable.\n\t//\n\t//     If this field is omitted, Wake-on-LAN configuration is not changed.\n\t//     An empty list disables Wake-on-LAN.\n\t//\n\t//     This is similar to `ethtool -s <link> wol <options>` command.\n\t//   values:\n\t//     - \"phy\"\n\t//     - \"unicast\"\n\t//     - \"multicast\"\n\t//     - \"broadcast\"\n\t//     - \"arp\"\n\t//     - \"magic\"\n\t//     - \"magicsecure\"\n\t//     - \"filter\"\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\t//   examples:\n\t//    - value: >\n\t//       []nethelpers.WOLMode{nethelpers.WOLModeUnicast, nethelpers.WOLModeMagic}\n\tWakeOnLANConfig []nethelpers.WOLMode `yaml:\"wakeOnLan,omitempty\"`\n}\n\n// EthernetRingsConfig is a configuration for Ethernet link rings.\ntype EthernetRingsConfig struct {\n\t//   description: |\n\t//     Number of RX rings.\n\tRX *uint32 `yaml:\"rx,omitempty\"`\n\t//   description: |\n\t//     Number of TX rings.\n\tTX *uint32 `yaml:\"tx,omitempty\"`\n\t//   description: |\n\t//     Number of RX mini rings.\n\tRXMini *uint32 `yaml:\"rx-mini,omitempty\"`\n\t//  description: |\n\t//    Number of RX jumbo rings.\n\tRXJumbo *uint32 `yaml:\"rx-jumbo,omitempty\"`\n\t//   description: |\n\t//     RX buffer length.\n\tRXBufLen *uint32 `yaml:\"rx-buf-len,omitempty\"`\n\t//   description: |\n\t//     CQE size.\n\tCQESize *uint32 `yaml:\"cqe-size,omitempty\"`\n\t//   description: |\n\t//     TX push enabled.\n\tTXPush *bool `yaml:\"tx-push,omitempty\"`\n\t//  description: |\n\t//    RX push enabled.\n\tRXPush *bool `yaml:\"rx-push,omitempty\"`\n\t//  description: |\n\t//    TX push buffer length.\n\tTXPushBufLen *uint32 `yaml:\"tx-push-buf-len,omitempty\"`\n\t//  description: |\n\t//    TCP data split enabled.\n\tTCPDataSplit *bool `yaml:\"tcp-data-split,omitempty\"`\n}\n\n// EthernetChannelsConfig is a configuration for Ethernet link channels.\ntype EthernetChannelsConfig struct {\n\t//   description: |\n\t//     Number of RX channels.\n\tRX *uint32 `yaml:\"rx,omitempty\"`\n\t//   description: |\n\t//     Number of TX channels.\n\tTX *uint32 `yaml:\"tx,omitempty\"`\n\t//   description: |\n\t//     Number of other channels.\n\tOther *uint32 `yaml:\"other,omitempty\"`\n\t//   description: |\n\t//     Number of combined channels.\n\tCombined *uint32 `yaml:\"combined,omitempty\"`\n}\n\n// NewEthernetConfigV1Alpha1 creates a new EthernetConfig config document.\nfunc NewEthernetConfigV1Alpha1(name string) *EthernetConfigV1Alpha1 {\n\treturn &EthernetConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       EthernetKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleEthernetConfigV1Alpha1() *EthernetConfigV1Alpha1 {\n\tcfg := NewEthernetConfigV1Alpha1(\"enp0s2\")\n\tcfg.RingsConfig = &EthernetRingsConfig{\n\t\tRX: new(uint32(256)),\n\t}\n\tcfg.FeaturesConfig = map[string]bool{\n\t\t\"tx-tcp-segmentation\": false,\n\t}\n\tcfg.ChannelsConfig = &EthernetChannelsConfig{\n\t\tRX: new(uint32(4)),\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *EthernetConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *EthernetConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Rings implements config.EthernetConfig interface.\nfunc (s *EthernetConfigV1Alpha1) Rings() config.EthernetRingsConfig {\n\treturn config.EthernetRingsConfig(pointer.SafeDeref(s.RingsConfig))\n}\n\n// Channels implements config.EthernetConfig interface.\nfunc (s *EthernetConfigV1Alpha1) Channels() config.EthernetChannelsConfig {\n\treturn config.EthernetChannelsConfig(pointer.SafeDeref(s.ChannelsConfig))\n}\n\n// Features implements config.EthernetConfig interface.\nfunc (s *EthernetConfigV1Alpha1) Features() map[string]bool {\n\treturn s.FeaturesConfig\n}\n\n// WakeOnLAN implements config.EthernetConfig interface.\nfunc (s *EthernetConfigV1Alpha1) WakeOnLAN() []nethelpers.WOLMode {\n\treturn s.WakeOnLANConfig\n}\n\n// Validate implements config.Validator interface.\nfunc (s *EthernetConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif s.MetaName == \"\" {\n\t\treturn nil, errors.New(\"name is required\")\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/ethernet_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/ethernetconfig.yaml\nvar expectedEthernetConfigDocument []byte\n\nfunc TestEthernetConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewEthernetConfigV1Alpha1(\"enp0s1\")\n\tcfg.RingsConfig = &network.EthernetRingsConfig{\n\t\tRX: new(uint32(16)),\n\t}\n\tcfg.FeaturesConfig = map[string]bool{\n\t\t\"tx-checksum-ipv4\": true,\n\t}\n\tcfg.ChannelsConfig = &network.EthernetChannelsConfig{\n\t\tCombined: new(uint32(1)),\n\t}\n\tcfg.WakeOnLANConfig = []nethelpers.WOLMode{\n\t\tnethelpers.WOLModeUnicast,\n\t\tnethelpers.WOLModeMulticast,\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedEthernetConfigDocument, marshaled)\n}\n\nfunc TestEthernetConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedEthernetConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.EthernetConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.EthernetKind,\n\t\t},\n\t\tMetaName: \"enp0s1\",\n\t\tFeaturesConfig: map[string]bool{\n\t\t\t\"tx-checksum-ipv4\": true,\n\t\t},\n\t\tRingsConfig: &network.EthernetRingsConfig{\n\t\t\tRX: new(uint32(16)),\n\t\t},\n\t\tChannelsConfig: &network.EthernetChannelsConfig{\n\t\t\tCombined: new(uint32(1)),\n\t\t},\n\t\tWakeOnLANConfig: []nethelpers.WOLMode{\n\t\t\tnethelpers.WOLModeUnicast,\n\t\t\tnethelpers.WOLModeMulticast,\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestEthernetValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.EthernetConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.EthernetConfigV1Alpha1 {\n\t\t\t\treturn network.NewEthernetConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.EthernetConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewEthernetConfigV1Alpha1(\"enp0s1\")\n\t\t\t\tcfg.FeaturesConfig = map[string]bool{\n\t\t\t\t\t\"tx-checksum-ipv4\": true,\n\t\t\t\t}\n\t\t\t\tcfg.RingsConfig = &network.EthernetRingsConfig{\n\t\t\t\t\tRX: new(uint32(16)),\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/hcloud_vip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// HCloudVIPKind is a HCloudVIP config document kind.\nconst HCloudVIPKind = \"HCloudVIPConfig\"\n\nfunc init() {\n\tregistry.Register(HCloudVIPKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &HCloudVIPConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkHCloudVIPConfig = &HCloudVIPConfigV1Alpha1{}\n\t_ config.ConflictingDocument    = &HCloudVIPConfigV1Alpha1{}\n\t_ config.NamedDocument          = &HCloudVIPConfigV1Alpha1{}\n\t_ config.Validator              = &HCloudVIPConfigV1Alpha1{}\n)\n\n// HCloudVIPConfigV1Alpha1 is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\n//\n//\tdescription: |\n//\t Virtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\n//\t Any other use cases are not supported and may lead to unexpected behavior.\n//\t Virtual IP will be announced from only one node at a time using Hetzner Cloud APIs.\n//\texamples:\n//\t  - value: exampleHCloudVIPConfigV1Alpha1()\n//\talias: HCloudVIPConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/HCloudVIPConfig\ntype HCloudVIPConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//    IP address to be advertised as a Layer 2 VIP.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"192.168.100.1\"\n\t//    - value: >\n\t//       \"fd00::1\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Name of the link to assign the VIP to.\n\t//\n\t//     Selector must match exactly one link, otherwise an error is returned.\n\t//     If multiple selectors match the same link, the first one is used.\n\tLinkName string `yaml:\"link\"`\n\t//   description: |\n\t//     Specifies the Hetzner Cloud API Token.\n\tAPIToken string `yaml:\"apiToken\"`\n}\n\n// NewHCloudVIPConfigV1Alpha1 creates a new HCloudVIPConfig config document.\nfunc NewHCloudVIPConfigV1Alpha1(name string) *HCloudVIPConfigV1Alpha1 {\n\treturn &HCloudVIPConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       HCloudVIPKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleHCloudVIPConfigV1Alpha1() *HCloudVIPConfigV1Alpha1 {\n\tcfg := NewHCloudVIPConfigV1Alpha1(\"int0\")\n\tcfg.LinkName = \"enp0s2\"\n\tcfg.APIToken = \"my-secret-token\"\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *HCloudVIPConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *HCloudVIPConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *HCloudVIPConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t} else if _, err := netip.ParseAddr(s.MetaName); err != nil {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"name must be a valid IP address: %w\", err))\n\t}\n\n\tif s.LinkName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"link must be specified\"))\n\t}\n\n\tif s.APIToken == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"apiToken must be specified\"))\n\t}\n\n\treturn warnings, errs\n}\n\n// Link implements config.NetworkHCloudVIPConfig interface.\nfunc (s *HCloudVIPConfigV1Alpha1) Link() string {\n\treturn s.LinkName\n}\n\n// VIP implements config.NetworkHCloudVIPConfig interface.\nfunc (s *HCloudVIPConfigV1Alpha1) VIP() netip.Addr {\n\taddr, _ := netip.ParseAddr(s.MetaName) //nolint:errcheck // already validated\n\n\treturn addr\n}\n\n// HCloudAPIToken implements config.NetworkHCloudVIPConfig interface.\nfunc (s *HCloudVIPConfigV1Alpha1) HCloudAPIToken() string {\n\treturn s.APIToken\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *HCloudVIPConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn []string{Layer2VIPKind}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/hcloud_vip_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/hcloudvipconfig.yaml\nvar expectedHCloudVIPConfigDocument []byte\n\nfunc TestHCloudVIPConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewHCloudVIPConfigV1Alpha1(\"1.2.3.4\")\n\tcfg.LinkName = \"net33\"\n\tcfg.APIToken = \"s3cr3t-t0k3n\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedHCloudVIPConfigDocument, marshaled)\n}\n\nfunc TestHCloudVIPConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedHCloudVIPConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tc := &network.HCloudVIPConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.HCloudVIPKind,\n\t\t},\n\t\tMetaName: \"1.2.3.4\",\n\t\tLinkName: \"net33\",\n\t\tAPIToken: \"s3cr3t-t0k3n\",\n\t}\n\n\tassert.Equal(t, c, docs[0])\n}\n\nfunc TestHCloudVIPValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.HCloudVIPConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.HCloudVIPConfigV1Alpha1 {\n\t\t\t\treturn network.NewHCloudVIPConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nlink must be specified\\napiToken must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"no link name and token\",\n\t\t\tcfg: func() *network.HCloudVIPConfigV1Alpha1 {\n\t\t\t\treturn network.NewHCloudVIPConfigV1Alpha1(\"1.1.1.1\")\n\t\t\t},\n\n\t\t\texpectedError: \"link must be specified\\napiToken must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid IP\",\n\t\t\tcfg: func() *network.HCloudVIPConfigV1Alpha1 {\n\t\t\t\tc := network.NewHCloudVIPConfigV1Alpha1(\"net32\")\n\t\t\t\tc.LinkName = \"net32\"\n\t\t\t\tc.APIToken = \"foo\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: \"name must be a valid IP address: ParseAddr(\\\"net32\\\"): unable to parse IP\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.HCloudVIPConfigV1Alpha1 {\n\t\t\t\tc := network.NewHCloudVIPConfigV1Alpha1(\"fd00::1\")\n\t\t\t\tc.LinkName = \"net33\"\n\t\t\t\tc.APIToken = \"my-secret-token\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/hostname.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// HostnameKind is a Hostname config document kind.\nconst HostnameKind = \"HostnameConfig\"\n\nfunc init() {\n\tregistry.Register(HostnameKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &HostnameConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkHostnameConfig        = &HostnameConfigV1Alpha1{}\n\t_ config.Validator                    = &HostnameConfigV1Alpha1{}\n\t_ container.V1Alpha1ConflictValidator = &HostnameConfigV1Alpha1{}\n)\n\n// HostnameConfigV1Alpha1 is a config document to configure the hostname: either a static hostname or an automatically generated hostname.\n//\n//\texamples:\n//\t  - value: exampleHostnameConfigV1Alpha1()\n//\t  - value: exampleHostnameConfigV1Alpha2()\n//\talias: HostnameConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/HostnameConfig\ntype HostnameConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     A method to automatically generate a hostname for the machine.\n\t//\n\t//     There are two methods available:\n\t//       - `stable` - generates a stable hostname based on machine identity\n\t//       - `off` - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\n\t//\n\t//     Automatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\n\t//     Conflicts with `hostname` field.\n\t//   values:\n\t//     - \"stable\"\n\t//     - \"off\"\n\tConfigAuto *nethelpers.AutoHostnameKind `yaml:\"auto,omitempty\"`\n\t//   description: |\n\t//     A static hostname to set for the machine.\n\t//\n\t//     This hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\n\t//     Conflicts with `auto` field.\n\t//   examples:\n\t//    - value: >\n\t//       \"controlplane1\"\n\t//    - value: >\n\t//       \"controlplane1.example.org\"\n\tConfigHostname string `yaml:\"hostname,omitempty\"`\n}\n\n// NewHostnameConfigV1Alpha1 creates a new HostnameConfig config document.\nfunc NewHostnameConfigV1Alpha1() *HostnameConfigV1Alpha1 {\n\treturn &HostnameConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       HostnameKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleHostnameConfigV1Alpha1() *HostnameConfigV1Alpha1 {\n\tcfg := NewHostnameConfigV1Alpha1()\n\tcfg.ConfigHostname = \"worker-33\"\n\n\treturn cfg\n}\n\nfunc exampleHostnameConfigV1Alpha2() *HostnameConfigV1Alpha1 {\n\tcfg := NewHostnameConfigV1Alpha1()\n\tcfg.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *HostnameConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s *HostnameConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif pointer.SafeDeref(s.ConfigAuto) == nethelpers.AutoHostnameKindOff && s.ConfigHostname == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"either 'auto' or 'hostname' must be set\"))\n\t}\n\n\tif pointer.SafeDeref(s.ConfigAuto) != nethelpers.AutoHostnameKindOff && s.ConfigHostname != \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"'auto' and 'hostname' cannot be set at the same time\"))\n\t}\n\n\tswitch pointer.SafeDeref(s.ConfigAuto) {\n\tcase nethelpers.AutoHostnameKindOff, nethelpers.AutoHostnameKindStable:\n\t\t// valid values\n\tcase nethelpers.AutoHostnameKindAddr:\n\t\tfallthrough\n\tdefault:\n\t\terrs = errors.Join(errs, fmt.Errorf(\"invalid value for 'auto': %s\", s.ConfigAuto))\n\t}\n\n\tif s.ConfigHostname != \"\" {\n\t\tif len(s.ConfigHostname) > 253 {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"fqdn is too long: %d\", len(s.ConfigHostname)))\n\t\t}\n\n\t\thostname, _, _ := strings.Cut(s.ConfigHostname, \".\")\n\n\t\tif len(hostname) == 0 || len(hostname) > 63 {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"invalid hostname %q\", hostname))\n\t\t}\n\t}\n\n\treturn nil, errs\n}\n\n// V1Alpha1ConflictValidate implements container.V1Alpha1ConflictValidator interface.\nfunc (s *HostnameConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Cfg *v1alpha1.Config) error {\n\tif v1alpha1Cfg.Hostname() != \"\" {\n\t\treturn errors.New(\"static hostname is already set in v1alpha1 config\")\n\t}\n\n\tif v1alpha1Cfg.AutoHostname() != nethelpers.AutoHostnameKindAddr {\n\t\treturn errors.New(\"stable hostname is already set in v1alpha1 config\")\n\t}\n\n\treturn nil\n}\n\n// Hostname implements config.NetworkHostnameConfig interface.\nfunc (s *HostnameConfigV1Alpha1) Hostname() string {\n\treturn s.ConfigHostname\n}\n\n// AutoHostname implements config.NetworkHostnameConfig interface.\nfunc (s *HostnameConfigV1Alpha1) AutoHostname() nethelpers.AutoHostnameKind {\n\treturn pointer.SafeDeref(s.ConfigAuto)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/hostname_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/hostnameconfig.yaml\nvar expectedHostnameConfigDocument []byte\n\nfunc TestHostnameConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewHostnameConfigV1Alpha1()\n\tcfg.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedHostnameConfigDocument, marshaled)\n}\n\nfunc TestHostnameConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.HostnameConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  network.NewHostnameConfigV1Alpha1,\n\n\t\t\texpectedError: \"either 'auto' or 'hostname' must be set\",\n\t\t},\n\t\t{\n\t\t\tname: \"both set\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = \"example.org\"\n\t\t\t\tcfg.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"'auto' and 'hostname' cannot be set at the same time\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid auto\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigAuto = new(nethelpers.AutoHostnameKindAddr)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid value for 'auto': talos-addr\",\n\t\t},\n\t\t{\n\t\t\tname: \"too long hostname\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = strings.Repeat(\"a\", 64)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid hostname \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"too long hostname\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = strings.Repeat(\"a\", 64) + \".\" + strings.Repeat(\"b\", 64)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid hostname \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid fqdn\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = \".example.org\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid hostname \\\"\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"fqdn too long\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = strings.Repeat(strings.Repeat(\"a\", 63)+\".\", 5)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"fqdn is too long: 320\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid 1\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigHostname = \"example.org\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid 2\",\n\t\t\tcfg: func() *network.HostnameConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewHostnameConfigV1Alpha1()\n\t\t\t\tcfg.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHostnameV1Alpha1Validate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname        string\n\t\tv1alpha1Cfg *v1alpha1.Config\n\t\tcfg         func() *network.HostnameConfigV1Alpha1\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{},\n\t\t\tcfg:         network.NewHostnameConfigV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 static hostname set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkHostname: \"foo\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewHostnameConfigV1Alpha1,\n\n\t\t\texpectedError: \"static hostname is already set in v1alpha1 config\",\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 stable hostname set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\tStableHostname: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewHostnameConfigV1Alpha1,\n\n\t\t\texpectedError: \"stable hostname is already set in v1alpha1 config\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := test.cfg().V1Alpha1ConflictValidate(test.v1alpha1Cfg)\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/kubespan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\tsideronet \"github.com/siderolabs/net\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// KubeSpanKind is a KubeSpan config document kind.\nconst KubeSpanKind = \"KubeSpanConfig\"\n\nfunc init() {\n\tregistry.Register(KubeSpanKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &KubeSpanConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkKubeSpanConfig        = &KubeSpanConfigV1Alpha1{}\n\t_ config.Validator                    = &KubeSpanConfigV1Alpha1{}\n\t_ container.V1Alpha1ConflictValidator = &KubeSpanConfigV1Alpha1{}\n)\n\n// KubeSpanConfigV1Alpha1 is a config document to configure KubeSpan.\n//\n//\texamples:\n//\t  - value: exampleKubeSpanV1Alpha1()\n//\talias: KubeSpanConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/KubeSpanConfig\ntype KubeSpanConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Enable the KubeSpan feature.\n\t//     Cluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\n\t//   schema:\n\t//     type: boolean\n\tConfigEnabled *bool `yaml:\"enabled,omitempty\"`\n\n\t//   description: |\n\t//     Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\n\t//     If disabled, CNI handles pod-to-pod traffic encapsulation.\n\t//     If enabled, KubeSpan takes over pod-to-pod traffic directly.\n\t//   schema:\n\t//     type: boolean\n\tConfigAdvertiseKubernetesNetworks *bool `yaml:\"advertiseKubernetesNetworks,omitempty\"`\n\n\t//   description: |\n\t//     Skip sending traffic via KubeSpan if the peer connection state is not up.\n\t//     This provides configurable choice between connectivity and security.\n\t//   schema:\n\t//     type: boolean\n\tConfigAllowDownPeerBypass *bool `yaml:\"allowDownPeerBypass,omitempty\"`\n\n\t//   description: |\n\t//     KubeSpan can collect and publish extra endpoints for each member of the cluster\n\t//     based on Wireguard endpoint information for each peer.\n\t//     Disabled by default. Do not enable with high peer counts (>50).\n\t//   schema:\n\t//     type: boolean\n\tConfigHarvestExtraEndpoints *bool `yaml:\"harvestExtraEndpoints,omitempty\"`\n\n\t//   description: |\n\t//     KubeSpan link MTU size.\n\t//     Default value is 1420.\n\t//   schema:\n\t//     type: integer\n\tConfigMTU *uint32 `yaml:\"mtu,omitempty\"`\n\n\t//   description: |\n\t//     KubeSpan advanced filtering of network addresses.\n\t//     Settings are optional and apply only to this node.\n\tConfigFilters *KubeSpanFiltersConfig `yaml:\"filters,omitempty\"`\n}\n\n// KubeSpanFiltersConfig configures KubeSpan endpoint filters.\ntype KubeSpanFiltersConfig struct {\n\t//   description: |\n\t//     Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\n\t//\n\t//     By default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\n\t//\n\t//     Default value: no filtering.\n\t//   examples:\n\t//     - name: Exclude addresses in 192.168.0.0/16 subnet.\n\t//       value: '[]string{\"0.0.0.0/0\", \"!192.168.0.0/16\", \"::/0\"}'\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\tConfigEndpoints []string `yaml:\"endpoints,omitempty\"`\n\n\t//   description: |\n\t//     Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\n\t//\n\t//     By default, all networks are advertised.\n\t//     Use this filter to exclude some networks from being advertised.\n\t//\n\t//     Note: excluded networks will not be reachable over KubeSpan, so make sure\n\t//     these networks are still reachable via some other route (e.g., direct connection).\n\t//\n\t//     Default value: no filtering.\n\t//   examples:\n\t//     - name: Exclude private networks from being advertised.\n\t//       value: '[]Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}}'\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\t//       pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\tConfigExcludeAdvertisedNetworks []Prefix `yaml:\"excludeAdvertisedNetworks,omitempty\"`\n}\n\n// NewKubeSpanV1Alpha1 creates a new KubeSpanConfig config document.\nfunc NewKubeSpanV1Alpha1() *KubeSpanConfigV1Alpha1 {\n\treturn &KubeSpanConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       KubeSpanKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleKubeSpanV1Alpha1() *KubeSpanConfigV1Alpha1 {\n\tcfg := NewKubeSpanV1Alpha1()\n\tcfg.ConfigEnabled = new(true)\n\tcfg.ConfigAdvertiseKubernetesNetworks = new(false)\n\tcfg.ConfigAllowDownPeerBypass = new(false)\n\tcfg.ConfigHarvestExtraEndpoints = new(false)\n\tcfg.ConfigMTU = new(uint32(1420))\n\tcfg.ConfigFilters = &KubeSpanFiltersConfig{\n\t\tConfigEndpoints:                 []string{\"0.0.0.0/0\", \"::/0\"},\n\t\tConfigExcludeAdvertisedNetworks: []Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}, {netip.MustParsePrefix(\"2003::/16\")}},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *KubeSpanConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (s *KubeSpanConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif s.ConfigMTU != nil && *s.ConfigMTU < constants.KubeSpanLinkMinimumMTU {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"kubespan link MTU must be at least %d\", constants.KubeSpanLinkMinimumMTU))\n\t}\n\n\tif s.ConfigFilters != nil {\n\t\tfor _, cidr := range s.ConfigFilters.ConfigEndpoints {\n\t\t\tcidr = strings.TrimPrefix(cidr, \"!\")\n\n\t\t\tif _, err := sideronet.ParseSubnetOrAddress(cidr); err != nil {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"KubeSpan endpoint filter is not valid: %q\", cidr))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, errs\n}\n\n// V1Alpha1ConflictValidate implements container.V1Alpha1ConflictValidator interface.\nfunc (s *KubeSpanConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Cfg *v1alpha1.Config) error {\n\tlegacyKubespan := v1alpha1Cfg.NetworkKubeSpanConfig()\n\n\tif legacyKubespan != nil {\n\t\treturn fmt.Errorf(\"kubespan is already configured in v1alpha1 machine.network.kubespan\")\n\t}\n\n\treturn nil\n}\n\n// Enabled implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) Enabled() bool {\n\treturn pointer.SafeDeref(s.ConfigEnabled)\n}\n\n// AdvertiseKubernetesNetworks implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) AdvertiseKubernetesNetworks() bool {\n\treturn pointer.SafeDeref(s.ConfigAdvertiseKubernetesNetworks)\n}\n\n// ForceRouting implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) ForceRouting() bool {\n\treturn !pointer.SafeDeref(s.ConfigAllowDownPeerBypass)\n}\n\n// HarvestExtraEndpoints implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) HarvestExtraEndpoints() bool {\n\treturn pointer.SafeDeref(s.ConfigHarvestExtraEndpoints)\n}\n\n// MTU implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) MTU() uint32 {\n\tif s.ConfigMTU != nil {\n\t\treturn *s.ConfigMTU\n\t}\n\n\treturn constants.KubeSpanLinkMTU\n}\n\n// Filters implements config.NetworkKubeSpanConfig interface.\nfunc (s *KubeSpanConfigV1Alpha1) Filters() config.NetworkKubeSpanFilters {\n\tif s.ConfigFilters == nil {\n\t\treturn nil\n\t}\n\n\treturn s.ConfigFilters\n}\n\n// Endpoints implements config.NetworkKubeSpanFilters interface.\nfunc (f *KubeSpanFiltersConfig) Endpoints() []string {\n\treturn f.ConfigEndpoints\n}\n\n// ExcludeAdvertisedNetworks implements config.NetworkKubeSpanFilters interface.\nfunc (f *KubeSpanFiltersConfig) ExcludeAdvertisedNetworks() []netip.Prefix {\n\treturn xslices.Map(f.ConfigExcludeAdvertisedNetworks, func(p Prefix) netip.Prefix { return p.Prefix })\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/kubespan_endpoints.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n// KubespanEndpointsKind is a KubeSpan endpoints document kind.\nconst KubespanEndpointsKind = \"KubeSpanEndpointsConfig\"\n\nfunc init() {\n\tregistry.Register(KubespanEndpointsKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &KubespanEndpointsConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.KubespanConfig = &KubespanEndpointsConfigV1Alpha1{}\n)\n\n// KubespanEndpointsConfigV1Alpha1 is a config document to configure KubeSpan endpoints.\n//\n//\texamples:\n//\t  - value: exampleKubespanEndpointsV1Alpha1()\n//\talias: KubeSpanEndpointsConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/KubeSpanEndpoints\ntype KubespanEndpointsConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     A list of extra Wireguard endpoints to announce from this machine.\n\t//\n\t//     Talos automatically adds endpoints based on machine addresses, public IP, etc.\n\t//     This field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\tExtraAnnouncedEndpointsConfig []netip.AddrPort `yaml:\"extraAnnouncedEndpoints\"`\n}\n\n// NewKubespanEndpointsV1Alpha1 creates a new KubespanEndpoints config document.\nfunc NewKubespanEndpointsV1Alpha1() *KubespanEndpointsConfigV1Alpha1 {\n\treturn &KubespanEndpointsConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       KubespanEndpointsKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleKubespanEndpointsV1Alpha1() *KubespanEndpointsConfigV1Alpha1 {\n\tcfg := NewKubespanEndpointsV1Alpha1()\n\tcfg.ExtraAnnouncedEndpointsConfig = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"192.168.13.46:52000\"),\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *KubespanEndpointsConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// ExtraAnnouncedEndpoints implements KubespanConfig interface.\nfunc (s *KubespanEndpointsConfigV1Alpha1) ExtraAnnouncedEndpoints() []netip.AddrPort {\n\treturn slices.Clone(s.ExtraAnnouncedEndpointsConfig)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/kubespan_endpoints_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/kubespanendpointsconfig.yaml\nvar expectedKubespanEndpointsConfigDocument []byte\n\nfunc TestKubespanEndpointsConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewKubespanEndpointsV1Alpha1()\n\tcfg.ExtraAnnouncedEndpointsConfig = []netip.AddrPort{\n\t\tnetip.MustParseAddrPort(\"3.4.5.6:123\"),\n\t\tnetip.MustParseAddrPort(\"10.11.12.13:456\"),\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedKubespanEndpointsConfigDocument, marshaled)\n}\n\nfunc TestKubespanEndpointsConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedKubespanEndpointsConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.KubespanEndpointsConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.KubespanEndpointsKind,\n\t\t},\n\t\tExtraAnnouncedEndpointsConfig: []netip.AddrPort{\n\t\t\tnetip.MustParseAddrPort(\"3.4.5.6:123\"),\n\t\t\tnetip.MustParseAddrPort(\"10.11.12.13:456\"),\n\t\t},\n\t}, docs[0])\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/kubespan_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n//go:embed testdata/kubespanconfig.yaml\nvar expectedKubeSpanConfigDocument []byte\n\nfunc TestKubeSpanConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewKubeSpanV1Alpha1()\n\tcfg.ConfigEnabled = new(true)\n\tcfg.ConfigAdvertiseKubernetesNetworks = new(false)\n\tcfg.ConfigAllowDownPeerBypass = new(false)\n\tcfg.ConfigMTU = new(uint32(1420))\n\tcfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\tConfigExcludeAdvertisedNetworks: []network.Prefix{{netip.MustParsePrefix(\"2007::/64\")}},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedKubeSpanConfigDocument, marshaled)\n}\n\nfunc TestKubeSpanConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewKubeSpanV1Alpha1()\n\tcfg.ConfigEnabled = new(true)\n\tcfg.ConfigMTU = new(uint32(1500))\n\tcfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\tConfigEndpoints:                 []string{\"0.0.0.0/0\", \"!192.168.0.0/16\"},\n\t\tConfigExcludeAdvertisedNetworks: []network.Prefix{{netip.MustParsePrefix(\"2007::/64\")}},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\t// Verify interface methods work\n\tassert.True(t, cfg.Enabled())\n\tassert.Equal(t, uint32(1500), cfg.MTU())\n\tassert.Equal(t, []string{\"0.0.0.0/0\", \"!192.168.0.0/16\"}, cfg.Filters().Endpoints())\n\tassert.Equal(t, []netip.Prefix{netip.MustParsePrefix(\"2007::/64\")}, cfg.Filters().ExcludeAdvertisedNetworks())\n}\n\nfunc TestKubeSpanConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.KubeSpanConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"valid default\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid with MTU\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigMTU = new(uint32(1420))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MTU too low\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigMTU = new(uint32(1279))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"kubespan link MTU must be at least 1280\",\n\t\t},\n\t\t{\n\t\t\tname: \"MTU at minimum\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigMTU = new(uint32(1280))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with filters\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\t\t\t\tConfigEndpoints: []string{\"0.0.0.0/0\", \"!10.0.0.0/8\"},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"with invalid filters\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\t\t\t\tConfigEndpoints: []string{\"0.0.0.0/0\", \"!/8\"},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: `KubeSpan endpoint filter is not valid: \"/8\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"all options enabled\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\t\t\t\tcfg.ConfigAdvertiseKubernetesNetworks = new(true)\n\t\t\t\tcfg.ConfigAllowDownPeerBypass = new(true)\n\t\t\t\tcfg.ConfigHarvestExtraEndpoints = new(true)\n\t\t\t\tcfg.ConfigMTU = new(uint32(1400))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestKubeSpanConfigConflictValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.KubeSpanConfigV1Alpha1\n\t\tv1   func() *v1alpha1.Config\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"no conflict when v1alpha1 empty\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\tv1: func() *v1alpha1.Config {\n\t\t\t\treturn &v1alpha1.Config{}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"conflict when both set\",\n\t\t\tcfg: func() *network.KubeSpanConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewKubeSpanV1Alpha1()\n\t\t\t\tcfg.ConfigEnabled = new(true)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\tv1: func() *v1alpha1.Config {\n\t\t\t\tcfg := &v1alpha1.Config{}\n\t\t\t\tcfg.MachineConfig = &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"kubespan is already configured in v1alpha1 machine.network.kubespan\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := test.cfg().V1Alpha1ConflictValidate(test.v1())\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestKubeSpanConfigInterface(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewKubeSpanV1Alpha1()\n\tcfg.ConfigEnabled = new(true)\n\tcfg.ConfigAdvertiseKubernetesNetworks = new(true)\n\tcfg.ConfigAllowDownPeerBypass = new(false)\n\tcfg.ConfigHarvestExtraEndpoints = new(true)\n\tcfg.ConfigMTU = new(uint32(1380))\n\tcfg.ConfigFilters = &network.KubeSpanFiltersConfig{\n\t\tConfigEndpoints:                 []string{\"192.168.0.0/16\"},\n\t\tConfigExcludeAdvertisedNetworks: []network.Prefix{{netip.MustParsePrefix(\"0.0.0.0/0\")}},\n\t}\n\n\t// Test interface methods\n\tassert.True(t, cfg.Enabled())\n\tassert.True(t, cfg.AdvertiseKubernetesNetworks())\n\tassert.True(t, cfg.ForceRouting())\n\tassert.True(t, cfg.HarvestExtraEndpoints())\n\tassert.Equal(t, uint32(1380), cfg.MTU())\n\tassert.NotNil(t, cfg.Filters())\n\tassert.Equal(t, []string{\"192.168.0.0/16\"}, cfg.Filters().Endpoints())\n\tassert.Equal(t, []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\")}, cfg.Filters().ExcludeAdvertisedNetworks())\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/layer2_vip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// Layer2VIPKind is a Layer2VIP config document kind.\nconst Layer2VIPKind = \"Layer2VIPConfig\"\n\nfunc init() {\n\tregistry.Register(Layer2VIPKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &Layer2VIPConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkLayer2VIPConfig = &Layer2VIPConfigV1Alpha1{}\n\t_ config.ConflictingDocument    = &Layer2VIPConfigV1Alpha1{}\n\t_ config.NamedDocument          = &Layer2VIPConfigV1Alpha1{}\n\t_ config.Validator              = &Layer2VIPConfigV1Alpha1{}\n)\n\n// Layer2VIPConfigV1Alpha1 is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\n//\n//\tdescription: |\n//\t Virtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\n//\t Any other use cases are not supported and may lead to unexpected behavior.\n//\t Virtual IP will be announced from only one node at a time using gratuitous ARP announcements for IPv4.\n//\texamples:\n//\t  - value: exampleLayer2VIPConfigV1Alpha1()\n//\talias: Layer2VIPConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/Layer2VIPConfig\ntype Layer2VIPConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//    IP address to be advertised as a Layer 2 VIP.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"192.168.100.1\"\n\t//    - value: >\n\t//       \"fd00::1\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Name of the link to assign the VIP to.\n\t//\n\t//     Selector must match exactly one link, otherwise an error is returned.\n\t//     If multiple selectors match the same link, the first one is used.\n\tLinkName string `yaml:\"link\"`\n}\n\n// NewLayer2VIPConfigV1Alpha1 creates a new Layer2VIPConfig config document.\nfunc NewLayer2VIPConfigV1Alpha1(name string) *Layer2VIPConfigV1Alpha1 {\n\treturn &Layer2VIPConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       Layer2VIPKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleLayer2VIPConfigV1Alpha1() *Layer2VIPConfigV1Alpha1 {\n\tcfg := NewLayer2VIPConfigV1Alpha1(\"10.3.0.1\")\n\tcfg.LinkName = \"enp0s2\"\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *Layer2VIPConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *Layer2VIPConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *Layer2VIPConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t} else if _, err := netip.ParseAddr(s.MetaName); err != nil {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"name must be a valid IP address: %w\", err))\n\t}\n\n\tif s.LinkName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"link must be specified\"))\n\t}\n\n\treturn warnings, errs\n}\n\n// Link implements config.NetworkLayer2VIPConfig interface.\nfunc (s *Layer2VIPConfigV1Alpha1) Link() string {\n\treturn s.LinkName\n}\n\n// VIP implements config.NetworkLayer2VIPConfig interface.\nfunc (s *Layer2VIPConfigV1Alpha1) VIP() netip.Addr {\n\taddr, _ := netip.ParseAddr(s.MetaName) //nolint:errcheck // already validated\n\n\treturn addr\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *Layer2VIPConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn []string{HCloudVIPKind}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/layer2_vip_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/layer2vipconfig.yaml\nvar expectedLayer2VIPConfigDocument []byte\n\nfunc TestLayer2VIPConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewLayer2VIPConfigV1Alpha1(\"1.2.3.4\")\n\tcfg.LinkName = \"net0\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedLayer2VIPConfigDocument, marshaled)\n}\n\nfunc TestLayer2VIPConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedLayer2VIPConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tc := &network.Layer2VIPConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.Layer2VIPKind,\n\t\t},\n\t\tMetaName: \"1.2.3.4\",\n\t\tLinkName: \"net0\",\n\t}\n\n\tassert.Equal(t, c, docs[0])\n}\n\nfunc TestLayer2VIPValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.Layer2VIPConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.Layer2VIPConfigV1Alpha1 {\n\t\t\t\treturn network.NewLayer2VIPConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nlink must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"no link name\",\n\t\t\tcfg: func() *network.Layer2VIPConfigV1Alpha1 {\n\t\t\t\treturn network.NewLayer2VIPConfigV1Alpha1(\"1.1.1.1\")\n\t\t\t},\n\n\t\t\texpectedError: \"link must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid IP\",\n\t\t\tcfg: func() *network.Layer2VIPConfigV1Alpha1 {\n\t\t\t\tc := network.NewLayer2VIPConfigV1Alpha1(\"net4\")\n\t\t\t\tc.LinkName = \"net0\"\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: \"name must be a valid IP address: ParseAddr(\\\"net4\\\"): unable to parse IP\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.Layer2VIPConfigV1Alpha1 {\n\t\t\t\tc := network.NewLayer2VIPConfigV1Alpha1(\"fd00::1\")\n\t\t\t\tc.LinkName = \"net45\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/link.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// LinkKind is a Link config document kind.\nconst LinkKind = \"LinkConfig\"\n\nfunc init() {\n\tregistry.Register(LinkKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &LinkConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\nfunc conflictingLinkKinds(selfKind string) []string {\n\treturn xslices.Filter([]string{\n\t\tBondKind,\n\t\tBridgeKind,\n\t\tDummyLinkKind,\n\t\tLinkKind,\n\t\tVLANKind,\n\t\tVRFKind,\n\t\tWireguardKind,\n\t}, func(kind string) bool {\n\t\treturn kind != selfKind\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkPhysicalLinkConfig = &LinkConfigV1Alpha1{}\n\t_ config.ConflictingDocument       = &LinkConfigV1Alpha1{}\n\t_ config.NamedDocument             = &LinkConfigV1Alpha1{}\n\t_ config.Validator                 = &LinkConfigV1Alpha1{}\n)\n\n// LinkConfigV1Alpha1 is a config document to configure physical interfaces (network links).\n//\n//\texamples:\n//\t  - value: exampleLinkConfigV1Alpha1()\n//\talias: LinkConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/LinkConfig\ntype LinkConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the link (interface).\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"enp0s2\"\n\t//    - value: >\n\t//       \"eth1\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// CommonLinkConfig is common configuration for network links, and logical links.\ntype CommonLinkConfig struct {\n\t//   description: |\n\t//     Bring the link up or down.\n\t//\n\t//     If not specified, the link will be brought up.\n\tLinkUp *bool `yaml:\"up,omitempty\"`\n\t//   description: |\n\t//     Configure LinkMTU (Maximum Transmission Unit) for the link.\n\t//\n\t//     If not specified, the system default LinkMTU will be used (usually 1500).\n\tLinkMTU uint32 `yaml:\"mtu,omitempty\"`\n\t//   description: |\n\t//     Configure addresses to be statically assigned to the link.\n\tLinkAddresses []AddressConfig `yaml:\"addresses,omitempty\"`\n\t//   description: |\n\t//     Configure routes to be statically created via the link.\n\tLinkRoutes []RouteConfig `yaml:\"routes,omitempty\"`\n\t//   description: |\n\t//     Set the multicast capability of the link.\n\tLinkMulticast *bool `yaml:\"multicast,omitempty\"`\n}\n\n// AddressConfig represents a network address configuration.\ntype AddressConfig struct {\n\t//   description: |\n\t//     IP address to be assigned to the link.\n\t//\n\t//     This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\n\t//   examples:\n\t//    - value: >\n\t//       netip.MustParsePrefix(\"192.168.1.100/24\")\n\t//    - value: >\n\t//       netip.MustParsePrefix(\"fd00::1/64\")\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\t//   schemaRequired: true\n\tAddressAddress netip.Prefix `yaml:\"address\"`\n\t//   description: |\n\t//     Configure the route priority (metric) for routes created for this address.\n\t//\n\t//     If not specified, the system default route priority will be used.\n\tAddressPriority *uint32 `yaml:\"routePriority,omitempty\"`\n}\n\n// RouteConfig represents a network route configuration.\ntype RouteConfig struct {\n\t//   description: |\n\t//    The route's destination as an address prefix.\n\t//\n\t//    If not specified, a default route will be created for the address family of the gateway.\n\t//   examples:\n\t//    - value: >\n\t//       Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\tRouteDestination Prefix `yaml:\"destination,omitempty\"`\n\t//   description: |\n\t//     The route's gateway (if empty, creates link scope route).\n\t//   examples:\n\t//    - value: >\n\t//       Addr{netip.MustParseAddr(\"10.0.0.1\")}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+$\n\tRouteGateway Addr `yaml:\"gateway,omitempty\"`\n\t//   description: |\n\t//     The route's source address (optional).\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+$\n\tRouteSource Addr `yaml:\"source,omitempty\"`\n\t//   description: |\n\t//     The optional metric for the route.\n\tRouteMetric uint32 `yaml:\"metric,omitempty\"`\n\t//   description: |\n\t//     The optional MTU for the route.\n\tRouteMTU uint32 `yaml:\"mtu,omitempty\"`\n\t//   description: |\n\t//     The routing table to use for the route.\n\t//\n\t//     If not specified, the main routing table will be used.\n\t//   schema:\n\t//     type: string\n\tRouteTable nethelpers.RoutingTable `yaml:\"table,omitempty\"`\n}\n\n// NewLinkConfigV1Alpha1 creates a new LinkConfig config document.\nfunc NewLinkConfigV1Alpha1(name string) *LinkConfigV1Alpha1 {\n\treturn &LinkConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       LinkKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleLinkConfigV1Alpha1() *LinkConfigV1Alpha1 {\n\tcfg := NewLinkConfigV1Alpha1(\"enp0s2\")\n\tcfg.LinkMTU = 9000\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t},\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t},\n\t}\n\tcfg.LinkRoutes = []RouteConfig{\n\t\t{\n\t\t\tRouteDestination: Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")},\n\t\t\tRouteGateway:     Addr{netip.MustParseAddr(\"10.0.0.1\")},\n\t\t},\n\t\t{\n\t\t\tRouteGateway: Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *LinkConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *LinkConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// PhysicalLinkConfig implements NetworkPhysicalLinkConfig interface.\nfunc (s *LinkConfigV1Alpha1) PhysicalLinkConfig() {}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *LinkConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(LinkKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *LinkConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\n// Validate validates the common link config.\n//\n//nolint:gocyclo\nfunc (s *CommonLinkConfig) Validate() ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tfor i, addr := range s.LinkAddresses {\n\t\tswitch {\n\t\tcase addr.AddressAddress == (netip.Prefix{}):\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"address %d must be specified\", i))\n\t\tcase !addr.AddressAddress.IsValid():\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"address %d must be a valid IP prefix\", i))\n\t\tcase !addr.AddressAddress.Addr().IsValid() || addr.AddressAddress.Addr().IsUnspecified():\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"address %d must be a valid IP address\", i))\n\t\t}\n\t}\n\n\tfor i, route := range s.LinkRoutes {\n\t\tif route.RouteDestination != (Prefix{}) && (!route.RouteDestination.IsValid() || route.RouteDestination.Addr().IsUnspecified()) {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"route %d destination must be a valid IP prefix\", i))\n\t\t}\n\n\t\tif route.RouteGateway != (Addr{}) && (!route.RouteGateway.IsValid() || route.RouteGateway.IsUnspecified()) {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"route %d gateway must be a valid IP address\", i))\n\t\t}\n\n\t\tif route.RouteSource != (Addr{}) && (!route.RouteSource.IsValid() || route.RouteSource.IsUnspecified()) {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"route %d source must be a valid IP address\", i))\n\t\t}\n\t}\n\n\treturn warnings, errs\n}\n\n// Up implements NetworkCommonLinkConfig interface.\nfunc (s *CommonLinkConfig) Up() optional.Optional[bool] {\n\tif s.LinkUp == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.LinkUp)\n}\n\n// MTU implements NetworkCommonLinkConfig interface.\nfunc (s *CommonLinkConfig) MTU() optional.Optional[uint32] {\n\tif s.LinkMTU == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(s.LinkMTU)\n}\n\n// Addresses implements NetworkCommonLinkConfig interface.\nfunc (s *CommonLinkConfig) Addresses() []config.NetworkAddressConfig {\n\treturn xslices.Map(s.LinkAddresses, func(a AddressConfig) config.NetworkAddressConfig {\n\t\treturn a\n\t})\n}\n\n// Routes implements NetworkCommonLinkConfig interface.\nfunc (s *CommonLinkConfig) Routes() []config.NetworkRouteConfig {\n\treturn xslices.Map(s.LinkRoutes, func(r RouteConfig) config.NetworkRouteConfig {\n\t\treturn r\n\t})\n}\n\n// Multicast implements NetworkCommonLinkConfig interface.\nfunc (s *CommonLinkConfig) Multicast() optional.Optional[bool] {\n\tif s.LinkMulticast == nil {\n\t\treturn optional.None[bool]()\n\t}\n\n\treturn optional.Some(*s.LinkMulticast)\n}\n\n// Address implements NetworkAddressConfig interface.\nfunc (a AddressConfig) Address() netip.Prefix {\n\treturn a.AddressAddress\n}\n\n// RoutePriority implements NetworkAddressConfig interface.\nfunc (a AddressConfig) RoutePriority() optional.Optional[uint32] {\n\tif a.AddressPriority == nil {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(*a.AddressPriority)\n}\n\n// Destination implements NetworkRouteConfig interface.\nfunc (r RouteConfig) Destination() optional.Optional[netip.Prefix] {\n\tif r.RouteDestination == (Prefix{}) {\n\t\treturn optional.None[netip.Prefix]()\n\t}\n\n\treturn optional.Some(r.RouteDestination.Prefix)\n}\n\n// Gateway implements NetworkRouteConfig interface.\nfunc (r RouteConfig) Gateway() optional.Optional[netip.Addr] {\n\tif r.RouteGateway == (Addr{}) {\n\t\treturn optional.None[netip.Addr]()\n\t}\n\n\treturn optional.Some(r.RouteGateway.Addr)\n}\n\n// Source implements NetworkRouteConfig interface.\nfunc (r RouteConfig) Source() optional.Optional[netip.Addr] {\n\tif r.RouteSource == (Addr{}) {\n\t\treturn optional.None[netip.Addr]()\n\t}\n\n\treturn optional.Some(r.RouteSource.Addr)\n}\n\n// MTU implements NetworkRouteConfig interface.\nfunc (r RouteConfig) MTU() optional.Optional[uint32] {\n\tif r.RouteMTU == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(r.RouteMTU)\n}\n\n// Metric implements NetworkRouteConfig interface.\nfunc (r RouteConfig) Metric() optional.Optional[uint32] {\n\tif r.RouteMetric == 0 {\n\t\treturn optional.None[uint32]()\n\t}\n\n\treturn optional.Some(r.RouteMetric)\n}\n\n// Table implements NetworkRouteConfig interface.\nfunc (r RouteConfig) Table() optional.Optional[nethelpers.RoutingTable] {\n\tif r.RouteTable == nethelpers.TableUnspec {\n\t\treturn optional.None[nethelpers.RoutingTable]()\n\t}\n\n\treturn optional.Some(r.RouteTable)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/link_alias.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// LinkAliasKind is a LinkAlias config document kind.\nconst LinkAliasKind = \"LinkAliasConfig\"\n\nfunc init() {\n\tregistry.Register(LinkAliasKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &LinkAliasConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkLinkAliasConfig = &LinkAliasConfigV1Alpha1{}\n\t_ config.NamedDocument          = &LinkAliasConfigV1Alpha1{}\n\t_ config.Validator              = &LinkAliasConfigV1Alpha1{}\n)\n\n// LinkAliasConfigV1Alpha1 is a config document to alias (give a different name) to a physical link.\n//\n//\texamples:\n//\t  - value: exampleLinkAliasConfigV1Alpha1()\n//\t  - value: exampleLinkAliasMultipleConfigV1Alpha1()\n//\talias: LinkAliasConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/LinkAliasConfig\ntype LinkAliasConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//    Alias for the link.\n\t//\n\t//    Don't use system interface names like \"eth0\", \"ens3\", \"enp0s2\", etc. as those may conflict\n\t//    with existing physical interfaces.\n\t//\n\t//    The name can contain a single integer format verb (`%d`) to create multiple aliases\n\t//    from a single config document. When a format verb is detected, each matched link receives a sequential\n\t//    alias (e.g. `net0`, `net1`, ...) based on hardware address order of the links.\n\t//    Links already aliased by a previous config are automatically skipped.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"net0\"\n\t//    - value: >\n\t//       \"private\"\n\t//    - value: >\n\t//       \"net%d\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Selector to match the link to alias.\n\t//\n\t//     When the alias name is a fixed string, the selector must match exactly one link.\n\t//     When the alias name contains a format verb (e.g. `net%d`), the selector may match multiple links\n\t//     and each match receives a sequential alias.\n\t//     If multiple selectors match the same link, the first one is used.\n\tSelector LinkSelector `yaml:\"selector,omitempty\"`\n}\n\n// LinkSelector selects a link to alias.\ntype LinkSelector struct {\n\t//   description: |\n\t//     The Common Expression Language (CEL) expression to match the link.\n\t//   schema:\n\t//     type: string\n\t//   examples:\n\t//    - value: >\n\t//        exampleLinkSelector1()\n\t//      name: match links with a specific MAC address\n\t//    - value: >\n\t//        exampleLinkSelector2()\n\t//      name: match links by MAC address prefix\n\t//    - value: >\n\t//        exampleLinkSelector3()\n\t//      name: match links by driver name\n\tMatch cel.Expression `yaml:\"match,omitempty\"`\n}\n\n// NewLinkAliasConfigV1Alpha1 creates a new LinkAliasConfig config document.\nfunc NewLinkAliasConfigV1Alpha1(name string) *LinkAliasConfigV1Alpha1 {\n\treturn &LinkAliasConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       LinkAliasKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleLinkAliasConfigV1Alpha1() *LinkAliasConfigV1Alpha1 {\n\tcfg := NewLinkAliasConfigV1Alpha1(\"int0\")\n\tcfg.Selector.Match = exampleLinkSelector2()\n\n\treturn cfg\n}\n\nfunc exampleLinkAliasMultipleConfigV1Alpha1() *LinkAliasConfigV1Alpha1 {\n\tcfg := NewLinkAliasConfigV1Alpha1(\"net%d\")\n\tcfg.Selector.Match = exampleLinkSelector3()\n\n\treturn cfg\n}\n\nfunc exampleLinkSelector1() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"`, celenv.LinkLocator()))\n}\n\nfunc exampleLinkSelector2() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`glob(\"00:1a:2b:*\", mac(link.permanent_addr))`, celenv.LinkLocator()))\n}\n\nfunc exampleLinkSelector3() cel.Expression {\n\treturn cel.MustExpression(cel.ParseBooleanExpression(`link.driver == \"e1000\"`, celenv.LinkLocator()))\n}\n\n// Clone implements config.Document interface.\nfunc (s *LinkAliasConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *LinkAliasConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *LinkAliasConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t} else if s.IsPatternAlias() {\n\t\tprefix, suffix, _ := strings.Cut(s.MetaName, \"%\")\n\t\tif suffix != \"d\" || prefix == \"\" {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"name %q contains an invalid format verb, use %%d suffix\", s.MetaName))\n\t\t}\n\t}\n\n\tif !s.Selector.Match.IsZero() {\n\t\tif err := s.Selector.Match.ParseBool(celenv.LinkLocator()); err != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"link selector is invalid: %w\", err))\n\t\t}\n\t} else {\n\t\terrs = errors.Join(errs, errors.New(\"link selector is required\"))\n\t}\n\n\treturn warnings, errs\n}\n\n// LinkSelector implements config.NetworkLinkAliasConfig interface.\nfunc (s *LinkAliasConfigV1Alpha1) LinkSelector() cel.Expression {\n\treturn s.Selector.Match\n}\n\n// IsPatternAlias returns true if the alias name contains a format verb (e.g. %d)\n// indicating this config should create multiple aliases.\nfunc (s *LinkAliasConfigV1Alpha1) IsPatternAlias() bool {\n\treturn strings.ContainsRune(s.MetaName, '%')\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/link_alias_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/linkaliasconfig.yaml\nvar expectedLinkAliasConfigDocument []byte\n\nfunc TestLinkAliasConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewLinkAliasConfigV1Alpha1(\"net0\")\n\tcfg.Selector.Match = cel.MustExpression(cel.ParseBooleanExpression(`mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"`, celenv.LinkLocator()))\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedLinkAliasConfigDocument, marshaled)\n}\n\nfunc TestLinkAliasConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedLinkAliasConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tc := &network.LinkAliasConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.LinkAliasKind,\n\t\t},\n\t\tMetaName: \"net0\",\n\t}\n\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"`)))\n\n\tassert.Equal(t, c, docs[0])\n}\n\nfunc TestLinkAliasValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.LinkAliasConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\treturn network.NewLinkAliasConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nlink selector is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"no disk selector\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\treturn network.NewLinkAliasConfigV1Alpha1(\"int0\")\n\t\t\t},\n\n\t\t\texpectedError: \"link selector is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid disk selector\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"int0\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`disk.size > 120`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: \"link selector is invalid: ERROR: <input>:1:1: undeclared reference to 'disk' (in container '')\\n | disk.size > 120\\n | ^\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"int0\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid pattern name\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"net%d\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`link.type == 1`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid pattern name with padding\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"net%02d\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`link.type == 1`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: \"name \\\"net%02d\\\" contains an invalid format verb, use %d suffix\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid pattern name with multiple verbs\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"net%d-port%d\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`link.type == 1`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: \"name \\\"net%d-port%d\\\" contains an invalid format verb, use %d suffix\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid format verb\",\n\t\t\tcfg: func() *network.LinkAliasConfigV1Alpha1 {\n\t\t\t\tc := network.NewLinkAliasConfigV1Alpha1(\"net%s\")\n\t\t\t\trequire.NoError(t, c.Selector.Match.UnmarshalText([]byte(`link.type == 1`)))\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedError: `name \"net%s\" contains an invalid format verb, use %d suffix`,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/link_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/linkconfig.yaml\nvar expectedLinkConfigDocument []byte\n\nfunc TestLinkConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewLinkConfigV1Alpha1(\"enp0s1\")\n\tcfg.LinkMTU = 9000\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t},\n\t\t{\n\t\t\tAddressAddress:  netip.MustParsePrefix(\"2001:db8::1/64\"),\n\t\t\tAddressPriority: new(uint32(100)),\n\t\t},\n\t}\n\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t{\n\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t},\n\t\t{\n\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t},\n\t}\n\tcfg.LinkMulticast = new(true)\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedLinkConfigDocument, marshaled)\n}\n\nfunc TestLinkConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedLinkConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.LinkConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.LinkKind,\n\t\t},\n\t\tMetaName: \"enp0s1\",\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkMTU: 9000,\n\t\t\tLinkUp:  new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tAddressAddress:  netip.MustParsePrefix(\"2001:db8::1/64\"),\n\t\t\t\t\tAddressPriority: new(uint32(100)),\n\t\t\t\t},\n\t\t\t},\n\t\t\tLinkRoutes: []network.RouteConfig{\n\t\t\t\t{\n\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tLinkMulticast: new(true),\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestLinkValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.LinkConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.LinkConfigV1Alpha1 {\n\t\t\t\treturn network.NewLinkConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid addresses\",\n\n\t\t\tcfg: func() *network.LinkConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewLinkConfigV1Alpha1(\"enp0s2\")\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.Prefix{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"address 0 must be specified\\naddress 1 must be a valid IP address\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.LinkConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewLinkConfigV1Alpha1(\"enp0s2\")\n\t\t\t\tcfg.LinkMTU = 9000\n\t\t\t\tcfg.LinkUp = new(true)\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides network machine configuration documents.\npackage network\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output network_doc.go network.go blackhole_route.go bond.go bridge.go vrf.go default_action_config.go dhcp4.go dhcp6.go dummy.go ethernet.go hcloud_vip.go hostname.go kubespan.go kubespan_endpoints.go layer2_vip.go link.go link_alias.go port_range.go resolver.go routing_rule.go rule_config.go static_host.go tcp_probe.go time_sync.go vlan.go wireguard.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type BlackholeRouteConfigV1Alpha1 -type BondConfigV1Alpha1 -type BridgeConfigV1Alpha1 -type VRFConfigV1Alpha1 -type DefaultActionConfigV1Alpha1 -type DHCPv4ConfigV1Alpha1 -type DHCPv6ConfigV1Alpha1 -type DummyLinkConfigV1Alpha1 -type EthernetConfigV1Alpha1 -type HCloudVIPConfigV1Alpha1 -type HostnameConfigV1Alpha1 -type KubeSpanConfigV1Alpha1 -type KubespanEndpointsConfigV1Alpha1 -type Layer2VIPConfigV1Alpha1 -type LinkConfigV1Alpha1 -type LinkAliasConfigV1Alpha1 -type ResolverConfigV1Alpha1 -type RoutingRuleConfigV1Alpha1 -type RuleConfigV1Alpha1 -type StaticHostConfigV1Alpha1 -type TCPProbeConfigV1Alpha1 -type TimeSyncConfigV1Alpha1 -type VLANConfigV1Alpha1 -type WireguardConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/network/network_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\nfunc (BlackholeRouteConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"BlackholeRouteConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"BlackholeRouteConfig is a config document to configure blackhole routes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"BlackholeRouteConfig is a config document to configure blackhole routes.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Route destination as an address prefix.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Route destination as an address prefix.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"metric\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The optional metric for the route.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The optional metric for the route.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleBlackholeRouteConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"10.0.0.0/12\")\n\n\treturn doc\n}\n\nfunc (BondConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"BondConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"BondConfig is a config document to create a bond (link aggregation) over a set of links.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"BondConfig is a config document to create a bond (link aggregation) over a set of links.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the bond link (interface) to be created.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the bond link (interface) to be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hardwareAddr\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Override the hardware (MAC) address of the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Override the hardware (MAC) address of the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"links\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Names of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Names of the links (interfaces) on which the bond will be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"bondMode\",\n\t\t\t\tType:        \"BondMode\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Bond mode.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Bond mode.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"balance-rr\",\n\t\t\t\t\t\"active-backup\",\n\t\t\t\t\t\"balance-xor\",\n\t\t\t\t\t\"broadcast\",\n\t\t\t\t\t\"802.3ad\",\n\t\t\t\t\t\"balance-tlb\",\n\t\t\t\t\t\"balance-alb\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"miimon\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Link monitoring frequency in milliseconds.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Link monitoring frequency in milliseconds.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"updelay\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"downdelay\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"useCarrier\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies whether or not miimon should use MII or ETHTOOL.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies whether or not miimon should use MII or ETHTOOL.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"xmitHashPolicy\",\n\t\t\t\tType:        \"BondXmitHashPolicy\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Selects the transmit hash policy to use for slave selection.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Selects the transmit hash policy to use for slave selection.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"layer2\",\n\t\t\t\t\t\"layer3+4\",\n\t\t\t\t\t\"layer2+3\",\n\t\t\t\t\t\"encap2+3\",\n\t\t\t\t\t\"encap3+4\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"arpInterval\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"ARP link monitoring frequency in milliseconds.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ARP link monitoring frequency in milliseconds.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"arpIpTargets\",\n\t\t\t\tType:        \"[]Addr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nsIp6Targets\",\n\t\t\t\tType:        \"[]Addr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"arpValidate\",\n\t\t\t\tType:        \"ARPValidate\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies whether or not ARP probes and replies should be validated.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies whether or not ARP probes and replies should be validated.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"none\",\n\t\t\t\t\t\"active\",\n\t\t\t\t\t\"backup\",\n\t\t\t\t\t\"all\",\n\t\t\t\t\t\"filter\",\n\t\t\t\t\t\"filter-active\",\n\t\t\t\t\t\"filter-backup\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"arpAllTargets\",\n\t\t\t\tType:        \"ARPAllTargets\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies whether ARP probes should be sent to any or all targets.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies whether ARP probes should be sent to any or all targets.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"any\",\n\t\t\t\t\t\"all\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"lacpRate\",\n\t\t\t\tType:        \"LACPRate\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"LACPDU frames periodic transmission rate.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LACPDU frames periodic transmission rate.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"slow\",\n\t\t\t\t\t\"fast\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"failOverMac\",\n\t\t\t\tType:        \"FailOverMAC\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies whether active-backup mode should set all slaves to the same MAC address\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"none\",\n\t\t\t\t\t\"active\",\n\t\t\t\t\t\"follow\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"adSelect\",\n\t\t\t\tType:        \"ADSelect\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Aggregate selection policy for 802.3ad.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Aggregate selection policy for 802.3ad.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"stable\",\n\t\t\t\t\t\"bandwidth\",\n\t\t\t\t\t\"count\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"adActorSysPrio\",\n\t\t\t\tType:        \"uint16\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Actor system priority for 802.3ad.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Actor system priority for 802.3ad.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"adUserPortKey\",\n\t\t\t\tType:        \"uint16\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"User port key (upper 10 bits) for 802.3ad.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"User port key (upper 10 bits) for 802.3ad.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"adLACPActive\",\n\t\t\t\tType:        \"ADLACPActive\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Whether to send LACPDU frames periodically.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Whether to send LACPDU frames periodically.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"on\",\n\t\t\t\t\t\"off\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"primaryReselect\",\n\t\t\t\tType:        \"PrimaryReselect\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Policy under which the primary slave should be reselected.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Policy under which the primary slave should be reselected.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"always\",\n\t\t\t\t\t\"better\",\n\t\t\t\t\t\"failure\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"resendIGMP\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The number of times IGMP packets should be resent.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The number of times IGMP packets should be resent.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"minLinks\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The minimum number of active links required for the bond to be considered active.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The minimum number of active links required for the bond to be considered active.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"lpInterval\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"packetsPerSlave\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The number of packets to transmit through a slave before moving to the next one.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The number of packets to transmit through a slave before moving to the next one.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"numPeerNotif\",\n\t\t\t\tType:        \"uint8\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tlbLogicalLb\",\n\t\t\t\tType:        \"uint8\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"allSlavesActive\",\n\t\t\t\tType:        \"uint8\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"peerNotifDelay\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The delay, in milliseconds, between each peer notification.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The delay, in milliseconds, between each peer notification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"missedMax\",\n\t\t\t\tType:        \"uint8\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleBondConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"bond.ext\")\n\tdoc.Fields[2].AddExample(\"\", nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70})\n\tdoc.Fields[3].AddExample(\"\", []string{\"enp0s3\", \"enp0s8\"})\n\tdoc.Fields[4].AddExample(\"\", \"802.3ad\")\n\tdoc.Fields[5].AddExample(\"\", 200)\n\tdoc.Fields[6].AddExample(\"\", 300)\n\tdoc.Fields[7].AddExample(\"\", 100)\n\tdoc.Fields[9].AddExample(\"\", \"layer2\")\n\tdoc.Fields[10].AddExample(\"\", 1000)\n\tdoc.Fields[11].AddExample(\"\", []netip.Addr{netip.MustParseAddr(\"10.15.0.1\")})\n\tdoc.Fields[12].AddExample(\"\", []netip.Addr{netip.MustParseAddr(\"fd00::1\")})\n\tdoc.Fields[13].AddExample(\"\", \"active\")\n\tdoc.Fields[14].AddExample(\"\", \"all\")\n\tdoc.Fields[15].AddExample(\"\", \"fast\")\n\tdoc.Fields[16].AddExample(\"\", \"active\")\n\tdoc.Fields[17].AddExample(\"\", \"stable\")\n\tdoc.Fields[18].AddExample(\"\", 65535)\n\tdoc.Fields[19].AddExample(\"\", 0)\n\tdoc.Fields[20].AddExample(\"\", \"on\")\n\tdoc.Fields[21].AddExample(\"\", \"always\")\n\tdoc.Fields[27].AddExample(\"\", 1)\n\tdoc.Fields[28].AddExample(\"\", 0)\n\n\treturn doc\n}\n\nfunc (BridgeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"BridgeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"BridgeConfig is a config document to create a Bridge (link aggregation) over a set of links.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"BridgeConfig is a config document to create a Bridge (link aggregation) over a set of links.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the bridge link (interface) to be created.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the bridge link (interface) to be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hardwareAddr\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Override the hardware (MAC) address of the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Override the hardware (MAC) address of the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"links\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Names of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Names of the links (interfaces) to be aggregated.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"stp\",\n\t\t\t\tType:        \"BridgeSTPConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Bridge STP (Spanning Tree Protocol) configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Bridge STP (Spanning Tree Protocol) configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"vlan\",\n\t\t\t\tType:        \"BridgeVLANConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Bridge VLAN configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Bridge VLAN configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleBridgeConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"Bridge.ext\")\n\tdoc.Fields[2].AddExample(\"\", nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70})\n\tdoc.Fields[3].AddExample(\"\", []string{\"enp1s3\", \"enp1s2\"})\n\n\treturn doc\n}\n\nfunc (BridgeSTPConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"BridgeSTPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"BridgeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"stp\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable or disable STP on the bridge.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable or disable STP on the bridge.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", true)\n\n\treturn doc\n}\n\nfunc (BridgeVLANConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"BridgeVLANConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"BridgeVLANConfig is a bridge VLAN configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"BridgeVLANConfig is a bridge VLAN configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"BridgeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"vlan\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"filtering\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable or disable VLAN filtering on the bridge.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable or disable VLAN filtering on the bridge.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", true)\n\n\treturn doc\n}\n\nfunc (VRFConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VRFConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VRFConfig is a config document to create a vrf and assign links to it.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VRFConfig is a config document to create a vrf and assign links to it.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the vrf link (interface) to be created.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the vrf link (interface) to be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hardwareAddr\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Override the hardware (MAC) address of the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Override the hardware (MAC) address of the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"links\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Names of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Names of the links (interfaces) to be assigned to this vrf.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"table\",\n\t\t\t\tType:        \"RoutingTable\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Routing table number to use for this vrf.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Routing table number to use for this vrf.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleVRFConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"vrf-blue\")\n\tdoc.Fields[2].AddExample(\"\", nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70})\n\tdoc.Fields[3].AddExample(\"\", []string{\"enp1s3\", \"enp1s2\"})\n\tdoc.Fields[4].AddExample(\"\", 10)\n\n\treturn doc\n}\n\nfunc (DefaultActionConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"NetworkDefaultActionConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"NetworkDefaultActionConfig is a ingress firewall default action configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"NetworkDefaultActionConfig is a ingress firewall default action configuration document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ingress\",\n\t\t\t\tType:        \"DefaultAction\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Default action for all not explicitly configured ingress traffic: accept or block.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Default action for all not explicitly configured ingress traffic: accept or block.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"accept\",\n\t\t\t\t\t\"block\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleDefaultActionConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (DHCPv4ConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"DHCPv4Config\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"DHCPv4Config is a config document to configure DHCPv4 on a network link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"DHCPv4Config is a config document to configure DHCPv4 on a network link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"routeMetric\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"An optional metric for the routes received from the DHCP server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ignoreHostname\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Ignore hostname received from the DHCP server.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Ignore hostname received from the DHCP server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"clientIdentifier\",\n\t\t\t\tType:        \"ClientIdentifier\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Client identifier to use when communicating with DHCP servers.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"none\",\n\t\t\t\t\t\"mac\",\n\t\t\t\t\t\"duid\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"duidRaw\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Raw value of the DUID to use as client identifier.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleDHCPv4ConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"enp0s2\")\n\tdoc.Fields[5].AddExample(\"\", \"00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\")\n\n\treturn doc\n}\n\nfunc (DHCPv6ConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"DHCPv6Config\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"DHCPv6Config is a config document to configure DHCPv6 on a network link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"DHCPv6Config is a config document to configure DHCPv6 on a network link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"routeMetric\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"An optional metric for the routes received from the DHCP server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ignoreHostname\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Ignore hostname received from the DHCP server.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Ignore hostname received from the DHCP server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"clientIdentifier\",\n\t\t\t\tType:        \"ClientIdentifier\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Client identifier to use when communicating with DHCP servers.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"none\",\n\t\t\t\t\t\"mac\",\n\t\t\t\t\t\"duid\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"duidRaw\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Raw value of the DUID to use as client identifier.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleDHCPv6ConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"enp0s2\")\n\tdoc.Fields[5].AddExample(\"\", \"00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\")\n\n\treturn doc\n}\n\nfunc (DummyLinkConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"DummyLinkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"DummyLinkConfig is a config document to create a dummy (virtual) network link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"DummyLinkConfig is a config document to create a dummy (virtual) network link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the dummy link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the dummy link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hardwareAddr\",\n\t\t\t\tType:        \"HardwareAddr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Override the hardware (MAC) address of the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Override the hardware (MAC) address of the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleDummyLinkConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"dummy1\")\n\tdoc.Fields[2].AddExample(\"\", nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70})\n\n\treturn doc\n}\n\nfunc (EthernetConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EthernetConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EthernetConfig is a config document to configure Ethernet interfaces.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EthernetConfig is a config document to configure Ethernet interfaces.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"features\",\n\t\t\t\tType:        \"map[string]bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configuration for Ethernet features.\\n\\nSet of features available and whether they can be enabled or disabled is driver specific.\\nUse `talosctl get ethernetstatus <link> -o yaml` to get the list of available features and\\ntheir current status.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configuration for Ethernet features.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rings\",\n\t\t\t\tType:        \"EthernetRingsConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configuration for Ethernet link rings.\\n\\nThis is similar to `ethtool -G` command.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configuration for Ethernet link rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"channels\",\n\t\t\t\tType:        \"EthernetChannelsConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configuration for Ethernet link channels.\\n\\nThis is similar to `ethtool -L` command.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configuration for Ethernet link channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"wakeOnLan\",\n\t\t\t\tType:        \"[]WOLMode\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Wake-on-LAN modes to enable.\\n\\nIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\n\\nThis is similar to `ethtool -s <link> wol <options>` command.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Wake-on-LAN modes to enable.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"phy\",\n\t\t\t\t\t\"unicast\",\n\t\t\t\t\t\"multicast\",\n\t\t\t\t\t\"broadcast\",\n\t\t\t\t\t\"arp\",\n\t\t\t\t\t\"magic\",\n\t\t\t\t\t\"magicsecure\",\n\t\t\t\t\t\"filter\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleEthernetConfigV1Alpha1())\n\n\tdoc.Fields[5].AddExample(\"\", []nethelpers.WOLMode{nethelpers.WOLModeUnicast, nethelpers.WOLModeMagic})\n\n\treturn doc\n}\n\nfunc (EthernetRingsConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EthernetRingsConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EthernetRingsConfig is a configuration for Ethernet link rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EthernetRingsConfig is a configuration for Ethernet link rings.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EthernetConfigV1Alpha1\",\n\t\t\t\tFieldName: \"rings\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"rx\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of RX rings.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of RX rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tx\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of TX rings.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of TX rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rx-mini\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of RX mini rings.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of RX mini rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rx-jumbo\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of RX jumbo rings.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of RX jumbo rings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rx-buf-len\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"RX buffer length.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RX buffer length.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"cqe-size\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"CQE size.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CQE size.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tx-push\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"TX push enabled.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TX push enabled.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rx-push\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"RX push enabled.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RX push enabled.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tx-push-buf-len\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"TX push buffer length.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TX push buffer length.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tcp-data-split\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"TCP data split enabled.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TCP data split enabled.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (EthernetChannelsConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EthernetChannelsConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EthernetChannelsConfig is a configuration for Ethernet link channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EthernetChannelsConfig is a configuration for Ethernet link channels.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"EthernetConfigV1Alpha1\",\n\t\t\t\tFieldName: \"channels\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"rx\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of RX channels.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of RX channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"tx\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of TX channels.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of TX channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"other\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of other channels.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of other channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"combined\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of combined channels.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of combined channels.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (HCloudVIPConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"HCloudVIPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"HCloudVIPConfig is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"HCloudVIPConfig is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\nAny other use cases are not supported and may lead to unexpected behavior.\\nVirtual IP will be announced from only one node at a time using Hetzner Cloud APIs.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"IP address to be advertised as a Layer 2 VIP.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"IP address to be advertised as a Layer 2 VIP.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"link\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link to assign the VIP to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"apiToken\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the Hetzner Cloud API Token.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the Hetzner Cloud API Token.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleHCloudVIPConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"192.168.100.1\")\n\tdoc.Fields[1].AddExample(\"\", \"fd00::1\")\n\n\treturn doc\n}\n\nfunc (HostnameConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"HostnameConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"HostnameConfig is a config document to configure the hostname: either a static hostname or an automatically generated hostname.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"HostnameConfig is a config document to configure the hostname: either a static hostname or an automatically generated hostname.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"auto\",\n\t\t\t\tType:        \"AutoHostnameKind\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A method to automatically generate a hostname for the machine.\\n\\nThere are two methods available:\\n  - `stable` - generates a stable hostname based on machine identity\\n  - `off` - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\n\\nAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `hostname` field.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A method to automatically generate a hostname for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"stable\",\n\t\t\t\t\t\"off\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hostname\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A static hostname to set for the machine.\\n\\nThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `auto` field.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A static hostname to set for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleHostnameConfigV1Alpha1())\n\n\tdoc.AddExample(\"\", exampleHostnameConfigV1Alpha2())\n\n\tdoc.Fields[2].AddExample(\"\", \"controlplane1\")\n\tdoc.Fields[2].AddExample(\"\", \"controlplane1.example.org\")\n\n\treturn doc\n}\n\nfunc (KubeSpanConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubeSpanConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpanConfig is a config document to configure KubeSpan.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubeSpanConfig is a config document to configure KubeSpan.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable the KubeSpan feature.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"advertiseKubernetesNetworks\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"allowDownPeerBypass\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Skip sending traffic via KubeSpan if the peer connection state is not up.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"harvestExtraEndpoints\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (>50).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpan can collect and publish extra endpoints for each member of the cluster\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mtu\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KubeSpan link MTU size.\\nDefault value is 1420.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpan link MTU size.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"filters\",\n\t\t\t\tType:        \"KubeSpanFiltersConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpan advanced filtering of network addresses.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleKubeSpanV1Alpha1())\n\n\treturn doc\n}\n\nfunc (KubeSpanFiltersConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubeSpanFiltersConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpanFiltersConfig configures KubeSpan endpoint filters.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubeSpanFiltersConfig configures KubeSpan endpoint filters.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"KubeSpanConfigV1Alpha1\",\n\t\t\t\tFieldName: \"filters\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"endpoints\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"excludeAdvertisedNetworks\",\n\t\t\t\tType:        \"[]Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\n\\nBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\n\\nNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\n\\nDefault value: no filtering.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"Exclude addresses in 192.168.0.0/16 subnet.\", []string{\"0.0.0.0/0\", \"!192.168.0.0/16\", \"::/0\"})\n\tdoc.Fields[1].AddExample(\"Exclude private networks from being advertised.\", []Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}})\n\n\treturn doc\n}\n\nfunc (KubespanEndpointsConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubeSpanEndpointsConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeSpanEndpointsConfig is a config document to configure KubeSpan endpoints.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubeSpanEndpointsConfig is a config document to configure KubeSpan endpoints.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraAnnouncedEndpoints\",\n\t\t\t\tType:        \"[]AddrPort\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of extra Wireguard endpoints to announce from this machine.\\n\\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of extra Wireguard endpoints to announce from this machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleKubespanEndpointsV1Alpha1())\n\n\treturn doc\n}\n\nfunc (Layer2VIPConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"Layer2VIPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Layer2VIPConfig is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"Layer2VIPConfig is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\nAny other use cases are not supported and may lead to unexpected behavior.\\nVirtual IP will be announced from only one node at a time using gratuitous ARP announcements for IPv4.\\n\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"IP address to be advertised as a Layer 2 VIP.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"IP address to be advertised as a Layer 2 VIP.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"link\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link to assign the VIP to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleLayer2VIPConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"192.168.100.1\")\n\tdoc.Fields[1].AddExample(\"\", \"fd00::1\")\n\n\treturn doc\n}\n\nfunc (LinkConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LinkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LinkConfig is a config document to configure physical interfaces (network links).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LinkConfig is a config document to configure physical interfaces (network links).\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleLinkConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"enp0s2\")\n\tdoc.Fields[1].AddExample(\"\", \"eth1\")\n\n\treturn doc\n}\n\nfunc (CommonLinkConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"CommonLinkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CommonLinkConfig is common configuration for network links, and logical links.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"CommonLinkConfig is common configuration for network links, and logical links.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"BondConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"BridgeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"VRFConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"DummyLinkConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"LinkConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"VLANConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"WireguardConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"up\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Bring the link up or down.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mtu\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure LinkMTU (Maximum Transmission Unit) for the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"addresses\",\n\t\t\t\tType:        \"[]AddressConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure addresses to be statically assigned to the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure addresses to be statically assigned to the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"routes\",\n\t\t\t\tType:        \"[]RouteConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure routes to be statically created via the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure routes to be statically created via the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"multicast\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Set the multicast capability of the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Set the multicast capability of the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (AddressConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"AddressConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"AddressConfig represents a network address configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"AddressConfig represents a network address configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"CommonLinkConfig\",\n\t\t\t\tFieldName: \"addresses\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"address\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"IP address to be assigned to the link.\\n\\nThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"IP address to be assigned to the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"routePriority\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the route priority (metric) for routes created for this address.\\n\\nIf not specified, the system default route priority will be used.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the route priority (metric) for routes created for this address.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", netip.MustParsePrefix(\"192.168.1.100/24\"))\n\tdoc.Fields[0].AddExample(\"\", netip.MustParsePrefix(\"fd00::1/64\"))\n\n\treturn doc\n}\n\nfunc (RouteConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RouteConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RouteConfig represents a network route configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RouteConfig represents a network route configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"CommonLinkConfig\",\n\t\t\t\tFieldName: \"routes\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"destination\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The route's destination as an address prefix.\\n\\nIf not specified, a default route will be created for the address family of the gateway.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The route's destination as an address prefix.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"gateway\",\n\t\t\t\tType:        \"Addr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The route's gateway (if empty, creates link scope route).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The route's gateway (if empty, creates link scope route).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"source\",\n\t\t\t\tType:        \"Addr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The route's source address (optional).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The route's source address (optional).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"metric\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The optional metric for the route.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The optional metric for the route.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mtu\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The optional MTU for the route.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The optional MTU for the route.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"table\",\n\t\t\t\tType:        \"RoutingTable\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The routing table to use for the route.\\n\\nIf not specified, the main routing table will be used.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The routing table to use for the route.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")})\n\tdoc.Fields[1].AddExample(\"\", Addr{netip.MustParseAddr(\"10.0.0.1\")})\n\n\treturn doc\n}\n\nfunc (LinkAliasConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LinkAliasConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LinkAliasConfig is a config document to alias (give a different name) to a physical link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LinkAliasConfig is a config document to alias (give a different name) to a physical link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Alias for the link.\\n\\nDon't use system interface names like \\\"eth0\\\", \\\"ens3\\\", \\\"enp0s2\\\", etc. as those may conflict\\nwith existing physical interfaces.\\n\\nThe name can contain a single integer format verb (`%d`) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. `net0`, `net1`, ...) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Alias for the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"selector\",\n\t\t\t\tType:        \"LinkSelector\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Selector to match the link to alias.\\n\\nWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. `net%d`), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Selector to match the link to alias.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleLinkAliasConfigV1Alpha1())\n\n\tdoc.AddExample(\"\", exampleLinkAliasMultipleConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"net0\")\n\tdoc.Fields[1].AddExample(\"\", \"private\")\n\tdoc.Fields[1].AddExample(\"\", \"net%d\")\n\n\treturn doc\n}\n\nfunc (LinkSelector) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LinkSelector\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LinkSelector selects a link to alias.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LinkSelector selects a link to alias.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"LinkAliasConfigV1Alpha1\",\n\t\t\t\tFieldName: \"selector\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"match\",\n\t\t\t\tType:        \"Expression\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The Common Expression Language (CEL) expression to match the link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The Common Expression Language (CEL) expression to match the link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"match links with a specific MAC address\", exampleLinkSelector1())\n\tdoc.Fields[0].AddExample(\"match links by MAC address prefix\", exampleLinkSelector2())\n\tdoc.Fields[0].AddExample(\"match links by driver name\", exampleLinkSelector3())\n\n\treturn doc\n}\n\nfunc (ResolverConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ResolverConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ResolverConfig is a config document to configure DNS resolving.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ResolverConfig is a config document to configure DNS resolving.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nameservers\",\n\t\t\t\tType:        \"[]NameserverConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of nameservers (DNS servers) to use for resolving domain names.\\n\\nNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\n\\nThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of nameservers (DNS servers) to use for resolving domain names.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"searchDomains\",\n\t\t\t\tType:        \"SearchDomainsConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configuration for search domains (in /etc/resolv.conf).\\n\\nThe default is to derive search domains from the hostname FQDN.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configuration for search domains (in /etc/resolv.conf).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleResolverConfigV1Alpha1())\n\n\tdoc.AddExample(\"\", exampleResolverConfigV1Alpha2())\n\n\treturn doc\n}\n\nfunc (NameserverConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"NameserverConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"NameserverConfig represents a single nameserver configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"NameserverConfig represents a single nameserver configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ResolverConfigV1Alpha1\",\n\t\t\t\tFieldName: \"nameservers\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"address\",\n\t\t\t\tType:        \"Addr\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The IP address of the nameserver.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The IP address of the nameserver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", Addr{netip.MustParseAddr(\"10.0.0.1\")})\n\n\treturn doc\n}\n\nfunc (SearchDomainsConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"SearchDomainsConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SearchDomainsConfig represents search domains configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"SearchDomainsConfig represents search domains configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ResolverConfigV1Alpha1\",\n\t\t\t\tFieldName: \"searchDomains\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"domains\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of search domains to be used for DNS resolution.\\n\\nSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if \\\"example.com\\\" is a search domain and a user tries to resolve\\n\\\"host\\\", the system will attempt to resolve \\\"host.example.com\\\".\\n\\nThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of search domains to be used for DNS resolution.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"disableDefault\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable default search domain configuration from hostname FQDN.\\n\\nWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable default search domain configuration from hostname FQDN.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (RoutingRuleConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RoutingRuleConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RoutingRuleConfig is a config document to configure Linux policy routing rules.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RoutingRuleConfig is a config document to configure Linux policy routing rules.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Priority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Priority of the routing rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"src\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Source address prefix to match.\\nIf empty, matches all sources.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Source address prefix to match.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"dst\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Destination address prefix to match.\\nIf empty, matches all destinations.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Destination address prefix to match.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"table\",\n\t\t\t\tType:        \"RoutingTable\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The routing table to look up if the rule matches.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The routing table to look up if the rule matches.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"action\",\n\t\t\t\tType:        \"RoutingRuleAction\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The action to perform when the rule matches.\\nDefaults to \\\"unicast\\\" (table lookup).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The action to perform when the rule matches.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"unicast\",\n\t\t\t\t\t\"blackhole\",\n\t\t\t\t\t\"unreachable\",\n\t\t\t\t\t\"prohibit\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"iifName\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Match packets arriving on this interface.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Match packets arriving on this interface.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"oifName\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Match packets going out on this interface.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Match packets going out on this interface.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"fwMark\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Match packets with this firewall mark value.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Match packets with this firewall mark value.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"fwMask\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Mask for the firewall mark comparison.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Mask for the firewall mark comparison.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRoutingRuleConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", 1000)\n\tdoc.Fields[2].AddExample(\"\", \"10.0.0.0/8\")\n\tdoc.Fields[3].AddExample(\"\", \"192.168.0.0/16\")\n\tdoc.Fields[4].AddExample(\"\", 100)\n\tdoc.Fields[6].AddExample(\"\", \"eth0\")\n\tdoc.Fields[7].AddExample(\"\", \"eth1\")\n\tdoc.Fields[8].AddExample(\"\", uint32(0x100))\n\tdoc.Fields[9].AddExample(\"\", uint32(0xff00))\n\n\treturn doc\n}\n\nfunc (RuleConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"NetworkRuleConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"NetworkRuleConfig is a network firewall rule config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"NetworkRuleConfig is a network firewall rule config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the config document.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"portSelector\",\n\t\t\t\tType:        \"RulePortSelector\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Port selector defines which ports and protocols on the host are affected by the rule.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Port selector defines which ports and protocols on the host are affected by the rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ingress\",\n\t\t\t\tType:        \"[]IngressRule\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleRuleConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (RulePortSelector) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RulePortSelector\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RulePortSelector is a port selector for the network rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RulePortSelector is a port selector for the network rule.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"RuleConfigV1Alpha1\",\n\t\t\t\tFieldName: \"portSelector\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"ports\",\n\t\t\t\tType:        \"PortRanges\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Ports defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Ports defines a list of port ranges or single ports.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"protocol\",\n\t\t\t\tType:        \"Protocol\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Protocol defines traffic protocol (e.g. TCP or UDP).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Protocol defines traffic protocol (e.g. TCP or UDP).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"tcp\",\n\t\t\t\t\t\"udp\",\n\t\t\t\t\t\"icmp\",\n\t\t\t\t\t\"icmpv6\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", examplePortRanges1())\n\tdoc.Fields[0].AddExample(\"\", examplePortRanges2())\n\n\treturn doc\n}\n\nfunc (IngressRule) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"IngressRule\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"IngressRule is a ingress rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"IngressRule is a ingress rule.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"RuleConfigV1Alpha1\",\n\t\t\t\tFieldName: \"ingress\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"subnet\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Subnet defines a source subnet.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Subnet defines a source subnet.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"except\",\n\t\t\t\tType:        \"Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", netip.MustParsePrefix(\"10.3.4.0/24\"))\n\tdoc.Fields[0].AddExample(\"\", netip.MustParsePrefix(\"2001:db8::/32\"))\n\tdoc.Fields[0].AddExample(\"\", netip.MustParsePrefix(\"1.3.4.5/32\"))\n\n\treturn doc\n}\n\nfunc (StaticHostConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"StaticHostConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"StaticHostConfig is a config document to set /etc/hosts entries.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"StaticHostConfig is a config document to set /etc/hosts entries.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"IP address (IPv4 or IPv6) to map the hostnames to.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"IP address (IPv4 or IPv6) to map the hostnames to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hostnames\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of hostnames to map to the IP address.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of hostnames to map to the IP address.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleStaticHostConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (TCPProbeConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"TCPProbeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TCPProbeConfig is a config document to configure network TCP connectivity probes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"TCPProbeConfig is a config document to configure network TCP connectivity probes.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the probe.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the probe.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonProbeConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Endpoint to probe in the format host:port.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Endpoint to probe in the format host:port.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"timeout\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Timeout for the probe.\\nDefaults to 10s.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Timeout for the probe.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleTCPProbeConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"proxy-check\")\n\tdoc.Fields[3].AddExample(\"\", \"proxy.example.com:3128\")\n\tdoc.Fields[4].AddExample(\"\", 10*time.Second)\n\n\treturn doc\n}\n\nfunc (CommonProbeConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"CommonProbeConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CommonProbeConfig holds fields common to all probe types.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"CommonProbeConfig holds fields common to all probe types.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"TCPProbeConfigV1Alpha1\",\n\t\t\t\tFieldName: \"\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"interval\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Interval between probe attempts.\\nDefaults to 1s.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Interval between probe attempts.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"failureThreshold\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Number of consecutive failures for the probe to be considered failed after having succeeded.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", time.Second)\n\tdoc.Fields[1].AddExample(\"\", 3)\n\n\treturn doc\n}\n\nfunc (TimeSyncConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"TimeSyncConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TimeSyncConfig is a config document to configure time synchronization (NTP).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"TimeSyncConfig is a config document to configure time synchronization (NTP).\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Indicates if the time synchronization is enabled for the machine.\\nDefaults to `true`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Indicates if the time synchronization is enabled for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"bootTimeout\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\\"infinity\\\" (waiting forever for time sync)\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ntp\",\n\t\t\t\tType:        \"NTPConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies NTP configuration to sync the time over network.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ptp\",\n\t\t\t\tType:        \"PTPConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleTimeSyncConfigV1Alpha1())\n\n\tdoc.AddExample(\"\", exampleTimeSyncConfigV1Alpha2())\n\n\treturn doc\n}\n\nfunc (NTPConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"NTPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"NTPConfig represents a NTP server configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"NTPConfig represents a NTP server configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"TimeSyncConfigV1Alpha1\",\n\t\t\t\tFieldName: \"ntp\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"servers\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to `time.cloudflare.com`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies time (NTP) servers to use for setting the system time.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (PTPConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"PTPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"PTPConfig represents a PTP (Precision Time Protocol) configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"PTPConfig represents a PTP (Precision Time Protocol) configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"TimeSyncConfigV1Alpha1\",\n\t\t\t\tFieldName: \"ptp\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"devices\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"description: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\n\\n    A PTP device is typically represented as a character device file in the /dev directory,\\n   such as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\\n\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"description: |\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (VLANConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VLANConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VLANConfig is a config document to create a VLAN (virtual LAN) over a parent link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VLANConfig is a config document to create a VLAN (virtual LAN) over a parent link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the VLAN link (interface) to be created.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the VLAN link (interface) to be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"vlanID\",\n\t\t\t\tType:        \"uint16\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"VLAN ID to be used for the VLAN link.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VLAN ID to be used for the VLAN link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"vlanMode\",\n\t\t\t\tType:        \"VLANProtocol\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Set the VLAN mode to use.\\nIf not set, defaults to '802.1q'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Set the VLAN mode to use.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"802.1q\",\n\t\t\t\t\t\"802.1ad\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"parent\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the parent link (interface) on which the VLAN link will be created.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleVLANConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"enp0s3.34\")\n\tdoc.Fields[2].AddExample(\"\", 34)\n\tdoc.Fields[3].AddExample(\"\", \"802.1q\")\n\tdoc.Fields[4].AddExample(\"\", \"enp0s3\")\n\n\treturn doc\n}\n\nfunc (WireguardConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"WireguardConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"WireguardConfig is a config document to create and configure a Wireguard network link.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"WireguardConfig is a config document to create and configure a Wireguard network link.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the Wireguard link (interface).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the Wireguard link (interface).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"privateKey\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies a private key configuration (base64 encoded).\\nCan be generated by `wg genkey`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies a private key configuration (base64 encoded).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"listenPort\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies a device's listening port (UDP).\\nIf not specified, a random port will be chosen.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies a device's listening port (UDP).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"firewallMark\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies a device's firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies a device's firewall mark.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"peers\",\n\t\t\t\tType:        \"[]WireguardPeer\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies a list of peer configurations to apply to a device.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies a list of peer configurations to apply to a device.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:   \"CommonLinkConfig\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleWireguardConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"wg.int\")\n\n\treturn doc\n}\n\nfunc (WireguardPeer) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"WireguardPeer\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"WireguardPeer describes a Wireguard peer configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"WireguardPeer describes a Wireguard peer configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"WireguardConfigV1Alpha1\",\n\t\t\t\tFieldName: \"peers\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"publicKey\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the public key of this peer.\\nCan be extracted from private key by running `wg pubkey < private.key`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the public key of this peer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"presharedKey\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the preshared key for this peer (base64 encoded).\\nCan be generated by `wg genpsk`.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the preshared key for this peer (base64 encoded).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"AddrPort\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the endpoint of this peer entry.\\nFormat: <IP address>:<port>.\\nIf not set, the peer should connect to us without us connecting to it first.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the endpoint of this peer entry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"persistentKeepaliveInterval\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specifies the persistent keepalive interval for this peer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"allowedIPs\",\n\t\t\t\tType:        \"[]Prefix\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file network_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"network\",\n\t\tDescription: \"Package network provides network machine configuration documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tBlackholeRouteConfigV1Alpha1{}.Doc(),\n\t\t\tBondConfigV1Alpha1{}.Doc(),\n\t\t\tBridgeConfigV1Alpha1{}.Doc(),\n\t\t\tBridgeSTPConfig{}.Doc(),\n\t\t\tBridgeVLANConfig{}.Doc(),\n\t\t\tVRFConfigV1Alpha1{}.Doc(),\n\t\t\tDefaultActionConfigV1Alpha1{}.Doc(),\n\t\t\tDHCPv4ConfigV1Alpha1{}.Doc(),\n\t\t\tDHCPv6ConfigV1Alpha1{}.Doc(),\n\t\t\tDummyLinkConfigV1Alpha1{}.Doc(),\n\t\t\tEthernetConfigV1Alpha1{}.Doc(),\n\t\t\tEthernetRingsConfig{}.Doc(),\n\t\t\tEthernetChannelsConfig{}.Doc(),\n\t\t\tHCloudVIPConfigV1Alpha1{}.Doc(),\n\t\t\tHostnameConfigV1Alpha1{}.Doc(),\n\t\t\tKubeSpanConfigV1Alpha1{}.Doc(),\n\t\t\tKubeSpanFiltersConfig{}.Doc(),\n\t\t\tKubespanEndpointsConfigV1Alpha1{}.Doc(),\n\t\t\tLayer2VIPConfigV1Alpha1{}.Doc(),\n\t\t\tLinkConfigV1Alpha1{}.Doc(),\n\t\t\tCommonLinkConfig{}.Doc(),\n\t\t\tAddressConfig{}.Doc(),\n\t\t\tRouteConfig{}.Doc(),\n\t\t\tLinkAliasConfigV1Alpha1{}.Doc(),\n\t\t\tLinkSelector{}.Doc(),\n\t\t\tResolverConfigV1Alpha1{}.Doc(),\n\t\t\tNameserverConfig{}.Doc(),\n\t\t\tSearchDomainsConfig{}.Doc(),\n\t\t\tRoutingRuleConfigV1Alpha1{}.Doc(),\n\t\t\tRuleConfigV1Alpha1{}.Doc(),\n\t\t\tRulePortSelector{}.Doc(),\n\t\t\tIngressRule{}.Doc(),\n\t\t\tStaticHostConfigV1Alpha1{}.Doc(),\n\t\t\tTCPProbeConfigV1Alpha1{}.Doc(),\n\t\t\tCommonProbeConfig{}.Doc(),\n\t\t\tTimeSyncConfigV1Alpha1{}.Doc(),\n\t\t\tNTPConfig{}.Doc(),\n\t\t\tPTPConfig{}.Doc(),\n\t\t\tVLANConfigV1Alpha1{}.Doc(),\n\t\t\tWireguardConfigV1Alpha1{}.Doc(),\n\t\t\tWireguardPeer{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/port_range.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// PortRange is a port range.\n//\n//docgen:nodoc\ntype PortRange struct {\n\tLo uint16\n\tHi uint16\n}\n\n// UnmarshalYAML is a custom unmarshaller for `PortRange`.\nfunc (pr *PortRange) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar port uint16\n\n\tif err := unmarshal(&port); err == nil {\n\t\tpr.Lo = port\n\t\tpr.Hi = port\n\n\t\treturn nil\n\t}\n\n\tvar rangeStr string\n\n\tif err := unmarshal(&rangeStr); err != nil {\n\t\treturn err\n\t}\n\n\tlo, hi, ok := strings.Cut(rangeStr, \"-\")\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid port range: %q\", rangeStr)\n\t}\n\n\tprLo, err := strconv.ParseUint(lo, 10, 16)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid port range: %q\", rangeStr)\n\t}\n\n\tprHi, err := strconv.ParseUint(hi, 10, 16)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid port range: %q\", rangeStr)\n\t}\n\n\tpr.Lo, pr.Hi = uint16(prLo), uint16(prHi)\n\n\treturn nil\n}\n\n// MarshalYAML is a custom marshaller for `PortRange`.\nfunc (pr PortRange) MarshalYAML() (any, error) {\n\tif pr.Lo == pr.Hi {\n\t\treturn pr.Lo, nil\n\t}\n\n\treturn fmt.Sprintf(\"%d-%d\", pr.Lo, pr.Hi), nil\n}\n\n// String implements fmt.Stringer interface.\nfunc (pr PortRange) String() string {\n\treturn fmt.Sprintf(\"%d-%d\", pr.Lo, pr.Hi)\n}\n\n// PortRanges is a slice of port ranges.\n//\n//docgen:nodoc\ntype PortRanges []PortRange\n\n// Validate the port ranges.\nfunc (prs PortRanges) Validate() error {\n\tclone := slices.Clone(prs)\n\tslices.SortFunc(clone, func(a, b PortRange) int {\n\t\treturn cmp.Compare(a.Lo, b.Lo)\n\t})\n\n\tfor i, pr := range clone {\n\t\tif pr.Lo > pr.Hi {\n\t\t\treturn fmt.Errorf(\"invalid port range: %s\", pr)\n\t\t}\n\n\t\tif i > 0 {\n\t\t\tprev := clone[i-1]\n\n\t\t\tif pr.Lo == prev.Lo {\n\t\t\t\treturn fmt.Errorf(\"invalid port range: %s, overlaps with %s\", pr, prev)\n\t\t\t}\n\n\t\t\tif pr.Lo <= prev.Hi {\n\t\t\t\treturn fmt.Errorf(\"invalid port range: %s, overlaps with %s\", pr, prev)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc examplePortRanges1() PortRanges {\n\treturn PortRanges{\n\t\t{Lo: 80, Hi: 80},\n\t\t{Lo: 443, Hi: 443},\n\t}\n}\n\nfunc examplePortRanges2() PortRanges {\n\treturn PortRanges{\n\t\t{Lo: 1200, Hi: 1299},\n\t\t{Lo: 8080, Hi: 8080},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/port_range_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\nfunc TestPortRange(t *testing.T) {\n\tt.Run(\"MarshalYAML\", func(t *testing.T) {\n\t\tfor _, test := range []struct {\n\t\t\tname string\n\t\t\tpr   network.PortRange\n\n\t\t\texpected string\n\t\t}{\n\t\t\t{\n\t\t\t\tname: \"single port\",\n\t\t\t\tpr:   network.PortRange{Lo: 80, Hi: 80},\n\n\t\t\t\texpected: \"80\\n\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"port range\",\n\t\t\t\tpr:   network.PortRange{Lo: 80, Hi: 443},\n\n\t\t\t\texpected: \"80-443\\n\",\n\t\t\t},\n\t\t} {\n\t\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t\tmarshaled, err := yaml.Marshal(test.pr)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, test.expected, string(marshaled))\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"UnmarshalYAML\", func(t *testing.T) {\n\t\tfor _, test := range []struct {\n\t\t\tname string\n\t\t\tyaml string\n\n\t\t\texpected network.PortRange\n\t\t}{\n\t\t\t{\n\t\t\t\tname: \"single port\",\n\t\t\t\tyaml: \"80\\n\",\n\n\t\t\t\texpected: network.PortRange{Lo: 80, Hi: 80},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"port range\",\n\t\t\t\tyaml: \"80-443\\n\",\n\n\t\t\t\texpected: network.PortRange{Lo: 80, Hi: 443},\n\t\t\t},\n\t\t} {\n\t\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t\tvar pr network.PortRange\n\n\t\t\t\terr := yaml.Unmarshal([]byte(test.yaml), &pr)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, test.expected, pr)\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestPortRanges(t *testing.T) {\n\tt.Run(\"Validate\", func(t *testing.T) {\n\t\tfor _, test := range []struct {\n\t\t\tname string\n\t\t\tprs  network.PortRanges\n\n\t\t\texpectedError string\n\t\t}{\n\t\t\t{\n\t\t\t\tname: \"empty\",\n\t\t\t\tprs:  network.PortRanges{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"valid\",\n\t\t\t\tprs:  network.PortRanges{{Lo: 80, Hi: 80}, {Lo: 443, Hi: 443}, {Lo: 8080, Hi: 8081}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"inversion\",\n\t\t\t\tprs:  network.PortRanges{{Lo: 8081, Hi: 8080}},\n\n\t\t\t\texpectedError: \"invalid port range: 8081-8080\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"overlap\",\n\t\t\t\tprs:  network.PortRanges{{Lo: 1000, Hi: 2000}, {Lo: 80, Hi: 80}, {Lo: 1500, Hi: 2500}},\n\n\t\t\t\texpectedError: \"invalid port range: 1500-2500, overlaps with 1000-2000\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"duplicate\",\n\t\t\t\tprs:  network.PortRanges{{Lo: 1000, Hi: 1000}, {Lo: 80, Hi: 80}, {Lo: 1000, Hi: 1000}},\n\n\t\t\t\texpectedError: \"invalid port range: 1000-1000, overlaps with 1000-1000\",\n\t\t\t},\n\t\t} {\n\t\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t\terr := test.prs.Validate()\n\t\t\t\tif test.expectedError != \"\" {\n\t\t\t\t\trequire.EqualError(t, err, test.expectedError)\n\t\t\t\t} else {\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/resolver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// ResolverKind is a ResolverConfig document kind.\nconst ResolverKind = \"ResolverConfig\"\n\nfunc init() {\n\tregistry.Register(ResolverKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &ResolverConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkResolverConfig        = &ResolverConfigV1Alpha1{}\n\t_ container.V1Alpha1ConflictValidator = &ResolverConfigV1Alpha1{}\n)\n\n// ResolverConfigV1Alpha1 is a config document to configure DNS resolving.\n//\n//\texamples:\n//\t  - value: exampleResolverConfigV1Alpha1()\n//\t  - value: exampleResolverConfigV1Alpha2()\n//\talias: ResolverConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ResolverConfig\ntype ResolverConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     A list of nameservers (DNS servers) to use for resolving domain names.\n\t//\n\t//     Nameservers are used to resolve domain names on the host, and they are also\n\t//     propagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\n\t//\n\t//     This overrides any nameservers obtained via DHCP or platform configuration.\n\t//     Default configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\n\tResolverNameservers []NameserverConfig `yaml:\"nameservers,omitempty\"`\n\t//   description: |\n\t//     Configuration for search domains (in /etc/resolv.conf).\n\t//\n\t//     The default is to derive search domains from the hostname FQDN.\n\tResolverSearchDomains SearchDomainsConfig `yaml:\"searchDomains,omitempty\"`\n}\n\n// NameserverConfig represents a single nameserver configuration.\ntype NameserverConfig struct {\n\t//   description: |\n\t//     The IP address of the nameserver.\n\t//   examples:\n\t//    - value: >\n\t//       Addr{netip.MustParseAddr(\"10.0.0.1\")}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+$\n\tAddress Addr `yaml:\"address\"`\n}\n\n// SearchDomainsConfig represents search domains configuration.\ntype SearchDomainsConfig struct {\n\t//   description: |\n\t//     A list of search domains to be used for DNS resolution.\n\t//\n\t//     Search domains are appended to unqualified domain names during DNS resolution.\n\t//     For example, if \"example.com\" is a search domain and a user tries to resolve\n\t//     \"host\", the system will attempt to resolve \"host.example.com\".\n\t//\n\t//     This overrides any search domains obtained via DHCP or platform configuration.\n\t//     The default configuration derives the search domain from the hostname FQDN.\n\tSearchDomains []string `yaml:\"domains,omitempty\"`\n\t//   description: |\n\t//     Disable default search domain configuration from hostname FQDN.\n\t//\n\t//     When set to true, the system will not derive search domains from the hostname FQDN.\n\t//     This allows for a custom configuration of search domains without any defaults.\n\tSearchDisableDefault *bool `yaml:\"disableDefault,omitempty\"`\n}\n\n// NewResolverConfigV1Alpha1 creates a new ResolverConfig config document.\nfunc NewResolverConfigV1Alpha1() *ResolverConfigV1Alpha1 {\n\treturn &ResolverConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ResolverKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleResolverConfigV1Alpha1() *ResolverConfigV1Alpha1 {\n\tcfg := NewResolverConfigV1Alpha1()\n\tcfg.ResolverNameservers = []NameserverConfig{\n\t\t{\n\t\t\tAddress: Addr{netip.MustParseAddr(\"1.1.1.1\")},\n\t\t},\n\t\t{\n\t\t\tAddress: Addr{netip.MustParseAddr(\"ff08::1\")},\n\t\t},\n\t}\n\tcfg.ResolverSearchDomains = SearchDomainsConfig{\n\t\tSearchDomains: []string{\"example.com\"},\n\t}\n\n\treturn cfg\n}\n\nfunc exampleResolverConfigV1Alpha2() *ResolverConfigV1Alpha1 {\n\tcfg := NewResolverConfigV1Alpha1()\n\tcfg.ResolverSearchDomains = SearchDomainsConfig{\n\t\tSearchDisableDefault: new(true),\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *ResolverConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// V1Alpha1ConflictValidate implements container.V1Alpha1ConflictValidator interface.\nfunc (s *ResolverConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Cfg *v1alpha1.Config) error {\n\tif v1alpha1Cfg.SearchDomains() != nil {\n\t\treturn errors.New(\".machine.network.searchDomains is already set in v1alpha1 config\")\n\t}\n\n\tif v1alpha1Cfg.Resolvers() != nil {\n\t\treturn errors.New(\".machine.network.nameservers is already set in v1alpha1 config\")\n\t}\n\n\tif v1alpha1Cfg.DisableSearchDomain() {\n\t\treturn errors.New(\".machine.network.disableSearchDomain is already set in v1alpha1 config\")\n\t}\n\n\treturn nil\n}\n\n// Resolvers implements NetworkResolverConfig interface.\nfunc (s *ResolverConfigV1Alpha1) Resolvers() []netip.Addr {\n\treturn xslices.Map(s.ResolverNameservers, func(ns NameserverConfig) netip.Addr {\n\t\treturn ns.Address.Addr\n\t})\n}\n\n// SearchDomains implements NetworkResolverConfig interface.\nfunc (s *ResolverConfigV1Alpha1) SearchDomains() []string {\n\treturn slices.Clone(s.ResolverSearchDomains.SearchDomains)\n}\n\n// DisableSearchDomain implements NetworkResolverConfig interface.\nfunc (s *ResolverConfigV1Alpha1) DisableSearchDomain() bool {\n\treturn pointer.SafeDeref(s.ResolverSearchDomains.SearchDisableDefault)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/resolver_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n//go:embed testdata/resolverconfig.yaml\nvar expectedResolverConfigDocument []byte\n\nfunc TestResolverConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewResolverConfigV1Alpha1()\n\tcfg.ResolverNameservers = []network.NameserverConfig{\n\t\t{\n\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"10.0.0.1\")},\n\t\t},\n\t\t{\n\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"2001:4860:4860::8888\")},\n\t\t},\n\t}\n\tcfg.ResolverSearchDomains = network.SearchDomainsConfig{\n\t\tSearchDomains:        []string{\"example.org\", \"example.com\"},\n\t\tSearchDisableDefault: new(false),\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedResolverConfigDocument, marshaled)\n}\n\nfunc TestResolverConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedResolverConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.ResolverConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.ResolverKind,\n\t\t},\n\t\tResolverNameservers: []network.NameserverConfig{\n\t\t\t{\n\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"10.0.0.1\")},\n\t\t\t},\n\t\t\t{\n\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"2001:4860:4860::8888\")},\n\t\t\t},\n\t\t},\n\t\tResolverSearchDomains: network.SearchDomainsConfig{\n\t\t\tSearchDomains:        []string{\"example.org\", \"example.com\"},\n\t\t\tSearchDisableDefault: new(false),\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestResolverV1Alpha1Validate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname        string\n\t\tv1alpha1Cfg *v1alpha1.Config\n\t\tcfg         func() *network.ResolverConfigV1Alpha1\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{},\n\t\t\tcfg:         network.NewResolverConfigV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 nameservers set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNameServers: []string{\"1.1.1.1\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewResolverConfigV1Alpha1,\n\n\t\t\texpectedError: \".machine.network.nameservers is already set in v1alpha1 config\",\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 search domains set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tSearches: []string{\"cluster.org\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewResolverConfigV1Alpha1,\n\n\t\t\texpectedError: \".machine.network.searchDomains is already set in v1alpha1 config\",\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 disable search domains set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{ //nolint:staticcheck // legacy config\n\t\t\t\t\t\tNetworkDisableSearchDomain: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewResolverConfigV1Alpha1,\n\n\t\t\texpectedError: \".machine.network.disableSearchDomain is already set in v1alpha1 config\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := test.cfg().V1Alpha1ConflictValidate(test.v1alpha1Cfg)\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/routing_rule.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// RoutingRuleKind is a RoutingRule config document kind.\nconst RoutingRuleKind = \"RoutingRuleConfig\"\n\nfunc init() {\n\tregistry.Register(RoutingRuleKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RoutingRuleConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkRoutingRuleConfig = &RoutingRuleConfigV1Alpha1{}\n\t_ config.NamedDocument            = &RoutingRuleConfigV1Alpha1{}\n\t_ config.Validator                = &RoutingRuleConfigV1Alpha1{}\n)\n\n// RoutingRuleConfigV1Alpha1 is a config document to configure Linux policy routing rules.\n//\n//\texamples:\n//\t  - value: exampleRoutingRuleConfigV1Alpha1()\n//\talias: RoutingRuleConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/RoutingRuleConfig\ntype RoutingRuleConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Priority of the routing rule.\n\t//     Lower values are matched first.\n\t//     Must be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\n\t//     Must be unique across all routing rules in the configuration.\n\t//\n\t//   examples:\n\t//    - value: \"1000\"\n\t//   schemaRequired: true\n\t//   schema:\n\t//     type: string\n\tRulePriority string `yaml:\"name\"`\n\t//   description: |\n\t//     Source address prefix to match.\n\t//     If empty, matches all sources.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"10.0.0.0/8\"\n\t//   schema:\n\t//     type: string\n\tRuleSrc Prefix `yaml:\"src,omitempty\"`\n\t//   description: |\n\t//     Destination address prefix to match.\n\t//     If empty, matches all destinations.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"192.168.0.0/16\"\n\t//   schema:\n\t//     type: string\n\tRuleDst Prefix `yaml:\"dst,omitempty\"`\n\t//   description: |\n\t//     The routing table to look up if the rule matches.\n\t//\n\t//   examples:\n\t//    - value: \"100\"\n\t//   schemaRequired: true\n\t//   schema:\n\t//     type: string\n\tRuleTable nethelpers.RoutingTable `yaml:\"table\"`\n\t//   description: |\n\t//     The action to perform when the rule matches.\n\t//     Defaults to \"unicast\" (table lookup).\n\t//\n\t//   values:\n\t//     - unicast\n\t//     - blackhole\n\t//     - unreachable\n\t//     - prohibit\n\t//   schema:\n\t//     type: integer\n\tRuleAction nethelpers.RoutingRuleAction `yaml:\"action,omitempty\"`\n\t//   description: |\n\t//     Match packets arriving on this interface.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"eth0\"\n\t//   schema:\n\t//     type: string\n\tRuleIIFName string `yaml:\"iifName,omitempty\"`\n\t//   description: |\n\t//     Match packets going out on this interface.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"eth1\"\n\t//   schema:\n\t//     type: string\n\tRuleOIFName string `yaml:\"oifName,omitempty\"`\n\t//   description: |\n\t//     Match packets with this firewall mark value.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       uint32(0x100)\n\t//   schema:\n\t//     type: integer\n\tRuleFwMark uint32 `yaml:\"fwMark,omitempty\"`\n\t//   description: |\n\t//     Mask for the firewall mark comparison.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       uint32(0xff00)\n\t//   schema:\n\t//     type: integer\n\tRuleFwMask uint32 `yaml:\"fwMask,omitempty\"`\n}\n\n// NewRoutingRuleConfigV1Alpha1 creates a new RoutingRuleConfig config document.\nfunc NewRoutingRuleConfigV1Alpha1(priority uint32) *RoutingRuleConfigV1Alpha1 {\n\treturn &RoutingRuleConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RoutingRuleKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tRulePriority: strconv.FormatUint(uint64(priority), 10),\n\t}\n}\n\nfunc exampleRoutingRuleConfigV1Alpha1() *RoutingRuleConfigV1Alpha1 {\n\tcfg := NewRoutingRuleConfigV1Alpha1(1000)\n\tcfg.RuleSrc = Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\tcfg.RuleAction = nethelpers.RoutingRuleActionUnicast\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Name() string {\n\treturn s.RulePriority\n}\n\n// RoutingRuleConfig implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) RoutingRuleConfig() {}\n\nvar reservedPriorities = []uint32{\n\tconstants.LinuxReservedRulePriorityLocal,\n\tconstants.KubeSpanDefaultRulePriority,\n\tconstants.LinuxReservedRulePriorityMain,\n\tconstants.LinuxReservedRulePriorityDefault,\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s *RoutingRuleConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif s.RulePriority == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tpriority, err := strconv.ParseUint(s.RulePriority, 10, 32)\n\tif err != nil {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"invalid name: must be priority parsable unsigned integer: %w\", err))\n\t}\n\n\tif slices.Contains(reservedPriorities, uint32(priority)) {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"priority must be between 1 and 32765 (excluding reserved priorities %v)\", reservedPriorities))\n\t}\n\n\tif s.RuleTable == nethelpers.TableUnspec &&\n\t\t(s.RuleAction == nethelpers.RoutingRuleActionUnspec || s.RuleAction == nethelpers.RoutingRuleActionUnicast) {\n\t\terrs = errors.Join(errs, errors.New(\"either table or a non-unicast action must be specified\"))\n\t}\n\n\tif s.RuleFwMask != 0 && s.RuleFwMark == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"fwMask requires fwMark to be set\"))\n\t}\n\n\treturn nil, errs\n}\n\n// Src implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Src() optional.Optional[netip.Prefix] {\n\tif s.RuleSrc == (Prefix{}) {\n\t\treturn optional.None[netip.Prefix]()\n\t}\n\n\treturn optional.Some(s.RuleSrc.Prefix)\n}\n\n// Dst implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Dst() optional.Optional[netip.Prefix] {\n\tif s.RuleDst == (Prefix{}) {\n\t\treturn optional.None[netip.Prefix]()\n\t}\n\n\treturn optional.Some(s.RuleDst.Prefix)\n}\n\n// Table implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Table() nethelpers.RoutingTable {\n\treturn s.RuleTable\n}\n\n// Priority implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Priority() uint32 {\n\tpriority, _ := strconv.ParseUint(s.RulePriority, 10, 32) //nolint:errcheck\n\n\treturn uint32(priority)\n}\n\n// Action implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) Action() nethelpers.RoutingRuleAction {\n\treturn s.RuleAction\n}\n\n// IIFName implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) IIFName() string {\n\treturn s.RuleIIFName\n}\n\n// OIFName implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) OIFName() string {\n\treturn s.RuleOIFName\n}\n\n// FwMark implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) FwMark() uint32 {\n\treturn s.RuleFwMark\n}\n\n// FwMask implements NetworkRoutingRuleConfig interface.\nfunc (s *RoutingRuleConfigV1Alpha1) FwMask() uint32 {\n\treturn s.RuleFwMask\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/routing_rule_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/routingruleconfig.yaml\nvar expectedRoutingRuleConfigDocument []byte\n\n//nolint:goconst\nfunc TestRoutingRuleConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\tcfg.RuleAction = nethelpers.RoutingRuleActionUnicast\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedRoutingRuleConfigDocument, marshaled)\n}\n\n//nolint:goconst\nfunc TestRoutingRuleConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedRoutingRuleConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.RoutingRuleConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.RoutingRuleKind,\n\t\t},\n\t\tRulePriority: \"1000\",\n\t\tRuleSrc:      network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")},\n\t\tRuleTable:    nethelpers.RoutingTable(100),\n\t\tRuleAction:   nethelpers.RoutingRuleActionUnicast,\n\t}, docs[0])\n}\n\n//nolint:goconst\nfunc TestRoutingRuleConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.RoutingRuleConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\treturn &network.RoutingRuleConfigV1Alpha1{}\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\ninvalid name: must be priority parsable unsigned integer: strconv.ParseUint: parsing \\\"\\\": invalid syntax\\npriority must be between 1 and 32765 (excluding reserved priorities [0 32500 32766 32767])\\neither table or a non-unicast action must be specified\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"fwMask without fwMark\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\t\t\t\tcfg.RuleFwMask = 0xff00\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"fwMask requires fwMark to be set\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing name\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := &network.RoutingRuleConfigV1Alpha1{}\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"reserved priority 32766\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(32766)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"priority must be between 1 and 32765 (excluding reserved priorities [0 32500 32766 32767])\",\n\t\t},\n\t\t{\n\t\t\tname: \"reserved priority 32767\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(32767)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"priority must be between 1 and 32765 (excluding reserved priorities [0 32500 32766 32767])\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid priority 1\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid priority 32765\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(32765)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"no table no action\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"either table or a non-unicast action must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid with table only\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid with blackhole action\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleAction = nethelpers.RoutingRuleActionBlackhole\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid with all fields\",\n\t\t\tcfg: func() *network.RoutingRuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRoutingRuleConfigV1Alpha1(1000)\n\t\t\t\tcfg.RuleSrc = network.Prefix{netip.MustParsePrefix(\"10.0.0.0/8\")}\n\t\t\t\tcfg.RuleDst = network.Prefix{netip.MustParsePrefix(\"192.168.0.0/16\")}\n\t\t\t\tcfg.RuleTable = nethelpers.RoutingTable(100)\n\t\t\t\tcfg.RuleAction = nethelpers.RoutingRuleActionUnicast\n\t\t\t\tcfg.RuleIIFName = \"eth0\"\n\t\t\t\tcfg.RuleOIFName = \"eth1\"\n\t\t\t\tcfg.RuleFwMark = 0x100\n\t\t\t\tcfg.RuleFwMask = 0xff00\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/rule_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/value\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// RuleConfigKind is a rule config document kind.\nconst RuleConfigKind = \"NetworkRuleConfig\"\n\nfunc init() {\n\tregistry.Register(RuleConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &RuleConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkRuleConfigRules  = &RuleConfigV1Alpha1{}\n\t_ config.NetworkRuleConfigSignal = &RuleConfigV1Alpha1{}\n\t_ config.NamedDocument           = &RuleConfigV1Alpha1{}\n\t_ config.Validator               = &RuleConfigV1Alpha1{}\n)\n\n// RuleConfigV1Alpha1 is a network firewall rule config document.\n//\n//\texamples:\n//\t  - value: exampleRuleConfigV1Alpha1()\n//\talias: NetworkRuleConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/NetworkRuleConfig\ntype RuleConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the config document.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Port selector defines which ports and protocols on the host are affected by the rule.\n\tPortSelector RulePortSelector `yaml:\"portSelector\"`\n\t//   description: |\n\t//     Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\n\tIngress IngressConfig `yaml:\"ingress\" merge:\"replace\"`\n}\n\n// RulePortSelector is a port selector for the network rule.\ntype RulePortSelector struct {\n\t//   description: |\n\t//     Ports defines a list of port ranges or single ports.\n\t//     The port ranges are inclusive, and should not overlap.\n\t//   examples:\n\t//    - value: >\n\t//       examplePortRanges1()\n\t//    - value: >\n\t//       examplePortRanges2()\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       oneOf:\n\t//         - type: integer\n\t//         - type: string\n\tPorts PortRanges `yaml:\"ports\" merge:\"replace\"`\n\t//   description: |\n\t//     Protocol defines traffic protocol (e.g. TCP or UDP).\n\t//   values:\n\t//    - \"tcp\"\n\t//    - \"udp\"\n\t//    - \"icmp\"\n\t//    - \"icmpv6\"\n\tProtocol nethelpers.Protocol `yaml:\"protocol\"`\n}\n\n// IngressConfig is a ingress config.\n//\n//docgen:alias\ntype IngressConfig []IngressRule\n\n// IngressRule is a ingress rule.\ntype IngressRule struct {\n\t//   description: |\n\t//     Subnet defines a source subnet.\n\t//   examples:\n\t//    - value: >\n\t//       netip.MustParsePrefix(\"10.3.4.0/24\")\n\t//    - value: >\n\t//       netip.MustParsePrefix(\"2001:db8::/32\")\n\t//    - value: >\n\t//       netip.MustParsePrefix(\"1.3.4.5/32\")\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\tSubnet netip.Prefix `yaml:\"subnet\"`\n\t//   description: |\n\t//     Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\tExcept Prefix `yaml:\"except,omitempty\"`\n}\n\n// NewRuleConfigV1Alpha1 creates a new RuleConfig config document.\nfunc NewRuleConfigV1Alpha1() *RuleConfigV1Alpha1 {\n\treturn &RuleConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       RuleConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleRuleConfigV1Alpha1() *RuleConfigV1Alpha1 {\n\tcfg := NewRuleConfigV1Alpha1()\n\tcfg.MetaName = \"ingress-apid\"\n\tcfg.PortSelector.Protocol = nethelpers.ProtocolTCP\n\tcfg.PortSelector.Ports = PortRanges{\n\t\t{Lo: 50000, Hi: 50000},\n\t}\n\tcfg.Ingress = IngressConfig{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *RuleConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *RuleConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (s *RuleConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif s.MetaName == \"\" {\n\t\treturn nil, errors.New(\"name is required\")\n\t}\n\n\tif len(s.PortSelector.Ports) == 0 {\n\t\treturn nil, errors.New(\"portSelector.ports is required\")\n\t}\n\n\tif err := s.PortSelector.Ports.Validate(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, rule := range s.Ingress {\n\t\tif !rule.Subnet.IsValid() {\n\t\t\treturn nil, fmt.Errorf(\"invalid subnet: %s\", rule.Subnet)\n\t\t}\n\n\t\tif !value.IsZero(rule.Except) && !rule.Except.IsValid() {\n\t\t\treturn nil, fmt.Errorf(\"invalid except: %s\", rule.Except)\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\n// NetworkRuleConfigSignal implements config.NetworkRuleConfigSignal interface.\nfunc (s *RuleConfigV1Alpha1) NetworkRuleConfigSignal() {}\n\n// Rules implements config.NetworkRuleConfigRules interface.\nfunc (s *RuleConfigV1Alpha1) Rules() []config.NetworkRule {\n\treturn []config.NetworkRule{s}\n}\n\n// Protocol implements config.NetworkRule interface.\nfunc (s *RuleConfigV1Alpha1) Protocol() nethelpers.Protocol {\n\treturn s.PortSelector.Protocol\n}\n\n// PortRanges implements config.NetworkRule interface.\nfunc (s *RuleConfigV1Alpha1) PortRanges() [][2]uint16 {\n\treturn xslices.Map(s.PortSelector.Ports, func(pr PortRange) [2]uint16 {\n\t\treturn [2]uint16{pr.Lo, pr.Hi}\n\t})\n}\n\n// Subnets implements config.NetworkRule interface.\nfunc (s *RuleConfigV1Alpha1) Subnets() []netip.Prefix {\n\treturn xslices.Map(s.Ingress, func(rule IngressRule) netip.Prefix {\n\t\treturn rule.Subnet\n\t})\n}\n\n// ExceptSubnets implements config.NetworkRule interface.\nfunc (s *RuleConfigV1Alpha1) ExceptSubnets() []netip.Prefix {\n\treturn xslices.Map(\n\t\txslices.Filter(\n\t\t\ts.Ingress,\n\t\t\tfunc(rule IngressRule) bool {\n\t\t\t\treturn rule.Except.IsValid()\n\t\t\t},\n\t\t),\n\t\tfunc(rule IngressRule) netip.Prefix {\n\t\t\treturn rule.Except.Prefix\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/rule_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/ruleconfig.yaml\nvar expectedRuleConfigDocument []byte\n\nfunc TestRuleConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewRuleConfigV1Alpha1()\n\tcfg.MetaName = \"test\"\n\n\tcfg.PortSelector = network.RulePortSelector{\n\t\tProtocol: nethelpers.ProtocolUDP,\n\t\tPorts: network.PortRanges{\n\t\t\t{Lo: 53, Hi: 53},\n\t\t\t{Lo: 8000, Hi: 9000},\n\t\t},\n\t}\n\n\tcfg.Ingress = network.IngressConfig{\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\tExcept: network.Prefix{netip.MustParsePrefix(\"192.168.0.3/32\")},\n\t\t},\n\t\t{\n\t\t\tSubnet: netip.MustParsePrefix(\"2001::/16\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedRuleConfigDocument, marshaled)\n}\n\nfunc TestRuleConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedRuleConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.RuleConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.RuleConfigKind,\n\t\t},\n\t\tMetaName: \"test\",\n\t\tPortSelector: network.RulePortSelector{\n\t\t\tProtocol: nethelpers.ProtocolUDP,\n\t\t\tPorts: network.PortRanges{\n\t\t\t\t{Lo: 53, Hi: 53},\n\t\t\t\t{Lo: 8000, Hi: 9000},\n\t\t\t},\n\t\t},\n\t\tIngress: network.IngressConfig{\n\t\t\t{\n\t\t\t\tSubnet: netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\tExcept: network.Prefix{netip.MustParsePrefix(\"192.168.0.3/32\")},\n\t\t\t},\n\t\t\t{\n\t\t\t\tSubnet: netip.MustParsePrefix(\"2001::/16\"),\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestRuleConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.RuleConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  network.NewRuleConfigV1Alpha1,\n\n\t\t\texpectedError: \"name is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"no ports\",\n\t\t\tcfg: func() *network.RuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRuleConfigV1Alpha1()\n\t\t\t\tcfg.MetaName = \"-\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"portSelector.ports is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid port range\",\n\t\t\tcfg: func() *network.RuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRuleConfigV1Alpha1()\n\t\t\t\tcfg.MetaName = \"-\"\n\t\t\t\tcfg.PortSelector.Ports = network.PortRanges{\n\t\t\t\t\t{Lo: 80, Hi: 80},\n\t\t\t\t\t{Lo: 80, Hi: 79},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid port range: 80-79\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid subnet\",\n\t\t\tcfg: func() *network.RuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRuleConfigV1Alpha1()\n\t\t\t\tcfg.MetaName = \"--\"\n\t\t\t\tcfg.PortSelector.Ports = network.PortRanges{\n\t\t\t\t\t{Lo: 80, Hi: 80},\n\t\t\t\t}\n\t\t\t\tcfg.Ingress = network.IngressConfig{\n\t\t\t\t\t{},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid subnet: invalid Prefix\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.RuleConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewRuleConfigV1Alpha1()\n\t\t\t\tcfg.MetaName = \"--\"\n\t\t\t\tcfg.PortSelector.Ports = network.PortRanges{\n\t\t\t\t\t{Lo: 80, Hi: 80},\n\t\t\t\t\t{Lo: 6443, Hi: 6444},\n\t\t\t\t}\n\t\t\t\tcfg.Ingress = network.IngressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tSubnet: netip.MustParsePrefix(\"192.168.0.0/16\"),\n\t\t\t\t\t\tExcept: network.Prefix{netip.MustParsePrefix(\"192.168.3.0/24\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tSubnet: netip.MustParsePrefix(\"2001::/16\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/static_host.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// StaticHostKind is a StaticHost config document kind.\nconst StaticHostKind = \"StaticHostConfig\"\n\nfunc init() {\n\tregistry.Register(StaticHostKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &StaticHostConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NamedDocument           = &StaticHostConfigV1Alpha1{}\n\t_ config.Validator               = &StaticHostConfigV1Alpha1{}\n\t_ config.NetworkStaticHostConfig = &StaticHostConfigV1Alpha1{}\n)\n\n// StaticHostConfigV1Alpha1 is a config document to set /etc/hosts entries.\n//\n//\texamples:\n//\t  - value: exampleStaticHostConfigV1Alpha1()\n//\talias: StaticHostConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/StaticHostConfig\ntype StaticHostConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     IP address (IPv4 or IPv6) to map the hostnames to.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     List of hostnames to map to the IP address.\n\tHostnames []string `yaml:\"hostnames\"`\n}\n\n// NewStaticHostConfigV1Alpha1 creates a new StaticHostConfig config document.\nfunc NewStaticHostConfigV1Alpha1(name string) *StaticHostConfigV1Alpha1 {\n\treturn &StaticHostConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       StaticHostKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleStaticHostConfigV1Alpha1() *StaticHostConfigV1Alpha1 {\n\tcfg := NewStaticHostConfigV1Alpha1(\"10.5.0.2\")\n\tcfg.Hostnames = []string{\"my-server\", \"my-server.example.org\"}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *StaticHostConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *StaticHostConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Validate implements config.Validator interface.\nfunc (s *StaticHostConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name is required\"))\n\t}\n\n\tif _, err := netip.ParseAddr(s.MetaName); err != nil {\n\t\terrs = errors.Join(errs, errors.New(\"name must be a valid IP address\"))\n\t}\n\n\tif len(s.Hostnames) == 0 {\n\t\terrs = errors.Join(errs, errors.New(\"at least one hostname is required\"))\n\t}\n\n\treturn nil, errs\n}\n\n// IP implements ExtraHost interface.\nfunc (s *StaticHostConfigV1Alpha1) IP() string {\n\treturn s.MetaName\n}\n\n// Aliases implements ExtraHost interface.\nfunc (s *StaticHostConfigV1Alpha1) Aliases() []string {\n\treturn s.Hostnames\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/static_host_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/statichostconfig.yaml\nvar expectedStaticHostConfigDocument []byte\n\nfunc TestStaticHostMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewStaticHostConfigV1Alpha1(\"10.5.0.2\")\n\tcfg.Hostnames = []string{\"example.org\", \"example.com\"}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedStaticHostConfigDocument, marshaled)\n}\n\nfunc TestHostConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.StaticHostConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.StaticHostConfigV1Alpha1 {\n\t\t\t\treturn network.NewStaticHostConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name is required\\nname must be a valid IP address\\nat least one hostname is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid ip\",\n\t\t\tcfg: func() *network.StaticHostConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewStaticHostConfigV1Alpha1(\"ab\")\n\t\t\t\tcfg.Hostnames = []string{\"example.org\", \"example.com\"}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"name must be a valid IP address\",\n\t\t},\n\t\t{\n\t\t\tname: \"no hostnames\",\n\t\t\tcfg: func() *network.StaticHostConfigV1Alpha1 {\n\t\t\t\treturn network.NewStaticHostConfigV1Alpha1(\"10.5.0.2\")\n\t\t\t},\n\n\t\t\texpectedError: \"at least one hostname is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.StaticHostConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewStaticHostConfigV1Alpha1(\"10.5.0.2\")\n\t\t\t\tcfg.Hostnames = []string{\"example.org\", \"example.com\"}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/tcp_probe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// TCPProbeKind is a TCPProbe config document kind.\nconst TCPProbeKind = \"TCPProbeConfig\"\n\nfunc init() {\n\tregistry.Register(TCPProbeKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &TCPProbeConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NamedDocument         = &TCPProbeConfigV1Alpha1{}\n\t_ config.Validator             = &TCPProbeConfigV1Alpha1{}\n\t_ config.NetworkTCPProbeConfig = &TCPProbeConfigV1Alpha1{}\n)\n\n// TCPProbeConfigV1Alpha1 is a config document to configure network TCP connectivity probes.\n//\n//\texamples:\n//\t  - value: exampleTCPProbeConfigV1Alpha1()\n//\talias: TCPProbeConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/TCPProbeConfig\ntype TCPProbeConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the probe.\n\t//   examples:\n\t//    - value: >\n\t//       \"proxy-check\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//nolint:embeddedstructfieldcheck\n\tCommonProbeConfig `yaml:\",inline\"`\n\t//   description: |\n\t//     Endpoint to probe in the format host:port.\n\t//   examples:\n\t//    - value: >\n\t//       \"proxy.example.com:3128\"\n\t//   schemaRequired: true\n\tTCPEndpoint string `yaml:\"endpoint\"`\n\t//   description: |\n\t//     Timeout for the probe.\n\t//     Defaults to 10s.\n\t//   examples:\n\t//    - value: >\n\t//       10 * time.Second\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tTCPTimeout time.Duration `yaml:\"timeout,omitempty\"`\n}\n\n// CommonProbeConfig holds fields common to all probe types.\ntype CommonProbeConfig struct {\n\t//   description: |\n\t//     Interval between probe attempts.\n\t//     Defaults to 1s.\n\t//   examples:\n\t//    - value: >\n\t//       time.Second\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tProbeInterval time.Duration `yaml:\"interval,omitempty\"`\n\t//   description: |\n\t//     Number of consecutive failures for the probe to be considered failed after having succeeded.\n\t//     Defaults to 0 (immediately fail on first failure).\n\t//   examples:\n\t//    - value: >\n\t//       3\n\tProbeFailureThreshold int `yaml:\"failureThreshold,omitempty\"`\n}\n\n// NewTCPProbeConfigV1Alpha1 creates a new TCPProbeConfigV1Alpha1 config document.\nfunc NewTCPProbeConfigV1Alpha1(name string) *TCPProbeConfigV1Alpha1 {\n\treturn &TCPProbeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       TCPProbeKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\n// Name implements config.NamedDocument interface.\nfunc (p *TCPProbeConfigV1Alpha1) Name() string {\n\treturn p.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (p *TCPProbeConfigV1Alpha1) Clone() config.Document {\n\treturn p.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (p *TCPProbeConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif p.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"probe name is required\"))\n\t}\n\n\tif p.TCPEndpoint == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"TCP probe endpoint is required\"))\n\t}\n\n\tif p.TCPTimeout < 0 {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"TCP probe timeout cannot be negative: %s\", p.TCPTimeout))\n\t}\n\n\textraWarnings, extraErrs := p.CommonProbeConfig.Validate()\n\terrs = errors.Join(errs, extraErrs)\n\n\twarnings = append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\nfunc exampleTCPProbeConfigV1Alpha1() *TCPProbeConfigV1Alpha1 {\n\tcfg := NewTCPProbeConfigV1Alpha1(\"proxy-check\")\n\n\tcfg.CommonProbeConfig = CommonProbeConfig{\n\t\tProbeInterval:         time.Second,\n\t\tProbeFailureThreshold: 3,\n\t}\n\tcfg.TCPEndpoint = \"proxy.example.com:3128\"\n\tcfg.TCPTimeout = 10 * time.Second\n\n\treturn cfg\n}\n\n// Interval implements config.NetworkCommonProbeConfig interface.\nfunc (p *CommonProbeConfig) Interval() time.Duration {\n\tif p.ProbeInterval == 0 {\n\t\treturn time.Second\n\t}\n\n\treturn p.ProbeInterval\n}\n\n// FailureThreshold implements config.NetworkCommonProbeConfig interface.\nfunc (p *CommonProbeConfig) FailureThreshold() int {\n\treturn p.ProbeFailureThreshold\n}\n\n// Validate the common probe config.\nfunc (p *CommonProbeConfig) Validate() ([]string, error) {\n\tvar errs error\n\n\tif p.ProbeInterval < 0 {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"probe interval cannot be negative: %s\", p.ProbeInterval))\n\t}\n\n\tif p.ProbeFailureThreshold < 0 {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"probe failure threshold cannot be negative: %d\", p.ProbeFailureThreshold))\n\t}\n\n\treturn nil, errs\n}\n\n// Endpoint implements config.NetworkTCPProbeConfig interface.\nfunc (p *TCPProbeConfigV1Alpha1) Endpoint() string {\n\treturn p.TCPEndpoint\n}\n\n// Timeout implements config.NetworkTCPProbeConfig interface.\nfunc (p *TCPProbeConfigV1Alpha1) Timeout() time.Duration {\n\tif p.TCPTimeout == 0 {\n\t\treturn 10 * time.Second\n\t}\n\n\treturn p.TCPTimeout\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/tcp_probe_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/tcpprobeconfig.yaml\nvar expectedTCPProbeConfigDocument []byte\n\nfunc TestTCPProbeConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewTCPProbeConfigV1Alpha1(\"proxy-check\")\n\tcfg.CommonProbeConfig = network.CommonProbeConfig{\n\t\tProbeInterval:         time.Second,\n\t\tProbeFailureThreshold: 3,\n\t}\n\tcfg.TCPEndpoint = \"proxy.example.com:3128\"\n\tcfg.TCPTimeout = 10 * time.Second\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedTCPProbeConfigDocument, marshaled)\n}\n\nfunc TestTCPProbeConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedTCPProbeConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.TCPProbeConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.TCPProbeKind,\n\t\t},\n\t\tMetaName: \"proxy-check\",\n\t\tCommonProbeConfig: network.CommonProbeConfig{\n\t\t\tProbeInterval:         time.Second,\n\t\t\tProbeFailureThreshold: 3,\n\t\t},\n\t\tTCPEndpoint: \"proxy.example.com:3128\",\n\t\tTCPTimeout:  10 * time.Second,\n\t}, docs[0])\n}\n\nfunc TestTCPProbeConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.TCPProbeConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"valid config\",\n\t\t\tcfg: func() *network.TCPProbeConfigV1Alpha1 {\n\t\t\t\tc := network.NewTCPProbeConfigV1Alpha1(\"test-probe\")\n\t\t\t\tc.CommonProbeConfig = network.CommonProbeConfig{\n\t\t\t\t\tProbeInterval:         time.Second,\n\t\t\t\t\tProbeFailureThreshold: 3,\n\t\t\t\t}\n\t\t\t\tc.TCPEndpoint = \"example.com:80\"\n\t\t\t\tc.TCPTimeout = 5 * time.Second\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"missing name\",\n\t\t\tcfg: func() *network.TCPProbeConfigV1Alpha1 {\n\t\t\t\tc := network.NewTCPProbeConfigV1Alpha1(\"\")\n\t\t\t\tc.TCPEndpoint = \"example.com:80\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"probe name is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing TCP endpoint\",\n\t\t\tcfg: func() *network.TCPProbeConfigV1Alpha1 {\n\t\t\t\tc := network.NewTCPProbeConfigV1Alpha1(\"probe44\")\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"TCP probe endpoint is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"negative values\",\n\t\t\tcfg: func() *network.TCPProbeConfigV1Alpha1 {\n\t\t\t\tc := network.NewTCPProbeConfigV1Alpha1(\"probe33\")\n\t\t\t\tc.CommonProbeConfig.ProbeFailureThreshold = -1\n\t\t\t\tc.CommonProbeConfig.ProbeInterval = -time.Second\n\t\t\t\tc.TCPTimeout = -5 * time.Second\n\t\t\t\tc.TCPEndpoint = \"example.com:443\"\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t\texpectedError: \"TCP probe timeout cannot be negative: -5s\\nprobe interval cannot be negative: -1s\\nprobe failure threshold cannot be negative: -1\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.TCPProbeConfigV1Alpha1 {\n\t\t\t\treturn network.NewTCPProbeConfigV1Alpha1(\"\")\n\t\t\t},\n\t\t\texpectedError: \"probe name is required\\nTCP probe endpoint is required\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/blackholerouteconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: BlackholeRouteConfig\nname: 169.254.1.1/32\nmetric: 2000\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/bondconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: BondConfig\nname: agg.0\nlinks:\n    - eth0\n    - eth1\nbondMode: 802.3ad\nmiimon: 100\nupdelay: 200\ndowndelay: 200\nxmitHashPolicy: layer3+4\nlacpRate: slow\nfailOverMac: follow\nadActorSysPrio: 65535\nresendIGMP: 1\npacketsPerSlave: 1\nup: true\naddresses:\n    - address: 1.2.3.4/24\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/bridgeconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: BridgeConfig\nname: bridge.1\nlinks:\n    - eno1\n    - eno5\nstp:\n    enabled: true\nvlan:\n    filtering: false\nup: true\naddresses:\n    - address: 1.2.3.5/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/defaultactionconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: block\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/dhcpv4config.yaml",
    "content": "apiVersion: v1alpha1\nkind: DHCPv4Config\nname: enp0s3\nrouteMetric: 512\nignoreHostname: true\nclientIdentifier: duid\nduidRaw: 00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/dhcpv6config.yaml",
    "content": "apiVersion: v1alpha1\nkind: DHCPv6Config\nname: enp0s3\nclientIdentifier: mac\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/dummylinkconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: DummyLinkConfig\nname: dummy1\nhardwareAddr: 2e:3c:4d:5e:6f:70\nup: true\naddresses:\n    - address: 192.168.1.100/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/ethernetconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: EthernetConfig\nname: enp0s1\nfeatures:\n    tx-checksum-ipv4: true\nrings:\n    rx: 16\nchannels:\n    combined: 1\nwakeOnLan:\n    - unicast\n    - multicast\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/hcloudvipconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: HCloudVIPConfig\nname: 1.2.3.4\nlink: net33\napiToken: s3cr3t-t0k3n\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/hostnameconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/kubespanconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: KubeSpanConfig\nenabled: true\nadvertiseKubernetesNetworks: false\nallowDownPeerBypass: false\nmtu: 1420\nfilters:\n    excludeAdvertisedNetworks:\n        - 2007::/64\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/kubespanendpointsconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: KubeSpanEndpointsConfig\nextraAnnouncedEndpoints:\n    - 3.4.5.6:123\n    - 10.11.12.13:456\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/layer2vipconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: Layer2VIPConfig\nname: 1.2.3.4\nlink: net0\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/linkaliasconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: LinkAliasConfig\nname: net0\nselector:\n    match: mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/linkconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: LinkConfig\nname: enp0s1\nup: true\nmtu: 9000\naddresses:\n    - address: 192.168.1.100/24\n    - address: 2001:db8::1/64\n      routePriority: 100\nroutes:\n    - destination: 10.3.5.0/24\n      gateway: 10.3.5.1\n    - gateway: fe80::1\nmulticast: true\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/resolverconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: ResolverConfig\nnameservers:\n    - address: 10.0.0.1\n    - address: 2001:4860:4860::8888\nsearchDomains:\n    domains:\n        - example.org\n        - example.com\n    disableDefault: false\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/routingruleconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: RoutingRuleConfig\nname: \"1000\"\nsrc: 10.0.0.0/8\ntable: \"100\"\naction: unicast\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/ruleconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: NetworkRuleConfig\nname: test\nportSelector:\n    ports:\n        - 53\n        - 8000-9000\n    protocol: udp\ningress:\n    - subnet: 192.168.0.0/16\n      except: 192.168.0.3/32\n    - subnet: 2001::/16\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/statichostconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: StaticHostConfig\nname: 10.5.0.2\nhostnames:\n    - example.org\n    - example.com\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/tcpprobeconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: TCPProbeConfig\nname: proxy-check\ninterval: 1s\nfailureThreshold: 3\nendpoint: proxy.example.com:3128\ntimeout: 10s\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/timesyncconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: TimeSyncConfig\nenabled: true\nbootTimeout: 1m0s\nntp:\n    servers:\n        - time.cloudflare.com\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/vlanconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: VLANConfig\nname: enp0s3.2\nvlanID: 2\nvlanMode: 802.1q\nparent: enp0s3\nup: true\naddresses:\n    - address: 192.168.1.100/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/vrfconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: VRFConfig\nname: vrf-blue\nlinks:\n    - eno1\n    - eno5\ntable: \"123\"\nup: true\naddresses:\n    - address: 1.2.3.5/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/wireguardconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: WireguardConfig\nname: wg.int\nprivateKey: GA1E1VB+g41Dl0+UH2TMW9C5953y+moVg6JIIqkJbmw=\nlistenPort: 5042\nfirewallMark: 176\npeers:\n    - publicKey: 735jkJdcVDninU5PzLJ/S+bfN6Q3QOk6svWrVLMJQAk=\n      allowedIPs:\n        - 192.168.1.0/24\n    - publicKey: uvdlJNva1X8/OCOZM+0gGT4Yu9x20odd3AWbbQUF7nM=\n      presharedKey: 6j4UMxwszrHVZZUjY8/SFsZMjgaHkxV7yp9Tz05btho=\n      endpoint: 10.3.4.3:2222\nup: true\naddresses:\n    - address: 192.168.1.100/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/testdata/wireguardconfig_redacted.yaml",
    "content": "apiVersion: v1alpha1\nkind: WireguardConfig\nname: wg.int\nprivateKey: REDACTED\nlistenPort: 5042\nfirewallMark: 176\npeers:\n    - publicKey: 735jkJdcVDninU5PzLJ/S+bfN6Q3QOk6svWrVLMJQAk=\n      allowedIPs:\n        - 192.168.1.0/24\n    - publicKey: uvdlJNva1X8/OCOZM+0gGT4Yu9x20odd3AWbbQUF7nM=\n      presharedKey: REDACTED\n      endpoint: 10.3.4.3:2222\nup: true\naddresses:\n    - address: 192.168.1.100/32\n"
  },
  {
    "path": "pkg/machinery/config/types/network/time_sync.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// TimeSyncKind is a TimeSyncConfig document kind.\nconst TimeSyncKind = \"TimeSyncConfig\"\n\nfunc init() {\n\tregistry.Register(TimeSyncKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &TimeSyncConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkTimeSyncConfig        = &TimeSyncConfigV1Alpha1{}\n\t_ config.Validator                    = &TimeSyncConfigV1Alpha1{}\n\t_ container.V1Alpha1ConflictValidator = &TimeSyncConfigV1Alpha1{}\n)\n\n// TimeSyncConfigV1Alpha1 is a config document to configure time synchronization (NTP).\n//\n//\texamples:\n//\t  - value: exampleTimeSyncConfigV1Alpha1()\n//\t  - value: exampleTimeSyncConfigV1Alpha2()\n//\talias: TimeSyncConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/TimeSyncConfig\ntype TimeSyncConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Indicates if the time synchronization is enabled for the machine.\n\t//     Defaults to `true`.\n\tTimeEnabled *bool `yaml:\"enabled,omitempty\"`\n\t//   description: |\n\t//     Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\n\t//     NTP sync will be still running in the background.\n\t//     Defaults to \"infinity\" (waiting forever for time sync)\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tTimeBootTimeout time.Duration `yaml:\"bootTimeout,omitempty\"`\n\t//   description: |\n\t//     Specifies NTP configuration to sync the time over network.\n\t//     Mutually exclusive with PTP configuration.\n\tTimeNTP *NTPConfig `yaml:\"ntp,omitempty\"`\n\t//   description: |\n\t//     Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\n\t//     Mutually exclusive with NTP configuration.\n\tTimePTP *PTPConfig `yaml:\"ptp,omitempty\"`\n}\n\n// NTPConfig represents a NTP server configuration.\ntype NTPConfig struct {\n\t//   description: |\n\t//     Specifies time (NTP) servers to use for setting the system time.\n\t//     Defaults to `time.cloudflare.com`.\n\tServers []string `yaml:\"servers,omitempty\"`\n}\n\n// PTPConfig represents a PTP (Precision Time Protocol) configuration.\ntype PTPConfig struct {\n\t//   description: |\n\t//     A list of PTP devices to sync with (e.g. provided by the hypervisor).\n\t//\n\t//     A PTP device is typically represented as a character device file in the /dev directory,\n\t//\t   such as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\n\t//     with an external time source that supports the Precision Time Protocol.\n\tDevices []string `yaml:\"devices,omitempty\"`\n}\n\n// NewTimeSyncConfigV1Alpha1 creates a new TimeSyncConfig config document.\nfunc NewTimeSyncConfigV1Alpha1() *TimeSyncConfigV1Alpha1 {\n\treturn &TimeSyncConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       TimeSyncKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleTimeSyncConfigV1Alpha1() *TimeSyncConfigV1Alpha1 {\n\tcfg := NewTimeSyncConfigV1Alpha1()\n\tcfg.TimeNTP = &NTPConfig{\n\t\tServers: []string{\"pool.ntp.org\"},\n\t}\n\n\treturn cfg\n}\n\nfunc exampleTimeSyncConfigV1Alpha2() *TimeSyncConfigV1Alpha1 {\n\tcfg := NewTimeSyncConfigV1Alpha1()\n\tcfg.TimePTP = &PTPConfig{\n\t\tDevices: []string{\"/dev/ptp0\"},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *TimeSyncConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (s *TimeSyncConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar errs error\n\n\tif s.TimeBootTimeout < 0 {\n\t\terrs = errors.Join(errs, errors.New(\"bootTimeout cannot be negative\"))\n\t}\n\n\tif s.TimeNTP != nil && s.TimePTP != nil {\n\t\terrs = errors.Join(errs, errors.New(\"only one of ntp or ptp configuration can be specified\"))\n\t}\n\n\treturn nil, errs\n}\n\n// V1Alpha1ConflictValidate implements container.V1Alpha1ConflictValidator interface.\nfunc (s *TimeSyncConfigV1Alpha1) V1Alpha1ConflictValidate(v1alpha1Cfg *v1alpha1.Config) error {\n\tv1tsc := v1alpha1Cfg.NetworkTimeSyncConfig()\n\n\tif v1tsc == nil {\n\t\treturn nil\n\t}\n\n\tif v1tsc.Disabled() {\n\t\treturn errors.New(\"time sync cannot be disabled in both v1alpha1 and new-style configuration\")\n\t}\n\n\tif len(v1tsc.Servers()) > 0 {\n\t\treturn errors.New(\"time servers cannot be specified in both v1alpha1 and new-style configuration\")\n\t}\n\n\tif v1tsc.BootTimeout() != 0 {\n\t\treturn errors.New(\"boot timeout cannot be specified in both v1alpha1 and new-style configuration\")\n\t}\n\n\treturn nil\n}\n\n// Disabled implements config.NetworkTimeSyncConfig interface.\nfunc (s *TimeSyncConfigV1Alpha1) Disabled() bool {\n\tif s.TimeEnabled == nil {\n\t\treturn false\n\t}\n\n\treturn !*s.TimeEnabled\n}\n\n// BootTimeout implements config.NetworkTimeSyncConfig interface.\nfunc (s *TimeSyncConfigV1Alpha1) BootTimeout() time.Duration {\n\treturn s.TimeBootTimeout\n}\n\n// Servers implements config.NetworkTimeSyncConfig interface.\nfunc (s *TimeSyncConfigV1Alpha1) Servers() []string {\n\t// The configuration validates that only one of the NTP or PTP is set.\n\tif s.TimeNTP != nil {\n\t\treturn s.TimeNTP.Servers\n\t}\n\n\tif s.TimePTP != nil {\n\t\treturn s.TimePTP.Devices\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/time_sync_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n//go:embed testdata/timesyncconfig.yaml\nvar expectedTimeSyncConfigDocument []byte\n\nfunc TestTimeSyncConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewTimeSyncConfigV1Alpha1()\n\tcfg.TimeEnabled = new(true)\n\tcfg.TimeBootTimeout = time.Minute\n\tcfg.TimeNTP = &network.NTPConfig{\n\t\tServers: []string{\"time.cloudflare.com\"},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedTimeSyncConfigDocument, marshaled)\n}\n\nfunc TestTimeSyncConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedTimeSyncConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.TimeSyncConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.TimeSyncKind,\n\t\t},\n\t\tTimeEnabled:     new(true),\n\t\tTimeBootTimeout: time.Minute,\n\t\tTimeNTP: &network.NTPConfig{\n\t\t\tServers: []string{\"time.cloudflare.com\"},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestTimeSyncValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.TimeSyncConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  network.NewTimeSyncConfigV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"both NTP and PTP set\",\n\t\t\tcfg: func() *network.TimeSyncConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewTimeSyncConfigV1Alpha1()\n\t\t\t\tcfg.TimeNTP = &network.NTPConfig{\n\t\t\t\t\tServers: []string{\"pool.ntp.org\"},\n\t\t\t\t}\n\t\t\t\tcfg.TimePTP = &network.PTPConfig{\n\t\t\t\t\tDevices: []string{\"/dev/ptp0\"},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"only one of ntp or ptp configuration can be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"negative boot timeout\",\n\t\t\tcfg: func() *network.TimeSyncConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewTimeSyncConfigV1Alpha1()\n\t\t\t\tcfg.TimeBootTimeout = -time.Second\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"bootTimeout cannot be negative\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid NTP config\",\n\t\t\tcfg: func() *network.TimeSyncConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewTimeSyncConfigV1Alpha1()\n\t\t\t\tcfg.TimeNTP = &network.NTPConfig{\n\t\t\t\t\tServers: []string{\"pool.ntp.org\"},\n\t\t\t\t}\n\t\t\t\tcfg.TimeBootTimeout = time.Second\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTimeSyncV1Alpha1Validate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname        string\n\t\tv1alpha1Cfg *v1alpha1.Config\n\t\tcfg         func() *network.TimeSyncConfigV1Alpha1\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{},\n\t\t\tcfg:         network.NewTimeSyncConfigV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 timeservers set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeServers: []string{\"za.pool.ntp.org\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewTimeSyncConfigV1Alpha1,\n\n\t\t\texpectedError: \"time servers cannot be specified in both v1alpha1 and new-style configuration\",\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 boot timeout set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeBootTimeout: time.Second,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewTimeSyncConfigV1Alpha1,\n\n\t\t\texpectedError: \"boot timeout cannot be specified in both v1alpha1 and new-style configuration\",\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 disable set\",\n\t\t\tv1alpha1Cfg: &v1alpha1.Config{\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\tTimeDisabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcfg: network.NewTimeSyncConfigV1Alpha1,\n\n\t\t\texpectedError: \"time sync cannot be disabled in both v1alpha1 and new-style configuration\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := test.cfg().V1Alpha1ConflictValidate(test.v1alpha1Cfg)\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/vlan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// VLANKind is a VLAN config document kind.\nconst VLANKind = \"VLANConfig\"\n\nfunc init() {\n\tregistry.Register(VLANKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &VLANConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkVLANConfig   = &VLANConfigV1Alpha1{}\n\t_ config.ConflictingDocument = &VLANConfigV1Alpha1{}\n\t_ config.NamedDocument       = &VLANConfigV1Alpha1{}\n\t_ config.Validator           = &VLANConfigV1Alpha1{}\n)\n\n// VLANConfigV1Alpha1 is a config document to create a VLAN (virtual LAN) over a parent link.\n//\n//\texamples:\n//\t  - value: exampleVLANConfigV1Alpha1()\n//\talias: VLANConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/VLANConfig\ntype VLANConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the VLAN link (interface) to be created.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"enp0s3.34\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     VLAN ID to be used for the VLAN link.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       34\n\t//   schemaRequired: true\n\tVLANIDConfig uint16 `yaml:\"vlanID,omitempty\"`\n\t//   description: |\n\t//     Set the VLAN mode to use.\n\t//     If not set, defaults to '802.1q'.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"802.1q\"\n\t//   values:\n\t//     - \"802.1q\"\n\t//     - \"802.1ad\"\n\tVLANModeConfig *nethelpers.VLANProtocol `yaml:\"vlanMode,omitempty\"`\n\t//   description: |\n\t//     Name of the parent link (interface) on which the VLAN link will be created.\n\t//     Link aliases can be used here as well.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"enp0s3\"\n\t//   schemaRequired: true\n\tParentLinkConfig string `yaml:\"parent,omitempty\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// NewVLANConfigV1Alpha1 creates a new VLANConfig config document.\nfunc NewVLANConfigV1Alpha1(name string) *VLANConfigV1Alpha1 {\n\treturn &VLANConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       VLANKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleVLANConfigV1Alpha1() *VLANConfigV1Alpha1 {\n\tcfg := NewVLANConfigV1Alpha1(\"enp0s3.34\")\n\tcfg.VLANIDConfig = 34\n\tcfg.ParentLinkConfig = \"enp0s3\"\n\tcfg.LinkAddresses = []AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t},\n\t}\n\tcfg.LinkRoutes = []RouteConfig{\n\t\t{\n\t\t\tRouteDestination: Prefix{netip.MustParsePrefix(\"192.168.0.0/16\")},\n\t\t\tRouteGateway:     Addr{netip.MustParseAddr(\"192.168.1.1\")},\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *VLANConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *VLANConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// VLANConfig implements NetworkVLANConfig interface.\nfunc (s *VLANConfigV1Alpha1) VLANConfig() {}\n\n// VLANID returns the VLAN ID.\nfunc (s *VLANConfigV1Alpha1) VLANID() uint16 {\n\treturn s.VLANIDConfig\n}\n\n// ParentLink returns the parent link name.\nfunc (s *VLANConfigV1Alpha1) ParentLink() string {\n\treturn s.ParentLinkConfig\n}\n\n// VLANMode returns the VLAN mode.\nfunc (s *VLANConfigV1Alpha1) VLANMode() optional.Optional[nethelpers.VLANProtocol] {\n\tif s.VLANModeConfig == nil {\n\t\treturn optional.None[nethelpers.VLANProtocol]()\n\t}\n\n\treturn optional.Some(*s.VLANModeConfig)\n}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *VLANConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(VLANKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *VLANConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif s.VLANIDConfig == 0 || s.VLANIDConfig > 4094 {\n\t\terrs = errors.Join(errs, errors.New(\"vlanID must be specified and between 1 and 4094\"))\n\t}\n\n\tif s.ParentLinkConfig == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"parent must be specified\"))\n\t}\n\n\tswitch {\n\tcase s.VLANModeConfig == nil:\n\t\t// default is 802.1q\n\tcase *s.VLANModeConfig != nethelpers.VLANProtocol8021Q && *s.VLANModeConfig != nethelpers.VLANProtocol8021AD:\n\t\terrs = errors.Join(errs, errors.New(\"vlanMode must be either '802.1q' or '802.1ad'\"))\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/vlan_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/vlanconfig.yaml\nvar expectedVLANConfigDocument []byte\n\nfunc TestVLANConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewVLANConfigV1Alpha1(\"enp0s3.2\")\n\tcfg.VLANIDConfig = 2\n\tcfg.ParentLinkConfig = \"enp0s3\"\n\tcfg.VLANModeConfig = new(nethelpers.VLANProtocol8021Q)\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedVLANConfigDocument, marshaled)\n}\n\nfunc TestVLANConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedVLANConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.VLANConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.VLANKind,\n\t\t},\n\t\tMetaName:         \"enp0s3.2\",\n\t\tVLANIDConfig:     2,\n\t\tParentLinkConfig: \"enp0s3\",\n\t\tVLANModeConfig:   new(nethelpers.VLANProtocol8021Q),\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestVLANValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.VLANConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.VLANConfigV1Alpha1 {\n\t\t\t\treturn network.NewVLANConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nvlanID must be specified and between 1 and 4094\\nparent must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid addresses\",\n\n\t\t\tcfg: func() *network.VLANConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVLANConfigV1Alpha1(\"enx8.2\")\n\t\t\t\tcfg.VLANIDConfig = 2\n\t\t\t\tcfg.ParentLinkConfig = \"enx8\"\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.Prefix{},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"address 0 must be specified\\naddress 1 must be a valid IP address\",\n\t\t},\n\t\t{\n\t\t\tname: \"no VLAN ID\",\n\n\t\t\tcfg: func() *network.VLANConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVLANConfigV1Alpha1(\"enx8.2\")\n\t\t\t\tcfg.ParentLinkConfig = \"enx9\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"vlanID must be specified and between 1 and 4094\",\n\t\t},\n\t\t{\n\t\t\tname: \"high VLAN ID\",\n\n\t\t\tcfg: func() *network.VLANConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVLANConfigV1Alpha1(\"enx8.2\")\n\t\t\t\tcfg.ParentLinkConfig = \"enx9\"\n\t\t\t\tcfg.VLANIDConfig = 5000\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"vlanID must be specified and between 1 and 4094\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.VLANConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVLANConfigV1Alpha1(\"enx8.2\")\n\t\t\t\tcfg.VLANIDConfig = 2\n\t\t\t\tcfg.ParentLinkConfig = \"enx8\"\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/vrf.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// VRFKind is a VRF config document kind.\nconst VRFKind = \"VRFConfig\"\n\nfunc init() {\n\tregistry.Register(VRFKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &VRFConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkVRFConfig    = &VRFConfigV1Alpha1{}\n\t_ config.ConflictingDocument = &VRFConfigV1Alpha1{}\n\t_ config.NamedDocument       = &VRFConfigV1Alpha1{}\n\t_ config.Validator           = &VRFConfigV1Alpha1{}\n)\n\n// VRFConfigV1Alpha1 is a config document to create a vrf and assign links to it.\n//\n//\texamples:\n//\t  - value: exampleVRFConfigV1Alpha1()\n//\talias: VRFConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/VRFConfig\ntype VRFConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the vrf link (interface) to be created.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"vrf-blue\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Override the hardware (MAC) address of the link.\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       nethelpers.HardwareAddr{0x2e, 0x3c, 0x4d, 0x5e, 0x6f, 0x70}\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[0-9a-f:]+$\n\tHardwareAddressConfig nethelpers.HardwareAddr `yaml:\"hardwareAddr,omitempty\"`\n\t//   description: |\n\t//     Names of the links (interfaces) to be assigned to this vrf.\n\t//     Link aliases can be used here as well.\n\t//   examples:\n\t//    - value: >\n\t//       []string{\"enp1s3\", \"enp1s2\"}\n\t//   schemaRequired: true\n\tVRFLinks []string `yaml:\"links,omitempty\"`\n\t//   description: |\n\t//     Routing table number to use for this vrf.\n\t//   examples:\n\t//    - value: >\n\t//       10\n\t//   schemaRequired: true\n\t//   schema:\n\t//     type: string\n\tVRFTable nethelpers.RoutingTable `yaml:\"table\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// NewVRFConfigV1Alpha1 creates a new VRFConfig config document.\nfunc NewVRFConfigV1Alpha1(name string) *VRFConfigV1Alpha1 {\n\treturn &VRFConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       VRFKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleVRFConfigV1Alpha1() *VRFConfigV1Alpha1 {\n\tcfg := NewVRFConfigV1Alpha1(\"vrf-blue\")\n\tcfg.VRFTable = 10\n\tcfg.VRFLinks = []string{\"eno1\", \"eno2\"}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *VRFConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *VRFConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// VRFConfig implements NetworkVRFConfig interface.\nfunc (s *VRFConfigV1Alpha1) VRFConfig() {}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *VRFConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(VRFKind)\n}\n\n// Validate implements config.Validator interface.\nfunc (s *VRFConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif s.VRFTable == nethelpers.TableUnspec || s.VRFTable == nethelpers.TableLocal || s.VRFTable == nethelpers.TableMain || s.VRFTable == nethelpers.TableDefault {\n\t\terrs = errors.Join(errs, fmt.Errorf(\"cannot create vrf with reserved table %s\", s.VRFTable))\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\n// Links implements NetworkVRFConfig interface.\nfunc (s *VRFConfigV1Alpha1) Links() []string {\n\treturn s.VRFLinks\n}\n\n// Table implements NetworkVRFConfig interface.\nfunc (s *VRFConfigV1Alpha1) Table() nethelpers.RoutingTable {\n\treturn s.VRFTable\n}\n\n// HardwareAddress implements NetworkHardwareAddressConfig interface.\nfunc (s *VRFConfigV1Alpha1) HardwareAddress() optional.Optional[nethelpers.HardwareAddr] {\n\tif len(s.HardwareAddressConfig) == 0 {\n\t\treturn optional.None[nethelpers.HardwareAddr]()\n\t}\n\n\treturn optional.Some(s.HardwareAddressConfig)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/vrf_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed testdata/vrfconfig.yaml\nvar expectedVRFConfigDocument []byte\n\nfunc TestVRFConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\tcfg.VRFLinks = []string{\"eno1\", \"eno5\"}\n\tcfg.VRFTable = 123\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.5/32\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedVRFConfigDocument, marshaled)\n}\n\nfunc TestVRFConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedVRFConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.VRFConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.VRFKind,\n\t\t},\n\t\tMetaName: \"vrf-blue\",\n\t\tVRFLinks: []string{\"eno1\", \"eno5\"},\n\t\tVRFTable: 123,\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"1.2.3.5/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestVRFValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.VRFConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\treturn network.NewVRFConfigV1Alpha1(\"\")\n\t\t\t},\n\t\t\texpectedError: \"name must be specified\\ncannot create vrf with reserved table unspec\",\n\t\t},\n\t\t{\n\t\t\tname: \"reject reserved table id 0\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"cannot create vrf with reserved table unspec\",\n\t\t},\n\t\t{\n\t\t\tname: \"reject reserved table id 253\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\t\t\t\tcfg.VRFTable = nethelpers.TableDefault\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"cannot create vrf with reserved table default\",\n\t\t},\n\t\t{\n\t\t\tname: \"reject reserved table id 254\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\t\t\t\tcfg.VRFTable = nethelpers.TableMain\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"cannot create vrf with reserved table main\",\n\t\t},\n\t\t{\n\t\t\tname: \"reject reserved table id 255\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-blue\")\n\t\t\t\tcfg.VRFTable = nethelpers.TableLocal\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t\texpectedError: \"cannot create vrf with reserved table local\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.VRFConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewVRFConfigV1Alpha1(\"vrf-red\")\n\t\t\t\tcfg.VRFLinks = []string{\"eth0\", \"eth1\"}\n\t\t\t\tcfg.VRFTable = nethelpers.RoutingTable(123)\n\t\t\t\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"fd00::1/64\"),\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/wireguard.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n//docgen:jsonschema\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// WireguardKind is a Wireguard config document kind.\nconst WireguardKind = \"WireguardConfig\"\n\nfunc init() {\n\tregistry.Register(WireguardKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &WireguardConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.NetworkWireguardConfig = &WireguardConfigV1Alpha1{}\n\t_ config.ConflictingDocument    = &WireguardConfigV1Alpha1{}\n\t_ config.NamedDocument          = &WireguardConfigV1Alpha1{}\n\t_ config.Validator              = &WireguardConfigV1Alpha1{}\n\t_ config.SecretDocument         = &WireguardConfigV1Alpha1{}\n)\n\n// WireguardConfigV1Alpha1 is a config document to create and configure a Wireguard network link.\n//\n//\texamples:\n//\t  - value: exampleWireguardConfigV1Alpha1()\n//\talias: WireguardConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/WireguardConfig\ntype WireguardConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the Wireguard link (interface).\n\t//\n\t//   examples:\n\t//    - value: >\n\t//       \"wg.int\"\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     Specifies a private key configuration (base64 encoded).\n\t//     Can be generated by `wg genkey`.\n\t//   schemaRequired: true\n\tWireguardPrivateKey string `yaml:\"privateKey,omitempty\"`\n\t//   description: |\n\t//     Specifies a device's listening port (UDP).\n\t//     If not specified, a random port will be chosen.\n\tWireguardListenPort int `yaml:\"listenPort,omitempty\"`\n\t//   description: |\n\t//     Specifies a device's firewall mark.\n\t//     Useful for advanced routing setups, marking packets originating from this device.\n\tWireguardFirewallMark int `yaml:\"firewallMark,omitempty\"`\n\t//   description: Specifies a list of peer configurations to apply to a device.\n\tWireguardPeers []WireguardPeer `yaml:\"peers,omitempty\"`\n\n\t//nolint:embeddedstructfieldcheck\n\tCommonLinkConfig `yaml:\",inline\"`\n}\n\n// WireguardPeer describes a Wireguard peer configuration.\ntype WireguardPeer struct {\n\t//   description: |\n\t//     Specifies the public key of this peer.\n\t//     Can be extracted from private key by running `wg pubkey < private.key`.\n\t//   schemaRequired: true\n\tWireguardPublicKey string `yaml:\"publicKey,omitempty\"`\n\t//   description: |\n\t//     Specifies the preshared key for this peer (base64 encoded).\n\t//     Can be generated by `wg genpsk`.\n\t//     Optional, this key provides an additional layer of symmetric-key cryptography\n\t//     to the peer connection.\n\tWireguardPresharedKey string `yaml:\"presharedKey,omitempty\"`\n\t//   description: |\n\t//     Specifies the endpoint of this peer entry.\n\t//     Format: <IP address>:<port>.\n\t//     If not set, the peer should connect to us without us connecting to it first.\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^([0-9a-f.:]+|\\[[0-9a-f:.]+\\]):\\d{1,5}$\n\tWireguardEndpoint AddrPort `yaml:\"endpoint,omitempty\"`\n\t//   description: |\n\t//     Specifies the persistent keepalive interval for this peer.\n\t//     Field format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tWireguardPersistentKeepaliveInterval time.Duration `yaml:\"persistentKeepaliveInterval,omitempty\"`\n\t//   description: |\n\t//     AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n\t//     These IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: string\n\t//       pattern: ^[0-9a-f.:]+/\\d{1,3}$\n\tWireguardAllowedIPs []Prefix `yaml:\"allowedIPs,omitempty\"`\n}\n\n// NewWireguardConfigV1Alpha1 creates a new WireguardConfig config document.\nfunc NewWireguardConfigV1Alpha1(name string) *WireguardConfigV1Alpha1 {\n\treturn &WireguardConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       WireguardKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t\tMetaName: name,\n\t}\n}\n\nfunc exampleWireguardConfigV1Alpha1() *WireguardConfigV1Alpha1 {\n\tcfg := NewWireguardConfigV1Alpha1(\"wg1\")\n\tcfg.WireguardPrivateKey = \"OJ34O6J1z4ZZB+t16c+vYrzIrKddxyU3Z2eLhwYzqE8=\"\n\tcfg.WireguardListenPort = 51820\n\tcfg.WireguardPeers = []WireguardPeer{\n\t\t{\n\t\t\tWireguardPublicKey:  \"fP+xJZvUA5n1Pi/f5wcPiV6tZ6fHwqcGaXe98NfEgkE=\",\n\t\t\tWireguardAllowedIPs: []Prefix{{netip.MustParsePrefix(\"192.168.2.0/24\")}},\n\t\t\tWireguardEndpoint:   AddrPort{netip.MustParseAddrPort(\"10.0.0.1:5180\")},\n\t\t},\n\t\t{\n\t\t\tWireguardPublicKey:    \"TDd25Cwq6tMZANIKUaqred+Zt+09HtCqwFeOLtKQ9Cs=\",\n\t\t\tWireguardPresharedKey: \"UpH8htYK7yJBPg5+q4M/Tx0o5ipHbeSZtI/h/mHxOeU=\",\n\t\t\tWireguardAllowedIPs:   []Prefix{{netip.MustParsePrefix(\"192.168.3.0/24\")}},\n\t\t},\n\t}\n\tcfg.LinkAddresses = []AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/24\"),\n\t\t},\n\t}\n\tcfg.LinkMTU = 1420\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *WireguardConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *WireguardConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// WireguardConfig implements NetworkWireguardConfig interface.\nfunc (s *WireguardConfigV1Alpha1) WireguardConfig() {}\n\n// ConflictsWithKinds implements config.ConflictingDocument interface.\nfunc (s *WireguardConfigV1Alpha1) ConflictsWithKinds() []string {\n\treturn conflictingLinkKinds(WireguardKind)\n}\n\nfunc validateWireguardKey(key string) error {\n\t// this is hand-rolled to avoid importing wgtypes into machinery\n\traw, err := base64.StdEncoding.DecodeString(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(raw) != 32 {\n\t\treturn errors.New(\"invalid wireguard key length\")\n\t}\n\n\treturn nil\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s *WireguardConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string //nolint:prealloc\n\t)\n\n\tif s.MetaName == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"name must be specified\"))\n\t}\n\n\tif s.WireguardPrivateKey == \"\" {\n\t\terrs = errors.Join(errs, errors.New(\"wireguard private key must be specified\"))\n\t} else if err := validateWireguardKey(s.WireguardPrivateKey); err != nil {\n\t\terrs = errors.Join(errs, errors.New(\"wireguard private key is invalid: \"+err.Error()))\n\t}\n\n\tif s.WireguardListenPort < 0 || s.WireguardListenPort > 65535 {\n\t\terrs = errors.Join(errs, errors.New(\"wireguard listen port must be between 0 and 65535\"))\n\t}\n\n\tfor i, peer := range s.WireguardPeers {\n\t\tif peer.WireguardPublicKey == \"\" {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"wireguard peer public key must be specified (peer index %d)\", i))\n\t\t} else if err := validateWireguardKey(peer.WireguardPublicKey); err != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"wireguard peer public key is invalid (peer index %d): %w\", i, err))\n\t\t}\n\n\t\tif peer.WireguardPresharedKey != \"\" {\n\t\t\tif err := validateWireguardKey(peer.WireguardPresharedKey); err != nil {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"wireguard peer preshared key is invalid (peer index %d): %w\", i, err))\n\t\t\t}\n\t\t}\n\n\t\tif peer.WireguardPersistentKeepaliveInterval < 0 {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"wireguard peer persistent keepalive interval cannot be negative (peer index %d)\", i))\n\t\t}\n\t}\n\n\textraWarnings, extraErrs := s.CommonLinkConfig.Validate()\n\terrs, warnings = errors.Join(errs, extraErrs), append(warnings, extraWarnings...)\n\n\treturn warnings, errs\n}\n\n// PrivateKey implements NetworkWireguardConfig interface.\nfunc (s *WireguardConfigV1Alpha1) PrivateKey() string {\n\treturn s.WireguardPrivateKey\n}\n\n// ListenPort implements NetworkWireguardConfig interface.\nfunc (s *WireguardConfigV1Alpha1) ListenPort() optional.Optional[int] {\n\tif s.WireguardListenPort == 0 {\n\t\treturn optional.None[int]()\n\t}\n\n\treturn optional.Some(s.WireguardListenPort)\n}\n\n// FirewallMark implements NetworkWireguardConfig interface.\nfunc (s *WireguardConfigV1Alpha1) FirewallMark() optional.Optional[int] {\n\tif s.WireguardFirewallMark == 0 {\n\t\treturn optional.None[int]()\n\t}\n\n\treturn optional.Some(s.WireguardFirewallMark)\n}\n\n// Peers implements NetworkWireguardConfig interface.\nfunc (s *WireguardConfigV1Alpha1) Peers() []config.NetworkWireguardPeerConfig {\n\treturn xslices.Map(s.WireguardPeers, func(peer WireguardPeer) config.NetworkWireguardPeerConfig {\n\t\treturn peer\n\t})\n}\n\n// PublicKey implements NetworkWireguardPeerConfig interface.\nfunc (p WireguardPeer) PublicKey() string {\n\treturn p.WireguardPublicKey\n}\n\n// PresharedKey implements NetworkWireguardPeerConfig interface.\nfunc (p WireguardPeer) PresharedKey() optional.Optional[string] {\n\tif p.WireguardPresharedKey == \"\" {\n\t\treturn optional.None[string]()\n\t}\n\n\treturn optional.Some(p.WireguardPresharedKey)\n}\n\n// Endpoint implements NetworkWireguardPeerConfig interface.\nfunc (p WireguardPeer) Endpoint() optional.Optional[string] {\n\tif p.WireguardEndpoint.IsZero() {\n\t\treturn optional.None[string]()\n\t}\n\n\treturn optional.Some(p.WireguardEndpoint.String())\n}\n\n// AllowedIPs implements NetworkWireguardPeerConfig interface.\nfunc (p WireguardPeer) AllowedIPs() []netip.Prefix {\n\treturn xslices.Map(p.WireguardAllowedIPs, func(pr Prefix) netip.Prefix {\n\t\treturn pr.Prefix\n\t})\n}\n\n// PersistentKeepalive implements NetworkWireguardPeerConfig interface.\nfunc (p WireguardPeer) PersistentKeepalive() optional.Optional[time.Duration] {\n\tif p.WireguardPersistentKeepaliveInterval == 0 {\n\t\treturn optional.None[time.Duration]()\n\t}\n\n\treturn optional.Some(p.WireguardPersistentKeepaliveInterval)\n}\n\n// Redact does in-place replacement of secrets with the given string.\nfunc (s *WireguardConfigV1Alpha1) Redact(replacement string) {\n\tif s.WireguardPrivateKey != \"\" {\n\t\ts.WireguardPrivateKey = replacement\n\t}\n\n\tfor i := range s.WireguardPeers {\n\t\ts.WireguardPeers[i].Redact(replacement)\n\t}\n}\n\n// Redact does in-place replacement of secrets with the given string.\nfunc (p *WireguardPeer) Redact(replacement string) {\n\tif p.WireguardPresharedKey != \"\" {\n\t\tp.WireguardPresharedKey = replacement\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/wireguard_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t_ \"embed\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n)\n\n//go:embed testdata/wireguardconfig.yaml\nvar expectedWireguardConfigDocument []byte\n\n//go:embed testdata/wireguardconfig_redacted.yaml\nvar expectedWireguardConfigRedactedDocument []byte\n\nfunc TestWireguardConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := network.NewWireguardConfigV1Alpha1(\"wg.int\")\n\tcfg.WireguardPrivateKey = \"GA1E1VB+g41Dl0+UH2TMW9C5953y+moVg6JIIqkJbmw=\"\n\tcfg.WireguardListenPort = 5042\n\tcfg.WireguardFirewallMark = 0xb0\n\tcfg.WireguardPeers = []network.WireguardPeer{\n\t\t{\n\t\t\tWireguardPublicKey:  \"735jkJdcVDninU5PzLJ/S+bfN6Q3QOk6svWrVLMJQAk=\",\n\t\t\tWireguardAllowedIPs: []network.Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}},\n\t\t},\n\t\t{\n\t\t\tWireguardPublicKey:    \"uvdlJNva1X8/OCOZM+0gGT4Yu9x20odd3AWbbQUF7nM=\",\n\t\t\tWireguardPresharedKey: \"6j4UMxwszrHVZZUjY8/SFsZMjgaHkxV7yp9Tz05btho=\",\n\t\t\tWireguardEndpoint:     network.AddrPort{netip.MustParseAddrPort(\"10.3.4.3:2222\")},\n\t\t},\n\t}\n\tcfg.LinkUp = new(true)\n\tcfg.LinkAddresses = []network.AddressConfig{\n\t\t{\n\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedWireguardConfigDocument, marshaled)\n}\n\nfunc TestWireguardConfigRedact(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedWireguardConfigDocument)\n\trequire.NoError(t, err)\n\n\tredactedProvider := provider.RedactSecrets(\"REDACTED\")\n\n\tredacted, err := redactedProvider.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\trequire.NoError(t, err)\n\n\tt.Log(string(redacted))\n\n\tassert.Equal(t, expectedWireguardConfigRedactedDocument, redacted)\n}\n\nfunc TestWireguardConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedWireguardConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &network.WireguardConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       network.WireguardKind,\n\t\t},\n\t\tMetaName:              \"wg.int\",\n\t\tWireguardPrivateKey:   \"GA1E1VB+g41Dl0+UH2TMW9C5953y+moVg6JIIqkJbmw=\",\n\t\tWireguardListenPort:   5042,\n\t\tWireguardFirewallMark: 0xb0,\n\t\tWireguardPeers: []network.WireguardPeer{\n\t\t\t{\n\t\t\t\tWireguardPublicKey:  \"735jkJdcVDninU5PzLJ/S+bfN6Q3QOk6svWrVLMJQAk=\",\n\t\t\t\tWireguardAllowedIPs: []network.Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tWireguardPublicKey:    \"uvdlJNva1X8/OCOZM+0gGT4Yu9x20odd3AWbbQUF7nM=\",\n\t\t\t\tWireguardPresharedKey: \"6j4UMxwszrHVZZUjY8/SFsZMjgaHkxV7yp9Tz05btho=\",\n\t\t\t\tWireguardEndpoint:     network.AddrPort{netip.MustParseAddrPort(\"10.3.4.3:2222\")},\n\t\t\t},\n\t\t},\n\t\tCommonLinkConfig: network.CommonLinkConfig{\n\t\t\tLinkUp: new(true),\n\t\t\tLinkAddresses: []network.AddressConfig{\n\t\t\t\t{\n\t\t\t\t\tAddressAddress: netip.MustParsePrefix(\"192.168.1.100/32\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestWireguardValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *network.WireguardConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg: func() *network.WireguardConfigV1Alpha1 {\n\t\t\t\treturn network.NewWireguardConfigV1Alpha1(\"\")\n\t\t\t},\n\n\t\t\texpectedError: \"name must be specified\\nwireguard private key must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid private key\",\n\t\t\tcfg: func() *network.WireguardConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewWireguardConfigV1Alpha1(\"wg.invalid\")\n\t\t\t\tcfg.WireguardPrivateKey = \"invalid-key\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"wireguard private key is invalid: illegal base64 data at input byte 7\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid peer public key\",\n\t\t\tcfg: func() *network.WireguardConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewWireguardConfigV1Alpha1(\"wg.invalidpeer\")\n\t\t\t\tcfg.WireguardPrivateKey = \"0CWDz05gWWwVAwr4i5Zaz41k/FgIVYJmCsgAfLHUakU=\"\n\t\t\t\tcfg.WireguardPeers = []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tWireguardPublicKey: \"invalid-peer-key\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"wireguard peer public key is invalid (peer index 0): illegal base64 data at input byte 7\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid peer preshared key\",\n\t\t\tcfg: func() *network.WireguardConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewWireguardConfigV1Alpha1(\"wg.invalidpreshared\")\n\t\t\t\tcfg.WireguardPrivateKey = \"OJ34O6J1z4ZZB+t16c+vYrzIrKddxyU3Z2eLhwYzqE8=\"\n\t\t\t\tcfg.WireguardPeers = []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tWireguardPublicKey:    \"fP+xJZvUA5n1Pi/f5wcPiV6tZ6fHwqcGaXe98NfEgkE=\",\n\t\t\t\t\t\tWireguardPresharedKey: \"invalid-preshared-key\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"wireguard peer preshared key is invalid (peer index 0): illegal base64 data at input byte 7\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *network.WireguardConfigV1Alpha1 {\n\t\t\t\tcfg := network.NewWireguardConfigV1Alpha1(\"wg.35\")\n\t\t\t\tcfg.WireguardPrivateKey = \"OJ34O6J1z4ZZB+t16c+vYrzIrKddxyU3Z2eLhwYzqE8=\"\n\t\t\t\tcfg.WireguardListenPort = 51820\n\t\t\t\tcfg.WireguardFirewallMark = 0x1\n\t\t\t\tcfg.WireguardPeers = []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tWireguardPublicKey:  \"735jkJdcVDninU5PzLJ/S+bfN6Q3QOk6svWrVLMJQAk=\",\n\t\t\t\t\t\tWireguardAllowedIPs: []network.Prefix{{netip.MustParsePrefix(\"192.168.1.0/24\")}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tWireguardPublicKey:    \"uvdlJNva1X8/OCOZM+0gGT4Yu9x20odd3AWbbQUF7nM=\",\n\t\t\t\t\t\tWireguardPresharedKey: \"6j4UMxwszrHVZZUjY8/SFsZMjgaHkxV7yp9Tz05btho=\",\n\t\t\t\t\t\tWireguardEndpoint:     network.AddrPort{netip.MustParseAddrPort(\"10.3.4.3:2222\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tcfg.LinkRoutes = []network.RouteConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteDestination: network.Prefix{netip.MustParsePrefix(\"10.3.5.0/24\")},\n\t\t\t\t\t\tRouteGateway:     network.Addr{netip.MustParseAddr(\"10.3.5.1\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRouteGateway: network.Addr{netip.MustParseAddr(\"fe80::1\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/network/yaml.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport \"net/netip\"\n\n// Prefix is a wrapper for netip.Prefix.\n//\n// It implements IsZero() so that yaml.Marshal correctly skips empty values.\n//\n//docgen:nodoc\ntype Prefix struct {\n\tnetip.Prefix\n}\n\n// IsZero implements yaml.IsZeroer interface.\nfunc (n Prefix) IsZero() bool {\n\treturn n.Prefix == netip.Prefix{}\n}\n\n// Addr is a wrapper for netip.Addr.\n//\n// It implements IsZero() so that yaml.Marshal correctly skips empty values.\n//\n//docgen:nodoc\ntype Addr struct {\n\tnetip.Addr\n}\n\n// IsZero implements yaml.IsZeroer interface.\nfunc (n Addr) IsZero() bool {\n\treturn n.Addr == netip.Addr{}\n}\n\n// AddrPort is a wrapper for netip.AddrPort.\n//\n// It implements IsZero() so that yaml.Marshal correctly skips empty values.\n//\n//docgen:nodoc\ntype AddrPort struct {\n\tnetip.AddrPort\n}\n\n// IsZero implements yaml.IsZeroer interface.\nfunc (n AddrPort) IsZero() bool {\n\treturn n.AddrPort == netip.AddrPort{}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type EventSinkV1Alpha1 -type EnvironmentV1Alpha1 -type KmsgLogV1Alpha1 -type OOMV1Alpha1 -type WatchdogTimerV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"net/url\"\n)\n\n// DeepCopy generates a deep copy of *EventSinkV1Alpha1.\nfunc (o *EventSinkV1Alpha1) DeepCopy() *EventSinkV1Alpha1 {\n\tvar cp EventSinkV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *EnvironmentV1Alpha1.\nfunc (o *EnvironmentV1Alpha1) DeepCopy() *EnvironmentV1Alpha1 {\n\tvar cp EnvironmentV1Alpha1 = *o\n\tif o.EnvironmentVariables != nil {\n\t\tcp.EnvironmentVariables = make(map[string]string, len(o.EnvironmentVariables))\n\t\tfor k2, v2 := range o.EnvironmentVariables {\n\t\t\tcp.EnvironmentVariables[k2] = v2\n\t\t}\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *KmsgLogV1Alpha1.\nfunc (o *KmsgLogV1Alpha1) DeepCopy() *KmsgLogV1Alpha1 {\n\tvar cp KmsgLogV1Alpha1 = *o\n\tif o.KmsgLogURL.URL != nil {\n\t\tcp.KmsgLogURL.URL = new(url.URL)\n\t\t*cp.KmsgLogURL.URL = *o.KmsgLogURL.URL\n\t\tif o.KmsgLogURL.URL.User != nil {\n\t\t\tcp.KmsgLogURL.URL.User = new(url.Userinfo)\n\t\t\t*cp.KmsgLogURL.URL.User = *o.KmsgLogURL.URL.User\n\t\t}\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *OOMV1Alpha1.\nfunc (o *OOMV1Alpha1) DeepCopy() *OOMV1Alpha1 {\n\tvar cp OOMV1Alpha1 = *o\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *WatchdogTimerV1Alpha1.\nfunc (o *WatchdogTimerV1Alpha1) DeepCopy() *WatchdogTimerV1Alpha1 {\n\tvar cp WatchdogTimerV1Alpha1 = *o\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// EnvironmentConfigKind is an environment config document kind.\nconst EnvironmentConfigKind = \"EnvironmentConfig\"\n\nfunc init() {\n\tregistry.Register(EnvironmentConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &EnvironmentV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.EnvironmentConfig = &EnvironmentV1Alpha1{}\n\t_ config.Validator         = &EnvironmentV1Alpha1{}\n)\n\n// EnvironmentV1Alpha1 is an environment config document.\n//\n//\texamples:\n//\t  - value: exampleEnvironmentV1Alpha1()\n//\talias: EnvironmentConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/EnvironmentConfig\ntype EnvironmentV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     This field allows for the addition of environment variables.\n\t//     All environment variables are set on PID 1 in addition to every service.\n\t//     Propagation of environment variables to services is done only at initial service start time.\n\t//     To modify environment variables for services, the node must be restarted.\n\t//     Multiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\n\t//     Fully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\n\t//     Environment variable names are validated, and should:\n\t//       - start with an uppercase letter, lowercase letter, or an underscore (_) character, and\n\t//       - contain only uppercase and lowercase letters, underscore (_) characters, and numbers.\n\t//   values:\n\t//     - \"`GRPC_GO_LOG_VERBOSITY_LEVEL`\"\n\t//     - \"`GRPC_GO_LOG_SEVERITY_LEVEL`\"\n\t//     - \"`http_proxy`\"\n\t//     - \"`https_proxy`\"\n\t//     - \"`no_proxy`\"\n\t//   examples:\n\t//     - name: Environment variables definition examples.\n\t//       value: exampleEnvVars0()\n\t//     - value: exampleEnvVars1()\n\t//     - value: exampleEnvVars2()\n\t//   schema:\n\t//     type: object\n\t//     patternProperties:\n\t//       \".*\":\n\t//         type: string\n\tEnvironmentVariables Env `yaml:\"variables\"`\n}\n\n// Env represents a set of environment variables.\ntype Env = map[string]string\n\n// NewEnvironmentV1Alpha1 creates a new Environment config document.\nfunc NewEnvironmentV1Alpha1() *EnvironmentV1Alpha1 {\n\treturn &EnvironmentV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       EnvironmentConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleEnvironmentV1Alpha1() *EnvironmentV1Alpha1 {\n\tcfg := NewEnvironmentV1Alpha1()\n\tcfg.EnvironmentVariables = exampleEnvVars0()\n\n\treturn cfg\n}\n\nfunc exampleEnvVars0() Env {\n\treturn Env{\n\t\t\"GRPC_GO_LOG_VERBOSITY_LEVEL\": \"99\",\n\t\t\"GRPC_GO_LOG_SEVERITY_LEVEL\":  \"info\",\n\t\t\"https_proxy\":                 \"http://SERVER:PORT/\",\n\t}\n}\n\nfunc exampleEnvVars1() Env {\n\treturn Env{\n\t\t\"GRPC_GO_LOG_SEVERITY_LEVEL\": \"error\",\n\t\t\"https_proxy\":                \"https://USERNAME:PASSWORD@SERVER:PORT/\",\n\t}\n}\n\nfunc exampleEnvVars2() Env {\n\treturn Env{\n\t\t\"https_proxy\": \"http://DOMAIN\\\\USERNAME:PASSWORD@SERVER:PORT/\",\n\t}\n}\n\n// Clone implements config.Document interface.\nfunc (s *EnvironmentV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Variables implements config.EnvironmentConfig interface.\nfunc (s *EnvironmentV1Alpha1) Variables() Env {\n\treturn s.EnvironmentVariables\n}\n\n// POSIX1EnvKeyRegex is a regex for validating POSIX.1 environment variable names.\nvar POSIX1EnvKeyRegex = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)\n\n// Validate implements config.Validator interface.\nfunc (s *EnvironmentV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar err error\n\n\tfor key := range s.EnvironmentVariables {\n\t\tif !POSIX1EnvKeyRegex.MatchString(key) {\n\t\t\terr = errors.Join(err, fmt.Errorf(\"invalid environment variable name: %q\", key))\n\t\t}\n\t}\n\n\treturn nil, err\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/environment_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n)\n\n//go:embed testdata/environment.yaml\nvar expectedEnvironmentDocument []byte\n\nfunc TestEnvironmentMarshalStability(t *testing.T) {\n\tcfg := runtime.NewEnvironmentV1Alpha1()\n\tcfg.EnvironmentVariables = map[string]string{\n\t\t\"HTTP_PROXY\": \"http://proxy.example.com:8080\",\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedEnvironmentDocument, marshaled)\n}\n\nfunc TestEnvironmentValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *runtime.EnvironmentV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  runtime.NewEnvironmentV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *runtime.EnvironmentV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEnvironmentV1Alpha1()\n\n\t\t\t\tcfg.EnvironmentVariables = map[string]string{\n\t\t\t\t\t\"HTTP_PROXY\":  \"http://proxy.example.com:8080\",\n\t\t\t\t\t\"HTTPS_PROXY\": \"http://proxy.example.com:8080\",\n\t\t\t\t\t\"NO_PROXY\":    \"localhost\",\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid - starts with invalid character\",\n\t\t\tcfg: func() *runtime.EnvironmentV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEnvironmentV1Alpha1()\n\n\t\t\t\tcfg.EnvironmentVariables = map[string]string{\n\t\t\t\t\t\"1INVALID\": \"value\",\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid environment variable name: \\\"1INVALID\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid - contains invalid character\",\n\t\t\tcfg: func() *runtime.EnvironmentV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEnvironmentV1Alpha1()\n\n\t\t\t\tcfg.EnvironmentVariables = map[string]string{\n\t\t\t\t\t\"INVALID-CHAR\": \"value\",\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid environment variable name: \\\"INVALID-CHAR\\\"\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid - empty\",\n\t\t\tcfg: func() *runtime.EnvironmentV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEnvironmentV1Alpha1()\n\n\t\t\t\tcfg.EnvironmentVariables = map[string]string{\n\t\t\t\t\t\"\": \"value\",\n\t\t\t\t}\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"invalid environment variable name: \\\"\\\"\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/event_sink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//docgen:jsonschema\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// EventSinkKind is a event sink config document kind.\nconst EventSinkKind = \"EventSinkConfig\"\n\nfunc init() {\n\tregistry.Register(EventSinkKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &EventSinkV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RuntimeConfig = &EventSinkV1Alpha1{}\n\t_ config.Validator     = &EventSinkV1Alpha1{}\n)\n\n// EventSinkV1Alpha1 is a event sink config document.\n//\n//\texamples:\n//\t  - value: exampleEventSinkV1Alpha1()\n//\talias: EventSinkConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/EventSinkConfig\ntype EventSinkV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     The endpoint for the event sink as 'host:port'.\n\t//   examples:\n\t//     - value: >\n\t//        \"10.3.7.3:2810\"\n\tEndpoint string `yaml:\"endpoint\"`\n}\n\n// NewEventSinkV1Alpha1 creates a new eventsink config document.\nfunc NewEventSinkV1Alpha1() *EventSinkV1Alpha1 {\n\treturn &EventSinkV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       EventSinkKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleEventSinkV1Alpha1() *EventSinkV1Alpha1 {\n\tcfg := NewEventSinkV1Alpha1()\n\tcfg.Endpoint = \"192.168.10.3:3247\"\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *EventSinkV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Runtime implements config.Config interface.\nfunc (s *EventSinkV1Alpha1) Runtime() config.RuntimeConfig {\n\treturn s\n}\n\n// EventsEndpoint implements config.RuntimeConfig interface.\nfunc (s *EventSinkV1Alpha1) EventsEndpoint() *string {\n\treturn new(s.Endpoint)\n}\n\n// KmsgLogURLs implements config.RuntimeConfig interface.\nfunc (s *EventSinkV1Alpha1) KmsgLogURLs() []*url.URL {\n\treturn nil\n}\n\n// WatchdogTimer implements config.RuntimeConfig interface.\nfunc (s *EventSinkV1Alpha1) WatchdogTimer() config.WatchdogTimerConfig {\n\treturn nil\n}\n\n// Validate implements config.Validator interface.\nfunc (s *EventSinkV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\t_, _, err := net.SplitHostPort(s.Endpoint)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"event sink endpoint: %w\", err)\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/event_sink_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n)\n\n//go:embed testdata/eventsink.yaml\nvar expectedEventSinkDocument []byte\n\nfunc TestEventSinkMarshalStability(t *testing.T) {\n\tcfg := runtime.NewEventSinkV1Alpha1()\n\tcfg.Endpoint = \"10.0.0.1:3333\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedEventSinkDocument, marshaled)\n}\n\nfunc TestEventSinkValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *runtime.EventSinkV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  runtime.NewEventSinkV1Alpha1,\n\n\t\t\texpectedError: \"event sink endpoint: missing port in address\",\n\t\t},\n\t\t{\n\t\t\tname: \"just IP\",\n\t\t\tcfg: func() *runtime.EventSinkV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEventSinkV1Alpha1()\n\t\t\t\tcfg.Endpoint = \"10.0.0.1\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"event sink endpoint: address 10.0.0.1: missing port in address\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *runtime.EventSinkV1Alpha1 {\n\t\t\t\tcfg := runtime.NewEventSinkV1Alpha1()\n\t\t\t\tcfg.Endpoint = \"[ff:80::01]:334\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ServiceConfigV1Alpha1 -pointer-receiver -header-file ../../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage extensions\n\n// DeepCopy generates a deep copy of *ServiceConfigV1Alpha1.\nfunc (o *ServiceConfigV1Alpha1) DeepCopy() *ServiceConfigV1Alpha1 {\n\tvar cp ServiceConfigV1Alpha1 = *o\n\tif o.ServiceConfigFiles != nil {\n\t\tcp.ServiceConfigFiles = make([]ConfigFile, len(o.ServiceConfigFiles))\n\t\tcopy(cp.ServiceConfigFiles, o.ServiceConfigFiles)\n\t}\n\tif o.ServiceEnvironment != nil {\n\t\tcp.ServiceEnvironment = make([]string, len(o.ServiceEnvironment))\n\t\tcopy(cp.ServiceEnvironment, o.ServiceEnvironment)\n\t}\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/extensions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package extensions provides extensions config documents.\npackage extensions\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output extensions_doc.go extensions.go service_config.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ServiceConfigV1Alpha1 -pointer-receiver -header-file ../../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/extensions_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage extensions\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (ServiceConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExtensionServiceConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExtensionServiceConfig is a extensionserviceconfig document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExtensionServiceConfig is a extensionserviceconfig document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the extension service.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the extension service.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"configFiles\",\n\t\t\t\tType:        \"[]ConfigFile\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The config files for the extension service.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The config files for the extension service.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"environment\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The environment for the extension service.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The environment for the extension service.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", extensionServiceConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (ConfigFile) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ConfigFile\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ConfigFile is a config file for extension services.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ConfigFile is a config file for extension services.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ServiceConfigV1Alpha1\",\n\t\t\t\tFieldName: \"configFiles\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"content\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The content of the extension service config file.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The content of the extension service config file.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mountPath\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The mount path of the extension service config file.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The mount path of the extension service config file.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file extensions_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"extensions\",\n\t\tDescription: \"Package extensions provides extensions config documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tServiceConfigV1Alpha1{}.Doc(),\n\t\t\tConfigFile{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/service_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\n//docgen:jsonschema\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// ServiceConfigKind is a Extension config document kind.\nconst ServiceConfigKind = \"ExtensionServiceConfig\"\n\nfunc init() {\n\tregistry.Register(ServiceConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\":\n\t\t\treturn &ServiceConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.ExtensionServiceConfig = &ServiceConfigV1Alpha1{}\n\t_ config.Document               = &ServiceConfigV1Alpha1{}\n\t_ config.Validator              = &ServiceConfigV1Alpha1{}\n)\n\n// ServiceConfigV1Alpha1 is a extensionserviceconfig document.\n//\n//\texamples:\n//\t  - value: extensionServiceConfigV1Alpha1()\n//\talias: ExtensionServiceConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ExtensionServiceConfig\ntype ServiceConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the extension service.\n\t//   schemaRequired: true\n\tServiceName string `yaml:\"name\"`\n\t//   description: |\n\t//     The config files for the extension service.\n\tServiceConfigFiles ConfigFileList `yaml:\"configFiles,omitempty\"`\n\t//   description: |\n\t//     The environment for the extension service.\n\tServiceEnvironment []string `yaml:\"environment,omitempty\"`\n}\n\n// ConfigFileList is a list of ConfigFiles.\n//\n//docgen:alias\ntype ConfigFileList []ConfigFile\n\n// Merge the config files by mountPath.\nfunc (list *ConfigFileList) Merge(other any) error {\n\totherFiles, ok := other.(ConfigFileList)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for config file merge %T\", other)\n\t}\n\n\tfor _, configFile := range otherFiles {\n\t\tif err := list.mergeConfigFile(configFile); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (list *ConfigFileList) mergeConfigFile(configFile ConfigFile) error {\n\tvar existing *ConfigFile\n\n\tfor idx, cf := range *list {\n\t\tif cf.ConfigFileMountPath == configFile.ConfigFileMountPath {\n\t\t\texisting = &(*list)[idx]\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif existing != nil {\n\t\treturn merge.Merge(existing, &configFile)\n\t}\n\n\t*list = append(*list, configFile)\n\n\treturn nil\n}\n\n// ConfigFile is a config file for extension services.\ntype ConfigFile struct {\n\t//   description: |\n\t//     The content of the extension service config file.\n\tConfigFileContent string `yaml:\"content\"`\n\t//   description: |\n\t//     The mount path of the extension service config file.\n\tConfigFileMountPath string `yaml:\"mountPath\"`\n}\n\n// NewServicesConfigV1Alpha1 creates a new siderolink config document.\nfunc NewServicesConfigV1Alpha1() *ServiceConfigV1Alpha1 {\n\treturn &ServiceConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ServiceConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\n// Clone implements config.Document interface.\nfunc (e *ServiceConfigV1Alpha1) Clone() config.Document {\n\treturn e.DeepCopy()\n}\n\n// Validate implements config.Validatator interface.\nfunc (e *ServiceConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif e.ServiceName == \"\" {\n\t\treturn nil, fmt.Errorf(\"name is required\")\n\t}\n\n\tif len(e.ServiceConfigFiles) == 0 && len(e.ServiceEnvironment) == 0 {\n\t\tif len(e.ServiceConfigFiles) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"no config files found for extension %q\", e.ServiceName)\n\t\t}\n\n\t\tif len(e.ServiceEnvironment) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"no environment defined for extension %q\", e.ServiceName)\n\t\t}\n\t}\n\n\tfor _, file := range e.ServiceConfigFiles {\n\t\tif file.ConfigFileContent == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"extension content is required for extension %q\", e.ServiceName)\n\t\t}\n\n\t\tif file.ConfigFileMountPath == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"extension mount path is required for extension %q\", e.ServiceName)\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\n// Name implements config.ExtensionServiceConfig interface.\nfunc (e *ServiceConfigV1Alpha1) Name() string {\n\treturn e.ServiceName\n}\n\n// ConfigFiles implements config.ExtensionServiceConfig interface.\nfunc (e *ServiceConfigV1Alpha1) ConfigFiles() []config.ExtensionServiceConfigFile {\n\treturn xslices.Map(e.ServiceConfigFiles, func(c ConfigFile) config.ExtensionServiceConfigFile {\n\t\treturn c\n\t})\n}\n\n// Environment implements config.ExtensionServiceConfig interface.\nfunc (e *ServiceConfigV1Alpha1) Environment() []string {\n\treturn e.ServiceEnvironment\n}\n\n// Content implements config.ExtensionServiceConfigFile interface.\nfunc (e ConfigFile) Content() string {\n\treturn e.ConfigFileContent\n}\n\n// MountPath implements config.ExtensionServiceConfigFile interface.\nfunc (e ConfigFile) MountPath() string {\n\treturn e.ConfigFileMountPath\n}\n\nfunc extensionServiceConfigV1Alpha1() *ServiceConfigV1Alpha1 {\n\tcfg := NewServicesConfigV1Alpha1()\n\tcfg.ServiceName = \"nut-client\"\n\tcfg.ServiceConfigFiles = []ConfigFile{\n\t\t{\n\t\t\tConfigFileContent:   \"MONITOR ${upsmonHost} 1 remote username password\",\n\t\t\tConfigFileMountPath: \"/usr/local/etc/nut/upsmon.conf\",\n\t\t},\n\t}\n\tcfg.ServiceEnvironment = []string{\"NUT_UPS=upsname\"}\n\n\treturn cfg\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/service_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions\"\n)\n\n//go:embed testdata/extension_service_config.yaml\nvar expectedExtensionServiceConfigDocument []byte\n\nfunc TestExtensionServiceConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := extensions.NewServicesConfigV1Alpha1()\n\tcfg.ServiceName = \"foo\"\n\tcfg.ServiceConfigFiles = []extensions.ConfigFile{\n\t\t{\n\t\t\tConfigFileContent:   \"hello\",\n\t\t\tConfigFileMountPath: \"/etc/foo\",\n\t\t},\n\t}\n\tcfg.ServiceEnvironment = []string{\"FOO=BAR\"}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedExtensionServiceConfigDocument, marshaled)\n}\n\nfunc TestExtensionServiceConfigMerge(t *testing.T) {\n\tt.Parallel()\n\n\tcfgLeft := extensions.NewServicesConfigV1Alpha1()\n\tcfgLeft.ServiceName = \"foo\"\n\tcfgLeft.ServiceConfigFiles = []extensions.ConfigFile{\n\t\t{\n\t\t\tConfigFileContent:   \"hello\",\n\t\t\tConfigFileMountPath: \"/etc/foo\",\n\t\t},\n\t}\n\n\tcfgRight := cfgLeft.DeepCopy()\n\tcfgRight.ServiceConfigFiles[0].ConfigFileContent = \"hello world\"\n\n\tcfgRight.ServiceConfigFiles = append(cfgRight.ServiceConfigFiles,\n\t\textensions.ConfigFile{\n\t\t\tConfigFileContent:   \"bar\",\n\t\t\tConfigFileMountPath: \"/etc/bar\",\n\t\t},\n\t)\n\n\trequire.NoError(t, merge.Merge(cfgLeft, cfgRight))\n\n\trequire.Len(t, cfgLeft.ConfigFiles(), 2)\n\n\tassert.Equal(t, \"hello world\", cfgLeft.ConfigFiles()[0].Content())\n\tassert.Equal(t, \"bar\", cfgLeft.ConfigFiles()[1].Content())\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/extensions/testdata/extension_service_config.yaml",
    "content": "apiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: foo\nconfigFiles:\n    - content: hello\n      mountPath: /etc/foo\nenvironment:\n    - FOO=BAR\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/kmsg_log.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// KmsgLogKind is a kmsg log config document kind.\nconst KmsgLogKind = \"KmsgLogConfig\"\n\nfunc init() {\n\tregistry.Register(KmsgLogKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &KmsgLogV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RuntimeConfig = &KmsgLogV1Alpha1{}\n\t_ config.NamedDocument = &KmsgLogV1Alpha1{}\n\t_ config.Validator     = &KmsgLogV1Alpha1{}\n)\n\n// KmsgLogV1Alpha1 is a event sink config document.\n//\n//\texamples:\n//\t  - value: exampleKmsgLogV1Alpha1()\n//\talias: KmsgLogConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/KmsgLogConfig\ntype KmsgLogV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the config document.\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     The URL encodes the log destination.\n\t//     The scheme must be tcp:// or udp://.\n\t//     The path must be empty.\n\t//     The port is required.\n\t//   examples:\n\t//     - value: >\n\t//        \"udp://10.3.7.3:2810\"\n\t//   schema:\n\t//     type: string\n\t//     pattern: \"^(tcp|udp)://\"\n\tKmsgLogURL meta.URL `yaml:\"url\"`\n}\n\n// NewKmsgLogV1Alpha1 creates a new eventsink config document.\nfunc NewKmsgLogV1Alpha1() *KmsgLogV1Alpha1 {\n\treturn &KmsgLogV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       KmsgLogKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleKmsgLogV1Alpha1() *KmsgLogV1Alpha1 {\n\tcfg := NewKmsgLogV1Alpha1()\n\tcfg.MetaName = \"remote-log\"\n\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"tcp://192.168.3.7:3478/\"))\n\n\treturn cfg\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *KmsgLogV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// Clone implements config.Document interface.\nfunc (s *KmsgLogV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Runtime implements config.Config interface.\nfunc (s *KmsgLogV1Alpha1) Runtime() config.RuntimeConfig {\n\treturn s\n}\n\n// EventsEndpoint implements config.RuntimeConfig interface.\nfunc (s *KmsgLogV1Alpha1) EventsEndpoint() *string {\n\treturn nil\n}\n\n// KmsgLogURLs implements config.RuntimeConfig interface.\nfunc (s *KmsgLogV1Alpha1) KmsgLogURLs() []*url.URL {\n\treturn []*url.URL{s.KmsgLogURL.URL}\n}\n\n// WatchdogTimer implements config.RuntimeConfig interface.\nfunc (s *KmsgLogV1Alpha1) WatchdogTimer() config.WatchdogTimerConfig {\n\treturn nil\n}\n\n// Validate implements config.Validator interface.\nfunc (s *KmsgLogV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif s.MetaName == \"\" {\n\t\treturn nil, errors.New(\"name is required\")\n\t}\n\n\tif s.KmsgLogURL.URL == nil {\n\t\treturn nil, errors.New(\"url is required\")\n\t}\n\n\tswitch s.KmsgLogURL.URL.Scheme {\n\tcase \"tcp\":\n\tcase \"udp\":\n\tdefault:\n\t\treturn nil, errors.New(\"url scheme must be tcp:// or udp://\")\n\t}\n\n\tswitch s.KmsgLogURL.URL.Path {\n\tcase \"/\":\n\tcase \"\":\n\tdefault:\n\t\treturn nil, errors.New(\"url path must be empty\")\n\t}\n\n\tif s.KmsgLogURL.URL.Port() == \"\" {\n\t\treturn nil, errors.New(\"url port is required\")\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/kmsg_log_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t_ \"embed\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n)\n\n//go:embed testdata/kmsglog.yaml\nvar expectedKmsgLogDocument []byte\n\nfunc TestKmsgLogMarshalStability(t *testing.T) {\n\tcfg := runtime.NewKmsgLogV1Alpha1()\n\tcfg.MetaName = \"apiSink\"\n\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"https://kmsglog.api/logs\"))\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedKmsgLogDocument, marshaled)\n}\n\nfunc TestKmsgLogValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *runtime.KmsgLogV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  runtime.NewKmsgLogV1Alpha1,\n\n\t\t\texpectedError: \"name is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"no URL\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name1\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"url is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"wrong scheme\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name2\"\n\t\t\t\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"https://some.destination/path\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"url scheme must be tcp:// or udp://\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra path\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name5\"\n\t\t\t\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"tcp://some.destination:34/path\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"url path must be empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"no port\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name6\"\n\t\t\t\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"tcp://some.destination/\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"url port is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid TCP\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name3\"\n\t\t\t\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"tcp://10.2.3.4:5000/\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid UDP\",\n\t\t\tcfg: func() *runtime.KmsgLogV1Alpha1 {\n\t\t\t\tcfg := runtime.NewKmsgLogV1Alpha1()\n\t\t\t\tcfg.MetaName = \"name4\"\n\t\t\t\tcfg.KmsgLogURL.URL = ensure.Value(url.Parse(\"udp://10.2.3.4:5000/\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/oom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/siderolabs/gen/optional\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// OOMKind is a Out of Memory Handler document kind.\nconst OOMKind = \"OOMConfig\"\n\nfunc init() {\n\tregistry.Register(OOMKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &OOMV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.Validator = &OOMV1Alpha1{}\n\t_ config.OOMConfig = &OOMV1Alpha1{}\n)\n\n// OOMV1Alpha1 is a Out of Memory handler config document.\n//\n//\texamples:\n//\t  - value: exampleOOMV1Alpha1()\n//\talias: OOMConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/OOMConfig\ntype OOMV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     This expression defines when to trigger OOM action.\n\t//\n\t//     The expression must evaluate to a boolean value.\n\t//     If the expression returns true, then OOM ranking and killing will be handled.\n\t//\n\t//     This expression receives the following parameters:\n\t//     - memory_{some,full}_{avg10,avg60,avg300,total} - double, representing PSI values\n\t//     - time_since_trigger - duration since the last OOM handler trigger event\n\t//   schema:\n\t//     type: string\n\tOOMTriggerExpression cel.Expression `yaml:\"triggerExpression,omitempty\"`\n\t//   description: |\n\t//     This expression defines how to rank cgroups for OOM handler.\n\t//\n\t//     The cgroup with the highest rank (score) will be evicted first.\n\t//     The expression must evaluate to a double value.\n\t//\n\t//     This expression receives the following parameters:\n\t//     - memory_max - Optional<uint> - in bytes\n\t//     - memory_current - Optional<uint> - in bytes\n\t//     - memory_peak - Optional<uint> - in bytes\n\t//     - path - string, path to the cgroup\n\t//     - class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\n\t//   schema:\n\t//     type: string\n\tOOMCgroupRankingExpression cel.Expression `yaml:\"cgroupRankingExpression,omitempty\"`\n\t//   description: |\n\t//     How often should the trigger expression be evaluated.\n\t//\n\t//     This interval determines how often should the OOM controller\n\t//     check for the OOM condition using the provided expression.\n\t//     Adjusting it can help tune the reactivity of the OOM handler.\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tOOMSampleInterval time.Duration `yaml:\"sampleInterval,omitempty\"`\n}\n\n// NewOOMV1Alpha1 creates a new eventsink config document.\nfunc NewOOMV1Alpha1() *OOMV1Alpha1 {\n\treturn &OOMV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       OOMKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleOOMV1Alpha1() *OOMV1Alpha1 {\n\tcfg := NewOOMV1Alpha1()\n\tcfg.OOMSampleInterval = 100 * time.Millisecond\n\tcfg.OOMTriggerExpression = cel.MustExpression(cel.ParseBooleanExpression(\n\t\tconstants.DefaultOOMTriggerExpression,\n\t\tcelenv.OOMTrigger(),\n\t))\n\tcfg.OOMCgroupRankingExpression = cel.MustExpression(cel.ParseDoubleExpression(\n\t\tconstants.DefaultOOMCgroupRankingExpression,\n\t\tcelenv.OOMCgroupScoring(),\n\t))\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *OOMV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\nfunc (s *OOMV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar validationErrors error\n\n\tif !s.OOMTriggerExpression.IsZero() {\n\t\tif err := s.OOMTriggerExpression.ParseBool(celenv.OOMTrigger()); err != nil {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"OOM trigger expression is invalid: %w\", err))\n\t\t}\n\t}\n\n\tif !s.OOMCgroupRankingExpression.IsZero() {\n\t\tif err := s.OOMCgroupRankingExpression.ParseDouble(celenv.OOMCgroupScoring()); err != nil {\n\t\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"OOM cgroup scoring expression is invalid: %w\", err))\n\t\t}\n\t}\n\n\tif s.OOMSampleInterval < 0 {\n\t\tvalidationErrors = errors.Join(validationErrors, fmt.Errorf(\"OOM sample interval must be longer than 0\"))\n\t}\n\n\treturn nil, validationErrors\n}\n\n// TriggerExpression returns the OOM trigger expression.\nfunc (s *OOMV1Alpha1) TriggerExpression() optional.Optional[cel.Expression] {\n\tif s.OOMCgroupRankingExpression.IsZero() {\n\t\treturn optional.None[cel.Expression]()\n\t}\n\n\treturn optional.Some(s.OOMTriggerExpression)\n}\n\n// CgroupRankingExpression returns the OOM cgroup ranking expression.\nfunc (s *OOMV1Alpha1) CgroupRankingExpression() optional.Optional[cel.Expression] {\n\tif s.OOMCgroupRankingExpression.IsZero() {\n\t\treturn optional.None[cel.Expression]()\n\t}\n\n\treturn optional.Some(s.OOMCgroupRankingExpression)\n}\n\n// SampleInterval returns the OOM sampling interval.\nfunc (s *OOMV1Alpha1) SampleInterval() optional.Optional[time.Duration] {\n\tif s.OOMSampleInterval == 0 {\n\t\treturn optional.None[time.Duration]()\n\t}\n\n\treturn optional.Some(s.OOMSampleInterval)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/oom_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n//go:embed testdata/oom.yaml\nvar expectedOOMDocument []byte\n\nfunc TestOOMMarshalStability(t *testing.T) {\n\tcfg := runtime.NewOOMV1Alpha1()\n\tcfg.OOMSampleInterval = 100 * time.Millisecond\n\tcfg.OOMTriggerExpression = cel.MustExpression(cel.ParseBooleanExpression(\n\t\tconstants.DefaultOOMTriggerExpression,\n\t\tcelenv.OOMTrigger(),\n\t))\n\tcfg.OOMCgroupRankingExpression = cel.MustExpression(cel.ParseDoubleExpression(\n\t\tconstants.DefaultOOMCgroupRankingExpression,\n\t\tcelenv.OOMCgroupScoring(),\n\t))\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, string(expectedOOMDocument), string(marshaled))\n}\n\nfunc TestOOMValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *runtime.OOMV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  runtime.NewOOMV1Alpha1,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid expression\",\n\t\t\tcfg: func() *runtime.OOMV1Alpha1 {\n\t\t\t\tcfg := runtime.NewOOMV1Alpha1()\n\n\t\t\t\trequire.NoError(t, cfg.OOMCgroupRankingExpression.UnmarshalText([]byte(`disk.transport`)))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"OOM cgroup scoring expression is invalid: ERROR: <input>:1:1: undeclared reference to 'disk' (in container '')\\n | disk.transport\\n | ^\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package runtime provides runtime machine configuration documents.\npackage runtime\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output runtime_doc.go runtime.go kmsg_log.go event_sink.go environment.go oom.go watchdog_timer.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type EventSinkV1Alpha1 -type EnvironmentV1Alpha1 -type KmsgLogV1Alpha1 -type OOMV1Alpha1 -type WatchdogTimerV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/runtime_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (KmsgLogV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KmsgLogConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KmsgLogConfig is a event sink config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KmsgLogConfig is a event sink config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the config document.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"url\",\n\t\t\t\tType:        \"URL\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The URL encodes the log destination.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleKmsgLogV1Alpha1())\n\n\tdoc.Fields[2].AddExample(\"\", \"udp://10.3.7.3:2810\")\n\n\treturn doc\n}\n\nfunc (EventSinkV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EventSinkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EventSinkConfig is a event sink config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EventSinkConfig is a event sink config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The endpoint for the event sink as 'host:port'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The endpoint for the event sink as 'host:port'.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleEventSinkV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"10.3.7.3:2810\")\n\n\treturn doc\n}\n\nfunc (EnvironmentV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EnvironmentConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EnvironmentConfig is an environment config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EnvironmentConfig is an environment config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"variables\",\n\t\t\t\tType:        \"Env\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"This field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore (_) character, and\\n  - contain only uppercase and lowercase letters, underscore (_) characters, and numbers.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"This field allows for the addition of environment variables.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"`GRPC_GO_LOG_VERBOSITY_LEVEL`\",\n\t\t\t\t\t\"`GRPC_GO_LOG_SEVERITY_LEVEL`\",\n\t\t\t\t\t\"`http_proxy`\",\n\t\t\t\t\t\"`https_proxy`\",\n\t\t\t\t\t\"`no_proxy`\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleEnvironmentV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"Environment variables definition examples.\", exampleEnvVars0())\n\tdoc.Fields[1].AddExample(\"\", exampleEnvVars1())\n\tdoc.Fields[1].AddExample(\"\", exampleEnvVars2())\n\n\treturn doc\n}\n\nfunc (OOMV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"OOMConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"OOMConfig is a Out of Memory handler config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"OOMConfig is a Out of Memory handler config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"triggerExpression\",\n\t\t\t\tType:        \"Expression\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"This expression defines when to trigger OOM action.\\n\\nThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\n\\nThis expression receives the following parameters:\\n- memory_{some,full}_{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"This expression defines when to trigger OOM action.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"cgroupRankingExpression\",\n\t\t\t\tType:        \"Expression\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"This expression defines how to rank cgroups for OOM handler.\\n\\nThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\n\\nThis expression receives the following parameters:\\n- memory_max - Optional<uint> - in bytes\\n- memory_current - Optional<uint> - in bytes\\n- memory_peak - Optional<uint> - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"This expression defines how to rank cgroups for OOM handler.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"sampleInterval\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"How often should the trigger expression be evaluated.\\n\\nThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"How often should the trigger expression be evaluated.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleOOMV1Alpha1())\n\n\treturn doc\n}\n\nfunc (WatchdogTimerV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"WatchdogTimerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"WatchdogTimerConfig is a watchdog timer config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"WatchdogTimerConfig is a watchdog timer config document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"device\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Path to the watchdog device.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Path to the watchdog device.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"timeout\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Timeout for the watchdog.\\n\\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\\n\\nDefault value is 1 minute, minimum value is 10 seconds.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Timeout for the watchdog.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleWatchdogTimerV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"/dev/watchdog0\")\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file runtime_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"runtime\",\n\t\tDescription: \"Package runtime provides runtime machine configuration documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tKmsgLogV1Alpha1{}.Doc(),\n\t\t\tEventSinkV1Alpha1{}.Doc(),\n\t\t\tEnvironmentV1Alpha1{}.Doc(),\n\t\t\tOOMV1Alpha1{}.Doc(),\n\t\t\tWatchdogTimerV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/testdata/environment.yaml",
    "content": "apiVersion: v1alpha1\nkind: EnvironmentConfig\nvariables:\n    HTTP_PROXY: http://proxy.example.com:8080\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/testdata/eventsink.yaml",
    "content": "apiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: 10.0.0.1:3333\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/testdata/kmsglog.yaml",
    "content": "apiVersion: v1alpha1\nkind: KmsgLogConfig\nname: apiSink\nurl: https://kmsglog.api/logs\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/testdata/oom.yaml",
    "content": "apiVersion: v1alpha1\nkind: OOMConfig\ntriggerExpression: |-\n    multiply_qos_vectors(d_qos_memory_full_total, {System: 8.0, Podruntime: 4.0}) > 3000.0 &&\n    multiply_qos_vectors(qos_memory_full_avg10, {System: 1.0, Podruntime: 1.0}) > 5.0 ||\n    memory_full_avg10 > 75.0 && time_since_trigger > duration(\"10s\")\ncgroupRankingExpression: 'memory_max.hasValue() ? 0.0 : ({Besteffort: 1.0, Burstable: 0.5, Guaranteed: 0.0, Podruntime: 0.0, System: 0.0}[class] * double(memory_current.orValue(0u)))'\nsampleInterval: 100ms\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/testdata/watchdogtimer.yaml",
    "content": "apiVersion: v1alpha1\nkind: WatchdogTimerConfig\ndevice: /dev/watchdog0\ntimeout: 3m0s\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/watchdog_timer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//docgen:jsonschema\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// WatchdogTimerKind is a watchdog timer config document kind.\nconst WatchdogTimerKind = \"WatchdogTimerConfig\"\n\nfunc init() {\n\tregistry.Register(WatchdogTimerKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\": //nolint:goconst\n\t\t\treturn &WatchdogTimerV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.RuntimeConfig = &WatchdogTimerV1Alpha1{}\n\t_ config.Validator     = &WatchdogTimerV1Alpha1{}\n)\n\n// Timeout constants.\nconst (\n\tMinWatchdogTimeout     = 10 * time.Second\n\tDefaultWatchdogTimeout = time.Minute\n)\n\n// WatchdogTimerV1Alpha1 is a watchdog timer config document.\n//\n//\texamples:\n//\t  - value: exampleWatchdogTimerV1Alpha1()\n//\talias: WatchdogTimerConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/WatchdogTimerConfig\ntype WatchdogTimerV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Path to the watchdog device.\n\t//   examples:\n\t//     - value: >\n\t//        \"/dev/watchdog0\"\n\tWatchdogDevice string `yaml:\"device\"`\n\t//   description: |\n\t//     Timeout for the watchdog.\n\t//\n\t//     If Talos is unresponsive for this duration, the watchdog will reset the system.\n\t//\n\t//     Default value is 1 minute, minimum value is 10 seconds.\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tWatchdogTimeout time.Duration `yaml:\"timeout,omitempty\"`\n}\n\n// NewWatchdogTimerV1Alpha1 creates a new eventsink config document.\nfunc NewWatchdogTimerV1Alpha1() *WatchdogTimerV1Alpha1 {\n\treturn &WatchdogTimerV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       WatchdogTimerKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleWatchdogTimerV1Alpha1() *WatchdogTimerV1Alpha1 {\n\tcfg := NewWatchdogTimerV1Alpha1()\n\tcfg.WatchdogDevice = \"/dev/watchdog0\"\n\tcfg.WatchdogTimeout = 2 * time.Minute\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *WatchdogTimerV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Runtime implements config.Config interface.\nfunc (s *WatchdogTimerV1Alpha1) Runtime() config.RuntimeConfig {\n\treturn s\n}\n\n// EventsEndpoint implements config.RuntimeConfig interface.\nfunc (s *WatchdogTimerV1Alpha1) EventsEndpoint() *string {\n\treturn nil\n}\n\n// KmsgLogURLs implements config.RuntimeConfig interface.\nfunc (s *WatchdogTimerV1Alpha1) KmsgLogURLs() []*url.URL {\n\treturn nil\n}\n\n// WatchdogTimer implements config.RuntimeConfig interface.\nfunc (s *WatchdogTimerV1Alpha1) WatchdogTimer() config.WatchdogTimerConfig {\n\treturn s\n}\n\n// Device implements config.WatchdogTimerConfig interface.\nfunc (s *WatchdogTimerV1Alpha1) Device() string {\n\treturn s.WatchdogDevice\n}\n\n// Timeout implements config.WatchdogTimerConfig interface.\nfunc (s *WatchdogTimerV1Alpha1) Timeout() time.Duration {\n\tif s.WatchdogTimeout == 0 {\n\t\treturn DefaultWatchdogTimeout\n\t}\n\n\treturn s.WatchdogTimeout\n}\n\n// Validate implements config.Validator interface.\nfunc (s *WatchdogTimerV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif s.WatchdogDevice == \"\" {\n\t\treturn nil, fmt.Errorf(\"watchdog device: empty value\")\n\t}\n\n\tif s.WatchdogTimeout != 0 && s.WatchdogTimeout < MinWatchdogTimeout {\n\t\treturn nil, fmt.Errorf(\"watchdog timeout: minimum value is %s\", MinWatchdogTimeout)\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/runtime/watchdog_timer_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"\n)\n\n//go:embed testdata/watchdogtimer.yaml\nvar expectedWatchdogTimerDocument []byte\n\nfunc TestWatchdogTimerMarshalStability(t *testing.T) {\n\tcfg := runtime.NewWatchdogTimerV1Alpha1()\n\tcfg.WatchdogDevice = \"/dev/watchdog0\"\n\tcfg.WatchdogTimeout = 3 * time.Minute\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedWatchdogTimerDocument, marshaled)\n}\n\nfunc TestWatchdogTimerValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *runtime.WatchdogTimerV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  runtime.NewWatchdogTimerV1Alpha1,\n\n\t\t\texpectedError: \"watchdog device: empty value\",\n\t\t},\n\t\t{\n\t\t\tname: \"negative timeout\",\n\t\t\tcfg: func() *runtime.WatchdogTimerV1Alpha1 {\n\t\t\t\tcfg := runtime.NewWatchdogTimerV1Alpha1()\n\t\t\t\tcfg.WatchdogDevice = \"/dev/watchdog1\"\n\t\t\t\tcfg.WatchdogTimeout = -1 * time.Minute\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"watchdog timeout: minimum value is 10s\",\n\t\t},\n\t\t{\n\t\t\tname: \"small timeout\",\n\t\t\tcfg: func() *runtime.WatchdogTimerV1Alpha1 {\n\t\t\t\tcfg := runtime.NewWatchdogTimerV1Alpha1()\n\t\t\t\tcfg.WatchdogDevice = \"/dev/watchdog1\"\n\t\t\t\tcfg.WatchdogTimeout = time.Second\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"watchdog timeout: minimum value is 10s\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *runtime.WatchdogTimerV1Alpha1 {\n\t\t\t\tcfg := runtime.NewWatchdogTimerV1Alpha1()\n\t\t\t\tcfg.WatchdogDevice = \"/dev/watchdog2\"\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ImageVerificationConfigV1Alpha1 -type TrustedRootsConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage security\n\n// DeepCopy generates a deep copy of *ImageVerificationConfigV1Alpha1.\nfunc (o *ImageVerificationConfigV1Alpha1) DeepCopy() *ImageVerificationConfigV1Alpha1 {\n\tvar cp ImageVerificationConfigV1Alpha1 = *o\n\tif o.ConfigRules != nil {\n\t\tcp.ConfigRules = make([]ImageVerificationRuleV1Alpha1, len(o.ConfigRules))\n\t\tcopy(cp.ConfigRules, o.ConfigRules)\n\t\tfor i2 := range o.ConfigRules {\n\t\t\tif o.ConfigRules[i2].RuleSkip != nil {\n\t\t\t\tcp.ConfigRules[i2].RuleSkip = new(bool)\n\t\t\t\t*cp.ConfigRules[i2].RuleSkip = *o.ConfigRules[i2].RuleSkip\n\t\t\t}\n\t\t\tif o.ConfigRules[i2].RuleDeny != nil {\n\t\t\t\tcp.ConfigRules[i2].RuleDeny = new(bool)\n\t\t\t\t*cp.ConfigRules[i2].RuleDeny = *o.ConfigRules[i2].RuleDeny\n\t\t\t}\n\t\t\tif o.ConfigRules[i2].RuleKeylessVerifier != nil {\n\t\t\t\tcp.ConfigRules[i2].RuleKeylessVerifier = new(ImageKeylessVerifierV1Alpha1)\n\t\t\t\t*cp.ConfigRules[i2].RuleKeylessVerifier = *o.ConfigRules[i2].RuleKeylessVerifier\n\t\t\t}\n\t\t\tif o.ConfigRules[i2].RulePublicKeyVerifier != nil {\n\t\t\t\tcp.ConfigRules[i2].RulePublicKeyVerifier = new(ImagePublicKeyVerifierV1Alpha1)\n\t\t\t\t*cp.ConfigRules[i2].RulePublicKeyVerifier = *o.ConfigRules[i2].RulePublicKeyVerifier\n\t\t\t}\n\t\t}\n\t}\n\treturn &cp\n}\n\n// DeepCopy generates a deep copy of *TrustedRootsConfigV1Alpha1.\nfunc (o *TrustedRootsConfigV1Alpha1) DeepCopy() *TrustedRootsConfigV1Alpha1 {\n\tvar cp TrustedRootsConfigV1Alpha1 = *o\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/image_verification.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n// ImageVerificationConfigKind defines the ImageVerificationConfig configuration kind.\nconst ImageVerificationConfigKind = \"ImageVerificationConfig\"\n\nfunc init() {\n\tregistry.Register(ImageVerificationConfigKind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\":\n\t\t\treturn &ImageVerificationConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.ImageVerificationConfig = &ImageVerificationConfigV1Alpha1{}\n\t_ config.Validator               = &ImageVerificationConfigV1Alpha1{}\n)\n\n// ImageVerificationConfigV1Alpha1 configures image signature verification policy.\n//\n//\texamples:\n//\t  - value: exampleImageVerificationConfigV1Alpha1()\n//\talias: ImageVerificationConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/ImageVerificationConfig\ntype ImageVerificationConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     List of verification rules.\n\t//     Rules are evaluated in order; first matching rule applies.\n\tConfigRules ImageVerificationRules `yaml:\"rules,omitempty\"`\n}\n\n// ImageVerificationRules is a list of ImageVerificationRuleV1Alpha1.\n//\n//docgen:alias\ntype ImageVerificationRules []ImageVerificationRuleV1Alpha1\n\n//docgen:nodoc\ntype indexedRule struct {\n\ti    int\n\trule ImageVerificationRuleV1Alpha1\n}\n\n// Merge the network interface configuration intelligently.\nfunc (r *ImageVerificationRules) Merge(other any) error {\n\totherRules, ok := other.(ImageVerificationRules)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for merge %T\", other)\n\t}\n\n\trulesByPattern := make(map[string]indexedRule)\n\tfor i, rule := range *r {\n\t\trulesByPattern[rule.RuleImagePattern] = indexedRule{i: i, rule: rule}\n\t}\n\n\tfor _, otherRule := range otherRules {\n\t\tiRule, exists := rulesByPattern[otherRule.RuleImagePattern]\n\t\tif exists {\n\t\t\t// replace\n\t\t\t(*r)[iRule.i] = otherRule\n\t\t} else {\n\t\t\t// append\n\t\t\t*r = append(*r, otherRule)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ImageVerificationRuleV1Alpha1 defines a verification rule.\ntype ImageVerificationRuleV1Alpha1 struct {\n\t//   description: |\n\t//     Image reference pattern to match for this rule.\n\t//     Supports glob patterns.\n\t//   examples:\n\t//     - value: >\n\t//         \"docker.io/library/nginx\"\n\t//     - value: >\n\t//         \"registry.k8s.io/*\"\n\tRuleImagePattern string `yaml:\"image,omitempty\"`\n\n\t//   description: |\n\t//     Skip verification for this image pattern (default: false).\n\tRuleSkip *bool `yaml:\"skip,omitempty\"`\n\n\t//   description: |\n\t//     Deny pulling images matching the pattern (default: false).\n\tRuleDeny *bool `yaml:\"deny,omitempty\"`\n\n\t//   description: |\n\t//     Keyless verifier configuration to use for this rule.\n\tRuleKeylessVerifier *ImageKeylessVerifierV1Alpha1 `yaml:\"keyless,omitempty\"`\n\n\t//   description: |\n\t//     Public key verifier configuration to use for this rule.\n\tRulePublicKeyVerifier *ImagePublicKeyVerifierV1Alpha1 `yaml:\"publicKey,omitempty\"`\n}\n\n// ImageKeylessVerifierV1Alpha1 configures a signature verification provider using Cosign keyless verification.\ntype ImageKeylessVerifierV1Alpha1 struct {\n\t//   description: |\n\t//     OIDC issuer URL for keyless verification.\n\t//   examples:\n\t//      - value: >\n\t//         \"https://accounts.google.com\"\n\t//      - value: >\n\t//         \"https://token.actions.githubusercontent.com\"\n\tKeylessIssuer string `yaml:\"issuer,omitempty\"`\n\n\t//   description: |\n\t//     Expected subject for keyless verification.\n\t//\n\t//     This is the identity (email, URI) that signed the image.\n\tKeylessSubject string `yaml:\"subject,omitempty\"`\n\n\t//   description: |\n\t//     Regex pattern for subject matching.\n\t//\n\t//     Use this instead of subject for flexible matching.\n\t//   examples:\n\t//       - value: >\n\t//           \".*@example\\\\.com\"\n\tKeylessSubjectRegex string `yaml:\"subjectRegex,omitempty\"`\n}\n\n// ImagePublicKeyVerifierV1Alpha1 configures a signature verification provider using a static public key.\ntype ImagePublicKeyVerifierV1Alpha1 struct {\n\t//   description: |\n\t//     A public certificate in PEM format accepted for image signature verification.\n\tConfigCertificate string `yaml:\"certificate,omitempty\"`\n}\n\n// NewImageVerificationConfigV1Alpha1 creates a new ImageVerificationConfig config document.\nfunc NewImageVerificationConfigV1Alpha1() *ImageVerificationConfigV1Alpha1 {\n\treturn &ImageVerificationConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       ImageVerificationConfigKind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleImageVerificationConfigV1Alpha1() *ImageVerificationConfigV1Alpha1 {\n\tcfg := NewImageVerificationConfigV1Alpha1()\n\tcfg.ConfigRules = []ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"registry.k8s.io/*\",\n\t\t\tRuleKeylessVerifier: &ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:  \"https://accounts.google.com\",\n\t\t\t\tKeylessSubject: \"krel-trust@k8s-releng-prod.iam.gserviceaccount.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"my-registry/*\",\n\t\t\tRulePublicKeyVerifier: &ImagePublicKeyVerifierV1Alpha1{\n\t\t\t\tConfigCertificate: `-----BEGIN CERTIFICATE-----\nMII--Sample Value--\n-----END CERTIFICATE-----`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"locahost:3000/*\",\n\t\t\tRuleDeny:         new(true),\n\t\t},\n\t}\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *ImageVerificationConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Validate implements config.Validator interface.\n//\n//nolint:gocyclo\nfunc (s *ImageVerificationConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tvar (\n\t\terrs     error\n\t\twarnings []string\n\t)\n\n\tfor i, rule := range s.ConfigRules {\n\t\tif rule.RuleImagePattern == \"\" {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: imagePattern must be specified\", i))\n\t\t}\n\n\t\tskip := pointer.SafeDeref(rule.RuleSkip)\n\t\tdeny := pointer.SafeDeref(rule.RuleDeny)\n\t\thasRules := rule.RuleKeylessVerifier != nil || rule.RulePublicKeyVerifier != nil\n\n\t\tif skip && deny {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: skip and deny cannot both be true\", i))\n\t\t}\n\n\t\tif (skip || deny) && hasRules {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: verifiers cannot be configured if skip or deny is true\", i))\n\t\t}\n\n\t\tif !skip && !deny && !hasRules {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: at least one verifier must be configured\", i))\n\t\t}\n\n\t\tif rule.RuleKeylessVerifier != nil && rule.RulePublicKeyVerifier != nil {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: only one of keyless or publicKey verifier can be configured\", i))\n\t\t}\n\n\t\tif rule.RuleKeylessVerifier != nil {\n\t\t\truleVerifier := rule.RuleKeylessVerifier\n\t\t\tif ruleVerifier.KeylessIssuer == \"\" {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: verifier OIDC issuer must be specified\", i))\n\t\t\t}\n\n\t\t\tif ruleVerifier.KeylessSubject == \"\" && ruleVerifier.KeylessSubjectRegex == \"\" {\n\t\t\t\terrs = errors.Join(errs,\n\t\t\t\t\tfmt.Errorf(\"rule %d: verifier subject or subjectRegex must be specified\", i))\n\t\t\t}\n\t\t}\n\n\t\tif rule.RulePublicKeyVerifier != nil {\n\t\t\truleVerifier := rule.RulePublicKeyVerifier\n\t\t\tif ruleVerifier.ConfigCertificate == \"\" {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"rule %d: verifier certificates must be specified\", i))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn warnings, errs\n}\n\n// Rules implements config.ImageVerificationConfig interface.\nfunc (s *ImageVerificationConfigV1Alpha1) Rules() []config.ImageVerificationRule {\n\treturn xslices.Map(s.ConfigRules, func(r ImageVerificationRuleV1Alpha1) config.ImageVerificationRule {\n\t\treturn &r\n\t})\n}\n\n// ImagePattern implements config.ImageVerificationRule interface.\nfunc (r *ImageVerificationRuleV1Alpha1) ImagePattern() string {\n\treturn r.RuleImagePattern\n}\n\n// Skip implements config.ImageVerificationRule interface.\nfunc (r *ImageVerificationRuleV1Alpha1) Skip() bool {\n\treturn pointer.SafeDeref(r.RuleSkip)\n}\n\n// Deny implements config.ImageVerificationRule interface.\nfunc (r *ImageVerificationRuleV1Alpha1) Deny() bool {\n\treturn pointer.SafeDeref(r.RuleDeny)\n}\n\n// VerifierKeyless implements config.ImageVerificationRule interface.\nfunc (r *ImageVerificationRuleV1Alpha1) VerifierKeyless() config.ImageKeylessVerifier {\n\tif r.RuleKeylessVerifier == nil {\n\t\treturn nil\n\t}\n\n\treturn r.RuleKeylessVerifier\n}\n\n// VerifierPublicKey implements config.ImageVerificationRule interface.\nfunc (r *ImageVerificationRuleV1Alpha1) VerifierPublicKey() config.ImagePublicKeyVerifier {\n\tif r.RulePublicKeyVerifier == nil {\n\t\treturn nil\n\t}\n\n\treturn r.RulePublicKeyVerifier\n}\n\n// Issuer implements config.ImageVerifierKeyless interface.\nfunc (k *ImageKeylessVerifierV1Alpha1) Issuer() string {\n\treturn k.KeylessIssuer\n}\n\n// Subject implements config.ImageVerifierKeyless interface.\nfunc (k *ImageKeylessVerifierV1Alpha1) Subject() string {\n\treturn k.KeylessSubject\n}\n\n// SubjectRegex implements config.ImageVerifierKeyless interface.\nfunc (k *ImageKeylessVerifierV1Alpha1) SubjectRegex() string {\n\treturn k.KeylessSubjectRegex\n}\n\n// Certificate implements config.ImagePublicKeyVerifier interface.\nfunc (p *ImagePublicKeyVerifierV1Alpha1) Certificate() string {\n\treturn p.ConfigCertificate\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/image_verification_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n)\n\n//go:embed testdata/imageverificationconfig.yaml\nvar expectedImageVerificationConfigDocument []byte\n\nfunc TestImageVerificationConfigMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := security.NewImageVerificationConfigV1Alpha1()\n\tcfg.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"ghcr.io/*\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\tKeylessSubjectRegex: \"https://github.com/myorg/.*\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"my-registry/*\",\n\t\t\tRulePublicKeyVerifier: &security.ImagePublicKeyVerifierV1Alpha1{\n\t\t\t\tConfigCertificate: `-----BEGIN CERTIFICATE-----\nMII--Sample Value--\n-----END CERTIFICATE-----`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"no-verifier/*\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"deny-all/*\",\n\t\t\tRuleDeny:         new(true),\n\t\t},\n\t}\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, string(expectedImageVerificationConfigDocument), string(marshaled))\n}\n\nfunc TestImageVerificationConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedImageVerificationConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &security.ImageVerificationConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       security.ImageVerificationConfigKind,\n\t\t},\n\t\tConfigRules: []security.ImageVerificationRuleV1Alpha1{\n\t\t\t{\n\t\t\t\tRuleImagePattern: \"ghcr.io/*\",\n\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\t\tKeylessSubjectRegex: \"https://github.com/myorg/.*\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tRuleImagePattern: \"my-registry/*\",\n\t\t\t\tRulePublicKeyVerifier: &security.ImagePublicKeyVerifierV1Alpha1{\n\t\t\t\t\tConfigCertificate: `-----BEGIN CERTIFICATE-----\nMII--Sample Value--\n-----END CERTIFICATE-----`,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tRuleImagePattern: \"no-verifier/*\",\n\t\t\t\tRuleSkip:         new(true),\n\t\t\t},\n\t\t\t{\n\t\t\t\tRuleImagePattern: \"deny-all/*\",\n\t\t\t\tRuleDeny:         new(true),\n\t\t\t},\n\t\t},\n\t}, docs[0])\n}\n\nfunc TestImageVerificationConfigRules(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := security.NewImageVerificationConfigV1Alpha1()\n\tcfg.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"docker.io/library/*\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:       \"https://accounts.google.com\",\n\t\t\t\tKeylessSubjectRegex: \"foo@bork.gserviceaccount.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"**\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t}\n\n\trules := cfg.Rules()\n\trequire.Len(t, rules, 2)\n\n\tassert.Equal(t, \"docker.io/library/*\", rules[0].ImagePattern())\n\tassert.False(t, rules[0].Skip())\n\tassert.False(t, rules[0].Deny())\n\tassert.NotNil(t, rules[0].VerifierKeyless())\n\tassert.Nil(t, rules[0].VerifierPublicKey())\n\tassert.Equal(t, \"https://accounts.google.com\", rules[0].VerifierKeyless().Issuer())\n\tassert.Equal(t, \"foo@bork.gserviceaccount.com\", rules[0].VerifierKeyless().SubjectRegex())\n\n\tassert.Equal(t, \"**\", rules[1].ImagePattern())\n\tassert.True(t, rules[1].Skip())\n\tassert.False(t, rules[1].Deny())\n\tassert.Nil(t, rules[1].VerifierKeyless())\n\tassert.Nil(t, rules[1].VerifierPublicKey())\n}\n\nfunc TestImageVerificationConfigValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func() *security.ImageVerificationConfigV1Alpha1\n\n\t\texpectedErrors string\n\t}{\n\t\t{\n\t\t\tname: \"valid config\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"ghcr.io/*\",\n\t\t\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\t\t\t\tKeylessSubjectRegex: \"https://github.com/myorg/.*\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid config with subject instead of subjectRegex\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\t\t\tKeylessIssuer:  \"https://accounts.google.com\",\n\t\t\t\t\t\t\tKeylessSubject: \"user@example.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid config with skip and no verifier\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"registry.internal.example.com/*\",\n\t\t\t\t\t\tRuleSkip:         new(true),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"valid config with deny and no verifier\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"registry.internal.example.com/*\",\n\t\t\t\t\t\tRuleDeny:         new(true),\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"rule missing imagePattern\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: imagePattern must be specified\\nrule 0: at least one verifier must be configured\",\n\t\t},\n\t\t{\n\t\t\tname: \"no verifier\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: at least one verifier must be configured\",\n\t\t},\n\t\t{\n\t\t\tname: \"verifier missing issuer\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\t\t\tKeylessSubject: \"user@example.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: verifier OIDC issuer must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"verifier missing subject and subjectRegex\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\t\t\tKeylessIssuer: \"https://accounts.google.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: verifier subject or subjectRegex must be specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"rule 0: verifiers cannot be configured if skip or deny is true\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t\tRuleSkip:         new(true),\n\t\t\t\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\t\t\t\tKeylessIssuer:  \"https://accounts.google.com\",\n\t\t\t\t\t\t\tKeylessSubject: \"user@example.com\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: verifiers cannot be configured if skip or deny is true\",\n\t\t},\n\t\t{\n\t\t\tname: \"multiple errors\",\n\n\t\t\tcfg: func() *security.ImageVerificationConfigV1Alpha1 {\n\t\t\t\tc := security.NewImageVerificationConfigV1Alpha1()\n\t\t\t\tc.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleSkip: new(true),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedErrors: \"rule 0: imagePattern must be specified\\nrule 1: at least one verifier must be configured\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg()\n\n\t\t\twarnings, err := cfg.Validate(validationMode{})\n\n\t\t\tif test.expectedErrors == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Empty(t, warnings)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.EqualError(t, err, test.expectedErrors)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n\nfunc TestImageVerificationConfigMerge(t *testing.T) {\n\tt.Parallel()\n\n\tbaseCfg := security.NewImageVerificationConfigV1Alpha1()\n\tbaseCfg.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"ghcr.io/siderolabs/talos*\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"docker.io/*\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:  \"https://accounts.google.com\",\n\t\t\t\tKeylessSubject: \"user@example.com\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"**\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\tKeylessSubjectRegex: \"https://github.com/fallbackorg/.*\",\n\t\t\t},\n\t\t},\n\t}\n\n\toverrideCfg := security.NewImageVerificationConfigV1Alpha1()\n\toverrideCfg.ConfigRules = []security.ImageVerificationRuleV1Alpha1{\n\t\t{\n\t\t\tRuleImagePattern: \"ghcr.io/siderolabs/talos*\",\n\t\t\tRuleKeylessVerifier: &security.ImageKeylessVerifierV1Alpha1{\n\t\t\t\tKeylessIssuer:       \"https://token.actions.githubusercontent.com\",\n\t\t\t\tKeylessSubjectRegex: \"https://github.com/differentorg/.*\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRuleImagePattern: \"**\",\n\t\t\tRuleSkip:         new(true),\n\t\t},\n\t}\n\n\trequire.NoError(t, merge.Merge(baseCfg, overrideCfg))\n\n\trequire.Len(t, baseCfg.ConfigRules, 3)\n\n\tassert.Equal(t, \"ghcr.io/siderolabs/talos*\", baseCfg.ConfigRules[0].RuleImagePattern)\n\tassert.False(t, pointer.SafeDeref(baseCfg.ConfigRules[0].RuleSkip))\n\tassert.Equal(t, \"https://token.actions.githubusercontent.com\", baseCfg.ConfigRules[0].RuleKeylessVerifier.KeylessIssuer)\n\tassert.Equal(t, \"https://github.com/differentorg/.*\", baseCfg.ConfigRules[0].RuleKeylessVerifier.KeylessSubjectRegex)\n\n\tassert.Equal(t, \"docker.io/*\", baseCfg.ConfigRules[1].RuleImagePattern)\n\tassert.False(t, pointer.SafeDeref(baseCfg.ConfigRules[1].RuleSkip))\n\tassert.Equal(t, \"https://accounts.google.com\", baseCfg.ConfigRules[1].RuleKeylessVerifier.KeylessIssuer)\n\tassert.Equal(t, \"user@example.com\", baseCfg.ConfigRules[1].RuleKeylessVerifier.KeylessSubject)\n\n\tassert.Equal(t, \"**\", baseCfg.ConfigRules[2].RuleImagePattern)\n\tassert.True(t, pointer.SafeDeref(baseCfg.ConfigRules[2].RuleSkip))\n\tassert.Nil(t, baseCfg.ConfigRules[2].RuleKeylessVerifier)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/security.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package security provides security-related machine configuration documents.\npackage security\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output security_doc.go security.go trusted_roots.go image_verification.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ImageVerificationConfigV1Alpha1 -type TrustedRootsConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/config/types/security/security_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage security\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (TrustedRootsConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"TrustedRootsConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"TrustedRootsConfig allows to configure additional trusted CA roots.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"TrustedRootsConfig allows to configure additional trusted CA roots.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the config document.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the config document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"certificates\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of additional trusted certificate authorities (as PEM-encoded certificates).\\n\\nMultiple certificates can be provided in a single config document, separated by newline characters.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of additional trusted certificate authorities (as PEM-encoded certificates).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleTrustedRootsConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (ImageVerificationConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ImageVerificationConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ImageVerificationConfig configures image signature verification policy.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ImageVerificationConfig configures image signature verification policy.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"rules\",\n\t\t\t\tType:        \"[]ImageVerificationRuleV1Alpha1\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of verification rules.\\nRules are evaluated in order; first matching rule applies.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of verification rules.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleImageVerificationConfigV1Alpha1())\n\n\treturn doc\n}\n\nfunc (ImageVerificationRuleV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ImageVerificationRuleV1Alpha1\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ImageVerificationRuleV1Alpha1 defines a verification rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ImageVerificationRuleV1Alpha1 defines a verification rule.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ImageVerificationConfigV1Alpha1\",\n\t\t\t\tFieldName: \"rules\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Image reference pattern to match for this rule.\\nSupports glob patterns.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Image reference pattern to match for this rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"skip\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Skip verification for this image pattern (default: false).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Skip verification for this image pattern (default: false).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"deny\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Deny pulling images matching the pattern (default: false).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Deny pulling images matching the pattern (default: false).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"keyless\",\n\t\t\t\tType:        \"ImageKeylessVerifierV1Alpha1\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Keyless verifier configuration to use for this rule.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Keyless verifier configuration to use for this rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"publicKey\",\n\t\t\t\tType:        \"ImagePublicKeyVerifierV1Alpha1\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Public key verifier configuration to use for this rule.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Public key verifier configuration to use for this rule.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", \"docker.io/library/nginx\")\n\tdoc.Fields[0].AddExample(\"\", \"registry.k8s.io/*\")\n\n\treturn doc\n}\n\nfunc (ImageKeylessVerifierV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ImageKeylessVerifierV1Alpha1\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ImageKeylessVerifierV1Alpha1 configures a signature verification provider using Cosign keyless verification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ImageKeylessVerifierV1Alpha1 configures a signature verification provider using Cosign keyless verification.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ImageVerificationRuleV1Alpha1\",\n\t\t\t\tFieldName: \"keyless\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"issuer\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"OIDC issuer URL for keyless verification.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"OIDC issuer URL for keyless verification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"subject\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Expected subject for keyless verification.\\n\\nThis is the identity (email, URI) that signed the image.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Expected subject for keyless verification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"subjectRegex\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Regex pattern for subject matching.\\n\\nUse this instead of subject for flexible matching.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Regex pattern for subject matching.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", \"https://accounts.google.com\")\n\tdoc.Fields[0].AddExample(\"\", \"https://token.actions.githubusercontent.com\")\n\tdoc.Fields[2].AddExample(\"\", \".*@example\\\\.com\")\n\n\treturn doc\n}\n\nfunc (ImagePublicKeyVerifierV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ImagePublicKeyVerifierV1Alpha1\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ImagePublicKeyVerifierV1Alpha1 configures a signature verification provider using a static public key.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ImagePublicKeyVerifierV1Alpha1 configures a signature verification provider using a static public key.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ImageVerificationRuleV1Alpha1\",\n\t\t\t\tFieldName: \"publicKey\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"certificate\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A public certificate in PEM format accepted for image signature verification.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A public certificate in PEM format accepted for image signature verification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file security_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"security\",\n\t\tDescription: \"Package security provides security-related machine configuration documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tTrustedRootsConfigV1Alpha1{}.Doc(),\n\t\t\tImageVerificationConfigV1Alpha1{}.Doc(),\n\t\t\tImageVerificationRuleV1Alpha1{}.Doc(),\n\t\t\tImageKeylessVerifierV1Alpha1{}.Doc(),\n\t\t\tImagePublicKeyVerifierV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/testdata/imageverificationconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: ImageVerificationConfig\nrules:\n    - image: ghcr.io/*\n      keyless:\n        issuer: https://token.actions.githubusercontent.com\n        subjectRegex: https://github.com/myorg/.*\n    - image: my-registry/*\n      publicKey:\n        certificate: |-\n            -----BEGIN CERTIFICATE-----\n            MII--Sample Value--\n            -----END CERTIFICATE-----\n    - image: no-verifier/*\n      skip: true\n    - image: deny-all/*\n      deny: true\n"
  },
  {
    "path": "pkg/machinery/config/types/security/testdata/trustedrootsconfig.yaml",
    "content": "apiVersion: v1alpha1\nkind: TrustedRootsConfig\nname: custom-ca\ncertificates: |-\n    -----BEGIN CERTIFICATE-----\n    MIIC0DCCAbigAwIBAgIUI7z\n    -----END CERTIFICATE-----\n"
  },
  {
    "path": "pkg/machinery/config/types/security/trusted_roots.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security\n\n//docgen:jsonschema\n\nimport (\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n)\n\n// TrustedRootsConfig is a default action config document kind.\nconst TrustedRootsConfig = \"TrustedRootsConfig\"\n\nfunc init() {\n\tregistry.Register(TrustedRootsConfig, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\":\n\t\t\treturn &TrustedRootsConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.TrustedRootsConfig = &TrustedRootsConfigV1Alpha1{}\n\t_ config.NamedDocument      = &TrustedRootsConfigV1Alpha1{}\n)\n\n// TrustedRootsConfigV1Alpha1 allows to configure additional trusted CA roots.\n//\n//\texamples:\n//\t  - value: exampleTrustedRootsConfigV1Alpha1()\n//\talias: TrustedRootsConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/TrustedRootsConfig\ntype TrustedRootsConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     Name of the config document.\n\t//   schemaRequired: true\n\tMetaName string `yaml:\"name\"`\n\t//   description: |\n\t//     List of additional trusted certificate authorities (as PEM-encoded certificates).\n\t//\n\t//     Multiple certificates can be provided in a single config document, separated by newline characters.\n\tCertificates string `yaml:\"certificates\"`\n}\n\n// NewTrustedRootsConfigV1Alpha1 creates a new TrustedRootsConfig config document.\nfunc NewTrustedRootsConfigV1Alpha1() *TrustedRootsConfigV1Alpha1 {\n\treturn &TrustedRootsConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       TrustedRootsConfig,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleTrustedRootsConfigV1Alpha1() *TrustedRootsConfigV1Alpha1 {\n\tcfg := NewTrustedRootsConfigV1Alpha1()\n\tcfg.MetaName = \"my-enterprise-ca\"\n\tcfg.Certificates = `-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n`\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *TrustedRootsConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Name implements config.NamedDocument interface.\nfunc (s *TrustedRootsConfigV1Alpha1) Name() string {\n\treturn s.MetaName\n}\n\n// ExtraTrustedRootCertificates implements config.TrustedRootsConfig interface.\nfunc (s *TrustedRootsConfigV1Alpha1) ExtraTrustedRootCertificates() []string {\n\t// build a header with the config name\n\theader := \"\\n\" + s.MetaName + \":\\n\" + strings.Repeat(\"=\", len(s.MetaName)+1) + \"\\n\"\n\n\treturn []string{header + s.Certificates}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/security/trusted_roots_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/security\"\n)\n\n//go:embed testdata/trustedrootsconfig.yaml\nvar expectedTrustedRootsConfigDocument []byte\n\nfunc TestTrustedRootsMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := security.NewTrustedRootsConfigV1Alpha1()\n\tcfg.MetaName = \"custom-ca\"\n\tcfg.Certificates = \"-----BEGIN CERTIFICATE-----\\nMIIC0DCCAbigAwIBAgIUI7z\\n-----END CERTIFICATE-----\"\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tt.Log(string(marshaled))\n\n\tassert.Equal(t, expectedTrustedRootsConfigDocument, marshaled)\n}\n\nfunc TestTrustedConfigUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\tprovider, err := configloader.NewFromBytes(expectedTrustedRootsConfigDocument)\n\trequire.NoError(t, err)\n\n\tdocs := provider.Documents()\n\trequire.Len(t, docs, 1)\n\n\tassert.Equal(t, &security.TrustedRootsConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t\tMetaKind:       security.TrustedRootsConfig,\n\t\t},\n\t\tMetaName:     \"custom-ca\",\n\t\tCertificates: \"-----BEGIN CERTIFICATE-----\\nMIIC0DCCAbigAwIBAgIUI7z\\n-----END CERTIFICATE-----\",\n\t}, docs[0])\n}\n\nfunc TestTrustedConfigHeader(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := security.NewTrustedRootsConfigV1Alpha1()\n\tcfg.MetaName = \"custom-ca\"\n\tcfg.Certificates = \"-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\"\n\n\tassert.Equal(t, []string{\"\\ncustom-ca:\\n==========\\n-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\"}, cfg.ExtraTrustedRootCertificates())\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/siderolink/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage siderolink\n\nimport (\n\t\"net/url\"\n)\n\n// DeepCopy generates a deep copy of *ConfigV1Alpha1.\nfunc (o *ConfigV1Alpha1) DeepCopy() *ConfigV1Alpha1 {\n\tvar cp ConfigV1Alpha1 = *o\n\tif o.APIUrlConfig.URL != nil {\n\t\tcp.APIUrlConfig.URL = new(url.URL)\n\t\t*cp.APIUrlConfig.URL = *o.APIUrlConfig.URL\n\t\tif o.APIUrlConfig.URL.User != nil {\n\t\t\tcp.APIUrlConfig.URL.User = new(url.Userinfo)\n\t\t\t*cp.APIUrlConfig.URL.User = *o.APIUrlConfig.URL.User\n\t\t}\n\t}\n\treturn &cp\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/siderolink/siderolink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package siderolink provides SideroLink machine configuration documents.\npackage siderolink\n\n//docgen:jsonschema\n\nimport (\n\t\"errors\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/meta\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n)\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output ./siderolink_doc.go ./siderolink.go\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// Kind is a siderolink config document kind.\nconst Kind = \"SideroLinkConfig\"\n\nfunc init() {\n\tregistry.Register(Kind, func(version string) config.Document {\n\t\tswitch version {\n\t\tcase \"v1alpha1\":\n\t\t\treturn &ConfigV1Alpha1{}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t})\n}\n\n// Check interfaces.\nvar (\n\t_ config.SecretDocument   = &ConfigV1Alpha1{}\n\t_ config.SideroLinkConfig = &ConfigV1Alpha1{}\n\t_ config.Validator        = &ConfigV1Alpha1{}\n)\n\n// ConfigV1Alpha1 is a SideroLink connection machine configuration document.\n//\n//\texamples:\n//\t  - value: exampleConfigV1Alpha1()\n//\talias: SideroLinkConfig\n//\tschemaRoot: true\n//\tschemaMeta: v1alpha1/SideroLinkConfig\ntype ConfigV1Alpha1 struct {\n\tmeta.Meta `yaml:\",inline\"`\n\n\t//   description: |\n\t//     SideroLink API URL to connect to.\n\t//   examples:\n\t//     - value: >\n\t//        \"https://siderolink.api/?jointoken=secret\"\n\t//   schema:\n\t//     type: string\n\t//     pattern: \"^(https|grpc)://\"\n\tAPIUrlConfig meta.URL `yaml:\"apiUrl\"`\n\t//   description: |\n\t//     SideroLink unique token to use for the connection (optional).\n\t//\n\t//     This value is overridden with META key UniqueMachineToken.\n\tUniqueTokenConfig string `yaml:\"uniqueToken,omitempty\"`\n}\n\n// NewConfigV1Alpha1 creates a new siderolink config document.\nfunc NewConfigV1Alpha1() *ConfigV1Alpha1 {\n\treturn &ConfigV1Alpha1{\n\t\tMeta: meta.Meta{\n\t\t\tMetaKind:       Kind,\n\t\t\tMetaAPIVersion: \"v1alpha1\",\n\t\t},\n\t}\n}\n\nfunc exampleConfigV1Alpha1() *ConfigV1Alpha1 {\n\tcfg := NewConfigV1Alpha1()\n\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"https://siderolink.api/jointoken?token=secret\"))\n\n\treturn cfg\n}\n\n// Clone implements config.Document interface.\nfunc (s *ConfigV1Alpha1) Clone() config.Document {\n\treturn s.DeepCopy()\n}\n\n// Redact implements config.SecretDocument interface.\nfunc (s *ConfigV1Alpha1) Redact(replacement string) {\n\tif s.APIUrlConfig.URL != nil {\n\t\tquery := s.APIUrlConfig.Query()\n\t\tif query.Has(\"jointoken\") {\n\t\t\tquery.Set(\"jointoken\", replacement)\n\t\t}\n\n\t\ts.APIUrlConfig.RawQuery = query.Encode()\n\t}\n}\n\n// SideroLink implements config.SideroLink interface.\nfunc (s *ConfigV1Alpha1) SideroLink() config.SideroLinkConfig {\n\treturn s\n}\n\n// APIUrl implements config.SideroLink interface.\nfunc (s *ConfigV1Alpha1) APIUrl() *url.URL {\n\tif s == nil {\n\t\treturn nil\n\t}\n\n\treturn s.APIUrlConfig.URL\n}\n\n// UniqueToken implements config.SideroLink interface.\nfunc (s *ConfigV1Alpha1) UniqueToken() string {\n\tif s == nil {\n\t\treturn \"\"\n\t}\n\n\treturn s.UniqueTokenConfig\n}\n\n// Validate implements config.Validator interface.\nfunc (s *ConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) {\n\tif s.APIUrlConfig.URL == nil {\n\t\treturn nil, errors.New(\"apiUrl is required\")\n\t}\n\n\tswitch s.APIUrlConfig.URL.Scheme {\n\tcase \"https\":\n\tcase \"grpc\":\n\tdefault:\n\t\treturn nil, errors.New(\"apiUrl scheme must be https:// or grpc://\")\n\t}\n\n\tswitch s.APIUrlConfig.URL.Path {\n\tcase \"/\":\n\tcase \"\":\n\tdefault:\n\t\treturn nil, errors.New(\"apiUrl path must be empty\")\n\t}\n\n\treturn nil, nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/siderolink/siderolink_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage siderolink\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\nfunc (ConfigV1Alpha1) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"SideroLinkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SideroLinkConfig is a SideroLink connection machine configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"SideroLinkConfig is a SideroLink connection machine configuration document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tType:   \"Meta\",\n\t\t\t\tInline: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"apiUrl\",\n\t\t\t\tType:        \"URL\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"SideroLink API URL to connect to.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SideroLink API URL to connect to.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"uniqueToken\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"SideroLink unique token to use for the connection (optional).\\n\\nThis value is overridden with META key UniqueMachineToken.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SideroLink unique token to use for the connection (optional).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", exampleConfigV1Alpha1())\n\n\tdoc.Fields[1].AddExample(\"\", \"https://siderolink.api/?jointoken=secret\")\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file ./siderolink_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"siderolink\",\n\t\tDescription: \"Package siderolink provides SideroLink machine configuration documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tConfigV1Alpha1{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/siderolink/siderolink_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink_test\n\nimport (\n\t_ \"embed\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"\n)\n\nfunc TestRedact(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := siderolink.NewConfigV1Alpha1()\n\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))\n\n\tassert.Equal(t, \"https://siderolink.api/?jointoken=secret&user=alice\", cfg.SideroLink().APIUrl().String())\n\n\tcfg.Redact(\"REDACTED\")\n\n\tassert.Equal(t, \"https://siderolink.api/?jointoken=REDACTED&user=alice\", cfg.APIUrlConfig.String())\n}\n\n//go:embed testdata/document.yaml\nvar expectedDocument []byte\n\nfunc TestMarshalStability(t *testing.T) {\n\tt.Parallel()\n\n\tcfg := siderolink.NewConfigV1Alpha1()\n\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"https://siderolink.api/?jointoken=secret&user=alice\"))\n\n\tmarshaled, err := encoder.NewEncoder(cfg, encoder.WithComments(encoder.CommentsDisabled)).Encode()\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, expectedDocument, marshaled)\n}\n\nfunc TestValidate(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\tcfg  func() *siderolink.ConfigV1Alpha1\n\n\t\texpectedError    string\n\t\texpectedWarnings []string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tcfg:  siderolink.NewConfigV1Alpha1,\n\n\t\t\texpectedError: \"apiUrl is required\",\n\t\t},\n\t\t{\n\t\t\tname: \"wrong scheme\",\n\t\t\tcfg: func() *siderolink.ConfigV1Alpha1 {\n\t\t\t\tcfg := siderolink.NewConfigV1Alpha1()\n\t\t\t\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"http://siderolink.api/\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"apiUrl scheme must be https:// or grpc://\",\n\t\t},\n\t\t{\n\t\t\tname: \"extra path\",\n\t\t\tcfg: func() *siderolink.ConfigV1Alpha1 {\n\t\t\t\tcfg := siderolink.NewConfigV1Alpha1()\n\t\t\t\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"grpc://siderolink.api/path?jointoken=foo\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\n\t\t\texpectedError: \"apiUrl path must be empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tcfg: func() *siderolink.ConfigV1Alpha1 {\n\t\t\t\tcfg := siderolink.NewConfigV1Alpha1()\n\t\t\t\tcfg.APIUrlConfig.URL = ensure.Value(url.Parse(\"https://siderolink.api:434/?jointoken=foo\"))\n\n\t\t\t\treturn cfg\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\twarnings, err := test.cfg().Validate(validationMode{})\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype validationMode struct{}\n\nfunc (validationMode) String() string {\n\treturn \"\"\n}\n\nfunc (validationMode) RequiresInstall() bool {\n\treturn false\n}\n\nfunc (validationMode) InContainer() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/siderolink/testdata/document.yaml",
    "content": "apiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/?jointoken=secret&user=alice\n"
  },
  {
    "path": "pkg/machinery/config/types/types.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package types imports all configuration document types to register them.\n//\n//nolint:revive\npackage types\n\nimport (\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/block\"              // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/cri\"                // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/hardware\"           // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"            // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime\"            // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions\" // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/security\"           // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/siderolink\"         // import config types to register them\n\t_ \"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"           // import config types to register them\n)\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// +k8s:deepcopy-gen=package\n\npackage v1alpha1\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/patch.yaml",
    "content": "machine:\n  kubelet:\n    extraMounts:\n      - source: /var/opt\n        destination: /var/opt\n        type: bind\n        options:\n          - rshared\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/secrets.yaml",
    "content": "# test set of secrets for config generation, please never use in production\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\nsecrets:\n    bootstraptoken: inn7ol.u4ehnti8qyls9ymo\n    secretboxencryptionsecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\ntrustdinfo:\n    token: d8cwfa.eyvpi0xwxyarbfid\ncerts:\n    etcd:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8s:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8saggregator:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    k8sserviceaccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    os:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.10/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.10/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.10/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.10/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.11/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.11/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.11/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.11/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.12/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n        grubUseUKICmdline: true\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.12/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n        grubUseUKICmdline: true\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.12/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n        grubUseUKICmdline: true\n    sysctls:\n        foo: bar\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - foo\n            - bar\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: ghcr.io\nendpoints:\n    - url: https://ghcr.io.my-mirror.com\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.12/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n        grubUseUKICmdline: true\n    sysctls:\n        foo: bar\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: ghcr.io\nendpoints:\n    - url: https://ghcr.io.my-mirror.com\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.13/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    install:\n        wipe: false\n        grubUseUKICmdline: true\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.13/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    install:\n        wipe: false\n        grubUseUKICmdline: true\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.13/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n        grubUseUKICmdline: true\n    sysctls:\n        foo: bar\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - foo\n            - bar\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: ghcr.io\nendpoints:\n    - url: https://ghcr.io.my-mirror.com\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.13/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n        grubUseUKICmdline: true\n    sysctls:\n        foo: bar\n    features:\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n---\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: ghcr.io\nendpoints:\n    - url: https://ghcr.io.my-mirror.com\n---\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.3/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.3/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.3/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.3/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.4/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.4/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.4/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.4/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.5/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.5/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.5/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.5/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.6/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.6/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.6/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.6/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.7/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.7/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.7/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.7/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.8/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.8/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.8/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.8/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.9/base-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.9/base-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        wipe: false\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.9/overrides-controlplane.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJTURXbklEdVpSdlhQcW1tbSt6bk15SWMrdk53ZjdnYksvSmR3WC9iN2d1RQotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\n    nodeLabels:\n        node.kubernetes.io/exclude-from-external-load-balancers: \"\"\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n        localAPIServerPort: 5443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    secretboxEncryptionSecret: 45yd2Ke+sytiICojDf8aibTfgt99nzJmO53cjDqrCto=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUVZbFloNzVTUTZ6VUJFTUZ6em5pUzZuVVg3Q2VxQ013S3k0RTZHVEVFMGNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFeXhvUi9JYklTZ3V2NG01azY2OFJTSzR6WDRjSHFoMlJHNVRCMEczenRtbnU0a1NHRUNWLwo2cmhCdzdHbE9KK2tjT3NEd0JNWGNGZ2dRVnBhQXM0MWF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJYakNDQVFXZ0F3SUJBZ0lRWnNnVDRZZzVxRkNIbS9QTnV5QUVSekFLQmdncWhrak9QUVFEQWpBQU1CNFgKRFRJek1UQXhNakV3TkRZd09Wb1hEVE16TVRBd09URXdORFl3T1Zvd0FEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxRwpTTTQ5QXdFSEEwSUFCRmQ1eEhFWHhZRndQeTdaWjhmd3FHRGU2YVQ5ZmxNRVlWZENRNDlEaWZobWVteTVDaHZRCnlVRkpZcFM4b21HODVTS1dnOEpFTkoyNnhEdm9WMFBCS2srallUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZApCZ05WSFE0RUZnUVV4K0xab1FrYjlmOTN0Y0g4NnZjOUc2ZE13T2t3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnClhudDVXdmEzOGtWVTB3NjExMEp4bU43Qm5zcWl2NnNMaXlJNXRUR1BDQk1DSUZDQlJ3RXZSYTNnU3pkdXB6ajcKQVJLV3NlK3V5YW9rMnlNYXZnaUVITWpUCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlMblhpQ3hOWU1CWHpncjVuYmc3bnVtUWM2UGlHaXdmWUN2eFF3Tlhxc3dvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjNuRWNSZkZnWEEvTHRsbngvQ29ZTjdwcFAxK1V3UmhWMEpEajBPSitHWjZiTGtLRzlESgpRVWxpbEx5aVliemxJcGFEd2tRMG5ickVPK2hYUThFcVR3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUlHVElBQjZZUzV0cFcrUnYxeDBPY09Jb1h0SXgzdGZteVFZNGxOWWRCbmpvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFQ3drbVVTUmtrbnlOc0NjTFJNUTlmZWx6cFY0dDdIdlNRcnp6ZGRvK2pWYmlqd2kwVVE1YQp0VW8vZkxQbDlBckVNOHNRWTVOSlgraVdxYjFkQWFXa2VnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.28.0\n        certSANs:\n            - base\n            - foo\n            - bar\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.28.0\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.28.0\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.28.0\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lRVkNTWmFQU3Z0TlZTcjYrVkRyUks0akFLQmdncWhrak9QUVFEQWpBUE1RMHcKQ3dZRFZRUUtFd1JsZEdOa01CNFhEVEl6TVRBeE1qRXdORFl3T1ZvWERUTXpNVEF3T1RFd05EWXdPVm93RHpFTgpNQXNHQTFVRUNoTUVaWFJqWkRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQk9wVXN0MHN3MEJZCkFDN0hpTGNrRElvdVdTRVhWTlJVWE42UmNLTWVRQU9VOEhJQkZBaTJlS2Rka2VJOEhZOTJNWTU1U21xQlhNK3cKRTh0RFgyT3kxSk9qWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjRApBUVlJS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVejVmai9oZTZoUjhMCkFRTU5qTjgxNS8zV3B6d3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdFWWcyTlp3NkExek02eURNWTRHN1JPVkwKc0JOU0VhSDd4VmVSalBSblAvZ0NJUURiYzFMNmI0SkU0MCtuUCtYNG5pZlB0QWp5REhhUzVMS0YzQWZkUkRWdApMUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU03Q2VnMk1GQW5TM3ROMzV6QTc0aFZ3VElkTkthK0ZwUHlYVERCdU4wVFlvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFNmxTeTNTekRRRmdBTHNlSXR5UU1paTVaSVJkVTFGUmMzcEZ3b3g1QUE1VHdjZ0VVQ0xaNApwMTJSNGp3ZGozWXhqbmxLYW9GY3o3QVR5ME5mWTdMVWt3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    allowSchedulingOnControlPlanes: true\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/stability/v1.9/overrides-worker.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: worker\n    token: d8cwfa.eyvpi0xwxyarbfid\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQakNCOGFBREFnRUNBaEI5cStGVXpodzkycHVPemtpNzB1eGRNQVVHQXl0bGNEQVFNUTR3REFZRFZRUUsKRXdWMFlXeHZjekFlRncweU16RXdNVEl4TURRMk1EbGFGdzB6TXpFd01Ea3hNRFEyTURsYU1CQXhEakFNQmdOVgpCQW9UQlhSaGJHOXpNQ293QlFZREsyVndBeUVBaHVLczZxeCtKWi8wWG8ybXdpQUNjK1EwSVYySGhMd3ozVTZICmUxemZjS2lqWVRCZk1BNEdBMVVkRHdFQi93UUVBd0lDaERBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUkKS3dZQkJRVUhBd0l3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVSlgzWlVNRktWWFZ5NWhKWQozZG9NWENpVEJZRXdCUVlESzJWd0EwRUFCbUxrbDhITmQ3cUpEN3VqQkk2UG9abVRQQWlEcU9GQ0NTVDZJYlZDClF3UzQ1bk1tMldtalRIc3ZrYU5FQ0dneTBhQXJaaFdsbnVYWUswY0t3Z2VJQ0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    certSANs:\n        - foo\n        - bar\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.28.0\n        extraMounts:\n            - destination: /var/opt\n              type: bind\n              source: /var/opt\n              options:\n                - rshared\n        defaultRuntimeSeccompProfileEnabled: true\n        disableManifestsDirectory: true\n    network: {}\n    install:\n        disk: /dev/vda\n        extraKernelArgs:\n            - foo=bar\n            - bar=baz\n        wipe: false\n    sysctls:\n        foo: bar\n    registries:\n        mirrors:\n            ghcr.io:\n                endpoints:\n                    - https://ghcr.io.my-mirror.com\n    features:\n        rbac: true\n        stableHostname: true\n        apidCheckExtKeyUsage: true\n        diskQuotaSupport: true\n        kubePrism:\n            enabled: true\n            port: 7445\n        hostDNS:\n            enabled: true\n            forwardKubeDNSToHost: true\ncluster:\n    id: 0raF93qnkMvF-FZNuvyGozXNdLiT2FOWSlyBaW4PR-w=\n    secret: pofHbABZq7VXuObsdLdy/bHmz6hlMHZ3p8+6WKrv1ic=\n    controlPlane:\n        endpoint: https://base:6443\n    clusterName: base\n    network:\n        cni:\n            name: custom\n            urls:\n                - https://example.com/cni.yaml\n        dnsDomain: example.com\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: inn7ol.u4ehnti8qyls9ymo\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRYm1hNDNPalRwR0I5TjVxOVFEc3RFekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXpNVEF4TWpFd05EWXdPVm9YRFRNek1UQXdPVEV3TkRZdwpPVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTXNhRWZ5R3lFb0xyK0p1Wk91dkVVaXVNMStIQjZvZGtSdVV3ZEJ0ODdacDd1SkVoaEFsZitxNFFjT3gKcFRpZnBIRHJBOEFURjNCWUlFRmFXZ0xPTld1allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU0ZEVkM1RoVzRKWlVWcXR1OEFZNWx1NUhQeGN3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUloQUpJbkFMb0EKY1VhRUp4VlJ5dkhQenFQcTBvaGJOY2oyT3N2d3VKUFMzSktVQWlCSmhwNGFWMG9zUURRSGJnbjdXUWFYaHZFTwo5bWxTbVRURTAyOXBWb0YyWkE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: \"\"\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n                disabled: true\n            service: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/001/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n        interfaces:\n            - interface: eth0\n              addresses:\n                - 10.3.5.7/24\n              dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: true\n    features:\n        rbac: false\n    env:\n        http_proxy: http://127.0.0.1:3128/\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://10.0.0.1/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets: [\"10.0.0.0/24\"]\n        serviceSubnets: [\"192.168.0.0/24\", \"ff:08::/64\"]\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes:\n              disabled: true\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/001/left.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network: {}\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/001/right.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth0\n        addresses:\n          - 10.3.5.7/24\n        dhcp: false\n  features:\n    rbac: false\n  env:\n    http_proxy: http://127.0.0.1:3128/\n  install:\n    wipe: true\ncluster:\n  controlPlane:\n    endpoint: https://10.0.0.1\n  discovery:\n    registries:\n      kubernetes:\n        disabled: true\n  network:\n    podSubnets: [\"10.0.0.0/24\"]\n    serviceSubnets: [\"192.168.0.0/24\", \"ff:08::/64\"]\n  serviceAccount:\n      key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/002/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network: {}\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/002/left.yaml",
    "content": "version: v1alpha1\nmachine: {}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/002/right.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network: {}\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/003/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n          vip:\n            ip: 10.3.5.7\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n          routes:\n            - network: 10.3.4.0/24\n              gateway: 10.3.4.1\n        - interface: eth1\n          addresses:\n            - \"192.168.0.1/24\"\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/003/left.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/003/right.yaml",
    "content": "machine:\n  network:\n    interfaces:\n      - interface: eth1\n        addresses:\n          - \"192.168.0.1/24\"\n      - interface: eth0\n        vip:\n          ip: 10.3.5.7\n      - deviceSelector:\n          driver: macvtap\n        routes:\n          - network: 10.3.4.0/24\n            gateway: 10.3.4.1\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/004/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: restricted\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                        - rook-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/004/left.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/004/right.yaml",
    "content": "cluster:\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                defaults:\n                    enforce: restricted\n                exemptions:\n                    namespaces:\n                        - rook-system\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/005/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.3\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/005/left.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/005/right.yaml",
    "content": "cluster:\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.3\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/006/expected.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: None\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/006/left.yaml",
    "content": "version: v1alpha1\ndebug: false\npersist: true\nmachine:\n    type: controlplane\n    token: u8ei4i.iymakyzguuqaw30r\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJQekNCOHFBREFnRUNBaEVBMENmN3VtOHV6akE4ZkRlY3FySElXakFGQmdNclpYQXdFREVPTUF3R0ExVUUKQ2hNRmRHRnNiM013SGhjTk1qSXdOakk1TVRNME9ERXhXaGNOTXpJd05qSTJNVE0wT0RFeFdqQVFNUTR3REFZRApWUVFLRXdWMFlXeHZjekFxTUFVR0F5dGxjQU1oQUR2dk1ESFdSY2xtRHdtOGRkNUZDV0w0djJQSlFnMkZ0bDBtCklLd1MwYjFObzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRk5TZGU2ZG9JZDFjckdLVwpxek1YbG80dStoVjRNQVVHQXl0bGNBTkJBR0c3aEQ3Z2FJckhnTnhKYjByOGVDdkozMS96eHQraW8wQlVoSi9FCnBvUkVxaWxOV1RHUDViSDRMcERqU2ZIOE1UcGdiZWhkZTRJUGxnRW5iR3VVYmdzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0KTUM0Q0FRQXdCUVlESzJWd0JDSUVJR2NZL0ZIU2lsNUhJTzlrcTNKZVBGbFdLNDJLZG9MOUwxYXBLZm1tdVJZaAotLS0tLUVORCBFRDI1NTE5IFBSSVZBVEUgS0VZLS0tLS0K\n    certSANs: []\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.24.2\n    network:\n      hostname:\n      interfaces:\n        - interface: eth0\n          addresses:\n            - 172.20.0.2/24\n          dhcp: true\n        - deviceSelector:\n            driver: macvtap\n          dhcp: false\n    install:\n        disk: /dev/sda\n        image: ghcr.io/siderolabs/installer:v1.1.0-alpha.2-105-g2deff6b6e\n        bootloader: true\n        wipe: false\n    features:\n        rbac: true\ncluster:\n    id: GGsG0g9PKDxVr1mV1hT929fu9lmC0MlTHfOkN63GJuQ=\n    secret: se0RJPQ6v2aN0ExMc7yE4L5fMuK/N9wuyGr57R0MskI=\n    controlPlane:\n        endpoint: https://127.0.0.1:6643/\n    clusterName: foo\n    network:\n        dnsDomain: cluster.local\n        podSubnets:\n            - 10.244.0.0/16\n        serviceSubnets:\n            - 10.96.0.0/12\n    token: 4pcl58.l0i5cv8h9k3k1az8\n    aescbcEncryptionSecret: A3U0/d6dmFeEO2/M6zQRWj9TqmhvOsM/RV8ZuxeIpXg=\n    ca:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJpVENDQVMrZ0F3SUJBZ0lRVU1UcVNRYlR4a2Iwb2gxdnEyRVdRekFLQmdncWhrak9QUVFEQWpBVk1STXcKRVFZRFZRUUtFd3ByZFdKbGNtNWxkR1Z6TUI0WERUSXlNRFl5T1RFek5EZ3hNVm9YRFRNeU1EWXlOakV6TkRneApNVm93RlRFVE1CRUdBMVVFQ2hNS2EzVmlaWEp1WlhSbGN6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VICkEwSUFCTTZvTVUvcGJuY043SUI3OC9NMTVkMHBFRDVvK3FaWEZFUmJsd1VxUzJXUmplM0d3S2RDYWpXZjM2YUcKbHR5RWFJUlNzZnNISU4vZm45SFNWL08zUTR5allUQmZNQTRHQTFVZER3RUIvd1FFQXdJQ2hEQWRCZ05WSFNVRQpGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFCkZnUVU5SjNqTHJmY2Z5TmlmNnBJampxVUlWdUQrbTR3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnVE1QVnR5TnMKRW5Mc1k1dXVOajdLcldVcFFQNTRyaVJ3WVZueGZOeStQRzRDSVFDUm5sR3k0bTExZFc5RjBJWVFmQUoweUZKRQpXRHRsT3QraEJaZzczWXR6N0E9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU1IeFZuVGFXdlFjNTNBTnlWMjhYVmltTW83U24zWnRhbTFGa2JwQjFmczNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFenFneFQrbHVkdzNzZ0h2ejh6WGwzU2tRUG1qNnBsY1VSRnVYQlNwTFpaR043Y2JBcDBKcQpOWi9mcG9hVzNJUm9oRkt4K3djZzM5K2YwZEpYODdkRGpBPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    aggregatorCA:\n        crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJZVENDQVFhZ0F3SUJBZ0lSQUlwbllnQVl3UTlWYUthNXI3K1Y1bW93Q2dZSUtvWkl6ajBFQXdJd0FEQWUKRncweU1qQTJNamt4TXpRNE1URmFGdzB6TWpBMk1qWXhNelE0TVRGYU1BQXdXVEFUQmdjcWhrak9QUUlCQmdncQpoa2pPUFFNQkJ3TkNBQVJINXpHY1M5NVZ4bjl4T1hOVXg5ai9PVytHTkkxcFREU1FRc3V0S0NtakhKRHN2VTNKCmFTa1NVWmxzSVpYbWkxZXhlTHRZeS9TN202M0JMaUZnUTFYMm8yRXdYekFPQmdOVkhROEJBZjhFQkFNQ0FvUXcKSFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01BOEdBMVVkRXdFQi93UUZNQU1CQWY4dwpIUVlEVlIwT0JCWUVGSDZ1Uk1IVUFBaXJwRUU1SkhQS3ZrT3g2RUljTUFvR0NDcUdTTTQ5QkFNQ0Ewa0FNRVlDCklRQ0FBems2YjBrK0VNTkZBbzVaTHo0bElqQmtFZnZwWDdsaGtBclM4MjZmcWdJaEFJeUI5OVNJVkFuYkFONlAKeFlSaWFqNS81R1d2OTFiT0pZQ2N0Y2tGL294YwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU5YS0M4YkkxbTBVd0NWb0NWQlZERndtL3lqaWdQUVNrdGV0MVAra0pjWU9vQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFUitjeG5FdmVWY1ovY1RselZNZlkvemx2aGpTTmFVdzBrRUxMclNncG94eVE3TDFOeVdrcApFbEdaYkNHVjVvdFhzWGk3V012MHU1dXR3UzRoWUVOVjlnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    serviceAccount:\n        key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUd6VlpnLzlmdityQW9DNmZmRmRRZzdKMzk0ZFMxc3p2cmFTRklBZVJsV0lvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVjYwUVgwN0hOVCtIbjJRNkJaQ1BPeVNqMExqS2FvMDM2TUJqMG5PMFFKNVVnZkhhaDVMUwp3QzRLajMwNU52bmZ4bnNnUnI5MWUrbjJreDMxTnJIaFF3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n    apiServer:\n        image: k8s.gcr.io/kube-apiserver:v1.24.2\n        certSANs:\n            - 127.0.0.1\n        disablePodSecurityPolicy: true\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: Metadata\n        admissionControl:\n            - name: PodSecurity\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n    controllerManager:\n        image: k8s.gcr.io/kube-controller-manager:v1.24.2\n    proxy:\n        image: k8s.gcr.io/kube-proxy:v1.24.2\n    scheduler:\n        image: k8s.gcr.io/kube-scheduler:v1.24.2\n    discovery:\n        enabled: true\n        registries:\n            kubernetes: {}\n            service: {}\n    etcd:\n        ca:\n            crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNTZ0F3SUJBZ0lSQU9jRytGVk5EYTI0SXJ1YnA5QVRTVkl3Q2dZSUtvWkl6ajBFQXdJd0R6RU4KTUFzR0ExVUVDaE1FWlhSalpEQWVGdzB5TWpBMk1qa3hNelE0TVRGYUZ3MHpNakEyTWpZeE16UTRNVEZhTUE4eApEVEFMQmdOVkJBb1RCR1YwWTJRd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRa2pRd3puYmF4ClFyOUVyOG51TUQyUEdEUHBRak1nNGc5czMzeW1GMnpCQWZhMGlta2RMK0hCRkZhaDZ4OHNNVnFsOWJIZEFyRWIKcjVjUFdEeUpRUkxmbzJFd1h6QU9CZ05WSFE4QkFmOEVCQU1DQW9Rd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSApBd0VHQ0NzR0FRVUZCd01DTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkl3VmNlNHhrNjI0ClZseVcvaHVwek40U2FZZGVNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJRnphUzkyMExjK1dlOEpjNkk4dm9LWlQKZXJ3NDlMQ0o0VGpaeUwwVzl5RzdBaUI5QWRlOWNVa1AwSitDelZIdUVVU3NmVjBENFg4N0RyM3lUbGV0NHVVSQpDdz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\n            key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUxqUCtiL1FnckZqTlh6WCswZWNQTU8xc1MvYzM4NUFObWFFU3VIbENSR0hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFSkkwTU01MjJzVUsvUksvSjdqQTlqeGd6NlVJeklPSVBiTjk4cGhkc3dRSDJ0SXBwSFMvaAp3UlJXb2VzZkxERmFwZld4M1FLeEc2K1hEMWc4aVVFUzN3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/testdata/strategic/006/right.yaml",
    "content": "cluster:\n    apiServer:\n        auditPolicy:\n            apiVersion: audit.k8s.io/v1\n            kind: Policy\n            rules:\n                - level: None\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_admissionplugin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\n// Name implements the config.AdmissionPlugin interface.\nfunc (a *AdmissionPluginConfig) Name() string {\n\treturn a.PluginName\n}\n\n// Configuration implements the config.AdmissionPlugin interface.\nfunc (a *AdmissionPluginConfig) Configuration() map[string]any {\n\treturn a.PluginConfiguration.Object\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_apiserverconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\n// APIServerDefaultAuditPolicy is the default kube-apiserver audit policy.\nvar APIServerDefaultAuditPolicy = Unstructured{\n\tObject: map[string]any{\n\t\t\"apiVersion\": \"audit.k8s.io/v1\",\n\t\t\"kind\":       \"Policy\",\n\t\t\"rules\": []any{\n\t\t\tmap[string]any{\n\t\t\t\t\"level\": \"Metadata\",\n\t\t\t},\n\t\t},\n\t},\n}\n\n// APIServerDefaultAuthorizationConfigAuthorizers is the default kube-apiserver authorization authorizers.\nvar APIServerDefaultAuthorizationConfigAuthorizers = []k8s.AuthorizationAuthorizersSpec{\n\t{\n\t\tType: \"Node\",\n\t\tName: \"node\",\n\t},\n\t{\n\t\tType: \"RBAC\",\n\t\tName: \"rbac\",\n\t},\n}\n\n// Image implements the config.APIServer interface.\nfunc (a *APIServerConfig) Image() string {\n\timage := a.ContainerImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:v%s\", constants.KubernetesAPIServerImage, constants.DefaultKubernetesVersion)\n\t}\n\n\treturn image\n}\n\n// ExtraArgs implements the config.APIServer interface.\nfunc (a *APIServerConfig) ExtraArgs() map[string][]string {\n\treturn a.ExtraArgsConfig.ToMap()\n}\n\n// ExtraVolumes implements the config.APIServer interface.\nfunc (a *APIServerConfig) ExtraVolumes() []config.VolumeMount {\n\treturn xslices.Map(a.ExtraVolumesConfig, func(v VolumeMountConfig) config.VolumeMount { return v })\n}\n\n// Env implements the config.APIServer interface.\nfunc (a *APIServerConfig) Env() Env {\n\treturn a.EnvConfig\n}\n\n// AdmissionControl implements the config.APIServer interface.\nfunc (a *APIServerConfig) AdmissionControl() []config.AdmissionPlugin {\n\treturn xslices.Map(a.AdmissionControlConfig, func(c *AdmissionPluginConfig) config.AdmissionPlugin { return c })\n}\n\n// AuditPolicy implements the config.APIServer interface.\nfunc (a *APIServerConfig) AuditPolicy() map[string]any {\n\tif len(a.AuditPolicyConfig.Object) == 0 {\n\t\treturn APIServerDefaultAuditPolicy.DeepCopy().Object\n\t}\n\n\treturn a.AuditPolicyConfig.Object\n}\n\n// Resources implements the config.Resources interface.\nfunc (a *APIServerConfig) Resources() config.Resources {\n\treturn a.ResourcesConfig\n}\n\n// AuthorizationConfig implements the config.APIServer interface.\nfunc (a *APIServerConfig) AuthorizationConfig() []config.AuthorizationConfigAuthorizer {\n\treturn xslices.Map(a.AuthorizationConfigConfig, func(c *AuthorizationConfigAuthorizerConfig) config.AuthorizationConfigAuthorizer { return c })\n}\n\n// Validate performs config validation.\nfunc (a *APIServerConfig) Validate() error {\n\tif a == nil {\n\t\treturn nil\n\t}\n\n\tif a.AuthorizationConfigConfig != nil {\n\t\tfor k := range a.ExtraArgs() {\n\t\t\tif k == \"authorization-mode\" {\n\t\t\t\treturn fmt.Errorf(\"authorization-mode cannot be used in conjunction with AuthorizationConfig, use eitherr AuthorizationConfig or authorization-mode\")\n\t\t\t}\n\n\t\t\tif strings.HasPrefix(k, \"authorization-webhook-\") {\n\t\t\t\treturn fmt.Errorf(\"authorization-webhook-* flags cannot be used in conjunction with AuthorizationConfig, use either AuthorizationConfig or authorization-webhook-* flags\")\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, authorizationConfig := range a.AuthorizationConfigConfig {\n\t\tif err := authorizationConfig.Validate(); err != nil {\n\t\t\treturn fmt.Errorf(\"apiserver authorization config validation failed: %w\", err)\n\t\t}\n\t}\n\n\tif err := a.ResourcesConfig.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"apiserver resource validation failed: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_authorizaationconfigauthorizer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n)\n\nvar allowedAuthorizationAuthorizerTypes = []string{\"Node\", \"RBAC\", \"Webhook\"}\n\n// Type implements the config.AuthorizationConfig interface.\nfunc (a *AuthorizationConfigAuthorizerConfig) Type() string {\n\treturn a.AuthorizerType\n}\n\n// Name implements the config.AuthorizationConfig interface.\nfunc (a *AuthorizationConfigAuthorizerConfig) Name() string {\n\treturn a.AuthorizerName\n}\n\n// Webhook implements the config.AuthorizationConfig interface.\nfunc (a *AuthorizationConfigAuthorizerConfig) Webhook() map[string]any {\n\treturn a.AuthorizerWebhook.Object\n}\n\n// Validate validates the AuthorizationConfigAuthorizerConfig.\nfunc (a *AuthorizationConfigAuthorizerConfig) Validate() error {\n\tif a.AuthorizerType == \"\" {\n\t\treturn fmt.Errorf(\"authorizer type must be set\")\n\t}\n\n\tif a.AuthorizerName == \"\" {\n\t\treturn fmt.Errorf(\"authorizer name must be set\")\n\t}\n\n\tif !slices.Contains(allowedAuthorizationAuthorizerTypes, a.AuthorizerType) {\n\t\treturn fmt.Errorf(\"authorizer type %s is not allowed, allowed types are %v\", a.AuthorizerType, allowedAuthorizationAuthorizerTypes)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_clusterconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\tsideronet \"github.com/siderolabs/net\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// ClusterConfig implements config.ClusterConfig, config.Token, and config.ClusterNetwork interfaces.\n\n// Name implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Name() string {\n\treturn c.ClusterName\n}\n\n// APIServer implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) APIServer() config.APIServer {\n\tif c.APIServerConfig == nil {\n\t\treturn &APIServerConfig{}\n\t}\n\n\treturn c.APIServerConfig\n}\n\n// ControllerManager implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ControllerManager() config.ControllerManager {\n\tif c.ControllerManagerConfig == nil {\n\t\treturn &ControllerManagerConfig{}\n\t}\n\n\treturn c.ControllerManagerConfig\n}\n\n// Proxy implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Proxy() config.Proxy {\n\tif c.ProxyConfig == nil {\n\t\treturn &ProxyConfig{}\n\t}\n\n\treturn c.ProxyConfig\n}\n\n// Scheduler implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Scheduler() config.Scheduler {\n\tif c.SchedulerConfig == nil {\n\t\treturn &SchedulerConfig{}\n\t}\n\n\treturn c.SchedulerConfig\n}\n\n// Endpoint implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Endpoint() *url.URL {\n\treturn c.ControlPlane.Endpoint.URL\n}\n\n// Token implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Token() config.Token {\n\treturn clusterToken(c.BootstrapToken)\n}\n\n// CertSANs implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) CertSANs() []string {\n\tif c.APIServerConfig == nil {\n\t\treturn nil\n\t}\n\n\treturn c.APIServerConfig.CertSANs\n}\n\n// IssuingCA implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) IssuingCA() *x509.PEMEncodedCertificateAndKey {\n\treturn c.ClusterCA\n}\n\n// AcceptedCAs implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) AcceptedCAs() []*x509.PEMEncodedCertificate {\n\treturn slices.Clone(c.ClusterAcceptedCAs)\n}\n\n// AggregatorCA implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) AggregatorCA() *x509.PEMEncodedCertificateAndKey {\n\treturn c.ClusterAggregatorCA\n}\n\n// ServiceAccount implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ServiceAccount() *x509.PEMEncodedKey {\n\treturn c.ClusterServiceAccount\n}\n\n// AESCBCEncryptionSecret implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) AESCBCEncryptionSecret() string {\n\treturn c.ClusterAESCBCEncryptionSecret\n}\n\n// SecretboxEncryptionSecret implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) SecretboxEncryptionSecret() string {\n\treturn c.ClusterSecretboxEncryptionSecret\n}\n\n// Etcd implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Etcd() config.Etcd {\n\tif c.EtcdConfig == nil {\n\t\treturn &EtcdConfig{}\n\t}\n\n\treturn c.EtcdConfig\n}\n\n// Network implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) Network() config.ClusterNetwork {\n\treturn c\n}\n\n// LocalAPIServerPort implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) LocalAPIServerPort() int {\n\tif c.ControlPlane == nil || c.ControlPlane.LocalAPIServerPort == 0 {\n\t\treturn constants.DefaultControlPlanePort\n\t}\n\n\treturn c.ControlPlane.LocalAPIServerPort\n}\n\n// CoreDNS implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) CoreDNS() config.CoreDNS {\n\tif c.CoreDNSConfig == nil {\n\t\treturn &CoreDNS{}\n\t}\n\n\treturn c.CoreDNSConfig\n}\n\n// ExternalCloudProvider implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ExternalCloudProvider() config.ExternalCloudProvider {\n\tif c.ExternalCloudProviderConfig == nil {\n\t\treturn &ExternalCloudProviderConfig{}\n\t}\n\n\treturn c.ExternalCloudProviderConfig\n}\n\n// ExtraManifestURLs implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ExtraManifestURLs() []string {\n\treturn c.ExtraManifests\n}\n\n// ExtraManifestHeaderMap implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ExtraManifestHeaderMap() map[string]string {\n\treturn c.ExtraManifestHeaders\n}\n\n// InlineManifests implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) InlineManifests() []config.InlineManifest {\n\treturn xslices.Map(c.ClusterInlineManifests, func(m ClusterInlineManifest) config.InlineManifest { return m })\n}\n\n// AdminKubeconfig implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) AdminKubeconfig() config.AdminKubeconfig {\n\tif c.AdminKubeconfigConfig == nil {\n\t\treturn &AdminKubeconfigConfig{}\n\t}\n\n\treturn c.AdminKubeconfigConfig\n}\n\n// ScheduleOnControlPlanes implements the config.ClusterConfig interface.\nfunc (c *ClusterConfig) ScheduleOnControlPlanes() bool {\n\tif c.AllowSchedulingOnControlPlanes != nil {\n\t\treturn pointer.SafeDeref(c.AllowSchedulingOnControlPlanes)\n\t}\n\n\treturn pointer.SafeDeref(c.AllowSchedulingOnMasters)\n}\n\n// ID returns the unique identifier for the cluster.\nfunc (c *ClusterConfig) ID() string {\n\treturn c.ClusterID\n}\n\n// Secret returns the cluster secret.\nfunc (c *ClusterConfig) Secret() string {\n\treturn c.ClusterSecret\n}\n\n// CNI implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) CNI() config.CNI {\n\tswitch {\n\tcase c.ClusterNetwork == nil:\n\t\tfallthrough\n\n\tcase c.ClusterNetwork.CNI == nil:\n\t\treturn &CNIConfig{\n\t\t\tCNIName: constants.FlannelCNI,\n\t\t}\n\t}\n\n\treturn c.ClusterNetwork.CNI\n}\n\n// PodCIDRs implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) PodCIDRs() []string {\n\tswitch {\n\tcase c.ClusterNetwork == nil:\n\t\tfallthrough\n\tcase len(c.ClusterNetwork.PodSubnet) == 0:\n\t\treturn []string{constants.DefaultIPv4PodNet}\n\t}\n\n\treturn c.ClusterNetwork.PodSubnet\n}\n\n// ServiceCIDRs implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) ServiceCIDRs() []string {\n\tswitch {\n\tcase c.ClusterNetwork == nil:\n\t\tfallthrough\n\tcase len(c.ClusterNetwork.ServiceSubnet) == 0:\n\t\treturn []string{constants.DefaultIPv4ServiceNet}\n\t}\n\n\treturn c.ClusterNetwork.ServiceSubnet\n}\n\n// DNSDomain implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) DNSDomain() string {\n\tif c.ClusterNetwork == nil || c.ClusterNetwork.DNSDomain == \"\" {\n\t\treturn constants.DefaultDNSDomain\n\t}\n\n\treturn c.ClusterNetwork.DNSDomain\n}\n\n// APIServerIPs implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) APIServerIPs() ([]netip.Addr, error) {\n\tserviceCIDRs, err := sideronet.SplitCIDRs(strings.Join(c.ServiceCIDRs(), \",\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to process Service CIDRs: %w\", err)\n\t}\n\n\treturn sideronet.NthIPInCIDRSet(serviceCIDRs, 1)\n}\n\n// DNSServiceIPs implements the config.ClusterNetwork interface.\nfunc (c *ClusterConfig) DNSServiceIPs() ([]netip.Addr, error) {\n\tserviceCIDRs, err := sideronet.SplitCIDRs(strings.Join(c.ServiceCIDRs(), \",\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to process Service CIDRs: %w\", err)\n\t}\n\n\treturn sideronet.NthIPInCIDRSet(serviceCIDRs, 10)\n}\n\n// Discovery implements the config.Cluster interface.\nfunc (c *ClusterConfig) Discovery() config.Discovery {\n\tif c.ClusterDiscoveryConfig == nil {\n\t\treturn &ClusterDiscoveryConfig{}\n\t}\n\n\treturn c.ClusterDiscoveryConfig\n}\n\ntype clusterToken string\n\n// ID implements the config.Token interface.\nfunc (t clusterToken) ID() string {\n\tparts := strings.Split(string(t), \".\")\n\tif len(parts) != 2 {\n\t\treturn \"\"\n\t}\n\n\treturn parts[0]\n}\n\n// Secret implements the config.Token interface.\nfunc (t clusterToken) Secret() string {\n\tparts := strings.Split(string(t), \".\")\n\tif len(parts) != 2 {\n\t\treturn \"\"\n\t}\n\n\treturn parts[1]\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_cniconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n// Name implements the config.CNI interface.\nfunc (c *CNIConfig) Name() string {\n\treturn c.CNIName\n}\n\n// URLs implements the config.CNI interface.\nfunc (c *CNIConfig) URLs() []string {\n\treturn c.CNIUrls\n}\n\n// Flannel implements the config.CNI interface.\nfunc (c *CNIConfig) Flannel() config.FlannelCNI {\n\treturn c.CNIFlannel\n}\n\n// ExtraArgs implements the config.FlannelCNI interface.\nfunc (c *FlannelCNIConfig) ExtraArgs() []string {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\treturn c.FlanneldExtraArgs\n}\n\n// KubeNetworkPoliciesEnabled implements the config.FlannelCNI interface.\nfunc (c *FlannelCNIConfig) KubeNetworkPoliciesEnabled() bool {\n\tif c == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(c.FlannelKubeNetworkPoliciesEnabled)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_controllermanagerconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Image implements the config.ControllerManager interface.\nfunc (c *ControllerManagerConfig) Image() string {\n\timage := c.ContainerImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:v%s\", constants.KubernetesControllerManagerImage, constants.DefaultKubernetesVersion)\n\t}\n\n\treturn image\n}\n\n// ExtraArgs implements the config.ControllerManager interface.\nfunc (c *ControllerManagerConfig) ExtraArgs() map[string][]string {\n\treturn c.ExtraArgsConfig.ToMap()\n}\n\n// ExtraVolumes implements the config.ControllerManager interface.\nfunc (c *ControllerManagerConfig) ExtraVolumes() []config.VolumeMount {\n\treturn xslices.Map(c.ExtraVolumesConfig, func(v VolumeMountConfig) config.VolumeMount { return v })\n}\n\n// Env implements the config.ControllerManager interface.\nfunc (c *ControllerManagerConfig) Env() Env {\n\treturn c.EnvConfig\n}\n\n// Resources implements the config.Resources interface.\nfunc (c *ControllerManagerConfig) Resources() config.Resources {\n\treturn c.ResourcesConfig\n}\n\n// Validate performs config validation.\nfunc (c *ControllerManagerConfig) Validate() error {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\tif err := c.ResourcesConfig.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"controller-manager resource validation failed: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_discoveryconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Enabled implements the config.ClusterDiscovery interface.\nfunc (c *ClusterDiscoveryConfig) Enabled() bool {\n\treturn pointer.SafeDeref(c.DiscoveryEnabled)\n}\n\n// Registries implements the config.ClusterDiscovery interface.\nfunc (c *ClusterDiscoveryConfig) Registries() config.DiscoveryRegistries {\n\treturn c.DiscoveryRegistries\n}\n\n// Kubernetes implements the config.DiscoveryRegistries interface.\nfunc (c DiscoveryRegistriesConfig) Kubernetes() config.KubernetesRegistry {\n\treturn c.RegistryKubernetes\n}\n\n// Service implements the config.DiscoveryRegistries interface.\nfunc (c DiscoveryRegistriesConfig) Service() config.ServiceRegistry {\n\treturn c.RegistryService\n}\n\n// Enabled implements the config.KubernetesRegistry interface.\nfunc (c RegistryKubernetesConfig) Enabled() bool {\n\treturn !pointer.SafeDeref(c.RegistryDisabled)\n}\n\n// Enabled implements the config.ServiceRegistry interface.\nfunc (c RegistryServiceConfig) Enabled() bool {\n\treturn !pointer.SafeDeref(c.RegistryDisabled)\n}\n\n// Endpoint implements the config.ServiceRegistry interface.\nfunc (c RegistryServiceConfig) Endpoint() string {\n\tif c.RegistryEndpoint == \"\" {\n\t\treturn constants.DefaultDiscoveryServiceEndpoint\n\t}\n\n\treturn c.RegistryEndpoint\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_etcdconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Image implements the config.Etcd interface.\nfunc (e *EtcdConfig) Image() string {\n\timage := e.ContainerImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:%s\", constants.EtcdImage, constants.DefaultEtcdVersion)\n\t}\n\n\treturn image\n}\n\n// CA implements the config.Etcd interface.\nfunc (e *EtcdConfig) CA() *x509.PEMEncodedCertificateAndKey {\n\treturn e.RootCA\n}\n\n// ExtraArgs implements the config.Etcd interface.\nfunc (e *EtcdConfig) ExtraArgs() map[string][]string {\n\treturn e.EtcdExtraArgs.ToMap()\n}\n\n// AdvertisedSubnets implements the config.Etcd interface.\nfunc (e *EtcdConfig) AdvertisedSubnets() []string {\n\tif len(e.EtcdAdvertisedSubnets) > 0 {\n\t\treturn e.EtcdAdvertisedSubnets\n\t}\n\n\tif e.EtcdSubnet != \"\" {\n\t\treturn []string{e.EtcdSubnet}\n\t}\n\n\treturn nil\n}\n\n// ListenSubnets implements the config.Etcd interface.\nfunc (e *EtcdConfig) ListenSubnets() []string {\n\tif len(e.EtcdListenSubnets) > 0 {\n\t\treturn e.EtcdListenSubnets\n\t}\n\n\t// if advertised subnets are set, use them\n\tif len(e.EtcdAdvertisedSubnets) > 0 {\n\t\treturn e.EtcdAdvertisedSubnets\n\t}\n\n\t// nothing set, rely on defaults (listen on all interfaces)\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_examples.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc mustParseURL(uri string) *url.URL {\n\tu, err := url.Parse(uri)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn u\n}\n\n// this is using custom type to avoid generating full example with all the nested structs.\nfunc configExample() any {\n\treturn struct {\n\t\tVersion string `yaml:\"version\"`\n\t\tMachine *yaml.Node\n\t\tCluster *yaml.Node\n\t}{\n\t\tVersion: \"v1alpha1\",\n\t\tMachine: &yaml.Node{Kind: yaml.ScalarNode, LineComment: \"...\"},\n\t\tCluster: &yaml.Node{Kind: yaml.ScalarNode, LineComment: \"...\"},\n\t}\n}\n\nfunc machineConfigExample() any {\n\treturn struct {\n\t\tType    string\n\t\tInstall *InstallConfig\n\t}{\n\t\tType:    machine.TypeControlPlane.String(),\n\t\tInstall: machineInstallExample(),\n\t}\n}\n\nfunc pemEncodedCertificateExample() *x509.PEMEncodedCertificateAndKey {\n\treturn &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: []byte(\"--- EXAMPLE CERTIFICATE ---\"),\n\t\tKey: []byte(\"--- EXAMPLE KEY ---\"),\n\t}\n}\n\nfunc pemEncodedKeyExample() *x509.PEMEncodedKey {\n\treturn &x509.PEMEncodedKey{\n\t\tKey: []byte(\"--- EXAMPLE KEY ---\"),\n\t}\n}\n\nfunc machineControlplaneExample() *MachineControlPlaneConfig {\n\treturn &MachineControlPlaneConfig{\n\t\tMachineControllerManager: &MachineControllerManagerConfig{\n\t\t\tMachineControllerManagerDisabled: new(false),\n\t\t},\n\t\tMachineScheduler: &MachineSchedulerConfig{\n\t\t\tMachineSchedulerDisabled: new(true),\n\t\t},\n\t}\n}\n\nfunc machineKubeletExample() *KubeletConfig {\n\treturn &KubeletConfig{\n\t\tKubeletImage: (&KubeletConfig{}).Image(),\n\t\tKubeletExtraArgs: Args{\n\t\t\t\"feature-gates\": ArgValue{strValue: \"ServerSideApply=true\"},\n\t\t},\n\t}\n}\n\nfunc kubeletImageExample() string {\n\treturn (&KubeletConfig{}).Image()\n}\n\nfunc machineInstallExample() *InstallConfig {\n\treturn &InstallConfig{\n\t\tInstallDisk:              \"/dev/sda\",\n\t\tInstallImage:             \"ghcr.io/siderolabs/installer:latest\",\n\t\tInstallWipe:              new(false),\n\t\tInstallGrubUseUKICmdline: new(true),\n\t}\n}\n\nfunc machineInstallDiskSelectorExample() *InstallDiskSelector {\n\treturn &InstallDiskSelector{\n\t\tModel: \"WDC*\",\n\t\tSize: &InstallDiskSizeMatcher{\n\t\t\tcondition: \">= 1TB\",\n\t\t},\n\t}\n}\n\nfunc machineInstallDiskSizeMatcherExamples0() *InstallDiskSizeMatcher {\n\treturn &InstallDiskSizeMatcher{\n\t\tcondition: \"4GB\",\n\t}\n}\n\nfunc machineInstallDiskSizeMatcherExamples1() *InstallDiskSizeMatcher {\n\treturn &InstallDiskSizeMatcher{\n\t\tcondition: \"> 1TB\",\n\t}\n}\n\nfunc machineInstallDiskSizeMatcherExamples2() *InstallDiskSizeMatcher {\n\treturn &InstallDiskSizeMatcher{\n\t\tcondition: \"<= 2TB\",\n\t}\n}\n\nfunc machineFilesExample() []*MachineFile {\n\treturn []*MachineFile{\n\t\t{\n\t\t\tFileContent:     \"...\",\n\t\t\tFilePermissions: 0o666,\n\t\t\tFilePath:        \"/tmp/file.txt\",\n\t\t\tFileOp:          \"append\",\n\t\t},\n\t}\n}\n\nfunc machineSysctlsExample() map[string]string {\n\treturn map[string]string{\n\t\t\"kernel.domainname\":                   \"talos.dev\",\n\t\t\"net.ipv4.ip_forward\":                 \"0\",\n\t\t\"net/ipv6/conf/eth0.100/disable_ipv6\": \"1\",\n\t}\n}\n\nfunc machineSysfsExample() map[string]string {\n\treturn map[string]string{\n\t\t\"devices.system.cpu.cpu0.cpufreq.scaling_governor\": \"performance\",\n\t}\n}\n\nfunc machineFeaturesExample() *FeaturesConfig {\n\treturn &FeaturesConfig{\n\t\tDiskQuotaSupport: new(true),\n\t}\n}\n\nfunc machineUdevExample() *UdevConfig {\n\treturn &UdevConfig{\n\t\tUdevRules: []string{\"SUBSYSTEM==\\\"drm\\\", KERNEL==\\\"renderD*\\\", GROUP=\\\"44\\\", MODE=\\\"0660\\\"\"},\n\t}\n}\n\nfunc clusterConfigExample() any {\n\treturn struct {\n\t\tControlPlane *ControlPlaneConfig   `yaml:\"controlPlane\"`\n\t\tClusterName  string                `yaml:\"clusterName\"`\n\t\tNetwork      *ClusterNetworkConfig `yaml:\"network\"`\n\t}{\n\t\tControlPlane: clusterControlPlaneExample(),\n\t\tClusterName:  \"talos.local\",\n\t\tNetwork:      clusterNetworkExample(),\n\t}\n}\n\nfunc clusterControlPlaneExample() *ControlPlaneConfig {\n\treturn &ControlPlaneConfig{\n\t\tEndpoint: &Endpoint{\n\t\t\t&url.URL{\n\t\t\t\tHost:   \"1.2.3.4\",\n\t\t\t\tScheme: \"https\",\n\t\t\t},\n\t\t},\n\t\tLocalAPIServerPort: 443,\n\t}\n}\n\nfunc clusterNetworkExample() *ClusterNetworkConfig {\n\treturn &ClusterNetworkConfig{\n\t\tCNI: &CNIConfig{\n\t\t\tCNIName: constants.FlannelCNI,\n\t\t},\n\t\tDNSDomain:     \"cluster.local\",\n\t\tPodSubnet:     []string{\"10.244.0.0/16\"},\n\t\tServiceSubnet: []string{\"10.96.0.0/12\"},\n\t}\n}\n\nfunc resourcesConfigRequestsExample() Unstructured {\n\treturn Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"cpu\":    1,\n\t\t\t\"memory\": \"1Gi\",\n\t\t},\n\t}\n}\n\nfunc resourcesConfigLimitsExample() Unstructured {\n\treturn Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"cpu\":    2,\n\t\t\t\"memory\": \"2500Mi\",\n\t\t},\n\t}\n}\n\nfunc clusterAPIServerExample() *APIServerConfig {\n\treturn &APIServerConfig{\n\t\tContainerImage: (&APIServerConfig{}).Image(),\n\t\tExtraArgsConfig: Args{\n\t\t\t\"feature-gates\":                    ArgValue{strValue: \"ServerSideApply=true\"},\n\t\t\t\"http2-max-streams-per-connection\": ArgValue{strValue: \"32\"},\n\t\t},\n\t\tCertSANs: []string{\n\t\t\t\"1.2.3.4\",\n\t\t\t\"4.5.6.7\",\n\t\t},\n\t}\n}\n\nfunc clusterAPIServerImageExample() string {\n\treturn (&APIServerConfig{}).Image()\n}\n\nfunc clusterControllerManagerExample() *ControllerManagerConfig {\n\treturn &ControllerManagerConfig{\n\t\tContainerImage: (&ControllerManagerConfig{}).Image(),\n\t\tExtraArgsConfig: Args{\n\t\t\t\"feature-gates\": ArgValue{strValue: \"ServerSideApply=true\"},\n\t\t},\n\t}\n}\n\nfunc clusterControllerManagerImageExample() string {\n\treturn (&ControllerManagerConfig{}).Image()\n}\n\nfunc clusterProxyExample() *ProxyConfig {\n\treturn &ProxyConfig{\n\t\tContainerImage: (&ProxyConfig{}).Image(),\n\t\tExtraArgsConfig: Args{\n\t\t\t\"proxy-mode\": ArgValue{strValue: \"iptables\"},\n\t\t},\n\t\tModeConfig: \"ipvs\",\n\t}\n}\n\nfunc clusterProxyImageExample() string {\n\treturn (&ProxyConfig{}).Image()\n}\n\nfunc clusterSchedulerExample() *SchedulerConfig {\n\treturn &SchedulerConfig{\n\t\tContainerImage: (&SchedulerConfig{}).Image(),\n\t\tExtraArgsConfig: Args{\n\t\t\t\"feature-gates\": ArgValue{strValue: \"AllBeta=true\"},\n\t\t},\n\t}\n}\n\nfunc clusterSchedulerImageExample() string {\n\treturn (&SchedulerConfig{}).Image()\n}\n\nfunc clusterEtcdExample() *EtcdConfig {\n\treturn &EtcdConfig{\n\t\tContainerImage: (&EtcdConfig{}).Image(),\n\t\tEtcdExtraArgs: Args{\n\t\t\t\"election-timeout\": ArgValue{strValue: \"5000\"},\n\t\t},\n\t\tRootCA: pemEncodedCertificateExample(),\n\t}\n}\n\nfunc clusterEtcdImageExample() string {\n\treturn (&EtcdConfig{}).Image()\n}\n\nfunc clusterEtcdAdvertisedSubnetsExample() []string {\n\treturn []string{\"10.0.0.0/8\"}\n}\n\nfunc clusterCoreDNSExample() *CoreDNS {\n\treturn &CoreDNS{\n\t\tCoreDNSImage: (&CoreDNS{}).Image(),\n\t}\n}\n\nfunc clusterExternalCloudProviderConfigExample() *ExternalCloudProviderConfig {\n\treturn &ExternalCloudProviderConfig{\n\t\tExternalEnabled: new(true),\n\t\tExternalManifests: []string{\n\t\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t\t},\n\t}\n}\n\nfunc clusterAdminKubeconfigExample() *AdminKubeconfigConfig {\n\treturn &AdminKubeconfigConfig{\n\t\tAdminKubeconfigCertLifetime: time.Hour,\n\t}\n}\n\nfunc machineSeccompExample() []*MachineSeccompProfile {\n\treturn []*MachineSeccompProfile{\n\t\t{\n\t\t\tMachineSeccompProfileName: \"audit.json\",\n\t\t\tMachineSeccompProfileValue: Unstructured{\n\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\"defaultAction\": \"SCMP_ACT_LOG\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc clusterEndpointExample1() *Endpoint {\n\treturn &Endpoint{\n\t\tmustParseURL(\"https://1.2.3.4:6443\"),\n\t}\n}\n\nfunc clusterEndpointExample2() *Endpoint {\n\treturn &Endpoint{\n\t\tmustParseURL(\"https://cluster1.internal:6443\"),\n\t}\n}\n\nfunc kubeletExtraMountsExample() []ExtraMount {\n\treturn []ExtraMount{\n\t\t{\n\t\t\tSource:      \"/var/lib/example\",\n\t\t\tDestination: \"/var/lib/example\",\n\t\t\tType:        \"bind\",\n\t\t\tOptions: []string{\n\t\t\t\t\"bind\",\n\t\t\t\t\"rshared\",\n\t\t\t\t\"rw\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc clusterCustomCNIExample() *CNIConfig {\n\treturn &CNIConfig{\n\t\tCNIName: constants.CustomCNI,\n\t\tCNIUrls: []string{\n\t\t\t\"https://docs.projectcalico.org/archive/v3.20/manifests/canal.yaml\",\n\t\t},\n\t}\n}\n\nfunc clusterInlineManifestsExample() ClusterInlineManifests {\n\treturn ClusterInlineManifests{\n\t\t{\n\t\t\tInlineManifestName: \"namespace-ci\",\n\t\t\tInlineManifestContents: strings.TrimSpace(`\napiVersion: v1\nkind: Namespace\nmetadata:\n\tname: ci\n`),\n\t\t},\n\t}\n}\n\nfunc clusterDiscoveryExample() ClusterDiscoveryConfig {\n\treturn ClusterDiscoveryConfig{\n\t\tDiscoveryEnabled: new(true),\n\t\tDiscoveryRegistries: DiscoveryRegistriesConfig{\n\t\t\tRegistryService: RegistryServiceConfig{\n\t\t\t\tRegistryEndpoint: constants.DefaultDiscoveryServiceEndpoint,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc kubeletNodeIPExample() *KubeletNodeIPConfig {\n\treturn &KubeletNodeIPConfig{\n\t\tKubeletNodeIPValidSubnets: []string{\n\t\t\t\"10.0.0.0/8\",\n\t\t\t\"!10.0.0.3/32\",\n\t\t\t\"fdc7::/16\",\n\t\t},\n\t}\n}\n\nfunc kubeletExtraConfigExample() Unstructured {\n\treturn Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"serverTLSBootstrap\": true,\n\t\t},\n\t}\n}\n\nfunc kubeletCredentialProviderConfigExample() Unstructured {\n\treturn Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"apiVersion\": \"kubelet.config.k8s.io/v1\",\n\t\t\t\"kind\":       \"CredentialProviderConfig\",\n\t\t\t\"providers\": []any{\n\t\t\t\tmap[string]any{\n\t\t\t\t\t\"name\":       \"ecr-credential-provider\",\n\t\t\t\t\t\"apiVersion\": \"credentialprovider.kubelet.k8s.io/v1\",\n\t\t\t\t\t\"matchImages\": []any{\n\t\t\t\t\t\t\"*.dkr.ecr.*.amazonaws.com\",\n\t\t\t\t\t\t\"*.dkr.ecr.*.amazonaws.com.cn\",\n\t\t\t\t\t\t\"*.dkr.ecr-fips.*.amazonaws.com\",\n\t\t\t\t\t\t\"*.dkr.ecr.us-iso-east-1.c2s.ic.gov\",\n\t\t\t\t\t\t\"*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov\",\n\t\t\t\t\t},\n\t\t\t\t\t\"defaultCacheDuration\": \"12h\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc loggingEndpointExample1() *Endpoint {\n\treturn &Endpoint{\n\t\tmustParseURL(\"udp://127.0.0.1:12345\"),\n\t}\n}\n\nfunc loggingEndpointExample2() *Endpoint {\n\treturn &Endpoint{\n\t\tmustParseURL(\"tcp://1.2.3.4:12345\"),\n\t}\n}\n\nfunc machineLoggingExample() LoggingConfig {\n\treturn LoggingConfig{\n\t\tLoggingDestinations: []LoggingDestination{\n\t\t\t{\n\t\t\t\tLoggingEndpoint: loggingEndpointExample2(),\n\t\t\t\tLoggingFormat:   constants.LoggingFormatJSONLines,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc machineKernelExample() *KernelConfig {\n\treturn &KernelConfig{\n\t\tKernelModules: []*KernelModuleConfig{\n\t\t\t{\n\t\t\t\tModuleName: \"btrfs\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc machinePodsExample() []Unstructured {\n\treturn []Unstructured{\n\t\t{\n\t\t\tObject: map[string]any{\n\t\t\t\t\"apiVersion\": \"v1\",\n\t\t\t\t\"kind\":       \"pod\",\n\t\t\t\t\"metadata\": map[string]any{\n\t\t\t\t\t\"name\": \"nginx\",\n\t\t\t\t},\n\t\t\t\t\"spec\": map[string]any{\n\t\t\t\t\t\"containers\": []any{\n\t\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\t\"name\":  \"nginx\",\n\t\t\t\t\t\t\t\"image\": \"nginx\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc admissionControlConfigExample() []*AdmissionPluginConfig {\n\treturn []*AdmissionPluginConfig{\n\t\t{\n\t\t\tPluginName: \"PodSecurity\",\n\t\t\tPluginConfiguration: Unstructured{\n\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\"apiVersion\": \"pod-security.admission.config.k8s.io/v1alpha1\",\n\t\t\t\t\t\"kind\":       \"PodSecurityConfiguration\",\n\t\t\t\t\t\"defaults\": map[string]any{\n\t\t\t\t\t\t\"enforce\":         \"baseline\",\n\t\t\t\t\t\t\"enforce-version\": \"latest\",\n\t\t\t\t\t\t\"audit\":           \"restricted\",\n\t\t\t\t\t\t\"audit-version\":   \"latest\",\n\t\t\t\t\t\t\"warn\":            \"restricted\",\n\t\t\t\t\t\t\"warn-version\":    \"latest\",\n\t\t\t\t\t},\n\t\t\t\t\t\"exemptions\": map[string]any{\n\t\t\t\t\t\t\"usernames\":      []any{},\n\t\t\t\t\t\t\"runtimeClasses\": []any{},\n\t\t\t\t\t\t\"namespaces\":     []any{\"kube-system\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc authorizationConfigExample() []*AuthorizationConfigAuthorizerConfig {\n\treturn []*AuthorizationConfigAuthorizerConfig{\n\t\t{\n\t\t\tAuthorizerType: \"Webhook\",\n\t\t\tAuthorizerName: \"webhook\",\n\t\t\tAuthorizerWebhook: Unstructured{\n\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\"failurePolicy\": \"Deny\",\n\t\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t\t},\n\t\t\t\t\t\"matchConditions\": []map[string]any{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"expression\": \"has(request.resourceAttributes)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"expression\": \"!(\\\\'system:serviceaccounts:kube-system\\\\' in request.groups)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tAuthorizerType: \"Webhook\",\n\t\t\tAuthorizerName: \"in-cluster-authorizer\",\n\t\t\tAuthorizerWebhook: Unstructured{\n\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\"timeout\":                    \"3s\",\n\t\t\t\t\t\"subjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\"matchConditionSubjectAccessReviewVersion\": \"v1\",\n\t\t\t\t\t\"failurePolicy\": \"NoOpinion\",\n\t\t\t\t\t\"connectionInfo\": map[string]any{\n\t\t\t\t\t\t\"type\": \"InClusterConfig\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc kubernetesTalosAPIAccessConfigExample() *KubernetesTalosAPIAccessConfig {\n\treturn &KubernetesTalosAPIAccessConfig{\n\t\tAccessEnabled: new(true),\n\t\tAccessAllowedRoles: []string{\n\t\t\t\"os:reader\",\n\t\t},\n\t\tAccessAllowedKubernetesNamespaces: []string{\n\t\t\t\"kube-system\",\n\t\t},\n\t}\n}\n\nfunc machineBaseRuntimeSpecOverridesExample() Unstructured {\n\treturn Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"process\": map[string]any{\n\t\t\t\t\"rlimits\": []map[string]any{\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"RLIMIT_NOFILE\",\n\t\t\t\t\t\t\"hard\": 1024,\n\t\t\t\t\t\t\"soft\": 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_externalcloudproviderconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport \"github.com/siderolabs/go-pointer\"\n\n// Enabled implements the config.ExternalCloudProvider interface.\nfunc (ecp *ExternalCloudProviderConfig) Enabled() bool {\n\treturn pointer.SafeDeref(ecp.ExternalEnabled)\n}\n\n// ManifestURLs implements the config.ExternalCloudProvider interface.\nfunc (ecp *ExternalCloudProviderConfig) ManifestURLs() []string {\n\treturn ecp.ExternalManifests\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_features.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// KubernetesTalosAPIAccess implements config.Features interface.\nfunc (f *FeaturesConfig) KubernetesTalosAPIAccess() config.KubernetesTalosAPIAccess {\n\treturn f.KubernetesTalosAPIAccessConfig\n}\n\n// DiskQuotaSupportEnabled implements config.Features interface.\nfunc (f *FeaturesConfig) DiskQuotaSupportEnabled() bool {\n\treturn pointer.SafeDeref(f.DiskQuotaSupport)\n}\n\n// HostDNS implements config.Features interface.\nfunc (f *FeaturesConfig) HostDNS() config.HostDNS {\n\tif f.HostDNSSupport == nil {\n\t\treturn &HostDNSConfig{}\n\t}\n\n\treturn f.HostDNSSupport\n}\n\n// KubePrism implements config.Features interface.\nfunc (f *FeaturesConfig) KubePrism() config.KubePrism {\n\tif f.KubePrismSupport == nil {\n\t\treturn &KubePrism{}\n\t}\n\n\treturn f.KubePrismSupport\n}\n\n// ImageCache implements config.Features interface.\nfunc (f *FeaturesConfig) ImageCache() config.ImageCache {\n\tif f.ImageCacheSupport == nil {\n\t\treturn &ImageCacheConfig{}\n\t}\n\n\treturn f.ImageCacheSupport\n}\n\n// NodeAddressSortAlgorithm implements config.Features interface.\nfunc (f *FeaturesConfig) NodeAddressSortAlgorithm() nethelpers.AddressSortAlgorithm {\n\tif f.FeatureNodeAddressSortAlgorithm == \"\" {\n\t\treturn nethelpers.AddressSortAlgorithmV1\n\t}\n\n\tres, err := nethelpers.AddressSortAlgorithmString(f.FeatureNodeAddressSortAlgorithm)\n\tif err != nil {\n\t\treturn nethelpers.AddressSortAlgorithmV1\n\t}\n\n\treturn res\n}\n\nconst defaultKubePrismPort = 7445\n\n// Enabled implements [config.KubePrism].\nfunc (a *KubePrism) Enabled() bool {\n\treturn pointer.SafeDeref(a.ServerEnabled)\n}\n\n// Port implements [config.KubePrism].\nfunc (a *KubePrism) Port() int {\n\tif a.ServerPort == 0 {\n\t\treturn defaultKubePrismPort\n\t}\n\n\treturn a.ServerPort\n}\n\n// Enabled implements config.HostDNS.\nfunc (h *HostDNSConfig) Enabled() bool {\n\treturn pointer.SafeDeref(h.HostDNSEnabled)\n}\n\n// ForwardKubeDNSToHost implements config.HostDNS.\nfunc (h *HostDNSConfig) ForwardKubeDNSToHost() bool {\n\treturn pointer.SafeDeref(h.HostDNSForwardKubeDNSToHost)\n}\n\n// ResolveMemberNames implements config.HostDNS.\nfunc (h *HostDNSConfig) ResolveMemberNames() bool {\n\treturn pointer.SafeDeref(h.HostDNSResolveMemberNames)\n}\n\n// LocalEnabled implements config.ImageCache.\nfunc (i *ImageCacheConfig) LocalEnabled() bool {\n\treturn pointer.SafeDeref(i.CacheLocalEnabled)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_inlinemanifest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\n// Name implements the config.InlineManifest interface.\nfunc (m ClusterInlineManifest) Name() string {\n\treturn m.InlineManifestName\n}\n\n// Contents implements the config.InlineManifest interface.\nfunc (m ClusterInlineManifest) Contents() string {\n\treturn m.InlineManifestContents\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_kernel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n// Modules implements config.Kernel interface.\nfunc (kc *KernelConfig) Modules() []config.KernelModule {\n\treturn xslices.Map(kc.KernelModules, func(kmc *KernelModuleConfig) config.KernelModule { return kmc })\n}\n\n// Name implements config.KernelModule interface.\nfunc (kmc *KernelModuleConfig) Name() string {\n\treturn kmc.ModuleName\n}\n\n// Parameters implements config.KernelModule interface.\nfunc (kmc *KernelModuleConfig) Parameters() []string {\n\treturn kmc.ModuleParameters\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_kubernetestalosapiaccess.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport \"github.com/siderolabs/go-pointer\"\n\n// Enabled implements config.KubernetesTalosAPIAccess.\nfunc (c *KubernetesTalosAPIAccessConfig) Enabled() bool {\n\tif c == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(c.AccessEnabled)\n}\n\n// AllowedRoles implements config.KubernetesTalosAPIAccess.\nfunc (c *KubernetesTalosAPIAccessConfig) AllowedRoles() []string {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\treturn c.AccessAllowedRoles\n}\n\n// AllowedKubernetesNamespaces implements config.KubernetesTalosAPIAccess.\nfunc (c *KubernetesTalosAPIAccessConfig) AllowedKubernetesNamespaces() []string {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\treturn c.AccessAllowedKubernetesNamespaces\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_logging.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Validate checks logging configuration for errors.\nfunc (lc *LoggingConfig) Validate() error {\n\tvar errs *multierror.Error\n\n\tfor _, dest := range lc.LoggingDestinations {\n\t\tvar endpoint *url.URL\n\t\tif dest.LoggingEndpoint != nil && dest.LoggingEndpoint.URL != nil {\n\t\t\tendpoint = dest.LoggingEndpoint.URL\n\t\t}\n\n\t\tif endpoint == nil {\n\t\t\terrs = multierror.Append(errs, errors.New(\"empty logging endpoint\"))\n\t\t} else {\n\t\t\tif endpoint.Host == \"\" {\n\t\t\t\terrs = multierror.Append(errs, errors.New(\"empty logging endpoint's host\"))\n\t\t\t}\n\n\t\t\tif endpoint.Scheme != \"tcp\" && endpoint.Scheme != \"udp\" {\n\t\t\t\terrs = multierror.Append(errs, fmt.Errorf(\"unexpected logging endpoint scheme %q\", endpoint.Scheme))\n\t\t\t}\n\t\t}\n\n\t\tswitch f := dest.LoggingFormat; f {\n\t\tcase constants.LoggingFormatJSONLines:\n\t\t\t// nothing\n\t\tdefault:\n\t\t\terrs = multierror.Append(errs, fmt.Errorf(\"unknown logging format %q\", f))\n\t\t}\n\t}\n\n\treturn errs.ErrorOrNil()\n}\n\n// Destinations implements config.Logging interface.\nfunc (lc *LoggingConfig) Destinations() []config.LoggingDestination {\n\treturn xslices.Map(lc.LoggingDestinations, func(ld LoggingDestination) config.LoggingDestination { return ld })\n}\n\n// Endpoint implements config.LoggingDestination interface.\nfunc (ld LoggingDestination) Endpoint() *url.URL {\n\treturn ld.LoggingEndpoint.URL\n}\n\n// ExtraTags implements config.LoggingDestination interface.\nfunc (ld LoggingDestination) ExtraTags() map[string]string {\n\treturn ld.LoggingExtraTags\n}\n\n// Format implements config.LoggingDestination interface.\nfunc (ld LoggingDestination) Format() string {\n\treturn ld.LoggingFormat\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_marshal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"encoding/base64\"\n)\n\n// Base64Bytes implements YAML marshaling/unmarshaling via base64 encoding.\ntype Base64Bytes []byte\n\n// UnmarshalYAML implements the yaml.Unmarshaler interface.\nfunc (b *Base64Bytes) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar data string\n\n\tif err := unmarshal(&data); err != nil {\n\t\treturn err\n\t}\n\n\tdecoded, err := base64.StdEncoding.DecodeString(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*b = decoded\n\n\treturn nil\n}\n\n// MarshalYAML implements the yaml.Marshaler interface.\nfunc (b Base64Bytes) MarshalYAML() (any, error) {\n\treturn base64.StdEncoding.EncodeToString(b), nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_marshal_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\tyaml \"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestBase64Bytes(t *testing.T) {\n\t// docgen: nodoc\n\ttype test struct {\n\t\tCA v1alpha1.Base64Bytes `yaml:\"ca,omitempty\"`\n\t}\n\n\tinput := test{\n\t\tCA: []byte{0xde, 0xad, 0xbe, 0xef},\n\t}\n\n\tout, err := yaml.Marshal(&input)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"ca: 3q2+7w==\\n\", string(out))\n\n\tvar decoded test\n\n\trequire.NoError(t, yaml.Unmarshal(out, &decoded))\n\n\tassert.Equal(t, input.CA, decoded.CA)\n}\n\nfunc TestDiskSizeMatcherUnmarshal(t *testing.T) {\n\tobj := struct {\n\t\tM *v1alpha1.InstallDiskSizeMatcher `yaml:\"m\"`\n\t}{\n\t\tM: &v1alpha1.InstallDiskSizeMatcher{},\n\t}\n\n\tfor _, test := range []struct {\n\t\tcondition string\n\t\tsize      string\n\t\tmatch     bool\n\t\terr       bool\n\t}{\n\t\t{\n\t\t\tcondition: \"<= 256GB\",\n\t\t\tsize:      \"200GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \">= 256GB\",\n\t\t\tsize:      \"200GB\",\n\t\t\tmatch:     false,\n\t\t},\n\t\t{\n\t\t\tcondition: \"<256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     false,\n\t\t},\n\t\t{\n\t\t\tcondition: \">256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     false,\n\t\t},\n\t\t{\n\t\t\tcondition: \">256GB\",\n\t\t\tsize:      \"257GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"==256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"==256GB\",\n\t\t\tsize:      \"257GB\",\n\t\t\tmatch:     false,\n\t\t},\n\t\t{\n\t\t\tcondition: \"==   256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"   256GB\",\n\t\t\tsize:      \"256GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"9a256GB\",\n\t\t\terr:       true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"--256GB\",\n\t\t\terr:       true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"<<256GB\",\n\t\t\terr:       true,\n\t\t},\n\t\t{\n\t\t\tcondition: \">1\",\n\t\t\tsize:      \"1GB\",\n\t\t\tmatch:     true,\n\t\t},\n\t\t{\n\t\t\tcondition: \"< 1\",\n\t\t\tsize:      \"1GB\",\n\t\t\tmatch:     false,\n\t\t},\n\t} {\n\t\terr := yaml.Unmarshal(fmt.Appendf(nil, \"m: '%s'\\n\", test.condition), &obj)\n\t\tif test.err {\n\t\t\trequire.Error(t, err)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_network_bridge.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// This file contains methods which bridge v1alpha1 (legacy) config types to new-style config interfaces for networking.\n\n// NetworkStaticHostConfig implements config.NetworkStaticHostConfig interface.\nfunc (c *Config) NetworkStaticHostConfig() []config.NetworkStaticHostConfig {\n\tif c == nil || c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil {\n\t\treturn nil\n\t}\n\n\treturn c.MachineConfig.MachineNetwork.ExtraHosts()\n}\n\n// Hostname implements config.NetworkHostnameConfig interface.\nfunc (c *Config) Hostname() string {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil {\n\t\treturn \"\"\n\t}\n\n\treturn c.MachineConfig.MachineNetwork.NetworkHostname\n}\n\n// AutoHostname implements config.NetworkHostnameConfig interface.\nfunc (c *Config) AutoHostname() nethelpers.AutoHostnameKind {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineFeatures == nil {\n\t\t// legacy mode\n\t\treturn nethelpers.AutoHostnameKindAddr\n\t}\n\n\tif pointer.SafeDeref(c.MachineConfig.MachineFeatures.StableHostname) {\n\t\treturn nethelpers.AutoHostnameKindStable\n\t}\n\n\treturn nethelpers.AutoHostnameKindAddr\n}\n\n// Resolvers implements config.NetworkResolverConfig interface.\nfunc (c *Config) Resolvers() []netip.Addr {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil {\n\t\treturn nil\n\t}\n\n\tvar result []netip.Addr\n\n\tfor _, r := range c.MachineConfig.MachineNetwork.NameServers {\n\t\tif addr, err := netip.ParseAddr(r); err == nil {\n\t\t\tresult = append(result, addr)\n\t\t}\n\t}\n\n\treturn result\n}\n\n// SearchDomains implements config.NetworkResolverConfig interface.\nfunc (c *Config) SearchDomains() []string {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil {\n\t\treturn nil\n\t}\n\n\treturn c.MachineConfig.MachineNetwork.Searches\n}\n\n// DisableSearchDomain implements config.NetworkResolverConfig interface.\nfunc (c *Config) DisableSearchDomain() bool {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(c.MachineConfig.MachineNetwork.NetworkDisableSearchDomain)\n}\n\n// NetworkTimeSyncConfig implements config.NetworkTimeSyncConfig interface.\nfunc (c *Config) NetworkTimeSyncConfig() config.NetworkTimeSyncConfig {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineTime == nil {\n\t\treturn nil\n\t}\n\n\treturn c.MachineConfig.MachineTime\n}\n\n// NetworkKubeSpanConfig implements the config.NetworkKubeSpanConfig interface.\nfunc (c *Config) NetworkKubeSpanConfig() config.NetworkKubeSpanConfig {\n\tif c.MachineConfig == nil || c.MachineConfig.MachineNetwork == nil || c.MachineConfig.MachineNetwork.NetworkKubeSpan == nil {\n\t\treturn nil\n\t}\n\n\treturn c.MachineConfig.MachineNetwork.NetworkKubeSpan\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_network_bridge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// These tests ensure that v1alpha1 types properly implement new-style config interfaces.\n\nfunc TestStaticHostsBridging(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(*testing.T) config.Config\n\t}{\n\t\t{\n\t\t\tname: \"v1alpha1 only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\t\tExtraHostEntries: []*v1alpha1.ExtraHost{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tHostIP: \"10.5.0.2\",\n\t\t\t\t\t\t\t\t\tHostAliases: []string{\n\t\t\t\t\t\t\t\t\t\t\"example.com\",\n\t\t\t\t\t\t\t\t\t\t\"example\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tHostIP: \"10.5.0.3\",\n\t\t\t\t\t\t\t\t\tHostAliases: []string{\n\t\t\t\t\t\t\t\t\t\t\"my-machine\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tHostIP: \"2001:db8::1\",\n\t\t\t\t\t\t\t\t\tHostAliases: []string{\n\t\t\t\t\t\t\t\t\t\t\"ipv6-host\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"new style only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\thost1 := network.NewStaticHostConfigV1Alpha1(\"10.5.0.2\")\n\t\t\t\thost1.Hostnames = []string{\"example.com\", \"example\"}\n\n\t\t\t\thost2 := network.NewStaticHostConfigV1Alpha1(\"10.5.0.3\")\n\t\t\t\thost2.Hostnames = []string{\"my-machine\"}\n\n\t\t\t\thost3 := network.NewStaticHostConfigV1Alpha1(\"2001:db8::1\")\n\t\t\t\thost3.Hostnames = []string{\"ipv6-host\"}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\thost1,\n\t\t\t\t\thost2,\n\t\t\t\t\thost3,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\thost2 := network.NewStaticHostConfigV1Alpha1(\"10.5.0.3\")\n\t\t\t\thost2.Hostnames = []string{\"my-machine\"}\n\n\t\t\t\thost3 := network.NewStaticHostConfigV1Alpha1(\"2001:db8::1\")\n\t\t\t\thost3.Hostnames = []string{\"ipv6-host\"}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\thost2,\n\t\t\t\t\thost3,\n\t\t\t\t\t&v1alpha1.Config{\n\t\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\t\t\tExtraHostEntries: []*v1alpha1.ExtraHost{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tHostIP: \"10.5.0.2\",\n\t\t\t\t\t\t\t\t\t\tHostAliases: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"example.com\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\tstaticHosts := cfg.NetworkStaticHostConfig()\n\n\t\t\trequire.Len(t, staticHosts, 3)\n\n\t\t\tassert.Equal(t, \"10.5.0.2\", staticHosts[0].IP())\n\t\t\tassert.Equal(t, []string{\"example.com\", \"example\"}, staticHosts[0].Aliases())\n\n\t\t\tassert.Equal(t, \"10.5.0.3\", staticHosts[1].IP())\n\t\t\tassert.Equal(t, []string{\"my-machine\"}, staticHosts[1].Aliases())\n\n\t\t\tassert.Equal(t, \"2001:db8::1\", staticHosts[2].IP())\n\t\t\tassert.Equal(t, []string{\"ipv6-host\"}, staticHosts[2].Aliases())\n\t\t})\n\t}\n}\n\nfunc TestHostnameBridging(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(*testing.T) config.Config\n\n\t\texpectedHostname     string\n\t\texpectedAutoHostname nethelpers.AutoHostnameKind\n\t}{\n\t\t{\n\t\t\tname: \"v1alpha1 only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\t\tNetworkHostname: \"my-machine\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\t\tStableHostname: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedHostname:     \"my-machine\",\n\t\t\texpectedAutoHostname: nethelpers.AutoHostnameKindStable,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 empty\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedHostname:     \"\",\n\t\t\texpectedAutoHostname: nethelpers.AutoHostnameKindAddr,\n\t\t},\n\t\t{\n\t\t\tname: \"new style only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\thc := network.NewHostnameConfigV1Alpha1()\n\t\t\t\thc.ConfigHostname = \"my-machine\"\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\thc,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedHostname:     \"my-machine\",\n\t\t\texpectedAutoHostname: nethelpers.AutoHostnameKindOff,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\thc := network.NewHostnameConfigV1Alpha1()\n\t\t\t\thc.ConfigAuto = new(nethelpers.AutoHostnameKindStable)\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\thc,\n\t\t\t\t\t&v1alpha1.Config{\n\t\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedHostname:     \"\",\n\t\t\texpectedAutoHostname: nethelpers.AutoHostnameKindStable,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\thostnameConfig := cfg.NetworkHostnameConfig()\n\n\t\t\trequire.NotNil(t, hostnameConfig)\n\n\t\t\tassert.Equal(t, test.expectedHostname, hostnameConfig.Hostname())\n\t\t\tassert.Equal(t, test.expectedAutoHostname, hostnameConfig.AutoHostname())\n\t\t})\n\t}\n}\n\nfunc TestResolverBridging(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(*testing.T) config.Config\n\n\t\texpectedNameservers   []netip.Addr\n\t\texpectedSearchDomains []string\n\t\texpectedDisableSearch bool\n\t}{\n\t\t{\n\t\t\tname: \"v1alpha1 only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\t\tNameServers:                []string{\"2.2.2.2\", \"3.3.3.3\"},\n\t\t\t\t\t\t\tSearches:                   []string{\"universe.com\", \"galaxy.org\"},\n\t\t\t\t\t\t\tNetworkDisableSearchDomain: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedNameservers:   []netip.Addr{netip.MustParseAddr(\"2.2.2.2\"), netip.MustParseAddr(\"3.3.3.3\")},\n\t\t\texpectedSearchDomains: []string{\"universe.com\", \"galaxy.org\"},\n\t\t\texpectedDisableSearch: true,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 empty\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedNameservers:   nil,\n\t\t\texpectedSearchDomains: nil,\n\t\t\texpectedDisableSearch: false,\n\t\t},\n\t\t{\n\t\t\tname: \"new style only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\trc := network.NewResolverConfigV1Alpha1()\n\t\t\t\trc.ResolverNameservers = []network.NameserverConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"2.2.2.2\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"3.3.3.3\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\trc.ResolverSearchDomains = network.SearchDomainsConfig{\n\t\t\t\t\tSearchDomains:        []string{\"universe.com\", \"galaxy.org\"},\n\t\t\t\t\tSearchDisableDefault: new(true),\n\t\t\t\t}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\trc,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedNameservers:   []netip.Addr{netip.MustParseAddr(\"2.2.2.2\"), netip.MustParseAddr(\"3.3.3.3\")},\n\t\t\texpectedSearchDomains: []string{\"universe.com\", \"galaxy.org\"},\n\t\t\texpectedDisableSearch: true,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\trc := network.NewResolverConfigV1Alpha1()\n\t\t\t\trc.ResolverNameservers = []network.NameserverConfig{\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"2.2.2.2\")},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tAddress: network.Addr{Addr: netip.MustParseAddr(\"3.3.3.3\")},\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\trc,\n\t\t\t\t\t&v1alpha1.Config{\n\t\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedNameservers:   []netip.Addr{netip.MustParseAddr(\"2.2.2.2\"), netip.MustParseAddr(\"3.3.3.3\")},\n\t\t\texpectedSearchDomains: nil,\n\t\t\texpectedDisableSearch: false,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\tresolverConfig := cfg.NetworkResolverConfig()\n\n\t\t\trequire.NotNil(t, resolverConfig)\n\n\t\t\tassert.Equal(t, test.expectedNameservers, resolverConfig.Resolvers())\n\t\t\tassert.Equal(t, test.expectedSearchDomains, resolverConfig.SearchDomains())\n\t\t\tassert.Equal(t, test.expectedDisableSearch, resolverConfig.DisableSearchDomain())\n\t\t})\n\t}\n}\n\nfunc TestTimeSyncBridging(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(*testing.T) config.Config\n\n\t\texpectedNil         bool\n\t\texpectedDisabled    bool\n\t\texpectedTimeservers []string\n\t\texpectedBootTimeout time.Duration\n\t}{\n\t\t{\n\t\t\tname: \"v1alpha1 only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineTime: &v1alpha1.TimeConfig{\n\t\t\t\t\t\t\tTimeDisabled:    new(true),\n\t\t\t\t\t\t\tTimeServers:     []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\t\t\t\t\tTimeBootTimeout: 30 * time.Second,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedDisabled:    true,\n\t\t\texpectedTimeservers: []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\texpectedBootTimeout: 30 * time.Second,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 empty\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedNil: true,\n\t\t},\n\t\t{\n\t\t\tname: \"new style only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\ttsc := network.NewTimeSyncConfigV1Alpha1()\n\t\t\t\ttsc.TimeBootTimeout = 10 * time.Second\n\t\t\t\ttsc.TimeNTP = &network.NTPConfig{\n\t\t\t\t\tServers: []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\t\t}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\ttsc,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedDisabled:    false,\n\t\t\texpectedTimeservers: []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\texpectedBootTimeout: 10 * time.Second,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\ttsc := network.NewTimeSyncConfigV1Alpha1()\n\t\t\t\ttsc.TimeBootTimeout = 10 * time.Second\n\t\t\t\ttsc.TimeNTP = &network.NTPConfig{\n\t\t\t\t\tServers: []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\t\t}\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\ttsc,\n\t\t\t\t\t&v1alpha1.Config{\n\t\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedDisabled:    false,\n\t\t\texpectedTimeservers: []string{\"time1.example.com\", \"time2.example.com\"},\n\t\t\texpectedBootTimeout: 10 * time.Second,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\ttimesyncConfig := cfg.NetworkTimeSyncConfig()\n\n\t\t\tif test.expectedNil {\n\t\t\t\trequire.Nil(t, timesyncConfig)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NotNil(t, timesyncConfig)\n\n\t\t\tassert.Equal(t, test.expectedTimeservers, timesyncConfig.Servers())\n\t\t\tassert.Equal(t, test.expectedDisabled, timesyncConfig.Disabled())\n\t\t\tassert.Equal(t, test.expectedBootTimeout, timesyncConfig.BootTimeout())\n\t\t})\n\t}\n}\n\nfunc TestKubeSpanBridging(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tcfg func(*testing.T) config.Config\n\n\t\texpectedKubeSpanExists  bool\n\t\texpectedKubeSpanEnabled bool\n\t}{\n\t\t{\n\t\t\tname: \"v1alpha1 only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedKubeSpanExists:  true,\n\t\t\texpectedKubeSpanEnabled: true,\n\t\t},\n\t\t{\n\t\t\tname: \"v1alpha1 empty\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\treturn container.NewV1Alpha1(&v1alpha1.Config{\n\t\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{},\n\t\t\t\t})\n\t\t\t},\n\n\t\t\texpectedKubeSpanExists:  false,\n\t\t\texpectedKubeSpanEnabled: false,\n\t\t},\n\t\t{\n\t\t\tname: \"new style only\",\n\n\t\t\tcfg: func(*testing.T) config.Config {\n\t\t\t\tkc := network.NewKubeSpanV1Alpha1()\n\t\t\t\tkc.ConfigEnabled = new(true)\n\n\t\t\t\tc, err := container.New(\n\t\t\t\t\tkc,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\treturn c\n\t\t\t},\n\n\t\t\texpectedKubeSpanExists:  true,\n\t\t\texpectedKubeSpanEnabled: true,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcfg := test.cfg(t)\n\n\t\t\tkubespanConfig := cfg.NetworkKubeSpanConfig()\n\n\t\t\tif !test.expectedKubeSpanExists {\n\t\t\t\trequire.Nil(t, kubespanConfig)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NotNil(t, kubespanConfig)\n\n\t\t\tassert.Equal(t, test.expectedKubeSpanEnabled, kubespanConfig.Enabled())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_network_options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// NetworkConfigOption generates NetworkConfig.\ntype NetworkConfigOption func(machine.Type, *NetworkConfig) error\n\n// WithNetworkConfig sets whole network config structure, overwrites any previous options.\nfunc WithNetworkConfig(c *NetworkConfig) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\t*cfg = *c\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkNameservers sets global nameservers list.\nfunc WithNetworkNameservers(nameservers ...string) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.NameServers = append(cfg.NameServers, nameservers...)\n\n\t\treturn nil\n\t}\n}\n\n// IfaceSelector is a helper type to select network interface.\n//\n// It might either to select interface by name or by selector.\ntype IfaceSelector struct {\n\tName     *string\n\tSelector *NetworkDeviceSelector\n}\n\n// matches checks if Device matches selector.\nfunc (selector IfaceSelector) matches(dev *Device) bool {\n\tif selector.Name != nil && *selector.Name == dev.DeviceInterface {\n\t\treturn true\n\t}\n\n\tif selector.Selector != nil && dev.DeviceSelector != nil && *selector.Selector == *dev.DeviceSelector {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// new returns new Device with selector.\nfunc (selector IfaceSelector) new() *Device {\n\tdev := &Device{}\n\n\tif selector.Name != nil {\n\t\tdev.DeviceInterface = *selector.Name\n\t}\n\n\tif selector.Selector != nil {\n\t\tdev.DeviceSelector = selector.Selector\n\t}\n\n\treturn dev\n}\n\n// IfaceByName selects interface by name.\nfunc IfaceByName(name string) IfaceSelector {\n\treturn IfaceSelector{\n\t\tName: &name,\n\t}\n}\n\n// IfaceBySelector selects interface by selector.\nfunc IfaceBySelector(selector NetworkDeviceSelector) IfaceSelector {\n\treturn IfaceSelector{\n\t\tSelector: &selector,\n\t}\n}\n\n// WithNetworkInterfaceIgnore marks interface as ignored.\nfunc WithNetworkInterfaceIgnore(iface IfaceSelector) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.getDevice(iface).DeviceIgnore = new(true)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceDHCP enables DHCP for the interface.\nfunc WithNetworkInterfaceDHCP(iface IfaceSelector, enable bool) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.getDevice(iface).DeviceDHCP = new(true)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceDHCPv4 enables DHCPv4 for the interface.\nfunc WithNetworkInterfaceDHCPv4(iface IfaceSelector, enable bool) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tdev := cfg.getDevice(iface)\n\n\t\tif dev.DeviceDHCPOptions == nil {\n\t\t\tdev.DeviceDHCPOptions = &DHCPOptions{}\n\t\t}\n\n\t\tdev.DeviceDHCPOptions.DHCPIPv4 = new(enable)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceDHCPv6 enables DHCPv6 for the interface.\nfunc WithNetworkInterfaceDHCPv6(iface IfaceSelector, enable bool) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tdev := cfg.getDevice(iface)\n\n\t\tif dev.DeviceDHCPOptions == nil {\n\t\t\tdev.DeviceDHCPOptions = &DHCPOptions{}\n\t\t}\n\n\t\tdev.DeviceDHCPOptions.DHCPIPv6 = new(enable)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceCIDR configures interface for static addressing.\nfunc WithNetworkInterfaceCIDR(iface IfaceSelector, cidr string) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.getDevice(iface).DeviceAddresses = append(cfg.getDevice(iface).DeviceAddresses, cidr)\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceMTU configures interface MTU.\nfunc WithNetworkInterfaceMTU(iface IfaceSelector, mtu int) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.getDevice(iface).DeviceMTU = mtu\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceWireguard configures interface for Wireguard.\nfunc WithNetworkInterfaceWireguard(iface IfaceSelector, wireguardConfig *DeviceWireguardConfig) NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tcfg.getDevice(iface).DeviceWireguardConfig = wireguardConfig\n\n\t\treturn nil\n\t}\n}\n\n// WithNetworkInterfaceVirtualIP configures interface for Virtual IP.\nfunc WithNetworkInterfaceVirtualIP(iface IfaceSelector, cidr string) NetworkConfigOption {\n\treturn func(machineType machine.Type, cfg *NetworkConfig) error {\n\t\tif machineType == machine.TypeWorker {\n\t\t\treturn nil\n\t\t}\n\n\t\tcfg.getDevice(iface).DeviceVIPConfig = &DeviceVIPConfig{\n\t\t\tSharedIP: cidr,\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// WithKubeSpan configures a KubeSpan interface.\n//\n// Deprecated: use generate.WithKubeSpanEnabled option instead.\nfunc WithKubeSpan() NetworkConfigOption {\n\treturn func(_ machine.Type, cfg *NetworkConfig) error {\n\t\tif cfg.NetworkKubeSpan == nil {\n\t\t\tcfg.NetworkKubeSpan = &NetworkKubeSpan{}\n\t\t}\n\n\t\tcfg.NetworkKubeSpan.KubeSpanEnabled = new(true)\n\n\t\treturn nil\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/google/cel-go/common/ast\"\n\t\"github.com/google/cel-go/common/operators\"\n\t\"github.com/google/cel-go/common/types\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\n// Verify interfaces.\nvar (\n\t_ config.Document       = (*Config)(nil)\n\t_ config.SecretDocument = (*Config)(nil)\n\t_ config.Validator      = (*Config)(nil)\n)\n\nconst (\n\t// Version is the version string for v1alpha1.\n\tVersion = \"v1alpha1\"\n)\n\n// Clone implements config.Document interface.\nfunc (c *Config) Clone() config.Document {\n\treturn c.DeepCopy()\n}\n\n// Kind returns the kind of the document.\nfunc (c *Config) Kind() string {\n\treturn Version // legacy document\n}\n\n// APIVersion returns the API version of the document.\nfunc (c *Config) APIVersion() string {\n\treturn \"\" // legacy document\n}\n\n// Debug implements the config.Provider interface.\nfunc (c *Config) Debug() bool {\n\tif c == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(c.ConfigDebug)\n}\n\n// Machine implements the config.Provider interface.\nfunc (c *Config) Machine() config.MachineConfig {\n\tif c == nil || c.MachineConfig == nil {\n\t\treturn &MachineConfig{}\n\t}\n\n\treturn c.MachineConfig\n}\n\n// SeccompProfiles implements the config.Provider interface.\nfunc (m *MachineConfig) SeccompProfiles() []config.SeccompProfile {\n\treturn xslices.Map(m.MachineSeccompProfiles, func(m *MachineSeccompProfile) config.SeccompProfile { return m })\n}\n\n// Name implements the config.Provider interface.\nfunc (m *MachineSeccompProfile) Name() string {\n\treturn m.MachineSeccompProfileName\n}\n\n// Value implements the config.Provider interface.\nfunc (m *MachineSeccompProfile) Value() map[string]any {\n\treturn m.MachineSeccompProfileValue.Object\n}\n\n// NodeLabels implements the config.Provider interface.\nfunc (m *MachineConfig) NodeLabels() config.NodeLabels {\n\treturn m.MachineNodeLabels\n}\n\n// NodeAnnotations implements the config.Provider interface.\nfunc (m *MachineConfig) NodeAnnotations() config.NodeAnnotations {\n\treturn m.MachineNodeAnnotations\n}\n\n// NodeTaints implements the config.Provider interface.\nfunc (m *MachineConfig) NodeTaints() config.NodeTaints {\n\treturn m.MachineNodeTaints\n}\n\n// BaseRuntimeSpecOverrides implements the config.Provider interface.\nfunc (m *MachineConfig) BaseRuntimeSpecOverrides() map[string]any {\n\treturn m.MachineBaseRuntimeSpecOverrides.Object\n}\n\n// Cluster implements the config.Provider interface.\nfunc (c *Config) Cluster() config.ClusterConfig {\n\tif c == nil || c.ClusterConfig == nil {\n\t\treturn &ClusterConfig{}\n\t}\n\n\treturn c.ClusterConfig\n}\n\n// Redact implements the config.SecretDocument interface.\n//\n//nolint:gocyclo\nfunc (c *Config) Redact(replacement string) {\n\tif c == nil {\n\t\treturn\n\t}\n\n\tredactBytes := func(b []byte) []byte {\n\t\tif len(b) == 0 {\n\t\t\treturn b\n\t\t}\n\n\t\treturn []byte(replacement)\n\t}\n\n\tredactStr := func(s string) string {\n\t\treturn string(redactBytes([]byte(s)))\n\t}\n\n\tif c.MachineConfig != nil {\n\t\tc.MachineConfig.MachineToken = redactStr(c.MachineConfig.MachineToken)\n\t\tif c.MachineConfig.MachineCA != nil {\n\t\t\tc.MachineConfig.MachineCA.Key = redactBytes(c.MachineConfig.MachineCA.Key)\n\t\t}\n\t}\n\n\tif c.ClusterConfig != nil {\n\t\tc.ClusterConfig.ClusterSecret = redactStr(c.ClusterConfig.ClusterSecret)\n\t\tc.ClusterConfig.BootstrapToken = redactStr(c.ClusterConfig.BootstrapToken)\n\t\tc.ClusterConfig.ClusterAESCBCEncryptionSecret = redactStr(c.ClusterConfig.ClusterAESCBCEncryptionSecret)\n\t\tc.ClusterConfig.ClusterSecretboxEncryptionSecret = redactStr(c.ClusterConfig.ClusterSecretboxEncryptionSecret)\n\n\t\tif c.ClusterConfig.ClusterServiceAccount != nil {\n\t\t\tc.ClusterConfig.ClusterServiceAccount.Key = redactBytes(c.ClusterConfig.ClusterServiceAccount.Key)\n\t\t}\n\n\t\tif c.ClusterConfig.ClusterCA != nil {\n\t\t\tc.ClusterConfig.ClusterCA.Key = redactBytes(c.ClusterConfig.ClusterCA.Key)\n\t\t}\n\n\t\tif c.ClusterConfig.ClusterAggregatorCA != nil {\n\t\t\tc.ClusterConfig.ClusterAggregatorCA.Key = redactBytes(c.ClusterConfig.ClusterAggregatorCA.Key)\n\t\t}\n\n\t\tif c.ClusterConfig.EtcdConfig != nil && c.ClusterConfig.EtcdConfig.RootCA != nil {\n\t\t\tc.ClusterConfig.EtcdConfig.RootCA.Key = redactBytes(c.ClusterConfig.EtcdConfig.RootCA.Key)\n\t\t}\n\t}\n}\n\n// Install implements the config.Provider interface.\nfunc (m *MachineConfig) Install() config.Install {\n\tif m.MachineInstall == nil {\n\t\treturn &InstallConfig{}\n\t}\n\n\treturn m.MachineInstall\n}\n\n// Security implements the config.Provider interface.\nfunc (m *MachineConfig) Security() config.Security {\n\treturn m\n}\n\n// Disks implements the config.Provider interface.\nfunc (m *MachineConfig) Disks() []config.Disk {\n\treturn xslices.Map(m.MachineDisks, func(d *MachineDisk) config.Disk { return d })\n}\n\n// Network implements the config.Provider interface.\nfunc (m *MachineConfig) Network() config.MachineNetwork {\n\tif m.MachineNetwork == nil {\n\t\treturn &NetworkConfig{}\n\t}\n\n\treturn m.MachineNetwork\n}\n\n// Controlplane implements the config.Provider interface.\nfunc (m *MachineConfig) Controlplane() config.MachineControlPlane {\n\tif m.MachineControlPlane == nil {\n\t\treturn &MachineControlPlaneConfig{}\n\t}\n\n\treturn m.MachineControlPlane\n}\n\n// Pods implements the config.Provider interface.\nfunc (m *MachineConfig) Pods() []map[string]any {\n\treturn xslices.Map(m.MachinePods, func(u Unstructured) map[string]any { return u.Object })\n}\n\n// ControllerManager implements the config.Provider interface.\nfunc (m *MachineControlPlaneConfig) ControllerManager() config.MachineControllerManager {\n\tif m.MachineControllerManager == nil {\n\t\treturn &MachineControllerManagerConfig{}\n\t}\n\n\treturn m.MachineControllerManager\n}\n\n// Scheduler implements the config.Provider interface.\nfunc (m *MachineControlPlaneConfig) Scheduler() config.MachineScheduler {\n\tif m.MachineScheduler == nil {\n\t\treturn &MachineSchedulerConfig{}\n\t}\n\n\treturn m.MachineScheduler\n}\n\n// Disabled implements the config.Provider interface.\nfunc (m *MachineControllerManagerConfig) Disabled() bool {\n\treturn pointer.SafeDeref(m.MachineControllerManagerDisabled)\n}\n\n// Disabled implements the config.Provider interface.\nfunc (m *MachineSchedulerConfig) Disabled() bool {\n\treturn pointer.SafeDeref(m.MachineSchedulerDisabled)\n}\n\n// Kubelet implements the config.Provider interface.\nfunc (m *MachineConfig) Kubelet() config.Kubelet {\n\tif m.MachineKubelet == nil {\n\t\treturn &KubeletConfig{}\n\t}\n\n\treturn m.MachineKubelet\n}\n\n// Env implements the config.Provider interface.\nfunc (m *MachineConfig) Env() config.Env {\n\treturn m.MachineEnv\n}\n\n// Files implements the config.Provider interface.\nfunc (m *MachineConfig) Files() ([]config.File, error) {\n\treturn xslices.Map(m.MachineFiles, func(f *MachineFile) config.File { return f }), nil\n}\n\n// Type implements the config.Provider interface.\nfunc (m *MachineConfig) Type() machine.Type {\n\tt, _ := machine.ParseType(m.MachineType) //nolint:errcheck\n\n\treturn t\n}\n\n// Server implements the config.Provider interface.\nfunc (m *MachineConfig) Server() string {\n\treturn \"\"\n}\n\n// Sysctls implements the config.Provider interface.\nfunc (m *MachineConfig) Sysctls() map[string]string {\n\tif m.MachineSysctls == nil {\n\t\treturn make(map[string]string)\n\t}\n\n\treturn m.MachineSysctls\n}\n\n// Sysfs implements the config.Provider interface.\nfunc (m *MachineConfig) Sysfs() map[string]string {\n\tif m.MachineSysfs == nil {\n\t\treturn make(map[string]string)\n\t}\n\n\treturn m.MachineSysfs\n}\n\n// IssuingCA implements the config.Provider interface.\nfunc (m *MachineConfig) IssuingCA() *x509.PEMEncodedCertificateAndKey {\n\treturn m.MachineCA\n}\n\n// AcceptedCAs implements the config.Provider interface.\nfunc (m *MachineConfig) AcceptedCAs() []*x509.PEMEncodedCertificate {\n\treturn slices.Clone(m.MachineAcceptedCAs)\n}\n\n// Token implements the config.Provider interface.\nfunc (m *MachineConfig) Token() string {\n\treturn m.MachineToken\n}\n\n// CertSANs implements the config.Provider interface.\nfunc (m *MachineConfig) CertSANs() []string {\n\treturn m.MachineCertSANs\n}\n\n// SystemDiskEncryption implements the config.Provider interface.\nfunc (m *MachineConfig) SystemDiskEncryption() config.SystemDiskEncryption {\n\tif m.MachineSystemDiskEncryption == nil {\n\t\treturn &SystemDiskEncryptionConfig{}\n\t}\n\n\treturn m.MachineSystemDiskEncryption\n}\n\n// Features implements the config.MachineConfig interface.\nfunc (m *MachineConfig) Features() config.Features {\n\tif m.MachineFeatures == nil {\n\t\treturn &FeaturesConfig{}\n\t}\n\n\treturn m.MachineFeatures\n}\n\n// Udev implements the config.MachineConfig interface.\nfunc (m *MachineConfig) Udev() config.UdevConfig {\n\tif m.MachineUdev == nil {\n\t\treturn &UdevConfig{}\n\t}\n\n\treturn m.MachineUdev\n}\n\n// Logging implements the config.MachineConfig interface.\nfunc (m *MachineConfig) Logging() config.Logging {\n\tif m.MachineLogging == nil {\n\t\treturn &LoggingConfig{}\n\t}\n\n\treturn m.MachineLogging\n}\n\n// Kernel implements the config.MachineConfig interface.\nfunc (m *MachineConfig) Kernel() config.Kernel {\n\tif m.MachineKernel == nil {\n\t\treturn &KernelConfig{}\n\t}\n\n\treturn m.MachineKernel\n}\n\n// Image implements the config.Provider interface.\nfunc (k *KubeletConfig) Image() string {\n\timage := k.KubeletImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:v%s\", constants.KubeletImage, constants.DefaultKubernetesVersion)\n\t}\n\n\treturn image\n}\n\n// ClusterDNS implements the config.Provider interface.\nfunc (k *KubeletConfig) ClusterDNS() []string {\n\tif k == nil || k.KubeletClusterDNS == nil {\n\t\treturn nil\n\t}\n\n\treturn k.KubeletClusterDNS\n}\n\n// ExtraArgs implements the config.Provider interface.\nfunc (k *KubeletConfig) ExtraArgs() map[string][]string {\n\tif k == nil || k.KubeletExtraArgs == nil {\n\t\treturn make(map[string][]string)\n\t}\n\n\treturn k.KubeletExtraArgs.ToMap()\n}\n\n// ExtraMounts implements the config.Provider interface.\nfunc (k *KubeletConfig) ExtraMounts() []specs.Mount {\n\t// use the intermediate type which is assignable to specs.Mount so that\n\t// we can be sure that `specs.Mount` and `Mount` have exactly same fields.\n\t//\n\t// as in Go []T1 is not assignable to []T2, even if T1 and T2 are assignable, we cannot\n\t// use direct conversion of Mount and specs.Mount\n\ttype mountConverter struct {\n\t\tDestination string\n\t\tType        string\n\t\tSource      string\n\t\tOptions     []string\n\t\tUIDMappings []specs.LinuxIDMapping\n\t\tGIDMappings []specs.LinuxIDMapping\n\t}\n\n\treturn xslices.Map(k.KubeletExtraMounts,\n\t\tfunc(m ExtraMount) specs.Mount {\n\t\t\treturn specs.Mount(func() mountConverter {\n\t\t\t\treturn mountConverter{\n\t\t\t\t\tDestination: m.Destination,\n\t\t\t\t\tType:        m.Type,\n\t\t\t\t\tSource:      m.Source,\n\t\t\t\t\tOptions:     m.Options,\n\t\t\t\t\tUIDMappings: xslices.Map(m.UIDMappings, func(m LinuxIDMapping) specs.LinuxIDMapping { return specs.LinuxIDMapping(m) }),\n\t\t\t\t\tGIDMappings: xslices.Map(m.GIDMappings, func(m LinuxIDMapping) specs.LinuxIDMapping { return specs.LinuxIDMapping(m) }),\n\t\t\t\t}\n\t\t\t}())\n\t\t})\n}\n\n// ExtraConfig implements the config.Provider interface.\nfunc (k *KubeletConfig) ExtraConfig() map[string]any {\n\treturn k.KubeletExtraConfig.Object\n}\n\n// CredentialProviderConfig implements the config.Provider interface.\nfunc (k *KubeletConfig) CredentialProviderConfig() map[string]any {\n\treturn k.KubeletCredentialProviderConfig.Object\n}\n\n// DefaultRuntimeSeccompProfileEnabled implements the config.Provider interface.\nfunc (k *KubeletConfig) DefaultRuntimeSeccompProfileEnabled() bool {\n\treturn pointer.SafeDeref(k.KubeletDefaultRuntimeSeccompProfileEnabled)\n}\n\n// RegisterWithFQDN implements the config.Provider interface.\nfunc (k *KubeletConfig) RegisterWithFQDN() bool {\n\treturn pointer.SafeDeref(k.KubeletRegisterWithFQDN)\n}\n\n// NodeIP implements the config.Provider interface.\nfunc (k *KubeletConfig) NodeIP() config.KubeletNodeIP {\n\tif k.KubeletNodeIP == nil {\n\t\treturn &KubeletNodeIPConfig{}\n\t}\n\n\treturn k.KubeletNodeIP\n}\n\n// SkipNodeRegistration implements the config.Provider interface.\nfunc (k *KubeletConfig) SkipNodeRegistration() bool {\n\treturn pointer.SafeDeref(k.KubeletSkipNodeRegistration)\n}\n\n// DisableManifestsDirectory implements the KubeletConfig interface.\nfunc (k *KubeletConfig) DisableManifestsDirectory() bool {\n\treturn pointer.SafeDeref(k.KubeletDisableManifestsDirectory)\n}\n\n// ValidSubnets implements the config.Provider interface.\nfunc (k *KubeletNodeIPConfig) ValidSubnets() []string {\n\treturn k.KubeletNodeIPValidSubnets\n}\n\n// RegistryMirrorConfigs returns a map of registry mirror configurations.\nfunc (c *Config) RegistryMirrorConfigs() map[string]config.RegistryMirrorConfig {\n\tif c == nil || c.MachineConfig == nil {\n\t\treturn nil\n\t}\n\n\tresult := make(map[string]config.RegistryMirrorConfig, len(c.MachineConfig.MachineRegistries.RegistryMirrors))\n\n\tfor k, v := range c.MachineConfig.MachineRegistries.RegistryMirrors {\n\t\tresult[k] = v\n\t}\n\n\treturn result\n}\n\n// RegistryAuthConfigs returns a map of registry authentication configurations.\nfunc (c *Config) RegistryAuthConfigs() map[string]config.RegistryAuthConfig {\n\tif c == nil || c.MachineConfig == nil {\n\t\treturn nil\n\t}\n\n\tresult := make(map[string]config.RegistryAuthConfig, len(c.MachineConfig.MachineRegistries.RegistryConfig))\n\n\tfor k, v := range c.MachineConfig.MachineRegistries.RegistryConfig {\n\t\tif v.RegistryAuth == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult[k] = v.RegistryAuth\n\t}\n\n\treturn result\n}\n\n// RegistryTLSConfigs returns a map of registry TLS configurations.\nfunc (c *Config) RegistryTLSConfigs() map[string]config.RegistryTLSConfig {\n\tif c == nil || c.MachineConfig == nil {\n\t\treturn nil\n\t}\n\n\tresult := make(map[string]config.RegistryTLSConfig, len(c.MachineConfig.MachineRegistries.RegistryConfig))\n\n\tfor k, v := range c.MachineConfig.MachineRegistries.RegistryConfig {\n\t\tif v.RegistryTLS == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult[k] = v.RegistryTLS\n\t}\n\n\treturn result\n}\n\n// ImageVerificationConfigs implements the config.Config interface.\n//\n// v1alpha1 config does not support image verification configs in the main document,\n// they are provided as separate documents.\nfunc (c *Config) ImageVerificationConfigs() map[string]config.ImageVerificationConfig {\n\treturn nil\n}\n\ntype registryEndpointWrapper struct {\n\tendpoint     string\n\toverridePath bool\n}\n\nfunc (wrapper *registryEndpointWrapper) Endpoint() string {\n\treturn wrapper.endpoint\n}\n\nfunc (wrapper *registryEndpointWrapper) OverridePath() bool {\n\treturn wrapper.overridePath\n}\n\n// Mirrors implements the Registries interface.\nfunc (r *RegistriesConfig) Mirrors() map[string]config.RegistryMirrorConfig {\n\tmirrors := make(map[string]config.RegistryMirrorConfig, len(r.RegistryMirrors))\n\n\tfor k, v := range r.RegistryMirrors {\n\t\tmirrors[k] = v\n\t}\n\n\treturn mirrors\n}\n\n// Username implements the Registries interface.\nfunc (r *RegistryAuthConfig) Username() string {\n\treturn r.RegistryUsername\n}\n\n// Password implements the Registries interface.\nfunc (r *RegistryAuthConfig) Password() string {\n\treturn r.RegistryPassword\n}\n\n// Auth implements the Registries interface.\nfunc (r *RegistryAuthConfig) Auth() string {\n\treturn r.RegistryAuth\n}\n\n// IdentityToken implements the Registries interface.\nfunc (r *RegistryAuthConfig) IdentityToken() string {\n\treturn r.RegistryIdentityToken\n}\n\n// ClientIdentity implements the Registries interface.\nfunc (r *RegistryTLSConfig) ClientIdentity() *x509.PEMEncodedCertificateAndKey {\n\treturn r.TLSClientIdentity\n}\n\n// CA implements the Registries interface.\nfunc (r *RegistryTLSConfig) CA() []byte {\n\treturn r.TLSCA\n}\n\n// InsecureSkipVerify implements the Registries interface.\nfunc (r *RegistryTLSConfig) InsecureSkipVerify() bool {\n\treturn pointer.SafeDeref(r.TLSInsecureSkipVerify)\n}\n\n// Devices implements the config.Provider interface.\nfunc (n *NetworkConfig) Devices() []config.Device {\n\treturn xslices.Map(n.NetworkInterfaces, func(d *Device) config.Device { return d })\n}\n\n// getDevice adds or returns existing Device by name.\n//\n// This method mutates configuration, but it's only used in config generation.\nfunc (n *NetworkConfig) getDevice(iface IfaceSelector) *Device {\n\tfor _, dev := range n.NetworkInterfaces {\n\t\tif iface.matches(dev) {\n\t\t\treturn dev\n\t\t}\n\t}\n\n\tdev := iface.new()\n\n\tn.NetworkInterfaces = append(n.NetworkInterfaces, dev)\n\n\treturn dev\n}\n\n// ExtraHosts implements the config.Provider interface.\nfunc (n *NetworkConfig) ExtraHosts() []config.NetworkStaticHostConfig {\n\treturn xslices.Map(n.ExtraHostEntries, func(e *ExtraHost) config.NetworkStaticHostConfig { return e })\n}\n\n// IP implements the MachineNetwork interface.\nfunc (e *ExtraHost) IP() string {\n\treturn e.HostIP\n}\n\n// Aliases implements the MachineNetwork interface.\nfunc (e *ExtraHost) Aliases() []string {\n\treturn e.HostAliases\n}\n\n// Interface implements the MachineNetwork interface.\nfunc (d *Device) Interface() string {\n\treturn d.DeviceInterface\n}\n\n// Addresses implements the MachineNetwork interface.\nfunc (d *Device) Addresses() []string {\n\tswitch {\n\tcase len(d.DeviceAddresses) > 0:\n\t\treturn slices.Clone(d.DeviceAddresses)\n\tcase d.DeviceCIDR != \"\":\n\t\treturn []string{d.DeviceCIDR}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// Routes implements the MachineNetwork interface.\nfunc (d *Device) Routes() []config.Route {\n\treturn xslices.Map(d.DeviceRoutes, func(r *Route) config.Route { return r })\n}\n\n// Bond implements the MachineNetwork interface.\nfunc (d *Device) Bond() config.Bond {\n\tif d.DeviceBond == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceBond\n}\n\n// Bridge implements the MachineNetwork interface.\nfunc (d *Device) Bridge() config.Bridge {\n\tif d.DeviceBridge == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceBridge\n}\n\n// BridgePort implements the MachineNetwork interface.\nfunc (d *Device) BridgePort() config.BridgePort {\n\tif d.DeviceBridgePort == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceBridgePort\n}\n\n// Vlans implements the MachineNetwork interface.\nfunc (d *Device) Vlans() []config.Vlan {\n\treturn xslices.Map(d.DeviceVlans, func(v *Vlan) config.Vlan { return v })\n}\n\n// MTU implements the MachineNetwork interface.\nfunc (d *Device) MTU() int {\n\treturn d.DeviceMTU\n}\n\n// DHCP implements the MachineNetwork interface.\nfunc (d *Device) DHCP() bool {\n\treturn pointer.SafeDeref(d.DeviceDHCP)\n}\n\n// Ignore implements the MachineNetwork interface.\nfunc (d *Device) Ignore() bool {\n\treturn pointer.SafeDeref(d.DeviceIgnore)\n}\n\n// Dummy implements the MachineNetwork interface.\nfunc (d *Device) Dummy() bool {\n\treturn pointer.SafeDeref(d.DeviceDummy)\n}\n\n// DHCPOptions implements the MachineNetwork interface.\nfunc (d *Device) DHCPOptions() config.DHCPOptions {\n\t// Default route metric on systemd is 1024. This sets the same.\n\tif d.DeviceDHCPOptions == nil {\n\t\treturn &DHCPOptions{\n\t\t\tDHCPRouteMetric: uint32(0),\n\t\t}\n\t}\n\n\treturn d.DeviceDHCPOptions\n}\n\n// VIPConfig implements the MachineNetwork interface.\nfunc (d *Device) VIPConfig() config.VIPConfig {\n\tif d.DeviceVIPConfig == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceVIPConfig\n}\n\n// Selector implements the config.Device interface.\nfunc (d *Device) Selector() config.NetworkDeviceSelector {\n\tif d.DeviceSelector == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceSelector\n}\n\n// IP implements the config.VIPConfig interface.\nfunc (d *DeviceVIPConfig) IP() string {\n\treturn d.SharedIP\n}\n\n// EquinixMetal implements the config.VIPConfig interface.\nfunc (d *DeviceVIPConfig) EquinixMetal() config.VIPEquinixMetal {\n\tif d.EquinixMetalConfig == nil {\n\t\treturn nil\n\t}\n\n\treturn d.EquinixMetalConfig\n}\n\n// APIToken implements the config.VIPEquinixMetal interface.\nfunc (v *VIPEquinixMetalConfig) APIToken() string {\n\treturn v.EquinixMetalAPIToken\n}\n\n// HCloud implements the config.VIPConfig interface.\nfunc (d *DeviceVIPConfig) HCloud() config.VIPHCloud {\n\tif d.HCloudConfig == nil {\n\t\treturn nil\n\t}\n\n\treturn d.HCloudConfig\n}\n\n// APIToken implements the config.VIPHCloud interface.\nfunc (v *VIPHCloudConfig) APIToken() string {\n\treturn v.HCloudAPIToken\n}\n\n// WireguardConfig implements the MachineNetwork interface.\nfunc (d *Device) WireguardConfig() config.WireguardConfig {\n\tif d.DeviceWireguardConfig == nil {\n\t\treturn nil\n\t}\n\n\treturn d.DeviceWireguardConfig\n}\n\n// RouteMetric implements the DHCPOptions interface.\nfunc (d *DHCPOptions) RouteMetric() uint32 {\n\treturn d.DHCPRouteMetric\n}\n\n// IPv4 implements the DHCPOptions interface.\nfunc (d *DHCPOptions) IPv4() bool {\n\tif d.DHCPIPv4 == nil {\n\t\treturn true\n\t}\n\n\treturn *d.DHCPIPv4\n}\n\n// IPv6 implements the DHCPOptions interface.\nfunc (d *DHCPOptions) IPv6() bool {\n\tif d.DHCPIPv6 == nil {\n\t\treturn false\n\t}\n\n\treturn *d.DHCPIPv6\n}\n\n// DUIDv6 implements the DHCPOptions interface.\nfunc (d *DHCPOptions) DUIDv6() string {\n\treturn d.DHCPDUIDv6\n}\n\n// PrivateKey implements the MachineNetwork interface.\nfunc (wc *DeviceWireguardConfig) PrivateKey() string {\n\treturn wc.WireguardPrivateKey\n}\n\n// ListenPort implements the MachineNetwork interface.\nfunc (wc *DeviceWireguardConfig) ListenPort() int {\n\treturn wc.WireguardListenPort\n}\n\n// FirewallMark implements the MachineNetwork interface.\nfunc (wc *DeviceWireguardConfig) FirewallMark() int {\n\treturn wc.WireguardFirewallMark\n}\n\n// Peers implements the MachineNetwork interface.\nfunc (wc *DeviceWireguardConfig) Peers() []config.WireguardPeer {\n\treturn xslices.Map(wc.WireguardPeers, func(p *DeviceWireguardPeer) config.WireguardPeer { return p })\n}\n\n// PublicKey implements the MachineNetwork interface.\nfunc (wd *DeviceWireguardPeer) PublicKey() string {\n\treturn wd.WireguardPublicKey\n}\n\n// Endpoint implements the MachineNetwork interface.\nfunc (wd *DeviceWireguardPeer) Endpoint() string {\n\treturn wd.WireguardEndpoint\n}\n\n// PersistentKeepaliveInterval implements the MachineNetwork interface.\nfunc (wd *DeviceWireguardPeer) PersistentKeepaliveInterval() time.Duration {\n\treturn wd.WireguardPersistentKeepaliveInterval\n}\n\n// AllowedIPs implements the MachineNetwork interface.\nfunc (wd *DeviceWireguardPeer) AllowedIPs() []string {\n\treturn wd.WireguardAllowedIPs\n}\n\n// Bus implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) Bus() string {\n\treturn s.NetworkDeviceBus\n}\n\n// HardwareAddress implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) HardwareAddress() string {\n\treturn s.NetworkDeviceHardwareAddress\n}\n\n// PermanentAddress implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) PermanentAddress() string {\n\treturn s.NetworkDevicePermanentAddress\n}\n\n// PCIID implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) PCIID() string {\n\treturn s.NetworkDevicePCIID\n}\n\n// KernelDriver implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) KernelDriver() string {\n\treturn s.NetworkDeviceKernelDriver\n}\n\n// Physical implements config.NetworkDeviceSelector interface.\nfunc (s *NetworkDeviceSelector) Physical() *bool {\n\treturn s.NetworkDevicePhysical\n}\n\n// Network implements the MachineNetwork interface.\nfunc (r *Route) Network() string {\n\treturn r.RouteNetwork\n}\n\n// Gateway implements the MachineNetwork interface.\nfunc (r *Route) Gateway() string {\n\treturn r.RouteGateway\n}\n\n// Source implements the MachineNetwork interface.\nfunc (r *Route) Source() string {\n\treturn r.RouteSource\n}\n\n// Metric implements the MachineNetwork interface.\nfunc (r *Route) Metric() uint32 {\n\treturn r.RouteMetric\n}\n\n// MTU implements the MachineNetwork interface.\nfunc (r *Route) MTU() uint32 {\n\treturn r.RouteMTU\n}\n\n// Interfaces implements the MachineNetwork interface.\nfunc (b *Bond) Interfaces() []string {\n\tif b == nil {\n\t\treturn nil\n\t}\n\n\treturn b.BondInterfaces\n}\n\n// Selectors implements the Bond interface.\nfunc (b *Bond) Selectors() []config.NetworkDeviceSelector {\n\tif b == nil || b.BondDeviceSelectors == nil {\n\t\treturn nil\n\t}\n\n\treturn xslices.Map(b.BondDeviceSelectors, func(d NetworkDeviceSelector) config.NetworkDeviceSelector { return &d })\n}\n\n// ARPIPTarget implements the MachineNetwork interface.\nfunc (b *Bond) ARPIPTarget() []string {\n\tif b == nil {\n\t\treturn nil\n\t}\n\n\treturn b.BondARPIPTarget\n}\n\n// Mode implements the MachineNetwork interface.\nfunc (b *Bond) Mode() string {\n\treturn b.BondMode\n}\n\n// HashPolicy implements the MachineNetwork interface.\nfunc (b *Bond) HashPolicy() string {\n\treturn b.BondHashPolicy\n}\n\n// LACPRate implements the MachineNetwork interface.\nfunc (b *Bond) LACPRate() string {\n\treturn b.BondLACPRate\n}\n\n// ADActorSystem implements the MachineNetwork interface.\nfunc (b *Bond) ADActorSystem() string {\n\treturn b.BondADActorSystem\n}\n\n// ARPValidate implements the MachineNetwork interface.\nfunc (b *Bond) ARPValidate() string {\n\treturn b.BondARPValidate\n}\n\n// ARPAllTargets implements the MachineNetwork interface.\nfunc (b *Bond) ARPAllTargets() string {\n\treturn b.BondARPAllTargets\n}\n\n// Primary implements the MachineNetwork interface.\nfunc (b *Bond) Primary() string {\n\treturn b.BondPrimary\n}\n\n// PrimaryReselect implements the MachineNetwork interface.\nfunc (b *Bond) PrimaryReselect() string {\n\treturn b.BondPrimaryReselect\n}\n\n// FailOverMac implements the MachineNetwork interface.\nfunc (b *Bond) FailOverMac() string {\n\treturn b.BondFailOverMac\n}\n\n// ADSelect implements the MachineNetwork interface.\nfunc (b *Bond) ADSelect() string {\n\treturn b.BondADSelect\n}\n\n// MIIMon implements the MachineNetwork interface.\nfunc (b *Bond) MIIMon() uint32 {\n\treturn b.BondMIIMon\n}\n\n// UpDelay implements the MachineNetwork interface.\nfunc (b *Bond) UpDelay() uint32 {\n\treturn b.BondUpDelay\n}\n\n// DownDelay implements the MachineNetwork interface.\nfunc (b *Bond) DownDelay() uint32 {\n\treturn b.BondDownDelay\n}\n\n// ARPInterval implements the MachineNetwork interface.\nfunc (b *Bond) ARPInterval() uint32 {\n\treturn b.BondARPInterval\n}\n\n// ResendIGMP implements the MachineNetwork interface.\nfunc (b *Bond) ResendIGMP() uint32 {\n\treturn b.BondResendIGMP\n}\n\n// MinLinks implements the MachineNetwork interface.\nfunc (b *Bond) MinLinks() uint32 {\n\treturn b.BondMinLinks\n}\n\n// LPInterval implements the MachineNetwork interface.\nfunc (b *Bond) LPInterval() uint32 {\n\treturn b.BondLPInterval\n}\n\n// PacketsPerSlave implements the MachineNetwork interface.\nfunc (b *Bond) PacketsPerSlave() uint32 {\n\treturn b.BondPacketsPerSlave\n}\n\n// NumPeerNotif implements the MachineNetwork interface.\nfunc (b *Bond) NumPeerNotif() uint8 {\n\treturn b.BondNumPeerNotif\n}\n\n// TLBDynamicLB implements the MachineNetwork interface.\nfunc (b *Bond) TLBDynamicLB() uint8 {\n\treturn b.BondTLBDynamicLB\n}\n\n// AllSlavesActive implements the MachineNetwork interface.\nfunc (b *Bond) AllSlavesActive() uint8 {\n\treturn b.BondAllSlavesActive\n}\n\n// UseCarrier implements the MachineNetwork interface.\nfunc (b *Bond) UseCarrier() bool {\n\tif b.BondUseCarrier == nil {\n\t\treturn true\n\t}\n\n\treturn *b.BondUseCarrier\n}\n\n// ADActorSysPrio implements the MachineNetwork interface.\nfunc (b *Bond) ADActorSysPrio() uint16 {\n\treturn b.BondADActorSysPrio\n}\n\n// ADUserPortKey implements the MachineNetwork interface.\nfunc (b *Bond) ADUserPortKey() uint16 {\n\treturn b.BondADUserPortKey\n}\n\n// PeerNotifyDelay implements the MachineNetwork interface.\nfunc (b *Bond) PeerNotifyDelay() uint32 {\n\treturn b.BondPeerNotifyDelay\n}\n\n// Enabled implements the config.STP interface.\nfunc (s *STP) Enabled() bool {\n\tif s == nil || s.STPEnabled == nil {\n\t\treturn true\n\t}\n\n\treturn *s.STPEnabled\n}\n\n// FilteringEnabled implements the config.BridgeVLAN interface.\nfunc (v *BridgeVLAN) FilteringEnabled() bool {\n\tif v == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(v.BridgeVLANFiltering)\n}\n\n// Interfaces implements the config.Bridge interface.\nfunc (b *Bridge) Interfaces() []string {\n\treturn b.BridgedInterfaces\n}\n\n// STP implements the config.Bridge interface.\nfunc (b *Bridge) STP() config.STP {\n\tif b.BridgeSTP == nil {\n\t\treturn (*STP)(nil)\n\t}\n\n\treturn b.BridgeSTP\n}\n\n// VLAN implements the config.Bridge interface.\nfunc (b *Bridge) VLAN() config.BridgeVLAN {\n\tif b.BridgeVLAN == nil {\n\t\treturn (*BridgeVLAN)(nil)\n\t}\n\n\treturn b.BridgeVLAN\n}\n\n// Master implements the config.BridgePort interface.\nfunc (b *BridgePort) Master() string {\n\tif b == nil {\n\t\treturn \"\"\n\t}\n\n\treturn b.BridgePortMaster\n}\n\n// Addresses implements the MachineNetwork interface.\nfunc (v *Vlan) Addresses() []string {\n\tswitch {\n\tcase len(v.VlanAddresses) > 0:\n\t\treturn slices.Clone(v.VlanAddresses)\n\tcase v.VlanCIDR != \"\":\n\t\treturn []string{v.VlanCIDR}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// MTU implements the MachineNetwork interface.\nfunc (v *Vlan) MTU() uint32 {\n\treturn v.VlanMTU\n}\n\n// VIPConfig implements the MachineNetwork interface.\nfunc (v *Vlan) VIPConfig() config.VIPConfig {\n\tif v.VlanVIP == nil {\n\t\treturn nil\n\t}\n\n\treturn v.VlanVIP\n}\n\n// Routes implements the MachineNetwork interface.\nfunc (v *Vlan) Routes() []config.Route {\n\treturn xslices.Map(v.VlanRoutes, func(r *Route) config.Route { return r })\n}\n\n// DHCP implements the MachineNetwork interface.\nfunc (v *Vlan) DHCP() bool {\n\treturn pointer.SafeDeref(v.VlanDHCP)\n}\n\n// DHCPOptions implements the MachineNetwork interface.\nfunc (v *Vlan) DHCPOptions() config.DHCPOptions {\n\t// Default route metric on systemd is 1024. This sets the same.\n\tif v.VlanDHCPOptions == nil {\n\t\treturn &DHCPOptions{\n\t\t\tDHCPRouteMetric: uint32(0),\n\t\t}\n\t}\n\n\treturn v.VlanDHCPOptions\n}\n\n// ID implements the MachineNetwork interface.\nfunc (v *Vlan) ID() uint16 {\n\treturn v.VlanID\n}\n\n// Mode implements the MachineNetwork interface.\nfunc (v *Vlan) Mode() nethelpers.VLANProtocol {\n\treturn nethelpers.VLANProtocol8021Q\n}\n\n// Enabled implements KubeSpan interface.\nfunc (k *NetworkKubeSpan) Enabled() bool {\n\treturn pointer.SafeDeref(k.KubeSpanEnabled)\n}\n\n// ForceRouting implements KubeSpan interface.\nfunc (k *NetworkKubeSpan) ForceRouting() bool {\n\treturn !pointer.SafeDeref(k.KubeSpanAllowDownPeerBypass)\n}\n\n// AdvertiseKubernetesNetworks implements KubeSpan interface.\nfunc (k *NetworkKubeSpan) AdvertiseKubernetesNetworks() bool {\n\treturn pointer.SafeDeref(k.KubeSpanAdvertiseKubernetesNetworks)\n}\n\n// HarvestExtraEndpoints implements KubeSpan interface.\nfunc (k *NetworkKubeSpan) HarvestExtraEndpoints() bool {\n\treturn pointer.SafeDeref(k.KubeSpanHarvestExtraEndpoints)\n}\n\n// MTU implements the KubeSpan interface.\nfunc (k *NetworkKubeSpan) MTU() uint32 {\n\tmtu := pointer.SafeDeref(k.KubeSpanMTU)\n\tif mtu == 0 {\n\t\tmtu = constants.KubeSpanLinkMTU\n\t}\n\n\treturn mtu\n}\n\n// Filters implements the NetworkKubeSpanConfig interface.\nfunc (k *NetworkKubeSpan) Filters() config.NetworkKubeSpanFilters {\n\tif k.KubeSpanFilters == nil {\n\t\treturn &KubeSpanFilters{}\n\t}\n\n\treturn k.KubeSpanFilters\n}\n\n// Endpoints implements the config.KubeSpanFilters interface.\nfunc (k *KubeSpanFilters) Endpoints() []string {\n\treturn k.KubeSpanFiltersEndpoints\n}\n\n// ExcludeAdvertisedNetworks implements the config.KubeSpanFilters interface.\nfunc (k *KubeSpanFilters) ExcludeAdvertisedNetworks() []netip.Prefix {\n\tif len(k.KubeSpanFiltersExcludeAdvertisedNetworks) == 0 {\n\t\treturn nil\n\t}\n\n\tresult := make([]netip.Prefix, 0, len(k.KubeSpanFiltersExcludeAdvertisedNetworks))\n\n\tfor _, cidrStr := range k.KubeSpanFiltersExcludeAdvertisedNetworks {\n\t\t// prefixes are validated, so for defensive programming, we can ignore errors here.\n\t\tprefix, err := netip.ParsePrefix(cidrStr)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, prefix)\n\t}\n\n\treturn result\n}\n\n// Disabled implements the config.Provider interface.\nfunc (t *TimeConfig) Disabled() bool {\n\treturn pointer.SafeDeref(t.TimeDisabled)\n}\n\n// Servers implements the config.Provider interface.\nfunc (t *TimeConfig) Servers() []string {\n\treturn t.TimeServers\n}\n\n// BootTimeout implements the config.Provider interface.\nfunc (t *TimeConfig) BootTimeout() time.Duration {\n\treturn t.TimeBootTimeout\n}\n\n// Image implements the config.Provider interface.\nfunc (i *InstallConfig) Image() string {\n\treturn i.InstallImage\n}\n\n// Extensions implements the config.Provider interface.\nfunc (i *InstallConfig) Extensions() []config.Extension {\n\treturn xslices.Map(i.InstallExtensions, func(e InstallExtensionConfig) config.Extension { return e })\n}\n\n// Disk implements the config.Provider interface.\nfunc (i *InstallConfig) Disk() string {\n\treturn i.InstallDisk\n}\n\n// DiskMatchExpression returns the disk matcher expression by inspecting the InstallDiskSelector.\n//\n//nolint:gocyclo\nfunc (i *InstallConfig) DiskMatchExpression() (*cel.Expression, error) {\n\tif i.InstallDiskSelector == nil {\n\t\treturn nil, nil\n\t}\n\n\tvar exprs []ast.Expr\n\n\tbuilder := cel.NewBuilder(celenv.DiskLocator())\n\tselector := i.InstallDiskSelector\n\n\tif selector.Size != nil {\n\t\top := selector.Size.MatchData.Op\n\t\tif op == \"\" {\n\t\t\top = \"==\"\n\t\t}\n\n\t\texprs = append(exprs, // disk.size op value\n\t\t\tbuilder.NewCall(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\t\"_\"+op+\"_\",\n\t\t\t\tbuilder.NewSelect(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\t\t\"size\",\n\t\t\t\t),\n\t\t\t\tbuilder.NewLiteral(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\ttypes.Uint(selector.Size.MatchData.Size),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\t}\n\n\tpatternMatcherExpr := func(pattern, field string) ast.Expr { // glob(pattern, disk.$field)\n\t\treturn builder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\t\"glob\",\n\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(pattern)),\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\tfield,\n\t\t\t),\n\t\t)\n\t}\n\n\tdirectMatchExpr := func(value, field string) ast.Expr { // disk.$field == value\n\t\treturn builder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.Equals,\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\tfield,\n\t\t\t),\n\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(value)),\n\t\t)\n\t}\n\n\tif selector.UUID != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.UUID, \"uuid\"))\n\t}\n\n\tif selector.WWID != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.WWID, \"wwid\"))\n\t}\n\n\tif selector.Model != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.Model, \"model\"))\n\t}\n\n\tif selector.Name != \"\" {\n\t\t// not supported\n\t\treturn nil, fmt.Errorf(\"selector on name is not supported\")\n\t}\n\n\tif selector.Serial != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.Serial, \"serial\"))\n\t}\n\n\tif selector.Modalias != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.Modalias, \"modalias\"))\n\t}\n\n\t// disk.transport != \"\" (otherwise it might select e.g. DM devices)\n\texprs = append(exprs,\n\t\tbuilder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.NotEquals,\n\t\t\tbuilder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\t\"transport\",\n\t\t\t),\n\t\t\tbuilder.NewLiteral(builder.NextID(), types.String(\"\")),\n\t\t),\n\t)\n\n\tif selector.Type != \"\" {\n\t\tswitch selector.Type {\n\t\tcase \"nvme\": // disk.transport == \"nvme\"\n\t\t\texprs = append(exprs, directMatchExpr(\"nvme\", \"transport\"))\n\t\tcase \"sd\": // disk.transport == \"mmc\"\n\t\t\texprs = append(exprs, directMatchExpr(\"mmc\", \"transport\"))\n\t\tcase \"hdd\": // disk.rotational\n\t\t\texprs = append(exprs, builder.NewSelect(\n\t\t\t\tbuilder.NextID(),\n\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\t\"rotational\",\n\t\t\t))\n\t\tcase \"ssd\": // !disk.rotational\n\t\t\texprs = append(exprs,\n\t\t\t\tbuilder.NewCall(\n\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\toperators.LogicalNot,\n\t\t\t\t\tbuilder.NewSelect(\n\t\t\t\t\t\tbuilder.NextID(),\n\t\t\t\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\t\t\t\"rotational\",\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unsupported disk type %q\", selector.Type)\n\t\t}\n\t}\n\n\tif selector.BusPath != \"\" {\n\t\texprs = append(exprs, patternMatcherExpr(selector.BusPath, \"bus_path\"))\n\t}\n\n\t// exclude readonly disks: !disk.readonly\n\texprs = append(exprs, builder.NewCall(\n\t\tbuilder.NextID(),\n\t\toperators.LogicalNot,\n\t\tbuilder.NewSelect(\n\t\t\tbuilder.NextID(),\n\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\"readonly\",\n\t\t),\n\t))\n\n\t// exclude CD-ROMs: !disk.cdrom\n\texprs = append(exprs, builder.NewCall(\n\t\tbuilder.NextID(),\n\t\toperators.LogicalNot,\n\t\tbuilder.NewSelect(\n\t\t\tbuilder.NextID(),\n\t\t\tbuilder.NewIdent(builder.NextID(), \"disk\"),\n\t\t\t\"cdrom\",\n\t\t),\n\t))\n\n\t// reduce all expressions to a single one with &&\n\tfor len(exprs) > 1 {\n\t\texprs = append(exprs[:len(exprs)-2], builder.NewCall(\n\t\t\tbuilder.NextID(),\n\t\t\toperators.LogicalAnd,\n\t\t\texprs[len(exprs)-2],\n\t\t\texprs[len(exprs)-1],\n\t\t))\n\t}\n\n\treturn builder.ToBooleanExpression(exprs[0])\n}\n\n// ExtraKernelArgs implements the config.Provider interface.\nfunc (i *InstallConfig) ExtraKernelArgs() []string {\n\treturn i.InstallExtraKernelArgs\n}\n\n// Zero implements the config.Provider interface.\nfunc (i *InstallConfig) Zero() bool {\n\treturn pointer.SafeDeref(i.InstallWipe)\n}\n\n// LegacyBIOSSupport implements the config.Provider interface.\nfunc (i *InstallConfig) LegacyBIOSSupport() bool {\n\treturn pointer.SafeDeref(i.InstallLegacyBIOSSupport)\n}\n\n// GrubUseUKICmdline implements the config.Provider interface.\nfunc (i *InstallConfig) GrubUseUKICmdline() bool {\n\treturn pointer.SafeDeref(i.InstallGrubUseUKICmdline)\n}\n\n// Image implements the config.Provider interface.\nfunc (i InstallExtensionConfig) Image() string {\n\treturn i.ExtensionImage\n}\n\n// Enabled implements the config.Provider interface.\nfunc (c *CoreDNS) Enabled() bool {\n\treturn c.CoreDNSDisabled == nil || !*c.CoreDNSDisabled\n}\n\n// Image implements the config.Provider interface.\nfunc (c *CoreDNS) Image() string {\n\tcoreDNSImage := fmt.Sprintf(\"%s:%s\", constants.CoreDNSImage, constants.DefaultCoreDNSVersion)\n\n\tif c.CoreDNSImage != \"\" {\n\t\tcoreDNSImage = c.CoreDNSImage\n\t}\n\n\treturn coreDNSImage\n}\n\n// CertLifetime implements the config.Provider interface.\nfunc (a *AdminKubeconfigConfig) CertLifetime() time.Duration {\n\tif a.AdminKubeconfigCertLifetime == 0 {\n\t\treturn constants.KubernetesAdminCertDefaultLifetime\n\t}\n\n\treturn a.AdminKubeconfigCertLifetime\n}\n\n// CommonName implements the config.Provider interface.\nfunc (a *AdminKubeconfigConfig) CommonName() string {\n\treturn constants.KubernetesAdminCertCommonName\n}\n\n// CertOrganization implements the config.Provider interface.\nfunc (a *AdminKubeconfigConfig) CertOrganization() string {\n\treturn constants.KubernetesAdminCertOrganization\n}\n\n// Endpoints implements the Registries interface.\nfunc (r *RegistryMirrorConfig) Endpoints() []config.RegistryEndpointConfig {\n\treturn xslices.Map(r.MirrorEndpoints, func(e string) config.RegistryEndpointConfig {\n\t\treturn &registryEndpointWrapper{\n\t\t\tendpoint:     e,\n\t\t\toverridePath: pointer.SafeDeref(r.MirrorOverridePath),\n\t\t}\n\t})\n}\n\n// SkipFallback implements the Registries interface.\nfunc (r *RegistryMirrorConfig) SkipFallback() bool {\n\treturn pointer.SafeDeref(r.MirrorSkipFallback)\n}\n\n// Content implements the config.Provider interface.\nfunc (f *MachineFile) Content() string {\n\treturn f.FileContent\n}\n\n// Permissions implements the config.Provider interface.\nfunc (f *MachineFile) Permissions() os.FileMode {\n\treturn os.FileMode(f.FilePermissions)\n}\n\n// Path implements the config.Provider interface.\nfunc (f *MachineFile) Path() string {\n\treturn f.FilePath\n}\n\n// Op implements the config.Provider interface.\nfunc (f *MachineFile) Op() string {\n\treturn f.FileOp\n}\n\n// Device implements the config.Provider interface.\nfunc (d *MachineDisk) Device() string {\n\treturn d.DeviceName\n}\n\n// Partitions implements the config.Provider interface.\nfunc (d *MachineDisk) Partitions() []config.Partition {\n\treturn xslices.Map(d.DiskPartitions, func(p *DiskPartition) config.Partition { return p })\n}\n\n// Size implements the config.Provider interface.\nfunc (p *DiskPartition) Size() uint64 {\n\treturn uint64(p.DiskSize)\n}\n\n// MountPoint implements the config.Provider interface.\nfunc (p *DiskPartition) MountPoint() string {\n\treturn p.DiskMountPoint\n}\n\n// Provider implements the config.Provider interface.\nfunc (e *EncryptionConfig) Provider() block.EncryptionProviderType {\n\tif e.EncryptionProvider == \"\" {\n\t\treturn block.EncryptionProviderLUKS2\n\t}\n\n\t// the provider is validated in the machine config validation\n\tprovider, _ := block.EncryptionProviderTypeString(e.EncryptionProvider) //nolint:errcheck\n\n\treturn provider\n}\n\n// Cipher implements the config.Provider interface.\nfunc (e *EncryptionConfig) Cipher() string {\n\treturn e.EncryptionCipher\n}\n\n// KeySize implements the config.Provider interface.\nfunc (e *EncryptionConfig) KeySize() uint {\n\treturn e.EncryptionKeySize\n}\n\n// BlockSize implements the config.Provider interface.\nfunc (e *EncryptionConfig) BlockSize() uint64 {\n\treturn e.EncryptionBlockSize\n}\n\n// Options implements the config.Provider interface.\nfunc (e *EncryptionConfig) Options() []string {\n\treturn e.EncryptionPerfOptions\n}\n\n// Keys implements the config.Provider interface.\nfunc (e *EncryptionConfig) Keys() []config.EncryptionKey {\n\treturn xslices.Map(e.EncryptionKeys, func(k *EncryptionKey) config.EncryptionKey { return k })\n}\n\n// Static implements the config.Provider interface.\nfunc (e *EncryptionKey) Static() config.EncryptionKeyStatic {\n\tif e.KeyStatic == nil {\n\t\treturn nil\n\t}\n\n\treturn e.KeyStatic\n}\n\n// NodeID implements the config.Provider interface.\nfunc (e *EncryptionKey) NodeID() config.EncryptionKeyNodeID {\n\tif e.KeyNodeID == nil {\n\t\treturn nil\n\t}\n\n\treturn e.KeyNodeID\n}\n\n// KMS implements the config.Provider interface.\nfunc (e *EncryptionKey) KMS() config.EncryptionKeyKMS {\n\tif e.KeyKMS == nil {\n\t\treturn nil\n\t}\n\n\treturn e.KeyKMS\n}\n\n// TPM implements the config.Provider interface.\nfunc (e *EncryptionKey) TPM() config.EncryptionKeyTPM {\n\tif e.KeyTPM == nil {\n\t\treturn nil\n\t}\n\n\treturn e.KeyTPM\n}\n\n// LockToSTATE implements the config.Provider interface.\nfunc (e *EncryptionKey) LockToSTATE() bool {\n\t// not supported in v1alpha1\n\treturn false\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyNodeID) String() string {\n\treturn \"nodeid\"\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) String() string {\n\treturn \"tpm\"\n}\n\n// CheckSecurebootOnEnroll implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) CheckSecurebootOnEnroll() bool {\n\tif e == nil {\n\t\treturn false\n\t}\n\n\treturn pointer.SafeDeref(e.TPMCheckSecurebootStatusOnEnroll)\n}\n\n// PCRs implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) PCRs() []int {\n\t// v1alpha1 always used PCR 7\n\treturn []int{constants.SecureBootStatePCR}\n}\n\n// PubKeyPCRs implements the config.Provider interface.\nfunc (e *EncryptionKeyTPM) PubKeyPCRs() []int {\n\t// we always lock to PCR 11\n\treturn []int{constants.UKIPCR}\n}\n\n// Slot implements the config.Provider interface.\nfunc (e *EncryptionKey) Slot() int {\n\treturn e.KeySlot\n}\n\n// Key implements the config.Provider interface.\nfunc (e *EncryptionKeyStatic) Key() []byte {\n\treturn []byte(e.KeyData)\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyStatic) String() string {\n\treturn \"static\"\n}\n\n// Endpoint implements the config.Provider interface.\nfunc (e *EncryptionKeyKMS) Endpoint() string {\n\treturn e.KMSEndpoint\n}\n\n// String implements the config.Provider interface.\nfunc (e *EncryptionKeyKMS) String() string {\n\treturn \"kms\"\n}\n\n// Get implements the config.Provider interface.\nfunc (e *SystemDiskEncryptionConfig) Get(label string) config.EncryptionConfig {\n\tswitch label {\n\tcase constants.StatePartitionLabel:\n\t\tif e.StatePartition == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn e.StatePartition\n\tcase constants.EphemeralPartitionLabel:\n\t\tif e.EphemeralPartition == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn e.EphemeralPartition\n\t}\n\n\treturn nil\n}\n\n// HostPath implements the config.VolumeMount interface.\nfunc (v VolumeMountConfig) HostPath() string {\n\treturn v.VolumeHostPath\n}\n\n// MountPath implements the config.VolumeMount interface.\nfunc (v VolumeMountConfig) MountPath() string {\n\treturn v.VolumeMountPath\n}\n\nvar volumeNameSanitizer = strings.NewReplacer(\"/\", \"-\", \"_\", \"-\", \".\", \"-\")\n\n// Name implements the config.VolumeMount interface.\nfunc (v VolumeMountConfig) Name() string {\n\treturn strings.Trim(volumeNameSanitizer.Replace(v.VolumeMountPath), \"-\")\n}\n\n// ReadOnly implements the config.VolumeMount interface.\nfunc (v VolumeMountConfig) ReadOnly() bool {\n\treturn v.VolumeReadOnly\n}\n\n// Rules implements config.Udev interface.\nfunc (u *UdevConfig) Rules() []string {\n\treturn u.UdevRules\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_provider_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestInstallDiskSelector(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tselector v1alpha1.InstallDiskSelector\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"size\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tSize: &v1alpha1.InstallDiskSizeMatcher{\n\t\t\t\t\tMatchData: v1alpha1.InstallDiskSizeMatchData{\n\t\t\t\t\t\tOp:   \"<=\",\n\t\t\t\t\t\tSize: 256 * 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: `disk.size <= 262144u && disk.transport != \"\" && !disk.readonly && !disk.cdrom`,\n\t\t},\n\t\t{\n\t\t\tname: \"size and type\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tSize: &v1alpha1.InstallDiskSizeMatcher{\n\t\t\t\t\tMatchData: v1alpha1.InstallDiskSizeMatchData{\n\t\t\t\t\t\tSize: 1024 * 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tType: v1alpha1.InstallDiskType(\"nvme\"),\n\t\t\t},\n\n\t\t\texpected: `disk.size == 1048576u && disk.transport != \"\" && disk.transport == \"nvme\" && !disk.readonly &&\n!disk.cdrom`,\n\t\t},\n\t\t{\n\t\t\tname: \"size and type and modalias\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tSize: &v1alpha1.InstallDiskSizeMatcher{\n\t\t\t\t\tMatchData: v1alpha1.InstallDiskSizeMatchData{\n\t\t\t\t\t\tSize: 1024 * 1024,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tType:     v1alpha1.InstallDiskType(\"hdd\"),\n\t\t\t\tModalias: \"pci:1234:5678*\",\n\t\t\t},\n\n\t\t\texpected: `disk.size == 1048576u && glob(\"pci:1234:5678*\", disk.modalias) && disk.transport != \"\" &&\ndisk.rotational && !disk.readonly && !disk.cdrom`,\n\t\t},\n\t\t{\n\t\t\tname: \"ssd\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tType: v1alpha1.InstallDiskType(\"ssd\"),\n\t\t\t},\n\n\t\t\texpected: `disk.transport != \"\" && !disk.rotational && !disk.readonly && !disk.cdrom`,\n\t\t},\n\t\t{\n\t\t\tname: \"bus path\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tBusPath: \"/pci-0000:00:1f.2/*\",\n\t\t\t},\n\n\t\t\texpected: `disk.transport != \"\" && glob(\"/pci-0000:00:1f.2/*\", disk.bus_path) && !disk.readonly &&\n!disk.cdrom`,\n\t\t},\n\t\t{\n\t\t\tname: \"uuid\",\n\n\t\t\tselector: v1alpha1.InstallDiskSelector{\n\t\t\t\tUUID: \"0000-0001-*\",\n\t\t\t},\n\n\t\t\texpected: `glob(\"0000-0001-*\", disk.uuid) && disk.transport != \"\" && !disk.readonly && !disk.cdrom`,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tinstallCfg := &v1alpha1.InstallConfig{\n\t\t\t\tInstallDiskSelector: &test.selector,\n\t\t\t}\n\n\t\t\texpr, err := installCfg.DiskMatchExpression()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, expr.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_proxyconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/go-pointer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Enabled implements the config.Proxy interface.\nfunc (p *ProxyConfig) Enabled() bool {\n\treturn !pointer.SafeDeref(p.Disabled)\n}\n\n// Image implements the config.Proxy interface.\nfunc (p *ProxyConfig) Image() string {\n\timage := p.ContainerImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:v%s\", constants.KubeProxyImage, constants.DefaultKubernetesVersion)\n\t}\n\n\treturn image\n}\n\n// Mode implements the config.Proxy interface.\nfunc (p *ProxyConfig) Mode() string {\n\treturn p.ModeConfig\n}\n\n// ExtraArgs implements the config.Proxy interface.\nfunc (p *ProxyConfig) ExtraArgs() map[string][]string {\n\treturn p.ExtraArgsConfig.ToMap()\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_redact_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc TestRedactSecrets(t *testing.T) {\n\tinput, err := generate.NewInput(\"test\", \"https://doesntmatter:6443\", constants.DefaultKubernetesVersion)\n\trequire.NoError(t, err)\n\n\tcontainer, err := input.Config(machine.TypeControlPlane)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tconfig := container.RawV1Alpha1()\n\n\trequire.NotEmpty(t, config.MachineConfig.MachineToken)\n\trequire.NotEmpty(t, config.MachineConfig.MachineCA.Key)\n\trequire.NotEmpty(t, config.ClusterConfig.ClusterSecret)\n\trequire.NotEmpty(t, config.ClusterConfig.BootstrapToken)\n\trequire.Empty(t, config.ClusterConfig.ClusterAESCBCEncryptionSecret)\n\trequire.NotEmpty(t, config.ClusterConfig.ClusterSecretboxEncryptionSecret)\n\trequire.NotEmpty(t, config.ClusterConfig.ClusterCA.Key)\n\trequire.NotEmpty(t, config.ClusterConfig.EtcdConfig.RootCA.Key)\n\trequire.NotEmpty(t, config.ClusterConfig.ClusterServiceAccount.Key)\n\n\treplacement := \"**.***\"\n\n\tconfig.Redact(replacement)\n\n\trequire.Equal(t, replacement, config.Machine().Security().Token())\n\trequire.Equal(t, replacement, string(config.Machine().Security().IssuingCA().Key))\n\trequire.Equal(t, replacement, config.Cluster().Secret())\n\trequire.Equal(t, \"***\", config.Cluster().Token().Secret())\n\trequire.Equal(t, \"\", config.Cluster().AESCBCEncryptionSecret())\n\trequire.Equal(t, replacement, config.Cluster().SecretboxEncryptionSecret())\n\trequire.Equal(t, replacement, string(config.Cluster().IssuingCA().Key))\n\trequire.Equal(t, replacement, string(config.Cluster().Etcd().CA().Key))\n\trequire.Equal(t, replacement, string(config.Cluster().ServiceAccount().Key))\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_resourcesconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// CPURequests implements the config.Resources interface.\nfunc (r *ResourcesConfig) CPURequests() string {\n\tif r != nil {\n\t\treturn convertResource(r.Requests, \"cpu\")\n\t}\n\n\treturn \"\"\n}\n\n// MemoryRequests implements the config.Resources interface.\nfunc (r *ResourcesConfig) MemoryRequests() string {\n\tif r != nil {\n\t\treturn convertResource(r.Requests, \"memory\")\n\t}\n\n\treturn \"\"\n}\n\n// CPULimits implements the config.Resources interface.\nfunc (r *ResourcesConfig) CPULimits() string {\n\tif r != nil {\n\t\treturn convertResource(r.Limits, \"cpu\")\n\t}\n\n\treturn \"\"\n}\n\n// MemoryLimits implements the config.Resources interface.\nfunc (r *ResourcesConfig) MemoryLimits() string {\n\tif r != nil {\n\t\treturn convertResource(r.Limits, \"memory\")\n\t}\n\n\treturn \"\"\n}\n\n// Validate performs config validation.\nfunc (r *ResourcesConfig) Validate() error {\n\tif r == nil {\n\t\treturn nil\n\t}\n\n\tcheckKeys := func(resource Unstructured) error {\n\t\tfor key := range resource.Object {\n\t\t\tswitch key {\n\t\t\tcase \"memory\":\n\t\t\tcase \"cpu\":\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unsupported pod resource %q\", key)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\tif err := checkKeys(r.Requests); err != nil {\n\t\treturn err\n\t}\n\n\treturn checkKeys(r.Limits)\n}\n\nfunc convertResource(resources Unstructured, key string) string {\n\tif resources.Object == nil {\n\t\treturn \"\"\n\t}\n\n\tif _, ok := resources.Object[key]; !ok {\n\t\treturn \"\"\n\t}\n\n\tval := resources.Object[key]\n\tswitch typedVal := val.(type) {\n\tcase int:\n\t\treturn strconv.Itoa(typedVal)\n\tcase string:\n\t\treturn typedVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_schedulerconfig.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Image implements the config.Scheduler interface.\nfunc (s *SchedulerConfig) Image() string {\n\timage := s.ContainerImage\n\n\tif image == \"\" {\n\t\timage = fmt.Sprintf(\"%s:v%s\", constants.KubernetesSchedulerImage, constants.DefaultKubernetesVersion)\n\t}\n\n\treturn image\n}\n\n// ExtraArgs implements the config.Scheduler interface.\nfunc (s *SchedulerConfig) ExtraArgs() map[string][]string {\n\treturn s.ExtraArgsConfig.ToMap()\n}\n\n// ExtraVolumes implements the config.Scheduler interface.\nfunc (s *SchedulerConfig) ExtraVolumes() []config.VolumeMount {\n\treturn xslices.Map(s.ExtraVolumesConfig, func(v VolumeMountConfig) config.VolumeMount { return v })\n}\n\n// Env implements the config.Scheduler interface.\nfunc (s *SchedulerConfig) Env() Env {\n\treturn s.EnvConfig\n}\n\n// Resources implements the config.Resources interface.\nfunc (s *SchedulerConfig) Resources() config.Resources {\n\treturn s.ResourcesConfig\n}\n\n// Config implements the config.Scheduler interface.\nfunc (s *SchedulerConfig) Config() map[string]any {\n\treturn s.SchedulerConfig.Object\n}\n\n// Validate performs config validation.\nfunc (s *SchedulerConfig) Validate() error {\n\tif s == nil {\n\t\treturn nil\n\t}\n\n\tif err := s.ResourcesConfig.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"scheduler resource validation failed: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_stability_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/siderolabs/gen/ensure\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/gendata\"\n)\n\n// TestConfigEncodingStability ensures that the encoding of a configuration is stable as we moved forward with the config format.\nfunc TestConfigEncodingStability(t *testing.T) {\n\tt.Parallel()\n\n\t// flip this to generate missing configs\n\tconst generateMode = false\n\n\tsecretsBundle, err := secrets.LoadBundle(\"testdata/stability/secrets.yaml\")\n\trequire.NoError(t, err)\n\n\tversionContracts := []*config.VersionContract{\n\t\tconfig.TalosVersion1_3,\n\t\tconfig.TalosVersion1_4,\n\t\tconfig.TalosVersion1_5,\n\t\tconfig.TalosVersion1_6,\n\t\tconfig.TalosVersion1_7,\n\t\tconfig.TalosVersion1_8,\n\t\tconfig.TalosVersion1_9,\n\t\tconfig.TalosVersion1_10,\n\t\tconfig.TalosVersion1_11,\n\t\tconfig.TalosVersion1_12,\n\t\tconfig.TalosVersion1_13,\n\t}\n\n\tcurrentVersion := ensure.Value(semver.ParseTolerant(gendata.VersionTag))\n\tcurrentVersion.Patch = 0\n\tmaxContractVersion := ensure.Value(semver.ParseTolerant(versionContracts[len(versionContracts)-1].String()))\n\trequire.True(t, currentVersion.LTE(maxContractVersion), \"latest version contract is not tested\")\n\n\tfor _, versionContract := range versionContracts {\n\t\tt.Run(versionContract.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tt.Run(\"base\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tin, err := generate.NewInput(\"base\", \"https://base:6443\", \"1.28.0\",\n\t\t\t\t\tgenerate.WithSecretsBundle(secretsBundle),\n\t\t\t\t\tgenerate.WithVersionContract(versionContract),\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\ttestConfigStability(t, in, versionContract, \"base\", generateMode)\n\t\t\t})\n\n\t\t\tt.Run(\"with overrides\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tin, err := generate.NewInput(\"base\", \"https://base:6443\", \"1.28.0\",\n\t\t\t\t\tgenerate.WithSecretsBundle(secretsBundle),\n\t\t\t\t\tgenerate.WithVersionContract(versionContract),\n\t\t\t\t\tgenerate.WithAdditionalSubjectAltNames([]string{\"foo\", \"bar\"}),\n\t\t\t\t\tgenerate.WithAllowSchedulingOnControlPlanes(true),\n\t\t\t\t\tgenerate.WithDNSDomain(\"example.com\"),\n\t\t\t\t\tgenerate.WithInstallDisk(\"/dev/vda\"),\n\t\t\t\t\tgenerate.WithInstallExtraKernelArgs([]string{\"foo=bar\", \"bar=baz\"}),\n\t\t\t\t\tgenerate.WithLocalAPIServerPort(5443),\n\t\t\t\t\tgenerate.WithSysctls(map[string]string{\"foo\": \"bar\"}),\n\t\t\t\t\tgenerate.WithClusterCNIConfig(&v1alpha1.CNIConfig{\n\t\t\t\t\t\tCNIName: \"custom\",\n\t\t\t\t\t\tCNIUrls: []string{\"https://example.com/cni.yaml\"},\n\t\t\t\t\t}),\n\t\t\t\t\tgenerate.WithRegistryMirror(\"ghcr.io\", \"https://ghcr.io.my-mirror.com\"),\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tpatches, err := configpatcher.LoadPatches([]string{\"@testdata/stability/patch.yaml\"})\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\ttestConfigStability(t, in, versionContract, \"overrides\", generateMode, patches...)\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc testConfigStability(t *testing.T, in *generate.Input, versionContract *config.VersionContract, flavor string, generateMode bool, patches ...configpatcher.Patch) {\n\tt.Helper()\n\n\tfor _, machineType := range []machine.Type{\n\t\tmachine.TypeControlPlane,\n\t\tmachine.TypeWorker,\n\t} {\n\t\tcfg, err := in.Config(machineType)\n\t\trequire.NoError(t, err)\n\n\t\tcfgBytes, err := cfg.EncodeBytes(encoder.WithComments(encoder.CommentsDisabled))\n\t\trequire.NoError(t, err)\n\n\t\tpatched, err := configpatcher.Apply(configpatcher.WithBytes(cfgBytes), patches)\n\t\trequire.NoError(t, err)\n\n\t\tcfgBytes, err = patched.Bytes()\n\t\trequire.NoError(t, err)\n\n\t\texpectedPath := fmt.Sprintf(\"testdata/stability/%s/%s-%s.yaml\", versionContract, flavor, machineType)\n\n\t\texpectedBytes, err := os.ReadFile(expectedPath)\n\t\tif errors.Is(err, fs.ErrNotExist) && generateMode {\n\t\t\trequire.NoError(t, os.WriteFile(expectedPath, cfgBytes, 0o644))\n\n\t\t\tt.Logf(\"generated %s\", expectedPath)\n\n\t\t\tcontinue\n\t\t}\n\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, string(expectedBytes), string(cfgBytes), \"config encoding mismatch for %s\", expectedPath)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_strategic_merge_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestStrategicMergePatch(t *testing.T) {\n\tt.Parallel()\n\n\tentries, err := os.ReadDir(\"testdata/strategic\")\n\trequire.NoError(t, err)\n\n\tfor _, entry := range entries {\n\t\tif !entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tt.Run(entry.Name(), testMerge(filepath.Join(\"testdata/strategic\", entry.Name())))\n\t}\n}\n\nfunc load(t *testing.T, path string) *v1alpha1.Config {\n\tprovider, err := configloader.NewFromFile(path)\n\trequire.NoError(t, err)\n\n\treturn provider.RawV1Alpha1()\n}\n\nfunc testMerge(path string) func(t *testing.T) {\n\treturn func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tleft := load(t, filepath.Join(path, \"left.yaml\"))\n\t\tright := load(t, filepath.Join(path, \"right.yaml\"))\n\t\texpected := load(t, filepath.Join(path, \"expected.yaml\"))\n\n\t\tresult := left.DeepCopy()\n\n\t\terr := merge.Merge(result, right)\n\t\trequire.NoError(t, err)\n\n\t\tctr, err := container.New(result)\n\t\trequire.NoError(t, err)\n\n\t\tmarshaled, err := ctr.EncodeString(encoder.WithComments(encoder.CommentsDisabled))\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, expected, result, \"got:\\n%v\", marshaled)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_types.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n/*\nPackage v1alpha1 contains definition of the `v1alpha1` configuration document.\n\nEven though the machine configuration in Talos Linux is multi-document, at the moment\nthis configuration document contains most of the configuration options.\n\nIt is expected that new configuration options will be added as new documents, and existing ones\nmigrated to their own documents.\n*/\npackage v1alpha1\n\n//go:generate go tool github.com/siderolabs/talos/tools/docgen -output ./v1alpha1_types_doc.go ./v1alpha1_types.go\n\n//go:generate go tool k8s.io/code-generator/cmd/deepcopy-gen --go-header-file ../../../../../hack/boilerplate.txt --bounding-dirs ../v1alpha1 --output-file zz_generated.deepcopy\n\n//docgen:jsonschema\n\nimport (\n\t\"fmt\"\n\t\"maps\"\n\t\"net/url\"\n\t\"os\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/dustin/go-humanize\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/internal/registry\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/merge\"\n)\n\nfunc init() {\n\tregistry.Register(\"v1alpha1\", func(version string) config.Document {\n\t\treturn &Config{}\n\t})\n}\n\n// Args represents a map of argument names to their values.\ntype Args map[string]ArgValue\n\n// ToMap converts Args to a map of string slices.\nfunc (a Args) ToMap() map[string][]string {\n\tresult := make(map[string][]string)\n\n\tfor key, argValue := range a {\n\t\t// technically this shouldn't happen due to validation during unmarshalling\n\t\t// but just in case, we handle case when both are set\n\t\tvalue := make([]string, 0)\n\n\t\tif argValue.strValue != \"\" {\n\t\t\tvalue = append(value, argValue.strValue)\n\t\t}\n\n\t\tif argValue.listValue != nil {\n\t\t\tvalue = append(value, argValue.listValue...)\n\t\t}\n\n\t\tresult[key] = value\n\t}\n\n\treturn result\n}\n\n// Merge with another Args.\nfunc (a *Args) Merge(other any) error {\n\totherArgs, ok := other.(Args)\n\tif !ok {\n\t\treturn fmt.Errorf(\"cannot merge Args with %T\", other)\n\t}\n\n\tif len(otherArgs) == 0 {\n\t\treturn nil\n\t}\n\n\tif *a == nil {\n\t\t*a = make(Args)\n\t}\n\n\tmaps.Copy(*a, otherArgs)\n\n\treturn nil\n}\n\n// ArgValue represents a value for an argument, which can be either a single string or a list of strings.\n// docgen:nodoc\ntype ArgValue struct {\n\tlistValue []string\n\tstrValue  string\n}\n\n// NewArgValue creates a new ArgValue from either a string or a list of strings.\nfunc NewArgValue(s string, l []string) ArgValue {\n\treturn ArgValue{\n\t\tlistValue: l,\n\t\tstrValue:  s,\n\t}\n}\n\n// MarshalYAML is a custom marshaller for `ArgValue`.\nfunc (a ArgValue) MarshalYAML() (any, error) {\n\tif a.listValue != nil {\n\t\treturn &yaml.Node{\n\t\t\tKind: yaml.SequenceNode,\n\t\t\tTag:  \"!!seq\",\n\t\t\tContent: func() []*yaml.Node {\n\t\t\t\tnodes := make([]*yaml.Node, 0, len(a.listValue))\n\n\t\t\t\tfor _, item := range a.listValue {\n\t\t\t\t\tnodes = append(nodes, &yaml.Node{\n\t\t\t\t\t\tKind:  yaml.ScalarNode,\n\t\t\t\t\t\tTag:   \"!!str\",\n\t\t\t\t\t\tValue: item,\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\treturn nodes\n\t\t\t}(),\n\t\t}, nil\n\t}\n\n\tif a.strValue != \"\" {\n\t\treturn &yaml.Node{\n\t\t\tKind:  yaml.ScalarNode,\n\t\t\tTag:   \"!!str\",\n\t\t\tValue: a.strValue,\n\t\t}, nil\n\t}\n\n\treturn nil, nil\n}\n\n// UnmarshalYAML is a custom unmarshaller for `ArgValue`.\nfunc (a *ArgValue) UnmarshalYAML(unmarshal func(any) error) error {\n\t// Try scalar string first\n\tvar s string\n\tif err := unmarshal(&s); err == nil {\n\t\ta.strValue = s\n\t\ta.listValue = nil\n\n\t\treturn nil\n\t}\n\n\t// Then try list of strings\n\tvar l []string\n\tif err := unmarshal(&l); err == nil {\n\t\ta.listValue = l\n\t\ta.strValue = \"\"\n\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"arg value must be a string or list of strings\")\n}\n\n// Config defines the v1alpha1.Config Talos machine configuration document.\n//\n//\texamples:\n//\t   - value: configExample()\n//\tschemaRoot: true\ntype Config struct {\n\t//   description: |\n\t//     Indicates the schema used to decode the contents.\n\t//   values:\n\t//     - \"v1alpha1\"\n\tConfigVersion string `yaml:\"version\"`\n\t//   description: |\n\t//     Enable verbose logging to the console.\n\t//     All system containers logs will flow into serial console.\n\t//\n\t//     **Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tConfigDebug *bool `yaml:\"debug,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Not supported anymore.\n\tConfigPersist *bool `yaml:\"persist,omitempty\"`\n\t//   description: |\n\t//     Provides machine specific configuration options.\n\tMachineConfig *MachineConfig `yaml:\"machine\"`\n\t//   description: |\n\t//     Provides cluster specific configuration options.\n\tClusterConfig *ClusterConfig `yaml:\"cluster\"`\n}\n\nvar _ config.MachineConfig = (*MachineConfig)(nil)\n\n// MachineConfig represents the machine-specific config values.\n//\n//\texamples:\n//\t   - value: machineConfigExample()\ntype MachineConfig struct {\n\t//   description: |\n\t//     Defines the role of the machine within the cluster.\n\t//\n\t//     **Control Plane**\n\t//\n\t//     Control Plane node type designates the node as a control plane member.\n\t//     This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\n\t//\n\t//     **Worker**\n\t//\n\t//     Worker node type designates the node as a worker node.\n\t//     This means it will be an available compute node for scheduling workloads.\n\t//\n\t//     This node type was previously known as \"join\"; that value is still supported but deprecated.\n\t//   values:\n\t//     - \"controlplane\"\n\t//     - \"worker\"\n\tMachineType string `yaml:\"type\"`\n\t//   description: |\n\t//     The `token` is used by a machine to join the PKI of the cluster.\n\t//     Using this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\n\t//   examples:\n\t//     - name: example token\n\t//       value: \"\\\"328hom.uqjzh6jnn2eie9oi\\\"\"\n\tMachineToken string `yaml:\"token\"` // Warning: It is important to ensure that this token is correct since a machine's certificate has a short TTL by default.\n\t//   description: |\n\t//     The root certificate authority of the PKI.\n\t//     It is composed of a base64 encoded `crt` and `key`.\n\t//   examples:\n\t//     - value: pemEncodedCertificateExample()\n\t//       name: machine CA example\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tMachineCA *x509.PEMEncodedCertificateAndKey `yaml:\"ca,omitempty\"`\n\t//   description: |\n\t//     The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.\n\t//     It is composed of a base64 encoded `crt``.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\tMachineAcceptedCAs []*x509.PEMEncodedCertificate `yaml:\"acceptedCAs,omitempty\"`\n\t//   description: |\n\t//     Extra certificate subject alternative names for the machine's certificate.\n\t//     By default, all non-loopback interface IPs are automatically added to the certificate's SANs.\n\t//   examples:\n\t//     - name: Uncomment this to enable SANs.\n\t//       value: '[]string{\"10.0.0.10\", \"172.16.0.10\", \"192.168.0.10\"}'\n\tMachineCertSANs []string `yaml:\"certSANs\"`\n\t//   description: |\n\t//     Provides machine specific control plane configuration options.\n\t//   examples:\n\t//     - name: ControlPlane definition example.\n\t//       value: machineControlplaneExample()\n\tMachineControlPlane *MachineControlPlaneConfig `yaml:\"controlPlane,omitempty\"`\n\t//   description: |\n\t//     Used to provide additional options to the kubelet.\n\t//   examples:\n\t//     - name: Kubelet definition example.\n\t//       value: machineKubeletExample()\n\tMachineKubelet *KubeletConfig `yaml:\"kubelet,omitempty\"`\n\t//   description: |\n\t//     Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\n\t//\n\t//     Static pods can be used to run components which should be started before the Kubernetes control plane is up.\n\t//     Talos doesn't validate the pod definition.\n\t//     Updates to this field can be applied without a reboot.\n\t//\n\t//     See https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\n\t//   examples:\n\t//     - name: nginx static pod.\n\t//       value: machinePodsExample()\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       type: object\n\tMachinePods []Unstructured `yaml:\"pods,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: All fields within NetworkConfig are deprecated. Use multi-document network config types instead:\n\t// HostnameConfig, NetworkDeviceConfig, ResolverConfig, StaticHostConfig, KubeSpanConfig.\n\tMachineNetwork *NetworkConfig `yaml:\"network,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use 'UserVolumeConfig' instead.\n\tMachineDisks []*MachineDisk `yaml:\"disks,omitempty\"` // Note: `size` is in units of bytes.\n\t//   description: |\n\t//     Used to provide instructions for installations.\n\t//\n\t//     Note that this configuration section gets silently ignored by Talos images that are considered pre-installed.\n\t//     To make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\n\t//   examples:\n\t//     - name: MachineInstall config usage example.\n\t//       value: machineInstallExample()\n\tMachineInstall *InstallConfig `yaml:\"install,omitempty\"`\n\t//   description: |\n\t//     Allows the addition of user specified files.\n\t//     The value of `op` can be `create`, `overwrite`, or `append`.\n\t//     In the case of `create`, `path` must not exist.\n\t//     In the case of `overwrite`, and `append`, `path` must be a valid file.\n\t//     If an `op` value of `append` is used, the existing file will be appended.\n\t//     Note that the file contents are not required to be base64 encoded.\n\t//   examples:\n\t//      - name: MachineFiles usage example.\n\t//        value: machineFilesExample()\n\tMachineFiles []*MachineFile `yaml:\"files,omitempty\"` // Note: The specified `path` is relative to `/var`.\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use 'EnvironmentConfig' instead.\n\tMachineEnv Env `yaml:\"env,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use 'TimeSyncConfig' instead.\n\tMachineTime *TimeConfig `yaml:\"time,omitempty\"`\n\t//   description: |\n\t//     Used to configure the machine's sysctls.\n\t//   examples:\n\t//     - name: MachineSysctls usage example.\n\t//       value: machineSysctlsExample()\n\tMachineSysctls map[string]string `yaml:\"sysctls,omitempty\"`\n\t//   description: |\n\t//     Used to configure the machine's sysfs.\n\t//   examples:\n\t//     - name: MachineSysfs usage example.\n\t//       value: machineSysfsExample()\n\tMachineSysfs map[string]string `yaml:\"sysfs,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `Registry*Config` instead.\n\tMachineRegistries RegistriesConfig `yaml:\"registries,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `VolumeConfig` instead.\n\tMachineSystemDiskEncryption *SystemDiskEncryptionConfig `yaml:\"systemDiskEncryption,omitempty\"`\n\t//   description: |\n\t//     Features describe individual Talos features that can be switched on or off.\n\t//   examples:\n\t//     - value: machineFeaturesExample()\n\tMachineFeatures *FeaturesConfig `yaml:\"features,omitempty\"`\n\t//   description: |\n\t//     Configures the udev system.\n\t//   examples:\n\t//     - value: machineUdevExample()\n\tMachineUdev *UdevConfig `yaml:\"udev,omitempty\"`\n\t//   description: |\n\t//     Configures the logging system.\n\t//   examples:\n\t//     - value: machineLoggingExample()\n\tMachineLogging *LoggingConfig `yaml:\"logging,omitempty\"`\n\t//   description: |\n\t//     Configures the kernel.\n\t//   examples:\n\t//     - value: machineKernelExample()\n\tMachineKernel *KernelConfig `yaml:\"kernel,omitempty\"`\n\t//  description: |\n\t//    Configures the seccomp profiles for the machine.\n\t//  examples:\n\t//    - value: machineSeccompExample()\n\tMachineSeccompProfiles []*MachineSeccompProfile `yaml:\"seccompProfiles,omitempty\" talos:\"omitonlyifnil\"`\n\t//  description: |\n\t//    Override (patch) settings in the default OCI runtime spec for CRI containers.\n\t//\n\t//    It can be used to set some default container settings which are not configurable in Kubernetes,\n\t//    for example default ulimits.\n\t//    Note: this change applies to all newly created containers, and it requires a reboot to take effect.\n\t//  examples:\n\t//    - name: override default open file limit\n\t//      value: machineBaseRuntimeSpecOverridesExample()\n\t//  schema:\n\t//    type: object\n\tMachineBaseRuntimeSpecOverrides Unstructured `yaml:\"baseRuntimeSpecOverrides,omitempty\"`\n\t//  description: |\n\t//    Configures the node labels for the machine.\n\t//\n\t//    Note: In the default Kubernetes configuration, worker nodes are restricted to set\n\t//    labels with some prefixes (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\n\t//  examples:\n\t//    - name: node labels example.\n\t//      value: 'map[string]string{\"exampleLabel\": \"exampleLabelValue\"}'\n\tMachineNodeLabels map[string]string `yaml:\"nodeLabels,omitempty\"`\n\t//  description: |\n\t//    Configures the node annotations for the machine.\n\t//  examples:\n\t//    - name: node annotations example.\n\t//      value: 'map[string]string{\"customer.io/rack\": \"r13a25\"}'\n\tMachineNodeAnnotations map[string]string `yaml:\"nodeAnnotations,omitempty\"`\n\t//  description: |\n\t//    Configures the node taints for the machine. Effect is optional.\n\t//\n\t//    Note: In the default Kubernetes configuration, worker nodes are not allowed to\n\t//    modify the taints (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\n\t//  examples:\n\t//    - name: node taints example.\n\t//      value: 'map[string]string{\"exampleTaint\": \"exampleTaintValue:NoSchedule\"}'\n\tMachineNodeTaints map[string]string `yaml:\"nodeTaints,omitempty\"`\n}\n\n// MachineSeccompProfile defines seccomp profiles for the machine.\ntype MachineSeccompProfile struct {\n\t//  description: |\n\t//    The `name` field is used to provide the file name of the seccomp profile.\n\tMachineSeccompProfileName string `yaml:\"name\"`\n\t// description: |\n\t//   The `value` field is used to provide the seccomp profile.\n\t// schema:\n\t//   type: object\n\tMachineSeccompProfileValue Unstructured `yaml:\"value\"`\n}\n\nvar (\n\t_ config.ClusterConfig  = (*ClusterConfig)(nil)\n\t_ config.ClusterNetwork = (*ClusterConfig)(nil)\n\t_ config.Token          = (*ClusterConfig)(nil)\n)\n\n// ClusterConfig represents the cluster-wide config values.\n//\n//\texamples:\n//\t   - value: clusterConfigExample()\ntype ClusterConfig struct {\n\t//   description: |\n\t//     Globally unique identifier for this cluster (base64 encoded random 32 bytes).\n\tClusterID string `yaml:\"id,omitempty\"`\n\t//   description: |\n\t//     Shared secret of cluster (base64 encoded random 32 bytes).\n\t//     This secret is shared among cluster members but should never be sent over the network.\n\tClusterSecret string `yaml:\"secret,omitempty\"`\n\t//   description: |\n\t//     Provides control plane specific configuration options.\n\t//   examples:\n\t//     - name: Setting controlplane endpoint address to 1.2.3.4 and port to 443 example.\n\t//       value: clusterControlPlaneExample()\n\tControlPlane *ControlPlaneConfig `yaml:\"controlPlane\"`\n\t//   description: |\n\t//     Configures the cluster's name.\n\tClusterName string `yaml:\"clusterName,omitempty\"`\n\t//   description: |\n\t//     Provides cluster specific network configuration options.\n\t//   examples:\n\t//     - name: Configuring with flannel CNI and setting up subnets.\n\t//       value:  clusterNetworkExample()\n\tClusterNetwork *ClusterNetworkConfig `yaml:\"network,omitempty\"`\n\t//   description: |\n\t//     The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\n\t//   examples:\n\t//     - name: Bootstrap token example (do not use in production!).\n\t//       value: '\"wlzjyw.bei2zfylhs2by0wd\"'\n\tBootstrapToken string `yaml:\"token,omitempty\"`\n\t//   description: |\n\t//     A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\n\t//     Enables encryption with AESCBC.\n\t//   examples:\n\t//     - name: Decryption secret example (do not use in production!).\n\t//       value: '\"z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\"'\n\tClusterAESCBCEncryptionSecret string `yaml:\"aescbcEncryptionSecret,omitempty\"`\n\t//   description: |\n\t//     A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\n\t//     Enables encryption with secretbox.\n\t//     Secretbox has precedence over AESCBC.\n\t//   examples:\n\t//     - name: Decryption secret example (do not use in production!).\n\t//       value: '\"z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\"'\n\tClusterSecretboxEncryptionSecret string `yaml:\"secretboxEncryptionSecret,omitempty\"`\n\t//   description: |\n\t//     The base64 encoded root certificate authority used by Kubernetes.\n\t//   examples:\n\t//     - name: ClusterCA example.\n\t//       value: pemEncodedCertificateExample()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tClusterCA *x509.PEMEncodedCertificateAndKey `yaml:\"ca,omitempty\"`\n\t//   description: |\n\t//     The list of base64 encoded accepted certificate authorities used by Kubernetes.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\tClusterAcceptedCAs []*x509.PEMEncodedCertificate `yaml:\"acceptedCAs,omitempty\"`\n\t//   description: |\n\t//     The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\n\t//\n\t//     This CA can be self-signed.\n\t//   examples:\n\t//     - name: AggregatorCA example.\n\t//       value: pemEncodedCertificateExample()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tClusterAggregatorCA *x509.PEMEncodedCertificateAndKey `yaml:\"aggregatorCA,omitempty\"`\n\t//   description: |\n\t//     The base64 encoded private key for service account token generation.\n\t//   examples:\n\t//     - name: AggregatorCA example.\n\t//       value: pemEncodedKeyExample()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       key:\n\t//         type: string\n\t//         additionalProperties: false\n\tClusterServiceAccount *x509.PEMEncodedKey `yaml:\"serviceAccount,omitempty\"`\n\t//   description: |\n\t//     API server specific configuration options.\n\t//   examples:\n\t//     - value: clusterAPIServerExample()\n\tAPIServerConfig *APIServerConfig `yaml:\"apiServer,omitempty\"`\n\t//   description: |\n\t//     Controller manager server specific configuration options.\n\t//   examples:\n\t//     - value: clusterControllerManagerExample()\n\tControllerManagerConfig *ControllerManagerConfig `yaml:\"controllerManager,omitempty\"`\n\t//   description: |\n\t//     Kube-proxy server-specific configuration options\n\t//   examples:\n\t//     - value: clusterProxyExample()\n\tProxyConfig *ProxyConfig `yaml:\"proxy,omitempty\"`\n\t//   description: |\n\t//     Scheduler server specific configuration options.\n\t//   examples:\n\t//     - value: clusterSchedulerExample()\n\tSchedulerConfig *SchedulerConfig `yaml:\"scheduler,omitempty\"`\n\t//   description: |\n\t//     Configures cluster member discovery.\n\t//   examples:\n\t//     - value: clusterDiscoveryExample()\n\tClusterDiscoveryConfig *ClusterDiscoveryConfig `yaml:\"discovery,omitempty\"`\n\t//   description: |\n\t//     Etcd specific configuration options.\n\t//   examples:\n\t//     - value: clusterEtcdExample()\n\tEtcdConfig *EtcdConfig `yaml:\"etcd,omitempty\"`\n\t//   description: |\n\t//     Core DNS specific configuration options.\n\t//   examples:\n\t//     - value: clusterCoreDNSExample()\n\tCoreDNSConfig *CoreDNS `yaml:\"coreDNS,omitempty\"`\n\t//   description: |\n\t//     External cloud provider configuration.\n\t//   examples:\n\t//     - value: clusterExternalCloudProviderConfigExample()\n\tExternalCloudProviderConfig *ExternalCloudProviderConfig `yaml:\"externalCloudProvider,omitempty\"`\n\t//   description: |\n\t//     A list of urls that point to additional manifests.\n\t//     These will get automatically deployed as part of the bootstrap.\n\t//   examples:\n\t//     - value: >\n\t//        []string{\n\t//         \"https://www.example.com/manifest1.yaml\",\n\t//         \"https://www.example.com/manifest2.yaml\",\n\t//        }\n\tExtraManifests []string `yaml:\"extraManifests,omitempty\" talos:\"omitonlyifnil\"`\n\t//   description: |\n\t//     A map of key value pairs that will be added while fetching the extraManifests.\n\t//   examples:\n\t//     - value: >\n\t//         map[string]string{\n\t//           \"Token\": \"1234567\",\n\t//           \"X-ExtraInfo\": \"info\",\n\t//         }\n\tExtraManifestHeaders map[string]string `yaml:\"extraManifestHeaders,omitempty\"`\n\t//   description: |\n\t//     A list of inline Kubernetes manifests.\n\t//     These will get automatically deployed as part of the bootstrap.\n\t//   examples:\n\t//     - value: clusterInlineManifestsExample()\n\t//   schema:\n\t//     type: array\n\t//     items:\n\t//       $ref: \"#/$defs/v1alpha1.ClusterInlineManifest\"\n\tClusterInlineManifests ClusterInlineManifests `yaml:\"inlineManifests,omitempty\" talos:\"omitonlyifnil\"`\n\t//   description: |\n\t//     Settings for admin kubeconfig generation.\n\t//     Certificate lifetime can be configured.\n\t//   examples:\n\t//     - value: clusterAdminKubeconfigExample()\n\tAdminKubeconfigConfig *AdminKubeconfigConfig `yaml:\"adminKubeconfig,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `AllowSchedulingOnControlPlanes` instead.\n\tAllowSchedulingOnMasters *bool `yaml:\"allowSchedulingOnMasters,omitempty\"`\n\t//   description: |\n\t//     Allows running workload on control-plane nodes.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\t//   examples:\n\t//     - value: true\n\tAllowSchedulingOnControlPlanes *bool `yaml:\"allowSchedulingOnControlPlanes,omitempty\"`\n}\n\n// LinuxIDMapping represents the Linux ID mapping.\ntype LinuxIDMapping struct {\n\t//   description: |\n\t//     ContainerID is the starting UID/GID in the container.\n\tContainerID uint32 `yaml:\"containerID\"`\n\t//   description: |\n\t//     HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\n\tHostID uint32 `yaml:\"hostID\"`\n\t//   description: |\n\t//     Size is the number of IDs to be mapped.\n\tSize uint32 `yaml:\"size\"`\n}\n\n// ExtraMount wraps OCI Mount specification.\ntype ExtraMount struct {\n\t//   description: |\n\t//     Destination is the absolute path where the mount will be placed in the container.\n\tDestination string `yaml:\"destination\"`\n\t//   description: |\n\t//     Type specifies the mount kind.\n\tType string `yaml:\"type,omitempty\"`\n\t//   description: |\n\t//     Source specifies the source path of the mount.\n\tSource string `yaml:\"source,omitempty\"`\n\t//   description: |\n\t//     Options are fstab style mount options.\n\tOptions []string `yaml:\"options,omitempty\"`\n\n\t//   description: |\n\t//     UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\n\t//\n\t//     Every mount point could have its own mapping.\n\tUIDMappings []LinuxIDMapping `yaml:\"uidMappings,omitempty\"`\n\t//   description: |\n\t//     UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\n\t//\n\t//     Every mount point could have its own mapping.\n\tGIDMappings []LinuxIDMapping `yaml:\"gidMappings,omitempty\"`\n}\n\n// MachineControlPlaneConfig machine specific configuration options.\ntype MachineControlPlaneConfig struct {\n\t//   description: |\n\t//     Controller manager machine specific configuration options.\n\tMachineControllerManager *MachineControllerManagerConfig `yaml:\"controllerManager,omitempty\"`\n\t//   description: |\n\t//     Scheduler machine specific configuration options.\n\tMachineScheduler *MachineSchedulerConfig `yaml:\"scheduler,omitempty\"`\n}\n\n// MachineControllerManagerConfig represents the machine specific ControllerManager config values.\ntype MachineControllerManagerConfig struct {\n\t//   description: |\n\t//     Disable kube-controller-manager on the node.\n\tMachineControllerManagerDisabled *bool `yaml:\"disabled,omitempty\"`\n}\n\n// MachineSchedulerConfig represents the machine specific Scheduler config values.\ntype MachineSchedulerConfig struct {\n\t//   description: |\n\t//     Disable kube-scheduler on the node.\n\tMachineSchedulerDisabled *bool `yaml:\"disabled,omitempty\"`\n}\n\n// KubeletConfig represents the kubelet config values.\ntype KubeletConfig struct {\n\t//   description: |\n\t//     The `image` field is an optional reference to an alternative kubelet image.\n\t//   examples:\n\t//     - value: kubeletImageExample()\n\tKubeletImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\n\t//   examples:\n\t//     - value: '[]string{\"10.96.0.10\", \"169.254.2.53\"}'\n\tKubeletClusterDNS []string `yaml:\"clusterDNS,omitempty\"`\n\t//   description: |\n\t//     The `extraArgs` field is used to provide additional flags to the kubelet.\n\t//   examples:\n\t//     - value: >\n\t//         Args{\n\t//           \"key\": ArgValue{strValue: \"value\"},\n\t//         }\n\t//     - value: >\n\t//         Args{\n\t//           \"key\": ArgValue{listValue: []string{\"value1\", \"value2\"}},\n\t//         }\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tKubeletExtraArgs Args `yaml:\"extraArgs,omitempty\"`\n\t//   description: |\n\t//     The `extraMounts` field is used to add additional mounts to the kubelet container.\n\t//     Note that either `bind` or `rbind` are required in the `options`.\n\t//   examples:\n\t//     - value: kubeletExtraMountsExample()\n\tKubeletExtraMounts []ExtraMount `yaml:\"extraMounts,omitempty\"`\n\t//   description: |\n\t//     The `extraConfig` field is used to provide kubelet configuration overrides.\n\t//\n\t//     Some fields are not allowed to be overridden: authentication and authorization, cgroups\n\t//     configuration, ports, etc.\n\t//   examples:\n\t//     - value: kubeletExtraConfigExample()\n\t//   schema:\n\t//     type: object\n\tKubeletExtraConfig Unstructured `yaml:\"extraConfig,omitempty\"`\n\t//  description: |\n\t//   The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\n\t//  examples:\n\t//    - value: kubeletCredentialProviderConfigExample()\n\t//  schema:\n\t//    type: object\n\tKubeletCredentialProviderConfig Unstructured `yaml:\"credentialProviderConfig,omitempty\"`\n\t//  description: |\n\t//    Enable container runtime default Seccomp profile.\n\t//  values:\n\t//    - true\n\t//    - yes\n\t//    - false\n\t//    - no\n\tKubeletDefaultRuntimeSeccompProfileEnabled *bool `yaml:\"defaultRuntimeSeccompProfileEnabled,omitempty\"`\n\t//   description: |\n\t//     The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\n\t//     This is required in clouds like AWS.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tKubeletRegisterWithFQDN *bool `yaml:\"registerWithFQDN,omitempty\"`\n\t//   description: |\n\t//     The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\n\t//     This is used when a node has multiple addresses to choose from.\n\t//   examples:\n\t//     - value: kubeletNodeIPExample()\n\tKubeletNodeIP *KubeletNodeIPConfig `yaml:\"nodeIP,omitempty\"`\n\t//   description: |\n\t//      The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\n\t//      This runs kubelet as standalone and only runs static pods.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tKubeletSkipNodeRegistration *bool `yaml:\"skipNodeRegistration,omitempty\"`\n\t//   description: |\n\t//     The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\n\t//     It's recommended to configure static pods with the \"pods\" key instead.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tKubeletDisableManifestsDirectory *bool `yaml:\"disableManifestsDirectory,omitempty\"`\n}\n\n// KubeletNodeIPConfig represents the kubelet node IP configuration.\ntype KubeletNodeIPConfig struct {\n\t//  description: |\n\t//    The `validSubnets` field configures the networks to pick kubelet node IP from.\n\t//    For dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\n\t//    IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\n\t//    Negative subnet matches should be specified last to filter out IPs picked by positive matches.\n\t//    If not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\n\tKubeletNodeIPValidSubnets []string `yaml:\"validSubnets,omitempty\"`\n}\n\n// NetworkConfig represents the machine's networking config values.\n//\n// Deprecated: all fields in NetworkConfig are deprecated, use corresponding multi-doc config types instead.\n//\n//docgen:nodoc\ntype NetworkConfig struct {\n\t// docgen:nodoc\n\t//\n\t// Deprecated: use `HostnameConfig` instead.\n\tNetworkHostname string `yaml:\"hostname,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: use multi-doc network config.\n\tNetworkInterfaces NetworkDeviceList `yaml:\"interfaces,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `ResolverConfig` instead.\n\tNameServers []string `yaml:\"nameservers,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `ResolverConfig` instead.\n\tSearches []string `yaml:\"searchDomains,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `StatisHostConfig` instead.\n\tExtraHostEntries []*ExtraHost `yaml:\"extraHostEntries,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `KubeSpanConfig` document instead.\n\tNetworkKubeSpan *NetworkKubeSpan `yaml:\"kubespan,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use `ResolverConfig` instead.\n\tNetworkDisableSearchDomain *bool `yaml:\"disableSearchDomain,omitempty\"`\n}\n\n// NetworkDeviceList is a list of *Device structures with overridden merge process.\n//\n// docgen:nodoc\ntype NetworkDeviceList []*Device\n\n// Merge the network interface configuration intelligently.\nfunc (devices *NetworkDeviceList) Merge(other any) error {\n\totherDevices, ok := other.(NetworkDeviceList)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for device merge %T\", other)\n\t}\n\n\tfor _, device := range otherDevices {\n\t\tif err := devices.mergeDevice(device); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (devices *NetworkDeviceList) mergeDevice(device *Device) error {\n\tvar existing *Device\n\n\tswitch {\n\tcase device.DeviceInterface != \"\":\n\t\tfor _, d := range *devices {\n\t\t\tif d.DeviceInterface == device.DeviceInterface {\n\t\t\t\texisting = d\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\tcase device.DeviceSelector != nil:\n\t\tfor _, d := range *devices {\n\t\t\tif d.DeviceSelector != nil && *d.DeviceSelector == *device.DeviceSelector {\n\t\t\t\texisting = d\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif existing != nil {\n\t\treturn merge.Merge(existing, device)\n\t}\n\n\t*devices = append(*devices, device)\n\n\treturn nil\n}\n\n// InstallConfig represents the installation options for preparing a node.\ntype InstallConfig struct {\n\t//   description: |\n\t//     The disk used for installations.\n\t//   examples:\n\t//     - value: '\"/dev/sda\"'\n\t//     - value: '\"/dev/nvme0\"'\n\tInstallDisk string `yaml:\"disk,omitempty\"`\n\t//   description: |\n\t//     Look up disk using disk attributes like model, size, serial and others.\n\t//     Always has priority over `disk`.\n\t//   examples:\n\t//     - value: machineInstallDiskSelectorExample()\n\tInstallDiskSelector *InstallDiskSelector `yaml:\"diskSelector,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use Image Factory/imager instead to build a proper installer.\n\tInstallExtraKernelArgs []string `yaml:\"extraKernelArgs,omitempty\"`\n\t//   description: |\n\t//     Allows for supplying the image used to perform the installation.\n\t//     Image reference for each Talos release can be found on\n\t//     [GitHub releases page](https://github.com/siderolabs/talos/releases).\n\t//   examples:\n\t//     - value: '\"ghcr.io/siderolabs/installer:latest\"'\n\tInstallImage string `yaml:\"image,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: Use custom `InstallImage` instead.\n\tInstallExtensions []InstallExtensionConfig `yaml:\"extensions,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: It never worked.\n\tInstallBootloader *bool `yaml:\"bootloader,omitempty\"`\n\t//   description: |\n\t//     Indicates if the installation disk should be wiped at installation time.\n\t//     Defaults to `true`.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tInstallWipe *bool `yaml:\"wipe\"`\n\t//   description: |\n\t//     Indicates if MBR partition should be marked as bootable (active).\n\t//     Should be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\n\tInstallLegacyBIOSSupport *bool `yaml:\"legacyBIOSSupport,omitempty\"`\n\t//   description: |\n\t//     Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\n\t//     This changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\n\tInstallGrubUseUKICmdline *bool `yaml:\"grubUseUKICmdline,omitempty\"`\n}\n\n// InstallDiskSizeMatcher disk size condition parser.\n// docgen:nodoc\ntype InstallDiskSizeMatcher struct {\n\tMatchData InstallDiskSizeMatchData\n\tcondition string\n}\n\n// MarshalYAML is a custom marshaller for `InstallDiskSizeMatcher`.\nfunc (m *InstallDiskSizeMatcher) MarshalYAML() (any, error) {\n\treturn m.condition, nil\n}\n\n// UnmarshalYAML is a custom unmarshaller for `InstallDiskSizeMatcher`.\nfunc (m *InstallDiskSizeMatcher) UnmarshalYAML(unmarshal func(any) error) error {\n\tif err := unmarshal(&m.condition); err != nil {\n\t\treturn err\n\t}\n\n\tm.condition = strings.TrimSpace(m.condition)\n\n\tre := regexp.MustCompile(`(>=|<=|>|<|==)?\\b*(.*)$`)\n\n\tparts := re.FindStringSubmatch(m.condition)\n\tif len(parts) < 2 {\n\t\treturn fmt.Errorf(\"failed to parse the condition: expected [>=|<=|>|<|==]<size>[units], got %s\", m.condition)\n\t}\n\n\tvar op string\n\n\tswitch parts[1] {\n\tcase \">=\", \"<=\", \">\", \"<\", \"\", \"==\":\n\t\top = parts[1]\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown binary operator %s\", parts[1])\n\t}\n\n\tsize, err := humanize.ParseBytes(strings.TrimSpace(parts[2]))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse disk size %s: %s\", parts[2], err)\n\t}\n\n\tm.MatchData = InstallDiskSizeMatchData{\n\t\tOp:   op,\n\t\tSize: size,\n\t}\n\n\treturn nil\n}\n\n// InstallDiskSizeMatchData contains data for comparison - Op and Size.\n//\n//docgen:nodoc\ntype InstallDiskSizeMatchData struct {\n\tOp   string\n\tSize uint64\n}\n\n// InstallDiskType custom type for disk type selector.\ntype InstallDiskType string\n\n// InstallDiskSelector represents a disk query parameters for the install disk lookup.\ntype InstallDiskSelector struct {\n\t//   description: Disk size.\n\t//   examples:\n\t//     - name: Select a disk which size is equal to 4GB.\n\t//       value: machineInstallDiskSizeMatcherExamples0()\n\t//     - name: Select a disk which size is greater than 1TB.\n\t//       value: machineInstallDiskSizeMatcherExamples1()\n\t//     - name: Select a disk which size is less or equal than 2TB.\n\t//       value: machineInstallDiskSizeMatcherExamples2()\n\t//   schema:\n\t//     type: string\n\tSize *InstallDiskSizeMatcher `yaml:\"size,omitempty\"`\n\t//   description: Disk name `/sys/block/<dev>/device/name`.\n\tName string `yaml:\"name,omitempty\"`\n\t//   description: Disk model `/sys/block/<dev>/device/model`.\n\tModel string `yaml:\"model,omitempty\"`\n\t//   description: Disk serial number `/sys/block/<dev>/serial`.\n\tSerial string `yaml:\"serial,omitempty\"`\n\t//   description: Disk modalias `/sys/block/<dev>/device/modalias`.\n\tModalias string `yaml:\"modalias,omitempty\"`\n\t//   description: Disk UUID `/sys/block/<dev>/uuid`.\n\tUUID string `yaml:\"uuid,omitempty\"`\n\t//   description: Disk WWID `/sys/block/<dev>/wwid`.\n\tWWID string `yaml:\"wwid,omitempty\"`\n\t//   description: Disk Type.\n\t//   values:\n\t//     - ssd\n\t//     - hdd\n\t//     - nvme\n\t//     - sd\n\tType InstallDiskType `yaml:\"type,omitempty\"`\n\t//   description: |\n\t//      Disk bus path.\n\t//   examples:\n\t//     - value: '\"/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0\"'\n\t//     - value: '\"/pci0000:00/*\"'\n\tBusPath string `yaml:\"busPath,omitempty\"`\n}\n\n// InstallExtensionConfig represents a configuration for a system extension.\n//\n// docgen:nodoc\ntype InstallExtensionConfig struct {\n\t//   description: System extension image.\n\tExtensionImage string `yaml:\"image\"`\n}\n\n// TimeConfig represents the options for configuring time on a machine.\n//\n//docgen:nodoc\ntype TimeConfig struct {\n\t//   description: |\n\t//     Indicates if the time service is disabled for the machine.\n\t//     Defaults to `false`.\n\tTimeDisabled *bool `yaml:\"disabled,omitempty\"`\n\t//   description: |\n\t//     Specifies time (NTP) servers to use for setting the system time.\n\t//     Defaults to `time.cloudflare.com`.\n\t//\n\t//\t   Talos can also sync to the PTP time source (e.g provided by the hypervisor),\n\t//     provide the path to the PTP device as \"/dev/ptp0\" or \"/dev/ptp_kvm\".\n\tTimeServers []string `yaml:\"servers,omitempty\"`\n\t//   description: |\n\t//     Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\n\t//     NTP sync will be still running in the background.\n\t//     Defaults to \"infinity\" (waiting forever for time sync)\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tTimeBootTimeout time.Duration `yaml:\"bootTimeout,omitempty\"`\n}\n\n// RegistriesConfig represents the image pull options.\n//\n// docgen:nodoc\ntype RegistriesConfig struct {\n\t//   description: |\n\t//     Specifies mirror configuration for each registry host namespace.\n\t//     This setting allows to configure local pull-through caching registires,\n\t//     air-gapped installations, etc.\n\t//\n\t//     For example, when pulling an image with the reference `example.com:123/image:v1`,\n\t//     the `example.com:123` key will be used to lookup the mirror configuration.\n\t//\n\t//     Optionally the `*` key can be used to configure a fallback mirror.\n\t//\n\t//     Registry name is the first segment of image identifier, with 'docker.io'\n\t//     being default one.\n\tRegistryMirrors map[string]*RegistryMirrorConfig `yaml:\"mirrors,omitempty\"`\n\t//   description: |\n\t//     Specifies TLS & auth configuration for HTTPS image registries.\n\t//     Mutual TLS can be enabled with 'clientIdentity' option.\n\t//\n\t//     The full hostname and port (if not using a default port 443)\n\t//     should be used as the key.\n\t//     The fallback key `*` can't be used for TLS configuration.\n\t//\n\t//     TLS configuration can be skipped if registry has trusted\n\t//     server certificate.\n\tRegistryConfig map[string]*RegistryConfig `yaml:\"config,omitempty\"`\n}\n\n// PodCheckpointer represents the pod-checkpointer config values.\n//\n//docgen:nodoc\ntype PodCheckpointer struct {\n\t//   description: |\n\t//     The `image` field is an override to the default pod-checkpointer image.\n\tPodCheckpointerImage string `yaml:\"image,omitempty\"`\n}\n\n// CoreDNS represents the CoreDNS config values.\ntype CoreDNS struct {\n\t//   description: |\n\t//     Disable coredns deployment on cluster bootstrap.\n\tCoreDNSDisabled *bool `yaml:\"disabled,omitempty\"`\n\t//   description: |\n\t//     The `image` field is an override to the default coredns image.\n\tCoreDNSImage string `yaml:\"image,omitempty\"`\n}\n\n// Endpoint represents the endpoint URL parsed out of the machine config.\ntype Endpoint struct {\n\t*url.URL\n}\n\n// UnmarshalYAML is a custom unmarshaller for `Endpoint`.\nfunc (e *Endpoint) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar endpoint string\n\n\tif err := unmarshal(&endpoint); err != nil {\n\t\treturn err\n\t}\n\n\turl, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*e = Endpoint{url}\n\n\treturn nil\n}\n\n// MarshalYAML is a custom marshaller for `Endpoint`.\nfunc (e *Endpoint) MarshalYAML() (any, error) {\n\treturn e.URL.String(), nil\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (e *Endpoint) DeepCopyInto(out *Endpoint) {\n\t*out = *e\n\n\tif e.URL != nil {\n\t\tin, out := &e.URL, &out.URL\n\t\t*out = new(url.URL)\n\t\t*out = *in\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint.\nfunc (e *Endpoint) DeepCopy() *Endpoint {\n\tif e == nil {\n\t\treturn nil\n\t}\n\n\tout := new(Endpoint)\n\te.DeepCopyInto(out)\n\n\treturn out\n}\n\n// ControlPlaneConfig represents the control plane configuration options.\ntype ControlPlaneConfig struct {\n\t//   description: |\n\t//     Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n\t//     It is single-valued, and may optionally include a port number.\n\t//   examples:\n\t//     - value: clusterEndpointExample1()\n\t//     - value: clusterEndpointExample2()\n\t//   schema:\n\t//     type: string\n\t//     format: uri\n\t//     pattern: \"^https://\"\n\tEndpoint *Endpoint `yaml:\"endpoint\"`\n\t//   description: |\n\t//     The port that the API server listens on internally.\n\t//     This may be different than the port portion listed in the endpoint field above.\n\t//     The default is `6443`.\n\tLocalAPIServerPort int `yaml:\"localAPIServerPort,omitempty\"`\n}\n\nvar _ config.APIServer = (*APIServerConfig)(nil)\n\n// APIServerConfig represents the kube apiserver configuration options.\ntype APIServerConfig struct {\n\t//   description: |\n\t//     The container image used in the API server manifest.\n\t//   examples:\n\t//     - value: clusterAPIServerImageExample()\n\tContainerImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     Extra arguments to supply to the API server.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tExtraArgsConfig Args `yaml:\"extraArgs,omitempty\"`\n\t//   description: |\n\t//     Extra volumes to mount to the API server static pod.\n\tExtraVolumesConfig []VolumeMountConfig `yaml:\"extraVolumes,omitempty\"`\n\t//   description: |\n\t//     The `env` field allows for the addition of environment variables for the control plane component.\n\t//   schema:\n\t//     type: object\n\t//     patternProperties:\n\t//       \".*\":\n\t//         type: string\n\tEnvConfig Env `yaml:\"env,omitempty\"`\n\t//   description: |\n\t//     Extra certificate subject alternative names for the API server's certificate.\n\tCertSANs []string `yaml:\"certSANs,omitempty\"`\n\t// docgen:nodoc\n\tDisablePodSecurityPolicyConfig *bool `yaml:\"disablePodSecurityPolicy,omitempty\"`\n\t//   description: |\n\t//     Configure the API server admission plugins.\n\t//   examples:\n\t//     - value: admissionControlConfigExample()\n\tAdmissionControlConfig AdmissionPluginConfigList `yaml:\"admissionControl,omitempty\"`\n\t//   description: |\n\t//     Configure the API server audit policy.\n\t//   examples:\n\t//     - value: APIServerDefaultAuditPolicy\n\t//   schema:\n\t//     type: object\n\tAuditPolicyConfig Unstructured `yaml:\"auditPolicy,omitempty\" merge:\"replace\"`\n\t//   description: |\n\t//     Configure the API server resources.\n\t//   schema:\n\t//     type: object\n\tResourcesConfig *ResourcesConfig `yaml:\"resources,omitempty\"`\n\t//   description: |\n\t//     Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\n\t//   examples:\n\t//     - value: authorizationConfigExample()\n\tAuthorizationConfigConfig AuthorizationConfigAuthorizerConfigList `yaml:\"authorizationConfig,omitempty\"`\n}\n\n// AdmissionPluginConfigList represents the admission plugin configuration list.\n//\n//docgen:alias\ntype AdmissionPluginConfigList []*AdmissionPluginConfig\n\n// Merge the admission plugin configuration intelligently.\nfunc (configs *AdmissionPluginConfigList) Merge(other any) error {\n\totherConfigs, ok := other.(AdmissionPluginConfigList)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for device merge %T\", other)\n\t}\n\n\tfor _, config := range otherConfigs {\n\t\tif err := configs.mergeConfig(config); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (configs *AdmissionPluginConfigList) mergeConfig(config *AdmissionPluginConfig) error {\n\tvar existing *AdmissionPluginConfig\n\n\tfor _, c := range *configs {\n\t\tif c.PluginName == config.PluginName {\n\t\t\texisting = c\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif existing != nil {\n\t\treturn merge.Merge(existing, config)\n\t}\n\n\t*configs = append(*configs, config)\n\n\treturn nil\n}\n\n// AdmissionPluginConfig represents the API server admission plugin configuration.\ntype AdmissionPluginConfig struct {\n\t//   description: |\n\t//     Name is the name of the admission controller.\n\t//     It must match the registered admission plugin name.\n\tPluginName string `yaml:\"name\"`\n\t//   description: |\n\t//     Configuration is an embedded configuration object to be used as the plugin's\n\t//     configuration.\n\t//   schema:\n\t//     type: object\n\tPluginConfiguration Unstructured `yaml:\"configuration\"`\n}\n\n// AuthorizationConfigAuthorizerConfigList represents the authorization config authorizer configuration list.\n//\n//docgen:alias\ntype AuthorizationConfigAuthorizerConfigList []*AuthorizationConfigAuthorizerConfig\n\n// AuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\ntype AuthorizationConfigAuthorizerConfig struct {\n\t//   description: |\n\t//     Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n\tAuthorizerType string `yaml:\"type\"`\n\t//   description: |\n\t//     Name is used to describe the authorizer.\n\tAuthorizerName string `yaml:\"name\"`\n\t//   description: |\n\t//     webhook is the configuration for the webhook authorizer.\n\t//   schema:\n\t//     type: object\n\tAuthorizerWebhook Unstructured `yaml:\"webhook,omitempty\"`\n}\n\nvar _ config.ControllerManager = (*ControllerManagerConfig)(nil)\n\n// ControllerManagerConfig represents the kube controller manager configuration options.\ntype ControllerManagerConfig struct {\n\t//   description: |\n\t//     The container image used in the controller manager manifest.\n\t//   examples:\n\t//     - value: clusterControllerManagerImageExample()\n\tContainerImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     Extra arguments to supply to the controller manager.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tExtraArgsConfig Args `yaml:\"extraArgs,omitempty\"`\n\t//   description: |\n\t//     Extra volumes to mount to the controller manager static pod.\n\tExtraVolumesConfig []VolumeMountConfig `yaml:\"extraVolumes,omitempty\"`\n\t//   description: |\n\t//     The `env` field allows for the addition of environment variables for the control plane component.\n\t//   schema:\n\t//     type: object\n\t//     patternProperties:\n\t//       \".*\":\n\t//         type: string\n\tEnvConfig Env `yaml:\"env,omitempty\"`\n\t//   description: |\n\t//     Configure the controller manager resources.\n\t//   schema:\n\t//     type: object\n\tResourcesConfig *ResourcesConfig `yaml:\"resources,omitempty\"`\n}\n\n// ProxyConfig represents the kube proxy configuration options.\ntype ProxyConfig struct {\n\t//   description: |\n\t//     Disable kube-proxy deployment on cluster bootstrap.\n\t//   examples:\n\t//     - value: new(false)\n\tDisabled *bool `yaml:\"disabled,omitempty\"`\n\t//   description: |\n\t//     The container image used in the kube-proxy manifest.\n\t//   examples:\n\t//     - value: clusterProxyImageExample()\n\tContainerImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     proxy mode of kube-proxy.\n\t//     The default is 'iptables'.\n\tModeConfig string `yaml:\"mode,omitempty\"`\n\t//   description: |\n\t//     Extra arguments to supply to kube-proxy.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tExtraArgsConfig Args `yaml:\"extraArgs,omitempty\"`\n}\n\nvar _ config.Scheduler = (*SchedulerConfig)(nil)\n\n// SchedulerConfig represents the kube scheduler configuration options.\ntype SchedulerConfig struct {\n\t//   description: |\n\t//     The container image used in the scheduler manifest.\n\t//   examples:\n\t//     - value: clusterSchedulerImageExample()\n\tContainerImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     Extra arguments to supply to the scheduler.\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tExtraArgsConfig Args `yaml:\"extraArgs,omitempty\"`\n\t//   description: |\n\t//     Extra volumes to mount to the scheduler static pod.\n\tExtraVolumesConfig []VolumeMountConfig `yaml:\"extraVolumes,omitempty\"`\n\t//   description: |\n\t//     The `env` field allows for the addition of environment variables for the control plane component.\n\t//   schema:\n\t//     type: object\n\t//     patternProperties:\n\t//       \".*\":\n\t//         type: string\n\tEnvConfig Env `yaml:\"env,omitempty\"`\n\t//   description: |\n\t//     Configure the scheduler resources.\n\t//   schema:\n\t//     type: object\n\tResourcesConfig *ResourcesConfig `yaml:\"resources,omitempty\"`\n\t//   description: |\n\t//     Specify custom kube-scheduler configuration.\n\t//   schema:\n\t//     type: object\n\tSchedulerConfig Unstructured `yaml:\"config,omitempty\"`\n}\n\nvar _ config.Etcd = (*EtcdConfig)(nil)\n\n// EtcdConfig represents the etcd configuration options.\ntype EtcdConfig struct {\n\t//   description: |\n\t//     The container image used to create the etcd service.\n\t//   examples:\n\t//     - value: clusterEtcdImageExample()\n\tContainerImage string `yaml:\"image,omitempty\"`\n\t//   description: |\n\t//     The `ca` is the root certificate authority of the PKI.\n\t//     It is composed of a base64 encoded `crt` and `key`.\n\t//   examples:\n\t//     - value: pemEncodedCertificateExample()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tRootCA *x509.PEMEncodedCertificateAndKey `yaml:\"ca\"`\n\t//   description: |\n\t//     Extra arguments to supply to etcd.\n\t//     Note that the following args are not allowed:\n\t//\n\t//     - `name`\n\t//     - `data-dir`\n\t//     - `initial-cluster-state`\n\t//     - `listen-peer-urls`\n\t//     - `listen-client-urls`\n\t//     - `cert-file`\n\t//     - `key-file`\n\t//     - `trusted-ca-file`\n\t//     - `peer-client-cert-auth`\n\t//     - `peer-cert-file`\n\t//     - `peer-trusted-ca-file`\n\t//     - `peer-key-file`\n\t//   examples:\n\t//     - values: >\n\t//         Args{\n\t//           \"initial-cluster\": ArgValue{strValue: \"https://1.2.3.4:2380\"},\n\t//           \"advertise-client-urls\": ArgValue{strValue: \"https://1.2.3.4:2379\"},\n\t//         }\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties:\n\t//       oneOf:\n\t//         - type: string\n\t//         - type: array\n\t//           items:\n\t//             type: string\n\tEtcdExtraArgs Args `yaml:\"extraArgs,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: use EtcdAdvertistedSubnets\n\tEtcdSubnet string `yaml:\"subnet,omitempty\"`\n\t//  description: |\n\t//    The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\n\t//\n\t//    IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\n\t//    Negative subnet matches should be specified last to filter out IPs picked by positive matches.\n\t//    If not specified, advertised IP is selected as the first routable address of the node.\n\t//\n\t//  examples:\n\t//    - value: clusterEtcdAdvertisedSubnetsExample()\n\tEtcdAdvertisedSubnets []string `yaml:\"advertisedSubnets,omitempty\"`\n\t//  description: |\n\t//    The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\n\t//\n\t//    If `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\n\t//    `advertisedSubnets`.\n\t//\n\t//    If neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\n\t//\n\t//    IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\n\t//    Negative subnet matches should be specified last to filter out IPs picked by positive matches.\n\t//    If not specified, advertised IP is selected as the first routable address of the node.\n\tEtcdListenSubnets []string `yaml:\"listenSubnets,omitempty\"`\n}\n\n// ClusterNetworkConfig represents kube networking configuration options.\ntype ClusterNetworkConfig struct {\n\t//   description: |\n\t//     The CNI used.\n\t//     Composed of \"name\" and \"urls\".\n\t//     The \"name\" key supports the following options: \"flannel\", \"custom\", and \"none\".\n\t//     \"flannel\" uses Talos-managed Flannel CNI, and that's the default option.\n\t//     \"custom\" uses custom manifests that should be provided in \"urls\".\n\t//     \"none\" indicates that Talos will not manage any CNI installation.\n\t//   examples:\n\t//     - value: clusterCustomCNIExample()\n\tCNI *CNIConfig `yaml:\"cni,omitempty\"`\n\t//   description: |\n\t//     The domain used by Kubernetes DNS.\n\t//     The default is `cluster.local`\n\t//   examples:\n\t//     - value: '\"cluster.local\"'\n\tDNSDomain string `yaml:\"dnsDomain\"`\n\t//   description: |\n\t//     The pod subnet CIDR.\n\t//   examples:\n\t//     -  value: >\n\t//          []string{\"10.244.0.0/16\"}\n\tPodSubnet []string `yaml:\"podSubnets\" merge:\"replace\"`\n\t//   description: |\n\t//     The service subnet CIDR.\n\t//   examples:\n\t//     -  value: >\n\t//          []string{\"10.96.0.0/12\"}\n\tServiceSubnet []string `yaml:\"serviceSubnets\" merge:\"replace\"`\n}\n\n// CNIConfig represents the CNI configuration options.\ntype CNIConfig struct {\n\t//   description: |\n\t//     Name of CNI to use.\n\t//   values:\n\t//     - flannel\n\t//     - custom\n\t//     - none\n\tCNIName string `yaml:\"name,omitempty\"`\n\t//   description: |\n\t//     URLs containing manifests to apply for the CNI.\n\t//     Should be present for \"custom\", must be empty for \"flannel\" and \"none\".\n\tCNIUrls []string `yaml:\"urls,omitempty\"`\n\t//   description: |\n\t//\t\tFlannel configuration options.\n\tCNIFlannel *FlannelCNIConfig `yaml:\"flannel,omitempty\"`\n}\n\n// FlannelCNIConfig represents the Flannel CNI configuration options.\ntype FlannelCNIConfig struct {\n\t//   description: |\n\t//     Extra arguments for 'flanneld'.\n\t//   examples:\n\t//     - value: >\n\t//         []string{\"--iface-can-reach=192.168.1.1\"}\n\tFlanneldExtraArgs []string `yaml:\"extraArgs,omitempty\"`\n\t//   description: |\n\t//     Deploys kube-network-policies along with Flannel.\n\t//\n\t//     This enables Kubernetes Network Policies support in the cluster.\n\tFlannelKubeNetworkPoliciesEnabled *bool `yaml:\"kubeNetworkPoliciesEnabled,omitempty\"`\n}\n\nvar _ config.ExternalCloudProvider = (*ExternalCloudProviderConfig)(nil)\n\n// ExternalCloudProviderConfig contains external cloud provider configuration.\ntype ExternalCloudProviderConfig struct {\n\t//   description: |\n\t//     Enable external cloud provider.\n\t//   values:\n\t//     - true\n\t//     - yes\n\t//     - false\n\t//     - no\n\tExternalEnabled *bool `yaml:\"enabled,omitempty\"`\n\t//   description: |\n\t//     A list of urls that point to additional manifests for an external cloud provider.\n\t//     These will get automatically deployed as part of the bootstrap.\n\t//   examples:\n\t//     - value: >\n\t//        []string{\n\t//         \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t//         \"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t//        }\n\tExternalManifests []string `yaml:\"manifests,omitempty\"`\n}\n\n// AdminKubeconfigConfig contains admin kubeconfig settings.\ntype AdminKubeconfigConfig struct {\n\t//   description: |\n\t//     Admin kubeconfig certificate lifetime (default is 1 year).\n\t//     Field format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tAdminKubeconfigCertLifetime time.Duration `yaml:\"certLifetime,omitempty\"`\n}\n\n// MachineDisk represents the options available for partitioning, formatting, and\n// mounting extra disks.\n//\n// docgen:nodoc\ntype MachineDisk struct {\n\t//   description: The name of the disk to use.\n\tDeviceName string `yaml:\"device,omitempty\"`\n\t//   description: A list of partitions to create on the disk.\n\tDiskPartitions []*DiskPartition `yaml:\"partitions,omitempty\"`\n}\n\n// DiskSize partition size in bytes.\n//\n// docgen:nodoc\ntype DiskSize uint64\n\n// MarshalYAML write as human readable string.\nfunc (ds DiskSize) MarshalYAML() (any, error) {\n\tif ds%DiskSize(1000) == 0 {\n\t\tbytesString := humanize.Bytes(uint64(ds))\n\t\t// ensure that stringifying bytes as human readable string\n\t\t// doesn't lose precision\n\t\tparsed, err := humanize.ParseBytes(bytesString)\n\t\tif err == nil && parsed == uint64(ds) {\n\t\t\treturn bytesString, nil\n\t\t}\n\t}\n\n\treturn uint64(ds), nil\n}\n\n// UnmarshalYAML read from human readable string.\nfunc (ds *DiskSize) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar size string\n\n\tif err := unmarshal(&size); err != nil {\n\t\treturn err\n\t}\n\n\ts, err := humanize.ParseBytes(size)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*ds = DiskSize(s)\n\n\treturn nil\n}\n\n// DiskPartition represents the options for a disk partition.\n//\n// docgen:nodoc\ntype DiskPartition struct {\n\t//   description: >\n\t//     The size of partition: either bytes or human readable representation. If `size:`\n\t//     is omitted, the partition is sized to occupy the full disk.\n\t//   examples:\n\t//     - name: Human readable representation.\n\t//       value: DiskSize(100000000)\n\t//     - name: Precise value in bytes.\n\t//       value: 1024 * 1024 * 1024\n\t//   schema:\n\t//     type: integer\n\tDiskSize DiskSize `yaml:\"size,omitempty\"`\n\t//   description:\n\t//     Where to mount the partition.\n\tDiskMountPoint string `yaml:\"mountpoint,omitempty\"`\n}\n\n// EncryptionConfig represents partition encryption settings.\n//\n//docgen:nodoc\ntype EncryptionConfig struct {\n\t//   description: >\n\t//     Encryption provider to use for the encryption.\n\t//   examples:\n\t//     - value: '\"luks2\"'\n\tEncryptionProvider string `yaml:\"provider\"`\n\t//   description: >\n\t//     Defines the encryption keys generation and storage method.\n\tEncryptionKeys []*EncryptionKey `yaml:\"keys\"`\n\t//   description: >\n\t//     Cipher kind to use for the encryption.\n\t//     Depends on the encryption provider.\n\t//   values:\n\t//     - aes-xts-plain64\n\t//     - xchacha12,aes-adiantum-plain64\n\t//     - xchacha20,aes-adiantum-plain64\n\t//   examples:\n\t//     - value: '\"aes-xts-plain64\"'\n\tEncryptionCipher string `yaml:\"cipher,omitempty\"`\n\t//   description: >\n\t//     Defines the encryption key length.\n\tEncryptionKeySize uint `yaml:\"keySize,omitempty\"`\n\t//   description: >\n\t//     Defines the encryption sector size.\n\t//   examples:\n\t//     - value: '4096'\n\tEncryptionBlockSize uint64 `yaml:\"blockSize,omitempty\"`\n\t//   description: >\n\t//     Additional --perf parameters for the LUKS2 encryption.\n\t//   values:\n\t//     - no_read_workqueue\n\t//     - no_write_workqueue\n\t//     - same_cpu_crypt\n\t//   examples:\n\t//     -  value: >\n\t//          []string{\"no_read_workqueue\",\"no_write_workqueue\"}\n\tEncryptionPerfOptions []string `yaml:\"options,omitempty\"`\n}\n\n// EncryptionKey represents configuration for disk encryption key.\n//\n//docgen:nodoc\ntype EncryptionKey struct {\n\t//   description: >\n\t//     Key which value is stored in the configuration file.\n\tKeyStatic *EncryptionKeyStatic `yaml:\"static,omitempty\"`\n\t//   description: >\n\t//     Deterministically generated key from the node UUID and PartitionLabel.\n\tKeyNodeID *EncryptionKeyNodeID `yaml:\"nodeID,omitempty\"`\n\t//   description: >\n\t//     KMS managed encryption key.\n\t//   examples:\n\t//     - value: kmsKeyExample()\n\tKeyKMS *EncryptionKeyKMS `yaml:\"kms,omitempty\"`\n\t//   description: >\n\t//     Key slot number for LUKS2 encryption.\n\tKeySlot int `yaml:\"slot\"`\n\t//   description: >\n\t//     Enable TPM based disk encryption.\n\tKeyTPM *EncryptionKeyTPM `yaml:\"tpm,omitempty\"`\n}\n\n// EncryptionKeyStatic represents throw away key type.\n//\n//docgen:nodoc\ntype EncryptionKeyStatic struct {\n\t//   description: >\n\t//     Defines the static passphrase value.\n\tKeyData string `yaml:\"passphrase,omitempty\"`\n}\n\n// EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n//\n//docgen:nodoc\ntype EncryptionKeyKMS struct {\n\t//   description: >\n\t//     KMS endpoint to Seal/Unseal the key.\n\tKMSEndpoint string `yaml:\"endpoint\"`\n}\n\n// EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\n//\n//docgen:nodoc\ntype EncryptionKeyTPM struct {\n\t//   description: >\n\t//     Check that Secureboot is enabled in the EFI firmware.\n\t//\n\t//     If Secureboot is not enabled, the enrollment of the key will fail.\n\t//     As the TPM key is anyways bound to the value of PCR 7,\n\t//     changing Secureboot status or configuration\n\t//     after the initial enrollment will make the key unusable.\n\tTPMCheckSecurebootStatusOnEnroll *bool `yaml:\"checkSecurebootStatusOnEnroll,omitempty\"`\n}\n\n// EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\n//\n//docgen:nodoc\ntype EncryptionKeyNodeID struct{}\n\n// Env represents a set of environment variables.\n//\n//docgen:nodoc\ntype Env = map[string]string\n\n// ResourcesConfig represents the pod resources.\ntype ResourcesConfig struct {\n\t//   description: |\n\t//     Requests configures the reserved cpu/memory resources.\n\t//   examples:\n\t//     - name: resources requests.\n\t//       value: resourcesConfigRequestsExample()\n\t//   schema:\n\t//     type: object\n\tRequests Unstructured `yaml:\"requests,omitempty\"`\n\t//   description: |\n\t//     Limits configures the maximum cpu/memory resources a container can use.\n\t//   examples:\n\t//     - name: resources requests.\n\t//       value: resourcesConfigLimitsExample()\n\t//   schema:\n\t//     type: object\n\tLimits Unstructured `yaml:\"limits,omitempty\"`\n}\n\n// FileMode represents file's permissions.\ntype FileMode os.FileMode\n\n// String convert file mode to octal string.\nfunc (fm FileMode) String() string {\n\treturn \"0o\" + strconv.FormatUint(uint64(fm), 8)\n}\n\n// MarshalYAML encodes as an octal value.\nfunc (fm FileMode) MarshalYAML() (any, error) {\n\treturn &yaml.Node{\n\t\tKind:  yaml.ScalarNode,\n\t\tTag:   \"!!int\",\n\t\tValue: fm.String(),\n\t}, nil\n}\n\n// MachineFile represents a file to write to disk.\ntype MachineFile struct {\n\t//   description: The contents of the file.\n\tFileContent string `yaml:\"content\"`\n\t//   description: The file's permissions in octal.\n\t//   schema:\n\t//     type: integer\n\tFilePermissions FileMode `yaml:\"permissions\"`\n\t//   description: The path of the file.\n\tFilePath string `yaml:\"path\"`\n\t//   description: The operation to use\n\t//   values:\n\t//     - create\n\t//     - append\n\t//     - overwrite\n\tFileOp string `yaml:\"op\"`\n}\n\n// ExtraHost represents a host entry in /etc/hosts.\n//\n// docgen:nodoc\ntype ExtraHost struct {\n\t//   description: The IP of the host.\n\tHostIP string `yaml:\"ip\"`\n\t//   description: The host alias.\n\tHostAliases []string `yaml:\"aliases\"`\n}\n\n// Device represents a network interface.\n//\n// docgen:nodoc\ntype Device struct {\n\t//   description: |\n\t//     The interface name.\n\t//     Mutually exclusive with `deviceSelector`.\n\t//   examples:\n\t//     - value: '\"enp0s3\"'\n\tDeviceInterface string `yaml:\"interface,omitempty\"`\n\t//   description: |\n\t//     Picks a network device using the selector.\n\t//     Mutually exclusive with `interface`.\n\t//     Supports partial match using wildcard syntax.\n\t//   examples:\n\t//     - name: select a device with bus prefix 00:*.\n\t//       value: networkDeviceSelectorExamples()[0]\n\t//     - name: select a device with mac address matching `*:f0:ab` and `virtio` kernel driver.\n\t//       value: networkDeviceSelectorExamples()[1]\n\tDeviceSelector *NetworkDeviceSelector `yaml:\"deviceSelector,omitempty\"`\n\t//   description: |\n\t//     Assigns static IP addresses to the interface.\n\t//     An address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\n\t//   examples:\n\t//     - value: '[]string{\"10.5.0.0/16\", \"192.168.3.7\"}'\n\tDeviceAddresses []string `yaml:\"addresses,omitempty\"`\n\t// docgen:nodoc\n\tDeviceCIDR string `yaml:\"cidr,omitempty\"`\n\t//   description: |\n\t//     A list of routes associated with the interface.\n\t//     If used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\n\t//   examples:\n\t//     - value: networkConfigRoutesExample()\n\tDeviceRoutes []*Route `yaml:\"routes,omitempty\"`\n\t//   description: Bond specific options.\n\t//   examples:\n\t//     - value: networkConfigBondExample()\n\tDeviceBond *Bond `yaml:\"bond,omitempty\"`\n\t//   description: Bridge specific options.\n\t//   examples:\n\t//     - value: networkConfigBridgeExample()\n\tDeviceBridge *Bridge `yaml:\"bridge,omitempty\"`\n\t//   description: |\n\t//     Configure this device as a bridge port.\n\t//     This can be used to dynamically assign network interfaces to a bridge.\n\t//   examples:\n\t//     - value: networkConfigDynamicBridgePortsExample()\n\tDeviceBridgePort *BridgePort `yaml:\"bridgePort,omitempty\"`\n\t//   description: VLAN specific options.\n\tDeviceVlans VlanList `yaml:\"vlans,omitempty\"`\n\t//   description: |\n\t//     The interface's MTU.\n\t//     If used in combination with DHCP, this will override any MTU settings returned from DHCP server.\n\tDeviceMTU int `yaml:\"mtu,omitempty\"`\n\t//   description: |\n\t//     Indicates if DHCP should be used to configure the interface.\n\t//     The following DHCP options are supported:\n\t//\n\t//     - `OptionClasslessStaticRoute`\n\t//     - `OptionDomainNameServer`\n\t//     - `OptionDNSDomainSearchList`\n\t//     - `OptionHostName`\n\t//\n\t//   examples:\n\t//     - value: true\n\tDeviceDHCP *bool `yaml:\"dhcp,omitempty\"`\n\t//   description: Indicates if the interface should be ignored (skips configuration).\n\tDeviceIgnore *bool `yaml:\"ignore,omitempty\"`\n\t//   description: |\n\t//     Indicates if the interface is a dummy interface.\n\t//     `dummy` is used to specify that this interface should be a virtual-only, dummy interface.\n\tDeviceDummy *bool `yaml:\"dummy,omitempty\"`\n\t//   description: |\n\t//     DHCP specific options.\n\t//     `dhcp` *must* be set to true for these to take effect.\n\t//   examples:\n\t//     - value: networkConfigDHCPOptionsExample()\n\tDeviceDHCPOptions *DHCPOptions `yaml:\"dhcpOptions,omitempty\"`\n\t//   description: |\n\t//     Wireguard specific configuration.\n\t//     Includes things like private key, listen port, peers.\n\t//   examples:\n\t//     - name: wireguard server example\n\t//       value: networkConfigWireguardHostExample()\n\t//     - name: wireguard peer example\n\t//       value: networkConfigWireguardPeerExample()\n\tDeviceWireguardConfig *DeviceWireguardConfig `yaml:\"wireguard,omitempty\"`\n\t//   description: Virtual (shared) IP address configuration.\n\t//   examples:\n\t//     - name: layer2 vip example\n\t//       value: networkConfigVIPLayer2Example()\n\tDeviceVIPConfig *DeviceVIPConfig `yaml:\"vip,omitempty\"`\n}\n\n// DHCPOptions contains options for configuring the DHCP settings for a given interface.\n//\n// docgen:nodoc\ntype DHCPOptions struct {\n\t//   description: The priority of all routes received via DHCP.\n\tDHCPRouteMetric uint32 `yaml:\"routeMetric\"`\n\t//   description: Enables DHCPv4 protocol for the interface (default is enabled).\n\tDHCPIPv4 *bool `yaml:\"ipv4,omitempty\"`\n\t//   description: Enables DHCPv6 protocol for the interface (default is disabled).\n\tDHCPIPv6 *bool `yaml:\"ipv6,omitempty\"`\n\t//   description: Set client DUID (hex string).\n\tDHCPDUIDv6 string `yaml:\"duidv6,omitempty\"`\n}\n\n// DeviceWireguardConfig contains settings for configuring Wireguard network interface.\n//\n// docgen:nodoc\ntype DeviceWireguardConfig struct {\n\t//   description: |\n\t//     Specifies a private key configuration (base64 encoded).\n\t//     Can be generated by `wg genkey`.\n\tWireguardPrivateKey string `yaml:\"privateKey,omitempty\"`\n\t//   description: Specifies a device's listening port.\n\tWireguardListenPort int `yaml:\"listenPort,omitempty\"`\n\t//   description: Specifies a device's firewall mark.\n\tWireguardFirewallMark int `yaml:\"firewallMark,omitempty\"`\n\t//   description: Specifies a list of peer configurations to apply to a device.\n\tWireguardPeers []*DeviceWireguardPeer `yaml:\"peers,omitempty\"`\n}\n\n// DeviceWireguardPeer a WireGuard device peer configuration.\n//\n// docgen:nodoc\ntype DeviceWireguardPeer struct {\n\t//   description: |\n\t//     Specifies the public key of this peer.\n\t//     Can be extracted from private key by running `wg pubkey < private.key > public.key && cat public.key`.\n\tWireguardPublicKey string `yaml:\"publicKey,omitempty\"`\n\t//   description: Specifies the endpoint of this peer entry.\n\tWireguardEndpoint string `yaml:\"endpoint,omitempty\"`\n\t//   description: |\n\t//     Specifies the persistent keepalive interval for this peer.\n\t//     Field format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\n\t//   schema:\n\t//     type: string\n\t//     pattern: ^[-+]?(((\\d+(\\.\\d*)?|\\d*(\\.\\d+)+)([nuµm]?s|m|h))|0)+$\n\tWireguardPersistentKeepaliveInterval time.Duration `yaml:\"persistentKeepaliveInterval,omitempty\"`\n\t//   description: AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n\tWireguardAllowedIPs []string `yaml:\"allowedIPs,omitempty\"`\n}\n\n// DeviceVIPConfig contains settings for configuring a Virtual Shared IP on an interface.\n//\n// docgen:nodoc\ntype DeviceVIPConfig struct {\n\t// description: Specifies the IP address to be used.\n\tSharedIP string `yaml:\"ip,omitempty\"`\n\t// description: Specifies the Equinix Metal API settings to assign VIP to the node.\n\tEquinixMetalConfig *VIPEquinixMetalConfig `yaml:\"equinixMetal,omitempty\"`\n\t// description: Specifies the Hetzner Cloud API settings to assign VIP to the node.\n\tHCloudConfig *VIPHCloudConfig `yaml:\"hcloud,omitempty\"`\n}\n\n// VIPEquinixMetalConfig contains settings for Equinix Metal VIP management.\n//\n// docgen:nodoc\ntype VIPEquinixMetalConfig struct {\n\t// description: Specifies the Equinix Metal API Token.\n\tEquinixMetalAPIToken string `yaml:\"apiToken\"`\n}\n\n// VIPHCloudConfig contains settings for Hetzner Cloud VIP management.\n//\n// docgen:nodoc\ntype VIPHCloudConfig struct {\n\t// description: Specifies the Hetzner Cloud API Token.\n\tHCloudAPIToken string `yaml:\"apiToken\"`\n}\n\n// Bond contains the various options for configuring a bonded interface.\n//\n// docgen:nodoc\ntype Bond struct {\n\t//   description: The interfaces that make up the bond.\n\tBondInterfaces []string `yaml:\"interfaces\"`\n\t//   description: |\n\t//     Picks a network device using the selector.\n\t//     Mutually exclusive with `interfaces`.\n\t//     Supports partial match using wildcard syntax.\n\t//   examples:\n\t//     - name: select a device with bus prefix 00:*, a device with mac address matching `*:f0:ab` and `virtio` kernel driver.\n\t//       value: networkDeviceSelectorExamples()\n\tBondDeviceSelectors []NetworkDeviceSelector `yaml:\"deviceSelectors,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\t//     Not supported at the moment.\n\tBondARPIPTarget []string `yaml:\"arpIPTarget,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondMode string `yaml:\"mode\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondHashPolicy string `yaml:\"xmitHashPolicy,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondLACPRate string `yaml:\"lacpRate,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\t//     Not supported at the moment.\n\tBondADActorSystem string `yaml:\"adActorSystem,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondARPValidate string `yaml:\"arpValidate,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondARPAllTargets string `yaml:\"arpAllTargets,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondPrimary string `yaml:\"primary,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondPrimaryReselect string `yaml:\"primaryReselect,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondFailOverMac string `yaml:\"failOverMac,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondADSelect string `yaml:\"adSelect,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondMIIMon uint32 `yaml:\"miimon,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondUpDelay uint32 `yaml:\"updelay,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondDownDelay uint32 `yaml:\"downdelay,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondARPInterval uint32 `yaml:\"arpInterval,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondResendIGMP uint32 `yaml:\"resendIgmp,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondMinLinks uint32 `yaml:\"minLinks,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondLPInterval uint32 `yaml:\"lpInterval,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondPacketsPerSlave uint32 `yaml:\"packetsPerSlave,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondNumPeerNotif uint8 `yaml:\"numPeerNotif,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondTLBDynamicLB uint8 `yaml:\"tlbDynamicLb,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondAllSlavesActive uint8 `yaml:\"allSlavesActive,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondUseCarrier *bool `yaml:\"useCarrier,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondADActorSysPrio uint16 `yaml:\"adActorSysPrio,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondADUserPortKey uint16 `yaml:\"adUserPortKey,omitempty\"`\n\t//   description: |\n\t//     A bond option.\n\t//     Please see the official kernel documentation.\n\tBondPeerNotifyDelay uint32 `yaml:\"peerNotifyDelay,omitempty\"`\n}\n\n// STP contains the various options for configuring the STP properties of a bridge interface.\n//\n// docgen:nodoc\ntype STP struct {\n\t//   description: Whether Spanning Tree Protocol (STP) is enabled.\n\tSTPEnabled *bool `yaml:\"enabled,omitempty\"`\n}\n\n// BridgeVLAN contains the various options for configuring the VLAN properties of a bridge interface.\n//\n// docgen:nodoc\ntype BridgeVLAN struct {\n\t//   description: Whether VLAN filtering is enabled.\n\tBridgeVLANFiltering *bool `yaml:\"vlanFiltering,omitempty\"`\n}\n\n// Bridge contains the various options for configuring a bridge interface.\n//\n// docgen:nodoc\ntype Bridge struct {\n\t//   description: The interfaces that make up the bridge.\n\tBridgedInterfaces []string `yaml:\"interfaces\"`\n\t//   description: |\n\t//     Enable STP on this bridge.\n\t//     Please see the official kernel documentation.\n\tBridgeSTP *STP `yaml:\"stp,omitempty\"`\n\t//   description: |\n\t//     Enable VLAN-awareness on this bridge.\n\t//     Please see the official kernel documentation.\n\tBridgeVLAN *BridgeVLAN `yaml:\"vlan,omitempty\"`\n}\n\n// BridgePort contains settings for assigning a link to a bridge interface.\n//\n// docgen:nodoc\ntype BridgePort struct {\n\t//   description: The name of the bridge master interface\n\tBridgePortMaster string `yaml:\"master,omitempty\"`\n}\n\n// VlanList is a list of *Vlan structures with overridden merge process.\n//\n// docgen:nodoc\ntype VlanList []*Vlan\n\n// Merge the network interface configuration intelligently.\nfunc (vlans *VlanList) Merge(other any) error {\n\totherVlans, ok := other.(VlanList)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for vlan merge %T\", other)\n\t}\n\n\tfor _, vlan := range otherVlans {\n\t\tif err := vlans.mergeVlan(vlan); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (vlans *VlanList) mergeVlan(vlan *Vlan) error {\n\tvar existing *Vlan\n\n\tfor _, v := range *vlans {\n\t\tif v.VlanID == vlan.VlanID {\n\t\t\texisting = v\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif existing != nil {\n\t\treturn merge.Merge(existing, vlan)\n\t}\n\n\t*vlans = append(*vlans, vlan)\n\n\treturn nil\n}\n\n// Vlan represents vlan settings for a device.\n//\n// docgen:nodoc\ntype Vlan struct {\n\t//   description: The addresses in CIDR notation or as plain IPs to use.\n\tVlanAddresses []string `yaml:\"addresses,omitempty\"`\n\t// docgen:nodoc\n\tVlanCIDR string `yaml:\"cidr,omitempty\"`\n\t//   description: A list of routes associated with the VLAN.\n\tVlanRoutes []*Route `yaml:\"routes\"`\n\t//   description: Indicates if DHCP should be used.\n\tVlanDHCP *bool `yaml:\"dhcp,omitempty\"`\n\t//   description: The VLAN's ID.\n\tVlanID uint16 `yaml:\"vlanId\"`\n\t//   description: The VLAN's MTU.\n\tVlanMTU uint32 `yaml:\"mtu,omitempty\"`\n\t//   description: The VLAN's virtual IP address configuration.\n\tVlanVIP *DeviceVIPConfig `yaml:\"vip,omitempty\"`\n\t//   description: |\n\t//     DHCP specific options.\n\t//     `dhcp` *must* be set to true for these to take effect.\n\tVlanDHCPOptions *DHCPOptions `yaml:\"dhcpOptions,omitempty\"`\n}\n\n// Route represents a network route.\n//\n// docgen:nodoc\ntype Route struct {\n\t//   description: The route's network (destination).\n\tRouteNetwork string `yaml:\"network\"`\n\t//   description: The route's gateway (if empty, creates link scope route).\n\tRouteGateway string `yaml:\"gateway\"`\n\t//   description: The route's source address (optional).\n\tRouteSource string `yaml:\"source,omitempty\"`\n\t//   description: The optional metric for the route.\n\tRouteMetric uint32 `yaml:\"metric,omitempty\"`\n\t//   description: The optional MTU for the route.\n\tRouteMTU uint32 `yaml:\"mtu,omitempty\"`\n}\n\n// RegistryMirrorConfig represents mirror configuration for a registry.\n//\n// docgen:nodoc\ntype RegistryMirrorConfig struct {\n\t//   description: |\n\t//     List of endpoints (URLs) for registry mirrors to use.\n\t//     Endpoint configures HTTP/HTTPS access mode, host name,\n\t//     port and path (if path is not set, it defaults to `/v2`).\n\tMirrorEndpoints []string `yaml:\"endpoints\"`\n\t//   description: |\n\t//     Use the exact path specified for the endpoint (don't append /v2/).\n\t//     This setting is often required for setting up multiple mirrors\n\t//     on a single instance of a registry.\n\tMirrorOverridePath *bool `yaml:\"overridePath,omitempty\"`\n\t//   description: |\n\t//     Skip fallback to the upstream endpoint, for example the mirror configuration\n\t//     for `docker.io` will not fallback to `registry-1.docker.io`.\n\tMirrorSkipFallback *bool `yaml:\"skipFallback,omitempty\"`\n}\n\n// RegistryConfig specifies auth & TLS config per registry.\n//\n// docgen:nodoc\ntype RegistryConfig struct {\n\t//   description: |\n\t//     The TLS configuration for the registry.\n\t//   examples:\n\t//     - value: machineConfigRegistryTLSConfigExample1()\n\t//     - value: machineConfigRegistryTLSConfigExample2()\n\tRegistryTLS *RegistryTLSConfig `yaml:\"tls,omitempty\"`\n\t//   description: |\n\t//     The auth configuration for this registry.\n\t//     Note: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\n\t//   examples:\n\t//     - value: machineConfigRegistryAuthConfigExample()\n\tRegistryAuth *RegistryAuthConfig `yaml:\"auth,omitempty\"`\n}\n\n// RegistryAuthConfig specifies authentication configuration for a registry.\n//\n// docgen:nodoc\ntype RegistryAuthConfig struct {\n\t//   description: |\n\t//     Optional registry authentication.\n\t//     The meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\n\tRegistryUsername string `yaml:\"username,omitempty\"`\n\t//   description: |\n\t//     Optional registry authentication.\n\t//     The meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\n\tRegistryPassword string `yaml:\"password,omitempty\"`\n\t//   description: |\n\t//     Optional registry authentication.\n\t//     The meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\n\tRegistryAuth string `yaml:\"auth,omitempty\"`\n\t//   description: |\n\t//     Optional registry authentication.\n\t//     The meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\n\tRegistryIdentityToken string `yaml:\"identityToken,omitempty\"`\n}\n\n// RegistryTLSConfig specifies TLS config for HTTPS registries.\n//\n// docgen:nodoc\ntype RegistryTLSConfig struct {\n\t//   description: |\n\t//     Enable mutual TLS authentication with the registry.\n\t//     Client certificate and key should be base64-encoded.\n\t//   examples:\n\t//     - value: pemEncodedCertificateExample()\n\t//   schema:\n\t//     type: object\n\t//     additionalProperties: false\n\t//     properties:\n\t//       crt:\n\t//         type: string\n\t//       key:\n\t//         type: string\n\tTLSClientIdentity *x509.PEMEncodedCertificateAndKey `yaml:\"clientIdentity,omitempty\"`\n\t//   description: |\n\t//     CA registry certificate to add the list of trusted certificates.\n\t//     Certificate should be base64-encoded.\n\t//   schema:\n\t//     type: string\n\tTLSCA Base64Bytes `yaml:\"ca,omitempty\"`\n\t//   description: |\n\t//     Skip TLS server certificate verification (not recommended).\n\tTLSInsecureSkipVerify *bool `yaml:\"insecureSkipVerify,omitempty\"`\n}\n\n// SystemDiskEncryptionConfig specifies system disk partitions encryption settings.\n//\n//docgen:nodoc\ntype SystemDiskEncryptionConfig struct {\n\t//   description: |\n\t//     State partition encryption.\n\tStatePartition *EncryptionConfig `yaml:\"state,omitempty\"`\n\t//   description: |\n\t//     Ephemeral partition encryption.\n\tEphemeralPartition *EncryptionConfig `yaml:\"ephemeral,omitempty\"`\n}\n\nvar _ config.Features = (*FeaturesConfig)(nil)\n\n// FeaturesConfig describes individual Talos features that can be switched on or off.\ntype FeaturesConfig struct {\n\t// docgen:nodoc\n\tRBAC *bool `yaml:\"rbac,omitempty\"`\n\t// docgen:nodoc\n\t//\n\t// Deprecated: use HostConfig instead.\n\tStableHostname *bool `yaml:\"stableHostname,omitempty\"`\n\t//   description: |\n\t//    Configure Talos API access from Kubernetes pods.\n\t//\n\t//    This feature is disabled if the feature config is not specified.\n\t//   examples:\n\t//     - value: kubernetesTalosAPIAccessConfigExample()\n\tKubernetesTalosAPIAccessConfig *KubernetesTalosAPIAccessConfig `yaml:\"kubernetesTalosAPIAccess,omitempty\"`\n\t// docgen:nodoc\n\tApidCheckExtKeyUsage *bool `yaml:\"apidCheckExtKeyUsage,omitempty\"`\n\t//   description: |\n\t//     Enable XFS project quota support for EPHEMERAL partition and user disks.\n\t//     Also enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\n\tDiskQuotaSupport *bool `yaml:\"diskQuotaSupport,omitempty\"`\n\t//   description: |\n\t//     KubePrism - local proxy/load balancer on defined port that will distribute\n\t//     requests to all API servers in the cluster.\n\tKubePrismSupport *KubePrism `yaml:\"kubePrism,omitempty\"`\n\t//   description: |\n\t//     Configures host DNS caching resolver.\n\tHostDNSSupport *HostDNSConfig `yaml:\"hostDNS,omitempty\"`\n\t//   description: |\n\t//     Enable Image Cache feature.\n\tImageCacheSupport *ImageCacheConfig `yaml:\"imageCache,omitempty\"`\n\t//   description: |\n\t//     Select the node address sort algorithm.\n\t//     The 'v1' algorithm sorts addresses by the address itself.\n\t//     The 'v2' algorithm prefers more specific prefixes.\n\t//     If unset, defaults to 'v1'.\n\tFeatureNodeAddressSortAlgorithm string `yaml:\"nodeAddressSortAlgorithm,omitempty\"`\n}\n\n// KubePrism describes the configuration for the KubePrism load balancer.\ntype KubePrism struct {\n\t//   description: |\n\t//     Enable KubePrism support - will start local load balancing proxy.\n\tServerEnabled *bool `yaml:\"enabled,omitempty\"`\n\t//   description: |\n\t//     KubePrism port.\n\tServerPort int `yaml:\"port,omitempty\"`\n}\n\n// ImageCacheConfig describes the configuration for the Image Cache feature.\ntype ImageCacheConfig struct {\n\t//   description: |\n\t//     Enable local image cache.\n\tCacheLocalEnabled *bool `yaml:\"localEnabled,omitempty\"`\n}\n\n// KubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\ntype KubernetesTalosAPIAccessConfig struct {\n\t//   description: |\n\t//     Enable Talos API access from Kubernetes pods.\n\tAccessEnabled *bool `yaml:\"enabled,omitempty\"`\n\t//   description: |\n\t//     The list of Talos API roles which can be granted for access from Kubernetes pods.\n\t//\n\t//     Empty list means that no roles can be granted, so access is blocked.\n\tAccessAllowedRoles []string `yaml:\"allowedRoles,omitempty\"`\n\t//   description: |\n\t//     The list of Kubernetes namespaces Talos API access is available from.\n\tAccessAllowedKubernetesNamespaces []string `yaml:\"allowedKubernetesNamespaces,omitempty\"`\n}\n\n// HostDNSConfig describes the configuration for the host DNS resolver.\ntype HostDNSConfig struct {\n\t//   description: |\n\t//     Enable host DNS caching resolver.\n\tHostDNSEnabled *bool `yaml:\"enabled,omitempty\"`\n\t//   description: |\n\t//     Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\n\t//\n\t//     When enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\n\t//     using configured upstream DNS resolvers directly).\n\tHostDNSForwardKubeDNSToHost *bool `yaml:\"forwardKubeDNSToHost,omitempty\"`\n\t//   description: |\n\t//     Resolve member hostnames using the host DNS resolver.\n\t//\n\t//     When enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\n\t//     This requires service discovery to be enabled.\n\tHostDNSResolveMemberNames *bool `yaml:\"resolveMemberNames,omitempty\"`\n}\n\n// VolumeMountConfig struct describes extra volume mount for the static pods.\ntype VolumeMountConfig struct {\n\t//   description: |\n\t//     Path on the host.\n\t//   examples:\n\t//     - value: '\"/var/lib/auth\"'\n\tVolumeHostPath string `yaml:\"hostPath\"`\n\t//   description: |\n\t//     Path in the container.\n\t//   examples:\n\t//     - value: '\"/etc/kubernetes/auth\"'\n\tVolumeMountPath string `yaml:\"mountPath\"`\n\t//   description: |\n\t//     Mount the volume read only.\n\t//   examples:\n\t//     - value: true\n\tVolumeReadOnly bool `yaml:\"readonly,omitempty\"`\n}\n\n// ClusterInlineManifests is a list of ClusterInlineManifest.\n//\n//docgen:alias\ntype ClusterInlineManifests []ClusterInlineManifest\n\n// UnmarshalYAML implements yaml.Unmarshaler.\nfunc (manifests *ClusterInlineManifests) UnmarshalYAML(value *yaml.Node) error {\n\tvar result []ClusterInlineManifest\n\n\tif err := value.Decode(&result); err != nil {\n\t\treturn err\n\t}\n\n\tfor i := range result {\n\t\tresult[i].InlineManifestContents = strings.TrimLeft(result[i].InlineManifestContents, \"\\t\\n\\v\\f\\r\")\n\t}\n\n\t*manifests = result\n\n\treturn nil\n}\n\n// ClusterInlineManifest struct describes inline bootstrap manifests for the user.\ntype ClusterInlineManifest struct {\n\t//   description: |\n\t//     Name of the manifest.\n\t//     Name should be unique.\n\t//   examples:\n\t//     - value: '\"csi\"'\n\tInlineManifestName string `yaml:\"name\"`\n\t//   description: |\n\t//     Manifest contents as a string.\n\t//   examples:\n\t//     - value: '\"/etc/kubernetes/auth\"'\n\tInlineManifestContents string `yaml:\"contents\"`\n}\n\n// NetworkKubeSpan struct describes KubeSpan configuration.\n//\n// Deprecated: Use KubeSpanConfig document instead.\n//\n// docgen:nodoc\ntype NetworkKubeSpan struct {\n\t// description: |\n\t//   Enable the KubeSpan feature.\n\t//   Cluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\n\tKubeSpanEnabled *bool `yaml:\"enabled,omitempty\"`\n\t// description: |\n\t//   Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\n\t//   If disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\n\t//   and KubeSpan handles the node-to-node traffic.\n\t//   If enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\n\t//   When enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\n\t//   is not always the case with CNIs not relying on Kubernetes for IPAM.\n\tKubeSpanAdvertiseKubernetesNetworks *bool `yaml:\"advertiseKubernetesNetworks,omitempty\"`\n\t// description: |\n\t//   Skip sending traffic via KubeSpan if the peer connection state is not up.\n\t//   This provides configurable choice between connectivity and security: either traffic is always\n\t//   forced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\n\t//   to the peer if Wireguard connection can't be established.\n\tKubeSpanAllowDownPeerBypass *bool `yaml:\"allowDownPeerBypass,omitempty\"`\n\t// description: |\n\t//   KubeSpan can collect and publish extra endpoints for each member of the cluster\n\t//   based on Wireguard endpoint information for each peer.\n\t//   This feature is disabled by default, don't enable it\n\t//   with high number of peers (>50) in the KubeSpan network (performance issues).\n\tKubeSpanHarvestExtraEndpoints *bool `yaml:\"harvestExtraEndpoints,omitempty\"`\n\t// description: |\n\t//   KubeSpan link MTU size.\n\t//   Default value is 1420.\n\tKubeSpanMTU *uint32 `yaml:\"mtu,omitempty\"`\n\t// description: |\n\t//   KubeSpan advanced filtering of network addresses .\n\t//\n\t//   Settings in this section are optional, and settings apply only to the node.\n\tKubeSpanFilters *KubeSpanFilters `yaml:\"filters,omitempty\"`\n}\n\n// KubeSpanFilters struct describes KubeSpan advanced network addresses filtering.\n//\n// docgen:nodoc\ntype KubeSpanFilters struct {\n\t// description: |\n\t//   Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\n\t//\n\t//   By default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\n\t//\n\t//   Default value: no filtering.\n\t// examples:\n\t//   - name: Exclude addresses in 192.168.0.0/16 subnet.\n\t//     value: '[]string{\"0.0.0.0/0\", \"!192.168.0.0/16\", \"::/0\"}'\n\tKubeSpanFiltersEndpoints []string `yaml:\"endpoints,omitempty\"`\n\t// description: |\n\t//   Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\n\t//\n\t//   By default, all networks are advertised.\n\t//   Use this filter to exclude some networks from being advertised.\n\t//\n\t//   Note: excluded networks will not be reachable over KubeSpan, so make sure\n\t//   these networks are still reachable via some other route (e.g., direct connection).\n\t//\n\t//   Default value: no filtering.\n\t// examples:\n\t//   - name: Exclude private networks from being advertised.\n\t//     value: '[]string{\"172.16.0.0/12\"}'\n\tKubeSpanFiltersExcludeAdvertisedNetworks []string `yaml:\"excludeAdvertisedNetworks,omitempty\"`\n}\n\n// NetworkDeviceSelector struct describes network device selector.\n//\n// docgen:nodoc\ntype NetworkDeviceSelector struct {\n\t// description: PCI, USB bus prefix, supports matching by wildcard.\n\tNetworkDeviceBus string `yaml:\"busPath,omitempty\"`\n\t// description: Device hardware (MAC) address, supports matching by wildcard.\n\tNetworkDeviceHardwareAddress string `yaml:\"hardwareAddr,omitempty\"`\n\t// description: |\n\t//    Device permanent hardware address, supports matching by wildcard.\n\t//    The permanent address doesn't change when the link is enslaved to a bond,\n\t//    so it's recommended to use this field for bond members.\n\tNetworkDevicePermanentAddress string `yaml:\"permanentAddr,omitempty\"`\n\t// description: PCI ID (vendor ID, product ID), supports matching by wildcard.\n\tNetworkDevicePCIID string `yaml:\"pciID,omitempty\"`\n\t// description: Kernel driver, supports matching by wildcard.\n\tNetworkDeviceKernelDriver string `yaml:\"driver,omitempty\"`\n\t// description: Select only physical devices.\n\tNetworkDevicePhysical *bool `yaml:\"physical,omitempty\"`\n}\n\n// ClusterDiscoveryConfig struct configures cluster membership discovery.\ntype ClusterDiscoveryConfig struct {\n\t// description: |\n\t//   Enable the cluster membership discovery feature.\n\t//   Cluster discovery is based on individual registries which are configured under the registries field.\n\tDiscoveryEnabled *bool `yaml:\"enabled,omitempty\"`\n\t// description: |\n\t//   Configure registries used for cluster member discovery.\n\tDiscoveryRegistries DiscoveryRegistriesConfig `yaml:\"registries\"`\n}\n\n// DiscoveryRegistriesConfig struct configures cluster membership discovery.\ntype DiscoveryRegistriesConfig struct {\n\t// description: |\n\t//   Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\n\t//   as annotations on the Node resources.\n\t//\n\t//   This feature is deprecated as it is not compatible with Kubernetes 1.32+.\n\t//   See https://github.com/siderolabs/talos/issues/9980 for more information.\n\tRegistryKubernetes RegistryKubernetesConfig `yaml:\"kubernetes\"`\n\t// description: |\n\t//   Service registry is using an external service to push and pull information about cluster members.\n\tRegistryService RegistryServiceConfig `yaml:\"service\"`\n}\n\n// RegistryKubernetesConfig struct configures Kubernetes discovery registry.\ntype RegistryKubernetesConfig struct {\n\t// description: |\n\t//   Disable Kubernetes discovery registry.\n\tRegistryDisabled *bool `yaml:\"disabled,omitempty\"`\n}\n\n// RegistryServiceConfig struct configures Kubernetes discovery registry.\ntype RegistryServiceConfig struct {\n\t// description: |\n\t//   Disable external service discovery registry.\n\tRegistryDisabled *bool `yaml:\"disabled,omitempty\"`\n\t// description: |\n\t//   External service endpoint.\n\t// examples:\n\t//   - value: constants.DefaultDiscoveryServiceEndpoint\n\tRegistryEndpoint string `yaml:\"endpoint,omitempty\"`\n}\n\n// UdevConfig describes how the udev system should be configured.\ntype UdevConfig struct {\n\t//   description: |\n\t//     List of udev rules to apply to the udev system\n\tUdevRules []string `yaml:\"rules,omitempty\"`\n}\n\n// LoggingConfig struct configures Talos logging.\ntype LoggingConfig struct {\n\t// description: |\n\t//   Logging destination.\n\tLoggingDestinations []LoggingDestination `yaml:\"destinations\"`\n}\n\n// LoggingDestination struct configures Talos logging destination.\ntype LoggingDestination struct {\n\t// description: |\n\t//   Where to send logs. Supported protocols are \"tcp\" and \"udp\".\n\t// examples:\n\t//   - value: loggingEndpointExample1()\n\t//   - value: loggingEndpointExample2()\n\tLoggingEndpoint *Endpoint `yaml:\"endpoint\"`\n\t// description: |\n\t//   Logs format.\n\t// values:\n\t//   - json_lines\n\tLoggingFormat string `yaml:\"format\"`\n\t// description: |\n\t//   Extra tags (key-value) pairs to attach to every log message sent.\n\tLoggingExtraTags map[string]string `yaml:\"extraTags,omitempty\"`\n}\n\n// KernelConfig struct configures Talos Linux kernel.\ntype KernelConfig struct {\n\t// description: |\n\t//   Kernel modules to load.\n\tKernelModules []*KernelModuleConfig `yaml:\"modules,omitempty\"`\n}\n\n// KernelModuleConfig struct configures Linux kernel modules to load.\ntype KernelModuleConfig struct {\n\t// description: |\n\t//   Module name.\n\tModuleName string `yaml:\"name\"`\n\t// description: |\n\t//   Module parameters, changes applied after reboot.\n\tModuleParameters []string `yaml:\"parameters,omitempty\"`\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc (Config) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"Config\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Config defines the v1alpha1.Config Talos machine configuration document.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"Config defines the v1alpha1.Config Talos machine configuration document.\",\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"version\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Indicates the schema used to decode the contents.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Indicates the schema used to decode the contents.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"v1alpha1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"debug\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\n**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable verbose logging to the console.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"machine\",\n\t\t\t\tType:        \"MachineConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Provides machine specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Provides machine specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"cluster\",\n\t\t\t\tType:        \"ClusterConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Provides cluster specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Provides cluster specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", configExample())\n\n\treturn doc\n}\n\nfunc (MachineConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineConfig represents the machine-specific config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineConfig represents the machine-specific config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"Config\",\n\t\t\t\tFieldName: \"machine\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"type\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Defines the role of the machine within the cluster.\\n\\n**Control Plane**\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\n**Worker**\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as \\\"join\\\"; that value is still supported but deprecated.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Defines the role of the machine within the cluster.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"controlplane\",\n\t\t\t\t\t\"worker\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"token\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"Warning: It is important to ensure that this token is correct since a machine's certificate has a short TTL by default.\\n\",\n\t\t\t\tDescription: \"The `token` is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `token` is used by a machine to join the PKI of the cluster.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ca\",\n\t\t\t\tType:        \"PEMEncodedCertificateAndKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The root certificate authority of the PKI.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"acceptedCAs\",\n\t\t\t\tType:        \"[]PEMEncodedCertificate\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.\\nIt is composed of a base64 encoded `crt``.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"certSANs\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra certificate subject alternative names for the machine's certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate's SANs.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra certificate subject alternative names for the machine's certificate.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"controlPlane\",\n\t\t\t\tType:        \"MachineControlPlaneConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Provides machine specific control plane configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Provides machine specific control plane configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"kubelet\",\n\t\t\t\tType:        \"KubeletConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Used to provide additional options to the kubelet.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Used to provide additional options to the kubelet.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"pods\",\n\t\t\t\tType:        \"[]Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn't validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"install\",\n\t\t\t\tType:        \"InstallConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Used to provide instructions for installations.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"files\",\n\t\t\t\tType:        \"[]MachineFile\",\n\t\t\t\tNote:        \"Note: The specified `path` is relative to `/var`.\\n\",\n\t\t\t\tDescription: \"Allows the addition of user specified files.\\nThe value of `op` can be `create`, `overwrite`, or `append`.\\nIn the case of `create`, `path` must not exist.\\nIn the case of `overwrite`, and `append`, `path` must be a valid file.\\nIf an `op` value of `append` is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Allows the addition of user specified files.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"sysctls\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Used to configure the machine's sysctls.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Used to configure the machine's sysctls.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"sysfs\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Used to configure the machine's sysfs.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Used to configure the machine's sysfs.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"features\",\n\t\t\t\tType:        \"FeaturesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Features describe individual Talos features that can be switched on or off.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Features describe individual Talos features that can be switched on or off.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"udev\",\n\t\t\t\tType:        \"UdevConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the udev system.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the udev system.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"logging\",\n\t\t\t\tType:        \"LoggingConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the logging system.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the logging system.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"kernel\",\n\t\t\t\tType:        \"KernelConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the kernel.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the kernel.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"seccompProfiles\",\n\t\t\t\tType:        \"[]MachineSeccompProfile\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the seccomp profiles for the machine.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the seccomp profiles for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"baseRuntimeSpecOverrides\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Override (patch) settings in the default OCI runtime spec for CRI containers.\\n\\nIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Override (patch) settings in the default OCI runtime spec for CRI containers.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeLabels\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the node labels for the machine.\\n\\nNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the node labels for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeAnnotations\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the node annotations for the machine.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the node annotations for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeTaints\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the node taints for the machine. Effect is optional.\\n\\nNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the node taints for the machine. Effect is optional.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineConfigExample())\n\n\tdoc.Fields[1].AddExample(\"example token\", \"328hom.uqjzh6jnn2eie9oi\")\n\tdoc.Fields[2].AddExample(\"machine CA example\", pemEncodedCertificateExample())\n\tdoc.Fields[4].AddExample(\"Uncomment this to enable SANs.\", []string{\"10.0.0.10\", \"172.16.0.10\", \"192.168.0.10\"})\n\tdoc.Fields[5].AddExample(\"ControlPlane definition example.\", machineControlplaneExample())\n\tdoc.Fields[6].AddExample(\"Kubelet definition example.\", machineKubeletExample())\n\tdoc.Fields[7].AddExample(\"nginx static pod.\", machinePodsExample())\n\tdoc.Fields[10].AddExample(\"MachineInstall config usage example.\", machineInstallExample())\n\tdoc.Fields[11].AddExample(\"MachineFiles usage example.\", machineFilesExample())\n\tdoc.Fields[14].AddExample(\"MachineSysctls usage example.\", machineSysctlsExample())\n\tdoc.Fields[15].AddExample(\"MachineSysfs usage example.\", machineSysfsExample())\n\tdoc.Fields[18].AddExample(\"\", machineFeaturesExample())\n\tdoc.Fields[19].AddExample(\"\", machineUdevExample())\n\tdoc.Fields[20].AddExample(\"\", machineLoggingExample())\n\tdoc.Fields[21].AddExample(\"\", machineKernelExample())\n\tdoc.Fields[22].AddExample(\"\", machineSeccompExample())\n\tdoc.Fields[23].AddExample(\"override default open file limit\", machineBaseRuntimeSpecOverridesExample())\n\tdoc.Fields[24].AddExample(\"node labels example.\", map[string]string{\"exampleLabel\": \"exampleLabelValue\"})\n\tdoc.Fields[25].AddExample(\"node annotations example.\", map[string]string{\"customer.io/rack\": \"r13a25\"})\n\tdoc.Fields[26].AddExample(\"node taints example.\", map[string]string{\"exampleTaint\": \"exampleTaintValue:NoSchedule\"})\n\n\treturn doc\n}\n\nfunc (MachineSeccompProfile) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineSeccompProfile\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineSeccompProfile defines seccomp profiles for the machine.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineSeccompProfile defines seccomp profiles for the machine.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"seccompProfiles\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `name` field is used to provide the file name of the seccomp profile.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `name` field is used to provide the file name of the seccomp profile.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"value\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `value` field is used to provide the seccomp profile.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `value` field is used to provide the seccomp profile.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineSeccompExample())\n\n\treturn doc\n}\n\nfunc (ClusterConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ClusterConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ClusterConfig represents the cluster-wide config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ClusterConfig represents the cluster-wide config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"Config\",\n\t\t\t\tFieldName: \"cluster\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"id\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"secret\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Shared secret of cluster (base64 encoded random 32 bytes).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"controlPlane\",\n\t\t\t\tType:        \"ControlPlaneConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Provides control plane specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Provides control plane specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"clusterName\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures the cluster's name.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures the cluster's name.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"network\",\n\t\t\t\tType:        \"ClusterNetworkConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Provides cluster specific network configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Provides cluster specific network configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"token\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"aescbcEncryptionSecret\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with AESCBC.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"secretboxEncryptionSecret\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ca\",\n\t\t\t\tType:        \"PEMEncodedCertificateAndKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The base64 encoded root certificate authority used by Kubernetes.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The base64 encoded root certificate authority used by Kubernetes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"acceptedCAs\",\n\t\t\t\tType:        \"[]PEMEncodedCertificate\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"aggregatorCA\",\n\t\t\t\tType:        \"PEMEncodedCertificateAndKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"serviceAccount\",\n\t\t\t\tType:        \"PEMEncodedKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The base64 encoded private key for service account token generation.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The base64 encoded private key for service account token generation.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"apiServer\",\n\t\t\t\tType:        \"APIServerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"API server specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"API server specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"controllerManager\",\n\t\t\t\tType:        \"ControllerManagerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Controller manager server specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Controller manager server specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"proxy\",\n\t\t\t\tType:        \"ProxyConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Kube-proxy server-specific configuration options\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Kube-proxy server-specific configuration options\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"scheduler\",\n\t\t\t\tType:        \"SchedulerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Scheduler server specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Scheduler server specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"discovery\",\n\t\t\t\tType:        \"ClusterDiscoveryConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures cluster member discovery.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures cluster member discovery.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"etcd\",\n\t\t\t\tType:        \"EtcdConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Etcd specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Etcd specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"coreDNS\",\n\t\t\t\tType:        \"CoreDNS\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Core DNS specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Core DNS specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"externalCloudProvider\",\n\t\t\t\tType:        \"ExternalCloudProviderConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"External cloud provider configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"External cloud provider configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraManifests\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of urls that point to additional manifests.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraManifestHeaders\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A map of key value pairs that will be added while fetching the extraManifests.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A map of key value pairs that will be added while fetching the extraManifests.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"inlineManifests\",\n\t\t\t\tType:        \"[]ClusterInlineManifest\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of inline Kubernetes manifests.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"adminKubeconfig\",\n\t\t\t\tType:        \"AdminKubeconfigConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Settings for admin kubeconfig generation.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"allowSchedulingOnControlPlanes\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Allows running workload on control-plane nodes.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Allows running workload on control-plane nodes.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterConfigExample())\n\n\tdoc.Fields[2].AddExample(\"Setting controlplane endpoint address to 1.2.3.4 and port to 443 example.\", clusterControlPlaneExample())\n\tdoc.Fields[4].AddExample(\"Configuring with flannel CNI and setting up subnets.\", clusterNetworkExample())\n\tdoc.Fields[5].AddExample(\"Bootstrap token example (do not use in production!).\", \"wlzjyw.bei2zfylhs2by0wd\")\n\tdoc.Fields[6].AddExample(\"Decryption secret example (do not use in production!).\", \"z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\")\n\tdoc.Fields[7].AddExample(\"Decryption secret example (do not use in production!).\", \"z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\")\n\tdoc.Fields[8].AddExample(\"ClusterCA example.\", pemEncodedCertificateExample())\n\tdoc.Fields[10].AddExample(\"AggregatorCA example.\", pemEncodedCertificateExample())\n\tdoc.Fields[11].AddExample(\"AggregatorCA example.\", pemEncodedKeyExample())\n\tdoc.Fields[12].AddExample(\"\", clusterAPIServerExample())\n\tdoc.Fields[13].AddExample(\"\", clusterControllerManagerExample())\n\tdoc.Fields[14].AddExample(\"\", clusterProxyExample())\n\tdoc.Fields[15].AddExample(\"\", clusterSchedulerExample())\n\tdoc.Fields[16].AddExample(\"\", clusterDiscoveryExample())\n\tdoc.Fields[17].AddExample(\"\", clusterEtcdExample())\n\tdoc.Fields[18].AddExample(\"\", clusterCoreDNSExample())\n\tdoc.Fields[19].AddExample(\"\", clusterExternalCloudProviderConfigExample())\n\tdoc.Fields[20].AddExample(\"\", []string{\n\t\t\"https://www.example.com/manifest1.yaml\",\n\t\t\"https://www.example.com/manifest2.yaml\",\n\t})\n\tdoc.Fields[21].AddExample(\"\", map[string]string{\n\t\t\"Token\":       \"1234567\",\n\t\t\"X-ExtraInfo\": \"info\",\n\t})\n\tdoc.Fields[22].AddExample(\"\", clusterInlineManifestsExample())\n\tdoc.Fields[23].AddExample(\"\", clusterAdminKubeconfigExample())\n\tdoc.Fields[25].AddExample(\"\", true)\n\n\treturn doc\n}\n\nfunc (LinuxIDMapping) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LinuxIDMapping\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LinuxIDMapping represents the Linux ID mapping.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LinuxIDMapping represents the Linux ID mapping.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ExtraMount\",\n\t\t\t\tFieldName: \"uidMappings\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"ExtraMount\",\n\t\t\t\tFieldName: \"gidMappings\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"containerID\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"ContainerID is the starting UID/GID in the container.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ContainerID is the starting UID/GID in the container.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hostID\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"size\",\n\t\t\t\tType:        \"uint32\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Size is the number of IDs to be mapped.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Size is the number of IDs to be mapped.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (ExtraMount) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExtraMount\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExtraMount wraps OCI Mount specification.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExtraMount wraps OCI Mount specification.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"KubeletConfig\",\n\t\t\t\tFieldName: \"extraMounts\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"destination\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Destination is the absolute path where the mount will be placed in the container.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Destination is the absolute path where the mount will be placed in the container.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"type\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Type specifies the mount kind.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Type specifies the mount kind.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"source\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Source specifies the source path of the mount.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Source specifies the source path of the mount.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"options\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Options are fstab style mount options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Options are fstab style mount options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"uidMappings\",\n\t\t\t\tType:        \"[]LinuxIDMapping\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"gidMappings\",\n\t\t\t\tType:        \"[]LinuxIDMapping\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", kubeletExtraMountsExample())\n\n\treturn doc\n}\n\nfunc (MachineControlPlaneConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineControlPlaneConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineControlPlaneConfig machine specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineControlPlaneConfig machine specific configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"controlPlane\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"controllerManager\",\n\t\t\t\tType:        \"MachineControllerManagerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Controller manager machine specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Controller manager machine specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"scheduler\",\n\t\t\t\tType:        \"MachineSchedulerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Scheduler machine specific configuration options.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Scheduler machine specific configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"ControlPlane definition example.\", machineControlplaneExample())\n\n\treturn doc\n}\n\nfunc (MachineControllerManagerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineControllerManagerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineControllerManagerConfig represents the machine specific ControllerManager config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineControllerManagerConfig represents the machine specific ControllerManager config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineControlPlaneConfig\",\n\t\t\t\tFieldName: \"controllerManager\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable kube-controller-manager on the node.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable kube-controller-manager on the node.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (MachineSchedulerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineSchedulerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineSchedulerConfig represents the machine specific Scheduler config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineSchedulerConfig represents the machine specific Scheduler config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineControlPlaneConfig\",\n\t\t\t\tFieldName: \"scheduler\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable kube-scheduler on the node.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable kube-scheduler on the node.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (KubeletConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubeletConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeletConfig represents the kubelet config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubeletConfig represents the kubelet config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"kubelet\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `image` field is an optional reference to an alternative kubelet image.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `image` field is an optional reference to an alternative kubelet image.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"clusterDNS\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `extraArgs` field is used to provide additional flags to the kubelet.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `extraArgs` field is used to provide additional flags to the kubelet.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraMounts\",\n\t\t\t\tType:        \"[]ExtraMount\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `extraMounts` field is used to add additional mounts to the kubelet container.\\nNote that either `bind` or `rbind` are required in the `options`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `extraMounts` field is used to add additional mounts to the kubelet container.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraConfig\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `extraConfig` field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `extraConfig` field is used to provide kubelet configuration overrides.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"credentialProviderConfig\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"defaultRuntimeSeccompProfileEnabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable container runtime default Seccomp profile.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable container runtime default Seccomp profile.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"registerWithFQDN\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeIP\",\n\t\t\t\tType:        \"KubeletNodeIPConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"skipNodeRegistration\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"disableManifestsDirectory\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt's recommended to configure static pods with the \\\"pods\\\" key instead.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"Kubelet definition example.\", machineKubeletExample())\n\n\tdoc.Fields[0].AddExample(\"\", kubeletImageExample())\n\tdoc.Fields[1].AddExample(\"\", []string{\"10.96.0.10\", \"169.254.2.53\"})\n\tdoc.Fields[2].AddExample(\"\", Args{\n\t\t\"key\": ArgValue{strValue: \"value\"},\n\t})\n\tdoc.Fields[2].AddExample(\"\", Args{\n\t\t\"key\": ArgValue{listValue: []string{\"value1\", \"value2\"}},\n\t})\n\tdoc.Fields[3].AddExample(\"\", kubeletExtraMountsExample())\n\tdoc.Fields[4].AddExample(\"\", kubeletExtraConfigExample())\n\tdoc.Fields[5].AddExample(\"\", kubeletCredentialProviderConfigExample())\n\tdoc.Fields[8].AddExample(\"\", kubeletNodeIPExample())\n\n\treturn doc\n}\n\nfunc (KubeletNodeIPConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubeletNodeIPConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubeletNodeIPConfig represents the kubelet node IP configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubeletNodeIPConfig represents the kubelet node IP configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"KubeletConfig\",\n\t\t\t\tFieldName: \"nodeIP\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"validSubnets\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `validSubnets` field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `validSubnets` field configures the networks to pick kubelet node IP from.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", kubeletNodeIPExample())\n\n\treturn doc\n}\n\nfunc (InstallConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"InstallConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"InstallConfig represents the installation options for preparing a node.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"InstallConfig represents the installation options for preparing a node.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"install\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disk\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The disk used for installations.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The disk used for installations.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"diskSelector\",\n\t\t\t\tType:        \"InstallDiskSelector\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over `disk`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Look up disk using disk attributes like model, size, serial and others.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n[GitHub releases page](https://github.com/siderolabs/talos/releases).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Allows for supplying the image used to perform the installation.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"wipe\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to `true`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Indicates if the installation disk should be wiped at installation time.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"legacyBIOSSupport\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Indicates if MBR partition should be marked as bootable (active).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"grubUseUKICmdline\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"MachineInstall config usage example.\", machineInstallExample())\n\n\tdoc.Fields[0].AddExample(\"\", \"/dev/sda\")\n\tdoc.Fields[0].AddExample(\"\", \"/dev/nvme0\")\n\tdoc.Fields[1].AddExample(\"\", machineInstallDiskSelectorExample())\n\tdoc.Fields[3].AddExample(\"\", \"ghcr.io/siderolabs/installer:latest\")\n\n\treturn doc\n}\n\nfunc (InstallDiskSelector) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"InstallDiskSelector\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"InstallDiskSelector represents a disk query parameters for the install disk lookup.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"InstallDiskSelector represents a disk query parameters for the install disk lookup.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"InstallConfig\",\n\t\t\t\tFieldName: \"diskSelector\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"size\",\n\t\t\t\tType:        \"InstallDiskSizeMatcher\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk size.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk size.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk name `/sys/block/<dev>/device/name`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk name `/sys/block/<dev>/device/name`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"model\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk model `/sys/block/<dev>/device/model`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk model `/sys/block/<dev>/device/model`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"serial\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk serial number `/sys/block/<dev>/serial`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk serial number `/sys/block/<dev>/serial`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"modalias\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk modalias `/sys/block/<dev>/device/modalias`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk modalias `/sys/block/<dev>/device/modalias`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"uuid\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk UUID `/sys/block/<dev>/uuid`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk UUID `/sys/block/<dev>/uuid`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"wwid\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk WWID `/sys/block/<dev>/wwid`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk WWID `/sys/block/<dev>/wwid`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"type\",\n\t\t\t\tType:        \"InstallDiskType\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk Type.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk Type.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"ssd\",\n\t\t\t\t\t\"hdd\",\n\t\t\t\t\t\"nvme\",\n\t\t\t\t\t\"sd\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"busPath\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disk bus path.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disk bus path.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineInstallDiskSelectorExample())\n\n\tdoc.Fields[0].AddExample(\"Select a disk which size is equal to 4GB.\", machineInstallDiskSizeMatcherExamples0())\n\tdoc.Fields[0].AddExample(\"Select a disk which size is greater than 1TB.\", machineInstallDiskSizeMatcherExamples1())\n\tdoc.Fields[0].AddExample(\"Select a disk which size is less or equal than 2TB.\", machineInstallDiskSizeMatcherExamples2())\n\tdoc.Fields[8].AddExample(\"\", \"/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0\")\n\tdoc.Fields[8].AddExample(\"\", \"/pci0000:00/*\")\n\n\treturn doc\n}\n\nfunc (CoreDNS) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"CoreDNS\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CoreDNS represents the CoreDNS config values.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"CoreDNS represents the CoreDNS config values.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"coreDNS\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable coredns deployment on cluster bootstrap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable coredns deployment on cluster bootstrap.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `image` field is an override to the default coredns image.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `image` field is an override to the default coredns image.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterCoreDNSExample())\n\n\treturn doc\n}\n\nfunc (Endpoint) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"Endpoint\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Endpoint represents the endpoint URL parsed out of the machine config.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"Endpoint represents the endpoint URL parsed out of the machine config.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ControlPlaneConfig\",\n\t\t\t\tFieldName: \"endpoint\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"LoggingDestination\",\n\t\t\t\tFieldName: \"endpoint\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterEndpointExample1())\n\n\tdoc.AddExample(\"\", clusterEndpointExample2())\n\n\tdoc.AddExample(\"\", loggingEndpointExample1())\n\n\tdoc.AddExample(\"\", loggingEndpointExample2())\n\n\treturn doc\n}\n\nfunc (ControlPlaneConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ControlPlaneConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ControlPlaneConfig represents the control plane configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ControlPlaneConfig represents the control plane configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"controlPlane\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"Endpoint\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"localAPIServerPort\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is `6443`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The port that the API server listens on internally.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"Setting controlplane endpoint address to 1.2.3.4 and port to 443 example.\", clusterControlPlaneExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterEndpointExample1())\n\tdoc.Fields[0].AddExample(\"\", clusterEndpointExample2())\n\n\treturn doc\n}\n\nfunc (APIServerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"APIServerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"APIServerConfig represents the kube apiserver configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"APIServerConfig represents the kube apiserver configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"apiServer\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The container image used in the API server manifest.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The container image used in the API server manifest.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments to supply to the API server.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments to supply to the API server.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraVolumes\",\n\t\t\t\tType:        \"[]VolumeMountConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra volumes to mount to the API server static pod.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra volumes to mount to the API server static pod.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"env\",\n\t\t\t\tType:        \"Env\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `env` field allows for the addition of environment variables for the control plane component.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `env` field allows for the addition of environment variables for the control plane component.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"certSANs\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra certificate subject alternative names for the API server's certificate.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra certificate subject alternative names for the API server's certificate.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"admissionControl\",\n\t\t\t\tType:        \"[]AdmissionPluginConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the API server admission plugins.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the API server admission plugins.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"auditPolicy\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the API server audit policy.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the API server audit policy.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"resources\",\n\t\t\t\tType:        \"ResourcesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the API server resources.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the API server resources.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"authorizationConfig\",\n\t\t\t\tType:        \"[]AuthorizationConfigAuthorizerConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterAPIServerExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterAPIServerImageExample())\n\tdoc.Fields[6].AddExample(\"\", admissionControlConfigExample())\n\tdoc.Fields[7].AddExample(\"\", APIServerDefaultAuditPolicy)\n\tdoc.Fields[9].AddExample(\"\", authorizationConfigExample())\n\n\treturn doc\n}\n\nfunc (AdmissionPluginConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"AdmissionPluginConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"AdmissionPluginConfig represents the API server admission plugin configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"AdmissionPluginConfig represents the API server admission plugin configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"APIServerConfig\",\n\t\t\t\tFieldName: \"admissionControl\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name is the name of the admission controller.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"configuration\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configuration is an embedded configuration object to be used as the plugin's\\nconfiguration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configuration is an embedded configuration object to be used as the plugin's\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", admissionControlConfigExample())\n\n\treturn doc\n}\n\nfunc (AuthorizationConfigAuthorizerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"AuthorizationConfigAuthorizerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"AuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"AuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"APIServerConfig\",\n\t\t\t\tFieldName: \"authorizationConfig\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"type\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name is used to describe the authorizer.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name is used to describe the authorizer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"webhook\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"webhook is the configuration for the webhook authorizer.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"webhook is the configuration for the webhook authorizer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", authorizationConfigExample())\n\n\treturn doc\n}\n\nfunc (ControllerManagerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ControllerManagerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ControllerManagerConfig represents the kube controller manager configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ControllerManagerConfig represents the kube controller manager configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"controllerManager\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The container image used in the controller manager manifest.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The container image used in the controller manager manifest.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments to supply to the controller manager.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments to supply to the controller manager.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraVolumes\",\n\t\t\t\tType:        \"[]VolumeMountConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra volumes to mount to the controller manager static pod.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra volumes to mount to the controller manager static pod.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"env\",\n\t\t\t\tType:        \"Env\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `env` field allows for the addition of environment variables for the control plane component.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `env` field allows for the addition of environment variables for the control plane component.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"resources\",\n\t\t\t\tType:        \"ResourcesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the controller manager resources.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the controller manager resources.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterControllerManagerExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterControllerManagerImageExample())\n\n\treturn doc\n}\n\nfunc (ProxyConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ProxyConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ProxyConfig represents the kube proxy configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ProxyConfig represents the kube proxy configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"proxy\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable kube-proxy deployment on cluster bootstrap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable kube-proxy deployment on cluster bootstrap.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The container image used in the kube-proxy manifest.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The container image used in the kube-proxy manifest.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mode\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"proxy mode of kube-proxy.\\nThe default is 'iptables'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"proxy mode of kube-proxy.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments to supply to kube-proxy.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments to supply to kube-proxy.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterProxyExample())\n\n\tdoc.Fields[0].AddExample(\"\", new(false))\n\tdoc.Fields[1].AddExample(\"\", clusterProxyImageExample())\n\n\treturn doc\n}\n\nfunc (SchedulerConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"SchedulerConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"SchedulerConfig represents the kube scheduler configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"SchedulerConfig represents the kube scheduler configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"scheduler\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The container image used in the scheduler manifest.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The container image used in the scheduler manifest.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments to supply to the scheduler.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments to supply to the scheduler.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraVolumes\",\n\t\t\t\tType:        \"[]VolumeMountConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra volumes to mount to the scheduler static pod.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra volumes to mount to the scheduler static pod.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"env\",\n\t\t\t\tType:        \"Env\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `env` field allows for the addition of environment variables for the control plane component.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `env` field allows for the addition of environment variables for the control plane component.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"resources\",\n\t\t\t\tType:        \"ResourcesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure the scheduler resources.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure the scheduler resources.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"config\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Specify custom kube-scheduler configuration.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Specify custom kube-scheduler configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterSchedulerExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterSchedulerImageExample())\n\n\treturn doc\n}\n\nfunc (EtcdConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"EtcdConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"EtcdConfig represents the etcd configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"EtcdConfig represents the etcd configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"etcd\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"image\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The container image used to create the etcd service.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The container image used to create the etcd service.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"ca\",\n\t\t\t\tType:        \"PEMEncodedCertificateAndKey\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `ca` is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `ca` is the root certificate authority of the PKI.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"Args\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n- `name`\\n- `data-dir`\\n- `initial-cluster-state`\\n- `listen-peer-urls`\\n- `listen-client-urls`\\n- `cert-file`\\n- `key-file`\\n- `trusted-ca-file`\\n- `peer-client-cert-auth`\\n- `peer-cert-file`\\n- `peer-trusted-ca-file`\\n- `peer-key-file`\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments to supply to etcd.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"advertisedSubnets\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"listenSubnets\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\\n`advertisedSubnets`.\\n\\nIf neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterEtcdExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterEtcdImageExample())\n\tdoc.Fields[1].AddExample(\"\", pemEncodedCertificateExample())\n\tdoc.Fields[4].AddExample(\"\", clusterEtcdAdvertisedSubnetsExample())\n\n\treturn doc\n}\n\nfunc (ClusterNetworkConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ClusterNetworkConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ClusterNetworkConfig represents kube networking configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ClusterNetworkConfig represents kube networking configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"network\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"cni\",\n\t\t\t\tType:        \"CNIConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The CNI used.\\nComposed of \\\"name\\\" and \\\"urls\\\".\\nThe \\\"name\\\" key supports the following options: \\\"flannel\\\", \\\"custom\\\", and \\\"none\\\".\\n\\\"flannel\\\" uses Talos-managed Flannel CNI, and that's the default option.\\n\\\"custom\\\" uses custom manifests that should be provided in \\\"urls\\\".\\n\\\"none\\\" indicates that Talos will not manage any CNI installation.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The CNI used.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"dnsDomain\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The domain used by Kubernetes DNS.\\nThe default is `cluster.local`\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The domain used by Kubernetes DNS.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"podSubnets\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The pod subnet CIDR.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The pod subnet CIDR.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"serviceSubnets\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The service subnet CIDR.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The service subnet CIDR.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"Configuring with flannel CNI and setting up subnets.\", clusterNetworkExample())\n\n\tdoc.Fields[0].AddExample(\"\", clusterCustomCNIExample())\n\tdoc.Fields[1].AddExample(\"\", \"cluster.local\")\n\tdoc.Fields[2].AddExample(\"\", []string{\"10.244.0.0/16\"})\n\tdoc.Fields[3].AddExample(\"\", []string{\"10.96.0.0/12\"})\n\n\treturn doc\n}\n\nfunc (CNIConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"CNIConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"CNIConfig represents the CNI configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"CNIConfig represents the CNI configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterNetworkConfig\",\n\t\t\t\tFieldName: \"cni\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of CNI to use.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of CNI to use.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"flannel\",\n\t\t\t\t\t\"custom\",\n\t\t\t\t\t\"none\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"urls\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"URLs containing manifests to apply for the CNI.\\nShould be present for \\\"custom\\\", must be empty for \\\"flannel\\\" and \\\"none\\\".\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"URLs containing manifests to apply for the CNI.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"flannel\",\n\t\t\t\tType:        \"FlannelCNIConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"description: |\\nFlannel configuration options.\\n\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"description: |\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterCustomCNIExample())\n\n\treturn doc\n}\n\nfunc (FlannelCNIConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"FlannelCNIConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"FlannelCNIConfig represents the Flannel CNI configuration options.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"FlannelCNIConfig represents the Flannel CNI configuration options.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"CNIConfig\",\n\t\t\t\tFieldName: \"flannel\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"extraArgs\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra arguments for 'flanneld'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra arguments for 'flanneld'.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"kubeNetworkPoliciesEnabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Deploys kube-network-policies along with Flannel.\\n\\nThis enables Kubernetes Network Policies support in the cluster.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Deploys kube-network-policies along with Flannel.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", []string{\"--iface-can-reach=192.168.1.1\"})\n\n\treturn doc\n}\n\nfunc (ExternalCloudProviderConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ExternalCloudProviderConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ExternalCloudProviderConfig contains external cloud provider configuration.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ExternalCloudProviderConfig contains external cloud provider configuration.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"externalCloudProvider\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable external cloud provider.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable external cloud provider.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"true\",\n\t\t\t\t\t\"yes\",\n\t\t\t\t\t\"false\",\n\t\t\t\t\t\"no\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"manifests\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"A list of urls that point to additional manifests for an external cloud provider.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterExternalCloudProviderConfigExample())\n\n\tdoc.Fields[1].AddExample(\"\", []string{\n\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\",\n\t\t\"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\",\n\t})\n\n\treturn doc\n}\n\nfunc (AdminKubeconfigConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"AdminKubeconfigConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"AdminKubeconfigConfig contains admin kubeconfig settings.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"AdminKubeconfigConfig contains admin kubeconfig settings.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"adminKubeconfig\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"certLifetime\",\n\t\t\t\tType:        \"Duration\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Admin kubeconfig certificate lifetime (default is 1 year).\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterAdminKubeconfigExample())\n\n\treturn doc\n}\n\nfunc (ResourcesConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ResourcesConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ResourcesConfig represents the pod resources.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ResourcesConfig represents the pod resources.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"APIServerConfig\",\n\t\t\t\tFieldName: \"resources\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"ControllerManagerConfig\",\n\t\t\t\tFieldName: \"resources\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"SchedulerConfig\",\n\t\t\t\tFieldName: \"resources\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"requests\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Requests configures the reserved cpu/memory resources.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Requests configures the reserved cpu/memory resources.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"limits\",\n\t\t\t\tType:        \"Unstructured\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Limits configures the maximum cpu/memory resources a container can use.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Limits configures the maximum cpu/memory resources a container can use.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"resources requests.\", resourcesConfigRequestsExample())\n\tdoc.Fields[1].AddExample(\"resources requests.\", resourcesConfigLimitsExample())\n\n\treturn doc\n}\n\nfunc (MachineFile) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"MachineFile\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"MachineFile represents a file to write to disk.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"MachineFile represents a file to write to disk.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"files\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"content\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The contents of the file.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The contents of the file.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"permissions\",\n\t\t\t\tType:        \"FileMode\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The file's permissions in octal.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The file's permissions in octal.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"path\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The path of the file.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The path of the file.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"op\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The operation to use\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The operation to use\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"create\",\n\t\t\t\t\t\"append\",\n\t\t\t\t\t\"overwrite\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"MachineFiles usage example.\", machineFilesExample())\n\n\treturn doc\n}\n\nfunc (FeaturesConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"FeaturesConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"FeaturesConfig describes individual Talos features that can be switched on or off.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"FeaturesConfig describes individual Talos features that can be switched on or off.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"features\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"kubernetesTalosAPIAccess\",\n\t\t\t\tType:        \"KubernetesTalosAPIAccessConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure Talos API access from Kubernetes pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{},\n\t\t\t{\n\t\t\t\tName:        \"diskQuotaSupport\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable XFS project quota support for EPHEMERAL partition and user disks.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"kubePrism\",\n\t\t\t\tType:        \"KubePrism\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubePrism - local proxy/load balancer on defined port that will distribute\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"hostDNS\",\n\t\t\t\tType:        \"HostDNSConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configures host DNS caching resolver.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configures host DNS caching resolver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"imageCache\",\n\t\t\t\tType:        \"ImageCacheConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable Image Cache feature.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable Image Cache feature.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"nodeAddressSortAlgorithm\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Select the node address sort algorithm.\\nThe 'v1' algorithm sorts addresses by the address itself.\\nThe 'v2' algorithm prefers more specific prefixes.\\nIf unset, defaults to 'v1'.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Select the node address sort algorithm.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineFeaturesExample())\n\n\tdoc.Fields[2].AddExample(\"\", kubernetesTalosAPIAccessConfigExample())\n\n\treturn doc\n}\n\nfunc (KubePrism) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubePrism\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubePrism describes the configuration for the KubePrism load balancer.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubePrism describes the configuration for the KubePrism load balancer.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"FeaturesConfig\",\n\t\t\t\tFieldName: \"kubePrism\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable KubePrism support - will start local load balancing proxy.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable KubePrism support - will start local load balancing proxy.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"port\",\n\t\t\t\tType:        \"int\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"KubePrism port.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubePrism port.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (ImageCacheConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ImageCacheConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ImageCacheConfig describes the configuration for the Image Cache feature.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ImageCacheConfig describes the configuration for the Image Cache feature.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"FeaturesConfig\",\n\t\t\t\tFieldName: \"imageCache\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"localEnabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable local image cache.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable local image cache.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (KubernetesTalosAPIAccessConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KubernetesTalosAPIAccessConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"FeaturesConfig\",\n\t\t\t\tFieldName: \"kubernetesTalosAPIAccess\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable Talos API access from Kubernetes pods.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable Talos API access from Kubernetes pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"allowedRoles\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The list of Talos API roles which can be granted for access from Kubernetes pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"allowedKubernetesNamespaces\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"The list of Kubernetes namespaces Talos API access is available from.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"The list of Kubernetes namespaces Talos API access is available from.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", kubernetesTalosAPIAccessConfigExample())\n\n\treturn doc\n}\n\nfunc (HostDNSConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"HostDNSConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"HostDNSConfig describes the configuration for the host DNS resolver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"HostDNSConfig describes the configuration for the host DNS resolver.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"FeaturesConfig\",\n\t\t\t\tFieldName: \"hostDNS\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable host DNS caching resolver.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable host DNS caching resolver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"forwardKubeDNSToHost\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\n\\nWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"resolveMemberNames\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Resolve member hostnames using the host DNS resolver.\\n\\nWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Resolve member hostnames using the host DNS resolver.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (VolumeMountConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"VolumeMountConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"VolumeMountConfig struct describes extra volume mount for the static pods.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"VolumeMountConfig struct describes extra volume mount for the static pods.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"APIServerConfig\",\n\t\t\t\tFieldName: \"extraVolumes\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"ControllerManagerConfig\",\n\t\t\t\tFieldName: \"extraVolumes\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tTypeName:  \"SchedulerConfig\",\n\t\t\t\tFieldName: \"extraVolumes\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"hostPath\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Path on the host.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Path on the host.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"mountPath\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Path in the container.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Path in the container.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"readonly\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Mount the volume read only.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Mount the volume read only.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", \"/var/lib/auth\")\n\tdoc.Fields[1].AddExample(\"\", \"/etc/kubernetes/auth\")\n\tdoc.Fields[2].AddExample(\"\", true)\n\n\treturn doc\n}\n\nfunc (ClusterInlineManifest) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ClusterInlineManifest\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ClusterInlineManifest struct describes inline bootstrap manifests for the user.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ClusterInlineManifest struct describes inline bootstrap manifests for the user.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"inlineManifests\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Name of the manifest.\\nName should be unique.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Name of the manifest.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"contents\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Manifest contents as a string.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Manifest contents as a string.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterInlineManifestsExample())\n\n\tdoc.Fields[0].AddExample(\"\", \"csi\")\n\tdoc.Fields[1].AddExample(\"\", \"/etc/kubernetes/auth\")\n\n\treturn doc\n}\n\nfunc (ClusterDiscoveryConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"ClusterDiscoveryConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"ClusterDiscoveryConfig struct configures cluster membership discovery.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"ClusterDiscoveryConfig struct configures cluster membership discovery.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterConfig\",\n\t\t\t\tFieldName: \"discovery\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"enabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Enable the cluster membership discovery feature.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"registries\",\n\t\t\t\tType:        \"DiscoveryRegistriesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Configure registries used for cluster member discovery.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Configure registries used for cluster member discovery.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", clusterDiscoveryExample())\n\n\treturn doc\n}\n\nfunc (DiscoveryRegistriesConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"DiscoveryRegistriesConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"DiscoveryRegistriesConfig struct configures cluster membership discovery.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"DiscoveryRegistriesConfig struct configures cluster membership discovery.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"ClusterDiscoveryConfig\",\n\t\t\t\tFieldName: \"registries\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"kubernetes\",\n\t\t\t\tType:        \"RegistryKubernetesConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\\nThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee https://github.com/siderolabs/talos/issues/9980 for more information.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"service\",\n\t\t\t\tType:        \"RegistryServiceConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Service registry is using an external service to push and pull information about cluster members.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Service registry is using an external service to push and pull information about cluster members.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (RegistryKubernetesConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryKubernetesConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryKubernetesConfig struct configures Kubernetes discovery registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryKubernetesConfig struct configures Kubernetes discovery registry.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"DiscoveryRegistriesConfig\",\n\t\t\t\tFieldName: \"kubernetes\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable Kubernetes discovery registry.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable Kubernetes discovery registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\nfunc (RegistryServiceConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"RegistryServiceConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"RegistryServiceConfig struct configures Kubernetes discovery registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"RegistryServiceConfig struct configures Kubernetes discovery registry.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"DiscoveryRegistriesConfig\",\n\t\t\t\tFieldName: \"service\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"disabled\",\n\t\t\t\tType:        \"bool\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Disable external service discovery registry.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Disable external service discovery registry.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"External service endpoint.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"External service endpoint.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[1].AddExample(\"\", constants.DefaultDiscoveryServiceEndpoint)\n\n\treturn doc\n}\n\nfunc (UdevConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"UdevConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"UdevConfig describes how the udev system should be configured.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"UdevConfig describes how the udev system should be configured.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"udev\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"rules\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"List of udev rules to apply to the udev system\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"List of udev rules to apply to the udev system\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineUdevExample())\n\n\treturn doc\n}\n\nfunc (LoggingConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LoggingConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LoggingConfig struct configures Talos logging.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LoggingConfig struct configures Talos logging.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"logging\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"destinations\",\n\t\t\t\tType:        \"[]LoggingDestination\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Logging destination.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Logging destination.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineLoggingExample())\n\n\treturn doc\n}\n\nfunc (LoggingDestination) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"LoggingDestination\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"LoggingDestination struct configures Talos logging destination.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"LoggingDestination struct configures Talos logging destination.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"LoggingConfig\",\n\t\t\t\tFieldName: \"destinations\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"endpoint\",\n\t\t\t\tType:        \"Endpoint\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"format\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Logs format.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Logs format.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t\tValues: []string{\n\t\t\t\t\t\"json_lines\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"extraTags\",\n\t\t\t\tType:        \"map[string]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Extra tags (key-value) pairs to attach to every log message sent.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Extra tags (key-value) pairs to attach to every log message sent.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.Fields[0].AddExample(\"\", loggingEndpointExample1())\n\tdoc.Fields[0].AddExample(\"\", loggingEndpointExample2())\n\n\treturn doc\n}\n\nfunc (KernelConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KernelConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KernelConfig struct configures Talos Linux kernel.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KernelConfig struct configures Talos Linux kernel.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"MachineConfig\",\n\t\t\t\tFieldName: \"kernel\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"modules\",\n\t\t\t\tType:        \"[]KernelModuleConfig\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Kernel modules to load.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Kernel modules to load.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\tdoc.AddExample(\"\", machineKernelExample())\n\n\treturn doc\n}\n\nfunc (KernelModuleConfig) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType:        \"KernelModuleConfig\",\n\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"KernelModuleConfig struct configures Linux kernel modules to load.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\tDescription: \"KernelModuleConfig struct configures Linux kernel modules to load.\",\n\t\tAppearsIn: []encoder.Appearance{\n\t\t\t{\n\t\t\t\tTypeName:  \"KernelConfig\",\n\t\t\t\tFieldName: \"modules\",\n\t\t\t},\n\t\t},\n\t\tFields: []encoder.Doc{\n\t\t\t{\n\t\t\t\tName:        \"name\",\n\t\t\t\tType:        \"string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Module name.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Module name.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:        \"parameters\",\n\t\t\t\tType:        \"[]string\",\n\t\t\t\tNote:        \"\",\n\t\t\t\tDescription: \"Module parameters, changes applied after reboot.\",\n\t\t\t\tComments:    [3]string{\"\" /* encoder.HeadComment */, \"Module parameters, changes applied after reboot.\" /* encoder.LineComment */, \"\" /* encoder.FootComment */},\n\t\t\t},\n\t\t},\n\t}\n\n\treturn doc\n}\n\n// GetFileDoc returns documentation for the file ./v1alpha1_types_doc.go.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName:        \"v1alpha1\",\n\t\tDescription: \"Package v1alpha1 contains definition of the `v1alpha1` configuration document.\\n\\nEven though the machine configuration in Talos Linux is multi-document, at the moment\\nthis configuration document contains most of the configuration options.\\n\\nIt is expected that new configuration options will be added as new documents, and existing ones\\nmigrated to their own documents.\\n\",\n\t\tStructs: []*encoder.Doc{\n\t\t\tConfig{}.Doc(),\n\t\t\tMachineConfig{}.Doc(),\n\t\t\tMachineSeccompProfile{}.Doc(),\n\t\t\tClusterConfig{}.Doc(),\n\t\t\tLinuxIDMapping{}.Doc(),\n\t\t\tExtraMount{}.Doc(),\n\t\t\tMachineControlPlaneConfig{}.Doc(),\n\t\t\tMachineControllerManagerConfig{}.Doc(),\n\t\t\tMachineSchedulerConfig{}.Doc(),\n\t\t\tKubeletConfig{}.Doc(),\n\t\t\tKubeletNodeIPConfig{}.Doc(),\n\t\t\tInstallConfig{}.Doc(),\n\t\t\tInstallDiskSelector{}.Doc(),\n\t\t\tCoreDNS{}.Doc(),\n\t\t\tEndpoint{}.Doc(),\n\t\t\tControlPlaneConfig{}.Doc(),\n\t\t\tAPIServerConfig{}.Doc(),\n\t\t\tAdmissionPluginConfig{}.Doc(),\n\t\t\tAuthorizationConfigAuthorizerConfig{}.Doc(),\n\t\t\tControllerManagerConfig{}.Doc(),\n\t\t\tProxyConfig{}.Doc(),\n\t\t\tSchedulerConfig{}.Doc(),\n\t\t\tEtcdConfig{}.Doc(),\n\t\t\tClusterNetworkConfig{}.Doc(),\n\t\t\tCNIConfig{}.Doc(),\n\t\t\tFlannelCNIConfig{}.Doc(),\n\t\t\tExternalCloudProviderConfig{}.Doc(),\n\t\t\tAdminKubeconfigConfig{}.Doc(),\n\t\t\tResourcesConfig{}.Doc(),\n\t\t\tMachineFile{}.Doc(),\n\t\t\tFeaturesConfig{}.Doc(),\n\t\t\tKubePrism{}.Doc(),\n\t\t\tImageCacheConfig{}.Doc(),\n\t\t\tKubernetesTalosAPIAccessConfig{}.Doc(),\n\t\t\tHostDNSConfig{}.Doc(),\n\t\t\tVolumeMountConfig{}.Doc(),\n\t\t\tClusterInlineManifest{}.Doc(),\n\t\t\tClusterDiscoveryConfig{}.Doc(),\n\t\t\tDiscoveryRegistriesConfig{}.Doc(),\n\t\t\tRegistryKubernetesConfig{}.Doc(),\n\t\t\tRegistryServiceConfig{}.Doc(),\n\t\t\tUdevConfig{}.Doc(),\n\t\t\tLoggingConfig{}.Doc(),\n\t\t\tLoggingDestination{}.Doc(),\n\t\t\tKernelConfig{}.Doc(),\n\t\t\tKernelModuleConfig{}.Doc(),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_unstructured.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n)\n\n// Unstructured allows wrapping any map[string]interface{} into a config object.\n//\n// docgen: nodoc\n// +k8s:deepcopy-gen=true\ntype Unstructured struct {\n\tObject map[string]any `yaml:\",inline\"`\n}\n\n// DeepCopy performs copying of the Object contents.\nfunc (in *Unstructured) DeepCopy() *Unstructured {\n\tif in == nil {\n\t\treturn nil\n\t}\n\n\tout := new(Unstructured)\n\n\tout.Object = deepCopyUnstructured(in.Object).(map[string]any) //nolint:forcetypeassert\n\n\treturn out\n}\n\nfunc deepCopyUnstructured(x any) any {\n\tswitch x := x.(type) {\n\tcase map[string]any:\n\t\tif x == nil {\n\t\t\treturn x\n\t\t}\n\n\t\tclone := make(map[string]any, len(x))\n\n\t\tfor k, v := range x {\n\t\t\tclone[k] = deepCopyUnstructured(v)\n\t\t}\n\n\t\treturn clone\n\tcase []any:\n\t\tif x == nil {\n\t\t\treturn x\n\t\t}\n\n\t\tclone := make([]any, len(x))\n\n\t\tfor i, v := range x {\n\t\t\tclone[i] = deepCopyUnstructured(v)\n\t\t}\n\n\t\treturn clone\n\tcase string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128, nil:\n\t\treturn x\n\tcase []byte:\n\t\treturn slices.Clone(x)\n\tdefault:\n\t\tpanic(fmt.Errorf(\"cannot deep copy %T\", x))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_unstructured_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\nfunc TestUnstructuredDeepCopy(t *testing.T) {\n\tu := v1alpha1.Unstructured{\n\t\tObject: map[string]any{\n\t\t\t\"strings\": map[string]any{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t},\n\t\t\t\"numbers\": []any{\n\t\t\t\tmap[string]any{\n\t\t\t\t\t\"int\":    32,\n\t\t\t\t\t\"int8\":   int8(34),\n\t\t\t\t\t\"byte\":   byte(35),\n\t\t\t\t\t\"int16\":  int16(36),\n\t\t\t\t\t\"int32\":  int32(37),\n\t\t\t\t\t\"int64\":  int64(38),\n\t\t\t\t\t\"uint\":   uint(39),\n\t\t\t\t\t\"uint8\":  uint8(40),\n\t\t\t\t\t\"uint16\": uint16(41),\n\t\t\t\t\t\"uint32\": uint32(42),\n\t\t\t\t\t\"uint64\": uint64(43),\n\t\t\t\t},\n\t\t\t\tfloat32(44.0),\n\t\t\t\tfloat64(45.0),\n\t\t\t\tcomplex64(complex(46.0, 47.0)),\n\t\t\t\tcomplex128(complex(48.0, 49.0)),\n\t\t\t},\n\t\t\t\"bytes\": []byte(\"abc\"),\n\t\t},\n\t}\n\n\tassert.Equal(t, u.DeepCopy(), &u)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_validation.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"os\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\tsideronet \"github.com/siderolabs/net\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/block/blockhelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kubelet\"\n\t\"github.com/siderolabs/talos/pkg/machinery/labels\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nvar (\n\t// General.\n\n\t// ErrRequiredSection denotes a section is required.\n\tErrRequiredSection = errors.New(\"required config section\")\n\t// ErrRequiredSectionOptions denotes at least one section is required.\n\tErrRequiredSectionOptions = errors.New(\"required either config section to be set\")\n\t// ErrInvalidVersion denotes that the config file version is invalid.\n\tErrInvalidVersion = errors.New(\"invalid config version\")\n\t// ErrMutuallyExclusive denotes that config sections are mutually exclusive.\n\tErrMutuallyExclusive = errors.New(\"config sections are mutually exclusive\")\n\t// ErrEmpty denotes that config section should have at least a single field defined.\n\tErrEmpty = errors.New(\"config section should contain at least one field\")\n\n\t// Security.\n\n\t// ErrEmptyKeyCert denotes that crypto key/cert combination should not be empty.\n\tErrEmptyKeyCert = errors.New(\"key/cert combination should not be empty\")\n\t// ErrInvalidCert denotes that the certificate specified is invalid.\n\tErrInvalidCert = errors.New(\"certificate is invalid\")\n\t// ErrInvalidCertType denotes that the certificate type is invalid.\n\tErrInvalidCertType = errors.New(\"certificate type is invalid\")\n\n\t// Services.\n\n\t// ErrUnsupportedCNI denotes that the specified CNI is invalid.\n\tErrUnsupportedCNI = errors.New(\"unsupported CNI driver\")\n\t// ErrInvalidTrustdToken denotes that a trustd token has not been specified.\n\tErrInvalidTrustdToken = errors.New(\"trustd token is invalid\")\n\n\t// Networking.\n\n\t// ErrInvalidAddress denotes that a bad address was provided.\n\tErrInvalidAddress = errors.New(\"invalid network address\")\n)\n\n// NetworkDeviceCheck defines the function type for checks.\ntype NetworkDeviceCheck func(*Device, map[string]string) ([]string, error)\n\n// Validate implements the config.Provider interface.\n//\n//nolint:gocyclo,cyclop\nfunc (c *Config) Validate(mode validation.RuntimeMode, options ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings []string\n\t\tresult   *multierror.Error\n\t)\n\n\topts := validation.NewOptions(options...)\n\n\tif c.MachineConfig == nil {\n\t\tresult = multierror.Append(result, errors.New(\"machine instructions are required\"))\n\n\t\treturn nil, result.ErrorOrNil()\n\t}\n\n\tif err := c.ClusterConfig.Validate(c.Machine().Type().IsControlPlane()); err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\tif mode.RequiresInstall() {\n\t\tif c.MachineConfig.MachineInstall == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"install instructions are required in %q mode\", mode))\n\t\t} else {\n\t\t\tmatcher, err := c.MachineConfig.MachineInstall.DiskMatchExpression()\n\t\t\tif err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"install disk selector is invalid: %w\", err))\n\t\t\t}\n\n\t\t\tif c.MachineConfig.MachineInstall.InstallDisk == \"\" && matcher == nil {\n\t\t\t\tresult = multierror.Append(result, errors.New(\"either install disk or diskSelector should be defined\"))\n\t\t\t}\n\n\t\t\tif len(c.MachineConfig.MachineInstall.InstallExtraKernelArgs) > 0 && c.MachineConfig.MachineInstall.GrubUseUKICmdline() {\n\t\t\t\tresult = multierror.Append(result, errors.New(\"install.extraKernelArgs and install.grubUseUKICmdline can't be used together\"))\n\t\t\t}\n\t\t}\n\t}\n\n\tif mode.InContainer() {\n\t\t// require that HostDNS features are enabled to passthrough container DNS to kube-dns\n\t\tif !c.Machine().Features().HostDNS().Enabled() {\n\t\t\tresult = multierror.Append(result, errors.New(\"feature HostDNS should be enabled in container mode (.machine.features.hostDNS.enabled)\"))\n\t\t}\n\n\t\tif !c.Machine().Features().HostDNS().ForwardKubeDNSToHost() {\n\t\t\tresult = multierror.Append(result, errors.New(\"feature HostDNS should forward kube-dns to host in container mode (.machine.features.hostDNS.forwardKubeDNSToHost)\"))\n\t\t}\n\t}\n\n\tif t := c.Machine().Type(); t != machine.TypeUnknown && t.String() != c.MachineConfig.MachineType {\n\t\twarnings = append(warnings, fmt.Sprintf(\"use %q instead of %q for machine type\", t.String(), c.MachineConfig.MachineType))\n\t}\n\n\tif c.Machine().Security().IssuingCA() == nil && len(c.Machine().Security().AcceptedCAs()) == 0 {\n\t\tresult = multierror.Append(result, errors.New(\"issuing CA or some accepted CAs are required (.machine.ca, machine.acceptedCAs)\"))\n\t}\n\n\tswitch c.Machine().Type() {\n\tcase machine.TypeInit, machine.TypeControlPlane:\n\t\twarn, err := ValidateCNI(c.Cluster().Network().CNI())\n\t\twarnings = append(warnings, warn...)\n\t\tresult = multierror.Append(result, err)\n\n\t\tif c.Machine().Security().IssuingCA() == nil {\n\t\t\tresult = multierror.Append(result, errors.New(\"issuing CA is required (.machine.ca)\"))\n\t\t} else if len(c.Machine().Security().IssuingCA().Key) == 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"issuing CA key is required for controlplane nodes (.machine.ca.key)\"))\n\t\t}\n\tcase machine.TypeWorker:\n\t\tfor _, d := range c.Machine().Network().Devices() {\n\t\t\tif d.VIPConfig() != nil {\n\t\t\t\tresult = multierror.Append(result, errors.New(\"virtual (shared) IP is not allowed on non-controlplane nodes\"))\n\t\t\t}\n\n\t\t\tfor _, vlan := range d.Vlans() {\n\t\t\t\tif vlan.VIPConfig() != nil {\n\t\t\t\t\tresult = multierror.Append(result, errors.New(\"virtual (shared) IP is not allowed on non-controlplane nodes\"))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif c.Machine().Security().IssuingCA() != nil {\n\t\t\tif len(c.Machine().Security().IssuingCA().Key) > 0 {\n\t\t\t\tresult = multierror.Append(result, errors.New(\"issuing Talos API CA key is not allowed on non-controlplane nodes (.machine.ca)\"))\n\t\t\t}\n\n\t\t\tif len(c.Machine().Security().IssuingCA().Crt) == 0 && len(c.Machine().Security().AcceptedCAs()) == 0 {\n\t\t\t\tresult = multierror.Append(result, errors.New(\"trusted CA certificates are required on non-controlplane nodes (.machine.ca.crt, .machine.acceptedCAs)\"))\n\t\t\t}\n\t\t}\n\n\t\tif c.Cluster().IssuingCA() != nil && len(c.Cluster().IssuingCA().Key) > 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"issuing Kubernetes API CA key is not allowed on non-controlplane nodes (.cluster.ca)\"))\n\t\t}\n\tcase machine.TypeUnknown:\n\t\tfallthrough\n\n\tdefault:\n\t\tresult = multierror.Append(result, fmt.Errorf(\"unknown machine type %q\", c.MachineConfig.MachineType))\n\t}\n\n\tif c.MachineConfig.MachineNetwork != nil {\n\t\tallSecondaryInterfaces := map[string]string{}\n\n\t\tfor _, device := range c.MachineConfig.MachineNetwork.NetworkInterfaces {\n\t\t\tif device.Bond() != nil && device.Bridge() != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"interface has both bridge and bond sections set %q: %w\", device.Interface(), ErrMutuallyExclusive))\n\t\t\t}\n\n\t\t\tvar myInterfaces []string\n\t\t\tif device.Bond() != nil {\n\t\t\t\tmyInterfaces = device.Bond().Interfaces()\n\n\t\t\t\tif len(device.Bond().Interfaces()) > 0 && len(device.Bond().Selectors()) > 0 {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"interface %q has both interfaces and selectors set: %w\", device.Interface(), ErrMutuallyExclusive))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif device.Bridge() != nil {\n\t\t\t\tmyInterfaces = device.Bridge().Interfaces()\n\t\t\t}\n\n\t\t\tfor _, iface := range myInterfaces {\n\t\t\t\tif otherIface, exists := allSecondaryInterfaces[iface]; exists && otherIface != device.Interface() {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"interface %q is declared as part of two separate links: %q and %q\", iface, otherIface, device.Interface()))\n\t\t\t\t}\n\n\t\t\t\tallSecondaryInterfaces[iface] = device.Interface()\n\t\t\t}\n\t\t}\n\n\t\tfor _, device := range c.MachineConfig.MachineNetwork.NetworkInterfaces {\n\t\t\twarn, err := ValidateNetworkDevices(device, allSecondaryInterfaces, CheckDeviceInterface, CheckDeviceAddressing, CheckDeviceRoutes)\n\t\t\twarnings = append(warnings, warn...)\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\t\tif kcfg := c.NetworkKubeSpanConfig(); kcfg != nil && kcfg.Enabled() {\n\t\t\tif kcfg.MTU() < constants.KubeSpanLinkMinimumMTU {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"kubespan link MTU must be at least %d\", constants.KubeSpanLinkMinimumMTU))\n\t\t\t}\n\t\t}\n\t}\n\n\tfor i, disk := range c.MachineConfig.MachineDisks {\n\t\tif disk == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"machine.disks[%d] is null\", i))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tfor i, pt := range disk.DiskPartitions {\n\t\t\tif pt.DiskSize == 0 && i != len(disk.DiskPartitions)-1 {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"partition for disk %q is set to occupy full disk, but it's not the last partition in the list\", disk.Device()))\n\t\t\t}\n\t\t}\n\t}\n\n\tif c.MachineConfig.MachineKubelet != nil {\n\t\twarn, err := c.MachineConfig.MachineKubelet.Validate()\n\t\twarnings = append(warnings, warn...)\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\tfor _, label := range []string{constants.EphemeralPartitionLabel, constants.StatePartitionLabel} {\n\t\tencryptionConfig := c.MachineConfig.SystemDiskEncryption().Get(label)\n\t\tif encryptionConfig != nil {\n\t\t\tif len(encryptionConfig.Keys()) == 0 {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"partition %q: no encryption keys provided\", label))\n\t\t\t}\n\n\t\t\tslotsInUse := map[int]struct{}{}\n\t\t\tfor _, key := range encryptionConfig.Keys() {\n\t\t\t\tif _, inUse := slotsInUse[key.Slot()]; inUse {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"partition %q: encryption key slot %d is already in use\", label, key.Slot()))\n\t\t\t\t}\n\n\t\t\t\tslotsInUse[key.Slot()] = struct{}{}\n\n\t\t\t\tif key.NodeID() == nil && key.Static() == nil && key.KMS() == nil && key.TPM() == nil {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"partition %q: encryption key at slot %d doesn't have the configuration parameters\", label, key.Slot()))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif kcfg := c.NetworkKubeSpanConfig(); kcfg != nil && kcfg.Enabled() {\n\t\tif !c.Cluster().Discovery().Enabled() {\n\t\t\tresult = multierror.Append(result, errors.New(\".cluster.discovery should be enabled when .machine.network.kubespan is enabled\"))\n\t\t}\n\n\t\tif c.Cluster().ID() == \"\" {\n\t\t\tresult = multierror.Append(result, errors.New(\".cluster.id should be set when .machine.network.kubespan is enabled\"))\n\t\t}\n\n\t\tif c.Cluster().Secret() == \"\" {\n\t\t\tresult = multierror.Append(result, errors.New(\".cluster.secret should be set when .machine.network.kubespan is enabled\"))\n\t\t}\n\n\t\tfor _, cidr := range kcfg.Filters().Endpoints() {\n\t\t\tcidr = strings.TrimPrefix(cidr, \"!\")\n\n\t\t\tif _, err := sideronet.ParseSubnetOrAddress(cidr); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"KubeSpan endpoint filter is not valid: %q\", cidr))\n\t\t\t}\n\t\t}\n\n\t\tif c.MachineConfig.MachineNetwork.NetworkKubeSpan.KubeSpanFilters != nil {\n\t\t\tfor _, cidr := range c.MachineConfig.MachineNetwork.NetworkKubeSpan.KubeSpanFilters.KubeSpanFiltersExcludeAdvertisedNetworks {\n\t\t\t\t_, err := netip.ParsePrefix(cidr)\n\t\t\t\tif err != nil {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"KubeSpan exclude advertised networks filter is not valid: %q\", cidr))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif c.MachineConfig.MachineLogging != nil {\n\t\terr := c.MachineConfig.MachineLogging.Validate()\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\tif c.MachineConfig.MachineInstall != nil {\n\t\textensions := map[string]struct{}{}\n\n\t\tfor _, ext := range c.MachineConfig.MachineInstall.InstallExtensions {\n\t\t\tif _, exists := extensions[ext.Image()]; exists {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"duplicate system extension %q\", ext.Image()))\n\t\t\t}\n\n\t\t\textensions[ext.Image()] = struct{}{}\n\t\t}\n\n\t\tif len(extensions) > 0 {\n\t\t\twarnings = append(warnings, \".machine.install.extensions is deprecated, please see https://docs.siderolabs.com/talos/latest/platform-specific-installations/boot-assets\")\n\t\t}\n\t}\n\n\tif err := labels.Validate(c.MachineConfig.MachineNodeLabels); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid machine node labels: %w\", err))\n\t}\n\n\tif err := labels.ValidateAnnotations(c.MachineConfig.MachineNodeAnnotations); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid machine node annotations: %w\", err))\n\t}\n\n\tif err := labels.ValidateTaints(c.MachineConfig.MachineNodeTaints); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid machine node taints: %w\", err))\n\t}\n\n\tif c.Machine().Features().KubernetesTalosAPIAccess().Enabled() {\n\t\tif !c.Machine().Type().IsControlPlane() {\n\t\t\tresult = multierror.Append(result, errors.New(\"feature Kubernetes Talos API Access can only be enabled on control plane machines\"))\n\t\t}\n\n\t\tfor _, r := range c.Machine().Features().KubernetesTalosAPIAccess().AllowedRoles() {\n\t\t\tif !role.All.Includes(role.Role(r)) {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid role %q in allowed roles for Kubernetes Talos API Access\", r))\n\t\t\t}\n\t\t}\n\t}\n\n\tif c.MachineConfig.MachineFeatures != nil && c.MachineConfig.MachineFeatures.FeatureNodeAddressSortAlgorithm != \"\" {\n\t\tif _, err := nethelpers.AddressSortAlgorithmString(c.MachineConfig.MachineFeatures.FeatureNodeAddressSortAlgorithm); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid node address sort algorithm: %w\", err))\n\t\t}\n\t}\n\n\tif c.ConfigPersist != nil && !*c.ConfigPersist {\n\t\tresult = multierror.Append(result, errors.New(\".persist should be enabled\"))\n\t}\n\n\tif len(c.Machine().BaseRuntimeSpecOverrides()) > 0 {\n\t\t// try to unmarshal the overrides to ensure they are valid\n\t\tjsonSpec, err := json.Marshal(c.Machine().BaseRuntimeSpecOverrides())\n\t\tif err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"failed to marshal base runtime spec overrides: %w\", err))\n\t\t} else {\n\t\t\tvar ociSpec specs.Spec\n\n\t\t\tif err := json.Unmarshal(jsonSpec, &ociSpec); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"failed to unmarshal base runtime spec overrides: %w\", err))\n\t\t\t}\n\t\t}\n\t}\n\n\tfor key, val := range c.MachineConfig.MachineRegistries.RegistryConfig {\n\t\tif val == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"registries.config[%q] is null\", key))\n\t\t}\n\t}\n\n\tfor key, val := range c.MachineConfig.MachineRegistries.RegistryMirrors {\n\t\tif val == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"registries.mirrors[%q] is null\", key))\n\t\t}\n\t}\n\n\tif opts.Strict {\n\t\tfor _, w := range warnings {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"warning: %s\", w))\n\t\t}\n\n\t\twarnings = nil\n\t}\n\n\treturn warnings, result.ErrorOrNil()\n}\n\nvar rxDNSNameRegexp = sync.OnceValue(func() *regexp.Regexp {\n\treturn regexp.MustCompile(`^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\\._]?$`)\n})\n\nfunc isValidDNSName(name string) bool {\n\tif name == \"\" || len(name)-strings.Count(name, \".\") > 255 {\n\t\treturn false\n\t}\n\n\treturn rxDNSNameRegexp().MatchString(name)\n}\n\n// Validate validates the config.\n//\n//nolint:gocyclo\nfunc (c *ClusterConfig) Validate(isControlPlane bool) error {\n\tvar result *multierror.Error\n\n\tif c == nil {\n\t\treturn errors.New(\"cluster instructions are required\")\n\t}\n\n\tif c.ControlPlane == nil || c.ControlPlane.Endpoint == nil {\n\t\treturn errors.New(\"cluster controlplane endpoint is required\")\n\t}\n\n\tif err := sideronet.ValidateEndpointURI(c.ControlPlane.Endpoint.URL.String()); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"invalid controlplane endpoint: %w\", err))\n\t}\n\n\tif c.ClusterNetwork != nil && c.ClusterNetwork.DNSDomain != \"\" && !isValidDNSName(c.ClusterNetwork.DNSDomain) {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"%q is not a valid DNS name\", c.ClusterNetwork.DNSDomain))\n\t}\n\n\tif ecp := c.ExternalCloudProviderConfig; ecp != nil {\n\t\tresult = multierror.Append(result, ecp.Validate())\n\t}\n\n\tif c.EtcdConfig != nil {\n\t\tif isControlPlane {\n\t\t\tresult = multierror.Append(result, c.EtcdConfig.Validate())\n\t\t} else {\n\t\t\tresult = multierror.Append(result, errors.New(\"etcd config is only allowed on control plane machines\"))\n\t\t}\n\t}\n\n\tif c.ClusterCA != nil && !isControlPlane && len(c.ClusterCA.Key) > 0 {\n\t\tresult = multierror.Append(result, errors.New(\"cluster CA key is not allowed on non-controlplane nodes (.cluster.ca)\"))\n\t}\n\n\tresult = multierror.Append(\n\t\tresult,\n\t\tc.ClusterInlineManifests.Validate(),\n\t\tc.ClusterDiscoveryConfig.Validate(c),\n\t\tc.APIServerConfig.Validate(),\n\t\tc.ControllerManagerConfig.Validate(),\n\t\tc.SchedulerConfig.Validate(),\n\t)\n\n\treturn result.ErrorOrNil()\n}\n\n// ValidateCNI validates CNI config.\n//\n//nolint:gocyclo\nfunc ValidateCNI(cni config.CNI) ([]string, error) {\n\tvar (\n\t\twarnings []string\n\t\tresult   *multierror.Error\n\t)\n\n\tswitch cni.Name() {\n\tcase constants.FlannelCNI:\n\t\tif len(cni.URLs()) != 0 {\n\t\t\terr := fmt.Errorf(`\"urls\" field should be empty for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\tcase constants.NoneCNI:\n\t\tif len(cni.URLs()) != 0 {\n\t\t\terr := fmt.Errorf(`\"urls\" field should be empty for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\t\tif len(cni.Flannel().ExtraArgs()) != 0 {\n\t\t\terr := fmt.Errorf(`\"flanneldExtraArgs\" field should be empty for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\t\tif cni.Flannel().KubeNetworkPoliciesEnabled() {\n\t\t\terr := fmt.Errorf(`\"flannelKubeNetworkPoliciesEnabled\" should not be enabled for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\tcase constants.CustomCNI:\n\t\tif len(cni.URLs()) == 0 {\n\t\t\twarn := fmt.Sprintf(`\"urls\" field should not be empty for %q CNI`, cni.Name())\n\t\t\twarnings = append(warnings, warn)\n\t\t}\n\n\t\tif len(cni.Flannel().ExtraArgs()) != 0 {\n\t\t\terr := fmt.Errorf(`\"flanneldExtraArgs\" field should be empty for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\t\tif cni.Flannel().KubeNetworkPoliciesEnabled() {\n\t\t\terr := fmt.Errorf(`\"flannelKubeNetworkPoliciesEnabled\" should not be enabled for %q CNI`, cni.Name())\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\n\t\tfor _, u := range cni.URLs() {\n\t\t\tif err := sideronet.ValidateEndpointURI(u); err != nil {\n\t\t\t\tresult = multierror.Append(result, err)\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\terr := fmt.Errorf(\"cni name should be one of [%q, %q, %q]\", constants.FlannelCNI, constants.CustomCNI, constants.NoneCNI)\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\treturn warnings, result.ErrorOrNil()\n}\n\n// Validate validates external cloud provider configuration.\nfunc (ecp *ExternalCloudProviderConfig) Validate() error {\n\tif !ecp.Enabled() && (len(ecp.ExternalManifests) != 0) {\n\t\treturn errors.New(\"external cloud provider is disabled, but manifests are provided\")\n\t}\n\n\tvar result *multierror.Error\n\n\tfor _, url := range ecp.ExternalManifests {\n\t\tif err := sideronet.ValidateEndpointURI(url); err != nil {\n\t\t\terr = fmt.Errorf(\"invalid external cloud provider manifest url %q: %w\", url, err)\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\n// Validate the inline manifests.\nfunc (manifests ClusterInlineManifests) Validate() error {\n\tvar result *multierror.Error\n\n\tmanifestNames := map[string]struct{}{}\n\n\tfor _, manifest := range manifests {\n\t\tif strings.TrimSpace(manifest.InlineManifestName) == \"\" {\n\t\t\tresult = multierror.Append(result, errors.New(\"inline manifest name can't be empty\"))\n\t\t}\n\n\t\tif _, ok := manifestNames[manifest.InlineManifestName]; ok {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"inline manifest name %q is duplicate\", manifest.InlineManifestName))\n\t\t}\n\n\t\tmanifestNames[manifest.InlineManifestName] = struct{}{}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\n// Validate the discovery config.\nfunc (c *ClusterDiscoveryConfig) Validate(clusterCfg *ClusterConfig) error {\n\tvar result *multierror.Error\n\n\tif c == nil || !c.Enabled() {\n\t\treturn nil\n\t}\n\n\tif c.Registries().Service().Enabled() {\n\t\turl, err := url.ParseRequestURI(c.Registries().Service().Endpoint())\n\t\tif err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"cluster discovery service registry endpoint is invalid: %w\", err))\n\t\t} else if url.Path != \"\" && url.Path != \"/\" {\n\t\t\tresult = multierror.Append(result, errors.New(\"cluster discovery service path should be empty\"))\n\t\t}\n\n\t\tif clusterCfg.ID() == \"\" {\n\t\t\tresult = multierror.Append(result, errors.New(\"cluster discovery service requires .cluster.id\"))\n\t\t}\n\n\t\tif clusterCfg.Secret() == \"\" {\n\t\t\tresult = multierror.Append(result, errors.New(\"cluster discovery service requires .cluster.secret\"))\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\n// ValidateNetworkDevices runs the specified validation checks specific to the\n// network devices.\nfunc ValidateNetworkDevices(d *Device, secondaryInterfaces map[string]string, checks ...NetworkDeviceCheck) ([]string, error) {\n\tvar result *multierror.Error\n\n\tif d == nil {\n\t\treturn nil, errors.New(\"empty device\")\n\t}\n\n\tif d.Ignore() {\n\t\treturn nil, result.ErrorOrNil()\n\t}\n\n\tvar warnings []string\n\n\tfor _, check := range checks {\n\t\twarn, err := check(d, secondaryInterfaces)\n\t\twarnings = append(warnings, warn...)\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\treturn warnings, result.ErrorOrNil()\n}\n\n// CheckDeviceInterface ensures that the interface has been specified.\n//\n//nolint:gocyclo\nfunc CheckDeviceInterface(d *Device, _ map[string]string) ([]string, error) {\n\tvar result *multierror.Error\n\n\tif d == nil {\n\t\treturn nil, errors.New(\"empty device\")\n\t}\n\n\tif d.DeviceInterface == \"\" && d.DeviceSelector == nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s], [%s]: %w\", \"networking.os.device.interface\", \"networking.os.device.deviceSelector\", ErrRequiredSectionOptions))\n\t} else if d.DeviceInterface != \"\" && d.DeviceSelector != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s], [%s]: %w\", \"networking.os.device.interface\", \"networking.os.device.deviceSelector\", ErrMutuallyExclusive))\n\t}\n\n\tif d.DeviceSelector != nil && reflect.ValueOf(d.DeviceSelector).Elem().IsZero() {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s]: %w\", \"networking.os.device.deviceSelector\", ErrEmpty))\n\t}\n\n\tif d.DeviceBond != nil {\n\t\tresult = multierror.Append(result, checkBond(d.DeviceBond))\n\t}\n\n\tif d.DeviceWireguardConfig != nil {\n\t\tresult = multierror.Append(result, checkWireguard(d.DeviceWireguardConfig))\n\t}\n\n\tif d.DeviceVlans != nil {\n\t\tresult = multierror.Append(result, checkVlans(d))\n\t}\n\n\treturn nil, result.ErrorOrNil()\n}\n\n//nolint:gocyclo,cyclop\nfunc checkBond(b *Bond) error {\n\tvar result *multierror.Error\n\n\tbondMode, err := nethelpers.BondModeByName(b.BondMode)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.BondXmitHashPolicyByName(b.BondHashPolicy)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.LACPRateByName(b.BondLACPRate)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.ARPValidateByName(b.BondARPValidate)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.ARPAllTargetsByName(b.BondARPAllTargets)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.PrimaryReselectByName(b.BondPrimaryReselect)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.FailOverMACByName(b.BondFailOverMac)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\t_, err = nethelpers.ADSelectByName(b.BondADSelect)\n\tif err != nil {\n\t\tresult = multierror.Append(result, err)\n\t}\n\n\tif b.BondMIIMon == 0 {\n\t\tif b.BondUpDelay != 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"bond.upDelay can't be set if miiMon is zero\"))\n\t\t}\n\n\t\tif b.BondDownDelay != 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"bond.downDelay can't be set if miiMon is zero\"))\n\t\t}\n\t} else {\n\t\tif b.BondUpDelay%b.BondMIIMon != 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"bond.upDelay should be a multiple of miiMon\"))\n\t\t}\n\n\t\tif b.BondDownDelay%b.BondMIIMon != 0 {\n\t\t\tresult = multierror.Append(result, errors.New(\"bond.downDelay should be a multiple of miiMon\"))\n\t\t}\n\t}\n\n\tif len(b.BondARPIPTarget) > 0 {\n\t\tresult = multierror.Append(result, errors.New(\"bond.arpIPTarget is not supported\"))\n\t}\n\n\tif b.BondLACPRate != \"\" && bondMode != nethelpers.BondMode8023AD {\n\t\tresult = multierror.Append(result, errors.New(\"bond.lacpRate is only available in 802.3ad mode\"))\n\t}\n\n\tif b.BondADActorSystem != \"\" {\n\t\tresult = multierror.Append(result, errors.New(\"bond.adActorSystem is not supported\"))\n\t}\n\n\tif (bondMode == nethelpers.BondMode8023AD || bondMode == nethelpers.BondModeALB || bondMode == nethelpers.BondModeTLB) && b.BondARPValidate != \"\" {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"bond.arpValidate is not available in %s mode\", bondMode))\n\t}\n\n\tif !(bondMode == nethelpers.BondModeActiveBackup || bondMode == nethelpers.BondModeALB || bondMode == nethelpers.BondModeTLB) && b.BondPrimary != \"\" {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"bond.primary is not available in %s mode\", bondMode))\n\t}\n\n\tif (bondMode == nethelpers.BondMode8023AD || bondMode == nethelpers.BondModeALB || bondMode == nethelpers.BondModeTLB) && b.BondARPInterval > 0 {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"bond.arpInterval is not available in %s mode\", bondMode))\n\t}\n\n\tif bondMode != nethelpers.BondModeRoundrobin && b.BondPacketsPerSlave > 1 {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"bond.packetsPerSlave is not available in %s mode\", bondMode))\n\t}\n\n\tif !(bondMode == nethelpers.BondModeALB || bondMode == nethelpers.BondModeTLB) && b.BondTLBDynamicLB > 0 {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"bond.tlbDynamicTLB is not available in %s mode\", bondMode))\n\t}\n\n\tif bondMode != nethelpers.BondMode8023AD && b.BondADActorSysPrio > 0 {\n\t\tresult = multierror.Append(result, errors.New(\"bond.adActorSysPrio is only available in 802.3ad mode\"))\n\t}\n\n\tif bondMode != nethelpers.BondMode8023AD && b.BondADUserPortKey > 0 {\n\t\tresult = multierror.Append(result, errors.New(\"bond.adUserPortKey is only available in 802.3ad mode\"))\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\nfunc checkWireguard(b *DeviceWireguardConfig) error {\n\tvar result *multierror.Error\n\n\t// avoid pulling in wgctrl code to keep machinery dependencies slim\n\tcheckKey := func(key string) error {\n\t\traw, err := base64.StdEncoding.DecodeString(key)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif len(raw) != 32 {\n\t\t\treturn fmt.Errorf(\"wrong key %q length: %d\", key, len(raw))\n\t\t}\n\n\t\treturn nil\n\t}\n\tif err := checkKey(b.WireguardPrivateKey); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"private key is invalid: %w\", err))\n\t}\n\n\tfor _, peer := range b.WireguardPeers {\n\t\tif err := checkKey(peer.WireguardPublicKey); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"public key invalid: %w\", err))\n\t\t}\n\n\t\tif peer.WireguardEndpoint != \"\" {\n\t\t\tif !sideronet.AddressContainsPort(peer.WireguardEndpoint) {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"peer endpoint %q is invalid\", peer.WireguardEndpoint))\n\t\t\t}\n\t\t}\n\n\t\tfor _, allowedIP := range peer.WireguardAllowedIPs {\n\t\t\tif _, _, err := net.ParseCIDR(allowedIP); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"peer allowed IP %q is invalid: %w\", allowedIP, err))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\nfunc checkVlans(d *Device) error {\n\tvar result *multierror.Error\n\n\t// check VLAN addressing\n\tfor _, vlan := range d.DeviceVlans {\n\t\tif len(vlan.VlanAddresses) > 0 && vlan.VlanCIDR != \"\" {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %s.%d: %s\", \"networking.os.device.vlan\", d.DeviceInterface, vlan.VlanID, \"vlan can't have both .cidr and .addresses set\"))\n\t\t}\n\n\t\tif vlan.VlanCIDR != \"\" {\n\t\t\tif err := validateIPOrCIDR(vlan.VlanCIDR); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %s.%d: %w\", \"networking.os.device.vlan.CIDR\", d.DeviceInterface, vlan.VlanID, err))\n\t\t\t}\n\t\t}\n\n\t\tfor _, address := range vlan.VlanAddresses {\n\t\t\tif err := validateIPOrCIDR(address); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %s.%d: %w\", \"networking.os.device.vlan.addresses\", d.DeviceInterface, vlan.VlanID, err))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\nfunc validateIPOrCIDR(address string) error {\n\tif strings.IndexByte(address, '/') >= 0 {\n\t\t_, _, err := net.ParseCIDR(address)\n\n\t\treturn err\n\t}\n\n\tif ip := net.ParseIP(address); ip == nil {\n\t\treturn fmt.Errorf(\"failed to parse IP address %q\", address)\n\t}\n\n\treturn nil\n}\n\n// CheckDeviceAddressing ensures that an appropriate addressing method.\n// has been specified.\n//\n//nolint:gocyclo\nfunc CheckDeviceAddressing(d *Device, secondaryInterfaces map[string]string) ([]string, error) {\n\tvar result *multierror.Error\n\n\tif d == nil {\n\t\treturn nil, errors.New(\"empty device\")\n\t}\n\n\tvar warnings []string\n\n\tif _, paired := secondaryInterfaces[d.Interface()]; paired {\n\t\tif d.DHCP() || d.DeviceCIDR != \"\" || len(d.DeviceAddresses) > 0 || d.DeviceVIPConfig != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %s\", \"networking.os.device\", d.DeviceInterface, \"bonded/bridged interface shouldn't have any addressing methods configured\"))\n\t\t}\n\t}\n\n\t// ensure either legacy CIDR is set or new addresses, but not both\n\tif len(d.DeviceAddresses) > 0 && d.DeviceCIDR != \"\" {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %s\", \"networking.os.device\", d.DeviceInterface, \"interface can't have both .cidr and .addresses set\"))\n\t}\n\n\t// ensure cidr is a valid address\n\tif d.DeviceCIDR != \"\" {\n\t\tif err := validateIPOrCIDR(d.DeviceCIDR); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %w\", \"networking.os.device.CIDR\", d.DeviceInterface, err))\n\t\t}\n\n\t\twarnings = append(warnings, fmt.Sprintf(\"%q: machine.network.interface.cidr is deprecated, please use machine.network.interface.addresses\", d.DeviceInterface))\n\t}\n\n\t// ensure addresses are valid addresses\n\tfor _, address := range d.DeviceAddresses {\n\t\tif err := validateIPOrCIDR(address); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %w\", \"networking.os.device.addresses\", d.DeviceInterface, err))\n\t\t}\n\t}\n\n\t// check VIP IP is valid\n\tif d.DeviceVIPConfig != nil {\n\t\tif ip := net.ParseIP(d.DeviceVIPConfig.IP()); ip == nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] failed to parse %q as IP address\", \"networking.os.device.vip\", d.DeviceVIPConfig.IP()))\n\t\t}\n\t}\n\n\treturn warnings, result.ErrorOrNil()\n}\n\n// CheckDeviceRoutes ensures that the specified routes are valid.\n//\n//nolint:gocyclo\nfunc CheckDeviceRoutes(d *Device, _ map[string]string) ([]string, error) {\n\tvar result *multierror.Error\n\n\tif d == nil {\n\t\treturn nil, errors.New(\"empty device\")\n\t}\n\n\tif len(d.DeviceRoutes) == 0 {\n\t\treturn nil, result.ErrorOrNil()\n\t}\n\n\tfor idx, route := range d.DeviceRoutes {\n\t\tif route.Network() != \"\" {\n\t\t\tif _, _, err := net.ParseCIDR(route.Network()); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %w\", \"networking.os.device.route[\"+strconv.Itoa(idx)+\"].network\", route.Network(), ErrInvalidAddress))\n\t\t\t}\n\t\t}\n\n\t\tif route.Gateway() != \"\" {\n\t\t\tif ip := net.ParseIP(route.Gateway()); ip == nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %w\", \"networking.os.device.route[\"+strconv.Itoa(idx)+\"].gateway\", route.Gateway(), ErrInvalidAddress))\n\t\t\t}\n\t\t}\n\n\t\tif route.Gateway() == \"\" && route.Network() == \"\" {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s]: %s\", \"networking.os.device.route[\"+strconv.Itoa(idx)+\"]\", \"either network or gateway should be set\"))\n\t\t}\n\n\t\tif route.Source() != \"\" {\n\t\t\tif ip := net.ParseIP(route.Source()); ip == nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"[%s] %q: %w\", \"networking.os.device.route[\"+strconv.Itoa(idx)+\"].source\", route.Source(), ErrInvalidAddress))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, result.ErrorOrNil()\n}\n\n// Validate kubelet configuration.\nfunc (k *KubeletConfig) Validate() ([]string, error) {\n\tvar result *multierror.Error\n\n\tif k.KubeletNodeIP != nil {\n\t\tfor _, cidr := range k.KubeletNodeIP.KubeletNodeIPValidSubnets {\n\t\t\tcidr = strings.TrimPrefix(cidr, \"!\")\n\n\t\t\tif _, err := sideronet.ParseSubnetOrAddress(cidr); err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"kubelet nodeIP subnet is not valid: %q\", cidr))\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, field := range kubelet.ProtectedConfigurationFields {\n\t\tif _, exists := k.KubeletExtraConfig.Object[field]; exists {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"kubelet configuration field %q can't be overridden\", field))\n\t\t}\n\t}\n\n\treturn nil, result.ErrorOrNil()\n}\n\n// Validate etcd configuration.\nfunc (e *EtcdConfig) Validate() error {\n\tvar result *multierror.Error\n\n\tif e.CA() == nil {\n\t\tresult = multierror.Append(result, ErrEmptyKeyCert)\n\t}\n\n\tif e.EtcdSubnet != \"\" && len(e.EtcdAdvertisedSubnets) > 0 {\n\t\tresult = multierror.Append(result, errors.New(\"etcd subnet can't be set when advertised subnets are set\"))\n\t}\n\n\tfor _, cidr := range e.AdvertisedSubnets() {\n\t\tcidr = strings.TrimPrefix(cidr, \"!\")\n\n\t\tif _, err := sideronet.ParseSubnetOrAddress(cidr); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"etcd advertised subnet is not valid: %q\", cidr))\n\t\t}\n\t}\n\n\tfor _, cidr := range e.ListenSubnets() {\n\t\tcidr = strings.TrimPrefix(cidr, \"!\")\n\n\t\tif _, err := sideronet.ParseSubnetOrAddress(cidr); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"etcd listen subnet is not valid: %q\", cidr))\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n\n// RuntimeValidate validates the config in runtime context.\n//\n// In runtime context, resource state is available.\n//\n//nolint:gocyclo\nfunc (c *Config) RuntimeValidate(ctx context.Context, st state.State, mode validation.RuntimeMode, opt ...validation.Option) ([]string, error) {\n\tvar (\n\t\twarnings []string\n\t\tresult   *multierror.Error\n\t)\n\n\tif c.MachineConfig != nil {\n\t\tif mode.RequiresInstall() && c.MachineConfig.MachineInstall != nil {\n\t\t\tdiskExpr, err := c.MachineConfig.MachineInstall.DiskMatchExpression()\n\t\t\tif err != nil {\n\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"install disk selector is invalid: %w\", err))\n\t\t\t} else if diskExpr != nil {\n\t\t\t\tmatchedDisks, err := blockhelpers.MatchDisks(ctx, st, diskExpr)\n\t\t\t\tif err != nil {\n\t\t\t\t\tresult = multierror.Append(result, err)\n\t\t\t\t}\n\n\t\t\t\tif len(matchedDisks) == 0 {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"no disks matched the expression: %s\", diskExpr))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if booted using sd-boot, extra kernel arguments are not supported\n\t\tif _, err := os.Stat(\"/sys/firmware/efi/efivars/StubInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f\"); err == nil {\n\t\t\tif len(c.MachineConfig.Install().ExtraKernelArgs()) > 0 {\n\t\t\t\twarnings = append(warnings, \"extra kernel arguments are not supported when booting using SDBoot\")\n\t\t\t}\n\t\t}\n\n\t\tif len(c.MachineConfig.Install().Extensions()) > 0 {\n\t\t\twarnings = append(warnings, \".machine.install.extensions is deprecated, please see https://docs.siderolabs.com/talos/latest/platform-specific-installations/boot-assets\")\n\t\t}\n\n\t\tif err := ValidateKubernetesImageTag(c.Machine().Kubelet().Image()); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"kubelet image is not valid: %w\", err))\n\t\t}\n\t}\n\n\tif c.ClusterConfig != nil && c.MachineConfig != nil {\n\t\tif c.Machine().Type().IsControlPlane() {\n\t\t\tfor _, spec := range []struct {\n\t\t\t\tname     string\n\t\t\t\timageRef string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tname:     \"kube-apiserver\",\n\t\t\t\t\timageRef: c.Cluster().APIServer().Image(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:     \"kube-controller-manager\",\n\t\t\t\t\timageRef: c.Cluster().ControllerManager().Image(),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname:     \"kube-scheduler\",\n\t\t\t\t\timageRef: c.Cluster().Scheduler().Image(),\n\t\t\t\t},\n\t\t\t} {\n\t\t\t\tif err := ValidateKubernetesImageTag(spec.imageRef); err != nil {\n\t\t\t\t\tresult = multierror.Append(result, fmt.Errorf(\"%s image is not valid: %w\", spec.name, err))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn warnings, result.ErrorOrNil()\n}\n\n// ValidateKubernetesImageTag validates the Kubernetes image tag format.\nfunc ValidateKubernetesImageTag(imageRef string) error {\n\t// this method is called from RuntimeValidate, so we are inside running Talos,\n\t// so the version of Talos is available, and we can check compatibility\n\tcurrentTalosVersion, err := compatibility.ParseTalosVersion(version.NewVersion())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse Talos version: %w\", err)\n\t}\n\n\tk8sVersion, err := KubernetesVersionFromImageRef(imageRef)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse Kubernetes version from image reference %q: %w\", imageRef, err)\n\t}\n\n\treturn k8sVersion.SupportedWith(currentTalosVersion)\n}\n\n// KubernetesVersionFromImageRef parses the Kubernetes version from the image reference.\nfunc KubernetesVersionFromImageRef(ref string) (*compatibility.KubernetesVersion, error) {\n\tidx := strings.LastIndex(ref, \":v\")\n\tif idx == -1 {\n\t\treturn nil, fmt.Errorf(\"invalid image reference: %q\", ref)\n\t}\n\n\tversionPart := ref[idx+2:]\n\n\tif shaIndex := strings.Index(versionPart, \"@\"); shaIndex != -1 {\n\t\tversionPart = versionPart[:shaIndex]\n\t}\n\n\treturn compatibility.ParseKubernetesVersion(versionPart)\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/v1alpha1_validation_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/compatibility\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/validation\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\ntype runtimeMode struct {\n\trequiresInstall bool\n}\n\nfunc (m runtimeMode) String() string {\n\treturn fmt.Sprintf(\"runtimeMode(%v)\", m.requiresInstall)\n}\n\nfunc (m runtimeMode) RequiresInstall() bool {\n\treturn m.requiresInstall\n}\n\nfunc (runtimeMode) InContainer() bool {\n\treturn false\n}\n\nfunc TestValidate(t *testing.T) {\n\tt.Parallel()\n\n\tendpointURL, err := url.Parse(\"https://localhost:6443/\")\n\trequire.NoError(t, err)\n\n\tfor _, test := range []struct {\n\t\tname             string\n\t\tconfig           *v1alpha1.Config\n\t\trequiresInstall  bool\n\t\tstrict           bool\n\t\texpectedWarnings []string\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\tname: \"NoMachine\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* machine instructions are required\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"NoMachineType\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedWarnings: []string{\n\t\t\t\t`use \"worker\" instead of \"\" for machine type`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"JoinMachineType\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"join\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedWarnings: []string{\n\t\t\t\t`use \"worker\" instead of \"join\" for machine type`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoMachineTypeStrict\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tstrict:        true,\n\t\t\texpectedError: \"1 error occurred:\\n\\t* warning: use \\\"worker\\\" instead of \\\"\\\" for machine type\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"WorkerNoAcceptedCAs\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA:   &x509.PEMEncodedCertificateAndKey{},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tstrict:        true,\n\t\t\texpectedError: \"1 error occurred:\\n\\t* trusted CA certificates are required on non-controlplane nodes (.machine.ca.crt, .machine.acceptedCAs)\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"WorkerOnlyAcceptedCAs\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineAcceptedCAs: []*x509.PEMEncodedCertificate{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tstrict: true,\n\t\t},\n\t\t{\n\t\t\tname: \"ControlplaneNoCAKey\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tstrict:        true,\n\t\t\texpectedError: \"1 error occurred:\\n\\t* issuing CA key is required for controlplane nodes (.machine.ca.key)\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"NoMachineInstall\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoMachineInstallRequired\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\trequiresInstall: true,\n\t\t\texpectedError:   \"1 error occurred:\\n\\t* install instructions are required in \\\"runtimeMode(true)\\\" mode\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"MachineInstallDisk\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineInstall: &v1alpha1.InstallConfig{\n\t\t\t\t\t\tInstallDisk: \"/dev/vda\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\trequiresInstall: true,\n\t\t},\n\t\t{\n\t\t\tname: \"MachineInstallExtensionsDuplicate\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineInstall: &v1alpha1.InstallConfig{\n\t\t\t\t\t\tInstallDisk: \"/dev/vda\",\n\t\t\t\t\t\tInstallExtensions: []v1alpha1.InstallExtensionConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tExtensionImage: \"ghcr.io/siderolabs/gvisor:v0.1.0\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\trequiresInstall: true,\n\t\t\texpectedWarnings: []string{\n\t\t\t\t\".machine.install.extensions is deprecated, please see https://docs.siderolabs.com/talos/latest/platform-specific-installations/boot-assets\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MachineInstallExtraArgsAndGrubUseUKICmdline\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineInstall: &v1alpha1.InstallConfig{\n\t\t\t\t\t\tInstallDisk:              \"/dev/vda\",\n\t\t\t\t\t\tInstallExtraKernelArgs:   []string{\"foo=bar\"},\n\t\t\t\t\t\tInstallGrubUseUKICmdline: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\trequiresInstall: true,\n\t\t\texpectedError:   \"1 error occurred:\\n\\t* install.extraKernelArgs and install.grubUseUKICmdline can't be used together\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"ExternalCloudProviderEnabled\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalEnabled: new(true),\n\t\t\t\t\t\tExternalManifests: []string{\n\t\t\t\t\t\t\t\"https://www.example.com/manifest1.yaml\",\n\t\t\t\t\t\t\t\"https://www.example.com/manifest2.yaml\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ExternalCloudProviderEnabledNoManifests\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ExternalCloudProviderDisabled\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ExternalCloudProviderExtraManifests\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalManifests: []string{\n\t\t\t\t\t\t\t\"https://www.example.com/manifest1.yaml\",\n\t\t\t\t\t\t\t\"https://www.example.com/manifest2.yaml\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* external cloud provider is disabled, but manifests are provided\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"ExternalCloudProviderInvalidManifests\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{\n\t\t\t\t\t\tExternalEnabled: new(true),\n\t\t\t\t\t\tExternalManifests: []string{\n\t\t\t\t\t\t\t\"/manifest.yaml\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* invalid external cloud provider manifest url \\\"/manifest.yaml\\\": hostname must not be blank\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"InlineManifests\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterInlineManifests: v1alpha1.ClusterInlineManifests{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInlineManifestName: \"\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInlineManifestName: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInlineManifestName: \"bar\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tInlineManifestName: \"foo\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* inline manifest name can't be empty\\n\\t* inline manifest name \\\"foo\\\" is duplicate\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DNSDomainEmpty\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterNetwork: &v1alpha1.ClusterNetworkConfig{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceCIDRInvalid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"10.3.x\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError:    \"1 error occurred:\\n\\t* [networking.os.device.CIDR] \\\"eth0\\\": failed to parse IP address \\\"10.3.x\\\"\\n\\n\",\n\t\t\texpectedWarnings: []string{\"\\\"eth0\\\": machine.network.interface.cidr is deprecated, please use machine.network.interface.addresses\"},\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceAddressInvalid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\n\t\t\t\t\t\t\t\t\t\"192.168.0.5/24\",\n\t\t\t\t\t\t\t\t\t\"10.35.7.8\",\n\t\t\t\t\t\t\t\t\t\"10.3.x/24\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.addresses] \\\"eth0\\\": invalid CIDR address: 10.3.x/24\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceAddressAndCIDR\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"192.24.3.45\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\n\t\t\t\t\t\t\t\t\t\"192.168.0.5/24\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError:    \"1 error occurred:\\n\\t* [networking.os.device] \\\"eth0\\\": interface can't have both .cidr and .addresses set\\n\\n\",\n\t\t\texpectedWarnings: []string{\"\\\"eth0\\\": machine.network.interface.cidr is deprecated, please use machine.network.interface.addresses\"},\n\t\t},\n\t\t{\n\t\t\tname: \"VlanCIDRInvalid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:   25,\n\t\t\t\t\t\t\t\t\t\tVlanCIDR: \"10.3.x\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.vlan.CIDR] eth0.25: failed to parse IP address \\\"10.3.x\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"VlanAddressInvalid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID: 25,\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"192.168.0.5/24\",\n\t\t\t\t\t\t\t\t\t\t\t\"10.35.7.8\",\n\t\t\t\t\t\t\t\t\t\t\t\"10.3.x/24\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.vlan.addresses] eth0.25: invalid CIDR address: 10.3.x/24\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"VlanAddressAndCIDR\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceVlans: []*v1alpha1.Vlan{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tVlanID:   26,\n\t\t\t\t\t\t\t\t\t\tVlanCIDR: \"192.24.3.45\",\n\t\t\t\t\t\t\t\t\t\tVlanAddresses: []string{\n\t\t\t\t\t\t\t\t\t\t\t\"192.168.0.5/24\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.vlan] eth0.26: vlan can't have both .cidr and .addresses set\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"BondDefaultConfig\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond:      &v1alpha1.Bond{},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"BondWrongMode\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondMode:            \"roundrobin\",\n\t\t\t\t\t\t\t\t\tBondUpDelay:         100,\n\t\t\t\t\t\t\t\t\tBondPacketsPerSlave: 8,\n\t\t\t\t\t\t\t\t\tBondADActorSysPrio:  48,\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"3 errors occurred:\\n\\t* invalid bond type roundrobin\\n\\t* bond.upDelay can't be set if miiMon is zero\\n\\t* bond.adActorSysPrio is only available in 802.3ad mode\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"BondInterfacesAndSelectors\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tBondDeviceSelectors: []v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tNetworkDeviceKernelDriver: \"virtio\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* interface \\\"bond0\\\" has both interfaces and selectors set: config sections are mutually exclusive\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"BondDoubleBond\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond1\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* interface \\\"eth1\\\" is declared as part of two separate links: \\\"bond0\\\" and \\\"bond1\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"BondSlaveAddressing\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\n\t\t\t\t\t\t\t\t\t\"192.168.0.1/24\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"192.168.1.1/24\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"3 errors occurred:\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth0\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth1\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth2\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\n\",\n\t\t\texpectedWarnings: []string{\n\t\t\t\t\"\\\"eth2\\\": machine.network.interface.cidr is deprecated, please use machine.network.interface.addresses\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"BridgeSlaveAddressing\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceDHCP:      new(true),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth1\",\n\t\t\t\t\t\t\t\tDeviceAddresses: []string{\n\t\t\t\t\t\t\t\t\t\"192.168.0.1/24\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth2\",\n\t\t\t\t\t\t\t\tDeviceCIDR:      \"192.168.1.1/24\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"3 errors occurred:\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth0\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth1\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\t* [networking.os.device] \\\"eth2\\\": bonded/bridged interface shouldn't have any addressing methods configured\\n\" +\n\t\t\t\t\"\\n\",\n\t\t\texpectedWarnings: []string{\n\t\t\t\t\"\\\"eth2\\\": machine.network.interface.cidr is deprecated, please use machine.network.interface.addresses\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"BridgeDoubleBridge\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br1\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* interface \\\"eth1\\\" is declared as part of two separate links: \\\"br0\\\" and \\\"br1\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"InterfaceIsBothBridgeAndBond\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bridgebond0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t\t\"eth3\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* interface has both bridge and bond sections set \\\"bridgebond0\\\": config sections are mutually exclusive\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"InterfacePartOfBridgeAndBond\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"br0\",\n\t\t\t\t\t\t\t\tDeviceBridge: &v1alpha1.Bridge{\n\t\t\t\t\t\t\t\t\tBridgedInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth0\",\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"bond0\",\n\t\t\t\t\t\t\t\tDeviceBond: &v1alpha1.Bond{\n\t\t\t\t\t\t\t\t\tBondInterfaces: []string{\n\t\t\t\t\t\t\t\t\t\t\"eth1\",\n\t\t\t\t\t\t\t\t\t\t\"eth2\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* interface \\\"eth1\\\" is declared as part of two separate links: \\\"br0\\\" and \\\"bond0\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"Wireguard\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"wireguard0\",\n\t\t\t\t\t\t\t\tDeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{\n\t\t\t\t\t\t\t\t\tWireguardPrivateKey: \"ONtS+jU1Q+ZHLgs7DbYvnF5Iyj+koxBtvknDigFsdG8=\",\n\t\t\t\t\t\t\t\t\tWireguardPeers: []*v1alpha1.DeviceWireguardPeer{\n\t\t\t\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tWireguardPublicKey: \"4A3rogGVHuVjeZz5cbqryWXGkGBdIGC0E6+5mX2Iz1A=\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardEndpoint:  \"example.com:1234\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardAllowedIPs: []string{\n\t\t\t\t\t\t\t\t\t\t\t\t\"10.2.0.5/31\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"2.4.5.3/32\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tWireguardPublicKey: \"4A3rogGVHuVjeZz5cbqryWXGkGBdIGC0E6+5mX2Iz1==\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardEndpoint:  \"12.3.4.5\",\n\t\t\t\t\t\t\t\t\t\t\tWireguardAllowedIPs: []string{\n\t\t\t\t\t\t\t\t\t\t\t\t\"10.2.0\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"4 errors occurred:\\n\\t* public key invalid: wrong key \\\"\\\" length: 0\\n\\t* public key invalid: wrong key \\\"4A3rogGVHuVjeZz5cbqryWXGkGBdIGC0E6+5mX2Iz1==\\\" length: 31\\n\" +\n\t\t\t\t\"\\t* peer endpoint \\\"12.3.4.5\\\" is invalid\\n\\t* peer allowed IP \\\"10.2.0\\\" is invalid: invalid CIDR address: 10.2.0\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"StaticRoutes\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceRoutes: []*v1alpha1.Route{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"172.0.0.1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"10.0.0.0/24\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"10.0.0.1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"10.0.0.0/24\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"10.0.0.1\",\n\t\t\t\t\t\t\t\t\t\tRouteSource:  \"10.0.0.5\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"172.0.0.x\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"10.0.0.0\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"10.0.0.1\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"10.0.0.0/24\",\n\t\t\t\t\t\t\t\t\t\tRouteGateway: \"10.0.0.1\",\n\t\t\t\t\t\t\t\t\t\tRouteSource:  \"10.0.0.3/32\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteNetwork: \"169.254.254.254/32\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tRouteSource: \"10.0.0.3\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"4 errors occurred:\\n\\t* [networking.os.device.route[3].gateway] \\\"172.0.0.x\\\": invalid network address\\n\" +\n\t\t\t\t\"\\t* [networking.os.device.route[4].network] \\\"10.0.0.0\\\": invalid network address\\n\" +\n\t\t\t\t\"\\t* [networking.os.device.route[5].source] \\\"10.0.0.3/32\\\": invalid network address\\n\" +\n\t\t\t\t\"\\t* [networking.os.device.route[7]]: either network or gateway should be set\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"KubeSpanNoDiscovery\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"3 errors occurred:\\n\\t* .cluster.discovery should be enabled when .machine.network.kubespan is enabled\\n\" +\n\t\t\t\t\"\\t* .cluster.id should be set when .machine.network.kubespan is enabled\\n\" +\n\t\t\t\t\"\\t* .cluster.secret should be set when .machine.network.kubespan is enabled\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DiscoveryServiceEndpoint\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tClusterID:     \"foo\",\n\t\t\t\t\tClusterSecret: \"bar\",\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t\tDiscoveryRegistries: v1alpha1.DiscoveryRegistriesConfig{\n\t\t\t\t\t\t\tRegistryService: v1alpha1.RegistryServiceConfig{\n\t\t\t\t\t\t\t\tRegistryEndpoint: \"foo\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* cluster discovery service registry endpoint is invalid: parse \\\"foo\\\": invalid URI for request\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DiscoveryServiceClusterIDSecret\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* cluster discovery service requires .cluster.id\\n\\t* cluster discovery service requires .cluster.secret\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"EtcdMissingCa\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tEtcdConfig: &v1alpha1.EtcdConfig{},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* key/cert combination should not be empty\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"EtcdConfigProvidedForWorker\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tEtcdConfig: &v1alpha1.EtcdConfig{},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* etcd config is only allowed on control plane machines\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"GoodEtcdSubnet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tEtcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\t\t\tRootCA: &x509.PEMEncodedCertificateAndKey{},\n\t\t\t\t\t\tEtcdAdvertisedSubnets: []string{\n\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\"!1.1.1.1/32\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tEtcdListenSubnets: []string{\n\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\"1.1.1.1/32\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"BadEtcdSubnet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tEtcdConfig: &v1alpha1.EtcdConfig{\n\t\t\t\t\t\tRootCA: &x509.PEMEncodedCertificateAndKey{},\n\t\t\t\t\t\tEtcdAdvertisedSubnets: []string{\n\t\t\t\t\t\t\t\"1234:\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tEtcdListenSubnets: []string{\n\t\t\t\t\t\t\t\"10\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* etcd advertised subnet is not valid: \\\"1234:\\\"\\n\\t* etcd listen subnet is not valid: \\\"10\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"GoodKubeletSubnet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletNodeIP: &v1alpha1.KubeletNodeIPConfig{\n\t\t\t\t\t\t\tKubeletNodeIPValidSubnets: []string{\n\t\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\t\"!10.0.0.3/32\",\n\t\t\t\t\t\t\t\t\"!fd00::169:254:2:53/128\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"BadKubeletSubnet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletNodeIP: &v1alpha1.KubeletNodeIPConfig{\n\t\t\t\t\t\t\tKubeletNodeIPValidSubnets: []string{\n\t\t\t\t\t\t\t\t\"10.0.0.0.3\",\n\t\t\t\t\t\t\t\t\"[fd00::169:254:2:53]:344\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\" +\n\t\t\t\t\"\\t* kubelet nodeIP subnet is not valid: \\\"10.0.0.0.3\\\"\\n\" +\n\t\t\t\t\"\\t* kubelet nodeIP subnet is not valid: \\\"[fd00::169:254:2:53]:344\\\"\\n\" +\n\t\t\t\t\"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"BadKubeletExtraConfig\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineAcceptedCAs: []*x509.PEMEncodedCertificate{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletExtraConfig: v1alpha1.Unstructured{\n\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\"port\": 345,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* kubelet configuration field \\\"port\\\" can't be overridden\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceInterfaceInvalid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.interface], [networking.os.device.deviceSelector]: required either config section to be set\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceSelectorAndInterfaceSet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceInterface: \"eth0\",\n\t\t\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{\n\t\t\t\t\t\t\t\t\tNetworkDeviceBus: \"00:01\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.interface], [networking.os.device.deviceSelector]: config sections are mutually exclusive\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"DeviceSelectorAndInterfaceSet\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkInterfaces: []*v1alpha1.Device{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tDeviceSelector: &v1alpha1.NetworkDeviceSelector{},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* [networking.os.device.deviceSelector]: config section should contain at least one field\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"TalosAPIAccessWorker\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\tRBAC: new(true),\n\t\t\t\t\t\tKubernetesTalosAPIAccessConfig: &v1alpha1.KubernetesTalosAPIAccessConfig{\n\t\t\t\t\t\t\tAccessEnabled: new(true),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* feature Kubernetes Talos API Access can only be enabled on control plane machines\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"TalosAPIAccessInvalidRole\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\tRBAC: new(true),\n\t\t\t\t\t\tKubernetesTalosAPIAccessConfig: &v1alpha1.KubernetesTalosAPIAccessConfig{\n\t\t\t\t\t\t\tAccessEnabled: new(true),\n\t\t\t\t\t\t\tAccessAllowedRoles: []string{\n\t\t\t\t\t\t\t\t\"os:reader\",\n\t\t\t\t\t\t\t\t\"invalid:role1\",\n\t\t\t\t\t\t\t\t\"os:etcd:backup\",\n\t\t\t\t\t\t\t\t\"invalid:role2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* invalid role \\\"invalid:role1\\\" in allowed roles for \" +\n\t\t\t\t\"Kubernetes Talos API Access\\n\\t* invalid role \\\"invalid:role2\\\" in allowed roles for \" +\n\t\t\t\t\"Kubernetes Talos API Access\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"NodeLabels\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNodeLabels: map[string]string{\n\t\t\t\t\t\t\"/foo\":          \"bar\",\n\t\t\t\t\t\t\"key\":           \"value\",\n\t\t\t\t\t\t\"talos.dev/foo\": \"bar\",\n\t\t\t\t\t\t\"@!\":            \"#$\",\n\t\t\t\t\t\t\"123@.dev/\":     \"456\",\n\t\t\t\t\t\t\"a/b/c\":         strings.Repeat(\"a\", 64),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* invalid machine node labels: 6 errors occurred:\\n\\t* prefix cannot be empty: \\\"/foo\\\"\\n\\t* prefix \\\"123@.dev\\\" is invalid: domain doesn't match required format: \\\"123@.dev\\\"\\n\\t* name \\\"@!\\\" is invalid\\n\\t* label value \\\"#$\\\" is invalid\\n\\t* invalid format: too many slashes: \\\"a/b/c\\\"\\n\\t* label value length exceeds limit of 63: \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"\\n\\n\\n\\n\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"GoodKubeSpanEndpointFilters\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\tKubeSpanFilters: &v1alpha1.KubeSpanFilters{\n\t\t\t\t\t\t\t\tKubeSpanFiltersEndpoints: []string{\n\t\t\t\t\t\t\t\t\t\"0.0.0.0/0\",\n\t\t\t\t\t\t\t\t\t\"::/0\",\n\t\t\t\t\t\t\t\t\t\"!192.168.0.0/16\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterID:     \"test\",\n\t\t\t\t\tClusterSecret: \"test\",\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"BadKubeSpanEndpointFilters\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\tKubeSpanFilters: &v1alpha1.KubeSpanFilters{\n\t\t\t\t\t\t\t\tKubeSpanFiltersEndpoints: []string{\n\t\t\t\t\t\t\t\t\t\"!10\",\n\t\t\t\t\t\t\t\t\t\"123::/456\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterID:     \"test\",\n\t\t\t\t\tClusterSecret: \"test\",\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* KubeSpan endpoint filter is not valid: \\\"10\\\"\\n\\t* KubeSpan endpoint filter is not valid: \\\"123::/456\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"GoodKubeSpanAdvertisedNetworkFilters\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\tKubeSpanFilters: &v1alpha1.KubeSpanFilters{\n\t\t\t\t\t\t\t\tKubeSpanFiltersExcludeAdvertisedNetworks: []string{\n\t\t\t\t\t\t\t\t\t\"0.0.0.0/0\",\n\t\t\t\t\t\t\t\t\t\"10.0.0.0/8\",\n\t\t\t\t\t\t\t\t\t\"172.16.0.0/12\",\n\t\t\t\t\t\t\t\t\t\"::/0\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterID:     \"test\",\n\t\t\t\t\tClusterSecret: \"test\",\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"BadKubeSpanAdvertisedNetworkFilters\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\tKubeSpanFilters: &v1alpha1.KubeSpanFilters{\n\t\t\t\t\t\t\t\tKubeSpanFiltersExcludeAdvertisedNetworks: []string{\n\t\t\t\t\t\t\t\t\t\"invalid\",\n\t\t\t\t\t\t\t\t\t\"123::/456\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterID:     \"test\",\n\t\t\t\t\tClusterSecret: \"test\",\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* KubeSpan exclude advertised networks filter is not valid: \\\"invalid\\\"\\n\\t* KubeSpan exclude advertised networks filter is not valid: \\\"123::/456\\\"\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"KubeSpanSmallMTU\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineNetwork: &v1alpha1.NetworkConfig{\n\t\t\t\t\t\tNetworkKubeSpan: &v1alpha1.NetworkKubeSpan{\n\t\t\t\t\t\t\tKubeSpanEnabled: new(true),\n\t\t\t\t\t\t\tKubeSpanMTU:     new(uint32(576)),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tClusterID:     \"test\",\n\t\t\t\t\tClusterSecret: \"test\",\n\t\t\t\t\tClusterDiscoveryConfig: &v1alpha1.ClusterDiscoveryConfig{\n\t\t\t\t\t\tDiscoveryEnabled: new(true),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* kubespan link MTU must be at least 1280\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"ControlPlanePodResources\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tRequests: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\":      \"1m\",\n\t\t\t\t\t\t\t\t\t\"invalid1\": \"23\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tLimits: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"memory\":   \"1m\",\n\t\t\t\t\t\t\t\t\t\"invalid2\": \"23\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tSchedulerConfig: &v1alpha1.SchedulerConfig{\n\t\t\t\t\t\tResourcesConfig: &v1alpha1.ResourcesConfig{\n\t\t\t\t\t\t\tRequests: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"cpu\": \"1m\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tLimits: v1alpha1.Unstructured{\n\t\t\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\t\t\"invalid3\": \"23\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"3 errors occurred:\\n\\t* apiserver resource validation failed: unsupported pod resource \\\"invalid1\\\"\\n\\t* controller-manager resource validation failed: unsupported pod resource \\\"invalid2\\\"\\n\\t* scheduler resource validation failed: unsupported pod resource \\\"invalid3\\\"\\n\\n\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tname: \"ControlPlaneInvalidAuthorizationConfig\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAuthorizerName: \"foo\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* apiserver authorization config validation failed: authorizer type must be set\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"ControlPlaneAuthorizationConfigWithAuthorizationModeFlag\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{},\n\t\t\t\t\t\tExtraArgsConfig: v1alpha1.Args{\n\t\t\t\t\t\t\t\"authorization-mode\": v1alpha1.NewArgValue(\"Node\", nil),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* authorization-mode cannot be used in conjunction with AuthorizationConfig, use eitherr AuthorizationConfig or authorization-mode\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"ControlPlaneAuthorizationConfigWithAuthorizationWebhook\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tAuthorizationConfigConfig: []*v1alpha1.AuthorizationConfigAuthorizerConfig{},\n\t\t\t\t\t\tExtraArgsConfig: v1alpha1.Args{\n\t\t\t\t\t\t\t\"authorization-webhook-version\": v1alpha1.NewArgValue(\"v1\", nil),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* authorization-webhook-* flags cannot be used in conjunction with AuthorizationConfig, use either AuthorizationConfig or authorization-webhook-* flags\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"MachineBaseRuntimeSpecOverrides\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineBaseRuntimeSpecOverrides: v1alpha1.Unstructured{\n\t\t\t\t\t\tObject: map[string]any{\n\t\t\t\t\t\t\t\"process\": map[string]any{\n\t\t\t\t\t\t\t\t\"rlimits\": []map[string]any{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"type\": \"RLIMIT_NOFILE\",\n\t\t\t\t\t\t\t\t\t\t\"hard\": 1024,\n\t\t\t\t\t\t\t\t\t\t\"soft\": 1024,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MachineFeaturesInvalidAddressSortingAlgorithm\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tConfigVersion: \"v1alpha1\",\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineCA: &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\t\tCrt: []byte(\"foo\"),\n\t\t\t\t\t\tKey: []byte(\"bar\"),\n\t\t\t\t\t},\n\t\t\t\t\tMachineFeatures: &v1alpha1.FeaturesConfig{\n\t\t\t\t\t\tFeatureNodeAddressSortAlgorithm: \"xyz\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tendpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* invalid node address sort algorithm: xyz does not belong to AddressSortAlgorithm values\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\topts := []validation.Option{validation.WithLocal()}\n\t\t\tif test.strict {\n\t\t\t\topts = append(opts, validation.WithStrict())\n\t\t\t}\n\n\t\t\twarnings, errors := test.config.Validate(runtimeMode{test.requiresInstall}, opts...)\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError == \"\" {\n\t\t\t\tassert.NoError(t, errors)\n\t\t\t} else {\n\t\t\t\tassert.EqualError(t, errors, test.expectedError)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestValidateCNI(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname             string\n\t\tconfig           *v1alpha1.CNIConfig\n\t\texpectedWarnings []string\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\tname:          \"Nil\",\n\t\t\texpectedError: \"\", // Flannel is used by default\n\t\t},\n\t\t{\n\t\t\tname:          \"Empty\",\n\t\t\tconfig:        &v1alpha1.CNIConfig{},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* cni name should be one of [\\\"flannel\\\", \\\"custom\\\", \\\"none\\\"]\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"FlannelNoManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.FlannelCNI,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"FlannelManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.FlannelCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* \\\"urls\\\" field should be empty for \\\"flannel\\\" CNI\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"FlannelExtraArgs\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.FlannelCNI,\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlanneldExtraArgs: []string{\"--foo\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"FlannelKubeNetworkPoliciesDisabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.FlannelCNI,\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(false),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"FlannelKubeNetworkPoliciesEnabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.FlannelCNI,\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"CustomNoManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t},\n\t\t\texpectedWarnings: []string{\n\t\t\t\t\"\\\"urls\\\" field should not be empty for \\\"custom\\\" CNI\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"CustomFlannelExtraArgs\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlanneldExtraArgs: []string{\"--foo\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* \\\"flanneldExtraArgs\\\" field should be empty for \\\"custom\\\" CNI\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"CustomFlannelKubeNetworkPoliciesDisabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(false),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"CustomFlannelKubeNetworkPoliciesEnabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* \\\"flannelKubeNetworkPoliciesEnabled\\\" should not be enabled for \\\"custom\\\" CNI\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"CustomManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.CustomCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoneNoManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.NoneCNI,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoneManifests\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.NoneCNI,\n\t\t\t\tCNIUrls: []string{\n\t\t\t\t\t\"https://host.test/quick-install.yaml\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* \\\"urls\\\" field should be empty for \\\"none\\\" CNI\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"NoneFlannelKubeNetworkPoliciesDisabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.NoneCNI,\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(false),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoneFlannelKubeNetworkPoliciesEnabled\",\n\t\t\tconfig: &v1alpha1.CNIConfig{\n\t\t\t\tCNIName: constants.NoneCNI,\n\t\t\t\tCNIFlannel: &v1alpha1.FlannelCNIConfig{\n\t\t\t\t\tFlannelKubeNetworkPoliciesEnabled: new(true),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* \\\"flannelKubeNetworkPoliciesEnabled\\\" should not be enabled for \\\"none\\\" CNI\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar cc v1alpha1.ClusterConfig\n\t\t\tif test.config != nil {\n\t\t\t\tcc.ClusterNetwork = &v1alpha1.ClusterNetworkConfig{\n\t\t\t\t\tCNI: test.config,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcni := cc.CNI()\n\t\t\trequire.NotNil(t, cni, \"CNI() method should return default value for empty config\")\n\n\t\t\twarnings, errrors := v1alpha1.ValidateCNI(cni)\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tif test.expectedError == \"\" {\n\t\t\t\tassert.NoError(t, errrors)\n\t\t\t} else {\n\t\t\t\tassert.EqualError(t, errrors, test.expectedError)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestKubernetesVersionFromImageRef(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\timageRef string\n\n\t\texpectedVersion string\n\t}{\n\t\t{\n\t\t\timageRef:        \"ghcr.io/siderolabs/kubelet:v1.32.2\",\n\t\t\texpectedVersion: \"1.32.2\",\n\t\t},\n\t\t{\n\t\t\timageRef:        \"ghcr.io/siderolabs/kubelet:v1.32.2@sha256:123456\",\n\t\t\texpectedVersion: \"1.32.2\",\n\t\t},\n\t} {\n\t\tt.Run(test.imageRef, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tversion, err := v1alpha1.KubernetesVersionFromImageRef(test.imageRef)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expectedVersion, version.String())\n\t\t})\n\t}\n}\n\nfunc TestRuntimeValidate(t *testing.T) {\n\tt.Parallel()\n\n\tendpointURL, err := url.Parse(\"https://localhost:6443/\")\n\trequire.NoError(t, err)\n\n\tfor _, test := range []struct {\n\t\tname             string\n\t\tconfig           *v1alpha1.Config\n\t\trequiresInstall  bool\n\t\tstrict           bool\n\t\texpectedWarnings []string\n\t\texpectedError    string\n\t}{\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: endpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"old kubelet version\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: endpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"worker\",\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletImage: constants.KubeletImage + \":v1.24.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* kubelet image is not valid: version of Kubernetes 1.24.0 is too old to be used with Talos VERSION\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"old api-server version\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: endpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tContainerImage: constants.KubernetesAPIServerImage + \":v1.24.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletImage: constants.KubeletImage + \":v\" + constants.DefaultKubernetesVersion,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* kube-apiserver image is not valid: version of Kubernetes 1.24.0 is too old to be used with Talos VERSION\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"old controller-manager and scheduler version\",\n\t\t\tconfig: &v1alpha1.Config{\n\t\t\t\tClusterConfig: &v1alpha1.ClusterConfig{\n\t\t\t\t\tControlPlane: &v1alpha1.ControlPlaneConfig{\n\t\t\t\t\t\tEndpoint: &v1alpha1.Endpoint{\n\t\t\t\t\t\t\tURL: endpointURL,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAPIServerConfig: &v1alpha1.APIServerConfig{\n\t\t\t\t\t\tContainerImage: constants.KubernetesAPIServerImage + \":v\" + constants.DefaultKubernetesVersion,\n\t\t\t\t\t},\n\t\t\t\t\tControllerManagerConfig: &v1alpha1.ControllerManagerConfig{\n\t\t\t\t\t\tContainerImage: constants.KubernetesControllerManagerImage + \":v1.24.0\",\n\t\t\t\t\t},\n\t\t\t\t\tSchedulerConfig: &v1alpha1.SchedulerConfig{\n\t\t\t\t\t\tContainerImage: constants.KubernetesSchedulerImage + \":v1.24.0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMachineConfig: &v1alpha1.MachineConfig{\n\t\t\t\t\tMachineType: \"controlplane\",\n\t\t\t\t\tMachineKubelet: &v1alpha1.KubeletConfig{\n\t\t\t\t\t\tKubeletImage: constants.KubeletImage + \":v\" + constants.DefaultKubernetesVersion,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedError: \"2 errors occurred:\\n\\t* kube-controller-manager image is not valid: version of Kubernetes 1.24.0 is too old to be used with Talos VERSION\\n\\t* kube-scheduler image is not valid: version of Kubernetes 1.24.0 is too old to be used with Talos VERSION\\n\\n\", //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar opts []validation.Option\n\t\t\tif test.strict {\n\t\t\t\topts = append(opts, validation.WithStrict())\n\t\t\t}\n\n\t\t\tst := state.WrapCore(inmem.NewState(\"\"))\n\n\t\t\twarnings, errors := test.config.RuntimeValidate(t.Context(), st, runtimeMode{test.requiresInstall}, opts...)\n\n\t\t\tassert.Equal(t, test.expectedWarnings, warnings)\n\n\t\t\tcurrentTalosVersion, err := compatibility.ParseTalosVersion(version.NewVersion())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif test.expectedError == \"\" {\n\t\t\t\tassert.NoError(t, errors)\n\t\t\t} else {\n\t\t\t\ttest.expectedError = strings.ReplaceAll(test.expectedError, \"VERSION\", currentTalosVersion.String())\n\n\t\t\t\tassert.EqualError(t, errors, test.expectedError)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go",
    "content": "//go:build !ignore_autogenerated\n// +build !ignore_autogenerated\n\n// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by deepcopy-gen. DO NOT EDIT.\n\npackage v1alpha1\n\nimport (\n\tx509 \"github.com/siderolabs/crypto/x509\"\n)\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *APIServerConfig) DeepCopyInto(out *APIServerConfig) {\n\t*out = *in\n\tif in.ExtraArgsConfig != nil {\n\t\tin, out := &in.ExtraArgsConfig, &out.ExtraArgsConfig\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ExtraVolumesConfig != nil {\n\t\tin, out := &in.ExtraVolumesConfig, &out.ExtraVolumesConfig\n\t\t*out = make([]VolumeMountConfig, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.EnvConfig != nil {\n\t\tin, out := &in.EnvConfig, &out.EnvConfig\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.CertSANs != nil {\n\t\tin, out := &in.CertSANs, &out.CertSANs\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.DisablePodSecurityPolicyConfig != nil {\n\t\tin, out := &in.DisablePodSecurityPolicyConfig, &out.DisablePodSecurityPolicyConfig\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.AdmissionControlConfig != nil {\n\t\tin, out := &in.AdmissionControlConfig, &out.AdmissionControlConfig\n\t\t*out = make(AdmissionPluginConfigList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(AdmissionPluginConfig)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tin.AuditPolicyConfig.DeepCopyInto(&out.AuditPolicyConfig)\n\tif in.ResourcesConfig != nil {\n\t\tin, out := &in.ResourcesConfig, &out.ResourcesConfig\n\t\t*out = new(ResourcesConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServerConfig.\nfunc (in *APIServerConfig) DeepCopy() *APIServerConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(APIServerConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *AdminKubeconfigConfig) DeepCopyInto(out *AdminKubeconfigConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdminKubeconfigConfig.\nfunc (in *AdminKubeconfigConfig) DeepCopy() *AdminKubeconfigConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(AdminKubeconfigConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *AdmissionPluginConfig) DeepCopyInto(out *AdmissionPluginConfig) {\n\t*out = *in\n\tin.PluginConfiguration.DeepCopyInto(&out.PluginConfiguration)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionPluginConfig.\nfunc (in *AdmissionPluginConfig) DeepCopy() *AdmissionPluginConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(AdmissionPluginConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in AdmissionPluginConfigList) DeepCopyInto(out *AdmissionPluginConfigList) {\n\t{\n\t\tin := &in\n\t\t*out = make(AdmissionPluginConfigList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(AdmissionPluginConfig)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmissionPluginConfigList.\nfunc (in AdmissionPluginConfigList) DeepCopy() AdmissionPluginConfigList {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(AdmissionPluginConfigList)\n\tin.DeepCopyInto(out)\n\treturn *out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in Base64Bytes) DeepCopyInto(out *Base64Bytes) {\n\t{\n\t\tin := &in\n\t\t*out = make(Base64Bytes, len(*in))\n\t\tcopy(*out, *in)\n\t\treturn\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Base64Bytes.\nfunc (in Base64Bytes) DeepCopy() Base64Bytes {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Base64Bytes)\n\tin.DeepCopyInto(out)\n\treturn *out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Bond) DeepCopyInto(out *Bond) {\n\t*out = *in\n\tif in.BondInterfaces != nil {\n\t\tin, out := &in.BondInterfaces, &out.BondInterfaces\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.BondDeviceSelectors != nil {\n\t\tin, out := &in.BondDeviceSelectors, &out.BondDeviceSelectors\n\t\t*out = make([]NetworkDeviceSelector, len(*in))\n\t\tfor i := range *in {\n\t\t\t(*in)[i].DeepCopyInto(&(*out)[i])\n\t\t}\n\t}\n\tif in.BondARPIPTarget != nil {\n\t\tin, out := &in.BondARPIPTarget, &out.BondARPIPTarget\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.BondUseCarrier != nil {\n\t\tin, out := &in.BondUseCarrier, &out.BondUseCarrier\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bond.\nfunc (in *Bond) DeepCopy() *Bond {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Bond)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Bridge) DeepCopyInto(out *Bridge) {\n\t*out = *in\n\tif in.BridgedInterfaces != nil {\n\t\tin, out := &in.BridgedInterfaces, &out.BridgedInterfaces\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.BridgeSTP != nil {\n\t\tin, out := &in.BridgeSTP, &out.BridgeSTP\n\t\t*out = new(STP)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bridge.\nfunc (in *Bridge) DeepCopy() *Bridge {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Bridge)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *CNIConfig) DeepCopyInto(out *CNIConfig) {\n\t*out = *in\n\tif in.CNIUrls != nil {\n\t\tin, out := &in.CNIUrls, &out.CNIUrls\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.CNIFlannel != nil {\n\t\tin, out := &in.CNIFlannel, &out.CNIFlannel\n\t\t*out = new(FlannelCNIConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNIConfig.\nfunc (in *CNIConfig) DeepCopy() *CNIConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(CNIConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) {\n\t*out = *in\n\tif in.ControlPlane != nil {\n\t\tin, out := &in.ControlPlane, &out.ControlPlane\n\t\t*out = new(ControlPlaneConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ClusterNetwork != nil {\n\t\tin, out := &in.ClusterNetwork, &out.ClusterNetwork\n\t\t*out = new(ClusterNetworkConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ClusterCA != nil {\n\t\tin, out := &in.ClusterCA, &out.ClusterCA\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.ClusterAcceptedCAs != nil {\n\t\tin, out := &in.ClusterAcceptedCAs, &out.ClusterAcceptedCAs\n\t\t*out = make([]*x509.PEMEncodedCertificate, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = (*in).DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif in.ClusterAggregatorCA != nil {\n\t\tin, out := &in.ClusterAggregatorCA, &out.ClusterAggregatorCA\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.ClusterServiceAccount != nil {\n\t\tin, out := &in.ClusterServiceAccount, &out.ClusterServiceAccount\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.APIServerConfig != nil {\n\t\tin, out := &in.APIServerConfig, &out.APIServerConfig\n\t\t*out = new(APIServerConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ControllerManagerConfig != nil {\n\t\tin, out := &in.ControllerManagerConfig, &out.ControllerManagerConfig\n\t\t*out = new(ControllerManagerConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ProxyConfig != nil {\n\t\tin, out := &in.ProxyConfig, &out.ProxyConfig\n\t\t*out = new(ProxyConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.SchedulerConfig != nil {\n\t\tin, out := &in.SchedulerConfig, &out.SchedulerConfig\n\t\t*out = new(SchedulerConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ClusterDiscoveryConfig != nil {\n\t\tin, out := &in.ClusterDiscoveryConfig, &out.ClusterDiscoveryConfig\n\t\t*out = new(ClusterDiscoveryConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.EtcdConfig != nil {\n\t\tin, out := &in.EtcdConfig, &out.EtcdConfig\n\t\t*out = new(EtcdConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.CoreDNSConfig != nil {\n\t\tin, out := &in.CoreDNSConfig, &out.CoreDNSConfig\n\t\t*out = new(CoreDNS)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ExternalCloudProviderConfig != nil {\n\t\tin, out := &in.ExternalCloudProviderConfig, &out.ExternalCloudProviderConfig\n\t\t*out = new(ExternalCloudProviderConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ExtraManifests != nil {\n\t\tin, out := &in.ExtraManifests, &out.ExtraManifests\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.ExtraManifestHeaders != nil {\n\t\tin, out := &in.ExtraManifestHeaders, &out.ExtraManifestHeaders\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ClusterInlineManifests != nil {\n\t\tin, out := &in.ClusterInlineManifests, &out.ClusterInlineManifests\n\t\t*out = make(ClusterInlineManifests, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.AdminKubeconfigConfig != nil {\n\t\tin, out := &in.AdminKubeconfigConfig, &out.AdminKubeconfigConfig\n\t\t*out = new(AdminKubeconfigConfig)\n\t\t**out = **in\n\t}\n\tif in.AllowSchedulingOnMasters != nil {\n\t\tin, out := &in.AllowSchedulingOnMasters, &out.AllowSchedulingOnMasters\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.AllowSchedulingOnControlPlanes != nil {\n\t\tin, out := &in.AllowSchedulingOnControlPlanes, &out.AllowSchedulingOnControlPlanes\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfig.\nfunc (in *ClusterConfig) DeepCopy() *ClusterConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ClusterConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ClusterDiscoveryConfig) DeepCopyInto(out *ClusterDiscoveryConfig) {\n\t*out = *in\n\tif in.DiscoveryEnabled != nil {\n\t\tin, out := &in.DiscoveryEnabled, &out.DiscoveryEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tin.DiscoveryRegistries.DeepCopyInto(&out.DiscoveryRegistries)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterDiscoveryConfig.\nfunc (in *ClusterDiscoveryConfig) DeepCopy() *ClusterDiscoveryConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ClusterDiscoveryConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ClusterInlineManifest) DeepCopyInto(out *ClusterInlineManifest) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInlineManifest.\nfunc (in *ClusterInlineManifest) DeepCopy() *ClusterInlineManifest {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ClusterInlineManifest)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in ClusterInlineManifests) DeepCopyInto(out *ClusterInlineManifests) {\n\t{\n\t\tin := &in\n\t\t*out = make(ClusterInlineManifests, len(*in))\n\t\tcopy(*out, *in)\n\t\treturn\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInlineManifests.\nfunc (in ClusterInlineManifests) DeepCopy() ClusterInlineManifests {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ClusterInlineManifests)\n\tin.DeepCopyInto(out)\n\treturn *out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ClusterNetworkConfig) DeepCopyInto(out *ClusterNetworkConfig) {\n\t*out = *in\n\tif in.CNI != nil {\n\t\tin, out := &in.CNI, &out.CNI\n\t\t*out = new(CNIConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.PodSubnet != nil {\n\t\tin, out := &in.PodSubnet, &out.PodSubnet\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.ServiceSubnet != nil {\n\t\tin, out := &in.ServiceSubnet, &out.ServiceSubnet\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterNetworkConfig.\nfunc (in *ClusterNetworkConfig) DeepCopy() *ClusterNetworkConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ClusterNetworkConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (c *Config) DeepCopyInto(out *Config) {\n\t*out = *c\n\tif c.ConfigDebug != nil {\n\t\tin, out := &c.ConfigDebug, &out.ConfigDebug\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif c.ConfigPersist != nil {\n\t\tin, out := &c.ConfigPersist, &out.ConfigPersist\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif c.MachineConfig != nil {\n\t\tin, out := &c.MachineConfig, &out.MachineConfig\n\t\t*out = new(MachineConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif c.ClusterConfig != nil {\n\t\tin, out := &c.ClusterConfig, &out.ClusterConfig\n\t\t*out = new(ClusterConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config.\nfunc (c *Config) DeepCopy() *Config {\n\tif c == nil {\n\t\treturn nil\n\t}\n\tout := new(Config)\n\tc.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ControlPlaneConfig) DeepCopyInto(out *ControlPlaneConfig) {\n\t*out = *in\n\tif in.Endpoint != nil {\n\t\tin, out := &in.Endpoint, &out.Endpoint\n\t\t*out = (*in).DeepCopy()\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneConfig.\nfunc (in *ControlPlaneConfig) DeepCopy() *ControlPlaneConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ControlPlaneConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ControllerManagerConfig) DeepCopyInto(out *ControllerManagerConfig) {\n\t*out = *in\n\tif in.ExtraArgsConfig != nil {\n\t\tin, out := &in.ExtraArgsConfig, &out.ExtraArgsConfig\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ExtraVolumesConfig != nil {\n\t\tin, out := &in.ExtraVolumesConfig, &out.ExtraVolumesConfig\n\t\t*out = make([]VolumeMountConfig, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.EnvConfig != nil {\n\t\tin, out := &in.EnvConfig, &out.EnvConfig\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ResourcesConfig != nil {\n\t\tin, out := &in.ResourcesConfig, &out.ResourcesConfig\n\t\t*out = new(ResourcesConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfig.\nfunc (in *ControllerManagerConfig) DeepCopy() *ControllerManagerConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ControllerManagerConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *CoreDNS) DeepCopyInto(out *CoreDNS) {\n\t*out = *in\n\tif in.CoreDNSDisabled != nil {\n\t\tin, out := &in.CoreDNSDisabled, &out.CoreDNSDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoreDNS.\nfunc (in *CoreDNS) DeepCopy() *CoreDNS {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(CoreDNS)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DHCPOptions) DeepCopyInto(out *DHCPOptions) {\n\t*out = *in\n\tif in.DHCPIPv4 != nil {\n\t\tin, out := &in.DHCPIPv4, &out.DHCPIPv4\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.DHCPIPv6 != nil {\n\t\tin, out := &in.DHCPIPv6, &out.DHCPIPv6\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DHCPOptions.\nfunc (in *DHCPOptions) DeepCopy() *DHCPOptions {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DHCPOptions)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Device) DeepCopyInto(out *Device) {\n\t*out = *in\n\tif in.DeviceSelector != nil {\n\t\tin, out := &in.DeviceSelector, &out.DeviceSelector\n\t\t*out = new(NetworkDeviceSelector)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.DeviceAddresses != nil {\n\t\tin, out := &in.DeviceAddresses, &out.DeviceAddresses\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.DeviceRoutes != nil {\n\t\tin, out := &in.DeviceRoutes, &out.DeviceRoutes\n\t\t*out = make([]*Route, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Route)\n\t\t\t\t**out = **in\n\t\t\t}\n\t\t}\n\t}\n\tif in.DeviceBond != nil {\n\t\tin, out := &in.DeviceBond, &out.DeviceBond\n\t\t*out = new(Bond)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.DeviceBridge != nil {\n\t\tin, out := &in.DeviceBridge, &out.DeviceBridge\n\t\t*out = new(Bridge)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.DeviceVlans != nil {\n\t\tin, out := &in.DeviceVlans, &out.DeviceVlans\n\t\t*out = make(VlanList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Vlan)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.DeviceDHCP != nil {\n\t\tin, out := &in.DeviceDHCP, &out.DeviceDHCP\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.DeviceIgnore != nil {\n\t\tin, out := &in.DeviceIgnore, &out.DeviceIgnore\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.DeviceDummy != nil {\n\t\tin, out := &in.DeviceDummy, &out.DeviceDummy\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.DeviceDHCPOptions != nil {\n\t\tin, out := &in.DeviceDHCPOptions, &out.DeviceDHCPOptions\n\t\t*out = new(DHCPOptions)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.DeviceWireguardConfig != nil {\n\t\tin, out := &in.DeviceWireguardConfig, &out.DeviceWireguardConfig\n\t\t*out = new(DeviceWireguardConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.DeviceVIPConfig != nil {\n\t\tin, out := &in.DeviceVIPConfig, &out.DeviceVIPConfig\n\t\t*out = new(DeviceVIPConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Device.\nfunc (in *Device) DeepCopy() *Device {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Device)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DeviceVIPConfig) DeepCopyInto(out *DeviceVIPConfig) {\n\t*out = *in\n\tif in.EquinixMetalConfig != nil {\n\t\tin, out := &in.EquinixMetalConfig, &out.EquinixMetalConfig\n\t\t*out = new(VIPEquinixMetalConfig)\n\t\t**out = **in\n\t}\n\tif in.HCloudConfig != nil {\n\t\tin, out := &in.HCloudConfig, &out.HCloudConfig\n\t\t*out = new(VIPHCloudConfig)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceVIPConfig.\nfunc (in *DeviceVIPConfig) DeepCopy() *DeviceVIPConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DeviceVIPConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DeviceWireguardConfig) DeepCopyInto(out *DeviceWireguardConfig) {\n\t*out = *in\n\tif in.WireguardPeers != nil {\n\t\tin, out := &in.WireguardPeers, &out.WireguardPeers\n\t\t*out = make([]*DeviceWireguardPeer, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(DeviceWireguardPeer)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceWireguardConfig.\nfunc (in *DeviceWireguardConfig) DeepCopy() *DeviceWireguardConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DeviceWireguardConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DeviceWireguardPeer) DeepCopyInto(out *DeviceWireguardPeer) {\n\t*out = *in\n\tif in.WireguardAllowedIPs != nil {\n\t\tin, out := &in.WireguardAllowedIPs, &out.WireguardAllowedIPs\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceWireguardPeer.\nfunc (in *DeviceWireguardPeer) DeepCopy() *DeviceWireguardPeer {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DeviceWireguardPeer)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DiscoveryRegistriesConfig) DeepCopyInto(out *DiscoveryRegistriesConfig) {\n\t*out = *in\n\tin.RegistryKubernetes.DeepCopyInto(&out.RegistryKubernetes)\n\tin.RegistryService.DeepCopyInto(&out.RegistryService)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiscoveryRegistriesConfig.\nfunc (in *DiscoveryRegistriesConfig) DeepCopy() *DiscoveryRegistriesConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DiscoveryRegistriesConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *DiskPartition) DeepCopyInto(out *DiskPartition) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiskPartition.\nfunc (in *DiskPartition) DeepCopy() *DiskPartition {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(DiskPartition)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionConfig) DeepCopyInto(out *EncryptionConfig) {\n\t*out = *in\n\tif in.EncryptionKeys != nil {\n\t\tin, out := &in.EncryptionKeys, &out.EncryptionKeys\n\t\t*out = make([]*EncryptionKey, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(EncryptionKey)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.EncryptionPerfOptions != nil {\n\t\tin, out := &in.EncryptionPerfOptions, &out.EncryptionPerfOptions\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionConfig.\nfunc (in *EncryptionConfig) DeepCopy() *EncryptionConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionKey) DeepCopyInto(out *EncryptionKey) {\n\t*out = *in\n\tif in.KeyStatic != nil {\n\t\tin, out := &in.KeyStatic, &out.KeyStatic\n\t\t*out = new(EncryptionKeyStatic)\n\t\t**out = **in\n\t}\n\tif in.KeyNodeID != nil {\n\t\tin, out := &in.KeyNodeID, &out.KeyNodeID\n\t\t*out = new(EncryptionKeyNodeID)\n\t\t**out = **in\n\t}\n\tif in.KeyKMS != nil {\n\t\tin, out := &in.KeyKMS, &out.KeyKMS\n\t\t*out = new(EncryptionKeyKMS)\n\t\t**out = **in\n\t}\n\tif in.KeyTPM != nil {\n\t\tin, out := &in.KeyTPM, &out.KeyTPM\n\t\t*out = new(EncryptionKeyTPM)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionKey.\nfunc (in *EncryptionKey) DeepCopy() *EncryptionKey {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionKey)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionKeyKMS) DeepCopyInto(out *EncryptionKeyKMS) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionKeyKMS.\nfunc (in *EncryptionKeyKMS) DeepCopy() *EncryptionKeyKMS {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionKeyKMS)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionKeyNodeID) DeepCopyInto(out *EncryptionKeyNodeID) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionKeyNodeID.\nfunc (in *EncryptionKeyNodeID) DeepCopy() *EncryptionKeyNodeID {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionKeyNodeID)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionKeyStatic) DeepCopyInto(out *EncryptionKeyStatic) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionKeyStatic.\nfunc (in *EncryptionKeyStatic) DeepCopy() *EncryptionKeyStatic {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionKeyStatic)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EncryptionKeyTPM) DeepCopyInto(out *EncryptionKeyTPM) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EncryptionKeyTPM.\nfunc (in *EncryptionKeyTPM) DeepCopy() *EncryptionKeyTPM {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EncryptionKeyTPM)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *EtcdConfig) DeepCopyInto(out *EtcdConfig) {\n\t*out = *in\n\tif in.RootCA != nil {\n\t\tin, out := &in.RootCA, &out.RootCA\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.EtcdExtraArgs != nil {\n\t\tin, out := &in.EtcdExtraArgs, &out.EtcdExtraArgs\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.EtcdAdvertisedSubnets != nil {\n\t\tin, out := &in.EtcdAdvertisedSubnets, &out.EtcdAdvertisedSubnets\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.EtcdListenSubnets != nil {\n\t\tin, out := &in.EtcdListenSubnets, &out.EtcdListenSubnets\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdConfig.\nfunc (in *EtcdConfig) DeepCopy() *EtcdConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(EtcdConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ExternalCloudProviderConfig) DeepCopyInto(out *ExternalCloudProviderConfig) {\n\t*out = *in\n\tif in.ExternalEnabled != nil {\n\t\tin, out := &in.ExternalEnabled, &out.ExternalEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.ExternalManifests != nil {\n\t\tin, out := &in.ExternalManifests, &out.ExternalManifests\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalCloudProviderConfig.\nfunc (in *ExternalCloudProviderConfig) DeepCopy() *ExternalCloudProviderConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ExternalCloudProviderConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ExtraHost) DeepCopyInto(out *ExtraHost) {\n\t*out = *in\n\tif in.HostAliases != nil {\n\t\tin, out := &in.HostAliases, &out.HostAliases\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraHost.\nfunc (in *ExtraHost) DeepCopy() *ExtraHost {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ExtraHost)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ExtraMount) DeepCopyInto(out *ExtraMount) {\n\t*out = *in\n\tif in.Options != nil {\n\t\tin, out := &in.Options, &out.Options\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.UIDMappings != nil {\n\t\tin, out := &in.UIDMappings, &out.UIDMappings\n\t\t*out = make([]LinuxIDMapping, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.GIDMappings != nil {\n\t\tin, out := &in.GIDMappings, &out.GIDMappings\n\t\t*out = make([]LinuxIDMapping, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraMount.\nfunc (in *ExtraMount) DeepCopy() *ExtraMount {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ExtraMount)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *FeaturesConfig) DeepCopyInto(out *FeaturesConfig) {\n\t*out = *in\n\tif in.RBAC != nil {\n\t\tin, out := &in.RBAC, &out.RBAC\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.StableHostname != nil {\n\t\tin, out := &in.StableHostname, &out.StableHostname\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubernetesTalosAPIAccessConfig != nil {\n\t\tin, out := &in.KubernetesTalosAPIAccessConfig, &out.KubernetesTalosAPIAccessConfig\n\t\t*out = new(KubernetesTalosAPIAccessConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.ApidCheckExtKeyUsage != nil {\n\t\tin, out := &in.ApidCheckExtKeyUsage, &out.ApidCheckExtKeyUsage\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.DiskQuotaSupport != nil {\n\t\tin, out := &in.DiskQuotaSupport, &out.DiskQuotaSupport\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubePrismSupport != nil {\n\t\tin, out := &in.KubePrismSupport, &out.KubePrismSupport\n\t\t*out = new(KubePrism)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.HostDNSSupport != nil {\n\t\tin, out := &in.HostDNSSupport, &out.HostDNSSupport\n\t\t*out = new(HostDNSConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeaturesConfig.\nfunc (in *FeaturesConfig) DeepCopy() *FeaturesConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(FeaturesConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *FlannelCNIConfig) DeepCopyInto(out *FlannelCNIConfig) {\n\t*out = *in\n\tif in.FlanneldExtraArgs != nil {\n\t\tin, out := &in.FlanneldExtraArgs, &out.FlanneldExtraArgs\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlannelCNIConfig.\nfunc (in *FlannelCNIConfig) DeepCopy() *FlannelCNIConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(FlannelCNIConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *HostDNSConfig) DeepCopyInto(out *HostDNSConfig) {\n\t*out = *in\n\tif in.HostDNSEnabled != nil {\n\t\tin, out := &in.HostDNSEnabled, &out.HostDNSEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.HostDNSForwardKubeDNSToHost != nil {\n\t\tin, out := &in.HostDNSForwardKubeDNSToHost, &out.HostDNSForwardKubeDNSToHost\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.HostDNSResolveMemberNames != nil {\n\t\tin, out := &in.HostDNSResolveMemberNames, &out.HostDNSResolveMemberNames\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostDNSConfig.\nfunc (in *HostDNSConfig) DeepCopy() *HostDNSConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(HostDNSConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *IfaceSelector) DeepCopyInto(out *IfaceSelector) {\n\t*out = *in\n\tif in.Name != nil {\n\t\tin, out := &in.Name, &out.Name\n\t\t*out = new(string)\n\t\t**out = **in\n\t}\n\tif in.Selector != nil {\n\t\tin, out := &in.Selector, &out.Selector\n\t\t*out = new(NetworkDeviceSelector)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IfaceSelector.\nfunc (in *IfaceSelector) DeepCopy() *IfaceSelector {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(IfaceSelector)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *InstallConfig) DeepCopyInto(out *InstallConfig) {\n\t*out = *in\n\tif in.InstallDiskSelector != nil {\n\t\tin, out := &in.InstallDiskSelector, &out.InstallDiskSelector\n\t\t*out = new(InstallDiskSelector)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.InstallExtraKernelArgs != nil {\n\t\tin, out := &in.InstallExtraKernelArgs, &out.InstallExtraKernelArgs\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.InstallExtensions != nil {\n\t\tin, out := &in.InstallExtensions, &out.InstallExtensions\n\t\t*out = make([]InstallExtensionConfig, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.InstallBootloader != nil {\n\t\tin, out := &in.InstallBootloader, &out.InstallBootloader\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.InstallWipe != nil {\n\t\tin, out := &in.InstallWipe, &out.InstallWipe\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.InstallLegacyBIOSSupport != nil {\n\t\tin, out := &in.InstallLegacyBIOSSupport, &out.InstallLegacyBIOSSupport\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallConfig.\nfunc (in *InstallConfig) DeepCopy() *InstallConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(InstallConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *InstallDiskSelector) DeepCopyInto(out *InstallDiskSelector) {\n\t*out = *in\n\tif in.Size != nil {\n\t\tin, out := &in.Size, &out.Size\n\t\t*out = new(InstallDiskSizeMatcher)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallDiskSelector.\nfunc (in *InstallDiskSelector) DeepCopy() *InstallDiskSelector {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(InstallDiskSelector)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *InstallDiskSizeMatchData) DeepCopyInto(out *InstallDiskSizeMatchData) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallDiskSizeMatchData.\nfunc (in *InstallDiskSizeMatchData) DeepCopy() *InstallDiskSizeMatchData {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(InstallDiskSizeMatchData)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *InstallDiskSizeMatcher) DeepCopyInto(out *InstallDiskSizeMatcher) {\n\t*out = *in\n\tout.MatchData = in.MatchData\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallDiskSizeMatcher.\nfunc (in *InstallDiskSizeMatcher) DeepCopy() *InstallDiskSizeMatcher {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(InstallDiskSizeMatcher)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *InstallExtensionConfig) DeepCopyInto(out *InstallExtensionConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstallExtensionConfig.\nfunc (in *InstallExtensionConfig) DeepCopy() *InstallExtensionConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(InstallExtensionConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KernelConfig) DeepCopyInto(out *KernelConfig) {\n\t*out = *in\n\tif in.KernelModules != nil {\n\t\tin, out := &in.KernelModules, &out.KernelModules\n\t\t*out = make([]*KernelModuleConfig, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(KernelModuleConfig)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelConfig.\nfunc (in *KernelConfig) DeepCopy() *KernelConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KernelConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KernelModuleConfig) DeepCopyInto(out *KernelModuleConfig) {\n\t*out = *in\n\tif in.ModuleParameters != nil {\n\t\tin, out := &in.ModuleParameters, &out.ModuleParameters\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KernelModuleConfig.\nfunc (in *KernelModuleConfig) DeepCopy() *KernelModuleConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KernelModuleConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KubePrism) DeepCopyInto(out *KubePrism) {\n\t*out = *in\n\tif in.ServerEnabled != nil {\n\t\tin, out := &in.ServerEnabled, &out.ServerEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubePrism.\nfunc (in *KubePrism) DeepCopy() *KubePrism {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KubePrism)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KubeSpanFilters) DeepCopyInto(out *KubeSpanFilters) {\n\t*out = *in\n\tif in.KubeSpanFiltersEndpoints != nil {\n\t\tin, out := &in.KubeSpanFiltersEndpoints, &out.KubeSpanFiltersEndpoints\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSpanFilters.\nfunc (in *KubeSpanFilters) DeepCopy() *KubeSpanFilters {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KubeSpanFilters)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KubeletConfig) DeepCopyInto(out *KubeletConfig) {\n\t*out = *in\n\tif in.KubeletClusterDNS != nil {\n\t\tin, out := &in.KubeletClusterDNS, &out.KubeletClusterDNS\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.KubeletExtraArgs != nil {\n\t\tin, out := &in.KubeletExtraArgs, &out.KubeletExtraArgs\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.KubeletExtraMounts != nil {\n\t\tin, out := &in.KubeletExtraMounts, &out.KubeletExtraMounts\n\t\t*out = make([]ExtraMount, len(*in))\n\t\tfor i := range *in {\n\t\t\t(*in)[i].DeepCopyInto(&(*out)[i])\n\t\t}\n\t}\n\tin.KubeletExtraConfig.DeepCopyInto(&out.KubeletExtraConfig)\n\tin.KubeletCredentialProviderConfig.DeepCopyInto(&out.KubeletCredentialProviderConfig)\n\tif in.KubeletDefaultRuntimeSeccompProfileEnabled != nil {\n\t\tin, out := &in.KubeletDefaultRuntimeSeccompProfileEnabled, &out.KubeletDefaultRuntimeSeccompProfileEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeletRegisterWithFQDN != nil {\n\t\tin, out := &in.KubeletRegisterWithFQDN, &out.KubeletRegisterWithFQDN\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeletNodeIP != nil {\n\t\tin, out := &in.KubeletNodeIP, &out.KubeletNodeIP\n\t\t*out = new(KubeletNodeIPConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.KubeletSkipNodeRegistration != nil {\n\t\tin, out := &in.KubeletSkipNodeRegistration, &out.KubeletSkipNodeRegistration\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeletDisableManifestsDirectory != nil {\n\t\tin, out := &in.KubeletDisableManifestsDirectory, &out.KubeletDisableManifestsDirectory\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletConfig.\nfunc (in *KubeletConfig) DeepCopy() *KubeletConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KubeletConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KubeletNodeIPConfig) DeepCopyInto(out *KubeletNodeIPConfig) {\n\t*out = *in\n\tif in.KubeletNodeIPValidSubnets != nil {\n\t\tin, out := &in.KubeletNodeIPValidSubnets, &out.KubeletNodeIPValidSubnets\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeletNodeIPConfig.\nfunc (in *KubeletNodeIPConfig) DeepCopy() *KubeletNodeIPConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KubeletNodeIPConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *KubernetesTalosAPIAccessConfig) DeepCopyInto(out *KubernetesTalosAPIAccessConfig) {\n\t*out = *in\n\tif in.AccessEnabled != nil {\n\t\tin, out := &in.AccessEnabled, &out.AccessEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.AccessAllowedRoles != nil {\n\t\tin, out := &in.AccessAllowedRoles, &out.AccessAllowedRoles\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.AccessAllowedKubernetesNamespaces != nil {\n\t\tin, out := &in.AccessAllowedKubernetesNamespaces, &out.AccessAllowedKubernetesNamespaces\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesTalosAPIAccessConfig.\nfunc (in *KubernetesTalosAPIAccessConfig) DeepCopy() *KubernetesTalosAPIAccessConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(KubernetesTalosAPIAccessConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *LinuxIDMapping) DeepCopyInto(out *LinuxIDMapping) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LinuxIDMapping.\nfunc (in *LinuxIDMapping) DeepCopy() *LinuxIDMapping {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(LinuxIDMapping)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *LoggingConfig) DeepCopyInto(out *LoggingConfig) {\n\t*out = *in\n\tif in.LoggingDestinations != nil {\n\t\tin, out := &in.LoggingDestinations, &out.LoggingDestinations\n\t\t*out = make([]LoggingDestination, len(*in))\n\t\tfor i := range *in {\n\t\t\t(*in)[i].DeepCopyInto(&(*out)[i])\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfig.\nfunc (in *LoggingConfig) DeepCopy() *LoggingConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(LoggingConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *LoggingDestination) DeepCopyInto(out *LoggingDestination) {\n\t*out = *in\n\tif in.LoggingEndpoint != nil {\n\t\tin, out := &in.LoggingEndpoint, &out.LoggingEndpoint\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.LoggingExtraTags != nil {\n\t\tin, out := &in.LoggingExtraTags, &out.LoggingExtraTags\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingDestination.\nfunc (in *LoggingDestination) DeepCopy() *LoggingDestination {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(LoggingDestination)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineConfig) DeepCopyInto(out *MachineConfig) {\n\t*out = *in\n\tif in.MachineCA != nil {\n\t\tin, out := &in.MachineCA, &out.MachineCA\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.MachineAcceptedCAs != nil {\n\t\tin, out := &in.MachineAcceptedCAs, &out.MachineAcceptedCAs\n\t\t*out = make([]*x509.PEMEncodedCertificate, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = (*in).DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif in.MachineCertSANs != nil {\n\t\tin, out := &in.MachineCertSANs, &out.MachineCertSANs\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.MachineControlPlane != nil {\n\t\tin, out := &in.MachineControlPlane, &out.MachineControlPlane\n\t\t*out = new(MachineControlPlaneConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineKubelet != nil {\n\t\tin, out := &in.MachineKubelet, &out.MachineKubelet\n\t\t*out = new(KubeletConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachinePods != nil {\n\t\tin, out := &in.MachinePods, &out.MachinePods\n\t\t*out = make([]Unstructured, len(*in))\n\t\tfor i := range *in {\n\t\t\t(*in)[i].DeepCopyInto(&(*out)[i])\n\t\t}\n\t}\n\tif in.MachineNetwork != nil {\n\t\tin, out := &in.MachineNetwork, &out.MachineNetwork\n\t\t*out = new(NetworkConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineDisks != nil {\n\t\tin, out := &in.MachineDisks, &out.MachineDisks\n\t\t*out = make([]*MachineDisk, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(MachineDisk)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.MachineInstall != nil {\n\t\tin, out := &in.MachineInstall, &out.MachineInstall\n\t\t*out = new(InstallConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineFiles != nil {\n\t\tin, out := &in.MachineFiles, &out.MachineFiles\n\t\t*out = make([]*MachineFile, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(MachineFile)\n\t\t\t\t**out = **in\n\t\t\t}\n\t\t}\n\t}\n\tif in.MachineEnv != nil {\n\t\tin, out := &in.MachineEnv, &out.MachineEnv\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.MachineTime != nil {\n\t\tin, out := &in.MachineTime, &out.MachineTime\n\t\t*out = new(TimeConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineSysctls != nil {\n\t\tin, out := &in.MachineSysctls, &out.MachineSysctls\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.MachineSysfs != nil {\n\t\tin, out := &in.MachineSysfs, &out.MachineSysfs\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tin.MachineRegistries.DeepCopyInto(&out.MachineRegistries)\n\tif in.MachineSystemDiskEncryption != nil {\n\t\tin, out := &in.MachineSystemDiskEncryption, &out.MachineSystemDiskEncryption\n\t\t*out = new(SystemDiskEncryptionConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineFeatures != nil {\n\t\tin, out := &in.MachineFeatures, &out.MachineFeatures\n\t\t*out = new(FeaturesConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineUdev != nil {\n\t\tin, out := &in.MachineUdev, &out.MachineUdev\n\t\t*out = new(UdevConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineLogging != nil {\n\t\tin, out := &in.MachineLogging, &out.MachineLogging\n\t\t*out = new(LoggingConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineKernel != nil {\n\t\tin, out := &in.MachineKernel, &out.MachineKernel\n\t\t*out = new(KernelConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineSeccompProfiles != nil {\n\t\tin, out := &in.MachineSeccompProfiles, &out.MachineSeccompProfiles\n\t\t*out = make([]*MachineSeccompProfile, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(MachineSeccompProfile)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.MachineNodeLabels != nil {\n\t\tin, out := &in.MachineNodeLabels, &out.MachineNodeLabels\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.MachineNodeTaints != nil {\n\t\tin, out := &in.MachineNodeTaints, &out.MachineNodeTaints\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineConfig.\nfunc (in *MachineConfig) DeepCopy() *MachineConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineControlPlaneConfig) DeepCopyInto(out *MachineControlPlaneConfig) {\n\t*out = *in\n\tif in.MachineControllerManager != nil {\n\t\tin, out := &in.MachineControllerManager, &out.MachineControllerManager\n\t\t*out = new(MachineControllerManagerConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.MachineScheduler != nil {\n\t\tin, out := &in.MachineScheduler, &out.MachineScheduler\n\t\t*out = new(MachineSchedulerConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineControlPlaneConfig.\nfunc (in *MachineControlPlaneConfig) DeepCopy() *MachineControlPlaneConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineControlPlaneConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineControllerManagerConfig) DeepCopyInto(out *MachineControllerManagerConfig) {\n\t*out = *in\n\tif in.MachineControllerManagerDisabled != nil {\n\t\tin, out := &in.MachineControllerManagerDisabled, &out.MachineControllerManagerDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineControllerManagerConfig.\nfunc (in *MachineControllerManagerConfig) DeepCopy() *MachineControllerManagerConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineControllerManagerConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineDisk) DeepCopyInto(out *MachineDisk) {\n\t*out = *in\n\tif in.DiskPartitions != nil {\n\t\tin, out := &in.DiskPartitions, &out.DiskPartitions\n\t\t*out = make([]*DiskPartition, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(DiskPartition)\n\t\t\t\t**out = **in\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineDisk.\nfunc (in *MachineDisk) DeepCopy() *MachineDisk {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineDisk)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineFile) DeepCopyInto(out *MachineFile) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineFile.\nfunc (in *MachineFile) DeepCopy() *MachineFile {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineFile)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineSchedulerConfig) DeepCopyInto(out *MachineSchedulerConfig) {\n\t*out = *in\n\tif in.MachineSchedulerDisabled != nil {\n\t\tin, out := &in.MachineSchedulerDisabled, &out.MachineSchedulerDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSchedulerConfig.\nfunc (in *MachineSchedulerConfig) DeepCopy() *MachineSchedulerConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineSchedulerConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *MachineSeccompProfile) DeepCopyInto(out *MachineSeccompProfile) {\n\t*out = *in\n\tin.MachineSeccompProfileValue.DeepCopyInto(&out.MachineSeccompProfileValue)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MachineSeccompProfile.\nfunc (in *MachineSeccompProfile) DeepCopy() *MachineSeccompProfile {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(MachineSeccompProfile)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *NetworkConfig) DeepCopyInto(out *NetworkConfig) {\n\t*out = *in\n\tif in.NetworkInterfaces != nil {\n\t\tin, out := &in.NetworkInterfaces, &out.NetworkInterfaces\n\t\t*out = make(NetworkDeviceList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Device)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.NameServers != nil {\n\t\tin, out := &in.NameServers, &out.NameServers\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.ExtraHostEntries != nil {\n\t\tin, out := &in.ExtraHostEntries, &out.ExtraHostEntries\n\t\t*out = make([]*ExtraHost, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(ExtraHost)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t}\n\tif in.NetworkKubeSpan != nil {\n\t\tin, out := &in.NetworkKubeSpan, &out.NetworkKubeSpan\n\t\t*out = new(NetworkKubeSpan)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.NetworkDisableSearchDomain != nil {\n\t\tin, out := &in.NetworkDisableSearchDomain, &out.NetworkDisableSearchDomain\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfig.\nfunc (in *NetworkConfig) DeepCopy() *NetworkConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(NetworkConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in NetworkDeviceList) DeepCopyInto(out *NetworkDeviceList) {\n\t{\n\t\tin := &in\n\t\t*out = make(NetworkDeviceList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Device)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDeviceList.\nfunc (in NetworkDeviceList) DeepCopy() NetworkDeviceList {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(NetworkDeviceList)\n\tin.DeepCopyInto(out)\n\treturn *out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *NetworkDeviceSelector) DeepCopyInto(out *NetworkDeviceSelector) {\n\t*out = *in\n\tif in.NetworkDevicePhysical != nil {\n\t\tin, out := &in.NetworkDevicePhysical, &out.NetworkDevicePhysical\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkDeviceSelector.\nfunc (in *NetworkDeviceSelector) DeepCopy() *NetworkDeviceSelector {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(NetworkDeviceSelector)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *NetworkKubeSpan) DeepCopyInto(out *NetworkKubeSpan) {\n\t*out = *in\n\tif in.KubeSpanEnabled != nil {\n\t\tin, out := &in.KubeSpanEnabled, &out.KubeSpanEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeSpanAdvertiseKubernetesNetworks != nil {\n\t\tin, out := &in.KubeSpanAdvertiseKubernetesNetworks, &out.KubeSpanAdvertiseKubernetesNetworks\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeSpanAllowDownPeerBypass != nil {\n\t\tin, out := &in.KubeSpanAllowDownPeerBypass, &out.KubeSpanAllowDownPeerBypass\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeSpanHarvestExtraEndpoints != nil {\n\t\tin, out := &in.KubeSpanHarvestExtraEndpoints, &out.KubeSpanHarvestExtraEndpoints\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.KubeSpanMTU != nil {\n\t\tin, out := &in.KubeSpanMTU, &out.KubeSpanMTU\n\t\t*out = new(uint32)\n\t\t**out = **in\n\t}\n\tif in.KubeSpanFilters != nil {\n\t\tin, out := &in.KubeSpanFilters, &out.KubeSpanFilters\n\t\t*out = new(KubeSpanFilters)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkKubeSpan.\nfunc (in *NetworkKubeSpan) DeepCopy() *NetworkKubeSpan {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(NetworkKubeSpan)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *PodCheckpointer) DeepCopyInto(out *PodCheckpointer) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodCheckpointer.\nfunc (in *PodCheckpointer) DeepCopy() *PodCheckpointer {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(PodCheckpointer)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) {\n\t*out = *in\n\tif in.Disabled != nil {\n\t\tin, out := &in.Disabled, &out.Disabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.ExtraArgsConfig != nil {\n\t\tin, out := &in.ExtraArgsConfig, &out.ExtraArgsConfig\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig.\nfunc (in *ProxyConfig) DeepCopy() *ProxyConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ProxyConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistriesConfig) DeepCopyInto(out *RegistriesConfig) {\n\t*out = *in\n\tif in.RegistryMirrors != nil {\n\t\tin, out := &in.RegistryMirrors, &out.RegistryMirrors\n\t\t*out = make(map[string]*RegistryMirrorConfig, len(*in))\n\t\tfor key, val := range *in {\n\t\t\tvar outVal *RegistryMirrorConfig\n\t\t\tif val == nil {\n\t\t\t\t(*out)[key] = nil\n\t\t\t} else {\n\t\t\t\tin, out := &val, &outVal\n\t\t\t\t*out = new(RegistryMirrorConfig)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t\t(*out)[key] = outVal\n\t\t}\n\t}\n\tif in.RegistryConfig != nil {\n\t\tin, out := &in.RegistryConfig, &out.RegistryConfig\n\t\t*out = make(map[string]*RegistryConfig, len(*in))\n\t\tfor key, val := range *in {\n\t\t\tvar outVal *RegistryConfig\n\t\t\tif val == nil {\n\t\t\t\t(*out)[key] = nil\n\t\t\t} else {\n\t\t\t\tin, out := &val, &outVal\n\t\t\t\t*out = new(RegistryConfig)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t\t(*out)[key] = outVal\n\t\t}\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistriesConfig.\nfunc (in *RegistriesConfig) DeepCopy() *RegistriesConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistriesConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryAuthConfig) DeepCopyInto(out *RegistryAuthConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryAuthConfig.\nfunc (in *RegistryAuthConfig) DeepCopy() *RegistryAuthConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryAuthConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryConfig) DeepCopyInto(out *RegistryConfig) {\n\t*out = *in\n\tif in.RegistryTLS != nil {\n\t\tin, out := &in.RegistryTLS, &out.RegistryTLS\n\t\t*out = new(RegistryTLSConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.RegistryAuth != nil {\n\t\tin, out := &in.RegistryAuth, &out.RegistryAuth\n\t\t*out = new(RegistryAuthConfig)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryConfig.\nfunc (in *RegistryConfig) DeepCopy() *RegistryConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryKubernetesConfig) DeepCopyInto(out *RegistryKubernetesConfig) {\n\t*out = *in\n\tif in.RegistryDisabled != nil {\n\t\tin, out := &in.RegistryDisabled, &out.RegistryDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryKubernetesConfig.\nfunc (in *RegistryKubernetesConfig) DeepCopy() *RegistryKubernetesConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryKubernetesConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryMirrorConfig) DeepCopyInto(out *RegistryMirrorConfig) {\n\t*out = *in\n\tif in.MirrorEndpoints != nil {\n\t\tin, out := &in.MirrorEndpoints, &out.MirrorEndpoints\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.MirrorOverridePath != nil {\n\t\tin, out := &in.MirrorOverridePath, &out.MirrorOverridePath\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryMirrorConfig.\nfunc (in *RegistryMirrorConfig) DeepCopy() *RegistryMirrorConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryMirrorConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryServiceConfig) DeepCopyInto(out *RegistryServiceConfig) {\n\t*out = *in\n\tif in.RegistryDisabled != nil {\n\t\tin, out := &in.RegistryDisabled, &out.RegistryDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryServiceConfig.\nfunc (in *RegistryServiceConfig) DeepCopy() *RegistryServiceConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryServiceConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *RegistryTLSConfig) DeepCopyInto(out *RegistryTLSConfig) {\n\t*out = *in\n\tif in.TLSClientIdentity != nil {\n\t\tin, out := &in.TLSClientIdentity, &out.TLSClientIdentity\n\t\t*out = (*in).DeepCopy()\n\t}\n\tif in.TLSCA != nil {\n\t\tin, out := &in.TLSCA, &out.TLSCA\n\t\t*out = make(Base64Bytes, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.TLSInsecureSkipVerify != nil {\n\t\tin, out := &in.TLSInsecureSkipVerify, &out.TLSInsecureSkipVerify\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryTLSConfig.\nfunc (in *RegistryTLSConfig) DeepCopy() *RegistryTLSConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(RegistryTLSConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *ResourcesConfig) DeepCopyInto(out *ResourcesConfig) {\n\t*out = *in\n\tin.Requests.DeepCopyInto(&out.Requests)\n\tin.Limits.DeepCopyInto(&out.Limits)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourcesConfig.\nfunc (in *ResourcesConfig) DeepCopy() *ResourcesConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(ResourcesConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Route) DeepCopyInto(out *Route) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route.\nfunc (in *Route) DeepCopy() *Route {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Route)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *STP) DeepCopyInto(out *STP) {\n\t*out = *in\n\tif in.STPEnabled != nil {\n\t\tin, out := &in.STPEnabled, &out.STPEnabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new STP.\nfunc (in *STP) DeepCopy() *STP {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(STP)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *SchedulerConfig) DeepCopyInto(out *SchedulerConfig) {\n\t*out = *in\n\tif in.ExtraArgsConfig != nil {\n\t\tin, out := &in.ExtraArgsConfig, &out.ExtraArgsConfig\n\t\t*out = make(Args, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ExtraVolumesConfig != nil {\n\t\tin, out := &in.ExtraVolumesConfig, &out.ExtraVolumesConfig\n\t\t*out = make([]VolumeMountConfig, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.EnvConfig != nil {\n\t\tin, out := &in.EnvConfig, &out.EnvConfig\n\t\t*out = make(map[string]string, len(*in))\n\t\tfor key, val := range *in {\n\t\t\t(*out)[key] = val\n\t\t}\n\t}\n\tif in.ResourcesConfig != nil {\n\t\tin, out := &in.ResourcesConfig, &out.ResourcesConfig\n\t\t*out = new(ResourcesConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tin.SchedulerConfig.DeepCopyInto(&out.SchedulerConfig)\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerConfig.\nfunc (in *SchedulerConfig) DeepCopy() *SchedulerConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(SchedulerConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *SystemDiskEncryptionConfig) DeepCopyInto(out *SystemDiskEncryptionConfig) {\n\t*out = *in\n\tif in.StatePartition != nil {\n\t\tin, out := &in.StatePartition, &out.StatePartition\n\t\t*out = new(EncryptionConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.EphemeralPartition != nil {\n\t\tin, out := &in.EphemeralPartition, &out.EphemeralPartition\n\t\t*out = new(EncryptionConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SystemDiskEncryptionConfig.\nfunc (in *SystemDiskEncryptionConfig) DeepCopy() *SystemDiskEncryptionConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(SystemDiskEncryptionConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *TimeConfig) DeepCopyInto(out *TimeConfig) {\n\t*out = *in\n\tif in.TimeDisabled != nil {\n\t\tin, out := &in.TimeDisabled, &out.TimeDisabled\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.TimeServers != nil {\n\t\tin, out := &in.TimeServers, &out.TimeServers\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TimeConfig.\nfunc (in *TimeConfig) DeepCopy() *TimeConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(TimeConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *UdevConfig) DeepCopyInto(out *UdevConfig) {\n\t*out = *in\n\tif in.UdevRules != nil {\n\t\tin, out := &in.UdevRules, &out.UdevRules\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UdevConfig.\nfunc (in *UdevConfig) DeepCopy() *UdevConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(UdevConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Unstructured) DeepCopyInto(out *Unstructured) {\n\tclone := in.DeepCopy()\n\t*out = *clone\n\treturn\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *VIPEquinixMetalConfig) DeepCopyInto(out *VIPEquinixMetalConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VIPEquinixMetalConfig.\nfunc (in *VIPEquinixMetalConfig) DeepCopy() *VIPEquinixMetalConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(VIPEquinixMetalConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *VIPHCloudConfig) DeepCopyInto(out *VIPHCloudConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VIPHCloudConfig.\nfunc (in *VIPHCloudConfig) DeepCopy() *VIPHCloudConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(VIPHCloudConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *Vlan) DeepCopyInto(out *Vlan) {\n\t*out = *in\n\tif in.VlanAddresses != nil {\n\t\tin, out := &in.VlanAddresses, &out.VlanAddresses\n\t\t*out = make([]string, len(*in))\n\t\tcopy(*out, *in)\n\t}\n\tif in.VlanRoutes != nil {\n\t\tin, out := &in.VlanRoutes, &out.VlanRoutes\n\t\t*out = make([]*Route, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Route)\n\t\t\t\t**out = **in\n\t\t\t}\n\t\t}\n\t}\n\tif in.VlanDHCP != nil {\n\t\tin, out := &in.VlanDHCP, &out.VlanDHCP\n\t\t*out = new(bool)\n\t\t**out = **in\n\t}\n\tif in.VlanVIP != nil {\n\t\tin, out := &in.VlanVIP, &out.VlanVIP\n\t\t*out = new(DeviceVIPConfig)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\tif in.VlanDHCPOptions != nil {\n\t\tin, out := &in.VlanDHCPOptions, &out.VlanDHCPOptions\n\t\t*out = new(DHCPOptions)\n\t\t(*in).DeepCopyInto(*out)\n\t}\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Vlan.\nfunc (in *Vlan) DeepCopy() *Vlan {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(Vlan)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in VlanList) DeepCopyInto(out *VlanList) {\n\t{\n\t\tin := &in\n\t\t*out = make(VlanList, len(*in))\n\t\tfor i := range *in {\n\t\t\tif (*in)[i] != nil {\n\t\t\t\tin, out := &(*in)[i], &(*out)[i]\n\t\t\t\t*out = new(Vlan)\n\t\t\t\t(*in).DeepCopyInto(*out)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VlanList.\nfunc (in VlanList) DeepCopy() VlanList {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(VlanList)\n\tin.DeepCopyInto(out)\n\treturn *out\n}\n\n// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\nfunc (in *VolumeMountConfig) DeepCopyInto(out *VolumeMountConfig) {\n\t*out = *in\n\treturn\n}\n\n// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeMountConfig.\nfunc (in *VolumeMountConfig) DeepCopy() *VolumeMountConfig {\n\tif in == nil {\n\t\treturn nil\n\t}\n\tout := new(VolumeMountConfig)\n\tin.DeepCopyInto(out)\n\treturn out\n}\n"
  },
  {
    "path": "pkg/machinery/config/validation/mode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage validation\n\nimport \"fmt\"\n\n// RuntimeMode abstracts current runtime mode.\ntype RuntimeMode interface {\n\tfmt.Stringer\n\tRequiresInstall() bool\n\tInContainer() bool\n}\n"
  },
  {
    "path": "pkg/machinery/config/validation/validation.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package validation provides validation options for the config Validate method.\npackage validation\n\n// Options additional validation parameters for the config Validate method.\ntype Options struct {\n\t// Local should disable part of the validation flow which won't work on the host machine.\n\tLocal bool\n\t// Strict mode returns warnings as errors.\n\tStrict bool\n}\n\n// Option represents an additional validation parameter for the config Validate method.\ntype Option func(opts *Options)\n\n// NewOptions creates new validation options.\nfunc NewOptions(options ...Option) *Options {\n\topts := &Options{}\n\tfor _, f := range options {\n\t\tf(opts)\n\t}\n\n\treturn opts\n}\n\n// WithLocal enables local flag.\nfunc WithLocal() Option {\n\treturn func(opts *Options) {\n\t\topts.Local = true\n\t}\n}\n\n// WithStrict enables strict flag.\nfunc WithStrict() Option {\n\treturn func(opts *Options) {\n\t\topts.Strict = true\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/constants/amd64.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !amd64.v1\n\npackage constants\n\nconst (\n\t// MinimumGOAMD64Level is the minimum x86_64 microarchitecture level required by Talos.\n\tMinimumGOAMD64Level = 2\n)\n"
  },
  {
    "path": "pkg/machinery/constants/amd64_v1.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build amd64.v1\n\npackage constants\n\nconst (\n\t// MinimumGOAMD64Level is the minimum x86_64 microarchitecture level required by Talos.\n\tMinimumGOAMD64Level = 1\n)\n"
  },
  {
    "path": "pkg/machinery/constants/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package constants defines constants used throughout Talos.\npackage constants\n\nimport (\n\t\"time\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\nconst (\n\t// DefaultKernelVersion is the default Linux kernel version.\n\tDefaultKernelVersion = \"6.18.18-talos\"\n\n\t// KernelParamConfig is the kernel parameter name for specifying the URL.\n\t// to the config.\n\tKernelParamConfig = \"talos.config\"\n\n\t// KernelParamConfigInline is the kernel parameter name for specifying the inline config.\n\t//\n\t// The inline config should be base64 encoded and zstd-compressed.\n\tKernelParamConfigInline = \"talos.config.inline\"\n\n\t// KernelParamConfigEarly is the kernel parameter name for specifying the inline config (as the first source).\n\t//\n\t// The inline config should be base64 encoded and zstd-compressed.\n\tKernelParamConfigEarly = \"talos.config.early\"\n\n\t// KernelParamConfigOAuthClientID is the kernel parameter name for specifying the OAuth2 client ID.\n\tKernelParamConfigOAuthClientID = \"talos.config.oauth.client_id\"\n\n\t// KernelParamConfigOAuthClientSecret is the kernel parameter name for specifying the OAuth2 client secret.\n\tKernelParamConfigOAuthClientSecret = \"talos.config.oauth.client_secret\"\n\n\t// KernelParamConfigOAuthAudience is the kernel parameter name for specifying the OAuth2 audience.\n\tKernelParamConfigOAuthAudience = \"talos.config.oauth.audience\"\n\n\t// KernelParamConfigOAuthScope is the kernel parameter name for specifying the OAuth2 scopes (might be repeated).\n\tKernelParamConfigOAuthScope = \"talos.config.oauth.scope\"\n\n\t// KernelParamConfigOAuthDeviceAuthURL is the kernel parameter name for specifying the OAuth2 device auth URL.\n\tKernelParamConfigOAuthDeviceAuthURL = \"talos.config.oauth.device_auth_url\"\n\n\t// KernelParamConfigOAuthTokenURL is the kernel parameter name for specifying the OAuth2 token URL.\n\tKernelParamConfigOAuthTokenURL = \"talos.config.oauth.token_url\"\n\n\t// KernelParamConfigOAuthExtraVariable is the kernel parameter name for specifying the OAuth2 extra variable (might be repeated).\n\tKernelParamConfigOAuthExtraVariable = \"talos.config.oauth.extra_variable\"\n\n\t// ConfigNone indicates no config is required.\n\tConfigNone = \"none\"\n\n\t// KernelParamPlatform is the kernel parameter name for specifying the\n\t// platform.\n\tKernelParamPlatform = \"talos.platform\"\n\n\t// KernelParamEventsSink is the kernel parameter name for specifying the\n\t// events sink server.\n\tKernelParamEventsSink = \"talos.events.sink\"\n\n\t// KernelParamLoggingKernel is the kernel parameter name for specifying the\n\t// kernel log delivery destination.\n\tKernelParamLoggingKernel = \"talos.logging.kernel\"\n\n\t// KernelParamWipe is the kernel parameter name for specifying the\n\t// disk to wipe on the next boot and reboot.\n\tKernelParamWipe = \"talos.experimental.wipe\"\n\n\t// KernelParamDeviceSettleTime is the kernel parameter name for specifying the\n\t// extra device settle timeout.\n\tKernelParamDeviceSettleTime = \"talos.device.settle_time\"\n\n\t// KernelParamCGroups is the legacy kernel parameter not supported anymore.\n\tKernelParamCGroups = \"talos.unified_cgroup_hierarchy\"\n\n\t// KernelParamAuditdDisabled is the kernel parameter name for disabling auditd service.\n\tKernelParamAuditdDisabled = \"talos.auditd.disabled\"\n\n\t// KernelParamDashboardDisabled is the kernel parameter name for disabling the dashboard.\n\tKernelParamDashboardDisabled = \"talos.dashboard.disabled\"\n\n\t// KernelParamDashboardConsole is the kernel parameter name for specifying the dashboard console.\n\tKernelParamDashboardConsole = \"talos.dashboard.console\"\n\n\t// KernelParamEnvironment is the kernel parameter name for passing process environment.\n\tKernelParamEnvironment = \"talos.environment\"\n\n\t// KernelParamNetIfnames is the kernel parameter name to control predictable network interface names.\n\tKernelParamNetIfnames = \"net.ifnames\"\n\n\t// KernelParamHaltIfInstalled is the kernel parameter name to control if Talos should pause if booting from boot media while Talos is already installed.\n\tKernelParamHaltIfInstalled = \"talos.halt_if_installed\"\n\n\t// KernelParamSELinux is the kernel parameter name to enable/disable SELinux.\n\tKernelParamSELinux = \"selinux\"\n\n\t// KernelParamSELinuxEnforcing is the kernel parameter name to control SELinux enforcement mode.\n\tKernelParamSELinuxEnforcing = \"enforcing\"\n\n\t// KernelParamHostname is the kernel parameter name for specifying the\n\t// hostname.\n\tKernelParamHostname = \"talos.hostname\"\n\n\t// KernelParamShutdown is the kernel parameter for specifying the\n\t// shutdown type (halt/poweroff).\n\tKernelParamShutdown = \"talos.shutdown\"\n\n\t// KernelParamNetworkInterfaceIgnore is the kernel parameter for specifying network interfaces which should be ignored by talos.\n\tKernelParamNetworkInterfaceIgnore = \"talos.network.interface.ignore\"\n\n\t// KernelParamVlan is the kernel parameter for specifying vlan for the interface.\n\tKernelParamVlan = \"vlan\"\n\n\t// KernelParamBonding is the kernel parameter for specifying bonded network interfaces.\n\tKernelParamBonding = \"bond\"\n\n\t// KernelParamPanic is the kernel parameter name for specifying the time to wait until rebooting after kernel panic (0 disables reboot).\n\tKernelParamPanic = \"panic\"\n\n\t// KernelParamSideroLink is the kernel parameter name to specify SideroLink API endpoint.\n\tKernelParamSideroLink = \"siderolink.api\"\n\n\t// KernelParamEquinixMetalEvents is the kernel parameter name to specify the Equinix Metal phone home endpoint.\n\t// This param is injected by Equinix Metal and depends on the device ID and datacenter.\n\tKernelParamEquinixMetalEvents = \"em.events_url\"\n\n\t// KernelParamEnforceModuleSigVerify is the kernel parameter name to specify module signature verification enforcement.\n\t// see https://github.com/siderolabs/talos/issues/11989\n\tKernelParamEnforceModuleSigVerify = \"module.sig_enforce\"\n\n\t// NewRoot is the path where the switchroot target is mounted.\n\tNewRoot = \"/root\"\n\n\t// ExtensionLayers is the path where the extensions layers are stored.\n\tExtensionLayers = \"/layers\"\n\n\t// ExtensionsConfigFile is the extensions layers configuration file name in the initramfs.\n\tExtensionsConfigFile = \"/extensions.yaml\"\n\n\t// ExtensionsRuntimeConfigFile extensions layers configuration file name in the rootfs.\n\tExtensionsRuntimeConfigFile = \"/etc/extensions.yaml\"\n\n\t// EFIPartitionLabel is the label of the partition to use for mounting at\n\t// the boot path.\n\tEFIPartitionLabel = \"EFI\"\n\n\t// EFIMountPoint is the label of the partition to use for mounting at\n\t// the boot path.\n\tEFIMountPoint = BootMountPoint + \"/EFI\"\n\n\t// EFIVarsMountPoint is mount point for efivars filesystem type.\n\t// https://www.kernel.org/doc/html/next/filesystems/efivarfs.html\n\tEFIVarsMountPoint = \"/sys/firmware/efi/efivars\"\n\n\t// BIOSGrubPartitionLabel is the label of the partition used by grub's second\n\t// stage bootloader.\n\tBIOSGrubPartitionLabel = \"BIOS\"\n\n\t// MetaPartitionLabel is the label of the meta partition.\n\tMetaPartitionLabel = \"META\"\n\n\t// StatePartitionLabel is the label of the state partition.\n\tStatePartitionLabel = \"STATE\"\n\n\t// StateMountPoint is the label of the partition to use for mounting at\n\t// the state path.\n\tStateMountPoint = \"/system/state\"\n\n\t// StateSelinuxLabel is the label to be assigned to the state mount.\n\tStateSelinuxLabel = \"system_u:object_r:system_state_t:s0\"\n\n\t// BootPartitionLabel is the label of the partition to use for mounting at\n\t// the boot path.\n\tBootPartitionLabel = \"BOOT\"\n\n\t// BootMountPoint is the label of the partition to use for mounting at\n\t// the boot path.\n\tBootMountPoint = \"/boot\"\n\n\t// EphemeralPartitionLabel is the label of the partition to use for\n\t// mounting at the data path.\n\tEphemeralPartitionLabel = \"EPHEMERAL\"\n\n\t// EphemeralMountPoint is the label of the partition to use for mounting at\n\t// the data path.\n\tEphemeralMountPoint = \"/var\"\n\n\t// EphemeralSelinuxLabel is the label to be assigned to the ephemeral mount.\n\tEphemeralSelinuxLabel = \"system_u:object_r:ephemeral_t:s0\"\n\n\t// OptSELinuxLabel is the SELinux label to be set for /opt overlay mount.\n\tOptSELinuxLabel = \"system_u:object_r:opt_t:s0\"\n\n\t// RootMountPoint is the label of the partition to use for mounting at\n\t// the root path.\n\tRootMountPoint = \"/\"\n\n\t// ISOFilesystemLabel is the label of the ISO file system for the Talos\n\t// installer.\n\tISOFilesystemLabel = \"TALOS\"\n\n\t// KubernetesDefaultCertificateValidityDuration specifies default certificate duration for Kubernetes generated certificates.\n\tKubernetesDefaultCertificateValidityDuration = time.Hour * 24 * 365\n\n\t// KubernetesConfigBaseDir is the path to the base Kubernetes configuration directory.\n\tKubernetesConfigBaseDir = \"/etc/kubernetes\"\n\n\t// KubernetesConfigSELinuxLabel is the SELinux label to be set for the Kubernetes configuration directory overlay mount.\n\tKubernetesConfigSELinuxLabel = \"system_u:object_r:k8s_conf_t:s0\"\n\n\t// KubeletPluginsSELinuxLabel is the SELinux label to be set for the Kubernetes plugin directory overlay mount.\n\tKubeletPluginsSELinuxLabel = \"system_u:object_r:k8s_plugin_t:s0\"\n\n\t// DefaultCertificatesDir is the path the Kubernetes PKI directory.\n\tDefaultCertificatesDir = KubernetesConfigBaseDir + \"/\" + \"pki\"\n\n\t// KubernetesCACert is the path to the root CA certificate.\n\tKubernetesCACert = DefaultCertificatesDir + \"/\" + \"ca.crt\"\n\n\t// EtcdCACert is the path to the etcd CA certificate.\n\tEtcdCACert = EtcdPKIPath + \"/\" + \"ca.crt\"\n\n\t// EtcdCAKey is the path to the etcd CA private key.\n\tEtcdCAKey = EtcdPKIPath + \"/\" + \"ca.key\"\n\n\t// EtcdCert is the path to the etcd server certificate.\n\tEtcdCert = EtcdPKIPath + \"/\" + \"server.crt\"\n\n\t// EtcdKey is the path to the etcd server private key.\n\tEtcdKey = EtcdPKIPath + \"/\" + \"server.key\"\n\n\t// EtcdPeerCert is the path to the etcd peer certificate.\n\tEtcdPeerCert = EtcdPKIPath + \"/\" + \"peer.crt\"\n\n\t// EtcdPeerKey is the path to the etcd peer private key.\n\tEtcdPeerKey = EtcdPKIPath + \"/\" + \"peer.key\"\n\n\t// EtcdAdminCert is the path to the talos client certificate.\n\tEtcdAdminCert = EtcdPKIPath + \"/\" + \"admin.crt\"\n\n\t// EtcdAdminKey is the path to the talos client private key.\n\tEtcdAdminKey = EtcdPKIPath + \"/\" + \"admin.key\"\n\n\t// EtcdClientPort defines the port etcd listen on for client traffic.\n\tEtcdClientPort = 2379\n\n\t// EtcdPeerPort defines the port etcd listens on for peer traffic.\n\tEtcdPeerPort = 2380\n\n\t// KubernetesAdminCertCommonName defines CN property of Kubernetes admin certificate.\n\tKubernetesAdminCertCommonName = \"admin\"\n\n\t// KubernetesTalosAdminCertCommonName defines CN property of Kubernetes admin certificate used by Talos itself.\n\tKubernetesTalosAdminCertCommonName = \"talos:admin\"\n\n\t// KubernetesAdminCertOrganization defines Organization values of Kubernetes admin certificate.\n\tKubernetesAdminCertOrganization = \"system:masters\"\n\n\t// KubernetesAPIServerKubeletClientCommonName defines CN property of Kubernetes API server certificate to access kubelet API.\n\tKubernetesAPIServerKubeletClientCommonName = \"apiserver-kubelet-client\"\n\n\t// KubernetesControllerManagerOrganization defines Organization value of kube-controller-manager client certificate.\n\tKubernetesControllerManagerOrganization = \"system:kube-controller-manager\"\n\n\t// KubernetesSchedulerOrganization defines Organization value of kube-scheduler client certificate.\n\tKubernetesSchedulerOrganization = \"system:kube-scheduler\"\n\n\t// KubernetesAdminCertDefaultLifetime defines default lifetime for Kubernetes generated admin certificate.\n\tKubernetesAdminCertDefaultLifetime = 365 * 24 * time.Hour\n\n\t// KubebernetesStaticSecretsDir defines ephemeral directory which contains rendered secrets for controlplane components.\n\tKubebernetesStaticSecretsDir = \"/system/secrets/kubernetes\"\n\n\t// KubebernetesStaticConfigDir defines ephemeral directory which contains rendered configs for controlplane components.\n\tKubebernetesStaticConfigDir = \"/system/config/kubernetes\"\n\n\t// KubernetesAuditLogDir defines the ephemeral directory where the kube-apiserver will store its audit logs.\n\tKubernetesAuditLogDir = EphemeralMountPoint + \"/\" + \"log\" + \"/\" + \"audit\" + \"/\" + \"kube\"\n\n\t// KubernetesAPIServerSecretsDir defines directory with kube-apiserver secrets.\n\tKubernetesAPIServerSecretsDir = KubebernetesStaticSecretsDir + \"/\" + \"kube-apiserver\"\n\n\t// KubernetesAPIServerSecretsDirSELinuxLabel defines SELinux label for the directory with kube-apiserver secrets.\n\tKubernetesAPIServerSecretsDirSELinuxLabel = \"system_u:object_r:kube_apiserver_secret_t:s0\"\n\n\t// KubernetesAPIServerConfigDir defines directory with kube-apiserver configs.\n\tKubernetesAPIServerConfigDir = KubebernetesStaticConfigDir + \"/\" + \"kube-apiserver\"\n\n\t// KubernetesAPIServerConfigDirSELinuxLabel defines SELinux label for the directory with kube-apiserver configs.\n\tKubernetesAPIServerConfigDirSELinuxLabel = \"system_u:object_r:kube_apiserver_config_t:s0\"\n\n\t// KubernetesControllerManagerSecretsDir defines ephemeral directory with kube-controller-manager secrets.\n\tKubernetesControllerManagerSecretsDir = KubebernetesStaticSecretsDir + \"/\" + \"kube-controller-manager\"\n\n\t// KubernetesControllerManagerSecretsDirSELinuxLabel defines SELinux label for the ephemeral directory with kube-controller-manager secrets.\n\tKubernetesControllerManagerSecretsDirSELinuxLabel = \"system_u:object_r:kube_controller_manager_secret_t:s0\"\n\n\t// KubernetesSchedulerSecretsDir defines ephemeral directory with kube-scheduler secrets.\n\tKubernetesSchedulerSecretsDir = KubebernetesStaticSecretsDir + \"/\" + \"kube-scheduler\"\n\n\t// KubernetesSchedulerSecretsDirSELinuxLabel defines SELinux label for the ephemeral directory with kube-scheduler secrets.\n\tKubernetesSchedulerSecretsDirSELinuxLabel = \"system_u:object_r:kube_scheduler_secret_t:s0\"\n\n\t// KubernetesSchedulerConfigDir defines ephemeral directory with kube-scheduler configs.\n\tKubernetesSchedulerConfigDir = KubebernetesStaticConfigDir + \"/\" + \"kube-scheduler\"\n\n\t// KubernetesSchedulerConfigDirSELinuxLabel defines SELinux label for the ephemeral directory with kube-scheduler configs.\n\tKubernetesSchedulerConfigDirSELinuxLabel = \"system_u:object_r:kube_scheduler_config_t:s0\"\n\n\t// KubernetesAPIServerRunUser defines UID to the API Server.\n\tKubernetesAPIServerRunUser = 65534\n\n\t// KubernetesAPIServerRunGroup defines GID to run the API Server.\n\tKubernetesAPIServerRunGroup = 65534\n\n\t// KubernetesControllerManagerRunUser defines UID to the Controller Manager.\n\tKubernetesControllerManagerRunUser = 65535\n\n\t// KubernetesControllerManagerRunGroup defines GID to run the Controller Manager.\n\tKubernetesControllerManagerRunGroup = 65535\n\n\t// KubernetesSchedulerRunUser defines UID to the Scheduler.\n\tKubernetesSchedulerRunUser = 65536\n\n\t// KubernetesSchedulerRunGroup defines GID to run the Scheduler.\n\tKubernetesSchedulerRunGroup = 65536\n\n\t// KubeletBootstrapKubeconfig is the path to the kubeconfig required to\n\t// bootstrap the kubelet.\n\tKubeletBootstrapKubeconfig = KubernetesConfigBaseDir + \"/\" + \"bootstrap-kubeconfig\"\n\n\t// KubeletCredentialProviderBinDir is the path to the directory where kubelet credential provider binaries are stored.\n\tKubeletCredentialProviderBinDir = \"/usr/local/lib/kubelet/credentialproviders\"\n\n\t// KubeletCredentialProviderConfig is the path to the kubelet credential provider config.\n\tKubeletCredentialProviderConfig = KubernetesConfigBaseDir + \"/\" + \"kubelet-credentialproviderconfig.yaml\"\n\n\t// KubeletPort is the kubelet port for secure API.\n\tKubeletPort = 10250\n\n\t// KubeletOOMScoreAdj oom_score_adj config.\n\tKubeletOOMScoreAdj = -450\n\n\t// KubeletPKIDir is the path to the directory where kubelet stores issued certificates and keys.\n\tKubeletPKIDir = \"/var/lib/kubelet/pki\"\n\n\t// SystemKubeletPKIDir is the path to the directory where Talos copies kubelet issued certificates and keys.\n\tSystemKubeletPKIDir = \"/system/secrets/kubelet\"\n\n\t// KubeletShutdownGracePeriod is the kubelet shutdown grace period.\n\tKubeletShutdownGracePeriod = 30 * time.Second\n\n\t// KubeletShutdownGracePeriodCriticalPods is the kubelet shutdown grace period for critical pods.\n\t//\n\t// Should be less than KubeletShutdownGracePeriod.\n\tKubeletShutdownGracePeriodCriticalPods = 10 * time.Second\n\n\t// SeccompProfilesDirectory is the path to the directory where user provided seccomp profiles are mounted inside Kubelet.\n\tSeccompProfilesDirectory = \"/var/lib/kubelet/seccomp/profiles\"\n\n\t// DefaultKubernetesVersion is the default target version of the control plane.\n\t// renovate: datasource=github-releases depName=kubernetes/kubernetes\n\tDefaultKubernetesVersion = \"1.36.0-alpha.2\"\n\n\t// SupportedKubernetesVersions is the number of Kubernetes versions supported by Talos starting from DefaultKubernesVersion going backwards.\n\tSupportedKubernetesVersions = 6\n\n\t// DefaultControlPlanePort is the default port to use for the control plane.\n\tDefaultControlPlanePort = 6443\n\n\t// KubeletImage is the enforced kubelet image to use.\n\tKubeletImage = \"ghcr.io/siderolabs/kubelet\"\n\n\t// KubeProxyImage is the enforced kube-proxy image to use for the control plane.\n\tKubeProxyImage = \"registry.k8s.io/kube-proxy\"\n\n\t// KubernetesAPIServerImage is the enforced apiserver image to use for the control plane.\n\tKubernetesAPIServerImage = \"registry.k8s.io/kube-apiserver\"\n\n\t// KubernetesControllerManagerImage is the enforced controllermanager image to use for the control plane.\n\tKubernetesControllerManagerImage = \"registry.k8s.io/kube-controller-manager\"\n\n\t// KubernetesSchedulerImage is the enforced scheduler image to use for the control plane.\n\tKubernetesSchedulerImage = \"registry.k8s.io/kube-scheduler\"\n\n\t// CoreDNSImage is the enforced CoreDNS image to use.\n\tCoreDNSImage = \"registry.k8s.io/coredns/coredns\"\n\n\t// DefaultCoreDNSVersion is the default version for the CoreDNS.\n\t// renovate: datasource=docker depName=registry.k8s.io/coredns/coredns\n\tDefaultCoreDNSVersion = \"v1.14.2\"\n\n\t// LabelNodeRoleControlPlane is the node label required by a control plane node.\n\tLabelNodeRoleControlPlane = \"node-role.kubernetes.io/control-plane\"\n\n\t// LabelExcludeFromExternalLB can be set on a node to exclude it from external load balancers.\n\tLabelExcludeFromExternalLB = \"node.kubernetes.io/exclude-from-external-load-balancers\"\n\n\t// ManifestsDirectory is the directory that contains all static manifests.\n\tManifestsDirectory = KubernetesConfigBaseDir + \"/\" + \"manifests\"\n\n\t// TalosManifestPrefix is the prefix for static pod files created in ManifestsDirectory by Talos.\n\tTalosManifestPrefix = \"talos-\"\n\n\t// KubeletKubeconfig is the generated kubeconfig for kubelet.\n\tKubeletKubeconfig = KubernetesConfigBaseDir + \"/\" + \"kubeconfig-kubelet\"\n\n\t// KubeletSystemReservedCPU cpu system reservation value for kubelet kubeconfig.\n\tKubeletSystemReservedCPU = \"50m\"\n\n\t// KubeletSystemReservedMemoryControlPlane memory system reservation value for kubelet kubeconfig (controlplane nodes).\n\tKubeletSystemReservedMemoryControlPlane = \"512Mi\"\n\n\t// KubeletSystemReservedMemoryWorker memory system reservation value for kubelet kubeconfig (worker nodes).\n\tKubeletSystemReservedMemoryWorker = \"384Mi\"\n\n\t// KubeletSystemReservedPid pid system reservation value for kubelet kubeconfig.\n\tKubeletSystemReservedPid = \"100\"\n\n\t// KubeletSystemReservedEphemeralStorage ephemeral-storage system reservation value for kubelet kubeconfig.\n\tKubeletSystemReservedEphemeralStorage = \"256Mi\"\n\n\t// DefaultEtcdVersion is the default target version of etcd.\n\t// renovate: datasource=docker depName=registry.k8s.io/etcd\n\tDefaultEtcdVersion = \"v3.6.8\"\n\n\t// EtcdRootTalosKey is the root etcd key for Talos-specific storage.\n\tEtcdRootTalosKey = \"talos:v1\"\n\n\t// EtcdTalosEtcdUpgradeMutex is the etcd mutex prefix to be used to set an etcd upgrade lock.\n\tEtcdTalosEtcdUpgradeMutex = EtcdRootTalosKey + \":etcdUpgradeMutex\"\n\n\t// EtcdTalosManifestApplyMutex is the etcd mutex prefix used by manifest apply controller.\n\tEtcdTalosManifestApplyMutex = EtcdRootTalosKey + \":manifestApplyMutex\"\n\n\t// EtcdTalosServiceAccountCRDControllerMutex is the etcd mutex prefix used by Talos ServiceAccount crd controller.\n\tEtcdTalosServiceAccountCRDControllerMutex = EtcdRootTalosKey + \":serviceAccountCRDController\"\n\n\t// EtcdImage is the reposistory for the etcd image.\n\tEtcdImage = \"registry.k8s.io/etcd\"\n\n\t// EtcdPKIPath is the path to the etcd PKI directory.\n\tEtcdPKIPath = \"/system/secrets/etcd\"\n\n\t// EtcdPKISELinuxLabel is the SELinux label for the etcd PKI directory.\n\tEtcdPKISELinuxLabel = \"system_u:object_r:etcd_pki_t:s0\"\n\n\t// EtcdDataPath is the path where etcd stores its' data.\n\tEtcdDataPath = \"/var/lib/etcd\"\n\n\t// EtcdDataVolumeID is the ID of the etcd data volume.\n\tEtcdDataVolumeID = \"ETCD\"\n\n\t// EtcdDataSELinuxLabel is the SELinux label for the etcd data directory.\n\tEtcdDataSELinuxLabel = \"system_u:object_r:etcd_data_t:s0\"\n\n\t// EtcdRecoverySnapshotPath is the path where etcd snapshot is uploaded for recovery.\n\tEtcdRecoverySnapshotPath = \"/var/lib/etcd.snapshot\"\n\n\t// EtcdUserID is the user ID for the etcd process.\n\tEtcdUserID = 60\n\n\t// ConfigFilename is the filename of the saved config in STATE partition.\n\tConfigFilename = \"config.yaml\"\n\n\t// EmbeddedConfigDirectory is the path to the embedded config is placed inside rootfs.\n\tEmbeddedConfigDirectory = \"/usr/local/etc/talos/\"\n\n\t// ConfigTryTimeout is the timeout of the config apply in try mode.\n\tConfigTryTimeout = time.Minute\n\n\t// MetalConfigISOLabel is the volume label for ISO based configuration.\n\tMetalConfigISOLabel = \"metal-iso\"\n\n\t// ConfigGuestInfo is the name of the VMware guestinfo config strategy.\n\tConfigGuestInfo = \"guestinfo\"\n\n\t// VMwareGuestInfoPrefix is the prefix to extraConfig variables.\n\tVMwareGuestInfoPrefix = \"guestinfo.\"\n\n\t// VMwareGuestInfoConfigKey is the guestinfo key used to provide a config file.\n\tVMwareGuestInfoConfigKey = \"talos.config\"\n\n\t// VMwareGuestInfoFallbackKey is the fallback guestinfo key used to provide a config file.\n\tVMwareGuestInfoFallbackKey = \"userdata\"\n\n\t// VMwareGuestInfoMetadataKey is the guestinfo key used to provide metadata.\n\tVMwareGuestInfoMetadataKey = \"metadata\"\n\n\t// VMwareGuestInfoOvfEnvKey is the guestinfo key used to provide the OVF environment.\n\tVMwareGuestInfoOvfEnvKey = \"ovfenv\"\n\n\t// AuditPolicyPath is the path to the audit-policy.yaml relative to initramfs.\n\tAuditPolicyPath = KubernetesConfigBaseDir + \"/\" + \"audit-policy.yaml\"\n\n\t// EncryptionConfigPath is the path to the EncryptionConfig relative to initramfs.\n\tEncryptionConfigPath = KubernetesConfigBaseDir + \"/\" + \"encryptionconfig.yaml\"\n\n\t// EncryptionConfigRootfsPath is the path to the EncryptionConfig relative to rootfs.\n\tEncryptionConfigRootfsPath = KubernetesConfigBaseDir + \"/\" + \"encryptionconfig.yaml\"\n\n\t// ApidPort is the port for the apid service.\n\tApidPort = 50000\n\n\t// ApidUserID is the user ID for apid.\n\tApidUserID = 50\n\n\t// DashboardUserID is the user ID for dashboard.\n\t// We use the same user ID as apid so that the dashboard can write to the machined unix socket.\n\tDashboardUserID = ApidUserID\n\n\t// DashboardPriority is the priority for the dashboard service.\n\t// Higher nice value for the dashboard to give more CPU time to other services when under load.\n\tDashboardPriority = 10\n\n\t// TrustdPort is the port for the trustd service.\n\tTrustdPort = 50001\n\n\t// TrustdUserID is the user ID for trustd.\n\tTrustdUserID = 51\n\n\t// DefaultContainerdVersion is the default container runtime version.\n\tDefaultContainerdVersion = \"2.2.2\"\n\n\t// RuncVersion is the runc version.\n\tRuncVersion = \"1.4.1\"\n\n\t// SystemContainerdNamespace is the Containerd namespace for Talos services.\n\tSystemContainerdNamespace = \"system\"\n\n\t// SystemContainerdAddress is the path to the system containerd socket.\n\tSystemContainerdAddress = SystemRunPath + \"/containerd/containerd.sock\"\n\n\t// K8sContainerdNamespace is the Containerd namespace for CRI pods.\n\tK8sContainerdNamespace = \"k8s.io\"\n\n\t// CRIContainerdAddress is the path to the CRI containerd socket address.\n\tCRIContainerdAddress = \"/run/containerd/containerd.sock\"\n\n\t// CRIContainerdConfig is the path to the config for the containerd instance that provides the CRI.\n\tCRIContainerdConfig = \"/etc/cri/containerd.toml\"\n\n\t// EtcCRIConfdPath is the path to the directory providing parts of CRI plugin configuration.\n\tEtcCRIConfdPath = \"/etc/cri/conf.d\"\n\n\t// CRIConfdPath is the path to the subdirectory providing parts of CRI plugin configuration.\n\tCRIConfdPath = \"cri/conf.d\"\n\n\t// CRIConfig is the path to the CRI merged configuration file relative to /etc.\n\tCRIConfig = \"cri/conf.d/cri.toml\"\n\n\t// CRIRegistryConfigPart is the path to the CRI generated registry configuration relative to /etc.\n\tCRIRegistryConfigPart = \"cri/conf.d/01-registries.part\"\n\n\t// CRICustomizationConfigPart is the path to the CRI generated registry configuration relative to /etc.\n\tCRICustomizationConfigPart = \"cri/conf.d/20-customization.part\"\n\n\t// CRIBaseRuntimeSpec is the path to the base runtime spec for the CRI.\n\tCRIBaseRuntimeSpec = \"cri/conf.d/base-spec.json\"\n\n\t// TalosConfigEnvVar is the environment variable for setting the Talos configuration file path.\n\tTalosConfigEnvVar = \"TALOSCONFIG\"\n\n\t// TalosHomeEnvVar is the environment variable for setting the Talos state directory file path.\n\tTalosHomeEnvVar = \"TALOS_HOME\"\n\n\t// APISocketPath is the path to file socket of apid.\n\tAPISocketPath = SystemRunPath + \"/apid/apid.sock\"\n\n\t// APIRuntimeSocketPath is the path to file socket of runtime server for apid.\n\tAPIRuntimeSocketPath = SystemRunPath + \"/apid/runtime.sock\"\n\n\t// APIRuntimeSocketLabel is the SELinux label for apid runtime socket file.\n\tAPIRuntimeSocketLabel = \"system_u:object_r:apid_runtime_socket_t:s0\"\n\n\t// TrustdRuntimeSocketPath is the path to file socket of runtime server for trustd.\n\tTrustdRuntimeSocketPath = SystemRunPath + \"/trustd/runtime.sock\"\n\n\t// TrustdRuntimeSocketLabel is the SELinux label for trustd runtime socket file.\n\tTrustdRuntimeSocketLabel = \"system_u:object_r:trustd_runtime_socket_t:s0\"\n\n\t// MachineSocketPath is the path to file socket of machine API.\n\tMachineSocketPath = SystemRunPath + \"/machined/machine.sock\"\n\n\t// MachineSocketLabel is the SELinux label for socket of machine API.\n\tMachineSocketLabel = \"system_u:object_r:machine_socket_t:s0\"\n\n\t// NetworkSocketPath is the path to file socket of network API.\n\tNetworkSocketPath = SystemRunPath + \"/networkd/networkd.sock\"\n\n\t// ArchVariable is replaced automatically by the target cluster arch.\n\tArchVariable = \"${ARCH}\"\n\n\t// KernelAsset defines a well known name for our kernel filename.\n\tKernelAsset = \"vmlinuz\"\n\n\t// KernelAssetWithArch defines a well known name for our kernel filename with arch variable.\n\tKernelAssetWithArch = \"vmlinuz-\" + ArchVariable\n\n\t// KernelAssetPath is the path to the kernel on disk.\n\tKernelAssetPath = \"/usr/install/%s/\" + KernelAsset\n\n\t// InitramfsAsset defines a well known name for our initramfs filename.\n\tInitramfsAsset = \"initramfs.xz\"\n\n\t// InitramfsAssetWithArch defines a well known name for our initramfs filename with arch variable.\n\tInitramfsAssetWithArch = \"initramfs-\" + ArchVariable + \".xz\"\n\n\t// InitramfsAssetPath is the path to the initramfs on disk.\n\tInitramfsAssetPath = \"/usr/install/%s/\" + InitramfsAsset\n\n\t// RootfsAsset defines a well known name for our rootfs filename.\n\tRootfsAsset = \"rootfs.sqsh\"\n\n\t// UKIAsset defines a well known name for our UKI filename.\n\tUKIAsset = \"vmlinuz.efi\"\n\n\t// UKIAssetPath is the path to the UKI in the installer.\n\tUKIAssetPath = \"/usr/install/%s/\" + UKIAsset\n\n\t// SDStubAsset defines a well known name for our systemd-stub filename.\n\tSDStubAsset = \"systemd-stub.efi\"\n\n\t// SDStubAssetPath is the path to the systemd-stub in the installer.\n\tSDStubAssetPath = \"/usr/install/%s/\" + SDStubAsset\n\n\t// SDBootAsset defines a well known name for our SDBoot filename.\n\tSDBootAsset = \"systemd-boot.efi\"\n\n\t// SDBootAssetPath is the path to the SDBoot in the installer.\n\tSDBootAssetPath = \"/usr/install/%s/\" + SDBootAsset\n\n\t// ImagerOverlayBasePath is the base path for the imager overlay.\n\tImagerOverlayBasePath = \"/overlay\"\n\t// ImagerOverlayArtifactsPath is the path to the artifacts in the imager overlay.\n\tImagerOverlayArtifactsPath = ImagerOverlayBasePath + \"/\" + \"artifacts\"\n\t// ImagerOverlayInstallersPath is the path to the installers in the imager overlay.\n\tImagerOverlayInstallersPath = ImagerOverlayBasePath + \"/\" + \"installers\"\n\t// ImagerOverlayProfilesPath is the path to the profiles in the imager overlay.\n\tImagerOverlayProfilesPath = ImagerOverlayBasePath + \"/\" + \"profiles\"\n\t// ImagerOverlayInstallerDefault is the default installer name.\n\tImagerOverlayInstallerDefault = \"default\"\n\t// ImagerOverlayInstallerDefaultPath is the path to the default installer in the imager overlay.\n\tImagerOverlayInstallerDefaultPath = ImagerOverlayInstallersPath + \"/\" + ImagerOverlayInstallerDefault\n\t// ImagerOverlayExtraOptionsPath is the path to the generated extra options file in the imager overlay.\n\tImagerOverlayExtraOptionsPath = ImagerOverlayBasePath + \"/\" + \"extra-options\"\n\n\t// PlatformKeyAsset defines a well known name for the platform key filename used for auto-enrolling.\n\tPlatformKeyAsset = \"PK.auth\"\n\n\t// KeyExchangeKeyAsset defines a well known name for the key exchange key filename used for auto-enrolling.\n\tKeyExchangeKeyAsset = \"KEK.auth\"\n\n\t// SignatureKeyAsset defines a well known name for the signature key filename used for auto-enrolling.\n\tSignatureKeyAsset = \"db.auth\"\n\n\t// SecureBootSigningKeyAsset defines a well known name for the secure boot signing key filename.\n\tSecureBootSigningKeyAsset = \"uki-signing-key.pem\"\n\n\t// SecureBootSigningCertAsset defines a well known name for the secure boot signing key filename.\n\tSecureBootSigningCertAsset = \"uki-signing-cert.pem\"\n\n\t// PCRSigningKeyAsset defines a well known name for the PCR signing key filename.\n\tPCRSigningKeyAsset = \"pcr-signing-key.pem\"\n\n\t// SDStubDynamicInitrdPath is the path where dynamically generated initrds are placed by systemd-stub.\n\t// https://www.mankier.com/7/systemd-stub#Description\n\tSDStubDynamicInitrdPath = \"/.extra\"\n\n\t// PCRSignatureJSON is the path to the PCR signature JSON file.\n\t// https://www.mankier.com/7/systemd-stub#Initrd_Resources\n\tPCRSignatureJSON = SDStubDynamicInitrdPath + \"/\" + \"tpm2-pcr-signature.json\"\n\n\t// PCRPublicKey is the path to the PCR public key file.\n\t// https://www.mankier.com/7/systemd-stub#Initrd_Resources\n\tPCRPublicKey = SDStubDynamicInitrdPath + \"/\" + \"tpm2-pcr-public-key.pem\"\n\n\t// UKIPCR is the PCR number where systemd-stub measures the UKI.\n\tUKIPCR = 11\n\n\t// SecureBootStatePCR is the PCR number where the secure boot state and the signature are measured.\n\t// PCR 7 changes when UEFI SecureBoot mode is enabled/disabled, or firmware certificates (PK, KEK, db, dbx, …) are updated.\n\tSecureBootStatePCR = 7\n\n\t// DefaultCertificateValidityDuration is the default duration for a certificate.\n\tDefaultCertificateValidityDuration = x509.DefaultCertificateValidityDuration\n\n\t// SystemPath is the path to write temporary runtime system related files\n\t// and directories.\n\tSystemPath = \"/system\"\n\n\t// SystemSelinuxLabel is the SELinux label for runtime system related files and directories.\n\tSystemSelinuxLabel = \"system_u:object_r:system_t:s0\"\n\n\t// RunPath is the path to the system run directory.\n\tRunPath = \"/run\"\n\n\t// RunSelinuxLabel is the SELinux label for the run directory.\n\tRunSelinuxLabel = \"system_u:object_r:run_t:s0\"\n\n\t// VarSystemOverlaysPath is the path where overlay mounts are created.\n\tVarSystemOverlaysPath = \"/var/system/overlays\"\n\n\t// SystemRunPath is the path to the system run directory.\n\tSystemRunPath = SystemPath + \"/run\"\n\n\t// SystemVarPath is the path to the system var directory.\n\tSystemVarPath = SystemPath + \"/var\"\n\n\t// SystemVarSelinuxLabel is the SELinux label for the system var directory.\n\tSystemVarSelinuxLabel = \"system_u:object_r:system_var_t:s0\"\n\n\t// SystemEtcPath is the path to the system etc directory.\n\tSystemEtcPath = SystemPath + \"/etc\"\n\n\t// EtcSelinuxLabel is the SELinux label for the /etc and /system/etc directories.\n\tEtcSelinuxLabel = \"system_u:object_r:etc_t:s0\"\n\n\t// SystemLibexecPath is the path to the system libexec directory.\n\tSystemLibexecPath = SystemPath + \"/libexec\"\n\n\t// SystemOverlaysPath is the path to the system overlay directory.\n\tSystemOverlaysPath = SystemPath + \"/overlays\"\n\n\t// CgroupMountPath is the default mount path for unified cgroupsv2 setup.\n\tCgroupMountPath = \"/sys/fs/cgroup\"\n\n\t// CgroupInit is the cgroup name for init process.\n\tCgroupInit = \"/init\"\n\n\t// CgroupInitReservedMemory is the hard memory protection for the init process.\n\tCgroupInitReservedMemory = 96 * 1024 * 1024\n\n\t// CgroupInitMillicores is the CPU weight for the init process.\n\tCgroupInitMillicores = 2000\n\n\t// CgroupSystem is the cgroup name for system processes.\n\tCgroupSystem = \"/system\"\n\n\t// CgroupSystemMillicores is the CPU weight for the system cgroup.\n\tCgroupSystemMillicores = 1500\n\n\t// CgroupSystemReservedMemory is the hard memory protection for the system processes.\n\tCgroupSystemReservedMemory = 96 * 1024 * 1024\n\n\t// CgroupSystemRuntime is the cgroup name for containerd runtime processes.\n\tCgroupSystemRuntime = CgroupSystem + \"/runtime\"\n\n\t// CgroupSystemRuntimeReservedMemory is the hard memory protection for the system containerd process.\n\tCgroupSystemRuntimeReservedMemory = 48 * 1024 * 1024\n\n\t// CgroupSystemRuntimeMillicores is the CPU weight for the system containerd process.\n\tCgroupSystemRuntimeMillicores = 500\n\n\t// CgroupSystemDebug is the cgroup name for debug processes.\n\tCgroupSystemDebug = CgroupSystem + \"/debug\"\n\n\t// SelinuxLabelMachined is the SELinux label for machined.\n\tSelinuxLabelMachined = \"system_u:system_r:init_t:s0\"\n\n\t// SelinuxLabelInstaller is the SELinux label for the installer.\n\tSelinuxLabelInstaller = \"system_u:system_r:installer_t:s0\"\n\n\t// SelinuxLabelUnconfinedSysContainer is the SELinux label for system containers without label set (normally extensions).\n\tSelinuxLabelUnconfinedSysContainer = \"system_u:system_r:unconfined_container_t:s0\"\n\n\t// SelinuxLabelUnconfinedService is the SELinux label for process without label set (normally should not occur).\n\tSelinuxLabelUnconfinedService = \"system_u:system_r:unconfined_service_t:s0\"\n\n\t// SelinuxLabelSystemRuntime is the SELinux label for containerd runtime processes.\n\tSelinuxLabelSystemRuntime = \"system_u:system_r:sys_containerd_t:s0\"\n\n\t// CgroupApid is the cgroup name for apid runtime processes.\n\tCgroupApid = CgroupSystem + \"/apid\"\n\n\t// CgroupApidReservedMemory is the hard memory protection for the apid processes.\n\tCgroupApidReservedMemory = 16 * 1024 * 1024\n\n\t// CgroupApidMaxMemory is the hard memory limit for the apid process.\n\tCgroupApidMaxMemory = 128 * 1024 * 1024\n\n\t// CgroupApidMillicores is the CPU weight for the apid process.\n\tCgroupApidMillicores = 500\n\n\t// SelinuxLabelApid is the SELinux label for apid runtime processes.\n\tSelinuxLabelApid = \"system_u:system_r:apid_t:s0\"\n\n\t// CgroupTrustd is the cgroup name for trustd runtime processes.\n\tCgroupTrustd = CgroupSystem + \"/trustd\"\n\n\t// CgroupTrustdReservedMemory is the hard memory protection for the trustd processes.\n\tCgroupTrustdReservedMemory = 8 * 1024 * 1024\n\n\t// CgroupTrustdMaxMemory is the hard memory limit for the trustd process.\n\tCgroupTrustdMaxMemory = 128 * 1024 * 1024\n\n\t// CgroupTrustdMillicores is the CPU weight for the trustd process.\n\tCgroupTrustdMillicores = 250\n\n\t// SelinuxLabelTrustd is the SELinux label for trustd runtime processes.\n\tSelinuxLabelTrustd = \"system_u:system_r:trustd_t:s0\"\n\n\t// CgroupUdevd is the cgroup name for udevd runtime processes.\n\tCgroupUdevd = CgroupSystem + \"/udevd\"\n\n\t// CgroupUdevdReservedMemory is the hard memory protection for the udevd processes.\n\tCgroupUdevdReservedMemory = 8 * 1024 * 1024\n\n\t// CgroupUdevdMillicores is the CPU weight for the udevd process.\n\tCgroupUdevdMillicores = 250\n\n\t// SelinuxLabelUdevd is the SELinux label for udevd runtime processes.\n\tSelinuxLabelUdevd = \"system_u:system_r:udev_t:s0\"\n\n\t// CgroupExtensions is the cgroup name for system extension processes.\n\tCgroupExtensions = CgroupSystem + \"/extensions\"\n\n\t// CgroupDashboard is the cgroup name for dashboard process.\n\tCgroupDashboard = CgroupSystem + \"/dashboard\"\n\n\t// SelinuxLabelDashboard is the SELinux label for dashboard process.\n\tSelinuxLabelDashboard = \"system_u:system_r:dashboard_t:s0\"\n\n\t// CgroupPodRuntimeRoot is the cgroup containing Kubernetes runtime components.\n\tCgroupPodRuntimeRoot = \"/podruntime\"\n\n\t// CgroupPodRuntimeRootMillicores is the CPU weight for the pod runtime cgroup.\n\tCgroupPodRuntimeRootMillicores = 4000\n\n\t// CgroupPodRuntime is the cgroup name for kubernetes containerd runtime processes.\n\tCgroupPodRuntime = CgroupPodRuntimeRoot + \"/runtime\"\n\n\t// CgroupPodRuntimeMillicores is the CPU weight for the pod runtime cgroup.\n\tCgroupPodRuntimeMillicores = 1000\n\n\t// SelinuxLabelPodRuntime is the SELinux label for kubernetes containerd runtime processes.\n\tSelinuxLabelPodRuntime = \"system_u:system_r:pod_containerd_t:s0\"\n\n\t// CgroupPodRuntimeReservedMemory is the hard memory protection for the cri runtime processes.\n\tCgroupPodRuntimeReservedMemory = 196 * 1024 * 1024\n\n\t// CgroupEtcd is the cgroup name for etcd process.\n\tCgroupEtcd = CgroupPodRuntimeRoot + \"/etcd\"\n\n\t// CgroupEtcdReservedMemory is the soft memory protection for the etcd processes.\n\tCgroupEtcdReservedMemory = 256 * 1024 * 1024\n\n\t// CgroupEtcdMillicores is the CPU weight for the etcd process.\n\tCgroupEtcdMillicores = 2000\n\n\t// SELinuxLabelEtcd is the SELinux label for etcd process.\n\tSELinuxLabelEtcd = \"system_u:system_r:etcd_t:s0\"\n\n\t// CgroupKubelet is the cgroup name for kubelet process.\n\tCgroupKubelet = CgroupPodRuntimeRoot + \"/kubelet\"\n\n\t// SelinuxLabelKubelet is the SELinux label for kubelet process.\n\tSelinuxLabelKubelet = \"system_u:system_r:kubelet_t:s0\"\n\n\t// CgroupKubeletReservedMemory is the hard memory protection for the kubelet processes.\n\tCgroupKubeletReservedMemory = 96 * 1024 * 1024\n\n\t// CgroupKubeletMillicores is the CPU weight for the kubelet process.\n\tCgroupKubeletMillicores = 1000\n\n\t// CgroupDashboardMaxMemory is the hard memory limit for the dashboard process.\n\tCgroupDashboardMaxMemory = 196 * 1024 * 1024\n\n\t// CgroupDashboardMillicores is the CPU weight for the dashboard process.\n\tCgroupDashboardMillicores = 200\n\n\t// FlannelCNI is the string to use Tanos-managed Flannel CNI (default).\n\tFlannelCNI = \"flannel\"\n\n\t// CustomCNI is the string to use custom CNI managed by Tanos with extra manifests.\n\tCustomCNI = \"custom\"\n\n\t// NoneCNI is the string to indicate that CNI will not be managed by Talos.\n\tNoneCNI = \"none\"\n\n\t// CNISELinuxLabel is the SELinux label to be set for CNI configuration overlay mount.\n\tCNISELinuxLabel = \"system_u:object_r:cni_conf_t:s0\"\n\n\t// DefaultIPv4PodNet is the IPv4 network to be used for kubernetes Pods.\n\tDefaultIPv4PodNet = \"10.244.0.0/16\"\n\n\t// DefaultIPv4ServiceNet is the IPv4 network to be used for kubernetes Services.\n\tDefaultIPv4ServiceNet = \"10.96.0.0/12\"\n\n\t// DefaultIPv6PodNet is the IPv6 network to be used for kubernetes Pods.\n\tDefaultIPv6PodNet = \"fc00:db8:10::/56\"\n\n\t// DefaultIPv6ServiceNet is the IPv6 network to be used for kubernetes Services.\n\tDefaultIPv6ServiceNet = \"fc00:db8:20::/112\"\n\n\t// DefaultDNSDomain is the default DNS domain.\n\tDefaultDNSDomain = \"cluster.local\"\n\n\t// ConfigLoadTimeout is the timeout to wait for the config to be loaded from an external source.\n\tConfigLoadTimeout = 3 * time.Hour\n\n\t// ConfigLoadAttemptTimeout is the timeout for a single attempt to download config.\n\tConfigLoadAttemptTimeout = 3 * time.Minute\n\n\t// BootTimeout is the timeout to run all services.\n\tBootTimeout = 70 * time.Minute\n\n\t// FailurePauseTimeout is the timeout for the sequencer failures which can be fixed by updating the machine config.\n\tFailurePauseTimeout = 35 * time.Minute\n\n\t// EtcdJoinTimeout is the timeout for etcd to join the existing cluster.\n\t//\n\t// BootTimeout should be higher than EtcdJoinTimeout.\n\tEtcdJoinTimeout = 30 * time.Minute\n\n\t// NodeReadyTimeout is the timeout to wait for the node to be ready (CNI to be running).\n\t// For bootstrap API, this includes time to run bootstrap.\n\tNodeReadyTimeout = BootTimeout\n\n\t// AnnotationCordonedKey is the annotation key for the nodes cordoned by Talos.\n\tAnnotationCordonedKey = \"talos.dev/cordoned\"\n\n\t// AnnotationCordonedValue is the annotation key for the nodes cordoned by Talos.\n\tAnnotationCordonedValue = \"true\"\n\n\t// AnnotationStaticPodSecretsVersion is the annotation key for the static pod secret version.\n\tAnnotationStaticPodSecretsVersion = \"talos.dev/secrets-version\"\n\n\t// AnnotationStaticPodConfigVersion is the annotation key for the static pod config version.\n\tAnnotationStaticPodConfigVersion = \"talos.dev/config-version\"\n\n\t// AnnotationStaticPodConfigFileVersion is the annotation key for the static pod configuration file version.\n\tAnnotationStaticPodConfigFileVersion = \"talos.dev/config-file-version\"\n\n\t// AnnotationOwnedLabels is the annotation key for the list of node labels owned by Talos.\n\tAnnotationOwnedLabels = \"talos.dev/owned-labels\"\n\n\t// AnnotationOwnedAnnotations is the annotation key for the list of node annotations owned by Talos.\n\tAnnotationOwnedAnnotations = \"talos.dev/owned-annotations\"\n\n\t// AnnotationOwnedTaints is the annotation key for the list of node taints owned by Talos.\n\tAnnotationOwnedTaints = \"talos.dev/owned-taints\"\n\n\t// K8sExtensionPrefix is the prefix for node labels/annotations listing extensions.\n\tK8sExtensionPrefix = \"extensions.talos.dev/\"\n\n\t// DefaultNTPServer is the NTP server to use if not configured explicitly.\n\tDefaultNTPServer = \"time.cloudflare.com\"\n\n\t// DefaultPrimaryResolver is the default primary DNS server.\n\tDefaultPrimaryResolver = \"1.1.1.1\"\n\n\t// DefaultSecondaryResolver is the default secondary DNS server.\n\tDefaultSecondaryResolver = \"8.8.8.8\"\n\n\t// DefaultClusterIDSize is the default size in bytes for the cluster ID token.\n\tDefaultClusterIDSize = 32\n\n\t// DefaultClusterSecretSize is the default size in bytes for the cluster secret.\n\tDefaultClusterSecretSize = 32\n\n\t// DefaultNodeIdentitySize is the default size in bytes for the node ID.\n\tDefaultNodeIdentitySize = 32\n\n\t// NodeIdentityFilename is the filename to cache node identity across reboots.\n\tNodeIdentityFilename = \"node-identity.yaml\"\n\n\t// DefaultDiscoveryServiceEndpoint is the default endpoint for Talos discovery service.\n\tDefaultDiscoveryServiceEndpoint = \"https://discovery.talos.dev/\"\n\n\t// KubeSpanIdentityFilename is the filename to cache KubeSpan identity across reboots.\n\tKubeSpanIdentityFilename = \"kubespan-identity.yaml\"\n\n\t// KubeSpanDefaultPort is the default Wireguard listening port for incoming connections.\n\tKubeSpanDefaultPort = 51820\n\n\t// KubeSpanDefaultRoutingTable is the default routing table for KubeSpan LAN targets.\n\t//\n\t// This specifies the routing table which will be used for Wireguard-available destinations.\n\tKubeSpanDefaultRoutingTable = 180\n\n\t// KubeSpanDefaultFirewallMark is the default firewall mark to use for Wireguard encrypted egress packets.\n\t//\n\t// Normal Wireguard configurations will NOT use this firewall mark.\n\tKubeSpanDefaultFirewallMark = 0x20\n\n\t// KubeSpanDefaultForceFirewallMark is the default firewall mark to use for packets destined to IPs serviced by KubeSpan.\n\t//\n\t// It is used to signal that matching packets should be forced into the Wireguard interface.\n\tKubeSpanDefaultForceFirewallMark = 0x40\n\n\t// KubeSpanDefaultFirewallMask is the mask applied to the packet mark when matching and setting the mark.\n\t//\n\t// This mask signals the bits of the firewall mark used by KubeSpan.\n\tKubeSpanDefaultFirewallMask = KubeSpanDefaultFirewallMark | KubeSpanDefaultForceFirewallMark\n\n\t// KubeSpanDefaultPeerKeepalive is the interval at which Wireguard Peer Keepalives should be sent.\n\tKubeSpanDefaultPeerKeepalive = 25 * time.Second\n\n\t// KubeSpanDefaultRulePriority is the default priority for KubeSpan IPv4 routing rules.\n\tKubeSpanDefaultRulePriority = 32500\n\n\t// LinuxReservedRulePriorityLocal is the priority for the local table lookup (ip rule show shows \"from all lookup local\").\n\t// This priority is reserved by the Linux kernel and should not be used by user-defined rules.\n\tLinuxReservedRulePriorityLocal = 0\n\n\t// LinuxReservedRulePriorityMain is the priority for the main table lookup (ip rule show shows \"from all lookup main\").\n\t// This priority is reserved by the Linux kernel and should not be used by user-defined rules.\n\tLinuxReservedRulePriorityMain = 32766\n\n\t// LinuxReservedRulePriorityDefault is the priority for the default table lookup (ip rule show shows \"from all lookup default\").\n\t// This priority is reserved by the Linux kernel and should not be used by user-defined rules.\n\tLinuxReservedRulePriorityDefault = 32767\n\n\t// NetworkSelfIPsAnnotation is the node annotation used to list the (comma-separated) IP addresses of the host, as discovered by Talos tooling.\n\tNetworkSelfIPsAnnotation = \"networking.talos.dev/self-ips\"\n\n\t// NetworkAPIServerPortAnnotation is the node annotation used to report the control plane API server port.\n\tNetworkAPIServerPortAnnotation = \"networking.talos.dev/api-server-port\"\n\n\t// ClusterNodeIDAnnotation is the node annotation used to represent node ID.\n\tClusterNodeIDAnnotation = \"cluster.talos.dev/node-id\"\n\n\t// KubeSpanIPAnnotation is the node annotation to be used for indicating the Wireguard IP of the node.\n\tKubeSpanIPAnnotation = \"networking.talos.dev/kubespan-ip\"\n\n\t// KubeSpanPublicKeyAnnotation is the node annotation to be used for indicating the Wireguard Public Key of the node.\n\tKubeSpanPublicKeyAnnotation = \"networking.talos.dev/kubespan-public-key\"\n\n\t// KubeSpanAssignedPrefixesAnnotation is the node annotation use to list the (comma-separated) set of IP prefixes for which the annotated node should be responsible.\n\tKubeSpanAssignedPrefixesAnnotation = \"networking.talos.dev/assigned-prefixes\"\n\n\t// KubeSpanKnownEndpointsAnnotation is the node annotation used to list the (comma-separated) known-good Wireguard endpoints for the node, as seen by other peers.\n\tKubeSpanKnownEndpointsAnnotation = \"networking.talos.dev/kubespan-endpoints\"\n\n\t// KubeSpanExcludeAdvertisedNetworksAnnotation is the node annotation used to list the (comma-separated) set of subnets to be excluded from advertisement.\n\tKubeSpanExcludeAdvertisedNetworksAnnotation = \"networking.talos.dev/kubespan-exclude-advertised-networks\"\n\n\t// KubeSpanLinkName is the link name for the KubeSpan Wireguard interface.\n\tKubeSpanLinkName = \"kubespan\"\n\n\t// KubeSpanLinkMTU is the default link MTU size for the KubeSpan Wireguard interface.\n\tKubeSpanLinkMTU = 1420\n\n\t// KubeSpanLinkMinimumMTU is the minimum link MTU size for the KubeSpan Wireguard interface.\n\t//\n\t// This is the minimum MTU size for the Wireguard interface with IPv6 enabled.\n\t// See: https://lore.kernel.org/wireguard/20190321033638.1ff82682@natsu/t/\n\tKubeSpanLinkMinimumMTU = 1280\n\n\t// UdevDir is the path to the udev directory.\n\tUdevDir = \"/usr/lib/udev\"\n\n\t// UdevRulesPath rules file path.\n\tUdevRulesPath = UdevDir + \"/\" + \"rules.d/99-talos.rules\"\n\n\t// UdevRulesLabel rules file SELinux label.\n\tUdevRulesLabel = \"system_u:object_r:udev_rules_t:s0\"\n\n\t// LoggingFormatJSONLines represents \"JSON lines\" logging format.\n\tLoggingFormatJSONLines = \"json_lines\"\n\n\t// SideroLinkName is the interface name for SideroLink.\n\tSideroLinkName = \"siderolink\"\n\n\t// SideroLinkTunnelName is the tunnel name for SideroLink in tunnel (Wireguard-over-GRPC) mode.\n\tSideroLinkTunnelName = \"siderolinktun\"\n\n\t// SideroLinkDefaultPeerKeepalive is the interval at which Wireguard Peer Keepalives should be sent.\n\tSideroLinkDefaultPeerKeepalive = 25 * time.Second\n\n\t// PlatformNetworkConfigFilename is the filename to cache platform network configuration reboots.\n\tPlatformNetworkConfigFilename = \"platform-network.yaml\"\n\n\t// ExtensionServiceConfigPath is the directory path which contains  configuration files of extension services.\n\t//\n\t// See pkg/machinery/extensions/services for the file format.\n\tExtensionServiceConfigPath = \"/usr/local/etc/containers\"\n\n\t// ExtensionServiceRootfsPath is the path to the extracted rootfs files of extension services.\n\tExtensionServiceRootfsPath = \"/usr/local/lib/containers\"\n\n\t// ExtensionServiceUserConfigPath is the path to the user provided extension services config directory.\n\tExtensionServiceUserConfigPath = SystemOverlaysPath + \"/extensions\"\n\n\t// DBusServiceSocketPath is the path to the D-Bus socket for the logind mock to connect to.\n\tDBusServiceSocketPath = SystemRunPath + \"/dbus/service.socket\"\n\n\t// DBusServiceSocketLabel is the SELinux label for the D-Bus socket for the logind mock to connect to.\n\tDBusServiceSocketLabel = \"system_u:object_r:dbus_service_socket_t:s0\"\n\n\t// DBusClientSocketPath is the path to the D-Bus socket for the kubelet to connect to.\n\tDBusClientSocketPath = \"/run/dbus/system_bus_socket\"\n\n\t// DBusClientSocketLabel is the SELinux label for the D-Bus socket for the kubelet to connect to.\n\tDBusClientSocketLabel = \"system_u:object_r:dbus_client_socket_t:s0\"\n\n\t// GoVersion is the version of Go compiler this release was built with.\n\tGoVersion = \"go1.26.1\"\n\n\t// KubernetesTalosAPIServiceName is the name of the Kubernetes service to access Talos API.\n\tKubernetesTalosAPIServiceName = \"talos\"\n\n\t// KubernetesTalosAPIServiceNamespace is the namespace of the Kubernetes service to access Talos API.\n\tKubernetesTalosAPIServiceNamespace = \"default\"\n\n\t// TalosDir is the default name of the Talos directory under user home.\n\tTalosDir = \".talos\"\n\n\t// TalosconfigFilename is the file name of Talosconfig under TalosDir or under ServiceAccountMountPath inside a pod.\n\tTalosconfigFilename = \"config\"\n\n\t// KubernetesTalosProvider is the name of the Talos provider as a Kubernetes label.\n\tKubernetesTalosProvider = \"talos.dev\"\n\n\t// KubernetesInventoryNamespace is the namespace where Talos inventory objects are stored.\n\tKubernetesInventoryNamespace = \"kube-system\"\n\n\t// KubernetesBootstrapManifestsInventoryName is the name of the Talos bootstrap manifests inventory object.\n\tKubernetesBootstrapManifestsInventoryName = \"talos-bootstrap-manifests-inventory\"\n\n\t// KubernetesFieldManagerName is the field manager name used by Talos when applying manifests.\n\tKubernetesFieldManagerName = \"talos\"\n\n\t// ServiceAccountResourceGroup is the group name of the Talos service account CRD.\n\tServiceAccountResourceGroup = \"talos.dev\"\n\n\t// ServiceAccountResourceVersion is the version of the Talos service account CRD.\n\tServiceAccountResourceVersion = \"v1alpha1\"\n\n\t// ServiceAccountResourceKind is the kind name of the Talos service account CRD.\n\tServiceAccountResourceKind = \"ServiceAccount\"\n\n\t// ServiceAccountResourceSingular is the singular name of the Talos service account CRD.\n\tServiceAccountResourceSingular = \"serviceaccount\"\n\n\t// ServiceAccountResourceShortName is the short name of the service account CRD.\n\tServiceAccountResourceShortName = \"tsa\"\n\n\t// ServiceAccountResourcePlural is the plural name of the service account CRD.\n\tServiceAccountResourcePlural = ServiceAccountResourceSingular + \"s\"\n\n\t// ServiceAccountMountPath is the path of the directory in which the Talos service account secrets are mounted.\n\tServiceAccountMountPath = \"/var/run/secrets/talos.dev\"\n\n\t// DefaultTrustedRelativeCAFile is the default path to the trusted CA file relative to the /etc.\n\tDefaultTrustedRelativeCAFile = \"ssl/certs/ca-certificates.crt\"\n\n\t// DefaultTrustedCAFile is the default path to the trusted CA file.\n\tDefaultTrustedCAFile = \"/etc/\" + DefaultTrustedRelativeCAFile\n\n\t// MachinedMaxProcs is the maximum number of GOMAXPROCS for machined.\n\tMachinedMaxProcs = 4\n\n\t// ApidMaxProcs is the maximum number of GOMAXPROCS for apid.\n\tApidMaxProcs = 2\n\n\t// TrustdMaxProcs is the maximum number of GOMAXPROCS for trustd.\n\tTrustdMaxProcs = 2\n\n\t// DashboardMaxProcs is the maximum number of GOMAXPROCS for dashboard.\n\tDashboardMaxProcs = 2\n\n\t// APIAuthzRoleMetadataKey is the gRPC metadata key used to submit a role with os:impersonator.\n\tAPIAuthzRoleMetadataKey = \"talos-role\"\n\n\t// KernelLogsTTY is the number of the TTY device (/dev/ttyN) to redirect Kernel logs to.\n\tKernelLogsTTY = 1\n\n\t// DashboardTTY is the number of the TTY device (/dev/ttyN) for dashboard.\n\tDashboardTTY = 2\n\n\t// FlannelVersion is the version of flannel to use.\n\t//\n\t// Note: while updating, make sure to copy flannel image from docker.io to ghcr.io:\n\t//   crane cp docker.io/flannel/flannel:vX.Y.Z ghcr.io/siderolabs/flannel:vX.Y.Z\n\t// And sign the image using image-signer.\n\t//\n\t// renovate: datasource=github-releases depName=flannel-io/flannel\n\tFlannelVersion = \"v0.28.1\"\n\n\t// KubeNetworkPoliciesVersion is the version of kube-network-policies when network policies are enabled for flannel.\n\t//\n\t// renovate: datasource=docker depName=registry.k8s.io/networking/kube-network-policies\n\tKubeNetworkPoliciesVersion = \"v1.0.0\"\n\n\t// PlatformMetal is the name of the metal platform.\n\tPlatformMetal = \"metal\"\n\n\t// MetaValuesEnvVar is the name of the environment variable to store encoded meta values for the disk image (installer).\n\tMetaValuesEnvVar = \"INSTALLER_META_BASE64\"\n\n\t// MaintenanceServiceCommonName is the CN of the maintenance service server certificate.\n\tMaintenanceServiceCommonName = \"maintenance-service.talos.dev\"\n\n\t// GRPCMaxMessageSize is the maximum message size for Talos API.\n\tGRPCMaxMessageSize = 32 * 1024 * 1024\n\n\t// DefaultKubePrismPort is the default port for the KubePrism loadbalancer.\n\tDefaultKubePrismPort = 7445\n\n\t// KubePrismDialTimeout is the timeout for the KubePrism loadbalancer dialing an endpoint.\n\tKubePrismDialTimeout = 15 * time.Second\n\n\t// KubePrismKeepAlivePeriod is the TCP keepalive period for the KubePrism loadbalancer.\n\tKubePrismKeepAlivePeriod = 30 * time.Second\n\n\t// KubePrismTCPUserTimeout is the TCP user timeout for the KubePrism loadbalancer.\n\tKubePrismTCPUserTimeout = 30 * time.Second\n\n\t// KubePrismHealthCheckInterval is the interval between health checks for the KubePrism loadbalancer.\n\tKubePrismHealthCheckInterval = 20 * time.Second\n\n\t// KubePrismHealthCheckTimeout is the timeout for health checks for the KubePrism loadbalancer.\n\tKubePrismHealthCheckTimeout = 15 * time.Second\n\n\t// TalosAPIDefaultCertificateValidityDuration specifies default certificate duration for Talos API generated client certificates.\n\tTalosAPIDefaultCertificateValidityDuration = time.Hour * 24 * 365\n\n\t// DefaultNfTablesTableName is the default name of the nftables table created by Talos.\n\tDefaultNfTablesTableName = \"talos\"\n\n\t// SystemResolvedPath is the path to the resolved dir.\n\tSystemResolvedPath = SystemPath + \"/resolved\"\n\n\t// PodResolvConfPath is the path to the pod resolv.conf file.\n\tPodResolvConfPath = SystemResolvedPath + \"/resolv.conf\"\n\n\t// SyslogListenSocketPath is the path to the syslog socket.\n\tSyslogListenSocketPath = \"/dev/log\"\n\n\t// ConsoleLogErrorSuppressThreshold is the threshold for suppressing console log errors.\n\tConsoleLogErrorSuppressThreshold = 4\n\n\t// HostDNSAddress is the address of the host DNS server.\n\t//\n\t// Note: 116 = 't' and 108 = 'l' in ASCII.\n\tHostDNSAddress = \"169.254.116.108\"\n\n\t// MetalAgentModeFlagPath is the path to the file indicating if the node is running in Metal Agent mode.\n\tMetalAgentModeFlagPath = \"/usr/local/etc/is-metal-agent\"\n\n\t// ImageCachePartitionLabel is the label for the image cache partition.\n\tImageCachePartitionLabel = \"IMAGECACHE\"\n\n\t// ImageCacheISOMountPoint is the mount point for the image cache ISO.\n\tImageCacheISOMountPoint = \"/system/imagecache/iso\"\n\n\t// ImageCacheDiskMountPoint is the mount point for the image cache partition.\n\tImageCacheDiskMountPoint = \"/system/imagecache/disk\"\n\n\t// RegistrydListenAddress is the address to listen on for the registryd service.\n\tRegistrydListenAddress = \"127.0.0.1:3172\"\n\n\t// KubernetesInformerDefaultResyncPeriod is the default resync period for Kubernetes informers.\n\tKubernetesInformerDefaultResyncPeriod = 30 * time.Second\n\n\t// UserVolumeMountPoint is the path to the volume mount point for the user volumes.\n\tUserVolumeMountPoint = \"/var/mnt\"\n\n\t// LogMountPoint is the path to the logs mount point, and ID of the logs volume.\n\tLogMountPoint = \"/var/log\"\n\n\t// UserVolumePrefix is the prefix for the user volumes.\n\tUserVolumePrefix = \"u-\"\n\n\t// ExternalVolumePrefix is the prefix for the user volumes.\n\tExternalVolumePrefix = \"x-\"\n\n\t// RawVolumePrefix is the prefix for the raw volumes.\n\tRawVolumePrefix = \"r-\"\n\n\t// ExistingVolumePrefix is the prefix for the existing volumes.\n\tExistingVolumePrefix = \"e-\"\n\n\t// SwapVolumePrefix is the prefix for the swap volumes.\n\tSwapVolumePrefix = \"s-\"\n\n\t// PartitionLabelLength is the length of the partition label.\n\t//\n\t// See https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_entries_(LBA_2%E2%80%9333)\n\tPartitionLabelLength = 36\n\n\t// SPDXPath is the path to the SBOM file(s).\n\tSPDXPath = \"/usr/share/spdx\"\n\n\t// ExtensionSPDXPath is the path to the SBOM file(s) provided by system extensions.\n\tExtensionSPDXPath = \"/usr/local/share/spdx\"\n\n\t// EncryptionSaltFilename is the filename for the encryption salt file.\n\tEncryptionSaltFilename = \"encryption-salt.yaml\"\n\n\t// DiskEncryptionSaltSize is the size of the disk encryption salt in bytes.\n\tDiskEncryptionSaltSize = 32\n\n\t// SideroV1KeysDirEnvVar is the environment variable that points to the directory containing user PGP keys for SideroV1 auth.\n\tSideroV1KeysDirEnvVar = \"SIDEROV1_KEYS_DIR\"\n\n\t// SideroV1KeysDir is the default directory containing user PGP keys for SideroV1 auth.\n\tSideroV1KeysDir = \"keys\"\n\n\t// ContainerMarkerFilePath is the path to the file added to container builds of Talos for platform detection.\n\tContainerMarkerFilePath = \"/usr/etc/in-container\"\n\n\t// DefaultOOMTriggerExpression is the default CEL expression used to determine whether to trigger OOM.\n\tDefaultOOMTriggerExpression = `(multiply_qos_vectors(d_qos_memory_full_total, {System: 8.0, Podruntime: 4.0}) > 3000.0 &&\n\t     multiply_qos_vectors(qos_memory_full_avg10, {System: 1.0, Podruntime: 1.0}) > 5.0) ||\n\t\t(memory_full_avg10 > 75.0 && time_since_trigger > duration(\"10s\"))`\n\n\t// DefaultOOMCgroupRankingExpression is the default CEL expression used to rank cgroups for OOM killer.\n\tDefaultOOMCgroupRankingExpression = `memory_max.hasValue() ? 0.0 :\n\t\t{Besteffort: 1.0, Burstable: 0.5, Guaranteed: 0.0, Podruntime: 0.0, System: 0.0}[class] *\n\t\t   double(memory_current.orValue(0u))`\n\n\t// OOMActionLogKeep is the number of OOM action log entries to keep in memory.\n\tOOMActionLogKeep = 50\n\n\t// SDStubCmdlineExtraOEMVar is the name of the SMBIOS OEM variable that can be used to pass extra kernel command line parameters to systemd-stub.\n\tSDStubCmdlineExtraOEMVar = \"io.systemd.stub.kernel-cmdline-extra\"\n\n\t// LogRotateThreshold is the size (in bytes), upon exceeding which the log file should be rotated.\n\tLogRotateThreshold = 5 * 1024 * 1024\n\n\t// LogFlushPeriod is the period for flushing in-memory log buffers to the filesystem.\n\tLogFlushPeriod = 15 * time.Second\n\n\t// ImageLabelVerified is the label key for the verified image label.\n\tImageLabelVerified = \"talos.dev/verified\"\n)\n\n// names of variable that can be substituted in the talos.config kernel parameter.\nconst (\n\tUUIDKey         = \"uuid\"\n\tSerialNumberKey = \"serial\"\n\tHostnameKey     = \"hostname\"\n\tMacKey          = \"mac\"\n\tCodeKey         = \"code\"\n)\n\n// SELinuxLabeledPath is an object used to describe overlay mounts with SELinux labels applied on creation.\ntype SELinuxLabeledPath struct {\n\tPath  string\n\tLabel string\n}\n\n// Overlays is the set of paths to create overlay mounts for.\nvar Overlays = []SELinuxLabeledPath{\n\t{\"/etc/cni\", CNISELinuxLabel},\n\t{KubernetesConfigBaseDir, KubernetesConfigSELinuxLabel},\n\t{\"/usr/libexec/kubernetes\", KubeletPluginsSELinuxLabel},\n\t{\"/opt\", OptSELinuxLabel},\n}\n\n// DefaultDroppedCapabilities is the default set of capabilities to drop.\nvar DefaultDroppedCapabilities = map[string]struct{}{\n\t\"cap_sys_boot\":   {},\n\t\"cap_sys_module\": {},\n}\n\n// UdevdDroppedCapabilities is the set of capabilities to drop for udevd.\nvar UdevdDroppedCapabilities = map[string]struct{}{\n\t\"cap_sys_boot\": {},\n}\n\n// ValidEffects is the set of valid taint effects.\nvar ValidEffects = []string{\n\t\"NoSchedule\",\n\t\"PreferNoSchedule\",\n\t\"NoExecute\",\n}\n\n// OSReleaseTemplate is the template for /etc/os-release.\nconst OSReleaseTemplate = `NAME=\"%[1]s\"\nID=%[2]s\nVERSION_ID=%[3]s\nPRETTY_NAME=\"%[1]s (%[3]s)\"\nHOME_URL=\"https://www.talos.dev/\"\nBUG_REPORT_URL=\"https://github.com/siderolabs/talos/issues\"\nVENDOR_NAME=\"Sidero Labs\"\nVENDOR_URL=\"https://www.siderolabs.com/\"\n`\n"
  },
  {
    "path": "pkg/machinery/constants/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage constants\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/containerd/go-cni\"\n)\n\nconst (\n\t// PATH defines all locations where executables are stored.\n\tPATH = \"/usr/bin:/usr/local/sbin:/usr/local/bin:\" + cni.DefaultCNIDir\n\n\t// EnvPath is the environment variable to set PATH.\n\tEnvPath = \"PATH=\" + PATH\n\n\t// EnvPathWithBin is the environment variable to set PATH with /bin prepended.\n\tEnvPathWithBin = \"PATH=/bin:\" + PATH\n\n\t// EnvTcellMinimizeEnvironment is the environment variable to minimize tcell library memory usage (skips rune width calculation).\n\tEnvTcellMinimizeEnvironment = \"TCELL_MINIMIZE=1\"\n\n\t// EnvGRPCEnforccceALPNEnabled is the environment variable to disable gRPC ALPN enforcement.\n\tEnvGRPCEnforccceALPNEnabled = \"GRPC_ENFORCE_ALPN_ENABLED=false\"\n\n\t// EnvTerm is the environment variable to set terminal type.\n\tEnvTerm = \"TERM=linux\"\n\n\t// EnvGoraceHaltOnError is the environment variable to set GORACE to halt on error.\n\tEnvGoraceHaltOnError = \"GORACE=halt_on_error=1\"\n\n\t// EnvFIPS140ModeStrict is the environment variable to set Go crypto to FIPS 140 strict mode.\n\tEnvFIPS140ModeStrict = \"GODEBUG=fips140=only\"\n\n\t// EnvXDGRuntimeDir is a default value for XDG_RUNTIME_DIR for the services running on the host.\n\t//\n\t// See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\n\tEnvXDGRuntimeDir = \"XDG_RUNTIME_DIR=/run\"\n)\n\n// EnvApidGomemlimit is the environment variable to set GOMEMLIMIT for apid process.\nfunc EnvApidGomemlimit() string {\n\treturn \"GOMEMLIMIT=\" + strconv.Itoa(CgroupApidMaxMemory/5*4)\n}\n\n// EnvDashboardGomemlimit is the environment variable to set GOMEMLIMIT for dashboard process.\nfunc EnvDashboardGomemlimit() string {\n\treturn \"GOMEMLIMIT=\" + strconv.Itoa(CgroupDashboardMaxMemory/5*4)\n}\n\n// EnvTrustdGomemlimit is the environment variable to set GOMEMLIMIT for trustd process.\nfunc EnvTrustdGomemlimit() string {\n\treturn \"GOMEMLIMIT=\" + strconv.Itoa(CgroupTrustdMaxMemory/5*4)\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"os\"\n\n\t\"go.yaml.in/yaml/v4\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type Layer -header-file ../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// Config specifies Talos installer extensions configuration.\ntype Config struct {\n\tLayers []*Layer `yaml:\"layers\"`\n}\n\n// Layer defines overlay mount layer.\n//\n//gotagsrewrite:gen\ntype Layer struct {\n\tImage    string   `yaml:\"image\" protobuf:\"1\"`\n\tMetadata Metadata `yaml:\"metadata\" protobuf:\"2\"`\n}\n\n// Read extensions config from a file.\nfunc (cfg *Config) Read(path string) error {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\treturn yaml.NewDecoder(f).Decode(cfg)\n}\n\n// Write extensions config to a file.\nfunc (cfg *Config) Write(path string) error {\n\tf, err := os.Create(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\treturn yaml.NewEncoder(f).Encode(cfg)\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type Layer -header-file ../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage extensions\n\n// DeepCopy generates a deep copy of Layer.\nfunc (o Layer) DeepCopy() Layer {\n\tvar cp Layer = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/extensions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package extensions contains Talos extensions specific API.\npackage extensions\n\nimport \"path/filepath\"\n\n// AllowedPaths lists paths allowed in the extension images.\nvar AllowedPaths = []string{\n\t\"/etc/cri/conf.d\",\n\t\"/usr/lib/firmware\",\n\t\"/usr/lib/modules\",\n\t// The glibc loader is required by glibc dynamic binaries.\n\t// It will be accessible via /lib64/ld-linux-x86-64.so.2 on x86_64\n\t// and /lib/ld-linux-aarch64.so.1 on aarch64.\n\t\"/usr/lib/ld-linux-x86-64.so.2\",\n\t\"/usr/lib/ld-linux-aarch64.so.1\",\n\t// /sbin/ldconfig is required by the nvidia container toolkit.\n\t\"/usr/bin/ldconfig\",\n\t\"/usr/lib/udev/rules.d\",\n\t\"/usr/local\",\n\t// glvnd, egl and vulkan are needed for OpenGL/Vulkan.\n\t\"/usr/share/glvnd\",\n\t\"/usr/share/egl\",\n\t\"/etc/vulkan\",\n}\n\n// Extension represents unpacked extension in the filesystem.\ntype Extension struct {\n\tManifest Manifest\n\n\tdirectory  string\n\trootfsPath string\n}\n\n// RootfsPath returns the path to the rootfs directory.\nfunc (ext *Extension) RootfsPath() string {\n\treturn ext.rootfsPath\n}\n\n// Directory returns the directory name of the extension.\nfunc (ext *Extension) Directory() string {\n\treturn ext.directory\n}\n\n// New creates a new extension from the rootfs path, directory name and manifest.\nfunc New(rootfsPath, directory string, manifest Manifest) *Extension {\n\textension := &Extension{\n\t\tManifest: manifest,\n\n\t\trootfsPath: rootfsPath,\n\t\tdirectory:  directory,\n\t}\n\n\tif extension.directory == \"\" {\n\t\textension.directory = filepath.Base(rootfsPath)\n\t}\n\n\treturn extension\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/extensions_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions_test\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/blang/semver/v4\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n)\n\nfunc TestLoadValidate(t *testing.T) {\n\text, err := extensions.Load(\"testdata/good/extension1\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"gvisor\", ext.Manifest.Metadata.Name)\n\n\tversion, err := semver.Parse(\"1.0.0\")\n\trequire.NoError(t, err)\n\n\tassert.NoError(t, ext.Validate(\n\t\textensions.WithValidateConstraints(),\n\t\textensions.WithValidateContents(),\n\t\textensions.WithTalosVersion(&version),\n\t))\n}\n\nfunc TestValidateFailures(t *testing.T) {\n\tversion, err := semver.Parse(\"1.0.0\")\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname          string\n\t\tloadError     string\n\t\tvalidateError string\n\t}{\n\t\t{\n\t\t\tname:      \"wrongfiles\",\n\t\t\tloadError: \"unexpected file \\\"a\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"emptymanifest\",\n\t\t\tloadError: \"unsupported manifest version: \\\"\\\"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"norootfs\",\n\t\t\tloadError: \"extension rootfs is missing\",\n\t\t},\n\t\t{\n\t\t\tname:          \"badpaths\",\n\t\t\tvalidateError: \"path \\\"/boot/vmlinuz\\\" is not allowed in extensions\",\n\t\t},\n\t\t{\n\t\t\tname:          \"usrmerge\",\n\t\t\tvalidateError: \"path \\\"/usr/lib64/a.so\\\" is not allowed in extensions\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\text, err := extensions.Load(filepath.Join(\"testdata/bad\", tt.name))\n\n\t\t\tif tt.loadError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.EqualError(t, err, tt.loadError)\n\t\t\t}\n\n\t\t\tif err == nil {\n\t\t\t\terr = ext.Validate(\n\t\t\t\t\textensions.WithValidateConstraints(),\n\t\t\t\t\textensions.WithValidateContents(),\n\t\t\t\t\textensions.WithTalosVersion(&version),\n\t\t\t\t)\n\n\t\t\t\tassert.EqualError(t, err, tt.validateError)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/load.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"go.yaml.in/yaml/v4\"\n)\n\n// Load extension from the filesystem.\n//\n// This performs initial validation of the extension file structure.\nfunc Load(path string) (*Extension, error) {\n\textension := &Extension{\n\t\tdirectory: filepath.Base(path),\n\t}\n\n\titems, err := os.ReadDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, item := range items {\n\t\tswitch item.Name() {\n\t\tcase \"manifest.yaml\":\n\t\t\tif err = extension.loadManifest(filepath.Join(path, item.Name())); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase \"rootfs\":\n\t\t\textension.rootfsPath = filepath.Join(path, item.Name())\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unexpected file %q\", item.Name())\n\t\t}\n\t}\n\n\tvar zeroManifest Manifest\n\n\tif extension.Manifest == zeroManifest {\n\t\treturn nil, errors.New(\"extension manifest is missing\")\n\t}\n\n\tif extension.rootfsPath == \"\" {\n\t\treturn nil, errors.New(\"extension rootfs is missing\")\n\t}\n\n\treturn extension, nil\n}\n\nfunc (ext *Extension) loadManifest(path string) error {\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tif err = yaml.NewDecoder(f).Decode(&ext.Manifest); err != nil {\n\t\treturn err\n\t}\n\n\tif ext.Manifest.Version != \"v1alpha1\" {\n\t\treturn fmt.Errorf(\"unsupported manifest version: %q\", ext.Manifest.Version)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\n// Manifest is the structure of the extension manifest.yaml file.\ntype Manifest struct {\n\tVersion  string   `yaml:\"version\"`\n\tMetadata Metadata `yaml:\"metadata\"`\n}\n\n// Metadata describes base extension metadata.\n//\n//gotagsrewrite:gen\ntype Metadata struct {\n\tName          string        `yaml:\"name\" protobuf:\"1\"`\n\tVersion       string        `yaml:\"version\" protobuf:\"2\"`\n\tAuthor        string        `yaml:\"author\" protobuf:\"3\"`\n\tDescription   string        `yaml:\"description\" protobuf:\"4\"`\n\tCompatibility Compatibility `yaml:\"compatibility\" protobuf:\"5\"`\n\tExtraInfo     string        `yaml:\"extraInfo,omitempty\" protobuf:\"6\"`\n}\n\n// Compatibility describes extension compatibility.\n//\n//gotagsrewrite:gen\ntype Compatibility struct {\n\tTalos Constraint `yaml:\"talos\" protobuf:\"1\"`\n}\n\n// Constraint describes compatibility constraint.\n//\n//gotagsrewrite:gen\ntype Constraint struct {\n\tVersion string `yaml:\"version\" protobuf:\"1\"`\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/services/restart_kind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services\n\n//go:generate go tool github.com/dmarkham/enumer -type=RestartKind -linecomment -text\n\n// RestartKind specifies how the service should be restarted.\ntype RestartKind int\n\n// RestartKind constants.\nconst (\n\tRestartAlways       RestartKind = 1 // always\n\tRestartNever        RestartKind = 2 // never\n\tRestartUntilSuccess RestartKind = 3 // untilSuccess\n)\n"
  },
  {
    "path": "pkg/machinery/extensions/services/restartkind_enumer.go",
    "content": "// Code generated by \"enumer -type=RestartKind -linecomment -text\"; DO NOT EDIT.\n\npackage services\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _RestartKindName = \"alwaysneveruntilSuccess\"\n\nvar _RestartKindIndex = [...]uint8{0, 6, 11, 23}\n\nconst _RestartKindLowerName = \"alwaysneveruntilsuccess\"\n\nfunc (i RestartKind) String() string {\n\ti -= 1\n\tif i < 0 || i >= RestartKind(len(_RestartKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"RestartKind(%d)\", i+1)\n\t}\n\treturn _RestartKindName[_RestartKindIndex[i]:_RestartKindIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RestartKindNoOp() {\n\tvar x [1]struct{}\n\t_ = x[RestartAlways-(1)]\n\t_ = x[RestartNever-(2)]\n\t_ = x[RestartUntilSuccess-(3)]\n}\n\nvar _RestartKindValues = []RestartKind{RestartAlways, RestartNever, RestartUntilSuccess}\n\nvar _RestartKindNameToValueMap = map[string]RestartKind{\n\t_RestartKindName[0:6]:        RestartAlways,\n\t_RestartKindLowerName[0:6]:   RestartAlways,\n\t_RestartKindName[6:11]:       RestartNever,\n\t_RestartKindLowerName[6:11]:  RestartNever,\n\t_RestartKindName[11:23]:      RestartUntilSuccess,\n\t_RestartKindLowerName[11:23]: RestartUntilSuccess,\n}\n\nvar _RestartKindNames = []string{\n\t_RestartKindName[0:6],\n\t_RestartKindName[6:11],\n\t_RestartKindName[11:23],\n}\n\n// RestartKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RestartKindString(s string) (RestartKind, error) {\n\tif val, ok := _RestartKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RestartKindNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RestartKind values\", s)\n}\n\n// RestartKindValues returns all values of the enum\nfunc RestartKindValues() []RestartKind {\n\treturn _RestartKindValues\n}\n\n// RestartKindStrings returns a slice of all String values of the enum\nfunc RestartKindStrings() []string {\n\tstrs := make([]string, len(_RestartKindNames))\n\tcopy(strs, _RestartKindNames)\n\treturn strs\n}\n\n// IsARestartKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RestartKind) IsARestartKind() bool {\n\tfor _, v := range _RestartKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RestartKind\nfunc (i RestartKind) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RestartKind\nfunc (i *RestartKind) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RestartKindString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/services/services.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package services contains definitions for non-system services.\npackage services\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"regexp\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// Spec is represents non-system service definition.\ntype Spec struct {\n\t// Name of the service to run, will be prefixed with `ext-` when registered as Talos service.\n\t//\n\t// Valid: [-_a-z0-9]+\n\tName string `yaml:\"name\"`\n\t// Container to run.\n\t//\n\t// Container rootfs should be extracted to the /usr/local/lib/containers/<name>.\n\tContainer Container `yaml:\"container\"`\n\t// Service dependencies.\n\tDepends []Dependency `yaml:\"depends\"`\n\t// Restart configuration.\n\tRestart RestartKind `yaml:\"restart\"`\n\t// LogToConsole enables sending service logs to the console.\n\tLogToConsole bool `yaml:\"logToConsole\"`\n}\n\n// Container specifies service container to run.\ntype Container struct {\n\t// Entrypoint for the service, relative to the container rootfs.\n\tEntrypoint string `yaml:\"entrypoint\"`\n\t// Environment variables for the service.\n\tEnvironment []string `yaml:\"environment\"`\n\t// EnvironmentFile to load environment vars before running the service.\n\tEnvironmentFile string `yaml:\"environmentFile\"`\n\t// Args to pass to the entrypoint.\n\tArgs []string `yaml:\"args\"`\n\t// Volume mounts.\n\tMounts []specs.Mount `yaml:\"mounts\"`\n\t// Security options.\n\tSecurity Security `yaml:\"security\"`\n}\n\n// Security options for containers.\ntype Security struct {\n\t// WriteableSysfs makes the '/sys' path writeable in the container namespace if set to true.\n\tWriteableSysfs bool `yaml:\"writeableSysfs\"`\n\t// MaskedPaths is a list of paths in the container namespace that should not be readable.\n\tMaskedPaths []string `yaml:\"maskedPaths\"`\n\t// ReadonlyPaths is a list of paths in the container namespace that should be read-only.\n\tReadonlyPaths []string `yaml:\"readonlyPaths\"`\n\t// WriteableRootfs\n\tWriteableRootfs bool `yaml:\"writeableRootfs\"`\n\t// RootfsPropagation is the propagation mode for the rootfs mount.\n\tRootfsPropagation string `yaml:\"rootfsPropagation,omitempty\"`\n}\n\n// Dependency describes a service Dependency.\n//\n// Only a single dependency out of the list might be specified.\ntype Dependency struct {\n\t// Depends on a service being running and healthy (if health checks are available).\n\tService string `yaml:\"service,omitempty\"`\n\t// Depends on file/directory existence.\n\tPath string `yaml:\"path,omitempty\"`\n\t// Network readiness checks.\n\t//\n\t// Valid options are nethelpers.Status string values.\n\tNetwork []nethelpers.Status `yaml:\"network,omitempty\"`\n\t// Time sync check.\n\tTime bool `yaml:\"time,omitempty\"`\n\t// Depends on configuration files to be present.\n\tConfiguration bool `yaml:\"configuration,omitempty\"`\n}\n\nvar nameRe = regexp.MustCompile(`^[-_a-z0-9]{1,}$`)\n\n// Validate the service spec.\nfunc (spec *Spec) Validate() error {\n\tvar multiErr *multierror.Error\n\n\tif !nameRe.MatchString(spec.Name) {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"name %q is invalid\", spec.Name))\n\t}\n\n\tif !spec.Restart.IsARestartKind() {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"restart kind is invalid: %s\", spec.Restart))\n\t}\n\n\tmultiErr = multierror.Append(multiErr, spec.Container.Validate())\n\n\tfor _, dep := range spec.Depends {\n\t\tmultiErr = multierror.Append(multiErr, dep.Validate())\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// Validate the container spec.\nfunc (ctr *Container) Validate() error {\n\tvar multiErr *multierror.Error\n\n\tif ctr.Entrypoint == \"\" {\n\t\tmultiErr = multierror.Append(multiErr, errors.New(\"container endpoint can't be empty\"))\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// Validate the dependency spec.\n//\n//nolint:gocyclo\nfunc (dep *Dependency) Validate() error {\n\tvar multiErr *multierror.Error\n\n\tnonZeroDeps := 0\n\n\tif dep.Service != \"\" {\n\t\tnonZeroDeps++\n\t}\n\n\tif dep.Path != \"\" {\n\t\tnonZeroDeps++\n\n\t\tif !filepath.IsAbs(dep.Path) {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"path is not absolute: %q\", dep.Path))\n\t\t}\n\t}\n\n\tif len(dep.Network) > 0 {\n\t\tnonZeroDeps++\n\n\t\tfor _, st := range dep.Network {\n\t\t\tif !st.IsAStatus() {\n\t\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"invalid network dependency: %s\", st))\n\t\t\t}\n\t\t}\n\t}\n\n\tif dep.Time {\n\t\tnonZeroDeps++\n\t}\n\n\tif dep.Configuration {\n\t\tnonZeroDeps++\n\t}\n\n\tif nonZeroDeps == 0 {\n\t\tmultiErr = multierror.Append(multiErr, errors.New(\"no dependency specified\"))\n\t}\n\n\tif nonZeroDeps > 1 {\n\t\tmultiErr = multierror.Append(multiErr, errors.New(\"more than a single dependency is set\"))\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/services/services_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage services_test\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions/services\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:embed \"testdata/hello.yaml\"\nvar helloYAML []byte\n\nfunc TestUnmarshal(t *testing.T) {\n\tvar spec services.Spec\n\n\trequire.NoError(t, yaml.Unmarshal(helloYAML, &spec))\n\n\tassert.Equal(t, services.Spec{\n\t\tName: \"hello\",\n\t\tContainer: services.Container{\n\t\t\tEntrypoint: \"hello-world\",\n\t\t\tArgs:       []string{\"--development\", \"--log=debug\"},\n\t\t\tMounts: []specs.Mount{\n\t\t\t\t{\n\t\t\t\t\tDestination: \"/var/lib/example\",\n\t\t\t\t\tType:        \"bind\",\n\t\t\t\t\tSource:      \"/var/lib/example\",\n\t\t\t\t\tOptions:     []string{\"rbind\", \"ro\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tDepends: []services.Dependency{\n\t\t\t{\n\t\t\t\tService: \"cri\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tPath: \"/system/run/machined/machined.sock\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tNetwork: []nethelpers.Status{nethelpers.StatusAddresses},\n\t\t\t},\n\t\t},\n\t\tRestart: services.RestartNever,\n\t}, spec)\n\n\tassert.NoError(t, spec.Validate())\n}\n\nfunc TestValidate(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname          string\n\t\tspec          services.Spec\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:          \"empty\",\n\t\t\tspec:          services.Spec{},\n\t\t\texpectedError: \"3 errors occurred:\\n\\t* name \\\"\\\" is invalid\\n\\t* restart kind is invalid: RestartKind(0)\\n\\t* container endpoint can't be empty\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid name\",\n\t\t\tspec: services.Spec{\n\t\t\t\tName: \"FOO\",\n\t\t\t\tContainer: services.Container{\n\t\t\t\t\tEntrypoint: \"foo\",\n\t\t\t\t},\n\t\t\t\tRestart: services.RestartAlways,\n\t\t\t},\n\t\t\texpectedError: \"1 error occurred:\\n\\t* name \\\"FOO\\\" is invalid\\n\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid deps\",\n\t\t\tspec: services.Spec{\n\t\t\t\tName: \"foo\",\n\t\t\t\tContainer: services.Container{\n\t\t\t\t\tEntrypoint: \"foo\",\n\t\t\t\t},\n\t\t\t\tDepends: []services.Dependency{\n\t\t\t\t\t{},\n\t\t\t\t\t{\n\t\t\t\t\t\tPath: \"./somefile\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: []nethelpers.Status{\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tNetwork: []nethelpers.Status{\n\t\t\t\t\t\t\tnethelpers.StatusAddresses,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tPath: \"/foo\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tRestart: services.RestartAlways,\n\t\t\t},\n\t\t\texpectedError: \"4 errors occurred:\\n\\t* no dependency specified\\n\\t* path is not absolute: \\\"./somefile\\\"\\n\\t* invalid network dependency: Status(0)\\n\\t* more than a single dependency is set\\n\\n\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := tt.spec.Validate()\n\t\t\tassert.EqualError(t, err, tt.expectedError)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/extensions/services/testdata/hello.yaml",
    "content": "name: hello\ncontainer:\n  entrypoint: hello-world\n  args:\n    - --development\n    - --log=debug\n  mounts:\n    - source: /var/lib/example\n      destination: /var/lib/example\n      type: bind\n      options:\n        - rbind\n        - ro\ndepends:\n  - service: cri\n  - path: /system/run/machined/machined.sock\n  - network:\n    - addresses\nrestart: never\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/badpaths/manifest.yaml",
    "content": "version: v1alpha1\nmetadata:\n  name: gvisor\n  version: 20220117.0-v1.0.0\n  author: Andrew Rynhard\n  description: >\n    This system extension provides gVisor using containerd's runtime handler.\n  compatibility:\n    talos:\n      version: \">= v1.0.0\"\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/badpaths/rootfs/boot/vmlinuz",
    "content": ""
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/emptymanifest/manifest.yaml",
    "content": "---\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/norootfs/manifest.yaml",
    "content": "version: v1alpha1\nmetadata:\n  name: gvisor\n  version: 20220117.0-v1.0.0\n  author: Andrew Rynhard\n  description: >\n    This system extension provides gVisor using containerd's runtime handler.\n  compatibility:\n    talos:\n      version: \">= v1.0.0\"\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/usrmerge/manifest.yaml",
    "content": "version: v1alpha1\nmetadata:\n  name: gvisor\n  version: 20220117.0-v1.0.0\n  author: Andrew Rynhard\n  description: >\n    This system extension provides gVisor using containerd's runtime handler.\n  compatibility:\n    talos:\n      version: \">= v1.0.0\"\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/bad/wrongfiles/a",
    "content": ""
  },
  {
    "path": "pkg/machinery/extensions/testdata/good/extension1/manifest.yaml",
    "content": "version: v1alpha1\nmetadata:\n  name: gvisor\n  version: 20220117.0-v1.0.0\n  author: Andrew Rynhard\n  description: >\n    This system extension provides gVisor using containerd's runtime handler.\n  compatibility:\n    talos:\n      version: \">= v1.0.0\"\n"
  },
  {
    "path": "pkg/machinery/extensions/testdata/good/extension1/rootfs/usr/lib/firmware/amd/cpu",
    "content": ""
  },
  {
    "path": "pkg/machinery/extensions/testdata/good/extension1/rootfs/usr/lib/ld-linux-x86-64.so.2",
    "content": ""
  },
  {
    "path": "pkg/machinery/extensions/validate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage extensions\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/blang/semver/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\n// ValidationOptions are used to configure the validation process.\ntype ValidationOptions struct {\n\t// ValidateContstraints enables validation of the extension constraints.\n\tValidateContstraints bool\n\t// ValidateContents enables validation of the extension contents.\n\tValidateContents bool\n\n\t// TalosVersion is the version of Talos to validate against.\n\tTalosVersion *semver.Version\n}\n\n// WithValidateConstraints enables validation of the extension constraints.\nfunc WithValidateConstraints() ValidationOption {\n\treturn func(o *ValidationOptions) error {\n\t\to.ValidateContstraints = true\n\n\t\treturn nil\n\t}\n}\n\n// WithValidateContents enables validation of the extension contents.\nfunc WithValidateContents() ValidationOption {\n\treturn func(o *ValidationOptions) error {\n\t\to.ValidateContents = true\n\n\t\treturn nil\n\t}\n}\n\n// WithTalosVersion sets the Talos version to validate against.\nfunc WithTalosVersion(version *semver.Version) ValidationOption {\n\treturn func(o *ValidationOptions) error {\n\t\to.TalosVersion = version\n\n\t\treturn nil\n\t}\n}\n\n// ValidationOption is a function that configures the validation options.\ntype ValidationOption func(*ValidationOptions) error\n\n// Validate the extension: compatibility, contents, etc.\nfunc (ext *Extension) Validate(opts ...ValidationOption) error {\n\tvalidationOptions := &ValidationOptions{}\n\n\tfor _, opt := range opts {\n\t\tif err := opt(validationOptions); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\n\tif validationOptions.TalosVersion == nil {\n\t\tversion, err := semver.ParseTolerant(version.Tag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvalidationOptions.TalosVersion = &version\n\t}\n\n\tif validationOptions.ValidateContstraints {\n\t\tif err := ext.validateConstraints(*validationOptions.TalosVersion); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif validationOptions.ValidateContents {\n\t\treturn ext.validateContents()\n\t}\n\n\treturn nil\n}\n\nfunc (ext *Extension) validateConstraints(talosVersion semver.Version) error {\n\tconstraint := ext.Manifest.Metadata.Compatibility.Talos.Version\n\n\tif constraint != \"\" {\n\t\tversionConstraint, err := semver.ParseRange(trim(constraint))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing Talos version constraint: %w\", err)\n\t\t}\n\n\t\tif !versionConstraint(coreVersion(talosVersion)) {\n\t\t\treturn fmt.Errorf(\"version constraint %s can't be satisfied with Talos version %s\", constraint, talosVersion)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// trim removes 'v' symbol anywhere in string if it's located before the number.\nfunc trim(constraint string) string {\n\tfor i := 0; i < len(constraint); i++ {\n\t\tif constraint[i] == 'v' && i+1 < len(constraint) && constraint[i+1] >= '0' && constraint[i+1] <= '9' {\n\t\t\tconstraint = constraint[:i] + constraint[i+1:]\n\t\t}\n\t}\n\n\treturn constraint\n}\n\nfunc coreVersion(talosVersion semver.Version) semver.Version {\n\treturn semver.Version{\n\t\tMajor: talosVersion.Major,\n\t\tMinor: talosVersion.Minor,\n\t\tPatch: talosVersion.Patch,\n\t}\n}\n\n//nolint:gocyclo\nfunc (ext *Extension) validateContents() error {\n\treturn filepath.WalkDir(ext.rootfsPath, func(path string, d fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\titemPath, err := filepath.Rel(ext.rootfsPath, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\titemPath = filepath.Join(\"/\", itemPath)\n\n\t\t// check for -------w-\n\t\tif d.Type().Perm()&0o002 > 0 {\n\t\t\treturn fmt.Errorf(\"world-writeable files are not allowed: %q\", itemPath)\n\t\t}\n\n\t\t// no special files\n\t\tif !d.IsDir() && !d.Type().IsRegular() && d.Type().Type() != os.ModeSymlink {\n\t\t\treturn fmt.Errorf(\"special files are not allowed: %q\", itemPath)\n\t\t}\n\n\t\t// regular file: check for file path being whitelisted\n\t\tif !d.IsDir() {\n\t\t\tallowed := false\n\n\t\t\tfor _, allowedPath := range AllowedPaths {\n\t\t\t\tif strings.HasPrefix(itemPath, allowedPath) {\n\t\t\t\t\t_, err = filepath.Rel(allowedPath, itemPath)\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tallowed = true\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !allowed {\n\t\t\t\treturn fmt.Errorf(\"path %q is not allowed in extensions\", itemPath)\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/fipsmode/fipsmode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package fipsmode provides a way to check if the system is running in FIPS mode.\npackage fipsmode\n\nimport (\n\t\"crypto/fips140\"\n\t\"crypto/sha1\"\n\t\"sync\"\n)\n\n// Enabled checks if the system is running in FIPS mode.\nfunc Enabled() bool {\n\treturn fips140.Enabled()\n}\n\n// Strict checks if the strict FIPS mode is enabled.\n//\n// Go doesn't provide a simple way to check for strict FIPS mode, so we\n// use a side-effect of SHA-1 to fail.\nvar Strict = sync.OnceValue(func() bool {\n\tif !Enabled() {\n\t\treturn false\n\t}\n\n\t_, err := sha1.New().Write(nil)\n\n\tstrict := err != nil\n\n\treturn strict\n})\n"
  },
  {
    "path": "pkg/machinery/fipsmode/fipsmode_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage fipsmode_test\n\nimport (\n\t\"crypto/fips140\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/fipsmode\"\n)\n\nfunc TestEnabled(t *testing.T) {\n\tt.Parallel()\n\n\tassert.Equal(t, fips140.Enabled(), fipsmode.Enabled())\n\n\tt.Logf(\"fips140.Enabled() = %v\", fips140.Enabled())\n}\n\nfunc TestStrict(t *testing.T) {\n\tt.Parallel()\n\n\t// guess strict mode from the environment\n\tgodebug := os.Getenv(\"GODEBUG\")\n\tshouldbeStrict := strings.Contains(godebug, \"fips140=only\")\n\n\tassert.Equal(t, shouldbeStrict, fipsmode.Strict())\n\n\tt.Logf(\"fipsmode.Strict() = %v\", fipsmode.Strict())\n}\n"
  },
  {
    "path": "pkg/machinery/formatters/formatters.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package formatters contains the API response formatters used in the CLI output.\npackage formatters\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/emicklei/dot\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/peer\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/inspect\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n)\n\n// RenderMounts renders mounts output.\nfunc RenderMounts(resp *machine.MountsResponse, output io.Writer, remotePeer *peer.Peer) error {\n\tw := tabwriter.NewWriter(output, 0, 0, 3, ' ', 0)\n\tparts := []string{\"FILESYSTEM\", \"SIZE(GB)\", \"USED(GB)\", \"AVAILABLE(GB)\", \"PERCENT USED\", \"MOUNTED ON\"}\n\n\tvar defaultNode string\n\n\tif remotePeer != nil {\n\t\tparts = append([]string{\"NODE\"}, parts...)\n\t\tdefaultNode = client.AddrFromPeer(remotePeer)\n\t}\n\n\tfmt.Fprintln(w, strings.Join(parts, \"\\t\"))\n\n\tfor _, msg := range resp.Messages {\n\t\tfor _, r := range msg.Stats {\n\t\t\tpercentAvailable := 100.0 - 100.0*(float64(r.Available)/float64(r.Size))\n\n\t\t\tif math.IsNaN(percentAvailable) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tnode := defaultNode\n\n\t\t\tif msg.Metadata != nil {\n\t\t\t\tnode = msg.Metadata.Hostname\n\t\t\t}\n\n\t\t\tformat := \"%s\\t%.02f\\t%.02f\\t%.02f\\t%.02f%%\\t%s\\n\"\n\t\t\targs := []any{r.Filesystem, float64(r.Size) * 1e-9, float64(r.Size-r.Available) * 1e-9, float64(r.Available) * 1e-9, percentAvailable, r.MountedOn}\n\n\t\t\tif defaultNode != \"\" {\n\t\t\t\tformat = \"%s\\t\" + format\n\n\t\t\t\targs = slices.Insert(args, 0, any(node))\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, format, args...)\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\n// RenderGraph renders inspect controller runtime graph.\n//\n//nolint:gocyclo,cyclop\nfunc RenderGraph(ctx context.Context, c *client.Client, resp *inspect.ControllerRuntimeDependenciesResponse, output io.Writer, withResources bool) error {\n\tgraph := dot.NewGraph(dot.Directed)\n\n\tresourceTypeID := func(edge *inspect.ControllerDependencyEdge) string {\n\t\treturn edge.GetResourceType()\n\t}\n\n\tresourceID := func(r resource.Resource) string {\n\t\treturn fmt.Sprintf(\"%s/%s/%s\", r.Metadata().Namespace(), r.Metadata().Type(), r.Metadata().ID())\n\t}\n\n\tif withResources {\n\t\tresources := map[string][]resource.Resource{}\n\n\t\tmd, _ := metadata.FromOutgoingContext(ctx)\n\t\tnodes := md[\"nodes\"]\n\n\t\tnodeCtx := ctx\n\n\t\tif len(nodes) > 0 {\n\t\t\tnodeCtx = client.WithNode(ctx, nodes[0])\n\t\t}\n\n\t\tfor _, msg := range resp.GetMessages() {\n\t\t\tfor _, edge := range msg.GetEdges() {\n\t\t\t\tresourceType := resourceTypeID(edge)\n\n\t\t\t\tif _, ok := resources[resourceType]; ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tnamespace := edge.GetResourceNamespace()\n\n\t\t\t\trd, err := c.ResolveResourceKind(nodeCtx, &namespace, edge.GetResourceType())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\titems, err := c.COSI.List(nodeCtx, resource.NewMetadata(namespace, rd.TypedSpec().Type, \"\", resource.VersionUndefined))\n\t\t\t\tif err != nil {\n\t\t\t\t\t// ignore errors here\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tresources[resourceType] = append(resources[resourceType], items.Items...)\n\t\t\t}\n\t\t}\n\n\t\tfor _, msg := range resp.GetMessages() {\n\t\t\tfor _, edge := range msg.GetEdges() {\n\t\t\t\tgraph.Node(edge.ControllerName).Box()\n\t\t\t}\n\t\t}\n\n\t\tfor resourceType, resourceList := range resources {\n\t\t\tcluster := graph.Subgraph(resourceType, dot.ClusterOption{})\n\n\t\t\tfor _, resource := range resourceList {\n\t\t\t\tcluster.Node(resourceID(resource)).\n\t\t\t\t\tAttr(\"shape\", \"note\").\n\t\t\t\t\tAttr(\"fillcolor\", \"azure2\").\n\t\t\t\t\tAttr(\"style\", \"filled\")\n\t\t\t}\n\t\t}\n\n\t\tfor _, msg := range resp.GetMessages() {\n\t\t\tfor _, edge := range msg.GetEdges() {\n\t\t\t\tfor _, resource := range resources[resourceTypeID(edge)] {\n\t\t\t\t\tif edge.GetResourceId() != \"\" && resource.Metadata().ID() != edge.GetResourceId() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif (edge.GetEdgeType() == inspect.DependencyEdgeType_OUTPUT_EXCLUSIVE ||\n\t\t\t\t\t\tedge.GetEdgeType() == inspect.DependencyEdgeType_OUTPUT_SHARED) &&\n\t\t\t\t\t\tedge.GetControllerName() != resource.Metadata().Owner() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch edge.GetEdgeType() {\n\t\t\t\t\tcase inspect.DependencyEdgeType_OUTPUT_EXCLUSIVE:\n\t\t\t\t\t\tgraph.Edge(graph.Node(edge.ControllerName), graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource))).Solid()\n\t\t\t\t\tcase inspect.DependencyEdgeType_OUTPUT_SHARED:\n\t\t\t\t\t\tgraph.Edge(graph.Node(edge.ControllerName), graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource))).Solid()\n\t\t\t\t\tcase inspect.DependencyEdgeType_INPUT_STRONG:\n\t\t\t\t\t\tgraph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Solid()\n\t\t\t\t\tcase inspect.DependencyEdgeType_INPUT_WEAK:\n\t\t\t\t\t\tgraph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Dotted()\n\t\t\t\t\tcase inspect.DependencyEdgeType_INPUT_DESTROY_READY: // don't show the DestroyReady inputs to reduce the visual clutter\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, msg := range resp.GetMessages() {\n\t\t\tfor _, edge := range msg.GetEdges() {\n\t\t\t\tgraph.Node(edge.ControllerName).Box()\n\n\t\t\t\tgraph.Node(resourceTypeID(edge)).\n\t\t\t\t\tAttr(\"shape\", \"note\").\n\t\t\t\t\tAttr(\"fillcolor\", \"azure2\").\n\t\t\t\t\tAttr(\"style\", \"filled\")\n\t\t\t}\n\t\t}\n\n\t\tfor _, msg := range resp.GetMessages() {\n\t\t\tfor _, edge := range msg.GetEdges() {\n\t\t\t\tvar idLabels []string\n\n\t\t\t\tif edge.GetResourceId() != \"\" {\n\t\t\t\t\tidLabels = append(idLabels, edge.GetResourceId())\n\t\t\t\t}\n\n\t\t\t\tswitch edge.GetEdgeType() {\n\t\t\t\tcase inspect.DependencyEdgeType_OUTPUT_EXCLUSIVE:\n\t\t\t\t\tgraph.Edge(graph.Node(edge.ControllerName), graph.Node(resourceTypeID(edge))).Bold()\n\t\t\t\tcase inspect.DependencyEdgeType_OUTPUT_SHARED:\n\t\t\t\t\tgraph.Edge(graph.Node(edge.ControllerName), graph.Node(resourceTypeID(edge))).Solid()\n\t\t\t\tcase inspect.DependencyEdgeType_INPUT_STRONG:\n\t\t\t\t\tgraph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Solid()\n\t\t\t\tcase inspect.DependencyEdgeType_INPUT_WEAK:\n\t\t\t\t\tgraph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Dotted()\n\t\t\t\tcase inspect.DependencyEdgeType_INPUT_DESTROY_READY: // don't show the DestroyReady inputs to reduce the visual clutter\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgraph.Write(output)\n\n\treturn nil\n}\n\n// RenderServicesInfo writes human readable service information to the io.Writer.\nfunc RenderServicesInfo(services []client.ServiceInfo, output io.Writer, defaultNode string, withNodeInfo bool) error {\n\tw := tabwriter.NewWriter(output, 0, 0, 3, ' ', 0)\n\n\tnode := defaultNode\n\n\tfor _, s := range services {\n\t\tif s.Metadata != nil {\n\t\t\tnode = s.Metadata.Hostname\n\t\t}\n\n\t\tif withNodeInfo {\n\t\t\tfmt.Fprintf(w, \"NODE\\t%s\\n\", node)\n\t\t}\n\n\t\tsvc := ServiceInfoWrapper{s.Service}\n\t\tfmt.Fprintf(w, \"ID\\t%s\\n\", svc.Id)\n\t\tfmt.Fprintf(w, \"STATE\\t%s\\n\", svc.State)\n\t\tfmt.Fprintf(w, \"HEALTH\\t%s\\n\", svc.HealthStatus())\n\n\t\tif svc.Health.LastMessage != \"\" {\n\t\t\tfmt.Fprintf(w, \"LAST HEALTH MESSAGE\\t%s\\n\", svc.Health.LastMessage)\n\t\t}\n\n\t\tlabel := \"EVENTS\"\n\n\t\tfor i := range svc.Events.Events {\n\t\t\tevent := svc.Events.Events[len(svc.Events.Events)-1-i]\n\n\t\t\tts := event.Ts.AsTime()\n\t\t\tfmt.Fprintf(w, \"%s\\t[%s]: %s (%s ago)\\n\", label, event.State, event.Msg, time.Since(ts).Round(time.Second))\n\t\t\tlabel = \"\"\n\t\t}\n\t}\n\n\treturn w.Flush()\n}\n\n// ServiceInfoWrapper helper that allows generating rich service information.\ntype ServiceInfoWrapper struct {\n\t*machine.ServiceInfo\n}\n\n// LastUpdated derive last updated time from events stream.\nfunc (svc ServiceInfoWrapper) LastUpdated() string {\n\tif len(svc.Events.Events) == 0 {\n\t\treturn \"\"\n\t}\n\n\tts := svc.Events.Events[len(svc.Events.Events)-1].Ts.AsTime()\n\n\treturn time.Since(ts).Round(time.Second).String()\n}\n\n// LastEvent return last service event.\nfunc (svc ServiceInfoWrapper) LastEvent() string {\n\tif len(svc.Events.Events) == 0 {\n\t\treturn \"<none>\"\n\t}\n\n\treturn svc.Events.Events[len(svc.Events.Events)-1].Msg\n}\n\n// HealthStatus service health status.\nfunc (svc ServiceInfoWrapper) HealthStatus() string {\n\tif svc.Health.Unknown {\n\t\treturn \"?\"\n\t}\n\n\tif svc.Health.Healthy {\n\t\treturn \"OK\"\n\t}\n\n\treturn \"Fail\"\n}\n"
  },
  {
    "path": "pkg/machinery/gendata/data/artifacts",
    "content": "_out"
  },
  {
    "path": "pkg/machinery/gendata/data/name",
    "content": "Talos"
  },
  {
    "path": "pkg/machinery/gendata/data/pkgs",
    "content": "v1.13.0-beta.0"
  },
  {
    "path": "pkg/machinery/gendata/data/registry",
    "content": "ghcr.io"
  },
  {
    "path": "pkg/machinery/gendata/data/sha",
    "content": "undefined"
  },
  {
    "path": "pkg/machinery/gendata/data/tag",
    "content": "v1.13.0-alpha.2"
  },
  {
    "path": "pkg/machinery/gendata/data/tools",
    "content": "v1.13.0-beta.0"
  },
  {
    "path": "pkg/machinery/gendata/data/username",
    "content": "siderolabs"
  },
  {
    "path": "pkg/machinery/gendata/gendata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package gendata contains that a variables generated from Makefile script. It's a proper alternative to using\n// -ldflags '-X ...'.\npackage gendata\n\nimport (\n\t_ \"embed\"\n)\n\nvar (\n\t// VersionName declares variable used by version package.\n\t//go:embed data/name\n\tVersionName string\n\t// VersionTag declares variable used by version package.\n\t//go:embed data/tag\n\tVersionTag string\n\t// VersionSHA declares variable used by version package.\n\t//go:embed data/sha\n\tVersionSHA string\n\t// VersionPkgs declares variable used by version package.\n\t//go:embed data/pkgs\n\tVersionPkgs string\n\t// ImagesUsername declares variable used by images package.\n\t//go:embed data/username\n\tImagesUsername string\n\t// ImagesRegistry declares variable used by images package.\n\t//go:embed data/registry\n\tImagesRegistry string\n\t// ArtifactsPath declares variable used by helpers package.\n\t//go:embed data/artifacts\n\tArtifactsPath string\n)\n"
  },
  {
    "path": "pkg/machinery/go.mod",
    "content": "module github.com/siderolabs/talos/pkg/machinery\n\ngo 1.26.1\n\n// forked ethtool introduces missing APIs\nreplace github.com/mdlayher/ethtool => github.com/siderolabs/ethtool v0.4.0-sidero\n\n\nrequire (\n\tgithub.com/blang/semver/v4 v4.0.0\n\tgithub.com/containerd/go-cni v1.1.13\n\tgithub.com/cosi-project/runtime v1.14.0\n\tgithub.com/dustin/go-humanize v1.0.1\n\tgithub.com/emicklei/dot v1.11.0\n\tgithub.com/evanphx/json-patch v5.9.11+incompatible\n\tgithub.com/ghodss/yaml v1.0.0\n\tgithub.com/google/cel-go v0.27.0\n\tgithub.com/hashicorp/go-multierror v1.1.1\n\tgithub.com/jsimonetti/rtnetlink/v2 v2.2.0\n\tgithub.com/mdlayher/ethtool v0.5.1\n\tgithub.com/neticdk/go-stdlib v1.0.1\n\tgithub.com/opencontainers/runtime-spec v1.3.0\n\tgithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25\n\tgithub.com/ryanuber/go-glob v1.0.0\n\tgithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2\n\tgithub.com/siderolabs/crypto v0.6.4\n\tgithub.com/siderolabs/gen v0.8.6\n\tgithub.com/siderolabs/go-api-signature v0.3.12\n\tgithub.com/siderolabs/go-pointer v1.0.1\n\tgithub.com/siderolabs/net v0.4.0\n\tgithub.com/siderolabs/protoenc v0.2.4\n\tgithub.com/stretchr/testify v1.11.1\n\tgo.yaml.in/yaml/v4 v4.0.0-rc.4\n\tgolang.org/x/net v0.52.0\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c\n\tgoogle.golang.org/grpc v1.79.3\n\tgoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tcel.dev/expr v0.25.1 // indirect\n\tgithub.com/ProtonMail/go-crypto v1.3.0 // indirect\n\tgithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect\n\tgithub.com/ProtonMail/gopenpgp/v2 v2.9.0 // indirect\n\tgithub.com/adrg/xdg v0.5.3 // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.1 // indirect\n\tgithub.com/cenkalti/backoff/v4 v4.3.0 // indirect\n\tgithub.com/cloudflare/circl v1.6.3 // indirect\n\tgithub.com/containernetworking/cni v1.3.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/gertd/go-pluralize v0.2.1 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/josharian/native v1.1.0 // indirect\n\tgithub.com/mdlayher/genetlink v1.3.2 // indirect\n\tgithub.com/mdlayher/netlink v1.8.0 // indirect\n\tgithub.com/mdlayher/socket v0.5.1 // indirect\n\tgithub.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect\n\tgithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/sasha-s/go-deadlock v0.3.5 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.1 // indirect\n\tgolang.org/x/crypto v0.49.0 // indirect\n\tgolang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.42.0 // indirect\n\tgolang.org/x/text v0.35.0 // indirect\n\tgolang.org/x/time v0.14.0 // indirect\n\tgopkg.in/yaml.v2 v2.4.0 // indirect\n)\n"
  },
  {
    "path": "pkg/machinery/go.sum",
    "content": "cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=\ngithub.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=\ngithub.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k=\ngithub.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw=\ngithub.com/ProtonMail/gopenpgp/v2 v2.9.0 h1:ruLzBmwe4dR1hdnrsEJ/S7psSBmV15gFttFUPP/+/kE=\ngithub.com/ProtonMail/gopenpgp/v2 v2.9.0/go.mod h1:IldDyh9Hv1ZCCYatTuuEt1XZJ0OPjxLpTarDfglih7s=\ngithub.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=\ngithub.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=\ngithub.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=\ngithub.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=\ngithub.com/brianvoe/gofakeit/v7 v7.7.3 h1:RWOATEGpJ5EVg2nN8nlaEyaV/aB4d6c3GqYrbqQekss=\ngithub.com/brianvoe/gofakeit/v7 v7.7.3/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cilium/ebpf v0.20.0 h1:atwWj9d3NffHyPZzVlx3hmw1on5CLe9eljR8VuHTwhM=\ngithub.com/cilium/ebpf v0.20.0/go.mod h1:pzLjFymM+uZPLk/IXZUL63xdx5VXEo+enTzxkZXdycw=\ngithub.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=\ngithub.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=\ngithub.com/containerd/go-cni v1.1.13 h1:eFSGOKlhoYNxpJ51KRIMHZNlg5UgocXEIEBGkY7Hnis=\ngithub.com/containerd/go-cni v1.1.13/go.mod h1:nTieub0XDRmvCZ9VI/SBG6PyqT95N4FIhxsauF1vSBI=\ngithub.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEmnuFjskwo=\ngithub.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4=\ngithub.com/cosi-project/runtime v1.14.0 h1:puGI7sssk1h2KScC4ETjC+M7nyN+0ur44bAuSLdY91A=\ngithub.com/cosi-project/runtime v1.14.0/go.mod h1:sd2+E6DjC/QjrnlEEglINDZ4FUW7cVDMB5aG98Dl3LA=\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/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=\ngithub.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/emicklei/dot v1.11.0 h1:zsrhCuFHAJge/aZIC4N4LdHy5tqYu4tWEaUzIwdYj4Y=\ngithub.com/emicklei/dot v1.11.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=\ngithub.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=\ngithub.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=\ngithub.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA=\ngithub.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk=\ngithub.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo=\ngithub.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=\ngithub.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=\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/grpc-ecosystem/grpc-gateway/v2 v2.27.8 h1:NpbJl/eVbvrGE0MJ6X16X9SAifesl6Fwxg/YmCvubRI=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8/go.mod h1:mi7YA+gCzVem12exXy46ZespvGtX/lZmD/RLnQhVW7U=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=\ngithub.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=\ngithub.com/jsimonetti/rtnetlink/v2 v2.2.0 h1:/KfZ310gOAFrXXol5VwnFEt+ucldD/0dsSRZwpHCP9w=\ngithub.com/jsimonetti/rtnetlink/v2 v2.2.0/go.mod h1:lbjDHxC+5RJ08lzPeA90Ls2pEoId3F08MoEMlhfHxeI=\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/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=\ngithub.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=\ngithub.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM=\ngithub.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594=\ngithub.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=\ngithub.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=\ngithub.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=\ngithub.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=\ngithub.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=\ngithub.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=\ngithub.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=\ngithub.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=\ngithub.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=\ngithub.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25 h1:S1hI5JiKP7883xBzZAr1ydcxrKNSVNm7+3+JwjxZEsg=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20250313105119-ba97887b0a25/go.mod h1:ZQntvDG8TkPgljxtA0R9frDoND4QORU1VXz015N5Ks4=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=\ngithub.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=\ngithub.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=\ngithub.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=\ngithub.com/siderolabs/crypto v0.6.4 h1:uMoe/X/mABOv6yOgvKcjmjIMdv6U8JegBXlPKtyjn3g=\ngithub.com/siderolabs/crypto v0.6.4/go.mod h1:39B7Mdrd8qTfEYOjsWPQOk7gLTWrEI30isAW+YYj9nk=\ngithub.com/siderolabs/ethtool v0.4.0-sidero h1:Ls/M4bFUjfcB1RDVviPZlL3kWcXaEVVSbKke+EZ2A9U=\ngithub.com/siderolabs/ethtool v0.4.0-sidero/go.mod h1:nOIR88fiFTdBfakYLEUAhxdy75Ih/fgnSlsSKAHRpfc=\ngithub.com/siderolabs/gen v0.8.6 h1:pE6shuqov3L+5rEcAUJ/kY6iJofimljQw5G95P8a5c4=\ngithub.com/siderolabs/gen v0.8.6/go.mod h1:J9IbusbES2W6QWjtSHpDV9iPGZHc978h1+KJ4oQRspQ=\ngithub.com/siderolabs/go-api-signature v0.3.12 h1:i1X+kPh9fzo+lEjtEplZSbtq1p21vKv4FCWJcB/ozvk=\ngithub.com/siderolabs/go-api-signature v0.3.12/go.mod h1:dPLiXohup4qHX7KUgF/wwOE3lRU5uAr3ssEomNxiyxY=\ngithub.com/siderolabs/go-pointer v1.0.1 h1:f7Yi4IK1jptS8yrT9GEbwhmGcVxvPQgBUG/weH3V3DM=\ngithub.com/siderolabs/go-pointer v1.0.1/go.mod h1:C8Q/3pNHT4RE9e4rYR9PHeS6KPMlStRBgYrJQJNy/vA=\ngithub.com/siderolabs/go-retry v0.3.3 h1:zKV+S1vumtO72E6sYsLlmIdV/G/GcYSBLiEx/c9oCEg=\ngithub.com/siderolabs/go-retry v0.3.3/go.mod h1:Ff/VGc7v7un4uQg3DybgrmOWHEmJ8BzZds/XNn/BqMI=\ngithub.com/siderolabs/net v0.4.0 h1:1bOgVay/ijPkJz4qct98nHsiB/ysLQU0KLoBC4qLm7I=\ngithub.com/siderolabs/net v0.4.0/go.mod h1:/ibG+Hm9HU27agp5r9Q3eZicEfjquzNzQNux5uEk0kM=\ngithub.com/siderolabs/protoenc v0.2.4 h1:D3Fpn2nQSQOhl8ZlAxijZAf7K6F8CM1uZq0afIGsr8Q=\ngithub.com/siderolabs/protoenc v0.2.4/go.mod h1:i5XLHjfv5vyi7LhQrSEo19HCA+lYtDd7CWxsoWp9XE8=\ngithub.com/smira/go-stdlib v0.0.0-20260318082201-9d387eb2130d h1:/A1ysgd+d93H+qhSUwosk6O6WoppaHQc45XzbLUilRU=\ngithub.com/smira/go-stdlib v0.0.0-20260318082201-9d387eb2130d/go.mod h1:KP9nLuDoanLbM8Wturn+hage2FtcrJaF1+1Znu+MKEw=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=\ngithub.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=\ngo.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=\ngo.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=\ngo.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=\ngo.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=\ngo.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=\ngo.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=\ngo.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=\ngo.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=\ngolang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=\ngolang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=\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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=\ngolang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c h1:OyQPd6I3pN/9gDxz6L13kYGJgqkpdrAohJRBeXyxlgI=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260311181403-84a4fc48630c/go.mod h1:X2gu9Qwng7Nn009s/r3RUxqkzQNqOrAy79bluY7ojIg=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c h1:xgCzyF2LFIO/0X2UAoVRiXKU5Xg6VjToG4i2/ecSswk=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260311181403-84a4fc48630c/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=\ngoogle.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=\ngoogle.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\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/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=\n"
  },
  {
    "path": "pkg/machinery/imager/imageropts/bootloaderkind_enumer.go",
    "content": "// Code generated by \"enumer -type BootloaderKind -linecomment -text\"; DO NOT EDIT.\n\npackage imageropts\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _BootloaderKindName = \"nonedual-bootsd-bootgrub\"\n\nvar _BootloaderKindIndex = [...]uint8{0, 4, 13, 20, 24}\n\nconst _BootloaderKindLowerName = \"nonedual-bootsd-bootgrub\"\n\nfunc (i BootloaderKind) String() string {\n\tif i < 0 || i >= BootloaderKind(len(_BootloaderKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"BootloaderKind(%d)\", i)\n\t}\n\treturn _BootloaderKindName[_BootloaderKindIndex[i]:_BootloaderKindIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _BootloaderKindNoOp() {\n\tvar x [1]struct{}\n\t_ = x[BootLoaderKindNone-(0)]\n\t_ = x[BootLoaderKindDualBoot-(1)]\n\t_ = x[BootLoaderKindSDBoot-(2)]\n\t_ = x[BootLoaderKindGrub-(3)]\n}\n\nvar _BootloaderKindValues = []BootloaderKind{BootLoaderKindNone, BootLoaderKindDualBoot, BootLoaderKindSDBoot, BootLoaderKindGrub}\n\nvar _BootloaderKindNameToValueMap = map[string]BootloaderKind{\n\t_BootloaderKindName[0:4]:        BootLoaderKindNone,\n\t_BootloaderKindLowerName[0:4]:   BootLoaderKindNone,\n\t_BootloaderKindName[4:13]:       BootLoaderKindDualBoot,\n\t_BootloaderKindLowerName[4:13]:  BootLoaderKindDualBoot,\n\t_BootloaderKindName[13:20]:      BootLoaderKindSDBoot,\n\t_BootloaderKindLowerName[13:20]: BootLoaderKindSDBoot,\n\t_BootloaderKindName[20:24]:      BootLoaderKindGrub,\n\t_BootloaderKindLowerName[20:24]: BootLoaderKindGrub,\n}\n\nvar _BootloaderKindNames = []string{\n\t_BootloaderKindName[0:4],\n\t_BootloaderKindName[4:13],\n\t_BootloaderKindName[13:20],\n\t_BootloaderKindName[20:24],\n}\n\n// BootloaderKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc BootloaderKindString(s string) (BootloaderKind, error) {\n\tif val, ok := _BootloaderKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _BootloaderKindNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to BootloaderKind values\", s)\n}\n\n// BootloaderKindValues returns all values of the enum\nfunc BootloaderKindValues() []BootloaderKind {\n\treturn _BootloaderKindValues\n}\n\n// BootloaderKindStrings returns a slice of all String values of the enum\nfunc BootloaderKindStrings() []string {\n\tstrs := make([]string, len(_BootloaderKindNames))\n\tcopy(strs, _BootloaderKindNames)\n\treturn strs\n}\n\n// IsABootloaderKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i BootloaderKind) IsABootloaderKind() bool {\n\tfor _, v := range _BootloaderKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for BootloaderKind\nfunc (i BootloaderKind) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for BootloaderKind\nfunc (i *BootloaderKind) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = BootloaderKindString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/imager/imageropts/imageropts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package imageropts contains exportable types used in imager profile options.\npackage imageropts\n\n//go:generate go tool github.com/dmarkham/enumer -type BootloaderKind -linecomment -text\n\n// BootloaderKind is a bootloader for the disk image.\ntype BootloaderKind int\n\nconst (\n\t// BootLoaderKindNone is the zero value.\n\tBootLoaderKindNone BootloaderKind = iota // none\n\t// BootLoaderKindDualBoot is the dual-boot bootloader.\n\t// using sd-boot for UEFI and GRUB for BIOS.\n\tBootLoaderKindDualBoot // dual-boot\n\t// BootLoaderKindSDBoot is the sd-boot bootloader.\n\tBootLoaderKindSDBoot // sd-boot\n\t// BootLoaderKindGrub is the GRUB bootloader.\n\tBootLoaderKindGrub // grub\n)\n"
  },
  {
    "path": "pkg/machinery/imager/quirks/partitions.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage quirks\n\n// PartitionSizes capture partition sizes for Talos.\ntype PartitionSizes struct {\n\tbootSize uint64\n}\n\nconst (\n\tmib = 1024 * 1024\n\tgib = 1024 * mib\n)\n\n// GrubEFISize return EFI partition size for GRUB layout.\nfunc (p PartitionSizes) GrubEFISize() uint64 {\n\treturn 100 * mib\n}\n\n// GrubBIOSSize return BIOS GRUB partition size.\nfunc (p PartitionSizes) GrubBIOSSize() uint64 {\n\treturn 1 * mib\n}\n\n// GrubBootSize return boot partition size for GRUB layout.\nfunc (p PartitionSizes) GrubBootSize() uint64 {\n\treturn p.bootSize\n}\n\n// UKIEFISize return EFI partition size for UKI layout.\nfunc (p PartitionSizes) UKIEFISize() uint64 {\n\t// EFIUKISize is the size of the EFI partition when UKI is enabled.\n\t// With UKI all assets are stored in the EFI partition.\n\t// This is the size of the old EFISize + BIOSGrubSize + BootSize.\n\treturn p.GrubEFISize() + p.GrubBIOSSize() + p.GrubBootSize()\n}\n\n// METASize return META partition size.\nfunc (p PartitionSizes) METASize() uint64 {\n\treturn 1 * mib\n}\n\n// StateSize return state partition size.\nfunc (p PartitionSizes) StateSize() uint64 {\n\treturn 100 * mib\n}\n\n// EphemeralMinSize return minimum size for ephemeral partition.\nfunc (p PartitionSizes) EphemeralMinSize() uint64 {\n\treturn 2 * gib\n}\n"
  },
  {
    "path": "pkg/machinery/imager/quirks/quirks.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package quirks contains the quirks for Talos image generation.\npackage quirks\n\nimport \"github.com/blang/semver/v4\"\n\n// Quirks contains the quirks for Talos image generation.\ntype Quirks struct {\n\tv *semver.Version\n}\n\n// New returns a new Quirks instance based on Talos version for the image.\nfunc New(talosVersion string) Quirks {\n\tv, err := semver.ParseTolerant(talosVersion) // ignore the error\n\tif err != nil {\n\t\treturn Quirks{}\n\t}\n\n\t// we only care about major, minor, and patch, so that alpha, beta, etc. are ignored\n\treturn Quirks{v: &semver.Version{\n\t\tMajor: v.Major,\n\t\tMinor: v.Minor,\n\t\tPatch: v.Patch,\n\t}}\n}\n\n// Version returns the Talos version.\nfunc (q Quirks) Version() *semver.Version {\n\treturn q.v\n}\n\nvar minVersionResetOption = semver.MustParse(\"1.4.0\")\n\n// SupportsResetGRUBOption returns true if the Talos version supports the reset option in GRUB menu (image and ISO).\nfunc (q Quirks) SupportsResetGRUBOption() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionResetOption)\n}\n\nvar minVersionUKI = semver.MustParse(\"1.5.0\")\n\n// SupportsUKI returns true if the Talos version supports building UKIs.\nfunc (q Quirks) SupportsUKI() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionUKI)\n}\n\nvar minVersionCompressedMETA = semver.MustParse(\"1.6.3\")\n\n// SupportsCompressedEncodedMETA returns true if the Talos version supports compressed and encoded META as an environment variable.\nfunc (q Quirks) SupportsCompressedEncodedMETA() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionCompressedMETA)\n}\n\nvar minVersionOverlay = semver.MustParse(\"1.7.0\")\n\n// SupportsOverlay returns true if the Talos imager version supports overlay.\nfunc (q Quirks) SupportsOverlay() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionOverlay)\n}\n\nvar minVersionZstd = semver.MustParse(\"1.8.0\")\n\n// UseZSTDCompression returns true if the Talos should use zstd compression in place of xz.\nfunc (q Quirks) UseZSTDCompression() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionZstd)\n}\n\nvar minVersionISOLabel = semver.MustParse(\"1.8.0\")\n\n// SupportsISOLabel returns true if the Talos version supports setting the ISO label.\nfunc (q Quirks) SupportsISOLabel() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionISOLabel)\n}\n\nvar minVersionMultidoc = semver.MustParse(\"1.5.0\")\n\n// SupportsMultidoc returns true if the Talos version supports multidoc machine configs.\nfunc (q Quirks) SupportsMultidoc() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionMultidoc)\n}\n\n// maxVersionMetalPlatformConsoleTTYS0Dropped is the version that dropped console=ttyS0 for metal image.\nvar maxVersionMetalPlatformConsoleTTYS0Dropped = semver.MustParse(\"1.8.0\")\n\n// SupportsMetalPlatformConsoleTTYS0 returns true if the Talos version supports already has console=ttyS0 kernel argument.\nfunc (q Quirks) SupportsMetalPlatformConsoleTTYS0() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn false\n\t}\n\n\treturn q.v.LT(maxVersionMetalPlatformConsoleTTYS0Dropped)\n}\n\n// minVersionSupportsHalfIfInstalled is the version that supports half if installed.\nvar minVersionSupportsHalfIfInstalled = semver.MustParse(\"1.8.0\")\n\n// SupportsHaltIfInstalled returns true if the Talos version supports half if installed.\nfunc (q Quirks) SupportsHaltIfInstalled() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionSupportsHalfIfInstalled)\n}\n\nvar minVersionSkipDataPartitions = semver.MustParse(\"1.8.0\")\n\n// SkipDataPartitions returns true if the Talos version supports creating EPHEMERAL/STATE partitions on its own.\nfunc (q Quirks) SkipDataPartitions() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionSkipDataPartitions)\n}\n\n// minVersionSELinux is the version that enabled SELinux and added respective parameters.\nvar minVersionSELinux = semver.MustParse(\"1.10.0\")\n\n// SupportsSELinux returns true if the Talos version enables selinux=1 by default.\nfunc (q Quirks) SupportsSELinux() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minVersionSELinux)\n}\n\n// minVersionUseSDBootOnly is the version that supports only SDBoot for UEFI.\nvar minTalosVersionUseSDBootOnly = semver.MustParse(\"1.10.0\")\n\n// UseSDBootForUEFI returns true if the Talos version supports only SDBoot for UEFI.\nfunc (q Quirks) UseSDBootForUEFI() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn false\n\t}\n\n\treturn q.v.GTE(minTalosVersionUseSDBootOnly)\n}\n\n// minTalosVersionUsrMerge is the version that has /lib and /bin symlinked into /usr.\nvar minTalosVersionUsrMerge = semver.MustParse(\"1.10.0\")\n\n// KernelModulesPath returns kernel module storage path for the given Talos version.\nfunc (q Quirks) KernelModulesPath() string {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil || q.v.GTE(minTalosVersionUsrMerge) {\n\t\treturn \"/usr/lib/modules\"\n\t}\n\n\treturn \"/lib/modules\"\n}\n\n// FirmwarePath returns firmware storage path for the given Talos version.\nfunc (q Quirks) FirmwarePath() string {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil || q.v.GTE(minTalosVersionUsrMerge) {\n\t\treturn \"/usr/lib/firmware\"\n\t}\n\n\treturn \"/lib/firmware\"\n}\n\n// minTalosVersionUKIProfiles is the version that supports UKI profiles.\nvar minTalosVersionUKIProfiles = semver.MustParse(\"1.10.0\")\n\n// SupportsUKIProfiles returns true if the Talos version supports UKI profiles.\nfunc (q Quirks) SupportsUKIProfiles() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionUKIProfiles)\n}\n\nvar minTalosVersionUnifiedInstaller = semver.MustParse(\"1.10.0\")\n\n// SupportsUnifiedInstaller returns true if the Talos version supports unified installer.\nfunc (q Quirks) SupportsUnifiedInstaller() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionUnifiedInstaller)\n}\n\nvar minTalosVersionBoot2G = semver.MustParse(\"1.11.0\")\n\n// PartitionSizes returns partition sizes for the given Talos version.\nfunc (q Quirks) PartitionSizes() PartitionSizes {\n\tbootSize := uint64(2000 * mib) // 2000 MiB\n\n\tif q.v != nil && q.v.LT(minTalosVersionBoot2G) {\n\t\t// legacy size of 1000 MiB\n\t\tbootSize = uint64(1000 * mib)\n\t}\n\n\treturn PartitionSizes{\n\t\tbootSize: bootSize,\n\t}\n}\n\n// XFSMkfsConfig returns the mkfs.xfs config for the given Talos version.\nfunc (q Quirks) XFSMkfsConfig() string {\n\tswitch version := q.v; {\n\t// if the version doesn't parse, we assume it's latest Talos\n\t// update when we have a new LTS config\n\tcase version == nil:\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.18.conf\"\n\t// add new version once we have a new LTS config\n\tcase version.GTE(semver.MustParse(\"1.13.0\")):\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.18.conf\"\n\tcase version.GTE(semver.MustParse(\"1.10.0\")):\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.12.conf\"\n\tcase version.GTE(semver.MustParse(\"1.8.0\")) && version.LT(semver.MustParse(\"1.10.0\")):\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.6.conf\"\n\tcase version.GTE(semver.MustParse(\"1.5.0\")) && version.LT(semver.MustParse(\"1.8.0\")):\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.1.conf\"\n\tdefault:\n\t\treturn \"/usr/share/xfsprogs/mkfs/lts_6.1.conf\"\n\t}\n}\n\nvar maxTalosVersionIMASupported = semver.MustParse(\"1.10.99\")\n\n// SupportsIMA returns true if the Talos version has IMA support.\nfunc (q Quirks) SupportsIMA() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn false\n\t}\n\n\treturn q.v.LTE(maxTalosVersionIMASupported)\n}\n\nvar minTalosVersionEmbeddedConfig = semver.MustParse(\"1.12.0\")\n\n// SupportsEmbeddedConfig returns true if the Talos version supports embedded machine configuration.\nfunc (q Quirks) SupportsEmbeddedConfig() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionEmbeddedConfig)\n}\n\nvar minTalosVersionDisableModSigVerify = semver.MustParse(\"1.12.0\")\n\n// SupportsDisablingModuleSignatureVerification returns true if the Talos version supports disabling module signature verification.\nfunc (q Quirks) SupportsDisablingModuleSignatureVerification() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionDisableModSigVerify)\n}\n\nvar minTalosVersionISOSupportsSettingBootloader = semver.MustParse(\"1.12.0\")\n\n// ISOSupportsSettingBootloader returns true if the Talos version supports setting bootloader for ISO output.\nfunc (q Quirks) ISOSupportsSettingBootloader() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionISOSupportsSettingBootloader)\n}\n\nvar minTalosVersionProcMemOverrideNever = semver.MustParse(\"1.13.0\")\n\n// ProcMemOverrideNever returns true if the Talos version should enforce 'proc_mem.force_override=never'.\nfunc (q Quirks) ProcMemOverrideNever() bool {\n\t// if the version doesn't parse, we assume it's latest Talos\n\tif q.v == nil {\n\t\treturn true\n\t}\n\n\treturn q.v.GTE(minTalosVersionProcMemOverrideNever)\n}\n"
  },
  {
    "path": "pkg/machinery/imager/quirks/quirks_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage quirks_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nfunc TestSupportsResetOption(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tversion:  \"1.5.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.3.7\",\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expected, quirks.New(test.version).SupportsResetGRUBOption())\n\t\t})\n\t}\n}\n\nfunc TestSupportsCompressedEncodedMETA(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tversion:  \"1.6.3\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.7.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.6.2\",\n\t\t\texpected: false,\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expected, quirks.New(test.version).SupportsCompressedEncodedMETA())\n\t\t})\n\t}\n}\n\nfunc TestSupportsOverlay(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tversion:  \"1.6.3\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.7.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.6.2\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.7.0-alpha.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"v1.7.0-alpha.0-75-gff08e2821\",\n\t\t\texpected: true,\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expected, quirks.New(test.version).SupportsOverlay())\n\t\t})\n\t}\n}\n\nfunc TestSupportsZstd(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\texpected bool\n\t}{\n\t\t{\n\t\t\tversion:  \"1.7.3\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.6.2\",\n\t\t\texpected: false,\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.8.0-alpha.0\",\n\t\t\texpected: true,\n\t\t},\n\t\t{\n\t\t\tversion:  \"v1.8.3\",\n\t\t\texpected: true,\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expected, quirks.New(test.version).UseZSTDCompression())\n\t\t})\n\t}\n}\n\nfunc TestXFSMkfsConfigFile(t *testing.T) {\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tversion:  \"1.5.0\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.1.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.6.2\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.1.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.7.0\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.1.conf\",\n\t\t},\n\n\t\t{\n\t\t\tversion:  \"1.8.1\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.6.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.9.3\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.6.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.10.0\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.12.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.12.0\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.12.conf\",\n\t\t},\n\t\t{\n\t\t\tversion:  \"1.13.0\",\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.18.conf\",\n\t\t},\n\t\t{\n\t\t\texpected: \"/usr/share/xfsprogs/mkfs/lts_6.18.conf\",\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tassert.Equal(t, test.expected, quirks.New(test.version).XFSMkfsConfig())\n\t\t})\n\t}\n}\n\nfunc TestPartitionSizes(t *testing.T) {\n\tconst (\n\t\tMiB = 1024 * 1024\n\t\tGiB = 1024 * MiB\n\t)\n\n\tfor _, test := range []struct {\n\t\tversion string\n\n\t\t// expected partition sizes\n\t\tgrubEFISize      uint64\n\t\tgrubBIOSSize     uint64\n\t\tgrubBootSize     uint64\n\t\tukiEFISize       uint64\n\t\tmetaSize         uint64\n\t\tstateSize        uint64\n\t\tephemeralMinSize uint64\n\t}{\n\t\t{\n\t\t\tversion:          \"1.9.0\",\n\t\t\tgrubEFISize:      100 * MiB,\n\t\t\tgrubBIOSSize:     1 * MiB,\n\t\t\tgrubBootSize:     1000 * MiB,\n\t\t\tukiEFISize:       1000*MiB + 100*MiB + 1*MiB,\n\t\t\tmetaSize:         1 * MiB,\n\t\t\tstateSize:        100 * MiB,\n\t\t\tephemeralMinSize: 2 * GiB,\n\t\t},\n\t\t{\n\t\t\tversion:          \"1.10.0\",\n\t\t\tgrubEFISize:      100 * MiB,\n\t\t\tgrubBIOSSize:     1 * MiB,\n\t\t\tgrubBootSize:     1000 * MiB,\n\t\t\tukiEFISize:       1000*MiB + 100*MiB + 1*MiB,\n\t\t\tmetaSize:         1 * MiB,\n\t\t\tstateSize:        100 * MiB,\n\t\t\tephemeralMinSize: 2 * GiB,\n\t\t},\n\t\t{\n\t\t\tversion:          \"1.11.0\",\n\t\t\tgrubEFISize:      100 * MiB,\n\t\t\tgrubBIOSSize:     1 * MiB,\n\t\t\tgrubBootSize:     2000 * MiB,\n\t\t\tukiEFISize:       2000*MiB + 100*MiB + 1*MiB,\n\t\t\tmetaSize:         1 * MiB,\n\t\t\tstateSize:        100 * MiB,\n\t\t\tephemeralMinSize: 2 * GiB,\n\t\t},\n\t\t{\n\t\t\tversion:          \"\",\n\t\t\tgrubEFISize:      100 * MiB,\n\t\t\tgrubBIOSSize:     1 * MiB,\n\t\t\tgrubBootSize:     2000 * MiB,\n\t\t\tukiEFISize:       2000*MiB + 100*MiB + 1*MiB,\n\t\t\tmetaSize:         1 * MiB,\n\t\t\tstateSize:        100 * MiB,\n\t\t\tephemeralMinSize: 2 * GiB,\n\t\t},\n\t} {\n\t\tt.Run(test.version, func(t *testing.T) {\n\t\t\tps := quirks.New(test.version).PartitionSizes()\n\n\t\t\tassert.Equal(t, test.grubEFISize, ps.GrubEFISize())\n\t\t\tassert.Equal(t, test.grubBIOSSize, ps.GrubBIOSSize())\n\t\t\tassert.Equal(t, test.grubBootSize, ps.GrubBootSize())\n\t\t\tassert.Equal(t, test.ukiEFISize, ps.UKIEFISize())\n\t\t\tassert.Equal(t, test.metaSize, ps.METASize())\n\t\t\tassert.Equal(t, test.stateSize, ps.StateSize())\n\t\t\tassert.Equal(t, test.ephemeralMinSize, ps.EphemeralMinSize())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/kernel/kernel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kernel\n\nimport (\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\nconst (\n\t// Sysfs defines prefix for sysfs kernel params.\n\tSysfs = \"sys\"\n\t// Sysctl defines prefix for sysctl kernel params.\n\tSysctl = \"proc.sys\"\n)\n\n// DefaultArgs returns the Talos default kernel commandline options.\nfunc DefaultArgs(quirks quirks.Quirks) []string {\n\tresult := []string{\n\t\t\"init_on_alloc=1\",\n\t\t\"slab_nomerge=\",\n\t\t\"pti=on\",\n\t\t\"consoleblank=0\",\n\t\t// AWS recommends setting the nvme_core.io_timeout to the highest value possible.\n\t\t// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html.\n\t\t\"nvme_core.io_timeout=4294967295\",\n\t\t// Disable rate limited printk\n\t\t\"printk.devkmsg=on\",\n\t}\n\n\tif quirks.SupportsIMA() {\n\t\t// Enable IMAs for integrity measurement\n\t\tresult = append(\n\t\t\tresult,\n\t\t\t\"ima_template=ima-ng\",\n\t\t\t\"ima_appraise=fix\",\n\t\t\t\"ima_hash=sha512\",\n\t\t)\n\t}\n\n\tif quirks.SupportsSELinux() {\n\t\tresult = append(result, constants.KernelParamSELinux+\"=1\")\n\t}\n\n\tif quirks.SupportsDisablingModuleSignatureVerification() {\n\t\tresult = append(result, constants.KernelParamEnforceModuleSigVerify+\"=1\") // see https://github.com/siderolabs/talos/issues/11989\n\t}\n\n\tif quirks.ProcMemOverrideNever() {\n\t\tresult = append(result, \"proc_mem.force_override=never\")\n\t}\n\n\treturn result\n}\n\n// SecureBootArgs returns the kernel commandline options required for secure boot.\nfunc SecureBootArgs(quirks.Quirks) []string {\n\treturn []string{\n\t\t\"lockdown=confidentiality\",\n\t}\n}\n\n// Param represents a kernel system property.\ntype Param struct {\n\tKey   string\n\tValue string\n}\n\n// Path returns the path to the systctl file under /proc/sys or /sys.\nfunc (prop *Param) Path() string {\n\t// From: https://man7.org/linux/man-pages/man5/sysctl.d.5.html\n\t//\n\t// Note that either \"/\" or \".\"  may be used as separators within\n\t// sysctl variable names. If the first separator is a slash,\n\t// remaining slashes and dots are left intact. If the first\n\t// separator is a dot, dots and slashes are interchanged.\n\t// \"kernel.domainname=foo\" and \"kernel/domainname=foo\" are\n\t// equivalent and will cause \"foo\" to be written to\n\t// /proc/sys/kernel/domainname. Either\n\t// \"net.ipv4.conf.enp3s0/200.forwarding\" or\n\t// \"net/ipv4/conf/enp3s0.200/forwarding\" may be used to refer to\n\t// /proc/sys/net/ipv4/conf/enp3s0.200/forwarding\n\t//\n\t// detect the first separator, either '.' or '/'\n\t// according to the sysctl man page, if the first separator is '/', we keep slashes intact,\n\t// otherwise we convert dots to slashes\n\tkeyPath := prop.Key\n\tprefix := \"\"\n\n\t// trim standard prefix\n\tfor _, stdPrefix := range []string{Sysctl, Sysfs} {\n\t\tif strings.HasPrefix(prop.Key, stdPrefix+\".\") {\n\t\t\tkeyPath = keyPath[len(stdPrefix)+1:]\n\t\t\tprefix = stdPrefix\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tfirstSepIndex := strings.IndexAny(keyPath, \"./\")\n\t// if the first separator is a dot, remap '.' to '/', and '/' to '.'\n\tif firstSepIndex != -1 && keyPath[firstSepIndex] == '.' {\n\t\tkeyPath = strings.Map(\n\t\t\tfunc(r rune) rune {\n\t\t\t\tswitch r {\n\t\t\t\tcase '.':\n\t\t\t\t\treturn '/'\n\t\t\t\tcase '/':\n\t\t\t\t\treturn '.'\n\t\t\t\tdefault:\n\t\t\t\t\treturn r\n\t\t\t\t}\n\t\t\t},\n\t\t\tkeyPath,\n\t\t)\n\t}\n\n\treturn path.Clean(\"/\" + filepath.Join(strings.ReplaceAll(prefix, \".\", \"/\"), keyPath))\n}\n"
  },
  {
    "path": "pkg/machinery/kernel/kernel_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kernel_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n)\n\nfunc TestParamPath(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname  string\n\t\tparam *kernel.Param\n\t\twant  string\n\t}{\n\t\t{\n\t\t\tname: \"Test Sysfs Path\",\n\t\t\tparam: &kernel.Param{\n\t\t\t\tKey: kernel.Sysfs + \".block.sda.queue.scheduler\",\n\t\t\t},\n\t\t\twant: \"/sys/block/sda/queue/scheduler\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test Sysctl Path\",\n\t\t\tparam: &kernel.Param{\n\t\t\t\tKey: kernel.Sysctl + \".net.ipv6.conf.eth0.accept_ra\",\n\t\t\t},\n\t\t\twant: \"/proc/sys/net/ipv6/conf/eth0/accept_ra\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test Sysctl Path with vlan interface untouched\",\n\t\t\tparam: &kernel.Param{\n\t\t\t\tKey: kernel.Sysctl + \".net/ipv6/conf/eth0.103/disable_ipv6\",\n\t\t\t},\n\t\t\twant: \"/proc/sys/net/ipv6/conf/eth0.103/disable_ipv6\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test Sysctl Path with vlan interface inverted\",\n\t\t\tparam: &kernel.Param{\n\t\t\t\tKey: kernel.Sysctl + \".net.ipv6.conf.eth0/103.disable_ipv6\",\n\t\t\t},\n\t\t\twant: \"/proc/sys/net/ipv6/conf/eth0.103/disable_ipv6\",\n\t\t},\n\t\t{\n\t\t\tname: \"Test Sysctl Path with invalid symbols which translate to '..'\",\n\t\t\tparam: &kernel.Param{\n\t\t\t\tKey: kernel.Sysctl + \".net.ipv6.conf.eth0/103.//.disable_ipv6\",\n\t\t\t},\n\t\t\twant: \"/proc/sys/net/ipv6/conf/disable_ipv6\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tif got := tt.param.Path(); got != tt.want {\n\t\t\t\tt.Errorf(\"Param.Path() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDefaultKernelArgs(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tquirks quirks.Quirks\n\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"latest\",\n\n\t\t\texpected: []string{\n\t\t\t\t\"init_on_alloc=1\",\n\t\t\t\t\"slab_nomerge=\",\n\t\t\t\t\"pti=on\",\n\t\t\t\t\"consoleblank=0\",\n\t\t\t\t\"nvme_core.io_timeout=4294967295\",\n\t\t\t\t\"printk.devkmsg=on\",\n\t\t\t\t\"selinux=1\",\n\t\t\t\t\"module.sig_enforce=1\",\n\t\t\t\t\"proc_mem.force_override=never\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"v1.9\",\n\n\t\t\tquirks: quirks.New(\"v1.9.0\"),\n\n\t\t\texpected: []string{\n\t\t\t\t\"init_on_alloc=1\",\n\t\t\t\t\"slab_nomerge=\",\n\t\t\t\t\"pti=on\",\n\t\t\t\t\"consoleblank=0\",\n\t\t\t\t\"nvme_core.io_timeout=4294967295\",\n\t\t\t\t\"printk.devkmsg=on\",\n\t\t\t\t\"ima_template=ima-ng\",\n\t\t\t\t\"ima_appraise=fix\",\n\t\t\t\t\"ima_hash=sha512\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"v1.12\",\n\n\t\t\tquirks: quirks.New(\"v1.12.0\"),\n\n\t\t\texpected: []string{\n\t\t\t\t\"init_on_alloc=1\",\n\t\t\t\t\"slab_nomerge=\",\n\t\t\t\t\"pti=on\",\n\t\t\t\t\"consoleblank=0\",\n\t\t\t\t\"nvme_core.io_timeout=4294967295\",\n\t\t\t\t\"printk.devkmsg=on\",\n\t\t\t\t\"selinux=1\",\n\t\t\t\t\"module.sig_enforce=1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"v1.13\",\n\n\t\t\tquirks: quirks.New(\"v1.13.0\"),\n\n\t\t\texpected: []string{\n\t\t\t\t\"init_on_alloc=1\",\n\t\t\t\t\"slab_nomerge=\",\n\t\t\t\t\"pti=on\",\n\t\t\t\t\"consoleblank=0\",\n\t\t\t\t\"nvme_core.io_timeout=4294967295\",\n\t\t\t\t\"printk.devkmsg=on\",\n\t\t\t\t\"selinux=1\",\n\t\t\t\t\"module.sig_enforce=1\",\n\t\t\t\t\"proc_mem.force_override=never\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expected, kernel.DefaultArgs(test.quirks))\n\t\t})\n\t}\n}\n\nfunc TestSecureBootArgs(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tquirks quirks.Quirks\n\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"latest\",\n\n\t\t\texpected: []string{\n\t\t\t\t\"lockdown=confidentiality\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expected, kernel.SecureBootArgs(test.quirks))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/kubelet/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubelet defines Talos interface for the kubelet.\npackage kubelet\n\n// ProtectedConfigurationFields is a list of kubelet config fields that can't be overridden\n// with the machine configuration.\nvar ProtectedConfigurationFields = []string{\n\t\"apiVersion\",\n\t\"authentication\",\n\t\"authorization\",\n\t\"cgroupRoot\",\n\t\"kind\",\n\t\"kubeletCgroups\",\n\t\"port\",\n\t\"protectKernelDefaults\",\n\t\"resolvConf\",\n\t\"rotateCertificates\",\n\t\"systemCgroups\",\n\t\"staticPodPath\",\n\t\"seccompDefault\",\n}\n"
  },
  {
    "path": "pkg/machinery/labels/validate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package labels contains adapter label validation functions from Kubernetes.\n//\n// We want to avoid dependency of machinery on Kubernetes packages.\npackage labels\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/siderolabs/gen/maps\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// Validate validates that a set of labels are correctly defined.\nfunc Validate(labels map[string]string) error {\n\tvar multiErr *multierror.Error\n\n\tkeys := maps.Keys(labels)\n\tslices.Sort(keys)\n\n\tfor _, k := range keys {\n\t\tif err := ValidateQualifiedName(k); err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t}\n\n\t\tif err := ValidateLabelValue(labels[k]); err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t}\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// TotalAnnotationSizeLimitB is the maximum size of all annotations in bytes.\nconst TotalAnnotationSizeLimitB int64 = 256 * (1 << 10) // 256 kB\n\n// ValidateAnnotations validates that a set of annotations are correctly defined.\nfunc ValidateAnnotations(annotations map[string]string) error {\n\tvar multiErr *multierror.Error\n\n\tkeys := maps.Keys(annotations)\n\tslices.Sort(keys)\n\n\tvar size int64\n\n\tfor _, k := range keys {\n\t\tif err := ValidateQualifiedName(k); err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\t\t}\n\n\t\tswitch k {\n\t\tcase constants.AnnotationOwnedAnnotations, constants.AnnotationOwnedLabels, constants.AnnotationOwnedTaints:\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"annotation %q is reserved\", k))\n\t\t}\n\n\t\tsize += int64(len(k)) + int64(len(annotations[k]))\n\t}\n\n\tif size > TotalAnnotationSizeLimitB {\n\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"total annotation size exceeds limit of %d bytes\", TotalAnnotationSizeLimitB))\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\nconst (\n\tdns1123LabelFmt           string = \"[a-z0-9]([-a-z0-9]*[a-z0-9])?\"\n\tdns1123SubdomainFmt       string = dns1123LabelFmt + \"(\\\\.\" + dns1123LabelFmt + \")*\"\n\tdns1123SubdomainMaxLength int    = 253\n)\n\nvar dns1123SubdomainRegexp = regexp.MustCompile(\"^\" + dns1123SubdomainFmt + \"$\")\n\n// ValidateDNS1123Subdomain tests for a string that conforms to the definition of a\n// subdomain in DNS (RFC 1123).\nfunc ValidateDNS1123Subdomain(value string) error {\n\tif len(value) > dns1123SubdomainMaxLength {\n\t\treturn fmt.Errorf(\"domain name length exceeds limit of %d: %q\", dns1123SubdomainMaxLength, value)\n\t}\n\n\tif !dns1123SubdomainRegexp.MatchString(value) {\n\t\treturn fmt.Errorf(\"domain doesn't match required format: %q\", value)\n\t}\n\n\treturn nil\n}\n\nconst (\n\tqnameCharFmt           string = \"[A-Za-z0-9]\"\n\tqnameExtCharFmt        string = \"[-A-Za-z0-9_.]\"\n\tqualifiedNameFmt       string = \"(\" + qnameCharFmt + qnameExtCharFmt + \"*)?\" + qnameCharFmt\n\tqualifiedNameMaxLength int    = 63\n)\n\nvar qualifiedNameRegexp = regexp.MustCompile(\"^\" + qualifiedNameFmt + \"$\")\n\n// ValidateQualifiedName tests whether the value passed is what Kubernetes calls a\n// \"qualified name\".\n//\n// This is a format used in various places throughout the\n// system.  If the value is not valid, a list of error strings is returned.\n// Otherwise an empty list (or nil) is returned.\nfunc ValidateQualifiedName(value string) error {\n\tparts := strings.Split(value, \"/\")\n\n\tvar name string\n\n\tswitch len(parts) {\n\tcase 1:\n\t\tname = parts[0]\n\tcase 2:\n\t\tvar prefix string\n\n\t\tprefix, name = parts[0], parts[1]\n\n\t\tif len(prefix) == 0 {\n\t\t\treturn fmt.Errorf(\"prefix cannot be empty: %q\", value)\n\t\t} else if err := ValidateDNS1123Subdomain(prefix); err != nil {\n\t\t\treturn fmt.Errorf(\"prefix %q is invalid: %v\", prefix, err)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid format: too many slashes: %q\", value)\n\t}\n\n\tswitch {\n\tcase len(name) == 0:\n\t\treturn fmt.Errorf(\"name cannot be empty: %q\", value)\n\tcase len(name) > qualifiedNameMaxLength:\n\t\treturn fmt.Errorf(\"name is too long: %q (limit is %d)\", value, qualifiedNameMaxLength)\n\tcase !qualifiedNameRegexp.MatchString(name):\n\t\treturn fmt.Errorf(\"name %q is invalid\", name)\n\t}\n\n\treturn nil\n}\n\nconst (\n\tlabelValueFmt       string = \"(\" + qualifiedNameFmt + \")?\"\n\tlabelValueMaxLength int    = 63\n)\n\nvar labelValueRegexp = regexp.MustCompile(\"^\" + labelValueFmt + \"$\")\n\n// ValidateLabelValue tests whether the value passed is a valid label value.\n//\n// If the value is not valid, a list of error strings is returned.\n// Otherwise an empty list (or nil) is returned.\nfunc ValidateLabelValue(value string) error {\n\tif len(value) > labelValueMaxLength {\n\t\treturn fmt.Errorf(\"label value length exceeds limit of %d: %q\", labelValueMaxLength, value)\n\t}\n\n\tif !labelValueRegexp.MatchString(value) {\n\t\treturn fmt.Errorf(\"label value %q is invalid\", value)\n\t}\n\n\treturn nil\n}\n\n// ValidateTaints validates that a set of taints is correctly defined.\nfunc ValidateTaints(taints map[string]string) error {\n\tvar multiErr *multierror.Error\n\n\tkeys := maps.Keys(taints)\n\tslices.Sort(keys)\n\n\tfor _, k := range keys {\n\t\tif err := ValidateQualifiedName(k); err != nil {\n\t\t\tmultiErr = multierror.Append(multiErr, err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tval, effect, found := strings.Cut(taints[k], \":\")\n\t\tif !found {\n\t\t\teffect = val\n\t\t}\n\n\t\t// validate that the taint has a valid effect, which is required to add the taint\n\t\tif !slices.Contains(constants.ValidEffects, effect) {\n\t\t\tmultiErr = multierror.Append(multiErr, fmt.Errorf(\"invalid taint effect: %q\", effect))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif found {\n\t\t\tif err := ValidateLabelValue(val); err != nil {\n\t\t\t\tmultiErr = multierror.Append(multiErr, err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n"
  },
  {
    "path": "pkg/machinery/labels/validate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage labels_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/labels\"\n)\n\nfunc TestValidate(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tlabels map[string]string\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tlabels: map[string]string{\n\t\t\t\t\"talos.dev/label\":        \"value\",\n\t\t\t\t\"foo\":                    \"bar\",\n\t\t\t\t\"kubernetes.io/hostname\": \"hostname1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tlabels: map[string]string{\n\t\t\t\t\"345@.345/label\":         \"value\",\n\t\t\t\t\"foo_\":                   \"bar\",\n\t\t\t\t\"/foo\":                   \"bar\",\n\t\t\t\t\"a/b/c\":                  \"bar\",\n\t\t\t\t\"kubernetes.io/hostname\": \"hostname1_\",\n\t\t\t\tstrings.Repeat(\"a\", 64):  \"bar\",\n\t\t\t\t\"bar\":                    strings.Repeat(\"a\", 64),\n\t\t\t},\n\t\t\texpectedError: \"7 errors occurred:\\n\\t* prefix cannot be empty: \\\"/foo\\\"\\n\\t* prefix \\\"345@.345\\\" is invalid: domain doesn't match required format: \\\"345@.345\\\"\\n\\t* invalid format: too many slashes: \\\"a/b/c\\\"\\n\\t* name is too long: \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\" (limit is 63)\\n\\t* label value length exceeds limit of 63: \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"\\n\\t* name \\\"foo_\\\" is invalid\\n\\t* label value \\\"hostname1_\\\" is invalid\\n\\n\", //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := labels.Validate(tt.labels)\n\t\t\tif tt.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, tt.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestValidateAnnotations(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tannotations map[string]string\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\tannotations: map[string]string{\n\t\t\t\t\"talos.dev/ann1\":     \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\",\n\t\t\t\t\"foo\":                \"bar\",\n\t\t\t\t\"kubernetes.io/rack\": \"rack2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\tannotations: map[string]string{\n\t\t\t\t\"foo_\":                               \"bar\",\n\t\t\t\t\"/foo\":                               \"bar\",\n\t\t\t\t\"a/b/c\":                              \"bar\",\n\t\t\t\t\"kubernetes.io/hostname\":             \"hostname1_\",\n\t\t\t\tconstants.AnnotationOwnedAnnotations: \"a\",\n\t\t\t},\n\t\t\texpectedError: \"4 errors occurred:\\n\\t* prefix cannot be empty: \\\"/foo\\\"\\n\\t* invalid format: too many slashes: \\\"a/b/c\\\"\\n\\t* name \\\"foo_\\\" is invalid\\n\\t* annotation \\\"talos.dev/owned-annotations\\\" is reserved\\n\\n\", //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := labels.ValidateAnnotations(tt.annotations)\n\t\t\tif tt.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, tt.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestValidateTaints(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\ttaints map[string]string\n\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t},\n\t\t{\n\t\t\tname: \"valid\",\n\t\t\ttaints: map[string]string{\n\t\t\t\t\"foor\": \"bar:NoExecute\",\n\t\t\t\t\"doo\":  \"NoExecute\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid\",\n\t\t\ttaints: map[string]string{\n\t\t\t\tstrings.Repeat(\"a\", 64): \"bar\",\n\t\t\t\t\"bar\":                   strings.Repeat(\"a\", 64),\n\t\t\t\t\"foo\":                   \"bar:NoExecute:NoSchedule\",\n\t\t\t\t\"loo\":                   \"bar:\",\n\t\t\t\t\"zoo\":                   \"bar:NoExocute\",\n\t\t\t\t\"koo\":                   \"key\",\n\t\t\t},\n\t\t\texpectedError: \"6 errors occurred:\\n\\t* name is too long: \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\" (limit is 63)\\n\\t* invalid taint effect: \\\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\"\\n\\t* invalid taint effect: \\\"NoExecute:NoSchedule\\\"\\n\\t* invalid taint effect: \\\"key\\\"\\n\\t* invalid taint effect: \\\"\\\"\\n\\t* invalid taint effect: \\\"NoExocute\\\"\\n\\n\", //nolint:lll\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\terr := labels.ValidateTaints(tt.taints)\n\t\t\tif tt.expectedError != \"\" {\n\t\t\t\tassert.EqualError(t, err, tt.expectedError)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/meta/constants.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage meta\n\nconst (\n\t// Upgrade is the upgrade tag.\n\tUpgrade = iota + 6\n\t// StagedUpgradeImageRef stores image reference for staged upgrade.\n\tStagedUpgradeImageRef\n\t// StagedUpgradeInstallOptions stores JSON-serialized install.Options.\n\tStagedUpgradeInstallOptions\n\t// StateEncryptionConfig stores JSON-serialized v1alpha1.Encryption.\n\tStateEncryptionConfig\n\t// MetalNetworkPlatformConfig stores serialized NetworkPlatformConfig for the `metal` platform.\n\tMetalNetworkPlatformConfig\n\t// DownloadURLCode stores the value of the `${code}` variable in the download URL for talos.config= URL.\n\tDownloadURLCode\n\t// UserReserved1 is reserved for user-defined metadata.\n\tUserReserved1\n\t// UserReserved2 is reserved for user-defined metadata.\n\tUserReserved2\n\t// UserReserved3 is reserved for user-defined metadata.\n\tUserReserved3\n\t// UUIDOverride stores the UUID that this machine will use instead of the one from the hardware.\n\tUUIDOverride\n\t// UniqueMachineToken store the unique token for this machine. It's useful because UUID may repeat or be filled with zeros.\n\tUniqueMachineToken\n\t// DiskImageBootloader stores the bootloader used for the disk image, this key is wiped on first boot.\n\tDiskImageBootloader\n)\n"
  },
  {
    "path": "pkg/machinery/meta/meta.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package meta provides interfaces for encoding and decoding META values.\npackage meta\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n)\n\n// Value represents a key/value pair for META.\ntype Value struct {\n\tKey   uint8\n\tValue string\n}\n\nfunc (v Value) String() string {\n\treturn fmt.Sprintf(\"0x%x=%s\", v.Key, v.Value)\n}\n\n// Parse k=v expression.\nfunc (v *Value) Parse(s string) error {\n\tk, vv, ok := strings.Cut(s, \"=\")\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid value %q\", s)\n\t}\n\n\tkey, err := strconv.ParseUint(k, 0, 8)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid key %q\", k)\n\t}\n\n\tv.Key = uint8(key)\n\tv.Value = vv\n\n\treturn nil\n}\n\n// Values is a collection of Value.\ntype Values []Value\n\n// Encode returns a string representation of Values for the environment variable.\n//\n// Each Value is encoded a k=v, split by ';' character.\n// The result is base64 encoded.\nfunc (v Values) Encode(allowGzip bool) string {\n\traw := []byte(strings.Join(xslices.Map(v, Value.String), \";\"))\n\n\tif allowGzip && len(raw) > 256 {\n\t\tvar buf bytes.Buffer\n\n\t\tgzW, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tif _, err := gzW.Write(raw); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tif err := gzW.Close(); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\traw = buf.Bytes()\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(raw)\n}\n\n// DecodeValues parses a string representation of Values for the environment variable.\n//\n// See Encode for the details of the encoding.\nfunc DecodeValues(s string) (Values, error) {\n\tb, err := base64.StdEncoding.DecodeString(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(b) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// do un-gzip if needed\n\tif hasGzipMagic(b) {\n\t\tgzR, err := gzip.NewReader(bytes.NewReader(b))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdefer gzR.Close() //nolint:errcheck\n\n\t\tb, err = io.ReadAll(gzR)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := gzR.Close(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tparts := strings.Split(string(b), \";\")\n\n\tresult := make(Values, 0, len(parts))\n\n\tfor _, v := range parts {\n\t\tvar vv Value\n\n\t\tif err := vv.Parse(v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tresult = append(result, vv)\n\t}\n\n\treturn result, nil\n}\n\nfunc hasGzipMagic(b []byte) bool {\n\tif len(b) < 10 {\n\t\treturn false\n\t}\n\n\t// See https://en.wikipedia.org/wiki/Gzip#File_format.\n\treturn b[0] == 0x1f && b[1] == 0x8b\n}\n"
  },
  {
    "path": "pkg/machinery/meta/meta_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage meta_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/meta\"\n)\n\nfunc TestValue(t *testing.T) {\n\tt.Parallel()\n\n\tvar v meta.Value\n\n\trequire.NoError(t, v.Parse(\"10=foo\"))\n\n\tassert.Equal(t, uint8(10), v.Key)\n\tassert.Equal(t, \"foo\", v.Value)\n\n\tassert.Equal(t, \"0xa=foo\", v.String())\n\n\tvar v2 meta.Value\n\n\trequire.NoError(t, v2.Parse(v.String()))\n\n\tassert.Equal(t, v, v2)\n}\n\nfunc TestEncodeDecodeValues(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, allowGzip := range []bool{false, true} {\n\t\tt.Run(fmt.Sprintf(\"allowGzip=%v\", allowGzip), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tfor _, test := range []struct {\n\t\t\t\tname string\n\n\t\t\t\tvalues []string\n\n\t\t\t\texpectedEncodedSize int\n\t\t\t\texpectedGzippedSize int\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\tname: \"empty\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"simple\",\n\t\t\t\t\tvalues: []string{\n\t\t\t\t\t\t\"10=foo\",\n\t\t\t\t\t\t\"0xb=bar\",\n\t\t\t\t\t},\n\n\t\t\t\t\texpectedEncodedSize: 20,\n\t\t\t\t\texpectedGzippedSize: 20,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"huge\",\n\t\t\t\t\tvalues: []string{\n\t\t\t\t\t\t\"10=\" + strings.Repeat(\"foobar\", 256),\n\t\t\t\t\t\t\"0xb=\" + strings.Repeat(\"baz\", 256),\n\t\t\t\t\t},\n\n\t\t\t\t\texpectedEncodedSize: 3084,\n\t\t\t\t\texpectedGzippedSize: 80,\n\t\t\t\t},\n\t\t\t} {\n\t\t\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\n\t\t\t\t\tvalues := make(meta.Values, len(test.values))\n\n\t\t\t\t\tfor i, v := range test.values {\n\t\t\t\t\t\trequire.NoError(t, values[i].Parse(v))\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(values) == 0 {\n\t\t\t\t\t\tvalues = nil\n\t\t\t\t\t}\n\n\t\t\t\t\tencoded := values.Encode(allowGzip)\n\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase test.expectedEncodedSize > 0 && !allowGzip:\n\t\t\t\t\t\tassert.Equal(t, test.expectedEncodedSize, len(encoded))\n\t\t\t\t\tcase test.expectedGzippedSize > 0 && allowGzip:\n\t\t\t\t\t\tassert.Equal(t, test.expectedGzippedSize, len(encoded))\n\t\t\t\t\t}\n\n\t\t\t\t\tdecoded, err := meta.DecodeValues(encoded)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tassert.Equal(t, values, decoded)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/address_flags.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"strings\"\n)\n\n// AddressFlags is a bitmask of AddressFlag.\ntype AddressFlags uint32\n\nfunc (flags AddressFlags) String() string {\n\tvar values []string\n\n\tfor flag := AddressTemporary; flag <= AddressStablePrivacy; flag <<= 1 {\n\t\tif (AddressFlag(flags) & flag) == flag {\n\t\t\tvalues = append(values, flag.String())\n\t\t}\n\t}\n\n\treturn strings.Join(values, \",\")\n}\n\n// AddressFlagsString converts string representation of flags into AddressFlags.\nfunc AddressFlagsString(s string) (AddressFlags, error) {\n\tflags := AddressFlags(0)\n\n\tfor p := range strings.SplitSeq(s, \",\") {\n\t\tflag, err := AddressFlagString(p)\n\t\tif err != nil {\n\t\t\treturn flags, err\n\t\t}\n\n\t\tflags |= AddressFlags(flag)\n\t}\n\n\treturn flags, nil\n}\n\n// MarshalText implements text.Marshaler.\nfunc (flags AddressFlags) MarshalText() ([]byte, error) {\n\treturn []byte(flags.String()), nil\n}\n\n// UnmarshalText implements text.Unmarshaler.\nfunc (flags *AddressFlags) UnmarshalText(b []byte) error {\n\tvar err error\n\n\t*flags, err = AddressFlagsString(string(b))\n\n\treturn err\n}\n\n// AddressFlag wraps IFF_* constants.\ntype AddressFlag uint32\n\n// AddressFlag constants.\n//\n//structprotogen:gen_enum\nconst (\n\tAddressTemporary      AddressFlag = 1 << iota // temporary\n\tAddressNoDAD                                  // nodad\n\tAddressOptimistic                             // optimistic\n\tAddressDADFailed                              // dadfailed\n\tAddressHome                                   // homeaddress\n\tAddressDeprecated                             // deprecated\n\tAddressTentative                              // tentative\n\tAddressPermanent                              // permanent\n\tAddressManagementTemp                         // mngmtmpaddr\n\tAddressNoPrefixRoute                          // noprefixroute\n\tAddressMCAutoJoin                             // mcautojoin\n\tAddressStablePrivacy                          // stableprivacy\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/addresssortalgorithm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// AddressSortAlgorithm is an internal address sorting algorithm.\ntype AddressSortAlgorithm int\n\n// AddressSortAlgorithm constants.\n//\n//structprotogen:gen_enum\nconst (\n\tAddressSortAlgorithmV1 AddressSortAlgorithm = iota // v1\n\tAddressSortAlgorithmV2                             // v2\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/adlacpactive.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// ADLACPActive is ADLACPActive.\ntype ADLACPActive uint8\n\n// ADLACPActive constants.\n//\n//structprotogen:gen_enum\nconst (\n\tADLACPActiveOff ADLACPActive = iota // off\n\tADLACPActiveOn                      // on\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/adselect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// ADSelect is ADSelect.\ntype ADSelect uint8\n\n// ADSelect constants.\n//\n//structprotogen:gen_enum\nconst (\n\tADSelectStable    ADSelect = iota // stable\n\tADSelectBandwidth                 // bandwidth\n\tADSelectCount                     // count\n)\n\n// ADSelectByName parses ADSelect.\nfunc ADSelectByName(sel string) (ADSelect, error) {\n\tswitch sel {\n\tcase \"\", \"stable\":\n\t\treturn ADSelectStable, nil\n\tcase \"bandwidth\":\n\t\treturn ADSelectBandwidth, nil\n\tcase \"count\":\n\t\treturn ADSelectCount, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid ad_select mode %v\", sel)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/arpalltargets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// ARPAllTargets is an ARP targets mode.\ntype ARPAllTargets uint32\n\n// ARPAllTargets constants.\n//\n//structprotogen:gen_enum\nconst (\n\tARPAllTargetsAny ARPAllTargets = iota // any\n\tARPAllTargetsAll                      // all\n)\n\n// ARPAllTargetsByName parses ARPAllTargets.\nfunc ARPAllTargetsByName(a string) (ARPAllTargets, error) {\n\tswitch a {\n\tcase \"\", \"any\":\n\t\treturn ARPAllTargetsAny, nil\n\tcase \"all\":\n\t\treturn ARPAllTargetsAll, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid arp_all_targets mode %v\", a)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/arpalltargets_enumer.go",
    "content": "// Code generated by \"enumer -type=ARPAllTargets,ARPValidate,AddressFlag,AddressSortAlgorithm,ADSelect,ADLACPActive,AutoHostnameKind,BondMode,BondXmitHashPolicy,ClientIdentifier,ConntrackState,DefaultAction,Duplex,Family,LACPRate,LinkFlag,LinkType,MatchOperator,NfTablesChainHook,NfTablesChainPriority,NfTablesVerdict,OperationalState,Port,PrimaryReselect,Protocol,RouteFlag,RouteProtocol,RouteType,RoutingRuleAction,RoutingTable,Scope,Status,VLANProtocol,WOLMode -linecomment -text\"; DO NOT EDIT.\n\npackage nethelpers\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _ARPAllTargetsName = \"anyall\"\n\nvar _ARPAllTargetsIndex = [...]uint8{0, 3, 6}\n\nconst _ARPAllTargetsLowerName = \"anyall\"\n\nfunc (i ARPAllTargets) String() string {\n\tif i >= ARPAllTargets(len(_ARPAllTargetsIndex)-1) {\n\t\treturn fmt.Sprintf(\"ARPAllTargets(%d)\", i)\n\t}\n\treturn _ARPAllTargetsName[_ARPAllTargetsIndex[i]:_ARPAllTargetsIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ARPAllTargetsNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ARPAllTargetsAny-(0)]\n\t_ = x[ARPAllTargetsAll-(1)]\n}\n\nvar _ARPAllTargetsValues = []ARPAllTargets{ARPAllTargetsAny, ARPAllTargetsAll}\n\nvar _ARPAllTargetsNameToValueMap = map[string]ARPAllTargets{\n\t_ARPAllTargetsName[0:3]:      ARPAllTargetsAny,\n\t_ARPAllTargetsLowerName[0:3]: ARPAllTargetsAny,\n\t_ARPAllTargetsName[3:6]:      ARPAllTargetsAll,\n\t_ARPAllTargetsLowerName[3:6]: ARPAllTargetsAll,\n}\n\nvar _ARPAllTargetsNames = []string{\n\t_ARPAllTargetsName[0:3],\n\t_ARPAllTargetsName[3:6],\n}\n\n// ARPAllTargetsString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ARPAllTargetsString(s string) (ARPAllTargets, error) {\n\tif val, ok := _ARPAllTargetsNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ARPAllTargetsNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ARPAllTargets values\", s)\n}\n\n// ARPAllTargetsValues returns all values of the enum\nfunc ARPAllTargetsValues() []ARPAllTargets {\n\treturn _ARPAllTargetsValues\n}\n\n// ARPAllTargetsStrings returns a slice of all String values of the enum\nfunc ARPAllTargetsStrings() []string {\n\tstrs := make([]string, len(_ARPAllTargetsNames))\n\tcopy(strs, _ARPAllTargetsNames)\n\treturn strs\n}\n\n// IsAARPAllTargets returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ARPAllTargets) IsAARPAllTargets() bool {\n\tfor _, v := range _ARPAllTargetsValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ARPAllTargets\nfunc (i ARPAllTargets) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ARPAllTargets\nfunc (i *ARPAllTargets) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ARPAllTargetsString(string(text))\n\treturn err\n}\n\nconst _ARPValidateName = \"noneactivebackupallfilterfilter-activefilter-backup\"\n\nvar _ARPValidateIndex = [...]uint8{0, 4, 10, 16, 19, 25, 38, 51}\n\nconst _ARPValidateLowerName = \"noneactivebackupallfilterfilter-activefilter-backup\"\n\nfunc (i ARPValidate) String() string {\n\tif i >= ARPValidate(len(_ARPValidateIndex)-1) {\n\t\treturn fmt.Sprintf(\"ARPValidate(%d)\", i)\n\t}\n\treturn _ARPValidateName[_ARPValidateIndex[i]:_ARPValidateIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ARPValidateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ARPValidateNone-(0)]\n\t_ = x[ARPValidateActive-(1)]\n\t_ = x[ARPValidateBackup-(2)]\n\t_ = x[ARPValidateAll-(3)]\n\t_ = x[ARPValidateFilter-(4)]\n\t_ = x[ARPValidateFilterActive-(5)]\n\t_ = x[ARPValidateFilterBackup-(6)]\n}\n\nvar _ARPValidateValues = []ARPValidate{ARPValidateNone, ARPValidateActive, ARPValidateBackup, ARPValidateAll, ARPValidateFilter, ARPValidateFilterActive, ARPValidateFilterBackup}\n\nvar _ARPValidateNameToValueMap = map[string]ARPValidate{\n\t_ARPValidateName[0:4]:        ARPValidateNone,\n\t_ARPValidateLowerName[0:4]:   ARPValidateNone,\n\t_ARPValidateName[4:10]:       ARPValidateActive,\n\t_ARPValidateLowerName[4:10]:  ARPValidateActive,\n\t_ARPValidateName[10:16]:      ARPValidateBackup,\n\t_ARPValidateLowerName[10:16]: ARPValidateBackup,\n\t_ARPValidateName[16:19]:      ARPValidateAll,\n\t_ARPValidateLowerName[16:19]: ARPValidateAll,\n\t_ARPValidateName[19:25]:      ARPValidateFilter,\n\t_ARPValidateLowerName[19:25]: ARPValidateFilter,\n\t_ARPValidateName[25:38]:      ARPValidateFilterActive,\n\t_ARPValidateLowerName[25:38]: ARPValidateFilterActive,\n\t_ARPValidateName[38:51]:      ARPValidateFilterBackup,\n\t_ARPValidateLowerName[38:51]: ARPValidateFilterBackup,\n}\n\nvar _ARPValidateNames = []string{\n\t_ARPValidateName[0:4],\n\t_ARPValidateName[4:10],\n\t_ARPValidateName[10:16],\n\t_ARPValidateName[16:19],\n\t_ARPValidateName[19:25],\n\t_ARPValidateName[25:38],\n\t_ARPValidateName[38:51],\n}\n\n// ARPValidateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ARPValidateString(s string) (ARPValidate, error) {\n\tif val, ok := _ARPValidateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ARPValidateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ARPValidate values\", s)\n}\n\n// ARPValidateValues returns all values of the enum\nfunc ARPValidateValues() []ARPValidate {\n\treturn _ARPValidateValues\n}\n\n// ARPValidateStrings returns a slice of all String values of the enum\nfunc ARPValidateStrings() []string {\n\tstrs := make([]string, len(_ARPValidateNames))\n\tcopy(strs, _ARPValidateNames)\n\treturn strs\n}\n\n// IsAARPValidate returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ARPValidate) IsAARPValidate() bool {\n\tfor _, v := range _ARPValidateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ARPValidate\nfunc (i ARPValidate) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ARPValidate\nfunc (i *ARPValidate) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ARPValidateString(string(text))\n\treturn err\n}\n\nconst _AddressFlagName = \"temporarynodadoptimisticdadfailedhomeaddressdeprecatedtentativepermanentmngmtmpaddrnoprefixroutemcautojoinstableprivacy\"\nconst _AddressFlagLowerName = \"temporarynodadoptimisticdadfailedhomeaddressdeprecatedtentativepermanentmngmtmpaddrnoprefixroutemcautojoinstableprivacy\"\n\nvar _AddressFlagMap = map[AddressFlag]string{\n\t1:    _AddressFlagName[0:9],\n\t2:    _AddressFlagName[9:14],\n\t4:    _AddressFlagName[14:24],\n\t8:    _AddressFlagName[24:33],\n\t16:   _AddressFlagName[33:44],\n\t32:   _AddressFlagName[44:54],\n\t64:   _AddressFlagName[54:63],\n\t128:  _AddressFlagName[63:72],\n\t256:  _AddressFlagName[72:83],\n\t512:  _AddressFlagName[83:96],\n\t1024: _AddressFlagName[96:106],\n\t2048: _AddressFlagName[106:119],\n}\n\nfunc (i AddressFlag) String() string {\n\tif str, ok := _AddressFlagMap[i]; ok {\n\t\treturn str\n\t}\n\treturn fmt.Sprintf(\"AddressFlag(%d)\", i)\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _AddressFlagNoOp() {\n\tvar x [1]struct{}\n\t_ = x[AddressTemporary-(1)]\n\t_ = x[AddressNoDAD-(2)]\n\t_ = x[AddressOptimistic-(4)]\n\t_ = x[AddressDADFailed-(8)]\n\t_ = x[AddressHome-(16)]\n\t_ = x[AddressDeprecated-(32)]\n\t_ = x[AddressTentative-(64)]\n\t_ = x[AddressPermanent-(128)]\n\t_ = x[AddressManagementTemp-(256)]\n\t_ = x[AddressNoPrefixRoute-(512)]\n\t_ = x[AddressMCAutoJoin-(1024)]\n\t_ = x[AddressStablePrivacy-(2048)]\n}\n\nvar _AddressFlagValues = []AddressFlag{AddressTemporary, AddressNoDAD, AddressOptimistic, AddressDADFailed, AddressHome, AddressDeprecated, AddressTentative, AddressPermanent, AddressManagementTemp, AddressNoPrefixRoute, AddressMCAutoJoin, AddressStablePrivacy}\n\nvar _AddressFlagNameToValueMap = map[string]AddressFlag{\n\t_AddressFlagName[0:9]:          AddressTemporary,\n\t_AddressFlagLowerName[0:9]:     AddressTemporary,\n\t_AddressFlagName[9:14]:         AddressNoDAD,\n\t_AddressFlagLowerName[9:14]:    AddressNoDAD,\n\t_AddressFlagName[14:24]:        AddressOptimistic,\n\t_AddressFlagLowerName[14:24]:   AddressOptimistic,\n\t_AddressFlagName[24:33]:        AddressDADFailed,\n\t_AddressFlagLowerName[24:33]:   AddressDADFailed,\n\t_AddressFlagName[33:44]:        AddressHome,\n\t_AddressFlagLowerName[33:44]:   AddressHome,\n\t_AddressFlagName[44:54]:        AddressDeprecated,\n\t_AddressFlagLowerName[44:54]:   AddressDeprecated,\n\t_AddressFlagName[54:63]:        AddressTentative,\n\t_AddressFlagLowerName[54:63]:   AddressTentative,\n\t_AddressFlagName[63:72]:        AddressPermanent,\n\t_AddressFlagLowerName[63:72]:   AddressPermanent,\n\t_AddressFlagName[72:83]:        AddressManagementTemp,\n\t_AddressFlagLowerName[72:83]:   AddressManagementTemp,\n\t_AddressFlagName[83:96]:        AddressNoPrefixRoute,\n\t_AddressFlagLowerName[83:96]:   AddressNoPrefixRoute,\n\t_AddressFlagName[96:106]:       AddressMCAutoJoin,\n\t_AddressFlagLowerName[96:106]:  AddressMCAutoJoin,\n\t_AddressFlagName[106:119]:      AddressStablePrivacy,\n\t_AddressFlagLowerName[106:119]: AddressStablePrivacy,\n}\n\nvar _AddressFlagNames = []string{\n\t_AddressFlagName[0:9],\n\t_AddressFlagName[9:14],\n\t_AddressFlagName[14:24],\n\t_AddressFlagName[24:33],\n\t_AddressFlagName[33:44],\n\t_AddressFlagName[44:54],\n\t_AddressFlagName[54:63],\n\t_AddressFlagName[63:72],\n\t_AddressFlagName[72:83],\n\t_AddressFlagName[83:96],\n\t_AddressFlagName[96:106],\n\t_AddressFlagName[106:119],\n}\n\n// AddressFlagString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc AddressFlagString(s string) (AddressFlag, error) {\n\tif val, ok := _AddressFlagNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _AddressFlagNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to AddressFlag values\", s)\n}\n\n// AddressFlagValues returns all values of the enum\nfunc AddressFlagValues() []AddressFlag {\n\treturn _AddressFlagValues\n}\n\n// AddressFlagStrings returns a slice of all String values of the enum\nfunc AddressFlagStrings() []string {\n\tstrs := make([]string, len(_AddressFlagNames))\n\tcopy(strs, _AddressFlagNames)\n\treturn strs\n}\n\n// IsAAddressFlag returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i AddressFlag) IsAAddressFlag() bool {\n\t_, ok := _AddressFlagMap[i]\n\treturn ok\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for AddressFlag\nfunc (i AddressFlag) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for AddressFlag\nfunc (i *AddressFlag) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = AddressFlagString(string(text))\n\treturn err\n}\n\nconst _AddressSortAlgorithmName = \"v1v2\"\n\nvar _AddressSortAlgorithmIndex = [...]uint8{0, 2, 4}\n\nconst _AddressSortAlgorithmLowerName = \"v1v2\"\n\nfunc (i AddressSortAlgorithm) String() string {\n\tif i < 0 || i >= AddressSortAlgorithm(len(_AddressSortAlgorithmIndex)-1) {\n\t\treturn fmt.Sprintf(\"AddressSortAlgorithm(%d)\", i)\n\t}\n\treturn _AddressSortAlgorithmName[_AddressSortAlgorithmIndex[i]:_AddressSortAlgorithmIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _AddressSortAlgorithmNoOp() {\n\tvar x [1]struct{}\n\t_ = x[AddressSortAlgorithmV1-(0)]\n\t_ = x[AddressSortAlgorithmV2-(1)]\n}\n\nvar _AddressSortAlgorithmValues = []AddressSortAlgorithm{AddressSortAlgorithmV1, AddressSortAlgorithmV2}\n\nvar _AddressSortAlgorithmNameToValueMap = map[string]AddressSortAlgorithm{\n\t_AddressSortAlgorithmName[0:2]:      AddressSortAlgorithmV1,\n\t_AddressSortAlgorithmLowerName[0:2]: AddressSortAlgorithmV1,\n\t_AddressSortAlgorithmName[2:4]:      AddressSortAlgorithmV2,\n\t_AddressSortAlgorithmLowerName[2:4]: AddressSortAlgorithmV2,\n}\n\nvar _AddressSortAlgorithmNames = []string{\n\t_AddressSortAlgorithmName[0:2],\n\t_AddressSortAlgorithmName[2:4],\n}\n\n// AddressSortAlgorithmString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc AddressSortAlgorithmString(s string) (AddressSortAlgorithm, error) {\n\tif val, ok := _AddressSortAlgorithmNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _AddressSortAlgorithmNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to AddressSortAlgorithm values\", s)\n}\n\n// AddressSortAlgorithmValues returns all values of the enum\nfunc AddressSortAlgorithmValues() []AddressSortAlgorithm {\n\treturn _AddressSortAlgorithmValues\n}\n\n// AddressSortAlgorithmStrings returns a slice of all String values of the enum\nfunc AddressSortAlgorithmStrings() []string {\n\tstrs := make([]string, len(_AddressSortAlgorithmNames))\n\tcopy(strs, _AddressSortAlgorithmNames)\n\treturn strs\n}\n\n// IsAAddressSortAlgorithm returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i AddressSortAlgorithm) IsAAddressSortAlgorithm() bool {\n\tfor _, v := range _AddressSortAlgorithmValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for AddressSortAlgorithm\nfunc (i AddressSortAlgorithm) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for AddressSortAlgorithm\nfunc (i *AddressSortAlgorithm) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = AddressSortAlgorithmString(string(text))\n\treturn err\n}\n\nconst _ADSelectName = \"stablebandwidthcount\"\n\nvar _ADSelectIndex = [...]uint8{0, 6, 15, 20}\n\nconst _ADSelectLowerName = \"stablebandwidthcount\"\n\nfunc (i ADSelect) String() string {\n\tif i >= ADSelect(len(_ADSelectIndex)-1) {\n\t\treturn fmt.Sprintf(\"ADSelect(%d)\", i)\n\t}\n\treturn _ADSelectName[_ADSelectIndex[i]:_ADSelectIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ADSelectNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ADSelectStable-(0)]\n\t_ = x[ADSelectBandwidth-(1)]\n\t_ = x[ADSelectCount-(2)]\n}\n\nvar _ADSelectValues = []ADSelect{ADSelectStable, ADSelectBandwidth, ADSelectCount}\n\nvar _ADSelectNameToValueMap = map[string]ADSelect{\n\t_ADSelectName[0:6]:        ADSelectStable,\n\t_ADSelectLowerName[0:6]:   ADSelectStable,\n\t_ADSelectName[6:15]:       ADSelectBandwidth,\n\t_ADSelectLowerName[6:15]:  ADSelectBandwidth,\n\t_ADSelectName[15:20]:      ADSelectCount,\n\t_ADSelectLowerName[15:20]: ADSelectCount,\n}\n\nvar _ADSelectNames = []string{\n\t_ADSelectName[0:6],\n\t_ADSelectName[6:15],\n\t_ADSelectName[15:20],\n}\n\n// ADSelectString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ADSelectString(s string) (ADSelect, error) {\n\tif val, ok := _ADSelectNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ADSelectNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ADSelect values\", s)\n}\n\n// ADSelectValues returns all values of the enum\nfunc ADSelectValues() []ADSelect {\n\treturn _ADSelectValues\n}\n\n// ADSelectStrings returns a slice of all String values of the enum\nfunc ADSelectStrings() []string {\n\tstrs := make([]string, len(_ADSelectNames))\n\tcopy(strs, _ADSelectNames)\n\treturn strs\n}\n\n// IsAADSelect returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ADSelect) IsAADSelect() bool {\n\tfor _, v := range _ADSelectValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ADSelect\nfunc (i ADSelect) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ADSelect\nfunc (i *ADSelect) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ADSelectString(string(text))\n\treturn err\n}\n\nconst _ADLACPActiveName = \"offon\"\n\nvar _ADLACPActiveIndex = [...]uint8{0, 3, 5}\n\nconst _ADLACPActiveLowerName = \"offon\"\n\nfunc (i ADLACPActive) String() string {\n\tif i >= ADLACPActive(len(_ADLACPActiveIndex)-1) {\n\t\treturn fmt.Sprintf(\"ADLACPActive(%d)\", i)\n\t}\n\treturn _ADLACPActiveName[_ADLACPActiveIndex[i]:_ADLACPActiveIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ADLACPActiveNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ADLACPActiveOff-(0)]\n\t_ = x[ADLACPActiveOn-(1)]\n}\n\nvar _ADLACPActiveValues = []ADLACPActive{ADLACPActiveOff, ADLACPActiveOn}\n\nvar _ADLACPActiveNameToValueMap = map[string]ADLACPActive{\n\t_ADLACPActiveName[0:3]:      ADLACPActiveOff,\n\t_ADLACPActiveLowerName[0:3]: ADLACPActiveOff,\n\t_ADLACPActiveName[3:5]:      ADLACPActiveOn,\n\t_ADLACPActiveLowerName[3:5]: ADLACPActiveOn,\n}\n\nvar _ADLACPActiveNames = []string{\n\t_ADLACPActiveName[0:3],\n\t_ADLACPActiveName[3:5],\n}\n\n// ADLACPActiveString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ADLACPActiveString(s string) (ADLACPActive, error) {\n\tif val, ok := _ADLACPActiveNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ADLACPActiveNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ADLACPActive values\", s)\n}\n\n// ADLACPActiveValues returns all values of the enum\nfunc ADLACPActiveValues() []ADLACPActive {\n\treturn _ADLACPActiveValues\n}\n\n// ADLACPActiveStrings returns a slice of all String values of the enum\nfunc ADLACPActiveStrings() []string {\n\tstrs := make([]string, len(_ADLACPActiveNames))\n\tcopy(strs, _ADLACPActiveNames)\n\treturn strs\n}\n\n// IsAADLACPActive returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ADLACPActive) IsAADLACPActive() bool {\n\tfor _, v := range _ADLACPActiveValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ADLACPActive\nfunc (i ADLACPActive) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ADLACPActive\nfunc (i *ADLACPActive) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ADLACPActiveString(string(text))\n\treturn err\n}\n\nconst _AutoHostnameKindName = \"offtalos-addrstable\"\n\nvar _AutoHostnameKindIndex = [...]uint8{0, 3, 13, 19}\n\nconst _AutoHostnameKindLowerName = \"offtalos-addrstable\"\n\nfunc (i AutoHostnameKind) String() string {\n\tif i >= AutoHostnameKind(len(_AutoHostnameKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"AutoHostnameKind(%d)\", i)\n\t}\n\treturn _AutoHostnameKindName[_AutoHostnameKindIndex[i]:_AutoHostnameKindIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _AutoHostnameKindNoOp() {\n\tvar x [1]struct{}\n\t_ = x[AutoHostnameKindOff-(0)]\n\t_ = x[AutoHostnameKindAddr-(1)]\n\t_ = x[AutoHostnameKindStable-(2)]\n}\n\nvar _AutoHostnameKindValues = []AutoHostnameKind{AutoHostnameKindOff, AutoHostnameKindAddr, AutoHostnameKindStable}\n\nvar _AutoHostnameKindNameToValueMap = map[string]AutoHostnameKind{\n\t_AutoHostnameKindName[0:3]:        AutoHostnameKindOff,\n\t_AutoHostnameKindLowerName[0:3]:   AutoHostnameKindOff,\n\t_AutoHostnameKindName[3:13]:       AutoHostnameKindAddr,\n\t_AutoHostnameKindLowerName[3:13]:  AutoHostnameKindAddr,\n\t_AutoHostnameKindName[13:19]:      AutoHostnameKindStable,\n\t_AutoHostnameKindLowerName[13:19]: AutoHostnameKindStable,\n}\n\nvar _AutoHostnameKindNames = []string{\n\t_AutoHostnameKindName[0:3],\n\t_AutoHostnameKindName[3:13],\n\t_AutoHostnameKindName[13:19],\n}\n\n// AutoHostnameKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc AutoHostnameKindString(s string) (AutoHostnameKind, error) {\n\tif val, ok := _AutoHostnameKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _AutoHostnameKindNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to AutoHostnameKind values\", s)\n}\n\n// AutoHostnameKindValues returns all values of the enum\nfunc AutoHostnameKindValues() []AutoHostnameKind {\n\treturn _AutoHostnameKindValues\n}\n\n// AutoHostnameKindStrings returns a slice of all String values of the enum\nfunc AutoHostnameKindStrings() []string {\n\tstrs := make([]string, len(_AutoHostnameKindNames))\n\tcopy(strs, _AutoHostnameKindNames)\n\treturn strs\n}\n\n// IsAAutoHostnameKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i AutoHostnameKind) IsAAutoHostnameKind() bool {\n\tfor _, v := range _AutoHostnameKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for AutoHostnameKind\nfunc (i AutoHostnameKind) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for AutoHostnameKind\nfunc (i *AutoHostnameKind) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = AutoHostnameKindString(string(text))\n\treturn err\n}\n\nconst _BondModeName = \"balance-rractive-backupbalance-xorbroadcast802.3adbalance-tlbbalance-alb\"\n\nvar _BondModeIndex = [...]uint8{0, 10, 23, 34, 43, 50, 61, 72}\n\nconst _BondModeLowerName = \"balance-rractive-backupbalance-xorbroadcast802.3adbalance-tlbbalance-alb\"\n\nfunc (i BondMode) String() string {\n\tif i >= BondMode(len(_BondModeIndex)-1) {\n\t\treturn fmt.Sprintf(\"BondMode(%d)\", i)\n\t}\n\treturn _BondModeName[_BondModeIndex[i]:_BondModeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _BondModeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[BondModeRoundrobin-(0)]\n\t_ = x[BondModeActiveBackup-(1)]\n\t_ = x[BondModeXOR-(2)]\n\t_ = x[BondModeBroadcast-(3)]\n\t_ = x[BondMode8023AD-(4)]\n\t_ = x[BondModeTLB-(5)]\n\t_ = x[BondModeALB-(6)]\n}\n\nvar _BondModeValues = []BondMode{BondModeRoundrobin, BondModeActiveBackup, BondModeXOR, BondModeBroadcast, BondMode8023AD, BondModeTLB, BondModeALB}\n\nvar _BondModeNameToValueMap = map[string]BondMode{\n\t_BondModeName[0:10]:       BondModeRoundrobin,\n\t_BondModeLowerName[0:10]:  BondModeRoundrobin,\n\t_BondModeName[10:23]:      BondModeActiveBackup,\n\t_BondModeLowerName[10:23]: BondModeActiveBackup,\n\t_BondModeName[23:34]:      BondModeXOR,\n\t_BondModeLowerName[23:34]: BondModeXOR,\n\t_BondModeName[34:43]:      BondModeBroadcast,\n\t_BondModeLowerName[34:43]: BondModeBroadcast,\n\t_BondModeName[43:50]:      BondMode8023AD,\n\t_BondModeLowerName[43:50]: BondMode8023AD,\n\t_BondModeName[50:61]:      BondModeTLB,\n\t_BondModeLowerName[50:61]: BondModeTLB,\n\t_BondModeName[61:72]:      BondModeALB,\n\t_BondModeLowerName[61:72]: BondModeALB,\n}\n\nvar _BondModeNames = []string{\n\t_BondModeName[0:10],\n\t_BondModeName[10:23],\n\t_BondModeName[23:34],\n\t_BondModeName[34:43],\n\t_BondModeName[43:50],\n\t_BondModeName[50:61],\n\t_BondModeName[61:72],\n}\n\n// BondModeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc BondModeString(s string) (BondMode, error) {\n\tif val, ok := _BondModeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _BondModeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to BondMode values\", s)\n}\n\n// BondModeValues returns all values of the enum\nfunc BondModeValues() []BondMode {\n\treturn _BondModeValues\n}\n\n// BondModeStrings returns a slice of all String values of the enum\nfunc BondModeStrings() []string {\n\tstrs := make([]string, len(_BondModeNames))\n\tcopy(strs, _BondModeNames)\n\treturn strs\n}\n\n// IsABondMode returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i BondMode) IsABondMode() bool {\n\tfor _, v := range _BondModeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for BondMode\nfunc (i BondMode) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for BondMode\nfunc (i *BondMode) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = BondModeString(string(text))\n\treturn err\n}\n\nconst _BondXmitHashPolicyName = \"layer2layer3+4layer2+3encap2+3encap3+4\"\n\nvar _BondXmitHashPolicyIndex = [...]uint8{0, 6, 14, 22, 30, 38}\n\nconst _BondXmitHashPolicyLowerName = \"layer2layer3+4layer2+3encap2+3encap3+4\"\n\nfunc (i BondXmitHashPolicy) String() string {\n\tif i >= BondXmitHashPolicy(len(_BondXmitHashPolicyIndex)-1) {\n\t\treturn fmt.Sprintf(\"BondXmitHashPolicy(%d)\", i)\n\t}\n\treturn _BondXmitHashPolicyName[_BondXmitHashPolicyIndex[i]:_BondXmitHashPolicyIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _BondXmitHashPolicyNoOp() {\n\tvar x [1]struct{}\n\t_ = x[BondXmitPolicyLayer2-(0)]\n\t_ = x[BondXmitPolicyLayer34-(1)]\n\t_ = x[BondXmitPolicyLayer23-(2)]\n\t_ = x[BondXmitPolicyEncap23-(3)]\n\t_ = x[BondXmitPolicyEncap34-(4)]\n}\n\nvar _BondXmitHashPolicyValues = []BondXmitHashPolicy{BondXmitPolicyLayer2, BondXmitPolicyLayer34, BondXmitPolicyLayer23, BondXmitPolicyEncap23, BondXmitPolicyEncap34}\n\nvar _BondXmitHashPolicyNameToValueMap = map[string]BondXmitHashPolicy{\n\t_BondXmitHashPolicyName[0:6]:        BondXmitPolicyLayer2,\n\t_BondXmitHashPolicyLowerName[0:6]:   BondXmitPolicyLayer2,\n\t_BondXmitHashPolicyName[6:14]:       BondXmitPolicyLayer34,\n\t_BondXmitHashPolicyLowerName[6:14]:  BondXmitPolicyLayer34,\n\t_BondXmitHashPolicyName[14:22]:      BondXmitPolicyLayer23,\n\t_BondXmitHashPolicyLowerName[14:22]: BondXmitPolicyLayer23,\n\t_BondXmitHashPolicyName[22:30]:      BondXmitPolicyEncap23,\n\t_BondXmitHashPolicyLowerName[22:30]: BondXmitPolicyEncap23,\n\t_BondXmitHashPolicyName[30:38]:      BondXmitPolicyEncap34,\n\t_BondXmitHashPolicyLowerName[30:38]: BondXmitPolicyEncap34,\n}\n\nvar _BondXmitHashPolicyNames = []string{\n\t_BondXmitHashPolicyName[0:6],\n\t_BondXmitHashPolicyName[6:14],\n\t_BondXmitHashPolicyName[14:22],\n\t_BondXmitHashPolicyName[22:30],\n\t_BondXmitHashPolicyName[30:38],\n}\n\n// BondXmitHashPolicyString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc BondXmitHashPolicyString(s string) (BondXmitHashPolicy, error) {\n\tif val, ok := _BondXmitHashPolicyNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _BondXmitHashPolicyNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to BondXmitHashPolicy values\", s)\n}\n\n// BondXmitHashPolicyValues returns all values of the enum\nfunc BondXmitHashPolicyValues() []BondXmitHashPolicy {\n\treturn _BondXmitHashPolicyValues\n}\n\n// BondXmitHashPolicyStrings returns a slice of all String values of the enum\nfunc BondXmitHashPolicyStrings() []string {\n\tstrs := make([]string, len(_BondXmitHashPolicyNames))\n\tcopy(strs, _BondXmitHashPolicyNames)\n\treturn strs\n}\n\n// IsABondXmitHashPolicy returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i BondXmitHashPolicy) IsABondXmitHashPolicy() bool {\n\tfor _, v := range _BondXmitHashPolicyValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for BondXmitHashPolicy\nfunc (i BondXmitHashPolicy) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for BondXmitHashPolicy\nfunc (i *BondXmitHashPolicy) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = BondXmitHashPolicyString(string(text))\n\treturn err\n}\n\nconst _ClientIdentifierName = \"nonemacduid\"\n\nvar _ClientIdentifierIndex = [...]uint8{0, 4, 7, 11}\n\nconst _ClientIdentifierLowerName = \"nonemacduid\"\n\nfunc (i ClientIdentifier) String() string {\n\tif i < 0 || i >= ClientIdentifier(len(_ClientIdentifierIndex)-1) {\n\t\treturn fmt.Sprintf(\"ClientIdentifier(%d)\", i)\n\t}\n\treturn _ClientIdentifierName[_ClientIdentifierIndex[i]:_ClientIdentifierIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ClientIdentifierNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ClientIdentifierNone-(0)]\n\t_ = x[ClientIdentifierMAC-(1)]\n\t_ = x[ClientIdentifierDUID-(2)]\n}\n\nvar _ClientIdentifierValues = []ClientIdentifier{ClientIdentifierNone, ClientIdentifierMAC, ClientIdentifierDUID}\n\nvar _ClientIdentifierNameToValueMap = map[string]ClientIdentifier{\n\t_ClientIdentifierName[0:4]:       ClientIdentifierNone,\n\t_ClientIdentifierLowerName[0:4]:  ClientIdentifierNone,\n\t_ClientIdentifierName[4:7]:       ClientIdentifierMAC,\n\t_ClientIdentifierLowerName[4:7]:  ClientIdentifierMAC,\n\t_ClientIdentifierName[7:11]:      ClientIdentifierDUID,\n\t_ClientIdentifierLowerName[7:11]: ClientIdentifierDUID,\n}\n\nvar _ClientIdentifierNames = []string{\n\t_ClientIdentifierName[0:4],\n\t_ClientIdentifierName[4:7],\n\t_ClientIdentifierName[7:11],\n}\n\n// ClientIdentifierString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ClientIdentifierString(s string) (ClientIdentifier, error) {\n\tif val, ok := _ClientIdentifierNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ClientIdentifierNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ClientIdentifier values\", s)\n}\n\n// ClientIdentifierValues returns all values of the enum\nfunc ClientIdentifierValues() []ClientIdentifier {\n\treturn _ClientIdentifierValues\n}\n\n// ClientIdentifierStrings returns a slice of all String values of the enum\nfunc ClientIdentifierStrings() []string {\n\tstrs := make([]string, len(_ClientIdentifierNames))\n\tcopy(strs, _ClientIdentifierNames)\n\treturn strs\n}\n\n// IsAClientIdentifier returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ClientIdentifier) IsAClientIdentifier() bool {\n\tfor _, v := range _ClientIdentifierValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ClientIdentifier\nfunc (i ClientIdentifier) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ClientIdentifier\nfunc (i *ClientIdentifier) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ClientIdentifierString(string(text))\n\treturn err\n}\n\nconst (\n\t_ConntrackStateName_0      = \"invalidestablished\"\n\t_ConntrackStateLowerName_0 = \"invalidestablished\"\n\t_ConntrackStateName_1      = \"related\"\n\t_ConntrackStateLowerName_1 = \"related\"\n\t_ConntrackStateName_2      = \"new\"\n\t_ConntrackStateLowerName_2 = \"new\"\n)\n\nvar (\n\t_ConntrackStateIndex_0 = [...]uint8{0, 7, 18}\n\t_ConntrackStateIndex_1 = [...]uint8{0, 7}\n\t_ConntrackStateIndex_2 = [...]uint8{0, 3}\n)\n\nfunc (i ConntrackState) String() string {\n\tswitch {\n\tcase 1 <= i && i <= 2:\n\t\ti -= 1\n\t\treturn _ConntrackStateName_0[_ConntrackStateIndex_0[i]:_ConntrackStateIndex_0[i+1]]\n\tcase i == 4:\n\t\treturn _ConntrackStateName_1\n\tcase i == 8:\n\t\treturn _ConntrackStateName_2\n\tdefault:\n\t\treturn fmt.Sprintf(\"ConntrackState(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ConntrackStateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ConntrackStateInvalid-(1)]\n\t_ = x[ConntrackStateEstablished-(2)]\n\t_ = x[ConntrackStateRelated-(4)]\n\t_ = x[ConntrackStateNew-(8)]\n}\n\nvar _ConntrackStateValues = []ConntrackState{ConntrackStateInvalid, ConntrackStateEstablished, ConntrackStateRelated, ConntrackStateNew}\n\nvar _ConntrackStateNameToValueMap = map[string]ConntrackState{\n\t_ConntrackStateName_0[0:7]:       ConntrackStateInvalid,\n\t_ConntrackStateLowerName_0[0:7]:  ConntrackStateInvalid,\n\t_ConntrackStateName_0[7:18]:      ConntrackStateEstablished,\n\t_ConntrackStateLowerName_0[7:18]: ConntrackStateEstablished,\n\t_ConntrackStateName_1[0:7]:       ConntrackStateRelated,\n\t_ConntrackStateLowerName_1[0:7]:  ConntrackStateRelated,\n\t_ConntrackStateName_2[0:3]:       ConntrackStateNew,\n\t_ConntrackStateLowerName_2[0:3]:  ConntrackStateNew,\n}\n\nvar _ConntrackStateNames = []string{\n\t_ConntrackStateName_0[0:7],\n\t_ConntrackStateName_0[7:18],\n\t_ConntrackStateName_1[0:7],\n\t_ConntrackStateName_2[0:3],\n}\n\n// ConntrackStateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ConntrackStateString(s string) (ConntrackState, error) {\n\tif val, ok := _ConntrackStateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ConntrackStateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ConntrackState values\", s)\n}\n\n// ConntrackStateValues returns all values of the enum\nfunc ConntrackStateValues() []ConntrackState {\n\treturn _ConntrackStateValues\n}\n\n// ConntrackStateStrings returns a slice of all String values of the enum\nfunc ConntrackStateStrings() []string {\n\tstrs := make([]string, len(_ConntrackStateNames))\n\tcopy(strs, _ConntrackStateNames)\n\treturn strs\n}\n\n// IsAConntrackState returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ConntrackState) IsAConntrackState() bool {\n\tfor _, v := range _ConntrackStateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ConntrackState\nfunc (i ConntrackState) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ConntrackState\nfunc (i *ConntrackState) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ConntrackStateString(string(text))\n\treturn err\n}\n\nconst _DefaultActionName = \"acceptblock\"\n\nvar _DefaultActionIndex = [...]uint8{0, 6, 11}\n\nconst _DefaultActionLowerName = \"acceptblock\"\n\nfunc (i DefaultAction) String() string {\n\tif i < 0 || i >= DefaultAction(len(_DefaultActionIndex)-1) {\n\t\treturn fmt.Sprintf(\"DefaultAction(%d)\", i)\n\t}\n\treturn _DefaultActionName[_DefaultActionIndex[i]:_DefaultActionIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _DefaultActionNoOp() {\n\tvar x [1]struct{}\n\t_ = x[DefaultActionAccept-(0)]\n\t_ = x[DefaultActionBlock-(1)]\n}\n\nvar _DefaultActionValues = []DefaultAction{DefaultActionAccept, DefaultActionBlock}\n\nvar _DefaultActionNameToValueMap = map[string]DefaultAction{\n\t_DefaultActionName[0:6]:       DefaultActionAccept,\n\t_DefaultActionLowerName[0:6]:  DefaultActionAccept,\n\t_DefaultActionName[6:11]:      DefaultActionBlock,\n\t_DefaultActionLowerName[6:11]: DefaultActionBlock,\n}\n\nvar _DefaultActionNames = []string{\n\t_DefaultActionName[0:6],\n\t_DefaultActionName[6:11],\n}\n\n// DefaultActionString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc DefaultActionString(s string) (DefaultAction, error) {\n\tif val, ok := _DefaultActionNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _DefaultActionNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to DefaultAction values\", s)\n}\n\n// DefaultActionValues returns all values of the enum\nfunc DefaultActionValues() []DefaultAction {\n\treturn _DefaultActionValues\n}\n\n// DefaultActionStrings returns a slice of all String values of the enum\nfunc DefaultActionStrings() []string {\n\tstrs := make([]string, len(_DefaultActionNames))\n\tcopy(strs, _DefaultActionNames)\n\treturn strs\n}\n\n// IsADefaultAction returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i DefaultAction) IsADefaultAction() bool {\n\tfor _, v := range _DefaultActionValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for DefaultAction\nfunc (i DefaultAction) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for DefaultAction\nfunc (i *DefaultAction) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = DefaultActionString(string(text))\n\treturn err\n}\n\nconst (\n\t_DuplexName_0      = \"HalfFull\"\n\t_DuplexLowerName_0 = \"halffull\"\n\t_DuplexName_1      = \"Unknown\"\n\t_DuplexLowerName_1 = \"unknown\"\n)\n\nvar (\n\t_DuplexIndex_0 = [...]uint8{0, 4, 8}\n\t_DuplexIndex_1 = [...]uint8{0, 7}\n)\n\nfunc (i Duplex) String() string {\n\tswitch {\n\tcase 0 <= i && i <= 1:\n\t\treturn _DuplexName_0[_DuplexIndex_0[i]:_DuplexIndex_0[i+1]]\n\tcase i == 255:\n\t\treturn _DuplexName_1\n\tdefault:\n\t\treturn fmt.Sprintf(\"Duplex(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _DuplexNoOp() {\n\tvar x [1]struct{}\n\t_ = x[Half-(0)]\n\t_ = x[Full-(1)]\n\t_ = x[Unknown-(255)]\n}\n\nvar _DuplexValues = []Duplex{Half, Full, Unknown}\n\nvar _DuplexNameToValueMap = map[string]Duplex{\n\t_DuplexName_0[0:4]:      Half,\n\t_DuplexLowerName_0[0:4]: Half,\n\t_DuplexName_0[4:8]:      Full,\n\t_DuplexLowerName_0[4:8]: Full,\n\t_DuplexName_1[0:7]:      Unknown,\n\t_DuplexLowerName_1[0:7]: Unknown,\n}\n\nvar _DuplexNames = []string{\n\t_DuplexName_0[0:4],\n\t_DuplexName_0[4:8],\n\t_DuplexName_1[0:7],\n}\n\n// DuplexString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc DuplexString(s string) (Duplex, error) {\n\tif val, ok := _DuplexNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _DuplexNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Duplex values\", s)\n}\n\n// DuplexValues returns all values of the enum\nfunc DuplexValues() []Duplex {\n\treturn _DuplexValues\n}\n\n// DuplexStrings returns a slice of all String values of the enum\nfunc DuplexStrings() []string {\n\tstrs := make([]string, len(_DuplexNames))\n\tcopy(strs, _DuplexNames)\n\treturn strs\n}\n\n// IsADuplex returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Duplex) IsADuplex() bool {\n\tfor _, v := range _DuplexValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Duplex\nfunc (i Duplex) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Duplex\nfunc (i *Duplex) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = DuplexString(string(text))\n\treturn err\n}\n\nconst (\n\t_FamilyName_0      = \"inet4\"\n\t_FamilyLowerName_0 = \"inet4\"\n\t_FamilyName_1      = \"inet6\"\n\t_FamilyLowerName_1 = \"inet6\"\n)\n\nvar (\n\t_FamilyIndex_0 = [...]uint8{0, 5}\n\t_FamilyIndex_1 = [...]uint8{0, 5}\n)\n\nfunc (i Family) String() string {\n\tswitch {\n\tcase i == 2:\n\t\treturn _FamilyName_0\n\tcase i == 10:\n\t\treturn _FamilyName_1\n\tdefault:\n\t\treturn fmt.Sprintf(\"Family(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _FamilyNoOp() {\n\tvar x [1]struct{}\n\t_ = x[FamilyInet4-(2)]\n\t_ = x[FamilyInet6-(10)]\n}\n\nvar _FamilyValues = []Family{FamilyInet4, FamilyInet6}\n\nvar _FamilyNameToValueMap = map[string]Family{\n\t_FamilyName_0[0:5]:      FamilyInet4,\n\t_FamilyLowerName_0[0:5]: FamilyInet4,\n\t_FamilyName_1[0:5]:      FamilyInet6,\n\t_FamilyLowerName_1[0:5]: FamilyInet6,\n}\n\nvar _FamilyNames = []string{\n\t_FamilyName_0[0:5],\n\t_FamilyName_1[0:5],\n}\n\n// FamilyString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc FamilyString(s string) (Family, error) {\n\tif val, ok := _FamilyNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _FamilyNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Family values\", s)\n}\n\n// FamilyValues returns all values of the enum\nfunc FamilyValues() []Family {\n\treturn _FamilyValues\n}\n\n// FamilyStrings returns a slice of all String values of the enum\nfunc FamilyStrings() []string {\n\tstrs := make([]string, len(_FamilyNames))\n\tcopy(strs, _FamilyNames)\n\treturn strs\n}\n\n// IsAFamily returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Family) IsAFamily() bool {\n\tfor _, v := range _FamilyValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Family\nfunc (i Family) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Family\nfunc (i *Family) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = FamilyString(string(text))\n\treturn err\n}\n\nconst _LACPRateName = \"slowfast\"\n\nvar _LACPRateIndex = [...]uint8{0, 4, 8}\n\nconst _LACPRateLowerName = \"slowfast\"\n\nfunc (i LACPRate) String() string {\n\tif i >= LACPRate(len(_LACPRateIndex)-1) {\n\t\treturn fmt.Sprintf(\"LACPRate(%d)\", i)\n\t}\n\treturn _LACPRateName[_LACPRateIndex[i]:_LACPRateIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _LACPRateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[LACPRateSlow-(0)]\n\t_ = x[LACPRateFast-(1)]\n}\n\nvar _LACPRateValues = []LACPRate{LACPRateSlow, LACPRateFast}\n\nvar _LACPRateNameToValueMap = map[string]LACPRate{\n\t_LACPRateName[0:4]:      LACPRateSlow,\n\t_LACPRateLowerName[0:4]: LACPRateSlow,\n\t_LACPRateName[4:8]:      LACPRateFast,\n\t_LACPRateLowerName[4:8]: LACPRateFast,\n}\n\nvar _LACPRateNames = []string{\n\t_LACPRateName[0:4],\n\t_LACPRateName[4:8],\n}\n\n// LACPRateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc LACPRateString(s string) (LACPRate, error) {\n\tif val, ok := _LACPRateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _LACPRateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to LACPRate values\", s)\n}\n\n// LACPRateValues returns all values of the enum\nfunc LACPRateValues() []LACPRate {\n\treturn _LACPRateValues\n}\n\n// LACPRateStrings returns a slice of all String values of the enum\nfunc LACPRateStrings() []string {\n\tstrs := make([]string, len(_LACPRateNames))\n\tcopy(strs, _LACPRateNames)\n\treturn strs\n}\n\n// IsALACPRate returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i LACPRate) IsALACPRate() bool {\n\tfor _, v := range _LACPRateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for LACPRate\nfunc (i LACPRate) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for LACPRate\nfunc (i *LACPRate) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = LACPRateString(string(text))\n\treturn err\n}\n\nconst _LinkFlagName = \"UPBROADCASTDEBUGLOOPBACKPOINTTOPOINTNOTRAILERSRUNNINGNOARPPROMISCALLMULTIMASTERSLAVEMULTICASTPORTSELAUTOMEDIADYNAMICLOWER_UPDORMANTECHO\"\nconst _LinkFlagLowerName = \"upbroadcastdebugloopbackpointtopointnotrailersrunningnoarppromiscallmultimasterslavemulticastportselautomediadynamiclower_updormantecho\"\n\nvar _LinkFlagMap = map[LinkFlag]string{\n\t1:      _LinkFlagName[0:2],\n\t2:      _LinkFlagName[2:11],\n\t4:      _LinkFlagName[11:16],\n\t8:      _LinkFlagName[16:24],\n\t16:     _LinkFlagName[24:36],\n\t32:     _LinkFlagName[36:46],\n\t64:     _LinkFlagName[46:53],\n\t128:    _LinkFlagName[53:58],\n\t256:    _LinkFlagName[58:65],\n\t512:    _LinkFlagName[65:73],\n\t1024:   _LinkFlagName[73:79],\n\t2048:   _LinkFlagName[79:84],\n\t4096:   _LinkFlagName[84:93],\n\t8192:   _LinkFlagName[93:100],\n\t16384:  _LinkFlagName[100:109],\n\t32768:  _LinkFlagName[109:116],\n\t65536:  _LinkFlagName[116:124],\n\t131072: _LinkFlagName[124:131],\n\t262144: _LinkFlagName[131:135],\n}\n\nfunc (i LinkFlag) String() string {\n\tif str, ok := _LinkFlagMap[i]; ok {\n\t\treturn str\n\t}\n\treturn fmt.Sprintf(\"LinkFlag(%d)\", i)\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _LinkFlagNoOp() {\n\tvar x [1]struct{}\n\t_ = x[LinkUp-(1)]\n\t_ = x[LinkBroadcast-(2)]\n\t_ = x[LinkDebug-(4)]\n\t_ = x[LinkLoopback-(8)]\n\t_ = x[LinkPointToPoint-(16)]\n\t_ = x[LinkNoTrailers-(32)]\n\t_ = x[LinkRunning-(64)]\n\t_ = x[LinkNoArp-(128)]\n\t_ = x[LinkPromisc-(256)]\n\t_ = x[LinkAllMulti-(512)]\n\t_ = x[LinkMaster-(1024)]\n\t_ = x[LinkSlave-(2048)]\n\t_ = x[LinkMulticast-(4096)]\n\t_ = x[LinkPortsel-(8192)]\n\t_ = x[LinKAutoMedia-(16384)]\n\t_ = x[LinkDynamic-(32768)]\n\t_ = x[LinkLowerUp-(65536)]\n\t_ = x[LinkDormant-(131072)]\n\t_ = x[LinkEcho-(262144)]\n}\n\nvar _LinkFlagValues = []LinkFlag{LinkUp, LinkBroadcast, LinkDebug, LinkLoopback, LinkPointToPoint, LinkNoTrailers, LinkRunning, LinkNoArp, LinkPromisc, LinkAllMulti, LinkMaster, LinkSlave, LinkMulticast, LinkPortsel, LinKAutoMedia, LinkDynamic, LinkLowerUp, LinkDormant, LinkEcho}\n\nvar _LinkFlagNameToValueMap = map[string]LinkFlag{\n\t_LinkFlagName[0:2]:          LinkUp,\n\t_LinkFlagLowerName[0:2]:     LinkUp,\n\t_LinkFlagName[2:11]:         LinkBroadcast,\n\t_LinkFlagLowerName[2:11]:    LinkBroadcast,\n\t_LinkFlagName[11:16]:        LinkDebug,\n\t_LinkFlagLowerName[11:16]:   LinkDebug,\n\t_LinkFlagName[16:24]:        LinkLoopback,\n\t_LinkFlagLowerName[16:24]:   LinkLoopback,\n\t_LinkFlagName[24:36]:        LinkPointToPoint,\n\t_LinkFlagLowerName[24:36]:   LinkPointToPoint,\n\t_LinkFlagName[36:46]:        LinkNoTrailers,\n\t_LinkFlagLowerName[36:46]:   LinkNoTrailers,\n\t_LinkFlagName[46:53]:        LinkRunning,\n\t_LinkFlagLowerName[46:53]:   LinkRunning,\n\t_LinkFlagName[53:58]:        LinkNoArp,\n\t_LinkFlagLowerName[53:58]:   LinkNoArp,\n\t_LinkFlagName[58:65]:        LinkPromisc,\n\t_LinkFlagLowerName[58:65]:   LinkPromisc,\n\t_LinkFlagName[65:73]:        LinkAllMulti,\n\t_LinkFlagLowerName[65:73]:   LinkAllMulti,\n\t_LinkFlagName[73:79]:        LinkMaster,\n\t_LinkFlagLowerName[73:79]:   LinkMaster,\n\t_LinkFlagName[79:84]:        LinkSlave,\n\t_LinkFlagLowerName[79:84]:   LinkSlave,\n\t_LinkFlagName[84:93]:        LinkMulticast,\n\t_LinkFlagLowerName[84:93]:   LinkMulticast,\n\t_LinkFlagName[93:100]:       LinkPortsel,\n\t_LinkFlagLowerName[93:100]:  LinkPortsel,\n\t_LinkFlagName[100:109]:      LinKAutoMedia,\n\t_LinkFlagLowerName[100:109]: LinKAutoMedia,\n\t_LinkFlagName[109:116]:      LinkDynamic,\n\t_LinkFlagLowerName[109:116]: LinkDynamic,\n\t_LinkFlagName[116:124]:      LinkLowerUp,\n\t_LinkFlagLowerName[116:124]: LinkLowerUp,\n\t_LinkFlagName[124:131]:      LinkDormant,\n\t_LinkFlagLowerName[124:131]: LinkDormant,\n\t_LinkFlagName[131:135]:      LinkEcho,\n\t_LinkFlagLowerName[131:135]: LinkEcho,\n}\n\nvar _LinkFlagNames = []string{\n\t_LinkFlagName[0:2],\n\t_LinkFlagName[2:11],\n\t_LinkFlagName[11:16],\n\t_LinkFlagName[16:24],\n\t_LinkFlagName[24:36],\n\t_LinkFlagName[36:46],\n\t_LinkFlagName[46:53],\n\t_LinkFlagName[53:58],\n\t_LinkFlagName[58:65],\n\t_LinkFlagName[65:73],\n\t_LinkFlagName[73:79],\n\t_LinkFlagName[79:84],\n\t_LinkFlagName[84:93],\n\t_LinkFlagName[93:100],\n\t_LinkFlagName[100:109],\n\t_LinkFlagName[109:116],\n\t_LinkFlagName[116:124],\n\t_LinkFlagName[124:131],\n\t_LinkFlagName[131:135],\n}\n\n// LinkFlagString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc LinkFlagString(s string) (LinkFlag, error) {\n\tif val, ok := _LinkFlagNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _LinkFlagNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to LinkFlag values\", s)\n}\n\n// LinkFlagValues returns all values of the enum\nfunc LinkFlagValues() []LinkFlag {\n\treturn _LinkFlagValues\n}\n\n// LinkFlagStrings returns a slice of all String values of the enum\nfunc LinkFlagStrings() []string {\n\tstrs := make([]string, len(_LinkFlagNames))\n\tcopy(strs, _LinkFlagNames)\n\treturn strs\n}\n\n// IsALinkFlag returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i LinkFlag) IsALinkFlag() bool {\n\t_, ok := _LinkFlagMap[i]\n\treturn ok\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for LinkFlag\nfunc (i LinkFlag) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for LinkFlag\nfunc (i *LinkFlag) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = LinkFlagString(string(text))\n\treturn err\n}\n\nconst _LinkTypeName = \"netromethereetherax25pronetchaosieee802arcnetatalkdlciatmmetricomieee1394eui64infinibandslipcslipslip6cslip6rsrvdadaptrosex25hwx25canpppciscolapbddcmprawhdlcipiptunnel6fradskiploopbacklocaltlkfddibifsitip/ddpgrepimreghippiasheconetirdafcppfcalfcplfcfb_0fcfb_1fcfb_2fcfb_3fcfb_4fcfb_5fcfb_6fcfb_7fcfb_8fcfb_9fcfb_10fcfb_11fcfb_12trieee802.11ieee802.11_prismieee802.11_radiotapieee802.15.4ieee802.15.4_monitorphonetphonet_pipecaifip6grenetlink6lowpannohdrvoid\"\nconst _LinkTypeLowerName = \"netromethereetherax25pronetchaosieee802arcnetatalkdlciatmmetricomieee1394eui64infinibandslipcslipslip6cslip6rsrvdadaptrosex25hwx25canpppciscolapbddcmprawhdlcipiptunnel6fradskiploopbacklocaltlkfddibifsitip/ddpgrepimreghippiasheconetirdafcppfcalfcplfcfb_0fcfb_1fcfb_2fcfb_3fcfb_4fcfb_5fcfb_6fcfb_7fcfb_8fcfb_9fcfb_10fcfb_11fcfb_12trieee802.11ieee802.11_prismieee802.11_radiotapieee802.15.4ieee802.15.4_monitorphonetphonet_pipecaifip6grenetlink6lowpannohdrvoid\"\n\nvar _LinkTypeMap = map[LinkType]string{\n\t0:     _LinkTypeName[0:6],\n\t1:     _LinkTypeName[6:11],\n\t2:     _LinkTypeName[11:17],\n\t3:     _LinkTypeName[17:21],\n\t4:     _LinkTypeName[21:27],\n\t5:     _LinkTypeName[27:32],\n\t6:     _LinkTypeName[32:39],\n\t7:     _LinkTypeName[39:45],\n\t8:     _LinkTypeName[45:50],\n\t15:    _LinkTypeName[50:54],\n\t19:    _LinkTypeName[54:57],\n\t23:    _LinkTypeName[57:65],\n\t24:    _LinkTypeName[65:73],\n\t27:    _LinkTypeName[73:78],\n\t32:    _LinkTypeName[78:88],\n\t256:   _LinkTypeName[88:92],\n\t257:   _LinkTypeName[92:97],\n\t258:   _LinkTypeName[97:102],\n\t259:   _LinkTypeName[102:108],\n\t260:   _LinkTypeName[108:113],\n\t264:   _LinkTypeName[113:118],\n\t270:   _LinkTypeName[118:122],\n\t271:   _LinkTypeName[122:125],\n\t272:   _LinkTypeName[125:130],\n\t280:   _LinkTypeName[130:133],\n\t512:   _LinkTypeName[133:136],\n\t513:   _LinkTypeName[136:141],\n\t516:   _LinkTypeName[141:145],\n\t517:   _LinkTypeName[145:150],\n\t518:   _LinkTypeName[150:157],\n\t768:   _LinkTypeName[157:161],\n\t769:   _LinkTypeName[161:168],\n\t770:   _LinkTypeName[168:172],\n\t771:   _LinkTypeName[172:176],\n\t772:   _LinkTypeName[176:184],\n\t773:   _LinkTypeName[184:192],\n\t774:   _LinkTypeName[192:196],\n\t775:   _LinkTypeName[196:199],\n\t776:   _LinkTypeName[199:202],\n\t777:   _LinkTypeName[202:208],\n\t778:   _LinkTypeName[208:211],\n\t779:   _LinkTypeName[211:217],\n\t780:   _LinkTypeName[217:222],\n\t781:   _LinkTypeName[222:225],\n\t782:   _LinkTypeName[225:231],\n\t783:   _LinkTypeName[231:235],\n\t784:   _LinkTypeName[235:239],\n\t785:   _LinkTypeName[239:243],\n\t786:   _LinkTypeName[243:247],\n\t787:   _LinkTypeName[247:253],\n\t788:   _LinkTypeName[253:259],\n\t789:   _LinkTypeName[259:265],\n\t790:   _LinkTypeName[265:271],\n\t791:   _LinkTypeName[271:277],\n\t792:   _LinkTypeName[277:283],\n\t793:   _LinkTypeName[283:289],\n\t794:   _LinkTypeName[289:295],\n\t795:   _LinkTypeName[295:301],\n\t796:   _LinkTypeName[301:307],\n\t797:   _LinkTypeName[307:314],\n\t798:   _LinkTypeName[314:321],\n\t799:   _LinkTypeName[321:328],\n\t800:   _LinkTypeName[328:330],\n\t801:   _LinkTypeName[330:340],\n\t802:   _LinkTypeName[340:356],\n\t803:   _LinkTypeName[356:375],\n\t804:   _LinkTypeName[375:387],\n\t805:   _LinkTypeName[387:407],\n\t820:   _LinkTypeName[407:413],\n\t821:   _LinkTypeName[413:424],\n\t822:   _LinkTypeName[424:428],\n\t823:   _LinkTypeName[428:434],\n\t824:   _LinkTypeName[434:441],\n\t825:   _LinkTypeName[441:448],\n\t65534: _LinkTypeName[448:453],\n\t65535: _LinkTypeName[453:457],\n}\n\nfunc (i LinkType) String() string {\n\tif str, ok := _LinkTypeMap[i]; ok {\n\t\treturn str\n\t}\n\treturn fmt.Sprintf(\"LinkType(%d)\", i)\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _LinkTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[LinkNetrom-(0)]\n\t_ = x[LinkEther-(1)]\n\t_ = x[LinkEether-(2)]\n\t_ = x[LinkAx25-(3)]\n\t_ = x[LinkPronet-(4)]\n\t_ = x[LinkChaos-(5)]\n\t_ = x[LinkIee802-(6)]\n\t_ = x[LinkArcnet-(7)]\n\t_ = x[LinkAtalk-(8)]\n\t_ = x[LinkDlci-(15)]\n\t_ = x[LinkAtm-(19)]\n\t_ = x[LinkMetricom-(23)]\n\t_ = x[LinkIeee1394-(24)]\n\t_ = x[LinkEui64-(27)]\n\t_ = x[LinkInfiniband-(32)]\n\t_ = x[LinkSlip-(256)]\n\t_ = x[LinkCslip-(257)]\n\t_ = x[LinkSlip6-(258)]\n\t_ = x[LinkCslip6-(259)]\n\t_ = x[LinkRsrvd-(260)]\n\t_ = x[LinkAdapt-(264)]\n\t_ = x[LinkRose-(270)]\n\t_ = x[LinkX25-(271)]\n\t_ = x[LinkHwx25-(272)]\n\t_ = x[LinkCan-(280)]\n\t_ = x[LinkPpp-(512)]\n\t_ = x[LinkCisco-(513)]\n\t_ = x[LinkLapb-(516)]\n\t_ = x[LinkDdcmp-(517)]\n\t_ = x[LinkRawhdlc-(518)]\n\t_ = x[LinkTunnel-(768)]\n\t_ = x[LinkTunnel6-(769)]\n\t_ = x[LinkFrad-(770)]\n\t_ = x[LinkSkip-(771)]\n\t_ = x[LinkLoopbck-(772)]\n\t_ = x[LinkLocaltlk-(773)]\n\t_ = x[LinkFddi-(774)]\n\t_ = x[LinkBif-(775)]\n\t_ = x[LinkSit-(776)]\n\t_ = x[LinkIpddp-(777)]\n\t_ = x[LinkIpgre-(778)]\n\t_ = x[LinkPimreg-(779)]\n\t_ = x[LinkHippi-(780)]\n\t_ = x[LinkAsh-(781)]\n\t_ = x[LinkEconet-(782)]\n\t_ = x[LinkIrda-(783)]\n\t_ = x[LinkFcpp-(784)]\n\t_ = x[LinkFcal-(785)]\n\t_ = x[LinkFcpl-(786)]\n\t_ = x[LinkFcfabric-(787)]\n\t_ = x[LinkFcfabric1-(788)]\n\t_ = x[LinkFcfabric2-(789)]\n\t_ = x[LinkFcfabric3-(790)]\n\t_ = x[LinkFcfabric4-(791)]\n\t_ = x[LinkFcfabric5-(792)]\n\t_ = x[LinkFcfabric6-(793)]\n\t_ = x[LinkFcfabric7-(794)]\n\t_ = x[LinkFcfabric8-(795)]\n\t_ = x[LinkFcfabric9-(796)]\n\t_ = x[LinkFcfabric10-(797)]\n\t_ = x[LinkFcfabric11-(798)]\n\t_ = x[LinkFcfabric12-(799)]\n\t_ = x[LinkIee802tr-(800)]\n\t_ = x[LinkIee80211-(801)]\n\t_ = x[LinkIee80211prism-(802)]\n\t_ = x[LinkIee80211Radiotap-(803)]\n\t_ = x[LinkIee8021154-(804)]\n\t_ = x[LinkIee8021154monitor-(805)]\n\t_ = x[LinkPhonet-(820)]\n\t_ = x[LinkPhonetpipe-(821)]\n\t_ = x[LinkCaif-(822)]\n\t_ = x[LinkIP6gre-(823)]\n\t_ = x[LinkNetlink-(824)]\n\t_ = x[Link6Lowpan-(825)]\n\t_ = x[LinkNone-(65534)]\n\t_ = x[LinkVoid-(65535)]\n}\n\nvar _LinkTypeValues = []LinkType{LinkNetrom, LinkEther, LinkEether, LinkAx25, LinkPronet, LinkChaos, LinkIee802, LinkArcnet, LinkAtalk, LinkDlci, LinkAtm, LinkMetricom, LinkIeee1394, LinkEui64, LinkInfiniband, LinkSlip, LinkCslip, LinkSlip6, LinkCslip6, LinkRsrvd, LinkAdapt, LinkRose, LinkX25, LinkHwx25, LinkCan, LinkPpp, LinkCisco, LinkLapb, LinkDdcmp, LinkRawhdlc, LinkTunnel, LinkTunnel6, LinkFrad, LinkSkip, LinkLoopbck, LinkLocaltlk, LinkFddi, LinkBif, LinkSit, LinkIpddp, LinkIpgre, LinkPimreg, LinkHippi, LinkAsh, LinkEconet, LinkIrda, LinkFcpp, LinkFcal, LinkFcpl, LinkFcfabric, LinkFcfabric1, LinkFcfabric2, LinkFcfabric3, LinkFcfabric4, LinkFcfabric5, LinkFcfabric6, LinkFcfabric7, LinkFcfabric8, LinkFcfabric9, LinkFcfabric10, LinkFcfabric11, LinkFcfabric12, LinkIee802tr, LinkIee80211, LinkIee80211prism, LinkIee80211Radiotap, LinkIee8021154, LinkIee8021154monitor, LinkPhonet, LinkPhonetpipe, LinkCaif, LinkIP6gre, LinkNetlink, Link6Lowpan, LinkNone, LinkVoid}\n\nvar _LinkTypeNameToValueMap = map[string]LinkType{\n\t_LinkTypeName[0:6]:          LinkNetrom,\n\t_LinkTypeLowerName[0:6]:     LinkNetrom,\n\t_LinkTypeName[6:11]:         LinkEther,\n\t_LinkTypeLowerName[6:11]:    LinkEther,\n\t_LinkTypeName[11:17]:        LinkEether,\n\t_LinkTypeLowerName[11:17]:   LinkEether,\n\t_LinkTypeName[17:21]:        LinkAx25,\n\t_LinkTypeLowerName[17:21]:   LinkAx25,\n\t_LinkTypeName[21:27]:        LinkPronet,\n\t_LinkTypeLowerName[21:27]:   LinkPronet,\n\t_LinkTypeName[27:32]:        LinkChaos,\n\t_LinkTypeLowerName[27:32]:   LinkChaos,\n\t_LinkTypeName[32:39]:        LinkIee802,\n\t_LinkTypeLowerName[32:39]:   LinkIee802,\n\t_LinkTypeName[39:45]:        LinkArcnet,\n\t_LinkTypeLowerName[39:45]:   LinkArcnet,\n\t_LinkTypeName[45:50]:        LinkAtalk,\n\t_LinkTypeLowerName[45:50]:   LinkAtalk,\n\t_LinkTypeName[50:54]:        LinkDlci,\n\t_LinkTypeLowerName[50:54]:   LinkDlci,\n\t_LinkTypeName[54:57]:        LinkAtm,\n\t_LinkTypeLowerName[54:57]:   LinkAtm,\n\t_LinkTypeName[57:65]:        LinkMetricom,\n\t_LinkTypeLowerName[57:65]:   LinkMetricom,\n\t_LinkTypeName[65:73]:        LinkIeee1394,\n\t_LinkTypeLowerName[65:73]:   LinkIeee1394,\n\t_LinkTypeName[73:78]:        LinkEui64,\n\t_LinkTypeLowerName[73:78]:   LinkEui64,\n\t_LinkTypeName[78:88]:        LinkInfiniband,\n\t_LinkTypeLowerName[78:88]:   LinkInfiniband,\n\t_LinkTypeName[88:92]:        LinkSlip,\n\t_LinkTypeLowerName[88:92]:   LinkSlip,\n\t_LinkTypeName[92:97]:        LinkCslip,\n\t_LinkTypeLowerName[92:97]:   LinkCslip,\n\t_LinkTypeName[97:102]:       LinkSlip6,\n\t_LinkTypeLowerName[97:102]:  LinkSlip6,\n\t_LinkTypeName[102:108]:      LinkCslip6,\n\t_LinkTypeLowerName[102:108]: LinkCslip6,\n\t_LinkTypeName[108:113]:      LinkRsrvd,\n\t_LinkTypeLowerName[108:113]: LinkRsrvd,\n\t_LinkTypeName[113:118]:      LinkAdapt,\n\t_LinkTypeLowerName[113:118]: LinkAdapt,\n\t_LinkTypeName[118:122]:      LinkRose,\n\t_LinkTypeLowerName[118:122]: LinkRose,\n\t_LinkTypeName[122:125]:      LinkX25,\n\t_LinkTypeLowerName[122:125]: LinkX25,\n\t_LinkTypeName[125:130]:      LinkHwx25,\n\t_LinkTypeLowerName[125:130]: LinkHwx25,\n\t_LinkTypeName[130:133]:      LinkCan,\n\t_LinkTypeLowerName[130:133]: LinkCan,\n\t_LinkTypeName[133:136]:      LinkPpp,\n\t_LinkTypeLowerName[133:136]: LinkPpp,\n\t_LinkTypeName[136:141]:      LinkCisco,\n\t_LinkTypeLowerName[136:141]: LinkCisco,\n\t_LinkTypeName[141:145]:      LinkLapb,\n\t_LinkTypeLowerName[141:145]: LinkLapb,\n\t_LinkTypeName[145:150]:      LinkDdcmp,\n\t_LinkTypeLowerName[145:150]: LinkDdcmp,\n\t_LinkTypeName[150:157]:      LinkRawhdlc,\n\t_LinkTypeLowerName[150:157]: LinkRawhdlc,\n\t_LinkTypeName[157:161]:      LinkTunnel,\n\t_LinkTypeLowerName[157:161]: LinkTunnel,\n\t_LinkTypeName[161:168]:      LinkTunnel6,\n\t_LinkTypeLowerName[161:168]: LinkTunnel6,\n\t_LinkTypeName[168:172]:      LinkFrad,\n\t_LinkTypeLowerName[168:172]: LinkFrad,\n\t_LinkTypeName[172:176]:      LinkSkip,\n\t_LinkTypeLowerName[172:176]: LinkSkip,\n\t_LinkTypeName[176:184]:      LinkLoopbck,\n\t_LinkTypeLowerName[176:184]: LinkLoopbck,\n\t_LinkTypeName[184:192]:      LinkLocaltlk,\n\t_LinkTypeLowerName[184:192]: LinkLocaltlk,\n\t_LinkTypeName[192:196]:      LinkFddi,\n\t_LinkTypeLowerName[192:196]: LinkFddi,\n\t_LinkTypeName[196:199]:      LinkBif,\n\t_LinkTypeLowerName[196:199]: LinkBif,\n\t_LinkTypeName[199:202]:      LinkSit,\n\t_LinkTypeLowerName[199:202]: LinkSit,\n\t_LinkTypeName[202:208]:      LinkIpddp,\n\t_LinkTypeLowerName[202:208]: LinkIpddp,\n\t_LinkTypeName[208:211]:      LinkIpgre,\n\t_LinkTypeLowerName[208:211]: LinkIpgre,\n\t_LinkTypeName[211:217]:      LinkPimreg,\n\t_LinkTypeLowerName[211:217]: LinkPimreg,\n\t_LinkTypeName[217:222]:      LinkHippi,\n\t_LinkTypeLowerName[217:222]: LinkHippi,\n\t_LinkTypeName[222:225]:      LinkAsh,\n\t_LinkTypeLowerName[222:225]: LinkAsh,\n\t_LinkTypeName[225:231]:      LinkEconet,\n\t_LinkTypeLowerName[225:231]: LinkEconet,\n\t_LinkTypeName[231:235]:      LinkIrda,\n\t_LinkTypeLowerName[231:235]: LinkIrda,\n\t_LinkTypeName[235:239]:      LinkFcpp,\n\t_LinkTypeLowerName[235:239]: LinkFcpp,\n\t_LinkTypeName[239:243]:      LinkFcal,\n\t_LinkTypeLowerName[239:243]: LinkFcal,\n\t_LinkTypeName[243:247]:      LinkFcpl,\n\t_LinkTypeLowerName[243:247]: LinkFcpl,\n\t_LinkTypeName[247:253]:      LinkFcfabric,\n\t_LinkTypeLowerName[247:253]: LinkFcfabric,\n\t_LinkTypeName[253:259]:      LinkFcfabric1,\n\t_LinkTypeLowerName[253:259]: LinkFcfabric1,\n\t_LinkTypeName[259:265]:      LinkFcfabric2,\n\t_LinkTypeLowerName[259:265]: LinkFcfabric2,\n\t_LinkTypeName[265:271]:      LinkFcfabric3,\n\t_LinkTypeLowerName[265:271]: LinkFcfabric3,\n\t_LinkTypeName[271:277]:      LinkFcfabric4,\n\t_LinkTypeLowerName[271:277]: LinkFcfabric4,\n\t_LinkTypeName[277:283]:      LinkFcfabric5,\n\t_LinkTypeLowerName[277:283]: LinkFcfabric5,\n\t_LinkTypeName[283:289]:      LinkFcfabric6,\n\t_LinkTypeLowerName[283:289]: LinkFcfabric6,\n\t_LinkTypeName[289:295]:      LinkFcfabric7,\n\t_LinkTypeLowerName[289:295]: LinkFcfabric7,\n\t_LinkTypeName[295:301]:      LinkFcfabric8,\n\t_LinkTypeLowerName[295:301]: LinkFcfabric8,\n\t_LinkTypeName[301:307]:      LinkFcfabric9,\n\t_LinkTypeLowerName[301:307]: LinkFcfabric9,\n\t_LinkTypeName[307:314]:      LinkFcfabric10,\n\t_LinkTypeLowerName[307:314]: LinkFcfabric10,\n\t_LinkTypeName[314:321]:      LinkFcfabric11,\n\t_LinkTypeLowerName[314:321]: LinkFcfabric11,\n\t_LinkTypeName[321:328]:      LinkFcfabric12,\n\t_LinkTypeLowerName[321:328]: LinkFcfabric12,\n\t_LinkTypeName[328:330]:      LinkIee802tr,\n\t_LinkTypeLowerName[328:330]: LinkIee802tr,\n\t_LinkTypeName[330:340]:      LinkIee80211,\n\t_LinkTypeLowerName[330:340]: LinkIee80211,\n\t_LinkTypeName[340:356]:      LinkIee80211prism,\n\t_LinkTypeLowerName[340:356]: LinkIee80211prism,\n\t_LinkTypeName[356:375]:      LinkIee80211Radiotap,\n\t_LinkTypeLowerName[356:375]: LinkIee80211Radiotap,\n\t_LinkTypeName[375:387]:      LinkIee8021154,\n\t_LinkTypeLowerName[375:387]: LinkIee8021154,\n\t_LinkTypeName[387:407]:      LinkIee8021154monitor,\n\t_LinkTypeLowerName[387:407]: LinkIee8021154monitor,\n\t_LinkTypeName[407:413]:      LinkPhonet,\n\t_LinkTypeLowerName[407:413]: LinkPhonet,\n\t_LinkTypeName[413:424]:      LinkPhonetpipe,\n\t_LinkTypeLowerName[413:424]: LinkPhonetpipe,\n\t_LinkTypeName[424:428]:      LinkCaif,\n\t_LinkTypeLowerName[424:428]: LinkCaif,\n\t_LinkTypeName[428:434]:      LinkIP6gre,\n\t_LinkTypeLowerName[428:434]: LinkIP6gre,\n\t_LinkTypeName[434:441]:      LinkNetlink,\n\t_LinkTypeLowerName[434:441]: LinkNetlink,\n\t_LinkTypeName[441:448]:      Link6Lowpan,\n\t_LinkTypeLowerName[441:448]: Link6Lowpan,\n\t_LinkTypeName[448:453]:      LinkNone,\n\t_LinkTypeLowerName[448:453]: LinkNone,\n\t_LinkTypeName[453:457]:      LinkVoid,\n\t_LinkTypeLowerName[453:457]: LinkVoid,\n}\n\nvar _LinkTypeNames = []string{\n\t_LinkTypeName[0:6],\n\t_LinkTypeName[6:11],\n\t_LinkTypeName[11:17],\n\t_LinkTypeName[17:21],\n\t_LinkTypeName[21:27],\n\t_LinkTypeName[27:32],\n\t_LinkTypeName[32:39],\n\t_LinkTypeName[39:45],\n\t_LinkTypeName[45:50],\n\t_LinkTypeName[50:54],\n\t_LinkTypeName[54:57],\n\t_LinkTypeName[57:65],\n\t_LinkTypeName[65:73],\n\t_LinkTypeName[73:78],\n\t_LinkTypeName[78:88],\n\t_LinkTypeName[88:92],\n\t_LinkTypeName[92:97],\n\t_LinkTypeName[97:102],\n\t_LinkTypeName[102:108],\n\t_LinkTypeName[108:113],\n\t_LinkTypeName[113:118],\n\t_LinkTypeName[118:122],\n\t_LinkTypeName[122:125],\n\t_LinkTypeName[125:130],\n\t_LinkTypeName[130:133],\n\t_LinkTypeName[133:136],\n\t_LinkTypeName[136:141],\n\t_LinkTypeName[141:145],\n\t_LinkTypeName[145:150],\n\t_LinkTypeName[150:157],\n\t_LinkTypeName[157:161],\n\t_LinkTypeName[161:168],\n\t_LinkTypeName[168:172],\n\t_LinkTypeName[172:176],\n\t_LinkTypeName[176:184],\n\t_LinkTypeName[184:192],\n\t_LinkTypeName[192:196],\n\t_LinkTypeName[196:199],\n\t_LinkTypeName[199:202],\n\t_LinkTypeName[202:208],\n\t_LinkTypeName[208:211],\n\t_LinkTypeName[211:217],\n\t_LinkTypeName[217:222],\n\t_LinkTypeName[222:225],\n\t_LinkTypeName[225:231],\n\t_LinkTypeName[231:235],\n\t_LinkTypeName[235:239],\n\t_LinkTypeName[239:243],\n\t_LinkTypeName[243:247],\n\t_LinkTypeName[247:253],\n\t_LinkTypeName[253:259],\n\t_LinkTypeName[259:265],\n\t_LinkTypeName[265:271],\n\t_LinkTypeName[271:277],\n\t_LinkTypeName[277:283],\n\t_LinkTypeName[283:289],\n\t_LinkTypeName[289:295],\n\t_LinkTypeName[295:301],\n\t_LinkTypeName[301:307],\n\t_LinkTypeName[307:314],\n\t_LinkTypeName[314:321],\n\t_LinkTypeName[321:328],\n\t_LinkTypeName[328:330],\n\t_LinkTypeName[330:340],\n\t_LinkTypeName[340:356],\n\t_LinkTypeName[356:375],\n\t_LinkTypeName[375:387],\n\t_LinkTypeName[387:407],\n\t_LinkTypeName[407:413],\n\t_LinkTypeName[413:424],\n\t_LinkTypeName[424:428],\n\t_LinkTypeName[428:434],\n\t_LinkTypeName[434:441],\n\t_LinkTypeName[441:448],\n\t_LinkTypeName[448:453],\n\t_LinkTypeName[453:457],\n}\n\n// LinkTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc LinkTypeString(s string) (LinkType, error) {\n\tif val, ok := _LinkTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _LinkTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to LinkType values\", s)\n}\n\n// LinkTypeValues returns all values of the enum\nfunc LinkTypeValues() []LinkType {\n\treturn _LinkTypeValues\n}\n\n// LinkTypeStrings returns a slice of all String values of the enum\nfunc LinkTypeStrings() []string {\n\tstrs := make([]string, len(_LinkTypeNames))\n\tcopy(strs, _LinkTypeNames)\n\treturn strs\n}\n\n// IsALinkType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i LinkType) IsALinkType() bool {\n\t_, ok := _LinkTypeMap[i]\n\treturn ok\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for LinkType\nfunc (i LinkType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for LinkType\nfunc (i *LinkType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = LinkTypeString(string(text))\n\treturn err\n}\n\nconst _MatchOperatorName = \"==!=\"\n\nvar _MatchOperatorIndex = [...]uint8{0, 2, 4}\n\nconst _MatchOperatorLowerName = \"==!=\"\n\nfunc (i MatchOperator) String() string {\n\tif i < 0 || i >= MatchOperator(len(_MatchOperatorIndex)-1) {\n\t\treturn fmt.Sprintf(\"MatchOperator(%d)\", i)\n\t}\n\treturn _MatchOperatorName[_MatchOperatorIndex[i]:_MatchOperatorIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _MatchOperatorNoOp() {\n\tvar x [1]struct{}\n\t_ = x[OperatorEqual-(0)]\n\t_ = x[OperatorNotEqual-(1)]\n}\n\nvar _MatchOperatorValues = []MatchOperator{OperatorEqual, OperatorNotEqual}\n\nvar _MatchOperatorNameToValueMap = map[string]MatchOperator{\n\t_MatchOperatorName[0:2]:      OperatorEqual,\n\t_MatchOperatorLowerName[0:2]: OperatorEqual,\n\t_MatchOperatorName[2:4]:      OperatorNotEqual,\n\t_MatchOperatorLowerName[2:4]: OperatorNotEqual,\n}\n\nvar _MatchOperatorNames = []string{\n\t_MatchOperatorName[0:2],\n\t_MatchOperatorName[2:4],\n}\n\n// MatchOperatorString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc MatchOperatorString(s string) (MatchOperator, error) {\n\tif val, ok := _MatchOperatorNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _MatchOperatorNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to MatchOperator values\", s)\n}\n\n// MatchOperatorValues returns all values of the enum\nfunc MatchOperatorValues() []MatchOperator {\n\treturn _MatchOperatorValues\n}\n\n// MatchOperatorStrings returns a slice of all String values of the enum\nfunc MatchOperatorStrings() []string {\n\tstrs := make([]string, len(_MatchOperatorNames))\n\tcopy(strs, _MatchOperatorNames)\n\treturn strs\n}\n\n// IsAMatchOperator returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i MatchOperator) IsAMatchOperator() bool {\n\tfor _, v := range _MatchOperatorValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for MatchOperator\nfunc (i MatchOperator) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for MatchOperator\nfunc (i *MatchOperator) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = MatchOperatorString(string(text))\n\treturn err\n}\n\nconst _NfTablesChainHookName = \"preroutinginputforwardoutputpostrouting\"\n\nvar _NfTablesChainHookIndex = [...]uint8{0, 10, 15, 22, 28, 39}\n\nconst _NfTablesChainHookLowerName = \"preroutinginputforwardoutputpostrouting\"\n\nfunc (i NfTablesChainHook) String() string {\n\tif i >= NfTablesChainHook(len(_NfTablesChainHookIndex)-1) {\n\t\treturn fmt.Sprintf(\"NfTablesChainHook(%d)\", i)\n\t}\n\treturn _NfTablesChainHookName[_NfTablesChainHookIndex[i]:_NfTablesChainHookIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _NfTablesChainHookNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ChainHookPrerouting-(0)]\n\t_ = x[ChainHookInput-(1)]\n\t_ = x[ChainHookForward-(2)]\n\t_ = x[ChainHookOutput-(3)]\n\t_ = x[ChainHookPostrouting-(4)]\n}\n\nvar _NfTablesChainHookValues = []NfTablesChainHook{ChainHookPrerouting, ChainHookInput, ChainHookForward, ChainHookOutput, ChainHookPostrouting}\n\nvar _NfTablesChainHookNameToValueMap = map[string]NfTablesChainHook{\n\t_NfTablesChainHookName[0:10]:       ChainHookPrerouting,\n\t_NfTablesChainHookLowerName[0:10]:  ChainHookPrerouting,\n\t_NfTablesChainHookName[10:15]:      ChainHookInput,\n\t_NfTablesChainHookLowerName[10:15]: ChainHookInput,\n\t_NfTablesChainHookName[15:22]:      ChainHookForward,\n\t_NfTablesChainHookLowerName[15:22]: ChainHookForward,\n\t_NfTablesChainHookName[22:28]:      ChainHookOutput,\n\t_NfTablesChainHookLowerName[22:28]: ChainHookOutput,\n\t_NfTablesChainHookName[28:39]:      ChainHookPostrouting,\n\t_NfTablesChainHookLowerName[28:39]: ChainHookPostrouting,\n}\n\nvar _NfTablesChainHookNames = []string{\n\t_NfTablesChainHookName[0:10],\n\t_NfTablesChainHookName[10:15],\n\t_NfTablesChainHookName[15:22],\n\t_NfTablesChainHookName[22:28],\n\t_NfTablesChainHookName[28:39],\n}\n\n// NfTablesChainHookString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc NfTablesChainHookString(s string) (NfTablesChainHook, error) {\n\tif val, ok := _NfTablesChainHookNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _NfTablesChainHookNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to NfTablesChainHook values\", s)\n}\n\n// NfTablesChainHookValues returns all values of the enum\nfunc NfTablesChainHookValues() []NfTablesChainHook {\n\treturn _NfTablesChainHookValues\n}\n\n// NfTablesChainHookStrings returns a slice of all String values of the enum\nfunc NfTablesChainHookStrings() []string {\n\tstrs := make([]string, len(_NfTablesChainHookNames))\n\tcopy(strs, _NfTablesChainHookNames)\n\treturn strs\n}\n\n// IsANfTablesChainHook returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i NfTablesChainHook) IsANfTablesChainHook() bool {\n\tfor _, v := range _NfTablesChainHookValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for NfTablesChainHook\nfunc (i NfTablesChainHook) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for NfTablesChainHook\nfunc (i *NfTablesChainHook) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = NfTablesChainHookString(string(text))\n\treturn err\n}\n\nconst _NfTablesChainPriorityName = \"firstconntrack-defragrawselinux-firstconntrackmanglenat-destfiltersecuritynat-sourceselinux-lastconntrack-helperlast\"\nconst _NfTablesChainPriorityLowerName = \"firstconntrack-defragrawselinux-firstconntrackmanglenat-destfiltersecuritynat-sourceselinux-lastconntrack-helperlast\"\n\nvar _NfTablesChainPriorityMap = map[NfTablesChainPriority]string{\n\t-2147483648: _NfTablesChainPriorityName[0:5],\n\t-400:        _NfTablesChainPriorityName[5:21],\n\t-300:        _NfTablesChainPriorityName[21:24],\n\t-225:        _NfTablesChainPriorityName[24:37],\n\t-200:        _NfTablesChainPriorityName[37:46],\n\t-150:        _NfTablesChainPriorityName[46:52],\n\t-100:        _NfTablesChainPriorityName[52:60],\n\t0:           _NfTablesChainPriorityName[60:66],\n\t50:          _NfTablesChainPriorityName[66:74],\n\t100:         _NfTablesChainPriorityName[74:84],\n\t225:         _NfTablesChainPriorityName[84:96],\n\t300:         _NfTablesChainPriorityName[96:112],\n\t2147483647:  _NfTablesChainPriorityName[112:116],\n}\n\nfunc (i NfTablesChainPriority) String() string {\n\tif str, ok := _NfTablesChainPriorityMap[i]; ok {\n\t\treturn str\n\t}\n\treturn fmt.Sprintf(\"NfTablesChainPriority(%d)\", i)\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _NfTablesChainPriorityNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ChainPriorityFirst-(-2147483648)]\n\t_ = x[ChainPriorityConntrackDefrag-(-400)]\n\t_ = x[ChainPriorityRaw-(-300)]\n\t_ = x[ChainPrioritySELinuxFirst-(-225)]\n\t_ = x[ChainPriorityConntrack-(-200)]\n\t_ = x[ChainPriorityMangle-(-150)]\n\t_ = x[ChainPriorityNATDest-(-100)]\n\t_ = x[ChainPriorityFilter-(0)]\n\t_ = x[ChainPrioritySecurity-(50)]\n\t_ = x[ChainPriorityNATSource-(100)]\n\t_ = x[ChainPrioritySELinuxLast-(225)]\n\t_ = x[ChainPriorityConntrackHelper-(300)]\n\t_ = x[ChainPriorityLast-(2147483647)]\n}\n\nvar _NfTablesChainPriorityValues = []NfTablesChainPriority{ChainPriorityFirst, ChainPriorityConntrackDefrag, ChainPriorityRaw, ChainPrioritySELinuxFirst, ChainPriorityConntrack, ChainPriorityMangle, ChainPriorityNATDest, ChainPriorityFilter, ChainPrioritySecurity, ChainPriorityNATSource, ChainPrioritySELinuxLast, ChainPriorityConntrackHelper, ChainPriorityLast}\n\nvar _NfTablesChainPriorityNameToValueMap = map[string]NfTablesChainPriority{\n\t_NfTablesChainPriorityName[0:5]:          ChainPriorityFirst,\n\t_NfTablesChainPriorityLowerName[0:5]:     ChainPriorityFirst,\n\t_NfTablesChainPriorityName[5:21]:         ChainPriorityConntrackDefrag,\n\t_NfTablesChainPriorityLowerName[5:21]:    ChainPriorityConntrackDefrag,\n\t_NfTablesChainPriorityName[21:24]:        ChainPriorityRaw,\n\t_NfTablesChainPriorityLowerName[21:24]:   ChainPriorityRaw,\n\t_NfTablesChainPriorityName[24:37]:        ChainPrioritySELinuxFirst,\n\t_NfTablesChainPriorityLowerName[24:37]:   ChainPrioritySELinuxFirst,\n\t_NfTablesChainPriorityName[37:46]:        ChainPriorityConntrack,\n\t_NfTablesChainPriorityLowerName[37:46]:   ChainPriorityConntrack,\n\t_NfTablesChainPriorityName[46:52]:        ChainPriorityMangle,\n\t_NfTablesChainPriorityLowerName[46:52]:   ChainPriorityMangle,\n\t_NfTablesChainPriorityName[52:60]:        ChainPriorityNATDest,\n\t_NfTablesChainPriorityLowerName[52:60]:   ChainPriorityNATDest,\n\t_NfTablesChainPriorityName[60:66]:        ChainPriorityFilter,\n\t_NfTablesChainPriorityLowerName[60:66]:   ChainPriorityFilter,\n\t_NfTablesChainPriorityName[66:74]:        ChainPrioritySecurity,\n\t_NfTablesChainPriorityLowerName[66:74]:   ChainPrioritySecurity,\n\t_NfTablesChainPriorityName[74:84]:        ChainPriorityNATSource,\n\t_NfTablesChainPriorityLowerName[74:84]:   ChainPriorityNATSource,\n\t_NfTablesChainPriorityName[84:96]:        ChainPrioritySELinuxLast,\n\t_NfTablesChainPriorityLowerName[84:96]:   ChainPrioritySELinuxLast,\n\t_NfTablesChainPriorityName[96:112]:       ChainPriorityConntrackHelper,\n\t_NfTablesChainPriorityLowerName[96:112]:  ChainPriorityConntrackHelper,\n\t_NfTablesChainPriorityName[112:116]:      ChainPriorityLast,\n\t_NfTablesChainPriorityLowerName[112:116]: ChainPriorityLast,\n}\n\nvar _NfTablesChainPriorityNames = []string{\n\t_NfTablesChainPriorityName[0:5],\n\t_NfTablesChainPriorityName[5:21],\n\t_NfTablesChainPriorityName[21:24],\n\t_NfTablesChainPriorityName[24:37],\n\t_NfTablesChainPriorityName[37:46],\n\t_NfTablesChainPriorityName[46:52],\n\t_NfTablesChainPriorityName[52:60],\n\t_NfTablesChainPriorityName[60:66],\n\t_NfTablesChainPriorityName[66:74],\n\t_NfTablesChainPriorityName[74:84],\n\t_NfTablesChainPriorityName[84:96],\n\t_NfTablesChainPriorityName[96:112],\n\t_NfTablesChainPriorityName[112:116],\n}\n\n// NfTablesChainPriorityString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc NfTablesChainPriorityString(s string) (NfTablesChainPriority, error) {\n\tif val, ok := _NfTablesChainPriorityNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _NfTablesChainPriorityNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to NfTablesChainPriority values\", s)\n}\n\n// NfTablesChainPriorityValues returns all values of the enum\nfunc NfTablesChainPriorityValues() []NfTablesChainPriority {\n\treturn _NfTablesChainPriorityValues\n}\n\n// NfTablesChainPriorityStrings returns a slice of all String values of the enum\nfunc NfTablesChainPriorityStrings() []string {\n\tstrs := make([]string, len(_NfTablesChainPriorityNames))\n\tcopy(strs, _NfTablesChainPriorityNames)\n\treturn strs\n}\n\n// IsANfTablesChainPriority returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i NfTablesChainPriority) IsANfTablesChainPriority() bool {\n\t_, ok := _NfTablesChainPriorityMap[i]\n\treturn ok\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for NfTablesChainPriority\nfunc (i NfTablesChainPriority) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for NfTablesChainPriority\nfunc (i *NfTablesChainPriority) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = NfTablesChainPriorityString(string(text))\n\treturn err\n}\n\nconst _NfTablesVerdictName = \"dropaccept\"\n\nvar _NfTablesVerdictIndex = [...]uint8{0, 4, 10}\n\nconst _NfTablesVerdictLowerName = \"dropaccept\"\n\nfunc (i NfTablesVerdict) String() string {\n\tif i < 0 || i >= NfTablesVerdict(len(_NfTablesVerdictIndex)-1) {\n\t\treturn fmt.Sprintf(\"NfTablesVerdict(%d)\", i)\n\t}\n\treturn _NfTablesVerdictName[_NfTablesVerdictIndex[i]:_NfTablesVerdictIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _NfTablesVerdictNoOp() {\n\tvar x [1]struct{}\n\t_ = x[VerdictDrop-(0)]\n\t_ = x[VerdictAccept-(1)]\n}\n\nvar _NfTablesVerdictValues = []NfTablesVerdict{VerdictDrop, VerdictAccept}\n\nvar _NfTablesVerdictNameToValueMap = map[string]NfTablesVerdict{\n\t_NfTablesVerdictName[0:4]:       VerdictDrop,\n\t_NfTablesVerdictLowerName[0:4]:  VerdictDrop,\n\t_NfTablesVerdictName[4:10]:      VerdictAccept,\n\t_NfTablesVerdictLowerName[4:10]: VerdictAccept,\n}\n\nvar _NfTablesVerdictNames = []string{\n\t_NfTablesVerdictName[0:4],\n\t_NfTablesVerdictName[4:10],\n}\n\n// NfTablesVerdictString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc NfTablesVerdictString(s string) (NfTablesVerdict, error) {\n\tif val, ok := _NfTablesVerdictNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _NfTablesVerdictNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to NfTablesVerdict values\", s)\n}\n\n// NfTablesVerdictValues returns all values of the enum\nfunc NfTablesVerdictValues() []NfTablesVerdict {\n\treturn _NfTablesVerdictValues\n}\n\n// NfTablesVerdictStrings returns a slice of all String values of the enum\nfunc NfTablesVerdictStrings() []string {\n\tstrs := make([]string, len(_NfTablesVerdictNames))\n\tcopy(strs, _NfTablesVerdictNames)\n\treturn strs\n}\n\n// IsANfTablesVerdict returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i NfTablesVerdict) IsANfTablesVerdict() bool {\n\tfor _, v := range _NfTablesVerdictValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for NfTablesVerdict\nfunc (i NfTablesVerdict) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for NfTablesVerdict\nfunc (i *NfTablesVerdict) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = NfTablesVerdictString(string(text))\n\treturn err\n}\n\nconst _OperationalStateName = \"unknownnotPresentdownlowerLayerDowntestingdormantup\"\n\nvar _OperationalStateIndex = [...]uint8{0, 7, 17, 21, 35, 42, 49, 51}\n\nconst _OperationalStateLowerName = \"unknownnotpresentdownlowerlayerdowntestingdormantup\"\n\nfunc (i OperationalState) String() string {\n\tif i >= OperationalState(len(_OperationalStateIndex)-1) {\n\t\treturn fmt.Sprintf(\"OperationalState(%d)\", i)\n\t}\n\treturn _OperationalStateName[_OperationalStateIndex[i]:_OperationalStateIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _OperationalStateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[OperStateUnknown-(0)]\n\t_ = x[OperStateNotPresent-(1)]\n\t_ = x[OperStateDown-(2)]\n\t_ = x[OperStateLowerLayerDown-(3)]\n\t_ = x[OperStateTesting-(4)]\n\t_ = x[OperStateDormant-(5)]\n\t_ = x[OperStateUp-(6)]\n}\n\nvar _OperationalStateValues = []OperationalState{OperStateUnknown, OperStateNotPresent, OperStateDown, OperStateLowerLayerDown, OperStateTesting, OperStateDormant, OperStateUp}\n\nvar _OperationalStateNameToValueMap = map[string]OperationalState{\n\t_OperationalStateName[0:7]:        OperStateUnknown,\n\t_OperationalStateLowerName[0:7]:   OperStateUnknown,\n\t_OperationalStateName[7:17]:       OperStateNotPresent,\n\t_OperationalStateLowerName[7:17]:  OperStateNotPresent,\n\t_OperationalStateName[17:21]:      OperStateDown,\n\t_OperationalStateLowerName[17:21]: OperStateDown,\n\t_OperationalStateName[21:35]:      OperStateLowerLayerDown,\n\t_OperationalStateLowerName[21:35]: OperStateLowerLayerDown,\n\t_OperationalStateName[35:42]:      OperStateTesting,\n\t_OperationalStateLowerName[35:42]: OperStateTesting,\n\t_OperationalStateName[42:49]:      OperStateDormant,\n\t_OperationalStateLowerName[42:49]: OperStateDormant,\n\t_OperationalStateName[49:51]:      OperStateUp,\n\t_OperationalStateLowerName[49:51]: OperStateUp,\n}\n\nvar _OperationalStateNames = []string{\n\t_OperationalStateName[0:7],\n\t_OperationalStateName[7:17],\n\t_OperationalStateName[17:21],\n\t_OperationalStateName[21:35],\n\t_OperationalStateName[35:42],\n\t_OperationalStateName[42:49],\n\t_OperationalStateName[49:51],\n}\n\n// OperationalStateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc OperationalStateString(s string) (OperationalState, error) {\n\tif val, ok := _OperationalStateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _OperationalStateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to OperationalState values\", s)\n}\n\n// OperationalStateValues returns all values of the enum\nfunc OperationalStateValues() []OperationalState {\n\treturn _OperationalStateValues\n}\n\n// OperationalStateStrings returns a slice of all String values of the enum\nfunc OperationalStateStrings() []string {\n\tstrs := make([]string, len(_OperationalStateNames))\n\tcopy(strs, _OperationalStateNames)\n\treturn strs\n}\n\n// IsAOperationalState returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i OperationalState) IsAOperationalState() bool {\n\tfor _, v := range _OperationalStateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for OperationalState\nfunc (i OperationalState) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for OperationalState\nfunc (i *OperationalState) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = OperationalStateString(string(text))\n\treturn err\n}\n\nconst (\n\t_PortName_0      = \"TwistedPairAUIMIIBNCDirectAttach\"\n\t_PortLowerName_0 = \"twistedpairauimiibncdirectattach\"\n\t_PortName_1      = \"None\"\n\t_PortLowerName_1 = \"none\"\n\t_PortName_2      = \"Other\"\n\t_PortLowerName_2 = \"other\"\n)\n\nvar (\n\t_PortIndex_0 = [...]uint8{0, 11, 14, 17, 17, 20, 32}\n\t_PortIndex_1 = [...]uint8{0, 4}\n\t_PortIndex_2 = [...]uint8{0, 5}\n)\n\nfunc (i Port) String() string {\n\tswitch {\n\tcase 0 <= i && i <= 5:\n\t\treturn _PortName_0[_PortIndex_0[i]:_PortIndex_0[i+1]]\n\tcase i == 239:\n\t\treturn _PortName_1\n\tcase i == 255:\n\t\treturn _PortName_2\n\tdefault:\n\t\treturn fmt.Sprintf(\"Port(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _PortNoOp() {\n\tvar x [1]struct{}\n\t_ = x[TwistedPair-(0)]\n\t_ = x[AUI-(1)]\n\t_ = x[MII-(2)]\n\t_ = x[Fibre-(3)]\n\t_ = x[BNC-(4)]\n\t_ = x[DirectAttach-(5)]\n\t_ = x[None-(239)]\n\t_ = x[Other-(255)]\n}\n\nvar _PortValues = []Port{TwistedPair, AUI, MII, Fibre, BNC, DirectAttach, None, Other}\n\nvar _PortNameToValueMap = map[string]Port{\n\t_PortName_0[0:11]:       TwistedPair,\n\t_PortLowerName_0[0:11]:  TwistedPair,\n\t_PortName_0[11:14]:      AUI,\n\t_PortLowerName_0[11:14]: AUI,\n\t_PortName_0[14:17]:      MII,\n\t_PortLowerName_0[14:17]: MII,\n\t_PortName_0[17:17]:      Fibre,\n\t_PortLowerName_0[17:17]: Fibre,\n\t_PortName_0[17:20]:      BNC,\n\t_PortLowerName_0[17:20]: BNC,\n\t_PortName_0[20:32]:      DirectAttach,\n\t_PortLowerName_0[20:32]: DirectAttach,\n\t_PortName_1[0:4]:        None,\n\t_PortLowerName_1[0:4]:   None,\n\t_PortName_2[0:5]:        Other,\n\t_PortLowerName_2[0:5]:   Other,\n}\n\nvar _PortNames = []string{\n\t_PortName_0[0:11],\n\t_PortName_0[11:14],\n\t_PortName_0[14:17],\n\t_PortName_0[17:17],\n\t_PortName_0[17:20],\n\t_PortName_0[20:32],\n\t_PortName_1[0:4],\n\t_PortName_2[0:5],\n}\n\n// PortString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc PortString(s string) (Port, error) {\n\tif val, ok := _PortNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _PortNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Port values\", s)\n}\n\n// PortValues returns all values of the enum\nfunc PortValues() []Port {\n\treturn _PortValues\n}\n\n// PortStrings returns a slice of all String values of the enum\nfunc PortStrings() []string {\n\tstrs := make([]string, len(_PortNames))\n\tcopy(strs, _PortNames)\n\treturn strs\n}\n\n// IsAPort returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Port) IsAPort() bool {\n\tfor _, v := range _PortValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Port\nfunc (i Port) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Port\nfunc (i *Port) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = PortString(string(text))\n\treturn err\n}\n\nconst _PrimaryReselectName = \"alwaysbetterfailure\"\n\nvar _PrimaryReselectIndex = [...]uint8{0, 6, 12, 19}\n\nconst _PrimaryReselectLowerName = \"alwaysbetterfailure\"\n\nfunc (i PrimaryReselect) String() string {\n\tif i >= PrimaryReselect(len(_PrimaryReselectIndex)-1) {\n\t\treturn fmt.Sprintf(\"PrimaryReselect(%d)\", i)\n\t}\n\treturn _PrimaryReselectName[_PrimaryReselectIndex[i]:_PrimaryReselectIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _PrimaryReselectNoOp() {\n\tvar x [1]struct{}\n\t_ = x[PrimaryReselectAlways-(0)]\n\t_ = x[PrimaryReselectBetter-(1)]\n\t_ = x[PrimaryReselectFailure-(2)]\n}\n\nvar _PrimaryReselectValues = []PrimaryReselect{PrimaryReselectAlways, PrimaryReselectBetter, PrimaryReselectFailure}\n\nvar _PrimaryReselectNameToValueMap = map[string]PrimaryReselect{\n\t_PrimaryReselectName[0:6]:        PrimaryReselectAlways,\n\t_PrimaryReselectLowerName[0:6]:   PrimaryReselectAlways,\n\t_PrimaryReselectName[6:12]:       PrimaryReselectBetter,\n\t_PrimaryReselectLowerName[6:12]:  PrimaryReselectBetter,\n\t_PrimaryReselectName[12:19]:      PrimaryReselectFailure,\n\t_PrimaryReselectLowerName[12:19]: PrimaryReselectFailure,\n}\n\nvar _PrimaryReselectNames = []string{\n\t_PrimaryReselectName[0:6],\n\t_PrimaryReselectName[6:12],\n\t_PrimaryReselectName[12:19],\n}\n\n// PrimaryReselectString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc PrimaryReselectString(s string) (PrimaryReselect, error) {\n\tif val, ok := _PrimaryReselectNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _PrimaryReselectNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to PrimaryReselect values\", s)\n}\n\n// PrimaryReselectValues returns all values of the enum\nfunc PrimaryReselectValues() []PrimaryReselect {\n\treturn _PrimaryReselectValues\n}\n\n// PrimaryReselectStrings returns a slice of all String values of the enum\nfunc PrimaryReselectStrings() []string {\n\tstrs := make([]string, len(_PrimaryReselectNames))\n\tcopy(strs, _PrimaryReselectNames)\n\treturn strs\n}\n\n// IsAPrimaryReselect returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i PrimaryReselect) IsAPrimaryReselect() bool {\n\tfor _, v := range _PrimaryReselectValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for PrimaryReselect\nfunc (i PrimaryReselect) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for PrimaryReselect\nfunc (i *PrimaryReselect) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = PrimaryReselectString(string(text))\n\treturn err\n}\n\nconst (\n\t_ProtocolName_0      = \"icmp\"\n\t_ProtocolLowerName_0 = \"icmp\"\n\t_ProtocolName_1      = \"tcp\"\n\t_ProtocolLowerName_1 = \"tcp\"\n\t_ProtocolName_2      = \"udp\"\n\t_ProtocolLowerName_2 = \"udp\"\n\t_ProtocolName_3      = \"icmpv6\"\n\t_ProtocolLowerName_3 = \"icmpv6\"\n)\n\nvar (\n\t_ProtocolIndex_0 = [...]uint8{0, 4}\n\t_ProtocolIndex_1 = [...]uint8{0, 3}\n\t_ProtocolIndex_2 = [...]uint8{0, 3}\n\t_ProtocolIndex_3 = [...]uint8{0, 6}\n)\n\nfunc (i Protocol) String() string {\n\tswitch {\n\tcase i == 1:\n\t\treturn _ProtocolName_0\n\tcase i == 6:\n\t\treturn _ProtocolName_1\n\tcase i == 17:\n\t\treturn _ProtocolName_2\n\tcase i == 58:\n\t\treturn _ProtocolName_3\n\tdefault:\n\t\treturn fmt.Sprintf(\"Protocol(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ProtocolNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ProtocolICMP-(1)]\n\t_ = x[ProtocolTCP-(6)]\n\t_ = x[ProtocolUDP-(17)]\n\t_ = x[ProtocolICMPv6-(58)]\n}\n\nvar _ProtocolValues = []Protocol{ProtocolICMP, ProtocolTCP, ProtocolUDP, ProtocolICMPv6}\n\nvar _ProtocolNameToValueMap = map[string]Protocol{\n\t_ProtocolName_0[0:4]:      ProtocolICMP,\n\t_ProtocolLowerName_0[0:4]: ProtocolICMP,\n\t_ProtocolName_1[0:3]:      ProtocolTCP,\n\t_ProtocolLowerName_1[0:3]: ProtocolTCP,\n\t_ProtocolName_2[0:3]:      ProtocolUDP,\n\t_ProtocolLowerName_2[0:3]: ProtocolUDP,\n\t_ProtocolName_3[0:6]:      ProtocolICMPv6,\n\t_ProtocolLowerName_3[0:6]: ProtocolICMPv6,\n}\n\nvar _ProtocolNames = []string{\n\t_ProtocolName_0[0:4],\n\t_ProtocolName_1[0:3],\n\t_ProtocolName_2[0:3],\n\t_ProtocolName_3[0:6],\n}\n\n// ProtocolString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ProtocolString(s string) (Protocol, error) {\n\tif val, ok := _ProtocolNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ProtocolNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Protocol values\", s)\n}\n\n// ProtocolValues returns all values of the enum\nfunc ProtocolValues() []Protocol {\n\treturn _ProtocolValues\n}\n\n// ProtocolStrings returns a slice of all String values of the enum\nfunc ProtocolStrings() []string {\n\tstrs := make([]string, len(_ProtocolNames))\n\tcopy(strs, _ProtocolNames)\n\treturn strs\n}\n\n// IsAProtocol returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Protocol) IsAProtocol() bool {\n\tfor _, v := range _ProtocolValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Protocol\nfunc (i Protocol) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Protocol\nfunc (i *Protocol) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ProtocolString(string(text))\n\treturn err\n}\n\nconst (\n\t_RouteFlagName_0      = \"notify\"\n\t_RouteFlagLowerName_0 = \"notify\"\n\t_RouteFlagName_1      = \"cloned\"\n\t_RouteFlagLowerName_1 = \"cloned\"\n\t_RouteFlagName_2      = \"equalize\"\n\t_RouteFlagLowerName_2 = \"equalize\"\n\t_RouteFlagName_3      = \"prefix\"\n\t_RouteFlagLowerName_3 = \"prefix\"\n\t_RouteFlagName_4      = \"lookup_table\"\n\t_RouteFlagLowerName_4 = \"lookup_table\"\n\t_RouteFlagName_5      = \"fib_match\"\n\t_RouteFlagLowerName_5 = \"fib_match\"\n\t_RouteFlagName_6      = \"offload\"\n\t_RouteFlagLowerName_6 = \"offload\"\n\t_RouteFlagName_7      = \"trap\"\n\t_RouteFlagLowerName_7 = \"trap\"\n)\n\nvar (\n\t_RouteFlagIndex_0 = [...]uint8{0, 6}\n\t_RouteFlagIndex_1 = [...]uint8{0, 6}\n\t_RouteFlagIndex_2 = [...]uint8{0, 8}\n\t_RouteFlagIndex_3 = [...]uint8{0, 6}\n\t_RouteFlagIndex_4 = [...]uint8{0, 12}\n\t_RouteFlagIndex_5 = [...]uint8{0, 9}\n\t_RouteFlagIndex_6 = [...]uint8{0, 7}\n\t_RouteFlagIndex_7 = [...]uint8{0, 4}\n)\n\nfunc (i RouteFlag) String() string {\n\tswitch {\n\tcase i == 256:\n\t\treturn _RouteFlagName_0\n\tcase i == 512:\n\t\treturn _RouteFlagName_1\n\tcase i == 1024:\n\t\treturn _RouteFlagName_2\n\tcase i == 2048:\n\t\treturn _RouteFlagName_3\n\tcase i == 4096:\n\t\treturn _RouteFlagName_4\n\tcase i == 8192:\n\t\treturn _RouteFlagName_5\n\tcase i == 16384:\n\t\treturn _RouteFlagName_6\n\tcase i == 32768:\n\t\treturn _RouteFlagName_7\n\tdefault:\n\t\treturn fmt.Sprintf(\"RouteFlag(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RouteFlagNoOp() {\n\tvar x [1]struct{}\n\t_ = x[RouteNotify-(256)]\n\t_ = x[RouteCloned-(512)]\n\t_ = x[RouteEqualize-(1024)]\n\t_ = x[RoutePrefix-(2048)]\n\t_ = x[RouteLookupTable-(4096)]\n\t_ = x[RouteFIBMatch-(8192)]\n\t_ = x[RouteOffload-(16384)]\n\t_ = x[RouteTrap-(32768)]\n}\n\nvar _RouteFlagValues = []RouteFlag{RouteNotify, RouteCloned, RouteEqualize, RoutePrefix, RouteLookupTable, RouteFIBMatch, RouteOffload, RouteTrap}\n\nvar _RouteFlagNameToValueMap = map[string]RouteFlag{\n\t_RouteFlagName_0[0:6]:       RouteNotify,\n\t_RouteFlagLowerName_0[0:6]:  RouteNotify,\n\t_RouteFlagName_1[0:6]:       RouteCloned,\n\t_RouteFlagLowerName_1[0:6]:  RouteCloned,\n\t_RouteFlagName_2[0:8]:       RouteEqualize,\n\t_RouteFlagLowerName_2[0:8]:  RouteEqualize,\n\t_RouteFlagName_3[0:6]:       RoutePrefix,\n\t_RouteFlagLowerName_3[0:6]:  RoutePrefix,\n\t_RouteFlagName_4[0:12]:      RouteLookupTable,\n\t_RouteFlagLowerName_4[0:12]: RouteLookupTable,\n\t_RouteFlagName_5[0:9]:       RouteFIBMatch,\n\t_RouteFlagLowerName_5[0:9]:  RouteFIBMatch,\n\t_RouteFlagName_6[0:7]:       RouteOffload,\n\t_RouteFlagLowerName_6[0:7]:  RouteOffload,\n\t_RouteFlagName_7[0:4]:       RouteTrap,\n\t_RouteFlagLowerName_7[0:4]:  RouteTrap,\n}\n\nvar _RouteFlagNames = []string{\n\t_RouteFlagName_0[0:6],\n\t_RouteFlagName_1[0:6],\n\t_RouteFlagName_2[0:8],\n\t_RouteFlagName_3[0:6],\n\t_RouteFlagName_4[0:12],\n\t_RouteFlagName_5[0:9],\n\t_RouteFlagName_6[0:7],\n\t_RouteFlagName_7[0:4],\n}\n\n// RouteFlagString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RouteFlagString(s string) (RouteFlag, error) {\n\tif val, ok := _RouteFlagNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RouteFlagNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RouteFlag values\", s)\n}\n\n// RouteFlagValues returns all values of the enum\nfunc RouteFlagValues() []RouteFlag {\n\treturn _RouteFlagValues\n}\n\n// RouteFlagStrings returns a slice of all String values of the enum\nfunc RouteFlagStrings() []string {\n\tstrs := make([]string, len(_RouteFlagNames))\n\tcopy(strs, _RouteFlagNames)\n\treturn strs\n}\n\n// IsARouteFlag returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RouteFlag) IsARouteFlag() bool {\n\tfor _, v := range _RouteFlagValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RouteFlag\nfunc (i RouteFlag) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RouteFlag\nfunc (i *RouteFlag) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RouteFlagString(string(text))\n\treturn err\n}\n\nconst (\n\t_RouteProtocolName_0      = \"unspecredirectkernelbootstatic\"\n\t_RouteProtocolLowerName_0 = \"unspecredirectkernelbootstatic\"\n\t_RouteProtocolName_1      = \"ramrtzebrabirddnroutedxorpntkdhcpmrtdkeepalived\"\n\t_RouteProtocolLowerName_1 = \"ramrtzebrabirddnroutedxorpntkdhcpmrtdkeepalived\"\n\t_RouteProtocolName_2      = \"babel\"\n\t_RouteProtocolLowerName_2 = \"babel\"\n\t_RouteProtocolName_3      = \"openr\"\n\t_RouteProtocolLowerName_3 = \"openr\"\n\t_RouteProtocolName_4      = \"bgpisisospfrip\"\n\t_RouteProtocolLowerName_4 = \"bgpisisospfrip\"\n\t_RouteProtocolName_5      = \"eigrp\"\n\t_RouteProtocolLowerName_5 = \"eigrp\"\n)\n\nvar (\n\t_RouteProtocolIndex_0 = [...]uint8{0, 6, 14, 20, 24, 30}\n\t_RouteProtocolIndex_1 = [...]uint8{0, 2, 5, 10, 14, 22, 26, 29, 33, 37, 47}\n\t_RouteProtocolIndex_2 = [...]uint8{0, 5}\n\t_RouteProtocolIndex_3 = [...]uint8{0, 5}\n\t_RouteProtocolIndex_4 = [...]uint8{0, 3, 7, 11, 14}\n\t_RouteProtocolIndex_5 = [...]uint8{0, 5}\n)\n\nfunc (i RouteProtocol) String() string {\n\tswitch {\n\tcase 0 <= i && i <= 4:\n\t\treturn _RouteProtocolName_0[_RouteProtocolIndex_0[i]:_RouteProtocolIndex_0[i+1]]\n\tcase 9 <= i && i <= 18:\n\t\ti -= 9\n\t\treturn _RouteProtocolName_1[_RouteProtocolIndex_1[i]:_RouteProtocolIndex_1[i+1]]\n\tcase i == 42:\n\t\treturn _RouteProtocolName_2\n\tcase i == 99:\n\t\treturn _RouteProtocolName_3\n\tcase 186 <= i && i <= 189:\n\t\ti -= 186\n\t\treturn _RouteProtocolName_4[_RouteProtocolIndex_4[i]:_RouteProtocolIndex_4[i+1]]\n\tcase i == 192:\n\t\treturn _RouteProtocolName_5\n\tdefault:\n\t\treturn fmt.Sprintf(\"RouteProtocol(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RouteProtocolNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ProtocolUnspec-(0)]\n\t_ = x[ProtocolRedirect-(1)]\n\t_ = x[ProtocolKernel-(2)]\n\t_ = x[ProtocolBoot-(3)]\n\t_ = x[ProtocolStatic-(4)]\n\t_ = x[ProtocolRA-(9)]\n\t_ = x[ProtocolMRT-(10)]\n\t_ = x[ProtocolZebra-(11)]\n\t_ = x[ProtocolBird-(12)]\n\t_ = x[ProtocolDnrouted-(13)]\n\t_ = x[ProtocolXorp-(14)]\n\t_ = x[ProtocolNTK-(15)]\n\t_ = x[ProtocolDHCP-(16)]\n\t_ = x[ProtocolMRTD-(17)]\n\t_ = x[ProtocolKeepalived-(18)]\n\t_ = x[ProtocolBabel-(42)]\n\t_ = x[ProtocolOpenr-(99)]\n\t_ = x[ProtocolBGP-(186)]\n\t_ = x[ProtocolISIS-(187)]\n\t_ = x[ProtocolOSPF-(188)]\n\t_ = x[ProtocolRIP-(189)]\n\t_ = x[ProtocolEIGRP-(192)]\n}\n\nvar _RouteProtocolValues = []RouteProtocol{ProtocolUnspec, ProtocolRedirect, ProtocolKernel, ProtocolBoot, ProtocolStatic, ProtocolRA, ProtocolMRT, ProtocolZebra, ProtocolBird, ProtocolDnrouted, ProtocolXorp, ProtocolNTK, ProtocolDHCP, ProtocolMRTD, ProtocolKeepalived, ProtocolBabel, ProtocolOpenr, ProtocolBGP, ProtocolISIS, ProtocolOSPF, ProtocolRIP, ProtocolEIGRP}\n\nvar _RouteProtocolNameToValueMap = map[string]RouteProtocol{\n\t_RouteProtocolName_0[0:6]:        ProtocolUnspec,\n\t_RouteProtocolLowerName_0[0:6]:   ProtocolUnspec,\n\t_RouteProtocolName_0[6:14]:       ProtocolRedirect,\n\t_RouteProtocolLowerName_0[6:14]:  ProtocolRedirect,\n\t_RouteProtocolName_0[14:20]:      ProtocolKernel,\n\t_RouteProtocolLowerName_0[14:20]: ProtocolKernel,\n\t_RouteProtocolName_0[20:24]:      ProtocolBoot,\n\t_RouteProtocolLowerName_0[20:24]: ProtocolBoot,\n\t_RouteProtocolName_0[24:30]:      ProtocolStatic,\n\t_RouteProtocolLowerName_0[24:30]: ProtocolStatic,\n\t_RouteProtocolName_1[0:2]:        ProtocolRA,\n\t_RouteProtocolLowerName_1[0:2]:   ProtocolRA,\n\t_RouteProtocolName_1[2:5]:        ProtocolMRT,\n\t_RouteProtocolLowerName_1[2:5]:   ProtocolMRT,\n\t_RouteProtocolName_1[5:10]:       ProtocolZebra,\n\t_RouteProtocolLowerName_1[5:10]:  ProtocolZebra,\n\t_RouteProtocolName_1[10:14]:      ProtocolBird,\n\t_RouteProtocolLowerName_1[10:14]: ProtocolBird,\n\t_RouteProtocolName_1[14:22]:      ProtocolDnrouted,\n\t_RouteProtocolLowerName_1[14:22]: ProtocolDnrouted,\n\t_RouteProtocolName_1[22:26]:      ProtocolXorp,\n\t_RouteProtocolLowerName_1[22:26]: ProtocolXorp,\n\t_RouteProtocolName_1[26:29]:      ProtocolNTK,\n\t_RouteProtocolLowerName_1[26:29]: ProtocolNTK,\n\t_RouteProtocolName_1[29:33]:      ProtocolDHCP,\n\t_RouteProtocolLowerName_1[29:33]: ProtocolDHCP,\n\t_RouteProtocolName_1[33:37]:      ProtocolMRTD,\n\t_RouteProtocolLowerName_1[33:37]: ProtocolMRTD,\n\t_RouteProtocolName_1[37:47]:      ProtocolKeepalived,\n\t_RouteProtocolLowerName_1[37:47]: ProtocolKeepalived,\n\t_RouteProtocolName_2[0:5]:        ProtocolBabel,\n\t_RouteProtocolLowerName_2[0:5]:   ProtocolBabel,\n\t_RouteProtocolName_3[0:5]:        ProtocolOpenr,\n\t_RouteProtocolLowerName_3[0:5]:   ProtocolOpenr,\n\t_RouteProtocolName_4[0:3]:        ProtocolBGP,\n\t_RouteProtocolLowerName_4[0:3]:   ProtocolBGP,\n\t_RouteProtocolName_4[3:7]:        ProtocolISIS,\n\t_RouteProtocolLowerName_4[3:7]:   ProtocolISIS,\n\t_RouteProtocolName_4[7:11]:       ProtocolOSPF,\n\t_RouteProtocolLowerName_4[7:11]:  ProtocolOSPF,\n\t_RouteProtocolName_4[11:14]:      ProtocolRIP,\n\t_RouteProtocolLowerName_4[11:14]: ProtocolRIP,\n\t_RouteProtocolName_5[0:5]:        ProtocolEIGRP,\n\t_RouteProtocolLowerName_5[0:5]:   ProtocolEIGRP,\n}\n\nvar _RouteProtocolNames = []string{\n\t_RouteProtocolName_0[0:6],\n\t_RouteProtocolName_0[6:14],\n\t_RouteProtocolName_0[14:20],\n\t_RouteProtocolName_0[20:24],\n\t_RouteProtocolName_0[24:30],\n\t_RouteProtocolName_1[0:2],\n\t_RouteProtocolName_1[2:5],\n\t_RouteProtocolName_1[5:10],\n\t_RouteProtocolName_1[10:14],\n\t_RouteProtocolName_1[14:22],\n\t_RouteProtocolName_1[22:26],\n\t_RouteProtocolName_1[26:29],\n\t_RouteProtocolName_1[29:33],\n\t_RouteProtocolName_1[33:37],\n\t_RouteProtocolName_1[37:47],\n\t_RouteProtocolName_2[0:5],\n\t_RouteProtocolName_3[0:5],\n\t_RouteProtocolName_4[0:3],\n\t_RouteProtocolName_4[3:7],\n\t_RouteProtocolName_4[7:11],\n\t_RouteProtocolName_4[11:14],\n\t_RouteProtocolName_5[0:5],\n}\n\n// RouteProtocolString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RouteProtocolString(s string) (RouteProtocol, error) {\n\tif val, ok := _RouteProtocolNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RouteProtocolNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RouteProtocol values\", s)\n}\n\n// RouteProtocolValues returns all values of the enum\nfunc RouteProtocolValues() []RouteProtocol {\n\treturn _RouteProtocolValues\n}\n\n// RouteProtocolStrings returns a slice of all String values of the enum\nfunc RouteProtocolStrings() []string {\n\tstrs := make([]string, len(_RouteProtocolNames))\n\tcopy(strs, _RouteProtocolNames)\n\treturn strs\n}\n\n// IsARouteProtocol returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RouteProtocol) IsARouteProtocol() bool {\n\tfor _, v := range _RouteProtocolValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RouteProtocol\nfunc (i RouteProtocol) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RouteProtocol\nfunc (i *RouteProtocol) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RouteProtocolString(string(text))\n\treturn err\n}\n\nconst _RouteTypeName = \"unspecunicastlocalbroadcastanycastmulticastblackholeunreachableprohibitthrownatxresolve\"\n\nvar _RouteTypeIndex = [...]uint8{0, 6, 13, 18, 27, 34, 43, 52, 63, 71, 76, 79, 87}\n\nconst _RouteTypeLowerName = \"unspecunicastlocalbroadcastanycastmulticastblackholeunreachableprohibitthrownatxresolve\"\n\nfunc (i RouteType) String() string {\n\tif i >= RouteType(len(_RouteTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"RouteType(%d)\", i)\n\t}\n\treturn _RouteTypeName[_RouteTypeIndex[i]:_RouteTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RouteTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[TypeUnspec-(0)]\n\t_ = x[TypeUnicast-(1)]\n\t_ = x[TypeLocal-(2)]\n\t_ = x[TypeBroadcast-(3)]\n\t_ = x[TypeAnycast-(4)]\n\t_ = x[TypeMulticast-(5)]\n\t_ = x[TypeBlackhole-(6)]\n\t_ = x[TypeUnreachable-(7)]\n\t_ = x[TypeProhibit-(8)]\n\t_ = x[TypeThrow-(9)]\n\t_ = x[TypeNAT-(10)]\n\t_ = x[TypeXResolve-(11)]\n}\n\nvar _RouteTypeValues = []RouteType{TypeUnspec, TypeUnicast, TypeLocal, TypeBroadcast, TypeAnycast, TypeMulticast, TypeBlackhole, TypeUnreachable, TypeProhibit, TypeThrow, TypeNAT, TypeXResolve}\n\nvar _RouteTypeNameToValueMap = map[string]RouteType{\n\t_RouteTypeName[0:6]:        TypeUnspec,\n\t_RouteTypeLowerName[0:6]:   TypeUnspec,\n\t_RouteTypeName[6:13]:       TypeUnicast,\n\t_RouteTypeLowerName[6:13]:  TypeUnicast,\n\t_RouteTypeName[13:18]:      TypeLocal,\n\t_RouteTypeLowerName[13:18]: TypeLocal,\n\t_RouteTypeName[18:27]:      TypeBroadcast,\n\t_RouteTypeLowerName[18:27]: TypeBroadcast,\n\t_RouteTypeName[27:34]:      TypeAnycast,\n\t_RouteTypeLowerName[27:34]: TypeAnycast,\n\t_RouteTypeName[34:43]:      TypeMulticast,\n\t_RouteTypeLowerName[34:43]: TypeMulticast,\n\t_RouteTypeName[43:52]:      TypeBlackhole,\n\t_RouteTypeLowerName[43:52]: TypeBlackhole,\n\t_RouteTypeName[52:63]:      TypeUnreachable,\n\t_RouteTypeLowerName[52:63]: TypeUnreachable,\n\t_RouteTypeName[63:71]:      TypeProhibit,\n\t_RouteTypeLowerName[63:71]: TypeProhibit,\n\t_RouteTypeName[71:76]:      TypeThrow,\n\t_RouteTypeLowerName[71:76]: TypeThrow,\n\t_RouteTypeName[76:79]:      TypeNAT,\n\t_RouteTypeLowerName[76:79]: TypeNAT,\n\t_RouteTypeName[79:87]:      TypeXResolve,\n\t_RouteTypeLowerName[79:87]: TypeXResolve,\n}\n\nvar _RouteTypeNames = []string{\n\t_RouteTypeName[0:6],\n\t_RouteTypeName[6:13],\n\t_RouteTypeName[13:18],\n\t_RouteTypeName[18:27],\n\t_RouteTypeName[27:34],\n\t_RouteTypeName[34:43],\n\t_RouteTypeName[43:52],\n\t_RouteTypeName[52:63],\n\t_RouteTypeName[63:71],\n\t_RouteTypeName[71:76],\n\t_RouteTypeName[76:79],\n\t_RouteTypeName[79:87],\n}\n\n// RouteTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RouteTypeString(s string) (RouteType, error) {\n\tif val, ok := _RouteTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RouteTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RouteType values\", s)\n}\n\n// RouteTypeValues returns all values of the enum\nfunc RouteTypeValues() []RouteType {\n\treturn _RouteTypeValues\n}\n\n// RouteTypeStrings returns a slice of all String values of the enum\nfunc RouteTypeStrings() []string {\n\tstrs := make([]string, len(_RouteTypeNames))\n\tcopy(strs, _RouteTypeNames)\n\treturn strs\n}\n\n// IsARouteType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RouteType) IsARouteType() bool {\n\tfor _, v := range _RouteTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RouteType\nfunc (i RouteType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RouteType\nfunc (i *RouteType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RouteTypeString(string(text))\n\treturn err\n}\n\nconst (\n\t_RoutingRuleActionName_0      = \"unspecunicast\"\n\t_RoutingRuleActionLowerName_0 = \"unspecunicast\"\n\t_RoutingRuleActionName_1      = \"blackholeunreachableprohibit\"\n\t_RoutingRuleActionLowerName_1 = \"blackholeunreachableprohibit\"\n)\n\nvar (\n\t_RoutingRuleActionIndex_0 = [...]uint8{0, 6, 13}\n\t_RoutingRuleActionIndex_1 = [...]uint8{0, 9, 20, 28}\n)\n\nfunc (i RoutingRuleAction) String() string {\n\tswitch {\n\tcase 0 <= i && i <= 1:\n\t\treturn _RoutingRuleActionName_0[_RoutingRuleActionIndex_0[i]:_RoutingRuleActionIndex_0[i+1]]\n\tcase 6 <= i && i <= 8:\n\t\ti -= 6\n\t\treturn _RoutingRuleActionName_1[_RoutingRuleActionIndex_1[i]:_RoutingRuleActionIndex_1[i+1]]\n\tdefault:\n\t\treturn fmt.Sprintf(\"RoutingRuleAction(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RoutingRuleActionNoOp() {\n\tvar x [1]struct{}\n\t_ = x[RoutingRuleActionUnspec-(0)]\n\t_ = x[RoutingRuleActionUnicast-(1)]\n\t_ = x[RoutingRuleActionBlackhole-(6)]\n\t_ = x[RoutingRuleActionUnreachable-(7)]\n\t_ = x[RoutingRuleActionProhibit-(8)]\n}\n\nvar _RoutingRuleActionValues = []RoutingRuleAction{RoutingRuleActionUnspec, RoutingRuleActionUnicast, RoutingRuleActionBlackhole, RoutingRuleActionUnreachable, RoutingRuleActionProhibit}\n\nvar _RoutingRuleActionNameToValueMap = map[string]RoutingRuleAction{\n\t_RoutingRuleActionName_0[0:6]:        RoutingRuleActionUnspec,\n\t_RoutingRuleActionLowerName_0[0:6]:   RoutingRuleActionUnspec,\n\t_RoutingRuleActionName_0[6:13]:       RoutingRuleActionUnicast,\n\t_RoutingRuleActionLowerName_0[6:13]:  RoutingRuleActionUnicast,\n\t_RoutingRuleActionName_1[0:9]:        RoutingRuleActionBlackhole,\n\t_RoutingRuleActionLowerName_1[0:9]:   RoutingRuleActionBlackhole,\n\t_RoutingRuleActionName_1[9:20]:       RoutingRuleActionUnreachable,\n\t_RoutingRuleActionLowerName_1[9:20]:  RoutingRuleActionUnreachable,\n\t_RoutingRuleActionName_1[20:28]:      RoutingRuleActionProhibit,\n\t_RoutingRuleActionLowerName_1[20:28]: RoutingRuleActionProhibit,\n}\n\nvar _RoutingRuleActionNames = []string{\n\t_RoutingRuleActionName_0[0:6],\n\t_RoutingRuleActionName_0[6:13],\n\t_RoutingRuleActionName_1[0:9],\n\t_RoutingRuleActionName_1[9:20],\n\t_RoutingRuleActionName_1[20:28],\n}\n\n// RoutingRuleActionString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RoutingRuleActionString(s string) (RoutingRuleAction, error) {\n\tif val, ok := _RoutingRuleActionNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RoutingRuleActionNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RoutingRuleAction values\", s)\n}\n\n// RoutingRuleActionValues returns all values of the enum\nfunc RoutingRuleActionValues() []RoutingRuleAction {\n\treturn _RoutingRuleActionValues\n}\n\n// RoutingRuleActionStrings returns a slice of all String values of the enum\nfunc RoutingRuleActionStrings() []string {\n\tstrs := make([]string, len(_RoutingRuleActionNames))\n\tcopy(strs, _RoutingRuleActionNames)\n\treturn strs\n}\n\n// IsARoutingRuleAction returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RoutingRuleAction) IsARoutingRuleAction() bool {\n\tfor _, v := range _RoutingRuleActionValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RoutingRuleAction\nfunc (i RoutingRuleAction) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RoutingRuleAction\nfunc (i *RoutingRuleAction) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RoutingRuleActionString(string(text))\n\treturn err\n}\n\nconst _RoutingTableName = \"unspec123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252defaultmainlocal\"\n\nvar _RoutingTableIndex = [...]uint16{0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 198, 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 282, 285, 288, 291, 294, 297, 300, 303, 306, 309, 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, 372, 375, 378, 381, 384, 387, 390, 393, 396, 399, 402, 405, 408, 411, 414, 417, 420, 423, 426, 429, 432, 435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 468, 471, 474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 516, 519, 522, 525, 528, 531, 534, 537, 540, 543, 546, 549, 552, 555, 558, 561, 564, 567, 570, 573, 576, 579, 582, 585, 588, 591, 594, 597, 600, 603, 606, 609, 612, 615, 618, 621, 624, 627, 630, 633, 636, 639, 642, 645, 648, 651, 654, 661, 665, 670}\n\nconst _RoutingTableLowerName = \"unspec123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252defaultmainlocal\"\n\nfunc (i RoutingTable) String() string {\n\tif i >= RoutingTable(len(_RoutingTableIndex)-1) {\n\t\treturn fmt.Sprintf(\"RoutingTable(%d)\", i)\n\t}\n\treturn _RoutingTableName[_RoutingTableIndex[i]:_RoutingTableIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _RoutingTableNoOp() {\n\tvar x [1]struct{}\n\t_ = x[TableUnspec-(0)]\n\t_ = x[Table1-(1)]\n\t_ = x[Table2-(2)]\n\t_ = x[Table3-(3)]\n\t_ = x[Table4-(4)]\n\t_ = x[Table5-(5)]\n\t_ = x[Table6-(6)]\n\t_ = x[Table7-(7)]\n\t_ = x[Table8-(8)]\n\t_ = x[Table9-(9)]\n\t_ = x[Table10-(10)]\n\t_ = x[Table11-(11)]\n\t_ = x[Table12-(12)]\n\t_ = x[Table13-(13)]\n\t_ = x[Table14-(14)]\n\t_ = x[Table15-(15)]\n\t_ = x[Table16-(16)]\n\t_ = x[Table17-(17)]\n\t_ = x[Table18-(18)]\n\t_ = x[Table19-(19)]\n\t_ = x[Table20-(20)]\n\t_ = x[Table21-(21)]\n\t_ = x[Table22-(22)]\n\t_ = x[Table23-(23)]\n\t_ = x[Table24-(24)]\n\t_ = x[Table25-(25)]\n\t_ = x[Table26-(26)]\n\t_ = x[Table27-(27)]\n\t_ = x[Table28-(28)]\n\t_ = x[Table29-(29)]\n\t_ = x[Table30-(30)]\n\t_ = x[Table31-(31)]\n\t_ = x[Table32-(32)]\n\t_ = x[Table33-(33)]\n\t_ = x[Table34-(34)]\n\t_ = x[Table35-(35)]\n\t_ = x[Table36-(36)]\n\t_ = x[Table37-(37)]\n\t_ = x[Table38-(38)]\n\t_ = x[Table39-(39)]\n\t_ = x[Table40-(40)]\n\t_ = x[Table41-(41)]\n\t_ = x[Table42-(42)]\n\t_ = x[Table43-(43)]\n\t_ = x[Table44-(44)]\n\t_ = x[Table45-(45)]\n\t_ = x[Table46-(46)]\n\t_ = x[Table47-(47)]\n\t_ = x[Table48-(48)]\n\t_ = x[Table49-(49)]\n\t_ = x[Table50-(50)]\n\t_ = x[Table51-(51)]\n\t_ = x[Table52-(52)]\n\t_ = x[Table53-(53)]\n\t_ = x[Table54-(54)]\n\t_ = x[Table55-(55)]\n\t_ = x[Table56-(56)]\n\t_ = x[Table57-(57)]\n\t_ = x[Table58-(58)]\n\t_ = x[Table59-(59)]\n\t_ = x[Table60-(60)]\n\t_ = x[Table61-(61)]\n\t_ = x[Table62-(62)]\n\t_ = x[Table63-(63)]\n\t_ = x[Table64-(64)]\n\t_ = x[Table65-(65)]\n\t_ = x[Table66-(66)]\n\t_ = x[Table67-(67)]\n\t_ = x[Table68-(68)]\n\t_ = x[Table69-(69)]\n\t_ = x[Table70-(70)]\n\t_ = x[Table71-(71)]\n\t_ = x[Table72-(72)]\n\t_ = x[Table73-(73)]\n\t_ = x[Table74-(74)]\n\t_ = x[Table75-(75)]\n\t_ = x[Table76-(76)]\n\t_ = x[Table77-(77)]\n\t_ = x[Table78-(78)]\n\t_ = x[Table79-(79)]\n\t_ = x[Table80-(80)]\n\t_ = x[Table81-(81)]\n\t_ = x[Table82-(82)]\n\t_ = x[Table83-(83)]\n\t_ = x[Table84-(84)]\n\t_ = x[Table85-(85)]\n\t_ = x[Table86-(86)]\n\t_ = x[Table87-(87)]\n\t_ = x[Table88-(88)]\n\t_ = x[Table89-(89)]\n\t_ = x[Table90-(90)]\n\t_ = x[Table91-(91)]\n\t_ = x[Table92-(92)]\n\t_ = x[Table93-(93)]\n\t_ = x[Table94-(94)]\n\t_ = x[Table95-(95)]\n\t_ = x[Table96-(96)]\n\t_ = x[Table97-(97)]\n\t_ = x[Table98-(98)]\n\t_ = x[Table99-(99)]\n\t_ = x[Table100-(100)]\n\t_ = x[Table101-(101)]\n\t_ = x[Table102-(102)]\n\t_ = x[Table103-(103)]\n\t_ = x[Table104-(104)]\n\t_ = x[Table105-(105)]\n\t_ = x[Table106-(106)]\n\t_ = x[Table107-(107)]\n\t_ = x[Table108-(108)]\n\t_ = x[Table109-(109)]\n\t_ = x[Table110-(110)]\n\t_ = x[Table111-(111)]\n\t_ = x[Table112-(112)]\n\t_ = x[Table113-(113)]\n\t_ = x[Table114-(114)]\n\t_ = x[Table115-(115)]\n\t_ = x[Table116-(116)]\n\t_ = x[Table117-(117)]\n\t_ = x[Table118-(118)]\n\t_ = x[Table119-(119)]\n\t_ = x[Table120-(120)]\n\t_ = x[Table121-(121)]\n\t_ = x[Table122-(122)]\n\t_ = x[Table123-(123)]\n\t_ = x[Table124-(124)]\n\t_ = x[Table125-(125)]\n\t_ = x[Table126-(126)]\n\t_ = x[Table127-(127)]\n\t_ = x[Table128-(128)]\n\t_ = x[Table129-(129)]\n\t_ = x[Table130-(130)]\n\t_ = x[Table131-(131)]\n\t_ = x[Table132-(132)]\n\t_ = x[Table133-(133)]\n\t_ = x[Table134-(134)]\n\t_ = x[Table135-(135)]\n\t_ = x[Table136-(136)]\n\t_ = x[Table137-(137)]\n\t_ = x[Table138-(138)]\n\t_ = x[Table139-(139)]\n\t_ = x[Table140-(140)]\n\t_ = x[Table141-(141)]\n\t_ = x[Table142-(142)]\n\t_ = x[Table143-(143)]\n\t_ = x[Table144-(144)]\n\t_ = x[Table145-(145)]\n\t_ = x[Table146-(146)]\n\t_ = x[Table147-(147)]\n\t_ = x[Table148-(148)]\n\t_ = x[Table149-(149)]\n\t_ = x[Table150-(150)]\n\t_ = x[Table151-(151)]\n\t_ = x[Table152-(152)]\n\t_ = x[Table153-(153)]\n\t_ = x[Table154-(154)]\n\t_ = x[Table155-(155)]\n\t_ = x[Table156-(156)]\n\t_ = x[Table157-(157)]\n\t_ = x[Table158-(158)]\n\t_ = x[Table159-(159)]\n\t_ = x[Table160-(160)]\n\t_ = x[Table161-(161)]\n\t_ = x[Table162-(162)]\n\t_ = x[Table163-(163)]\n\t_ = x[Table164-(164)]\n\t_ = x[Table165-(165)]\n\t_ = x[Table166-(166)]\n\t_ = x[Table167-(167)]\n\t_ = x[Table168-(168)]\n\t_ = x[Table169-(169)]\n\t_ = x[Table170-(170)]\n\t_ = x[Table171-(171)]\n\t_ = x[Table172-(172)]\n\t_ = x[Table173-(173)]\n\t_ = x[Table174-(174)]\n\t_ = x[Table175-(175)]\n\t_ = x[Table176-(176)]\n\t_ = x[Table177-(177)]\n\t_ = x[Table178-(178)]\n\t_ = x[Table179-(179)]\n\t_ = x[Table180-(180)]\n\t_ = x[Table181-(181)]\n\t_ = x[Table182-(182)]\n\t_ = x[Table183-(183)]\n\t_ = x[Table184-(184)]\n\t_ = x[Table185-(185)]\n\t_ = x[Table186-(186)]\n\t_ = x[Table187-(187)]\n\t_ = x[Table188-(188)]\n\t_ = x[Table189-(189)]\n\t_ = x[Table190-(190)]\n\t_ = x[Table191-(191)]\n\t_ = x[Table192-(192)]\n\t_ = x[Table193-(193)]\n\t_ = x[Table194-(194)]\n\t_ = x[Table195-(195)]\n\t_ = x[Table196-(196)]\n\t_ = x[Table197-(197)]\n\t_ = x[Table198-(198)]\n\t_ = x[Table199-(199)]\n\t_ = x[Table200-(200)]\n\t_ = x[Table201-(201)]\n\t_ = x[Table202-(202)]\n\t_ = x[Table203-(203)]\n\t_ = x[Table204-(204)]\n\t_ = x[Table205-(205)]\n\t_ = x[Table206-(206)]\n\t_ = x[Table207-(207)]\n\t_ = x[Table208-(208)]\n\t_ = x[Table209-(209)]\n\t_ = x[Table210-(210)]\n\t_ = x[Table211-(211)]\n\t_ = x[Table212-(212)]\n\t_ = x[Table213-(213)]\n\t_ = x[Table214-(214)]\n\t_ = x[Table215-(215)]\n\t_ = x[Table216-(216)]\n\t_ = x[Table217-(217)]\n\t_ = x[Table218-(218)]\n\t_ = x[Table219-(219)]\n\t_ = x[Table220-(220)]\n\t_ = x[Table221-(221)]\n\t_ = x[Table222-(222)]\n\t_ = x[Table223-(223)]\n\t_ = x[Table224-(224)]\n\t_ = x[Table225-(225)]\n\t_ = x[Table226-(226)]\n\t_ = x[Table227-(227)]\n\t_ = x[Table228-(228)]\n\t_ = x[Table229-(229)]\n\t_ = x[Table230-(230)]\n\t_ = x[Table231-(231)]\n\t_ = x[Table232-(232)]\n\t_ = x[Table233-(233)]\n\t_ = x[Table234-(234)]\n\t_ = x[Table235-(235)]\n\t_ = x[Table236-(236)]\n\t_ = x[Table237-(237)]\n\t_ = x[Table238-(238)]\n\t_ = x[Table239-(239)]\n\t_ = x[Table240-(240)]\n\t_ = x[Table241-(241)]\n\t_ = x[Table242-(242)]\n\t_ = x[Table243-(243)]\n\t_ = x[Table244-(244)]\n\t_ = x[Table245-(245)]\n\t_ = x[Table246-(246)]\n\t_ = x[Table247-(247)]\n\t_ = x[Table248-(248)]\n\t_ = x[Table249-(249)]\n\t_ = x[Table250-(250)]\n\t_ = x[Table251-(251)]\n\t_ = x[Table252-(252)]\n\t_ = x[TableDefault-(253)]\n\t_ = x[TableMain-(254)]\n\t_ = x[TableLocal-(255)]\n}\n\nvar _RoutingTableValues = []RoutingTable{TableUnspec, Table1, Table2, Table3, Table4, Table5, Table6, Table7, Table8, Table9, Table10, Table11, Table12, Table13, Table14, Table15, Table16, Table17, Table18, Table19, Table20, Table21, Table22, Table23, Table24, Table25, Table26, Table27, Table28, Table29, Table30, Table31, Table32, Table33, Table34, Table35, Table36, Table37, Table38, Table39, Table40, Table41, Table42, Table43, Table44, Table45, Table46, Table47, Table48, Table49, Table50, Table51, Table52, Table53, Table54, Table55, Table56, Table57, Table58, Table59, Table60, Table61, Table62, Table63, Table64, Table65, Table66, Table67, Table68, Table69, Table70, Table71, Table72, Table73, Table74, Table75, Table76, Table77, Table78, Table79, Table80, Table81, Table82, Table83, Table84, Table85, Table86, Table87, Table88, Table89, Table90, Table91, Table92, Table93, Table94, Table95, Table96, Table97, Table98, Table99, Table100, Table101, Table102, Table103, Table104, Table105, Table106, Table107, Table108, Table109, Table110, Table111, Table112, Table113, Table114, Table115, Table116, Table117, Table118, Table119, Table120, Table121, Table122, Table123, Table124, Table125, Table126, Table127, Table128, Table129, Table130, Table131, Table132, Table133, Table134, Table135, Table136, Table137, Table138, Table139, Table140, Table141, Table142, Table143, Table144, Table145, Table146, Table147, Table148, Table149, Table150, Table151, Table152, Table153, Table154, Table155, Table156, Table157, Table158, Table159, Table160, Table161, Table162, Table163, Table164, Table165, Table166, Table167, Table168, Table169, Table170, Table171, Table172, Table173, Table174, Table175, Table176, Table177, Table178, Table179, Table180, Table181, Table182, Table183, Table184, Table185, Table186, Table187, Table188, Table189, Table190, Table191, Table192, Table193, Table194, Table195, Table196, Table197, Table198, Table199, Table200, Table201, Table202, Table203, Table204, Table205, Table206, Table207, Table208, Table209, Table210, Table211, Table212, Table213, Table214, Table215, Table216, Table217, Table218, Table219, Table220, Table221, Table222, Table223, Table224, Table225, Table226, Table227, Table228, Table229, Table230, Table231, Table232, Table233, Table234, Table235, Table236, Table237, Table238, Table239, Table240, Table241, Table242, Table243, Table244, Table245, Table246, Table247, Table248, Table249, Table250, Table251, Table252, TableDefault, TableMain, TableLocal}\n\nvar _RoutingTableNameToValueMap = map[string]RoutingTable{\n\t_RoutingTableName[0:6]:          TableUnspec,\n\t_RoutingTableLowerName[0:6]:     TableUnspec,\n\t_RoutingTableName[6:7]:          Table1,\n\t_RoutingTableLowerName[6:7]:     Table1,\n\t_RoutingTableName[7:8]:          Table2,\n\t_RoutingTableLowerName[7:8]:     Table2,\n\t_RoutingTableName[8:9]:          Table3,\n\t_RoutingTableLowerName[8:9]:     Table3,\n\t_RoutingTableName[9:10]:         Table4,\n\t_RoutingTableLowerName[9:10]:    Table4,\n\t_RoutingTableName[10:11]:        Table5,\n\t_RoutingTableLowerName[10:11]:   Table5,\n\t_RoutingTableName[11:12]:        Table6,\n\t_RoutingTableLowerName[11:12]:   Table6,\n\t_RoutingTableName[12:13]:        Table7,\n\t_RoutingTableLowerName[12:13]:   Table7,\n\t_RoutingTableName[13:14]:        Table8,\n\t_RoutingTableLowerName[13:14]:   Table8,\n\t_RoutingTableName[14:15]:        Table9,\n\t_RoutingTableLowerName[14:15]:   Table9,\n\t_RoutingTableName[15:17]:        Table10,\n\t_RoutingTableLowerName[15:17]:   Table10,\n\t_RoutingTableName[17:19]:        Table11,\n\t_RoutingTableLowerName[17:19]:   Table11,\n\t_RoutingTableName[19:21]:        Table12,\n\t_RoutingTableLowerName[19:21]:   Table12,\n\t_RoutingTableName[21:23]:        Table13,\n\t_RoutingTableLowerName[21:23]:   Table13,\n\t_RoutingTableName[23:25]:        Table14,\n\t_RoutingTableLowerName[23:25]:   Table14,\n\t_RoutingTableName[25:27]:        Table15,\n\t_RoutingTableLowerName[25:27]:   Table15,\n\t_RoutingTableName[27:29]:        Table16,\n\t_RoutingTableLowerName[27:29]:   Table16,\n\t_RoutingTableName[29:31]:        Table17,\n\t_RoutingTableLowerName[29:31]:   Table17,\n\t_RoutingTableName[31:33]:        Table18,\n\t_RoutingTableLowerName[31:33]:   Table18,\n\t_RoutingTableName[33:35]:        Table19,\n\t_RoutingTableLowerName[33:35]:   Table19,\n\t_RoutingTableName[35:37]:        Table20,\n\t_RoutingTableLowerName[35:37]:   Table20,\n\t_RoutingTableName[37:39]:        Table21,\n\t_RoutingTableLowerName[37:39]:   Table21,\n\t_RoutingTableName[39:41]:        Table22,\n\t_RoutingTableLowerName[39:41]:   Table22,\n\t_RoutingTableName[41:43]:        Table23,\n\t_RoutingTableLowerName[41:43]:   Table23,\n\t_RoutingTableName[43:45]:        Table24,\n\t_RoutingTableLowerName[43:45]:   Table24,\n\t_RoutingTableName[45:47]:        Table25,\n\t_RoutingTableLowerName[45:47]:   Table25,\n\t_RoutingTableName[47:49]:        Table26,\n\t_RoutingTableLowerName[47:49]:   Table26,\n\t_RoutingTableName[49:51]:        Table27,\n\t_RoutingTableLowerName[49:51]:   Table27,\n\t_RoutingTableName[51:53]:        Table28,\n\t_RoutingTableLowerName[51:53]:   Table28,\n\t_RoutingTableName[53:55]:        Table29,\n\t_RoutingTableLowerName[53:55]:   Table29,\n\t_RoutingTableName[55:57]:        Table30,\n\t_RoutingTableLowerName[55:57]:   Table30,\n\t_RoutingTableName[57:59]:        Table31,\n\t_RoutingTableLowerName[57:59]:   Table31,\n\t_RoutingTableName[59:61]:        Table32,\n\t_RoutingTableLowerName[59:61]:   Table32,\n\t_RoutingTableName[61:63]:        Table33,\n\t_RoutingTableLowerName[61:63]:   Table33,\n\t_RoutingTableName[63:65]:        Table34,\n\t_RoutingTableLowerName[63:65]:   Table34,\n\t_RoutingTableName[65:67]:        Table35,\n\t_RoutingTableLowerName[65:67]:   Table35,\n\t_RoutingTableName[67:69]:        Table36,\n\t_RoutingTableLowerName[67:69]:   Table36,\n\t_RoutingTableName[69:71]:        Table37,\n\t_RoutingTableLowerName[69:71]:   Table37,\n\t_RoutingTableName[71:73]:        Table38,\n\t_RoutingTableLowerName[71:73]:   Table38,\n\t_RoutingTableName[73:75]:        Table39,\n\t_RoutingTableLowerName[73:75]:   Table39,\n\t_RoutingTableName[75:77]:        Table40,\n\t_RoutingTableLowerName[75:77]:   Table40,\n\t_RoutingTableName[77:79]:        Table41,\n\t_RoutingTableLowerName[77:79]:   Table41,\n\t_RoutingTableName[79:81]:        Table42,\n\t_RoutingTableLowerName[79:81]:   Table42,\n\t_RoutingTableName[81:83]:        Table43,\n\t_RoutingTableLowerName[81:83]:   Table43,\n\t_RoutingTableName[83:85]:        Table44,\n\t_RoutingTableLowerName[83:85]:   Table44,\n\t_RoutingTableName[85:87]:        Table45,\n\t_RoutingTableLowerName[85:87]:   Table45,\n\t_RoutingTableName[87:89]:        Table46,\n\t_RoutingTableLowerName[87:89]:   Table46,\n\t_RoutingTableName[89:91]:        Table47,\n\t_RoutingTableLowerName[89:91]:   Table47,\n\t_RoutingTableName[91:93]:        Table48,\n\t_RoutingTableLowerName[91:93]:   Table48,\n\t_RoutingTableName[93:95]:        Table49,\n\t_RoutingTableLowerName[93:95]:   Table49,\n\t_RoutingTableName[95:97]:        Table50,\n\t_RoutingTableLowerName[95:97]:   Table50,\n\t_RoutingTableName[97:99]:        Table51,\n\t_RoutingTableLowerName[97:99]:   Table51,\n\t_RoutingTableName[99:101]:       Table52,\n\t_RoutingTableLowerName[99:101]:  Table52,\n\t_RoutingTableName[101:103]:      Table53,\n\t_RoutingTableLowerName[101:103]: Table53,\n\t_RoutingTableName[103:105]:      Table54,\n\t_RoutingTableLowerName[103:105]: Table54,\n\t_RoutingTableName[105:107]:      Table55,\n\t_RoutingTableLowerName[105:107]: Table55,\n\t_RoutingTableName[107:109]:      Table56,\n\t_RoutingTableLowerName[107:109]: Table56,\n\t_RoutingTableName[109:111]:      Table57,\n\t_RoutingTableLowerName[109:111]: Table57,\n\t_RoutingTableName[111:113]:      Table58,\n\t_RoutingTableLowerName[111:113]: Table58,\n\t_RoutingTableName[113:115]:      Table59,\n\t_RoutingTableLowerName[113:115]: Table59,\n\t_RoutingTableName[115:117]:      Table60,\n\t_RoutingTableLowerName[115:117]: Table60,\n\t_RoutingTableName[117:119]:      Table61,\n\t_RoutingTableLowerName[117:119]: Table61,\n\t_RoutingTableName[119:121]:      Table62,\n\t_RoutingTableLowerName[119:121]: Table62,\n\t_RoutingTableName[121:123]:      Table63,\n\t_RoutingTableLowerName[121:123]: Table63,\n\t_RoutingTableName[123:125]:      Table64,\n\t_RoutingTableLowerName[123:125]: Table64,\n\t_RoutingTableName[125:127]:      Table65,\n\t_RoutingTableLowerName[125:127]: Table65,\n\t_RoutingTableName[127:129]:      Table66,\n\t_RoutingTableLowerName[127:129]: Table66,\n\t_RoutingTableName[129:131]:      Table67,\n\t_RoutingTableLowerName[129:131]: Table67,\n\t_RoutingTableName[131:133]:      Table68,\n\t_RoutingTableLowerName[131:133]: Table68,\n\t_RoutingTableName[133:135]:      Table69,\n\t_RoutingTableLowerName[133:135]: Table69,\n\t_RoutingTableName[135:137]:      Table70,\n\t_RoutingTableLowerName[135:137]: Table70,\n\t_RoutingTableName[137:139]:      Table71,\n\t_RoutingTableLowerName[137:139]: Table71,\n\t_RoutingTableName[139:141]:      Table72,\n\t_RoutingTableLowerName[139:141]: Table72,\n\t_RoutingTableName[141:143]:      Table73,\n\t_RoutingTableLowerName[141:143]: Table73,\n\t_RoutingTableName[143:145]:      Table74,\n\t_RoutingTableLowerName[143:145]: Table74,\n\t_RoutingTableName[145:147]:      Table75,\n\t_RoutingTableLowerName[145:147]: Table75,\n\t_RoutingTableName[147:149]:      Table76,\n\t_RoutingTableLowerName[147:149]: Table76,\n\t_RoutingTableName[149:151]:      Table77,\n\t_RoutingTableLowerName[149:151]: Table77,\n\t_RoutingTableName[151:153]:      Table78,\n\t_RoutingTableLowerName[151:153]: Table78,\n\t_RoutingTableName[153:155]:      Table79,\n\t_RoutingTableLowerName[153:155]: Table79,\n\t_RoutingTableName[155:157]:      Table80,\n\t_RoutingTableLowerName[155:157]: Table80,\n\t_RoutingTableName[157:159]:      Table81,\n\t_RoutingTableLowerName[157:159]: Table81,\n\t_RoutingTableName[159:161]:      Table82,\n\t_RoutingTableLowerName[159:161]: Table82,\n\t_RoutingTableName[161:163]:      Table83,\n\t_RoutingTableLowerName[161:163]: Table83,\n\t_RoutingTableName[163:165]:      Table84,\n\t_RoutingTableLowerName[163:165]: Table84,\n\t_RoutingTableName[165:167]:      Table85,\n\t_RoutingTableLowerName[165:167]: Table85,\n\t_RoutingTableName[167:169]:      Table86,\n\t_RoutingTableLowerName[167:169]: Table86,\n\t_RoutingTableName[169:171]:      Table87,\n\t_RoutingTableLowerName[169:171]: Table87,\n\t_RoutingTableName[171:173]:      Table88,\n\t_RoutingTableLowerName[171:173]: Table88,\n\t_RoutingTableName[173:175]:      Table89,\n\t_RoutingTableLowerName[173:175]: Table89,\n\t_RoutingTableName[175:177]:      Table90,\n\t_RoutingTableLowerName[175:177]: Table90,\n\t_RoutingTableName[177:179]:      Table91,\n\t_RoutingTableLowerName[177:179]: Table91,\n\t_RoutingTableName[179:181]:      Table92,\n\t_RoutingTableLowerName[179:181]: Table92,\n\t_RoutingTableName[181:183]:      Table93,\n\t_RoutingTableLowerName[181:183]: Table93,\n\t_RoutingTableName[183:185]:      Table94,\n\t_RoutingTableLowerName[183:185]: Table94,\n\t_RoutingTableName[185:187]:      Table95,\n\t_RoutingTableLowerName[185:187]: Table95,\n\t_RoutingTableName[187:189]:      Table96,\n\t_RoutingTableLowerName[187:189]: Table96,\n\t_RoutingTableName[189:191]:      Table97,\n\t_RoutingTableLowerName[189:191]: Table97,\n\t_RoutingTableName[191:193]:      Table98,\n\t_RoutingTableLowerName[191:193]: Table98,\n\t_RoutingTableName[193:195]:      Table99,\n\t_RoutingTableLowerName[193:195]: Table99,\n\t_RoutingTableName[195:198]:      Table100,\n\t_RoutingTableLowerName[195:198]: Table100,\n\t_RoutingTableName[198:201]:      Table101,\n\t_RoutingTableLowerName[198:201]: Table101,\n\t_RoutingTableName[201:204]:      Table102,\n\t_RoutingTableLowerName[201:204]: Table102,\n\t_RoutingTableName[204:207]:      Table103,\n\t_RoutingTableLowerName[204:207]: Table103,\n\t_RoutingTableName[207:210]:      Table104,\n\t_RoutingTableLowerName[207:210]: Table104,\n\t_RoutingTableName[210:213]:      Table105,\n\t_RoutingTableLowerName[210:213]: Table105,\n\t_RoutingTableName[213:216]:      Table106,\n\t_RoutingTableLowerName[213:216]: Table106,\n\t_RoutingTableName[216:219]:      Table107,\n\t_RoutingTableLowerName[216:219]: Table107,\n\t_RoutingTableName[219:222]:      Table108,\n\t_RoutingTableLowerName[219:222]: Table108,\n\t_RoutingTableName[222:225]:      Table109,\n\t_RoutingTableLowerName[222:225]: Table109,\n\t_RoutingTableName[225:228]:      Table110,\n\t_RoutingTableLowerName[225:228]: Table110,\n\t_RoutingTableName[228:231]:      Table111,\n\t_RoutingTableLowerName[228:231]: Table111,\n\t_RoutingTableName[231:234]:      Table112,\n\t_RoutingTableLowerName[231:234]: Table112,\n\t_RoutingTableName[234:237]:      Table113,\n\t_RoutingTableLowerName[234:237]: Table113,\n\t_RoutingTableName[237:240]:      Table114,\n\t_RoutingTableLowerName[237:240]: Table114,\n\t_RoutingTableName[240:243]:      Table115,\n\t_RoutingTableLowerName[240:243]: Table115,\n\t_RoutingTableName[243:246]:      Table116,\n\t_RoutingTableLowerName[243:246]: Table116,\n\t_RoutingTableName[246:249]:      Table117,\n\t_RoutingTableLowerName[246:249]: Table117,\n\t_RoutingTableName[249:252]:      Table118,\n\t_RoutingTableLowerName[249:252]: Table118,\n\t_RoutingTableName[252:255]:      Table119,\n\t_RoutingTableLowerName[252:255]: Table119,\n\t_RoutingTableName[255:258]:      Table120,\n\t_RoutingTableLowerName[255:258]: Table120,\n\t_RoutingTableName[258:261]:      Table121,\n\t_RoutingTableLowerName[258:261]: Table121,\n\t_RoutingTableName[261:264]:      Table122,\n\t_RoutingTableLowerName[261:264]: Table122,\n\t_RoutingTableName[264:267]:      Table123,\n\t_RoutingTableLowerName[264:267]: Table123,\n\t_RoutingTableName[267:270]:      Table124,\n\t_RoutingTableLowerName[267:270]: Table124,\n\t_RoutingTableName[270:273]:      Table125,\n\t_RoutingTableLowerName[270:273]: Table125,\n\t_RoutingTableName[273:276]:      Table126,\n\t_RoutingTableLowerName[273:276]: Table126,\n\t_RoutingTableName[276:279]:      Table127,\n\t_RoutingTableLowerName[276:279]: Table127,\n\t_RoutingTableName[279:282]:      Table128,\n\t_RoutingTableLowerName[279:282]: Table128,\n\t_RoutingTableName[282:285]:      Table129,\n\t_RoutingTableLowerName[282:285]: Table129,\n\t_RoutingTableName[285:288]:      Table130,\n\t_RoutingTableLowerName[285:288]: Table130,\n\t_RoutingTableName[288:291]:      Table131,\n\t_RoutingTableLowerName[288:291]: Table131,\n\t_RoutingTableName[291:294]:      Table132,\n\t_RoutingTableLowerName[291:294]: Table132,\n\t_RoutingTableName[294:297]:      Table133,\n\t_RoutingTableLowerName[294:297]: Table133,\n\t_RoutingTableName[297:300]:      Table134,\n\t_RoutingTableLowerName[297:300]: Table134,\n\t_RoutingTableName[300:303]:      Table135,\n\t_RoutingTableLowerName[300:303]: Table135,\n\t_RoutingTableName[303:306]:      Table136,\n\t_RoutingTableLowerName[303:306]: Table136,\n\t_RoutingTableName[306:309]:      Table137,\n\t_RoutingTableLowerName[306:309]: Table137,\n\t_RoutingTableName[309:312]:      Table138,\n\t_RoutingTableLowerName[309:312]: Table138,\n\t_RoutingTableName[312:315]:      Table139,\n\t_RoutingTableLowerName[312:315]: Table139,\n\t_RoutingTableName[315:318]:      Table140,\n\t_RoutingTableLowerName[315:318]: Table140,\n\t_RoutingTableName[318:321]:      Table141,\n\t_RoutingTableLowerName[318:321]: Table141,\n\t_RoutingTableName[321:324]:      Table142,\n\t_RoutingTableLowerName[321:324]: Table142,\n\t_RoutingTableName[324:327]:      Table143,\n\t_RoutingTableLowerName[324:327]: Table143,\n\t_RoutingTableName[327:330]:      Table144,\n\t_RoutingTableLowerName[327:330]: Table144,\n\t_RoutingTableName[330:333]:      Table145,\n\t_RoutingTableLowerName[330:333]: Table145,\n\t_RoutingTableName[333:336]:      Table146,\n\t_RoutingTableLowerName[333:336]: Table146,\n\t_RoutingTableName[336:339]:      Table147,\n\t_RoutingTableLowerName[336:339]: Table147,\n\t_RoutingTableName[339:342]:      Table148,\n\t_RoutingTableLowerName[339:342]: Table148,\n\t_RoutingTableName[342:345]:      Table149,\n\t_RoutingTableLowerName[342:345]: Table149,\n\t_RoutingTableName[345:348]:      Table150,\n\t_RoutingTableLowerName[345:348]: Table150,\n\t_RoutingTableName[348:351]:      Table151,\n\t_RoutingTableLowerName[348:351]: Table151,\n\t_RoutingTableName[351:354]:      Table152,\n\t_RoutingTableLowerName[351:354]: Table152,\n\t_RoutingTableName[354:357]:      Table153,\n\t_RoutingTableLowerName[354:357]: Table153,\n\t_RoutingTableName[357:360]:      Table154,\n\t_RoutingTableLowerName[357:360]: Table154,\n\t_RoutingTableName[360:363]:      Table155,\n\t_RoutingTableLowerName[360:363]: Table155,\n\t_RoutingTableName[363:366]:      Table156,\n\t_RoutingTableLowerName[363:366]: Table156,\n\t_RoutingTableName[366:369]:      Table157,\n\t_RoutingTableLowerName[366:369]: Table157,\n\t_RoutingTableName[369:372]:      Table158,\n\t_RoutingTableLowerName[369:372]: Table158,\n\t_RoutingTableName[372:375]:      Table159,\n\t_RoutingTableLowerName[372:375]: Table159,\n\t_RoutingTableName[375:378]:      Table160,\n\t_RoutingTableLowerName[375:378]: Table160,\n\t_RoutingTableName[378:381]:      Table161,\n\t_RoutingTableLowerName[378:381]: Table161,\n\t_RoutingTableName[381:384]:      Table162,\n\t_RoutingTableLowerName[381:384]: Table162,\n\t_RoutingTableName[384:387]:      Table163,\n\t_RoutingTableLowerName[384:387]: Table163,\n\t_RoutingTableName[387:390]:      Table164,\n\t_RoutingTableLowerName[387:390]: Table164,\n\t_RoutingTableName[390:393]:      Table165,\n\t_RoutingTableLowerName[390:393]: Table165,\n\t_RoutingTableName[393:396]:      Table166,\n\t_RoutingTableLowerName[393:396]: Table166,\n\t_RoutingTableName[396:399]:      Table167,\n\t_RoutingTableLowerName[396:399]: Table167,\n\t_RoutingTableName[399:402]:      Table168,\n\t_RoutingTableLowerName[399:402]: Table168,\n\t_RoutingTableName[402:405]:      Table169,\n\t_RoutingTableLowerName[402:405]: Table169,\n\t_RoutingTableName[405:408]:      Table170,\n\t_RoutingTableLowerName[405:408]: Table170,\n\t_RoutingTableName[408:411]:      Table171,\n\t_RoutingTableLowerName[408:411]: Table171,\n\t_RoutingTableName[411:414]:      Table172,\n\t_RoutingTableLowerName[411:414]: Table172,\n\t_RoutingTableName[414:417]:      Table173,\n\t_RoutingTableLowerName[414:417]: Table173,\n\t_RoutingTableName[417:420]:      Table174,\n\t_RoutingTableLowerName[417:420]: Table174,\n\t_RoutingTableName[420:423]:      Table175,\n\t_RoutingTableLowerName[420:423]: Table175,\n\t_RoutingTableName[423:426]:      Table176,\n\t_RoutingTableLowerName[423:426]: Table176,\n\t_RoutingTableName[426:429]:      Table177,\n\t_RoutingTableLowerName[426:429]: Table177,\n\t_RoutingTableName[429:432]:      Table178,\n\t_RoutingTableLowerName[429:432]: Table178,\n\t_RoutingTableName[432:435]:      Table179,\n\t_RoutingTableLowerName[432:435]: Table179,\n\t_RoutingTableName[435:438]:      Table180,\n\t_RoutingTableLowerName[435:438]: Table180,\n\t_RoutingTableName[438:441]:      Table181,\n\t_RoutingTableLowerName[438:441]: Table181,\n\t_RoutingTableName[441:444]:      Table182,\n\t_RoutingTableLowerName[441:444]: Table182,\n\t_RoutingTableName[444:447]:      Table183,\n\t_RoutingTableLowerName[444:447]: Table183,\n\t_RoutingTableName[447:450]:      Table184,\n\t_RoutingTableLowerName[447:450]: Table184,\n\t_RoutingTableName[450:453]:      Table185,\n\t_RoutingTableLowerName[450:453]: Table185,\n\t_RoutingTableName[453:456]:      Table186,\n\t_RoutingTableLowerName[453:456]: Table186,\n\t_RoutingTableName[456:459]:      Table187,\n\t_RoutingTableLowerName[456:459]: Table187,\n\t_RoutingTableName[459:462]:      Table188,\n\t_RoutingTableLowerName[459:462]: Table188,\n\t_RoutingTableName[462:465]:      Table189,\n\t_RoutingTableLowerName[462:465]: Table189,\n\t_RoutingTableName[465:468]:      Table190,\n\t_RoutingTableLowerName[465:468]: Table190,\n\t_RoutingTableName[468:471]:      Table191,\n\t_RoutingTableLowerName[468:471]: Table191,\n\t_RoutingTableName[471:474]:      Table192,\n\t_RoutingTableLowerName[471:474]: Table192,\n\t_RoutingTableName[474:477]:      Table193,\n\t_RoutingTableLowerName[474:477]: Table193,\n\t_RoutingTableName[477:480]:      Table194,\n\t_RoutingTableLowerName[477:480]: Table194,\n\t_RoutingTableName[480:483]:      Table195,\n\t_RoutingTableLowerName[480:483]: Table195,\n\t_RoutingTableName[483:486]:      Table196,\n\t_RoutingTableLowerName[483:486]: Table196,\n\t_RoutingTableName[486:489]:      Table197,\n\t_RoutingTableLowerName[486:489]: Table197,\n\t_RoutingTableName[489:492]:      Table198,\n\t_RoutingTableLowerName[489:492]: Table198,\n\t_RoutingTableName[492:495]:      Table199,\n\t_RoutingTableLowerName[492:495]: Table199,\n\t_RoutingTableName[495:498]:      Table200,\n\t_RoutingTableLowerName[495:498]: Table200,\n\t_RoutingTableName[498:501]:      Table201,\n\t_RoutingTableLowerName[498:501]: Table201,\n\t_RoutingTableName[501:504]:      Table202,\n\t_RoutingTableLowerName[501:504]: Table202,\n\t_RoutingTableName[504:507]:      Table203,\n\t_RoutingTableLowerName[504:507]: Table203,\n\t_RoutingTableName[507:510]:      Table204,\n\t_RoutingTableLowerName[507:510]: Table204,\n\t_RoutingTableName[510:513]:      Table205,\n\t_RoutingTableLowerName[510:513]: Table205,\n\t_RoutingTableName[513:516]:      Table206,\n\t_RoutingTableLowerName[513:516]: Table206,\n\t_RoutingTableName[516:519]:      Table207,\n\t_RoutingTableLowerName[516:519]: Table207,\n\t_RoutingTableName[519:522]:      Table208,\n\t_RoutingTableLowerName[519:522]: Table208,\n\t_RoutingTableName[522:525]:      Table209,\n\t_RoutingTableLowerName[522:525]: Table209,\n\t_RoutingTableName[525:528]:      Table210,\n\t_RoutingTableLowerName[525:528]: Table210,\n\t_RoutingTableName[528:531]:      Table211,\n\t_RoutingTableLowerName[528:531]: Table211,\n\t_RoutingTableName[531:534]:      Table212,\n\t_RoutingTableLowerName[531:534]: Table212,\n\t_RoutingTableName[534:537]:      Table213,\n\t_RoutingTableLowerName[534:537]: Table213,\n\t_RoutingTableName[537:540]:      Table214,\n\t_RoutingTableLowerName[537:540]: Table214,\n\t_RoutingTableName[540:543]:      Table215,\n\t_RoutingTableLowerName[540:543]: Table215,\n\t_RoutingTableName[543:546]:      Table216,\n\t_RoutingTableLowerName[543:546]: Table216,\n\t_RoutingTableName[546:549]:      Table217,\n\t_RoutingTableLowerName[546:549]: Table217,\n\t_RoutingTableName[549:552]:      Table218,\n\t_RoutingTableLowerName[549:552]: Table218,\n\t_RoutingTableName[552:555]:      Table219,\n\t_RoutingTableLowerName[552:555]: Table219,\n\t_RoutingTableName[555:558]:      Table220,\n\t_RoutingTableLowerName[555:558]: Table220,\n\t_RoutingTableName[558:561]:      Table221,\n\t_RoutingTableLowerName[558:561]: Table221,\n\t_RoutingTableName[561:564]:      Table222,\n\t_RoutingTableLowerName[561:564]: Table222,\n\t_RoutingTableName[564:567]:      Table223,\n\t_RoutingTableLowerName[564:567]: Table223,\n\t_RoutingTableName[567:570]:      Table224,\n\t_RoutingTableLowerName[567:570]: Table224,\n\t_RoutingTableName[570:573]:      Table225,\n\t_RoutingTableLowerName[570:573]: Table225,\n\t_RoutingTableName[573:576]:      Table226,\n\t_RoutingTableLowerName[573:576]: Table226,\n\t_RoutingTableName[576:579]:      Table227,\n\t_RoutingTableLowerName[576:579]: Table227,\n\t_RoutingTableName[579:582]:      Table228,\n\t_RoutingTableLowerName[579:582]: Table228,\n\t_RoutingTableName[582:585]:      Table229,\n\t_RoutingTableLowerName[582:585]: Table229,\n\t_RoutingTableName[585:588]:      Table230,\n\t_RoutingTableLowerName[585:588]: Table230,\n\t_RoutingTableName[588:591]:      Table231,\n\t_RoutingTableLowerName[588:591]: Table231,\n\t_RoutingTableName[591:594]:      Table232,\n\t_RoutingTableLowerName[591:594]: Table232,\n\t_RoutingTableName[594:597]:      Table233,\n\t_RoutingTableLowerName[594:597]: Table233,\n\t_RoutingTableName[597:600]:      Table234,\n\t_RoutingTableLowerName[597:600]: Table234,\n\t_RoutingTableName[600:603]:      Table235,\n\t_RoutingTableLowerName[600:603]: Table235,\n\t_RoutingTableName[603:606]:      Table236,\n\t_RoutingTableLowerName[603:606]: Table236,\n\t_RoutingTableName[606:609]:      Table237,\n\t_RoutingTableLowerName[606:609]: Table237,\n\t_RoutingTableName[609:612]:      Table238,\n\t_RoutingTableLowerName[609:612]: Table238,\n\t_RoutingTableName[612:615]:      Table239,\n\t_RoutingTableLowerName[612:615]: Table239,\n\t_RoutingTableName[615:618]:      Table240,\n\t_RoutingTableLowerName[615:618]: Table240,\n\t_RoutingTableName[618:621]:      Table241,\n\t_RoutingTableLowerName[618:621]: Table241,\n\t_RoutingTableName[621:624]:      Table242,\n\t_RoutingTableLowerName[621:624]: Table242,\n\t_RoutingTableName[624:627]:      Table243,\n\t_RoutingTableLowerName[624:627]: Table243,\n\t_RoutingTableName[627:630]:      Table244,\n\t_RoutingTableLowerName[627:630]: Table244,\n\t_RoutingTableName[630:633]:      Table245,\n\t_RoutingTableLowerName[630:633]: Table245,\n\t_RoutingTableName[633:636]:      Table246,\n\t_RoutingTableLowerName[633:636]: Table246,\n\t_RoutingTableName[636:639]:      Table247,\n\t_RoutingTableLowerName[636:639]: Table247,\n\t_RoutingTableName[639:642]:      Table248,\n\t_RoutingTableLowerName[639:642]: Table248,\n\t_RoutingTableName[642:645]:      Table249,\n\t_RoutingTableLowerName[642:645]: Table249,\n\t_RoutingTableName[645:648]:      Table250,\n\t_RoutingTableLowerName[645:648]: Table250,\n\t_RoutingTableName[648:651]:      Table251,\n\t_RoutingTableLowerName[648:651]: Table251,\n\t_RoutingTableName[651:654]:      Table252,\n\t_RoutingTableLowerName[651:654]: Table252,\n\t_RoutingTableName[654:661]:      TableDefault,\n\t_RoutingTableLowerName[654:661]: TableDefault,\n\t_RoutingTableName[661:665]:      TableMain,\n\t_RoutingTableLowerName[661:665]: TableMain,\n\t_RoutingTableName[665:670]:      TableLocal,\n\t_RoutingTableLowerName[665:670]: TableLocal,\n}\n\nvar _RoutingTableNames = []string{\n\t_RoutingTableName[0:6],\n\t_RoutingTableName[6:7],\n\t_RoutingTableName[7:8],\n\t_RoutingTableName[8:9],\n\t_RoutingTableName[9:10],\n\t_RoutingTableName[10:11],\n\t_RoutingTableName[11:12],\n\t_RoutingTableName[12:13],\n\t_RoutingTableName[13:14],\n\t_RoutingTableName[14:15],\n\t_RoutingTableName[15:17],\n\t_RoutingTableName[17:19],\n\t_RoutingTableName[19:21],\n\t_RoutingTableName[21:23],\n\t_RoutingTableName[23:25],\n\t_RoutingTableName[25:27],\n\t_RoutingTableName[27:29],\n\t_RoutingTableName[29:31],\n\t_RoutingTableName[31:33],\n\t_RoutingTableName[33:35],\n\t_RoutingTableName[35:37],\n\t_RoutingTableName[37:39],\n\t_RoutingTableName[39:41],\n\t_RoutingTableName[41:43],\n\t_RoutingTableName[43:45],\n\t_RoutingTableName[45:47],\n\t_RoutingTableName[47:49],\n\t_RoutingTableName[49:51],\n\t_RoutingTableName[51:53],\n\t_RoutingTableName[53:55],\n\t_RoutingTableName[55:57],\n\t_RoutingTableName[57:59],\n\t_RoutingTableName[59:61],\n\t_RoutingTableName[61:63],\n\t_RoutingTableName[63:65],\n\t_RoutingTableName[65:67],\n\t_RoutingTableName[67:69],\n\t_RoutingTableName[69:71],\n\t_RoutingTableName[71:73],\n\t_RoutingTableName[73:75],\n\t_RoutingTableName[75:77],\n\t_RoutingTableName[77:79],\n\t_RoutingTableName[79:81],\n\t_RoutingTableName[81:83],\n\t_RoutingTableName[83:85],\n\t_RoutingTableName[85:87],\n\t_RoutingTableName[87:89],\n\t_RoutingTableName[89:91],\n\t_RoutingTableName[91:93],\n\t_RoutingTableName[93:95],\n\t_RoutingTableName[95:97],\n\t_RoutingTableName[97:99],\n\t_RoutingTableName[99:101],\n\t_RoutingTableName[101:103],\n\t_RoutingTableName[103:105],\n\t_RoutingTableName[105:107],\n\t_RoutingTableName[107:109],\n\t_RoutingTableName[109:111],\n\t_RoutingTableName[111:113],\n\t_RoutingTableName[113:115],\n\t_RoutingTableName[115:117],\n\t_RoutingTableName[117:119],\n\t_RoutingTableName[119:121],\n\t_RoutingTableName[121:123],\n\t_RoutingTableName[123:125],\n\t_RoutingTableName[125:127],\n\t_RoutingTableName[127:129],\n\t_RoutingTableName[129:131],\n\t_RoutingTableName[131:133],\n\t_RoutingTableName[133:135],\n\t_RoutingTableName[135:137],\n\t_RoutingTableName[137:139],\n\t_RoutingTableName[139:141],\n\t_RoutingTableName[141:143],\n\t_RoutingTableName[143:145],\n\t_RoutingTableName[145:147],\n\t_RoutingTableName[147:149],\n\t_RoutingTableName[149:151],\n\t_RoutingTableName[151:153],\n\t_RoutingTableName[153:155],\n\t_RoutingTableName[155:157],\n\t_RoutingTableName[157:159],\n\t_RoutingTableName[159:161],\n\t_RoutingTableName[161:163],\n\t_RoutingTableName[163:165],\n\t_RoutingTableName[165:167],\n\t_RoutingTableName[167:169],\n\t_RoutingTableName[169:171],\n\t_RoutingTableName[171:173],\n\t_RoutingTableName[173:175],\n\t_RoutingTableName[175:177],\n\t_RoutingTableName[177:179],\n\t_RoutingTableName[179:181],\n\t_RoutingTableName[181:183],\n\t_RoutingTableName[183:185],\n\t_RoutingTableName[185:187],\n\t_RoutingTableName[187:189],\n\t_RoutingTableName[189:191],\n\t_RoutingTableName[191:193],\n\t_RoutingTableName[193:195],\n\t_RoutingTableName[195:198],\n\t_RoutingTableName[198:201],\n\t_RoutingTableName[201:204],\n\t_RoutingTableName[204:207],\n\t_RoutingTableName[207:210],\n\t_RoutingTableName[210:213],\n\t_RoutingTableName[213:216],\n\t_RoutingTableName[216:219],\n\t_RoutingTableName[219:222],\n\t_RoutingTableName[222:225],\n\t_RoutingTableName[225:228],\n\t_RoutingTableName[228:231],\n\t_RoutingTableName[231:234],\n\t_RoutingTableName[234:237],\n\t_RoutingTableName[237:240],\n\t_RoutingTableName[240:243],\n\t_RoutingTableName[243:246],\n\t_RoutingTableName[246:249],\n\t_RoutingTableName[249:252],\n\t_RoutingTableName[252:255],\n\t_RoutingTableName[255:258],\n\t_RoutingTableName[258:261],\n\t_RoutingTableName[261:264],\n\t_RoutingTableName[264:267],\n\t_RoutingTableName[267:270],\n\t_RoutingTableName[270:273],\n\t_RoutingTableName[273:276],\n\t_RoutingTableName[276:279],\n\t_RoutingTableName[279:282],\n\t_RoutingTableName[282:285],\n\t_RoutingTableName[285:288],\n\t_RoutingTableName[288:291],\n\t_RoutingTableName[291:294],\n\t_RoutingTableName[294:297],\n\t_RoutingTableName[297:300],\n\t_RoutingTableName[300:303],\n\t_RoutingTableName[303:306],\n\t_RoutingTableName[306:309],\n\t_RoutingTableName[309:312],\n\t_RoutingTableName[312:315],\n\t_RoutingTableName[315:318],\n\t_RoutingTableName[318:321],\n\t_RoutingTableName[321:324],\n\t_RoutingTableName[324:327],\n\t_RoutingTableName[327:330],\n\t_RoutingTableName[330:333],\n\t_RoutingTableName[333:336],\n\t_RoutingTableName[336:339],\n\t_RoutingTableName[339:342],\n\t_RoutingTableName[342:345],\n\t_RoutingTableName[345:348],\n\t_RoutingTableName[348:351],\n\t_RoutingTableName[351:354],\n\t_RoutingTableName[354:357],\n\t_RoutingTableName[357:360],\n\t_RoutingTableName[360:363],\n\t_RoutingTableName[363:366],\n\t_RoutingTableName[366:369],\n\t_RoutingTableName[369:372],\n\t_RoutingTableName[372:375],\n\t_RoutingTableName[375:378],\n\t_RoutingTableName[378:381],\n\t_RoutingTableName[381:384],\n\t_RoutingTableName[384:387],\n\t_RoutingTableName[387:390],\n\t_RoutingTableName[390:393],\n\t_RoutingTableName[393:396],\n\t_RoutingTableName[396:399],\n\t_RoutingTableName[399:402],\n\t_RoutingTableName[402:405],\n\t_RoutingTableName[405:408],\n\t_RoutingTableName[408:411],\n\t_RoutingTableName[411:414],\n\t_RoutingTableName[414:417],\n\t_RoutingTableName[417:420],\n\t_RoutingTableName[420:423],\n\t_RoutingTableName[423:426],\n\t_RoutingTableName[426:429],\n\t_RoutingTableName[429:432],\n\t_RoutingTableName[432:435],\n\t_RoutingTableName[435:438],\n\t_RoutingTableName[438:441],\n\t_RoutingTableName[441:444],\n\t_RoutingTableName[444:447],\n\t_RoutingTableName[447:450],\n\t_RoutingTableName[450:453],\n\t_RoutingTableName[453:456],\n\t_RoutingTableName[456:459],\n\t_RoutingTableName[459:462],\n\t_RoutingTableName[462:465],\n\t_RoutingTableName[465:468],\n\t_RoutingTableName[468:471],\n\t_RoutingTableName[471:474],\n\t_RoutingTableName[474:477],\n\t_RoutingTableName[477:480],\n\t_RoutingTableName[480:483],\n\t_RoutingTableName[483:486],\n\t_RoutingTableName[486:489],\n\t_RoutingTableName[489:492],\n\t_RoutingTableName[492:495],\n\t_RoutingTableName[495:498],\n\t_RoutingTableName[498:501],\n\t_RoutingTableName[501:504],\n\t_RoutingTableName[504:507],\n\t_RoutingTableName[507:510],\n\t_RoutingTableName[510:513],\n\t_RoutingTableName[513:516],\n\t_RoutingTableName[516:519],\n\t_RoutingTableName[519:522],\n\t_RoutingTableName[522:525],\n\t_RoutingTableName[525:528],\n\t_RoutingTableName[528:531],\n\t_RoutingTableName[531:534],\n\t_RoutingTableName[534:537],\n\t_RoutingTableName[537:540],\n\t_RoutingTableName[540:543],\n\t_RoutingTableName[543:546],\n\t_RoutingTableName[546:549],\n\t_RoutingTableName[549:552],\n\t_RoutingTableName[552:555],\n\t_RoutingTableName[555:558],\n\t_RoutingTableName[558:561],\n\t_RoutingTableName[561:564],\n\t_RoutingTableName[564:567],\n\t_RoutingTableName[567:570],\n\t_RoutingTableName[570:573],\n\t_RoutingTableName[573:576],\n\t_RoutingTableName[576:579],\n\t_RoutingTableName[579:582],\n\t_RoutingTableName[582:585],\n\t_RoutingTableName[585:588],\n\t_RoutingTableName[588:591],\n\t_RoutingTableName[591:594],\n\t_RoutingTableName[594:597],\n\t_RoutingTableName[597:600],\n\t_RoutingTableName[600:603],\n\t_RoutingTableName[603:606],\n\t_RoutingTableName[606:609],\n\t_RoutingTableName[609:612],\n\t_RoutingTableName[612:615],\n\t_RoutingTableName[615:618],\n\t_RoutingTableName[618:621],\n\t_RoutingTableName[621:624],\n\t_RoutingTableName[624:627],\n\t_RoutingTableName[627:630],\n\t_RoutingTableName[630:633],\n\t_RoutingTableName[633:636],\n\t_RoutingTableName[636:639],\n\t_RoutingTableName[639:642],\n\t_RoutingTableName[642:645],\n\t_RoutingTableName[645:648],\n\t_RoutingTableName[648:651],\n\t_RoutingTableName[651:654],\n\t_RoutingTableName[654:661],\n\t_RoutingTableName[661:665],\n\t_RoutingTableName[665:670],\n}\n\n// RoutingTableString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc RoutingTableString(s string) (RoutingTable, error) {\n\tif val, ok := _RoutingTableNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _RoutingTableNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to RoutingTable values\", s)\n}\n\n// RoutingTableValues returns all values of the enum\nfunc RoutingTableValues() []RoutingTable {\n\treturn _RoutingTableValues\n}\n\n// RoutingTableStrings returns a slice of all String values of the enum\nfunc RoutingTableStrings() []string {\n\tstrs := make([]string, len(_RoutingTableNames))\n\tcopy(strs, _RoutingTableNames)\n\treturn strs\n}\n\n// IsARoutingTable returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i RoutingTable) IsARoutingTable() bool {\n\tfor _, v := range _RoutingTableValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for RoutingTable\nfunc (i RoutingTable) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for RoutingTable\nfunc (i *RoutingTable) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = RoutingTableString(string(text))\n\treturn err\n}\n\nconst (\n\t_ScopeName_0      = \"global\"\n\t_ScopeLowerName_0 = \"global\"\n\t_ScopeName_1      = \"site\"\n\t_ScopeLowerName_1 = \"site\"\n\t_ScopeName_2      = \"linkhostnowhere\"\n\t_ScopeLowerName_2 = \"linkhostnowhere\"\n)\n\nvar (\n\t_ScopeIndex_0 = [...]uint8{0, 6}\n\t_ScopeIndex_1 = [...]uint8{0, 4}\n\t_ScopeIndex_2 = [...]uint8{0, 4, 8, 15}\n)\n\nfunc (i Scope) String() string {\n\tswitch {\n\tcase i == 0:\n\t\treturn _ScopeName_0\n\tcase i == 200:\n\t\treturn _ScopeName_1\n\tcase 253 <= i && i <= 255:\n\t\ti -= 253\n\t\treturn _ScopeName_2[_ScopeIndex_2[i]:_ScopeIndex_2[i+1]]\n\tdefault:\n\t\treturn fmt.Sprintf(\"Scope(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ScopeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ScopeGlobal-(0)]\n\t_ = x[ScopeSite-(200)]\n\t_ = x[ScopeLink-(253)]\n\t_ = x[ScopeHost-(254)]\n\t_ = x[ScopeNowhere-(255)]\n}\n\nvar _ScopeValues = []Scope{ScopeGlobal, ScopeSite, ScopeLink, ScopeHost, ScopeNowhere}\n\nvar _ScopeNameToValueMap = map[string]Scope{\n\t_ScopeName_0[0:6]:       ScopeGlobal,\n\t_ScopeLowerName_0[0:6]:  ScopeGlobal,\n\t_ScopeName_1[0:4]:       ScopeSite,\n\t_ScopeLowerName_1[0:4]:  ScopeSite,\n\t_ScopeName_2[0:4]:       ScopeLink,\n\t_ScopeLowerName_2[0:4]:  ScopeLink,\n\t_ScopeName_2[4:8]:       ScopeHost,\n\t_ScopeLowerName_2[4:8]:  ScopeHost,\n\t_ScopeName_2[8:15]:      ScopeNowhere,\n\t_ScopeLowerName_2[8:15]: ScopeNowhere,\n}\n\nvar _ScopeNames = []string{\n\t_ScopeName_0[0:6],\n\t_ScopeName_1[0:4],\n\t_ScopeName_2[0:4],\n\t_ScopeName_2[4:8],\n\t_ScopeName_2[8:15],\n}\n\n// ScopeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ScopeString(s string) (Scope, error) {\n\tif val, ok := _ScopeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ScopeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Scope values\", s)\n}\n\n// ScopeValues returns all values of the enum\nfunc ScopeValues() []Scope {\n\treturn _ScopeValues\n}\n\n// ScopeStrings returns a slice of all String values of the enum\nfunc ScopeStrings() []string {\n\tstrs := make([]string, len(_ScopeNames))\n\tcopy(strs, _ScopeNames)\n\treturn strs\n}\n\n// IsAScope returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Scope) IsAScope() bool {\n\tfor _, v := range _ScopeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Scope\nfunc (i Scope) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Scope\nfunc (i *Scope) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ScopeString(string(text))\n\treturn err\n}\n\nconst _StatusName = \"addressesconnectivityhostnameetcfiles\"\n\nvar _StatusIndex = [...]uint8{0, 9, 21, 29, 37}\n\nconst _StatusLowerName = \"addressesconnectivityhostnameetcfiles\"\n\nfunc (i Status) String() string {\n\ti -= 1\n\tif i < 0 || i >= Status(len(_StatusIndex)-1) {\n\t\treturn fmt.Sprintf(\"Status(%d)\", i+1)\n\t}\n\treturn _StatusName[_StatusIndex[i]:_StatusIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _StatusNoOp() {\n\tvar x [1]struct{}\n\t_ = x[StatusAddresses-(1)]\n\t_ = x[StatusConnectivity-(2)]\n\t_ = x[StatusHostname-(3)]\n\t_ = x[StatusEtcFiles-(4)]\n}\n\nvar _StatusValues = []Status{StatusAddresses, StatusConnectivity, StatusHostname, StatusEtcFiles}\n\nvar _StatusNameToValueMap = map[string]Status{\n\t_StatusName[0:9]:        StatusAddresses,\n\t_StatusLowerName[0:9]:   StatusAddresses,\n\t_StatusName[9:21]:       StatusConnectivity,\n\t_StatusLowerName[9:21]:  StatusConnectivity,\n\t_StatusName[21:29]:      StatusHostname,\n\t_StatusLowerName[21:29]: StatusHostname,\n\t_StatusName[29:37]:      StatusEtcFiles,\n\t_StatusLowerName[29:37]: StatusEtcFiles,\n}\n\nvar _StatusNames = []string{\n\t_StatusName[0:9],\n\t_StatusName[9:21],\n\t_StatusName[21:29],\n\t_StatusName[29:37],\n}\n\n// StatusString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc StatusString(s string) (Status, error) {\n\tif val, ok := _StatusNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _StatusNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Status values\", s)\n}\n\n// StatusValues returns all values of the enum\nfunc StatusValues() []Status {\n\treturn _StatusValues\n}\n\n// StatusStrings returns a slice of all String values of the enum\nfunc StatusStrings() []string {\n\tstrs := make([]string, len(_StatusNames))\n\tcopy(strs, _StatusNames)\n\treturn strs\n}\n\n// IsAStatus returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Status) IsAStatus() bool {\n\tfor _, v := range _StatusValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Status\nfunc (i Status) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Status\nfunc (i *Status) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = StatusString(string(text))\n\treturn err\n}\n\nconst (\n\t_VLANProtocolName_0      = \"802.1q\"\n\t_VLANProtocolLowerName_0 = \"802.1q\"\n\t_VLANProtocolName_1      = \"802.1ad\"\n\t_VLANProtocolLowerName_1 = \"802.1ad\"\n)\n\nvar (\n\t_VLANProtocolIndex_0 = [...]uint8{0, 6}\n\t_VLANProtocolIndex_1 = [...]uint8{0, 7}\n)\n\nfunc (i VLANProtocol) String() string {\n\tswitch {\n\tcase i == 33024:\n\t\treturn _VLANProtocolName_0\n\tcase i == 34984:\n\t\treturn _VLANProtocolName_1\n\tdefault:\n\t\treturn fmt.Sprintf(\"VLANProtocol(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _VLANProtocolNoOp() {\n\tvar x [1]struct{}\n\t_ = x[VLANProtocol8021Q-(33024)]\n\t_ = x[VLANProtocol8021AD-(34984)]\n}\n\nvar _VLANProtocolValues = []VLANProtocol{VLANProtocol8021Q, VLANProtocol8021AD}\n\nvar _VLANProtocolNameToValueMap = map[string]VLANProtocol{\n\t_VLANProtocolName_0[0:6]:      VLANProtocol8021Q,\n\t_VLANProtocolLowerName_0[0:6]: VLANProtocol8021Q,\n\t_VLANProtocolName_1[0:7]:      VLANProtocol8021AD,\n\t_VLANProtocolLowerName_1[0:7]: VLANProtocol8021AD,\n}\n\nvar _VLANProtocolNames = []string{\n\t_VLANProtocolName_0[0:6],\n\t_VLANProtocolName_1[0:7],\n}\n\n// VLANProtocolString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc VLANProtocolString(s string) (VLANProtocol, error) {\n\tif val, ok := _VLANProtocolNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _VLANProtocolNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to VLANProtocol values\", s)\n}\n\n// VLANProtocolValues returns all values of the enum\nfunc VLANProtocolValues() []VLANProtocol {\n\treturn _VLANProtocolValues\n}\n\n// VLANProtocolStrings returns a slice of all String values of the enum\nfunc VLANProtocolStrings() []string {\n\tstrs := make([]string, len(_VLANProtocolNames))\n\tcopy(strs, _VLANProtocolNames)\n\treturn strs\n}\n\n// IsAVLANProtocol returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i VLANProtocol) IsAVLANProtocol() bool {\n\tfor _, v := range _VLANProtocolValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for VLANProtocol\nfunc (i VLANProtocol) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for VLANProtocol\nfunc (i *VLANProtocol) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = VLANProtocolString(string(text))\n\treturn err\n}\n\nconst (\n\t_WOLModeName_0      = \"phyunicast\"\n\t_WOLModeLowerName_0 = \"phyunicast\"\n\t_WOLModeName_1      = \"multicast\"\n\t_WOLModeLowerName_1 = \"multicast\"\n\t_WOLModeName_2      = \"broadcast\"\n\t_WOLModeLowerName_2 = \"broadcast\"\n\t_WOLModeName_3      = \"magic\"\n\t_WOLModeLowerName_3 = \"magic\"\n\t_WOLModeName_4      = \"magicsecure\"\n\t_WOLModeLowerName_4 = \"magicsecure\"\n\t_WOLModeName_5      = \"filter\"\n\t_WOLModeLowerName_5 = \"filter\"\n)\n\nvar (\n\t_WOLModeIndex_0 = [...]uint8{0, 3, 10}\n\t_WOLModeIndex_1 = [...]uint8{0, 9}\n\t_WOLModeIndex_2 = [...]uint8{0, 9}\n\t_WOLModeIndex_3 = [...]uint8{0, 5}\n\t_WOLModeIndex_4 = [...]uint8{0, 11}\n\t_WOLModeIndex_5 = [...]uint8{0, 6}\n)\n\nfunc (i WOLMode) String() string {\n\tswitch {\n\tcase 1 <= i && i <= 2:\n\t\ti -= 1\n\t\treturn _WOLModeName_0[_WOLModeIndex_0[i]:_WOLModeIndex_0[i+1]]\n\tcase i == 4:\n\t\treturn _WOLModeName_1\n\tcase i == 8:\n\t\treturn _WOLModeName_2\n\tcase i == 32:\n\t\treturn _WOLModeName_3\n\tcase i == 64:\n\t\treturn _WOLModeName_4\n\tcase i == 128:\n\t\treturn _WOLModeName_5\n\tdefault:\n\t\treturn fmt.Sprintf(\"WOLMode(%d)\", i)\n\t}\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _WOLModeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[WOLModePhy-(1)]\n\t_ = x[WOLModeUnicast-(2)]\n\t_ = x[WOLModeMulticast-(4)]\n\t_ = x[WOLModeBroadcast-(8)]\n\t_ = x[WOLModeMagic-(32)]\n\t_ = x[WOLModeMagicSecure-(64)]\n\t_ = x[WOLModeFilter-(128)]\n}\n\nvar _WOLModeValues = []WOLMode{WOLModePhy, WOLModeUnicast, WOLModeMulticast, WOLModeBroadcast, WOLModeMagic, WOLModeMagicSecure, WOLModeFilter}\n\nvar _WOLModeNameToValueMap = map[string]WOLMode{\n\t_WOLModeName_0[0:3]:       WOLModePhy,\n\t_WOLModeLowerName_0[0:3]:  WOLModePhy,\n\t_WOLModeName_0[3:10]:      WOLModeUnicast,\n\t_WOLModeLowerName_0[3:10]: WOLModeUnicast,\n\t_WOLModeName_1[0:9]:       WOLModeMulticast,\n\t_WOLModeLowerName_1[0:9]:  WOLModeMulticast,\n\t_WOLModeName_2[0:9]:       WOLModeBroadcast,\n\t_WOLModeLowerName_2[0:9]:  WOLModeBroadcast,\n\t_WOLModeName_3[0:5]:       WOLModeMagic,\n\t_WOLModeLowerName_3[0:5]:  WOLModeMagic,\n\t_WOLModeName_4[0:11]:      WOLModeMagicSecure,\n\t_WOLModeLowerName_4[0:11]: WOLModeMagicSecure,\n\t_WOLModeName_5[0:6]:       WOLModeFilter,\n\t_WOLModeLowerName_5[0:6]:  WOLModeFilter,\n}\n\nvar _WOLModeNames = []string{\n\t_WOLModeName_0[0:3],\n\t_WOLModeName_0[3:10],\n\t_WOLModeName_1[0:9],\n\t_WOLModeName_2[0:9],\n\t_WOLModeName_3[0:5],\n\t_WOLModeName_4[0:11],\n\t_WOLModeName_5[0:6],\n}\n\n// WOLModeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc WOLModeString(s string) (WOLMode, error) {\n\tif val, ok := _WOLModeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _WOLModeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to WOLMode values\", s)\n}\n\n// WOLModeValues returns all values of the enum\nfunc WOLModeValues() []WOLMode {\n\treturn _WOLModeValues\n}\n\n// WOLModeStrings returns a slice of all String values of the enum\nfunc WOLModeStrings() []string {\n\tstrs := make([]string, len(_WOLModeNames))\n\tcopy(strs, _WOLModeNames)\n\treturn strs\n}\n\n// IsAWOLMode returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i WOLMode) IsAWOLMode() bool {\n\tfor _, v := range _WOLModeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for WOLMode\nfunc (i WOLMode) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for WOLMode\nfunc (i *WOLMode) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = WOLModeString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/arpvalidate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// ARPValidate is an ARP Validation mode.\ntype ARPValidate uint32\n\n// ARPValidate constants.\n//\n//structprotogen:gen_enum\nconst (\n\tARPValidateNone         ARPValidate = iota // none\n\tARPValidateActive                          // active\n\tARPValidateBackup                          // backup\n\tARPValidateAll                             // all\n\tARPValidateFilter                          // filter\n\tARPValidateFilterActive                    // filter-active\n\tARPValidateFilterBackup                    // filter-backup\n)\n\n// ARPValidateByName parses ARPValidate.\nfunc ARPValidateByName(a string) (ARPValidate, error) {\n\tswitch a {\n\tcase \"\", \"none\":\n\t\treturn ARPValidateNone, nil\n\tcase \"active\":\n\t\treturn ARPValidateActive, nil\n\tcase \"backup\":\n\t\treturn ARPValidateBackup, nil\n\tcase \"all\":\n\t\treturn ARPValidateAll, nil\n\tcase \"filter\":\n\t\treturn ARPValidateFilter, nil\n\tcase \"filter-active\":\n\t\treturn ARPValidateFilterActive, nil\n\tcase \"filter-backup\":\n\t\treturn ARPValidateFilterBackup, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid arp_validate mode %v\", a)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/autohostnamekind.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// AutoHostnameKind is a kind of automatically generated hostname.\ntype AutoHostnameKind byte\n\n// AutoHostnameKind constants.\n//\n// Note: AutoHostnameKindAddr is a legacy setting for backwards compatibility, and\n// it is no longer exposed in network multi-doc configuration.\n//\n//structprotogen:gen_enum\nconst (\n\tAutoHostnameKindOff    AutoHostnameKind = iota // off\n\tAutoHostnameKindAddr                           // talos-addr\n\tAutoHostnameKindStable                         // stable\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/bondmode.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// BondMode is a bond mode.\ntype BondMode uint8\n\n// BondMode constants.\n//\n// See linux/if_bonding.h.\n//\n//structprotogen:gen_enum\nconst (\n\tBondModeRoundrobin   BondMode = iota // balance-rr\n\tBondModeActiveBackup                 // active-backup\n\tBondModeXOR                          // balance-xor\n\tBondModeBroadcast                    // broadcast\n\tBondMode8023AD                       // 802.3ad\n\tBondModeTLB                          // balance-tlb\n\tBondModeALB                          // balance-alb\n)\n\n// BondModeByName converts string bond mode into a constant.\nfunc BondModeByName(mode string) (bm BondMode, err error) {\n\tswitch mode {\n\tcase \"\", \"balance-rr\":\n\t\treturn BondModeRoundrobin, nil\n\tcase \"active-backup\":\n\t\treturn BondModeActiveBackup, nil\n\tcase \"balance-xor\":\n\t\treturn BondModeXOR, nil\n\tcase \"broadcast\":\n\t\treturn BondModeBroadcast, nil\n\tcase \"802.3ad\":\n\t\treturn BondMode8023AD, nil\n\tcase \"balance-tlb\":\n\t\treturn BondModeTLB, nil\n\tcase \"balance-alb\":\n\t\treturn BondModeALB, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid bond type %s\", mode)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/bondxmithashpolicy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// BondXmitHashPolicy is a bond hash policy.\ntype BondXmitHashPolicy uint8\n\n// Bond hash policy constants.\n//\n//structprotogen:gen_enum\nconst (\n\tBondXmitPolicyLayer2  BondXmitHashPolicy = iota // layer2\n\tBondXmitPolicyLayer34                           // layer3+4\n\tBondXmitPolicyLayer23                           // layer2+3\n\tBondXmitPolicyEncap23                           // encap2+3\n\tBondXmitPolicyEncap34                           // encap3+4\n)\n\n// BondXmitHashPolicyByName parses bond hash policy.\nfunc BondXmitHashPolicyByName(policy string) (BondXmitHashPolicy, error) {\n\tswitch policy {\n\tcase \"\", \"layer2\":\n\t\treturn BondXmitPolicyLayer2, nil\n\tcase \"layer3+4\":\n\t\treturn BondXmitPolicyLayer34, nil\n\tcase \"layer2+3\":\n\t\treturn BondXmitPolicyLayer23, nil\n\tcase \"encap2+3\":\n\t\treturn BondXmitPolicyEncap23, nil\n\tcase \"encap3+4\":\n\t\treturn BondXmitPolicyEncap34, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid xmit hash policy %v\", policy)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/client_identifier.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// ClientIdentifier is a DHCP client identifier.\ntype ClientIdentifier int\n\n// ClientIdentifier constants.\n//\n//structprotogen:gen_enum\nconst (\n\tClientIdentifierNone ClientIdentifier = iota // none\n\tClientIdentifierMAC                          // mac\n\tClientIdentifierDUID                         // duid\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/conntrack_state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// ConntrackState is a conntrack state.\ntype ConntrackState uint32\n\n// ConntrackState constants.\n//\n//structprotogen:gen_enum\nconst (\n\tConntrackStateNew         ConntrackState = 0x08 // new\n\tConntrackStateRelated     ConntrackState = 0x04 // related\n\tConntrackStateEstablished ConntrackState = 0x02 // established\n\tConntrackStateInvalid     ConntrackState = 0x01 // invalid\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/default_action.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// DefaultAction is a default firewall action.\ntype DefaultAction int\n\n// DefaultAction constants.\nconst (\n\tDefaultActionAccept DefaultAction = iota // accept\n\tDefaultActionBlock                       // block\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/device.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n// DeviceInfo contains device hardware information that can be read from /sys/.\ntype DeviceInfo struct {\n\tBusPath string\n\tPCIID   string\n\tDriver  string\n}\n\n// GetDeviceInfo get additional device information by reading /sys/ directory.\n//\n//nolint:gocyclo\nfunc GetDeviceInfo(deviceName string) (*DeviceInfo, error) {\n\tpath := filepath.Join(\"/sys/class/net/\", deviceName, \"/device/\")\n\n\treadFile := func(path string) (string, error) {\n\t\tf, err := os.Open(path)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tres, err := io.ReadAll(f)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\treturn string(bytes.TrimSpace(res)), nil\n\t}\n\n\t_, err := os.Stat(path)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn &DeviceInfo{}, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tueventContents, err := readFile(filepath.Join(path, \"uevent\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif ueventContents == \"\" {\n\t\treturn &DeviceInfo{}, nil\n\t}\n\n\tdevice := &DeviceInfo{}\n\n\tfor line := range strings.SplitSeq(ueventContents, \"\\n\") {\n\t\tkey, value, found := strings.Cut(line, \"=\")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch key {\n\t\tcase \"DRIVER\":\n\t\t\tdevice.Driver = value\n\t\tcase \"PCI_ID\":\n\t\t\tdevice.PCIID = value\n\t\tcase \"PCI_SLOT_NAME\":\n\t\t\tdevice.BusPath = value\n\t\t}\n\t}\n\n\treturn device, nil\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/duplex.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"github.com/mdlayher/ethtool\"\n\n// Duplex wraps ethtool.Duplex for YAML marshaling.\ntype Duplex ethtool.Duplex\n\n// Possible Duplex type values.\n//\n//structprotogen:gen_enum\nconst (\n\tHalf    Duplex = Duplex(ethtool.Half)    // Half\n\tFull    Duplex = Duplex(ethtool.Full)    // Full\n\tUnknown Duplex = Duplex(ethtool.Unknown) // Unknown\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/failovermac.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n)\n\n// FailOverMAC is a MAC failover mode.\ntype FailOverMAC uint8\n\n// FailOverMAC constants.\n//\n//structprotogen:gen_enum\nconst (\n\tFailOverMACNone   FailOverMAC = iota // none\n\tFailOverMACActive                    // active\n\tFailOverMACFollow                    // follow\n)\n\n// FailOverMACByName parses FailOverMac.\nfunc FailOverMACByName(f string) (FailOverMAC, error) {\n\tswitch f {\n\tcase \"\", \"none\":\n\t\treturn FailOverMACNone, nil\n\tcase \"active\":\n\t\treturn FailOverMACActive, nil\n\tcase \"follow\":\n\t\treturn FailOverMACFollow, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid fail_over_mac value %v\", f)\n\t}\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (f FailOverMAC) MarshalText() ([]byte, error) {\n\treturn []byte(f.String()), nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\n//\n// There is some old historical reason we don't use enumer's -text method to automatically\n// generate the MarshalText/UnmarshalText methods - so we have to implement UnmarshalText manually\n// to support both name and numeric representation for backward compatibility.\nfunc (f *FailOverMAC) UnmarshalText(text []byte) error {\n\tparsed, err := FailOverMACByName(string(text))\n\tif err != nil {\n\t\t// for legacy compatibility try to parse as a number\n\t\tout, parseErr := strconv.ParseInt(string(text), 10, 8)\n\t\tif parseErr == nil && out >= int64(FailOverMACNone) && out <= int64(FailOverMACFollow) {\n\t\t\t*f = FailOverMAC(out)\n\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\t*f = parsed\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/failovermac_enumer.go",
    "content": "// Code generated by \"enumer -type=FailOverMAC -linecomment\"; DO NOT EDIT.\n\npackage nethelpers\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _FailOverMACName = \"noneactivefollow\"\n\nvar _FailOverMACIndex = [...]uint8{0, 4, 10, 16}\n\nconst _FailOverMACLowerName = \"noneactivefollow\"\n\nfunc (i FailOverMAC) String() string {\n\tif i >= FailOverMAC(len(_FailOverMACIndex)-1) {\n\t\treturn fmt.Sprintf(\"FailOverMAC(%d)\", i)\n\t}\n\treturn _FailOverMACName[_FailOverMACIndex[i]:_FailOverMACIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _FailOverMACNoOp() {\n\tvar x [1]struct{}\n\t_ = x[FailOverMACNone-(0)]\n\t_ = x[FailOverMACActive-(1)]\n\t_ = x[FailOverMACFollow-(2)]\n}\n\nvar _FailOverMACValues = []FailOverMAC{FailOverMACNone, FailOverMACActive, FailOverMACFollow}\n\nvar _FailOverMACNameToValueMap = map[string]FailOverMAC{\n\t_FailOverMACName[0:4]:        FailOverMACNone,\n\t_FailOverMACLowerName[0:4]:   FailOverMACNone,\n\t_FailOverMACName[4:10]:       FailOverMACActive,\n\t_FailOverMACLowerName[4:10]:  FailOverMACActive,\n\t_FailOverMACName[10:16]:      FailOverMACFollow,\n\t_FailOverMACLowerName[10:16]: FailOverMACFollow,\n}\n\nvar _FailOverMACNames = []string{\n\t_FailOverMACName[0:4],\n\t_FailOverMACName[4:10],\n\t_FailOverMACName[10:16],\n}\n\n// FailOverMACString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc FailOverMACString(s string) (FailOverMAC, error) {\n\tif val, ok := _FailOverMACNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _FailOverMACNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to FailOverMAC values\", s)\n}\n\n// FailOverMACValues returns all values of the enum\nfunc FailOverMACValues() []FailOverMAC {\n\treturn _FailOverMACValues\n}\n\n// FailOverMACStrings returns a slice of all String values of the enum\nfunc FailOverMACStrings() []string {\n\tstrs := make([]string, len(_FailOverMACNames))\n\tcopy(strs, _FailOverMACNames)\n\treturn strs\n}\n\n// IsAFailOverMAC returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i FailOverMAC) IsAFailOverMAC() bool {\n\tfor _, v := range _FailOverMACValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/failovermac_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\nfunc TestFailOverMACUnmarshalText(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tinput    string\n\t\texpected nethelpers.FailOverMAC\n\t}{\n\t\t{\n\t\t\tinput:    \"none\",\n\t\t\texpected: nethelpers.FailOverMACNone,\n\t\t},\n\t\t{\n\t\t\tinput:    \"active\",\n\t\t\texpected: nethelpers.FailOverMACActive,\n\t\t},\n\t\t{\n\t\t\tinput:    \"follow\",\n\t\t\texpected: nethelpers.FailOverMACFollow,\n\t\t},\n\t\t{\n\t\t\tinput:    \"\",\n\t\t\texpected: nethelpers.FailOverMACNone,\n\t\t},\n\t\t{\n\t\t\tinput:    \"0\",\n\t\t\texpected: nethelpers.FailOverMACNone,\n\t\t},\n\t\t{\n\t\t\tinput:    \"1\",\n\t\t\texpected: nethelpers.FailOverMACActive,\n\t\t},\n\t\t{\n\t\t\tinput:    \"2\",\n\t\t\texpected: nethelpers.FailOverMACFollow,\n\t\t},\n\t} {\n\t\tt.Run(test.input, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar f nethelpers.FailOverMAC\n\n\t\t\terr := f.UnmarshalText([]byte(test.input))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, f)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/family.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// Family is a network family.\ntype Family uint8\n\n// Family constants.\n//\n//structprotogen:gen_enum\nconst (\n\tFamilyInet4 Family = 2  // inet4\n\tFamilyInet6 Family = 10 // inet6\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/host_port.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"fmt\"\n\t\"net\"\n)\n\ntype ints interface {\n\t~int16 | ~int32 | ~int64 | ~uint16 | ~uint32 | ~uint64 | int | uint\n}\n\n// JoinHostPort is a wrapper around net.JoinHostPort which accepts port any integer type.\nfunc JoinHostPort[T ints](host string, port T) string {\n\treturn net.JoinHostPort(host, fmt.Sprintf(\"%d\", port))\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/hwaddr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"net\"\n)\n\n// HardwareAddr wraps net.HardwareAddr for YAML marshaling.\ntype HardwareAddr net.HardwareAddr\n\n// MarshalText implements text.Marshaler interface.\nfunc (addr HardwareAddr) MarshalText() ([]byte, error) {\n\treturn []byte(net.HardwareAddr(addr).String()), nil\n}\n\n// UnmarshalText implements text.Unmarshaler interface.\nfunc (addr *HardwareAddr) UnmarshalText(b []byte) error {\n\trawHex := bytes.ReplaceAll(b, []byte(\":\"), []byte(\"\"))\n\tdstLen := hex.DecodedLen(len(rawHex))\n\n\tdst := make([]byte, dstLen)\n\n\tn, err := hex.Decode(dst, rawHex)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*addr = HardwareAddr(dst[:n])\n\n\treturn nil\n}\n\nfunc (addr HardwareAddr) String() string {\n\treturn net.HardwareAddr(addr).String()\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/icmp_type.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// ICMPType is a ICMP packet type.\ntype ICMPType byte\n\n// ICMPType constants.\n//\n//structprotogen:gen_enum\nconst (\n\tICMPTypeTimestampRequest   ICMPType = 13 // timestamp-request\n\tICMPTypeTimestampReply     ICMPType = 14 // timestamp-reply\n\tICMPTypeAddressMaskRequest ICMPType = 17 // address-mask-request\n\tICMPTypeAddressMaskReply   ICMPType = 18 // address-mask-reply\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/lacprate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// LACPRate is a LACP rate.\ntype LACPRate uint8\n\n// LACP rate constants.\n//\n//structprotogen:gen_enum\nconst (\n\tLACPRateSlow LACPRate = iota // slow\n\tLACPRateFast                 // fast\n)\n\n// LACPRateByName parses LACPRate.\nfunc LACPRateByName(mode string) (LACPRate, error) {\n\tswitch mode {\n\tcase \"\", \"slow\":\n\t\treturn LACPRateSlow, nil\n\tcase \"fast\":\n\t\treturn LACPRateFast, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid lacp rate %v\", mode)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/linkflag.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"strings\"\n)\n\n// LinkFlags is a bitmask of LinkFlags.\ntype LinkFlags uint32\n\nfunc (flags LinkFlags) String() string {\n\tvar values []string\n\n\tfor flag := LinkUp; flag <= LinkEcho; flag <<= 1 {\n\t\tif (LinkFlag(flags) & flag) == flag {\n\t\t\tvalues = append(values, flag.String())\n\t\t}\n\t}\n\n\treturn strings.Join(values, \",\")\n}\n\n// LinkFlagsString parses string representation of LinkFlags.\nfunc LinkFlagsString(s string) (LinkFlags, error) {\n\tflags := LinkFlags(0)\n\n\tfor p := range strings.SplitSeq(s, \",\") {\n\t\tflag, err := LinkFlagString(p)\n\t\tif err != nil {\n\t\t\treturn flags, err\n\t\t}\n\n\t\tflags |= LinkFlags(flag)\n\t}\n\n\treturn flags, nil\n}\n\n// MarshalText implements text.Marshaler.\nfunc (flags LinkFlags) MarshalText() ([]byte, error) {\n\treturn []byte(flags.String()), nil\n}\n\n// UnmarshalText implements text.Unmarshaler.\nfunc (flags *LinkFlags) UnmarshalText(b []byte) error {\n\tvar err error\n\n\t*flags, err = LinkFlagsString(string(b))\n\n\treturn err\n}\n\n// LinkFlag wraps IFF_* constants.\ntype LinkFlag uint32\n\n// LinkFlag constants.\nconst (\n\tLinkUp           LinkFlag = 1 << iota // UP\n\tLinkBroadcast                         // BROADCAST\n\tLinkDebug                             // DEBUG\n\tLinkLoopback                          // LOOPBACK\n\tLinkPointToPoint                      // POINTTOPOINT\n\tLinkNoTrailers                        // NOTRAILERS\n\tLinkRunning                           // RUNNING\n\tLinkNoArp                             // NOARP\n\tLinkPromisc                           // PROMISC\n\tLinkAllMulti                          // ALLMULTI\n\tLinkMaster                            // MASTER\n\tLinkSlave                             // SLAVE\n\tLinkMulticast                         // MULTICAST\n\tLinkPortsel                           // PORTSEL\n\tLinKAutoMedia                         // AUTOMEDIA\n\tLinkDynamic                           // DYNAMIC\n\tLinkLowerUp                           // LOWER_UP\n\tLinkDormant                           // DORMANT\n\tLinkEcho                              // ECHO\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/linktype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// LinkType is a link type.\ntype LinkType uint16\n\n// LinkType constants.\n//\n//structprotogen:gen_enum\nconst (\n\tLinkNetrom            LinkType = 0                 // netrom\n\tLinkEther             LinkType = 1                 // ether\n\tLinkEether            LinkType = 2                 // eether\n\tLinkAx25              LinkType = 3                 // ax25\n\tLinkPronet            LinkType = 4                 // pronet\n\tLinkChaos             LinkType = 5                 // chaos\n\tLinkIee802            LinkType = 6                 // ieee802\n\tLinkArcnet            LinkType = 7                 // arcnet\n\tLinkAtalk             LinkType = 8                 // atalk\n\tLinkDlci              LinkType = 15                // dlci\n\tLinkAtm               LinkType = 19                // atm\n\tLinkMetricom          LinkType = 23                // metricom\n\tLinkIeee1394          LinkType = 24                // ieee1394\n\tLinkEui64             LinkType = 27                // eui64\n\tLinkInfiniband        LinkType = 32                // infiniband\n\tLinkSlip              LinkType = 256               // slip\n\tLinkCslip             LinkType = 257               // cslip\n\tLinkSlip6             LinkType = 258               // slip6\n\tLinkCslip6            LinkType = 259               // cslip6\n\tLinkRsrvd             LinkType = 260               // rsrvd\n\tLinkAdapt             LinkType = 264               // adapt\n\tLinkRose              LinkType = 270               // rose\n\tLinkX25               LinkType = 271               // x25\n\tLinkHwx25             LinkType = 272               // hwx25\n\tLinkCan               LinkType = 280               // can\n\tLinkPpp               LinkType = 512               // ppp\n\tLinkCisco             LinkType = 513               // cisco\n\tLinkHdlc              LinkType = 513               // hdlc\n\tLinkLapb              LinkType = 516               // lapb\n\tLinkDdcmp             LinkType = 517               // ddcmp\n\tLinkRawhdlc           LinkType = 518               // rawhdlc\n\tLinkTunnel            LinkType = 768               // ipip\n\tLinkTunnel6           LinkType = 769               // tunnel6\n\tLinkFrad              LinkType = 770               // frad\n\tLinkSkip              LinkType = 771               // skip\n\tLinkLoopbck           LinkType = 772               // loopback\n\tLinkLocaltlk          LinkType = 773               // localtlk\n\tLinkFddi              LinkType = 774               // fddi\n\tLinkBif               LinkType = 775               // bif\n\tLinkSit               LinkType = 776               // sit\n\tLinkIpddp             LinkType = 777               // ip/ddp\n\tLinkIpgre             LinkType = 778               // gre\n\tLinkPimreg            LinkType = 779               // pimreg\n\tLinkHippi             LinkType = 780               // hippi\n\tLinkAsh               LinkType = 781               // ash\n\tLinkEconet            LinkType = 782               // econet\n\tLinkIrda              LinkType = 783               // irda\n\tLinkFcpp              LinkType = 784               // fcpp\n\tLinkFcal              LinkType = 785               // fcal\n\tLinkFcpl              LinkType = 786               // fcpl\n\tLinkFcfabric          LinkType = 787               // fcfb_0\n\tLinkFcfabric1         LinkType = LinkFcfabric + 1  // fcfb_1\n\tLinkFcfabric2         LinkType = LinkFcfabric + 2  // fcfb_2\n\tLinkFcfabric3         LinkType = LinkFcfabric + 3  // fcfb_3\n\tLinkFcfabric4         LinkType = LinkFcfabric + 4  // fcfb_4\n\tLinkFcfabric5         LinkType = LinkFcfabric + 5  // fcfb_5\n\tLinkFcfabric6         LinkType = LinkFcfabric + 6  // fcfb_6\n\tLinkFcfabric7         LinkType = LinkFcfabric + 7  // fcfb_7\n\tLinkFcfabric8         LinkType = LinkFcfabric + 8  // fcfb_8\n\tLinkFcfabric9         LinkType = LinkFcfabric + 9  // fcfb_9\n\tLinkFcfabric10        LinkType = LinkFcfabric + 10 // fcfb_10\n\tLinkFcfabric11        LinkType = LinkFcfabric + 11 // fcfb_11\n\tLinkFcfabric12        LinkType = LinkFcfabric + 12 // fcfb_12\n\tLinkIee802tr          LinkType = 800               // tr\n\tLinkIee80211          LinkType = 801               // ieee802.11\n\tLinkIee80211prism     LinkType = 802               // ieee802.11_prism\n\tLinkIee80211Radiotap  LinkType = 803               // ieee802.11_radiotap\n\tLinkIee8021154        LinkType = 804               // ieee802.15.4\n\tLinkIee8021154monitor LinkType = 805               // ieee802.15.4_monitor\n\tLinkPhonet            LinkType = 820               // phonet\n\tLinkPhonetpipe        LinkType = 821               // phonet_pipe\n\tLinkCaif              LinkType = 822               // caif\n\tLinkIP6gre            LinkType = 823               // ip6gre\n\tLinkNetlink           LinkType = 824               // netlink\n\tLink6Lowpan           LinkType = 825               // 6lowpan\n\tLinkVoid              LinkType = 65535             // void\n\tLinkNone              LinkType = 65534             // nohdr\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/match_operator.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// MatchOperator is a netfilter match operator.\ntype MatchOperator int\n\n// MatchOperator constants.\n//\n//structprotogen:gen_enum\nconst (\n\tOperatorEqual    MatchOperator = 0 // ==\n\tOperatorNotEqual MatchOperator = 1 // !=\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/nethelpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package nethelpers provides types and type wrappers to support network resources.\npackage nethelpers\n\n//go:generate go tool github.com/dmarkham/enumer -type=ARPAllTargets,ARPValidate,AddressFlag,AddressSortAlgorithm,ADSelect,ADLACPActive,AutoHostnameKind,BondMode,BondXmitHashPolicy,ClientIdentifier,ConntrackState,DefaultAction,Duplex,Family,LACPRate,LinkFlag,LinkType,MatchOperator,NfTablesChainHook,NfTablesChainPriority,NfTablesVerdict,OperationalState,Port,PrimaryReselect,Protocol,RouteFlag,RouteProtocol,RouteType,RoutingRuleAction,RoutingTable,Scope,Status,VLANProtocol,WOLMode -linecomment -text\n//go:generate go tool github.com/dmarkham/enumer -type=FailOverMAC -linecomment\n"
  },
  {
    "path": "pkg/machinery/nethelpers/nftables_chain_hook.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// NfTablesChainHook wraps nftables.ChainHook for YAML marshaling.\ntype NfTablesChainHook uint32\n\n// Constants copied from nftables to provide Stringer interface.\n//\n//structprotogen:gen_enum\nconst (\n\tChainHookPrerouting  NfTablesChainHook = 0 // prerouting\n\tChainHookInput       NfTablesChainHook = 1 // input\n\tChainHookForward     NfTablesChainHook = 2 // forward\n\tChainHookOutput      NfTablesChainHook = 3 // output\n\tChainHookPostrouting NfTablesChainHook = 4 // postrouting\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/nftables_chain_priority.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"math\"\n\n// NfTablesChainPriority wraps nftables.ChainPriority for YAML marshaling.\ntype NfTablesChainPriority int32\n\n// Constants copied from nftables to provide Stringer interface.\n//\n//structprotogen:gen_enum\nconst (\n\tChainPriorityFirst           NfTablesChainPriority = math.MinInt32 // first\n\tChainPriorityConntrackDefrag NfTablesChainPriority = -400          // conntrack-defrag\n\tChainPriorityRaw             NfTablesChainPriority = -300          // raw\n\tChainPrioritySELinuxFirst    NfTablesChainPriority = -225          // selinux-first\n\tChainPriorityConntrack       NfTablesChainPriority = -200          // conntrack\n\tChainPriorityMangle          NfTablesChainPriority = -150          // mangle\n\tChainPriorityNATDest         NfTablesChainPriority = -100          // nat-dest\n\tChainPriorityFilter          NfTablesChainPriority = 0             // filter\n\tChainPrioritySecurity        NfTablesChainPriority = 50            // security\n\tChainPriorityNATSource       NfTablesChainPriority = 100           // nat-source\n\tChainPrioritySELinuxLast     NfTablesChainPriority = 225           // selinux-last\n\tChainPriorityConntrackHelper NfTablesChainPriority = 300           // conntrack-helper\n\tChainPriorityLast            NfTablesChainPriority = math.MaxInt32 // last\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/nftables_chain_type.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// NfTablesChainType defines what this chain will be used for. See also\n// https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types\ntype NfTablesChainType = string\n\n// Possible ChainType values.\nconst (\n\tChainTypeFilter NfTablesChainType = \"filter\"\n\tChainTypeRoute  NfTablesChainType = \"route\"\n\tChainTypeNAT    NfTablesChainType = \"nat\"\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/nftables_verdict.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// NfTablesVerdict wraps nftables.Verdict for YAML marshaling.\ntype NfTablesVerdict int64\n\n// Constants copied from nftables to provide Stringer interface.\n//\n//structprotogen:gen_enum\nconst (\n\tVerdictDrop   NfTablesVerdict = 0 // drop\n\tVerdictAccept NfTablesVerdict = 1 // accept\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/operstate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n)\n\n// OperationalState wraps rtnetlink.OperationalState for YAML marshaling.\ntype OperationalState uint8\n\n// Constants copied from rtnetlink to provide Stringer interface.\n//\n//structprotogen:gen_enum\nconst (\n\tOperStateUnknown        OperationalState = OperationalState(rtnetlink.OperStateUnknown)        // unknown\n\tOperStateNotPresent     OperationalState = OperationalState(rtnetlink.OperStateNotPresent)     // notPresent\n\tOperStateDown           OperationalState = OperationalState(rtnetlink.OperStateDown)           // down\n\tOperStateLowerLayerDown OperationalState = OperationalState(rtnetlink.OperStateLowerLayerDown) // lowerLayerDown\n\tOperStateTesting        OperationalState = OperationalState(rtnetlink.OperStateTesting)        // testing\n\tOperStateDormant        OperationalState = OperationalState(rtnetlink.OperStateDormant)        // dormant\n\tOperStateUp             OperationalState = OperationalState(rtnetlink.OperStateUp)             // up\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/port.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"github.com/mdlayher/ethtool\"\n\n// Port wraps ethtool.Port for YAML marshaling.\ntype Port ethtool.Port\n\n// Possible Port type values.\n//\n//structprotogen:gen_enum\nconst (\n\tTwistedPair  Port = Port(ethtool.TwistedPair)\n\tAUI          Port = Port(ethtool.AUI)\n\tMII          Port = Port(ethtool.MII)\n\tFibre        Port = Port(ethtool.Fibre) //nolint:misspell\n\tBNC          Port = Port(ethtool.BNC)\n\tDirectAttach Port = Port(ethtool.DirectAttach)\n\tNone         Port = Port(ethtool.None)\n\tOther        Port = Port(ethtool.Other)\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/primaryreselect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"fmt\"\n\n// PrimaryReselect is an ARP targets mode.\ntype PrimaryReselect uint8\n\n// PrimaryReslect constants.\n//\n//structprotogen:gen_enum\nconst (\n\tPrimaryReselectAlways  PrimaryReselect = iota // always\n\tPrimaryReselectBetter                         // better\n\tPrimaryReselectFailure                        // failure\n)\n\n// PrimaryReselectByName parses PrimaryReselect.\nfunc PrimaryReselectByName(p string) (PrimaryReselect, error) {\n\tswitch p {\n\tcase \"\", \"always\":\n\t\treturn PrimaryReselectAlways, nil\n\tcase \"better\":\n\t\treturn PrimaryReselectBetter, nil\n\tcase \"failure\":\n\t\treturn PrimaryReselectFailure, nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"invalid primary_reselect mode %v\", p)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/protocol.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// Protocol is a inet protocol.\ntype Protocol uint8\n\n// Protocol constants.\n//\n//structprotogen:gen_enum\nconst (\n\tProtocolICMP   Protocol = 0x1  // icmp\n\tProtocolTCP    Protocol = 0x6  // tcp\n\tProtocolUDP    Protocol = 0x11 // udp\n\tProtocolICMPv6 Protocol = 0x3a // icmpv6\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routeflags.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"strings\"\n)\n\n// RouteFlags is a bitmask of RouteFlag.\ntype RouteFlags uint32\n\nfunc (flags RouteFlags) String() string {\n\tvar values []string\n\n\tfor flag := RouteNotify; flag <= RouteTrap; flag <<= 1 {\n\t\tif (RouteFlag(flags) & flag) == flag {\n\t\t\tvalues = append(values, flag.String())\n\t\t}\n\t}\n\n\treturn strings.Join(values, \",\")\n}\n\n// RouteFlagsString parses string representation into RouteFlags.\nfunc RouteFlagsString(s string) (RouteFlags, error) {\n\tflags := RouteFlags(0)\n\n\tif s == \"\" {\n\t\treturn flags, nil\n\t}\n\n\tfor p := range strings.SplitSeq(s, \",\") {\n\t\tflag, err := RouteFlagString(p)\n\t\tif err != nil {\n\t\t\treturn flags, err\n\t\t}\n\n\t\tflags |= RouteFlags(flag)\n\t}\n\n\treturn flags, nil\n}\n\n// Equal tests for RouteFlags equality ignoring flags not managed by this implementation.\nfunc (flags RouteFlags) Equal(other RouteFlags) bool {\n\treturn (flags & RouteFlags(RouteFlagsMask)) == (other & RouteFlags(RouteFlagsMask))\n}\n\n// MarshalText implements text.Marshaler.\nfunc (flags RouteFlags) MarshalText() ([]byte, error) {\n\treturn []byte(flags.String()), nil\n}\n\n// UnmarshalText implements text.Unmarshaler.\nfunc (flags *RouteFlags) UnmarshalText(b []byte) error {\n\tvar err error\n\n\t*flags, err = RouteFlagsString(string(b))\n\n\treturn err\n}\n\n// RouteFlag wraps RTM_F_* constants.\ntype RouteFlag uint32\n\n// RouteFlag constants.\n//\n//structprotogen:gen_enum\nconst (\n\tRouteNotify      RouteFlag = 256 << iota // notify\n\tRouteCloned                              // cloned\n\tRouteEqualize                            // equalize\n\tRoutePrefix                              // prefix\n\tRouteLookupTable                         // lookup_table\n\tRouteFIBMatch                            // fib_match\n\tRouteOffload                             // offload\n\tRouteTrap                                // trap\n)\n\n// RouteFlagsMask is a supported set of flags to manage.\nconst RouteFlagsMask = RouteNotify | RouteCloned | RouteEqualize | RoutePrefix\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routeflags_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\nfunc TestRouteFlagsStrings(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\trouteFlagsString string\n\t\texpected         nethelpers.RouteFlags\n\t}{\n\t\t{\n\t\t\trouteFlagsString: \"\",\n\t\t\texpected:         nethelpers.RouteFlags(0),\n\t\t},\n\t\t{\n\t\t\trouteFlagsString: \"cloned\",\n\t\t\texpected:         nethelpers.RouteFlags(nethelpers.RouteCloned),\n\t\t},\n\t\t{\n\t\t\trouteFlagsString: \"cloned,prefix\",\n\t\t\texpected:         nethelpers.RouteFlags(nethelpers.RouteCloned | nethelpers.RoutePrefix),\n\t\t},\n\t} {\n\t\trouteFlags, err := nethelpers.RouteFlagsString(tt.routeFlagsString)\n\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, tt.expected, routeFlags)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routeprotocol.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// RouteProtocol is a routing protocol.\ntype RouteProtocol uint8\n\n// RouteType constants.\n//\n//structprotogen:gen_enum\nconst (\n\tProtocolUnspec     RouteProtocol = 0   // unspec\n\tProtocolRedirect   RouteProtocol = 1   // redirect\n\tProtocolKernel     RouteProtocol = 2   // kernel\n\tProtocolBoot       RouteProtocol = 3   // boot\n\tProtocolStatic     RouteProtocol = 4   // static\n\tProtocolRA         RouteProtocol = 9   // ra\n\tProtocolMRT        RouteProtocol = 10  // mrt\n\tProtocolZebra      RouteProtocol = 11  // zebra\n\tProtocolBird       RouteProtocol = 12  // bird\n\tProtocolDnrouted   RouteProtocol = 13  // dnrouted\n\tProtocolXorp       RouteProtocol = 14  // xorp\n\tProtocolNTK        RouteProtocol = 15  // ntk\n\tProtocolDHCP       RouteProtocol = 16  // dhcp\n\tProtocolMRTD       RouteProtocol = 17  // mrtd\n\tProtocolKeepalived RouteProtocol = 18  // keepalived\n\tProtocolBabel      RouteProtocol = 42  // babel\n\tProtocolOpenr      RouteProtocol = 99  // openr\n\tProtocolBGP        RouteProtocol = 186 // bgp\n\tProtocolISIS       RouteProtocol = 187 // isis\n\tProtocolOSPF       RouteProtocol = 188 // ospf\n\tProtocolRIP        RouteProtocol = 189 // rip\n\tProtocolEIGRP      RouteProtocol = 192 // eigrp\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routetype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// RouteType is a route type.\ntype RouteType uint8\n\n// RouteType constants.\n//\n//structprotogen:gen_enum\nconst (\n\tTypeUnspec      RouteType = iota // unspec\n\tTypeUnicast                      // unicast\n\tTypeLocal                        // local\n\tTypeBroadcast                    // broadcast\n\tTypeAnycast                      // anycast\n\tTypeMulticast                    // multicast\n\tTypeBlackhole                    // blackhole\n\tTypeUnreachable                  // unreachable\n\tTypeProhibit                     // prohibit\n\tTypeThrow                        // throw\n\tTypeNAT                          // nat\n\tTypeXResolve                     // xresolve\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routingruleaction.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// RoutingRuleAction is a routing rule action.\ntype RoutingRuleAction uint8\n\n// RoutingRuleAction constants.\n//\n//structprotogen:gen_enum\nconst (\n\tRoutingRuleActionUnspec      RoutingRuleAction = 0 // unspec\n\tRoutingRuleActionUnicast     RoutingRuleAction = 1 // unicast\n\tRoutingRuleActionBlackhole   RoutingRuleAction = 6 // blackhole\n\tRoutingRuleActionUnreachable RoutingRuleAction = 7 // unreachable\n\tRoutingRuleActionProhibit    RoutingRuleAction = 8 // prohibit\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/routingtable.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// RoutingTable is a routing table ID.\ntype RoutingTable uint32\n\n// RoutingTable constants.\n//\n//structprotogen:gen_enum\nconst (\n\tTableUnspec  RoutingTable = 0   // unspec\n\tTable1       RoutingTable = 1   // 1\n\tTable2       RoutingTable = 2   // 2\n\tTable3       RoutingTable = 3   // 3\n\tTable4       RoutingTable = 4   // 4\n\tTable5       RoutingTable = 5   // 5\n\tTable6       RoutingTable = 6   // 6\n\tTable7       RoutingTable = 7   // 7\n\tTable8       RoutingTable = 8   // 8\n\tTable9       RoutingTable = 9   // 9\n\tTable10      RoutingTable = 10  // 10\n\tTable11      RoutingTable = 11  // 11\n\tTable12      RoutingTable = 12  // 12\n\tTable13      RoutingTable = 13  // 13\n\tTable14      RoutingTable = 14  // 14\n\tTable15      RoutingTable = 15  // 15\n\tTable16      RoutingTable = 16  // 16\n\tTable17      RoutingTable = 17  // 17\n\tTable18      RoutingTable = 18  // 18\n\tTable19      RoutingTable = 19  // 19\n\tTable20      RoutingTable = 20  // 20\n\tTable21      RoutingTable = 21  // 21\n\tTable22      RoutingTable = 22  // 22\n\tTable23      RoutingTable = 23  // 23\n\tTable24      RoutingTable = 24  // 24\n\tTable25      RoutingTable = 25  // 25\n\tTable26      RoutingTable = 26  // 26\n\tTable27      RoutingTable = 27  // 27\n\tTable28      RoutingTable = 28  // 28\n\tTable29      RoutingTable = 29  // 29\n\tTable30      RoutingTable = 30  // 30\n\tTable31      RoutingTable = 31  // 31\n\tTable32      RoutingTable = 32  // 32\n\tTable33      RoutingTable = 33  // 33\n\tTable34      RoutingTable = 34  // 34\n\tTable35      RoutingTable = 35  // 35\n\tTable36      RoutingTable = 36  // 36\n\tTable37      RoutingTable = 37  // 37\n\tTable38      RoutingTable = 38  // 38\n\tTable39      RoutingTable = 39  // 39\n\tTable40      RoutingTable = 40  // 40\n\tTable41      RoutingTable = 41  // 41\n\tTable42      RoutingTable = 42  // 42\n\tTable43      RoutingTable = 43  // 43\n\tTable44      RoutingTable = 44  // 44\n\tTable45      RoutingTable = 45  // 45\n\tTable46      RoutingTable = 46  // 46\n\tTable47      RoutingTable = 47  // 47\n\tTable48      RoutingTable = 48  // 48\n\tTable49      RoutingTable = 49  // 49\n\tTable50      RoutingTable = 50  // 50\n\tTable51      RoutingTable = 51  // 51\n\tTable52      RoutingTable = 52  // 52\n\tTable53      RoutingTable = 53  // 53\n\tTable54      RoutingTable = 54  // 54\n\tTable55      RoutingTable = 55  // 55\n\tTable56      RoutingTable = 56  // 56\n\tTable57      RoutingTable = 57  // 57\n\tTable58      RoutingTable = 58  // 58\n\tTable59      RoutingTable = 59  // 59\n\tTable60      RoutingTable = 60  // 60\n\tTable61      RoutingTable = 61  // 61\n\tTable62      RoutingTable = 62  // 62\n\tTable63      RoutingTable = 63  // 63\n\tTable64      RoutingTable = 64  // 64\n\tTable65      RoutingTable = 65  // 65\n\tTable66      RoutingTable = 66  // 66\n\tTable67      RoutingTable = 67  // 67\n\tTable68      RoutingTable = 68  // 68\n\tTable69      RoutingTable = 69  // 69\n\tTable70      RoutingTable = 70  // 70\n\tTable71      RoutingTable = 71  // 71\n\tTable72      RoutingTable = 72  // 72\n\tTable73      RoutingTable = 73  // 73\n\tTable74      RoutingTable = 74  // 74\n\tTable75      RoutingTable = 75  // 75\n\tTable76      RoutingTable = 76  // 76\n\tTable77      RoutingTable = 77  // 77\n\tTable78      RoutingTable = 78  // 78\n\tTable79      RoutingTable = 79  // 79\n\tTable80      RoutingTable = 80  // 80\n\tTable81      RoutingTable = 81  // 81\n\tTable82      RoutingTable = 82  // 82\n\tTable83      RoutingTable = 83  // 83\n\tTable84      RoutingTable = 84  // 84\n\tTable85      RoutingTable = 85  // 85\n\tTable86      RoutingTable = 86  // 86\n\tTable87      RoutingTable = 87  // 87\n\tTable88      RoutingTable = 88  // 88\n\tTable89      RoutingTable = 89  // 89\n\tTable90      RoutingTable = 90  // 90\n\tTable91      RoutingTable = 91  // 91\n\tTable92      RoutingTable = 92  // 92\n\tTable93      RoutingTable = 93  // 93\n\tTable94      RoutingTable = 94  // 94\n\tTable95      RoutingTable = 95  // 95\n\tTable96      RoutingTable = 96  // 96\n\tTable97      RoutingTable = 97  // 97\n\tTable98      RoutingTable = 98  // 98\n\tTable99      RoutingTable = 99  // 99\n\tTable100     RoutingTable = 100 // 100\n\tTable101     RoutingTable = 101 // 101\n\tTable102     RoutingTable = 102 // 102\n\tTable103     RoutingTable = 103 // 103\n\tTable104     RoutingTable = 104 // 104\n\tTable105     RoutingTable = 105 // 105\n\tTable106     RoutingTable = 106 // 106\n\tTable107     RoutingTable = 107 // 107\n\tTable108     RoutingTable = 108 // 108\n\tTable109     RoutingTable = 109 // 109\n\tTable110     RoutingTable = 110 // 110\n\tTable111     RoutingTable = 111 // 111\n\tTable112     RoutingTable = 112 // 112\n\tTable113     RoutingTable = 113 // 113\n\tTable114     RoutingTable = 114 // 114\n\tTable115     RoutingTable = 115 // 115\n\tTable116     RoutingTable = 116 // 116\n\tTable117     RoutingTable = 117 // 117\n\tTable118     RoutingTable = 118 // 118\n\tTable119     RoutingTable = 119 // 119\n\tTable120     RoutingTable = 120 // 120\n\tTable121     RoutingTable = 121 // 121\n\tTable122     RoutingTable = 122 // 122\n\tTable123     RoutingTable = 123 // 123\n\tTable124     RoutingTable = 124 // 124\n\tTable125     RoutingTable = 125 // 125\n\tTable126     RoutingTable = 126 // 126\n\tTable127     RoutingTable = 127 // 127\n\tTable128     RoutingTable = 128 // 128\n\tTable129     RoutingTable = 129 // 129\n\tTable130     RoutingTable = 130 // 130\n\tTable131     RoutingTable = 131 // 131\n\tTable132     RoutingTable = 132 // 132\n\tTable133     RoutingTable = 133 // 133\n\tTable134     RoutingTable = 134 // 134\n\tTable135     RoutingTable = 135 // 135\n\tTable136     RoutingTable = 136 // 136\n\tTable137     RoutingTable = 137 // 137\n\tTable138     RoutingTable = 138 // 138\n\tTable139     RoutingTable = 139 // 139\n\tTable140     RoutingTable = 140 // 140\n\tTable141     RoutingTable = 141 // 141\n\tTable142     RoutingTable = 142 // 142\n\tTable143     RoutingTable = 143 // 143\n\tTable144     RoutingTable = 144 // 144\n\tTable145     RoutingTable = 145 // 145\n\tTable146     RoutingTable = 146 // 146\n\tTable147     RoutingTable = 147 // 147\n\tTable148     RoutingTable = 148 // 148\n\tTable149     RoutingTable = 149 // 149\n\tTable150     RoutingTable = 150 // 150\n\tTable151     RoutingTable = 151 // 151\n\tTable152     RoutingTable = 152 // 152\n\tTable153     RoutingTable = 153 // 153\n\tTable154     RoutingTable = 154 // 154\n\tTable155     RoutingTable = 155 // 155\n\tTable156     RoutingTable = 156 // 156\n\tTable157     RoutingTable = 157 // 157\n\tTable158     RoutingTable = 158 // 158\n\tTable159     RoutingTable = 159 // 159\n\tTable160     RoutingTable = 160 // 160\n\tTable161     RoutingTable = 161 // 161\n\tTable162     RoutingTable = 162 // 162\n\tTable163     RoutingTable = 163 // 163\n\tTable164     RoutingTable = 164 // 164\n\tTable165     RoutingTable = 165 // 165\n\tTable166     RoutingTable = 166 // 166\n\tTable167     RoutingTable = 167 // 167\n\tTable168     RoutingTable = 168 // 168\n\tTable169     RoutingTable = 169 // 169\n\tTable170     RoutingTable = 170 // 170\n\tTable171     RoutingTable = 171 // 171\n\tTable172     RoutingTable = 172 // 172\n\tTable173     RoutingTable = 173 // 173\n\tTable174     RoutingTable = 174 // 174\n\tTable175     RoutingTable = 175 // 175\n\tTable176     RoutingTable = 176 // 176\n\tTable177     RoutingTable = 177 // 177\n\tTable178     RoutingTable = 178 // 178\n\tTable179     RoutingTable = 179 // 179\n\tTable180     RoutingTable = 180 // 180\n\tTable181     RoutingTable = 181 // 181\n\tTable182     RoutingTable = 182 // 182\n\tTable183     RoutingTable = 183 // 183\n\tTable184     RoutingTable = 184 // 184\n\tTable185     RoutingTable = 185 // 185\n\tTable186     RoutingTable = 186 // 186\n\tTable187     RoutingTable = 187 // 187\n\tTable188     RoutingTable = 188 // 188\n\tTable189     RoutingTable = 189 // 189\n\tTable190     RoutingTable = 190 // 190\n\tTable191     RoutingTable = 191 // 191\n\tTable192     RoutingTable = 192 // 192\n\tTable193     RoutingTable = 193 // 193\n\tTable194     RoutingTable = 194 // 194\n\tTable195     RoutingTable = 195 // 195\n\tTable196     RoutingTable = 196 // 196\n\tTable197     RoutingTable = 197 // 197\n\tTable198     RoutingTable = 198 // 198\n\tTable199     RoutingTable = 199 // 199\n\tTable200     RoutingTable = 200 // 200\n\tTable201     RoutingTable = 201 // 201\n\tTable202     RoutingTable = 202 // 202\n\tTable203     RoutingTable = 203 // 203\n\tTable204     RoutingTable = 204 // 204\n\tTable205     RoutingTable = 205 // 205\n\tTable206     RoutingTable = 206 // 206\n\tTable207     RoutingTable = 207 // 207\n\tTable208     RoutingTable = 208 // 208\n\tTable209     RoutingTable = 209 // 209\n\tTable210     RoutingTable = 210 // 210\n\tTable211     RoutingTable = 211 // 211\n\tTable212     RoutingTable = 212 // 212\n\tTable213     RoutingTable = 213 // 213\n\tTable214     RoutingTable = 214 // 214\n\tTable215     RoutingTable = 215 // 215\n\tTable216     RoutingTable = 216 // 216\n\tTable217     RoutingTable = 217 // 217\n\tTable218     RoutingTable = 218 // 218\n\tTable219     RoutingTable = 219 // 219\n\tTable220     RoutingTable = 220 // 220\n\tTable221     RoutingTable = 221 // 221\n\tTable222     RoutingTable = 222 // 222\n\tTable223     RoutingTable = 223 // 223\n\tTable224     RoutingTable = 224 // 224\n\tTable225     RoutingTable = 225 // 225\n\tTable226     RoutingTable = 226 // 226\n\tTable227     RoutingTable = 227 // 227\n\tTable228     RoutingTable = 228 // 228\n\tTable229     RoutingTable = 229 // 229\n\tTable230     RoutingTable = 230 // 230\n\tTable231     RoutingTable = 231 // 231\n\tTable232     RoutingTable = 232 // 232\n\tTable233     RoutingTable = 233 // 233\n\tTable234     RoutingTable = 234 // 234\n\tTable235     RoutingTable = 235 // 235\n\tTable236     RoutingTable = 236 // 236\n\tTable237     RoutingTable = 237 // 237\n\tTable238     RoutingTable = 238 // 238\n\tTable239     RoutingTable = 239 // 239\n\tTable240     RoutingTable = 240 // 240\n\tTable241     RoutingTable = 241 // 241\n\tTable242     RoutingTable = 242 // 242\n\tTable243     RoutingTable = 243 // 243\n\tTable244     RoutingTable = 244 // 244\n\tTable245     RoutingTable = 245 // 245\n\tTable246     RoutingTable = 246 // 246\n\tTable247     RoutingTable = 247 // 247\n\tTable248     RoutingTable = 248 // 248\n\tTable249     RoutingTable = 249 // 249\n\tTable250     RoutingTable = 250 // 250\n\tTable251     RoutingTable = 251 // 251\n\tTable252     RoutingTable = 252 // 252\n\tTableDefault RoutingTable = 253 // default\n\tTableMain    RoutingTable = 254 // main\n\tTableLocal   RoutingTable = 255 // local\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/scope.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// Scope is an address scope.\ntype Scope uint8\n\n// Scope constants.\n//\n//structprotogen:gen_enum\nconst (\n\tScopeGlobal  Scope = 0   // global\n\tScopeSite    Scope = 200 // site\n\tScopeLink    Scope = 253 // link\n\tScopeHost    Scope = 254 // host\n\tScopeNowhere Scope = 255 // nowhere\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// Status is a network status.\n//\n// Please see resources/network/status.go.\ntype Status int\n\n// Status constants.\nconst (\n\tStatusAddresses    Status = 1 // addresses\n\tStatusConnectivity Status = 2 // connectivity\n\tStatusHostname     Status = 3 // hostname\n\tStatusEtcFiles     Status = 4 // etcfiles\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/vlan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport (\n\t\"crypto/sha256\"\n\t\"fmt\"\n)\n\nconst maxLinkNameLength = 15\n\n// VLANLinkName builds a VLAN link name out of the base device name and VLAN ID.\n//\n// The function takes care of the maximum length of the link name.\nfunc VLANLinkName(base string, vlanID uint16) string {\n\t// VLAN ID is actually 12-bit, so the allowed values are 0-4095.\n\t// In \".%d\" format, vlanID can be up to 5 characters long.\n\tif len(base)+5 <= maxLinkNameLength {\n\t\treturn fmt.Sprintf(\"%s.%d\", base, vlanID)\n\t}\n\n\t// If the base name is too long, we need to truncate it, but simply\n\t// truncating might lead to ambiguous link name, so take some hash of the original\n\t// name.\n\tprefix := base[:4]\n\n\thash := sha256.Sum256([]byte(base))\n\n\treturn fmt.Sprintf(\"%s%x.%d\", prefix, hash[:(maxLinkNameLength-len(prefix)-5)/2], vlanID)\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/vlan_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\nfunc TestVLANLinkName(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tbase   string\n\t\tvlanID uint16\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tbase:   \"eth0\",\n\t\t\tvlanID: 1,\n\n\t\t\texpected: \"eth0.1\",\n\t\t},\n\t\t{\n\t\t\tbase:   \"en9s0\",\n\t\t\tvlanID: 4095,\n\n\t\t\texpected: \"en9s0.4095\",\n\t\t},\n\t\t{\n\t\t\tbase:   \"0123456789\",\n\t\t\tvlanID: 4095,\n\n\t\t\texpected: \"0123456789.4095\",\n\t\t},\n\t\t{\n\t\t\tbase:   \"enx12545f8c99cd\",\n\t\t\tvlanID: 25,\n\n\t\t\texpected: \"enx1ee6413.25\",\n\t\t},\n\t\t{\n\t\t\tbase:   \"enx12545f8c99cd\",\n\t\t\tvlanID: 4095,\n\n\t\t\texpected: \"enx1ee6413.4095\",\n\t\t},\n\t\t{\n\t\t\tbase:   \"enx12545f8c99ce\",\n\t\t\tvlanID: 4095,\n\n\t\t\texpected: \"enx1ef972f.4095\",\n\t\t},\n\t} {\n\t\tt.Run(fmt.Sprintf(\"%s.%d\", test.base, test.vlanID), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expected, nethelpers.VLANLinkName(test.base, test.vlanID))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/nethelpers/vlanprotocol.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\n// VLANProtocol is a VLAN protocol.\ntype VLANProtocol uint16\n\n// VLANProtocol constants.\n//\n//structprotogen:gen_enum\nconst (\n\tVLANProtocol8021Q  VLANProtocol = 33024 // 802.1q\n\tVLANProtocol8021AD VLANProtocol = 34984 // 802.1ad\n)\n"
  },
  {
    "path": "pkg/machinery/nethelpers/wol.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage nethelpers\n\nimport \"github.com/mdlayher/ethtool\"\n\n// WOLMode wraps ethtool.WOLMode for YAML marshaling.\ntype WOLMode int\n\n// Constants copied from ethtool to provide Stringer interface.\n//\n//structprotogen:gen_enum\nconst (\n\tWOLModePhy         WOLMode = WOLMode(ethtool.PHY)         // phy\n\tWOLModeUnicast     WOLMode = WOLMode(ethtool.Unicast)     // unicast\n\tWOLModeMulticast   WOLMode = WOLMode(ethtool.Multicast)   // multicast\n\tWOLModeBroadcast   WOLMode = WOLMode(ethtool.Broadcast)   // broadcast\n\tWOLModeMagic       WOLMode = WOLMode(ethtool.Magic)       // magic\n\tWOLModeMagicSecure WOLMode = WOLMode(ethtool.MagicSecure) // magicsecure\n\tWOLModeFilter      WOLMode = WOLMode(ethtool.Filter)      // filter\n)\n\n// WOLModeMin is the minimum valid WOLMode.\nconst WOLModeMin = WOLModePhy\n\n// WOLModeMax is the maximum valid WOLMode.\nconst WOLModeMax = WOLModeFilter\n"
  },
  {
    "path": "pkg/machinery/overlay/adapter/adapter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package adapter provides an adapter for the overlay installer.\npackage adapter\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/overlay\"\n)\n\n// Execute executes the overlay installer.\nfunc Execute[T any](ctx context.Context, installer overlay.Installer[T]) {\n\tif len(os.Args) < 2 {\n\t\tfmt.Fprint(os.Stderr, \"missing command\")\n\n\t\tos.Exit(1)\n\t}\n\n\tswitch os.Args[1] {\n\tcase \"install\":\n\t\tinstall(ctx, installer)\n\tcase \"get-options\":\n\t\tgetOptions(ctx, installer)\n\tdefault:\n\t\tfmt.Fprintf(os.Stderr, \"unknown command: %s\", os.Args[1])\n\n\t\tos.Exit(1)\n\t}\n}\n\nfunc getOptions[T any](ctx context.Context, installer overlay.Installer[T]) {\n\tvar opts T\n\n\twithErrorHandler(yaml.NewDecoder(os.Stdin).Decode(&opts))\n\n\topt, err := installer.GetOptions(ctx, opts)\n\tif err != nil {\n\t\tfmt.Fprint(os.Stderr, err.Error())\n\n\t\tos.Exit(1)\n\t}\n\n\twithErrorHandler(yaml.NewEncoder(os.Stdout).Encode(opt))\n}\n\nfunc install[T any](ctx context.Context, installer overlay.Installer[T]) {\n\tvar opts overlay.InstallOptions[T]\n\n\twithErrorHandler(yaml.NewDecoder(os.Stdin).Decode(&opts))\n\n\twithErrorHandler(installer.Install(ctx, opts))\n}\n\nfunc withErrorHandler(err error) {\n\tif err != nil {\n\t\tfmt.Fprint(os.Stderr, err.Error())\n\n\t\tos.Exit(1)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/overlay/overlay.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package overlay provides an interface for overlay installers.\npackage overlay\n\nimport \"context\"\n\n// Installer is an interface for overlay installers.\ntype Installer[T any] interface {\n\tGetOptions(ctx context.Context, extra T) (Options, error)\n\tInstall(ctx context.Context, options InstallOptions[T]) error\n}\n\n// Options for the overlay installer.\ntype Options struct {\n\tName             string           `yaml:\"name\"`\n\tKernelArgs       []string         `yaml:\"kernelArgs,omitempty\"`\n\tPartitionOptions PartitionOptions `yaml:\"partitionOptions,omitempty\"`\n}\n\n// PartitionOptions for the overlay installer.\ntype PartitionOptions struct {\n\tOffset uint64 `yaml:\"offset,omitempty\"`\n}\n\n// InstallOptions for the overlay installer.\ntype InstallOptions[T any] struct {\n\tInstallDisk   string `yaml:\"installDisk\"`\n\tMountPrefix   string `yaml:\"mountPrefix\"`\n\tArtifactsPath string `yaml:\"artifactsPath\"`\n\tExtraOptions  T      `yaml:\"extraOptions,omitempty\"`\n}\n\n// ExtraOptions for the overlay installer.\ntype ExtraOptions map[string]any\n"
  },
  {
    "path": "pkg/machinery/platforms/platforms.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package platforms provides meta information about supported Talos platforms.\npackage platforms\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/blang/semver/v4\"\n)\n\n// Arch represents an architecture supported by Talos.\ntype Arch = string\n\n// Architecture constants.\nconst (\n\tArchAmd64 = \"amd64\"\n\tArchArm64 = \"arm64\"\n)\n\n// BootMethod represents a boot method supported by Talos.\ntype BootMethod = string\n\n// BootMethod constants.\nconst (\n\tBootMethodDiskImage = \"disk-image\"\n\tBootMethodISO       = \"iso\"\n\tBootMethodPXE       = \"pxe\"\n)\n\n// Platform represents a platform supported by Talos.\ntype Platform struct {\n\tName string\n\n\tLabel       string\n\tDescription string\n\n\tMinVersion          semver.Version\n\tArchitectures       []Arch\n\tDocumentation       string\n\tDiskImageSuffix     string\n\tBootMethods         []BootMethod\n\tSecureBootSupported bool\n}\n\n// NotOnlyDiskImage is true if the platform supports boot methods other than disk-image.\nfunc (p Platform) NotOnlyDiskImage() bool {\n\tif len(p.BootMethods) == 1 && p.BootMethods[0] == BootMethodDiskImage {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// DiskImageDefaultPath returns the path to the disk image for the platform.\nfunc (p Platform) DiskImageDefaultPath(arch Arch) string {\n\treturn p.DiskImagePath(arch, p.DiskImageSuffix)\n}\n\n// SecureBootDiskImageDefaultPath returns the path to the SecureBoot disk image for the platform.\nfunc (p Platform) SecureBootDiskImageDefaultPath(arch Arch) string {\n\treturn p.SecureBootDiskImagePath(arch, p.DiskImageSuffix)\n}\n\n// DiskImagePath returns the path to the disk image for the platform and suffix.\nfunc (p Platform) DiskImagePath(arch Arch, suffix string) string {\n\treturn fmt.Sprintf(\"%s-%s.%s\", p.Name, arch, suffix)\n}\n\n// SecureBootDiskImagePath returns the path to the SecureBoot disk image for the platform and suffix.\nfunc (p Platform) SecureBootDiskImagePath(arch Arch, suffix string) string {\n\treturn fmt.Sprintf(\"%s-%s-secureboot.%s\", p.Name, arch, suffix)\n}\n\n// ISOPath returns the path to the ISO for the platform.\nfunc (p Platform) ISOPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s.iso\", p.Name, arch)\n}\n\n// SecureBootISOPath returns the path to the SecureBoot ISO for the platform.\nfunc (p Platform) SecureBootISOPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s-secureboot.iso\", p.Name, arch)\n}\n\n// PXEScriptPath returns the path to the PXE script for the platform.\nfunc (p Platform) PXEScriptPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s\", p.Name, arch)\n}\n\n// SecureBootPXEScriptPath returns the path to the SecureBoot PXE script for the platform.\nfunc (p Platform) SecureBootPXEScriptPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s-secureboot\", p.Name, arch)\n}\n\n// UKIPath returns the path to the UKI for the platform.\nfunc (p Platform) UKIPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s-uki.efi\", p.Name, arch)\n}\n\n// SecureBootUKIPath returns the path to the SecureBoot UKI for the platform.\nfunc (p Platform) SecureBootUKIPath(arch Arch) string {\n\treturn fmt.Sprintf(\"%s-%s-secureboot-uki.efi\", p.Name, arch)\n}\n\n// KernelPath returns the path to the kernel for the platform.\n//\n// NB: Kernel path doesn't depend on the platform.\nfunc (p Platform) KernelPath(arch Arch) string {\n\treturn fmt.Sprintf(\"kernel-%s\", arch)\n}\n\n// InitramfsPath returns the path to the initramfs for the platform.\n//\n// NB: Initramfs path doesn't depend on the platform.\nfunc (p Platform) InitramfsPath(arch Arch) string {\n\treturn fmt.Sprintf(\"initramfs-%s.xz\", arch)\n}\n\n// CmdlinePath returns the path to the cmdline for the platform.\nfunc (p Platform) CmdlinePath(arch Arch) string {\n\treturn fmt.Sprintf(\"cmdline-%s-%s\", p.Name, arch)\n}\n\n// MetalPlatform returns a metal platform.\nfunc MetalPlatform() Platform {\n\treturn Platform{\n\t\tName: \"metal\",\n\n\t\tLabel:       \"Bare Metal\",\n\t\tDescription: \"Runs on bare-metal servers\",\n\n\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\tDocumentation:   \"/platform-specific-installations/bare-metal-platforms/bootloader\",\n\t\tDiskImageSuffix: \"raw.zst\",\n\t\tBootMethods: []BootMethod{\n\t\t\tBootMethodISO,\n\t\t\tBootMethodDiskImage,\n\t\t\tBootMethodPXE,\n\t\t},\n\t\tSecureBootSupported: true,\n\t}\n}\n\n// CloudPlatforms returns a list of supported cloud platforms.\nfunc CloudPlatforms() []Platform {\n\t// metal platform is not listed here, as it is handled separately.\n\treturn []Platform{\n\t\t// Tier 1\n\t\t{\n\t\t\tName: \"aws\",\n\n\t\t\tLabel:       \"Amazon Web Services (AWS)\",\n\t\t\tDescription: \"Runs on AWS VMs booted from an AMI\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/aws\",\n\t\t\tDiskImageSuffix: \"raw.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"gcp\",\n\n\t\t\tLabel:       \"Google Cloud (GCP)\",\n\t\t\tDescription: \"Runs on Google Cloud VMs booted from a disk image\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/gcp\",\n\t\t\tDiskImageSuffix: \"raw.tar.gz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"equinixMetal\",\n\n\t\t\tLabel:       \"Equinix Metal\",\n\t\t\tDescription: \"Runs on Equinix Metal bare-metal servers\",\n\n\t\t\tArchitectures: []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation: \"/platform-specific-installations/bare-metal-platforms/equinix-metal\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodPXE,\n\t\t\t},\n\t\t},\n\t\t// Tier 2\n\t\t{\n\t\t\tName: \"azure\",\n\n\t\t\tLabel:       \"Microsoft Azure\",\n\t\t\tDescription: \"Runs on Microsoft Azure Linux Virtual Machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/azure\",\n\t\t\tDiskImageSuffix: \"vhd.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"digital-ocean\",\n\n\t\t\tLabel:       \"Digital Ocean\",\n\t\t\tDescription: \"Runs on Digital Ocean droplets\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/digitalocean\",\n\t\t\tDiskImageSuffix: \"raw.gz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"nocloud\",\n\n\t\t\tLabel:       \"Nocloud\",\n\t\t\tDescription: \"Runs on various hypervisors supporting 'nocloud' metadata (Proxmox, Oxide Computer, etc.)\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/nocloud\",\n\t\t\tDiskImageSuffix: \"raw.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t\tBootMethodISO,\n\t\t\t\tBootMethodPXE,\n\t\t\t},\n\t\t\tSecureBootSupported: true,\n\t\t},\n\t\t{\n\t\t\tName: \"openstack\",\n\n\t\t\tLabel:       \"OpenStack\",\n\t\t\tDescription: \"Runs on OpenStack virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/openstack\",\n\t\t\tDiskImageSuffix: \"raw.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t\tBootMethodISO,\n\t\t\t\tBootMethodPXE,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"vmware\",\n\n\t\t\tLabel:       \"VMWare\",\n\t\t\tDescription: \"Runs on VMWare ESXi virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/virtualized-platforms/vmware\",\n\t\t\tDiskImageSuffix: \"ova\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t\tBootMethodISO,\n\t\t\t},\n\t\t},\n\t\t// Tier 3\n\t\t{\n\t\t\tName: \"akamai\",\n\n\t\t\tLabel:       \"Akamai\",\n\t\t\tDescription: \"Runs on Akamai Cloud (Linode) virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64},\n\t\t\tMinVersion:      semver.MustParse(\"1.7.0\"),\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/akamai\",\n\t\t\tDiskImageSuffix: \"raw.gz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"cloudstack\",\n\n\t\t\tLabel:       \"Apache CloudStack\",\n\t\t\tDescription: \"Runs on Apache CloudStack virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/cloudstack\",\n\t\t\tDiskImageSuffix: \"raw.gz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t\tSecureBootSupported: true,\n\t\t\tMinVersion:          semver.MustParse(\"1.8.0-alpha.2\"),\n\t\t},\n\t\t{\n\t\t\tName: \"hcloud\",\n\n\t\t\tLabel:       \"Hetzner\",\n\t\t\tDescription: \"Runs on Hetzner virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/hetzner\",\n\t\t\tDiskImageSuffix: \"raw.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"oracle\",\n\n\t\t\tLabel:       \"Oracle Cloud\",\n\t\t\tDescription: \"Runs on Oracle Cloud virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/oracle\",\n\t\t\tDiskImageSuffix: \"qcow2\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"upcloud\",\n\n\t\t\tLabel:       \"UpCloud\",\n\t\t\tDescription: \"Runs on UpCloud virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/upcloud\",\n\t\t\tDiskImageSuffix: \"raw.xz\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"vultr\",\n\n\t\t\tLabel:       \"Vultr\",\n\t\t\tDescription: \"Runs on Vultr Cloud Compute virtual machines\",\n\n\t\t\tArchitectures: []Arch{ArchAmd64},\n\t\t\tDocumentation: \"/platform-specific-installations/cloud-platforms/vultr\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodISO,\n\t\t\t\tBootMethodPXE,\n\t\t\t},\n\t\t},\n\t\t// Tier 4 (no documentation).\n\t\t{\n\t\t\tName: \"exoscale\",\n\n\t\t\tLabel:       \"Exoscale\",\n\t\t\tDescription: \"Runs on Exoscale virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/exoscale\",\n\t\t\tDiskImageSuffix: \"qcow2\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t},\n\t\t\tMinVersion: semver.MustParse(\"1.3.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"opennebula\",\n\n\t\t\tLabel:       \"OpenNebula\",\n\t\t\tDescription: \"Runs on OpenNebula virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDiskImageSuffix: \"raw.zst\",\n\t\t\tDocumentation:   \"/platform-specific-installations/virtualized-platforms/opennebula\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t\tBootMethodISO,\n\t\t\t},\n\t\t\tMinVersion: semver.MustParse(\"1.7.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"scaleway\",\n\n\t\t\tLabel:       \"Scaleway\",\n\t\t\tDescription: \"Runs on Scaleway virtual machines\",\n\n\t\t\tArchitectures:   []Arch{ArchAmd64, ArchArm64},\n\t\t\tDiskImageSuffix: \"raw.zst\",\n\t\t\tDocumentation:   \"/platform-specific-installations/cloud-platforms/scaleway\",\n\t\t\tBootMethods: []BootMethod{\n\t\t\t\tBootMethodDiskImage,\n\t\t\t\tBootMethodISO,\n\t\t\t},\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/platforms/platforms_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage platforms_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/platforms\"\n)\n\nfunc TestPlatform(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tplatform platforms.Platform\n\n\t\texpectedDefaultDiskImagePath string\n\t\texpectedISOPath              string\n\t\texpectedSecureBootISOPath    string\n\t\texpectedPXEPath              string\n\t\texpectedSecureBootPXEPath    string\n\t\texpectedUKIPath              string\n\t\texpectedSecureBootUKIPath    string\n\t\texpectedKernelPath           string\n\t\texpectedInitramfsPath        string\n\t\texpectedCmdlinePath          string\n\t\texpectedNotOnlyDiskImage     bool\n\t}{\n\t\t{\n\t\t\tname: \"metal\",\n\n\t\t\tplatform: platforms.MetalPlatform(),\n\n\t\t\texpectedDefaultDiskImagePath: \"metal-amd64.raw.zst\",\n\t\t\texpectedISOPath:              \"metal-amd64.iso\",\n\t\t\texpectedSecureBootISOPath:    \"metal-amd64-secureboot.iso\",\n\t\t\texpectedPXEPath:              \"metal-amd64\",\n\t\t\texpectedSecureBootPXEPath:    \"metal-amd64-secureboot\",\n\t\t\texpectedUKIPath:              \"metal-amd64-uki.efi\",\n\t\t\texpectedSecureBootUKIPath:    \"metal-amd64-secureboot-uki.efi\",\n\t\t\texpectedKernelPath:           \"kernel-amd64\",\n\t\t\texpectedInitramfsPath:        \"initramfs-amd64.xz\",\n\t\t\texpectedCmdlinePath:          \"cmdline-metal-amd64\",\n\t\t\texpectedNotOnlyDiskImage:     true,\n\t\t},\n\t\t{\n\t\t\tname: \"aws\",\n\n\t\t\tplatform: platforms.CloudPlatforms()[0],\n\n\t\t\texpectedDefaultDiskImagePath: \"aws-amd64.raw.xz\",\n\t\t\texpectedISOPath:              \"aws-amd64.iso\",\n\t\t\texpectedSecureBootISOPath:    \"aws-amd64-secureboot.iso\",\n\t\t\texpectedPXEPath:              \"aws-amd64\",\n\t\t\texpectedSecureBootPXEPath:    \"aws-amd64-secureboot\",\n\t\t\texpectedUKIPath:              \"aws-amd64-uki.efi\",\n\t\t\texpectedSecureBootUKIPath:    \"aws-amd64-secureboot-uki.efi\",\n\t\t\texpectedKernelPath:           \"kernel-amd64\",\n\t\t\texpectedInitramfsPath:        \"initramfs-amd64.xz\",\n\t\t\texpectedCmdlinePath:          \"cmdline-aws-amd64\",\n\t\t\texpectedNotOnlyDiskImage:     false,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expectedDefaultDiskImagePath, test.platform.DiskImageDefaultPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedISOPath, test.platform.ISOPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedSecureBootISOPath, test.platform.SecureBootISOPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedPXEPath, test.platform.PXEScriptPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedSecureBootPXEPath, test.platform.SecureBootPXEScriptPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedUKIPath, test.platform.UKIPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedSecureBootUKIPath, test.platform.SecureBootUKIPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedKernelPath, test.platform.KernelPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedInitramfsPath, test.platform.InitramfsPath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedCmdlinePath, test.platform.CmdlinePath(platforms.ArchAmd64))\n\t\t\tassert.Equal(t, test.expectedNotOnlyDiskImage, test.platform.NotOnlyDiskImage())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/platforms/sbcs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage platforms\n\nimport (\n\t\"github.com/blang/semver/v4\"\n)\n\n// SBC describes a Single Board Computer configuration.\ntype SBC struct {\n\tName string\n\n\t// For Talos 1.7+\n\tOverlayName  string\n\tOverlayImage string\n\n\tLabel         string\n\tDocumentation string\n\n\tMinVersion semver.Version\n}\n\n// DiskImagePath returns the path to the disk image for the SBC.\nfunc (s SBC) DiskImagePath(talosVersion string) string {\n\treturn \"metal-arm64.raw.xz\"\n}\n\n// SBCs returns a list of supported Single Board Computers.\nfunc SBCs() []SBC {\n\treturn []SBC{\n\t\t{\n\t\t\tName: \"rpi_5\",\n\n\t\t\tOverlayName:  \"rpi_5\",\n\t\t\tOverlayImage: \"siderolabs/sbc-raspberrypi\",\n\n\t\t\tLabel: \"Raspberry Pi 5\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.3\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rpi_generic\",\n\n\t\t\tOverlayName:  \"rpi_generic\",\n\t\t\tOverlayImage: \"siderolabs/sbc-raspberrypi\",\n\n\t\t\tLabel:         \"Raspberry Pi Series\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rpi_generic\",\n\t\t},\n\t\t{\n\t\t\tName: \"revpi_generic\",\n\n\t\t\tOverlayName:  \"revpi_generic\",\n\t\t\tOverlayImage: \"siderolabs/sbc-raspberrypi\",\n\n\t\t\tLabel: \"Revolution Pi Series\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.10.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"bananapi_m64\",\n\n\t\t\tOverlayName:  \"bananapi_m64\",\n\t\t\tOverlayImage: \"siderolabs/sbc-allwinner\",\n\n\t\t\tLabel:         \"Banana Pi M64\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/bananapi_m64\",\n\t\t},\n\t\t{\n\t\t\tName: \"nanopi_r4s\",\n\n\t\t\tOverlayName:  \"nanopi-r4s\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Friendlyelec Nano PI R4S\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/nanopi_r4s\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.3.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"nanopi_r5s\",\n\n\t\t\tOverlayName:  \"nanopi-r5s\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Friendlyelec Nano PI R5S\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.8.0-alpha.2\"),\n\t\t},\n\t\t{\n\t\t\tName: \"jetson_nano\",\n\n\t\t\tOverlayName:  \"jetson_nano\",\n\t\t\tOverlayImage: \"siderolabs/sbc-jetson\",\n\n\t\t\tLabel:         \"Jetson Nano\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/jetson_nano\",\n\t\t},\n\t\t{\n\t\t\tName: \"libretech_all_h3_cc_h5\",\n\n\t\t\tOverlayName:  \"libretech_all_h3_cc_h5\",\n\t\t\tOverlayImage: \"siderolabs/sbc-allwinner\",\n\n\t\t\tLabel:         \"Libre Computer Board ALL-H3-CC\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/libretech_all_h3_cc_h5\",\n\t\t},\n\t\t{\n\t\t\tName: \"orangepi_r1_plus_lts\",\n\n\t\t\tOverlayName:  \"orangepi-r1-plus-lts\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Orange Pi R1 Plus LTS\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/orangepi_r1_plus_lts\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.7.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"pine64\",\n\n\t\t\tOverlayName:  \"pine64\",\n\t\t\tOverlayImage: \"siderolabs/sbc-allwinner\",\n\n\t\t\tLabel:         \"Pine64\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/pine64\",\n\t\t},\n\t\t{\n\t\t\tName: \"rock64\",\n\n\t\t\tOverlayName:  \"rock64\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Pine64 Rock64\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rock64\",\n\t\t},\n\t\t{\n\t\t\tName: \"rock4cplus\",\n\n\t\t\tOverlayName:  \"rock4cplus\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Radxa ROCK 4C Plus\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rock4cplus\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.7.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock4se\",\n\n\t\t\tOverlayName:  \"rock4se\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Radxa ROCK 4SE\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.8.0-alpha.1\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock5a\",\n\n\t\t\tOverlayName:  \"rock5a\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Radxa ROCK 5A\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rock5b\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.10.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock5b\",\n\n\t\t\tOverlayName:  \"rock5b\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Radxa ROCK 5B\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rock5b\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.9.2\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rockpi_4\",\n\n\t\t\tOverlayName:  \"rockpi4\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Radxa ROCK PI 4\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rockpi_4\",\n\t\t},\n\t\t{\n\t\t\tName: \"rockpi_4c\",\n\n\t\t\tOverlayName:  \"rockpi4c\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Radxa ROCK PI 4C\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/rockpi_4c\",\n\t\t},\n\t\t{\n\t\t\tName: \"helios64\",\n\n\t\t\tOverlayName:  \"helios64\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Kobol Helios64\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.8.0-alpha.2\"),\n\t\t},\n\t\t{\n\t\t\tName: \"turingrk1\",\n\n\t\t\tOverlayName:  \"turingrk1\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Turing RK1\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/turing_rk1\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.9.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"orangepi-5\",\n\n\t\t\tOverlayName:  \"orangepi-5\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel:         \"Orange Pi 5\",\n\t\t\tDocumentation: \"/platform-specific-installations/single-board-computers/orangepi_5\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.9.2\"),\n\t\t},\n\t\t{\n\t\t\tName: \"orangepi-5-plus\",\n\n\t\t\tOverlayName:  \"orangepi-5-plus\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Orange Pi 5 Plus\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.10.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rockpro64\",\n\n\t\t\tOverlayName:  \"rockpro64\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Pine64 RockPro64\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.10.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"odroid-m1\",\n\n\t\t\tOverlayName:  \"odroid-m1\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Odroid M1\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"radxa-zero-3e\",\n\n\t\t\tOverlayName:  \"radxa-zero-3e\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Radxa Zero 3E\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock3b\",\n\n\t\t\tOverlayName:  \"rock3b\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Rock 3B\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"orangepi-5-max\",\n\n\t\t\tOverlayName:  \"orangepi-5-max\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Orange Pi 5 Max\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock5t\",\n\n\t\t\tOverlayName:  \"rock5t\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Rock 5T\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.12.0-beta.0\"),\n\t\t},\n\t\t{\n\t\t\tName: \"friendlyelec-cm3588-nas\",\n\n\t\t\tOverlayName:  \"friendlyelec-cm3588-nas\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"FriendlyELEC CM3588 NAS\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.13.0-alpha.1\"),\n\t\t},\n\t\t{\n\t\t\tName: \"rock5b-plus\",\n\n\t\t\tOverlayName:  \"rock5b-plus\",\n\t\t\tOverlayImage: \"siderolabs/sbc-rockchip\",\n\n\t\t\tLabel: \"Rock 5B Plus\",\n\n\t\t\tMinVersion: semver.MustParse(\"1.13.0-alpha.1\"),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/platforms/sbcs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage platforms_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/platforms\"\n)\n\nfunc TestSBC(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tsbc          platforms.SBC\n\t\ttalosVersion string\n\n\t\texpectedDiskImagePath string\n\t}{\n\t\t{\n\t\t\tname: \"rpi_generic\",\n\n\t\t\tsbc:          platforms.SBCs()[0],\n\t\t\ttalosVersion: \"1.9.0\",\n\n\t\t\texpectedDiskImagePath: \"metal-arm64.raw.xz\",\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, test.expectedDiskImagePath, test.sbc.DiskImagePath(test.talosVersion))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/proto/proto.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package proto defines a functions to work with proto messages.\npackage proto\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/protoenc\"\n\t_ \"google.golang.org/grpc/encoding/gzip\" //nolint:depguard // enable compression server-side\n\t\"google.golang.org/protobuf/proto\"       //nolint:depguard\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n)\n\n// Message is the main interface for protobuf API v2 messages.\ntype Message = proto.Message\n\n// UnmarshalOptions is alias for [proto.UnmarshalOptions].\ntype UnmarshalOptions = proto.UnmarshalOptions\n\ntype vtprotoEqual interface {\n\tEqualMessageVT(proto.Message) bool\n}\n\n// Equal reports whether two messages are equal.\nfunc Equal(a, b Message) bool {\n\tif vm, ok := a.(vtprotoEqual); ok {\n\t\treturn vm.EqualMessageVT(b)\n\t}\n\n\treturn proto.Equal(a, b)\n}\n\n// vtprotoMessage is the interface for vtproto additions.\n//\n// We use only a subset of that interface but include additional methods\n// to prevent accidental successful type assertion for unrelated types.\ntype vtprotoMessage interface {\n\tMarshalVT() ([]byte, error)\n\tMarshalToVT([]byte) (int, error)\n\tMarshalToSizedBufferVT([]byte) (int, error)\n\tUnmarshalVT([]byte) error\n}\n\n// Marshal returns the wire-format encoding of m.\nfunc Marshal(m Message) ([]byte, error) {\n\tif vm, ok := m.(vtprotoMessage); ok {\n\t\treturn vm.MarshalVT()\n\t}\n\n\treturn proto.Marshal(m)\n}\n\n// Unmarshal parses the wire-format message in b and places the result in m.\n// The provided message must be mutable (e.g., a non-nil pointer to a message).\nfunc Unmarshal(b []byte, m Message) error {\n\tif vm, ok := m.(vtprotoMessage); ok {\n\t\treturn vm.UnmarshalVT(b)\n\t}\n\n\treturn proto.Unmarshal(b, m)\n}\n\nvar once sync.Once\n\n// RegisterDefaultTypes registers the pair of encoders/decoders for common types.\nfunc RegisterDefaultTypes() {\n\tonce.Do(registerDefaultTypes)\n}\n\n// Mount specifies a mount for a container.\n//\n//gotagsrewrite:gen\ntype Mount struct {\n\tDestination string           `protobuf:\"1\"`\n\tType        string           `protobuf:\"2\"`\n\tSource      string           `protobuf:\"3\"`\n\tOptions     []string         `protobuf:\"4\"`\n\tUIDMappings []LinuxIDMapping `protobuf:\"5\"`\n\tGIDMappings []LinuxIDMapping `protobuf:\"6\"`\n}\n\n// LinuxIDMapping specifies UID/GID mappings.\n//\n//gotagsrewrite:gen\ntype LinuxIDMapping struct {\n\tContainerID uint32 `protobuf:\"1\"`\n\tHostID      uint32 `protobuf:\"2\"`\n\tSize        uint32 `protobuf:\"3\"`\n}\n\n//nolint:gocyclo\nfunc registerDefaultTypes() {\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v *url.URL) ([]byte, error) {\n\t\t\tsource := common.URL{\n\t\t\t\tFullPath: v.String(),\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (*url.URL, error) {\n\t\t\tvar dest common.URL\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn url.Parse(dest.FullPath)\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v *x509.PEMEncodedCertificateAndKey) ([]byte, error) {\n\t\t\tsource := common.PEMEncodedCertificateAndKey{\n\t\t\t\tCrt: v.Crt,\n\t\t\t\tKey: v.Key,\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (*x509.PEMEncodedCertificateAndKey, error) {\n\t\t\tvar dest common.PEMEncodedCertificateAndKey\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn &x509.PEMEncodedCertificateAndKey{\n\t\t\t\tCrt: dest.Crt,\n\t\t\t\tKey: dest.Key,\n\t\t\t}, nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v *x509.PEMEncodedKey) ([]byte, error) {\n\t\t\tsource := common.PEMEncodedKey{\n\t\t\t\tKey: v.Key,\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (*x509.PEMEncodedKey, error) {\n\t\t\tvar dest common.PEMEncodedKey\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn &x509.PEMEncodedKey{\n\t\t\t\tKey: dest.Key,\n\t\t\t}, nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v *x509.PEMEncodedCertificate) ([]byte, error) {\n\t\t\tsource := common.PEMEncodedCertificate{\n\t\t\t\tCrt: v.Crt,\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (*x509.PEMEncodedCertificate, error) {\n\t\t\tvar dest common.PEMEncodedCertificate\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn &x509.PEMEncodedCertificate{\n\t\t\t\tCrt: dest.Crt,\n\t\t\t}, nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v netip.Addr) ([]byte, error) {\n\t\t\tipEncoded, err := v.MarshalBinary()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tsource := common.NetIP{\n\t\t\t\tIp: ipEncoded,\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (netip.Addr, error) {\n\t\t\tif len(slc) == 0 || len(slc) == 4 || len(slc) == 16 {\n\t\t\t\tvar parsedIP netip.Addr\n\n\t\t\t\tif err := parsedIP.UnmarshalBinary(slc); err != nil {\n\t\t\t\t\treturn netip.Addr{}, err\n\t\t\t\t}\n\n\t\t\t\treturn parsedIP, nil\n\t\t\t}\n\n\t\t\tvar dest common.NetIP\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn netip.Addr{}, err\n\t\t\t}\n\n\t\t\tvar parsedIP netip.Addr\n\n\t\t\tif err := parsedIP.UnmarshalBinary(dest.Ip); err != nil {\n\t\t\t\treturn netip.Addr{}, err\n\t\t\t}\n\n\t\t\treturn parsedIP, nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v netip.AddrPort) ([]byte, error) {\n\t\t\tipEncoded, err := v.Addr().MarshalBinary()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tsource := common.NetIPPort{\n\t\t\t\tIp:   ipEncoded,\n\t\t\t\tPort: int32(v.Port()),\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (netip.AddrPort, error) {\n\t\t\tvar dest common.NetIPPort\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn netip.AddrPort{}, err\n\t\t\t}\n\n\t\t\tvar parsedIP netip.Addr\n\n\t\t\tif err := parsedIP.UnmarshalBinary(dest.Ip); err != nil {\n\t\t\t\treturn netip.AddrPort{}, err\n\t\t\t}\n\n\t\t\treturn netip.AddrPortFrom(parsedIP, uint16(dest.Port)), nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v netip.Prefix) ([]byte, error) {\n\t\t\tipEncoded, err := v.Addr().WithZone(\"\").MarshalBinary()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tsource := common.NetIPPrefix{\n\t\t\t\tIp:           ipEncoded,\n\t\t\t\tPrefixLength: int32(v.Bits()),\n\t\t\t}\n\n\t\t\treturn proto.Marshal(&source)\n\t\t},\n\t\tfunc(slc []byte) (netip.Prefix, error) {\n\t\t\tvar dest common.NetIPPrefix\n\n\t\t\tif err := proto.Unmarshal(slc, &dest); err != nil {\n\t\t\t\treturn netip.Prefix{}, err\n\t\t\t}\n\n\t\t\tvar parsedIP netip.Addr\n\n\t\t\tif err := parsedIP.UnmarshalBinary(dest.Ip); err != nil {\n\t\t\t\treturn netip.Prefix{}, err\n\t\t\t}\n\n\t\t\treturn netip.PrefixFrom(parsedIP, int(dest.PrefixLength)), nil\n\t\t},\n\t)\n\n\tprotoenc.RegisterEncoderDecoder(\n\t\tfunc(v specs.Mount) ([]byte, error) {\n\t\t\t// use the intermediate type which is assignable to specs.Mount so that\n\t\t\t// we can be sure that `specs.Mount` and `Mount` have exactly same fields.\n\t\t\t//\n\t\t\t// as in Go []T1 is not assignable to []T2, even if T1 and T2 are assignable, we cannot\n\t\t\t// use direct conversion of Mount and specs.Mount\n\t\t\ttype mountConverter struct {\n\t\t\t\tDestination string\n\t\t\t\tType        string\n\t\t\t\tSource      string\n\t\t\t\tOptions     []string\n\t\t\t\tUIDMappings []specs.LinuxIDMapping\n\t\t\t\tGIDMappings []specs.LinuxIDMapping\n\t\t\t}\n\n\t\t\tmount := func(m mountConverter) Mount {\n\t\t\t\treturn Mount{\n\t\t\t\t\tDestination: m.Destination,\n\t\t\t\t\tType:        m.Type,\n\t\t\t\t\tSource:      m.Source,\n\t\t\t\t\tOptions:     m.Options,\n\t\t\t\t\tUIDMappings: xslices.Map(m.UIDMappings, func(m specs.LinuxIDMapping) LinuxIDMapping { return LinuxIDMapping(m) }),\n\t\t\t\t\tGIDMappings: xslices.Map(m.GIDMappings, func(m specs.LinuxIDMapping) LinuxIDMapping { return LinuxIDMapping(m) }),\n\t\t\t\t}\n\t\t\t}(mountConverter(v))\n\n\t\t\treturn protoenc.Marshal(&mount)\n\t\t},\n\t\tfunc(slc []byte) (specs.Mount, error) {\n\t\t\tvar result Mount\n\n\t\t\terr := protoenc.Unmarshal(slc, &result)\n\t\t\tif err != nil {\n\t\t\t\treturn specs.Mount{}, err\n\t\t\t}\n\n\t\t\treturn specs.Mount{\n\t\t\t\tDestination: result.Destination,\n\t\t\t\tType:        result.Type,\n\t\t\t\tSource:      result.Source,\n\t\t\t\tOptions:     result.Options,\n\t\t\t\tUIDMappings: xslices.Map(result.UIDMappings, func(v LinuxIDMapping) specs.LinuxIDMapping { return specs.LinuxIDMapping(v) }),\n\t\t\t\tGIDMappings: xslices.Map(result.GIDMappings, func(v LinuxIDMapping) specs.LinuxIDMapping { return specs.LinuxIDMapping(v) }),\n\t\t\t}, nil\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/proto/proto_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage proto_test\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/protoenc\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/common\"\n\tclusterpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\"\n\tnetworkpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\n//nolint:lll\nfunc TestMemberSpecOldEncoding(t *testing.T) {\n\tt.Parallel()\n\t// Input:\n\t// 00000000  0a 2c 37 78 31 53 75 43  38 45 67 65 35 42 47 58  |.,7x1SuC8Ege5BGX|\n\t// 00000010  64 41 66 54 45 66 66 35  69 51 6e 6c 57 5a 4c 66  |dAfTEff5iQnlWZLf|\n\t// 00000020  76 39 68 31 4c 47 4d 78  41 32 70 59 6b 43 12 04  |v9h1LGMxA2pYkC..|\n\t// 00000030  ac 14 00 02 12 10 fd 50  8d 60 42 38 63 02 f8 57  |.......P.`B8c..W|\n\t// 00000040  23 ff fe 21 d1 e0 1a 1c  74 61 6c 6f 73 2d 64 65  |#..!....talos-de|\n\t// 00000050  66 61 75 6c 74 2d 63 6f  6e 74 72 6f 6c 70 6c 61  |fault-controlpla|\n\t// 00000060  6e 65 2d 31 20 02 2a 0e  54 61 6c 6f 73 20 28 76  |ne-1 .*.Talos (v|\n\t// 00000070  31 2e 30 2e 30 29                                 |1.0.0)|\n\tconst encodedString = \"0a2c3778315375433845676535424758644166544566663569516e6c575a4c66763968314c474d78413270596b431204ac1400021210fd508d6042386302f85723fffe21d1e01a1c74616c6f732d64656661756c742d636f6e74726f6c706c616e652d3120022a0e54616c6f73202876312e302e3029\"\n\n\ttype T = cluster.MemberSpec\n\n\tencoded := must(hex.DecodeString(encodedString))(t)\n\taddresses := []netip.Addr{netip.MustParseAddr(\"172.20.0.2\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\")}\n\texpected := T{\n\t\tNodeID:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tAddresses:       addresses,\n\t\tHostname:        \"talos-default-controlplane-1\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tvar decoded T\n\n\trequire.NoError(t, protoenc.Unmarshal(encoded, &decoded))\n\trequire.Equal(t, expected, decoded)\n}\n\nfunc TestVIPOperatorSpecOldEncoding(t *testing.T) {\n\tt.Parallel()\n\t// Input:\n\t// 00000000  0a 04 c0 a8 01 01 10 01  1a 09 0a 01 61 12 01 62  |............a..b|\n\t// 00000010  1a 01 63 22 07 08 03 10  04 1a 01 64              |..c\".......d|\n\tconst ecnodedString = \"0a04c0a8010110011a090a01611201621a01632207080310041a0164\"\n\n\ttype T = network.VIPOperatorSpec\n\n\tencoded := must(hex.DecodeString(ecnodedString))(t)\n\texpected := T{\n\t\tIP:            netip.MustParseAddr(\"192.168.1.1\"),\n\t\tGratuitousARP: true,\n\t\tEquinixMetal: network.VIPEquinixMetalSpec{\n\t\t\tProjectID: \"a\",\n\t\t\tDeviceID:  \"b\",\n\t\t\tAPIToken:  \"c\",\n\t\t},\n\t\tHCloud: network.VIPHCloudSpec{\n\t\t\tDeviceID:  3,\n\t\t\tNetworkID: 4,\n\t\t\tAPIToken:  \"d\",\n\t\t},\n\t}\n\n\tvar decoded T\n\n\trequire.NoError(t, protoenc.Unmarshal(encoded, &decoded))\n\trequire.Equal(t, expected, decoded)\n}\n\n//nolint:lll\nfunc ExampleMemberSpec_outputProtoMarshal() {\n\taddresses := []netip.Addr{netip.MustParseAddr(\"172.20.0.2\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\")}\n\tspec := &clusterpb.MemberSpec{\n\t\tNodeId: \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tAddresses: []*common.NetIP{\n\t\t\t{\n\t\t\t\tIp: try(addresses[0].MarshalBinary()),\n\t\t\t},\n\t\t\t{\n\t\t\t\tIp: try(addresses[1].MarshalBinary()),\n\t\t\t},\n\t\t},\n\t\tHostname:        \"talos-default-controlplane-1\",\n\t\tMachineType:     enums.MachineType_TYPE_CONTROL_PLANE,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tresult := try(proto.Marshal(spec))\n\n\tfmt.Println(hex.Dump(result))\n\tfmt.Println(hex.EncodeToString(result))\n\n\t// Output:\n\t// 00000000  0a 2c 37 78 31 53 75 43  38 45 67 65 35 42 47 58  |.,7x1SuC8Ege5BGX|\n\t// 00000010  64 41 66 54 45 66 66 35  69 51 6e 6c 57 5a 4c 66  |dAfTEff5iQnlWZLf|\n\t// 00000020  76 39 68 31 4c 47 4d 78  41 32 70 59 6b 43 12 06  |v9h1LGMxA2pYkC..|\n\t// 00000030  0a 04 ac 14 00 02 12 12  0a 10 fd 50 8d 60 42 38  |...........P.`B8|\n\t// 00000040  63 02 f8 57 23 ff fe 21  d1 e0 1a 1c 74 61 6c 6f  |c..W#..!....talo|\n\t// 00000050  73 2d 64 65 66 61 75 6c  74 2d 63 6f 6e 74 72 6f  |s-default-contro|\n\t// 00000060  6c 70 6c 61 6e 65 2d 31  20 02 2a 0e 54 61 6c 6f  |lplane-1 .*.Talo|\n\t// 00000070  73 20 28 76 31 2e 30 2e  30 29                    |s (v1.0.0)|\n\t//\n\t// 0a2c3778315375433845676535424758644166544566663569516e6c575a4c66763968314c474d78413270596b4312060a04ac14000212120a10fd508d6042386302f85723fffe21d1e01a1c74616c6f732d64656661756c742d636f6e74726f6c706c616e652d3120022a0e54616c6f73202876312e302e3029\n}\n\n//nolint:lll\nfunc ExampleMemberSpec_outputProtoencMarshal() {\n\taddresses := []netip.Addr{netip.MustParseAddr(\"172.20.0.2\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\")}\n\tspec := &cluster.MemberSpec{\n\t\tNodeID:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tAddresses:       addresses,\n\t\tHostname:        \"talos-default-controlplane-1\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\tresult := try(protoenc.Marshal(spec))\n\n\tfmt.Println(hex.Dump(result))\n\tfmt.Println(hex.EncodeToString(result))\n\n\t// Output:\n\t// 00000000  0a 2c 37 78 31 53 75 43  38 45 67 65 35 42 47 58  |.,7x1SuC8Ege5BGX|\n\t// 00000010  64 41 66 54 45 66 66 35  69 51 6e 6c 57 5a 4c 66  |dAfTEff5iQnlWZLf|\n\t// 00000020  76 39 68 31 4c 47 4d 78  41 32 70 59 6b 43 12 06  |v9h1LGMxA2pYkC..|\n\t// 00000030  0a 04 ac 14 00 02 12 12  0a 10 fd 50 8d 60 42 38  |...........P.`B8|\n\t// 00000040  63 02 f8 57 23 ff fe 21  d1 e0 1a 1c 74 61 6c 6f  |c..W#..!....talo|\n\t// 00000050  73 2d 64 65 66 61 75 6c  74 2d 63 6f 6e 74 72 6f  |s-default-contro|\n\t// 00000060  6c 70 6c 61 6e 65 2d 31  20 02 2a 0e 54 61 6c 6f  |lplane-1 .*.Talo|\n\t// 00000070  73 20 28 76 31 2e 30 2e  30 29                    |s (v1.0.0)|\n\t//\n\t// 0a2c3778315375433845676535424758644166544566663569516e6c575a4c66763968314c474d78413270596b4312060a04ac14000212120a10fd508d6042386302f85723fffe21d1e01a1c74616c6f732d64656661756c742d636f6e74726f6c706c616e652d3120022a0e54616c6f73202876312e302e3029\n}\n\nfunc ExampleVIPOperatorSpec_outputProtoMarshal() {\n\tspec := &networkpb.VIPOperatorSpec{\n\t\tIp:            &common.NetIP{Ip: try(netip.MustParseAddr(\"192.168.1.1\").MarshalBinary())},\n\t\tGratuitousArp: true,\n\t\tEquinixMetal: &networkpb.VIPEquinixMetalSpec{\n\t\t\tProjectId: \"a\",\n\t\t\tDeviceId:  \"b\",\n\t\t\tApiToken:  \"c\",\n\t\t},\n\t\tHCloud: &networkpb.VIPHCloudSpec{\n\t\t\tDeviceId:  3,\n\t\t\tNetworkId: 4,\n\t\t\tApiToken:  \"d\",\n\t\t},\n\t}\n\n\tresult := try(proto.Marshal(spec))\n\n\tfmt.Println(hex.Dump(result))\n\tfmt.Println(hex.EncodeToString(result))\n\n\t// Output:\n\t// 00000000  0a 06 0a 04 c0 a8 01 01  10 01 1a 09 0a 01 61 12  |..............a.|\n\t// 00000010  01 62 1a 01 63 22 07 08  03 10 04 1a 01 64        |.b..c\".......d|\n\t//\n\t// 0a060a04c0a8010110011a090a01611201621a01632207080310041a0164\n}\n\n//nolint:dupword\nfunc ExampleVIPOperatorSpec_outputProtoencMarshal() {\n\tspec := &network.VIPOperatorSpec{\n\t\tIP:            netip.MustParseAddr(\"192.168.1.1\"),\n\t\tGratuitousARP: true,\n\t\tEquinixMetal: network.VIPEquinixMetalSpec{\n\t\t\tProjectID: \"a\",\n\t\t\tDeviceID:  \"b\",\n\t\t\tAPIToken:  \"c\",\n\t\t},\n\t\tHCloud: network.VIPHCloudSpec{\n\t\t\tDeviceID:  3,\n\t\t\tNetworkID: 4,\n\t\t\tAPIToken:  \"d\",\n\t\t},\n\t}\n\n\tresult := try(protoenc.Marshal(spec))\n\n\tfmt.Println(hex.Dump(result))\n\tfmt.Println(hex.EncodeToString(result))\n\n\t// Output:\n\t// 00000000  0a 06 0a 04 c0 a8 01 01  10 01 1a 09 0a 01 61 12  |..............a.|\n\t// 00000010  01 62 1a 01 63 22 07 08  03 10 04 1a 01 64        |.b..c\".......d|\n\t//\n\t// 0a060a04c0a8010110011a090a01611201621a01632207080310041a0164\n}\n\nfunc TestMemberSpec(t *testing.T) {\n\taddresses := []netip.Addr{netip.MustParseAddr(\"172.20.0.2\"), netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\")}\n\tspec := cluster.MemberSpec{\n\t\tNodeID:          \"7x1SuC8Ege5BGXdAfTEff5iQnlWZLfv9h1LGMxA2pYkC\",\n\t\tAddresses:       addresses,\n\t\tHostname:        \"talos-default-controlplane-1\",\n\t\tMachineType:     machine.TypeControlPlane,\n\t\tOperatingSystem: \"Talos (v1.0.0)\",\n\t}\n\n\trunTestPipe[clusterpb.MemberSpec](t, spec)\n}\n\nfunc TestVIPOperatorSpec(t *testing.T) {\n\tspec := network.VIPOperatorSpec{\n\t\tIP:            netip.MustParseAddr(\"192.168.1.1\"),\n\t\tGratuitousARP: true,\n\t\tEquinixMetal: network.VIPEquinixMetalSpec{\n\t\t\tProjectID: \"a\",\n\t\t\tDeviceID:  \"b\",\n\t\t\tAPIToken:  \"c\",\n\t\t},\n\t\tHCloud: network.VIPHCloudSpec{\n\t\t\tDeviceID:  3,\n\t\t\tNetworkID: 4,\n\t\t\tAPIToken:  \"d\",\n\t\t},\n\t}\n\n\trunTestPipe[networkpb.VIPOperatorSpec](t, spec)\n}\n\n//nolint:dupword\nfunc TestVLANSpecOldEncoding(t *testing.T) {\n\tt.Parallel()\n\t// Input:\n\t// 00000000  0d 19 00 00 00 15 a8 88  00 00                    |..........|\n\tconst ecnodedString = \"0d1900000015a8880000\"\n\n\ttype T = network.VLANSpec\n\n\tencoded := must(hex.DecodeString(ecnodedString))(t)\n\texpected := T{\n\t\tVID:      25,\n\t\tProtocol: nethelpers.VLANProtocol8021AD,\n\t}\n\n\tvar decoded T\n\n\trequire.NoError(t, protoenc.Unmarshal(encoded, &decoded))\n\trequire.Equal(t, expected, decoded)\n\n\tencodedThis := must(protoenc.Marshal(&decoded))(t)\n\n\tt.Logf(\"encoded original:\\n%s\", hex.Dump(encoded))\n\tt.Logf(\"encoded in this version:\\n%s\", hex.Dump(encodedThis))\n}\n\ntype msg[T any] interface {\n\t*T\n\tproto.Message\n}\n\nfunc runTestPipe[R any, RP msg[R], T any](t *testing.T, original T) {\n\tencoded1 := must(protoenc.Marshal(&original))(t)\n\n\tvar decoded1 R\n\n\trequire.NoError(t, proto.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(encoded1, RP(&decoded1)))\n\tencoded2 := must(proto.Marshal(RP(&decoded1)))(t)\n\n\tvar decoded2 T\n\n\trequire.NoError(t, protoenc.Unmarshal(encoded2, &decoded2))\n\trequire.Equal(t, original, decoded2)\n}\n\nfunc try[T any](v T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn v\n}\n\nfunc must[T any](v T, err error) func(t *testing.T) T {\n\treturn func(t *testing.T) T {\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\treturn v\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/proto/resource.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package proto defines a functions to work with proto messages.\npackage proto\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/siderolabs/protoenc\"\n)\n\n// ResourceSpecToProto converts a resource spec to a proto message.\nfunc ResourceSpecToProto(i resource.Resource, o Message, opts ...protoenc.MarshalOption) error {\n\tmarshaled, err := protoenc.Marshal(i.Spec(), opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn Unmarshal(marshaled, o)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/block.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package block provides resources related to blockdevices, mounts, etc.\npackage block\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/maps\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiscoveryRefreshRequestSpec -type DiscoveryRefreshStatusSpec -type DiskSpec -type MountRequestSpec -type MountStatusSpec -type ParameterSpec -type SwapStatusSpec -type SymlinkSpec -type SystemDiskSpec -type UserDiskConfigStatusSpec -type VolumeConfigSpec -type VolumeLifecycleSpec -type VolumeMountRequestSpec -type VolumeMountStatusSpec -type VolumeStatusSpec -type ZswapStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n//go:generate go tool github.com/dmarkham/enumer -type=VolumeType,VolumePhase,FilesystemType,EncryptionKeyType,EncryptionProviderType,FSParameterType -linecomment -text\n\n// NamespaceName contains configuration resources.\nconst NamespaceName resource.Namespace = v1alpha1.NamespaceName\n\n// UserDiskLabel is the label for user disks.\nconst UserDiskLabel = \"talos.dev/user-disk\"\n\n// UserVolumeLabel is the label for user volumes.\nconst UserVolumeLabel = \"talos.dev/user-volume\"\n\n// SystemVolumeLabel is the label for system volumes.\nconst SystemVolumeLabel = \"talos.dev/system-volume\"\n\n// RawVolumeLabel is the label for raw volumes.\nconst RawVolumeLabel = \"talos.dev/raw-volume\"\n\n// ExistingVolumeLabel is the label for existing volumes.\nconst ExistingVolumeLabel = \"talos.dev/existing-volume\"\n\n// ExternalVolumeLabel is the label for external volumes.\nconst ExternalVolumeLabel = \"talos.dev/external-volume\"\n\n// SwapVolumeLabel is the label for swap volumes.\nconst SwapVolumeLabel = \"talos.dev/swap-volume\"\n\n// PlatformLabel is the label for platform volumes.\nconst PlatformLabel = \"talos.dev/platform\"\n\n// WaitForVolumePhase waits for the volume to reach the expected phase(s).\nfunc WaitForVolumePhase(ctx context.Context, st state.State, volumeID string, expectedPhases ...VolumePhase) (*VolumeStatus, error) {\n\tvolumeStatus, err := st.WatchFor(ctx,\n\t\tNewVolumeStatus(NamespaceName, volumeID).Metadata(),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tvolumeStatus, ok := r.(*VolumeStatus)\n\t\t\tif !ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn slices.Index(expectedPhases, volumeStatus.TypedSpec().Phase) != -1, nil\n\t\t}),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error waiting for volume %q to be ready: %w\", volumeID, err)\n\t}\n\n\treturn volumeStatus.(*VolumeStatus), nil\n}\n\n// GetSystemDisk returns the system disk from the state.\n//\n// If the system disk is not found, it returns nil.\nfunc GetSystemDisk(ctx context.Context, st state.State) (*SystemDiskSpec, error) {\n\tsystemDisk, err := safe.StateGetByID[*SystemDisk](ctx, st, SystemDiskID)\n\tif err != nil {\n\t\tif state.IsNotFoundError(err) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"error getting system disk: %w\", err)\n\t}\n\n\treturn systemDisk.TypedSpec(), nil\n}\n\n// GetSystemDiskPaths returns the path(s) of system disk and STATE/EPHEMERAL partitions.\n//\n// This is a legacy method to map old concept of system disk wipe into new volume subsystem.\nfunc GetSystemDiskPaths(ctx context.Context, st state.State) ([]string, error) {\n\tsystemDisks := map[string]struct{}{}\n\n\t// fetch system disk (where Talos is installed)\n\tsystemDisk, err := GetSystemDisk(ctx, st)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif systemDisk != nil {\n\t\tsystemDisks[systemDisk.DevPath] = struct{}{}\n\t}\n\n\t// fetch additional system volumes (which might be on the same or other disks)\n\tfor _, volumeID := range []string{constants.StatePartitionLabel, constants.EphemeralPartitionLabel} {\n\t\tvolumeStatus, err := safe.ReaderGetByID[*VolumeStatus](ctx, st, volumeID)\n\t\tif err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif volumeStatus.TypedSpec().ParentLocation != \"\" {\n\t\t\tsystemDisks[volumeStatus.TypedSpec().ParentLocation] = struct{}{}\n\t\t} else if volumeStatus.TypedSpec().Location != \"\" {\n\t\t\tsystemDisks[volumeStatus.TypedSpec().Location] = struct{}{}\n\t\t}\n\t}\n\n\treturn maps.Keys(systemDisks), nil\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/block_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&block.Device{},\n\t\t&block.DiscoveryRefreshRequest{},\n\t\t&block.DiscoveryRefreshStatus{},\n\t\t&block.DiscoveredVolume{},\n\t\t&block.Disk{},\n\t\t&block.MountRequest{},\n\t\t&block.MountStatus{},\n\t\t&block.SwapStatus{},\n\t\t&block.Symlink{},\n\t\t&block.SystemDisk{},\n\t\t&block.UserDiskConfigStatus{},\n\t\t&block.VolumeConfig{},\n\t\t&block.VolumeLifecycle{},\n\t\t&block.VolumeMountRequest{},\n\t\t&block.VolumeMountStatus{},\n\t\t&block.VolumeStatus{},\n\t\t&block.ZswapStatus{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiscoveryRefreshRequestSpec -type DiscoveryRefreshStatusSpec -type DiskSpec -type MountRequestSpec -type MountStatusSpec -type ParameterSpec -type SwapStatusSpec -type SymlinkSpec -type SystemDiskSpec -type UserDiskConfigStatusSpec -type VolumeConfigSpec -type VolumeLifecycleSpec -type VolumeMountRequestSpec -type VolumeMountStatusSpec -type VolumeStatusSpec -type ZswapStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage block\n\n// DeepCopy generates a deep copy of DeviceSpec.\nfunc (o DeviceSpec) DeepCopy() DeviceSpec {\n\tvar cp DeviceSpec = o\n\tif o.Secondaries != nil {\n\t\tcp.Secondaries = make([]string, len(o.Secondaries))\n\t\tcopy(cp.Secondaries, o.Secondaries)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DiscoveredVolumeSpec.\nfunc (o DiscoveredVolumeSpec) DeepCopy() DiscoveredVolumeSpec {\n\tvar cp DiscoveredVolumeSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DiscoveryRefreshRequestSpec.\nfunc (o DiscoveryRefreshRequestSpec) DeepCopy() DiscoveryRefreshRequestSpec {\n\tvar cp DiscoveryRefreshRequestSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DiscoveryRefreshStatusSpec.\nfunc (o DiscoveryRefreshStatusSpec) DeepCopy() DiscoveryRefreshStatusSpec {\n\tvar cp DiscoveryRefreshStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DiskSpec.\nfunc (o DiskSpec) DeepCopy() DiskSpec {\n\tvar cp DiskSpec = o\n\tif o.SecondaryDisks != nil {\n\t\tcp.SecondaryDisks = make([]string, len(o.SecondaryDisks))\n\t\tcopy(cp.SecondaryDisks, o.SecondaryDisks)\n\t}\n\tif o.Symlinks != nil {\n\t\tcp.Symlinks = make([]string, len(o.Symlinks))\n\t\tcopy(cp.Symlinks, o.Symlinks)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MountRequestSpec.\nfunc (o MountRequestSpec) DeepCopy() MountRequestSpec {\n\tvar cp MountRequestSpec = o\n\tif o.Requesters != nil {\n\t\tcp.Requesters = make([]string, len(o.Requesters))\n\t\tcopy(cp.Requesters, o.Requesters)\n\t}\n\tif o.RequesterIDs != nil {\n\t\tcp.RequesterIDs = make([]string, len(o.RequesterIDs))\n\t\tcopy(cp.RequesterIDs, o.RequesterIDs)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MountStatusSpec.\nfunc (o MountStatusSpec) DeepCopy() MountStatusSpec {\n\tvar cp MountStatusSpec = o\n\tcp.Spec = o.Spec.DeepCopy()\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ParameterSpec.\nfunc (o ParameterSpec) DeepCopy() ParameterSpec {\n\tvar cp ParameterSpec = o\n\tif o.String != nil {\n\t\tcp.String = new(string)\n\t\t*cp.String = *o.String\n\t}\n\tif o.Binary != nil {\n\t\tcp.Binary = make([]byte, len(o.Binary))\n\t\tcopy(cp.Binary, o.Binary)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SwapStatusSpec.\nfunc (o SwapStatusSpec) DeepCopy() SwapStatusSpec {\n\tvar cp SwapStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SymlinkSpec.\nfunc (o SymlinkSpec) DeepCopy() SymlinkSpec {\n\tvar cp SymlinkSpec = o\n\tif o.Paths != nil {\n\t\tcp.Paths = make([]string, len(o.Paths))\n\t\tcopy(cp.Paths, o.Paths)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SystemDiskSpec.\nfunc (o SystemDiskSpec) DeepCopy() SystemDiskSpec {\n\tvar cp SystemDiskSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of UserDiskConfigStatusSpec.\nfunc (o UserDiskConfigStatusSpec) DeepCopy() UserDiskConfigStatusSpec {\n\tvar cp UserDiskConfigStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VolumeConfigSpec.\nfunc (o VolumeConfigSpec) DeepCopy() VolumeConfigSpec {\n\tvar cp VolumeConfigSpec = o\n\tif o.Encryption.Keys != nil {\n\t\tcp.Encryption.Keys = make([]EncryptionKey, len(o.Encryption.Keys))\n\t\tcopy(cp.Encryption.Keys, o.Encryption.Keys)\n\t\tfor i3 := range o.Encryption.Keys {\n\t\t\tif o.Encryption.Keys[i3].StaticPassphrase != nil {\n\t\t\t\tcp.Encryption.Keys[i3].StaticPassphrase = make([]byte, len(o.Encryption.Keys[i3].StaticPassphrase))\n\t\t\t\tcopy(cp.Encryption.Keys[i3].StaticPassphrase, o.Encryption.Keys[i3].StaticPassphrase)\n\t\t\t}\n\t\t\tif o.Encryption.Keys[i3].TPMPCRs != nil {\n\t\t\t\tcp.Encryption.Keys[i3].TPMPCRs = make([]int, len(o.Encryption.Keys[i3].TPMPCRs))\n\t\t\t\tcopy(cp.Encryption.Keys[i3].TPMPCRs, o.Encryption.Keys[i3].TPMPCRs)\n\t\t\t}\n\t\t\tif o.Encryption.Keys[i3].TPMPubKeyPCRs != nil {\n\t\t\t\tcp.Encryption.Keys[i3].TPMPubKeyPCRs = make([]int, len(o.Encryption.Keys[i3].TPMPubKeyPCRs))\n\t\t\t\tcopy(cp.Encryption.Keys[i3].TPMPubKeyPCRs, o.Encryption.Keys[i3].TPMPubKeyPCRs)\n\t\t\t}\n\t\t}\n\t}\n\tif o.Encryption.PerfOptions != nil {\n\t\tcp.Encryption.PerfOptions = make([]string, len(o.Encryption.PerfOptions))\n\t\tcopy(cp.Encryption.PerfOptions, o.Encryption.PerfOptions)\n\t}\n\tif o.Mount.BindTarget != nil {\n\t\tcp.Mount.BindTarget = new(string)\n\t\t*cp.Mount.BindTarget = *o.Mount.BindTarget\n\t}\n\tif o.Mount.Parameters != nil {\n\t\tcp.Mount.Parameters = make([]ParameterSpec, len(o.Mount.Parameters))\n\t\tcopy(cp.Mount.Parameters, o.Mount.Parameters)\n\t\tfor i3 := range o.Mount.Parameters {\n\t\t\tcp.Mount.Parameters[i3] = o.Mount.Parameters[i3].DeepCopy()\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VolumeLifecycleSpec.\nfunc (o VolumeLifecycleSpec) DeepCopy() VolumeLifecycleSpec {\n\tvar cp VolumeLifecycleSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VolumeMountRequestSpec.\nfunc (o VolumeMountRequestSpec) DeepCopy() VolumeMountRequestSpec {\n\tvar cp VolumeMountRequestSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VolumeMountStatusSpec.\nfunc (o VolumeMountStatusSpec) DeepCopy() VolumeMountStatusSpec {\n\tvar cp VolumeMountStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VolumeStatusSpec.\nfunc (o VolumeStatusSpec) DeepCopy() VolumeStatusSpec {\n\tvar cp VolumeStatusSpec = o\n\tif o.EncryptionFailedSyncs != nil {\n\t\tcp.EncryptionFailedSyncs = make([]string, len(o.EncryptionFailedSyncs))\n\t\tcopy(cp.EncryptionFailedSyncs, o.EncryptionFailedSyncs)\n\t}\n\tif o.ConfiguredEncryptionKeys != nil {\n\t\tcp.ConfiguredEncryptionKeys = make([]string, len(o.ConfiguredEncryptionKeys))\n\t\tcopy(cp.ConfiguredEncryptionKeys, o.ConfiguredEncryptionKeys)\n\t}\n\tif o.EncryptionSlot != nil {\n\t\tcp.EncryptionSlot = new(int)\n\t\t*cp.EncryptionSlot = *o.EncryptionSlot\n\t}\n\tif o.TPMEncryptionOptions.PCRs != nil {\n\t\tcp.TPMEncryptionOptions.PCRs = make([]int, len(o.TPMEncryptionOptions.PCRs))\n\t\tcopy(cp.TPMEncryptionOptions.PCRs, o.TPMEncryptionOptions.PCRs)\n\t}\n\tif o.TPMEncryptionOptions.PubKeyPCRs != nil {\n\t\tcp.TPMEncryptionOptions.PubKeyPCRs = make([]int, len(o.TPMEncryptionOptions.PubKeyPCRs))\n\t\tcopy(cp.TPMEncryptionOptions.PubKeyPCRs, o.TPMEncryptionOptions.PubKeyPCRs)\n\t}\n\tif o.MountSpec.BindTarget != nil {\n\t\tcp.MountSpec.BindTarget = new(string)\n\t\t*cp.MountSpec.BindTarget = *o.MountSpec.BindTarget\n\t}\n\tif o.MountSpec.Parameters != nil {\n\t\tcp.MountSpec.Parameters = make([]ParameterSpec, len(o.MountSpec.Parameters))\n\t\tcopy(cp.MountSpec.Parameters, o.MountSpec.Parameters)\n\t\tfor i3 := range o.MountSpec.Parameters {\n\t\t\tcp.MountSpec.Parameters[i3] = o.MountSpec.Parameters[i3].DeepCopy()\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ZswapStatusSpec.\nfunc (o ZswapStatusSpec) DeepCopy() ZswapStatusSpec {\n\tvar cp ZswapStatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/device.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DeviceType is type of BlockDevice resource.\nconst DeviceType = resource.Type(\"BlockDevices.block.talos.dev\")\n\n// Device resource holds status of hardware devices (overall).\ntype Device = typed.Resource[DeviceSpec, DeviceExtension]\n\n// DeviceSpec is the spec for devices status.\n//\n//gotagsrewrite:gen\ntype DeviceSpec struct {\n\tType            string `yaml:\"type\" protobuf:\"1\"`\n\tMajor           int    `yaml:\"major\" protobuf:\"2\"`\n\tMinor           int    `yaml:\"minor\" protobuf:\"3\"`\n\tPartitionName   string `yaml:\"partitionName,omitempty\" protobuf:\"4\"`\n\tPartitionNumber int    `yaml:\"partitionNumber,omitempty\" protobuf:\"5\"`\n\tDevicePath      string `yaml:\"devicePath\" protobuf:\"7\"`\n\n\t// Generation is bumped every time the device might have changed and might need to be re-probed.\n\tGeneration int `yaml:\"generation\" protobuf:\"6\"`\n\n\t// Parent (if set) specifies the parent device ID.\n\tParent string `yaml:\"parent,omitempty\" protobuf:\"8\"`\n\n\t// Secondaries (if set) specifies the secondary device IDs.\n\t//\n\t// E.g. for a LVM volume secondary is a list of blockdevices that the volume consists of.\n\tSecondaries []string `yaml:\"secondaries,omitempty\" protobuf:\"9\"`\n}\n\n// DeviceType constants.\nconst (\n\tDeviceTypeDisk      = \"disk\"\n\tDeviceTypePartition = \"partition\"\n)\n\n// NewDevice initializes a BlockDevice resource.\nfunc NewDevice(namespace resource.Namespace, id resource.ID) *Device {\n\treturn typed.NewResource[DeviceSpec, DeviceExtension](\n\t\tresource.NewMetadata(namespace, DeviceType, id, resource.VersionUndefined),\n\t\tDeviceSpec{},\n\t)\n}\n\n// DeviceExtension is auxiliary resource data for BlockDevice.\ntype DeviceExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DeviceExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DeviceType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.type}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PartitionName\",\n\t\t\t\tJSONPath: `{.partitionName}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Generation\",\n\t\t\t\tJSONPath: `{.generation}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(DeviceType, &Device{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/discovered_volume.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/dustin/go-humanize\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DiscoveredVolumeType is type of DiscoveredVolume resource.\nconst DiscoveredVolumeType = resource.Type(\"DiscoveredVolumes.block.talos.dev\")\n\n// DiscoveredVolume resource holds status of hardware DiscoveredVolumes (overall).\ntype DiscoveredVolume = typed.Resource[DiscoveredVolumeSpec, DiscoveredVolumeExtension]\n\n// DiscoveredVolumeSpec is the spec for DiscoveredVolumes resource.\n//\n//gotagsrewrite:gen\ntype DiscoveredVolumeSpec struct {\n\tDevPath       string `yaml:\"dev_path\" protobuf:\"17\"`\n\tType          string `yaml:\"type\" protobuf:\"14\"`\n\tDevicePath    string `yaml:\"device_path\" protobuf:\"15\"`\n\tParent        string `yaml:\"parent,omitempty\" protobuf:\"16\"`\n\tParentDevPath string `yaml:\"parent_dev_path,omitempty\" protobuf:\"18\"`\n\n\t// Offset of the partition/volume inside Parent device (in bytes).\n\tOffset uint64 `yaml:\"offset\" protobuf:\"20\"`\n\n\t// Overall size of the probed device (in bytes).\n\tSize       uint64 `yaml:\"size\" protobuf:\"1\"`\n\tPrettySize string `yaml:\"pretty_size\" protobuf:\"19\"`\n\n\t// Sector size of the device (in bytes).\n\tSectorSize uint `yaml:\"sector_size,omitempty\" protobuf:\"2\"`\n\n\t// Optimal I/O size for the device (in bytes).\n\tIOSize uint `yaml:\"io_size,omitempty\" protobuf:\"3\"`\n\n\tName  string `yaml:\"name\" protobuf:\"4\"`\n\tUUID  string `yaml:\"uuid,omitempty\" protobuf:\"5\"`\n\tLabel string `yaml:\"label,omitempty\" protobuf:\"6\"`\n\n\tBlockSize           uint32 `yaml:\"block_size,omitempty\" protobuf:\"7\"`\n\tFilesystemBlockSize uint32 `yaml:\"filesystem_block_size,omitempty\" protobuf:\"8\"`\n\tProbedSize          uint64 `yaml:\"probed_size,omitempty\" protobuf:\"9\"`\n\n\tPartitionUUID  string `yaml:\"partition_uuid,omitempty\" protobuf:\"10\"`\n\tPartitionType  string `yaml:\"partition_type,omitempty\" protobuf:\"11\"`\n\tPartitionLabel string `yaml:\"partition_label,omitempty\" protobuf:\"12\"`\n\tPartitionIndex uint   `yaml:\"partition_index,omitempty\" protobuf:\"13\"`\n}\n\n// SetSize sets the size of the DiscoveredVolume, including the pretty size.\nfunc (s *DiscoveredVolumeSpec) SetSize(size uint64) {\n\ts.Size = size\n\ts.PrettySize = humanize.Bytes(size)\n}\n\n// NewDiscoveredVolume initializes a BlockDiscoveredVolume resource.\nfunc NewDiscoveredVolume(namespace resource.Namespace, id resource.ID) *DiscoveredVolume {\n\treturn typed.NewResource[DiscoveredVolumeSpec, DiscoveredVolumeExtension](\n\t\tresource.NewMetadata(namespace, DiscoveredVolumeType, id, resource.VersionUndefined),\n\t\tDiscoveredVolumeSpec{},\n\t)\n}\n\n// DiscoveredVolumeExtension is auxiliary resource data for BlockDiscoveredVolume.\ntype DiscoveredVolumeExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DiscoveredVolumeExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DiscoveredVolumeType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.type}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Size\",\n\t\t\t\tJSONPath: `{.pretty_size}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Discovered\",\n\t\t\t\tJSONPath: `{.name}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Label\",\n\t\t\t\tJSONPath: `{.label}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PartitionLabel\",\n\t\t\t\tJSONPath: `{.partition_label}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(DiscoveredVolumeType, &DiscoveredVolume{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/discovery_refresh_request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DiscoveryRefreshRequestType is type of DiscoveryRefreshRequest resource.\nconst DiscoveryRefreshRequestType = resource.Type(\"DiscoveryRefreshRequests.block.talos.dev\")\n\n// RefreshID is the ID of the singleton discovery refresh request/statue.\nconst RefreshID resource.ID = \"refresh\"\n\n// DiscoveryRefreshRequest resource holds a request to refresh the discovered volumes.\ntype DiscoveryRefreshRequest = typed.Resource[DiscoveryRefreshRequestSpec, DiscoveryRefreshRequestExtension]\n\n// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest.\n//\n//gotagsrewrite:gen\ntype DiscoveryRefreshRequestSpec struct {\n\tRequest int `yaml:\"request\" protobuf:\"1\"`\n}\n\n// NewDiscoveryRefreshRequest initializes a DiscoveryRefreshRequest resource.\nfunc NewDiscoveryRefreshRequest(namespace resource.Namespace, id resource.ID) *DiscoveryRefreshRequest {\n\treturn typed.NewResource[DiscoveryRefreshRequestSpec, DiscoveryRefreshRequestExtension](\n\t\tresource.NewMetadata(namespace, DiscoveryRefreshRequestType, id, resource.VersionUndefined),\n\t\tDiscoveryRefreshRequestSpec{},\n\t)\n}\n\n// DiscoveryRefreshRequestExtension is auxiliary resource data for DiscoveryRefreshRequest.\ntype DiscoveryRefreshRequestExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DiscoveryRefreshRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DiscoveryRefreshRequestType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Request\",\n\t\t\t\tJSONPath: `{.request}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(DiscoveryRefreshRequestType, &DiscoveryRefreshRequest{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/discovery_refresh_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DiscoveryRefreshStatusType is type of DiscoveryRefreshStatus resource.\nconst DiscoveryRefreshStatusType = resource.Type(\"DiscoveryRefreshStatuses.block.talos.dev\")\n\n// DiscoveryRefreshStatus resource holds a status of refresh.\ntype DiscoveryRefreshStatus = typed.Resource[DiscoveryRefreshStatusSpec, DiscoveryRefreshStatusExtension]\n\n// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status.\n//\n//gotagsrewrite:gen\ntype DiscoveryRefreshStatusSpec struct {\n\tRequest int `yaml:\"request\" protobuf:\"1\"`\n}\n\n// NewDiscoveryRefreshStatus initializes a DiscoveryRefreshStatus resource.\nfunc NewDiscoveryRefreshStatus(namespace resource.Namespace, id resource.ID) *DiscoveryRefreshStatus {\n\treturn typed.NewResource[DiscoveryRefreshStatusSpec, DiscoveryRefreshStatusExtension](\n\t\tresource.NewMetadata(namespace, DiscoveryRefreshStatusType, id, resource.VersionUndefined),\n\t\tDiscoveryRefreshStatusSpec{},\n\t)\n}\n\n// DiscoveryRefreshStatusExtension is auxiliary resource data for DiscoveryRefreshStatus.\ntype DiscoveryRefreshStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DiscoveryRefreshStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DiscoveryRefreshStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Request\",\n\t\t\t\tJSONPath: `{.request}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(DiscoveryRefreshStatusType, &DiscoveryRefreshStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/dustin/go-humanize\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DiskType is type of Disk resource.\nconst DiskType = resource.Type(\"Disks.block.talos.dev\")\n\n// Disk resource holds status of hardware disks.\ntype Disk = typed.Resource[DiskSpec, DiskExtension]\n\n// DiskSpec is the spec for Disks status.\n//\n//gotagsrewrite:gen\ntype DiskSpec struct {\n\tDevPath string `yaml:\"dev_path\" protobuf:\"14\"`\n\n\tSize       uint64 `yaml:\"size\" protobuf:\"1\"`\n\tPrettySize string `yaml:\"pretty_size\" protobuf:\"15\"`\n\tIOSize     uint   `yaml:\"io_size\" protobuf:\"2\"`\n\tSectorSize uint   `yaml:\"sector_size\" protobuf:\"3\"`\n\n\tReadonly bool `yaml:\"readonly\" protobuf:\"4\"`\n\tCDROM    bool `yaml:\"cdrom\" protobuf:\"13\"`\n\n\tModel      string `yaml:\"model,omitempty\" protobuf:\"5\"`\n\tSerial     string `yaml:\"serial,omitempty\" protobuf:\"6\"`\n\tModalias   string `yaml:\"modalias,omitempty\" protobuf:\"7\"`\n\tWWID       string `yaml:\"wwid,omitempty\" protobuf:\"8\"`\n\tUUID       string `yaml:\"uuid,omitempty\" protobuf:\"17\"`\n\tBusPath    string `yaml:\"bus_path,omitempty\" protobuf:\"9\"`\n\tSubSystem  string `yaml:\"sub_system,omitempty\" protobuf:\"10\"`\n\tTransport  string `yaml:\"transport,omitempty\" protobuf:\"11\"`\n\tRotational bool   `yaml:\"rotational,omitempty\" protobuf:\"12\"`\n\n\t// SecondaryDisks (if set) specifies the secondary disk IDs.\n\t//\n\t// E.g. if the blockdevice secondary is vda5, the secondary disk will be set as vda.\n\t// This allows to map secondaries between disks ignoring the partitions.\n\tSecondaryDisks []string `yaml:\"secondary_disks,omitempty\" protobuf:\"16\"`\n\n\tSymlinks []string `yaml:\"symlinks,omitempty\" protobuf:\"18\"`\n}\n\n// SetSize sets the size of the disk, including the pretty size.\nfunc (s *DiskSpec) SetSize(size uint64) {\n\ts.Size = size\n\ts.PrettySize = humanize.Bytes(size)\n}\n\n// NewDisk initializes a BlockDisk resource.\nfunc NewDisk(namespace resource.Namespace, id resource.ID) *Disk {\n\treturn typed.NewResource[DiskSpec, DiskExtension](\n\t\tresource.NewMetadata(namespace, DiskType, id, resource.VersionUndefined),\n\t\tDiskSpec{},\n\t)\n}\n\n// DiskExtension is auxiliary resource data for BlockDisk.\ntype DiskExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DiskExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DiskType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Size\",\n\t\t\t\tJSONPath: `{.pretty_size}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Read Only\",\n\t\t\t\tJSONPath: `{.readonly}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Transport\",\n\t\t\t\tJSONPath: `{.transport}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Rotational\",\n\t\t\t\tJSONPath: `{.rotational}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"WWID\",\n\t\t\t\tJSONPath: `{.wwid}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Model\",\n\t\t\t\tJSONPath: `{.model}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Serial\",\n\t\t\t\tJSONPath: `{.serial}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(DiskType, &Disk{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/encryptionkeytype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// EncryptionKeyType describes encryption key type.\ntype EncryptionKeyType int\n\n// Encryption key types.\n//\n//structprotogen:gen_enum\nconst (\n\tEncryptionKeyStatic EncryptionKeyType = iota // static\n\tEncryptionKeyNodeID                          // nodeID\n\tEncryptionKeyKMS                             // kms\n\tEncryptionKeyTPM                             // tpm\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/encryptionprovidertype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// EncryptionProviderType describes encryption provider type.\ntype EncryptionProviderType int\n\n// Encryption provider types.\n//\n//structprotogen:gen_enum\nconst (\n\tEncryptionProviderNone  EncryptionProviderType = iota // none\n\tEncryptionProviderLUKS2                               // luks2\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/filesystemtype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// FilesystemType describes filesystem type.\ntype FilesystemType int\n\n// Filesystem types.\n//\n//structprotogen:gen_enum\nconst (\n\tFilesystemTypeNone     FilesystemType = iota // none\n\tFilesystemTypeXFS                            // xfs\n\tFilesystemTypeVFAT                           // vfat\n\tFilesystemTypeEXT4                           // ext4\n\tFilesystemTypeISO9660                        // iso9660\n\tFilesystemTypeSwap                           // swapi\n\tFilesystemTypeVirtiofs                       // virtiofs\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/fsparametertype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// FSParameterType describes Filesystem Parameter type.\ntype FSParameterType int\n\n// NFS Version types.\n//\n//structprotogen:gen_enum\nconst (\n\tFSParameterTypeStringValue  FSParameterType = iota // string\n\tFSParameterTypeBooleanValue                        // boolean\n\tFSParameterTypeBinaryValue                         // binary\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/mount_request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MountRequestType is type of MountRequest resource.\nconst MountRequestType = resource.Type(\"MountRequests.block.talos.dev\")\n\n// MountRequest resource is a final mount request spec.\ntype MountRequest = typed.Resource[MountRequestSpec, MountRequestExtension]\n\n// MountRequestSpec is the spec for MountRequest.\n//\n//gotagsrewrite:gen\ntype MountRequestSpec struct {\n\tVolumeID string `yaml:\"volumeID\" protobuf:\"1\"`\n\n\tParentMountID string `yaml:\"parentID\" protobuf:\"2\"`\n\tReadOnly      bool   `yaml:\"readOnly\" protobuf:\"5\"`\n\tDetached      bool   `yaml:\"detached\" protobuf:\"6\"`\n\n\tDisableAccessTime bool `yaml:\"disableAccessTime,omitempty\" protobuf:\"7\"`\n\tSecure            bool `yaml:\"secure,omitempty\" protobuf:\"8\"`\n\n\tRequesters   []string `yaml:\"requesters\" protobuf:\"3\"`\n\tRequesterIDs []string `yaml:\"requesterIDs\" protobuf:\"4\"`\n}\n\n// NewMountRequest initializes a MountRequest resource.\nfunc NewMountRequest(namespace resource.Namespace, id resource.ID) *MountRequest {\n\treturn typed.NewResource[MountRequestSpec, MountRequestExtension](\n\t\tresource.NewMetadata(namespace, MountRequestType, id, resource.VersionUndefined),\n\t\tMountRequestSpec{},\n\t)\n}\n\n// MountRequestExtension is auxiliary resource data for BlockMountRequest.\ntype MountRequestExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MountRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MountRequestType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Volume\",\n\t\t\t\tJSONPath: `{.volumeID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Parent\",\n\t\t\t\tJSONPath: `{.parentID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Requesters\",\n\t\t\t\tJSONPath: `{.requesters}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(MountRequestType, &MountRequest{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MountStatusType is type of MountStatus resource.\nconst MountStatusType = resource.Type(\"MountStatuses.block.talos.dev\")\n\n// MountStatus resource is a final mount request spec.\ntype MountStatus = typed.Resource[MountStatusSpec, MountStatusExtension]\n\n// MountStatusSpec is the spec for MountStatus.\n//\n//gotagsrewrite:gen\ntype MountStatusSpec struct {\n\tSpec               MountRequestSpec       `yaml:\"spec\" protobuf:\"1\"`\n\tSource             string                 `yaml:\"source\" protobuf:\"3\"`\n\tTarget             string                 `yaml:\"target\" protobuf:\"2\"`\n\tFilesystem         FilesystemType         `yaml:\"filesystem\" protobuf:\"4\"`\n\tEncryptionProvider EncryptionProviderType `yaml:\"encryptionProvider,omitempty\" protobuf:\"7\"`\n\n\tReadOnly            bool `yaml:\"readOnly\" protobuf:\"5\"`\n\tProjectQuotaSupport bool `yaml:\"projectQuotaSupport\" protobuf:\"6\"`\n\tDetached            bool `yaml:\"detached\" protobuf:\"8\"`\n\n\troot any\n}\n\n// SetRoot sets the XFS root for the mount.\nfunc (m *MountStatusSpec) SetRoot(root any) {\n\tm.root = root\n}\n\n// Root gets the XFS root for the mount.\n// It's not guaranteed to be set (may be nil).\nfunc (m *MountStatusSpec) Root() any {\n\treturn m.root\n}\n\n// NewMountStatus initializes a MountStatus resource.\nfunc NewMountStatus(namespace resource.Namespace, id resource.ID) *MountStatus {\n\treturn typed.NewResource[MountStatusSpec, MountStatusExtension](\n\t\tresource.NewMetadata(namespace, MountStatusType, id, resource.VersionUndefined),\n\t\tMountStatusSpec{},\n\t)\n}\n\n// MountStatusExtension is auxiliary resource data for BlockMountStatus.\ntype MountStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MountStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MountStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Source\",\n\t\t\t\tJSONPath: `{.source}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Target\",\n\t\t\t\tJSONPath: `{.target}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Filesystem\",\n\t\t\t\tJSONPath: `{.filesystem}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Volume\",\n\t\t\t\tJSONPath: `{.spec.volumeID}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(MountStatusType, &MountStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/swap_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SwapStatusType is type of SwapStatus resource.\nconst SwapStatusType = resource.Type(\"SwapStatuses.block.talos.dev\")\n\n// SwapStatus resource holds a list of stable symlinks to the blockdevice.\ntype SwapStatus = typed.Resource[SwapStatusSpec, SwapStatusExtension]\n\n// SwapStatusSpec is the spec for SwapStatuss resource.\n//\n//gotagsrewrite:gen\ntype SwapStatusSpec struct {\n\tDevice    string `yaml:\"device\" protobuf:\"1\"`\n\tType      string `yaml:\"type\" protobuf:\"7\"`\n\tSizeBytes uint64 `yaml:\"size\" protobuf:\"2\"`\n\tSizeHuman string `yaml:\"sizeHuman\" protobuf:\"3\"`\n\tUsedBytes uint64 `yaml:\"used\" protobuf:\"4\"`\n\tUsedHuman string `yaml:\"usedHuman\" protobuf:\"5\"`\n\tPriority  int32  `yaml:\"priority\" protobuf:\"6\"`\n}\n\n// NewSwapStatus initializes a SwapStatus resource.\nfunc NewSwapStatus(namespace resource.Namespace, id resource.ID) *SwapStatus {\n\treturn typed.NewResource[SwapStatusSpec, SwapStatusExtension](\n\t\tresource.NewMetadata(namespace, SwapStatusType, id, resource.VersionUndefined),\n\t\tSwapStatusSpec{},\n\t)\n}\n\n// SwapStatusExtension is auxiliary resource data for SwapStatus.\ntype SwapStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (SwapStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SwapStatusType,\n\t\tAliases:          []resource.Type{\"swap\", \"swaps\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Device\",\n\t\t\t\tJSONPath: \"{.device}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Size\",\n\t\t\t\tJSONPath: \"{.sizeHuman}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Used\",\n\t\t\t\tJSONPath: \"{.usedHuman}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Priority\",\n\t\t\t\tJSONPath: \"{.priority}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(SwapStatusType, &SwapStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/symlink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SymlinkType is type of Symlink resource.\nconst SymlinkType = resource.Type(\"BlockSymlinks.block.talos.dev\")\n\n// Symlink resource holds a list of stable symlinks to the blockdevice.\ntype Symlink = typed.Resource[SymlinkSpec, SymlinkExtension]\n\n// SymlinkID is the singleton resource ID.\nconst SymlinkID resource.ID = \"system-disk\"\n\n// SymlinkSpec is the spec for Symlinks resource.\n//\n//gotagsrewrite:gen\ntype SymlinkSpec struct {\n\tPaths []string `yaml:\"paths\" protobuf:\"1\"`\n}\n\n// NewSymlink initializes a BlockSymlink resource.\nfunc NewSymlink(namespace resource.Namespace, id resource.ID) *Symlink {\n\treturn typed.NewResource[SymlinkSpec, SymlinkExtension](\n\t\tresource.NewMetadata(namespace, SymlinkType, id, resource.VersionUndefined),\n\t\tSymlinkSpec{},\n\t)\n}\n\n// SymlinkExtension is auxiliary resource data for BlockSymlink.\ntype SymlinkExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (SymlinkExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SymlinkType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(SymlinkType, &Symlink{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/system_disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SystemDiskType is type of SystemDisk resource.\nconst SystemDiskType = resource.Type(\"SystemDisks.block.talos.dev\")\n\n// SystemDisk resource holds ID of the disk which is the Talos system disk.\ntype SystemDisk = typed.Resource[SystemDiskSpec, SystemDiskExtension]\n\n// SystemDiskID is the singleton resource ID.\nconst SystemDiskID resource.ID = \"system-disk\"\n\n// SystemDiskSpec is the spec for SystemDisks resource.\n//\n//gotagsrewrite:gen\ntype SystemDiskSpec struct {\n\tDiskID  string `yaml:\"diskID\" protobuf:\"1\"`\n\tDevPath string `yaml:\"devPath\" protobuf:\"2\"`\n}\n\n// NewSystemDisk initializes a BlockSystemDisk resource.\nfunc NewSystemDisk(namespace resource.Namespace, id resource.ID) *SystemDisk {\n\treturn typed.NewResource[SystemDiskSpec, SystemDiskExtension](\n\t\tresource.NewMetadata(namespace, SystemDiskType, id, resource.VersionUndefined),\n\t\tSystemDiskSpec{},\n\t)\n}\n\n// SystemDiskExtension is auxiliary resource data for BlockSystemDisk.\ntype SystemDiskExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (SystemDiskExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SystemDiskType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Disk\",\n\t\t\t\tJSONPath: `{.diskID}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(SystemDiskType, &SystemDisk{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/user_disk_config_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// UserDiskConfigStatusType is type of UserDiskConfigStatus resource.\nconst UserDiskConfigStatusType = resource.Type(\"UserDiskConfigStatuses.block.talos.dev\")\n\n// UserDiskConfigStatus resource holds a status of user disk machine configuration.\ntype UserDiskConfigStatus = typed.Resource[UserDiskConfigStatusSpec, UserDiskConfigStatusExtension]\n\n// UserDiskConfigStatusID is the ID of the UserDiskConfigStatus resource.\nconst UserDiskConfigStatusID = \"user-disks\"\n\n// UserDiskConfigStatusSpec is the spec for UserDiskConfigStatus resource.\n//\n//gotagsrewrite:gen\ntype UserDiskConfigStatusSpec struct {\n\tReady    bool `yaml:\"ready\" protobuf:\"1\"`\n\tTornDown bool `yaml:\"tornDown\" protobuf:\"2\"`\n}\n\n// NewUserDiskConfigStatus initializes a UserDiskConfigStatus resource.\nfunc NewUserDiskConfigStatus(namespace resource.Namespace, id resource.ID) *UserDiskConfigStatus {\n\treturn typed.NewResource[UserDiskConfigStatusSpec, UserDiskConfigStatusExtension](\n\t\tresource.NewMetadata(namespace, UserDiskConfigStatusType, id, resource.VersionUndefined),\n\t\tUserDiskConfigStatusSpec{},\n\t)\n}\n\n// UserDiskConfigStatusExtension is auxiliary resource data for UserDiskConfigStatus.\ntype UserDiskConfigStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (UserDiskConfigStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             UserDiskConfigStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: `{.ready}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(UserDiskConfigStatusType, &UserDiskConfigStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/yamlutils\"\n)\n\n// VolumeConfigType is type of VolumeConfig resource.\nconst VolumeConfigType = resource.Type(\"VolumeConfigs.block.talos.dev\")\n\n// VolumeConfig resource contains configuration for machine volumes.\ntype VolumeConfig = typed.Resource[VolumeConfigSpec, VolumeConfigExtension]\n\n// VolumeConfigSpec is the spec for VolumeConfig resource.\n//\n//gotagsrewrite:gen\ntype VolumeConfigSpec struct {\n\t// Parent volume ID, if set no operations on the volume continue until the parent volume is ready.\n\tParentID string `yaml:\"parentId,omitempty\" protobuf:\"1\"`\n\n\t// Volume type.\n\tType VolumeType `yaml:\"type\" protobuf:\"2\"`\n\n\t// Provisioning configuration (how to provision a volume).\n\tProvisioning ProvisioningSpec `yaml:\"provisioning\" protobuf:\"3\"`\n\n\t// Encryption configuration (how to encrypt a volume).\n\tEncryption EncryptionSpec `yaml:\"encryption,omitempty\" protobuf:\"6\"`\n\n\t// How to find a volume.\n\tLocator LocatorSpec `yaml:\"locator\" protobuf:\"4\"`\n\n\t// Mount options for the volume.\n\tMount MountSpec `yaml:\"mount,omitempty\" protobuf:\"5\"`\n\n\t// Symlink options for the volume.\n\tSymlink SymlinkProvisioningSpec `yaml:\"symlink,omitempty\" protobuf:\"7\"`\n}\n\n// Wave constants.\nconst (\n\tWaveSystemDisk      = -1\n\tWaveUserVolumes     = 0\n\tWaveLegacyUserDisks = 1000000 // legacy user disks rely on specific order of provisioning\n)\n\n// ProvisioningSpec is the spec for volume provisioning.\n//\n//gotagsrewrite:gen\ntype ProvisioningSpec struct {\n\t// Provisioning wave for the volume.\n\t//\n\t// Waves are processed sequentially - the volumes in the wave are only provisioned after the previous wave is done.\n\tWave int `yaml:\"wave,omitempty\" protobuf:\"3\"`\n\n\t// DiskSelector selects a disk for the volume.\n\tDiskSelector DiskSelector `yaml:\"diskSelector,omitempty\" protobuf:\"1\"`\n\n\t// PartitionSpec describes how to provision the volume (partition type).\n\tPartitionSpec PartitionSpec `yaml:\"partitionSpec,omitempty\" protobuf:\"2\"`\n\n\t// FilesystemSpec describes how to provision the volume (filesystem type).\n\tFilesystemSpec FilesystemSpec `yaml:\"filesystemSpec,omitempty\" protobuf:\"4\"`\n}\n\n// DiskSelector selects a disk for the volume.\n//\n//gotagsrewrite:gen\ntype DiskSelector struct {\n\tMatch    cel.Expression `yaml:\"match,omitempty\" protobuf:\"1\"`\n\tExternal string         `yaml:\"external,omitempty\" protobuf:\"2\"`\n}\n\n// PartitionSpec is the spec for volume partitioning.\n//\n//gotagsrewrite:gen\ntype PartitionSpec struct {\n\t// Partition minimum size in bytes.\n\tMinSize uint64 `yaml:\"minSize\" protobuf:\"1\"`\n\n\t// Partition maximum size in bytes, if not set, grows to the maximum size.\n\tMaxSize uint64 `yaml:\"maxSize,omitempty\" protobuf:\"2\"`\n\n\t// Partition maximum size (relative), if not set, grows to the maximum size.\n\tRelativeMaxSize uint64 `yaml:\"relativeMaxSize\" protobuf:\"6\"`\n\n\t// NegativeMaxSize indicates that MaxSize or RelativeMaxSize represents space to be left free on the device rather than space to consume.\n\tNegativeMaxSize bool `yaml:\"negativeMaxSize\" protobuf:\"7\"`\n\n\t// Grow the partition automatically to the maximum size.\n\tGrow bool `yaml:\"grow\" protobuf:\"3\"`\n\n\t// Label for the partition.\n\tLabel string `yaml:\"label,omitempty\" protobuf:\"4\"`\n\n\t// Partition type UUID.\n\tTypeUUID string `yaml:\"typeUUID,omitempty\" protobuf:\"5\"`\n}\n\n// ResolveMaxSize resolves the maximum size of the partition.\n// Returns the maximum size of the partition and an error if the partition size cannot be resolved.\nfunc (ps *PartitionSpec) ResolveMaxSize(available uint64) (uint64, error) {\n\tvar size uint64\n\n\tif ps.RelativeMaxSize != 0 {\n\t\tsize = available * ps.RelativeMaxSize / 100\n\t} else {\n\t\tsize = ps.MaxSize\n\t}\n\n\tif ps.NegativeMaxSize {\n\t\tif size > available {\n\t\t\treturn 0, fmt.Errorf(\"partition size cannot be negative\")\n\t\t}\n\n\t\treturn available - size, nil\n\t}\n\n\treturn size, nil\n}\n\n// LocatorSpec is the spec for volume locator.\n//\n//gotagsrewrite:gen\ntype LocatorSpec struct {\n\t// Match is a volume locator match expression.\n\tMatch cel.Expression `yaml:\"match,omitempty\" protobuf:\"1\"`\n\t// DiskMatch is a disk locator match expression.\n\tDiskMatch cel.Expression `yaml:\"diskMatch,omitempty\" protobuf:\"2\"`\n}\n\n// FilesystemSpec is the spec for volume filesystem.\n//\n//gotagsrewrite:gen\ntype FilesystemSpec struct {\n\t// Filesystem type.\n\tType FilesystemType `yaml:\"type\" protobuf:\"1\"`\n\t// Filesystem label.\n\tLabel string `yaml:\"label,omitempty\" protobuf:\"2\"`\n}\n\n// EncryptionSpec is the spec for volume encryption.\n//\n//gotagsrewrite:gen\ntype EncryptionSpec struct {\n\tProvider    EncryptionProviderType `yaml:\"provider\" protobuf:\"1\"`\n\tKeys        []EncryptionKey        `yaml:\"keys\" protobuf:\"2\"`\n\tCipher      string                 `yaml:\"cipher,omitempty\" protobuf:\"3\"`\n\tKeySize     uint                   `yaml:\"keySize,omitempty\" protobuf:\"4\"`\n\tBlockSize   uint64                 `yaml:\"blockSize,omitempty\" protobuf:\"5\"`\n\tPerfOptions []string               `yaml:\"perfOptions,omitempty\" protobuf:\"6\"`\n}\n\n// EncryptionKey is the spec for volume encryption key.\n//\n//gotagsrewrite:gen\ntype EncryptionKey struct {\n\tSlot        int               `yaml:\"slot\" protobuf:\"1\"`\n\tType        EncryptionKeyType `yaml:\"type\" protobuf:\"2\"`\n\tLockToSTATE bool              `yaml:\"lockToState,omitempty\" protobuf:\"6\"`\n\n\t// Only for Type == \"static\":\n\tStaticPassphrase yamlutils.StringBytes `yaml:\"staticPassphrase,omitempty\" protobuf:\"3\"`\n\n\t// Only for Type == \"kms\":\n\tKMSEndpoint string `yaml:\"kmsEndpoint,omitempty\" protobuf:\"4\"`\n\n\t// Only for Type == \"tpm\":\n\tTPMCheckSecurebootStatusOnEnroll bool `yaml:\"tpmCheckSecurebootStatusOnEnroll,omitempty\" protobuf:\"5\"`\n\t// Only for Type == \"tpm\":\n\tTPMPCRs []int `yaml:\"pcrs,omitempty\" protobuf:\"7\"`\n\t// Only for Type == \"tpm\":\n\tTPMPubKeyPCRs []int `yaml:\"pubKeyPcrs,omitempty\" protobuf:\"8\"`\n}\n\n// ParameterSpec is a mount parameter.\n//\n//gotagsrewrite:gen\ntype ParameterSpec struct {\n\t// Type of the parameter.\n\tType FSParameterType `yaml:\"type\" protobuf:\"1\"`\n\t// Name of the parameter.\n\tName string `yaml:\"name\" protobuf:\"2\"`\n\t// String value of the parameter.\n\tString *string `yaml:\"string,omitempty\" protobuf:\"3\"`\n\t// Binary value of the parameter.\n\tBinary []byte `yaml:\"binary,omitempty\" protobuf:\"5\"`\n}\n\n// NewBooleanParameter creates a new boolean parameter.\nfunc NewBooleanParameter(name string) ParameterSpec {\n\treturn ParameterSpec{\n\t\tType: FSParameterTypeBooleanValue,\n\t\tName: name,\n\t}\n}\n\n// NewBinaryParameter creates a new binary parameter.\nfunc NewBinaryParameter(name string, value []byte) ParameterSpec {\n\treturn ParameterSpec{\n\t\tType:   FSParameterTypeBinaryValue,\n\t\tName:   name,\n\t\tBinary: value,\n\t}\n}\n\n// NewStringParameter creates a new string parameter.\nfunc NewStringParameter(name, value string) ParameterSpec {\n\treturn ParameterSpec{\n\t\tType:   FSParameterTypeStringValue,\n\t\tName:   name,\n\t\tString: new(value),\n\t}\n}\n\n// MountSpec is the spec for volume mount.\n//\n//gotagsrewrite:gen\ntype MountSpec struct {\n\t// Mount path for the volume.\n\tTargetPath string `yaml:\"targetPath\" protobuf:\"1\"`\n\t// SELinux label for the volume.\n\tSelinuxLabel string `yaml:\"selinuxLabel\" protobuf:\"2\"`\n\t// Enable project quota (xfs) for the volume.\n\tProjectQuotaSupport bool `yaml:\"projectQuotaSupport\" protobuf:\"3\"`\n\t// Parent mount request ID.\n\tParentID string `yaml:\"parentId,omitempty\" protobuf:\"4\"`\n\t// FileMode is the file mode for the mount target.\n\tFileMode os.FileMode `yaml:\"fileMode,omitempty\" protobuf:\"5\"`\n\t// UID is the user ID for the mount target.\n\tUID int `yaml:\"uid,omitempty\" protobuf:\"6\"`\n\t// GID is the group ID for the mount target.\n\tGID int `yaml:\"gid,omitempty\" protobuf:\"7\"`\n\t// RecursiveRelabel is the recursive relabel/chown flag for the mount target.\n\tRecursiveRelabel bool `yaml:\"recursiveRelabel,omitempty\" protobuf:\"8\"`\n\t// BindTarget is an optional path on the host to bind-mount the volume onto.\n\tBindTarget *string `yaml:\"bindTarget,omitempty\" protobuf:\"9\"`\n\t// Parameters are additional filesystem mount options used when mounting the volume.\n\tParameters []ParameterSpec `yaml:\"parameters,omitempty\" protobuf:\"10\"`\n}\n\n// SymlinkProvisioningSpec is the spec for volume symlink.\n//\n//gotagsrewrite:gen\ntype SymlinkProvisioningSpec struct {\n\t// Symlink target path for the volume.\n\tSymlinkTargetPath string `yaml:\"symlinkTargetPath\" protobuf:\"1\"`\n\t// Force symlink creation.\n\tForce bool `yaml:\"force\" protobuf:\"2\"`\n}\n\n// NewVolumeConfig initializes a BlockVolumeConfig resource.\nfunc NewVolumeConfig(namespace resource.Namespace, id resource.ID) *VolumeConfig {\n\treturn typed.NewResource[VolumeConfigSpec, VolumeConfigExtension](\n\t\tresource.NewMetadata(namespace, VolumeConfigType, id, resource.VersionUndefined),\n\t\tVolumeConfigSpec{},\n\t)\n}\n\n// VolumeConfigExtension is auxiliary resource data for BlockVolumeConfig.\ntype VolumeConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (VolumeConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VolumeConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VolumeConfigType, &VolumeConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/block\"\n)\n\nfunc TestPartitionSpec_ResolveMaxSize(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tps        *block.PartitionSpec\n\t\tavailable uint64\n\t\twant      uint64\n\t\terr       string\n\t}{\n\t\t{\n\t\t\tname: \"absolute max size\",\n\t\t\tps: &block.PartitionSpec{\n\t\t\t\tMaxSize: 50,\n\t\t\t},\n\t\t\tavailable: 100,\n\t\t\twant:      50,\n\t\t},\n\t\t{\n\t\t\tname: \"relative max size\",\n\t\t\tps: &block.PartitionSpec{\n\t\t\t\tRelativeMaxSize: 50,\n\t\t\t},\n\t\t\tavailable: 100,\n\t\t\twant:      50,\n\t\t},\n\t\t{\n\t\t\tname: \"negative absolute max size\",\n\t\t\tps: &block.PartitionSpec{\n\t\t\t\tMaxSize:         20,\n\t\t\t\tNegativeMaxSize: true,\n\t\t\t},\n\t\t\tavailable: 100,\n\t\t\twant:      80,\n\t\t},\n\t\t{\n\t\t\tname: \"negative relative max size\",\n\t\t\tps: &block.PartitionSpec{\n\t\t\t\tRelativeMaxSize: 25,\n\t\t\t\tNegativeMaxSize: true,\n\t\t\t},\n\t\t\tavailable: 200,\n\t\t\twant:      150,\n\t\t},\n\t\t{\n\t\t\tname:      \"zero sizes\",\n\t\t\tps:        &block.PartitionSpec{},\n\t\t\tavailable: 100,\n\t\t\twant:      0,\n\t\t},\n\t\t{\n\t\t\tname: \"negative absolute max size > available\",\n\t\t\tps: &block.PartitionSpec{\n\t\t\t\tMaxSize:         2500,\n\t\t\t\tNegativeMaxSize: true,\n\t\t\t},\n\t\t\tavailable: 200,\n\t\t\terr:       \"partition size cannot be negative\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tactual, err := tt.ps.ResolveMaxSize(tt.available)\n\t\t\tassert.Equal(t, tt.want, actual)\n\n\t\t\tif tt.err != \"\" {\n\t\t\t\tassert.EqualError(t, err, tt.err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_lifecycle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// VolumeLifecycleType is type of VolumeLifecycle resource.\nconst VolumeLifecycleType = resource.Type(\"VolumeLifecycles.block.talos.dev\")\n\n// VolumeLifecycleID is the singleton ID of the resource.\nconst VolumeLifecycleID = resource.ID(\"volumes\")\n\n// VolumeLifecycle resource exists to signal that the volumes are to be closed.\n//\n// Volume manager controller puts a finalizer on this resource, and when\n// this resource is being torn down, it will close all the volumes, and release the finalizer.\ntype VolumeLifecycle = typed.Resource[VolumeLifecycleSpec, VolumeLifecycleExtension]\n\n// VolumeLifecycleSpec is empty.\ntype VolumeLifecycleSpec struct{}\n\n// NewVolumeLifecycle initializes an empty VolumeLifecycle resource.\nfunc NewVolumeLifecycle(namespace resource.Namespace, id resource.ID) *VolumeLifecycle {\n\treturn typed.NewResource[VolumeLifecycleSpec, VolumeLifecycleExtension](\n\t\tresource.NewMetadata(namespace, VolumeLifecycleType, id, resource.VersionUndefined),\n\t\tVolumeLifecycleSpec{},\n\t)\n}\n\n// VolumeLifecycleExtension provides auxiliary methods for VolumeLifecycle.\ntype VolumeLifecycleExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (VolumeLifecycleExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VolumeLifecycleType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VolumeLifecycleType, &VolumeLifecycle{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_mount_request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// VolumeMountRequestType is type of VolumeMountRequest resource.\nconst VolumeMountRequestType = resource.Type(\"VolumeMountRequests.block.talos.dev\")\n\n// VolumeMountRequest resource holds a request of a subsystem to mount some volume.\ntype VolumeMountRequest = typed.Resource[VolumeMountRequestSpec, VolumeMountRequestExtension]\n\n// VolumeMountRequestSpec is the spec for VolumeMountRequest.\n//\n//gotagsrewrite:gen\ntype VolumeMountRequestSpec struct {\n\tVolumeID string `yaml:\"volumeID\" protobuf:\"1\"`\n\n\tRequester         string `yaml:\"requester\" protobuf:\"2\"`\n\tReadOnly          bool   `yaml:\"readOnly\" protobuf:\"3\"`\n\tDetached          bool   `yaml:\"detached\" protobuf:\"4\"`\n\tDisableAccessTime bool   `yaml:\"disableAccessTime\" protobuf:\"5\"`\n\tSecure            bool   `yaml:\"secure\" protobuf:\"6\"`\n}\n\n// NewVolumeMountRequest initializes a VolumeMountRequest resource.\nfunc NewVolumeMountRequest(namespace resource.Namespace, id resource.ID) *VolumeMountRequest {\n\treturn typed.NewResource[VolumeMountRequestSpec, VolumeMountRequestExtension](\n\t\tresource.NewMetadata(namespace, VolumeMountRequestType, id, resource.VersionUndefined),\n\t\tVolumeMountRequestSpec{},\n\t)\n}\n\n// VolumeMountRequestExtension is auxiliary resource data for BlockVolumeMountRequest.\ntype VolumeMountRequestExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (VolumeMountRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VolumeMountRequestType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Volume ID\",\n\t\t\t\tJSONPath: `{.volumeID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Requester\",\n\t\t\t\tJSONPath: `{.requester}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VolumeMountRequestType, &VolumeMountRequest{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// VolumeMountStatusType is type of VolumeMountStatus resource.\nconst VolumeMountStatusType = resource.Type(\"VolumeMountStatuses.block.talos.dev\")\n\n// VolumeMountStatus resource holds a status of a subsystem to mount some volume.\ntype VolumeMountStatus = typed.Resource[VolumeMountStatusSpec, VolumeMountStatusExtension]\n\n// VolumeMountStatusSpec is the spec for VolumeMountStatus.\n//\n//gotagsrewrite:gen\ntype VolumeMountStatusSpec struct {\n\tVolumeID  string `yaml:\"volumeID\" protobuf:\"1\"`\n\tRequester string `yaml:\"requester\" protobuf:\"2\"`\n\n\tTarget            string `yaml:\"target\" protobuf:\"3\"`\n\tReadOnly          bool   `yaml:\"readOnly\" protobuf:\"4\"`\n\tDetached          bool   `yaml:\"detached\" protobuf:\"5\"`\n\tDisableAccessTime bool   `yaml:\"disableAccessTime\" protobuf:\"6\"`\n\tSecure            bool   `yaml:\"secure\" protobuf:\"7\"`\n\n\troot any\n}\n\n// SetRoot sets the XFS root for the mount.\nfunc (m *VolumeMountStatusSpec) SetRoot(root any) {\n\tm.root = root\n}\n\n// Root gets the XFS root for the mount.\n// It's not guaranteed to be set (may be nil).\nfunc (m *VolumeMountStatusSpec) Root() any {\n\treturn m.root\n}\n\n// NewVolumeMountStatus initializes a VolumeMountStatus resource.\nfunc NewVolumeMountStatus(namespace resource.Namespace, id resource.ID) *VolumeMountStatus {\n\treturn typed.NewResource[VolumeMountStatusSpec, VolumeMountStatusExtension](\n\t\tresource.NewMetadata(namespace, VolumeMountStatusType, id, resource.VersionUndefined),\n\t\tVolumeMountStatusSpec{},\n\t)\n}\n\n// VolumeMountStatusExtension is auxiliary resource data for BlockVolumeMountStatus.\ntype VolumeMountStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (VolumeMountStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VolumeMountStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Volume ID\",\n\t\t\t\tJSONPath: `{.volumeID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Requester\",\n\t\t\t\tJSONPath: `{.requester}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Target\",\n\t\t\t\tJSONPath: `{.target}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VolumeMountStatusType, &VolumeMountStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volume_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/dustin/go-humanize\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// VolumeStatusType is type of VolumeStatus resource.\nconst VolumeStatusType = resource.Type(\"VolumeStatuses.block.talos.dev\")\n\n// VolumeStatus resource contains information about the volume status.\ntype VolumeStatus = typed.Resource[VolumeStatusSpec, VolumeStatusExtension]\n\n// VolumeStatusSpec is the spec for VolumeStatus resource.\n//\n//gotagsrewrite:gen\ntype VolumeStatusSpec struct {\n\tPhase        VolumePhase `yaml:\"phase\" protobuf:\"1\"`\n\tPreFailPhase VolumePhase `yaml:\"preFailPhase,omitempty\" protobuf:\"6\"`\n\n\tType     VolumeType `yaml:\"type\" protobuf:\"16\"`\n\tParentID string     `yaml:\"parentID,omitempty\" protobuf:\"19\"`\n\n\t// Location is the path to the block device (raw).\n\tLocation string `yaml:\"location,omitempty\" protobuf:\"2\"`\n\t// MountLocation is the location to be mounted, might be different from location.\n\tMountLocation string `yaml:\"mountLocation,omitempty\" protobuf:\"11\"`\n\n\tPartitionIndex int `yaml:\"partitionIndex,omitempty\" protobuf:\"8\"`\n\n\t// ParentLocation (if present) is the location of the parent block device for partitions.\n\tParentLocation string `yaml:\"parentLocation,omitempty\" protobuf:\"7\"`\n\tUUID           string `yaml:\"uuid,omitempty\" protobuf:\"4\"`\n\tPartitionUUID  string `yaml:\"partitionUUID,omitempty\" protobuf:\"5\"`\n\tSize           uint64 `yaml:\"size,omitempty\" protobuf:\"9\"`\n\tPrettySize     string `yaml:\"prettySize,omitempty\" protobuf:\"13\"`\n\n\t// Filesystem is the filesystem type.\n\tFilesystem FilesystemType `yaml:\"filesystem,omitempty\" protobuf:\"10\"`\n\n\t// EncryptionProvider is the provider of the encryption which was used to unlock the volume.\n\tEncryptionProvider EncryptionProviderType `yaml:\"encryptionProvider,omitempty\" protobuf:\"12\"`\n\t// EncryptionFailedSyncs is the list of failed syncs for the volume (per key/provider)/\n\tEncryptionFailedSyncs []string `yaml:\"encryptionFailedSyncs,omitempty\" protobuf:\"14\"`\n\t// ConfiguredEncryptionKeys is the list of configured encryption keys for the volume.\n\tConfiguredEncryptionKeys []string `yaml:\"configuredEncryptionKeys,omitempty\" protobuf:\"17\"`\n\t// EncryptionLockedToState indicates if the encryption is locked to STATE partition\n\tEncryptionLockedToState bool `yaml:\"encryptionLockedToState,omitempty\" protobuf:\"20\"`\n\t// EncryptionSlot indicates the currently used encryption slot used for decryption.\n\tEncryptionSlot *int `yaml:\"encryptionSlot,omitempty\" protobuf:\"21\"`\n\t// TPMEncryptionOptions is the options for TPM-based encryption.\n\tTPMEncryptionOptions TPMEncryptionOptionsInfo `yaml:\"tpmEncryptionOptions,omitempty\" protobuf:\"22\"`\n\n\t// MountSpec is the mount specification.\n\tMountSpec MountSpec `yaml:\"mountSpec,omitempty\" protobuf:\"15\"`\n\n\t// Symlink is the symlink specification.\n\tSymlinkSpec SymlinkProvisioningSpec `yaml:\"symlink,omitempty\" protobuf:\"18\"`\n\n\tErrorMessage string `yaml:\"errorMessage,omitempty\" protobuf:\"3\"`\n}\n\n// TPMEncryptionOptionsInfo is the options for TPM-based encryption.\n//\n//gotagsrewrite:gen\ntype TPMEncryptionOptionsInfo struct {\n\tPCRs       []int `yaml:\"pcrs,omitempty\" protobuf:\"1\"`\n\tPubKeyPCRs []int `yaml:\"pubKeyPcrs,omitempty\" protobuf:\"2\"`\n}\n\n// SetSize sets the size of the volume status, including the pretty size.\nfunc (s *VolumeStatusSpec) SetSize(size uint64) {\n\ts.Size = size\n\ts.PrettySize = humanize.Bytes(size)\n}\n\n// NewVolumeStatus initializes a BlockVolumeStatus resource.\nfunc NewVolumeStatus(namespace resource.Namespace, id resource.ID) *VolumeStatus {\n\treturn typed.NewResource[VolumeStatusSpec, VolumeStatusExtension](\n\t\tresource.NewMetadata(namespace, VolumeStatusType, id, resource.VersionUndefined),\n\t\tVolumeStatusSpec{},\n\t)\n}\n\n// VolumeStatusExtension is auxiliary resource data for BlockVolumeStatus.\ntype VolumeStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (VolumeStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VolumeStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.type}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Phase\",\n\t\t\t\tJSONPath: `{.phase}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Location\",\n\t\t\t\tJSONPath: `{.location}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Size\",\n\t\t\t\tJSONPath: `{.prettySize}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VolumeStatusType, &VolumeStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/volumephase.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// VolumePhase describes volume phase.\ntype VolumePhase int\n\n// Volume phases.\n//\n//structprotogen:gen_enum\nconst (\n\tVolumePhaseWaiting     VolumePhase = iota // waiting\n\tVolumePhaseFailed                         // failed\n\tVolumePhaseMissing                        // missing\n\tVolumePhaseLocated                        // located\n\tVolumePhaseProvisioned                    // provisioned\n\tVolumePhasePrepared                       // prepared\n\tVolumePhaseReady                          // ready\n\tVolumePhaseClosed                         // closed\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/volumetype.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\n// VolumeType describes volume type.\ntype VolumeType int\n\n// Volume types.\n//\n//structprotogen:gen_enum\nconst (\n\tVolumeTypePartition VolumeType = iota // partition\n\tVolumeTypeDisk                        // disk\n\tVolumeTypeTmpfs                       // tmpfs\n\tVolumeTypeDirectory                   // directory\n\tVolumeTypeSymlink                     // symlink\n\tVolumeTypeOverlay                     // overlay\n\tVolumeTypeExternal                    // external\n)\n"
  },
  {
    "path": "pkg/machinery/resources/block/volumetype_enumer.go",
    "content": "// Code generated by \"enumer -type=VolumeType,VolumePhase,FilesystemType,EncryptionKeyType,EncryptionProviderType,FSParameterType -linecomment -text\"; DO NOT EDIT.\n\npackage block\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _VolumeTypeName = \"partitiondisktmpfsdirectorysymlinkoverlayexternal\"\n\nvar _VolumeTypeIndex = [...]uint8{0, 9, 13, 18, 27, 34, 41, 49}\n\nconst _VolumeTypeLowerName = \"partitiondisktmpfsdirectorysymlinkoverlayexternal\"\n\nfunc (i VolumeType) String() string {\n\tif i < 0 || i >= VolumeType(len(_VolumeTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"VolumeType(%d)\", i)\n\t}\n\treturn _VolumeTypeName[_VolumeTypeIndex[i]:_VolumeTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _VolumeTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[VolumeTypePartition-(0)]\n\t_ = x[VolumeTypeDisk-(1)]\n\t_ = x[VolumeTypeTmpfs-(2)]\n\t_ = x[VolumeTypeDirectory-(3)]\n\t_ = x[VolumeTypeSymlink-(4)]\n\t_ = x[VolumeTypeOverlay-(5)]\n\t_ = x[VolumeTypeExternal-(6)]\n}\n\nvar _VolumeTypeValues = []VolumeType{VolumeTypePartition, VolumeTypeDisk, VolumeTypeTmpfs, VolumeTypeDirectory, VolumeTypeSymlink, VolumeTypeOverlay, VolumeTypeExternal}\n\nvar _VolumeTypeNameToValueMap = map[string]VolumeType{\n\t_VolumeTypeName[0:9]:        VolumeTypePartition,\n\t_VolumeTypeLowerName[0:9]:   VolumeTypePartition,\n\t_VolumeTypeName[9:13]:       VolumeTypeDisk,\n\t_VolumeTypeLowerName[9:13]:  VolumeTypeDisk,\n\t_VolumeTypeName[13:18]:      VolumeTypeTmpfs,\n\t_VolumeTypeLowerName[13:18]: VolumeTypeTmpfs,\n\t_VolumeTypeName[18:27]:      VolumeTypeDirectory,\n\t_VolumeTypeLowerName[18:27]: VolumeTypeDirectory,\n\t_VolumeTypeName[27:34]:      VolumeTypeSymlink,\n\t_VolumeTypeLowerName[27:34]: VolumeTypeSymlink,\n\t_VolumeTypeName[34:41]:      VolumeTypeOverlay,\n\t_VolumeTypeLowerName[34:41]: VolumeTypeOverlay,\n\t_VolumeTypeName[41:49]:      VolumeTypeExternal,\n\t_VolumeTypeLowerName[41:49]: VolumeTypeExternal,\n}\n\nvar _VolumeTypeNames = []string{\n\t_VolumeTypeName[0:9],\n\t_VolumeTypeName[9:13],\n\t_VolumeTypeName[13:18],\n\t_VolumeTypeName[18:27],\n\t_VolumeTypeName[27:34],\n\t_VolumeTypeName[34:41],\n\t_VolumeTypeName[41:49],\n}\n\n// VolumeTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc VolumeTypeString(s string) (VolumeType, error) {\n\tif val, ok := _VolumeTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _VolumeTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to VolumeType values\", s)\n}\n\n// VolumeTypeValues returns all values of the enum\nfunc VolumeTypeValues() []VolumeType {\n\treturn _VolumeTypeValues\n}\n\n// VolumeTypeStrings returns a slice of all String values of the enum\nfunc VolumeTypeStrings() []string {\n\tstrs := make([]string, len(_VolumeTypeNames))\n\tcopy(strs, _VolumeTypeNames)\n\treturn strs\n}\n\n// IsAVolumeType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i VolumeType) IsAVolumeType() bool {\n\tfor _, v := range _VolumeTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for VolumeType\nfunc (i VolumeType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for VolumeType\nfunc (i *VolumeType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = VolumeTypeString(string(text))\n\treturn err\n}\n\nconst _VolumePhaseName = \"waitingfailedmissinglocatedprovisionedpreparedreadyclosed\"\n\nvar _VolumePhaseIndex = [...]uint8{0, 7, 13, 20, 27, 38, 46, 51, 57}\n\nconst _VolumePhaseLowerName = \"waitingfailedmissinglocatedprovisionedpreparedreadyclosed\"\n\nfunc (i VolumePhase) String() string {\n\tif i < 0 || i >= VolumePhase(len(_VolumePhaseIndex)-1) {\n\t\treturn fmt.Sprintf(\"VolumePhase(%d)\", i)\n\t}\n\treturn _VolumePhaseName[_VolumePhaseIndex[i]:_VolumePhaseIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _VolumePhaseNoOp() {\n\tvar x [1]struct{}\n\t_ = x[VolumePhaseWaiting-(0)]\n\t_ = x[VolumePhaseFailed-(1)]\n\t_ = x[VolumePhaseMissing-(2)]\n\t_ = x[VolumePhaseLocated-(3)]\n\t_ = x[VolumePhaseProvisioned-(4)]\n\t_ = x[VolumePhasePrepared-(5)]\n\t_ = x[VolumePhaseReady-(6)]\n\t_ = x[VolumePhaseClosed-(7)]\n}\n\nvar _VolumePhaseValues = []VolumePhase{VolumePhaseWaiting, VolumePhaseFailed, VolumePhaseMissing, VolumePhaseLocated, VolumePhaseProvisioned, VolumePhasePrepared, VolumePhaseReady, VolumePhaseClosed}\n\nvar _VolumePhaseNameToValueMap = map[string]VolumePhase{\n\t_VolumePhaseName[0:7]:        VolumePhaseWaiting,\n\t_VolumePhaseLowerName[0:7]:   VolumePhaseWaiting,\n\t_VolumePhaseName[7:13]:       VolumePhaseFailed,\n\t_VolumePhaseLowerName[7:13]:  VolumePhaseFailed,\n\t_VolumePhaseName[13:20]:      VolumePhaseMissing,\n\t_VolumePhaseLowerName[13:20]: VolumePhaseMissing,\n\t_VolumePhaseName[20:27]:      VolumePhaseLocated,\n\t_VolumePhaseLowerName[20:27]: VolumePhaseLocated,\n\t_VolumePhaseName[27:38]:      VolumePhaseProvisioned,\n\t_VolumePhaseLowerName[27:38]: VolumePhaseProvisioned,\n\t_VolumePhaseName[38:46]:      VolumePhasePrepared,\n\t_VolumePhaseLowerName[38:46]: VolumePhasePrepared,\n\t_VolumePhaseName[46:51]:      VolumePhaseReady,\n\t_VolumePhaseLowerName[46:51]: VolumePhaseReady,\n\t_VolumePhaseName[51:57]:      VolumePhaseClosed,\n\t_VolumePhaseLowerName[51:57]: VolumePhaseClosed,\n}\n\nvar _VolumePhaseNames = []string{\n\t_VolumePhaseName[0:7],\n\t_VolumePhaseName[7:13],\n\t_VolumePhaseName[13:20],\n\t_VolumePhaseName[20:27],\n\t_VolumePhaseName[27:38],\n\t_VolumePhaseName[38:46],\n\t_VolumePhaseName[46:51],\n\t_VolumePhaseName[51:57],\n}\n\n// VolumePhaseString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc VolumePhaseString(s string) (VolumePhase, error) {\n\tif val, ok := _VolumePhaseNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _VolumePhaseNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to VolumePhase values\", s)\n}\n\n// VolumePhaseValues returns all values of the enum\nfunc VolumePhaseValues() []VolumePhase {\n\treturn _VolumePhaseValues\n}\n\n// VolumePhaseStrings returns a slice of all String values of the enum\nfunc VolumePhaseStrings() []string {\n\tstrs := make([]string, len(_VolumePhaseNames))\n\tcopy(strs, _VolumePhaseNames)\n\treturn strs\n}\n\n// IsAVolumePhase returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i VolumePhase) IsAVolumePhase() bool {\n\tfor _, v := range _VolumePhaseValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for VolumePhase\nfunc (i VolumePhase) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for VolumePhase\nfunc (i *VolumePhase) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = VolumePhaseString(string(text))\n\treturn err\n}\n\nconst _FilesystemTypeName = \"nonexfsvfatext4iso9660swapivirtiofs\"\n\nvar _FilesystemTypeIndex = [...]uint8{0, 4, 7, 11, 15, 22, 27, 35}\n\nconst _FilesystemTypeLowerName = \"nonexfsvfatext4iso9660swapivirtiofs\"\n\nfunc (i FilesystemType) String() string {\n\tif i < 0 || i >= FilesystemType(len(_FilesystemTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"FilesystemType(%d)\", i)\n\t}\n\treturn _FilesystemTypeName[_FilesystemTypeIndex[i]:_FilesystemTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _FilesystemTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[FilesystemTypeNone-(0)]\n\t_ = x[FilesystemTypeXFS-(1)]\n\t_ = x[FilesystemTypeVFAT-(2)]\n\t_ = x[FilesystemTypeEXT4-(3)]\n\t_ = x[FilesystemTypeISO9660-(4)]\n\t_ = x[FilesystemTypeSwap-(5)]\n\t_ = x[FilesystemTypeVirtiofs-(6)]\n}\n\nvar _FilesystemTypeValues = []FilesystemType{FilesystemTypeNone, FilesystemTypeXFS, FilesystemTypeVFAT, FilesystemTypeEXT4, FilesystemTypeISO9660, FilesystemTypeSwap, FilesystemTypeVirtiofs}\n\nvar _FilesystemTypeNameToValueMap = map[string]FilesystemType{\n\t_FilesystemTypeName[0:4]:        FilesystemTypeNone,\n\t_FilesystemTypeLowerName[0:4]:   FilesystemTypeNone,\n\t_FilesystemTypeName[4:7]:        FilesystemTypeXFS,\n\t_FilesystemTypeLowerName[4:7]:   FilesystemTypeXFS,\n\t_FilesystemTypeName[7:11]:       FilesystemTypeVFAT,\n\t_FilesystemTypeLowerName[7:11]:  FilesystemTypeVFAT,\n\t_FilesystemTypeName[11:15]:      FilesystemTypeEXT4,\n\t_FilesystemTypeLowerName[11:15]: FilesystemTypeEXT4,\n\t_FilesystemTypeName[15:22]:      FilesystemTypeISO9660,\n\t_FilesystemTypeLowerName[15:22]: FilesystemTypeISO9660,\n\t_FilesystemTypeName[22:27]:      FilesystemTypeSwap,\n\t_FilesystemTypeLowerName[22:27]: FilesystemTypeSwap,\n\t_FilesystemTypeName[27:35]:      FilesystemTypeVirtiofs,\n\t_FilesystemTypeLowerName[27:35]: FilesystemTypeVirtiofs,\n}\n\nvar _FilesystemTypeNames = []string{\n\t_FilesystemTypeName[0:4],\n\t_FilesystemTypeName[4:7],\n\t_FilesystemTypeName[7:11],\n\t_FilesystemTypeName[11:15],\n\t_FilesystemTypeName[15:22],\n\t_FilesystemTypeName[22:27],\n\t_FilesystemTypeName[27:35],\n}\n\n// FilesystemTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc FilesystemTypeString(s string) (FilesystemType, error) {\n\tif val, ok := _FilesystemTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _FilesystemTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to FilesystemType values\", s)\n}\n\n// FilesystemTypeValues returns all values of the enum\nfunc FilesystemTypeValues() []FilesystemType {\n\treturn _FilesystemTypeValues\n}\n\n// FilesystemTypeStrings returns a slice of all String values of the enum\nfunc FilesystemTypeStrings() []string {\n\tstrs := make([]string, len(_FilesystemTypeNames))\n\tcopy(strs, _FilesystemTypeNames)\n\treturn strs\n}\n\n// IsAFilesystemType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i FilesystemType) IsAFilesystemType() bool {\n\tfor _, v := range _FilesystemTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for FilesystemType\nfunc (i FilesystemType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for FilesystemType\nfunc (i *FilesystemType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = FilesystemTypeString(string(text))\n\treturn err\n}\n\nconst _EncryptionKeyTypeName = \"staticnodeIDkmstpm\"\n\nvar _EncryptionKeyTypeIndex = [...]uint8{0, 6, 12, 15, 18}\n\nconst _EncryptionKeyTypeLowerName = \"staticnodeidkmstpm\"\n\nfunc (i EncryptionKeyType) String() string {\n\tif i < 0 || i >= EncryptionKeyType(len(_EncryptionKeyTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"EncryptionKeyType(%d)\", i)\n\t}\n\treturn _EncryptionKeyTypeName[_EncryptionKeyTypeIndex[i]:_EncryptionKeyTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _EncryptionKeyTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[EncryptionKeyStatic-(0)]\n\t_ = x[EncryptionKeyNodeID-(1)]\n\t_ = x[EncryptionKeyKMS-(2)]\n\t_ = x[EncryptionKeyTPM-(3)]\n}\n\nvar _EncryptionKeyTypeValues = []EncryptionKeyType{EncryptionKeyStatic, EncryptionKeyNodeID, EncryptionKeyKMS, EncryptionKeyTPM}\n\nvar _EncryptionKeyTypeNameToValueMap = map[string]EncryptionKeyType{\n\t_EncryptionKeyTypeName[0:6]:        EncryptionKeyStatic,\n\t_EncryptionKeyTypeLowerName[0:6]:   EncryptionKeyStatic,\n\t_EncryptionKeyTypeName[6:12]:       EncryptionKeyNodeID,\n\t_EncryptionKeyTypeLowerName[6:12]:  EncryptionKeyNodeID,\n\t_EncryptionKeyTypeName[12:15]:      EncryptionKeyKMS,\n\t_EncryptionKeyTypeLowerName[12:15]: EncryptionKeyKMS,\n\t_EncryptionKeyTypeName[15:18]:      EncryptionKeyTPM,\n\t_EncryptionKeyTypeLowerName[15:18]: EncryptionKeyTPM,\n}\n\nvar _EncryptionKeyTypeNames = []string{\n\t_EncryptionKeyTypeName[0:6],\n\t_EncryptionKeyTypeName[6:12],\n\t_EncryptionKeyTypeName[12:15],\n\t_EncryptionKeyTypeName[15:18],\n}\n\n// EncryptionKeyTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc EncryptionKeyTypeString(s string) (EncryptionKeyType, error) {\n\tif val, ok := _EncryptionKeyTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _EncryptionKeyTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to EncryptionKeyType values\", s)\n}\n\n// EncryptionKeyTypeValues returns all values of the enum\nfunc EncryptionKeyTypeValues() []EncryptionKeyType {\n\treturn _EncryptionKeyTypeValues\n}\n\n// EncryptionKeyTypeStrings returns a slice of all String values of the enum\nfunc EncryptionKeyTypeStrings() []string {\n\tstrs := make([]string, len(_EncryptionKeyTypeNames))\n\tcopy(strs, _EncryptionKeyTypeNames)\n\treturn strs\n}\n\n// IsAEncryptionKeyType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i EncryptionKeyType) IsAEncryptionKeyType() bool {\n\tfor _, v := range _EncryptionKeyTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for EncryptionKeyType\nfunc (i EncryptionKeyType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for EncryptionKeyType\nfunc (i *EncryptionKeyType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = EncryptionKeyTypeString(string(text))\n\treturn err\n}\n\nconst _EncryptionProviderTypeName = \"noneluks2\"\n\nvar _EncryptionProviderTypeIndex = [...]uint8{0, 4, 9}\n\nconst _EncryptionProviderTypeLowerName = \"noneluks2\"\n\nfunc (i EncryptionProviderType) String() string {\n\tif i < 0 || i >= EncryptionProviderType(len(_EncryptionProviderTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"EncryptionProviderType(%d)\", i)\n\t}\n\treturn _EncryptionProviderTypeName[_EncryptionProviderTypeIndex[i]:_EncryptionProviderTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _EncryptionProviderTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[EncryptionProviderNone-(0)]\n\t_ = x[EncryptionProviderLUKS2-(1)]\n}\n\nvar _EncryptionProviderTypeValues = []EncryptionProviderType{EncryptionProviderNone, EncryptionProviderLUKS2}\n\nvar _EncryptionProviderTypeNameToValueMap = map[string]EncryptionProviderType{\n\t_EncryptionProviderTypeName[0:4]:      EncryptionProviderNone,\n\t_EncryptionProviderTypeLowerName[0:4]: EncryptionProviderNone,\n\t_EncryptionProviderTypeName[4:9]:      EncryptionProviderLUKS2,\n\t_EncryptionProviderTypeLowerName[4:9]: EncryptionProviderLUKS2,\n}\n\nvar _EncryptionProviderTypeNames = []string{\n\t_EncryptionProviderTypeName[0:4],\n\t_EncryptionProviderTypeName[4:9],\n}\n\n// EncryptionProviderTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc EncryptionProviderTypeString(s string) (EncryptionProviderType, error) {\n\tif val, ok := _EncryptionProviderTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _EncryptionProviderTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to EncryptionProviderType values\", s)\n}\n\n// EncryptionProviderTypeValues returns all values of the enum\nfunc EncryptionProviderTypeValues() []EncryptionProviderType {\n\treturn _EncryptionProviderTypeValues\n}\n\n// EncryptionProviderTypeStrings returns a slice of all String values of the enum\nfunc EncryptionProviderTypeStrings() []string {\n\tstrs := make([]string, len(_EncryptionProviderTypeNames))\n\tcopy(strs, _EncryptionProviderTypeNames)\n\treturn strs\n}\n\n// IsAEncryptionProviderType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i EncryptionProviderType) IsAEncryptionProviderType() bool {\n\tfor _, v := range _EncryptionProviderTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for EncryptionProviderType\nfunc (i EncryptionProviderType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for EncryptionProviderType\nfunc (i *EncryptionProviderType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = EncryptionProviderTypeString(string(text))\n\treturn err\n}\n\nconst _FSParameterTypeName = \"stringbooleanbinary\"\n\nvar _FSParameterTypeIndex = [...]uint8{0, 6, 13, 19}\n\nconst _FSParameterTypeLowerName = \"stringbooleanbinary\"\n\nfunc (i FSParameterType) String() string {\n\tif i < 0 || i >= FSParameterType(len(_FSParameterTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"FSParameterType(%d)\", i)\n\t}\n\treturn _FSParameterTypeName[_FSParameterTypeIndex[i]:_FSParameterTypeIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _FSParameterTypeNoOp() {\n\tvar x [1]struct{}\n\t_ = x[FSParameterTypeStringValue-(0)]\n\t_ = x[FSParameterTypeBooleanValue-(1)]\n\t_ = x[FSParameterTypeBinaryValue-(2)]\n}\n\nvar _FSParameterTypeValues = []FSParameterType{FSParameterTypeStringValue, FSParameterTypeBooleanValue, FSParameterTypeBinaryValue}\n\nvar _FSParameterTypeNameToValueMap = map[string]FSParameterType{\n\t_FSParameterTypeName[0:6]:        FSParameterTypeStringValue,\n\t_FSParameterTypeLowerName[0:6]:   FSParameterTypeStringValue,\n\t_FSParameterTypeName[6:13]:       FSParameterTypeBooleanValue,\n\t_FSParameterTypeLowerName[6:13]:  FSParameterTypeBooleanValue,\n\t_FSParameterTypeName[13:19]:      FSParameterTypeBinaryValue,\n\t_FSParameterTypeLowerName[13:19]: FSParameterTypeBinaryValue,\n}\n\nvar _FSParameterTypeNames = []string{\n\t_FSParameterTypeName[0:6],\n\t_FSParameterTypeName[6:13],\n\t_FSParameterTypeName[13:19],\n}\n\n// FSParameterTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc FSParameterTypeString(s string) (FSParameterType, error) {\n\tif val, ok := _FSParameterTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _FSParameterTypeNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to FSParameterType values\", s)\n}\n\n// FSParameterTypeValues returns all values of the enum\nfunc FSParameterTypeValues() []FSParameterType {\n\treturn _FSParameterTypeValues\n}\n\n// FSParameterTypeStrings returns a slice of all String values of the enum\nfunc FSParameterTypeStrings() []string {\n\tstrs := make([]string, len(_FSParameterTypeNames))\n\tcopy(strs, _FSParameterTypeNames)\n\treturn strs\n}\n\n// IsAFSParameterType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i FSParameterType) IsAFSParameterType() bool {\n\tfor _, v := range _FSParameterTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for FSParameterType\nfunc (i FSParameterType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for FSParameterType\nfunc (i *FSParameterType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = FSParameterTypeString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/block/zswap_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage block\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ZswapStatusType is type of ZswapStatus resource.\nconst ZswapStatusType = resource.Type(\"ZswapStatuses.block.talos.dev\")\n\n// ZswapStatus resource holds status of zwap subsystem.\ntype ZswapStatus = typed.Resource[ZswapStatusSpec, ZswapStatusExtension]\n\n// ZswapStatusID is the ID of the singleton ZswapStatus resource.\nconst ZswapStatusID resource.ID = \"zswap\"\n\n// ZswapStatusSpec is the spec for ZswapStatus resource.\n//\n//gotagsrewrite:gen\ntype ZswapStatusSpec struct {\n\tTotalSizeBytes      uint64 `yaml:\"totalSize\" protobuf:\"1\"`\n\tTotalSizeHuman      string `yaml:\"totalSizeHuman\" protobuf:\"2\"`\n\tStoredPages         uint64 `yaml:\"storedPages\" protobuf:\"3\"`\n\tPoolLimitHit        uint64 `yaml:\"poolLimitHit\" protobuf:\"4\"`\n\tRejectReclaimFail   uint64 `yaml:\"rejectReclaimFail\" protobuf:\"5\"`\n\tRejectAllocFail     uint64 `yaml:\"rejectAllocFail\" protobuf:\"6\"`\n\tRejectKmemcacheFail uint64 `yaml:\"rejectKmemcacheFail\" protobuf:\"7\"`\n\tRejectCompressFail  uint64 `yaml:\"rejectCompressFail\" protobuf:\"8\"`\n\tRejectCompressPoor  uint64 `yaml:\"rejectCompressPoor\" protobuf:\"9\"`\n\tWrittenBackPages    uint64 `yaml:\"writtenBackPages\" protobuf:\"10\"`\n}\n\n// NewZswapStatus initializes a ZswapStatus resource.\nfunc NewZswapStatus(namespace resource.Namespace, id resource.ID) *ZswapStatus {\n\treturn typed.NewResource[ZswapStatusSpec, ZswapStatusExtension](\n\t\tresource.NewMetadata(namespace, ZswapStatusType, id, resource.VersionUndefined),\n\t\tZswapStatusSpec{},\n\t)\n}\n\n// ZswapStatusExtension is auxiliary resource data for ZswapStatus.\ntype ZswapStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ZswapStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ZswapStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Total Size\",\n\t\t\t\tJSONPath: \"{.totalSizeHuman}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Stored Pages\",\n\t\t\t\tJSONPath: \"{.storedPages}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Written Back\",\n\t\t\t\tJSONPath: \"{.writtenBackPages}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Pool Limit Hit\",\n\t\t\t\tJSONPath: \"{.poolLimitHit}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(ZswapStatusType, &ZswapStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/affiliate.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/gen/value\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type AffiliateSpec -type ConfigSpec -type IdentitySpec -type MemberSpec -type InfoSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// AffiliateType is type of Affiliate resource.\nconst AffiliateType = resource.Type(\"Affiliates.cluster.talos.dev\")\n\n// Affiliate resource holds information about cluster affiliate: it is discovered potential cluster member and/or KubeSpan peer.\n//\n// Controller builds local Affiliate structure for the node itself, other Affiliates are pulled from the registry during the discovery process.\ntype Affiliate = typed.Resource[AffiliateSpec, AffiliateExtension]\n\n// KubeSpanAffiliateSpec describes additional information specific for the KubeSpan.\n//\n//gotagsrewrite:gen\ntype KubeSpanAffiliateSpec struct {\n\tPublicKey                 string           `yaml:\"publicKey\" protobuf:\"1\"`\n\tAddress                   netip.Addr       `yaml:\"address\" protobuf:\"2\"`\n\tAdditionalAddresses       []netip.Prefix   `yaml:\"additionalAddresses\" protobuf:\"3\"`\n\tEndpoints                 []netip.AddrPort `yaml:\"endpoints\" protobuf:\"4\"`\n\tExcludeAdvertisedNetworks []netip.Prefix   `yaml:\"excludeAdvertisedNetworks\" protobuf:\"5\"`\n}\n\n// NewAffiliate initializes the Affiliate resource.\nfunc NewAffiliate(namespace resource.Namespace, id resource.ID) *Affiliate {\n\treturn typed.NewResource[AffiliateSpec, AffiliateExtension](\n\t\tresource.NewMetadata(namespace, AffiliateType, id, resource.VersionUndefined),\n\t\tAffiliateSpec{},\n\t)\n}\n\n// AffiliateExtension provides auxiliary methods for Affiliate.\ntype AffiliateExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (r AffiliateExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AffiliateType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Hostname\",\n\t\t\t\tJSONPath: `{.hostname}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Machine Type\",\n\t\t\t\tJSONPath: `{.machineType}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Addresses\",\n\t\t\t\tJSONPath: `{.addresses}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// AffiliateSpec describes Affiliate state.\n//\n//gotagsrewrite:gen\ntype AffiliateSpec struct {\n\tNodeID          string                `yaml:\"nodeId\" protobuf:\"1\"`\n\tAddresses       []netip.Addr          `yaml:\"addresses\" protobuf:\"2\"`\n\tHostname        string                `yaml:\"hostname\" protobuf:\"3\"`\n\tNodename        string                `yaml:\"nodename,omitempty\" protobuf:\"4\"`\n\tOperatingSystem string                `yaml:\"operatingSystem\" protobuf:\"5\"`\n\tMachineType     machine.Type          `yaml:\"machineType\" protobuf:\"6\"`\n\tKubeSpan        KubeSpanAffiliateSpec `yaml:\"kubespan,omitempty\" protobuf:\"7\"`\n\tControlPlane    *ControlPlane         `yaml:\"controlPlane,omitempty\" protobuf:\"8\"`\n}\n\n// ControlPlane describes ControlPlane data if any.\n//\n//gotagsrewrite:gen\ntype ControlPlane struct {\n\tAPIServerPort int `yaml:\"port\" protobuf:\"1\"`\n}\n\n// Merge two AffiliateSpecs.\n//\n//nolint:gocyclo\nfunc (spec *AffiliateSpec) Merge(other *AffiliateSpec) {\n\tfor _, addr := range other.Addresses {\n\t\tfound := slices.Contains(spec.Addresses, addr)\n\n\t\tif !found {\n\t\t\tspec.Addresses = append(spec.Addresses, addr)\n\t\t}\n\t}\n\n\tif other.ControlPlane != nil {\n\t\tspec.ControlPlane = other.ControlPlane\n\t}\n\n\tif other.Hostname != \"\" {\n\t\tspec.Hostname = other.Hostname\n\t}\n\n\tif other.Nodename != \"\" {\n\t\tspec.Nodename = other.Nodename\n\t}\n\n\tif other.MachineType != machine.TypeUnknown {\n\t\tspec.MachineType = other.MachineType\n\t}\n\n\tif other.KubeSpan.PublicKey != \"\" {\n\t\tspec.KubeSpan.PublicKey = other.KubeSpan.PublicKey\n\t}\n\n\tif !value.IsZero(other.KubeSpan.Address) {\n\t\tspec.KubeSpan.Address = other.KubeSpan.Address\n\t}\n\n\tfor _, addr := range other.KubeSpan.AdditionalAddresses {\n\t\tfound := slices.Contains(spec.KubeSpan.AdditionalAddresses, addr)\n\n\t\tif !found {\n\t\t\tspec.KubeSpan.AdditionalAddresses = append(spec.KubeSpan.AdditionalAddresses, addr)\n\t\t}\n\t}\n\n\tfor _, filter := range other.KubeSpan.ExcludeAdvertisedNetworks {\n\t\tfound := slices.Contains(spec.KubeSpan.ExcludeAdvertisedNetworks, filter)\n\n\t\tif !found {\n\t\t\tspec.KubeSpan.ExcludeAdvertisedNetworks = append(spec.KubeSpan.ExcludeAdvertisedNetworks, filter)\n\t\t}\n\t}\n\n\tfor _, addr := range other.KubeSpan.Endpoints {\n\t\tfound := slices.Contains(spec.KubeSpan.Endpoints, addr)\n\n\t\tif !found {\n\t\t\tspec.KubeSpan.Endpoints = append(spec.KubeSpan.Endpoints, addr)\n\t\t}\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AffiliateSpec](AffiliateType, &Affiliate{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/affiliate_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/protoenc\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tcluster2 \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc TestAffiliateSpec_Merge(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname           string\n\t\ta, b, expected cluster.AffiliateSpec\n\t}{\n\t\t{\n\t\t\tname: \"zero\",\n\t\t},\n\t\t{\n\t\t\tname: \"merge kubespan\",\n\t\t\ta: cluster.AffiliateSpec{\n\t\t\t\tHostname:     \"foo.com\",\n\t\t\t\tNodename:     \"bar\",\n\t\t\t\tMachineType:  machine.TypeControlPlane,\n\t\t\t\tAddresses:    []netip.Addr{netip.MustParseAddr(\"10.0.0.2\")},\n\t\t\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t\t\t},\n\t\t\tb: cluster.AffiliateSpec{\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"2007::/64\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: cluster.AffiliateSpec{\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"2007::/64\")},\n\t\t\t\t},\n\t\t\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"merge mixed\",\n\t\t\ta: cluster.AffiliateSpec{\n\t\t\t\tAddresses: []netip.Addr{netip.MustParseAddr(\"10.0.0.2\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\"), netip.MustParsePrefix(\"2007::/64\")},\n\t\t\t\t},\n\t\t\t},\n\t\t\tb: cluster.AffiliateSpec{\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"10.0.0.2:51820\"), netip.MustParseAddrPort(\"192.168.3.4:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"2007::/64\")},\n\t\t\t\t},\n\t\t\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t\t\t},\n\t\t\texpected: cluster.AffiliateSpec{\n\t\t\t\tHostname:    \"foo.com\",\n\t\t\t\tNodename:    \"bar\",\n\t\t\t\tMachineType: machine.TypeControlPlane,\n\t\t\t\tAddresses:   []netip.Addr{netip.MustParseAddr(\"10.0.0.2\"), netip.MustParseAddr(\"192.168.3.4\")},\n\t\t\t\tKubeSpan: cluster.KubeSpanAffiliateSpec{\n\t\t\t\t\tPublicKey:                 \"PLPNBddmTgHJhtw0vxltq1ZBdPP9RNOEUd5JjJZzBRY=\",\n\t\t\t\t\tAddress:                   netip.MustParseAddr(\"fd50:8d60:4238:6302:f857:23ff:fe21:d1e0\"),\n\t\t\t\t\tAdditionalAddresses:       []netip.Prefix{netip.MustParsePrefix(\"10.244.3.1/24\")},\n\t\t\t\t\tEndpoints:                 []netip.AddrPort{netip.MustParseAddrPort(\"192.168.3.4:51820\"), netip.MustParseAddrPort(\"10.0.0.2:51820\")},\n\t\t\t\t\tExcludeAdvertisedNetworks: []netip.Prefix{netip.MustParsePrefix(\"0.0.0.0/0\"), netip.MustParsePrefix(\"2007::/64\")},\n\t\t\t\t},\n\t\t\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tspec := tt.a\n\t\t\tspec.Merge(&tt.b)\n\n\t\t\tassert.Equal(t, tt.expected, spec)\n\t\t})\n\t}\n}\n\nfunc TestAffiliateSpecMarshal(t *testing.T) {\n\toriginal := &cluster.AffiliateSpec{\n\t\tNodeID:       \"myNodeID\",\n\t\tHostname:     \"foo.com\",\n\t\tMachineType:  machine.TypeControlPlane,\n\t\tControlPlane: &cluster.ControlPlane{APIServerPort: 6443},\n\t}\n\n\twire, err := protoenc.Marshal(original)\n\trequire.NoError(t, err)\n\n\tvar unmarshaled cluster2.AffiliateSpec\n\n\terr = proto.Unmarshal(wire, &unmarshaled)\n\trequire.NoError(t, err)\n\n\trequire.EqualValues(t, original.NodeID, unmarshaled.NodeId)\n\trequire.EqualValues(t, original.Hostname, unmarshaled.Hostname)\n\trequire.EqualValues(t, original.MachineType, unmarshaled.MachineType)\n\trequire.EqualValues(t, original.ControlPlane.APIServerPort, unmarshaled.ControlPlane.ApiServerPort)\n\n\tunmarshaled.ControlPlane = nil\n\n\twire, err = proto.Marshal(&unmarshaled)\n\trequire.NoError(t, err)\n\n\tspec := &cluster.AffiliateSpec{}\n\terr = protoenc.Unmarshal(wire, spec)\n\trequire.NoError(t, err)\n\n\toriginal.ControlPlane = nil\n\n\trequire.Equal(t, original, spec)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/cluster.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains resources related to cluster as a whole.\nconst NamespaceName resource.Namespace = \"cluster\"\n\n// RawNamespaceName contains raw resources which haven't gone through the merge phase yet.\nconst RawNamespaceName resource.Namespace = \"cluster-raw\"\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/cluster_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cluster\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&cluster.Affiliate{},\n\t\t&cluster.Config{},\n\t\t&cluster.Identity{},\n\t\t&cluster.Member{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// ConfigType is type of Config resource.\nconst ConfigType = resource.Type(\"DiscoveryConfigs.cluster.talos.dev\")\n\n// ConfigID the singleton config resource ID.\nconst ConfigID = resource.ID(\"cluster\")\n\n// Config resource holds KubeSpan configuration.\ntype Config = typed.Resource[ConfigSpec, ConfigExtension]\n\n// ConfigSpec describes KubeSpan configuration.\n//\n//gotagsrewrite:gen\ntype ConfigSpec struct {\n\tDiscoveryEnabled          bool   `yaml:\"discoveryEnabled\" protobuf:\"1\"`\n\tRegistryKubernetesEnabled bool   `yaml:\"registryKubernetesEnabled\" protobuf:\"2\"`\n\tRegistryServiceEnabled    bool   `yaml:\"registryServiceEnabled\" protobuf:\"3\"`\n\tServiceEndpoint           string `yaml:\"serviceEndpoint\" protobuf:\"4\"`\n\tServiceEndpointInsecure   bool   `yaml:\"serviceEndpointInsecure,omitempty\" protobuf:\"5\"`\n\tServiceEncryptionKey      []byte `yaml:\"serviceEncryptionKey\" protobuf:\"6\"`\n\tServiceClusterID          string `yaml:\"serviceClusterID\" protobuf:\"7\"`\n}\n\n// NewConfig initializes a Config resource.\nfunc NewConfig(namespace resource.Namespace, id resource.ID) *Config {\n\treturn typed.NewResource[ConfigSpec, ConfigExtension](\n\t\tresource.NewMetadata(namespace, ConfigType, id, resource.VersionUndefined),\n\t\tConfigSpec{},\n\t)\n}\n\n// ConfigExtension provides auxiliary methods for Config.\ntype ConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigSpec](ConfigType, &Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type AffiliateSpec -type ConfigSpec -type IdentitySpec -type MemberSpec -type InfoSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage cluster\n\nimport (\n\t\"net/netip\"\n)\n\n// DeepCopy generates a deep copy of AffiliateSpec.\nfunc (o AffiliateSpec) DeepCopy() AffiliateSpec {\n\tvar cp AffiliateSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]netip.Addr, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t}\n\tif o.KubeSpan.AdditionalAddresses != nil {\n\t\tcp.KubeSpan.AdditionalAddresses = make([]netip.Prefix, len(o.KubeSpan.AdditionalAddresses))\n\t\tcopy(cp.KubeSpan.AdditionalAddresses, o.KubeSpan.AdditionalAddresses)\n\t}\n\tif o.KubeSpan.Endpoints != nil {\n\t\tcp.KubeSpan.Endpoints = make([]netip.AddrPort, len(o.KubeSpan.Endpoints))\n\t\tcopy(cp.KubeSpan.Endpoints, o.KubeSpan.Endpoints)\n\t}\n\tif o.KubeSpan.ExcludeAdvertisedNetworks != nil {\n\t\tcp.KubeSpan.ExcludeAdvertisedNetworks = make([]netip.Prefix, len(o.KubeSpan.ExcludeAdvertisedNetworks))\n\t\tcopy(cp.KubeSpan.ExcludeAdvertisedNetworks, o.KubeSpan.ExcludeAdvertisedNetworks)\n\t}\n\tif o.ControlPlane != nil {\n\t\tcp.ControlPlane = new(ControlPlane)\n\t\t*cp.ControlPlane = *o.ControlPlane\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ConfigSpec.\nfunc (o ConfigSpec) DeepCopy() ConfigSpec {\n\tvar cp ConfigSpec = o\n\tif o.ServiceEncryptionKey != nil {\n\t\tcp.ServiceEncryptionKey = make([]byte, len(o.ServiceEncryptionKey))\n\t\tcopy(cp.ServiceEncryptionKey, o.ServiceEncryptionKey)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of IdentitySpec.\nfunc (o IdentitySpec) DeepCopy() IdentitySpec {\n\tvar cp IdentitySpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MemberSpec.\nfunc (o MemberSpec) DeepCopy() MemberSpec {\n\tvar cp MemberSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]netip.Addr, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t}\n\tif o.ControlPlane != nil {\n\t\tcp.ControlPlane = new(ControlPlane)\n\t\t*cp.ControlPlane = *o.ControlPlane\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of InfoSpec.\nfunc (o InfoSpec) DeepCopy() InfoSpec {\n\tvar cp InfoSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// IdentityType is type of Identity resource.\nconst IdentityType = resource.Type(\"Identities.cluster.talos.dev\")\n\n// LocalIdentity is the resource ID for the local node identity.\nconst LocalIdentity = resource.ID(\"local\")\n\n// Identity resource holds node identity (as a member of the cluster).\ntype Identity = typed.Resource[IdentitySpec, IdentityExtension]\n\n// IdentitySpec describes status of rendered secrets.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\n//\n//gotagsrewrite:gen\ntype IdentitySpec struct {\n\t// NodeID is a random value which is persisted across reboots,\n\t// but it gets reset on wipe.\n\tNodeID string `yaml:\"nodeId\" protobuf:\"1\"`\n}\n\n// NewIdentity initializes a Identity resource.\nfunc NewIdentity(namespace resource.Namespace, id resource.ID) *Identity {\n\treturn typed.NewResource[IdentitySpec, IdentityExtension](\n\t\tresource.NewMetadata(namespace, IdentityType, id, resource.VersionUndefined),\n\t\tIdentitySpec{},\n\t)\n}\n\n// IdentityExtension provides auxiliary methods for Identity.\ntype IdentityExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (IdentityExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             IdentityType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"ID\",\n\t\t\t\tJSONPath: `{.nodeId}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[IdentitySpec](IdentityType, &Identity{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/info.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// InfoType is type of Info resource.\nconst InfoType = resource.Type(\"Infos.cluster.talos.dev\")\n\n// InfoID is the resource ID for the current cluster info.\nconst InfoID = resource.ID(\"current\")\n\n// Info resource holds cluster information.\ntype Info = typed.Resource[InfoSpec, InfoExtension]\n\n// InfoSpec describes cluster information.\n//\n//gotagsrewrite:gen\ntype InfoSpec struct {\n\tClusterID   string `yaml:\"clusterId\" protobuf:\"1\"`\n\tClusterName string `yaml:\"clusterName\" protobuf:\"2\"`\n}\n\n// NewInfo initializes an Info resource.\nfunc NewInfo() *Info {\n\treturn typed.NewResource[InfoSpec, InfoExtension](\n\t\tresource.NewMetadata(NamespaceName, InfoType, InfoID, resource.VersionUndefined),\n\t\tInfoSpec{},\n\t)\n}\n\n// InfoExtension provides auxiliary methods for Info.\ntype InfoExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (InfoExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             InfoType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Cluster ID\",\n\t\t\t\tJSONPath: `{.clusterId}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Cluster Name\",\n\t\t\t\tJSONPath: `{.clusterName}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[InfoSpec](InfoType, &Info{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cluster/member.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cluster\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MemberType is type of Member resource.\nconst MemberType = resource.Type(\"Members.cluster.talos.dev\")\n\n// Member resource contains information about discovered cluster members.\n//\n// Members are usually derived from Affiliates.\ntype Member = typed.Resource[MemberSpec, MemberExtension]\n\n// MemberSpec describes Member state.\n//\n//gotagsrewrite:gen\ntype MemberSpec struct {\n\tNodeID          string        `yaml:\"nodeId\" protobuf:\"1\"`\n\tAddresses       []netip.Addr  `yaml:\"addresses\" protobuf:\"2\"`\n\tHostname        string        `yaml:\"hostname\" protobuf:\"3\"`\n\tMachineType     machine.Type  `yaml:\"machineType\" protobuf:\"4\"`\n\tOperatingSystem string        `yaml:\"operatingSystem\" protobuf:\"5\"`\n\tControlPlane    *ControlPlane `yaml:\"controlPlane,omitempty\" protobuf:\"6\"`\n}\n\n// NewMember initializes a Member resource.\nfunc NewMember(namespace resource.Namespace, id resource.ID) *Member {\n\treturn typed.NewResource[MemberSpec, MemberExtension](\n\t\tresource.NewMetadata(namespace, MemberType, id, resource.VersionUndefined),\n\t\tMemberSpec{},\n\t)\n}\n\n// MemberExtension provides auxiliary methods for Member.\ntype MemberExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (MemberExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MemberType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Hostname\",\n\t\t\t\tJSONPath: `{.hostname}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Machine Type\",\n\t\t\t\tJSONPath: `{.machineType}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"OS\",\n\t\t\t\tJSONPath: `{.operatingSystem}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Addresses\",\n\t\t\t\tJSONPath: `{.addresses}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MemberSpec](MemberType, &Member{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/config/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package config provides resources which hold Talos node configuration.\npackage config\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains configuration resources.\nconst NamespaceName resource.Namespace = \"config\"\n"
  },
  {
    "path": "pkg/machinery/resources/config/config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&config.MachineType{},\n\t\t&config.MachineConfig{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/config/machine_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\n\tconfigpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MachineConfigType is type of Service resource.\nconst MachineConfigType = resource.Type(\"MachineConfigs.config.talos.dev\")\n\n// ActiveID is the ID of active (applied to the running OS) machine configuration.\nconst ActiveID = resource.ID(\"v1alpha1\")\n\n// PersistentID is the ID of the config saved to the persistent storage.\n//\n// Note: PersistentID might be ahead of the \"current\" ID if the config was submitted in e.g. \"staged\" mode.\n// Note: PersistentID might be behind the \"current\" ID if the config was submitted in e.g. \"try\" mode.\nconst PersistentID = resource.ID(\"persistent\")\n\n// MachineConfig resource holds v1alpha Talos configuration.\ntype MachineConfig struct {\n\tmd   resource.Metadata\n\tspec *v1alpha1Spec\n}\n\ntype v1alpha1Spec struct {\n\tcfg config.Provider\n}\n\n// MarshalYAML implements yaml.Marshaler interface.\n//\n// Machine configuration in the spec is presented as raw YAML string.\nfunc (s *v1alpha1Spec) MarshalYAML() (any, error) {\n\tb, err := s.cfg.Bytes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn string(b), nil\n}\n\n// NewMachineConfig initializes a V1Alpha1 resource.\nfunc NewMachineConfig(spec config.Provider) *MachineConfig {\n\treturn NewMachineConfigWithID(spec, ActiveID)\n}\n\n// NewMachineConfigWithID initializes a MachineConfig resource.\nfunc NewMachineConfigWithID(spec config.Provider, id resource.ID) *MachineConfig {\n\tr := &MachineConfig{\n\t\tmd: resource.NewMetadata(NamespaceName, MachineConfigType, id, resource.VersionUndefined),\n\t\tspec: &v1alpha1Spec{\n\t\t\tcfg: spec,\n\t\t},\n\t}\n\n\t// set the annotation to mark that the spec is marshaled as YAML string properly\n\t// the actual annotation value does not matter, as the key right now\n\tr.Metadata().Annotations().Set(\"talos.dev/yaml-spec\", \"1\")\n\n\treturn r\n}\n\n// Metadata implements resource.Resource.\nfunc (r *MachineConfig) Metadata() *resource.Metadata {\n\treturn &r.md\n}\n\n// Spec implements resource.Resource.\nfunc (r *MachineConfig) Spec() any {\n\treturn r.spec\n}\n\n// DeepCopy implements resource.Resource.\nfunc (r *MachineConfig) DeepCopy() resource.Resource {\n\tcfgCopy := r.spec.cfg\n\n\tif !cfgCopy.Readonly() {\n\t\tcfgCopy = cfgCopy.Clone()\n\t}\n\n\treturn &MachineConfig{\n\t\tmd: r.md,\n\t\tspec: &v1alpha1Spec{\n\t\t\tcfg: cfgCopy,\n\t\t},\n\t}\n}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (r *MachineConfig) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MachineConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\n// MarshalProto implements ProtoMarshaler.\nfunc (s *v1alpha1Spec) MarshalProto() ([]byte, error) {\n\tyamlBytes, err := s.cfg.Bytes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprotoSpec := configpb.MachineConfigSpec{\n\t\tYamlMarshalled: yamlBytes,\n\t}\n\n\treturn proto.Marshal(&protoSpec)\n}\n\n// UnmarshalProto implements protobuf.ResourceUnmarshaler.\nfunc (r *MachineConfig) UnmarshalProto(md *resource.Metadata, protoBytes []byte) error {\n\tprotoSpec := configpb.MachineConfigSpec{}\n\n\tif err := proto.Unmarshal(protoBytes, &protoSpec); err != nil {\n\t\treturn err\n\t}\n\n\tcfg, err := configloader.NewFromBytes(protoSpec.YamlMarshalled)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr.md = *md\n\tr.spec = &v1alpha1Spec{\n\t\tcfg: cfg,\n\t}\n\n\treturn nil\n}\n\n// Config returns config.Config to access config fields.\nfunc (r *MachineConfig) Config() config.Config {\n\treturn r.spec.cfg\n}\n\n// Container returns config.Container to access config as a whole.\nfunc (r *MachineConfig) Container() config.Container {\n\treturn r.spec.cfg\n}\n\n// Provider returns config.Provider to access config provider.\n//\n// This method should only be used when Container() and Config() methods are not enough.\n// Config()/Container() provides better semantic split on the config access.\nfunc (r *MachineConfig) Provider() config.Provider {\n\treturn r.spec.cfg\n}\n\nfunc init() {\n\tif err := protobuf.RegisterResource(MachineConfigType, &MachineConfig{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/config/machine_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t_ \"embed\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configloader\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\nconst sampleConfig = `version: v1alpha1\npersist: true # foo\ndebug: false\nmachine:\n  type: controlplane\n`\n\n//go:embed testdata/machineconfig.yaml\nvar machineConfigYAML string\n\nfunc TestMachineConfigMarshal(t *testing.T) {\n\tcfg, err := configloader.NewFromBytes([]byte(sampleConfig))\n\trequire.NoError(t, err)\n\n\tr := config.NewMachineConfig(cfg)\n\n\tm, err := resource.MarshalYAML(r)\n\trequire.NoError(t, err)\n\n\tenc, err := yaml.Marshal(m)\n\trequire.NoError(t, err)\n\n\tenc = regexp.MustCompile(\"(created|updated): [0-9-:TZ+]+\").ReplaceAll(enc, []byte(\"$1: <redacted>\"))\n\n\tassert.Equal(t,\n\t\tmachineConfigYAML,\n\t\tstring(enc))\n}\n\nfunc TestMachineConfigProtobufMarshal(t *testing.T) {\n\tif _, offset := time.Now().Zone(); offset != 0 {\n\t\tt.Skipf(\"timezone offset is not zero: %d\", offset)\n\t}\n\n\tcfg, err := configloader.NewFromBytes([]byte(sampleConfig))\n\trequire.NoError(t, err)\n\n\tr := config.NewMachineConfig(cfg)\n\n\tprotoR, err := protobuf.FromResource(r)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := protoR.Marshal()\n\trequire.NoError(t, err)\n\n\tprotoR, err = protobuf.Unmarshal(marshaled)\n\trequire.NoError(t, err)\n\n\tr2, err := protobuf.UnmarshalResource(protoR)\n\trequire.NoError(t, err)\n\n\trequire.True(t, resource.Equal(r, r2))\n\n\tm1, err := resource.MarshalYAML(r)\n\trequire.NoError(t, err)\n\n\tyaml1, err := yaml.Marshal(m1)\n\trequire.NoError(t, err)\n\n\tm2, err := resource.MarshalYAML(r2)\n\trequire.NoError(t, err)\n\n\tyaml2, err := yaml.Marshal(m2)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, string(yaml1), string(yaml2))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/config/machine_type.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\n\tconfigpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MachineTypeType is type of MachineType resource.\nconst MachineTypeType = resource.Type(\"MachineTypes.config.talos.dev\")\n\n// MachineTypeID is singleton resource ID.\nconst MachineTypeID = resource.ID(\"machine-type\")\n\n// MachineType describes machine type.\ntype MachineType struct {\n\tmd   resource.Metadata\n\tspec machineTypeSpec\n}\n\ntype machineTypeSpec struct {\n\tmachine.Type\n}\n\nfunc (spec machineTypeSpec) MarshalYAML() (any, error) {\n\treturn spec.Type.String(), nil\n}\n\n// NewMachineType initializes a MachineType resource.\nfunc NewMachineType() *MachineType {\n\tr := &MachineType{\n\t\tmd:   resource.NewMetadata(NamespaceName, MachineTypeType, MachineTypeID, resource.VersionUndefined),\n\t\tspec: machineTypeSpec{},\n\t}\n\n\treturn r\n}\n\n// Metadata implements resource.Resource.\nfunc (r *MachineType) Metadata() *resource.Metadata {\n\treturn &r.md\n}\n\n// Spec implements resource.Resource.\nfunc (r *MachineType) Spec() any {\n\treturn r.spec\n}\n\n// DeepCopy implements resource.Resource.\nfunc (r *MachineType) DeepCopy() resource.Resource {\n\treturn &MachineType{\n\t\tmd:   r.md,\n\t\tspec: r.spec,\n\t}\n}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (r *MachineType) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MachineTypeType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: \"{@}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// MachineType returns machine.Type.\nfunc (r *MachineType) MachineType() machine.Type {\n\treturn r.spec.Type\n}\n\n// SetMachineType sets machine.Type.\nfunc (r *MachineType) SetMachineType(typ machine.Type) {\n\tr.spec.Type = typ\n}\n\n// MarshalProto implements ProtoMarshaler.\nfunc (spec machineTypeSpec) MarshalProto() ([]byte, error) {\n\tprotoSpec := configpb.MachineTypeSpec{\n\t\tMachineType: configpb.MachineType(spec.Type),\n\t}\n\n\treturn proto.Marshal(&protoSpec)\n}\n\n// UnmarshalProto implements protobuf.ResourceUnmarshaler.\nfunc (r *MachineType) UnmarshalProto(md *resource.Metadata, protoBytes []byte) error {\n\tprotoSpec := configpb.MachineTypeSpec{}\n\n\tif err := proto.Unmarshal(protoBytes, &protoSpec); err != nil {\n\t\treturn err\n\t}\n\n\tr.md = *md\n\tr.spec = machineTypeSpec{\n\t\tType: machine.Type(protoSpec.MachineType),\n\t}\n\n\treturn nil\n}\n\nfunc init() {\n\tif err := protobuf.RegisterResource(MachineTypeType, &MachineType{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/config/machine_type_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage config_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\nfunc TestMachineTypeProtobufMarshal(t *testing.T) {\n\tr := config.NewMachineType()\n\tr.SetMachineType(machine.TypeWorker)\n\n\tprotoR, err := protobuf.FromResource(r)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := protoR.Marshal()\n\trequire.NoError(t, err)\n\n\tprotoR, err = protobuf.Unmarshal(marshaled)\n\trequire.NoError(t, err)\n\n\tr2, err := protobuf.UnmarshalResource(protoR)\n\trequire.NoError(t, err)\n\n\trequire.True(t, resource.Equal(r, r2))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/cri.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cri contains resources related to the Container Runtime Interface (CRI).\npackage cri\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\tconfig2 \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type RegistriesConfigSpec -type ImageCacheConfigSpec -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n//go:generate go tool github.com/dmarkham/enumer -type=ImageCacheStatus -type=ImageCacheCopyStatus -linecomment -text\n\n// NamespaceName contains resources related to stats.\nconst NamespaceName resource.Namespace = \"cri\"\n\n// RegistryTLSConfigExtended is an extended registry TLS config.\ntype RegistryTLSConfigExtended interface {\n\tconfig2.RegistryTLSConfig\n\tGetTLSConfig() (*tls.Config, error)\n}\n\n// Registries is the interface for accessing container registries configuration.\ntype Registries interface {\n\tMirrors() map[string]config2.RegistryMirrorConfig\n\tAuths() map[string]config2.RegistryAuthConfig\n\tTLSs() map[string]RegistryTLSConfigExtended\n}\n\n// RegistryBuilder implements image.RegistriesBuilder.\nfunc RegistryBuilder(st state.State, opts ...func(*RegistriesConfigSpec)) func(ctx context.Context) (Registries, error) {\n\treturn func(ctx context.Context) (Registries, error) {\n\t\tregs, err := safe.StateWatchFor[*RegistriesConfig](ctx, st, NewRegistriesConfig().Metadata(), state.WithEventTypes(state.Created, state.Updated))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tspec := regs.TypedSpec()\n\n\t\t// mutate the spec with the provided options\n\t\tfor _, opt := range opts {\n\t\t\topt(spec)\n\t\t}\n\n\t\treturn spec, nil\n\t}\n}\n\n// WaitForImageCache waits for the image cache config to be either disabled or ready.\nfunc WaitForImageCache(ctx context.Context, st state.State) error {\n\t_, err := st.WatchFor(ctx, NewImageCacheConfig().Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\timageCacheConfig, ok := r.(*ImageCacheConfig)\n\t\t\tif !ok {\n\t\t\t\treturn false, fmt.Errorf(\"unexpected resource type: %T\", r)\n\t\t\t}\n\n\t\t\ts := imageCacheConfig.TypedSpec().Status\n\n\t\t\treturn s == ImageCacheStatusDisabled || s == ImageCacheStatusReady, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n\n// WaitForImageCacheCopy waits for the image cache copy to be done (or skipped).\nfunc WaitForImageCacheCopy(ctx context.Context, st state.State) error {\n\t_, err := st.WatchFor(ctx, NewImageCacheConfig().Metadata(),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\timageCacheConfig, ok := r.(*ImageCacheConfig)\n\t\t\tif !ok {\n\t\t\t\treturn false, fmt.Errorf(\"unexpected resource type: %T\", r)\n\t\t\t}\n\n\t\t\ts := imageCacheConfig.TypedSpec().CopyStatus\n\n\t\t\treturn s == ImageCacheCopyStatusReady || s == ImageCacheCopyStatusSkipped, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/cri_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/cri\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&cri.ImageCacheConfig{},\n\t\t&cri.SeccompProfile{},\n\t\t&cri.RegistriesConfig{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type RegistriesConfigSpec -type ImageCacheConfigSpec -type SeccompProfileSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage cri\n\n// DeepCopy generates a deep copy of RegistriesConfigSpec.\nfunc (o RegistriesConfigSpec) DeepCopy() RegistriesConfigSpec {\n\tvar cp RegistriesConfigSpec = o\n\tif o.RegistryMirrors != nil {\n\t\tcp.RegistryMirrors = make(map[string]*RegistryMirrorConfig, len(o.RegistryMirrors))\n\t\tfor k2, v2 := range o.RegistryMirrors {\n\t\t\tvar cp_RegistryMirrors_v2 *RegistryMirrorConfig\n\t\t\tif v2 != nil {\n\t\t\t\tcp_RegistryMirrors_v2 = new(RegistryMirrorConfig)\n\t\t\t\t*cp_RegistryMirrors_v2 = *v2\n\t\t\t\tif v2.MirrorEndpoints != nil {\n\t\t\t\t\tcp_RegistryMirrors_v2.MirrorEndpoints = make([]RegistryEndpointConfig, len(v2.MirrorEndpoints))\n\t\t\t\t\tcopy(cp_RegistryMirrors_v2.MirrorEndpoints, v2.MirrorEndpoints)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcp.RegistryMirrors[k2] = cp_RegistryMirrors_v2\n\t\t}\n\t}\n\tif o.RegistryAuths != nil {\n\t\tcp.RegistryAuths = make(map[string]*RegistryAuthConfig, len(o.RegistryAuths))\n\t\tfor k2, v2 := range o.RegistryAuths {\n\t\t\tvar cp_RegistryAuths_v2 *RegistryAuthConfig\n\t\t\tif v2 != nil {\n\t\t\t\tcp_RegistryAuths_v2 = new(RegistryAuthConfig)\n\t\t\t\t*cp_RegistryAuths_v2 = *v2\n\t\t\t}\n\t\t\tcp.RegistryAuths[k2] = cp_RegistryAuths_v2\n\t\t}\n\t}\n\tif o.RegistryTLSs != nil {\n\t\tcp.RegistryTLSs = make(map[string]*RegistryTLSConfig, len(o.RegistryTLSs))\n\t\tfor k2, v2 := range o.RegistryTLSs {\n\t\t\tvar cp_RegistryTLSs_v2 *RegistryTLSConfig\n\t\t\tif v2 != nil {\n\t\t\t\tcp_RegistryTLSs_v2 = new(RegistryTLSConfig)\n\t\t\t\t*cp_RegistryTLSs_v2 = *v2\n\t\t\t\tif v2.TLSClientIdentity != nil {\n\t\t\t\t\tcp_RegistryTLSs_v2.TLSClientIdentity = v2.TLSClientIdentity.DeepCopy()\n\t\t\t\t}\n\t\t\t\tcp_RegistryTLSs_v2.TLSCA = v2.TLSCA.DeepCopy()\n\t\t\t}\n\t\t\tcp.RegistryTLSs[k2] = cp_RegistryTLSs_v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ImageCacheConfigSpec.\nfunc (o ImageCacheConfigSpec) DeepCopy() ImageCacheConfigSpec {\n\tvar cp ImageCacheConfigSpec = o\n\tif o.Roots != nil {\n\t\tcp.Roots = make([]string, len(o.Roots))\n\t\tcopy(cp.Roots, o.Roots)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SeccompProfileSpec.\nfunc (o SeccompProfileSpec) DeepCopy() SeccompProfileSpec {\n\tvar cp SeccompProfileSpec = o\n\tif o.Value != nil {\n\t\tcp.Value = make(map[string]any, len(o.Value))\n\t\tfor k2, v2 := range o.Value {\n\t\t\tcp.Value[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/image_cache_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ImageCacheConfigType is type of ImageCacheConfig resource.\nconst ImageCacheConfigType = resource.Type(\"ImageCacheConfigs.cri.talos.dev\")\n\n// ImageCacheConfig represents ImageCacheConfig typed resource.\ntype ImageCacheConfig = typed.Resource[ImageCacheConfigSpec, ImageCacheConfigExtension]\n\n// ImageCacheConfigID is the ID of the ImageCacheConfig resource.\nconst ImageCacheConfigID = \"image-cache\"\n\n// ImageCacheConfigSpec represents the ImageCacheConfig.\n//\n//gotagsrewrite:gen\ntype ImageCacheConfigSpec struct {\n\tStatus     ImageCacheStatus     `yaml:\"status\" protobuf:\"1\"`\n\tCopyStatus ImageCacheCopyStatus `yaml:\"copyStatus\" protobuf:\"3\"`\n\tRoots      []string             `yaml:\"roots\" protobuf:\"2\"`\n}\n\n// NewImageCacheConfig creates new ImageCacheConfig object.\nfunc NewImageCacheConfig() *ImageCacheConfig {\n\treturn typed.NewResource[ImageCacheConfigSpec, ImageCacheConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, ImageCacheConfigType, ImageCacheConfigID, resource.VersionUndefined),\n\t\tImageCacheConfigSpec{},\n\t)\n}\n\n// ImageCacheConfigExtension is an auxiliary type for ImageCacheConfig resource.\ntype ImageCacheConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ImageCacheConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ImageCacheConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Status\",\n\t\t\t\tJSONPath: \"{.status}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"CopyStatus\",\n\t\t\t\tJSONPath: \"{.copyStatus}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Roots\",\n\t\t\t\tJSONPath: \"{.roots}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(ImageCacheConfigType, &ImageCacheConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/imagecachecopystatus_enumer.go",
    "content": "// Code generated by \"enumer -type=ImageCacheStatus -type=ImageCacheCopyStatus -linecomment -text\"; DO NOT EDIT.\n\npackage cri\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _ImageCacheCopyStatusName = \"unknownskippedcopyingready\"\n\nvar _ImageCacheCopyStatusIndex = [...]uint8{0, 7, 14, 21, 26}\n\nconst _ImageCacheCopyStatusLowerName = \"unknownskippedcopyingready\"\n\nfunc (i ImageCacheCopyStatus) String() string {\n\tif i < 0 || i >= ImageCacheCopyStatus(len(_ImageCacheCopyStatusIndex)-1) {\n\t\treturn fmt.Sprintf(\"ImageCacheCopyStatus(%d)\", i)\n\t}\n\treturn _ImageCacheCopyStatusName[_ImageCacheCopyStatusIndex[i]:_ImageCacheCopyStatusIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ImageCacheCopyStatusNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ImageCacheCopyStatusUnknown-(0)]\n\t_ = x[ImageCacheCopyStatusSkipped-(1)]\n\t_ = x[ImageCacheCopyStatusPending-(2)]\n\t_ = x[ImageCacheCopyStatusReady-(3)]\n}\n\nvar _ImageCacheCopyStatusValues = []ImageCacheCopyStatus{ImageCacheCopyStatusUnknown, ImageCacheCopyStatusSkipped, ImageCacheCopyStatusPending, ImageCacheCopyStatusReady}\n\nvar _ImageCacheCopyStatusNameToValueMap = map[string]ImageCacheCopyStatus{\n\t_ImageCacheCopyStatusName[0:7]:        ImageCacheCopyStatusUnknown,\n\t_ImageCacheCopyStatusLowerName[0:7]:   ImageCacheCopyStatusUnknown,\n\t_ImageCacheCopyStatusName[7:14]:       ImageCacheCopyStatusSkipped,\n\t_ImageCacheCopyStatusLowerName[7:14]:  ImageCacheCopyStatusSkipped,\n\t_ImageCacheCopyStatusName[14:21]:      ImageCacheCopyStatusPending,\n\t_ImageCacheCopyStatusLowerName[14:21]: ImageCacheCopyStatusPending,\n\t_ImageCacheCopyStatusName[21:26]:      ImageCacheCopyStatusReady,\n\t_ImageCacheCopyStatusLowerName[21:26]: ImageCacheCopyStatusReady,\n}\n\nvar _ImageCacheCopyStatusNames = []string{\n\t_ImageCacheCopyStatusName[0:7],\n\t_ImageCacheCopyStatusName[7:14],\n\t_ImageCacheCopyStatusName[14:21],\n\t_ImageCacheCopyStatusName[21:26],\n}\n\n// ImageCacheCopyStatusString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ImageCacheCopyStatusString(s string) (ImageCacheCopyStatus, error) {\n\tif val, ok := _ImageCacheCopyStatusNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ImageCacheCopyStatusNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ImageCacheCopyStatus values\", s)\n}\n\n// ImageCacheCopyStatusValues returns all values of the enum\nfunc ImageCacheCopyStatusValues() []ImageCacheCopyStatus {\n\treturn _ImageCacheCopyStatusValues\n}\n\n// ImageCacheCopyStatusStrings returns a slice of all String values of the enum\nfunc ImageCacheCopyStatusStrings() []string {\n\tstrs := make([]string, len(_ImageCacheCopyStatusNames))\n\tcopy(strs, _ImageCacheCopyStatusNames)\n\treturn strs\n}\n\n// IsAImageCacheCopyStatus returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ImageCacheCopyStatus) IsAImageCacheCopyStatus() bool {\n\tfor _, v := range _ImageCacheCopyStatusValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ImageCacheCopyStatus\nfunc (i ImageCacheCopyStatus) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ImageCacheCopyStatus\nfunc (i *ImageCacheCopyStatus) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ImageCacheCopyStatusString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/imagecachestatus.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\n// ImageCacheStatus describes image cache status type.\ntype ImageCacheStatus int\n\n// ImageCacheStatus values.\n//\n//structprotogen:gen_enum\nconst (\n\tImageCacheStatusUnknown   ImageCacheStatus = iota // unknown\n\tImageCacheStatusDisabled                          // disabled\n\tImageCacheStatusPreparing                         // preparing\n\tImageCacheStatusReady                             // ready\n)\n\n// ImageCacheCopyStatus describes image cache copy status type.\ntype ImageCacheCopyStatus int\n\n// ImageCacheCopyStatus values.\n//\n//structprotogen:gen_enum\nconst (\n\tImageCacheCopyStatusUnknown ImageCacheCopyStatus = iota // unknown\n\tImageCacheCopyStatusSkipped                             // skipped\n\tImageCacheCopyStatusPending                             // copying\n\tImageCacheCopyStatusReady                               // ready\n)\n"
  },
  {
    "path": "pkg/machinery/resources/cri/imagecachestatus_enumer.go",
    "content": "// Code generated by \"enumer -type=ImageCacheStatus -linecomment -text\"; DO NOT EDIT.\n\npackage cri\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _ImageCacheStatusName = \"unknowndisabledpreparingready\"\n\nvar _ImageCacheStatusIndex = [...]uint8{0, 7, 15, 24, 29}\n\nconst _ImageCacheStatusLowerName = \"unknowndisabledpreparingready\"\n\nfunc (i ImageCacheStatus) String() string {\n\tif i < 0 || i >= ImageCacheStatus(len(_ImageCacheStatusIndex)-1) {\n\t\treturn fmt.Sprintf(\"ImageCacheStatus(%d)\", i)\n\t}\n\treturn _ImageCacheStatusName[_ImageCacheStatusIndex[i]:_ImageCacheStatusIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ImageCacheStatusNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ImageCacheStatusUnknown-(0)]\n\t_ = x[ImageCacheStatusDisabled-(1)]\n\t_ = x[ImageCacheStatusPreparing-(2)]\n\t_ = x[ImageCacheStatusReady-(3)]\n}\n\nvar _ImageCacheStatusValues = []ImageCacheStatus{ImageCacheStatusUnknown, ImageCacheStatusDisabled, ImageCacheStatusPreparing, ImageCacheStatusReady}\n\nvar _ImageCacheStatusNameToValueMap = map[string]ImageCacheStatus{\n\t_ImageCacheStatusName[0:7]:        ImageCacheStatusUnknown,\n\t_ImageCacheStatusLowerName[0:7]:   ImageCacheStatusUnknown,\n\t_ImageCacheStatusName[7:15]:       ImageCacheStatusDisabled,\n\t_ImageCacheStatusLowerName[7:15]:  ImageCacheStatusDisabled,\n\t_ImageCacheStatusName[15:24]:      ImageCacheStatusPreparing,\n\t_ImageCacheStatusLowerName[15:24]: ImageCacheStatusPreparing,\n\t_ImageCacheStatusName[24:29]:      ImageCacheStatusReady,\n\t_ImageCacheStatusLowerName[24:29]: ImageCacheStatusReady,\n}\n\nvar _ImageCacheStatusNames = []string{\n\t_ImageCacheStatusName[0:7],\n\t_ImageCacheStatusName[7:15],\n\t_ImageCacheStatusName[15:24],\n\t_ImageCacheStatusName[24:29],\n}\n\n// ImageCacheStatusString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ImageCacheStatusString(s string) (ImageCacheStatus, error) {\n\tif val, ok := _ImageCacheStatusNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ImageCacheStatusNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ImageCacheStatus values\", s)\n}\n\n// ImageCacheStatusValues returns all values of the enum\nfunc ImageCacheStatusValues() []ImageCacheStatus {\n\treturn _ImageCacheStatusValues\n}\n\n// ImageCacheStatusStrings returns a slice of all String values of the enum\nfunc ImageCacheStatusStrings() []string {\n\tstrs := make([]string, len(_ImageCacheStatusNames))\n\tcopy(strs, _ImageCacheStatusNames)\n\treturn strs\n}\n\n// IsAImageCacheStatus returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ImageCacheStatus) IsAImageCacheStatus() bool {\n\tfor _, v := range _ImageCacheStatusValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ImageCacheStatus\nfunc (i ImageCacheStatus) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ImageCacheStatus\nfunc (i *ImageCacheStatus) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ImageCacheStatusString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/registries_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"crypto/tls\"\n\tstdx509 \"crypto/x509\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\tconfig2 \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// RegistriesConfigType is type of RegistriesConfig resource.\nconst RegistriesConfigType = resource.Type(\"RegistryConfigs.cri.talos.dev\")\n\n// RegistriesConfigID is the singleton resource ID.\nconst RegistriesConfigID resource.ID = \"registries\"\n\n// RegistriesConfig resource holds info about container registries.\ntype RegistriesConfig = typed.Resource[RegistriesConfigSpec, RegistriesConfigExtension]\n\n// RegistriesConfigSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype RegistriesConfigSpec struct {\n\tRegistryMirrors map[string]*RegistryMirrorConfig `yaml:\"mirrors,omitempty\" protobuf:\"1\"`\n\tRegistryAuths   map[string]*RegistryAuthConfig   `yaml:\"auths,omitempty\" protobuf:\"2\"`\n\tRegistryTLSs    map[string]*RegistryTLSConfig    `yaml:\"tls,omitempty\" protobuf:\"3\"`\n}\n\n// Mirrors implements the Registries interface.\nfunc (r RegistriesConfigSpec) Mirrors() map[string]config2.RegistryMirrorConfig {\n\tmirrors := make(map[string]config2.RegistryMirrorConfig, len(r.RegistryMirrors))\n\n\tfor k, v := range r.RegistryMirrors {\n\t\tmirrors[k] = v\n\t}\n\n\treturn mirrors\n}\n\n// Auths implements the Registries interface.\nfunc (r RegistriesConfigSpec) Auths() map[string]config2.RegistryAuthConfig {\n\tauths := make(map[string]config2.RegistryAuthConfig, len(r.RegistryAuths))\n\n\tfor k, v := range r.RegistryAuths {\n\t\tauths[k] = v\n\t}\n\n\treturn auths\n}\n\n// TLSs implements the Registries interface.\nfunc (r RegistriesConfigSpec) TLSs() map[string]RegistryTLSConfigExtended {\n\ttlss := make(map[string]RegistryTLSConfigExtended, len(r.RegistryTLSs))\n\n\tfor k, v := range r.RegistryTLSs {\n\t\ttlss[k] = v\n\t}\n\n\treturn tlss\n}\n\n// RegistryMirrorConfig represents mirror configuration for a registry.\n//\n//gotagsrewrite:gen\ntype RegistryMirrorConfig struct {\n\tMirrorEndpoints    []RegistryEndpointConfig `yaml:\"endpoints\" protobuf:\"1\"`\n\tMirrorSkipFallback bool                     `yaml:\"skipFallback,omitempty\" protobuf:\"3\"`\n}\n\n// SkipFallback implements the Registries interface.\nfunc (r *RegistryMirrorConfig) SkipFallback() bool {\n\treturn r.MirrorSkipFallback\n}\n\n// Endpoints implements the Registries interface.\nfunc (r *RegistryMirrorConfig) Endpoints() []config2.RegistryEndpointConfig {\n\treturn xslices.Map(r.MirrorEndpoints, func(endpoint RegistryEndpointConfig) config2.RegistryEndpointConfig {\n\t\treturn endpoint\n\t})\n}\n\n// RegistryEndpointConfig represents a single registry endpoint.\n//\n//gotagsrewrite:gen\ntype RegistryEndpointConfig struct {\n\tEndpointEndpoint     string `yaml:\"endpoint\" protobuf:\"1\"`\n\tEndpointOverridePath bool   `yaml:\"overridePath\" protobuf:\"2\"`\n}\n\n// Endpoint implements the Registries interface.\nfunc (r RegistryEndpointConfig) Endpoint() string {\n\treturn r.EndpointEndpoint\n}\n\n// OverridePath implements the Registries interface.\nfunc (r RegistryEndpointConfig) OverridePath() bool {\n\treturn r.EndpointOverridePath\n}\n\n// RegistryAuthConfig specifies authentication configuration for a registry.\n//\n//gotagsrewrite:gen\ntype RegistryAuthConfig struct {\n\tRegistryUsername      string `yaml:\"username,omitempty\" protobuf:\"1\"`\n\tRegistryPassword      string `yaml:\"password,omitempty\" protobuf:\"2\"`\n\tRegistryAuth          string `yaml:\"auth,omitempty\" protobuf:\"3\"`\n\tRegistryIdentityToken string `yaml:\"identityToken,omitempty\" protobuf:\"4\"`\n}\n\n// Username implements the Registries interface.\nfunc (r *RegistryAuthConfig) Username() string {\n\treturn r.RegistryUsername\n}\n\n// Password implements the Registries interface.\nfunc (r *RegistryAuthConfig) Password() string {\n\treturn r.RegistryPassword\n}\n\n// Auth implements the Registries interface.\nfunc (r *RegistryAuthConfig) Auth() string {\n\treturn r.RegistryAuth\n}\n\n// IdentityToken implements the Registries interface.\nfunc (r *RegistryAuthConfig) IdentityToken() string {\n\treturn r.RegistryIdentityToken\n}\n\n// RegistryTLSConfig specifies TLS config for HTTPS registries.\n//\n//gotagsrewrite:gen\ntype RegistryTLSConfig struct {\n\tTLSClientIdentity     *x509.PEMEncodedCertificateAndKey `yaml:\"clientIdentity,omitempty\" protobuf:\"1\"`\n\tTLSCA                 v1alpha1.Base64Bytes              `yaml:\"ca,omitempty\" protobuf:\"2\"`\n\tTLSInsecureSkipVerify bool                              `yaml:\"insecureSkipVerify,omitempty\" protobuf:\"3\"`\n}\n\n// ClientIdentity implements the Registries interface.\nfunc (r *RegistryTLSConfig) ClientIdentity() *x509.PEMEncodedCertificateAndKey {\n\treturn r.TLSClientIdentity\n}\n\n// CA implements the Registries interface.\nfunc (r *RegistryTLSConfig) CA() []byte {\n\treturn r.TLSCA\n}\n\n// InsecureSkipVerify implements the Registries interface.\nfunc (r *RegistryTLSConfig) InsecureSkipVerify() bool {\n\treturn r.TLSInsecureSkipVerify\n}\n\n// GetTLSConfig prepares TLS configuration for connection.\nfunc (r *RegistryTLSConfig) GetTLSConfig() (*tls.Config, error) {\n\ttlsConfig := &tls.Config{}\n\n\tif r.TLSClientIdentity != nil {\n\t\tcert, err := tls.X509KeyPair(r.TLSClientIdentity.Crt, r.TLSClientIdentity.Key)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing client identity: %w\", err)\n\t\t}\n\n\t\ttlsConfig.Certificates = []tls.Certificate{cert}\n\t}\n\n\tif r.CA() != nil {\n\t\ttlsConfig.RootCAs = stdx509.NewCertPool()\n\t\ttlsConfig.RootCAs.AppendCertsFromPEM(r.TLSCA)\n\t}\n\n\tif r.InsecureSkipVerify() {\n\t\ttlsConfig.InsecureSkipVerify = true\n\t}\n\n\treturn tlsConfig, nil\n}\n\n// NewRegistriesConfig initializes a RegistriesConfig resource.\nfunc NewRegistriesConfig() *RegistriesConfig {\n\treturn typed.NewResource[RegistriesConfigSpec, RegistriesConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, RegistriesConfigType, RegistriesConfigID, resource.VersionUndefined),\n\t\tRegistriesConfigSpec{},\n\t)\n}\n\n// RegistriesConfigExtension provides auxiliary methods for RegistriesConfig.\ntype RegistriesConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (RegistriesConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             RegistriesConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(RegistriesConfigType, &RegistriesConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/cri/seccomp_profile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage cri\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SeccompProfileType is type of SeccompProfile resource.\nconst SeccompProfileType = resource.Type(\"SeccompProfiles.cri.talos.dev\")\n\n// SeccompProfile represents SeccompProfile typed resource.\ntype SeccompProfile = typed.Resource[SeccompProfileSpec, SeccompProfileExtension]\n\n// SeccompProfileSpec represents the SeccompProfile.\n//\n//gotagsrewrite:gen\ntype SeccompProfileSpec struct {\n\tName  string         `yaml:\"name\" protobuf:\"1\"`\n\tValue map[string]any `yaml:\"value\" protobuf:\"2\"`\n}\n\n// NewSeccompProfile creates new SeccompProfile object.\nfunc NewSeccompProfile(id string) *SeccompProfile {\n\treturn typed.NewResource[SeccompProfileSpec, SeccompProfileExtension](\n\t\tresource.NewMetadata(NamespaceName, SeccompProfileType, id, resource.VersionUndefined),\n\t\tSeccompProfileSpec{},\n\t)\n}\n\n// SeccompProfileExtension is an auxiliary type for SeccompProfile resource.\ntype SeccompProfileExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (SeccompProfileExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SeccompProfileType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(SeccompProfileType, &SeccompProfile{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/condition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n)\n\n// SpecReadyCondition implements condition which waits for the etcd spec to be ready.\ntype SpecReadyCondition struct {\n\tstate state.State\n}\n\n// NewSpecReadyCondition builds a condition which waits for the etcd spec to be ready.\nfunc NewSpecReadyCondition(state state.State) *SpecReadyCondition {\n\treturn &SpecReadyCondition{\n\t\tstate: state,\n\t}\n}\n\nfunc (condition *SpecReadyCondition) String() string {\n\treturn \"etcd spec\"\n}\n\n// Wait implements condition interface.\nfunc (condition *SpecReadyCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, SpecType, SpecID, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ConfigType is type of Config resource.\nconst ConfigType = resource.Type(\"EtcdConfigs.etcd.talos.dev\")\n\n// ConfigID is resource ID for Config resource for etcd.\nconst ConfigID = resource.ID(\"etcd\")\n\n// Config resource holds status of rendered secrets.\ntype Config = typed.Resource[ConfigSpec, ConfigExtension]\n\n// ConfigSpec describes (some) configuration settings of etcd.\n//\n//gotagsrewrite:gen\ntype ConfigSpec struct {\n\tAdvertiseValidSubnets   []string `yaml:\"advertiseValidSubnets,omitempty\" protobuf:\"1\"`\n\tAdvertiseExcludeSubnets []string `yaml:\"advertiseExcludeSubnets\" protobuf:\"2\"`\n\n\tListenValidSubnets   []string `yaml:\"listenValidSubnets,omitempty\" protobuf:\"5\"`\n\tListenExcludeSubnets []string `yaml:\"listenExcludeSubnets\" protobuf:\"6\"`\n\n\tImage string `yaml:\"image\" protobuf:\"3\"`\n\n\tExtraArgs map[string]ArgValues `yaml:\"extraArgs\" protobuf:\"4\"`\n}\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\n//\n//gotagsrewrite:gen\ntype ArgValues struct {\n\tValues []string `yaml:\"values\" protobuf:\"1\"`\n}\n\n// NewConfig initializes a Config resource.\nfunc NewConfig(namespace resource.Namespace, id resource.ID) *Config {\n\treturn typed.NewResource[ConfigSpec, ConfigExtension](\n\t\tresource.NewMetadata(namespace, ConfigType, id, resource.VersionUndefined),\n\t\tConfigSpec{},\n\t)\n}\n\n// ConfigExtension provides auxiliary methods for Config.\ntype ConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Image\",\n\t\t\t\tJSONPath: \"{.image}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigSpec](ConfigType, &Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ConfigSpec -type PKIStatusSpec -type SpecSpec -type MemberSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage etcd\n\nimport (\n\t\"net/netip\"\n)\n\n// DeepCopy generates a deep copy of ConfigSpec.\nfunc (o ConfigSpec) DeepCopy() ConfigSpec {\n\tvar cp ConfigSpec = o\n\tif o.AdvertiseValidSubnets != nil {\n\t\tcp.AdvertiseValidSubnets = make([]string, len(o.AdvertiseValidSubnets))\n\t\tcopy(cp.AdvertiseValidSubnets, o.AdvertiseValidSubnets)\n\t}\n\tif o.AdvertiseExcludeSubnets != nil {\n\t\tcp.AdvertiseExcludeSubnets = make([]string, len(o.AdvertiseExcludeSubnets))\n\t\tcopy(cp.AdvertiseExcludeSubnets, o.AdvertiseExcludeSubnets)\n\t}\n\tif o.ListenValidSubnets != nil {\n\t\tcp.ListenValidSubnets = make([]string, len(o.ListenValidSubnets))\n\t\tcopy(cp.ListenValidSubnets, o.ListenValidSubnets)\n\t}\n\tif o.ListenExcludeSubnets != nil {\n\t\tcp.ListenExcludeSubnets = make([]string, len(o.ListenExcludeSubnets))\n\t\tcopy(cp.ListenExcludeSubnets, o.ListenExcludeSubnets)\n\t}\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PKIStatusSpec.\nfunc (o PKIStatusSpec) DeepCopy() PKIStatusSpec {\n\tvar cp PKIStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SpecSpec.\nfunc (o SpecSpec) DeepCopy() SpecSpec {\n\tvar cp SpecSpec = o\n\tif o.AdvertisedAddresses != nil {\n\t\tcp.AdvertisedAddresses = make([]netip.Addr, len(o.AdvertisedAddresses))\n\t\tcopy(cp.AdvertisedAddresses, o.AdvertisedAddresses)\n\t}\n\tif o.ListenPeerAddresses != nil {\n\t\tcp.ListenPeerAddresses = make([]netip.Addr, len(o.ListenPeerAddresses))\n\t\tcopy(cp.ListenPeerAddresses, o.ListenPeerAddresses)\n\t}\n\tif o.ListenClientAddresses != nil {\n\t\tcp.ListenClientAddresses = make([]netip.Addr, len(o.ListenClientAddresses))\n\t\tcopy(cp.ListenClientAddresses, o.ListenClientAddresses)\n\t}\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MemberSpec.\nfunc (o MemberSpec) DeepCopy() MemberSpec {\n\tvar cp MemberSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package etcd provides resources which interface with etcd.\npackage etcd\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ConfigSpec -type PKIStatusSpec -type SpecSpec -type MemberSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName contains resources supporting etcd service.\nconst NamespaceName resource.Namespace = \"etcd\"\n\n// FormatMemberID represents a uint64 in hexadecimal notation.\nfunc FormatMemberID(memberID uint64) string {\n\treturn fmt.Sprintf(\"%016x\", memberID)\n}\n\n// ParseMemberID converts a member ID in hexadecimal notation to a uint64.\nfunc ParseMemberID(memberID string) (uint64, error) {\n\tid, err := strconv.ParseUint(memberID, 16, 64)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"error parsing etcd member id: %w\", err)\n\t}\n\n\treturn id, nil\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/etcd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&etcd.PKIStatus{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n\nfunc TestFormatMemberID(t *testing.T) {\n\ttests := []struct {\n\t\tname string\n\t\tid   uint64\n\t\tstr  string\n\t}{\n\t\t{\n\t\t\tname: \"small id\",\n\t\t\tid:   1,\n\t\t\tstr:  \"0000000000000001\",\n\t\t},\n\t\t{\n\t\t\tname: \"big id\",\n\t\t\tid:   uint64(1) << 63,\n\t\t\tstr:  \"8000000000000000\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tassert.Equal(t, tt.str, etcd.FormatMemberID(tt.id))\n\n\t\t\tid, err := etcd.ParseMemberID(tt.str)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.id, id)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/member.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MemberType is type of Member resource.\nconst MemberType = resource.Type(\"EtcdMembers.etcd.talos.dev\")\n\n// LocalMemberID is resource ID for Member resource for etcd.\nconst LocalMemberID = resource.ID(\"local\")\n\n// Member resource holds status of rendered secrets.\ntype Member = typed.Resource[MemberSpec, MemberExtension]\n\n// MemberSpec holds information about an etcd member.\n//\n//gotagsrewrite:gen\ntype MemberSpec struct {\n\tMemberID string `yaml:\"memberID\" protobuf:\"1\"`\n}\n\n// NewMember initializes a Member resource.\nfunc NewMember(namespace resource.Namespace, id resource.ID) *Member {\n\treturn typed.NewResource[MemberSpec, MemberExtension](\n\t\tresource.NewMetadata(namespace, MemberType, id, resource.VersionUndefined),\n\t\tMemberSpec{},\n\t)\n}\n\n// MemberExtension provides auxiliary methods for Member.\ntype MemberExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (MemberExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MemberType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Member ID\",\n\t\t\t\tJSONPath: \"{.memberID}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MemberSpec](MemberType, &Member{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/pki_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PKIStatusType is type of PKIStatus resource.\nconst PKIStatusType = resource.Type(\"PKIStatuses.etcd.talos.dev\")\n\n// PKIID is resource ID for PKIStatus resource for etcd.\nconst PKIID = resource.ID(\"etcd\")\n\n// PKIStatus resource holds status of rendered secrets.\ntype PKIStatus = typed.Resource[PKIStatusSpec, PKIStatusExtension]\n\n// PKIStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype PKIStatusSpec struct {\n\tReady   bool   `yaml:\"ready\" protobuf:\"1\"`\n\tVersion string `yaml:\"version\" protobuf:\"2\"`\n}\n\n// NewPKIStatus initializes a PKIStatus resource.\nfunc NewPKIStatus(namespace resource.Namespace, id resource.ID) *PKIStatus {\n\treturn typed.NewResource[PKIStatusSpec, PKIStatusExtension](\n\t\tresource.NewMetadata(namespace, PKIStatusType, id, resource.VersionUndefined),\n\t\tPKIStatusSpec{},\n\t)\n}\n\n// PKIStatusExtension provides auxiliary methods for PKIStatus.\ntype PKIStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PKIStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PKIStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: \"{.ready}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Secrets Version\",\n\t\t\t\tJSONPath: \"{.version}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PKIStatusSpec](PKIStatusType, &PKIStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/etcd/spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage etcd\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SpecType is type of Spec resource.\nconst SpecType = resource.Type(\"EtcdSpecs.etcd.talos.dev\")\n\n// SpecID is resource ID for Spec resource for etcd.\nconst SpecID = resource.ID(\"etcd\")\n\n// Spec resource holds status of rendered secrets.\ntype Spec = typed.Resource[SpecSpec, SpecExtension]\n\n// SpecSpec describes (some) Specuration settings of etcd.\n//\n//gotagsrewrite:gen\ntype SpecSpec struct {\n\tName                  string               `yaml:\"name\" protobuf:\"1\"`\n\tAdvertisedAddresses   []netip.Addr         `yaml:\"advertisedAddresses\" protobuf:\"2\"`\n\tListenPeerAddresses   []netip.Addr         `yaml:\"listenPeerAddresses\" protobuf:\"5\"`\n\tListenClientAddresses []netip.Addr         `yaml:\"listenClientAddresses\" protobuf:\"6\"`\n\tImage                 string               `yaml:\"image\" protobuf:\"3\"`\n\tExtraArgs             map[string]ArgValues `yaml:\"extraArgs\" protobuf:\"4\"`\n}\n\n// NewSpec initializes a Spec resource.\nfunc NewSpec(namespace resource.Namespace, id resource.ID) *Spec {\n\treturn typed.NewResource[SpecSpec, SpecExtension](\n\t\tresource.NewMetadata(namespace, SpecType, id, resource.VersionUndefined),\n\t\tSpecSpec{},\n\t)\n}\n\n// SpecExtension provides auxiliary methods for Spec.\ntype SpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (SpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Name\",\n\t\t\t\tJSONPath: \"{.name}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"AdvertisedAddresses\",\n\t\t\t\tJSONPath: \"{.advertisedAddresses}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"ListenPeerAddresses\",\n\t\t\t\tJSONPath: \"{.listenPeerAddresses}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"ListenClientAddresses\",\n\t\t\t\tJSONPath: \"{.listenClientAddresses}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SpecSpec](SpecType, &Spec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/files/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type EtcFileSpecSpec -type EtcFileStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage files\n\n// DeepCopy generates a deep copy of EtcFileSpecSpec.\nfunc (o EtcFileSpecSpec) DeepCopy() EtcFileSpecSpec {\n\tvar cp EtcFileSpecSpec = o\n\tif o.Contents != nil {\n\t\tcp.Contents = make([]byte, len(o.Contents))\n\t\tcopy(cp.Contents, o.Contents)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EtcFileStatusSpec.\nfunc (o EtcFileStatusSpec) DeepCopy() EtcFileStatusSpec {\n\tvar cp EtcFileStatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/files/etcfile_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"io/fs\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/yamlutils\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type EtcFileSpecSpec -type EtcFileStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// EtcFileSpecType is type of EtcFile resource.\nconst EtcFileSpecType = resource.Type(\"EtcFileSpecs.files.talos.dev\")\n\n// EtcFileSpec resource holds contents of the file which should be put to `/etc` directory.\ntype EtcFileSpec = typed.Resource[EtcFileSpecSpec, EtcFileSpecExtension]\n\n// EtcFileSpecSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype EtcFileSpecSpec struct {\n\tContents     yamlutils.StringBytes `yaml:\"contents\" protobuf:\"1\"`\n\tMode         fs.FileMode           `yaml:\"mode\" protobuf:\"2\"`\n\tSelinuxLabel string                `yaml:\"selinux_label\" protobuf:\"3\"`\n}\n\n// NewEtcFileSpec initializes a EtcFileSpec resource.\nfunc NewEtcFileSpec(namespace resource.Namespace, id resource.ID) *EtcFileSpec {\n\treturn typed.NewResource[EtcFileSpecSpec, EtcFileSpecExtension](\n\t\tresource.NewMetadata(namespace, EtcFileSpecType, id, resource.VersionUndefined),\n\t\tEtcFileSpecSpec{},\n\t)\n}\n\n// EtcFileSpecExtension provides auxiliary methods for EtcFileSpec.\ntype EtcFileSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EtcFileSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EtcFileSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EtcFileSpecSpec](EtcFileSpecType, &EtcFileSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/files/etcfile_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EtcFileStatusType is type of EtcFile resource.\nconst EtcFileStatusType = resource.Type(\"EtcFileStatuses.files.talos.dev\")\n\n// EtcFileStatus resource holds contents of the file which should be put to `/etc` directory.\ntype EtcFileStatus = typed.Resource[EtcFileStatusSpec, EtcFileStatusMD]\n\n// EtcFileStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype EtcFileStatusSpec struct {\n\tSpecVersion string `yaml:\"specVersion\" protobuf:\"1\"`\n}\n\n// NewEtcFileStatus initializes a EtcFileStatus resource.\nfunc NewEtcFileStatus(namespace resource.Namespace, id resource.ID) *EtcFileStatus {\n\treturn typed.NewResource[EtcFileStatusSpec, EtcFileStatusMD](\n\t\tresource.NewMetadata(namespace, EtcFileStatusType, id, resource.VersionUndefined),\n\t\tEtcFileStatusSpec{},\n\t)\n}\n\n// EtcFileStatusMD provides auxiliary methods for EtcFileStatus.\ntype EtcFileStatusMD struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (EtcFileStatusMD) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EtcFileStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EtcFileStatusSpec](EtcFileStatusType, &EtcFileStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/files/files.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package files provides resources which describe files on disk.\npackage files\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains file resources.\nconst NamespaceName resource.Namespace = \"files\"\n\n// SourceFileAnnotation is used to annotate a file resource with the source file path(s).\nconst SourceFileAnnotation = \"talos.dev/source-file\"\n"
  },
  {
    "path": "pkg/machinery/resources/files/files_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage files_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/files\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&files.EtcFileSpec{},\n\t\t&files.EtcFileStatus{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type MemoryModuleSpec -type PCIDeviceSpec -type PCIDriverRebindConfigSpec -type PCIDriverRebindStatusSpec -type PCRStatusSpec -type ProcessorSpec -type SystemInformationSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage hardware\n\n// DeepCopy generates a deep copy of MemoryModuleSpec.\nfunc (o MemoryModuleSpec) DeepCopy() MemoryModuleSpec {\n\tvar cp MemoryModuleSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PCIDeviceSpec.\nfunc (o PCIDeviceSpec) DeepCopy() PCIDeviceSpec {\n\tvar cp PCIDeviceSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PCIDriverRebindConfigSpec.\nfunc (o PCIDriverRebindConfigSpec) DeepCopy() PCIDriverRebindConfigSpec {\n\tvar cp PCIDriverRebindConfigSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PCIDriverRebindStatusSpec.\nfunc (o PCIDriverRebindStatusSpec) DeepCopy() PCIDriverRebindStatusSpec {\n\tvar cp PCIDriverRebindStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PCRStatusSpec.\nfunc (o PCRStatusSpec) DeepCopy() PCRStatusSpec {\n\tvar cp PCRStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ProcessorSpec.\nfunc (o ProcessorSpec) DeepCopy() ProcessorSpec {\n\tvar cp ProcessorSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SystemInformationSpec.\nfunc (o SystemInformationSpec) DeepCopy() SystemInformationSpec {\n\tvar cp SystemInformationSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/hardware.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type MemoryModuleSpec -type PCIDeviceSpec -type PCIDriverRebindConfigSpec -type PCIDriverRebindStatusSpec -type PCRStatusSpec -type ProcessorSpec -type SystemInformationSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName contains resources related to hardware as a whole.\nconst NamespaceName resource.Namespace = \"hardware\"\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/hardware_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/hardware\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&hardware.MemoryModule{},\n\t\t&hardware.PCIDevice{},\n\t\t&hardware.PCIDriverRebindConfig{},\n\t\t&hardware.PCIDriverRebindStatus{},\n\t\t&hardware.PCRStatus{},\n\t\t&hardware.Processor{},\n\t\t&hardware.SystemInformation{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/memorymodule.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MemoryModuleType is type of MemoryModule resource.\nconst MemoryModuleType = resource.Type(\"MemoryModules.hardware.talos.dev\")\n\n// MemoryModule resource holds node MemoryModule information.\ntype MemoryModule = typed.Resource[MemoryModuleSpec, MemoryModuleExtension]\n\n// MemoryModuleSpec represents a single Memory.\n//\n//gotagsrewrite:gen\ntype MemoryModuleSpec struct {\n\tSize          uint32 `yaml:\"sizeMiB,omitempty\" protobuf:\"1\"`\n\tDeviceLocator string `yaml:\"deviceLocator,omitempty\" protobuf:\"2\"`\n\tBankLocator   string `yaml:\"bankLocator,omitempty\" protobuf:\"3\"`\n\tSpeed         uint32 `yaml:\"speed,omitempty\" protobuf:\"4\"`\n\tManufacturer  string `yaml:\"manufacturer,omitempty\" protobuf:\"5\"`\n\tSerialNumber  string `yaml:\"serialNumber,omitempty\" protobuf:\"6\"`\n\tAssetTag      string `yaml:\"assetTag,omitempty\" protobuf:\"7\"`\n\tProductName   string `yaml:\"productName,omitempty\" protobuf:\"8\"`\n}\n\n// NewMemoryModuleInfo initializes a MemoryModuleInfo resource.\nfunc NewMemoryModuleInfo(id string) *MemoryModule {\n\treturn typed.NewResource[MemoryModuleSpec, MemoryModuleExtension](\n\t\tresource.NewMetadata(NamespaceName, MemoryModuleType, id, resource.VersionUndefined),\n\t\tMemoryModuleSpec{},\n\t)\n}\n\n// MemoryModuleExtension provides auxiliary methods for Memory info.\ntype MemoryModuleExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (MemoryModuleExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType: MemoryModuleType,\n\t\tAliases: []resource.Type{\n\t\t\t\"memorymodules\",\n\t\t\t\"ram\",\n\t\t},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Manufacturer\",\n\t\t\t\tJSONPath: `{.manufacturer}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Model\",\n\t\t\t\tJSONPath: `{.productName}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"SizeMiB\",\n\t\t\t\tJSONPath: `{.sizeMiB}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MemoryModuleSpec](MemoryModuleType, &MemoryModule{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/pci_driver_rebind_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PCIDriverRebindConfigType is type of PCIDriverRebindConfig resource.\nconst PCIDriverRebindConfigType = resource.Type(\"PCIDriverRebindConfigs.runtime.talos.dev\")\n\n// PCIDriverRebindConfig resource holds PCI rebind configuration.\ntype PCIDriverRebindConfig = typed.Resource[PCIDriverRebindConfigSpec, PCIDriverRebindConfigExtension]\n\n// PCIDriverRebindConfigSpec describes PCI rebind configuration.\n//\n//gotagsrewrite:gen\ntype PCIDriverRebindConfigSpec struct {\n\tPCIID        string `yaml:\"pciID\" protobuf:\"1\"`\n\tTargetDriver string `yaml:\"targetDriver\" protobuf:\"2\"`\n}\n\n// PCIDriverRebindConfigExtension is auxiliary resource data for PCIDriverRebindConfig.\ntype PCIDriverRebindConfigExtension struct{}\n\n// NewPCIDriverRebindConfig initializes a PCIDriverRebindConfig resource.\nfunc NewPCIDriverRebindConfig(id resource.ID) *PCIDriverRebindConfig {\n\treturn typed.NewResource[PCIDriverRebindConfigSpec, PCIDriverRebindConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, PCIDriverRebindConfigType, id, resource.VersionUndefined),\n\t\tPCIDriverRebindConfigSpec{},\n\t)\n}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (PCIDriverRebindConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PCIDriverRebindConfigType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Name\",\n\t\t\t\tJSONPath: `{.name}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PCI ID\",\n\t\t\t\tJSONPath: `{.pciID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"TargetDriver\",\n\t\t\t\tJSONPath: `{.targetDriver}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PCIDriverRebindConfigSpec](PCIDriverRebindConfigType, &PCIDriverRebindConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/pci_driver_rebind_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PCIDriverRebindStatusType is the type of the PCIDriverRebindStatus resource.\nconst PCIDriverRebindStatusType = resource.Type(\"PCIDriverRebindStatuses.runtime.talos.dev\")\n\n// PCIDriverRebindStatus resource holds status of rebinded drivers.\ntype PCIDriverRebindStatus = typed.Resource[PCIDriverRebindStatusSpec, PCIDriverRebindStatusExtension]\n\n// PCIDriverRebindStatusSpec describes status of rebinded drivers.\n//\n//gotagsrewrite:gen\ntype PCIDriverRebindStatusSpec struct {\n\tPCIID        string `yaml:\"pciID\" protobuf:\"1\"`\n\tTargetDriver string `yaml:\"targetDriver\" protobuf:\"2\"`\n}\n\n// NewPCIDriverRebindStatus initializes a PCIDriverRebindStatus resource.\nfunc NewPCIDriverRebindStatus(id resource.ID) *PCIDriverRebindStatus {\n\treturn typed.NewResource[PCIDriverRebindStatusSpec, PCIDriverRebindStatusExtension](\n\t\tresource.NewMetadata(NamespaceName, PCIDriverRebindStatusType, id, resource.VersionUndefined),\n\t\tPCIDriverRebindStatusSpec{},\n\t)\n}\n\n// PCIDriverRebindStatusExtension is auxiliary resource data for PCIDriverRebindStatus.\ntype PCIDriverRebindStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (PCIDriverRebindStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PCIDriverRebindStatusType,\n\t\tAliases:          []resource.Type{\"pcidriverrebinds\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Name\",\n\t\t\t\tJSONPath: `{.name}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PCI ID\",\n\t\t\t\tJSONPath: `{.pciID}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"TargetDriver\",\n\t\t\t\tJSONPath: `{.targetDriver}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PCIDriverRebindStatusSpec](PCIDriverRebindStatusType, &PCIDriverRebindStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/pcidevice.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PCIDeviceType is type of PCIDevice resource.\nconst PCIDeviceType = resource.Type(\"PCIDevices.hardware.talos.dev\")\n\n// PCIDevice resource holds node PCIDevice information.\ntype PCIDevice = typed.Resource[PCIDeviceSpec, PCIDeviceExtension]\n\n// PCIDeviceSpec represents a single processor.\n//\n//gotagsrewrite:gen\ntype PCIDeviceSpec struct {\n\tClass    string `yaml:\"class,omitempty\" protobuf:\"1\"`\n\tSubclass string `yaml:\"subclass,omitempty\" protobuf:\"2\"`\n\tVendor   string `yaml:\"vendor,omitempty\" protobuf:\"3\"`\n\tProduct  string `yaml:\"product,omitempty\" protobuf:\"4\"`\n\n\tClassID    string `yaml:\"class_id\" protobuf:\"5\"`\n\tSubclassID string `yaml:\"subclass_id\" protobuf:\"6\"`\n\tVendorID   string `yaml:\"vendor_id\" protobuf:\"7\"`\n\tProductID  string `yaml:\"product_id\" protobuf:\"8\"`\n\tDriver     string `yaml:\"driver,omitempty\" protobuf:\"9\"`\n}\n\n// NewPCIDeviceInfo initializes a PCIDeviceInfo resource.\nfunc NewPCIDeviceInfo(id string) *PCIDevice {\n\treturn typed.NewResource[PCIDeviceSpec, PCIDeviceExtension](\n\t\tresource.NewMetadata(NamespaceName, PCIDeviceType, id, resource.VersionUndefined),\n\t\tPCIDeviceSpec{},\n\t)\n}\n\n// PCIDeviceExtension provides auxiliary methods for PCIDevice info.\ntype PCIDeviceExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PCIDeviceExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType: PCIDeviceType,\n\t\tAliases: []resource.Type{\n\t\t\t\"devices\",\n\t\t\t\"device\",\n\t\t},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Class\",\n\t\t\t\tJSONPath: `{.class}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Subclass\",\n\t\t\t\tJSONPath: `{.subclass}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Vendor\",\n\t\t\t\tJSONPath: `{.vendor}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Product\",\n\t\t\t\tJSONPath: `{.product}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(PCIDeviceType, &PCIDevice{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/pcr_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PCRStatusType is type of PCRStatus resource.\nconst PCRStatusType = resource.Type(\"PCRStatuses.hardware.talos.dev\")\n\n// PCRStatus resource holds node PCRStatus information.\ntype PCRStatus = typed.Resource[PCRStatusSpec, PCRStatusExtension]\n\n// PCRStatusSpec represents a single PCR status.\n//\n// The resource is created when the PCR is ready to be used, and\n// torn down/destroyed as the PCR value is extended to prevent it from being\n// used.\n//\n//gotagsrewrite:gen\ntype PCRStatusSpec struct{}\n\n// NewPCCRStatus initializes a PCRStatus resource.\nfunc NewPCCRStatus(pcr int) *PCRStatus {\n\treturn typed.NewResource[PCRStatusSpec, PCRStatusExtension](\n\t\tresource.NewMetadata(NamespaceName, PCRStatusType, strconv.Itoa(pcr), resource.VersionUndefined),\n\t\tPCRStatusSpec{},\n\t)\n}\n\n// PCRStatusExtension provides auxiliary methods for PCRStatus info.\ntype PCRStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PCRStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PCRStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\n// FinalizerState is a minimal interface for state that supports finalizers.\ntype FinalizerState interface {\n\tAddFinalizer(context.Context, resource.Pointer, ...resource.Finalizer) error\n\tRemoveFinalizer(context.Context, resource.Pointer, ...resource.Finalizer) error\n}\n\n// LockPCRStatus locks the PCR status resource.\nfunc LockPCRStatus(st FinalizerState, pcr int, finalizerName string) func(context.Context, func() error) error {\n\treturn func(ctx context.Context, fn func() error) error {\n\t\tpcrStatus := NewPCCRStatus(pcr)\n\n\t\tif err := st.AddFinalizer(ctx, pcrStatus.Metadata(), finalizerName); err != nil {\n\t\t\tif state.IsNotFoundError(err) {\n\t\t\t\treturn fmt.Errorf(\"failed to lock PCR %d, as it is in the wrong state, a reboot might be required\", pcr)\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"failed to lock PCR %d: %w\", pcr, err)\n\t\t}\n\n\t\tfnErr := fn()\n\n\t\tif err := st.RemoveFinalizer(ctx, pcrStatus.Metadata(), finalizerName); err != nil {\n\t\t\tfnErr = errors.Join(fnErr, fmt.Errorf(\"failed to unlock PCR %d: %w\", pcr, err))\n\t\t}\n\n\t\treturn fnErr\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(PCRStatusType, &PCRStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/processor.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ProcessorType is type of Processor resource.\nconst ProcessorType = resource.Type(\"Processors.hardware.talos.dev\")\n\n// Processor resource holds node Processor information.\ntype Processor = typed.Resource[ProcessorSpec, ProcessorExtension]\n\n// ProcessorSpec represents a single processor.\n//\n//gotagsrewrite:gen\ntype ProcessorSpec struct {\n\tSocket       string `yaml:\"socket,omitempty\" protobuf:\"1\"`\n\tManufacturer string `yaml:\"manufacturer,omitempty\" protobuf:\"2\"`\n\tProductName  string `yaml:\"productName,omitempty\" protobuf:\"3\"`\n\t// MaxSpeed is in megahertz (Mhz)\n\tMaxSpeed uint32 `yaml:\"maxSpeedMhz,omitempty\" protobuf:\"4\"`\n\t// Speed is in megahertz (Mhz)\n\tBootSpeed    uint32 `yaml:\"bootSpeedMhz,omitempty\" protobuf:\"5\"`\n\tStatus       uint32 `yaml:\"status,omitempty\" protobuf:\"6\"`\n\tSerialNumber string `yaml:\"serialNumber,omitempty\" protobuf:\"7\"`\n\tAssetTag     string `yaml:\"assetTag,omitempty\" protobuf:\"8\"`\n\tPartNumber   string `yaml:\"partNumber,omitempty\" protobuf:\"9\"`\n\tCoreCount    uint32 `yaml:\"coreCount,omitempty\" protobuf:\"10\"`\n\tCoreEnabled  uint32 `yaml:\"coreEnabled,omitempty\" protobuf:\"11\"`\n\tThreadCount  uint32 `yaml:\"threadCount,omitempty\" protobuf:\"12\"`\n}\n\n// NewProcessorInfo initializes a ProcessorInfo resource.\nfunc NewProcessorInfo(id string) *Processor {\n\treturn typed.NewResource[ProcessorSpec, ProcessorExtension](\n\t\tresource.NewMetadata(NamespaceName, ProcessorType, id, resource.VersionUndefined),\n\t\tProcessorSpec{},\n\t)\n}\n\n// ProcessorExtension provides auxiliary methods for Processor info.\ntype ProcessorExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ProcessorExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType: ProcessorType,\n\t\tAliases: []resource.Type{\n\t\t\t\"cpus\",\n\t\t\t\"cpu\",\n\t\t},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Manufacturer\",\n\t\t\t\tJSONPath: `{.manufacturer}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Model\",\n\t\t\t\tJSONPath: `{.productName}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Cores\",\n\t\t\t\tJSONPath: `{.coreCount}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Threads\",\n\t\t\t\tJSONPath: `{.threadCount}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ProcessorSpec](ProcessorType, &Processor{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/hardware/system_information.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage hardware\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SystemInformationType is type of SystemInformation resource.\nconst SystemInformationType = resource.Type(\"SystemInformations.hardware.talos.dev\")\n\n// SystemInformationID is the ID of the SystemInformation resource.\nconst SystemInformationID = resource.ID(\"systeminformation\")\n\n// SystemInformation resource holds node SystemInformation information.\ntype SystemInformation = typed.Resource[SystemInformationSpec, SystemInformationExtension]\n\n// SystemInformationSpec represents the system information obtained from smbios.\n//\n//gotagsrewrite:gen\ntype SystemInformationSpec struct {\n\tManufacturer string `yaml:\"manufacturer,omitempty\" protobuf:\"1\"`\n\tProductName  string `yaml:\"productName,omitempty\" protobuf:\"2\"`\n\tVersion      string `yaml:\"version,omitempty\" protobuf:\"3\"`\n\tSerialNumber string `yaml:\"serialnumber,omitempty\" protobuf:\"4\"`\n\tUUID         string `yaml:\"uuid,omitempty\" protobuf:\"5\"`\n\tWakeUpType   string `yaml:\"wakeUpType,omitempty\" protobuf:\"6\"`\n\tSKUNumber    string `yaml:\"skuNumber,omitempty\" protobuf:\"7\"`\n}\n\n// NewSystemInformation initializes a SystemInformationInfo resource.\nfunc NewSystemInformation(id string) *SystemInformation {\n\treturn typed.NewResource[SystemInformationSpec, SystemInformationExtension](\n\t\tresource.NewMetadata(NamespaceName, SystemInformationType, id, resource.VersionUndefined),\n\t\tSystemInformationSpec{},\n\t)\n}\n\n// SystemInformationExtension provides auxiliary methods for SystemInformation.\ntype SystemInformationExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (SystemInformationExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType: SystemInformationType,\n\t\tAliases: []resource.Type{\n\t\t\t\"systeminformation\",\n\t\t},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Manufacturer\",\n\t\t\t\tJSONPath: `{.manufacturer}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"ProductName\",\n\t\t\t\tJSONPath: `{.productName}`,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tName:     \"Version\",\n\t\t\t\tJSONPath: `{.version}`,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tName:     \"SerialNumber\",\n\t\t\t\tJSONPath: `{.serialnumber}`,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tName:     \"UUID\",\n\t\t\t\tJSONPath: `{.uuid}`,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tName:     \"WakeUpType\",\n\t\t\t\tJSONPath: `{.wakeUpType}`,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tName:     \"SKUNumber\",\n\t\t\t\tJSONPath: `{.skuNumber}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SystemInformationSpec](SystemInformationType, &SystemInformation{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/admissioncontrol_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// AdmissionControlConfigType is type of AdmissionControlConfig resource.\nconst AdmissionControlConfigType = resource.Type(\"AdmissionControlConfigs.kubernetes.talos.dev\")\n\n// AdmissionControlConfigID is a singleton resource ID for AdmissionControlConfig.\nconst AdmissionControlConfigID = resource.ID(\"admission-control\")\n\n// AdmissionControlConfig represents configuration for kube-apiserver Admission Control plugins.\ntype AdmissionControlConfig = typed.Resource[AdmissionControlConfigSpec, AdmissionControlConfigExtension]\n\n// AdmissionControlConfigSpec is configuration for kube-apiserver.\n//\n//gotagsrewrite:gen\ntype AdmissionControlConfigSpec struct {\n\tConfig []AdmissionPluginSpec `yaml:\"config\" protobuf:\"1\"`\n}\n\n// AdmissionPluginSpec is a single admission plugin configuration Admission Control plugins.\n//\n//gotagsrewrite:gen\ntype AdmissionPluginSpec struct {\n\tName          string         `yaml:\"name\" protobuf:\"1\"`\n\tConfiguration map[string]any `yaml:\"configuration\" protobuf:\"2\"`\n}\n\n// NewAdmissionControlConfig returns new AdmissionControlConfig resource.\nfunc NewAdmissionControlConfig() *AdmissionControlConfig {\n\treturn typed.NewResource[AdmissionControlConfigSpec, AdmissionControlConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, AdmissionControlConfigType, AdmissionControlConfigID, resource.VersionUndefined),\n\t\tAdmissionControlConfigSpec{})\n}\n\n// AdmissionControlConfigExtension defines AdmissionControlConfig resource definition.\ntype AdmissionControlConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AdmissionControlConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AdmissionControlConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AdmissionControlConfigSpec](AdmissionControlConfigType, &AdmissionControlConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/apiserver_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// APIServerConfigType is type of APIServerConfig resource.\nconst APIServerConfigType = resource.Type(\"APIServerConfigs.kubernetes.talos.dev\")\n\n// APIServerConfigID is a singleton resource ID for APIServerConfig.\nconst APIServerConfigID = resource.ID(APIServerID)\n\n// APIServerConfig represents configuration for kube-apiserver.\ntype APIServerConfig = typed.Resource[APIServerConfigSpec, APIServerConfigExtension]\n\n// ExtraVolume is a configuration of extra volume.\n//\n//gotagsrewrite:gen\ntype ExtraVolume struct {\n\tName      string `yaml:\"name\" protobuf:\"1\"`\n\tHostPath  string `yaml:\"hostPath\" protobuf:\"2\"`\n\tMountPath string `yaml:\"mountPath\" protobuf:\"3\"`\n\tReadOnly  bool   `yaml:\"readonly\" protobuf:\"4\"`\n}\n\n// Resources is a configuration of cpu and memory resources.\n//\n//gotagsrewrite:gen\ntype Resources struct {\n\tRequests map[string]string `yaml:\"requests\" protobuf:\"1\"`\n\tLimits   map[string]string `yaml:\"limits\" protobuf:\"2\"`\n}\n\n// APIServerConfigSpec is configuration for kube-apiserver.\n//\n//gotagsrewrite:gen\ntype APIServerConfigSpec struct {\n\tImage                string               `yaml:\"image\" protobuf:\"1\"`\n\tCloudProvider        string               `yaml:\"cloudProvider\" protobuf:\"2\"`\n\tControlPlaneEndpoint string               `yaml:\"controlPlaneEndpoint\" protobuf:\"3\"`\n\tEtcdServers          []string             `yaml:\"etcdServers\" protobuf:\"4\"`\n\tLocalPort            int                  `yaml:\"localPort\" protobuf:\"5\"`\n\tServiceCIDRs         []string             `yaml:\"serviceCIDR\" protobuf:\"6\"`\n\tExtraArgs            map[string]ArgValues `yaml:\"extraArgs\" protobuf:\"7\"`\n\tExtraVolumes         []ExtraVolume        `yaml:\"extraVolumes\" protobuf:\"8\"`\n\tEnvironmentVariables map[string]string    `yaml:\"environmentVariables\" protobuf:\"9\"`\n\tAdvertisedAddress    string               `yaml:\"advertisedAddress\" protobuf:\"11\"`\n\tResources            Resources            `yaml:\"resources\" protobuf:\"12\"`\n}\n\n// ArgValues represents values for a command line argument which can be specified multiple times.\n//\n//gotagsrewrite:gen\ntype ArgValues struct {\n\tValues []string `yaml:\"values\" protobuf:\"1\"`\n}\n\n// NewAPIServerConfig returns new APIServerConfig resource.\nfunc NewAPIServerConfig() *APIServerConfig {\n\treturn typed.NewResource[APIServerConfigSpec, APIServerConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, APIServerConfigType, APIServerConfigID, resource.VersionUndefined),\n\t\tAPIServerConfigSpec{})\n}\n\n// APIServerConfigExtension defines APIServerConfig resource definition.\ntype APIServerConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (APIServerConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             APIServerConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[APIServerConfigSpec](APIServerConfigType, &APIServerConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/auditpolicy_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// AuditPolicyConfigType is type of AuditPolicyConfig resource.\nconst AuditPolicyConfigType = resource.Type(\"AuditPolicyConfigs.kubernetes.talos.dev\")\n\n// AuditPolicyConfigID is a singleton resource ID for AuditPolicyConfig.\nconst AuditPolicyConfigID = resource.ID(\"audit-policy\")\n\n// AuditPolicyConfig represents configuration for kube-apiserver audit policy.\ntype AuditPolicyConfig = typed.Resource[AuditPolicyConfigSpec, AuditPolicyConfigExtension]\n\n// AuditPolicyConfigSpec is audit policy configuration for kube-apiserver.\n//\n//gotagsrewrite:gen\ntype AuditPolicyConfigSpec struct {\n\tConfig map[string]any `yaml:\"config\" protobuf:\"1\"`\n}\n\n// NewAuditPolicyConfig returns new AuditPolicyConfig resource.\nfunc NewAuditPolicyConfig() *AuditPolicyConfig {\n\treturn typed.NewResource[AuditPolicyConfigSpec, AuditPolicyConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, AuditPolicyConfigType, AuditPolicyConfigID, resource.VersionUndefined),\n\t\tAuditPolicyConfigSpec{})\n}\n\n// AuditPolicyConfigExtension defines AuditPolicyConfig resource definition.\ntype AuditPolicyConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AuditPolicyConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AuditPolicyConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AuditPolicyConfigSpec](AuditPolicyConfigType, &AuditPolicyConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/authorization_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n)\n\n// AuthorizationConfigType is type of AuthorizationConfig resource.\nconst AuthorizationConfigType = resource.Type(\"AuthorizationConfigs.kubernetes.talos.dev\")\n\n// AuthorizationConfigID is a singleton resource ID for AuthorizationConfig.\nconst AuthorizationConfigID = resource.ID(\"authorization\")\n\n// AuthorizationConfig represents configuration for kube-apiserver authorization.\ntype AuthorizationConfig = typed.Resource[AuthorizationConfigSpec, AuthorizationConfigExtension]\n\n// AuthorizationConfigSpec is authorization configuration for kube-apiserver.\n//\n//gotagsrewrite:gen\ntype AuthorizationConfigSpec struct {\n\tImage  string                         `yaml:\"image\" protobuf:\"1\"`\n\tConfig []AuthorizationAuthorizersSpec `yaml:\"config\" protobuf:\"2\"`\n}\n\n// AuthorizationAuthorizersSpec is a configuration of authorization authorizers.\n//\n//gotagsrewrite:gen\ntype AuthorizationAuthorizersSpec struct {\n\tType    string         `yaml:\"type\" protobuf:\"1\"`\n\tName    string         `yaml:\"name\" protobuf:\"2\"`\n\tWebhook map[string]any `yaml:\"webhook\" protobuf:\"3\"`\n}\n\n// NewAuthorizationConfig returns new AuthorizationConfig resource.\nfunc NewAuthorizationConfig() *AuthorizationConfig {\n\treturn typed.NewResource[AuthorizationConfigSpec, AuthorizationConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, AuthorizationConfigType, AuthorizationConfigID, resource.VersionUndefined),\n\t\tAuthorizationConfigSpec{})\n}\n\n// AuthorizationConfigExtension defines AuthorizationConfig resource definition.\ntype AuthorizationConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AuthorizationConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AuthorizationConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\terr := protobuf.RegisterDynamic[AuthorizationConfigSpec](AuthorizationConfigType, &AuthorizationConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/config_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\n//\n//nolint:dupl\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ConfigStatusType is type of ConfigStatus resource.\nconst ConfigStatusType = resource.Type(\"ConfigStatuses.kubernetes.talos.dev\")\n\n// ConfigStatusStaticPodID is resource ID for ConfigStatus resource for static pods.\nconst ConfigStatusStaticPodID = resource.ID(\"static-pods\")\n\n// ConfigStatus resource holds definition of rendered secrets.\ntype ConfigStatus = typed.Resource[ConfigStatusSpec, ConfigStatusExtension]\n\n// ConfigStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype ConfigStatusSpec struct {\n\tReady   bool   `yaml:\"ready\" protobuf:\"1\"`\n\tVersion string `yaml:\"version\" protobuf:\"2\"`\n}\n\n// NewConfigStatus initializes a ConfigStatus resource.\nfunc NewConfigStatus(namespace resource.Namespace, id resource.ID) *ConfigStatus {\n\treturn typed.NewResource[ConfigStatusSpec, ConfigStatusExtension](\n\t\tresource.NewMetadata(namespace, ConfigStatusType, id, resource.VersionUndefined),\n\t\tConfigStatusSpec{},\n\t)\n}\n\n// ConfigStatusExtension provides auxiliary methods for ConfigStatus.\ntype ConfigStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ConfigStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: \"{.ready}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Secrets Version\",\n\t\t\t\tJSONPath: \"{.version}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigStatusSpec](ConfigStatusType, &ConfigStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/controllermanager_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ControllerManagerConfigType is type of ControllerManagerConfig resource.\nconst ControllerManagerConfigType = resource.Type(\"ControllerManagerConfigs.kubernetes.talos.dev\")\n\n// ControllerManagerConfigID is a singleton resource ID for ControllerManagerConfig.\nconst ControllerManagerConfigID = resource.ID(ControllerManagerID)\n\n// ControllerManagerConfig represents configuration for kube-controller-manager.\ntype ControllerManagerConfig = typed.Resource[ControllerManagerConfigSpec, ControllerManagerConfigExtension]\n\n// ControllerManagerConfigSpec is configuration for kube-controller-manager.\n//\n//gotagsrewrite:gen\ntype ControllerManagerConfigSpec struct {\n\tEnabled              bool                 `yaml:\"enabled\" protobuf:\"1\"`\n\tImage                string               `yaml:\"image\" protobuf:\"2\"`\n\tCloudProvider        string               `yaml:\"cloudProvider\" protobuf:\"3\"`\n\tPodCIDRs             []string             `yaml:\"podCIDRs\" protobuf:\"4\"`\n\tServiceCIDRs         []string             `yaml:\"serviceCIDRs\" protobuf:\"5\"`\n\tExtraArgs            map[string]ArgValues `yaml:\"extraArgs\" protobuf:\"6\"`\n\tExtraVolumes         []ExtraVolume        `yaml:\"extraVolumes\" protobuf:\"7\"`\n\tEnvironmentVariables map[string]string    `yaml:\"environmentVariables\" protobuf:\"8\"`\n\tResources            Resources            `yaml:\"resources\" protobuf:\"9\"`\n}\n\n// NewControllerManagerConfig returns new ControllerManagerConfig resource.\nfunc NewControllerManagerConfig() *ControllerManagerConfig {\n\treturn typed.NewResource[ControllerManagerConfigSpec, ControllerManagerConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, ControllerManagerConfigType, ControllerManagerConfigID, resource.VersionUndefined),\n\t\tControllerManagerConfigSpec{})\n}\n\n// ControllerManagerConfigExtension defines ControllerManagerConfig resource definition.\ntype ControllerManagerConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ControllerManagerConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ControllerManagerConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ControllerManagerConfigSpec](ControllerManagerConfigType, &ControllerManagerConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type AdmissionControlConfigSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type AuthorizationConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubePrismConfigSpec -type KubePrismEndpointsSpec -type KubePrismStatusesSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeAnnotationSpecSpec -type NodeCordonedSpecSpec -type NodeLabelSpecSpec -type NodeTaintSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodeStatusSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage k8s\n\nimport (\n\t\"net/netip\"\n\n\tspecs \"github.com/opencontainers/runtime-spec/specs-go\"\n)\n\n// DeepCopy generates a deep copy of AdmissionControlConfigSpec.\nfunc (o AdmissionControlConfigSpec) DeepCopy() AdmissionControlConfigSpec {\n\tvar cp AdmissionControlConfigSpec = o\n\tif o.Config != nil {\n\t\tcp.Config = make([]AdmissionPluginSpec, len(o.Config))\n\t\tcopy(cp.Config, o.Config)\n\t\tfor i2 := range o.Config {\n\t\t\tif o.Config[i2].Configuration != nil {\n\t\t\t\tcp.Config[i2].Configuration = make(map[string]any, len(o.Config[i2].Configuration))\n\t\t\t\tfor k4, v4 := range o.Config[i2].Configuration {\n\t\t\t\t\tcp.Config[i2].Configuration[k4] = v4\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of APIServerConfigSpec.\nfunc (o APIServerConfigSpec) DeepCopy() APIServerConfigSpec {\n\tvar cp APIServerConfigSpec = o\n\tif o.EtcdServers != nil {\n\t\tcp.EtcdServers = make([]string, len(o.EtcdServers))\n\t\tcopy(cp.EtcdServers, o.EtcdServers)\n\t}\n\tif o.ServiceCIDRs != nil {\n\t\tcp.ServiceCIDRs = make([]string, len(o.ServiceCIDRs))\n\t\tcopy(cp.ServiceCIDRs, o.ServiceCIDRs)\n\t}\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\tif o.ExtraVolumes != nil {\n\t\tcp.ExtraVolumes = make([]ExtraVolume, len(o.ExtraVolumes))\n\t\tcopy(cp.ExtraVolumes, o.ExtraVolumes)\n\t}\n\tif o.EnvironmentVariables != nil {\n\t\tcp.EnvironmentVariables = make(map[string]string, len(o.EnvironmentVariables))\n\t\tfor k2, v2 := range o.EnvironmentVariables {\n\t\t\tcp.EnvironmentVariables[k2] = v2\n\t\t}\n\t}\n\tif o.Resources.Requests != nil {\n\t\tcp.Resources.Requests = make(map[string]string, len(o.Resources.Requests))\n\t\tfor k3, v3 := range o.Resources.Requests {\n\t\t\tcp.Resources.Requests[k3] = v3\n\t\t}\n\t}\n\tif o.Resources.Limits != nil {\n\t\tcp.Resources.Limits = make(map[string]string, len(o.Resources.Limits))\n\t\tfor k3, v3 := range o.Resources.Limits {\n\t\t\tcp.Resources.Limits[k3] = v3\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of AuditPolicyConfigSpec.\nfunc (o AuditPolicyConfigSpec) DeepCopy() AuditPolicyConfigSpec {\n\tvar cp AuditPolicyConfigSpec = o\n\tif o.Config != nil {\n\t\tcp.Config = make(map[string]any, len(o.Config))\n\t\tfor k2, v2 := range o.Config {\n\t\t\tcp.Config[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of AuthorizationConfigSpec.\nfunc (o AuthorizationConfigSpec) DeepCopy() AuthorizationConfigSpec {\n\tvar cp AuthorizationConfigSpec = o\n\tif o.Config != nil {\n\t\tcp.Config = make([]AuthorizationAuthorizersSpec, len(o.Config))\n\t\tcopy(cp.Config, o.Config)\n\t\tfor i2 := range o.Config {\n\t\t\tif o.Config[i2].Webhook != nil {\n\t\t\t\tcp.Config[i2].Webhook = make(map[string]any, len(o.Config[i2].Webhook))\n\t\t\t\tfor k4, v4 := range o.Config[i2].Webhook {\n\t\t\t\t\tcp.Config[i2].Webhook[k4] = v4\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of BootstrapManifestsConfigSpec.\nfunc (o BootstrapManifestsConfigSpec) DeepCopy() BootstrapManifestsConfigSpec {\n\tvar cp BootstrapManifestsConfigSpec = o\n\tif o.PodCIDRs != nil {\n\t\tcp.PodCIDRs = make([]string, len(o.PodCIDRs))\n\t\tcopy(cp.PodCIDRs, o.PodCIDRs)\n\t}\n\tif o.ProxyArgs != nil {\n\t\tcp.ProxyArgs = make([]string, len(o.ProxyArgs))\n\t\tcopy(cp.ProxyArgs, o.ProxyArgs)\n\t}\n\tif o.FlannelExtraArgs != nil {\n\t\tcp.FlannelExtraArgs = make([]string, len(o.FlannelExtraArgs))\n\t\tcopy(cp.FlannelExtraArgs, o.FlannelExtraArgs)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ConfigStatusSpec.\nfunc (o ConfigStatusSpec) DeepCopy() ConfigStatusSpec {\n\tvar cp ConfigStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ControllerManagerConfigSpec.\nfunc (o ControllerManagerConfigSpec) DeepCopy() ControllerManagerConfigSpec {\n\tvar cp ControllerManagerConfigSpec = o\n\tif o.PodCIDRs != nil {\n\t\tcp.PodCIDRs = make([]string, len(o.PodCIDRs))\n\t\tcopy(cp.PodCIDRs, o.PodCIDRs)\n\t}\n\tif o.ServiceCIDRs != nil {\n\t\tcp.ServiceCIDRs = make([]string, len(o.ServiceCIDRs))\n\t\tcopy(cp.ServiceCIDRs, o.ServiceCIDRs)\n\t}\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\tif o.ExtraVolumes != nil {\n\t\tcp.ExtraVolumes = make([]ExtraVolume, len(o.ExtraVolumes))\n\t\tcopy(cp.ExtraVolumes, o.ExtraVolumes)\n\t}\n\tif o.EnvironmentVariables != nil {\n\t\tcp.EnvironmentVariables = make(map[string]string, len(o.EnvironmentVariables))\n\t\tfor k2, v2 := range o.EnvironmentVariables {\n\t\t\tcp.EnvironmentVariables[k2] = v2\n\t\t}\n\t}\n\tif o.Resources.Requests != nil {\n\t\tcp.Resources.Requests = make(map[string]string, len(o.Resources.Requests))\n\t\tfor k3, v3 := range o.Resources.Requests {\n\t\t\tcp.Resources.Requests[k3] = v3\n\t\t}\n\t}\n\tif o.Resources.Limits != nil {\n\t\tcp.Resources.Limits = make(map[string]string, len(o.Resources.Limits))\n\t\tfor k3, v3 := range o.Resources.Limits {\n\t\t\tcp.Resources.Limits[k3] = v3\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EndpointSpec.\nfunc (o EndpointSpec) DeepCopy() EndpointSpec {\n\tvar cp EndpointSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]netip.Addr, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t}\n\tif o.Hosts != nil {\n\t\tcp.Hosts = make([]string, len(o.Hosts))\n\t\tcopy(cp.Hosts, o.Hosts)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ExtraManifestsConfigSpec.\nfunc (o ExtraManifestsConfigSpec) DeepCopy() ExtraManifestsConfigSpec {\n\tvar cp ExtraManifestsConfigSpec = o\n\tif o.ExtraManifests != nil {\n\t\tcp.ExtraManifests = make([]ExtraManifest, len(o.ExtraManifests))\n\t\tcopy(cp.ExtraManifests, o.ExtraManifests)\n\t\tfor i2 := range o.ExtraManifests {\n\t\t\tif o.ExtraManifests[i2].ExtraHeaders != nil {\n\t\t\t\tcp.ExtraManifests[i2].ExtraHeaders = make(map[string]string, len(o.ExtraManifests[i2].ExtraHeaders))\n\t\t\t\tfor k4, v4 := range o.ExtraManifests[i2].ExtraHeaders {\n\t\t\t\t\tcp.ExtraManifests[i2].ExtraHeaders[k4] = v4\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubeletLifecycleSpec.\nfunc (o KubeletLifecycleSpec) DeepCopy() KubeletLifecycleSpec {\n\tvar cp KubeletLifecycleSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubePrismConfigSpec.\nfunc (o KubePrismConfigSpec) DeepCopy() KubePrismConfigSpec {\n\tvar cp KubePrismConfigSpec = o\n\tif o.Endpoints != nil {\n\t\tcp.Endpoints = make([]KubePrismEndpoint, len(o.Endpoints))\n\t\tcopy(cp.Endpoints, o.Endpoints)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubePrismEndpointsSpec.\nfunc (o KubePrismEndpointsSpec) DeepCopy() KubePrismEndpointsSpec {\n\tvar cp KubePrismEndpointsSpec = o\n\tif o.Endpoints != nil {\n\t\tcp.Endpoints = make([]KubePrismEndpoint, len(o.Endpoints))\n\t\tcopy(cp.Endpoints, o.Endpoints)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubePrismStatusesSpec.\nfunc (o KubePrismStatusesSpec) DeepCopy() KubePrismStatusesSpec {\n\tvar cp KubePrismStatusesSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubeletSpecSpec.\nfunc (o KubeletSpecSpec) DeepCopy() KubeletSpecSpec {\n\tvar cp KubeletSpecSpec = o\n\tif o.Args != nil {\n\t\tcp.Args = make([]string, len(o.Args))\n\t\tcopy(cp.Args, o.Args)\n\t}\n\tif o.ExtraMounts != nil {\n\t\tcp.ExtraMounts = make([]specs.Mount, len(o.ExtraMounts))\n\t\tcopy(cp.ExtraMounts, o.ExtraMounts)\n\t\tfor i2 := range o.ExtraMounts {\n\t\t\tif o.ExtraMounts[i2].Options != nil {\n\t\t\t\tcp.ExtraMounts[i2].Options = make([]string, len(o.ExtraMounts[i2].Options))\n\t\t\t\tcopy(cp.ExtraMounts[i2].Options, o.ExtraMounts[i2].Options)\n\t\t\t}\n\t\t\tif o.ExtraMounts[i2].UIDMappings != nil {\n\t\t\t\tcp.ExtraMounts[i2].UIDMappings = make([]specs.LinuxIDMapping, len(o.ExtraMounts[i2].UIDMappings))\n\t\t\t\tcopy(cp.ExtraMounts[i2].UIDMappings, o.ExtraMounts[i2].UIDMappings)\n\t\t\t}\n\t\t\tif o.ExtraMounts[i2].GIDMappings != nil {\n\t\t\t\tcp.ExtraMounts[i2].GIDMappings = make([]specs.LinuxIDMapping, len(o.ExtraMounts[i2].GIDMappings))\n\t\t\t\tcopy(cp.ExtraMounts[i2].GIDMappings, o.ExtraMounts[i2].GIDMappings)\n\t\t\t}\n\t\t}\n\t}\n\tif o.Config != nil {\n\t\tcp.Config = make(map[string]any, len(o.Config))\n\t\tfor k2, v2 := range o.Config {\n\t\t\tcp.Config[k2] = v2\n\t\t}\n\t}\n\tif o.CredentialProviderConfig != nil {\n\t\tcp.CredentialProviderConfig = make(map[string]any, len(o.CredentialProviderConfig))\n\t\tfor k2, v2 := range o.CredentialProviderConfig {\n\t\t\tcp.CredentialProviderConfig[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ManifestSpec.\nfunc (o ManifestSpec) DeepCopy() ManifestSpec {\n\tvar cp ManifestSpec = o\n\tif o.Items != nil {\n\t\tcp.Items = make([]SingleManifest, len(o.Items))\n\t\tcopy(cp.Items, o.Items)\n\t\tfor i2 := range o.Items {\n\t\t\tif o.Items[i2].Object != nil {\n\t\t\t\tcp.Items[i2].Object = make(map[string]any, len(o.Items[i2].Object))\n\t\t\t\tfor k4, v4 := range o.Items[i2].Object {\n\t\t\t\t\tcp.Items[i2].Object[k4] = v4\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ManifestStatusSpec.\nfunc (o ManifestStatusSpec) DeepCopy() ManifestStatusSpec {\n\tvar cp ManifestStatusSpec = o\n\tif o.ManifestsApplied != nil {\n\t\tcp.ManifestsApplied = make([]string, len(o.ManifestsApplied))\n\t\tcopy(cp.ManifestsApplied, o.ManifestsApplied)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeAnnotationSpecSpec.\nfunc (o NodeAnnotationSpecSpec) DeepCopy() NodeAnnotationSpecSpec {\n\tvar cp NodeAnnotationSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeCordonedSpecSpec.\nfunc (o NodeCordonedSpecSpec) DeepCopy() NodeCordonedSpecSpec {\n\tvar cp NodeCordonedSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeLabelSpecSpec.\nfunc (o NodeLabelSpecSpec) DeepCopy() NodeLabelSpecSpec {\n\tvar cp NodeLabelSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeTaintSpecSpec.\nfunc (o NodeTaintSpecSpec) DeepCopy() NodeTaintSpecSpec {\n\tvar cp NodeTaintSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubeletConfigSpec.\nfunc (o KubeletConfigSpec) DeepCopy() KubeletConfigSpec {\n\tvar cp KubeletConfigSpec = o\n\tif o.ClusterDNS != nil {\n\t\tcp.ClusterDNS = make([]string, len(o.ClusterDNS))\n\t\tcopy(cp.ClusterDNS, o.ClusterDNS)\n\t}\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\tif o.ExtraMounts != nil {\n\t\tcp.ExtraMounts = make([]specs.Mount, len(o.ExtraMounts))\n\t\tcopy(cp.ExtraMounts, o.ExtraMounts)\n\t\tfor i2 := range o.ExtraMounts {\n\t\t\tif o.ExtraMounts[i2].Options != nil {\n\t\t\t\tcp.ExtraMounts[i2].Options = make([]string, len(o.ExtraMounts[i2].Options))\n\t\t\t\tcopy(cp.ExtraMounts[i2].Options, o.ExtraMounts[i2].Options)\n\t\t\t}\n\t\t\tif o.ExtraMounts[i2].UIDMappings != nil {\n\t\t\t\tcp.ExtraMounts[i2].UIDMappings = make([]specs.LinuxIDMapping, len(o.ExtraMounts[i2].UIDMappings))\n\t\t\t\tcopy(cp.ExtraMounts[i2].UIDMappings, o.ExtraMounts[i2].UIDMappings)\n\t\t\t}\n\t\t\tif o.ExtraMounts[i2].GIDMappings != nil {\n\t\t\t\tcp.ExtraMounts[i2].GIDMappings = make([]specs.LinuxIDMapping, len(o.ExtraMounts[i2].GIDMappings))\n\t\t\t\tcopy(cp.ExtraMounts[i2].GIDMappings, o.ExtraMounts[i2].GIDMappings)\n\t\t\t}\n\t\t}\n\t}\n\tif o.ExtraConfig != nil {\n\t\tcp.ExtraConfig = make(map[string]any, len(o.ExtraConfig))\n\t\tfor k2, v2 := range o.ExtraConfig {\n\t\t\tcp.ExtraConfig[k2] = v2\n\t\t}\n\t}\n\tif o.CredentialProviderConfig != nil {\n\t\tcp.CredentialProviderConfig = make(map[string]any, len(o.CredentialProviderConfig))\n\t\tfor k2, v2 := range o.CredentialProviderConfig {\n\t\t\tcp.CredentialProviderConfig[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeIPSpec.\nfunc (o NodeIPSpec) DeepCopy() NodeIPSpec {\n\tvar cp NodeIPSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]netip.Addr, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeIPConfigSpec.\nfunc (o NodeIPConfigSpec) DeepCopy() NodeIPConfigSpec {\n\tvar cp NodeIPConfigSpec = o\n\tif o.ValidSubnets != nil {\n\t\tcp.ValidSubnets = make([]string, len(o.ValidSubnets))\n\t\tcopy(cp.ValidSubnets, o.ValidSubnets)\n\t}\n\tif o.ExcludeSubnets != nil {\n\t\tcp.ExcludeSubnets = make([]string, len(o.ExcludeSubnets))\n\t\tcopy(cp.ExcludeSubnets, o.ExcludeSubnets)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeStatusSpec.\nfunc (o NodeStatusSpec) DeepCopy() NodeStatusSpec {\n\tvar cp NodeStatusSpec = o\n\tif o.Labels != nil {\n\t\tcp.Labels = make(map[string]string, len(o.Labels))\n\t\tfor k2, v2 := range o.Labels {\n\t\t\tcp.Labels[k2] = v2\n\t\t}\n\t}\n\tif o.Annotations != nil {\n\t\tcp.Annotations = make(map[string]string, len(o.Annotations))\n\t\tfor k2, v2 := range o.Annotations {\n\t\t\tcp.Annotations[k2] = v2\n\t\t}\n\t}\n\tif o.PodCIDRs != nil {\n\t\tcp.PodCIDRs = make([]netip.Prefix, len(o.PodCIDRs))\n\t\tcopy(cp.PodCIDRs, o.PodCIDRs)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodenameSpec.\nfunc (o NodenameSpec) DeepCopy() NodenameSpec {\n\tvar cp NodenameSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SchedulerConfigSpec.\nfunc (o SchedulerConfigSpec) DeepCopy() SchedulerConfigSpec {\n\tvar cp SchedulerConfigSpec = o\n\tif o.ExtraArgs != nil {\n\t\tcp.ExtraArgs = make(map[string]ArgValues, len(o.ExtraArgs))\n\t\tfor k2, v2 := range o.ExtraArgs {\n\t\t\tvar cp_ExtraArgs_v2 ArgValues\n\t\t\tif v2.Values != nil {\n\t\t\t\tcp_ExtraArgs_v2.Values = make([]string, len(v2.Values))\n\t\t\t\tcopy(cp_ExtraArgs_v2.Values, v2.Values)\n\t\t\t}\n\t\t\tcp.ExtraArgs[k2] = cp_ExtraArgs_v2\n\t\t}\n\t}\n\tif o.ExtraVolumes != nil {\n\t\tcp.ExtraVolumes = make([]ExtraVolume, len(o.ExtraVolumes))\n\t\tcopy(cp.ExtraVolumes, o.ExtraVolumes)\n\t}\n\tif o.EnvironmentVariables != nil {\n\t\tcp.EnvironmentVariables = make(map[string]string, len(o.EnvironmentVariables))\n\t\tfor k2, v2 := range o.EnvironmentVariables {\n\t\t\tcp.EnvironmentVariables[k2] = v2\n\t\t}\n\t}\n\tif o.Resources.Requests != nil {\n\t\tcp.Resources.Requests = make(map[string]string, len(o.Resources.Requests))\n\t\tfor k3, v3 := range o.Resources.Requests {\n\t\t\tcp.Resources.Requests[k3] = v3\n\t\t}\n\t}\n\tif o.Resources.Limits != nil {\n\t\tcp.Resources.Limits = make(map[string]string, len(o.Resources.Limits))\n\t\tfor k3, v3 := range o.Resources.Limits {\n\t\t\tcp.Resources.Limits[k3] = v3\n\t\t}\n\t}\n\tif o.Config != nil {\n\t\tcp.Config = make(map[string]any, len(o.Config))\n\t\tfor k2, v2 := range o.Config {\n\t\t\tcp.Config[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SecretsStatusSpec.\nfunc (o SecretsStatusSpec) DeepCopy() SecretsStatusSpec {\n\tvar cp SecretsStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StaticPodSpec.\nfunc (o StaticPodSpec) DeepCopy() StaticPodSpec {\n\tvar cp StaticPodSpec = o\n\tif o.Pod != nil {\n\t\tcp.Pod = make(map[string]any, len(o.Pod))\n\t\tfor k2, v2 := range o.Pod {\n\t\t\tcp.Pod[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StaticPodStatusSpec.\nfunc (o StaticPodStatusSpec) DeepCopy() StaticPodStatusSpec {\n\tvar cp StaticPodStatusSpec = o\n\tif o.PodStatus != nil {\n\t\tcp.PodStatus = make(map[string]any, len(o.PodStatus))\n\t\tfor k2, v2 := range o.PodStatus {\n\t\t\tcp.PodStatus[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StaticPodServerStatusSpec.\nfunc (o StaticPodServerStatusSpec) DeepCopy() StaticPodServerStatusSpec {\n\tvar cp StaticPodServerStatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EndpointType is type of Endpoint resource.\nconst EndpointType = resource.Type(\"Endpoints.kubernetes.talos.dev\")\n\n// ControlPlaneAPIServerEndpointsID is resource ID for kube-apiserver based Endpoints.\nconst ControlPlaneAPIServerEndpointsID = resource.ID(\"kube-apiserver\")\n\n// ControlPlaneDiscoveredEndpointsID is resource ID for cluster discovery based Endpoints.\nconst ControlPlaneDiscoveredEndpointsID = resource.ID(\"discovery\")\n\n// ControlPlaneKubernetesEndpointsID is resource ID for control plane endpoint-based Endpoints.\nconst ControlPlaneKubernetesEndpointsID = resource.ID(\"controlplane\")\n\n// Endpoint resource holds definition of rendered secrets.\ntype Endpoint = typed.Resource[EndpointSpec, EndpointExtension]\n\n// EndpointSpec describes a list of endpoints to connect to.\n//\n//gotagsrewrite:gen\ntype EndpointSpec struct {\n\tAddresses []netip.Addr `yaml:\"addresses\" protobuf:\"1\"`\n\tHosts     []string     `yaml:\"hosts\" protobuf:\"2\"`\n}\n\n// NewEndpoint initializes the Endpoint resource.\nfunc NewEndpoint(namespace resource.Namespace, id resource.ID) *Endpoint {\n\treturn typed.NewResource[EndpointSpec, EndpointExtension](\n\t\tresource.NewMetadata(namespace, EndpointType, id, resource.VersionUndefined),\n\t\tEndpointSpec{},\n\t)\n}\n\n// EndpointExtension provides auxiliary methods for Endpoint.\ntype EndpointExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (EndpointExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EndpointType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Addresses\",\n\t\t\t\tJSONPath: \"{.addresses}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Hosts\",\n\t\t\t\tJSONPath: \"{.hosts}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// EndpointList is a flattened list of endpoints.\ntype EndpointList struct {\n\tAddresses []netip.Addr\n\tHosts     []string\n}\n\n// Merge endpoints from multiple Endpoint resources into a single list.\nfunc (l EndpointList) Merge(endpoint *Endpoint) EndpointList {\n\tfor _, ip := range endpoint.TypedSpec().Addresses {\n\t\tidx, _ := slices.BinarySearchFunc(l.Addresses, ip, func(a netip.Addr, target netip.Addr) int {\n\t\t\treturn a.Compare(target)\n\t\t})\n\t\tif idx < len(l.Addresses) && l.Addresses[idx].Compare(ip) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tl.Addresses = slices.Insert(l.Addresses, idx, ip)\n\t}\n\n\tfor _, host := range endpoint.TypedSpec().Hosts {\n\t\tidx, _ := slices.BinarySearch(l.Hosts, host)\n\t\tif idx < len(l.Hosts) && l.Hosts[idx] == host {\n\t\t\tcontinue\n\t\t}\n\n\t\tl.Hosts = slices.Insert(l.Hosts, idx, host)\n\t}\n\n\treturn l\n}\n\n// IsEmpty checks if the EndpointList is empty.\nfunc (l EndpointList) IsEmpty() bool {\n\treturn len(l.Addresses) == 0 && len(l.Hosts) == 0\n}\n\n// Strings returns a slice of formatted endpoints to string.\nfunc (l EndpointList) Strings() []string {\n\treturn slices.Concat(\n\t\txslices.Map(l.Addresses, netip.Addr.String),\n\t\tl.Hosts,\n\t)\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EndpointSpec](EndpointType, &Endpoint{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/endpoint_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\nfunc TestEndpointList(t *testing.T) {\n\tt.Parallel()\n\n\tvar l k8s.EndpointList\n\n\te1 := k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, \"1\")\n\te1.TypedSpec().Addresses = []netip.Addr{\n\t\tnetip.MustParseAddr(\"172.20.0.2\"),\n\t\tnetip.MustParseAddr(\"172.20.0.3\"),\n\t}\n\n\te2 := k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, \"2\")\n\te2.TypedSpec().Addresses = []netip.Addr{\n\t\tnetip.MustParseAddr(\"172.20.0.4\"),\n\t\tnetip.MustParseAddr(\"172.20.0.3\"),\n\t}\n\n\tl = l.Merge(e1)\n\tl = l.Merge(e2)\n\n\tassert.Equal(t, []string{\"172.20.0.2\", \"172.20.0.3\", \"172.20.0.4\"}, l.Strings())\n}\n\nfunc TestEndpointListWithHosts(t *testing.T) {\n\tt.Parallel()\n\n\tvar l k8s.EndpointList\n\n\tassert.True(t, l.IsEmpty())\n\n\te1 := k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, \"1\")\n\te1.TypedSpec().Addresses = []netip.Addr{\n\t\tnetip.MustParseAddr(\"172.20.0.2\"),\n\t}\n\te1.TypedSpec().Hosts = []string{\n\t\t\"host1.example.com\",\n\t\t\"host2.example.com\",\n\t}\n\n\te2 := k8s.NewEndpoint(k8s.ControlPlaneNamespaceName, \"2\")\n\te2.TypedSpec().Addresses = []netip.Addr{\n\t\tnetip.MustParseAddr(\"172.20.0.3\"),\n\t}\n\te2.TypedSpec().Hosts = []string{\n\t\t\"host2.example.com\",\n\t\t\"host3.example.com\",\n\t}\n\n\tl = l.Merge(e1)\n\tl = l.Merge(e2)\n\n\tassert.Equal(t,\n\t\t[]string{\n\t\t\t\"172.20.0.2\",\n\t\t\t\"172.20.0.3\",\n\t\t\t\"host1.example.com\",\n\t\t\t\"host2.example.com\",\n\t\t\t\"host3.example.com\",\n\t\t},\n\t\tl.Strings(),\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/extramanifests_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ExtraManifestsConfigType is type of ExtraManifestsConfig resource.\nconst ExtraManifestsConfigType = resource.Type(\"ExtraManifestsConfigs.kubernetes.talos.dev\")\n\n// ExtraManifestsConfigID is a singleton resource ID for ExtraManifestsConfig.\nconst ExtraManifestsConfigID = resource.ID(\"extra-manifests\")\n\n// ExtraManifestsConfig represents configuration for extra bootstrap manifests.\ntype ExtraManifestsConfig = typed.Resource[ExtraManifestsConfigSpec, ExtraManifestsConfigExtension]\n\n// ExtraManifestsConfigSpec is configuration for extra bootstrap manifests.\n//\n//gotagsrewrite:gen\ntype ExtraManifestsConfigSpec struct {\n\tExtraManifests []ExtraManifest `yaml:\"extraManifests\" protobuf:\"1\"`\n}\n\n// ExtraManifest defines a single extra manifest to download.\n//\n//gotagsrewrite:gen\ntype ExtraManifest struct {\n\tName           string            `yaml:\"name\" protobuf:\"1\"`\n\tURL            string            `yaml:\"url\" protobuf:\"2\"`\n\tPriority       string            `yaml:\"priority\" protobuf:\"3\"`\n\tExtraHeaders   map[string]string `yaml:\"extraHeaders\" protobuf:\"4\"`\n\tInlineManifest string            `yaml:\"inlineManifest\" protobuf:\"5\"`\n}\n\n// NewExtraManifestsConfig returns new ExtraManifestsConfig resource.\nfunc NewExtraManifestsConfig() *ExtraManifestsConfig {\n\treturn typed.NewResource[ExtraManifestsConfigSpec, ExtraManifestsConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, ExtraManifestsConfigType, ExtraManifestsConfigID, resource.VersionUndefined),\n\t\tExtraManifestsConfigSpec{})\n}\n\n// ExtraManifestsConfigExtension defines ExtraManifestsConfig resource definition.\ntype ExtraManifestsConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ExtraManifestsConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ExtraManifestsConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ExtraManifestsConfigSpec](ExtraManifestsConfigType, &ExtraManifestsConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/k8s.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n//go:generate go tool github.com/siderolabs/deep-copy -type AdmissionControlConfigSpec -type APIServerConfigSpec -type AuditPolicyConfigSpec -type AuthorizationConfigSpec -type BootstrapManifestsConfigSpec -type ConfigStatusSpec -type ControllerManagerConfigSpec -type EndpointSpec -type ExtraManifestsConfigSpec -type KubeletLifecycleSpec -type KubePrismConfigSpec -type KubePrismEndpointsSpec -type KubePrismStatusesSpec -type KubeletSpecSpec -type ManifestSpec -type ManifestStatusSpec -type NodeAnnotationSpecSpec -type NodeCordonedSpecSpec -type NodeLabelSpecSpec -type NodeTaintSpecSpec -type KubeletConfigSpec -type NodeIPSpec -type NodeIPConfigSpec -type NodeStatusSpec -type NodenameSpec -type SchedulerConfigSpec -type SecretsStatusSpec -type StaticPodSpec -type StaticPodStatusSpec -type StaticPodServerStatusSpec  -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName contains resources supporting Kubernetes components on all node types.\nconst NamespaceName resource.Namespace = \"k8s\"\n\n// ControlPlaneNamespaceName contains resources supporting Kubernetes control plane.\nconst ControlPlaneNamespaceName resource.Namespace = \"controlplane\"\n\n// NodeAddressFilterOnlyK8s is the ID for the node address filter which leaves only Kubernetes IPs.\nconst NodeAddressFilterOnlyK8s = \"only-k8s\"\n\n// NodeAddressFilterNoK8s is the ID for the node address filter which removes any Kubernetes IPs.\nconst NodeAddressFilterNoK8s = \"no-k8s\"\n\n// APIServerID is a generic ID for resources related to kube-apiserver.\nconst APIServerID = \"kube-apiserver\"\n\n// ControllerManagerID is a generic ID for resources related to kube-controller-manager.\nconst ControllerManagerID = \"kube-controller-manager\"\n\n// SchedulerID is a generic ID for resources related to kube-scheduler.\nconst SchedulerID = \"kube-scheduler\"\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/k8s_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&k8s.AdmissionControlConfig{},\n\t\t&k8s.APIServerConfig{},\n\t\t&k8s.KubePrismEndpoints{},\n\t\t&k8s.AuditPolicyConfig{},\n\t\t&k8s.ConfigStatus{},\n\t\t&k8s.ControllerManagerConfig{},\n\t\t&k8s.Endpoint{},\n\t\t&k8s.ExtraManifestsConfig{},\n\t\t&k8s.KubeletConfig{},\n\t\t&k8s.KubeletLifecycle{},\n\t\t&k8s.KubeletSpec{},\n\t\t&k8s.KubePrismStatuses{},\n\t\t&k8s.KubePrismConfig{},\n\t\t&k8s.ManifestStatus{},\n\t\t&k8s.Manifest{},\n\t\t&k8s.BootstrapManifestsConfig{},\n\t\t&k8s.NodeAnnotationSpec{},\n\t\t&k8s.NodeCordonedSpec{},\n\t\t&k8s.NodeLabelSpec{},\n\t\t&k8s.NodeTaintSpec{},\n\t\t&k8s.Nodename{},\n\t\t&k8s.NodeIP{},\n\t\t&k8s.NodeIPConfig{},\n\t\t&k8s.SchedulerConfig{},\n\t\t&k8s.SecretsStatus{},\n\t\t&k8s.StaticPodStatus{},\n\t\t&k8s.StaticPod{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n\nfunc TestKubeletConfig(t *testing.T) {\n\tcfg := k8s.NewKubeletConfig(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v1.0.0\"\n\tcfg.TypedSpec().ClusterDNS = []string{\"10.96.0.10\"}\n\tcfg.TypedSpec().ClusterDomain = \"cluster.local\"\n\tcfg.TypedSpec().ExtraArgs = map[string]k8s.ArgValues{\"foo\": {Values: []string{\"bar\"}}}\n\tcfg.TypedSpec().ExtraMounts = []specs.Mount{\n\t\t{\n\t\t\tDestination: \"/tmp\",\n\t\t\tSource:      \"/var\",\n\t\t\tType:        \"tmpfs\",\n\t\t},\n\t}\n\tcfg.TypedSpec().CloudProviderExternal = true\n\n\tres, err := protobuf.FromResource(cfg)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, res)\n}\n\nfunc TestKubeletSpec(t *testing.T) {\n\tcfg := k8s.NewKubeletSpec(k8s.NamespaceName, k8s.KubeletID)\n\tcfg.TypedSpec().Image = \"kubelet:v1.0.0\"\n\tcfg.TypedSpec().ExtraMounts = []specs.Mount{\n\t\t{\n\t\t\tDestination: \"/tmp\",\n\t\t\tSource:      \"/var\",\n\t\t\tType:        \"tmpfs\",\n\t\t},\n\t}\n\n\tres, err := protobuf.FromResource(cfg)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, res)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubelet_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubeletConfigType is type of KubeletConfig resource.\nconst KubeletConfigType = resource.Type(\"KubeletConfigs.kubernetes.talos.dev\")\n\n// KubeletID is the ID of KubeletConfig resource.\nconst KubeletID = resource.ID(\"kubelet\")\n\n// KubeletConfig resource holds source of kubelet configuration.\ntype KubeletConfig = typed.Resource[KubeletConfigSpec, KubeletConfigExtension]\n\n// KubeletConfigSpec holds the source of kubelet configuration.\n//\n//gotagsrewrite:gen\ntype KubeletConfigSpec struct {\n\tImage                         string               `yaml:\"image\" protobuf:\"1\"`\n\tClusterDNS                    []string             `yaml:\"clusterDNS\" protobuf:\"2\"`\n\tClusterDomain                 string               `yaml:\"clusterDomain\" protobuf:\"3\"`\n\tExtraArgs                     map[string]ArgValues `yaml:\"extraArgs,omitempty\" protobuf:\"4\"`\n\tExtraMounts                   []specs.Mount        `yaml:\"extraMounts,omitempty\" protobuf:\"5\"`\n\tExtraConfig                   map[string]any       `yaml:\"extraConfig,omitempty\" protobuf:\"6\"`\n\tCloudProviderExternal         bool                 `yaml:\"cloudProviderExternal\" protobuf:\"7\"`\n\tDefaultRuntimeSeccompEnabled  bool                 `yaml:\"defaultRuntimeSeccompEnabled\" protobuf:\"8\"`\n\tSkipNodeRegistration          bool                 `yaml:\"skipNodeRegistration\" protobuf:\"9\"`\n\tStaticPodListURL              string               `yaml:\"staticPodListURL\" protobuf:\"10\"`\n\tDisableManifestsDirectory     bool                 `yaml:\"disableManifestsDirectory\" protobuf:\"11\"`\n\tEnableFSQuotaMonitoring       bool                 `yaml:\"enableFSQuotaMonitoring\" protobuf:\"12\"`\n\tCredentialProviderConfig      map[string]any       `yaml:\"credentialProviderConfig,omitempty\" protobuf:\"13\"`\n\tAllowSchedulingOnControlPlane bool                 `yaml:\"allowSchedulingOnControlPlane\" protobuf:\"14\"`\n}\n\n// NewKubeletConfig initializes an empty KubeletConfig resource.\nfunc NewKubeletConfig(namespace resource.Namespace, id resource.ID) *KubeletConfig {\n\treturn typed.NewResource[KubeletConfigSpec, KubeletConfigExtension](\n\t\tresource.NewMetadata(namespace, KubeletConfigType, id, resource.VersionUndefined),\n\t\tKubeletConfigSpec{},\n\t)\n}\n\n// KubeletConfigExtension provides auxiliary methods for KubeletConfig.\ntype KubeletConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubeletConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubeletConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubeletConfigSpec](KubeletConfigType, &KubeletConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubelet_lifecycle.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubeletLifecycleType is type of KubeletLifecycle resource.\nconst KubeletLifecycleType = resource.Type(\"KubeletLifecycles.kubernetes.talos.dev\")\n\n// KubeletLifecycleID is the singleton ID of the resource.\nconst KubeletLifecycleID = resource.ID(\"kubelet\")\n\n// KubeletLifecycle resource exists to signal that the kubelet pods are running.\n//\n// Components might put finalizers on the KubeletLifecycle resource to signal that additional\n// actions should be taken before the kubelet is about to be shut down.\n//\n// KubeletLifecycle is mostly about status of the workloads kubelet is running vs.\n// the actual status of the kubelet service itself.\ntype KubeletLifecycle = typed.Resource[KubeletLifecycleSpec, KubeletLifecycleExtension]\n\n// KubeletLifecycleSpec is empty.\ntype KubeletLifecycleSpec struct{}\n\n// NewKubeletLifecycle initializes an empty KubeletLifecycle resource.\nfunc NewKubeletLifecycle(namespace resource.Namespace, id resource.ID) *KubeletLifecycle {\n\treturn typed.NewResource[KubeletLifecycleSpec, KubeletLifecycleExtension](\n\t\tresource.NewMetadata(namespace, KubeletLifecycleType, id, resource.VersionUndefined),\n\t\tKubeletLifecycleSpec{},\n\t)\n}\n\n// KubeletLifecycleExtension provides auxiliary methods for KubeletLifecycle.\ntype KubeletLifecycleExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubeletLifecycleExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubeletLifecycleType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubeletLifecycleSpec](KubeletLifecycleType, &KubeletLifecycle{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubelet_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/opencontainers/runtime-spec/specs-go\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubeletSpecType is type of KubeletSpec resource.\nconst KubeletSpecType = resource.Type(\"KubeletSpecs.kubernetes.talos.dev\")\n\n// KubeletSpec resource holds final definition of kubelet runtime configuration.\ntype KubeletSpec = typed.Resource[KubeletSpecSpec, KubeletSpecExtension]\n\n// KubeletSpecSpec holds the source of kubelet configuration.\n//\n//gotagsrewrite:gen\ntype KubeletSpecSpec struct {\n\tImage                    string         `yaml:\"image\" protobuf:\"1\"`\n\tArgs                     []string       `yaml:\"args,omitempty\" protobuf:\"2\"`\n\tExtraMounts              []specs.Mount  `yaml:\"extraMounts,omitempty\" protobuf:\"3\"`\n\tExpectedNodename         string         `yaml:\"expectedNodename,omitempty\" protobuf:\"4\"`\n\tConfig                   map[string]any `yaml:\"config\" protobuf:\"5\"`\n\tCredentialProviderConfig map[string]any `yaml:\"credentialProviderConfig,omitempty\" protobuf:\"6\"`\n}\n\n// NewKubeletSpec initializes an empty KubeletSpec resource.\nfunc NewKubeletSpec(namespace resource.Namespace, id resource.ID) *KubeletSpec {\n\treturn typed.NewResource[KubeletSpecSpec, KubeletSpecExtension](\n\t\tresource.NewMetadata(namespace, KubeletSpecType, id, resource.VersionUndefined),\n\t\tKubeletSpecSpec{},\n\t)\n}\n\n// KubeletSpecExtension provides auxiliary methods for KubeletSpec.\ntype KubeletSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubeletSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubeletSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubeletSpecSpec](KubeletSpecType, &KubeletSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubeprism.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubePrismStatusesType is type of KubePrismStatuses resource.\nconst KubePrismStatusesType = resource.Type(\"KubePrismStatuses.kubernetes.talos.dev\")\n\n// KubePrismStatusesID the singleton balancer health data resource ID.\nconst KubePrismStatusesID = resource.ID(\"k8s-loadbalancer\")\n\n// KubePrismStatuses resource holds load balancer health data.\ntype KubePrismStatuses = typed.Resource[KubePrismStatusesSpec, KubePrismStatusesExtension]\n\n// NewKubePrismStatuses initializes an KubePrismStatuses resource.\nfunc NewKubePrismStatuses(namespace resource.Namespace, id resource.ID) *KubePrismStatuses {\n\treturn typed.NewResource[KubePrismStatusesSpec, KubePrismStatusesExtension](\n\t\tresource.NewMetadata(namespace, KubePrismStatusesType, id, resource.VersionUndefined),\n\t\tKubePrismStatusesSpec{},\n\t)\n}\n\n// KubePrismStatusesSpec describes KubePrismStatuses data.\n//\n//gotagsrewrite:gen\ntype KubePrismStatusesSpec struct {\n\tHost    string `yaml:\"host\" protobuf:\"1\"`\n\tHealthy bool   `yaml:\"healthy\" protobuf:\"2\"`\n}\n\n// KubePrismStatusesExtension provides auxiliary methods for KubePrismStatuses.\ntype KubePrismStatusesExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubePrismStatusesExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubePrismStatusesType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"HOST\",\n\t\t\t\tJSONPath: \"{.host}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"HEALTHY\",\n\t\t\t\tJSONPath: \"{.healthy}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubePrismStatusesSpec](KubePrismStatusesType, &KubePrismStatuses{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubeprism_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubePrismConfigType is type of KubePrismConfig resource.\nconst KubePrismConfigType = resource.Type(\"KubePrismConfigs.kubernetes.talos.dev\")\n\n// KubePrismConfigID the singleton config resource ID.\nconst KubePrismConfigID = resource.ID(\"k8s-loadbalancer-config\")\n\n// KubePrismConfig resource holds load balancer health data.\ntype KubePrismConfig = typed.Resource[KubePrismConfigSpec, KubePrismConfigExtension]\n\n// NewKubePrismConfig initializes an KubePrismConfig resource.\nfunc NewKubePrismConfig(namespace resource.Namespace, id resource.ID) *KubePrismConfig {\n\treturn typed.NewResource[KubePrismConfigSpec, KubePrismConfigExtension](\n\t\tresource.NewMetadata(namespace, KubePrismConfigType, id, resource.VersionUndefined),\n\t\tKubePrismConfigSpec{},\n\t)\n}\n\n// KubePrismConfigSpec describes KubePrismConfig data.\n//\n//gotagsrewrite:gen\ntype KubePrismConfigSpec struct {\n\tHost      string              `yaml:\"host\" protobuf:\"1\"`\n\tPort      int                 `yaml:\"port\" protobuf:\"2\"`\n\tEndpoints []KubePrismEndpoint `yaml:\"endpoints\" protobuf:\"3\"`\n}\n\n// KubePrismConfigExtension provides auxiliary methods for KubePrismConfig.\ntype KubePrismConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubePrismConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubePrismConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Host\",\n\t\t\t\tJSONPath: \"{.host}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Port\",\n\t\t\t\tJSONPath: \"{.port}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Endpoints\",\n\t\t\t\tJSONPath: \"{.endpoints}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubePrismConfigSpec](KubePrismConfigType, &KubePrismConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/kubeprism_endpoints.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubePrismEndpointsType is type of KubePrismEndpoints resource.\nconst KubePrismEndpointsType = resource.Type(\"KubePrismEndpoints.kubernetes.talos.dev\")\n\n// KubePrismEndpointsID the singleton balancer data resource ID.\nconst KubePrismEndpointsID = resource.ID(\"k8s-cluster\")\n\n// KubePrismEndpoints resource holds endpoints data.\ntype KubePrismEndpoints = typed.Resource[KubePrismEndpointsSpec, KubePrismEndpointsExtension]\n\n// NewKubePrismEndpoints initializes an KubePrismEndpoints resource.\nfunc NewKubePrismEndpoints(namespace resource.Namespace, id resource.ID) *KubePrismEndpoints {\n\treturn typed.NewResource[KubePrismEndpointsSpec, KubePrismEndpointsExtension](\n\t\tresource.NewMetadata(namespace, KubePrismEndpointsType, id, resource.VersionUndefined),\n\t\tKubePrismEndpointsSpec{},\n\t)\n}\n\n// KubePrismEndpointsSpec describes KubePrismEndpoints configuration.\n//\n//gotagsrewrite:gen\ntype KubePrismEndpointsSpec struct {\n\tEndpoints []KubePrismEndpoint `yaml:\"endpoints\" protobuf:\"1\"`\n}\n\n// KubePrismEndpoint holds data for control plane endpoint.\n//\n//gotagsrewrite:gen\ntype KubePrismEndpoint struct {\n\tHost string `yaml:\"host\" protobuf:\"1\"`\n\tPort uint32 `yaml:\"port\" protobuf:\"2\"`\n}\n\n// String returns string representation of KubePrismEndpoint.\nfunc (e KubePrismEndpoint) String() string {\n\treturn fmt.Sprintf(\"host: %s, port: %d\", e.Host, e.Port)\n}\n\n// KubePrismEndpointsExtension provides auxiliary methods for KubePrismEndpoints.\ntype KubePrismEndpointsExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (KubePrismEndpointsExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubePrismEndpointsType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Hosts\",\n\t\t\t\tJSONPath: \"{.endpoints[*].host}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Ports\",\n\t\t\t\tJSONPath: \"{.endpoints[*].port}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubePrismEndpointsSpec](KubePrismEndpointsType, &KubePrismEndpoints{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/manifest.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ManifestType is type of Manifest resource.\nconst ManifestType = resource.Type(\"Manifests.kubernetes.talos.dev\")\n\n// Manifest resource holds definition of kubelet static pod.\ntype Manifest = typed.Resource[ManifestSpec, ManifestExtension]\n\n// ManifestSpec holds the Kubernetes resources spec.\n//\n//gotagsrewrite:gen\ntype ManifestSpec struct {\n\tItems []SingleManifest `protobuf:\"1\" yaml:\"items\"`\n}\n\n// SingleManifest is a single manifest.\n//\n//gotagsrewrite:gen\ntype SingleManifest struct {\n\tObject map[string]any `protobuf:\"1\" yaml:\",inline\"`\n}\n\n// MarshalYAML implements yaml.Marshaler.\nfunc (spec ManifestSpec) MarshalYAML() (any, error) {\n\treturn spec.Items, nil\n}\n\n// NewManifest initializes an empty Manifest resource.\nfunc NewManifest(namespace resource.Namespace, id resource.ID) *Manifest {\n\treturn typed.NewResource[ManifestSpec, ManifestExtension](\n\t\tresource.NewMetadata(namespace, ManifestType, id, resource.VersionUndefined),\n\t\tManifestSpec{},\n\t)\n}\n\n// ManifestExtension provides auxiliary methods for Manifest.\ntype ManifestExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ManifestExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ManifestType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ManifestSpec](ManifestType, &Manifest{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/manifest_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ManifestStatusType is type of ManifestStatus resource.\nconst ManifestStatusType = resource.Type(\"ManifestStatuses.kubernetes.talos.dev\")\n\n// ManifestStatusID is a singleton resource ID.\nconst ManifestStatusID = resource.ID(\"manifests\")\n\n// ManifestStatus resource holds definition of kubelet static pod.\ntype ManifestStatus = typed.Resource[ManifestStatusSpec, ManifestStatusExtension]\n\n// ManifestStatusSpec describes manifest application status.\n//\n//gotagsrewrite:gen\ntype ManifestStatusSpec struct {\n\tManifestsApplied []string `yaml:\"manifestsApplied\" protobuf:\"1\"`\n}\n\n// NewManifestStatus initializes an empty ManifestStatus resource.\nfunc NewManifestStatus(namespace resource.Namespace) *ManifestStatus {\n\treturn typed.NewResource[ManifestStatusSpec, ManifestStatusExtension](\n\t\tresource.NewMetadata(namespace, ManifestStatusType, ManifestStatusID, resource.VersionUndefined),\n\t\tManifestStatusSpec{},\n\t)\n}\n\n// ManifestStatusExtension provides auxiliary methods for ManifestStatus.\ntype ManifestStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ManifestStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ManifestStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ManifestStatusSpec](ManifestStatusType, &ManifestStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/manifests_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// BootstrapManifestsConfigType is type of BootstrapManifestsConfig resource.\nconst BootstrapManifestsConfigType = resource.Type(\"BootstrapManifestsConfigs.kubernetes.talos.dev\")\n\n// BootstrapManifestsConfigID is a singleton resource ID for BootstrapManifestsConfig.\nconst BootstrapManifestsConfigID = resource.ID(\"manifests\")\n\n// BootstrapManifestsConfig represents configuration for bootstrap manifests.\ntype BootstrapManifestsConfig = typed.Resource[BootstrapManifestsConfigSpec, BootstrapManifestsConfigExtension]\n\n// BootstrapManifestsConfigSpec is configuration for bootstrap manifests.\n//\n//gotagsrewrite:gen\ntype BootstrapManifestsConfigSpec struct {\n\tServer        string `yaml:\"string\" protobuf:\"1\"`\n\tClusterDomain string `yaml:\"clusterDomain\" protobuf:\"2\"`\n\n\tPodCIDRs []string `yaml:\"podCIDRs\" protobuf:\"3\"`\n\n\tProxyEnabled bool     `yaml:\"proxyEnabled\" protobuf:\"4\"`\n\tProxyImage   string   `yaml:\"proxyImage\" protobuf:\"5\"`\n\tProxyArgs    []string `yaml:\"proxyArgs\" protobuf:\"6\"`\n\n\tCoreDNSEnabled bool   `yaml:\"coreDNSEnabled\" protobuf:\"7\"`\n\tCoreDNSImage   string `yaml:\"coreDNSImage\" protobuf:\"8\"`\n\n\tDNSServiceIP   string `yaml:\"dnsServiceIP\" protobuf:\"9\"`\n\tDNSServiceIPv6 string `yaml:\"dnsServiceIPv6\" protobuf:\"10\"`\n\n\tFlannelEnabled                    bool     `yaml:\"flannelEnabled\" protobuf:\"11\"`\n\tFlannelImage                      string   `yaml:\"flannelImage\" protobuf:\"12\"`\n\tFlannelExtraArgs                  []string `yaml:\"flannelExtraArgs\" protobuf:\"16\"`\n\tFlannelKubeServiceHost            string   `yaml:\"flannelKubeServiceHost\" protobuf:\"17\"`\n\tFlannelKubeServicePort            string   `yaml:\"flannelKubeServicePort\" protobuf:\"18\"`\n\tFlannelKubeNetworkPoliciesEnabled bool     `yaml:\"flannelKubeNetworkPoliciesEnabled\" protobuf:\"19\"`\n\tFlannelKubeNetworkPoliciesImage   string   `yaml:\"flannelKubeNetworkPoliciesImage\" protobuf:\"20\"`\n\n\tPodSecurityPolicyEnabled bool `yaml:\"podSecurityPolicyEnabled\" protobuf:\"14\"`\n\n\tTalosAPIServiceEnabled bool `yaml:\"talosAPIServiceEnabled\" protobuf:\"15\"`\n\n\tCNIName string `yaml:\"cniName\" protobuf:\"21\"`\n}\n\n// NewBootstrapManifestsConfig returns new BootstrapManifestsConfig resource.\nfunc NewBootstrapManifestsConfig() *BootstrapManifestsConfig {\n\treturn typed.NewResource[BootstrapManifestsConfigSpec, BootstrapManifestsConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, BootstrapManifestsConfigType, BootstrapManifestsConfigID, resource.VersionUndefined),\n\t\tBootstrapManifestsConfigSpec{})\n}\n\n// BootstrapManifestsConfigExtension defines BootstrapManifestsConfig resource definition.\ntype BootstrapManifestsConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (BootstrapManifestsConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             BootstrapManifestsConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[BootstrapManifestsConfigSpec](BootstrapManifestsConfigType, &BootstrapManifestsConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/node_annotation_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s //nolint:dupl\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeAnnotationSpecType is the type.\nconst NodeAnnotationSpecType = resource.Type(\"NodeAnnotationSpecs.k8s.talos.dev\")\n\n// NodeAnnotationSpecSpec represents an annoation that's attached to a Talos node.\n//\n//gotagsrewrite:gen\ntype NodeAnnotationSpecSpec struct {\n\tKey   string `yaml:\"key\" protobuf:\"1\"`\n\tValue string `yaml:\"value\" protobuf:\"2\"`\n}\n\n// NodeAnnotationSpec ...\ntype NodeAnnotationSpec = typed.Resource[NodeAnnotationSpecSpec, NodeAnnotationSpecExtension]\n\n// NewNodeAnnotationSpec initializes a NodeAnnotation resource.\nfunc NewNodeAnnotationSpec(id resource.ID) *NodeAnnotationSpec {\n\treturn typed.NewResource[NodeAnnotationSpecSpec, NodeAnnotationSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, NodeAnnotationSpecType, id, resource.VersionUndefined),\n\t\tNodeAnnotationSpecSpec{},\n\t)\n}\n\n// NodeAnnotationSpecExtension provides auxiliary methods for NodeAnnotation.\ntype NodeAnnotationSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (NodeAnnotationSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeAnnotationSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Value\",\n\t\t\t\tJSONPath: \"{.value}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeAnnotationSpecSpec](NodeAnnotationSpecType, &NodeAnnotationSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/node_cordoned_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeCordonedSpecType is the type.\nconst NodeCordonedSpecType = resource.Type(\"NodeCordonedSpecs.k8s.talos.dev\")\n\n// NodeCordonedSpecSpec represents an intention to make a node cordoned (unschedulable).\n//\n//gotagsrewrite:gen\ntype NodeCordonedSpecSpec struct{}\n\n// NodeCordonedID is the ID of the NodeCordonedSpec resource.\nconst NodeCordonedID = resource.ID(\"cordoned\")\n\n// NodeCordonedSpec ...\ntype NodeCordonedSpec = typed.Resource[NodeCordonedSpecSpec, NodeCordonedSpecExtension]\n\n// NewNodeCordonedSpec initializes a NodeLabel resource.\nfunc NewNodeCordonedSpec(id resource.ID) *NodeCordonedSpec {\n\treturn typed.NewResource[NodeCordonedSpecSpec, NodeCordonedSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, NodeCordonedSpecType, id, resource.VersionUndefined),\n\t\tNodeCordonedSpecSpec{},\n\t)\n}\n\n// NodeCordonedSpecExtension provides auxiliary methods for NodeLabel.\ntype NodeCordonedSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (NodeCordonedSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeCordonedSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeCordonedSpecSpec](NodeCordonedSpecType, &NodeCordonedSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/node_label_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s //nolint:dupl\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeLabelSpecType is the type.\nconst NodeLabelSpecType = resource.Type(\"NodeLabelSpecs.k8s.talos.dev\")\n\n// NodeLabelSpecSpec represents a label that's attached to a Talos node.\n//\n//gotagsrewrite:gen\ntype NodeLabelSpecSpec struct {\n\tKey   string `yaml:\"key\" protobuf:\"1\"`\n\tValue string `yaml:\"value\" protobuf:\"2\"`\n}\n\n// NodeLabelSpec ...\ntype NodeLabelSpec = typed.Resource[NodeLabelSpecSpec, NodeLabelSpecExtension]\n\n// NewNodeLabelSpec initializes a NodeLabel resource.\nfunc NewNodeLabelSpec(id resource.ID) *NodeLabelSpec {\n\treturn typed.NewResource[NodeLabelSpecSpec, NodeLabelSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, NodeLabelSpecType, id, resource.VersionUndefined),\n\t\tNodeLabelSpecSpec{},\n\t)\n}\n\n// NodeLabelSpecExtension provides auxiliary methods for NodeLabel.\ntype NodeLabelSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (NodeLabelSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeLabelSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Value\",\n\t\t\t\tJSONPath: \"{.value}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeLabelSpecSpec](NodeLabelSpecType, &NodeLabelSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/node_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeStatusType is type of NodeStatus resource.\nconst NodeStatusType = resource.Type(\"NodeStatuses.kubernetes.talos.dev\")\n\n// NodeStatus resource holds Kubernetes NodeStatus.\ntype NodeStatus = typed.Resource[NodeStatusSpec, NodeStatusExtension]\n\n// NodeStatusSpec describes Kubernetes NodeStatus.\n//\n//gotagsrewrite:gen\ntype NodeStatusSpec struct {\n\tNodename      string            `yaml:\"nodename\" protobuf:\"1\"`\n\tNodeReady     bool              `yaml:\"nodeReady\" protobuf:\"2\"`\n\tUnschedulable bool              `yaml:\"unschedulable\" protobuf:\"3\"`\n\tLabels        map[string]string `yaml:\"labels\" protobuf:\"4\"`\n\tAnnotations   map[string]string `yaml:\"annotations\" protobuf:\"5\"`\n\tPodCIDRs      []netip.Prefix    `yaml:\"podCIDRs\" protobuf:\"6\"`\n}\n\n// NewNodeStatus initializes a NodeStatus resource.\nfunc NewNodeStatus(namespace resource.Namespace, id resource.ID) *NodeStatus {\n\treturn typed.NewResource[NodeStatusSpec, NodeStatusExtension](\n\t\tresource.NewMetadata(namespace, NodeStatusType, id, resource.VersionUndefined),\n\t\tNodeStatusSpec{},\n\t)\n}\n\n// NodeStatusExtension provides auxiliary methods for NodeStatus.\ntype NodeStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: \"{.nodeReady}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Unschedulable\",\n\t\t\t\tJSONPath: \"{.unschedulable}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeStatusSpec](NodeStatusType, &NodeStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/node_taint_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeTaintSpecType is the type.\nconst NodeTaintSpecType = resource.Type(\"NodeTaintSpecs.k8s.talos.dev\")\n\n// NodeTaintSpecSpec represents a label that's attached to a Talos node.\n//\n//gotagsrewrite:gen\ntype NodeTaintSpecSpec struct {\n\tKey    string `yaml:\"key\" protobuf:\"1\"`\n\tEffect string `yaml:\"effect\" protobuf:\"2\"`\n\tValue  string `yaml:\"value\" protobuf:\"3\"`\n}\n\n// NodeTaintSpec ...\ntype NodeTaintSpec = typed.Resource[NodeTaintSpecSpec, NodeTaintSpecExtension]\n\n// NewNodeTaintSpec initializes a NodeLabel resource.\nfunc NewNodeTaintSpec(id resource.ID) *NodeTaintSpec {\n\treturn typed.NewResource[NodeTaintSpecSpec, NodeTaintSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, NodeTaintSpecType, id, resource.VersionUndefined),\n\t\tNodeTaintSpecSpec{},\n\t)\n}\n\n// NodeTaintSpecExtension provides auxiliary methods for NodeLabel.\ntype NodeTaintSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (NodeTaintSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeTaintSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Effect\",\n\t\t\t\tJSONPath: \"{.effect}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Value\",\n\t\t\t\tJSONPath: \"{.value}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeTaintSpecSpec](NodeTaintSpecType, &NodeTaintSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/nodeip.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeIPType is type of NodeIP resource.\nconst NodeIPType = resource.Type(\"NodeIPs.kubernetes.talos.dev\")\n\n// NodeIP resource holds definition of Node IP specification.\ntype NodeIP = typed.Resource[NodeIPSpec, NodeIPExtension]\n\n// NodeIPSpec holds the Node IP specification.\n//\n//gotagsrewrite:gen\ntype NodeIPSpec struct {\n\tAddresses []netip.Addr `yaml:\"addresses\" protobuf:\"1\"`\n}\n\n// NewNodeIP initializes an empty NodeIP resource.\nfunc NewNodeIP(namespace resource.Namespace, id resource.ID) *NodeIP {\n\treturn typed.NewResource[NodeIPSpec, NodeIPExtension](\n\t\tresource.NewMetadata(namespace, NodeIPType, id, resource.VersionUndefined),\n\t\tNodeIPSpec{},\n\t)\n}\n\n// NodeIPExtension provides auxiliary methods for NodeIP.\ntype NodeIPExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeIPExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeIPType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeIPSpec](NodeIPType, &NodeIP{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/nodeip_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeIPConfigType is type of NodeIPConfig resource.\nconst NodeIPConfigType = resource.Type(\"NodeIPConfigs.kubernetes.talos.dev\")\n\n// NodeIPConfig resource holds definition of Node IP specification.\ntype NodeIPConfig = typed.Resource[NodeIPConfigSpec, NodeIPConfigExtension]\n\n// NodeIPConfigSpec holds the Node IP specification.\n//\n//gotagsrewrite:gen\ntype NodeIPConfigSpec struct {\n\tValidSubnets   []string `yaml:\"validSubnets,omitempty\" protobuf:\"1\"`\n\tExcludeSubnets []string `yaml:\"excludeSubnets\" protobuf:\"2\"`\n}\n\n// NewNodeIPConfig initializes an empty NodeIPConfig resource.\nfunc NewNodeIPConfig(namespace resource.Namespace, id resource.ID) *NodeIPConfig {\n\treturn typed.NewResource[NodeIPConfigSpec, NodeIPConfigExtension](\n\t\tresource.NewMetadata(namespace, NodeIPConfigType, id, resource.VersionUndefined),\n\t\tNodeIPConfigSpec{},\n\t)\n}\n\n// NodeIPConfigExtension provides auxiliary methods for NodeIPConfig.\ntype NodeIPConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeIPConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeIPConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeIPConfigSpec](NodeIPConfigType, &NodeIPConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/nodename.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodenameType is type of Nodename resource.\nconst NodenameType = resource.Type(\"Nodenames.kubernetes.talos.dev\")\n\n// NodenameID is a singleton resource ID for Nodename.\nconst NodenameID = resource.ID(\"nodename\")\n\n// Nodename resource holds Kubernetes nodename.\ntype Nodename = typed.Resource[NodenameSpec, NodenameExtension]\n\n// NodenameSpec describes Kubernetes nodename.\n//\n//gotagsrewrite:gen\ntype NodenameSpec struct {\n\tNodename             string `yaml:\"nodename\" protobuf:\"1\"`\n\tHostnameVersion      string `yaml:\"hostnameVersion\" protobuf:\"2\"`\n\tSkipNodeRegistration bool   `yaml:\"skipNodeRegistration\" protobuf:\"3\"`\n}\n\n// NewNodename initializes a Nodename resource.\nfunc NewNodename(namespace resource.Namespace, id resource.ID) *Nodename {\n\treturn typed.NewResource[NodenameSpec, NodenameExtension](\n\t\tresource.NewMetadata(namespace, NodenameType, id, resource.VersionUndefined),\n\t\tNodenameSpec{},\n\t)\n}\n\n// NodenameExtension provides auxiliary methods for Nodename.\ntype NodenameExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodenameExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodenameType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Nodename\",\n\t\t\t\tJSONPath: \"{.nodename}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodenameSpec](NodenameType, &Nodename{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/scheduler_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SchedulerConfigType is type of SchedulerConfig resource.\nconst SchedulerConfigType = resource.Type(\"SchedulerConfigs.kubernetes.talos.dev\")\n\n// SchedulerConfigID is a singleton resource ID for SchedulerConfig.\nconst SchedulerConfigID = resource.ID(SchedulerID)\n\n// SchedulerConfig represents configuration for kube-scheduler.\ntype SchedulerConfig = typed.Resource[SchedulerConfigSpec, SchedulerConfigExtension]\n\n// SchedulerConfigSpec is configuration for kube-scheduler.\n//\n//gotagsrewrite:gen\ntype SchedulerConfigSpec struct {\n\tEnabled              bool                 `yaml:\"enabled\" protobuf:\"1\"`\n\tImage                string               `yaml:\"image\" protobuf:\"2\"`\n\tExtraArgs            map[string]ArgValues `yaml:\"extraArgs\" protobuf:\"3\"`\n\tExtraVolumes         []ExtraVolume        `yaml:\"extraVolumes\" protobuf:\"4\"`\n\tEnvironmentVariables map[string]string    `yaml:\"environmentVariables\" protobuf:\"5\"`\n\tResources            Resources            `yaml:\"resources\" protobuf:\"6\"`\n\tConfig               map[string]any       `yaml:\"config\" protobuf:\"7\"`\n}\n\n// NewSchedulerConfig returns new SchedulerConfig resource.\nfunc NewSchedulerConfig() *SchedulerConfig {\n\treturn typed.NewResource[SchedulerConfigSpec, SchedulerConfigExtension](\n\t\tresource.NewMetadata(ControlPlaneNamespaceName, SchedulerConfigType, SchedulerConfigID, resource.VersionUndefined),\n\t\tSchedulerConfigSpec{})\n}\n\n// SchedulerConfigExtension defines SchedulerConfig resource definition.\ntype SchedulerConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (SchedulerConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SchedulerConfigType,\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SchedulerConfigSpec](SchedulerConfigType, &SchedulerConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/secrets_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package k8s provides resources which interface with Kubernetes.\n//\n//nolint:dupl\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SecretsStatusType is type of SecretsStatus resource.\nconst SecretsStatusType = resource.Type(\"SecretStatuses.kubernetes.talos.dev\")\n\n// StaticPodSecretsStaticPodID is resource ID for SecretStatus resource for static pods.\nconst StaticPodSecretsStaticPodID = resource.ID(\"static-pods\")\n\n// SecretsStatus resource holds definition of rendered secrets.\ntype SecretsStatus = typed.Resource[SecretsStatusSpec, SecretsStatusExtension]\n\n// SecretsStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype SecretsStatusSpec struct {\n\tReady   bool   `yaml:\"ready\" protobuf:\"1\"`\n\tVersion string `yaml:\"version\" protobuf:\"2\"`\n}\n\n// NewSecretsStatus initializes a SecretsStatus resource.\nfunc NewSecretsStatus(namespace resource.Namespace, id resource.ID) *SecretsStatus {\n\treturn typed.NewResource[SecretsStatusSpec, SecretsStatusExtension](\n\t\tresource.NewMetadata(namespace, SecretsStatusType, id, resource.VersionUndefined),\n\t\tSecretsStatusSpec{},\n\t)\n}\n\n// SecretsStatusExtension provides auxiliary methods for SecretsStatus.\ntype SecretsStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (SecretsStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SecretsStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: ControlPlaneNamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: \"{.ready}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Secrets Version\",\n\t\t\t\tJSONPath: \"{.version}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SecretsStatusSpec](SecretsStatusType, &SecretsStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/static_pod.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// StaticPodType is type of StaticPod resource.\nconst StaticPodType = resource.Type(\"StaticPods.kubernetes.talos.dev\")\n\n// StaticPod resource holds definition of kubelet static pod.\ntype StaticPod = typed.Resource[StaticPodSpec, StaticPodExtension]\n\n// StaticPodSpec describes static pod spec, it contains marshaled *v1.Pod spec.\n//\n//gotagsrewrite:gen\ntype StaticPodSpec struct {\n\tPod map[string]any `protobuf:\"1\"`\n}\n\n// MarshalYAML implements yaml.Marshaler.\nfunc (spec StaticPodSpec) MarshalYAML() (any, error) {\n\treturn spec.Pod, nil\n}\n\n// NewStaticPod initializes a StaticPod resource.\nfunc NewStaticPod(namespace resource.Namespace, id resource.ID) *StaticPod {\n\treturn typed.NewResource[StaticPodSpec, StaticPodExtension](\n\t\tresource.NewMetadata(namespace, StaticPodType, id, resource.VersionUndefined),\n\t\tStaticPodSpec{},\n\t)\n}\n\n// StaticPodExtension provides auxiliary methods for StaticPod.\ntype StaticPodExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (StaticPodExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StaticPodType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StaticPodSpec](StaticPodType, &StaticPod{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/static_pod_server_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// StaticPodServerStatusType is type of StaticPodServerStatus resource.\nconst StaticPodServerStatusType = resource.Type(\"StaticPodServerStatuses.kubernetes.talos.dev\")\n\n// StaticPodServerStatus resource holds definition of kubelet static pod.\ntype StaticPodServerStatus = typed.Resource[StaticPodServerStatusSpec, StaticPodServerStatusExtension]\n\n// StaticPodServerStatusSpec describes static pod spec, it contains marshaled *v1.Pod spec.\n//\n//gotagsrewrite:gen\ntype StaticPodServerStatusSpec struct {\n\tURL string `yaml:\"url\" protobuf:\"1\"`\n}\n\n// StaticPodServerStatusResourceID is the resource ID under which the static pod server status will be saved.\nconst StaticPodServerStatusResourceID = \"static-pod-server-status\"\n\n// NewStaticPodServerStatus initializes a StaticPodServerStatus resource.\nfunc NewStaticPodServerStatus(namespace resource.Namespace, id resource.ID) *StaticPodServerStatus {\n\treturn typed.NewResource[StaticPodServerStatusSpec, StaticPodServerStatusExtension](\n\t\tresource.NewMetadata(namespace, StaticPodServerStatusType, id, resource.VersionUndefined),\n\t\tStaticPodServerStatusSpec{},\n\t)\n}\n\n// StaticPodServerStatusExtension provides auxiliary methods for StaticPodServerStatus.\ntype StaticPodServerStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (StaticPodServerStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StaticPodServerStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StaticPodServerStatusSpec](StaticPodServerStatusType, &StaticPodServerStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/k8s/static_pod_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage k8s\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// StaticPodStatusType is type of StaticPodStatus resource.\nconst StaticPodStatusType = resource.Type(\"StaticPodStatuses.kubernetes.talos.dev\")\n\n// StaticPodStatus resource holds definition of kubelet static pod.\ntype StaticPodStatus = typed.Resource[StaticPodStatusSpec, StaticPodStatusExtension]\n\n// StaticPodStatusSpec describes kubelet static pod status.\n//\n//gotagsrewrite:gen\ntype StaticPodStatusSpec struct {\n\tPodStatus map[string]any `protobuf:\"1\"`\n}\n\n// MarshalYAML implements yaml.Marshaler.\nfunc (spec StaticPodStatusSpec) MarshalYAML() (any, error) {\n\treturn spec.PodStatus, nil\n}\n\n// NewStaticPodStatus initializes a StaticPodStatus resource.\nfunc NewStaticPodStatus(namespace resource.Namespace, id resource.ID) *StaticPodStatus {\n\treturn typed.NewResource[StaticPodStatusSpec, StaticPodStatusExtension](\n\t\tresource.NewMetadata(namespace, StaticPodStatusType, id, resource.VersionUndefined),\n\t\tStaticPodStatusSpec{},\n\t)\n}\n\n// StaticPodStatusExtension provides auxiliary methods for StaticPodStatus.\ntype StaticPodStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (StaticPodStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StaticPodStatusType,\n\t\tAliases:          []resource.Type{\"podstatus\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: `{.conditions[?(@.type==\"Ready\")].status}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StaticPodStatusSpec](StaticPodStatusType, &StaticPodStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubeaccess/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// ConfigType is type of Config resource.\nconst ConfigType = resource.Type(\"KubernetesAccessConfigs.cluster.talos.dev\")\n\n// ConfigID the singleton config resource ID.\nconst ConfigID = resource.ID(\"config\")\n\n// Config resource holds KubeSpan configuration.\ntype Config = typed.Resource[ConfigSpec, ConfigExtension]\n\n// ConfigSpec describes KubeSpan configuration..\n//\n//gotagsrewrite:gen\ntype ConfigSpec struct {\n\tEnabled                     bool     `yaml:\"enabled\" protobuf:\"1\"`\n\tAllowedAPIRoles             []string `yaml:\"allowedAPIRoles\" protobuf:\"2\"`\n\tAllowedKubernetesNamespaces []string `yaml:\"allowedKubernetesNamespaces\" protobuf:\"3\"`\n}\n\n// DeepCopy generates a deep copy of ConfigSpec.\nfunc (cs ConfigSpec) DeepCopy() ConfigSpec {\n\tcp := cs\n\n\tif cs.AllowedAPIRoles != nil {\n\t\tcp.AllowedAPIRoles = make([]string, len(cs.AllowedAPIRoles))\n\t\tcopy(cp.AllowedAPIRoles, cs.AllowedAPIRoles)\n\t}\n\n\tif cs.AllowedKubernetesNamespaces != nil {\n\t\tcp.AllowedKubernetesNamespaces = make([]string, len(cs.AllowedKubernetesNamespaces))\n\t\tcopy(cp.AllowedKubernetesNamespaces, cs.AllowedKubernetesNamespaces)\n\t}\n\n\treturn cp\n}\n\n// NewConfig initializes a Config resource.\nfunc NewConfig(namespace resource.Namespace, id resource.ID) *Config {\n\treturn typed.NewResource[ConfigSpec, ConfigExtension](\n\t\tresource.NewMetadata(namespace, ConfigType, id, resource.VersionUndefined),\n\t\tConfigSpec{},\n\t)\n}\n\n// ConfigExtension provides auxiliary methods for Config.\ntype ConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (c ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.NonSensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigSpec](ConfigType, &Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubeaccess/kubeaccess.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubeaccess provides resources related to the Talos API access from Kubernetes workloads.\npackage kubeaccess\n"
  },
  {
    "path": "pkg/machinery/resources/kubeaccess/kubeaccess_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubeaccess_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubeaccess\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&kubeaccess.Config{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ConfigSpec -type EndpointSpec -type IdentitySpec -type PeerSpecSpec -type PeerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// ConfigType is type of Config resource.\nconst ConfigType = resource.Type(\"KubeSpanConfigs.kubespan.talos.dev\")\n\n// ConfigID the singleton config resource ID.\nconst ConfigID = resource.ID(\"kubespan\")\n\n// Config resource holds KubeSpan configuration.\ntype Config = typed.Resource[ConfigSpec, ConfigExtension]\n\n// ConfigSpec describes KubeSpan configuration..\n//\n//gotagsrewrite:gen\ntype ConfigSpec struct {\n\tEnabled      bool   `yaml:\"enabled\" protobuf:\"1\"`\n\tClusterID    string `yaml:\"clusterId\" protobuf:\"2\"`\n\tSharedSecret string `yaml:\"sharedSecret\" protobuf:\"3\"`\n\t// Force routing via KubeSpan even if the peer connection is not up.\n\tForceRouting bool `yaml:\"forceRouting\" protobuf:\"4\"`\n\t// Advertise Kubernetes pod networks or skip it completely.\n\tAdvertiseKubernetesNetworks bool `yaml:\"advertiseKubernetesNetworks\" protobuf:\"5\"`\n\t// Force kubeSpan MTU size.\n\tMTU uint32 `yaml:\"mtu,omitempty\" protobuf:\"6\"`\n\t// If not empty, filter advertised endpoints using the list of CIDRs.\n\tEndpointFilters []string `yaml:\"endpointFilters,omitempty\" protobuf:\"7\"`\n\t// Harvest endpoints from the peer statuses.\n\tHarvestExtraEndpoints bool `yaml:\"harvestExtraEndpoints\" protobuf:\"8\"`\n\t// Extra endpoints to announce.\n\tExtraEndpoints []netip.AddrPort `yaml:\"extraEndpoints,omitempty\" protobuf:\"9\"`\n\t// If not empty, filter advertised networks using the list of CIDRs.\n\tExcludeAdvertisedNetworks []netip.Prefix `yaml:\"excludeAdvertisedNetworks,omitempty\" protobuf:\"10\"`\n}\n\n// NewConfig initializes a Config resource.\nfunc NewConfig(namespace resource.Namespace, id resource.ID) *Config {\n\treturn typed.NewResource[ConfigSpec, ConfigExtension](\n\t\tresource.NewMetadata(namespace, ConfigType, id, resource.VersionUndefined),\n\t\tConfigSpec{},\n\t)\n}\n\n// ConfigExtension provides auxiliary methods for Config.\ntype ConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigSpec](ConfigType, &Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ConfigSpec -type EndpointSpec -type IdentitySpec -type PeerSpecSpec -type PeerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n)\n\n// DeepCopy generates a deep copy of ConfigSpec.\nfunc (o ConfigSpec) DeepCopy() ConfigSpec {\n\tvar cp ConfigSpec = o\n\tif o.EndpointFilters != nil {\n\t\tcp.EndpointFilters = make([]string, len(o.EndpointFilters))\n\t\tcopy(cp.EndpointFilters, o.EndpointFilters)\n\t}\n\tif o.ExtraEndpoints != nil {\n\t\tcp.ExtraEndpoints = make([]netip.AddrPort, len(o.ExtraEndpoints))\n\t\tcopy(cp.ExtraEndpoints, o.ExtraEndpoints)\n\t}\n\tif o.ExcludeAdvertisedNetworks != nil {\n\t\tcp.ExcludeAdvertisedNetworks = make([]netip.Prefix, len(o.ExcludeAdvertisedNetworks))\n\t\tcopy(cp.ExcludeAdvertisedNetworks, o.ExcludeAdvertisedNetworks)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EndpointSpec.\nfunc (o EndpointSpec) DeepCopy() EndpointSpec {\n\tvar cp EndpointSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of IdentitySpec.\nfunc (o IdentitySpec) DeepCopy() IdentitySpec {\n\tvar cp IdentitySpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PeerSpecSpec.\nfunc (o PeerSpecSpec) DeepCopy() PeerSpecSpec {\n\tvar cp PeerSpecSpec = o\n\tif o.AllowedIPs != nil {\n\t\tcp.AllowedIPs = make([]netip.Prefix, len(o.AllowedIPs))\n\t\tcopy(cp.AllowedIPs, o.AllowedIPs)\n\t}\n\tif o.Endpoints != nil {\n\t\tcp.Endpoints = make([]netip.AddrPort, len(o.Endpoints))\n\t\tcopy(cp.Endpoints, o.Endpoints)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PeerStatusSpec.\nfunc (o PeerStatusSpec) DeepCopy() PeerStatusSpec {\n\tvar cp PeerStatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/endpoint.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EndpointType is type of Endpoint resource.\nconst EndpointType = resource.Type(\"KubeSpanEndpoints.kubespan.talos.dev\")\n\n// Endpoint is produced from KubeSpanPeerStatuses by mapping back discovered endpoints to the affiliates.\n//\n// Endpoint is identified by the public key of the peer.\ntype Endpoint = typed.Resource[EndpointSpec, EndpointExtension]\n\n// EndpointSpec describes Endpoint state.\n//\n//gotagsrewrite:gen\ntype EndpointSpec struct {\n\tAffiliateID string         `yaml:\"affiliateID\" protobuf:\"1\"`\n\tEndpoint    netip.AddrPort `yaml:\"endpoint\" protobuf:\"2\"`\n}\n\n// NewEndpoint initializes a Endpoint resource.\nfunc NewEndpoint(namespace resource.Namespace, id resource.ID) *Endpoint {\n\treturn typed.NewResource[EndpointSpec, EndpointExtension](\n\t\tresource.NewMetadata(namespace, EndpointType, id, resource.VersionUndefined),\n\t\tEndpointSpec{},\n\t)\n}\n\n// EndpointExtension provides auxiliary methods for Endpoint.\ntype EndpointExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (EndpointExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EndpointType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Endpoint\",\n\t\t\t\tJSONPath: `{.endpoint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Affiliate ID\",\n\t\t\t\tJSONPath: `{.affiliateID}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EndpointSpec](EndpointType, &Endpoint{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/identity.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// IdentityType is type of Identity resource.\nconst IdentityType = resource.Type(\"KubeSpanIdentities.kubespan.talos.dev\")\n\n// LocalIdentity is the resource ID for the local node KubeSpan identity.\nconst LocalIdentity = resource.ID(\"local\")\n\n// Identity resource holds node identity (as a member of the cluster).\ntype Identity = typed.Resource[IdentitySpec, IdentityExtension]\n\n// IdentitySpec describes KubeSpan keys and address.\n//\n// Note: IdentitySpec is persisted on disk in the STATE partition,\n// so YAML serialization should be kept backwards compatible.\n//\n//gotagsrewrite:gen\ntype IdentitySpec struct {\n\t// Address of the node on the Wireguard network.\n\tAddress netip.Prefix `yaml:\"address\" protobuf:\"1\"`\n\tSubnet  netip.Prefix `yaml:\"subnet\" protobuf:\"2\"`\n\t// Public and private Wireguard keys.\n\tPrivateKey string `yaml:\"privateKey\" protobuf:\"3\"`\n\tPublicKey  string `yaml:\"publicKey\" protobuf:\"4\"`\n}\n\n// NewIdentity initializes a Identity resource.\nfunc NewIdentity(namespace resource.Namespace, id resource.ID) *Identity {\n\treturn typed.NewResource[IdentitySpec, IdentityExtension](\n\t\tresource.NewMetadata(namespace, IdentityType, id, resource.VersionUndefined),\n\t\tIdentitySpec{},\n\t)\n}\n\n// IdentityExtension provides auxiliary methods for Identity.\ntype IdentityExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (IdentityExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             IdentityType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Address\",\n\t\t\t\tJSONPath: `{.address}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PublicKey\",\n\t\t\t\tJSONPath: `{.publicKey}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[IdentitySpec](IdentityType, &Identity{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/kubespan.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains resources related to KubeSpan.\nconst NamespaceName resource.Namespace = \"kubespan\"\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/kubespan_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/kubespan\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&kubespan.Config{},\n\t\t&kubespan.Endpoint{},\n\t\t&kubespan.Identity{},\n\t\t&kubespan.PeerSpec{},\n\t\t&kubespan.PeerStatus{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/peer_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PeerSpecType is type of PeerSpec resource.\nconst PeerSpecType = resource.Type(\"KubeSpanPeerSpecs.kubespan.talos.dev\")\n\n// PeerSpec is produced from cluster.Affiliate which has KubeSpan information attached.\n//\n// PeerSpec is identified by the public key.\ntype PeerSpec = typed.Resource[PeerSpecSpec, PeerSpecExtension]\n\n// PeerSpecSpec describes PeerSpec state.\n//\n//gotagsrewrite:gen\ntype PeerSpecSpec struct {\n\tAddress    netip.Addr       `yaml:\"address\" protobuf:\"1\"`\n\tAllowedIPs []netip.Prefix   `yaml:\"allowedIPs\" protobuf:\"2\"`\n\tEndpoints  []netip.AddrPort `yaml:\"endpoints\" protobuf:\"3\"`\n\tLabel      string           `yaml:\"label\" protobuf:\"4\"`\n}\n\n// NewPeerSpec initializes a PeerSpec resource.\nfunc NewPeerSpec(namespace resource.Namespace, id resource.ID) *PeerSpec {\n\treturn typed.NewResource[PeerSpecSpec, PeerSpecExtension](\n\t\tresource.NewMetadata(namespace, PeerSpecType, id, resource.VersionUndefined),\n\t\tPeerSpecSpec{},\n\t)\n}\n\n// PeerSpecExtension provides auxiliary methods for PeerSpec.\ntype PeerSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PeerSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PeerSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Label\",\n\t\t\t\tJSONPath: `{.label}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Endpoints\",\n\t\t\t\tJSONPath: `{.endpoints}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PeerSpecSpec](PeerSpecType, &PeerSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/peer_state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport \"fmt\"\n\n//go:generate go tool golang.org/x/tools/cmd/stringer -type=PeerState -linecomment\n\n// PeerState is KubeSpan peer current state.\ntype PeerState int\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (v PeerState) MarshalText() ([]byte, error) {\n\treturn []byte(v.String()), nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (v *PeerState) UnmarshalText(b []byte) error {\n\tswitch string(b) {\n\tcase \"unknown\":\n\t\t*v = PeerStateUnknown\n\tcase \"up\":\n\t\t*v = PeerStateUp\n\tcase \"down\":\n\t\t*v = PeerStateDown\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported value for PeerState: %q\", string(b))\n\t}\n\n\treturn nil\n}\n\n// PeerState constants.\n//\n//structprotogen:gen_enum\nconst (\n\tPeerStateUnknown PeerState = iota // unknown\n\tPeerStateUp                       // up\n\tPeerStateDown                     // down\n)\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/peer_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage kubespan\n\nimport (\n\t\"net/netip\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PeerStatusType is type of PeerStatus resource.\nconst PeerStatusType = resource.Type(\"KubeSpanPeerStatuses.kubespan.talos.dev\")\n\n// PeerStatus the Wireguard peer state for KubeSpan.\n//\n// PeerStatus is identified by the public key.\ntype PeerStatus = typed.Resource[PeerStatusSpec, PeerStatusExtension]\n\n// PeerStatusSpec describes PeerStatus state.\n//\n//gotagsrewrite:gen\ntype PeerStatusSpec struct {\n\t// Active endpoint as seen by the Wireguard.\n\tEndpoint netip.AddrPort `yaml:\"endpoint\" protobuf:\"1\"`\n\t// Label derived from the peer spec.\n\tLabel string `yaml:\"label\" protobuf:\"2\"`\n\t// Calculated state.\n\tState PeerState `yaml:\"state\" protobuf:\"3\"`\n\t// Tx/Rx bytes.\n\tReceiveBytes  int64 `yaml:\"receiveBytes\" protobuf:\"4\"`\n\tTransmitBytes int64 `yaml:\"transmitBytes\" protobuf:\"5\"`\n\t// Handshake.\n\tLastHandshakeTime time.Time `yaml:\"lastHandshakeTime\" protobuf:\"6\"`\n\t// Endpoint selection input.\n\tLastUsedEndpoint   netip.AddrPort `yaml:\"lastUsedEndpoint\" protobuf:\"7\"`\n\tLastEndpointChange time.Time      `yaml:\"lastEndpointChange\" protobuf:\"8\"`\n}\n\n// NewPeerStatus initializes a PeerStatus resource.\nfunc NewPeerStatus(namespace resource.Namespace, id resource.ID) *PeerStatus {\n\treturn typed.NewResource[PeerStatusSpec, PeerStatusExtension](\n\t\tresource.NewMetadata(namespace, PeerStatusType, id, resource.VersionUndefined),\n\t\tPeerStatusSpec{},\n\t)\n}\n\n// PeerStatusExtension provides auxiliary methods for PeerStatus.\ntype PeerStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PeerStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PeerStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Label\",\n\t\t\t\tJSONPath: `{.label}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Endpoint\",\n\t\t\t\tJSONPath: `{.endpoint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"State\",\n\t\t\t\tJSONPath: `{.state}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Rx\",\n\t\t\t\tJSONPath: `{.receiveBytes}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Tx\",\n\t\t\t\tJSONPath: `{.transmitBytes}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PeerStatusSpec](PeerStatusType, &PeerStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/kubespan/peerstate_string.go",
    "content": "// Code generated by \"stringer -type=PeerState -linecomment\"; DO NOT EDIT.\n\npackage kubespan\n\nimport \"strconv\"\n\nfunc _() {\n\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n\t// Re-run the stringer command to generate them again.\n\tvar x [1]struct{}\n\t_ = x[PeerStateUnknown-0]\n\t_ = x[PeerStateUp-1]\n\t_ = x[PeerStateDown-2]\n}\n\nconst _PeerState_name = \"unknownupdown\"\n\nvar _PeerState_index = [...]uint8{0, 7, 9, 13}\n\nfunc (i PeerState) String() string {\n\tidx := int(i) - 0\n\tif i < 0 || idx >= len(_PeerState_index)-1 {\n\t\treturn \"PeerState(\" + strconv.FormatInt(int64(i), 10) + \")\"\n\t}\n\treturn _PeerState_name[_PeerState_index[idx]:_PeerState_index[idx+1]]\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/address_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type AddressSpecSpec -type AddressStatusSpec -type BondMasterSpec -type DNSResolveCacheSpec -type EthernetSpecSpec -type EthernetStatusSpec -type HardwareAddrSpec -type HostDNSConfigSpec -type HostnameSpecSpec -type HostnameStatusSpec -type LinkAliasSpecSpec -type LinkRefreshSpec -type LinkSpecSpec -type LinkStatusSpec -type NfTablesChainSpec -type NodeAddressSpec -type NodeAddressSortAlgorithmSpec -type NodeAddressFilterSpec -type OperatorSpecSpec -type PlatformConfigSpec -type ProbeSpecSpec -type ProbeStatusSpec -type ResolverSpecSpec -type ResolverStatusSpec -type RouteSpecSpec -type RouteStatusSpec -type RoutingRuleSpecSpec -type RoutingRuleStatusSpec -type StatusSpec -type TimeServerSpecSpec -type TimeServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// AddressSpecType is type of AddressSpec resource.\nconst AddressSpecType = resource.Type(\"AddressSpecs.net.talos.dev\")\n\n// AddressSpec resource holds physical network link status.\ntype AddressSpec = typed.Resource[AddressSpecSpec, AddressSpecExtension]\n\n// AddressSpecSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype AddressSpecSpec struct {\n\tAddress         netip.Prefix            `yaml:\"address\" protobuf:\"1\"`\n\tLinkName        string                  `yaml:\"linkName\" protobuf:\"2\"`\n\tFamily          nethelpers.Family       `yaml:\"family\" protobuf:\"3\"`\n\tScope           nethelpers.Scope        `yaml:\"scope\" protobuf:\"4\"`\n\tFlags           nethelpers.AddressFlags `yaml:\"flags\" protobuf:\"5\"`\n\tAnnounceWithARP bool                    `yaml:\"announceWithARP,omitempty\" protobuf:\"6\"`\n\tPriority        uint32                  `yaml:\"priority,omitempty\" protobuf:\"8\"`\n\tConfigLayer     ConfigLayer             `yaml:\"layer\" protobuf:\"7\"`\n}\n\n// NewAddressSpec initializes a AddressSpec resource.\nfunc NewAddressSpec(namespace resource.Namespace, id resource.ID) *AddressSpec {\n\treturn typed.NewResource[AddressSpecSpec, AddressSpecExtension](\n\t\tresource.NewMetadata(namespace, AddressSpecType, id, resource.VersionUndefined),\n\t\tAddressSpecSpec{},\n\t)\n}\n\n// AddressSpecExtension provides auxiliary methods for AddressSpec.\ntype AddressSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (AddressSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AddressSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AddressSpecSpec](AddressSpecType, &AddressSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/address_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestAddressSpecMarshalYAML(t *testing.T) {\n\tspec := network.AddressSpecSpec{\n\t\tAddress:     netip.MustParsePrefix(\"192.168.3.6/27\"),\n\t\tLinkName:    \"eth0\",\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tScope:       nethelpers.ScopeLink,\n\t\tFlags:       nethelpers.AddressFlags(nethelpers.AddressPermanent),\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"address: 192.168.3.6/27\\nlinkName: eth0\\nfamily: inet4\\nscope: link\\nflags: permanent\\nlayer: configuration\\n\", string(marshaled))\n\n\tvar spec2 network.AddressSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/address_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// AddressStatusType is type of AddressStatus resource.\nconst AddressStatusType = resource.Type(\"AddressStatuses.net.talos.dev\")\n\n// AddressStatus resource holds physical network link status.\ntype AddressStatus = typed.Resource[AddressStatusSpec, AddressStatusExtension]\n\n// AddressStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype AddressStatusSpec struct {\n\tAddress   netip.Prefix            `yaml:\"address\" protobuf:\"1\"`\n\tLocal     netip.Addr              `yaml:\"local,omitempty\" protobuf:\"2\"`\n\tBroadcast netip.Addr              `yaml:\"broadcast,omitempty\" protobuf:\"3\"`\n\tAnycast   netip.Addr              `yaml:\"anycast,omitempty\" protobuf:\"4\"`\n\tMulticast netip.Addr              `yaml:\"multicast,omitempty\" protobuf:\"5\"`\n\tLinkIndex uint32                  `yaml:\"linkIndex\" protobuf:\"6\"`\n\tLinkName  string                  `yaml:\"linkName\" protobuf:\"7\"`\n\tFamily    nethelpers.Family       `yaml:\"family\" protobuf:\"8\"`\n\tScope     nethelpers.Scope        `yaml:\"scope\" protobuf:\"9\"`\n\tFlags     nethelpers.AddressFlags `yaml:\"flags\" protobuf:\"10\"`\n\tPriority  uint32                  `yaml:\"priority\" protobuf:\"11\"`\n}\n\n// NewAddressStatus initializes a AddressStatus resource.\nfunc NewAddressStatus(namespace resource.Namespace, id resource.ID) *AddressStatus {\n\treturn typed.NewResource[AddressStatusSpec, AddressStatusExtension](\n\t\tresource.NewMetadata(namespace, AddressStatusType, id, resource.VersionUndefined),\n\t\tAddressStatusSpec{},\n\t)\n}\n\n// AddressStatusExtension provides auxiliary methods for AddressStatus.\ntype AddressStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (AddressStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AddressStatusType,\n\t\tAliases:          []resource.Type{\"address\", \"addresses\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Address\",\n\t\t\t\tJSONPath: `{.address}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Link\",\n\t\t\t\tJSONPath: `{.linkName}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AddressStatusSpec](AddressStatusType, &AddressStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/condition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// ReadyCondition implements condition which waits for the network to be ready.\ntype ReadyCondition struct {\n\tstate  state.State\n\tchecks []StatusCheck\n}\n\n// NewReadyCondition builds a condition which waits for the network to be ready.\nfunc NewReadyCondition(state state.State, checks ...StatusCheck) *ReadyCondition {\n\treturn &ReadyCondition{\n\t\tstate:  state,\n\t\tchecks: checks,\n\t}\n}\n\nfunc (condition *ReadyCondition) String() string {\n\treturn \"network\"\n}\n\n// Wait implements condition interface.\nfunc (condition *ReadyCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, StatusType, StatusID, resource.VersionUndefined),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\tstatus := r.(*Status).TypedSpec()\n\n\t\t\tfor _, check := range condition.checks {\n\t\t\t\tif !check(status) {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n\n// StatusCheck asserts specific part of Status to be true.\ntype StatusCheck func(*StatusSpec) bool\n\n// AddressReady checks if address is ready.\nfunc AddressReady(spec *StatusSpec) bool {\n\treturn spec.AddressReady\n}\n\n// ConnectivityReady checks if connectivity is ready.\nfunc ConnectivityReady(spec *StatusSpec) bool {\n\treturn spec.ConnectivityReady\n}\n\n// HostnameReady checks if hostname is ready.\nfunc HostnameReady(spec *StatusSpec) bool {\n\treturn spec.HostnameReady\n}\n\n// EtcFilesReady checks if etc files are ready.\nfunc EtcFilesReady(spec *StatusSpec) bool {\n\treturn spec.EtcFilesReady\n}\n\n// StatusChecksFromStatuses converts nethelpers.Status list into list of checks.\nfunc StatusChecksFromStatuses(statuses ...nethelpers.Status) []StatusCheck {\n\tchecks := make([]StatusCheck, 0, len(statuses))\n\n\tfor _, st := range statuses {\n\t\tswitch st {\n\t\tcase nethelpers.StatusAddresses:\n\t\t\tchecks = append(checks, AddressReady)\n\t\tcase nethelpers.StatusConnectivity:\n\t\t\tchecks = append(checks, ConnectivityReady)\n\t\tcase nethelpers.StatusHostname:\n\t\t\tchecks = append(checks, HostnameReady)\n\t\tcase nethelpers.StatusEtcFiles:\n\t\t\tchecks = append(checks, EtcFilesReady)\n\t\t}\n\t}\n\n\treturn checks\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/condition_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestCondition(t *testing.T) {\n\tctx, ctxCancel := context.WithTimeout(t.Context(), time.Second)\n\tt.Cleanup(ctxCancel)\n\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tName     string\n\t\tStatus   network.StatusSpec\n\t\tChecks   []network.StatusCheck\n\t\tSucceeds bool\n\t}{\n\t\t{\n\t\t\tName:     \"no checks\",\n\t\t\tSucceeds: true,\n\t\t},\n\t\t{\n\t\t\tName:     \"timeout\",\n\t\t\tChecks:   []network.StatusCheck{network.AddressReady, network.ConnectivityReady},\n\t\t\tSucceeds: false,\n\t\t},\n\t\t{\n\t\t\tName: \"partial\",\n\t\t\tStatus: network.StatusSpec{\n\t\t\t\tAddressReady: true,\n\t\t\t},\n\t\t\tChecks:   []network.StatusCheck{network.AddressReady, network.ConnectivityReady},\n\t\t\tSucceeds: false,\n\t\t},\n\t\t{\n\t\t\tName: \"okay\",\n\t\t\tStatus: network.StatusSpec{\n\t\t\t\tAddressReady:      true,\n\t\t\t\tConnectivityReady: true,\n\t\t\t\tEtcFilesReady:     true,\n\t\t\t},\n\t\t\tChecks:   []network.StatusCheck{network.AddressReady, network.ConnectivityReady},\n\t\t\tSucceeds: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tstate := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tstatus := network.NewStatus(network.NamespaceName, network.StatusID)\n\t\t\t*status.TypedSpec() = tt.Status\n\n\t\t\trequire.NoError(t, state.Create(ctx, status))\n\n\t\t\terr := network.NewReadyCondition(state, tt.Checks...).Wait(ctx)\n\n\t\t\tif tt.Succeeds {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.True(t, errors.Is(err, context.DeadlineExceeded), \"error is %v\", err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/configlayer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n// ConfigLayer describes network configuration layers, with lowest priority first.\ntype ConfigLayer int\n\n// Configuration layers.\n//\n//structprotogen:gen_enum\nconst (\n\tConfigDefault              ConfigLayer = iota // default\n\tConfigCmdline                                 // cmdline\n\tConfigPlatform                                // platform\n\tConfigOperator                                // operator\n\tConfigMachineConfiguration                    // configuration\n)\n"
  },
  {
    "path": "pkg/machinery/resources/network/configlayer_enumer.go",
    "content": "// Code generated by \"enumer -type=ConfigLayer,Operator -linecomment -text\"; DO NOT EDIT.\n\npackage network\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _ConfigLayerName = \"defaultcmdlineplatformoperatorconfiguration\"\n\nvar _ConfigLayerIndex = [...]uint8{0, 7, 14, 22, 30, 43}\n\nconst _ConfigLayerLowerName = \"defaultcmdlineplatformoperatorconfiguration\"\n\nfunc (i ConfigLayer) String() string {\n\tif i < 0 || i >= ConfigLayer(len(_ConfigLayerIndex)-1) {\n\t\treturn fmt.Sprintf(\"ConfigLayer(%d)\", i)\n\t}\n\treturn _ConfigLayerName[_ConfigLayerIndex[i]:_ConfigLayerIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _ConfigLayerNoOp() {\n\tvar x [1]struct{}\n\t_ = x[ConfigDefault-(0)]\n\t_ = x[ConfigCmdline-(1)]\n\t_ = x[ConfigPlatform-(2)]\n\t_ = x[ConfigOperator-(3)]\n\t_ = x[ConfigMachineConfiguration-(4)]\n}\n\nvar _ConfigLayerValues = []ConfigLayer{ConfigDefault, ConfigCmdline, ConfigPlatform, ConfigOperator, ConfigMachineConfiguration}\n\nvar _ConfigLayerNameToValueMap = map[string]ConfigLayer{\n\t_ConfigLayerName[0:7]:        ConfigDefault,\n\t_ConfigLayerLowerName[0:7]:   ConfigDefault,\n\t_ConfigLayerName[7:14]:       ConfigCmdline,\n\t_ConfigLayerLowerName[7:14]:  ConfigCmdline,\n\t_ConfigLayerName[14:22]:      ConfigPlatform,\n\t_ConfigLayerLowerName[14:22]: ConfigPlatform,\n\t_ConfigLayerName[22:30]:      ConfigOperator,\n\t_ConfigLayerLowerName[22:30]: ConfigOperator,\n\t_ConfigLayerName[30:43]:      ConfigMachineConfiguration,\n\t_ConfigLayerLowerName[30:43]: ConfigMachineConfiguration,\n}\n\nvar _ConfigLayerNames = []string{\n\t_ConfigLayerName[0:7],\n\t_ConfigLayerName[7:14],\n\t_ConfigLayerName[14:22],\n\t_ConfigLayerName[22:30],\n\t_ConfigLayerName[30:43],\n}\n\n// ConfigLayerString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ConfigLayerString(s string) (ConfigLayer, error) {\n\tif val, ok := _ConfigLayerNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _ConfigLayerNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ConfigLayer values\", s)\n}\n\n// ConfigLayerValues returns all values of the enum\nfunc ConfigLayerValues() []ConfigLayer {\n\treturn _ConfigLayerValues\n}\n\n// ConfigLayerStrings returns a slice of all String values of the enum\nfunc ConfigLayerStrings() []string {\n\tstrs := make([]string, len(_ConfigLayerNames))\n\tcopy(strs, _ConfigLayerNames)\n\treturn strs\n}\n\n// IsAConfigLayer returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ConfigLayer) IsAConfigLayer() bool {\n\tfor _, v := range _ConfigLayerValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ConfigLayer\nfunc (i ConfigLayer) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ConfigLayer\nfunc (i *ConfigLayer) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ConfigLayerString(string(text))\n\treturn err\n}\n\nconst _OperatorName = \"dhcp4dhcp6vip\"\n\nvar _OperatorIndex = [...]uint8{0, 5, 10, 13}\n\nconst _OperatorLowerName = \"dhcp4dhcp6vip\"\n\nfunc (i Operator) String() string {\n\tif i < 0 || i >= Operator(len(_OperatorIndex)-1) {\n\t\treturn fmt.Sprintf(\"Operator(%d)\", i)\n\t}\n\treturn _OperatorName[_OperatorIndex[i]:_OperatorIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _OperatorNoOp() {\n\tvar x [1]struct{}\n\t_ = x[OperatorDHCP4-(0)]\n\t_ = x[OperatorDHCP6-(1)]\n\t_ = x[OperatorVIP-(2)]\n}\n\nvar _OperatorValues = []Operator{OperatorDHCP4, OperatorDHCP6, OperatorVIP}\n\nvar _OperatorNameToValueMap = map[string]Operator{\n\t_OperatorName[0:5]:        OperatorDHCP4,\n\t_OperatorLowerName[0:5]:   OperatorDHCP4,\n\t_OperatorName[5:10]:       OperatorDHCP6,\n\t_OperatorLowerName[5:10]:  OperatorDHCP6,\n\t_OperatorName[10:13]:      OperatorVIP,\n\t_OperatorLowerName[10:13]: OperatorVIP,\n}\n\nvar _OperatorNames = []string{\n\t_OperatorName[0:5],\n\t_OperatorName[5:10],\n\t_OperatorName[10:13],\n}\n\n// OperatorString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc OperatorString(s string) (Operator, error) {\n\tif val, ok := _OperatorNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _OperatorNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Operator values\", s)\n}\n\n// OperatorValues returns all values of the enum\nfunc OperatorValues() []Operator {\n\treturn _OperatorValues\n}\n\n// OperatorStrings returns a slice of all String values of the enum\nfunc OperatorStrings() []string {\n\tstrs := make([]string, len(_OperatorNames))\n\tcopy(strs, _OperatorNames)\n\treturn strs\n}\n\n// IsAOperator returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Operator) IsAOperator() bool {\n\tfor _, v := range _OperatorValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for Operator\nfunc (i Operator) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for Operator\nfunc (i *Operator) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = OperatorString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type AddressSpecSpec -type AddressStatusSpec -type BondMasterSpec -type DNSResolveCacheSpec -type EthernetSpecSpec -type EthernetStatusSpec -type HardwareAddrSpec -type HostDNSConfigSpec -type HostnameSpecSpec -type HostnameStatusSpec -type LinkAliasSpecSpec -type LinkRefreshSpec -type LinkSpecSpec -type LinkStatusSpec -type NfTablesChainSpec -type NodeAddressSpec -type NodeAddressSortAlgorithmSpec -type NodeAddressFilterSpec -type OperatorSpecSpec -type PlatformConfigSpec -type ProbeSpecSpec -type ProbeStatusSpec -type ResolverSpecSpec -type ResolverStatusSpec -type RouteSpecSpec -type RouteStatusSpec -type RoutingRuleSpecSpec -type RoutingRuleStatusSpec -type StatusSpec -type TimeServerSpecSpec -type TimeServerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// DeepCopy generates a deep copy of AddressSpecSpec.\nfunc (o AddressSpecSpec) DeepCopy() AddressSpecSpec {\n\tvar cp AddressSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of AddressStatusSpec.\nfunc (o AddressStatusSpec) DeepCopy() AddressStatusSpec {\n\tvar cp AddressStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of BondMasterSpec.\nfunc (o BondMasterSpec) DeepCopy() BondMasterSpec {\n\tvar cp BondMasterSpec = o\n\tif o.PrimaryIndex != nil {\n\t\tcp.PrimaryIndex = new(uint32)\n\t\t*cp.PrimaryIndex = *o.PrimaryIndex\n\t}\n\tif o.ARPIPTargets != nil {\n\t\tcp.ARPIPTargets = make([]netip.Addr, len(o.ARPIPTargets))\n\t\tcopy(cp.ARPIPTargets, o.ARPIPTargets)\n\t}\n\tif o.NSIP6Targets != nil {\n\t\tcp.NSIP6Targets = make([]netip.Addr, len(o.NSIP6Targets))\n\t\tcopy(cp.NSIP6Targets, o.NSIP6Targets)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DNSResolveCacheSpec.\nfunc (o DNSResolveCacheSpec) DeepCopy() DNSResolveCacheSpec {\n\tvar cp DNSResolveCacheSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EthernetSpecSpec.\nfunc (o EthernetSpecSpec) DeepCopy() EthernetSpecSpec {\n\tvar cp EthernetSpecSpec = o\n\tif o.Rings.RX != nil {\n\t\tcp.Rings.RX = new(uint32)\n\t\t*cp.Rings.RX = *o.Rings.RX\n\t}\n\tif o.Rings.TX != nil {\n\t\tcp.Rings.TX = new(uint32)\n\t\t*cp.Rings.TX = *o.Rings.TX\n\t}\n\tif o.Rings.RXMini != nil {\n\t\tcp.Rings.RXMini = new(uint32)\n\t\t*cp.Rings.RXMini = *o.Rings.RXMini\n\t}\n\tif o.Rings.RXJumbo != nil {\n\t\tcp.Rings.RXJumbo = new(uint32)\n\t\t*cp.Rings.RXJumbo = *o.Rings.RXJumbo\n\t}\n\tif o.Rings.RXBufLen != nil {\n\t\tcp.Rings.RXBufLen = new(uint32)\n\t\t*cp.Rings.RXBufLen = *o.Rings.RXBufLen\n\t}\n\tif o.Rings.CQESize != nil {\n\t\tcp.Rings.CQESize = new(uint32)\n\t\t*cp.Rings.CQESize = *o.Rings.CQESize\n\t}\n\tif o.Rings.TXPush != nil {\n\t\tcp.Rings.TXPush = new(bool)\n\t\t*cp.Rings.TXPush = *o.Rings.TXPush\n\t}\n\tif o.Rings.RXPush != nil {\n\t\tcp.Rings.RXPush = new(bool)\n\t\t*cp.Rings.RXPush = *o.Rings.RXPush\n\t}\n\tif o.Rings.TXPushBufLen != nil {\n\t\tcp.Rings.TXPushBufLen = new(uint32)\n\t\t*cp.Rings.TXPushBufLen = *o.Rings.TXPushBufLen\n\t}\n\tif o.Rings.TCPDataSplit != nil {\n\t\tcp.Rings.TCPDataSplit = new(bool)\n\t\t*cp.Rings.TCPDataSplit = *o.Rings.TCPDataSplit\n\t}\n\tif o.Features != nil {\n\t\tcp.Features = make(map[string]bool, len(o.Features))\n\t\tfor k2, v2 := range o.Features {\n\t\t\tcp.Features[k2] = v2\n\t\t}\n\t}\n\tif o.Channels.RX != nil {\n\t\tcp.Channels.RX = new(uint32)\n\t\t*cp.Channels.RX = *o.Channels.RX\n\t}\n\tif o.Channels.TX != nil {\n\t\tcp.Channels.TX = new(uint32)\n\t\t*cp.Channels.TX = *o.Channels.TX\n\t}\n\tif o.Channels.Other != nil {\n\t\tcp.Channels.Other = new(uint32)\n\t\t*cp.Channels.Other = *o.Channels.Other\n\t}\n\tif o.Channels.Combined != nil {\n\t\tcp.Channels.Combined = new(uint32)\n\t\t*cp.Channels.Combined = *o.Channels.Combined\n\t}\n\tif o.WakeOnLAN != nil {\n\t\tcp.WakeOnLAN = make([]nethelpers.WOLMode, len(o.WakeOnLAN))\n\t\tcopy(cp.WakeOnLAN, o.WakeOnLAN)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EthernetStatusSpec.\nfunc (o EthernetStatusSpec) DeepCopy() EthernetStatusSpec {\n\tvar cp EthernetStatusSpec = o\n\tif o.LinkState != nil {\n\t\tcp.LinkState = new(bool)\n\t\t*cp.LinkState = *o.LinkState\n\t}\n\tif o.OurModes != nil {\n\t\tcp.OurModes = make([]string, len(o.OurModes))\n\t\tcopy(cp.OurModes, o.OurModes)\n\t}\n\tif o.PeerModes != nil {\n\t\tcp.PeerModes = make([]string, len(o.PeerModes))\n\t\tcopy(cp.PeerModes, o.PeerModes)\n\t}\n\tif o.Rings != nil {\n\t\tcp.Rings = new(EthernetRingsStatus)\n\t\t*cp.Rings = *o.Rings\n\t\tif o.Rings.RXMax != nil {\n\t\t\tcp.Rings.RXMax = new(uint32)\n\t\t\t*cp.Rings.RXMax = *o.Rings.RXMax\n\t\t}\n\t\tif o.Rings.RXMiniMax != nil {\n\t\t\tcp.Rings.RXMiniMax = new(uint32)\n\t\t\t*cp.Rings.RXMiniMax = *o.Rings.RXMiniMax\n\t\t}\n\t\tif o.Rings.RXJumboMax != nil {\n\t\t\tcp.Rings.RXJumboMax = new(uint32)\n\t\t\t*cp.Rings.RXJumboMax = *o.Rings.RXJumboMax\n\t\t}\n\t\tif o.Rings.TXMax != nil {\n\t\t\tcp.Rings.TXMax = new(uint32)\n\t\t\t*cp.Rings.TXMax = *o.Rings.TXMax\n\t\t}\n\t\tif o.Rings.TXPushBufLenMax != nil {\n\t\t\tcp.Rings.TXPushBufLenMax = new(uint32)\n\t\t\t*cp.Rings.TXPushBufLenMax = *o.Rings.TXPushBufLenMax\n\t\t}\n\t\tif o.Rings.RX != nil {\n\t\t\tcp.Rings.RX = new(uint32)\n\t\t\t*cp.Rings.RX = *o.Rings.RX\n\t\t}\n\t\tif o.Rings.RXMini != nil {\n\t\t\tcp.Rings.RXMini = new(uint32)\n\t\t\t*cp.Rings.RXMini = *o.Rings.RXMini\n\t\t}\n\t\tif o.Rings.RXJumbo != nil {\n\t\t\tcp.Rings.RXJumbo = new(uint32)\n\t\t\t*cp.Rings.RXJumbo = *o.Rings.RXJumbo\n\t\t}\n\t\tif o.Rings.TX != nil {\n\t\t\tcp.Rings.TX = new(uint32)\n\t\t\t*cp.Rings.TX = *o.Rings.TX\n\t\t}\n\t\tif o.Rings.RXBufLen != nil {\n\t\t\tcp.Rings.RXBufLen = new(uint32)\n\t\t\t*cp.Rings.RXBufLen = *o.Rings.RXBufLen\n\t\t}\n\t\tif o.Rings.CQESize != nil {\n\t\t\tcp.Rings.CQESize = new(uint32)\n\t\t\t*cp.Rings.CQESize = *o.Rings.CQESize\n\t\t}\n\t\tif o.Rings.TXPush != nil {\n\t\t\tcp.Rings.TXPush = new(bool)\n\t\t\t*cp.Rings.TXPush = *o.Rings.TXPush\n\t\t}\n\t\tif o.Rings.RXPush != nil {\n\t\t\tcp.Rings.RXPush = new(bool)\n\t\t\t*cp.Rings.RXPush = *o.Rings.RXPush\n\t\t}\n\t\tif o.Rings.TXPushBufLen != nil {\n\t\t\tcp.Rings.TXPushBufLen = new(uint32)\n\t\t\t*cp.Rings.TXPushBufLen = *o.Rings.TXPushBufLen\n\t\t}\n\t\tif o.Rings.TCPDataSplit != nil {\n\t\t\tcp.Rings.TCPDataSplit = new(bool)\n\t\t\t*cp.Rings.TCPDataSplit = *o.Rings.TCPDataSplit\n\t\t}\n\t}\n\tif o.Features != nil {\n\t\tcp.Features = make([]EthernetFeatureStatus, len(o.Features))\n\t\tcopy(cp.Features, o.Features)\n\t}\n\tif o.Channels != nil {\n\t\tcp.Channels = new(EthernetChannelsStatus)\n\t\t*cp.Channels = *o.Channels\n\t\tif o.Channels.RXMax != nil {\n\t\t\tcp.Channels.RXMax = new(uint32)\n\t\t\t*cp.Channels.RXMax = *o.Channels.RXMax\n\t\t}\n\t\tif o.Channels.TXMax != nil {\n\t\t\tcp.Channels.TXMax = new(uint32)\n\t\t\t*cp.Channels.TXMax = *o.Channels.TXMax\n\t\t}\n\t\tif o.Channels.OtherMax != nil {\n\t\t\tcp.Channels.OtherMax = new(uint32)\n\t\t\t*cp.Channels.OtherMax = *o.Channels.OtherMax\n\t\t}\n\t\tif o.Channels.CombinedMax != nil {\n\t\t\tcp.Channels.CombinedMax = new(uint32)\n\t\t\t*cp.Channels.CombinedMax = *o.Channels.CombinedMax\n\t\t}\n\t\tif o.Channels.RX != nil {\n\t\t\tcp.Channels.RX = new(uint32)\n\t\t\t*cp.Channels.RX = *o.Channels.RX\n\t\t}\n\t\tif o.Channels.TX != nil {\n\t\t\tcp.Channels.TX = new(uint32)\n\t\t\t*cp.Channels.TX = *o.Channels.TX\n\t\t}\n\t\tif o.Channels.Other != nil {\n\t\t\tcp.Channels.Other = new(uint32)\n\t\t\t*cp.Channels.Other = *o.Channels.Other\n\t\t}\n\t\tif o.Channels.Combined != nil {\n\t\t\tcp.Channels.Combined = new(uint32)\n\t\t\t*cp.Channels.Combined = *o.Channels.Combined\n\t\t}\n\t}\n\tif o.WakeOnLAN != nil {\n\t\tcp.WakeOnLAN = make([]nethelpers.WOLMode, len(o.WakeOnLAN))\n\t\tcopy(cp.WakeOnLAN, o.WakeOnLAN)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of HardwareAddrSpec.\nfunc (o HardwareAddrSpec) DeepCopy() HardwareAddrSpec {\n\tvar cp HardwareAddrSpec = o\n\tif o.HardwareAddr != nil {\n\t\tcp.HardwareAddr = make([]byte, len(o.HardwareAddr))\n\t\tcopy(cp.HardwareAddr, o.HardwareAddr)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of HostDNSConfigSpec.\nfunc (o HostDNSConfigSpec) DeepCopy() HostDNSConfigSpec {\n\tvar cp HostDNSConfigSpec = o\n\tif o.ListenAddresses != nil {\n\t\tcp.ListenAddresses = make([]netip.AddrPort, len(o.ListenAddresses))\n\t\tcopy(cp.ListenAddresses, o.ListenAddresses)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of HostnameSpecSpec.\nfunc (o HostnameSpecSpec) DeepCopy() HostnameSpecSpec {\n\tvar cp HostnameSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of HostnameStatusSpec.\nfunc (o HostnameStatusSpec) DeepCopy() HostnameStatusSpec {\n\tvar cp HostnameStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of LinkAliasSpecSpec.\nfunc (o LinkAliasSpecSpec) DeepCopy() LinkAliasSpecSpec {\n\tvar cp LinkAliasSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of LinkRefreshSpec.\nfunc (o LinkRefreshSpec) DeepCopy() LinkRefreshSpec {\n\tvar cp LinkRefreshSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of LinkSpecSpec.\nfunc (o LinkSpecSpec) DeepCopy() LinkSpecSpec {\n\tvar cp LinkSpecSpec = o\n\tif o.HardwareAddress != nil {\n\t\tcp.HardwareAddress = make([]byte, len(o.HardwareAddress))\n\t\tcopy(cp.HardwareAddress, o.HardwareAddress)\n\t}\n\tcp.BondMaster = o.BondMaster.DeepCopy()\n\tif o.Wireguard.Peers != nil {\n\t\tcp.Wireguard.Peers = make([]WireguardPeer, len(o.Wireguard.Peers))\n\t\tcopy(cp.Wireguard.Peers, o.Wireguard.Peers)\n\t\tfor i3 := range o.Wireguard.Peers {\n\t\t\tif o.Wireguard.Peers[i3].AllowedIPs != nil {\n\t\t\t\tcp.Wireguard.Peers[i3].AllowedIPs = make([]netip.Prefix, len(o.Wireguard.Peers[i3].AllowedIPs))\n\t\t\t\tcopy(cp.Wireguard.Peers[i3].AllowedIPs, o.Wireguard.Peers[i3].AllowedIPs)\n\t\t\t}\n\t\t}\n\t}\n\tif o.Multicast != nil {\n\t\tcp.Multicast = new(bool)\n\t\t*cp.Multicast = *o.Multicast\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of LinkStatusSpec.\nfunc (o LinkStatusSpec) DeepCopy() LinkStatusSpec {\n\tvar cp LinkStatusSpec = o\n\tif o.AltNames != nil {\n\t\tcp.AltNames = make([]string, len(o.AltNames))\n\t\tcopy(cp.AltNames, o.AltNames)\n\t}\n\tif o.HardwareAddr != nil {\n\t\tcp.HardwareAddr = make([]byte, len(o.HardwareAddr))\n\t\tcopy(cp.HardwareAddr, o.HardwareAddr)\n\t}\n\tif o.PermanentAddr != nil {\n\t\tcp.PermanentAddr = make([]byte, len(o.PermanentAddr))\n\t\tcopy(cp.PermanentAddr, o.PermanentAddr)\n\t}\n\tif o.BroadcastAddr != nil {\n\t\tcp.BroadcastAddr = make([]byte, len(o.BroadcastAddr))\n\t\tcopy(cp.BroadcastAddr, o.BroadcastAddr)\n\t}\n\tcp.BondMaster = o.BondMaster.DeepCopy()\n\tif o.Wireguard.Peers != nil {\n\t\tcp.Wireguard.Peers = make([]WireguardPeer, len(o.Wireguard.Peers))\n\t\tcopy(cp.Wireguard.Peers, o.Wireguard.Peers)\n\t\tfor i3 := range o.Wireguard.Peers {\n\t\t\tif o.Wireguard.Peers[i3].AllowedIPs != nil {\n\t\t\t\tcp.Wireguard.Peers[i3].AllowedIPs = make([]netip.Prefix, len(o.Wireguard.Peers[i3].AllowedIPs))\n\t\t\t\tcopy(cp.Wireguard.Peers[i3].AllowedIPs, o.Wireguard.Peers[i3].AllowedIPs)\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NfTablesChainSpec.\nfunc (o NfTablesChainSpec) DeepCopy() NfTablesChainSpec {\n\tvar cp NfTablesChainSpec = o\n\tif o.Rules != nil {\n\t\tcp.Rules = make([]NfTablesRule, len(o.Rules))\n\t\tcopy(cp.Rules, o.Rules)\n\t\tfor i2 := range o.Rules {\n\t\t\tif o.Rules[i2].MatchIIfName != nil {\n\t\t\t\tcp.Rules[i2].MatchIIfName = new(NfTablesIfNameMatch)\n\t\t\t\t*cp.Rules[i2].MatchIIfName = *o.Rules[i2].MatchIIfName\n\t\t\t\tif o.Rules[i2].MatchIIfName.InterfaceNames != nil {\n\t\t\t\t\tcp.Rules[i2].MatchIIfName.InterfaceNames = make([]string, len(o.Rules[i2].MatchIIfName.InterfaceNames))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchIIfName.InterfaceNames, o.Rules[i2].MatchIIfName.InterfaceNames)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchOIfName != nil {\n\t\t\t\tcp.Rules[i2].MatchOIfName = new(NfTablesIfNameMatch)\n\t\t\t\t*cp.Rules[i2].MatchOIfName = *o.Rules[i2].MatchOIfName\n\t\t\t\tif o.Rules[i2].MatchOIfName.InterfaceNames != nil {\n\t\t\t\t\tcp.Rules[i2].MatchOIfName.InterfaceNames = make([]string, len(o.Rules[i2].MatchOIfName.InterfaceNames))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchOIfName.InterfaceNames, o.Rules[i2].MatchOIfName.InterfaceNames)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchMark != nil {\n\t\t\t\tcp.Rules[i2].MatchMark = new(NfTablesMark)\n\t\t\t\t*cp.Rules[i2].MatchMark = *o.Rules[i2].MatchMark\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchConntrackState != nil {\n\t\t\t\tcp.Rules[i2].MatchConntrackState = new(NfTablesConntrackStateMatch)\n\t\t\t\t*cp.Rules[i2].MatchConntrackState = *o.Rules[i2].MatchConntrackState\n\t\t\t\tif o.Rules[i2].MatchConntrackState.States != nil {\n\t\t\t\t\tcp.Rules[i2].MatchConntrackState.States = make([]nethelpers.ConntrackState, len(o.Rules[i2].MatchConntrackState.States))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchConntrackState.States, o.Rules[i2].MatchConntrackState.States)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchSourceAddress != nil {\n\t\t\t\tcp.Rules[i2].MatchSourceAddress = new(NfTablesAddressMatch)\n\t\t\t\t*cp.Rules[i2].MatchSourceAddress = *o.Rules[i2].MatchSourceAddress\n\t\t\t\tif o.Rules[i2].MatchSourceAddress.IncludeSubnets != nil {\n\t\t\t\t\tcp.Rules[i2].MatchSourceAddress.IncludeSubnets = make([]netip.Prefix, len(o.Rules[i2].MatchSourceAddress.IncludeSubnets))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchSourceAddress.IncludeSubnets, o.Rules[i2].MatchSourceAddress.IncludeSubnets)\n\t\t\t\t}\n\t\t\t\tif o.Rules[i2].MatchSourceAddress.ExcludeSubnets != nil {\n\t\t\t\t\tcp.Rules[i2].MatchSourceAddress.ExcludeSubnets = make([]netip.Prefix, len(o.Rules[i2].MatchSourceAddress.ExcludeSubnets))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchSourceAddress.ExcludeSubnets, o.Rules[i2].MatchSourceAddress.ExcludeSubnets)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchDestinationAddress != nil {\n\t\t\t\tcp.Rules[i2].MatchDestinationAddress = new(NfTablesAddressMatch)\n\t\t\t\t*cp.Rules[i2].MatchDestinationAddress = *o.Rules[i2].MatchDestinationAddress\n\t\t\t\tif o.Rules[i2].MatchDestinationAddress.IncludeSubnets != nil {\n\t\t\t\t\tcp.Rules[i2].MatchDestinationAddress.IncludeSubnets = make([]netip.Prefix, len(o.Rules[i2].MatchDestinationAddress.IncludeSubnets))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchDestinationAddress.IncludeSubnets, o.Rules[i2].MatchDestinationAddress.IncludeSubnets)\n\t\t\t\t}\n\t\t\t\tif o.Rules[i2].MatchDestinationAddress.ExcludeSubnets != nil {\n\t\t\t\t\tcp.Rules[i2].MatchDestinationAddress.ExcludeSubnets = make([]netip.Prefix, len(o.Rules[i2].MatchDestinationAddress.ExcludeSubnets))\n\t\t\t\t\tcopy(cp.Rules[i2].MatchDestinationAddress.ExcludeSubnets, o.Rules[i2].MatchDestinationAddress.ExcludeSubnets)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchLayer4 != nil {\n\t\t\t\tcp.Rules[i2].MatchLayer4 = new(NfTablesLayer4Match)\n\t\t\t\t*cp.Rules[i2].MatchLayer4 = *o.Rules[i2].MatchLayer4\n\t\t\t\tif o.Rules[i2].MatchLayer4.MatchSourcePort != nil {\n\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchSourcePort = new(NfTablesPortMatch)\n\t\t\t\t\t*cp.Rules[i2].MatchLayer4.MatchSourcePort = *o.Rules[i2].MatchLayer4.MatchSourcePort\n\t\t\t\t\tif o.Rules[i2].MatchLayer4.MatchSourcePort.Ranges != nil {\n\t\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchSourcePort.Ranges = make([]PortRange, len(o.Rules[i2].MatchLayer4.MatchSourcePort.Ranges))\n\t\t\t\t\t\tcopy(cp.Rules[i2].MatchLayer4.MatchSourcePort.Ranges, o.Rules[i2].MatchLayer4.MatchSourcePort.Ranges)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.Rules[i2].MatchLayer4.MatchDestinationPort != nil {\n\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchDestinationPort = new(NfTablesPortMatch)\n\t\t\t\t\t*cp.Rules[i2].MatchLayer4.MatchDestinationPort = *o.Rules[i2].MatchLayer4.MatchDestinationPort\n\t\t\t\t\tif o.Rules[i2].MatchLayer4.MatchDestinationPort.Ranges != nil {\n\t\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchDestinationPort.Ranges = make([]PortRange, len(o.Rules[i2].MatchLayer4.MatchDestinationPort.Ranges))\n\t\t\t\t\t\tcopy(cp.Rules[i2].MatchLayer4.MatchDestinationPort.Ranges, o.Rules[i2].MatchLayer4.MatchDestinationPort.Ranges)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif o.Rules[i2].MatchLayer4.MatchICMPType != nil {\n\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchICMPType = new(NfTablesICMPTypeMatch)\n\t\t\t\t\t*cp.Rules[i2].MatchLayer4.MatchICMPType = *o.Rules[i2].MatchLayer4.MatchICMPType\n\t\t\t\t\tif o.Rules[i2].MatchLayer4.MatchICMPType.Types != nil {\n\t\t\t\t\t\tcp.Rules[i2].MatchLayer4.MatchICMPType.Types = make([]nethelpers.ICMPType, len(o.Rules[i2].MatchLayer4.MatchICMPType.Types))\n\t\t\t\t\t\tcopy(cp.Rules[i2].MatchLayer4.MatchICMPType.Types, o.Rules[i2].MatchLayer4.MatchICMPType.Types)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif o.Rules[i2].MatchLimit != nil {\n\t\t\t\tcp.Rules[i2].MatchLimit = new(NfTablesLimitMatch)\n\t\t\t\t*cp.Rules[i2].MatchLimit = *o.Rules[i2].MatchLimit\n\t\t\t}\n\t\t\tif o.Rules[i2].ClampMSS != nil {\n\t\t\t\tcp.Rules[i2].ClampMSS = new(NfTablesClampMSS)\n\t\t\t\t*cp.Rules[i2].ClampMSS = *o.Rules[i2].ClampMSS\n\t\t\t}\n\t\t\tif o.Rules[i2].SetMark != nil {\n\t\t\t\tcp.Rules[i2].SetMark = new(NfTablesMark)\n\t\t\t\t*cp.Rules[i2].SetMark = *o.Rules[i2].SetMark\n\t\t\t}\n\t\t\tif o.Rules[i2].Verdict != nil {\n\t\t\t\tcp.Rules[i2].Verdict = new(nethelpers.NfTablesVerdict)\n\t\t\t\t*cp.Rules[i2].Verdict = *o.Rules[i2].Verdict\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeAddressSpec.\nfunc (o NodeAddressSpec) DeepCopy() NodeAddressSpec {\n\tvar cp NodeAddressSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]netip.Prefix, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeAddressSortAlgorithmSpec.\nfunc (o NodeAddressSortAlgorithmSpec) DeepCopy() NodeAddressSortAlgorithmSpec {\n\tvar cp NodeAddressSortAlgorithmSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of NodeAddressFilterSpec.\nfunc (o NodeAddressFilterSpec) DeepCopy() NodeAddressFilterSpec {\n\tvar cp NodeAddressFilterSpec = o\n\tif o.IncludeSubnets != nil {\n\t\tcp.IncludeSubnets = make([]netip.Prefix, len(o.IncludeSubnets))\n\t\tcopy(cp.IncludeSubnets, o.IncludeSubnets)\n\t}\n\tif o.ExcludeSubnets != nil {\n\t\tcp.ExcludeSubnets = make([]netip.Prefix, len(o.ExcludeSubnets))\n\t\tcopy(cp.ExcludeSubnets, o.ExcludeSubnets)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of OperatorSpecSpec.\nfunc (o OperatorSpecSpec) DeepCopy() OperatorSpecSpec {\n\tvar cp OperatorSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PlatformConfigSpec.\nfunc (o PlatformConfigSpec) DeepCopy() PlatformConfigSpec {\n\tvar cp PlatformConfigSpec = o\n\tif o.Addresses != nil {\n\t\tcp.Addresses = make([]AddressSpecSpec, len(o.Addresses))\n\t\tcopy(cp.Addresses, o.Addresses)\n\t\tfor i2 := range o.Addresses {\n\t\t\tcp.Addresses[i2] = o.Addresses[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Links != nil {\n\t\tcp.Links = make([]LinkSpecSpec, len(o.Links))\n\t\tcopy(cp.Links, o.Links)\n\t\tfor i2 := range o.Links {\n\t\t\tcp.Links[i2] = o.Links[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Routes != nil {\n\t\tcp.Routes = make([]RouteSpecSpec, len(o.Routes))\n\t\tcopy(cp.Routes, o.Routes)\n\t\tfor i2 := range o.Routes {\n\t\t\tcp.Routes[i2] = o.Routes[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Hostnames != nil {\n\t\tcp.Hostnames = make([]HostnameSpecSpec, len(o.Hostnames))\n\t\tcopy(cp.Hostnames, o.Hostnames)\n\t\tfor i2 := range o.Hostnames {\n\t\t\tcp.Hostnames[i2] = o.Hostnames[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Resolvers != nil {\n\t\tcp.Resolvers = make([]ResolverSpecSpec, len(o.Resolvers))\n\t\tcopy(cp.Resolvers, o.Resolvers)\n\t\tfor i2 := range o.Resolvers {\n\t\t\tcp.Resolvers[i2] = o.Resolvers[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.TimeServers != nil {\n\t\tcp.TimeServers = make([]TimeServerSpecSpec, len(o.TimeServers))\n\t\tcopy(cp.TimeServers, o.TimeServers)\n\t\tfor i2 := range o.TimeServers {\n\t\t\tcp.TimeServers[i2] = o.TimeServers[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Operators != nil {\n\t\tcp.Operators = make([]OperatorSpecSpec, len(o.Operators))\n\t\tcopy(cp.Operators, o.Operators)\n\t\tfor i2 := range o.Operators {\n\t\t\tcp.Operators[i2] = o.Operators[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.ExternalIPs != nil {\n\t\tcp.ExternalIPs = make([]netip.Addr, len(o.ExternalIPs))\n\t\tcopy(cp.ExternalIPs, o.ExternalIPs)\n\t}\n\tif o.Probes != nil {\n\t\tcp.Probes = make([]ProbeSpecSpec, len(o.Probes))\n\t\tcopy(cp.Probes, o.Probes)\n\t\tfor i2 := range o.Probes {\n\t\t\tcp.Probes[i2] = o.Probes[i2].DeepCopy()\n\t\t}\n\t}\n\tif o.Metadata != nil {\n\t\tretV := o.Metadata.DeepCopy()\n\t\tcp.Metadata = &retV\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ProbeSpecSpec.\nfunc (o ProbeSpecSpec) DeepCopy() ProbeSpecSpec {\n\tvar cp ProbeSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ProbeStatusSpec.\nfunc (o ProbeStatusSpec) DeepCopy() ProbeStatusSpec {\n\tvar cp ProbeStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ResolverSpecSpec.\nfunc (o ResolverSpecSpec) DeepCopy() ResolverSpecSpec {\n\tvar cp ResolverSpecSpec = o\n\tif o.DNSServers != nil {\n\t\tcp.DNSServers = make([]netip.Addr, len(o.DNSServers))\n\t\tcopy(cp.DNSServers, o.DNSServers)\n\t}\n\tif o.SearchDomains != nil {\n\t\tcp.SearchDomains = make([]string, len(o.SearchDomains))\n\t\tcopy(cp.SearchDomains, o.SearchDomains)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ResolverStatusSpec.\nfunc (o ResolverStatusSpec) DeepCopy() ResolverStatusSpec {\n\tvar cp ResolverStatusSpec = o\n\tif o.DNSServers != nil {\n\t\tcp.DNSServers = make([]netip.Addr, len(o.DNSServers))\n\t\tcopy(cp.DNSServers, o.DNSServers)\n\t}\n\tif o.SearchDomains != nil {\n\t\tcp.SearchDomains = make([]string, len(o.SearchDomains))\n\t\tcopy(cp.SearchDomains, o.SearchDomains)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of RouteSpecSpec.\nfunc (o RouteSpecSpec) DeepCopy() RouteSpecSpec {\n\tvar cp RouteSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of RouteStatusSpec.\nfunc (o RouteStatusSpec) DeepCopy() RouteStatusSpec {\n\tvar cp RouteStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of RoutingRuleSpecSpec.\nfunc (o RoutingRuleSpecSpec) DeepCopy() RoutingRuleSpecSpec {\n\tvar cp RoutingRuleSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of RoutingRuleStatusSpec.\nfunc (o RoutingRuleStatusSpec) DeepCopy() RoutingRuleStatusSpec {\n\tvar cp RoutingRuleStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StatusSpec.\nfunc (o StatusSpec) DeepCopy() StatusSpec {\n\tvar cp StatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of TimeServerSpecSpec.\nfunc (o TimeServerSpecSpec) DeepCopy() TimeServerSpecSpec {\n\tvar cp TimeServerSpecSpec = o\n\tif o.NTPServers != nil {\n\t\tcp.NTPServers = make([]string, len(o.NTPServers))\n\t\tcopy(cp.NTPServers, o.NTPServers)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of TimeServerStatusSpec.\nfunc (o TimeServerStatusSpec) DeepCopy() TimeServerStatusSpec {\n\tvar cp TimeServerStatusSpec = o\n\tif o.NTPServers != nil {\n\t\tcp.NTPServers = make([]string, len(o.NTPServers))\n\t\tcopy(cp.NTPServers, o.NTPServers)\n\t}\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/device_config_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"go.yaml.in/yaml/v4\"\n\n\tnetworkpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DeviceConfigSpecType is type of DeviceConfigSpec resource.\nconst DeviceConfigSpecType = resource.Type(\"DeviceConfigSpecs.net.talos.dev\")\n\n// DeviceConfigSpec resource holds network interface configs.\ntype DeviceConfigSpec = typed.Resource[DeviceConfigSpecSpec, DeviceConfigSpecExtension]\n\n// DeviceConfigSpecSpec contains the spec of a device config.\n//\n//gotagsrewrite:gen\ntype DeviceConfigSpecSpec struct {\n\tDevice config.Device `protobuf:\"1\"`\n}\n\n// NewDeviceConfig creates new interface config.\nfunc NewDeviceConfig(id resource.ID, device config.Device) *DeviceConfigSpec {\n\treturn typed.NewResource[DeviceConfigSpecSpec, DeviceConfigSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, DeviceConfigSpecType, id, resource.VersionUndefined),\n\t\tDeviceConfigSpecSpec{Device: device},\n\t)\n}\n\n// DeepCopy generates a deep copy of DeviceConfigSpecSpec.\nfunc (spec DeviceConfigSpecSpec) DeepCopy() DeviceConfigSpecSpec {\n\tcp := spec\n\tcp.Device = spec.Device.(*v1alpha1.Device).DeepCopy()\n\n\treturn cp\n}\n\n// DeviceConfigSpecExtension providers auxiliary methods for DeviceConfigSpec.\ntype DeviceConfigSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (DeviceConfigSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DeviceConfigSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\n// MarshalProto implements ProtoMarshaler.\nfunc (spec *DeviceConfigSpecSpec) MarshalProto() ([]byte, error) {\n\tyamlBytes, err := yaml.Marshal(spec.Device)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tprotoSpec := networkpb.DeviceConfigSpecSpec{\n\t\tYamlMarshalled: yamlBytes,\n\t}\n\n\treturn proto.Marshal(&protoSpec)\n}\n\n// UnmarshalProto implements protobuf.ResourceUnmarshaler.\nfunc (spec *DeviceConfigSpecSpec) UnmarshalProto(protoBytes []byte) error {\n\tprotoSpec := networkpb.DeviceConfigSpecSpec{}\n\n\tif err := proto.Unmarshal(protoBytes, &protoSpec); err != nil {\n\t\treturn err\n\t}\n\n\tvar dev v1alpha1.Device\n\n\tif err := yaml.Unmarshal(protoSpec.YamlMarshalled, &dev); err != nil {\n\t\treturn err\n\t}\n\n\tspec.Device = &dev\n\n\treturn nil\n}\n\nfunc init() {\n\tif err := protobuf.RegisterResource(DeviceConfigSpecType, &DeviceConfigSpec{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/device_config_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestDeviceConfigProtobufMarshal(t *testing.T) {\n\td := &v1alpha1.Device{\n\t\tDeviceInterface: \"eth0\",\n\t\tDeviceAddresses: []string{\"10.0.0.8/32\"},\n\t}\n\n\tr := network.NewDeviceConfig(\"id1\", d)\n\n\tprotoR, err := protobuf.FromResource(r)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := protoR.Marshal()\n\trequire.NoError(t, err)\n\n\tprotoR, err = protobuf.Unmarshal(marshaled)\n\trequire.NoError(t, err)\n\n\tr2, err := protobuf.UnmarshalResource(protoR)\n\trequire.NoError(t, err)\n\n\trequire.True(t, resource.Equal(r, r2))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/dns_resolve_cache.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DNSResolveCacheType is type of DNSResolveCache resource.\nconst DNSResolveCacheType = resource.Type(\"DNSResolveCaches.net.talos.dev\")\n\n// DNSResolveCache resource holds DNS resolver info.\ntype DNSResolveCache = typed.Resource[DNSResolveCacheSpec, DNSResolveCacheExtension]\n\n// DNSResolveCacheSpec describes DNS servers status.\n//\n//gotagsrewrite:gen\ntype DNSResolveCacheSpec struct {\n\tStatus string `yaml:\"status\" protobuf:\"1\"`\n}\n\n// NewDNSResolveCache initializes a DNSResolveCache resource.\nfunc NewDNSResolveCache(id resource.ID) *DNSResolveCache {\n\treturn typed.NewResource[DNSResolveCacheSpec, DNSResolveCacheExtension](\n\t\tresource.NewMetadata(NamespaceName, DNSResolveCacheType, id, resource.VersionUndefined),\n\t\tDNSResolveCacheSpec{},\n\t)\n}\n\n// DNSResolveCacheExtension provides auxiliary methods for DNSResolveCache.\ntype DNSResolveCacheExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (DNSResolveCacheExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DNSResolveCacheType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Status\",\n\t\t\t\tJSONPath: \"{.status}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[DNSResolveCacheSpec](DNSResolveCacheType, &DNSResolveCache{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/dns_upstream.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/handle\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n)\n\n// DNSUpstreamType is type of DNSUpstream resource.\nconst DNSUpstreamType = resource.Type(\"DNSUpstreams.net.talos.dev\")\n\n// DNSUpstream resource holds DNS resolver info.\ntype DNSUpstream = typed.Resource[DNSUpstreamSpec, DNSUpstreamExtension]\n\n// DNSUpstreamSpec describes DNS upstreams status.\ntype DNSUpstreamSpec = handle.ResourceSpec[DNSUpstreamSpecSpec]\n\n// DNSUpstreamSpecSpec describes DNS upstreams status.\ntype DNSUpstreamSpecSpec struct {\n\tConn *DNSConn\n}\n\n// MarshalYAML implements yaml.Marshaler interface.\nfunc (d DNSUpstreamSpecSpec) MarshalYAML() (any, error) {\n\td.Conn.Healthcheck()\n\n\treturn map[string]string{\n\t\t\"healthy\": strconv.FormatBool(d.Conn.Fails() == 0),\n\t\t\"addr\":    d.Conn.Addr(),\n\t}, nil\n}\n\n// NewDNSUpstream initializes a DNSUpstream resource.\nfunc NewDNSUpstream(id resource.ID) *DNSUpstream {\n\treturn typed.NewResource[DNSUpstreamSpec, DNSUpstreamExtension](\n\t\tresource.NewMetadata(NamespaceName, DNSUpstreamType, id, resource.VersionUndefined),\n\t\tDNSUpstreamSpec{Value: DNSUpstreamSpecSpec{}},\n\t)\n}\n\n// DNSUpstreamExtension provides auxiliary methods for DNSUpstream.\ntype DNSUpstreamExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (DNSUpstreamExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DNSUpstreamType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Healthy\",\n\t\t\t\tJSONPath: \"{.healthy}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Address\",\n\t\t\t\tJSONPath: \"{.addr}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// Proxy is essentially a proxy.Proxy interface. It's here because we don't want machinery to depend on coredns.\n// The good thing we don't need any additional methods from coredns, so we can use a simple interface.\ntype Proxy interface {\n\tAddr() string\n\tFails() uint32\n\tHealthcheck()\n\tClose()\n\tStart(time.Duration)\n}\n\n// DNSConn is a wrapper around a Proxy.\ntype DNSConn struct {\n\tcounter atomic.Int64\n\t// Proxy is essentially a *proxy.Proxy interface. It's here because we don't want machinery to depend on coredns.\n\t// We could use a generic struct here, but without generic aliases the usage would look ugly.\n\t// Once generic aliases are here, redo the type above as `type DNSUpstream[P Proxy] = typed.Resource[...]`.\n\tproxy Proxy\n}\n\n// NewDNSConn initializes a new DNSConn.\nfunc NewDNSConn(proxy Proxy) *DNSConn {\n\tproxy.Start(500 * time.Millisecond)\n\n\tres := &DNSConn{proxy: proxy}\n\n\tres.counter.Add(1)\n\n\treturn res\n}\n\n// Addr returns the address of the DNSConn.\nfunc (u *DNSConn) Addr() string { return u.proxy.Addr() }\n\n// Fails returns the number of fails of the DNSConn.\nfunc (u *DNSConn) Fails() uint32 { return u.proxy.Fails() }\n\n// Proxy returns the Proxy field of the DNSConn.\nfunc (u *DNSConn) Proxy() Proxy { return u.proxy }\n\n// Healthcheck kicks of a round of health checks for this DNSConn.\nfunc (u *DNSConn) Healthcheck() { u.proxy.Healthcheck() }\n\n// Close stops the DNSConn.\nfunc (u *DNSConn) Close() {\n\tif u.counter.Add(-1) == 0 {\n\t\tu.proxy.Close()\n\t}\n}\n\n// NewRef returns a new reference to the DNSConn.\nfunc (u *DNSConn) NewRef() *DNSConn {\n\tu.counter.Add(1)\n\n\treturn u\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/ethernet_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EthernetSpecType is type of EthernetSpec resource.\nconst EthernetSpecType = resource.Type(\"EthernetSpecs.net.talos.dev\")\n\n// EthernetSpec resource holds Ethernet network link status.\ntype EthernetSpec = typed.Resource[EthernetSpecSpec, EthernetSpecExtension]\n\n// EthernetSpecSpec describes config of Ethernet link.\n//\n//gotagsrewrite:gen\ntype EthernetSpecSpec struct {\n\tRings     EthernetRingsSpec    `yaml:\"rings,omitempty\" protobuf:\"1\"`\n\tFeatures  map[string]bool      `yaml:\"features,omitempty\" protobuf:\"2\"`\n\tChannels  EthernetChannelsSpec `yaml:\"channels,omitempty\" protobuf:\"3\"`\n\tWakeOnLAN []nethelpers.WOLMode `yaml:\"wakeOnLan,omitempty\" protobuf:\"4\"`\n}\n\n// EthernetRingsSpec describes config of Ethernet rings.\n//\n//gotagsrewrite:gen\ntype EthernetRingsSpec struct {\n\tRX           *uint32 `yaml:\"rx,omitempty\" protobuf:\"1\"`\n\tTX           *uint32 `yaml:\"tx,omitempty\" protobuf:\"4\"`\n\tRXMini       *uint32 `yaml:\"rx-mini,omitempty\" protobuf:\"2\"`\n\tRXJumbo      *uint32 `yaml:\"rx-jumbo,omitempty\" protobuf:\"3\"`\n\tRXBufLen     *uint32 `yaml:\"rx-buf-len,omitempty\" protobuf:\"5\"`\n\tCQESize      *uint32 `yaml:\"cqe-size,omitempty\" protobuf:\"6\"`\n\tTXPush       *bool   `yaml:\"tx-push,omitempty\" protobuf:\"7\"`\n\tRXPush       *bool   `yaml:\"rx-push,omitempty\" protobuf:\"8\"`\n\tTXPushBufLen *uint32 `yaml:\"tx-push-buf-len,omitempty\" protobuf:\"9\"`\n\tTCPDataSplit *bool   `yaml:\"tcp-data-split,omitempty\" protobuf:\"10\"`\n}\n\n// EthernetChannelsSpec describes config of Ethernet channels.\n//\n//gotagsrewrite:gen\ntype EthernetChannelsSpec struct {\n\tRX       *uint32 `yaml:\"rx,omitempty\" protobuf:\"1\"`\n\tTX       *uint32 `yaml:\"tx,omitempty\" protobuf:\"2\"`\n\tOther    *uint32 `yaml:\"other,omitempty\" protobuf:\"3\"`\n\tCombined *uint32 `yaml:\"combined,omitempty\" protobuf:\"4\"`\n}\n\n// NewEthernetSpec initializes a EthernetSpec resource.\nfunc NewEthernetSpec(namespace resource.Namespace, id resource.ID) *EthernetSpec {\n\treturn typed.NewResource[EthernetSpecSpec, EthernetSpecExtension](\n\t\tresource.NewMetadata(namespace, EthernetSpecType, id, resource.VersionUndefined),\n\t\tEthernetSpecSpec{},\n\t)\n}\n\n// EthernetSpecExtension provides auxiliary methods for EthernetSpec.\ntype EthernetSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (EthernetSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EthernetSpecType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.NonSensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EthernetSpecSpec](EthernetSpecType, &EthernetSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/ethernet_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EthernetStatusType is type of EthernetStatus resource.\nconst EthernetStatusType = resource.Type(\"EthernetStatuses.net.talos.dev\")\n\n// EthernetStatus resource holds Ethernet network link status.\ntype EthernetStatus = typed.Resource[EthernetStatusSpec, EthernetStatusExtension]\n\n// EthernetStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype EthernetStatusSpec struct {\n\tLinkState     *bool                     `yaml:\"linkState,omitempty\" protobuf:\"1\"`\n\tSpeedMegabits int                       `yaml:\"speedMbit,omitempty\" protobuf:\"2\"`\n\tPort          nethelpers.Port           `yaml:\"port\" protobuf:\"3\"`\n\tDuplex        nethelpers.Duplex         `yaml:\"duplex\" protobuf:\"4\"`\n\tOurModes      []string                  `yaml:\"ourModes,omitempty\" protobuf:\"5\"`\n\tPeerModes     []string                  `yaml:\"peerModes,omitempty\" protobuf:\"6\"`\n\tRings         *EthernetRingsStatus      `yaml:\"rings,omitempty\" protobuf:\"7\"`\n\tFeatures      EthernetFeatureStatusList `yaml:\"features,omitempty\" protobuf:\"8\"`\n\tChannels      *EthernetChannelsStatus   `yaml:\"channels,omitempty\" protobuf:\"9\"`\n\tWakeOnLAN     []nethelpers.WOLMode      `yaml:\"wakeOnLAN,omitempty\" protobuf:\"10\"`\n}\n\n// EthernetFeatureStatusList is a list of EthernetFeatureStatus.\ntype EthernetFeatureStatusList []EthernetFeatureStatus\n\n// MarshalYAML implements yaml.Marshaler interface.\nfunc (l EthernetFeatureStatusList) MarshalYAML() (any, error) {\n\t// marshal into a custom dict for easier reading\n\t// we use this to preserve the order of Features which is important for the user\n\tnode := &yaml.Node{\n\t\tKind:    yaml.MappingNode,\n\t\tContent: make([]*yaml.Node, 0, len(l)*2),\n\t}\n\n\tfor _, f := range l {\n\t\tnode.Content = append(node.Content, &yaml.Node{\n\t\t\tKind:  yaml.ScalarNode,\n\t\t\tValue: f.Name,\n\t\t}, &yaml.Node{\n\t\t\tKind:  yaml.ScalarNode,\n\t\t\tValue: f.Status,\n\t\t})\n\t}\n\n\treturn node, nil\n}\n\n// EthernetRingsStatus describes status of Ethernet rings.\n//\n//gotagsrewrite:gen\ntype EthernetRingsStatus struct {\n\t// Read-only settings.\n\tRXMax           *uint32 `yaml:\"rx-max,omitempty\" protobuf:\"1\"`\n\tRXMiniMax       *uint32 `yaml:\"rx-mini-max,omitempty\" protobuf:\"2\"`\n\tRXJumboMax      *uint32 `yaml:\"rx-jumbo-max,omitempty\" protobuf:\"3\"`\n\tTXMax           *uint32 `yaml:\"tx-max,omitempty\" protobuf:\"4\"`\n\tTXPushBufLenMax *uint32 `yaml:\"tx-push-buf-len-max,omitempty\" protobuf:\"5\"`\n\n\t// Current settings (read-write).\n\tRX           *uint32 `yaml:\"rx,omitempty\" protobuf:\"6\"`\n\tRXMini       *uint32 `yaml:\"rx-mini,omitempty\" protobuf:\"7\"`\n\tRXJumbo      *uint32 `yaml:\"rx-jumbo,omitempty\" protobuf:\"8\"`\n\tTX           *uint32 `yaml:\"tx,omitempty\" protobuf:\"9\"`\n\tRXBufLen     *uint32 `yaml:\"rx-buf-len,omitempty\" protobuf:\"10\"`\n\tCQESize      *uint32 `yaml:\"cqe-size,omitempty\" protobuf:\"11\"`\n\tTXPush       *bool   `yaml:\"tx-push,omitempty\" protobuf:\"12\"`\n\tRXPush       *bool   `yaml:\"rx-push,omitempty\" protobuf:\"13\"`\n\tTXPushBufLen *uint32 `yaml:\"tx-push-buf-len,omitempty\" protobuf:\"14\"`\n\tTCPDataSplit *bool   `yaml:\"tcp-data-split,omitempty\" protobuf:\"15\"`\n}\n\n// EthernetChannelsStatus describes status of Ethernet channels.\n//\n//gotagsrewrite:gen\ntype EthernetChannelsStatus struct {\n\t// Read-only settings.\n\tRXMax       *uint32 `yaml:\"rx-max,omitempty\" protobuf:\"1\"`\n\tTXMax       *uint32 `yaml:\"tx-max,omitempty\" protobuf:\"2\"`\n\tOtherMax    *uint32 `yaml:\"other-max,omitempty\" protobuf:\"3\"`\n\tCombinedMax *uint32 `yaml:\"combined-max,omitempty\" protobuf:\"4\"`\n\n\t// Current settings (read-write).\n\tRX       *uint32 `yaml:\"rx,omitempty\" protobuf:\"5\"`\n\tTX       *uint32 `yaml:\"tx,omitempty\" protobuf:\"6\"`\n\tOther    *uint32 `yaml:\"other,omitempty\" protobuf:\"7\"`\n\tCombined *uint32 `yaml:\"combined,omitempty\" protobuf:\"8\"`\n}\n\n// EthernetFeatureStatus describes status of Ethernet features.\n//\n//gotagsrewrite:gen\ntype EthernetFeatureStatus struct {\n\tName   string `yaml:\"name\" protobuf:\"1\"`\n\tStatus string `yaml:\"status\" protobuf:\"2\"`\n}\n\n// NewEthernetStatus initializes a EthernetStatus resource.\nfunc NewEthernetStatus(namespace resource.Namespace, id resource.ID) *EthernetStatus {\n\treturn typed.NewResource[EthernetStatusSpec, EthernetStatusExtension](\n\t\tresource.NewMetadata(namespace, EthernetStatusType, id, resource.VersionUndefined),\n\t\tEthernetStatusSpec{},\n\t)\n}\n\n// EthernetStatusExtension provides auxiliary methods for EthernetStatus.\ntype EthernetStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (EthernetStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EthernetStatusType,\n\t\tAliases:          []resource.Type{\"ethtool\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Link\",\n\t\t\t\tJSONPath: `{.linkState}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Speed\",\n\t\t\t\tJSONPath: `{.speedMbit}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.NonSensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EthernetStatusSpec](EthernetStatusType, &EthernetStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/hardrware_addr.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// HardwareAddrType is type of HardwareAddr resource.\nconst HardwareAddrType = resource.Type(\"HardwareAddresses.net.talos.dev\")\n\n// FirstHardwareAddr is a resource ID for the first NIC HW addr.\nconst FirstHardwareAddr = resource.ID(\"first\")\n\n// HardwareAddr resource describes hardware address of the physical links.\ntype HardwareAddr = typed.Resource[HardwareAddrSpec, HardwareAddrExtension]\n\n// HardwareAddrSpec describes spec for the link.\n//\n//gotagsrewrite:gen\ntype HardwareAddrSpec struct {\n\t// Name defines link name\n\tName string `yaml:\"name\" protobuf:\"1\"`\n\n\t// Hardware address\n\tHardwareAddr nethelpers.HardwareAddr `yaml:\"hardwareAddr\" protobuf:\"2\"`\n}\n\n// NewHardwareAddr initializes a HardwareAddr resource.\nfunc NewHardwareAddr(namespace resource.Namespace, id resource.ID) *HardwareAddr {\n\treturn typed.NewResource[HardwareAddrSpec, HardwareAddrExtension](\n\t\tresource.NewMetadata(namespace, HardwareAddrType, id, resource.VersionUndefined),\n\t\tHardwareAddrSpec{},\n\t)\n}\n\n// HardwareAddrExtension provides auxiliary methods for HardwareAddr.\ntype HardwareAddrExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (HardwareAddrExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             HardwareAddrType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[HardwareAddrSpec](HardwareAddrType, &HardwareAddr{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/hostdns_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// HostDNSConfigType is type of HostDNSConfig resource.\nconst HostDNSConfigType = resource.Type(\"HostDNSConfigs.net.talos.dev\")\n\n// HostDNSConfig resource holds host DNS config.\ntype HostDNSConfig = typed.Resource[HostDNSConfigSpec, HostDNSConfigExtension]\n\n// HostDNSConfigID is the singleton ID for HostDNSConfig.\nconst HostDNSConfigID resource.ID = \"config\"\n\n// HostDNSConfigSpec describes host DNS config.\n//\n//gotagsrewrite:gen\ntype HostDNSConfigSpec struct {\n\tEnabled               bool             `yaml:\"enabled\" protobuf:\"1\"`\n\tListenAddresses       []netip.AddrPort `yaml:\"listenAddresses,omitempty\" protobuf:\"2\"`\n\tServiceHostDNSAddress netip.Addr       `yaml:\"serviceHostDNSAddress,omitempty\" protobuf:\"3\"`\n\tResolveMemberNames    bool             `yaml:\"resolveMemberNames,omitempty\" protobuf:\"4\"`\n}\n\n// NewHostDNSConfig initializes a HostDNSConfig resource.\nfunc NewHostDNSConfig(id resource.ID) *HostDNSConfig {\n\treturn typed.NewResource[HostDNSConfigSpec, HostDNSConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, HostDNSConfigType, id, resource.VersionUndefined),\n\t\tHostDNSConfigSpec{},\n\t)\n}\n\n// HostDNSConfigExtension provides auxiliary methods for HostDNSConfig.\ntype HostDNSConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (HostDNSConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             HostDNSConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Enabled\",\n\t\t\t\tJSONPath: \"{.enabled}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[HostDNSConfigSpec](HostDNSConfigType, &HostDNSConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/hostname_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// HostnameSpecType is type of HostnameSpec resource.\nconst HostnameSpecType = resource.Type(\"HostnameSpecs.net.talos.dev\")\n\n// HostnameSpec resource holds node hostname.\ntype HostnameSpec = typed.Resource[HostnameSpecSpec, HostnameSpecExtension]\n\n// HostnameID is the ID of the singleton instance.\nconst HostnameID resource.ID = \"hostname\"\n\n// HostnameSpecSpec describes node hostname.\n//\n//gotagsrewrite:gen\ntype HostnameSpecSpec struct {\n\tHostname    string      `yaml:\"hostname\" protobuf:\"1\"`\n\tDomainname  string      `yaml:\"domainname\" protobuf:\"2\"`\n\tConfigLayer ConfigLayer `yaml:\"layer\" protobuf:\"3\"`\n}\n\n// Validate the hostname.\nfunc (spec *HostnameSpecSpec) Validate() error {\n\tlenHostname := len(spec.Hostname)\n\n\tif lenHostname == 0 || lenHostname > 63 {\n\t\treturn fmt.Errorf(\"invalid hostname %q\", spec.Hostname)\n\t}\n\n\tif len(spec.FQDN()) > 253 {\n\t\treturn fmt.Errorf(\"fqdn is too long: %d\", len(spec.FQDN()))\n\t}\n\n\treturn nil\n}\n\n// FQDN returns the fully-qualified domain name.\nfunc (spec *HostnameSpecSpec) FQDN() string {\n\tif spec.Domainname == \"\" {\n\t\treturn spec.Hostname\n\t}\n\n\treturn spec.Hostname + \".\" + spec.Domainname\n}\n\n// ParseFQDN into parts and validate it.\nfunc (spec *HostnameSpecSpec) ParseFQDN(fqdn string) error {\n\tparts := strings.SplitN(fqdn, \".\", 2)\n\n\tspec.Hostname = parts[0]\n\n\tif len(parts) > 1 {\n\t\tspec.Domainname = parts[1]\n\t}\n\n\treturn spec.Validate()\n}\n\n// NewHostnameSpec initializes a HostnameSpec resource.\nfunc NewHostnameSpec(namespace resource.Namespace, id resource.ID) *HostnameSpec {\n\treturn typed.NewResource[HostnameSpecSpec, HostnameSpecExtension](\n\t\tresource.NewMetadata(namespace, HostnameSpecType, id, resource.VersionUndefined),\n\t\tHostnameSpecSpec{},\n\t)\n}\n\n// HostnameSpecExtension provides auxiliary methods for HostnameSpec.\ntype HostnameSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (HostnameSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             HostnameSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[HostnameSpecSpec](HostnameSpecType, &HostnameSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/hostname_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestHostnameSpecMarshalYAML(t *testing.T) {\n\tspec := network.HostnameSpecSpec{\n\t\tHostname:    \"foo\",\n\t\tDomainname:  \"example.com\",\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"hostname: foo\\ndomainname: example.com\\nlayer: platform\\n\", string(marshaled))\n\n\tvar spec2 network.HostnameSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/hostname_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// HostnameStatusType is type of HostnameStatus resource.\nconst HostnameStatusType = resource.Type(\"HostnameStatuses.net.talos.dev\")\n\n// HostnameStatus resource holds node hostname.\ntype HostnameStatus = typed.Resource[HostnameStatusSpec, HostnameStatusExtension]\n\n// HostnameStatusSpec describes node hostname.\n//\n//gotagsrewrite:gen\ntype HostnameStatusSpec struct {\n\tHostname   string `yaml:\"hostname\" protobuf:\"1\"`\n\tDomainname string `yaml:\"domainname\" protobuf:\"2\"`\n}\n\n// FQDN returns the fully-qualified domain name.\nfunc (spec *HostnameStatusSpec) FQDN() string {\n\tif spec.Domainname == \"\" {\n\t\treturn spec.Hostname\n\t}\n\n\treturn spec.Hostname + \".\" + spec.Domainname\n}\n\n// DNSNames returns DNS names to be added to the certificate based on the hostname and fqdn.\nfunc (spec *HostnameStatusSpec) DNSNames() []string {\n\tresult := []string{spec.Hostname}\n\n\tif spec.Domainname != \"\" {\n\t\tresult = append(result, spec.FQDN())\n\t}\n\n\treturn result\n}\n\n// NewHostnameStatus initializes a HostnameStatus resource.\nfunc NewHostnameStatus(namespace resource.Namespace, id resource.ID) *HostnameStatus {\n\treturn typed.NewResource[HostnameStatusSpec, HostnameStatusExtension](\n\t\tresource.NewMetadata(namespace, HostnameStatusType, id, resource.VersionUndefined),\n\t\tHostnameStatusSpec{},\n\t)\n}\n\n// HostnameStatusExtension provides auxiliary methods for HostnameStatus.\ntype HostnameStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (HostnameStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             HostnameStatusType,\n\t\tAliases:          []resource.Type{\"hostname\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Hostname\",\n\t\t\t\tJSONPath: \"{.hostname}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Domainname\",\n\t\t\t\tJSONPath: \"{.domainname}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[HostnameStatusSpec](HostnameStatusType, &HostnameStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"cmp\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n// VLANSpec describes VLAN settings if Kind == \"vlan\".\n//\n//gotagsrewrite:gen\ntype VLANSpec struct {\n\t// VID is the vlan ID.\n\tVID uint16 `yaml:\"vlanID\" protobuf:\"1\"`\n\n\t// Protocol is the vlan protocol.\n\tProtocol nethelpers.VLANProtocol `yaml:\"vlanProtocol\" protobuf:\"2\"`\n}\n\n// BondMasterSpec describes bond settings if Kind == \"bond\".\n//\n//gotagsrewrite:gen\ntype BondMasterSpec struct {\n\t// Mode specifies the bonding policy\n\tMode nethelpers.BondMode `yaml:\"mode\" protobuf:\"1\"`\n\t// HashPolicy selects the transmit hash policy to use for slave selection.\n\tHashPolicy nethelpers.BondXmitHashPolicy `yaml:\"xmitHashPolicy\" protobuf:\"2\"`\n\t// LACPRate specifies the rate at which LACPDU frames are sent.\n\tLACPRate nethelpers.LACPRate `yaml:\"lacpRate\" protobuf:\"3\"`\n\t// ARPValidate specifies whether or not ARP probes and replies should be validated.\n\tARPValidate nethelpers.ARPValidate `yaml:\"arpValidate\" protobuf:\"4\"`\n\t// ARPAllTargets specifies whether ARP probes should be sent to any or all targets.\n\tARPAllTargets nethelpers.ARPAllTargets `yaml:\"arpAllTargets\" protobuf:\"5\"`\n\t// PrimaryIndex is a device index specifying which slave is the primary device.\n\tPrimaryIndex *uint32 `yaml:\"primary,omitempty\" protobuf:\"6\"`\n\t// PrimaryReselect specifies the policy under which the primary slave should be reselected.\n\tPrimaryReselect nethelpers.PrimaryReselect `yaml:\"primaryReselect\" protobuf:\"7\"`\n\t// FailOverMac whether active-backup mode should set all slaves to the same MAC address at enslavement, when enabled, or perform special handling.\n\tFailOverMac nethelpers.FailOverMAC `yaml:\"failOverMac\" protobuf:\"8\"`\n\t// ADSelect specifies the aggregate selection policy for 802.3ad.\n\tADSelect nethelpers.ADSelect `yaml:\"adSelect,omitempty\" protobuf:\"9\"`\n\t// MIIMon is the link monitoring frequency in milliseconds.\n\tMIIMon uint32 `yaml:\"miimon,omitempty\" protobuf:\"10\"`\n\t// UpDelay is the time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\n\tUpDelay uint32 `yaml:\"updelay,omitempty\" protobuf:\"11\"`\n\t// DownDelay is the time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\n\tDownDelay uint32 `yaml:\"downdelay,omitempty\" protobuf:\"12\"`\n\t// ARPInterval is the ARP link monitoring frequency in milliseconds.\n\tARPInterval uint32 `yaml:\"arpInterval,omitempty\" protobuf:\"13\"`\n\t// ResendIGMP specifies the number of times IGMP packets should be resent.\n\tResendIGMP uint32 `yaml:\"resendIgmp,omitempty\" protobuf:\"14\"`\n\t// MinLinks specifies the minimum number of active links to assert carrier.\n\tMinLinks uint32 `yaml:\"minLinks,omitempty\" protobuf:\"15\"`\n\t// LPInterval specifies the number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\n\tLPInterval uint32 `yaml:\"lpInterval,omitempty\" protobuf:\"16\"`\n\t// PacketsPerSlave specifies the number of packets to transmit through a slave before moving to the next one.\n\tPacketsPerSlave uint32 `yaml:\"packetsPerSlave,omitempty\" protobuf:\"17\"`\n\t// NumPeerNotif specifies the number of peer notifications\n\t// (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements) to be issued after a failover event.\n\tNumPeerNotif uint8 `yaml:\"numPeerNotif,omitempty\" protobuf:\"18\"`\n\t// TLBDynamicLB specifies if dynamic shuffling of flows is enabled in tlb or alb mode.\n\tTLBDynamicLB uint8 `yaml:\"tlbLogicalLb,omitempty\" protobuf:\"19\"`\n\t// AllSlavesActive specifies that duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\n\tAllSlavesActive uint8 `yaml:\"allSlavesActive,omitempty\" protobuf:\"20\"`\n\t// UseCarrier specifies whether or not miimon should use MII or ETHTOOL.\n\tUseCarrier bool `yaml:\"useCarrier,omitempty\" protobuf:\"21\"`\n\t// ADActorSysPrio is the actor system priority for 802.3ad.\n\tADActorSysPrio uint16 `yaml:\"adActorSysPrio,omitempty\" protobuf:\"22\"`\n\t// ADUserPortKey is the user port key (upper 10 bits) for 802.3ad.\n\tADUserPortKey uint16 `yaml:\"adUserPortKey,omitempty\" protobuf:\"23\"`\n\t// PeerNotifyDelay is the delay, in milliseconds, between each peer notification.\n\tPeerNotifyDelay uint32 `yaml:\"peerNotifyDelay,omitempty\" protobuf:\"24\"`\n\t// ARPIPTargets is the list of IP addresses to use for ARP link monitoring when ARPInterval is set.\n\t//\n\t// Maximum of 16 targets are supported.\n\tARPIPTargets []netip.Addr `yaml:\"arpIpTargets,omitempty\" protobuf:\"25\"`\n\t// NSIP6Targets is the list of IPv6 addresses to use for NS link monitoring when ARPInterval is set.\n\t//\n\t// Maximum of 16 targets are supported.\n\tNSIP6Targets []netip.Addr `yaml:\"nsIp6Targets,omitempty\" protobuf:\"26\"`\n\t// ADLACPActive specifies whether to send LACPDU frames periodically.\n\tADLACPActive nethelpers.ADLACPActive `yaml:\"adLacpActive,omitempty\" protobuf:\"27\"`\n\t// MissedMax is the number of arp_interval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\n\tMissedMax uint8 `yaml:\"missedMax,omitempty\" protobuf:\"28\"`\n}\n\n// Equal checks two BondMasterSpecs for equality.\n//\n//nolint:gocyclo,cyclop\nfunc (spec *BondMasterSpec) Equal(other *BondMasterSpec) bool {\n\tif spec.Mode != other.Mode {\n\t\treturn false\n\t}\n\n\tif spec.HashPolicy != other.HashPolicy {\n\t\treturn false\n\t}\n\n\tif spec.LACPRate != other.LACPRate {\n\t\treturn false\n\t}\n\n\tif spec.ARPValidate != other.ARPValidate {\n\t\treturn false\n\t}\n\n\tif spec.ARPAllTargets != other.ARPAllTargets {\n\t\treturn false\n\t}\n\n\tif spec.PrimaryIndex != nil && other.PrimaryIndex != nil && *spec.PrimaryIndex != *other.PrimaryIndex {\n\t\treturn false\n\t}\n\n\tif spec.PrimaryReselect != other.PrimaryReselect {\n\t\treturn false\n\t}\n\n\tif spec.FailOverMac != other.FailOverMac {\n\t\treturn false\n\t}\n\n\tif spec.ADSelect != other.ADSelect {\n\t\treturn false\n\t}\n\n\tif spec.MIIMon != other.MIIMon {\n\t\treturn false\n\t}\n\n\tif spec.UpDelay != other.UpDelay {\n\t\treturn false\n\t}\n\n\tif spec.DownDelay != other.DownDelay {\n\t\treturn false\n\t}\n\n\tif spec.ARPInterval != other.ARPInterval {\n\t\treturn false\n\t}\n\n\tif spec.ResendIGMP != other.ResendIGMP {\n\t\treturn false\n\t}\n\n\tif spec.MinLinks != other.MinLinks {\n\t\treturn false\n\t}\n\n\tif spec.LPInterval != other.LPInterval {\n\t\treturn false\n\t}\n\n\tif spec.PacketsPerSlave != other.PacketsPerSlave {\n\t\treturn false\n\t}\n\n\tif spec.NumPeerNotif != other.NumPeerNotif {\n\t\treturn false\n\t}\n\n\tif spec.TLBDynamicLB != other.TLBDynamicLB {\n\t\treturn false\n\t}\n\n\tif spec.AllSlavesActive != other.AllSlavesActive {\n\t\treturn false\n\t}\n\n\tif spec.UseCarrier != other.UseCarrier {\n\t\treturn false\n\t}\n\n\tif spec.ADActorSysPrio != other.ADActorSysPrio {\n\t\treturn false\n\t}\n\n\tif spec.ADUserPortKey != other.ADUserPortKey {\n\t\treturn false\n\t}\n\n\tif spec.PeerNotifyDelay != other.PeerNotifyDelay {\n\t\treturn false\n\t}\n\n\tif len(spec.ARPIPTargets) != len(other.ARPIPTargets) {\n\t\treturn false\n\t}\n\n\tfor i := range spec.ARPIPTargets {\n\t\tif spec.ARPIPTargets[i] != other.ARPIPTargets[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(spec.NSIP6Targets) != len(other.NSIP6Targets) {\n\t\treturn false\n\t}\n\n\tfor i := range spec.NSIP6Targets {\n\t\tif spec.NSIP6Targets[i] != other.NSIP6Targets[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif spec.ADLACPActive != other.ADLACPActive {\n\t\treturn false\n\t}\n\n\tif spec.Mode != nethelpers.BondMode8023AD && spec.Mode != nethelpers.BondModeALB && spec.Mode != nethelpers.BondModeTLB {\n\t\tif spec.MissedMax != other.MissedMax {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// IsZero checks if the BondMasterSpec is zero value.\n//\n//nolint:gocyclo,cyclop\nfunc (spec *BondMasterSpec) IsZero() bool {\n\treturn spec.Mode == 0 &&\n\t\tspec.HashPolicy == 0 &&\n\t\tspec.LACPRate == 0 &&\n\t\tspec.ARPValidate == 0 &&\n\t\tspec.ARPAllTargets == 0 &&\n\t\tspec.PrimaryIndex == nil &&\n\t\tspec.PrimaryReselect == 0 &&\n\t\tspec.FailOverMac == 0 &&\n\t\tspec.ADSelect == 0 &&\n\t\tspec.MIIMon == 0 &&\n\t\tspec.UpDelay == 0 &&\n\t\tspec.DownDelay == 0 &&\n\t\tspec.ARPInterval == 0 &&\n\t\tspec.ResendIGMP == 0 &&\n\t\tspec.MinLinks == 0 &&\n\t\tspec.LPInterval == 0 &&\n\t\tspec.PacketsPerSlave == 0 &&\n\t\tspec.NumPeerNotif == 0 &&\n\t\tspec.TLBDynamicLB == 0 &&\n\t\tspec.AllSlavesActive == 0 &&\n\t\t!spec.UseCarrier &&\n\t\tspec.ADActorSysPrio == 0 &&\n\t\tspec.ADUserPortKey == 0 &&\n\t\tspec.PeerNotifyDelay == 0 &&\n\t\tlen(spec.ARPIPTargets) == 0 &&\n\t\tlen(spec.NSIP6Targets) == 0 &&\n\t\tspec.ADLACPActive == 0 &&\n\t\tspec.MissedMax == 0\n}\n\n// BridgeMasterSpec describes bridge settings if Kind == \"bridge\".\n//\n//gotagsrewrite:gen\ntype BridgeMasterSpec struct {\n\tSTP  STPSpec        `yaml:\"stp,omitempty\" protobuf:\"1\"`\n\tVLAN BridgeVLANSpec `yaml:\"vlan,omitempty\" protobuf:\"2\"`\n}\n\n// STPSpec describes Spanning Tree Protocol (STP) settings of a bridge.\n//\n//gotagsrewrite:gen\ntype STPSpec struct {\n\tEnabled bool `yaml:\"enabled\" protobuf:\"1\"`\n}\n\n// BridgeVLANSpec describes VLAN settings of a bridge.\n//\n//gotagsrewrite:gen\ntype BridgeVLANSpec struct {\n\tFilteringEnabled bool `yaml:\"filteringEnabled\" protobuf:\"1\"`\n}\n\n// VRFMasterSpec describes vrf settings if Kind == \"vrf\".\n//\n//gotagsrewrite:gen\ntype VRFMasterSpec struct {\n\tTable nethelpers.RoutingTable `yaml:\"table\" protobuf:\"1\"`\n}\n\n// WireguardSpec describes Wireguard settings if Kind == \"wireguard\".\n//\n//gotagsrewrite:gen\ntype WireguardSpec struct {\n\t// PrivateKey is used to configure the link, present only in the LinkSpec.\n\tPrivateKey string `yaml:\"privateKey,omitempty\" protobuf:\"1\"`\n\t// PublicKey is only used in LinkStatus to show the link status.\n\tPublicKey    string          `yaml:\"publicKey,omitempty\" protobuf:\"2\"`\n\tListenPort   int             `yaml:\"listenPort\" protobuf:\"3\"`\n\tFirewallMark int             `yaml:\"firewallMark\" protobuf:\"4\"`\n\tPeers        []WireguardPeer `yaml:\"peers\" protobuf:\"5\"`\n}\n\n// WireguardPeer describes a single peer.\n//\n//gotagsrewrite:gen\ntype WireguardPeer struct {\n\tPublicKey                   string         `yaml:\"publicKey\" protobuf:\"1\"`\n\tPresharedKey                string         `yaml:\"presharedKey\" protobuf:\"2\"`\n\tEndpoint                    string         `yaml:\"endpoint\" protobuf:\"3\"`\n\tPersistentKeepaliveInterval time.Duration  `yaml:\"persistentKeepaliveInterval\" protobuf:\"4\"`\n\tAllowedIPs                  []netip.Prefix `yaml:\"allowedIPs\" protobuf:\"5\"`\n}\n\n// ID Returns the VID for type VLANSpec.\nfunc (vlan VLANSpec) ID() uint16 {\n\treturn vlan.VID\n}\n\n// MTU Returns MTU=0 for type VLANSpec.\nfunc (vlan VLANSpec) MTU() uint32 {\n\treturn 0\n}\n\n// Mode returns the protocol (mode) for type VLANSpec.\nfunc (vlan VLANSpec) Mode() nethelpers.VLANProtocol {\n\treturn vlan.Protocol\n}\n\n// Equal checks two WireguardPeer structs for equality.\n//\n// `spec` is considered to be the result of getting current Wireguard configuration,\n// while `other` is the new (updated configuration).\nfunc (peer *WireguardPeer) Equal(other *WireguardPeer) bool {\n\tif peer.PublicKey != other.PublicKey {\n\t\treturn false\n\t}\n\n\tif peer.PresharedKey != other.PresharedKey {\n\t\treturn false\n\t}\n\n\t// if the Endpoint is not set in `other`, don't consider this to be a change\n\tif other.Endpoint != \"\" && peer.Endpoint != other.Endpoint {\n\t\treturn false\n\t}\n\n\tif peer.PersistentKeepaliveInterval != other.PersistentKeepaliveInterval {\n\t\treturn false\n\t}\n\n\tif len(peer.AllowedIPs) != len(other.AllowedIPs) {\n\t\treturn false\n\t}\n\n\tfor i := range peer.AllowedIPs {\n\t\tif peer.AllowedIPs[i].Addr().Compare(other.AllowedIPs[i].Addr()) != 0 {\n\t\t\treturn false\n\t\t}\n\n\t\tif peer.AllowedIPs[i].Bits() != other.AllowedIPs[i].Bits() {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// IsZero checks if the WireguardSpec is zero value.\nfunc (spec *WireguardSpec) IsZero() bool {\n\treturn spec.PrivateKey == \"\" && spec.ListenPort == 0 && spec.FirewallMark == 0 && len(spec.Peers) == 0\n}\n\n// Equal checks two WireguardSpecs for equality.\n//\n// Both specs should be sorted before calling this method.\n//\n// `spec` is considered to be the result of getting current Wireguard configuration,\n// while `other` is the new (updated configuration).\nfunc (spec *WireguardSpec) Equal(other *WireguardSpec) bool {\n\tif spec.PrivateKey != other.PrivateKey {\n\t\treturn false\n\t}\n\n\t// listenPort of '0' means use any available port, so we shouldn't consider this to be a \"change\"\n\tif spec.ListenPort != other.ListenPort && other.ListenPort != 0 {\n\t\treturn false\n\t}\n\n\tif spec.FirewallMark != other.FirewallMark {\n\t\treturn false\n\t}\n\n\tif len(spec.Peers) != len(other.Peers) {\n\t\treturn false\n\t}\n\n\tfor i := range spec.Peers {\n\t\tif !spec.Peers[i].Equal(&other.Peers[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Sort the spec so that comparison is possible.\nfunc (spec *WireguardSpec) Sort() {\n\tslices.SortFunc(spec.Peers, func(a, b WireguardPeer) int { return cmp.Compare(a.PublicKey, b.PublicKey) })\n\n\tfor k := range spec.Peers {\n\t\tslices.SortFunc(spec.Peers[k].AllowedIPs, func(left, right netip.Prefix) int {\n\t\t\tif res := left.Addr().Compare(right.Addr()); res != 0 {\n\t\t\t\treturn res\n\t\t\t}\n\n\t\t\treturn cmp.Compare(left.Bits(), right.Bits())\n\t\t})\n\t}\n}\n\n// Merge with other Wireguard spec overwriting non-zero values.\nfunc (spec *WireguardSpec) Merge(other WireguardSpec) {\n\tif other.ListenPort != 0 {\n\t\tspec.ListenPort = other.ListenPort\n\t}\n\n\tif other.FirewallMark != 0 {\n\t\tspec.FirewallMark = other.FirewallMark\n\t}\n\n\tif other.PrivateKey != \"\" {\n\t\tspec.PrivateKey = other.PrivateKey\n\t}\n\n\t// avoid adding same peer twice, no real peer information merging for now\n\tfor _, peer := range other.Peers {\n\t\texists := false\n\n\t\tfor _, p := range spec.Peers {\n\t\t\tif p.PublicKey == peer.PublicKey {\n\t\t\t\texists = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !exists {\n\t\t\tspec.Peers = append(spec.Peers, peer)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_alias_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// LinkAliasSpecType is type of LinkAliasSpec resource.\nconst LinkAliasSpecType = resource.Type(\"LinkAliasSpecs.net.talos.dev\")\n\n// LinkAliasSpec resource tells which link should have which alias (name).\n//\n// If the link shouldn't have the alias, resource is removed.\ntype LinkAliasSpec = typed.Resource[LinkAliasSpecSpec, LinkAliasSpecExtension]\n\n// LinkAliasSpecSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype LinkAliasSpecSpec struct {\n\tAlias string `yaml:\"alias\" protobuf:\"1\"`\n}\n\n// NewLinkAliasSpec initializes a LinkAliasSpec resource.\nfunc NewLinkAliasSpec(namespace resource.Namespace, id resource.ID) *LinkAliasSpec {\n\treturn typed.NewResource[LinkAliasSpecSpec, LinkAliasSpecExtension](\n\t\tresource.NewMetadata(namespace, LinkAliasSpecType, id, resource.VersionUndefined),\n\t\tLinkAliasSpecSpec{},\n\t)\n}\n\n// LinkAliasSpecExtension provides auxiliary methods for LinkAliasSpec.\ntype LinkAliasSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (LinkAliasSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             LinkAliasSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Alias\",\n\t\t\t\tJSONPath: `{.alias}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[LinkAliasSpecSpec](LinkAliasSpecType, &LinkAliasSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_name_resolver.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport \"iter\"\n\n// LinkResolver resolves link names and aliases to actual link names.\ntype LinkResolver struct {\n\tlookup map[string]string // map of link names/aliases to link names\n}\n\n// Resolve resolves the link name or alias to the actual link name.\n//\n// If the link name or alias is not found in the lookup table, it is returned as is.\nfunc (r *LinkResolver) Resolve(name string) string {\n\tif resolved, ok := r.lookup[name]; ok {\n\t\treturn resolved\n\t}\n\n\treturn name\n}\n\n// NewLinkResolver creates a new link name resolver.\nfunc NewLinkResolver(f func() iter.Seq[*LinkStatus]) *LinkResolver {\n\tlookup := make(map[string]string)\n\n\tfor link := range f() {\n\t\tfor alias := range AllLinkAliases(link) {\n\t\t\tlookup[alias] = link.Metadata().ID()\n\t\t}\n\t}\n\n\tfor link := range f() {\n\t\tlookup[link.Metadata().ID()] = link.Metadata().ID()\n\t}\n\n\treturn &LinkResolver{lookup: lookup}\n}\n\n// NewEmptyLinkResolver creates a new link name resolver with an empty lookup table.\nfunc NewEmptyLinkResolver() *LinkResolver {\n\treturn &LinkResolver{}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_name_resolver_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"iter\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestLinkNameResolver(t *testing.T) {\n\tt.Parallel()\n\n\tlink1 := network.NewLinkStatus(network.NamespaceName, \"eth0\")\n\tlink1.TypedSpec().Alias = \"net0\"\n\tlink1.TypedSpec().AltNames = []string{\"ext0\"}\n\n\tlink2 := network.NewLinkStatus(network.NamespaceName, \"eth1\")\n\n\tlink3 := network.NewLinkStatus(network.NamespaceName, \"eth2\")\n\tlink3.TypedSpec().AltNames = []string{\"ext2\"}\n\n\tlinks := []*network.LinkStatus{\n\t\tlink1,\n\t\tlink2,\n\t\tlink3,\n\t}\n\n\tresolver := network.NewLinkResolver(func() iter.Seq[*network.LinkStatus] { return slices.Values(links) })\n\n\tassert.Equal(t, \"eth0\", resolver.Resolve(\"eth0\"))\n\tassert.Equal(t, \"eth0\", resolver.Resolve(\"net0\"))\n\tassert.Equal(t, \"eth0\", resolver.Resolve(\"ext0\"))\n\tassert.Equal(t, \"eth1\", resolver.Resolve(\"eth1\"))\n\tassert.Equal(t, \"eth2\", resolver.Resolve(\"eth2\"))\n\tassert.Equal(t, \"eth2\", resolver.Resolve(\"ext2\"))\n\tassert.Equal(t, \"eth3\", resolver.Resolve(\"eth3\"))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_refresh.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// LinkRefreshType is type of LinkRefresh resource.\nconst LinkRefreshType = resource.Type(\"LinkRefreshes.net.talos.dev\")\n\n// LinkRefresh resource is used to communicate link changes which can't be subscribed to via netlink.\n//\n// The only usecase for now is the Wireguards, as there's no way subscribe to wireguard updates\n// via the netlink API.\n//\n// Whenever Wireguard interface is updated, LinkRefresh resource is modified to trigger a reconcile\n// loop in the LinkStatusController.\ntype LinkRefresh = typed.Resource[LinkRefreshSpec, LinkRefreshExtension]\n\n// LinkRefreshSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype LinkRefreshSpec struct {\n\tGeneration int `yaml:\"generation\" protobuf:\"1\"`\n}\n\n// Bump performs an update.\nfunc (s *LinkRefreshSpec) Bump() {\n\ts.Generation++\n}\n\n// NewLinkRefresh initializes a LinkRefresh resource.\nfunc NewLinkRefresh(namespace resource.Namespace, id resource.ID) *LinkRefresh {\n\treturn typed.NewResource[LinkRefreshSpec, LinkRefreshExtension](\n\t\tresource.NewMetadata(namespace, LinkRefreshType, id, resource.VersionUndefined),\n\t\tLinkRefreshSpec{},\n\t)\n}\n\n// LinkRefreshExtension provides auxiliary methods for LinkRefresh.\ntype LinkRefreshExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (LinkRefreshExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             LinkRefreshType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[LinkRefreshSpec](LinkRefreshType, &LinkRefresh{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// LinkSpecType is type of LinkSpec resource.\nconst LinkSpecType = resource.Type(\"LinkSpecs.net.talos.dev\")\n\n// LinkSpec resource describes desired state of the link (network interface).\ntype LinkSpec = typed.Resource[LinkSpecSpec, LinkSpecExtension]\n\n// LinkSpecSpec describes spec for the link.\n//\n//gotagsrewrite:gen\ntype LinkSpecSpec struct {\n\t// Name defines link name\n\tName string `yaml:\"name\" protobuf:\"1\"`\n\n\t// Logical describes if the interface should be created on the fly if it doesn't exist.\n\tLogical bool `yaml:\"logical\" protobuf:\"2\"`\n\n\t// If Up is true, bring interface up, otherwise bring interface down.\n\t//\n\t// TODO: make *bool ?\n\tUp bool `yaml:\"up\" protobuf:\"3\"`\n\n\t// Interface MTU (always applies).\n\tMTU uint32 `yaml:\"mtu\" protobuf:\"4\"`\n\n\t// Kind and Type are only required for Logical interfaces.\n\tKind string              `yaml:\"kind\" protobuf:\"5\"`\n\tType nethelpers.LinkType `yaml:\"type\" protobuf:\"6\"`\n\n\t// Override hardware (MAC) address (if supported).\n\tHardwareAddress nethelpers.HardwareAddr `yaml:\"hardwareAddr,omitempty\" protobuf:\"15\"`\n\n\t// ParentName indicates link parent for VLAN interfaces.\n\tParentName string `yaml:\"parentName,omitempty\" protobuf:\"7\"`\n\n\t// MasterName indicates master link for enslaved bonded interfaces.\n\tBondSlave BondSlave `yaml:\",omitempty,inline\" protobuf:\"8\"`\n\n\t// BridgeSlave indicates master link for bridged interfaces.\n\tBridgeSlave BridgeSlave `yaml:\"bridgeSlave,omitempty\" protobuf:\"9\"`\n\n\t// VRFSlave indicates master link for interfaces in a vrf\n\tVRFSlave VRFSlave `yaml:\"vrfSlave,omitempty\" protobuf:\"18\"`\n\n\t// These structures are present depending on \"Kind\" for Logical interfaces.\n\tVLAN         VLANSpec         `yaml:\"vlan,omitempty\" protobuf:\"10\"`\n\tBondMaster   BondMasterSpec   `yaml:\"bondMaster,omitempty\" protobuf:\"11\"`\n\tBridgeMaster BridgeMasterSpec `yaml:\"bridgeMaster,omitempty\" protobuf:\"12\"`\n\tVRFMaster    VRFMasterSpec    `yaml:\"vrfMaster,omitempty\" protobuf:\"17\"`\n\tWireguard    WireguardSpec    `yaml:\"wireguard,omitempty\" protobuf:\"13\"`\n\n\t// Configuration layer.\n\tConfigLayer ConfigLayer `yaml:\"layer\" protobuf:\"14\"`\n\n\t// Multicast indicates whether the multicast flag should be set on the interface to the value.\n\tMulticast *bool `yaml:\"multicast,omitempty\" protobuf:\"16\"`\n}\n\n// BondSlave contains a bond's master name and slave index.\n//\n//gotagsrewrite:gen\ntype BondSlave struct {\n\t// MasterName indicates master link for enslaved bonded interfaces.\n\tMasterName string `yaml:\"masterName,omitempty\" protobuf:\"1\"`\n\n\t// SlaveIndex indicates a slave's position in bond.\n\tSlaveIndex int `yaml:\"slaveIndex,omitempty\" protobuf:\"2\"`\n}\n\n// BridgeSlave contains the name of the master bridge of a bridged interface\n//\n//gotagsrewrite:gen\ntype BridgeSlave struct {\n\t// MasterName indicates master link for enslaved bridged interfaces.\n\tMasterName string `yaml:\"masterName,omitempty\" protobuf:\"1\"`\n}\n\n// VRFSlave contains the name of the master vrf for an interface\n//\n//gotagsrewrite:gen\ntype VRFSlave struct {\n\tMasterName string `yaml:\"masterName,omitempty\" protobuf:\"1\"`\n}\n\n// Merge with other, overwriting fields from other if set.\nfunc (spec *LinkSpecSpec) Merge(other *LinkSpecSpec) error {\n\t// prefer Logical, as it is defined for bonds/vlans, etc.\n\tupdateIfNotZero(&spec.Logical, other.Logical)\n\tupdateIfNotZero(&spec.Up, other.Up)\n\tupdateIfNotZero(&spec.MTU, other.MTU)\n\tupdateIfNotZero(&spec.Kind, other.Kind)\n\tupdateIfNotZero(&spec.Type, other.Type)\n\tupdateIfNotZero(&spec.ParentName, other.ParentName)\n\tupdateIfNotZero(&spec.BondSlave, other.BondSlave)\n\tupdateIfNotZero(&spec.VLAN, other.VLAN)\n\tupdateIfNotZero(&spec.BridgeMaster, other.BridgeMaster)\n\tupdateIfNotZero(&spec.BridgeSlave, other.BridgeSlave)\n\tupdateIfNotZero(&spec.VRFMaster, other.VRFMaster)\n\tupdateIfNotZero(&spec.VRFSlave, other.VRFSlave)\n\n\tif !other.BondMaster.IsZero() {\n\t\tspec.BondMaster = other.BondMaster.DeepCopy()\n\t}\n\n\tif other.HardwareAddress != nil {\n\t\tspec.HardwareAddress = slices.Clone(other.HardwareAddress)\n\t}\n\n\t// Wireguard config should be able to apply non-zero values in earlier config layers which may be zero values in later layers.\n\t// Thus, we handle each Wireguard configuration value discretely.\n\tif !other.Wireguard.IsZero() {\n\t\tif spec.Wireguard.IsZero() {\n\t\t\tspec.Wireguard = other.Wireguard\n\t\t} else {\n\t\t\tspec.Wireguard.Merge(other.Wireguard)\n\t\t}\n\t}\n\n\tspec.ConfigLayer = other.ConfigLayer\n\n\treturn nil\n}\n\nfunc updateIfNotZero[T comparable](target *T, source T) {\n\tvar zero T\n\tif source != zero {\n\t\t*target = source\n\t}\n}\n\n// NewLinkSpec initializes a LinkSpec resource.\nfunc NewLinkSpec(namespace resource.Namespace, id resource.ID) *LinkSpec {\n\treturn typed.NewResource[LinkSpecSpec, LinkSpecExtension](\n\t\tresource.NewMetadata(namespace, LinkSpecType, id, resource.VersionUndefined),\n\t\tLinkSpecSpec{},\n\t)\n}\n\n// LinkSpecExtension provides auxiliary methods for LinkSpec.\ntype LinkSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (LinkSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             LinkSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[LinkSpecSpec](LinkSpecType, &LinkSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestLinkSpecMarshalYAML(t *testing.T) {\n\tspec := network.LinkSpecSpec{\n\t\tName:       \"eth0\",\n\t\tLogical:    true,\n\t\tUp:         true,\n\t\tMTU:        1437,\n\t\tKind:       \"eth\",\n\t\tType:       nethelpers.LinkEther,\n\t\tParentName: \"eth1\",\n\t\tBondSlave: network.BondSlave{\n\t\t\tMasterName: \"bond0\",\n\t\t\tSlaveIndex: 0,\n\t\t},\n\t\tVRFSlave: network.VRFSlave{\n\t\t\tMasterName: \"vrf-blue\",\n\t\t},\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      25,\n\t\t\tProtocol: nethelpers.VLANProtocol8021AD,\n\t\t},\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode:            nethelpers.BondMode8023AD,\n\t\t\tHashPolicy:      nethelpers.BondXmitPolicyEncap34,\n\t\t\tLACPRate:        nethelpers.LACPRateFast,\n\t\t\tARPValidate:     nethelpers.ARPValidateAll,\n\t\t\tARPAllTargets:   nethelpers.ARPAllTargetsAny,\n\t\t\tPrimaryIndex:    new(uint32(3)),\n\t\t\tPrimaryReselect: nethelpers.PrimaryReselectBetter,\n\t\t\tFailOverMac:     nethelpers.FailOverMACFollow,\n\t\t\tADSelect:        nethelpers.ADSelectCount,\n\t\t\tMIIMon:          33,\n\t\t\tUpDelay:         100,\n\t\t\tDownDelay:       200,\n\t\t\tARPInterval:     10,\n\t\t\tResendIGMP:      30,\n\t\t\tMinLinks:        1,\n\t\t\tLPInterval:      3,\n\t\t\tPacketsPerSlave: 4,\n\t\t\tNumPeerNotif:    4,\n\t\t\tTLBDynamicLB:    5,\n\t\t\tAllSlavesActive: 1,\n\t\t\tUseCarrier:      true,\n\t\t\tADActorSysPrio:  6,\n\t\t\tADUserPortKey:   7,\n\t\t\tPeerNotifyDelay: 40,\n\t\t},\n\t\tVRFMaster: network.VRFMasterSpec{\n\t\t\tTable: 123,\n\t\t},\n\t\tWireguard: network.WireguardSpec{\n\t\t\tPrivateKey:   \"foo=\",\n\t\t\tPublicKey:    \"bar=\",\n\t\t\tListenPort:   51820,\n\t\t\tFirewallMark: 11233,\n\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey:                   \"peer=\",\n\t\t\t\t\tPresharedKey:                \"key=\",\n\t\t\t\t\tEndpoint:                    \"127.0.0.1:3333\",\n\t\t\t\t\tPersistentKeepaliveInterval: 30 * time.Second,\n\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.83.93.94/31\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t,\n\t\t`name: eth0\nlogical: true\nup: true\nmtu: 1437\nkind: eth\ntype: ether\nparentName: eth1\nmasterName: bond0\nvrfSlave:\n    masterName: vrf-blue\nvlan:\n    vlanID: 25\n    vlanProtocol: 802.1ad\nbondMaster:\n    mode: 802.3ad\n    xmitHashPolicy: encap3+4\n    lacpRate: fast\n    arpValidate: all\n    arpAllTargets: any\n    primary: 3\n    primaryReselect: better\n    failOverMac: follow\n    adSelect: count\n    miimon: 33\n    updelay: 100\n    downdelay: 200\n    arpInterval: 10\n    resendIgmp: 30\n    minLinks: 1\n    lpInterval: 3\n    packetsPerSlave: 4\n    numPeerNotif: 4\n    tlbLogicalLb: 5\n    allSlavesActive: 1\n    useCarrier: true\n    adActorSysPrio: 6\n    adUserPortKey: 7\n    peerNotifyDelay: 40\nvrfMaster:\n    table: \"123\"\nwireguard:\n    privateKey: foo=\n    publicKey: bar=\n    listenPort: 51820\n    firewallMark: 11233\n    peers:\n        - publicKey: peer=\n          presharedKey: key=\n          endpoint: 127.0.0.1:3333\n          persistentKeepaliveInterval: 30s\n          allowedIPs:\n            - 192.83.93.94/31\nlayer: platform\n`,\n\t\tstring(marshaled))\n\n\tvar spec2 network.LinkSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"iter\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// LinkStatusType is type of LinkStatus resource.\nconst LinkStatusType = resource.Type(\"LinkStatuses.net.talos.dev\")\n\n// LinkStatus resource holds physical network link status.\ntype LinkStatus = typed.Resource[LinkStatusSpec, LinkStatusExtension]\n\n// LinkStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype LinkStatusSpec struct {\n\t// Fields coming from rtnetlink API.\n\tAlias            string                      `yaml:\"alias,omitempty\" protobuf:\"31\"`\n\tAltNames         []string                    `yaml:\"altNames,omitempty\" protobuf:\"32\"`\n\tIndex            uint32                      `yaml:\"index\" protobuf:\"1\"`\n\tType             nethelpers.LinkType         `yaml:\"type\" protobuf:\"2\"`\n\tLinkIndex        uint32                      `yaml:\"linkIndex\" protobuf:\"3\"`\n\tFlags            nethelpers.LinkFlags        `yaml:\"flags\" protobuf:\"4\"`\n\tHardwareAddr     nethelpers.HardwareAddr     `yaml:\"hardwareAddr\" protobuf:\"5\"`\n\tPermanentAddr    nethelpers.HardwareAddr     `yaml:\"permanentAddr\" protobuf:\"30\"`\n\tBroadcastAddr    nethelpers.HardwareAddr     `yaml:\"broadcastAddr\" protobuf:\"6\"`\n\tMTU              uint32                      `yaml:\"mtu\" protobuf:\"7\"`\n\tQueueDisc        string                      `yaml:\"queueDisc\" protobuf:\"8\"`\n\tMasterIndex      uint32                      `yaml:\"masterIndex,omitempty\" protobuf:\"9\"`\n\tOperationalState nethelpers.OperationalState `yaml:\"operationalState\" protobuf:\"10\"`\n\tKind             string                      `yaml:\"kind\" protobuf:\"11\"`\n\tSlaveKind        string                      `yaml:\"slaveKind\" protobuf:\"12\"`\n\tBusPath          string                      `yaml:\"busPath,omitempty\" protobuf:\"13\"`\n\tPCIID            string                      `yaml:\"pciID,omitempty\" protobuf:\"14\"`\n\tDriver           string                      `yaml:\"driver,omitempty\" protobuf:\"15\"`\n\tDriverVersion    string                      `yaml:\"driverVersion,omitempty\" protobuf:\"16\"`\n\tFirmwareVersion  string                      `yaml:\"firmwareVersion,omitempty\" protobuf:\"17\"`\n\tProductID        string                      `yaml:\"productID,omitempty\" protobuf:\"18\"`\n\tVendorID         string                      `yaml:\"vendorID,omitempty\" protobuf:\"19\"`\n\tProduct          string                      `yaml:\"product,omitempty\" protobuf:\"20\"`\n\tVendor           string                      `yaml:\"vendor,omitempty\" protobuf:\"21\"`\n\t// Fields coming from ethtool API.\n\tLinkState     bool              `yaml:\"linkState\" protobuf:\"22\"`\n\tSpeedMegabits int               `yaml:\"speedMbit,omitempty\" protobuf:\"23\"`\n\tPort          nethelpers.Port   `yaml:\"port\" protobuf:\"24\"`\n\tDuplex        nethelpers.Duplex `yaml:\"duplex\" protobuf:\"25\"`\n\t// Following fields are only populated with respective Kind.\n\tVLAN         VLANSpec         `yaml:\"vlan,omitempty\" protobuf:\"26\"`\n\tBridgeMaster BridgeMasterSpec `yaml:\"bridgeMaster,omitempty\" protobuf:\"27\"`\n\tBondMaster   BondMasterSpec   `yaml:\"bondMaster,omitempty\" protobuf:\"28\"`\n\tVRFMaster    VRFMasterSpec    `yaml:\"vrfMaster,omitempty\" protobuf:\"33\"`\n\tWireguard    WireguardSpec    `yaml:\"wireguard,omitempty\" protobuf:\"29\"`\n}\n\n// Physical checks if the link is physical ethernet.\nfunc (s LinkStatusSpec) Physical() bool {\n\treturn s.Type == nethelpers.LinkEther && s.Kind == \"\"\n}\n\n// AllLinkNames returns all link names, including name, alias and altnames.\nfunc AllLinkNames(link *LinkStatus) iter.Seq[string] {\n\treturn func(yield func(string) bool) {\n\t\tif !yield(link.Metadata().ID()) {\n\t\t\treturn\n\t\t}\n\n\t\tfor alias := range AllLinkAliases(link) {\n\t\t\tif !yield(alias) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// AllLinkAliases returns all link aliases (altnames and alias).\nfunc AllLinkAliases(link *LinkStatus) iter.Seq[string] {\n\treturn func(yield func(string) bool) {\n\t\tif link.TypedSpec().Alias != \"\" {\n\t\t\tif !yield(link.TypedSpec().Alias) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tfor _, altName := range link.TypedSpec().AltNames {\n\t\t\tif !yield(altName) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// NewLinkStatus initializes a LinkStatus resource.\nfunc NewLinkStatus(namespace resource.Namespace, id resource.ID) *LinkStatus {\n\treturn typed.NewResource[LinkStatusSpec, LinkStatusExtension](\n\t\tresource.NewMetadata(namespace, LinkStatusType, id, resource.VersionUndefined),\n\t\tLinkStatusSpec{},\n\t)\n}\n\n// LinkStatusExtension provides auxiliary methods for LinkStatus.\ntype LinkStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (LinkStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             LinkStatusType,\n\t\tAliases:          []resource.Type{\"link\", \"links\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Alias\",\n\t\t\t\tJSONPath: `{.alias}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.type}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Kind\",\n\t\t\t\tJSONPath: `{.kind}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Hw Addr\",\n\t\t\t\tJSONPath: `{.hardwareAddr}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Oper State\",\n\t\t\t\tJSONPath: `{.operationalState}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Link State\",\n\t\t\t\tJSONPath: `{.linkState}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.NonSensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[LinkStatusSpec](LinkStatusType, &LinkStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_status_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:dupl\npackage network_test\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/mdlayher/ethtool\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestLinkStatusMarshalYAML(t *testing.T) {\n\thwAddr, err := net.ParseMAC(\"01:23:45:67:89:ab\")\n\trequire.NoError(t, err)\n\n\tbcAddr, err := net.ParseMAC(\"ff:ff:ff:ff:ff:ff\")\n\trequire.NoError(t, err)\n\n\tspec := network.LinkStatusSpec{\n\t\tIndex:            3,\n\t\tType:             nethelpers.LinkEther,\n\t\tLinkIndex:        44,\n\t\tFlags:            nethelpers.LinkFlags(nethelpers.LinkUp | nethelpers.LinkRunning),\n\t\tHardwareAddr:     nethelpers.HardwareAddr(hwAddr),\n\t\tPermanentAddr:    nethelpers.HardwareAddr(hwAddr),\n\t\tBroadcastAddr:    nethelpers.HardwareAddr(bcAddr),\n\t\tMTU:              1500,\n\t\tQueueDisc:        \"fifo\",\n\t\tMasterIndex:      4,\n\t\tOperationalState: nethelpers.OperStateLowerLayerDown,\n\t\tKind:             \"bridge\",\n\t\tSlaveKind:        \"ether\",\n\t\tBusPath:          \"00:11:22\",\n\t\tPCIID:            \"0000:00:00.0\",\n\t\tDriver:           \"bonding\",\n\t\tDriverVersion:    \"1.0.0\",\n\t\tFirmwareVersion:  \"3.1.5\",\n\t\tProductID:        \"0x3ebf\",\n\t\tVendorID:         \"0x1d6b\",\n\t\tProduct:          \"10Gbase-T\",\n\t\tVendor:           \"Intel Corporation\",\n\t\tLinkState:        true,\n\t\tSpeedMegabits:    1024,\n\t\tPort:             nethelpers.Port(ethtool.TwistedPair),\n\t\tDuplex:           nethelpers.Duplex(ethtool.Full),\n\t\tVLAN: network.VLANSpec{\n\t\t\tVID:      25,\n\t\t\tProtocol: nethelpers.VLANProtocol8021AD,\n\t\t},\n\t\tBondMaster: network.BondMasterSpec{\n\t\t\tMode:            nethelpers.BondMode8023AD,\n\t\t\tHashPolicy:      nethelpers.BondXmitPolicyEncap34,\n\t\t\tLACPRate:        nethelpers.LACPRateFast,\n\t\t\tARPValidate:     nethelpers.ARPValidateAll,\n\t\t\tARPAllTargets:   nethelpers.ARPAllTargetsAny,\n\t\t\tPrimaryIndex:    new(uint32(3)),\n\t\t\tPrimaryReselect: nethelpers.PrimaryReselectBetter,\n\t\t\tFailOverMac:     nethelpers.FailOverMACFollow,\n\t\t\tADSelect:        nethelpers.ADSelectCount,\n\t\t\tMIIMon:          33,\n\t\t\tUpDelay:         100,\n\t\t\tDownDelay:       200,\n\t\t\tARPInterval:     10,\n\t\t\tResendIGMP:      30,\n\t\t\tMinLinks:        1,\n\t\t\tLPInterval:      3,\n\t\t\tPacketsPerSlave: 4,\n\t\t\tNumPeerNotif:    4,\n\t\t\tTLBDynamicLB:    5,\n\t\t\tAllSlavesActive: 1,\n\t\t\tUseCarrier:      true,\n\t\t\tADActorSysPrio:  6,\n\t\t\tADUserPortKey:   7,\n\t\t\tPeerNotifyDelay: 40,\n\t\t},\n\t\tVRFMaster: network.VRFMasterSpec{\n\t\t\tTable: 123,\n\t\t},\n\t\tWireguard: network.WireguardSpec{\n\t\t\tPublicKey:    \"bar=\",\n\t\t\tListenPort:   51820,\n\t\t\tFirewallMark: 11233,\n\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t{\n\t\t\t\t\tPublicKey:                   \"peer=\",\n\t\t\t\t\tPresharedKey:                \"key=\",\n\t\t\t\t\tEndpoint:                    \"127.0.0.1:3333\",\n\t\t\t\t\tPersistentKeepaliveInterval: 30 * time.Second,\n\t\t\t\t\tAllowedIPs: []netip.Prefix{\n\t\t\t\t\t\tnetip.MustParsePrefix(\"192.83.93.94/31\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t,\n\t\t`index: 3\ntype: ether\nlinkIndex: 44\nflags: UP,RUNNING\nhardwareAddr: 01:23:45:67:89:ab\npermanentAddr: 01:23:45:67:89:ab\nbroadcastAddr: ff:ff:ff:ff:ff:ff\nmtu: 1500\nqueueDisc: fifo\nmasterIndex: 4\noperationalState: lowerLayerDown\nkind: bridge\nslaveKind: ether\nbusPath: \"00:11:22\"\npciID: \"0000:00:00.0\"\ndriver: bonding\ndriverVersion: 1.0.0\nfirmwareVersion: 3.1.5\nproductID: \"0x3ebf\"\nvendorID: \"0x1d6b\"\nproduct: 10Gbase-T\nvendor: Intel Corporation\nlinkState: true\nspeedMbit: 1024\nport: TwistedPair\nduplex: Full\nvlan:\n    vlanID: 25\n    vlanProtocol: 802.1ad\nbondMaster:\n    mode: 802.3ad\n    xmitHashPolicy: encap3+4\n    lacpRate: fast\n    arpValidate: all\n    arpAllTargets: any\n    primary: 3\n    primaryReselect: better\n    failOverMac: follow\n    adSelect: count\n    miimon: 33\n    updelay: 100\n    downdelay: 200\n    arpInterval: 10\n    resendIgmp: 30\n    minLinks: 1\n    lpInterval: 3\n    packetsPerSlave: 4\n    numPeerNotif: 4\n    tlbLogicalLb: 5\n    allSlavesActive: 1\n    useCarrier: true\n    adActorSysPrio: 6\n    adUserPortKey: 7\n    peerNotifyDelay: 40\nvrfMaster:\n    table: \"123\"\nwireguard:\n    publicKey: bar=\n    listenPort: 51820\n    firewallMark: 11233\n    peers:\n        - publicKey: peer=\n          presharedKey: key=\n          endpoint: 127.0.0.1:3333\n          persistentKeepaliveInterval: 30s\n          allowedIPs:\n            - 192.83.93.94/31\n`,\n\t\tstring(marshaled))\n\n\tvar spec2 network.LinkStatusSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/link_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestWireguardPeer(t *testing.T) {\n\tkey1 := \"2t4fMmV1fBhI6RgoUzHp9BoWLT7oq0C/fOV17f7FqTI=\"\n\tkey2 := \"zHyf80qsjQ1EfiXkjxaLf9K9VZ6YRwcXx8GrpXQ6/yQ=\"\n\n\tpeer1 := network.WireguardPeer{\n\t\tPublicKey:                   key1,\n\t\tEndpoint:                    \"127.0.0.1:1000\",\n\t\tPersistentKeepaliveInterval: 10 * time.Second,\n\t\tAllowedIPs: []netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/16\"),\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/24\"),\n\t\t},\n\t}\n\n\tpeer2 := network.WireguardPeer{\n\t\tPublicKey: key2,\n\t\tEndpoint:  \"127.0.0.1:2000\",\n\t\tAllowedIPs: []netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/15\"),\n\t\t\tnetip.MustParsePrefix(\"10.3.0.0/28\"),\n\t\t},\n\t}\n\n\tpeer1_1 := network.WireguardPeer{\n\t\tPublicKey:                   key1,\n\t\tEndpoint:                    \"127.0.0.1:1000\",\n\t\tPersistentKeepaliveInterval: 10 * time.Second,\n\t\tAllowedIPs: []netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/15\"),\n\t\t\tnetip.MustParsePrefix(\"10.3.0.0/28\"),\n\t\t},\n\t}\n\n\tpeer1_2 := network.WireguardPeer{\n\t\tPublicKey:                   key1,\n\t\tPersistentKeepaliveInterval: 10 * time.Second,\n\t\tAllowedIPs: []netip.Prefix{\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/16\"),\n\t\t\tnetip.MustParsePrefix(\"10.2.0.0/24\"),\n\t\t},\n\t}\n\n\tassert.True(t, peer1.Equal(&peer1))\n\tassert.False(t, peer1.Equal(&peer2))\n\tassert.False(t, peer1.Equal(&peer1_1))\n\tassert.True(t, peer1.Equal(&peer1_2))\n}\n\nfunc TestWireguardSpecZero(t *testing.T) {\n\tzeroSpec := network.WireguardSpec{}\n\n\tassert.True(t, zeroSpec.IsZero())\n}\n\nfunc TestWireguardSpecMerge(t *testing.T) {\n\tpriv := \"KIT4Pe7jFbCnH+ZMwsqsIbX2xiTdmemQU9w9sYItqXY=\"\n\tpub1 := \"VHlgUWcakWcZyrtKI476PJSdoINTc1G5PYO1SEkr4FQ=\"\n\tpub2 := \"EiBteTHU1Dk3w9CYJtHFaSgkuZBVBZLEa+Y07xu+xno=\"\n\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tspec  network.WireguardSpec\n\t\tother network.WireguardSpec\n\n\t\texpected network.WireguardSpec\n\t}{\n\t\t{\n\t\t\tname: \"zero\",\n\t\t},\n\t\t{\n\t\t\tname: \"speczero\",\n\t\t\tother: network.WireguardSpec{\n\t\t\t\tListenPort: 456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: network.WireguardSpec{\n\t\t\t\tListenPort: 456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"otherzero\",\n\t\t\tspec: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed\",\n\t\t\tspec: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tother: network.WireguardSpec{\n\t\t\t\tListenPort: 456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tListenPort:   456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub1,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"peerconflict\",\n\t\t\tspec: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey:                   pub1,\n\t\t\t\t\t\tPersistentKeepaliveInterval: time.Second,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tother: network.WireguardSpec{\n\t\t\t\tListenPort: 456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub1,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:466\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\texpected: network.WireguardSpec{\n\t\t\t\tPrivateKey:   priv,\n\t\t\t\tFirewallMark: 34,\n\t\t\t\tListenPort:   456,\n\t\t\t\tPeers: []network.WireguardPeer{\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey:                   pub1,\n\t\t\t\t\t\tPersistentKeepaliveInterval: time.Second,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tPublicKey: pub2,\n\t\t\t\t\t\tEndpoint:  \"127.0.0.1:3445\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tspec := tt.spec\n\t\t\tspec.Merge(tt.other)\n\n\t\t\tassert.Equal(t, tt.expected, spec)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package network provides resources which describe networking subsystem state.\npackage network\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n)\n\n//go:generate go tool github.com/dmarkham/enumer -type=ConfigLayer,Operator -linecomment -text\n\n// NamespaceName contains resources related to networking.\nconst NamespaceName resource.Namespace = \"network\"\n\n// ConfigNamespaceName contains umerged resources related to networking generate from the configuration.\n//\n// Resources in the ConfigNamespaceName namespace are merged to produce final versions in the NamespaceName namespace.\nconst ConfigNamespaceName resource.Namespace = \"network-config\"\n\n// DefaultRouteMetric is the default route metric if no metric was specified explicitly.\nconst DefaultRouteMetric = 1024\n\n// AddressID builds ID (primary key) for the address.\nfunc AddressID(linkName string, addr netip.Prefix) string {\n\treturn fmt.Sprintf(\"%s/%s\", linkName, addr)\n}\n\n// LinkID builds ID (primary key) for the link (interface).\nfunc LinkID(linkName string) string {\n\treturn linkName\n}\n\n// RouteID builds ID (primary key) for the route.\nfunc RouteID(table nethelpers.RoutingTable, family nethelpers.Family, destination netip.Prefix, gateway netip.Addr, priority uint32, outLinkName string) string {\n\tdst, _ := destination.MarshalText() //nolint:errcheck\n\tgw, _ := gateway.MarshalText()      //nolint:errcheck\n\n\tprefix := \"\"\n\n\tif table != nethelpers.TableMain {\n\t\tprefix = fmt.Sprintf(\"%s/\", table)\n\t}\n\n\tif family == nethelpers.FamilyInet6 {\n\t\tprefix += fmt.Sprintf(\"%s/\", outLinkName)\n\t}\n\n\treturn fmt.Sprintf(\"%s%s/%s/%s/%d\", prefix, family, string(gw), string(dst), priority)\n}\n\n// RoutingRuleID builds ID (primary key) for the routing rule.\nfunc RoutingRuleID(family nethelpers.Family, priority uint32) string {\n\treturn fmt.Sprintf(\"%s/%05d\", family, priority)\n}\n\n// OperatorID builds ID (primary key) for the operators.\nfunc OperatorID(spec OperatorSpecSpec) string {\n\tswitch spec.Operator {\n\tcase OperatorVIP:\n\t\treturn fmt.Sprintf(\"%s/%s/%s\", spec.Operator, spec.LinkName, spec.VIP.IP.String())\n\tcase OperatorDHCP4:\n\t\tfallthrough\n\tcase OperatorDHCP6:\n\t\tfallthrough\n\tdefault:\n\t\treturn fmt.Sprintf(\"%s/%s\", spec.Operator, spec.LinkName)\n\t}\n}\n\n// LayeredID builds configuration for the entity at some layer.\nfunc LayeredID(layer ConfigLayer, id string) string {\n\treturn fmt.Sprintf(\"%s/%s\", layer, id)\n}\n\n// Link kinds.\nconst (\n\tLinkKindVLAN      = \"vlan\"\n\tLinkKindBond      = \"bond\"\n\tLinkKindBridge    = \"bridge\"\n\tLinkKindVRF       = \"vrf\"\n\tLinkKindWireguard = \"wireguard\"\n)\n"
  },
  {
    "path": "pkg/machinery/resources/network/network_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/siderolabs/protoenc\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tnetworkpb \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&network.AddressStatus{},\n\t\t&network.AddressSpec{},\n\t\t&network.HardwareAddr{},\n\t\t&network.DNSUpstream{},\n\t\t&network.EthernetSpec{},\n\t\t&network.EthernetStatus{},\n\t\t&network.HostDNSConfig{},\n\t\t&network.HostnameStatus{},\n\t\t&network.HostnameSpec{},\n\t\t&network.LinkAliasSpec{},\n\t\t&network.LinkRefresh{},\n\t\t&network.LinkStatus{},\n\t\t&network.LinkSpec{},\n\t\t&network.NfTablesChain{},\n\t\t&network.NodeAddress{},\n\t\t&network.NodeAddressFilter{},\n\t\t&network.NodeAddressSortAlgorithm{},\n\t\t&network.OperatorSpec{},\n\t\t&network.PlatformConfig{},\n\t\t&network.ProbeSpec{},\n\t\t&network.ResolverStatus{},\n\t\t&network.ResolverSpec{},\n\t\t&network.RouteStatus{},\n\t\t&network.RouteSpec{},\n\t\t&network.Status{},\n\t\t&network.TimeServerStatus{},\n\t\t&network.TimeServerSpec{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n\nfunc TestProtobufInterop(t *testing.T) {\n\tt.Parallel()\n\n\t// TODO: this should be auto-generated, but for now we just want to fix the bug and add regression\n\tfor _, test := range []struct {\n\t\tres interface {\n\t\t\tresource.Resource\n\t\t\tResourceDefinition() meta.ResourceDefinitionSpec\n\t\t}\n\t\tspec proto.Message\n\t}{\n\t\t{\n\t\t\tres:  &network.AddressStatus{},\n\t\t\tspec: &networkpb.AddressStatusSpec{},\n\t\t},\n\t\t{\n\t\t\tres:  &network.EthernetStatus{},\n\t\t\tspec: &networkpb.EthernetStatusSpec{},\n\t\t},\n\t\t{\n\t\t\tres:  &network.LinkSpec{},\n\t\t\tspec: &networkpb.LinkSpecSpec{},\n\t\t},\n\t\t{\n\t\t\tres:  &network.LinkStatus{},\n\t\t\tspec: &networkpb.LinkStatusSpec{},\n\t\t},\n\t\t{\n\t\t\tres:  &network.NfTablesChain{},\n\t\t\tspec: &networkpb.NfTablesChainSpec{},\n\t\t},\n\t} {\n\t\tt.Run(test.res.ResourceDefinition().Type, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trequire.NoError(t, proto.ResourceSpecToProto(test.res, test.spec, protoenc.WithMarshalZeroFields()))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/nftables_chain.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NfTablesChainType is type of NfTablesChain resource.\nconst NfTablesChainType = resource.Type(\"NfTablesChains.net.talos.dev\")\n\n// NfTablesChain resource holds definition of the nftables chain.\ntype NfTablesChain = typed.Resource[NfTablesChainSpec, NfTablesChainExtension]\n\n// NfTablesChainSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype NfTablesChainSpec struct {\n\tType     nethelpers.NfTablesChainType     `yaml:\"type\" protobuf:\"1\"`\n\tHook     nethelpers.NfTablesChainHook     `yaml:\"hook\" protobuf:\"2\"`\n\tPriority nethelpers.NfTablesChainPriority `yaml:\"priority\" protobuf:\"3\"`\n\tPolicy   nethelpers.NfTablesVerdict       `yaml:\"policy\" protobuf:\"5\"`\n\n\tRules []NfTablesRule `yaml:\"rules\" protobuf:\"4\"`\n}\n\n// NfTablesRule describes a single rule in the nftables chain.\n//\n//gotagsrewrite:gen\ntype NfTablesRule struct {\n\tMatchIIfName            *NfTablesIfNameMatch         `yaml:\"matchIIfName,omitempty\" protobuf:\"8\"`\n\tMatchOIfName            *NfTablesIfNameMatch         `yaml:\"matchOIfName,omitempty\" protobuf:\"1\"`\n\tMatchMark               *NfTablesMark                `yaml:\"matchMark,omitempty\" protobuf:\"3\"`\n\tMatchConntrackState     *NfTablesConntrackStateMatch `yaml:\"matchConntrackState,omitempty\" protobuf:\"11\"`\n\tMatchSourceAddress      *NfTablesAddressMatch        `yaml:\"matchSourceAddress,omitempty\" protobuf:\"5\"`\n\tMatchDestinationAddress *NfTablesAddressMatch        `yaml:\"matchDestinationAddress,omitempty\" protobuf:\"6\"`\n\tMatchLayer4             *NfTablesLayer4Match         `yaml:\"matchLayer4,omitempty\" protobuf:\"7\"`\n\tMatchLimit              *NfTablesLimitMatch          `yaml:\"matchLimit,omitempty\" protobuf:\"10\"`\n\n\tClampMSS    *NfTablesClampMSS           `yaml:\"clampMSS,omitempty\" protobuf:\"9\"`\n\tSetMark     *NfTablesMark               `yaml:\"setMark,omitempty\" protobuf:\"4\"`\n\tAnonCounter bool                        `yaml:\"anonymousCounter,omitempty\" protobuf:\"12\"`\n\tVerdict     *nethelpers.NfTablesVerdict `yaml:\"verdict,omitempty\" protobuf:\"2\"`\n}\n\n// NfTablesIfNameMatch describes the match on the interface name.\n//\n//gotagsrewrite:gen\ntype NfTablesIfNameMatch struct {\n\tInterfaceNames []string                 `yaml:\"interfaceName\" protobuf:\"3\"`\n\tOperator       nethelpers.MatchOperator `yaml:\"operator\" protobuf:\"2\"`\n}\n\n// NfTablesMark encodes packet mark match/update operation.\n//\n// When used as a match computes the following condition:\n// (mark & mask) ^ xor == value\n//\n// When used as an update computes the following operation:\n// mark = (mark & mask) ^ xor.\n//\n//gotagsrewrite:gen\ntype NfTablesMark struct {\n\tMask  uint32 `yaml:\"mask,omitempty\" protobuf:\"1\"`\n\tXor   uint32 `yaml:\"xor,omitempty\" protobuf:\"2\"`\n\tValue uint32 `yaml:\"value,omitempty\" protobuf:\"3\"`\n}\n\n// NfTablesAddressMatch describes the match on the IP address.\n//\n//gotagsrewrite:gen\ntype NfTablesAddressMatch struct {\n\tIncludeSubnets []netip.Prefix `yaml:\"includeSubnets,omitempty\" protobuf:\"1\"`\n\tExcludeSubnets []netip.Prefix `yaml:\"excludeSubnets,omitempty\" protobuf:\"2\"`\n\tInvert         bool           `yaml:\"invert,omitempty\" protobuf:\"3\"`\n}\n\n// NfTablesLayer4Match describes the match on the transport layer protocol.\n//\n//gotagsrewrite:gen\ntype NfTablesLayer4Match struct {\n\tProtocol             nethelpers.Protocol    `yaml:\"protocol\" protobuf:\"1\"`\n\tMatchSourcePort      *NfTablesPortMatch     `yaml:\"matchSourcePort,omitempty\" protobuf:\"2\"`\n\tMatchDestinationPort *NfTablesPortMatch     `yaml:\"matchDestinationPort,omitempty\" protobuf:\"3\"`\n\tMatchICMPType        *NfTablesICMPTypeMatch `yaml:\"matchICMPType,omitempty\" protobuf:\"4\"`\n}\n\n// NfTablesPortMatch describes the match on the transport layer port.\n//\n//gotagsrewrite:gen\ntype NfTablesPortMatch struct {\n\tRanges []PortRange `yaml:\"ranges,omitempty\" protobuf:\"1\"`\n}\n\n// NfTablesICMPTypeMatch describes the match on the ICMP type.\n//\n//gotagsrewrite:gen\ntype NfTablesICMPTypeMatch struct {\n\tTypes []nethelpers.ICMPType `yaml:\"types\" protobuf:\"1\"`\n}\n\n// PortRange describes a range of ports.\n//\n// Range is [lo, hi].\n//\n//gotagsrewrite:gen\ntype PortRange struct {\n\tLo uint16 `yaml:\"lo\" protobuf:\"1\"`\n\tHi uint16 `yaml:\"hi\" protobuf:\"2\"`\n}\n\n// NfTablesClampMSS describes the TCP MSS clamping operation.\n//\n// MSS is limited by the `MaxMTU` so that:\n// - IPv4: MSS = MaxMTU - 40\n// - IPv6: MSS = MaxMTU - 60.\n//\n//gotagsrewrite:gen\ntype NfTablesClampMSS struct {\n\tMTU uint16 `yaml:\"mtu\" protobuf:\"1\"`\n}\n\n// NfTablesLimitMatch describes the match on the packet rate.\n//\n//gotagsrewrite:gen\ntype NfTablesLimitMatch struct {\n\tPacketRatePerSecond uint64 `yaml:\"packetRatePerSecond\" protobuf:\"1\"`\n}\n\n// NfTablesConntrackStateMatch describes the match on the connection tracking state.\n//\n//gotagsrewrite:gen\ntype NfTablesConntrackStateMatch struct {\n\tStates []nethelpers.ConntrackState `yaml:\"states\" protobuf:\"1\"`\n}\n\n// NewNfTablesChain initializes a NfTablesChain resource.\nfunc NewNfTablesChain(namespace resource.Namespace, id resource.ID) *NfTablesChain {\n\treturn typed.NewResource[NfTablesChainSpec, NfTablesChainExtension](\n\t\tresource.NewMetadata(namespace, NfTablesChainType, id, resource.VersionUndefined),\n\t\tNfTablesChainSpec{},\n\t)\n}\n\n// NfTablesChainExtension provides auxiliary methods for NfTablesChain.\ntype NfTablesChainExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NfTablesChainExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NfTablesChainType,\n\t\tAliases:          []resource.Type{\"chain\", \"chains\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.type}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Hook\",\n\t\t\t\tJSONPath: `{.hook}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Priority\",\n\t\t\t\tJSONPath: `{.priority}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Policy\",\n\t\t\t\tJSONPath: `{.policy}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.NonSensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NfTablesChainSpec](NfTablesChainType, &NfTablesChain{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/node_address.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeAddressType is type of NodeAddress resource.\nconst NodeAddressType = resource.Type(\"NodeAddresses.net.talos.dev\")\n\n// NodeAddress resource holds physical network link status.\ntype NodeAddress = typed.Resource[NodeAddressSpec, NodeAddressExtension]\n\n// NodeAddress well-known IDs.\nconst (\n\t// Default node address (should be a single address in the spec).\n\t//\n\t// Used to set for example published etcd peer address.\n\tNodeAddressDefaultID = \"default\"\n\t// Current node addresses (as seen at the moment).\n\t//\n\t// Shows a list of addresses for the node for the UP interfaces.\n\tNodeAddressCurrentID = \"current\"\n\t// Accumulative list of the addresses node had over time.\n\t//\n\t// If some address is no longer present, it will be still kept in the accumulative list.\n\tNodeAddressAccumulativeID = \"accumulative\"\n\t// Routed current node addresses (as seen at the moment).\n\t//\n\t// This is current addresses minus 'external' IPs, and SideroLink IPs.\n\t//\n\t// This list is used to pick advertised/listen addresses for different services.\n\tNodeAddressRoutedID = \"routed\"\n)\n\n// NodeAddressSpec describes a set of node addresses.\n//\n//gotagsrewrite:gen\ntype NodeAddressSpec struct {\n\tAddresses     []netip.Prefix                  `yaml:\"addresses\" protobuf:\"1\"`\n\tSortAlgorithm nethelpers.AddressSortAlgorithm `yaml:\"sortAlgorithm\" protobuf:\"2\"`\n}\n\n// NewNodeAddress initializes a NodeAddress resource.\nfunc NewNodeAddress(namespace resource.Namespace, id resource.ID) *NodeAddress {\n\treturn typed.NewResource[NodeAddressSpec, NodeAddressExtension](\n\t\tresource.NewMetadata(namespace, NodeAddressType, id, resource.VersionUndefined),\n\t\tNodeAddressSpec{},\n\t)\n}\n\n// NodeAddressExtension provides auxiliary methods for NodeAddress.\ntype NodeAddressExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeAddressExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeAddressType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Addresses\",\n\t\t\t\tJSONPath: `{.addresses}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"SortAlgorithm\",\n\t\t\t\tJSONPath: `{.sortAlgorithm}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// IPs returns IP without prefix.\nfunc (spec *NodeAddressSpec) IPs() []netip.Addr {\n\t// make sure addresses are unique, as different prefixes can have the same IP\n\t// at the same we want to preserve order\n\tips := xslices.Map(spec.Addresses, netip.Prefix.Addr)\n\n\tresult := make([]netip.Addr, 0, len(ips))\n\n\tfor _, ip := range ips {\n\t\tif slices.ContainsFunc(result, func(addr netip.Addr) bool {\n\t\t\treturn addr == ip\n\t\t}) {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, ip)\n\t}\n\n\treturn result\n}\n\n// FilteredNodeAddressID returns resource ID for node addresses with filter applied.\nfunc FilteredNodeAddressID(kind resource.ID, filterID string) resource.ID {\n\treturn fmt.Sprintf(\"%s-%s\", kind, filterID)\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeAddressSpec](NodeAddressType, &NodeAddress{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/node_address_filter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeAddressFilterType is type of NodeAddressFilter resource.\nconst NodeAddressFilterType = resource.Type(\"NodeAddressFilters.net.talos.dev\")\n\n// NodeAddressFilter resource holds filter for NodeAddress resources.\ntype NodeAddressFilter = typed.Resource[NodeAddressFilterSpec, NodeAddressFilterExtension]\n\n// NodeAddressFilterSpec describes a filter for NodeAddresses.\n//\n//gotagsrewrite:gen\ntype NodeAddressFilterSpec struct {\n\t// Address is skipped if it doesn't match any of the includeSubnets (if includeSubnets is not empty).\n\tIncludeSubnets []netip.Prefix `yaml:\"includeSubnets\" protobuf:\"1\"`\n\t// Address is skipped if it matches any of the includeSubnets.\n\tExcludeSubnets []netip.Prefix `yaml:\"excludeSubnets\" protobuf:\"2\"`\n}\n\n// NewNodeAddressFilter initializes a NodeAddressFilter resource.\nfunc NewNodeAddressFilter(namespace resource.Namespace, id resource.ID) *NodeAddressFilter {\n\treturn typed.NewResource[NodeAddressFilterSpec, NodeAddressFilterExtension](\n\t\tresource.NewMetadata(namespace, NodeAddressFilterType, id, resource.VersionUndefined),\n\t\tNodeAddressFilterSpec{},\n\t)\n}\n\n// NodeAddressFilterExtension provides auxiliary methods for NodeAddressFilter.\ntype NodeAddressFilterExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeAddressFilterExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeAddressFilterType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Include Subnets\",\n\t\t\t\tJSONPath: `{.includeSubnets}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Exclude Subnets\",\n\t\t\t\tJSONPath: `{.excludeSubnets}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeAddressFilterSpec](NodeAddressFilterType, &NodeAddressFilter{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/node_address_sort_algorithm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// NodeAddressSortAlgorithmType is type of NodeAddressSortAlgorithm resource.\nconst NodeAddressSortAlgorithmType = resource.Type(\"NodeAddressSortAlgorithms.net.talos.dev\")\n\n// NodeAddressSortAlgorithm resource holds filter for NodeAddress resources.\ntype NodeAddressSortAlgorithm = typed.Resource[NodeAddressSortAlgorithmSpec, NodeAddressSortAlgorithmExtension]\n\n// NodeAddressSortAlgorithmID is the resource ID for NodeAddressSortAlgorithm.\nconst NodeAddressSortAlgorithmID = \"default\"\n\n// NodeAddressSortAlgorithmSpec describes a filter for NodeAddresses.\n//\n//gotagsrewrite:gen\ntype NodeAddressSortAlgorithmSpec struct {\n\tAlgorithm nethelpers.AddressSortAlgorithm `yaml:\"algorithm\" protobuf:\"1\"`\n}\n\n// NewNodeAddressSortAlgorithm initializes a NodeAddressSortAlgorithm resource.\nfunc NewNodeAddressSortAlgorithm(namespace resource.Namespace, id resource.ID) *NodeAddressSortAlgorithm {\n\treturn typed.NewResource[NodeAddressSortAlgorithmSpec, NodeAddressSortAlgorithmExtension](\n\t\tresource.NewMetadata(namespace, NodeAddressSortAlgorithmType, id, resource.VersionUndefined),\n\t\tNodeAddressSortAlgorithmSpec{},\n\t)\n}\n\n// NodeAddressSortAlgorithmExtension provides auxiliary methods for NodeAddressSortAlgorithm.\ntype NodeAddressSortAlgorithmExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (NodeAddressSortAlgorithmExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             NodeAddressSortAlgorithmType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Algorithm\",\n\t\t\t\tJSONPath: `{.algorithm}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[NodeAddressSortAlgorithmSpec](NodeAddressSortAlgorithmType, &NodeAddressSortAlgorithm{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/operator.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\n// Operator enumerates Talos network operators.\ntype Operator int\n\n// Operator list.\n//\n//structprotogen:gen_enum\nconst (\n\tOperatorDHCP4 Operator = iota // dhcp4\n\tOperatorDHCP6                 // dhcp6\n\tOperatorVIP                   // vip\n)\n"
  },
  {
    "path": "pkg/machinery/resources/network/operator_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// OperatorSpecType is type of OperatorSpec resource.\nconst OperatorSpecType = resource.Type(\"OperatorSpecs.net.talos.dev\")\n\n// OperatorSpec resource holds operator specification.\ntype OperatorSpec = typed.Resource[OperatorSpecSpec, OperatorSpecExtension]\n\n// OperatorSpecSpec describes operator specification.\n//\n//gotagsrewrite:gen\ntype OperatorSpecSpec struct {\n\tOperator  Operator `yaml:\"operator\" protobuf:\"1\"`\n\tLinkName  string   `yaml:\"linkName\" protobuf:\"2\"`\n\tRequireUp bool     `yaml:\"requireUp\" protobuf:\"3\"`\n\n\tDHCP4 DHCP4OperatorSpec `yaml:\"dhcp4,omitempty\" protobuf:\"4\"`\n\tDHCP6 DHCP6OperatorSpec `yaml:\"dhcp6,omitempty\" protobuf:\"5\"`\n\tVIP   VIPOperatorSpec   `yaml:\"vip,omitempty\" protobuf:\"6\"`\n\n\tConfigLayer ConfigLayer `yaml:\"layer\" protobuf:\"7\"`\n}\n\n// Equal implements equality check for OperatorSpecSpec.\nfunc (spec OperatorSpecSpec) Equal(other OperatorSpecSpec) bool {\n\t// config layer is not important for equality check\n\tspec.ConfigLayer = other.ConfigLayer\n\n\treturn spec == other\n}\n\n// ClientIdentifierSpec is a shared DHCP4/DHCP6 client identifier spec.\n//\n//gotagsrewrite:gen\ntype ClientIdentifierSpec struct {\n\tClientIdentifier nethelpers.ClientIdentifier `yaml:\"clientIdentifier\" protobuf:\"1\"`\n\tDUIDRawHex       string                      `yaml:\"duidRawHex,omitempty\" protobuf:\"2\"`\n}\n\n// DHCP4OperatorSpec describes DHCP4 operator options.\n//\n//gotagsrewrite:gen\ntype DHCP4OperatorSpec struct {\n\tRouteMetric         uint32               `yaml:\"routeMetric\" protobuf:\"1\"`\n\tSkipHostnameRequest bool                 `yaml:\"skipHostnameRequest,omitempty\" protobuf:\"2\"`\n\tClientIdentifier    ClientIdentifierSpec `yaml:\"clientIdentifier,omitempty\" protobuf:\"3\"`\n}\n\n// DHCP6OperatorSpec describes DHCP6 operator options.\n//\n//gotagsrewrite:gen\ntype DHCP6OperatorSpec struct {\n\tRouteMetric         uint32               `yaml:\"routeMetric\" protobuf:\"2\"`\n\tSkipHostnameRequest bool                 `yaml:\"skipHostnameRequest,omitempty\" protobuf:\"3\"`\n\tClientIdentifier    ClientIdentifierSpec `yaml:\"clientIdentifier,omitempty\" protobuf:\"4\"`\n}\n\n// VIPOperatorSpec describes virtual IP operator options.\n//\n//gotagsrewrite:gen\ntype VIPOperatorSpec struct {\n\tIP            netip.Addr `yaml:\"ip\" protobuf:\"1\"`\n\tGratuitousARP bool       `yaml:\"gratuitousARP\" protobuf:\"2\"`\n\n\tEquinixMetal VIPEquinixMetalSpec `yaml:\"equinixMetal,omitempty\" protobuf:\"3\"`\n\tHCloud       VIPHCloudSpec       `yaml:\"hcloud,omitempty\" protobuf:\"4\"`\n}\n\n// VIPEquinixMetalSpec describes virtual (elastic) IP settings for Equinix Metal.\n//\n//gotagsrewrite:gen\ntype VIPEquinixMetalSpec struct {\n\tProjectID string `yaml:\"projectID\" protobuf:\"1\"`\n\tDeviceID  string `yaml:\"deviceID\" protobuf:\"2\"`\n\tAPIToken  string `yaml:\"apiToken\" protobuf:\"3\"`\n}\n\n// VIPHCloudSpec describes virtual (elastic) IP settings for Hetzner Cloud.\n//\n//gotagsrewrite:gen\ntype VIPHCloudSpec struct {\n\tDeviceID  int64  `yaml:\"deviceID\" protobuf:\"1\"`\n\tNetworkID int64  `yaml:\"networkID\" protobuf:\"2\"`\n\tAPIToken  string `yaml:\"apiToken\" protobuf:\"3\"`\n}\n\n// NewOperatorSpec initializes a OperatorSpec resource.\nfunc NewOperatorSpec(namespace resource.Namespace, id resource.ID) *OperatorSpec {\n\treturn typed.NewResource[OperatorSpecSpec, OperatorSpecExtension](\n\t\tresource.NewMetadata(namespace, OperatorSpecType, id, resource.VersionUndefined),\n\t\tOperatorSpecSpec{},\n\t)\n}\n\n// OperatorSpecExtension provides auxiliary methods for OperatorSpec.\ntype OperatorSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (OperatorSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             OperatorSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[OperatorSpecSpec](OperatorSpecType, &OperatorSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/operator_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestOperatorSpecMarshalYAML(t *testing.T) {\n\tspec := network.OperatorSpecSpec{\n\t\tOperator:  network.OperatorDHCP4,\n\t\tLinkName:  \"eth0\",\n\t\tRequireUp: true,\n\n\t\tDHCP4: network.DHCP4OperatorSpec{\n\t\t\tRouteMetric: 1024,\n\t\t},\n\t\tDHCP6: network.DHCP6OperatorSpec{\n\t\t\tRouteMetric: 1024,\n\t\t},\n\t\tVIP: network.VIPOperatorSpec{\n\t\t\tIP:            netip.MustParseAddr(\"192.168.1.1\"),\n\t\t\tGratuitousARP: true,\n\t\t\tEquinixMetal: network.VIPEquinixMetalSpec{\n\t\t\t\tProjectID: \"a\",\n\t\t\t\tDeviceID:  \"b\",\n\t\t\t\tAPIToken:  \"c\",\n\t\t\t},\n\t\t\tHCloud: network.VIPHCloudSpec{\n\t\t\t\tDeviceID:  3,\n\t\t\t\tNetworkID: 4,\n\t\t\t\tAPIToken:  \"d\",\n\t\t\t},\n\t\t},\n\t\tConfigLayer: network.ConfigMachineConfiguration,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t,\n\t\t`operator: dhcp4\nlinkName: eth0\nrequireUp: true\ndhcp4:\n    routeMetric: 1024\ndhcp6:\n    routeMetric: 1024\nvip:\n    ip: 192.168.1.1\n    gratuitousARP: true\n    equinixMetal:\n        projectID: a\n        deviceID: b\n        apiToken: c\n    hcloud:\n        deviceID: 3\n        networkID: 4\n        apiToken: d\nlayer: configuration\n`,\n\t\tstring(marshaled))\n\n\tvar spec2 network.OperatorSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/platform_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"bytes\"\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\n// PlatformConfigType is type of PlatformConfig resource.\nconst PlatformConfigType = resource.Type(\"PlatformConfigs.net.talos.dev\")\n\n// PlatformConfig resource holds DNS resolver info.\ntype PlatformConfig = typed.Resource[PlatformConfigSpec, PlatformConfigExtension]\n\n// PlatformConfigActiveID is the ID of instance containing active config.\nconst PlatformConfigActiveID resource.ID = \"active\"\n\n// PlatformConfigCachedID is the ID of instance containing cached (persisted) config.\nconst PlatformConfigCachedID resource.ID = \"cached\"\n\n// PlatformConfigSpec describes platform network configuration.\n//\n// This structure is marshaled to STATE partition to persist cached network configuration across\n// reboots.\n//\n//gotagsrewrite:gen\ntype PlatformConfigSpec struct {\n\tAddresses []AddressSpecSpec `yaml:\"addresses\" protobuf:\"1\"`\n\tLinks     []LinkSpecSpec    `yaml:\"links\" protobuf:\"2\"`\n\tRoutes    []RouteSpecSpec   `yaml:\"routes\" protobuf:\"3\"`\n\n\tHostnames   []HostnameSpecSpec   `yaml:\"hostnames\" protobuf:\"4\"`\n\tResolvers   []ResolverSpecSpec   `yaml:\"resolvers\" protobuf:\"5\"`\n\tTimeServers []TimeServerSpecSpec `yaml:\"timeServers\" protobuf:\"6\"`\n\n\tOperators []OperatorSpecSpec `yaml:\"operators\" protobuf:\"7\"`\n\n\tExternalIPs []netip.Addr `yaml:\"externalIPs\" protobuf:\"8\"`\n\n\tProbes []ProbeSpecSpec `yaml:\"probes,omitempty\" protobuf:\"9\"`\n\n\tMetadata *runtime.PlatformMetadataSpec `yaml:\"metadata,omitempty\" protobuf:\"10\"`\n}\n\n// Equal compares two platform network configurations.\nfunc (p *PlatformConfigSpec) Equal(other *PlatformConfigSpec) bool {\n\t// we will compare by marshaling to YAML\n\t// and then comparing the bytes\n\t// this is not the most efficient way to do this,\n\t// but it will handle omitting empty fields\n\tm1, err1 := yaml.Marshal(p)\n\n\tm2, err2 := yaml.Marshal(other)\n\tif err1 != nil || err2 != nil {\n\t\treturn false\n\t}\n\n\treturn bytes.Equal(m1, m2)\n}\n\n// NewPlatformConfig initializes a PlatformConfig resource.\nfunc NewPlatformConfig(namespace resource.Namespace, id resource.ID) *PlatformConfig {\n\treturn typed.NewResource[PlatformConfigSpec, PlatformConfigExtension](\n\t\tresource.NewMetadata(namespace, PlatformConfigType, id, resource.VersionUndefined),\n\t\tPlatformConfigSpec{},\n\t)\n}\n\n// PlatformConfigExtension provides auxiliary methods for PlatformConfig.\ntype PlatformConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PlatformConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PlatformConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PlatformConfigSpec](PlatformConfigType, &PlatformConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/platform_config_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestPlatformConfigEqual(t *testing.T) {\n\tt.Parallel()\n\n\tassert.True(t, (&network.PlatformConfigSpec{}).Equal(&network.PlatformConfigSpec{}))\n\tassert.True(t, (&network.PlatformConfigSpec{Addresses: []network.AddressSpecSpec{}}).Equal(&network.PlatformConfigSpec{}))\n\tassert.True(t, (&network.PlatformConfigSpec{Addresses: []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:  netip.MustParsePrefix(\"192.168.68.54/22\"),\n\t\t\tLinkName: \"eth0\",\n\t\t\tFamily:   nethelpers.FamilyInet4,\n\t\t\tScope:    nethelpers.ScopeGlobal,\n\t\t},\n\t}}).Equal(&network.PlatformConfigSpec{Addresses: []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:  netip.MustParsePrefix(\"192.168.68.54/22\"),\n\t\t\tLinkName: \"eth0\",\n\t\t\tFamily:   nethelpers.FamilyInet4,\n\t\t\tScope:    nethelpers.ScopeGlobal,\n\t\t},\n\t}}))\n\n\tassert.False(t, (&network.PlatformConfigSpec{}).Equal(nil))\n\tassert.False(t, (&network.PlatformConfigSpec{Addresses: []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:  netip.MustParsePrefix(\"192.168.68.1/22\"),\n\t\t\tLinkName: \"eth0\",\n\t\t\tFamily:   nethelpers.FamilyInet4,\n\t\t\tScope:    nethelpers.ScopeGlobal,\n\t\t},\n\t}}).Equal(&network.PlatformConfigSpec{Addresses: []network.AddressSpecSpec{\n\t\t{\n\t\t\tAddress:  netip.MustParsePrefix(\"192.168.68.2/22\"),\n\t\t\tLinkName: \"eth1\",\n\t\t\tFamily:   nethelpers.FamilyInet4,\n\t\t\tScope:    nethelpers.ScopeGlobal,\n\t\t},\n\t}}))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/probe_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ProbeSpecType is type of ProbeSpec resource.\nconst ProbeSpecType = resource.Type(\"ProbeSpecs.net.talos.dev\")\n\n// ProbeSpec resource holds Probe specification to be run.\ntype ProbeSpec = typed.Resource[ProbeSpecSpec, ProbeSpecExtension]\n\n// ProbeSpecSpec describes the Probe.\n//\n//gotagsrewrite:gen\ntype ProbeSpecSpec struct {\n\t// Interval between the probes.\n\tInterval time.Duration `yaml:\"interval\" protobuf:\"1\"`\n\t// FailureThreshold is the number of consecutive failures for the probe to be considered failed after having succeeded.\n\tFailureThreshold int `yaml:\"failureThreshold\" protobuf:\"2\"`\n\t// One of the probe types should be specified, for now it's only TCP.\n\tTCP TCPProbeSpec `yaml:\"tcp,omitempty\" protobuf:\"3\"`\n\t// Configuration layer.\n\tConfigLayer ConfigLayer `yaml:\"layer\" protobuf:\"4\"`\n}\n\n// ID returns the ID of the resource based on the spec.\nfunc (spec *ProbeSpecSpec) ID() (resource.ID, error) {\n\tvar zeroTCP TCPProbeSpec\n\n\tif spec.TCP == zeroTCP {\n\t\treturn \"\", errors.New(\"no probe type specified\")\n\t}\n\n\treturn fmt.Sprintf(\"tcp:%s\", spec.TCP.Endpoint), nil\n}\n\n// Equal returns true if the specs are equal.\nfunc (spec ProbeSpecSpec) Equal(other ProbeSpecSpec) bool {\n\treturn spec == other\n}\n\n// TCPProbeSpec describes the TCP Probe.\n//\n//gotagsrewrite:gen\ntype TCPProbeSpec struct {\n\t// Endpoint to probe: host:port.\n\tEndpoint string `yaml:\"endpoint\" protobuf:\"1\"`\n\t// Timeout for the probe.\n\tTimeout time.Duration `yaml:\"timeout\" protobuf:\"2\"`\n}\n\n// NewProbeSpec initializes a ProbeSpec resource.\nfunc NewProbeSpec(namespace resource.Namespace, id resource.ID) *ProbeSpec {\n\treturn typed.NewResource[ProbeSpecSpec, ProbeSpecExtension](\n\t\tresource.NewMetadata(namespace, ProbeSpecType, id, resource.VersionUndefined),\n\t\tProbeSpecSpec{},\n\t)\n}\n\n// ProbeSpecExtension provides auxiliary methods for ProbeSpec.\ntype ProbeSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ProbeSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ProbeSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ProbeSpecSpec](ProbeSpecType, &ProbeSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/probe_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ProbeStatusType is type of ProbeStatus resource.\nconst ProbeStatusType = resource.Type(\"ProbeStatuses.net.talos.dev\")\n\n// ProbeStatus resource holds Probe result.\ntype ProbeStatus = typed.Resource[ProbeStatusSpec, ProbeStatusExtension]\n\n// ProbeStatusSpec describes the Probe.\n//\n//gotagsrewrite:gen\ntype ProbeStatusSpec struct {\n\t// Success of the check.\n\tSuccess bool `yaml:\"success\" protobuf:\"1\"`\n\t// Last error of the probe.\n\tLastError string `yaml:\"lastError\" protobuf:\"2\"`\n}\n\n// NewProbeStatus initializes a ProbeStatus resource.\nfunc NewProbeStatus(namespace resource.Namespace, id resource.ID) *ProbeStatus {\n\treturn typed.NewResource[ProbeStatusSpec, ProbeStatusExtension](\n\t\tresource.NewMetadata(namespace, ProbeStatusType, id, resource.VersionUndefined),\n\t\tProbeStatusSpec{},\n\t)\n}\n\n// ProbeStatusExtension provides auxiliary methods for ProbeStatus.\ntype ProbeStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ProbeStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ProbeStatusType,\n\t\tAliases:          []resource.Type{\"probe\", \"probes\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Success\",\n\t\t\t\tJSONPath: \"{.success}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ProbeStatusSpec](ProbeStatusType, &ProbeStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/resolver_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ResolverSpecType is type of ResolverSpec resource.\nconst ResolverSpecType = resource.Type(\"ResolverSpecs.net.talos.dev\")\n\n// ResolverSpec resource holds DNS resolver info.\ntype ResolverSpec = typed.Resource[ResolverSpecSpec, ResolverSpecExtension]\n\n// ResolverID is the ID of the singleton instance.\nconst ResolverID resource.ID = \"resolvers\"\n\n// ResolverSpecSpec describes DNS resolvers.\n//\n//gotagsrewrite:gen\ntype ResolverSpecSpec struct {\n\tDNSServers    []netip.Addr `yaml:\"dnsServers\" protobuf:\"1\"`\n\tConfigLayer   ConfigLayer  `yaml:\"layer\" protobuf:\"2\"`\n\tSearchDomains []string     `yaml:\"searchDomains,omitempty\" protobuf:\"3\"`\n}\n\n// NewResolverSpec initializes a ResolverSpec resource.\nfunc NewResolverSpec(namespace resource.Namespace, id resource.ID) *ResolverSpec {\n\treturn typed.NewResource[ResolverSpecSpec, ResolverSpecExtension](\n\t\tresource.NewMetadata(namespace, ResolverSpecType, id, resource.VersionUndefined),\n\t\tResolverSpecSpec{},\n\t)\n}\n\n// ResolverSpecExtension provides auxiliary methods for ResolverSpec.\ntype ResolverSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ResolverSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ResolverSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Layer\",\n\t\t\t\tJSONPath: \"{.layer}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Resolvers\",\n\t\t\t\tJSONPath: \"{.dnsServers}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Search Domains\",\n\t\t\t\tJSONPath: \"{.searchDomains}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ResolverSpecSpec](ResolverSpecType, &ResolverSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/resolver_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestResolverSpecMarshalYAML(t *testing.T) {\n\tspec := network.ResolverSpecSpec{\n\t\tDNSServers:    []netip.Addr{netip.MustParseAddr(\"1.1.1.1\"), netip.MustParseAddr(\"8.8.8.8\")},\n\t\tConfigLayer:   network.ConfigPlatform,\n\t\tSearchDomains: []string{\"example.com\"},\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"dnsServers:\\n    - 1.1.1.1\\n    - 8.8.8.8\\nlayer: platform\\nsearchDomains:\\n    - example.com\\n\", string(marshaled))\n\n\tvar spec2 network.ResolverSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/resolver_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ResolverStatusType is type of ResolverStatus resource.\nconst ResolverStatusType = resource.Type(\"ResolverStatuses.net.talos.dev\")\n\n// ResolverStatus resource holds DNS resolver info.\ntype ResolverStatus = typed.Resource[ResolverStatusSpec, ResolverStatusExtension]\n\n// ResolverStatusSpec describes DNS resolvers.\n//\n//gotagsrewrite:gen\ntype ResolverStatusSpec struct {\n\tDNSServers    []netip.Addr `yaml:\"dnsServers\" protobuf:\"1\"`\n\tSearchDomains []string     `yaml:\"searchDomains\" protobuf:\"2\"`\n}\n\n// NewResolverStatus initializes a ResolverStatus resource.\nfunc NewResolverStatus(namespace resource.Namespace, id resource.ID) *ResolverStatus {\n\treturn typed.NewResource[ResolverStatusSpec, ResolverStatusExtension](\n\t\tresource.NewMetadata(namespace, ResolverStatusType, id, resource.VersionUndefined),\n\t\tResolverStatusSpec{},\n\t)\n}\n\n// ResolverStatusExtension provides auxiliary methods for ResolverStatus.\ntype ResolverStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ResolverStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ResolverStatusType,\n\t\tAliases:          []resource.Type{\"resolvers\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Resolvers\",\n\t\t\t\tJSONPath: \"{.dnsServers}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Search Domains\",\n\t\t\t\tJSONPath: \"{.searchDomains}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ResolverStatusSpec](ResolverStatusType, &ResolverStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/route_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/gen/value\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// RouteSpecType is type of RouteSpec resource.\nconst RouteSpecType = resource.Type(\"RouteSpecs.net.talos.dev\")\n\n// RouteSpec resource holds route specification to be applied to the kernel.\ntype RouteSpec = typed.Resource[RouteSpecSpec, RouteSpecExtension]\n\n// RouteSpecSpec describes the route.\n//\n//gotagsrewrite:gen\ntype RouteSpecSpec struct {\n\tFamily      nethelpers.Family        `yaml:\"family\" protobuf:\"1\"`\n\tDestination netip.Prefix             `yaml:\"dst\" protobuf:\"2\"`\n\tSource      netip.Addr               `yaml:\"src\" protobuf:\"3\"`\n\tGateway     netip.Addr               `yaml:\"gateway\" protobuf:\"4\"`\n\tOutLinkName string                   `yaml:\"outLinkName,omitempty\" protobuf:\"5\"`\n\tTable       nethelpers.RoutingTable  `yaml:\"table\" protobuf:\"6\"`\n\tPriority    uint32                   `yaml:\"priority,omitempty\" protobuf:\"7\"`\n\tScope       nethelpers.Scope         `yaml:\"scope\" protobuf:\"8\"`\n\tType        nethelpers.RouteType     `yaml:\"type\" protobuf:\"9\"`\n\tFlags       nethelpers.RouteFlags    `yaml:\"flags\" protobuf:\"10\"`\n\tProtocol    nethelpers.RouteProtocol `yaml:\"protocol\" protobuf:\"11\"`\n\tConfigLayer ConfigLayer              `yaml:\"layer\" protobuf:\"12\"`\n\tMTU         uint32                   `yaml:\"mtu,omitempty\" protobuf:\"13\"`\n}\n\nvar (\n\tzero16 = netip.MustParseAddr(\"::\")\n\tzero4  = netip.MustParseAddr(\"0.0.0.0\")\n)\n\n// Normalize converts 0.0.0.0 to zero value.\n//\n//nolint:gocyclo\nfunc (route *RouteSpecSpec) Normalize() nethelpers.Family {\n\tvar family nethelpers.Family\n\n\tif route.Destination.Bits() == 0 {\n\t\t// clear destination to be zero value to support \"0.0.0.0/0\" routes\n\t\tif route.Destination.Addr().Compare(zero4) == 0 {\n\t\t\tfamily = nethelpers.FamilyInet4\n\t\t\troute.Destination = netip.Prefix{}\n\t\t}\n\n\t\tif route.Destination.Addr().Compare(zero16) == 0 {\n\t\t\tfamily = nethelpers.FamilyInet6\n\t\t\troute.Destination = netip.Prefix{}\n\t\t}\n\t}\n\n\tif route.Gateway.Compare(zero4) == 0 {\n\t\tfamily = nethelpers.FamilyInet4\n\t\troute.Gateway = netip.Addr{}\n\t}\n\n\tif route.Gateway.Compare(zero16) == 0 {\n\t\tfamily = nethelpers.FamilyInet6\n\t\troute.Gateway = netip.Addr{}\n\t}\n\n\tif route.Source.Compare(zero4) == 0 {\n\t\tfamily = nethelpers.FamilyInet4\n\t\troute.Source = netip.Addr{}\n\t}\n\n\tif route.Source.Compare(zero16) == 0 {\n\t\tfamily = nethelpers.FamilyInet6\n\t\troute.Source = netip.Addr{}\n\t}\n\n\tswitch {\n\tcase value.IsZero(route.Gateway) && !value.IsZero(route.Destination):\n\t\troute.Scope = nethelpers.ScopeLink\n\tcase route.Destination.Addr().IsLoopback():\n\t\troute.Scope = nethelpers.ScopeHost\n\tdefault:\n\t\troute.Scope = nethelpers.ScopeGlobal\n\t}\n\n\treturn family\n}\n\n// NewRouteSpec initializes a RouteSpec resource.\nfunc NewRouteSpec(namespace resource.Namespace, id resource.ID) *RouteSpec {\n\treturn typed.NewResource[RouteSpecSpec, RouteSpecExtension](\n\t\tresource.NewMetadata(namespace, RouteSpecType, id, resource.VersionUndefined),\n\t\tRouteSpecSpec{},\n\t)\n}\n\n// RouteSpecExtension provides auxiliary methods for RouteSpec.\ntype RouteSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (RouteSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             RouteSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[RouteSpecSpec](RouteSpecType, &RouteSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/route_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"net/netip\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestRoutSpecMarshalYAML(t *testing.T) {\n\tspec := network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet6,\n\t\tDestination: netip.MustParsePrefix(\"192.168.3.4/25\"),\n\t\tSource:      netip.MustParseAddr(\"1.1.1.1\"),\n\t\tGateway:     netip.MustParseAddr(\"2.2.2.2\"),\n\t\tOutLinkName: \"eth0\",\n\t\tTable:       nethelpers.TableLocal,\n\t\tPriority:    1024,\n\t\tScope:       nethelpers.ScopeHost,\n\t\tType:        nethelpers.TypeAnycast,\n\t\tFlags:       nethelpers.RouteFlags(nethelpers.RouteOffload | nethelpers.RouteCloned),\n\t\tProtocol:    nethelpers.ProtocolBoot,\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tMTU:         1400,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t,\n\t\t`family: inet6\ndst: 192.168.3.4/25\nsrc: 1.1.1.1\ngateway: 2.2.2.2\noutLinkName: eth0\ntable: local\npriority: 1024\nscope: host\ntype: anycast\nflags: cloned,offload\nprotocol: boot\nlayer: platform\nmtu: 1400\n`,\n\t\tstring(marshaled))\n\n\tvar spec2 network.RouteSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n\nfunc TestRoutSpecNormalize(t *testing.T) {\n\tspec := network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"0.0.0.0/0\"),\n\t\tSource:      netip.MustParseAddr(\"0.0.0.0\"),\n\t\tGateway:     netip.MustParseAddr(\"0.0.0.0\"),\n\t\tOutLinkName: \"eth0\",\n\t\tTable:       nethelpers.TableLocal,\n\t\tPriority:    1024,\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tMTU:         1400,\n\t}\n\n\tnormalizedFamily := spec.Normalize()\n\n\tassert.Equal(t, netip.Prefix{}, spec.Destination)\n\tassert.Equal(t, netip.Addr{}, spec.Source)\n\tassert.Equal(t, netip.Addr{}, spec.Gateway)\n\tassert.Equal(t, nethelpers.FamilyInet4, normalizedFamily)\n\tassert.Equal(t, nethelpers.ScopeGlobal, spec.Scope)\n}\n\nfunc TestRoutSpecNormalizeV6(t *testing.T) {\n\tspec := network.RouteSpecSpec{\n\t\tFamily:      nethelpers.FamilyInet4,\n\t\tDestination: netip.MustParsePrefix(\"::/0\"),\n\t\tOutLinkName: \"eth0\",\n\t\tTable:       nethelpers.TableLocal,\n\t\tPriority:    1024,\n\t\tConfigLayer: network.ConfigPlatform,\n\t\tMTU:         1400,\n\t}\n\n\tnormalizedFamily := spec.Normalize()\n\n\tassert.Equal(t, netip.Prefix{}, spec.Destination)\n\tassert.Equal(t, netip.Addr{}, spec.Source)\n\tassert.Equal(t, netip.Addr{}, spec.Gateway)\n\tassert.Equal(t, nethelpers.FamilyInet6, normalizedFamily)\n\tassert.Equal(t, nethelpers.ScopeGlobal, spec.Scope)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/route_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// RouteStatusType is type of RouteStatus resource.\nconst RouteStatusType = resource.Type(\"RouteStatuses.net.talos.dev\")\n\n// RouteStatus resource holds physical network link status.\ntype RouteStatus = typed.Resource[RouteStatusSpec, RouteStatusExtension]\n\n// RouteStatusSpec describes status of rendered secrets.\n//\n//gotagsrewrite:gen\ntype RouteStatusSpec struct {\n\tFamily       nethelpers.Family        `yaml:\"family\" protobuf:\"1\"`\n\tDestination  netip.Prefix             `yaml:\"dst\" protobuf:\"2\"`\n\tSource       netip.Addr               `yaml:\"src\" protobuf:\"3\"`\n\tGateway      netip.Addr               `yaml:\"gateway\" protobuf:\"4\"`\n\tOutLinkIndex uint32                   `yaml:\"outLinkIndex,omitempty\" protobuf:\"5\"`\n\tOutLinkName  string                   `yaml:\"outLinkName,omitempty\" protobuf:\"6\"`\n\tTable        nethelpers.RoutingTable  `yaml:\"table\" protobuf:\"7\"`\n\tPriority     uint32                   `yaml:\"priority\" protobuf:\"8\"`\n\tScope        nethelpers.Scope         `yaml:\"scope\" protobuf:\"9\"`\n\tType         nethelpers.RouteType     `yaml:\"type\" protobuf:\"10\"`\n\tFlags        nethelpers.RouteFlags    `yaml:\"flags\" protobuf:\"11\"`\n\tProtocol     nethelpers.RouteProtocol `yaml:\"protocol\" protobuf:\"12\"`\n\tMTU          uint32                   `yaml:\"mtu,omitempty\" protobuf:\"13\"`\n}\n\n// NewRouteStatus initializes a RouteStatus resource.\nfunc NewRouteStatus(namespace resource.Namespace, id resource.ID) *RouteStatus {\n\treturn typed.NewResource[RouteStatusSpec, RouteStatusExtension](\n\t\tresource.NewMetadata(namespace, RouteStatusType, id, resource.VersionUndefined),\n\t\tRouteStatusSpec{},\n\t)\n}\n\n// RouteStatusExtension provides auxiliary methods for RouteStatus.\ntype RouteStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (RouteStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             RouteStatusType,\n\t\tAliases:          []resource.Type{\"route\", \"routes\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Destination\",\n\t\t\t\tJSONPath: `{.dst}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Gateway\",\n\t\t\t\tJSONPath: `{.gateway}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Link\",\n\t\t\t\tJSONPath: `{.outLinkName}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Metric\",\n\t\t\t\tJSONPath: `{.priority}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[RouteStatusSpec](RouteStatusType, &RouteStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/routing_rule_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// RoutingRuleSpecType is type of RoutingRuleSpec resource.\nconst RoutingRuleSpecType = resource.Type(\"RoutingRuleSpecs.net.talos.dev\")\n\n// RoutingRuleSpec resource holds routing rule specification to be applied to the kernel.\ntype RoutingRuleSpec = typed.Resource[RoutingRuleSpecSpec, RoutingRuleSpecExtension]\n\n// RoutingRuleSpecSpec describes the routing rule.\n//\n//gotagsrewrite:gen\ntype RoutingRuleSpecSpec struct {\n\tFamily      nethelpers.Family            `yaml:\"family\" protobuf:\"1\"`\n\tSrc         netip.Prefix                 `yaml:\"src\" protobuf:\"2\"`\n\tDst         netip.Prefix                 `yaml:\"dst\" protobuf:\"3\"`\n\tTable       nethelpers.RoutingTable      `yaml:\"table\" protobuf:\"4\"`\n\tPriority    uint32                       `yaml:\"priority\" protobuf:\"5\"`\n\tAction      nethelpers.RoutingRuleAction `yaml:\"action\" protobuf:\"6\"`\n\tIIFName     string                       `yaml:\"iifName,omitempty\" protobuf:\"7\"`\n\tOIFName     string                       `yaml:\"oifName,omitempty\" protobuf:\"8\"`\n\tFwMark      uint32                       `yaml:\"fwMark,omitempty\" protobuf:\"9\"`\n\tFwMask      uint32                       `yaml:\"fwMask,omitempty\" protobuf:\"10\"`\n\tConfigLayer ConfigLayer                  `yaml:\"layer\" protobuf:\"11\"`\n}\n\n// NewRoutingRuleSpec initializes a RoutingRuleSpec resource.\nfunc NewRoutingRuleSpec(namespace resource.Namespace, id resource.ID) *RoutingRuleSpec {\n\treturn typed.NewResource[RoutingRuleSpecSpec, RoutingRuleSpecExtension](\n\t\tresource.NewMetadata(namespace, RoutingRuleSpecType, id, resource.VersionUndefined),\n\t\tRoutingRuleSpecSpec{},\n\t)\n}\n\n// RoutingRuleSpecExtension provides auxiliary methods for RoutingRuleSpec.\ntype RoutingRuleSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (RoutingRuleSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             RoutingRuleSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[RoutingRuleSpecSpec](RoutingRuleSpecType, &RoutingRuleSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/routing_rule_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// RoutingRuleStatusType is type of RoutingRuleStatus resource.\nconst RoutingRuleStatusType = resource.Type(\"RoutingRuleStatuses.net.talos.dev\")\n\n// RoutingRuleStatus resource holds routing rule status observed from the kernel.\ntype RoutingRuleStatus = typed.Resource[RoutingRuleStatusSpec, RoutingRuleStatusExtension]\n\n// RoutingRuleStatusSpec describes the observed routing rule state.\n//\n//gotagsrewrite:gen\ntype RoutingRuleStatusSpec struct {\n\tFamily   nethelpers.Family            `yaml:\"family\" protobuf:\"1\"`\n\tSrc      netip.Prefix                 `yaml:\"src\" protobuf:\"2\"`\n\tDst      netip.Prefix                 `yaml:\"dst\" protobuf:\"3\"`\n\tTable    nethelpers.RoutingTable      `yaml:\"table\" protobuf:\"4\"`\n\tPriority uint32                       `yaml:\"priority\" protobuf:\"5\"`\n\tAction   nethelpers.RoutingRuleAction `yaml:\"action\" protobuf:\"6\"`\n\tIIFName  string                       `yaml:\"iifName,omitempty\" protobuf:\"7\"`\n\tOIFName  string                       `yaml:\"oifName,omitempty\" protobuf:\"8\"`\n\tFwMark   uint32                       `yaml:\"fwMark,omitempty\" protobuf:\"9\"`\n\tFwMask   uint32                       `yaml:\"fwMask,omitempty\" protobuf:\"10\"`\n}\n\n// NewRoutingRuleStatus initializes a RoutingRuleStatus resource.\nfunc NewRoutingRuleStatus(namespace resource.Namespace, id resource.ID) *RoutingRuleStatus {\n\treturn typed.NewResource[RoutingRuleStatusSpec, RoutingRuleStatusExtension](\n\t\tresource.NewMetadata(namespace, RoutingRuleStatusType, id, resource.VersionUndefined),\n\t\tRoutingRuleStatusSpec{},\n\t)\n}\n\n// RoutingRuleStatusExtension provides auxiliary methods for RoutingRuleStatus.\ntype RoutingRuleStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (RoutingRuleStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             RoutingRuleStatusType,\n\t\tAliases:          []resource.Type{\"routingrule\", \"routingrules\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Src\",\n\t\t\t\tJSONPath: `{.src}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Dst\",\n\t\t\t\tJSONPath: `{.dst}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Table\",\n\t\t\t\tJSONPath: `{.table}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Priority\",\n\t\t\t\tJSONPath: `{.priority}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[RoutingRuleStatusSpec](RoutingRuleStatusType, &RoutingRuleStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// StatusType is type of Status resource.\nconst StatusType = resource.Type(\"NetworkStatuses.net.talos.dev\")\n\n// Status resource holds status of networking setup.\ntype Status = typed.Resource[StatusSpec, StatusExtension]\n\n// StatusSpec describes network state.\n//\n//gotagsrewrite:gen\ntype StatusSpec struct {\n\tAddressReady      bool `yaml:\"addressReady\" protobuf:\"1\"`\n\tConnectivityReady bool `yaml:\"connectivityReady\" protobuf:\"2\"`\n\tHostnameReady     bool `yaml:\"hostnameReady\" protobuf:\"3\"`\n\tEtcFilesReady     bool `yaml:\"etcFilesReady\" protobuf:\"4\"`\n}\n\n// StatusID is the resource ID of the singleton instance.\nconst StatusID resource.ID = \"status\"\n\n// NewStatus initializes a Status resource.\nfunc NewStatus(namespace resource.Namespace, id resource.ID) *Status {\n\treturn typed.NewResource[StatusSpec, StatusExtension](\n\t\tresource.NewMetadata(namespace, StatusType, id, resource.VersionUndefined),\n\t\tStatusSpec{},\n\t)\n}\n\n// StatusExtension provides auxiliary methods for Status.\ntype StatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (StatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StatusType,\n\t\tAliases:          []resource.Type{\"netstatus\", \"netstatuses\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Address\",\n\t\t\t\tJSONPath: \"{.addressReady}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Connectivity\",\n\t\t\t\tJSONPath: \"{.connectivityReady}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Hostname\",\n\t\t\t\tJSONPath: \"{.hostnameReady}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Etc\",\n\t\t\t\tJSONPath: \"{.etcFilesReady}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StatusSpec](StatusType, &Status{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/timeserver_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// TimeServerSpecType is type of TimeServerSpec resource.\nconst TimeServerSpecType = resource.Type(\"TimeServerSpecs.net.talos.dev\")\n\n// TimeServerSpec resource holds NTP server info.\ntype TimeServerSpec = typed.Resource[TimeServerSpecSpec, TimeServerSpecExtension]\n\n// TimeServerID is the ID of the singleton instance.\nconst TimeServerID resource.ID = \"timeservers\"\n\n// TimeServerSpecSpec describes NTP servers.\n//\n//gotagsrewrite:gen\ntype TimeServerSpecSpec struct {\n\tNTPServers  []string    `yaml:\"timeServers\" protobuf:\"1\"`\n\tConfigLayer ConfigLayer `yaml:\"layer\" protobuf:\"2\"`\n}\n\n// NewTimeServerSpec initializes a TimeServerSpec resource.\nfunc NewTimeServerSpec(namespace resource.Namespace, id resource.ID) *TimeServerSpec {\n\treturn typed.NewResource[TimeServerSpecSpec, TimeServerSpecExtension](\n\t\tresource.NewMetadata(namespace, TimeServerSpecType, id, resource.VersionUndefined),\n\t\tTimeServerSpecSpec{},\n\t)\n}\n\n// TimeServerSpecExtension provides auxiliary methods for TimeServerSpec.\ntype TimeServerSpecExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (TimeServerSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             TimeServerSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[TimeServerSpecSpec](TimeServerSpecType, &TimeServerSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/timeserver_spec_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestTimeServerSpecMarshalYAML(t *testing.T) {\n\tspec := network.TimeServerSpecSpec{\n\t\tNTPServers:  []string{\"pool.ntp.org\"},\n\t\tConfigLayer: network.ConfigPlatform,\n\t}\n\n\tmarshaled, err := yaml.Marshal(spec)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"timeServers:\\n    - pool.ntp.org\\nlayer: platform\\n\", string(marshaled))\n\n\tvar spec2 network.TimeServerSpecSpec\n\n\trequire.NoError(t, yaml.Unmarshal(marshaled, &spec2))\n\n\tassert.Equal(t, spec, spec2)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/timeserver_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// TimeServerStatusType is type of TimeServerStatus resource.\nconst TimeServerStatusType = resource.Type(\"TimeServerStatuses.net.talos.dev\")\n\n// TimeServerStatus resource holds NTP server info.\ntype TimeServerStatus = typed.Resource[TimeServerStatusSpec, TimeServerStatusExtension]\n\n// TimeServerStatusSpec describes NTP servers.\n//\n//gotagsrewrite:gen\ntype TimeServerStatusSpec struct {\n\tNTPServers []string `yaml:\"timeServers\" protobuf:\"1\"`\n}\n\n// NewTimeServerStatus initializes a TimeServerStatus resource.\nfunc NewTimeServerStatus(namespace resource.Namespace, id resource.ID) *TimeServerStatus {\n\treturn typed.NewResource[TimeServerStatusSpec, TimeServerStatusExtension](\n\t\tresource.NewMetadata(namespace, TimeServerStatusType, id, resource.VersionUndefined),\n\t\tTimeServerStatusSpec{},\n\t)\n}\n\n// TimeServerStatusExtension provides auxiliary methods for TimeServerStatus.\ntype TimeServerStatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (TimeServerStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             TimeServerStatusType,\n\t\tAliases:          []resource.Type{\"timeserver\", \"timeservers\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Timeservers\",\n\t\t\t\tJSONPath: \"{.timeServers}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[TimeServerStatusSpec](TimeServerStatusType, &TimeServerStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/ula.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network\n\nimport (\n\t\"crypto/sha256\"\n\t\"net/netip\"\n)\n\n// ULAPurpose is the Unique Local Addressing key for the Talos-specific purpose of the prefix.\ntype ULAPurpose byte\n\nconst (\n\t// ULAUnknown indicates an unknown ULA Purpose.\n\tULAUnknown = 0x00\n\n\t// ULABootstrap is the Unique Local Addressing space key for the Talos Self-Bootstrapping protocol.\n\tULABootstrap = 0x01\n\n\t// ULAKubeSpan is the Unique Local Addressing space key for the Talos KubeSpan feature.\n\tULAKubeSpan = 0x02\n\n\t// ULASideroLink is the Unique Local Addressing space key for the SideroLink feature.\n\tULASideroLink = 0x03\n\n\t// ULAVirtualSideroLink is the Unique Local Addressing space key for the Virtual SideroLink over GRPC feature.\n\tULAVirtualSideroLink = 0x04\n)\n\n// ULAPrefix calculates and returns a Talos-specific Unique Local Address prefix for the given purpose.\n// This implements a Talos-specific implementation of RFC4193.\n// The Talos implementation uses a combination of a 48-bit cluster-unique portion with an 8-bit purpose portion.\nfunc ULAPrefix(clusterID string, purpose ULAPurpose) netip.Prefix {\n\tvar prefixData [16]byte\n\n\thash := sha256.Sum256([]byte(clusterID))\n\n\t// Take the last 16 bytes of the clusterID's hash.\n\tcopy(prefixData[:], hash[sha256.Size-16:])\n\n\t// Apply the ULA prefix as per RFC4193\n\tprefixData[0] = 0xfd\n\n\t// Apply the Talos-specific ULA Purpose suffix\n\tprefixData[7] = byte(purpose)\n\n\treturn netip.PrefixFrom(netip.AddrFrom16(prefixData), 64).Masked()\n}\n\n// IsULA checks whether IP address is a Unique Local Address with the specific purpose.\nfunc IsULA(ip netip.Addr, purpose ULAPurpose) bool {\n\tif !ip.Is6() {\n\t\treturn false\n\t}\n\n\traw := ip.As16()\n\n\treturn raw[0] == 0xfd && raw[7] == byte(purpose)\n}\n\n// NotSideroLinkIP is a shorthand for !IsULA(ip, ULASideroLink).\nfunc NotSideroLinkIP(ip netip.Addr) bool {\n\treturn !IsULA(ip, ULASideroLink)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/network/ula_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage network_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/network\"\n)\n\nfunc TestULAPrefix(t *testing.T) {\n\tassert.Equal(t, \"fd7f:175a:b97c:5602::/64\", network.ULAPrefix(\"8XuV9TZHW08DOk3bVxQjH9ih_TBKjnh-j44tsCLSBzo=\", network.ULAKubeSpan).String())\n}\n"
  },
  {
    "path": "pkg/machinery/resources/perf/cpu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type CPUSpec -type MemorySpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// CPUType is type of Etcd resource.\nconst CPUType = resource.Type(\"CPUStats.perf.talos.dev\")\n\n// CPUID is a resource ID of singleton instance.\nconst CPUID = resource.ID(\"latest\")\n\n// CPU represents the last CPU stats snapshot.\ntype CPU = typed.Resource[CPUSpec, CPUExtension]\n\n// CPUSpec represents the last CPU stats snapshot.\n//\n//gotagsrewrite:gen\ntype CPUSpec struct {\n\tCPU             []CPUStat `yaml:\"cpu\" protobuf:\"1\"`\n\tCPUTotal        CPUStat   `yaml:\"cpuTotal\" protobuf:\"2\"`\n\tIRQTotal        uint64    `yaml:\"irqTotal\" protobuf:\"3\"`\n\tContextSwitches uint64    `yaml:\"contextSwitches\" protobuf:\"4\"`\n\tProcessCreated  uint64    `yaml:\"processCreated\" protobuf:\"5\"`\n\tProcessRunning  uint64    `yaml:\"processRunning\" protobuf:\"6\"`\n\tProcessBlocked  uint64    `yaml:\"processBlocked\" protobuf:\"7\"`\n\tSoftIrqTotal    uint64    `yaml:\"softIrqTotal\" protobuf:\"8\"`\n}\n\n// CPUStat represents a single cpu stat.\n//\n//gotagsrewrite:gen\ntype CPUStat struct {\n\tUser      float64 `yaml:\"user\" protobuf:\"1\"`\n\tNice      float64 `yaml:\"nice\" protobuf:\"2\"`\n\tSystem    float64 `yaml:\"system\" protobuf:\"3\"`\n\tIdle      float64 `yaml:\"idle\" protobuf:\"4\"`\n\tIowait    float64 `yaml:\"iowait\" protobuf:\"5\"`\n\tIrq       float64 `yaml:\"irq\" protobuf:\"6\"`\n\tSoftIrq   float64 `yaml:\"softIrq\" protobuf:\"7\"`\n\tSteal     float64 `yaml:\"steal\" protobuf:\"8\"`\n\tGuest     float64 `yaml:\"guest\" protobuf:\"9\"`\n\tGuestNice float64 `yaml:\"guestNice\" protobuf:\"10\"`\n}\n\n// NewCPU creates new default CPU stats object.\nfunc NewCPU() *CPU {\n\treturn typed.NewResource[CPUSpec, CPUExtension](\n\t\tresource.NewMetadata(NamespaceName, CPUType, CPUID, resource.VersionUndefined),\n\t\tCPUSpec{},\n\t)\n}\n\n// CPUExtension is an auxiliary type for CPU resource.\ntype CPUExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (CPUExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             CPUType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"User\",\n\t\t\t\tJSONPath: \"{.cpuTotal.user}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"System\",\n\t\t\t\tJSONPath: \"{.cpuTotal.system}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[CPUSpec](CPUType, &CPU{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/perf/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type CPUSpec -type MemorySpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage perf\n\n// DeepCopy generates a deep copy of CPUSpec.\nfunc (o CPUSpec) DeepCopy() CPUSpec {\n\tvar cp CPUSpec = o\n\tif o.CPU != nil {\n\t\tcp.CPU = make([]CPUStat, len(o.CPU))\n\t\tcopy(cp.CPU, o.CPU)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MemorySpec.\nfunc (o MemorySpec) DeepCopy() MemorySpec {\n\tvar cp MemorySpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/perf/mem.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MemoryType is type of Etcd resource.\nconst MemoryType = resource.Type(\"MemoryStats.perf.talos.dev\")\n\n// MemoryID is a resource ID of singleton instance.\nconst MemoryID = resource.ID(\"latest\")\n\n// Memory represents the last Memory stats snapshot.\ntype Memory = typed.Resource[MemorySpec, MemoryExtension]\n\n// MemorySpec represents the last Memory stats snapshot.\n//\n//gotagsrewrite:gen\ntype MemorySpec struct {\n\tMemTotal          uint64 `yaml:\"total\" protobuf:\"1\"`\n\tMemUsed           uint64 `yaml:\"used\" protobuf:\"2\"`\n\tMemAvailable      uint64 `yaml:\"available\" protobuf:\"3\"`\n\tBuffers           uint64 `yaml:\"buffers\" protobuf:\"4\"`\n\tCached            uint64 `yaml:\"cached\" protobuf:\"5\"`\n\tSwapCached        uint64 `yaml:\"swapCached\" protobuf:\"6\"`\n\tActive            uint64 `yaml:\"active\" protobuf:\"7\"`\n\tInactive          uint64 `yaml:\"inactive\" protobuf:\"8\"`\n\tActiveAnon        uint64 `yaml:\"activeAnon\" protobuf:\"9\"`\n\tInactiveAnon      uint64 `yaml:\"inactiveAnon\" protobuf:\"10\"`\n\tActiveFile        uint64 `yaml:\"activeFile\" protobuf:\"11\"`\n\tInactiveFile      uint64 `yaml:\"inactiveFile\" protobuf:\"12\"`\n\tUnevictable       uint64 `yaml:\"unevictable\" protobuf:\"13\"`\n\tMlocked           uint64 `yaml:\"mlocked\" protobuf:\"14\"`\n\tSwapTotal         uint64 `yaml:\"swapTotal\" protobuf:\"15\"`\n\tSwapFree          uint64 `yaml:\"swapFree\" protobuf:\"16\"`\n\tDirty             uint64 `yaml:\"dirty\" protobuf:\"17\"`\n\tWriteback         uint64 `yaml:\"writeback\" protobuf:\"18\"`\n\tAnonPages         uint64 `yaml:\"anonPages\" protobuf:\"19\"`\n\tMapped            uint64 `yaml:\"mapped\" protobuf:\"20\"`\n\tShmem             uint64 `yaml:\"shmem\" protobuf:\"21\"`\n\tSlab              uint64 `yaml:\"slab\" protobuf:\"22\"`\n\tSReclaimable      uint64 `yaml:\"sreclaimable\" protobuf:\"23\"`\n\tSUnreclaim        uint64 `yaml:\"sunreclaim\" protobuf:\"24\"`\n\tKernelStack       uint64 `yaml:\"kernelStack\" protobuf:\"25\"`\n\tPageTables        uint64 `yaml:\"pageTables\" protobuf:\"26\"`\n\tNFSunstable       uint64 `yaml:\"nfsunstable\" protobuf:\"27\"`\n\tBounce            uint64 `yaml:\"bounce\" protobuf:\"28\"`\n\tWritebackTmp      uint64 `yaml:\"writeBacktmp\" protobuf:\"29\"`\n\tCommitLimit       uint64 `yaml:\"commitLimit\" protobuf:\"30\"`\n\tCommittedAS       uint64 `yaml:\"commitTedas\" protobuf:\"31\"`\n\tVmallocTotal      uint64 `yaml:\"vmallocTotal\" protobuf:\"32\"`\n\tVmallocUsed       uint64 `yaml:\"vmallocUsed\" protobuf:\"33\"`\n\tVmallocChunk      uint64 `yaml:\"vmallocChunk\" protobuf:\"34\"`\n\tHardwareCorrupted uint64 `yaml:\"hardwareCorrupted\" protobuf:\"35\"`\n\tAnonHugePages     uint64 `yaml:\"anonHugePages\" protobuf:\"36\"`\n\tShmemHugePages    uint64 `yaml:\"shmemHugePages\" protobuf:\"37\"`\n\tShmemPmdMapped    uint64 `yaml:\"shmemPmdMapped\" protobuf:\"38\"`\n\tCmaTotal          uint64 `yaml:\"cmaTotal\" protobuf:\"39\"`\n\tCmaFree           uint64 `yaml:\"cmaFree\" protobuf:\"40\"`\n\tHugePagesTotal    uint64 `yaml:\"hugePagesTotal\" protobuf:\"41\"`\n\tHugePagesFree     uint64 `yaml:\"hugePagesFree\" protobuf:\"42\"`\n\tHugePagesRsvd     uint64 `yaml:\"hugePagesRsvd\" protobuf:\"43\"`\n\tHugePagesSurp     uint64 `yaml:\"hugePagesSurp\" protobuf:\"44\"`\n\tHugepagesize      uint64 `yaml:\"hugepagesize\" protobuf:\"45\"`\n\tDirectMap4k       uint64 `yaml:\"directMap4k\" protobuf:\"46\"`\n\tDirectMap2m       uint64 `yaml:\"directMap2m\" protobuf:\"47\"`\n\tDirectMap1g       uint64 `yaml:\"directMap1g\" protobuf:\"48\"`\n}\n\n// NewMemory creates new default Memory stats object.\nfunc NewMemory() *Memory {\n\treturn typed.NewResource[MemorySpec, MemoryExtension](\n\t\tresource.NewMetadata(NamespaceName, MemoryType, MemoryID, resource.VersionUndefined),\n\t\tMemorySpec{},\n\t)\n}\n\n// MemoryExtension is an auxiliary type for Memory resource.\ntype MemoryExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MemoryExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MemoryType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Used\",\n\t\t\t\tJSONPath: \"{.used}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Total\",\n\t\t\t\tJSONPath: \"{.total}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MemorySpec](MemoryType, &Memory{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/perf/perf.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains resources related to stats.\nconst NamespaceName resource.Namespace = \"perf\"\n"
  },
  {
    "path": "pkg/machinery/resources/perf/perf_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage perf_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/perf\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&perf.Memory{},\n\t\t&perf.CPU{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/resources.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package resources provides common Talos resources settings.\npackage resources\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/api_service_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// APIServiceConfigType is type of MaintenanceConfig resource.\nconst APIServiceConfigType = resource.Type(\"APIServiceConfigs.runtime.talos.dev\")\n\n// APIServiceConfig resource holds configuration for Talos API service (apid).\ntype APIServiceConfig = typed.Resource[APIServiceConfigSpec, APIServiceConfigExtension]\n\n// APIServiceConfigID is a resource ID for APIServiceConfig.\nconst APIServiceConfigID resource.ID = \"apid\"\n\n// APIServiceConfigSpec describes configuration for Talos API service (apid).\n//\n//gotagsrewrite:gen\ntype APIServiceConfigSpec struct {\n\tListenAddress string `yaml:\"listenAddress\" protobuf:\"1\"`\n\n\tNodeRoutingDisabled     bool `yaml:\"nodeRoutingDisabled\" protobuf:\"2\"`\n\tReadonlyRoleMode        bool `yaml:\"readonlyRoleMode\" protobuf:\"3\"`\n\tSkipVerifyingClientCert bool `yaml:\"skipVerifyingClientCert\" protobuf:\"4\"`\n}\n\n// NewAPIServiceConfig initializes an APIServiceConfig resource.\nfunc NewAPIServiceConfig() *APIServiceConfig {\n\treturn typed.NewResource[APIServiceConfigSpec, APIServiceConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, APIServiceConfigType, APIServiceConfigID, resource.VersionUndefined),\n\t\tAPIServiceConfigSpec{},\n\t)\n}\n\n// APIServiceConfigExtension is auxiliary resource data for APIServiceConfig.\ntype APIServiceConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (APIServiceConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             APIServiceConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[APIServiceConfigSpec](APIServiceConfigType, &APIServiceConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/booted_entry_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// BootedEntryType is the type of booted entry resource.\nconst BootedEntryType = resource.Type(\"BootedEntries.talos.dev\")\n\n// BootedEntryID is the ID of the booted entry resource.\nconst BootedEntryID = resource.ID(\"bootedentry\")\n\n// BootedEntry is the booted entry resource.\ntype BootedEntry = typed.Resource[BootedEntrySpec, BootedEntryExtension]\n\n// BootedEntrySpec describes the booted entry resource properties.\n//\n//gotagsrewrite:gen\ntype BootedEntrySpec struct {\n\tBootedEntry string `yaml:\"bootedEntry,omitempty\" protobuf:\"1\"`\n}\n\n// BootedEntryExtension provides auxiliary methods for BootedEntry resource.\ntype BootedEntryExtension struct{}\n\n// NewBootedEntrySpec initializes a new BootedEntrySpec.\nfunc NewBootedEntrySpec() *BootedEntry {\n\treturn typed.NewResource[BootedEntrySpec, BootedEntryExtension](\n\t\tresource.NewMetadata(NamespaceName, BootedEntryType, BootedEntryID, resource.VersionUndefined),\n\t\tBootedEntrySpec{},\n\t)\n}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (BootedEntryExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             BootedEntryType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Booted Entry\",\n\t\t\t\tJSONPath: `{.bootedEntry}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(BootedEntryType, &BootedEntry{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/condition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n)\n\n// KernelParamsSetCondition implements condition which waits for the kernels to be in sync.\ntype KernelParamsSetCondition struct {\n\tstate state.State\n\tprops []*kernel.Param\n}\n\n// NewKernelParamsSetCondition builds a coondition which waits for the kernel to be in sync.\nfunc NewKernelParamsSetCondition(state state.State, props ...*kernel.Param) *KernelParamsSetCondition {\n\treturn &KernelParamsSetCondition{\n\t\tstate: state,\n\t\tprops: props,\n\t}\n}\n\nfunc (condition *KernelParamsSetCondition) String() string {\n\treturn \"kernelParams\"\n}\n\n// Wait implements condition interface.\nfunc (condition *KernelParamsSetCondition) Wait(ctx context.Context) error {\n\tfor _, prop := range condition.props {\n\t\tif _, err := condition.state.WatchFor(\n\t\t\tctx,\n\t\t\tresource.NewMetadata(NamespaceName, KernelParamStatusType, prop.Key, resource.VersionUndefined),\n\t\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\t\tif resource.IsTombstone(r) {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\n\t\t\t\tstatus := r.(*KernelParamStatus).TypedSpec()\n\t\t\t\tif status.Current != prop.Value {\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\n\t\t\t\treturn true, nil\n\t\t\t}),\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ExtensionServiceConfigStatusCondition implements condition which waits for extension service config to be available.\ntype ExtensionServiceConfigStatusCondition struct {\n\tstate       state.State\n\tserviceName string\n}\n\n// NewExtensionServiceConfigStatusCondition builds a condition which waits for extension service config to be available.\nfunc NewExtensionServiceConfigStatusCondition(state state.State, serviceName string) *ExtensionServiceConfigStatusCondition {\n\treturn &ExtensionServiceConfigStatusCondition{\n\t\tstate:       state,\n\t\tserviceName: serviceName,\n\t}\n}\n\nfunc (condition *ExtensionServiceConfigStatusCondition) String() string {\n\treturn \"extension service config\"\n}\n\n// Wait implements condition interface.\nfunc (condition *ExtensionServiceConfigStatusCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, ExtensionServiceConfigStatusType, condition.serviceName, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t)\n\n\treturn err\n}\n\n// DevicesStatusCondition implements condition which waits for devices to be ready.\ntype DevicesStatusCondition struct {\n\tstate state.State\n}\n\n// NewDevicesStatusCondition builds a condition which waits for devices to be ready.\nfunc NewDevicesStatusCondition(state state.State) *DevicesStatusCondition {\n\treturn &DevicesStatusCondition{\n\t\tstate: state,\n\t}\n}\n\nfunc (condition *DevicesStatusCondition) String() string {\n\treturn \"devices to be ready\"\n}\n\n// Wait implements condition interface.\nfunc (condition *DevicesStatusCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, DevicesStatusType, DevicesID, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn r.(*DevicesStatus).TypedSpec().Ready, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n\n// APIServiceConfigCondition implements condition which waits for api service config to be ready.\ntype APIServiceConfigCondition struct {\n\tstate state.State\n}\n\n// NewAPIServiceConfigCondition builds a condition which waits for api service config to be ready.\nfunc NewAPIServiceConfigCondition(state state.State) *APIServiceConfigCondition {\n\treturn &APIServiceConfigCondition{\n\t\tstate: state,\n\t}\n}\n\nfunc (condition *APIServiceConfigCondition) String() string {\n\treturn \"config to be ready\"\n}\n\n// Wait implements condition interface.\nfunc (condition *APIServiceConfigCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, APIServiceConfigType, APIServiceConfigID, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn true, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/condition_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestCondition(t *testing.T) {\n\tctx, ctxCancel := context.WithTimeout(t.Context(), time.Second)\n\tt.Cleanup(ctxCancel)\n\n\tt.Parallel()\n\n\tfor _, tt := range []struct {\n\t\tName               string\n\t\tActualKernelParams []*kernel.Param\n\t\tAwaitKernelParams  []*kernel.Param\n\t\tSucceeds           bool\n\t}{\n\t\t{\n\t\t\tName: \"okay\",\n\t\t\tActualKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tAwaitKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSucceeds: true,\n\t\t},\n\t\t{\n\t\t\tName:               \"timeout\",\n\t\t\tActualKernelParams: []*kernel.Param{},\n\t\t\tAwaitKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSucceeds: false,\n\t\t},\n\t\t{\n\t\t\tName: \"value differs\",\n\t\t\tActualKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"0\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tAwaitKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSucceeds: false,\n\t\t},\n\t\t{\n\t\t\tName: \"multiple values\",\n\t\t\tActualKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.dmesg_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.perf_event_paranoid\",\n\t\t\t\t\tValue: \"3\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tAwaitKernelParams: []*kernel.Param{\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.kptr_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.dmesg_restrict\",\n\t\t\t\t\tValue: \"1\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tKey:   \"proc.sys.kernel.perf_event_paranoid\",\n\t\t\t\t\tValue: \"3\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tSucceeds: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tstate := state.WrapCore(namespaced.NewState(inmem.Build))\n\n\t\t\tfor _, prop := range tt.ActualKernelParams {\n\t\t\t\tstatus := runtime.NewKernelParamStatus(runtime.NamespaceName, prop.Key)\n\t\t\t\t*status.TypedSpec() = runtime.KernelParamStatusSpec{\n\t\t\t\t\tCurrent: prop.Value,\n\t\t\t\t}\n\n\t\t\t\trequire.NoError(t, state.Create(ctx, status))\n\t\t\t}\n\n\t\t\terr := runtime.NewKernelParamsSetCondition(state, tt.AwaitKernelParams...).Wait(ctx)\n\n\t\t\tif tt.Succeeds {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t} else {\n\t\t\t\tassert.True(t, errors.Is(err, context.DeadlineExceeded), \"error is %v\", err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type APIServiceConfigSpec -type BootedEntrySpec -type DevicesStatusSpec -type DiagnosticSpec -type EnvironmentSpec -type EventSinkConfigSpec -type ExtensionServiceConfigSpec -type ExtensionServiceConfigStatusSpec -type KernelCmdlineSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type LoadedKernelModuleSpec -type MaintenanceServiceConfigSpec -type MaintenanceServiceRequestSpec -type MachineResetSignalSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type OOMActionSpec -type PlatformMetadataSpec -type SecurityStateSpec -type MetaLoadedSpec -type SBOMItemSpec -type UniqueMachineTokenSpec -type VersionSpec -type WatchdogTimerConfigSpec -type WatchdogTimerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n)\n\n// DeepCopy generates a deep copy of APIServiceConfigSpec.\nfunc (o APIServiceConfigSpec) DeepCopy() APIServiceConfigSpec {\n\tvar cp APIServiceConfigSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of BootedEntrySpec.\nfunc (o BootedEntrySpec) DeepCopy() BootedEntrySpec {\n\tvar cp BootedEntrySpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DevicesStatusSpec.\nfunc (o DevicesStatusSpec) DeepCopy() DevicesStatusSpec {\n\tvar cp DevicesStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of DiagnosticSpec.\nfunc (o DiagnosticSpec) DeepCopy() DiagnosticSpec {\n\tvar cp DiagnosticSpec = o\n\tif o.Details != nil {\n\t\tcp.Details = make([]string, len(o.Details))\n\t\tcopy(cp.Details, o.Details)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EnvironmentSpec.\nfunc (o EnvironmentSpec) DeepCopy() EnvironmentSpec {\n\tvar cp EnvironmentSpec = o\n\tif o.Variables != nil {\n\t\tcp.Variables = make([]string, len(o.Variables))\n\t\tcopy(cp.Variables, o.Variables)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EventSinkConfigSpec.\nfunc (o EventSinkConfigSpec) DeepCopy() EventSinkConfigSpec {\n\tvar cp EventSinkConfigSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ExtensionServiceConfigSpec.\nfunc (o ExtensionServiceConfigSpec) DeepCopy() ExtensionServiceConfigSpec {\n\tvar cp ExtensionServiceConfigSpec = o\n\tif o.Files != nil {\n\t\tcp.Files = make([]ExtensionServiceConfigFile, len(o.Files))\n\t\tcopy(cp.Files, o.Files)\n\t}\n\tif o.Environment != nil {\n\t\tcp.Environment = make([]string, len(o.Environment))\n\t\tcopy(cp.Environment, o.Environment)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ExtensionServiceConfigStatusSpec.\nfunc (o ExtensionServiceConfigStatusSpec) DeepCopy() ExtensionServiceConfigStatusSpec {\n\tvar cp ExtensionServiceConfigStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KernelCmdlineSpec.\nfunc (o KernelCmdlineSpec) DeepCopy() KernelCmdlineSpec {\n\tvar cp KernelCmdlineSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KernelModuleSpecSpec.\nfunc (o KernelModuleSpecSpec) DeepCopy() KernelModuleSpecSpec {\n\tvar cp KernelModuleSpecSpec = o\n\tif o.Parameters != nil {\n\t\tcp.Parameters = make([]string, len(o.Parameters))\n\t\tcopy(cp.Parameters, o.Parameters)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KernelParamSpecSpec.\nfunc (o KernelParamSpecSpec) DeepCopy() KernelParamSpecSpec {\n\tvar cp KernelParamSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KernelParamStatusSpec.\nfunc (o KernelParamStatusSpec) DeepCopy() KernelParamStatusSpec {\n\tvar cp KernelParamStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KmsgLogConfigSpec.\nfunc (o KmsgLogConfigSpec) DeepCopy() KmsgLogConfigSpec {\n\tvar cp KmsgLogConfigSpec = o\n\tif o.Destinations != nil {\n\t\tcp.Destinations = make([]*url.URL, len(o.Destinations))\n\t\tcopy(cp.Destinations, o.Destinations)\n\t\tfor i2 := range o.Destinations {\n\t\t\tif o.Destinations[i2] != nil {\n\t\t\t\tcp.Destinations[i2] = new(url.URL)\n\t\t\t\t*cp.Destinations[i2] = *o.Destinations[i2]\n\t\t\t\tif o.Destinations[i2].User != nil {\n\t\t\t\t\tcp.Destinations[i2].User = new(url.Userinfo)\n\t\t\t\t\t*cp.Destinations[i2].User = *o.Destinations[i2].User\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of LoadedKernelModuleSpec.\nfunc (o LoadedKernelModuleSpec) DeepCopy() LoadedKernelModuleSpec {\n\tvar cp LoadedKernelModuleSpec = o\n\tif o.Dependencies != nil {\n\t\tcp.Dependencies = make([]string, len(o.Dependencies))\n\t\tcopy(cp.Dependencies, o.Dependencies)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MaintenanceServiceConfigSpec.\nfunc (o MaintenanceServiceConfigSpec) DeepCopy() MaintenanceServiceConfigSpec {\n\tvar cp MaintenanceServiceConfigSpec = o\n\tif o.ReachableAddresses != nil {\n\t\tcp.ReachableAddresses = make([]netip.Addr, len(o.ReachableAddresses))\n\t\tcopy(cp.ReachableAddresses, o.ReachableAddresses)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MaintenanceServiceRequestSpec.\nfunc (o MaintenanceServiceRequestSpec) DeepCopy() MaintenanceServiceRequestSpec {\n\tvar cp MaintenanceServiceRequestSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MachineResetSignalSpec.\nfunc (o MachineResetSignalSpec) DeepCopy() MachineResetSignalSpec {\n\tvar cp MachineResetSignalSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MachineStatusSpec.\nfunc (o MachineStatusSpec) DeepCopy() MachineStatusSpec {\n\tvar cp MachineStatusSpec = o\n\tif o.Status.UnmetConditions != nil {\n\t\tcp.Status.UnmetConditions = make([]UnmetCondition, len(o.Status.UnmetConditions))\n\t\tcopy(cp.Status.UnmetConditions, o.Status.UnmetConditions)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MetaKeySpec.\nfunc (o MetaKeySpec) DeepCopy() MetaKeySpec {\n\tvar cp MetaKeySpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MountStatusSpec.\nfunc (o MountStatusSpec) DeepCopy() MountStatusSpec {\n\tvar cp MountStatusSpec = o\n\tif o.Options != nil {\n\t\tcp.Options = make([]string, len(o.Options))\n\t\tcopy(cp.Options, o.Options)\n\t}\n\tif o.EncryptionProviders != nil {\n\t\tcp.EncryptionProviders = make([]string, len(o.EncryptionProviders))\n\t\tcopy(cp.EncryptionProviders, o.EncryptionProviders)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of OOMActionSpec.\nfunc (o OOMActionSpec) DeepCopy() OOMActionSpec {\n\tvar cp OOMActionSpec = o\n\tif o.Processes != nil {\n\t\tcp.Processes = make([]string, len(o.Processes))\n\t\tcopy(cp.Processes, o.Processes)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of PlatformMetadataSpec.\nfunc (o PlatformMetadataSpec) DeepCopy() PlatformMetadataSpec {\n\tvar cp PlatformMetadataSpec = o\n\tif o.Tags != nil {\n\t\tcp.Tags = make(map[string]string, len(o.Tags))\n\t\tfor k2, v2 := range o.Tags {\n\t\t\tcp.Tags[k2] = v2\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SecurityStateSpec.\nfunc (o SecurityStateSpec) DeepCopy() SecurityStateSpec {\n\tvar cp SecurityStateSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MetaLoadedSpec.\nfunc (o MetaLoadedSpec) DeepCopy() MetaLoadedSpec {\n\tvar cp MetaLoadedSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of SBOMItemSpec.\nfunc (o SBOMItemSpec) DeepCopy() SBOMItemSpec {\n\tvar cp SBOMItemSpec = o\n\tif o.CPEs != nil {\n\t\tcp.CPEs = make([]string, len(o.CPEs))\n\t\tcopy(cp.CPEs, o.CPEs)\n\t}\n\tif o.PURLs != nil {\n\t\tcp.PURLs = make([]string, len(o.PURLs))\n\t\tcopy(cp.PURLs, o.PURLs)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of UniqueMachineTokenSpec.\nfunc (o UniqueMachineTokenSpec) DeepCopy() UniqueMachineTokenSpec {\n\tvar cp UniqueMachineTokenSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of VersionSpec.\nfunc (o VersionSpec) DeepCopy() VersionSpec {\n\tvar cp VersionSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of WatchdogTimerConfigSpec.\nfunc (o WatchdogTimerConfigSpec) DeepCopy() WatchdogTimerConfigSpec {\n\tvar cp WatchdogTimerConfigSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of WatchdogTimerStatusSpec.\nfunc (o WatchdogTimerStatusSpec) DeepCopy() WatchdogTimerStatusSpec {\n\tvar cp WatchdogTimerStatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/devices_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DevicesStatusType is type of DevicesStatus resource.\nconst DevicesStatusType = resource.Type(\"DevicesStatuses.runtime.talos.dev\")\n\n// DevicesStatus resource holds status of hardware devices (overall).\ntype DevicesStatus = typed.Resource[DevicesStatusSpec, DevicesStatusExtension]\n\n// DevicesID is the ID of DevicesStatus resource.\nconst DevicesID = resource.ID(\"devices\")\n\n// DevicesStatusSpec is the spec for devices status.\n//\n//gotagsrewrite:gen\ntype DevicesStatusSpec struct {\n\t// Devices are settled down and ready to be used.\n\tReady bool `yaml:\"ready\" protobuf:\"1\"`\n}\n\n// NewDevicesStatus initializes a DevicesStatus resource.\nfunc NewDevicesStatus(namespace resource.Namespace, id resource.ID) *DevicesStatus {\n\treturn typed.NewResource[DevicesStatusSpec, DevicesStatusExtension](\n\t\tresource.NewMetadata(namespace, DevicesStatusType, id, resource.VersionUndefined),\n\t\tDevicesStatusSpec{},\n\t)\n}\n\n// DevicesStatusExtension is auxiliary resource data for DevicesStatus.\ntype DevicesStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DevicesStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DevicesStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: `{.ready}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[DevicesStatusSpec](DevicesStatusType, &DevicesStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/diagnostic.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// DiagnosticType is type of Diagnostic resource.\nconst DiagnosticType = resource.Type(\"Diagnostics.runtime.talos.dev\")\n\n// Diagnostic resource contains warnings produced by Talos Diagnostics.\ntype Diagnostic = typed.Resource[DiagnosticSpec, DiagnosticExtension]\n\n// DiagnosticSpec is the spec for devices status.\n//\n//gotagsrewrite:gen\ntype DiagnosticSpec struct {\n\t// Short message describing the problem.\n\tMessage string `yaml:\"message\" protobuf:\"1\"`\n\t// Details about the problem.\n\tDetails []string `yaml:\"details\" protobuf:\"2\"`\n}\n\n// DocumentationURL returns the URL to the documentation for the warning.\nfunc (spec *DiagnosticSpec) DocumentationURL(id string) string {\n\treturn \"https://talos.dev/diagnostic/\" + id\n}\n\n// NewDiagnostic initializes a Diagnostic resource.\nfunc NewDiagnostic(namespace resource.Namespace, id resource.ID) *Diagnostic {\n\treturn typed.NewResource[DiagnosticSpec, DiagnosticExtension](\n\t\tresource.NewMetadata(namespace, DiagnosticType, id, resource.VersionUndefined),\n\t\tDiagnosticSpec{},\n\t)\n}\n\n// DiagnosticExtension is auxiliary resource data for Diagnostic.\ntype DiagnosticExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (DiagnosticExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             DiagnosticType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Message\",\n\t\t\t\tJSONPath: `{.message}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[DiagnosticSpec](DiagnosticType, &Diagnostic{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/environment.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EnvironmentType is type of Environment resource.\nconst EnvironmentType = resource.Type(\"Environments.runtime.talos.dev\")\n\n// Environment resource holds information about environment variables.\ntype Environment = typed.Resource[EnvironmentSpec, EnvironmentExtension]\n\n// EnvironmentSpec describes the specification of Environment resource.\n//\n//gotagsrewrite:gen\ntype EnvironmentSpec struct {\n\tVariables []string `yaml:\"variables\" protobuf:\"1\"`\n}\n\n// NewEnvironment initializes a Environment resource.\nfunc NewEnvironment(id resource.ID) *Environment {\n\treturn typed.NewResource[EnvironmentSpec, EnvironmentExtension](\n\t\tresource.NewMetadata(NamespaceName, EnvironmentType, id, resource.VersionUndefined),\n\t\tEnvironmentSpec{},\n\t)\n}\n\n// EnvironmentExtension is auxiliary resource data for Environment.\ntype EnvironmentExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EnvironmentExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType: EnvironmentType,\n\t\tAliases: []resource.Type{\n\t\t\t\"env\",\n\t\t},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Variables\",\n\t\t\t\tJSONPath: \"{.variables}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EnvironmentSpec](EnvironmentType, &Environment{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/event_sink_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EventSinkConfigType is type of EventSinkConfig resource.\nconst EventSinkConfigType = resource.Type(\"EventSinkConfigs.runtime.talos.dev\")\n\n// EventSinkConfig resource holds configuration for Talos event log streaming.\ntype EventSinkConfig = typed.Resource[EventSinkConfigSpec, EventSinkConfigExtension]\n\n// EventSinkConfigID is a resource ID for EventSinkConfig.\nconst EventSinkConfigID resource.ID = \"event-sink\"\n\n// EventSinkConfigSpec describes configuration of Talos event log streaming.\n//\n//gotagsrewrite:gen\ntype EventSinkConfigSpec struct {\n\tEndpoint string `yaml:\"endpoint\" protobuf:\"1\"`\n}\n\n// NewEventSinkConfig initializes a EventSinkConfig resource.\nfunc NewEventSinkConfig() *EventSinkConfig {\n\treturn typed.NewResource[EventSinkConfigSpec, EventSinkConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, EventSinkConfigType, EventSinkConfigID, resource.VersionUndefined),\n\t\tEventSinkConfigSpec{},\n\t)\n}\n\n// EventSinkConfigExtension is auxiliary resource data for EventSinkConfig.\ntype EventSinkConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EventSinkConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EventSinkConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EventSinkConfigSpec](EventSinkConfigType, &EventSinkConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/extension_services_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ExtensionServiceConfigType is a type of ExtensionServiceConfig.\nconst ExtensionServiceConfigType = resource.Type(\"ExtensionServiceConfigs.runtime.talos.dev\")\n\n// ExtensionServiceConfig represents a resource that describes status of rendered extensions service config files.\ntype ExtensionServiceConfig = typed.Resource[ExtensionServiceConfigSpec, ExtensionServiceConfigExtension]\n\n// ExtensionServiceConfigSpec describes status of rendered extensions service config files.\n//\n//gotagsrewrite:gen\ntype ExtensionServiceConfigSpec struct {\n\tFiles       []ExtensionServiceConfigFile `yaml:\"files,omitempty\" protobuf:\"1\"`\n\tEnvironment []string                     `yaml:\"environment,omitempty\" protobuf:\"2\"`\n}\n\n// ExtensionServiceConfigFile describes extensions service config files.\n//\n//gotagsrewrite:gen\ntype ExtensionServiceConfigFile struct {\n\tContent   string `yaml:\"content\" protobuf:\"1\"`\n\tMountPath string `yaml:\"mountPath\" protobuf:\"2\"`\n}\n\n// NewExtensionServiceConfigSpec initializes a new ExtensionServiceConfigSpec.\nfunc NewExtensionServiceConfigSpec(namespace resource.Namespace, id resource.ID) *ExtensionServiceConfig {\n\treturn typed.NewResource[ExtensionServiceConfigSpec, ExtensionServiceConfigExtension](\n\t\tresource.NewMetadata(namespace, ExtensionServiceConfigType, id, resource.VersionUndefined),\n\t\tExtensionServiceConfigSpec{},\n\t)\n}\n\n// ExtensionServiceConfigExtension provides auxiliary methods for ExtensionServiceConfig.\ntype ExtensionServiceConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ExtensionServiceConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ExtensionServiceConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ExtensionServiceConfigSpec](ExtensionServiceConfigType, &ExtensionServiceConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/extension_services_config_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ExtensionServiceConfigStatusType is a type of ExtensionServiceConfig.\nconst ExtensionServiceConfigStatusType = resource.Type(\"ExtensionServiceConfigStatuses.runtime.talos.dev\")\n\n// ExtensionServiceConfigStatus represents a resource that describes status of rendered extensions service config files.\ntype ExtensionServiceConfigStatus = typed.Resource[ExtensionServiceConfigStatusSpec, ExtensionServiceConfigStatusExtension]\n\n// ExtensionServiceConfigStatusSpec describes status of rendered extensions service config files.\n//\n//gotagsrewrite:gen\ntype ExtensionServiceConfigStatusSpec struct {\n\tSpecVersion string `yaml:\"specVersion\" protobuf:\"1\"`\n}\n\n// NewExtensionServiceConfigStatusSpec initializes a new ExtensionServiceConfigStatusSpec.\nfunc NewExtensionServiceConfigStatusSpec(namespace resource.Namespace, id resource.ID) *ExtensionServiceConfigStatus {\n\treturn typed.NewResource[ExtensionServiceConfigStatusSpec, ExtensionServiceConfigStatusExtension](\n\t\tresource.NewMetadata(namespace, ExtensionServiceConfigStatusType, id, resource.VersionUndefined),\n\t\tExtensionServiceConfigStatusSpec{},\n\t)\n}\n\n// ExtensionServiceConfigStatusExtension provides auxiliary methods for ExtensionServiceConfig.\ntype ExtensionServiceConfigStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ExtensionServiceConfigStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ExtensionServiceConfigStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ExtensionServiceConfigStatusSpec](ExtensionServiceConfigStatusType, &ExtensionServiceConfigStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/extension_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/extensions\"\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ExtensionStatusType is type of Extension resource.\nconst ExtensionStatusType = resource.Type(\"ExtensionStatuses.runtime.talos.dev\")\n\n// ExtensionStatus resource holds status of installed system extensions.\ntype ExtensionStatus = typed.Resource[ExtensionStatusSpec, ExtensionStatusExtension]\n\n// ExtensionStatusSpec is the spec for system extensions.\ntype ExtensionStatusSpec = extensions.Layer\n\n// NewExtensionStatus initializes a ExtensionStatus resource.\nfunc NewExtensionStatus(namespace resource.Namespace, id resource.ID) *ExtensionStatus {\n\treturn typed.NewResource[ExtensionStatusSpec, ExtensionStatusExtension](\n\t\tresource.NewMetadata(namespace, ExtensionStatusType, id, resource.VersionUndefined),\n\t\tExtensionStatusSpec{},\n\t)\n}\n\n// ExtensionStatusExtension is auxiliary resource data for ExtensionStatus.\ntype ExtensionStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ExtensionStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ExtensionStatusType,\n\t\tAliases:          []resource.Type{\"extensions\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Name\",\n\t\t\t\tJSONPath: `{.metadata.name}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Version\",\n\t\t\t\tJSONPath: `{.metadata.version}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ExtensionStatusSpec](ExtensionStatusType, &ExtensionStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/fipsstate_enumer.go",
    "content": "// Code generated by \"enumer -type=SELinuxState -type FIPSState -linecomment -text\"; DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _FIPSStateName = \"disabledenabledenabled, strict\"\n\nvar _FIPSStateIndex = [...]uint8{0, 8, 15, 30}\n\nconst _FIPSStateLowerName = \"disabledenabledenabled, strict\"\n\nfunc (i FIPSState) String() string {\n\tif i < 0 || i >= FIPSState(len(_FIPSStateIndex)-1) {\n\t\treturn fmt.Sprintf(\"FIPSState(%d)\", i)\n\t}\n\treturn _FIPSStateName[_FIPSStateIndex[i]:_FIPSStateIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _FIPSStateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[FIPSStateDisabled-(0)]\n\t_ = x[FIPSStateEnabled-(1)]\n\t_ = x[FIPSStateStrict-(2)]\n}\n\nvar _FIPSStateValues = []FIPSState{FIPSStateDisabled, FIPSStateEnabled, FIPSStateStrict}\n\nvar _FIPSStateNameToValueMap = map[string]FIPSState{\n\t_FIPSStateName[0:8]:        FIPSStateDisabled,\n\t_FIPSStateLowerName[0:8]:   FIPSStateDisabled,\n\t_FIPSStateName[8:15]:       FIPSStateEnabled,\n\t_FIPSStateLowerName[8:15]:  FIPSStateEnabled,\n\t_FIPSStateName[15:30]:      FIPSStateStrict,\n\t_FIPSStateLowerName[15:30]: FIPSStateStrict,\n}\n\nvar _FIPSStateNames = []string{\n\t_FIPSStateName[0:8],\n\t_FIPSStateName[8:15],\n\t_FIPSStateName[15:30],\n}\n\n// FIPSStateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc FIPSStateString(s string) (FIPSState, error) {\n\tif val, ok := _FIPSStateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _FIPSStateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to FIPSState values\", s)\n}\n\n// FIPSStateValues returns all values of the enum\nfunc FIPSStateValues() []FIPSState {\n\treturn _FIPSStateValues\n}\n\n// FIPSStateStrings returns a slice of all String values of the enum\nfunc FIPSStateStrings() []string {\n\tstrs := make([]string, len(_FIPSStateNames))\n\tcopy(strs, _FIPSStateNames)\n\treturn strs\n}\n\n// IsAFIPSState returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i FIPSState) IsAFIPSState() bool {\n\tfor _, v := range _FIPSStateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for FIPSState\nfunc (i FIPSState) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for FIPSState\nfunc (i *FIPSState) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = FIPSStateString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/kernel_cmdline.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KernelCmdlineType is type of KernelCmdline resource.\nconst KernelCmdlineType = resource.Type(\"KernelCmdlines.runtime.talos.dev\")\n\n// KernelCmdline resource holds configuration for kernel message log streaming.\ntype KernelCmdline = typed.Resource[KernelCmdlineSpec, KernelCmdlineExtension]\n\n// KernelCmdlineID is a resource ID for KernelCmdline.\nconst KernelCmdlineID resource.ID = \"cmdline\"\n\n// KernelCmdlineSpec presents kernel command line (contents of /proc/cmdline).\n//\n//gotagsrewrite:gen\ntype KernelCmdlineSpec struct {\n\tCmdline string `yaml:\"cmdline\" protobuf:\"1\"`\n}\n\n// NewKernelCmdline initializes a KernelCmdline resource.\nfunc NewKernelCmdline() *KernelCmdline {\n\treturn typed.NewResource[KernelCmdlineSpec, KernelCmdlineExtension](\n\t\tresource.NewMetadata(NamespaceName, KernelCmdlineType, KernelCmdlineID, resource.VersionUndefined),\n\t\tKernelCmdlineSpec{},\n\t)\n}\n\n// KernelCmdlineExtension is auxiliary resource data for KernelCmdline.\ntype KernelCmdlineExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KernelCmdlineExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KernelCmdlineType,\n\t\tAliases:          []resource.Type{\"cmdline\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Cmdline\",\n\t\t\t\tJSONPath: \"{.cmdline}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KernelCmdlineSpec](KernelCmdlineType, &KernelCmdline{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/kernel_module_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KernelModuleSpecType is type of KernelModuleSpec resource.\nconst KernelModuleSpecType = resource.Type(\"KernelModuleSpecs.runtime.talos.dev\")\n\n// KernelModuleSpec resource holds information about Linux kernel module to load.\ntype KernelModuleSpec = typed.Resource[KernelModuleSpecSpec, KernelModuleSpecExtension]\n\n// KernelModuleSpecSpec describes Linux kernel module to load.\n//\n//gotagsrewrite:gen\ntype KernelModuleSpecSpec struct {\n\tName       string   `yaml:\"string\" protobuf:\"1\"`\n\tParameters []string `yaml:\"parameters\" protobuf:\"2\"`\n\t// more options in the future: aliases, etc.\n}\n\n// NewKernelModuleSpec initializes a KernelModuleSpec resource.\nfunc NewKernelModuleSpec(namespace resource.Namespace, id resource.ID) *KernelModuleSpec {\n\treturn typed.NewResource[KernelModuleSpecSpec, KernelModuleSpecExtension](\n\t\tresource.NewMetadata(namespace, KernelModuleSpecType, id, resource.VersionUndefined),\n\t\tKernelModuleSpecSpec{},\n\t)\n}\n\n// KernelModuleSpecExtension is auxiliary resource data for KernelModuleSpec.\ntype KernelModuleSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KernelModuleSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KernelModuleSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KernelModuleSpecSpec](KernelModuleSpecType, &KernelModuleSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/kernel_params_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KernelParamSpecType is type of KernelParam resource.\nconst KernelParamSpecType = resource.Type(\"KernelParamSpecs.runtime.talos.dev\")\n\n// KernelParamDefaultSpecType is type of KernelParam resource for default kernel params.\nconst KernelParamDefaultSpecType = resource.Type(\"KernelParamDefaultSpecs.runtime.talos.dev\")\n\n// KernelParam interface.\ntype KernelParam interface {\n\tTypedSpec() *KernelParamSpecSpec\n}\n\n// KernelParamSpec resource holds sysctl flags to define.\ntype KernelParamSpec = typed.Resource[KernelParamSpecSpec, KernelParamSpecExtension]\n\n// KernelParamSpecSpec describes status of the defined sysctls.\n//\n//gotagsrewrite:gen\ntype KernelParamSpecSpec struct {\n\tValue        string `yaml:\"value\" protobuf:\"1\"`\n\tIgnoreErrors bool   `yaml:\"ignoreErrors\" protobuf:\"2\"`\n}\n\n// NewKernelParamSpec initializes a KernelParamSpec resource.\nfunc NewKernelParamSpec(namespace resource.Namespace, id resource.ID) *KernelParamSpec {\n\treturn typed.NewResource[KernelParamSpecSpec, KernelParamSpecExtension](\n\t\tresource.NewMetadata(namespace, KernelParamSpecType, id, resource.VersionUndefined),\n\t\tKernelParamSpecSpec{},\n\t)\n}\n\n// KernelParamSpecExtension is the typed.Extension for KernelParamSpec.\ntype KernelParamSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KernelParamSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KernelParamSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\n// KernelParamDefaultSpec implements meta.ResourceDefinitionProvider interface.\ntype KernelParamDefaultSpec = typed.Resource[KernelParamDefaultSpecSpec, KernelParamDefaultSpecExtension]\n\n// KernelParamDefaultSpecSpec is same as KernelParamSpecSpec.\ntype KernelParamDefaultSpecSpec = KernelParamSpecSpec\n\n// NewKernelParamDefaultSpec initializes a KernelParamDefaultSpec resource.\nfunc NewKernelParamDefaultSpec(namespace resource.Namespace, id resource.ID) *KernelParamDefaultSpec {\n\treturn typed.NewResource[KernelParamDefaultSpecSpec, KernelParamDefaultSpecExtension](\n\t\tresource.NewMetadata(namespace, KernelParamDefaultSpecType, id, resource.VersionUndefined),\n\t\tKernelParamSpecSpec{},\n\t)\n}\n\n// KernelParamDefaultSpecExtension is the typed.Extension for KernelParamDefaultSpec.\ntype KernelParamDefaultSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KernelParamDefaultSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KernelParamDefaultSpecType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns:     []meta.PrintColumn{},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KernelParamSpecSpec](KernelParamSpecType, &KernelParamSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = protobuf.RegisterDynamic[KernelParamDefaultSpecSpec](KernelParamDefaultSpecType, &KernelParamDefaultSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/kernel_params_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KernelParamStatusType is type of KernelParam resource.\nconst KernelParamStatusType = resource.Type(\"KernelParamStatuses.runtime.talos.dev\")\n\n// KernelParamStatus resource holds defined sysctl flags status.\ntype KernelParamStatus = typed.Resource[KernelParamStatusSpec, KernelParamStatusExtension]\n\n// KernelParamStatusSpec describes status of the defined sysctls.\n//\n//gotagsrewrite:gen\ntype KernelParamStatusSpec struct {\n\tCurrent     string `yaml:\"current\" protobuf:\"1\"`\n\tDefault     string `yaml:\"default\" protobuf:\"2\"`\n\tUnsupported bool   `yaml:\"unsupported\" protobuf:\"3\"`\n}\n\n// NewKernelParamStatus initializes a KernelParamStatus resource.\nfunc NewKernelParamStatus(namespace resource.Namespace, id resource.ID) *KernelParamStatus {\n\treturn typed.NewResource[KernelParamStatusSpec, KernelParamStatusExtension](\n\t\tresource.NewMetadata(namespace, KernelParamStatusType, id, resource.VersionUndefined),\n\t\tKernelParamStatusSpec{},\n\t)\n}\n\n// KernelParamStatusExtension is auxiliary resource data for KernelParamStatus.\ntype KernelParamStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KernelParamStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KernelParamStatusType,\n\t\tAliases:          []resource.Type{\"sysctls\", \"kernelparameters\", \"kernelparams\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Current\",\n\t\t\t\tJSONPath: `{.current}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Default\",\n\t\t\t\tJSONPath: `{.default}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Unsupported\",\n\t\t\t\tJSONPath: `{.unsupported}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KernelParamStatusSpec](KernelParamStatusType, &KernelParamStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/kmsg_log_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KmsgLogConfigType is type of KmsgLogConfig resource.\nconst KmsgLogConfigType = resource.Type(\"KmsgLogConfigs.runtime.talos.dev\")\n\n// KmsgLogConfig resource holds configuration for kernel message log streaming.\ntype KmsgLogConfig = typed.Resource[KmsgLogConfigSpec, KmsgLogConfigExtension]\n\n// KmsgLogConfigID is a resource ID for KmsgLogConfig.\nconst KmsgLogConfigID resource.ID = \"kmsg-log\"\n\n// KmsgLogConfigSpec describes configuration for kmsg log streaming.\n//\n//gotagsrewrite:gen\ntype KmsgLogConfigSpec struct {\n\tDestinations []*url.URL `yaml:\"destinations\" protobuf:\"1\"`\n}\n\n// NewKmsgLogConfig initializes a KmsgLogConfig resource.\nfunc NewKmsgLogConfig() *KmsgLogConfig {\n\treturn typed.NewResource[KmsgLogConfigSpec, KmsgLogConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, KmsgLogConfigType, KmsgLogConfigID, resource.VersionUndefined),\n\t\tKmsgLogConfigSpec{},\n\t)\n}\n\n// KmsgLogConfigExtension is auxiliary resource data for KmsgLogConfig.\ntype KmsgLogConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KmsgLogConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KmsgLogConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KmsgLogConfigSpec](KmsgLogConfigType, &KmsgLogConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/loaded_kernel_module.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// LoadedKernelModuleType is type of LoadedKernelModule resource.\nconst LoadedKernelModuleType = resource.Type(\"LoadedKernelModules.runtime.talos.dev\")\n\n// LoadedKernelModule resource holds information about Linux kernel module to load.\ntype LoadedKernelModule = typed.Resource[LoadedKernelModuleSpec, LoadedKernelModuleExtension]\n\n// LoadedKernelModuleSpec describes Linux kernel module to load.\n//\n//gotagsrewrite:gen\ntype LoadedKernelModuleSpec struct {\n\tSize           int      `yaml:\"size\" protobuf:\"1\"`\n\tReferenceCount int      `yaml:\"referenceCount\" protobuf:\"2\"`\n\tDependencies   []string `yaml:\"dependencies,omitempty\" protobuf:\"3\"`\n\tState          string   `yaml:\"state\" protobuf:\"4\"`\n\tAddress        string   `yaml:\"address\" protobuf:\"5\"`\n}\n\n// NewLoadedKernelModule initializes a LoadedKernelModule resource.\nfunc NewLoadedKernelModule(namespace resource.Namespace, id resource.ID) *LoadedKernelModule {\n\treturn typed.NewResource[LoadedKernelModuleSpec, LoadedKernelModuleExtension](\n\t\tresource.NewMetadata(namespace, LoadedKernelModuleType, id, resource.VersionUndefined),\n\t\tLoadedKernelModuleSpec{},\n\t)\n}\n\n// LoadedKernelModuleExtension is auxiliary resource data for LoadedKernelModule.\ntype LoadedKernelModuleExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (LoadedKernelModuleExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             LoadedKernelModuleType,\n\t\tAliases:          []resource.Type{\"module\", \"modules\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"State\",\n\t\t\t\tJSONPath: \"{.state}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[LoadedKernelModuleSpec](LoadedKernelModuleType, &LoadedKernelModule{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/machine_reset_signal.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MachineResetSignalType is type of MachineResetSignal resource.\nconst MachineResetSignalType = resource.Type(\"MachineResetSignals.runtime.talos.dev\")\n\n// MachineResetSignalID is singleton MachineResetSignal resource ID.\nconst MachineResetSignalID = resource.ID(\"machine\")\n\n// MachineResetSignal resource is created to signal that the machine is going to be reset soon.\n//\n// This resource is created when all remaining actions are local to the node, and network communication is not required.\ntype MachineResetSignal = typed.Resource[MachineResetSignalSpec, MachineResetSignalExtension]\n\n// MachineResetSignalSpec describes the spec of MachineResetSignal.\n//\n//gotagsrewrite:gen\ntype MachineResetSignalSpec struct{}\n\n// NewMachineResetSignal initializes a MachineResetSignal resource.\nfunc NewMachineResetSignal() *MachineResetSignal {\n\treturn typed.NewResource[MachineResetSignalSpec, MachineResetSignalExtension](\n\t\tresource.NewMetadata(NamespaceName, MachineResetSignalType, MachineResetSignalID, resource.VersionUndefined),\n\t\tMachineResetSignalSpec{},\n\t)\n}\n\n// MachineResetSignalExtension is auxiliary resource data for MachineResetSignal.\ntype MachineResetSignalExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MachineResetSignalExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MachineResetSignalType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MachineResetSignalSpec](MachineResetSignalType, &MachineResetSignal{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/machine_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MachineStatusType is type of MachineStatus resource.\nconst MachineStatusType = resource.Type(\"MachineStatuses.runtime.talos.dev\")\n\n// MachineStatusID is singleton MachineStatus resource ID.\nconst MachineStatusID = resource.ID(\"machine\")\n\n// MachineStatus resource holds information about aggregated machine status.\ntype MachineStatus = typed.Resource[MachineStatusSpec, MachineStatusExtension]\n\n// MachineStatusSpec describes status of the defined sysctls.\n//\n//gotagsrewrite:gen\ntype MachineStatusSpec struct {\n\tStage  MachineStage        `yaml:\"stage\" protobuf:\"1\"`\n\tStatus MachineStatusStatus `yaml:\"status\" protobuf:\"2\"`\n}\n\n// MachineStatusStatus describes machine current status at the stage.\n//\n//gotagsrewrite:gen\ntype MachineStatusStatus struct {\n\tReady           bool             `yaml:\"ready\" protobuf:\"1\"`\n\tUnmetConditions []UnmetCondition `yaml:\"unmetConditions\" protobuf:\"2\"`\n}\n\n// UnmetCondition is a failure which prevents machine from being ready at the stage.\n//\n//gotagsrewrite:gen\ntype UnmetCondition struct {\n\tName   string `yaml:\"name\" protobuf:\"1\"`\n\tReason string `yaml:\"reason\" protobuf:\"2\"`\n}\n\n// NewMachineStatus initializes a MachineStatus resource.\nfunc NewMachineStatus() *MachineStatus {\n\treturn typed.NewResource[MachineStatusSpec, MachineStatusExtension](\n\t\tresource.NewMetadata(NamespaceName, MachineStatusType, MachineStatusID, resource.VersionUndefined),\n\t\tMachineStatusSpec{},\n\t)\n}\n\n// MachineStatusExtension is auxiliary resource data for MachineStatus.\ntype MachineStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MachineStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MachineStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Stage\",\n\t\t\t\tJSONPath: `{.stage}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Ready\",\n\t\t\t\tJSONPath: `{.status.ready}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MachineStatusSpec](MachineStatusType, &MachineStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/machinestage.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n//go:generate go tool github.com/dmarkham/enumer -type=MachineStage -linecomment -text\n\n// MachineStage describes the stage of the machine boot/run process.\ntype MachineStage int\n\n// Machine stages.\n//\n//structprotogen:gen_enum\nconst (\n\tMachineStageUnknown      MachineStage = iota // unknown\n\tMachineStageBooting                          // booting\n\tMachineStageInstalling                       // installing\n\tMachineStageMaintenance                      // maintenance\n\tMachineStageRunning                          // running\n\tMachineStageRebooting                        // rebooting\n\tMachineStageShuttingDown                     // shutting down\n\tMachineStageResetting                        // resetting\n\tMachineStageUpgrading                        // upgrading\n)\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/machinestage_enumer.go",
    "content": "// Code generated by \"enumer -type=MachineStage -linecomment -text\"; DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _MachineStageName = \"unknownbootinginstallingmaintenancerunningrebootingshutting downresettingupgrading\"\n\nvar _MachineStageIndex = [...]uint8{0, 7, 14, 24, 35, 42, 51, 64, 73, 82}\n\nconst _MachineStageLowerName = \"unknownbootinginstallingmaintenancerunningrebootingshutting downresettingupgrading\"\n\nfunc (i MachineStage) String() string {\n\tif i < 0 || i >= MachineStage(len(_MachineStageIndex)-1) {\n\t\treturn fmt.Sprintf(\"MachineStage(%d)\", i)\n\t}\n\treturn _MachineStageName[_MachineStageIndex[i]:_MachineStageIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _MachineStageNoOp() {\n\tvar x [1]struct{}\n\t_ = x[MachineStageUnknown-(0)]\n\t_ = x[MachineStageBooting-(1)]\n\t_ = x[MachineStageInstalling-(2)]\n\t_ = x[MachineStageMaintenance-(3)]\n\t_ = x[MachineStageRunning-(4)]\n\t_ = x[MachineStageRebooting-(5)]\n\t_ = x[MachineStageShuttingDown-(6)]\n\t_ = x[MachineStageResetting-(7)]\n\t_ = x[MachineStageUpgrading-(8)]\n}\n\nvar _MachineStageValues = []MachineStage{MachineStageUnknown, MachineStageBooting, MachineStageInstalling, MachineStageMaintenance, MachineStageRunning, MachineStageRebooting, MachineStageShuttingDown, MachineStageResetting, MachineStageUpgrading}\n\nvar _MachineStageNameToValueMap = map[string]MachineStage{\n\t_MachineStageName[0:7]:        MachineStageUnknown,\n\t_MachineStageLowerName[0:7]:   MachineStageUnknown,\n\t_MachineStageName[7:14]:       MachineStageBooting,\n\t_MachineStageLowerName[7:14]:  MachineStageBooting,\n\t_MachineStageName[14:24]:      MachineStageInstalling,\n\t_MachineStageLowerName[14:24]: MachineStageInstalling,\n\t_MachineStageName[24:35]:      MachineStageMaintenance,\n\t_MachineStageLowerName[24:35]: MachineStageMaintenance,\n\t_MachineStageName[35:42]:      MachineStageRunning,\n\t_MachineStageLowerName[35:42]: MachineStageRunning,\n\t_MachineStageName[42:51]:      MachineStageRebooting,\n\t_MachineStageLowerName[42:51]: MachineStageRebooting,\n\t_MachineStageName[51:64]:      MachineStageShuttingDown,\n\t_MachineStageLowerName[51:64]: MachineStageShuttingDown,\n\t_MachineStageName[64:73]:      MachineStageResetting,\n\t_MachineStageLowerName[64:73]: MachineStageResetting,\n\t_MachineStageName[73:82]:      MachineStageUpgrading,\n\t_MachineStageLowerName[73:82]: MachineStageUpgrading,\n}\n\nvar _MachineStageNames = []string{\n\t_MachineStageName[0:7],\n\t_MachineStageName[7:14],\n\t_MachineStageName[14:24],\n\t_MachineStageName[24:35],\n\t_MachineStageName[35:42],\n\t_MachineStageName[42:51],\n\t_MachineStageName[51:64],\n\t_MachineStageName[64:73],\n\t_MachineStageName[73:82],\n}\n\n// MachineStageString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc MachineStageString(s string) (MachineStage, error) {\n\tif val, ok := _MachineStageNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _MachineStageNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to MachineStage values\", s)\n}\n\n// MachineStageValues returns all values of the enum\nfunc MachineStageValues() []MachineStage {\n\treturn _MachineStageValues\n}\n\n// MachineStageStrings returns a slice of all String values of the enum\nfunc MachineStageStrings() []string {\n\tstrs := make([]string, len(_MachineStageNames))\n\tcopy(strs, _MachineStageNames)\n\treturn strs\n}\n\n// IsAMachineStage returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i MachineStage) IsAMachineStage() bool {\n\tfor _, v := range _MachineStageValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for MachineStage\nfunc (i MachineStage) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for MachineStage\nfunc (i *MachineStage) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = MachineStageString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/machinestage_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestMachineStageMatchesProto(t *testing.T) {\n\tassert := assert.New(t)\n\n\tassert.EqualValues(runtime.MachineStageUnknown, machine.MachineStatusEvent_UNKNOWN)\n\tassert.EqualValues(runtime.MachineStageBooting, machine.MachineStatusEvent_BOOTING)\n\tassert.EqualValues(runtime.MachineStageInstalling, machine.MachineStatusEvent_INSTALLING)\n\tassert.EqualValues(runtime.MachineStageMaintenance, machine.MachineStatusEvent_MAINTENANCE)\n\tassert.EqualValues(runtime.MachineStageRunning, machine.MachineStatusEvent_RUNNING)\n\tassert.EqualValues(runtime.MachineStageRebooting, machine.MachineStatusEvent_REBOOTING)\n\tassert.EqualValues(runtime.MachineStageShuttingDown, machine.MachineStatusEvent_SHUTTING_DOWN)\n\tassert.EqualValues(runtime.MachineStageResetting, machine.MachineStatusEvent_RESETTING)\n\tassert.EqualValues(runtime.MachineStageUpgrading, machine.MachineStatusEvent_UPGRADING)\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/maintenance_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MaintenanceServiceConfigType is type of MaintenanceConfig resource.\nconst MaintenanceServiceConfigType = resource.Type(\"MaintenanceServiceConfigs.runtime.talos.dev\")\n\n// MaintenanceServiceConfig resource holds configuration for maintenance service API.\ntype MaintenanceServiceConfig = typed.Resource[MaintenanceServiceConfigSpec, MaintenanceServiceConfigExtension]\n\n// MaintenanceServiceConfigID is a resource ID for MaintenanceConfig.\nconst MaintenanceServiceConfigID resource.ID = \"maintenance\"\n\n// MaintenanceServiceConfigSpec describes configuration for maintenance service API.\n//\n//gotagsrewrite:gen\ntype MaintenanceServiceConfigSpec struct {\n\tListenAddress      string       `yaml:\"listenAddress\" protobuf:\"1\"`\n\tReachableAddresses []netip.Addr `yaml:\"reachableAddresses\" protobuf:\"2\"`\n}\n\n// NewMaintenanceServiceConfig initializes a MaintenanceConfig resource.\nfunc NewMaintenanceServiceConfig() *MaintenanceServiceConfig {\n\treturn typed.NewResource[MaintenanceServiceConfigSpec, MaintenanceServiceConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, MaintenanceServiceConfigType, MaintenanceServiceConfigID, resource.VersionUndefined),\n\t\tMaintenanceServiceConfigSpec{},\n\t)\n}\n\n// MaintenanceServiceConfigExtension is auxiliary resource data for MaintenanceConfig.\ntype MaintenanceServiceConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MaintenanceServiceConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MaintenanceServiceConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MaintenanceServiceConfigSpec](MaintenanceServiceConfigType, &MaintenanceServiceConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/maintenance_request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MaintenanceServiceRequestType is type of MaintenanceServiceConfig resource.\nconst MaintenanceServiceRequestType = resource.Type(\"MaintenanceServiceRequests.runtime.talos.dev\")\n\n// MaintenanceServiceRequest resource indicates that the maintenance service should run.\ntype MaintenanceServiceRequest = typed.Resource[MaintenanceServiceRequestSpec, MaintenanceServiceRequestExtension]\n\n// MaintenanceServiceRequestID is a resource ID for MaintenanceConfig.\nconst MaintenanceServiceRequestID resource.ID = \"maintenance\"\n\n// MaintenanceServiceRequestSpec indicates that maintenance service API should be started.\n//\n//gotagsrewrite:gen\ntype MaintenanceServiceRequestSpec struct{}\n\n// NewMaintenanceServiceRequest initializes a MaintenanceConfig resource.\nfunc NewMaintenanceServiceRequest() *MaintenanceServiceRequest {\n\treturn typed.NewResource[MaintenanceServiceRequestSpec, MaintenanceServiceRequestExtension](\n\t\tresource.NewMetadata(NamespaceName, MaintenanceServiceRequestType, MaintenanceServiceRequestID, resource.VersionUndefined),\n\t\tMaintenanceServiceRequestSpec{},\n\t)\n}\n\n// MaintenanceServiceRequestExtension is auxiliary resource data for MaintenanceConfig.\ntype MaintenanceServiceRequestExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MaintenanceServiceRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MaintenanceServiceRequestType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MaintenanceServiceRequestSpec](MaintenanceServiceRequestType, &MaintenanceServiceRequest{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/meta_key.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MetaKeyType is type of MetaKey resource.\nconst MetaKeyType = resource.Type(\"MetaKeys.runtime.talos.dev\")\n\n// MetaKey resource holds value of a key in META partition.\ntype MetaKey = typed.Resource[MetaKeySpec, MetaKeyExtension]\n\n// MetaKeySpec describes status of the defined sysctls.\n//\n//gotagsrewrite:gen\ntype MetaKeySpec struct {\n\tValue string `yaml:\"value\" protobuf:\"1\"`\n}\n\n// NewMetaKey initializes a MetaKey resource.\nfunc NewMetaKey(namespace resource.Namespace, id resource.ID) *MetaKey {\n\treturn typed.NewResource[MetaKeySpec, MetaKeyExtension](\n\t\tresource.NewMetadata(namespace, MetaKeyType, id, resource.VersionUndefined),\n\t\tMetaKeySpec{},\n\t)\n}\n\n// MetaKeyExtension is auxiliary resource data for MetaKey.\ntype MetaKeyExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MetaKeyExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MetaKeyType,\n\t\tAliases:          []resource.Type{\"meta\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Value\",\n\t\t\t\tJSONPath: `{.value}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// MetaKeyTagToID converts a tag to ID for MetaKey resource.\nfunc MetaKeyTagToID(t uint8) resource.ID {\n\treturn fmt.Sprintf(\"0x%02x\", t)\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MetaKeySpec](MetaKeyType, &MetaKey{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/meta_loaded.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MetaLoadedType is type of [MetaLoaded] resource.\nconst MetaLoadedType = resource.Type(\"MetaLoads.runtime.talos.dev\")\n\n// MetaLoaded resource appears when all meta keys are loaded.\ntype MetaLoaded = typed.Resource[MetaLoadedSpec, MetaLoadedExtension]\n\n// MetaLoadedID is the ID of [MetaLoaded] resource.\nconst MetaLoadedID = resource.ID(\"meta-loaded\")\n\n// MetaLoadedSpec is the spec for meta loaded. The Done field is always true when resource exists.\n//\n//gotagsrewrite:gen\ntype MetaLoadedSpec struct {\n\tDone bool `yaml:\"done\" protobuf:\"1\"`\n}\n\n// NewMetaLoaded initializes a [MetaLoaded] resource.\nfunc NewMetaLoaded() *MetaLoaded {\n\treturn typed.NewResource[MetaLoadedSpec, MetaLoadedExtension](\n\t\tresource.NewMetadata(NamespaceName, MetaLoadedType, MetaLoadedID, resource.VersionUndefined),\n\t\tMetaLoadedSpec{},\n\t)\n}\n\n// MetaLoadedExtension is auxiliary resource data for [MetaLoaded].\ntype MetaLoadedExtension struct{}\n\n// ResourceDefinition implements [meta.ResourceDefinitionProvider] interface.\nfunc (MetaLoadedExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MetaLoadedType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Done\",\n\t\t\t\tJSONPath: `{.done}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MetaLoadedSpec](MetaLoadedType, &MetaLoaded{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/mount_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MountStatusType is type of Mount resource.\nconst MountStatusType = resource.Type(\"MountStatuses.runtime.talos.dev\")\n\n// MountStatus resource holds defined sysctl flags status.\ntype MountStatus = typed.Resource[MountStatusSpec, MountStatusExtension]\n\n// MountStatusSpec describes status of the defined sysctls.\n//\n//gotagsrewrite:gen\ntype MountStatusSpec struct {\n\tSource              string   `yaml:\"source\" protobuf:\"1\"`\n\tTarget              string   `yaml:\"target\" protobuf:\"2\"`\n\tFilesystemType      string   `yaml:\"filesystemType\" protobuf:\"3\"`\n\tOptions             []string `yaml:\"options\" protobuf:\"4\"`\n\tEncrypted           bool     `yaml:\"encrypted\" protobuf:\"5\"`\n\tEncryptionProviders []string `yaml:\"encryptionProviders,omitempty\" protobuf:\"6\"`\n}\n\n// NewMountStatus initializes a MountStatus resource.\nfunc NewMountStatus(namespace resource.Namespace, id resource.ID) *MountStatus {\n\treturn typed.NewResource[MountStatusSpec, MountStatusExtension](\n\t\tresource.NewMetadata(namespace, MountStatusType, id, resource.VersionUndefined),\n\t\tMountStatusSpec{},\n\t)\n}\n\n// MountStatusExtension is auxiliary resource data for MountStatus.\ntype MountStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MountStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:                 MountStatusType,\n\t\tAliases:              []resource.Type{\"mounts\"},\n\t\tDefaultNamespace:     NamespaceName,\n\t\tSkipAutomaticAliases: true,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Source\",\n\t\t\t\tJSONPath: `{.source}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Target\",\n\t\t\t\tJSONPath: `{.target}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Filesystem Type\",\n\t\t\t\tJSONPath: `{.filesystemType}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[MountStatusSpec](MountStatusType, &MountStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/oom.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\n// QoSCgroupClass is a quality of service class of cgroup.\ntype QoSCgroupClass int\n\n// QoSCgroupClass constants.\n//\n// Higher value corresponds to a more important cgroup.\nconst (\n\tQoSCgroupClassBesteffort QoSCgroupClass = iota\n\tQoSCgroupClassBurstable\n\tQoSCgroupClassGuaranteed\n\tQoSCgroupClassPodruntime\n\tQoSCgroupClassSystem\n)\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/oom_action.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// OOMActionType is the type of the OOM action record resource.\nconst OOMActionType = resource.Type(\"OOMActions.talos.dev\")\n\n// OOMAction is the OOM action record resource.\ntype OOMAction = typed.Resource[OOMActionSpec, OOMActionExtension]\n\n// OOMActionSpec describes the OOM action record resource properties.\n//\n//gotagsrewrite:gen\ntype OOMActionSpec struct {\n\tTriggerContext string   `yaml:\"triggerContext,omitempty\" protobuf:\"1\"`\n\tScore          float64  `yaml:\"score,omitempty\" protobuf:\"2\"`\n\tProcesses      []string `yaml:\"processes,omitempty\" protobuf:\"3\"`\n}\n\n// NewOOMActionSpec initializes an OOM action log entry resource.\nfunc NewOOMActionSpec(namespace resource.Namespace, id resource.ID) *OOMAction {\n\treturn typed.NewResource[OOMActionSpec, OOMActionExtension](\n\t\tresource.NewMetadata(namespace, OOMActionType, id, resource.VersionUndefined),\n\t\tOOMActionSpec{},\n\t)\n}\n\n// OOMActionExtension provides auxiliary methods for OOMAction.\ntype OOMActionExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (OOMActionExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             OOMActionType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tAliases:          []string{\"oomaction\", \"oomactions\"},\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Time\",\n\t\t\t\tJSONPath: `{.time}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Score\",\n\t\t\t\tJSONPath: `{.score}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[OOMActionSpec](OOMActionType, &OOMAction{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/pcirebind_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/platform_metadata.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// PlatformMetadataType is type of Metadata resource.\nconst PlatformMetadataType = resource.Type(\"PlatformMetadatas.talos.dev\")\n\n// PlatformMetadataID is the ID for Metadata resource platform.\nconst PlatformMetadataID resource.ID = \"platformmetadata\"\n\n// PlatformMetadata resource holds.\ntype PlatformMetadata = typed.Resource[PlatformMetadataSpec, PlatformMetadataExtension]\n\n// PlatformMetadataSpec describes platform metadata properties.\n//\n//gotagsrewrite:gen\ntype PlatformMetadataSpec struct {\n\tPlatform     string            `yaml:\"platform,omitempty\" protobuf:\"1\"`\n\tHostname     string            `yaml:\"hostname,omitempty\" protobuf:\"2\"`\n\tRegion       string            `yaml:\"region,omitempty\" protobuf:\"3\"`\n\tZone         string            `yaml:\"zone,omitempty\" protobuf:\"4\"`\n\tInstanceType string            `yaml:\"instanceType,omitempty\" protobuf:\"5\"`\n\tInstanceID   string            `yaml:\"instanceId,omitempty\" protobuf:\"6\"`\n\tProviderID   string            `yaml:\"providerId,omitempty\" protobuf:\"7\"`\n\tSpot         bool              `yaml:\"spot,omitempty\" protobuf:\"8\"`\n\tInternalDNS  string            `yaml:\"internalDNS,omitempty\" protobuf:\"9\"`\n\tExternalDNS  string            `yaml:\"externalDNS,omitempty\" protobuf:\"10\"`\n\tTags         map[string]string `yaml:\"tags,omitempty\" protobuf:\"11\"`\n}\n\n// NewPlatformMetadataSpec initializes a MetadataSpec resource.\nfunc NewPlatformMetadataSpec(namespace resource.Namespace, _ resource.ID) *PlatformMetadata {\n\treturn typed.NewResource[PlatformMetadataSpec, PlatformMetadataExtension](\n\t\tresource.NewMetadata(namespace, PlatformMetadataType, PlatformMetadataID, resource.VersionUndefined),\n\t\tPlatformMetadataSpec{},\n\t)\n}\n\n// PlatformMetadataExtension provides auxiliary methods for PlatformMetadata.\ntype PlatformMetadataExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (PlatformMetadataExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             PlatformMetadataType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Platform\",\n\t\t\t\tJSONPath: `{.platform}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Type\",\n\t\t\t\tJSONPath: `{.instanceType}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Region\",\n\t\t\t\tJSONPath: `{.region}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Zone\",\n\t\t\t\tJSONPath: `{.zone}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[PlatformMetadataSpec](PlatformMetadataType, &PlatformMetadata{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/runtime.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type APIServiceConfigSpec -type BootedEntrySpec -type DevicesStatusSpec -type DiagnosticSpec -type EnvironmentSpec -type EventSinkConfigSpec -type ExtensionServiceConfigSpec -type ExtensionServiceConfigStatusSpec -type KernelCmdlineSpec -type KernelModuleSpecSpec -type KernelParamSpecSpec -type KernelParamStatusSpec -type KmsgLogConfigSpec -type LoadedKernelModuleSpec -type MaintenanceServiceConfigSpec -type MaintenanceServiceRequestSpec -type MachineResetSignalSpec -type MachineStatusSpec -type MetaKeySpec -type MountStatusSpec -type OOMActionSpec -type PlatformMetadataSpec -type SecurityStateSpec -type MetaLoadedSpec -type SBOMItemSpec -type UniqueMachineTokenSpec -type VersionSpec -type WatchdogTimerConfigSpec -type WatchdogTimerStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName contains configuration resources.\nconst NamespaceName resource.Namespace = v1alpha1.NamespaceName\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/runtime_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&runtime.APIServiceConfig{},\n\t\t&runtime.BootedEntry{},\n\t\t&runtime.DevicesStatus{},\n\t\t&runtime.Diagnostic{},\n\t\t&runtime.EventSinkConfig{},\n\t\t&runtime.ExtensionStatus{},\n\t\t&runtime.KernelCmdline{},\n\t\t&runtime.KernelModuleSpec{},\n\t\t&runtime.KernelParamSpec{},\n\t\t&runtime.KernelParamStatus{},\n\t\t&runtime.KmsgLogConfig{},\n\t\t&runtime.LoadedKernelModule{},\n\t\t&runtime.MachineStatus{},\n\t\t&runtime.MachineResetSignal{},\n\t\t&runtime.MaintenanceServiceConfig{},\n\t\t&runtime.MaintenanceServiceRequest{},\n\t\t&runtime.MetaKey{},\n\t\t&runtime.MetaLoaded{},\n\t\t&runtime.MountStatus{},\n\t\t&runtime.OOMAction{},\n\t\t&runtime.PlatformMetadata{},\n\t\t&runtime.SBOMItem{},\n\t\t&runtime.SecurityState{},\n\t\t&runtime.UniqueMachineToken{},\n\t\t&runtime.WatchdogTimerConfig{},\n\t\t&runtime.WatchdogTimerStatus{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/sbom_item.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SBOMItemType is the type of the SBOM item resource.\nconst SBOMItemType = resource.Type(\"SBOMItems.talos.dev\")\n\n// SBOMItem is the SBOM item resource.\ntype SBOMItem = typed.Resource[SBOMItemSpec, SBOMItemExtension]\n\n// SBOMItemSpec describes the SBOM item resource properties.\n//\n//gotagsrewrite:gen\ntype SBOMItemSpec struct {\n\tName      string   `yaml:\"name\" protobuf:\"1\"`\n\tVersion   string   `yaml:\"version\" protobuf:\"2\"`\n\tLicense   string   `yaml:\"license,omitempty\" protobuf:\"3\"`\n\tCPEs      []string `yaml:\"cpes,omitempty\" protobuf:\"4\"`\n\tPURLs     []string `yaml:\"purls,omitempty\" protobuf:\"5\"`\n\tExtension bool     `yaml:\"extension,omitempty\" protobuf:\"6\"`\n}\n\n// NewSBOMItemSpec initializes a security state resource.\nfunc NewSBOMItemSpec(namespace resource.Namespace, id resource.ID) *SBOMItem {\n\treturn typed.NewResource[SBOMItemSpec, SBOMItemExtension](\n\t\tresource.NewMetadata(namespace, SBOMItemType, id, resource.VersionUndefined),\n\t\tSBOMItemSpec{},\n\t)\n}\n\n// SBOMItemExtension provides auxiliary methods for SBOMItem.\ntype SBOMItemExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (SBOMItemExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SBOMItemType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tAliases:          []string{\"sbom\", \"sboms\"},\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Version\",\n\t\t\t\tJSONPath: `{.version}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"License\",\n\t\t\t\tJSONPath: `{.license}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Extension\",\n\t\t\t\tJSONPath: `{.extension}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SBOMItemSpec](SBOMItemType, &SBOMItem{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/security_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// SecurityStateType is the type of the security state resource.\nconst SecurityStateType = resource.Type(\"SecurityStates.talos.dev\")\n\n// SecurityStateID is the ID of the security state resource.\nconst SecurityStateID = resource.ID(\"securitystate\")\n\n// SecurityState is the security state resource.\ntype SecurityState = typed.Resource[SecurityStateSpec, SecurityStateExtension]\n\n//go:generate go tool github.com/dmarkham/enumer -type FIPSState -type=SELinuxState -linecomment -text\n\n// SELinuxState describes the current SELinux status.\ntype SELinuxState int\n\n// SELinux state.\n//\n//structprotogen:gen_enum\nconst (\n\tSELinuxStateDisabled   SELinuxState = iota // disabled\n\tSELinuxStatePermissive                     // enabled, permissive\n\tSELinuxStateEnforcing                      // enabled, enforcing\n)\n\n// FIPSState describes the current FIPS status.\ntype FIPSState int\n\n// FIPS state.\n//\n//structprotogen:gen_enum\nconst (\n\tFIPSStateDisabled FIPSState = iota // disabled\n\tFIPSStateEnabled                   // enabled\n\tFIPSStateStrict                    // enabled, strict\n)\n\n// SecurityStateSpec describes the security state resource properties.\n//\n//gotagsrewrite:gen\ntype SecurityStateSpec struct {\n\tSecureBoot               bool         `yaml:\"secureBoot\" protobuf:\"1\"`\n\tUKISigningKeyFingerprint string       `yaml:\"ukiSigningKeyFingerprint,omitempty\" protobuf:\"2\"`\n\tPCRSigningKeyFingerprint string       `yaml:\"pcrSigningKeyFingerprint,omitempty\" protobuf:\"3\"`\n\tSELinuxState             SELinuxState `yaml:\"selinuxState,omitempty\" protobuf:\"4\"`\n\tFIPSState                FIPSState    `yaml:\"fipsState,omitempty\" protobuf:\"6\"`\n\tBootedWithUKI            bool         `yaml:\"bootedWithUKI,omitempty\" protobuf:\"5\"`\n\tModuleSignatureEnforced  bool         `yaml:\"moduleSignatureEnforced,omitempty\" protobuf:\"7\"`\n}\n\n// NewSecurityStateSpec initializes a security state resource.\nfunc NewSecurityStateSpec(namespace resource.Namespace) *SecurityState {\n\treturn typed.NewResource[SecurityStateSpec, SecurityStateExtension](\n\t\tresource.NewMetadata(namespace, SecurityStateType, SecurityStateID, resource.VersionUndefined),\n\t\tSecurityStateSpec{},\n\t)\n}\n\n// SecurityStateExtension provides auxiliary methods for SecurityState.\ntype SecurityStateExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (SecurityStateExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             SecurityStateType,\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"SecureBoot\",\n\t\t\t\tJSONPath: `{.secureBoot}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"UKISigningKeyFingerprint\",\n\t\t\t\tJSONPath: `{.ukiSigningKeyFingerprint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"PCRSigningKeyFingerprint\",\n\t\t\t\tJSONPath: `{.pcrSigningKeyFingerprint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"SELinuxState\",\n\t\t\t\tJSONPath: `{.selinuxState}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"ModuleSignatureEnforced\",\n\t\t\t\tJSONPath: `{.moduleSignatureEnforced}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[SecurityStateSpec](SecurityStateType, &SecurityState{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/selinuxstate_enumer.go",
    "content": "// Code generated by \"enumer -type FIPSState -type=SELinuxState -linecomment -text\"; DO NOT EDIT.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _SELinuxStateName = \"disabledenabled, permissiveenabled, enforcing\"\n\nvar _SELinuxStateIndex = [...]uint8{0, 8, 27, 45}\n\nconst _SELinuxStateLowerName = \"disabledenabled, permissiveenabled, enforcing\"\n\nfunc (i SELinuxState) String() string {\n\tif i < 0 || i >= SELinuxState(len(_SELinuxStateIndex)-1) {\n\t\treturn fmt.Sprintf(\"SELinuxState(%d)\", i)\n\t}\n\treturn _SELinuxStateName[_SELinuxStateIndex[i]:_SELinuxStateIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _SELinuxStateNoOp() {\n\tvar x [1]struct{}\n\t_ = x[SELinuxStateDisabled-(0)]\n\t_ = x[SELinuxStatePermissive-(1)]\n\t_ = x[SELinuxStateEnforcing-(2)]\n}\n\nvar _SELinuxStateValues = []SELinuxState{SELinuxStateDisabled, SELinuxStatePermissive, SELinuxStateEnforcing}\n\nvar _SELinuxStateNameToValueMap = map[string]SELinuxState{\n\t_SELinuxStateName[0:8]:        SELinuxStateDisabled,\n\t_SELinuxStateLowerName[0:8]:   SELinuxStateDisabled,\n\t_SELinuxStateName[8:27]:       SELinuxStatePermissive,\n\t_SELinuxStateLowerName[8:27]:  SELinuxStatePermissive,\n\t_SELinuxStateName[27:45]:      SELinuxStateEnforcing,\n\t_SELinuxStateLowerName[27:45]: SELinuxStateEnforcing,\n}\n\nvar _SELinuxStateNames = []string{\n\t_SELinuxStateName[0:8],\n\t_SELinuxStateName[8:27],\n\t_SELinuxStateName[27:45],\n}\n\n// SELinuxStateString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc SELinuxStateString(s string) (SELinuxState, error) {\n\tif val, ok := _SELinuxStateNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _SELinuxStateNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to SELinuxState values\", s)\n}\n\n// SELinuxStateValues returns all values of the enum\nfunc SELinuxStateValues() []SELinuxState {\n\treturn _SELinuxStateValues\n}\n\n// SELinuxStateStrings returns a slice of all String values of the enum\nfunc SELinuxStateStrings() []string {\n\tstrs := make([]string, len(_SELinuxStateNames))\n\tcopy(strs, _SELinuxStateNames)\n\treturn strs\n}\n\n// IsASELinuxState returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i SELinuxState) IsASELinuxState() bool {\n\tfor _, v := range _SELinuxStateValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for SELinuxState\nfunc (i SELinuxState) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for SELinuxState\nfunc (i *SELinuxState) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = SELinuxStateString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/unique_machine_token.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\nconst (\n\t// UniqueMachineTokenType is type of [UniqueMachineToken] resource.\n\tUniqueMachineTokenType = resource.Type(\"UniqueMachineTokens.runtime.talos.dev\")\n\n\t// UniqueMachineTokenID is the ID of [UniqueMachineToken] resource.\n\tUniqueMachineTokenID = resource.ID(\"unique-machine-token\")\n)\n\n// UniqueMachineToken resource appears when all meta keys are loaded.\ntype UniqueMachineToken = typed.Resource[UniqueMachineTokenSpec, UniqueMachineTokenExtension]\n\n// UniqueMachineTokenSpec is the spec for the machine unique token. Token can be empty if machine wasn't assigned any.\n//\n//gotagsrewrite:gen\ntype UniqueMachineTokenSpec struct {\n\tToken string `yaml:\"token\" protobuf:\"1\"`\n}\n\n// NewUniqueMachineToken initializes a [UniqueMachineToken] resource.\nfunc NewUniqueMachineToken() *UniqueMachineToken {\n\treturn typed.NewResource[UniqueMachineTokenSpec, UniqueMachineTokenExtension](\n\t\tresource.NewMetadata(NamespaceName, UniqueMachineTokenType, UniqueMachineTokenID, resource.VersionUndefined),\n\t\tUniqueMachineTokenSpec{},\n\t)\n}\n\n// UniqueMachineTokenExtension is auxiliary resource data for [UniqueMachineToken].\ntype UniqueMachineTokenExtension struct{}\n\n// ResourceDefinition implements [meta.ResourceDefinitionProvider] interface.\nfunc (UniqueMachineTokenExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             UniqueMachineTokenType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Token\",\n\t\t\t\tJSONPath: `{.token}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[UniqueMachineTokenSpec](UniqueMachineTokenType, &UniqueMachineToken{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// VersionType is type of VersionStatus resource.\nconst VersionType = resource.Type(\"Versions.runtime.talos.dev\")\n\n// Version resource holds version of Talos.\ntype Version = typed.Resource[VersionSpec, VersionExtension]\n\n// VersionSpec describes version of Talos.\ntype VersionSpec struct {\n\tVersion string `yaml:\"version\" protobuf:\"1\"`\n}\n\n// NewVersion initializes a VersionStatus resource.\nfunc NewVersion() *Version {\n\treturn typed.NewResource[VersionSpec, VersionExtension](\n\t\tresource.NewMetadata(NamespaceName, VersionType, \"version\", resource.VersionUndefined),\n\t\tVersionSpec{},\n\t)\n}\n\n// VersionExtension is auxiliary resource data for VersionStatus.\ntype VersionExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (VersionExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             VersionType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Version\",\n\t\t\t\tJSONPath: `{.version}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(VersionType, &Version{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/watchdog_timer_config.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// WatchdogTimerConfigType is type of WatchdogTimerConfig resource.\nconst WatchdogTimerConfigType = resource.Type(\"WatchdogTimerConfigs.runtime.talos.dev\")\n\n// WatchdogTimerConfig resource holds configuration for watchdog timer.\ntype WatchdogTimerConfig = typed.Resource[WatchdogTimerConfigSpec, WatchdogTimerConfigExtension]\n\n// WatchdogTimerConfigID is a resource ID for WatchdogTimerConfig.\nconst WatchdogTimerConfigID resource.ID = \"timer\"\n\n// WatchdogTimerConfigSpec describes configuration of watchdog timer.\n//\n//gotagsrewrite:gen\ntype WatchdogTimerConfigSpec struct {\n\tDevice  string        `yaml:\"device\" protobuf:\"1\"`\n\tTimeout time.Duration `yaml:\"timeout\" protobuf:\"2\"`\n}\n\n// NewWatchdogTimerConfig initializes a WatchdogTimerConfig resource.\nfunc NewWatchdogTimerConfig() *WatchdogTimerConfig {\n\treturn typed.NewResource[WatchdogTimerConfigSpec, WatchdogTimerConfigExtension](\n\t\tresource.NewMetadata(NamespaceName, WatchdogTimerConfigType, WatchdogTimerConfigID, resource.VersionUndefined),\n\t\tWatchdogTimerConfigSpec{},\n\t)\n}\n\n// WatchdogTimerConfigExtension is auxiliary resource data for WatchdogTimerConfig.\ntype WatchdogTimerConfigExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (WatchdogTimerConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             WatchdogTimerConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Device\",\n\t\t\t\tJSONPath: `{.device}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Timeout\",\n\t\t\t\tJSONPath: `{.timeout}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[WatchdogTimerConfigSpec](WatchdogTimerConfigType, &WatchdogTimerConfig{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/runtime/watchdog_timer_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage runtime\n\nimport (\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// WatchdogTimerStatusType is type of WatchdogTimerStatus resource.\nconst WatchdogTimerStatusType = resource.Type(\"WatchdogTimerStatuses.runtime.talos.dev\")\n\n// WatchdogTimerStatus resource holds status of watchdog timer.\ntype WatchdogTimerStatus = typed.Resource[WatchdogTimerStatusSpec, WatchdogTimerStatusExtension]\n\n// WatchdogTimerStatusSpec describes configuration of watchdog timer.\n//\n//gotagsrewrite:gen\ntype WatchdogTimerStatusSpec struct {\n\tDevice       string        `yaml:\"device\" protobuf:\"1\"`\n\tTimeout      time.Duration `yaml:\"timeout\" protobuf:\"2\"`\n\tFeedInterval time.Duration `yaml:\"feedInterval\" protobuf:\"3\"`\n}\n\n// NewWatchdogTimerStatus initializes a WatchdogTimerStatus resource.\nfunc NewWatchdogTimerStatus(id string) *WatchdogTimerStatus {\n\treturn typed.NewResource[WatchdogTimerStatusSpec, WatchdogTimerStatusExtension](\n\t\tresource.NewMetadata(NamespaceName, WatchdogTimerStatusType, id, resource.VersionUndefined),\n\t\tWatchdogTimerStatusSpec{},\n\t)\n}\n\n// WatchdogTimerStatusExtension is auxiliary resource data for WatchdogTimerStatus.\ntype WatchdogTimerStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (WatchdogTimerStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             WatchdogTimerStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Device\",\n\t\t\t\tJSONPath: `{.device}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Timeout\",\n\t\t\t\tJSONPath: `{.timeout}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[WatchdogTimerStatusSpec](WatchdogTimerStatusType, &WatchdogTimerStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/api.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// APIType is type of API resource.\nconst APIType = resource.Type(\"ApiCertificates.secrets.talos.dev\")\n\n// APIID is a resource ID of singleton instance.\nconst APIID = resource.ID(\"api\")\n\n// API contains apid generated secrets.\ntype API = typed.Resource[APICertsSpec, APIExtension]\n\n// APICertsSpec describes etcd certs secrets.\n//\n//gotagsrewrite:gen\ntype APICertsSpec struct {\n\tAcceptedCAs []*x509.PEMEncodedCertificate     `yaml:\"acceptedCAs\" protobuf:\"4\"`\n\tClient      *x509.PEMEncodedCertificateAndKey `yaml:\"client\" protobuf:\"2\"`\n\tServer      *x509.PEMEncodedCertificateAndKey `yaml:\"server\" protobuf:\"3\"`\n\n\t// Skip verifying client certificate, to be used only with the maintenance mode operations.\n\tSkipVerifyingClientCert bool `yaml:\"skipVerifyingClientCert\" protobuf:\"5\"`\n}\n\n// NewAPI initializes an API resource.\nfunc NewAPI() *API {\n\treturn typed.NewResource[APICertsSpec, APIExtension](\n\t\tresource.NewMetadata(NamespaceName, APIType, APIID, resource.VersionUndefined),\n\t\tAPICertsSpec{},\n\t)\n}\n\n// APIExtension provides auxiliary methods for API.\ntype APIExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (APIExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             APIType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\tif err := protobuf.RegisterDynamic[APICertsSpec](APIType, &API{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/api_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestAPIProtobufMarshal(t *testing.T) {\n\tr := secrets.NewAPI()\n\tr.TypedSpec().AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t{\n\t\t\tCrt: []byte(\"foo\"),\n\t\t},\n\t}\n\tr.TypedSpec().Client = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: []byte(\"bar\"),\n\t\tKey: []byte(\"baz\"),\n\t}\n\tr.TypedSpec().Server = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: []byte(\"car\"),\n\t\tKey: []byte(\"caz\"),\n\t}\n\n\tprotoR, err := protobuf.FromResource(r)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := protoR.Marshal()\n\trequire.NoError(t, err)\n\n\tprotoR, err = protobuf.Unmarshal(marshaled)\n\trequire.NoError(t, err)\n\n\tr2, err := protobuf.UnmarshalResource(protoR)\n\trequire.NoError(t, err)\n\n\trequire.True(t, resource.Equal(r, r2))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/cert_sans.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"net\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// CertSANType is type of CertSAN resource.\nconst CertSANType = resource.Type(\"CertSANs.secrets.talos.dev\")\n\n// CertSANAPIID is a resource ID of singleton instance for the Talos API.\nconst CertSANAPIID = resource.ID(\"api\")\n\n// CertSANMaintenanceID is a resource ID of singleton instance for the Talos Maintenance API.\nconst CertSANMaintenanceID = resource.ID(\"maintenance\")\n\n// CertSANKubernetesID is a resource ID of singleton instance for the Kubernetes API Server.\nconst CertSANKubernetesID = resource.ID(\"k8s\")\n\n// CertSAN contains certficiate subject alternative names.\ntype CertSAN = typed.Resource[CertSANSpec, CertSANExtension]\n\n// CertSANSpec describes fields of the cert SANs.\n//\n//gotagsrewrite:gen\ntype CertSANSpec struct {\n\tIPs      []netip.Addr `yaml:\"ips\" protobuf:\"1\"`\n\tDNSNames []string     `yaml:\"dnsNames\" protobuf:\"2\"`\n\tFQDN     string       `yaml:\"fqdn\" protobuf:\"3\"`\n}\n\n// NewCertSAN initializes a Etc resource.\nfunc NewCertSAN(namespace resource.Namespace, id resource.ID) *CertSAN {\n\treturn typed.NewResource[CertSANSpec, CertSANExtension](\n\t\tresource.NewMetadata(namespace, CertSANType, id, resource.VersionUndefined),\n\t\tCertSANSpec{},\n\t)\n}\n\n// CertSANExtension is a resource data of CertSAN.\ntype CertSANExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (CertSANExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             CertSANType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\n// Reset the list of SANs.\nfunc (spec *CertSANSpec) Reset() {\n\tspec.DNSNames = nil\n\tspec.IPs = nil\n\tspec.FQDN = \"\"\n}\n\n// Append list of SANs splitting into IPs/DNS names.\nfunc (spec *CertSANSpec) Append(sans ...string) {\n\tfor _, san := range sans {\n\t\tif ip, err := netip.ParseAddr(san); err == nil {\n\t\t\tspec.AppendIPs(ip)\n\t\t} else {\n\t\t\tspec.AppendDNSNames(san)\n\t\t}\n\t}\n}\n\n// AppendIPs skipping duplicates.\nfunc (spec *CertSANSpec) AppendIPs(ips ...netip.Addr) {\n\tfor _, ip := range ips {\n\t\tfound := slices.Contains(spec.IPs, ip)\n\n\t\tif !found {\n\t\t\tspec.IPs = append(spec.IPs, ip)\n\t\t}\n\t}\n}\n\n// AppendDNSNames skipping duplicates.\nfunc (spec *CertSANSpec) AppendDNSNames(dnsNames ...string) {\n\tfor _, dnsName := range dnsNames {\n\t\t// remove trailing dot from the DNS name, as it shouldn't be stored in the cert SANs\n\t\tdnsName = strings.TrimRight(dnsName, \".\")\n\n\t\tfound := slices.Contains(spec.DNSNames, dnsName)\n\n\t\tif !found && dnsName != \"\" {\n\t\t\tspec.DNSNames = append(spec.DNSNames, dnsName)\n\t\t}\n\t}\n}\n\n// StdIPs returns a list of converted std.IPs.\nfunc (spec *CertSANSpec) StdIPs() []net.IP {\n\treturn xslices.Map(spec.IPs, func(ip netip.Addr) net.IP { return ip.AsSlice() })\n}\n\n// Sort the CertSANs.\nfunc (spec *CertSANSpec) Sort() {\n\tslices.Sort(spec.DNSNames)\n\tslices.SortFunc(spec.IPs, func(a, b netip.Addr) int { return a.Compare(b) })\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[CertSANSpec](CertSANType, &CertSAN{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/condition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n)\n\n// APIReadyCondition implements condition which waits for the API certs to be ready.\ntype APIReadyCondition struct {\n\tstate state.State\n}\n\n// NewAPIReadyCondition builds a coondition which waits for the API certs to be ready.\nfunc NewAPIReadyCondition(state state.State) *APIReadyCondition {\n\treturn &APIReadyCondition{\n\t\tstate: state,\n\t}\n}\n\nfunc (condition *APIReadyCondition) String() string {\n\treturn \"api certificates\"\n}\n\n// Wait implements condition interface.\nfunc (condition *APIReadyCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(NamespaceName, APIType, APIID, resource.VersionUndefined),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\tif resource.IsTombstone(r) {\n\t\t\t\treturn false, nil\n\t\t\t}\n\n\t\t\treturn true, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type EncryptionSaltSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage secrets\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\n\t\"github.com/siderolabs/crypto/x509\"\n)\n\n// DeepCopy generates a deep copy of APICertsSpec.\nfunc (o APICertsSpec) DeepCopy() APICertsSpec {\n\tvar cp APICertsSpec = o\n\tif o.AcceptedCAs != nil {\n\t\tcp.AcceptedCAs = make([]*x509.PEMEncodedCertificate, len(o.AcceptedCAs))\n\t\tcopy(cp.AcceptedCAs, o.AcceptedCAs)\n\t\tfor i2 := range o.AcceptedCAs {\n\t\t\tif o.AcceptedCAs[i2] != nil {\n\t\t\t\tcp.AcceptedCAs[i2] = o.AcceptedCAs[i2].DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif o.Client != nil {\n\t\tcp.Client = o.Client.DeepCopy()\n\t}\n\tif o.Server != nil {\n\t\tcp.Server = o.Server.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of CertSANSpec.\nfunc (o CertSANSpec) DeepCopy() CertSANSpec {\n\tvar cp CertSANSpec = o\n\tif o.IPs != nil {\n\t\tcp.IPs = make([]netip.Addr, len(o.IPs))\n\t\tcopy(cp.IPs, o.IPs)\n\t}\n\tif o.DNSNames != nil {\n\t\tcp.DNSNames = make([]string, len(o.DNSNames))\n\t\tcopy(cp.DNSNames, o.DNSNames)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EtcdCertsSpec.\nfunc (o EtcdCertsSpec) DeepCopy() EtcdCertsSpec {\n\tvar cp EtcdCertsSpec = o\n\tif o.Etcd != nil {\n\t\tcp.Etcd = o.Etcd.DeepCopy()\n\t}\n\tif o.EtcdPeer != nil {\n\t\tcp.EtcdPeer = o.EtcdPeer.DeepCopy()\n\t}\n\tif o.EtcdAdmin != nil {\n\t\tcp.EtcdAdmin = o.EtcdAdmin.DeepCopy()\n\t}\n\tif o.EtcdAPIServer != nil {\n\t\tcp.EtcdAPIServer = o.EtcdAPIServer.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EtcdRootSpec.\nfunc (o EtcdRootSpec) DeepCopy() EtcdRootSpec {\n\tvar cp EtcdRootSpec = o\n\tif o.EtcdCA != nil {\n\t\tcp.EtcdCA = o.EtcdCA.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of EncryptionSaltSpec.\nfunc (o EncryptionSaltSpec) DeepCopy() EncryptionSaltSpec {\n\tvar cp EncryptionSaltSpec = o\n\tif o.DiskSalt != nil {\n\t\tcp.DiskSalt = make([]byte, len(o.DiskSalt))\n\t\tcopy(cp.DiskSalt, o.DiskSalt)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubeletSpec.\nfunc (o KubeletSpec) DeepCopy() KubeletSpec {\n\tvar cp KubeletSpec = o\n\tif o.Endpoint != nil {\n\t\tcp.Endpoint = new(url.URL)\n\t\t*cp.Endpoint = *o.Endpoint\n\t\tif o.Endpoint.User != nil {\n\t\t\tcp.Endpoint.User = new(url.Userinfo)\n\t\t\t*cp.Endpoint.User = *o.Endpoint.User\n\t\t}\n\t}\n\tif o.AcceptedCAs != nil {\n\t\tcp.AcceptedCAs = make([]*x509.PEMEncodedCertificate, len(o.AcceptedCAs))\n\t\tcopy(cp.AcceptedCAs, o.AcceptedCAs)\n\t\tfor i2 := range o.AcceptedCAs {\n\t\t\tif o.AcceptedCAs[i2] != nil {\n\t\t\t\tcp.AcceptedCAs[i2] = o.AcceptedCAs[i2].DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubernetesCertsSpec.\nfunc (o KubernetesCertsSpec) DeepCopy() KubernetesCertsSpec {\n\tvar cp KubernetesCertsSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubernetesDynamicCertsSpec.\nfunc (o KubernetesDynamicCertsSpec) DeepCopy() KubernetesDynamicCertsSpec {\n\tvar cp KubernetesDynamicCertsSpec = o\n\tif o.APIServer != nil {\n\t\tcp.APIServer = o.APIServer.DeepCopy()\n\t}\n\tif o.APIServerKubeletClient != nil {\n\t\tcp.APIServerKubeletClient = o.APIServerKubeletClient.DeepCopy()\n\t}\n\tif o.FrontProxy != nil {\n\t\tcp.FrontProxy = o.FrontProxy.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of KubernetesRootSpec.\nfunc (o KubernetesRootSpec) DeepCopy() KubernetesRootSpec {\n\tvar cp KubernetesRootSpec = o\n\tif o.Endpoint != nil {\n\t\tcp.Endpoint = new(url.URL)\n\t\t*cp.Endpoint = *o.Endpoint\n\t\tif o.Endpoint.User != nil {\n\t\t\tcp.Endpoint.User = new(url.Userinfo)\n\t\t\t*cp.Endpoint.User = *o.Endpoint.User\n\t\t}\n\t}\n\tif o.LocalEndpoint != nil {\n\t\tcp.LocalEndpoint = new(url.URL)\n\t\t*cp.LocalEndpoint = *o.LocalEndpoint\n\t\tif o.LocalEndpoint.User != nil {\n\t\t\tcp.LocalEndpoint.User = new(url.Userinfo)\n\t\t\t*cp.LocalEndpoint.User = *o.LocalEndpoint.User\n\t\t}\n\t}\n\tif o.CertSANs != nil {\n\t\tcp.CertSANs = make([]string, len(o.CertSANs))\n\t\tcopy(cp.CertSANs, o.CertSANs)\n\t}\n\tif o.APIServerIPs != nil {\n\t\tcp.APIServerIPs = make([]netip.Addr, len(o.APIServerIPs))\n\t\tcopy(cp.APIServerIPs, o.APIServerIPs)\n\t}\n\tif o.IssuingCA != nil {\n\t\tcp.IssuingCA = o.IssuingCA.DeepCopy()\n\t}\n\tif o.AcceptedCAs != nil {\n\t\tcp.AcceptedCAs = make([]*x509.PEMEncodedCertificate, len(o.AcceptedCAs))\n\t\tcopy(cp.AcceptedCAs, o.AcceptedCAs)\n\t\tfor i2 := range o.AcceptedCAs {\n\t\t\tif o.AcceptedCAs[i2] != nil {\n\t\t\t\tcp.AcceptedCAs[i2] = o.AcceptedCAs[i2].DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif o.ServiceAccount != nil {\n\t\tcp.ServiceAccount = o.ServiceAccount.DeepCopy()\n\t}\n\tif o.AggregatorCA != nil {\n\t\tcp.AggregatorCA = o.AggregatorCA.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of MaintenanceRootSpec.\nfunc (o MaintenanceRootSpec) DeepCopy() MaintenanceRootSpec {\n\tvar cp MaintenanceRootSpec = o\n\tif o.CA != nil {\n\t\tcp.CA = o.CA.DeepCopy()\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of OSRootSpec.\nfunc (o OSRootSpec) DeepCopy() OSRootSpec {\n\tvar cp OSRootSpec = o\n\tif o.IssuingCA != nil {\n\t\tcp.IssuingCA = o.IssuingCA.DeepCopy()\n\t}\n\tif o.AcceptedCAs != nil {\n\t\tcp.AcceptedCAs = make([]*x509.PEMEncodedCertificate, len(o.AcceptedCAs))\n\t\tcopy(cp.AcceptedCAs, o.AcceptedCAs)\n\t\tfor i2 := range o.AcceptedCAs {\n\t\t\tif o.AcceptedCAs[i2] != nil {\n\t\t\t\tcp.AcceptedCAs[i2] = o.AcceptedCAs[i2].DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif o.CertSANIPs != nil {\n\t\tcp.CertSANIPs = make([]netip.Addr, len(o.CertSANIPs))\n\t\tcopy(cp.CertSANIPs, o.CertSANIPs)\n\t}\n\tif o.CertSANDNSNames != nil {\n\t\tcp.CertSANDNSNames = make([]string, len(o.CertSANDNSNames))\n\t\tcopy(cp.CertSANDNSNames, o.CertSANDNSNames)\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of TrustdCertsSpec.\nfunc (o TrustdCertsSpec) DeepCopy() TrustdCertsSpec {\n\tvar cp TrustdCertsSpec = o\n\tif o.AcceptedCAs != nil {\n\t\tcp.AcceptedCAs = make([]*x509.PEMEncodedCertificate, len(o.AcceptedCAs))\n\t\tcopy(cp.AcceptedCAs, o.AcceptedCAs)\n\t\tfor i2 := range o.AcceptedCAs {\n\t\t\tif o.AcceptedCAs[i2] != nil {\n\t\t\t\tcp.AcceptedCAs[i2] = o.AcceptedCAs[i2].DeepCopy()\n\t\t\t}\n\t\t}\n\t}\n\tif o.Server != nil {\n\t\tcp.Server = o.Server.DeepCopy()\n\t}\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/encryption_salt.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EncryptionSaltType is type of EncryptionSalt resource.\nconst EncryptionSaltType = resource.Type(\"EncryptionSalts.secrets.talos.dev\")\n\n// EncryptionSaltID is a resource ID of singleton instance.\nconst EncryptionSaltID = resource.ID(\"salt\")\n\n// EncryptionSalt contains salt data used to mix in into disk encryption keys.\ntype EncryptionSalt = typed.Resource[EncryptionSaltSpec, EncryptionSaltExtension]\n\n// EncryptionSaltSpec describes the salt.\n//\n//gotagsrewrite:gen\ntype EncryptionSaltSpec struct {\n\tDiskSalt []byte `yaml:\"diskSalt\" protobuf:\"1\"`\n}\n\n// NewEncryptionSalt initializes a EncryptionSalt resource.\nfunc NewEncryptionSalt() *EncryptionSalt {\n\treturn typed.NewResource[EncryptionSaltSpec, EncryptionSaltExtension](\n\t\tresource.NewMetadata(NamespaceName, EncryptionSaltType, EncryptionSaltID, resource.VersionUndefined),\n\t\tEncryptionSaltSpec{},\n\t)\n}\n\n// EncryptionSaltExtension provides auxiliary methods for EncryptionSalt.\ntype EncryptionSaltExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EncryptionSaltExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EncryptionSaltType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\tif err := protobuf.RegisterDynamic[EncryptionSaltSpec](EncryptionSaltType, &EncryptionSalt{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/etcd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EtcdType is type of Etcd resource.\nconst EtcdType = resource.Type(\"EtcdSecrets.secrets.talos.dev\")\n\n// EtcdID is a resource ID of singleton instance.\nconst EtcdID = resource.ID(\"etcd\")\n\n// Etcd contains etcd generated secrets.\ntype Etcd = typed.Resource[EtcdCertsSpec, EtcdExtension]\n\n// EtcdCertsSpec describes etcd certs secrets.\n//\n//gotagsrewrite:gen\ntype EtcdCertsSpec struct {\n\tEtcd          *x509.PEMEncodedCertificateAndKey `yaml:\"etcd\" protobuf:\"1\"`\n\tEtcdPeer      *x509.PEMEncodedCertificateAndKey `yaml:\"etcdPeer\" protobuf:\"2\"`\n\tEtcdAdmin     *x509.PEMEncodedCertificateAndKey `yaml:\"etcdAdmin\" protobuf:\"3\"`\n\tEtcdAPIServer *x509.PEMEncodedCertificateAndKey `yaml:\"etcdAPIServer\" protobuf:\"4\"`\n}\n\n// NewEtcd initializes a Etc resource.\nfunc NewEtcd() *Etcd {\n\treturn typed.NewResource[EtcdCertsSpec, EtcdExtension](\n\t\tresource.NewMetadata(NamespaceName, EtcdType, EtcdID, resource.VersionUndefined),\n\t\tEtcdCertsSpec{},\n\t)\n}\n\n// EtcdExtension provides auxiliary methods for Etcd.\ntype EtcdExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EtcdExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EtcdType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EtcdCertsSpec](EtcdType, &Etcd{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/etcd_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// EtcdRootType is type of EtcdRoot secret resource.\nconst EtcdRootType = resource.Type(\"EtcdRootSecrets.secrets.talos.dev\")\n\n// EtcdRootID is the IDs of EtcdRoot.\nconst EtcdRootID = resource.ID(\"etcd\")\n\n// EtcdRoot contains root (not generated) secrets.\ntype EtcdRoot = typed.Resource[EtcdRootSpec, EtcdRootExtension]\n\n// EtcdRootSpec describes etcd CA secrets.\n//\n//gotagsrewrite:gen\ntype EtcdRootSpec struct {\n\tEtcdCA *x509.PEMEncodedCertificateAndKey `yaml:\"etcdCA\" protobuf:\"1\"`\n}\n\n// NewEtcdRoot initializes a EtcdRoot resource.\nfunc NewEtcdRoot(id resource.ID) *EtcdRoot {\n\treturn typed.NewResource[EtcdRootSpec, EtcdRootExtension](\n\t\tresource.NewMetadata(NamespaceName, EtcdRootType, id, resource.VersionUndefined),\n\t\tEtcdRootSpec{},\n\t)\n}\n\n// EtcdRootExtension provides auxiliary methods for EtcdRoot.\ntype EtcdRootExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (EtcdRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             EtcdRootType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[EtcdRootSpec](EtcdRootType, &EtcdRoot{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/kubelet.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubeletType is type of Kubelet secret resource.\nconst KubeletType = resource.Type(\"KubeletSecrets.secrets.talos.dev\")\n\n// KubeletID is the ID of KubeletType resource.\nconst KubeletID = resource.ID(\"kubelet\")\n\n// Kubelet contains root (not generated) secrets.\ntype Kubelet = typed.Resource[KubeletSpec, KubeletExtension]\n\n// KubeletSpec describes root Kubernetes secrets.\n//\n//gotagsrewrite:gen\ntype KubeletSpec struct {\n\tEndpoint *url.URL `yaml:\"endpoint\" protobuf:\"1\"`\n\n\tAcceptedCAs []*x509.PEMEncodedCertificate `yaml:\"acceptedCAs\" protobuf:\"5\"`\n\n\tBootstrapTokenID     string `yaml:\"bootstrapTokenID\" protobuf:\"3\"`\n\tBootstrapTokenSecret string `yaml:\"bootstrapTokenSecret\" protobuf:\"4\"`\n}\n\n// NewKubelet initializes a Kubelet resource.\nfunc NewKubelet(id resource.ID) *Kubelet {\n\treturn typed.NewResource[KubeletSpec, KubeletExtension](\n\t\tresource.NewMetadata(NamespaceName, KubeletType, id, resource.VersionUndefined),\n\t\tKubeletSpec{},\n\t)\n}\n\n// KubeletExtension provides auxiliary methods for Kubelet.\ntype KubeletExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KubeletExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubeletType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubeletSpec](KubeletType, &Kubelet{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubernetesType is type of Kubernetes resource.\nconst KubernetesType = resource.Type(\"KubernetesSecrets.secrets.talos.dev\")\n\n// KubernetesID is a resource ID of singleton instance.\nconst KubernetesID = resource.ID(\"k8s-certs\")\n\n// Kubernetes contains K8s generated secrets.\n//\n// Kubernetes resource contains secrets which require reload of the control plane pods if updated.\ntype Kubernetes = typed.Resource[KubernetesCertsSpec, KubernetesExtension]\n\n// KubernetesCertsSpec describes generated Kubernetes certificates.\n//\n//gotagsrewrite:gen\ntype KubernetesCertsSpec struct {\n\tSchedulerKubeconfig         string `yaml:\"schedulerKubeconfig\" protobuf:\"4\"`\n\tControllerManagerKubeconfig string `yaml:\"controllerManagerKubeconfig\" protobuf:\"5\"`\n\n\t// Admin-level kubeconfig with access through the localhost endpoint and cluster endpoints.\n\tLocalhostAdminKubeconfig string `yaml:\"localhostAdminKubeconfig\" protobuf:\"6\"`\n\tAdminKubeconfig          string `yaml:\"adminKubeconfig\" protobuf:\"7\"`\n}\n\n// NewKubernetes initializes a Kubernetes resource.\nfunc NewKubernetes() *Kubernetes {\n\treturn typed.NewResource[KubernetesCertsSpec, KubernetesExtension](\n\t\tresource.NewMetadata(NamespaceName, KubernetesType, KubernetesID, resource.VersionUndefined),\n\t\tKubernetesCertsSpec{},\n\t)\n}\n\n// KubernetesExtension provides auxiliary methods for Kubernetes.\ntype KubernetesExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KubernetesExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubernetesType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubernetesCertsSpec](KubernetesType, &Kubernetes{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/kubernetes_certs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubernetesDynamicCertsType is type of KubernetesCerts resource.\nconst KubernetesDynamicCertsType = resource.Type(\"KubernetesDynamicCerts.secrets.talos.dev\")\n\n// KubernetesDynamicCertsID is a resource ID of singleton instance.\nconst KubernetesDynamicCertsID = resource.ID(\"k8s-dynamic-certs\")\n\n// KubernetesDynamicCerts contains K8s generated secrets.\n//\n// KubernetesDynamicCerts resource contains secrets which do not require reload when updated.\ntype KubernetesDynamicCerts = typed.Resource[KubernetesDynamicCertsSpec, KubernetesDynamicCertsExtension]\n\n// KubernetesDynamicCertsSpec describes generated KubernetesCerts certificates.\n//\n//gotagsrewrite:gen\ntype KubernetesDynamicCertsSpec struct {\n\tAPIServer              *x509.PEMEncodedCertificateAndKey `yaml:\"apiServer\" protobuf:\"1\"`\n\tAPIServerKubeletClient *x509.PEMEncodedCertificateAndKey `yaml:\"apiServerKubeletClient\" protobuf:\"2\"`\n\tFrontProxy             *x509.PEMEncodedCertificateAndKey `yaml:\"frontProxy\" protobuf:\"3\"`\n}\n\n// NewKubernetesDynamicCerts initializes a KubernetesCerts resource.\nfunc NewKubernetesDynamicCerts() *KubernetesDynamicCerts {\n\treturn typed.NewResource[KubernetesDynamicCertsSpec, KubernetesDynamicCertsExtension](\n\t\tresource.NewMetadata(NamespaceName, KubernetesDynamicCertsType, KubernetesDynamicCertsID, resource.VersionUndefined),\n\t\tKubernetesDynamicCertsSpec{},\n\t)\n}\n\n// KubernetesDynamicCertsExtension provides auxiliary methods for KubernetesCerts.\ntype KubernetesDynamicCertsExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KubernetesDynamicCertsExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubernetesDynamicCertsType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubernetesDynamicCertsSpec](KubernetesDynamicCertsType, &KubernetesDynamicCerts{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/kubernetes_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"net/netip\"\n\t\"net/url\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// KubernetesRootType is type of KubernetesRoot secret resource.\nconst KubernetesRootType = resource.Type(\"KubernetesRootSecrets.secrets.talos.dev\")\n\n// KubernetesRootID is the ID of KubernetesRootType resource.\nconst KubernetesRootID = resource.ID(\"k8s\")\n\n// KubernetesRoot contains root (not generated) secrets.\ntype KubernetesRoot = typed.Resource[KubernetesRootSpec, KubernetesRootExtension]\n\n// KubernetesRootSpec describes root Kubernetes secrets.\n//\n//gotagsrewrite:gen\ntype KubernetesRootSpec struct {\n\tName          string       `yaml:\"name\" protobuf:\"1\"`\n\tEndpoint      *url.URL     `yaml:\"endpoint\" protobuf:\"2\"`\n\tLocalEndpoint *url.URL     `yaml:\"local_endpoint\" protobuf:\"3\"`\n\tCertSANs      []string     `yaml:\"certSANs\" protobuf:\"4\"`\n\tAPIServerIPs  []netip.Addr `yaml:\"apiServerIPs\" protobuf:\"14\"`\n\tDNSDomain     string       `yaml:\"dnsDomain\" protobuf:\"6\"`\n\n\tIssuingCA      *x509.PEMEncodedCertificateAndKey `yaml:\"issuingCA\" protobuf:\"7\"`\n\tAcceptedCAs    []*x509.PEMEncodedCertificate     `yaml:\"acceptedCAs\" protobuf:\"15\"`\n\tServiceAccount *x509.PEMEncodedKey               `yaml:\"serviceAccount\" protobuf:\"8\"`\n\tAggregatorCA   *x509.PEMEncodedCertificateAndKey `yaml:\"aggregatorCA\" protobuf:\"9\"`\n\n\tAESCBCEncryptionSecret string `yaml:\"aesCBCEncryptionSecret\" protobuf:\"10\"`\n\n\tBootstrapTokenID     string `yaml:\"bootstrapTokenID\" protobuf:\"11\"`\n\tBootstrapTokenSecret string `yaml:\"bootstrapTokenSecret\" protobuf:\"12\"`\n\n\tSecretboxEncryptionSecret string `yaml:\"secretboxEncryptionSecret\" protobuf:\"13\"`\n}\n\n// NewKubernetesRoot initializes a KubernetesRoot resource.\nfunc NewKubernetesRoot(id resource.ID) *KubernetesRoot {\n\treturn typed.NewResource[KubernetesRootSpec, KubernetesRootExtension](\n\t\tresource.NewMetadata(NamespaceName, KubernetesRootType, id, resource.VersionUndefined),\n\t\tKubernetesRootSpec{},\n\t)\n}\n\n// KubernetesRootExtension provides auxiliary methods for KubernetesRoot.\ntype KubernetesRootExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (KubernetesRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             KubernetesRootType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[KubernetesRootSpec](KubernetesRootType, &KubernetesRoot{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/maintenance_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// MaintenanceRootType is type of MaintenanceRoot secret resource.\nconst MaintenanceRootType = resource.Type(\"MaintenanceRootSecrets.secrets.talos.dev\")\n\n// MaintenanceRootID is the Resource ID for MaintenanceRoot.\nconst MaintenanceRootID = resource.ID(\"maintenance\")\n\n// MaintenanceRoot contains root secrets for the maintenance service.\ntype MaintenanceRoot = typed.Resource[MaintenanceRootSpec, MaintenanceRootExtension]\n\n// MaintenanceRootSpec describes maintenance service CA.\n//\n//gotagsrewrite:gen\ntype MaintenanceRootSpec struct {\n\tCA *x509.PEMEncodedCertificateAndKey `yaml:\"ca\" protobuf:\"1\"`\n}\n\n// NewMaintenanceRoot initializes a MaintenanceRoot resource.\nfunc NewMaintenanceRoot(id resource.ID) *MaintenanceRoot {\n\treturn typed.NewResource[MaintenanceRootSpec, MaintenanceRootExtension](\n\t\tresource.NewMetadata(NamespaceName, MaintenanceRootType, id, resource.VersionUndefined),\n\t\tMaintenanceRootSpec{},\n\t)\n}\n\n// MaintenanceRootExtension provides auxiliary methods for MaintenanceRoot.\ntype MaintenanceRootExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (MaintenanceRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             MaintenanceRootType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\tif err := protobuf.RegisterDynamic[MaintenanceRootSpec](MaintenanceRootType, &MaintenanceRoot{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/os_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// OSRootType is type of OSRoot secret resource.\nconst OSRootType = resource.Type(\"OSRootSecrets.secrets.talos.dev\")\n\n// OSRootID is the Resource ID for OSRoot.\nconst OSRootID = resource.ID(\"os\")\n\n// OSRoot contains root (not generated) secrets.\ntype OSRoot = typed.Resource[OSRootSpec, OSRootExtension]\n\n// OSRootSpec describes operating system CA.\n//\n//gotagsrewrite:gen\ntype OSRootSpec struct {\n\tIssuingCA       *x509.PEMEncodedCertificateAndKey `yaml:\"issuingCA\" protobuf:\"1\"`\n\tAcceptedCAs     []*x509.PEMEncodedCertificate     `yaml:\"acceptedCAs\" protobuf:\"5\"`\n\tCertSANIPs      []netip.Addr                      `yaml:\"certSANIPs\" protobuf:\"2\"`\n\tCertSANDNSNames []string                          `yaml:\"certSANDNSNames\" protobuf:\"3\"`\n\n\tToken string `yaml:\"token\" protobuf:\"4\"`\n}\n\n// NewOSRoot initializes a OSRoot resource.\nfunc NewOSRoot(id resource.ID) *OSRoot {\n\treturn typed.NewResource[OSRootSpec, OSRootExtension](\n\t\tresource.NewMetadata(NamespaceName, OSRootType, id, resource.VersionUndefined),\n\t\tOSRootSpec{},\n\t)\n}\n\n// OSRootExtension provides auxiliary methods for OSRoot.\ntype OSRootExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (OSRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             OSRootType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\tif err := protobuf.RegisterDynamic[OSRootSpec](OSRootType, &OSRoot{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/secrets.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package secrets provides resources which store secrets.\npackage secrets\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n// NamespaceName contains resources containing secret material.\nconst NamespaceName resource.Namespace = \"secrets\"\n\n//go:generate go tool github.com/siderolabs/deep-copy -type APICertsSpec -type CertSANSpec -type EtcdCertsSpec -type EtcdRootSpec -type EncryptionSaltSpec -type KubeletSpec -type KubernetesCertsSpec -type KubernetesDynamicCertsSpec -type KubernetesRootSpec -type MaintenanceRootSpec -type OSRootSpec -type TrustdCertsSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/secrets_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&secrets.API{},\n\t\t&secrets.CertSAN{},\n\t\t&secrets.EncryptionSalt{},\n\t\t&secrets.Etcd{},\n\t\t&secrets.EtcdRoot{},\n\t\t&secrets.Kubelet{},\n\t\t&secrets.Kubernetes{},\n\t\t&secrets.KubernetesDynamicCerts{},\n\t\t&secrets.KubernetesRoot{},\n\t\t&secrets.MaintenanceRoot{},\n\t\t&secrets.OSRoot{},\n\t\t&secrets.Trustd{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/trustd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/siderolabs/crypto/x509\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// TrustdType is type of Trustd resource.\nconst TrustdType = resource.Type(\"TrustdCertificates.secrets.talos.dev\")\n\n// TrustdID is a resource ID of singleton instance.\nconst TrustdID = resource.ID(\"trustd\")\n\n// Trustd contains trustd generated secrets.\ntype Trustd = typed.Resource[TrustdCertsSpec, TrustdExtension]\n\n// TrustdCertsSpec describes etcd certs secrets.\n//\n//gotagsrewrite:gen\ntype TrustdCertsSpec struct {\n\tAcceptedCAs []*x509.PEMEncodedCertificate     `yaml:\"acceptedCAs\" protobuf:\"3\"`\n\tServer      *x509.PEMEncodedCertificateAndKey `yaml:\"server\" protobuf:\"2\"`\n}\n\n// NewTrustd initializes a Trustd resource.\nfunc NewTrustd() *Trustd {\n\treturn typed.NewResource[TrustdCertsSpec, TrustdExtension](\n\t\tresource.NewMetadata(NamespaceName, TrustdType, TrustdID, resource.VersionUndefined),\n\t\tTrustdCertsSpec{},\n\t)\n}\n\n// TrustdExtension provides auxiliary methods for Trustd.\ntype TrustdExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (TrustdExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             TrustdType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tSensitivity:      meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\tif err := protobuf.RegisterDynamic[TrustdCertsSpec](TrustdType, &Trustd{}); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/secrets/trustd_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage secrets_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n)\n\nfunc TestTrustdProtobufMarshal(t *testing.T) {\n\tr := secrets.NewTrustd()\n\tr.TypedSpec().AcceptedCAs = []*x509.PEMEncodedCertificate{\n\t\t{\n\t\t\tCrt: []byte(\"foo\"),\n\t\t},\n\t}\n\tr.TypedSpec().Server = &x509.PEMEncodedCertificateAndKey{\n\t\tCrt: []byte(\"car\"),\n\t\tKey: []byte(\"caz\"),\n\t}\n\n\tprotoR, err := protobuf.FromResource(r)\n\trequire.NoError(t, err)\n\n\tmarshaled, err := protoR.Marshal()\n\trequire.NoError(t, err)\n\n\tprotoR, err = protobuf.Unmarshal(marshaled)\n\trequire.NoError(t, err)\n\n\tr2, err := protobuf.UnmarshalResource(protoR)\n\trequire.NoError(t, err)\n\n\trequire.True(t, resource.Equal(r, r2))\n}\n"
  },
  {
    "path": "pkg/machinery/resources/security/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ImageVerificationRuleSpec -type TUFTrustedRootSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage security\n\n// DeepCopy generates a deep copy of ImageVerificationRuleSpec.\nfunc (o ImageVerificationRuleSpec) DeepCopy() ImageVerificationRuleSpec {\n\tvar cp ImageVerificationRuleSpec = o\n\tif o.KeylessVerifier != nil {\n\t\tcp.KeylessVerifier = new(ImageKeylessVerifierSpec)\n\t\t*cp.KeylessVerifier = *o.KeylessVerifier\n\t}\n\tif o.PublicKeyVerifier != nil {\n\t\tcp.PublicKeyVerifier = new(ImagePublicKeyVerifierSpec)\n\t\t*cp.PublicKeyVerifier = *o.PublicKeyVerifier\n\t}\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of TUFTrustedRootSpec.\nfunc (o TUFTrustedRootSpec) DeepCopy() TUFTrustedRootSpec {\n\tvar cp TUFTrustedRootSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/security/image_verification_rule.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage security\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/ryanuber/go-glob\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ImageVerificationRuleType is type of ImageVerificationRule resource.\nconst ImageVerificationRuleType = resource.Type(\"ImageVerificationRules.security.talos.dev\")\n\n// ImageVerificationRule represents ImageVerificationRule typed resource.\ntype ImageVerificationRule = typed.Resource[ImageVerificationRuleSpec, ImageVerificationRuleExtension]\n\n// ImageVerificationRuleSpec represents a verification rule.\n//\n//gotagsrewrite:gen\ntype ImageVerificationRuleSpec struct {\n\t// ImagePattern is the image name pattern.\n\tImagePattern string `yaml:\"imagePattern,omitempty\" protobuf:\"2\"`\n\t// Skip is the action for matching images.\n\tSkip bool `yaml:\"skip\" protobuf:\"3\"`\n\t// Deny is the action for matching images.\n\tDeny bool `yaml:\"deny\" protobuf:\"4\"`\n\t// KeylessVerifier is the keyless verifier configuration to use.\n\tKeylessVerifier *ImageKeylessVerifierSpec `yaml:\"keylessVerifier,omitempty\" protobuf:\"5\"`\n\t// PublicKeyVerifier is the public key verifier configuration to use.\n\tPublicKeyVerifier *ImagePublicKeyVerifierSpec `yaml:\"publicKeyVerifier,omitempty\" protobuf:\"6\"`\n}\n\n// ImageKeylessVerifierSpec represents a signature verification provider.\n//\n//gotagsrewrite:gen\ntype ImageKeylessVerifierSpec struct {\n\t// Issuer is the OIDC issuer URL.\n\tIssuer string `yaml:\"issuer\" protobuf:\"1\"`\n\t// Subject is the expected subject.\n\tSubject string `yaml:\"subject,omitempty\" protobuf:\"2\"`\n\t// SubjectRegex is a regex pattern for subject matching.\n\tSubjectRegex string `yaml:\"subjectRegex,omitempty\" protobuf:\"3\"`\n}\n\n// ImagePublicKeyVerifierSpec represents a signature verification provider with static public key.\n//\n//gotagsrewrite:gen\ntype ImagePublicKeyVerifierSpec struct {\n\t// Certificate is a public certificate in PEM format accepted for image signature verification.\n\tCertificate string `yaml:\"certificate\" protobuf:\"1\"`\n}\n\n// NewImageVerificationRule creates new ImageVerificationRule object.\nfunc NewImageVerificationRule(id resource.ID) *ImageVerificationRule {\n\treturn typed.NewResource[ImageVerificationRuleSpec, ImageVerificationRuleExtension](\n\t\tresource.NewMetadata(NamespaceName, ImageVerificationRuleType, id, resource.VersionUndefined),\n\t\tImageVerificationRuleSpec{},\n\t)\n}\n\n// ImageVerificationRuleExtension is an auxiliary type for ImageVerificationRule resource.\ntype ImageVerificationRuleExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ImageVerificationRuleExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ImageVerificationRuleType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Pattern\",\n\t\t\t\tJSONPath: \"{.imagePattern}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Skip\",\n\t\t\t\tJSONPath: \"{.skip}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Deny\",\n\t\t\t\tJSONPath: \"{.deny}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\n// ImageVerificationRuleMatchFunc is a function type for matching image references to verification rules.\ntype ImageVerificationRuleMatchFunc func(imageRef string) *ImageVerificationRule\n\n// ImageVerificationRuleMatcher creates the matcher for the given image reference against the provided rules and returns the first matching rule.\nfunc ImageVerificationRuleMatcher(ctx context.Context, st state.State) (ImageVerificationRuleMatchFunc, error) {\n\trules, err := safe.StateListAll[*ImageVerificationRule](ctx, st)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to list image verification rules: %w\", err)\n\t}\n\n\treturn func(imageRef string) *ImageVerificationRule {\n\t\tfor rule := range rules.All() {\n\t\t\tif rule.TypedSpec().ImagePattern != \"\" && glob.Glob(rule.TypedSpec().ImagePattern, imageRef) {\n\t\t\t\treturn rule\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}, nil\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(ImageVerificationRuleType, &ImageVerificationRule{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/security/security.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage security\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ImageVerificationRuleSpec -type TUFTrustedRootSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName is the namespace for security resources.\nconst NamespaceName resource.Namespace = \"security\"\n"
  },
  {
    "path": "pkg/machinery/resources/security/security_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage security_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/security\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&security.ImageVerificationRule{},\n\t\t&security.TUFTrustedRoot{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/security/tuf_trusted_root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage security\n\nimport (\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// TUFTrustedRootType is type of TUFTrustedRoot resource.\nconst TUFTrustedRootType = resource.Type(\"TUFTrustedRoots.security.talos.dev\")\n\n// TUFTrustedRoot represents TUFTrustedRoot typed resource.\ntype TUFTrustedRoot = typed.Resource[TUFTrustedRootSpec, TUFTrustedRootExtension]\n\n// TrustedRootID is the ID for the TUF trusted root resource.\nconst TrustedRootID = resource.ID(\"trusted_root.json\")\n\n// TUFTrustedRootSpec represents a sigstore's TUF trusted root information.\n//\n//gotagsrewrite:gen\ntype TUFTrustedRootSpec struct {\n\t// LastRefreshTime is the last time the trusted root was refreshed.\n\tLastRefreshTime time.Time `yaml:\"lastRefreshTime,omitempty\" protobuf:\"1\"`\n\t// JSONData is the trusted root data in JSON format.\n\tJSONData string `yaml:\"jsonData,omitempty\" protobuf:\"2\"`\n}\n\n// NewTUFTrustedRoot creates new TUFTrustedRoot object.\nfunc NewTUFTrustedRoot(id resource.ID) *TUFTrustedRoot {\n\treturn typed.NewResource[TUFTrustedRootSpec, TUFTrustedRootExtension](\n\t\tresource.NewMetadata(NamespaceName, TUFTrustedRootType, id, resource.VersionUndefined),\n\t\tTUFTrustedRootSpec{},\n\t)\n}\n\n// TUFTrustedRootExtension is an auxiliary type for TUFTrustedRoot resource.\ntype TUFTrustedRootExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (TUFTrustedRootExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             TUFTrustedRootType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Last Refresh\",\n\t\t\t\tJSONPath: \"{.lastRefreshTime}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic(TUFTrustedRootType, &TUFTrustedRoot{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/siderolink/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type ConfigSpec -type StatusSpec -type TunnelSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage siderolink\n\n// DeepCopy generates a deep copy of ConfigSpec.\nfunc (o ConfigSpec) DeepCopy() ConfigSpec {\n\tvar cp ConfigSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StatusSpec.\nfunc (o StatusSpec) DeepCopy() StatusSpec {\n\tvar cp StatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of TunnelSpec.\nfunc (o TunnelSpec) DeepCopy() TunnelSpec {\n\tvar cp TunnelSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/siderolink/siderolink.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package siderolink contains SideroLink-related resources.\npackage siderolink\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n//go:generate go tool github.com/siderolabs/deep-copy -type ConfigSpec -type StatusSpec -type TunnelSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// ConfigType is type of Config resource.\nconst ConfigType = resource.Type(\"SiderolinkConfigs.siderolink.talos.dev\")\n\n// ConfigID the singleton config resource ID.\nconst ConfigID = resource.ID(\"siderolink\")\n\n// Config resource holds Siderolink configuration.\ntype Config = typed.Resource[ConfigSpec, ConfigExtension]\n\n// ConfigSpec describes Siderolink configuration.\n//\n//gotagsrewrite:gen\ntype ConfigSpec struct {\n\tAPIEndpoint string `yaml:\"apiEndpoint\" protobuf:\"1\"`\n\tHost        string `yaml:\"host\" protobuf:\"2\"`\n\tJoinToken   string `yaml:\"joinToken\" protobuf:\"3\"`\n\tInsecure    bool   `yaml:\"insecure\" protobuf:\"4\"`\n\tTunnel      bool   `yaml:\"tunnel\" protobuf:\"5\"`\n}\n\n// NewConfig initializes a Config resource.\nfunc NewConfig(namespace resource.Namespace, id resource.ID) *Config {\n\treturn typed.NewResource[ConfigSpec, ConfigExtension](\n\t\tresource.NewMetadata(namespace, ConfigType, id, resource.VersionUndefined),\n\t\tConfigSpec{},\n\t)\n}\n\n// ConfigExtension provides auxiliary methods for Config.\ntype ConfigExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (ConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ConfigType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"API Endpoint\",\n\t\t\t\tJSONPath: `{.apiEndpoint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Tunnel\",\n\t\t\t\tJSONPath: `{.tunnel}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ConfigSpec](ConfigType, &Config{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/siderolink/siderolink_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// StatusType is the type of Status resource.\nconst StatusType = resource.Type(\"SiderolinkStatuses.siderolink.talos.dev\")\n\n// StatusID the singleton status resource ID.\nconst StatusID = resource.ID(\"siderolink-status\")\n\n// Status resource holds Siderolink status.\ntype Status = typed.Resource[StatusSpec, StatusExtension]\n\n// StatusSpec describes Siderolink status.\n//\n//gotagsrewrite:gen\ntype StatusSpec struct {\n\t// Host is the Siderolink target host.\n\tHost string `yaml:\"host\" protobuf:\"1\"`\n\t// Connected is the status of the Siderolink GRPC connection.\n\tConnected bool `yaml:\"connected\" protobuf:\"2\"`\n\t// LinkName is the name of the interface used for the Siderolink tunnel.\n\tLinkName string `yaml:\"linkName\" protobuf:\"3\"`\n\t// GRPCTunnel is true if the Wireguard-over-GRPC tunnel is being used.\n\tGRPCTunnel bool `yaml:\"grpcTunnel\" protobuf:\"4\"`\n}\n\n// NewStatus initializes a Status resource.\nfunc NewStatus() *Status {\n\treturn typed.NewResource[StatusSpec, StatusExtension](\n\t\tresource.NewMetadata(config.NamespaceName, StatusType, StatusID, resource.VersionUndefined),\n\t\tStatusSpec{},\n\t)\n}\n\n// StatusExtension provides auxiliary methods for Status.\ntype StatusExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (StatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Host\",\n\t\t\t\tJSONPath: `{.host}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Connected\",\n\t\t\t\tJSONPath: `{.connected}`,\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StatusSpec](StatusType, &Status{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/siderolink/siderolink_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/siderolink\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&siderolink.Config{},\n\t\t&siderolink.Status{},\n\t\t&siderolink.Tunnel{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/siderolink/siderolink_tunnel.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage siderolink\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n)\n\n// TunnelType is type of Tunnel resource.\nconst TunnelType = resource.Type(\"SiderolinkTunnels.siderolink.talos.dev\")\n\n// TunnelID the singleton tunnel resource ID.\nconst TunnelID = resource.ID(\"siderolink-tunnel\")\n\n// Tunnel resource holds Siderolink GRPC Tunnel configuration.\ntype Tunnel = typed.Resource[TunnelSpec, TunnelExtension]\n\n// TunnelSpec describes Siderolink GRPC Tunnel configuration.\n//\n//gotagsrewrite:gen\ntype TunnelSpec struct {\n\t// APIEndpoint is the Siderolink WireGuard over GRPC endpoint.\n\tAPIEndpoint string `yaml:\"apiEndpoint\" protobuf:\"1\"`\n\t// LinkName is the name to use for WireGuard tunnel.\n\tLinkName string `yaml:\"linkName\" protobuf:\"2\"`\n\t// MTU is the maximum transmission unit for the tunnel.\n\tMTU int `yaml:\"mtu\" protobuf:\"3\"`\n\t// NodeAddress is the virtual address of our node. It's used to identify our node in the WireGuard GRPC streamer.\n\t// It's not the address of the actual WireGuard interface.\n\tNodeAddress netip.AddrPort `yaml:\"nodeAddress\" protobuf:\"4\"`\n}\n\n// NewTunnel initializes a Config resource.\nfunc NewTunnel() *Tunnel {\n\treturn typed.NewResource[TunnelSpec, TunnelExtension](\n\t\tresource.NewMetadata(config.NamespaceName, TunnelType, TunnelID, resource.VersionUndefined),\n\t\tTunnelSpec{},\n\t)\n}\n\n// TunnelExtension provides auxiliary methods for Tunnel.\ntype TunnelExtension struct{}\n\n// ResourceDefinition implements [typed.Extension] interface.\nfunc (TunnelExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             TunnelType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: config.NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"API Endpoint\",\n\t\t\t\tJSONPath: `{.apiEndpoint}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Link name\",\n\t\t\t\tJSONPath: `{.linkName}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"MTU\",\n\t\t\t\tJSONPath: `{.mtu}`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Node address\",\n\t\t\t\tJSONPath: `{.nodeAddress}`,\n\t\t\t},\n\t\t},\n\t\tSensitivity: meta.Sensitive,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[TunnelSpec](TunnelType, &Tunnel{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/time/adjtime_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time\n\nimport (\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// AdjtimeStatusType is type of AdjtimeStatus resource.\nconst AdjtimeStatusType = resource.Type(\"AdjtimeStatuses.v1alpha1.talos.dev\")\n\n// AdjtimeStatusID is the ID of the singletone resource.\nconst AdjtimeStatusID = resource.ID(\"node\")\n\n// AdjtimeStatus describes running current time sync AdjtimeStatus.\ntype AdjtimeStatus = typed.Resource[AdjtimeStatusSpec, AdjtimeStatusExtension]\n\n// AdjtimeStatusSpec describes Linux internal adjtime state.\n//\n//gotagsrewrite:gen\ntype AdjtimeStatusSpec struct {\n\tOffset                   time.Duration `yaml:\"offset\" protobuf:\"1\"`\n\tFrequencyAdjustmentRatio float64       `yaml:\"frequencyAdjustmentRatio\" protobuf:\"2\"`\n\tMaxError                 time.Duration `yaml:\"maxError\" protobuf:\"3\"`\n\tEstError                 time.Duration `yaml:\"estError\" protobuf:\"4\"`\n\tStatus                   string        `yaml:\"status\" protobuf:\"5\"`\n\tConstant                 int           `yaml:\"constant\" protobuf:\"6\"`\n\tSyncStatus               bool          `yaml:\"syncStatus\" protobuf:\"7\"`\n\tState                    string        `yaml:\"state\" protobuf:\"8\"`\n}\n\n// NewAdjtimeStatus initializes a TimeSync resource.\nfunc NewAdjtimeStatus() *AdjtimeStatus {\n\treturn typed.NewResource[AdjtimeStatusSpec, AdjtimeStatusExtension](\n\t\tresource.NewMetadata(v1alpha1.NamespaceName, AdjtimeStatusType, AdjtimeStatusID, resource.VersionUndefined),\n\t\tAdjtimeStatusSpec{},\n\t)\n}\n\n// AdjtimeStatusExtension provides auxiliary methods for AdjtimeStatus.\ntype AdjtimeStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AdjtimeStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AdjtimeStatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: v1alpha1.NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Offset\",\n\t\t\t\tJSONPath: \"{.offset}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"EstError\",\n\t\t\t\tJSONPath: \"{.estError}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"MaxError\",\n\t\t\t\tJSONPath: \"{.maxError}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Status\",\n\t\t\t\tJSONPath: \"{.status}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Sync\",\n\t\t\t\tJSONPath: \"{.syncStatus}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AdjtimeStatusSpec](AdjtimeStatusType, &AdjtimeStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/time/condition.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time\n\nimport (\n\t\"context\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// SyncCondition implements condition which waits for the time to be in sync.\ntype SyncCondition struct {\n\tstate state.State\n}\n\n// NewSyncCondition builds a coondition which waits for the time to be in sync.\nfunc NewSyncCondition(state state.State) *SyncCondition {\n\treturn &SyncCondition{\n\t\tstate: state,\n\t}\n}\n\nfunc (condition *SyncCondition) String() string {\n\treturn \"time sync\"\n}\n\n// Wait implements condition interface.\nfunc (condition *SyncCondition) Wait(ctx context.Context) error {\n\t_, err := condition.state.WatchFor(\n\t\tctx,\n\t\tresource.NewMetadata(v1alpha1.NamespaceName, StatusType, StatusID, resource.VersionUndefined),\n\t\tstate.WithEventTypes(state.Created, state.Updated),\n\t\tstate.WithCondition(func(r resource.Resource) (bool, error) {\n\t\t\treturn r.(*Status).TypedSpec().Synced, nil\n\t\t}),\n\t)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/machinery/resources/time/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type AdjtimeStatusSpec -type StatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage time\n\n// DeepCopy generates a deep copy of AdjtimeStatusSpec.\nfunc (o AdjtimeStatusSpec) DeepCopy() AdjtimeStatusSpec {\n\tvar cp AdjtimeStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of StatusSpec.\nfunc (o StatusSpec) DeepCopy() StatusSpec {\n\tvar cp StatusSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/time/status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// StatusType is type of TimeSync resource.\nconst StatusType = resource.Type(\"TimeStatuses.v1alpha1.talos.dev\")\n\n// StatusID is the ID of the singletone resource.\nconst StatusID = resource.ID(\"node\")\n\n// Status describes running current time sync status.\ntype Status = typed.Resource[StatusSpec, StatusExtension]\n\n// StatusSpec describes time sync state.\n//\n//gotagsrewrite:gen\ntype StatusSpec struct {\n\t// Synced indicates whether time is in sync.\n\tSynced bool `yaml:\"synced\" protobuf:\"1\"`\n\n\t// Epoch is incremented every time clock jumps more than 15min.\n\tEpoch int `yaml:\"epoch\" protobuf:\"2\"`\n\n\t// SyncDisabled indicates if time sync is disabled.\n\tSyncDisabled bool `yaml:\"syncDisabled\" protobuf:\"3\"`\n}\n\n// NewStatus initializes a TimeSync resource.\nfunc NewStatus() *Status {\n\treturn typed.NewResource[StatusSpec, StatusExtension](\n\t\tresource.NewMetadata(v1alpha1.NamespaceName, StatusType, StatusID, resource.VersionUndefined),\n\t\tStatusSpec{},\n\t)\n}\n\n// StatusExtension provides auxiliary methods for Status.\ntype StatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (StatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             StatusType,\n\t\tAliases:          []resource.Type{},\n\t\tDefaultNamespace: v1alpha1.NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Synced\",\n\t\t\t\tJSONPath: \"{.synced}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[StatusSpec](StatusType, &Status{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/time/time.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package time provides time-related resources.\npackage time\n\n//go:generate go tool github.com/siderolabs/deep-copy -type AdjtimeStatusSpec -type StatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n"
  },
  {
    "path": "pkg/machinery/resources/time/time_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage time_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/time\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&time.AdjtimeStatus{},\n\t\t&time.Status{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/acquire_config_spec.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1 //nolint:dupl\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// AcquireConfigSpecType is type of AcquireConfigSpec resource.\nconst AcquireConfigSpecType = resource.Type(\"AcquireConfigSpecs.v1alpha1.talos.dev\")\n\n// AcquireConfigSpec is created when Talos is ready to start acquiring machine configuration.\ntype AcquireConfigSpec = typed.Resource[AcquireConfigSpecSpec, AcquireConfigSpecExtension]\n\n// AcquireConfigSpecSpec describe state of ready to acquire config.\n//\n//gotagsrewrite:gen\ntype AcquireConfigSpecSpec struct{}\n\n// NewAcquireConfigSpec initializes a AcquireConfigSpec resource.\nfunc NewAcquireConfigSpec() *AcquireConfigSpec {\n\treturn typed.NewResource[AcquireConfigSpecSpec, AcquireConfigSpecExtension](\n\t\tresource.NewMetadata(NamespaceName, AcquireConfigSpecType, \"machine-config\", resource.VersionUndefined),\n\t\tAcquireConfigSpecSpec{},\n\t)\n}\n\n// AcquireConfigSpecExtension provides auxiliary methods for AcquireConfigSpec.\ntype AcquireConfigSpecExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AcquireConfigSpecExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AcquireConfigSpecType,\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AcquireConfigSpecSpec](AcquireConfigSpecType, &AcquireConfigSpec{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/acquire_config_status.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1 //nolint:dupl\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// AcquireConfigStatusType is type of AcquireConfigStatus resource.\nconst AcquireConfigStatusType = resource.Type(\"AcquireConfigStatuses.v1alpha1.talos.dev\")\n\n// AcquireConfigStatus is created when machine configuration is ready and boot process is ok to proceed.\ntype AcquireConfigStatus = typed.Resource[AcquireConfigStatusSpec, AcquireConfigStatusExtension]\n\n// AcquireConfigStatusSpec describe state of ready proceed booting with machine config.\n//\n//gotagsrewrite:gen\ntype AcquireConfigStatusSpec struct{}\n\n// NewAcquireConfigStatus initializes a AcquireConfigStatus resource.\nfunc NewAcquireConfigStatus() *AcquireConfigStatus {\n\treturn typed.NewResource[AcquireConfigStatusSpec, AcquireConfigStatusExtension](\n\t\tresource.NewMetadata(NamespaceName, AcquireConfigStatusType, \"machine-config\", resource.VersionUndefined),\n\t\tAcquireConfigStatusSpec{},\n\t)\n}\n\n// AcquireConfigStatusExtension provides auxiliary methods for AcquireConfigStatus.\ntype AcquireConfigStatusExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (AcquireConfigStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             AcquireConfigStatusType,\n\t\tDefaultNamespace: NamespaceName,\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[AcquireConfigStatusSpec](AcquireConfigStatusType, &AcquireConfigStatus{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/deep_copy.generated.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by \"deep-copy -type AcquireConfigSpecSpec -type AcquireConfigStatusSpec -type ServiceSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\"; DO NOT EDIT.\n\npackage v1alpha1\n\n// DeepCopy generates a deep copy of AcquireConfigSpecSpec.\nfunc (o AcquireConfigSpecSpec) DeepCopy() AcquireConfigSpecSpec {\n\tvar cp AcquireConfigSpecSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of AcquireConfigStatusSpec.\nfunc (o AcquireConfigStatusSpec) DeepCopy() AcquireConfigStatusSpec {\n\tvar cp AcquireConfigStatusSpec = o\n\treturn cp\n}\n\n// DeepCopy generates a deep copy of ServiceSpec.\nfunc (o ServiceSpec) DeepCopy() ServiceSpec {\n\tvar cp ServiceSpec = o\n\treturn cp\n}\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/service.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1\n\nimport (\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/resource/protobuf\"\n\t\"github.com/cosi-project/runtime/pkg/resource/typed\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/proto\"\n)\n\n// ServiceType is type of Service resource.\nconst ServiceType = resource.Type(\"Services.v1alpha1.talos.dev\")\n\n// Service describes running service state.\ntype Service = typed.Resource[ServiceSpec, ServiceExtension]\n\n// ServiceSpec describe service state.\n//\n//gotagsrewrite:gen\ntype ServiceSpec struct {\n\tRunning bool `yaml:\"running\" protobuf:\"1\"`\n\tHealthy bool `yaml:\"healthy\" protobuf:\"2\"`\n\tUnknown bool `yaml:\"unknown\" protobuf:\"3\"`\n}\n\n// NewService initializes a Service resource.\nfunc NewService(id resource.ID) *Service {\n\treturn typed.NewResource[ServiceSpec, ServiceExtension](\n\t\tresource.NewMetadata(NamespaceName, ServiceType, id, resource.VersionUndefined),\n\t\tServiceSpec{},\n\t)\n}\n\n// ServiceExtension provides auxiliary methods for Service.\ntype ServiceExtension struct{}\n\n// ResourceDefinition implements meta.ResourceDefinitionProvider interface.\nfunc (ServiceExtension) ResourceDefinition() meta.ResourceDefinitionSpec {\n\treturn meta.ResourceDefinitionSpec{\n\t\tType:             ServiceType,\n\t\tAliases:          []resource.Type{\"svc\"},\n\t\tDefaultNamespace: NamespaceName,\n\t\tPrintColumns: []meta.PrintColumn{\n\t\t\t{\n\t\t\t\tName:     \"Running\",\n\t\t\t\tJSONPath: \"{.running}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Healthy\",\n\t\t\t\tJSONPath: \"{.healthy}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:     \"Health Unknown\",\n\t\t\t\tJSONPath: \"{.unknown}\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc init() {\n\tproto.RegisterDefaultTypes()\n\n\terr := protobuf.RegisterDynamic[ServiceSpec](ServiceType, &Service{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/v1alpha1.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package v1alpha1 provides resources which implement \"glue\" code from v1alpha1 Talos init system.\npackage v1alpha1\n\nimport \"github.com/cosi-project/runtime/pkg/resource\"\n\n//go:generate go tool github.com/siderolabs/deep-copy -type AcquireConfigSpecSpec -type AcquireConfigStatusSpec -type ServiceSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go .\n\n// NamespaceName contains resources linking v1alpha2 components with v1alpha1 Talos runtime.\nconst NamespaceName resource.Namespace = \"runtime\"\n"
  },
  {
    "path": "pkg/machinery/resources/v1alpha1/v1alpha1_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage v1alpha1_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource/meta\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/inmem\"\n\t\"github.com/cosi-project/runtime/pkg/state/impl/namespaced\"\n\t\"github.com/cosi-project/runtime/pkg/state/registry\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\nfunc TestRegisterResource(t *testing.T) {\n\tctx := t.Context()\n\n\tresources := state.WrapCore(namespaced.NewState(inmem.Build))\n\tresourceRegistry := registry.NewResourceRegistry(resources)\n\n\tfor _, resource := range []meta.ResourceWithRD{\n\t\t&v1alpha1.AcquireConfigSpec{},\n\t\t&v1alpha1.AcquireConfigStatus{},\n\t\t&v1alpha1.Service{},\n\t} {\n\t\tassert.NoError(t, resourceRegistry.Register(ctx, resource))\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/role/role.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage role\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/gen/maps\"\n)\n\n// Role represents Talos user role.\n// Its string value is used everywhere: as the Organization value of Talos client certificate,\n// as the value of talosctl flag, etc.\ntype Role string\n\nconst (\n\t// Prefix for all built-in roles.\n\tPrefix = string(\"os:\")\n\n\t// Admin defines Talos role for admins (every API is available).\n\tAdmin = Role(Prefix + \"admin\")\n\n\t// Operator defines Talos role for operators (Reader + management APIs which do not allow secret access, e.g. rebooting a node).\n\tOperator = Role(Prefix + \"operator\")\n\n\t// Reader defines Talos role for readers who can access read-only APIs that do not expose secrets.\n\tReader = Role(Prefix + \"reader\")\n\n\t// EtcdBackup defines Talos role that allows making etcd backups.\n\tEtcdBackup = Role(Prefix + \"etcd:backup\")\n\n\t// Impersonator defines Talos role for impersonating another user (and their role).\n\t// Used internally, but may also be granted to the user.\n\tImpersonator = Role(Prefix + \"impersonator\")\n)\n\n// Set represents a set of roles.\ntype Set struct {\n\troles map[Role]struct{}\n}\n\nvar (\n\t// All roles that can be granted to users.\n\tAll = MakeSet(Admin, Operator, Reader, EtcdBackup, Impersonator)\n\n\t// Zero is an empty set of roles.\n\tZero = MakeSet()\n)\n\n// MakeSet makes a set of roles from constants.\n// Use Parse in other cases.\nfunc MakeSet(roles ...Role) Set {\n\tres := Set{\n\t\troles: make(map[Role]struct{}, len(roles)),\n\t}\n\tfor _, r := range roles {\n\t\tres.roles[r] = struct{}{}\n\t}\n\n\treturn res\n}\n\n// Parse parses a set of roles.\n// The returned set is always non-nil and contains all roles, including unknown (for compatibility with future versions).\n// The returned slice contains roles unknown to the current version.\nfunc Parse(str []string) (Set, []string) {\n\tres := MakeSet()\n\n\tvar unknownRoles []string\n\n\tfor _, r := range str {\n\t\tr = strings.TrimSpace(r)\n\n\t\t// Client certificates generated by previous Talos versions contained one empty organization.\n\t\tif r == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\trole := Role(r)\n\t\tif _, ok := All.roles[role]; !ok {\n\t\t\tunknownRoles = append(unknownRoles, r)\n\t\t}\n\n\t\tres.roles[role] = struct{}{}\n\t}\n\n\treturn res, unknownRoles\n}\n\n// Strings returns a set as a slice of strings.\nfunc (s Set) Strings() []string {\n\tres := maps.KeysFunc(s.roles, func(r Role) string { return string(r) })\n\tslices.Sort(res)\n\n\treturn res\n}\n\n// IncludesAny returns true if there is a non-empty intersection between sets.\n//\n// Returns false if any set is empty.\nfunc (s Set) IncludesAny(other Set) bool {\n\tfor r := range other.roles {\n\t\tif _, ok := s.roles[r]; ok {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Includes returns true if given role is present in the set.\nfunc (s Set) Includes(role Role) bool {\n\t_, ok := s.roles[role]\n\n\treturn ok\n}\n"
  },
  {
    "path": "pkg/machinery/role/role_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage role_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n)\n\nfunc TestSet(t *testing.T) {\n\tt.Parallel()\n\n\troles, unknownRoles := role.Parse([]string{\"os:admin\", \"os:operator\", \"os:reader\", \"os:future\", \"os:impersonator\", \"\", \" \"})\n\tassert.Equal(t, []string{\"os:future\"}, unknownRoles)\n\tassert.Equal(t, role.MakeSet(role.Admin, role.Operator, role.Reader, role.Role(\"os:future\"), role.Impersonator), roles)\n\n\tassert.Equal(t, []string{\"os:admin\", \"os:future\", \"os:impersonator\", \"os:operator\", \"os:reader\"}, roles.Strings())\n\tassert.Equal(t, []string(nil), role.MakeSet().Strings())\n\n\tassert.True(t, roles.Includes(role.Admin))\n\tassert.False(t, roles.Includes(role.Role(\"wrong\")))\n\n\tassert.True(t, roles.IncludesAny(role.MakeSet(role.Admin)))\n\tassert.False(t, roles.IncludesAny(role.MakeSet(role.Role(\"wrong\"))))\n\n\tassert.False(t, roles.IncludesAny(role.MakeSet()))\n\tassert.False(t, role.MakeSet().IncludesAny(roles))\n\tassert.False(t, role.MakeSet().IncludesAny(role.MakeSet()))\n}\n"
  },
  {
    "path": "pkg/machinery/textdiff/testdata/fuzz/FuzzDiff/4436c698e19c9ea6",
    "content": "go test fuzz v1\nstring(\"1\\n\\n\\n\\n\\n\\n\")\nstring(\"\\n1\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n0\")\n"
  },
  {
    "path": "pkg/machinery/textdiff/testdata/fuzz/FuzzDiff/72f7d10cdb1b4c78",
    "content": "go test fuzz v1\nstring(\"\\n\\n\\n\\n\\n\\n\\n\\n\\n0\")\nstring(\"0\")\n"
  },
  {
    "path": "pkg/machinery/textdiff/testdata/fuzz/FuzzDiff/e8e3f58f18e0ab28",
    "content": "go test fuzz v1\nstring(\"\\n\\n\\n\\n\\n\\n\\n\\n\\n0\")\nstring(\"\\n\")\n"
  },
  {
    "path": "pkg/machinery/textdiff/textdiff.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package textdiff provides a way to compare two text blobs.\npackage textdiff\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/neticdk/go-stdlib/diff/myers\"\n)\n\n// MaxLines is the maximum number of lines that the diff function will process before giving up and returning a message instead.\nconst MaxLines = 75_000\n\n// Diff is a function that computes unified diff between two strings.\n//\n// The diff is limited to MaxLines lines, and if the diff is larger than that, a message is returned instead of the actual diff.\n// This is to prevent the function from consuming too much memory or CPU time when comparing large text blobs.\nfunc Diff(a, b string) (string, error) {\n\tif a == b {\n\t\treturn \"\", nil\n\t}\n\n\tprevLines := strings.Count(a, \"\\n\")\n\tnewLines := strings.Count(b, \"\\n\")\n\n\tif prevLines+newLines > MaxLines {\n\t\treturn fmt.Sprintf(\"@@ -%d,%d +%d,%d @@ diff too large to display\\n\", 1, prevLines, 1, newLines), nil\n\t}\n\n\tdiffer := myers.NewCustomDiffer(\n\t\tmyers.WithUnifiedFormatter(),\n\t\tmyers.WithLinearSpace(true),\n\t\t// Disable the library's standard-Myers and LCS fallback paths:\n\t\t// - Standard Myers (< smallInputThreshold) is O((N+M)²) when inputs are asymmetric.\n\t\t// - LCS (> largeInputThreshold) is O(N*M) for the DP table.\n\t\t// By setting these to 0 and MaxLines respectively, only Hirschberg's\n\t\t// O(N+M) linear-space algorithm runs. Our MaxLines guard above ensures\n\t\t// inputs never exceed largeInputThreshold.\n\t\tmyers.WithSmallInputThreshold(0),\n\t\tmyers.WithLargeInputThreshold(MaxLines),\n\t)\n\n\treturn differ.Diff(a, b)\n}\n\n// DiffWithCustomPaths is almost same as Diff, but allows to specify custom paths for the diff header.\nfunc DiffWithCustomPaths(a, b, aPath, bPath string) (string, error) {\n\tdiff, err := Diff(a, b)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif diff == \"\" {\n\t\treturn \"\", nil\n\t}\n\n\t// patch the diff header to include the manifest path\n\tdiff, ok := strings.CutPrefix(diff, \"--- a\\n+++ b\\n\")\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected diff format\")\n\t}\n\n\tvar sb strings.Builder\n\n\tsb.WriteString(\"--- \")\n\tsb.WriteString(aPath)\n\tsb.WriteString(\"\\n+++ \")\n\tsb.WriteString(bPath)\n\tsb.WriteString(\"\\n\")\n\tsb.WriteString(diff)\n\n\treturn sb.String(), nil\n}\n"
  },
  {
    "path": "pkg/machinery/textdiff/textdiff_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage textdiff_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/textdiff\"\n)\n\nfunc TestDiff(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\ta, b string\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"empty\",\n\t\t\ta:        \"\",\n\t\t\tb:        \"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"identical\",\n\t\t\ta:    \"line 1\\nline 2\\nline 3\\n\",\n\t\t\tb:    \"line 1\\nline 2\\nline 3\\n\",\n\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"completely different\",\n\t\t\ta:    \"line 1\\nline 2\\nline 3\\n\",\n\t\t\tb:    \"line A\\nline B\\nline C\\n\",\n\n\t\t\texpected: `--- a\n+++ b\n@@ -1,3 +1,3 @@\n-line 1\n-line 2\n-line 3\n+line A\n+line B\n+line C\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"inserted line\",\n\t\t\ta:    \"line 1\\nline 3\\n\",\n\t\t\tb:    \"line 1\\nline 2\\nline 3\\n\",\n\n\t\t\texpected: `--- a\n+++ b\n@@ -1,2 +1,3 @@\n line 1\n+line 2\n line 3\n`,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdiff, err := textdiff.Diff(test.a, test.b)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, test.expected, diff)\n\t\t})\n\t}\n}\n\nfunc TestDiffWithCustomPaths(t *testing.T) {\n\tt.Parallel()\n\n\tdiff, err := textdiff.DiffWithCustomPaths(\"line 1\\nline 3\\n\", \"line 1\\nline 2\\nline 3\\n\", \"fileA.txt\", \"fileB.txt\")\n\trequire.NoError(t, err)\n\tassert.Equal(t, `--- fileA.txt\n+++ fileB.txt\n@@ -1,2 +1,3 @@\n line 1\n+line 2\n line 3\n`, diff)\n}\n\nfunc genRandomLines(n int) string {\n\tvar sb strings.Builder\n\n\tfor range n {\n\t\tfmt.Fprintf(&sb, \"line %d\\n\", rand.Int())\n\t}\n\n\treturn sb.String()\n}\n\nfunc TestDiffMemoryBudge(t *testing.T) {\n\t// not parallel, we need to measure memory allocations\n\tlinesA := genRandomLines(1000)\n\tlinesB := genRandomLines(20000)\n\tlinesC := genRandomLines(1000)\n\n\tfor _, test := range []struct {\n\t\tname string\n\t\ta, b string\n\n\t\tmemoryBudget uint64\n\t}{\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\ta:    \"\",\n\t\t\tb:    \"\",\n\n\t\t\tmemoryBudget: 1024, // 1KB\n\t\t},\n\t\t{\n\t\t\tname: \"large\",\n\t\t\ta:    linesA + linesB,\n\t\t\tb:    linesB + linesC,\n\n\t\t\tmemoryBudget: 3 * 1024 * 1024, // 3MB\n\t\t},\n\t\t{\n\t\t\tname: \"large 2\",\n\t\t\ta:    linesA + linesB,\n\t\t\tb:    linesA + linesB + linesC,\n\n\t\t\tmemoryBudget: 2 * 1024 * 1024, // 2MB\n\t\t},\n\t\t{\n\t\t\tname: \"completely different\",\n\t\t\ta:    linesA,\n\t\t\tb:    linesC,\n\n\t\t\tmemoryBudget: 512 * 1024, // 512KB\n\t\t},\n\t\t{\n\t\t\tname: \"large to empty\",\n\n\t\t\ta: linesA + linesB + linesC,\n\t\t\tb: \"\",\n\n\t\t\tmemoryBudget: 6 * 1024 * 1024, // 6MB\n\t\t},\n\t\t{\n\t\t\tname: \"empty to large\",\n\n\t\t\ta: \"\",\n\t\t\tb: linesA + linesB + linesC,\n\n\t\t\tmemoryBudget: 6 * 1024 * 1024, // 6MB\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tdiffer := textdiff.Diff\n\n\t\t\tallocs := MemoryAllocated(func() {\n\t\t\t\t_, err := differ(test.a, test.b)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\trequire.LessOrEqual(t, allocs, test.memoryBudget, \"memory allocations exceeded the budget\")\n\t\t})\n\t}\n}\n\nfunc MemoryAllocated(f func()) uint64 {\n\tdefer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))\n\n\truntime.GC()\n\n\t// Measure the starting statistics\n\tvar memstats runtime.MemStats\n\truntime.ReadMemStats(&memstats)\n\tallocs := 0 - memstats.TotalAlloc\n\n\tf()\n\n\t// Read the final statistics\n\truntime.ReadMemStats(&memstats)\n\tallocs += memstats.TotalAlloc\n\n\treturn allocs\n}\n\nfunc FuzzDiff(f *testing.F) {\n\tf.Add(\"\", \"\")\n\tf.Add(\"line 1\\nline 2\\n\", \"line 1\\nline 2\\n\")\n\tf.Add(\"line 1\\nline 2\\n\", \"line 1\\nline 2\\nline 3\\n\")\n\n\tf.Fuzz(func(t *testing.T, a, b string) {\n\t\t_, err := textdiff.Diff(a, b)\n\t\trequire.NoError(t, err)\n\t})\n}\n"
  },
  {
    "path": "pkg/machinery/version/gen.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build generate\n\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nfunc main() {\n\tdata, err := version.OSRelease()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tif err = os.WriteFile(\"os-release\", data, 0o644); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/machinery/version/os-release",
    "content": "NAME=\"Talos\"\nID=talos\nVERSION_ID=v1.13.0-alpha.2\nPRETTY_NAME=\"Talos (v1.13.0-alpha.2)\"\nHOME_URL=\"https://www.talos.dev/\"\nBUG_REPORT_URL=\"https://github.com/siderolabs/talos/issues\"\nVENDOR_NAME=\"Sidero Labs\"\nVENDOR_URL=\"https://www.siderolabs.com/\"\n"
  },
  {
    "path": "pkg/machinery/version/osrelease.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage version\n\n//go:generate env CGO_ENABLED=0 go run ./gen.go\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\n// OSRelease returns the contents of /etc/os-release.\nfunc OSRelease() ([]byte, error) {\n\tvar v string\n\n\tswitch Tag {\n\tcase \"none\":\n\t\tv = SHA\n\tdefault:\n\t\tv = Tag\n\t}\n\n\treturn OSReleaseFor(Name, v)\n}\n\n// OSReleaseFor returns the contents of /etc/os-release for a given name and version.\nfunc OSReleaseFor(name, version string) ([]byte, error) {\n\treturn fmt.Appendf(nil, constants.OSReleaseTemplate, name, strings.ToLower(name), version), nil\n}\n"
  },
  {
    "path": "pkg/machinery/version/osrelease_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage version_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/version\"\n)\n\nfunc TestOSRelease(t *testing.T) {\n\tt.Parallel()\n\n\t// simply verify generation without errors\n\t_, err := version.OSRelease()\n\trequire.NoError(t, err)\n}\n\nfunc TestOSReleaseFor(t *testing.T) {\n\tt.Parallel()\n\n\tcontents, err := version.OSReleaseFor(\"Talos\", \"v1.0.0\")\n\trequire.NoError(t, err)\n\n\tassert.Equal(\n\t\tt,\n\t\t\"NAME=\\\"Talos\\\"\\nID=talos\\nVERSION_ID=v1.0.0\\nPRETTY_NAME=\\\"Talos (v1.0.0)\\\"\\nHOME_URL=\\\"https://www.talos.dev/\\\"\\nBUG_REPORT_URL=\\\"https://github.com/siderolabs/talos/issues\\\"\\nVENDOR_NAME=\\\"Sidero Labs\\\"\\nVENDOR_URL=\\\"https://www.siderolabs.com/\\\"\\n\", //nolint:lll\n\t\tstring(contents),\n\t)\n}\n"
  },
  {
    "path": "pkg/machinery/version/version.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package version defines version information.\npackage version\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"regexp\"\n\t\"runtime\"\n\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/gendata\"\n)\n\nvar (\n\t// Name is set at build time.\n\tName = gendata.VersionName\n\t// Tag is set at build time.\n\tTag = gendata.VersionTag\n\t// SHA is set at build time.\n\tSHA = gendata.VersionSHA\n\t// Built is set at build time.\n\t// TODO: its not.\n\tBuilt string\n\t// PkgsVersion is set at build time.\n\tPkgsVersion = gendata.VersionPkgs\n)\n\nconst versionTemplate = `\tTag:         %[1]s\n\tSHA:         %[2]s\n\tBuilt:       %[3]s\n\tGo version:  %[4]s\n\tOS/Arch:     %[5]s/%[6]s\n`\n\n// NewVersion prints verbose version information.\nfunc NewVersion() *machineapi.VersionInfo {\n\treturn &machineapi.VersionInfo{\n\t\tTag:       Tag,\n\t\tSha:       SHA,\n\t\tBuilt:     Built,\n\t\tGoVersion: runtime.Version(),\n\t\tOs:        runtime.GOOS,\n\t\tArch:      runtime.GOARCH,\n\t}\n}\n\n// PrintLongVersion prints verbose version information.\nfunc PrintLongVersion() {\n\tprintLong(os.Stdout, NewVersion())\n}\n\n// PrintLongVersionFromExisting prints verbose version information.\nfunc PrintLongVersionFromExisting(v *machineapi.VersionInfo) {\n\tprintLong(os.Stdout, v)\n}\n\n// WriteLongVersionFromExisting writes verbose version to io.Writer.\nfunc WriteLongVersionFromExisting(w io.Writer, v *machineapi.VersionInfo) {\n\tprintLong(w, v)\n}\n\nfunc printLong(w io.Writer, v *machineapi.VersionInfo) {\n\tfmt.Fprintf(w, versionTemplate, v.Tag, v.Sha, v.Built, v.GoVersion, v.Os, v.Arch)\n}\n\n// PrintShortVersion prints the tag and SHA.\nfunc PrintShortVersion() {\n\tfmt.Println(Short())\n}\n\n// Short returns the short version string consist of name, tag and SHA.\nfunc Short() string {\n\treturn fmt.Sprintf(\"%s %s\", Name, Tag)\n}\n\n// Trim removes anything extra after semantic version core, `v0.3.2-1-abcd` -> `v0.3.2`.\nfunc Trim(version string) string {\n\treturn regexp.MustCompile(`(-\\d+(-g[0-9a-f]+)?(-dirty)?)$`).ReplaceAllString(version, \"\")\n}\n"
  },
  {
    "path": "pkg/machinery/yamlutils/yamlutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package yamlutils provides utility types to work with YAML marshaling and unmarshaling.\npackage yamlutils\n\nimport \"bytes\"\n\n// StringBytes is a type that represents a byte slice as a string when marshaled to YAML.\ntype StringBytes []byte\n\n// MarshalYAML implements yaml.Marshaller interface for StringBytes.\nfunc (s StringBytes) MarshalYAML() (any, error) {\n\tif bytes.Equal(bytes.ToValidUTF8(s, nil), s) {\n\t\t// If the byte slice is valid UTF-8, return it as a string.\n\t\treturn string(s), nil\n\t}\n\n\treturn s.Bytes(), nil\n}\n\n// UnmarshalYAML implements yaml.Unmarshaler interface for StringBytes.\nfunc (s *StringBytes) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar str string\n\n\tif err := unmarshal(&str); err == nil {\n\t\t*s = []byte(str)\n\n\t\treturn nil\n\t}\n\n\tvar data []byte\n\n\tif err := unmarshal(&data); err != nil {\n\t\treturn err\n\t}\n\n\t*s = data\n\n\treturn nil\n}\n\n// Bytes returns the byte slice representation of StringBytes.\nfunc (s StringBytes) Bytes() []byte {\n\treturn []byte(s)\n}\n"
  },
  {
    "path": "pkg/machinery/yamlutils/yamlutils_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage yamlutils_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.yaml.in/yaml/v4\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/yamlutils\"\n)\n\nfunc TestStringBytes(t *testing.T) {\n\tt.Parallel()\n\n\ttype sbStruct struct {\n\t\tField yamlutils.StringBytes `yaml:\"field\"`\n\t}\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tin       any\n\t\texpected string\n\n\t\tempty func() any\n\n\t\t// extraMarshaled is a list of strings that should be unmarshaled from YAML into the same `in`\n\t\textraMarshaled []string\n\t}{\n\t\t{\n\t\t\tname: \"simple\",\n\t\t\tin:   &sbStruct{yamlutils.StringBytes([]byte(\"abcde\"))},\n\n\t\t\texpected: \"field: abcde\\n\",\n\t\t\tempty: func() any {\n\t\t\t\treturn &sbStruct{}\n\t\t\t},\n\t\t\textraMarshaled: []string{\n\t\t\t\t\"field:\\n - 0x61\\n - 0x62\\n - 0x63\\n - 0x64\\n - 0x65\\n\",\n\t\t\t\t\"field:\\n    - 97\\n    - 98\\n    - 99\\n    - 100\\n    - 101\\n\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"empty\",\n\t\t\tin:   &sbStruct{yamlutils.StringBytes([]byte{})},\n\n\t\t\texpected: \"field: \\\"\\\"\\n\",\n\t\t\tempty: func() any {\n\t\t\t\treturn &sbStruct{}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid utf8\",\n\t\t\tin:   &sbStruct{yamlutils.StringBytes([]byte{0xff})},\n\n\t\t\texpected: \"field:\\n    - 255\\n\",\n\t\t\tempty: func() any {\n\t\t\t\treturn &sbStruct{}\n\t\t\t},\n\n\t\t\textraMarshaled: []string{\n\t\t\t\t\"field:\\n - 0xff\\n\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tout, err := yaml.Marshal(test.in)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.expected, string(out))\n\n\t\t\tback := test.empty()\n\n\t\t\terr = yaml.Unmarshal(out, back)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, test.in, back)\n\n\t\t\tfor _, extra := range test.extraMarshaled {\n\t\t\t\tback := test.empty()\n\n\t\t\t\terr = yaml.Unmarshal([]byte(extra), back)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, test.in, back)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/makefs/ext4.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\n\t\"github.com/siderolabs/talos/pkg/imager/utils\"\n)\n\nconst (\n\t// FilesystemTypeEXT4 is the filesystem type for EXT4.\n\tFilesystemTypeEXT4 = \"ext4\"\n)\n\n// Ext4 creates a ext4 filesystem on the specified partition.\n//\n//nolint:gocyclo\nfunc Ext4(ctx context.Context, partname string, setters ...Option) error {\n\tif partname == \"\" {\n\t\treturn errors.New(\"missing path to disk\")\n\t}\n\n\topts := NewDefaultOptions(setters...)\n\n\tvar args []string\n\n\tif opts.Label != \"\" {\n\t\targs = append(args, \"-L\", opts.Label)\n\t}\n\n\tif opts.Force {\n\t\targs = append(args, \"-F\")\n\t}\n\n\tif opts.Reproducible {\n\t\tif opts.Label == \"\" {\n\t\t\treturn errors.New(\"label must be set for reproducible ext4 filesystem\")\n\t\t}\n\n\t\tpartitionGUID := GUIDFromLabel(opts.Label)\n\n\t\targs = append(args, \"-U\", partitionGUID.String())\n\t\targs = append(args, \"-E\", fmt.Sprintf(\"hash_seed=%s\", partitionGUID.String()))\n\t}\n\n\tvar errCh chan error\n\n\t// Use a tar archive instead of passing a source directory directly to mke2fs.\n\t// This allows us to force all files in the image to be owned by root (uid/gid 0)\n\t// regardless of their ownership on the host, enabling rootless operation without\n\t// requiring elevated privileges.\n\tif opts.SourceDirectory != \"\" {\n\t\terrCh = make(chan error, 1)\n\n\t\tpr, pw, err := os.Pipe()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create pipe: %w\", err)\n\t\t}\n\n\t\tdefer pr.Close() //nolint:errcheck\n\n\t\targs = append(args, \"-d\", \"-\")\n\n\t\tctx = cmd.WithStdin(ctx, pr)\n\n\t\tgo func() {\n\t\t\tdefer pw.Close() //nolint:errcheck\n\n\t\t\terrCh <- handleTarArchive(ctx, opts.SourceDirectory, pw)\n\t\t}()\n\t}\n\n\targs = append(args, partname)\n\n\topts.Printf(\"creating ext4 filesystem on %s with args: %v\", partname, args)\n\n\t_, err := cmd.RunWithOptions(ctx, \"mkfs.ext4\", args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif errCh != nil {\n\t\treturn <-errCh\n\t}\n\n\treturn nil\n}\n\n// Ext4Resize expands a ext4 filesystem to the maximum possible.\nfunc Ext4Resize(ctx context.Context, partname string) error {\n\t// resizing the filesystem requires a check first\n\tif err := Ext4Repair(ctx, partname); err != nil {\n\t\treturn fmt.Errorf(\"failed to repair before growing ext4 filesystem: %w\", err)\n\t}\n\n\t_, err := cmd.RunWithOptions(ctx, \"resize2fs\", []string{partname})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to grow ext4 filesystem: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Ext4Repair repairs a ext4 filesystem.\nfunc Ext4Repair(ctx context.Context, partname string) error {\n\t_, err := cmd.RunWithOptions(ctx, \"e2fsck\", []string{\"-f\", \"-p\", partname})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to repair ext4 filesystem: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// handleTarArchive creates a tar archive from the sourceDir and writes it to the provided\n// io.WriteCloser.\nfunc handleTarArchive(ctx context.Context, sourceDir string, w io.WriteCloser) error {\n\ttimestamp, ok, err := utils.SourceDateEpoch()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get SOURCE_DATE_EPOCH: %w\", err)\n\t}\n\n\tif !ok {\n\t\ttimestamp = time.Now().Unix()\n\t}\n\n\tcmd := exec.CommandContext(\n\t\tctx,\n\t\t\"tar\",\n\t\t\"-cf\",\n\t\t\"-\",\n\t\t\"-C\",\n\t\tsourceDir,\n\t\t\"--sort=name\",\n\t\t\"--owner=0\",\n\t\t\"--group=0\",\n\t\t\"--numeric-owner\",\n\t\t\"--mtime=@\"+strconv.FormatInt(timestamp, 10),\n\t\t\".\",\n\t)\n\n\tcmd.Stdout = w\n\tcmd.Stderr = os.Stderr\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"failed to start tar command: %w\", err)\n\t}\n\n\tcloseErr := w.Close()\n\twaitErr := cmd.Wait()\n\n\tif closeErr != nil {\n\t\treturn fmt.Errorf(\"failed to close pipe writer: %w\", closeErr)\n\t}\n\n\treturn waitErr\n}\n"
  },
  {
    "path": "pkg/makefs/ext4_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs_test\n\nimport (\n\t\"crypto/sha256\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\n// TestExt4Reproducibility tests that the ext4 filesystem is reproducible.\nfunc TestExt4Reproducibility(t *testing.T) {\n\tt.Setenv(\"PATH\", \"/usr/bin:/bin:/usr/sbin:/sbin\")\n\tt.Setenv(\"SOURCE_DATE_EPOCH\", \"1234567890\")\n\n\ttmpDir := t.TempDir()\n\n\ttempFile := filepath.Join(tmpDir, \"reproducible-ext4.img\")\n\n\tf, err := os.Create(tempFile)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f.Truncate(512*1024*1024))\n\trequire.NoError(t, f.Close())\n\n\tsourceDirectory := filepath.Join(tmpDir, \"source\")\n\n\tpopulateTestDir(t, sourceDirectory, []string{\n\t\t\"file1.txt\",\n\t\t\"dir1/\",\n\t\t\"dir1/file2.txt\",\n\t\t\"dir1/subdir1/\",\n\t\t\"dir1/subdir1/file3.txt\",\n\t})\n\n\trequire.NoError(t, makefs.Ext4(t.Context(),\n\t\ttempFile,\n\t\tmakefs.WithReproducible(true),\n\t\tmakefs.WithLabel(\"TESTLABEL\"),\n\t\tmakefs.WithSourceDirectory(sourceDirectory),\n\t))\n\n\tfileData, err := os.Open(tempFile)\n\trequire.NoError(t, err)\n\n\tsum1 := sha256.New()\n\n\t_, err = io.Copy(sum1, fileData)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, fileData.Close())\n\n\t// create the filesystem again\n\trequire.NoError(t, makefs.Ext4(t.Context(),\n\t\ttempFile,\n\t\tmakefs.WithReproducible(true),\n\t\tmakefs.WithLabel(\"TESTLABEL\"),\n\t\tmakefs.WithSourceDirectory(sourceDirectory),\n\t\tmakefs.WithForce(true)))\n\n\tfileData, err = os.Open(tempFile)\n\trequire.NoError(t, err)\n\n\tsum2 := sha256.New()\n\n\t_, err = io.Copy(sum2, fileData)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, fileData.Close())\n\n\tassert.Equal(t, sum1.Sum(nil), sum2.Sum(nil), \"ext4 filesystem is not reproducible\")\n}\n\n// TestExt4Resize tests that the ext4 filesystem can be resized.\nfunc TestExt4Resize(t *testing.T) {\n\tt.Setenv(\"PATH\", \"/usr/bin:/bin:/usr/sbin:/sbin\")\n\n\ttmpDir := t.TempDir()\n\n\ttempFile := filepath.Join(tmpDir, \"resize-ext4.img\")\n\n\tif _, err := os.Create(tempFile); err != nil {\n\t\tt.Fatalf(\"failed to create file: %v\", err)\n\t}\n\n\tif err := os.Truncate(tempFile, 64*1024*1024); err != nil {\n\t\tt.Fatalf(\"failed to create file: %v\", err)\n\t}\n\n\tif err := makefs.Ext4(t.Context(), tempFile); err != nil {\n\t\tt.Fatalf(\"failed to create ext4 filesystem: %v\", err)\n\t}\n\n\tif err := os.Truncate(tempFile, 128*1024*1024); err != nil {\n\t\tt.Fatalf(\"failed to resize file: %v\", err)\n\t}\n\n\tassert.NoError(t, makefs.Ext4Resize(t.Context(), tempFile))\n}\n"
  },
  {
    "path": "pkg/makefs/makefs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package makefs provides function to format and grow filesystems.\npackage makefs\n\nimport (\n\t\"crypto/sha256\"\n\n\t\"github.com/google/uuid\"\n)\n\n// Option to control makefs settings.\ntype Option func(*Options)\n\n// Options for makefs.\ntype Options struct {\n\tLabel               string\n\tConfigFile          string\n\tSourceDirectory     string\n\tForce               bool\n\tReproducible        bool\n\tUnsupportedFSOption bool\n\n\tPrintf func(string, ...any)\n}\n\n// WithLabel sets the label for the filesystem to be created.\nfunc WithLabel(label string) Option {\n\treturn func(o *Options) {\n\t\to.Label = label\n\t}\n}\n\n// WithForce forces creation of a filesystem even if one already exists.\nfunc WithForce(force bool) Option {\n\treturn func(o *Options) {\n\t\to.Force = force\n\t}\n}\n\n// WithReproducible sets the reproducible flag for the filesystem to be created.\n// This should only be used when creating filesystems on raw disk images.\nfunc WithReproducible(reproducible bool) Option {\n\treturn func(o *Options) {\n\t\to.Reproducible = reproducible\n\t}\n}\n\n// WithUnsupportedFSOption sets the unsupported filesystem option.\nfunc WithUnsupportedFSOption(unsupported bool) Option {\n\treturn func(o *Options) {\n\t\to.UnsupportedFSOption = unsupported\n\t}\n}\n\n// WithConfigFile sets the config file for the filesystem to be created.\nfunc WithConfigFile(configFile string) Option {\n\treturn func(o *Options) {\n\t\to.ConfigFile = configFile\n\t}\n}\n\n// WithSourceDirectory sets the source directory for populating the filesystem.\nfunc WithSourceDirectory(sourceDir string) Option {\n\treturn func(o *Options) {\n\t\to.SourceDirectory = sourceDir\n\t}\n}\n\n// WithPrintf sets the printf function for logging.\nfunc WithPrintf(printf func(string, ...any)) Option {\n\treturn func(o *Options) {\n\t\to.Printf = printf\n\t}\n}\n\n// NewDefaultOptions builds options with specified setters applied.\nfunc NewDefaultOptions(setters ...Option) Options {\n\tvar opt Options\n\n\tfor _, o := range setters {\n\t\to(&opt)\n\t}\n\n\tif opt.Printf == nil {\n\t\topt.Printf = func(string, ...any) {}\n\t}\n\n\treturn opt\n}\n\n// GUIDFromLabel generates a deterministic partition GUID from a label by\n// creating a version 8 UUID derived from a SHA-256 hash of the label bytes.\nfunc GUIDFromLabel(label string) uuid.UUID {\n\t// version 8 UUID since we're doing custom hashing\n\treturn uuid.NewHash(sha256.New(), uuid.Nil, []byte(label), 8)\n}\n"
  },
  {
    "path": "pkg/makefs/makefs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\nfunc TestPartitionGUIDFromLabel(t *testing.T) {\n\ttests := []struct {\n\t\tlabel    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tlabel:    constants.EFIPartitionLabel,\n\t\t\texpected: \"bca5174b-0118-8a6a-af0b-2c6e1585acae\",\n\t\t},\n\t\t{\n\t\t\tlabel:    constants.BootPartitionLabel,\n\t\t\texpected: \"24c73076-4092-85dd-9d98-686a2dbf6d81\",\n\t\t},\n\t\t{\n\t\t\tlabel:    constants.MetaPartitionLabel,\n\t\t\texpected: \"cf04f137-101e-8ec6-9627-fa3f51cdabb8\",\n\t\t},\n\t\t{\n\t\t\tlabel:    constants.ImageCachePartitionLabel,\n\t\t\texpected: \"3b5449bc-c21f-8009-8b51-18945967f8df\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.label, func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.expected, makefs.GUIDFromLabel(tt.label).String())\n\t\t})\n\t}\n}\n\n// populateTestDir is a helper function to populate a test directory with files,\n// it can handle nested files and directories, file content is populated with the name of the file.\n// All files are created relative to the provided dir.\nfunc populateTestDir(t *testing.T, dir string, files []string) {\n\tt.Helper()\n\n\tfor _, file := range files {\n\t\tfullPath := filepath.Join(dir, file)\n\n\t\tif strings.HasSuffix(file, \"/\") {\n\t\t\trequire.NoError(t, os.MkdirAll(fullPath, 0o755))\n\t\t} else {\n\t\t\trequire.NoError(t, os.MkdirAll(filepath.Dir(fullPath), 0o755))\n\t\t\trequire.NoError(t, os.WriteFile(fullPath, []byte(file), 0o644))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/makefs/protofile.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// GenerateProtofile walks a filesystem tree and generates an XFS protofile.\n// All files and directories will have uid/gid mapped to 0:0.\nfunc GenerateProtofile(sourcePath string) (io.Reader, error) {\n\tvar buf bytes.Buffer\n\n\t// Emit protofile header\n\tfmt.Fprintln(&buf, \"/\")\n\tfmt.Fprintln(&buf, \"0 0\")\n\n\t// Get stat of the root directory\n\tstatbuf, err := os.Stat(sourcePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to stat path %s: %w\", sourcePath, err)\n\t}\n\n\tif !statbuf.IsDir() {\n\t\treturn nil, fmt.Errorf(\"path %s is not a directory\", sourcePath)\n\t}\n\n\t// Write root directory stat\n\tfmt.Fprintln(&buf, statToProtoStr(statbuf))\n\t// Walk the tree\n\tif err := walkTree(&buf, sourcePath, 1); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfmt.Fprintln(&buf, \"$\")\n\n\treturn &buf, nil\n}\n\n// statToProtoStr converts a FileInfo to a proto string.\nfunc statToProtoStr(info fs.FileInfo) string {\n\tmode := info.Mode()\n\n\tvar fileType rune\n\n\tswitch {\n\tcase mode.IsRegular():\n\t\tfileType = '-'\n\tcase mode&fs.ModeCharDevice != 0:\n\t\tfileType = 'c'\n\tcase mode&fs.ModeDevice != 0:\n\t\tfileType = 'b'\n\tcase mode&fs.ModeNamedPipe != 0:\n\t\tfileType = 'p'\n\tcase mode.IsDir():\n\t\tfileType = 'd'\n\tcase mode&fs.ModeSymlink != 0:\n\t\tfileType = 'l'\n\tdefault:\n\t\tfileType = '-'\n\t}\n\n\tvar suid, sgid rune\n\tif mode&fs.ModeSetuid != 0 {\n\t\tsuid = 'u'\n\t} else {\n\t\tsuid = '-'\n\t}\n\n\tif mode&fs.ModeSetgid != 0 {\n\t\tsgid = 'g'\n\t} else {\n\t\tsgid = '-'\n\t}\n\n\t// Extract permissions (mask out file type and special bits)\n\tperms := mode.Perm()\n\n\treturn fmt.Sprintf(\"%c%c%c%03o %d %d\", fileType, suid, sgid, perms, 0, 0)\n}\n\n// statToExtra computes the extras column for a protofile entry.\nfunc statToExtra(info fs.FileInfo, fullpath string) (string, error) {\n\tmode := info.Mode()\n\n\tswitch {\n\tcase mode.IsRegular():\n\t\treturn fmt.Sprintf(\" %s\", fullpath), nil\n\tcase mode&fs.ModeCharDevice != 0, mode&fs.ModeDevice != 0:\n\t\tif sys := info.Sys(); sys != nil {\n\t\t\tif stat, ok := sys.(*syscall.Stat_t); ok {\n\t\t\t\tmajor := unix.Major(stat.Rdev)\n\t\t\t\tminor := unix.Minor(stat.Rdev)\n\n\t\t\t\treturn fmt.Sprintf(\" %d %d\", major, minor), nil\n\t\t\t}\n\t\t}\n\n\t\treturn \" 0 0\", nil\n\tcase mode&fs.ModeSymlink != 0:\n\t\ttarget, err := os.Readlink(fullpath)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to read symlink %s: %w\", fullpath, err)\n\t\t}\n\n\t\treturn fmt.Sprintf(\" %s\", target), nil\n\t}\n\n\treturn \"\", nil\n}\n\n// walkTree walks the directory tree rooted by path.\n//\n//nolint:gocyclo\nfunc walkTree(w io.Writer, path string, depth int) error {\n\ttype entry struct {\n\t\tname     string\n\t\tfullpath string\n\t\tinfo     fs.FileInfo\n\t\tisDir    bool\n\t}\n\n\tvar entries []entry\n\n\terr := filepath.WalkDir(path, func(p string, d fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// Skip the root directory itself\n\t\tif p == path {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Only process direct children of the current path\n\t\trel, err := filepath.Rel(path, p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif strings.Contains(rel, string(filepath.Separator)) {\n\t\t\treturn filepath.SkipDir\n\t\t}\n\n\t\tinfo, err := d.Info()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to stat %s: %w\", p, err)\n\t\t}\n\n\t\t// Skip sockets\n\t\tif info.Mode()&fs.ModeSocket != 0 {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Validate no spaces in name\n\t\tif strings.Contains(d.Name(), \" \") {\n\t\t\treturn fmt.Errorf(\"spaces not allowed in file names: %s\", d.Name())\n\t\t}\n\n\t\tentries = append(entries, entry{\n\t\t\tname:     d.Name(),\n\t\t\tfullpath: p,\n\t\t\tinfo:     info,\n\t\t\tisDir:    d.IsDir(),\n\t\t})\n\n\t\t// Skip descending into directories, as we'll recurse manually later\n\t\tif d.IsDir() {\n\t\t\treturn filepath.SkipDir\n\t\t}\n\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to walk directory %s: %w\", path, err)\n\t}\n\n\t// Print files first\n\tfor _, e := range entries {\n\t\tif !e.isDir {\n\t\t\textra, err := statToExtra(e.info, e.fullpath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tindent := strings.Repeat(\" \", depth)\n\t\t\tfmt.Fprintf(w, \"%s%s %s%s\\n\", indent, e.name, statToProtoStr(e.info), extra)\n\t\t}\n\t}\n\n\t// Print and recurse into directories\n\tfor _, e := range entries {\n\t\tif e.isDir {\n\t\t\textra, err := statToExtra(e.info, e.fullpath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tindent := strings.Repeat(\" \", depth)\n\t\t\tfmt.Fprintf(w, \"%s%s %s%s\\n\", indent, e.name, statToProtoStr(e.info), extra)\n\n\t\t\tif err := walkTree(w, e.fullpath, depth+1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// Close directory marker (except for depth 1)\n\tif depth > 1 {\n\t\tindent := strings.Repeat(\" \", depth-1)\n\t\tfmt.Fprintf(w, \"%s$\\n\", indent)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/makefs/protofile_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs_test\n\nimport (\n\t_ \"embed\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\nfunc TestGenerateProtofile(t *testing.T) {\n\ttests := []struct {\n\t\tname      string\n\t\tprotoFile string\n\t\tsetupFunc func(t *testing.T, dir string)\n\t}{\n\t\t{\n\t\t\tname:      \"simple directory with files\",\n\t\t\tprotoFile: \"testdata/simple_directory.proto\",\n\t\t\tsetupFunc: func(t *testing.T, dir string) {\n\t\t\t\tpopulateTestDir(t, dir, []string{\n\t\t\t\t\t\"file1.txt\",\n\t\t\t\t\t\"file2.txt\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"nested directories\",\n\t\t\tprotoFile: \"testdata/nested_directories.proto\",\n\t\t\tsetupFunc: func(t *testing.T, dir string) {\n\t\t\t\tpopulateTestDir(t, dir, []string{\n\t\t\t\t\t\"subdir/\",\n\t\t\t\t\t\"root.txt\",\n\t\t\t\t\t\"subdir/nested.txt\",\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\tname:      \"symlinks\",\n\t\t\tprotoFile: \"testdata/symlinks.proto\",\n\t\t\tsetupFunc: func(t *testing.T, dir string) {\n\t\t\t\tpopulateTestDir(t, dir, []string{\n\t\t\t\t\t\"target.txt\",\n\t\t\t\t})\n\n\t\t\t\tlink := filepath.Join(dir, \"link.txt\")\n\t\t\t\trequire.NoError(t, os.Symlink(\"target.txt\", link))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"deeply nested directories\",\n\t\t\tprotoFile: \"testdata/deeply_nested.proto\",\n\t\t\tsetupFunc: func(t *testing.T, dir string) {\n\t\t\t\tpopulateTestDir(t, dir, []string{\n\t\t\t\t\t\"root1.txt\",\n\t\t\t\t\t\"root2.txt\",\n\t\t\t\t\t\"subdir/\",\n\t\t\t\t\t\"subdir/file1.txt\",\n\t\t\t\t\t\"subdir/file2.txt\",\n\t\t\t\t\t\"subdir/nested/\",\n\t\t\t\t\t\"subdir/nested/deep.txt\",\n\t\t\t\t\t\"anotherdir/\",\n\t\t\t\t\t\"anotherdir/file.txt\",\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\ttmpDir := t.TempDir()\n\t\t\ttestDir := filepath.Join(tmpDir, \"testdata\")\n\t\t\trequire.NoError(t, os.Mkdir(testDir, 0o755))\n\n\t\t\ttt.setupFunc(t, testDir)\n\n\t\t\tr, err := makefs.GenerateProtofile(testDir)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tprotoFileData, err := io.ReadAll(r)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Read expected protofile\n\t\t\tprotoData, err := os.ReadFile(tt.protoFile)\n\t\t\trequire.NoError(t, err, \"failed to read protofile %s\", tt.protoFile)\n\n\t\t\tprotoDataStr := strings.ReplaceAll(string(protoData), \"FILEPATH\", testDir)\n\n\t\t\tassert.Equal(t, protoDataStr, string(protoFileData), \"protofile output does not match expected %s\", tt.protoFile)\n\t\t})\n\t}\n}\n\nfunc TestProtofileRejectsSpaces(t *testing.T) {\n\ttmpDir := t.TempDir()\n\ttestDir := filepath.Join(tmpDir, \"testdata\")\n\trequire.NoError(t, os.Mkdir(testDir, 0o755))\n\n\t// Create a file with space in name\n\trequire.NoError(t, os.WriteFile(filepath.Join(testDir, \"file with space.txt\"), []byte(\"content\"), 0o644))\n\n\t_, err := makefs.GenerateProtofile(testDir)\n\trequire.Error(t, err)\n\n\tassert.Contains(t, err.Error(), \"spaces not allowed\")\n}\n\nfunc TestProtofileErrorCases(t *testing.T) {\n\tt.Run(\"nonexistent directory\", func(t *testing.T) {\n\t\t_, err := makefs.GenerateProtofile(\"/nonexistent/path\")\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"not a directory\", func(t *testing.T) {\n\t\ttmpDir := t.TempDir()\n\t\tfilePath := filepath.Join(tmpDir, \"file.txt\")\n\t\trequire.NoError(t, os.WriteFile(filePath, []byte(\"content\"), 0o644))\n\n\t\t_, err := makefs.GenerateProtofile(filePath)\n\t\trequire.Error(t, err)\n\n\t\tassert.Contains(t, err.Error(), \"not a directory\")\n\t})\n}\n"
  },
  {
    "path": "pkg/makefs/testdata/deeply_nested.proto",
    "content": "/\n0 0\nd--755 0 0\n root1.txt ---644 0 0 FILEPATH/root1.txt\n root2.txt ---644 0 0 FILEPATH/root2.txt\n anotherdir d--755 0 0\n  file.txt ---644 0 0 FILEPATH/anotherdir/file.txt\n $\n subdir d--755 0 0\n  file1.txt ---644 0 0 FILEPATH/subdir/file1.txt\n  file2.txt ---644 0 0 FILEPATH/subdir/file2.txt\n  nested d--755 0 0\n   deep.txt ---644 0 0 FILEPATH/subdir/nested/deep.txt\n  $\n $\n$\n"
  },
  {
    "path": "pkg/makefs/testdata/nested_directories.proto",
    "content": "/\n0 0\nd--755 0 0\n root.txt ---644 0 0 FILEPATH/root.txt\n subdir d--755 0 0\n  nested.txt ---644 0 0 FILEPATH/subdir/nested.txt\n $\n$\n"
  },
  {
    "path": "pkg/makefs/testdata/simple_directory.proto",
    "content": "/\n0 0\nd--755 0 0\n file1.txt ---644 0 0 FILEPATH/file1.txt\n file2.txt ---644 0 0 FILEPATH/file2.txt\n$\n"
  },
  {
    "path": "pkg/makefs/testdata/symlinks.proto",
    "content": "/\n0 0\nd--755 0 0\n link.txt l--777 0 0 target.txt\n target.txt ---644 0 0 FILEPATH/target.txt\n$\n"
  },
  {
    "path": "pkg/makefs/vfat.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n)\n\nconst (\n\t// FilesystemTypeVFAT is the filesystem type for VFAT.\n\tFilesystemTypeVFAT = \"vfat\"\n)\n\n// VFAT creates a VFAT filesystem on the specified partition.\nfunc VFAT(ctx context.Context, partname string, setters ...Option) error {\n\topts := NewDefaultOptions(setters...)\n\n\tvar args []string\n\n\tif opts.Label != \"\" {\n\t\targs = append(args, \"-F\", \"32\", \"-n\", opts.Label)\n\t}\n\n\tif opts.Reproducible {\n\t\targs = append(args, \"--invariant\")\n\t}\n\n\targs = append(args, partname)\n\n\t_, err := cmd.RunWithOptions(ctx, \"mkfs.vfat\", args)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// If source directory is specified, populate the filesystem using mtools\n\tif opts.SourceDirectory != \"\" {\n\t\tif err := populateVFAT(ctx, partname, opts.SourceDirectory); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to populate VFAT filesystem: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// populateVFAT populates a VFAT filesystem on the given partition with the\n// contents of sourceDir.\nfunc populateVFAT(ctx context.Context, partname, sourceDir string) error {\n\tentries, err := os.ReadDir(sourceDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read source directory %q: %w\", sourceDir, err)\n\t}\n\n\tfor _, entry := range entries {\n\t\tswitch {\n\t\tcase entry.Type().IsDir():\n\t\t\t// copy directories\n\t\tcase entry.Type().IsRegular():\n\t\t\t// copy regular files\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported file type for entry %q in source directory %q\", entry.Name(), sourceDir)\n\t\t}\n\n\t\tif _, err := cmd.RunWithOptions(\n\t\t\tctx,\n\t\t\t\"mcopy\",\n\t\t\t[]string{\n\t\t\t\t\"-s\", // recursive\n\t\t\t\t\"-p\", // preserve attributes\n\t\t\t\t\"-Q\", // quit on error\n\t\t\t\t\"-m\", // preserve modification time\n\t\t\t\t\"-i\",\n\t\t\t\tpartname,\n\t\t\t\tfilepath.Join(sourceDir, entry.Name()),\n\t\t\t\t\"::\",\n\t\t\t},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/makefs/vfat_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs_test\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\nfunc TestVFATWithSourceDirectory(t *testing.T) {\n\t_, err := exec.LookPath(\"mcopy\")\n\tif err != nil {\n\t\tt.Skip(\"mcopy not found in PATH, skipping test\")\n\t}\n\n\ttempDir := t.TempDir()\n\n\t// Create source directory structure\n\tsourceDir := filepath.Join(tempDir, \"source\")\n\trequire.NoError(t, os.MkdirAll(filepath.Join(sourceDir, \"subdir\"), 0o755))\n\n\t// Create test files\n\trequire.NoError(t, os.WriteFile(filepath.Join(sourceDir, \"file1.txt\"), []byte(\"content1\"), 0o644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(sourceDir, \"file2.txt\"), []byte(\"content2\"), 0o644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(sourceDir, \"subdir\", \"file3.txt\"), []byte(\"content3\"), 0o644))\n\n\t// Create VFAT image\n\tvfatImg := filepath.Join(tempDir, \"test.img\")\n\n\t// Create a 10MB image file\n\tf, err := os.Create(vfatImg)\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Truncate(10*1024*1024))\n\trequire.NoError(t, f.Close())\n\n\t// Format and populate VFAT\n\terr = makefs.VFAT(t.Context(), vfatImg, makefs.WithLabel(\"TEST\"), makefs.WithSourceDirectory(sourceDir))\n\trequire.NoError(t, err)\n\n\t// Verify file contents using mcopy\n\textractDir := filepath.Join(tempDir, \"extract\")\n\trequire.NoError(t, os.MkdirAll(extractDir, 0o755))\n\n\t// Extract all files\n\t_, err = cmd.RunWithOptions(t.Context(), \"mcopy\", []string{\"-s\", \"-i\", vfatImg, \"::/\", extractDir})\n\trequire.NoError(t, err)\n\n\t// Verify extracted files with full filenames\n\tcontent, err := os.ReadFile(filepath.Join(extractDir, \"file1.txt\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"content1\", string(content))\n\n\tcontent, err = os.ReadFile(filepath.Join(extractDir, \"file2.txt\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"content2\", string(content))\n\n\tcontent, err = os.ReadFile(filepath.Join(extractDir, \"subdir\", \"file3.txt\"))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"content3\", string(content))\n}\n"
  },
  {
    "path": "pkg/makefs/xfs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\t// FilesystemTypeXFS is the filesystem type for XFS.\n\tFilesystemTypeXFS = \"xfs\"\n)\n\n// XFSGrow expands a XFS filesystem to the maximum possible. The partition\n// MUST be mounted, or this will fail.\nfunc XFSGrow(ctx context.Context, partname string) error {\n\t_, err := cmd.RunWithOptions(ctx, \"xfs_growfs\", []string{\"-d\", partname})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to grow XFS filesystem: %w\", err)\n\t}\n\n\treturn err\n}\n\n// XFSRepair repairs a XFS filesystem on the specified partition.\nfunc XFSRepair(ctx context.Context, partname string) error {\n\t_, err := cmd.RunWithOptions(ctx, \"xfs_repair\", []string{partname})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error repairing XFS filesystem: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// XFS creates a XFS filesystem on the specified partition.\n//\n//nolint:gocyclo\nfunc XFS(ctx context.Context, partname string, setters ...Option) error {\n\tif partname == \"\" {\n\t\treturn errors.New(\"missing path to disk\")\n\t}\n\n\topts := NewDefaultOptions(setters...)\n\n\t// The ftype=1 naming option is required by overlayfs.\n\targs := []string{\"-n\", \"ftype=1\"}\n\n\tif opts.ConfigFile != \"\" {\n\t\targs = append(args, \"-c\", fmt.Sprintf(\"options=%s\", opts.ConfigFile))\n\t}\n\n\tif opts.Force {\n\t\targs = append(args, \"-f\")\n\t}\n\n\tif opts.Label != \"\" {\n\t\targs = append(args, \"-L\", opts.Label)\n\t}\n\n\tif opts.UnsupportedFSOption {\n\t\targs = append(args, \"--unsupported\")\n\t}\n\n\tif opts.SourceDirectory != \"\" {\n\t\tr, err := GenerateProtofile(opts.SourceDirectory)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to generate protofile: %w\", err)\n\t\t}\n\n\t\tfd, err := unix.MemfdCreate(\"protofile\", 0)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error creating memfd for protofile: %w\", err)\n\t\t}\n\n\t\tprotoMemfd := os.NewFile(uintptr(fd), \"protofile\")\n\t\tdefer protoMemfd.Close() //nolint:errcheck\n\n\t\t_, err = io.Copy(protoMemfd, r)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write protofile to memfd: %w\", err)\n\t\t}\n\n\t\t// Seek back to the beginning so mkfs.xfs can read from start\n\t\tif _, err := protoMemfd.Seek(0, 0); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to seek protofile: %w\", err)\n\t\t}\n\n\t\targs = append(args, \"-p\", fmt.Sprintf(\"file=/proc/self/fd/%d\", protoMemfd.Fd()))\n\t}\n\n\tif opts.Reproducible {\n\t\tif opts.Label == \"\" {\n\t\t\treturn errors.New(\"label must be set for reproducible XFS filesystem\")\n\t\t}\n\n\t\tpartitionGUID := GUIDFromLabel(opts.Label)\n\n\t\targs = append(args, \"-m\", fmt.Sprintf(\"uuid=%s\", partitionGUID.String()))\n\t}\n\n\targs = append(args, partname)\n\n\topts.Printf(\"creating xfs filesystem on %s with args: %v\", partname, args)\n\n\t_, err := cmd.RunWithOptions(ctx, \"mkfs.xfs\", args)\n\n\treturn err\n}\n"
  },
  {
    "path": "pkg/makefs/xfs_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage makefs_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n)\n\nfunc TestXFSInfo(t *testing.T) { //nolint:tparallel\n\tt.Setenv(\"PATH\", \"/usr/bin:/bin:/usr/sbin:/sbin\")\n\n\tfor _, test := range []struct {\n\t\tname string\n\n\t\tsize int64\n\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"1G\",\n\n\t\t\tsize: 1024 * 1024 * 1024,\n\n\t\t\texpected: `meta-data=image isize=512    agcount=4, agsize=65536 blks\n         =                       sectsz=512   attr=2, projid32bit=1\n         =                       crc=1        finobt=1, sparse=1, rmapbt=1\n         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=1\n         =                       exchange=1   metadir=0\ndata     =                       bsize=4096   blocks=262144, imaxpct=25\n         =                       sunit=0      swidth=0 blks\nnaming   =version 2              bsize=4096   ascii-ci=0, ftype=1, parent=1\nlog      =internal log           bsize=4096   blocks=16384, version=2\n         =                       sectsz=512   sunit=0 blks, lazy-count=1\nrealtime =none                   extsz=4096   blocks=0, rtextents=0\n         =                       rgcount=0    rgsize=0 extents\n         =                       zoned=0      start=0 reserved=0\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"10G\",\n\n\t\t\tsize: 10 * 1024 * 1024 * 1024,\n\n\t\t\texpected: `meta-data=image isize=512    agcount=4, agsize=655360 blks\n         =                       sectsz=512   attr=2, projid32bit=1\n         =                       crc=1        finobt=1, sparse=1, rmapbt=1\n         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=1\n         =                       exchange=1   metadir=0\ndata     =                       bsize=4096   blocks=2621440, imaxpct=25\n         =                       sunit=0      swidth=0 blks\nnaming   =version 2              bsize=4096   ascii-ci=0, ftype=1, parent=1\nlog      =internal log           bsize=4096   blocks=16384, version=2\n         =                       sectsz=512   sunit=0 blks, lazy-count=1\nrealtime =none                   extsz=4096   blocks=0, rtextents=0\n         =                       rgcount=0    rgsize=0 extents\n         =                       zoned=0      start=0 reserved=0\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"100G\",\n\n\t\t\tsize: 100 * 1024 * 1024 * 1024,\n\n\t\t\texpected: `meta-data=image isize=512    agcount=4, agsize=6553600 blks\n         =                       sectsz=512   attr=2, projid32bit=1\n         =                       crc=1        finobt=1, sparse=1, rmapbt=1\n         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=1\n         =                       exchange=1   metadir=0\ndata     =                       bsize=4096   blocks=26214400, imaxpct=25\n         =                       sunit=0      swidth=0 blks\nnaming   =version 2              bsize=4096   ascii-ci=0, ftype=1, parent=1\nlog      =internal log           bsize=4096   blocks=16384, version=2\n         =                       sectsz=512   sunit=0 blks, lazy-count=1\nrealtime =none                   extsz=4096   blocks=0, rtextents=0\n         =                       rgcount=0    rgsize=0 extents\n         =                       zoned=0      start=0 reserved=0\n`,\n\t\t},\n\t} {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttmpDir := t.TempDir()\n\n\t\t\ttempFile := filepath.Join(tmpDir, \"xfs.img\")\n\n\t\t\trequire.NoError(t, os.WriteFile(tempFile, nil, 0o644))\n\t\t\trequire.NoError(t, os.Truncate(tempFile, test.size))\n\n\t\t\trequire.NoError(t, makefs.XFS(t.Context(), tempFile))\n\n\t\t\tvar stdout bytes.Buffer\n\n\t\t\tcmd := exec.CommandContext(t.Context(), \"xfs_db\", \"-p\", \"xfs_info\", \"-c\", \"info\", tempFile)\n\t\t\tcmd.Stdout = &stdout\n\t\t\trequire.NoError(t, cmd.Run())\n\n\t\t\tactual := strings.ReplaceAll(stdout.String(), tempFile, \"image\")\n\n\t\t\tassert.Equal(t, test.expected, actual)\n\t\t})\n\t}\n}\n\nfunc TestXFSReproducibility(t *testing.T) {\n\tt.Setenv(\"SOURCE_DATE_EPOCH\", \"1732109929\")\n\tt.Setenv(\"DETERMINISTIC_SEED\", \"1\")\n\tt.Setenv(\"PATH\", \"/usr/bin:/bin:/usr/sbin:/sbin\")\n\n\ttmpDir := t.TempDir()\n\n\ttempFile := filepath.Join(tmpDir, \"reproducible-xfs.img\")\n\n\tf, err := os.Create(tempFile)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, f.Truncate(512*1024*1024))\n\trequire.NoError(t, f.Close())\n\n\tsourceDirectory := filepath.Join(tmpDir, \"source\")\n\n\tpopulateTestDir(t, sourceDirectory, []string{\n\t\t\"file1.txt\",\n\t\t\"dir1/\",\n\t\t\"dir1/file2.txt\",\n\t\t\"dir1/subdir1/\",\n\t\t\"dir1/subdir1/file3.txt\",\n\t})\n\n\trequire.NoError(t, makefs.XFS(t.Context(),\n\t\ttempFile,\n\t\tmakefs.WithReproducible(true),\n\t\tmakefs.WithLabel(\"TESTLABEL\"),\n\t\tmakefs.WithSourceDirectory(sourceDirectory),\n\t))\n\n\tfileData, err := os.Open(tempFile)\n\trequire.NoError(t, err)\n\n\tsum1 := sha256.New()\n\n\t_, err = io.Copy(sum1, fileData)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, fileData.Close())\n\n\t// create the filesystem again\n\trequire.NoError(t, makefs.XFS(t.Context(),\n\t\ttempFile,\n\t\tmakefs.WithReproducible(true),\n\t\tmakefs.WithForce(true),\n\t\tmakefs.WithLabel(\"TESTLABEL\"),\n\t\tmakefs.WithSourceDirectory(sourceDirectory),\n\t))\n\n\t// get the file sha256 checksum\n\tfileData, err = os.Open(tempFile)\n\trequire.NoError(t, err)\n\n\tsum2 := sha256.New()\n\n\t_, err = io.Copy(sum2, fileData)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, fileData.Close())\n\n\tassert.Equal(t, sum1.Sum(nil), sum2.Sum(nil))\n}\n"
  },
  {
    "path": "pkg/minimal/limits.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package minimal provides the minimal/recommended limits for different machine types.\npackage minimal\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/dustin/go-humanize\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// Memory returns the minimal/recommended amount of memory required to run the node.\nfunc Memory(typ machine.Type) (minimum, recommended uint64, err error) {\n\t// We remove 150 MiB from the recommended memory to account for the kernel\n\tswitch typ { //nolint:exhaustive\n\tcase machine.TypeControlPlane, machine.TypeInit:\n\t\tminimum = 1848*humanize.MiByte - 150*humanize.MiByte\n\t\trecommended = 4*humanize.GiByte - 150*humanize.MiByte\n\n\tcase machine.TypeWorker:\n\t\tminimum = 1*humanize.GiByte - 150*humanize.MiByte\n\t\trecommended = 2*humanize.GiByte - 150*humanize.MiByte\n\n\tdefault:\n\t\treturn 0, 0, fmt.Errorf(\"unknown machine type %q\", typ)\n\t}\n\n\treturn minimum, recommended, nil\n}\n\n// DiskSize returns the minimal/recommended amount of disk space required to run the node.\nfunc DiskSize() uint64 {\n\treturn 6 * humanize.GiByte\n}\n"
  },
  {
    "path": "pkg/provision/access/access.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package access provides methods to access provisioned Talos cluster.\npackage access\n"
  },
  {
    "path": "pkg/provision/access/access_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage access_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/provision/access/adapter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage access\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Adapter provides cluster access via provision.Cluster.\ntype Adapter struct {\n\tcluster.ConfigClientProvider\n\tcluster.KubernetesClient\n\tcluster.APIBootstrapper\n\tcluster.Info\n\tcluster.ApplyConfigClient\n}\n\ntype infoWrapper struct {\n\tclusterInfo provision.ClusterInfo\n\tnodes       []cluster.NodeInfo\n\tnodesByType map[machine.Type][]cluster.NodeInfo\n}\n\nfunc (wrapper *infoWrapper) Nodes() []cluster.NodeInfo {\n\treturn wrapper.nodes\n}\n\nfunc (wrapper *infoWrapper) NodesByType(t machine.Type) []cluster.NodeInfo {\n\treturn wrapper.nodesByType[t]\n}\n\n// NewAdapter returns ClusterAccess object from Cluster.\nfunc NewAdapter(clusterInfo provision.Cluster, opts ...provision.Option) *Adapter {\n\toptions := provision.DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}\n\n\tc := clusterInfo.Info()\n\n\tnodeInfos, err := cluster.MapProvisionNodeInfosToClusterNodeInfos(c.Nodes)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tnodeInfosByType, err := cluster.MapProvisionNodeInfosToNodeInfosByType(c.Nodes)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tinfoW := &infoWrapper{\n\t\tclusterInfo: c,\n\t\tnodes:       nodeInfos,\n\t\tnodesByType: nodeInfosByType,\n\t}\n\n\tconfigProvider := cluster.ConfigClientProvider{\n\t\tDefaultClient: options.TalosClient,\n\t\tTalosConfig:   options.TalosConfig,\n\t}\n\n\treturn &Adapter{\n\t\tConfigClientProvider: configProvider,\n\t\tKubernetesClient: cluster.KubernetesClient{\n\t\t\tClientProvider: &configProvider,\n\t\t\tForceEndpoint:  options.KubernetesEndpoint,\n\t\t},\n\t\tAPIBootstrapper: cluster.APIBootstrapper{\n\t\t\tClientProvider: &configProvider,\n\t\t\tInfo:           infoW,\n\t\t},\n\t\tInfo: infoW,\n\t}\n}\n"
  },
  {
    "path": "pkg/provision/internal/cniutils/cniutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package cniutils provides helper functions to parse CNI results.\npackage cniutils\n\nimport (\n\t\"fmt\"\n\n\ttypes100 \"github.com/containernetworking/cni/pkg/types/100\"\n)\n\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\"). You may\n// not use this file except in compliance with the License. A copy of the\n// License is located at\n//\n//\thttp://aws.amazon.com/apache2.0/\n//\n// or in the \"license\" file accompanying this file. This file is distributed\n// on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n// express or implied. See the License for the specific language governing\n// permissions and limitations under the License.\n\n// FilterBySandbox returns scans the provided list of interfaces and returns two lists: the first\n// are a list of interfaces with the provided sandboxID, the second are the other interfaces not\n// in that sandboxID.\nfunc FilterBySandbox(sandbox string, ifaces ...*types100.Interface) (in, out []*types100.Interface) {\n\tfor _, iface := range ifaces {\n\t\tif iface.Sandbox == sandbox {\n\t\t\tin = append(in, iface)\n\t\t} else {\n\t\t\tout = append(out, iface)\n\t\t}\n\t}\n\n\treturn in, out\n}\n\n// IfacesWithName scans the provided list of ifaces and returns the ones with the provided name.\nfunc IfacesWithName(name string, ifaces ...*types100.Interface) []*types100.Interface {\n\tvar foundIfaces []*types100.Interface\n\n\tfor _, iface := range ifaces {\n\t\tif iface.Name == name {\n\t\t\tfoundIfaces = append(foundIfaces, iface)\n\t\t}\n\t}\n\n\treturn foundIfaces\n}\n\n// VMTapPair takes a CNI result and returns the vm iface and the tap iface corresponding\n// to the provided vmID. See the vmconf package docs for details on the expected\n// vm and tap iface configurations.\nfunc VMTapPair(result *types100.Result, vmID string) (vmIface, tapIface *types100.Interface, err error) {\n\tvmIfaces, otherIfaces := FilterBySandbox(vmID, result.Interfaces...)\n\tif len(vmIfaces) > 1 {\n\t\treturn nil, nil, fmt.Errorf(\n\t\t\t\"expected to find at most 1 interface in sandbox %q, but instead found %d\",\n\t\t\tvmID, len(vmIfaces))\n\t} else if len(vmIfaces) == 0 {\n\t\treturn nil, nil, fmt.Errorf(\"no pseudo-device for %s\", vmID)\n\t}\n\n\tvmIface = vmIfaces[0]\n\n\t// As specified in the package docstring, the vm interface is given the same name as the\n\t// corresponding tap device outside the VM. The tap device, however, will be in a sandbox\n\t// corresponding to a network namespace path.\n\ttapName := vmIface.Name\n\n\ttapIfaces := IfacesWithName(tapName, otherIfaces...)\n\tif len(tapIfaces) > 1 {\n\t\treturn nil, nil, fmt.Errorf(\n\t\t\t\"expected to find at most 1 interface with name %q, but instead found %d\",\n\t\t\ttapName, len(tapIfaces))\n\t} else if len(tapIfaces) == 0 {\n\t\treturn nil, nil, fmt.Errorf(\"device not found: %s\", tapName)\n\t}\n\n\ttapIface = tapIfaces[0]\n\n\treturn vmIface, tapIface, nil\n}\n"
  },
  {
    "path": "pkg/provision/internal/inmemhttp/inmemhttp.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package inmemhttp implements temporary HTTP server which is based off memory fs.\npackage inmemhttp\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\"\n\t\"slices\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// Server is an in-memory http web server.\ntype Server interface {\n\tAddFile(filename string, contents []byte) error\n\tAddHandler(pattern string, handler http.Handler)\n\n\tGetAddr() net.Addr\n\tServe()\n\tShutdown(ctx context.Context) error\n}\n\ntype server struct {\n\tl    net.Listener\n\taddr net.Addr\n\n\tsrv *http.Server\n\tmux *http.ServeMux\n}\n\n// NewServer creates in-mem HTTP server.\nfunc NewServer(ctx context.Context, address string) (Server, error) {\n\ts := &server{\n\t\tmux: http.NewServeMux(),\n\t}\n\n\tvar err error\n\n\ts.l, err = (&net.ListenConfig{}).Listen(ctx, \"tcp\", address)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ts.addr = s.l.Addr()\n\n\ts.srv = &http.Server{\n\t\tHandler: s.mux,\n\t}\n\n\treturn s, nil\n}\n\nfunc (s *server) AddFile(filename string, contents []byte) error {\n\tcontentsCopy := slices.Clone(contents)\n\n\ts.mux.Handle(\"/\"+filename, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tswitch req.Method {\n\t\tcase http.MethodHead:\n\t\t\tw.Header().Add(\"Content-Length\", strconv.Itoa(len(contentsCopy)))\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\tcase http.MethodGet:\n\t\t\tw.Header().Add(\"Content-Length\", strconv.Itoa(len(contentsCopy)))\n\t\t\tw.WriteHeader(http.StatusOK)\n\n\t\t\tw.Write(contentsCopy) //nolint:errcheck\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotImplemented)\n\t\t}\n\t}))\n\n\treturn nil\n}\n\nfunc (s *server) AddHandler(pattern string, handler http.Handler) {\n\ts.mux.Handle(pattern, handler)\n}\n\nfunc (s *server) GetAddr() net.Addr {\n\treturn s.addr\n}\n\nfunc (s *server) Serve() {\n\tgo s.srv.Serve(s.l) //nolint:errcheck\n}\n\nfunc (s *server) Shutdown(ctx context.Context) error {\n\tctx, cancel := context.WithTimeout(ctx, 10*time.Second)\n\tdefer cancel()\n\n\treturn s.srv.Shutdown(ctx)\n}\n"
  },
  {
    "path": "pkg/provision/internal/inmemhttp/inmemhttp_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage inmemhttp_test\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/internal/inmemhttp\"\n)\n\nfunc TestServer(t *testing.T) {\n\tsrv, err := inmemhttp.NewServer(t.Context(), \"localhost:0\")\n\tassert.NoError(t, err)\n\n\tcontents := []byte(\"DEADBEEF\")\n\n\tassert.NoError(t, srv.AddFile(\"test.txt\", contents))\n\n\tsrv.Serve()\n\tdefer srv.Shutdown(t.Context()) //nolint:errcheck\n\n\tresp, err := http.Get(fmt.Sprintf(\"http://%s/test.txt\", srv.GetAddr())) //nolint:noctx\n\tassert.NoError(t, err)\n\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n\n\tgot, err := io.ReadAll(resp.Body)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, contents, got)\n\n\tassert.NoError(t, resp.Body.Close())\n\n\tresp, err = http.Head(fmt.Sprintf(\"http://%s/test.txt\", srv.GetAddr())) //nolint:noctx\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n\n\tassert.EqualValues(t, 8, resp.ContentLength)\n\n\tassert.NoError(t, resp.Body.Close())\n\n\tresp, err = http.Get(fmt.Sprintf(\"http://%s/test.txt2\", srv.GetAddr())) //nolint:noctx\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, http.StatusNotFound, resp.StatusCode)\n\n\tassert.NoError(t, resp.Body.Close())\n\n\tassert.NoError(t, srv.Shutdown(t.Context()))\n}\n"
  },
  {
    "path": "pkg/provision/options.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provision\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n)\n\n// Option controls Provisioner.\ntype Option func(o *Options) error\n\n// WithLogWriter sets logging destination.\nfunc WithLogWriter(w io.Writer) Option {\n\treturn func(o *Options) error {\n\t\to.LogWriter = w\n\n\t\treturn nil\n\t}\n}\n\n// WithKubernetesEndpoint specifies full external Kubernetes API endpoint to use when accessing Talos cluster.\nfunc WithKubernetesEndpoint(endpoint string) Option {\n\treturn func(o *Options) error {\n\t\to.KubernetesEndpoint = endpoint\n\n\t\treturn nil\n\t}\n}\n\n// WithTalosConfig specifies talosconfig to use when acessing Talos cluster.\nfunc WithTalosConfig(talosConfig *clientconfig.Config) Option {\n\treturn func(o *Options) error {\n\t\to.TalosConfig = talosConfig\n\n\t\treturn nil\n\t}\n}\n\n// WithTalosClient specifies client to use when acessing Talos cluster.\nfunc WithTalosClient(client *client.Client) Option {\n\treturn func(o *Options) error {\n\t\to.TalosClient = client\n\n\t\treturn nil\n\t}\n}\n\n// WithBootlader enables or disables bootloader (bootloader is enabled by default).\nfunc WithBootlader(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.BootloaderEnabled = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithUEFI enables or disables UEFI boot on amd64 (default for amd64 is BIOS boot).\nfunc WithUEFI(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.UEFIEnabled = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithTPM1_2 enables or disables TPM1.2 emulation.\nfunc WithTPM1_2(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.TPM1_2Enabled = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithTPM2 enables or disables TPM2.0 emulation.\nfunc WithTPM2(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.TPM2Enabled = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithDebugShell drops into debug shell in initramfs.\nfunc WithDebugShell(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.WithDebugShell = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithIOMMU enables or disables IOMMU.\nfunc WithIOMMU(enabled bool) Option {\n\treturn func(o *Options) error {\n\t\to.IOMMUEnabled = enabled\n\n\t\treturn nil\n\t}\n}\n\n// WithExtraUEFISearchPaths configures additional search paths to look for UEFI firmware.\nfunc WithExtraUEFISearchPaths(extraUEFISearchPaths []string) Option {\n\treturn func(o *Options) error {\n\t\to.ExtraUEFISearchPaths = extraUEFISearchPaths\n\n\t\treturn nil\n\t}\n}\n\n// WithTargetArch specifies target architecture for the cluster.\nfunc WithTargetArch(arch string) Option {\n\treturn func(o *Options) error {\n\t\to.TargetArch = arch\n\n\t\treturn nil\n\t}\n}\n\n// WithDockerPorts allows docker provisioner to expose ports on workers.\nfunc WithDockerPorts(ports []string) Option {\n\treturn func(o *Options) error {\n\t\to.DockerPorts = ports\n\n\t\treturn nil\n\t}\n}\n\n// WithDockerPortsHostIP sets host IP for docker provisioner to expose ports on workers.\nfunc WithDockerPortsHostIP(hostIP string) Option {\n\treturn func(o *Options) error {\n\t\to.DockerPortsHostIP = hostIP\n\n\t\treturn nil\n\t}\n}\n\n// WithDeleteOnErr informs the provisioner to delete cluster state folder on error.\nfunc WithDeleteOnErr(v bool) Option {\n\treturn func(o *Options) error {\n\t\to.DeleteStateOnErr = v\n\n\t\treturn nil\n\t}\n}\n\n// WithSaveSupportArchivePath specifies path to save support archive on destroy.\nfunc WithSaveSupportArchivePath(path string) Option {\n\treturn func(o *Options) error {\n\t\to.SaveSupportArchivePath = path\n\n\t\treturn nil\n\t}\n}\n\n// WithSaveClusterLogsArchivePath specifies path to save cluster logs archive on destroy.\nfunc WithSaveClusterLogsArchivePath(path string) Option {\n\treturn func(o *Options) error {\n\t\to.SaveClusterLogsArchivePath = path\n\n\t\treturn nil\n\t}\n}\n\n// WithKMS inits KMS server in the provisioner.\nfunc WithKMS(endpoint string) Option {\n\treturn func(o *Options) error {\n\t\to.KMSEndpoint = endpoint\n\n\t\treturn nil\n\t}\n}\n\n// WithJSONLogs specifies endpoint to send logs in JSON format.\nfunc WithJSONLogs(endpoint string) Option {\n\treturn func(o *Options) error {\n\t\to.JSONLogsEndpoint = endpoint\n\n\t\treturn nil\n\t}\n}\n\n// WithSiderolinkAgent enables or disables siderolink agent.\nfunc WithSiderolinkAgent(v bool) Option {\n\treturn func(o *Options) error {\n\t\to.SiderolinkEnabled = v\n\n\t\treturn nil\n\t}\n}\n\n// WithSkipInjectingExtraCmdline prevents injecting extra kernel args into EFI vars.\nfunc WithSkipInjectingExtraCmdline(v bool) Option {\n\treturn func(o *Options) error {\n\t\to.SkipInjectingExtraCmdline = v\n\n\t\treturn nil\n\t}\n}\n\n// Options describes Provisioner parameters.\ntype Options struct {\n\tLogWriter          io.Writer\n\tTalosConfig        *clientconfig.Config\n\tTalosClient        *client.Client\n\tKubernetesEndpoint string\n\tTargetArch         string\n\n\t// Enable bootloader by booting from disk image after install.\n\tBootloaderEnabled bool\n\n\t// SkipInjectingExtraCmdline prevents injecting extra kernel args, e.g., console=ttyS0, into the EFI vars. Only applies when UEFI is enabled.\n\tSkipInjectingExtraCmdline bool\n\n\t// Enable UEFI (for amd64), arm64 can only boot UEFI\n\tUEFIEnabled bool\n\t// Enable TPM 1.2 emulation using swtpm.\n\tTPM1_2Enabled bool\n\t// Enable TPM 2.0 emulation using swtpm.\n\tTPM2Enabled bool\n\t// Enable debug shell in the bootloader.\n\tWithDebugShell bool\n\t// Enable IOMMU for VMs and add a new PCI root controller and network interface.\n\tIOMMUEnabled bool\n\t// Configure additional search paths to look for UEFI firmware.\n\tExtraUEFISearchPaths []string\n\n\t// Expose ports to worker machines in docker provisioner\n\tDockerPorts                []string\n\tDockerPortsHostIP          string\n\tSaveSupportArchivePath     string\n\tSaveClusterLogsArchivePath string\n\tDeleteStateOnErr           bool\n\n\tKMSEndpoint      string\n\tJSONLogsEndpoint string\n\n\tSiderolinkEnabled bool\n}\n\n// DefaultOptions returns default options.\nfunc DefaultOptions() Options {\n\treturn Options{\n\t\tBootloaderEnabled: true,\n\t\tTargetArch:        runtime.GOARCH,\n\t\tLogWriter:         os.Stderr,\n\t\tDockerPortsHostIP: \"0.0.0.0\",\n\t}\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/create.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Create Talos cluster as a set of docker containers on docker network.\nfunc (p *provisioner) Create(ctx context.Context, request provision.ClusterRequest, opts ...provision.Option) (provision.Cluster, error) {\n\tvar err error\n\n\toptions := provision.DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err = opt(&options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tstatePath := filepath.Join(request.StateDirectory, request.Name)\n\n\tfmt.Fprintf(options.LogWriter, \"creating state directory in %q\\n\", statePath)\n\n\tstate, err := provision.NewState(statePath, \"docker\", request.Name)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize provisioner state: %w\", err)\n\t}\n\n\tif err = p.ensureImageExists(ctx, request.Image, &options); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating network\", request.Network.Name)\n\n\tif err = p.createNetwork(ctx, request.Network); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to create or re-use a docker network: %w\", err)\n\t}\n\n\tvar nodeInfo []provision.NodeInfo //nolint:prealloc // this is created by p.createNodes\n\n\tfmt.Fprintln(options.LogWriter, \"creating controlplane nodes\")\n\n\tif nodeInfo, err = p.createNodes(ctx, request, request.Nodes.ControlPlaneNodes(), &options, true); err != nil {\n\t\treturn nil, err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating worker nodes\")\n\n\tvar workerNodeInfo []provision.NodeInfo //nolint:prealloc // this is created by p.createNodes\n\n\tif workerNodeInfo, err = p.createNodes(ctx, request, request.Nodes.WorkerNodes(), &options, false); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnodeInfo = append(nodeInfo, workerNodeInfo...)\n\n\tstate.ClusterInfo = provision.ClusterInfo{\n\t\tClusterName: request.Name,\n\t\tNetwork: provision.NetworkInfo{\n\t\t\tName:         request.Network.Name,\n\t\t\tCIDRs:        request.Network.CIDRs[:1],\n\t\t\tGatewayAddrs: request.Network.GatewayAddrs[:1],\n\t\t\tMTU:          request.Network.MTU,\n\t\t},\n\t\tNodes:              nodeInfo,\n\t\tKubernetesEndpoint: p.GetExternalKubernetesControlPlaneEndpoint(request.Network, constants.DefaultControlPlanePort),\n\t}\n\tif err := state.Save(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tres := &result{\n\t\tclusterInfo: state.ClusterInfo,\n\t\tstatePath:   statePath,\n\t}\n\n\treturn res, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/destroy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/moby/moby/client\"\n\n\tcl \"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Destroy Talos cluster as set of Docker nodes.\n//\n// Only cluster.Info().ClusterName and cluster.Info().Network.Name is being used.\nfunc (p *provisioner) Destroy(ctx context.Context, cluster provision.Cluster, opts ...provision.Option) error {\n\toptions := provision.DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tstateDirectoryPath, err := cluster.StatePath()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcomplete := false\n\tdeleteStateDirectory := func(stateDir string, shouldDelete bool) error {\n\t\tif complete || !shouldDelete {\n\t\t\treturn nil\n\t\t}\n\n\t\tcomplete = true\n\n\t\treturn os.RemoveAll(stateDir)\n\t}\n\n\tdefer deleteStateDirectory(stateDirectoryPath, options.DeleteStateOnErr) //nolint:errcheck\n\n\tif options.SaveClusterLogsArchivePath != \"\" {\n\t\tfmt.Fprintf(options.LogWriter, \"saving cluster logs archive to %s\\n\", options.SaveClusterLogsArchivePath)\n\n\t\tp.saveContainerLogs(ctx, cluster, options.SaveClusterLogsArchivePath)\n\t}\n\n\tif options.SaveSupportArchivePath != \"\" {\n\t\tfmt.Fprintf(options.LogWriter, \"saving support archive to %s\\n\", options.SaveSupportArchivePath)\n\n\t\tcl.Crashdump(ctx, cluster, options.LogWriter, options.SaveSupportArchivePath)\n\t}\n\n\tif err := p.destroyNodes(ctx, cluster.Info().ClusterName, &options); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(os.Stderr, \"destroying network\", cluster.Info().Network.Name)\n\n\tif err := p.destroyNetwork(ctx, cluster.Info().Network.Name); err != nil {\n\t\treturn err\n\t}\n\n\treturn deleteStateDirectory(stateDirectoryPath, true)\n}\n\nfunc (p *provisioner) saveContainerLogs(ctx context.Context, cluster provision.Cluster, logsArchivePath string) {\n\tcontainers, err := p.listNodes(ctx, cluster.Info().ClusterName)\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"error listing containers: %s\\n\", err)\n\n\t\treturn\n\t}\n\n\tstatePath, err := cluster.StatePath()\n\tif err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"error getting state path: %s\\n\", err)\n\n\t\treturn\n\t}\n\n\tfor _, ctr := range containers {\n\t\tname := ctr.Names[0][1:]\n\n\t\tlogs, err := p.client.ContainerLogs(ctx, ctr.ID, client.ContainerLogsOptions{\n\t\t\tShowStdout: true,\n\t\t\tShowStderr: true,\n\t\t\tTail:       \"1000\",\n\t\t})\n\t\tif err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"error querying container logs: %s\\n\", err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tlogPath := filepath.Join(statePath, fmt.Sprintf(\"%s.log\", name))\n\n\t\tvar logData bytes.Buffer\n\n\t\tif _, err := io.Copy(&logData, logs); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"error reading container logs: %s\\n\", err)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := os.WriteFile(logPath, logData.Bytes(), 0o644); err != nil {\n\t\t\tfmt.Fprintf(os.Stderr, \"error writing container logs: %s\\n\", err)\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\tcl.SaveClusterLogsArchive(statePath, logsArchivePath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/docker.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package docker implements Provisioner via docker.\npackage docker\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/moby/moby/client\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\ntype provisioner struct {\n\tclient *client.Client\n\n\tmappedKubernetesPort, mappedTalosAPIPort int\n}\n\nfunc getAvailableTCPPort(ctx context.Context) (int, error) {\n\tl, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t_, portStr, err := net.SplitHostPort(l.Addr().String())\n\tif err != nil {\n\t\tl.Close() //nolint:errcheck\n\n\t\treturn 0, err\n\t}\n\n\terr = l.Close()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tport, err := strconv.Atoi(portStr)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn port, nil\n}\n\n// NewProvisioner initializes docker provisioner.\nfunc NewProvisioner(ctx context.Context) (provision.Provisioner, error) {\n\tp := &provisioner{}\n\n\tvar err error\n\n\tp.client, err = client.New(client.FromEnv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tp.mappedKubernetesPort, err = getAvailableTCPPort(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get available port for Kubernetes API: %w\", err)\n\t}\n\n\tp.mappedTalosAPIPort, err = getAvailableTCPPort(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get available port for Talos API: %w\", err)\n\t}\n\n\treturn p, nil\n}\n\n// Close and release resources.\nfunc (p *provisioner) Close() error {\n\tif p.client != nil {\n\t\treturn p.client.Close()\n\t}\n\n\treturn nil\n}\n\n// GenOptions provides a list of additional config generate options.\nfunc (p *provisioner) GenOptions(networkReq provision.NetworkRequest, contract *config.VersionContract) ([]generate.Option, []bundle.Option) {\n\tvar genOptions []generate.Option\n\n\tif contract.HostDNSEnabled() {\n\t\tgenOptions = append(genOptions,\n\t\t\tgenerate.WithHostDNSForwardKubeDNSToHost(true),\n\t\t)\n\t}\n\n\tif !contract.MultidocNetworkConfigSupported() {\n\t\tgenOptions = append(genOptions,\n\t\t\tgenerate.WithNetworkOptions(\n\t\t\t\tv1alpha1.WithNetworkInterfaceIgnore(v1alpha1.IfaceByName(\"eth0\")),\n\t\t\t),\n\t\t)\n\t}\n\n\treturn genOptions, nil\n}\n\n// GetInClusterKubernetesControlPlaneEndpoint returns the Kubernetes control plane endpoint.\nfunc (p *provisioner) GetInClusterKubernetesControlPlaneEndpoint(networkReq provision.NetworkRequest, controlPlanePort int) string {\n\t// Docker doesn't have a loadbalancer, so use the first container IP.\n\treturn \"https://\" + nethelpers.JoinHostPort(networkReq.CIDRs[0].Addr().Next().Next().String(), controlPlanePort)\n}\n\n// GetExternalKubernetesControlPlaneEndpoint returns the Kubernetes control plane endpoint.\nfunc (p *provisioner) GetExternalKubernetesControlPlaneEndpoint(provision.NetworkRequest, int) string {\n\t// return a mapped to the localhost first container Kubernetes API endpoint.\n\treturn \"https://\" + nethelpers.JoinHostPort(\"127.0.0.1\", p.mappedKubernetesPort)\n}\n\n// GetTalosAPIEndpoints returns a list of Talos API endpoints.\nfunc (p *provisioner) GetTalosAPIEndpoints(provision.NetworkRequest) []string {\n\t// return a mapped to the localhost first container Talos API endpoint.\n\treturn []string{nethelpers.JoinHostPort(\"127.0.0.1\", p.mappedTalosAPIPort)}\n}\n\n// UserDiskName not implemented for docker.\nfunc (p *provisioner) UserDiskName(index int) string {\n\treturn \"\"\n}\n\n// GetFirstInterface returns first network interface name.\nfunc (p *provisioner) GetFirstInterface() v1alpha1.IfaceSelector {\n\treturn v1alpha1.IfaceByName(p.GetFirstInterfaceName())\n}\n\n// GetFirstInterfaceName returns first network interface name as string.\nfunc (p *provisioner) GetFirstInterfaceName() string {\n\treturn \"eth0\"\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/docker_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/image.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/distribution/reference\"\n\t\"github.com/moby/moby/client\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *provisioner) ensureImageExists(ctx context.Context, containerImage string, options *provision.Options) error {\n\t// In order to pull an image, the reference must be in canonical\n\t// format (e.g. domain/repo/image:tag).\n\tref, err := reference.ParseNormalizedNamed(containerImage)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcontainerImage = ref.String()\n\n\t// To filter the images, we need a familiar name and a tag\n\t// (e.g. domain/repo/image:tag => repo/image:tag).\n\tfamiliarName := reference.FamiliarName(ref)\n\ttag := \"\"\n\n\tif tagged, isTagged := ref.(reference.Tagged); isTagged {\n\t\ttag = tagged.Tag()\n\t}\n\n\tfilters := client.Filters{}\n\tfilters.Add(\"reference\", familiarName+\":\"+tag)\n\n\timages, err := p.client.ImageList(ctx, client.ImageListOptions{Filters: filters})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(images.Items) == 0 {\n\t\tfmt.Fprintln(options.LogWriter, \"downloading\", containerImage)\n\n\t\tvar reader io.ReadCloser\n\n\t\tif reader, err = p.client.ImagePull(ctx, containerImage, client.ImagePullOptions{}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t//nolint:errcheck\n\t\tdefer reader.Close()\n\n\t\tif _, err = io.Copy(io.Discard, reader); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/moby/moby/api/types/network\"\n\t\"github.com/moby/moby/client\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// createNetwork will take a network request and check if a network with the same name + cidr exists.\n// If so, it simply returns without error and assumes we will re-use that network. Otherwise it will create a new one.\nfunc (p *provisioner) createNetwork(ctx context.Context, req provision.NetworkRequest) error {\n\texistingNet, err := p.listNetworks(ctx, req.Name)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// If named net already exists, see if we can reuse it\n\tif len(existingNet) > 0 {\n\t\tif existingNet[0].IPAM.Config[0].Subnet != req.CIDRs[0] {\n\t\t\treturn fmt.Errorf(\"existing network has differing cidr: %s vs %s\", existingNet[0].IPAM.Config[0].Subnet, req.CIDRs[0].String())\n\t\t}\n\t\t// CIDRs match, we'll reuse\n\t\treturn nil\n\t}\n\n\t// Create new net\n\toptions := client.NetworkCreateOptions{\n\t\tLabels: map[string]string{\n\t\t\t\"talos.owned\":        \"true\",\n\t\t\t\"talos.cluster.name\": req.Name,\n\t\t},\n\t\tIPAM: &network.IPAM{\n\t\t\tConfig: []network.IPAMConfig{\n\t\t\t\t{\n\t\t\t\t\tSubnet: req.CIDRs[0],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tOptions: map[string]string{\n\t\t\t\"com.docker.network.driver.mtu\": strconv.Itoa(req.MTU),\n\t\t},\n\t}\n\n\t_, err = p.client.NetworkCreate(ctx, req.Name, options)\n\n\treturn err\n}\n\nfunc (p *provisioner) listNetworks(ctx context.Context, name string) ([]network.Summary, error) {\n\tfilters := client.Filters{}\n\tfilters.Add(\"label\", \"talos.owned=true\")\n\tfilters.Add(\"label\", \"talos.cluster.name=\"+name)\n\n\toptions := client.NetworkListOptions{\n\t\tFilters: filters,\n\t}\n\n\tresult, err := p.client.NetworkList(ctx, options)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn result.Items, nil\n}\n\nfunc (p *provisioner) destroyNetwork(ctx context.Context, name string) error {\n\tnetworks, err := p.listNetworks(ctx, name)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar result *multierror.Error\n\n\tfor _, network := range networks {\n\t\tif _, err := p.client.NetworkRemove(ctx, network.ID, client.NetworkRemoveOptions{}); err != nil {\n\t\t\tresult = multierror.Append(result, err)\n\t\t}\n\t}\n\n\treturn result.ErrorOrNil()\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/node.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/netip\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/moby/moby/api/types/container\"\n\t\"github.com/moby/moby/api/types/mount\"\n\t\"github.com/moby/moby/api/types/network\"\n\t\"github.com/moby/moby/client\"\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\ntype portMap struct {\n\texposedPorts network.PortSet\n\tportBindings network.PortMap\n}\n\nfunc (p *provisioner) createNodes(\n\tctx context.Context,\n\tclusterReq provision.ClusterRequest,\n\tnodeReqs []provision.NodeRequest,\n\toptions *provision.Options,\n\tisControlplane bool,\n) ([]provision.NodeInfo, error) {\n\terrCh := make(chan error)\n\tnodeCh := make(chan provision.NodeInfo, len(nodeReqs))\n\n\tfor i, nodeReq := range nodeReqs {\n\t\tgo func(i int, nodeReq provision.NodeRequest) {\n\t\t\tif i == 0 && isControlplane {\n\t\t\t\thostPrefix := \"\"\n\n\t\t\t\t// on Linux, limit listening to localhost, on other OSes Docker engine VM is separate from the host\n\t\t\t\tif runtime.GOOS == \"linux\" {\n\t\t\t\t\thostPrefix = \"127.0.0.1:\"\n\t\t\t\t}\n\n\t\t\t\tnodeReq.Ports = append(\n\t\t\t\t\t[]string{\n\t\t\t\t\t\tfmt.Sprintf(\"%s%d:%d/tcp\", hostPrefix, p.mappedTalosAPIPort, constants.ApidPort),\n\t\t\t\t\t\tfmt.Sprintf(\"%s%d:%d/tcp\", hostPrefix, p.mappedKubernetesPort, constants.DefaultControlPlanePort),\n\t\t\t\t\t},\n\t\t\t\t\tnodeReq.Ports...,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tnodeInfo, err := p.createNode(ctx, clusterReq, nodeReq, options)\n\t\t\tif err == nil {\n\t\t\t\tnodeCh <- nodeInfo\n\t\t\t}\n\n\t\t\terrCh <- err\n\t\t}(i, nodeReq)\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor range nodeReqs {\n\t\tmultiErr = multierror.Append(multiErr, <-errCh)\n\t}\n\n\tclose(nodeCh)\n\n\tnodesInfo := make([]provision.NodeInfo, 0, len(nodeReqs))\n\n\tfor nodeInfo := range nodeCh {\n\t\tnodesInfo = append(nodesInfo, nodeInfo)\n\t}\n\n\treturn nodesInfo, multiErr.ErrorOrNil()\n}\n\n//nolint:gocyclo\nfunc (p *provisioner) createNode(ctx context.Context, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest, options *provision.Options) (provision.NodeInfo, error) {\n\tenv := []string{\n\t\t\"PLATFORM=container\",\n\t\tfmt.Sprintf(\"TALOSSKU=%dCPU-%dRAM\", nodeReq.NanoCPUs/(1000*1000*1000), nodeReq.Memory/(1024*1024)),\n\t}\n\n\tif !nodeReq.SkipInjectingConfig {\n\t\tcfg, err := nodeReq.Config.EncodeString()\n\t\tif err != nil {\n\t\t\treturn provision.NodeInfo{}, err\n\t\t}\n\n\t\tenv = append(env, \"USERDATA=\"+base64.StdEncoding.EncodeToString([]byte(cfg)))\n\t}\n\n\t// Create the container config.\n\tcontainerConfig := &container.Config{\n\t\tHostname: nodeReq.Name,\n\t\tImage:    clusterReq.Image,\n\t\tEnv:      env,\n\t\tLabels: map[string]string{\n\t\t\t\"talos.owned\":        \"true\",\n\t\t\t\"talos.cluster.name\": clusterReq.Name,\n\t\t\t\"talos.type\":         nodeReq.Type.String(),\n\t\t},\n\t}\n\n\t// Create the host config.\n\tmounts := make([]mount.Mount, 0, len(constants.Overlays)+5+len(nodeReq.Mounts))\n\n\tfor _, path := range []string{\"/run\", \"/system\", \"/tmp\"} {\n\t\tmounts = append(mounts, mount.Mount{\n\t\t\tType:   mount.TypeTmpfs,\n\t\t\tTarget: path,\n\t\t})\n\t}\n\n\tfor _, path := range append(\n\t\t[]string{constants.EphemeralMountPoint, constants.StateMountPoint},\n\t\txslices.Map(constants.Overlays, func(overlay constants.SELinuxLabeledPath) string {\n\t\t\treturn overlay.Path\n\t\t})...,\n\t) {\n\t\tmounts = append(mounts, mount.Mount{\n\t\t\tType:   mount.TypeVolume,\n\t\t\tTarget: path,\n\t\t})\n\t}\n\n\tmounts = slices.Concat(mounts, nodeReq.Mounts)\n\n\thostConfig := &container.HostConfig{\n\t\tPrivileged:  true,\n\t\tSecurityOpt: []string{\"seccomp:unconfined\"},\n\t\tResources: container.Resources{\n\t\t\tNanoCPUs: nodeReq.NanoCPUs,\n\t\t\tMemory:   nodeReq.Memory,\n\t\t},\n\t\tReadonlyRootfs: true,\n\t\tMounts:         mounts,\n\t}\n\n\tif !clusterReq.Network.DockerDisableIPv6 {\n\t\t// enable IPv6\n\t\thostConfig.Sysctls = map[string]string{\n\t\t\t\"net.ipv6.conf.all.disable_ipv6\": \"0\",\n\t\t}\n\t}\n\n\t// Ensure that the container is created in the talos network.\n\n\tnetworkConfig := &network.NetworkingConfig{\n\t\tEndpointsConfig: map[string]*network.EndpointSettings{\n\t\t\tclusterReq.Network.Name: {\n\t\t\t\tNetworkID: clusterReq.Network.Name,\n\t\t\t},\n\t\t},\n\t}\n\n\t// Mutate the container configurations based on the node type.\n\n\tif nodeReq.Type == machine.TypeInit || nodeReq.Type == machine.TypeControlPlane {\n\t\tportsToOpen := nodeReq.Ports\n\n\t\tif len(options.DockerPorts) > 0 {\n\t\t\tportsToOpen = append(portsToOpen, options.DockerPorts...)\n\t\t}\n\n\t\tgeneratedPortMap, err := genPortMap(portsToOpen, options.DockerPortsHostIP)\n\t\tif err != nil {\n\t\t\treturn provision.NodeInfo{}, err\n\t\t}\n\n\t\tcontainerConfig.ExposedPorts = generatedPortMap.exposedPorts\n\n\t\thostConfig.PortBindings = generatedPortMap.portBindings\n\n\t\tif nodeReq.IPs == nil {\n\t\t\treturn provision.NodeInfo{}, errors.New(\"an IP address must be provided when creating a controlplane node\")\n\t\t}\n\t}\n\n\tif nodeReq.IPs != nil {\n\t\tnetworkConfig.EndpointsConfig[clusterReq.Network.Name].IPAMConfig = &network.EndpointIPAMConfig{IPv4Address: nodeReq.IPs[0]}\n\t}\n\n\t// Create the container.\n\tresp, err := p.client.ContainerCreate(ctx, client.ContainerCreateOptions{\n\t\tConfig:           containerConfig,\n\t\tHostConfig:       hostConfig,\n\t\tNetworkingConfig: networkConfig,\n\t\tName:             nodeReq.Name,\n\t})\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\t// Start the container.\n\t_, err = p.client.ContainerStart(ctx, resp.ID, client.ContainerStartOptions{})\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\t// Inspect the container.\n\tinfo, err := p.client.ContainerInspect(ctx, resp.ID, client.ContainerInspectOptions{})\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\t// Get the container's IP address.\n\tvar addr netip.Addr\n\n\tif network, ok := info.Container.NetworkSettings.Networks[clusterReq.Network.Name]; ok {\n\t\tip := network.IPAddress\n\n\t\tif ip.IsUnspecified() && network.IPAMConfig != nil {\n\t\t\tip = network.IPAMConfig.IPv4Address\n\t\t}\n\n\t\taddr = ip\n\t}\n\n\tnodeInfo := provision.NodeInfo{\n\t\tID:   info.Container.ID,\n\t\tName: info.Container.Name,\n\t\tType: nodeReq.Type,\n\n\t\tNanoCPUs: nodeReq.NanoCPUs,\n\t\tMemory:   nodeReq.Memory,\n\n\t\tIPs: []netip.Addr{addr},\n\t}\n\n\treturn nodeInfo, nil\n}\n\nfunc (p *provisioner) listNodes(ctx context.Context, clusterName string) ([]container.Summary, error) {\n\tfilters := client.Filters{}\n\tfilters.Add(\"label\", \"talos.owned=true\")\n\tfilters.Add(\"label\", \"talos.cluster.name=\"+clusterName)\n\n\tsummary, err := p.client.ContainerList(ctx, client.ContainerListOptions{All: true, Filters: filters})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn summary.Items, nil\n}\n\nfunc (p *provisioner) destroyNodes(ctx context.Context, clusterName string, options *provision.Options) error {\n\tcontainers, err := p.listNodes(ctx, clusterName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terrCh := make(chan error)\n\n\tfor _, ctr := range containers {\n\t\tgo func(ctr container.Summary) {\n\t\t\tfmt.Fprintln(options.LogWriter, \"destroying node\", ctr.Names[0][1:])\n\n\t\t\t_, err := p.client.ContainerRemove(ctx, ctr.ID, client.ContainerRemoveOptions{RemoveVolumes: true, Force: true})\n\n\t\t\terrCh <- err\n\t\t}(ctr)\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor range containers {\n\t\tmultiErr = multierror.Append(multiErr, <-errCh)\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\nfunc genPortMap(portList []string, defaultHostIP string) (portMap, error) {\n\tportSetRet := network.PortSet{}\n\tportMapRet := network.PortMap{}\n\n\tfor _, port := range portList {\n\t\tportsAndHost, protocol, ok := strings.Cut(port, \"/\")\n\n\t\tif !ok {\n\t\t\treturn portMap{}, errors.New(\"incorrect format for exposed port/protocols\")\n\t\t}\n\n\t\texpodedPortsAndHost := strings.Split(portsAndHost, \":\")\n\n\t\tvar containerPort, hostPort string\n\n\t\thostIP := defaultHostIP\n\n\t\tswitch len(expodedPortsAndHost) {\n\t\tcase 2:\n\t\t\thostPort, containerPort = expodedPortsAndHost[0], expodedPortsAndHost[1]\n\t\tcase 3:\n\t\t\thostIP, hostPort, containerPort = expodedPortsAndHost[0], expodedPortsAndHost[1], expodedPortsAndHost[2]\n\t\tdefault:\n\t\t\treturn portMap{}, errors.New(\"incorrect format for exposed ports\")\n\t\t}\n\n\t\tnatPort, err := network.ParsePort(containerPort + \"/\" + protocol)\n\t\tif err != nil {\n\t\t\treturn portMap{}, err\n\t\t}\n\n\t\thostAddr, err := netip.ParseAddr(hostIP)\n\t\tif err != nil {\n\t\t\treturn portMap{}, fmt.Errorf(\"invalid host IP address '%s': %w\", hostIP, err)\n\t\t}\n\n\t\tportSetRet[natPort] = struct{}{}\n\t\tportMapRet[natPort] = append(portMapRet[natPort], network.PortBinding{\n\t\t\tHostIP:   hostAddr,\n\t\t\tHostPort: hostPort,\n\t\t})\n\t}\n\n\treturn portMap{portSetRet, portMapRet}, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/reflect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/netip\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/moby/moby/client\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n//nolint:gocyclo\nfunc (p *provisioner) Reflect(ctx context.Context, clusterName, stateDirectory string) (provision.Cluster, error) {\n\tres := &result{\n\t\tclusterInfo: provision.ClusterInfo{\n\t\t\tClusterName: clusterName,\n\t\t},\n\t\tstatePath: stateDirectory,\n\t}\n\n\t// find network assuming network name == cluster name\n\tnetworks, err := p.listNetworks(ctx, clusterName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(networks) > 0 {\n\t\tnetwork := networks[0]\n\n\t\tcidr := network.IPAM.Config[0].Subnet\n\n\t\tres.clusterInfo.Network.Name = network.Name\n\t\tres.clusterInfo.Network.CIDRs = []netip.Prefix{cidr}\n\t\tres.clusterInfo.Network.GatewayAddrs = []netip.Addr{network.IPAM.Config[0].Gateway}\n\n\t\tmtuStr, ok := network.Options[\"com.docker.network.driver.mtu\"]\n\t\tif !ok {\n\t\t\tmtuStr = network.Options[\"mtu\"] // Use the podman version of the option\n\t\t}\n\n\t\tres.clusterInfo.Network.MTU, err = strconv.Atoi(mtuStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// find nodes (containers)\n\tnodes, err := p.listNodes(ctx, clusterName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar mappedKubernetesPort string\n\n\tfor _, node := range nodes {\n\t\tt, err := machine.ParseType(node.Labels[\"talos.type\"])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcontainer, err := p.client.ContainerInspect(ctx, node.ID, client.ContainerInspectOptions{})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar ips []netip.Addr\n\n\t\tif network, ok := node.NetworkSettings.Networks[res.clusterInfo.Network.Name]; ok {\n\t\t\tip := network.IPAddress\n\t\t\tif ip.IsUnspecified() && network.IPAMConfig != nil {\n\t\t\t\tip = network.IPAMConfig.IPv4Address\n\t\t\t}\n\n\t\t\tips = append(ips, ip)\n\t\t}\n\n\t\tfor port, portBinding := range container.Container.HostConfig.PortBindings {\n\t\t\tif port.Num() == constants.DefaultControlPlanePort {\n\t\t\t\tfor _, binding := range portBinding {\n\t\t\t\t\tmappedKubernetesPort = binding.HostPort\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tres.clusterInfo.Nodes = append(res.clusterInfo.Nodes,\n\t\t\tprovision.NodeInfo{\n\t\t\t\tID:   node.ID,\n\t\t\t\tName: strings.TrimLeft(node.Names[0], \"/\"),\n\t\t\t\tType: t,\n\n\t\t\t\tIPs: ips,\n\n\t\t\t\tNanoCPUs: container.Container.HostConfig.Resources.NanoCPUs,\n\t\t\t\tMemory:   container.Container.HostConfig.Resources.Memory,\n\t\t\t})\n\t}\n\n\tif mappedKubernetesPort != \"\" {\n\t\tres.clusterInfo.KubernetesEndpoint = \"https://\" + net.JoinHostPort(\"127.0.0.1\", mappedKubernetesPort)\n\t}\n\n\treturn res, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/docker/result.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage docker\n\nimport (\n\t\"errors\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\ntype result struct {\n\tclusterInfo provision.ClusterInfo\n\n\tstatePath string\n}\n\nfunc (res *result) Provisioner() string {\n\treturn \"docker\"\n}\n\nfunc (res *result) Info() provision.ClusterInfo {\n\treturn res.clusterInfo\n}\n\nfunc (res *result) StatePath() (string, error) {\n\tif res.statePath == \"\" {\n\t\treturn \"\", errors.New(\"state path is not used for docker provisioner\")\n\t}\n\n\treturn res.statePath, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/factory.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage providers\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/docker\"\n)\n\nconst (\n\t// QemuProviderName is the name of the qemu provider.\n\tQemuProviderName = \"qemu\"\n\t// DockerProviderName is the name of the docker provider.\n\tDockerProviderName = \"docker\"\n)\n\n// Factory instantiates provision provider by name.\nfunc Factory(ctx context.Context, name string) (provision.Provisioner, error) {\n\tif err := IsValidProvider(name); err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch name {\n\tcase DockerProviderName:\n\t\treturn docker.NewProvisioner(ctx)\n\tcase QemuProviderName:\n\t\treturn newQemu(ctx)\n\t}\n\n\tpanic(\"unknown valid provisioner\")\n}\n\n// IsValidProvider returns an error if the passed provider doesn't exist.\nfunc IsValidProvider(name string) error {\n\tswitch name {\n\tcase QemuProviderName, DockerProviderName:\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"unsupported provisioner %q\", name)\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/arch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n)\n\n// Arch abstracts away differences between different architectures.\ntype Arch string\n\n// Arch constants.\nconst (\n\tArchAmd64 Arch = \"amd64\"\n\tArchArm64 Arch = \"arm64\"\n)\n\n// Valid returns an error if the architecture is not supported.\nfunc (arch Arch) Valid() error {\n\tswitch arch {\n\tcase ArchArm64, ArchAmd64:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported arch: %q\", arch)\n\t}\n}\n\n// QemuArch defines which qemu binary to use.\nfunc (arch Arch) QemuArch() string {\n\tswitch arch {\n\tcase ArchAmd64:\n\t\treturn \"x86_64\"\n\tcase ArchArm64:\n\t\treturn \"aarch64\"\n\tdefault:\n\t\tpanic(\"unsupported architecture\")\n\t}\n}\n\n// QemuMachine defines the machine type for qemu.\nfunc (arch Arch) QemuMachine() string {\n\tswitch arch {\n\tcase ArchAmd64:\n\t\treturn \"q35\"\n\tcase ArchArm64:\n\t\treturn \"virt,gic-version=max\"\n\tdefault:\n\t\tpanic(\"unsupported architecture\")\n\t}\n}\n\n// Console defines proper argument for the kernel to send logs to serial console.\nfunc (arch Arch) Console() string {\n\tswitch arch {\n\tcase ArchAmd64:\n\t\treturn \"ttyS0\"\n\tcase ArchArm64:\n\t\treturn \"ttyAMA0,115200n8\"\n\tdefault:\n\t\tpanic(\"unsupported architecture\")\n\t}\n}\n\n// PFlash for UEFI boot.\ntype PFlash struct {\n\tSize        int64\n\tSourcePaths []string\n}\n\n// PFlash returns settings for parallel flash.\nfunc (arch Arch) PFlash(uefiEnabled bool, extraUEFISearchPaths []string) []PFlash {\n\tswitch arch {\n\tcase ArchArm64:\n\t\t// default search paths\n\t\tuefiSourcePathPrefixes := []string{ //nolint:prealloc // complex length\n\t\t\t\"/usr/share/AAVMF\", // most standard location\n\t\t\t\"/usr/share/qemu-efi-aarch64\",\n\t\t\t\"/usr/share/OVMF\",\n\t\t\t\"/usr/share/edk2/aarch64\",      // Fedora\n\t\t\t\"/usr/share/edk2/experimental\", // Fedora\n\t\t\t\"/opt/homebrew/share/qemu\",     // Darwin\n\t\t}\n\n\t\t// Secure boot enabled firmware files\n\t\tuefiSourceFiles := []string{\n\t\t\t\"AAVMF_CODE.secboot.fd\",        // debian, EFI vars not protected\n\t\t\t\"QEMU_EFI.secboot.testonly.fd\", // Fedora, ref: https://bugzilla.redhat.com/show_bug.cgi?id=1882135\n\t\t}\n\n\t\t// Non-secure boot firmware files\n\t\tuefiSourceFilesInsecure := []string{\n\t\t\t\"AAVMF_CODE.fd\",\n\t\t\t\"QEMU_EFI.fd\",\n\t\t\t\"OVMF.stateless.fd\",\n\t\t\t\"edk2-aarch64-code.fd\",\n\t\t}\n\n\t\t// Empty vars files\n\t\tuefiVarsFiles := []string{\n\t\t\t\"AAVMF_VARS.fd\",\n\t\t\t\"QEMU_VARS.fd\",\n\t\t\t\"edk2-arm-vars.fd\",\n\t\t}\n\n\t\t// Append extra search paths\n\t\tuefiSourcePathPrefixes = append(uefiSourcePathPrefixes, extraUEFISearchPaths...)\n\n\t\tuefiSourcePaths, uefiVarsPaths := generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure)\n\n\t\treturn []PFlash{\n\t\t\t{\n\t\t\t\tSize:        64 * 1024 * 1024,\n\t\t\t\tSourcePaths: uefiSourcePaths,\n\t\t\t},\n\t\t\t{\n\t\t\t\tSourcePaths: uefiVarsPaths,\n\t\t\t\tSize:        64 * 1024 * 1024,\n\t\t\t},\n\t\t}\n\tcase ArchAmd64:\n\t\tif !uefiEnabled {\n\t\t\treturn nil\n\t\t}\n\n\t\t// Default search paths\n\t\tuefiSourcePathPrefixes := []string{ //nolint:prealloc // complex length\n\t\t\t\"/usr/share/ovmf\",\n\t\t\t\"/usr/share/OVMF\",\n\t\t\t\"/usr/share/qemu\",\n\t\t\t\"/usr/share/ovmf/x64\",      // Arch Linux\n\t\t\t\"/opt/homebrew/share/qemu\", // Darwin\n\t\t}\n\n\t\t// Secure boot enabled firmware files\n\t\tuefiSourceFiles := []string{\n\t\t\t\"OVMF_CODE_4M.secboot.fd\",\n\t\t\t\"OVMF_CODE.secboot.4m.fd\", // Arch Linux\n\t\t\t\"OVMF_CODE.secboot.fd\",\n\t\t\t\"OVMF.secboot.fd\",\n\t\t\t\"edk2-x86_64-secure-code.fd\", // Alpine Linux, Darwin\n\t\t\t\"ovmf-x86_64-ms-4m-code.bin\",\n\t\t}\n\n\t\t// Non-secure boot firmware files\n\t\tuefiSourceFilesInsecure := []string{\n\t\t\t\"OVMF_CODE_4M.fd\",\n\t\t\t\"OVMF_CODE.4m.fd\", // Arch Linux\n\t\t\t\"OVMF_CODE.fd\",\n\t\t\t\"OVMF.fd\",\n\t\t\t\"edk2-x86_64-code.fd\", // Darwin\n\t\t\t\"ovmf-x86_64-4m-code.bin\",\n\t\t}\n\n\t\t// Empty vars files\n\t\tuefiVarsFiles := []string{\n\t\t\t\"OVMF_VARS_4M.fd\",\n\t\t\t\"OVMF_VARS.4m.fd\", // Arch Linux\n\t\t\t\"OVMF_VARS.fd\",\n\t\t\t\"edk2-i386-vars.fd\", // Darwin\n\t\t\t\"ovmf-x86_64-4m-vars.bin\",\n\t\t}\n\n\t\t// Append extra search paths\n\t\tuefiSourcePathPrefixes = append(uefiSourcePathPrefixes, extraUEFISearchPaths...)\n\n\t\tuefiSourcePaths, uefiVarsPaths := generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure)\n\n\t\treturn []PFlash{\n\t\t\t{\n\t\t\t\tSize:        0,\n\t\t\t\tSourcePaths: uefiSourcePaths,\n\t\t\t},\n\t\t\t{\n\t\t\t\tSize:        0,\n\t\t\t\tSourcePaths: uefiVarsPaths,\n\t\t\t},\n\t\t}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc generateUEFIPFlashList(uefiSourcePathPrefixes, uefiSourceFiles, uefiVarsFiles, uefiSourceFilesInsecure []string) (uefiSourcePaths, uefiVarsPaths []string) {\n\tfor _, p := range uefiSourcePathPrefixes {\n\t\tfor _, f := range uefiSourceFiles {\n\t\t\tuefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))\n\t\t}\n\n\t\tfor _, f := range uefiVarsFiles {\n\t\t\tuefiVarsPaths = append(uefiVarsPaths, filepath.Join(p, f))\n\t\t}\n\t}\n\n\tfor _, p := range uefiSourcePathPrefixes {\n\t\tfor _, f := range uefiSourceFilesInsecure {\n\t\t\tuefiSourcePaths = append(uefiSourcePaths, filepath.Join(p, f))\n\t\t}\n\t}\n\n\treturn uefiSourcePaths, uefiVarsPaths\n}\n\n// QemuExecutable returns name of qemu executable for the arch.\nfunc (arch Arch) QemuExecutable() string {\n\tbinaries := []string{\n\t\t\"qemu-system-\" + arch.QemuArch(),\n\t\t\"qemu-kvm\",\n\t\t\"/usr/libexec/qemu-kvm\",\n\t}\n\n\tfor _, binary := range binaries {\n\t\tif path, err := exec.LookPath(binary); err == nil {\n\t\t\treturn path\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\n// TPMDeviceArgs returns arguments for qemu to enable TPM device.\nfunc (arch Arch) TPMDeviceArgs(socketPath string) []string {\n\ttpmDeviceArgs := []string{\n\t\t\"-chardev\",\n\t\tfmt.Sprintf(\"socket,id=chrtpm,path=%s\", socketPath),\n\t\t\"-tpmdev\",\n\t\t\"emulator,id=tpm0,chardev=chrtpm\",\n\t\t\"-device\",\n\t}\n\n\tswitch arch {\n\tcase ArchAmd64:\n\t\treturn slices.Concat(tpmDeviceArgs, []string{\"tpm-tis,tpmdev=tpm0\"})\n\tcase ArchArm64:\n\t\treturn slices.Concat(tpmDeviceArgs, []string{\"tpm-tis-device,tpmdev=tpm0\"})\n\tdefault:\n\t\tpanic(\"unsupported architecture\")\n\t}\n}\n\nfunc (arch Arch) getMachineArgs(iommu bool) []string {\n\targs := arch.QemuMachine()\n\tif arch.acceleratorAvailable() {\n\t\targs += \",accel=\" + accelerator\n\t}\n\n\t// ref: https://wiki.qemu.org/Features/VT-d\n\tif iommu {\n\t\targs += \",kernel-irqchip=split\"\n\t}\n\n\tif arch == ArchAmd64 {\n\t\targs += \",smm=on\"\n\t}\n\n\treturn []string{\"-machine\", args}\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/arch_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport \"runtime\"\n\nconst accelerator = \"hvf\"\n\nfunc (arch Arch) acceleratorAvailable() bool {\n\t// hvf only supports emulating native architectures\n\treturn string(arch) == runtime.GOARCH\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/arch_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport \"runtime\"\n\nconst accelerator = \"kvm\"\n\nfunc (arch Arch) acceleratorAvailable() bool {\n\tif err := checkKVM(); err != nil {\n\t\treturn false\n\t}\n\n\t// kvm only supports emulating native architectures\n\treturn string(arch) == runtime.GOARCH\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"sync\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\n// PowerState is current VM power state.\ntype PowerState string\n\n// Virtual machine power state.\nconst (\n\tPoweredOn  PowerState = \"on\"\n\tPoweredOff PowerState = \"off\"\n)\n\n// VMCommand is a translated VM command.\ntype VMCommand string\n\n// Virtual machine commands.\nconst (\n\tVMCommandStart VMCommand = \"start\"\n\tVMCommandStop  VMCommand = \"stop\"\n)\n\n// Controller supports IPMI-like machine control.\ntype Controller struct {\n\tmu    sync.Mutex\n\tstate PowerState\n\n\tforcePXEBoot bool\n\n\tcommandsCh chan VMCommand\n}\n\n// NewController initializes controller in \"powered on\" state.\nfunc NewController() *Controller {\n\treturn &Controller{\n\t\tstate:      PoweredOn,\n\t\tcommandsCh: make(chan VMCommand),\n\t}\n}\n\n// PowerOn implements vm.Controller interface.\nfunc (c *Controller) PowerOn() error {\n\tc.mu.Lock()\n\n\tif c.state == PoweredOn {\n\t\tc.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\tc.state = PoweredOn\n\tc.mu.Unlock()\n\n\tc.commandsCh <- VMCommandStart\n\n\treturn nil\n}\n\n// PowerOff implements vm.Controller interface.\nfunc (c *Controller) PowerOff() error {\n\tc.mu.Lock()\n\n\tif c.state == PoweredOff {\n\t\tc.mu.Unlock()\n\n\t\treturn nil\n\t}\n\n\tc.state = PoweredOff\n\tc.mu.Unlock()\n\n\tc.commandsCh <- VMCommandStop\n\n\treturn nil\n}\n\n// Reboot implements vm.Controller interface.\nfunc (c *Controller) Reboot() error {\n\tc.mu.Lock()\n\n\tif c.state == PoweredOff {\n\t\tc.state = PoweredOn\n\n\t\tc.mu.Unlock()\n\n\t\tc.commandsCh <- VMCommandStart\n\n\t\treturn nil\n\t}\n\n\tc.mu.Unlock()\n\n\tc.commandsCh <- VMCommandStop\n\n\treturn nil\n}\n\n// PXEBootOnce implements vm.Controller interface.\nfunc (c *Controller) PXEBootOnce() error {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tc.forcePXEBoot = true\n\n\treturn nil\n}\n\n// Status implements vm.Controller interface.\nfunc (c *Controller) Status() vm.Status {\n\treturn vm.Status{\n\t\tPoweredOn: c.PowerState() == PoweredOn,\n\t}\n}\n\n// PowerState returns current power state.\nfunc (c *Controller) PowerState() PowerState {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\treturn c.state\n}\n\n// ForcePXEBoot returns whether next boot should be PXE boot.\nfunc (c *Controller) ForcePXEBoot() bool {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif c.forcePXEBoot {\n\t\tc.forcePXEBoot = false\n\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// CommandsCh returns channel with commands.\nfunc (c *Controller) CommandsCh() <-chan VMCommand {\n\treturn c.commandsCh\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/create.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Create Talos cluster as a set of qemu VMs.\n//\n//nolint:gocyclo,cyclop\nfunc (p *provisioner) Create(ctx context.Context, request provision.ClusterRequest, opts ...provision.Option) (provision.Cluster, error) {\n\toptions := provision.DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tarch := Arch(options.TargetArch)\n\tif err := arch.Valid(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := p.preflightChecks(ctx, request, options, arch); err != nil {\n\t\treturn nil, err\n\t}\n\n\tstatePath := filepath.Join(request.StateDirectory, request.Name)\n\n\tfmt.Fprintf(options.LogWriter, \"creating state directory in %q\\n\", statePath)\n\n\tstate, err := provision.NewState(\n\t\tstatePath,\n\t\tp.Name,\n\t\trequest.Name,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.SiderolinkEnabled {\n\t\tfmt.Fprintln(options.LogWriter, \"creating siderolink agent\")\n\n\t\tif err = p.CreateSiderolinkAgent(state, request); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfmt.Fprintln(options.LogWriter, \"created siderolink agent\")\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating network\", request.Network.Name)\n\n\tif err = p.CreateNetwork(ctx, state, request.Network, options); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to provision CNI network: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating load balancer\")\n\n\tif err = p.CreateLoadBalancer(state, request); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating loadbalancer: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating dnsd\")\n\n\tif err = p.CreateDNSd(state, request); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating dnsd: %w\", err)\n\t}\n\n\tif hasVirtiofsDisk(request.Nodes.WorkerNodes()) {\n\t\tvirtiofsdBin, err := p.FindVirtiofsd()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"virtiofsd lookup: %w\", err)\n\t\t}\n\n\t\tif virtiofsdBin != \"\" {\n\t\t\tfmt.Fprintln(options.LogWriter, \"creating virtiofsd using\", virtiofsdBin)\n\n\t\t\tif err = p.CreateVirtiofsd(state, request, virtiofsdBin); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"error creating virtiofsd: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tfmt.Fprintln(options.LogWriter, \"virtiofsd not found, skipping\")\n\t\t}\n\t}\n\n\tif request.Network.ImageCachePath != \"\" {\n\t\tfmt.Fprintln(options.LogWriter, \"creating image cache\")\n\n\t\tif err = p.CreateImageCache(state, request); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating image cache: %w\", err)\n\t\t}\n\t}\n\n\tif options.KMSEndpoint != \"\" {\n\t\tfmt.Fprintln(options.LogWriter, \"creating KMS server\")\n\n\t\tif err = p.CreateKMS(state, request, options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating KMS server: %w\", err)\n\t\t}\n\t}\n\n\tif options.JSONLogsEndpoint != \"\" {\n\t\tfmt.Fprintln(options.LogWriter, \"creating JSON logs server\")\n\n\t\tif err = p.CreateJSONLogs(state, request, options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating JSON logs server: %w\", err)\n\t\t}\n\t}\n\n\tvar nodeInfo []provision.NodeInfo //nolint:prealloc // this is created by p.createNodes\n\n\tfmt.Fprintln(options.LogWriter, \"creating controlplane nodes\")\n\n\tif nodeInfo, err = p.createNodes(ctx, state, request, request.Nodes.ControlPlaneNodes(), &options); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// On darwin, qemu creates the bridge interface to which the dhcpd server is attached to, so at least one machine has to be created first.\n\tfmt.Fprintln(options.LogWriter, \"creating dhcpd\")\n\n\tif err = p.CreateDHCPd(ctx, state, request); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating dhcpd: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"creating worker nodes\")\n\n\tvar workerNodeInfo []provision.NodeInfo\n\n\tif workerNodeInfo, err = p.createNodes(ctx, state, request, request.Nodes.WorkerNodes(), &options); err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar pxeNodeInfo []provision.NodeInfo\n\n\tpxeNodes := request.Nodes.PXENodes()\n\tif len(pxeNodes) > 0 {\n\t\tfmt.Fprintln(options.LogWriter, \"creating PXE nodes\")\n\n\t\tif pxeNodeInfo, err = p.createNodes(ctx, state, request, pxeNodes, &options); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tnodeInfo = append(nodeInfo, workerNodeInfo...)\n\n\tlbPort := constants.DefaultControlPlanePort\n\n\tif len(request.Network.LoadBalancerPorts) > 0 {\n\t\tlbPort = request.Network.LoadBalancerPorts[0]\n\t}\n\n\tstate.ClusterInfo = provision.ClusterInfo{\n\t\tClusterName: request.Name,\n\t\tNetwork: provision.NetworkInfo{\n\t\t\tName:              request.Network.Name,\n\t\t\tCIDRs:             request.Network.CIDRs,\n\t\t\tNoMasqueradeCIDRs: request.Network.NoMasqueradeCIDRs,\n\t\t\tGatewayAddrs:      request.Network.GatewayAddrs,\n\t\t\tMTU:               request.Network.MTU,\n\t\t},\n\t\tNodes:              nodeInfo,\n\t\tExtraNodes:         pxeNodeInfo,\n\t\tKubernetesEndpoint: p.GetExternalKubernetesControlPlaneEndpoint(request.Network, lbPort),\n\t}\n\n\tif err := state.Save(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn state, nil\n}\n\nfunc hasVirtiofsDisk(nodes []provision.NodeRequest) bool {\n\tfor _, node := range nodes {\n\t\tfor _, disk := range node.Disks {\n\t\t\tif disk.Driver == \"virtiofs\" {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/destroy.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\tcl \"github.com/siderolabs/talos/pkg/cluster\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Destroy Talos cluster as set of qemu VMs.\n//\n//nolint:gocyclo,cyclop\nfunc (p *provisioner) Destroy(ctx context.Context, cluster provision.Cluster, opts ...provision.Option) error {\n\toptions := provision.DefaultOptions()\n\n\tfor _, opt := range opts {\n\t\tif err := opt(&options); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tstateDirectoryPath, err := cluster.StatePath()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcomplete := false\n\tdeleteStateDirectory := func(stateDir string, shouldDelete bool) error {\n\t\tif complete || !shouldDelete {\n\t\t\treturn nil\n\t\t}\n\n\t\tcomplete = true\n\n\t\treturn os.RemoveAll(stateDir)\n\t}\n\n\tdefer deleteStateDirectory(stateDirectoryPath, options.DeleteStateOnErr) //nolint:errcheck\n\n\tif options.SaveSupportArchivePath != \"\" {\n\t\tfmt.Fprintf(options.LogWriter, \"saving support archive to %s\\n\", options.SaveSupportArchivePath)\n\n\t\tcl.Crashdump(ctx, cluster, options.LogWriter, options.SaveSupportArchivePath)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"stopping VMs\")\n\n\tif err := p.DestroyNodes(cluster.Info(), &options); err != nil {\n\t\treturn err\n\t}\n\n\tif err := p.destroyVirtualTPMs(cluster.Info()); err != nil {\n\t\treturn err\n\t}\n\n\tstate, ok := cluster.(*provision.State)\n\tif !ok {\n\t\treturn fmt.Errorf(\"error inspecting QEMU state, %#+v\", cluster)\n\t}\n\n\tif err := p.destroySHMFiles(state); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing dhcpd\")\n\n\tif err := p.DestroyDHCPd(state); err != nil {\n\t\treturn fmt.Errorf(\"error stopping dhcpd: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing image cache\")\n\n\tif err = p.DestroyImageCache(state); err != nil {\n\t\treturn fmt.Errorf(\"error stopping image cache: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing virtiofsd\")\n\n\tif err := p.DestroyVirtiofsd(state); err != nil {\n\t\treturn fmt.Errorf(\"error stopping virtiofsd: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing dnsd\")\n\n\tif err := p.DestroyDNSd(state); err != nil {\n\t\treturn fmt.Errorf(\"error stopping dnsd: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing load balancer\")\n\n\tif err := p.DestroyLoadBalancer(state); err != nil {\n\t\treturn fmt.Errorf(\"error stopping loadbalancer: %w\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing kms\")\n\n\tif err := p.DestroyKMS(state); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing network\")\n\n\tif err := p.DestroyNetwork(state); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing siderolink agent\")\n\n\tif err := p.DestroySiderolinkAgent(state); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing state directory\")\n\n\tif options.SaveClusterLogsArchivePath != \"\" {\n\t\tfmt.Fprintf(options.LogWriter, \"saving cluster logs archive to %s\\n\", options.SaveClusterLogsArchivePath)\n\n\t\tcl.SaveClusterLogsArchive(stateDirectoryPath, options.SaveClusterLogsArchivePath)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"removing json logs\")\n\n\tif err := p.DestroyJSONLogs(state); err != nil {\n\t\treturn err\n\t}\n\n\treturn deleteStateDirectory(stateDirectoryPath, true)\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/go-blockdevice/v2/blkid\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\n// LaunchConfig is passed in to the Launch function over stdin.\ntype LaunchConfig struct {\n\tStatePath string\n\n\t// VM options\n\tDiskPaths                 []string\n\tDiskDrivers               []string\n\tDiskTags                  []string\n\tDiskSerials               []string\n\tDiskBlockSizes            []uint\n\tVCPUCount                 int64\n\tMemSize                   int64\n\tMemShmPath                string\n\tKernelImagePath           string\n\tInitrdPath                string\n\tISOPath                   string\n\tUSBPath                   string\n\tUKIPath                   string\n\tExtraISOPath              string\n\tPFlashImages              []string\n\tKernelArgs                string\n\tSDStubKernelArgs          string\n\tMonitorPath               string\n\tDefaultBootOrder          string\n\tBootloaderEnabled         bool\n\tTPMConfig                 tpmConfig\n\tNodeUUID                  uuid.UUID\n\tBadRTC                    bool\n\tArchitectureData          Arch\n\tWithDebugShell            bool\n\tIOMMUEnabled              bool\n\tSkipInjectingExtraCmdline bool\n\n\t// Talos config\n\tConfig string\n\n\t// PXE\n\tTFTPServer       string\n\tBootFilename     string\n\tIPXEBootFileName string\n\n\t// API\n\tAPIBindAddress *net.TCPAddr\n\n\t// sd-stub\n\tsdStubExtraCmdline       string\n\tsdStubExtraCmdlineConfig string\n\n\t// platform specific Network configuration\n\tNetwork networkConfig\n\n\tVMMac string\n\n\t// signals\n\tc chan os.Signal\n\n\t// controller\n\tcontroller *Controller\n}\n\ntype networkConfigBase struct {\n\tBridgeName   string\n\tIPs          []netip.Addr\n\tCIDRs        []netip.Prefix\n\tGatewayAddrs []netip.Addr\n\tHostname     string\n\tMTU          int\n\tNameservers  []netip.Addr\n}\n\ntype tpmConfig struct {\n\tNodeName string\n\tStateDir string\n\n\tTPM2 bool\n}\n\n// launchVM runs qemu with args built based on config.\n//\n//nolint:gocyclo,cyclop\nfunc launchVM(config *LaunchConfig) error {\n\tbootOrder := config.DefaultBootOrder\n\n\tif config.controller.ForcePXEBoot() {\n\t\tbootOrder = \"nc\"\n\t}\n\n\tcpuArg := \"max\"\n\n\tif config.BadRTC {\n\t\tcpuArg += \",-kvmclock\"\n\t}\n\n\targs := []string{\n\t\t\"-m\", strconv.FormatInt(config.MemSize, 10),\n\t\t\"-smp\", fmt.Sprintf(\"cpus=%d\", config.VCPUCount),\n\t\t\"-cpu\", cpuArg,\n\t\t\"-nographic\",\n\t\t\"-netdev\", getNetdevParams(config.Network, \"net0\"),\n\t\t\"-device\", fmt.Sprintf(\"virtio-net-pci,netdev=net0,mac=%s,host_mtu=%d\", config.VMMac, config.Network.MTU),\n\t\t// TODO: uncomment the following line to get another eth interface not connected to anything\n\t\t// \"-nic\", \"tap,model=e1000,script=no,downscript=no\",\n\t\t\"-device\", \"virtio-rng-pci\",\n\t\t\"-device\", \"virtio-balloon,deflate-on-oom=on\",\n\t\t\"-monitor\", fmt.Sprintf(\"unix:%s,server,nowait\", config.MonitorPath),\n\t\t\"-no-reboot\",\n\t\t\"-boot\", fmt.Sprintf(\"order=%s,reboot-timeout=5000\", bootOrder),\n\t\t\"-smbios\", fmt.Sprintf(\"type=1,uuid=%s\", config.NodeUUID),\n\t\t\"-chardev\", fmt.Sprintf(\"socket,path=%s/%s.sock,server=on,wait=off,id=qga0\", config.StatePath, config.Network.Hostname),\n\t\t\"-device\", \"virtio-serial\",\n\t\t\"-device\", \"virtserialport,chardev=qga0,name=org.qemu.guest_agent.0\",\n\t\t\"-device\", \"i6300esb,id=watchdog0\",\n\t\t\"-watchdog-action\", \"pause\",\n\t}\n\n\tif config.WithDebugShell {\n\t\targs = append(\n\t\t\targs,\n\t\t\t\"-serial\",\n\t\t\tfmt.Sprintf(\"unix:%s/%s.serial,server,nowait\", config.StatePath, config.Network.Hostname),\n\t\t)\n\t}\n\n\tvar (\n\t\tscsiAttached, ahciAttached, nvmeAttached, megaraidAttached, virtiofsAttached bool\n\t\tahciBus                                                                      int\n\t)\n\n\tfor i, disk := range config.DiskPaths {\n\t\tdriver := config.DiskDrivers[i]\n\t\tblockSize := config.DiskBlockSizes[i]\n\n\t\ttag := config.DiskTags[i]\n\t\tif tag == \"\" {\n\t\t\ttag = fmt.Sprintf(\"disk%d\", i)\n\t\t}\n\n\t\tserial := \"\"\n\t\tif config.DiskSerials[i] != \"\" {\n\t\t\tserial = \",serial=\" + config.DiskSerials[i]\n\t\t}\n\n\t\tswitch driver {\n\t\tcase \"virtio\":\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"id=virtio%d,format=raw,if=none,file=%s,cache=none\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"virtio-blk-pci,drive=virtio%d,logical_block_size=%d,physical_block_size=%d%s\", i, blockSize, blockSize, serial),\n\t\t\t)\n\n\t\tcase \"ide\":\n\t\t\targs = append(args, \"-drive\", fmt.Sprintf(\"format=raw,if=ide,file=%s,cache=none\", disk))\n\n\t\tcase \"ahci\":\n\t\t\tif !ahciAttached {\n\t\t\t\targs = append(args, \"-device\", \"ahci,id=ahci0\")\n\t\t\t\tahciAttached = true\n\t\t\t}\n\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"id=ide%d,format=raw,if=none,file=%s\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"ide-hd,drive=ide%d,bus=ahci0.%d\", i, ahciBus),\n\t\t\t)\n\n\t\t\tahciBus++\n\n\t\tcase \"scsi\":\n\t\t\tif !scsiAttached {\n\t\t\t\targs = append(args, \"-device\", \"virtio-scsi-pci,id=scsi0\")\n\t\t\t\tscsiAttached = true\n\t\t\t}\n\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"id=scsi%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"scsi-hd,drive=scsi%d,bus=scsi0.0,logical_block_size=%d,physical_block_size=%d\", i, blockSize, blockSize),\n\t\t\t)\n\n\t\tcase \"nvme\":\n\t\t\tif !nvmeAttached {\n\t\t\t\t// [TODO]: once Talos is fixed, use multipath NVME: https://qemu-project.gitlab.io/qemu/system/devices/nvme.html\n\t\t\t\targs = append(args,\n\t\t\t\t\t\"-device\", \"nvme,id=nvme-ctrl-0,serial=deadbeef\",\n\t\t\t\t)\n\t\t\t\tnvmeAttached = true\n\t\t\t}\n\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"id=nvme%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"nvme-ns,drive=nvme%d,logical_block_size=%d,physical_block_size=%d\", i, blockSize, blockSize),\n\t\t\t)\n\n\t\tcase \"megaraid\":\n\t\t\tif !megaraidAttached {\n\t\t\t\targs = append(args,\n\t\t\t\t\t\"-device\", \"megasas-gen2,id=scsi1\")\n\n\t\t\t\tmegaraidAttached = true\n\t\t\t}\n\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"id=scsi%d,format=raw,if=none,file=%s,discard=unmap,aio=native,cache=none\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"scsi-hd,drive=scsi%d,bus=scsi1.0,channel=0,scsi-id=%d,lun=0,logical_block_size=%d,physical_block_size=%d\", i, i, blockSize, blockSize),\n\t\t\t)\n\n\t\tcase \"virtiofs\":\n\t\t\tif runtime.GOOS != \"linux\" {\n\t\t\t\treturn fmt.Errorf(\"virtiofs driver is only supported on linux hosts\")\n\t\t\t}\n\n\t\t\tif !virtiofsAttached {\n\t\t\t\targs = append(args,\n\t\t\t\t\t\"-object\", fmt.Sprintf(\"memory-backend-file,id=mem,size=%sM,mem-path=%s,share=on\", strconv.FormatInt(config.MemSize, 10), config.MemShmPath),\n\t\t\t\t\t\"-numa\", \"node,memdev=mem\",\n\t\t\t\t)\n\n\t\t\t\tvirtiofsAttached = true\n\t\t\t}\n\n\t\t\targs = append(args,\n\t\t\t\t\"-chardev\", fmt.Sprintf(\"socket,id=char%d,path=%s\", i, disk),\n\t\t\t\t\"-device\", fmt.Sprintf(\"vhost-user-fs-pci,queue-size=1024,chardev=char%d,tag=%s\", i, tag),\n\t\t\t)\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported disk driver %q\", driver)\n\t\t}\n\t}\n\n\targs = append(args, config.ArchitectureData.getMachineArgs(config.IOMMUEnabled)...)\n\n\tpflashArgs := make([]string, 2*len(config.PFlashImages))\n\tfor i := range config.PFlashImages {\n\t\tpflashArgs[2*i] = \"-drive\"\n\t\tpflashArgs[2*i+1] = fmt.Sprintf(\"file=%s,format=raw,if=pflash\", config.PFlashImages[i])\n\t}\n\n\targs = append(args, pflashArgs...)\n\n\tif config.ExtraISOPath != \"\" {\n\t\targs = append(args,\n\t\t\t\"-drive\",\n\t\t\tfmt.Sprintf(\"id=cdrom1,file=%s,media=cdrom\", config.ExtraISOPath),\n\t\t)\n\t}\n\n\t// check if disk is empty/wiped\n\tdiskBootable, err := checkPartitions(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif config.TPMConfig.NodeName != \"\" {\n\t\ttpm2SocketPath := filepath.Join(config.TPMConfig.StateDir, \"swtpm.sock\")\n\n\t\tswtpmArgs := []string{\n\t\t\t\"socket\",\n\t\t\t\"--tpmstate\",\n\t\t\tfmt.Sprintf(\"dir=%s,mode=0644\", config.TPMConfig.StateDir),\n\t\t\t\"--ctrl\",\n\t\t\tfmt.Sprintf(\"type=unixio,path=%s\", tpm2SocketPath),\n\t\t\t\"--pid\",\n\t\t\tfmt.Sprintf(\"file=%s\", filepath.Join(config.TPMConfig.StateDir, \"swtpm.pid\")),\n\t\t\t\"--log\",\n\t\t\tfmt.Sprintf(\"file=%s,level=20\", filepath.Join(config.TPMConfig.StateDir, \"swtpm.log\")),\n\t\t}\n\n\t\tif config.TPMConfig.TPM2 {\n\t\t\tswtpmArgs = append(swtpmArgs, \"--tpm2\")\n\t\t}\n\n\t\tcmd := exec.Command(\"swtpm\", swtpmArgs...) //nolint:noctx // runs in background\n\n\t\tlog.Printf(\"starting swtpm: %s\", cmd.String())\n\n\t\tif err := cmd.Start(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err := waitForFileToExist(tpm2SocketPath, 5*time.Second); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\targs = append(args,\n\t\t\tconfig.ArchitectureData.TPMDeviceArgs(tpm2SocketPath)...,\n\t\t)\n\t}\n\n\t// ref: https://wiki.qemu.org/Features/VT-d\n\tif config.IOMMUEnabled {\n\t\targs = append(args,\n\t\t\t\"-device\", \"intel-iommu,intremap=on,device-iotlb=on\",\n\t\t\t\"-device\", \"ioh3420,id=pcie.1,chassis=1\",\n\t\t\t\"-device\", \"e1000,bus=pcie.1,netdev=net1\",\n\t\t\t\"-netdev\", \"tap,id=net1,vhostforce=on,script=no,downscript=no\",\n\t\t)\n\t}\n\n\tif !diskBootable || !config.BootloaderEnabled {\n\t\t// if the disk is bootable, and we were forced to disable disk bootloader,\n\t\t// we need to skip ISO/USB boot, as it will fall back to boot from disk\n\t\tskipBootloader := diskBootable && !config.BootloaderEnabled\n\n\t\tswitch {\n\t\tcase config.ISOPath != \"\" && !skipBootloader:\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\",\n\t\t\t\tfmt.Sprintf(\"id=cdrom0,file=%s,media=cdrom\", config.ISOPath),\n\t\t\t)\n\t\tcase config.USBPath != \"\" && !skipBootloader:\n\t\t\targs = append(args,\n\t\t\t\t\"-drive\", fmt.Sprintf(\"if=none,id=stick,format=raw,read-only=on,file=%s\", config.USBPath),\n\t\t\t\t\"-device\", \"nec-usb-xhci,id=xhci\",\n\t\t\t\t\"-device\", \"usb-storage,bus=xhci.0,drive=stick,removable=on\",\n\t\t\t)\n\t\tcase config.UKIPath != \"\":\n\t\t\targs = append(args,\n\t\t\t\t\"-kernel\", config.UKIPath,\n\t\t\t\t\"-append\", config.KernelArgs,\n\t\t\t)\n\t\t\tconfig.sdStubExtraCmdline += config.sdStubExtraCmdlineConfig\n\t\tcase config.KernelImagePath != \"\":\n\t\t\targs = append(args,\n\t\t\t\t\"-kernel\", config.KernelImagePath,\n\t\t\t\t\"-initrd\", config.InitrdPath,\n\t\t\t\t\"-append\", config.KernelArgs,\n\t\t\t)\n\t\t\tconfig.sdStubExtraCmdline += config.sdStubExtraCmdlineConfig\n\t\t}\n\t}\n\n\tif !config.SkipInjectingExtraCmdline {\n\t\targs = append(args,\n\t\t\t\"-smbios\", fmt.Sprintf(\"type=11,value=%s=%s\", constants.SDStubCmdlineExtraOEMVar, config.sdStubExtraCmdline),\n\t\t)\n\t}\n\n\tif config.BadRTC {\n\t\targs = append(args,\n\t\t\t\"-rtc\",\n\t\t\t\"base=2011-11-11T11:11:00,clock=rt\",\n\t\t)\n\t}\n\n\tfmt.Fprintf(os.Stderr, \"starting %s with args:\\n%s\\n\", config.ArchitectureData.QemuExecutable(), strings.Join(args, \" \"))\n\tcmd := exec.Command( //nolint:noctx // runs in background\n\t\tconfig.ArchitectureData.QemuExecutable(),\n\t\targs...,\n\t)\n\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\tif err := startQemuCmd(config, cmd); err != nil {\n\t\treturn err\n\t}\n\n\tdone := make(chan error)\n\n\tgo func() {\n\t\tdone <- cmd.Wait()\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase sig := <-config.c:\n\t\t\tfmt.Fprintf(os.Stderr, \"exiting VM as signal %s was received\\n\", sig)\n\n\t\t\tif err := cmd.Process.Kill(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to kill process %w\", err)\n\t\t\t}\n\n\t\t\t<-done\n\n\t\t\treturn errors.New(\"process stopped\")\n\t\tcase err := <-done:\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"process exited with error %s\", err)\n\t\t\t}\n\n\t\t\t// graceful exit\n\t\t\treturn nil\n\t\tcase command := <-config.controller.CommandsCh():\n\t\t\tif command == VMCommandStop {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"exiting VM as stop command via API was received\\n\")\n\n\t\t\t\tif err := cmd.Process.Kill(); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to kill process %w\", err)\n\t\t\t\t}\n\n\t\t\t\t<-done\n\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Launch a control process around qemu VM manager.\n//\n// This function is invoked from 'talosctl qemu-launch' hidden command\n// and wraps starting, controlling 'qemu' VM process.\n//\n// Launch restarts VM forever until control process is stopped itself with a signal.\n//\n// Process is expected to receive configuration on stdin. Current working directory\n// should be cluster state directory, process output should be redirected to the\n// logfile in state directory.\n//\n// When signals SIGINT, SIGTERM are received, control process stops qemu and exits.\n//\n//nolint:gocyclo\nfunc Launch() error {\n\tvar config LaunchConfig\n\n\tctx := context.Background()\n\n\tif err := vm.ReadConfig(&config); err != nil {\n\t\treturn err\n\t}\n\n\tconfig.c = vm.ConfigureSignals()\n\tconfig.controller = NewController()\n\n\tapiBindAddrs, err := netip.ParseAddr(config.APIBindAddress.IP.String())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttpServer, err := vm.NewHTTPServer(ctx, apiBindAddrs, config.APIBindAddress.Port, []byte(config.Config), config.controller)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttpServer.Serve()\n\tdefer httpServer.Shutdown(ctx) //nolint:errcheck\n\n\tif err := patchKernelArgs(&config, httpServer.GetAddr()); err != nil {\n\t\treturn err\n\t}\n\n\treturn withNetworkContext(ctx, &config, func(config *LaunchConfig) error {\n\t\terr = dumpIpam(*config)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor {\n\t\t\tfor config.controller.PowerState() != PoweredOn {\n\t\t\t\tselect {\n\t\t\t\tcase <-config.controller.CommandsCh():\n\t\t\t\t\t// machine might have been powered on\n\t\t\t\tcase sig := <-config.c:\n\t\t\t\t\tfmt.Fprintf(os.Stderr, \"exiting stopped launcher as signal %s was received\\n\", sig)\n\n\t\t\t\t\treturn errors.New(\"process stopped\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := launchVM(config); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc patchKernelArgs(config *LaunchConfig, httpServerAddr net.Addr) error {\n\tconfigServerAddr, err := getConfigServerAddr(httpServerAddr, *config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconfig.sdStubExtraCmdline = \"console=ttyS0\"\n\n\tif config.SDStubKernelArgs != \"\" {\n\t\tconfig.sdStubExtraCmdline += \" \" + config.SDStubKernelArgs\n\t}\n\n\tif strings.Contains(config.KernelArgs, \"{TALOS_CONFIG_URL}\") {\n\t\tconfig.KernelArgs = strings.ReplaceAll(config.KernelArgs, \"{TALOS_CONFIG_URL}\", fmt.Sprintf(\"http://%s/config.yaml\", configServerAddr))\n\t\tconfig.sdStubExtraCmdlineConfig = fmt.Sprintf(\" talos.config=http://%s/config.yaml\", httpServerAddr)\n\t}\n\n\treturn nil\n}\n\nfunc waitForFileToExist(path string, timeout time.Duration) error {\n\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\tdefer cancel()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:\n\t\t\tif _, err := os.Stat(path); err == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}\n}\n\nfunc dumpIpam(config LaunchConfig) error {\n\tfor j := range config.Network.CIDRs {\n\t\tnameservers := make([]netip.Addr, 0, len(config.Network.Nameservers))\n\n\t\t// filter nameservers by IPv4/IPv6 matching IPs\n\t\tfor i := range config.Network.Nameservers {\n\t\t\tif config.Network.IPs[j].Is6() {\n\t\t\t\tif config.Network.Nameservers[i].Is6() {\n\t\t\t\t\tnameservers = append(nameservers, config.Network.Nameservers[i])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif config.Network.Nameservers[i].Is4() {\n\t\t\t\t\tnameservers = append(nameservers, config.Network.Nameservers[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// dump node IP/mac/hostname for dhcp\n\t\tif err := vm.DumpIPAMRecord(config.StatePath, vm.IPAMRecord{\n\t\t\tIP:               config.Network.IPs[j],\n\t\t\tNetmask:          byte(config.Network.CIDRs[j].Bits()),\n\t\t\tMAC:              config.VMMac,\n\t\t\tHostname:         config.Network.Hostname,\n\t\t\tGateway:          config.Network.GatewayAddrs[j],\n\t\t\tMTU:              config.Network.MTU,\n\t\t\tNameservers:      nameservers,\n\t\t\tTFTPServer:       config.TFTPServer,\n\t\t\tIPXEBootFilename: config.IPXEBootFileName,\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc checkPartitions(config *LaunchConfig) (bool, error) {\n\tinfo, err := blkid.ProbePath(config.DiskPaths[0], blkid.WithSectorSize(config.DiskBlockSizes[0]))\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"error probing disk: %w\", err)\n\t}\n\n\treturn info.Name == \"gpt\" && len(info.Parts) > 0, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/launch_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os/exec\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\ntype networkConfig struct {\n\tnetworkConfigBase\n\tStartAddr netip.Addr\n\tEndAddr   netip.Addr\n}\n\nfunc getLaunchNetworkConfig(state *provision.State, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest) networkConfig {\n\t// This ip will be assigned to the bridge\n\t// The following ips will be assigned to the vms\n\tstartAddr := clusterReq.Nodes[0].IPs[0].Prev()\n\tendAddr := clusterReq.Nodes[len(clusterReq.Nodes)-1].IPs[0].Next()\n\n\treturn networkConfig{\n\t\tnetworkConfigBase: getLaunchNetworkConfigBase(state, clusterReq, nodeReq),\n\t\tStartAddr:         startAddr,\n\t\tEndAddr:           endAddr,\n\t}\n}\n\nfunc getNetdevParams(networkConfig networkConfig, id string) string {\n\tnetDevArg := \"vmnet-shared,id=\" + id\n\tcidr := networkConfig.CIDRs[0]\n\tm := net.CIDRMask(cidr.Bits(), 32)\n\tsubnetMask := fmt.Sprintf(\"%d.%d.%d.%d\", m[0], m[1], m[2], m[3])\n\tnetDevArg += fmt.Sprintf(\",start-address=%s,end-address=%s,subnet-mask=%s\", networkConfig.StartAddr, networkConfig.EndAddr, subnetMask)\n\n\treturn netDevArg\n}\n\n// getConfigServerAddr returns the ip accessible to the VM that will route to the config server.\n// hostAddrs is the address on which the server is accessible from the host network.\nfunc getConfigServerAddr(hostAddrs net.Addr, config LaunchConfig) (netip.AddrPort, error) {\n\taddrPort, err := netip.ParseAddrPort(hostAddrs.String())\n\tif err != nil {\n\t\treturn netip.AddrPort{}, err\n\t}\n\n\treturn netip.AddrPortFrom(config.Network.GatewayAddrs[0], addrPort.Port()), nil\n}\n\n// withNetworkContext runs the f on the host network on darwin.\nfunc withNetworkContext(ctx context.Context, config *LaunchConfig, f func(config *LaunchConfig) error) error {\n\treturn f(config)\n}\n\n// startQemuCmd on darwin just runs cmd.Start.\nfunc startQemuCmd(_ *LaunchConfig, cmd *exec.Cmd) error {\n\treturn cmd.Start()\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/launch_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/alexflint/go-filemutex\"\n\t\"github.com/containernetworking/cni/libcni\"\n\t\"github.com/containernetworking/cni/pkg/types\"\n\ttypes100 \"github.com/containernetworking/cni/pkg/types/100\"\n\t\"github.com/containernetworking/plugins/pkg/ns\"\n\t\"github.com/containernetworking/plugins/pkg/testutils\"\n\t\"github.com/containernetworking/plugins/pkg/utils\"\n\t\"github.com/coreos/go-iptables/iptables\"\n\t\"github.com/google/uuid\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tsideronet \"github.com/siderolabs/net\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/internal/cniutils\"\n)\n\ntype networkConfig struct {\n\tnetworkConfigBase\n\n\tAirgapped bool\n\n\t// TODO: rename field to cniNetworkConfig\n\tCniNetworkConfig  *libcni.NetworkConfigList\n\tCNI               provision.CNIConfig\n\tNoMasqueradeCIDRs []netip.Prefix\n\n\t// filled by CNI invocation\n\ttapName string\n\tns      ns.NetNS\n}\n\nfunc getLaunchNetworkConfig(state *provision.State, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest) networkConfig {\n\treturn networkConfig{\n\t\tnetworkConfigBase: getLaunchNetworkConfigBase(state, clusterReq, nodeReq),\n\t\tCniNetworkConfig:  state.VMCNIConfig,\n\t\tCNI:               clusterReq.Network.CNI,\n\t\tNoMasqueradeCIDRs: clusterReq.Network.NoMasqueradeCIDRs,\n\t\tAirgapped:         clusterReq.Network.Airgapped,\n\t}\n}\n\nfunc getNetdevParams(networkConfig networkConfig, id string) string {\n\treturn fmt.Sprintf(\"tap,id=%s,ifname=%s,script=no,downscript=no\", id, networkConfig.tapName)\n}\n\nfunc getConfigServerAddr(hostAddrs net.Addr, _ LaunchConfig) (net.Addr, error) {\n\treturn hostAddrs, nil\n}\n\n// withCNIOperationLocked ensures that CNI operations don't run concurrently.\n//\n// There are race conditions in the CNI plugins that can cause a failure if called concurrently.\nfunc withCNIOperationLocked[T any](config *LaunchConfig, f func() (T, error)) (T, error) {\n\tvar zeroT T\n\n\tlock, err := filemutex.New(filepath.Join(config.StatePath, \"cni.lock\"))\n\tif err != nil {\n\t\treturn zeroT, fmt.Errorf(\"failed to create CNI lock: %w\", err)\n\t}\n\n\tif err = lock.Lock(); err != nil {\n\t\treturn zeroT, fmt.Errorf(\"failed to acquire CNI lock: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := lock.Close(); err != nil {\n\t\t\tlog.Printf(\"failed to release CNI lock: %s\", err)\n\t\t}\n\t}()\n\n\treturn f()\n}\n\n// withCNIOperationLockedNoResult ensures that CNI operations don't run concurrently.\nfunc withCNIOperationLockedNoResult(config *LaunchConfig, f func() error) error {\n\t_, err := withCNIOperationLocked(config, func() (struct{}, error) {\n\t\treturn struct{}{}, f()\n\t})\n\n\treturn err\n}\n\n// withNetworkContext creates a network namespace, launches CNI and passes control to the next function\n// filling config with netNS and interface details.\n//\n//nolint:gocyclo\nfunc withNetworkContext(ctx context.Context, config *LaunchConfig, f func(config *LaunchConfig) error) error {\n\t// random ID for the CNI, maps to single VM\n\tcontainerID := uuid.New().String()\n\n\tcniConfig := libcni.NewCNIConfigWithCacheDir(config.Network.CNI.BinPath, config.Network.CNI.CacheDir, nil)\n\n\t// create a network namespace\n\tns, err := testutils.NewNS()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tns.Close()              //nolint:errcheck\n\t\ttestutils.UnmountNS(ns) //nolint:errcheck\n\t}()\n\n\tips := make([]string, len(config.Network.IPs))\n\tfor j := range ips {\n\t\tips[j] = sideronet.FormatCIDR(config.Network.IPs[j], config.Network.CIDRs[j])\n\t}\n\n\tgatewayAddrs := xslices.Map(config.Network.GatewayAddrs, netip.Addr.String)\n\n\truntimeConf := libcni.RuntimeConf{\n\t\tContainerID: containerID,\n\t\tNetNS:       ns.Path(),\n\t\tIfName:      \"veth0\",\n\t\tArgs: [][2]string{\n\t\t\t{\"IP\", strings.Join(ips, \",\")},\n\t\t\t{\"GATEWAY\", strings.Join(gatewayAddrs, \",\")},\n\t\t\t{\"IgnoreUnknown\", \"1\"},\n\t\t},\n\t}\n\n\t// attempt to clean up network in case it was deployed previously\n\terr = withCNIOperationLockedNoResult(\n\t\tconfig,\n\t\tfunc() error {\n\t\t\treturn cniConfig.DelNetworkList(ctx, config.Network.CniNetworkConfig, &runtimeConf)\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting CNI network: %w\", err)\n\t}\n\n\tres, err := withCNIOperationLocked(\n\t\tconfig,\n\t\tfunc() (types.Result, error) {\n\t\t\treturn cniConfig.AddNetworkList(ctx, config.Network.CniNetworkConfig, &runtimeConf)\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error provisioning CNI network: %w\", err)\n\t}\n\n\tdefer func() {\n\t\tif e := withCNIOperationLockedNoResult(\n\t\t\tconfig,\n\t\t\tfunc() error {\n\t\t\t\treturn cniConfig.DelNetworkList(ctx, config.Network.CniNetworkConfig, &runtimeConf)\n\t\t\t},\n\t\t); e != nil {\n\t\t\tlog.Printf(\"error cleaning up CNI: %s\", e)\n\t\t}\n\t}()\n\n\tcurrentResult, err := types100.NewResultFromResult(res)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse cni result: %w\", err)\n\t}\n\n\tvmIface, tapIface, err := cniutils.VMTapPair(currentResult, containerID)\n\tif err != nil {\n\t\treturn errors.New(\n\t\t\t\"failed to parse VM network configuration from CNI output, ensure CNI is configured with a plugin \" +\n\t\t\t\t\"that supports automatic VM network configuration such as tc-redirect-tap\")\n\t}\n\n\tif !config.Network.Airgapped {\n\t\tcniChain := utils.FormatChainName(config.Network.CniNetworkConfig.Name, containerID)\n\n\t\tipt, err := iptables.New()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to initialize iptables: %w\", err)\n\t\t}\n\n\t\t// don't masquerade traffic with \"broadcast\" destination from the VM\n\t\t//\n\t\t// no need to clean up the rule, as CNI drops the whole chain\n\t\tif err = ipt.InsertUnique(\"nat\", cniChain, 1, \"--destination\", \"255.255.255.255/32\", \"-j\", \"ACCEPT\"); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to insert iptables rule to allow broadcast traffic: %w\", err)\n\t\t}\n\n\t\tfor _, cidr := range config.Network.NoMasqueradeCIDRs {\n\t\t\tif err = ipt.InsertUnique(\"nat\", cniChain, 1, \"--destination\", cidr.String(), \"-j\", \"ACCEPT\"); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to insert iptables rule to allow non-masquerade traffic to cidr %q: %w\", cidr.String(), err)\n\t\t\t}\n\t\t}\n\t}\n\n\tconfig.Network.tapName = tapIface.Name\n\tconfig.VMMac = vmIface.Mac\n\tconfig.Network.ns = ns\n\n\treturn f(config)\n}\n\nfunc startQemuCmd(config *LaunchConfig, cmd *exec.Cmd) error {\n\tif err := ns.WithNetNSPath(config.Network.ns.Path(), func(_ ns.NetNS) error {\n\t\treturn cmd.Start()\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/node.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-cmd/pkg/cmd\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n\t\"github.com/siderolabs/talos/pkg/machinery/kernel\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n//nolint:gocyclo,cyclop\nfunc (p *provisioner) createNode(ctx context.Context, state *provision.State, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest, opts *provision.Options) (provision.NodeInfo, error) {\n\tarch := Arch(opts.TargetArch)\n\tpidPath := state.GetRelativePath(fmt.Sprintf(\"%s.pid\", nodeReq.Name))\n\n\tvar pflashImages []string\n\n\tif pflashSpec := arch.PFlash(opts.UEFIEnabled, opts.ExtraUEFISearchPaths); pflashSpec != nil {\n\t\tvar err error\n\t\tif pflashImages, err = p.createPFlashImages(state, nodeReq.Name, pflashSpec); err != nil {\n\t\t\treturn provision.NodeInfo{}, fmt.Errorf(\"error creating flash images: %w\", err)\n\t\t}\n\t}\n\n\tvcpuCount := int64(math.RoundToEven(float64(nodeReq.NanoCPUs) / 1000 / 1000 / 1000))\n\tif vcpuCount < 2 {\n\t\tvcpuCount = 1\n\t}\n\n\tmemSize := nodeReq.Memory / 1024 / 1024\n\n\tdiskPaths, err := p.CreateDisks(state, nodeReq)\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\terr = p.populateSystemDisk(diskPaths, clusterReq)\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(fmt.Sprintf(\"%s.log\", nodeReq.Name)), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tcmdline := procfs.NewCmdline(\"\")\n\n\tcmdline.SetAll(kernel.DefaultArgs(nodeReq.Quirks))\n\n\t// required to get kernel console\n\tcmdline.Append(\"console\", arch.Console())\n\n\t// reboot configuration\n\tcmdline.Append(\"reboot\", \"k\")\n\tcmdline.Append(\"panic\", \"1\")\n\tcmdline.Append(\"talos.shutdown\", \"halt\")\n\n\t// Talos config\n\tcmdline.Append(\"talos.platform\", constants.PlatformMetal)\n\n\t// add overrides\n\tif nodeReq.ExtraKernelArgs != nil {\n\t\tif err = cmdline.AppendAll(\n\t\t\tnodeReq.ExtraKernelArgs.Strings(),\n\t\t\tprocfs.WithDeleteNegatedArgs(),\n\t\t); err != nil {\n\t\t\treturn provision.NodeInfo{}, err\n\t\t}\n\t}\n\n\tif opts.WithDebugShell {\n\t\tcmdline.Append(\"talos.debugshell\", \"\")\n\t}\n\n\tvar (\n\t\tnodeConfig   string\n\t\textraISOPath string\n\t)\n\n\tif !nodeReq.SkipInjectingConfig {\n\t\tnodeConfig, err = nodeReq.Config.EncodeString()\n\t\tif err != nil {\n\t\t\treturn provision.NodeInfo{}, err\n\t\t}\n\n\t\tswitch nodeReq.ConfigInjectionMethod {\n\t\tcase provision.ConfigInjectionMethodHTTP:\n\t\t\tcmdline.Append(\"talos.config\", \"{TALOS_CONFIG_URL}\") // to be patched by launcher\n\t\tcase provision.ConfigInjectionMethodMetalISO:\n\t\t\tcmdline.Append(\"talos.config\", \"metal-iso\")\n\n\t\t\textraISOPath, err = p.createMetalConfigISO(ctx, state, nodeReq.Name, nodeConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn provision.NodeInfo{}, fmt.Errorf(\"error creating metal-iso: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\tnodeUUID := uuid.New()\n\tif nodeReq.UUID != nil {\n\t\tnodeUUID = *nodeReq.UUID\n\t}\n\n\tapiBind, err := p.findAPIBindAddrs(ctx, clusterReq)\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, fmt.Errorf(\"error finding listen address for the API: %w\", err)\n\t}\n\n\tdefaultBootOrder := \"cd\"\n\tif nodeReq.DefaultBootOrder != \"\" {\n\t\tdefaultBootOrder = nodeReq.DefaultBootOrder\n\t}\n\n\t// backwards compatibility, set Driver/BlockSize if not set\n\tfor i := range nodeReq.Disks {\n\t\tif nodeReq.Disks[i].BlockSize == 0 {\n\t\t\tnodeReq.Disks[i].BlockSize = 512\n\t\t}\n\n\t\tif nodeReq.Disks[i].Driver != \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif i == 0 {\n\t\t\tnodeReq.Disks[i].Driver = \"virtio\"\n\t\t} else {\n\t\t\tnodeReq.Disks[i].Driver = \"ide\"\n\t\t}\n\t}\n\n\tlaunchConfig := LaunchConfig{\n\t\tArchitectureData: arch,\n\t\tDiskPaths:        diskPaths,\n\t\tDiskDrivers: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {\n\t\t\treturn disk.Driver\n\t\t}),\n\t\tDiskTags: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {\n\t\t\treturn disk.Tag\n\t\t}),\n\t\tDiskSerials: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) string {\n\t\t\treturn disk.Serial\n\t\t}),\n\t\tDiskBlockSizes: xslices.Map(nodeReq.Disks, func(disk *provision.Disk) uint {\n\t\t\treturn disk.BlockSize\n\t\t}),\n\t\tVCPUCount:                 vcpuCount,\n\t\tMemSize:                   memSize,\n\t\tMemShmPath:                state.GetShmPath(fmt.Sprintf(\"shm-%s\", nodeReq.Name)), // this is used only when attaching virtiofs disks\n\t\tKernelArgs:                cmdline.String(),\n\t\tExtraISOPath:              extraISOPath,\n\t\tPFlashImages:              pflashImages,\n\t\tMonitorPath:               state.GetRelativePath(fmt.Sprintf(\"%s.monitor\", nodeReq.Name)),\n\t\tBadRTC:                    nodeReq.BadRTC,\n\t\tDefaultBootOrder:          defaultBootOrder,\n\t\tBootloaderEnabled:         opts.BootloaderEnabled,\n\t\tSkipInjectingExtraCmdline: opts.SkipInjectingExtraCmdline,\n\t\tNodeUUID:                  nodeUUID,\n\t\tConfig:                    nodeConfig,\n\t\tTFTPServer:                nodeReq.TFTPServer,\n\t\tIPXEBootFileName:          nodeReq.IPXEBootFilename,\n\t\tAPIBindAddress:            apiBind,\n\t\tWithDebugShell:            opts.WithDebugShell,\n\t\tIOMMUEnabled:              opts.IOMMUEnabled,\n\t\tNetwork:                   getLaunchNetworkConfig(state, clusterReq, nodeReq),\n\n\t\t// Generate a random MAC address.\n\t\t// On linux this is later overridden to the interface mac.\n\t\tVMMac: getRandomMacAddress(),\n\t}\n\n\tif clusterReq.IPXEBootScript != \"\" {\n\t\tlaunchConfig.TFTPServer = clusterReq.Network.GatewayAddrs[0].String()\n\t\tlaunchConfig.IPXEBootFileName = fmt.Sprintf(\"ipxe/%s/snp.efi\", string(arch))\n\t}\n\n\tnodeInfo := provision.NodeInfo{\n\t\tID:   pidPath,\n\t\tUUID: nodeUUID,\n\t\tName: nodeReq.Name,\n\t\tType: nodeReq.Type,\n\n\t\tNanoCPUs: nodeReq.NanoCPUs,\n\t\tMemory:   nodeReq.Memory,\n\t\tDiskSize: nodeReq.Disks[0].Size,\n\n\t\tIPs: nodeReq.IPs,\n\n\t\tAPIPort: apiBind.Port,\n\t}\n\n\tif opts.TPM1_2Enabled || opts.TPM2Enabled {\n\t\ttpmConfig, tpm2Err := p.createVirtualTPMState(state, nodeReq.Name, opts.TPM2Enabled)\n\t\tif tpm2Err != nil {\n\t\t\treturn provision.NodeInfo{}, tpm2Err\n\t\t}\n\n\t\tlaunchConfig.TPMConfig = tpmConfig\n\t\tnodeInfo.TPMStateDir = tpmConfig.StateDir\n\t}\n\n\tif !clusterReq.Network.DHCPSkipHostname {\n\t\tlaunchConfig.Network.Hostname = nodeReq.Name\n\t}\n\n\tif nodeReq.SDStubKernelArgs != nil {\n\t\tlaunchConfig.SDStubKernelArgs = nodeReq.SDStubKernelArgs.String()\n\t}\n\n\tif !nodeReq.PXEBooted && launchConfig.IPXEBootFileName == \"\" {\n\t\tlaunchConfig.KernelImagePath = strings.ReplaceAll(clusterReq.KernelPath, constants.ArchVariable, opts.TargetArch)\n\t\tlaunchConfig.InitrdPath = strings.ReplaceAll(clusterReq.InitramfsPath, constants.ArchVariable, opts.TargetArch)\n\t\tlaunchConfig.ISOPath = strings.ReplaceAll(clusterReq.ISOPath, constants.ArchVariable, opts.TargetArch)\n\t\tlaunchConfig.USBPath = strings.ReplaceAll(clusterReq.USBPath, constants.ArchVariable, opts.TargetArch)\n\t\tlaunchConfig.UKIPath = strings.ReplaceAll(clusterReq.UKIPath, constants.ArchVariable, opts.TargetArch)\n\t}\n\n\tlaunchConfig.StatePath, err = state.StatePath()\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tlaunchConfigFile, err := os.Create(state.GetRelativePath(fmt.Sprintf(\"%s.config\", nodeReq.Name)))\n\tif err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tif err = json.NewEncoder(launchConfigFile).Encode(&launchConfig); err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tif _, err = launchConfigFile.Seek(0, io.SeekStart); err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tdefer launchConfigFile.Close() //nolint:errcheck\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, \"qemu-launch\") //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.Stdin = launchConfigFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn provision.NodeInfo{}, err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn provision.NodeInfo{}, fmt.Errorf(\"error writing PID file: %w\", err)\n\t}\n\n\t// no need to wait here, as cmd has all the Stdin/out/err via *os.File\n\n\treturn nodeInfo, nil\n}\n\nfunc (p *provisioner) createNodes(\n\tctx context.Context,\n\tstate *provision.State,\n\tclusterReq provision.ClusterRequest,\n\tnodeReqs []provision.NodeRequest,\n\topts *provision.Options,\n) ([]provision.NodeInfo, error) {\n\terrCh := make(chan error)\n\tnodeCh := make(chan provision.NodeInfo, len(nodeReqs))\n\n\tfor _, nodeReq := range nodeReqs {\n\t\tgo func(nodeReq provision.NodeRequest) {\n\t\t\tnodeInfo, err := p.createNode(ctx, state, clusterReq, nodeReq, opts)\n\t\t\tif err == nil {\n\t\t\t\tnodeCh <- nodeInfo\n\t\t\t}\n\n\t\t\terrCh <- err\n\t\t}(nodeReq)\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor range nodeReqs {\n\t\tmultiErr = multierror.Append(multiErr, <-errCh)\n\t}\n\n\tclose(nodeCh)\n\n\tnodesInfo := make([]provision.NodeInfo, 0, len(nodeReqs))\n\n\tfor nodeInfo := range nodeCh {\n\t\tnodesInfo = append(nodesInfo, nodeInfo)\n\t}\n\n\treturn nodesInfo, multiErr.ErrorOrNil()\n}\n\nfunc (p *provisioner) populateSystemDisk(disks []string, clusterReq provision.ClusterRequest) error {\n\tif len(disks) > 0 && clusterReq.DiskImagePath != \"\" {\n\t\tif err := p.handleOptionalZSTDDiskImage(disks[0], clusterReq.DiskImagePath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *provisioner) destroySHMFiles(state *provision.State) error {\n\tfor _, node := range state.Info().Nodes {\n\t\tif node.Type != machine.TypeWorker {\n\t\t\tcontinue\n\t\t}\n\n\t\tshmFilePath := state.GetShmPath(fmt.Sprintf(\"shm-%s\", node.Name))\n\n\t\tif err := os.RemoveAll(shmFilePath); err != nil && !os.IsNotExist(err) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *provisioner) handleOptionalZSTDDiskImage(provisionerDisk, diskImagePath string) error {\n\timage, err := os.Open(diskImagePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer image.Close() //nolint:errcheck\n\n\tdisk, err := os.OpenFile(provisionerDisk, os.O_RDWR, 0o755)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer disk.Close() //nolint:errcheck\n\n\tif strings.HasSuffix(diskImagePath, \".zst\") {\n\t\tzstdReader, err := zstd.NewReader(image)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer zstdReader.Close() //nolint:errcheck\n\n\t\t_, err = io.Copy(disk, zstdReader)\n\n\t\treturn err\n\t}\n\n\t_, err = io.Copy(disk, image)\n\n\treturn err\n}\n\nfunc (p *provisioner) createMetalConfigISO(ctx context.Context, state *provision.State, nodeName, config string) (string, error) {\n\tisoPath := state.GetRelativePath(nodeName + \"-metal-config.iso\")\n\n\ttmpDir, err := os.MkdirTemp(\"\", \"talos-metal-config-iso\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tdefer os.RemoveAll(tmpDir) //nolint:errcheck\n\n\tif err = os.WriteFile(filepath.Join(tmpDir, \"config.yaml\"), []byte(config), 0o644); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t_, err = cmd.RunWithOptions(ctx, \"mkisofs\", []string{\"-joliet\", \"-rock\", \"-volid\", \"metal-iso\", \"-output\", isoPath, tmpDir})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn isoPath, nil\n}\n\nfunc getLaunchNetworkConfigBase(state *provision.State, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest) networkConfigBase {\n\treturn networkConfigBase{\n\t\tBridgeName:   state.BridgeName,\n\t\tCIDRs:        clusterReq.Network.CIDRs,\n\t\tIPs:          nodeReq.IPs,\n\t\tGatewayAddrs: clusterReq.Network.GatewayAddrs,\n\t\tMTU:          clusterReq.Network.MTU,\n\t\tNameservers:  clusterReq.Network.Nameservers,\n\t}\n}\n\n// getRandomMacAddress generates a random local MAC address\n// https://stackoverflow.com/a/21027407/10938317\nfunc getRandomMacAddress() string {\n\tconst (\n\t\tlocal     = 0b10\n\t\tmulticast = 0b1\n\t)\n\n\tbuf := make([]byte, 6)\n\trand.Read(buf) //nolint:errcheck\n\t// clear multicast bit (&^), ensure local bit (|)\n\tbuf[0] = buf[0]&^multicast | local\n\n\treturn net.HardwareAddr(buf).String()\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/node_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// findAPIBindAddrs returns the 0.0.0.0 address to bind to all interfaces on macos with a random port on macos.\n// The bridge interface address is not used as the bridge is not yet created at this stage.\nfunc (p *provisioner) findAPIBindAddrs(_ context.Context, _ provision.ClusterRequest) (*net.TCPAddr, error) {\n\tl, err := net.Listen(\"tcp\", net.JoinHostPort(\"0.0.0.0\", \"0\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l.Addr().(*net.TCPAddr), l.Close()\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/node_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *provisioner) findAPIBindAddrs(ctx context.Context, clusterReq provision.ClusterRequest) (*net.TCPAddr, error) {\n\tl, err := (&net.ListenConfig{}).Listen(ctx, \"tcp\", net.JoinHostPort(clusterReq.Network.GatewayAddrs[0].String(), \"0\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn l.Addr().(*net.TCPAddr), l.Close()\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/pflash.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n//nolint:gocyclo\nfunc (p *provisioner) createPFlashImages(state *provision.State, nodeName string, pflashSpec []PFlash) ([]string, error) {\n\tvar images []string\n\n\tfor i, pflash := range pflashSpec {\n\t\tif err := func(i int, pflash PFlash) error {\n\t\t\tpath := state.GetRelativePath(fmt.Sprintf(\"%s-flash%d.img\", nodeName, i))\n\n\t\t\tf, err := os.Create(path)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tdefer f.Close() //nolint:errcheck\n\n\t\t\tif err = f.Truncate(pflash.Size); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif pflash.SourcePaths != nil {\n\t\t\t\tfor _, sourcePath := range pflash.SourcePaths {\n\t\t\t\t\tvar src *os.File\n\n\t\t\t\t\tsrc, err = os.Open(sourcePath)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tdefer src.Close() //nolint:errcheck\n\n\t\t\t\t\tif _, err = io.Copy(f, src); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timages = append(images, path)\n\n\t\t\treturn nil\n\t\t}(i, pflash); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn images, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/preflight.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *provisioner) preflightChecks(ctx context.Context, request provision.ClusterRequest, options provision.Options, arch Arch) error {\n\tcheckContext := preflightCheckContext{\n\t\trequest: request,\n\t\toptions: options,\n\t\tarch:    arch,\n\t}\n\n\tfor _, check := range []func(ctx context.Context) error{\n\t\tcheckContext.verifyRoot,\n\t\tcheckContext.qemuExecutable,\n\t\tcheckContext.checkFlashImages,\n\t} {\n\t\tif err := check(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn checkContext.verifyPlatformSpecific(ctx)\n}\n\ntype preflightCheckContext struct {\n\trequest provision.ClusterRequest\n\toptions provision.Options\n\tarch    Arch\n}\n\nfunc (check *preflightCheckContext) verifyRoot(context.Context) error {\n\tif os.Geteuid() != 0 {\n\t\treturn errors.New(\"error: please run as root user (CNI, qemu hvf requirement), we recommend running with `sudo -E`\")\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) qemuExecutable(context.Context) error {\n\tif check.arch.QemuExecutable() == \"\" {\n\t\treturn fmt.Errorf(\"QEMU executable (qemu-system-%s or qemu-kvm) not found, please install QEMU with package manager\", check.arch.QemuArch())\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) checkFlashImages(context.Context) error {\n\tfor _, flashImage := range check.arch.PFlash(check.options.UEFIEnabled, check.options.ExtraUEFISearchPaths) {\n\t\tif len(flashImage.SourcePaths) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfound := false\n\n\t\tfor _, path := range flashImage.SourcePaths {\n\t\t\t_, err := os.Stat(path)\n\t\t\tif err == nil {\n\t\t\t\tfound = true\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\treturn fmt.Errorf(\"the required flash image was not found in any of the expected paths for (%q), \"+\n\t\t\t\t\"please install it with the package manager or specify --extra-uefi-search-paths\", flashImage.SourcePaths)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/preflight_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"runtime\"\n)\n\nfunc (check *preflightCheckContext) verifyPlatformSpecific(ctx context.Context) error {\n\treturn check.verifyAppleMachine(ctx)\n}\n\nfunc (check *preflightCheckContext) verifyAppleMachine(context.Context) error {\n\tif runtime.GOARCH != \"arm64\" {\n\t\treturn errors.New(\"currently qemu on darwin is supported only on arm machines\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/preflight_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/coreos/go-iptables/iptables\"\n\t\"github.com/hashicorp/go-getter/v2\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/constants\"\n)\n\nfunc (check *preflightCheckContext) verifyPlatformSpecific(ctx context.Context) error {\n\tfor _, check := range []func(ctx context.Context) error{\n\t\tcheck.cniDirectories,\n\t\tcheck.cniBundle,\n\t\tcheck.checkIptables,\n\t\tcheck.swtpmExecutable,\n\t\tcheck.checkKVM,\n\t} {\n\t\tif err := check(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) cniDirectories(ctx context.Context) error {\n\tcniDirs := append([]string{}, check.request.Network.CNI.BinPath...)\n\tcniDirs = append(cniDirs, check.request.Network.CNI.CacheDir, check.request.Network.CNI.ConfDir)\n\n\tfor _, cniDir := range cniDirs {\n\t\tst, err := os.Stat(cniDir)\n\t\tif err != nil {\n\t\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn fmt.Errorf(\"error checking CNI directory %q: %w\", cniDir, err)\n\t\t\t}\n\n\t\t\tfmt.Fprintf(check.options.LogWriter, \"creating %q\\n\", cniDir)\n\n\t\t\terr = os.MkdirAll(cniDir, 0o777)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif !st.IsDir() {\n\t\t\treturn fmt.Errorf(\"CNI path %q exists, but it's not a directory\", cniDir)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) cniBundle(ctx context.Context) error {\n\tvar missing bool\n\n\trequiredCNIPlugins := []string{\"bridge\", \"firewall\", \"static\", \"tc-redirect-tap\"}\n\n\tfor _, cniPlugin := range requiredCNIPlugins {\n\t\tmissing = true\n\n\t\tfor _, binPath := range check.request.Network.CNI.BinPath {\n\t\t\t_, err := os.Stat(filepath.Join(binPath, cniPlugin))\n\t\t\tif err == nil {\n\t\t\t\tmissing = false\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif missing {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif !missing {\n\t\treturn nil\n\t}\n\n\tif check.request.Network.CNI.BundleURL == \"\" {\n\t\treturn fmt.Errorf(\"error: required CNI plugins %q were not found in %q\", requiredCNIPlugins, check.request.Network.CNI.BinPath)\n\t}\n\n\tpwd, err := os.Getwd()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tclient := getter.Client{}\n\tsrc := strings.ReplaceAll(check.request.Network.CNI.BundleURL, constants.ArchVariable, runtime.GOARCH)\n\tdst := check.request.Network.CNI.BinPath[0]\n\n\tfmt.Fprintf(check.options.LogWriter, \"downloading CNI bundle from %q to %q\\n\", src, dst)\n\n\t_, err = client.Get(ctx, &getter.Request{\n\t\tSrc:     src,\n\t\tDst:     dst,\n\t\tPwd:     pwd,\n\t\tGetMode: getter.ModeDir,\n\t})\n\n\treturn err\n}\n\nfunc (check *preflightCheckContext) checkIptables(ctx context.Context) error {\n\t_, err := iptables.New()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error accessing iptables: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) swtpmExecutable(ctx context.Context) error {\n\tif check.options.TPM1_2Enabled || check.options.TPM2Enabled {\n\t\tif _, err := exec.LookPath(\"swtpm\"); err != nil {\n\t\t\treturn fmt.Errorf(\"swtpm not found in PATH, please install swtpm-tools with the package manager: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (check *preflightCheckContext) checkKVM(ctx context.Context) error {\n\terr := checkKVM()\n\tif err != nil {\n\t\tfmt.Printf(\"error opening /dev/kvm, please make sure KVM support is enabled in Linux kernel: %s\\n\", err)\n\t\tfmt.Println(\"running without KVM\")\n\t}\n\n\treturn nil\n}\n\nfunc checkKVM() error {\n\tf, err := os.OpenFile(\"/dev/kvm\", os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn f.Close()\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/cel\"\n\t\"github.com/siderolabs/talos/pkg/machinery/cel/celenv\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\tconfigconfig \"github.com/siderolabs/talos/pkg/machinery/config/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/configpatcher\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/container\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\tnetworkcfg \"github.com/siderolabs/talos/pkg/machinery/config/types/network\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\ntype provisioner struct {\n\tvm.Provisioner\n}\n\n// NewProvisioner initializes qemu provisioner.\nfunc NewProvisioner(ctx context.Context) (provision.Provisioner, error) {\n\tp := &provisioner{\n\t\tvm.Provisioner{\n\t\t\tName: \"qemu\",\n\t\t},\n\t}\n\n\treturn p, nil\n}\n\n// Close and release resources.\nfunc (p *provisioner) Close() error {\n\treturn nil\n}\n\n// GenOptions provides a list of additional config generate options.\nfunc (p *provisioner) GenOptions(networkReq provision.NetworkRequest, contract *config.VersionContract) ([]generate.Option, []bundle.Option) {\n\thasIPv4 := false\n\thasIPv6 := false\n\n\tfor _, cidr := range networkReq.CIDRs {\n\t\tif cidr.Addr().Is6() {\n\t\t\thasIPv6 = true\n\t\t} else {\n\t\t\thasIPv4 = true\n\t\t}\n\t}\n\n\tgenOpts := []generate.Option{\n\t\tgenerate.WithInstallDisk(\"/dev/vda\"),\n\t}\n\n\tvar bundleOpts []bundle.Option\n\n\tif contract.MultidocNetworkConfigSupported() {\n\t\taliasConfig := networkcfg.NewLinkAliasConfigV1Alpha1(\"net0\")\n\t\taliasConfig.Selector = networkcfg.LinkSelector{\n\t\t\tMatch: cel.MustExpression(cel.ParseBooleanExpression(`link.driver == \"virtio_net\"`, celenv.LinkLocator())),\n\t\t}\n\n\t\tdocuments := []configconfig.Document{aliasConfig}\n\n\t\tif hasIPv4 {\n\t\t\tdhcp4Config := networkcfg.NewDHCPv4ConfigV1Alpha1(\"net0\")\n\t\t\tdocuments = append(documents, dhcp4Config)\n\t\t} else if hasIPv6 {\n\t\t\tdhcp6Config := networkcfg.NewDHCPv6ConfigV1Alpha1(\"net0\")\n\t\t\tdocuments = append(documents, dhcp6Config)\n\t\t}\n\n\t\tctr, err := container.New(documents...)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\tbundleOpts = append(bundleOpts,\n\t\t\tbundle.WithPatch([]configpatcher.Patch{configpatcher.NewStrategicMergePatch(ctr)}),\n\t\t)\n\t} else {\n\t\tvirtioSelector := v1alpha1.IfaceBySelector(v1alpha1.NetworkDeviceSelector{\n\t\t\tNetworkDeviceKernelDriver: \"virtio_net\",\n\t\t})\n\n\t\tgenOpts = append(genOpts,\n\t\t\tgenerate.WithNetworkOptions(\n\t\t\t\tv1alpha1.WithNetworkInterfaceDHCP(virtioSelector, true),\n\t\t\t\tv1alpha1.WithNetworkInterfaceDHCPv4(virtioSelector, hasIPv4),\n\t\t\t\tv1alpha1.WithNetworkInterfaceDHCPv6(virtioSelector, hasIPv6),\n\t\t\t),\n\t\t)\n\t}\n\n\tif !contract.GrubUseUKICmdlineDefault() {\n\t\tgenOpts = append(genOpts,\n\t\t\tgenerate.WithInstallExtraKernelArgs([]string{\n\t\t\t\t\"console=ttyS0\", // TODO: should depend on arch\n\t\t\t\t// reboot configuration\n\t\t\t\t\"reboot=k\",\n\t\t\t\t\"panic=1\",\n\t\t\t\t\"talos.shutdown=halt\",\n\t\t\t\t// Talos-specific\n\t\t\t\t\"talos.platform=metal\",\n\t\t\t}),\n\t\t)\n\t}\n\n\treturn genOpts, bundleOpts\n}\n\n// GetInClusterKubernetesControlPlaneEndpoint returns the Kubernetes control plane endpoint.\nfunc (p *provisioner) GetInClusterKubernetesControlPlaneEndpoint(networkReq provision.NetworkRequest, controlPlanePort int) string {\n\t// QEMU provisioner always runs TCP loadbalancer on the bridge IP and port 6443.\n\treturn \"https://\" + nethelpers.JoinHostPort(networkReq.GatewayAddrs[0].String(), controlPlanePort)\n}\n\n// GetExternalKubernetesControlPlaneEndpoint returns the Kubernetes control plane endpoint.\nfunc (p *provisioner) GetExternalKubernetesControlPlaneEndpoint(networkReq provision.NetworkRequest, controlPlanePort int) string {\n\t// for QEMU, external and in-cluster endpoints are same.\n\treturn p.GetInClusterKubernetesControlPlaneEndpoint(networkReq, controlPlanePort)\n}\n\n// GetTalosAPIEndpoints returns a list of Talos API endpoints.\nfunc (p *provisioner) GetTalosAPIEndpoints(provision.NetworkRequest) []string {\n\t// nil means that the API of controlplane endpoints should be used\n\treturn nil\n}\n\n// GetFirstInterface returns first network interface name.\nfunc (p *provisioner) GetFirstInterface() v1alpha1.IfaceSelector {\n\treturn v1alpha1.IfaceBySelector(v1alpha1.NetworkDeviceSelector{\n\t\tNetworkDeviceKernelDriver: \"virtio_net\",\n\t})\n}\n\n// GetFirstInterfaceName return the first network interface name.\nfunc (p *provisioner) GetFirstInterfaceName() string {\n\treturn \"net0\" // real interface will be aliased to net0\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu/tpm2.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage qemu\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\nfunc (p *provisioner) createVirtualTPMState(state *provision.State, nodeName string, tpm2Enabled bool) (tpmConfig, error) {\n\ttpmStateDir := state.GetRelativePath(fmt.Sprintf(\"%s-tpm\", nodeName))\n\n\tif err := os.MkdirAll(tpmStateDir, 0o755); err != nil {\n\t\treturn tpmConfig{}, err\n\t}\n\n\treturn tpmConfig{\n\t\tNodeName: nodeName,\n\t\tStateDir: tpmStateDir,\n\n\t\tTPM2: tpm2Enabled,\n\t}, nil\n}\n\nfunc (p *provisioner) destroyVirtualTPMs(cluster provision.ClusterInfo) error {\n\terrCh := make(chan error)\n\n\tnodes := append([]provision.NodeInfo{}, cluster.Nodes...)\n\n\tfor _, node := range nodes {\n\t\tif node.TPMStateDir == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\ttpm2PidPath := filepath.Join(node.TPMStateDir, \"swtpm.pid\")\n\n\t\tgo func() {\n\t\t\terrCh <- p.destroyVirtualTPM(tpm2PidPath)\n\t\t}()\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor _, node := range nodes {\n\t\tif node.TPMStateDir == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tmultiErr = multierror.Append(multiErr, <-errCh)\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\nfunc (p *provisioner) destroyVirtualTPM(pid string) error {\n\treturn vm.StopProcessByPidfile(pid)\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux || darwin\n\npackage providers\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/qemu\"\n)\n\nfunc newQemu(ctx context.Context) (provision.Provisioner, error) {\n\treturn qemu.NewProvisioner(ctx)\n}\n"
  },
  {
    "path": "pkg/provision/providers/qemu_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux && !darwin\n\npackage providers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc newQemu(ctx context.Context) (provision.Provisioner, error) {\n\treturn nil, errors.New(\"qemu provisioner is not supported on this platform\")\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/controller.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\n// Controller interface should be implemented by the VM to be controlled via the API.\ntype Controller interface {\n\tPowerOn() error\n\tPowerOff() error\n\tReboot() error\n\tPXEBootOnce() error\n\tStatus() Status\n}\n\n// Status describes current VM status.\ntype Status struct {\n\tPoweredOn bool\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dhcpd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/insomniacslk/dhcp/dhcpv4\"\n\t\"github.com/insomniacslk/dhcp/dhcpv4/server4\"\n\t\"github.com/insomniacslk/dhcp/dhcpv6\"\n\t\"github.com/insomniacslk/dhcp/dhcpv6/server6\"\n\t\"github.com/insomniacslk/dhcp/iana\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm/internal/ethtool\"\n)\n\n//nolint:gocyclo\nfunc handlerDHCP4(serverIP net.IP, statePath string) server4.Handler {\n\treturn func(conn net.PacketConn, peer net.Addr, m *dhcpv4.DHCPv4) {\n\t\tlog.Printf(\"DHCPv4: got %s\", m.Summary())\n\n\t\tif m.OpCode != dhcpv4.OpcodeBootRequest {\n\t\t\treturn\n\t\t}\n\n\t\tdb, err := LoadIPAMRecords(statePath)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed loading the IPAM db: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tif db == nil {\n\t\t\treturn\n\t\t}\n\n\t\trow, ok := db[m.ClientHWAddr.String()]\n\t\tif !ok {\n\t\t\tlog.Printf(\"no match for MAC: %s\", m.ClientHWAddr.String())\n\n\t\t\treturn\n\t\t}\n\n\t\tmatch, ok := row[4]\n\t\tif !ok {\n\t\t\tlog.Printf(\"no match for MAC on IPv4: %s\", m.ClientHWAddr.String())\n\n\t\t\treturn\n\t\t}\n\n\t\tmodifiers := []dhcpv4.Modifier{\n\t\t\tdhcpv4.WithServerIP(serverIP),\n\t\t\tdhcpv4.WithNetmask(net.CIDRMask(int(match.Netmask), match.IP.BitLen())),\n\t\t\tdhcpv4.WithYourIP(match.IP.AsSlice()),\n\t\t\tdhcpv4.WithOption(dhcpv4.OptRouter(match.Gateway.AsSlice())),\n\t\t\tdhcpv4.WithOption(dhcpv4.OptIPAddressLeaseTime(5 * time.Minute)),\n\t\t\tdhcpv4.WithOption(dhcpv4.OptServerIdentifier(serverIP)),\n\t\t}\n\n\t\tif m.IsOptionRequested(dhcpv4.OptionDomainNameServer) {\n\t\t\tmodifiers = append(modifiers, dhcpv4.WithOption(dhcpv4.OptDNS(netipAddrsToIPs(match.Nameservers)...)))\n\t\t}\n\n\t\tif match.Hostname != \"\" && m.IsOptionRequested(dhcpv4.OptionHostName) {\n\t\t\tmodifiers = append(modifiers,\n\t\t\t\tdhcpv4.WithOption(dhcpv4.OptHostName(match.Hostname)),\n\t\t\t)\n\t\t}\n\n\t\tresp, err := dhcpv4.NewReplyFromRequest(m,\n\t\t\tmodifiers...,\n\t\t)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failure building response: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tif m.IsOptionRequested(dhcpv4.OptionBootfileName) {\n\t\t\tlog.Printf(\"received PXE boot request from %s\", m.ClientHWAddr)\n\t\t\tlog.Printf(\"sending PXE response to %s: %s/%s\", m.ClientHWAddr, match.TFTPServer, match.IPXEBootFilename)\n\n\t\t\tif match.TFTPServer != \"\" {\n\t\t\t\tresp.ServerIPAddr = net.ParseIP(match.TFTPServer)\n\t\t\t\tresp.UpdateOption(dhcpv4.OptTFTPServerName(match.TFTPServer))\n\t\t\t}\n\n\t\t\tif match.IPXEBootFilename != \"\" {\n\t\t\t\tresp.UpdateOption(dhcpv4.OptBootFileName(match.IPXEBootFilename))\n\t\t\t}\n\t\t}\n\n\t\tif m.IsOptionRequested(dhcpv4.OptionInterfaceMTU) {\n\t\t\tresp.UpdateOption(dhcpv4.OptGeneric(dhcpv4.OptionInterfaceMTU, dhcpv4.Uint16(match.MTU).ToBytes()))\n\t\t}\n\n\t\tswitch mt := m.MessageType(); mt { //nolint:exhaustive\n\t\tcase dhcpv4.MessageTypeDiscover:\n\t\t\tresp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))\n\t\tcase dhcpv4.MessageTypeRequest, dhcpv4.MessageTypeInform:\n\t\t\tresp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeAck))\n\t\tdefault:\n\t\t\tlog.Printf(\"unhandled message type: %v\", mt)\n\n\t\t\treturn\n\t\t}\n\n\t\t_, err = conn.WriteTo(resp.ToBytes(), peer)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failure sending response: %s\", err)\n\t\t}\n\t}\n}\n\n//nolint:gocyclo\nfunc handlerDHCP6(serverHwAddr net.HardwareAddr, statePath string) server6.Handler {\n\treturn func(conn net.PacketConn, peer net.Addr, m dhcpv6.DHCPv6) {\n\t\tlog.Printf(\"DHCPv6: got %s\", m.Summary())\n\n\t\tdb, err := LoadIPAMRecords(statePath)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed loading the IPAM db: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tif db == nil {\n\t\t\treturn\n\t\t}\n\n\t\tmsg, err := m.GetInnerMessage()\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failed loading inner message: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\thwaddr, err := dhcpv6.ExtractMAC(m)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"error extracting hwaddr: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\trow, ok := db[hwaddr.String()]\n\t\tif !ok {\n\t\t\tlog.Printf(\"no match for MAC: %s\", hwaddr)\n\n\t\t\treturn\n\t\t}\n\n\t\tmatch, ok := row[6]\n\t\tif !ok {\n\t\t\tlog.Printf(\"no match for MAC on IPv6: %s\", hwaddr)\n\n\t\t\treturn\n\t\t}\n\n\t\tmodifiers := []dhcpv6.Modifier{\n\t\t\tdhcpv6.WithDNS(netipAddrsToIPs(match.Nameservers)...),\n\t\t\tdhcpv6.WithIANA(dhcpv6.OptIAAddress{\n\t\t\t\tIPv6Addr:          match.IP.AsSlice(),\n\t\t\t\tPreferredLifetime: 5 * time.Minute,\n\t\t\t\tValidLifetime:     5 * time.Minute,\n\t\t\t}),\n\t\t\tdhcpv6.WithServerID(&dhcpv6.DUIDLLT{\n\t\t\t\tHWType:        iana.HWTypeEthernet,\n\t\t\t\tTime:          dhcpv6.GetTime(),\n\t\t\t\tLinkLayerAddr: serverHwAddr,\n\t\t\t}),\n\t\t}\n\n\t\tif match.Hostname != \"\" {\n\t\t\tmodifiers = append(modifiers,\n\t\t\t\tdhcpv6.WithFQDN(0, match.Hostname),\n\t\t\t)\n\t\t}\n\n\t\tvar resp *dhcpv6.Message\n\n\t\tswitch msg.MessageType { //nolint:exhaustive\n\t\tcase dhcpv6.MessageTypeSolicit:\n\t\t\tresp, err = dhcpv6.NewAdvertiseFromSolicit(msg, modifiers...)\n\t\tcase dhcpv6.MessageTypeRequest:\n\t\t\tresp, err = dhcpv6.NewReplyFromMessage(msg, modifiers...)\n\t\tdefault:\n\t\t\tlog.Printf(\"unsupported message type %s\", msg.Summary())\n\t\t}\n\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failure building response: %s\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\t_, err = conn.WriteTo(resp.ToBytes(), peer)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"failure sending response: %s\", err)\n\t\t}\n\t}\n}\n\nfunc netipAddrsToIPs(addrs []netip.Addr) []net.IP {\n\treturn xslices.Map(addrs, func(addr netip.Addr) net.IP {\n\t\treturn addr.AsSlice()\n\t})\n}\n\n// DHCPd entrypoint.\nfunc DHCPd(ifName string, ips []net.IP, statePath string) error {\n\tiface, err := net.InterfaceByName(ifName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error looking up interface: %w\", err)\n\t}\n\n\tif err := ethtool.TXOff(iface.Name); err != nil {\n\t\treturn fmt.Errorf(\"error disabling TX checksum offload: %w\", err)\n\t}\n\n\tvar eg errgroup.Group\n\n\tfor _, ip := range ips {\n\t\teg.Go(func() error {\n\t\t\tif ip.To4() == nil {\n\t\t\t\tserver, err := server6.NewServer(\n\t\t\t\t\tifName,\n\t\t\t\t\tnil,\n\t\t\t\t\thandlerDHCP6(iface.HardwareAddr, statePath),\n\t\t\t\t\tserver6.WithDebugLogger(),\n\t\t\t\t)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Printf(\"error on dhcp6 startup: %s\", err)\n\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\treturn server.Serve()\n\t\t\t}\n\n\t\t\tserver, err := server4.NewServer(\n\t\t\t\tifName,\n\t\t\t\tnil,\n\t\t\t\thandlerDHCP4(ip, statePath),\n\t\t\t\tserver4.WithSummaryLogger(),\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\tlog.Printf(\"error on dhcp4 startup: %s\", err)\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn server.Serve()\n\t\t})\n\t}\n\n\treturn eg.Wait()\n}\n\nconst (\n\tdhcpPid = \"dhcpd.pid\"\n\tdhcpLog = \"dhcpd.log\"\n)\n\n// startDHCPd starts the DHCPd server.\nfunc (p *Provisioner) startDHCPd(state *provision.State, clusterReq provision.ClusterRequest) error {\n\tpidPath := state.GetRelativePath(dhcpPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(dhcpLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tstatePath, err := state.StatePath()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgatewayAddrs := xslices.Map(clusterReq.Network.GatewayAddrs, netip.Addr.String)\n\n\targs := []string{\n\t\t\"dhcpd-launch\",\n\t\t\"--state-path\", statePath,\n\t\t\"--addr\", strings.Join(gatewayAddrs, \",\"),\n\t\t\"--interface\", state.BridgeName,\n\t\t\"--ipxe-next-handler\", clusterReq.IPXEBootScript,\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing dhcp PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroyDHCPd destoys load balancer.\nfunc (p *Provisioner) DestroyDHCPd(state *provision.State) error {\n\tpidPath := state.GetRelativePath(dhcpPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dhcpd_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// CreateDHCPd creates a DHCP server on darwin.\n// It waits for the interface to appear, shut's down the apple bootp DHCPd server created by qemu by default,\n// starts the talos DHCP server and then starts the apple bootp server again, which is configured such\n// that it detects existing dhcp servers on interfaces and doesn't interfare with them.\nfunc (p *Provisioner) CreateDHCPd(ctx context.Context, state *provision.State, clusterReq provision.ClusterRequest) error {\n\terr := waitForInterface(ctx, state.BridgeName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcmd := exec.CommandContext(ctx, \"/bin/launchctl\", \"unload\", \"-w\", \"/System/Library/LaunchDaemons/bootps.plist\")\n\n\terr = cmd.Run()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to stop native dhcp server: %w\", err)\n\t}\n\n\terr = p.startDHCPd(state, clusterReq)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = waitForDHCPServerUp(ctx, state)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttime.Sleep(time.Second)\n\n\tcmd = exec.CommandContext(ctx, \"/bin/launchctl\", \"load\", \"-w\", \"/System/Library/LaunchDaemons/bootps.plist\")\n\n\terr = cmd.Run()\n\tif err != nil {\n\t\tfmt.Printf(\"warning: failed to start native dhcp server after creating a talos dhcp server: %s\", err)\n\t}\n\n\treturn nil\n}\n\n// waitForInterface returns when interface is found or errors after a minute.\nfunc waitForInterface(ctx context.Context, interfaceName string) error {\n\treturn retry.Constant(1*time.Minute, retry.WithUnits(50*time.Millisecond)).RetryWithContext(ctx, func(_ context.Context) error {\n\t\tifaces, err := net.Interfaces()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, iface := range ifaces {\n\t\t\tif iface.Name == interfaceName {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\treturn retry.ExpectedError(fmt.Errorf(\"interface %s not found\", interfaceName))\n\t})\n}\n\nfunc waitForDHCPServerUp(ctx context.Context, state *provision.State) error {\n\treturn retry.Constant(1*time.Minute, retry.WithUnits(100*time.Millisecond)).RetryWithContext(ctx, func(_ context.Context) error {\n\t\tlogFileData, err := os.ReadFile(state.GetRelativePath(dhcpLog))\n\t\tif err != nil {\n\t\t\treturn retry.ExpectedError(err)\n\t\t}\n\n\t\tif strings.Contains(string(logFileData), \"Ready to handle requests\") {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn retry.ExpectedError(fmt.Errorf(\"failure: DHCPd server has not started\"))\n\t})\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dhcpd_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// CreateDHCPd creates a DHCP server.\nfunc (p *Provisioner) CreateDHCPd(ctx context.Context, state *provision.State, clusterReq provision.ClusterRequest) error {\n\treturn p.startDHCPd(state, clusterReq)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/disk.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/detailyang/go-fallocate\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// UserDiskName returns disk device path.\nfunc (p *Provisioner) UserDiskName(index int) string {\n\t// the disk IDs are assigned in the following way:\n\t// * ata-QEMU_HARDDISK_QM00001\n\t// * ata-QEMU_HARDDISK_QM00003\n\t// * ata-QEMU_HARDDISK_QM00005\n\treturn fmt.Sprintf(\"/dev/disk/by-id/ata-QEMU_HARDDISK_QM%05d\", (index-1)*2+1)\n}\n\n// CreateDisks creates empty disk files for each disk.\n//\n//nolint:gocyclo\nfunc (p *Provisioner) CreateDisks(state *provision.State, nodeReq provision.NodeRequest) (diskPaths []string, err error) {\n\tconst QEMUAlignment = 4 * 1024 * 1024 // 4 MiB, required by QEMU\n\n\tdiskPaths = make([]string, len(nodeReq.Disks))\n\n\tfor i, disk := range nodeReq.Disks {\n\t\tif disk.Driver == \"virtiofs\" {\n\t\t\t// virtiofs does not require disk image files\n\t\t\t// skip creating disk files for such disks, but keep the index consistent\n\t\t\t// and add socket path instead\n\t\t\t//\n\t\t\t// however we need to preallocate a file for shm backing store\n\t\t\tdiskPaths[i] = state.GetRelativePath(fmt.Sprintf(\"%s-%d.virtiofs.sock\", nodeReq.Name, i))\n\n\t\t\t// check if we already have a shm file created\n\t\t\tshmFilePath := state.GetShmPath(fmt.Sprintf(\"shm-%s\", nodeReq.Name))\n\n\t\t\tif _, err = os.Stat(shmFilePath); os.IsNotExist(err) {\n\t\t\t\tvar shmF *os.File\n\n\t\t\t\tshmF, err = os.Create(shmFilePath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to create shm backing file: %w\", err)\n\t\t\t\t}\n\t\t\t\tdefer shmF.Close() //nolint:errcheck\n\n\t\t\t\tshmSize := nodeReq.Memory // already in bytes\n\t\t\t\tif err = shmF.Truncate(shmSize); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to truncate shm backing file: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif err = fallocate.Fallocate(shmF, 0, shmSize); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"failed to preallocate shm backing file: %w\", err)\n\t\t\t\t}\n\t\t\t} else if err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to stat shm backing file: %w\", err)\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tdiskPath := state.GetRelativePath(fmt.Sprintf(\"%s-%d.disk\", nodeReq.Name, i))\n\t\tdiskSize := (disk.Size + QEMUAlignment - 1) / QEMUAlignment * QEMUAlignment\n\n\t\tvar diskF *os.File\n\n\t\tdiskF, err = os.Create(diskPath)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdefer diskF.Close() //nolint:errcheck\n\n\t\tif err = diskF.Truncate(int64(diskSize)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif !disk.SkipPreallocate {\n\t\t\tif err = fallocate.Fallocate(diskF, 0, int64(disk.Size)); err != nil {\n\t\t\t\tfmt.Fprintf(os.Stderr, \"WARNING: failed to preallocate disk space for %q (size %d): %s\", diskPath, diskSize, err)\n\t\t\t}\n\t\t}\n\n\t\tdiskPaths[i] = diskPath\n\t}\n\n\tif len(diskPaths) == 0 {\n\t\treturn nil, errors.New(\"node request must have at least one disk defined to be used as primary disk\")\n\t}\n\n\treturn diskPaths, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dnsd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"log/slog\"\n\t\"net\"\n\t\"os\"\n\n\t\"github.com/miekg/dns\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// DNSd entrypoint.\nfunc DNSd(ips []net.IP, resolvConfPath string) error {\n\tvar eg errgroup.Group\n\n\tconfig, err := dns.ClientConfigFromFile(resolvConfPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read %q: %v\", resolvConfPath, err)\n\t}\n\n\tinitLog := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{\n\t\tAddSource: true,\n\t\tLevel:     slog.LevelDebug,\n\t}))\n\n\tdefer initLog.Info(\"bye\")\n\n\tdnsServe := func(ip net.IP, mode string) error {\n\t\taddr := net.JoinHostPort(ip.String(), \"53\")\n\n\t\tlog := initLog.With(\"mode\", mode, \"addr\", addr)\n\n\t\tserver := &dns.Server{\n\t\t\tAddr:    addr,\n\t\t\tNet:     mode,\n\t\t\tHandler: dns.HandlerFunc(forwardHandler(mode, log, config)),\n\t\t}\n\n\t\tlog.Info(\"starting DNS forwarder server\")\n\n\t\treturn server.ListenAndServe()\n\t}\n\n\tfor _, ip := range ips {\n\t\teg.Go(func() error {\n\t\t\treturn dnsServe(ip, \"udp\")\n\t\t})\n\n\t\teg.Go(func() error {\n\t\t\treturn dnsServe(ip, \"tcp\")\n\t\t})\n\t}\n\n\treturn eg.Wait()\n}\n\nconst (\n\tdnsPid = \"dnsd.pid\"\n\tdnsLog = \"dnsd.log\"\n)\n\n// CreateDNSd creates the DNSd server.\nfunc (p *Provisioner) CreateDNSd(state *State, clusterReq provision.ClusterRequest) error {\n\treturn p.startDNSd(state, clusterReq)\n}\n\n// DestroyDNSd destoys DNSd server.\nfunc (p *Provisioner) DestroyDNSd(state *State) error {\n\treturn p.stopDNSd(state)\n}\n\nfunc forwardHandler(mode string, log *slog.Logger, config *dns.ClientConfig) func(w dns.ResponseWriter, r *dns.Msg) {\n\treturn func(w dns.ResponseWriter, r *dns.Msg) {\n\t\tslog.Debug(\"handling DNS request\", \"request\", r.String())\n\n\t\tc := new(dns.Client)\n\t\tc.Net = mode\n\n\t\tvar (\n\t\t\tresp *dns.Msg\n\t\t\terr  error\n\t\t)\n\n\t\tfor _, serverAddr := range config.Servers {\n\t\t\tlog.Debug(\"making DNS request\", \"target\", serverAddr+\":\"+config.Port)\n\n\t\t\tresp, _, err = c.Exchange(r, net.JoinHostPort(serverAddr, config.Port))\n\t\t\tif err != nil {\n\t\t\t\tlog.Debug(\"DNS request failed\", \"error\", err)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif resp != nil && (resp.Rcode == dns.RcodeServerFailure || resp.Rcode == dns.RcodeRefused) {\n\t\t\t\tlog.Debug(\"DNS request succeeded, but RCODE reports failure\", \"response\", resp.String())\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tif resp == nil {\n\t\t\tlog.Error(\"DNS exchange failed\", \"error\", err)\n\t\t\tdns.HandleFailed(w, r)\n\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debug(\"writing DNS response\", \"response\", resp.String())\n\n\t\tif err := w.WriteMsg(resp); err != nil {\n\t\t\tlog.Error(\"failed to write response\", \"error\", err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dnsd_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *Provisioner) startDNSd(_ *State, _ provision.ClusterRequest) error {\n\treturn nil\n}\n\nfunc (p *Provisioner) stopDNSd(_ *State) error {\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/dnsd_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *Provisioner) startDNSd(state *State, clusterReq provision.ClusterRequest) error {\n\tpidPath := state.GetRelativePath(dnsPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(dnsLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tgatewayAddrs := xslices.Map(clusterReq.Network.GatewayAddrs, netip.Addr.String)\n\n\targs := []string{\n\t\t\"dnsd-launch\",\n\t\t\"--addr\", strings.Join(gatewayAddrs, \",\"),\n\t\t\"--resolv-conf\", \"/etc/resolv.conf\",\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing dns PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Provisioner) stopDNSd(state *State) error {\n\tpidPath := state.GetRelativePath(dnsPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/image_cache.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\timageCachePid = \"image-cache.pid\"\n\timageCacheLog = \"image-cache.log\"\n)\n\n// CreateImageCache creates the Image Cache server.\nfunc (p *Provisioner) CreateImageCache(state *State, clusterReq provision.ClusterRequest) error {\n\tpidPath := state.GetRelativePath(imageCachePid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(imageCacheLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tgatewayAddrs := xslices.Map(clusterReq.Network.GatewayAddrs, netip.Addr.String)\n\tgatewayAddrs = xslices.Map(gatewayAddrs, func(s string) string { return net.JoinHostPort(s, fmt.Sprint(clusterReq.Network.ImageCachePort)) })\n\n\targs := []string{\n\t\t\"image\", \"cache-serve\",\n\t\t\"--address\", gatewayAddrs[0],\n\t\t\"--image-cache-path\", clusterReq.Network.ImageCachePath,\n\t\t\"--tls-cert-file\", clusterReq.Network.ImageCacheTLSCertFile,\n\t\t\"--tls-key-file\", clusterReq.Network.ImageCacheTLSKeyFile,\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing imageCache PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroyImageCache destoys Image Cache server.\nfunc (p *Provisioner) DestroyImageCache(state *State) error {\n\tpidPath := state.GetRelativePath(imageCachePid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/internal/ethtool/ethtool_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage ethtool\n\n// Origin: https://github.com/weaveworks/weave/blob/master/net/ethtool.go\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n)\n\n// Linux constants.\n//\n//nolint:revive\nconst (\n\tSIOCETHTOOL     = 0x8946     // linux/sockios.h\n\tETHTOOL_GTXCSUM = 0x00000016 // linux/ethtool.h\n\tETHTOOL_STXCSUM = 0x00000017 // linux/ethtool.h\n\tIFNAMSIZ        = 16         // linux/if.h\n)\n\n// linux/if.h 'struct ifreq'.\ntype ifReqData struct {\n\tName [IFNAMSIZ]byte\n\tData uintptr\n}\n\n// linux/ethtool.h 'struct ethtool_value'.\ntype ethtoolValue struct {\n\tCmd  uint32\n\tData uint32\n}\n\nfunc ioctlEthtool(fd int, argp uintptr) error {\n\t_, _, errno := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(SIOCETHTOOL), argp)\n\tif errno != 0 {\n\t\treturn errno\n\t}\n\n\treturn nil\n}\n\n// TXOff disables TX checksum offload on specified interface.\nfunc TXOff(name string) error {\n\tif len(name)+1 > IFNAMSIZ {\n\t\treturn fmt.Errorf(\"name too long\")\n\t}\n\n\tsocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer syscall.Close(socket) //nolint:errcheck\n\n\t// Request current value\n\tvalue := ethtoolValue{Cmd: ETHTOOL_GTXCSUM}\n\trequest := ifReqData{Data: uintptr(unsafe.Pointer(&value))}\n\tcopy(request.Name[:], name)\n\n\tif err := ioctlEthtool(socket, uintptr(unsafe.Pointer(&request))); err != nil {\n\t\treturn err\n\t}\n\n\tif value.Data == 0 { // if already off, don't try to change\n\t\treturn nil\n\t}\n\n\tvalue = ethtoolValue{ETHTOOL_STXCSUM, 0}\n\n\treturn ioctlEthtool(socket, uintptr(unsafe.Pointer(&request)))\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/internal/ethtool/ethtool_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\npackage ethtool\n\n// TXOff disables TX checksum offload on specified interface.\n//\n// Not applicable on non-linux systems.\nfunc TXOff(name string) error {\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/internal/ipxe/ipxe.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ipxe provides utility to deliver iPXE images and build iPXE scripts.\npackage ipxe\n\nimport (\n\t\"bytes\"\n\t\"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"path/filepath\"\n\t\"text/template\"\n)\n\n//go:embed \"data/*\"\nvar ipxeFiles embed.FS\n\n// TFTPHandler is called when client starts file download from the TFTP server.\n//\n// TFTP handler also patches the iPXE binary on the fly with the script\n// which chainloads next handler.\nfunc TFTPHandler(next string) func(filename string, rf io.ReaderFrom) error {\n\treturn func(filename string, rf io.ReaderFrom) error {\n\t\tlog.Printf(\"tftp request: %s\", filename)\n\n\t\tfile, err := ipxeFiles.Open(filepath.Join(\"data\", filename))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdefer file.Close() //nolint:errcheck\n\n\t\tcontents, err := io.ReadAll(file)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar script bytes.Buffer\n\n\t\tif err = scriptTemplate.Execute(&script, struct {\n\t\t\tNext string\n\t\t}{\n\t\t\tNext: next,\n\t\t}); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcontents, err = patchScript(contents, script.Bytes())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error patching %q: %w\", filename, err)\n\t\t}\n\n\t\t_, err = rf.ReadFrom(bytes.NewReader(contents))\n\n\t\treturn err\n\t}\n}\n\n// scriptTemplate to run DHCP and chain the boot to the .Next endpoint.\nvar scriptTemplate = template.Must(template.New(\"iPXE embedded\").Parse(`#!ipxe\nprompt --key 0x02 --timeout 2000 Press Ctrl-B for the iPXE command line... && shell ||\n\n{{/* print interfaces */}}\nifstat\n\n{{/* retry 10 times overall */}}\nset attempts:int32 10\nset x:int32 0\n\n:retry_loop\n\n\tset idx:int32 0\n\n\t:loop\n\t\t{{/* try DHCP on each interface */}}\n\t\tisset ${net${idx}/mac} || goto exhausted\n\n\t\tifclose\n\t\tiflinkwait --timeout 5000 net${idx} || goto next_iface\n\t\tdhcp net${idx} || goto next_iface\n\t\tgoto boot\n\n\t:next_iface\n\t\tinc idx && goto loop\n\n\t:boot\n\t\t{{/* attempt boot, if fails try next iface */}}\n\t\troute\n\n\t\tchain --replace {{ .Next }} || goto next_iface\n\n:exhausted\n\techo\n\techo Failed to iPXE boot successfully via all interfaces\n\n\tiseq ${x} ${attempts} && goto fail ||\n\n\techo Retrying...\n\techo\n\n\tinc x\n\tgoto retry_loop\n\n:fail\n\techo\n\techo Failed to get a valid response after ${attempts} attempts\n\techo\n\n\techo Rebooting in 5 seconds...\n\tsleep 5\n\treboot\n`))\n\nvar (\n\tplaceholderStart = []byte(\"# *PLACEHOLDER START*\")\n\tplaceholderEnd   = []byte(\"# *PLACEHOLDER END*\")\n)\n\n// patchScript patches the iPXE script into the iPXE binary.\n//\n// The iPXE binary should be built uncompressed with an embedded\n// script stub which contains abovementioned placeholders.\nfunc patchScript(contents, script []byte) ([]byte, error) {\n\tstart := bytes.Index(contents, placeholderStart)\n\tif start == -1 {\n\t\treturn nil, errors.New(\"placeholder start not found\")\n\t}\n\n\tend := bytes.Index(contents, placeholderEnd)\n\tif end == -1 {\n\t\treturn nil, errors.New(\"placeholder end not found\")\n\t}\n\n\tif end < start {\n\t\treturn nil, errors.New(\"placeholder end before start\")\n\t}\n\n\tend += len(placeholderEnd)\n\n\tlength := end - start\n\n\tif len(script) > length {\n\t\treturn nil, fmt.Errorf(\"script size %d is larger than placeholder space %d\", len(script), length)\n\t}\n\n\tscript = append(script, bytes.Repeat([]byte{'\\n'}, length-len(script))...)\n\n\tcopy(contents[start:end], script)\n\n\treturn contents, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/ipam.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/netip\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// IPAMRecord describes a single record about a node.\ntype IPAMRecord struct {\n\tIP          netip.Addr\n\tNetmask     byte\n\tMAC         string\n\tHostname    string\n\tGateway     netip.Addr\n\tMTU         int\n\tNameservers []netip.Addr\n\n\tTFTPServer       string\n\tIPXEBootFilename string\n}\n\n// IPAMDatabase is a mapping from MAC address to records with IPv4/IPv6 flag.\ntype IPAMDatabase map[string]map[int]IPAMRecord\n\nconst dbFile = \"ipam.db\"\n\n// DumpIPAMRecord appends IPAM record to the database.\nfunc DumpIPAMRecord(statePath string, record IPAMRecord) error {\n\tf, err := os.OpenFile(filepath.Join(statePath, dbFile), os.O_APPEND|os.O_WRONLY|os.O_CREATE, os.ModePerm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\t// need atomic write, buffering json\n\tb, err := json.Marshal(record)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling IPAM record: %w\", err)\n\t}\n\n\t_, err = f.Write(append(b, '\\n'))\n\n\treturn err\n}\n\n// LoadIPAMRecords loads all the IPAM records indexed by the MAC address.\nfunc LoadIPAMRecords(statePath string) (IPAMDatabase, error) {\n\tf, err := os.Open(filepath.Join(statePath, dbFile))\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tdefer f.Close() //nolint:errcheck\n\n\tresult := make(IPAMDatabase)\n\n\tscanner := bufio.NewScanner(f)\n\tfor scanner.Scan() {\n\t\tvar record IPAMRecord\n\n\t\tif err := json.Unmarshal(scanner.Bytes(), &record); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tipFormat := 4\n\t\tif record.IP.Is6() {\n\t\t\tipFormat = 6\n\t\t}\n\n\t\tif result[record.MAC] == nil {\n\t\t\tresult[record.MAC] = make(map[int]IPAMRecord)\n\t\t}\n\n\t\tresult[record.MAC][ipFormat] = record\n\t}\n\n\treturn result, scanner.Err()\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/json-logs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\tjsonLogsPid = \"json-logs.pid\"\n\tjsonLogsLog = \"json-logs.log\"\n)\n\n// CreateJSONLogs creates JSON logs server.\nfunc (p *Provisioner) CreateJSONLogs(state *provision.State, clusterReq provision.ClusterRequest, options provision.Options) error {\n\tpidPath := state.GetRelativePath(jsonLogsPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(jsonLogsLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tkey := make([]byte, 32)\n\tif _, err = io.ReadFull(rand.Reader, key); err != nil {\n\t\treturn err\n\t}\n\n\targs := []string{\n\t\t\"json-logs-launch\",\n\t\t\"--addr\", options.JSONLogsEndpoint,\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing LB PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroyJSONLogs destroys JSON logs server.\nfunc (p *Provisioner) DestroyJSONLogs(state *provision.State) error {\n\tpidPath := state.GetRelativePath(jsonLogsPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/kms.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\tkmsPid = \"kms.pid\"\n\tkmsLog = \"kms.log\"\n)\n\n// CreateKMS creates KMS server.\nfunc (p *Provisioner) CreateKMS(state *provision.State, clusterReq provision.ClusterRequest, options provision.Options) error {\n\tpidPath := state.GetRelativePath(kmsPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(kmsLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tkey := make([]byte, 32)\n\tif _, err = io.ReadFull(rand.Reader, key); err != nil {\n\t\treturn err\n\t}\n\n\targs := []string{\n\t\t\"kms-launch\",\n\t\t\"--kms-addr\", options.KMSEndpoint,\n\t\t\"--kms-key\", base64.StdEncoding.EncodeToString(key),\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing LB PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroyKMS destroys KMS server.\nfunc (p *Provisioner) DestroyKMS(state *provision.State) error {\n\tpidPath := state.GetRelativePath(kmsPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/launch.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/netip\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/nethelpers\"\n\t\"github.com/siderolabs/talos/pkg/provision/internal/inmemhttp\"\n)\n\n// ReadConfig loads configuration from stdin.\nfunc ReadConfig(config any) error {\n\td := json.NewDecoder(os.Stdin)\n\tif err := d.Decode(config); err != nil {\n\t\treturn fmt.Errorf(\"error decoding config from stdin: %w\", err)\n\t}\n\n\tif d.More() {\n\t\treturn errors.New(\"extra unexpected input on stdin\")\n\t}\n\n\treturn os.Stdin.Close()\n}\n\n// ConfigureSignals configures signal handling for the process.\nfunc ConfigureSignals() chan os.Signal {\n\tsignal.Ignore(syscall.SIGHUP)\n\n\tc := make(chan os.Signal, 1)\n\tsignal.Notify(c, syscall.SIGTERM, syscall.SIGINT)\n\n\treturn c\n}\n\nfunc httpPostWrapper(f func() error) http.Handler {\n\treturn http.HandlerFunc(\n\t\tfunc(w http.ResponseWriter, req *http.Request) {\n\t\t\tif req.Body != nil {\n\t\t\t\t_, _ = io.Copy(io.Discard, req.Body) //nolint:errcheck\n\t\t\t\treq.Body.Close()                     //nolint:errcheck\n\t\t\t}\n\n\t\t\tif req.Method != http.MethodPost {\n\t\t\t\tw.WriteHeader(http.StatusNotImplemented)\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\terr := f()\n\t\t\tif err != nil {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\n\t\t\t\tfmt.Fprint(w, err.Error())\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t},\n\t)\n}\n\nfunc httpGetWrapper(f func(w io.Writer)) http.Handler {\n\treturn http.HandlerFunc(\n\t\tfunc(w http.ResponseWriter, req *http.Request) {\n\t\t\tif req.Body != nil {\n\t\t\t\t_, _ = io.Copy(io.Discard, req.Body) //nolint:errcheck\n\t\t\t\treq.Body.Close()                     //nolint:errcheck\n\t\t\t}\n\n\t\t\tswitch req.Method {\n\t\t\tcase http.MethodHead:\n\t\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tcase http.MethodGet:\n\t\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\t\tw.WriteHeader(http.StatusOK)\n\n\t\t\t\tf(w)\n\t\t\tdefault:\n\t\t\t\tw.WriteHeader(http.StatusNotImplemented)\n\t\t\t}\n\t\t},\n\t)\n}\n\n// NewHTTPServer creates new inmemhttp.Server and mounts config file into it.\nfunc NewHTTPServer(ctx context.Context, gatewayAddr netip.Addr, port int, config []byte, controller Controller) (inmemhttp.Server, error) {\n\thttpServer, err := inmemhttp.NewServer(ctx, nethelpers.JoinHostPort(gatewayAddr.String(), port))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error launching in-memory HTTP server: %w\", err)\n\t}\n\n\tif err = httpServer.AddFile(\"config.yaml\", config); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif controller != nil {\n\t\tfor _, method := range []struct {\n\t\t\tpattern string\n\t\t\tf       func() error\n\t\t}{\n\t\t\t{\n\t\t\t\tpattern: \"/poweron\",\n\t\t\t\tf:       controller.PowerOn,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpattern: \"/poweroff\",\n\t\t\t\tf:       controller.PowerOff,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpattern: \"/reboot\",\n\t\t\t\tf:       controller.Reboot,\n\t\t\t},\n\t\t\t{\n\t\t\t\tpattern: \"/pxeboot\",\n\t\t\t\tf:       controller.PXEBootOnce,\n\t\t\t},\n\t\t} {\n\t\t\thttpServer.AddHandler(method.pattern, httpPostWrapper(method.f))\n\t\t}\n\n\t\thttpServer.AddHandler(\n\t\t\t\"/status\", httpGetWrapper(\n\t\t\t\tfunc(w io.Writer) {\n\t\t\t\t\tjson.NewEncoder(w).Encode(controller.Status()) //nolint:errcheck\n\t\t\t\t},\n\t\t\t),\n\t\t)\n\t}\n\n\treturn httpServer, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/loadbalancer.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\tlbPid = \"lb.pid\"\n\tlbLog = \"lb.log\"\n)\n\n// CreateLoadBalancer creates load balancer.\nfunc (p *Provisioner) CreateLoadBalancer(state *provision.State, clusterReq provision.ClusterRequest) error {\n\tpidPath := state.GetRelativePath(lbPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(lbLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tcontrolPlaneIPs := xslices.Map(clusterReq.Nodes.ControlPlaneNodes(), func(req provision.NodeRequest) string { return req.IPs[0].String() })\n\tports := xslices.Map(clusterReq.Network.LoadBalancerPorts, strconv.Itoa)\n\n\targs := []string{\n\t\t\"loadbalancer-launch\",\n\t\t\"--loadbalancer-addr\", getLbBindIP(clusterReq.Network.GatewayAddrs[0]),\n\t\t\"--loadbalancer-upstreams\", strings.Join(controlPlaneIPs, \",\"),\n\t}\n\n\tif len(ports) > 0 {\n\t\targs = append(args, \"--loadbalancer-ports\", strings.Join(ports, \",\"))\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing LB PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroyLoadBalancer destroys load balancer.\nfunc (p *Provisioner) DestroyLoadBalancer(state *provision.State) error {\n\tpidPath := state.GetRelativePath(lbPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/loadbalancer_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport \"net/netip\"\n\n// getLbBindIP returns the 0.0.0.0 address to bind to all interfaces on macos.\n// The bridge interface address is not used as the bridge is not yet created at this stage.\n// Multiple loadbalancers can be assigned via different ports.\nfunc getLbBindIP(_ netip.Addr) string {\n\treturn \"0.0.0.0\"\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/loadbalancer_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport \"net/netip\"\n\n// getLbBindIP returns the gateway address to bind the loadbalancer to the bridge interface.\nfunc getLbBindIP(gateway netip.Addr) string {\n\treturn gateway.String()\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/network.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n)\n\n// GetVmnetInterfaceName returns the name of the interface that will be assigned to the next vmnet interface.\n// The name is assigned incrementing by one, starting from \"bridge100\".\nfunc GetVmnetInterfaceName(allCurrentInterfaces []string) (string, error) {\n\tfor i := 100; i < 200; i++ {\n\t\tinterfaceName := fmt.Sprintf(\"bridge%d\", i)\n\t\tif slices.Index(allCurrentInterfaces, interfaceName) == -1 {\n\t\t\treturn interfaceName, nil\n\t\t}\n\t}\n\n\treturn \"\", errors.New(\"all interface names seem to be already in use\")\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/network_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// CreateNetwork on darwin assigns the bridge name to the to-be created interface name.\n// The interface itself is later created by qemu, but the name needs to be known so that the dhcp server can be linked to the interface.\nfunc (p *Provisioner) CreateNetwork(ctx context.Context, state *provision.State, network provision.NetworkRequest, options provision.Options) error {\n\tifaces, err := net.Interfaces()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tifNames := xslices.Map(ifaces, func(iface net.Interface) string { return iface.Name })\n\n\tbridgeNAme, err := GetVmnetInterfaceName(ifNames)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate.BridgeName = bridgeNAme\n\n\treturn nil\n}\n\n// DestroyNetwork does nothing on darwin as the network is automatically cleaned up by qemu when the final machine of a cidr block is killed.\nfunc (p *Provisioner) DestroyNetwork(state *provision.State) error {\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/network_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/netip\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/containernetworking/cni/libcni\"\n\t\"github.com/containernetworking/plugins/pkg/testutils\"\n\t\"github.com/coreos/go-iptables/iptables\"\n\t\"github.com/florianl/go-tc\"\n\t\"github.com/florianl/go-tc/core\"\n\t\"github.com/google/uuid\"\n\t\"github.com/jsimonetti/rtnetlink/v2\"\n\t\"github.com/siderolabs/gen/xslices\"\n\tsideronet \"github.com/siderolabs/net\"\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// CreateNetwork builds bridge interface name by taking part of checksum of the network name\n// so that interface name is defined by network name, and different networks have\n// different bridge interfaces.\n//\n//nolint:gocyclo\nfunc (p *Provisioner) CreateNetwork(ctx context.Context, state *provision.State, network provision.NetworkRequest, options provision.Options) error {\n\tnetworkNameHash := sha256.Sum256([]byte(network.Name))\n\tstate.BridgeName = fmt.Sprintf(\"%s%s\", \"talos\", hex.EncodeToString(networkNameHash[:])[:8])\n\n\t// bring up the bridge interface for the first time to get gateway IP assigned\n\tt := template.Must(template.New(\"bridge\").Parse(bridgeTemplate))\n\n\tvar buf bytes.Buffer\n\n\terr := t.Execute(&buf, struct {\n\t\tNetworkName   string\n\t\tInterfaceName string\n\t\tMTU           string\n\t\tIPMasquerade  bool\n\t}{\n\t\tNetworkName:   network.Name,\n\t\tInterfaceName: state.BridgeName,\n\t\tMTU:           strconv.Itoa(network.MTU),\n\t\tIPMasquerade:  !network.Airgapped,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error templating bridge CNI config: %w\", err)\n\t}\n\n\tbridgeConfig, err := libcni.NetworkPluginConfFromBytes(buf.Bytes())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing bridge CNI config: %w\", err)\n\t}\n\n\tcniConfig := libcni.NewCNIConfigWithCacheDir(network.CNI.BinPath, network.CNI.CacheDir, nil)\n\n\tns, err := testutils.NewNS()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tns.Close()              //nolint:errcheck\n\t\ttestutils.UnmountNS(ns) //nolint:errcheck\n\t}()\n\n\t// pick a fake address to use for provisioning an interface\n\tfakeIPs := make([]string, len(network.CIDRs))\n\tfor j := range fakeIPs {\n\t\tvar fakeIP netip.Addr\n\n\t\tfakeIP, err = sideronet.NthIPInNetwork(network.CIDRs[j], 2)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfakeIPs[j] = sideronet.FormatCIDR(fakeIP, network.CIDRs[j])\n\t}\n\n\tgatewayAddrs := xslices.Map(network.GatewayAddrs, netip.Addr.String)\n\n\tcontainerID := uuid.New().String()\n\truntimeConf := libcni.RuntimeConf{\n\t\tContainerID: containerID,\n\t\tNetNS:       ns.Path(),\n\t\tIfName:      \"veth0\",\n\t\tArgs: [][2]string{\n\t\t\t{\"IP\", strings.Join(fakeIPs, \",\")},\n\t\t\t{\"GATEWAY\", strings.Join(gatewayAddrs, \",\")},\n\t\t\t{\"IgnoreUnknown\", \"1\"},\n\t\t},\n\t}\n\n\t_, err = cniConfig.AddNetwork(ctx, bridgeConfig, &runtimeConf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error provisioning bridge CNI network: %w\", err)\n\t}\n\n\terr = cniConfig.DelNetwork(ctx, bridgeConfig, &runtimeConf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error deleting bridge CNI network: %w\", err)\n\t}\n\n\t// prepare an actual network config to be used by the VMs\n\tt = template.Must(template.New(\"network\").Parse(networkTemplate))\n\n\tbuf.Reset()\n\n\terr = t.Execute(&buf, struct {\n\t\tNetworkName   string\n\t\tInterfaceName string\n\t\tMTU           string\n\t\tIPMasquerade  bool\n\t}{\n\t\tNetworkName:   network.Name,\n\t\tInterfaceName: state.BridgeName,\n\t\tMTU:           strconv.Itoa(network.MTU),\n\t\tIPMasquerade:  !network.Airgapped,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error templating VM CNI config: %w\", err)\n\t}\n\n\tif state.VMCNIConfig, err = libcni.ConfListFromBytes(buf.Bytes()); err != nil {\n\t\treturn fmt.Errorf(\"error parsing VM CNI config: %w\", err)\n\t}\n\n\t// allow traffic on the bridge via `DOCKER-USER` chain\n\t// Docker enables br-netfilter which causes layer2 packets to be filtered with iptables, but we'd like to skip that\n\t// if Docker is not running, this will be no-op\n\t//\n\t// See https://serverfault.com/questions/963759/docker-breaks-libvirt-bridge-network for more details\n\tif err = p.allowBridgeTraffic(state.BridgeName); err != nil {\n\t\treturn fmt.Errorf(\"error configuring DOCKER-USER chain: %w\", err)\n\t}\n\n\t// configure bridge interface with network chaos if flag is set\n\tif network.NetworkChaos {\n\t\tif err = p.configureNetworkChaos(network, state, options); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Provisioner) allowBridgeTraffic(bridgeName string) error {\n\tipt, err := iptables.New()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing iptables: %w\", err)\n\t}\n\n\tchainExists, err := ipt.ChainExists(\"filter\", \"DOCKER-USER\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error checking chain existence: %w\", err)\n\t}\n\n\tif !chainExists {\n\t\tif err = ipt.NewChain(\"filter\", \"DOCKER-USER\"); err != nil {\n\t\t\treturn fmt.Errorf(\"error creating DOCKER-USER chain: %w\", err)\n\t\t}\n\t}\n\n\tif err := ipt.InsertUnique(\"filter\", \"DOCKER-USER\", 1, \"-i\", bridgeName, \"-o\", bridgeName, \"-j\", \"ACCEPT\"); err != nil {\n\t\treturn fmt.Errorf(\"error inserting rule into DOCKER-USER chain: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Provisioner) dropBridgeTrafficRule(bridgeName string) error {\n\tipt, err := iptables.New()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing iptables: %w\", err)\n\t}\n\n\tchainExists, err := ipt.ChainExists(\"filter\", \"DOCKER-USER\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error checking chain existence: %w\", err)\n\t}\n\n\tif !chainExists {\n\t\treturn nil\n\t}\n\n\tif err := ipt.DeleteIfExists(\"filter\", \"DOCKER-USER\", \"-i\", bridgeName, \"-o\", bridgeName, \"-j\", \"ACCEPT\"); err != nil {\n\t\treturn fmt.Errorf(\"error deleting rule in DOCKER-USER chain: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc getTicksInUsec() (float64, error) {\n\tdata, err := os.ReadFile(\"/proc/net/psched\")\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tparts := strings.Split(strings.TrimSpace(string(data)), \" \")\n\tif len(parts) < 3 {\n\t\treturn 0, errors.New(\"unexpected format\")\n\t}\n\n\tvar vals [3]uint64\n\n\tfor i := range vals {\n\t\tvals[i], err = strconv.ParseUint(parts[i], 16, 32)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\t// compatibility\n\tif vals[2] == 1000000000 {\n\t\tvals[0] = vals[1]\n\t}\n\n\tclockFactor := float64(vals[2]) / 1000000\n\n\treturn float64(vals[0]) / float64(vals[1]) * clockFactor, nil\n}\n\n//nolint:gocyclo\nfunc (p *Provisioner) configureNetworkChaos(network provision.NetworkRequest, state *provision.State, options provision.Options) error {\n\tif (network.Bandwidth != 0) && (network.Latency != 0 || network.Jitter != 0 || network.PacketLoss != 0 || network.PacketReorder != 0 || network.PacketCorrupt != 0) {\n\t\treturn errors.New(\"bandwidth and other chaos options cannot be used together\")\n\t}\n\n\ttcnl, err := tc.Open(&tc.Config{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not open tc: %v\", err)\n\t}\n\n\tdefer tcnl.Close() //nolint:errcheck\n\n\tlink, err := net.InterfaceByName(state.BridgeName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not get link: %v\", err)\n\t}\n\n\tfmt.Fprintln(options.LogWriter, \"network chaos enabled on interface:\", state.BridgeName)\n\n\tif network.Bandwidth != 0 {\n\t\tfmt.Fprintf(options.LogWriter, \"  bandwidth: %4d kbps\\n\", network.Bandwidth)\n\n\t\tticksInUsec, err := getTicksInUsec()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not get ticks in usec: %w\", err)\n\t\t}\n\n\t\trate := network.Bandwidth * 1000 / 8 // rate in kbps\n\t\tlatency := 0.2                       // 200ms\n\t\tburst := 50 * 1000                   // 50kb\n\n\t\tlimit := uint32(float64(rate)*latency + float64(burst))\n\t\tbuffer := uint32(1000000.0 * float64(burst) / float64(rate) * ticksInUsec)\n\n\t\tqdisc := tc.Object{\n\t\t\tMsg: tc.Msg{\n\t\t\t\tFamily:  unix.AF_UNSPEC,\n\t\t\t\tIfindex: uint32(link.Index),\n\t\t\t\tHandle:  core.BuildHandle(tc.HandleRoot, 0x0),\n\t\t\t\tParent:  tc.HandleRoot,\n\t\t\t\tInfo:    0,\n\t\t\t},\n\t\t\tAttribute: tc.Attribute{\n\t\t\t\tKind: \"tbf\",\n\t\t\t\tTbf: &tc.Tbf{\n\t\t\t\t\tParms: &tc.TbfQopt{\n\t\t\t\t\t\tLimit: limit,\n\t\t\t\t\t\tRate: tc.RateSpec{\n\t\t\t\t\t\t\tRate:      uint32(rate),\n\t\t\t\t\t\t\tLinklayer: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tBuffer: buffer,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tif err := tcnl.Qdisc().Add(&qdisc); err != nil {\n\t\t\treturn fmt.Errorf(\"could not add netem qdisc: %v\", err)\n\t\t}\n\t} else {\n\t\tpacketLoss := network.PacketLoss * 100\n\t\tpacketReorder := network.PacketReorder * 100\n\t\tpacketCorrupt := network.PacketCorrupt * 100\n\n\t\tfmt.Fprintf(options.LogWriter, \"  jitter:            %4dms\\n\", network.Jitter.Milliseconds())\n\t\tfmt.Fprintf(options.LogWriter, \"  latency:           %4dms\\n\", network.Latency.Milliseconds())\n\t\tfmt.Fprintf(options.LogWriter, \"  packet loss:       %4v%%\\n\", packetLoss)\n\t\tfmt.Fprintf(options.LogWriter, \"  packet reordering: %4v%%\\n\", packetReorder)\n\t\tfmt.Fprintf(options.LogWriter, \"  packet corruption: %4v%%\\n\", packetCorrupt)\n\n\t\tqdisc := tc.Object{\n\t\t\tMsg: tc.Msg{\n\t\t\t\tFamily:  unix.AF_UNSPEC,\n\t\t\t\tIfindex: uint32(link.Index),\n\t\t\t\tHandle:  core.BuildHandle(tc.HandleRoot, 0x0),\n\t\t\t\tParent:  tc.HandleRoot,\n\t\t\t\tInfo:    0,\n\t\t\t},\n\t\t\tAttribute: tc.Attribute{\n\t\t\t\tKind: \"netem\",\n\t\t\t\tNetem: &tc.Netem{\n\t\t\t\t\tJitter64:  new(int64(network.Jitter)),\n\t\t\t\t\tLatency64: new(int64(network.Latency)),\n\t\t\t\t\tQopt: tc.NetemQopt{\n\t\t\t\t\t\tLimit: 1000,\n\t\t\t\t\t\tLoss:  uint32(packetLoss / 100 * math.MaxUint32),\n\t\t\t\t\t},\n\t\t\t\t\tCorrupt: &tc.NetemCorrupt{\n\t\t\t\t\t\tProbability: uint32(packetCorrupt / 100 * math.MaxUint32),\n\t\t\t\t\t},\n\t\t\t\t\tReorder: &tc.NetemReorder{\n\t\t\t\t\t\tProbability: uint32(packetReorder / 100 * math.MaxUint32),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tif err := tcnl.Qdisc().Add(&qdisc); err != nil {\n\t\t\treturn fmt.Errorf(\"could not add netem qdisc: %v\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// DestroyNetwork destroy bridge interface by name to clean up.\nfunc (p *Provisioner) DestroyNetwork(state *provision.State) error {\n\tiface, err := net.InterfaceByName(state.BridgeName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error looking up bridge interface %q: %w\", state.BridgeName, err)\n\t}\n\n\trtconn, err := rtnetlink.Dial(nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error dialing rnetlink: %w\", err)\n\t}\n\n\tif err = rtconn.Link.Delete(uint32(iface.Index)); err != nil {\n\t\treturn fmt.Errorf(\"error deleting bridge interface: %w\", err)\n\t}\n\n\tif err = p.dropBridgeTrafficRule(state.BridgeName); err != nil {\n\t\treturn fmt.Errorf(\"error dropping bridge traffic rule: %w\", err)\n\t}\n\n\treturn nil\n}\n\nconst bridgeTemplate = `\n{\n\t\"name\": \"{{ .NetworkName }}\",\n\t\"cniVersion\": \"0.4.0\",\n\t\"type\": \"bridge\",\n\t\"bridge\": \"{{ .InterfaceName }}\",\n\t\"ipMasq\": {{ .IPMasquerade }},\n\t\"isGateway\": true,\n\t\"isDefaultGateway\": true,\n\t\"ipam\": {\n\t\t  \"type\": \"static\"\n\t},\n\t\"mtu\": {{ .MTU }}\n}\n`\n\nconst networkTemplate = `\n{\n\t\"name\": \"{{ .NetworkName }}\",\n\t\"cniVersion\": \"0.4.0\",\n\t\"plugins\": [\n\t\t{\n\t\t\t\"type\": \"bridge\",\n\t\t\t\"bridge\": \"{{ .InterfaceName }}\",\n\t\t\t\"ipMasq\": {{ .IPMasquerade }},\n\t\t\t\"isGateway\": true,\n\t\t\t\"isDefaultGateway\": true,\n\t\t\t\"ipam\": {\n\t\t\t\t\"type\": \"static\"\n\t\t\t},\n\t\t\t\"mtu\": {{ .MTU }}\n\t\t},\n\t\t{\n\t\t\t\"type\": \"firewall\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"tc-redirect-tap\"\n\t\t}\n\t]\n}\n`\n"
  },
  {
    "path": "pkg/provision/providers/vm/network_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm\"\n)\n\nfunc TestGetVmnetInterfaceNameNoVmnetInterface(t *testing.T) {\n\tinterfaces := []string{\n\t\t\"bridge\", \"bridge1\", \"eth0\", \"utun1\", \"bridge001\", \"bridge1001\",\n\t}\n\tresult, err := vm.GetVmnetInterfaceName(interfaces)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"bridge100\", result)\n}\n\nfunc TestGetVmnetInterfaceNameWithExistingVmnetInterfaces(t *testing.T) {\n\tinterfaces := []string{\n\t\t\"bridge\", \"bridge1\", \"eth0\", \"utun1\", \"bridge001\", \"bridge1001\", \"bridge100\", \"bridge101\", \"bridge104\",\n\t}\n\tresult, err := vm.GetVmnetInterfaceName(interfaces)\n\tassert.NoError(t, err)\n\n\tassert.Equal(t, \"bridge102\", result)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/node.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\tmultierror \"github.com/hashicorp/go-multierror\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// DestroyNodes destroys all VMs.\nfunc (p *Provisioner) DestroyNodes(cluster provision.ClusterInfo, options *provision.Options) error {\n\terrCh := make(chan error)\n\n\tnodes := slices.Concat(cluster.Nodes, cluster.ExtraNodes)\n\n\tfor _, node := range nodes {\n\t\tgo func(node provision.NodeInfo) {\n\t\t\tfmt.Fprintln(options.LogWriter, \"stopping VM\", node.Name)\n\n\t\t\terrCh <- p.DestroyNode(node)\n\t\t}(node)\n\t}\n\n\tvar multiErr *multierror.Error\n\n\tfor range nodes {\n\t\tmultiErr = multierror.Append(multiErr, <-errCh)\n\t}\n\n\treturn multiErr.ErrorOrNil()\n}\n\n// DestroyNode destroys VM.\nfunc (p *Provisioner) DestroyNode(node provision.NodeInfo) error {\n\treturn StopProcessByPidfile(node.ID) // node.ID stores PID path for control process\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/process.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/siderolabs/go-retry/retry\"\n)\n\n// StopProcessByPidfile stops a process by reading its PID from a file.\nfunc StopProcessByPidfile(pidPath string) error {\n\tpidFile, err := os.Open(pidPath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error checking PID file %q: %w\", pidPath, err)\n\t}\n\n\tdefer pidFile.Close() //nolint:errcheck\n\n\tvar pid int\n\n\tif _, err = fmt.Fscanf(pidFile, \"%d\", &pid); err != nil {\n\t\treturn fmt.Errorf(\"error reading PID for %q: %w\", pidPath, err)\n\t}\n\n\tproc, err := os.FindProcess(pid)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error finding process %d for %q: %w\", pid, pidPath, err)\n\t}\n\n\tif err = proc.Signal(syscall.SIGTERM); err != nil {\n\t\tif err.Error() == \"os: process already finished\" {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"error sending SIGTERM to %d (path %q): %w\", pid, pidPath, err)\n\t}\n\n\t// wait for the process to exit, this is using (unreliable and slow) polling\n\treturn retry.Constant(30*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error {\n\t\t// wait for the process if it's our child, we should clean up zombies, but if it's not our child, it would return ECHILD\n\t\tproc.Wait() //nolint:errcheck\n\n\t\tsignalErr := proc.Signal(syscall.Signal(0))\n\t\tif signalErr == nil {\n\t\t\treturn retry.ExpectedErrorf(\"process %d still running\", pid)\n\t\t}\n\n\t\treturn nil\n\t})\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/reflect.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\n// Reflect decode state file.\nfunc (p *Provisioner) Reflect(ctx context.Context, clusterName, stateDirectory string) (provision.Cluster, error) {\n\tstate, err := provision.ReadState(ctx, clusterName, stateDirectory)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif state.ProvisionerName != p.Name {\n\t\treturn nil, fmt.Errorf(\"cluster %q was created with different provisioner %q\", clusterName, state.ProvisionerName)\n\t}\n\n\treturn state, nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/siderolink-agent.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\tsiderolinkAgentPid = \"siderolink-agent.pid\"\n\tsiderolinkAgentLog = \"siderolink-agent.log\"\n\tsiderolinkCert     = \"siderolink-agent-cert.pem\"\n\tsiderolinkKey      = \"siderolink-agent-key.pem\"\n)\n\n// CreateSiderolinkAgent creates siderlink agent.\nfunc (p *Provisioner) CreateSiderolinkAgent(state *provision.State, clusterReq provision.ClusterRequest) error {\n\tpidPath := state.GetRelativePath(siderolinkAgentPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(siderolinkAgentLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\targs := []string{\n\t\t\"siderolink-launch\",\n\t\t\"--sidero-link-join-token\", \"foo\",\n\t\t\"--sidero-link-wireguard-endpoint\", clusterReq.SiderolinkRequest.WireguardEndpoint,\n\t\t\"--event-sink-endpoint\", clusterReq.SiderolinkRequest.SinkEndpoint,\n\t\t\"--sidero-link-api-endpoint\", clusterReq.SiderolinkRequest.APIEndpoint,\n\t\t\"--log-receiver-endpoint\", clusterReq.SiderolinkRequest.LogEndpoint,\n\t}\n\n\tif clusterReq.SiderolinkRequest.APICertificate != nil && clusterReq.SiderolinkRequest.APIKey != nil {\n\t\tapiCertPath := state.GetRelativePath(siderolinkCert)\n\t\tapiKeyPath := state.GetRelativePath(siderolinkKey)\n\n\t\tif err = os.WriteFile(apiCertPath, clusterReq.SiderolinkRequest.APICertificate, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing SideroLink API certificate: %w\", err)\n\t\t}\n\n\t\tif err = os.WriteFile(apiKeyPath, clusterReq.SiderolinkRequest.APIKey, 0o600); err != nil {\n\t\t\treturn fmt.Errorf(\"error writing SideroLink API key: %w\", err)\n\t\t}\n\n\t\targs = append(args, \"--sidero-link-api-cert\", apiCertPath, \"--sidero-link-api-key\", apiKeyPath)\n\t}\n\n\tfor _, bind := range clusterReq.SiderolinkRequest.SiderolinkBind {\n\t\targs = append(args, \"--predefined-pair\", bind.UUID.String()+\"=\"+bind.Addr.String())\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing SA PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// DestroySiderolinkAgent destroys siderolink agent.\nfunc (p *Provisioner) DestroySiderolinkAgent(state *provision.State) error {\n\tpidPath := state.GetRelativePath(siderolinkAgentPid)\n\n\tif _, err := os.Stat(pidPath); errors.Is(err, os.ErrNotExist) {\n\t\t// If the pid file does not exist, the process was not started.\n\t\treturn nil\n\t}\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//nolint:revive\npackage vm\n\nimport \"github.com/siderolabs/talos/pkg/provision\"\n\n// Deprecated: Use provision.State instead.\ntype State = provision.State\n\n// Deprecated: Use provision.NewState instead.\nvar NewState = provision.NewState\n"
  },
  {
    "path": "pkg/provision/providers/vm/tftpd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/pin/tftp/v3\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"github.com/siderolabs/talos/pkg/provision/providers/vm/internal/ipxe\"\n)\n\n// TFTPd starts a TFTP server on the given IPs.\nfunc TFTPd(ips []net.IP, nextHandler string) error {\n\tserver := tftp.NewServer(ipxe.TFTPHandler(nextHandler), nil)\n\n\tserver.SetTimeout(5 * time.Second)\n\n\tvar eg errgroup.Group\n\n\tfor _, ip := range ips {\n\t\teg.Go(func() error {\n\t\t\treturn server.ListenAndServe(net.JoinHostPort(ip.String(), \"69\"))\n\t\t})\n\t}\n\n\treturn eg.Wait()\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/virtiofsd.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nconst (\n\tvirtiofsdPid = \"virtiofsd.pid\"\n\tvirtiofsdLog = \"virtiofsd.log\"\n)\n\n// FindVirtiofsd tries to find the virtiofsd binary in common locations.\nfunc (p *Provisioner) FindVirtiofsd() (string, error) {\n\treturn p.findVirtiofsd()\n}\n\n// Virtiofsd starts virtiofsd and restarts it if it exits.\n// The restart is needed, because the virtiofsd exits when client disconnects.\nfunc Virtiofsd(ctx context.Context, virtiofsdBin, share, socket string) error {\n\tif virtiofsdBin == \"\" {\n\t\treturn errors.New(\"virtiofsd binary path is empty\")\n\t}\n\n\tif err := os.MkdirAll(share, 0o755); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"failed to create shared dir %s: %v\\n\", share, err)\n\t}\n\n\targs := []string{\n\t\t\"--shared-dir\", share,\n\t\t\"--socket-path\", socket,\n\t\t\"--announce-submounts\",\n\t\t\"--inode-file-handles=mandatory\",\n\t}\n\n\tfmt.Printf(\"Starting virtiofsd with restart loop: %s %s\\n\",\n\t\tvirtiofsdBin, strings.Join(args, \" \"))\n\n\tfor {\n\t\terr := runVirtiofsd(ctx, share, virtiofsdBin, args)\n\t\tswitch {\n\t\tcase err == nil:\n\t\t\tfmt.Printf(\"virtiofsd exited - restarting...\\n\")\n\n\t\tcase errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):\n\t\t\treturn nil\n\n\t\tdefault:\n\t\t\tfmt.Printf(\"virtiofsd exited: %v - restarting...\\n\", err)\n\t\t}\n\t}\n}\n\nfunc runVirtiofsd(ctx context.Context, share, virtiofsdBin string, args []string) error {\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\tcmd := exec.CommandContext(ctx, virtiofsdBin, args...)\n\n\tstdoutPipe, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer stdoutPipe.Close() //nolint:errcheck\n\n\tstderrPipe, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer stderrPipe.Close() //nolint:errcheck\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Printf(\"virtiofsd started with PID %d\\n\", cmd.Process.Pid)\n\n\tgo printPipe(share, os.Stdout, stdoutPipe)\n\tgo printPipe(share, os.Stderr, stderrPipe)\n\n\terr = cmd.Wait()\n\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\treturn err\n}\n\nfunc printPipe(prefix string, wr io.Writer, r io.Reader) {\n\tif len(prefix) > 32 {\n\t\t// print only last 32 characters\n\t\tprefix = prefix[len(prefix)-32:]\n\t}\n\n\tscanner := bufio.NewScanner(r)\n\n\tfor scanner.Scan() {\n\t\tfmt.Fprintf(wr, \"[%s] %s\\n\", prefix, scanner.Text())\n\t}\n\n\tif err := scanner.Err(); err != nil {\n\t\tfmt.Fprintf(wr, \"error reading from pipe: %v\\n\", err)\n\t}\n}\n\n// CreateVirtiofsd creates the Virtiofsd server.\nfunc (p *Provisioner) CreateVirtiofsd(state *State, clusterReq provision.ClusterRequest, virtiofdPath string) error {\n\treturn p.startVirtiofsd(state, clusterReq, virtiofdPath)\n}\n\n// DestroyVirtiofsd destoys Virtiofsd server.\nfunc (p *Provisioner) DestroyVirtiofsd(state *State) error {\n\treturn p.stopVirtiofsd(state)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/virtiofsd_darwin.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *Provisioner) findVirtiofsd() (string, error) {\n\treturn \"\", nil\n}\n\nfunc (p *Provisioner) startVirtiofsd(_ *State, _ provision.ClusterRequest, _ string) error {\n\treturn nil\n}\n\nfunc (p *Provisioner) stopVirtiofsd(_ *State) error {\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/virtiofsd_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage vm\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/siderolabs/talos/pkg/provision\"\n)\n\nfunc (p *Provisioner) findVirtiofsd() (string, error) {\n\tvirtiofsdPaths := []string{\n\t\t\"virtiofsd\",\n\t\t\"/usr/libexec/virtiofsd\",\n\t}\n\n\tfor _, p := range virtiofsdPaths {\n\t\tif full, err := exec.LookPath(p); err == nil {\n\t\t\treturn full, nil\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"virtiofsd not found in paths: %v\", virtiofsdPaths)\n}\n\nfunc (p *Provisioner) startVirtiofsd(state *State, clusterReq provision.ClusterRequest, virtiofdPath string) error {\n\tpidPath := state.GetRelativePath(virtiofsdPid)\n\n\tlogFile, err := os.OpenFile(state.GetRelativePath(virtiofsdLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer logFile.Close() //nolint:errcheck\n\n\tvirtiofs := []string{}\n\n\tfor _, nodeReq := range clusterReq.Nodes {\n\t\tfor i, disk := range nodeReq.Disks {\n\t\t\tif disk.Driver != \"virtiofs\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvirtiofs = append(virtiofs,\n\t\t\t\tfmt.Sprintf(\"%s:%s\",\n\t\t\t\t\tstate.GetRelativePath(fmt.Sprintf(\"%s-%d.virtiofs.d\", nodeReq.Name, i)),\n\t\t\t\t\tstate.GetRelativePath(fmt.Sprintf(\"%s-%d.virtiofs.sock\", nodeReq.Name, i)),\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t}\n\n\targs := []string{\n\t\t\"virtiofsd-launch\",\n\t\t\"--bin\", virtiofdPath,\n\t\t\"--virtiofs\", strings.Join(virtiofs, \",\"),\n\t}\n\n\tcmd := exec.Command(clusterReq.SelfExecutable, args...) //nolint:noctx // runs in background\n\tcmd.Stdout = logFile\n\tcmd.Stderr = logFile\n\tcmd.SysProcAttr = &syscall.SysProcAttr{\n\t\tSetsid: true, // daemonize\n\t}\n\n\tif err = cmd.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm); err != nil {\n\t\treturn fmt.Errorf(\"error writing virtiofsd PID file: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Provisioner) stopVirtiofsd(state *State) error {\n\tpidPath := state.GetRelativePath(virtiofsdPid)\n\n\treturn StopProcessByPidfile(pidPath)\n}\n"
  },
  {
    "path": "pkg/provision/providers/vm/vm.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package vm implements common methods for VM provisioners.\npackage vm\n\n// Provisioner base for VM provisioners.\ntype Provisioner struct {\n\t// Name actual provisioner type.\n\tName string\n}\n"
  },
  {
    "path": "pkg/provision/provision.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package provision provides abstract definitions for Talos cluster provisioners.\npackage provision\n\nimport (\n\t\"context\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/bundle\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n)\n\n// Provisioner is an interface each provisioner should implement.\n//\n//nolint:interfacebloat\ntype Provisioner interface {\n\tCreate(context.Context, ClusterRequest, ...Option) (Cluster, error)\n\tDestroy(context.Context, Cluster, ...Option) error\n\n\tReflect(ctx context.Context, clusterName, stateDirectory string) (Cluster, error)\n\n\tGenOptions(NetworkRequest, *config.VersionContract) ([]generate.Option, []bundle.Option)\n\n\tGetInClusterKubernetesControlPlaneEndpoint(req NetworkRequest, controlPlanePort int) string\n\tGetExternalKubernetesControlPlaneEndpoint(req NetworkRequest, controlPlanePort int) string\n\tGetTalosAPIEndpoints(NetworkRequest) []string\n\n\tGetFirstInterface() v1alpha1.IfaceSelector\n\tGetFirstInterfaceName() string\n\n\tClose() error\n\n\tUserDiskName(index int) string\n}\n"
  },
  {
    "path": "pkg/provision/provision_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provision_test\n\nimport \"testing\"\n\nfunc TestEmpty(t *testing.T) {\n\t// added for accurate coverage estimation\n\t//\n\t// please remove it once any unit-test is added\n\t// for this package\n}\n"
  },
  {
    "path": "pkg/provision/request.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provision\n\nimport (\n\t\"errors\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\tmounttypes \"github.com/moby/moby/api/types/mount\"\n\t\"github.com/siderolabs/go-procfs/procfs\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/imager/quirks\"\n)\n\n// ClusterRequest is the root object describing cluster to be provisioned.\ntype ClusterRequest struct {\n\tName string\n\n\tNetwork NetworkRequest\n\tNodes   NodeRequests\n\n\t// Docker specific parameters.\n\tImage string\n\n\t// Boot options (QEMU).\n\tKernelPath     string\n\tInitramfsPath  string\n\tISOPath        string\n\tUSBPath        string\n\tUKIPath        string\n\tDiskImagePath  string\n\tIPXEBootScript string\n\n\t// Encryption\n\tKMSEndpoint string\n\n\t// Path to talosctl executable to re-execute itself as needed.\n\tSelfExecutable string\n\n\t// Path to root of state directory (~/.talos/clusters by default).\n\tStateDirectory string\n\n\tSiderolinkRequest SiderolinkRequest\n}\n\n// CNIConfig describes CNI part of NetworkRequest.\ntype CNIConfig struct {\n\tBinPath  []string\n\tConfDir  string\n\tCacheDir string\n\n\tBundleURL string\n}\n\n// NetworkRequest describes cluster network.\ntype NetworkRequest struct {\n\tName              string\n\tCIDRs             []netip.Prefix\n\tNoMasqueradeCIDRs []netip.Prefix\n\tGatewayAddrs      []netip.Addr\n\tMTU               int\n\tNameservers       []netip.Addr\n\n\tLoadBalancerPorts []int\n\n\t// CNI-specific parameters.\n\tCNI CNIConfig\n\n\t// DHCP options\n\tDHCPSkipHostname bool\n\n\t// Docker-specific parameters.\n\tDockerDisableIPv6 bool\n\n\t// Network chaos parameters.\n\tNetworkChaos  bool\n\tJitter        time.Duration\n\tLatency       time.Duration\n\tPacketLoss    float64\n\tPacketReorder float64\n\tPacketCorrupt float64\n\tBandwidth     int\n\n\t// Airgapped limits VM network access to the provisioning network only (qemu/linux).\n\tAirgapped             bool\n\tImageCachePath        string\n\tImageCacheTLSCertFile string\n\tImageCacheTLSKeyFile  string\n\tImageCachePort        uint16\n}\n\n// NodeRequests is a list of NodeRequest.\ntype NodeRequests []NodeRequest\n\n// FindInitNode looks up init node, it returns an error if no init node is present or if it's duplicate.\nfunc (reqs NodeRequests) FindInitNode() (req NodeRequest, err error) {\n\tfound := false\n\n\tfor i := range reqs {\n\t\tif reqs[i].Config == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif reqs[i].Config.Machine().Type() == machine.TypeInit {\n\t\t\tif found {\n\t\t\t\terr = errors.New(\"duplicate init node in requests\")\n\n\t\t\t\treturn req, err\n\t\t\t}\n\n\t\t\treq = reqs[i]\n\t\t\tfound = true\n\t\t}\n\t}\n\n\tif !found {\n\t\terr = errors.New(\"no init node found in requests\")\n\t}\n\n\treturn req, err\n}\n\n// ControlPlaneNodes returns subset of nodes which are Init/ControlPlane type.\nfunc (reqs NodeRequests) ControlPlaneNodes() (nodes []NodeRequest) {\n\tfor i := range reqs {\n\t\tif reqs[i].Type == machine.TypeInit || reqs[i].Type == machine.TypeControlPlane {\n\t\t\tnodes = append(nodes, reqs[i])\n\t\t}\n\t}\n\n\treturn nodes\n}\n\n// WorkerNodes returns subset of nodes which are Init/ControlPlane type.\nfunc (reqs NodeRequests) WorkerNodes() (nodes []NodeRequest) {\n\tfor i := range reqs {\n\t\tif reqs[i].Type == machine.TypeWorker {\n\t\t\tnodes = append(nodes, reqs[i])\n\t\t}\n\t}\n\n\treturn nodes\n}\n\n// PXENodes returns subset of nodes which are PXE booted.\nfunc (reqs NodeRequests) PXENodes() (nodes []NodeRequest) {\n\tfor i := range reqs {\n\t\tif reqs[i].PXEBooted {\n\t\t\tnodes = append(nodes, reqs[i])\n\t\t}\n\t}\n\n\treturn nodes\n}\n\n// Disk represents a disk size and name in NodeRequest.\ntype Disk struct {\n\t// Size in bytes.\n\tSize uint64\n\t// Whether to skip preallocating the disk space.\n\tSkipPreallocate bool\n\t// Driver for the disk.\n\t//\n\t// Supported types: \"virtio\", \"ide\", \"ahci\", \"scsi\", \"nvme\", \"megaraid\", \"virtiofs\" (special).\n\tDriver string\n\t// Block size for the disk, defaults to 512 if not set.\n\tBlockSize uint\n\t// Serial number for the disk.\n\tSerial string\n\t// Tag for the disk, only used for Virtiofs disks.\n\tTag string\n}\n\n// ConfigInjectionMethod describes how to inject configuration into the node.\ntype ConfigInjectionMethod int\n\nconst (\n\t// ConfigInjectionMethodHTTP injects configuration via HTTP.\n\tConfigInjectionMethodHTTP ConfigInjectionMethod = iota\n\t// ConfigInjectionMethodMetalISO injects configuration via Metal ISO.\n\tConfigInjectionMethodMetalISO\n)\n\n// NodeRequest describes a request for a node.\ntype NodeRequest struct {\n\tName string\n\tIPs  []netip.Addr\n\tType machine.Type\n\n\tQuirks quirks.Quirks\n\n\tConfig                config.Provider\n\tConfigInjectionMethod ConfigInjectionMethod\n\n\t// Share of CPUs, in 1e-9 fractions\n\tNanoCPUs int64\n\t// Memory limit in bytes\n\tMemory int64\n\t// Disks (volumes), if applicable (VM only)\n\tDisks []*Disk\n\t// Mounts (containers only)\n\tMounts []mounttypes.Mount\n\t// Ports\n\tPorts []string\n\t// SkipInjectingConfig disables reading configuration from http server\n\tSkipInjectingConfig bool\n\t// DefaultBootOrder overrides default boot order \"cn\" (disk, then network boot).\n\t//\n\t// BootOrder can be forced to be \"nc\" (PXE boot) via the API in QEMU provisioner.\n\tDefaultBootOrder string\n\n\t// ExtraKernelArgs passes additional kernel args\n\t// to the initial boot from initramfs and vmlinuz.\n\t//\n\t// This doesn't apply to boots from ISO or from the disk image.\n\tExtraKernelArgs *procfs.Cmdline\n\n\t// SDStubKernelArgs passes additional kernel args via the systemd-stub.\n\t//\n\t// This applies to boots from ISO and from the disk image.\n\tSDStubKernelArgs *procfs.Cmdline\n\n\t// UUID allows to specify the UUID of the node (VMs only).\n\t//\n\t// If not specified, a random UUID will be generated.\n\tUUID *uuid.UUID\n\n\t// Testing features\n\n\t// BadRTC resets RTC to well known time in the past (QEMU provisioner).\n\tBadRTC bool\n\n\t// PXE-booted VMs\n\tPXEBooted        bool\n\tTFTPServer       string\n\tIPXEBootFilename string\n}\n\n// SiderolinkRequest describes a request for SideroLink agent.\ntype SiderolinkRequest struct {\n\tWireguardEndpoint string\n\tAPIEndpoint       string\n\tAPICertificate    []byte\n\tAPIKey            []byte\n\tSinkEndpoint      string\n\tLogEndpoint       string\n\tSiderolinkBind    []SiderolinkBind\n}\n\n// GetAddr returns the address for the given UUID.\nfunc (sr *SiderolinkRequest) GetAddr(u *uuid.UUID) (netip.Addr, bool) {\n\tif idx := slices.IndexFunc(sr.SiderolinkBind, func(sb SiderolinkBind) bool { return sb.UUID == *u }); idx != -1 {\n\t\treturn sr.SiderolinkBind[idx].Addr, true\n\t}\n\n\treturn netip.Addr{}, false\n}\n\n// SiderolinkBind describes a pair of prebinded UUID->Addr for SideroLink agent.\ntype SiderolinkBind struct {\n\tUUID uuid.UUID\n\tAddr netip.Addr\n}\n"
  },
  {
    "path": "pkg/provision/result.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provision\n\nimport (\n\t\"net/netip\"\n\n\t\"github.com/google/uuid\"\n\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n)\n\n// Cluster describes the provisioned Cluster.\ntype Cluster interface {\n\t// Provisioner returns name of the provisioner used to build the cluster.\n\tProvisioner() string\n\t// StatePath returns path to the state directory of the cluster.\n\tStatePath() (string, error)\n\t// Info returns running cluster information.\n\tInfo() ClusterInfo\n}\n\n// ClusterInfo describes the cluster.\ntype ClusterInfo struct {\n\tClusterName string\n\n\tNetwork NetworkInfo\n\tNodes   []NodeInfo\n\n\t// ExtraNodes are not part of the cluster.\n\tExtraNodes []NodeInfo\n\n\t// KubernetesEndpoint is the endpoint of the Kubernetes API server.\n\tKubernetesEndpoint string\n}\n\n// NetworkInfo describes cluster network.\ntype NetworkInfo struct {\n\tName              string\n\tCIDRs             []netip.Prefix\n\tGatewayAddrs      []netip.Addr\n\tMTU               int\n\tNoMasqueradeCIDRs []netip.Prefix\n}\n\n// NodeInfo describes a node.\ntype NodeInfo struct {\n\tID   string\n\tUUID uuid.UUID\n\tName string\n\tType machine.Type\n\n\t// Share of CPUs, in 1e-9 fractions\n\tNanoCPUs int64\n\t// Memory limit in bytes\n\tMemory int64\n\t// Disk (volume) size in bytes, if applicable\n\tDiskSize uint64\n\n\tIPs []netip.Addr\n\n\tAPIPort     int\n\tTPMStateDir string\n}\n"
  },
  {
    "path": "pkg/provision/state.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage provision\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/containernetworking/cni/libcni\"\n\tyaml \"go.yaml.in/yaml/v4\"\n)\n\n// StateFileName is the name of the yaml state file.\nconst StateFileName = \"state.yaml\"\n\n// State common state representation for vm provisioners.\ntype State struct {\n\tProvisionerName string\n\tBridgeName      string\n\n\tClusterInfo ClusterInfo\n\n\tVMCNIConfig *libcni.NetworkConfigList\n\n\tstatePath string\n}\n\n// NewState create new vm provisioner state.\nfunc NewState(statePath, provisionerName, clusterName string) (*State, error) {\n\ts := &State{\n\t\tProvisionerName: provisionerName,\n\t\tstatePath:       statePath,\n\t}\n\n\t_, err := os.Stat(s.statePath)\n\tif err == nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"state directory %q already exists, is the cluster %q already running? remove cluster state with talosctl cluster destroy\",\n\t\t\ts.statePath,\n\t\t\tclusterName,\n\t\t)\n\t}\n\n\tif !errors.Is(err, fs.ErrNotExist) {\n\t\treturn nil, fmt.Errorf(\"error checking state directory: %w\", err)\n\t}\n\n\tif err = os.MkdirAll(s.statePath, os.ModePerm); err != nil {\n\t\treturn nil, fmt.Errorf(\"error creating state directory: %w\", err)\n\t}\n\n\treturn s, nil\n}\n\n// ReadState reads and parses the state saved to a file.\nfunc ReadState(ctx context.Context, clusterName, stateDirectory string) (*State, error) {\n\tstatePath := filepath.Join(stateDirectory, clusterName)\n\n\tst, err := os.Stat(statePath)\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, fmt.Errorf(\"cluster %q not found: %w\", clusterName, err)\n\t\t}\n\n\t\treturn nil, err\n\t}\n\n\tif !st.IsDir() {\n\t\treturn nil, fmt.Errorf(\"state path %q is not a directory: %s\", statePath, st.Mode())\n\t}\n\n\tstateFile, err := os.Open(filepath.Join(statePath, StateFileName))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer stateFile.Close() //nolint:errcheck\n\n\tstate := &State{}\n\n\tif err = yaml.NewDecoder(stateFile).Decode(state); err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling state file: %w\", err)\n\t}\n\n\tstate.statePath = statePath\n\n\treturn state, nil\n}\n\n// Provisioner get provisioner name.\nfunc (s *State) Provisioner() string {\n\treturn s.ProvisionerName\n}\n\n// Info get cluster info.\nfunc (s *State) Info() ClusterInfo {\n\treturn s.ClusterInfo\n}\n\n// StatePath get state config file path.\nfunc (s *State) StatePath() (string, error) {\n\tif s.statePath == \"\" {\n\t\treturn \"\", errors.New(\"state path is not set\")\n\t}\n\n\treturn s.statePath, nil\n}\n\n// Save save state to config file.\nfunc (s *State) Save() error {\n\t// save state\n\tstateFile, err := os.Create(filepath.Join(s.statePath, StateFileName))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer stateFile.Close() //nolint:errcheck\n\n\tif err = yaml.NewEncoder(stateFile).Encode(&s); err != nil {\n\t\treturn fmt.Errorf(\"error marshaling state: %w\", err)\n\t}\n\n\treturn stateFile.Close()\n}\n\n// GetRelativePath get file path relative to config folder.\nfunc (s *State) GetRelativePath(path string) string {\n\treturn filepath.Join(s.statePath, path)\n}\n\n// GetShmPath get shm path.\nfunc (s *State) GetShmPath(path string) string {\n\tif s.isDevShmAvailable() {\n\t\treturn filepath.Join(\"/dev/shm\", path)\n\t}\n\n\treturn filepath.Join(\"/tmp\", path)\n}\n"
  },
  {
    "path": "pkg/provision/state_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage provision\n\nimport (\n\t\"os\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst defaultContainerShmSize = 64 * 1024 * 1024 // 64MiB\n\nfunc (s *State) isDevShmAvailable() bool {\n\t// check if /dev/shm exists\n\tif _, err := os.Stat(\"/dev/shm\"); err != nil {\n\t\treturn false\n\t}\n\n\t// get /dev/shm stats\n\tvar stat unix.Statfs_t\n\n\tif err := unix.Statfs(\"/dev/shm\", &stat); err != nil {\n\t\treturn false\n\t}\n\n\t// check if is tmpfs\n\tif stat.Type != unix.TMPFS_MAGIC {\n\t\treturn false\n\t}\n\n\t// check if /dev/shm has potentially enough space\n\tif stat.Blocks*uint64(stat.Bsize) <= defaultContainerShmSize {\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "pkg/provision/state_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\npackage provision\n\nfunc (s *State) isDevShmAvailable() bool {\n\treturn false\n}\n"
  },
  {
    "path": "pkg/reporter/reporter.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package reporter implements the console reporter.\npackage reporter\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/mattn/go-isatty\"\n\t\"golang.org/x/term\"\n\n\t\"github.com/siderolabs/talos/pkg/flags\"\n)\n\n// Status represents the status of an Update.\ntype Status int\n\nconst (\n\t// StatusError represents an error status.\n\tStatusError Status = iota\n\t// StatusRunning represents a running status.\n\tStatusRunning\n\t// StatusSucceeded represents a success status.\n\tStatusSucceeded\n\t// StatusSkip represents a skipped status.\n\tStatusSkip\n)\n\nvar spinner = []string{\"◰\", \"◳\", \"◲\", \"◱\"}\n\n// Update represents an update to be reported.\ntype Update struct {\n\tMessage string\n\tStatus  Status\n}\n\n// Reporter is a console reporter with stderr output.\ntype Reporter struct {\n\tw                 *os.File\n\tlastLine          string\n\tlastLineTemporary bool\n\n\tcolorized  bool\n\tspinnerIdx int\n}\n\n// OutputMode represents the output mode of the reporter.\ntype OutputMode int32\n\n// String implements the fmt.Stringer interface for OutputMode.\nfunc (o OutputMode) String() string {\n\treturn outputModeNames[int32(o)]\n}\n\nvar outputModeValues = map[string]int32{\n\t\"AUTO\":  int32(OutputModeAuto),\n\t\"PLAIN\": int32(OutputModePlain),\n}\n\nvar outputModeNames = map[int32]string{\n\tint32(OutputModeAuto):  \"AUTO\",\n\tint32(OutputModePlain): \"PLAIN\",\n}\n\nconst (\n\t// OutputModeAuto represents the automatic output mode, which detects if the output is a terminal.\n\tOutputModeAuto OutputMode = iota\n\n\t// OutputModePlain represents the plain output mode, which disables colorization and spinner.\n\tOutputModePlain\n)\n\n// NewOutputModeFlag returns a pflag.Value for the output mode.\nfunc NewOutputModeFlag() flags.PflagExtended[OutputMode] {\n\treturn flags.ProtoEnum(\n\t\tOutputModeAuto,\n\t\toutputModeValues,\n\t\toutputModeNames,\n\t)\n}\n\n// Option represents an option for configuring the Reporter.\ntype Option func(*Reporter)\n\n// WithOutputMode returns an Option that sets the output mode of the Reporter.\nfunc WithOutputMode(mode OutputMode) Option {\n\treturn func(r *Reporter) {\n\t\tswitch mode {\n\t\tcase OutputModePlain:\n\t\t\tr.colorized = false\n\t\tcase OutputModeAuto:\n\t\t\tr.colorized = isatty.IsTerminal(r.w.Fd())\n\t\t}\n\t}\n}\n\n// New returns a console reporter with stderr output.\nfunc New(opts ...Option) *Reporter {\n\trep := &Reporter{\n\t\tw:         os.Stderr,\n\t\tcolorized: isatty.IsTerminal(os.Stderr.Fd()),\n\t}\n\n\tfor _, opt := range opts {\n\t\topt(rep)\n\t}\n\n\treturn rep\n}\n\n// IsColorized returns true if the reporter is colorized.\nfunc (r *Reporter) IsColorized() bool {\n\treturn r.colorized\n}\n\n// Report reports an update to the reporter.\n//\n//nolint:gocyclo\nfunc (r *Reporter) Report(update Update) {\n\tline := strings.TrimSpace(update.Message)\n\t// replace tabs with spaces to get consistent output length\n\tline = strings.ReplaceAll(line, \"\\t\", \"    \")\n\n\tif !r.colorized {\n\t\tif line != r.lastLine {\n\t\t\tfmt.Fprintln(r.w, line)\n\t\t\tr.lastLine = line\n\t\t}\n\n\t\treturn\n\t}\n\n\tw, _, _ := term.GetSize(int(r.w.Fd())) //nolint:errcheck\n\tif w <= 0 {\n\t\tw = 80\n\t}\n\n\tvar coloredLine string\n\n\tshowSpinner := false\n\tprevLineTemporary := r.lastLineTemporary\n\n\tswitch update.Status {\n\tcase StatusRunning:\n\t\tline = fmt.Sprintf(\"%s %s\", spinner[r.spinnerIdx], line)\n\t\tcoloredLine = color.YellowString(\"%s\", line)\n\t\tr.lastLineTemporary = true\n\t\tshowSpinner = true\n\tcase StatusSucceeded:\n\t\tcoloredLine = color.GreenString(\"%s\", line)\n\t\tr.lastLineTemporary = false\n\tcase StatusSkip:\n\t\tcoloredLine = color.BlueString(\"%s\", line)\n\t\tr.lastLineTemporary = false\n\tcase StatusError:\n\t\tfallthrough\n\tdefault:\n\t\tline = fmt.Sprintf(\"%s %s\", spinner[r.spinnerIdx], line)\n\t\tcoloredLine = color.RedString(\"%s\", line)\n\t\tr.lastLineTemporary = true\n\t\tshowSpinner = true\n\t}\n\n\tif line == r.lastLine {\n\t\treturn\n\t}\n\n\tif showSpinner {\n\t\tr.spinnerIdx = (r.spinnerIdx + 1) % len(spinner)\n\t}\n\n\tif prevLineTemporary {\n\t\tfor outputLine := range strings.SplitSeq(r.lastLine, \"\\n\") {\n\t\t\tfor range (utf8.RuneCountInString(outputLine) + w - 1) / w {\n\t\t\t\tfmt.Fprint(r.w, \"\\033[A\\033[K\") // cursor up, clear line\n\t\t\t}\n\t\t}\n\t}\n\n\tfmt.Fprintln(r.w, coloredLine)\n\tr.lastLine = line\n}\n"
  },
  {
    "path": "pkg/rotate/pki/internal/helpers/helpers.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package helpers provides helper functions for the rotate/pki package.\npackage helpers\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/resource\"\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/cosi-project/runtime/pkg/state\"\n\t\"github.com/siderolabs/gen/xslices\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\tconfigres \"github.com/siderolabs/talos/pkg/machinery/resources/config\"\n\tv1alpha1res \"github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1\"\n)\n\n// MapToInternalIP maps a slice of NodeInfo to a slice of internal IPs.\nfunc MapToInternalIP(in []cluster.NodeInfo) []string {\n\treturn xslices.Map(in, func(i cluster.NodeInfo) string {\n\t\treturn i.InternalIP.String()\n\t})\n}\n\n// PatchNodeConfig patches the node config for the given node.\nfunc PatchNodeConfig(ctx context.Context, c *client.Client, node string, encoderOpt encoder.Option, patchFunc func(config *v1alpha1.Config) error) error {\n\treturn retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond), retry.WithErrorLogging(true)).RetryWithContext(\n\t\tctx,\n\t\tfunc(ctx context.Context) error {\n\t\t\terr := patchNodeConfigInternal(ctx, c, node, encoderOpt, patchFunc)\n\t\t\tif err != nil {\n\t\t\t\tif client.StatusCode(err) == codes.Unavailable || client.StatusCode(err) == codes.Canceled {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn err\n\t\t},\n\t)\n}\n\n// PatchNodeConfigWithKubeletRestart patches the node config for the given node waiting for the kubelet to be restarted.\n//\n//nolint:gocyclo,cyclop\nfunc PatchNodeConfigWithKubeletRestart(ctx context.Context, c *client.Client, node string, encoderOpt encoder.Option, patchFunc func(config *v1alpha1.Config) error) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tctx = client.WithNode(ctx, node)\n\n\twatchCh := make(chan safe.WrappedStateEvent[*v1alpha1res.Service])\n\n\tif err := safe.StateWatch(ctx, c.COSI, resource.NewMetadata(v1alpha1res.NamespaceName, v1alpha1res.ServiceType, \"kubelet\", resource.VersionUndefined), watchCh); err != nil {\n\t\treturn fmt.Errorf(\"error watching service: %w\", err)\n\t}\n\n\tvar ev safe.WrappedStateEvent[*v1alpha1res.Service]\n\n\tselect {\n\tcase ev = <-watchCh:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n\n\tif ev.Type() != state.Created {\n\t\treturn fmt.Errorf(\"unexpected event type: %s\", ev.Type())\n\t}\n\n\tinitialService, err := ev.Resource()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error inspecting service: %w\", err)\n\t}\n\n\tif !initialService.TypedSpec().Running || !initialService.TypedSpec().Healthy {\n\t\treturn errors.New(\"kubelet is not healthy\")\n\t}\n\n\tif err = PatchNodeConfig(ctx, c, node, encoderOpt, patchFunc); err != nil {\n\t\treturn fmt.Errorf(\"error patching node config: %w\", err)\n\t}\n\n\t// first, wait for kubelet to go down\n\tfor {\n\t\tselect {\n\t\tcase ev = <-watchCh:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\n\t\tif ev.Type() == state.Destroyed {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// now wait for kubelet to go up & healthy\n\tfor {\n\t\tselect {\n\t\tcase ev = <-watchCh:\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\t}\n\n\t\tif ev.Type() == state.Created || ev.Type() == state.Updated {\n\t\t\tvar service *v1alpha1res.Service\n\n\t\t\tservice, err = ev.Resource()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error inspecting service: %w\", err)\n\t\t\t}\n\n\t\t\tif service.TypedSpec().Running && service.TypedSpec().Healthy {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc patchNodeConfigInternal(ctx context.Context, c *client.Client, node string, encoderOpt encoder.Option, patchFunc func(config *v1alpha1.Config) error) error {\n\tctx = client.WithNode(ctx, node)\n\n\tmc, err := safe.StateGetByID[*configres.MachineConfig](ctx, c.COSI, configres.ActiveID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching config resource: %w\", err)\n\t}\n\n\tprovider := mc.Provider()\n\n\tnewProvider, err := provider.PatchV1Alpha1(patchFunc)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error patching config: %w\", err)\n\t}\n\n\tcfgBytes, err := newProvider.EncodeBytes(encoderOpt)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error serializing config: %w\", err)\n\t}\n\n\t_, err = c.ApplyConfiguration(ctx, &machineapi.ApplyConfigurationRequest{\n\t\tData: cfgBytes,\n\t\tMode: machineapi.ApplyConfigurationRequest_NO_REBOOT,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error applying config: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/rotate/pki/kubernetes/kubernetes.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package kubernetes implements safe Talos API PKI rotation for the cluster.\npackage kubernetes\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.yaml.in/yaml/v4\"\n\tv1 \"k8s.io/api/core/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\ttaloskubernetes \"github.com/siderolabs/talos/pkg/kubernetes\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\tsecretsres \"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/internal/helpers\"\n)\n\n// Options is the input to the Kubernetes API rotation process.\ntype Options struct {\n\t// DryRun is the flag to enable dry-run mode.\n\t//\n\t// In dry-run mode, the rotation process will not make any changes to the cluster.\n\tDryRun bool\n\n\t// TalosClient is a Talos API client\n\tTalosClient *client.Client\n\t// ClusterInfo provides information about cluster topology.\n\tClusterInfo cluster.Info\n\n\t// KubernetesEndpoint overrides the default Kubernetes API endpoint.\n\tKubernetesEndpoint string\n\n\t// NewKubernetesCA is the new CA for Kubernetes API.\n\tNewKubernetesCA *x509.PEMEncodedCertificateAndKey\n\n\t// EncoderOption is the option for encoding machine configuration (while patching).\n\tEncoderOption encoder.Option\n\n\t// Printf is the function used to print messages.\n\tPrintf func(format string, args ...any)\n}\n\ntype rotator struct {\n\topts Options\n\n\tcurrentCA []byte\n\n\ttalosClientProvider *cluster.ConfigClientProvider\n\tcurrentKubernetes   *cluster.KubernetesClient\n\tnewKubernetes       *cluster.KubernetesClient\n}\n\n// Rotate rotates the Kubernetes API PKI.\n//\n// The process overview:\n//   - fetch current information\n//   - verify connectivity with the existing PKI\n//   - add new Kubernetes CA as accepted\n//   - verify connectivity\n//   - make new CA issuing, old CA is still accepted\n//   - verify connectivity with the new PKI\n//   - remove old CA\n//   - verify connectivity with the new PKI.\nfunc Rotate(ctx context.Context, opts Options) error {\n\tr := rotator{\n\t\topts: opts,\n\t}\n\n\tdefer func() {\n\t\tif r.currentKubernetes != nil {\n\t\t\tr.currentKubernetes.K8sClose() //nolint:errcheck\n\t\t}\n\n\t\tif r.newKubernetes != nil {\n\t\t\tr.newKubernetes.K8sClose() //nolint:errcheck\n\t\t}\n\t}()\n\n\tr.talosClientProvider = &cluster.ConfigClientProvider{\n\t\tDefaultClient: opts.TalosClient,\n\t}\n\n\treturn r.rotate(ctx)\n}\n\n//nolint:gocyclo\nfunc (r *rotator) rotate(ctx context.Context) error {\n\tr.printIntro()\n\n\tif err := r.fetchClient(ctx, &r.currentKubernetes, \"current\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.fetchCurrentCA(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.printNewCA(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.currentKubernetes, \"existing PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.addNewCAAccepted(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.swapCAs(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.fetchClient(ctx, &r.newKubernetes, \"new\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.newKubernetes, \"new PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.dropOldCA(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.newKubernetes, \"new PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) printIntro() {\n\tr.opts.Printf(\"> Starting Kubernetes API PKI rotation, dry-run mode %v...\\n\", r.opts.DryRun)\n\n\tr.opts.Printf(\"> Cluster topology:\\n\")\n\n\tr.opts.Printf(\"  - control plane nodes: %q\\n\",\n\t\tappend(\n\t\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeInit)),\n\t\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeControlPlane))...,\n\t\t),\n\t)\n\tr.opts.Printf(\"  - worker nodes: %q\\n\",\n\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeWorker)),\n\t)\n}\n\nfunc (r *rotator) fetchClient(ctx context.Context, clientPtr **cluster.KubernetesClient, label string) error {\n\tr.opts.Printf(\"> Building %s Kubernetes client...\\n\", label)\n\n\tfirstNode := append(\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeInit),\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeControlPlane)...,\n\t)[0]\n\n\t*clientPtr = &cluster.KubernetesClient{\n\t\tClientProvider: r.talosClientProvider,\n\t\tForceEndpoint:  r.opts.KubernetesEndpoint,\n\t}\n\n\t_, err := (*clientPtr).K8sClient(client.WithNode(ctx, firstNode.InternalIP.String()))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching kubeconfig: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) fetchCurrentCA(ctx context.Context) error {\n\tr.opts.Printf(\"> Current Kubernetes CA:\\n\")\n\n\tfirstNode := append(\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeInit),\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeControlPlane)...,\n\t)[0]\n\n\tk8sRoot, err := safe.StateGetByID[*secretsres.KubernetesRoot](client.WithNode(ctx, firstNode.InternalIP.String()), r.opts.TalosClient.COSI, secretsres.KubernetesRootID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching current Kubernetes CA: %w\", err)\n\t}\n\n\tr.currentCA = k8sRoot.TypedSpec().IssuingCA.Crt\n\n\tvar b bytes.Buffer\n\n\tif err = yaml.NewEncoder(&b).Encode(k8sRoot.TypedSpec().IssuingCA); err != nil {\n\t\treturn fmt.Errorf(\"error encoding current Kubernetes CA: %w\", err)\n\t}\n\n\tfor scanner := bufio.NewScanner(&b); scanner.Scan(); {\n\t\tr.opts.Printf(\"  %s\\n\", scanner.Text())\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) printNewCA() error {\n\tr.opts.Printf(\"> New Kubernetes CA:\\n\")\n\n\tvar b bytes.Buffer\n\n\tif err := yaml.NewEncoder(&b).Encode(r.opts.NewKubernetesCA); err != nil {\n\t\treturn fmt.Errorf(\"error encoding new Talos CA: %w\", err)\n\t}\n\n\tfor scanner := bufio.NewScanner(&b); scanner.Scan(); {\n\t\tr.opts.Printf(\"  %s\\n\", scanner.Text())\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) verifyConnectivity(ctx context.Context, client *cluster.KubernetesClient, label string) error {\n\tr.opts.Printf(\"> Verifying connectivity with %s...\\n\", label)\n\n\tif r.opts.DryRun {\n\t\tr.opts.Printf(\" - OK (dry-run mode)\\n\")\n\n\t\treturn nil\n\t}\n\n\tclientset, err := client.K8sClient(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error building Kubernetes client: %w\", err)\n\t}\n\n\treturn retry.Constant(3*time.Minute, retry.WithUnits(time.Second), retry.WithErrorLogging(true)).RetryWithContext(ctx,\n\t\tfunc(ctx context.Context) error {\n\t\t\tnodes, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})\n\t\t\tif err != nil {\n\t\t\t\tif taloskubernetes.IsRetryableError(err) {\n\t\t\t\t\treturn retry.ExpectedError(err)\n\t\t\t\t}\n\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tvar notReadyNodes []string\n\n\t\t\tfor _, node := range nodes.Items {\n\t\t\t\tfor _, cond := range node.Status.Conditions {\n\t\t\t\t\tif cond.Type == v1.NodeReady {\n\t\t\t\t\t\tif cond.Status != v1.ConditionTrue {\n\t\t\t\t\t\t\tnotReadyNodes = append(notReadyNodes, node.Name)\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif len(notReadyNodes) > 0 {\n\t\t\t\treturn retry.ExpectedErrorf(\"nodes not ready: %q\", notReadyNodes)\n\t\t\t}\n\n\t\t\tr.opts.Printf(\" - OK (%d nodes ready)\\n\", len(nodes.Items))\n\n\t\t\treturn nil\n\t\t})\n}\n\nfunc (r *rotator) addNewCAAccepted(ctx context.Context) error {\n\tr.opts.Printf(\"> Adding new Kubernetes CA as accepted...\\n\")\n\n\tif err := r.patchAllNodes(ctx,\n\t\tfunc(_ machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs = append(\n\t\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs,\n\t\t\t\t&x509.PEMEncodedCertificate{\n\t\t\t\t\tCrt: r.opts.NewKubernetesCA.Crt,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) swapCAs(ctx context.Context) error {\n\tr.opts.Printf(\"> Making new Kubernetes CA the issuing CA, old Kubernetes CA the accepted CA...\\n\")\n\n\tif err := r.patchAllNodes(ctx,\n\t\tfunc(machineType machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs = append(\n\t\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs,\n\t\t\t\t&x509.PEMEncodedCertificate{\n\t\t\t\t\tCrt: r.currentCA,\n\t\t\t\t},\n\t\t\t)\n\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs = slices.DeleteFunc(config.Cluster().AcceptedCAs(), func(ca *x509.PEMEncodedCertificate) bool {\n\t\t\t\treturn bytes.Equal(ca.Crt, r.opts.NewKubernetesCA.Crt)\n\t\t\t})\n\n\t\t\tif machineType.IsControlPlane() {\n\t\t\t\tconfig.ClusterConfig.ClusterCA = r.opts.NewKubernetesCA\n\t\t\t} else {\n\t\t\t\tconfig.ClusterConfig.ClusterCA = &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\tCrt: r.opts.NewKubernetesCA.Crt,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) dropOldCA(ctx context.Context) error {\n\tr.opts.Printf(\"> Removing old Kubernetes CA from the accepted CAs...\\n\")\n\n\tif err := r.patchAllNodes(ctx,\n\t\tfunc(_ machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.ClusterConfig.ClusterAcceptedCAs = slices.DeleteFunc(config.Cluster().AcceptedCAs(), func(ca *x509.PEMEncodedCertificate) bool {\n\t\t\t\treturn bytes.Equal(ca.Crt, r.currentCA)\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) patchAllNodes(ctx context.Context, patchFunc func(machineType machine.Type, config *v1alpha1.Config) error) error {\n\tfor _, machineType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {\n\t\tfor _, node := range r.opts.ClusterInfo.NodesByType(machineType) {\n\t\t\tif r.opts.DryRun {\n\t\t\t\tr.opts.Printf(\"  - %s: skipped (dry-run)\\n\", node.InternalIP)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := helpers.PatchNodeConfigWithKubeletRestart(ctx, r.opts.TalosClient, node.InternalIP.String(), r.opts.EncoderOption, func(config *v1alpha1.Config) error {\n\t\t\t\treturn patchFunc(machineType, config)\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error patching node %s: %w\", node.InternalIP, err)\n\t\t\t}\n\n\t\t\tr.opts.Printf(\"  - %s: OK\\n\", node.InternalIP)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/rotate/pki/talos/talos.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package talos implements safe Talos API PKI rotation for the cluster.\npackage talos\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/cosi-project/runtime/pkg/safe\"\n\t\"github.com/siderolabs/crypto/x509\"\n\t\"github.com/siderolabs/go-retry/retry\"\n\t\"go.yaml.in/yaml/v4\"\n\t\"google.golang.org/grpc/codes\"\n\n\t\"github.com/siderolabs/talos/pkg/cluster\"\n\tmachineapi \"github.com/siderolabs/talos/pkg/machinery/api/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/client\"\n\tclientconfig \"github.com/siderolabs/talos/pkg/machinery/client/config\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/generate/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/machine\"\n\t\"github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1\"\n\tsecretsres \"github.com/siderolabs/talos/pkg/machinery/resources/secrets\"\n\t\"github.com/siderolabs/talos/pkg/machinery/role\"\n\t\"github.com/siderolabs/talos/pkg/rotate/pki/internal/helpers\"\n)\n\n// Options is the input to the Talos API rotation process.\ntype Options struct {\n\t// DryRun is the flag to enable dry-run mode.\n\t//\n\t// In dry-run mode, the rotation process will not make any changes to the cluster.\n\tDryRun bool\n\n\t// CurrentClient is a Talos client for the existing PKI.\n\tCurrentClient *client.Client\n\t// ClusterInfo provides information about cluster topology.\n\tClusterInfo cluster.Info\n\n\t// ContextName is the context name for the 'talosconfig'.\n\tContextName string\n\t// Endpoints is the list of endpoints for the 'talosconfig'.\n\tEndpoints []string\n\n\t// NewTalosCA is the new CA for Talos API.\n\tNewTalosCA *x509.PEMEncodedCertificateAndKey\n\n\t// EncoderOption is the option for encoding machine configuration (while patching).\n\tEncoderOption encoder.Option\n\n\t// Printf is the function used to print messages.\n\tPrintf func(format string, args ...any)\n}\n\ntype rotator struct {\n\topts Options\n\n\tcurrentCA []byte\n\n\tintermediateTalosconfig *clientconfig.Config\n\tnewTalosconfig          *clientconfig.Config\n\n\tintermediateClient *client.Client\n\tnewClient          *client.Client\n}\n\n// Rotate rotates the Talos API PKI.\n//\n// The process overview:\n//   - fetch current information\n//   - verify connectivity with the existing PKI\n//   - add new Talos CA as accepted\n//   - verify connectivity with the intermediate PKI\n//   - make new CA issuing, old CA is still accepted\n//   - verify connectivity with the new PKI\n//   - remove old Talos CA\n//   - verify connectivity with the new PKI.\nfunc Rotate(ctx context.Context, opts Options) (*clientconfig.Config, error) {\n\tr := rotator{\n\t\topts: opts,\n\t}\n\n\tdefer func() {\n\t\tif r.intermediateClient != nil {\n\t\t\tr.intermediateClient.Close() //nolint:errcheck\n\t\t}\n\n\t\tif r.newClient != nil {\n\t\t\tr.newClient.Close() //nolint:errcheck\n\t\t}\n\t}()\n\n\terr := r.rotate(ctx)\n\n\treturn r.newTalosconfig, err\n}\n\n//nolint:gocyclo\nfunc (r *rotator) rotate(ctx context.Context) error {\n\tr.printIntro()\n\n\tif err := r.fetchCurrentCA(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.printNewCA(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.generateClients(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.opts.CurrentClient, \"existing PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.addNewCAAccepted(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.intermediateClient, \"new client cert, but old server CA\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.swapCAs(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.newClient, \"new PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.dropOldCA(ctx); err != nil {\n\t\treturn err\n\t}\n\n\tif err := r.verifyConnectivity(ctx, r.newClient, \"new PKI\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) printIntro() {\n\tr.opts.Printf(\"> Starting Talos API PKI rotation, dry-run mode %v...\\n\", r.opts.DryRun)\n\tr.opts.Printf(\"> Using config context: %q\\n\", r.opts.ContextName)\n\tr.opts.Printf(\"> Using Talos API endpoints: %q\\n\", r.opts.Endpoints)\n\n\tr.opts.Printf(\"> Cluster topology:\\n\")\n\n\tr.opts.Printf(\"  - control plane nodes: %q\\n\",\n\t\tappend(\n\t\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeInit)),\n\t\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeControlPlane))...,\n\t\t),\n\t)\n\tr.opts.Printf(\"  - worker nodes: %q\\n\",\n\t\thelpers.MapToInternalIP(r.opts.ClusterInfo.NodesByType(machine.TypeWorker)),\n\t)\n}\n\nfunc (r *rotator) fetchCurrentCA(ctx context.Context) error {\n\tr.opts.Printf(\"> Current Talos CA:\\n\")\n\n\tfirstNode := append(\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeInit),\n\t\tr.opts.ClusterInfo.NodesByType(machine.TypeControlPlane)...,\n\t)[0]\n\n\tosRoot, err := safe.StateGetByID[*secretsres.OSRoot](client.WithNode(ctx, firstNode.InternalIP.String()), r.opts.CurrentClient.COSI, secretsres.OSRootID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error fetching existing Talos CA: %w\", err)\n\t}\n\n\tr.currentCA = osRoot.TypedSpec().IssuingCA.Crt\n\n\tvar b bytes.Buffer\n\n\tif err = yaml.NewEncoder(&b).Encode(osRoot.TypedSpec().IssuingCA); err != nil {\n\t\treturn fmt.Errorf(\"error encoding new Talos CA: %w\", err)\n\t}\n\n\tfor scanner := bufio.NewScanner(&b); scanner.Scan(); {\n\t\tr.opts.Printf(\"  %s\\n\", scanner.Text())\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) printNewCA() error {\n\tr.opts.Printf(\"> New Talos CA:\\n\")\n\n\tvar b bytes.Buffer\n\n\tif err := yaml.NewEncoder(&b).Encode(r.opts.NewTalosCA); err != nil {\n\t\treturn fmt.Errorf(\"error encoding new Talos CA: %w\", err)\n\t}\n\n\tfor scanner := bufio.NewScanner(&b); scanner.Scan(); {\n\t\tr.opts.Printf(\"  %s\\n\", scanner.Text())\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) generateClients(ctx context.Context) error {\n\tr.opts.Printf(\"> Generating new talosconfig:\\n\")\n\n\tnewBundle := &secrets.Bundle{\n\t\tClock: secrets.NewFixedClock(time.Now()),\n\t\tCerts: &secrets.Certs{\n\t\t\tOS: r.opts.NewTalosCA,\n\t\t},\n\t}\n\n\tcert, err := newBundle.GenerateTalosAPIClientCertificate(role.MakeSet(role.Admin))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error generating new talosconfig: %w\", err)\n\t}\n\n\t// using old server CA, but new client cert\n\tr.intermediateTalosconfig = clientconfig.NewConfig(r.opts.ContextName, r.opts.Endpoints, r.currentCA, cert)\n\n\t// using new server CA and a new client cert\n\tr.newTalosconfig = clientconfig.NewConfig(r.opts.ContextName, r.opts.Endpoints, r.opts.NewTalosCA.Crt, cert)\n\n\tmarshalledTalosconfig, err := r.newTalosconfig.Bytes()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling talosconfig: %w\", err)\n\t}\n\n\tr.opts.Printf(\"%s\\n\", string(marshalledTalosconfig))\n\n\tr.intermediateClient, err = client.New(ctx,\n\t\tclient.WithConfig(r.intermediateTalosconfig),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating intermediate client: %w\", err)\n\t}\n\n\tr.newClient, err = client.New(ctx,\n\t\tclient.WithConfig(r.newTalosconfig),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating new client: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) verifyConnectivity(ctx context.Context, c *client.Client, label string) error {\n\tr.opts.Printf(\"> Verifying connectivity with %s:\\n\", label)\n\n\tfor _, node := range r.opts.ClusterInfo.Nodes() {\n\t\tif r.opts.DryRun {\n\t\t\tr.opts.Printf(\"  - %s: OK (dry-run)\\n\", node.InternalIP)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tvar resp *machineapi.VersionResponse\n\n\t\tif err := retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond), retry.WithErrorLogging(true)).RetryWithContext(ctx, func(ctx context.Context) error {\n\t\t\tnodeCtx := client.WithNode(ctx, node.InternalIP.String())\n\n\t\t\tvar respErr error\n\n\t\t\tresp, respErr = c.Version(nodeCtx)\n\t\t\tif respErr != nil {\n\t\t\t\tif client.StatusCode(respErr) == codes.Unavailable {\n\t\t\t\t\treturn retry.ExpectedError(respErr)\n\t\t\t\t}\n\n\t\t\t\treturn respErr\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\treturn fmt.Errorf(\"error calling version API on node %s: %w\", node.InternalIP, err)\n\t\t}\n\n\t\tr.opts.Printf(\"  - %s: OK (version %s)\\n\", node.InternalIP, resp.Messages[0].Version.GetTag())\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) addNewCAAccepted(ctx context.Context) error {\n\tr.opts.Printf(\"> Adding new Talos CA as accepted...\\n\")\n\n\tif err := r.patchAllNodes(ctx, r.opts.CurrentClient,\n\t\tfunc(_ machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.MachineConfig.MachineAcceptedCAs = append(\n\t\t\t\tconfig.MachineConfig.MachineAcceptedCAs,\n\t\t\t\t&x509.PEMEncodedCertificate{\n\t\t\t\t\tCrt: r.opts.NewTalosCA.Crt,\n\t\t\t\t},\n\t\t\t)\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) swapCAs(ctx context.Context) error {\n\tr.opts.Printf(\"> Making new Talos CA the issuing CA, old Talos CA the accepted CA...\\n\")\n\n\tif err := r.patchAllNodes(ctx, r.intermediateClient,\n\t\tfunc(machineType machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.MachineConfig.MachineAcceptedCAs = append(\n\t\t\t\tconfig.MachineConfig.MachineAcceptedCAs,\n\t\t\t\t&x509.PEMEncodedCertificate{\n\t\t\t\t\tCrt: r.currentCA,\n\t\t\t\t},\n\t\t\t)\n\t\t\tconfig.MachineConfig.MachineAcceptedCAs = slices.DeleteFunc(config.Machine().Security().AcceptedCAs(), func(ca *x509.PEMEncodedCertificate) bool {\n\t\t\t\treturn bytes.Equal(ca.Crt, r.opts.NewTalosCA.Crt)\n\t\t\t})\n\n\t\t\tif machineType.IsControlPlane() {\n\t\t\t\tconfig.MachineConfig.MachineCA = r.opts.NewTalosCA\n\t\t\t} else {\n\t\t\t\tconfig.MachineConfig.MachineCA = &x509.PEMEncodedCertificateAndKey{\n\t\t\t\t\tCrt: r.opts.NewTalosCA.Crt,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) dropOldCA(ctx context.Context) error {\n\tr.opts.Printf(\"> Removing old Talos CA from the accepted CAs...\\n\")\n\n\tif err := r.patchAllNodes(ctx, r.newClient,\n\t\tfunc(_ machine.Type, config *v1alpha1.Config) error {\n\t\t\tconfig.MachineConfig.MachineAcceptedCAs = slices.DeleteFunc(config.Machine().Security().AcceptedCAs(), func(ca *x509.PEMEncodedCertificate) bool {\n\t\t\t\treturn bytes.Equal(ca.Crt, r.currentCA)\n\t\t\t})\n\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn fmt.Errorf(\"error patching all machine configs: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (r *rotator) patchAllNodes(ctx context.Context, c *client.Client, patchFunc func(machineType machine.Type, config *v1alpha1.Config) error) error {\n\tfor _, machineType := range []machine.Type{machine.TypeInit, machine.TypeControlPlane, machine.TypeWorker} {\n\t\tfor _, node := range r.opts.ClusterInfo.NodesByType(machineType) {\n\t\t\tif r.opts.DryRun {\n\t\t\t\tr.opts.Printf(\"  - %s: skipped (dry-run)\\n\", node.InternalIP)\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := helpers.PatchNodeConfig(ctx, c, node.InternalIP.String(), r.opts.EncoderOption, func(config *v1alpha1.Config) error {\n\t\t\t\treturn patchFunc(machineType, config)\n\t\t\t}); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error patching node %s: %w\", node.InternalIP, err)\n\t\t\t}\n\n\t\t\tr.opts.Printf(\"  - %s: OK\\n\", node.InternalIP)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/safepath/safepath.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package safepath provides a set of functions to make paths safe for use with.\npackage safepath\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// CleanPath makes a path safe for use with filepath.Join. This is done by not\n// only cleaning the path, but also (if the path is relative) adding a leading\n// '/' and cleaning it (then removing the leading '/'). This ensures that a\n// path resulting from prepending another path will always resolve to lexically\n// be a subdirectory of the prefixed path. This is all done lexically, so paths\n// that include symlinks won't be safe as a result of using CleanPath.\nfunc CleanPath(path string) string {\n\t// Deal with empty strings nicely.\n\tif path == \"\" {\n\t\treturn \"\"\n\t}\n\n\t// Ensure that all paths are cleaned (especially problematic ones like\n\t// \"/../../../../../\" which can cause lots of issues).\n\tpath = filepath.Clean(path)\n\n\t// If the path isn't absolute, we need to do more processing to fix paths\n\t// such as \"../../../../<etc>/some/path\". We also shouldn't convert absolute\n\t// paths to relative ones.\n\tif !filepath.IsAbs(path) {\n\t\tpath = filepath.Clean(string(os.PathSeparator) + path)\n\t\t// This can't fail, as (by definition) all paths are relative to root.\n\t\tpath, _ = filepath.Rel(string(os.PathSeparator), path) //nolint:errcheck\n\t}\n\n\t// Clean the path again for good measure.\n\treturn filepath.Clean(path)\n}\n"
  },
  {
    "path": "pkg/safepath/safepath_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage safepath_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/siderolabs/talos/pkg/safepath\"\n)\n\nfunc TestCleanPath(t *testing.T) {\n\tpath := safepath.CleanPath(\"\")\n\tif path != \"\" {\n\t\tt.Errorf(\"expected to receive empty string and received %s\", path)\n\t}\n\n\tpath = safepath.CleanPath(\"rootfs\")\n\tif path != \"rootfs\" {\n\t\tt.Errorf(\"expected to receive 'rootfs' and received %s\", path)\n\t}\n\n\tpath = safepath.CleanPath(\"../../../var\")\n\tif path != \"var\" {\n\t\tt.Errorf(\"expected to receive 'var' and received %s\", path)\n\t}\n\n\tpath = safepath.CleanPath(\"/../../../var\")\n\tif path != \"/var\" {\n\t\tt.Errorf(\"expected to receive '/var' and received %s\", path)\n\t}\n\n\tpath = safepath.CleanPath(\"/foo/bar/\")\n\tif path != \"/foo/bar\" {\n\t\tt.Errorf(\"expected to receive '/foo/bar' and received %s\", path)\n\t}\n\n\tpath = safepath.CleanPath(\"/foo/bar/../\")\n\tif path != \"/foo\" {\n\t\tt.Errorf(\"expected to receive '/foo' and received %s\", path)\n\t}\n}\n"
  },
  {
    "path": "pkg/splash/splash.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package splash contains boot splash images.\npackage splash\n\nimport (\n\t_ \"embed\"\n)\n\n//go:embed sidero.bmp\nvar sideroBMP []byte\n\n// GetBootImage returns boot splash image.\nfunc GetBootImage() []byte {\n\treturn sideroBMP\n}\n"
  },
  {
    "path": "pkg/startup/maxprocs.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage startup\n\nimport (\n\t\"log\"\n\t\"runtime\"\n)\n\n// LimitMaxProcs limits the GOMAXPROCS to the number specified.\nfunc LimitMaxProcs(maxProcs int) {\n\tcurProcs := runtime.GOMAXPROCS(0)\n\n\tif curProcs > maxProcs {\n\t\truntime.GOMAXPROCS(maxProcs)\n\n\t\tlog.Printf(\"limited GOMAXPROCS to %d\", maxProcs)\n\t}\n}\n"
  },
  {
    "path": "pkg/startup/startup.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package startup provides utility function for process startup\npackage startup\n"
  },
  {
    "path": "pkg/xfs/fsopen/fsopen_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\n// Package fsopen provides a simple interface to create and manage a filesystem\n// using the Linux syscalls for filesystem operations.\npackage fsopen\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/siderolabs/talos/pkg/makefs\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// ErrRepairUnsupported is reported when the filesystem does not support repairs.\nvar ErrRepairUnsupported = errors.New(\"unsupported filesystem type for repair\")\n\n// FS represents a filesystem that can be created and managed.\n// It holds the flags and strings used for configuration, as well as the file descriptor\n// for the mounted filesystem.\ntype FS struct {\n\tfstype string\n\tsource string\n\n\tboolParams   map[string]struct{}\n\tstringParams map[string][]string\n\tbinaryParams map[string][][]byte\n\n\tmntfd    int\n\tmntflags int\n}\n\n// Interface guard.\nvar (\n\t_ xfs.FS = (*FS)(nil)\n)\n\n// New creates a new FS instance with the provided options.\nfunc New(fstype string, opts ...Option) *FS {\n\tfs := &FS{\n\t\tfstype:       fstype,\n\t\tboolParams:   make(map[string]struct{}),\n\t\tstringParams: make(map[string][]string),\n\t\tbinaryParams: make(map[string][][]byte),\n\t}\n\n\tfor _, opt := range defaultOpts(fstype, opts...) {\n\t\topt.set(fs)\n\t}\n\n\treturn fs\n}\n\n// defaultOpts applies default options for filesystems.\nfunc defaultOpts(fstype string, opts ...Option) []Option {\n\tif fstype == \"iso9660\" {\n\t\topts = append(\n\t\t\topts,\n\t\t\tWithBoolParameter(\"ro\"),\n\t\t)\n\t}\n\n\treturn opts\n}\n\n// Open initializes the filesystem and returns the file descriptor for the mounted filesystem.\n// If the filesystem is already created, it returns the existing file descriptor.\n// This method is idempotent, meaning it can be called multiple times without side effects.\nfunc (fs *FS) Open() (int, error) {\n\tif fs.mntfd != 0 {\n\t\treturn fs.mntfd, nil\n\t}\n\n\terr := fs.new()\n\n\treturn fs.mntfd, err\n}\n\n//nolint:gocyclo\nfunc (fs *FS) new() (err error) {\n\tvar fsfd int\n\n\tfsfd, err = unix.Fsopen(fs.fstype, unix.FSOPEN_CLOEXEC)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unix.Fsopen fstype=%q failed: %w\", fs.fstype, err)\n\t}\n\n\tdefer func() {\n\t\tif cloErr := unix.Close(fsfd); err == nil {\n\t\t\terr = cloErr\n\t\t} else {\n\t\t\terr = errors.Join(err, cloErr)\n\t\t}\n\t}()\n\n\tif fs.source != \"\" {\n\t\tif err := unix.FsconfigSetString(fsfd, \"source\", fs.source); err != nil {\n\t\t\treturn fmt.Errorf(\"FSCONFIG_SET_STRING failed: %w: key=%q value=%q\", err, \"source\", fs.source)\n\t\t}\n\t}\n\n\tfor key := range fs.boolParams {\n\t\tif err := unix.FsconfigSetFlag(fsfd, key); err != nil {\n\t\t\treturn fmt.Errorf(\"FSCONFIG_SET_FLAG failed: %w: key=%q\", err, key)\n\t\t}\n\t}\n\n\tfor key, binary := range fs.binaryParams {\n\t\tfor _, bf := range binary {\n\t\t\tif err := unix.FsconfigSetBinary(fsfd, key, bf); err != nil {\n\t\t\t\treturn fmt.Errorf(\"FSCONFIG_SET_BINARY failed: %w: key=%q\", err, key)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor key, values := range fs.stringParams {\n\t\tfor _, value := range values {\n\t\t\tif err := unix.FsconfigSetString(fsfd, key, value); err != nil {\n\t\t\t\treturn fmt.Errorf(\"FSCONFIG_SET_BINARY failed: %w: key=%q\", err, key)\n\t\t\t}\n\t\t}\n\t}\n\n\terr = unix.FsconfigCreate(fsfd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"FSCONFIG_CMD_CREATE failed: %w\", err)\n\t}\n\n\tfs.mntflags |= unix.FSMOUNT_CLOEXEC\n\n\tfs.mntfd, err = unix.Fsmount(fsfd, fs.mntflags, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"FSMOUNT failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Close closes the file descriptor.\nfunc (fs *FS) Close() error {\n\tif fs.mntfd == 0 {\n\t\treturn os.ErrClosed\n\t}\n\n\toldmntfd := fs.mntfd\n\tfs.mntfd = 0\n\n\treturn unix.Close(oldmntfd)\n}\n\n// Repair attempts to repair the filesystem if it is in a dirty state.\nfunc (fs *FS) Repair(ctx context.Context) error {\n\tvar repairFunc func(ctx context.Context, partition string) error\n\n\tswitch fs.fstype {\n\tcase makefs.FilesystemTypeEXT4:\n\t\trepairFunc = makefs.Ext4Repair\n\tcase makefs.FilesystemTypeXFS:\n\t\trepairFunc = makefs.XFSRepair\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %s\", ErrRepairUnsupported, fs.fstype)\n\t}\n\n\tif err := repairFunc(ctx, fs.source); err != nil {\n\t\treturn fmt.Errorf(\"repair %q: %w\", fs.source, err)\n\t}\n\n\treturn nil\n}\n\n// MountAt mounts the filesystem at the specified path.\n//\n// EXPERIMENTAL: This function is experimental and may change in the future.\nfunc (fs *FS) MountAt(path string) (string, error) {\n\trealpath, err := filepath.EvalSymlinks(path)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: %q -> %q\", err, path, realpath)\n\t}\n\n\tif err := fs.mountAt(realpath); err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: %q\", err, realpath)\n\t}\n\n\treturn realpath, nil\n}\n\nfunc (fs *FS) mountAt(path string) error {\n\treturn unix.MoveMount(fs.mntfd, \"\", unix.AT_FDCWD, path, unix.MOVE_MOUNT_F_EMPTY_PATH)\n}\n\n// UnmountFrom unmounts the filesystem from the specified path.\n//\n// EXPERIMENTAL: This function is experimental and may change in the future.\nfunc (fs *FS) UnmountFrom(path string) error {\n\treturn unix.Unmount(path, 0)\n}\n\n// Source returns the source string used to create the filesystem.\nfunc (fs *FS) Source() string {\n\treturn fs.source\n}\n\n// FSType returns the filesystem type string.\nfunc (fs *FS) FSType() string {\n\treturn fs.fstype\n}\n"
  },
  {
    "path": "pkg/xfs/fsopen/fsopen_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\n// Package fsopen provides a simple interface to create and manage a filesystem\n// using the Linux syscalls for filesystem operations.\npackage fsopen\n"
  },
  {
    "path": "pkg/xfs/fsopen/options_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage fsopen\n\n// Option is a functional option for configuring a filesystem instance.\ntype Option struct {\n\tset func(*FS)\n}\n\n// WithSource adds a source to the filesystem configuration.\nfunc WithSource(source string) Option {\n\treturn Option{\n\t\tset: func(t *FS) {\n\t\t\tt.source = source\n\t\t},\n\t}\n}\n\n// WithMountFlags adds a flag set that will be passed to Fsmount syscall.\nfunc WithMountFlags(flag int) Option {\n\treturn Option{\n\t\tset: func(f *FS) {\n\t\t\tf.mntflags |= flag\n\t\t},\n\t}\n}\n\n// WithProjectQuota sets the project quota flag.\nfunc WithProjectQuota(enabled bool) Option {\n\treturn Option{\n\t\tset: func(t *FS) {\n\t\t\tif !enabled {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif t.boolParams == nil {\n\t\t\t\tt.boolParams = make(map[string]struct{})\n\t\t\t}\n\n\t\t\tt.boolParams[\"prjquota\"] = struct{}{}\n\t\t},\n\t}\n}\n\n// WithStringParameter adds a map of strings to the filesystem configuration.\nfunc WithStringParameter(param, value string) Option {\n\treturn Option{\n\t\tset: func(t *FS) {\n\t\t\tif t.stringParams == nil {\n\t\t\t\tt.stringParams = make(map[string][]string)\n\t\t\t}\n\n\t\t\tt.stringParams[param] = append(t.stringParams[param], value)\n\t\t},\n\t}\n}\n\n// WithBoolParameter adds a flag parameter to the filesystem configuration.\nfunc WithBoolParameter(param string) Option {\n\treturn Option{\n\t\tset: func(t *FS) {\n\t\t\tif t.boolParams == nil {\n\t\t\t\tt.boolParams = make(map[string]struct{})\n\t\t\t}\n\n\t\t\tt.boolParams[param] = struct{}{}\n\t\t},\n\t}\n}\n\n// WithBinaryParameters adds a map of byte arrays to the filesystem configuration.\nfunc WithBinaryParameters(param string, value []byte) Option {\n\treturn Option{\n\t\tset: func(t *FS) {\n\t\t\tif t.binaryParams == nil {\n\t\t\t\tt.binaryParams = make(map[string][][]byte)\n\t\t\t}\n\n\t\t\tt.binaryParams[param] = append(t.binaryParams[param], value)\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "pkg/xfs/fsopen_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage xfs_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n)\n\nfunc TestFsopen(t *testing.T) {\n\tt.Parallel()\n\n\tif uid := os.Getuid(); uid != 0 {\n\t\tt.Skipf(\"skipping test, not running as root (uid %d)\", uid)\n\t}\n\n\tfor _, tc := range []struct {\n\t\tfstype string\n\t\topts   []fsopen.Option\n\t}{\n\t\t{fstype: \"tmpfs\"},\n\t} {\n\t\tt.Run(tc.fstype, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\troot := &xfs.UnixRoot{FS: fsopen.New(tc.fstype, tc.opts...)}\n\n\t\t\terr := root.OpenFS()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tt.Cleanup(func() {\n\t\t\t\trequire.NoError(t, root.Close())\n\t\t\t})\n\n\t\t\ttestFilesystem(t, root, nil)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/xfs/helpers_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage xfs\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"syscall\"\n)\n\n// AsOSFile attempts to convert fs.File to *os.File.\nfunc AsOSFile(f fs.File, name string) (*os.File, error) {\n\tff, ok := f.(File)\n\tif !ok {\n\t\treturn nil, errors.ErrUnsupported\n\t}\n\n\tnewFd, err := syscall.Dup(int(ff.Fd()))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to duplicate file descriptor: %w\", err)\n\t}\n\n\treturn os.NewFile(uintptr(newFd), name), nil\n}\n"
  },
  {
    "path": "pkg/xfs/opentree/opentree_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\n// Package opentree provides a simple interface to create and manage a subfilesystem\n// using the `open_tree` syscall. It allows for creating a new subfilesystem\n// by cloning an existing filesystem tree and provides a method to close the filesystem\n// when it is no longer needed.\npackage opentree\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"golang.org/x/sys/unix\"\n\n\txfs \"github.com/siderolabs/talos/pkg/xfs\"\n)\n\n// FS represents a subfilesystem that can be created and managed.\n// It uses a file descriptor to represent the mounted filesystem and provides methods\n// to create and close the filesystem. The creation of the filesystem is idempotent,\n// meaning it can be called multiple times without side effects.\ntype FS struct {\n\troot   string\n\trootfd int\n\n\tmntfd int\n}\n\n// Interface guard.\nvar _ xfs.FS = (*FS)(nil)\n\n// NewFromPath creates a new fs instance from path.\nfunc NewFromPath(path string) *FS {\n\treturn &FS{\n\t\troot:   path,\n\t\trootfd: unix.AT_FDCWD,\n\t}\n}\n\n// NewFromFd creates a new fs instance from file descriptor.\nfunc NewFromFd(fd int) *FS {\n\treturn &FS{\n\t\trootfd: fd,\n\t}\n}\n\n// Open initializes the fs filesystem and returns the file descriptor for the mounted filesystem.\n// If the filesystem is already created, it returns the existing file descriptor.\n// This method is idempotent, meaning it can be called multiple times without side effects.\nfunc (fs *FS) Open() (int, error) {\n\tif fs.mntfd != 0 {\n\t\treturn fs.mntfd, nil\n\t}\n\n\tflags := unix.OPEN_TREE_CLONE | unix.OPEN_TREE_CLOEXEC\n\tif fs.root == \"\" {\n\t\tflags |= unix.AT_EMPTY_PATH\n\t}\n\n\terr := fs.new(uint(flags))\n\n\treturn fs.mntfd, err\n}\n\nfunc (fs *FS) new(flags uint) error {\n\tmntfd, err := unix.OpenTree(fs.rootfd, fs.root, flags)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unix.OpenTree on %q failed: %w\", fs.root, err)\n\t}\n\n\tfs.mntfd = mntfd\n\n\treturn nil\n}\n\n// Close closes the file descriptor.\nfunc (fs *FS) Close() error {\n\tif fs.mntfd == 0 {\n\t\treturn nil\n\t}\n\n\toldmntfd := fs.mntfd\n\tfs.mntfd = 0\n\n\treturn unix.Close(oldmntfd)\n}\n\n// Repair repairs the filesystem if needed.\n// This method is a no-op as the `open_tree` syscall does not support repair operations.\nfunc (fs *FS) Repair(context.Context) error {\n\treturn nil\n}\n\n// Source returns the source path of the filesystem.\nfunc (fs *FS) Source() string {\n\treturn fs.root\n}\n\n// FSType is no-op for opentree fs.\nfunc (fs *FS) FSType() string {\n\treturn \"\"\n}\n"
  },
  {
    "path": "pkg/xfs/opentree/opentree_other.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build !linux\n\n// Package opentree provides a simple interface to create and manage a subfilesystem\n// using the `open_tree` syscall. It allows for creating a new subfilesystem\n// by cloning an existing filesystem tree and provides a method to close the filesystem\n// when it is no longer needed.\npackage opentree\n"
  },
  {
    "path": "pkg/xfs/opentree_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage xfs_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/internal/app/machined/pkg/runtime\"\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n\t\"github.com/siderolabs/talos/pkg/xfs/fsopen\"\n\t\"github.com/siderolabs/talos/pkg/xfs/opentree\"\n)\n\nfunc TestOpentree(t *testing.T) {\n\tt.Parallel()\n\n\tif uid := os.Getuid(); uid != 0 {\n\t\tt.Skipf(\"skipping test, not running as root (uid %d)\", uid)\n\t}\n\n\tt.Run(\"TempDir\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRoot := t.TempDir()\n\n\t\troot := &xfs.UnixRoot{FS: opentree.NewFromPath(testRoot)}\n\n\t\terr := root.OpenFS()\n\t\trequire.NoError(t, err)\n\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, root.Close())\n\t\t})\n\n\t\ttestFilesystem(t, root, root)\n\t})\n\n\tt.Run(\"MountDir\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfs := fsopen.New(\"tmpfs\")\n\n\t\troRoot := &xfs.UnixRoot{FS: fs}\n\n\t\terr := roRoot.OpenFS()\n\t\trequire.NoError(t, err)\n\n\t\troRoot.Shadow, err = fs.MountAt(t.TempDir())\n\t\trequire.NoError(t, err)\n\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, roRoot.Close())\n\t\t\trequire.NoError(t, fs.UnmountFrom(roRoot.Shadow))\n\t\t})\n\n\t\tbfs := opentree.NewFromPath(roRoot.Shadow)\n\n\t\trwRoot := &xfs.UnixRoot{FS: bfs}\n\n\t\terr = rwRoot.OpenFS()\n\t\trequire.NoError(t, err)\n\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, rwRoot.Close())\n\t\t})\n\n\t\ttestFilesystem(t, rwRoot, roRoot)\n\t})\n\n\tt.Run(\"FileDescriptor\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tok, err := runtime.KernelCapabilities().OpentreeOnAnonymousFS()\n\t\trequire.NoError(t, err)\n\n\t\tif !ok {\n\t\t\tt.Skip(\"OpenTree on Anonymous FS requires kernel 6.15.0+\")\n\t\t}\n\n\t\troRoot := &xfs.UnixRoot{FS: fsopen.New(\"tmpfs\")}\n\n\t\terr = roRoot.OpenFS()\n\t\trequire.NoError(t, err)\n\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, roRoot.Close())\n\t\t})\n\n\t\tfd, err := roRoot.Fd()\n\t\trequire.NoError(t, err)\n\n\t\tbfs := opentree.NewFromFd(fd)\n\n\t\trwRoot := &xfs.UnixRoot{FS: bfs}\n\n\t\terr = rwRoot.OpenFS()\n\t\trequire.NoError(t, err)\n\n\t\ttestFilesystem(t, rwRoot, roRoot)\n\t})\n}\n"
  },
  {
    "path": "pkg/xfs/osroot.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage xfs\n\nimport (\n\t\"context\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\n// OSRoot represents a filesystem wrapper using os interface.\ntype OSRoot struct {\n\tShadow string\n}\n\n// Interface guard.\nvar _ interface {\n\tRoot\n} = (*OSRoot)(nil)\n\n// OpenFS is no-op for OSRoot.\nfunc (root *OSRoot) OpenFS() error {\n\treturn nil\n}\n\n// Close is no-op for OSRoot.\nfunc (root *OSRoot) Close() error {\n\treturn nil\n}\n\n// RepairFS is no-op for OSRoot.\nfunc (root *OSRoot) RepairFS(context.Context) error {\n\treturn nil\n}\n\n// Fd is no-op for OSRoot.\nfunc (root *OSRoot) Fd() (int, error) {\n\treturn 0, os.ErrInvalid\n}\n\n// Mkdir creates a new directory in the root filesystem with the specified name and permissions.\nfunc (root *OSRoot) Mkdir(name string, perm os.FileMode) error {\n\treturn os.Mkdir(filepath.Join(root.Shadow, name), perm)\n}\n\n// Open opens a file in the root filesystem with the specified name in read-only mode.\nfunc (root *OSRoot) Open(name string) (fs.File, error) {\n\treturn os.Open(filepath.Join(root.Shadow, name))\n}\n\n// OpenFile opens a file in the root filesystem with the specified name, flags, and permissions.\nfunc (root *OSRoot) OpenFile(name string, flags int, perm os.FileMode) (File, error) {\n\treturn os.OpenFile(filepath.Join(root.Shadow, name), flags, perm)\n}\n\n// Remove removes a file or directory from the root filesystem.\nfunc (root *OSRoot) Remove(name string) error {\n\treturn os.Remove(filepath.Join(root.Shadow, name))\n}\n\n// Rename renames a file or directory in the root filesystem from old to new.\nfunc (root *OSRoot) Rename(oldname, newname string) error {\n\treturn os.Rename(filepath.Join(root.Shadow, oldname), filepath.Join(root.Shadow, newname))\n}\n\n// Source returns the source of the underlying filesystem.\nfunc (root *OSRoot) Source() string {\n\treturn root.Shadow\n}\n\n// FSType returns the type of the underlying filesystem.\nfunc (root *OSRoot) FSType() string {\n\treturn \"os\"\n}\n"
  },
  {
    "path": "pkg/xfs/osroot_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage xfs_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\nfunc TestOs(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"OSRoot\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\troot := &xfs.OSRoot{Shadow: t.TempDir()}\n\n\t\trequire.NoError(t, root.OpenFS())\n\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, root.Close())\n\t\t})\n\n\t\ttestFilesystem(t, root, nil)\n\t})\n}\n"
  },
  {
    "path": "pkg/xfs/root.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package xfs provides an extended file system interface that includes\n// additional methods for writing files and directories, as well as utility\n// functions for reading, writing, and manipulating files and directories\n// within a specified file system.\npackage xfs\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"math/rand/v2\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// FS is an interface for creating file system handles.\ntype FS interface {\n\tOpen() (int, error)\n\tio.Closer\n\tRepair(context.Context) error\n\n\tSource() string\n\tFSType() string\n}\n\n// Root is an interface that extends the standard fs.FS interface with Write capabilities.\n//\n//nolint:interfacebloat\ntype Root interface {\n\tfs.FS\n\n\tio.Closer\n\tOpenFS() error\n\tRepairFS(context.Context) error\n\tFd() (int, error)\n\n\tMkdir(name string, perm os.FileMode) error\n\tOpenFile(name string, flags int, perm os.FileMode) (File, error)\n\tRemove(name string) error\n\tRename(oldname, newname string) error\n\n\tSource() string\n\tFSType() string\n}\n\n// File is an interface that extends the standard fs.File interface with additional methods for writing.\ntype File interface {\n\tfs.File\n\tio.Closer\n\tio.Reader\n\tio.ReaderAt\n\tio.Seeker\n\tio.Writer\n\tio.WriterAt\n\tFd() uintptr\n}\n\n// Interface guard.\nvar _ File = (*os.File)(nil)\n\n// ReadFile wraps fs.ReadFile to read a file from the specified FileSystem.\nfunc ReadFile(root Root, name string) ([]byte, error) {\n\treturn fs.ReadFile(root, name)\n}\n\n// ReadDir wraps fs.ReadDir to read a directory from the specified FileSystem.\nfunc ReadDir(root Root, name string) ([]fs.DirEntry, error) {\n\treturn fs.ReadDir(root, name)\n}\n\n// Stat wraps fs.Stat to get the file or directory information from the specified FileSystem.\nfunc Stat(root Root, name string) (fs.FileInfo, error) {\n\treturn fs.Stat(root, name)\n}\n\n// WriteFile is equivalent of os.WriteFile acting on specified FileSystem.\nfunc WriteFile(root Root, name string, data []byte, perm os.FileMode) error {\n\tf, err := root.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = f.Write(data)\n\tif err1 := f.Close(); err1 != nil && err == nil {\n\t\terr = err1\n\t}\n\n\treturn err\n}\n\n// Open wraps (FS).Open.\nfunc Open(root Root, name string) (fs.File, error) {\n\treturn root.Open(name)\n}\n\n// OpenFile wraps (FS).OpenFile.\nfunc OpenFile(root Root, name string, flags int, perm os.FileMode) (File, error) {\n\treturn root.OpenFile(name, flags, perm)\n}\n\n// Mkdir wraps (FS).Mkdir.\nfunc Mkdir(root Root, name string, perm os.FileMode) error {\n\treturn root.Mkdir(name, perm)\n}\n\n// MkdirAll is equivalent of os.MkdirAll acting on specified FileSystem.\nfunc MkdirAll(root Root, name string, perm os.FileMode) error {\n\tcomponents := SplitPath(name)\n\n\tfor i := range len(components) + 1 {\n\t\tdir := filepath.Join(components[:i]...)\n\t\tif dir == \"\" {\n\t\t\t// empty name, continue...\n\t\t\tcontinue\n\t\t}\n\n\t\terr := root.Mkdir(dir, perm)\n\t\tif err != nil && !errors.Is(err, fs.ErrExist) {\n\t\t\treturn fmt.Errorf(\"%w: %s\", err, dir)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// MkdirTemp creates a temporary directory in the specified directory with a given pattern.\nfunc MkdirTemp(root Root, dir, pattern string) (string, error) {\n\tif dir == \"\" {\n\t\tdir = os.TempDir()\n\t}\n\n\tif pattern == \"\" {\n\t\tpattern = \"tmp\"\n\t}\n\n\tif strings.Count(pattern, \"*\") > 1 {\n\t\treturn \"\", fmt.Errorf(\"pattern %q must contain at most one '*'\", pattern)\n\t}\n\n\tconst maxAttempts = 10000\n\n\tfor range maxAttempts {\n\t\tsuffix := strconv.Itoa(rand.Int())\n\n\t\tname := strings.Replace(pattern, \"*\", suffix, 1)\n\t\tif !strings.Contains(pattern, \"*\") {\n\t\t\tname = pattern + suffix\n\t\t}\n\n\t\ttempDir := filepath.Join(dir, name)\n\n\t\terr := MkdirAll(root, tempDir, 0o777)\n\t\tif err == nil {\n\t\t\treturn tempDir, nil\n\t\t}\n\n\t\tif errors.Is(err, fs.ErrExist) {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn \"\", err\n\t}\n\n\treturn \"\", fmt.Errorf(\"failed to create temporary directory after %d attempts\", maxAttempts)\n}\n\n// Remove wraps (FS).Remove.\nfunc Remove(root Root, name string) error {\n\treturn root.Remove(name)\n}\n\n// RemoveAll is equivalent of os.RemoveAll acting on specified FileSystem.\nfunc RemoveAll(root Root, name string) (err error) {\n\tvar f fs.File\n\n\tf, err = root.Open(name)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn err\n\t}\n\n\tstat, err := f.Stat()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := f.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif !stat.IsDir() {\n\t\treturn root.Remove(name)\n\t}\n\n\tentries, err := ReadDir(root, name)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, entry := range entries {\n\t\tchildPath := filepath.Join(name, entry.Name())\n\t\tif err := RemoveAll(root, childPath); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn root.Remove(name)\n}\n\n// Rename wraps (FS).Rename.\nfunc Rename(root Root, oldname, newname string) error {\n\treturn root.Rename(oldname, newname)\n}\n\n// SplitPath splits a path into its components, similar to filepath.Split but returns all parts.\nfunc SplitPath(path string) []string {\n\tvar parts []string\n\n\tfor {\n\t\tdir, file := filepath.Split(path)\n\t\tif file != \"\" {\n\t\t\tparts = append([]string{file}, parts...)\n\t\t}\n\n\t\tif dir == \"\" || dir == path {\n\t\t\tbreak\n\t\t}\n\n\t\tpath = filepath.Clean(dir)\n\t}\n\n\treturn parts\n}\n"
  },
  {
    "path": "pkg/xfs/root_linux.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n//go:build linux\n\npackage xfs\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"strings\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// UnixRoot represents a filesystem wrapper for Unix-like systems.\ntype UnixRoot struct {\n\tShadow string\n\tFS     FS\n\n\tmntfd int\n}\n\n// Interface guard.\nvar _ interface {\n\tRoot\n} = (*UnixRoot)(nil)\n\n// OpenFS opens the underlying filesystem.\nfunc (root *UnixRoot) OpenFS() error {\n\tvar err error\n\n\tif root.mntfd != 0 {\n\t\treturn nil\n\t}\n\n\troot.mntfd, err = root.FS.Open()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create root filesystem: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Close closes the underlying filesystem.\nfunc (root *UnixRoot) Close() error {\n\tif root.mntfd == 0 {\n\t\treturn nil\n\t}\n\n\troot.mntfd = 0\n\n\treturn root.FS.Close()\n}\n\n// RepairFS repairs the underlying filesystem if necessary.\nfunc (root *UnixRoot) RepairFS(ctx context.Context) error {\n\treturn root.FS.Repair(ctx)\n}\n\n// Fd returns the file descriptor of the mounted root filesystem.\n// It returns an error if the filesystem is not open or has been closed.\n// Usage of the returned file descriptior is no longer thread safe.\nfunc (root *UnixRoot) Fd() (int, error) {\n\tif root.mntfd == 0 {\n\t\treturn 0, os.ErrClosed\n\t}\n\n\treturn root.mntfd, nil\n}\n\n// Mkdir creates a new directory in the root filesystem with the specified name and permissions.\nfunc (root *UnixRoot) Mkdir(name string, perm os.FileMode) error {\n\treturn unix.Mkdirat(root.mntfd, strings.TrimLeft(name, \"/\"), uint32(perm))\n}\n\n// Open opens a file in the root filesystem with the specified name in read-only mode.\nfunc (root *UnixRoot) Open(name string) (fs.File, error) {\n\treturn root.OpenFile(strings.TrimLeft(name, \"/\"), unix.O_RDONLY, 0)\n}\n\n// OpenFile opens a file in the root filesystem with the specified name, flags, and permissions.\nfunc (root *UnixRoot) OpenFile(name string, flags int, perm os.FileMode) (File, error) {\n\tfd, err := unix.Openat(root.mntfd, strings.TrimLeft(name, \"/\"), flags, uint32(perm))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn os.NewFile(uintptr(fd), strings.TrimLeft(name, \"/\")), nil\n}\n\n// Remove removes a file or directory from the root filesystem.\nfunc (root *UnixRoot) Remove(name string) error {\n\tflags := 0\n\n\tinfo, err := root.stat(strings.TrimLeft(name, \"/\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif info.IsDir() {\n\t\tflags = unix.AT_REMOVEDIR\n\t}\n\n\treturn unix.Unlinkat(root.mntfd, strings.TrimLeft(name, \"/\"), flags)\n}\n\n// Rename renames a file or directory in the root filesystem from old to new.\nfunc (root *UnixRoot) Rename(oldname, newname string) error {\n\treturn unix.Renameat(root.mntfd, strings.TrimLeft(oldname, \"/\"), root.mntfd, strings.TrimLeft(newname, \"/\"))\n}\n\nfunc (root *UnixRoot) stat(name string) (os.FileInfo, error) {\n\tf, err := root.Open(strings.TrimLeft(name, \"/\"))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\treturn f.Stat()\n}\n\n// Source returns the source of the underlying filesystem.\nfunc (root *UnixRoot) Source() string {\n\treturn root.FS.Source()\n}\n\n// FSType returns the type of the underlying filesystem.\nfunc (root *UnixRoot) FSType() string {\n\treturn root.FS.FSType()\n}\n"
  },
  {
    "path": "pkg/xfs/root_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage xfs_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"github.com/siderolabs/talos/pkg/xfs\"\n)\n\nconst testDir = \"testdir\"\n\nvar testFileContent = []byte(\"test content\")\n\nfunc testFilesystem(t *testing.T, rwRoot xfs.Root, roRoot xfs.Root) {\n\tif roRoot == nil {\n\t\troRoot = rwRoot\n\t}\n\n\ttouchTree(t, rwRoot, filepath.Join(testDir, \"root.test\"))\n\n\tt.Run(\"Open\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"open.test\")\n\n\t\ttouchTree(t, rwRoot, name)\n\n\t\tactual, err := xfs.Open(rwRoot, name)\n\t\tassert.NoError(t, err)\n\t\tassert.NoError(t, actual.Close())\n\t})\n\n\tt.Run(\"OpenFile\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tflags := os.O_RDWR | os.O_CREATE\n\t\tname := filepath.Join(testDir, \"open-file.test\")\n\n\t\tactual, err := xfs.OpenFile(rwRoot, name, flags, 0o644)\n\t\trequire.NoError(t, err)\n\t\tassert.NoError(t, actual.Close())\n\t})\n\n\tt.Run(\"WriteFile\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"write-file.test\")\n\n\t\terr := xfs.WriteFile(rwRoot, name, testFileContent, 0o644)\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"ReadFile\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"read-file.test\")\n\n\t\twriteFile(t, rwRoot, name, testFileContent)\n\n\t\tactual, err := xfs.ReadFile(rwRoot, name)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, testFileContent, actual)\n\t})\n\n\tt.Run(\"Mkdir\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"mkdir.test\")\n\n\t\terr := xfs.Mkdir(rwRoot, name, 0o755)\n\t\tassert.NoError(t, err)\n\n\t\ttestIsDir(t, roRoot, name)\n\t})\n\n\tt.Run(\"MkdirAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"mkdir-all.d\", \"test.d\")\n\n\t\terr := xfs.MkdirAll(rwRoot, name, 0o755)\n\t\tassert.NoError(t, err)\n\n\t\tcomponents := xfs.SplitPath(name)\n\n\t\tfor i := range len(components) + 1 {\n\t\t\tdir := filepath.Join(components[:i]...)\n\t\t\tif dir == \"\" {\n\t\t\t\t// empty name, continue...\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttestIsDir(t, roRoot, dir)\n\t\t}\n\t})\n\n\tt.Run(\"MkdirTemp\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname, err := xfs.MkdirTemp(rwRoot, testDir, \"\")\n\t\tassert.NoError(t, err)\n\n\t\tcomponents := xfs.SplitPath(name)\n\n\t\tfor i := range len(components) + 1 {\n\t\t\tdir := filepath.Join(components[:i]...)\n\t\t\tif dir == \"\" {\n\t\t\t\t// empty name, continue...\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttestIsDir(t, roRoot, dir)\n\t\t}\n\t})\n\n\tt.Run(\"Remove\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"remove.test\")\n\n\t\ttouchTree(t, rwRoot, name)\n\n\t\terr := xfs.Remove(rwRoot, name)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = xfs.Stat(roRoot, name)\n\t\trequire.ErrorIs(t, err, os.ErrNotExist)\n\t})\n\n\tt.Run(\"RemoveAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"remove-all.d\", \"file.test\")\n\n\t\ttouchTree(t, rwRoot, name)\n\n\t\tcomponents := xfs.SplitPath(name)\n\n\t\terr := xfs.RemoveAll(rwRoot, filepath.Join(components[:2]...))\n\t\trequire.NoError(t, err)\n\n\t\tfor i := range len(components[1:]) {\n\t\t\ttest := filepath.Join(components[:len(components)-i]...)\n\t\t\tif test == \"\" {\n\t\t\t\t// empty name, continue...\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t_, err := xfs.Stat(roRoot, test)\n\t\t\trequire.ErrorIs(t, err, os.ErrNotExist, \"stat %q should not exist\", test)\n\t\t}\n\t})\n\n\tt.Run(\"Stat\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tname := filepath.Join(testDir, \"stat.d\", \"stat.test\")\n\n\t\ttouchTree(t, rwRoot, name)\n\n\t\tcomponents := xfs.SplitPath(name)\n\n\t\tfor i := range components {\n\t\t\tdir := filepath.Join(components[:i]...)\n\t\t\tif dir == \"\" {\n\t\t\t\t// empty name, continue...\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tactual, err := xfs.Stat(roRoot, dir)\n\t\t\trequire.NoError(t, err, \"stat dir %q failed\", dir)\n\t\t\tassert.True(t, actual.IsDir())\n\t\t}\n\n\t\tactual, err := xfs.Stat(roRoot, name)\n\t\trequire.NoError(t, err, \"stat file %q failed\", name)\n\t\tassert.False(t, actual.IsDir())\n\t})\n\n\tt.Run(\"Rename\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"Dir\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\toldName := filepath.Join(testDir, \"rename.old.d\", \"test\")\n\t\t\tnewName := filepath.Join(testDir, \"rename.new.d\", \"test\")\n\n\t\t\ttouchTree(t, rwRoot, oldName)\n\n\t\t\terr := xfs.Rename(rwRoot, filepath.Dir(oldName), filepath.Dir(newName))\n\t\t\tassert.NoError(t, err)\n\n\t\t\tnewDirStat, err := xfs.Stat(roRoot, filepath.Dir(newName))\n\t\t\trequire.NoError(t, err, \"stat dir %q failed\", filepath.Dir(newName))\n\t\t\tassert.True(t, newDirStat.IsDir())\n\n\t\t\t_, err = xfs.Stat(roRoot, newName)\n\t\t\trequire.NoError(t, err, \"stat file %q failed\", newName)\n\n\t\t\t_, err = xfs.Stat(roRoot, oldName)\n\t\t\trequire.ErrorIs(t, err, os.ErrNotExist, \"stat dir %q failed\", filepath.Dir(oldName))\n\t\t})\n\n\t\tt.Run(\"File\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\toldName := filepath.Join(testDir, \"rename.old.test\")\n\t\t\tnewName := filepath.Join(testDir, \"rename.new.test\")\n\n\t\t\ttouchTree(t, rwRoot, oldName)\n\n\t\t\terr := xfs.Rename(rwRoot, oldName, newName)\n\t\t\tassert.NoError(t, err)\n\n\t\t\t_, err = xfs.Stat(roRoot, newName)\n\t\t\trequire.NoError(t, err, \"stat file %q failed\", newName)\n\n\t\t\t_, err = xfs.Stat(roRoot, oldName)\n\t\t\trequire.ErrorIs(t, err, os.ErrNotExist, \"stat file %q failed\", oldName)\n\t\t})\n\t})\n}\n\nfunc writeFile(tb testing.TB, root xfs.Root, name string, content []byte) {\n\ttb.Helper()\n\n\terr := xfs.WriteFile(root, name, content, 0o644)\n\trequire.NoError(tb, err)\n}\n\nfunc touchTree(tb testing.TB, root xfs.Root, tree string) {\n\ttb.Helper()\n\n\tcomponents := xfs.SplitPath(tree)\n\n\tfor i := range components {\n\t\tdir := filepath.Join(components[:i]...)\n\t\tif dir == \"\" {\n\t\t\t// empty name, continue...\n\t\t\tcontinue\n\t\t}\n\n\t\terr := root.Mkdir(dir, 0o755)\n\t\tif os.IsExist(err) {\n\t\t\tcontinue\n\t\t}\n\n\t\trequire.NoError(tb, err, \"creating dir %q failed\", dir)\n\t}\n\n\tf, err := root.OpenFile(tree, os.O_CREATE|os.O_TRUNC, 0o644)\n\trequire.NoError(tb, err, \"creating tree %q failed\", tree)\n\n\ttb.Cleanup(func() {\n\t\tassert.NoError(tb, f.Close(), \"closing file %q failed\", tree)\n\t})\n}\n\nfunc testIsDir(tb testing.TB, root xfs.Root, name string) {\n\tactual, err := root.Open(name)\n\trequire.NoError(tb, err, \"opening %q failed\", name)\n\n\ttb.Cleanup(func() {\n\t\tassert.NoError(tb, actual.Close(), \"closing %q failed\", name)\n\t})\n\n\tinfo, err := actual.Stat()\n\trequire.NoError(tb, err, \"stat on %q failed\", name)\n\tassert.True(tb, info.IsDir())\n}\n"
  },
  {
    "path": "tools/docgen/go.mod",
    "content": "module github.com/siderolabs/talos/tools/docgen\n\ngo 1.26.0\n\nrequire (\n\tgithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab\n\tgithub.com/invopop/jsonschema v0.13.0\n\tgithub.com/microcosm-cc/bluemonday v1.0.27\n\tgithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2\n\tgithub.com/siderolabs/gen v0.8.6\n\tgithub.com/wk8/go-ordered-map/v2 v2.1.8\n\tgo.yaml.in/yaml/v4 v4.0.0-rc.4\n\tmvdan.cc/gofumpt v0.9.2\n)\n\nrequire (\n\tgithub.com/aymerick/douceur v0.2.0 // indirect\n\tgithub.com/bahlo/generic-list-go v0.2.0 // indirect\n\tgithub.com/buger/jsonparser v1.1.1 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/gorilla/css v1.0.1 // indirect\n\tgithub.com/mailru/easyjson v0.7.7 // indirect\n\tgolang.org/x/net v0.46.0 // indirect\n\tgolang.org/x/text v0.30.0 // indirect\n\tgolang.org/x/tools v0.38.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "tools/docgen/go.sum",
    "content": "github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=\ngithub.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=\ngithub.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=\ngithub.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=\ngithub.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=\ngithub.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=\ngithub.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=\ngithub.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=\ngithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=\ngithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=\ngithub.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=\ngithub.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=\ngithub.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=\ngithub.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=\ngithub.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=\ngithub.com/siderolabs/gen v0.8.6 h1:pE6shuqov3L+5rEcAUJ/kY6iJofimljQw5G95P8a5c4=\ngithub.com/siderolabs/gen v0.8.6/go.mod h1:J9IbusbES2W6QWjtSHpDV9iPGZHc978h1+KJ4oQRspQ=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=\ngolang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=\ngolang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=\ngolang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=\ngolang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=\ngolang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=\ngolang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nmvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4=\nmvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s=\n"
  },
  {
    "path": "tools/docgen/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"log\"\n\t\"maps\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/siderolabs/gen/xslices\"\n\n\t\"go.yaml.in/yaml/v4\"\n\t\"mvdan.cc/gofumpt/format\"\n)\n\nvar tpl = `// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Code generated by hack/docgen tool. DO NOT EDIT.\n\npackage {{ .Package }}\n\nimport (\n\t\"github.com/siderolabs/talos/pkg/machinery/config/encoder\"\n)\n\n{{ $tick := \"` + \"`\" + `\" -}}\n\n{{ range $struct := .Structs -}}\nfunc ({{ $struct.Name }}) Doc() *encoder.Doc {\n\tdoc := &encoder.Doc{\n\t\tType : \"{{ if $struct.Text.Alias }}{{ $struct.Text.Alias}}{{ else }}{{ $struct.Name }}{{ end }}\",\n\t\tComments: [3]string{ \"\" /* encoder.HeadComment */, \"{{ $struct.Text.Comment }}\" /* encoder.LineComment */,  \"\" /* encoder.FootComment */},\n\t\tDescription: \"{{ $struct.Text.Description }}\",\n\t\t{{ if $struct.AppearsIn -}}\n\t\tAppearsIn: []encoder.Appearance{\n\t\t{{ range $value := $struct.AppearsIn -}}\n\t\t\t{\n\t\t\t\tTypeName: \"{{ $value.Struct.Name }}\",\n\t\t\t\tFieldName: \"{{ $value.FieldName }}\",\n\t\t\t},\n\t\t{{ end -}}\n\t\t},\n\t\t{{ end -}}\n\t\tFields: []encoder.Doc{\n\t\t\t{{ range $index, $field := $struct.Fields -}}\n\t\t\t\t{{ if $field.Tag -}}\n\t\t\t\t\t{\n\t\t\t\t\t  Name: \"{{ $field.Tag }}\",\n\t\t\t\t\t  Type: \"{{ $field.Type }}\",\n\t\t\t\t\t  Note: \"{{ $field.Note }}\",\n\t\t\t\t\t  Description: \"{{ $field.Text.Description }}\",\n\t\t\t\t\t  Comments: [3]string{ \"\" /* encoder.HeadComment */, \"{{ $field.Text.Comment }}\" /* encoder.LineComment */,  \"\" /* encoder.FootComment */},\n\t  \t\t\t\t  {{ if $field.Text.Values -}}\n\t\t\t\t\t  Values : []string{\n\t\t\t\t\t\t{{ range $value := $field.Text.Values -}}\n\t\t\t\t\t\t\t\"{{ $value }}\",\n\t\t\t\t\t\t{{ end -}}\n\t\t\t\t\t  },\n\t\t\t\t\t  {{ end -}}\n\t\t\t\t\t},\n\t\t\t\t{{ else if $field.Inline -}}\n\t\t\t\t\t{\n\t\t\t\t\t  Type: \"{{ $field.Type }}\",\n\t\t\t\t\t  Inline: true,\n\t\t\t\t\t},\n\t\t\t\t{{ else -}}\n\t\t\t\t\t{},\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\n\t\t},\n\t}\n\n\t{{ range $example := $struct.Text.Examples }}\n\t{{ if $example.Value }}\n\tdoc.AddExample(\"{{ $example.Name }}\", {{ $example.Value }})\n\t{{ end -}}\n\t{{ end }}\n\n\t{{ range $index, $field := $struct.Fields -}}\n\t\t{{ if $field.Tag -}}\n\t\t\t{{ if $field.Text.Examples -}}\n\t\t\t\t{{ range $example := $field.Text.Examples -}}\n\t\t\t\t\t{{- if $example.Value }}\n\t\t\t\t\t\tdoc.Fields[{{ $index }}].AddExample(\"{{ $example.Name }}\", {{ $example.Value }})\n\t\t\t\t\t{{- end }}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t{{- end }}\n\n\n\treturn doc\n}\n{{ end -}}\n\n// GetFileDoc returns documentation for the file {{ .File }}.\nfunc GetFileDoc() *encoder.FileDoc {\n\treturn &encoder.FileDoc{\n\t\tName: \"{{ .Name }}\",\n\t\tDescription: \"{{ .Header }}\",\n\t\tStructs: []*encoder.Doc{\n\t\t\t{{ range $struct := .Structs -}}\n\t\t\t{{ $struct.Name }}{}.Doc(),\n\t\t\t{{ end -}}\n\t\t},\n\t}\n}\n`\n\ntype Doc struct {\n\tName    string\n\tPackage string\n\tTitle   string\n\tHeader  string\n\tFile    string\n\tStructs []*Struct\n}\n\ntype Struct struct {\n\tName      string\n\tText      *Text\n\tFields    []*Field\n\tAppearsIn []Appearance\n}\n\ntype Appearance struct {\n\tStruct    *Struct\n\tFieldName string\n}\n\ntype Example struct {\n\tName  string `yaml:\"name\"`\n\tValue string `yaml:\"value\"`\n}\n\ntype Field struct {\n\tName    string\n\tType    string\n\tTypeRef string\n\tText    *Text\n\tTag     string\n\tNote    string\n\tInline  bool\n}\n\ntype Text struct {\n\tComment        string         `json:\"-\"`\n\tDescription    string         `json:\"description\"`\n\tExamples       []*Example     `json:\"examples\"`\n\tAlias          string         `json:\"alias\"`\n\tValues         []string       `json:\"values\"`\n\tSchema         *SchemaWrapper `json:\"schema\"`\n\tSchemaRoot     bool           `json:\"schemaRoot\" yaml:\"schemaRoot\"`\n\tSchemaRequired bool           `json:\"schemaRequired\" yaml:\"schemaRequired\"`\n\tSchemaMeta     string         `json:\"schemaMeta\" yaml:\"schemaMeta\"`\n}\n\nfunc in(p string) (string, error) {\n\treturn filepath.Abs(p)\n}\n\nfunc out(p string) (*os.File, error) {\n\tabs, err := filepath.Abs(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn os.Create(abs)\n}\n\ntype packageType struct {\n\tname    string\n\tdoc     string\n\tfile    string\n\tstructs []*structType\n}\n\ntype structType struct {\n\tname string\n\ttext *Text\n\tpos  token.Pos\n\tnode *ast.StructType\n}\n\ntype aliasType struct {\n\tfieldType    string\n\tfieldTypeRef string\n}\n\nfunc collectStructs(node ast.Node) ([]*structType, map[string]aliasType) {\n\tvar structs []*structType\n\n\taliases := map[string]aliasType{}\n\n\tcollectStructs := func(n ast.Node) bool {\n\t\tg, ok := n.(*ast.GenDecl)\n\t\tif !ok {\n\t\t\treturn true\n\t\t}\n\n\t\tisAlias := false\n\n\t\tif g.Doc != nil {\n\t\t\tfor _, comment := range g.Doc.List {\n\t\t\t\tif strings.Contains(comment.Text, \"docgen:nodoc\") {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\tif strings.Contains(comment.Text, \"docgen:alias\") {\n\t\t\t\t\tisAlias = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, spec := range g.Specs {\n\t\t\tt, ok := spec.(*ast.TypeSpec)\n\t\t\tif !ok {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tif t.Type == nil {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tx, ok := t.Type.(*ast.StructType)\n\t\t\tif !ok {\n\t\t\t\tif isAlias {\n\t\t\t\t\taliases[t.Name.Name] = aliasType{\n\t\t\t\t\t\tfieldType:    formatFieldType(t.Type),\n\t\t\t\t\t\tfieldTypeRef: getFieldType(t.Type),\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tstructName := t.Name.Name\n\n\t\t\ttext := &Text{}\n\n\t\t\tif t.Doc != nil {\n\t\t\t\ttext = parseComment([]byte(t.Doc.Text()))\n\t\t\t} else if g.Doc != nil {\n\t\t\t\ttext = parseComment([]byte(g.Doc.Text()))\n\t\t\t}\n\n\t\t\ts := &structType{\n\t\t\t\tname: structName,\n\t\t\t\ttext: text,\n\t\t\t\tnode: x,\n\t\t\t\tpos:  x.Pos(),\n\t\t\t}\n\n\t\t\tstructs = append(structs, s)\n\t\t}\n\n\t\treturn true\n\t}\n\n\tast.Inspect(node, collectStructs)\n\n\treturn structs, aliases\n}\n\nfunc parseComment(comment []byte) *Text {\n\ttext := &Text{}\n\tif err := yaml.Unmarshal(comment, text); err != nil {\n\t\tlines := strings.Split(string(comment), \"\\n\")\n\t\tfor i := range lines {\n\t\t\tlines[i] = strings.TrimLeft(lines[i], \"\\t\")\n\t\t}\n\n\t\t// not yaml, fallback\n\t\ttext.Description = strings.Join(lines, \"\\n\")\n\t\t// take only the first line from the Description for the comment\n\t\ttext.Comment = lines[0]\n\n\t\toldDescription := text.Description\n\n\t\t// try to parse everything except for the first line as yaml\n\t\tif err = yaml.Unmarshal([]byte(strings.Join(lines[1:], \"\\n\")), text); err == nil {\n\t\t\t// if parsed, remove it from the description\n\t\t\tif text.Description != oldDescription {\n\t\t\t\t// something got parsed\n\t\t\t\ttext.Description = text.Comment + \"\\n\" + text.Description\n\t\t\t} else {\n\t\t\t\t// nothing got parsed\n\t\t\t\ttext.Description = text.Comment\n\t\t\t}\n\t\t}\n\t} else {\n\t\ttext.Description = strings.TrimSpace(text.Description)\n\t\t// take only the first line from the Description for the comment\n\t\ttext.Comment = strings.Split(text.Description, \"\\n\")[0]\n\t}\n\n\ttext.Comment = escape(text.Comment)\n\n\ttext.Description = escape(text.Description)\n\tfor _, example := range text.Examples {\n\t\texample.Name = escape(example.Name)\n\t\texample.Value = strings.TrimSpace(example.Value)\n\t}\n\n\treturn text\n}\n\nfunc getFieldType(p any) string {\n\tif m, ok := p.(*ast.MapType); ok {\n\t\treturn getFieldType(m.Value)\n\t}\n\n\tswitch t := p.(type) {\n\tcase *ast.Ident:\n\t\treturn t.Name\n\tcase *ast.ArrayType:\n\t\treturn getFieldType(p.(*ast.ArrayType).Elt)\n\tcase *ast.StarExpr:\n\t\treturn getFieldType(t.X)\n\tcase *ast.SelectorExpr:\n\t\treturn getFieldType(t.Sel)\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc formatFieldType(p any) string {\n\tif m, ok := p.(*ast.MapType); ok {\n\t\treturn fmt.Sprintf(\"map[%s]%s\", formatFieldType(m.Key), formatFieldType(m.Value))\n\t}\n\n\tswitch t := p.(type) {\n\tcase *ast.Ident:\n\t\treturn t.Name\n\tcase *ast.ArrayType:\n\t\treturn \"[]\" + formatFieldType(p.(*ast.ArrayType).Elt)\n\tcase *ast.StructType:\n\t\treturn \"struct\"\n\tcase *ast.StarExpr:\n\t\treturn formatFieldType(t.X)\n\tcase *ast.SelectorExpr:\n\t\treturn formatFieldType(t.Sel)\n\tdefault:\n\t\tlog.Printf(\"unknown: %#v\", t)\n\n\t\treturn \"\"\n\t}\n}\n\nfunc escape(value string) string {\n\tvalue = strings.ReplaceAll(value, `\"`, `\\\"`)\n\tvalue = strings.ReplaceAll(value, \"\\n\", `\\n`)\n\n\treturn strings.TrimSpace(value)\n}\n\nfunc collectFields(s *structType, aliases map[string]aliasType) (fields []*Field) {\n\tfields = []*Field{}\n\n\tfor _, f := range s.node.Fields.List {\n\t\tif f.Names == nil {\n\t\t\t// This is an embedded struct.\n\t\t\tif f.Tag != nil && reflect.StructTag(strings.Trim(f.Tag.Value, \"`\")).Get(\"yaml\") == \",inline\" {\n\t\t\t\tfields = append(fields, &Field{\n\t\t\t\t\tType:    formatFieldType(f.Type),\n\t\t\t\t\tTypeRef: getFieldType(f.Type),\n\t\t\t\t\tInline:  true,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfields = append(fields, &Field{Type: \"unknown\"})\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\tname := f.Names[0].Name\n\n\t\tif f.Doc == nil {\n\t\t\tlog.Fatalf(\"field %q is missing a documentation\", name)\n\t\t}\n\n\t\tif strings.Contains(f.Doc.Text(), \"docgen:nodoc\") {\n\t\t\tfields = append(fields, &Field{Type: \"unknown\"})\n\n\t\t\tcontinue\n\t\t}\n\n\t\tif f.Tag == nil {\n\t\t\tlog.Fatalf(\"field %q is missing a tag\", name)\n\t\t}\n\n\t\tfieldType := formatFieldType(f.Type)\n\n\t\tif alias, ok := aliases[fieldType]; ok {\n\t\t\tfieldType = alias.fieldType\n\t\t}\n\n\t\tfieldTypeRef := getFieldType(f.Type)\n\n\t\tif alias, ok := aliases[fieldTypeRef]; ok {\n\t\t\tfieldTypeRef = alias.fieldTypeRef\n\t\t}\n\n\t\ttag := reflect.StructTag(strings.Trim(f.Tag.Value, \"`\"))\n\t\tyamlTag := tag.Get(\"yaml\")\n\t\tyamlTag = strings.Split(yamlTag, \",\")[0]\n\n\t\tif yamlTag == \"\" {\n\t\t\tlog.Fatalf(\"field %q is missing a `yaml` tag or name in it\", name)\n\t\t}\n\n\t\ttext := parseComment([]byte(f.Doc.Text()))\n\n\t\tfield := &Field{\n\t\t\tName:    name,\n\t\t\tTag:     yamlTag,\n\t\t\tType:    fieldType,\n\t\t\tTypeRef: fieldTypeRef,\n\t\t\tText:    text,\n\t\t}\n\n\t\tif f.Comment != nil {\n\t\t\tfield.Note = escape(f.Comment.Text())\n\t\t}\n\n\t\tfields = append(fields, field)\n\t}\n\n\treturn fields\n}\n\nfunc renderDoc(doc *Doc, dest string) {\n\tt := template.Must(template.New(\"docfile.tpl\").Parse(tpl))\n\tbuf := bytes.Buffer{}\n\n\terr := t.Execute(&buf, doc)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to render template: %v\", err)\n\t}\n\n\tformatted, err := format.Source(buf.Bytes(), format.Options{})\n\tif err != nil {\n\t\tlog.Printf(\"data: %s\", buf.Bytes())\n\t\tlog.Fatalf(\"failed to format source: %v\", err)\n\t}\n\n\tout, err := out(dest)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to create output file: %v\", err)\n\t}\n\tdefer out.Close()\n\n\t_, err = out.Write(formatted)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to write output file: %v\", err)\n\t}\n}\n\nfunc processFiles(inputFiles []string, outputFile, schemaOutputFile, versionTagFile string) {\n\tvar packageNames []string\n\n\tpackageNameToType := map[string]*packageType{}\n\taliases := map[string]aliasType{}\n\n\tfor _, inputFile := range inputFiles {\n\t\tabs, err := in(inputFile)\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\n\t\tlog.Printf(\"creating package file set: %q\", abs)\n\n\t\tfset := token.NewFileSet()\n\n\t\tnode, err := parser.ParseFile(fset, abs, nil, parser.ParseComments)\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\n\t\tpackageName := node.Name.Name\n\n\t\tif _, ok := packageNameToType[packageName]; !ok {\n\t\t\tpackageNameToType[packageName] = &packageType{\n\t\t\t\tname: packageName,\n\t\t\t\tfile: outputFile,\n\t\t\t}\n\n\t\t\tpackageNames = append(packageNames, packageName)\n\t\t}\n\n\t\tpkg := packageNameToType[packageName]\n\n\t\tif node.Doc != nil && node.Doc.Text() != \"\" {\n\t\t\tpkg.doc = node.Doc.Text()\n\t\t}\n\n\t\ttokenFile := fset.File(node.Pos())\n\t\tif tokenFile == nil {\n\t\t\tlog.Fatalf(\"No token\")\n\t\t}\n\n\t\tlog.Printf(\"parsing file in package %q: %s\", packageName, tokenFile.Name())\n\n\t\tfileStructs, fileAliases := collectStructs(node)\n\n\t\tpkg.structs = append(pkg.structs, fileStructs...)\n\n\t\tmaps.Copy(aliases, fileAliases)\n\t}\n\n\tslices.Sort(packageNames)\n\n\tdocs := xslices.Map(packageNames, func(name string) *Doc {\n\t\treturn packageToDoc(packageNameToType[name], aliases)\n\t})\n\n\tif schemaOutputFile != \"\" {\n\t\trenderSchema(docs, schemaOutputFile, versionTagFile)\n\t}\n\n\tif outputFile == \"\" {\n\t\treturn\n\t}\n\n\tif len(docs) != 1 {\n\t\tlog.Fatalf(\"expected exactly one package to generate docs, got %d\", len(docs))\n\t}\n\n\trenderDoc(docs[0], outputFile)\n}\n\nfunc packageToDoc(pkg *packageType, aliases map[string]aliasType) *Doc {\n\tif len(pkg.structs) == 0 {\n\t\tlog.Fatalf(\"failed to find types that could be documented in %v (package %v)\", pkg.file, pkg.name)\n\t}\n\n\tdoc := &Doc{\n\t\tPackage: pkg.name,\n\t\tStructs: []*Struct{},\n\t}\n\n\textraExamples := map[string][]*Example{}\n\tbackReferences := map[string][]Appearance{}\n\n\tfor _, s := range pkg.structs {\n\t\tlog.Printf(\"generating docs for type: %q\", s.name)\n\n\t\tfields := collectFields(s, aliases)\n\n\t\ts := &Struct{\n\t\t\tName:   s.name,\n\t\t\tText:   s.text,\n\t\t\tFields: fields,\n\t\t}\n\n\t\tfor _, field := range fields {\n\t\t\tif field.TypeRef == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif field.Text != nil && len(field.Text.Examples) > 0 {\n\t\t\t\textraExamples[field.TypeRef] = append(extraExamples[field.TypeRef], field.Text.Examples...)\n\t\t\t}\n\n\t\t\tbackReferences[field.TypeRef] = append(backReferences[field.TypeRef], Appearance{\n\t\t\t\tStruct:    s,\n\t\t\t\tFieldName: field.Tag,\n\t\t\t})\n\t\t}\n\n\t\tdoc.Structs = append(doc.Structs, s)\n\t}\n\n\tfor _, s := range doc.Structs {\n\t\tif s.Text.Alias != \"\" {\n\t\t\ts.Text.Description = strings.ReplaceAll(s.Text.Description, s.Name, s.Text.Alias)\n\t\t\ts.Text.Comment = strings.ReplaceAll(s.Text.Comment, s.Name, s.Text.Alias)\n\t\t}\n\n\t\tif extra, ok := extraExamples[s.Name]; ok {\n\t\t\ts.Text.Examples = append(s.Text.Examples, extra...)\n\t\t}\n\n\t\tif ref, ok := backReferences[s.Name]; ok {\n\t\t\ts.AppearsIn = append(s.AppearsIn, ref...)\n\t\t}\n\t}\n\n\tdoc.Package = pkg.name\n\tdoc.Name = doc.Package\n\tdoc.Header = escape(pkg.doc)\n\n\tdoc.File = pkg.file\n\n\treturn doc\n}\n\nfunc sourcesWithJSONSchema(dir string) []string {\n\tvar sources []string\n\n\tif err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() || !strings.HasSuffix(info.Name(), \".go\") {\n\t\t\treturn nil\n\t\t}\n\n\t\tfileBytes, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif strings.Contains(string(fileBytes), \"//docgen:jsonschema\") {\n\t\t\tsources = append(sources, path)\n\t\t}\n\n\t\treturn nil\n\t}); err != nil {\n\t\tlog.Fatalf(\"failed to walk directory %q: %v\", dir, err)\n\t}\n\n\treturn sources\n}\n\nfunc determineFiles(generateSchemaFromDir string, args []string) []string {\n\tif generateSchemaFromDir != \"\" {\n\t\tif len(args) > 0 {\n\t\t\tlog.Fatalf(\"cannot specify both -generate-schema-from-dir and input files as args\")\n\t\t}\n\n\t\tfiles := sourcesWithJSONSchema(generateSchemaFromDir)\n\n\t\tif len(files) == 0 {\n\t\t\tlog.Fatalf(\"no Go files annotated with //docgen:jsonschema found in %q\", generateSchemaFromDir)\n\t\t}\n\n\t\treturn files\n\t}\n\n\tif len(args) == 0 {\n\t\tlog.Fatalf(\"no input files\")\n\t}\n\n\treturn args\n}\n\nfunc main() {\n\toutputFile := flag.String(\"output\", \"\", \"output file name\")\n\tjsonSchemaOutputFile := flag.String(\"json-schema-output\", \"\", \"output file name for json schema\")\n\tversionTagFile := flag.String(\"version-tag-file\", \"\", \"file name for version tag\")\n\tgenerateSchemaFromDir := flag.String(\"generate-schema-from-dir\", \"\", \"generate a JSON schema by recursively parsing the sources in the specified directory\")\n\n\tflag.Parse()\n\n\tfiles := determineFiles(*generateSchemaFromDir, flag.Args())\n\n\tprocessFiles(files, *outputFile, *jsonSchemaOutputFile, *versionTagFile)\n}\n"
  },
  {
    "path": "tools/docgen/main_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n)\n\n// This test exists mainly for easier debugging with debugger.\nfunc TestProcessFile(t *testing.T) {\n\tinputFile := filepath.Join(\"..\", \"..\", \"pkg\", \"machinery\", \"config\", \"types\", \"v1alpha1\", \"v1alpha1_types.go\")\n\toutputFile := filepath.Join(t.TempDir(), \"out.go\")\n\tschemaOutputFile := filepath.Join(t.TempDir(), \"out.schema.json\")\n\tversionTagFile := filepath.Join(\"..\", \"..\", \"pkg\", \"machinery\", \"gendata\", \"data\", \"tag\")\n\tprocessFiles([]string{inputFile}, outputFile, schemaOutputFile, versionTagFile)\n}\n"
  },
  {
    "path": "tools/docgen/schema.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/gomarkdown/markdown\"\n\t\"github.com/gomarkdown/markdown/html\"\n\t\"github.com/invopop/jsonschema\"\n\t\"github.com/microcosm-cc/bluemonday\"\n\tvalidatejsonschema \"github.com/santhosh-tekuri/jsonschema/v6\"\n\torderedmap \"github.com/wk8/go-ordered-map/v2\"\n)\n\nconst ConfigSchemaURLFormat = \"https://talos.dev/%s/schemas/%s\"\n\n// SchemaWrapper wraps jsonschema.Schema to provide correct YAML unmarshalling using its internal JSON marshaller.\ntype SchemaWrapper struct {\n\tjsonschema.Schema\n}\n\n// UnmarshalYAML unmarshals the schema from YAML.\n//\n// This converts the YAML that was read from the comments to JSON,\n// then uses the custom JSON unmarshaler of the wrapped Schema.\nfunc (t *SchemaWrapper) UnmarshalYAML(unmarshal func(any) error) error {\n\tvar data map[string]any\n\n\terr := unmarshal(&data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tjsonBytes, err := json.Marshal(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn t.UnmarshalJSON(jsonBytes)\n}\n\ntype SchemaTypeInfo struct {\n\ttypeName string\n\tref      string\n}\n\ntype SchemaDefinitionInfo struct {\n\ttypeInfo           SchemaTypeInfo\n\tarrayItemsTypeInfo *SchemaTypeInfo\n\tmapValueTypeInfo   *SchemaTypeInfo\n\tenumValues         []any\n}\n\nfunc goTypeToTypeInfo(pkg, goType string) *SchemaTypeInfo {\n\tswitch goType {\n\tcase \"string\":\n\t\treturn &SchemaTypeInfo{typeName: \"string\"}\n\tcase \"int\", \"int8\", \"int16\", \"int32\", \"int64\", \"uint\", \"uint8\", \"uint16\", \"uint32\", \"uint64\":\n\t\treturn &SchemaTypeInfo{typeName: \"integer\"}\n\tcase \"bool\":\n\t\treturn &SchemaTypeInfo{typeName: \"boolean\"}\n\tdefault:\n\t\treturn &SchemaTypeInfo{ref: \"#/$defs/\" + pkg + \".\" + goType}\n\t}\n}\n\nfunc fieldToDefinitionInfo(pkg string, field *Field) SchemaDefinitionInfo {\n\tgoType := field.Type\n\n\tif field.Text != nil {\n\t\t// skip enumifying boolean fields so that we don't pick up the \"on\", \"off\", \"yes\", \"no\" from the values\n\t\tif goType != \"bool\" && field.Text.Values != nil {\n\t\t\tenumValues := make([]any, 0, len(field.Text.Values))\n\n\t\t\tfor _, val := range field.Text.Values {\n\t\t\t\tenumValues = append(enumValues, val)\n\t\t\t}\n\n\t\t\treturn SchemaDefinitionInfo{enumValues: enumValues}\n\t\t}\n\t}\n\n\tif strings.HasPrefix(goType, \"[]\") {\n\t\treturn SchemaDefinitionInfo{\n\t\t\ttypeInfo:           SchemaTypeInfo{typeName: \"array\"},\n\t\t\tarrayItemsTypeInfo: goTypeToTypeInfo(pkg, strings.TrimPrefix(goType, \"[]\")),\n\t\t}\n\t}\n\n\tif strings.HasPrefix(goType, \"map[string]\") {\n\t\treturn SchemaDefinitionInfo{\n\t\t\ttypeInfo:         SchemaTypeInfo{typeName: \"object\"},\n\t\t\tmapValueTypeInfo: goTypeToTypeInfo(pkg, strings.TrimPrefix(goType, \"map[string]\")),\n\t\t}\n\t}\n\n\treturn SchemaDefinitionInfo{\n\t\ttypeInfo: *goTypeToTypeInfo(pkg, goType),\n\t}\n}\n\nfunc typeInfoToSchema(typeInfo *SchemaTypeInfo) *jsonschema.Schema {\n\tschema := jsonschema.Schema{}\n\n\tif typeInfo.typeName != \"\" {\n\t\tschema.Type = typeInfo.typeName\n\t}\n\n\tif typeInfo.ref != \"\" {\n\t\tschema.Ref = typeInfo.ref\n\t}\n\n\treturn &schema\n}\n\nfunc fieldToSchema(pkg string, field *Field) *jsonschema.Schema {\n\tschema := jsonschema.Schema{}\n\n\tif field.Text != nil {\n\t\t// if there is an explicit schema, use it\n\t\tif field.Text.Schema != nil {\n\t\t\tschema = field.Text.Schema.Schema\n\t\t}\n\n\t\t// if no title is provided on the explicit schema, grab it from the comment\n\t\tif schema.Title == \"\" {\n\t\t\tschema.Title = strings.ReplaceAll(field.Tag, \"\\\\n\", \"\\n\")\n\t\t}\n\n\t\tpopulateDescriptionFields(field.Text.Description, &schema)\n\n\t\t// if an explicit schema was provided, return it\n\t\tif field.Text.Schema != nil {\n\t\t\treturn &schema\n\t\t}\n\t}\n\n\t// schema was not explicitly provided, generate it from the comment\n\n\tinfo := fieldToDefinitionInfo(pkg, field)\n\n\tif info.typeInfo.ref != \"\" {\n\t\tschema.Ref = info.typeInfo.ref\n\t}\n\n\tif info.enumValues != nil {\n\t\tschema.Enum = info.enumValues\n\t}\n\n\tif info.typeInfo.typeName != \"\" {\n\t\tschema.Type = info.typeInfo.typeName\n\t}\n\n\tif info.arrayItemsTypeInfo != nil {\n\t\tschema.Items = typeInfoToSchema(info.arrayItemsTypeInfo)\n\t}\n\n\tif info.mapValueTypeInfo != nil {\n\t\tschema.PatternProperties = map[string]*jsonschema.Schema{\n\t\t\t\".*\": typeInfoToSchema(info.mapValueTypeInfo),\n\t\t}\n\t}\n\n\treturn &schema\n}\n\nfunc populateDescriptionFields(description string, schema *jsonschema.Schema) {\n\tif schema.Extras == nil {\n\t\tschema.Extras = make(map[string]any)\n\t}\n\n\tmarkdownDescription := normalizeDescription(description)\n\n\thtmlFlags := html.CommonFlags | html.HrefTargetBlank\n\topts := html.RendererOptions{Flags: htmlFlags}\n\trenderer := html.NewRenderer(opts)\n\n\thtmlDescription := string(markdown.ToHTML([]byte(markdownDescription), nil, renderer))\n\n\tpolicy := bluemonday.StrictPolicy()\n\n\tplaintextDescription := policy.Sanitize(htmlDescription)\n\n\t// set description\n\tif schema.Description == \"\" {\n\t\tschema.Description = plaintextDescription\n\t}\n\n\t// set markdownDescription for vscode/monaco editor\n\tif schema.Extras[\"markdownDescription\"] == nil {\n\t\tschema.Extras[\"markdownDescription\"] = markdownDescription\n\t}\n\n\t// set htmlDescription for Jetbrains IDEs\n\tif schema.Extras[\"x-intellij-html-description\"] == nil {\n\t\tschema.Extras[\"x-intellij-html-description\"] = htmlDescription\n\t}\n}\n\nfunc structToSchema(pkg string, st *Struct, allStructs []*Struct) *jsonschema.Schema {\n\tschema := jsonschema.Schema{\n\t\tType:                 \"object\",\n\t\tAdditionalProperties: jsonschema.FalseSchema,\n\t}\n\n\tvar requiredFields []string\n\n\tproperties := orderedmap.New[string, *jsonschema.Schema]()\n\n\tif st.Text != nil && st.Text.SchemaMeta != \"\" {\n\t\tparts := strings.Split(st.Text.SchemaMeta, \"/\")\n\t\tif len(parts) != 2 {\n\t\t\tlog.Fatalf(\"invalid schema meta: %s\", st.Text.SchemaMeta)\n\t\t}\n\n\t\tapiVersionVal := parts[0]\n\t\tkindVal := parts[1]\n\n\t\tapiVersionSchema := &jsonschema.Schema{\n\t\t\tTitle: \"apiVersion\",\n\t\t\tEnum:  []any{apiVersionVal},\n\t\t}\n\n\t\tkindSchema := &jsonschema.Schema{\n\t\t\tTitle: \"kind\",\n\t\t\tEnum:  []any{kindVal},\n\t\t}\n\n\t\tpopulateDescriptionFields(\"apiVersion is the API version of the resource.\", apiVersionSchema)\n\t\tpopulateDescriptionFields(\"kind is the kind of the resource.\", kindSchema)\n\n\t\tproperties.Set(\"apiVersion\", apiVersionSchema)\n\t\tproperties.Set(\"kind\", kindSchema)\n\n\t\trequiredFields = append(requiredFields, \"apiVersion\", \"kind\")\n\t}\n\n\tfor _, field := range st.Fields {\n\t\tif field.Inline {\n\t\t\tvar inlinedStruct *Struct\n\n\t\t\tfor _, otherStruct := range allStructs {\n\t\t\t\tif otherStruct.Name == field.Type {\n\t\t\t\t\tinlinedStruct = otherStruct\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif inlinedStruct != nil {\n\t\t\t\tfor _, inlineField := range inlinedStruct.Fields {\n\t\t\t\t\tif inlineField.Tag == \"\" {\n\t\t\t\t\t\t// skip unknown/untagged field\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif inlineField.Text != nil && inlineField.Text.SchemaRequired {\n\t\t\t\t\t\trequiredFields = append(requiredFields, inlineField.Tag)\n\t\t\t\t\t}\n\n\t\t\t\t\tproperties.Set(inlineField.Tag, fieldToSchema(pkg, inlineField))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif field.Tag == \"\" {\n\t\t\t// skip unknown/untagged field\n\t\t\tcontinue\n\t\t}\n\n\t\tif field.Text != nil && field.Text.SchemaRequired {\n\t\t\trequiredFields = append(requiredFields, field.Tag)\n\t\t}\n\n\t\tproperties.Set(field.Tag, fieldToSchema(pkg, field))\n\t}\n\n\tslices.Sort(requiredFields)\n\n\tschema.Properties = properties\n\tschema.Required = requiredFields\n\n\tif st.Text.Description != \"\" {\n\t\tschema.Description = st.Text.Description\n\t}\n\n\treturn &schema\n}\n\nfunc docsToSchema(docs []*Doc, schemaURL string) *jsonschema.Schema {\n\tschema := jsonschema.Schema{\n\t\tVersion:     jsonschema.Version,\n\t\tID:          jsonschema.ID(schemaURL),\n\t\tDefinitions: make(jsonschema.Definitions),\n\t}\n\n\tfor _, doc := range docs {\n\t\tfor _, docStruct := range doc.Structs {\n\t\t\tname := doc.Package + \".\" + docStruct.Name\n\n\t\t\tif docStruct.Text != nil && docStruct.Text.SchemaRoot {\n\t\t\t\tschema.OneOf = append(schema.OneOf, &jsonschema.Schema{\n\t\t\t\t\tRef: \"#/$defs/\" + name,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tschema.Definitions[name] = structToSchema(doc.Package, docStruct, doc.Structs)\n\t\t}\n\t}\n\n\treturn &schema\n}\n\nfunc renderSchema(docs []*Doc, destinationFile, versionTagFile string) {\n\tversion := readMajorMinorVersion(versionTagFile)\n\tschemaFileName := filepath.Base(destinationFile)\n\tschemaURL := fmt.Sprintf(ConfigSchemaURLFormat, version, schemaFileName)\n\n\tschema := docsToSchema(docs, schemaURL)\n\n\tmarshaled, err := json.MarshalIndent(schema, \"\", \"  \")\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to marshal schema: %v\", err)\n\t}\n\n\tvalidateSchema(string(marshaled), schemaURL)\n\n\tdestDir := filepath.Dir(destinationFile)\n\n\tif err = os.MkdirAll(destDir, 0o755); err != nil {\n\t\tlog.Fatalf(\"failed to create destination directory %q: %v\", destDir, err)\n\t}\n\n\terr = os.WriteFile(destinationFile, marshaled, 0o644)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to write schema to %s: %v\", destinationFile, err)\n\t}\n}\n\n// validateSchema validates the schema itself by compiling it.\nfunc validateSchema(schema, schemaURL string) {\n\tschemaJSON, err := validatejsonschema.UnmarshalJSON(strings.NewReader(schema))\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to unmarshal schema JSON: %v\", err)\n\t}\n\n\tcompiler := validatejsonschema.NewCompiler()\n\n\tif err := compiler.AddResource(schemaURL, schemaJSON); err != nil {\n\t\tlog.Fatalf(\"failed to add schema resource: %v\", err)\n\t}\n\n\tif _, err := compiler.Compile(schemaURL); err != nil {\n\t\tlog.Fatalf(\"failed to compile schema: %v\", err)\n\t}\n}\n\nfunc normalizeDescription(description string) string {\n\tdescription = strings.ReplaceAll(description, `\\n`, \"\\n\")\n\tdescription = strings.ReplaceAll(description, `\\\"`, `\"`)\n\tdescription = strings.TrimSpace(description)\n\n\treturn description\n}\n\nfunc readMajorMinorVersion(filePath string) string {\n\tfileBytes, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to read version file: %v\", err)\n\t}\n\n\tversion := string(fileBytes)\n\n\tversionParts := strings.Split(version, \".\")\n\n\tif len(versionParts) < 2 {\n\t\tlog.Fatalf(\"unexpected version in version file: %s\", version)\n\t}\n\n\treturn versionParts[0] + \".\" + versionParts[1]\n}\n"
  },
  {
    "path": "tools/go.mod",
    "content": "module github.com/siderolabs/talos/tools\n\n// upgrading all tools: go get tool\n\ngo 1.26.0\n\ntool (\n\tgithub.com/aarzilli/whydeadcode\n\tgithub.com/anchore/grype/cmd/grype\n\tgithub.com/anchore/syft/cmd/syft\n\tgithub.com/bufbuild/buf/cmd/buf\n\tgithub.com/dmarkham/enumer\n\tgithub.com/golangci/golangci-lint/v2/cmd/golangci-lint\n\tgithub.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto\n\tgithub.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc\n\tgithub.com/siderolabs/deep-copy\n\tgithub.com/siderolabs/importvet/cmd/importvet\n\tgithub.com/siderolabs/talos/tools/docgen\n\tgithub.com/siderolabs/talos/tools/gotagsrewrite\n\tgithub.com/siderolabs/talos/tools/structprotogen\n\tgolang.org/x/tools/cmd/goimports\n\tgolang.org/x/tools/cmd/stringer\n\tgolang.org/x/vuln/cmd/govulncheck\n\tgoogle.golang.org/grpc/cmd/protoc-gen-go-grpc\n\tgoogle.golang.org/protobuf/cmd/protoc-gen-go\n\tk8s.io/code-generator/cmd/deepcopy-gen\n\tmvdan.cc/gofumpt\n)\n\n// local modules\nreplace (\n\tgithub.com/siderolabs/talos/tools/docgen => ./docgen\n\tgithub.com/siderolabs/talos/tools/gotagsrewrite => ./gotagsrewrite\n\tgithub.com/siderolabs/talos/tools/structprotogen => ./structprotogen\n)\n\n// Changes from https://github.com/anchore/syft/pull/3932 for deterministic SBOM\nreplace github.com/anchore/syft => github.com/dsseng/syft v1.42.1-0.20260219105507-8cf142cbcb79\n\nrequire (\n\t4d63.com/gocheckcompilerdirectives v1.3.0 // indirect\n\t4d63.com/gochecknoglobals v0.2.2 // indirect\n\tbuf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20250718181942-e35f9b667443.1 // indirect\n\tbuf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect\n\tbuf.build/gen/go/bufbuild/registry/connectrpc/go v1.19.1-20260126144947-819582968857.2 // indirect\n\tbuf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260126144947-819582968857.1 // indirect\n\tbuf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1 // indirect\n\tbuf.build/go/app v0.2.0 // indirect\n\tbuf.build/go/bufplugin v0.9.0 // indirect\n\tbuf.build/go/bufprivateusage v0.1.0 // indirect\n\tbuf.build/go/interrupt v1.1.0 // indirect\n\tbuf.build/go/protovalidate v1.1.3 // indirect\n\tbuf.build/go/protoyaml v0.6.0 // indirect\n\tbuf.build/go/spdx v0.2.0 // indirect\n\tbuf.build/go/standard v0.1.0 // indirect\n\tcel.dev/expr v0.25.1 // indirect\n\tcloud.google.com/go v0.123.0 // indirect\n\tcloud.google.com/go/auth v0.18.2 // indirect\n\tcloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect\n\tcloud.google.com/go/compute/metadata v0.9.0 // indirect\n\tcloud.google.com/go/iam v1.5.3 // indirect\n\tcloud.google.com/go/monitoring v1.24.3 // indirect\n\tcloud.google.com/go/storage v1.60.0 // indirect\n\tcodeberg.org/chavacava/garif v0.2.0 // indirect\n\tcodeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect\n\tconnectrpc.com/connect v1.19.1 // indirect\n\tconnectrpc.com/otelconnect v0.9.0 // indirect\n\tcyphar.com/go-pathrs v0.2.3 // indirect\n\tdario.cat/mergo v1.0.2 // indirect\n\tdev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect\n\tdev.gaijin.team/go/golib v0.8.1 // indirect\n\tgithub.com/4meepo/tagalign v1.4.3 // indirect\n\tgithub.com/Abirdcfly/dupword v0.1.7 // indirect\n\tgithub.com/AdminBenni/iota-mixing v1.0.0 // indirect\n\tgithub.com/AlwxSin/noinlineerr v1.0.5 // indirect\n\tgithub.com/Antonboom/errname v1.1.1 // indirect\n\tgithub.com/Antonboom/nilnil v1.1.1 // indirect\n\tgithub.com/Antonboom/testifylint v1.6.4 // indirect\n\tgithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect\n\tgithub.com/BurntSushi/toml v1.6.0 // indirect\n\tgithub.com/CycloneDX/cyclonedx-go v0.10.0 // indirect\n\tgithub.com/DataDog/zstd v1.5.7 // indirect\n\tgithub.com/Djarvur/go-err113 v0.1.1 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect\n\tgithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect\n\tgithub.com/Intevation/gval v1.3.0 // indirect\n\tgithub.com/Intevation/jsonpath v0.2.1 // indirect\n\tgithub.com/Masterminds/goutils v1.1.1 // indirect\n\tgithub.com/Masterminds/semver v1.5.0 // indirect\n\tgithub.com/Masterminds/semver/v3 v3.4.0 // indirect\n\tgithub.com/Masterminds/sprig v2.22.0+incompatible // indirect\n\tgithub.com/Masterminds/sprig/v3 v3.3.0 // indirect\n\tgithub.com/Microsoft/go-winio v0.6.2 // indirect\n\tgithub.com/Microsoft/hcsshim v0.14.0-rc.1 // indirect\n\tgithub.com/MirrexOne/unqueryvet v1.5.4 // indirect\n\tgithub.com/OneOfOne/xxhash v1.2.8 // indirect\n\tgithub.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect\n\tgithub.com/ProtonMail/go-crypto v1.3.0 // indirect\n\tgithub.com/STARRY-S/zip v0.2.3 // indirect\n\tgithub.com/aarzilli/whydeadcode v0.0.0-20260303092945-8d908f77de3a // indirect\n\tgithub.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect\n\tgithub.com/acobaugh/osrelease v0.1.0 // indirect\n\tgithub.com/adrg/xdg v0.5.3 // indirect\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/alecthomas/chroma/v2 v2.23.1 // indirect\n\tgithub.com/alecthomas/go-check-sumtype v0.3.1 // indirect\n\tgithub.com/alexkohler/nakedret/v2 v2.0.6 // indirect\n\tgithub.com/alexkohler/prealloc v1.1.0 // indirect\n\tgithub.com/alfatraining/structtag v1.0.0 // indirect\n\tgithub.com/alingse/asasalint v0.0.11 // indirect\n\tgithub.com/alingse/nilnesserr v0.2.0 // indirect\n\tgithub.com/anchore/bubbly v0.0.0-20250717181826-8a411f9d8cbf // indirect\n\tgithub.com/anchore/clio v0.0.0-20260217161816-1b390cf973f8 // indirect\n\tgithub.com/anchore/fangs v0.0.0-20260205223337-3833021a87e1 // indirect\n\tgithub.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c // indirect\n\tgithub.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d // indirect\n\tgithub.com/anchore/go-logger v0.0.0-20260217144723-3bb369b8046c // indirect\n\tgithub.com/anchore/go-lzo v0.1.0 // indirect\n\tgithub.com/anchore/go-macholibre v0.0.0-20260203040931-2d1882573092 // indirect\n\tgithub.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec // indirect\n\tgithub.com/anchore/go-struct-converter v0.1.0 // indirect\n\tgithub.com/anchore/go-sync v0.0.0-20260122203928-582959aeb913 // indirect\n\tgithub.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect\n\tgithub.com/anchore/grype v0.109.1 // indirect\n\tgithub.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect\n\tgithub.com/anchore/stereoscope v0.1.21 // indirect\n\tgithub.com/anchore/syft v1.42.2 // indirect\n\tgithub.com/andybalholm/brotli v1.2.0 // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.1 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/aquasecurity/go-pep440-version v0.0.1 // indirect\n\tgithub.com/aquasecurity/go-version v0.0.1 // indirect\n\tgithub.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect\n\tgithub.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect\n\tgithub.com/ashanbrown/makezero/v2 v2.1.0 // indirect\n\tgithub.com/aws/aws-sdk-go-v2 v1.41.2 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/config v1.32.10 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.19.10 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/signin v1.0.6 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.41.7 // indirect\n\tgithub.com/aws/smithy-go v1.24.1 // indirect\n\tgithub.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect\n\tgithub.com/aymerick/douceur v0.2.0 // indirect\n\tgithub.com/bahlo/generic-list-go v0.2.0 // indirect\n\tgithub.com/becheran/wildmatch-go v1.0.0 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect\n\tgithub.com/bitnami/go-version v0.0.0-20251209151629-b46c9d8f1f27 // indirect\n\tgithub.com/bkielbasa/cyclop v1.2.3 // indirect\n\tgithub.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect\n\tgithub.com/blizzy78/varnamelen v0.8.0 // indirect\n\tgithub.com/bmatcuk/doublestar/v2 v2.0.4 // indirect\n\tgithub.com/bmatcuk/doublestar/v4 v4.10.0 // indirect\n\tgithub.com/bodgit/plumbing v1.3.0 // indirect\n\tgithub.com/bodgit/sevenzip v1.6.1 // indirect\n\tgithub.com/bodgit/windows v1.0.1 // indirect\n\tgithub.com/bombsimon/wsl/v4 v4.7.0 // indirect\n\tgithub.com/bombsimon/wsl/v5 v5.6.0 // indirect\n\tgithub.com/breml/bidichk v0.3.3 // indirect\n\tgithub.com/breml/errchkjson v0.4.1 // indirect\n\tgithub.com/bufbuild/buf v1.66.1 // indirect\n\tgithub.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156 // indirect\n\tgithub.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 // indirect\n\tgithub.com/buger/jsonparser v1.1.1 // indirect\n\tgithub.com/butuzov/ireturn v0.4.0 // indirect\n\tgithub.com/butuzov/mirror v1.3.0 // indirect\n\tgithub.com/catenacyber/perfsprint v0.10.1 // indirect\n\tgithub.com/ccojocar/zxcvbn-go v1.0.4 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/charithe/durationcheck v0.0.11 // indirect\n\tgithub.com/charmbracelet/bubbles v1.0.0 // indirect\n\tgithub.com/charmbracelet/bubbletea v1.3.10 // indirect\n\tgithub.com/charmbracelet/colorprofile v0.4.2 // indirect\n\tgithub.com/charmbracelet/harmonica v0.2.0 // indirect\n\tgithub.com/charmbracelet/lipgloss v1.1.0 // indirect\n\tgithub.com/charmbracelet/x/ansi v0.11.6 // indirect\n\tgithub.com/charmbracelet/x/cellbuf v0.0.15 // indirect\n\tgithub.com/charmbracelet/x/term v0.2.2 // indirect\n\tgithub.com/ckaznocha/intrange v0.3.1 // indirect\n\tgithub.com/cli/browser v1.3.0 // indirect\n\tgithub.com/clipperhouse/displaywidth v0.10.0 // indirect\n\tgithub.com/clipperhouse/uax29/v2 v2.7.0 // indirect\n\tgithub.com/cloudflare/circl v1.6.3 // indirect\n\tgithub.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect\n\tgithub.com/containerd/cgroups/v3 v3.1.3 // indirect\n\tgithub.com/containerd/containerd/api v1.10.0 // indirect\n\tgithub.com/containerd/containerd/v2 v2.2.1 // indirect\n\tgithub.com/containerd/continuity v0.4.5 // indirect\n\tgithub.com/containerd/errdefs v1.0.0 // indirect\n\tgithub.com/containerd/errdefs/pkg v0.3.0 // indirect\n\tgithub.com/containerd/fifo v1.1.0 // indirect\n\tgithub.com/containerd/log v0.1.0 // indirect\n\tgithub.com/containerd/platforms v1.0.0-rc.2 // indirect\n\tgithub.com/containerd/plugin v1.0.0 // indirect\n\tgithub.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect\n\tgithub.com/containerd/ttrpc v1.2.7 // indirect\n\tgithub.com/containerd/typeurl/v2 v2.2.3 // indirect\n\tgithub.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect\n\tgithub.com/curioswitch/go-reassign v0.3.0 // indirect\n\tgithub.com/cyphar/filepath-securejoin v0.6.1 // indirect\n\tgithub.com/daixiang0/gci v0.13.7 // indirect\n\tgithub.com/dave/dst v0.27.3 // indirect\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect\n\tgithub.com/denis-tingaikin/go-header v0.5.0 // indirect\n\tgithub.com/dghubble/trie v0.1.0 // indirect\n\tgithub.com/diskfs/go-diskfs v1.7.0 // indirect\n\tgithub.com/distribution/reference v0.6.0 // indirect\n\tgithub.com/dlclark/regexp2 v1.11.5 // indirect\n\tgithub.com/dmarkham/enumer v1.6.3 // indirect\n\tgithub.com/docker/cli v29.3.0+incompatible // indirect\n\tgithub.com/docker/distribution v2.8.3+incompatible // indirect\n\tgithub.com/docker/docker v28.5.2+incompatible // indirect\n\tgithub.com/docker/docker-credential-helpers v0.9.5 // indirect\n\tgithub.com/docker/go-connections v0.6.0 // indirect\n\tgithub.com/docker/go-units v0.5.0 // indirect\n\tgithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect\n\tgithub.com/dustin/go-humanize v1.0.1 // indirect\n\tgithub.com/elliotchance/phpserialize v1.4.0 // indirect\n\tgithub.com/emirpasic/gods v1.18.1 // indirect\n\tgithub.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect\n\tgithub.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect\n\tgithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect\n\tgithub.com/ettle/strcase v0.2.0 // indirect\n\tgithub.com/facebookincubator/nvdtools v0.1.5 // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/fatih/structtag v1.2.0 // indirect\n\tgithub.com/felixge/fgprof v0.9.5 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/firefart/nonamedreturns v1.0.6 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/fzipp/gocyclo v0.6.0 // indirect\n\tgithub.com/gabriel-vasile/mimetype v1.4.13 // indirect\n\tgithub.com/ghostiam/protogetter v0.3.20 // indirect\n\tgithub.com/github/go-spdx/v2 v2.4.0 // indirect\n\tgithub.com/glebarez/go-sqlite v1.22.0 // indirect\n\tgithub.com/glebarez/sqlite v1.11.0 // indirect\n\tgithub.com/go-critic/go-critic v0.14.3 // indirect\n\tgithub.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect\n\tgithub.com/go-git/go-billy/v5 v5.8.0 // indirect\n\tgithub.com/go-git/go-git/v5 v5.17.0 // indirect\n\tgithub.com/go-jose/go-jose/v4 v4.1.3 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-restruct/restruct v1.2.0-alpha // indirect\n\tgithub.com/go-toolsmith/astcast v1.1.0 // indirect\n\tgithub.com/go-toolsmith/astcopy v1.1.0 // indirect\n\tgithub.com/go-toolsmith/astequal v1.2.0 // indirect\n\tgithub.com/go-toolsmith/astfmt v1.1.0 // indirect\n\tgithub.com/go-toolsmith/astp v1.1.0 // indirect\n\tgithub.com/go-toolsmith/strparse v1.1.0 // indirect\n\tgithub.com/go-toolsmith/typep v1.1.0 // indirect\n\tgithub.com/go-viper/mapstructure/v2 v2.5.0 // indirect\n\tgithub.com/go-xmlfmt/xmlfmt v1.1.3 // indirect\n\tgithub.com/gobwas/glob v0.2.3 // indirect\n\tgithub.com/goccy/go-yaml v1.19.2 // indirect\n\tgithub.com/gocsaf/csaf/v3 v3.5.1 // indirect\n\tgithub.com/godoc-lint/godoc-lint v0.11.2 // indirect\n\tgithub.com/gofrs/flock v0.13.0 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/gohugoio/hashstructure v0.6.0 // indirect\n\tgithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/golangci/asciicheck v0.5.0 // indirect\n\tgithub.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect\n\tgithub.com/golangci/go-printf-func-name v0.1.1 // indirect\n\tgithub.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect\n\tgithub.com/golangci/golangci-lint/v2 v2.11.3 // indirect\n\tgithub.com/golangci/golines v0.15.0 // indirect\n\tgithub.com/golangci/misspell v0.8.0 // indirect\n\tgithub.com/golangci/plugin-module-register v0.1.2 // indirect\n\tgithub.com/golangci/revgrep v0.8.0 // indirect\n\tgithub.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect\n\tgithub.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect\n\tgithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab // indirect\n\tgithub.com/google/cel-go v0.27.0 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/go-containerregistry v0.21.2 // indirect\n\tgithub.com/google/licensecheck v0.3.1 // indirect\n\tgithub.com/google/pprof v0.0.0-20260202012954-cb029daf43ef // indirect\n\tgithub.com/google/s2a-go v0.1.9 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/googleapis/enterprise-certificate-proxy v0.3.12 // indirect\n\tgithub.com/googleapis/gax-go/v2 v2.17.0 // indirect\n\tgithub.com/gookit/color v1.6.0 // indirect\n\tgithub.com/gordonklaus/ineffassign v0.2.0 // indirect\n\tgithub.com/gorilla/css v1.0.1 // indirect\n\tgithub.com/gostaticanalysis/analysisutil v0.7.1 // indirect\n\tgithub.com/gostaticanalysis/comment v1.5.0 // indirect\n\tgithub.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect\n\tgithub.com/gostaticanalysis/nilerr v0.1.2 // indirect\n\tgithub.com/gpustack/gguf-parser-go v0.24.0 // indirect\n\tgithub.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect\n\tgithub.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 // indirect\n\tgithub.com/hashicorp/errwrap v1.1.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-getter v1.8.4 // indirect\n\tgithub.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect\n\tgithub.com/hashicorp/go-multierror v1.1.1 // indirect\n\tgithub.com/hashicorp/go-version v1.8.0 // indirect\n\tgithub.com/hashicorp/golang-lru/v2 v2.0.7 // indirect\n\tgithub.com/hashicorp/hcl/v2 v2.24.0 // indirect\n\tgithub.com/henvic/httpretty v0.1.4 // indirect\n\tgithub.com/hexops/gotextdiff v1.0.3 // indirect\n\tgithub.com/huandu/xstrings v1.5.0 // indirect\n\tgithub.com/iancoleman/strcase v0.3.0 // indirect\n\tgithub.com/imdario/mergo v0.3.16 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/invopop/jsonschema v0.13.0 // indirect\n\tgithub.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect\n\tgithub.com/jdx/go-netrc v1.0.0 // indirect\n\tgithub.com/jedib0t/go-pretty/v6 v6.7.8 // indirect\n\tgithub.com/jgautheron/goconst v1.8.2 // indirect\n\tgithub.com/jingyugao/rowserrcheck v1.1.1 // indirect\n\tgithub.com/jinzhu/copier v0.4.0 // indirect\n\tgithub.com/jinzhu/inflection v1.0.0 // indirect\n\tgithub.com/jinzhu/now v1.1.5 // indirect\n\tgithub.com/jjti/go-spancheck v0.6.5 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/julz/importas v0.2.0 // indirect\n\tgithub.com/karamaru-alpha/copyloopvar v1.2.2 // indirect\n\tgithub.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect\n\tgithub.com/kevinburke/ssh_config v1.6.0 // indirect\n\tgithub.com/kisielk/errcheck v1.10.0 // indirect\n\tgithub.com/kkHAIKE/contextcheck v1.1.6 // indirect\n\tgithub.com/klauspost/compress v1.18.4 // indirect\n\tgithub.com/klauspost/cpuid/v2 v2.3.0 // indirect\n\tgithub.com/klauspost/pgzip v1.2.6 // indirect\n\tgithub.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect\n\tgithub.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 // indirect\n\tgithub.com/kulti/thelper v0.7.1 // indirect\n\tgithub.com/kunwardeep/paralleltest v1.0.15 // indirect\n\tgithub.com/lasiar/canonicalheader v1.1.2 // indirect\n\tgithub.com/ldez/exptostd v0.4.5 // indirect\n\tgithub.com/ldez/gomoddirectives v0.8.0 // indirect\n\tgithub.com/ldez/grignotin v0.10.1 // indirect\n\tgithub.com/ldez/structtags v0.6.1 // indirect\n\tgithub.com/ldez/tagliatelle v0.7.2 // indirect\n\tgithub.com/ldez/usetesting v0.5.0 // indirect\n\tgithub.com/leonklingele/grouper v1.1.2 // indirect\n\tgithub.com/lucasb-eyer/go-colorful v1.3.0 // indirect\n\tgithub.com/macabu/inamedparam v0.2.0 // indirect\n\tgithub.com/mailru/easyjson v0.9.1 // indirect\n\tgithub.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect\n\tgithub.com/manuelarte/funcorder v0.5.0 // indirect\n\tgithub.com/maratori/testableexamples v1.0.1 // indirect\n\tgithub.com/maratori/testpackage v1.1.2 // indirect\n\tgithub.com/masahiro331/go-mvn-version v0.0.0-20260119054159-d21fcd2e7de1 // indirect\n\tgithub.com/matoous/godox v1.1.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.20 // indirect\n\tgithub.com/mgechev/revive v1.15.0 // indirect\n\tgithub.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect\n\tgithub.com/mholt/archives v0.1.5 // indirect\n\tgithub.com/microcosm-cc/bluemonday v1.0.27 // indirect\n\tgithub.com/mikelolasagasti/xz v1.0.1 // indirect\n\tgithub.com/minio/minlz v1.0.1 // indirect\n\tgithub.com/mitchellh/copystructure v1.2.0 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/moby/docker-image-spec v1.3.1 // indirect\n\tgithub.com/moby/locker v1.0.1 // indirect\n\tgithub.com/moby/moby/api v1.53.0 // indirect\n\tgithub.com/moby/moby/client v0.2.2 // indirect\n\tgithub.com/moby/sys/mountinfo v0.7.2 // indirect\n\tgithub.com/moby/sys/sequential v0.6.0 // indirect\n\tgithub.com/moby/sys/signal v0.7.1 // indirect\n\tgithub.com/moby/sys/user v0.4.0 // indirect\n\tgithub.com/moby/sys/userns v0.1.0 // indirect\n\tgithub.com/moby/term v0.5.2 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect\n\tgithub.com/moricho/tparallel v0.3.2 // indirect\n\tgithub.com/morikuni/aec v1.1.0 // indirect\n\tgithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect\n\tgithub.com/muesli/cancelreader v0.2.2 // indirect\n\tgithub.com/muesli/termenv v0.16.0 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/mwitkow/go-proto-validators v0.3.2 // indirect\n\tgithub.com/nakabonne/nestif v0.3.1 // indirect\n\tgithub.com/ncruces/go-strftime v1.0.0 // indirect\n\tgithub.com/nishanths/exhaustive v0.12.0 // indirect\n\tgithub.com/nishanths/predeclared v0.2.2 // indirect\n\tgithub.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 // indirect\n\tgithub.com/nunnatsa/ginkgolinter v0.23.0 // indirect\n\tgithub.com/nwaples/rardecode/v2 v2.2.2 // indirect\n\tgithub.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect\n\tgithub.com/olekukonko/errors v1.2.0 // indirect\n\tgithub.com/olekukonko/ll v0.1.6 // indirect\n\tgithub.com/olekukonko/tablewriter v1.1.3 // indirect\n\tgithub.com/opencontainers/go-digest v1.0.0 // indirect\n\tgithub.com/opencontainers/image-spec v1.1.1 // indirect\n\tgithub.com/opencontainers/runtime-spec v1.3.0 // indirect\n\tgithub.com/opencontainers/selinux v1.13.1 // indirect\n\tgithub.com/openvex/go-vex v0.2.7 // indirect\n\tgithub.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect\n\tgithub.com/package-url/packageurl-go v0.1.3 // indirect\n\tgithub.com/pandatix/go-cvss v0.6.2 // indirect\n\tgithub.com/pascaldekloe/name v1.0.1 // indirect\n\tgithub.com/pborman/indent v1.2.1 // indirect\n\tgithub.com/pelletier/go-toml v1.9.5 // indirect\n\tgithub.com/pelletier/go-toml/v2 v2.2.4 // indirect\n\tgithub.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.25 // indirect\n\tgithub.com/pjbgf/sha1cd v0.5.0 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/pkg/profile v1.7.0 // indirect\n\tgithub.com/pkg/xattr v0.4.12 // indirect\n\tgithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect\n\tgithub.com/prometheus/client_golang v1.23.2 // indirect\n\tgithub.com/prometheus/client_model v0.6.2 // indirect\n\tgithub.com/prometheus/common v0.67.5 // indirect\n\tgithub.com/prometheus/procfs v0.19.2 // indirect\n\tgithub.com/pseudomuto/protoc-gen-doc v1.5.1 // indirect\n\tgithub.com/pseudomuto/protokit v0.2.1 // indirect\n\tgithub.com/quasilyte/go-ruleguard v0.4.5 // indirect\n\tgithub.com/quasilyte/go-ruleguard/dsl v0.3.23 // indirect\n\tgithub.com/quasilyte/gogrep v0.5.0 // indirect\n\tgithub.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect\n\tgithub.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect\n\tgithub.com/quic-go/qpack v0.6.0 // indirect\n\tgithub.com/quic-go/quic-go v0.59.0 // indirect\n\tgithub.com/raeperd/recvcheck v0.2.0 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/rogpeppe/go-internal v1.14.1 // indirect\n\tgithub.com/rs/cors v1.11.1 // indirect\n\tgithub.com/russross/blackfriday/v2 v2.1.0 // indirect\n\tgithub.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect\n\tgithub.com/ryancurrah/gomodguard v1.4.1 // indirect\n\tgithub.com/ryanrolds/sqlclosecheck v0.5.1 // indirect\n\tgithub.com/sagikazarmark/locafero v0.12.0 // indirect\n\tgithub.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect\n\tgithub.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect\n\tgithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect\n\tgithub.com/sashamelentyev/interfacebloat v1.1.0 // indirect\n\tgithub.com/sashamelentyev/usestdlibvars v1.29.0 // indirect\n\tgithub.com/sassoftware/go-rpmutils v0.4.0 // indirect\n\tgithub.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect\n\tgithub.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 // indirect\n\tgithub.com/segmentio/asm v1.2.1 // indirect\n\tgithub.com/segmentio/encoding v0.5.3 // indirect\n\tgithub.com/sergi/go-diff v1.4.0 // indirect\n\tgithub.com/shopspring/decimal v1.4.0 // indirect\n\tgithub.com/siderolabs/deep-copy v0.5.8 // indirect\n\tgithub.com/siderolabs/gen v0.8.6 // indirect\n\tgithub.com/siderolabs/importvet v0.2.0 // indirect\n\tgithub.com/siderolabs/talos/tools/docgen v0.0.0-20260313141749-6bb5cf57a28c // indirect\n\tgithub.com/siderolabs/talos/tools/gotagsrewrite v0.0.0-20260313141749-6bb5cf57a28c // indirect\n\tgithub.com/siderolabs/talos/tools/structprotogen v0.0.0-20260313141749-6bb5cf57a28c // indirect\n\tgithub.com/sirupsen/logrus v1.9.4 // indirect\n\tgithub.com/sivchari/containedctx v1.0.3 // indirect\n\tgithub.com/skeema/knownhosts v1.3.2 // indirect\n\tgithub.com/smallnest/ringbuffer v0.1.1 // indirect\n\tgithub.com/sonatard/noctx v0.5.0 // indirect\n\tgithub.com/sorairolake/lzip-go v0.3.8 // indirect\n\tgithub.com/sourcegraph/go-diff v0.7.0 // indirect\n\tgithub.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb // indirect\n\tgithub.com/spdx/tools-golang v0.5.7 // indirect\n\tgithub.com/spf13/afero v1.15.0 // indirect\n\tgithub.com/spf13/cast v1.10.0 // indirect\n\tgithub.com/spf13/cobra v1.10.2 // indirect\n\tgithub.com/spf13/pflag v1.0.10 // indirect\n\tgithub.com/spf13/viper v1.21.0 // indirect\n\tgithub.com/spiffe/go-spiffe/v2 v2.6.0 // indirect\n\tgithub.com/ssgreg/nlreturn/v2 v2.2.1 // indirect\n\tgithub.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect\n\tgithub.com/stretchr/objx v0.5.3 // indirect\n\tgithub.com/stretchr/testify v1.11.1 // indirect\n\tgithub.com/subosito/gotenv v1.6.0 // indirect\n\tgithub.com/sylabs/sif/v2 v2.23.0 // indirect\n\tgithub.com/sylabs/squashfs v1.0.6 // indirect\n\tgithub.com/tetafro/godot v1.5.4 // indirect\n\tgithub.com/tetratelabs/wazero v1.11.0 // indirect\n\tgithub.com/therootcompany/xz v1.0.1 // indirect\n\tgithub.com/tidwall/btree v1.8.1 // indirect\n\tgithub.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect\n\tgithub.com/timonwong/loggercheck v0.11.0 // indirect\n\tgithub.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect\n\tgithub.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect\n\tgithub.com/ulikunitz/xz v0.5.15 // indirect\n\tgithub.com/ultraware/funlen v0.2.0 // indirect\n\tgithub.com/ultraware/whitespace v0.2.0 // indirect\n\tgithub.com/uudashr/gocognit v1.2.1 // indirect\n\tgithub.com/uudashr/iface v1.4.1 // indirect\n\tgithub.com/vbatts/go-mtree v0.7.0 // indirect\n\tgithub.com/vbatts/tar-split v0.12.2 // indirect\n\tgithub.com/vifraa/gopom v1.0.0 // indirect\n\tgithub.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect\n\tgithub.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect\n\tgithub.com/wagoodman/go-progress v0.0.0-20260303201901-10176f79b2c0 // indirect\n\tgithub.com/wk8/go-ordered-map/v2 v2.1.8 // indirect\n\tgithub.com/xanzy/ssh-agent v0.3.3 // indirect\n\tgithub.com/xen0n/gosmopolitan v1.3.0 // indirect\n\tgithub.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect\n\tgithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect\n\tgithub.com/yagipy/maintidx v1.0.0 // indirect\n\tgithub.com/yeya24/promlinter v0.3.0 // indirect\n\tgithub.com/ykadowak/zerologlint v0.1.5 // indirect\n\tgithub.com/zclconf/go-cty v1.17.0 // indirect\n\tgithub.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1 // indirect\n\tgitlab.com/bosi/decorder v0.4.2 // indirect\n\tgo-simpler.org/musttag v0.14.0 // indirect\n\tgo-simpler.org/sloglint v0.11.1 // indirect\n\tgo.augendre.info/arangolint v0.4.0 // indirect\n\tgo.augendre.info/fatcontext v0.9.0 // indirect\n\tgo.etcd.io/bbolt v1.4.3 // indirect\n\tgo.lsp.dev/jsonrpc2 v0.10.0 // indirect\n\tgo.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect\n\tgo.lsp.dev/protocol v0.12.0 // indirect\n\tgo.lsp.dev/uri v0.3.0 // indirect\n\tgo.opencensus.io v0.24.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgo.opentelemetry.io/contrib/detectors/gcp v1.40.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect\n\tgo.opentelemetry.io/otel v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.42.0 // indirect\n\tgo.uber.org/mock v0.6.0 // indirect\n\tgo.uber.org/multierr v1.11.0 // indirect\n\tgo.uber.org/zap v1.27.1 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.3 // indirect\n\tgo.yaml.in/yaml/v3 v3.0.4 // indirect\n\tgo.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect\n\tgo4.org v0.0.0-20260112195520-a5071408f32f // indirect\n\tgolang.org/x/crypto v0.49.0 // indirect\n\tgolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect\n\tgolang.org/x/exp/typeparams v0.0.0-20260218203240-3dfff04db8fa // indirect\n\tgolang.org/x/mod v0.34.0 // indirect\n\tgolang.org/x/net v0.52.0 // indirect\n\tgolang.org/x/oauth2 v0.35.0 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/sys v0.42.0 // indirect\n\tgolang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c // indirect\n\tgolang.org/x/term v0.41.0 // indirect\n\tgolang.org/x/text v0.35.0 // indirect\n\tgolang.org/x/time v0.14.0 // indirect\n\tgolang.org/x/tools v0.43.0 // indirect\n\tgolang.org/x/vuln v1.1.4 // indirect\n\tgolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect\n\tgonum.org/v1/gonum v0.17.0 // indirect\n\tgoogle.golang.org/api v0.267.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect\n\tgoogle.golang.org/grpc v1.79.1 // indirect\n\tgoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n\tgopkg.in/typ.v4 v4.4.0 // indirect\n\tgopkg.in/warnings.v0 v0.1.2 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tgorm.io/gorm v1.31.1 // indirect\n\thonnef.co/go/tools v0.7.0 // indirect\n\tk8s.io/code-generator v0.35.2 // indirect\n\tk8s.io/gengo/v2 v2.0.0-20251215205346-5ee0d033ba5b // indirect\n\tk8s.io/klog/v2 v2.130.1 // indirect\n\tmodernc.org/libc v1.68.0 // indirect\n\tmodernc.org/mathutil v1.7.1 // indirect\n\tmodernc.org/memory v1.11.0 // indirect\n\tmodernc.org/sqlite v1.46.1 // indirect\n\tmvdan.cc/gofumpt v0.9.2 // indirect\n\tmvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect\n\tmvdan.cc/xurls/v2 v2.6.0 // indirect\n\tpluginrpc.com/pluginrpc v0.5.0 // indirect\n)\n"
  },
  {
    "path": "tools/go.sum",
    "content": "4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A=\n4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY=\n4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU=\n4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0=\nbuf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20250718181942-e35f9b667443.1 h1:zQ9C3e6FtwSZUFuKAQfpIKGFk5ZuRoGt5g35Bix55sI=\nbuf.build/gen/go/bufbuild/bufplugin/protocolbuffers/go v1.36.11-20250718181942-e35f9b667443.1/go.mod h1:1Znr6gmYBhbxWUPRrrVnSLXQsz8bvFVw1HHJq2bI3VQ=\nbuf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.11-20250109164928-1da0de137947.1 h1:HwzzCRS4ZrEm1++rzSDxHnO0DOjiT1b8I/24e8a4exY=\nbuf.build/gen/go/bufbuild/protodescriptor/protocolbuffers/go v1.36.11-20250109164928-1da0de137947.1/go.mod h1:8PRKXhgNes29Tjrnv8KdZzg3I1QceOkzibW1QK7EXv0=\nbuf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 h1:PMmTMyvHScV9Mn8wc6ASge9uRcHy0jtqPd+fM35LmsQ=\nbuf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=\nbuf.build/gen/go/bufbuild/registry/connectrpc/go v1.19.1-20260126144947-819582968857.2 h1:XPrWCd9ydEo5Ofv1aNJVJaxndMXLQjRO9vVzsJG3jL8=\nbuf.build/gen/go/bufbuild/registry/connectrpc/go v1.19.1-20260126144947-819582968857.2/go.mod h1:mpsjeEaxOYPIJV2cz4IagLghZufRvx+NPVtInjEeoQ8=\nbuf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260126144947-819582968857.1 h1:Yreby6Ypa58wdQUEm9Fnc5g8n/jP487Dq3aK5yBYwfk=\nbuf.build/gen/go/bufbuild/registry/protocolbuffers/go v1.36.11-20260126144947-819582968857.1/go.mod h1:1JJi9jvOqRxSMa+JxiZSm57doB+db/1WYCIa2lHfc40=\nbuf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1 h1:iGPvEJltOXUMANWf0zajcRcbiOXLD90ZwPUFvbcuv6Q=\nbuf.build/gen/go/pluginrpc/pluginrpc/protocolbuffers/go v1.36.11-20241007202033-cf42259fcbfc.1/go.mod h1:nWVKKRA29zdt4uvkjka3i/y4mkrswyWwiu0TbdX0zts=\nbuf.build/go/app v0.2.0 h1:NYaH13A+RzPb7M5vO8uZYZ2maBZI5+MS9A9tQm66fy8=\nbuf.build/go/app v0.2.0/go.mod h1:0XVOYemubVbxNXVY0DnsVgWeGkcbbAvjDa1fmhBC+Wo=\nbuf.build/go/bufplugin v0.9.0 h1:ktZJNP3If7ldcWVqh46XKeiYJVPxHQxCfjzVQDzZ/lo=\nbuf.build/go/bufplugin v0.9.0/go.mod h1:Z0CxA3sKQ6EPz/Os4kJJneeRO6CjPeidtP1ABh5jPPY=\nbuf.build/go/bufprivateusage v0.1.0 h1:SzCoCcmzS3zyXHEXHeSQhGI7OTkgtljoknLzsUz9Gg4=\nbuf.build/go/bufprivateusage v0.1.0/go.mod h1:GlCCJ3VVF7EqqU0CoRmo1FzAwwaKymEWSr+ty69xU5w=\nbuf.build/go/interrupt v1.1.0 h1:olBuhgv9Sav4/9pkSLoxgiOsZDgM5VhRhvRpn3DL0lE=\nbuf.build/go/interrupt v1.1.0/go.mod h1:ql56nXPG1oHlvZa6efNC7SKAQ/tUjS6z0mhJl0gyeRM=\nbuf.build/go/protovalidate v1.1.3 h1:m2GVEgQWd7rk+vIoAZ+f0ygGjvQTuqPQapBBdcpWVPE=\nbuf.build/go/protovalidate v1.1.3/go.mod h1:9XIuohWz+kj+9JVn3WQneHA5LZP50mjvneZMnbLkiIE=\nbuf.build/go/protoyaml v0.6.0 h1:Nzz1lvcXF8YgNZXk+voPPwdU8FjDPTUV4ndNTXN0n2w=\nbuf.build/go/protoyaml v0.6.0/go.mod h1:RgUOsBu/GYKLDSIRgQXniXbNgFlGEZnQpRAUdLAFV2Q=\nbuf.build/go/spdx v0.2.0 h1:IItqM0/cMxvFJJumcBuP8NrsIzMs/UYjp/6WSpq8LTw=\nbuf.build/go/spdx v0.2.0/go.mod h1:bXdwQFem9Si3nsbNy8aJKGPoaPi5DKwdeEp5/ArZ6w8=\nbuf.build/go/standard v0.1.0 h1:g98T9IyvAl0vS3Pq8iVk6Cvj2ZiFvoUJRtfyGa0120U=\nbuf.build/go/standard v0.1.0/go.mod h1:PiqpHz/7ZFq+kqvYhc/SK3lxFIB9N/aiH2CFC2JHIQg=\ncel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=\ncel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=\ncloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=\ncloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=\ncloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=\ncloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=\ncloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=\ncloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=\ncloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=\ncloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=\ncloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=\ncloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=\ncloud.google.com/go/auth v0.18.2 h1:+Nbt5Ev0xEqxlNjd6c+yYUeosQ5TtEUaNcN/3FozlaM=\ncloud.google.com/go/auth v0.18.2/go.mod h1:xD+oY7gcahcu7G2SG2DsBerfFxgPAJz17zz2joOFF3M=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=\ncloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=\ncloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=\ncloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=\ncloud.google.com/go/logging v1.13.2 h1:qqlHCBvieJT9Cdq4QqYx1KPadCQ2noD4FK02eNqHAjA=\ncloud.google.com/go/logging v1.13.2/go.mod h1:zaybliM3yun1J8mU2dVQ1/qDzjbOqEijZCn6hSBtKak=\ncloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8=\ncloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk=\ncloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=\ncloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ncloud.google.com/go/storage v1.60.0 h1:oBfZrSOCimggVNz9Y/bXY35uUcts7OViubeddTTVzQ8=\ncloud.google.com/go/storage v1.60.0/go.mod h1:q+5196hXfejkctrnx+VYU8RKQr/L3c0cBIlrjmiAKE0=\ncloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=\ncloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=\ncodeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY=\ncodeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ=\ncodeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI=\ncodeberg.org/polyfloyd/go-errorlint v1.9.0/go.mod h1:GPRRu2LzVijNn4YkrZYJfatQIdS+TrcK8rL5Xs24qw8=\nconnectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14=\nconnectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w=\nconnectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA=\nconnectrpc.com/otelconnect v0.9.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc=\ncyphar.com/go-pathrs v0.2.3 h1:0pH8gep37wB0BgaXrEaN1OtZhUMeS7VvaejSr6i822o=\ncyphar.com/go-pathrs v0.2.3/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=\ndario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=\ndario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=\ndev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y=\ndev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI=\ndev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E=\ndev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8=\ngithub.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c=\ngithub.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ=\ngithub.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=\ngithub.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=\ngithub.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo=\ngithub.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY=\ngithub.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY=\ngithub.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc=\ngithub.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q=\ngithub.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ=\ngithub.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ=\ngithub.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II=\ngithub.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ=\ngithub.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=\ngithub.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=\ngithub.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/CycloneDX/cyclonedx-go v0.10.0 h1:7xyklU7YD+CUyGzSFIARG18NYLsKVn4QFg04qSsu+7Y=\ngithub.com/CycloneDX/cyclonedx-go v0.10.0/go.mod h1:vUvbCXQsEm48OI6oOlanxstwNByXjCZ2wuleUlwGEO8=\ngithub.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE=\ngithub.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=\ngithub.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g=\ngithub.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk=\ngithub.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=\ngithub.com/Intevation/gval v1.3.0 h1:+Ze5sft5MmGbZrHj06NVUbcxCb67l9RaPTLMNr37mjw=\ngithub.com/Intevation/gval v1.3.0/go.mod h1:xmGyGpP5be12EL0P12h+dqiYG8qn2j3PJxIgkoOHO5o=\ngithub.com/Intevation/jsonpath v0.2.1 h1:rINNQJ0Pts5XTFEG+zamtdL7l9uuE1z0FBA+r55Sw+A=\ngithub.com/Intevation/jsonpath v0.2.1/go.mod h1:WnZ8weMmwAx/fAO3SutjYFU+v7DFreNYnibV7CiaYIw=\ngithub.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=\ngithub.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=\ngithub.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=\ngithub.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=\ngithub.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=\ngithub.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=\ngithub.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=\ngithub.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=\ngithub.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=\ngithub.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=\ngithub.com/Microsoft/hcsshim v0.14.0-rc.1 h1:qAPXKwGOkVn8LlqgBN8GS0bxZ83hOJpcjxzmlQKxKsQ=\ngithub.com/Microsoft/hcsshim v0.14.0-rc.1/go.mod h1:hTKFGbnDtQb1wHiOWv4v0eN+7boSWAHyK/tNAaYZL0c=\ngithub.com/MirrexOne/unqueryvet v1.5.4 h1:38QOxShO7JmMWT+eCdDMbcUgGCOeJphVkzzRgyLJgsQ=\ngithub.com/MirrexOne/unqueryvet v1.5.4/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=\ngithub.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=\ngithub.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4=\ngithub.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo=\ngithub.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=\ngithub.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=\ngithub.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=\ngithub.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=\ngithub.com/aarzilli/whydeadcode v0.0.0-20260303092945-8d908f77de3a h1:qHtQIeFjOta2EylF59J2UJxZrYT0dCprYXe399PO8xw=\ngithub.com/aarzilli/whydeadcode v0.0.0-20260303092945-8d908f77de3a/go.mod h1:rHV6WbQI4oOtjbl+J0d9UYVs8eBU9bqZIp9UB5QACiQ=\ngithub.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=\ngithub.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=\ngithub.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=\ngithub.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY=\ngithub.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=\ngithub.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=\ngithub.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=\ngithub.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=\ngithub.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=\ngithub.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=\ngithub.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=\ngithub.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=\ngithub.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ=\ngithub.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q=\ngithub.com/alexkohler/prealloc v1.1.0 h1:cKGRBqlXw5iyQGLYhrXrDlcHxugXpTq4tQ5c91wkf8M=\ngithub.com/alexkohler/prealloc v1.1.0/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig=\ngithub.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc=\ngithub.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus=\ngithub.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=\ngithub.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=\ngithub.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w=\ngithub.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=\ngithub.com/anchore/bubbly v0.0.0-20250717181826-8a411f9d8cbf h1:UY7SQkfVVaeGUpPZrJxqmTc8M0ZSWc5ChiKF6I6aL3I=\ngithub.com/anchore/bubbly v0.0.0-20250717181826-8a411f9d8cbf/go.mod h1:w8Br1ZKk1Nk82YRSh10pcD7LO7avPyFmNnaY1TRPgs0=\ngithub.com/anchore/clio v0.0.0-20260217161816-1b390cf973f8 h1:bMBDwRpDFGH86AGZwvERDPCn3sUl9Ezzjwya6docleI=\ngithub.com/anchore/clio v0.0.0-20260217161816-1b390cf973f8/go.mod h1:X9RG7xV3Uam2q050c0XcQv+BHgVS8Phr9BbSpnkcDNc=\ngithub.com/anchore/fangs v0.0.0-20260205223337-3833021a87e1 h1:wfmBzsWSaLHKktgyoDugnw3TYjIPOmkdgM8Oe9CvR7o=\ngithub.com/anchore/fangs v0.0.0-20260205223337-3833021a87e1/go.mod h1:yYsgDLrzipKlyDAzrjtd35lMcXyZ60b8Ko8vTaMwqoU=\ngithub.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c h1:eoJXyC0n7DZ4YvySG/ETdYkTar2Due7eH+UmLK6FbrA=\ngithub.com/anchore/go-collections v0.0.0-20251016125210-a3c352120e8c/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8=\ngithub.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d h1:gT69osH9AsdpOfqxbRwtxcNnSZ1zg4aKy2BevO3ZBdc=\ngithub.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d/go.mod h1:PhSnuFYknwPZkOWKB1jXBNToChBA+l0FjwOxtViIc50=\ngithub.com/anchore/go-logger v0.0.0-20260217144723-3bb369b8046c h1:AgdlwjTK8Lr+CA8Mq1gg1nxpSDbkLzmHATM8vr3d5do=\ngithub.com/anchore/go-logger v0.0.0-20260217144723-3bb369b8046c/go.mod h1:0l63X5VyHqfWQwsNaTmkgXErsfohze3NAFCXFdhSjdQ=\ngithub.com/anchore/go-lzo v0.1.0 h1:NgAacnzqPeGH49Ky19QKLBZEuFRqtTG9cdaucc3Vncs=\ngithub.com/anchore/go-lzo v0.1.0/go.mod h1:3kLx0bve2oN1iDwgM1U5zGku1Tfbdb0No5qp1eL1fIk=\ngithub.com/anchore/go-macholibre v0.0.0-20260203040931-2d1882573092 h1:Qd2kg6T/hW/KJSG6Y10dAuo+eQ7xU7TCMqegdNcUU34=\ngithub.com/anchore/go-macholibre v0.0.0-20260203040931-2d1882573092/go.mod h1:eu0gbwaZ+ocVFJLePdmPPDKU8MboV1MKsUCr36Ckd5s=\ngithub.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec h1:SjjPMOXTzpuU1ZME4XeoHyek+dry3/C7I8gzaCo02eg=\ngithub.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec/go.mod h1:eQVa6QFGzKy0qMcnW2pez0XBczvgwSjw9vA23qifEyU=\ngithub.com/anchore/go-struct-converter v0.1.0 h1:2rDRssAl6mgKBSLNiVCMADgZRhoqtw9dedlWa0OhD30=\ngithub.com/anchore/go-struct-converter v0.1.0/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=\ngithub.com/anchore/go-sync v0.0.0-20260122203928-582959aeb913 h1:oLusMayBRYlFy/E+6PDX77JRTFjLy6HpxFdP31b9Cqc=\ngithub.com/anchore/go-sync v0.0.0-20260122203928-582959aeb913/go.mod h1:G58yNg7ki6sPGmC88zS7lslJZvfdgQuf7b/GTnjTn5M=\ngithub.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8=\ngithub.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=\ngithub.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 h1:rmZG77uXgE+o2gozGEBoUMpX27lsku+xrMwlmBZJtbg=\ngithub.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=\ngithub.com/anchore/grype v0.109.1 h1:DASABCFZ+xM41dP9jCz9i43/GpN04C7efeq+KPr6/RE=\ngithub.com/anchore/grype v0.109.1/go.mod h1:UPOdf/+lggCHIYL6YAkTv0hsP226bloueGb2lawEfSE=\ngithub.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY=\ngithub.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI=\ngithub.com/anchore/stereoscope v0.1.21 h1:rIwPDjJQdOdIvMrkNyZFkUS5dSyQPDjAwUqU0XjVF74=\ngithub.com/anchore/stereoscope v0.1.21/go.mod h1:8652axKmO8itOcGX8gzAvHW3cVWvbxpJ4woLNMEO4a0=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=\ngithub.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=\ngithub.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=\ngithub.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/aquasecurity/go-pep440-version v0.0.1 h1:8VKKQtH2aV61+0hovZS3T//rUF+6GDn18paFTVS0h0M=\ngithub.com/aquasecurity/go-pep440-version v0.0.1/go.mod h1:3naPe+Bp6wi3n4l5iBFCZgS0JG8vY6FT0H4NGhFJ+i4=\ngithub.com/aquasecurity/go-version v0.0.1 h1:4cNl516agK0TCn5F7mmYN+xVs1E3S45LkgZk3cbaW2E=\ngithub.com/aquasecurity/go-version v0.0.1/go.mod h1:s1UU6/v2hctXcOa3OLwfj5d9yoXHa3ahf+ipSwEvGT0=\ngithub.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=\ngithub.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=\ngithub.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=\ngithub.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo=\ngithub.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c=\ngithub.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE=\ngithub.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY=\ngithub.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=\ngithub.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=\ngithub.com/aws/aws-sdk-go-v2 v1.41.2 h1:LuT2rzqNQsauaGkPK/7813XxcZ3o3yePY0Iy891T2ls=\ngithub.com/aws/aws-sdk-go-v2 v1.41.2/go.mod h1:IvvlAZQXvTXznUPfRVfryiG1fbzE2NGK6m9u39YQ+S4=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=\ngithub.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.10 h1:9DMthfO6XWZYLfzZglAgW5Fyou2nRI5CuV44sTedKBI=\ngithub.com/aws/aws-sdk-go-v2/config v1.32.10/go.mod h1:2rUIOnA2JaiqYmSKYmRJlcMWy6qTj1vuRFscppSBMcw=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 h1:Ii4s+Sq3yDfaMLpjrJsqD6SmG/Wq/P5L/hw2qa78UAY=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18/go.mod h1:6x81qnY++ovptLE6nWQeWrpXxbnlIex+4H4eYYGcqfc=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 h1:F43zk1vemYIqPAwhjTjYIz0irU2EY7sOb/F5eJ3HuyM=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18/go.mod h1:w1jdlZXrGKaJcNoL+Nnrj+k5wlpGXqnNrKoP22HvAug=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 h1:xCeWVjj0ki0l3nruoyP2slHsGArMxeiiaoPN5QZH6YQ=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18/go.mod h1:r/eLGuGCBw6l36ZRWiw6PaZwPXb6YOj+i/7MizNl5/k=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=\ngithub.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 h1:CeY9LUdur+Dxoeldqoun6y4WtJ3RQtzk0JMP2gfUay0=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5/go.mod h1:AZLZf2fMaahW5s/wMRciu1sYbdsikT/UHwbUjOdEVTc=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=\ngithub.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 h1:LTRCYFlnnKFlKsyIQxKhJuDuA3ZkrDQMRYm6rXiHlLY=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18/go.mod h1:XhwkgGG6bHSd00nO/mexWTcTjgd6PjuvWQMqSn2UaEk=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=\ngithub.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=\ngithub.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.6 h1:MzORe+J94I+hYu2a6XmV5yC9huoTv8NRcCrUNedDypQ=\ngithub.com/aws/aws-sdk-go-v2/service/signin v1.0.6/go.mod h1:hXzcHLARD7GeWnifd8j9RWqtfIgxj4/cAtIVIK7hg8g=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.11 h1:7oGD8KPfBOJGXiCoRKrrrQkbvCp8N++u36hrLMPey6o=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.30.11/go.mod h1:0DO9B5EUJQlIDif+XJRWCljZRKsAFKh3gpFz7UnDtOo=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 h1:edCcNp9eGIUDUCrzoCu1jWAXLGFIizeqkdkKgRlJwWc=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15/go.mod h1:lyRQKED9xWfgkYC/wmmYfv7iVIM68Z5OQ88ZdcV1QbU=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.7 h1:NITQpgo9A5NrDZ57uOWj+abvXSb83BbyggcUBVksN7c=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.41.7/go.mod h1:sks5UWBhEuWYDPdwlnRFn1w7xWdH29Jcpe+/PJQefEs=\ngithub.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0=\ngithub.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=\ngithub.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=\ngithub.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=\ngithub.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=\ngithub.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=\ngithub.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=\ngithub.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=\ngithub.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bitnami/go-version v0.0.0-20251209151629-b46c9d8f1f27 h1:YuYtreKQCWQ4nVexOCcoMcAJSESJXTNLKRCaaKMYL1s=\ngithub.com/bitnami/go-version v0.0.0-20251209151629-b46c9d8f1f27/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=\ngithub.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=\ngithub.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo=\ngithub.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=\ngithub.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=\ngithub.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=\ngithub.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=\ngithub.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI=\ngithub.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw=\ngithub.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=\ngithub.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=\ngithub.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=\ngithub.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=\ngithub.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=\ngithub.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=\ngithub.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=\ngithub.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=\ngithub.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ=\ngithub.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg=\ngithub.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8=\ngithub.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU=\ngithub.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=\ngithub.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=\ngithub.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE=\ngithub.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE=\ngithub.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg=\ngithub.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s=\ngithub.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=\ngithub.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=\ngithub.com/bufbuild/buf v1.66.1 h1:wqmmU+6uoxB/eYDOmXq2To4qEXvOJN7gR6L9AxrPL1E=\ngithub.com/bufbuild/buf v1.66.1/go.mod h1:Vd3ELm8IePWaDJaS9FLy94FFOnLrjLi4mDxmXtw9Xio=\ngithub.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156 h1:XOfIInPVufMjifwy3fli8qQVsGHWVCDVY/zp6elAOsY=\ngithub.com/bufbuild/protocompile v0.14.2-0.20260306221011-519528254156/go.mod h1:cxhE8h+14t0Yxq2H9MV/UggzQ1L0gh0t2tJobITWsBE=\ngithub.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1 h1:V1xulAoqLqVg44rY97xOR+mQpD2N+GzhMHVwJ030WEU=\ngithub.com/bufbuild/protoplugin v0.0.0-20250218205857-750e09ce93e1/go.mod h1:c5D8gWRIZ2HLWO3gXYTtUfw/hbJyD8xikv2ooPxnklQ=\ngithub.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=\ngithub.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=\ngithub.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E=\ngithub.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70=\ngithub.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=\ngithub.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=\ngithub.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ=\ngithub.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc=\ngithub.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc=\ngithub.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk=\ngithub.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4=\ngithub.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=\ngithub.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E=\ngithub.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=\ngithub.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=\ngithub.com/charmbracelet/colorprofile v0.4.2 h1:BdSNuMjRbotnxHSfxy+PCSa4xAmz7szw70ktAtWRYrY=\ngithub.com/charmbracelet/colorprofile v0.4.2/go.mod h1:0rTi81QpwDElInthtrQ6Ni7cG0sDtwAd4C4le060fT8=\ngithub.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=\ngithub.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=\ngithub.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=\ngithub.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=\ngithub.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=\ngithub.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=\ngithub.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=\ngithub.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=\ngithub.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=\ngithub.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=\ngithub.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=\ngithub.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=\ngithub.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs=\ngithub.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk=\ngithub.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=\ngithub.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g=\ngithub.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=\ngithub.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=\ngithub.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=\ngithub.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=\ngithub.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=\ngithub.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4=\ngithub.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=\ngithub.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=\ngithub.com/containerd/containerd/api v1.10.0 h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=\ngithub.com/containerd/containerd/api v1.10.0/go.mod h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=\ngithub.com/containerd/containerd/v2 v2.2.1 h1:TpyxcY4AL5A+07dxETevunVS5zxqzuq7ZqJXknM11yk=\ngithub.com/containerd/containerd/v2 v2.2.1/go.mod h1:NR70yW1iDxe84F2iFWbR9xfAN0N2F0NcjTi1OVth4nU=\ngithub.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=\ngithub.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=\ngithub.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=\ngithub.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=\ngithub.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=\ngithub.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=\ngithub.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=\ngithub.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=\ngithub.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=\ngithub.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=\ngithub.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4=\ngithub.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=\ngithub.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=\ngithub.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8=\ngithub.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=\ngithub.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=\ngithub.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=\ngithub.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=\ngithub.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=\ngithub.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=\ngithub.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=\ngithub.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=\ngithub.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=\ngithub.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=\ngithub.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=\ngithub.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ=\ngithub.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ=\ngithub.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY=\ngithub.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=\ngithub.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo=\ngithub.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=\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/deitch/magic v0.0.0-20240306090643-c67ab88f10cb h1:4W/2rQ3wzEimF5s+J6OY3ODiQtJZ5W1sForSgogVXkY=\ngithub.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=\ngithub.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=\ngithub.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=\ngithub.com/dghubble/trie v0.1.0 h1:kJnjBLFFElBwS60N4tkPvnLhnpcDxbBjIulgI8CpNGM=\ngithub.com/dghubble/trie v0.1.0/go.mod h1:sOmnzfBNH7H92ow2292dDFWNsVQuh/izuD7otCYb1ak=\ngithub.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=\ngithub.com/diskfs/go-diskfs v1.7.0 h1:vonWmt5CMowXwUc79jWyGrf2DIMeoOjkLlMnQYGVOs8=\ngithub.com/diskfs/go-diskfs v1.7.0/go.mod h1:LhQyXqOugWFRahYUSw47NyZJPezFzB9UELwhpszLP/k=\ngithub.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=\ngithub.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=\ngithub.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=\ngithub.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=\ngithub.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=\ngithub.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/dmarkham/enumer v1.6.3 h1:B4aV4OsfzbrS5rvjILt4mMjiWBA//cKxJUMsvHZ8mEI=\ngithub.com/dmarkham/enumer v1.6.3/go.mod h1:DyjXaqCglj4GhELF73oWiparNkYkXvmOBLza/o4kO74=\ngithub.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk=\ngithub.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=\ngithub.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=\ngithub.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=\ngithub.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=\ngithub.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=\ngithub.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=\ngithub.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=\ngithub.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=\ngithub.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=\ngithub.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=\ngithub.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=\ngithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=\ngithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=\ngithub.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=\ngithub.com/dsseng/syft v1.42.1-0.20260219105507-8cf142cbcb79 h1:j32iisjF/lFkyDMQ18zTZFi2ojbJxqAt5TovGryBXmQ=\ngithub.com/dsseng/syft v1.42.1-0.20260219105507-8cf142cbcb79/go.mod h1:uo2xEPi6gyc/qabZFv0Oni6W2pL0gE7sshAyZJCnHNg=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=\ngithub.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=\ngithub.com/elliotchance/phpserialize v1.4.0 h1:cAp/9+KSnEbUC8oYCE32n2n84BeW8HOY3HMDI8hG2OY=\ngithub.com/elliotchance/phpserialize v1.4.0/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=\ngithub.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab h1:h1UgjJdAAhj+uPL68n7XASS6bU+07ZX1WJvVS2eyoeY=\ngithub.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab/go.mod h1:GLo/8fDswSAniFG+BFIaiSPcK610jyzgEhWYPQwuQdw=\ngithub.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=\ngithub.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=\ngithub.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=\ngithub.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=\ngithub.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=\ngithub.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=\ngithub.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=\ngithub.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=\ngithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=\ngithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=\ngithub.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=\ngithub.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=\ngithub.com/facebookincubator/flog v0.0.0-20190930132826-d2511d0ce33c/go.mod h1:QGzNH9ujQ2ZUr/CjDGZGWeDAVStrWNjHeEcjJL96Nuk=\ngithub.com/facebookincubator/nvdtools v0.1.5 h1:jbmDT1nd6+k+rlvKhnkgMokrCAzHoASWE5LtHbX2qFQ=\ngithub.com/facebookincubator/nvdtools v0.1.5/go.mod h1:Kh55SAWnjckS96TBSrXI99KrEKH4iB0OJby3N8GRJO4=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=\ngithub.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA=\ngithub.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=\ngithub.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=\ngithub.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=\ngithub.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=\ngithub.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=\ngithub.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E=\ngithub.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=\ngithub.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=\ngithub.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=\ngithub.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0=\ngithub.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI=\ngithub.com/github/go-spdx/v2 v2.4.0 h1:+4IwVwJJbm3rzvrQ6P1nI9BDMcy3la4RchRy5uehV/M=\ngithub.com/github/go-spdx/v2 v2.4.0/go.mod h1:/5rwgS0txhGtRdUZwc02bTglzg6HK3FfuEbECKlK2Sg=\ngithub.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=\ngithub.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=\ngithub.com/gkampitakis/go-snaps v0.5.20 h1:FGKonEeQPJ12t7RQj6cTPa881fl5c8HYarMLv5vP7sg=\ngithub.com/gkampitakis/go-snaps v0.5.20/go.mod h1:gC3YqxQTPyIXvQrw/Vpt3a8VqR1MO8sVpZFWN4DGwNs=\ngithub.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=\ngithub.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=\ngithub.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=\ngithub.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=\ngithub.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=\ngithub.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=\ngithub.com/go-critic/go-critic v0.14.3 h1:5R1qH2iFeo4I/RJU8vTezdqs08Egi4u5p6vOESA0pog=\ngithub.com/go-critic/go-critic v0.14.3/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ=\ngithub.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=\ngithub.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=\ngithub.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0=\ngithub.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY=\ngithub.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=\ngithub.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=\ngithub.com/go-git/go-git/v5 v5.17.0 h1:AbyI4xf+7DsjINHMu35quAh4wJygKBKBuXVjV/pxesM=\ngithub.com/go-git/go-git/v5 v5.17.0/go.mod h1:f82C4YiLx+Lhi8eHxltLeGC5uBTXSFa6PC5WW9o4SjI=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=\ngithub.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=\ngithub.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=\ngithub.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc=\ngithub.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\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/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=\ngithub.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=\ngithub.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=\ngithub.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=\ngithub.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s=\ngithub.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw=\ngithub.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=\ngithub.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ=\ngithub.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw=\ngithub.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY=\ngithub.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco=\ngithub.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4=\ngithub.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA=\ngithub.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA=\ngithub.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk=\ngithub.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus=\ngithub.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=\ngithub.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=\ngithub.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=\ngithub.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=\ngithub.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=\ngithub.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=\ngithub.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=\ngithub.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=\ngithub.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=\ngithub.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=\ngithub.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=\ngithub.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=\ngithub.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=\ngithub.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=\ngithub.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=\ngithub.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=\ngithub.com/gocsaf/csaf/v3 v3.5.1 h1:jTA1fLrK0/JIczPs7itTD53qANoO4tn2VaGvUeitePc=\ngithub.com/gocsaf/csaf/v3 v3.5.1/go.mod h1:pga89lE+iWJm7smTdzYcXuetYUbgY8caXfaIP4BJG98=\ngithub.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5WSBQUeeM=\ngithub.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo=\ngithub.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=\ngithub.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/gohugoio/hashstructure v0.6.0 h1:7wMB/2CfXoThFYhdWRGv3u3rUM761Cq29CxUW+NltUg=\ngithub.com/gohugoio/hashstructure v0.6.0/go.mod h1:lapVLk9XidheHG1IQ4ZSbyYrXcaILU1ZEP/+vno5rBQ=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=\ngithub.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0=\ngithub.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ=\ngithub.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw=\ngithub.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E=\ngithub.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U=\ngithub.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss=\ngithub.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE=\ngithub.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=\ngithub.com/golangci/golangci-lint/v2 v2.11.3 h1:ySX1GtLwlwOEzcLKJifI/aIVesrcHDno+5mrro8rWes=\ngithub.com/golangci/golangci-lint/v2 v2.11.3/go.mod h1:HmDEVZuxz77cNLumPfNNHAFyMX/b7IbA0tpmAbwiVfo=\ngithub.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0=\ngithub.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10=\ngithub.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg=\ngithub.com/golangci/misspell v0.8.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg=\ngithub.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg=\ngithub.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw=\ngithub.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s=\ngithub.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=\ngithub.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM=\ngithub.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s=\ngithub.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM=\ngithub.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc=\ngithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc=\ngithub.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/cel-go v0.27.0 h1:e7ih85+4qVrBuqQWTW4FKSqZYokVuc3HnhH5keboFTo=\ngithub.com/google/cel-go v0.27.0/go.mod h1:tTJ11FWqnhw5KKpnWpvW9CJC3Y9GK4EIS0WXnBbebzw=\ngithub.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=\ngithub.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-containerregistry v0.21.2 h1:vYaMU4nU55JJGFC9JR/s8NZcTjbE9DBBbvusTW9NeS0=\ngithub.com/google/go-containerregistry v0.21.2/go.mod h1:ctO5aCaewH4AK1AumSF5DPW+0+R+d2FmylMJdp5G7p0=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=\ngithub.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=\ngithub.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=\ngithub.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=\ngithub.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=\ngithub.com/google/pprof v0.0.0-20260202012954-cb029daf43ef h1:xpF9fUHpoIrrjX24DURVKiwHcFpw19ndIs+FwTSMbno=\ngithub.com/google/pprof v0.0.0-20260202012954-cb029daf43ef/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=\ngithub.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\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/googleapis/enterprise-certificate-proxy v0.3.12 h1:Fg+zsqzYEs1ZnvmcztTYxhgCBsx3eEhEwQ1W/lHq/sQ=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.12/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=\ngithub.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=\ngithub.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=\ngithub.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=\ngithub.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=\ngithub.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=\ngithub.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=\ngithub.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA=\ngithub.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=\ngithub.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs=\ngithub.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw=\ngithub.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=\ngithub.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=\ngithub.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=\ngithub.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=\ngithub.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=\ngithub.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8=\ngithub.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc=\ngithub.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk=\ngithub.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY=\ngithub.com/gostaticanalysis/nilerr v0.1.2 h1:S6nk8a9N8g062nsx63kUkF6AzbHGw7zzyHMcpu52xQU=\ngithub.com/gostaticanalysis/nilerr v0.1.2/go.mod h1:A19UHhoY3y8ahoL7YKz6sdjDtduwTSI4CsymaC2htPA=\ngithub.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=\ngithub.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8=\ngithub.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs=\ngithub.com/gpustack/gguf-parser-go v0.24.0 h1:tdJceXYp9e5RhE9RwVYIuUpir72Jz2D68NEtDXkKCKc=\ngithub.com/gpustack/gguf-parser-go v0.24.0/go.mod h1:y4TwTtDqFWTK+xvprOjRUh+dowgU2TKCX37vRKvGiZ0=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=\ngithub.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4=\ngithub.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0=\ngithub.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 h1:0HADrxxqaQkGycO1JoUUA+B4FnIkuo8d2bz/hSaTFFQ=\ngithub.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70/go.mod h1:fm2FdDCzJdtbXF7WKAMvBb5NEPouXPHFbGNYs9ShFns=\ngithub.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=\ngithub.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=\ngithub.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-getter v1.8.4 h1:hGEd2xsuVKgwkMtPVufq73fAmZU/x65PPcqH3cb0D9A=\ngithub.com/hashicorp/go-getter v1.8.4/go.mod h1:x27pPGSg9kzoB147QXI8d/nDvp2IgYGcwuRjpaXE9Yg=\ngithub.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=\ngithub.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo=\ngithub.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=\ngithub.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=\ngithub.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=\ngithub.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=\ngithub.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=\ngithub.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=\ngithub.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=\ngithub.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=\ngithub.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=\ngithub.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=\ngithub.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=\ngithub.com/henvic/httpretty v0.1.4 h1:Jo7uwIRWVFxkqOnErcoYfH90o3ddQyVrSANeS4cxYmU=\ngithub.com/henvic/httpretty v0.1.4/go.mod h1:Dn60sQTZfbt2dYsdUSNsCljyF4AfdqnuJFDLJA1I4AM=\ngithub.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=\ngithub.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=\ngithub.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=\ngithub.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=\ngithub.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=\ngithub.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=\ngithub.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=\ngithub.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=\ngithub.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=\ngithub.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=\ngithub.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=\ngithub.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=\ngithub.com/jdx/go-netrc v1.0.0 h1:QbLMLyCZGj0NA8glAhxUpf1zDg6cxnWgMBbjq40W0gQ=\ngithub.com/jdx/go-netrc v1.0.0/go.mod h1:Gh9eFQJnoTNIRHXl2j5bJXA1u84hQWJWgGh569zF3v8=\ngithub.com/jedib0t/go-pretty/v6 v6.7.8 h1:BVYrDy5DPBA3Qn9ICT+PokP9cvCv1KaHv2i+Hc8sr5o=\ngithub.com/jedib0t/go-pretty/v6 v6.7.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=\ngithub.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4=\ngithub.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako=\ngithub.com/jhump/protoreflect/v2 v2.0.0-beta.2 h1:qZU+rEZUOYTz1Bnhi3xbwn+VxdXkLVeEpAeZzVXLY88=\ngithub.com/jhump/protoreflect/v2 v2.0.0-beta.2/go.mod h1:4tnOYkB/mq7QTyS3YKtVtNrJv4Psqout8HA1U+hZtgM=\ngithub.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=\ngithub.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=\ngithub.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=\ngithub.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=\ngithub.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=\ngithub.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=\ngithub.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=\ngithub.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=\ngithub.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8=\ngithub.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=\ngithub.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY=\ngithub.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0=\ngithub.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY=\ngithub.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 h1:WdAeg/imY2JFPc/9CST4bZ80nNJbiBFCAdSZCSgrS5Y=\ngithub.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953/go.mod h1:6o+UrvuZWc4UTyBhQf0LGjW9Ld7qJxLz/OqvSOWWlEc=\ngithub.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY=\ngithub.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=\ngithub.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/errcheck v1.10.0 h1:Lvs/YAHP24YKg08LA8oDw2z9fJVme090RAXd90S+rrw=\ngithub.com/kisielk/errcheck v1.10.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE=\ngithub.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg=\ngithub.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=\ngithub.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=\ngithub.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=\ngithub.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg=\ngithub.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8=\ngithub.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 h1:dWzdsqjh1p2gNtRKqNwuBvKqMNwnLOPLzVZT1n6DK7s=\ngithub.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23/go.mod h1:lUaIXCWzf7BRKTY5iEcrYy1TfgbYLYVIS/B2vPkJzOc=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98=\ngithub.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs=\ngithub.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w=\ngithub.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk=\ngithub.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=\ngithub.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=\ngithub.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ=\ngithub.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM=\ngithub.com/ldez/gomoddirectives v0.8.0 h1:JqIuTtgvFC2RdH1s357vrE23WJF2cpDCPFgA/TWDGpk=\ngithub.com/ldez/gomoddirectives v0.8.0/go.mod h1:jutzamvZR4XYJLr0d5Honycp4Gy6GEg2mS9+2YX3F1Q=\ngithub.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o=\ngithub.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas=\ngithub.com/ldez/structtags v0.6.1 h1:bUooFLbXx41tW8SvkfwfFkkjPYvFFs59AAMgVg6DUBk=\ngithub.com/ldez/structtags v0.6.1/go.mod h1:YDxVSgDy/MON6ariaxLF2X09bh19qL7MtGBN5MrvbdY=\ngithub.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk=\ngithub.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI=\ngithub.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc=\ngithub.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ=\ngithub.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=\ngithub.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=\ngithub.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=\ngithub.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=\ngithub.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=\ngithub.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=\ngithub.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=\ngithub.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=\ngithub.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE=\ngithub.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U=\ngithub.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\ngithub.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=\ngithub.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=\ngithub.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=\ngithub.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=\ngithub.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww=\ngithub.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM=\ngithub.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8=\ngithub.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA=\ngithub.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8=\ngithub.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ=\ngithub.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs=\ngithub.com/maratori/testpackage v1.1.2/go.mod h1:8F24GdVDFW5Ew43Et02jamrVMNXLUNaOynhDssITGfc=\ngithub.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=\ngithub.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=\ngithub.com/masahiro331/go-mvn-version v0.0.0-20260119054159-d21fcd2e7de1 h1:XC9v1PB6rMOCTnQIInoFvgSA+vhTCt0wQ7B+Tjpombk=\ngithub.com/masahiro331/go-mvn-version v0.0.0-20260119054159-d21fcd2e7de1/go.mod h1:jZ3F25l7DbD7l7DcA8aj7eo1EZ84nbzcQHBB4lCSrI8=\ngithub.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4=\ngithub.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs=\ngithub.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=\ngithub.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=\ngithub.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=\ngithub.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=\ngithub.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=\ngithub.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=\ngithub.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=\ngithub.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 h1:P8UmIzZMYDR+NGImiFvErt6VWfIRPuGM+vyjiEdkmIw=\ngithub.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=\ngithub.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=\ngithub.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=\ngithub.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mgechev/revive v1.15.0 h1:vJ0HzSBzfNyPbHKolgiFjHxLek9KUijhqh42yGoqZ8Q=\ngithub.com/mgechev/revive v1.15.0/go.mod h1:LlAKO3QQe9OJ0pVZzI2GPa8CbXGZ/9lNpCGvK4T/a8A=\ngithub.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=\ngithub.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=\ngithub.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ=\ngithub.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4=\ngithub.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=\ngithub.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=\ngithub.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=\ngithub.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=\ngithub.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=\ngithub.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=\ngithub.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=\ngithub.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=\ngithub.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=\ngithub.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=\ngithub.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=\ngithub.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=\ngithub.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=\ngithub.com/moby/moby/api v1.53.0 h1:PihqG1ncw4W+8mZs69jlwGXdaYBeb5brF6BL7mPIS/w=\ngithub.com/moby/moby/api v1.53.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=\ngithub.com/moby/moby/client v0.2.2 h1:Pt4hRMCAIlyjL3cr8M5TrXCwKzguebPAc2do2ur7dEM=\ngithub.com/moby/moby/client v0.2.2/go.mod h1:2EkIPVNCqR05CMIzL1mfA07t0HvVUUOl85pasRz/GmQ=\ngithub.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=\ngithub.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=\ngithub.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=\ngithub.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=\ngithub.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=\ngithub.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=\ngithub.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=\ngithub.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=\ngithub.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=\ngithub.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=\ngithub.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=\ngithub.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=\ngithub.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=\ngithub.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=\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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=\ngithub.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=\ngithub.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=\ngithub.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=\ngithub.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=\ngithub.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=\ngithub.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=\ngithub.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=\ngithub.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=\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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos=\ngithub.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=\ngithub.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=\ngithub.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=\ngithub.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=\ngithub.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=\ngithub.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg=\ngithub.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=\ngithub.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=\ngithub.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=\ngithub.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 h1:kpt9ZfKcm+EDG4s40hMwE//d5SBgDjUOrITReV2u4aA=\ngithub.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1/go.mod h1:qgCw4bBKZX8qMgGeEZzGFVT3notl42dBjNqO2jut0M0=\ngithub.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE=\ngithub.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=\ngithub.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8=\ngithub.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4=\ngithub.com/nwaples/rardecode/v2 v2.2.2 h1:/5oL8dzYivRM/tqX9VcTSWfbpwcbwKG1QtSJr3b3KcU=\ngithub.com/nwaples/rardecode/v2 v2.2.2/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=\ngithub.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=\ngithub.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=\ngithub.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo=\ngithub.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=\ngithub.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA=\ngithub.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88=\ngithub.com/olekukonko/tablewriter v1.1.3 h1:VSHhghXxrP0JHl+0NnKid7WoEmd9/urKRJLysb70nnA=\ngithub.com/olekukonko/tablewriter v1.1.3/go.mod h1:9VU0knjhmMkXjnMKrZ3+L2JhhtsQ/L38BbL3CRNE8tM=\ngithub.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=\ngithub.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=\ngithub.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=\ngithub.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=\ngithub.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=\ngithub.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=\ngithub.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=\ngithub.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=\ngithub.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=\ngithub.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=\ngithub.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE=\ngithub.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg=\ngithub.com/openvex/go-vex v0.2.7 h1:/pN3bqvS4QOc6WkkL0hbKzJuAtsUD9vmvk9IZkzD3Zc=\ngithub.com/openvex/go-vex v0.2.7/go.mod h1:ZyQC3NXl9jjS53JOpBG3LAUXySkW8IlJ/GIhsnf5D54=\ngithub.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=\ngithub.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=\ngithub.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=\ngithub.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=\ngithub.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=\ngithub.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=\ngithub.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=\ngithub.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=\ngithub.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 h1:FvA4bwjKpPqik5WsQ8+4z4DKWgA1tO1RTTtNKr5oYNA=\ngithub.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554/go.mod h1:n73K/hcuJ50MiVznXyN4rde6fZY7naGKWBXOLFTyc94=\ngithub.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoXLtmE3I0PLs=\ngithub.com/package-url/packageurl-go v0.1.3/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0=\ngithub.com/pandatix/go-cvss v0.6.2 h1:TFiHlzUkT67s6UkelHmK6s1INKVUG7nlKYiWWDTITGI=\ngithub.com/pandatix/go-cvss v0.6.2/go.mod h1:jDXYlQBZrc8nvrMUVVvTG8PhmuShOnKrxP53nOFkt8Q=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pascaldekloe/name v1.0.1 h1:9lnXOHeqeHHnWLbKfH6X98+4+ETVqFqxN09UXSjcMb0=\ngithub.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM=\ngithub.com/pborman/indent v1.2.1 h1:lFiviAbISHv3Rf0jcuh489bi06hj98JsVMtIDZQb9yM=\ngithub.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrpz5K6Vw=\ngithub.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=\ngithub.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=\ngithub.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=\ngithub.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE=\ngithub.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=\ngithub.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=\ngithub.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=\ngithub.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=\ngithub.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=\ngithub.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=\ngithub.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=\ngithub.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=\ngithub.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=\ngithub.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=\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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=\ngithub.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=\ngithub.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=\ngithub.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9 h1:arwj11zP0yJIxIRiDn22E0H8PxfF7TsTrc2wIPFIsf4=\ngithub.com/protocolbuffers/protoscope v0.0.0-20221109213918-8e7a6aafa2c9/go.mod h1:SKZx6stCn03JN3BOWTwvVIO2ajMkb/zQdTceXYhKw/4=\ngithub.com/pseudomuto/protoc-gen-doc v1.5.1 h1:Ah259kcrio7Ix1Rhb6u8FCaOkzf9qRBqXnvAufg061w=\ngithub.com/pseudomuto/protoc-gen-doc v1.5.1/go.mod h1:XpMKYg6zkcpgfpCfQ8GcWBDRtRxOmMR5w7pz4Xo+dYM=\ngithub.com/pseudomuto/protokit v0.2.1 h1:kCYpE3thoR6Esm0CUvd5xbrDTOZPvQPTDeyXpZfrJdk=\ngithub.com/pseudomuto/protokit v0.2.1/go.mod h1:gt7N5Rz2flBzYafvaxyIxMZC0TTF5jDZfRnw25hAAyo=\ngithub.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA=\ngithub.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE=\ngithub.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY=\ngithub.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=\ngithub.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=\ngithub.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=\ngithub.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU=\ngithub.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=\ngithub.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=\ngithub.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=\ngithub.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=\ngithub.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=\ngithub.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=\ngithub.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=\ngithub.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI=\ngithub.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=\ngithub.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=\ngithub.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=\ngithub.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c h1:8gOLsYwaY2JwlTMT4brS5/9XJdrdIbmk2obvQ748CC0=\ngithub.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c/go.mod h1:kwM/7r/rVluTE8qJbHAffduuqmSv4knVQT2IajGvSiA=\ngithub.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g=\ngithub.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I=\ngithub.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=\ngithub.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=\ngithub.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=\ngithub.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=\ngithub.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=\ngithub.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=\ngithub.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=\ngithub.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=\ngithub.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rYg=\ngithub.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=\ngithub.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=\ngithub.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=\ngithub.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=\ngithub.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=\ngithub.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=\ngithub.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ=\ngithub.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8=\ngithub.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=\ngithub.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=\ngithub.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=\ngithub.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=\ngithub.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/sebdah/goldie/v2 v2.8.0 h1:dZb9wR8q5++oplmEiJT+U/5KyotVD+HNGCAc5gNr8rc=\ngithub.com/sebdah/goldie/v2 v2.8.0/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=\ngithub.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08 h1:AoLtJX4WUtZkhhUUMFy3GgecAALp/Mb4S1iyQOA2s0U=\ngithub.com/securego/gosec/v2 v2.24.8-0.20260309165252-619ce2117e08/go.mod h1:+XLCJiRE95ga77XInNELh2M6zQP+PdqiT9Zpm0D9Wpk=\ngithub.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=\ngithub.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=\ngithub.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=\ngithub.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=\ngithub.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=\ngithub.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=\ngithub.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=\ngithub.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=\ngithub.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=\ngithub.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=\ngithub.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=\ngithub.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=\ngithub.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=\ngithub.com/siderolabs/deep-copy v0.5.8 h1:43G8qJBTwGuKZX+UYNe29ZOtyDFqayS7/GfJVviz6RU=\ngithub.com/siderolabs/deep-copy v0.5.8/go.mod h1:PNX2/lqNu3oyDZGWe1eKW8bkYkhs583WcUBBB2EviX8=\ngithub.com/siderolabs/gen v0.8.6 h1:pE6shuqov3L+5rEcAUJ/kY6iJofimljQw5G95P8a5c4=\ngithub.com/siderolabs/gen v0.8.6/go.mod h1:J9IbusbES2W6QWjtSHpDV9iPGZHc978h1+KJ4oQRspQ=\ngithub.com/siderolabs/importvet v0.2.0 h1:oGQXke2/TnSg5xEFD/ktc+G59INzmgRU3yJ8wt++QRE=\ngithub.com/siderolabs/importvet v0.2.0/go.mod h1:X0AIl/3MnvlEeCzYRJe/t9YOk4FjPhT53doU4xOG4AU=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=\ngithub.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=\ngithub.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=\ngithub.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=\ngithub.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg=\ngithub.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow=\ngithub.com/smallnest/ringbuffer v0.1.1 h1:KL2iILLdDCr9nWxYrNcsQ7Px7EVnoNBDJ0r/M/hEksA=\ngithub.com/smallnest/ringbuffer v0.1.1/go.mod h1:tAG61zBM1DYRaGIPloumExGvScf08oHuo0kFoOqdbT0=\ngithub.com/sonatard/noctx v0.5.0 h1:e/jdaqAsuWVOKQ0P6NWiIdDNHmHT5SwuuSfojFjzwrw=\ngithub.com/sonatard/noctx v0.5.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas=\ngithub.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=\ngithub.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=\ngithub.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=\ngithub.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb h1:7G2Czq97VORM5xNRrD8tSQdhoXPRs8s+Otlc7st9TS0=\ngithub.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=\ngithub.com/spdx/tools-golang v0.5.7 h1:+sWcKGnhwp3vLdMqPcLdA6QK679vd86cK9hQWH3AwCg=\ngithub.com/spdx/tools-golang v0.5.7/go.mod h1:jg7w0LOpoNAw6OxKEzCoqPC2GCTj45LyTlVmXubDsYw=\ngithub.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=\ngithub.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=\ngithub.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=\ngithub.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=\ngithub.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=\ngithub.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=\ngithub.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=\ngithub.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=\ngithub.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=\ngithub.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=\ngithub.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=\ngithub.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=\ngithub.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g=\ngithub.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=\ngithub.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=\ngithub.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=\ngithub.com/sylabs/sif/v2 v2.23.0 h1:VWJC7iryINdIgyIK8EdxMCJkx8EDPVlvFaskgY+ruFk=\ngithub.com/sylabs/sif/v2 v2.23.0/go.mod h1:0UJk7MMSQS2n/95yYd+CvAfK7K2mE0aWHRYYybd+ouw=\ngithub.com/sylabs/squashfs v1.0.6 h1:PvJcDzxr+vIm2kH56mEMbaOzvGu79gK7P7IX+R7BDZI=\ngithub.com/sylabs/squashfs v1.0.6/go.mod h1:DlDeUawVXLWAsSRa085Eo0ZenGzAB32JdAUFaB0LZfE=\ngithub.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=\ngithub.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=\ngithub.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=\ngithub.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=\ngithub.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo=\ngithub.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=\ngithub.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg=\ngithub.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU=\ngithub.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=\ngithub.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=\ngithub.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=\ngithub.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=\ngithub.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA=\ngithub.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=\ngithub.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=\ngithub.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=\ngithub.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=\ngithub.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=\ngithub.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0=\ngithub.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M=\ngithub.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M=\ngithub.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=\ngithub.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is=\ngithub.com/tomarrell/wrapcheck/v2 v2.12.0/go.mod h1:AQhQuZd0p7b6rfW+vUwHm5OMCGgp63moQ9Qr/0BpIWo=\ngithub.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=\ngithub.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=\ngithub.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=\ngithub.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA=\ngithub.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g=\ngithub.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=\ngithub.com/uudashr/gocognit v1.2.1 h1:CSJynt5txTnORn/DkhiB4mZjwPuifyASC8/6Q0I/QS4=\ngithub.com/uudashr/gocognit v1.2.1/go.mod h1:acaubQc6xYlXFEMb9nWX2dYBzJ/bIjEkc1zzvyIZg5Q=\ngithub.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU=\ngithub.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg=\ngithub.com/vbatts/go-mtree v0.7.0 h1:ytmOc3MTRidZiBi9VBCyZ2BHe4fZS47L5v7BVXDWW4E=\ngithub.com/vbatts/go-mtree v0.7.0/go.mod h1:EjdpFC+LZy1TXbRGNa1MKKgjQ+7ew3foMFJK8o4/TdY=\ngithub.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=\ngithub.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=\ngithub.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0=\ngithub.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o=\ngithub.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=\ngithub.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=\ngithub.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA=\ngithub.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20=\ngithub.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b h1:uWNQ0khA6RdFzODOMwKo9XXu7fuewnnkHykUtuKru8s=\ngithub.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b/go.mod h1:ewlIKbKV8l+jCj8rkdXIs361ocR5x3qGyoCSca47Gx8=\ngithub.com/wagoodman/go-progress v0.0.0-20260303201901-10176f79b2c0 h1:EHsPe0Q0ANoLOZff1dBLAyeWLTA4sbPTpGI+2zb0FnM=\ngithub.com/wagoodman/go-progress v0.0.0-20260303201901-10176f79b2c0/go.mod h1:g/D9uEUFp5YLyciwCpVsSOZOm56hfv4rzGJod6MlqIM=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=\ngithub.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=\ngithub.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=\ngithub.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=\ngithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=\ngithub.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=\ngithub.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=\ngithub.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=\ngithub.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM=\ngithub.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4=\ngithub.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=\ngithub.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=\ngithub.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=\ngithub.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=\ngithub.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=\ngithub.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=\ngithub.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs=\ngithub.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4=\ngithub.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw=\ngithub.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/zclconf/go-cty v1.14.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=\ngithub.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0=\ngithub.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=\ngithub.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1 h1:V+UsotZpAVvfj3X/LMoEytoLzSiP6Lg0F7wdVyu9gGg=\ngithub.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis=\ngitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo=\ngitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=\ngo-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=\ngo-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=\ngo-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo=\ngo-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE=\ngo-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s=\ngo-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ=\ngo.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50=\ngo.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA=\ngo.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE=\ngo.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw=\ngo.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=\ngo.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=\ngo.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=\ngo.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=\ngo.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI=\ngo.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac=\ngo.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 h1:hCzQgh6UcwbKgNSRurYWSqh8MufqRRPODRBblutn4TE=\ngo.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2/go.mod h1:gtSHRuYfbCT0qnbLnovpie/WEmqyJ7T4n6VXiFMBtcw=\ngo.lsp.dev/protocol v0.12.0 h1:tNprUI9klQW5FAFVM4Sa+AbPFuVQByWhP1ttNUAjIWg=\ngo.lsp.dev/protocol v0.12.0/go.mod h1:Qb11/HgZQ72qQbeyPfJbu3hZBH23s1sr4st8czGeDMQ=\ngo.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo=\ngo.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=\ngo.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/contrib/detectors/gcp v1.40.0 h1:Awaf8gmW99tZTOWqkLCOl6aw1/rxAWVlHsHIZ3fT2sA=\ngo.opentelemetry.io/contrib/detectors/gcp v1.40.0/go.mod h1:99OY9ZCqyLkzJLTh5XhECpLRSxcZl+ZDKBEO+jMBFR4=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=\ngo.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=\ngo.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8=\ngo.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0/go.mod h1:0fBG6ZJxhqByfFZDwSwpZGzJU671HkwpWaNe2t4VUPI=\ngo.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=\ngo.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=\ngo.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=\ngo.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=\ngo.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=\ngo.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=\ngo.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=\ngo.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngo.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=\ngo.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=\ngo.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=\ngo.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=\ngo.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=\ngo.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=\ngo.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=\ngo.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=\ngo.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=\ngo.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=\ngo4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw=\ngo4.org v0.0.0-20260112195520-a5071408f32f/go.mod h1:ZRJnO5ZI4zAwMFp+dS1+V6J6MSyAowhRqAE+DPa1Xp0=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=\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/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0=\ngolang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=\ngolang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=\ngolang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=\ngolang.org/x/exp/typeparams v0.0.0-20260218203240-3dfff04db8fa h1:6Wi43P0isP8Nl8D4qJmA3VC4FswVH0RJkr5cauo67SQ=\ngolang.org/x/exp/typeparams v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:PqrXSW65cXDZH0k4IeUbhmg/bcAZDbzNz3byBpKCsXo=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\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/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=\ngolang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=\ngolang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=\ngolang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc=\ngolang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=\ngolang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=\ngolang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=\ngolang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=\ngolang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=\ngolang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=\ngolang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=\ngolang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=\ngolang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=\ngolang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=\ngolang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=\ngolang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=\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=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=\ngonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=\ngonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=\ngoogle.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=\ngoogle.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=\ngoogle.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=\ngoogle.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=\ngoogle.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=\ngoogle.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=\ngoogle.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=\ngoogle.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=\ngoogle.golang.org/api v0.267.0 h1:w+vfWPMPYeRs8qH1aYYsFX68jMls5acWl/jocfLomwE=\ngoogle.golang.org/api v0.267.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=\ngoogle.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=\ngoogle.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d h1:vsOm753cOAMkt76efriTCDKjpCbK18XGHMJHo0JUKhc=\ngoogle.golang.org/genproto v0.0.0-20260217215200-42d3e9bedb6d/go.mod h1:0oz9d7g9QLSdv9/lgbIjowW1JoxMbxmBVNe8i6tORJI=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=\ngoogle.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 h1:/WILD1UcXj/ujCxgoL/DvRgt2CP3txG8+FwkUbb9110=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1/go.mod h1:YNKnb2OAApgYn2oYY47Rn7alMr1zWjb2U8Q0aoGWiNc=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/typ.v4 v4.4.0 h1:O9vTueEmZd0iA9DF+g2wXeNCeloN2TOpxu6FXKl3AqM=\ngopkg.in/typ.v4 v4.4.0/go.mod h1:wolXe8DlewxRCjA7SOiT3zjrZ0eQJZcr8cmV6bQWJUM=\ngopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=\ngopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=\ngorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=\ngotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=\ngotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU=\nhonnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc=\nk8s.io/code-generator v0.35.2 h1:3874swbO2c26VWTf6lKD4NWGyHIfyBeTCk7caCG3TuU=\nk8s.io/code-generator v0.35.2/go.mod h1:id4XLCm0yAQq5nlvyfAKibMOKnMjzlesAwGw6kM3Adc=\nk8s.io/gengo/v2 v2.0.0-20251215205346-5ee0d033ba5b h1:0YkdvW3rX2vaBWsqCGZAekxPRwaI5NuYNprOsMNVLns=\nk8s.io/gengo/v2 v2.0.0-20251215205346-5ee0d033ba5b/go.mod h1:yvyl3l9E+UxlqOMUULdKTAYB0rEhsmjr7+2Vb/1pCSo=\nk8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=\nk8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=\nmodernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=\nmodernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=\nmodernc.org/ccgo/v4 v4.30.2 h1:4yPaaq9dXYXZ2V8s1UgrC3KIj580l2N4ClrLwnbv2so=\nmodernc.org/ccgo/v4 v4.30.2/go.mod h1:yZMnhWEdW0qw3EtCndG1+ldRrVGS+bIwyWmAWzS0XEw=\nmodernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=\nmodernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=\nmodernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=\nmodernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=\nmodernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=\nmodernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=\nmodernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=\nmodernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=\nmodernc.org/libc v1.68.0 h1:PJ5ikFOV5pwpW+VqCK1hKJuEWsonkIJhhIXyuF/91pQ=\nmodernc.org/libc v1.68.0/go.mod h1:NnKCYeoYgsEqnY3PgvNgAeaJnso968ygU8Z0DxjoEc0=\nmodernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=\nmodernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=\nmodernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=\nmodernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=\nmodernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=\nmodernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=\nmodernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=\nmodernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=\nmodernc.org/sqlite v1.46.1 h1:eFJ2ShBLIEnUWlLy12raN0Z1plqmFX9Qe3rjQTKt6sU=\nmodernc.org/sqlite v1.46.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=\nmodernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=\nmodernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=\nmodernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=\nmodernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=\nmvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4=\nmvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s=\nmvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI=\nmvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU=\nmvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=\nmvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=\npgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=\npgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=\npluginrpc.com/pluginrpc v0.5.0 h1:tOQj2D35hOmvHyPu8e7ohW2/QvAnEtKscy2IJYWQ2yo=\npluginrpc.com/pluginrpc v0.5.0/go.mod h1:UNWZ941hcVAoOZUn8YZsMmOZBzbUjQa3XMns8RQLp9o=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "tools/gotagsrewrite/ast.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n)\n\n// parseAst parses the given Go source file and returns the AST.\nfunc parseAst(fset *token.FileSet, path string) (*ast.File, error) {\n\tf, err := parser.ParseFile(fset, path, nil, parser.ParseComments)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn f, nil\n}\n\n// findAllStructs with comments finds all structs in the given AST.\nfunc findAllStructs(f ast.Node) []*ast.TypeSpec {\n\tvar nodes []*ast.TypeSpec\n\n\tast.Inspect(f, func(n ast.Node) bool {\n\t\tgenDecl, ok := n.(*ast.GenDecl)\n\t\tif !ok || genDecl.Tok != token.TYPE {\n\t\t\treturn true\n\t\t}\n\n\t\ttypeSpecs := filter(genDecl.Specs, typeSpecFilter)\n\n\t\tswitch len(typeSpecs) {\n\t\tcase 0:\n\t\t\treturn false\n\t\tcase 1:\n\t\t\tif isTarget(genDecl.Doc) || isTarget(typeSpecs[0].Doc) {\n\t\t\t\tnodes = append(nodes, typeSpecs[0])\n\t\t\t}\n\n\t\t\treturn false\n\t\tdefault:\n\t\t\tfor _, typeSpec := range typeSpecs {\n\t\t\t\tif isTarget(typeSpec.Doc) {\n\t\t\t\t\tnodes = append(nodes, typeSpec)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t}\n\t})\n\n\treturn nodes\n}\n\nfunc typeSpecFilter(n ast.Spec) (*ast.TypeSpec, bool) {\n\ttypeSpec, ok := n.(*ast.TypeSpec)\n\tif !ok {\n\t\treturn typeSpec, false\n\t}\n\n\tstructType, ok := typeSpec.Type.(*ast.StructType)\n\tif !ok {\n\t\treturn typeSpec, false\n\t}\n\n\tif structType.Fields.NumFields() == 0 {\n\t\treturn typeSpec, false\n\t}\n\n\tif !isCapitalCase(typeSpec.Name.Name) {\n\t\treturn typeSpec, false\n\t}\n\n\treturn typeSpec, true\n}\n\nfunc isTarget(doc *ast.CommentGroup) bool {\n\tif doc == nil {\n\t\treturn false\n\t}\n\n\tfor _, c := range doc.List {\n\t\tif c.Text == \"//gotagsrewrite:gen\" {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc filter[T, V any](slc []T, f func(n T) (V, bool)) []V {\n\tvar result []V\n\n\tfor _, v := range slc {\n\t\tres, ok := f(v)\n\t\tif ok {\n\t\t\tresult = append(result, res)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "tools/gotagsrewrite/go.mod",
    "content": "module github.com/siderolabs/talos/tools/gotagsrewrite\n\ngo 1.26.0\n\nrequire (\n\tgithub.com/fatih/structtag v1.2.0\n\tgithub.com/spf13/cobra v1.10.2\n\tgithub.com/stretchr/testify v1.11.1\n)\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/kr/pretty v0.3.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/spf13/pflag v1.0.9 // indirect\n\tgopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "tools/gotagsrewrite/go.sum",
    "content": "github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=\ngithub.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "tools/gotagsrewrite/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/format\"\n\t\"go/token\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/fatih/structtag\"\n\t\"github.com/spf13/cobra\"\n)\n\n// rootCmd represents the base command when called without any subcommands.\nvar rootCmd = &cobra.Command{\n\tUse:     \"gotagsrewrite path\",\n\tShort:   \"This CLI is used to add `protobuf:<n>` tags to structs with //gotagsrewrite:gen comment\",\n\tExample: \"gotagsrewrite .\",\n\tArgs:    cobra.ExactArgs(1),\n\tVersion: \"v1.0.0\",\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn Run(args[0])\n\t},\n\tSilenceUsage:      true,\n\tDisableAutoGenTag: true,\n}\n\nfunc main() {\n\terr := rootCmd.Execute()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n}\n\n// Run runs the main logic of the program.\nfunc Run(path string) error {\n\tpaths, err := findGoFiles(path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find Go files: %w\", err)\n\t}\n\n\tfilesAndStructs := map[string]fileStruct{}\n\ttokenSet := token.NewFileSet()\n\n\tfor _, path := range paths {\n\t\tparsedAST, err := parseAst(tokenSet, path) //nolint:govet\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse AST for %s: %w\", path, err)\n\t\t}\n\n\t\tstructs := findAllStructs(parsedAST)\n\t\tif len(structs) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfilesAndStructs[path] = fileStruct{\n\t\t\tpath:    path,\n\t\t\tfullAST: parsedAST,\n\t\t\tstructs: append(filesAndStructs[path].structs, structs...),\n\t\t}\n\t}\n\n\terr = updateStructs(filesAndStructs, tokenSet)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc updateStructs(filesAndStructs map[string]fileStruct, tokenSet *token.FileSet) error {\n\tfor path, val := range filesAndStructs {\n\t\tfor _, t := range val.structs {\n\t\t\terr := updateProtoTags(t)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tgoFile, err := os.OpenFile(path, os.O_RDWR|os.O_TRUNC, os.ModePerm)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to open file %s: %w\", path, err)\n\t\t\t}\n\n\t\t\terr = format.Node(goFile, tokenSet, val.fullAST)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\tfmt.Printf(\"updated %s\\n\", path)\n\t}\n\n\treturn nil\n}\n\n// findGoFiles recursevly finds all Go files in the given directory.\nfunc findGoFiles(dir string) ([]string, error) {\n\tvar files []string\n\n\terr := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\n\t\tif info.Name() == \"testdata\" || strings.HasPrefix(info.Name(), \".\") {\n\t\t\treturn nil\n\t\t}\n\n\t\tif strings.HasSuffix(path, \".go\") {\n\t\t\tfiles = append(files, path)\n\t\t}\n\n\t\treturn nil\n\t})\n\n\treturn files, err\n}\n\ntype fileStruct struct {\n\tpath    string\n\tfullAST *ast.File\n\tstructs []*ast.TypeSpec\n}\n\nfunc updateProtoTags(t *ast.TypeSpec) error {\n\tstructNode := t.Type.(*ast.StructType) //nolint:errcheck\n\n\tnum, err := findHighestProtoNum(structNode)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update proto tags for %s: %w\", t.Name.Name, err)\n\t}\n\n\tif num == -1 {\n\t\treturn nil\n\t}\n\n\terr = forEachFieldTag(structNode, func(tags *structtag.Tags) (*structtag.Tags, error) {\n\t\t_, err := tags.Get(\"protobuf\") //nolint:govet\n\t\tif err == nil {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tnum++\n\t\tnewTag := &structtag.Tag{\n\t\t\tKey:     \"protobuf\",\n\t\t\tName:    strconv.Itoa(num),\n\t\t\tOptions: nil,\n\t\t}\n\n\t\ttags.Set(newTag) //nolint:errcheck\n\n\t\treturn tags, nil\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// findHighestProtoNum returns the highest proto num in the given struct.\n// It returns -1 if struct has no exported fields. It returns 0 if there is no fields with \"protobuf\" tag.\n// Otherwise, it returns the highest proto num extracted from the fields tags.\nfunc findHighestProtoNum(structNode *ast.StructType) (int, error) {\n\thighestNum := -1\n\n\terr := forEachFieldTag(structNode, func(tags *structtag.Tags) (*structtag.Tags, error) {\n\t\tif highestNum == -1 {\n\t\t\thighestNum = 0\n\t\t}\n\n\t\ttag, err := tags.Get(\"protobuf\")\n\t\tif err != nil {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tnum, err := strconv.Atoi(tag.Name)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\thighestNum = max(highestNum, num)\n\n\t\treturn nil, nil\n\t})\n\n\treturn highestNum, err\n}\n\nfunc forEachFieldTag(structNode *ast.StructType, fn func(tags *structtag.Tags) (*structtag.Tags, error)) error {\n\tfor _, field := range structNode.Fields.List {\n\t\tif len(field.Names) < 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfieldName := field.Names[0]\n\t\tif fieldName == nil || !isCapitalCase(fieldName.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttags := &structtag.Tags{}\n\t\ttagValue := \"\"\n\n\t\tif field.Tag != nil {\n\t\t\ttagValue = strings.Trim(field.Tag.Value, \"`\")\n\n\t\t\tvar err error\n\n\t\t\ttags, err = structtag.Parse(tagValue)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid tag: field '%s', tag '%s': %w\", fieldName.Name, tagValue, err)\n\t\t\t}\n\t\t}\n\n\t\tnewTags, err := fn(tags)\n\n\t\tswitch {\n\t\tcase err != nil:\n\t\t\treturn fmt.Errorf(\"tag failure: field '%s', tag '%s': %w\", fieldName.Name, tagValue, err)\n\t\tcase newTags == nil:\n\t\t\tcontinue\n\t\t}\n\n\t\tif field.Tag == nil {\n\t\t\tfield.Tag = &ast.BasicLit{\n\t\t\t\tKind: token.STRING,\n\t\t\t}\n\t\t}\n\n\t\tfield.Tag.Value = \"`\" + newTags.String() + \"`\"\n\t}\n\n\treturn nil\n}\n\n// isCapitalCase returns true if the given string is in capital case.\nfunc isCapitalCase(s string) bool {\n\treturn len(s) > 0 && unicode.IsUpper(rune(s[0]))\n}\n\nconst fileMode = 0o644\n\n// CopyFile copies the contents of src to dst atomically.\nfunc CopyFile(src, dst string) (err error) {\n\tin, err := os.Open(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer wrapErr(&err, in.Close)\n\n\ttmp, err := ioutil.TempFile(filepath.Dir(dst), \"copyfile\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t_, err = io.Copy(tmp, in)\n\tif err != nil {\n\t\tpanicOnErr(tmp.Close())\n\t\tpanicOnErr(os.Remove(tmp.Name()))\n\n\t\treturn err\n\t}\n\n\tif err := tmp.Close(); err != nil {\n\t\tpanicOnErr(os.Remove(tmp.Name()))\n\n\t\treturn err\n\t}\n\n\tif err := os.Chmod(tmp.Name(), fileMode); err != nil {\n\t\tpanicOnErr(os.Remove(tmp.Name()))\n\n\t\treturn err\n\t}\n\n\tif err := os.Rename(tmp.Name(), dst); err != nil {\n\t\tpanicOnErr(os.Remove(tmp.Name()))\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc panicOnErr(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\nfunc wrapErr(e *error, c func() error) {\n\terr := c()\n\tif err != nil && *e == nil {\n\t\t*e = err\n\t}\n}\n"
  },
  {
    "path": "tools/gotagsrewrite/main_test.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\npackage main\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRun(t *testing.T) {\n\ttests := map[string]struct {\n\t\toriginal string\n\t\tgolden   string\n\t}{\n\t\t\"default_test\": {\n\t\t\toriginal: \"a.orig\",\n\t\t\tgolden:   \"a.golden\",\n\t\t},\n\t}\n\n\tfor name, test := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\ttempDir := t.TempDir()\n\n\t\t\ttmpFile := filepath.Join(tempDir, \"my.go\")\n\t\t\torigPath := filepath.Join(\"testdata\", test.original)\n\n\t\t\trequire.NoError(t, CopyFile(origPath, tmpFile))\n\n\t\t\terr := Run(tempDir)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfileData := string(must(os.ReadFile(tmpFile))(t))\n\t\t\tgoldenPath := filepath.Join(\"testdata\", test.golden)\n\t\t\tgoldenData := string(must(os.ReadFile(goldenPath))(t))\n\n\t\t\trequire.Equal(t, goldenData, fileData)\n\t\t})\n\t}\n}\n\nfunc must[V any](v V, err error) func(t *testing.T) V {\n\treturn func(t *testing.T) V {\n\t\trequire.NoError(t, err)\n\n\t\treturn v\n\t}\n}\n"
  },
  {
    "path": "tools/gotagsrewrite/testdata/a.golden",
    "content": "package testdata\n\n//gotagsrewrite:gen\ntype MySpecSpec struct {\n\tNewField     string `yaml:\"new_field\" protobuf:\"4\"`\n\tFirstField   string `protobuf:\"5\"`\n\tName         string `yaml:\"string\" protobuf:\"6\"`\n\tunexported   string\n\tAnotherField string `yaml:\"another_field\" protobuf:\"3\"`\n\tLastField    string `protobuf:\"7\"`\n}\n\ntype MySpec struct{}\n\ntype MySpecSpec2 struct {\n\tunexported string\n\tMySpec\n\tunexported2 string\n}\n\ntype MySpecSpec3 struct {\n\tNewField string `yaml:\"new_field\"`\n}\n\n// MyCustomStruct is a custom struct\n//\n//gotagsrewrite:gen\ntype MyCustomStruct struct {\n\tNewField string `yaml:\"new_field\" protobuf:\"1\"`\n}\n\ntype (\n\t//gotagsrewrite:gen\n\tMyAnotherStruct struct {\n\t\tNewField string `yaml:\"new_field\" protobuf:\"1\"`\n\t}\n\n\t//gotagsrewrite:gen\n\tMyBasicStruct struct {\n\t\tNewField string `yaml:\"new_field\" protobuf:\"1\"`\n\t}\n\n\tMyNoneStruct struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n)\n\n//gotagsrewrite:gen\ntype (\n\tMyOnlyStruct struct {\n\t\tNewField string `yaml:\"new_field\" protobuf:\"1\"`\n\t}\n)\n\n//gotagsrewrite:gen\ntype (\n\tMyOnlyStruct2 struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n\n\tMyOnlyStruct3 struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n)\n"
  },
  {
    "path": "tools/gotagsrewrite/testdata/a.orig",
    "content": "package testdata\n\n//gotagsrewrite:gen\ntype MySpecSpec struct {\n\tNewField     string `yaml:\"new_field\"`\n\tFirstField   string\n\tName         string `yaml:\"string\"`\n\tunexported   string\n\tAnotherField string `yaml:\"another_field\" protobuf:\"3\"`\n\tLastField    string\n}\n\ntype MySpec struct{}\n\ntype MySpecSpec2 struct {\n\tunexported string\n\tMySpec\n\tunexported2 string\n}\n\ntype MySpecSpec3 struct {\n\tNewField string `yaml:\"new_field\"`\n}\n\n// MyCustomStruct is a custom struct\n//gotagsrewrite:gen\ntype MyCustomStruct struct {\n\tNewField string `yaml:\"new_field\"`\n}\n\ntype (\n\t//gotagsrewrite:gen\n\tMyAnotherStruct struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n\n\t//gotagsrewrite:gen\n\tMyBasicStruct struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n\n\tMyNoneStruct struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n)\n\n//gotagsrewrite:gen\ntype (\n\tMyOnlyStruct struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n)\n\n//gotagsrewrite:gen\ntype (\n\tMyOnlyStruct2 struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n\n\tMyOnlyStruct3 struct {\n\t\tNewField string `yaml:\"new_field\"`\n\t}\n)\n"
  },
  {
    "path": "tools/structprotogen/ast/ast.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package ast is used to find all structs with expected tag in the given AST.\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/token\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/fatih/structtag\"\n\t\"golang.org/x/tools/go/packages\"\n)\n\n// FindAllTaggedStructs extracts all structs with comments which contain tag in the given AST.\nfunc FindAllTaggedStructs(pkgs []*packages.Package) TaggedStructs {\n\tresult := TaggedStructs{}\n\n\tfor _, pkg := range pkgs {\n\t\tfor _, file := range pkg.Syntax {\n\t\t\tstructs := findAllStructs(file)\n\n\t\t\tfor _, structDef := range structs {\n\t\t\t\tresult.Add(pkg.PkgPath, structDef.Struct.Name.Name, TaggedStruct{\n\t\t\t\t\tComments: formatComments(structDef.Comment),\n\t\t\t\t\tFields:   structDef.Fields,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n// TaggedStructs is a map of tagged struct declarations to their data.\ntype TaggedStructs map[StructDecl]TaggedStruct\n\n// TaggedStruct contains struct comments and fields.\ntype TaggedStruct struct {\n\tComments []string\n\tFields   Fields\n}\n\n// Get returns the struct data for given pkg and pkgPath.\nfunc (t TaggedStructs) Get(pkg, name string) (TaggedStruct, bool) {\n\tval, ok := t[StructDecl{pkg, name}]\n\n\treturn val, ok\n}\n\n// Add adds the given struct data to the map.\nfunc (t TaggedStructs) Add(pkg, name string, structData TaggedStruct) {\n\tt[StructDecl{Pkg: pkg, Name: name}] = structData\n}\n\n// findAllStructs finds all structs with comments in the given AST.\nfunc findAllStructs(f ast.Node) []structData {\n\tvar result []structData\n\n\tast.Inspect(f, func(n ast.Node) bool {\n\t\tgenDecl, ok := n.(*ast.GenDecl)\n\t\tif !ok || genDecl.Tok != token.TYPE {\n\t\t\treturn true\n\t\t}\n\n\t\ttypeSpecs := filter(genDecl.Specs, typeSpecFilter)\n\n\t\tswitch len(typeSpecs) {\n\t\tcase 0:\n\t\t\treturn false\n\t\tcase 1:\n\t\t\tswitch {\n\t\t\tcase isTarget(genDecl.Doc):\n\t\t\t\tfields := getStructFieldsWithTags(typeSpecs[0])\n\n\t\t\t\tresult = append(result, structData{\n\t\t\t\t\tStruct:  typeSpecs[0],\n\t\t\t\t\tComment: genDecl.Doc,\n\t\t\t\t\tFields:  fields,\n\t\t\t\t})\n\t\t\tcase isTarget(typeSpecs[0].Doc):\n\t\t\t\tfields := getStructFieldsWithTags(typeSpecs[0])\n\n\t\t\t\tresult = append(result, structData{\n\t\t\t\t\tStruct:  typeSpecs[0],\n\t\t\t\t\tComment: typeSpecs[0].Doc,\n\t\t\t\t\tFields:  fields,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn false\n\t\tdefault:\n\t\t\tfor _, typeSpec := range typeSpecs {\n\t\t\t\tif isTarget(typeSpec.Doc) {\n\t\t\t\t\tfields := getStructFieldsWithTags(typeSpec)\n\n\t\t\t\t\tresult = append(result, structData{\n\t\t\t\t\t\tStruct:  typeSpec,\n\t\t\t\t\t\tComment: typeSpec.Doc,\n\t\t\t\t\t\tFields:  fields,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t}\n\t})\n\n\treturn result\n}\n\ntype structData struct {\n\tStruct  *ast.TypeSpec\n\tComment *ast.CommentGroup\n\tFields  Fields\n}\n\nfunc typeSpecFilter(n ast.Spec) (*ast.TypeSpec, bool) {\n\ttypeSpec, ok := n.(*ast.TypeSpec)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tstructType, ok := typeSpec.Type.(*ast.StructType)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tif structType.Fields.NumFields() == 0 {\n\t\treturn nil, false\n\t}\n\n\tif !isCapitalCase(typeSpec.Name.Name) {\n\t\treturn nil, false\n\t}\n\n\treturn typeSpec, true\n}\n\n// isCapitalCase returns true if the given string is in capital case.\nfunc isCapitalCase(s string) bool {\n\treturn len(s) > 0 && unicode.IsUpper(rune(s[0]))\n}\n\nfunc isTarget(doc *ast.CommentGroup) bool {\n\tif doc == nil {\n\t\treturn false\n\t}\n\n\tfor _, c := range doc.List {\n\t\tif isTargetComment(c.Text) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc isTargetComment(str string) bool {\n\treturn str == \"//gotagsrewrite:gen\"\n}\n\nfunc filter[T, V any](slc []T, f func(n T) (V, bool)) []V {\n\tvar result []V\n\n\tfor _, v := range slc {\n\t\tres, ok := f(v)\n\t\tif ok {\n\t\t\tresult = append(result, res)\n\t\t}\n\t}\n\n\treturn result\n}\n\n// StructDecl is a struct declaration.\ntype StructDecl struct {\n\tPkg  string\n\tName string\n}\n\nfunc formatComments(comment *ast.CommentGroup) []string {\n\tif comment == nil {\n\t\treturn nil\n\t}\n\n\tresult := make([]string, 0, len(comment.List))\n\n\tfor i := range comment.List {\n\t\tif len(comment.List)-1 >= i+1 && isTargetComment(comment.List[i+1].Text) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif isTargetComment(comment.List[i].Text) {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, comment.List[i].Text)\n\t}\n\n\treturn result\n}\n\n// Fields represents a struct field and its protobuf number.\ntype Fields map[string]int\n\n// getStructFieldsWithTags returns all fields of the given struct with their tags.\nfunc getStructFieldsWithTags(structDecl *ast.TypeSpec) Fields {\n\tresult := Fields{}\n\n\tstructType := structDecl.Type.(*ast.StructType) //nolint:errcheck\n\n\tfor _, field := range structType.Fields.List {\n\t\tif field.Names == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, name := range field.Names {\n\t\t\tif field.Tag == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttagValue := strings.Trim(field.Tag.Value, \"`\")\n\n\t\t\ttags, err := structtag.Parse(tagValue)\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"invalid tag: field '%s', tag '%s': %w\", name, tagValue, err))\n\t\t\t}\n\n\t\t\ttag, err := tags.Get(\"protobuf\")\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"cannot find protobuf tag: field '%s', tag '%s': %w\", name, tagValue, err))\n\t\t\t}\n\n\t\t\tnum, err := strconv.Atoi(tag.Name)\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"invalid protobuf tag: field '%s', tag '%s': %w\", name, tagValue, err))\n\t\t\t}\n\n\t\t\tresult[name.Name] = num\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "tools/structprotogen/consts/consts.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package consts is used to find all consts with expected tag in the given AST.\npackage consts\n\nimport (\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/token\"\n\t\"go/types\"\n\t\"io\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"golang.org/x/tools/go/packages\"\n)\n\nconst tag = \"structprotogen:gen_enum\"\n\n// FindIn looks up all const blocks with the specific comment in the given packages.\n//\n//nolint:gocyclo\nfunc FindIn(pkgs []*packages.Package) (ConstBlocks, error) {\n\tvar result ConstBlocks\n\n\tfor _, pkg := range pkgs {\n\t\tfor _, f := range pkg.Syntax {\n\t\t\tfor _, constBlock := range findGenDecls(f.Decls) {\n\t\t\t\tvar consts []Constant\n\n\t\t\t\tvar typeData typeData\n\n\t\t\t\tvalueSpecs := filter(constBlock.Specs, func(spec ast.Spec) (*ast.ValueSpec, bool) {\n\t\t\t\t\tvalueSpec, ok := spec.(*ast.ValueSpec)\n\n\t\t\t\t\treturn valueSpec, ok\n\t\t\t\t})\n\n\t\t\t\tfor _, valueSpec := range valueSpecs {\n\t\t\t\t\tfor _, name := range valueSpec.Names {\n\t\t\t\t\t\tdef := pkg.TypesInfo.Defs[name]\n\n\t\t\t\t\t\tif !def.Exported() {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttd, err := getTypeData(pkg.Syntax, def.Type())\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"%s: const named '%s': %w\", pkg.PkgPath, def.Name(), err)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif typeData.name == \"\" {\n\t\t\t\t\t\t\ttypeData = td\n\t\t\t\t\t\t} else if typeData.name != td.name {\n\t\t\t\t\t\t\treturn nil, fmt.Errorf(\"const type mismatch: %s != %s\", typeData.name, def.Type().String())\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tval, err := getValue(def)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconsts = append(consts, Constant{\n\t\t\t\t\t\t\tName:         name.Name,\n\t\t\t\t\t\t\tValue:        val,\n\t\t\t\t\t\t\tCommentLines: commentToStrings(valueSpec.Doc),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif len(consts) == 0 {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%s: const block with no exported consts\", pkg.PkgPath)\n\t\t\t\t}\n\n\t\t\t\tresult = append(result, ConstBlock{\n\t\t\t\t\tTypeName:     typeData.name,\n\t\t\t\t\tTypePkg:      typeData.pkgName,\n\t\t\t\t\tTypePath:     typeData.pkgPath,\n\t\t\t\t\tCommentLines: typeData.comments,\n\t\t\t\t\tConsts:       consts,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc getValue(obj types.Object) (string, error) {\n\tresult := obj.(*types.Const).Val().String()\n\n\t_, err := strconv.Atoi(result)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"value %s is not an integer: %s\", obj.Name(), result)\n\t}\n\n\treturn result, nil\n}\n\nfunc findGenDecls(decl []ast.Decl) []*ast.GenDecl {\n\treturn filter(decl, func(decl ast.Decl) (*ast.GenDecl, bool) {\n\t\tgenDecl, ok := decl.(*ast.GenDecl)\n\t\tif !ok ||\n\t\t\tgenDecl.Tok != token.CONST ||\n\t\t\tgenDecl.Lparen == token.NoPos || // single const declaration, ignore\n\t\t\tlen(genDecl.Specs) == 0 {\n\t\t\treturn nil, false\n\t\t}\n\n\t\tstrs := commentToStrings(genDecl.Doc)\n\t\tif len(strs) == 0 {\n\t\t\treturn nil, false\n\t\t}\n\n\t\tif findInStrings(strs, tag) == -1 {\n\t\t\treturn nil, false\n\t\t}\n\n\t\treturn genDecl, true\n\t})\n}\n\n// findInStrings finds a string in a list of strings.\nfunc findInStrings(strs []string, find string) int {\n\tfor i, str := range strs {\n\t\tif strings.Contains(str, find) {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc getTypeData(files []*ast.File, t types.Type) (typeData, error) {\n\tswitch t := t.(type) {\n\tcase *types.Named:\n\t\tcommentGroup, err := findTypeComment(files, t.Obj().Name())\n\t\tif err != nil {\n\t\t\treturn typeData{}, err\n\t\t}\n\n\t\treturn typeData{\n\t\t\tname:     t.Obj().Name(),\n\t\t\tpkgName:  t.Obj().Pkg().Name(),\n\t\t\tpkgPath:  t.Obj().Pkg().Path(),\n\t\t\tcomments: commentToStrings(commentGroup),\n\t\t}, nil\n\tdefault:\n\t\treturn typeData{}, fmt.Errorf(\"unsupported type: %s\", t.String())\n\t}\n}\n\ntype typeData struct {\n\tname     string\n\tpkgName  string\n\tpkgPath  string\n\tcomments []string\n}\n\nfunc findTypeComment(files []*ast.File, typeName string) (*ast.CommentGroup, error) {\n\tfor _, f := range files {\n\t\tfor _, decl := range f.Decls {\n\t\t\tgenDecl, ok := decl.(*ast.GenDecl)\n\t\t\tif !ok ||\n\t\t\t\tgenDecl.Tok != token.TYPE ||\n\t\t\t\tlen(genDecl.Specs) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfor _, spec := range genDecl.Specs {\n\t\t\t\ttypeSpec, ok := spec.(*ast.TypeSpec)\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif typeSpec.Name.Name == typeName {\n\t\t\t\t\treturn genDecl.Doc, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"type %s not found\", typeName)\n}\n\n// commentToStrings converts a list of comments to a list of strings.\nfunc commentToStrings(doc *ast.CommentGroup) []string {\n\tif doc == nil {\n\t\treturn nil\n\t}\n\n\tresult := make([]string, 0, len(doc.List))\n\tfor _, c := range doc.List {\n\t\tresult = append(result, c.Text)\n\t}\n\n\treturn result\n}\n\n// ConstBlock is a block of constants.\ntype ConstBlock struct {\n\tTypeName     string\n\tTypePkg      string\n\tTypePath     string\n\tCommentLines []string\n\tConsts       []Constant\n}\n\n// ProtoMessageName returns the name of the proto message for this const block.\nfunc (b *ConstBlock) ProtoMessageName() string {\n\treturn strings.Title(b.TypePkg) + strings.Title(b.TypeName) //nolint:staticcheck\n}\n\n// Constant represents a constant.\ntype Constant struct {\n\tName         string\n\tValue        string\n\tCommentLines []string\n}\n\n// ConstBlocks is a slice of ConstBlock.\ntype ConstBlocks []ConstBlock\n\n// FormatProtoFile generates proto file from the list of ConstBlocks.\nfunc (b *ConstBlocks) FormatProtoFile(w io.Writer) error {\n\tfmt.Fprint(w, \"syntax = \\\"proto3\\\";\\n\\n\")\n\tfmt.Fprint(w, \"package talos.resource.definitions.enums;\\n\\n\")\n\tfmt.Fprint(w, `option go_package = \"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums\";`+\"\\n\")\n\tfmt.Fprint(w, `option java_package = \"dev.talos.api.resource.definitions.enums\";`+\"\\n\\n\")\n\n\tfor _, block := range *b {\n\t\tfor _, comment := range block.CommentLines {\n\t\t\tfmt.Fprintln(w, strings.ReplaceAll(comment, \" \"+block.TypeName+\" \", \" \"+block.ProtoMessageName()+\" \"))\n\t\t}\n\n\t\tfmt.Fprintf(w, \"enum %s {\\n\", block.ProtoMessageName())\n\n\t\thasZeroNotFirstConstValue := slices.IndexFunc(block.Consts, func(c Constant) bool { return c.Value == \"0\" }) > 0\n\n\t\tif hasDuplicates(block.Consts, func(c Constant) string { return c.Value }) || hasZeroNotFirstConstValue {\n\t\t\tfmt.Fprintln(w, \"  option allow_alias = true;\")\n\t\t}\n\n\t\tfor i, constant := range block.Consts {\n\t\t\tfor _, comment := range constant.CommentLines {\n\t\t\t\tfmt.Fprintln(w, \" \", comment)\n\t\t\t}\n\n\t\t\tif i == 0 && constant.Value != \"0\" {\n\t\t\t\tfmt.Fprintf(w,\n\t\t\t\t\t\"  %s_%s_UNSPECIFIED = 0;\\n\",\n\t\t\t\t\tstrings.ToUpper(block.TypePkg),\n\t\t\t\t\tstrings.ToUpper(block.TypeName),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"  %s = %s;\\n\", toCapitalSnakeCase(constant.Name), constant.Value)\n\t\t}\n\n\t\tfmt.Fprintf(w, \"}\\n\\n\")\n\t}\n\n\treturn nil\n}\n\n// HaveType returns true if the list of ConstBlocks contains a block with the given type.\nfunc (b *ConstBlocks) HaveType(pkgPath, typeName string) bool {\n\t_, ok := b.Get(pkgPath, typeName)\n\n\treturn ok\n}\n\n// Get returns a ConstBlock for a given type.\nfunc (b *ConstBlocks) Get(pkgPath, typeName string) (ConstBlock, bool) {\n\tfor _, block := range *b {\n\t\tif block.TypePath == pkgPath && block.TypeName == typeName {\n\t\t\treturn block, true\n\t\t}\n\t}\n\n\treturn ConstBlock{}, false\n}\n\nfunc hasDuplicates[T any, K comparable](slc []T, fn func(T) K) bool {\n\tseen := make(map[K]struct{}, len(slc))\n\n\tfor _, elem := range slc {\n\t\tk := fn(elem)\n\t\tif _, ok := seen[k]; ok {\n\t\t\treturn true\n\t\t}\n\n\t\tseen[k] = struct{}{}\n\t}\n\n\treturn false\n}\n\n// toCapitalSnakeCase converts a string to a capital snake case.\nfunc toCapitalSnakeCase(str string) string {\n\tsnake := matchFirstCap.ReplaceAllString(str, \"${1}_${2}\")\n\tsnake = matchAllCap.ReplaceAllString(snake, \"${1}_${2}\")\n\tsnake = strings.ToUpper(snake)\n\n\t// special case for \"SomethingsIps\"\n\tif strings.HasSuffix(snake, \"_i_ps\") {\n\t\tsnake = strings.TrimSuffix(snake, \"_i_ps\") + \"_ips\"\n\t}\n\n\treturn snake\n}\n\nvar (\n\tmatchFirstCap = regexp.MustCompile(\"(.)([A-Z][a-z]+)\")\n\tmatchAllCap   = regexp.MustCompile(\"([a-z0-9])([A-Z])\")\n)\n\nfunc filter[T, V any](slc []T, f func(n T) (V, bool)) []V {\n\tvar result []V\n\n\tfor _, v := range slc {\n\t\tres, ok := f(v)\n\t\tif ok {\n\t\t\tresult = append(result, res)\n\t\t}\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "tools/structprotogen/go.mod",
    "content": "module github.com/siderolabs/talos/tools/structprotogen\n\ngo 1.26.0\n\nrequire (\n\tgithub.com/fatih/structtag v1.2.0\n\tgithub.com/spf13/cobra v1.10.2\n\tgolang.org/x/tools v0.43.0\n\tgopkg.in/typ.v4 v4.4.0\n)\n\nrequire (\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/spf13/pflag v1.0.9 // indirect\n\tgolang.org/x/mod v0.34.0 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n)\n"
  },
  {
    "path": "tools/structprotogen/go.sum",
    "content": "github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=\ngithub.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=\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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=\ngolang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/typ.v4 v4.4.0 h1:O9vTueEmZd0iA9DF+g2wXeNCeloN2TOpxu6FXKl3AqM=\ngopkg.in/typ.v4 v4.4.0/go.mod h1:wolXe8DlewxRCjA7SOiT3zjrZ0eQJZcr8cmV6bQWJUM=\n"
  },
  {
    "path": "tools/structprotogen/loader/loader.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package loader is used to load all packages from the given path.\npackage loader\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"golang.org/x/tools/go/packages\"\n)\n\n// LoadPackages loads all packages from the given path.\nfunc LoadPackages(pkgPath string) ([]*packages.Package, error) {\n\tcfg := &packages.Config{Mode: packages.NeedName | packages.NeedFiles |\n\t\tpackages.NeedCompiledGoFiles | packages.NeedImports |\n\t\tpackages.NeedDeps | packages.NeedTypes | packages.NeedTypesSizes |\n\t\tpackages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps}\n\n\tpkgs, err := packages.Load(cfg, pkgPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load pkgs from '%s': %w\", pkgPath, err)\n\t}\n\n\tif len(pkgs) == 0 {\n\t\treturn nil, errors.New(\"no packages found\")\n\t}\n\n\terr = collectErrors(pkgs)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error during processing '%s' packages: %w\", pkgPath, err)\n\t}\n\n\treturn pkgs, nil\n}\n\nfunc collectErrors(pkgs []*packages.Package) error {\n\tvar (\n\t\tbuilder strings.Builder\n\t\tn       int\n\t)\n\n\tpackages.Visit(pkgs, nil, func(pkg *packages.Package) {\n\t\tfor _, err := range pkg.Errors {\n\t\t\tfmt.Fprintf(&builder, \"Error '%d': %s\\n\", n, err)\n\t\t\tn++\n\t\t}\n\t})\n\n\tif n > 0 {\n\t\treturn errors.New(builder.String())\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "tools/structprotogen/main.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// structprotogen is a tool to generate proto files from Go structs.\npackage main\n\n//nolint:gci\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/siderolabs/talos/tools/structprotogen/ast\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/consts\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/loader\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/proto\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/types\"\n)\n\n// rootCmd represents the base command when called without any subcommands.\nvar rootCmd = &cobra.Command{\n\tUse:     \"structprotogen path dest\",\n\tShort:   \"This CLI is used to generate proto files from Go structs into one proto file\",\n\tExample: \"structprotogen github.com/siderolabs/talos/pkg/machinery/resources/... ./api/resource/definitions\",\n\tArgs:    cobra.ExactArgs(2),\n\tVersion: \"v1.0.0\",\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\treturn run(args[0], args[1])\n\t},\n\tSilenceUsage:      true,\n\tDisableAutoGenTag: true,\n}\n\nfunc main() {\n\terr := rootCmd.Execute()\n\tif err != nil {\n\t\tos.Exit(1)\n\t}\n}\n\n// TODO(DmitriyMV): get comments for fields\n\n//nolint:gocyclo\nfunc run(pkgPath, dst string) error {\n\tloadedPkgs, err := loader.LoadPackages(pkgPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconstants, err := consts.FindIn(loadedPkgs)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttaggedStructs := ast.FindAllTaggedStructs(loadedPkgs)\n\tprintFoundStructs(taggedStructs)\n\n\tsortedPkgs, err := types.FindPkgDecls(taggedStructs, loadedPkgs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error finding path '%s' declarations: %w\", pkgPath, err)\n\t}\n\n\tpkgsTypes, err := types.ParseDeclsData(sortedPkgs, taggedStructs)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing path '%s' declarations data: %w\", pkgPath, err)\n\t}\n\n\texternalTypes := types.FindExternalTypes(pkgsTypes, taggedStructs)\n\tfor i := 0; i < externalTypes.Len(); i++ {\n\t\texternalType := externalTypes.Get(i)\n\n\t\tif constants.HaveType(externalType.Pkg, externalType.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !proto.IsSupportedExternalType(externalType) {\n\t\t\treturn fmt.Errorf(\"external type '%s.%s' is not supported\", externalType.Pkg, externalType.Name)\n\t\t}\n\t}\n\n\tdata := proto.PrepareProtoData(pkgsTypes, constants)\n\n\tfor i := 0; i < data.Len(); i++ {\n\t\tprotoData := data.Get(i)\n\n\t\tfmt.Println(\"--------\")\n\t\tprotoData.WriteDebug(os.Stdout)\n\t}\n\n\terr = os.MkdirAll(dst, 0o755)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create directory for proto files: %w\", err)\n\t}\n\n\tif len(constants) > 0 {\n\t\terr = withFile(filepath.Join(dst, \"enums\", \"enums.proto\"), func(f *os.File) error {\n\t\t\treturn constants.FormatProtoFile(f)\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write enums proto file: %w\", err)\n\t\t}\n\t}\n\n\tfor i := 0; i < data.Len(); i++ {\n\t\tprotoData := data.Get(i)\n\n\t\tdstDir, err := filepath.Abs(filepath.Join(dst, protoData.Name))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get absolute path for pkg '%s': %w\", protoData.GoPkg, err)\n\t\t}\n\n\t\terr = os.MkdirAll(dstDir, 0o755)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create directory for pkg '%s' proto files: %w\", protoData.GoPkg, err)\n\t\t}\n\n\t\tdstFile, err := filepath.Abs(filepath.Join(dstDir, path.Base(protoData.GoPkg)+\".proto\"))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to get absolute path for destination file: %w\", err)\n\t\t}\n\n\t\tfmt.Println(\"writing file\", dstFile)\n\n\t\terr = withFile(dstFile, func(f *os.File) error {\n\t\t\tprotoData.Format(f)\n\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to write file '%s': %w\", dstFile, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc printFoundStructs(structs ast.TaggedStructs) {\n\tfor decl := range structs {\n\t\tfmt.Printf(\"found tagged struct '%s' in pkg '%s'\\n\", decl.Name, decl.Pkg)\n\t}\n}\n\nfunc withFile(filename string, fn func(f *os.File) error) error {\n\tdir := filepath.Dir(filename)\n\n\t_, err := os.Stat(dir)\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\terr = os.MkdirAll(dir, 0o755)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if err != nil {\n\t\treturn err\n\t}\n\n\tfile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.ModePerm)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\terr := file.Close()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"failed to close file:\", err)\n\t\t}\n\t}()\n\n\treturn fn(file)\n}\n"
  },
  {
    "path": "tools/structprotogen/proto/proto.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package proto contains the protobuf generation logic.\npackage proto\n\n//nolint:gci\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"gopkg.in/typ.v4/slices\"\n\n\t\"github.com/siderolabs/talos/tools/structprotogen/consts\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/sliceutil\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/types\"\n)\n\n// Pkg represents a protobuf package.\ntype Pkg struct {\n\tName  string\n\tGoPkg string\n\n\tisInit    bool\n\tprotoDefs slices.Sorted[*protoDef]\n\timports   slices.Sorted[string]\n}\n\nfunc protoPkgsCmp(left, right *Pkg) int {\n\treturn strings.Compare(left.Name, right.Name)\n}\n\nfunc (p *Pkg) init() {\n\tif !p.isInit {\n\t\tp.protoDefs = slices.NewSortedCompare([]*protoDef{}, protoDefCmp)\n\t\tp.imports = slices.NewSortedCompare([]string{}, strings.Compare)\n\t\tp.isInit = true\n\t}\n}\n\n// Defs returns the list of definitions.\nfunc (p *Pkg) Defs() *slices.Sorted[*protoDef] {\n\tp.init()\n\n\treturn &p.protoDefs\n}\n\n// Imports returns the list of imports.\nfunc (p *Pkg) Imports() *slices.Sorted[string] {\n\tp.init()\n\n\treturn &p.imports\n}\n\n// WriteDebug is like Format, but writes additional debug info.\nfunc (p *Pkg) WriteDebug(w io.Writer) {\n\tpkgName := p.Name\n\n\tfmt.Fprint(w, \"syntax = \\\"proto3\\\";\\n\\n\")\n\tfmt.Fprintf(w, \"package talos.resource.definitions.%s; // %s\\n\\n\", p.Name, p.GoPkg)\n\tfmt.Fprintf(w, \"option go_package = \\\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/%s\\\";\\n\", pkgName) // TODO: insert proper path\n\tfmt.Fprintf(w, \"option java_package = \\\"dev.talos.api.resource.definitions.%s\\\";\\n\\n\", pkgName)\n\n\tif p.imports.Len() > 0 {\n\t\tfor i := 0; i < p.imports.Len(); i++ {\n\t\t\timportPath := p.imports.Get(i)\n\t\t\tif !strings.ContainsRune(importPath, '.') {\n\t\t\t\timportPath = \"talos.resource.definitions.\" + importPath\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"import \\\"%s\\\";\\n\", importPath)\n\t\t}\n\n\t\tfmt.Fprintln(w, ``)\n\t}\n\n\tfor i := 0; i < p.protoDefs.Len(); i++ {\n\t\tp.protoDefs.Get(i).WriteDebug(w)\n\t\tfmt.Fprintln(w)\n\t}\n}\n\n// Format formats the protobuf data.\nfunc (p *Pkg) Format(w io.Writer) {\n\tpkgName := p.Name\n\n\tfmt.Fprint(w, \"syntax = \\\"proto3\\\";\\n\\n\")\n\tfmt.Fprintf(w, \"package talos.resource.definitions.%s;\\n\\n\", p.Name)\n\tfmt.Fprintf(w, \"option go_package = \\\"github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/%s\\\";\\n\", pkgName) // TODO: insert proper path\n\tfmt.Fprintf(w, \"option java_package = \\\"dev.talos.api.resource.definitions.%s\\\";\\n\\n\", pkgName)\n\n\tif p.imports.Len() > 0 {\n\t\tfor i := 0; i < p.imports.Len(); i++ {\n\t\t\timportPath := p.imports.Get(i)\n\t\t\tif !strings.ContainsRune(importPath, '.') {\n\t\t\t\timportPath = \"talos.resource.definitions.\" + importPath\n\t\t\t}\n\n\t\t\tfmt.Fprintf(w, \"import \\\"%s\\\";\\n\", importPath)\n\t\t}\n\n\t\tfmt.Fprintln(w, ``)\n\t}\n\n\tfor i := 0; i < p.protoDefs.Len(); i++ {\n\t\tp.protoDefs.Get(i).Format(w)\n\t\tfmt.Fprintln(w)\n\t}\n}\n\ntype protoDef struct {\n\tname string\n\n\tgoPkg    string\n\tcomments []string\n\n\tisInit bool\n\tfields slices.Sorted[protoField]\n}\n\nfunc protoDefCmp(left, right *protoDef) int {\n\treturn strings.Compare(left.name, right.name)\n}\n\nfunc (p *protoDef) init() {\n\tif !p.isInit {\n\t\tp.fields = slices.NewSortedCompare([]protoField{}, protoFieldCmp)\n\t\tp.isInit = true\n\t}\n}\n\nfunc (p *protoDef) Fields() *slices.Sorted[protoField] {\n\tp.init()\n\n\treturn &p.fields\n}\n\nfunc (p *protoDef) WriteDebug(w io.Writer) {\n\tfor _, comment := range p.comments {\n\t\tfmt.Fprintf(w, \"%s\\n\", comment)\n\t}\n\n\tfmt.Fprintf(w, \"message %s { //%s.%s\\n\", p.name, p.goPkg, p.name)\n\n\tfor i := 0; i < p.fields.Len(); i++ {\n\t\tfmt.Fprintf(w, \"  \")\n\t\tp.fields.Get(i).WriteDebug(w)\n\t}\n\n\tfmt.Fprintln(w, \"}\")\n}\n\nfunc (p *protoDef) Format(w io.Writer) {\n\tfor _, comment := range p.comments {\n\t\tfmt.Fprintf(w, \"%s\\n\", comment)\n\t}\n\n\tfmt.Fprintf(w, \"message %s {\\n\", p.name)\n\n\tfor i := 0; i < p.fields.Len(); i++ {\n\t\tfmt.Fprintf(w, \"  \")\n\t\tp.fields.Get(i).Format(w)\n\t}\n\n\tfmt.Fprintln(w, \"}\")\n}\n\ntype protoField struct {\n\tname string\n\ttyp  string\n\tnum  int\n\n\tgoType string\n}\n\nfunc protoFieldCmp(left, right protoField) int {\n\tif left.num == 0 {\n\t\tpanic(fmt.Errorf(\"left field '%s' has no number\", left.name))\n\t}\n\n\tif right.num == 0 {\n\t\tpanic(fmt.Errorf(\"right field '%s' has no number\", right.name))\n\t}\n\n\tswitch {\n\tcase left.num < right.num:\n\t\treturn -1\n\tcase left.num > right.num:\n\t\treturn 1\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nfunc (pf protoField) WriteDebug(w io.Writer) {\n\tfmt.Fprintf(w, \"%s %s = %d; // %s \\n\", pf.typ, ToSnakeCase(pf.name), pf.num, pf.goType)\n}\n\nfunc (pf protoField) Format(w io.Writer) {\n\tfmt.Fprintf(w, \"%s %s = %d;\\n\", pf.typ, ToSnakeCase(pf.name), pf.num)\n}\n\n// PrepareProtoData prepares the data for the protobuf generation.\n//\n//nolint:gocyclo,cyclop\nfunc PrepareProtoData(pkgsTypes slices.Sorted[*types.Type], constants consts.ConstBlocks) slices.Sorted[*Pkg] {\n\tresult := slices.NewSortedCompare([]*Pkg{}, protoPkgsCmp)\n\n\tfor i := 0; i < pkgsTypes.Len(); i++ {\n\t\tpkgType := pkgsTypes.Get(i)\n\n\t\tprotoPkg := sliceutil.GetOrAdd(&result, &Pkg{\n\t\t\tName:  pkgType.PkgName(),\n\t\t\tGoPkg: pkgType.Pkg,\n\t\t})\n\n\t\tdef := sliceutil.GetOrAdd(protoPkg.Defs(), &protoDef{\n\t\t\tname:     pkgType.Name,\n\t\t\tgoPkg:    pkgType.Pkg,\n\t\t\tcomments: pkgType.Comments,\n\t\t})\n\n\t\tfor j := 0; j < pkgType.Fields().Len(); j++ {\n\t\t\tfield := pkgType.Fields().Get(j)\n\n\t\t\tfieldTypeData := types.TypeInfo(field.TypeData.Type())\n\n\t\t\tif fieldTyp, ok := types.MatchTypeData[types.Complex](fieldTypeData); ok {\n\t\t\t\timportName, typeName := mustFormatTypeName(fieldTyp.Pkg, fieldTyp.Name, pkgType.Pkg)\n\n\t\t\t\tif importName != \"\" {\n\t\t\t\t\tsliceutil.AddIfNotFound(protoPkg.Imports(), importName)\n\t\t\t\t}\n\n\t\t\t\tsliceutil.AddIfNotFound(def.Fields(), protoField{\n\t\t\t\t\tname:   field.Name,\n\t\t\t\t\ttyp:    typeName,\n\t\t\t\t\tnum:    field.Num,\n\t\t\t\t\tgoType: field.TypeData.Type().String(),\n\t\t\t\t})\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif fieldTyp, ok := types.MatchTypeData[types.Basic](fieldTypeData); ok {\n\t\t\t\tvar importName, typeName string\n\n\t\t\t\tif block, ok := constants.Get(fieldTyp.Pkg, fieldTyp.Name); ok {\n\t\t\t\t\timportName = \"resource/definitions/enums/enums.proto\"\n\t\t\t\t\ttypeName = \"talos.resource.definitions.enums.\" + block.ProtoMessageName()\n\t\t\t\t} else {\n\t\t\t\t\timportName, typeName = mustFormatBasicTypeName(fieldTyp.Pkg, fieldTyp.Name)\n\t\t\t\t}\n\n\t\t\t\tif importName != \"\" {\n\t\t\t\t\tsliceutil.AddIfNotFound(protoPkg.Imports(), importName)\n\t\t\t\t}\n\n\t\t\t\tsliceutil.AddIfNotFound(def.Fields(), protoField{\n\t\t\t\t\tname:   field.Name,\n\t\t\t\t\ttyp:    typeName,\n\t\t\t\t\tnum:    field.Num,\n\t\t\t\t\tgoType: field.TypeData.Type().String(),\n\t\t\t\t})\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif fieldTyp, ok := types.MatchTypeData[types.Slice](fieldTypeData); ok {\n\t\t\t\tvar importName, typeName string\n\n\t\t\t\tblock, isEnum := constants.Get(fieldTyp.Pkg, fieldTyp.Name)\n\n\t\t\t\tswitch {\n\t\t\t\tcase isEnum:\n\t\t\t\t\timportName = \"resource/definitions/enums/enums.proto\"\n\t\t\t\t\ttypeName = \"repeated talos.resource.definitions.enums.\" + block.ProtoMessageName()\n\t\t\t\tcase fieldTyp.Pkg == \"\" && fieldTyp.Name == \"byte\" && fieldTyp.Is2DSlice: //nolint:goconst\n\t\t\t\t\ttypeName = \"repeated bytes\"\n\t\t\t\tcase fieldTyp.Pkg == \"\" && fieldTyp.Name == \"byte\":\n\t\t\t\t\ttypeName = \"bytes\"\n\t\t\t\tcase fieldTyp.Pkg == \"\":\n\t\t\t\t\ttypeName = fmt.Sprintf(\"repeated %s\", getProtoBasicName(fieldTyp.Name))\n\t\t\t\tdefault:\n\t\t\t\t\timportName, typeName = mustFormatTypeName(fieldTyp.Pkg, fieldTyp.Name, pkgType.Pkg)\n\t\t\t\t\ttypeName = fmt.Sprintf(\"repeated %s\", typeName)\n\t\t\t\t}\n\n\t\t\t\tif importName != \"\" {\n\t\t\t\t\tsliceutil.AddIfNotFound(protoPkg.Imports(), importName)\n\t\t\t\t}\n\n\t\t\t\tsliceutil.AddIfNotFound(def.Fields(), protoField{\n\t\t\t\t\tname:   field.Name,\n\t\t\t\t\ttyp:    typeName,\n\t\t\t\t\tnum:    field.Num,\n\t\t\t\t\tgoType: field.TypeData.Type().String(),\n\t\t\t\t})\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif fieldTyp, ok := types.MatchTypeData[types.Map](fieldTypeData); ok {\n\t\t\t\t// key cannot be anything but a basic type\n\t\t\t\timportKeyName, keyTypeName := mustFormatBasicTypeName(fieldTyp.KeyTypePkg, fieldTyp.KeyTypeName)\n\t\t\t\tif importKeyName != \"\" {\n\t\t\t\t\tpanic(fmt.Errorf(\"map key type '%s.%s' is not basic type\", fieldTyp.KeyTypePkg, fieldTyp.KeyTypeName))\n\t\t\t\t}\n\n\t\t\t\tvar (\n\t\t\t\t\ttypText    string\n\t\t\t\t\timportElem string\n\t\t\t\t)\n\n\t\t\t\tswitch {\n\t\t\t\tcase fieldTyp.ElemTypeName == \"interface{}\": // handle map[key]interface{}\n\t\t\t\t\timportElem = \"google/protobuf/struct.proto\"\n\t\t\t\t\ttypText = \"google.protobuf.Struct\"\n\t\t\t\tcase fieldTyp.ElemTypePkg == \"\":\n\t\t\t\t\telemTypeName := getProtoBasicName(fieldTyp.ElemTypeName)\n\t\t\t\t\ttypText = fmt.Sprintf(\"map<%s, %s>\", keyTypeName, elemTypeName)\n\t\t\t\tcase fieldTyp.ElemTypePkg == pkgType.Pkg:\n\t\t\t\t\tvar elemTypeName string\n\t\t\t\t\timportElem, elemTypeName = mustFormatTypeName(fieldTyp.ElemTypePkg, fieldTyp.ElemTypeName, pkgType.Pkg)\n\t\t\t\t\ttypText = fmt.Sprintf(\"map<%s, %s>\", keyTypeName, elemTypeName)\n\t\t\t\tdefault:\n\t\t\t\t\tpanic(fmt.Errorf(\"map value type '%s.%s' is not known type\", fieldTyp.ElemTypePkg, fieldTyp.ElemTypeName))\n\t\t\t\t}\n\n\t\t\t\tif importElem != \"\" {\n\t\t\t\t\tsliceutil.AddIfNotFound(protoPkg.Imports(), importElem)\n\t\t\t\t}\n\n\t\t\t\tsliceutil.AddIfNotFound(def.Fields(), protoField{\n\t\t\t\t\tname:   field.Name,\n\t\t\t\t\ttyp:    typText,\n\t\t\t\t\tnum:    field.Num,\n\t\t\t\t\tgoType: field.TypeData.Type().String(),\n\t\t\t\t})\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc mustFormatTypeName(fieldTypePkg string, fieldType string, declPkg string) (string, string) {\n\timportPath, name := formatTypeName(fieldTypePkg, fieldType, declPkg)\n\tif name == \"\" {\n\t\tpanic(fmt.Errorf(\"unknown type %s.%s\", fieldTypePkg, fieldType))\n\t}\n\n\treturn importPath, name\n}\n\nfunc formatTypeName(fieldTypePkg string, fieldType string, declPkg string) (string, string) {\n\tif fieldTypePkg == declPkg {\n\t\treturn \"\", fieldType\n\t}\n\n\ttype typeData struct {\n\t\tpkg  string\n\t\tname string\n\t}\n\n\ttd := typeData{\n\t\tname: fieldType,\n\t\tpkg:  fieldTypePkg,\n\t}\n\n\tconst commoProto = \"common/common.proto\"\n\n\tswitch td {\n\tcase typeData{\"time\", \"Time\"}:\n\t\treturn \"google/protobuf/timestamp.proto\", \"google.protobuf.Timestamp\"\n\tcase typeData{\"net/url\", \"URL\"}:\n\t\treturn commoProto, \"common.URL\"\n\tcase typeData{\"net/netip\", \"Prefix\"}:\n\t\treturn commoProto, \"common.NetIPPrefix\"\n\tcase typeData{\"net/netip\", \"AddrPort\"}:\n\t\treturn commoProto, \"common.NetIPPort\"\n\tcase typeData{\"net/netip\", \"Addr\"}:\n\t\treturn commoProto, \"common.NetIP\"\n\tcase typeData{\"github.com/opencontainers/runtime-spec/specs-go\", \"Mount\"}:\n\t\treturn \"resource/definitions/proto/proto.proto\", \"talos.resource.definitions.proto.Mount\"\n\tcase typeData{\"github.com/siderolabs/crypto/x509\", \"PEMEncodedCertificateAndKey\"}:\n\t\treturn commoProto, \"common.PEMEncodedCertificateAndKey\"\n\tcase typeData{\"github.com/siderolabs/crypto/x509\", \"PEMEncodedKey\"}:\n\t\treturn commoProto, \"common.PEMEncodedKey\"\n\tcase typeData{\"github.com/siderolabs/crypto/x509\", \"PEMEncodedCertificate\"}:\n\t\treturn commoProto, \"common.PEMEncodedCertificate\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/cel\", \"Expression\"}:\n\t\treturn \"google/api/expr/v1alpha1/checked.proto\", \"google.api.expr.v1alpha1.CheckedExpr\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/cri\", \"RegistryMirrorConfig\"}:\n\t\t// This is a hack, but I (Dmitry) don't have enough patience to figure out why we don't support complex maps\n\t\treturn \"resource/definitions/cri/registry.proto\", \"talos.resource.definitions.cri.RegistryMirrorConfig\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/cri\", \"RegistryAuthConfig\"}:\n\t\t// This is a hack, but I (Dmitry) don't have enough patience to figure out why we don't support complex maps\n\t\treturn \"resource/definitions/cri/registry.proto\", \"talos.resource.definitions.cri.RegistryAuthConfig\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/cri\", \"RegistryTLSConfig\"}:\n\t\t// This is a hack, but I (Dmitry) don't have enough patience to figure out why we don't support complex maps\n\t\treturn \"resource/definitions/cri/registry.proto\", \"talos.resource.definitions.cri.RegistryTLSConfig\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/runtime\", \"PlatformMetadataSpec\"}:\n\t\treturn \"resource/definitions/runtime/runtime.proto\", \"talos.resource.definitions.runtime.PlatformMetadataSpec\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/block\", \"ParameterSpec\"}:\n\t\treturn \"resource/definitions/block/block.proto\", \"talos.resource.definitions.block.ParameterSpec\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/etcd\", \"ArgValues\"}:\n\t\treturn \"resource/definitions/etcd/etcd.proto\", \"talos.resource.definitions.etcd.ArgValues\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/resources/k8s\", \"ArgValues\"}:\n\t\treturn \"resource/definitions/k8s/k8s.proto\", \"talos.resource.definitions.k8s.ArgValues\"\n\tdefault:\n\t\treturn \"\", \"\"\n\t}\n}\n\nfunc mustFormatBasicTypeName(fieldTypePkg string, fieldType string) (string, string) {\n\tif fieldTypePkg == \"\" {\n\t\treturn \"\", getProtoBasicName(fieldType)\n\t}\n\n\timportPath, fullName := formatBasicTypeName(fieldTypePkg, fieldType)\n\tif fullName == \"\" {\n\t\tpanic(fmt.Errorf(\"unknown type %s.%s\", fieldTypePkg, fieldType))\n\t}\n\n\treturn importPath, fullName\n}\n\n// IsSupportedExternalType checks if external type is supported.\nfunc IsSupportedExternalType(typ types.ExternalType) bool {\n\tif _, name := formatBasicTypeName(typ.Pkg, typ.Name); name != \"\" {\n\t\treturn true\n\t}\n\n\tif _, name := formatTypeName(typ.Pkg, typ.Name, \"\"); name != \"\" {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n//nolint:gocyclo,cyclop\nfunc formatBasicTypeName(typPkg string, typ string) (importPath, fullName string) {\n\ttype typeData struct {\n\t\tpkg  string\n\t\tname string\n\t}\n\n\ttd := typeData{\n\t\tname: typ,\n\t\tpkg:  typPkg,\n\t}\n\n\tswitch td {\n\tcase typeData{\"time\", \"Duration\"}:\n\t\treturn \"google/protobuf/duration.proto\", \"google.protobuf.Duration\"\n\tcase typeData{\"io/fs\", \"FileMode\"}:\n\t\treturn \"\", \"uint32\" //nolint:goconst\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/nethelpers\", \"AddressFlags\"}:\n\t\treturn \"\", \"uint32\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/nethelpers\", \"LinkFlags\"}:\n\t\treturn \"\", \"uint32\"\n\tcase typeData{\"github.com/siderolabs/talos/pkg/machinery/nethelpers\", \"RouteFlags\"}:\n\t\treturn \"\", \"uint32\"\n\tdefault:\n\t\treturn \"\", \"\"\n\t}\n}\n\n//nolint:gocyclo\nfunc getProtoBasicName(typ string) string {\n\t// Note: this should match: https://github.com/siderolabs/protoenc/blob/4b9363e618950aa6243872c640d89578c68fd1ed/marshal.go#L168-L204\n\t//\n\t// Note: protoenc marshals to protowire, not proto3, so for mapping see: https://protobuf.dev/programming-guides/encoding/#structure\n\tswitch typ {\n\tcase \"bool\":\n\t\treturn \"bool\"\n\tcase \"int8\", \"int16\", \"int32\":\n\t\treturn \"int32\"\n\tcase \"int64\", \"int\":\n\t\treturn \"int64\"\n\tcase \"byte\", \"uint8\", \"uint16\", \"uint32\":\n\t\treturn \"uint32\"\n\tcase \"uint64\", \"uint\":\n\t\treturn \"uint64\"\n\tcase \"float32\":\n\t\treturn \"float\"\n\tcase \"float64\":\n\t\treturn \"double\"\n\tcase \"string\":\n\t\treturn \"string\"\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown type %s\", typ))\n\t}\n}\n\n// ToSnakeCase converts a string to snake case.\nfunc ToSnakeCase(str string) string {\n\tsnake := matchFirstCap.ReplaceAllString(str, \"${1}_${2}\")\n\tsnake = matchAllCap.ReplaceAllString(snake, \"${1}_${2}\")\n\tsnake = strings.ToLower(snake)\n\n\t// special case for \"SomethingsIps\"\n\tif strings.HasSuffix(snake, \"_i_ps\") {\n\t\tsnake = strings.TrimSuffix(snake, \"_i_ps\") + \"_ips\"\n\t}\n\n\treturn snake\n}\n\nvar (\n\tmatchFirstCap = regexp.MustCompile(\"(.)([A-Z][a-z]+)\")\n\tmatchAllCap   = regexp.MustCompile(\"([a-z0-9])([A-Z])\")\n)\n"
  },
  {
    "path": "tools/structprotogen/sliceutil/sliceutils.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package sliceutil contains utility functions for slices.\npackage sliceutil\n\nimport \"gopkg.in/typ.v4/slices\"\n\n// GetOrAdd returns existing value or adds new one.\nfunc GetOrAdd[T any](slc *slices.Sorted[T], v T) T {\n\tvar index int\n\tif index = slc.Index(v); index == -1 {\n\t\tindex = slc.Add(v)\n\t}\n\n\treturn slc.Get(index)\n}\n\n// AddIfNotFound adds value to the slice if it's not found.\nfunc AddIfNotFound[T any](slc *slices.Sorted[T], v T) {\n\tif index := slc.Index(v); index == -1 {\n\t\tslc.Add(v)\n\t}\n}\n"
  },
  {
    "path": "tools/structprotogen/types/types.go",
    "content": "// This Source Code Form is subject to the terms of the Mozilla Public\n// License, v. 2.0. If a copy of the MPL was not distributed with this\n// file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n// Package types contains utils to work with types.\npackage types\n\n//nolint:gci\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"go/types\"\n\t\"path\"\n\t\"strings\"\n\n\t\"golang.org/x/tools/go/packages\"\n\t\"gopkg.in/typ.v4/slices\"\n\n\t\"github.com/siderolabs/talos/tools/structprotogen/ast\"\n\t\"github.com/siderolabs/talos/tools/structprotogen/sliceutil\"\n)\n\n// PkgDecl is a struct which contains package path and tagged struct declarations.\ntype PkgDecl struct {\n\tpath string\n\n\tdecl []types.Object\n}\n\nfunc pkgCmp(left, right *PkgDecl) int { return strings.Compare(left.path, right.path) }\n\n// FindPkgDecls finds all declarations in the given packages.\nfunc FindPkgDecls(taggedStructs ast.TaggedStructs, loadedPkgs []*packages.Package) (slices.Sorted[*PkgDecl], error) {\n\tresult := slices.NewSortedCompare([]*PkgDecl{}, pkgCmp)\n\n\tfor _, loadedPkg := range loadedPkgs {\n\t\tforEachTaggedStruct(taggedStructs, loadedPkg, func(decl types.Object) {\n\t\t\tv := sliceutil.GetOrAdd(&result, &PkgDecl{\n\t\t\t\tpath: decl.Pkg().Path(),\n\t\t\t})\n\n\t\t\tv.decl = append(v.decl, decl)\n\t\t})\n\t}\n\n\tif result.Len() == 0 {\n\t\treturn slices.Sorted[*PkgDecl]{}, errors.New(\"no definitions found\")\n\t}\n\n\treturn result, nil\n}\n\nfunc forEachTaggedStruct(taggedStructs ast.TaggedStructs, pkg *packages.Package, f func(decl types.Object)) {\n\tscope := pkg.Types.Scope()\n\n\tfor _, name := range scope.Names() {\n\t\t_, ok := taggedStructs.Get(pkg.PkgPath, name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tobj := scope.Lookup(name)\n\n\t\t// This is special resource - ignore it.\n\t\tif pkg.PkgPath == \"github.com/siderolabs/talos/pkg/machinery/resources/network\" && name == \"DeviceConfigSpecSpec\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tf(obj)\n\t}\n}\n\n// Type is a struct which contains type pkg, name, comments and fields.\ntype Type struct {\n\tPkg      string\n\tName     string\n\tComments []string\n\n\tisInit bool\n\tfields slices.Sorted[FieldData]\n}\n\n// PkgName returns a package name for the given type.\nfunc (t *Type) PkgName() string {\n\treturn path.Base(t.Pkg)\n}\n\n// Fields returns a list of fields for the given type.\nfunc (t *Type) Fields() *slices.Sorted[FieldData] {\n\tif !t.isInit {\n\t\tt.fields = slices.NewSortedCompare([]FieldData{}, fieldCmp)\n\t\tt.isInit = true\n\t}\n\n\treturn &t.fields\n}\n\nfunc pkgTypeCmp(left, right *Type) int {\n\tpathCmp := strings.Compare(left.Pkg, right.Pkg)\n\tif pathCmp != 0 {\n\t\treturn pathCmp\n\t}\n\n\treturn strings.Compare(left.Name, right.Name)\n}\n\n// FieldData is a struct which contains field name, proto num and type data.\ntype FieldData struct {\n\tName     string\n\tNum      int\n\tTypeData *types.Var\n}\n\nfunc fieldCmp(left, right FieldData) int { return strings.Compare(left.Name, right.Name) }\n\n// ParseDeclsData parses all declarations and returns a list of packages with proper types.\nfunc ParseDeclsData(sortedPkgs slices.Sorted[*PkgDecl], taggedStructs ast.TaggedStructs) (slices.Sorted[*Type], error) {\n\tresult := slices.NewSortedCompare([]*Type{}, pkgTypeCmp)\n\n\tfor i := 0; i < sortedPkgs.Len(); i++ {\n\t\tpkg := sortedPkgs.Get(i)\n\n\t\tfor _, decl := range pkg.decl {\n\t\t\tstructName := decl.Name()\n\n\t\t\tstructType, ok := decl.Type().Underlying().(*types.Struct)\n\t\t\tif !ok {\n\t\t\t\treturn slices.Sorted[*Type]{}, fmt.Errorf(\"type %s is not a struct\", structName)\n\t\t\t}\n\n\t\t\ttaggedStruct, ok := taggedStructs.Get(pkg.path, structName)\n\t\t\tif !ok {\n\t\t\t\treturn slices.Sorted[*Type]{}, fmt.Errorf(\"type %s is unknown struct\", structName)\n\t\t\t}\n\n\t\t\tfor j := 0; j < structType.NumFields(); j++ {\n\t\t\t\tfield := structType.Field(j)\n\n\t\t\t\tif !field.Exported() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tv := sliceutil.GetOrAdd(&result, &Type{\n\t\t\t\t\tPkg:      pkg.path,\n\t\t\t\t\tName:     structName,\n\t\t\t\t\tComments: taggedStruct.Comments,\n\t\t\t\t})\n\n\t\t\t\tv.Fields().Add(FieldData{\n\t\t\t\t\tName:     field.Name(),\n\t\t\t\t\tNum:      taggedStruct.Fields[field.Name()],\n\t\t\t\t\tTypeData: field,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\n// ExternalType is a struct which contains external type pkg and name.\ntype ExternalType struct {\n\tPkg  string\n\tName string\n}\n\n// String returns a string representation of the ExternalType.\nfunc (e ExternalType) String() string {\n\treturn fmt.Sprintf(\"%s.%s\", e.Pkg, e.Name)\n}\n\nfunc externalTypesCmp(left, right ExternalType) int {\n\tpkgCmp := strings.Compare(left.Pkg, right.Pkg)\n\tif pkgCmp != 0 {\n\t\treturn pkgCmp\n\t}\n\n\treturn strings.Compare(left.Name, right.Name)\n}\n\n// FindExternalTypes finds all external types in the given list of types.\nfunc FindExternalTypes(pkgsTypes slices.Sorted[*Type], taggedStructs ast.TaggedStructs) slices.Sorted[ExternalType] {\n\tresult := slices.NewSortedCompare([]ExternalType{}, externalTypesCmp)\n\n\tfor i := 0; i < pkgsTypes.Len(); i++ {\n\t\ttyp := pkgsTypes.Get(i)\n\n\t\tfor j := 0; j < typ.fields.Len(); j++ {\n\t\t\tfield := typ.fields.Get(j)\n\n\t\t\tif !field.TypeData.Exported() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttypeData := TypeInfo(field.TypeData.Type())\n\n\t\t\tif typePkg := typeData.typePkg(); typePkg != \"\" {\n\t\t\t\ttypeName := typeData.typeName()\n\n\t\t\t\tif _, ok := taggedStructs.Get(typePkg, typeName); !ok {\n\t\t\t\t\tsliceutil.AddIfNotFound(&result, ExternalType{\n\t\t\t\t\t\tPkg:  typePkg,\n\t\t\t\t\t\tName: typeName,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif typ, ok := MatchTypeData[Basic](typeData); ok && typ.Pkg != \"\" {\n\t\t\t\tsliceutil.AddIfNotFound(&result, ExternalType{\n\t\t\t\t\tPkg:  typ.Pkg,\n\t\t\t\t\tName: typ.Name,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif typ, ok := MatchTypeData[Map](typeData); ok && typ.ElemTypePkg != \"\" {\n\t\t\t\tsliceutil.AddIfNotFound(&result, ExternalType{\n\t\t\t\t\tPkg:  typ.ElemTypePkg,\n\t\t\t\t\tName: typ.ElemTypeName,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n// TypeInfo extracts all type data from the given type.\n//\n//nolint:gocyclo\nfunc TypeInfo(t types.Type) TypeInfoData {\n\tswitch t := t.(type) {\n\tcase *types.Slice:\n\t\treturn makeSliceType(TypeInfo(t.Elem()))\n\tcase *types.Map:\n\t\treturn makeMapType(TypeInfo(t.Key()), TypeInfo(t.Elem()))\n\tcase *types.Basic:\n\t\treturn makeType[Basic](\"\", t.Name())\n\tcase *types.Pointer:\n\t\treturn TypeInfo(t.Elem())\n\tcase *types.Alias:\n\t\treturn TypeInfo(types.Unalias(t))\n\tcase *types.Named:\n\t\tif _, ok := t.Underlying().(*types.Basic); ok {\n\t\t\treturn makeType[Basic](t.Obj().Pkg().Path(), t.Obj().Name())\n\t\t}\n\n\t\tif underlying, ok := t.Underlying().(*types.Slice); ok {\n\t\t\treturn makeSliceType(TypeInfo(underlying.Elem()))\n\t\t}\n\n\t\treturn makeType[Complex](t.Obj().Pkg().Path(), t.Obj().Name())\n\tcase *types.Interface:\n\t\treturn makeType[Complex](\"\", \"interface{}\")\n\tcase *types.Struct:\n\t\tpanic(fmt.Errorf(\"unsupported unnamed struct: %T\", t))\n\tcase *types.Chan:\n\t\tpanic(fmt.Errorf(\"unsupported type: %T\", t))\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unknown type: %T\", t))\n\t}\n}\n\nfunc makeSliceType(td TypeInfoData) TypeInfoData {\n\tisSliceInSlice := false\n\n\tif td, ok := MatchTypeData[Slice](td); ok {\n\t\tif td.Pkg != \"\" || td.Name != \"byte\" {\n\t\t\tpanic(fmt.Errorf(\"unsupported slice in slice: %s.%s\", td.Pkg, td.Name))\n\t\t}\n\n\t\tisSliceInSlice = true\n\t}\n\n\treturn MakeTypeData(Slice{\n\t\tPkg:       td.typePkg(),\n\t\tName:      td.typeName(),\n\t\tIs2DSlice: isSliceInSlice,\n\t})\n}\n\nfunc makeType[T Basic | Complex](pkg string, name string) TypeInfoData {\n\treturn MakeTypeData(T{Pkg: pkg, Name: name})\n}\n\nfunc makeMapType(key, elem TypeInfoData) TypeInfoData {\n\treturn MakeTypeData(Map{\n\t\tKeyTypePkg:   key.typePkg(),\n\t\tKeyTypeName:  key.typeName(),\n\t\tElemTypePkg:  elem.typePkg(),\n\t\tElemTypeName: elem.typeName(),\n\t})\n}\n\n// MakeTypeData creates a new TypeInfoData from the given type.\nfunc MakeTypeData[T Basic | Complex | Map | Slice](v T) TypeInfoData {\n\treturn TypeInfoData{v: v}\n}\n\n// MatchTypeData matches the given TypeInfoData to the given type.\nfunc MatchTypeData[T Basic | Complex | Map | Slice](d TypeInfoData) (T, bool) {\n\tv, ok := d.v.(T)\n\n\treturn v, ok\n}\n\n// TypeInfoData is a struct which contains type data.\ntype TypeInfoData struct{ v any }\n\nfunc (td TypeInfoData) typeName() string {\n\tswitch v := td.v.(type) {\n\tcase Basic:\n\t\treturn v.Name\n\tcase Complex:\n\t\treturn v.Name\n\tcase Map:\n\t\treturn v.KeyTypeName\n\tcase Slice:\n\t\treturn v.Name\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unknown type: %T\", v))\n\t}\n}\n\nfunc (td TypeInfoData) typePkg() string {\n\tswitch v := td.v.(type) {\n\tcase Basic:\n\t\treturn v.Pkg\n\tcase Complex:\n\t\treturn v.Pkg\n\tcase Map:\n\t\treturn v.KeyTypePkg\n\tcase Slice:\n\t\treturn v.Pkg\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unknown type: %T\", v))\n\t}\n}\n\n// Basic is a basic type.\ntype Basic struct {\n\tName string\n\tPkg  string\n}\n\n// Complex is a complex type.\ntype Complex struct {\n\tName string\n\tPkg  string\n}\n\n// Slice is a slice type.\ntype Slice struct {\n\tName      string\n\tPkg       string\n\tIs2DSlice bool\n}\n\n// Map is a map type.\ntype Map struct {\n\tKeyTypeName string\n\tKeyTypePkg  string\n\n\tElemTypeName string\n\tElemTypePkg  string\n}\n"
  },
  {
    "path": "website/content/v1.13/reference/_index.md",
    "content": "---\ntitle: \"Reference\"\nweight: 70\n---\n"
  },
  {
    "path": "website/content/v1.13/reference/api.md",
    "content": "---\ntitle: API\ndescription: Talos gRPC API reference.\n---\n\n## Table of Contents\n\n- [common/common.proto](#common/common.proto)\n    - [ContainerdInstance](#common.ContainerdInstance)\n    - [Data](#common.Data)\n    - [DataResponse](#common.DataResponse)\n    - [Empty](#common.Empty)\n    - [EmptyResponse](#common.EmptyResponse)\n    - [Error](#common.Error)\n    - [Metadata](#common.Metadata)\n    - [NetIP](#common.NetIP)\n    - [NetIPPort](#common.NetIPPort)\n    - [NetIPPrefix](#common.NetIPPrefix)\n    - [PEMEncodedCertificate](#common.PEMEncodedCertificate)\n    - [PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey)\n    - [PEMEncodedKey](#common.PEMEncodedKey)\n    - [URL](#common.URL)\n  \n    - [Code](#common.Code)\n    - [ContainerDriver](#common.ContainerDriver)\n    - [ContainerdNamespace](#common.ContainerdNamespace)\n  \n    - [File-level Extensions](#common/common.proto-extensions)\n  \n- [cluster/cluster.proto](#cluster/cluster.proto)\n    - [ClusterInfo](#cluster.ClusterInfo)\n    - [HealthCheckProgress](#cluster.HealthCheckProgress)\n    - [HealthCheckRequest](#cluster.HealthCheckRequest)\n  \n    - [ClusterService](#cluster.ClusterService)\n  \n- [inspect/inspect.proto](#inspect/inspect.proto)\n    - [ControllerDependencyEdge](#inspect.ControllerDependencyEdge)\n    - [ControllerRuntimeDependenciesResponse](#inspect.ControllerRuntimeDependenciesResponse)\n    - [ControllerRuntimeDependency](#inspect.ControllerRuntimeDependency)\n  \n    - [DependencyEdgeType](#inspect.DependencyEdgeType)\n  \n    - [InspectService](#inspect.InspectService)\n  \n- [machine/debug.proto](#machine/debug.proto)\n    - [DebugContainerRunRequest](#machine.DebugContainerRunRequest)\n    - [DebugContainerRunRequestSpec](#machine.DebugContainerRunRequestSpec)\n    - [DebugContainerRunRequestSpec.EnvEntry](#machine.DebugContainerRunRequestSpec.EnvEntry)\n    - [DebugContainerRunResponse](#machine.DebugContainerRunResponse)\n    - [DebugContainerTerminalResize](#machine.DebugContainerTerminalResize)\n  \n    - [DebugContainerRunRequestSpec.Profile](#machine.DebugContainerRunRequestSpec.Profile)\n  \n    - [DebugService](#machine.DebugService)\n  \n- [machine/image.proto](#machine/image.proto)\n    - [ImageServiceCredentials](#machine.ImageServiceCredentials)\n    - [ImageServiceImportRequest](#machine.ImageServiceImportRequest)\n    - [ImageServiceImportResponse](#machine.ImageServiceImportResponse)\n    - [ImageServiceListRequest](#machine.ImageServiceListRequest)\n    - [ImageServiceListResponse](#machine.ImageServiceListResponse)\n    - [ImageServiceListResponse.LabelsEntry](#machine.ImageServiceListResponse.LabelsEntry)\n    - [ImageServicePullLayerProgress](#machine.ImageServicePullLayerProgress)\n    - [ImageServicePullProgress](#machine.ImageServicePullProgress)\n    - [ImageServicePullRequest](#machine.ImageServicePullRequest)\n    - [ImageServicePullResponse](#machine.ImageServicePullResponse)\n    - [ImageServiceRemoveRequest](#machine.ImageServiceRemoveRequest)\n    - [ImageServiceVerifyRequest](#machine.ImageServiceVerifyRequest)\n    - [ImageServiceVerifyResponse](#machine.ImageServiceVerifyResponse)\n  \n    - [ImageServicePullLayerProgress.Status](#machine.ImageServicePullLayerProgress.Status)\n  \n    - [ImageService](#machine.ImageService)\n  \n- [machine/lifecycle.proto](#machine/lifecycle.proto)\n    - [InstallArtifactsSource](#machine.InstallArtifactsSource)\n    - [InstallDestination](#machine.InstallDestination)\n    - [LifecycleServiceInstallProgress](#machine.LifecycleServiceInstallProgress)\n    - [LifecycleServiceInstallRequest](#machine.LifecycleServiceInstallRequest)\n    - [LifecycleServiceInstallResponse](#machine.LifecycleServiceInstallResponse)\n    - [LifecycleServiceUpgradeRequest](#machine.LifecycleServiceUpgradeRequest)\n    - [LifecycleServiceUpgradeResponse](#machine.LifecycleServiceUpgradeResponse)\n  \n    - [LifecycleService](#machine.LifecycleService)\n  \n- [machine/machine.proto](#machine/machine.proto)\n    - [AddressEvent](#machine.AddressEvent)\n    - [ApplyConfiguration](#machine.ApplyConfiguration)\n    - [ApplyConfigurationRequest](#machine.ApplyConfigurationRequest)\n    - [ApplyConfigurationResponse](#machine.ApplyConfigurationResponse)\n    - [BPFInstruction](#machine.BPFInstruction)\n    - [Bootstrap](#machine.Bootstrap)\n    - [BootstrapRequest](#machine.BootstrapRequest)\n    - [BootstrapResponse](#machine.BootstrapResponse)\n    - [CNIConfig](#machine.CNIConfig)\n    - [CPUFreqStats](#machine.CPUFreqStats)\n    - [CPUFreqStatsResponse](#machine.CPUFreqStatsResponse)\n    - [CPUInfo](#machine.CPUInfo)\n    - [CPUInfoResponse](#machine.CPUInfoResponse)\n    - [CPUStat](#machine.CPUStat)\n    - [CPUsFreqStats](#machine.CPUsFreqStats)\n    - [CPUsInfo](#machine.CPUsInfo)\n    - [ClusterConfig](#machine.ClusterConfig)\n    - [ClusterNetworkConfig](#machine.ClusterNetworkConfig)\n    - [ConfigLoadErrorEvent](#machine.ConfigLoadErrorEvent)\n    - [ConfigValidationErrorEvent](#machine.ConfigValidationErrorEvent)\n    - [ConnectRecord](#machine.ConnectRecord)\n    - [ConnectRecord.Process](#machine.ConnectRecord.Process)\n    - [Container](#machine.Container)\n    - [ContainerInfo](#machine.ContainerInfo)\n    - [ContainersRequest](#machine.ContainersRequest)\n    - [ContainersResponse](#machine.ContainersResponse)\n    - [ControlPlaneConfig](#machine.ControlPlaneConfig)\n    - [CopyRequest](#machine.CopyRequest)\n    - [DHCPOptionsConfig](#machine.DHCPOptionsConfig)\n    - [DiskStat](#machine.DiskStat)\n    - [DiskStats](#machine.DiskStats)\n    - [DiskStatsResponse](#machine.DiskStatsResponse)\n    - [DiskUsageInfo](#machine.DiskUsageInfo)\n    - [DiskUsageRequest](#machine.DiskUsageRequest)\n    - [DmesgRequest](#machine.DmesgRequest)\n    - [EtcdAlarm](#machine.EtcdAlarm)\n    - [EtcdAlarmDisarm](#machine.EtcdAlarmDisarm)\n    - [EtcdAlarmDisarmResponse](#machine.EtcdAlarmDisarmResponse)\n    - [EtcdAlarmListResponse](#machine.EtcdAlarmListResponse)\n    - [EtcdClusterDowngrade](#machine.EtcdClusterDowngrade)\n    - [EtcdDefragment](#machine.EtcdDefragment)\n    - [EtcdDefragmentResponse](#machine.EtcdDefragmentResponse)\n    - [EtcdDowngradeCancel](#machine.EtcdDowngradeCancel)\n    - [EtcdDowngradeCancelResponse](#machine.EtcdDowngradeCancelResponse)\n    - [EtcdDowngradeEnable](#machine.EtcdDowngradeEnable)\n    - [EtcdDowngradeEnableRequest](#machine.EtcdDowngradeEnableRequest)\n    - [EtcdDowngradeEnableResponse](#machine.EtcdDowngradeEnableResponse)\n    - [EtcdDowngradeValidate](#machine.EtcdDowngradeValidate)\n    - [EtcdDowngradeValidateRequest](#machine.EtcdDowngradeValidateRequest)\n    - [EtcdDowngradeValidateResponse](#machine.EtcdDowngradeValidateResponse)\n    - [EtcdForfeitLeadership](#machine.EtcdForfeitLeadership)\n    - [EtcdForfeitLeadershipRequest](#machine.EtcdForfeitLeadershipRequest)\n    - [EtcdForfeitLeadershipResponse](#machine.EtcdForfeitLeadershipResponse)\n    - [EtcdLeaveCluster](#machine.EtcdLeaveCluster)\n    - [EtcdLeaveClusterRequest](#machine.EtcdLeaveClusterRequest)\n    - [EtcdLeaveClusterResponse](#machine.EtcdLeaveClusterResponse)\n    - [EtcdMember](#machine.EtcdMember)\n    - [EtcdMemberAlarm](#machine.EtcdMemberAlarm)\n    - [EtcdMemberListRequest](#machine.EtcdMemberListRequest)\n    - [EtcdMemberListResponse](#machine.EtcdMemberListResponse)\n    - [EtcdMemberStatus](#machine.EtcdMemberStatus)\n    - [EtcdMembers](#machine.EtcdMembers)\n    - [EtcdRecover](#machine.EtcdRecover)\n    - [EtcdRecoverResponse](#machine.EtcdRecoverResponse)\n    - [EtcdRemoveMember](#machine.EtcdRemoveMember)\n    - [EtcdRemoveMemberByID](#machine.EtcdRemoveMemberByID)\n    - [EtcdRemoveMemberByIDRequest](#machine.EtcdRemoveMemberByIDRequest)\n    - [EtcdRemoveMemberByIDResponse](#machine.EtcdRemoveMemberByIDResponse)\n    - [EtcdRemoveMemberRequest](#machine.EtcdRemoveMemberRequest)\n    - [EtcdRemoveMemberResponse](#machine.EtcdRemoveMemberResponse)\n    - [EtcdSnapshotRequest](#machine.EtcdSnapshotRequest)\n    - [EtcdStatus](#machine.EtcdStatus)\n    - [EtcdStatusResponse](#machine.EtcdStatusResponse)\n    - [Event](#machine.Event)\n    - [EventsRequest](#machine.EventsRequest)\n    - [FeaturesInfo](#machine.FeaturesInfo)\n    - [FileInfo](#machine.FileInfo)\n    - [GenerateClientConfiguration](#machine.GenerateClientConfiguration)\n    - [GenerateClientConfigurationRequest](#machine.GenerateClientConfigurationRequest)\n    - [GenerateClientConfigurationResponse](#machine.GenerateClientConfigurationResponse)\n    - [Hostname](#machine.Hostname)\n    - [HostnameResponse](#machine.HostnameResponse)\n    - [ImageListRequest](#machine.ImageListRequest)\n    - [ImageListResponse](#machine.ImageListResponse)\n    - [ImagePull](#machine.ImagePull)\n    - [ImagePullRequest](#machine.ImagePullRequest)\n    - [ImagePullResponse](#machine.ImagePullResponse)\n    - [InstallConfig](#machine.InstallConfig)\n    - [ListRequest](#machine.ListRequest)\n    - [LoadAvg](#machine.LoadAvg)\n    - [LoadAvgResponse](#machine.LoadAvgResponse)\n    - [LogsContainer](#machine.LogsContainer)\n    - [LogsContainersResponse](#machine.LogsContainersResponse)\n    - [LogsRequest](#machine.LogsRequest)\n    - [MachineConfig](#machine.MachineConfig)\n    - [MachineStatusEvent](#machine.MachineStatusEvent)\n    - [MachineStatusEvent.MachineStatus](#machine.MachineStatusEvent.MachineStatus)\n    - [MachineStatusEvent.MachineStatus.UnmetCondition](#machine.MachineStatusEvent.MachineStatus.UnmetCondition)\n    - [MemInfo](#machine.MemInfo)\n    - [Memory](#machine.Memory)\n    - [MemoryResponse](#machine.MemoryResponse)\n    - [MetaDelete](#machine.MetaDelete)\n    - [MetaDeleteRequest](#machine.MetaDeleteRequest)\n    - [MetaDeleteResponse](#machine.MetaDeleteResponse)\n    - [MetaWrite](#machine.MetaWrite)\n    - [MetaWriteRequest](#machine.MetaWriteRequest)\n    - [MetaWriteResponse](#machine.MetaWriteResponse)\n    - [MountStat](#machine.MountStat)\n    - [Mounts](#machine.Mounts)\n    - [MountsResponse](#machine.MountsResponse)\n    - [NetDev](#machine.NetDev)\n    - [Netstat](#machine.Netstat)\n    - [NetstatRequest](#machine.NetstatRequest)\n    - [NetstatRequest.Feature](#machine.NetstatRequest.Feature)\n    - [NetstatRequest.L4proto](#machine.NetstatRequest.L4proto)\n    - [NetstatRequest.NetNS](#machine.NetstatRequest.NetNS)\n    - [NetstatResponse](#machine.NetstatResponse)\n    - [NetworkConfig](#machine.NetworkConfig)\n    - [NetworkDeviceConfig](#machine.NetworkDeviceConfig)\n    - [NetworkDeviceStats](#machine.NetworkDeviceStats)\n    - [NetworkDeviceStatsResponse](#machine.NetworkDeviceStatsResponse)\n    - [PacketCaptureRequest](#machine.PacketCaptureRequest)\n    - [PhaseEvent](#machine.PhaseEvent)\n    - [PlatformInfo](#machine.PlatformInfo)\n    - [Process](#machine.Process)\n    - [ProcessInfo](#machine.ProcessInfo)\n    - [ProcessesResponse](#machine.ProcessesResponse)\n    - [ReadRequest](#machine.ReadRequest)\n    - [Reboot](#machine.Reboot)\n    - [RebootRequest](#machine.RebootRequest)\n    - [RebootResponse](#machine.RebootResponse)\n    - [Reset](#machine.Reset)\n    - [ResetPartitionSpec](#machine.ResetPartitionSpec)\n    - [ResetRequest](#machine.ResetRequest)\n    - [ResetResponse](#machine.ResetResponse)\n    - [Restart](#machine.Restart)\n    - [RestartEvent](#machine.RestartEvent)\n    - [RestartRequest](#machine.RestartRequest)\n    - [RestartResponse](#machine.RestartResponse)\n    - [Rollback](#machine.Rollback)\n    - [RollbackRequest](#machine.RollbackRequest)\n    - [RollbackResponse](#machine.RollbackResponse)\n    - [RouteConfig](#machine.RouteConfig)\n    - [SequenceEvent](#machine.SequenceEvent)\n    - [ServiceEvent](#machine.ServiceEvent)\n    - [ServiceEvents](#machine.ServiceEvents)\n    - [ServiceHealth](#machine.ServiceHealth)\n    - [ServiceInfo](#machine.ServiceInfo)\n    - [ServiceList](#machine.ServiceList)\n    - [ServiceListResponse](#machine.ServiceListResponse)\n    - [ServiceRestart](#machine.ServiceRestart)\n    - [ServiceRestartRequest](#machine.ServiceRestartRequest)\n    - [ServiceRestartResponse](#machine.ServiceRestartResponse)\n    - [ServiceStart](#machine.ServiceStart)\n    - [ServiceStartRequest](#machine.ServiceStartRequest)\n    - [ServiceStartResponse](#machine.ServiceStartResponse)\n    - [ServiceStateEvent](#machine.ServiceStateEvent)\n    - [ServiceStop](#machine.ServiceStop)\n    - [ServiceStopRequest](#machine.ServiceStopRequest)\n    - [ServiceStopResponse](#machine.ServiceStopResponse)\n    - [Shutdown](#machine.Shutdown)\n    - [ShutdownRequest](#machine.ShutdownRequest)\n    - [ShutdownResponse](#machine.ShutdownResponse)\n    - [SoftIRQStat](#machine.SoftIRQStat)\n    - [Stat](#machine.Stat)\n    - [Stats](#machine.Stats)\n    - [StatsRequest](#machine.StatsRequest)\n    - [StatsResponse](#machine.StatsResponse)\n    - [SystemStat](#machine.SystemStat)\n    - [SystemStatResponse](#machine.SystemStatResponse)\n    - [TaskEvent](#machine.TaskEvent)\n    - [Upgrade](#machine.Upgrade)\n    - [UpgradeRequest](#machine.UpgradeRequest)\n    - [UpgradeResponse](#machine.UpgradeResponse)\n    - [Version](#machine.Version)\n    - [VersionInfo](#machine.VersionInfo)\n    - [VersionResponse](#machine.VersionResponse)\n    - [Xattr](#machine.Xattr)\n  \n    - [ApplyConfigurationRequest.Mode](#machine.ApplyConfigurationRequest.Mode)\n    - [ConnectRecord.State](#machine.ConnectRecord.State)\n    - [ConnectRecord.TimerActive](#machine.ConnectRecord.TimerActive)\n    - [EtcdMemberAlarm.AlarmType](#machine.EtcdMemberAlarm.AlarmType)\n    - [ListRequest.Type](#machine.ListRequest.Type)\n    - [MachineConfig.MachineType](#machine.MachineConfig.MachineType)\n    - [MachineStatusEvent.MachineStage](#machine.MachineStatusEvent.MachineStage)\n    - [NetstatRequest.Filter](#machine.NetstatRequest.Filter)\n    - [PhaseEvent.Action](#machine.PhaseEvent.Action)\n    - [RebootRequest.Mode](#machine.RebootRequest.Mode)\n    - [ResetRequest.WipeMode](#machine.ResetRequest.WipeMode)\n    - [SequenceEvent.Action](#machine.SequenceEvent.Action)\n    - [ServiceStateEvent.Action](#machine.ServiceStateEvent.Action)\n    - [TaskEvent.Action](#machine.TaskEvent.Action)\n    - [UpgradeRequest.RebootMode](#machine.UpgradeRequest.RebootMode)\n  \n    - [MachineService](#machine.MachineService)\n  \n- [resource/config/config.proto](#resource/config/config.proto)\n    - [MachineConfigSpec](#resource.config.MachineConfigSpec)\n    - [MachineTypeSpec](#resource.config.MachineTypeSpec)\n  \n    - [MachineType](#resource.config.MachineType)\n  \n- [resource/definitions/enums/enums.proto](#resource/definitions/enums/enums.proto)\n    - [BlockEncryptionKeyType](#talos.resource.definitions.enums.BlockEncryptionKeyType)\n    - [BlockEncryptionProviderType](#talos.resource.definitions.enums.BlockEncryptionProviderType)\n    - [BlockFSParameterType](#talos.resource.definitions.enums.BlockFSParameterType)\n    - [BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType)\n    - [BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase)\n    - [BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType)\n    - [CriImageCacheCopyStatus](#talos.resource.definitions.enums.CriImageCacheCopyStatus)\n    - [CriImageCacheStatus](#talos.resource.definitions.enums.CriImageCacheStatus)\n    - [KubespanPeerState](#talos.resource.definitions.enums.KubespanPeerState)\n    - [MachineType](#talos.resource.definitions.enums.MachineType)\n    - [NethelpersADLACPActive](#talos.resource.definitions.enums.NethelpersADLACPActive)\n    - [NethelpersADSelect](#talos.resource.definitions.enums.NethelpersADSelect)\n    - [NethelpersARPAllTargets](#talos.resource.definitions.enums.NethelpersARPAllTargets)\n    - [NethelpersARPValidate](#talos.resource.definitions.enums.NethelpersARPValidate)\n    - [NethelpersAddressFlag](#talos.resource.definitions.enums.NethelpersAddressFlag)\n    - [NethelpersAddressSortAlgorithm](#talos.resource.definitions.enums.NethelpersAddressSortAlgorithm)\n    - [NethelpersAutoHostnameKind](#talos.resource.definitions.enums.NethelpersAutoHostnameKind)\n    - [NethelpersBondMode](#talos.resource.definitions.enums.NethelpersBondMode)\n    - [NethelpersBondXmitHashPolicy](#talos.resource.definitions.enums.NethelpersBondXmitHashPolicy)\n    - [NethelpersClientIdentifier](#talos.resource.definitions.enums.NethelpersClientIdentifier)\n    - [NethelpersConntrackState](#talos.resource.definitions.enums.NethelpersConntrackState)\n    - [NethelpersDuplex](#talos.resource.definitions.enums.NethelpersDuplex)\n    - [NethelpersFailOverMAC](#talos.resource.definitions.enums.NethelpersFailOverMAC)\n    - [NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily)\n    - [NethelpersICMPType](#talos.resource.definitions.enums.NethelpersICMPType)\n    - [NethelpersLACPRate](#talos.resource.definitions.enums.NethelpersLACPRate)\n    - [NethelpersLinkType](#talos.resource.definitions.enums.NethelpersLinkType)\n    - [NethelpersMatchOperator](#talos.resource.definitions.enums.NethelpersMatchOperator)\n    - [NethelpersNfTablesChainHook](#talos.resource.definitions.enums.NethelpersNfTablesChainHook)\n    - [NethelpersNfTablesChainPriority](#talos.resource.definitions.enums.NethelpersNfTablesChainPriority)\n    - [NethelpersNfTablesVerdict](#talos.resource.definitions.enums.NethelpersNfTablesVerdict)\n    - [NethelpersOperationalState](#talos.resource.definitions.enums.NethelpersOperationalState)\n    - [NethelpersPort](#talos.resource.definitions.enums.NethelpersPort)\n    - [NethelpersPrimaryReselect](#talos.resource.definitions.enums.NethelpersPrimaryReselect)\n    - [NethelpersProtocol](#talos.resource.definitions.enums.NethelpersProtocol)\n    - [NethelpersRouteFlag](#talos.resource.definitions.enums.NethelpersRouteFlag)\n    - [NethelpersRouteProtocol](#talos.resource.definitions.enums.NethelpersRouteProtocol)\n    - [NethelpersRouteType](#talos.resource.definitions.enums.NethelpersRouteType)\n    - [NethelpersRoutingRuleAction](#talos.resource.definitions.enums.NethelpersRoutingRuleAction)\n    - [NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable)\n    - [NethelpersScope](#talos.resource.definitions.enums.NethelpersScope)\n    - [NethelpersVLANProtocol](#talos.resource.definitions.enums.NethelpersVLANProtocol)\n    - [NethelpersWOLMode](#talos.resource.definitions.enums.NethelpersWOLMode)\n    - [NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer)\n    - [NetworkOperator](#talos.resource.definitions.enums.NetworkOperator)\n    - [RuntimeFIPSState](#talos.resource.definitions.enums.RuntimeFIPSState)\n    - [RuntimeMachineStage](#talos.resource.definitions.enums.RuntimeMachineStage)\n    - [RuntimeSELinuxState](#talos.resource.definitions.enums.RuntimeSELinuxState)\n  \n- [resource/definitions/block/block.proto](#resource/definitions/block/block.proto)\n    - [DeviceSpec](#talos.resource.definitions.block.DeviceSpec)\n    - [DiscoveredVolumeSpec](#talos.resource.definitions.block.DiscoveredVolumeSpec)\n    - [DiscoveryRefreshRequestSpec](#talos.resource.definitions.block.DiscoveryRefreshRequestSpec)\n    - [DiscoveryRefreshStatusSpec](#talos.resource.definitions.block.DiscoveryRefreshStatusSpec)\n    - [DiskSelector](#talos.resource.definitions.block.DiskSelector)\n    - [DiskSpec](#talos.resource.definitions.block.DiskSpec)\n    - [EncryptionKey](#talos.resource.definitions.block.EncryptionKey)\n    - [EncryptionSpec](#talos.resource.definitions.block.EncryptionSpec)\n    - [FilesystemSpec](#talos.resource.definitions.block.FilesystemSpec)\n    - [LocatorSpec](#talos.resource.definitions.block.LocatorSpec)\n    - [MountRequestSpec](#talos.resource.definitions.block.MountRequestSpec)\n    - [MountSpec](#talos.resource.definitions.block.MountSpec)\n    - [MountStatusSpec](#talos.resource.definitions.block.MountStatusSpec)\n    - [ParameterSpec](#talos.resource.definitions.block.ParameterSpec)\n    - [PartitionSpec](#talos.resource.definitions.block.PartitionSpec)\n    - [ProvisioningSpec](#talos.resource.definitions.block.ProvisioningSpec)\n    - [SwapStatusSpec](#talos.resource.definitions.block.SwapStatusSpec)\n    - [SymlinkProvisioningSpec](#talos.resource.definitions.block.SymlinkProvisioningSpec)\n    - [SymlinkSpec](#talos.resource.definitions.block.SymlinkSpec)\n    - [SystemDiskSpec](#talos.resource.definitions.block.SystemDiskSpec)\n    - [TPMEncryptionOptionsInfo](#talos.resource.definitions.block.TPMEncryptionOptionsInfo)\n    - [UserDiskConfigStatusSpec](#talos.resource.definitions.block.UserDiskConfigStatusSpec)\n    - [VolumeConfigSpec](#talos.resource.definitions.block.VolumeConfigSpec)\n    - [VolumeMountRequestSpec](#talos.resource.definitions.block.VolumeMountRequestSpec)\n    - [VolumeMountStatusSpec](#talos.resource.definitions.block.VolumeMountStatusSpec)\n    - [VolumeStatusSpec](#talos.resource.definitions.block.VolumeStatusSpec)\n    - [ZswapStatusSpec](#talos.resource.definitions.block.ZswapStatusSpec)\n  \n- [resource/definitions/cluster/cluster.proto](#resource/definitions/cluster/cluster.proto)\n    - [AffiliateSpec](#talos.resource.definitions.cluster.AffiliateSpec)\n    - [ConfigSpec](#talos.resource.definitions.cluster.ConfigSpec)\n    - [ControlPlane](#talos.resource.definitions.cluster.ControlPlane)\n    - [IdentitySpec](#talos.resource.definitions.cluster.IdentitySpec)\n    - [InfoSpec](#talos.resource.definitions.cluster.InfoSpec)\n    - [KubeSpanAffiliateSpec](#talos.resource.definitions.cluster.KubeSpanAffiliateSpec)\n    - [MemberSpec](#talos.resource.definitions.cluster.MemberSpec)\n  \n- [resource/definitions/cri/cri.proto](#resource/definitions/cri/cri.proto)\n    - [ImageCacheConfigSpec](#talos.resource.definitions.cri.ImageCacheConfigSpec)\n    - [RegistriesConfigSpec](#talos.resource.definitions.cri.RegistriesConfigSpec)\n    - [RegistriesConfigSpec.RegistryAuthsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry)\n    - [RegistriesConfigSpec.RegistryMirrorsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry)\n    - [RegistriesConfigSpec.RegistryTlSsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry)\n    - [RegistryAuthConfig](#talos.resource.definitions.cri.RegistryAuthConfig)\n    - [RegistryEndpointConfig](#talos.resource.definitions.cri.RegistryEndpointConfig)\n    - [RegistryMirrorConfig](#talos.resource.definitions.cri.RegistryMirrorConfig)\n    - [RegistryTLSConfig](#talos.resource.definitions.cri.RegistryTLSConfig)\n    - [SeccompProfileSpec](#talos.resource.definitions.cri.SeccompProfileSpec)\n  \n- [resource/definitions/etcd/etcd.proto](#resource/definitions/etcd/etcd.proto)\n    - [ArgValues](#talos.resource.definitions.etcd.ArgValues)\n    - [ConfigSpec](#talos.resource.definitions.etcd.ConfigSpec)\n    - [ConfigSpec.ExtraArgsEntry](#talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry)\n    - [MemberSpec](#talos.resource.definitions.etcd.MemberSpec)\n    - [PKIStatusSpec](#talos.resource.definitions.etcd.PKIStatusSpec)\n    - [SpecSpec](#talos.resource.definitions.etcd.SpecSpec)\n    - [SpecSpec.ExtraArgsEntry](#talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry)\n  \n- [resource/definitions/extensions/extensions.proto](#resource/definitions/extensions/extensions.proto)\n    - [Compatibility](#talos.resource.definitions.extensions.Compatibility)\n    - [Constraint](#talos.resource.definitions.extensions.Constraint)\n    - [Layer](#talos.resource.definitions.extensions.Layer)\n    - [Metadata](#talos.resource.definitions.extensions.Metadata)\n  \n- [resource/definitions/files/files.proto](#resource/definitions/files/files.proto)\n    - [EtcFileSpecSpec](#talos.resource.definitions.files.EtcFileSpecSpec)\n    - [EtcFileStatusSpec](#talos.resource.definitions.files.EtcFileStatusSpec)\n  \n- [resource/definitions/hardware/hardware.proto](#resource/definitions/hardware/hardware.proto)\n    - [MemoryModuleSpec](#talos.resource.definitions.hardware.MemoryModuleSpec)\n    - [PCIDeviceSpec](#talos.resource.definitions.hardware.PCIDeviceSpec)\n    - [PCIDriverRebindConfigSpec](#talos.resource.definitions.hardware.PCIDriverRebindConfigSpec)\n    - [PCIDriverRebindStatusSpec](#talos.resource.definitions.hardware.PCIDriverRebindStatusSpec)\n    - [ProcessorSpec](#talos.resource.definitions.hardware.ProcessorSpec)\n    - [SystemInformationSpec](#talos.resource.definitions.hardware.SystemInformationSpec)\n  \n- [resource/definitions/proto/proto.proto](#resource/definitions/proto/proto.proto)\n    - [LinuxIDMapping](#talos.resource.definitions.proto.LinuxIDMapping)\n    - [Mount](#talos.resource.definitions.proto.Mount)\n  \n- [resource/definitions/k8s/k8s.proto](#resource/definitions/k8s/k8s.proto)\n    - [APIServerConfigSpec](#talos.resource.definitions.k8s.APIServerConfigSpec)\n    - [APIServerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry)\n    - [APIServerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry)\n    - [AdmissionControlConfigSpec](#talos.resource.definitions.k8s.AdmissionControlConfigSpec)\n    - [AdmissionPluginSpec](#talos.resource.definitions.k8s.AdmissionPluginSpec)\n    - [ArgValues](#talos.resource.definitions.k8s.ArgValues)\n    - [AuditPolicyConfigSpec](#talos.resource.definitions.k8s.AuditPolicyConfigSpec)\n    - [AuthorizationAuthorizersSpec](#talos.resource.definitions.k8s.AuthorizationAuthorizersSpec)\n    - [AuthorizationConfigSpec](#talos.resource.definitions.k8s.AuthorizationConfigSpec)\n    - [BootstrapManifestsConfigSpec](#talos.resource.definitions.k8s.BootstrapManifestsConfigSpec)\n    - [ConfigStatusSpec](#talos.resource.definitions.k8s.ConfigStatusSpec)\n    - [ControllerManagerConfigSpec](#talos.resource.definitions.k8s.ControllerManagerConfigSpec)\n    - [ControllerManagerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry)\n    - [ControllerManagerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry)\n    - [EndpointSpec](#talos.resource.definitions.k8s.EndpointSpec)\n    - [ExtraManifest](#talos.resource.definitions.k8s.ExtraManifest)\n    - [ExtraManifest.ExtraHeadersEntry](#talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry)\n    - [ExtraManifestsConfigSpec](#talos.resource.definitions.k8s.ExtraManifestsConfigSpec)\n    - [ExtraVolume](#talos.resource.definitions.k8s.ExtraVolume)\n    - [KubePrismConfigSpec](#talos.resource.definitions.k8s.KubePrismConfigSpec)\n    - [KubePrismEndpoint](#talos.resource.definitions.k8s.KubePrismEndpoint)\n    - [KubePrismEndpointsSpec](#talos.resource.definitions.k8s.KubePrismEndpointsSpec)\n    - [KubePrismStatusesSpec](#talos.resource.definitions.k8s.KubePrismStatusesSpec)\n    - [KubeletConfigSpec](#talos.resource.definitions.k8s.KubeletConfigSpec)\n    - [KubeletConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry)\n    - [KubeletSpecSpec](#talos.resource.definitions.k8s.KubeletSpecSpec)\n    - [ManifestSpec](#talos.resource.definitions.k8s.ManifestSpec)\n    - [ManifestStatusSpec](#talos.resource.definitions.k8s.ManifestStatusSpec)\n    - [NodeAnnotationSpecSpec](#talos.resource.definitions.k8s.NodeAnnotationSpecSpec)\n    - [NodeIPConfigSpec](#talos.resource.definitions.k8s.NodeIPConfigSpec)\n    - [NodeIPSpec](#talos.resource.definitions.k8s.NodeIPSpec)\n    - [NodeLabelSpecSpec](#talos.resource.definitions.k8s.NodeLabelSpecSpec)\n    - [NodeStatusSpec](#talos.resource.definitions.k8s.NodeStatusSpec)\n    - [NodeStatusSpec.AnnotationsEntry](#talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntry)\n    - [NodeStatusSpec.LabelsEntry](#talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntry)\n    - [NodeTaintSpecSpec](#talos.resource.definitions.k8s.NodeTaintSpecSpec)\n    - [NodenameSpec](#talos.resource.definitions.k8s.NodenameSpec)\n    - [Resources](#talos.resource.definitions.k8s.Resources)\n    - [Resources.LimitsEntry](#talos.resource.definitions.k8s.Resources.LimitsEntry)\n    - [Resources.RequestsEntry](#talos.resource.definitions.k8s.Resources.RequestsEntry)\n    - [SchedulerConfigSpec](#talos.resource.definitions.k8s.SchedulerConfigSpec)\n    - [SchedulerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry)\n    - [SchedulerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry)\n    - [SecretsStatusSpec](#talos.resource.definitions.k8s.SecretsStatusSpec)\n    - [SingleManifest](#talos.resource.definitions.k8s.SingleManifest)\n    - [StaticPodServerStatusSpec](#talos.resource.definitions.k8s.StaticPodServerStatusSpec)\n    - [StaticPodSpec](#talos.resource.definitions.k8s.StaticPodSpec)\n    - [StaticPodStatusSpec](#talos.resource.definitions.k8s.StaticPodStatusSpec)\n  \n- [resource/definitions/kubeaccess/kubeaccess.proto](#resource/definitions/kubeaccess/kubeaccess.proto)\n    - [ConfigSpec](#talos.resource.definitions.kubeaccess.ConfigSpec)\n  \n- [resource/definitions/kubespan/kubespan.proto](#resource/definitions/kubespan/kubespan.proto)\n    - [ConfigSpec](#talos.resource.definitions.kubespan.ConfigSpec)\n    - [EndpointSpec](#talos.resource.definitions.kubespan.EndpointSpec)\n    - [IdentitySpec](#talos.resource.definitions.kubespan.IdentitySpec)\n    - [PeerSpecSpec](#talos.resource.definitions.kubespan.PeerSpecSpec)\n    - [PeerStatusSpec](#talos.resource.definitions.kubespan.PeerStatusSpec)\n  \n- [resource/definitions/runtime/runtime.proto](#resource/definitions/runtime/runtime.proto)\n    - [APIServiceConfigSpec](#talos.resource.definitions.runtime.APIServiceConfigSpec)\n    - [BootedEntrySpec](#talos.resource.definitions.runtime.BootedEntrySpec)\n    - [DevicesStatusSpec](#talos.resource.definitions.runtime.DevicesStatusSpec)\n    - [DiagnosticSpec](#talos.resource.definitions.runtime.DiagnosticSpec)\n    - [EnvironmentSpec](#talos.resource.definitions.runtime.EnvironmentSpec)\n    - [EventSinkConfigSpec](#talos.resource.definitions.runtime.EventSinkConfigSpec)\n    - [ExtensionServiceConfigFile](#talos.resource.definitions.runtime.ExtensionServiceConfigFile)\n    - [ExtensionServiceConfigSpec](#talos.resource.definitions.runtime.ExtensionServiceConfigSpec)\n    - [ExtensionServiceConfigStatusSpec](#talos.resource.definitions.runtime.ExtensionServiceConfigStatusSpec)\n    - [KernelCmdlineSpec](#talos.resource.definitions.runtime.KernelCmdlineSpec)\n    - [KernelModuleSpecSpec](#talos.resource.definitions.runtime.KernelModuleSpecSpec)\n    - [KernelParamSpecSpec](#talos.resource.definitions.runtime.KernelParamSpecSpec)\n    - [KernelParamStatusSpec](#talos.resource.definitions.runtime.KernelParamStatusSpec)\n    - [KmsgLogConfigSpec](#talos.resource.definitions.runtime.KmsgLogConfigSpec)\n    - [LoadedKernelModuleSpec](#talos.resource.definitions.runtime.LoadedKernelModuleSpec)\n    - [MachineStatusSpec](#talos.resource.definitions.runtime.MachineStatusSpec)\n    - [MachineStatusStatus](#talos.resource.definitions.runtime.MachineStatusStatus)\n    - [MaintenanceServiceConfigSpec](#talos.resource.definitions.runtime.MaintenanceServiceConfigSpec)\n    - [MetaKeySpec](#talos.resource.definitions.runtime.MetaKeySpec)\n    - [MetaLoadedSpec](#talos.resource.definitions.runtime.MetaLoadedSpec)\n    - [MountStatusSpec](#talos.resource.definitions.runtime.MountStatusSpec)\n    - [OOMActionSpec](#talos.resource.definitions.runtime.OOMActionSpec)\n    - [PlatformMetadataSpec](#talos.resource.definitions.runtime.PlatformMetadataSpec)\n    - [PlatformMetadataSpec.TagsEntry](#talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntry)\n    - [SBOMItemSpec](#talos.resource.definitions.runtime.SBOMItemSpec)\n    - [SecurityStateSpec](#talos.resource.definitions.runtime.SecurityStateSpec)\n    - [UniqueMachineTokenSpec](#talos.resource.definitions.runtime.UniqueMachineTokenSpec)\n    - [UnmetCondition](#talos.resource.definitions.runtime.UnmetCondition)\n    - [WatchdogTimerConfigSpec](#talos.resource.definitions.runtime.WatchdogTimerConfigSpec)\n    - [WatchdogTimerStatusSpec](#talos.resource.definitions.runtime.WatchdogTimerStatusSpec)\n  \n- [resource/definitions/network/network.proto](#resource/definitions/network/network.proto)\n    - [AddressSpecSpec](#talos.resource.definitions.network.AddressSpecSpec)\n    - [AddressStatusSpec](#talos.resource.definitions.network.AddressStatusSpec)\n    - [BondMasterSpec](#talos.resource.definitions.network.BondMasterSpec)\n    - [BondSlave](#talos.resource.definitions.network.BondSlave)\n    - [BridgeMasterSpec](#talos.resource.definitions.network.BridgeMasterSpec)\n    - [BridgeSlave](#talos.resource.definitions.network.BridgeSlave)\n    - [BridgeVLANSpec](#talos.resource.definitions.network.BridgeVLANSpec)\n    - [ClientIdentifierSpec](#talos.resource.definitions.network.ClientIdentifierSpec)\n    - [DHCP4OperatorSpec](#talos.resource.definitions.network.DHCP4OperatorSpec)\n    - [DHCP6OperatorSpec](#talos.resource.definitions.network.DHCP6OperatorSpec)\n    - [DNSResolveCacheSpec](#talos.resource.definitions.network.DNSResolveCacheSpec)\n    - [EthernetChannelsSpec](#talos.resource.definitions.network.EthernetChannelsSpec)\n    - [EthernetChannelsStatus](#talos.resource.definitions.network.EthernetChannelsStatus)\n    - [EthernetFeatureStatus](#talos.resource.definitions.network.EthernetFeatureStatus)\n    - [EthernetRingsSpec](#talos.resource.definitions.network.EthernetRingsSpec)\n    - [EthernetRingsStatus](#talos.resource.definitions.network.EthernetRingsStatus)\n    - [EthernetSpecSpec](#talos.resource.definitions.network.EthernetSpecSpec)\n    - [EthernetSpecSpec.FeaturesEntry](#talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntry)\n    - [EthernetStatusSpec](#talos.resource.definitions.network.EthernetStatusSpec)\n    - [HardwareAddrSpec](#talos.resource.definitions.network.HardwareAddrSpec)\n    - [HostDNSConfigSpec](#talos.resource.definitions.network.HostDNSConfigSpec)\n    - [HostnameSpecSpec](#talos.resource.definitions.network.HostnameSpecSpec)\n    - [HostnameStatusSpec](#talos.resource.definitions.network.HostnameStatusSpec)\n    - [LinkAliasSpecSpec](#talos.resource.definitions.network.LinkAliasSpecSpec)\n    - [LinkRefreshSpec](#talos.resource.definitions.network.LinkRefreshSpec)\n    - [LinkSpecSpec](#talos.resource.definitions.network.LinkSpecSpec)\n    - [LinkStatusSpec](#talos.resource.definitions.network.LinkStatusSpec)\n    - [NfTablesAddressMatch](#talos.resource.definitions.network.NfTablesAddressMatch)\n    - [NfTablesChainSpec](#talos.resource.definitions.network.NfTablesChainSpec)\n    - [NfTablesClampMSS](#talos.resource.definitions.network.NfTablesClampMSS)\n    - [NfTablesConntrackStateMatch](#talos.resource.definitions.network.NfTablesConntrackStateMatch)\n    - [NfTablesICMPTypeMatch](#talos.resource.definitions.network.NfTablesICMPTypeMatch)\n    - [NfTablesIfNameMatch](#talos.resource.definitions.network.NfTablesIfNameMatch)\n    - [NfTablesLayer4Match](#talos.resource.definitions.network.NfTablesLayer4Match)\n    - [NfTablesLimitMatch](#talos.resource.definitions.network.NfTablesLimitMatch)\n    - [NfTablesMark](#talos.resource.definitions.network.NfTablesMark)\n    - [NfTablesPortMatch](#talos.resource.definitions.network.NfTablesPortMatch)\n    - [NfTablesRule](#talos.resource.definitions.network.NfTablesRule)\n    - [NodeAddressFilterSpec](#talos.resource.definitions.network.NodeAddressFilterSpec)\n    - [NodeAddressSortAlgorithmSpec](#talos.resource.definitions.network.NodeAddressSortAlgorithmSpec)\n    - [NodeAddressSpec](#talos.resource.definitions.network.NodeAddressSpec)\n    - [OperatorSpecSpec](#talos.resource.definitions.network.OperatorSpecSpec)\n    - [PlatformConfigSpec](#talos.resource.definitions.network.PlatformConfigSpec)\n    - [PortRange](#talos.resource.definitions.network.PortRange)\n    - [ProbeSpecSpec](#talos.resource.definitions.network.ProbeSpecSpec)\n    - [ProbeStatusSpec](#talos.resource.definitions.network.ProbeStatusSpec)\n    - [ResolverSpecSpec](#talos.resource.definitions.network.ResolverSpecSpec)\n    - [ResolverStatusSpec](#talos.resource.definitions.network.ResolverStatusSpec)\n    - [RouteSpecSpec](#talos.resource.definitions.network.RouteSpecSpec)\n    - [RouteStatusSpec](#talos.resource.definitions.network.RouteStatusSpec)\n    - [RoutingRuleSpecSpec](#talos.resource.definitions.network.RoutingRuleSpecSpec)\n    - [RoutingRuleStatusSpec](#talos.resource.definitions.network.RoutingRuleStatusSpec)\n    - [STPSpec](#talos.resource.definitions.network.STPSpec)\n    - [StatusSpec](#talos.resource.definitions.network.StatusSpec)\n    - [TCPProbeSpec](#talos.resource.definitions.network.TCPProbeSpec)\n    - [TimeServerSpecSpec](#talos.resource.definitions.network.TimeServerSpecSpec)\n    - [TimeServerStatusSpec](#talos.resource.definitions.network.TimeServerStatusSpec)\n    - [VIPEquinixMetalSpec](#talos.resource.definitions.network.VIPEquinixMetalSpec)\n    - [VIPHCloudSpec](#talos.resource.definitions.network.VIPHCloudSpec)\n    - [VIPOperatorSpec](#talos.resource.definitions.network.VIPOperatorSpec)\n    - [VLANSpec](#talos.resource.definitions.network.VLANSpec)\n    - [VRFMasterSpec](#talos.resource.definitions.network.VRFMasterSpec)\n    - [VRFSlave](#talos.resource.definitions.network.VRFSlave)\n    - [WireguardPeer](#talos.resource.definitions.network.WireguardPeer)\n    - [WireguardSpec](#talos.resource.definitions.network.WireguardSpec)\n  \n- [resource/definitions/perf/perf.proto](#resource/definitions/perf/perf.proto)\n    - [CPUSpec](#talos.resource.definitions.perf.CPUSpec)\n    - [CPUStat](#talos.resource.definitions.perf.CPUStat)\n    - [MemorySpec](#talos.resource.definitions.perf.MemorySpec)\n  \n- [resource/definitions/secrets/secrets.proto](#resource/definitions/secrets/secrets.proto)\n    - [APICertsSpec](#talos.resource.definitions.secrets.APICertsSpec)\n    - [CertSANSpec](#talos.resource.definitions.secrets.CertSANSpec)\n    - [EncryptionSaltSpec](#talos.resource.definitions.secrets.EncryptionSaltSpec)\n    - [EtcdCertsSpec](#talos.resource.definitions.secrets.EtcdCertsSpec)\n    - [EtcdRootSpec](#talos.resource.definitions.secrets.EtcdRootSpec)\n    - [KubeletSpec](#talos.resource.definitions.secrets.KubeletSpec)\n    - [KubernetesCertsSpec](#talos.resource.definitions.secrets.KubernetesCertsSpec)\n    - [KubernetesDynamicCertsSpec](#talos.resource.definitions.secrets.KubernetesDynamicCertsSpec)\n    - [KubernetesRootSpec](#talos.resource.definitions.secrets.KubernetesRootSpec)\n    - [MaintenanceRootSpec](#talos.resource.definitions.secrets.MaintenanceRootSpec)\n    - [OSRootSpec](#talos.resource.definitions.secrets.OSRootSpec)\n    - [TrustdCertsSpec](#talos.resource.definitions.secrets.TrustdCertsSpec)\n  \n- [resource/definitions/security/security.proto](#resource/definitions/security/security.proto)\n    - [ImageKeylessVerifierSpec](#talos.resource.definitions.security.ImageKeylessVerifierSpec)\n    - [ImagePublicKeyVerifierSpec](#talos.resource.definitions.security.ImagePublicKeyVerifierSpec)\n    - [ImageVerificationRuleSpec](#talos.resource.definitions.security.ImageVerificationRuleSpec)\n    - [TUFTrustedRootSpec](#talos.resource.definitions.security.TUFTrustedRootSpec)\n  \n- [resource/definitions/siderolink/siderolink.proto](#resource/definitions/siderolink/siderolink.proto)\n    - [ConfigSpec](#talos.resource.definitions.siderolink.ConfigSpec)\n    - [StatusSpec](#talos.resource.definitions.siderolink.StatusSpec)\n    - [TunnelSpec](#talos.resource.definitions.siderolink.TunnelSpec)\n  \n- [resource/definitions/time/time.proto](#resource/definitions/time/time.proto)\n    - [AdjtimeStatusSpec](#talos.resource.definitions.time.AdjtimeStatusSpec)\n    - [StatusSpec](#talos.resource.definitions.time.StatusSpec)\n  \n- [resource/definitions/v1alpha1/v1alpha1.proto](#resource/definitions/v1alpha1/v1alpha1.proto)\n    - [ServiceSpec](#talos.resource.definitions.v1alpha1.ServiceSpec)\n  \n- [resource/network/device_config.proto](#resource/network/device_config.proto)\n    - [DeviceConfigSpecSpec](#resource.network.DeviceConfigSpecSpec)\n  \n- [security/security.proto](#security/security.proto)\n    - [CertificateRequest](#securityapi.CertificateRequest)\n    - [CertificateResponse](#securityapi.CertificateResponse)\n  \n    - [SecurityService](#securityapi.SecurityService)\n  \n- [storage/storage.proto](#storage/storage.proto)\n    - [BlockDeviceWipe](#storage.BlockDeviceWipe)\n    - [BlockDeviceWipeDescriptor](#storage.BlockDeviceWipeDescriptor)\n    - [BlockDeviceWipeRequest](#storage.BlockDeviceWipeRequest)\n    - [BlockDeviceWipeResponse](#storage.BlockDeviceWipeResponse)\n    - [Disk](#storage.Disk)\n    - [Disks](#storage.Disks)\n    - [DisksResponse](#storage.DisksResponse)\n  \n    - [BlockDeviceWipeDescriptor.Method](#storage.BlockDeviceWipeDescriptor.Method)\n    - [Disk.DiskType](#storage.Disk.DiskType)\n  \n    - [StorageService](#storage.StorageService)\n  \n- [time/time.proto](#time/time.proto)\n    - [Time](#time.Time)\n    - [TimeRequest](#time.TimeRequest)\n    - [TimeResponse](#time.TimeResponse)\n  \n    - [TimeService](#time.TimeService)\n  \n- [Scalar Value Types](#scalar-value-types)\n\n\n\n<a name=\"common/common.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## common/common.proto\n\n\n\n<a name=\"common.ContainerdInstance\"></a>\n\n### ContainerdInstance\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| driver | [ContainerDriver](#common.ContainerDriver) |  | Containerd instance to use. |\n| namespace | [ContainerdNamespace](#common.ContainerdNamespace) |  | Containerd namespace to use. |\n\n\n\n\n\n\n<a name=\"common.Data\"></a>\n\n### Data\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [Metadata](#common.Metadata) |  |  |\n| bytes | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"common.DataResponse\"></a>\n\n### DataResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Data](#common.Data) | repeated |  |\n\n\n\n\n\n\n<a name=\"common.Empty\"></a>\n\n### Empty\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"common.EmptyResponse\"></a>\n\n### EmptyResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Empty](#common.Empty) | repeated |  |\n\n\n\n\n\n\n<a name=\"common.Error\"></a>\n\n### Error\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| code | [Code](#common.Code) |  |  |\n| message | [string](#string) |  |  |\n| details | [google.protobuf.Any](#google.protobuf.Any) | repeated |  |\n\n\n\n\n\n\n<a name=\"common.Metadata\"></a>\n\n### Metadata\nCommon metadata message nested in all reply message types\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostname | [string](#string) |  | hostname of the server response comes from (injected by proxy) |\n| error | [string](#string) |  | error is set if request failed to the upstream (rest of response is undefined) |\n| status | [google.rpc.Status](#google.rpc.Status) |  | error as gRPC Status |\n\n\n\n\n\n\n<a name=\"common.NetIP\"></a>\n\n### NetIP\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ip | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"common.NetIPPort\"></a>\n\n### NetIPPort\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ip | [bytes](#bytes) |  |  |\n| port | [int32](#int32) |  |  |\n\n\n\n\n\n\n<a name=\"common.NetIPPrefix\"></a>\n\n### NetIPPrefix\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ip | [bytes](#bytes) |  |  |\n| prefix_length | [int32](#int32) |  |  |\n\n\n\n\n\n\n<a name=\"common.PEMEncodedCertificate\"></a>\n\n### PEMEncodedCertificate\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| crt | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"common.PEMEncodedCertificateAndKey\"></a>\n\n### PEMEncodedCertificateAndKey\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| crt | [bytes](#bytes) |  |  |\n| key | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"common.PEMEncodedKey\"></a>\n\n### PEMEncodedKey\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"common.URL\"></a>\n\n### URL\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| full_path | [string](#string) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"common.Code\"></a>\n\n### Code\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FATAL | 0 |  |\n| LOCKED | 1 |  |\n| CANCELED | 2 |  |\n\n\n\n<a name=\"common.ContainerDriver\"></a>\n\n### ContainerDriver\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| CONTAINERD | 0 |  |\n| CRI | 1 |  |\n\n\n\n<a name=\"common.ContainerdNamespace\"></a>\n\n### ContainerdNamespace\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NS_UNKNOWN | 0 |  |\n| NS_SYSTEM | 1 |  |\n| NS_CRI | 2 |  |\n\n\n <!-- end enums -->\n\n\n<a name=\"common/common.proto-extensions\"></a>\n\n### File-level Extensions\n| Extension | Type | Base | Number | Description |\n| --------- | ---- | ---- | ------ | ----------- |\n| remove_deprecated_enum | string | .google.protobuf.EnumOptions | 93117 | Indicates the Talos version when this deprecated enum will be removed from API. |\n| remove_deprecated_enum_value | string | .google.protobuf.EnumValueOptions | 93117 | Indicates the Talos version when this deprecated enum value will be removed from API. |\n| remove_deprecated_field | string | .google.protobuf.FieldOptions | 93117 | Indicates the Talos version when this deprecated filed will be removed from API. |\n| remove_deprecated_message | string | .google.protobuf.MessageOptions | 93117 | Indicates the Talos version when this deprecated message will be removed from API. |\n| remove_deprecated_method | string | .google.protobuf.MethodOptions | 93117 | Indicates the Talos version when this deprecated method will be removed from API. |\n| remove_deprecated_service | string | .google.protobuf.ServiceOptions | 93117 | Indicates the Talos version when this deprecated service will be removed from API. |\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"cluster/cluster.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## cluster/cluster.proto\n\n\n\n<a name=\"cluster.ClusterInfo\"></a>\n\n### ClusterInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| control_plane_nodes | [string](#string) | repeated |  |\n| worker_nodes | [string](#string) | repeated |  |\n| force_endpoint | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"cluster.HealthCheckProgress\"></a>\n\n### HealthCheckProgress\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| message | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"cluster.HealthCheckRequest\"></a>\n\n### HealthCheckRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| wait_timeout | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| cluster_info | [ClusterInfo](#cluster.ClusterInfo) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"cluster.ClusterService\"></a>\n\n### ClusterService\nThe cluster service definition.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| HealthCheck | [HealthCheckRequest](#cluster.HealthCheckRequest) | [HealthCheckProgress](#cluster.HealthCheckProgress) stream |  |\n\n <!-- end services -->\n\n\n\n<a name=\"inspect/inspect.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## inspect/inspect.proto\n\n\n\n<a name=\"inspect.ControllerDependencyEdge\"></a>\n\n### ControllerDependencyEdge\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| controller_name | [string](#string) |  |  |\n| edge_type | [DependencyEdgeType](#inspect.DependencyEdgeType) |  |  |\n| resource_namespace | [string](#string) |  |  |\n| resource_type | [string](#string) |  |  |\n| resource_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"inspect.ControllerRuntimeDependenciesResponse\"></a>\n\n### ControllerRuntimeDependenciesResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ControllerRuntimeDependency](#inspect.ControllerRuntimeDependency) | repeated |  |\n\n\n\n\n\n\n<a name=\"inspect.ControllerRuntimeDependency\"></a>\n\n### ControllerRuntimeDependency\nThe ControllerRuntimeDependency message contains the graph of controller-resource dependencies.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| edges | [ControllerDependencyEdge](#inspect.ControllerDependencyEdge) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"inspect.DependencyEdgeType\"></a>\n\n### DependencyEdgeType\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| OUTPUT_EXCLUSIVE | 0 |  |\n| OUTPUT_SHARED | 3 |  |\n| INPUT_STRONG | 1 |  |\n| INPUT_WEAK | 2 |  |\n| INPUT_DESTROY_READY | 4 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"inspect.InspectService\"></a>\n\n### InspectService\nThe inspect service definition.\n\nInspectService provides auxiliary API to inspect OS internals.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| ControllerRuntimeDependencies | [.google.protobuf.Empty](#google.protobuf.Empty) | [ControllerRuntimeDependenciesResponse](#inspect.ControllerRuntimeDependenciesResponse) |  |\n\n <!-- end services -->\n\n\n\n<a name=\"machine/debug.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## machine/debug.proto\n\n\n\n<a name=\"machine.DebugContainerRunRequest\"></a>\n\n### DebugContainerRunRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| spec | [DebugContainerRunRequestSpec](#machine.DebugContainerRunRequestSpec) |  | 1. send the container spec |\n| stdin_data | [bytes](#bytes) |  | 2. send either of the three below to interact with the running container |\n| signal | [int32](#int32) |  |  |\n| term_resize | [DebugContainerTerminalResize](#machine.DebugContainerTerminalResize) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DebugContainerRunRequestSpec\"></a>\n\n### DebugContainerRunRequestSpec\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  |  |\n| image_name | [string](#string) |  |  |\n| args | [string](#string) | repeated |  |\n| env | [DebugContainerRunRequestSpec.EnvEntry](#machine.DebugContainerRunRequestSpec.EnvEntry) | repeated |  |\n| profile | [DebugContainerRunRequestSpec.Profile](#machine.DebugContainerRunRequestSpec.Profile) |  |  |\n| tty | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DebugContainerRunRequestSpec.EnvEntry\"></a>\n\n### DebugContainerRunRequestSpec.EnvEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DebugContainerRunResponse\"></a>\n\n### DebugContainerRunResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| stdout_data | [bytes](#bytes) |  |  |\n| exit_code | [int32](#int32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DebugContainerTerminalResize\"></a>\n\n### DebugContainerTerminalResize\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| width | [int32](#int32) |  |  |\n| height | [int32](#int32) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"machine.DebugContainerRunRequestSpec.Profile\"></a>\n\n### DebugContainerRunRequestSpec.Profile\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| PROFILE_UNSPECIFIED | 0 |  |\n| PROFILE_PRIVILEGED | 1 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"machine.DebugService\"></a>\n\n### DebugService\nDebugService provides debugging and inspection capabilities for a Talos node.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| ContainerRun | [DebugContainerRunRequest](#machine.DebugContainerRunRequest) stream | [DebugContainerRunResponse](#machine.DebugContainerRunResponse) stream | ContainerRun runs a debug container, attaches to it, and streams I/O. |\n\n <!-- end services -->\n\n\n\n<a name=\"machine/image.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## machine/image.proto\n\n\n\n<a name=\"machine.ImageServiceCredentials\"></a>\n\n### ImageServiceCredentials\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| host | [string](#string) |  | Host of the registry (e.g. \"docker.io\"). |\n| username | [string](#string) |  | Username for the registry. |\n| password | [string](#string) |  | Password (token) for the registry. |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceImportRequest\"></a>\n\n### ImageServiceImportRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  | Containerd instance to use. |\n| image_chunk | [common.Data](#common.Data) |  | Chunk of the image tarball. |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceImportResponse\"></a>\n\n### ImageServiceImportResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  | Name of the imported image. |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceListRequest\"></a>\n\n### ImageServiceListRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceListResponse\"></a>\n\n### ImageServiceListResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| digest | [string](#string) |  |  |\n| size | [int64](#int64) |  |  |\n| created_at | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n| labels | [ImageServiceListResponse.LabelsEntry](#machine.ImageServiceListResponse.LabelsEntry) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceListResponse.LabelsEntry\"></a>\n\n### ImageServiceListResponse.LabelsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImageServicePullLayerProgress\"></a>\n\n### ImageServicePullLayerProgress\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| status | [ImageServicePullLayerProgress.Status](#machine.ImageServicePullLayerProgress.Status) |  |  |\n| elapsed | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| offset | [int64](#int64) |  |  |\n| total | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImageServicePullProgress\"></a>\n\n### ImageServicePullProgress\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| layer_id | [string](#string) |  |  |\n| progress | [ImageServicePullLayerProgress](#machine.ImageServicePullLayerProgress) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImageServicePullRequest\"></a>\n\n### ImageServicePullRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  |  |\n| image_ref | [string](#string) |  | Image reference to pull. |\n\n\n\n\n\n\n<a name=\"machine.ImageServicePullResponse\"></a>\n\n### ImageServicePullResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  | Name of the pulled image (when done). |\n| pull_progress | [ImageServicePullProgress](#machine.ImageServicePullProgress) |  | Progress of the image pull (intermediate updates). |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceRemoveRequest\"></a>\n\n### ImageServiceRemoveRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  |  |\n| image_ref | [string](#string) |  | Image reference to remove. |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceVerifyRequest\"></a>\n\n### ImageServiceVerifyRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image_ref | [string](#string) |  | Image reference to verify.<br><br>The image reference could be either in: * the digest form (e.g. \"docker.io/library/nginx@sha256:abc123...\") to ensure that the exact image is verified. * the tag form (e.g. \"docker.io/library/nginx:latest\") to verify the image currently pointed by the tag, and the resolved digested will be returned in the response.<br><br>Any other format will cause the error. |\n| credentials | [ImageServiceCredentials](#machine.ImageServiceCredentials) |  | Authentication credentials for the registry (if needed).<br><br>By default Talos will use configured auth, but additional image pull secret can be submitted here. |\n\n\n\n\n\n\n<a name=\"machine.ImageServiceVerifyResponse\"></a>\n\n### ImageServiceVerifyResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| verified | [bool](#bool) |  | Was the image verified: if it didn't match any verify rule, false will be returned. If the image matched the rule, but the verification failed, an error will be returned. |\n| message | [string](#string) |  | Free-form verification result message, e.g. with details about the matched rule and how the image was verified. |\n| digested_image_ref | [string](#string) |  | The pinned image reference with resolved digest that was verified (e.g. \"docker.io/library/nginx@sha256:abc123...\").<br><br>This is only set if verified=true. |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"machine.ImageServicePullLayerProgress.Status\"></a>\n\n### ImageServicePullLayerProgress.Status\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| DOWNLOADING | 0 | Keep this in sync with ImagePullLayerProgress.Status. |\n| DOWNLOAD_COMPLETE | 1 |  |\n| EXTRACTING | 2 |  |\n| EXTRACT_COMPLETE | 3 |  |\n| ALREADY_EXISTS | 4 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"machine.ImageService\"></a>\n\n### ImageService\nThe machine service definition.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| List | [ImageServiceListRequest](#machine.ImageServiceListRequest) | [ImageServiceListResponse](#machine.ImageServiceListResponse) stream | List images in the containerd. |\n| Pull | [ImageServicePullRequest](#machine.ImageServicePullRequest) | [ImageServicePullResponse](#machine.ImageServicePullResponse) stream | Pull an image into the containerd. |\n| Import | [ImageServiceImportRequest](#machine.ImageServiceImportRequest) stream | [ImageServiceImportResponse](#machine.ImageServiceImportResponse) | Import an image from a stream (tarball). |\n| Remove | [ImageServiceRemoveRequest](#machine.ImageServiceRemoveRequest) | [.google.protobuf.Empty](#google.protobuf.Empty) | Remove an image from the containerd. |\n| Verify | [ImageServiceVerifyRequest](#machine.ImageServiceVerifyRequest) | [ImageServiceVerifyResponse](#machine.ImageServiceVerifyResponse) | Verify an image signature. |\n\n <!-- end services -->\n\n\n\n<a name=\"machine/lifecycle.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## machine/lifecycle.proto\n\n\n\n<a name=\"machine.InstallArtifactsSource\"></a>\n\n### InstallArtifactsSource\nInstallArtifactsSource specifies the source of the installation artifacts.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image_name | [string](#string) |  | The reference name of the image, as returned by `talosctl image pull`. |\n\n\n\n\n\n\n<a name=\"machine.InstallDestination\"></a>\n\n### InstallDestination\nInstallDestination specifies the target for installation.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| disk | [string](#string) |  | The disk to which Talos should be installed, e.g. \"/dev/sda\". |\n\n\n\n\n\n\n<a name=\"machine.LifecycleServiceInstallProgress\"></a>\n\n### LifecycleServiceInstallProgress\nLifecycleServiceInstallProgress represents the progress of the installation or upgrade process.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| message | [string](#string) |  | A message indicating the current progress of the installation or upgrade. |\n| exit_code | [int32](#int32) |  | An exit code indicating the result of the installation or upgrade process. A non-zero value indicates an error. Server SHOULD NOT respond with error, even if the value is non-zero. It's responsibility of the client to handle the exit code appropriately. |\n\n\n\n\n\n\n<a name=\"machine.LifecycleServiceInstallRequest\"></a>\n\n### LifecycleServiceInstallRequest\nLifecycleServiceInstallRequest contains the necessary information to perform an installation.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  | The containerd instance to use for pulling the installation artifacts. |\n| source | [InstallArtifactsSource](#machine.InstallArtifactsSource) |  | The source of the installation artifacts. |\n| destination | [InstallDestination](#machine.InstallDestination) |  | The destination for the installation. |\n\n\n\n\n\n\n<a name=\"machine.LifecycleServiceInstallResponse\"></a>\n\n### LifecycleServiceInstallResponse\nLifecycleServiceInstallResponse is the response message for the Install RPC, containing progress updates.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| progress | [LifecycleServiceInstallProgress](#machine.LifecycleServiceInstallProgress) |  | The progress of the installation process. |\n\n\n\n\n\n\n<a name=\"machine.LifecycleServiceUpgradeRequest\"></a>\n\n### LifecycleServiceUpgradeRequest\nLifecycleServiceUpgradeRequest contains the necessary information to perform an upgrade.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| containerd | [common.ContainerdInstance](#common.ContainerdInstance) |  | The containerd instance to use for pulling the installation artifacts. |\n| source | [InstallArtifactsSource](#machine.InstallArtifactsSource) |  | The source of the installation artifacts for the upgrade. |\n\n\n\n\n\n\n<a name=\"machine.LifecycleServiceUpgradeResponse\"></a>\n\n### LifecycleServiceUpgradeResponse\nLifecycleServiceUpgradeResponse is the response message for the Upgrade RPC, containing progress updates.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| progress | [LifecycleServiceInstallProgress](#machine.LifecycleServiceInstallProgress) |  | The progress of the upgrade process. |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"machine.LifecycleService\"></a>\n\n### LifecycleService\nThe LifecycleService handles installation and upgrade operations.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| Install | [LifecycleServiceInstallRequest](#machine.LifecycleServiceInstallRequest) | [LifecycleServiceInstallResponse](#machine.LifecycleServiceInstallResponse) stream | Install Talos to disk. The RPC should fail if the Talos is already installed on the target disk. |\n| Upgrade | [LifecycleServiceUpgradeRequest](#machine.LifecycleServiceUpgradeRequest) | [LifecycleServiceUpgradeResponse](#machine.LifecycleServiceUpgradeResponse) stream | Upgrade Talos to a new version. The RPC should fail if Talos is not already installed on the target disk. |\n\n <!-- end services -->\n\n\n\n<a name=\"machine/machine.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## machine/machine.proto\n\n\n\n<a name=\"machine.AddressEvent\"></a>\n\n### AddressEvent\nAddressEvent reports node endpoints aggregated from k8s.Endpoints and network.Hostname.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostname | [string](#string) |  |  |\n| addresses | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ApplyConfiguration\"></a>\n\n### ApplyConfiguration\nApplyConfigurationResponse describes the response to a configuration request.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| warnings | [string](#string) | repeated | Configuration validation warnings. |\n| mode | [ApplyConfigurationRequest.Mode](#machine.ApplyConfigurationRequest.Mode) |  | States which mode was actually chosen. |\n| mode_details | [string](#string) |  | Human-readable message explaining the result of the apply configuration call. |\n\n\n\n\n\n\n<a name=\"machine.ApplyConfigurationRequest\"></a>\n\n### ApplyConfigurationRequest\nrpc applyConfiguration\nApplyConfiguration describes a request to assert a new configuration upon a\nnode.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| data | [bytes](#bytes) |  |  |\n| mode | [ApplyConfigurationRequest.Mode](#machine.ApplyConfigurationRequest.Mode) |  |  |\n| dry_run | [bool](#bool) |  |  |\n| try_mode_timeout | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ApplyConfigurationResponse\"></a>\n\n### ApplyConfigurationResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ApplyConfiguration](#machine.ApplyConfiguration) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.BPFInstruction\"></a>\n\n### BPFInstruction\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| op | [uint32](#uint32) |  |  |\n| jt | [uint32](#uint32) |  |  |\n| jf | [uint32](#uint32) |  |  |\n| k | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Bootstrap\"></a>\n\n### Bootstrap\nThe bootstrap message containing the bootstrap status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.BootstrapRequest\"></a>\n\n### BootstrapRequest\nrpc Bootstrap\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| recover_etcd | [bool](#bool) |  | Enable etcd recovery from the snapshot. Snapshot should be uploaded before this call via EtcdRecover RPC. |\n| recover_skip_hash_check | [bool](#bool) |  | Skip hash check on the snapshot (etcd). Enable this when recovering from data directory copy to skip integrity check. |\n\n\n\n\n\n\n<a name=\"machine.BootstrapResponse\"></a>\n\n### BootstrapResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Bootstrap](#machine.Bootstrap) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.CNIConfig\"></a>\n\n### CNIConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| urls | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.CPUFreqStats\"></a>\n\n### CPUFreqStats\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| current_frequency | [uint64](#uint64) |  |  |\n| minimum_frequency | [uint64](#uint64) |  |  |\n| maximum_frequency | [uint64](#uint64) |  |  |\n| governor | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.CPUFreqStatsResponse\"></a>\n\n### CPUFreqStatsResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [CPUsFreqStats](#machine.CPUsFreqStats) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.CPUInfo\"></a>\n\n### CPUInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| processor | [uint32](#uint32) |  |  |\n| vendor_id | [string](#string) |  |  |\n| cpu_family | [string](#string) |  |  |\n| model | [string](#string) |  |  |\n| model_name | [string](#string) |  |  |\n| stepping | [string](#string) |  |  |\n| microcode | [string](#string) |  |  |\n| cpu_mhz | [double](#double) |  |  |\n| cache_size | [string](#string) |  |  |\n| physical_id | [string](#string) |  |  |\n| siblings | [uint32](#uint32) |  |  |\n| core_id | [string](#string) |  |  |\n| cpu_cores | [uint32](#uint32) |  |  |\n| apic_id | [string](#string) |  |  |\n| initial_apic_id | [string](#string) |  |  |\n| fpu | [string](#string) |  |  |\n| fpu_exception | [string](#string) |  |  |\n| cpu_id_level | [uint32](#uint32) |  |  |\n| wp | [string](#string) |  |  |\n| flags | [string](#string) | repeated |  |\n| bugs | [string](#string) | repeated |  |\n| bogo_mips | [double](#double) |  |  |\n| cl_flush_size | [uint32](#uint32) |  |  |\n| cache_alignment | [uint32](#uint32) |  |  |\n| address_sizes | [string](#string) |  |  |\n| power_management | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.CPUInfoResponse\"></a>\n\n### CPUInfoResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [CPUsInfo](#machine.CPUsInfo) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.CPUStat\"></a>\n\n### CPUStat\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| user | [double](#double) |  |  |\n| nice | [double](#double) |  |  |\n| system | [double](#double) |  |  |\n| idle | [double](#double) |  |  |\n| iowait | [double](#double) |  |  |\n| irq | [double](#double) |  |  |\n| soft_irq | [double](#double) |  |  |\n| steal | [double](#double) |  |  |\n| guest | [double](#double) |  |  |\n| guest_nice | [double](#double) |  |  |\n\n\n\n\n\n\n<a name=\"machine.CPUsFreqStats\"></a>\n\n### CPUsFreqStats\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| cpu_freq_stats | [CPUFreqStats](#machine.CPUFreqStats) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.CPUsInfo\"></a>\n\n### CPUsInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| cpu_info | [CPUInfo](#machine.CPUInfo) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ClusterConfig\"></a>\n\n### ClusterConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| control_plane | [ControlPlaneConfig](#machine.ControlPlaneConfig) |  |  |\n| cluster_network | [ClusterNetworkConfig](#machine.ClusterNetworkConfig) |  |  |\n| allow_scheduling_on_control_planes | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ClusterNetworkConfig\"></a>\n\n### ClusterNetworkConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| dns_domain | [string](#string) |  |  |\n| cni_config | [CNIConfig](#machine.CNIConfig) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ConfigLoadErrorEvent\"></a>\n\n### ConfigLoadErrorEvent\nConfigLoadErrorEvent is reported when the config loading has failed.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| error | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ConfigValidationErrorEvent\"></a>\n\n### ConfigValidationErrorEvent\nConfigValidationErrorEvent is reported when config validation has failed.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| error | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ConnectRecord\"></a>\n\n### ConnectRecord\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| l4proto | [string](#string) |  |  |\n| localip | [string](#string) |  |  |\n| localport | [uint32](#uint32) |  |  |\n| remoteip | [string](#string) |  |  |\n| remoteport | [uint32](#uint32) |  |  |\n| state | [ConnectRecord.State](#machine.ConnectRecord.State) |  |  |\n| txqueue | [uint64](#uint64) |  |  |\n| rxqueue | [uint64](#uint64) |  |  |\n| tr | [ConnectRecord.TimerActive](#machine.ConnectRecord.TimerActive) |  |  |\n| timerwhen | [uint64](#uint64) |  |  |\n| retrnsmt | [uint64](#uint64) |  |  |\n| uid | [uint32](#uint32) |  |  |\n| timeout | [uint64](#uint64) |  |  |\n| inode | [uint64](#uint64) |  |  |\n| ref | [uint64](#uint64) |  |  |\n| pointer | [uint64](#uint64) |  |  |\n| process | [ConnectRecord.Process](#machine.ConnectRecord.Process) |  |  |\n| netns | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ConnectRecord.Process\"></a>\n\n### ConnectRecord.Process\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pid | [uint32](#uint32) |  |  |\n| name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Container\"></a>\n\n### Container\nThe messages message containing the requested containers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| containers | [ContainerInfo](#machine.ContainerInfo) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ContainerInfo\"></a>\n\n### ContainerInfo\nThe messages message containing the requested containers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| id | [string](#string) |  |  |\n| uid | [string](#string) |  |  |\n| internal_id | [string](#string) |  |  |\n| image | [string](#string) |  |  |\n| pid | [uint32](#uint32) |  |  |\n| status | [string](#string) |  |  |\n| pod_id | [string](#string) |  |  |\n| name | [string](#string) |  |  |\n| network_namespace | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ContainersRequest\"></a>\n\n### ContainersRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| driver | [common.ContainerDriver](#common.ContainerDriver) |  | driver might be default \"containerd\" or \"cri\" |\n\n\n\n\n\n\n<a name=\"machine.ContainersResponse\"></a>\n\n### ContainersResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Container](#machine.Container) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ControlPlaneConfig\"></a>\n\n### ControlPlaneConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.CopyRequest\"></a>\n\n### CopyRequest\nCopyRequest describes a request to copy data out of Talos node\n\nCopy produces .tar.gz archive which is streamed back to the caller\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| root_path | [string](#string) |  | Root path to start copying data out, it might be either a file or directory |\n\n\n\n\n\n\n<a name=\"machine.DHCPOptionsConfig\"></a>\n\n### DHCPOptionsConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| route_metric | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DiskStat\"></a>\n\n### DiskStat\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| read_completed | [uint64](#uint64) |  |  |\n| read_merged | [uint64](#uint64) |  |  |\n| read_sectors | [uint64](#uint64) |  |  |\n| read_time_ms | [uint64](#uint64) |  |  |\n| write_completed | [uint64](#uint64) |  |  |\n| write_merged | [uint64](#uint64) |  |  |\n| write_sectors | [uint64](#uint64) |  |  |\n| write_time_ms | [uint64](#uint64) |  |  |\n| io_in_progress | [uint64](#uint64) |  |  |\n| io_time_ms | [uint64](#uint64) |  |  |\n| io_time_weighted_ms | [uint64](#uint64) |  |  |\n| discard_completed | [uint64](#uint64) |  |  |\n| discard_merged | [uint64](#uint64) |  |  |\n| discard_sectors | [uint64](#uint64) |  |  |\n| discard_time_ms | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.DiskStats\"></a>\n\n### DiskStats\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| total | [DiskStat](#machine.DiskStat) |  |  |\n| devices | [DiskStat](#machine.DiskStat) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.DiskStatsResponse\"></a>\n\n### DiskStatsResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [DiskStats](#machine.DiskStats) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.DiskUsageInfo\"></a>\n\n### DiskUsageInfo\nDiskUsageInfo describes a file or directory's information for du command\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| name | [string](#string) |  | Name is the name (including prefixed path) of the file or directory |\n| size | [int64](#int64) |  | Size indicates the number of bytes contained within the file |\n| error | [string](#string) |  | Error describes any error encountered while trying to read the file information. |\n| relative_name | [string](#string) |  | RelativeName is the name of the file or directory relative to the RootPath |\n\n\n\n\n\n\n<a name=\"machine.DiskUsageRequest\"></a>\n\n### DiskUsageRequest\nDiskUsageRequest describes a request to list disk usage of directories and regular files\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| recursion_depth | [int32](#int32) |  | RecursionDepth indicates how many levels of subdirectories should be recursed. The default (0) indicates that no limit should be enforced. |\n| all | [bool](#bool) |  | All write sizes for all files, not just directories. |\n| threshold | [int64](#int64) |  | Threshold exclude entries smaller than SIZE if positive, or entries greater than SIZE if negative. |\n| paths | [string](#string) | repeated | DiskUsagePaths is the list of directories to calculate disk usage for. |\n\n\n\n\n\n\n<a name=\"machine.DmesgRequest\"></a>\n\n### DmesgRequest\ndmesg\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| follow | [bool](#bool) |  |  |\n| tail | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdAlarm\"></a>\n\n### EtcdAlarm\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| member_alarms | [EtcdMemberAlarm](#machine.EtcdMemberAlarm) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdAlarmDisarm\"></a>\n\n### EtcdAlarmDisarm\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| member_alarms | [EtcdMemberAlarm](#machine.EtcdMemberAlarm) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdAlarmDisarmResponse\"></a>\n\n### EtcdAlarmDisarmResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdAlarmDisarm](#machine.EtcdAlarmDisarm) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdAlarmListResponse\"></a>\n\n### EtcdAlarmListResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdAlarm](#machine.EtcdAlarm) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdClusterDowngrade\"></a>\n\n### EtcdClusterDowngrade\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| cluster_version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDefragment\"></a>\n\n### EtcdDefragment\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDefragmentResponse\"></a>\n\n### EtcdDefragmentResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdDefragment](#machine.EtcdDefragment) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeCancel\"></a>\n\n### EtcdDowngradeCancel\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| cluster_downgrade | [EtcdClusterDowngrade](#machine.EtcdClusterDowngrade) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeCancelResponse\"></a>\n\n### EtcdDowngradeCancelResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdDowngradeCancel](#machine.EtcdDowngradeCancel) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeEnable\"></a>\n\n### EtcdDowngradeEnable\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| cluster_downgrade | [EtcdClusterDowngrade](#machine.EtcdClusterDowngrade) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeEnableRequest\"></a>\n\n### EtcdDowngradeEnableRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeEnableResponse\"></a>\n\n### EtcdDowngradeEnableResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdDowngradeEnable](#machine.EtcdDowngradeEnable) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeValidate\"></a>\n\n### EtcdDowngradeValidate\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| cluster_downgrade | [EtcdClusterDowngrade](#machine.EtcdClusterDowngrade) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeValidateRequest\"></a>\n\n### EtcdDowngradeValidateRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdDowngradeValidateResponse\"></a>\n\n### EtcdDowngradeValidateResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdDowngradeValidate](#machine.EtcdDowngradeValidate) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdForfeitLeadership\"></a>\n\n### EtcdForfeitLeadership\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| member | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdForfeitLeadershipRequest\"></a>\n\n### EtcdForfeitLeadershipRequest\n\n\n\n\n\n\n\n<a name=\"machine.EtcdForfeitLeadershipResponse\"></a>\n\n### EtcdForfeitLeadershipResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdForfeitLeadership](#machine.EtcdForfeitLeadership) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdLeaveCluster\"></a>\n\n### EtcdLeaveCluster\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdLeaveClusterRequest\"></a>\n\n### EtcdLeaveClusterRequest\n\n\n\n\n\n\n\n<a name=\"machine.EtcdLeaveClusterResponse\"></a>\n\n### EtcdLeaveClusterResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdLeaveCluster](#machine.EtcdLeaveCluster) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdMember\"></a>\n\n### EtcdMember\nEtcdMember describes a single etcd member.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| id | [uint64](#uint64) |  | member ID. |\n| hostname | [string](#string) |  | human-readable name of the member. |\n| peer_urls | [string](#string) | repeated | the list of URLs the member exposes to clients for communication. |\n| client_urls | [string](#string) | repeated | the list of URLs the member exposes to the cluster for communication. |\n| is_learner | [bool](#bool) |  | learner flag |\n\n\n\n\n\n\n<a name=\"machine.EtcdMemberAlarm\"></a>\n\n### EtcdMemberAlarm\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| member_id | [uint64](#uint64) |  |  |\n| alarm | [EtcdMemberAlarm.AlarmType](#machine.EtcdMemberAlarm.AlarmType) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdMemberListRequest\"></a>\n\n### EtcdMemberListRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| query_local | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdMemberListResponse\"></a>\n\n### EtcdMemberListResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdMembers](#machine.EtcdMembers) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdMemberStatus\"></a>\n\n### EtcdMemberStatus\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| storage_version | [string](#string) |  |  |\n| member_id | [uint64](#uint64) |  |  |\n| protocol_version | [string](#string) |  |  |\n| db_size | [int64](#int64) |  |  |\n| db_size_in_use | [int64](#int64) |  |  |\n| leader | [uint64](#uint64) |  |  |\n| raft_index | [uint64](#uint64) |  |  |\n| raft_term | [uint64](#uint64) |  |  |\n| raft_applied_index | [uint64](#uint64) |  |  |\n| errors | [string](#string) | repeated |  |\n| is_learner | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdMembers\"></a>\n\n### EtcdMembers\nEtcdMembers contains the list of members registered on the host.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| legacy_members | [string](#string) | repeated | list of member hostnames. |\n| members | [EtcdMember](#machine.EtcdMember) | repeated | the list of etcd members registered on the node. |\n\n\n\n\n\n\n<a name=\"machine.EtcdRecover\"></a>\n\n### EtcdRecover\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRecoverResponse\"></a>\n\n### EtcdRecoverResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdRecover](#machine.EtcdRecover) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMember\"></a>\n\n### EtcdRemoveMember\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMemberByID\"></a>\n\n### EtcdRemoveMemberByID\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMemberByIDRequest\"></a>\n\n### EtcdRemoveMemberByIDRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| member_id | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMemberByIDResponse\"></a>\n\n### EtcdRemoveMemberByIDResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdRemoveMemberByID](#machine.EtcdRemoveMemberByID) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMemberRequest\"></a>\n\n### EtcdRemoveMemberRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| member | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdRemoveMemberResponse\"></a>\n\n### EtcdRemoveMemberResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdRemoveMember](#machine.EtcdRemoveMember) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdSnapshotRequest\"></a>\n\n### EtcdSnapshotRequest\n\n\n\n\n\n\n\n<a name=\"machine.EtcdStatus\"></a>\n\n### EtcdStatus\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| member_status | [EtcdMemberStatus](#machine.EtcdMemberStatus) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EtcdStatusResponse\"></a>\n\n### EtcdStatusResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [EtcdStatus](#machine.EtcdStatus) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Event\"></a>\n\n### Event\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| data | [google.protobuf.Any](#google.protobuf.Any) |  |  |\n| id | [string](#string) |  |  |\n| actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.EventsRequest\"></a>\n\n### EventsRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| tail_events | [int32](#int32) |  |  |\n| tail_id | [string](#string) |  |  |\n| tail_seconds | [int32](#int32) |  |  |\n| with_actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.FeaturesInfo\"></a>\n\n### FeaturesInfo\nFeaturesInfo describes individual Talos features that can be switched on or off.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rbac | [bool](#bool) |  | RBAC is true if role-based access control is enabled. |\n\n\n\n\n\n\n<a name=\"machine.FileInfo\"></a>\n\n### FileInfo\nFileInfo describes a file or directory's information\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| name | [string](#string) |  | Name is the name (including prefixed path) of the file or directory |\n| size | [int64](#int64) |  | Size indicates the number of bytes contained within the file |\n| mode | [uint32](#uint32) |  | Mode is the bitmap of UNIX mode/permission flags of the file |\n| modified | [int64](#int64) |  | Modified indicates the UNIX timestamp at which the file was last modified |\n| is_dir | [bool](#bool) |  | IsDir indicates that the file is a directory |\n| error | [string](#string) |  | Error describes any error encountered while trying to read the file information. |\n| link | [string](#string) |  | Link is filled with symlink target |\n| relative_name | [string](#string) |  | RelativeName is the name of the file or directory relative to the RootPath |\n| uid | [uint32](#uint32) |  | Owner uid |\n| gid | [uint32](#uint32) |  | Owner gid |\n| xattrs | [Xattr](#machine.Xattr) | repeated | Extended attributes (if present and requested) |\n\n\n\n\n\n\n<a name=\"machine.GenerateClientConfiguration\"></a>\n\n### GenerateClientConfiguration\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| ca | [bytes](#bytes) |  | PEM-encoded CA certificate. |\n| crt | [bytes](#bytes) |  | PEM-encoded generated client certificate. |\n| key | [bytes](#bytes) |  | PEM-encoded generated client key. |\n| talosconfig | [bytes](#bytes) |  | Client configuration (talosconfig) file content. |\n\n\n\n\n\n\n<a name=\"machine.GenerateClientConfigurationRequest\"></a>\n\n### GenerateClientConfigurationRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| roles | [string](#string) | repeated | Roles in the generated client certificate. |\n| crt_ttl | [google.protobuf.Duration](#google.protobuf.Duration) |  | Client certificate TTL. |\n\n\n\n\n\n\n<a name=\"machine.GenerateClientConfigurationResponse\"></a>\n\n### GenerateClientConfigurationResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [GenerateClientConfiguration](#machine.GenerateClientConfiguration) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Hostname\"></a>\n\n### Hostname\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| hostname | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.HostnameResponse\"></a>\n\n### HostnameResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Hostname](#machine.Hostname) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ImageListRequest\"></a>\n\n### ImageListRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [common.ContainerdNamespace](#common.ContainerdNamespace) |  | Containerd namespace to use. |\n\n\n\n\n\n\n<a name=\"machine.ImageListResponse\"></a>\n\n### ImageListResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| name | [string](#string) |  |  |\n| digest | [string](#string) |  |  |\n| size | [int64](#int64) |  |  |\n| created_at | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImagePull\"></a>\n\n### ImagePull\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ImagePullRequest\"></a>\n\n### ImagePullRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [common.ContainerdNamespace](#common.ContainerdNamespace) |  | Containerd namespace to use. |\n| reference | [string](#string) |  | Image reference to pull. |\n\n\n\n\n\n\n<a name=\"machine.ImagePullResponse\"></a>\n\n### ImagePullResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ImagePull](#machine.ImagePull) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.InstallConfig\"></a>\n\n### InstallConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| install_disk | [string](#string) |  |  |\n| install_image | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ListRequest\"></a>\n\n### ListRequest\nListRequest describes a request to list the contents of a directory.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| root | [string](#string) |  | Root indicates the root directory for the list. If not indicated, '/' is presumed. |\n| recurse | [bool](#bool) |  | Recurse indicates that subdirectories should be recursed. |\n| recursion_depth | [int32](#int32) |  | RecursionDepth indicates how many levels of subdirectories should be recursed. The default (0) indicates that no limit should be enforced. |\n| types | [ListRequest.Type](#machine.ListRequest.Type) | repeated | Types indicates what file type should be returned. If not indicated, all files will be returned. |\n| report_xattrs | [bool](#bool) |  | Report xattrs |\n\n\n\n\n\n\n<a name=\"machine.LoadAvg\"></a>\n\n### LoadAvg\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| load1 | [double](#double) |  |  |\n| load5 | [double](#double) |  |  |\n| load15 | [double](#double) |  |  |\n\n\n\n\n\n\n<a name=\"machine.LoadAvgResponse\"></a>\n\n### LoadAvgResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [LoadAvg](#machine.LoadAvg) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.LogsContainer\"></a>\n\n### LogsContainer\nLogsContainer describes all available registered log containers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| ids | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.LogsContainersResponse\"></a>\n\n### LogsContainersResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [LogsContainer](#machine.LogsContainer) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.LogsRequest\"></a>\n\n### LogsRequest\nrpc logs\nThe request message containing the process name.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| id | [string](#string) |  |  |\n| driver | [common.ContainerDriver](#common.ContainerDriver) |  | driver might be default \"containerd\" or \"cri\" |\n| follow | [bool](#bool) |  |  |\n| tail_lines | [int32](#int32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MachineConfig\"></a>\n\n### MachineConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [MachineConfig.MachineType](#machine.MachineConfig.MachineType) |  |  |\n| install_config | [InstallConfig](#machine.InstallConfig) |  |  |\n| network_config | [NetworkConfig](#machine.NetworkConfig) |  |  |\n| kubernetes_version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MachineStatusEvent\"></a>\n\n### MachineStatusEvent\nMachineStatusEvent reports changes to the MachineStatus resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| stage | [MachineStatusEvent.MachineStage](#machine.MachineStatusEvent.MachineStage) |  |  |\n| status | [MachineStatusEvent.MachineStatus](#machine.MachineStatusEvent.MachineStatus) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MachineStatusEvent.MachineStatus\"></a>\n\n### MachineStatusEvent.MachineStatus\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| unmet_conditions | [MachineStatusEvent.MachineStatus.UnmetCondition](#machine.MachineStatusEvent.MachineStatus.UnmetCondition) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.MachineStatusEvent.MachineStatus.UnmetCondition\"></a>\n\n### MachineStatusEvent.MachineStatus.UnmetCondition\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| reason | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MemInfo\"></a>\n\n### MemInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| memtotal | [uint64](#uint64) |  |  |\n| memfree | [uint64](#uint64) |  |  |\n| memavailable | [uint64](#uint64) |  |  |\n| buffers | [uint64](#uint64) |  |  |\n| cached | [uint64](#uint64) |  |  |\n| swapcached | [uint64](#uint64) |  |  |\n| active | [uint64](#uint64) |  |  |\n| inactive | [uint64](#uint64) |  |  |\n| activeanon | [uint64](#uint64) |  |  |\n| inactiveanon | [uint64](#uint64) |  |  |\n| activefile | [uint64](#uint64) |  |  |\n| inactivefile | [uint64](#uint64) |  |  |\n| unevictable | [uint64](#uint64) |  |  |\n| mlocked | [uint64](#uint64) |  |  |\n| swaptotal | [uint64](#uint64) |  |  |\n| swapfree | [uint64](#uint64) |  |  |\n| dirty | [uint64](#uint64) |  |  |\n| writeback | [uint64](#uint64) |  |  |\n| anonpages | [uint64](#uint64) |  |  |\n| mapped | [uint64](#uint64) |  |  |\n| shmem | [uint64](#uint64) |  |  |\n| slab | [uint64](#uint64) |  |  |\n| sreclaimable | [uint64](#uint64) |  |  |\n| sunreclaim | [uint64](#uint64) |  |  |\n| kernelstack | [uint64](#uint64) |  |  |\n| pagetables | [uint64](#uint64) |  |  |\n| nfsunstable | [uint64](#uint64) |  |  |\n| bounce | [uint64](#uint64) |  |  |\n| writebacktmp | [uint64](#uint64) |  |  |\n| commitlimit | [uint64](#uint64) |  |  |\n| committedas | [uint64](#uint64) |  |  |\n| vmalloctotal | [uint64](#uint64) |  |  |\n| vmallocused | [uint64](#uint64) |  |  |\n| vmallocchunk | [uint64](#uint64) |  |  |\n| hardwarecorrupted | [uint64](#uint64) |  |  |\n| anonhugepages | [uint64](#uint64) |  |  |\n| shmemhugepages | [uint64](#uint64) |  |  |\n| shmempmdmapped | [uint64](#uint64) |  |  |\n| cmatotal | [uint64](#uint64) |  |  |\n| cmafree | [uint64](#uint64) |  |  |\n| hugepagestotal | [uint64](#uint64) |  |  |\n| hugepagesfree | [uint64](#uint64) |  |  |\n| hugepagesrsvd | [uint64](#uint64) |  |  |\n| hugepagessurp | [uint64](#uint64) |  |  |\n| hugepagesize | [uint64](#uint64) |  |  |\n| directmap4k | [uint64](#uint64) |  |  |\n| directmap2m | [uint64](#uint64) |  |  |\n| directmap1g | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Memory\"></a>\n\n### Memory\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| meminfo | [MemInfo](#machine.MemInfo) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MemoryResponse\"></a>\n\n### MemoryResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Memory](#machine.Memory) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.MetaDelete\"></a>\n\n### MetaDelete\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MetaDeleteRequest\"></a>\n\n### MetaDeleteRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MetaDeleteResponse\"></a>\n\n### MetaDeleteResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [MetaDelete](#machine.MetaDelete) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.MetaWrite\"></a>\n\n### MetaWrite\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MetaWriteRequest\"></a>\n\n### MetaWriteRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [uint32](#uint32) |  |  |\n| value | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"machine.MetaWriteResponse\"></a>\n\n### MetaWriteResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [MetaWrite](#machine.MetaWrite) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.MountStat\"></a>\n\n### MountStat\nThe messages message containing the requested processes.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| filesystem | [string](#string) |  |  |\n| size | [uint64](#uint64) |  |  |\n| available | [uint64](#uint64) |  |  |\n| mounted_on | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Mounts\"></a>\n\n### Mounts\nThe messages message containing the requested df stats.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| stats | [MountStat](#machine.MountStat) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.MountsResponse\"></a>\n\n### MountsResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Mounts](#machine.Mounts) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetDev\"></a>\n\n### NetDev\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| rx_bytes | [uint64](#uint64) |  |  |\n| rx_packets | [uint64](#uint64) |  |  |\n| rx_errors | [uint64](#uint64) |  |  |\n| rx_dropped | [uint64](#uint64) |  |  |\n| rx_fifo | [uint64](#uint64) |  |  |\n| rx_frame | [uint64](#uint64) |  |  |\n| rx_compressed | [uint64](#uint64) |  |  |\n| rx_multicast | [uint64](#uint64) |  |  |\n| tx_bytes | [uint64](#uint64) |  |  |\n| tx_packets | [uint64](#uint64) |  |  |\n| tx_errors | [uint64](#uint64) |  |  |\n| tx_dropped | [uint64](#uint64) |  |  |\n| tx_fifo | [uint64](#uint64) |  |  |\n| tx_collisions | [uint64](#uint64) |  |  |\n| tx_carrier | [uint64](#uint64) |  |  |\n| tx_compressed | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Netstat\"></a>\n\n### Netstat\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| connectrecord | [ConnectRecord](#machine.ConnectRecord) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetstatRequest\"></a>\n\n### NetstatRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| filter | [NetstatRequest.Filter](#machine.NetstatRequest.Filter) |  |  |\n| feature | [NetstatRequest.Feature](#machine.NetstatRequest.Feature) |  |  |\n| l4proto | [NetstatRequest.L4proto](#machine.NetstatRequest.L4proto) |  |  |\n| netns | [NetstatRequest.NetNS](#machine.NetstatRequest.NetNS) |  |  |\n\n\n\n\n\n\n<a name=\"machine.NetstatRequest.Feature\"></a>\n\n### NetstatRequest.Feature\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pid | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.NetstatRequest.L4proto\"></a>\n\n### NetstatRequest.L4proto\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| tcp | [bool](#bool) |  |  |\n| tcp6 | [bool](#bool) |  |  |\n| udp | [bool](#bool) |  |  |\n| udp6 | [bool](#bool) |  |  |\n| udplite | [bool](#bool) |  |  |\n| udplite6 | [bool](#bool) |  |  |\n| raw | [bool](#bool) |  |  |\n| raw6 | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.NetstatRequest.NetNS\"></a>\n\n### NetstatRequest.NetNS\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostnetwork | [bool](#bool) |  |  |\n| netns | [string](#string) | repeated |  |\n| allnetns | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.NetstatResponse\"></a>\n\n### NetstatResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Netstat](#machine.Netstat) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetworkConfig\"></a>\n\n### NetworkConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostname | [string](#string) |  |  |\n| interfaces | [NetworkDeviceConfig](#machine.NetworkDeviceConfig) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetworkDeviceConfig\"></a>\n\n### NetworkDeviceConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| interface | [string](#string) |  |  |\n| cidr | [string](#string) |  |  |\n| mtu | [int32](#int32) |  |  |\n| dhcp | [bool](#bool) |  |  |\n| ignore | [bool](#bool) |  |  |\n| dhcp_options | [DHCPOptionsConfig](#machine.DHCPOptionsConfig) |  |  |\n| routes | [RouteConfig](#machine.RouteConfig) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetworkDeviceStats\"></a>\n\n### NetworkDeviceStats\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| total | [NetDev](#machine.NetDev) |  |  |\n| devices | [NetDev](#machine.NetDev) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.NetworkDeviceStatsResponse\"></a>\n\n### NetworkDeviceStatsResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [NetworkDeviceStats](#machine.NetworkDeviceStats) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.PacketCaptureRequest\"></a>\n\n### PacketCaptureRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| interface | [string](#string) |  | Interface name to perform packet capture on. |\n| promiscuous | [bool](#bool) |  | Enable promiscuous mode. |\n| snap_len | [uint32](#uint32) |  | Snap length in bytes. |\n| bpf_filter | [BPFInstruction](#machine.BPFInstruction) | repeated | BPF filter. |\n\n\n\n\n\n\n<a name=\"machine.PhaseEvent\"></a>\n\n### PhaseEvent\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| phase | [string](#string) |  |  |\n| action | [PhaseEvent.Action](#machine.PhaseEvent.Action) |  |  |\n\n\n\n\n\n\n<a name=\"machine.PlatformInfo\"></a>\n\n### PlatformInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| mode | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Process\"></a>\n\n### Process\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| processes | [ProcessInfo](#machine.ProcessInfo) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ProcessInfo\"></a>\n\n### ProcessInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pid | [int32](#int32) |  |  |\n| ppid | [int32](#int32) |  |  |\n| state | [string](#string) |  |  |\n| threads | [int32](#int32) |  |  |\n| cpu_time | [double](#double) |  |  |\n| virtual_memory | [uint64](#uint64) |  |  |\n| resident_memory | [uint64](#uint64) |  |  |\n| command | [string](#string) |  |  |\n| executable | [string](#string) |  |  |\n| args | [string](#string) |  |  |\n| label | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ProcessesResponse\"></a>\n\n### ProcessesResponse\nrpc processes\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Process](#machine.Process) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ReadRequest\"></a>\n\n### ReadRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| path | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Reboot\"></a>\n\n### Reboot\nThe reboot message containing the reboot status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.RebootRequest\"></a>\n\n### RebootRequest\nrpc reboot\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mode | [RebootRequest.Mode](#machine.RebootRequest.Mode) |  |  |\n\n\n\n\n\n\n<a name=\"machine.RebootResponse\"></a>\n\n### RebootResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Reboot](#machine.Reboot) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Reset\"></a>\n\n### Reset\nThe reset message containing the restart status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ResetPartitionSpec\"></a>\n\n### ResetPartitionSpec\nrpc reset\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| label | [string](#string) |  |  |\n| wipe | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ResetRequest\"></a>\n\n### ResetRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| graceful | [bool](#bool) |  | Graceful indicates whether node should leave etcd before the upgrade, it also enforces etcd checks before leaving. |\n| reboot | [bool](#bool) |  | Reboot indicates whether node should reboot or halt after resetting. |\n| system_partitions_to_wipe | [ResetPartitionSpec](#machine.ResetPartitionSpec) | repeated | System_partitions_to_wipe lists specific system disk partitions to be reset (wiped). If system_partitions_to_wipe is empty, all the partitions are erased. |\n| user_disks_to_wipe | [string](#string) | repeated | UserDisksToWipe lists specific connected block devices to be reset (wiped). |\n| mode | [ResetRequest.WipeMode](#machine.ResetRequest.WipeMode) |  | WipeMode defines which devices should be wiped. |\n\n\n\n\n\n\n<a name=\"machine.ResetResponse\"></a>\n\n### ResetResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Reset](#machine.Reset) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Restart\"></a>\n\n### Restart\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.RestartEvent\"></a>\n\n### RestartEvent\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| cmd | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.RestartRequest\"></a>\n\n### RestartRequest\nrpc restart\nThe request message containing the process to restart.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| id | [string](#string) |  |  |\n| driver | [common.ContainerDriver](#common.ContainerDriver) |  | driver might be default \"containerd\" or \"cri\" |\n\n\n\n\n\n\n<a name=\"machine.RestartResponse\"></a>\n\n### RestartResponse\nThe messages message containing the restart status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Restart](#machine.Restart) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Rollback\"></a>\n\n### Rollback\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"machine.RollbackRequest\"></a>\n\n### RollbackRequest\nrpc rollback\n\n\n\n\n\n\n<a name=\"machine.RollbackResponse\"></a>\n\n### RollbackResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Rollback](#machine.Rollback) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.RouteConfig\"></a>\n\n### RouteConfig\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| network | [string](#string) |  |  |\n| gateway | [string](#string) |  |  |\n| metric | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"machine.SequenceEvent\"></a>\n\n### SequenceEvent\nrpc events\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| sequence | [string](#string) |  |  |\n| action | [SequenceEvent.Action](#machine.SequenceEvent.Action) |  |  |\n| error | [common.Error](#common.Error) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceEvent\"></a>\n\n### ServiceEvent\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| msg | [string](#string) |  |  |\n| state | [string](#string) |  |  |\n| ts | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceEvents\"></a>\n\n### ServiceEvents\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| events | [ServiceEvent](#machine.ServiceEvent) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceHealth\"></a>\n\n### ServiceHealth\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| unknown | [bool](#bool) |  |  |\n| healthy | [bool](#bool) |  |  |\n| last_message | [string](#string) |  |  |\n| last_change | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceInfo\"></a>\n\n### ServiceInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| id | [string](#string) |  |  |\n| state | [string](#string) |  |  |\n| events | [ServiceEvents](#machine.ServiceEvents) |  |  |\n| health | [ServiceHealth](#machine.ServiceHealth) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceList\"></a>\n\n### ServiceList\nrpc servicelist\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| services | [ServiceInfo](#machine.ServiceInfo) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceListResponse\"></a>\n\n### ServiceListResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ServiceList](#machine.ServiceList) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceRestart\"></a>\n\n### ServiceRestart\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| resp | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceRestartRequest\"></a>\n\n### ServiceRestartRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceRestartResponse\"></a>\n\n### ServiceRestartResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ServiceRestart](#machine.ServiceRestart) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStart\"></a>\n\n### ServiceStart\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| resp | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStartRequest\"></a>\n\n### ServiceStartRequest\nrpc servicestart\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStartResponse\"></a>\n\n### ServiceStartResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ServiceStart](#machine.ServiceStart) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStateEvent\"></a>\n\n### ServiceStateEvent\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| service | [string](#string) |  |  |\n| action | [ServiceStateEvent.Action](#machine.ServiceStateEvent.Action) |  |  |\n| message | [string](#string) |  |  |\n| health | [ServiceHealth](#machine.ServiceHealth) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStop\"></a>\n\n### ServiceStop\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| resp | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStopRequest\"></a>\n\n### ServiceStopRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ServiceStopResponse\"></a>\n\n### ServiceStopResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [ServiceStop](#machine.ServiceStop) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Shutdown\"></a>\n\n### Shutdown\nrpc shutdown\nThe messages message containing the shutdown status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.ShutdownRequest\"></a>\n\n### ShutdownRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| force | [bool](#bool) |  | Force indicates whether node should shutdown without first cordening and draining |\n\n\n\n\n\n\n<a name=\"machine.ShutdownResponse\"></a>\n\n### ShutdownResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Shutdown](#machine.Shutdown) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.SoftIRQStat\"></a>\n\n### SoftIRQStat\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hi | [uint64](#uint64) |  |  |\n| timer | [uint64](#uint64) |  |  |\n| net_tx | [uint64](#uint64) |  |  |\n| net_rx | [uint64](#uint64) |  |  |\n| block | [uint64](#uint64) |  |  |\n| block_io_poll | [uint64](#uint64) |  |  |\n| tasklet | [uint64](#uint64) |  |  |\n| sched | [uint64](#uint64) |  |  |\n| hrtimer | [uint64](#uint64) |  |  |\n| rcu | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Stat\"></a>\n\n### Stat\nThe messages message containing the requested stat.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| id | [string](#string) |  |  |\n| memory_usage | [uint64](#uint64) |  |  |\n| cpu_usage | [uint64](#uint64) |  |  |\n| pod_id | [string](#string) |  |  |\n| name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Stats\"></a>\n\n### Stats\nThe messages message containing the requested stats.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| stats | [Stat](#machine.Stat) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.StatsRequest\"></a>\n\n### StatsRequest\nThe request message containing the containerd namespace.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| namespace | [string](#string) |  |  |\n| driver | [common.ContainerDriver](#common.ContainerDriver) |  | driver might be default \"containerd\" or \"cri\" |\n\n\n\n\n\n\n<a name=\"machine.StatsResponse\"></a>\n\n### StatsResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Stats](#machine.Stats) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.SystemStat\"></a>\n\n### SystemStat\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| boot_time | [uint64](#uint64) |  |  |\n| cpu_total | [CPUStat](#machine.CPUStat) |  |  |\n| cpu | [CPUStat](#machine.CPUStat) | repeated |  |\n| irq_total | [uint64](#uint64) |  |  |\n| irq | [uint64](#uint64) | repeated |  |\n| context_switches | [uint64](#uint64) |  |  |\n| process_created | [uint64](#uint64) |  |  |\n| process_running | [uint64](#uint64) |  |  |\n| process_blocked | [uint64](#uint64) |  |  |\n| soft_irq_total | [uint64](#uint64) |  |  |\n| soft_irq | [SoftIRQStat](#machine.SoftIRQStat) |  |  |\n\n\n\n\n\n\n<a name=\"machine.SystemStatResponse\"></a>\n\n### SystemStatResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [SystemStat](#machine.SystemStat) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.TaskEvent\"></a>\n\n### TaskEvent\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| task | [string](#string) |  |  |\n| action | [TaskEvent.Action](#machine.TaskEvent.Action) |  |  |\n\n\n\n\n\n\n<a name=\"machine.Upgrade\"></a>\n\n### Upgrade\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| ack | [string](#string) |  |  |\n| actor_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.UpgradeRequest\"></a>\n\n### UpgradeRequest\nrpc upgrade\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| preserve | [bool](#bool) |  |  |\n| stage | [bool](#bool) |  |  |\n| force | [bool](#bool) |  |  |\n| reboot_mode | [UpgradeRequest.RebootMode](#machine.UpgradeRequest.RebootMode) |  |  |\n\n\n\n\n\n\n<a name=\"machine.UpgradeResponse\"></a>\n\n### UpgradeResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Upgrade](#machine.Upgrade) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Version\"></a>\n\n### Version\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| version | [VersionInfo](#machine.VersionInfo) |  |  |\n| platform | [PlatformInfo](#machine.PlatformInfo) |  |  |\n| features | [FeaturesInfo](#machine.FeaturesInfo) |  | Features describe individual Talos features that can be switched on or off. |\n\n\n\n\n\n\n<a name=\"machine.VersionInfo\"></a>\n\n### VersionInfo\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| tag | [string](#string) |  |  |\n| sha | [string](#string) |  |  |\n| built | [string](#string) |  |  |\n| go_version | [string](#string) |  |  |\n| os | [string](#string) |  |  |\n| arch | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"machine.VersionResponse\"></a>\n\n### VersionResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Version](#machine.Version) | repeated |  |\n\n\n\n\n\n\n<a name=\"machine.Xattr\"></a>\n\n### Xattr\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| data | [bytes](#bytes) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"machine.ApplyConfigurationRequest.Mode\"></a>\n\n### ApplyConfigurationRequest.Mode\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| REBOOT | 0 |  |\n| AUTO | 1 |  |\n| NO_REBOOT | 2 |  |\n| STAGED | 3 |  |\n| TRY | 4 |  |\n\n\n\n<a name=\"machine.ConnectRecord.State\"></a>\n\n### ConnectRecord.State\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| RESERVED | 0 |  |\n| ESTABLISHED | 1 |  |\n| SYN_SENT | 2 |  |\n| SYN_RECV | 3 |  |\n| FIN_WAIT1 | 4 |  |\n| FIN_WAIT2 | 5 |  |\n| TIME_WAIT | 6 |  |\n| CLOSE | 7 |  |\n| CLOSEWAIT | 8 |  |\n| LASTACK | 9 |  |\n| LISTEN | 10 |  |\n| CLOSING | 11 |  |\n\n\n\n<a name=\"machine.ConnectRecord.TimerActive\"></a>\n\n### ConnectRecord.TimerActive\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| OFF | 0 |  |\n| ON | 1 |  |\n| KEEPALIVE | 2 |  |\n| TIMEWAIT | 3 |  |\n| PROBE | 4 |  |\n\n\n\n<a name=\"machine.EtcdMemberAlarm.AlarmType\"></a>\n\n### EtcdMemberAlarm.AlarmType\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NONE | 0 |  |\n| NOSPACE | 1 |  |\n| CORRUPT | 2 |  |\n\n\n\n<a name=\"machine.ListRequest.Type\"></a>\n\n### ListRequest.Type\nFile type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| REGULAR | 0 | Regular file (not directory, symlink, etc). |\n| DIRECTORY | 1 | Directory. |\n| SYMLINK | 2 | Symbolic link. |\n\n\n\n<a name=\"machine.MachineConfig.MachineType\"></a>\n\n### MachineConfig.MachineType\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| TYPE_UNKNOWN | 0 |  |\n| TYPE_INIT | 1 |  |\n| TYPE_CONTROL_PLANE | 2 |  |\n| TYPE_WORKER | 3 |  |\n\n\n\n<a name=\"machine.MachineStatusEvent.MachineStage\"></a>\n\n### MachineStatusEvent.MachineStage\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| UNKNOWN | 0 |  |\n| BOOTING | 1 |  |\n| INSTALLING | 2 |  |\n| MAINTENANCE | 3 |  |\n| RUNNING | 4 |  |\n| REBOOTING | 5 |  |\n| SHUTTING_DOWN | 6 |  |\n| RESETTING | 7 |  |\n| UPGRADING | 8 |  |\n\n\n\n<a name=\"machine.NetstatRequest.Filter\"></a>\n\n### NetstatRequest.Filter\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ALL | 0 |  |\n| CONNECTED | 1 |  |\n| LISTENING | 2 |  |\n\n\n\n<a name=\"machine.PhaseEvent.Action\"></a>\n\n### PhaseEvent.Action\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| START | 0 |  |\n| STOP | 1 |  |\n\n\n\n<a name=\"machine.RebootRequest.Mode\"></a>\n\n### RebootRequest.Mode\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| DEFAULT | 0 |  |\n| POWERCYCLE | 1 |  |\n| FORCE | 2 |  |\n\n\n\n<a name=\"machine.ResetRequest.WipeMode\"></a>\n\n### ResetRequest.WipeMode\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ALL | 0 |  |\n| SYSTEM_DISK | 1 |  |\n| USER_DISKS | 2 |  |\n\n\n\n<a name=\"machine.SequenceEvent.Action\"></a>\n\n### SequenceEvent.Action\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NOOP | 0 |  |\n| START | 1 |  |\n| STOP | 2 |  |\n\n\n\n<a name=\"machine.ServiceStateEvent.Action\"></a>\n\n### ServiceStateEvent.Action\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| INITIALIZED | 0 |  |\n| PREPARING | 1 |  |\n| WAITING | 2 |  |\n| RUNNING | 3 |  |\n| STOPPING | 4 |  |\n| FINISHED | 5 |  |\n| FAILED | 6 |  |\n| SKIPPED | 7 |  |\n| STARTING | 8 |  |\n\n\n\n<a name=\"machine.TaskEvent.Action\"></a>\n\n### TaskEvent.Action\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| START | 0 |  |\n| STOP | 1 |  |\n\n\n\n<a name=\"machine.UpgradeRequest.RebootMode\"></a>\n\n### UpgradeRequest.RebootMode\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| DEFAULT | 0 |  |\n| POWERCYCLE | 1 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"machine.MachineService\"></a>\n\n### MachineService\nThe machine service definition.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| ApplyConfiguration | [ApplyConfigurationRequest](#machine.ApplyConfigurationRequest) | [ApplyConfigurationResponse](#machine.ApplyConfigurationResponse) |  |\n| Bootstrap | [BootstrapRequest](#machine.BootstrapRequest) | [BootstrapResponse](#machine.BootstrapResponse) | Bootstrap method makes control plane node enter etcd bootstrap mode. Node aborts etcd join sequence and creates single-node etcd cluster. If recover_etcd argument is specified, etcd is recovered from a snapshot uploaded with EtcdRecover. |\n| Containers | [ContainersRequest](#machine.ContainersRequest) | [ContainersResponse](#machine.ContainersResponse) |  |\n| Copy | [CopyRequest](#machine.CopyRequest) | [.common.Data](#common.Data) stream |  |\n| CPUFreqStats | [.google.protobuf.Empty](#google.protobuf.Empty) | [CPUFreqStatsResponse](#machine.CPUFreqStatsResponse) |  |\n| CPUInfo | [.google.protobuf.Empty](#google.protobuf.Empty) | [CPUInfoResponse](#machine.CPUInfoResponse) |  |\n| DiskStats | [.google.protobuf.Empty](#google.protobuf.Empty) | [DiskStatsResponse](#machine.DiskStatsResponse) |  |\n| Dmesg | [DmesgRequest](#machine.DmesgRequest) | [.common.Data](#common.Data) stream |  |\n| Events | [EventsRequest](#machine.EventsRequest) | [Event](#machine.Event) stream |  |\n| EtcdMemberList | [EtcdMemberListRequest](#machine.EtcdMemberListRequest) | [EtcdMemberListResponse](#machine.EtcdMemberListResponse) |  |\n| EtcdRemoveMemberByID | [EtcdRemoveMemberByIDRequest](#machine.EtcdRemoveMemberByIDRequest) | [EtcdRemoveMemberByIDResponse](#machine.EtcdRemoveMemberByIDResponse) | EtcdRemoveMemberByID removes a member from the etcd cluster identified by member ID. This API should be used to remove members which don't have an associated Talos node anymore. To remove a member with a running Talos node, use EtcdLeaveCluster API on the node to be removed. |\n| EtcdLeaveCluster | [EtcdLeaveClusterRequest](#machine.EtcdLeaveClusterRequest) | [EtcdLeaveClusterResponse](#machine.EtcdLeaveClusterResponse) |  |\n| EtcdForfeitLeadership | [EtcdForfeitLeadershipRequest](#machine.EtcdForfeitLeadershipRequest) | [EtcdForfeitLeadershipResponse](#machine.EtcdForfeitLeadershipResponse) |  |\n| EtcdRecover | [.common.Data](#common.Data) stream | [EtcdRecoverResponse](#machine.EtcdRecoverResponse) | EtcdRecover method uploads etcd data snapshot created with EtcdSnapshot to the node. Snapshot can be later used to recover the cluster via Bootstrap method. |\n| EtcdSnapshot | [EtcdSnapshotRequest](#machine.EtcdSnapshotRequest) | [.common.Data](#common.Data) stream | EtcdSnapshot method creates etcd data snapshot (backup) from the local etcd instance and streams it back to the client. This method is available only on control plane nodes (which run etcd). |\n| EtcdAlarmList | [.google.protobuf.Empty](#google.protobuf.Empty) | [EtcdAlarmListResponse](#machine.EtcdAlarmListResponse) | EtcdAlarmList lists etcd alarms for the current node. This method is available only on control plane nodes (which run etcd). |\n| EtcdAlarmDisarm | [.google.protobuf.Empty](#google.protobuf.Empty) | [EtcdAlarmDisarmResponse](#machine.EtcdAlarmDisarmResponse) | EtcdAlarmDisarm disarms etcd alarms for the current node. This method is available only on control plane nodes (which run etcd). |\n| EtcdDefragment | [.google.protobuf.Empty](#google.protobuf.Empty) | [EtcdDefragmentResponse](#machine.EtcdDefragmentResponse) | EtcdDefragment defragments etcd data directory for the current node. Defragmentation is a resource-heavy operation, so it should only run on a specific node. This method is available only on control plane nodes (which run etcd). |\n| EtcdStatus | [.google.protobuf.Empty](#google.protobuf.Empty) | [EtcdStatusResponse](#machine.EtcdStatusResponse) | EtcdStatus returns etcd status for the current member. This method is available only on control plane nodes (which run etcd). |\n| EtcdDowngradeValidate | [EtcdDowngradeValidateRequest](#machine.EtcdDowngradeValidateRequest) | [EtcdDowngradeValidateResponse](#machine.EtcdDowngradeValidateResponse) | EtcdDowngradeValidate validates etcd cluster for downgrade to a specific version. This method is available only on control plane nodes (which run etcd). |\n| EtcdDowngradeEnable | [EtcdDowngradeEnableRequest](#machine.EtcdDowngradeEnableRequest) | [EtcdDowngradeEnableResponse](#machine.EtcdDowngradeEnableResponse) | EtcdDowngradeEnable enables etcd cluster downgrade to a specific version. This method is available only on control plane nodes (which run etcd). |\n| EtcdDowngradeCancel | [.google.protobuf.Empty](#google.protobuf.Empty) | [EtcdDowngradeCancelResponse](#machine.EtcdDowngradeCancelResponse) | EtcdDowngradeCancel cancels etcd cluster downgrade that is in progress. This method is available only on control plane nodes (which run etcd). |\n| Hostname | [.google.protobuf.Empty](#google.protobuf.Empty) | [HostnameResponse](#machine.HostnameResponse) |  |\n| Kubeconfig | [.google.protobuf.Empty](#google.protobuf.Empty) | [.common.Data](#common.Data) stream |  |\n| List | [ListRequest](#machine.ListRequest) | [FileInfo](#machine.FileInfo) stream |  |\n| DiskUsage | [DiskUsageRequest](#machine.DiskUsageRequest) | [DiskUsageInfo](#machine.DiskUsageInfo) stream |  |\n| LoadAvg | [.google.protobuf.Empty](#google.protobuf.Empty) | [LoadAvgResponse](#machine.LoadAvgResponse) |  |\n| Logs | [LogsRequest](#machine.LogsRequest) | [.common.Data](#common.Data) stream |  |\n| LogsContainers | [.google.protobuf.Empty](#google.protobuf.Empty) | [LogsContainersResponse](#machine.LogsContainersResponse) |  |\n| Memory | [.google.protobuf.Empty](#google.protobuf.Empty) | [MemoryResponse](#machine.MemoryResponse) |  |\n| Mounts | [.google.protobuf.Empty](#google.protobuf.Empty) | [MountsResponse](#machine.MountsResponse) |  |\n| NetworkDeviceStats | [.google.protobuf.Empty](#google.protobuf.Empty) | [NetworkDeviceStatsResponse](#machine.NetworkDeviceStatsResponse) |  |\n| Processes | [.google.protobuf.Empty](#google.protobuf.Empty) | [ProcessesResponse](#machine.ProcessesResponse) |  |\n| Read | [ReadRequest](#machine.ReadRequest) | [.common.Data](#common.Data) stream |  |\n| Reboot | [RebootRequest](#machine.RebootRequest) | [RebootResponse](#machine.RebootResponse) |  |\n| Restart | [RestartRequest](#machine.RestartRequest) | [RestartResponse](#machine.RestartResponse) |  |\n| Rollback | [RollbackRequest](#machine.RollbackRequest) | [RollbackResponse](#machine.RollbackResponse) |  |\n| Reset | [ResetRequest](#machine.ResetRequest) | [ResetResponse](#machine.ResetResponse) |  |\n| ServiceList | [.google.protobuf.Empty](#google.protobuf.Empty) | [ServiceListResponse](#machine.ServiceListResponse) |  |\n| ServiceRestart | [ServiceRestartRequest](#machine.ServiceRestartRequest) | [ServiceRestartResponse](#machine.ServiceRestartResponse) |  |\n| ServiceStart | [ServiceStartRequest](#machine.ServiceStartRequest) | [ServiceStartResponse](#machine.ServiceStartResponse) |  |\n| ServiceStop | [ServiceStopRequest](#machine.ServiceStopRequest) | [ServiceStopResponse](#machine.ServiceStopResponse) |  |\n| Shutdown | [ShutdownRequest](#machine.ShutdownRequest) | [ShutdownResponse](#machine.ShutdownResponse) |  |\n| Stats | [StatsRequest](#machine.StatsRequest) | [StatsResponse](#machine.StatsResponse) |  |\n| SystemStat | [.google.protobuf.Empty](#google.protobuf.Empty) | [SystemStatResponse](#machine.SystemStatResponse) |  |\n| Upgrade | [UpgradeRequest](#machine.UpgradeRequest) | [UpgradeResponse](#machine.UpgradeResponse) | Upgrade initiates the upgrade of the node to a new version of Talos.<br><br>Use LifecycleService Upgrade RPC instead. |\n| Version | [.google.protobuf.Empty](#google.protobuf.Empty) | [VersionResponse](#machine.VersionResponse) |  |\n| GenerateClientConfiguration | [GenerateClientConfigurationRequest](#machine.GenerateClientConfigurationRequest) | [GenerateClientConfigurationResponse](#machine.GenerateClientConfigurationResponse) | GenerateClientConfiguration generates talosctl client configuration (talosconfig). |\n| PacketCapture | [PacketCaptureRequest](#machine.PacketCaptureRequest) | [.common.Data](#common.Data) stream | PacketCapture performs packet capture and streams back pcap file. |\n| Netstat | [NetstatRequest](#machine.NetstatRequest) | [NetstatResponse](#machine.NetstatResponse) | Netstat provides information about network connections. |\n| MetaWrite | [MetaWriteRequest](#machine.MetaWriteRequest) | [MetaWriteResponse](#machine.MetaWriteResponse) | MetaWrite writes a META key-value pair. |\n| MetaDelete | [MetaDeleteRequest](#machine.MetaDeleteRequest) | [MetaDeleteResponse](#machine.MetaDeleteResponse) | MetaDelete deletes a META key. |\n| ImageList | [ImageListRequest](#machine.ImageListRequest) | [ImageListResponse](#machine.ImageListResponse) stream | ImageList lists images in the CRI.<br><br>Use ImageService List RPC instead. |\n| ImagePull | [ImagePullRequest](#machine.ImagePullRequest) | [ImagePullResponse](#machine.ImagePullResponse) | ImagePull pulls an image into the CRI.<br><br>Use ImageService Pull RPC instead. |\n\n <!-- end services -->\n\n\n\n<a name=\"resource/config/config.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/config/config.proto\n\n\n\n<a name=\"resource.config.MachineConfigSpec\"></a>\n\n### MachineConfigSpec\nMessageConfigSpec is the spec for the config.MachineConfig resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| yaml_marshalled | [bytes](#bytes) |  | Contains YAML marshalled machine configuration.<br><br>Byte representation is preserved as the machine configuration was submitted to the node. |\n\n\n\n\n\n\n<a name=\"resource.config.MachineTypeSpec\"></a>\n\n### MachineTypeSpec\nMachineTypeSpec is the spec for the config.MachineType resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| machine_type | [MachineType](#resource.config.MachineType) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"resource.config.MachineType\"></a>\n\n### MachineType\nMachineType matches machine.Type constants.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| UNKNOWN | 0 |  |\n| INIT | 1 |  |\n| CONTROL_PLANE | 2 |  |\n| WORKER | 3 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/enums/enums.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/enums/enums.proto\n\n\n <!-- end messages -->\n\n\n<a name=\"talos.resource.definitions.enums.BlockEncryptionKeyType\"></a>\n\n### BlockEncryptionKeyType\nBlockEncryptionKeyType describes encryption key type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ENCRYPTION_KEY_STATIC | 0 |  |\n| ENCRYPTION_KEY_NODE_ID | 1 |  |\n| ENCRYPTION_KEY_KMS | 2 |  |\n| ENCRYPTION_KEY_TPM | 3 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.BlockEncryptionProviderType\"></a>\n\n### BlockEncryptionProviderType\nBlockEncryptionProviderType describes encryption provider type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ENCRYPTION_PROVIDER_NONE | 0 |  |\n| ENCRYPTION_PROVIDER_LUKS2 | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.BlockFSParameterType\"></a>\n\n### BlockFSParameterType\nBlockFSParameterType describes Filesystem Parameter type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FS_PARAMETER_TYPE_STRING_VALUE | 0 |  |\n| FS_PARAMETER_TYPE_BOOLEAN_VALUE | 1 |  |\n| FS_PARAMETER_TYPE_BINARY_VALUE | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.BlockFilesystemType\"></a>\n\n### BlockFilesystemType\nBlockFilesystemType describes filesystem type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FILESYSTEM_TYPE_NONE | 0 |  |\n| FILESYSTEM_TYPE_XFS | 1 |  |\n| FILESYSTEM_TYPE_VFAT | 2 |  |\n| FILESYSTEM_TYPE_EXT4 | 3 |  |\n| FILESYSTEM_TYPE_ISO9660 | 4 |  |\n| FILESYSTEM_TYPE_SWAP | 5 |  |\n| FILESYSTEM_TYPE_VIRTIOFS | 6 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.BlockVolumePhase\"></a>\n\n### BlockVolumePhase\nBlockVolumePhase describes volume phase.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| VOLUME_PHASE_WAITING | 0 |  |\n| VOLUME_PHASE_FAILED | 1 |  |\n| VOLUME_PHASE_MISSING | 2 |  |\n| VOLUME_PHASE_LOCATED | 3 |  |\n| VOLUME_PHASE_PROVISIONED | 4 |  |\n| VOLUME_PHASE_PREPARED | 5 |  |\n| VOLUME_PHASE_READY | 6 |  |\n| VOLUME_PHASE_CLOSED | 7 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.BlockVolumeType\"></a>\n\n### BlockVolumeType\nBlockVolumeType describes volume type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| VOLUME_TYPE_PARTITION | 0 |  |\n| VOLUME_TYPE_DISK | 1 |  |\n| VOLUME_TYPE_TMPFS | 2 |  |\n| VOLUME_TYPE_DIRECTORY | 3 |  |\n| VOLUME_TYPE_SYMLINK | 4 |  |\n| VOLUME_TYPE_OVERLAY | 5 |  |\n| VOLUME_TYPE_EXTERNAL | 6 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.CriImageCacheCopyStatus\"></a>\n\n### CriImageCacheCopyStatus\nCriImageCacheCopyStatus describes image cache copy status type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| IMAGE_CACHE_COPY_STATUS_UNKNOWN | 0 |  |\n| IMAGE_CACHE_COPY_STATUS_SKIPPED | 1 |  |\n| IMAGE_CACHE_COPY_STATUS_PENDING | 2 |  |\n| IMAGE_CACHE_COPY_STATUS_READY | 3 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.CriImageCacheStatus\"></a>\n\n### CriImageCacheStatus\nCriImageCacheStatus describes image cache status type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| IMAGE_CACHE_STATUS_UNKNOWN | 0 |  |\n| IMAGE_CACHE_STATUS_DISABLED | 1 |  |\n| IMAGE_CACHE_STATUS_PREPARING | 2 |  |\n| IMAGE_CACHE_STATUS_READY | 3 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.KubespanPeerState\"></a>\n\n### KubespanPeerState\nKubespanPeerState is KubeSpan peer current state.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| PEER_STATE_UNKNOWN | 0 |  |\n| PEER_STATE_UP | 1 |  |\n| PEER_STATE_DOWN | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.MachineType\"></a>\n\n### MachineType\nMachineType represents a machine type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| TYPE_UNKNOWN | 0 | TypeUnknown represents undefined node type, when there is no machine configuration yet. |\n| TYPE_INIT | 1 | TypeInit type designates the first control plane node to come up. You can think of it like a bootstrap node. This node will perform the initial steps to bootstrap the cluster -- generation of TLS assets, starting of the control plane, etc. |\n| TYPE_CONTROL_PLANE | 2 | TypeControlPlane designates the node as a control plane member. This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler. |\n| TYPE_WORKER | 3 | TypeWorker designates the node as a worker node. This means it will be an available compute node for scheduling workloads. |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersADLACPActive\"></a>\n\n### NethelpersADLACPActive\nNethelpersADLACPActive is ADLACPActive.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ADLACP_ACTIVE_OFF | 0 |  |\n| ADLACP_ACTIVE_ON | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersADSelect\"></a>\n\n### NethelpersADSelect\nNethelpersADSelect is ADSelect.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| AD_SELECT_STABLE | 0 |  |\n| AD_SELECT_BANDWIDTH | 1 |  |\n| AD_SELECT_COUNT | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersARPAllTargets\"></a>\n\n### NethelpersARPAllTargets\nNethelpersARPAllTargets is an ARP targets mode.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ARP_ALL_TARGETS_ANY | 0 |  |\n| ARP_ALL_TARGETS_ALL | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersARPValidate\"></a>\n\n### NethelpersARPValidate\nNethelpersARPValidate is an ARP Validation mode.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ARP_VALIDATE_NONE | 0 |  |\n| ARP_VALIDATE_ACTIVE | 1 |  |\n| ARP_VALIDATE_BACKUP | 2 |  |\n| ARP_VALIDATE_ALL | 3 |  |\n| ARP_VALIDATE_FILTER | 4 |  |\n| ARP_VALIDATE_FILTER_ACTIVE | 5 |  |\n| ARP_VALIDATE_FILTER_BACKUP | 6 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersAddressFlag\"></a>\n\n### NethelpersAddressFlag\nNethelpersAddressFlag wraps IFF_* constants.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_ADDRESSFLAG_UNSPECIFIED | 0 |  |\n| ADDRESS_TEMPORARY | 1 |  |\n| ADDRESS_NO_DAD | 2 |  |\n| ADDRESS_OPTIMISTIC | 4 |  |\n| ADDRESS_DAD_FAILED | 8 |  |\n| ADDRESS_HOME | 16 |  |\n| ADDRESS_DEPRECATED | 32 |  |\n| ADDRESS_TENTATIVE | 64 |  |\n| ADDRESS_PERMANENT | 128 |  |\n| ADDRESS_MANAGEMENT_TEMP | 256 |  |\n| ADDRESS_NO_PREFIX_ROUTE | 512 |  |\n| ADDRESS_MC_AUTO_JOIN | 1024 |  |\n| ADDRESS_STABLE_PRIVACY | 2048 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersAddressSortAlgorithm\"></a>\n\n### NethelpersAddressSortAlgorithm\nNethelpersAddressSortAlgorithm is an internal address sorting algorithm.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ADDRESS_SORT_ALGORITHM_V1 | 0 |  |\n| ADDRESS_SORT_ALGORITHM_V2 | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersAutoHostnameKind\"></a>\n\n### NethelpersAutoHostnameKind\nNethelpersAutoHostnameKind is a kind of automatically generated hostname.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| AUTO_HOSTNAME_KIND_OFF | 0 |  |\n| AUTO_HOSTNAME_KIND_ADDR | 1 |  |\n| AUTO_HOSTNAME_KIND_STABLE | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersBondMode\"></a>\n\n### NethelpersBondMode\nNethelpersBondMode is a bond mode.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| BOND_MODE_ROUNDROBIN | 0 |  |\n| BOND_MODE_ACTIVE_BACKUP | 1 |  |\n| BOND_MODE_XOR | 2 |  |\n| BOND_MODE_BROADCAST | 3 |  |\n| BOND_MODE8023_AD | 4 |  |\n| BOND_MODE_TLB | 5 |  |\n| BOND_MODE_ALB | 6 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersBondXmitHashPolicy\"></a>\n\n### NethelpersBondXmitHashPolicy\nNethelpersBondXmitHashPolicy is a bond hash policy.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| BOND_XMIT_POLICY_LAYER2 | 0 |  |\n| BOND_XMIT_POLICY_LAYER34 | 1 |  |\n| BOND_XMIT_POLICY_LAYER23 | 2 |  |\n| BOND_XMIT_POLICY_ENCAP23 | 3 |  |\n| BOND_XMIT_POLICY_ENCAP34 | 4 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersClientIdentifier\"></a>\n\n### NethelpersClientIdentifier\nNethelpersClientIdentifier is a DHCP client identifier.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| CLIENT_IDENTIFIER_NONE | 0 |  |\n| CLIENT_IDENTIFIER_MAC | 1 |  |\n| CLIENT_IDENTIFIER_DUID | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersConntrackState\"></a>\n\n### NethelpersConntrackState\nNethelpersConntrackState is a conntrack state.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_CONNTRACKSTATE_UNSPECIFIED | 0 |  |\n| CONNTRACK_STATE_NEW | 8 |  |\n| CONNTRACK_STATE_RELATED | 4 |  |\n| CONNTRACK_STATE_ESTABLISHED | 2 |  |\n| CONNTRACK_STATE_INVALID | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersDuplex\"></a>\n\n### NethelpersDuplex\nNethelpersDuplex wraps ethtool.Duplex for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| HALF | 0 |  |\n| FULL | 1 |  |\n| UNKNOWN | 255 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersFailOverMAC\"></a>\n\n### NethelpersFailOverMAC\nNethelpersFailOverMAC is a MAC failover mode.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FAIL_OVER_MAC_NONE | 0 |  |\n| FAIL_OVER_MAC_ACTIVE | 1 |  |\n| FAIL_OVER_MAC_FOLLOW | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersFamily\"></a>\n\n### NethelpersFamily\nNethelpersFamily is a network family.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_FAMILY_UNSPECIFIED | 0 |  |\n| FAMILY_INET4 | 2 |  |\n| FAMILY_INET6 | 10 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersICMPType\"></a>\n\n### NethelpersICMPType\nNethelpersICMPType is a ICMP packet type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_ICMPTYPE_UNSPECIFIED | 0 |  |\n| ICMP_TYPE_TIMESTAMP_REQUEST | 13 |  |\n| ICMP_TYPE_TIMESTAMP_REPLY | 14 |  |\n| ICMP_TYPE_ADDRESS_MASK_REQUEST | 17 |  |\n| ICMP_TYPE_ADDRESS_MASK_REPLY | 18 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersLACPRate\"></a>\n\n### NethelpersLACPRate\nNethelpersLACPRate is a LACP rate.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| LACP_RATE_SLOW | 0 |  |\n| LACP_RATE_FAST | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersLinkType\"></a>\n\n### NethelpersLinkType\nNethelpersLinkType is a link type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| LINK_NETROM | 0 |  |\n| LINK_ETHER | 1 |  |\n| LINK_EETHER | 2 |  |\n| LINK_AX25 | 3 |  |\n| LINK_PRONET | 4 |  |\n| LINK_CHAOS | 5 |  |\n| LINK_IEE802 | 6 |  |\n| LINK_ARCNET | 7 |  |\n| LINK_ATALK | 8 |  |\n| LINK_DLCI | 15 |  |\n| LINK_ATM | 19 |  |\n| LINK_METRICOM | 23 |  |\n| LINK_IEEE1394 | 24 |  |\n| LINK_EUI64 | 27 |  |\n| LINK_INFINIBAND | 32 |  |\n| LINK_SLIP | 256 |  |\n| LINK_CSLIP | 257 |  |\n| LINK_SLIP6 | 258 |  |\n| LINK_CSLIP6 | 259 |  |\n| LINK_RSRVD | 260 |  |\n| LINK_ADAPT | 264 |  |\n| LINK_ROSE | 270 |  |\n| LINK_X25 | 271 |  |\n| LINK_HWX25 | 272 |  |\n| LINK_CAN | 280 |  |\n| LINK_PPP | 512 |  |\n| LINK_CISCO | 513 |  |\n| LINK_HDLC | 513 |  |\n| LINK_LAPB | 516 |  |\n| LINK_DDCMP | 517 |  |\n| LINK_RAWHDLC | 518 |  |\n| LINK_TUNNEL | 768 |  |\n| LINK_TUNNEL6 | 769 |  |\n| LINK_FRAD | 770 |  |\n| LINK_SKIP | 771 |  |\n| LINK_LOOPBCK | 772 |  |\n| LINK_LOCALTLK | 773 |  |\n| LINK_FDDI | 774 |  |\n| LINK_BIF | 775 |  |\n| LINK_SIT | 776 |  |\n| LINK_IPDDP | 777 |  |\n| LINK_IPGRE | 778 |  |\n| LINK_PIMREG | 779 |  |\n| LINK_HIPPI | 780 |  |\n| LINK_ASH | 781 |  |\n| LINK_ECONET | 782 |  |\n| LINK_IRDA | 783 |  |\n| LINK_FCPP | 784 |  |\n| LINK_FCAL | 785 |  |\n| LINK_FCPL | 786 |  |\n| LINK_FCFABRIC | 787 |  |\n| LINK_FCFABRIC1 | 788 |  |\n| LINK_FCFABRIC2 | 789 |  |\n| LINK_FCFABRIC3 | 790 |  |\n| LINK_FCFABRIC4 | 791 |  |\n| LINK_FCFABRIC5 | 792 |  |\n| LINK_FCFABRIC6 | 793 |  |\n| LINK_FCFABRIC7 | 794 |  |\n| LINK_FCFABRIC8 | 795 |  |\n| LINK_FCFABRIC9 | 796 |  |\n| LINK_FCFABRIC10 | 797 |  |\n| LINK_FCFABRIC11 | 798 |  |\n| LINK_FCFABRIC12 | 799 |  |\n| LINK_IEE802TR | 800 |  |\n| LINK_IEE80211 | 801 |  |\n| LINK_IEE80211PRISM | 802 |  |\n| LINK_IEE80211_RADIOTAP | 803 |  |\n| LINK_IEE8021154 | 804 |  |\n| LINK_IEE8021154MONITOR | 805 |  |\n| LINK_PHONET | 820 |  |\n| LINK_PHONETPIPE | 821 |  |\n| LINK_CAIF | 822 |  |\n| LINK_IP6GRE | 823 |  |\n| LINK_NETLINK | 824 |  |\n| LINK6_LOWPAN | 825 |  |\n| LINK_VOID | 65535 |  |\n| LINK_NONE | 65534 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersMatchOperator\"></a>\n\n### NethelpersMatchOperator\nNethelpersMatchOperator is a netfilter match operator.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| OPERATOR_EQUAL | 0 |  |\n| OPERATOR_NOT_EQUAL | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersNfTablesChainHook\"></a>\n\n### NethelpersNfTablesChainHook\nNethelpersNfTablesChainHook wraps nftables.ChainHook for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| CHAIN_HOOK_PREROUTING | 0 |  |\n| CHAIN_HOOK_INPUT | 1 |  |\n| CHAIN_HOOK_FORWARD | 2 |  |\n| CHAIN_HOOK_OUTPUT | 3 |  |\n| CHAIN_HOOK_POSTROUTING | 4 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersNfTablesChainPriority\"></a>\n\n### NethelpersNfTablesChainPriority\nNethelpersNfTablesChainPriority wraps nftables.ChainPriority for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_NFTABLESCHAINPRIORITY_UNSPECIFIED | 0 |  |\n| CHAIN_PRIORITY_FIRST | -2147483648 |  |\n| CHAIN_PRIORITY_CONNTRACK_DEFRAG | -400 |  |\n| CHAIN_PRIORITY_RAW | -300 |  |\n| CHAIN_PRIORITY_SE_LINUX_FIRST | -225 |  |\n| CHAIN_PRIORITY_CONNTRACK | -200 |  |\n| CHAIN_PRIORITY_MANGLE | -150 |  |\n| CHAIN_PRIORITY_NAT_DEST | -100 |  |\n| CHAIN_PRIORITY_FILTER | 0 |  |\n| CHAIN_PRIORITY_SECURITY | 50 |  |\n| CHAIN_PRIORITY_NAT_SOURCE | 100 |  |\n| CHAIN_PRIORITY_SE_LINUX_LAST | 225 |  |\n| CHAIN_PRIORITY_CONNTRACK_HELPER | 300 |  |\n| CHAIN_PRIORITY_LAST | 2147483647 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersNfTablesVerdict\"></a>\n\n### NethelpersNfTablesVerdict\nNethelpersNfTablesVerdict wraps nftables.Verdict for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| VERDICT_DROP | 0 |  |\n| VERDICT_ACCEPT | 1 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersOperationalState\"></a>\n\n### NethelpersOperationalState\nNethelpersOperationalState wraps rtnetlink.OperationalState for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| OPER_STATE_UNKNOWN | 0 |  |\n| OPER_STATE_NOT_PRESENT | 1 |  |\n| OPER_STATE_DOWN | 2 |  |\n| OPER_STATE_LOWER_LAYER_DOWN | 3 |  |\n| OPER_STATE_TESTING | 4 |  |\n| OPER_STATE_DORMANT | 5 |  |\n| OPER_STATE_UP | 6 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersPort\"></a>\n\n### NethelpersPort\nNethelpersPort wraps ethtool.Port for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| TWISTED_PAIR | 0 |  |\n| AUI | 1 |  |\n| MII | 2 |  |\n| FIBRE | 3 |  |\n| BNC | 4 |  |\n| DIRECT_ATTACH | 5 |  |\n| NONE | 239 |  |\n| OTHER | 255 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersPrimaryReselect\"></a>\n\n### NethelpersPrimaryReselect\nNethelpersPrimaryReselect is an ARP targets mode.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| PRIMARY_RESELECT_ALWAYS | 0 |  |\n| PRIMARY_RESELECT_BETTER | 1 |  |\n| PRIMARY_RESELECT_FAILURE | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersProtocol\"></a>\n\n### NethelpersProtocol\nNethelpersProtocol is a inet protocol.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_PROTOCOL_UNSPECIFIED | 0 |  |\n| PROTOCOL_ICMP | 1 |  |\n| PROTOCOL_TCP | 6 |  |\n| PROTOCOL_UDP | 17 |  |\n| PROTOCOL_ICM_PV6 | 58 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersRouteFlag\"></a>\n\n### NethelpersRouteFlag\nNethelpersRouteFlag wraps RTM_F_* constants.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_ROUTEFLAG_UNSPECIFIED | 0 |  |\n| ROUTE_NOTIFY | 256 |  |\n| ROUTE_CLONED | 512 |  |\n| ROUTE_EQUALIZE | 1024 |  |\n| ROUTE_PREFIX | 2048 |  |\n| ROUTE_LOOKUP_TABLE | 4096 |  |\n| ROUTE_FIB_MATCH | 8192 |  |\n| ROUTE_OFFLOAD | 16384 |  |\n| ROUTE_TRAP | 32768 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersRouteProtocol\"></a>\n\n### NethelpersRouteProtocol\nNethelpersRouteProtocol is a routing protocol.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| PROTOCOL_UNSPEC | 0 |  |\n| PROTOCOL_REDIRECT | 1 |  |\n| PROTOCOL_KERNEL | 2 |  |\n| PROTOCOL_BOOT | 3 |  |\n| PROTOCOL_STATIC | 4 |  |\n| PROTOCOL_RA | 9 |  |\n| PROTOCOL_MRT | 10 |  |\n| PROTOCOL_ZEBRA | 11 |  |\n| PROTOCOL_BIRD | 12 |  |\n| PROTOCOL_DNROUTED | 13 |  |\n| PROTOCOL_XORP | 14 |  |\n| PROTOCOL_NTK | 15 |  |\n| PROTOCOL_DHCP | 16 |  |\n| PROTOCOL_MRTD | 17 |  |\n| PROTOCOL_KEEPALIVED | 18 |  |\n| PROTOCOL_BABEL | 42 |  |\n| PROTOCOL_OPENR | 99 |  |\n| PROTOCOL_BGP | 186 |  |\n| PROTOCOL_ISIS | 187 |  |\n| PROTOCOL_OSPF | 188 |  |\n| PROTOCOL_RIP | 189 |  |\n| PROTOCOL_EIGRP | 192 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersRouteType\"></a>\n\n### NethelpersRouteType\nNethelpersRouteType is a route type.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| TYPE_UNSPEC | 0 |  |\n| TYPE_UNICAST | 1 |  |\n| TYPE_LOCAL | 2 |  |\n| TYPE_BROADCAST | 3 |  |\n| TYPE_ANYCAST | 4 |  |\n| TYPE_MULTICAST | 5 |  |\n| TYPE_BLACKHOLE | 6 |  |\n| TYPE_UNREACHABLE | 7 |  |\n| TYPE_PROHIBIT | 8 |  |\n| TYPE_THROW | 9 |  |\n| TYPE_NAT | 10 |  |\n| TYPE_X_RESOLVE | 11 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersRoutingRuleAction\"></a>\n\n### NethelpersRoutingRuleAction\nNethelpersRoutingRuleAction is a routing rule action.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| ROUTING_RULE_ACTION_UNSPEC | 0 |  |\n| ROUTING_RULE_ACTION_UNICAST | 1 |  |\n| ROUTING_RULE_ACTION_BLACKHOLE | 6 |  |\n| ROUTING_RULE_ACTION_UNREACHABLE | 7 |  |\n| ROUTING_RULE_ACTION_PROHIBIT | 8 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersRoutingTable\"></a>\n\n### NethelpersRoutingTable\nNethelpersRoutingTable is a routing table ID.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| TABLE_UNSPEC | 0 |  |\n| TABLE1 | 1 |  |\n| TABLE2 | 2 |  |\n| TABLE3 | 3 |  |\n| TABLE4 | 4 |  |\n| TABLE5 | 5 |  |\n| TABLE6 | 6 |  |\n| TABLE7 | 7 |  |\n| TABLE8 | 8 |  |\n| TABLE9 | 9 |  |\n| TABLE10 | 10 |  |\n| TABLE11 | 11 |  |\n| TABLE12 | 12 |  |\n| TABLE13 | 13 |  |\n| TABLE14 | 14 |  |\n| TABLE15 | 15 |  |\n| TABLE16 | 16 |  |\n| TABLE17 | 17 |  |\n| TABLE18 | 18 |  |\n| TABLE19 | 19 |  |\n| TABLE20 | 20 |  |\n| TABLE21 | 21 |  |\n| TABLE22 | 22 |  |\n| TABLE23 | 23 |  |\n| TABLE24 | 24 |  |\n| TABLE25 | 25 |  |\n| TABLE26 | 26 |  |\n| TABLE27 | 27 |  |\n| TABLE28 | 28 |  |\n| TABLE29 | 29 |  |\n| TABLE30 | 30 |  |\n| TABLE31 | 31 |  |\n| TABLE32 | 32 |  |\n| TABLE33 | 33 |  |\n| TABLE34 | 34 |  |\n| TABLE35 | 35 |  |\n| TABLE36 | 36 |  |\n| TABLE37 | 37 |  |\n| TABLE38 | 38 |  |\n| TABLE39 | 39 |  |\n| TABLE40 | 40 |  |\n| TABLE41 | 41 |  |\n| TABLE42 | 42 |  |\n| TABLE43 | 43 |  |\n| TABLE44 | 44 |  |\n| TABLE45 | 45 |  |\n| TABLE46 | 46 |  |\n| TABLE47 | 47 |  |\n| TABLE48 | 48 |  |\n| TABLE49 | 49 |  |\n| TABLE50 | 50 |  |\n| TABLE51 | 51 |  |\n| TABLE52 | 52 |  |\n| TABLE53 | 53 |  |\n| TABLE54 | 54 |  |\n| TABLE55 | 55 |  |\n| TABLE56 | 56 |  |\n| TABLE57 | 57 |  |\n| TABLE58 | 58 |  |\n| TABLE59 | 59 |  |\n| TABLE60 | 60 |  |\n| TABLE61 | 61 |  |\n| TABLE62 | 62 |  |\n| TABLE63 | 63 |  |\n| TABLE64 | 64 |  |\n| TABLE65 | 65 |  |\n| TABLE66 | 66 |  |\n| TABLE67 | 67 |  |\n| TABLE68 | 68 |  |\n| TABLE69 | 69 |  |\n| TABLE70 | 70 |  |\n| TABLE71 | 71 |  |\n| TABLE72 | 72 |  |\n| TABLE73 | 73 |  |\n| TABLE74 | 74 |  |\n| TABLE75 | 75 |  |\n| TABLE76 | 76 |  |\n| TABLE77 | 77 |  |\n| TABLE78 | 78 |  |\n| TABLE79 | 79 |  |\n| TABLE80 | 80 |  |\n| TABLE81 | 81 |  |\n| TABLE82 | 82 |  |\n| TABLE83 | 83 |  |\n| TABLE84 | 84 |  |\n| TABLE85 | 85 |  |\n| TABLE86 | 86 |  |\n| TABLE87 | 87 |  |\n| TABLE88 | 88 |  |\n| TABLE89 | 89 |  |\n| TABLE90 | 90 |  |\n| TABLE91 | 91 |  |\n| TABLE92 | 92 |  |\n| TABLE93 | 93 |  |\n| TABLE94 | 94 |  |\n| TABLE95 | 95 |  |\n| TABLE96 | 96 |  |\n| TABLE97 | 97 |  |\n| TABLE98 | 98 |  |\n| TABLE99 | 99 |  |\n| TABLE100 | 100 |  |\n| TABLE101 | 101 |  |\n| TABLE102 | 102 |  |\n| TABLE103 | 103 |  |\n| TABLE104 | 104 |  |\n| TABLE105 | 105 |  |\n| TABLE106 | 106 |  |\n| TABLE107 | 107 |  |\n| TABLE108 | 108 |  |\n| TABLE109 | 109 |  |\n| TABLE110 | 110 |  |\n| TABLE111 | 111 |  |\n| TABLE112 | 112 |  |\n| TABLE113 | 113 |  |\n| TABLE114 | 114 |  |\n| TABLE115 | 115 |  |\n| TABLE116 | 116 |  |\n| TABLE117 | 117 |  |\n| TABLE118 | 118 |  |\n| TABLE119 | 119 |  |\n| TABLE120 | 120 |  |\n| TABLE121 | 121 |  |\n| TABLE122 | 122 |  |\n| TABLE123 | 123 |  |\n| TABLE124 | 124 |  |\n| TABLE125 | 125 |  |\n| TABLE126 | 126 |  |\n| TABLE127 | 127 |  |\n| TABLE128 | 128 |  |\n| TABLE129 | 129 |  |\n| TABLE130 | 130 |  |\n| TABLE131 | 131 |  |\n| TABLE132 | 132 |  |\n| TABLE133 | 133 |  |\n| TABLE134 | 134 |  |\n| TABLE135 | 135 |  |\n| TABLE136 | 136 |  |\n| TABLE137 | 137 |  |\n| TABLE138 | 138 |  |\n| TABLE139 | 139 |  |\n| TABLE140 | 140 |  |\n| TABLE141 | 141 |  |\n| TABLE142 | 142 |  |\n| TABLE143 | 143 |  |\n| TABLE144 | 144 |  |\n| TABLE145 | 145 |  |\n| TABLE146 | 146 |  |\n| TABLE147 | 147 |  |\n| TABLE148 | 148 |  |\n| TABLE149 | 149 |  |\n| TABLE150 | 150 |  |\n| TABLE151 | 151 |  |\n| TABLE152 | 152 |  |\n| TABLE153 | 153 |  |\n| TABLE154 | 154 |  |\n| TABLE155 | 155 |  |\n| TABLE156 | 156 |  |\n| TABLE157 | 157 |  |\n| TABLE158 | 158 |  |\n| TABLE159 | 159 |  |\n| TABLE160 | 160 |  |\n| TABLE161 | 161 |  |\n| TABLE162 | 162 |  |\n| TABLE163 | 163 |  |\n| TABLE164 | 164 |  |\n| TABLE165 | 165 |  |\n| TABLE166 | 166 |  |\n| TABLE167 | 167 |  |\n| TABLE168 | 168 |  |\n| TABLE169 | 169 |  |\n| TABLE170 | 170 |  |\n| TABLE171 | 171 |  |\n| TABLE172 | 172 |  |\n| TABLE173 | 173 |  |\n| TABLE174 | 174 |  |\n| TABLE175 | 175 |  |\n| TABLE176 | 176 |  |\n| TABLE177 | 177 |  |\n| TABLE178 | 178 |  |\n| TABLE179 | 179 |  |\n| TABLE180 | 180 |  |\n| TABLE181 | 181 |  |\n| TABLE182 | 182 |  |\n| TABLE183 | 183 |  |\n| TABLE184 | 184 |  |\n| TABLE185 | 185 |  |\n| TABLE186 | 186 |  |\n| TABLE187 | 187 |  |\n| TABLE188 | 188 |  |\n| TABLE189 | 189 |  |\n| TABLE190 | 190 |  |\n| TABLE191 | 191 |  |\n| TABLE192 | 192 |  |\n| TABLE193 | 193 |  |\n| TABLE194 | 194 |  |\n| TABLE195 | 195 |  |\n| TABLE196 | 196 |  |\n| TABLE197 | 197 |  |\n| TABLE198 | 198 |  |\n| TABLE199 | 199 |  |\n| TABLE200 | 200 |  |\n| TABLE201 | 201 |  |\n| TABLE202 | 202 |  |\n| TABLE203 | 203 |  |\n| TABLE204 | 204 |  |\n| TABLE205 | 205 |  |\n| TABLE206 | 206 |  |\n| TABLE207 | 207 |  |\n| TABLE208 | 208 |  |\n| TABLE209 | 209 |  |\n| TABLE210 | 210 |  |\n| TABLE211 | 211 |  |\n| TABLE212 | 212 |  |\n| TABLE213 | 213 |  |\n| TABLE214 | 214 |  |\n| TABLE215 | 215 |  |\n| TABLE216 | 216 |  |\n| TABLE217 | 217 |  |\n| TABLE218 | 218 |  |\n| TABLE219 | 219 |  |\n| TABLE220 | 220 |  |\n| TABLE221 | 221 |  |\n| TABLE222 | 222 |  |\n| TABLE223 | 223 |  |\n| TABLE224 | 224 |  |\n| TABLE225 | 225 |  |\n| TABLE226 | 226 |  |\n| TABLE227 | 227 |  |\n| TABLE228 | 228 |  |\n| TABLE229 | 229 |  |\n| TABLE230 | 230 |  |\n| TABLE231 | 231 |  |\n| TABLE232 | 232 |  |\n| TABLE233 | 233 |  |\n| TABLE234 | 234 |  |\n| TABLE235 | 235 |  |\n| TABLE236 | 236 |  |\n| TABLE237 | 237 |  |\n| TABLE238 | 238 |  |\n| TABLE239 | 239 |  |\n| TABLE240 | 240 |  |\n| TABLE241 | 241 |  |\n| TABLE242 | 242 |  |\n| TABLE243 | 243 |  |\n| TABLE244 | 244 |  |\n| TABLE245 | 245 |  |\n| TABLE246 | 246 |  |\n| TABLE247 | 247 |  |\n| TABLE248 | 248 |  |\n| TABLE249 | 249 |  |\n| TABLE250 | 250 |  |\n| TABLE251 | 251 |  |\n| TABLE252 | 252 |  |\n| TABLE_DEFAULT | 253 |  |\n| TABLE_MAIN | 254 |  |\n| TABLE_LOCAL | 255 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersScope\"></a>\n\n### NethelpersScope\nNethelpersScope is an address scope.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| SCOPE_GLOBAL | 0 |  |\n| SCOPE_SITE | 200 |  |\n| SCOPE_LINK | 253 |  |\n| SCOPE_HOST | 254 |  |\n| SCOPE_NOWHERE | 255 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersVLANProtocol\"></a>\n\n### NethelpersVLANProtocol\nNethelpersVLANProtocol is a VLAN protocol.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_VLANPROTOCOL_UNSPECIFIED | 0 |  |\n| VLAN_PROTOCOL8021_Q | 33024 |  |\n| VLAN_PROTOCOL8021_AD | 34984 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NethelpersWOLMode\"></a>\n\n### NethelpersWOLMode\nNethelpersWOLMode wraps ethtool.WOLMode for YAML marshaling.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| NETHELPERS_WOLMODE_UNSPECIFIED | 0 |  |\n| WOL_MODE_PHY | 1 |  |\n| WOL_MODE_UNICAST | 2 |  |\n| WOL_MODE_MULTICAST | 4 |  |\n| WOL_MODE_BROADCAST | 8 |  |\n| WOL_MODE_MAGIC | 32 |  |\n| WOL_MODE_MAGIC_SECURE | 64 |  |\n| WOL_MODE_FILTER | 128 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NetworkConfigLayer\"></a>\n\n### NetworkConfigLayer\nNetworkConfigLayer describes network configuration layers, with lowest priority first.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| CONFIG_DEFAULT | 0 |  |\n| CONFIG_CMDLINE | 1 |  |\n| CONFIG_PLATFORM | 2 |  |\n| CONFIG_OPERATOR | 3 |  |\n| CONFIG_MACHINE_CONFIGURATION | 4 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.NetworkOperator\"></a>\n\n### NetworkOperator\nNetworkOperator enumerates Talos network operators.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| OPERATOR_DHCP4 | 0 |  |\n| OPERATOR_DHCP6 | 1 |  |\n| OPERATOR_VIP | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.RuntimeFIPSState\"></a>\n\n### RuntimeFIPSState\nRuntimeFIPSState describes the current FIPS status.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FIPS_STATE_DISABLED | 0 |  |\n| FIPS_STATE_ENABLED | 1 |  |\n| FIPS_STATE_STRICT | 2 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.RuntimeMachineStage\"></a>\n\n### RuntimeMachineStage\nRuntimeMachineStage describes the stage of the machine boot/run process.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| MACHINE_STAGE_UNKNOWN | 0 |  |\n| MACHINE_STAGE_BOOTING | 1 |  |\n| MACHINE_STAGE_INSTALLING | 2 |  |\n| MACHINE_STAGE_MAINTENANCE | 3 |  |\n| MACHINE_STAGE_RUNNING | 4 |  |\n| MACHINE_STAGE_REBOOTING | 5 |  |\n| MACHINE_STAGE_SHUTTING_DOWN | 6 |  |\n| MACHINE_STAGE_RESETTING | 7 |  |\n| MACHINE_STAGE_UPGRADING | 8 |  |\n\n\n\n<a name=\"talos.resource.definitions.enums.RuntimeSELinuxState\"></a>\n\n### RuntimeSELinuxState\nRuntimeSELinuxState describes the current SELinux status.\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| SE_LINUX_STATE_DISABLED | 0 |  |\n| SE_LINUX_STATE_PERMISSIVE | 1 |  |\n| SE_LINUX_STATE_ENFORCING | 2 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/block/block.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/block/block.proto\n\n\n\n<a name=\"talos.resource.definitions.block.DeviceSpec\"></a>\n\n### DeviceSpec\nDeviceSpec is the spec for devices status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [string](#string) |  |  |\n| major | [int64](#int64) |  |  |\n| minor | [int64](#int64) |  |  |\n| partition_name | [string](#string) |  |  |\n| partition_number | [int64](#int64) |  |  |\n| generation | [int64](#int64) |  |  |\n| device_path | [string](#string) |  |  |\n| parent | [string](#string) |  |  |\n| secondaries | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.DiscoveredVolumeSpec\"></a>\n\n### DiscoveredVolumeSpec\nDiscoveredVolumeSpec is the spec for DiscoveredVolumes resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| size | [uint64](#uint64) |  |  |\n| sector_size | [uint64](#uint64) |  |  |\n| io_size | [uint64](#uint64) |  |  |\n| name | [string](#string) |  |  |\n| uuid | [string](#string) |  |  |\n| label | [string](#string) |  |  |\n| block_size | [uint32](#uint32) |  |  |\n| filesystem_block_size | [uint32](#uint32) |  |  |\n| probed_size | [uint64](#uint64) |  |  |\n| partition_uuid | [string](#string) |  |  |\n| partition_type | [string](#string) |  |  |\n| partition_label | [string](#string) |  |  |\n| partition_index | [uint64](#uint64) |  |  |\n| type | [string](#string) |  |  |\n| device_path | [string](#string) |  |  |\n| parent | [string](#string) |  |  |\n| dev_path | [string](#string) |  |  |\n| parent_dev_path | [string](#string) |  |  |\n| pretty_size | [string](#string) |  |  |\n| offset | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.DiscoveryRefreshRequestSpec\"></a>\n\n### DiscoveryRefreshRequestSpec\nDiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| request | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.DiscoveryRefreshStatusSpec\"></a>\n\n### DiscoveryRefreshStatusSpec\nDiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| request | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.DiskSelector\"></a>\n\n### DiskSelector\nDiskSelector selects a disk for the volume.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| match | [google.api.expr.v1alpha1.CheckedExpr](#google.api.expr.v1alpha1.CheckedExpr) |  |  |\n| external | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.DiskSpec\"></a>\n\n### DiskSpec\nDiskSpec is the spec for Disks status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| size | [uint64](#uint64) |  |  |\n| io_size | [uint64](#uint64) |  |  |\n| sector_size | [uint64](#uint64) |  |  |\n| readonly | [bool](#bool) |  |  |\n| model | [string](#string) |  |  |\n| serial | [string](#string) |  |  |\n| modalias | [string](#string) |  |  |\n| wwid | [string](#string) |  |  |\n| bus_path | [string](#string) |  |  |\n| sub_system | [string](#string) |  |  |\n| transport | [string](#string) |  |  |\n| rotational | [bool](#bool) |  |  |\n| cdrom | [bool](#bool) |  |  |\n| dev_path | [string](#string) |  |  |\n| pretty_size | [string](#string) |  |  |\n| secondary_disks | [string](#string) | repeated |  |\n| uuid | [string](#string) |  |  |\n| symlinks | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.EncryptionKey\"></a>\n\n### EncryptionKey\nEncryptionKey is the spec for volume encryption key.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| slot | [int64](#int64) |  |  |\n| type | [talos.resource.definitions.enums.BlockEncryptionKeyType](#talos.resource.definitions.enums.BlockEncryptionKeyType) |  |  |\n| static_passphrase | [bytes](#bytes) |  |  |\n| kms_endpoint | [string](#string) |  |  |\n| tpm_check_secureboot_status_on_enroll | [bool](#bool) |  |  |\n| lock_to_state | [bool](#bool) |  |  |\n| tpmpc_rs | [int64](#int64) | repeated |  |\n| tpm_pub_key_pc_rs | [int64](#int64) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.EncryptionSpec\"></a>\n\n### EncryptionSpec\nEncryptionSpec is the spec for volume encryption.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| provider | [talos.resource.definitions.enums.BlockEncryptionProviderType](#talos.resource.definitions.enums.BlockEncryptionProviderType) |  |  |\n| keys | [EncryptionKey](#talos.resource.definitions.block.EncryptionKey) | repeated |  |\n| cipher | [string](#string) |  |  |\n| key_size | [uint64](#uint64) |  |  |\n| block_size | [uint64](#uint64) |  |  |\n| perf_options | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.FilesystemSpec\"></a>\n\n### FilesystemSpec\nFilesystemSpec is the spec for volume filesystem.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [talos.resource.definitions.enums.BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) |  |  |\n| label | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.LocatorSpec\"></a>\n\n### LocatorSpec\nLocatorSpec is the spec for volume locator.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| match | [google.api.expr.v1alpha1.CheckedExpr](#google.api.expr.v1alpha1.CheckedExpr) |  |  |\n| disk_match | [google.api.expr.v1alpha1.CheckedExpr](#google.api.expr.v1alpha1.CheckedExpr) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.MountRequestSpec\"></a>\n\n### MountRequestSpec\nMountRequestSpec is the spec for MountRequest.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| volume_id | [string](#string) |  |  |\n| parent_mount_id | [string](#string) |  |  |\n| requesters | [string](#string) | repeated |  |\n| requester_i_ds | [string](#string) | repeated |  |\n| read_only | [bool](#bool) |  |  |\n| detached | [bool](#bool) |  |  |\n| disable_access_time | [bool](#bool) |  |  |\n| secure | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.MountSpec\"></a>\n\n### MountSpec\nMountSpec is the spec for volume mount.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| target_path | [string](#string) |  |  |\n| selinux_label | [string](#string) |  |  |\n| project_quota_support | [bool](#bool) |  |  |\n| parent_id | [string](#string) |  |  |\n| file_mode | [uint32](#uint32) |  |  |\n| uid | [int64](#int64) |  |  |\n| gid | [int64](#int64) |  |  |\n| recursive_relabel | [bool](#bool) |  |  |\n| bind_target | [string](#string) |  |  |\n| parameters | [ParameterSpec](#talos.resource.definitions.block.ParameterSpec) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.MountStatusSpec\"></a>\n\n### MountStatusSpec\nMountStatusSpec is the spec for MountStatus.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| spec | [MountRequestSpec](#talos.resource.definitions.block.MountRequestSpec) |  |  |\n| target | [string](#string) |  |  |\n| source | [string](#string) |  |  |\n| filesystem | [talos.resource.definitions.enums.BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) |  |  |\n| read_only | [bool](#bool) |  |  |\n| project_quota_support | [bool](#bool) |  |  |\n| encryption_provider | [talos.resource.definitions.enums.BlockEncryptionProviderType](#talos.resource.definitions.enums.BlockEncryptionProviderType) |  |  |\n| detached | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.ParameterSpec\"></a>\n\n### ParameterSpec\nParameterSpec is a mount parameter.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [talos.resource.definitions.enums.BlockFSParameterType](#talos.resource.definitions.enums.BlockFSParameterType) |  |  |\n| name | [string](#string) |  |  |\n| string | [string](#string) |  |  |\n| binary | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.PartitionSpec\"></a>\n\n### PartitionSpec\nPartitionSpec is the spec for volume partitioning.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| min_size | [uint64](#uint64) |  |  |\n| max_size | [uint64](#uint64) |  |  |\n| grow | [bool](#bool) |  |  |\n| label | [string](#string) |  |  |\n| type_uuid | [string](#string) |  |  |\n| relative_max_size | [uint64](#uint64) |  |  |\n| negative_max_size | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.ProvisioningSpec\"></a>\n\n### ProvisioningSpec\nProvisioningSpec is the spec for volume provisioning.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| disk_selector | [DiskSelector](#talos.resource.definitions.block.DiskSelector) |  |  |\n| partition_spec | [PartitionSpec](#talos.resource.definitions.block.PartitionSpec) |  |  |\n| wave | [int64](#int64) |  |  |\n| filesystem_spec | [FilesystemSpec](#talos.resource.definitions.block.FilesystemSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.SwapStatusSpec\"></a>\n\n### SwapStatusSpec\nSwapStatusSpec is the spec for SwapStatuss resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| device | [string](#string) |  |  |\n| size_bytes | [uint64](#uint64) |  |  |\n| size_human | [string](#string) |  |  |\n| used_bytes | [uint64](#uint64) |  |  |\n| used_human | [string](#string) |  |  |\n| priority | [int32](#int32) |  |  |\n| type | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.SymlinkProvisioningSpec\"></a>\n\n### SymlinkProvisioningSpec\nSymlinkProvisioningSpec is the spec for volume symlink.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| symlink_target_path | [string](#string) |  |  |\n| force | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.SymlinkSpec\"></a>\n\n### SymlinkSpec\nSymlinkSpec is the spec for Symlinks resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| paths | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.SystemDiskSpec\"></a>\n\n### SystemDiskSpec\nSystemDiskSpec is the spec for SystemDisks resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| disk_id | [string](#string) |  |  |\n| dev_path | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.TPMEncryptionOptionsInfo\"></a>\n\n### TPMEncryptionOptionsInfo\nTPMEncryptionOptionsInfo is the options for TPM-based encryption.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pc_rs | [int64](#int64) | repeated |  |\n| pub_key_pc_rs | [int64](#int64) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.UserDiskConfigStatusSpec\"></a>\n\n### UserDiskConfigStatusSpec\nUserDiskConfigStatusSpec is the spec for UserDiskConfigStatus resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| torn_down | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.VolumeConfigSpec\"></a>\n\n### VolumeConfigSpec\nVolumeConfigSpec is the spec for VolumeConfig resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| parent_id | [string](#string) |  |  |\n| type | [talos.resource.definitions.enums.BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType) |  |  |\n| provisioning | [ProvisioningSpec](#talos.resource.definitions.block.ProvisioningSpec) |  |  |\n| locator | [LocatorSpec](#talos.resource.definitions.block.LocatorSpec) |  |  |\n| mount | [MountSpec](#talos.resource.definitions.block.MountSpec) |  |  |\n| encryption | [EncryptionSpec](#talos.resource.definitions.block.EncryptionSpec) |  |  |\n| symlink | [SymlinkProvisioningSpec](#talos.resource.definitions.block.SymlinkProvisioningSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.VolumeMountRequestSpec\"></a>\n\n### VolumeMountRequestSpec\nVolumeMountRequestSpec is the spec for VolumeMountRequest.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| volume_id | [string](#string) |  |  |\n| requester | [string](#string) |  |  |\n| read_only | [bool](#bool) |  |  |\n| detached | [bool](#bool) |  |  |\n| disable_access_time | [bool](#bool) |  |  |\n| secure | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.VolumeMountStatusSpec\"></a>\n\n### VolumeMountStatusSpec\nVolumeMountStatusSpec is the spec for VolumeMountStatus.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| volume_id | [string](#string) |  |  |\n| requester | [string](#string) |  |  |\n| target | [string](#string) |  |  |\n| read_only | [bool](#bool) |  |  |\n| detached | [bool](#bool) |  |  |\n| disable_access_time | [bool](#bool) |  |  |\n| secure | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.VolumeStatusSpec\"></a>\n\n### VolumeStatusSpec\nVolumeStatusSpec is the spec for VolumeStatus resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| phase | [talos.resource.definitions.enums.BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) |  |  |\n| location | [string](#string) |  |  |\n| error_message | [string](#string) |  |  |\n| uuid | [string](#string) |  |  |\n| partition_uuid | [string](#string) |  |  |\n| pre_fail_phase | [talos.resource.definitions.enums.BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) |  |  |\n| parent_location | [string](#string) |  |  |\n| partition_index | [int64](#int64) |  |  |\n| size | [uint64](#uint64) |  |  |\n| filesystem | [talos.resource.definitions.enums.BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) |  |  |\n| mount_location | [string](#string) |  |  |\n| encryption_provider | [talos.resource.definitions.enums.BlockEncryptionProviderType](#talos.resource.definitions.enums.BlockEncryptionProviderType) |  |  |\n| pretty_size | [string](#string) |  |  |\n| encryption_failed_syncs | [string](#string) | repeated |  |\n| mount_spec | [MountSpec](#talos.resource.definitions.block.MountSpec) |  |  |\n| type | [talos.resource.definitions.enums.BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType) |  |  |\n| configured_encryption_keys | [string](#string) | repeated |  |\n| symlink_spec | [SymlinkProvisioningSpec](#talos.resource.definitions.block.SymlinkProvisioningSpec) |  |  |\n| parent_id | [string](#string) |  |  |\n| encryption_locked_to_state | [bool](#bool) |  |  |\n| encryption_slot | [int64](#int64) |  |  |\n| tpm_encryption_options | [TPMEncryptionOptionsInfo](#talos.resource.definitions.block.TPMEncryptionOptionsInfo) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.block.ZswapStatusSpec\"></a>\n\n### ZswapStatusSpec\nZswapStatusSpec is the spec for ZswapStatus resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| total_size_bytes | [uint64](#uint64) |  |  |\n| total_size_human | [string](#string) |  |  |\n| stored_pages | [uint64](#uint64) |  |  |\n| pool_limit_hit | [uint64](#uint64) |  |  |\n| reject_reclaim_fail | [uint64](#uint64) |  |  |\n| reject_alloc_fail | [uint64](#uint64) |  |  |\n| reject_kmemcache_fail | [uint64](#uint64) |  |  |\n| reject_compress_fail | [uint64](#uint64) |  |  |\n| reject_compress_poor | [uint64](#uint64) |  |  |\n| written_back_pages | [uint64](#uint64) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/cluster/cluster.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/cluster/cluster.proto\n\n\n\n<a name=\"talos.resource.definitions.cluster.AffiliateSpec\"></a>\n\n### AffiliateSpec\nAffiliateSpec describes Affiliate state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| node_id | [string](#string) |  |  |\n| addresses | [common.NetIP](#common.NetIP) | repeated |  |\n| hostname | [string](#string) |  |  |\n| nodename | [string](#string) |  |  |\n| operating_system | [string](#string) |  |  |\n| machine_type | [talos.resource.definitions.enums.MachineType](#talos.resource.definitions.enums.MachineType) |  |  |\n| kube_span | [KubeSpanAffiliateSpec](#talos.resource.definitions.cluster.KubeSpanAffiliateSpec) |  |  |\n| control_plane | [ControlPlane](#talos.resource.definitions.cluster.ControlPlane) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.ConfigSpec\"></a>\n\n### ConfigSpec\nConfigSpec describes KubeSpan configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| discovery_enabled | [bool](#bool) |  |  |\n| registry_kubernetes_enabled | [bool](#bool) |  |  |\n| registry_service_enabled | [bool](#bool) |  |  |\n| service_endpoint | [string](#string) |  |  |\n| service_endpoint_insecure | [bool](#bool) |  |  |\n| service_encryption_key | [bytes](#bytes) |  |  |\n| service_cluster_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.ControlPlane\"></a>\n\n### ControlPlane\nControlPlane describes ControlPlane data if any.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| api_server_port | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.IdentitySpec\"></a>\n\n### IdentitySpec\nIdentitySpec describes status of rendered secrets.\n\nNote: IdentitySpec is persisted on disk in the STATE partition,\nso YAML serialization should be kept backwards compatible.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| node_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.InfoSpec\"></a>\n\n### InfoSpec\nInfoSpec describes cluster information.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| cluster_id | [string](#string) |  |  |\n| cluster_name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.KubeSpanAffiliateSpec\"></a>\n\n### KubeSpanAffiliateSpec\nKubeSpanAffiliateSpec describes additional information specific for the KubeSpan.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| public_key | [string](#string) |  |  |\n| address | [common.NetIP](#common.NetIP) |  |  |\n| additional_addresses | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| endpoints | [common.NetIPPort](#common.NetIPPort) | repeated |  |\n| exclude_advertised_networks | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cluster.MemberSpec\"></a>\n\n### MemberSpec\nMemberSpec describes Member state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| node_id | [string](#string) |  |  |\n| addresses | [common.NetIP](#common.NetIP) | repeated |  |\n| hostname | [string](#string) |  |  |\n| machine_type | [talos.resource.definitions.enums.MachineType](#talos.resource.definitions.enums.MachineType) |  |  |\n| operating_system | [string](#string) |  |  |\n| control_plane | [ControlPlane](#talos.resource.definitions.cluster.ControlPlane) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/cri/cri.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/cri/cri.proto\n\n\n\n<a name=\"talos.resource.definitions.cri.ImageCacheConfigSpec\"></a>\n\n### ImageCacheConfigSpec\nImageCacheConfigSpec represents the ImageCacheConfig.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| status | [talos.resource.definitions.enums.CriImageCacheStatus](#talos.resource.definitions.enums.CriImageCacheStatus) |  |  |\n| roots | [string](#string) | repeated |  |\n| copy_status | [talos.resource.definitions.enums.CriImageCacheCopyStatus](#talos.resource.definitions.enums.CriImageCacheCopyStatus) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistriesConfigSpec\"></a>\n\n### RegistriesConfigSpec\nRegistriesConfigSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| registry_mirrors | [RegistriesConfigSpec.RegistryMirrorsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry) | repeated |  |\n| registry_auths | [RegistriesConfigSpec.RegistryAuthsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry) | repeated |  |\n| registry_tl_ss | [RegistriesConfigSpec.RegistryTlSsEntry](#talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistriesConfigSpec.RegistryAuthsEntry\"></a>\n\n### RegistriesConfigSpec.RegistryAuthsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [RegistryAuthConfig](#talos.resource.definitions.cri.RegistryAuthConfig) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistriesConfigSpec.RegistryMirrorsEntry\"></a>\n\n### RegistriesConfigSpec.RegistryMirrorsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [RegistryMirrorConfig](#talos.resource.definitions.cri.RegistryMirrorConfig) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistriesConfigSpec.RegistryTlSsEntry\"></a>\n\n### RegistriesConfigSpec.RegistryTlSsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [RegistryTLSConfig](#talos.resource.definitions.cri.RegistryTLSConfig) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistryAuthConfig\"></a>\n\n### RegistryAuthConfig\nRegistryAuthConfig specifies authentication configuration for a registry.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| registry_username | [string](#string) |  |  |\n| registry_password | [string](#string) |  |  |\n| registry_auth | [string](#string) |  |  |\n| registry_identity_token | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistryEndpointConfig\"></a>\n\n### RegistryEndpointConfig\nRegistryEndpointConfig represents a single registry endpoint.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint_endpoint | [string](#string) |  |  |\n| endpoint_override_path | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistryMirrorConfig\"></a>\n\n### RegistryMirrorConfig\nRegistryMirrorConfig represents mirror configuration for a registry.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mirror_endpoints | [RegistryEndpointConfig](#talos.resource.definitions.cri.RegistryEndpointConfig) | repeated |  |\n| mirror_skip_fallback | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.RegistryTLSConfig\"></a>\n\n### RegistryTLSConfig\nRegistryTLSConfig specifies TLS config for HTTPS registries.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| tls_client_identity | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| tlsca | [bytes](#bytes) |  |  |\n| tls_insecure_skip_verify | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.cri.SeccompProfileSpec\"></a>\n\n### SeccompProfileSpec\nSeccompProfileSpec represents the SeccompProfile.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| value | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/etcd/etcd.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/etcd/etcd.proto\n\n\n\n<a name=\"talos.resource.definitions.etcd.ArgValues\"></a>\n\n### ArgValues\nArgValues represents values for a command line argument which can be specified multiple times.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| values | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.ConfigSpec\"></a>\n\n### ConfigSpec\nConfigSpec describes (some) configuration settings of etcd.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| advertise_valid_subnets | [string](#string) | repeated |  |\n| advertise_exclude_subnets | [string](#string) | repeated |  |\n| image | [string](#string) |  |  |\n| extra_args | [ConfigSpec.ExtraArgsEntry](#talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry) | repeated |  |\n| listen_valid_subnets | [string](#string) | repeated |  |\n| listen_exclude_subnets | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.ConfigSpec.ExtraArgsEntry\"></a>\n\n### ConfigSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.etcd.ArgValues) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.MemberSpec\"></a>\n\n### MemberSpec\nMemberSpec holds information about an etcd member.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| member_id | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.PKIStatusSpec\"></a>\n\n### PKIStatusSpec\nPKIStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.SpecSpec\"></a>\n\n### SpecSpec\nSpecSpec describes (some) Specuration settings of etcd.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| advertised_addresses | [common.NetIP](#common.NetIP) | repeated |  |\n| image | [string](#string) |  |  |\n| extra_args | [SpecSpec.ExtraArgsEntry](#talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry) | repeated |  |\n| listen_peer_addresses | [common.NetIP](#common.NetIP) | repeated |  |\n| listen_client_addresses | [common.NetIP](#common.NetIP) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.etcd.SpecSpec.ExtraArgsEntry\"></a>\n\n### SpecSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.etcd.ArgValues) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/extensions/extensions.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/extensions/extensions.proto\n\n\n\n<a name=\"talos.resource.definitions.extensions.Compatibility\"></a>\n\n### Compatibility\nCompatibility describes extension compatibility.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| talos | [Constraint](#talos.resource.definitions.extensions.Constraint) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.extensions.Constraint\"></a>\n\n### Constraint\nConstraint describes compatibility constraint.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.extensions.Layer\"></a>\n\n### Layer\nLayer defines overlay mount layer.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| metadata | [Metadata](#talos.resource.definitions.extensions.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.extensions.Metadata\"></a>\n\n### Metadata\nMetadata describes base extension metadata.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| version | [string](#string) |  |  |\n| author | [string](#string) |  |  |\n| description | [string](#string) |  |  |\n| compatibility | [Compatibility](#talos.resource.definitions.extensions.Compatibility) |  |  |\n| extra_info | [string](#string) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/files/files.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/files/files.proto\n\n\n\n<a name=\"talos.resource.definitions.files.EtcFileSpecSpec\"></a>\n\n### EtcFileSpecSpec\nEtcFileSpecSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| contents | [bytes](#bytes) |  |  |\n| mode | [uint32](#uint32) |  |  |\n| selinux_label | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.files.EtcFileStatusSpec\"></a>\n\n### EtcFileStatusSpec\nEtcFileStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| spec_version | [string](#string) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/hardware/hardware.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/hardware/hardware.proto\n\n\n\n<a name=\"talos.resource.definitions.hardware.MemoryModuleSpec\"></a>\n\n### MemoryModuleSpec\nMemoryModuleSpec represents a single Memory.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| size | [uint32](#uint32) |  |  |\n| device_locator | [string](#string) |  |  |\n| bank_locator | [string](#string) |  |  |\n| speed | [uint32](#uint32) |  |  |\n| manufacturer | [string](#string) |  |  |\n| serial_number | [string](#string) |  |  |\n| asset_tag | [string](#string) |  |  |\n| product_name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.hardware.PCIDeviceSpec\"></a>\n\n### PCIDeviceSpec\nPCIDeviceSpec represents a single processor.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| class | [string](#string) |  |  |\n| subclass | [string](#string) |  |  |\n| vendor | [string](#string) |  |  |\n| product | [string](#string) |  |  |\n| class_id | [string](#string) |  |  |\n| subclass_id | [string](#string) |  |  |\n| vendor_id | [string](#string) |  |  |\n| product_id | [string](#string) |  |  |\n| driver | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.hardware.PCIDriverRebindConfigSpec\"></a>\n\n### PCIDriverRebindConfigSpec\nPCIDriverRebindConfigSpec describes PCI rebind configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pciid | [string](#string) |  |  |\n| target_driver | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.hardware.PCIDriverRebindStatusSpec\"></a>\n\n### PCIDriverRebindStatusSpec\nPCIDriverRebindStatusSpec describes status of rebinded drivers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pciid | [string](#string) |  |  |\n| target_driver | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.hardware.ProcessorSpec\"></a>\n\n### ProcessorSpec\nProcessorSpec represents a single processor.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| socket | [string](#string) |  |  |\n| manufacturer | [string](#string) |  |  |\n| product_name | [string](#string) |  |  |\n| max_speed | [uint32](#uint32) |  |  |\n| boot_speed | [uint32](#uint32) |  |  |\n| status | [uint32](#uint32) |  |  |\n| serial_number | [string](#string) |  |  |\n| asset_tag | [string](#string) |  |  |\n| part_number | [string](#string) |  |  |\n| core_count | [uint32](#uint32) |  |  |\n| core_enabled | [uint32](#uint32) |  |  |\n| thread_count | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.hardware.SystemInformationSpec\"></a>\n\n### SystemInformationSpec\nSystemInformationSpec represents the system information obtained from smbios.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| manufacturer | [string](#string) |  |  |\n| product_name | [string](#string) |  |  |\n| version | [string](#string) |  |  |\n| serial_number | [string](#string) |  |  |\n| uuid | [string](#string) |  |  |\n| wake_up_type | [string](#string) |  |  |\n| sku_number | [string](#string) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/proto/proto.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/proto/proto.proto\n\n\n\n<a name=\"talos.resource.definitions.proto.LinuxIDMapping\"></a>\n\n### LinuxIDMapping\nLinuxIDMapping specifies UID/GID mappings.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| container_id | [uint32](#uint32) |  |  |\n| host_id | [uint32](#uint32) |  |  |\n| size | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.proto.Mount\"></a>\n\n### Mount\nMount specifies a mount for a container.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| destination | [string](#string) |  |  |\n| type | [string](#string) |  |  |\n| source | [string](#string) |  |  |\n| options | [string](#string) | repeated |  |\n| uid_mappings | [LinuxIDMapping](#talos.resource.definitions.proto.LinuxIDMapping) | repeated |  |\n| gid_mappings | [LinuxIDMapping](#talos.resource.definitions.proto.LinuxIDMapping) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/k8s/k8s.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/k8s/k8s.proto\n\n\n\n<a name=\"talos.resource.definitions.k8s.APIServerConfigSpec\"></a>\n\n### APIServerConfigSpec\nAPIServerConfigSpec is configuration for kube-apiserver.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| cloud_provider | [string](#string) |  |  |\n| control_plane_endpoint | [string](#string) |  |  |\n| etcd_servers | [string](#string) | repeated |  |\n| local_port | [int64](#int64) |  |  |\n| service_cid_rs | [string](#string) | repeated |  |\n| extra_args | [APIServerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry) | repeated |  |\n| extra_volumes | [ExtraVolume](#talos.resource.definitions.k8s.ExtraVolume) | repeated |  |\n| environment_variables | [APIServerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry) | repeated |  |\n| advertised_address | [string](#string) |  |  |\n| resources | [Resources](#talos.resource.definitions.k8s.Resources) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.APIServerConfigSpec.EnvironmentVariablesEntry\"></a>\n\n### APIServerConfigSpec.EnvironmentVariablesEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.APIServerConfigSpec.ExtraArgsEntry\"></a>\n\n### APIServerConfigSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.k8s.ArgValues) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.AdmissionControlConfigSpec\"></a>\n\n### AdmissionControlConfigSpec\nAdmissionControlConfigSpec is configuration for kube-apiserver.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| config | [AdmissionPluginSpec](#talos.resource.definitions.k8s.AdmissionPluginSpec) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.AdmissionPluginSpec\"></a>\n\n### AdmissionPluginSpec\nAdmissionPluginSpec is a single admission plugin configuration Admission Control plugins.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| configuration | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ArgValues\"></a>\n\n### ArgValues\nArgValues represents values for a command line argument which can be specified multiple times.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| values | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.AuditPolicyConfigSpec\"></a>\n\n### AuditPolicyConfigSpec\nAuditPolicyConfigSpec is audit policy configuration for kube-apiserver.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.AuthorizationAuthorizersSpec\"></a>\n\n### AuthorizationAuthorizersSpec\nAuthorizationAuthorizersSpec is a configuration of authorization authorizers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [string](#string) |  |  |\n| name | [string](#string) |  |  |\n| webhook | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.AuthorizationConfigSpec\"></a>\n\n### AuthorizationConfigSpec\nAuthorizationConfigSpec is authorization configuration for kube-apiserver.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| config | [AuthorizationAuthorizersSpec](#talos.resource.definitions.k8s.AuthorizationAuthorizersSpec) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.BootstrapManifestsConfigSpec\"></a>\n\n### BootstrapManifestsConfigSpec\nBootstrapManifestsConfigSpec is configuration for bootstrap manifests.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| server | [string](#string) |  |  |\n| cluster_domain | [string](#string) |  |  |\n| pod_cid_rs | [string](#string) | repeated |  |\n| proxy_enabled | [bool](#bool) |  |  |\n| proxy_image | [string](#string) |  |  |\n| proxy_args | [string](#string) | repeated |  |\n| core_dns_enabled | [bool](#bool) |  |  |\n| core_dns_image | [string](#string) |  |  |\n| dns_service_ip | [string](#string) |  |  |\n| dns_service_i_pv6 | [string](#string) |  |  |\n| flannel_enabled | [bool](#bool) |  |  |\n| flannel_image | [string](#string) |  |  |\n| pod_security_policy_enabled | [bool](#bool) |  |  |\n| talos_api_service_enabled | [bool](#bool) |  |  |\n| flannel_extra_args | [string](#string) | repeated |  |\n| flannel_kube_service_host | [string](#string) |  |  |\n| flannel_kube_service_port | [string](#string) |  |  |\n| flannel_kube_network_policies_enabled | [bool](#bool) |  |  |\n| flannel_kube_network_policies_image | [string](#string) |  |  |\n| cni_name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ConfigStatusSpec\"></a>\n\n### ConfigStatusSpec\nConfigStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ControllerManagerConfigSpec\"></a>\n\n### ControllerManagerConfigSpec\nControllerManagerConfigSpec is configuration for kube-controller-manager.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n| image | [string](#string) |  |  |\n| cloud_provider | [string](#string) |  |  |\n| pod_cid_rs | [string](#string) | repeated |  |\n| service_cid_rs | [string](#string) | repeated |  |\n| extra_args | [ControllerManagerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry) | repeated |  |\n| extra_volumes | [ExtraVolume](#talos.resource.definitions.k8s.ExtraVolume) | repeated |  |\n| environment_variables | [ControllerManagerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry) | repeated |  |\n| resources | [Resources](#talos.resource.definitions.k8s.Resources) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ControllerManagerConfigSpec.EnvironmentVariablesEntry\"></a>\n\n### ControllerManagerConfigSpec.EnvironmentVariablesEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ControllerManagerConfigSpec.ExtraArgsEntry\"></a>\n\n### ControllerManagerConfigSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.k8s.ArgValues) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.EndpointSpec\"></a>\n\n### EndpointSpec\nEndpointSpec describes a list of endpoints to connect to.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| addresses | [common.NetIP](#common.NetIP) | repeated |  |\n| hosts | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ExtraManifest\"></a>\n\n### ExtraManifest\nExtraManifest defines a single extra manifest to download.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| url | [string](#string) |  |  |\n| priority | [string](#string) |  |  |\n| extra_headers | [ExtraManifest.ExtraHeadersEntry](#talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry) | repeated |  |\n| inline_manifest | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ExtraManifest.ExtraHeadersEntry\"></a>\n\n### ExtraManifest.ExtraHeadersEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ExtraManifestsConfigSpec\"></a>\n\n### ExtraManifestsConfigSpec\nExtraManifestsConfigSpec is configuration for extra bootstrap manifests.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| extra_manifests | [ExtraManifest](#talos.resource.definitions.k8s.ExtraManifest) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ExtraVolume\"></a>\n\n### ExtraVolume\nExtraVolume is a configuration of extra volume.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| host_path | [string](#string) |  |  |\n| mount_path | [string](#string) |  |  |\n| read_only | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubePrismConfigSpec\"></a>\n\n### KubePrismConfigSpec\nKubePrismConfigSpec describes KubePrismConfig data.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| host | [string](#string) |  |  |\n| port | [int64](#int64) |  |  |\n| endpoints | [KubePrismEndpoint](#talos.resource.definitions.k8s.KubePrismEndpoint) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubePrismEndpoint\"></a>\n\n### KubePrismEndpoint\nKubePrismEndpoint holds data for control plane endpoint.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| host | [string](#string) |  |  |\n| port | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubePrismEndpointsSpec\"></a>\n\n### KubePrismEndpointsSpec\nKubePrismEndpointsSpec describes KubePrismEndpoints configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoints | [KubePrismEndpoint](#talos.resource.definitions.k8s.KubePrismEndpoint) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubePrismStatusesSpec\"></a>\n\n### KubePrismStatusesSpec\nKubePrismStatusesSpec describes KubePrismStatuses data.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| host | [string](#string) |  |  |\n| healthy | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubeletConfigSpec\"></a>\n\n### KubeletConfigSpec\nKubeletConfigSpec holds the source of kubelet configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| cluster_dns | [string](#string) | repeated |  |\n| cluster_domain | [string](#string) |  |  |\n| extra_args | [KubeletConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry) | repeated |  |\n| extra_mounts | [talos.resource.definitions.proto.Mount](#talos.resource.definitions.proto.Mount) | repeated |  |\n| extra_config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n| cloud_provider_external | [bool](#bool) |  |  |\n| default_runtime_seccomp_enabled | [bool](#bool) |  |  |\n| skip_node_registration | [bool](#bool) |  |  |\n| static_pod_list_url | [string](#string) |  |  |\n| disable_manifests_directory | [bool](#bool) |  |  |\n| enable_fs_quota_monitoring | [bool](#bool) |  |  |\n| credential_provider_config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n| allow_scheduling_on_control_plane | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubeletConfigSpec.ExtraArgsEntry\"></a>\n\n### KubeletConfigSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.k8s.ArgValues) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.KubeletSpecSpec\"></a>\n\n### KubeletSpecSpec\nKubeletSpecSpec holds the source of kubelet configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image | [string](#string) |  |  |\n| args | [string](#string) | repeated |  |\n| extra_mounts | [talos.resource.definitions.proto.Mount](#talos.resource.definitions.proto.Mount) | repeated |  |\n| expected_nodename | [string](#string) |  |  |\n| config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n| credential_provider_config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ManifestSpec\"></a>\n\n### ManifestSpec\nManifestSpec holds the Kubernetes resources spec.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| items | [SingleManifest](#talos.resource.definitions.k8s.SingleManifest) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.ManifestStatusSpec\"></a>\n\n### ManifestStatusSpec\nManifestStatusSpec describes manifest application status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| manifests_applied | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeAnnotationSpecSpec\"></a>\n\n### NodeAnnotationSpecSpec\nNodeAnnotationSpecSpec represents an annoation that's attached to a Talos node.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeIPConfigSpec\"></a>\n\n### NodeIPConfigSpec\nNodeIPConfigSpec holds the Node IP specification.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| valid_subnets | [string](#string) | repeated |  |\n| exclude_subnets | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeIPSpec\"></a>\n\n### NodeIPSpec\nNodeIPSpec holds the Node IP specification.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| addresses | [common.NetIP](#common.NetIP) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeLabelSpecSpec\"></a>\n\n### NodeLabelSpecSpec\nNodeLabelSpecSpec represents a label that's attached to a Talos node.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeStatusSpec\"></a>\n\n### NodeStatusSpec\nNodeStatusSpec describes Kubernetes NodeStatus.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| nodename | [string](#string) |  |  |\n| node_ready | [bool](#bool) |  |  |\n| unschedulable | [bool](#bool) |  |  |\n| labels | [NodeStatusSpec.LabelsEntry](#talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntry) | repeated |  |\n| annotations | [NodeStatusSpec.AnnotationsEntry](#talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntry) | repeated |  |\n| pod_cid_rs | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeStatusSpec.AnnotationsEntry\"></a>\n\n### NodeStatusSpec.AnnotationsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeStatusSpec.LabelsEntry\"></a>\n\n### NodeStatusSpec.LabelsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodeTaintSpecSpec\"></a>\n\n### NodeTaintSpecSpec\nNodeTaintSpecSpec represents a label that's attached to a Talos node.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| effect | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.NodenameSpec\"></a>\n\n### NodenameSpec\nNodenameSpec describes Kubernetes nodename.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| nodename | [string](#string) |  |  |\n| hostname_version | [string](#string) |  |  |\n| skip_node_registration | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.Resources\"></a>\n\n### Resources\nResources is a configuration of cpu and memory resources.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| requests | [Resources.RequestsEntry](#talos.resource.definitions.k8s.Resources.RequestsEntry) | repeated |  |\n| limits | [Resources.LimitsEntry](#talos.resource.definitions.k8s.Resources.LimitsEntry) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.Resources.LimitsEntry\"></a>\n\n### Resources.LimitsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.Resources.RequestsEntry\"></a>\n\n### Resources.RequestsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.SchedulerConfigSpec\"></a>\n\n### SchedulerConfigSpec\nSchedulerConfigSpec is configuration for kube-scheduler.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n| image | [string](#string) |  |  |\n| extra_args | [SchedulerConfigSpec.ExtraArgsEntry](#talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry) | repeated |  |\n| extra_volumes | [ExtraVolume](#talos.resource.definitions.k8s.ExtraVolume) | repeated |  |\n| environment_variables | [SchedulerConfigSpec.EnvironmentVariablesEntry](#talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry) | repeated |  |\n| resources | [Resources](#talos.resource.definitions.k8s.Resources) |  |  |\n| config | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.SchedulerConfigSpec.EnvironmentVariablesEntry\"></a>\n\n### SchedulerConfigSpec.EnvironmentVariablesEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.SchedulerConfigSpec.ExtraArgsEntry\"></a>\n\n### SchedulerConfigSpec.ExtraArgsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [ArgValues](#talos.resource.definitions.k8s.ArgValues) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.SecretsStatusSpec\"></a>\n\n### SecretsStatusSpec\nSecretsStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.SingleManifest\"></a>\n\n### SingleManifest\nSingleManifest is a single manifest.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| object | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.StaticPodServerStatusSpec\"></a>\n\n### StaticPodServerStatusSpec\nStaticPodServerStatusSpec describes static pod spec, it contains marshaled *v1.Pod spec.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| url | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.StaticPodSpec\"></a>\n\n### StaticPodSpec\nStaticPodSpec describes static pod spec, it contains marshaled *v1.Pod spec.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pod | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.k8s.StaticPodStatusSpec\"></a>\n\n### StaticPodStatusSpec\nStaticPodStatusSpec describes kubelet static pod status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| pod_status | [google.protobuf.Struct](#google.protobuf.Struct) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/kubeaccess/kubeaccess.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/kubeaccess/kubeaccess.proto\n\n\n\n<a name=\"talos.resource.definitions.kubeaccess.ConfigSpec\"></a>\n\n### ConfigSpec\nConfigSpec describes KubeSpan configuration..\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n| allowed_api_roles | [string](#string) | repeated |  |\n| allowed_kubernetes_namespaces | [string](#string) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/kubespan/kubespan.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/kubespan/kubespan.proto\n\n\n\n<a name=\"talos.resource.definitions.kubespan.ConfigSpec\"></a>\n\n### ConfigSpec\nConfigSpec describes KubeSpan configuration..\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n| cluster_id | [string](#string) |  |  |\n| shared_secret | [string](#string) |  |  |\n| force_routing | [bool](#bool) |  |  |\n| advertise_kubernetes_networks | [bool](#bool) |  |  |\n| mtu | [uint32](#uint32) |  |  |\n| endpoint_filters | [string](#string) | repeated |  |\n| harvest_extra_endpoints | [bool](#bool) |  |  |\n| extra_endpoints | [common.NetIPPort](#common.NetIPPort) | repeated |  |\n| exclude_advertised_networks | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.kubespan.EndpointSpec\"></a>\n\n### EndpointSpec\nEndpointSpec describes Endpoint state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| affiliate_id | [string](#string) |  |  |\n| endpoint | [common.NetIPPort](#common.NetIPPort) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.kubespan.IdentitySpec\"></a>\n\n### IdentitySpec\nIdentitySpec describes KubeSpan keys and address.\n\nNote: IdentitySpec is persisted on disk in the STATE partition,\nso YAML serialization should be kept backwards compatible.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| address | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| subnet | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| private_key | [string](#string) |  |  |\n| public_key | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.kubespan.PeerSpecSpec\"></a>\n\n### PeerSpecSpec\nPeerSpecSpec describes PeerSpec state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| address | [common.NetIP](#common.NetIP) |  |  |\n| allowed_ips | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| endpoints | [common.NetIPPort](#common.NetIPPort) | repeated |  |\n| label | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.kubespan.PeerStatusSpec\"></a>\n\n### PeerStatusSpec\nPeerStatusSpec describes PeerStatus state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint | [common.NetIPPort](#common.NetIPPort) |  |  |\n| label | [string](#string) |  |  |\n| state | [talos.resource.definitions.enums.KubespanPeerState](#talos.resource.definitions.enums.KubespanPeerState) |  |  |\n| receive_bytes | [int64](#int64) |  |  |\n| transmit_bytes | [int64](#int64) |  |  |\n| last_handshake_time | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n| last_used_endpoint | [common.NetIPPort](#common.NetIPPort) |  |  |\n| last_endpoint_change | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/runtime/runtime.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/runtime/runtime.proto\n\n\n\n<a name=\"talos.resource.definitions.runtime.APIServiceConfigSpec\"></a>\n\n### APIServiceConfigSpec\nAPIServiceConfigSpec describes configuration for Talos API service (apid).\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| listen_address | [string](#string) |  |  |\n| node_routing_disabled | [bool](#bool) |  |  |\n| readonly_role_mode | [bool](#bool) |  |  |\n| skip_verifying_client_cert | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.BootedEntrySpec\"></a>\n\n### BootedEntrySpec\nBootedEntrySpec describes the booted entry resource properties.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| booted_entry | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.DevicesStatusSpec\"></a>\n\n### DevicesStatusSpec\nDevicesStatusSpec is the spec for devices status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.DiagnosticSpec\"></a>\n\n### DiagnosticSpec\nDiagnosticSpec is the spec for devices status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| message | [string](#string) |  |  |\n| details | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.EnvironmentSpec\"></a>\n\n### EnvironmentSpec\nEnvironmentSpec describes the specification of Environment resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| variables | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.EventSinkConfigSpec\"></a>\n\n### EventSinkConfigSpec\nEventSinkConfigSpec describes configuration of Talos event log streaming.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.ExtensionServiceConfigFile\"></a>\n\n### ExtensionServiceConfigFile\nExtensionServiceConfigFile describes extensions service config files.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| content | [string](#string) |  |  |\n| mount_path | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.ExtensionServiceConfigSpec\"></a>\n\n### ExtensionServiceConfigSpec\nExtensionServiceConfigSpec describes status of rendered extensions service config files.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| files | [ExtensionServiceConfigFile](#talos.resource.definitions.runtime.ExtensionServiceConfigFile) | repeated |  |\n| environment | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.ExtensionServiceConfigStatusSpec\"></a>\n\n### ExtensionServiceConfigStatusSpec\nExtensionServiceConfigStatusSpec describes status of rendered extensions service config files.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| spec_version | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.KernelCmdlineSpec\"></a>\n\n### KernelCmdlineSpec\nKernelCmdlineSpec presents kernel command line (contents of /proc/cmdline).\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| cmdline | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.KernelModuleSpecSpec\"></a>\n\n### KernelModuleSpecSpec\nKernelModuleSpecSpec describes Linux kernel module to load.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| parameters | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.KernelParamSpecSpec\"></a>\n\n### KernelParamSpecSpec\nKernelParamSpecSpec describes status of the defined sysctls.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| value | [string](#string) |  |  |\n| ignore_errors | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.KernelParamStatusSpec\"></a>\n\n### KernelParamStatusSpec\nKernelParamStatusSpec describes status of the defined sysctls.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| current | [string](#string) |  |  |\n| default | [string](#string) |  |  |\n| unsupported | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.KmsgLogConfigSpec\"></a>\n\n### KmsgLogConfigSpec\nKmsgLogConfigSpec describes configuration for kmsg log streaming.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| destinations | [common.URL](#common.URL) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.LoadedKernelModuleSpec\"></a>\n\n### LoadedKernelModuleSpec\nLoadedKernelModuleSpec describes Linux kernel module to load.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| size | [int64](#int64) |  |  |\n| reference_count | [int64](#int64) |  |  |\n| dependencies | [string](#string) | repeated |  |\n| state | [string](#string) |  |  |\n| address | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MachineStatusSpec\"></a>\n\n### MachineStatusSpec\nMachineStatusSpec describes status of the defined sysctls.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| stage | [talos.resource.definitions.enums.RuntimeMachineStage](#talos.resource.definitions.enums.RuntimeMachineStage) |  |  |\n| status | [MachineStatusStatus](#talos.resource.definitions.runtime.MachineStatusStatus) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MachineStatusStatus\"></a>\n\n### MachineStatusStatus\nMachineStatusStatus describes machine current status at the stage.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ready | [bool](#bool) |  |  |\n| unmet_conditions | [UnmetCondition](#talos.resource.definitions.runtime.UnmetCondition) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MaintenanceServiceConfigSpec\"></a>\n\n### MaintenanceServiceConfigSpec\nMaintenanceServiceConfigSpec describes configuration for maintenance service API.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| listen_address | [string](#string) |  |  |\n| reachable_addresses | [common.NetIP](#common.NetIP) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MetaKeySpec\"></a>\n\n### MetaKeySpec\nMetaKeySpec describes status of the defined sysctls.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MetaLoadedSpec\"></a>\n\n### MetaLoadedSpec\nMetaLoadedSpec is the spec for meta loaded. The Done field is always true when resource exists.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| done | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.MountStatusSpec\"></a>\n\n### MountStatusSpec\nMountStatusSpec describes status of the defined sysctls.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| source | [string](#string) |  |  |\n| target | [string](#string) |  |  |\n| filesystem_type | [string](#string) |  |  |\n| options | [string](#string) | repeated |  |\n| encrypted | [bool](#bool) |  |  |\n| encryption_providers | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.OOMActionSpec\"></a>\n\n### OOMActionSpec\nOOMActionSpec describes the OOM action record resource properties.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| trigger_context | [string](#string) |  |  |\n| score | [double](#double) |  |  |\n| processes | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.PlatformMetadataSpec\"></a>\n\n### PlatformMetadataSpec\nPlatformMetadataSpec describes platform metadata properties.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| platform | [string](#string) |  |  |\n| hostname | [string](#string) |  |  |\n| region | [string](#string) |  |  |\n| zone | [string](#string) |  |  |\n| instance_type | [string](#string) |  |  |\n| instance_id | [string](#string) |  |  |\n| provider_id | [string](#string) |  |  |\n| spot | [bool](#bool) |  |  |\n| internal_dns | [string](#string) |  |  |\n| external_dns | [string](#string) |  |  |\n| tags | [PlatformMetadataSpec.TagsEntry](#talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntry) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.PlatformMetadataSpec.TagsEntry\"></a>\n\n### PlatformMetadataSpec.TagsEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.SBOMItemSpec\"></a>\n\n### SBOMItemSpec\nSBOMItemSpec describes the SBOM item resource properties.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| version | [string](#string) |  |  |\n| license | [string](#string) |  |  |\n| cp_es | [string](#string) | repeated |  |\n| pur_ls | [string](#string) | repeated |  |\n| extension | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.SecurityStateSpec\"></a>\n\n### SecurityStateSpec\nSecurityStateSpec describes the security state resource properties.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| secure_boot | [bool](#bool) |  |  |\n| uki_signing_key_fingerprint | [string](#string) |  |  |\n| pcr_signing_key_fingerprint | [string](#string) |  |  |\n| se_linux_state | [talos.resource.definitions.enums.RuntimeSELinuxState](#talos.resource.definitions.enums.RuntimeSELinuxState) |  |  |\n| booted_with_uki | [bool](#bool) |  |  |\n| fips_state | [talos.resource.definitions.enums.RuntimeFIPSState](#talos.resource.definitions.enums.RuntimeFIPSState) |  |  |\n| module_signature_enforced | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.UniqueMachineTokenSpec\"></a>\n\n### UniqueMachineTokenSpec\nUniqueMachineTokenSpec is the spec for the machine unique token. Token can be empty if machine wasn't assigned any.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| token | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.UnmetCondition\"></a>\n\n### UnmetCondition\nUnmetCondition is a failure which prevents machine from being ready at the stage.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| reason | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.WatchdogTimerConfigSpec\"></a>\n\n### WatchdogTimerConfigSpec\nWatchdogTimerConfigSpec describes configuration of watchdog timer.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| device | [string](#string) |  |  |\n| timeout | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.runtime.WatchdogTimerStatusSpec\"></a>\n\n### WatchdogTimerStatusSpec\nWatchdogTimerStatusSpec describes configuration of watchdog timer.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| device | [string](#string) |  |  |\n| timeout | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| feed_interval | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/network/network.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/network/network.proto\n\n\n\n<a name=\"talos.resource.definitions.network.AddressSpecSpec\"></a>\n\n### AddressSpecSpec\nAddressSpecSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| address | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| link_name | [string](#string) |  |  |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| scope | [talos.resource.definitions.enums.NethelpersScope](#talos.resource.definitions.enums.NethelpersScope) |  |  |\n| flags | [uint32](#uint32) |  |  |\n| announce_with_arp | [bool](#bool) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n| priority | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.AddressStatusSpec\"></a>\n\n### AddressStatusSpec\nAddressStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| address | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| local | [common.NetIP](#common.NetIP) |  |  |\n| broadcast | [common.NetIP](#common.NetIP) |  |  |\n| anycast | [common.NetIP](#common.NetIP) |  |  |\n| multicast | [common.NetIP](#common.NetIP) |  |  |\n| link_index | [uint32](#uint32) |  |  |\n| link_name | [string](#string) |  |  |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| scope | [talos.resource.definitions.enums.NethelpersScope](#talos.resource.definitions.enums.NethelpersScope) |  |  |\n| flags | [uint32](#uint32) |  |  |\n| priority | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.BondMasterSpec\"></a>\n\n### BondMasterSpec\nBondMasterSpec describes bond settings if Kind == \"bond\".\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mode | [talos.resource.definitions.enums.NethelpersBondMode](#talos.resource.definitions.enums.NethelpersBondMode) |  |  |\n| hash_policy | [talos.resource.definitions.enums.NethelpersBondXmitHashPolicy](#talos.resource.definitions.enums.NethelpersBondXmitHashPolicy) |  |  |\n| lacp_rate | [talos.resource.definitions.enums.NethelpersLACPRate](#talos.resource.definitions.enums.NethelpersLACPRate) |  |  |\n| arp_validate | [talos.resource.definitions.enums.NethelpersARPValidate](#talos.resource.definitions.enums.NethelpersARPValidate) |  |  |\n| arp_all_targets | [talos.resource.definitions.enums.NethelpersARPAllTargets](#talos.resource.definitions.enums.NethelpersARPAllTargets) |  |  |\n| primary_index | [uint32](#uint32) |  |  |\n| primary_reselect | [talos.resource.definitions.enums.NethelpersPrimaryReselect](#talos.resource.definitions.enums.NethelpersPrimaryReselect) |  |  |\n| fail_over_mac | [talos.resource.definitions.enums.NethelpersFailOverMAC](#talos.resource.definitions.enums.NethelpersFailOverMAC) |  |  |\n| ad_select | [talos.resource.definitions.enums.NethelpersADSelect](#talos.resource.definitions.enums.NethelpersADSelect) |  |  |\n| mii_mon | [uint32](#uint32) |  |  |\n| up_delay | [uint32](#uint32) |  |  |\n| down_delay | [uint32](#uint32) |  |  |\n| arp_interval | [uint32](#uint32) |  |  |\n| resend_igmp | [uint32](#uint32) |  |  |\n| min_links | [uint32](#uint32) |  |  |\n| lp_interval | [uint32](#uint32) |  |  |\n| packets_per_slave | [uint32](#uint32) |  |  |\n| num_peer_notif | [uint32](#uint32) |  |  |\n| tlb_dynamic_lb | [uint32](#uint32) |  |  |\n| all_slaves_active | [uint32](#uint32) |  |  |\n| use_carrier | [bool](#bool) |  |  |\n| ad_actor_sys_prio | [uint32](#uint32) |  |  |\n| ad_user_port_key | [uint32](#uint32) |  |  |\n| peer_notify_delay | [uint32](#uint32) |  |  |\n| arpip_targets | [common.NetIP](#common.NetIP) | repeated |  |\n| nsip6_targets | [common.NetIP](#common.NetIP) | repeated |  |\n| adlacp_active | [talos.resource.definitions.enums.NethelpersADLACPActive](#talos.resource.definitions.enums.NethelpersADLACPActive) |  |  |\n| missed_max | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.BondSlave\"></a>\n\n### BondSlave\nBondSlave contains a bond's master name and slave index.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| master_name | [string](#string) |  |  |\n| slave_index | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.BridgeMasterSpec\"></a>\n\n### BridgeMasterSpec\nBridgeMasterSpec describes bridge settings if Kind == \"bridge\".\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| stp | [STPSpec](#talos.resource.definitions.network.STPSpec) |  |  |\n| vlan | [BridgeVLANSpec](#talos.resource.definitions.network.BridgeVLANSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.BridgeSlave\"></a>\n\n### BridgeSlave\nBridgeSlave contains the name of the master bridge of a bridged interface\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| master_name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.BridgeVLANSpec\"></a>\n\n### BridgeVLANSpec\nBridgeVLANSpec describes VLAN settings of a bridge.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| filtering_enabled | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.ClientIdentifierSpec\"></a>\n\n### ClientIdentifierSpec\nClientIdentifierSpec is a shared DHCP4/DHCP6 client identifier spec.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| client_identifier | [talos.resource.definitions.enums.NethelpersClientIdentifier](#talos.resource.definitions.enums.NethelpersClientIdentifier) |  |  |\n| duid_raw_hex | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.DHCP4OperatorSpec\"></a>\n\n### DHCP4OperatorSpec\nDHCP4OperatorSpec describes DHCP4 operator options.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| route_metric | [uint32](#uint32) |  |  |\n| skip_hostname_request | [bool](#bool) |  |  |\n| client_identifier | [ClientIdentifierSpec](#talos.resource.definitions.network.ClientIdentifierSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.DHCP6OperatorSpec\"></a>\n\n### DHCP6OperatorSpec\nDHCP6OperatorSpec describes DHCP6 operator options.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| route_metric | [uint32](#uint32) |  |  |\n| skip_hostname_request | [bool](#bool) |  |  |\n| client_identifier | [ClientIdentifierSpec](#talos.resource.definitions.network.ClientIdentifierSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.DNSResolveCacheSpec\"></a>\n\n### DNSResolveCacheSpec\nDNSResolveCacheSpec describes DNS servers status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| status | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetChannelsSpec\"></a>\n\n### EthernetChannelsSpec\nEthernetChannelsSpec describes config of Ethernet channels.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rx | [uint32](#uint32) |  |  |\n| tx | [uint32](#uint32) |  |  |\n| other | [uint32](#uint32) |  |  |\n| combined | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetChannelsStatus\"></a>\n\n### EthernetChannelsStatus\nEthernetChannelsStatus describes status of Ethernet channels.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rx_max | [uint32](#uint32) |  |  |\n| tx_max | [uint32](#uint32) |  |  |\n| other_max | [uint32](#uint32) |  |  |\n| combined_max | [uint32](#uint32) |  |  |\n| rx | [uint32](#uint32) |  |  |\n| tx | [uint32](#uint32) |  |  |\n| other | [uint32](#uint32) |  |  |\n| combined | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetFeatureStatus\"></a>\n\n### EthernetFeatureStatus\nEthernetFeatureStatus describes status of Ethernet features.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| status | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetRingsSpec\"></a>\n\n### EthernetRingsSpec\nEthernetRingsSpec describes config of Ethernet rings.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rx | [uint32](#uint32) |  |  |\n| rx_mini | [uint32](#uint32) |  |  |\n| rx_jumbo | [uint32](#uint32) |  |  |\n| tx | [uint32](#uint32) |  |  |\n| rx_buf_len | [uint32](#uint32) |  |  |\n| cqe_size | [uint32](#uint32) |  |  |\n| tx_push | [bool](#bool) |  |  |\n| rx_push | [bool](#bool) |  |  |\n| tx_push_buf_len | [uint32](#uint32) |  |  |\n| tcp_data_split | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetRingsStatus\"></a>\n\n### EthernetRingsStatus\nEthernetRingsStatus describes status of Ethernet rings.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rx_max | [uint32](#uint32) |  |  |\n| rx_mini_max | [uint32](#uint32) |  |  |\n| rx_jumbo_max | [uint32](#uint32) |  |  |\n| tx_max | [uint32](#uint32) |  |  |\n| tx_push_buf_len_max | [uint32](#uint32) |  |  |\n| rx | [uint32](#uint32) |  |  |\n| rx_mini | [uint32](#uint32) |  |  |\n| rx_jumbo | [uint32](#uint32) |  |  |\n| tx | [uint32](#uint32) |  |  |\n| rx_buf_len | [uint32](#uint32) |  |  |\n| cqe_size | [uint32](#uint32) |  |  |\n| tx_push | [bool](#bool) |  |  |\n| rx_push | [bool](#bool) |  |  |\n| tx_push_buf_len | [uint32](#uint32) |  |  |\n| tcp_data_split | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetSpecSpec\"></a>\n\n### EthernetSpecSpec\nEthernetSpecSpec describes config of Ethernet link.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| rings | [EthernetRingsSpec](#talos.resource.definitions.network.EthernetRingsSpec) |  |  |\n| features | [EthernetSpecSpec.FeaturesEntry](#talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntry) | repeated |  |\n| channels | [EthernetChannelsSpec](#talos.resource.definitions.network.EthernetChannelsSpec) |  |  |\n| wake_on_lan | [talos.resource.definitions.enums.NethelpersWOLMode](#talos.resource.definitions.enums.NethelpersWOLMode) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetSpecSpec.FeaturesEntry\"></a>\n\n### EthernetSpecSpec.FeaturesEntry\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| key | [string](#string) |  |  |\n| value | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.EthernetStatusSpec\"></a>\n\n### EthernetStatusSpec\nEthernetStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| link_state | [bool](#bool) |  |  |\n| speed_megabits | [int64](#int64) |  |  |\n| port | [talos.resource.definitions.enums.NethelpersPort](#talos.resource.definitions.enums.NethelpersPort) |  |  |\n| duplex | [talos.resource.definitions.enums.NethelpersDuplex](#talos.resource.definitions.enums.NethelpersDuplex) |  |  |\n| our_modes | [string](#string) | repeated |  |\n| peer_modes | [string](#string) | repeated |  |\n| rings | [EthernetRingsStatus](#talos.resource.definitions.network.EthernetRingsStatus) |  |  |\n| features | [EthernetFeatureStatus](#talos.resource.definitions.network.EthernetFeatureStatus) | repeated |  |\n| channels | [EthernetChannelsStatus](#talos.resource.definitions.network.EthernetChannelsStatus) |  |  |\n| wake_on_lan | [talos.resource.definitions.enums.NethelpersWOLMode](#talos.resource.definitions.enums.NethelpersWOLMode) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.HardwareAddrSpec\"></a>\n\n### HardwareAddrSpec\nHardwareAddrSpec describes spec for the link.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| hardware_addr | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.HostDNSConfigSpec\"></a>\n\n### HostDNSConfigSpec\nHostDNSConfigSpec describes host DNS config.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n| listen_addresses | [common.NetIPPort](#common.NetIPPort) | repeated |  |\n| service_host_dns_address | [common.NetIP](#common.NetIP) |  |  |\n| resolve_member_names | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.HostnameSpecSpec\"></a>\n\n### HostnameSpecSpec\nHostnameSpecSpec describes node hostname.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostname | [string](#string) |  |  |\n| domainname | [string](#string) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.HostnameStatusSpec\"></a>\n\n### HostnameStatusSpec\nHostnameStatusSpec describes node hostname.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| hostname | [string](#string) |  |  |\n| domainname | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.LinkAliasSpecSpec\"></a>\n\n### LinkAliasSpecSpec\nLinkAliasSpecSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| alias | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.LinkRefreshSpec\"></a>\n\n### LinkRefreshSpec\nLinkRefreshSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| generation | [int64](#int64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.LinkSpecSpec\"></a>\n\n### LinkSpecSpec\nLinkSpecSpec describes spec for the link.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| logical | [bool](#bool) |  |  |\n| up | [bool](#bool) |  |  |\n| mtu | [uint32](#uint32) |  |  |\n| kind | [string](#string) |  |  |\n| type | [talos.resource.definitions.enums.NethelpersLinkType](#talos.resource.definitions.enums.NethelpersLinkType) |  |  |\n| parent_name | [string](#string) |  |  |\n| bond_slave | [BondSlave](#talos.resource.definitions.network.BondSlave) |  |  |\n| bridge_slave | [BridgeSlave](#talos.resource.definitions.network.BridgeSlave) |  |  |\n| vlan | [VLANSpec](#talos.resource.definitions.network.VLANSpec) |  |  |\n| bond_master | [BondMasterSpec](#talos.resource.definitions.network.BondMasterSpec) |  |  |\n| bridge_master | [BridgeMasterSpec](#talos.resource.definitions.network.BridgeMasterSpec) |  |  |\n| wireguard | [WireguardSpec](#talos.resource.definitions.network.WireguardSpec) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n| hardware_address | [bytes](#bytes) |  |  |\n| multicast | [bool](#bool) |  |  |\n| vrf_master | [VRFMasterSpec](#talos.resource.definitions.network.VRFMasterSpec) |  |  |\n| vrf_slave | [VRFSlave](#talos.resource.definitions.network.VRFSlave) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.LinkStatusSpec\"></a>\n\n### LinkStatusSpec\nLinkStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| index | [uint32](#uint32) |  |  |\n| type | [talos.resource.definitions.enums.NethelpersLinkType](#talos.resource.definitions.enums.NethelpersLinkType) |  |  |\n| link_index | [uint32](#uint32) |  |  |\n| flags | [uint32](#uint32) |  |  |\n| hardware_addr | [bytes](#bytes) |  |  |\n| broadcast_addr | [bytes](#bytes) |  |  |\n| mtu | [uint32](#uint32) |  |  |\n| queue_disc | [string](#string) |  |  |\n| master_index | [uint32](#uint32) |  |  |\n| operational_state | [talos.resource.definitions.enums.NethelpersOperationalState](#talos.resource.definitions.enums.NethelpersOperationalState) |  |  |\n| kind | [string](#string) |  |  |\n| slave_kind | [string](#string) |  |  |\n| bus_path | [string](#string) |  |  |\n| pciid | [string](#string) |  |  |\n| driver | [string](#string) |  |  |\n| driver_version | [string](#string) |  |  |\n| firmware_version | [string](#string) |  |  |\n| product_id | [string](#string) |  |  |\n| vendor_id | [string](#string) |  |  |\n| product | [string](#string) |  |  |\n| vendor | [string](#string) |  |  |\n| link_state | [bool](#bool) |  |  |\n| speed_megabits | [int64](#int64) |  |  |\n| port | [talos.resource.definitions.enums.NethelpersPort](#talos.resource.definitions.enums.NethelpersPort) |  |  |\n| duplex | [talos.resource.definitions.enums.NethelpersDuplex](#talos.resource.definitions.enums.NethelpersDuplex) |  |  |\n| vlan | [VLANSpec](#talos.resource.definitions.network.VLANSpec) |  |  |\n| bridge_master | [BridgeMasterSpec](#talos.resource.definitions.network.BridgeMasterSpec) |  |  |\n| bond_master | [BondMasterSpec](#talos.resource.definitions.network.BondMasterSpec) |  |  |\n| wireguard | [WireguardSpec](#talos.resource.definitions.network.WireguardSpec) |  |  |\n| permanent_addr | [bytes](#bytes) |  |  |\n| alias | [string](#string) |  |  |\n| alt_names | [string](#string) | repeated |  |\n| vrf_master | [VRFMasterSpec](#talos.resource.definitions.network.VRFMasterSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesAddressMatch\"></a>\n\n### NfTablesAddressMatch\nNfTablesAddressMatch describes the match on the IP address.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| include_subnets | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| exclude_subnets | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| invert | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesChainSpec\"></a>\n\n### NfTablesChainSpec\nNfTablesChainSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| type | [string](#string) |  |  |\n| hook | [talos.resource.definitions.enums.NethelpersNfTablesChainHook](#talos.resource.definitions.enums.NethelpersNfTablesChainHook) |  |  |\n| priority | [talos.resource.definitions.enums.NethelpersNfTablesChainPriority](#talos.resource.definitions.enums.NethelpersNfTablesChainPriority) |  |  |\n| rules | [NfTablesRule](#talos.resource.definitions.network.NfTablesRule) | repeated |  |\n| policy | [talos.resource.definitions.enums.NethelpersNfTablesVerdict](#talos.resource.definitions.enums.NethelpersNfTablesVerdict) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesClampMSS\"></a>\n\n### NfTablesClampMSS\nNfTablesClampMSS describes the TCP MSS clamping operation.\n\nMSS is limited by the `MaxMTU` so that:\n- IPv4: MSS = MaxMTU - 40\n- IPv6: MSS = MaxMTU - 60.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mtu | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesConntrackStateMatch\"></a>\n\n### NfTablesConntrackStateMatch\nNfTablesConntrackStateMatch describes the match on the connection tracking state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| states | [talos.resource.definitions.enums.NethelpersConntrackState](#talos.resource.definitions.enums.NethelpersConntrackState) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesICMPTypeMatch\"></a>\n\n### NfTablesICMPTypeMatch\nNfTablesICMPTypeMatch describes the match on the ICMP type.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| types | [talos.resource.definitions.enums.NethelpersICMPType](#talos.resource.definitions.enums.NethelpersICMPType) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesIfNameMatch\"></a>\n\n### NfTablesIfNameMatch\nNfTablesIfNameMatch describes the match on the interface name.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| operator | [talos.resource.definitions.enums.NethelpersMatchOperator](#talos.resource.definitions.enums.NethelpersMatchOperator) |  |  |\n| interface_names | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesLayer4Match\"></a>\n\n### NfTablesLayer4Match\nNfTablesLayer4Match describes the match on the transport layer protocol.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| protocol | [talos.resource.definitions.enums.NethelpersProtocol](#talos.resource.definitions.enums.NethelpersProtocol) |  |  |\n| match_source_port | [NfTablesPortMatch](#talos.resource.definitions.network.NfTablesPortMatch) |  |  |\n| match_destination_port | [NfTablesPortMatch](#talos.resource.definitions.network.NfTablesPortMatch) |  |  |\n| match_icmp_type | [NfTablesICMPTypeMatch](#talos.resource.definitions.network.NfTablesICMPTypeMatch) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesLimitMatch\"></a>\n\n### NfTablesLimitMatch\nNfTablesLimitMatch describes the match on the packet rate.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| packet_rate_per_second | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesMark\"></a>\n\n### NfTablesMark\nNfTablesMark encodes packet mark match/update operation.\n\nWhen used as a match computes the following condition:\n(mark & mask) ^ xor == value\n\nWhen used as an update computes the following operation:\nmark = (mark & mask) ^ xor.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mask | [uint32](#uint32) |  |  |\n| xor | [uint32](#uint32) |  |  |\n| value | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesPortMatch\"></a>\n\n### NfTablesPortMatch\nNfTablesPortMatch describes the match on the transport layer port.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ranges | [PortRange](#talos.resource.definitions.network.PortRange) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NfTablesRule\"></a>\n\n### NfTablesRule\nNfTablesRule describes a single rule in the nftables chain.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| match_o_if_name | [NfTablesIfNameMatch](#talos.resource.definitions.network.NfTablesIfNameMatch) |  |  |\n| verdict | [talos.resource.definitions.enums.NethelpersNfTablesVerdict](#talos.resource.definitions.enums.NethelpersNfTablesVerdict) |  |  |\n| match_mark | [NfTablesMark](#talos.resource.definitions.network.NfTablesMark) |  |  |\n| set_mark | [NfTablesMark](#talos.resource.definitions.network.NfTablesMark) |  |  |\n| match_source_address | [NfTablesAddressMatch](#talos.resource.definitions.network.NfTablesAddressMatch) |  |  |\n| match_destination_address | [NfTablesAddressMatch](#talos.resource.definitions.network.NfTablesAddressMatch) |  |  |\n| match_layer4 | [NfTablesLayer4Match](#talos.resource.definitions.network.NfTablesLayer4Match) |  |  |\n| match_i_if_name | [NfTablesIfNameMatch](#talos.resource.definitions.network.NfTablesIfNameMatch) |  |  |\n| clamp_mss | [NfTablesClampMSS](#talos.resource.definitions.network.NfTablesClampMSS) |  |  |\n| match_limit | [NfTablesLimitMatch](#talos.resource.definitions.network.NfTablesLimitMatch) |  |  |\n| match_conntrack_state | [NfTablesConntrackStateMatch](#talos.resource.definitions.network.NfTablesConntrackStateMatch) |  |  |\n| anon_counter | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NodeAddressFilterSpec\"></a>\n\n### NodeAddressFilterSpec\nNodeAddressFilterSpec describes a filter for NodeAddresses.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| include_subnets | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| exclude_subnets | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NodeAddressSortAlgorithmSpec\"></a>\n\n### NodeAddressSortAlgorithmSpec\nNodeAddressSortAlgorithmSpec describes a filter for NodeAddresses.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| algorithm | [talos.resource.definitions.enums.NethelpersAddressSortAlgorithm](#talos.resource.definitions.enums.NethelpersAddressSortAlgorithm) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.NodeAddressSpec\"></a>\n\n### NodeAddressSpec\nNodeAddressSpec describes a set of node addresses.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| addresses | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n| sort_algorithm | [talos.resource.definitions.enums.NethelpersAddressSortAlgorithm](#talos.resource.definitions.enums.NethelpersAddressSortAlgorithm) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.OperatorSpecSpec\"></a>\n\n### OperatorSpecSpec\nOperatorSpecSpec describes operator specification.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| operator | [talos.resource.definitions.enums.NetworkOperator](#talos.resource.definitions.enums.NetworkOperator) |  |  |\n| link_name | [string](#string) |  |  |\n| require_up | [bool](#bool) |  |  |\n| dhcp4 | [DHCP4OperatorSpec](#talos.resource.definitions.network.DHCP4OperatorSpec) |  |  |\n| dhcp6 | [DHCP6OperatorSpec](#talos.resource.definitions.network.DHCP6OperatorSpec) |  |  |\n| vip | [VIPOperatorSpec](#talos.resource.definitions.network.VIPOperatorSpec) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.PlatformConfigSpec\"></a>\n\n### PlatformConfigSpec\nPlatformConfigSpec describes platform network configuration.\n\nThis structure is marshaled to STATE partition to persist cached network configuration across\nreboots.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| addresses | [AddressSpecSpec](#talos.resource.definitions.network.AddressSpecSpec) | repeated |  |\n| links | [LinkSpecSpec](#talos.resource.definitions.network.LinkSpecSpec) | repeated |  |\n| routes | [RouteSpecSpec](#talos.resource.definitions.network.RouteSpecSpec) | repeated |  |\n| hostnames | [HostnameSpecSpec](#talos.resource.definitions.network.HostnameSpecSpec) | repeated |  |\n| resolvers | [ResolverSpecSpec](#talos.resource.definitions.network.ResolverSpecSpec) | repeated |  |\n| time_servers | [TimeServerSpecSpec](#talos.resource.definitions.network.TimeServerSpecSpec) | repeated |  |\n| operators | [OperatorSpecSpec](#talos.resource.definitions.network.OperatorSpecSpec) | repeated |  |\n| external_ips | [common.NetIP](#common.NetIP) | repeated |  |\n| probes | [ProbeSpecSpec](#talos.resource.definitions.network.ProbeSpecSpec) | repeated |  |\n| metadata | [talos.resource.definitions.runtime.PlatformMetadataSpec](#talos.resource.definitions.runtime.PlatformMetadataSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.PortRange\"></a>\n\n### PortRange\nPortRange describes a range of ports.\n\nRange is [lo, hi].\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| lo | [uint32](#uint32) |  |  |\n| hi | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.ProbeSpecSpec\"></a>\n\n### ProbeSpecSpec\nProbeSpecSpec describes the Probe.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| interval | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| failure_threshold | [int64](#int64) |  |  |\n| tcp | [TCPProbeSpec](#talos.resource.definitions.network.TCPProbeSpec) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.ProbeStatusSpec\"></a>\n\n### ProbeStatusSpec\nProbeStatusSpec describes the Probe.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| success | [bool](#bool) |  |  |\n| last_error | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.ResolverSpecSpec\"></a>\n\n### ResolverSpecSpec\nResolverSpecSpec describes DNS resolvers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| dns_servers | [common.NetIP](#common.NetIP) | repeated |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n| search_domains | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.ResolverStatusSpec\"></a>\n\n### ResolverStatusSpec\nResolverStatusSpec describes DNS resolvers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| dns_servers | [common.NetIP](#common.NetIP) | repeated |  |\n| search_domains | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.RouteSpecSpec\"></a>\n\n### RouteSpecSpec\nRouteSpecSpec describes the route.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| destination | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| source | [common.NetIP](#common.NetIP) |  |  |\n| gateway | [common.NetIP](#common.NetIP) |  |  |\n| out_link_name | [string](#string) |  |  |\n| table | [talos.resource.definitions.enums.NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable) |  |  |\n| priority | [uint32](#uint32) |  |  |\n| scope | [talos.resource.definitions.enums.NethelpersScope](#talos.resource.definitions.enums.NethelpersScope) |  |  |\n| type | [talos.resource.definitions.enums.NethelpersRouteType](#talos.resource.definitions.enums.NethelpersRouteType) |  |  |\n| flags | [uint32](#uint32) |  |  |\n| protocol | [talos.resource.definitions.enums.NethelpersRouteProtocol](#talos.resource.definitions.enums.NethelpersRouteProtocol) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n| mtu | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.RouteStatusSpec\"></a>\n\n### RouteStatusSpec\nRouteStatusSpec describes status of rendered secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| destination | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| source | [common.NetIP](#common.NetIP) |  |  |\n| gateway | [common.NetIP](#common.NetIP) |  |  |\n| out_link_index | [uint32](#uint32) |  |  |\n| out_link_name | [string](#string) |  |  |\n| table | [talos.resource.definitions.enums.NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable) |  |  |\n| priority | [uint32](#uint32) |  |  |\n| scope | [talos.resource.definitions.enums.NethelpersScope](#talos.resource.definitions.enums.NethelpersScope) |  |  |\n| type | [talos.resource.definitions.enums.NethelpersRouteType](#talos.resource.definitions.enums.NethelpersRouteType) |  |  |\n| flags | [uint32](#uint32) |  |  |\n| protocol | [talos.resource.definitions.enums.NethelpersRouteProtocol](#talos.resource.definitions.enums.NethelpersRouteProtocol) |  |  |\n| mtu | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.RoutingRuleSpecSpec\"></a>\n\n### RoutingRuleSpecSpec\nRoutingRuleSpecSpec describes the routing rule.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| src | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| dst | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| table | [talos.resource.definitions.enums.NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable) |  |  |\n| priority | [uint32](#uint32) |  |  |\n| action | [talos.resource.definitions.enums.NethelpersRoutingRuleAction](#talos.resource.definitions.enums.NethelpersRoutingRuleAction) |  |  |\n| iif_name | [string](#string) |  |  |\n| oif_name | [string](#string) |  |  |\n| fw_mark | [uint32](#uint32) |  |  |\n| fw_mask | [uint32](#uint32) |  |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.RoutingRuleStatusSpec\"></a>\n\n### RoutingRuleStatusSpec\nRoutingRuleStatusSpec describes the observed routing rule state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| family | [talos.resource.definitions.enums.NethelpersFamily](#talos.resource.definitions.enums.NethelpersFamily) |  |  |\n| src | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| dst | [common.NetIPPrefix](#common.NetIPPrefix) |  |  |\n| table | [talos.resource.definitions.enums.NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable) |  |  |\n| priority | [uint32](#uint32) |  |  |\n| action | [talos.resource.definitions.enums.NethelpersRoutingRuleAction](#talos.resource.definitions.enums.NethelpersRoutingRuleAction) |  |  |\n| iif_name | [string](#string) |  |  |\n| oif_name | [string](#string) |  |  |\n| fw_mark | [uint32](#uint32) |  |  |\n| fw_mask | [uint32](#uint32) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.STPSpec\"></a>\n\n### STPSpec\nSTPSpec describes Spanning Tree Protocol (STP) settings of a bridge.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| enabled | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.StatusSpec\"></a>\n\n### StatusSpec\nStatusSpec describes network state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| address_ready | [bool](#bool) |  |  |\n| connectivity_ready | [bool](#bool) |  |  |\n| hostname_ready | [bool](#bool) |  |  |\n| etc_files_ready | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.TCPProbeSpec\"></a>\n\n### TCPProbeSpec\nTCPProbeSpec describes the TCP Probe.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint | [string](#string) |  |  |\n| timeout | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.TimeServerSpecSpec\"></a>\n\n### TimeServerSpecSpec\nTimeServerSpecSpec describes NTP servers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ntp_servers | [string](#string) | repeated |  |\n| config_layer | [talos.resource.definitions.enums.NetworkConfigLayer](#talos.resource.definitions.enums.NetworkConfigLayer) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.TimeServerStatusSpec\"></a>\n\n### TimeServerStatusSpec\nTimeServerStatusSpec describes NTP servers.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ntp_servers | [string](#string) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VIPEquinixMetalSpec\"></a>\n\n### VIPEquinixMetalSpec\nVIPEquinixMetalSpec describes virtual (elastic) IP settings for Equinix Metal.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| project_id | [string](#string) |  |  |\n| device_id | [string](#string) |  |  |\n| api_token | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VIPHCloudSpec\"></a>\n\n### VIPHCloudSpec\nVIPHCloudSpec describes virtual (elastic) IP settings for Hetzner Cloud.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| device_id | [int64](#int64) |  |  |\n| network_id | [int64](#int64) |  |  |\n| api_token | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VIPOperatorSpec\"></a>\n\n### VIPOperatorSpec\nVIPOperatorSpec describes virtual IP operator options.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ip | [common.NetIP](#common.NetIP) |  |  |\n| gratuitous_arp | [bool](#bool) |  |  |\n| equinix_metal | [VIPEquinixMetalSpec](#talos.resource.definitions.network.VIPEquinixMetalSpec) |  |  |\n| h_cloud | [VIPHCloudSpec](#talos.resource.definitions.network.VIPHCloudSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VLANSpec\"></a>\n\n### VLANSpec\nVLANSpec describes VLAN settings if Kind == \"vlan\".\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| vid | [uint32](#uint32) |  |  |\n| protocol | [talos.resource.definitions.enums.NethelpersVLANProtocol](#talos.resource.definitions.enums.NethelpersVLANProtocol) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VRFMasterSpec\"></a>\n\n### VRFMasterSpec\nVRFMasterSpec describes vrf settings if Kind == \"vrf\".\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| table | [talos.resource.definitions.enums.NethelpersRoutingTable](#talos.resource.definitions.enums.NethelpersRoutingTable) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.VRFSlave\"></a>\n\n### VRFSlave\nVRFSlave contains the name of the master vrf for an interface\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| master_name | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.WireguardPeer\"></a>\n\n### WireguardPeer\nWireguardPeer describes a single peer.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| public_key | [string](#string) |  |  |\n| preshared_key | [string](#string) |  |  |\n| endpoint | [string](#string) |  |  |\n| persistent_keepalive_interval | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| allowed_ips | [common.NetIPPrefix](#common.NetIPPrefix) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.network.WireguardSpec\"></a>\n\n### WireguardSpec\nWireguardSpec describes Wireguard settings if Kind == \"wireguard\".\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| private_key | [string](#string) |  |  |\n| public_key | [string](#string) |  |  |\n| listen_port | [int64](#int64) |  |  |\n| firewall_mark | [int64](#int64) |  |  |\n| peers | [WireguardPeer](#talos.resource.definitions.network.WireguardPeer) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/perf/perf.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/perf/perf.proto\n\n\n\n<a name=\"talos.resource.definitions.perf.CPUSpec\"></a>\n\n### CPUSpec\nCPUSpec represents the last CPU stats snapshot.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| cpu | [CPUStat](#talos.resource.definitions.perf.CPUStat) | repeated |  |\n| cpu_total | [CPUStat](#talos.resource.definitions.perf.CPUStat) |  |  |\n| irq_total | [uint64](#uint64) |  |  |\n| context_switches | [uint64](#uint64) |  |  |\n| process_created | [uint64](#uint64) |  |  |\n| process_running | [uint64](#uint64) |  |  |\n| process_blocked | [uint64](#uint64) |  |  |\n| soft_irq_total | [uint64](#uint64) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.perf.CPUStat\"></a>\n\n### CPUStat\nCPUStat represents a single cpu stat.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| user | [double](#double) |  |  |\n| nice | [double](#double) |  |  |\n| system | [double](#double) |  |  |\n| idle | [double](#double) |  |  |\n| iowait | [double](#double) |  |  |\n| irq | [double](#double) |  |  |\n| soft_irq | [double](#double) |  |  |\n| steal | [double](#double) |  |  |\n| guest | [double](#double) |  |  |\n| guest_nice | [double](#double) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.perf.MemorySpec\"></a>\n\n### MemorySpec\nMemorySpec represents the last Memory stats snapshot.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| mem_total | [uint64](#uint64) |  |  |\n| mem_used | [uint64](#uint64) |  |  |\n| mem_available | [uint64](#uint64) |  |  |\n| buffers | [uint64](#uint64) |  |  |\n| cached | [uint64](#uint64) |  |  |\n| swap_cached | [uint64](#uint64) |  |  |\n| active | [uint64](#uint64) |  |  |\n| inactive | [uint64](#uint64) |  |  |\n| active_anon | [uint64](#uint64) |  |  |\n| inactive_anon | [uint64](#uint64) |  |  |\n| active_file | [uint64](#uint64) |  |  |\n| inactive_file | [uint64](#uint64) |  |  |\n| unevictable | [uint64](#uint64) |  |  |\n| mlocked | [uint64](#uint64) |  |  |\n| swap_total | [uint64](#uint64) |  |  |\n| swap_free | [uint64](#uint64) |  |  |\n| dirty | [uint64](#uint64) |  |  |\n| writeback | [uint64](#uint64) |  |  |\n| anon_pages | [uint64](#uint64) |  |  |\n| mapped | [uint64](#uint64) |  |  |\n| shmem | [uint64](#uint64) |  |  |\n| slab | [uint64](#uint64) |  |  |\n| s_reclaimable | [uint64](#uint64) |  |  |\n| s_unreclaim | [uint64](#uint64) |  |  |\n| kernel_stack | [uint64](#uint64) |  |  |\n| page_tables | [uint64](#uint64) |  |  |\n| nf_sunstable | [uint64](#uint64) |  |  |\n| bounce | [uint64](#uint64) |  |  |\n| writeback_tmp | [uint64](#uint64) |  |  |\n| commit_limit | [uint64](#uint64) |  |  |\n| committed_as | [uint64](#uint64) |  |  |\n| vmalloc_total | [uint64](#uint64) |  |  |\n| vmalloc_used | [uint64](#uint64) |  |  |\n| vmalloc_chunk | [uint64](#uint64) |  |  |\n| hardware_corrupted | [uint64](#uint64) |  |  |\n| anon_huge_pages | [uint64](#uint64) |  |  |\n| shmem_huge_pages | [uint64](#uint64) |  |  |\n| shmem_pmd_mapped | [uint64](#uint64) |  |  |\n| cma_total | [uint64](#uint64) |  |  |\n| cma_free | [uint64](#uint64) |  |  |\n| huge_pages_total | [uint64](#uint64) |  |  |\n| huge_pages_free | [uint64](#uint64) |  |  |\n| huge_pages_rsvd | [uint64](#uint64) |  |  |\n| huge_pages_surp | [uint64](#uint64) |  |  |\n| hugepagesize | [uint64](#uint64) |  |  |\n| direct_map4k | [uint64](#uint64) |  |  |\n| direct_map2m | [uint64](#uint64) |  |  |\n| direct_map1g | [uint64](#uint64) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/secrets/secrets.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/secrets/secrets.proto\n\n\n\n<a name=\"talos.resource.definitions.secrets.APICertsSpec\"></a>\n\n### APICertsSpec\nAPICertsSpec describes etcd certs secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| client | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| server | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| accepted_c_as | [common.PEMEncodedCertificate](#common.PEMEncodedCertificate) | repeated |  |\n| skip_verifying_client_cert | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.CertSANSpec\"></a>\n\n### CertSANSpec\nCertSANSpec describes fields of the cert SANs.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| i_ps | [common.NetIP](#common.NetIP) | repeated |  |\n| dns_names | [string](#string) | repeated |  |\n| fqdn | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.EncryptionSaltSpec\"></a>\n\n### EncryptionSaltSpec\nEncryptionSaltSpec describes the salt.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| disk_salt | [bytes](#bytes) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.EtcdCertsSpec\"></a>\n\n### EtcdCertsSpec\nEtcdCertsSpec describes etcd certs secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| etcd | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| etcd_peer | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| etcd_admin | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| etcd_api_server | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.EtcdRootSpec\"></a>\n\n### EtcdRootSpec\nEtcdRootSpec describes etcd CA secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| etcd_ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.KubeletSpec\"></a>\n\n### KubeletSpec\nKubeletSpec describes root Kubernetes secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| endpoint | [common.URL](#common.URL) |  |  |\n| bootstrap_token_id | [string](#string) |  |  |\n| bootstrap_token_secret | [string](#string) |  |  |\n| accepted_c_as | [common.PEMEncodedCertificate](#common.PEMEncodedCertificate) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.KubernetesCertsSpec\"></a>\n\n### KubernetesCertsSpec\nKubernetesCertsSpec describes generated Kubernetes certificates.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| scheduler_kubeconfig | [string](#string) |  |  |\n| controller_manager_kubeconfig | [string](#string) |  |  |\n| localhost_admin_kubeconfig | [string](#string) |  |  |\n| admin_kubeconfig | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.KubernetesDynamicCertsSpec\"></a>\n\n### KubernetesDynamicCertsSpec\nKubernetesDynamicCertsSpec describes generated KubernetesCerts certificates.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| api_server | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| api_server_kubelet_client | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| front_proxy | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.KubernetesRootSpec\"></a>\n\n### KubernetesRootSpec\nKubernetesRootSpec describes root Kubernetes secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| name | [string](#string) |  |  |\n| endpoint | [common.URL](#common.URL) |  |  |\n| local_endpoint | [common.URL](#common.URL) |  |  |\n| cert_sa_ns | [string](#string) | repeated |  |\n| dns_domain | [string](#string) |  |  |\n| issuing_ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| service_account | [common.PEMEncodedKey](#common.PEMEncodedKey) |  |  |\n| aggregator_ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| aescbc_encryption_secret | [string](#string) |  |  |\n| bootstrap_token_id | [string](#string) |  |  |\n| bootstrap_token_secret | [string](#string) |  |  |\n| secretbox_encryption_secret | [string](#string) |  |  |\n| api_server_ips | [common.NetIP](#common.NetIP) | repeated |  |\n| accepted_c_as | [common.PEMEncodedCertificate](#common.PEMEncodedCertificate) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.MaintenanceRootSpec\"></a>\n\n### MaintenanceRootSpec\nMaintenanceRootSpec describes maintenance service CA.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.OSRootSpec\"></a>\n\n### OSRootSpec\nOSRootSpec describes operating system CA.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| issuing_ca | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| cert_sani_ps | [common.NetIP](#common.NetIP) | repeated |  |\n| cert_sandns_names | [string](#string) | repeated |  |\n| token | [string](#string) |  |  |\n| accepted_c_as | [common.PEMEncodedCertificate](#common.PEMEncodedCertificate) | repeated |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.secrets.TrustdCertsSpec\"></a>\n\n### TrustdCertsSpec\nTrustdCertsSpec describes etcd certs secrets.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| server | [common.PEMEncodedCertificateAndKey](#common.PEMEncodedCertificateAndKey) |  |  |\n| accepted_c_as | [common.PEMEncodedCertificate](#common.PEMEncodedCertificate) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/security/security.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/security/security.proto\n\n\n\n<a name=\"talos.resource.definitions.security.ImageKeylessVerifierSpec\"></a>\n\n### ImageKeylessVerifierSpec\nImageKeylessVerifierSpec represents a signature verification provider.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| issuer | [string](#string) |  |  |\n| subject | [string](#string) |  |  |\n| subject_regex | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.security.ImagePublicKeyVerifierSpec\"></a>\n\n### ImagePublicKeyVerifierSpec\nImagePublicKeyVerifierSpec represents a signature verification provider with static public key.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| certificate | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.security.ImageVerificationRuleSpec\"></a>\n\n### ImageVerificationRuleSpec\nImageVerificationRuleSpec represents a verification rule.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| image_pattern | [string](#string) |  |  |\n| skip | [bool](#bool) |  |  |\n| deny | [bool](#bool) |  |  |\n| keyless_verifier | [ImageKeylessVerifierSpec](#talos.resource.definitions.security.ImageKeylessVerifierSpec) |  |  |\n| public_key_verifier | [ImagePublicKeyVerifierSpec](#talos.resource.definitions.security.ImagePublicKeyVerifierSpec) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.security.TUFTrustedRootSpec\"></a>\n\n### TUFTrustedRootSpec\nTUFTrustedRootSpec represents a sigstore's TUF trusted root information.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| last_refresh_time | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n| json_data | [string](#string) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/siderolink/siderolink.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/siderolink/siderolink.proto\n\n\n\n<a name=\"talos.resource.definitions.siderolink.ConfigSpec\"></a>\n\n### ConfigSpec\nConfigSpec describes Siderolink configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| api_endpoint | [string](#string) |  |  |\n| host | [string](#string) |  |  |\n| join_token | [string](#string) |  |  |\n| insecure | [bool](#bool) |  |  |\n| tunnel | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.siderolink.StatusSpec\"></a>\n\n### StatusSpec\nStatusSpec describes Siderolink status.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| host | [string](#string) |  |  |\n| connected | [bool](#bool) |  |  |\n| link_name | [string](#string) |  |  |\n| grpc_tunnel | [bool](#bool) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.siderolink.TunnelSpec\"></a>\n\n### TunnelSpec\nTunnelSpec describes Siderolink GRPC Tunnel configuration.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| api_endpoint | [string](#string) |  |  |\n| link_name | [string](#string) |  |  |\n| mtu | [int64](#int64) |  |  |\n| node_address | [common.NetIPPort](#common.NetIPPort) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/time/time.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/time/time.proto\n\n\n\n<a name=\"talos.resource.definitions.time.AdjtimeStatusSpec\"></a>\n\n### AdjtimeStatusSpec\nAdjtimeStatusSpec describes Linux internal adjtime state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| offset | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| frequency_adjustment_ratio | [double](#double) |  |  |\n| max_error | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| est_error | [google.protobuf.Duration](#google.protobuf.Duration) |  |  |\n| status | [string](#string) |  |  |\n| constant | [int64](#int64) |  |  |\n| sync_status | [bool](#bool) |  |  |\n| state | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"talos.resource.definitions.time.StatusSpec\"></a>\n\n### StatusSpec\nStatusSpec describes time sync state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| synced | [bool](#bool) |  |  |\n| epoch | [int64](#int64) |  |  |\n| sync_disabled | [bool](#bool) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/definitions/v1alpha1/v1alpha1.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/definitions/v1alpha1/v1alpha1.proto\n\n\n\n<a name=\"talos.resource.definitions.v1alpha1.ServiceSpec\"></a>\n\n### ServiceSpec\nServiceSpec describe service state.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| running | [bool](#bool) |  |  |\n| healthy | [bool](#bool) |  |  |\n| unknown | [bool](#bool) |  |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"resource/network/device_config.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## resource/network/device_config.proto\n\n\n\n<a name=\"resource.network.DeviceConfigSpecSpec\"></a>\n\n### DeviceConfigSpecSpec\nDeviceConfigSpecSpec is the spec for the network.DeviceConfigSpec resource.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| yaml_marshalled | [bytes](#bytes) |  | Contains YAML marshalled device config (as part of the machine config). |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n <!-- end services -->\n\n\n\n<a name=\"security/security.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## security/security.proto\n\n\n\n<a name=\"securityapi.CertificateRequest\"></a>\n\n### CertificateRequest\nThe request message containing the certificate signing request.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| csr | [bytes](#bytes) |  | Certificate Signing Request in PEM format. |\n\n\n\n\n\n\n<a name=\"securityapi.CertificateResponse\"></a>\n\n### CertificateResponse\nThe response message containing signed certificate.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| ca | [bytes](#bytes) |  | Certificate of the CA that signed the requested certificate in PEM format. |\n| crt | [bytes](#bytes) |  | Signed X.509 requested certificate in PEM format. |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"securityapi.SecurityService\"></a>\n\n### SecurityService\nThe security service definition.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| Certificate | [CertificateRequest](#securityapi.CertificateRequest) | [CertificateResponse](#securityapi.CertificateResponse) |  |\n\n <!-- end services -->\n\n\n\n<a name=\"storage/storage.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## storage/storage.proto\n\n\n\n<a name=\"storage.BlockDeviceWipe\"></a>\n\n### BlockDeviceWipe\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n\n\n\n\n\n\n<a name=\"storage.BlockDeviceWipeDescriptor\"></a>\n\n### BlockDeviceWipeDescriptor\nBlockDeviceWipeDescriptor represents a single block device to be wiped.\n\nThe device can be either a full disk (e.g. vda) or a partition (vda5).\nThe device should not be used in any of active volumes.\nThe device should not be used as a secondary (e.g. part of LVM).\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| device | [string](#string) |  | Device name to wipe (e.g. sda or sda5).<br><br>The name should be submitted without `/dev/` prefix. |\n| method | [BlockDeviceWipeDescriptor.Method](#storage.BlockDeviceWipeDescriptor.Method) |  | Wipe method to use. |\n| skip_volume_check | [bool](#bool) |  | Skip the volume in use check. |\n| skip_secondary_check | [bool](#bool) |  | Skip the secondary disk check (e.g. underlying disk for RAID or LVM). |\n| drop_partition | [bool](#bool) |  | Drop the partition (only applies if the device is a partition). |\n\n\n\n\n\n\n<a name=\"storage.BlockDeviceWipeRequest\"></a>\n\n### BlockDeviceWipeRequest\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| devices | [BlockDeviceWipeDescriptor](#storage.BlockDeviceWipeDescriptor) | repeated |  |\n\n\n\n\n\n\n<a name=\"storage.BlockDeviceWipeResponse\"></a>\n\n### BlockDeviceWipeResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [BlockDeviceWipe](#storage.BlockDeviceWipe) | repeated |  |\n\n\n\n\n\n\n<a name=\"storage.Disk\"></a>\n\n### Disk\nDisk represents a disk.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| size | [uint64](#uint64) |  | Size indicates the disk size in bytes. |\n| model | [string](#string) |  | Model idicates the disk model. |\n| device_name | [string](#string) |  | DeviceName indicates the disk name (e.g. `sda`). |\n| name | [string](#string) |  | Name as in `/sys/block/<dev>/device/name`. |\n| serial | [string](#string) |  | Serial as in `/sys/block/<dev>/device/serial`. |\n| modalias | [string](#string) |  | Modalias as in `/sys/block/<dev>/device/modalias`. |\n| uuid | [string](#string) |  | Uuid as in `/sys/block/<dev>/device/uuid`. |\n| wwid | [string](#string) |  | Wwid as in `/sys/block/<dev>/device/wwid`. |\n| type | [Disk.DiskType](#storage.Disk.DiskType) |  | Type is a type of the disk: nvme, ssd, hdd, sd card. |\n| bus_path | [string](#string) |  | BusPath is the bus path of the disk. |\n| system_disk | [bool](#bool) |  | SystemDisk indicates that the disk is used as Talos system disk. |\n| subsystem | [string](#string) |  | Subsystem is the symlink path in the `/sys/block/<dev>/subsystem`. |\n| readonly | [bool](#bool) |  | Readonly specifies if the disk is read only. |\n\n\n\n\n\n\n<a name=\"storage.Disks\"></a>\n\n### Disks\nDisksResponse represents the response of the `Disks` RPC.\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| disks | [Disk](#storage.Disk) | repeated |  |\n\n\n\n\n\n\n<a name=\"storage.DisksResponse\"></a>\n\n### DisksResponse\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Disks](#storage.Disks) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n\n<a name=\"storage.BlockDeviceWipeDescriptor.Method\"></a>\n\n### BlockDeviceWipeDescriptor.Method\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| FAST | 0 | Fast wipe - wipe only filesystem signatures. |\n| ZEROES | 1 | Zeroes wipe - wipe by overwriting with zeroes (might be slow depending on the disk size and available hardware features). |\n\n\n\n<a name=\"storage.Disk.DiskType\"></a>\n\n### Disk.DiskType\n\n\n| Name | Number | Description |\n| ---- | ------ | ----------- |\n| UNKNOWN | 0 |  |\n| SSD | 1 |  |\n| HDD | 2 |  |\n| NVME | 3 |  |\n| SD | 4 |  |\n| CD | 5 |  |\n\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"storage.StorageService\"></a>\n\n### StorageService\nStorageService represents the storage service.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| Disks | [.google.protobuf.Empty](#google.protobuf.Empty) | [DisksResponse](#storage.DisksResponse) |  |\n| BlockDeviceWipe | [BlockDeviceWipeRequest](#storage.BlockDeviceWipeRequest) | [BlockDeviceWipeResponse](#storage.BlockDeviceWipeResponse) | BlockDeviceWipe performs a wipe of the blockdevice (partition or disk).<br><br>The method doesn't require a reboot, and it can only wipe blockdevices which are not being used as volumes at the moment. Wiping of volumes requires a different API. |\n\n <!-- end services -->\n\n\n\n<a name=\"time/time.proto\"></a>\n<p align=\"right\"><a href=\"#top\">Top</a></p>\n\n## time/time.proto\n\n\n\n<a name=\"time.Time\"></a>\n\n### Time\n\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| metadata | [common.Metadata](#common.Metadata) |  |  |\n| server | [string](#string) |  |  |\n| localtime | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n| remotetime | [google.protobuf.Timestamp](#google.protobuf.Timestamp) |  |  |\n\n\n\n\n\n\n<a name=\"time.TimeRequest\"></a>\n\n### TimeRequest\nThe response message containing the ntp server\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| server | [string](#string) |  |  |\n\n\n\n\n\n\n<a name=\"time.TimeResponse\"></a>\n\n### TimeResponse\nThe response message containing the ntp server, time, and offset\n\n\n| Field | Type | Label | Description |\n| ----- | ---- | ----- | ----------- |\n| messages | [Time](#time.Time) | repeated |  |\n\n\n\n\n\n <!-- end messages -->\n\n <!-- end enums -->\n\n <!-- end HasExtensions -->\n\n\n<a name=\"time.TimeService\"></a>\n\n### TimeService\nThe time service definition.\n\n| Method Name | Request Type | Response Type | Description |\n| ----------- | ------------ | ------------- | ------------|\n| Time | [.google.protobuf.Empty](#google.protobuf.Empty) | [TimeResponse](#time.TimeResponse) |  |\n| TimeCheck | [TimeRequest](#time.TimeRequest) | [TimeResponse](#time.TimeResponse) |  |\n\n <!-- end services -->\n\n\n\n## Scalar Value Types\n\n| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |\n| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |\n| <a name=\"double\" /> double |  | double | double | float | float64 | double | float | Float |\n| <a name=\"float\" /> float |  | float | float | float | float32 | float | float | Float |\n| <a name=\"int32\" /> int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |\n| <a name=\"int64\" /> int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |\n| <a name=\"uint32\" /> uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |\n| <a name=\"uint64\" /> uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |\n| <a name=\"sint32\" /> sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |\n| <a name=\"sint64\" /> sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |\n| <a name=\"fixed32\" /> fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |\n| <a name=\"fixed64\" /> fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |\n| <a name=\"sfixed32\" /> sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |\n| <a name=\"sfixed64\" /> sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |\n| <a name=\"bool\" /> bool |  | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |\n| <a name=\"string\" /> string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |\n| <a name=\"bytes\" /> bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |\n\n"
  },
  {
    "path": "website/content/v1.13/reference/cli.md",
    "content": "---\ndescription: Talosctl CLI tool reference.\ntitle: CLI\n---\n\n<!-- markdownlint-disable -->\n\n## talosctl apply-config\n\nApply a new configuration to a node\n\n```\ntalosctl apply-config [flags]\n```\n\n### Options\n\n```\n      --cert-fingerprint strings                    list of server certificate fingeprints to accept (defaults to no check)\n  -c, --cluster string                              Cluster to connect to if a proxy endpoint is used.\n  -p, --config-patch stringArray                    the list of config patches to apply to the local config file before sending it to the node\n      --context string                              Context to be used in command\n      --dry-run                                     check how the config change will be applied in dry-run mode\n  -e, --endpoints strings                           override default endpoints in Talos configuration\n  -f, --file string                                 the filename of the updated configuration\n  -h, --help                                        help for apply-config\n  -i, --insecure                                    apply the config using the insecure (encrypted with no auth) maintenance service\n  -m, --mode auto, no-reboot, reboot, staged, try   apply config mode (default auto)\n  -n, --nodes strings                               target the specified nodes\n      --siderov1-keys-dir string                    The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string                          The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration                            the config will be rolled back after specified timeout (if try mode is selected) (default 1m0s)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl bootstrap\n\nBootstrap the etcd cluster on the specified node.\n\n### Synopsis\n\nWhen Talos cluster is created etcd service on control plane nodes enter the join loop waiting\nto join etcd peers from other control plane nodes. One node should be picked as the bootstrap node.\nWhen bootstrap command is issued, the node aborts join process and bootstraps etcd cluster as a single node cluster.\nOther control plane nodes will join etcd cluster once Kubernetes is bootstrapped on the bootstrap node.\n\nThis command should not be used when \"init\" type node are used.\n\nTalos etcd cluster can be recovered from a known snapshot with '--recover-from=' flag.\n\n```\ntalosctl bootstrap [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for bootstrap\n  -n, --nodes strings              target the specified nodes\n      --recover-from string        recover etcd cluster from the snapshot\n      --recover-skip-hash-check    skip integrity check when recovering etcd (use when recovering from data directory copy)\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl cgroups\n\nRetrieve cgroups usage information\n\n### Synopsis\n\nThe cgroups command fetches control group v2 (cgroupv2) usage details from the machine.\nSeveral presets are available to focus on specific cgroup subsystems:\n\n* cpu\n* cpuset\n* io\n* memory\n* process\n* swap\n\nYou can specify the preset using the --preset flag.\n\nAlternatively, a custom schema can be provided using the --schema-file flag.\nTo see schema examples, refer to https://github.com/siderolabs/talos/tree/main/cmd/talosctl/cmd/talos/cgroupsprinter/schemas.\n\n\n```\ntalosctl cgroups [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for cgroups\n  -n, --nodes strings              target the specified nodes\n      --preset string              preset name (one of: [cpu cpuset io memory process psi swap])\n      --schema-file string         path to the columns schema file\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --skip-cri-resolve           do not resolve cgroup names via a request to CRI\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl cluster create dev\n\nCreates a local QEMU-based cluster for Talos development.\n\n```\ntalosctl cluster create dev [flags]\n```\n\n### Options\n\n```\n      --airgapped                                limit VM network access to the provisioning network only\n      --arch string                              cluster architecture (default \"amd64\")\n      --bad-rtc                                  launch VM with bad RTC state\n      --cidr string                              CIDR of the cluster network (IPv4, ULA network for IPv6 is derived in automated way) (default \"10.5.0.0/24\")\n      --cni-bin-path strings                     search path for CNI binaries (default [/home/user/.talos/cni/bin])\n      --cni-bundle-url string                    URL to download CNI bundle from (default \"https://github.com/siderolabs/talos/releases/download/v1.13.0-alpha.2/talosctl-cni-bundle-${ARCH}.tar.gz\")\n      --cni-cache-dir string                     CNI cache directory path (default \"/home/user/.talos/cni/cache\")\n      --cni-conf-dir string                      CNI config directory path (default \"/home/user/.talos/cni/conf.d\")\n      --config-injection-method string           a method to inject machine config: default is HTTP server, 'metal-iso' to mount an ISO\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-control-plane stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-worker stringArray          patch generated machineconfigs (applied to 'worker' type)\n      --control-plane-port int                   control plane port (load balancer and local API port) (default 6443)\n      --controlplanes int                        the number of controlplanes to create (default 1)\n      --cpus string                              the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n      --custom-cni-url string                    install custom CNI from the URL (Talos cluster)\n      --disable-dhcp-hostname                    skip announcing hostname via DHCP\n      --disk int                                 default limit on disk size in MB (each VM) (default 6144)\n      --disk-block-size uint                     disk block size (default 512)\n      --disk-encryption-key-types stringArray    encryption key types to use for disk encryption (uuid, kms) (default [uuid])\n      --disk-image-path string                   disk image to use\n      --disk-preallocate                         whether disk space should be preallocated (default true)\n      --dns-domain string                        the dns domain to use for cluster (default \"cluster.local\")\n      --encrypt-ephemeral                        enable ephemeral partition encryption\n      --encrypt-state                            enable state partition encryption\n      --encrypt-user-volumes                     enable ephemeral partition encryption\n      --endpoint string                          use endpoint instead of provider defaults\n      --extra-boot-kernel-args string            add extra kernel args to the initial boot from vmlinuz and initramfs\n      --extra-disks int                          number of extra disks to create for each worker VM\n      --extra-disks-drivers strings              driver for each extra disk (virtio, ide, ahci, scsi, nvme, megaraid)\n      --extra-disks-serials strings              serials for each extra disk\n      --extra-disks-size int                     default limit on disk size in MB (each VM) (default 5120)\n      --extra-disks-tags strings                 tags for each extra disk (only used by virtiofs)\n      --extra-uefi-search-paths strings          additional search paths for UEFI firmware (only applies when UEFI is enabled)\n  -h, --help                                     help for dev\n      --image-cache-path string                  path to image cache\n      --image-cache-port uint16                  port on which to serve image cache (default 5000)\n      --image-cache-tls-cert-file string         path to image cache TLS cert\n      --image-cache-tls-key-file string          path to image cache TLS key\n      --init-node-as-endpoint                    use init node as endpoint instead of any load balancer endpoint\n      --initrd-path string                       initramfs image to use (default \"_out/initramfs-${ARCH}.xz\")\n      --install-image string                     the installer image to use (default \"ghcr.io/siderolabs/installer:latest\")\n      --ipv4                                     enable IPv4 network in the cluster (default true)\n      --ipv6                                     enable IPv6 network in the cluster\n      --ipxe-boot-script string                  iPXE boot script (URL) to use\n      --iso-path string                          the ISO path to use for the initial boot\n      --kubeprism-port int                       KubePrism port (set to 0 to disable) (default 7445)\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory string(mb,gb)                     the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --mtu int                                  MTU of the cluster network (default 1500)\n      --nameservers strings                      list of nameservers to use\n      --no-masquerade-cidrs strings              list of CIDRs to exclude from NAT\n      --omni-api-endpoint string                 the Omni API endpoint (must include a scheme, a hostname and a join token, e.g. 'https://siderolink.omni.example?jointoken=foobar')\n      --registry-insecure-skip-verify strings    list of registry hostnames to skip TLS verification for\n      --registry-mirror strings                  list of registry mirrors to use in format: <registry host>=<mirror URL>\n      --skip-injecting-config                    skip injecting config from embedded metadata server, write config files to current directory\n      --skip-injecting-extra-cmdline             skip injecting extra kernel cmdline parameters via EFI vars through bootloader\n      --skip-k8s-node-readiness-check            skip k8s node readiness checks\n      --skip-kubeconfig                          skip merging kubeconfig from the created cluster\n      --talos-version string                     the desired Talos version to generate config for (default \"latest\")\n      --talosconfig string                       The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --uki-path string                          the UKI image path to use for the initial boot\n      --usb-path string                          the USB stick image path to use for the initial boot\n      --use-vip                                  use a virtual IP for the controlplane endpoint instead of the loadbalancer\n      --user-volumes strings                     list of user volumes to create for each VM in format: <name1>:<size1>:<name2>:<size2>\n      --vmlinuz-path string                      the compressed kernel image to use (default \"_out/vmlinuz-${ARCH}\")\n      --wait                                     wait for the cluster to be ready before returning (default true)\n      --wait-timeout duration                    timeout to wait for the cluster to be ready (default 20m0s)\n      --wireguard-cidr string                    CIDR of the wireguard network\n      --with-apply-config                        enable apply config when the VM is starting in maintenance mode\n      --with-bootloader                          enable bootloader to load kernel and initramfs from disk image after install (default true)\n      --with-cluster-discovery                   enable cluster discovery (default true)\n      --with-debug                               enable debug in Talos config to send service logs to the console\n      --with-firewall string                     inject firewall rules into the cluster, value is default policy - accept/block\n      --with-init-node                           create the cluster with an init node\n      --with-iommu                               enable IOMMU support, this also add a new PCI root port and an interface attached to it\n      --with-json-logs                           enable JSON logs receiver and configure Talos to send logs there\n      --with-kubespan                            enable KubeSpan system\n      --with-network-bandwidth int               specify bandwidth restriction (in kbps) on the bridge interface\n      --with-network-chaos                       enable to use network chaos parameters\n      --with-network-jitter duration             specify jitter on the bridge interface\n      --with-network-latency duration            specify latency on the bridge interface\n      --with-network-packet-corrupt float        specify percent of corrupt packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-network-packet-loss float           specify percent of packet loss on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-network-packet-reorder float        specify percent of reordered packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-siderolink true                     enables the use of siderolink agent as configuration apply mechanism. true or `wireguard` enables the agent, `tunnel` enables the agent with grpc tunneling (default none)\n      --with-tpm1_2                              enable TPM 1.2 emulation support using swtpm\n      --with-tpm2                                enable TPM 2.0 emulation support using swtpm\n      --with-uefi                                enable UEFI on x86_64 architecture (default true)\n      --with-uuid-hostnames                      use machine UUIDs as default hostnames\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster create docker\n\nCreate a local Docker based kubernetes cluster\n\n```\ntalosctl cluster create docker [flags]\n```\n\n### Options\n\n```\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-controlplanes stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-workers stringArray         patch generated machineconfigs (applied to 'worker' type)\n      --cpus-controlplanes string                the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n  -p, --exposed-ports string                     comma-separated list of ports/protocols to expose on init node. Ex -p <hostPort>:<containerPort>/<protocol (tcp or udp)>\n  -h, --help                                     help for docker\n      --host-ip string                           Host IP to forward exposed ports to (default \"0.0.0.0\")\n      --image string                             the talos image to run (default \"ghcr.io/siderolabs/talos:latest\")\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory-controlplanes string(mb,gb)       the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --mount mount                              attach a mount to the container (docker --mount syntax)\n      --subnet string                            Docker network subnet CIDR (default \"10.5.0.0/24\")\n      --talosconfig-destination string           The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster create qemu\n\nCreate a local QEMU based Talos cluster.\n\n### Synopsis\n\nCreate a local QEMU based Talos cluster.\n\nAvailable presets:\n  - iso: Configure Talos to boot from an ISO from the Image Factory.\n  - iso-secureboot: Configure Talos for Secureboot via ISO. Only available on Linux hosts.\n  - pxe: Configure Talos to boot via PXE from the Image Factory.\n  - disk-image: Configure Talos to boot from a disk image from the Image Factory.\n  - maintenance: Skip applying machine configuration and leave the machines in maintenance mode. The machine configuration files are written to the working directory.\n\nNote: exactly one of 'iso', 'iso-secureboot', 'pxe' or 'disk-image' presets must be specified.\n\n\n```\ntalosctl cluster create qemu [flags]\n```\n\n### Options\n\n```\n      --cidr string                              CIDR of the cluster network (default \"10.5.0.0/24\")\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-controlplanes stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-workers stringArray         patch generated machineconfigs (applied to 'worker' type)\n      --controlplanes int                        the number of controlplanes to create (default 1)\n      --cpus-controlplanes string                the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n      --disks disks                              list of disks to create in format \"<driver1>:<size1>\" (disks after the first one are added only to worker machines) (default virtio:10GiB,virtio:6GiB)\n  -h, --help                                     help for qemu\n      --image-factory-url string                 image factory url (default \"https://factory.talos.dev/\")\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory-controlplanes string(mb,gb)       the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --omni-api-endpoint string                 the Omni API endpoint (must include a scheme, a hostname and a join token, e.g. 'https://siderolink.omni.example?jointoken=foobar')\n      --presets strings                          list of presets to apply (default [iso])\n      --schematic-id string                      image factory schematic id (defaults to an empty schematic)\n      --talos-version string                     the desired talos version (default \"latest\")\n      --talosconfig-destination string           The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster create dev\n\nCreates a local QEMU-based cluster for Talos development.\n\n```\ntalosctl cluster create dev [flags]\n```\n\n### Options\n\n```\n      --airgapped                                limit VM network access to the provisioning network only\n      --arch string                              cluster architecture (default \"amd64\")\n      --bad-rtc                                  launch VM with bad RTC state\n      --cidr string                              CIDR of the cluster network (IPv4, ULA network for IPv6 is derived in automated way) (default \"10.5.0.0/24\")\n      --cni-bin-path strings                     search path for CNI binaries (default [/home/user/.talos/cni/bin])\n      --cni-bundle-url string                    URL to download CNI bundle from (default \"https://github.com/siderolabs/talos/releases/download/v1.13.0-alpha.2/talosctl-cni-bundle-${ARCH}.tar.gz\")\n      --cni-cache-dir string                     CNI cache directory path (default \"/home/user/.talos/cni/cache\")\n      --cni-conf-dir string                      CNI config directory path (default \"/home/user/.talos/cni/conf.d\")\n      --config-injection-method string           a method to inject machine config: default is HTTP server, 'metal-iso' to mount an ISO\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-control-plane stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-worker stringArray          patch generated machineconfigs (applied to 'worker' type)\n      --control-plane-port int                   control plane port (load balancer and local API port) (default 6443)\n      --controlplanes int                        the number of controlplanes to create (default 1)\n      --cpus string                              the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n      --custom-cni-url string                    install custom CNI from the URL (Talos cluster)\n      --disable-dhcp-hostname                    skip announcing hostname via DHCP\n      --disk int                                 default limit on disk size in MB (each VM) (default 6144)\n      --disk-block-size uint                     disk block size (default 512)\n      --disk-encryption-key-types stringArray    encryption key types to use for disk encryption (uuid, kms) (default [uuid])\n      --disk-image-path string                   disk image to use\n      --disk-preallocate                         whether disk space should be preallocated (default true)\n      --dns-domain string                        the dns domain to use for cluster (default \"cluster.local\")\n      --encrypt-ephemeral                        enable ephemeral partition encryption\n      --encrypt-state                            enable state partition encryption\n      --encrypt-user-volumes                     enable ephemeral partition encryption\n      --endpoint string                          use endpoint instead of provider defaults\n      --extra-boot-kernel-args string            add extra kernel args to the initial boot from vmlinuz and initramfs\n      --extra-disks int                          number of extra disks to create for each worker VM\n      --extra-disks-drivers strings              driver for each extra disk (virtio, ide, ahci, scsi, nvme, megaraid)\n      --extra-disks-serials strings              serials for each extra disk\n      --extra-disks-size int                     default limit on disk size in MB (each VM) (default 5120)\n      --extra-disks-tags strings                 tags for each extra disk (only used by virtiofs)\n      --extra-uefi-search-paths strings          additional search paths for UEFI firmware (only applies when UEFI is enabled)\n  -h, --help                                     help for dev\n      --image-cache-path string                  path to image cache\n      --image-cache-port uint16                  port on which to serve image cache (default 5000)\n      --image-cache-tls-cert-file string         path to image cache TLS cert\n      --image-cache-tls-key-file string          path to image cache TLS key\n      --init-node-as-endpoint                    use init node as endpoint instead of any load balancer endpoint\n      --initrd-path string                       initramfs image to use (default \"_out/initramfs-${ARCH}.xz\")\n      --install-image string                     the installer image to use (default \"ghcr.io/siderolabs/installer:latest\")\n      --ipv4                                     enable IPv4 network in the cluster (default true)\n      --ipv6                                     enable IPv6 network in the cluster\n      --ipxe-boot-script string                  iPXE boot script (URL) to use\n      --iso-path string                          the ISO path to use for the initial boot\n      --kubeprism-port int                       KubePrism port (set to 0 to disable) (default 7445)\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory string(mb,gb)                     the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --mtu int                                  MTU of the cluster network (default 1500)\n      --nameservers strings                      list of nameservers to use\n      --no-masquerade-cidrs strings              list of CIDRs to exclude from NAT\n      --omni-api-endpoint string                 the Omni API endpoint (must include a scheme, a hostname and a join token, e.g. 'https://siderolink.omni.example?jointoken=foobar')\n      --registry-insecure-skip-verify strings    list of registry hostnames to skip TLS verification for\n      --registry-mirror strings                  list of registry mirrors to use in format: <registry host>=<mirror URL>\n      --skip-injecting-config                    skip injecting config from embedded metadata server, write config files to current directory\n      --skip-injecting-extra-cmdline             skip injecting extra kernel cmdline parameters via EFI vars through bootloader\n      --skip-k8s-node-readiness-check            skip k8s node readiness checks\n      --skip-kubeconfig                          skip merging kubeconfig from the created cluster\n      --talos-version string                     the desired Talos version to generate config for (default \"latest\")\n      --talosconfig string                       The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --uki-path string                          the UKI image path to use for the initial boot\n      --usb-path string                          the USB stick image path to use for the initial boot\n      --use-vip                                  use a virtual IP for the controlplane endpoint instead of the loadbalancer\n      --user-volumes strings                     list of user volumes to create for each VM in format: <name1>:<size1>:<name2>:<size2>\n      --vmlinuz-path string                      the compressed kernel image to use (default \"_out/vmlinuz-${ARCH}\")\n      --wait                                     wait for the cluster to be ready before returning (default true)\n      --wait-timeout duration                    timeout to wait for the cluster to be ready (default 20m0s)\n      --wireguard-cidr string                    CIDR of the wireguard network\n      --with-apply-config                        enable apply config when the VM is starting in maintenance mode\n      --with-bootloader                          enable bootloader to load kernel and initramfs from disk image after install (default true)\n      --with-cluster-discovery                   enable cluster discovery (default true)\n      --with-debug                               enable debug in Talos config to send service logs to the console\n      --with-firewall string                     inject firewall rules into the cluster, value is default policy - accept/block\n      --with-init-node                           create the cluster with an init node\n      --with-iommu                               enable IOMMU support, this also add a new PCI root port and an interface attached to it\n      --with-json-logs                           enable JSON logs receiver and configure Talos to send logs there\n      --with-kubespan                            enable KubeSpan system\n      --with-network-bandwidth int               specify bandwidth restriction (in kbps) on the bridge interface\n      --with-network-chaos                       enable to use network chaos parameters\n      --with-network-jitter duration             specify jitter on the bridge interface\n      --with-network-latency duration            specify latency on the bridge interface\n      --with-network-packet-corrupt float        specify percent of corrupt packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-network-packet-loss float           specify percent of packet loss on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-network-packet-reorder float        specify percent of reordered packets on the bridge interface. e.g. 50% = 0.50 (default: 0.0)\n      --with-siderolink true                     enables the use of siderolink agent as configuration apply mechanism. true or `wireguard` enables the agent, `tunnel` enables the agent with grpc tunneling (default none)\n      --with-tpm1_2                              enable TPM 1.2 emulation support using swtpm\n      --with-tpm2                                enable TPM 2.0 emulation support using swtpm\n      --with-uefi                                enable UEFI on x86_64 architecture (default true)\n      --with-uuid-hostnames                      use machine UUIDs as default hostnames\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster create docker\n\nCreate a local Docker based kubernetes cluster\n\n```\ntalosctl cluster create docker [flags]\n```\n\n### Options\n\n```\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-controlplanes stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-workers stringArray         patch generated machineconfigs (applied to 'worker' type)\n      --cpus-controlplanes string                the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n  -p, --exposed-ports string                     comma-separated list of ports/protocols to expose on init node. Ex -p <hostPort>:<containerPort>/<protocol (tcp or udp)>\n  -h, --help                                     help for docker\n      --host-ip string                           Host IP to forward exposed ports to (default \"0.0.0.0\")\n      --image string                             the talos image to run (default \"ghcr.io/siderolabs/talos:latest\")\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory-controlplanes string(mb,gb)       the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --mount mount                              attach a mount to the container (docker --mount syntax)\n      --subnet string                            Docker network subnet CIDR (default \"10.5.0.0/24\")\n      --talosconfig-destination string           The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster create qemu\n\nCreate a local QEMU based Talos cluster.\n\n### Synopsis\n\nCreate a local QEMU based Talos cluster.\n\nAvailable presets:\n  - iso: Configure Talos to boot from an ISO from the Image Factory.\n  - iso-secureboot: Configure Talos for Secureboot via ISO. Only available on Linux hosts.\n  - pxe: Configure Talos to boot via PXE from the Image Factory.\n  - disk-image: Configure Talos to boot from a disk image from the Image Factory.\n  - maintenance: Skip applying machine configuration and leave the machines in maintenance mode. The machine configuration files are written to the working directory.\n\nNote: exactly one of 'iso', 'iso-secureboot', 'pxe' or 'disk-image' presets must be specified.\n\n\n```\ntalosctl cluster create qemu [flags]\n```\n\n### Options\n\n```\n      --cidr string                              CIDR of the cluster network (default \"10.5.0.0/24\")\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-controlplanes stringArray   patch generated machineconfigs (applied to 'controlplane' type)\n      --config-patch-workers stringArray         patch generated machineconfigs (applied to 'worker' type)\n      --controlplanes int                        the number of controlplanes to create (default 1)\n      --cpus-controlplanes string                the share of CPUs as fraction for each control plane/VM (default \"2.0\")\n      --cpus-workers string                      the share of CPUs as fraction for each worker/VM (default \"2.0\")\n      --disks disks                              list of disks to create in format \"<driver1>:<size1>\" (disks after the first one are added only to worker machines) (default virtio:10GiB,virtio:6GiB)\n  -h, --help                                     help for qemu\n      --image-factory-url string                 image factory url (default \"https://factory.talos.dev/\")\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n      --memory-controlplanes string(mb,gb)       the limit on memory usage for each control plane/VM (default 2.0GiB)\n      --memory-workers string(mb,gb)             the limit on memory usage for each worker/VM (default 2.0GiB)\n      --omni-api-endpoint string                 the Omni API endpoint (must include a scheme, a hostname and a join token, e.g. 'https://siderolink.omni.example?jointoken=foobar')\n      --presets strings                          list of presets to apply (default [iso])\n      --schematic-id string                      image factory schematic id (defaults to an empty schematic)\n      --talos-version string                     the desired talos version (default \"latest\")\n      --talosconfig-destination string           The location to save the generated Talos configuration file to. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --workers int                              the number of workers to create (default 1)\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n\n## talosctl cluster destroy\n\nDestroys a local Talos kubernetes cluster\n\n```\ntalosctl cluster destroy [flags]\n```\n\n### Options\n\n```\n  -f, --force                                   force deletion of cluster directory if there were errors\n  -h, --help                                    help for destroy\n      --save-cluster-logs-archive-path string   save cluster logs archive to the specified file on destroy\n      --save-support-archive-path string        save support archive to the specified file on destroy\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster](#talosctl-cluster)\t - A collection of commands for managing local docker-based or QEMU-based clusters\n\n## talosctl cluster show\n\nShows info about a local provisioned kubernetes cluster\n\n```\ntalosctl cluster show [flags]\n```\n\n### Options\n\n```\n  -h, --help                 help for show\n      --provisioner string   Talos cluster provisioner to use (default \"docker\")\n```\n\n### Options inherited from parent commands\n\n```\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl cluster](#talosctl-cluster)\t - A collection of commands for managing local docker-based or QEMU-based clusters\n\n## talosctl cluster\n\nA collection of commands for managing local docker-based or QEMU-based clusters\n\n### Options\n\n```\n  -h, --help           help for cluster\n      --name string    the name of the cluster (default \"talos-default\")\n      --state string   directory path to store cluster state (default \"/home/user/.talos/clusters\")\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl cluster create](#talosctl-cluster-create)\t - Create a local Talos cluster.\n* [talosctl cluster destroy](#talosctl-cluster-destroy)\t - Destroys a local Talos kubernetes cluster\n* [talosctl cluster show](#talosctl-cluster-show)\t - Shows info about a local provisioned kubernetes cluster\n\n## talosctl completion\n\nOutput shell completion code for the specified shell (bash, fish or zsh)\n\n### Synopsis\n\nOutput shell completion code for the specified shell (bash, fish or zsh).\nThe shell code must be evaluated to provide interactive\ncompletion of talosctl commands.  This can be done by sourcing it from\nthe .bash_profile.\n\nNote for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2\n\n```\ntalosctl completion SHELL [flags]\n```\n\n### Examples\n\n```\n# Installing bash completion on macOS using homebrew\n## If running Bash 3.2 included with macOS\n\tbrew install bash-completion\n## or, if running Bash 4.1+\n\tbrew install bash-completion@2\n## If talosctl is installed via homebrew, this should start working immediately.\n## If you've installed via other means, you may need add the completion to your completion directory\n\ttalosctl completion bash > $(brew --prefix)/etc/bash_completion.d/talosctl\n\n# Installing bash completion on Linux\n## If bash-completion is not installed on Linux, please install the 'bash-completion' package\n## via your distribution's package manager.\n## Load the talosctl completion code for bash into the current shell\n\tsource <(talosctl completion bash)\n## Write bash completion code to a file and source if from .bash_profile\n\ttalosctl completion bash > \"${TALOS_HOME:-$HOME/.talos}/completion.bash.inc\"\n\tprintf '\n\t\t# talosctl shell completion\n\t\tsource \"${TALOS_HOME:-$HOME/.talos}/completion.bash.inc\"\n\t\t' >> $HOME/.bash_profile\n\tsource $HOME/.bash_profile\n# Load the talosctl completion code for fish[1] into the current shell\n\ttalosctl completion fish | source\n# Set the talosctl completion code for fish[1] to autoload on startup\n    talosctl completion fish > ~/.config/fish/completions/talosctl.fish\n# Load the talosctl completion code for zsh[1] into the current shell\n\tsource <(talosctl completion zsh)\n# Set the talosctl completion code for zsh[1] to autoload on startup\n    talosctl completion zsh > \"${fpath[1]}/_talosctl\"\n```\n\n### Options\n\n```\n  -h, --help   help for completion\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl config add\n\nAdd a new context\n\n```\ntalosctl config add <context> [flags]\n```\n\n### Options\n\n```\n      --ca string    the path to the CA certificate\n      --crt string   the path to the certificate\n  -h, --help         help for add\n      --key string   the path to the key\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config context\n\nSet the current context\n\n```\ntalosctl config context <context> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for context\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config contexts\n\nList defined contexts\n\n```\ntalosctl config contexts [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for contexts\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config endpoint\n\nSet the endpoint(s) for the current context\n\n```\ntalosctl config endpoint <endpoint>... [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for endpoint\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config info\n\nShow information about the current context\n\n```\ntalosctl config info [flags]\n```\n\n### Options\n\n```\n  -h, --help            help for info\n  -o, --output string   output format (json|yaml|text). Default text. (default \"text\")\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config merge\n\nMerge additional contexts from another client configuration file\n\n### Synopsis\n\nContexts with the same name are renamed while merging configs.\n\n```\ntalosctl config merge <from> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for merge\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config new\n\nGenerate a new client configuration file\n\n```\ntalosctl config new [<path>] [flags]\n```\n\n### Options\n\n```\n      --crt-ttl duration   certificate TTL (default 8760h0m0s)\n  -h, --help               help for new\n      --roles strings      roles (default [os:admin])\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config node\n\nSet the node(s) for the current context\n\n```\ntalosctl config node <endpoint>... [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for node\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config remove\n\nRemove contexts\n\n```\ntalosctl config remove <context> [flags]\n```\n\n### Options\n\n```\n      --dry-run     dry run\n  -h, --help        help for remove\n  -y, --noconfirm   do not ask for confirmation\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n\n## talosctl config\n\nManage the client configuration file (talosconfig)\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for config\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl config add](#talosctl-config-add)\t - Add a new context\n* [talosctl config context](#talosctl-config-context)\t - Set the current context\n* [talosctl config contexts](#talosctl-config-contexts)\t - List defined contexts\n* [talosctl config endpoint](#talosctl-config-endpoint)\t - Set the endpoint(s) for the current context\n* [talosctl config info](#talosctl-config-info)\t - Show information about the current context\n* [talosctl config merge](#talosctl-config-merge)\t - Merge additional contexts from another client configuration file\n* [talosctl config new](#talosctl-config-new)\t - Generate a new client configuration file\n* [talosctl config node](#talosctl-config-node)\t - Set the node(s) for the current context\n* [talosctl config remove](#talosctl-config-remove)\t - Remove contexts\n\n## talosctl conformance kubernetes\n\nRun Kubernetes conformance tests\n\n```\ntalosctl conformance kubernetes [flags]\n```\n\n### Options\n\n```\n  -h, --help          help for kubernetes\n      --mode string   conformance test mode: [fast, certified, network-policy] (default \"fast\")\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl conformance](#talosctl-conformance)\t - Run conformance tests\n\n## talosctl conformance\n\nRun conformance tests\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for conformance\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl conformance kubernetes](#talosctl-conformance-kubernetes)\t - Run Kubernetes conformance tests\n\n## talosctl containers\n\nList containers\n\n```\ntalosctl containers [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for containers\n  -k, --kubernetes                 use the k8s.io containerd namespace\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl copy\n\nCopy data out from the node\n\n### Synopsis\n\nCreates an .tar.gz archive at the node starting at <src-path> and\nstreams it back to the client.\n\nIf '-' is given for <local-path>, archive is written to stdout.\nOtherwise archive is extracted to <local-path> which should be an empty directory or\ntalosctl creates a directory if <local-path> doesn't exist. Command doesn't preserve\nownership and access mode for the files in extract mode, while  streamed .tar archive\ncaptures ownership and permission bits.\n\n```\ntalosctl copy <src-path> -|<local-path> [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for copy\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl dashboard\n\nCluster dashboard with node overview, logs and real-time metrics\n\n### Synopsis\n\nProvide a text-based UI to navigate node overview, logs and real-time metrics.\n\nKeyboard shortcuts:\n\n - h, <Left> - switch one node to the left\n - l, <Right> - switch one node to the right\n - j, <Down> - scroll logs/process list down\n - k, <Up> - scroll logs/process list up\n - <C-d> - scroll logs/process list half page down\n - <C-u> - scroll logs/process list half page up\n - <C-f> - scroll logs/process list one page down\n - <C-b> - scroll logs/process list one page up\n\n\n```\ntalosctl dashboard [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for dashboard\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -d, --update-interval duration   interval between updates (default 3s)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl debug\n\nRun a debug container from an image archive or reference\n\n```\ntalosctl debug <image-tar-path|image ref> [args] [flags]\n```\n\n### Examples\n\n```\n  # Run a debug container from a local tar archive (image will be loaded into Talos from the archive)\n    talosctl debug ./debug-tools.tar --args /bin/sh\n\n  # Run a debug container from an image reference (Talos will pull the image if not present)\n    talosctl debug docker.io/library/alpine:latest --args /bin/sh\n```\n\n### Options\n\n```\n      --args strings               arguments to pass to the container\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for debug\n      --namespace system           namespace to use: system (CRI containerd) or `inmem` for in-memory containerd instance (default \"inmem\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl dmesg\n\nRetrieve kernel logs\n\n```\ntalosctl dmesg [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -f, --follow                     specify if the kernel log should be streamed\n  -h, --help                       help for dmesg\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --tail                       specify if only new messages should be sent (makes sense only when combined with --follow)\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl edit\n\nEdit Talos node machine configuration with the default editor.\n\n### Synopsis\n\nThe edit command allows you to directly edit the machine configuration\nof a Talos node using your preferred text editor.\n\nIt will open the editor defined by your TALOS_EDITOR,\nor EDITOR environment variables, or fall back to 'vi' for Linux\nor 'notepad' for Windows.\n\n```\ntalosctl edit machineconfig [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string                              Cluster to connect to if a proxy endpoint is used.\n      --context string                              Context to be used in command\n      --dry-run                                     do not apply the change after editing and print the change summary instead\n  -e, --endpoints strings                           override default endpoints in Talos configuration\n  -h, --help                                        help for edit\n  -m, --mode auto, no-reboot, reboot, staged, try   apply config mode (default auto)\n      --namespace string                            resource namespace (default is to use default namespace per resource)\n  -n, --nodes strings                               target the specified nodes\n      --siderov1-keys-dir string                    The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string                          The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration                            the config will be rolled back after specified timeout (if try mode is selected) (default 1m0s)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl etcd alarm disarm\n\nDisarm the etcd alarms for the node.\n\n```\ntalosctl etcd alarm disarm [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for disarm\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd alarm](#talosctl-etcd-alarm)\t - Manage etcd alarms\n\n## talosctl etcd alarm list\n\nList the etcd alarms for the node.\n\n```\ntalosctl etcd alarm list [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for list\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd alarm](#talosctl-etcd-alarm)\t - Manage etcd alarms\n\n## talosctl etcd alarm\n\nManage etcd alarms\n\n### Options\n\n```\n  -h, --help   help for alarm\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n* [talosctl etcd alarm disarm](#talosctl-etcd-alarm-disarm)\t - Disarm the etcd alarms for the node.\n* [talosctl etcd alarm list](#talosctl-etcd-alarm-list)\t - List the etcd alarms for the node.\n\n## talosctl etcd defrag\n\nDefragment etcd database on the node\n\n### Synopsis\n\nDefragmentation is a maintenance operation that releases unused space from the etcd database file.\nDefragmentation is a resource heavy operation and should be performed only when necessary on a single node at a time.\n\n```\ntalosctl etcd defrag [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for defrag\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd downgrade cancel\n\nCancel etcd storage system downgrade.\n\n```\ntalosctl etcd downgrade cancel [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for cancel\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd downgrade](#talosctl-etcd-downgrade)\t - Manage etcd storage system downgrades\n\n## talosctl etcd downgrade enable\n\nEnable etcd storage system downgrade to the specified version.\n\n```\ntalosctl etcd downgrade enable <version> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for enable\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd downgrade](#talosctl-etcd-downgrade)\t - Manage etcd storage system downgrades\n\n## talosctl etcd downgrade validate\n\nValidate if the etcd storage system can be downgraded to the specified version.\n\n```\ntalosctl etcd downgrade validate <version> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for validate\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd downgrade](#talosctl-etcd-downgrade)\t - Manage etcd storage system downgrades\n\n## talosctl etcd downgrade\n\nManage etcd storage system downgrades\n\n### Options\n\n```\n  -h, --help   help for downgrade\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n* [talosctl etcd downgrade cancel](#talosctl-etcd-downgrade-cancel)\t - Cancel etcd storage system downgrade.\n* [talosctl etcd downgrade enable](#talosctl-etcd-downgrade-enable)\t - Enable etcd storage system downgrade to the specified version.\n* [talosctl etcd downgrade validate](#talosctl-etcd-downgrade-validate)\t - Validate if the etcd storage system can be downgraded to the specified version.\n\n## talosctl etcd forfeit-leadership\n\nTell node to forfeit etcd cluster leadership\n\n```\ntalosctl etcd forfeit-leadership [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for forfeit-leadership\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd leave\n\nTell nodes to leave etcd cluster\n\n```\ntalosctl etcd leave [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for leave\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd members\n\nGet the list of etcd cluster members\n\n```\ntalosctl etcd members [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for members\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd remove-member\n\nRemove the node from etcd cluster\n\n### Synopsis\n\nUse this command only if you want to remove a member which is in broken state.\nIf there is no access to the node, or the node can't access etcd to call etcd leave.\nAlways prefer etcd leave over this command.\n\n```\ntalosctl etcd remove-member <member ID> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for remove-member\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd snapshot\n\nStream snapshot of the etcd node to the path.\n\n```\ntalosctl etcd snapshot <path> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for snapshot\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd status\n\nGet the status of etcd cluster member\n\n### Synopsis\n\nReturns the status of etcd member on the node, use multiple nodes to get status of all members.\n\n```\ntalosctl etcd status [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for status\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n\n## talosctl etcd\n\nManage etcd\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for etcd\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl etcd alarm](#talosctl-etcd-alarm)\t - Manage etcd alarms\n* [talosctl etcd defrag](#talosctl-etcd-defrag)\t - Defragment etcd database on the node\n* [talosctl etcd downgrade](#talosctl-etcd-downgrade)\t - Manage etcd storage system downgrades\n* [talosctl etcd forfeit-leadership](#talosctl-etcd-forfeit-leadership)\t - Tell node to forfeit etcd cluster leadership\n* [talosctl etcd leave](#talosctl-etcd-leave)\t - Tell nodes to leave etcd cluster\n* [talosctl etcd members](#talosctl-etcd-members)\t - Get the list of etcd cluster members\n* [talosctl etcd remove-member](#talosctl-etcd-remove-member)\t - Remove the node from etcd cluster\n* [talosctl etcd snapshot](#talosctl-etcd-snapshot)\t - Stream snapshot of the etcd node to the path.\n* [talosctl etcd status](#talosctl-etcd-status)\t - Get the status of etcd cluster member\n\n## talosctl events\n\nStream runtime events\n\n```\ntalosctl events [flags]\n```\n\n### Options\n\n```\n      --actor-id string            filter events by the specified actor ID (default is no filter)\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n      --duration duration          show events for the past duration interval (one second resolution, default is to show no history)\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for events\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --since string               show events after the specified event ID (default is to show no history)\n      --tail int32                 show specified number of past events (use -1 to show full history, default is to show no history)\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl gen ca\n\nGenerates a self-signed X.509 certificate authority\n\n```\ntalosctl gen ca [flags]\n```\n\n### Options\n\n```\n  -h, --help                  help for ca\n      --hours int             the hours from now on which the certificate validity period ends (default 87600)\n      --organization string   X.509 distinguished name for the Organization\n      --rsa                   generate in RSA format\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen config\n\nGenerates a set of configuration files for Talos cluster\n\n### Synopsis\n\nThe cluster endpoint is the URL for the Kubernetes API. If you decide to use\na control plane node, common in a single node control plane setup, use port 6443 as\nthis is the port that the API server binds to on every control plane node. For an HA\nsetup, usually involving a load balancer, use the IP and port of the load balancer.\n\n```\ntalosctl gen config <cluster name> <cluster endpoint> [flags]\n```\n\n### Options\n\n```\n      --additional-sans strings                  additional Subject-Alt-Names for the APIServer certificate\n      --config-patch stringArray                 patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n      --config-patch-control-plane stringArray   patch generated machineconfigs (applied to 'init' and 'controlplane' types)\n      --config-patch-worker stringArray          patch generated machineconfigs (applied to 'worker' type)\n      --dns-domain string                        the dns domain to use for cluster (default \"cluster.local\")\n  -h, --help                                     help for config\n      --install-disk string                      the disk to install to (default \"/dev/sda\")\n      --install-image string                     the image used to perform an installation (default \"ghcr.io/siderolabs/installer:latest\")\n      --kubernetes-version string                desired kubernetes version to run (default \"1.36.0-alpha.2\")\n  -o, --output string                            destination to output generated files. when multiple output types are specified, it must be a directory. for a single output type, it must either be a file path, or \"-\" for stdout\n  -t, --output-types strings                     types of outputs to be generated. valid types are: [\"controlplane\" \"worker\" \"talosconfig\"] (default [controlplane,worker,talosconfig])\n      --registry-mirror strings                  list of registry mirrors to use in format: <registry host>=<mirror URL>\n      --talos-version string                     the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)\n      --version string                           the desired machine config version to generate (default \"v1alpha1\")\n      --with-cluster-discovery                   enable cluster discovery feature (default true)\n      --with-docs                                renders all machine configs adding the documentation for each field (default true)\n      --with-examples                            renders all machine configs with the commented examples (default true)\n      --with-kubespan                            enable KubeSpan feature\n      --with-secrets string                      use a secrets file generated using 'gen secrets'\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen crt\n\nGenerates an X.509 Ed25519 certificate\n\n```\ntalosctl gen crt [flags]\n```\n\n### Options\n\n```\n      --ca string     path to the PEM encoded CERTIFICATE\n      --csr string    path to the PEM encoded CERTIFICATE REQUEST\n  -h, --help          help for crt\n      --hours int     the hours from now on which the certificate validity period ends (default 24)\n      --name string   the basename of the generated file\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen csr\n\nGenerates a CSR using an Ed25519 private key\n\n```\ntalosctl gen csr [flags]\n```\n\n### Options\n\n```\n  -h, --help            help for csr\n      --ip string       generate the certificate for this IP address\n      --key string      path to the PEM encoded EC or RSA PRIVATE KEY\n      --roles strings   roles (default [os:admin])\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen key\n\nGenerates an Ed25519 private key\n\n```\ntalosctl gen key [flags]\n```\n\n### Options\n\n```\n  -h, --help          help for key\n      --name string   the basename of the generated file\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen keypair\n\nGenerates an X.509 Ed25519 key pair\n\n```\ntalosctl gen keypair [flags]\n```\n\n### Options\n\n```\n  -h, --help                  help for keypair\n      --ip string             generate the certificate for this IP address\n      --organization string   X.509 distinguished name for the Organization\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen secrets\n\nGenerates a secrets bundle file which can later be used to generate a config\n\n```\ntalosctl gen secrets [flags]\n```\n\n### Options\n\n```\n      --from-controlplane-config string     use the provided controlplane Talos machine configuration as input\n  -p, --from-kubernetes-pki string          use a Kubernetes PKI directory (e.g. /etc/kubernetes/pki) as input\n  -h, --help                                help for secrets\n  -t, --kubernetes-bootstrap-token string   use the provided bootstrap token as input\n  -o, --output-file string                  path of the output file, or \"-\" for stdout (default \"secrets.yaml\")\n      --talos-version string                the desired Talos version to generate secrets bundle for (backwards compatibility, e.g. v0.8)\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n\n## talosctl gen secureboot database\n\nGenerates a UEFI database to enroll the signing certificate\n\n```\ntalosctl gen secureboot database [flags]\n```\n\n### Options\n\n```\n      --enrolled-certificate string     path to the certificate to enroll (default \"_out/uki-signing-cert.pem\")\n  -h, --help                            help for database\n      --include-well-known-uefi-certs   include well-known UEFI (Microsoft) certificates in the database\n      --signing-certificate string      path to the certificate used to sign the database (default \"_out/uki-signing-cert.pem\")\n      --signing-key string              path to the key used to sign the database (default \"_out/uki-signing-key.pem\")\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force           will overwrite existing files\n  -o, --output string   path to the directory storing the generated files (default \"_out\")\n```\n\n### SEE ALSO\n\n* [talosctl gen secureboot](#talosctl-gen-secureboot)\t - Generates secrets for the SecureBoot process\n\n## talosctl gen secureboot pcr\n\nGenerates a key which is used to sign TPM PCR values\n\n```\ntalosctl gen secureboot pcr [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for pcr\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force           will overwrite existing files\n  -o, --output string   path to the directory storing the generated files (default \"_out\")\n```\n\n### SEE ALSO\n\n* [talosctl gen secureboot](#talosctl-gen-secureboot)\t - Generates secrets for the SecureBoot process\n\n## talosctl gen secureboot uki\n\nGenerates a certificate which is used to sign boot assets (UKI)\n\n```\ntalosctl gen secureboot uki [flags]\n```\n\n### Options\n\n```\n      --common-name string   common name for the certificate (default \"Test UKI Signing Key\")\n  -h, --help                 help for uki\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force           will overwrite existing files\n  -o, --output string   path to the directory storing the generated files (default \"_out\")\n```\n\n### SEE ALSO\n\n* [talosctl gen secureboot](#talosctl-gen-secureboot)\t - Generates secrets for the SecureBoot process\n\n## talosctl gen secureboot\n\nGenerates secrets for the SecureBoot process\n\n### Options\n\n```\n  -h, --help            help for secureboot\n  -o, --output string   path to the directory storing the generated files (default \"_out\")\n```\n\n### Options inherited from parent commands\n\n```\n  -f, --force   will overwrite existing files\n```\n\n### SEE ALSO\n\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n* [talosctl gen secureboot database](#talosctl-gen-secureboot-database)\t - Generates a UEFI database to enroll the signing certificate\n* [talosctl gen secureboot pcr](#talosctl-gen-secureboot-pcr)\t - Generates a key which is used to sign TPM PCR values\n* [talosctl gen secureboot uki](#talosctl-gen-secureboot-uki)\t - Generates a certificate which is used to sign boot assets (UKI)\n\n## talosctl gen\n\nGenerate CAs, certificates, and private keys\n\n### Options\n\n```\n  -f, --force   will overwrite existing files\n  -h, --help    help for gen\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl gen ca](#talosctl-gen-ca)\t - Generates a self-signed X.509 certificate authority\n* [talosctl gen config](#talosctl-gen-config)\t - Generates a set of configuration files for Talos cluster\n* [talosctl gen crt](#talosctl-gen-crt)\t - Generates an X.509 Ed25519 certificate\n* [talosctl gen csr](#talosctl-gen-csr)\t - Generates a CSR using an Ed25519 private key\n* [talosctl gen key](#talosctl-gen-key)\t - Generates an Ed25519 private key\n* [talosctl gen keypair](#talosctl-gen-keypair)\t - Generates an X.509 Ed25519 key pair\n* [talosctl gen secrets](#talosctl-gen-secrets)\t - Generates a secrets bundle file which can later be used to generate a config\n* [talosctl gen secureboot](#talosctl-gen-secureboot)\t - Generates secrets for the SecureBoot process\n\n## talosctl get\n\nGet a specific resource or list of resources (use 'talosctl get rd' to see all available resource types).\n\n### Synopsis\n\nSimilar to 'kubectl get', 'talosctl get' returns a set of resources from the OS.\nTo get a list of all available resource definitions, issue 'talosctl get rd'\n\n```\ntalosctl get <type> [<id>] [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for get\n  -i, --insecure                   get resources using the insecure (encrypted with no auth) maintenance service\n      --namespace string           resource namespace (default is to use default namespace per resource)\n  -n, --nodes strings              target the specified nodes\n  -o, --output string              output mode (json, table, yaml, jsonpath) (default \"table\")\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -w, --watch                      watch resource changes\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl health\n\nCheck cluster health\n\n```\ntalosctl health [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string                Cluster to connect to if a proxy endpoint is used.\n      --context string                Context to be used in command\n      --control-plane-nodes strings   specify IPs of control plane nodes\n  -e, --endpoints strings             override default endpoints in Talos configuration\n  -h, --help                          help for health\n      --init-node string              specify IPs of init node\n      --k8s-endpoint string           use endpoint instead of kubeconfig default\n  -n, --nodes strings                 target the specified nodes\n      --run-e2e                       run Kubernetes e2e test\n      --server                        run server-side check (default true)\n      --siderov1-keys-dir string      The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string            The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --wait-timeout duration         timeout to wait for the cluster to be ready (default 20m0s)\n      --worker-nodes strings          specify IPs of worker nodes\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl image cache-cert-gen\n\nGenerate TLS certificates and CA patch required for securing image cache to Talos communication\n\n### Synopsis\n\nGenerate TLS certificates and CA patch required for securing image cache to Talos communication\n\n```\ntalosctl image cache-cert-gen [flags]\n```\n\n### Options\n\n```\n      --advertised-address ipSlice   The addresses to advertise. (default [])\n      --advertised-name strings      The DNS names to advertise.\n  -h, --help                         help for cache-cert-gen\n      --tls-ca-file string           TLS certificate authority file (default \"ca.crt\")\n      --tls-cert-file string         TLS certificate file to use for serving (default \"tls.crt\")\n      --tls-key-file string          TLS key file to use for serving (default \"tls.key\")\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image cache-create\n\nCreate a cache of images in OCI format into a directory\n\n### Synopsis\n\nCreate a cache of images in OCI format into a directory\n\n```\ntalosctl image cache-create [flags]\n```\n\n### Examples\n\n```\ntalosctl images cache-create --images=ghcr.io/siderolabs/kubelet:v1.36.0-alpha.2 --image-cache-path=/tmp/talos-image-cache\n\nAlternatively, stdin can be piped to the command:\ntalosctl images default | talosctl images cache-create --image-cache-path=/tmp/talos-image-cache --images=-\n\n```\n\n### Options\n\n```\n      --cosign-signatures               pull and cache cosign signatures for images (default true)\n      --force                           force overwrite of existing image cache\n  -h, --help                            help for cache-create\n      --image-cache-path string         directory to save the image cache in OCI format\n      --image-layer-cache-path string   directory to save the image layer cache\n      --images strings                  images to cache\n      --insecure                        allow insecure registries\n      --layout string                   Specifies the cache layout format: \"oci\" for an OCI image layout directory, or \"flat\" for a registry-like flat file structure (default \"oci\")\n      --platform strings                platform to use for the cache (default [linux/amd64])\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image cache-serve\n\nServe an OCI image cache directory over HTTP(S) as a container registry\n\n### Synopsis\n\nServe an OCI image cache directory over HTTP(S) as a container registry\n\n```\ntalosctl image cache-serve [flags]\n```\n\n### Options\n\n```\n      --address string            address to serve the registry on (default \"127.0.0.1:3172\")\n  -h, --help                      help for cache-serve\n      --image-cache-path string   directory to save the image cache in flat format\n      --mirror strings            list of registry mirrors to add to the Talos config patch (default [docker.io,ghcr.io,registry.k8s.io])\n      --tls-cert-file string      TLS certificate file to use for serving\n      --tls-key-file string       TLS key file to use for serving\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image k8s-bundle\n\nList the default Kubernetes images used by Talos\n\n```\ntalosctl image k8s-bundle [flags]\n```\n\n### Options\n\n```\n      --coredns-version semver                 CoreDNS semantic version (default v1.14.2)\n      --etcd-version semver                    ETCD semantic version (default v3.6.8)\n      --flannel-version semver                 Flannel CNI semantic version (default v0.28.1)\n  -h, --help                                   help for k8s-bundle\n      --k8s-version semver                     Kubernetes semantic version (default v1.36.0-alpha.2)\n      --kube-network-policies-version semver   kube-network-policies semantic version (default v1.0.0)\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image list\n\nList images in the machine's container runtime\n\n```\ntalosctl image list [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for list\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image pull\n\nPull an image into the machine's container runtime\n\n```\ntalosctl image pull <image> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for pull\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image remove\n\nRemove an image from the machine's container runtime\n\n```\ntalosctl image remove <image> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for remove\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image talos-bundle\n\nList the default system images and extensions used for Talos\n\n```\ntalosctl image talos-bundle [talos-version] [flags]\n```\n\n### Options\n\n```\n      --extensions   Include images that belong to Talos extensions (default true)\n  -h, --help         help for talos-bundle\n      --overlays     Include images that belong to Talos overlays (default true)\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl image](#talosctl-image)\t - Manage container images\n\n## talosctl image\n\nManage container images\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for image\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"cri\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl image cache-cert-gen](#talosctl-image-cache-cert-gen)\t - Generate TLS certificates and CA patch required for securing image cache to Talos communication\n* [talosctl image cache-create](#talosctl-image-cache-create)\t - Create a cache of images in OCI format into a directory\n* [talosctl image cache-serve](#talosctl-image-cache-serve)\t - Serve an OCI image cache directory over HTTP(S) as a container registry\n* [talosctl image k8s-bundle](#talosctl-image-k8s-bundle)\t - List the default Kubernetes images used by Talos\n* [talosctl image list](#talosctl-image-list)\t - List images in the machine's container runtime\n* [talosctl image pull](#talosctl-image-pull)\t - Pull an image into the machine's container runtime\n* [talosctl image remove](#talosctl-image-remove)\t - Remove an image from the machine's container runtime\n* [talosctl image talos-bundle](#talosctl-image-talos-bundle)\t - List the default system images and extensions used for Talos\n\n## talosctl inject serviceaccount\n\nInject Talos API ServiceAccount into Kubernetes manifests\n\n```\ntalosctl inject serviceaccount [--roles='<ROLE_1>,<ROLE_2>'] -f <manifest.yaml> [flags]\n```\n\n### Examples\n\n```\ntalosctl inject serviceaccount --roles=\"os:admin\" -f deployment.yaml > deployment-injected.yaml\n\nAlternatively, stdin can be piped to the command:\ncat deployment.yaml | talosctl inject serviceaccount --roles=\"os:admin\" -f - > deployment-injected.yaml\n\n```\n\n### Options\n\n```\n  -f, --file string     file with Kubernetes manifests to be injected with ServiceAccount\n  -h, --help            help for serviceaccount\n  -r, --roles strings   roles to add to the generated ServiceAccount manifests (default [os:reader])\n```\n\n### SEE ALSO\n\n* [talosctl inject](#talosctl-inject)\t - Inject Talos API resources into Kubernetes manifests\n\n## talosctl inject\n\nInject Talos API resources into Kubernetes manifests\n\n### Options\n\n```\n  -h, --help   help for inject\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl inject serviceaccount](#talosctl-inject-serviceaccount)\t - Inject Talos API ServiceAccount into Kubernetes manifests\n\n## talosctl inspect dependencies\n\nInspect controller-resource dependencies as graphviz graph.\n\n### Synopsis\n\nInspect controller-resource dependencies as graphviz graph.\n\nPipe the output of the command through the \"dot\" program (part of graphviz package)\nto render the graph:\n\n    talosctl inspect dependencies | dot -Tpng > graph.png\n\n\n```\ntalosctl inspect dependencies [flags]\n```\n\n### Options\n\n```\n  -h, --help             help for dependencies\n      --with-resources   display live resource information with dependencies\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl inspect](#talosctl-inspect)\t - Inspect internals of Talos\n\n## talosctl inspect\n\nInspect internals of Talos\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for inspect\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl inspect dependencies](#talosctl-inspect-dependencies)\t - Inspect controller-resource dependencies as graphviz graph.\n\n## talosctl kubeconfig\n\nDownload the admin kubeconfig from the node\n\n### Synopsis\n\nDownload the admin kubeconfig from the node.\nIf merge flag is true, config will be merged with ~/.kube/config or [local-path] if specified.\nOtherwise, kubeconfig will be written to PWD or [local-path] if specified.\n\nIf merge flag is false and [local-path] is \"-\", config will be written to stdout.\n\n```\ntalosctl kubeconfig [local-path] [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string              Cluster to connect to if a proxy endpoint is used.\n      --context string              Context to be used in command\n  -e, --endpoints strings           override default endpoints in Talos configuration\n  -f, --force                       Force overwrite of kubeconfig if already present, force overwrite on kubeconfig merge\n      --force-context-name string   Force context name for kubeconfig merge\n  -h, --help                        help for kubeconfig\n  -m, --merge                       Merge with existing kubeconfig (default true)\n  -n, --nodes strings               target the specified nodes\n      --siderov1-keys-dir string    The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string          The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl list\n\nRetrieve a directory listing\n\n```\ntalosctl list [path] [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -d, --depth int32                maximum recursion depth (default 1)\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for list\n  -H, --humanize                   humanize size and time in the output\n  -l, --long                       display additional file details\n  -n, --nodes strings              target the specified nodes\n  -r, --recurse                    recurse into subdirectories\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -t, --type strings               filter by specified types:\n                                   f\tregular file\n                                   d\tdirectory\n                                   l, L\tsymbolic link\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl logs\n\nRetrieve logs for a service\n\n```\ntalosctl logs <service name> [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -f, --follow                     specify if the logs should be streamed\n  -h, --help                       help for logs\n  -k, --kubernetes                 use the k8s.io containerd namespace\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --tail int32                 lines of log file to display (default is to show from the beginning) (default -1)\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl machineconfig gen\n\nGenerates a set of configuration files for Talos cluster\n\n### Synopsis\n\nThe cluster endpoint is the URL for the Kubernetes API. If you decide to use\na control plane node, common in a single node control plane setup, use port 6443 as\nthis is the port that the API server binds to on every control plane node. For an HA\nsetup, usually involving a load balancer, use the IP and port of the load balancer.\n\n```\ntalosctl machineconfig gen <cluster name> <cluster endpoint> [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for gen\n```\n\n### SEE ALSO\n\n* [talosctl machineconfig](#talosctl-machineconfig)\t - Machine config related commands\n\n## talosctl machineconfig patch\n\nPatch a machine config\n\n```\ntalosctl machineconfig patch <machineconfig-file> [flags]\n```\n\n### Options\n\n```\n  -h, --help                help for patch\n  -o, --output string       output destination. if not specified, output will be printed to stdout\n  -p, --patch stringArray   patch generated machineconfigs (applied to all node types), use @file to read a patch from file\n```\n\n### SEE ALSO\n\n* [talosctl machineconfig](#talosctl-machineconfig)\t - Machine config related commands\n\n## talosctl machineconfig\n\nMachine config related commands\n\n### Options\n\n```\n  -h, --help   help for machineconfig\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl machineconfig gen](#talosctl-machineconfig-gen)\t - Generates a set of configuration files for Talos cluster\n* [talosctl machineconfig patch](#talosctl-machineconfig-patch)\t - Patch a machine config\n\n## talosctl memory\n\nShow memory usage\n\n```\ntalosctl memory [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for memory\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -v, --verbose                    display extended memory statistics\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl meta delete\n\nDelete a key from the META partition.\n\n```\ntalosctl meta delete key [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for delete\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -i, --insecure                   write|delete meta using the insecure (encrypted with no auth) maintenance service\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl meta](#talosctl-meta)\t - Write and delete keys in the META partition\n\n## talosctl meta write\n\nWrite a key-value pair to the META partition.\n\n```\ntalosctl meta write key value [flags]\n```\n\n### Options\n\n```\n  -h, --help   help for write\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -i, --insecure                   write|delete meta using the insecure (encrypted with no auth) maintenance service\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl meta](#talosctl-meta)\t - Write and delete keys in the META partition\n\n## talosctl meta\n\nWrite and delete keys in the META partition\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for meta\n  -i, --insecure                   write|delete meta using the insecure (encrypted with no auth) maintenance service\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl meta delete](#talosctl-meta-delete)\t - Delete a key from the META partition.\n* [talosctl meta write](#talosctl-meta-write)\t - Write a key-value pair to the META partition.\n\n## talosctl mounts\n\nList mounts\n\n```\ntalosctl mounts [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for mounts\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl netstat\n\nShow network connections and sockets\n\n### Synopsis\n\nShow network connections and sockets.\n\nYou can pass an optional argument to view a specific pod's connections.\nTo do this, format the argument as \"namespace/pod\".\nNote that only pods with a pod network namespace are allowed.\nIf you don't pass an argument, the command will show host connections.\n\n```\ntalosctl netstat [flags]\n```\n\n### Options\n\n```\n  -a, --all                        display all sockets states (default: connected)\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -x, --extend                     show detailed socket information\n  -h, --help                       help for netstat\n  -4, --ipv4                       display only ipv4 sockets\n  -6, --ipv6                       display only ipv6 sockets\n  -l, --listening                  display listening server sockets\n  -n, --nodes strings              target the specified nodes\n  -k, --pods                       show sockets used by Kubernetes pods\n  -p, --programs                   show process using socket\n  -w, --raw                        display only RAW sockets\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -t, --tcp                        display only TCP sockets\n  -o, --timers                     display timers\n  -u, --udp                        display only UDP sockets\n  -U, --udplite                    display only UDPLite sockets\n  -v, --verbose                    display sockets of all supported transport protocols\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl patch\n\nPatch machine configuration of a Talos node with a local patch.\n\n```\ntalosctl patch machineconfig [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string                              Cluster to connect to if a proxy endpoint is used.\n      --context string                              Context to be used in command\n      --dry-run                                     print the change summary and patch preview without applying the changes\n  -e, --endpoints strings                           override default endpoints in Talos configuration\n  -h, --help                                        help for patch\n  -m, --mode auto, no-reboot, reboot, staged, try   apply config mode (default auto)\n      --namespace string                            resource namespace (default is to use default namespace per resource)\n  -n, --nodes strings                               target the specified nodes\n  -p, --patch stringArray                           the patch to be applied to the resource file, use @file to read a patch from file.\n      --patch-file string                           a file containing a patch to be applied to the resource.\n      --siderov1-keys-dir string                    The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string                          The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration                            the config will be rolled back after specified timeout (if try mode is selected) (default 1m0s)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl pcap\n\nCapture the network packets from the node.\n\n### Synopsis\n\nThe command launches packet capture on the node and streams back the packets as raw pcap file.\n\n```\ntalosctl pcap [flags]\n```\n\n### Examples\n\n```\nDefault behavior is to decode the packets with internal decoder to stdout:\n\n    talosctl pcap -i eth0\n\nRaw pcap file can be saved with `--output` flag:\n\n    talosctl pcap -i eth0 --output eth0.pcap\n\nOutput can be piped to tcpdump:\n\n    talosctl pcap -i eth0 -o - | tcpdump -vvv -r -\n\nBPF filter can be applied, but it has to compiled to BPF instructions first using tcpdump.\nCorrect link type should be specified for the tcpdump: EN10MB for Ethernet links and RAW\nfor e.g. Wireguard tunnels:\n\n    talosctl pcap -i eth0 --bpf-filter \"$(tcpdump -dd -y EN10MB 'tcp and dst port 80')\"\n\n    talosctl pcap -i kubespan --bpf-filter \"$(tcpdump -dd -y RAW 'port 50000')\"\n\nAs packet capture is transmitted over the network, it is recommended to filter out the Talos API traffic,\ne.g. by excluding packets with the port 50000.\n   \n```\n\n### Options\n\n```\n      --bpf-filter string          bpf filter to apply, tcpdump -dd format\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n      --duration duration          duration of the capture\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for pcap\n  -i, --interface string           interface name to capture packets on (default \"eth0\")\n  -n, --nodes strings              target the specified nodes\n  -o, --output string              if not set, decode packets to stdout; if set write raw pcap data to a file, use '-' for stdout\n      --promiscuous                put interface into promiscuous mode\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl processes\n\nList running processes\n\n```\ntalosctl processes [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for processes\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n  -s, --sort string                Column to sort output by. [rss|cpu] (default \"rss\")\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl read\n\nRead a file on the machine\n\n```\ntalosctl read <path> [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for read\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl reboot\n\nReboot a node\n\n```\ntalosctl reboot [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n      --debug                      debug operation from kernel logs. --wait is set to true when this flag is set\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for reboot\n  -m, --mode string                select the reboot mode: \"default\", \"powercycle\" (skips kexec), \"force\" (skips graceful teardown) (default \"default\")\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration           time to wait for the operation is complete if --debug or --wait is set (default 30m0s)\n      --wait                       wait for the operation to complete, tracking its progress. always set to true when --debug is set (default true)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl reset\n\nReset a node\n\n```\ntalosctl reset [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string                           Cluster to connect to if a proxy endpoint is used.\n      --context string                           Context to be used in command\n      --debug                                    debug operation from kernel logs. --wait is set to true when this flag is set\n  -e, --endpoints strings                        override default endpoints in Talos configuration\n      --graceful                                 if true, attempt to cordon/drain node and leave etcd (if applicable) (default true)\n  -h, --help                                     help for reset\n      --insecure                                 reset using the insecure (encrypted with no auth) maintenance service\n  -n, --nodes strings                            target the specified nodes\n      --reboot                                   if true, reboot the node after resetting instead of shutting down\n      --siderov1-keys-dir string                 The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --system-labels-to-wipe strings            if set, just wipe selected system disk partitions by label but keep other partitions intact\n      --talosconfig string                       The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration                         time to wait for the operation is complete if --debug or --wait is set (default 30m0s)\n      --user-disks-to-wipe strings               if set, wipes defined devices in the list\n      --wait                                     wait for the operation to complete, tracking its progress. always set to true when --debug is set (default true)\n      --wipe-mode all, system-disk, user-disks   disk reset mode (default all)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl restart\n\nRestart a process\n\n```\ntalosctl restart <id> [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for restart\n  -k, --kubernetes                 use the k8s.io containerd namespace\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl rollback\n\nRollback a node to the previous installation\n\n```\ntalosctl rollback [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for rollback\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl rotate-ca\n\nRotate cluster CAs (Talos and Kubernetes APIs).\n\n### Synopsis\n\nThe command can rotate both Talos and Kubernetes root CAs (for the API).\nBy default both CAs are rotated, but you can choose to rotate just one or another.\nThe command starts by generating new CAs, and gracefully applying it to the cluster.\n\nFor Kubernetes, the command only rotates the API server issuing CA, and other Kubernetes\nPKI can be rotated by applying machine config changes to the controlplane nodes.\n\n```\ntalosctl rotate-ca [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string                Cluster to connect to if a proxy endpoint is used.\n      --context string                Context to be used in command\n      --control-plane-nodes strings   specify IPs of control plane nodes\n      --dry-run                       dry-run mode (no changes to the cluster) (default true)\n  -e, --endpoints strings             override default endpoints in Talos configuration\n  -h, --help                          help for rotate-ca\n      --init-node string              specify IPs of init node\n      --k8s-endpoint string           use endpoint instead of kubeconfig default\n      --kubernetes                    rotate Kubernetes API CA (default true)\n  -n, --nodes strings                 target the specified nodes\n  -o, --output talosconfig            path to the output new talosconfig (default \"talosconfig\")\n      --siderov1-keys-dir string      The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talos                         rotate Talos API CA (default true)\n      --talosconfig string            The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --with-docs                     patch all machine configs adding the documentation for each field (default true)\n      --with-examples                 patch all machine configs with the commented examples (default true)\n      --worker-nodes strings          specify IPs of worker nodes\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl service\n\nRetrieve the state of a service (or all services), control service state\n\n### Synopsis\n\nService control command. If run without arguments, lists all the services and their state.\nIf service ID is specified, default action 'status' is executed which shows status of a single list service.\nWith actions 'start', 'stop', 'restart', service state is updated respectively.\n\n```\ntalosctl service [<id> [start|stop|restart|status]] [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for service\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl shutdown\n\nShutdown a node\n\n```\ntalosctl shutdown [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n      --debug                      debug operation from kernel logs. --wait is set to true when this flag is set\n  -e, --endpoints strings          override default endpoints in Talos configuration\n      --force                      if true, force a node to shutdown without a cordon/drain\n  -h, --help                       help for shutdown\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration           time to wait for the operation is complete if --debug or --wait is set (default 30m0s)\n      --wait                       wait for the operation to complete, tracking its progress. always set to true when --debug is set (default true)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl stats\n\nGet container stats\n\n```\ntalosctl stats [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for stats\n  -k, --kubernetes                 use the k8s.io containerd namespace\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl support\n\nDump debug information about the cluster\n\n### Synopsis\n\nGenerated bundle contains the following debug information:\n\n- For each node:\n\n\t- Kernel logs.\n\t- All Talos internal services logs.\n\t- All kube-system pods logs.\n\t- Talos COSI resources without secrets.\n\t- COSI runtime state graph.\n\t- Processes snapshot.\n\t- IO pressure snapshot.\n\t- Mounts list.\n\t- PCI devices info.\n\t- Talos version.\n\n- For the cluster:\n\n\t- Kubernetes nodes and kube-system pods manifests.\n\n\n```\ntalosctl support [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for support\n  -n, --nodes strings              target the specified nodes\n  -w, --num-workers int            number of workers per node (default 1)\n  -O, --output string              output file to write support archive to\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -v, --verbose                    verbose output\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl time\n\nGets current server time\n\n```\ntalosctl time [--check server] [flags]\n```\n\n### Options\n\n```\n      --check string               checks server time against specified ntp server\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for time\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl upgrade\n\nUpgrade Talos on the target node\n\n```\ntalosctl upgrade [flags]\n```\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n      --debug                      debug operation from kernel logs. --wait is set to true when this flag is set\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for upgrade\n  -i, --image string               the container image to use for performing the install (default \"ghcr.io/siderolabs/installer:v1.13.0-alpha.2\")\n      --namespace string           namespace to use: \"system\" (etcd and kubelet images), \"cri\" for all Kubernetes workloads, \"inmem\" for in-memory containerd instance (default \"system\")\n  -n, --nodes strings              target the specified nodes\n      --progress string            output mode for upgrade progress. Values: [auto plain] (default \"auto\")\n  -m, --reboot-mode string         select the reboot mode during upgrade. Mode \"powercycle\" bypasses kexec. Values: [default force powercycle] (default \"default\")\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --timeout duration           time to wait for the operation is complete if --debug or --wait is set (default 30m0s)\n      --wait                       wait for the operation to complete, tracking its progress. always set to true when --debug is set (default true)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl upgrade-k8s\n\nUpgrade Kubernetes control plane in the Talos cluster.\n\n### Synopsis\n\nCommand runs upgrade of Kubernetes control plane components between specified versions.\n\n```\ntalosctl upgrade-k8s [flags]\n```\n\n### Options\n\n```\n      --apiserver-image string                 kube-apiserver image to use (default \"registry.k8s.io/kube-apiserver\")\n  -c, --cluster string                         Cluster to connect to if a proxy endpoint is used.\n      --context string                         Context to be used in command\n      --controller-manager-image string        kube-controller-manager image to use (default \"registry.k8s.io/kube-controller-manager\")\n      --dry-run                                skip the actual upgrade and show the upgrade plan instead\n      --endpoint string                        the cluster control plane endpoint\n  -e, --endpoints strings                      override default endpoints in Talos configuration\n      --from string                            the Kubernetes control plane version to upgrade from\n  -h, --help                                   help for upgrade-k8s\n      --kubelet-image string                   kubelet image to use (default \"ghcr.io/siderolabs/kubelet\")\n      --manifests-force                        whether to recreate objects that contain immutable field changes\n      --manifests-inventory-policy string      kubernetes SSA inventory policy (one of 'MustMatch', 'AdoptIfNoInventory' or 'AdoptAll') (default \"AdoptIfNoInventory\")\n      --manifests-no-prune                     whether pruning of previously applied objects should happen after apply\n      --manifests-reconcile-timeout duration   how long to wait for resources to be fully reconciled (set to zero to disable waiting) (default 5m0s)\n  -n, --nodes strings                          target the specified nodes\n      --pre-pull-images                        pre-pull images before upgrade (default true)\n      --proxy-image string                     kube-proxy image to use (default \"registry.k8s.io/kube-proxy\")\n      --scheduler-image string                 kube-scheduler image to use (default \"registry.k8s.io/kube-scheduler\")\n      --siderov1-keys-dir string               The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string                     The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n      --to string                              the Kubernetes control plane version to upgrade to (default \"1.36.0-alpha.2\")\n      --upgrade-kubelet                        upgrade kubelet service (default true)\n      --with-docs                              patch all machine configs adding the documentation for each field (default true)\n      --with-examples                          patch all machine configs with the commented examples (default true)\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl usage\n\nRetrieve a disk usage\n\n```\ntalosctl usage [path1] [path2] ... [pathN] [flags]\n```\n\n### Options\n\n```\n  -a, --all                        write counts for all files, not just directories\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -d, --depth int32                maximum recursion depth\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for usage\n  -H, --humanize                   humanize size and time in the output\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n  -t, --threshold int              threshold exclude entries smaller than SIZE if positive, or entries greater than SIZE if negative\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl validate\n\nValidate config\n\n```\ntalosctl validate [flags]\n```\n\n### Options\n\n```\n  -c, --config string   the path of the config file\n  -h, --help            help for validate\n  -m, --mode string     the mode to validate the config for (valid values are metal, cloud, and container)\n      --strict          treat validation warnings as errors\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl version\n\nPrints the version\n\n```\ntalosctl version [flags]\n```\n\n### Options\n\n```\n      --client                     Print client version only\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for version\n  -i, --insecure                   use Talos maintenance mode API\n  -n, --nodes strings              target the specified nodes\n      --short                      Print the short version\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n\n## talosctl wipe disk\n\nWipe a block device (disk or partition) which is not used as a volume\n\n### Synopsis\n\nWipe a block device (disk or partition) which is not used as a volume.\n\nUse device names as arguments, for example: vda or sda5.\n\n```\ntalosctl wipe disk <device names>... [flags]\n```\n\n### Options\n\n```\n      --drop-partition   drop partition after wipe (if applicable)\n  -h, --help             help for disk\n  -i, --insecure         use Talos maintenance mode API\n      --method string    wipe method to use [FAST ZEROES] (default \"FAST\")\n```\n\n### Options inherited from parent commands\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl wipe](#talosctl-wipe)\t - Wipe block device or volumes\n\n## talosctl wipe\n\nWipe block device or volumes\n\n### Options\n\n```\n  -c, --cluster string             Cluster to connect to if a proxy endpoint is used.\n      --context string             Context to be used in command\n  -e, --endpoints strings          override default endpoints in Talos configuration\n  -h, --help                       help for wipe\n  -n, --nodes strings              target the specified nodes\n      --siderov1-keys-dir string   The path to the SideroV1 auth PGP keys directory. Defaults to 'SIDEROV1_KEYS_DIR' env variable if set, otherwise '$HOME/.talos/keys'. Only valid for Contexts that use SideroV1 auth.\n      --talosconfig string         The path to the Talos configuration file. Defaults to 'TALOSCONFIG' env variable if set, otherwise '$HOME/.talos/config' and '/var/run/secrets/talos.dev/config' in order.\n```\n\n### SEE ALSO\n\n* [talosctl](#talosctl)\t - A CLI for out-of-band management of Kubernetes nodes created by Talos\n* [talosctl wipe disk](#talosctl-wipe-disk)\t - Wipe a block device (disk or partition) which is not used as a volume\n\n## talosctl\n\nA CLI for out-of-band management of Kubernetes nodes created by Talos\n\n### Options\n\n```\n  -h, --help   help for talosctl\n```\n\n### SEE ALSO\n\n* [talosctl apply-config](#talosctl-apply-config)\t - Apply a new configuration to a node\n* [talosctl bootstrap](#talosctl-bootstrap)\t - Bootstrap the etcd cluster on the specified node.\n* [talosctl cgroups](#talosctl-cgroups)\t - Retrieve cgroups usage information\n* [talosctl cluster](#talosctl-cluster)\t - A collection of commands for managing local docker-based or QEMU-based clusters\n* [talosctl completion](#talosctl-completion)\t - Output shell completion code for the specified shell (bash, fish or zsh)\n* [talosctl config](#talosctl-config)\t - Manage the client configuration file (talosconfig)\n* [talosctl conformance](#talosctl-conformance)\t - Run conformance tests\n* [talosctl containers](#talosctl-containers)\t - List containers\n* [talosctl copy](#talosctl-copy)\t - Copy data out from the node\n* [talosctl dashboard](#talosctl-dashboard)\t - Cluster dashboard with node overview, logs and real-time metrics\n* [talosctl debug](#talosctl-debug)\t - Run a debug container from an image archive or reference\n* [talosctl dmesg](#talosctl-dmesg)\t - Retrieve kernel logs\n* [talosctl edit](#talosctl-edit)\t - Edit Talos node machine configuration with the default editor.\n* [talosctl etcd](#talosctl-etcd)\t - Manage etcd\n* [talosctl events](#talosctl-events)\t - Stream runtime events\n* [talosctl gen](#talosctl-gen)\t - Generate CAs, certificates, and private keys\n* [talosctl get](#talosctl-get)\t - Get a specific resource or list of resources (use 'talosctl get rd' to see all available resource types).\n* [talosctl health](#talosctl-health)\t - Check cluster health\n* [talosctl image](#talosctl-image)\t - Manage container images\n* [talosctl inject](#talosctl-inject)\t - Inject Talos API resources into Kubernetes manifests\n* [talosctl inspect](#talosctl-inspect)\t - Inspect internals of Talos\n* [talosctl kubeconfig](#talosctl-kubeconfig)\t - Download the admin kubeconfig from the node\n* [talosctl list](#talosctl-list)\t - Retrieve a directory listing\n* [talosctl logs](#talosctl-logs)\t - Retrieve logs for a service\n* [talosctl machineconfig](#talosctl-machineconfig)\t - Machine config related commands\n* [talosctl memory](#talosctl-memory)\t - Show memory usage\n* [talosctl meta](#talosctl-meta)\t - Write and delete keys in the META partition\n* [talosctl mounts](#talosctl-mounts)\t - List mounts\n* [talosctl netstat](#talosctl-netstat)\t - Show network connections and sockets\n* [talosctl patch](#talosctl-patch)\t - Patch machine configuration of a Talos node with a local patch.\n* [talosctl pcap](#talosctl-pcap)\t - Capture the network packets from the node.\n* [talosctl processes](#talosctl-processes)\t - List running processes\n* [talosctl read](#talosctl-read)\t - Read a file on the machine\n* [talosctl reboot](#talosctl-reboot)\t - Reboot a node\n* [talosctl reset](#talosctl-reset)\t - Reset a node\n* [talosctl restart](#talosctl-restart)\t - Restart a process\n* [talosctl rollback](#talosctl-rollback)\t - Rollback a node to the previous installation\n* [talosctl rotate-ca](#talosctl-rotate-ca)\t - Rotate cluster CAs (Talos and Kubernetes APIs).\n* [talosctl service](#talosctl-service)\t - Retrieve the state of a service (or all services), control service state\n* [talosctl shutdown](#talosctl-shutdown)\t - Shutdown a node\n* [talosctl stats](#talosctl-stats)\t - Get container stats\n* [talosctl support](#talosctl-support)\t - Dump debug information about the cluster\n* [talosctl time](#talosctl-time)\t - Gets current server time\n* [talosctl upgrade](#talosctl-upgrade)\t - Upgrade Talos on the target node\n* [talosctl upgrade-k8s](#talosctl-upgrade-k8s)\t - Upgrade Kubernetes control plane in the Talos cluster.\n* [talosctl usage](#talosctl-usage)\t - Retrieve a disk usage\n* [talosctl validate](#talosctl-validate)\t - Validate config\n* [talosctl version](#talosctl-version)\t - Prints the version\n* [talosctl wipe](#talosctl-wipe)\t - Wipe block device or volumes\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/_index.md",
    "content": "---\ntitle: Configuration\ndescription: Talos Linux machine configuration reference.\n---\n\nTalos Linux machine is fully configured via a single YAML file called *machine configuration*.\n\nThe file might contain one or more configuration documents separated by `---` (three dashes) lines.\nAt the moment, majority of the configuration options are within the [v1alpha1]({{< relref \"./v1alpha1\" >}}) document, so\nthis is the only mandatory document in the configuration file.\n\nConfiguration documents might be named (contain a `name:` field) or unnamed.\nUnnamed documents can be supplied to the machine configuration file only once, while named documents can be supplied multiple times with unique names.\n\nThe `v1alpha1` document has its own (legacy) structure, while every other document has the following set of fields:\n\n```yaml\napiVersion: v1alpha1 # version of the document\nkind: NetworkRuleConfig # type of document\nname: rule1 # only for named documents\n```\n\nThis section contains the configuration reference, to learn more about Talos Linux machine configuration management, please see:\n\n* [quick guide to configuration generation]({{< relref \"../../introduction/getting-started#configure-talos-linux\" >}})\n* [configuration management in production]({{< relref \"../../introduction/prodnotes#configure-talos\" >}})\n* [configuration patches]({{< relref \"../../talos-guides/configuration/patching\" >}})\n* [editing live machine configuration]({{< relref \"../../talos-guides/configuration/editing-machine-configuration\" >}})\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/_index.md",
    "content": "---\ndescription: |\n    Package block provides block device and volume configuration documents.\ntitle: block\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/existingvolumeconfig.md",
    "content": "---\ndescription: |\n    ExistingVolumeConfig is an existing volume configuration document.\n    Existing volumes allow to mount partitions (or whole disks) that were created\n    outside of Talos. Volume will be mounted under `/var/mnt/<name>`.\n    The existing volume config name should not conflict with user volume names.\ntitle: ExistingVolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ExistingVolumeConfig\nname: my-existing-volume # Name of the volume.\n# The discovery describes how to find a volume.\ndiscovery:\n    # The volume selector expression.\n    volumeSelector:\n        match: volume.partition_label == \"MY-DATA\" # The Common Expression Language (CEL) expression to match the volume.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the volume.<br><br>Name can only contain:<br>lowercase and uppercase ASCII letters, digits, and hyphens.  | |\n|`discovery` |<a href=\"#ExistingVolumeConfig.discovery\">VolumeDiscoverySpec</a> |The discovery describes how to find a volume.  | |\n|`mount` |<a href=\"#ExistingVolumeConfig.mount\">ExistingMountSpec</a> |The mount describes additional mount options.  | |\n\n\n\n\n## discovery {#ExistingVolumeConfig.discovery}\n\nVolumeDiscoverySpec describes how the volume is discovered.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`volumeSelector` |<a href=\"#ExistingVolumeConfig.discovery.volumeSelector\">VolumeSelector</a> |The volume selector expression.  | |\n\n\n\n\n### volumeSelector {#ExistingVolumeConfig.discovery.volumeSelector}\n\nVolumeSelector selects an existing volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the volume. <details><summary>Show example(s)</summary>match volumes with partition label MY-DATA:{{< highlight yaml >}}\nmatch: volume.partition_label == \"MY-DATA\"\n{{< /highlight >}}match xfs volume on disk with serial 'SERIAL123':{{< highlight yaml >}}\nmatch: volume.name == \"xfs\" && disk.serial == \"SERIAL123\"\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n## mount {#ExistingVolumeConfig.mount}\n\nExistingMountSpec describes how the volume is mounted.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`readOnly` |bool |Mount the volume read-only.  | |\n|`disableAccessTime` |bool |If true, disable file access time updates.  | |\n|`secure` |bool |Enable secure mount options (nosuid, nodev).<br><br>Defaults to true for better security.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/externalvolumeconfig.md",
    "content": "---\ndescription: |\n    ExternalVolumeConfig is an external disk mount configuration document.\n    External volumes allow to mount volumes that were created outside of Talos,\n    over the network or API. Volume will be mounted under `/var/mnt/<name>`.\n    The external volume config name should not conflict with user volume names.\ntitle: ExternalVolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ExternalVolumeConfig\nname: mount1 # Name of the mount.\nfilesystemType: virtiofs # Filesystem type.\n# The mount describes additional mount options.\nmount:\n    # Virtiofs mount options.\n    virtiofs:\n        tag: Data # Selector tag for the Virtiofs mount.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the mount.<br><br>Name might be between 1 and 34 characters long and can only contain:<br>lowercase and uppercase ASCII letters, digits, and hyphens.  | |\n|`filesystemType` |FilesystemType |Filesystem type.  |`virtiofs`<br />`nfs`<br /> |\n|`mount` |<a href=\"#ExternalVolumeConfig.mount\">ExternalMountSpec</a> |The mount describes additional mount options.  | |\n\n\n\n\n## mount {#ExternalVolumeConfig.mount}\n\nExternalMountSpec describes how the external volume is mounted.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`readOnly` |bool |Mount the volume read-only.  | |\n|`disableAccessTime` |bool |If true, disable file access time updates.  | |\n|`secure` |bool |Enable secure mount options (nosuid, nodev).<br><br>Defaults to true for better security.  | |\n|`virtiofs` |<a href=\"#ExternalVolumeConfig.mount.virtiofs\">VirtiofsMountSpec</a> |Virtiofs mount options.  | |\n\n\n\n\n### virtiofs {#ExternalVolumeConfig.mount.virtiofs}\n\nVirtiofsMountSpec describes Virtiofs mount options.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`tag` |string |Selector tag for the Virtiofs mount.  | |\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/rawvolumeconfig.md",
    "content": "---\ndescription: |\n    RawVolumeConfig is a raw volume configuration document.\n    Raw volumes allow to create partitions without formatting them.\n     If you want to use local storage, user volumes is a better choice,\n     raw volumes are intended to be used with CSI provisioners.\n    The partition label is automatically generated as `r-<name>`.\ntitle: RawVolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: RawVolumeConfig\nname: local-data # Name of the volume.\n# The provisioning describes how the volume is provisioned.\nprovisioning:\n    # The disk selector expression.\n    diskSelector:\n        match: disk.transport == \"nvme\" # The Common Expression Language (CEL) expression to match the disk.\n    maxSize: 50GiB # The maximum size of the volume, if not specified the volume can grow to the size of the\n\n    # # The minimum size of the volume.\n    # minSize: 2.5GiB\n\n# # The encryption describes how the volume is encrypted.\n# encryption:\n#     provider: luks2 # Encryption provider to use for the encryption.\n#     # Defines the encryption keys generation and storage method.\n#     keys:\n#         - slot: 0 # Key slot number for LUKS2 encryption.\n#           # Key which value is stored in the configuration file.\n#           static:\n#             passphrase: exampleKey # Defines the static passphrase value.\n#\n#           # # KMS managed encryption key.\n#           # kms:\n#           #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n#         - slot: 1 # Key slot number for LUKS2 encryption.\n#           # KMS managed encryption key.\n#           kms:\n#             endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n#     cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n#     blockSize: 4096 # Defines the encryption sector size.\n#     # Additional --perf parameters for the LUKS2 encryption.\n#     options:\n#         - no_read_workqueue\n#         - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the volume.<br><br>Name might be between 1 and 34 characters long and can only contain:<br>lowercase and uppercase ASCII letters, digits, and hyphens.  | |\n|`provisioning` |<a href=\"#RawVolumeConfig.provisioning\">ProvisioningSpec</a> |The provisioning describes how the volume is provisioned.  | |\n|`encryption` |<a href=\"#RawVolumeConfig.encryption\">EncryptionSpec</a> |The encryption describes how the volume is encrypted.  | |\n\n\n\n\n## provisioning {#RawVolumeConfig.provisioning}\n\nProvisioningSpec describes how the volume is provisioned.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`diskSelector` |<a href=\"#RawVolumeConfig.provisioning.diskSelector\">DiskSelector</a> |The disk selector expression.  | |\n|`grow` |bool |Should the volume grow to the size of the disk (if possible).  | |\n|`minSize` |ByteSize |The minimum size of the volume.<br><br>Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nminSize: 2.5GiB\n{{< /highlight >}}</details> | |\n|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the<br>disk.<br><br>Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmaxSize: 50GiB\n{{< /highlight >}}{{< highlight yaml >}}\nmaxSize: 80%\n{{< /highlight >}}</details> | |\n\n\n\n\n### diskSelector {#RawVolumeConfig.provisioning.diskSelector}\n\nDiskSelector selects a disk for the volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the disk. <details><summary>Show example(s)</summary>match disks with size between 120GB and 1TB:{{< highlight yaml >}}\nmatch: disk.size > 120u * GB && disk.size < 1u * TB\n{{< /highlight >}}match SATA disks that are not rotational and not system disks:{{< highlight yaml >}}\nmatch: disk.transport == \"sata\" && !disk.rotational && !system_disk\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n## encryption {#RawVolumeConfig.encryption}\n\nEncryptionSpec represents volume encryption settings.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: exampleKey # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # KMS managed encryption key.\n          kms:\n            endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n    cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n    blockSize: 4096 # Defines the encryption sector size.\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`provider` |EncryptionProviderType |Encryption provider to use for the encryption.  |`luks2`<br /> |\n|`keys` |<a href=\"#RawVolumeConfig.encryption.keys.\">[]EncryptionKey</a> |Defines the encryption keys generation and storage method.  | |\n|`cipher` |string |Cipher to use for the encryption. Depends on the encryption provider. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncipher: aes-xts-plain64\n{{< /highlight >}}</details> |`aes-xts-plain64`<br />`xchacha12,aes-adiantum-plain64`<br />`xchacha20,aes-adiantum-plain64`<br /> |\n|`keySize` |uint |Defines the encryption key length.  | |\n|`blockSize` |uint64 |Defines the encryption sector size. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nblockSize: 4096\n{{< /highlight >}}</details> | |\n|`options` |[]string |Additional --perf parameters for the LUKS2 encryption. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\noptions:\n    - no_read_workqueue\n    - no_write_workqueue\n{{< /highlight >}}</details> |`no_read_workqueue`<br />`no_write_workqueue`<br />`same_cpu_crypt`<br /> |\n\n\n\n\n### keys[] {#RawVolumeConfig.encryption.keys.}\n\nEncryptionKey represents configuration for disk encryption key.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`slot` |int |Key slot number for LUKS2 encryption.  | |\n|`static` |<a href=\"#RawVolumeConfig.encryption.keys..static\">EncryptionKeyStatic</a> |Key which value is stored in the configuration file.  | |\n|`nodeID` |<a href=\"#RawVolumeConfig.encryption.keys..nodeID\">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel.  | |\n|`kms` |<a href=\"#RawVolumeConfig.encryption.keys..kms\">EncryptionKeyKMS</a> |KMS managed encryption key.  | |\n|`tpm` |<a href=\"#RawVolumeConfig.encryption.keys..tpm\">EncryptionKeyTPM</a> |Enable TPM based disk encryption.  | |\n|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.  | |\n\n\n\n\n#### static {#RawVolumeConfig.encryption.keys..static}\n\nEncryptionKeyStatic represents throw away key type.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`passphrase` |string |Defines the static passphrase value.  | |\n\n\n\n\n\n\n#### nodeID {#RawVolumeConfig.encryption.keys..nodeID}\n\nEncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\n\n\n\n\n\n\n\n\n\n#### kms {#RawVolumeConfig.encryption.keys..kms}\n\nEncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    keys:\n        - kms:\n            endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |string |KMS endpoint to Seal/Unseal the key.  | |\n\n\n\n\n\n\n#### tpm {#RawVolumeConfig.encryption.keys..tpm}\n\nEncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`options` |<a href=\"#RawVolumeConfig.encryption.keys..tpm.options\">EncryptionKeyTPMOptions</a> |TPM options for key protection.  | |\n|`checkSecurebootStatusOnEnroll` |bool |Check that Secureboot is enabled in the EFI firmware.<br>If Secureboot is not enabled, the enrollment of the key will fail.  | |\n\n\n\n\n##### options {#RawVolumeConfig.encryption.keys..tpm.options}\n\nEncryptionKeyTPMOptions represents the options for TPM-based key protection.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`pcrs` |[]int |List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.  | |\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/swapvolumeconfig.md",
    "content": "---\ndescription: |\n    SwapVolumeConfig is a disk swap volume configuration document.\n    Swap volume is automatically allocated as a partition on the specified disk\n    and activated as swap, removing a swap volume deactivates swap.\n    The partition label is automatically generated as `s-<name>`.\ntitle: SwapVolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: SwapVolumeConfig\nname: swap1 # Name of the volume.\n# The provisioning describes how the volume is provisioned.\nprovisioning:\n    # The disk selector expression.\n    diskSelector:\n        match: disk.transport == \"nvme\" # The Common Expression Language (CEL) expression to match the disk.\n    minSize: 3GiB # The minimum size of the volume.\n    maxSize: 4GiB # The maximum size of the volume, if not specified the volume can grow to the size of the\n# The encryption describes how the volume is encrypted.\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: swapsecret # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n\n    # # Cipher to use for the encryption. Depends on the encryption provider.\n    # cipher: aes-xts-plain64\n\n    # # Defines the encryption sector size.\n    # blockSize: 4096\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the volume.<br><br>Name might be between 1 and 34 characters long and can only contain:<br>lowercase and uppercase ASCII letters, digits, and hyphens.  | |\n|`provisioning` |<a href=\"#SwapVolumeConfig.provisioning\">ProvisioningSpec</a> |The provisioning describes how the volume is provisioned.  | |\n|`encryption` |<a href=\"#SwapVolumeConfig.encryption\">EncryptionSpec</a> |The encryption describes how the volume is encrypted.  | |\n\n\n\n\n## provisioning {#SwapVolumeConfig.provisioning}\n\nProvisioningSpec describes how the volume is provisioned.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`diskSelector` |<a href=\"#SwapVolumeConfig.provisioning.diskSelector\">DiskSelector</a> |The disk selector expression.  | |\n|`grow` |bool |Should the volume grow to the size of the disk (if possible).  | |\n|`minSize` |ByteSize |The minimum size of the volume.<br><br>Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nminSize: 2.5GiB\n{{< /highlight >}}</details> | |\n|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the<br>disk.<br><br>Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmaxSize: 50GiB\n{{< /highlight >}}{{< highlight yaml >}}\nmaxSize: 80%\n{{< /highlight >}}</details> | |\n\n\n\n\n### diskSelector {#SwapVolumeConfig.provisioning.diskSelector}\n\nDiskSelector selects a disk for the volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the disk. <details><summary>Show example(s)</summary>match disks with size between 120GB and 1TB:{{< highlight yaml >}}\nmatch: disk.size > 120u * GB && disk.size < 1u * TB\n{{< /highlight >}}match SATA disks that are not rotational and not system disks:{{< highlight yaml >}}\nmatch: disk.transport == \"sata\" && !disk.rotational && !system_disk\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n## encryption {#SwapVolumeConfig.encryption}\n\nEncryptionSpec represents volume encryption settings.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: exampleKey # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # KMS managed encryption key.\n          kms:\n            endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n    cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n    blockSize: 4096 # Defines the encryption sector size.\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`provider` |EncryptionProviderType |Encryption provider to use for the encryption.  |`luks2`<br /> |\n|`keys` |<a href=\"#SwapVolumeConfig.encryption.keys.\">[]EncryptionKey</a> |Defines the encryption keys generation and storage method.  | |\n|`cipher` |string |Cipher to use for the encryption. Depends on the encryption provider. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncipher: aes-xts-plain64\n{{< /highlight >}}</details> |`aes-xts-plain64`<br />`xchacha12,aes-adiantum-plain64`<br />`xchacha20,aes-adiantum-plain64`<br /> |\n|`keySize` |uint |Defines the encryption key length.  | |\n|`blockSize` |uint64 |Defines the encryption sector size. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nblockSize: 4096\n{{< /highlight >}}</details> | |\n|`options` |[]string |Additional --perf parameters for the LUKS2 encryption. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\noptions:\n    - no_read_workqueue\n    - no_write_workqueue\n{{< /highlight >}}</details> |`no_read_workqueue`<br />`no_write_workqueue`<br />`same_cpu_crypt`<br /> |\n\n\n\n\n### keys[] {#SwapVolumeConfig.encryption.keys.}\n\nEncryptionKey represents configuration for disk encryption key.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`slot` |int |Key slot number for LUKS2 encryption.  | |\n|`static` |<a href=\"#SwapVolumeConfig.encryption.keys..static\">EncryptionKeyStatic</a> |Key which value is stored in the configuration file.  | |\n|`nodeID` |<a href=\"#SwapVolumeConfig.encryption.keys..nodeID\">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel.  | |\n|`kms` |<a href=\"#SwapVolumeConfig.encryption.keys..kms\">EncryptionKeyKMS</a> |KMS managed encryption key.  | |\n|`tpm` |<a href=\"#SwapVolumeConfig.encryption.keys..tpm\">EncryptionKeyTPM</a> |Enable TPM based disk encryption.  | |\n|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.  | |\n\n\n\n\n#### static {#SwapVolumeConfig.encryption.keys..static}\n\nEncryptionKeyStatic represents throw away key type.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`passphrase` |string |Defines the static passphrase value.  | |\n\n\n\n\n\n\n#### nodeID {#SwapVolumeConfig.encryption.keys..nodeID}\n\nEncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\n\n\n\n\n\n\n\n\n\n#### kms {#SwapVolumeConfig.encryption.keys..kms}\n\nEncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    keys:\n        - kms:\n            endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |string |KMS endpoint to Seal/Unseal the key.  | |\n\n\n\n\n\n\n#### tpm {#SwapVolumeConfig.encryption.keys..tpm}\n\nEncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`options` |<a href=\"#SwapVolumeConfig.encryption.keys..tpm.options\">EncryptionKeyTPMOptions</a> |TPM options for key protection.  | |\n|`checkSecurebootStatusOnEnroll` |bool |Check that Secureboot is enabled in the EFI firmware.<br>If Secureboot is not enabled, the enrollment of the key will fail.  | |\n\n\n\n\n##### options {#SwapVolumeConfig.encryption.keys..tpm.options}\n\nEncryptionKeyTPMOptions represents the options for TPM-based key protection.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`pcrs` |[]int |List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.  | |\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/uservolumeconfig.md",
    "content": "---\ndescription: |\n    UserVolumeConfig is a user volume configuration document.\n    User volume is automatically allocated as a partition on the specified disk\n    and mounted under `/var/mnt/<name>`.\n    The partition label is automatically generated as `u-<name>`.\ntitle: UserVolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: UserVolumeConfig\nname: local-data # Name of the volume.\nvolumeType: directory # Volume type.\n\n# # The encryption describes how the volume is encrypted.\n# encryption:\n#     provider: luks2 # Encryption provider to use for the encryption.\n#     # Defines the encryption keys generation and storage method.\n#     keys:\n#         - slot: 0 # Key slot number for LUKS2 encryption.\n#           # Key which value is stored in the configuration file.\n#           static:\n#             passphrase: exampleKey # Defines the static passphrase value.\n#\n#           # # KMS managed encryption key.\n#           # kms:\n#           #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n#         - slot: 1 # Key slot number for LUKS2 encryption.\n#           # KMS managed encryption key.\n#           kms:\n#             endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n#     cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n#     blockSize: 4096 # Defines the encryption sector size.\n#     # Additional --perf parameters for the LUKS2 encryption.\n#     options:\n#         - no_read_workqueue\n#         - no_write_workqueue\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: UserVolumeConfig\nname: local-data # Name of the volume.\nvolumeType: disk # Volume type.\n# The provisioning describes how the volume is provisioned.\nprovisioning:\n    # The disk selector expression.\n    diskSelector:\n        match: disk.transport == \"nvme\" # The Common Expression Language (CEL) expression to match the disk.\n\n    # # The minimum size of the volume.\n    # minSize: 2.5GiB\n\n    # # The maximum size of the volume, if not specified the volume can grow to the size of the\n    # maxSize: 50GiB\n    # maxSize: 80%\n# The filesystem describes how the volume is formatted.\nfilesystem:\n    type: xfs # Filesystem type. Default is `xfs`.\n# The encryption describes how the volume is encrypted.\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Enable TPM based disk encryption.\n          tpm: {}\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: topsecret # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n\n    # # Cipher to use for the encryption. Depends on the encryption provider.\n    # cipher: aes-xts-plain64\n\n    # # Defines the encryption sector size.\n    # blockSize: 4096\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: UserVolumeConfig\nname: local-data # Name of the volume.\nvolumeType: partition # Volume type.\n# The provisioning describes how the volume is provisioned.\nprovisioning:\n    # The disk selector expression.\n    diskSelector:\n        match: disk.transport == \"nvme\" # The Common Expression Language (CEL) expression to match the disk.\n    maxSize: 50GiB # The maximum size of the volume, if not specified the volume can grow to the size of the\n\n    # # The minimum size of the volume.\n    # minSize: 2.5GiB\n# The filesystem describes how the volume is formatted.\nfilesystem:\n    type: xfs # Filesystem type. Default is `xfs`.\n# The encryption describes how the volume is encrypted.\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Enable TPM based disk encryption.\n          tpm: {}\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: topsecret # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n\n    # # Cipher to use for the encryption. Depends on the encryption provider.\n    # cipher: aes-xts-plain64\n\n    # # Defines the encryption sector size.\n    # blockSize: 4096\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the volume.<br><br>Name might be between 1 and 34 characters long and can only contain:<br>lowercase and uppercase ASCII letters, digits, and hyphens.  | |\n|`volumeType` |VolumeType |Volume type.  |`directory`<br />`disk`<br />`partition`<br /> |\n|`provisioning` |<a href=\"#UserVolumeConfig.provisioning\">ProvisioningSpec</a> |The provisioning describes how the volume is provisioned.  | |\n|`filesystem` |<a href=\"#UserVolumeConfig.filesystem\">FilesystemSpec</a> |The filesystem describes how the volume is formatted.  | |\n|`encryption` |<a href=\"#UserVolumeConfig.encryption\">EncryptionSpec</a> |The encryption describes how the volume is encrypted.  | |\n|`mount` |<a href=\"#UserVolumeConfig.mount\">UserMountSpec</a> |The mount describes additional mount options.  | |\n\n\n\n\n## provisioning {#UserVolumeConfig.provisioning}\n\nProvisioningSpec describes how the volume is provisioned.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`diskSelector` |<a href=\"#UserVolumeConfig.provisioning.diskSelector\">DiskSelector</a> |The disk selector expression.  | |\n|`grow` |bool |Should the volume grow to the size of the disk (if possible).  | |\n|`minSize` |ByteSize |The minimum size of the volume.<br><br>Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nminSize: 2.5GiB\n{{< /highlight >}}</details> | |\n|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the<br>disk.<br><br>Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmaxSize: 50GiB\n{{< /highlight >}}{{< highlight yaml >}}\nmaxSize: 80%\n{{< /highlight >}}</details> | |\n\n\n\n\n### diskSelector {#UserVolumeConfig.provisioning.diskSelector}\n\nDiskSelector selects a disk for the volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the disk. <details><summary>Show example(s)</summary>match disks with size between 120GB and 1TB:{{< highlight yaml >}}\nmatch: disk.size > 120u * GB && disk.size < 1u * TB\n{{< /highlight >}}match SATA disks that are not rotational and not system disks:{{< highlight yaml >}}\nmatch: disk.transport == \"sata\" && !disk.rotational && !system_disk\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n## filesystem {#UserVolumeConfig.filesystem}\n\nFilesystemSpec configures the filesystem for the volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`type` |FilesystemType |Filesystem type. Default is `xfs`.  |`ext4`<br />`xfs`<br /> |\n|`projectQuotaSupport` |bool |Enables project quota support, valid only for 'xfs' filesystem.<br><br>Note: changing this value might require a full remount of the filesystem.  | |\n\n\n\n\n\n\n## encryption {#UserVolumeConfig.encryption}\n\nEncryptionSpec represents volume encryption settings.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: exampleKey # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # KMS managed encryption key.\n          kms:\n            endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n    cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n    blockSize: 4096 # Defines the encryption sector size.\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`provider` |EncryptionProviderType |Encryption provider to use for the encryption.  |`luks2`<br /> |\n|`keys` |<a href=\"#UserVolumeConfig.encryption.keys.\">[]EncryptionKey</a> |Defines the encryption keys generation and storage method.  | |\n|`cipher` |string |Cipher to use for the encryption. Depends on the encryption provider. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncipher: aes-xts-plain64\n{{< /highlight >}}</details> |`aes-xts-plain64`<br />`xchacha12,aes-adiantum-plain64`<br />`xchacha20,aes-adiantum-plain64`<br /> |\n|`keySize` |uint |Defines the encryption key length.  | |\n|`blockSize` |uint64 |Defines the encryption sector size. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nblockSize: 4096\n{{< /highlight >}}</details> | |\n|`options` |[]string |Additional --perf parameters for the LUKS2 encryption. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\noptions:\n    - no_read_workqueue\n    - no_write_workqueue\n{{< /highlight >}}</details> |`no_read_workqueue`<br />`no_write_workqueue`<br />`same_cpu_crypt`<br /> |\n\n\n\n\n### keys[] {#UserVolumeConfig.encryption.keys.}\n\nEncryptionKey represents configuration for disk encryption key.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`slot` |int |Key slot number for LUKS2 encryption.  | |\n|`static` |<a href=\"#UserVolumeConfig.encryption.keys..static\">EncryptionKeyStatic</a> |Key which value is stored in the configuration file.  | |\n|`nodeID` |<a href=\"#UserVolumeConfig.encryption.keys..nodeID\">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel.  | |\n|`kms` |<a href=\"#UserVolumeConfig.encryption.keys..kms\">EncryptionKeyKMS</a> |KMS managed encryption key.  | |\n|`tpm` |<a href=\"#UserVolumeConfig.encryption.keys..tpm\">EncryptionKeyTPM</a> |Enable TPM based disk encryption.  | |\n|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.  | |\n\n\n\n\n#### static {#UserVolumeConfig.encryption.keys..static}\n\nEncryptionKeyStatic represents throw away key type.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`passphrase` |string |Defines the static passphrase value.  | |\n\n\n\n\n\n\n#### nodeID {#UserVolumeConfig.encryption.keys..nodeID}\n\nEncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\n\n\n\n\n\n\n\n\n\n#### kms {#UserVolumeConfig.encryption.keys..kms}\n\nEncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    keys:\n        - kms:\n            endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |string |KMS endpoint to Seal/Unseal the key.  | |\n\n\n\n\n\n\n#### tpm {#UserVolumeConfig.encryption.keys..tpm}\n\nEncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`options` |<a href=\"#UserVolumeConfig.encryption.keys..tpm.options\">EncryptionKeyTPMOptions</a> |TPM options for key protection.  | |\n|`checkSecurebootStatusOnEnroll` |bool |Check that Secureboot is enabled in the EFI firmware.<br>If Secureboot is not enabled, the enrollment of the key will fail.  | |\n\n\n\n\n##### options {#UserVolumeConfig.encryption.keys..tpm.options}\n\nEncryptionKeyTPMOptions represents the options for TPM-based key protection.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`pcrs` |[]int |List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.  | |\n\n\n\n\n\n\n\n\n\n\n\n\n## mount {#UserVolumeConfig.mount}\n\nUserMountSpec describes how the volume is mounted.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disableAccessTime` |bool |If true, disable file access time updates.  | |\n|`secure` |bool |Enable secure mount options (nosuid, nodev).<br><br>Defaults to true for better security.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/volumeconfig.md",
    "content": "---\ndescription: |\n    VolumeConfig is a system volume configuration document.\n    Note: at the moment, only `STATE`, `EPHEMERAL` and `IMAGE-CACHE` system volumes are supported.\ntitle: VolumeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: VolumeConfig\nname: EPHEMERAL # Name of the volume.\n# The provisioning describes how the volume is provisioned.\nprovisioning:\n    # The disk selector expression.\n    diskSelector:\n        match: disk.transport == \"nvme\" # The Common Expression Language (CEL) expression to match the disk.\n    maxSize: 50GiB # The maximum size of the volume, if not specified the volume can grow to the size of the\n\n    # # The minimum size of the volume.\n    # minSize: 2.5GiB\n\n# # The encryption describes how the volume is encrypted.\n# encryption:\n#     provider: luks2 # Encryption provider to use for the encryption.\n#     # Defines the encryption keys generation and storage method.\n#     keys:\n#         - slot: 0 # Key slot number for LUKS2 encryption.\n#           # Key which value is stored in the configuration file.\n#           static:\n#             passphrase: exampleKey # Defines the static passphrase value.\n#\n#           # # KMS managed encryption key.\n#           # kms:\n#           #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n#         - slot: 1 # Key slot number for LUKS2 encryption.\n#           # KMS managed encryption key.\n#           kms:\n#             endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n#     cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n#     blockSize: 4096 # Defines the encryption sector size.\n#     # Additional --perf parameters for the LUKS2 encryption.\n#     options:\n#         - no_read_workqueue\n#         - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the volume.  | |\n|`provisioning` |<a href=\"#VolumeConfig.provisioning\">ProvisioningSpec</a> |The provisioning describes how the volume is provisioned.  | |\n|`encryption` |<a href=\"#VolumeConfig.encryption\">EncryptionSpec</a> |The encryption describes how the volume is encrypted.  | |\n|`mount` |<a href=\"#VolumeConfig.mount\">MountSpec</a> |The mount describes additional mount options.  | |\n\n\n\n\n## provisioning {#VolumeConfig.provisioning}\n\nProvisioningSpec describes how the volume is provisioned.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`diskSelector` |<a href=\"#VolumeConfig.provisioning.diskSelector\">DiskSelector</a> |The disk selector expression.  | |\n|`grow` |bool |Should the volume grow to the size of the disk (if possible).  | |\n|`minSize` |ByteSize |The minimum size of the volume.<br><br>Size is specified in bytes, but can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nminSize: 2.5GiB\n{{< /highlight >}}</details> | |\n|`maxSize` |Size |The maximum size of the volume, if not specified the volume can grow to the size of the<br>disk.<br><br>Size is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmaxSize: 50GiB\n{{< /highlight >}}{{< highlight yaml >}}\nmaxSize: 80%\n{{< /highlight >}}</details> | |\n\n\n\n\n### diskSelector {#VolumeConfig.provisioning.diskSelector}\n\nDiskSelector selects a disk for the volume.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the disk. <details><summary>Show example(s)</summary>match disks with size between 120GB and 1TB:{{< highlight yaml >}}\nmatch: disk.size > 120u * GB && disk.size < 1u * TB\n{{< /highlight >}}match SATA disks that are not rotational and not system disks:{{< highlight yaml >}}\nmatch: disk.transport == \"sata\" && !disk.rotational && !system_disk\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n## encryption {#VolumeConfig.encryption}\n\nEncryptionSpec represents volume encryption settings.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    provider: luks2 # Encryption provider to use for the encryption.\n    # Defines the encryption keys generation and storage method.\n    keys:\n        - slot: 0 # Key slot number for LUKS2 encryption.\n          # Key which value is stored in the configuration file.\n          static:\n            passphrase: exampleKey # Defines the static passphrase value.\n\n          # # KMS managed encryption key.\n          # kms:\n          #     endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n        - slot: 1 # Key slot number for LUKS2 encryption.\n          # KMS managed encryption key.\n          kms:\n            endpoint: https://example-kms-endpoint.com # KMS endpoint to Seal/Unseal the key.\n    cipher: aes-xts-plain64 # Cipher to use for the encryption. Depends on the encryption provider.\n    blockSize: 4096 # Defines the encryption sector size.\n\n    # # Additional --perf parameters for the LUKS2 encryption.\n    # options:\n    #     - no_read_workqueue\n    #     - no_write_workqueue\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`provider` |EncryptionProviderType |Encryption provider to use for the encryption.  |`luks2`<br /> |\n|`keys` |<a href=\"#VolumeConfig.encryption.keys.\">[]EncryptionKey</a> |Defines the encryption keys generation and storage method.  | |\n|`cipher` |string |Cipher to use for the encryption. Depends on the encryption provider. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncipher: aes-xts-plain64\n{{< /highlight >}}</details> |`aes-xts-plain64`<br />`xchacha12,aes-adiantum-plain64`<br />`xchacha20,aes-adiantum-plain64`<br /> |\n|`keySize` |uint |Defines the encryption key length.  | |\n|`blockSize` |uint64 |Defines the encryption sector size. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nblockSize: 4096\n{{< /highlight >}}</details> | |\n|`options` |[]string |Additional --perf parameters for the LUKS2 encryption. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\noptions:\n    - no_read_workqueue\n    - no_write_workqueue\n{{< /highlight >}}</details> |`no_read_workqueue`<br />`no_write_workqueue`<br />`same_cpu_crypt`<br /> |\n\n\n\n\n### keys[] {#VolumeConfig.encryption.keys.}\n\nEncryptionKey represents configuration for disk encryption key.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`slot` |int |Key slot number for LUKS2 encryption.  | |\n|`static` |<a href=\"#VolumeConfig.encryption.keys..static\">EncryptionKeyStatic</a> |Key which value is stored in the configuration file.  | |\n|`nodeID` |<a href=\"#VolumeConfig.encryption.keys..nodeID\">EncryptionKeyNodeID</a> |Deterministically generated key from the node UUID and PartitionLabel.  | |\n|`kms` |<a href=\"#VolumeConfig.encryption.keys..kms\">EncryptionKeyKMS</a> |KMS managed encryption key.  | |\n|`tpm` |<a href=\"#VolumeConfig.encryption.keys..tpm\">EncryptionKeyTPM</a> |Enable TPM based disk encryption.  | |\n|`lockToState` |bool |Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.  | |\n\n\n\n\n#### static {#VolumeConfig.encryption.keys..static}\n\nEncryptionKeyStatic represents throw away key type.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`passphrase` |string |Defines the static passphrase value.  | |\n\n\n\n\n\n\n#### nodeID {#VolumeConfig.encryption.keys..nodeID}\n\nEncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\n\n\n\n\n\n\n\n\n\n#### kms {#VolumeConfig.encryption.keys..kms}\n\nEncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\n\n\n\n{{< highlight yaml >}}\nencryption:\n    keys:\n        - kms:\n            endpoint: https://192.168.88.21:4443 # KMS endpoint to Seal/Unseal the key.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |string |KMS endpoint to Seal/Unseal the key.  | |\n\n\n\n\n\n\n#### tpm {#VolumeConfig.encryption.keys..tpm}\n\nEncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`options` |<a href=\"#VolumeConfig.encryption.keys..tpm.options\">EncryptionKeyTPMOptions</a> |TPM options for key protection.  | |\n|`checkSecurebootStatusOnEnroll` |bool |Check that Secureboot is enabled in the EFI firmware.<br>If Secureboot is not enabled, the enrollment of the key will fail.  | |\n\n\n\n\n##### options {#VolumeConfig.encryption.keys..tpm.options}\n\nEncryptionKeyTPMOptions represents the options for TPM-based key protection.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`pcrs` |[]int |List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.  | |\n\n\n\n\n\n\n\n\n\n\n\n\n## mount {#VolumeConfig.mount}\n\nMountSpec describes how the volume is mounted.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`secure` |bool |Enable secure mount options (nosuid, nodev).<br><br>Defaults to true for better security.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/block/zswapconfig.md",
    "content": "---\ndescription: |\n    ZswapConfig is a zswap (compressed memory) configuration document.\n    When zswap is enabled, Linux kernel compresses pages that would otherwise be swapped out to disk.\n    The compressed pages are stored in a memory pool, which is used to avoid writing to disk\n    when the system is under memory pressure.\ntitle: ZswapConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ZswapConfig\nmaxPoolPercent: 25 # The maximum percent of memory that zswap can use.\nshrinkerEnabled: true # Enable the shrinker feature: kernel might move\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`maxPoolPercent` |int |The maximum percent of memory that zswap can use.<br>This is a percentage of the total system memory.<br>The value must be between 0 and 100.  | |\n|`shrinkerEnabled` |bool |Enable the shrinker feature: kernel might move<br>cold pages from zswap to swap device to free up memory<br>for other use cases.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/cri/_index.md",
    "content": "---\ndescription: \"\"\ntitle: cri\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/cri/registryauthconfig.md",
    "content": "---\ndescription: RegistryAuthConfig configures authentication for a registry endpoint.\ntitle: RegistryAuthConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: RegistryAuthConfig\nname: my-private-registry.local:5000 # Registry endpoint to apply the authentication configuration to.\nusername: my-username # Username/password authentication.\npassword: my-password # Username/password authentication.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Registry endpoint to apply the authentication configuration to.<br><br>Registry endpoint is the hostname part of the endpoint URL,<br>e.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.<br><br>The authentication configuration will apply to all image pulls for this<br>registry endpoint, by Talos or any Kubernetes workloads.  | |\n|`username` |string |Username/password authentication.  | |\n|`password` |string |Username/password authentication.  | |\n|`auth` |string |Raw authentication string.  | |\n|`identityToken` |string |Identity token authentication.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/cri/registrymirrorconfig.md",
    "content": "---\ndescription: RegistryMirrorConfig configures an image registry mirror.\ntitle: RegistryMirrorConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: RegistryMirrorConfig\nname: registry.k8s.io # Registry name to apply the mirror configuration to.\n# List of mirror endpoints for the registry.\nendpoints:\n    - url: https://my-private-registry.local:5000 # The URL of the registry mirror endpoint.\n    - url: http://my-harbor/v2/registry-k8s.io/ # The URL of the registry mirror endpoint.\n      overridePath: true # Use endpoint path as supplied, without adding `/v2/` suffix.\nskipFallback: true # Skip fallback to the original registry if none of the mirrors are available\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Registry name to apply the mirror configuration to.<br><br>Registry name is the first segment of image identifier, with 'docker.io'<br>being default one.<br><br>A special name '*' can be used to define mirror configuration<br>that applies to all registries.  | |\n|`endpoints` |<a href=\"#RegistryMirrorConfig.endpoints.\">[]RegistryEndpoint</a> |List of mirror endpoints for the registry.<br>Mirrors will be used in the order they are specified,<br>falling back to the default registry is `skipFallback` is not set to true.  | |\n|`skipFallback` |bool |Skip fallback to the original registry if none of the mirrors are available<br>or contain the requested image.  | |\n\n\n\n\n## endpoints[] {#RegistryMirrorConfig.endpoints.}\n\nRegistryEndpoint defines a registry mirror endpoint.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`url` |URL |The URL of the registry mirror endpoint. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nurl: https://my-registry-mirror.local:5000\n{{< /highlight >}}</details> | |\n|`overridePath` |bool |Use endpoint path as supplied, without adding `/v2/` suffix.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/cri/registrytlsconfig.md",
    "content": "---\ndescription: RegistryTLSConfig configures TLS for a registry endpoint.\ntitle: RegistryTLSConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: RegistryTLSConfig\nname: my-private-registry.local:5000 # Registry endpoint to apply the TLS configuration to.\nca: |- # CA registry certificate to add the list of trusted certificates.\n    -----BEGIN CERTIFICATE-----\n    MIID...IDAQAB\n    -----END CERTIFICATE-----\n\n# # Enable mutual TLS authentication with the registry.\n# clientIdentity:\n#     cert: |-\n#         -----BEGIN CERTIFICATE-----\n#         MIID...IDAQAB\n#         -----END CERTIFICATE-----\n#     key: |-\n#         -----BEGIN PRIVATE KEY-----\n#         MIIE...AB\n#         -----END PRIVATE KEY-----\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Registry endpoint to apply the TLS configuration to.<br><br>Registry endpoint is the hostname part of the endpoint URL,<br>e.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.<br><br>The TLS configuration makes sense only for HTTPS endpoints.<br>The TLS configuration will apply to all image pulls for this<br>registry endpoint, by Talos or any Kubernetes workloads.  | |\n|`clientIdentity` |CertificateAndKey |Enable mutual TLS authentication with the registry.<br>Client certificate and key should be PEM-encoded. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nclientIdentity:\n    cert: |-\n        -----BEGIN CERTIFICATE-----\n        MIID...IDAQAB\n        -----END CERTIFICATE-----\n    key: |-\n        -----BEGIN PRIVATE KEY-----\n        MIIE...AB\n        -----END PRIVATE KEY-----\n{{< /highlight >}}</details> | |\n|`ca` |string |CA registry certificate to add the list of trusted certificates.<br>Certificate should be PEM-encoded.  | |\n|`insecureSkipVerify` |bool |Skip TLS server certificate verification (not recommended).  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/extensions/_index.md",
    "content": "---\ndescription: |\n    Package extensions provides extensions config documents.\ntitle: extensions\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/extensions/extensionserviceconfig.md",
    "content": "---\ndescription: ExtensionServiceConfig is a extensionserviceconfig document.\ntitle: ExtensionServiceConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ExtensionServiceConfig\nname: nut-client # Name of the extension service.\n# The config files for the extension service.\nconfigFiles:\n    - content: MONITOR ${upsmonHost} 1 remote username password # The content of the extension service config file.\n      mountPath: /usr/local/etc/nut/upsmon.conf # The mount path of the extension service config file.\n# The environment for the extension service.\nenvironment:\n    - NUT_UPS=upsname\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the extension service.  | |\n|`configFiles` |<a href=\"#ExtensionServiceConfig.configFiles.\">[]ConfigFile</a> |The config files for the extension service.  | |\n|`environment` |[]string |The environment for the extension service.  | |\n\n\n\n\n## configFiles[] {#ExtensionServiceConfig.configFiles.}\n\nConfigFile is a config file for extension services.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`content` |string |The content of the extension service config file.  | |\n|`mountPath` |string |The mount path of the extension service config file.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/hardware/_index.md",
    "content": "---\ndescription: |\n    Package hardware provides hardware related config documents.\ntitle: hardware\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/hardware/pcidriverrebindconfig.md",
    "content": "---\ndescription: PCIDriverRebindConfig allows to configure PCI driver rebinds.\ntitle: PCIDriverRebindConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: PCIDriverRebindConfig\nname: 0000:04:00.00 # PCI device id\ntargetDriver: vfio-pci # Target driver to rebind the PCI device to.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |PCI device id  | |\n|`targetDriver` |string |Target driver to rebind the PCI device to.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/_index.md",
    "content": "---\ndescription: |\n    Package network provides network machine configuration documents.\ntitle: network\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/blackholerouteconfig.md",
    "content": "---\ndescription: BlackholeRouteConfig is a config document to configure blackhole routes.\ntitle: BlackholeRouteConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: BlackholeRouteConfig\nname: 10.0.0.0/12 # Route destination as an address prefix.\nmetric: 100 # The optional metric for the route.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Route destination as an address prefix. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: 10.0.0.0/12\n{{< /highlight >}}</details> | |\n|`metric` |uint32 |The optional metric for the route.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/bondconfig.md",
    "content": "---\ndescription: BondConfig is a config document to create a bond (link aggregation) over a set of links.\ntitle: BondConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: BondConfig\nname: bond.int # Name of the bond link (interface) to be created.\n# Names of the links (interfaces) on which the bond will be created.\nlinks:\n    - enp1s2\n    - enp1s2\nbondMode: 802.3ad # Bond mode.\nmiimon: 100 # Link monitoring frequency in milliseconds.\nupdelay: 200 # The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\ndowndelay: 200 # The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\nxmitHashPolicy: layer3+4 # Selects the transmit hash policy to use for slave selection.\nlacpRate: slow # LACPDU frames periodic transmission rate.\nadActorSysPrio: 65535 # Actor system priority for 802.3ad.\nresendIGMP: 1 # The number of times IGMP packets should be resent.\npacketsPerSlave: 1 # The number of packets to transmit through a slave before moving to the next one.\n# Configure addresses to be statically assigned to the link.\naddresses:\n    - address: 10.15.0.3/16 # IP address to be assigned to the link.\n# Configure routes to be statically created via the link.\nroutes:\n    - destination: 10.0.0.0/8 # The route's destination as an address prefix.\n      gateway: 10.15.0.1 # The route's gateway (if empty, creates link scope route).\n\n# # Override the hardware (MAC) address of the link.\n# hardwareAddr: 2e:3c:4d:5e:6f:70\n\n# # ARP link monitoring frequency in milliseconds.\n# arpInterval: 1000\n\n# # The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\n# arpIpTargets:\n#     - 10.15.0.1\n\n# # The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\n# nsIp6Targets:\n#     - fd00::1\n\n# # Specifies whether or not ARP probes and replies should be validated.\n# arpValidate: active\n\n# # Specifies whether ARP probes should be sent to any or all targets.\n# arpAllTargets: all\n\n# # Specifies whether active-backup mode should set all slaves to the same MAC address\n# failOverMac: active\n\n# # Aggregate selection policy for 802.3ad.\n# adSelect: stable\n\n# # Whether to send LACPDU frames periodically.\n# adLACPActive: on\n\n# # Policy under which the primary slave should be reselected.\n# primaryReselect: always\n\n# # Whether dynamic shuffling of flows is enabled in tlb or alb mode.\n# tlbLogicalLb: 1\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the bond link (interface) to be created. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: bond.ext\n{{< /highlight >}}</details> | |\n|`hardwareAddr` |HardwareAddr |Override the hardware (MAC) address of the link. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}</details> | |\n|`links` |[]string |Names of the links (interfaces) on which the bond will be created.<br>Link aliases can be used here as well. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nlinks:\n    - enp0s3\n    - enp0s8\n{{< /highlight >}}</details> | |\n|`bondMode` |BondMode |Bond mode. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nbondMode: 802.3ad\n{{< /highlight >}}</details> |`balance-rr`<br />`active-backup`<br />`balance-xor`<br />`broadcast`<br />`802.3ad`<br />`balance-tlb`<br />`balance-alb`<br /> |\n|`miimon` |uint32 |Link monitoring frequency in milliseconds. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmiimon: 200\n{{< /highlight >}}</details> | |\n|`updelay` |uint32 |The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nupdelay: 300\n{{< /highlight >}}</details> | |\n|`downdelay` |uint32 |The time, in milliseconds, to wait before disabling a slave after a link failure has been detected. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndowndelay: 100\n{{< /highlight >}}</details> | |\n|`useCarrier` |bool |Specifies whether or not miimon should use MII or ETHTOOL.  | |\n|`xmitHashPolicy` |BondXmitHashPolicy |Selects the transmit hash policy to use for slave selection. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nxmitHashPolicy: layer2\n{{< /highlight >}}</details> |`layer2`<br />`layer3+4`<br />`layer2+3`<br />`encap2+3`<br />`encap3+4`<br /> |\n|`arpInterval` |uint32 |ARP link monitoring frequency in milliseconds. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\narpInterval: 1000\n{{< /highlight >}}</details> | |\n|`arpIpTargets` |[]Addr |The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.<br>Maximum of 16 targets are supported. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\narpIpTargets:\n    - 10.15.0.1\n{{< /highlight >}}</details> | |\n|`nsIp6Targets` |[]Addr |The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.<br>Maximum of 16 targets are supported. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nnsIp6Targets:\n    - fd00::1\n{{< /highlight >}}</details> | |\n|`arpValidate` |ARPValidate |Specifies whether or not ARP probes and replies should be validated. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\narpValidate: active\n{{< /highlight >}}</details> |`none`<br />`active`<br />`backup`<br />`all`<br />`filter`<br />`filter-active`<br />`filter-backup`<br /> |\n|`arpAllTargets` |ARPAllTargets |Specifies whether ARP probes should be sent to any or all targets. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\narpAllTargets: all\n{{< /highlight >}}</details> |`any`<br />`all`<br /> |\n|`lacpRate` |LACPRate |LACPDU frames periodic transmission rate. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nlacpRate: fast\n{{< /highlight >}}</details> |`slow`<br />`fast`<br /> |\n|`failOverMac` |FailOverMAC |Specifies whether active-backup mode should set all slaves to the same MAC address<br>at enslavement, when enabled, or perform special handling. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfailOverMac: active\n{{< /highlight >}}</details> |`none`<br />`active`<br />`follow`<br /> |\n|`adSelect` |ADSelect |Aggregate selection policy for 802.3ad. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadSelect: stable\n{{< /highlight >}}</details> |`stable`<br />`bandwidth`<br />`count`<br /> |\n|`adActorSysPrio` |uint16 |Actor system priority for 802.3ad. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadActorSysPrio: 65535\n{{< /highlight >}}</details> | |\n|`adUserPortKey` |uint16 |User port key (upper 10 bits) for 802.3ad. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadUserPortKey: 0\n{{< /highlight >}}</details> | |\n|`adLACPActive` |ADLACPActive |Whether to send LACPDU frames periodically. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadLACPActive: on\n{{< /highlight >}}</details> |`on`<br />`off`<br /> |\n|`primaryReselect` |PrimaryReselect |Policy under which the primary slave should be reselected. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nprimaryReselect: always\n{{< /highlight >}}</details> |`always`<br />`better`<br />`failure`<br /> |\n|`resendIGMP` |uint32 |The number of times IGMP packets should be resent.  | |\n|`minLinks` |uint32 |The minimum number of active links required for the bond to be considered active.  | |\n|`lpInterval` |uint32 |The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.  | |\n|`packetsPerSlave` |uint32 |The number of packets to transmit through a slave before moving to the next one.  | |\n|`numPeerNotif` |uint8 |The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)<br>to be issued after a failover event.  | |\n|`tlbLogicalLb` |uint8 |Whether dynamic shuffling of flows is enabled in tlb or alb mode. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ntlbLogicalLb: 1\n{{< /highlight >}}</details> | |\n|`allSlavesActive` |uint8 |Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nallSlavesActive: 0\n{{< /highlight >}}</details> | |\n|`peerNotifDelay` |uint32 |The delay, in milliseconds, between each peer notification.  | |\n|`missedMax` |uint8 |The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.  | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#BondConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#BondConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## addresses[] {#BondConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#BondConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/bridgeconfig.md",
    "content": "---\ndescription: BridgeConfig is a config document to create a Bridge (link aggregation) over a set of links.\ntitle: BridgeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: BridgeConfig\nname: bridge.3 # Name of the bridge link (interface) to be created.\n# Names of the links (interfaces) to be aggregated.\nlinks:\n    - eno1\n    - eno2\n# Bridge STP (Spanning Tree Protocol) configuration.\nstp:\n    enabled: true # Enable or disable STP on the bridge.\n\n# # Override the hardware (MAC) address of the link.\n# hardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the bridge link (interface) to be created. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: Bridge.ext\n{{< /highlight >}}</details> | |\n|`hardwareAddr` |HardwareAddr |Override the hardware (MAC) address of the link. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}</details> | |\n|`links` |[]string |Names of the links (interfaces) to be aggregated.<br>Link aliases can be used here as well. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nlinks:\n    - enp1s3\n    - enp1s2\n{{< /highlight >}}</details> | |\n|`stp` |<a href=\"#BridgeConfig.stp\">BridgeSTPConfig</a> |Bridge STP (Spanning Tree Protocol) configuration.  | |\n|`vlan` |<a href=\"#BridgeConfig.vlan\">BridgeVLANConfig</a> |Bridge VLAN configuration.  | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#BridgeConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#BridgeConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## stp {#BridgeConfig.stp}\n\nBridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable or disable STP on the bridge. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nenabled: true\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n## vlan {#BridgeConfig.vlan}\n\nBridgeVLANConfig is a bridge VLAN configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`filtering` |bool |Enable or disable VLAN filtering on the bridge. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfiltering: true\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n## addresses[] {#BridgeConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#BridgeConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/dhcpv4config.md",
    "content": "---\ndescription: DHCPv4Config is a config document to configure DHCPv4 on a network link.\ntitle: DHCPv4Config\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: DHCPv4Config\nname: enp0s2 # Name of the link (interface).\nclientIdentifier: mac # Client identifier to use when communicating with DHCP servers.\n\n# # Raw value of the DUID to use as client identifier.\n# duidRaw: 00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the link (interface). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: enp0s2\n{{< /highlight >}}</details> | |\n|`routeMetric` |uint32 |An optional metric for the routes received from the DHCP server.<br><br>Lower values indicate higher priority.<br>Default value is 1024.  | |\n|`ignoreHostname` |bool |Ignore hostname received from the DHCP server.  | |\n|`clientIdentifier` |ClientIdentifier |Client identifier to use when communicating with DHCP servers.<br><br>Defaults to 'mac' if not set.  |`none`<br />`mac`<br />`duid`<br /> |\n|`duidRaw` |HardwareAddr |Raw value of the DUID to use as client identifier.<br><br>This field is only used if 'clientIdentifier' is set to 'duid'. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nduidRaw: 00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/dhcpv6config.md",
    "content": "---\ndescription: DHCPv6Config is a config document to configure DHCPv6 on a network link.\ntitle: DHCPv6Config\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: DHCPv6Config\nname: enp0s2 # Name of the link (interface).\n\n# # Raw value of the DUID to use as client identifier.\n# duidRaw: 00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the link (interface). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: enp0s2\n{{< /highlight >}}</details> | |\n|`routeMetric` |uint32 |An optional metric for the routes received from the DHCP server.<br><br>Lower values indicate higher priority.<br>Default value is 1024.  | |\n|`ignoreHostname` |bool |Ignore hostname received from the DHCP server.  | |\n|`clientIdentifier` |ClientIdentifier |Client identifier to use when communicating with DHCP servers.<br><br>Defaults to 'mac' if not set.  |`none`<br />`mac`<br />`duid`<br /> |\n|`duidRaw` |HardwareAddr |Raw value of the DUID to use as client identifier.<br><br>This field is only used if 'clientIdentifier' is set to 'duid'. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nduidRaw: 00:01:00:01:23:45:67:89:ab:cd:ef:01:23:45\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/dummylinkconfig.md",
    "content": "---\ndescription: DummyLinkConfig is a config document to create a dummy (virtual) network link.\ntitle: DummyLinkConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: DummyLinkConfig\nname: dummy1 # Name of the dummy link (interface).\n# Configure addresses to be statically assigned to the link.\naddresses:\n    - address: 192.168.1.100/24 # IP address to be assigned to the link.\n\n# # Override the hardware (MAC) address of the link.\n# hardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the dummy link (interface). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: dummy1\n{{< /highlight >}}</details> | |\n|`hardwareAddr` |HardwareAddr |Override the hardware (MAC) address of the link. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}</details> | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#DummyLinkConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#DummyLinkConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## addresses[] {#DummyLinkConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#DummyLinkConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/ethernetconfig.md",
    "content": "---\ndescription: EthernetConfig is a config document to configure Ethernet interfaces.\ntitle: EthernetConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: EthernetConfig\nname: enp0s2 # Name of the link (interface).\n# Configuration for Ethernet features.\nfeatures:\n    tx-tcp-segmentation: false\n# Configuration for Ethernet link rings.\nrings:\n    rx: 256 # Number of RX rings.\n# Configuration for Ethernet link channels.\nchannels:\n    rx: 4 # Number of RX channels.\n\n# # Wake-on-LAN modes to enable.\n# wakeOnLan:\n#     - unicast\n#     - magic\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the link (interface).  | |\n|`features` |map[string]bool |Configuration for Ethernet features.<br><br>Set of features available and whether they can be enabled or disabled is driver specific.<br>Use `talosctl get ethernetstatus <link> -o yaml` to get the list of available features and<br>their current status.  | |\n|`rings` |<a href=\"#EthernetConfig.rings\">EthernetRingsConfig</a> |Configuration for Ethernet link rings.<br><br>This is similar to `ethtool -G` command.  | |\n|`channels` |<a href=\"#EthernetConfig.channels\">EthernetChannelsConfig</a> |Configuration for Ethernet link channels.<br><br>This is similar to `ethtool -L` command.  | |\n|`wakeOnLan` |[]WOLMode |Wake-on-LAN modes to enable.<br><br>If this field is omitted, Wake-on-LAN configuration is not changed.<br>An empty list disables Wake-on-LAN.<br><br>This is similar to `ethtool -s <link> wol <options>` command. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nwakeOnLan:\n    - unicast\n    - magic\n{{< /highlight >}}</details> |`phy`<br />`unicast`<br />`multicast`<br />`broadcast`<br />`arp`<br />`magic`<br />`magicsecure`<br />`filter`<br /> |\n\n\n\n\n## rings {#EthernetConfig.rings}\n\nEthernetRingsConfig is a configuration for Ethernet link rings.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`rx` |uint32 |Number of RX rings.  | |\n|`tx` |uint32 |Number of TX rings.  | |\n|`rx-mini` |uint32 |Number of RX mini rings.  | |\n|`rx-jumbo` |uint32 |Number of RX jumbo rings.  | |\n|`rx-buf-len` |uint32 |RX buffer length.  | |\n|`cqe-size` |uint32 |CQE size.  | |\n|`tx-push` |bool |TX push enabled.  | |\n|`rx-push` |bool |RX push enabled.  | |\n|`tx-push-buf-len` |uint32 |TX push buffer length.  | |\n|`tcp-data-split` |bool |TCP data split enabled.  | |\n\n\n\n\n\n\n## channels {#EthernetConfig.channels}\n\nEthernetChannelsConfig is a configuration for Ethernet link channels.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`rx` |uint32 |Number of RX channels.  | |\n|`tx` |uint32 |Number of TX channels.  | |\n|`other` |uint32 |Number of other channels.  | |\n|`combined` |uint32 |Number of combined channels.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/hcloudvipconfig.md",
    "content": "---\ndescription: |\n    HCloudVIPConfig is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\n    Virtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\n    Any other use cases are not supported and may lead to unexpected behavior.\n    Virtual IP will be announced from only one node at a time using Hetzner Cloud APIs.\ntitle: HCloudVIPConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: HCloudVIPConfig\nname: int0 # IP address to be advertised as a Layer 2 VIP.\nlink: enp0s2 # Name of the link to assign the VIP to.\napiToken: my-secret-token # Specifies the Hetzner Cloud API Token.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |IP address to be advertised as a Layer 2 VIP. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: 192.168.100.1\n{{< /highlight >}}{{< highlight yaml >}}\nname: fd00::1\n{{< /highlight >}}</details> | |\n|`link` |string |Name of the link to assign the VIP to.<br><br>Selector must match exactly one link, otherwise an error is returned.<br>If multiple selectors match the same link, the first one is used.  | |\n|`apiToken` |string |Specifies the Hetzner Cloud API Token.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/hostnameconfig.md",
    "content": "---\ndescription: 'HostnameConfig is a config document to configure the hostname: either a static hostname or an automatically generated hostname.'\ntitle: HostnameConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: HostnameConfig\nhostname: worker-33 # A static hostname to set for the machine.\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: HostnameConfig\nauto: stable # A method to automatically generate a hostname for the machine.\n\n# # A static hostname to set for the machine.\n# hostname: controlplane1\n# hostname: controlplane1.example.org\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`auto` |AutoHostnameKind |A method to automatically generate a hostname for the machine.<br><br>There are two methods available:<br>  - `stable` - generates a stable hostname based on machine identity<br>  - `off` - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).<br><br>Automatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.<br>Conflicts with `hostname` field.  |`stable`<br />`off`<br /> |\n|`hostname` |string |A static hostname to set for the machine.<br><br>This hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.<br>Conflicts with `auto` field. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhostname: controlplane1\n{{< /highlight >}}{{< highlight yaml >}}\nhostname: controlplane1.example.org\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/kubespanconfig.md",
    "content": "---\ndescription: KubeSpanConfig is a config document to configure KubeSpan.\ntitle: KubeSpanConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: KubeSpanConfig\nenabled: true # Enable the KubeSpan feature.\nadvertiseKubernetesNetworks: false # Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\nallowDownPeerBypass: false # Skip sending traffic via KubeSpan if the peer connection state is not up.\nharvestExtraEndpoints: false # KubeSpan can collect and publish extra endpoints for each member of the cluster\nmtu: 1420 # KubeSpan link MTU size.\n# KubeSpan advanced filtering of network addresses.\nfilters:\n    # Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\n    endpoints:\n        - 0.0.0.0/0\n        - ::/0\n    # Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\n    excludeAdvertisedNetworks:\n        - 192.168.1.0/24\n        - 2003::/16\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable the KubeSpan feature.<br>Cluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.  | |\n|`advertiseKubernetesNetworks` |bool |Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.<br>If disabled, CNI handles pod-to-pod traffic encapsulation.<br>If enabled, KubeSpan takes over pod-to-pod traffic directly.  | |\n|`allowDownPeerBypass` |bool |Skip sending traffic via KubeSpan if the peer connection state is not up.<br>This provides configurable choice between connectivity and security.  | |\n|`harvestExtraEndpoints` |bool |KubeSpan can collect and publish extra endpoints for each member of the cluster<br>based on Wireguard endpoint information for each peer.<br>Disabled by default. Do not enable with high peer counts (>50).  | |\n|`mtu` |uint32 |KubeSpan link MTU size.<br>Default value is 1420.  | |\n|`filters` |<a href=\"#KubeSpanConfig.filters\">KubeSpanFiltersConfig</a> |KubeSpan advanced filtering of network addresses.<br>Settings are optional and apply only to this node.  | |\n\n\n\n\n## filters {#KubeSpanConfig.filters}\n\nKubeSpanFiltersConfig configures KubeSpan endpoint filters.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoints` |[]string |Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.<br><br>By default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.<br><br>Default value: no filtering. <details><summary>Show example(s)</summary>Exclude addresses in 192.168.0.0/16 subnet.:{{< highlight yaml >}}\nendpoints:\n    - 0.0.0.0/0\n    - '!192.168.0.0/16'\n    - ::/0\n{{< /highlight >}}</details> | |\n|`excludeAdvertisedNetworks` |[]Prefix |Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.<br><br>By default, all networks are advertised.<br>Use this filter to exclude some networks from being advertised.<br><br>Note: excluded networks will not be reachable over KubeSpan, so make sure<br>these networks are still reachable via some other route (e.g., direct connection).<br><br>Default value: no filtering. <details><summary>Show example(s)</summary>Exclude private networks from being advertised.:{{< highlight yaml >}}\nexcludeAdvertisedNetworks:\n    - 192.168.1.0/24\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/kubespanendpointsconfig.md",
    "content": "---\ndescription: KubeSpanEndpointsConfig is a config document to configure KubeSpan endpoints.\ntitle: KubeSpanEndpointsConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: KubeSpanEndpointsConfig\n# A list of extra Wireguard endpoints to announce from this machine.\nextraAnnouncedEndpoints:\n    - 192.168.13.46:52000\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`extraAnnouncedEndpoints` |[]AddrPort |A list of extra Wireguard endpoints to announce from this machine.<br><br>Talos automatically adds endpoints based on machine addresses, public IP, etc.<br>This field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/layer2vipconfig.md",
    "content": "---\ndescription: |\n    Layer2VIPConfig is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\n    Virtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\n    Any other use cases are not supported and may lead to unexpected behavior.\n    Virtual IP will be announced from only one node at a time using gratuitous ARP announcements for IPv4.\ntitle: Layer2VIPConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: Layer2VIPConfig\nname: 10.3.0.1 # IP address to be advertised as a Layer 2 VIP.\nlink: enp0s2 # Name of the link to assign the VIP to.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |IP address to be advertised as a Layer 2 VIP. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: 192.168.100.1\n{{< /highlight >}}{{< highlight yaml >}}\nname: fd00::1\n{{< /highlight >}}</details> | |\n|`link` |string |Name of the link to assign the VIP to.<br><br>Selector must match exactly one link, otherwise an error is returned.<br>If multiple selectors match the same link, the first one is used.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/linkaliasconfig.md",
    "content": "---\ndescription: LinkAliasConfig is a config document to alias (give a different name) to a physical link.\ntitle: LinkAliasConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: LinkAliasConfig\nname: int0 # Alias for the link.\n# Selector to match the link to alias.\nselector:\n    match: glob(\"00:1a:2b:*\", mac(link.permanent_addr)) # The Common Expression Language (CEL) expression to match the link.\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: LinkAliasConfig\nname: net%d # Alias for the link.\n# Selector to match the link to alias.\nselector:\n    match: link.driver == \"e1000\" # The Common Expression Language (CEL) expression to match the link.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Alias for the link.<br><br>Don't use system interface names like \"eth0\", \"ens3\", \"enp0s2\", etc. as those may conflict<br>with existing physical interfaces.<br><br>The name can contain a single integer format verb (`%d`) to create multiple aliases<br>from a single config document. When a format verb is detected, each matched link receives a sequential<br>alias (e.g. `net0`, `net1`, ...) based on hardware address order of the links.<br>Links already aliased by a previous config are automatically skipped. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: net0\n{{< /highlight >}}{{< highlight yaml >}}\nname: private\n{{< /highlight >}}{{< highlight yaml >}}\nname: net%d\n{{< /highlight >}}</details> | |\n|`selector` |<a href=\"#LinkAliasConfig.selector\">LinkSelector</a> |Selector to match the link to alias.<br><br>When the alias name is a fixed string, the selector must match exactly one link.<br>When the alias name contains a format verb (e.g. `net%d`), the selector may match multiple links<br>and each match receives a sequential alias.<br>If multiple selectors match the same link, the first one is used.  | |\n\n\n\n\n## selector {#LinkAliasConfig.selector}\n\nLinkSelector selects a link to alias.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`match` |Expression |The Common Expression Language (CEL) expression to match the link. <details><summary>Show example(s)</summary>match links with a specific MAC address:{{< highlight yaml >}}\nmatch: mac(link.permanent_addr) == \"00:1a:2b:3c:4d:5e\"\n{{< /highlight >}}match links by MAC address prefix:{{< highlight yaml >}}\nmatch: glob(\"00:1a:2b:*\", mac(link.permanent_addr))\n{{< /highlight >}}match links by driver name:{{< highlight yaml >}}\nmatch: link.driver == \"e1000\"\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/linkconfig.md",
    "content": "---\ndescription: LinkConfig is a config document to configure physical interfaces (network links).\ntitle: LinkConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: LinkConfig\nname: enp0s2 # Name of the link (interface).\nup: true # Bring the link up or down.\nmtu: 9000 # Configure LinkMTU (Maximum Transmission Unit) for the link.\n# Configure addresses to be statically assigned to the link.\naddresses:\n    - address: 192.168.1.100/24 # IP address to be assigned to the link.\n    - address: fd00::1/64 # IP address to be assigned to the link.\n# Configure routes to be statically created via the link.\nroutes:\n    - destination: 10.0.0.0/8 # The route's destination as an address prefix.\n      gateway: 10.0.0.1 # The route's gateway (if empty, creates link scope route).\n    - gateway: fe80::1 # The route's gateway (if empty, creates link scope route).\n\n      # # The route's destination as an address prefix.\n      # destination: 10.0.0.0/8\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the link (interface). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: enp0s2\n{{< /highlight >}}{{< highlight yaml >}}\nname: eth1\n{{< /highlight >}}</details> | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#LinkConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#LinkConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## addresses[] {#LinkConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#LinkConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/networkdefaultactionconfig.md",
    "content": "---\ndescription: NetworkDefaultActionConfig is a ingress firewall default action configuration document.\ntitle: NetworkDefaultActionConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: NetworkDefaultActionConfig\ningress: accept # Default action for all not explicitly configured ingress traffic: accept or block.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`ingress` |DefaultAction |Default action for all not explicitly configured ingress traffic: accept or block.  |`accept`<br />`block`<br /> |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/networkruleconfig.md",
    "content": "---\ndescription: NetworkRuleConfig is a network firewall rule config document.\ntitle: NetworkRuleConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: NetworkRuleConfig\nname: ingress-apid # Name of the config document.\n# Port selector defines which ports and protocols on the host are affected by the rule.\nportSelector:\n    # Ports defines a list of port ranges or single ports.\n    ports:\n        - 50000\n    protocol: tcp # Protocol defines traffic protocol (e.g. TCP or UDP).\n# Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\ningress:\n    - subnet: 192.168.0.0/16 # Subnet defines a source subnet.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the config document.  | |\n|`portSelector` |<a href=\"#NetworkRuleConfig.portSelector\">RulePortSelector</a> |Port selector defines which ports and protocols on the host are affected by the rule.  | |\n|`ingress` |<a href=\"#NetworkRuleConfig.ingress.\">[]IngressRule</a> |Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.  | |\n\n\n\n\n## portSelector {#NetworkRuleConfig.portSelector}\n\nRulePortSelector is a port selector for the network rule.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`ports` |PortRanges |Ports defines a list of port ranges or single ports.<br>The port ranges are inclusive, and should not overlap. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nports:\n    - 80\n    - 443\n{{< /highlight >}}{{< highlight yaml >}}\nports:\n    - 1200-1299\n    - 8080\n{{< /highlight >}}</details> | |\n|`protocol` |Protocol |Protocol defines traffic protocol (e.g. TCP or UDP).  |`tcp`<br />`udp`<br />`icmp`<br />`icmpv6`<br /> |\n\n\n\n\n\n\n## ingress[] {#NetworkRuleConfig.ingress.}\n\nIngressRule is a ingress rule.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`subnet` |Prefix |Subnet defines a source subnet. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nsubnet: 10.3.4.0/24\n{{< /highlight >}}{{< highlight yaml >}}\nsubnet: 2001:db8::/32\n{{< /highlight >}}{{< highlight yaml >}}\nsubnet: 1.3.4.5/32\n{{< /highlight >}}</details> | |\n|`except` |Prefix |Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/resolverconfig.md",
    "content": "---\ndescription: ResolverConfig is a config document to configure DNS resolving.\ntitle: ResolverConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ResolverConfig\n# A list of nameservers (DNS servers) to use for resolving domain names.\nnameservers:\n    - address: 1.1.1.1 # The IP address of the nameserver.\n    - address: ff08::1 # The IP address of the nameserver.\n# Configuration for search domains (in /etc/resolv.conf).\nsearchDomains:\n    # A list of search domains to be used for DNS resolution.\n    domains:\n        - example.com\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ResolverConfig\n# Configuration for search domains (in /etc/resolv.conf).\nsearchDomains:\n    disableDefault: true # Disable default search domain configuration from hostname FQDN.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`nameservers` |<a href=\"#ResolverConfig.nameservers.\">[]NameserverConfig</a> |A list of nameservers (DNS servers) to use for resolving domain names.<br><br>Nameservers are used to resolve domain names on the host, and they are also<br>propagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.<br><br>This overrides any nameservers obtained via DHCP or platform configuration.<br>Default configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.  | |\n|`searchDomains` |<a href=\"#ResolverConfig.searchDomains\">SearchDomainsConfig</a> |Configuration for search domains (in /etc/resolv.conf).<br><br>The default is to derive search domains from the hostname FQDN.  | |\n\n\n\n\n## nameservers[] {#ResolverConfig.nameservers.}\n\nNameserverConfig represents a single nameserver configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Addr |The IP address of the nameserver. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 10.0.0.1\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n## searchDomains {#ResolverConfig.searchDomains}\n\nSearchDomainsConfig represents search domains configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`domains` |[]string |A list of search domains to be used for DNS resolution.<br><br>Search domains are appended to unqualified domain names during DNS resolution.<br>For example, if \"example.com\" is a search domain and a user tries to resolve<br>\"host\", the system will attempt to resolve \"host.example.com\".<br><br>This overrides any search domains obtained via DHCP or platform configuration.<br>The default configuration derives the search domain from the hostname FQDN.  | |\n|`disableDefault` |bool |Disable default search domain configuration from hostname FQDN.<br><br>When set to true, the system will not derive search domains from the hostname FQDN.<br>This allows for a custom configuration of search domains without any defaults.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/routingruleconfig.md",
    "content": "---\ndescription: RoutingRuleConfig is a config document to configure Linux policy routing rules.\ntitle: RoutingRuleConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: RoutingRuleConfig\nname: \"1000\" # Priority of the routing rule.\nsrc: 10.0.0.0/8 # Source address prefix to match.\ntable: \"100\" # The routing table to look up if the rule matches.\naction: unicast # The action to perform when the rule matches.\n\n# # Destination address prefix to match.\n# dst: 192.168.0.0/16\n\n# # Match packets arriving on this interface.\n# iifName: eth0\n\n# # Match packets going out on this interface.\n# oifName: eth1\n\n# # Match packets with this firewall mark value.\n# fwMark: 256\n\n# # Mask for the firewall mark comparison.\n# fwMask: 65280\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Priority of the routing rule.<br>Lower values are matched first.<br>Must be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).<br>Must be unique across all routing rules in the configuration. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: 1000\n{{< /highlight >}}</details> | |\n|`src` |Prefix |Source address prefix to match.<br>If empty, matches all sources. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nsrc: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`dst` |Prefix |Destination address prefix to match.<br>If empty, matches all destinations. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndst: 192.168.0.0/16\n{{< /highlight >}}</details> | |\n|`table` |RoutingTable |The routing table to look up if the rule matches. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ntable: 100\n{{< /highlight >}}</details> | |\n|`action` |RoutingRuleAction |The action to perform when the rule matches.<br>Defaults to \"unicast\" (table lookup).  |`unicast`<br />`blackhole`<br />`unreachable`<br />`prohibit`<br /> |\n|`iifName` |string |Match packets arriving on this interface. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\niifName: eth0\n{{< /highlight >}}</details> | |\n|`oifName` |string |Match packets going out on this interface. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\noifName: eth1\n{{< /highlight >}}</details> | |\n|`fwMark` |uint32 |Match packets with this firewall mark value. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfwMark: 256\n{{< /highlight >}}</details> | |\n|`fwMask` |uint32 |Mask for the firewall mark comparison. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfwMask: 65280\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/statichostconfig.md",
    "content": "---\ndescription: StaticHostConfig is a config document to set /etc/hosts entries.\ntitle: StaticHostConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: StaticHostConfig\nname: 10.5.0.2 # IP address (IPv4 or IPv6) to map the hostnames to.\n# List of hostnames to map to the IP address.\nhostnames:\n    - my-server\n    - my-server.example.org\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |IP address (IPv4 or IPv6) to map the hostnames to.  | |\n|`hostnames` |[]string |List of hostnames to map to the IP address.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/tcpprobeconfig.md",
    "content": "---\ndescription: TCPProbeConfig is a config document to configure network TCP connectivity probes.\ntitle: TCPProbeConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: TCPProbeConfig\nname: proxy-check # Name of the probe.\ninterval: 1s # Interval between probe attempts.\nfailureThreshold: 3 # Number of consecutive failures for the probe to be considered failed after having succeeded.\nendpoint: proxy.example.com:3128 # Endpoint to probe in the format host:port.\ntimeout: 10s # Timeout for the probe.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the probe. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: proxy-check\n{{< /highlight >}}</details> | |\n|`interval` |Duration |Interval between probe attempts.<br>Defaults to 1s. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ninterval: 1s\n{{< /highlight >}}</details> | |\n|`failureThreshold` |int |Number of consecutive failures for the probe to be considered failed after having succeeded.<br>Defaults to 0 (immediately fail on first failure). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfailureThreshold: 3\n{{< /highlight >}}</details> | |\n|`endpoint` |string |Endpoint to probe in the format host:port. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nendpoint: proxy.example.com:3128\n{{< /highlight >}}</details> | |\n|`timeout` |Duration |Timeout for the probe.<br>Defaults to 10s. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ntimeout: 10s\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/timesyncconfig.md",
    "content": "---\ndescription: TimeSyncConfig is a config document to configure time synchronization (NTP).\ntitle: TimeSyncConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: TimeSyncConfig\n# Specifies NTP configuration to sync the time over network.\nntp:\n    # Specifies time (NTP) servers to use for setting the system time.\n    servers:\n        - pool.ntp.org\n{{< /highlight >}}\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: TimeSyncConfig\n# Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\nptp:\n    # description: |\n    devices:\n        - /dev/ptp0\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Indicates if the time synchronization is enabled for the machine.<br>Defaults to `true`.  | |\n|`bootTimeout` |Duration |Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.<br>NTP sync will be still running in the background.<br>Defaults to \"infinity\" (waiting forever for time sync)  | |\n|`ntp` |<a href=\"#TimeSyncConfig.ntp\">NTPConfig</a> |Specifies NTP configuration to sync the time over network.<br>Mutually exclusive with PTP configuration.  | |\n|`ptp` |<a href=\"#TimeSyncConfig.ptp\">PTPConfig</a> |Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.<br>Mutually exclusive with NTP configuration.  | |\n\n\n\n\n## ntp {#TimeSyncConfig.ntp}\n\nNTPConfig represents a NTP server configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`servers` |[]string |Specifies time (NTP) servers to use for setting the system time.<br>Defaults to `time.cloudflare.com`.  | |\n\n\n\n\n\n\n## ptp {#TimeSyncConfig.ptp}\n\nPTPConfig represents a PTP (Precision Time Protocol) configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`devices` |[]string |description: |<br>    A list of PTP devices to sync with (e.g. provided by the hypervisor).<br><br>    A PTP device is typically represented as a character device file in the /dev directory,<br>   such as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time<br>    with an external time source that supports the Precision Time Protocol.<br>  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/vlanconfig.md",
    "content": "---\ndescription: VLANConfig is a config document to create a VLAN (virtual LAN) over a parent link.\ntitle: VLANConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: VLANConfig\nname: enp0s3.34 # Name of the VLAN link (interface) to be created.\nvlanID: 34 # VLAN ID to be used for the VLAN link.\nparent: enp0s3 # Name of the parent link (interface) on which the VLAN link will be created.\n# Configure addresses to be statically assigned to the link.\naddresses:\n    - address: 192.168.1.100/24 # IP address to be assigned to the link.\n# Configure routes to be statically created via the link.\nroutes:\n    - destination: 192.168.0.0/16 # The route's destination as an address prefix.\n      gateway: 192.168.1.1 # The route's gateway (if empty, creates link scope route).\n\n# # Set the VLAN mode to use.\n# vlanMode: 802.1q\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the VLAN link (interface) to be created. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: enp0s3.34\n{{< /highlight >}}</details> | |\n|`vlanID` |uint16 |VLAN ID to be used for the VLAN link. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nvlanID: 34\n{{< /highlight >}}</details> | |\n|`vlanMode` |VLANProtocol |Set the VLAN mode to use.<br>If not set, defaults to '802.1q'. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nvlanMode: 802.1q\n{{< /highlight >}}</details> |`802.1q`<br />`802.1ad`<br /> |\n|`parent` |string |Name of the parent link (interface) on which the VLAN link will be created.<br>Link aliases can be used here as well. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nparent: enp0s3\n{{< /highlight >}}</details> | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#VLANConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#VLANConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## addresses[] {#VLANConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#VLANConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/vrfconfig.md",
    "content": "---\ndescription: VRFConfig is a config document to create a vrf and assign links to it.\ntitle: VRFConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: VRFConfig\nname: vrf-blue # Name of the vrf link (interface) to be created.\n# Names of the links (interfaces) to be assigned to this vrf.\nlinks:\n    - eno1\n    - eno2\ntable: \"10\" # Routing table number to use for this vrf.\n\n# # Override the hardware (MAC) address of the link.\n# hardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the vrf link (interface) to be created. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: vrf-blue\n{{< /highlight >}}</details> | |\n|`hardwareAddr` |HardwareAddr |Override the hardware (MAC) address of the link. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhardwareAddr: 2e:3c:4d:5e:6f:70\n{{< /highlight >}}</details> | |\n|`links` |[]string |Names of the links (interfaces) to be assigned to this vrf.<br>Link aliases can be used here as well. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nlinks:\n    - enp1s3\n    - enp1s2\n{{< /highlight >}}</details> | |\n|`table` |RoutingTable |Routing table number to use for this vrf. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ntable: 10\n{{< /highlight >}}</details> | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#VRFConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#VRFConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## addresses[] {#VRFConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#VRFConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/network/wireguardconfig.md",
    "content": "---\ndescription: WireguardConfig is a config document to create and configure a Wireguard network link.\ntitle: WireguardConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: WireguardConfig\nname: wg1 # Name of the Wireguard link (interface).\nprivateKey: OJ34O6J1z4ZZB+t16c+vYrzIrKddxyU3Z2eLhwYzqE8= # Specifies a private key configuration (base64 encoded).\nlistenPort: 51820 # Specifies a device's listening port (UDP).\n# Specifies a list of peer configurations to apply to a device.\npeers:\n    - publicKey: fP+xJZvUA5n1Pi/f5wcPiV6tZ6fHwqcGaXe98NfEgkE= # Specifies the public key of this peer.\n      endpoint: 10.0.0.1:5180 # Specifies the endpoint of this peer entry.\n      # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n      allowedIPs:\n        - 192.168.2.0/24\n    - publicKey: TDd25Cwq6tMZANIKUaqred+Zt+09HtCqwFeOLtKQ9Cs= # Specifies the public key of this peer.\n      presharedKey: UpH8htYK7yJBPg5+q4M/Tx0o5ipHbeSZtI/h/mHxOeU= # Specifies the preshared key for this peer (base64 encoded).\n      # AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\n      allowedIPs:\n        - 192.168.3.0/24\nmtu: 1420 # Configure LinkMTU (Maximum Transmission Unit) for the link.\n# Configure addresses to be statically assigned to the link.\naddresses:\n    - address: 192.168.1.100/24 # IP address to be assigned to the link.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the Wireguard link (interface). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: wg.int\n{{< /highlight >}}</details> | |\n|`privateKey` |string |Specifies a private key configuration (base64 encoded).<br>Can be generated by `wg genkey`.  | |\n|`listenPort` |int |Specifies a device's listening port (UDP).<br>If not specified, a random port will be chosen.  | |\n|`firewallMark` |int |Specifies a device's firewall mark.<br>Useful for advanced routing setups, marking packets originating from this device.  | |\n|`peers` |<a href=\"#WireguardConfig.peers.\">[]WireguardPeer</a> |Specifies a list of peer configurations to apply to a device.  | |\n|`up` |bool |Bring the link up or down.<br><br>If not specified, the link will be brought up.  | |\n|`mtu` |uint32 |Configure LinkMTU (Maximum Transmission Unit) for the link.<br><br>If not specified, the system default LinkMTU will be used (usually 1500).  | |\n|`addresses` |<a href=\"#WireguardConfig.addresses.\">[]AddressConfig</a> |Configure addresses to be statically assigned to the link.  | |\n|`routes` |<a href=\"#WireguardConfig.routes.\">[]RouteConfig</a> |Configure routes to be statically created via the link.  | |\n|`multicast` |bool |Set the multicast capability of the link.  | |\n\n\n\n\n## peers[] {#WireguardConfig.peers.}\n\nWireguardPeer describes a Wireguard peer configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`publicKey` |string |Specifies the public key of this peer.<br>Can be extracted from private key by running `wg pubkey < private.key`.  | |\n|`presharedKey` |string |Specifies the preshared key for this peer (base64 encoded).<br>Can be generated by `wg genpsk`.<br>Optional, this key provides an additional layer of symmetric-key cryptography<br>to the peer connection.  | |\n|`endpoint` |AddrPort |Specifies the endpoint of this peer entry.<br>Format: <IP address>:<port>.<br>If not set, the peer should connect to us without us connecting to it first.  | |\n|`persistentKeepaliveInterval` |Duration |Specifies the persistent keepalive interval for this peer.<br>Field format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).  | |\n|`allowedIPs` |[]Prefix |AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.<br>These IPs will be routed to this peer, and defines which IPs this peer is allowed to use.  | |\n\n\n\n\n\n\n## addresses[] {#WireguardConfig.addresses.}\n\nAddressConfig represents a network address configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`address` |Prefix |IP address to be assigned to the link.<br><br>This field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\naddress: 192.168.1.100/24\n{{< /highlight >}}{{< highlight yaml >}}\naddress: fd00::1/64\n{{< /highlight >}}</details> | |\n|`routePriority` |uint32 |Configure the route priority (metric) for routes created for this address.<br><br>If not specified, the system default route priority will be used.  | |\n\n\n\n\n\n\n## routes[] {#WireguardConfig.routes.}\n\nRouteConfig represents a network route configuration.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |Prefix |The route's destination as an address prefix.<br><br>If not specified, a default route will be created for the address family of the gateway. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndestination: 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`gateway` |Addr |The route's gateway (if empty, creates link scope route). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ngateway: 10.0.0.1\n{{< /highlight >}}</details> | |\n|`source` |Addr |The route's source address (optional).  | |\n|`metric` |uint32 |The optional metric for the route.  | |\n|`mtu` |uint32 |The optional MTU for the route.  | |\n|`table` |RoutingTable |The routing table to use for the route.<br><br>If not specified, the main routing table will be used.  | |\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/_index.md",
    "content": "---\ndescription: |\n    Package runtime provides runtime machine configuration documents.\ntitle: runtime\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/environmentconfig.md",
    "content": "---\ndescription: EnvironmentConfig is an environment config document.\ntitle: EnvironmentConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: EnvironmentConfig\n# This field allows for the addition of environment variables.\nvariables:\n    GRPC_GO_LOG_SEVERITY_LEVEL: info\n    GRPC_GO_LOG_VERBOSITY_LEVEL: \"99\"\n    https_proxy: http://SERVER:PORT/\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`variables` |Env |This field allows for the addition of environment variables.<br>All environment variables are set on PID 1 in addition to every service.<br>Propagation of environment variables to services is done only at initial service start time.<br>To modify environment variables for services, the node must be restarted.<br>Multiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.<br>Fully removing an environment variable can only be achieved by removing it from the document and restarting the machine.<br>Environment variable names are validated, and should:<br>  - start with an uppercase letter, lowercase letter, or an underscore (_) character, and<br>  - contain only uppercase and lowercase letters, underscore (_) characters, and numbers. <details><summary>Show example(s)</summary>Environment variables definition examples.:{{< highlight yaml >}}\nvariables:\n    GRPC_GO_LOG_SEVERITY_LEVEL: info\n    GRPC_GO_LOG_VERBOSITY_LEVEL: \"99\"\n    https_proxy: http://SERVER:PORT/\n{{< /highlight >}}{{< highlight yaml >}}\nvariables:\n    GRPC_GO_LOG_SEVERITY_LEVEL: error\n    https_proxy: https://USERNAME:PASSWORD@SERVER:PORT/\n{{< /highlight >}}{{< highlight yaml >}}\nvariables:\n    https_proxy: http://DOMAIN\\USERNAME:PASSWORD@SERVER:PORT/\n{{< /highlight >}}</details> |``GRPC_GO_LOG_VERBOSITY_LEVEL``<br />``GRPC_GO_LOG_SEVERITY_LEVEL``<br />``http_proxy``<br />``https_proxy``<br />``no_proxy``<br /> |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/eventsinkconfig.md",
    "content": "---\ndescription: EventSinkConfig is a event sink config document.\ntitle: EventSinkConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: EventSinkConfig\nendpoint: 192.168.10.3:3247 # The endpoint for the event sink as 'host:port'.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |string |The endpoint for the event sink as 'host:port'. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nendpoint: 10.3.7.3:2810\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/kmsglogconfig.md",
    "content": "---\ndescription: KmsgLogConfig is a event sink config document.\ntitle: KmsgLogConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: KmsgLogConfig\nname: remote-log # Name of the config document.\nurl: tcp://192.168.3.7:3478/ # The URL encodes the log destination.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the config document.  | |\n|`url` |URL |The URL encodes the log destination.<br>The scheme must be tcp:// or udp://.<br>The path must be empty.<br>The port is required. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nurl: udp://10.3.7.3:2810\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/oomconfig.md",
    "content": "---\ndescription: OOMConfig is a Out of Memory handler config document.\ntitle: OOMConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: OOMConfig\ntriggerExpression: |- # This expression defines when to trigger OOM action.\n    multiply_qos_vectors(d_qos_memory_full_total, {System: 8.0, Podruntime: 4.0}) > 3000.0 &&\n    multiply_qos_vectors(qos_memory_full_avg10, {System: 1.0, Podruntime: 1.0}) > 5.0 ||\n    memory_full_avg10 > 75.0 && time_since_trigger > duration(\"10s\")\ncgroupRankingExpression: 'memory_max.hasValue() ? 0.0 : ({Besteffort: 1.0, Burstable: 0.5, Guaranteed: 0.0, Podruntime: 0.0, System: 0.0}[class] * double(memory_current.orValue(0u)))' # This expression defines how to rank cgroups for OOM handler.\nsampleInterval: 100ms # How often should the trigger expression be evaluated.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`triggerExpression` |Expression |This expression defines when to trigger OOM action.<br><br>The expression must evaluate to a boolean value.<br>If the expression returns true, then OOM ranking and killing will be handled.<br><br>This expression receives the following parameters:<br>- memory_{some,full}_{avg10,avg60,avg300,total} - double, representing PSI values<br>- time_since_trigger - duration since the last OOM handler trigger event  | |\n|`cgroupRankingExpression` |Expression |This expression defines how to rank cgroups for OOM handler.<br><br>The cgroup with the highest rank (score) will be evicted first.<br>The expression must evaluate to a double value.<br><br>This expression receives the following parameters:<br>- memory_max - Optional<uint> - in bytes<br>- memory_current - Optional<uint> - in bytes<br>- memory_peak - Optional<uint> - in bytes<br>- path - string, path to the cgroup<br>- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System  | |\n|`sampleInterval` |Duration |How often should the trigger expression be evaluated.<br><br>This interval determines how often should the OOM controller<br>check for the OOM condition using the provided expression.<br>Adjusting it can help tune the reactivity of the OOM handler.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/runtime/watchdogtimerconfig.md",
    "content": "---\ndescription: WatchdogTimerConfig is a watchdog timer config document.\ntitle: WatchdogTimerConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: WatchdogTimerConfig\ndevice: /dev/watchdog0 # Path to the watchdog device.\ntimeout: 2m0s # Timeout for the watchdog.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`device` |string |Path to the watchdog device. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndevice: /dev/watchdog0\n{{< /highlight >}}</details> | |\n|`timeout` |Duration |Timeout for the watchdog.<br><br>If Talos is unresponsive for this duration, the watchdog will reset the system.<br><br>Default value is 1 minute, minimum value is 10 seconds.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/security/_index.md",
    "content": "---\ndescription: |\n    Package security provides security-related machine configuration documents.\ntitle: security\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/security/imageverificationconfig.md",
    "content": "---\ndescription: ImageVerificationConfig configures image signature verification policy.\ntitle: ImageVerificationConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: ImageVerificationConfig\n# List of verification rules.\nrules:\n    - image: registry.k8s.io/* # Image reference pattern to match for this rule.\n      # Keyless verifier configuration to use for this rule.\n      keyless:\n        issuer: https://accounts.google.com # OIDC issuer URL for keyless verification.\n        subject: krel-trust@k8s-releng-prod.iam.gserviceaccount.com # Expected subject for keyless verification.\n\n        # # Regex pattern for subject matching.\n        # subjectRegex: .*@example\\.com\n    - image: my-registry/* # Image reference pattern to match for this rule.\n      # Public key verifier configuration to use for this rule.\n      publicKey:\n        certificate: |- # A public certificate in PEM format accepted for image signature verification.\n            -----BEGIN CERTIFICATE-----\n            MII--Sample Value--\n            -----END CERTIFICATE-----\n    - image: locahost:3000/* # Image reference pattern to match for this rule.\n      deny: true # Deny pulling images matching the pattern (default: false).\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`rules` |<a href=\"#ImageVerificationConfig.rules.\">[]ImageVerificationRuleV1Alpha1</a> |List of verification rules.<br>Rules are evaluated in order; first matching rule applies.  | |\n\n\n\n\n## rules[] {#ImageVerificationConfig.rules.}\n\nImageVerificationRuleV1Alpha1 defines a verification rule.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |Image reference pattern to match for this rule.<br>Supports glob patterns. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: docker.io/library/nginx\n{{< /highlight >}}{{< highlight yaml >}}\nimage: registry.k8s.io/*\n{{< /highlight >}}</details> | |\n|`skip` |bool |Skip verification for this image pattern (default: false).  | |\n|`deny` |bool |Deny pulling images matching the pattern (default: false).  | |\n|`keyless` |<a href=\"#ImageVerificationConfig.rules..keyless\">ImageKeylessVerifierV1Alpha1</a> |Keyless verifier configuration to use for this rule.  | |\n|`publicKey` |<a href=\"#ImageVerificationConfig.rules..publicKey\">ImagePublicKeyVerifierV1Alpha1</a> |Public key verifier configuration to use for this rule.  | |\n\n\n\n\n### keyless {#ImageVerificationConfig.rules..keyless}\n\nImageKeylessVerifierV1Alpha1 configures a signature verification provider using Cosign keyless verification.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`issuer` |string |OIDC issuer URL for keyless verification. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nissuer: https://accounts.google.com\n{{< /highlight >}}{{< highlight yaml >}}\nissuer: https://token.actions.githubusercontent.com\n{{< /highlight >}}</details> | |\n|`subject` |string |Expected subject for keyless verification.<br><br>This is the identity (email, URI) that signed the image.  | |\n|`subjectRegex` |string |Regex pattern for subject matching.<br><br>Use this instead of subject for flexible matching. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nsubjectRegex: .*@example\\.com\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n### publicKey {#ImageVerificationConfig.rules..publicKey}\n\nImagePublicKeyVerifierV1Alpha1 configures a signature verification provider using a static public key.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`certificate` |string |A public certificate in PEM format accepted for image signature verification.  | |\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/security/trustedrootsconfig.md",
    "content": "---\ndescription: TrustedRootsConfig allows to configure additional trusted CA roots.\ntitle: TrustedRootsConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: TrustedRootsConfig\nname: my-enterprise-ca # Name of the config document.\ncertificates: | # List of additional trusted certificate authorities (as PEM-encoded certificates).\n    -----BEGIN CERTIFICATE-----\n    ...\n    -----END CERTIFICATE-----\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the config document.  | |\n|`certificates` |string |List of additional trusted certificate authorities (as PEM-encoded certificates).<br><br>Multiple certificates can be provided in a single config document, separated by newline characters.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/siderolink/_index.md",
    "content": "---\ndescription: |\n    Package siderolink provides SideroLink machine configuration documents.\ntitle: siderolink\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/siderolink/siderolinkconfig.md",
    "content": "---\ndescription: SideroLinkConfig is a SideroLink connection machine configuration document.\ntitle: SideroLinkConfig\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\napiVersion: v1alpha1\nkind: SideroLinkConfig\napiUrl: https://siderolink.api/jointoken?token=secret # SideroLink API URL to connect to.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`apiUrl` |URL |SideroLink API URL to connect to. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\napiUrl: https://siderolink.api/?jointoken=secret\n{{< /highlight >}}</details> | |\n|`uniqueToken` |string |SideroLink unique token to use for the connection (optional).<br><br>This value is overridden with META key UniqueMachineToken.  | |\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/v1alpha1/_index.md",
    "content": "---\ndescription: |\n    Package v1alpha1 contains definition of the `v1alpha1` configuration document.\n\n    Even though the machine configuration in Talos Linux is multi-document, at the moment\n    this configuration document contains most of the configuration options.\n\n    It is expected that new configuration options will be added as new documents, and existing ones\n    migrated to their own documents.\ntitle: v1alpha1\n---\n\n<!-- markdownlint-disable -->\n\n"
  },
  {
    "path": "website/content/v1.13/reference/configuration/v1alpha1/config.md",
    "content": "---\ndescription: Config defines the v1alpha1.Config Talos machine configuration document.\ntitle: Config\n---\n\n<!-- markdownlint-disable -->\n\n\n\n\n\n\n\n\n\n{{< highlight yaml >}}\nversion: v1alpha1\nmachine: # ...\ncluster: # ...\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`version` |string |Indicates the schema used to decode the contents.  |`v1alpha1`<br /> |\n|`debug` |bool |Enable verbose logging to the console.<br>All system containers logs will flow into serial console.<br><br>**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`machine` |<a href=\"#Config.machine\">MachineConfig</a> |Provides machine specific configuration options.  | |\n|`cluster` |<a href=\"#Config.cluster\">ClusterConfig</a> |Provides cluster specific configuration options.  | |\n\n\n\n\n## machine {#Config.machine}\n\nMachineConfig represents the machine-specific config values.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    type: controlplane\n    # InstallConfig represents the installation options for preparing a node.\n    install:\n        disk: /dev/sda # The disk used for installations.\n        image: ghcr.io/siderolabs/installer:latest # Allows for supplying the image used to perform the installation.\n        wipe: false # Indicates if the installation disk should be wiped at installation time.\n        grubUseUKICmdline: true # Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\n\n        # # Look up disk using disk attributes like model, size, serial and others.\n        # diskSelector:\n        #     size: 4GB # Disk size.\n        #     model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n        #     busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0 # Disk bus path.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`type` |string |Defines the role of the machine within the cluster.<br><br>**Control Plane**<br><br>Control Plane node type designates the node as a control plane member.<br>This means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.<br><br>**Worker**<br><br>Worker node type designates the node as a worker node.<br>This means it will be an available compute node for scheduling workloads.<br><br>This node type was previously known as \"join\"; that value is still supported but deprecated.  |`controlplane`<br />`worker`<br /> |\n|`token` |string |The `token` is used by a machine to join the PKI of the cluster.<br>Using this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity. <details><summary>Show example(s)</summary>example token:{{< highlight yaml >}}\ntoken: 328hom.uqjzh6jnn2eie9oi\n{{< /highlight >}}</details> | |\n|`ca` |PEMEncodedCertificateAndKey |The root certificate authority of the PKI.<br>It is composed of a base64 encoded `crt` and `key`. <details><summary>Show example(s)</summary>machine CA example:{{< highlight yaml >}}\nca:\n    crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n    key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n{{< /highlight >}}</details> | |\n|`acceptedCAs` |[]PEMEncodedCertificate |The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.<br>It is composed of a base64 encoded `crt``.  | |\n|`certSANs` |[]string |Extra certificate subject alternative names for the machine's certificate.<br>By default, all non-loopback interface IPs are automatically added to the certificate's SANs. <details><summary>Show example(s)</summary>Uncomment this to enable SANs.:{{< highlight yaml >}}\ncertSANs:\n    - 10.0.0.10\n    - 172.16.0.10\n    - 192.168.0.10\n{{< /highlight >}}</details> | |\n|`controlPlane` |<a href=\"#Config.machine.controlPlane\">MachineControlPlaneConfig</a> |Provides machine specific control plane configuration options. <details><summary>Show example(s)</summary>ControlPlane definition example.:{{< highlight yaml >}}\ncontrolPlane:\n    # Controller manager machine specific configuration options.\n    controllerManager:\n        disabled: false # Disable kube-controller-manager on the node.\n    # Scheduler machine specific configuration options.\n    scheduler:\n        disabled: true # Disable kube-scheduler on the node.\n{{< /highlight >}}</details> | |\n|`kubelet` |<a href=\"#Config.machine.kubelet\">KubeletConfig</a> |Used to provide additional options to the kubelet. <details><summary>Show example(s)</summary>Kubelet definition example.:{{< highlight yaml >}}\nkubelet:\n    image: ghcr.io/siderolabs/kubelet:v1.36.0-alpha.2 # The `image` field is an optional reference to an alternative kubelet image.\n    # The `extraArgs` field is used to provide additional flags to the kubelet.\n    extraArgs:\n        feature-gates: ServerSideApply=true\n\n    # # The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\n    # clusterDNS:\n    #     - 10.96.0.10\n    #     - 169.254.2.53\n\n    # # The `extraMounts` field is used to add additional mounts to the kubelet container.\n    # extraMounts:\n    #     - destination: /var/lib/example # Destination is the absolute path where the mount will be placed in the container.\n    #       type: bind # Type specifies the mount kind.\n    #       source: /var/lib/example # Source specifies the source path of the mount.\n    #       # Options are fstab style mount options.\n    #       options:\n    #         - bind\n    #         - rshared\n    #         - rw\n\n    # # The `extraConfig` field is used to provide kubelet configuration overrides.\n    # extraConfig:\n    #     serverTLSBootstrap: true\n\n    # # The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\n    # credentialProviderConfig:\n    #     apiVersion: kubelet.config.k8s.io/v1\n    #     kind: CredentialProviderConfig\n    #     providers:\n    #         - apiVersion: credentialprovider.kubelet.k8s.io/v1\n    #           defaultCacheDuration: 12h\n    #           matchImages:\n    #             - '*.dkr.ecr.*.amazonaws.com'\n    #             - '*.dkr.ecr.*.amazonaws.com.cn'\n    #             - '*.dkr.ecr-fips.*.amazonaws.com'\n    #             - '*.dkr.ecr.us-iso-east-1.c2s.ic.gov'\n    #             - '*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov'\n    #           name: ecr-credential-provider\n\n    # # The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\n    # nodeIP:\n    #     # The `validSubnets` field configures the networks to pick kubelet node IP from.\n    #     validSubnets:\n    #         - 10.0.0.0/8\n    #         - '!10.0.0.3/32'\n    #         - fdc7::/16\n{{< /highlight >}}</details> | |\n|`pods` |[]Unstructured |Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.<br><br>Static pods can be used to run components which should be started before the Kubernetes control plane is up.<br>Talos doesn't validate the pod definition.<br>Updates to this field can be applied without a reboot.<br><br>See https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/. <details><summary>Show example(s)</summary>nginx static pod.:{{< highlight yaml >}}\npods:\n    - apiVersion: v1\n      kind: pod\n      metadata:\n        name: nginx\n      spec:\n        containers:\n            - image: nginx\n              name: nginx\n{{< /highlight >}}</details> | |\n|`install` |<a href=\"#Config.machine.install\">InstallConfig</a> |Used to provide instructions for installations.<br><br>Note that this configuration section gets silently ignored by Talos images that are considered pre-installed.<br>To make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted. <details><summary>Show example(s)</summary>MachineInstall config usage example.:{{< highlight yaml >}}\ninstall:\n    disk: /dev/sda # The disk used for installations.\n    image: ghcr.io/siderolabs/installer:latest # Allows for supplying the image used to perform the installation.\n    wipe: false # Indicates if the installation disk should be wiped at installation time.\n    grubUseUKICmdline: true # Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\n\n    # # Look up disk using disk attributes like model, size, serial and others.\n    # diskSelector:\n    #     size: 4GB # Disk size.\n    #     model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n    #     busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0 # Disk bus path.\n{{< /highlight >}}</details> | |\n|`files` |<a href=\"#Config.machine.files.\">[]MachineFile</a> |Allows the addition of user specified files.<br>The value of `op` can be `create`, `overwrite`, or `append`.<br>In the case of `create`, `path` must not exist.<br>In the case of `overwrite`, and `append`, `path` must be a valid file.<br>If an `op` value of `append` is used, the existing file will be appended.<br>Note that the file contents are not required to be base64 encoded. <details><summary>Show example(s)</summary>MachineFiles usage example.:{{< highlight yaml >}}\nfiles:\n    - content: '...' # The contents of the file.\n      permissions: 0o666 # The file's permissions in octal.\n      path: /tmp/file.txt # The path of the file.\n      op: append # The operation to use\n{{< /highlight >}}</details> | |\n|`sysctls` |map[string]string |Used to configure the machine's sysctls. <details><summary>Show example(s)</summary>MachineSysctls usage example.:{{< highlight yaml >}}\nsysctls:\n    kernel.domainname: talos.dev\n    net.ipv4.ip_forward: \"0\"\n    net/ipv6/conf/eth0.100/disable_ipv6: \"1\"\n{{< /highlight >}}</details> | |\n|`sysfs` |map[string]string |Used to configure the machine's sysfs. <details><summary>Show example(s)</summary>MachineSysfs usage example.:{{< highlight yaml >}}\nsysfs:\n    devices.system.cpu.cpu0.cpufreq.scaling_governor: performance\n{{< /highlight >}}</details> | |\n|`features` |<a href=\"#Config.machine.features\">FeaturesConfig</a> |Features describe individual Talos features that can be switched on or off. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nfeatures:\n    diskQuotaSupport: true # Enable XFS project quota support for EPHEMERAL partition and user disks.\n\n    # # Configure Talos API access from Kubernetes pods.\n    # kubernetesTalosAPIAccess:\n    #     enabled: true # Enable Talos API access from Kubernetes pods.\n    #     # The list of Talos API roles which can be granted for access from Kubernetes pods.\n    #     allowedRoles:\n    #         - os:reader\n    #     # The list of Kubernetes namespaces Talos API access is available from.\n    #     allowedKubernetesNamespaces:\n    #         - kube-system\n{{< /highlight >}}</details> | |\n|`udev` |<a href=\"#Config.machine.udev\">UdevConfig</a> |Configures the udev system. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nudev:\n    # List of udev rules to apply to the udev system\n    rules:\n        - SUBSYSTEM==\"drm\", KERNEL==\"renderD*\", GROUP=\"44\", MODE=\"0660\"\n{{< /highlight >}}</details> | |\n|`logging` |<a href=\"#Config.machine.logging\">LoggingConfig</a> |Configures the logging system. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nlogging:\n    # Logging destination.\n    destinations:\n        - endpoint: tcp://1.2.3.4:12345 # Where to send logs. Supported protocols are \"tcp\" and \"udp\".\n          format: json_lines # Logs format.\n{{< /highlight >}}</details> | |\n|`kernel` |<a href=\"#Config.machine.kernel\">KernelConfig</a> |Configures the kernel. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nkernel:\n    # Kernel modules to load.\n    modules:\n        - name: btrfs # Module name.\n{{< /highlight >}}</details> | |\n|`seccompProfiles` |<a href=\"#Config.machine.seccompProfiles.\">[]MachineSeccompProfile</a> |Configures the seccomp profiles for the machine. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nseccompProfiles:\n    - name: audit.json # The `name` field is used to provide the file name of the seccomp profile.\n      # The `value` field is used to provide the seccomp profile.\n      value:\n        defaultAction: SCMP_ACT_LOG\n{{< /highlight >}}</details> | |\n|`baseRuntimeSpecOverrides` |Unstructured |Override (patch) settings in the default OCI runtime spec for CRI containers.<br><br>It can be used to set some default container settings which are not configurable in Kubernetes,<br>for example default ulimits.<br>Note: this change applies to all newly created containers, and it requires a reboot to take effect. <details><summary>Show example(s)</summary>override default open file limit:{{< highlight yaml >}}\nbaseRuntimeSpecOverrides:\n    process:\n        rlimits:\n            - hard: 1024\n              soft: 1024\n              type: RLIMIT_NOFILE\n{{< /highlight >}}</details> | |\n|`nodeLabels` |map[string]string |Configures the node labels for the machine.<br><br>Note: In the default Kubernetes configuration, worker nodes are restricted to set<br>labels with some prefixes (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin). <details><summary>Show example(s)</summary>node labels example.:{{< highlight yaml >}}\nnodeLabels:\n    exampleLabel: exampleLabelValue\n{{< /highlight >}}</details> | |\n|`nodeAnnotations` |map[string]string |Configures the node annotations for the machine. <details><summary>Show example(s)</summary>node annotations example.:{{< highlight yaml >}}\nnodeAnnotations:\n    customer.io/rack: r13a25\n{{< /highlight >}}</details> | |\n|`nodeTaints` |map[string]string |Configures the node taints for the machine. Effect is optional.<br><br>Note: In the default Kubernetes configuration, worker nodes are not allowed to<br>modify the taints (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin). <details><summary>Show example(s)</summary>node taints example.:{{< highlight yaml >}}\nnodeTaints:\n    exampleTaint: exampleTaintValue:NoSchedule\n{{< /highlight >}}</details> | |\n\n\n\n\n### controlPlane {#Config.machine.controlPlane}\n\nMachineControlPlaneConfig machine specific configuration options.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    controlPlane:\n        # Controller manager machine specific configuration options.\n        controllerManager:\n            disabled: false # Disable kube-controller-manager on the node.\n        # Scheduler machine specific configuration options.\n        scheduler:\n            disabled: true # Disable kube-scheduler on the node.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`controllerManager` |<a href=\"#Config.machine.controlPlane.controllerManager\">MachineControllerManagerConfig</a> |Controller manager machine specific configuration options.  | |\n|`scheduler` |<a href=\"#Config.machine.controlPlane.scheduler\">MachineSchedulerConfig</a> |Scheduler machine specific configuration options.  | |\n\n\n\n\n#### controllerManager {#Config.machine.controlPlane.controllerManager}\n\nMachineControllerManagerConfig represents the machine specific ControllerManager config values.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable kube-controller-manager on the node.  | |\n\n\n\n\n\n\n#### scheduler {#Config.machine.controlPlane.scheduler}\n\nMachineSchedulerConfig represents the machine specific Scheduler config values.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable kube-scheduler on the node.  | |\n\n\n\n\n\n\n\n\n### kubelet {#Config.machine.kubelet}\n\nKubeletConfig represents the kubelet config values.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    kubelet:\n        image: ghcr.io/siderolabs/kubelet:v1.36.0-alpha.2 # The `image` field is an optional reference to an alternative kubelet image.\n        # The `extraArgs` field is used to provide additional flags to the kubelet.\n        extraArgs:\n            feature-gates: ServerSideApply=true\n\n        # # The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\n        # clusterDNS:\n        #     - 10.96.0.10\n        #     - 169.254.2.53\n\n        # # The `extraMounts` field is used to add additional mounts to the kubelet container.\n        # extraMounts:\n        #     - destination: /var/lib/example # Destination is the absolute path where the mount will be placed in the container.\n        #       type: bind # Type specifies the mount kind.\n        #       source: /var/lib/example # Source specifies the source path of the mount.\n        #       # Options are fstab style mount options.\n        #       options:\n        #         - bind\n        #         - rshared\n        #         - rw\n\n        # # The `extraConfig` field is used to provide kubelet configuration overrides.\n        # extraConfig:\n        #     serverTLSBootstrap: true\n\n        # # The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\n        # credentialProviderConfig:\n        #     apiVersion: kubelet.config.k8s.io/v1\n        #     kind: CredentialProviderConfig\n        #     providers:\n        #         - apiVersion: credentialprovider.kubelet.k8s.io/v1\n        #           defaultCacheDuration: 12h\n        #           matchImages:\n        #             - '*.dkr.ecr.*.amazonaws.com'\n        #             - '*.dkr.ecr.*.amazonaws.com.cn'\n        #             - '*.dkr.ecr-fips.*.amazonaws.com'\n        #             - '*.dkr.ecr.us-iso-east-1.c2s.ic.gov'\n        #             - '*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov'\n        #           name: ecr-credential-provider\n\n        # # The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\n        # nodeIP:\n        #     # The `validSubnets` field configures the networks to pick kubelet node IP from.\n        #     validSubnets:\n        #         - 10.0.0.0/8\n        #         - '!10.0.0.3/32'\n        #         - fdc7::/16\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |The `image` field is an optional reference to an alternative kubelet image. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: ghcr.io/siderolabs/kubelet:v1.36.0-alpha.2\n{{< /highlight >}}</details> | |\n|`clusterDNS` |[]string |The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nclusterDNS:\n    - 10.96.0.10\n    - 169.254.2.53\n{{< /highlight >}}</details> | |\n|`extraArgs` |Args |The `extraArgs` field is used to provide additional flags to the kubelet. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraArgs:\n    key: value\n{{< /highlight >}}{{< highlight yaml >}}\nextraArgs:\n    key:\n        - value1\n        - value2\n{{< /highlight >}}</details> | |\n|`extraMounts` |<a href=\"#Config.machine.kubelet.extraMounts.\">[]ExtraMount</a> |The `extraMounts` field is used to add additional mounts to the kubelet container.<br>Note that either `bind` or `rbind` are required in the `options`. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraMounts:\n    - destination: /var/lib/example # Destination is the absolute path where the mount will be placed in the container.\n      type: bind # Type specifies the mount kind.\n      source: /var/lib/example # Source specifies the source path of the mount.\n      # Options are fstab style mount options.\n      options:\n        - bind\n        - rshared\n        - rw\n{{< /highlight >}}</details> | |\n|`extraConfig` |Unstructured |The `extraConfig` field is used to provide kubelet configuration overrides.<br><br>Some fields are not allowed to be overridden: authentication and authorization, cgroups<br>configuration, ports, etc. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraConfig:\n    serverTLSBootstrap: true\n{{< /highlight >}}</details> | |\n|`credentialProviderConfig` |Unstructured |The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncredentialProviderConfig:\n    apiVersion: kubelet.config.k8s.io/v1\n    kind: CredentialProviderConfig\n    providers:\n        - apiVersion: credentialprovider.kubelet.k8s.io/v1\n          defaultCacheDuration: 12h\n          matchImages:\n            - '*.dkr.ecr.*.amazonaws.com'\n            - '*.dkr.ecr.*.amazonaws.com.cn'\n            - '*.dkr.ecr-fips.*.amazonaws.com'\n            - '*.dkr.ecr.us-iso-east-1.c2s.ic.gov'\n            - '*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov'\n          name: ecr-credential-provider\n{{< /highlight >}}</details> | |\n|`defaultRuntimeSeccompProfileEnabled` |bool |Enable container runtime default Seccomp profile.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`registerWithFQDN` |bool |The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.<br>This is required in clouds like AWS.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`nodeIP` |<a href=\"#Config.machine.kubelet.nodeIP\">KubeletNodeIPConfig</a> |The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.<br>This is used when a node has multiple addresses to choose from. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nnodeIP:\n    # The `validSubnets` field configures the networks to pick kubelet node IP from.\n    validSubnets:\n        - 10.0.0.0/8\n        - '!10.0.0.3/32'\n        - fdc7::/16\n{{< /highlight >}}</details> | |\n|`skipNodeRegistration` |bool |The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.<br>This runs kubelet as standalone and only runs static pods.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`disableManifestsDirectory` |bool |The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.<br>It's recommended to configure static pods with the \"pods\" key instead.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n\n\n\n\n#### extraMounts[] {#Config.machine.kubelet.extraMounts.}\n\nExtraMount wraps OCI Mount specification.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    kubelet:\n        extraMounts:\n            - destination: /var/lib/example # Destination is the absolute path where the mount will be placed in the container.\n              type: bind # Type specifies the mount kind.\n              source: /var/lib/example # Source specifies the source path of the mount.\n              # Options are fstab style mount options.\n              options:\n                - bind\n                - rshared\n                - rw\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destination` |string |Destination is the absolute path where the mount will be placed in the container.  | |\n|`type` |string |Type specifies the mount kind.  | |\n|`source` |string |Source specifies the source path of the mount.  | |\n|`options` |[]string |Options are fstab style mount options.  | |\n|`uidMappings` |<a href=\"#Config.machine.kubelet.extraMounts..uidMappings.\">[]LinuxIDMapping</a> |UID/GID mappings used for changing file owners w/o calling chown, fs should support it.<br><br>Every mount point could have its own mapping.  | |\n|`gidMappings` |<a href=\"#Config.machine.kubelet.extraMounts..gidMappings.\">[]LinuxIDMapping</a> |UID/GID mappings used for changing file owners w/o calling chown, fs should support it.<br><br>Every mount point could have its own mapping.  | |\n\n\n\n\n##### uidMappings[] {#Config.machine.kubelet.extraMounts..uidMappings.}\n\nLinuxIDMapping represents the Linux ID mapping.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`containerID` |uint32 |ContainerID is the starting UID/GID in the container.  | |\n|`hostID` |uint32 |HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.  | |\n|`size` |uint32 |Size is the number of IDs to be mapped.  | |\n\n\n\n\n\n\n##### gidMappings[] {#Config.machine.kubelet.extraMounts..gidMappings.}\n\nLinuxIDMapping represents the Linux ID mapping.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`containerID` |uint32 |ContainerID is the starting UID/GID in the container.  | |\n|`hostID` |uint32 |HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.  | |\n|`size` |uint32 |Size is the number of IDs to be mapped.  | |\n\n\n\n\n\n\n\n\n#### nodeIP {#Config.machine.kubelet.nodeIP}\n\nKubeletNodeIPConfig represents the kubelet node IP configuration.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    kubelet:\n        nodeIP:\n            # The `validSubnets` field configures the networks to pick kubelet node IP from.\n            validSubnets:\n                - 10.0.0.0/8\n                - '!10.0.0.3/32'\n                - fdc7::/16\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`validSubnets` |[]string |The `validSubnets` field configures the networks to pick kubelet node IP from.<br>For dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.<br>IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.<br>Negative subnet matches should be specified last to filter out IPs picked by positive matches.<br>If not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.  | |\n\n\n\n\n\n\n\n\n### install {#Config.machine.install}\n\nInstallConfig represents the installation options for preparing a node.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    install:\n        disk: /dev/sda # The disk used for installations.\n        image: ghcr.io/siderolabs/installer:latest # Allows for supplying the image used to perform the installation.\n        wipe: false # Indicates if the installation disk should be wiped at installation time.\n        grubUseUKICmdline: true # Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\n\n        # # Look up disk using disk attributes like model, size, serial and others.\n        # diskSelector:\n        #     size: 4GB # Disk size.\n        #     model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n        #     busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0 # Disk bus path.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disk` |string |The disk used for installations. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndisk: /dev/sda\n{{< /highlight >}}{{< highlight yaml >}}\ndisk: /dev/nvme0\n{{< /highlight >}}</details> | |\n|`diskSelector` |<a href=\"#Config.machine.install.diskSelector\">InstallDiskSelector</a> |Look up disk using disk attributes like model, size, serial and others.<br>Always has priority over `disk`. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndiskSelector:\n    size: '>= 1TB' # Disk size.\n    model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n\n    # # Disk bus path.\n    # busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0\n    # busPath: /pci0000:00/*\n{{< /highlight >}}</details> | |\n|`image` |string |Allows for supplying the image used to perform the installation.<br>Image reference for each Talos release can be found on<br>[GitHub releases page](https://github.com/siderolabs/talos/releases). <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: ghcr.io/siderolabs/installer:latest\n{{< /highlight >}}</details> | |\n|`wipe` |bool |Indicates if the installation disk should be wiped at installation time.<br>Defaults to `true`.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`legacyBIOSSupport` |bool |Indicates if MBR partition should be marked as bootable (active).<br>Should be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.  | |\n|`grubUseUKICmdline` |bool |Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.<br>This changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.  | |\n\n\n\n\n#### diskSelector {#Config.machine.install.diskSelector}\n\nInstallDiskSelector represents a disk query parameters for the install disk lookup.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    install:\n        diskSelector:\n            size: '>= 1TB' # Disk size.\n            model: WDC* # Disk model `/sys/block/<dev>/device/model`.\n\n            # # Disk bus path.\n            # busPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0\n            # busPath: /pci0000:00/*\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`size` |InstallDiskSizeMatcher |Disk size. <details><summary>Show example(s)</summary>Select a disk which size is equal to 4GB.:{{< highlight yaml >}}\nsize: 4GB\n{{< /highlight >}}Select a disk which size is greater than 1TB.:{{< highlight yaml >}}\nsize: '> 1TB'\n{{< /highlight >}}Select a disk which size is less or equal than 2TB.:{{< highlight yaml >}}\nsize: <= 2TB\n{{< /highlight >}}</details> | |\n|`name` |string |Disk name `/sys/block/<dev>/device/name`.  | |\n|`model` |string |Disk model `/sys/block/<dev>/device/model`.  | |\n|`serial` |string |Disk serial number `/sys/block/<dev>/serial`.  | |\n|`modalias` |string |Disk modalias `/sys/block/<dev>/device/modalias`.  | |\n|`uuid` |string |Disk UUID `/sys/block/<dev>/uuid`.  | |\n|`wwid` |string |Disk WWID `/sys/block/<dev>/wwid`.  | |\n|`type` |InstallDiskType |Disk Type.  |`ssd`<br />`hdd`<br />`nvme`<br />`sd`<br /> |\n|`busPath` |string |Disk bus path. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nbusPath: /pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0\n{{< /highlight >}}{{< highlight yaml >}}\nbusPath: /pci0000:00/*\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n### files[] {#Config.machine.files.}\n\nMachineFile represents a file to write to disk.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    files:\n        - content: '...' # The contents of the file.\n          permissions: 0o666 # The file's permissions in octal.\n          path: /tmp/file.txt # The path of the file.\n          op: append # The operation to use\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`content` |string |The contents of the file.  | |\n|`permissions` |FileMode |The file's permissions in octal.  | |\n|`path` |string |The path of the file.  | |\n|`op` |string |The operation to use  |`create`<br />`append`<br />`overwrite`<br /> |\n\n\n\n\n\n\n### features {#Config.machine.features}\n\nFeaturesConfig describes individual Talos features that can be switched on or off.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    features:\n        diskQuotaSupport: true # Enable XFS project quota support for EPHEMERAL partition and user disks.\n\n        # # Configure Talos API access from Kubernetes pods.\n        # kubernetesTalosAPIAccess:\n        #     enabled: true # Enable Talos API access from Kubernetes pods.\n        #     # The list of Talos API roles which can be granted for access from Kubernetes pods.\n        #     allowedRoles:\n        #         - os:reader\n        #     # The list of Kubernetes namespaces Talos API access is available from.\n        #     allowedKubernetesNamespaces:\n        #         - kube-system\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`kubernetesTalosAPIAccess` |<a href=\"#Config.machine.features.kubernetesTalosAPIAccess\">KubernetesTalosAPIAccessConfig</a> |Configure Talos API access from Kubernetes pods.<br><br>This feature is disabled if the feature config is not specified. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nkubernetesTalosAPIAccess:\n    enabled: true # Enable Talos API access from Kubernetes pods.\n    # The list of Talos API roles which can be granted for access from Kubernetes pods.\n    allowedRoles:\n        - os:reader\n    # The list of Kubernetes namespaces Talos API access is available from.\n    allowedKubernetesNamespaces:\n        - kube-system\n{{< /highlight >}}</details> | |\n|`diskQuotaSupport` |bool |Enable XFS project quota support for EPHEMERAL partition and user disks.<br>Also enables kubelet tracking of ephemeral disk usage in the kubelet via quota.  | |\n|`kubePrism` |<a href=\"#Config.machine.features.kubePrism\">KubePrism</a> |KubePrism - local proxy/load balancer on defined port that will distribute<br>requests to all API servers in the cluster.  | |\n|`hostDNS` |<a href=\"#Config.machine.features.hostDNS\">HostDNSConfig</a> |Configures host DNS caching resolver.  | |\n|`imageCache` |<a href=\"#Config.machine.features.imageCache\">ImageCacheConfig</a> |Enable Image Cache feature.  | |\n|`nodeAddressSortAlgorithm` |string |Select the node address sort algorithm.<br>The 'v1' algorithm sorts addresses by the address itself.<br>The 'v2' algorithm prefers more specific prefixes.<br>If unset, defaults to 'v1'.  | |\n\n\n\n\n#### kubernetesTalosAPIAccess {#Config.machine.features.kubernetesTalosAPIAccess}\n\nKubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    features:\n        kubernetesTalosAPIAccess:\n            enabled: true # Enable Talos API access from Kubernetes pods.\n            # The list of Talos API roles which can be granted for access from Kubernetes pods.\n            allowedRoles:\n                - os:reader\n            # The list of Kubernetes namespaces Talos API access is available from.\n            allowedKubernetesNamespaces:\n                - kube-system\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable Talos API access from Kubernetes pods.  | |\n|`allowedRoles` |[]string |The list of Talos API roles which can be granted for access from Kubernetes pods.<br><br>Empty list means that no roles can be granted, so access is blocked.  | |\n|`allowedKubernetesNamespaces` |[]string |The list of Kubernetes namespaces Talos API access is available from.  | |\n\n\n\n\n\n\n#### kubePrism {#Config.machine.features.kubePrism}\n\nKubePrism describes the configuration for the KubePrism load balancer.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable KubePrism support - will start local load balancing proxy.  | |\n|`port` |int |KubePrism port.  | |\n\n\n\n\n\n\n#### hostDNS {#Config.machine.features.hostDNS}\n\nHostDNSConfig describes the configuration for the host DNS resolver.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable host DNS caching resolver.  | |\n|`forwardKubeDNSToHost` |bool |Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.<br><br>When enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of<br>using configured upstream DNS resolvers directly).  | |\n|`resolveMemberNames` |bool |Resolve member hostnames using the host DNS resolver.<br><br>When enabled, cluster member hostnames and node names are resolved using the host DNS resolver.<br>This requires service discovery to be enabled.  | |\n\n\n\n\n\n\n#### imageCache {#Config.machine.features.imageCache}\n\nImageCacheConfig describes the configuration for the Image Cache feature.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`localEnabled` |bool |Enable local image cache.  | |\n\n\n\n\n\n\n\n\n### udev {#Config.machine.udev}\n\nUdevConfig describes how the udev system should be configured.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    udev:\n        # List of udev rules to apply to the udev system\n        rules:\n            - SUBSYSTEM==\"drm\", KERNEL==\"renderD*\", GROUP=\"44\", MODE=\"0660\"\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`rules` |[]string |List of udev rules to apply to the udev system  | |\n\n\n\n\n\n\n### logging {#Config.machine.logging}\n\nLoggingConfig struct configures Talos logging.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    logging:\n        # Logging destination.\n        destinations:\n            - endpoint: tcp://1.2.3.4:12345 # Where to send logs. Supported protocols are \"tcp\" and \"udp\".\n              format: json_lines # Logs format.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`destinations` |<a href=\"#Config.machine.logging.destinations.\">[]LoggingDestination</a> |Logging destination.  | |\n\n\n\n\n#### destinations[] {#Config.machine.logging.destinations.}\n\nLoggingDestination struct configures Talos logging destination.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |<a href=\"#Config.machine.logging.destinations..endpoint\">Endpoint</a> |Where to send logs. Supported protocols are \"tcp\" and \"udp\". <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nendpoint: udp://127.0.0.1:12345\n{{< /highlight >}}{{< highlight yaml >}}\nendpoint: tcp://1.2.3.4:12345\n{{< /highlight >}}</details> | |\n|`format` |string |Logs format.  |`json_lines`<br /> |\n|`extraTags` |map[string]string |Extra tags (key-value) pairs to attach to every log message sent.  | |\n\n\n\n\n##### endpoint {#Config.machine.logging.destinations..endpoint}\n\nEndpoint represents the endpoint URL parsed out of the machine config.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    logging:\n        destinations:\n            - endpoint: https://1.2.3.4:6443\n{{< /highlight >}}\n\n{{< highlight yaml >}}\nmachine:\n    logging:\n        destinations:\n            - endpoint: https://cluster1.internal:6443\n{{< /highlight >}}\n\n{{< highlight yaml >}}\nmachine:\n    logging:\n        destinations:\n            - endpoint: udp://127.0.0.1:12345\n{{< /highlight >}}\n\n{{< highlight yaml >}}\nmachine:\n    logging:\n        destinations:\n            - endpoint: tcp://1.2.3.4:12345\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n\n\n\n\n\n\n\n\n\n\n### kernel {#Config.machine.kernel}\n\nKernelConfig struct configures Talos Linux kernel.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    kernel:\n        # Kernel modules to load.\n        modules:\n            - name: btrfs # Module name.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`modules` |<a href=\"#Config.machine.kernel.modules.\">[]KernelModuleConfig</a> |Kernel modules to load.  | |\n\n\n\n\n#### modules[] {#Config.machine.kernel.modules.}\n\nKernelModuleConfig struct configures Linux kernel modules to load.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Module name.  | |\n|`parameters` |[]string |Module parameters, changes applied after reboot.  | |\n\n\n\n\n\n\n\n\n### seccompProfiles[] {#Config.machine.seccompProfiles.}\n\nMachineSeccompProfile defines seccomp profiles for the machine.\n\n\n\n{{< highlight yaml >}}\nmachine:\n    seccompProfiles:\n        - name: audit.json # The `name` field is used to provide the file name of the seccomp profile.\n          # The `value` field is used to provide the seccomp profile.\n          value:\n            defaultAction: SCMP_ACT_LOG\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |The `name` field is used to provide the file name of the seccomp profile.  | |\n|`value` |Unstructured |The `value` field is used to provide the seccomp profile.  | |\n\n\n\n\n\n\n\n\n## cluster {#Config.cluster}\n\nClusterConfig represents the cluster-wide config values.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    # ControlPlaneConfig represents the control plane configuration options.\n    controlPlane:\n        endpoint: https://1.2.3.4 # Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n        localAPIServerPort: 443 # The port that the API server listens on internally.\n    clusterName: talos.local\n    # ClusterNetworkConfig represents kube networking configuration options.\n    network:\n        # The CNI used.\n        cni:\n            name: flannel # Name of CNI to use.\n        dnsDomain: cluster.local # The domain used by Kubernetes DNS.\n        # The pod subnet CIDR.\n        podSubnets:\n            - 10.244.0.0/16\n        # The service subnet CIDR.\n        serviceSubnets:\n            - 10.96.0.0/12\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`id` |string |Globally unique identifier for this cluster (base64 encoded random 32 bytes).  | |\n|`secret` |string |Shared secret of cluster (base64 encoded random 32 bytes).<br>This secret is shared among cluster members but should never be sent over the network.  | |\n|`controlPlane` |<a href=\"#Config.cluster.controlPlane\">ControlPlaneConfig</a> |Provides control plane specific configuration options. <details><summary>Show example(s)</summary>Setting controlplane endpoint address to 1.2.3.4 and port to 443 example.:{{< highlight yaml >}}\ncontrolPlane:\n    endpoint: https://1.2.3.4 # Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n    localAPIServerPort: 443 # The port that the API server listens on internally.\n{{< /highlight >}}</details> | |\n|`clusterName` |string |Configures the cluster's name.  | |\n|`network` |<a href=\"#Config.cluster.network\">ClusterNetworkConfig</a> |Provides cluster specific network configuration options. <details><summary>Show example(s)</summary>Configuring with flannel CNI and setting up subnets.:{{< highlight yaml >}}\nnetwork:\n    # The CNI used.\n    cni:\n        name: flannel # Name of CNI to use.\n    dnsDomain: cluster.local # The domain used by Kubernetes DNS.\n    # The pod subnet CIDR.\n    podSubnets:\n        - 10.244.0.0/16\n    # The service subnet CIDR.\n    serviceSubnets:\n        - 10.96.0.0/12\n{{< /highlight >}}</details> | |\n|`token` |string |The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster. <details><summary>Show example(s)</summary>Bootstrap token example (do not use in production!).:{{< highlight yaml >}}\ntoken: wlzjyw.bei2zfylhs2by0wd\n{{< /highlight >}}</details> | |\n|`aescbcEncryptionSecret` |string |A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).<br>Enables encryption with AESCBC. <details><summary>Show example(s)</summary>Decryption secret example (do not use in production!).:{{< highlight yaml >}}\naescbcEncryptionSecret: z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\n{{< /highlight >}}</details> | |\n|`secretboxEncryptionSecret` |string |A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).<br>Enables encryption with secretbox.<br>Secretbox has precedence over AESCBC. <details><summary>Show example(s)</summary>Decryption secret example (do not use in production!).:{{< highlight yaml >}}\nsecretboxEncryptionSecret: z01mye6j16bspJYtTB/5SFX8j7Ph4JXxM2Xuu4vsBPM=\n{{< /highlight >}}</details> | |\n|`ca` |PEMEncodedCertificateAndKey |The base64 encoded root certificate authority used by Kubernetes. <details><summary>Show example(s)</summary>ClusterCA example.:{{< highlight yaml >}}\nca:\n    crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n    key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n{{< /highlight >}}</details> | |\n|`acceptedCAs` |[]PEMEncodedCertificate |The list of base64 encoded accepted certificate authorities used by Kubernetes.  | |\n|`aggregatorCA` |PEMEncodedCertificateAndKey |The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.<br><br>This CA can be self-signed. <details><summary>Show example(s)</summary>AggregatorCA example.:{{< highlight yaml >}}\naggregatorCA:\n    crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n    key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n{{< /highlight >}}</details> | |\n|`serviceAccount` |PEMEncodedKey |The base64 encoded private key for service account token generation. <details><summary>Show example(s)</summary>AggregatorCA example.:{{< highlight yaml >}}\nserviceAccount:\n    key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n{{< /highlight >}}</details> | |\n|`apiServer` |<a href=\"#Config.cluster.apiServer\">APIServerConfig</a> |API server specific configuration options. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\napiServer:\n    image: registry.k8s.io/kube-apiserver:v1.36.0-alpha.2 # The container image used in the API server manifest.\n    # Extra arguments to supply to the API server.\n    extraArgs:\n        feature-gates: ServerSideApply=true\n        http2-max-streams-per-connection: \"32\"\n    # Extra certificate subject alternative names for the API server's certificate.\n    certSANs:\n        - 1.2.3.4\n        - 4.5.6.7\n\n    # # Configure the API server admission plugins.\n    # admissionControl:\n    #     - name: PodSecurity # Name is the name of the admission controller.\n    #       # Configuration is an embedded configuration object to be used as the plugin's\n    #       configuration:\n    #         apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n    #         defaults:\n    #             audit: restricted\n    #             audit-version: latest\n    #             enforce: baseline\n    #             enforce-version: latest\n    #             warn: restricted\n    #             warn-version: latest\n    #         exemptions:\n    #             namespaces:\n    #                 - kube-system\n    #             runtimeClasses: []\n    #             usernames: []\n    #         kind: PodSecurityConfiguration\n\n    # # Configure the API server audit policy.\n    # auditPolicy:\n    #     apiVersion: audit.k8s.io/v1\n    #     kind: Policy\n    #     rules:\n    #         - level: Metadata\n\n    # # Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\n    # authorizationConfig:\n    #     - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n    #       name: webhook # Name is used to describe the authorizer.\n    #       # webhook is the configuration for the webhook authorizer.\n    #       webhook:\n    #         connectionInfo:\n    #             type: InClusterConfig\n    #         failurePolicy: Deny\n    #         matchConditionSubjectAccessReviewVersion: v1\n    #         matchConditions:\n    #             - expression: has(request.resourceAttributes)\n    #             - expression: '!(\\''system:serviceaccounts:kube-system\\'' in request.groups)'\n    #         subjectAccessReviewVersion: v1\n    #         timeout: 3s\n    #     - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n    #       name: in-cluster-authorizer # Name is used to describe the authorizer.\n    #       # webhook is the configuration for the webhook authorizer.\n    #       webhook:\n    #         connectionInfo:\n    #             type: InClusterConfig\n    #         failurePolicy: NoOpinion\n    #         matchConditionSubjectAccessReviewVersion: v1\n    #         subjectAccessReviewVersion: v1\n    #         timeout: 3s\n{{< /highlight >}}</details> | |\n|`controllerManager` |<a href=\"#Config.cluster.controllerManager\">ControllerManagerConfig</a> |Controller manager server specific configuration options. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncontrollerManager:\n    image: registry.k8s.io/kube-controller-manager:v1.36.0-alpha.2 # The container image used in the controller manager manifest.\n    # Extra arguments to supply to the controller manager.\n    extraArgs:\n        feature-gates: ServerSideApply=true\n{{< /highlight >}}</details> | |\n|`proxy` |<a href=\"#Config.cluster.proxy\">ProxyConfig</a> |Kube-proxy server-specific configuration options <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nproxy:\n    image: registry.k8s.io/kube-proxy:v1.36.0-alpha.2 # The container image used in the kube-proxy manifest.\n    mode: ipvs # proxy mode of kube-proxy.\n    # Extra arguments to supply to kube-proxy.\n    extraArgs:\n        proxy-mode: iptables\n\n    # # Disable kube-proxy deployment on cluster bootstrap.\n    # disabled: false\n{{< /highlight >}}</details> | |\n|`scheduler` |<a href=\"#Config.cluster.scheduler\">SchedulerConfig</a> |Scheduler server specific configuration options. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nscheduler:\n    image: registry.k8s.io/kube-scheduler:v1.36.0-alpha.2 # The container image used in the scheduler manifest.\n    # Extra arguments to supply to the scheduler.\n    extraArgs:\n        feature-gates: AllBeta=true\n{{< /highlight >}}</details> | |\n|`discovery` |<a href=\"#Config.cluster.discovery\">ClusterDiscoveryConfig</a> |Configures cluster member discovery. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndiscovery:\n    enabled: true # Enable the cluster membership discovery feature.\n    # Configure registries used for cluster member discovery.\n    registries:\n        # Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\n        kubernetes: {}\n        # Service registry is using an external service to push and pull information about cluster members.\n        service:\n            endpoint: https://discovery.talos.dev/ # External service endpoint.\n{{< /highlight >}}</details> | |\n|`etcd` |<a href=\"#Config.cluster.etcd\">EtcdConfig</a> |Etcd specific configuration options. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\netcd:\n    image: registry.k8s.io/etcd:v3.6.8 # The container image used to create the etcd service.\n    # The `ca` is the root certificate authority of the PKI.\n    ca:\n        crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n        key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n    # Extra arguments to supply to etcd.\n    extraArgs:\n        election-timeout: \"5000\"\n\n    # # The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\n    # advertisedSubnets:\n    #     - 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`coreDNS` |<a href=\"#Config.cluster.coreDNS\">CoreDNS</a> |Core DNS specific configuration options. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncoreDNS:\n    image: registry.k8s.io/coredns/coredns:v1.14.2 # The `image` field is an override to the default coredns image.\n{{< /highlight >}}</details> | |\n|`externalCloudProvider` |<a href=\"#Config.cluster.externalCloudProvider\">ExternalCloudProviderConfig</a> |External cloud provider configuration. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nexternalCloudProvider:\n    enabled: true # Enable external cloud provider.\n    # A list of urls that point to additional manifests for an external cloud provider.\n    manifests:\n        - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\n        - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\n{{< /highlight >}}</details> | |\n|`extraManifests` |[]string |A list of urls that point to additional manifests.<br>These will get automatically deployed as part of the bootstrap. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraManifests:\n    - https://www.example.com/manifest1.yaml\n    - https://www.example.com/manifest2.yaml\n{{< /highlight >}}</details> | |\n|`extraManifestHeaders` |map[string]string |A map of key value pairs that will be added while fetching the extraManifests. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraManifestHeaders:\n    Token: \"1234567\"\n    X-ExtraInfo: info\n{{< /highlight >}}</details> | |\n|`inlineManifests` |<a href=\"#Config.cluster.inlineManifests.\">[]ClusterInlineManifest</a> |A list of inline Kubernetes manifests.<br>These will get automatically deployed as part of the bootstrap. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ninlineManifests:\n    - name: namespace-ci # Name of the manifest.\n      contents: |- # Manifest contents as a string.\n        apiVersion: v1\n        kind: Namespace\n        metadata:\n        \tname: ci\n{{< /highlight >}}</details> | |\n|`adminKubeconfig` |<a href=\"#Config.cluster.adminKubeconfig\">AdminKubeconfigConfig</a> |Settings for admin kubeconfig generation.<br>Certificate lifetime can be configured. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadminKubeconfig:\n    certLifetime: 1h0m0s # Admin kubeconfig certificate lifetime (default is 1 year).\n{{< /highlight >}}</details> | |\n|`allowSchedulingOnControlPlanes` |bool |Allows running workload on control-plane nodes. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nallowSchedulingOnControlPlanes: true\n{{< /highlight >}}</details> |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n\n\n\n\n### controlPlane {#Config.cluster.controlPlane}\n\nControlPlaneConfig represents the control plane configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    controlPlane:\n        endpoint: https://1.2.3.4 # Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\n        localAPIServerPort: 443 # The port that the API server listens on internally.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`endpoint` |<a href=\"#Config.cluster.controlPlane.endpoint\">Endpoint</a> |Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.<br>It is single-valued, and may optionally include a port number. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nendpoint: https://1.2.3.4:6443\n{{< /highlight >}}{{< highlight yaml >}}\nendpoint: https://cluster1.internal:6443\n{{< /highlight >}}</details> | |\n|`localAPIServerPort` |int |The port that the API server listens on internally.<br>This may be different than the port portion listed in the endpoint field above.<br>The default is `6443`.  | |\n\n\n\n\n#### endpoint {#Config.cluster.controlPlane.endpoint}\n\nEndpoint represents the endpoint URL parsed out of the machine config.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    controlPlane:\n        endpoint: https://1.2.3.4:6443\n{{< /highlight >}}\n\n{{< highlight yaml >}}\ncluster:\n    controlPlane:\n        endpoint: https://cluster1.internal:6443\n{{< /highlight >}}\n\n{{< highlight yaml >}}\ncluster:\n    controlPlane:\n        endpoint: udp://127.0.0.1:12345\n{{< /highlight >}}\n\n{{< highlight yaml >}}\ncluster:\n    controlPlane:\n        endpoint: tcp://1.2.3.4:12345\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n\n\n\n\n\n\n\n\n### network {#Config.cluster.network}\n\nClusterNetworkConfig represents kube networking configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    network:\n        # The CNI used.\n        cni:\n            name: flannel # Name of CNI to use.\n        dnsDomain: cluster.local # The domain used by Kubernetes DNS.\n        # The pod subnet CIDR.\n        podSubnets:\n            - 10.244.0.0/16\n        # The service subnet CIDR.\n        serviceSubnets:\n            - 10.96.0.0/12\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`cni` |<a href=\"#Config.cluster.network.cni\">CNIConfig</a> |The CNI used.<br>Composed of \"name\" and \"urls\".<br>The \"name\" key supports the following options: \"flannel\", \"custom\", and \"none\".<br>\"flannel\" uses Talos-managed Flannel CNI, and that's the default option.<br>\"custom\" uses custom manifests that should be provided in \"urls\".<br>\"none\" indicates that Talos will not manage any CNI installation. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncni:\n    name: custom # Name of CNI to use.\n    # URLs containing manifests to apply for the CNI.\n    urls:\n        - https://docs.projectcalico.org/archive/v3.20/manifests/canal.yaml\n{{< /highlight >}}</details> | |\n|`dnsDomain` |string |The domain used by Kubernetes DNS.<br>The default is `cluster.local` <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndnsDomain: cluster.local\n{{< /highlight >}}</details> | |\n|`podSubnets` |[]string |The pod subnet CIDR. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\npodSubnets:\n    - 10.244.0.0/16\n{{< /highlight >}}</details> | |\n|`serviceSubnets` |[]string |The service subnet CIDR. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nserviceSubnets:\n    - 10.96.0.0/12\n{{< /highlight >}}</details> | |\n\n\n\n\n#### cni {#Config.cluster.network.cni}\n\nCNIConfig represents the CNI configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    network:\n        cni:\n            name: custom # Name of CNI to use.\n            # URLs containing manifests to apply for the CNI.\n            urls:\n                - https://docs.projectcalico.org/archive/v3.20/manifests/canal.yaml\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of CNI to use.  |`flannel`<br />`custom`<br />`none`<br /> |\n|`urls` |[]string |URLs containing manifests to apply for the CNI.<br>Should be present for \"custom\", must be empty for \"flannel\" and \"none\".  | |\n|`flannel` |<a href=\"#Config.cluster.network.cni.flannel\">FlannelCNIConfig</a> |description: |<br>Flannel configuration options.<br>  | |\n\n\n\n\n##### flannel {#Config.cluster.network.cni.flannel}\n\nFlannelCNIConfig represents the Flannel CNI configuration options.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`extraArgs` |[]string |Extra arguments for 'flanneld'. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nextraArgs:\n    - --iface-can-reach=192.168.1.1\n{{< /highlight >}}</details> | |\n|`kubeNetworkPoliciesEnabled` |bool |Deploys kube-network-policies along with Flannel.<br><br>This enables Kubernetes Network Policies support in the cluster.  | |\n\n\n\n\n\n\n\n\n\n\n### apiServer {#Config.cluster.apiServer}\n\nAPIServerConfig represents the kube apiserver configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    apiServer:\n        image: registry.k8s.io/kube-apiserver:v1.36.0-alpha.2 # The container image used in the API server manifest.\n        # Extra arguments to supply to the API server.\n        extraArgs:\n            feature-gates: ServerSideApply=true\n            http2-max-streams-per-connection: \"32\"\n        # Extra certificate subject alternative names for the API server's certificate.\n        certSANs:\n            - 1.2.3.4\n            - 4.5.6.7\n\n        # # Configure the API server admission plugins.\n        # admissionControl:\n        #     - name: PodSecurity # Name is the name of the admission controller.\n        #       # Configuration is an embedded configuration object to be used as the plugin's\n        #       configuration:\n        #         apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n        #         defaults:\n        #             audit: restricted\n        #             audit-version: latest\n        #             enforce: baseline\n        #             enforce-version: latest\n        #             warn: restricted\n        #             warn-version: latest\n        #         exemptions:\n        #             namespaces:\n        #                 - kube-system\n        #             runtimeClasses: []\n        #             usernames: []\n        #         kind: PodSecurityConfiguration\n\n        # # Configure the API server audit policy.\n        # auditPolicy:\n        #     apiVersion: audit.k8s.io/v1\n        #     kind: Policy\n        #     rules:\n        #         - level: Metadata\n\n        # # Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\n        # authorizationConfig:\n        #     - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n        #       name: webhook # Name is used to describe the authorizer.\n        #       # webhook is the configuration for the webhook authorizer.\n        #       webhook:\n        #         connectionInfo:\n        #             type: InClusterConfig\n        #         failurePolicy: Deny\n        #         matchConditionSubjectAccessReviewVersion: v1\n        #         matchConditions:\n        #             - expression: has(request.resourceAttributes)\n        #             - expression: '!(\\''system:serviceaccounts:kube-system\\'' in request.groups)'\n        #         subjectAccessReviewVersion: v1\n        #         timeout: 3s\n        #     - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n        #       name: in-cluster-authorizer # Name is used to describe the authorizer.\n        #       # webhook is the configuration for the webhook authorizer.\n        #       webhook:\n        #         connectionInfo:\n        #             type: InClusterConfig\n        #         failurePolicy: NoOpinion\n        #         matchConditionSubjectAccessReviewVersion: v1\n        #         subjectAccessReviewVersion: v1\n        #         timeout: 3s\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |The container image used in the API server manifest. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: registry.k8s.io/kube-apiserver:v1.36.0-alpha.2\n{{< /highlight >}}</details> | |\n|`extraArgs` |Args |Extra arguments to supply to the API server.  | |\n|`extraVolumes` |<a href=\"#Config.cluster.apiServer.extraVolumes.\">[]VolumeMountConfig</a> |Extra volumes to mount to the API server static pod.  | |\n|`env` |Env |The `env` field allows for the addition of environment variables for the control plane component.  | |\n|`certSANs` |[]string |Extra certificate subject alternative names for the API server's certificate.  | |\n|`admissionControl` |<a href=\"#Config.cluster.apiServer.admissionControl.\">[]AdmissionPluginConfig</a> |Configure the API server admission plugins. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadmissionControl:\n    - name: PodSecurity # Name is the name of the admission controller.\n      # Configuration is an embedded configuration object to be used as the plugin's\n      configuration:\n        apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n        defaults:\n            audit: restricted\n            audit-version: latest\n            enforce: baseline\n            enforce-version: latest\n            warn: restricted\n            warn-version: latest\n        exemptions:\n            namespaces:\n                - kube-system\n            runtimeClasses: []\n            usernames: []\n        kind: PodSecurityConfiguration\n{{< /highlight >}}</details> | |\n|`auditPolicy` |Unstructured |Configure the API server audit policy. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nauditPolicy:\n    apiVersion: audit.k8s.io/v1\n    kind: Policy\n    rules:\n        - level: Metadata\n{{< /highlight >}}</details> | |\n|`resources` |<a href=\"#Config.cluster.apiServer.resources\">ResourcesConfig</a> |Configure the API server resources.  | |\n|`authorizationConfig` |<a href=\"#Config.cluster.apiServer.authorizationConfig.\">[]AuthorizationConfigAuthorizerConfig</a> |Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nauthorizationConfig:\n    - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n      name: webhook # Name is used to describe the authorizer.\n      # webhook is the configuration for the webhook authorizer.\n      webhook:\n        connectionInfo:\n            type: InClusterConfig\n        failurePolicy: Deny\n        matchConditionSubjectAccessReviewVersion: v1\n        matchConditions:\n            - expression: has(request.resourceAttributes)\n            - expression: '!(\\''system:serviceaccounts:kube-system\\'' in request.groups)'\n        subjectAccessReviewVersion: v1\n        timeout: 3s\n    - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n      name: in-cluster-authorizer # Name is used to describe the authorizer.\n      # webhook is the configuration for the webhook authorizer.\n      webhook:\n        connectionInfo:\n            type: InClusterConfig\n        failurePolicy: NoOpinion\n        matchConditionSubjectAccessReviewVersion: v1\n        subjectAccessReviewVersion: v1\n        timeout: 3s\n{{< /highlight >}}</details> | |\n\n\n\n\n#### extraVolumes[] {#Config.cluster.apiServer.extraVolumes.}\n\nVolumeMountConfig struct describes extra volume mount for the static pods.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`hostPath` |string |Path on the host. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhostPath: /var/lib/auth\n{{< /highlight >}}</details> | |\n|`mountPath` |string |Path in the container. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmountPath: /etc/kubernetes/auth\n{{< /highlight >}}</details> | |\n|`readonly` |bool |Mount the volume read only. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nreadonly: true\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n#### admissionControl[] {#Config.cluster.apiServer.admissionControl.}\n\nAdmissionPluginConfig represents the API server admission plugin configuration.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    apiServer:\n        admissionControl:\n            - name: PodSecurity # Name is the name of the admission controller.\n              # Configuration is an embedded configuration object to be used as the plugin's\n              configuration:\n                apiVersion: pod-security.admission.config.k8s.io/v1alpha1\n                defaults:\n                    audit: restricted\n                    audit-version: latest\n                    enforce: baseline\n                    enforce-version: latest\n                    warn: restricted\n                    warn-version: latest\n                exemptions:\n                    namespaces:\n                        - kube-system\n                    runtimeClasses: []\n                    usernames: []\n                kind: PodSecurityConfiguration\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name is the name of the admission controller.<br>It must match the registered admission plugin name.  | |\n|`configuration` |Unstructured |Configuration is an embedded configuration object to be used as the plugin's<br>configuration.  | |\n\n\n\n\n\n\n#### resources {#Config.cluster.apiServer.resources}\n\nResourcesConfig represents the pod resources.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`requests` |Unstructured |Requests configures the reserved cpu/memory resources. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nrequests:\n    cpu: 1\n    memory: 1Gi\n{{< /highlight >}}</details> | |\n|`limits` |Unstructured |Limits configures the maximum cpu/memory resources a container can use. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nlimits:\n    cpu: 2\n    memory: 2500Mi\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n#### authorizationConfig[] {#Config.cluster.apiServer.authorizationConfig.}\n\nAuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    apiServer:\n        authorizationConfig:\n            - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n              name: webhook # Name is used to describe the authorizer.\n              # webhook is the configuration for the webhook authorizer.\n              webhook:\n                connectionInfo:\n                    type: InClusterConfig\n                failurePolicy: Deny\n                matchConditionSubjectAccessReviewVersion: v1\n                matchConditions:\n                    - expression: has(request.resourceAttributes)\n                    - expression: '!(\\''system:serviceaccounts:kube-system\\'' in request.groups)'\n                subjectAccessReviewVersion: v1\n                timeout: 3s\n            - type: Webhook # Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\n              name: in-cluster-authorizer # Name is used to describe the authorizer.\n              # webhook is the configuration for the webhook authorizer.\n              webhook:\n                connectionInfo:\n                    type: InClusterConfig\n                failurePolicy: NoOpinion\n                matchConditionSubjectAccessReviewVersion: v1\n                subjectAccessReviewVersion: v1\n                timeout: 3s\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`type` |string |Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.  | |\n|`name` |string |Name is used to describe the authorizer.  | |\n|`webhook` |Unstructured |webhook is the configuration for the webhook authorizer.  | |\n\n\n\n\n\n\n\n\n### controllerManager {#Config.cluster.controllerManager}\n\nControllerManagerConfig represents the kube controller manager configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    controllerManager:\n        image: registry.k8s.io/kube-controller-manager:v1.36.0-alpha.2 # The container image used in the controller manager manifest.\n        # Extra arguments to supply to the controller manager.\n        extraArgs:\n            feature-gates: ServerSideApply=true\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |The container image used in the controller manager manifest. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: registry.k8s.io/kube-controller-manager:v1.36.0-alpha.2\n{{< /highlight >}}</details> | |\n|`extraArgs` |Args |Extra arguments to supply to the controller manager.  | |\n|`extraVolumes` |<a href=\"#Config.cluster.controllerManager.extraVolumes.\">[]VolumeMountConfig</a> |Extra volumes to mount to the controller manager static pod.  | |\n|`env` |Env |The `env` field allows for the addition of environment variables for the control plane component.  | |\n|`resources` |<a href=\"#Config.cluster.controllerManager.resources\">ResourcesConfig</a> |Configure the controller manager resources.  | |\n\n\n\n\n#### extraVolumes[] {#Config.cluster.controllerManager.extraVolumes.}\n\nVolumeMountConfig struct describes extra volume mount for the static pods.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`hostPath` |string |Path on the host. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhostPath: /var/lib/auth\n{{< /highlight >}}</details> | |\n|`mountPath` |string |Path in the container. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmountPath: /etc/kubernetes/auth\n{{< /highlight >}}</details> | |\n|`readonly` |bool |Mount the volume read only. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nreadonly: true\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n#### resources {#Config.cluster.controllerManager.resources}\n\nResourcesConfig represents the pod resources.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`requests` |Unstructured |Requests configures the reserved cpu/memory resources. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nrequests:\n    cpu: 1\n    memory: 1Gi\n{{< /highlight >}}</details> | |\n|`limits` |Unstructured |Limits configures the maximum cpu/memory resources a container can use. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nlimits:\n    cpu: 2\n    memory: 2500Mi\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n### proxy {#Config.cluster.proxy}\n\nProxyConfig represents the kube proxy configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    proxy:\n        image: registry.k8s.io/kube-proxy:v1.36.0-alpha.2 # The container image used in the kube-proxy manifest.\n        mode: ipvs # proxy mode of kube-proxy.\n        # Extra arguments to supply to kube-proxy.\n        extraArgs:\n            proxy-mode: iptables\n\n        # # Disable kube-proxy deployment on cluster bootstrap.\n        # disabled: false\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable kube-proxy deployment on cluster bootstrap. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ndisabled: false\n{{< /highlight >}}</details> | |\n|`image` |string |The container image used in the kube-proxy manifest. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: registry.k8s.io/kube-proxy:v1.36.0-alpha.2\n{{< /highlight >}}</details> | |\n|`mode` |string |proxy mode of kube-proxy.<br>The default is 'iptables'.  | |\n|`extraArgs` |Args |Extra arguments to supply to kube-proxy.  | |\n\n\n\n\n\n\n### scheduler {#Config.cluster.scheduler}\n\nSchedulerConfig represents the kube scheduler configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    scheduler:\n        image: registry.k8s.io/kube-scheduler:v1.36.0-alpha.2 # The container image used in the scheduler manifest.\n        # Extra arguments to supply to the scheduler.\n        extraArgs:\n            feature-gates: AllBeta=true\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |The container image used in the scheduler manifest. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: registry.k8s.io/kube-scheduler:v1.36.0-alpha.2\n{{< /highlight >}}</details> | |\n|`extraArgs` |Args |Extra arguments to supply to the scheduler.  | |\n|`extraVolumes` |<a href=\"#Config.cluster.scheduler.extraVolumes.\">[]VolumeMountConfig</a> |Extra volumes to mount to the scheduler static pod.  | |\n|`env` |Env |The `env` field allows for the addition of environment variables for the control plane component.  | |\n|`resources` |<a href=\"#Config.cluster.scheduler.resources\">ResourcesConfig</a> |Configure the scheduler resources.  | |\n|`config` |Unstructured |Specify custom kube-scheduler configuration.  | |\n\n\n\n\n#### extraVolumes[] {#Config.cluster.scheduler.extraVolumes.}\n\nVolumeMountConfig struct describes extra volume mount for the static pods.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`hostPath` |string |Path on the host. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nhostPath: /var/lib/auth\n{{< /highlight >}}</details> | |\n|`mountPath` |string |Path in the container. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmountPath: /etc/kubernetes/auth\n{{< /highlight >}}</details> | |\n|`readonly` |bool |Mount the volume read only. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nreadonly: true\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n#### resources {#Config.cluster.scheduler.resources}\n\nResourcesConfig represents the pod resources.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`requests` |Unstructured |Requests configures the reserved cpu/memory resources. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nrequests:\n    cpu: 1\n    memory: 1Gi\n{{< /highlight >}}</details> | |\n|`limits` |Unstructured |Limits configures the maximum cpu/memory resources a container can use. <details><summary>Show example(s)</summary>resources requests.:{{< highlight yaml >}}\nlimits:\n    cpu: 2\n    memory: 2500Mi\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n### discovery {#Config.cluster.discovery}\n\nClusterDiscoveryConfig struct configures cluster membership discovery.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    discovery:\n        enabled: true # Enable the cluster membership discovery feature.\n        # Configure registries used for cluster member discovery.\n        registries:\n            # Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\n            kubernetes: {}\n            # Service registry is using an external service to push and pull information about cluster members.\n            service:\n                endpoint: https://discovery.talos.dev/ # External service endpoint.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable the cluster membership discovery feature.<br>Cluster discovery is based on individual registries which are configured under the registries field.  | |\n|`registries` |<a href=\"#Config.cluster.discovery.registries\">DiscoveryRegistriesConfig</a> |Configure registries used for cluster member discovery.  | |\n\n\n\n\n#### registries {#Config.cluster.discovery.registries}\n\nDiscoveryRegistriesConfig struct configures cluster membership discovery.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`kubernetes` |<a href=\"#Config.cluster.discovery.registries.kubernetes\">RegistryKubernetesConfig</a> |Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information<br>as annotations on the Node resources.<br><br>This feature is deprecated as it is not compatible with Kubernetes 1.32+.<br>See https://github.com/siderolabs/talos/issues/9980 for more information.  | |\n|`service` |<a href=\"#Config.cluster.discovery.registries.service\">RegistryServiceConfig</a> |Service registry is using an external service to push and pull information about cluster members.  | |\n\n\n\n\n##### kubernetes {#Config.cluster.discovery.registries.kubernetes}\n\nRegistryKubernetesConfig struct configures Kubernetes discovery registry.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable Kubernetes discovery registry.  | |\n\n\n\n\n\n\n##### service {#Config.cluster.discovery.registries.service}\n\nRegistryServiceConfig struct configures Kubernetes discovery registry.\n\n\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable external service discovery registry.  | |\n|`endpoint` |string |External service endpoint. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nendpoint: https://discovery.talos.dev/\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n\n\n\n\n### etcd {#Config.cluster.etcd}\n\nEtcdConfig represents the etcd configuration options.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    etcd:\n        image: registry.k8s.io/etcd:v3.6.8 # The container image used to create the etcd service.\n        # The `ca` is the root certificate authority of the PKI.\n        ca:\n            crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n            key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n        # Extra arguments to supply to etcd.\n        extraArgs:\n            election-timeout: \"5000\"\n\n        # # The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\n        # advertisedSubnets:\n        #     - 10.0.0.0/8\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`image` |string |The container image used to create the etcd service. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nimage: registry.k8s.io/etcd:v3.6.8\n{{< /highlight >}}</details> | |\n|`ca` |PEMEncodedCertificateAndKey |The `ca` is the root certificate authority of the PKI.<br>It is composed of a base64 encoded `crt` and `key`. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nca:\n    crt: LS0tIEVYQU1QTEUgQ0VSVElGSUNBVEUgLS0t\n    key: LS0tIEVYQU1QTEUgS0VZIC0tLQ==\n{{< /highlight >}}</details> | |\n|`extraArgs` |Args |Extra arguments to supply to etcd.<br>Note that the following args are not allowed:<br><br>- `name`<br>- `data-dir`<br>- `initial-cluster-state`<br>- `listen-peer-urls`<br>- `listen-client-urls`<br>- `cert-file`<br>- `key-file`<br>- `trusted-ca-file`<br>- `peer-client-cert-auth`<br>- `peer-cert-file`<br>- `peer-trusted-ca-file`<br>- `peer-key-file`  | |\n|`advertisedSubnets` |[]string |The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.<br><br>IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.<br>Negative subnet matches should be specified last to filter out IPs picked by positive matches.<br>If not specified, advertised IP is selected as the first routable address of the node. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nadvertisedSubnets:\n    - 10.0.0.0/8\n{{< /highlight >}}</details> | |\n|`listenSubnets` |[]string |The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.<br><br>If `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to<br>`advertisedSubnets`.<br><br>If neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.<br><br>IPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.<br>Negative subnet matches should be specified last to filter out IPs picked by positive matches.<br>If not specified, advertised IP is selected as the first routable address of the node.  | |\n\n\n\n\n\n\n### coreDNS {#Config.cluster.coreDNS}\n\nCoreDNS represents the CoreDNS config values.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    coreDNS:\n        image: registry.k8s.io/coredns/coredns:v1.14.2 # The `image` field is an override to the default coredns image.\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`disabled` |bool |Disable coredns deployment on cluster bootstrap.  | |\n|`image` |string |The `image` field is an override to the default coredns image.  | |\n\n\n\n\n\n\n### externalCloudProvider {#Config.cluster.externalCloudProvider}\n\nExternalCloudProviderConfig contains external cloud provider configuration.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    externalCloudProvider:\n        enabled: true # Enable external cloud provider.\n        # A list of urls that point to additional manifests for an external cloud provider.\n        manifests:\n            - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\n            - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`enabled` |bool |Enable external cloud provider.  |`true`<br />`yes`<br />`false`<br />`no`<br /> |\n|`manifests` |[]string |A list of urls that point to additional manifests for an external cloud provider.<br>These will get automatically deployed as part of the bootstrap. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nmanifests:\n    - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml\n    - https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n### inlineManifests[] {#Config.cluster.inlineManifests.}\n\nClusterInlineManifest struct describes inline bootstrap manifests for the user.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    inlineManifests:\n        - name: namespace-ci # Name of the manifest.\n          contents: |- # Manifest contents as a string.\n            apiVersion: v1\n            kind: Namespace\n            metadata:\n            \tname: ci\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`name` |string |Name of the manifest.<br>Name should be unique. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\nname: csi\n{{< /highlight >}}</details> | |\n|`contents` |string |Manifest contents as a string. <details><summary>Show example(s)</summary>{{< highlight yaml >}}\ncontents: /etc/kubernetes/auth\n{{< /highlight >}}</details> | |\n\n\n\n\n\n\n### adminKubeconfig {#Config.cluster.adminKubeconfig}\n\nAdminKubeconfigConfig contains admin kubeconfig settings.\n\n\n\n{{< highlight yaml >}}\ncluster:\n    adminKubeconfig:\n        certLifetime: 1h0m0s # Admin kubeconfig certificate lifetime (default is 1 year).\n{{< /highlight >}}\n\n\n| Field | Type | Description | Value(s) |\n|-------|------|-------------|----------|\n|`certLifetime` |Duration |Admin kubeconfig certificate lifetime (default is 1 year).<br>Field format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).  | |\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "website/content/v1.13/reference/kernel.md",
    "content": "---\ntitle: \"Kernel\"\ndescription: \"Linux kernel reference.\"\n---\n\n## Commandline Parameters\n\nTalos supports a number of kernel commandline parameters.  Some are required for\nit to operate.  Others are optional and useful in certain circumstances.\n\nSeveral of these are enforced by the Kernel Self Protection Project [KSPP](https://kspp.github.io/Recommended_Settings).\n\n**Required** parameters:\n\n* `talos.platform`: can be one of `akamai`, `aws`, `azure`, `container`, `digitalocean`, `equinixMetal`, `gcp`, `hcloud`, `metal`, `nocloud`, `openstack`, `oracle`, `scaleway`, `upcloud`, `vmware` or `vultr`\n* `slab_nomerge`: required by KSPP\n* `pti=on`: required by KSPP\n\n**Recommended** parameters:\n\n* `init_on_alloc=1`: advised by KSPP, enabled by default in kernel config\n* `init_on_free=1`: advised by KSPP, enabled by default in kernel config\n\n### Available Talos-specific parameters\n\n#### `ip`\n\nInitial configuration of the interface, routes, DNS, NTP servers (multiple `ip=` kernel parameters are accepted).\n\nFull documentation is available in the [Linux kernel docs](https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt).\n\n`ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>:<ntp0-ip>`\n\nTalos will use the configuration supplied via the kernel parameter as the initial network configuration.\nThis parameter is useful in the environments where DHCP doesn't provide IP addresses or when default DNS and NTP servers should be overridden\nbefore loading machine configuration.\nPartial configuration can be applied as well, e.g. `ip=:::::::<dns0-ip>:<dns1-ip>:<ntp0-ip>` sets only the DNS and NTP servers.\n\nIPv6 addresses can be specified by enclosing them in the square brackets, e.g. `ip=[2001:db8::a]:[2001:db8::b]:[fe80::1]::controlplane1:eth1::[2001:4860:4860::6464]:[2001:4860:4860::64]:[2001:4860:4806::]`.\n\n`<netmask>` can use either an IP address notation (IPv4: `255.255.255.0`, IPv6: `[ffff:ffff:ffff:ffff::0]`), or simply a number of one bits in the netmask (`24`).\n\n`<device>` can be traditional interface naming scheme `eth0, eth1` or `enx<MAC>`, example: `enx78e7d1ea46da`\n\nDHCP can be enabled by setting `<autoconf>` to `dhcp`, example: `ip=:::::eth0.3:dhcp`.\nAlternative syntax is `ip=eth0.3:dhcp`.\n\n#### `bond`\n\nBond interface configuration.\n\nFull documentation is available in the [Dracut kernel docs](https://man7.org/linux/man-pages/man7/dracut.cmdline.7.html).\n\n`bond=<bondname>:<bondslaves>:<options>:<mtu>`\n\nTalos will use the `bond=` kernel parameter if supplied to set the initial bond configuration.\nThis parameter is useful in environments where the switch ports are suspended if the machine doesn't setup a LACP bond.\n\nIf only the bond name is supplied, the bond will be created with `eth0` and `eth1` as slaves and bond mode set as `balance-rr`\n\nAll these below configurations are equivalent:\n\n* `bond=bond0`\n* `bond=bond0:`\n* `bond=bond0::`\n* `bond=bond0:::`\n* `bond=bond0:eth0,eth1`\n* `bond=bond0:eth0,eth1:balance-rr`\n\nAn example of a bond configuration with all options specified:\n\n`bond=bond1:eth3,eth4:mode=802.3ad,xmit_hash_policy=layer2+3:1450`\n\nThis will create a bond interface named `bond1` with `eth3` and `eth4` as slaves and set the bond mode to `802.3ad`, the transmit hash policy to `layer2+3` and bond interface MTU to 1450.\n\n#### `vlan`\n\nThe interface vlan configuration.\n\nFull documentation is available in the [Dracut kernel docs](https://man7.org/linux/man-pages/man7/dracut.cmdline.7.html).\n\nTalos will use the `vlan=` kernel parameter if supplied to set the initial vlan configuration.\nThis parameter is useful in environments where the switch ports are VLAN tagged with no native VLAN.\n\nOnly one vlan can be configured at this stage.\n\nAn example of a vlan configuration including static ip configuration:\n\n`vlan=eth0.100:eth0 ip=172.20.0.2::172.20.0.1:255.255.255.0::eth0.100:::::`\n\nThis will create a vlan interface named `eth0.100` with `eth0` as the underlying interface and set the vlan id to 100 with static IP 172.20.0.2/24 and 172.20.0.1 as default gateway.\n\n#### `net.ifnames=0`\n\nDisable the predictable network interface names by specifying `net.ifnames=0` on the kernel command line.\n\n#### `panic`\n\nThe amount of time to wait after a panic before a reboot is issued.\n\nTalos will always reboot if it encounters an unrecoverable error.\nHowever, when collecting debug information, it may reboot too quickly for\nhumans to read the logs.\nThis option allows the user to delay the reboot to give time to collect debug\ninformation from the console screen.\n\nA value of `0` disables automatic rebooting entirely.\n\n#### `talos.config`\n\nThe URL at which the machine configuration data may be found (only for `metal` platform, with the kernel parameter `talos.platform=metal`).\n\nThis parameter supports variable substitution inside URL query values for the following case-insensitive placeholders:\n\n* `${uuid}` the SMBIOS UUID\n* `${serial}` the SMBIOS Serial Number\n* `${mac}` the MAC address of the first network interface attaining link state `up`\n* `${hostname}` the hostname of the machine\n\nThe following example\n\n`http://example.com/metadata?h=${hostname}&m=${mac}&s=${serial}&u=${uuid}`\n\nmay translate to\n\n`http://example.com/metadata?h=myTestHostname&m=52%3A2f%3Afd%3Adf%3Afc%3Ac0&s=0OCZJ19N65&u=40dcbd19-3b10-444e-bfff-aaee44a51fda`\n\nFor backwards compatibility we insert the system UUID into the query parameter `uuid` if its value is empty. As in\n`http://example.com/metadata?uuid=` => `http://example.com/metadata?uuid=40dcbd19-3b10-444e-bfff-aaee44a51fda`\n\n##### `metal-iso`\n\nWhen the kernel parameter `talos.config=metal-iso` is set, Talos will attempt to load the machine configuration from any block device with a filesystem label of `metal-iso`.\nTalos will look for a file named `config.yaml` in the root of the filesystem.\n\nFor example, such ISO filesystem can be created with:\n\n```sh\nmkdir iso/\ncp config.yaml iso/\nmkisofs -joliet -rock -volid 'metal-iso' -output config.iso iso/\n```\n\n#### `talos.config.auth.*`\n\nKernel parameters prefixed with `talos.config.auth.` are used to configure [OAuth2 authentication for the machine configuration]({{< relref \"../advanced/machine-config-oauth\" >}}).\n\n#### `talos.config.early` and `talos.config.inline`\n\nThe kernel parameters `talos.config.early` and `talos.config.inline` are used to provide the initial machine configuration directly on the kernel command line.\n\nThe difference between the two is the order of configuration loading:\n\n* first, the persisted configuration is loaded from the `STATE` partition, if it exists;\n* `talos.config.early` is tried next;\n* any platform-specific configuration source is tried next (e.g. `talos.config` for the `metal` platform, our VM user data source, etc.);\n* finally, `talos.config.inline` is tried;\n* if no complete configuration is found, the system will enter maintenance mode.\n\nFor both arguments, the machine configuration should be `zstd` compressed and base64-encoded to be passed as a kernel parameter.\n\n> Note: The kernel command line has a limited size (~2000 bytes), so this method is only suitable for small configuration documents.\n\nOne such example is to provide [a custom CA certificate]({{<  relref \"../talos-guides/configuration/certificate-authorities\" >}}) via `TrustedRootsConfig` in the machine configuration:\n\n```shell\ncat config.yaml | zstd --compress --ultra -22 | base64 -w 0\n```\n\nPlease note that configuration from this argument is only loaded if the configuration hasn't been yet saved to `STATE` partition.\n\n#### `talos.platform`\n\nThe platform name on which Talos will run.\n\nValid options are:\n\n* `akamai`\n* `aws`\n* `azure`\n* `container`\n* `digitalocean`\n* `equinixMetal`\n* `gcp`\n* `hcloud`\n* `metal`\n* `nocloud`\n* `openstack`\n* `oracle`\n* `scaleway`\n* `upcloud`\n* `vmware`\n* `vultr`\n\n#### `talos.hostname`\n\nThe hostname to be used.\nThe hostname is generally specified in the machine config.\nHowever, in some cases, the DHCP server needs to know the hostname\nbefore the machine configuration has been acquired.\n\nUnless specifically required, the machine configuration should be used\ninstead.\n\n#### `talos.shutdown`\n\nThe type of shutdown to use when Talos is told to shutdown.\n\nValid options are:\n\n* `halt`\n* `poweroff`\n\n#### `talos.network.interface.ignore`\n\nA network interface which should be ignored and not configured by Talos.\n\nBefore a configuration is applied (early on each boot), Talos attempts to\nconfigure each network interface by DHCP.\nIf there are many network interfaces on the machine which have link but no\nDHCP server, this can add significant boot delays.\n\nThis option may be specified multiple times for multiple network interfaces.\n\n#### `talos.experimental.wipe`\n\nResets the disk before starting up the system.\n\nValid options are:\n\n* `system` resets system disk.\n* `system:EPHEMERAL,STATE` resets ephemeral and state partitions. Doing this reverts Talos into maintenance mode.\n\n#### `talos.auditd.disabled`\n\nBy default, Talos runs `auditd` service capturing kernel audit events.\nIf you set `talos.auditd.disabled=1`, this behavior will be disabled, and you can run your own `auditd` service.\n\n#### `talos.dashboard.disabled`\n\nBy default, Talos redirects kernel logs to virtual console `/dev/tty1` and starts the dashboard on `/dev/tty2`,\nthen switches to the dashboard tty.\n\nIf you set `talos.dashboard.disabled=1`, this behavior will be disabled.\nKernel logs will be sent to the currently active console and the dashboard will not be started.\n\nIt is set to be `1` by default on SBCs.\n\n#### `talos.dashboard.console`\n\nBy default, the Talos dashboard runs on `/dev/tty2` with automatic TTY switching.\nYou can specify a custom console device for the dashboard using this parameter.\n\nFor example, to run the dashboard on a serial console:\n\n```text\ntalos.dashboard.console=ttyS0\n```\n\nWhen this parameter is specified:\n\n* The dashboard will run on `/dev/ttyS0`\n* TTY switching will be disabled (no automatic switching between tty1 and tty2)\n* The console name must start with \"tty\"\n\nThis is useful for headless servers or systems where you want the dashboard accessible through a serial console connection.\n\n> Note: If Talos dashboard is set to use ttyS0, make sure that Linux kernel command line doesn't include\n> `console=ttyS0` or similar, as it will conflict with the dashboard output.\n\n#### `talos.environment`\n\nEach value of the argument sets a default environment variable.\nThe expected format is `key=value`.\n\nExample:\n\n```text\ntalos.environment=http_proxy=http://proxy.example.com:8080 talos.environment=https_proxy=http://proxy.example.com:8080\n```\n\n#### `talos.device.settle_time`\n\nThe time in Go duration format to wait for devices to settle before starting the boot process.\nBy default, Talos waits for `udevd` to scan and settle, but with some RAID controllers `udevd` might\nreport settled devices before they are actually ready.\nAdding this kernel argument provides extra settle time on top of `udevd` settle time.\nThe maximum value is `10m` (10 minutes).\n\nExample:\n\n```text\ntalos.device.settle_time=3m\n```\n\n#### `talos.halt_if_installed`\n\nIf set to `1`, Talos will pause the boot sequence and keeps printing a message until the boot timeout is reached if it detects that it is already installed.\nThis is useful if booting from ISO/PXE and you want to prevent the machine accidentally booting from the ISO/PXE after installation to the disk.\n"
  },
  {
    "path": "website/content/v1.13/schemas/config.schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://talos.dev/v1.13/schemas/config.schema.json\",\n  \"$defs\": {\n    \"block.DiskSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the disk.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the disk.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"DiskSelector selects a disk for the volume.\"\n    },\n    \"block.EncryptionKey\": {\n      \"properties\": {\n        \"slot\": {\n          \"type\": \"integer\",\n          \"title\": \"slot\",\n          \"description\": \"Key slot number for LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Key slot number for LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey slot number for LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"static\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyStatic\",\n          \"title\": \"static\",\n          \"description\": \"Key which value is stored in the configuration file.\\n\",\n          \"markdownDescription\": \"Key which value is stored in the configuration file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey which value is stored in the configuration file.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeID\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyNodeID\",\n          \"title\": \"nodeID\",\n          \"description\": \"Deterministically generated key from the node UUID and PartitionLabel.\\n\",\n          \"markdownDescription\": \"Deterministically generated key from the node UUID and PartitionLabel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeterministically generated key from the node UUID and PartitionLabel.\\u003c/p\\u003e\\n\"\n        },\n        \"kms\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyKMS\",\n          \"title\": \"kms\",\n          \"description\": \"KMS managed encryption key.\\n\",\n          \"markdownDescription\": \"KMS managed encryption key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS managed encryption key.\\u003c/p\\u003e\\n\"\n        },\n        \"tpm\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyTPM\",\n          \"title\": \"tpm\",\n          \"description\": \"Enable TPM based disk encryption.\\n\",\n          \"markdownDescription\": \"Enable TPM based disk encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable TPM based disk encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"lockToState\": {\n          \"type\": \"boolean\",\n          \"title\": \"lockToState\",\n          \"description\": \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\\n\",\n          \"markdownDescription\": \"Lock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLock the disk encryption key to the random salt stored in the STATE partition. This is useful to prevent the volume from being unlocked if STATE partition is compromised or replaced. It is recommended to use this option with TPM disk encryption for non-STATE volumes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKey represents configuration for disk encryption key.\"\n    },\n    \"block.EncryptionKeyKMS\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"KMS endpoint to Seal/Unseal the key.\\n\",\n          \"markdownDescription\": \"KMS endpoint to Seal/Unseal the key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS endpoint to Seal/Unseal the key.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyKMS represents a key that is generated and then sealed/unsealed by the KMS server.\"\n    },\n    \"block.EncryptionKeyNodeID\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyNodeID represents deterministically generated key from the node UUID and PartitionLabel.\"\n    },\n    \"block.EncryptionKeyStatic\": {\n      \"properties\": {\n        \"passphrase\": {\n          \"type\": \"string\",\n          \"title\": \"passphrase\",\n          \"description\": \"Defines the static passphrase value.\\n\",\n          \"markdownDescription\": \"Defines the static passphrase value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the static passphrase value.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyStatic represents throw away key type.\"\n    },\n    \"block.EncryptionKeyTPM\": {\n      \"properties\": {\n        \"options\": {\n          \"$ref\": \"#/$defs/block.EncryptionKeyTPMOptions\",\n          \"title\": \"options\",\n          \"description\": \"TPM options for key protection.\\n\",\n          \"markdownDescription\": \"TPM options for key protection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTPM options for key protection.\\u003c/p\\u003e\\n\"\n        },\n        \"checkSecurebootStatusOnEnroll\": {\n          \"type\": \"boolean\",\n          \"title\": \"checkSecurebootStatusOnEnroll\",\n          \"description\": \"Check that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\\n\",\n          \"markdownDescription\": \"Check that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCheck that Secureboot is enabled in the EFI firmware.\\nIf Secureboot is not enabled, the enrollment of the key will fail.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyTPM represents a key that is generated and then sealed/unsealed by the TPM.\"\n    },\n    \"block.EncryptionKeyTPMOptions\": {\n      \"properties\": {\n        \"pcrs\": {\n          \"items\": {\n            \"type\": \"integer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pcrs\",\n          \"description\": \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\\n\",\n          \"markdownDescription\": \"List of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of PCRs to bind the key to. If not set, defaults to PCR 7, can be disabled by passing an empty list.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionKeyTPMOptions represents the options for TPM-based key protection.\"\n    },\n    \"block.EncryptionSpec\": {\n      \"properties\": {\n        \"provider\": {\n          \"enum\": [\n            \"luks2\"\n          ],\n          \"title\": \"provider\",\n          \"description\": \"Encryption provider to use for the encryption.\\n\",\n          \"markdownDescription\": \"Encryption provider to use for the encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEncryption provider to use for the encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"keys\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/block.EncryptionKey\"\n          },\n          \"type\": \"array\",\n          \"title\": \"keys\",\n          \"description\": \"Defines the encryption keys generation and storage method.\\n\",\n          \"markdownDescription\": \"Defines the encryption keys generation and storage method.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption keys generation and storage method.\\u003c/p\\u003e\\n\"\n        },\n        \"cipher\": {\n          \"enum\": [\n            \"aes-xts-plain64\",\n            \"xchacha12,aes-adiantum-plain64\",\n            \"xchacha20,aes-adiantum-plain64\"\n          ],\n          \"title\": \"cipher\",\n          \"description\": \"Cipher to use for the encryption. Depends on the encryption provider.\\n\",\n          \"markdownDescription\": \"Cipher to use for the encryption. Depends on the encryption provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCipher to use for the encryption. Depends on the encryption provider.\\u003c/p\\u003e\\n\"\n        },\n        \"keySize\": {\n          \"type\": \"integer\",\n          \"title\": \"keySize\",\n          \"description\": \"Defines the encryption key length.\\n\",\n          \"markdownDescription\": \"Defines the encryption key length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption key length.\\u003c/p\\u003e\\n\"\n        },\n        \"blockSize\": {\n          \"type\": \"integer\",\n          \"title\": \"blockSize\",\n          \"description\": \"Defines the encryption sector size.\\n\",\n          \"markdownDescription\": \"Defines the encryption sector size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption sector size.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"enum\": [\n            \"no_read_workqueue\",\n            \"no_write_workqueue\",\n            \"same_cpu_crypt\"\n          ],\n          \"title\": \"options\",\n          \"description\": \"Additional –perf parameters for the LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Additional --perf parameters for the LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdditional \\u0026ndash;perf parameters for the LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EncryptionSpec represents volume encryption settings.\"\n    },\n    \"block.ExistingMountSpec\": {\n      \"properties\": {\n        \"readOnly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readOnly\",\n          \"description\": \"Mount the volume read-only.\\n\",\n          \"markdownDescription\": \"Mount the volume read-only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read-only.\\u003c/p\\u003e\\n\"\n        },\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExistingMountSpec describes how the volume is mounted.\"\n    },\n    \"block.ExistingVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExistingVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/block.VolumeDiscoverySpec\",\n          \"title\": \"discovery\",\n          \"description\": \"The discovery describes how to find a volume.\\n\",\n          \"markdownDescription\": \"The discovery describes how to find a volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe discovery describes how to find a volume.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.ExistingMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ExistingVolumeConfig is an existing volume configuration document.\\\\nExisting volumes allow to mount partitions (or whole disks) that were created\\\\noutside of Talos. Volume will be mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe existing volume config name should not conflict with user volume names.\\\\n\"\n    },\n    \"block.ExternalMountSpec\": {\n      \"properties\": {\n        \"readOnly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readOnly\",\n          \"description\": \"Mount the volume read-only.\\n\",\n          \"markdownDescription\": \"Mount the volume read-only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read-only.\\u003c/p\\u003e\\n\"\n        },\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        },\n        \"virtiofs\": {\n          \"$ref\": \"#/$defs/block.VirtiofsMountSpec\",\n          \"title\": \"virtiofs\",\n          \"description\": \"Virtiofs mount options.\\n\",\n          \"markdownDescription\": \"Virtiofs mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVirtiofs mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExternalMountSpec describes how the external volume is mounted.\"\n    },\n    \"block.ExternalVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExternalVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the mount.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the mount.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the mount.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"filesystemType\": {\n          \"enum\": [\n            \"virtiofs\",\n            \"nfs\"\n          ],\n          \"title\": \"filesystemType\",\n          \"description\": \"Filesystem type.\\n\",\n          \"markdownDescription\": \"Filesystem type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilesystem type.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.ExternalMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ExternalVolumeConfig is an external disk mount configuration document.\\\\nExternal volumes allow to mount volumes that were created outside of Talos,\\\\nover the network or API. Volume will be mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe external volume config name should not conflict with user volume names.\\\\n\"\n    },\n    \"block.FilesystemSpec\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"ext4\",\n            \"xfs\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Filesystem type. Default is xfs.\\n\",\n          \"markdownDescription\": \"Filesystem type. Default is `xfs`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilesystem type. Default is \\u003ccode\\u003exfs\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"projectQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"projectQuotaSupport\",\n          \"description\": \"Enables project quota support, valid only for ‘xfs’ filesystem.\\n\\nNote: changing this value might require a full remount of the filesystem.\\n\",\n          \"markdownDescription\": \"Enables project quota support, valid only for 'xfs' filesystem.\\n\\nNote: changing this value might require a full remount of the filesystem.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables project quota support, valid only for \\u0026lsquo;xfs\\u0026rsquo; filesystem.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: changing this value might require a full remount of the filesystem.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FilesystemSpec configures the filesystem for the volume.\"\n    },\n    \"block.MountSpec\": {\n      \"properties\": {\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MountSpec describes how the volume is mounted.\"\n    },\n    \"block.ProvisioningSpec\": {\n      \"properties\": {\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/block.DiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"The disk selector expression.\\n\",\n          \"markdownDescription\": \"The disk selector expression.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk selector expression.\\u003c/p\\u003e\\n\"\n        },\n        \"grow\": {\n          \"type\": \"boolean\",\n          \"title\": \"grow\",\n          \"description\": \"Should the volume grow to the size of the disk (if possible).\\n\",\n          \"markdownDescription\": \"Should the volume grow to the size of the disk (if possible).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShould the volume grow to the size of the disk (if possible).\\u003c/p\\u003e\\n\"\n        },\n        \"minSize\": {\n          \"type\": \"string\",\n          \"title\": \"minSize\",\n          \"description\": \"The minimum size of the volume.\\n\\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\\n\",\n          \"markdownDescription\": \"The minimum size of the volume.\\n\\nSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe minimum size of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSize is specified in bytes, but can be expressed in human readable format, e.g. 100MB.\\u003c/p\\u003e\\n\"\n        },\n        \"maxSize\": {\n          \"type\": \"string\",\n          \"title\": \"maxSize\",\n          \"description\": \"The maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\n\\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\\n\",\n          \"markdownDescription\": \"The maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\n\\nSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe maximum size of the volume, if not specified the volume can grow to the size of the\\ndisk.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSize is specified in bytes or in percents. It can be expressed in human readable format, e.g. 100MB.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ProvisioningSpec describes how the volume is provisioned.\"\n    },\n    \"block.RawVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RawVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"RawVolumeConfig is a raw volume configuration document.\\\\nRaw volumes allow to create partitions without formatting them.\\\\n If you want to use local storage, user volumes is a better choice,\\\\n raw volumes are intended to be used with CSI provisioners.\\\\nThe partition label is automatically generated as `r-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.SwapVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"SwapVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"SwapVolumeConfig is a disk swap volume configuration document.\\\\nSwap volume is automatically allocated as a partition on the specified disk\\\\nand activated as swap, removing a swap volume deactivates swap.\\\\nThe partition label is automatically generated as `s-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.UserMountSpec\": {\n      \"properties\": {\n        \"disableAccessTime\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableAccessTime\",\n          \"description\": \"If true, disable file access time updates.\\n\",\n          \"markdownDescription\": \"If true, disable file access time updates.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIf true, disable file access time updates.\\u003c/p\\u003e\\n\"\n        },\n        \"secure\": {\n          \"type\": \"boolean\",\n          \"title\": \"secure\",\n          \"description\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\\n\",\n          \"markdownDescription\": \"Enable secure mount options (nosuid, nodev).\\n\\nDefaults to true for better security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable secure mount options (nosuid, nodev).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to true for better security.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"UserMountSpec describes how the volume is mounted.\"\n    },\n    \"block.UserVolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"UserVolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\n\",\n          \"markdownDescription\": \"Name of the volume.\\n\\nName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eName might be between 1 and 34 characters long and can only contain:\\nlowercase and uppercase ASCII letters, digits, and hyphens.\\u003c/p\\u003e\\n\"\n        },\n        \"volumeType\": {\n          \"enum\": [\n            \"directory\",\n            \"disk\",\n            \"partition\"\n          ],\n          \"title\": \"volumeType\",\n          \"description\": \"Volume type.\\n\",\n          \"markdownDescription\": \"Volume type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVolume type.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"filesystem\": {\n          \"$ref\": \"#/$defs/block.FilesystemSpec\",\n          \"title\": \"filesystem\",\n          \"description\": \"The filesystem describes how the volume is formatted.\\n\",\n          \"markdownDescription\": \"The filesystem describes how the volume is formatted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe filesystem describes how the volume is formatted.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.UserMountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"UserVolumeConfig is a user volume configuration document.\\\\nUser volume is automatically allocated as a partition on the specified disk\\\\nand mounted under `/var/mnt/\\u003cname\\u003e`.\\\\nThe partition label is automatically generated as `u-\\u003cname\\u003e`.\\\\n\"\n    },\n    \"block.VirtiofsMountSpec\": {\n      \"properties\": {\n        \"tag\": {\n          \"type\": \"string\",\n          \"title\": \"tag\",\n          \"description\": \"Selector tag for the Virtiofs mount.\\n\",\n          \"markdownDescription\": \"Selector tag for the Virtiofs mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelector tag for the Virtiofs mount.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VirtiofsMountSpec describes Virtiofs mount options.\"\n    },\n    \"block.VolumeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VolumeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the volume.\\n\",\n          \"markdownDescription\": \"Name of the volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the volume.\\u003c/p\\u003e\\n\"\n        },\n        \"provisioning\": {\n          \"$ref\": \"#/$defs/block.ProvisioningSpec\",\n          \"title\": \"provisioning\",\n          \"description\": \"The provisioning describes how the volume is provisioned.\\n\",\n          \"markdownDescription\": \"The provisioning describes how the volume is provisioned.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe provisioning describes how the volume is provisioned.\\u003c/p\\u003e\\n\"\n        },\n        \"encryption\": {\n          \"$ref\": \"#/$defs/block.EncryptionSpec\",\n          \"title\": \"encryption\",\n          \"description\": \"The encryption describes how the volume is encrypted.\\n\",\n          \"markdownDescription\": \"The encryption describes how the volume is encrypted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe encryption describes how the volume is encrypted.\\u003c/p\\u003e\\n\"\n        },\n        \"mount\": {\n          \"$ref\": \"#/$defs/block.MountSpec\",\n          \"title\": \"mount\",\n          \"description\": \"The mount describes additional mount options.\\n\",\n          \"markdownDescription\": \"The mount describes additional mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount describes additional mount options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"VolumeConfig is a system volume configuration document.\\\\nNote: at the moment, only `STATE`, `EPHEMERAL` and `IMAGE-CACHE` system volumes are supported.\\\\n\"\n    },\n    \"block.VolumeDiscoverySpec\": {\n      \"properties\": {\n        \"volumeSelector\": {\n          \"$ref\": \"#/$defs/block.VolumeSelector\",\n          \"title\": \"volumeSelector\",\n          \"description\": \"The volume selector expression.\\n\",\n          \"markdownDescription\": \"The volume selector expression.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe volume selector expression.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeDiscoverySpec describes how the volume is discovered.\"\n    },\n    \"block.VolumeSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the volume.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the volume.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the volume.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeSelector selects an existing volume.\"\n    },\n    \"block.ZswapConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ZswapConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"maxPoolPercent\": {\n          \"type\": \"integer\",\n          \"title\": \"maxPoolPercent\",\n          \"description\": \"The maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\\n\",\n          \"markdownDescription\": \"The maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe maximum percent of memory that zswap can use.\\nThis is a percentage of the total system memory.\\nThe value must be between 0 and 100.\\u003c/p\\u003e\\n\"\n        },\n        \"shrinkerEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"shrinkerEnabled\",\n          \"description\": \"Enable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\\n\",\n          \"markdownDescription\": \"Enable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the shrinker feature: kernel might move\\ncold pages from zswap to swap device to free up memory\\nfor other use cases.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ZswapConfig is a zswap (compressed memory) configuration document.\\\\nWhen zswap is enabled, Linux kernel compresses pages that would otherwise be swapped out to disk.\\\\nThe compressed pages are stored in a memory pool, which is used to avoid writing to disk\\\\nwhen the system is under memory pressure.\\\\n\"\n    },\n    \"cri.RegistryAuthConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryAuthConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry endpoint to apply the authentication configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. ‘my-mirror.local:5000’ for ‘https://my-mirror.local:5000/v2/’.\\n\\nThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\n\",\n          \"markdownDescription\": \"Registry endpoint to apply the authentication configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry endpoint to apply the authentication configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. \\u0026lsquo;my-mirror.local:5000\\u0026rsquo; for \\u0026lsquo;\\u003ca href=\\\"https://my-mirror.local:5000/v2/'\\\" target=\\\"_blank\\\"\\u003ehttps://my-mirror.local:5000/v2/\\u0026rsquo;\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe authentication configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\u003c/p\\u003e\\n\"\n        },\n        \"username\": {\n          \"type\": \"string\",\n          \"title\": \"username\",\n          \"description\": \"Username/password authentication.\\n\",\n          \"markdownDescription\": \"Username/password authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsername/password authentication.\\u003c/p\\u003e\\n\"\n        },\n        \"password\": {\n          \"type\": \"string\",\n          \"title\": \"password\",\n          \"description\": \"Username/password authentication.\\n\",\n          \"markdownDescription\": \"Username/password authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsername/password authentication.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"type\": \"string\",\n          \"title\": \"auth\",\n          \"description\": \"Raw authentication string.\\n\",\n          \"markdownDescription\": \"Raw authentication string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw authentication string.\\u003c/p\\u003e\\n\"\n        },\n        \"identityToken\": {\n          \"type\": \"string\",\n          \"title\": \"identityToken\",\n          \"description\": \"Identity token authentication.\\n\",\n          \"markdownDescription\": \"Identity token authentication.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIdentity token authentication.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryAuthConfig configures authentication for a registry endpoint.\"\n    },\n    \"cri.RegistryEndpoint\": {\n      \"properties\": {\n        \"url\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(http|https)://\",\n          \"title\": \"url\",\n          \"description\": \"The URL of the registry mirror endpoint.\\n\",\n          \"markdownDescription\": \"The URL of the registry mirror endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe URL of the registry mirror endpoint.\\u003c/p\\u003e\\n\"\n        },\n        \"overridePath\": {\n          \"type\": \"boolean\",\n          \"title\": \"overridePath\",\n          \"description\": \"Use endpoint path as supplied, without adding /v2/ suffix.\\n\",\n          \"markdownDescription\": \"Use endpoint path as supplied, without adding `/v2/` suffix.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse endpoint path as supplied, without adding \\u003ccode\\u003e/v2/\\u003c/code\\u003e suffix.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"url\"\n      ],\n      \"description\": \"RegistryEndpoint defines a registry mirror endpoint.\"\n    },\n    \"cri.RegistryMirrorConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryMirrorConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry name to apply the mirror configuration to.\\n\\nRegistry name is the first segment of image identifier, with ‘docker.io’\\nbeing default one.\\n\\nA special name ‘*’ can be used to define mirror configuration\\nthat applies to all registries.\\n\",\n          \"markdownDescription\": \"Registry name to apply the mirror configuration to.\\n\\nRegistry name is the first segment of image identifier, with 'docker.io'\\nbeing default one.\\n\\nA special name '*' can be used to define mirror configuration\\nthat applies to all registries.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry name to apply the mirror configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry name is the first segment of image identifier, with \\u0026lsquo;docker.io\\u0026rsquo;\\nbeing default one.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eA special name \\u0026lsquo;*\\u0026rsquo; can be used to define mirror configuration\\nthat applies to all registries.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoints\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/cri.RegistryEndpoint\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"List of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is skipFallback is not set to true.\\n\",\n          \"markdownDescription\": \"List of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is `skipFallback` is not set to true.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of mirror endpoints for the registry.\\nMirrors will be used in the order they are specified,\\nfalling back to the default registry is \\u003ccode\\u003eskipFallback\\u003c/code\\u003e is not set to true.\\u003c/p\\u003e\\n\"\n        },\n        \"skipFallback\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipFallback\",\n          \"description\": \"Skip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\\n\",\n          \"markdownDescription\": \"Skip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip fallback to the original registry if none of the mirrors are available\\nor contain the requested image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryMirrorConfig configures an image registry mirror.\"\n    },\n    \"cri.RegistryTLSConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RegistryTLSConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Registry endpoint to apply the TLS configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. ‘my-mirror.local:5000’ for ‘https://my-mirror.local:5000/v2/’.\\n\\nThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\n\",\n          \"markdownDescription\": \"Registry endpoint to apply the TLS configuration to.\\n\\nRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. 'my-mirror.local:5000' for 'https://my-mirror.local:5000/v2/'.\\n\\nThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRegistry endpoint to apply the TLS configuration to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry endpoint is the hostname part of the endpoint URL,\\ne.g. \\u0026lsquo;my-mirror.local:5000\\u0026rsquo; for \\u0026lsquo;\\u003ca href=\\\"https://my-mirror.local:5000/v2/'\\\" target=\\\"_blank\\\"\\u003ehttps://my-mirror.local:5000/v2/\\u0026rsquo;\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe TLS configuration makes sense only for HTTPS endpoints.\\nThe TLS configuration will apply to all image pulls for this\\nregistry endpoint, by Talos or any Kubernetes workloads.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentity\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"clientIdentity\",\n          \"description\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\\n\",\n          \"markdownDescription\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable mutual TLS authentication with the registry.\\nClient certificate and key should be PEM-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"type\": \"string\",\n          \"title\": \"ca\",\n          \"description\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\\n\",\n          \"markdownDescription\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCA registry certificate to add the list of trusted certificates.\\nCertificate should be PEM-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"insecureSkipVerify\": {\n          \"type\": \"boolean\",\n          \"title\": \"insecureSkipVerify\",\n          \"description\": \"Skip TLS server certificate verification (not recommended).\\n\",\n          \"markdownDescription\": \"Skip TLS server certificate verification (not recommended).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip TLS server certificate verification (not recommended).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"RegistryTLSConfig configures TLS for a registry endpoint.\"\n    },\n    \"extensions.ConfigFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The content of the extension service config file.\\n\",\n          \"markdownDescription\": \"The content of the extension service config file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe content of the extension service config file.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"The mount path of the extension service config file.\\n\",\n          \"markdownDescription\": \"The mount path of the extension service config file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe mount path of the extension service config file.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ConfigFile is a config file for extension services.\"\n    },\n    \"extensions.ServiceConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ExtensionServiceConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the extension service.\\n\",\n          \"markdownDescription\": \"Name of the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the extension service.\\u003c/p\\u003e\\n\"\n        },\n        \"configFiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/extensions.ConfigFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"configFiles\",\n          \"description\": \"The config files for the extension service.\\n\",\n          \"markdownDescription\": \"The config files for the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe config files for the extension service.\\u003c/p\\u003e\\n\"\n        },\n        \"environment\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"environment\",\n          \"description\": \"The environment for the extension service.\\n\",\n          \"markdownDescription\": \"The environment for the extension service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe environment for the extension service.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"ExtensionServiceConfig is a extensionserviceconfig document.\"\n    },\n    \"hardware.PCIDriverRebindConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"PCIDriverRebindConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"PCI device id\\n\",\n          \"markdownDescription\": \"PCI device id\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI device id\\u003c/p\\u003e\\n\"\n        },\n        \"targetDriver\": {\n          \"type\": \"string\",\n          \"title\": \"targetDriver\",\n          \"description\": \"Target driver to rebind the PCI device to.\\n\",\n          \"markdownDescription\": \"Target driver to rebind the PCI device to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTarget driver to rebind the PCI device to.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"targetDriver\"\n      ],\n      \"description\": \"PCIDriverRebindConfig allows to configure PCI driver rebinds.\"\n    },\n    \"network.AddressConfig\": {\n      \"properties\": {\n        \"address\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"address\",\n          \"description\": \"IP address to be assigned to the link.\\n\\nThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\\n\",\n          \"markdownDescription\": \"IP address to be assigned to the link.\\n\\nThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be assigned to the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field must include the network prefix length (e.g. /24 for IPv4, /64 for IPv6).\\u003c/p\\u003e\\n\"\n        },\n        \"routePriority\": {\n          \"type\": \"integer\",\n          \"title\": \"routePriority\",\n          \"description\": \"Configure the route priority (metric) for routes created for this address.\\n\\nIf not specified, the system default route priority will be used.\\n\",\n          \"markdownDescription\": \"Configure the route priority (metric) for routes created for this address.\\n\\nIf not specified, the system default route priority will be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the route priority (metric) for routes created for this address.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default route priority will be used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"address\"\n      ],\n      \"description\": \"AddressConfig represents a network address configuration.\"\n    },\n    \"network.BlackholeRouteConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BlackholeRouteConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Route destination as an address prefix.\\n\",\n          \"markdownDescription\": \"Route destination as an address prefix.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRoute destination as an address prefix.\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"BlackholeRouteConfig is a config document to configure blackhole routes.\"\n    },\n    \"network.BondConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BondConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the bond link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the bond link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the bond link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) on which the bond will be created.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"bondMode\": {\n          \"enum\": [\n            \"balance-rr\",\n            \"active-backup\",\n            \"balance-xor\",\n            \"broadcast\",\n            \"802.3ad\",\n            \"balance-tlb\",\n            \"balance-alb\"\n          ],\n          \"title\": \"bondMode\",\n          \"description\": \"Bond mode.\\n\",\n          \"markdownDescription\": \"Bond mode.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBond mode.\\u003c/p\\u003e\\n\"\n        },\n        \"miimon\": {\n          \"type\": \"integer\",\n          \"title\": \"miimon\",\n          \"description\": \"Link monitoring frequency in milliseconds.\\n\",\n          \"markdownDescription\": \"Link monitoring frequency in milliseconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLink monitoring frequency in milliseconds.\\u003c/p\\u003e\\n\"\n        },\n        \"updelay\": {\n          \"type\": \"integer\",\n          \"title\": \"updelay\",\n          \"description\": \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\\n\",\n          \"markdownDescription\": \"The time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.\\u003c/p\\u003e\\n\"\n        },\n        \"downdelay\": {\n          \"type\": \"integer\",\n          \"title\": \"downdelay\",\n          \"description\": \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\\n\",\n          \"markdownDescription\": \"The time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe time, in milliseconds, to wait before disabling a slave after a link failure has been detected.\\u003c/p\\u003e\\n\"\n        },\n        \"useCarrier\": {\n          \"type\": \"boolean\",\n          \"title\": \"useCarrier\",\n          \"description\": \"Specifies whether or not miimon should use MII or ETHTOOL.\\n\",\n          \"markdownDescription\": \"Specifies whether or not miimon should use MII or ETHTOOL.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether or not miimon should use MII or ETHTOOL.\\u003c/p\\u003e\\n\"\n        },\n        \"xmitHashPolicy\": {\n          \"enum\": [\n            \"layer2\",\n            \"layer3+4\",\n            \"layer2+3\",\n            \"encap2+3\",\n            \"encap3+4\"\n          ],\n          \"title\": \"xmitHashPolicy\",\n          \"description\": \"Selects the transmit hash policy to use for slave selection.\\n\",\n          \"markdownDescription\": \"Selects the transmit hash policy to use for slave selection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelects the transmit hash policy to use for slave selection.\\u003c/p\\u003e\\n\"\n        },\n        \"arpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"arpInterval\",\n          \"description\": \"ARP link monitoring frequency in milliseconds.\\n\",\n          \"markdownDescription\": \"ARP link monitoring frequency in milliseconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eARP link monitoring frequency in milliseconds.\\u003c/p\\u003e\\n\"\n        },\n        \"arpIpTargets\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"arpIpTargets\",\n          \"description\": \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\n\",\n          \"markdownDescription\": \"The list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of IPv4 addresses to use for ARP link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\u003c/p\\u003e\\n\"\n        },\n        \"nsIp6Targets\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nsIp6Targets\",\n          \"description\": \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\n\",\n          \"markdownDescription\": \"The list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of IPv6 addresses to use for NS link monitoring when arpInterval is set.\\nMaximum of 16 targets are supported.\\u003c/p\\u003e\\n\"\n        },\n        \"arpValidate\": {\n          \"enum\": [\n            \"none\",\n            \"active\",\n            \"backup\",\n            \"all\",\n            \"filter\",\n            \"filter-active\",\n            \"filter-backup\"\n          ],\n          \"title\": \"arpValidate\",\n          \"description\": \"Specifies whether or not ARP probes and replies should be validated.\\n\",\n          \"markdownDescription\": \"Specifies whether or not ARP probes and replies should be validated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether or not ARP probes and replies should be validated.\\u003c/p\\u003e\\n\"\n        },\n        \"arpAllTargets\": {\n          \"enum\": [\n            \"any\",\n            \"all\"\n          ],\n          \"title\": \"arpAllTargets\",\n          \"description\": \"Specifies whether ARP probes should be sent to any or all targets.\\n\",\n          \"markdownDescription\": \"Specifies whether ARP probes should be sent to any or all targets.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether ARP probes should be sent to any or all targets.\\u003c/p\\u003e\\n\"\n        },\n        \"lacpRate\": {\n          \"enum\": [\n            \"slow\",\n            \"fast\"\n          ],\n          \"title\": \"lacpRate\",\n          \"description\": \"LACPDU frames periodic transmission rate.\\n\",\n          \"markdownDescription\": \"LACPDU frames periodic transmission rate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLACPDU frames periodic transmission rate.\\u003c/p\\u003e\\n\"\n        },\n        \"failOverMac\": {\n          \"enum\": [\n            \"none\",\n            \"active\",\n            \"follow\"\n          ],\n          \"title\": \"failOverMac\",\n          \"description\": \"Specifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\\n\",\n          \"markdownDescription\": \"Specifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies whether active-backup mode should set all slaves to the same MAC address\\nat enslavement, when enabled, or perform special handling.\\u003c/p\\u003e\\n\"\n        },\n        \"adSelect\": {\n          \"enum\": [\n            \"stable\",\n            \"bandwidth\",\n            \"count\"\n          ],\n          \"title\": \"adSelect\",\n          \"description\": \"Aggregate selection policy for 802.3ad.\\n\",\n          \"markdownDescription\": \"Aggregate selection policy for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAggregate selection policy for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSysPrio\": {\n          \"type\": \"integer\",\n          \"title\": \"adActorSysPrio\",\n          \"description\": \"Actor system priority for 802.3ad.\\n\",\n          \"markdownDescription\": \"Actor system priority for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eActor system priority for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adUserPortKey\": {\n          \"type\": \"integer\",\n          \"title\": \"adUserPortKey\",\n          \"description\": \"User port key (upper 10 bits) for 802.3ad.\\n\",\n          \"markdownDescription\": \"User port key (upper 10 bits) for 802.3ad.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUser port key (upper 10 bits) for 802.3ad.\\u003c/p\\u003e\\n\"\n        },\n        \"adLACPActive\": {\n          \"enum\": [\n            \"on\",\n            \"off\"\n          ],\n          \"title\": \"adLACPActive\",\n          \"description\": \"Whether to send LACPDU frames periodically.\\n\",\n          \"markdownDescription\": \"Whether to send LACPDU frames periodically.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether to send LACPDU frames periodically.\\u003c/p\\u003e\\n\"\n        },\n        \"primaryReselect\": {\n          \"enum\": [\n            \"always\",\n            \"better\",\n            \"failure\"\n          ],\n          \"title\": \"primaryReselect\",\n          \"description\": \"Policy under which the primary slave should be reselected.\\n\",\n          \"markdownDescription\": \"Policy under which the primary slave should be reselected.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePolicy under which the primary slave should be reselected.\\u003c/p\\u003e\\n\"\n        },\n        \"resendIGMP\": {\n          \"type\": \"integer\",\n          \"title\": \"resendIGMP\",\n          \"description\": \"The number of times IGMP packets should be resent.\\n\",\n          \"markdownDescription\": \"The number of times IGMP packets should be resent.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of times IGMP packets should be resent.\\u003c/p\\u003e\\n\"\n        },\n        \"minLinks\": {\n          \"type\": \"integer\",\n          \"title\": \"minLinks\",\n          \"description\": \"The minimum number of active links required for the bond to be considered active.\\n\",\n          \"markdownDescription\": \"The minimum number of active links required for the bond to be considered active.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe minimum number of active links required for the bond to be considered active.\\u003c/p\\u003e\\n\"\n        },\n        \"lpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"lpInterval\",\n          \"description\": \"The number of seconds between instances where the bonding driver sends learning packets to each slave’s peer switch.\\n\",\n          \"markdownDescription\": \"The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of seconds between instances where the bonding driver sends learning packets to each slave\\u0026rsquo;s peer switch.\\u003c/p\\u003e\\n\"\n        },\n        \"packetsPerSlave\": {\n          \"type\": \"integer\",\n          \"title\": \"packetsPerSlave\",\n          \"description\": \"The number of packets to transmit through a slave before moving to the next one.\\n\",\n          \"markdownDescription\": \"The number of packets to transmit through a slave before moving to the next one.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of packets to transmit through a slave before moving to the next one.\\u003c/p\\u003e\\n\"\n        },\n        \"numPeerNotif\": {\n          \"type\": \"integer\",\n          \"title\": \"numPeerNotif\",\n          \"description\": \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\\n\",\n          \"markdownDescription\": \"The number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements)\\nto be issued after a failover event.\\u003c/p\\u003e\\n\"\n        },\n        \"tlbLogicalLb\": {\n          \"type\": \"integer\",\n          \"title\": \"tlbLogicalLb\",\n          \"description\": \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\\n\",\n          \"markdownDescription\": \"Whether dynamic shuffling of flows is enabled in tlb or alb mode.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether dynamic shuffling of flows is enabled in tlb or alb mode.\\u003c/p\\u003e\\n\"\n        },\n        \"allSlavesActive\": {\n          \"type\": \"integer\",\n          \"title\": \"allSlavesActive\",\n          \"description\": \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\\n\",\n          \"markdownDescription\": \"Whether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1).\\u003c/p\\u003e\\n\"\n        },\n        \"peerNotifDelay\": {\n          \"type\": \"integer\",\n          \"title\": \"peerNotifDelay\",\n          \"description\": \"The delay, in milliseconds, between each peer notification.\\n\",\n          \"markdownDescription\": \"The delay, in milliseconds, between each peer notification.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe delay, in milliseconds, between each peer notification.\\u003c/p\\u003e\\n\"\n        },\n        \"missedMax\": {\n          \"type\": \"integer\",\n          \"title\": \"missedMax\",\n          \"description\": \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\\n\",\n          \"markdownDescription\": \"The number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe number of arpInterval monitor checks that must fail in order for an interface to be marked down by the ARP monitor.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"bondMode\",\n        \"kind\",\n        \"links\",\n        \"name\"\n      ],\n      \"description\": \"BondConfig is a config document to create a bond (link aggregation) over a set of links.\"\n    },\n    \"network.BridgeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"BridgeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the bridge link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the bridge link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the bridge link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) to be aggregated.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"stp\": {\n          \"$ref\": \"#/$defs/network.BridgeSTPConfig\",\n          \"title\": \"stp\",\n          \"description\": \"Bridge STP (Spanning Tree Protocol) configuration.\\n\",\n          \"markdownDescription\": \"Bridge STP (Spanning Tree Protocol) configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge STP (Spanning Tree Protocol) configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"vlan\": {\n          \"$ref\": \"#/$defs/network.BridgeVLANConfig\",\n          \"title\": \"vlan\",\n          \"description\": \"Bridge VLAN configuration.\\n\",\n          \"markdownDescription\": \"Bridge VLAN configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge VLAN configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"links\",\n        \"name\"\n      ],\n      \"description\": \"BridgeConfig is a config document to create a Bridge (link aggregation) over a set of links.\"\n    },\n    \"network.BridgeSTPConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable or disable STP on the bridge.\\n\",\n          \"markdownDescription\": \"Enable or disable STP on the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable or disable STP on the bridge.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"BridgeSTPConfig is a bridge STP (Spanning Tree Protocol) configuration.\"\n    },\n    \"network.BridgeVLANConfig\": {\n      \"properties\": {\n        \"filtering\": {\n          \"type\": \"boolean\",\n          \"title\": \"filtering\",\n          \"description\": \"Enable or disable VLAN filtering on the bridge.\\n\",\n          \"markdownDescription\": \"Enable or disable VLAN filtering on the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable or disable VLAN filtering on the bridge.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"BridgeVLANConfig is a bridge VLAN configuration.\"\n    },\n    \"network.CommonLinkConfig\": {\n      \"properties\": {\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CommonLinkConfig is common configuration for network links, and logical links.\"\n    },\n    \"network.CommonProbeConfig\": {\n      \"properties\": {\n        \"interval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"interval\",\n          \"description\": \"Interval between probe attempts.\\nDefaults to 1s.\\n\",\n          \"markdownDescription\": \"Interval between probe attempts.\\nDefaults to 1s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eInterval between probe attempts.\\nDefaults to 1s.\\u003c/p\\u003e\\n\"\n        },\n        \"failureThreshold\": {\n          \"type\": \"integer\",\n          \"title\": \"failureThreshold\",\n          \"description\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\n\",\n          \"markdownDescription\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CommonProbeConfig holds fields common to all probe types.\"\n    },\n    \"network.DHCPv4ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DHCPv4Config\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\\n\",\n          \"markdownDescription\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAn optional metric for the routes received from the DHCP server.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eLower values indicate higher priority.\\nDefault value is 1024.\\u003c/p\\u003e\\n\"\n        },\n        \"ignoreHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignoreHostname\",\n          \"description\": \"Ignore hostname received from the DHCP server.\\n\",\n          \"markdownDescription\": \"Ignore hostname received from the DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIgnore hostname received from the DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentifier\": {\n          \"enum\": [\n            \"none\",\n            \"mac\",\n            \"duid\"\n          ],\n          \"title\": \"clientIdentifier\",\n          \"description\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to ‘mac’ if not set.\\n\",\n          \"markdownDescription\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eClient identifier to use when communicating with DHCP servers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to \\u0026lsquo;mac\\u0026rsquo; if not set.\\u003c/p\\u003e\\n\"\n        },\n        \"duidRaw\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\",\n          \"title\": \"duidRaw\",\n          \"description\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if ‘clientIdentifier’ is set to ‘duid’.\\n\",\n          \"markdownDescription\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw value of the DUID to use as client identifier.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field is only used if \\u0026lsquo;clientIdentifier\\u0026rsquo; is set to \\u0026lsquo;duid\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DHCPv4Config is a config document to configure DHCPv4 on a network link.\"\n    },\n    \"network.DHCPv6ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DHCPv6Config\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\\n\",\n          \"markdownDescription\": \"An optional metric for the routes received from the DHCP server.\\n\\nLower values indicate higher priority.\\nDefault value is 1024.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAn optional metric for the routes received from the DHCP server.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eLower values indicate higher priority.\\nDefault value is 1024.\\u003c/p\\u003e\\n\"\n        },\n        \"ignoreHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignoreHostname\",\n          \"description\": \"Ignore hostname received from the DHCP server.\\n\",\n          \"markdownDescription\": \"Ignore hostname received from the DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIgnore hostname received from the DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"clientIdentifier\": {\n          \"enum\": [\n            \"none\",\n            \"mac\",\n            \"duid\"\n          ],\n          \"title\": \"clientIdentifier\",\n          \"description\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to ‘mac’ if not set.\\n\",\n          \"markdownDescription\": \"Client identifier to use when communicating with DHCP servers.\\n\\nDefaults to 'mac' if not set.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eClient identifier to use when communicating with DHCP servers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefaults to \\u0026lsquo;mac\\u0026rsquo; if not set.\\u003c/p\\u003e\\n\"\n        },\n        \"duidRaw\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+)$\",\n          \"title\": \"duidRaw\",\n          \"description\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if ‘clientIdentifier’ is set to ‘duid’.\\n\",\n          \"markdownDescription\": \"Raw value of the DUID to use as client identifier.\\n\\nThis field is only used if 'clientIdentifier' is set to 'duid'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRaw value of the DUID to use as client identifier.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis field is only used if \\u0026lsquo;clientIdentifier\\u0026rsquo; is set to \\u0026lsquo;duid\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DHCPv6Config is a config document to configure DHCPv6 on a network link.\"\n    },\n    \"network.DefaultActionConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"NetworkDefaultActionConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"ingress\": {\n          \"enum\": [\n            \"accept\",\n            \"block\"\n          ],\n          \"title\": \"ingress\",\n          \"description\": \"Default action for all not explicitly configured ingress traffic: accept or block.\\n\",\n          \"markdownDescription\": \"Default action for all not explicitly configured ingress traffic: accept or block.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefault action for all not explicitly configured ingress traffic: accept or block.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"NetworkDefaultActionConfig is a ingress firewall default action configuration document.\"\n    },\n    \"network.DummyLinkConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"DummyLinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the dummy link (interface).\\n\",\n          \"markdownDescription\": \"Name of the dummy link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the dummy link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"DummyLinkConfig is a config document to create a dummy (virtual) network link.\"\n    },\n    \"network.EthernetChannelsConfig\": {\n      \"properties\": {\n        \"rx\": {\n          \"type\": \"integer\",\n          \"title\": \"rx\",\n          \"description\": \"Number of RX channels.\\n\",\n          \"markdownDescription\": \"Number of RX channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX channels.\\u003c/p\\u003e\\n\"\n        },\n        \"tx\": {\n          \"type\": \"integer\",\n          \"title\": \"tx\",\n          \"description\": \"Number of TX channels.\\n\",\n          \"markdownDescription\": \"Number of TX channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of TX channels.\\u003c/p\\u003e\\n\"\n        },\n        \"other\": {\n          \"type\": \"integer\",\n          \"title\": \"other\",\n          \"description\": \"Number of other channels.\\n\",\n          \"markdownDescription\": \"Number of other channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of other channels.\\u003c/p\\u003e\\n\"\n        },\n        \"combined\": {\n          \"type\": \"integer\",\n          \"title\": \"combined\",\n          \"description\": \"Number of combined channels.\\n\",\n          \"markdownDescription\": \"Number of combined channels.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of combined channels.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EthernetChannelsConfig is a configuration for Ethernet link channels.\"\n    },\n    \"network.EthernetConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EthernetConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"boolean\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"features\",\n          \"description\": \"Configuration for Ethernet features.\\n\\nSet of features available and whether they can be enabled or disabled is driver specific.\\nUse talosctl get ethernetstatus \\u0026lt;link\\u0026gt; -o yaml to get the list of available features and\\ntheir current status.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet features.\\n\\nSet of features available and whether they can be enabled or disabled is driver specific.\\nUse `talosctl get ethernetstatus \\u003clink\\u003e -o yaml` to get the list of available features and\\ntheir current status.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet features.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSet of features available and whether they can be enabled or disabled is driver specific.\\nUse \\u003ccode\\u003etalosctl get ethernetstatus \\u0026lt;link\\u0026gt; -o yaml\\u003c/code\\u003e to get the list of available features and\\ntheir current status.\\u003c/p\\u003e\\n\"\n        },\n        \"rings\": {\n          \"$ref\": \"#/$defs/network.EthernetRingsConfig\",\n          \"title\": \"rings\",\n          \"description\": \"Configuration for Ethernet link rings.\\n\\nThis is similar to ethtool -G command.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet link rings.\\n\\nThis is similar to `ethtool -G` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet link rings.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -G\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        },\n        \"channels\": {\n          \"$ref\": \"#/$defs/network.EthernetChannelsConfig\",\n          \"title\": \"channels\",\n          \"description\": \"Configuration for Ethernet link channels.\\n\\nThis is similar to ethtool -L command.\\n\",\n          \"markdownDescription\": \"Configuration for Ethernet link channels.\\n\\nThis is similar to `ethtool -L` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for Ethernet link channels.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -L\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        },\n        \"wakeOnLan\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"wakeOnLan\",\n          \"description\": \"Wake-on-LAN modes to enable.\\n\\nIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\n\\nThis is similar to ethtool -s \\u0026lt;link\\u0026gt; wol \\u0026lt;options\\u0026gt; command.\\n\",\n          \"markdownDescription\": \"Wake-on-LAN modes to enable.\\n\\nIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\n\\nThis is similar to `ethtool -s \\u003clink\\u003e wol \\u003coptions\\u003e` command.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWake-on-LAN modes to enable.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf this field is omitted, Wake-on-LAN configuration is not changed.\\nAn empty list disables Wake-on-LAN.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis is similar to \\u003ccode\\u003eethtool -s \\u0026lt;link\\u0026gt; wol \\u0026lt;options\\u0026gt;\\u003c/code\\u003e command.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"EthernetConfig is a config document to configure Ethernet interfaces.\"\n    },\n    \"network.EthernetRingsConfig\": {\n      \"properties\": {\n        \"rx\": {\n          \"type\": \"integer\",\n          \"title\": \"rx\",\n          \"description\": \"Number of RX rings.\\n\",\n          \"markdownDescription\": \"Number of RX rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX rings.\\u003c/p\\u003e\\n\"\n        },\n        \"tx\": {\n          \"type\": \"integer\",\n          \"title\": \"tx\",\n          \"description\": \"Number of TX rings.\\n\",\n          \"markdownDescription\": \"Number of TX rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of TX rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-mini\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-mini\",\n          \"description\": \"Number of RX mini rings.\\n\",\n          \"markdownDescription\": \"Number of RX mini rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX mini rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-jumbo\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-jumbo\",\n          \"description\": \"Number of RX jumbo rings.\\n\",\n          \"markdownDescription\": \"Number of RX jumbo rings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of RX jumbo rings.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-buf-len\": {\n          \"type\": \"integer\",\n          \"title\": \"rx-buf-len\",\n          \"description\": \"RX buffer length.\\n\",\n          \"markdownDescription\": \"RX buffer length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRX buffer length.\\u003c/p\\u003e\\n\"\n        },\n        \"cqe-size\": {\n          \"type\": \"integer\",\n          \"title\": \"cqe-size\",\n          \"description\": \"CQE size.\\n\",\n          \"markdownDescription\": \"CQE size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCQE size.\\u003c/p\\u003e\\n\"\n        },\n        \"tx-push\": {\n          \"type\": \"boolean\",\n          \"title\": \"tx-push\",\n          \"description\": \"TX push enabled.\\n\",\n          \"markdownDescription\": \"TX push enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTX push enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"rx-push\": {\n          \"type\": \"boolean\",\n          \"title\": \"rx-push\",\n          \"description\": \"RX push enabled.\\n\",\n          \"markdownDescription\": \"RX push enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRX push enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"tx-push-buf-len\": {\n          \"type\": \"integer\",\n          \"title\": \"tx-push-buf-len\",\n          \"description\": \"TX push buffer length.\\n\",\n          \"markdownDescription\": \"TX push buffer length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTX push buffer length.\\u003c/p\\u003e\\n\"\n        },\n        \"tcp-data-split\": {\n          \"type\": \"boolean\",\n          \"title\": \"tcp-data-split\",\n          \"description\": \"TCP data split enabled.\\n\",\n          \"markdownDescription\": \"TCP data split enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTCP data split enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EthernetRingsConfig is a configuration for Ethernet link rings.\"\n    },\n    \"network.HCloudVIPConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"HCloudVIPConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address to be advertised as a Layer 2 VIP.\\n\",\n          \"markdownDescription\": \"IP address to be advertised as a Layer 2 VIP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be advertised as a Layer 2 VIP.\\u003c/p\\u003e\\n\"\n        },\n        \"link\": {\n          \"type\": \"string\",\n          \"title\": \"link\",\n          \"description\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link to assign the VIP to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        },\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Hetzner Cloud API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"HCloudVIPConfig is a config document to configure virtual IP using Hetzner Cloud APIs for announcement.\\\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\\\nAny other use cases are not supported and may lead to unexpected behavior.\\\\nVirtual IP will be announced from only one node at a time using Hetzner Cloud APIs.\\\\n\"\n    },\n    \"network.HostnameConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"HostnameConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"auto\": {\n          \"enum\": [\n            \"stable\",\n            \"off\"\n          ],\n          \"title\": \"auto\",\n          \"description\": \"A method to automatically generate a hostname for the machine.\\n\\nThere are two methods available:\\n  - stable - generates a stable hostname based on machine identity\\n  - off - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\n\\nAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with hostname field.\\n\",\n          \"markdownDescription\": \"A method to automatically generate a hostname for the machine.\\n\\nThere are two methods available:\\n  - `stable` - generates a stable hostname based on machine identity\\n  - `off` - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\n\\nAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `hostname` field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA method to automatically generate a hostname for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThere are two methods available:\\n  - \\u003ccode\\u003estable\\u003c/code\\u003e - generates a stable hostname based on machine identity\\n  - \\u003ccode\\u003eoff\\u003c/code\\u003e - disables automatic hostname generation, Talos will wait for an external source to provide a hostname (DHCP, cloud-init, etc).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eAutomatic hostnames have the lowest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with \\u003ccode\\u003ehostname\\u003c/code\\u003e field.\\u003c/p\\u003e\\n\"\n        },\n        \"hostname\": {\n          \"type\": \"string\",\n          \"title\": \"hostname\",\n          \"description\": \"A static hostname to set for the machine.\\n\\nThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with auto field.\\n\",\n          \"markdownDescription\": \"A static hostname to set for the machine.\\n\\nThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with `auto` field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA static hostname to set for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis hostname has the highest priority over any other hostname sources: DHCP, cloud-init, etc.\\nConflicts with \\u003ccode\\u003eauto\\u003c/code\\u003e field.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"HostnameConfig is a config document to configure the hostname: either a static hostname or an automatically generated hostname.\"\n    },\n    \"network.IngressRule\": {\n      \"properties\": {\n        \"subnet\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"subnet\",\n          \"description\": \"Subnet defines a source subnet.\\n\",\n          \"markdownDescription\": \"Subnet defines a source subnet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSubnet defines a source subnet.\\u003c/p\\u003e\\n\"\n        },\n        \"except\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"except\",\n          \"description\": \"Except defines a source subnet to exclude from the rule, it gets excluded from the subnet.\\n\",\n          \"markdownDescription\": \"Except defines a source subnet to exclude from the rule, it gets excluded from the `subnet`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExcept defines a source subnet to exclude from the rule, it gets excluded from the \\u003ccode\\u003esubnet\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"IngressRule is a ingress rule.\"\n    },\n    \"network.KubeSpanConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KubeSpanConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\\n\",\n          \"markdownDescription\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the KubeSpan feature.\\nCluster discovery should be enabled with cluster.discovery.enabled for KubeSpan to be enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"advertiseKubernetesNetworks\": {\n          \"type\": \"boolean\",\n          \"title\": \"advertiseKubernetesNetworks\",\n          \"description\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\\n\",\n          \"markdownDescription\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eControl whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles pod-to-pod traffic encapsulation.\\nIf enabled, KubeSpan takes over pod-to-pod traffic directly.\\u003c/p\\u003e\\n\"\n        },\n        \"allowDownPeerBypass\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowDownPeerBypass\",\n          \"description\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\\n\",\n          \"markdownDescription\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security.\\u003c/p\\u003e\\n\"\n        },\n        \"harvestExtraEndpoints\": {\n          \"type\": \"boolean\",\n          \"title\": \"harvestExtraEndpoints\",\n          \"description\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u0026gt;50).\\n\",\n          \"markdownDescription\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u003e50).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nDisabled by default. Do not enable with high peer counts (\\u0026gt;50).\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"KubeSpan link MTU size.\\nDefault value is 1420.\\n\",\n          \"markdownDescription\": \"KubeSpan link MTU size.\\nDefault value is 1420.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan link MTU size.\\nDefault value is 1420.\\u003c/p\\u003e\\n\"\n        },\n        \"filters\": {\n          \"$ref\": \"#/$defs/network.KubeSpanFiltersConfig\",\n          \"title\": \"filters\",\n          \"description\": \"KubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\\n\",\n          \"markdownDescription\": \"KubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan advanced filtering of network addresses.\\nSettings are optional and apply only to this node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KubeSpanConfig is a config document to configure KubeSpan.\"\n    },\n    \"network.KubeSpanFiltersConfig\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        },\n        \"excludeAdvertisedNetworks\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"excludeAdvertisedNetworks\",\n          \"description\": \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\n\\nBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\n\\nNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\n\\nBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\n\\nNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter networks (e.g., host addresses, pod CIDRs if enabled) which will be advertised over KubeSpan.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all networks are advertised.\\nUse this filter to exclude some networks from being advertised.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: excluded networks will not be reachable over KubeSpan, so make sure\\nthese networks are still reachable via some other route (e.g., direct connection).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeSpanFiltersConfig configures KubeSpan endpoint filters.\"\n    },\n    \"network.KubespanEndpointsConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KubeSpanEndpoints\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"extraAnnouncedEndpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraAnnouncedEndpoints\",\n          \"description\": \"A list of extra Wireguard endpoints to announce from this machine.\\n\\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\\n\",\n          \"markdownDescription\": \"A list of extra Wireguard endpoints to announce from this machine.\\n\\nTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of extra Wireguard endpoints to announce from this machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eTalos automatically adds endpoints based on machine addresses, public IP, etc.\\nThis field allows to add extra endpoints which are managed outside of Talos, e.g. NAT mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KubeSpanEndpointsConfig is a config document to configure KubeSpan endpoints.\"\n    },\n    \"network.Layer2VIPConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"Layer2VIPConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address to be advertised as a Layer 2 VIP.\\n\",\n          \"markdownDescription\": \"IP address to be advertised as a Layer 2 VIP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address to be advertised as a Layer 2 VIP.\\u003c/p\\u003e\\n\"\n        },\n        \"link\": {\n          \"type\": \"string\",\n          \"title\": \"link\",\n          \"description\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Name of the link to assign the VIP to.\\n\\nSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link to assign the VIP to.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSelector must match exactly one link, otherwise an error is returned.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"Layer2VIPConfig is a config document to configure virtual IP using Layer 2 (Ethernet) advertisement.\\\\nVirtual IP configuration should be used only on controlplane nodes to provide virtual IP for Kubernetes API server.\\\\nAny other use cases are not supported and may lead to unexpected behavior.\\\\nVirtual IP will be announced from only one node at a time using gratuitous ARP announcements for IPv4.\\\\n\"\n    },\n    \"network.LinkAliasConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"LinkAliasConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Alias for the link.\\n\\nDon’t use system interface names like “eth0”, “ens3”, “enp0s2”, etc. as those may conflict\\nwith existing physical interfaces.\\n\\nThe name can contain a single integer format verb (%d) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. net0, net1, …) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\\n\",\n          \"markdownDescription\": \"Alias for the link.\\n\\nDon't use system interface names like \\\"eth0\\\", \\\"ens3\\\", \\\"enp0s2\\\", etc. as those may conflict\\nwith existing physical interfaces.\\n\\nThe name can contain a single integer format verb (`%d`) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. `net0`, `net1`, ...) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAlias for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDon\\u0026rsquo;t use system interface names like \\u0026ldquo;eth0\\u0026rdquo;, \\u0026ldquo;ens3\\u0026rdquo;, \\u0026ldquo;enp0s2\\u0026rdquo;, etc. as those may conflict\\nwith existing physical interfaces.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe name can contain a single integer format verb (\\u003ccode\\u003e%d\\u003c/code\\u003e) to create multiple aliases\\nfrom a single config document. When a format verb is detected, each matched link receives a sequential\\nalias (e.g. \\u003ccode\\u003enet0\\u003c/code\\u003e, \\u003ccode\\u003enet1\\u003c/code\\u003e, \\u0026hellip;) based on hardware address order of the links.\\nLinks already aliased by a previous config are automatically skipped.\\u003c/p\\u003e\\n\"\n        },\n        \"selector\": {\n          \"$ref\": \"#/$defs/network.LinkSelector\",\n          \"title\": \"selector\",\n          \"description\": \"Selector to match the link to alias.\\n\\nWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. net%d), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\\n\",\n          \"markdownDescription\": \"Selector to match the link to alias.\\n\\nWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. `net%d`), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelector to match the link to alias.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen the alias name is a fixed string, the selector must match exactly one link.\\nWhen the alias name contains a format verb (e.g. \\u003ccode\\u003enet%d\\u003c/code\\u003e), the selector may match multiple links\\nand each match receives a sequential alias.\\nIf multiple selectors match the same link, the first one is used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"LinkAliasConfig is a config document to alias (give a different name) to a physical link.\"\n    },\n    \"network.LinkConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"LinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the link (interface).\\n\",\n          \"markdownDescription\": \"Name of the link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"LinkConfig is a config document to configure physical interfaces (network links).\"\n    },\n    \"network.LinkSelector\": {\n      \"properties\": {\n        \"match\": {\n          \"type\": \"string\",\n          \"title\": \"match\",\n          \"description\": \"The Common Expression Language (CEL) expression to match the link.\\n\",\n          \"markdownDescription\": \"The Common Expression Language (CEL) expression to match the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe Common Expression Language (CEL) expression to match the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LinkSelector selects a link to alias.\"\n    },\n    \"network.NTPConfig\": {\n      \"properties\": {\n        \"servers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"servers\",\n          \"description\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to time.cloudflare.com.\\n\",\n          \"markdownDescription\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to `time.cloudflare.com`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies time (NTP) servers to use for setting the system time.\\nDefaults to \\u003ccode\\u003etime.cloudflare.com\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"NTPConfig represents a NTP server configuration.\"\n    },\n    \"network.NameserverConfig\": {\n      \"properties\": {\n        \"address\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"address\",\n          \"description\": \"The IP address of the nameserver.\\n\",\n          \"markdownDescription\": \"The IP address of the nameserver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe IP address of the nameserver.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"NameserverConfig represents a single nameserver configuration.\"\n    },\n    \"network.PTPConfig\": {\n      \"properties\": {\n        \"devices\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"devices\",\n          \"description\": \"description: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\n\\nA PTP device is typically represented as a character device file in the /dev directory,\\n\\n\\nsuch as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\\n\",\n          \"markdownDescription\": \"description: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\n\\n    A PTP device is typically represented as a character device file in the /dev directory,\\n   such as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\n    A list of PTP devices to sync with (e.g. provided by the hypervisor).\\u003c/p\\u003e\\n\\n\\u003cpre\\u003e\\u003ccode\\u003eA PTP device is typically represented as a character device file in the /dev directory,\\n\\u003c/code\\u003e\\u003c/pre\\u003e\\n\\n\\u003cp\\u003esuch as /dev/ptp0 or /dev/ptp_kvm. These devices are used to synchronize the system time\\n    with an external time source that supports the Precision Time Protocol.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"PTPConfig represents a PTP (Precision Time Protocol) configuration.\"\n    },\n    \"network.ResolverConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"ResolverConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"nameservers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.NameserverConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nameservers\",\n          \"description\": \"A list of nameservers (DNS servers) to use for resolving domain names.\\n\\nNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\n\\nThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\\n\",\n          \"markdownDescription\": \"A list of nameservers (DNS servers) to use for resolving domain names.\\n\\nNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\n\\nThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of nameservers (DNS servers) to use for resolving domain names.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNameservers are used to resolve domain names on the host, and they are also\\npropagated to Kubernetes DNS (CoreDNS) for use by pods running on the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis overrides any nameservers obtained via DHCP or platform configuration.\\nDefault configuration is to use 1.1.1.1 and 8.8.8.8 as nameservers.\\u003c/p\\u003e\\n\"\n        },\n        \"searchDomains\": {\n          \"$ref\": \"#/$defs/network.SearchDomainsConfig\",\n          \"title\": \"searchDomains\",\n          \"description\": \"Configuration for search domains (in /etc/resolv.conf).\\n\\nThe default is to derive search domains from the hostname FQDN.\\n\",\n          \"markdownDescription\": \"Configuration for search domains (in /etc/resolv.conf).\\n\\nThe default is to derive search domains from the hostname FQDN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration for search domains (in /etc/resolv.conf).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe default is to derive search domains from the hostname FQDN.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"ResolverConfig is a config document to configure DNS resolving.\"\n    },\n    \"network.RouteConfig\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\",\n          \"title\": \"destination\",\n          \"description\": \"The route’s destination as an address prefix.\\n\\nIf not specified, a default route will be created for the address family of the gateway.\\n\",\n          \"markdownDescription\": \"The route's destination as an address prefix.\\n\\nIf not specified, a default route will be created for the address family of the gateway.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s destination as an address prefix.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, a default route will be created for the address family of the gateway.\\u003c/p\\u003e\\n\"\n        },\n        \"gateway\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"gateway\",\n          \"description\": \"The route’s gateway (if empty, creates link scope route).\\n\",\n          \"markdownDescription\": \"The route's gateway (if empty, creates link scope route).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s gateway (if empty, creates link scope route).\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f.:]+$\",\n          \"title\": \"source\",\n          \"description\": \"The route’s source address (optional).\\n\",\n          \"markdownDescription\": \"The route's source address (optional).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s source address (optional).\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The optional MTU for the route.\\n\",\n          \"markdownDescription\": \"The optional MTU for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional MTU for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"The routing table to use for the route.\\n\\nIf not specified, the main routing table will be used.\\n\",\n          \"markdownDescription\": \"The routing table to use for the route.\\n\\nIf not specified, the main routing table will be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe routing table to use for the route.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the main routing table will be used.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RouteConfig represents a network route configuration.\"\n    },\n    \"network.RoutingRuleConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"RoutingRuleConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Priority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\\n\",\n          \"markdownDescription\": \"Priority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePriority of the routing rule.\\nLower values are matched first.\\nMust be between 1 and 32765 (excluding reserved priorities [0 32500 32501 32766 32767]).\\nMust be unique across all routing rules in the configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"src\": {\n          \"type\": \"string\",\n          \"title\": \"src\",\n          \"description\": \"Source address prefix to match.\\nIf empty, matches all sources.\\n\",\n          \"markdownDescription\": \"Source address prefix to match.\\nIf empty, matches all sources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource address prefix to match.\\nIf empty, matches all sources.\\u003c/p\\u003e\\n\"\n        },\n        \"dst\": {\n          \"type\": \"string\",\n          \"title\": \"dst\",\n          \"description\": \"Destination address prefix to match.\\nIf empty, matches all destinations.\\n\",\n          \"markdownDescription\": \"Destination address prefix to match.\\nIf empty, matches all destinations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination address prefix to match.\\nIf empty, matches all destinations.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"The routing table to look up if the rule matches.\\n\",\n          \"markdownDescription\": \"The routing table to look up if the rule matches.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe routing table to look up if the rule matches.\\u003c/p\\u003e\\n\"\n        },\n        \"action\": {\n          \"type\": \"integer\",\n          \"title\": \"action\",\n          \"description\": \"The action to perform when the rule matches.\\nDefaults to “unicast” (table lookup).\\n\",\n          \"markdownDescription\": \"The action to perform when the rule matches.\\nDefaults to \\\"unicast\\\" (table lookup).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe action to perform when the rule matches.\\nDefaults to \\u0026ldquo;unicast\\u0026rdquo; (table lookup).\\u003c/p\\u003e\\n\"\n        },\n        \"iifName\": {\n          \"type\": \"string\",\n          \"title\": \"iifName\",\n          \"description\": \"Match packets arriving on this interface.\\n\",\n          \"markdownDescription\": \"Match packets arriving on this interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets arriving on this interface.\\u003c/p\\u003e\\n\"\n        },\n        \"oifName\": {\n          \"type\": \"string\",\n          \"title\": \"oifName\",\n          \"description\": \"Match packets going out on this interface.\\n\",\n          \"markdownDescription\": \"Match packets going out on this interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets going out on this interface.\\u003c/p\\u003e\\n\"\n        },\n        \"fwMark\": {\n          \"type\": \"integer\",\n          \"title\": \"fwMark\",\n          \"description\": \"Match packets with this firewall mark value.\\n\",\n          \"markdownDescription\": \"Match packets with this firewall mark value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMatch packets with this firewall mark value.\\u003c/p\\u003e\\n\"\n        },\n        \"fwMask\": {\n          \"type\": \"integer\",\n          \"title\": \"fwMask\",\n          \"description\": \"Mask for the firewall mark comparison.\\n\",\n          \"markdownDescription\": \"Mask for the firewall mark comparison.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMask for the firewall mark comparison.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"table\"\n      ],\n      \"description\": \"RoutingRuleConfig is a config document to configure Linux policy routing rules.\"\n    },\n    \"network.RuleConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"NetworkRuleConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"portSelector\": {\n          \"$ref\": \"#/$defs/network.RulePortSelector\",\n          \"title\": \"portSelector\",\n          \"description\": \"Port selector defines which ports and protocols on the host are affected by the rule.\\n\",\n          \"markdownDescription\": \"Port selector defines which ports and protocols on the host are affected by the rule.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePort selector defines which ports and protocols on the host are affected by the rule.\\u003c/p\\u003e\\n\"\n        },\n        \"ingress\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.IngressRule\"\n          },\n          \"type\": \"array\",\n          \"title\": \"ingress\",\n          \"description\": \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the portSelector.\\n\",\n          \"markdownDescription\": \"Ingress defines which source subnets are allowed to access the host ports/protocols defined by the `portSelector`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIngress defines which source subnets are allowed to access the host ports/protocols defined by the \\u003ccode\\u003eportSelector\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"NetworkRuleConfig is a network firewall rule config document.\"\n    },\n    \"network.RulePortSelector\": {\n      \"properties\": {\n        \"ports\": {\n          \"items\": {\n            \"oneOf\": [\n              {\n                \"type\": \"integer\"\n              },\n              {\n                \"type\": \"string\"\n              }\n            ]\n          },\n          \"type\": \"array\",\n          \"title\": \"ports\",\n          \"description\": \"Ports defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\\n\",\n          \"markdownDescription\": \"Ports defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePorts defines a list of port ranges or single ports.\\nThe port ranges are inclusive, and should not overlap.\\u003c/p\\u003e\\n\"\n        },\n        \"protocol\": {\n          \"enum\": [\n            \"tcp\",\n            \"udp\",\n            \"icmp\",\n            \"icmpv6\"\n          ],\n          \"title\": \"protocol\",\n          \"description\": \"Protocol defines traffic protocol (e.g. TCP or UDP).\\n\",\n          \"markdownDescription\": \"Protocol defines traffic protocol (e.g. TCP or UDP).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProtocol defines traffic protocol (e.g. TCP or UDP).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RulePortSelector is a port selector for the network rule.\"\n    },\n    \"network.SearchDomainsConfig\": {\n      \"properties\": {\n        \"domains\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"domains\",\n          \"description\": \"A list of search domains to be used for DNS resolution.\\n\\nSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if “example.com” is a search domain and a user tries to resolve\\n“host”, the system will attempt to resolve “host.example.com”.\\n\\nThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\\n\",\n          \"markdownDescription\": \"A list of search domains to be used for DNS resolution.\\n\\nSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if \\\"example.com\\\" is a search domain and a user tries to resolve\\n\\\"host\\\", the system will attempt to resolve \\\"host.example.com\\\".\\n\\nThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of search domains to be used for DNS resolution.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSearch domains are appended to unqualified domain names during DNS resolution.\\nFor example, if \\u0026ldquo;example.com\\u0026rdquo; is a search domain and a user tries to resolve\\n\\u0026ldquo;host\\u0026rdquo;, the system will attempt to resolve \\u0026ldquo;host.example.com\\u0026rdquo;.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis overrides any search domains obtained via DHCP or platform configuration.\\nThe default configuration derives the search domain from the hostname FQDN.\\u003c/p\\u003e\\n\"\n        },\n        \"disableDefault\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableDefault\",\n          \"description\": \"Disable default search domain configuration from hostname FQDN.\\n\\nWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\\n\",\n          \"markdownDescription\": \"Disable default search domain configuration from hostname FQDN.\\n\\nWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable default search domain configuration from hostname FQDN.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen set to true, the system will not derive search domains from the hostname FQDN.\\nThis allows for a custom configuration of search domains without any defaults.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"SearchDomainsConfig represents search domains configuration.\"\n    },\n    \"network.StaticHostConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"StaticHostConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"IP address (IPv4 or IPv6) to map the hostnames to.\\n\",\n          \"markdownDescription\": \"IP address (IPv4 or IPv6) to map the hostnames to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIP address (IPv4 or IPv6) to map the hostnames to.\\u003c/p\\u003e\\n\"\n        },\n        \"hostnames\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"hostnames\",\n          \"description\": \"List of hostnames to map to the IP address.\\n\",\n          \"markdownDescription\": \"List of hostnames to map to the IP address.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of hostnames to map to the IP address.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"StaticHostConfig is a config document to set /etc/hosts entries.\"\n    },\n    \"network.TCPProbeConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TCPProbeConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the probe.\\n\",\n          \"markdownDescription\": \"Name of the probe.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the probe.\\u003c/p\\u003e\\n\"\n        },\n        \"interval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"interval\",\n          \"description\": \"Interval between probe attempts.\\nDefaults to 1s.\\n\",\n          \"markdownDescription\": \"Interval between probe attempts.\\nDefaults to 1s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eInterval between probe attempts.\\nDefaults to 1s.\\u003c/p\\u003e\\n\"\n        },\n        \"failureThreshold\": {\n          \"type\": \"integer\",\n          \"title\": \"failureThreshold\",\n          \"description\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\n\",\n          \"markdownDescription\": \"Number of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNumber of consecutive failures for the probe to be considered failed after having succeeded.\\nDefaults to 0 (immediately fail on first failure).\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint to probe in the format host:port.\\n\",\n          \"markdownDescription\": \"Endpoint to probe in the format host:port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint to probe in the format host:port.\\u003c/p\\u003e\\n\"\n        },\n        \"timeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"timeout\",\n          \"description\": \"Timeout for the probe.\\nDefaults to 10s.\\n\",\n          \"markdownDescription\": \"Timeout for the probe.\\nDefaults to 10s.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTimeout for the probe.\\nDefaults to 10s.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"endpoint\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"TCPProbeConfig is a config document to configure network TCP connectivity probes.\"\n    },\n    \"network.TimeSyncConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TimeSyncConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Indicates if the time synchronization is enabled for the machine.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the time synchronization is enabled for the machine.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the time synchronization is enabled for the machine.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"bootTimeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"bootTimeout\",\n          \"description\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to “infinity” (waiting forever for time sync)\\n\",\n          \"markdownDescription\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\\"infinity\\\" (waiting forever for time sync)\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\u0026ldquo;infinity\\u0026rdquo; (waiting forever for time sync)\\u003c/p\\u003e\\n\"\n        },\n        \"ntp\": {\n          \"$ref\": \"#/$defs/network.NTPConfig\",\n          \"title\": \"ntp\",\n          \"description\": \"Specifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\\n\",\n          \"markdownDescription\": \"Specifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies NTP configuration to sync the time over network.\\nMutually exclusive with PTP configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"ptp\": {\n          \"$ref\": \"#/$defs/network.PTPConfig\",\n          \"title\": \"ptp\",\n          \"description\": \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\\n\",\n          \"markdownDescription\": \"Specific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecific PTP (Precision Time Protocol) configuration to sync the time over PTP devices.\\nMutually exclusive with NTP configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"TimeSyncConfig is a config document to configure time synchronization (NTP).\"\n    },\n    \"network.VLANConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VLANConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the VLAN link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the VLAN link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the VLAN link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanID\": {\n          \"type\": \"integer\",\n          \"title\": \"vlanID\",\n          \"description\": \"VLAN ID to be used for the VLAN link.\\n\",\n          \"markdownDescription\": \"VLAN ID to be used for the VLAN link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVLAN ID to be used for the VLAN link.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanMode\": {\n          \"enum\": [\n            \"802.1q\",\n            \"802.1ad\"\n          ],\n          \"title\": \"vlanMode\",\n          \"description\": \"Set the VLAN mode to use.\\nIf not set, defaults to ‘802.1q’.\\n\",\n          \"markdownDescription\": \"Set the VLAN mode to use.\\nIf not set, defaults to '802.1q'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the VLAN mode to use.\\nIf not set, defaults to \\u0026lsquo;802.1q\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"parent\": {\n          \"type\": \"string\",\n          \"title\": \"parent\",\n          \"description\": \"Name of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Name of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the parent link (interface) on which the VLAN link will be created.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"parent\",\n        \"vlanID\"\n      ],\n      \"description\": \"VLANConfig is a config document to create a VLAN (virtual LAN) over a parent link.\"\n    },\n    \"network.VRFConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"VRFConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the vrf link (interface) to be created.\\n\",\n          \"markdownDescription\": \"Name of the vrf link (interface) to be created.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the vrf link (interface) to be created.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[0-9a-f:]+$\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Override the hardware (MAC) address of the link.\\n\",\n          \"markdownDescription\": \"Override the hardware (MAC) address of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride the hardware (MAC) address of the link.\\u003c/p\\u003e\\n\"\n        },\n        \"links\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"links\",\n          \"description\": \"Names of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\\n\",\n          \"markdownDescription\": \"Names of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eNames of the links (interfaces) to be assigned to this vrf.\\nLink aliases can be used here as well.\\u003c/p\\u003e\\n\"\n        },\n        \"table\": {\n          \"type\": \"string\",\n          \"title\": \"table\",\n          \"description\": \"Routing table number to use for this vrf.\\n\",\n          \"markdownDescription\": \"Routing table number to use for this vrf.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRouting table number to use for this vrf.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"links\",\n        \"name\",\n        \"table\"\n      ],\n      \"description\": \"VRFConfig is a config document to create a vrf and assign links to it.\"\n    },\n    \"network.WireguardConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"WireguardConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the Wireguard link (interface).\\n\",\n          \"markdownDescription\": \"Name of the Wireguard link (interface).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the Wireguard link (interface).\\u003c/p\\u003e\\n\"\n        },\n        \"privateKey\": {\n          \"type\": \"string\",\n          \"title\": \"privateKey\",\n          \"description\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by wg genkey.\\n\",\n          \"markdownDescription\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by `wg genkey`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a private key configuration (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genkey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"listenPort\": {\n          \"type\": \"integer\",\n          \"title\": \"listenPort\",\n          \"description\": \"Specifies a device’s listening port (UDP).\\nIf not specified, a random port will be chosen.\\n\",\n          \"markdownDescription\": \"Specifies a device's listening port (UDP).\\nIf not specified, a random port will be chosen.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s listening port (UDP).\\nIf not specified, a random port will be chosen.\\u003c/p\\u003e\\n\"\n        },\n        \"firewallMark\": {\n          \"type\": \"integer\",\n          \"title\": \"firewallMark\",\n          \"description\": \"Specifies a device’s firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\\n\",\n          \"markdownDescription\": \"Specifies a device's firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s firewall mark.\\nUseful for advanced routing setups, marking packets originating from this device.\\u003c/p\\u003e\\n\"\n        },\n        \"peers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.WireguardPeer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"peers\",\n          \"description\": \"Specifies a list of peer configurations to apply to a device.\\n\",\n          \"markdownDescription\": \"Specifies a list of peer configurations to apply to a device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a list of peer configurations to apply to a device.\\u003c/p\\u003e\\n\"\n        },\n        \"up\": {\n          \"type\": \"boolean\",\n          \"title\": \"up\",\n          \"description\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\\n\",\n          \"markdownDescription\": \"Bring the link up or down.\\n\\nIf not specified, the link will be brought up.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBring the link up or down.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the link will be brought up.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\\n\",\n          \"markdownDescription\": \"Configure LinkMTU (Maximum Transmission Unit) for the link.\\n\\nIf not specified, the system default LinkMTU will be used (usually 1500).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure LinkMTU (Maximum Transmission Unit) for the link.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf not specified, the system default LinkMTU will be used (usually 1500).\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.AddressConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Configure addresses to be statically assigned to the link.\\n\",\n          \"markdownDescription\": \"Configure addresses to be statically assigned to the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure addresses to be statically assigned to the link.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/network.RouteConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"Configure routes to be statically created via the link.\\n\",\n          \"markdownDescription\": \"Configure routes to be statically created via the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure routes to be statically created via the link.\\u003c/p\\u003e\\n\"\n        },\n        \"multicast\": {\n          \"type\": \"boolean\",\n          \"title\": \"multicast\",\n          \"description\": \"Set the multicast capability of the link.\\n\",\n          \"markdownDescription\": \"Set the multicast capability of the link.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet the multicast capability of the link.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\",\n        \"privateKey\"\n      ],\n      \"description\": \"WireguardConfig is a config document to create and configure a Wireguard network link.\"\n    },\n    \"network.WireguardPeer\": {\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\",\n          \"title\": \"publicKey\",\n          \"description\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running wg pubkey \\u0026lt; private.key.\\n\",\n          \"markdownDescription\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running `wg pubkey \\u003c private.key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the public key of this peer.\\nCan be extracted from private key by running \\u003ccode\\u003ewg pubkey \\u0026lt; private.key\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"presharedKey\": {\n          \"type\": \"string\",\n          \"title\": \"presharedKey\",\n          \"description\": \"Specifies the preshared key for this peer (base64 encoded).\\nCan be generated by wg genpsk.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\\n\",\n          \"markdownDescription\": \"Specifies the preshared key for this peer (base64 encoded).\\nCan be generated by `wg genpsk`.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the preshared key for this peer (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genpsk\\u003c/code\\u003e.\\nOptional, this key provides an additional layer of symmetric-key cryptography\\nto the peer connection.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^([0-9a-f.:]+|\\\\[[0-9a-f:.]+\\\\]):\\\\d{1,5}$\",\n          \"title\": \"endpoint\",\n          \"description\": \"Specifies the endpoint of this peer entry.\\nFormat: :.\\nIf not set, the peer should connect to us without us connecting to it first.\\n\",\n          \"markdownDescription\": \"Specifies the endpoint of this peer entry.\\nFormat: \\u003cIP address\\u003e:\\u003cport\\u003e.\\nIf not set, the peer should connect to us without us connecting to it first.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the endpoint of this peer entry.\\nFormat: \\u003cIP address\\u003e:\\u003cport\\u003e.\\nIf not set, the peer should connect to us without us connecting to it first.\\u003c/p\\u003e\\n\"\n        },\n        \"persistentKeepaliveInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"persistentKeepaliveInterval\",\n          \"description\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        },\n        \"allowedIPs\": {\n          \"items\": {\n            \"type\": \"string\",\n            \"pattern\": \"^[0-9a-f.:]+/\\\\d{1,3}$\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedIPs\",\n          \"description\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\\n\",\n          \"markdownDescription\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\nThese IPs will be routed to this peer, and defines which IPs this peer is allowed to use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"publicKey\"\n      ],\n      \"description\": \"WireguardPeer describes a Wireguard peer configuration.\"\n    },\n    \"runtime.EnvironmentV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EnvironmentConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"variables\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"variables\",\n          \"description\": \"This field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore () character, and\\n  - contain only uppercase and lowercase letters, underscore () characters, and numbers.\\n\",\n          \"markdownDescription\": \"This field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore (_) character, and\\n  - contain only uppercase and lowercase letters, underscore (_) characters, and numbers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\nPropagation of environment variables to services is done only at initial service start time.\\nTo modify environment variables for services, the node must be restarted.\\nMultiple values for the same environment variable (in multiple documents) will replace previous values, with the last one taking precedence.\\nFully removing an environment variable can only be achieved by removing it from the document and restarting the machine.\\nEnvironment variable names are validated, and should:\\n  - start with an uppercase letter, lowercase letter, or an underscore (\\u003cem\\u003e) character, and\\n  - contain only uppercase and lowercase letters, underscore (\\u003c/em\\u003e) characters, and numbers.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"EnvironmentConfig is an environment config document.\"\n    },\n    \"runtime.EventSinkV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"EventSinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"The endpoint for the event sink as ‘host:port’.\\n\",\n          \"markdownDescription\": \"The endpoint for the event sink as 'host:port'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe endpoint for the event sink as \\u0026lsquo;host:port\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"EventSinkConfig is a event sink config document.\"\n    },\n    \"runtime.KmsgLogV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"KmsgLogConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"url\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(tcp|udp)://\",\n          \"title\": \"url\",\n          \"description\": \"The URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\\n\",\n          \"markdownDescription\": \"The URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe URL encodes the log destination.\\nThe scheme must be tcp:// or udp://.\\nThe path must be empty.\\nThe port is required.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"KmsgLogConfig is a event sink config document.\"\n    },\n    \"runtime.OOMV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"OOMConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"triggerExpression\": {\n          \"type\": \"string\",\n          \"title\": \"triggerExpression\",\n          \"description\": \"This expression defines when to trigger OOM action.\\n\\nThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\n\\nThis expression receives the following parameters:\\n- memory{some,full}{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\\n\",\n          \"markdownDescription\": \"This expression defines when to trigger OOM action.\\n\\nThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\n\\nThis expression receives the following parameters:\\n- memory_{some,full}_{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis expression defines when to trigger OOM action.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe expression must evaluate to a boolean value.\\nIf the expression returns true, then OOM ranking and killing will be handled.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis expression receives the following parameters:\\n- memory\\u003cem\\u003e{some,full}\\u003c/em\\u003e{avg10,avg60,avg300,total} - double, representing PSI values\\n- time_since_trigger - duration since the last OOM handler trigger event\\u003c/p\\u003e\\n\"\n        },\n        \"cgroupRankingExpression\": {\n          \"type\": \"string\",\n          \"title\": \"cgroupRankingExpression\",\n          \"description\": \"This expression defines how to rank cgroups for OOM handler.\\n\\nThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\n\\nThis expression receives the following parameters:\\n- memory_max - Optional - in bytes\\n- memory_current - Optional - in bytes\\n- memory_peak - Optional - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\\n\",\n          \"markdownDescription\": \"This expression defines how to rank cgroups for OOM handler.\\n\\nThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\n\\nThis expression receives the following parameters:\\n- memory_max - Optional\\u003cuint\\u003e - in bytes\\n- memory_current - Optional\\u003cuint\\u003e - in bytes\\n- memory_peak - Optional\\u003cuint\\u003e - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThis expression defines how to rank cgroups for OOM handler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe cgroup with the highest rank (score) will be evicted first.\\nThe expression must evaluate to a double value.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis expression receives the following parameters:\\n- memory_max - Optional\\u003cuint\\u003e - in bytes\\n- memory_current - Optional\\u003cuint\\u003e - in bytes\\n- memory_peak - Optional\\u003cuint\\u003e - in bytes\\n- path - string, path to the cgroup\\n- class - int. This represents cgroup QoS class, and matches one of the constants, which are also provided: Besteffort, Burstable, Guaranteed, Podruntime, System\\u003c/p\\u003e\\n\"\n        },\n        \"sampleInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"sampleInterval\",\n          \"description\": \"How often should the trigger expression be evaluated.\\n\\nThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\\n\",\n          \"markdownDescription\": \"How often should the trigger expression be evaluated.\\n\\nThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHow often should the trigger expression be evaluated.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis interval determines how often should the OOM controller\\ncheck for the OOM condition using the provided expression.\\nAdjusting it can help tune the reactivity of the OOM handler.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"OOMConfig is a Out of Memory handler config document.\"\n    },\n    \"runtime.WatchdogTimerV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"WatchdogTimerConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"device\": {\n          \"type\": \"string\",\n          \"title\": \"device\",\n          \"description\": \"Path to the watchdog device.\\n\",\n          \"markdownDescription\": \"Path to the watchdog device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath to the watchdog device.\\u003c/p\\u003e\\n\"\n        },\n        \"timeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"timeout\",\n          \"description\": \"Timeout for the watchdog.\\n\\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\\n\\nDefault value is 1 minute, minimum value is 10 seconds.\\n\",\n          \"markdownDescription\": \"Timeout for the watchdog.\\n\\nIf Talos is unresponsive for this duration, the watchdog will reset the system.\\n\\nDefault value is 1 minute, minimum value is 10 seconds.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eTimeout for the watchdog.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf Talos is unresponsive for this duration, the watchdog will reset the system.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value is 1 minute, minimum value is 10 seconds.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"WatchdogTimerConfig is a watchdog timer config document.\"\n    },\n    \"security.TrustedRootsConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"TrustedRootsConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the config document.\\n\",\n          \"markdownDescription\": \"Name of the config document.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the config document.\\u003c/p\\u003e\\n\"\n        },\n        \"certificates\": {\n          \"type\": \"string\",\n          \"title\": \"certificates\",\n          \"description\": \"List of additional trusted certificate authorities (as PEM-encoded certificates).\\n\\nMultiple certificates can be provided in a single config document, separated by newline characters.\\n\",\n          \"markdownDescription\": \"List of additional trusted certificate authorities (as PEM-encoded certificates).\\n\\nMultiple certificates can be provided in a single config document, separated by newline characters.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of additional trusted certificate authorities (as PEM-encoded certificates).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eMultiple certificates can be provided in a single config document, separated by newline characters.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\",\n        \"name\"\n      ],\n      \"description\": \"TrustedRootsConfig allows to configure additional trusted CA roots.\"\n    },\n    \"siderolink.ConfigV1Alpha1\": {\n      \"properties\": {\n        \"apiVersion\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"apiVersion\",\n          \"description\": \"apiVersion is the API version of the resource.\\n\",\n          \"markdownDescription\": \"apiVersion is the API version of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eapiVersion is the API version of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"kind\": {\n          \"enum\": [\n            \"SideroLinkConfig\"\n          ],\n          \"title\": \"kind\",\n          \"description\": \"kind is the kind of the resource.\\n\",\n          \"markdownDescription\": \"kind is the kind of the resource.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ekind is the kind of the resource.\\u003c/p\\u003e\\n\"\n        },\n        \"apiUrl\": {\n          \"type\": \"string\",\n          \"pattern\": \"^(https|grpc)://\",\n          \"title\": \"apiUrl\",\n          \"description\": \"SideroLink API URL to connect to.\\n\",\n          \"markdownDescription\": \"SideroLink API URL to connect to.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSideroLink API URL to connect to.\\u003c/p\\u003e\\n\"\n        },\n        \"uniqueToken\": {\n          \"type\": \"string\",\n          \"title\": \"uniqueToken\",\n          \"description\": \"SideroLink unique token to use for the connection (optional).\\n\\nThis value is overridden with META key UniqueMachineToken.\\n\",\n          \"markdownDescription\": \"SideroLink unique token to use for the connection (optional).\\n\\nThis value is overridden with META key UniqueMachineToken.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSideroLink unique token to use for the connection (optional).\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis value is overridden with META key UniqueMachineToken.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"required\": [\n        \"apiVersion\",\n        \"kind\"\n      ],\n      \"description\": \"SideroLinkConfig is a SideroLink connection machine configuration document.\"\n    },\n    \"v1alpha1.APIServerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the API server manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the API server manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the API server manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the API server.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the API server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the API server.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the API server static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the API server static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the API server static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the API server’s certificate.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the API server's certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the API server\\u0026rsquo;s certificate.\\u003c/p\\u003e\\n\"\n        },\n        \"admissionControl\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.AdmissionPluginConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"admissionControl\",\n          \"description\": \"Configure the API server admission plugins.\\n\",\n          \"markdownDescription\": \"Configure the API server admission plugins.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server admission plugins.\\u003c/p\\u003e\\n\"\n        },\n        \"auditPolicy\": {\n          \"type\": \"object\",\n          \"title\": \"auditPolicy\",\n          \"description\": \"Configure the API server audit policy.\\n\",\n          \"markdownDescription\": \"Configure the API server audit policy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server audit policy.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the API server resources.\\n\",\n          \"markdownDescription\": \"Configure the API server resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server resources.\\u003c/p\\u003e\\n\"\n        },\n        \"authorizationConfig\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.AuthorizationConfigAuthorizerConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"authorizationConfig\",\n          \"description\": \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\\n\",\n          \"markdownDescription\": \"Configure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server authorization config. Node and RBAC authorizers are always added irrespective of the configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"APIServerConfig represents the kube apiserver configuration options.\"\n    },\n    \"v1alpha1.AdminKubeconfigConfig\": {\n      \"properties\": {\n        \"certLifetime\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"certLifetime\",\n          \"description\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdmin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AdminKubeconfigConfig contains admin kubeconfig settings.\"\n    },\n    \"v1alpha1.AdmissionPluginConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\\n\",\n          \"markdownDescription\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is the name of the admission controller.\\nIt must match the registered admission plugin name.\\u003c/p\\u003e\\n\"\n        },\n        \"configuration\": {\n          \"type\": \"object\",\n          \"title\": \"configuration\",\n          \"description\": \"Configuration is an embedded configuration object to be used as the plugin’s\\nconfiguration.\\n\",\n          \"markdownDescription\": \"Configuration is an embedded configuration object to be used as the plugin's\\nconfiguration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration is an embedded configuration object to be used as the plugin\\u0026rsquo;s\\nconfiguration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AdmissionPluginConfig represents the API server admission plugin configuration.\"\n    },\n    \"v1alpha1.AuthorizationConfigAuthorizerConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type is the name of the authorizer. Allowed values are Node, RBAC, and Webhook.\\n\",\n          \"markdownDescription\": \"Type is the name of the authorizer. Allowed values are `Node`, `RBAC`, and `Webhook`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType is the name of the authorizer. Allowed values are \\u003ccode\\u003eNode\\u003c/code\\u003e, \\u003ccode\\u003eRBAC\\u003c/code\\u003e, and \\u003ccode\\u003eWebhook\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is used to describe the authorizer.\\n\",\n          \"markdownDescription\": \"Name is used to describe the authorizer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is used to describe the authorizer.\\u003c/p\\u003e\\n\"\n        },\n        \"webhook\": {\n          \"type\": \"object\",\n          \"title\": \"webhook\",\n          \"description\": \"webhook is the configuration for the webhook authorizer.\\n\",\n          \"markdownDescription\": \"webhook is the configuration for the webhook authorizer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ewebhook is the configuration for the webhook authorizer.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"AuthorizationConfigAuthorizerConfig represents the API server authorization config authorizer configuration.\"\n    },\n    \"v1alpha1.CNIConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"enum\": [\n            \"flannel\",\n            \"custom\",\n            \"none\"\n          ],\n          \"title\": \"name\",\n          \"description\": \"Name of CNI to use.\\n\",\n          \"markdownDescription\": \"Name of CNI to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of CNI to use.\\u003c/p\\u003e\\n\"\n        },\n        \"urls\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"urls\",\n          \"description\": \"URLs containing manifests to apply for the CNI.\\nShould be present for “custom”, must be empty for “flannel” and “none”.\\n\",\n          \"markdownDescription\": \"URLs containing manifests to apply for the CNI.\\nShould be present for \\\"custom\\\", must be empty for \\\"flannel\\\" and \\\"none\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eURLs containing manifests to apply for the CNI.\\nShould be present for \\u0026ldquo;custom\\u0026rdquo;, must be empty for \\u0026ldquo;flannel\\u0026rdquo; and \\u0026ldquo;none\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"flannel\": {\n          \"$ref\": \"#/$defs/v1alpha1.FlannelCNIConfig\",\n          \"title\": \"flannel\",\n          \"description\": \"description: |\\nFlannel configuration options.\\n\",\n          \"markdownDescription\": \"description: |\\nFlannel configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\nFlannel configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CNIConfig represents the CNI configuration options.\"\n    },\n    \"v1alpha1.ClusterConfig\": {\n      \"properties\": {\n        \"id\": {\n          \"type\": \"string\",\n          \"title\": \"id\",\n          \"description\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\\n\",\n          \"markdownDescription\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eGlobally unique identifier for this cluster (base64 encoded random 32 bytes).\\u003c/p\\u003e\\n\"\n        },\n        \"secret\": {\n          \"type\": \"string\",\n          \"title\": \"secret\",\n          \"description\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\n\",\n          \"markdownDescription\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/v1alpha1.ControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides control plane specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides control plane specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides control plane specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterName\": {\n          \"type\": \"string\",\n          \"title\": \"clusterName\",\n          \"description\": \"Configures the cluster’s name.\\n\",\n          \"markdownDescription\": \"Configures the cluster's name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the cluster\\u0026rsquo;s name.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterNetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides cluster specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The bootstrap token used to join the cluster.\\n\",\n          \"markdownDescription\": \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/\\\" target=\\\"_blank\\\"\\u003ebootstrap token\\u003c/a\\u003e used to join the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"aescbcEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"aescbcEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"secretboxEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"secretboxEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The base64 encoded root certificate authority used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The base64 encoded root certificate authority used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded root certificate authority used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"acceptedCAs\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"acceptedCAs\",\n          \"description\": \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The list of base64 encoded accepted certificate authorities used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of base64 encoded accepted certificate authorities used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"aggregatorCA\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"aggregatorCA\",\n          \"description\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\\n\",\n          \"markdownDescription\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis CA can be self-signed.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceAccount\": {\n          \"properties\": {\n            \"key\": {\n              \"additionalProperties\": false,\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"serviceAccount\",\n          \"description\": \"The base64 encoded private key for service account token generation.\\n\",\n          \"markdownDescription\": \"The base64 encoded private key for service account token generation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded private key for service account token generation.\\u003c/p\\u003e\\n\"\n        },\n        \"apiServer\": {\n          \"$ref\": \"#/$defs/v1alpha1.APIServerConfig\",\n          \"title\": \"apiServer\",\n          \"description\": \"API server specific configuration options.\\n\",\n          \"markdownDescription\": \"API server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAPI server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/v1alpha1.ControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager server specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"proxy\": {\n          \"$ref\": \"#/$defs/v1alpha1.ProxyConfig\",\n          \"title\": \"proxy\",\n          \"description\": \"Kube-proxy server-specific configuration options\\n\",\n          \"markdownDescription\": \"Kube-proxy server-specific configuration options\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKube-proxy server-specific configuration options\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/v1alpha1.SchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler server specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterDiscoveryConfig\",\n          \"title\": \"discovery\",\n          \"description\": \"Configures cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configures cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures cluster member discovery.\\u003c/p\\u003e\\n\"\n        },\n        \"etcd\": {\n          \"$ref\": \"#/$defs/v1alpha1.EtcdConfig\",\n          \"title\": \"etcd\",\n          \"description\": \"Etcd specific configuration options.\\n\",\n          \"markdownDescription\": \"Etcd specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEtcd specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"coreDNS\": {\n          \"$ref\": \"#/$defs/v1alpha1.CoreDNS\",\n          \"title\": \"coreDNS\",\n          \"description\": \"Core DNS specific configuration options.\\n\",\n          \"markdownDescription\": \"Core DNS specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCore DNS specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"externalCloudProvider\": {\n          \"$ref\": \"#/$defs/v1alpha1.ExternalCloudProviderConfig\",\n          \"title\": \"externalCloudProvider\",\n          \"description\": \"External cloud provider configuration.\\n\",\n          \"markdownDescription\": \"External cloud provider configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal cloud provider configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraManifests\",\n          \"description\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifestHeaders\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraManifestHeaders\",\n          \"description\": \"A map of key value pairs that will be added while fetching the extraManifests.\\n\",\n          \"markdownDescription\": \"A map of key value pairs that will be added while fetching the extraManifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA map of key value pairs that will be added while fetching the extraManifests.\\u003c/p\\u003e\\n\"\n        },\n        \"inlineManifests\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.ClusterInlineManifest\"\n          },\n          \"type\": \"array\",\n          \"title\": \"inlineManifests\",\n          \"description\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"adminKubeconfig\": {\n          \"$ref\": \"#/$defs/v1alpha1.AdminKubeconfigConfig\",\n          \"title\": \"adminKubeconfig\",\n          \"description\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\n\",\n          \"markdownDescription\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSettings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\u003c/p\\u003e\\n\"\n        },\n        \"allowSchedulingOnControlPlanes\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowSchedulingOnControlPlanes\",\n          \"description\": \"Allows running workload on control-plane nodes.\\n\",\n          \"markdownDescription\": \"Allows running workload on control-plane nodes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows running workload on control-plane nodes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterConfig represents the cluster-wide config values.\"\n    },\n    \"v1alpha1.ClusterDiscoveryConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\n\",\n          \"markdownDescription\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/v1alpha1.DiscoveryRegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Configure registries used for cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configure registries used for cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure registries used for cluster member discovery.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterDiscoveryConfig struct configures cluster membership discovery.\"\n    },\n    \"v1alpha1.ClusterInlineManifest\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the manifest.\\nName should be unique.\\n\",\n          \"markdownDescription\": \"Name of the manifest.\\nName should be unique.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the manifest.\\nName should be unique.\\u003c/p\\u003e\\n\"\n        },\n        \"contents\": {\n          \"type\": \"string\",\n          \"title\": \"contents\",\n          \"description\": \"Manifest contents as a string.\\n\",\n          \"markdownDescription\": \"Manifest contents as a string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eManifest contents as a string.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterInlineManifest struct describes inline bootstrap manifests for the user.\"\n    },\n    \"v1alpha1.ClusterNetworkConfig\": {\n      \"properties\": {\n        \"cni\": {\n          \"$ref\": \"#/$defs/v1alpha1.CNIConfig\",\n          \"title\": \"cni\",\n          \"description\": \"The CNI used.\\nComposed of “name” and “urls”.\\nThe “name” key supports the following options: “flannel”, “custom”, and “none”.\\n“flannel” uses Talos-managed Flannel CNI, and that’s the default option.\\n“custom” uses custom manifests that should be provided in “urls”.\\n“none” indicates that Talos will not manage any CNI installation.\\n\",\n          \"markdownDescription\": \"The CNI used.\\nComposed of \\\"name\\\" and \\\"urls\\\".\\nThe \\\"name\\\" key supports the following options: \\\"flannel\\\", \\\"custom\\\", and \\\"none\\\".\\n\\\"flannel\\\" uses Talos-managed Flannel CNI, and that's the default option.\\n\\\"custom\\\" uses custom manifests that should be provided in \\\"urls\\\".\\n\\\"none\\\" indicates that Talos will not manage any CNI installation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe CNI used.\\nComposed of \\u0026ldquo;name\\u0026rdquo; and \\u0026ldquo;urls\\u0026rdquo;.\\nThe \\u0026ldquo;name\\u0026rdquo; key supports the following options: \\u0026ldquo;flannel\\u0026rdquo;, \\u0026ldquo;custom\\u0026rdquo;, and \\u0026ldquo;none\\u0026rdquo;.\\n\\u0026ldquo;flannel\\u0026rdquo; uses Talos-managed Flannel CNI, and that\\u0026rsquo;s the default option.\\n\\u0026ldquo;custom\\u0026rdquo; uses custom manifests that should be provided in \\u0026ldquo;urls\\u0026rdquo;.\\n\\u0026ldquo;none\\u0026rdquo; indicates that Talos will not manage any CNI installation.\\u003c/p\\u003e\\n\"\n        },\n        \"dnsDomain\": {\n          \"type\": \"string\",\n          \"title\": \"dnsDomain\",\n          \"description\": \"The domain used by Kubernetes DNS.\\nThe default is cluster.local\\n\",\n          \"markdownDescription\": \"The domain used by Kubernetes DNS.\\nThe default is `cluster.local`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe domain used by Kubernetes DNS.\\nThe default is \\u003ccode\\u003ecluster.local\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"podSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"podSubnets\",\n          \"description\": \"The pod subnet CIDR.\\n\",\n          \"markdownDescription\": \"The pod subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe pod subnet CIDR.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"serviceSubnets\",\n          \"description\": \"The service subnet CIDR.\\n\",\n          \"markdownDescription\": \"The service subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe service subnet CIDR.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ClusterNetworkConfig represents kube networking configuration options.\"\n    },\n    \"v1alpha1.Config\": {\n      \"properties\": {\n        \"version\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"version\",\n          \"description\": \"Indicates the schema used to decode the contents.\\n\",\n          \"markdownDescription\": \"Indicates the schema used to decode the contents.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates the schema used to decode the contents.\\u003c/p\\u003e\\n\"\n        },\n        \"debug\": {\n          \"type\": \"boolean\",\n          \"title\": \"debug\",\n          \"description\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\nNote: To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\n\",\n          \"markdownDescription\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\n**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eNote:\\u003c/strong\\u003e To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\u003c/p\\u003e\\n\"\n        },\n        \"machine\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineConfig\",\n          \"title\": \"machine\",\n          \"description\": \"Provides machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"cluster\": {\n          \"$ref\": \"#/$defs/v1alpha1.ClusterConfig\",\n          \"title\": \"cluster\",\n          \"description\": \"Provides cluster specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"Config defines the v1alpha1.Config Talos machine configuration document.\"\n    },\n    \"v1alpha1.ControlPlaneConfig\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^https://\",\n          \"format\": \"uri\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\n\",\n          \"markdownDescription\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\u003c/p\\u003e\\n\"\n        },\n        \"localAPIServerPort\": {\n          \"type\": \"integer\",\n          \"title\": \"localAPIServerPort\",\n          \"description\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is 6443.\\n\",\n          \"markdownDescription\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is `6443`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is \\u003ccode\\u003e6443\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ControlPlaneConfig represents the control plane configuration options.\"\n    },\n    \"v1alpha1.ControllerManagerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the controller manager manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the controller manager manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the controller manager manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the controller manager.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the controller manager.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the controller manager.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the controller manager static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the controller manager static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the controller manager static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the controller manager resources.\\n\",\n          \"markdownDescription\": \"Configure the controller manager resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the controller manager resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ControllerManagerConfig represents the kube controller manager configuration options.\"\n    },\n    \"v1alpha1.CoreDNS\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable coredns deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable coredns deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable coredns deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an override to the default coredns image.\\n\",\n          \"markdownDescription\": \"The `image` field is an override to the default coredns image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an override to the default coredns image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"CoreDNS represents the CoreDNS config values.\"\n    },\n    \"v1alpha1.DiscoveryRegistriesConfig\": {\n      \"properties\": {\n        \"kubernetes\": {\n          \"$ref\": \"#/$defs/v1alpha1.RegistryKubernetesConfig\",\n          \"title\": \"kubernetes\",\n          \"description\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\\nThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee https://github.com/siderolabs/talos/issues/9980 for more information.\\n\",\n          \"markdownDescription\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\\nThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee https://github.com/siderolabs/talos/issues/9980 for more information.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is deprecated as it is not compatible with Kubernetes 1.32+.\\nSee \\u003ca href=\\\"https://github.com/siderolabs/talos/issues/9980\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/siderolabs/talos/issues/9980\\u003c/a\\u003e for more information.\\u003c/p\\u003e\\n\"\n        },\n        \"service\": {\n          \"$ref\": \"#/$defs/v1alpha1.RegistryServiceConfig\",\n          \"title\": \"service\",\n          \"description\": \"Service registry is using an external service to push and pull information about cluster members.\\n\",\n          \"markdownDescription\": \"Service registry is using an external service to push and pull information about cluster members.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eService registry is using an external service to push and pull information about cluster members.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"DiscoveryRegistriesConfig struct configures cluster membership discovery.\"\n    },\n    \"v1alpha1.Endpoint\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"Endpoint represents the endpoint URL parsed out of the machine config.\"\n    },\n    \"v1alpha1.EtcdConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used to create the etcd service.\\n\",\n          \"markdownDescription\": \"The container image used to create the etcd service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used to create the etcd service.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The ca is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The `ca` is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eca\\u003c/code\\u003e is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n\\nname\\ndata-dir\\ninitial-cluster-state\\nlisten-peer-urls\\nlisten-client-urls\\ncert-file\\nkey-file\\ntrusted-ca-file\\npeer-client-cert-auth\\npeer-cert-file\\npeer-trusted-ca-file\\npeer-key-file\\n\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n- `name`\\n- `data-dir`\\n- `initial-cluster-state`\\n- `listen-peer-urls`\\n- `listen-client-urls`\\n- `cert-file`\\n- `key-file`\\n- `trusted-ca-file`\\n- `peer-client-cert-auth`\\n- `peer-cert-file`\\n- `peer-trusted-ca-file`\\n- `peer-key-file`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to etcd.\\nNote that the following args are not allowed:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ename\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003edata-dir\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003einitial-cluster-state\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-peer-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-client-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ecert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ekey-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003etrusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-client-cert-auth\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-cert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-trusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-key-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"advertisedSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"advertisedSubnets\",\n          \"description\": \"The advertisedSubnets field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e field configures the networks to pick etcd advertised IP from.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        },\n        \"listenSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"listenSubnets\",\n          \"description\": \"The listenSubnets field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf listenSubnets is not set, but advertisedSubnets is set, listenSubnets defaults to\\nadvertisedSubnets.\\n\\nIf neither advertisedSubnets nor listenSubnets is set, listenSubnets defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\\n`advertisedSubnets`.\\n\\nIf neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e field configures the networks for the etcd to listen for peer and client connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is not set, but \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to\\n\\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf neither \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e nor \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to listen on all addresses.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"EtcdConfig represents the etcd configuration options.\"\n    },\n    \"v1alpha1.ExternalCloudProviderConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable external cloud provider.\\n\",\n          \"markdownDescription\": \"Enable external cloud provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable external cloud provider.\\u003c/p\\u003e\\n\"\n        },\n        \"manifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"manifests\",\n          \"description\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExternalCloudProviderConfig contains external cloud provider configuration.\"\n    },\n    \"v1alpha1.ExtraMount\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"title\": \"destination\",\n          \"description\": \"Destination is the absolute path where the mount will be placed in the container.\\n\",\n          \"markdownDescription\": \"Destination is the absolute path where the mount will be placed in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination is the absolute path where the mount will be placed in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type specifies the mount kind.\\n\",\n          \"markdownDescription\": \"Type specifies the mount kind.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType specifies the mount kind.\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"Source specifies the source path of the mount.\\n\",\n          \"markdownDescription\": \"Source specifies the source path of the mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource specifies the source path of the mount.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"options\",\n          \"description\": \"Options are fstab style mount options.\\n\",\n          \"markdownDescription\": \"Options are fstab style mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptions are fstab style mount options.\\u003c/p\\u003e\\n\"\n        },\n        \"uidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"uidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        },\n        \"gidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"gidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ExtraMount wraps OCI Mount specification.\"\n    },\n    \"v1alpha1.FeaturesConfig\": {\n      \"properties\": {\n        \"kubernetesTalosAPIAccess\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubernetesTalosAPIAccessConfig\",\n          \"title\": \"kubernetesTalosAPIAccess\",\n          \"description\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\\n\",\n          \"markdownDescription\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is disabled if the feature config is not specified.\\u003c/p\\u003e\\n\"\n        },\n        \"diskQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"diskQuotaSupport\",\n          \"description\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\n\",\n          \"markdownDescription\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\u003c/p\\u003e\\n\"\n        },\n        \"kubePrism\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubePrism\",\n          \"title\": \"kubePrism\",\n          \"description\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\n\",\n          \"markdownDescription\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"hostDNS\": {\n          \"$ref\": \"#/$defs/v1alpha1.HostDNSConfig\",\n          \"title\": \"hostDNS\",\n          \"description\": \"Configures host DNS caching resolver.\\n\",\n          \"markdownDescription\": \"Configures host DNS caching resolver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures host DNS caching resolver.\\u003c/p\\u003e\\n\"\n        },\n        \"imageCache\": {\n          \"$ref\": \"#/$defs/v1alpha1.ImageCacheConfig\",\n          \"title\": \"imageCache\",\n          \"description\": \"Enable Image Cache feature.\\n\",\n          \"markdownDescription\": \"Enable Image Cache feature.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Image Cache feature.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeAddressSortAlgorithm\": {\n          \"type\": \"string\",\n          \"title\": \"nodeAddressSortAlgorithm\",\n          \"description\": \"Select the node address sort algorithm.\\nThe ‘v1’ algorithm sorts addresses by the address itself.\\nThe ‘v2’ algorithm prefers more specific prefixes.\\nIf unset, defaults to ‘v1’.\\n\",\n          \"markdownDescription\": \"Select the node address sort algorithm.\\nThe 'v1' algorithm sorts addresses by the address itself.\\nThe 'v2' algorithm prefers more specific prefixes.\\nIf unset, defaults to 'v1'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSelect the node address sort algorithm.\\nThe \\u0026lsquo;v1\\u0026rsquo; algorithm sorts addresses by the address itself.\\nThe \\u0026lsquo;v2\\u0026rsquo; algorithm prefers more specific prefixes.\\nIf unset, defaults to \\u0026lsquo;v1\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FeaturesConfig describes individual Talos features that can be switched on or off.\"\n    },\n    \"v1alpha1.FlannelCNIConfig\": {\n      \"properties\": {\n        \"extraArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments for ‘flanneld’.\\n\",\n          \"markdownDescription\": \"Extra arguments for 'flanneld'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments for \\u0026lsquo;flanneld\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"kubeNetworkPoliciesEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"kubeNetworkPoliciesEnabled\",\n          \"description\": \"Deploys kube-network-policies along with Flannel.\\n\\nThis enables Kubernetes Network Policies support in the cluster.\\n\",\n          \"markdownDescription\": \"Deploys kube-network-policies along with Flannel.\\n\\nThis enables Kubernetes Network Policies support in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeploys kube-network-policies along with Flannel.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis enables Kubernetes Network Policies support in the cluster.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"FlannelCNIConfig represents the Flannel CNI configuration options.\"\n    },\n    \"v1alpha1.HostDNSConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable host DNS caching resolver.\\n\",\n          \"markdownDescription\": \"Enable host DNS caching resolver.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable host DNS caching resolver.\\u003c/p\\u003e\\n\"\n        },\n        \"forwardKubeDNSToHost\": {\n          \"type\": \"boolean\",\n          \"title\": \"forwardKubeDNSToHost\",\n          \"description\": \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\n\\nWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\\n\",\n          \"markdownDescription\": \"Use the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\n\\nWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse the host DNS resolver as upstream for Kubernetes CoreDNS pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen enabled, CoreDNS pods use host DNS server as the upstream DNS (instead of\\nusing configured upstream DNS resolvers directly).\\u003c/p\\u003e\\n\"\n        },\n        \"resolveMemberNames\": {\n          \"type\": \"boolean\",\n          \"title\": \"resolveMemberNames\",\n          \"description\": \"Resolve member hostnames using the host DNS resolver.\\n\\nWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\\n\",\n          \"markdownDescription\": \"Resolve member hostnames using the host DNS resolver.\\n\\nWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eResolve member hostnames using the host DNS resolver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWhen enabled, cluster member hostnames and node names are resolved using the host DNS resolver.\\nThis requires service discovery to be enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"HostDNSConfig describes the configuration for the host DNS resolver.\"\n    },\n    \"v1alpha1.ImageCacheConfig\": {\n      \"properties\": {\n        \"localEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"localEnabled\",\n          \"description\": \"Enable local image cache.\\n\",\n          \"markdownDescription\": \"Enable local image cache.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable local image cache.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ImageCacheConfig describes the configuration for the Image Cache feature.\"\n    },\n    \"v1alpha1.InstallConfig\": {\n      \"properties\": {\n        \"disk\": {\n          \"type\": \"string\",\n          \"title\": \"disk\",\n          \"description\": \"The disk used for installations.\\n\",\n          \"markdownDescription\": \"The disk used for installations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk used for installations.\\u003c/p\\u003e\\n\"\n        },\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/v1alpha1.InstallDiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over disk.\\n\",\n          \"markdownDescription\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over `disk`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLook up disk using disk attributes like model, size, serial and others.\\nAlways has priority over \\u003ccode\\u003edisk\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\nGitHub releases page.\\n\",\n          \"markdownDescription\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n[GitHub releases page](https://github.com/siderolabs/talos/releases).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n\\u003ca href=\\\"https://github.com/siderolabs/talos/releases\\\" target=\\\"_blank\\\"\\u003eGitHub releases page\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wipe\": {\n          \"type\": \"boolean\",\n          \"title\": \"wipe\",\n          \"description\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the installation disk should be wiped at installation time.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"legacyBIOSSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"legacyBIOSSupport\",\n          \"description\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn’t support GPT partitioning scheme.\\n\",\n          \"markdownDescription\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn\\u0026rsquo;t support GPT partitioning scheme.\\u003c/p\\u003e\\n\"\n        },\n        \"grubUseUKICmdline\": {\n          \"type\": \"boolean\",\n          \"title\": \"grubUseUKICmdline\",\n          \"description\": \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\\n\",\n          \"markdownDescription\": \"Indicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if legacy GRUB bootloader should use kernel cmdline from the UKI instead of building it on the host.\\nThis changes the way cmdline is managed with GRUB bootloader to be more consistent with UKI/systemd-boot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"InstallConfig represents the installation options for preparing a node.\"\n    },\n    \"v1alpha1.InstallDiskSelector\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"string\",\n          \"title\": \"size\",\n          \"description\": \"Disk size.\\n\",\n          \"markdownDescription\": \"Disk size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk size.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Disk name /sys/block/\\u0026lt;dev\\u0026gt;/device/name.\\n\",\n          \"markdownDescription\": \"Disk name `/sys/block/\\u003cdev\\u003e/device/name`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk name \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/name\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"model\": {\n          \"type\": \"string\",\n          \"title\": \"model\",\n          \"description\": \"Disk model /sys/block/\\u0026lt;dev\\u0026gt;/device/model.\\n\",\n          \"markdownDescription\": \"Disk model `/sys/block/\\u003cdev\\u003e/device/model`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk model \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/model\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"serial\": {\n          \"type\": \"string\",\n          \"title\": \"serial\",\n          \"description\": \"Disk serial number /sys/block/\\u0026lt;dev\\u0026gt;/serial.\\n\",\n          \"markdownDescription\": \"Disk serial number `/sys/block/\\u003cdev\\u003e/serial`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk serial number \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/serial\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"modalias\": {\n          \"type\": \"string\",\n          \"title\": \"modalias\",\n          \"description\": \"Disk modalias /sys/block/\\u0026lt;dev\\u0026gt;/device/modalias.\\n\",\n          \"markdownDescription\": \"Disk modalias `/sys/block/\\u003cdev\\u003e/device/modalias`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk modalias \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/modalias\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"uuid\": {\n          \"type\": \"string\",\n          \"title\": \"uuid\",\n          \"description\": \"Disk UUID /sys/block/\\u0026lt;dev\\u0026gt;/uuid.\\n\",\n          \"markdownDescription\": \"Disk UUID `/sys/block/\\u003cdev\\u003e/uuid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk UUID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/uuid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wwid\": {\n          \"type\": \"string\",\n          \"title\": \"wwid\",\n          \"description\": \"Disk WWID /sys/block/\\u0026lt;dev\\u0026gt;/wwid.\\n\",\n          \"markdownDescription\": \"Disk WWID `/sys/block/\\u003cdev\\u003e/wwid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk WWID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/wwid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"enum\": [\n            \"ssd\",\n            \"hdd\",\n            \"nvme\",\n            \"sd\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Disk Type.\\n\",\n          \"markdownDescription\": \"Disk Type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk Type.\\u003c/p\\u003e\\n\"\n        },\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"Disk bus path.\\n\",\n          \"markdownDescription\": \"Disk bus path.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk bus path.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"InstallDiskSelector represents a disk query parameters for the install disk lookup.\"\n    },\n    \"v1alpha1.KernelConfig\": {\n      \"properties\": {\n        \"modules\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.KernelModuleConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"modules\",\n          \"description\": \"Kernel modules to load.\\n\",\n          \"markdownDescription\": \"Kernel modules to load.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel modules to load.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KernelConfig struct configures Talos Linux kernel.\"\n    },\n    \"v1alpha1.KernelModuleConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Module name.\\n\",\n          \"markdownDescription\": \"Module name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule name.\\u003c/p\\u003e\\n\"\n        },\n        \"parameters\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"parameters\",\n          \"description\": \"Module parameters, changes applied after reboot.\\n\",\n          \"markdownDescription\": \"Module parameters, changes applied after reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule parameters, changes applied after reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KernelModuleConfig struct configures Linux kernel modules to load.\"\n    },\n    \"v1alpha1.KubePrism\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable KubePrism support - will start local load balancing proxy.\\n\",\n          \"markdownDescription\": \"Enable KubePrism support - will start local load balancing proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable KubePrism support - will start local load balancing proxy.\\u003c/p\\u003e\\n\"\n        },\n        \"port\": {\n          \"type\": \"integer\",\n          \"title\": \"port\",\n          \"description\": \"KubePrism port.\\n\",\n          \"markdownDescription\": \"KubePrism port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism port.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubePrism describes the configuration for the KubePrism load balancer.\"\n    },\n    \"v1alpha1.KubeletConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an optional reference to an alternative kubelet image.\\n\",\n          \"markdownDescription\": \"The `image` field is an optional reference to an alternative kubelet image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an optional reference to an alternative kubelet image.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterDNS\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"clusterDNS\",\n          \"description\": \"The ClusterDNS field is an optional reference to an alternative kubelet clusterDNS ip list.\\n\",\n          \"markdownDescription\": \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eClusterDNS\\u003c/code\\u003e field is an optional reference to an alternative kubelet clusterDNS ip list.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"The extraArgs field is used to provide additional flags to the kubelet.\\n\",\n          \"markdownDescription\": \"The `extraArgs` field is used to provide additional flags to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraArgs\\u003c/code\\u003e field is used to provide additional flags to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"extraMounts\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.ExtraMount\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraMounts\",\n          \"description\": \"The extraMounts field is used to add additional mounts to the kubelet container.\\nNote that either bind or rbind are required in the options.\\n\",\n          \"markdownDescription\": \"The `extraMounts` field is used to add additional mounts to the kubelet container.\\nNote that either `bind` or `rbind` are required in the `options`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraMounts\\u003c/code\\u003e field is used to add additional mounts to the kubelet container.\\nNote that either \\u003ccode\\u003ebind\\u003c/code\\u003e or \\u003ccode\\u003erbind\\u003c/code\\u003e are required in the \\u003ccode\\u003eoptions\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraConfig\": {\n          \"type\": \"object\",\n          \"title\": \"extraConfig\",\n          \"description\": \"The extraConfig field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\n\",\n          \"markdownDescription\": \"The `extraConfig` field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraConfig\\u003c/code\\u003e field is used to provide kubelet configuration overrides.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\u003c/p\\u003e\\n\"\n        },\n        \"credentialProviderConfig\": {\n          \"type\": \"object\",\n          \"title\": \"credentialProviderConfig\",\n          \"description\": \"The KubeletCredentialProviderConfig field is used to provide kubelet credential configuration.\\n\",\n          \"markdownDescription\": \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eKubeletCredentialProviderConfig\\u003c/code\\u003e field is used to provide kubelet credential configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"defaultRuntimeSeccompProfileEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"defaultRuntimeSeccompProfileEnabled\",\n          \"description\": \"Enable container runtime default Seccomp profile.\\n\",\n          \"markdownDescription\": \"Enable container runtime default Seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable container runtime default Seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"registerWithFQDN\": {\n          \"type\": \"boolean\",\n          \"title\": \"registerWithFQDN\",\n          \"description\": \"The registerWithFQDN field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\n\",\n          \"markdownDescription\": \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eregisterWithFQDN\\u003c/code\\u003e field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeIP\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubeletNodeIPConfig\",\n          \"title\": \"nodeIP\",\n          \"description\": \"The nodeIP field is used to configure --node-ip flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\n\",\n          \"markdownDescription\": \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003enodeIP\\u003c/code\\u003e field is used to configure \\u003ccode\\u003e--node-ip\\u003c/code\\u003e flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\u003c/p\\u003e\\n\"\n        },\n        \"skipNodeRegistration\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipNodeRegistration\",\n          \"description\": \"The skipNodeRegistration is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\n\",\n          \"markdownDescription\": \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eskipNodeRegistration\\u003c/code\\u003e is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\u003c/p\\u003e\\n\"\n        },\n        \"disableManifestsDirectory\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableManifestsDirectory\",\n          \"description\": \"The disableManifestsDirectory field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt’s recommended to configure static pods with the “pods” key instead.\\n\",\n          \"markdownDescription\": \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt's recommended to configure static pods with the \\\"pods\\\" key instead.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003edisableManifestsDirectory\\u003c/code\\u003e field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt\\u0026rsquo;s recommended to configure static pods with the \\u0026ldquo;pods\\u0026rdquo; key instead.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeletConfig represents the kubelet config values.\"\n    },\n    \"v1alpha1.KubeletNodeIPConfig\": {\n      \"properties\": {\n        \"validSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"validSubnets\",\n          \"description\": \"The validSubnets field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\n\",\n          \"markdownDescription\": \"The `validSubnets` field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalidSubnets\\u003c/code\\u003e field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubeletNodeIPConfig represents the kubelet node IP configuration.\"\n    },\n    \"v1alpha1.KubernetesTalosAPIAccessConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable Talos API access from Kubernetes pods.\\n\",\n          \"markdownDescription\": \"Enable Talos API access from Kubernetes pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedRoles\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedRoles\",\n          \"description\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\\n\",\n          \"markdownDescription\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Talos API roles which can be granted for access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEmpty list means that no roles can be granted, so access is blocked.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedKubernetesNamespaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedKubernetesNamespaces\",\n          \"description\": \"The list of Kubernetes namespaces Talos API access is available from.\\n\",\n          \"markdownDescription\": \"The list of Kubernetes namespaces Talos API access is available from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Kubernetes namespaces Talos API access is available from.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"KubernetesTalosAPIAccessConfig describes the configuration for the Talos API access from Kubernetes pods.\"\n    },\n    \"v1alpha1.LinuxIDMapping\": {\n      \"properties\": {\n        \"containerID\": {\n          \"type\": \"integer\",\n          \"title\": \"containerID\",\n          \"description\": \"ContainerID is the starting UID/GID in the container.\\n\",\n          \"markdownDescription\": \"ContainerID is the starting UID/GID in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eContainerID is the starting UID/GID in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"hostID\": {\n          \"type\": \"integer\",\n          \"title\": \"hostID\",\n          \"description\": \"HostID is the starting UID/GID on the host to be mapped to ‘ContainerID’.\\n\",\n          \"markdownDescription\": \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHostID is the starting UID/GID on the host to be mapped to \\u0026lsquo;ContainerID\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"Size is the number of IDs to be mapped.\\n\",\n          \"markdownDescription\": \"Size is the number of IDs to be mapped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSize is the number of IDs to be mapped.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LinuxIDMapping represents the Linux ID mapping.\"\n    },\n    \"v1alpha1.LoggingConfig\": {\n      \"properties\": {\n        \"destinations\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.LoggingDestination\"\n          },\n          \"type\": \"array\",\n          \"title\": \"destinations\",\n          \"description\": \"Logging destination.\\n\",\n          \"markdownDescription\": \"Logging destination.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogging destination.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LoggingConfig struct configures Talos logging.\"\n    },\n    \"v1alpha1.LoggingDestination\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"$ref\": \"#/$defs/v1alpha1.Endpoint\",\n          \"title\": \"endpoint\",\n          \"description\": \"Where to send logs. Supported protocols are “tcp” and “udp”.\\n\",\n          \"markdownDescription\": \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to send logs. Supported protocols are \\u0026ldquo;tcp\\u0026rdquo; and \\u0026ldquo;udp\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"format\": {\n          \"enum\": [\n            \"json_lines\"\n          ],\n          \"title\": \"format\",\n          \"description\": \"Logs format.\\n\",\n          \"markdownDescription\": \"Logs format.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogs format.\\u003c/p\\u003e\\n\"\n        },\n        \"extraTags\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraTags\",\n          \"description\": \"Extra tags (key-value) pairs to attach to every log message sent.\\n\",\n          \"markdownDescription\": \"Extra tags (key-value) pairs to attach to every log message sent.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra tags (key-value) pairs to attach to every log message sent.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"LoggingDestination struct configures Talos logging destination.\"\n    },\n    \"v1alpha1.MachineConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"controlplane\",\n            \"worker\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Defines the role of the machine within the cluster.\\n\\nControl Plane\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\nWorker\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as “join”; that value is still supported but deprecated.\\n\",\n          \"markdownDescription\": \"Defines the role of the machine within the cluster.\\n\\n**Control Plane**\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\n**Worker**\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as \\\"join\\\"; that value is still supported but deprecated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the role of the machine within the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eControl Plane\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eWorker\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis node type was previously known as \\u0026ldquo;join\\u0026rdquo;; that value is still supported but deprecated.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The token is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its’ identity.\\n\",\n          \"markdownDescription\": \"The `token` is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003etoken\\u003c/code\\u003e is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its\\u0026rsquo; identity.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"acceptedCAs\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"acceptedCAs\",\n          \"description\": \"The certificates issued by certificate authorities are accepted in addition to issuing ‘ca’.\\nIt is composed of a base64 encoded crt`.\\n\",\n          \"markdownDescription\": \"The certificates issued by certificate authorities are accepted in addition to issuing 'ca'.\\nIt is composed of a base64 encoded `crt``.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe certificates issued by certificate authorities are accepted in addition to issuing \\u0026lsquo;ca\\u0026rsquo;.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e`.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the machine’s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate’s SANs.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the machine's certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate's SANs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the machine\\u0026rsquo;s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate\\u0026rsquo;s SANs.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides machine specific control plane configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific control plane configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific control plane configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"kubelet\": {\n          \"$ref\": \"#/$defs/v1alpha1.KubeletConfig\",\n          \"title\": \"kubelet\",\n          \"description\": \"Used to provide additional options to the kubelet.\\n\",\n          \"markdownDescription\": \"Used to provide additional options to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide additional options to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"pods\": {\n          \"items\": {\n            \"type\": \"object\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pods\",\n          \"description\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn’t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\\n\",\n          \"markdownDescription\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn't validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn\\u0026rsquo;t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee \\u003ca href=\\\"https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\\" target=\\\"_blank\\\"\\u003ehttps://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"install\": {\n          \"$ref\": \"#/$defs/v1alpha1.InstallConfig\",\n          \"title\": \"install\",\n          \"description\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\n\",\n          \"markdownDescription\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide instructions for installations.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\u003c/p\\u003e\\n\"\n        },\n        \"files\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.MachineFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"files\",\n          \"description\": \"Allows the addition of user specified files.\\nThe value of op can be create, overwrite, or append.\\nIn the case of create, path must not exist.\\nIn the case of overwrite, and append, path must be a valid file.\\nIf an op value of append is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\n\",\n          \"markdownDescription\": \"Allows the addition of user specified files.\\nThe value of `op` can be `create`, `overwrite`, or `append`.\\nIn the case of `create`, `path` must not exist.\\nIn the case of `overwrite`, and `append`, `path` must be a valid file.\\nIf an `op` value of `append` is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows the addition of user specified files.\\nThe value of \\u003ccode\\u003eop\\u003c/code\\u003e can be \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, or \\u003ccode\\u003eappend\\u003c/code\\u003e.\\nIn the case of \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must not exist.\\nIn the case of \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, and \\u003ccode\\u003eappend\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must be a valid file.\\nIf an \\u003ccode\\u003eop\\u003c/code\\u003e value of \\u003ccode\\u003eappend\\u003c/code\\u003e is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"sysctls\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysctls\",\n          \"description\": \"Used to configure the machine’s sysctls.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysctls.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysctls.\\u003c/p\\u003e\\n\"\n        },\n        \"sysfs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysfs\",\n          \"description\": \"Used to configure the machine’s sysfs.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysfs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysfs.\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"$ref\": \"#/$defs/v1alpha1.FeaturesConfig\",\n          \"title\": \"features\",\n          \"description\": \"Features describe individual Talos features that can be switched on or off.\\n\",\n          \"markdownDescription\": \"Features describe individual Talos features that can be switched on or off.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFeatures describe individual Talos features that can be switched on or off.\\u003c/p\\u003e\\n\"\n        },\n        \"udev\": {\n          \"$ref\": \"#/$defs/v1alpha1.UdevConfig\",\n          \"title\": \"udev\",\n          \"description\": \"Configures the udev system.\\n\",\n          \"markdownDescription\": \"Configures the udev system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the udev system.\\u003c/p\\u003e\\n\"\n        },\n        \"logging\": {\n          \"$ref\": \"#/$defs/v1alpha1.LoggingConfig\",\n          \"title\": \"logging\",\n          \"description\": \"Configures the logging system.\\n\",\n          \"markdownDescription\": \"Configures the logging system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the logging system.\\u003c/p\\u003e\\n\"\n        },\n        \"kernel\": {\n          \"$ref\": \"#/$defs/v1alpha1.KernelConfig\",\n          \"title\": \"kernel\",\n          \"description\": \"Configures the kernel.\\n\",\n          \"markdownDescription\": \"Configures the kernel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the kernel.\\u003c/p\\u003e\\n\"\n        },\n        \"seccompProfiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.MachineSeccompProfile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"seccompProfiles\",\n          \"description\": \"Configures the seccomp profiles for the machine.\\n\",\n          \"markdownDescription\": \"Configures the seccomp profiles for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the seccomp profiles for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"baseRuntimeSpecOverrides\": {\n          \"type\": \"object\",\n          \"title\": \"baseRuntimeSpecOverrides\",\n          \"description\": \"Override (patch) settings in the default OCI runtime spec for CRI containers.\\n\\nIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\\n\",\n          \"markdownDescription\": \"Override (patch) settings in the default OCI runtime spec for CRI containers.\\n\\nIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOverride (patch) settings in the default OCI runtime spec for CRI containers.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIt can be used to set some default container settings which are not configurable in Kubernetes,\\nfor example default ulimits.\\nNote: this change applies to all newly created containers, and it requires a reboot to take effect.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeLabels\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeLabels\",\n          \"description\": \"Configures the node labels for the machine.\\n\\nNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see NodeRestriction admission plugin).\\n\",\n          \"markdownDescription\": \"Configures the node labels for the machine.\\n\\nNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node labels for the machine.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: In the default Kubernetes configuration, worker nodes are restricted to set\\nlabels with some prefixes (see \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction\\\" target=\\\"_blank\\\"\\u003eNodeRestriction\\u003c/a\\u003e admission plugin).\\u003c/p\\u003e\\n\"\n        },\n        \"nodeAnnotations\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeAnnotations\",\n          \"description\": \"Configures the node annotations for the machine.\\n\",\n          \"markdownDescription\": \"Configures the node annotations for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node annotations for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeTaints\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeTaints\",\n          \"description\": \"Configures the node taints for the machine. Effect is optional.\\n\\nNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see NodeRestriction admission plugin).\\n\",\n          \"markdownDescription\": \"Configures the node taints for the machine. Effect is optional.\\n\\nNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) admission plugin).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node taints for the machine. Effect is optional.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote: In the default Kubernetes configuration, worker nodes are not allowed to\\nmodify the taints (see \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction\\\" target=\\\"_blank\\\"\\u003eNodeRestriction\\u003c/a\\u003e admission plugin).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineConfig represents the machine-specific config values.\"\n    },\n    \"v1alpha1.MachineControlPlaneConfig\": {\n      \"properties\": {\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/v1alpha1.MachineSchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler machine specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineControlPlaneConfig machine specific configuration options.\"\n    },\n    \"v1alpha1.MachineControllerManagerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-controller-manager on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-controller-manager on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-controller-manager on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineControllerManagerConfig represents the machine specific ControllerManager config values.\"\n    },\n    \"v1alpha1.MachineFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The contents of the file.\\n\",\n          \"markdownDescription\": \"The contents of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe contents of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"permissions\": {\n          \"type\": \"integer\",\n          \"title\": \"permissions\",\n          \"description\": \"The file’s permissions in octal.\\n\",\n          \"markdownDescription\": \"The file's permissions in octal.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe file\\u0026rsquo;s permissions in octal.\\u003c/p\\u003e\\n\"\n        },\n        \"path\": {\n          \"type\": \"string\",\n          \"title\": \"path\",\n          \"description\": \"The path of the file.\\n\",\n          \"markdownDescription\": \"The path of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe path of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"op\": {\n          \"enum\": [\n            \"create\",\n            \"append\",\n            \"overwrite\"\n          ],\n          \"title\": \"op\",\n          \"description\": \"The operation to use\\n\",\n          \"markdownDescription\": \"The operation to use\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe operation to use\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineFile represents a file to write to disk.\"\n    },\n    \"v1alpha1.MachineSchedulerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-scheduler on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-scheduler on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-scheduler on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineSchedulerConfig represents the machine specific Scheduler config values.\"\n    },\n    \"v1alpha1.MachineSeccompProfile\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"The name field is used to provide the file name of the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `name` field is used to provide the file name of the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003ename\\u003c/code\\u003e field is used to provide the file name of the seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"value\": {\n          \"type\": \"object\",\n          \"title\": \"value\",\n          \"description\": \"The value field is used to provide the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `value` field is used to provide the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalue\\u003c/code\\u003e field is used to provide the seccomp profile.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"MachineSeccompProfile defines seccomp profiles for the machine.\"\n    },\n    \"v1alpha1.ProxyConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-proxy deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable kube-proxy deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-proxy deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the kube-proxy manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the kube-proxy manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the kube-proxy manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"proxy mode of kube-proxy.\\nThe default is ‘iptables’.\\n\",\n          \"markdownDescription\": \"proxy mode of kube-proxy.\\nThe default is 'iptables'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eproxy mode of kube-proxy.\\nThe default is \\u0026lsquo;iptables\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to kube-proxy.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to kube-proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to kube-proxy.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ProxyConfig represents the kube proxy configuration options.\"\n    },\n    \"v1alpha1.RegistryKubernetesConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable Kubernetes discovery registry.\\n\",\n          \"markdownDescription\": \"Disable Kubernetes discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable Kubernetes discovery registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RegistryKubernetesConfig struct configures Kubernetes discovery registry.\"\n    },\n    \"v1alpha1.RegistryServiceConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable external service discovery registry.\\n\",\n          \"markdownDescription\": \"Disable external service discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable external service discovery registry.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"External service endpoint.\\n\",\n          \"markdownDescription\": \"External service endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal service endpoint.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"RegistryServiceConfig struct configures Kubernetes discovery registry.\"\n    },\n    \"v1alpha1.ResourcesConfig\": {\n      \"properties\": {\n        \"requests\": {\n          \"type\": \"object\",\n          \"title\": \"requests\",\n          \"description\": \"Requests configures the reserved cpu/memory resources.\\n\",\n          \"markdownDescription\": \"Requests configures the reserved cpu/memory resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRequests configures the reserved cpu/memory resources.\\u003c/p\\u003e\\n\"\n        },\n        \"limits\": {\n          \"type\": \"object\",\n          \"title\": \"limits\",\n          \"description\": \"Limits configures the maximum cpu/memory resources a container can use.\\n\",\n          \"markdownDescription\": \"Limits configures the maximum cpu/memory resources a container can use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLimits configures the maximum cpu/memory resources a container can use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"ResourcesConfig represents the pod resources.\"\n    },\n    \"v1alpha1.SchedulerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the scheduler manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the scheduler manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the scheduler manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"additionalProperties\": {\n            \"oneOf\": [\n              {\n                \"type\": \"string\"\n              },\n              {\n                \"items\": {\n                  \"type\": \"string\"\n                },\n                \"type\": \"array\"\n              }\n            ]\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the scheduler.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the scheduler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the scheduler.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/v1alpha1.VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the scheduler static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the scheduler static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the scheduler static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the scheduler resources.\\n\",\n          \"markdownDescription\": \"Configure the scheduler resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the scheduler resources.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specify custom kube-scheduler configuration.\\n\",\n          \"markdownDescription\": \"Specify custom kube-scheduler configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecify custom kube-scheduler configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"SchedulerConfig represents the kube scheduler configuration options.\"\n    },\n    \"v1alpha1.UdevConfig\": {\n      \"properties\": {\n        \"rules\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"rules\",\n          \"description\": \"List of udev rules to apply to the udev system\\n\",\n          \"markdownDescription\": \"List of udev rules to apply to the udev system\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of udev rules to apply to the udev system\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"UdevConfig describes how the udev system should be configured.\"\n    },\n    \"v1alpha1.VolumeMountConfig\": {\n      \"properties\": {\n        \"hostPath\": {\n          \"type\": \"string\",\n          \"title\": \"hostPath\",\n          \"description\": \"Path on the host.\\n\",\n          \"markdownDescription\": \"Path on the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath on the host.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"Path in the container.\\n\",\n          \"markdownDescription\": \"Path in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"readonly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readonly\",\n          \"description\": \"Mount the volume read only.\\n\",\n          \"markdownDescription\": \"Mount the volume read only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read only.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\",\n      \"description\": \"VolumeMountConfig struct describes extra volume mount for the static pods.\"\n    }\n  },\n  \"oneOf\": [\n    {\n      \"$ref\": \"#/$defs/block.ExistingVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.ExternalVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.RawVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.SwapVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.UserVolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.VolumeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/block.ZswapConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryAuthConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryMirrorConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/cri.RegistryTLSConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/extensions.ServiceConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/hardware.PCIDriverRebindConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BlackholeRouteConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BondConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.BridgeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DefaultActionConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DHCPv4ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DHCPv6ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.DummyLinkConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.EthernetConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.HCloudVIPConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.HostnameConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.KubeSpanConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.KubespanEndpointsConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.Layer2VIPConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.LinkConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.LinkAliasConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.ResolverConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.RoutingRuleConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.RuleConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.StaticHostConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.TCPProbeConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.TimeSyncConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.VLANConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.VRFConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/network.WireguardConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.EnvironmentV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.EventSinkV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.KmsgLogV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.OOMV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/runtime.WatchdogTimerV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/security.TrustedRootsConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/siderolink.ConfigV1Alpha1\"\n    },\n    {\n      \"$ref\": \"#/$defs/v1alpha1.Config\"\n    }\n  ]\n}"
  },
  {
    "path": "website/content/v1.13/schemas/v1alpha1_config.schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://talos.dev/v1.6/schemas/v1alpha1_config.schema.json\",\n  \"$ref\": \"#/$defs/Config\",\n  \"$defs\": {\n    \"APIServerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the API server manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the API server manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the API server manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the API server.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the API server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the API server.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the API server static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the API server static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the API server static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the API server’s certificate.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the API server's certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the API server\\u0026rsquo;s certificate.\\u003c/p\\u003e\\n\"\n        },\n        \"disablePodSecurityPolicy\": {\n          \"type\": \"boolean\",\n          \"title\": \"disablePodSecurityPolicy\",\n          \"description\": \"Disable PodSecurityPolicy in the API server and default manifests.\\n\",\n          \"markdownDescription\": \"Disable PodSecurityPolicy in the API server and default manifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable PodSecurityPolicy in the API server and default manifests.\\u003c/p\\u003e\\n\"\n        },\n        \"admissionControl\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/AdmissionPluginConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"admissionControl\",\n          \"description\": \"Configure the API server admission plugins.\\n\",\n          \"markdownDescription\": \"Configure the API server admission plugins.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server admission plugins.\\u003c/p\\u003e\\n\"\n        },\n        \"auditPolicy\": {\n          \"type\": \"object\",\n          \"title\": \"auditPolicy\",\n          \"description\": \"Configure the API server audit policy.\\n\",\n          \"markdownDescription\": \"Configure the API server audit policy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server audit policy.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the API server resources.\\n\",\n          \"markdownDescription\": \"Configure the API server resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the API server resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"AdminKubeconfigConfig\": {\n      \"properties\": {\n        \"certLifetime\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"certLifetime\",\n          \"description\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Admin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdmin kubeconfig certificate lifetime (default is 1 year).\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"AdmissionPluginConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\\n\",\n          \"markdownDescription\": \"Name is the name of the admission controller.\\nIt must match the registered admission plugin name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName is the name of the admission controller.\\nIt must match the registered admission plugin name.\\u003c/p\\u003e\\n\"\n        },\n        \"configuration\": {\n          \"type\": \"object\",\n          \"title\": \"configuration\",\n          \"description\": \"Configuration is an embedded configuration object to be used as the plugin’s\\nconfiguration.\\n\",\n          \"markdownDescription\": \"Configuration is an embedded configuration object to be used as the plugin's\\nconfiguration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfiguration is an embedded configuration object to be used as the plugin\\u0026rsquo;s\\nconfiguration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Bond\": {\n      \"properties\": {\n        \"interfaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"The interfaces that make up the bond.\\n\",\n          \"markdownDescription\": \"The interfaces that make up the bond.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interfaces that make up the bond.\\u003c/p\\u003e\\n\"\n        },\n        \"deviceSelectors\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/NetworkDeviceSelector\"\n          },\n          \"type\": \"array\",\n          \"title\": \"deviceSelectors\",\n          \"description\": \"Picks a network device using the selector.\\nMutually exclusive with interfaces.\\nSupports partial match using wildcard syntax.\\n\",\n          \"markdownDescription\": \"Picks a network device using the selector.\\nMutually exclusive with `interfaces`.\\nSupports partial match using wildcard syntax.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePicks a network device using the selector.\\nMutually exclusive with \\u003ccode\\u003einterfaces\\u003c/code\\u003e.\\nSupports partial match using wildcard syntax.\\u003c/p\\u003e\\n\"\n        },\n        \"arpIPTarget\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"arpIPTarget\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"xmitHashPolicy\": {\n          \"type\": \"string\",\n          \"title\": \"xmitHashPolicy\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"lacpRate\": {\n          \"type\": \"string\",\n          \"title\": \"lacpRate\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSystem\": {\n          \"type\": \"string\",\n          \"title\": \"adActorSystem\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\nNot supported at the moment.\\u003c/p\\u003e\\n\"\n        },\n        \"arpValidate\": {\n          \"type\": \"string\",\n          \"title\": \"arpValidate\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"arpAllTargets\": {\n          \"type\": \"string\",\n          \"title\": \"arpAllTargets\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"primary\": {\n          \"type\": \"string\",\n          \"title\": \"primary\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"primaryReselect\": {\n          \"type\": \"string\",\n          \"title\": \"primaryReselect\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"failOverMac\": {\n          \"type\": \"string\",\n          \"title\": \"failOverMac\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adSelect\": {\n          \"type\": \"string\",\n          \"title\": \"adSelect\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"miimon\": {\n          \"type\": \"integer\",\n          \"title\": \"miimon\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"updelay\": {\n          \"type\": \"integer\",\n          \"title\": \"updelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"downdelay\": {\n          \"type\": \"integer\",\n          \"title\": \"downdelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"arpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"arpInterval\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"resendIgmp\": {\n          \"type\": \"integer\",\n          \"title\": \"resendIgmp\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"minLinks\": {\n          \"type\": \"integer\",\n          \"title\": \"minLinks\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"lpInterval\": {\n          \"type\": \"integer\",\n          \"title\": \"lpInterval\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"packetsPerSlave\": {\n          \"type\": \"integer\",\n          \"title\": \"packetsPerSlave\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"numPeerNotif\": {\n          \"type\": \"integer\",\n          \"title\": \"numPeerNotif\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"tlbDynamicLb\": {\n          \"type\": \"integer\",\n          \"title\": \"tlbDynamicLb\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"allSlavesActive\": {\n          \"type\": \"integer\",\n          \"title\": \"allSlavesActive\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"useCarrier\": {\n          \"type\": \"boolean\",\n          \"title\": \"useCarrier\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adActorSysPrio\": {\n          \"type\": \"integer\",\n          \"title\": \"adActorSysPrio\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"adUserPortKey\": {\n          \"type\": \"integer\",\n          \"title\": \"adUserPortKey\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        },\n        \"peerNotifyDelay\": {\n          \"type\": \"integer\",\n          \"title\": \"peerNotifyDelay\",\n          \"description\": \"A bond option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bond option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bond option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Bridge\": {\n      \"properties\": {\n        \"interfaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"The interfaces that make up the bridge.\\n\",\n          \"markdownDescription\": \"The interfaces that make up the bridge.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interfaces that make up the bridge.\\u003c/p\\u003e\\n\"\n        },\n        \"stp\": {\n          \"$ref\": \"#/$defs/STP\",\n          \"title\": \"stp\",\n          \"description\": \"A bridge option.\\nPlease see the official kernel documentation.\\n\",\n          \"markdownDescription\": \"A bridge option.\\nPlease see the official kernel documentation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA bridge option.\\nPlease see the official kernel documentation.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"CNIConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"enum\": [\n            \"flannel\",\n            \"custom\",\n            \"none\"\n          ],\n          \"title\": \"name\",\n          \"description\": \"Name of CNI to use.\\n\",\n          \"markdownDescription\": \"Name of CNI to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of CNI to use.\\u003c/p\\u003e\\n\"\n        },\n        \"urls\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"urls\",\n          \"description\": \"URLs containing manifests to apply for the CNI.\\nShould be present for “custom”, must be empty for “flannel” and “none”.\\n\",\n          \"markdownDescription\": \"URLs containing manifests to apply for the CNI.\\nShould be present for \\\"custom\\\", must be empty for \\\"flannel\\\" and \\\"none\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eURLs containing manifests to apply for the CNI.\\nShould be present for \\u0026ldquo;custom\\u0026rdquo;, must be empty for \\u0026ldquo;flannel\\u0026rdquo; and \\u0026ldquo;none\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"flannel\": {\n          \"$ref\": \"#/$defs/FlannelCNIConfig\",\n          \"title\": \"flannel\",\n          \"description\": \"description: |\\nFlannel configuration options.\\n\",\n          \"markdownDescription\": \"description: |\\nFlannel configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003edescription: |\\nFlannel configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterConfig\": {\n      \"properties\": {\n        \"id\": {\n          \"type\": \"string\",\n          \"title\": \"id\",\n          \"description\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\\n\",\n          \"markdownDescription\": \"Globally unique identifier for this cluster (base64 encoded random 32 bytes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eGlobally unique identifier for this cluster (base64 encoded random 32 bytes).\\u003c/p\\u003e\\n\"\n        },\n        \"secret\": {\n          \"type\": \"string\",\n          \"title\": \"secret\",\n          \"description\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\n\",\n          \"markdownDescription\": \"Shared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eShared secret of cluster (base64 encoded random 32 bytes).\\nThis secret is shared among cluster members but should never be sent over the network.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/ControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides control plane specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides control plane specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides control plane specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterName\": {\n          \"type\": \"string\",\n          \"title\": \"clusterName\",\n          \"description\": \"Configures the cluster’s name.\\n\",\n          \"markdownDescription\": \"Configures the cluster's name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the cluster\\u0026rsquo;s name.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/ClusterNetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides cluster specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The bootstrap token used to join the cluster.\\n\",\n          \"markdownDescription\": \"The [bootstrap token](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/) used to join the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ca href=\\\"https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/\\\" target=\\\"_blank\\\"\\u003ebootstrap token\\u003c/a\\u003e used to join the cluster.\\u003c/p\\u003e\\n\"\n        },\n        \"aescbcEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"aescbcEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"secretboxEncryptionSecret\": {\n          \"type\": \"string\",\n          \"title\": \"secretboxEncryptionSecret\",\n          \"description\": \"A key used for the encryption of secret data at rest.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\n\",\n          \"markdownDescription\": \"A key used for the [encryption of secret data at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/).\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA key used for the \\u003ca href=\\\"https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/\\\" target=\\\"_blank\\\"\\u003eencryption of secret data at rest\\u003c/a\\u003e.\\nEnables encryption with secretbox.\\nSecretbox has precedence over AESCBC.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The base64 encoded root certificate authority used by Kubernetes.\\n\",\n          \"markdownDescription\": \"The base64 encoded root certificate authority used by Kubernetes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded root certificate authority used by Kubernetes.\\u003c/p\\u003e\\n\"\n        },\n        \"aggregatorCA\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"aggregatorCA\",\n          \"description\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\\n\",\n          \"markdownDescription\": \"The base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\n\\nThis CA can be self-signed.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded aggregator certificate authority used by Kubernetes for front-proxy certificate generation.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis CA can be self-signed.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceAccount\": {\n          \"properties\": {\n            \"key\": {\n              \"additionalProperties\": false,\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"serviceAccount\",\n          \"description\": \"The base64 encoded private key for service account token generation.\\n\",\n          \"markdownDescription\": \"The base64 encoded private key for service account token generation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe base64 encoded private key for service account token generation.\\u003c/p\\u003e\\n\"\n        },\n        \"apiServer\": {\n          \"$ref\": \"#/$defs/APIServerConfig\",\n          \"title\": \"apiServer\",\n          \"description\": \"API server specific configuration options.\\n\",\n          \"markdownDescription\": \"API server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAPI server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/ControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager server specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"proxy\": {\n          \"$ref\": \"#/$defs/ProxyConfig\",\n          \"title\": \"proxy\",\n          \"description\": \"Kube-proxy server-specific configuration options\\n\",\n          \"markdownDescription\": \"Kube-proxy server-specific configuration options\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKube-proxy server-specific configuration options\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/SchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler server specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler server specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler server specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"discovery\": {\n          \"$ref\": \"#/$defs/ClusterDiscoveryConfig\",\n          \"title\": \"discovery\",\n          \"description\": \"Configures cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configures cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures cluster member discovery.\\u003c/p\\u003e\\n\"\n        },\n        \"etcd\": {\n          \"$ref\": \"#/$defs/EtcdConfig\",\n          \"title\": \"etcd\",\n          \"description\": \"Etcd specific configuration options.\\n\",\n          \"markdownDescription\": \"Etcd specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEtcd specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"coreDNS\": {\n          \"$ref\": \"#/$defs/CoreDNS\",\n          \"title\": \"coreDNS\",\n          \"description\": \"Core DNS specific configuration options.\\n\",\n          \"markdownDescription\": \"Core DNS specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCore DNS specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"externalCloudProvider\": {\n          \"$ref\": \"#/$defs/ExternalCloudProviderConfig\",\n          \"title\": \"externalCloudProvider\",\n          \"description\": \"External cloud provider configuration.\\n\",\n          \"markdownDescription\": \"External cloud provider configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal cloud provider configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraManifests\",\n          \"description\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"extraManifestHeaders\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraManifestHeaders\",\n          \"description\": \"A map of key value pairs that will be added while fetching the extraManifests.\\n\",\n          \"markdownDescription\": \"A map of key value pairs that will be added while fetching the extraManifests.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA map of key value pairs that will be added while fetching the extraManifests.\\u003c/p\\u003e\\n\"\n        },\n        \"inlineManifests\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ClusterInlineManifest\"\n          },\n          \"type\": \"array\",\n          \"title\": \"inlineManifests\",\n          \"description\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of inline Kubernetes manifests.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"adminKubeconfig\": {\n          \"$ref\": \"#/$defs/AdminKubeconfigConfig\",\n          \"title\": \"adminKubeconfig\",\n          \"description\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\n\",\n          \"markdownDescription\": \"Settings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSettings for admin kubeconfig generation.\\nCertificate lifetime can be configured.\\u003c/p\\u003e\\n\"\n        },\n        \"allowSchedulingOnControlPlanes\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowSchedulingOnControlPlanes\",\n          \"description\": \"Allows running workload on control-plane nodes.\\n\",\n          \"markdownDescription\": \"Allows running workload on control-plane nodes.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows running workload on control-plane nodes.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterDiscoveryConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\n\",\n          \"markdownDescription\": \"Enable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the cluster membership discovery feature.\\nCluster discovery is based on individual registries which are configured under the registries field.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/DiscoveryRegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Configure registries used for cluster member discovery.\\n\",\n          \"markdownDescription\": \"Configure registries used for cluster member discovery.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure registries used for cluster member discovery.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterInlineManifest\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Name of the manifest.\\nName should be unique.\\n\",\n          \"markdownDescription\": \"Name of the manifest.\\nName should be unique.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eName of the manifest.\\nName should be unique.\\u003c/p\\u003e\\n\"\n        },\n        \"contents\": {\n          \"type\": \"string\",\n          \"title\": \"contents\",\n          \"description\": \"Manifest contents as a string.\\n\",\n          \"markdownDescription\": \"Manifest contents as a string.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eManifest contents as a string.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ClusterNetworkConfig\": {\n      \"properties\": {\n        \"cni\": {\n          \"$ref\": \"#/$defs/CNIConfig\",\n          \"title\": \"cni\",\n          \"description\": \"The CNI used.\\nComposed of “name” and “urls”.\\nThe “name” key supports the following options: “flannel”, “custom”, and “none”.\\n“flannel” uses Talos-managed Flannel CNI, and that’s the default option.\\n“custom” uses custom manifests that should be provided in “urls”.\\n“none” indicates that Talos will not manage any CNI installation.\\n\",\n          \"markdownDescription\": \"The CNI used.\\nComposed of \\\"name\\\" and \\\"urls\\\".\\nThe \\\"name\\\" key supports the following options: \\\"flannel\\\", \\\"custom\\\", and \\\"none\\\".\\n\\\"flannel\\\" uses Talos-managed Flannel CNI, and that's the default option.\\n\\\"custom\\\" uses custom manifests that should be provided in \\\"urls\\\".\\n\\\"none\\\" indicates that Talos will not manage any CNI installation.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe CNI used.\\nComposed of \\u0026ldquo;name\\u0026rdquo; and \\u0026ldquo;urls\\u0026rdquo;.\\nThe \\u0026ldquo;name\\u0026rdquo; key supports the following options: \\u0026ldquo;flannel\\u0026rdquo;, \\u0026ldquo;custom\\u0026rdquo;, and \\u0026ldquo;none\\u0026rdquo;.\\n\\u0026ldquo;flannel\\u0026rdquo; uses Talos-managed Flannel CNI, and that\\u0026rsquo;s the default option.\\n\\u0026ldquo;custom\\u0026rdquo; uses custom manifests that should be provided in \\u0026ldquo;urls\\u0026rdquo;.\\n\\u0026ldquo;none\\u0026rdquo; indicates that Talos will not manage any CNI installation.\\u003c/p\\u003e\\n\"\n        },\n        \"dnsDomain\": {\n          \"type\": \"string\",\n          \"title\": \"dnsDomain\",\n          \"description\": \"The domain used by Kubernetes DNS.\\nThe default is cluster.local\\n\",\n          \"markdownDescription\": \"The domain used by Kubernetes DNS.\\nThe default is `cluster.local`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe domain used by Kubernetes DNS.\\nThe default is \\u003ccode\\u003ecluster.local\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"podSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"podSubnets\",\n          \"description\": \"The pod subnet CIDR.\\n\",\n          \"markdownDescription\": \"The pod subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe pod subnet CIDR.\\u003c/p\\u003e\\n\"\n        },\n        \"serviceSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"serviceSubnets\",\n          \"description\": \"The service subnet CIDR.\\n\",\n          \"markdownDescription\": \"The service subnet CIDR.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe service subnet CIDR.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Config\": {\n      \"properties\": {\n        \"version\": {\n          \"enum\": [\n            \"v1alpha1\"\n          ],\n          \"title\": \"version\",\n          \"description\": \"Indicates the schema used to decode the contents.\\n\",\n          \"markdownDescription\": \"Indicates the schema used to decode the contents.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates the schema used to decode the contents.\\u003c/p\\u003e\\n\"\n        },\n        \"debug\": {\n          \"type\": \"boolean\",\n          \"title\": \"debug\",\n          \"description\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\nNote: To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\n\",\n          \"markdownDescription\": \"Enable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\n\\n**Note:** To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable verbose logging to the console.\\nAll system containers logs will flow into serial console.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eNote:\\u003c/strong\\u003e To avoid breaking Talos bootstrap flow enable this option only if serial console can handle high message throughput.\\u003c/p\\u003e\\n\"\n        },\n        \"machine\": {\n          \"$ref\": \"#/$defs/MachineConfig\",\n          \"title\": \"machine\",\n          \"description\": \"Provides machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"cluster\": {\n          \"$ref\": \"#/$defs/ClusterConfig\",\n          \"title\": \"cluster\",\n          \"description\": \"Provides cluster specific configuration options.\\n\",\n          \"markdownDescription\": \"Provides cluster specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides cluster specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ControlPlaneConfig\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"pattern\": \"^https://\",\n          \"format\": \"uri\",\n          \"title\": \"endpoint\",\n          \"description\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\n\",\n          \"markdownDescription\": \"Endpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEndpoint is the canonical controlplane endpoint, which can be an IP address or a DNS hostname.\\nIt is single-valued, and may optionally include a port number.\\u003c/p\\u003e\\n\"\n        },\n        \"localAPIServerPort\": {\n          \"type\": \"integer\",\n          \"title\": \"localAPIServerPort\",\n          \"description\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is 6443.\\n\",\n          \"markdownDescription\": \"The port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is `6443`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe port that the API server listens on internally.\\nThis may be different than the port portion listed in the endpoint field above.\\nThe default is \\u003ccode\\u003e6443\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ControllerManagerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the controller manager manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the controller manager manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the controller manager manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the controller manager.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the controller manager.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the controller manager.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the controller manager static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the controller manager static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the controller manager static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the controller manager resources.\\n\",\n          \"markdownDescription\": \"Configure the controller manager resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the controller manager resources.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"CoreDNS\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable coredns deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable coredns deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable coredns deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an override to the default coredns image.\\n\",\n          \"markdownDescription\": \"The `image` field is an override to the default coredns image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an override to the default coredns image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DHCPOptions\": {\n      \"properties\": {\n        \"routeMetric\": {\n          \"type\": \"integer\",\n          \"title\": \"routeMetric\",\n          \"description\": \"The priority of all routes received via DHCP.\\n\",\n          \"markdownDescription\": \"The priority of all routes received via DHCP.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe priority of all routes received via DHCP.\\u003c/p\\u003e\\n\"\n        },\n        \"ipv4\": {\n          \"type\": \"boolean\",\n          \"title\": \"ipv4\",\n          \"description\": \"Enables DHCPv4 protocol for the interface (default is enabled).\\n\",\n          \"markdownDescription\": \"Enables DHCPv4 protocol for the interface (default is enabled).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables DHCPv4 protocol for the interface (default is enabled).\\u003c/p\\u003e\\n\"\n        },\n        \"ipv6\": {\n          \"type\": \"boolean\",\n          \"title\": \"ipv6\",\n          \"description\": \"Enables DHCPv6 protocol for the interface (default is disabled).\\n\",\n          \"markdownDescription\": \"Enables DHCPv6 protocol for the interface (default is disabled).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnables DHCPv6 protocol for the interface (default is disabled).\\u003c/p\\u003e\\n\"\n        },\n        \"duidv6\": {\n          \"type\": \"string\",\n          \"title\": \"duidv6\",\n          \"description\": \"Set client DUID (hex string).\\n\",\n          \"markdownDescription\": \"Set client DUID (hex string).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSet client DUID (hex string).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Device\": {\n      \"properties\": {\n        \"interface\": {\n          \"type\": \"string\",\n          \"title\": \"interface\",\n          \"description\": \"The interface name.\\nMutually exclusive with deviceSelector.\\n\",\n          \"markdownDescription\": \"The interface name.\\nMutually exclusive with `deviceSelector`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interface name.\\nMutually exclusive with \\u003ccode\\u003edeviceSelector\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"deviceSelector\": {\n          \"$ref\": \"#/$defs/NetworkDeviceSelector\",\n          \"title\": \"deviceSelector\",\n          \"description\": \"Picks a network device using the selector.\\nMutually exclusive with interface.\\nSupports partial match using wildcard syntax.\\n\",\n          \"markdownDescription\": \"Picks a network device using the selector.\\nMutually exclusive with `interface`.\\nSupports partial match using wildcard syntax.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePicks a network device using the selector.\\nMutually exclusive with \\u003ccode\\u003einterface\\u003c/code\\u003e.\\nSupports partial match using wildcard syntax.\\u003c/p\\u003e\\n\"\n        },\n        \"addresses\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"Assigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\\n\",\n          \"markdownDescription\": \"Assigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAssigns static IP addresses to the interface.\\nAn address can be specified either in proper CIDR notation or as a standalone address (netmask of all ones is assumed).\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Route\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"A list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\\n\",\n          \"markdownDescription\": \"A list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of routes associated with the interface.\\nIf used in combination with DHCP, these routes will be appended to routes returned by DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"bond\": {\n          \"$ref\": \"#/$defs/Bond\",\n          \"title\": \"bond\",\n          \"description\": \"Bond specific options.\\n\",\n          \"markdownDescription\": \"Bond specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBond specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"bridge\": {\n          \"$ref\": \"#/$defs/Bridge\",\n          \"title\": \"bridge\",\n          \"description\": \"Bridge specific options.\\n\",\n          \"markdownDescription\": \"Bridge specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eBridge specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"vlans\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Vlan\"\n          },\n          \"type\": \"array\",\n          \"title\": \"vlans\",\n          \"description\": \"VLAN specific options.\\n\",\n          \"markdownDescription\": \"VLAN specific options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVLAN specific options.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The interface’s MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\\n\",\n          \"markdownDescription\": \"The interface's MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe interface\\u0026rsquo;s MTU.\\nIf used in combination with DHCP, this will override any MTU settings returned from DHCP server.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcp\": {\n          \"type\": \"boolean\",\n          \"title\": \"dhcp\",\n          \"description\": \"Indicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\n\\n\\nOptionClasslessStaticRoute\\nOptionDomainNameServer\\nOptionDNSDomainSearchList\\nOptionHostName\\n\\n\",\n          \"markdownDescription\": \"Indicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\n\\n- `OptionClasslessStaticRoute`\\n- `OptionDomainNameServer`\\n- `OptionDNSDomainSearchList`\\n- `OptionHostName`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if DHCP should be used to configure the interface.\\nThe following DHCP options are supported:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionClasslessStaticRoute\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionDomainNameServer\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionDNSDomainSearchList\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003eOptionHostName\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"ignore\": {\n          \"type\": \"boolean\",\n          \"title\": \"ignore\",\n          \"description\": \"Indicates if the interface should be ignored (skips configuration).\\n\",\n          \"markdownDescription\": \"Indicates if the interface should be ignored (skips configuration).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the interface should be ignored (skips configuration).\\u003c/p\\u003e\\n\"\n        },\n        \"dummy\": {\n          \"type\": \"boolean\",\n          \"title\": \"dummy\",\n          \"description\": \"Indicates if the interface is a dummy interface.\\ndummy is used to specify that this interface should be a virtual-only, dummy interface.\\n\",\n          \"markdownDescription\": \"Indicates if the interface is a dummy interface.\\n`dummy` is used to specify that this interface should be a virtual-only, dummy interface.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the interface is a dummy interface.\\n\\u003ccode\\u003edummy\\u003c/code\\u003e is used to specify that this interface should be a virtual-only, dummy interface.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcpOptions\": {\n          \"$ref\": \"#/$defs/DHCPOptions\",\n          \"title\": \"dhcpOptions\",\n          \"description\": \"DHCP specific options.\\ndhcp must be set to true for these to take effect.\\n\",\n          \"markdownDescription\": \"DHCP specific options.\\n`dhcp` *must* be set to true for these to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDHCP specific options.\\n\\u003ccode\\u003edhcp\\u003c/code\\u003e \\u003cem\\u003emust\\u003c/em\\u003e be set to true for these to take effect.\\u003c/p\\u003e\\n\"\n        },\n        \"wireguard\": {\n          \"$ref\": \"#/$defs/DeviceWireguardConfig\",\n          \"title\": \"wireguard\",\n          \"description\": \"Wireguard specific configuration.\\nIncludes things like private key, listen port, peers.\\n\",\n          \"markdownDescription\": \"Wireguard specific configuration.\\nIncludes things like private key, listen port, peers.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWireguard specific configuration.\\nIncludes things like private key, listen port, peers.\\u003c/p\\u003e\\n\"\n        },\n        \"vip\": {\n          \"$ref\": \"#/$defs/DeviceVIPConfig\",\n          \"title\": \"vip\",\n          \"description\": \"Virtual (shared) IP address configuration.\\n\",\n          \"markdownDescription\": \"Virtual (shared) IP address configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eVirtual (shared) IP address configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceVIPConfig\": {\n      \"properties\": {\n        \"ip\": {\n          \"type\": \"string\",\n          \"title\": \"ip\",\n          \"description\": \"Specifies the IP address to be used.\\n\",\n          \"markdownDescription\": \"Specifies the IP address to be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the IP address to be used.\\u003c/p\\u003e\\n\"\n        },\n        \"equinixMetal\": {\n          \"$ref\": \"#/$defs/VIPEquinixMetalConfig\",\n          \"title\": \"equinixMetal\",\n          \"description\": \"Specifies the Equinix Metal API settings to assign VIP to the node.\\n\",\n          \"markdownDescription\": \"Specifies the Equinix Metal API settings to assign VIP to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Equinix Metal API settings to assign VIP to the node.\\u003c/p\\u003e\\n\"\n        },\n        \"hcloud\": {\n          \"$ref\": \"#/$defs/VIPHCloudConfig\",\n          \"title\": \"hcloud\",\n          \"description\": \"Specifies the Hetzner Cloud API settings to assign VIP to the node.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API settings to assign VIP to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API settings to assign VIP to the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceWireguardConfig\": {\n      \"properties\": {\n        \"privateKey\": {\n          \"type\": \"string\",\n          \"title\": \"privateKey\",\n          \"description\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by wg genkey.\\n\",\n          \"markdownDescription\": \"Specifies a private key configuration (base64 encoded).\\nCan be generated by `wg genkey`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a private key configuration (base64 encoded).\\nCan be generated by \\u003ccode\\u003ewg genkey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"listenPort\": {\n          \"type\": \"integer\",\n          \"title\": \"listenPort\",\n          \"description\": \"Specifies a device’s listening port.\\n\",\n          \"markdownDescription\": \"Specifies a device's listening port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s listening port.\\u003c/p\\u003e\\n\"\n        },\n        \"firewallMark\": {\n          \"type\": \"integer\",\n          \"title\": \"firewallMark\",\n          \"description\": \"Specifies a device’s firewall mark.\\n\",\n          \"markdownDescription\": \"Specifies a device's firewall mark.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a device\\u0026rsquo;s firewall mark.\\u003c/p\\u003e\\n\"\n        },\n        \"peers\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/DeviceWireguardPeer\"\n          },\n          \"type\": \"array\",\n          \"title\": \"peers\",\n          \"description\": \"Specifies a list of peer configurations to apply to a device.\\n\",\n          \"markdownDescription\": \"Specifies a list of peer configurations to apply to a device.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies a list of peer configurations to apply to a device.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DeviceWireguardPeer\": {\n      \"properties\": {\n        \"publicKey\": {\n          \"type\": \"string\",\n          \"title\": \"publicKey\",\n          \"description\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running wg pubkey \\u0026lt; private.key \\u0026gt; public.key \\u0026amp;\\u0026amp; cat public.key.\\n\",\n          \"markdownDescription\": \"Specifies the public key of this peer.\\nCan be extracted from private key by running `wg pubkey \\u003c private.key \\u003e public.key \\u0026\\u0026 cat public.key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the public key of this peer.\\nCan be extracted from private key by running \\u003ccode\\u003ewg pubkey \\u0026lt; private.key \\u0026gt; public.key \\u0026amp;\\u0026amp; cat public.key\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"Specifies the endpoint of this peer entry.\\n\",\n          \"markdownDescription\": \"Specifies the endpoint of this peer entry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the endpoint of this peer entry.\\u003c/p\\u003e\\n\"\n        },\n        \"persistentKeepaliveInterval\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"persistentKeepaliveInterval\",\n          \"description\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (‘1h’ for one hour, ‘10m’ for ten minutes).\\n\",\n          \"markdownDescription\": \"Specifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format ('1h' for one hour, '10m' for ten minutes).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the persistent keepalive interval for this peer.\\nField format accepts any Go time.Duration format (\\u0026lsquo;1h\\u0026rsquo; for one hour, \\u0026lsquo;10m\\u0026rsquo; for ten minutes).\\u003c/p\\u003e\\n\"\n        },\n        \"allowedIPs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedIPs\",\n          \"description\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\n\",\n          \"markdownDescription\": \"AllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllowedIPs specifies a list of allowed IP addresses in CIDR notation for this peer.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DiscoveryRegistriesConfig\": {\n      \"properties\": {\n        \"kubernetes\": {\n          \"$ref\": \"#/$defs/RegistryKubernetesConfig\",\n          \"title\": \"kubernetes\",\n          \"description\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\n\",\n          \"markdownDescription\": \"Kubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubernetes registry uses Kubernetes API server to discover cluster members and stores additional information\\nas annotations on the Node resources.\\u003c/p\\u003e\\n\"\n        },\n        \"service\": {\n          \"$ref\": \"#/$defs/RegistryServiceConfig\",\n          \"title\": \"service\",\n          \"description\": \"Service registry is using an external service to push and pull information about cluster members.\\n\",\n          \"markdownDescription\": \"Service registry is using an external service to push and pull information about cluster members.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eService registry is using an external service to push and pull information about cluster members.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"DiskPartition\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"The size of partition: either bytes or human readable representation. If size: is omitted, the partition is sized to occupy the full disk.\\n\",\n          \"markdownDescription\": \"The size of partition: either bytes or human readable representation. If `size:` is omitted, the partition is sized to occupy the full disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe size of partition: either bytes or human readable representation. If \\u003ccode\\u003esize:\\u003c/code\\u003e is omitted, the partition is sized to occupy the full disk.\\u003c/p\\u003e\\n\"\n        },\n        \"mountpoint\": {\n          \"type\": \"string\",\n          \"title\": \"mountpoint\",\n          \"description\": \"Where to mount the partition.\\n\",\n          \"markdownDescription\": \"Where to mount the partition.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to mount the partition.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionConfig\": {\n      \"properties\": {\n        \"provider\": {\n          \"type\": \"string\",\n          \"title\": \"provider\",\n          \"description\": \"Encryption provider to use for the encryption.\\n\",\n          \"markdownDescription\": \"Encryption provider to use for the encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEncryption provider to use for the encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"keys\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/EncryptionKey\"\n          },\n          \"type\": \"array\",\n          \"title\": \"keys\",\n          \"description\": \"Defines the encryption keys generation and storage method.\\n\",\n          \"markdownDescription\": \"Defines the encryption keys generation and storage method.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption keys generation and storage method.\\u003c/p\\u003e\\n\"\n        },\n        \"cipher\": {\n          \"enum\": [\n            \"aes-xts-plain64\",\n            \"xchacha12,aes-adiantum-plain64\",\n            \"xchacha20,aes-adiantum-plain64\"\n          ],\n          \"title\": \"cipher\",\n          \"description\": \"Cipher kind to use for the encryption. Depends on the encryption provider.\\n\",\n          \"markdownDescription\": \"Cipher kind to use for the encryption. Depends on the encryption provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCipher kind to use for the encryption. Depends on the encryption provider.\\u003c/p\\u003e\\n\"\n        },\n        \"keySize\": {\n          \"type\": \"integer\",\n          \"title\": \"keySize\",\n          \"description\": \"Defines the encryption key length.\\n\",\n          \"markdownDescription\": \"Defines the encryption key length.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption key length.\\u003c/p\\u003e\\n\"\n        },\n        \"blockSize\": {\n          \"type\": \"integer\",\n          \"title\": \"blockSize\",\n          \"description\": \"Defines the encryption sector size.\\n\",\n          \"markdownDescription\": \"Defines the encryption sector size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the encryption sector size.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"enum\": [\n            \"no_read_workqueue\",\n            \"no_write_workqueue\",\n            \"same_cpu_crypt\"\n          ],\n          \"title\": \"options\",\n          \"description\": \"Additional –perf parameters for the LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Additional --perf parameters for the LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAdditional \\u0026ndash;perf parameters for the LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKey\": {\n      \"properties\": {\n        \"static\": {\n          \"$ref\": \"#/$defs/EncryptionKeyStatic\",\n          \"title\": \"static\",\n          \"description\": \"Key which value is stored in the configuration file.\\n\",\n          \"markdownDescription\": \"Key which value is stored in the configuration file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey which value is stored in the configuration file.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeID\": {\n          \"$ref\": \"#/$defs/EncryptionKeyNodeID\",\n          \"title\": \"nodeID\",\n          \"description\": \"Deterministically generated key from the node UUID and PartitionLabel.\\n\",\n          \"markdownDescription\": \"Deterministically generated key from the node UUID and PartitionLabel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDeterministically generated key from the node UUID and PartitionLabel.\\u003c/p\\u003e\\n\"\n        },\n        \"kms\": {\n          \"$ref\": \"#/$defs/EncryptionKeyKMS\",\n          \"title\": \"kms\",\n          \"description\": \"KMS managed encryption key.\\n\",\n          \"markdownDescription\": \"KMS managed encryption key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS managed encryption key.\\u003c/p\\u003e\\n\"\n        },\n        \"slot\": {\n          \"type\": \"integer\",\n          \"title\": \"slot\",\n          \"description\": \"Key slot number for LUKS2 encryption.\\n\",\n          \"markdownDescription\": \"Key slot number for LUKS2 encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKey slot number for LUKS2 encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"tpm\": {\n          \"$ref\": \"#/$defs/EncryptionKeyTPM\",\n          \"title\": \"tpm\",\n          \"description\": \"Enable TPM based disk encryption.\\n\",\n          \"markdownDescription\": \"Enable TPM based disk encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable TPM based disk encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyKMS\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"KMS endpoint to Seal/Unseal the key.\\n\",\n          \"markdownDescription\": \"KMS endpoint to Seal/Unseal the key.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKMS endpoint to Seal/Unseal the key.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyNodeID\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyStatic\": {\n      \"properties\": {\n        \"passphrase\": {\n          \"type\": \"string\",\n          \"title\": \"passphrase\",\n          \"description\": \"Defines the static passphrase value.\\n\",\n          \"markdownDescription\": \"Defines the static passphrase value.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the static passphrase value.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EncryptionKeyTPM\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Endpoint\": {\n      \"properties\": {},\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"EtcdConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used to create the etcd service.\\n\",\n          \"markdownDescription\": \"The container image used to create the etcd service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used to create the etcd service.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The ca is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The `ca` is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eca\\u003c/code\\u003e is the root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n\\nname\\ndata-dir\\ninitial-cluster-state\\nlisten-peer-urls\\nlisten-client-urls\\ncert-file\\nkey-file\\ntrusted-ca-file\\npeer-client-cert-auth\\npeer-cert-file\\npeer-trusted-ca-file\\npeer-key-file\\n\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to etcd.\\nNote that the following args are not allowed:\\n\\n- `name`\\n- `data-dir`\\n- `initial-cluster-state`\\n- `listen-peer-urls`\\n- `listen-client-urls`\\n- `cert-file`\\n- `key-file`\\n- `trusted-ca-file`\\n- `peer-client-cert-auth`\\n- `peer-cert-file`\\n- `peer-trusted-ca-file`\\n- `peer-key-file`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to etcd.\\nNote that the following args are not allowed:\\u003c/p\\u003e\\n\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ename\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003edata-dir\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003einitial-cluster-state\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-peer-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003elisten-client-urls\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ecert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003ekey-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003etrusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-client-cert-auth\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-cert-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-trusted-ca-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ccode\\u003epeer-key-file\\u003c/code\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\"\n        },\n        \"advertisedSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"advertisedSubnets\",\n          \"description\": \"The advertisedSubnets field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `advertisedSubnets` field configures the networks to pick etcd advertised IP from.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e field configures the networks to pick etcd advertised IP from.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        },\n        \"listenSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"listenSubnets\",\n          \"description\": \"The listenSubnets field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf listenSubnets is not set, but advertisedSubnets is set, listenSubnets defaults to\\nadvertisedSubnets.\\n\\nIf neither advertisedSubnets nor listenSubnets is set, listenSubnets defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\n\",\n          \"markdownDescription\": \"The `listenSubnets` field configures the networks for the etcd to listen for peer and client connections.\\n\\nIf `listenSubnets` is not set, but `advertisedSubnets` is set, `listenSubnets` defaults to\\n`advertisedSubnets`.\\n\\nIf neither `advertisedSubnets` nor `listenSubnets` is set, `listenSubnets` defaults to listen on all addresses.\\n\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e field configures the networks for the etcd to listen for peer and client connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is not set, but \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to\\n\\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIf neither \\u003ccode\\u003eadvertisedSubnets\\u003c/code\\u003e nor \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e is set, \\u003ccode\\u003elistenSubnets\\u003c/code\\u003e defaults to listen on all addresses.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, advertised IP is selected as the first routable address of the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExternalCloudProviderConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable external cloud provider.\\n\",\n          \"markdownDescription\": \"Enable external cloud provider.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable external cloud provider.\\u003c/p\\u003e\\n\"\n        },\n        \"manifests\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"manifests\",\n          \"description\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\n\",\n          \"markdownDescription\": \"A list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of urls that point to additional manifests for an external cloud provider.\\nThese will get automatically deployed as part of the bootstrap.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExtraHost\": {\n      \"properties\": {\n        \"ip\": {\n          \"type\": \"string\",\n          \"title\": \"ip\",\n          \"description\": \"The IP of the host.\\n\",\n          \"markdownDescription\": \"The IP of the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe IP of the host.\\u003c/p\\u003e\\n\"\n        },\n        \"aliases\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"aliases\",\n          \"description\": \"The host alias.\\n\",\n          \"markdownDescription\": \"The host alias.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe host alias.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ExtraMount\": {\n      \"properties\": {\n        \"destination\": {\n          \"type\": \"string\",\n          \"title\": \"destination\",\n          \"description\": \"Destination is the absolute path where the mount will be placed in the container.\\n\",\n          \"markdownDescription\": \"Destination is the absolute path where the mount will be placed in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDestination is the absolute path where the mount will be placed in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"type\",\n          \"description\": \"Type specifies the mount kind.\\n\",\n          \"markdownDescription\": \"Type specifies the mount kind.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eType specifies the mount kind.\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"Source specifies the source path of the mount.\\n\",\n          \"markdownDescription\": \"Source specifies the source path of the mount.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSource specifies the source path of the mount.\\u003c/p\\u003e\\n\"\n        },\n        \"options\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"options\",\n          \"description\": \"Options are fstab style mount options.\\n\",\n          \"markdownDescription\": \"Options are fstab style mount options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptions are fstab style mount options.\\u003c/p\\u003e\\n\"\n        },\n        \"uidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"uidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        },\n        \"gidMappings\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LinuxIDMapping\"\n          },\n          \"type\": \"array\",\n          \"title\": \"gidMappings\",\n          \"description\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\\n\",\n          \"markdownDescription\": \"UID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\n\\nEvery mount point could have its own mapping.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUID/GID mappings used for changing file owners w/o calling chown, fs should support it.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEvery mount point could have its own mapping.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"FeaturesConfig\": {\n      \"properties\": {\n        \"rbac\": {\n          \"type\": \"boolean\",\n          \"title\": \"rbac\",\n          \"description\": \"Enable role-based access control (RBAC).\\n\",\n          \"markdownDescription\": \"Enable role-based access control (RBAC).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable role-based access control (RBAC).\\u003c/p\\u003e\\n\"\n        },\n        \"stableHostname\": {\n          \"type\": \"boolean\",\n          \"title\": \"stableHostname\",\n          \"description\": \"Enable stable default hostname.\\n\",\n          \"markdownDescription\": \"Enable stable default hostname.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable stable default hostname.\\u003c/p\\u003e\\n\"\n        },\n        \"kubernetesTalosAPIAccess\": {\n          \"$ref\": \"#/$defs/KubernetesTalosAPIAccessConfig\",\n          \"title\": \"kubernetesTalosAPIAccess\",\n          \"description\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\\n\",\n          \"markdownDescription\": \"Configure Talos API access from Kubernetes pods.\\n\\nThis feature is disabled if the feature config is not specified.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis feature is disabled if the feature config is not specified.\\u003c/p\\u003e\\n\"\n        },\n        \"apidCheckExtKeyUsage\": {\n          \"type\": \"boolean\",\n          \"title\": \"apidCheckExtKeyUsage\",\n          \"description\": \"Enable checks for extended key usage of client certificates in apid.\\n\",\n          \"markdownDescription\": \"Enable checks for extended key usage of client certificates in apid.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable checks for extended key usage of client certificates in apid.\\u003c/p\\u003e\\n\"\n        },\n        \"diskQuotaSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"diskQuotaSupport\",\n          \"description\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\n\",\n          \"markdownDescription\": \"Enable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable XFS project quota support for EPHEMERAL partition and user disks.\\nAlso enables kubelet tracking of ephemeral disk usage in the kubelet via quota.\\u003c/p\\u003e\\n\"\n        },\n        \"kubePrism\": {\n          \"$ref\": \"#/$defs/KubePrism\",\n          \"title\": \"kubePrism\",\n          \"description\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\n\",\n          \"markdownDescription\": \"KubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism - local proxy/load balancer on defined port that will distribute\\nrequests to all API servers in the cluster.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"FlannelCNIConfig\": {\n      \"properties\": {\n        \"extraArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments for ‘flanneld’.\\n\",\n          \"markdownDescription\": \"Extra arguments for 'flanneld'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments for \\u0026lsquo;flanneld\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallConfig\": {\n      \"properties\": {\n        \"disk\": {\n          \"type\": \"string\",\n          \"title\": \"disk\",\n          \"description\": \"The disk used for installations.\\n\",\n          \"markdownDescription\": \"The disk used for installations.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe disk used for installations.\\u003c/p\\u003e\\n\"\n        },\n        \"diskSelector\": {\n          \"$ref\": \"#/$defs/InstallDiskSelector\",\n          \"title\": \"diskSelector\",\n          \"description\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over disk.\\n\",\n          \"markdownDescription\": \"Look up disk using disk attributes like model, size, serial and others.\\nAlways has priority over `disk`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLook up disk using disk attributes like model, size, serial and others.\\nAlways has priority over \\u003ccode\\u003edisk\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraKernelArgs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraKernelArgs\",\n          \"description\": \"Allows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a -.\\nFor example -console removes all console=\\u0026lt;value\\u0026gt; arguments, whereas -console=tty0 removes the console=tty0 default argument.\\n\",\n          \"markdownDescription\": \"Allows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a `-`.\\nFor example `-console` removes all `console=\\u003cvalue\\u003e` arguments, whereas `-console=tty0` removes the `console=tty0` default argument.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying extra kernel args via the bootloader.\\nExisting kernel args can be removed by prefixing the argument with a \\u003ccode\\u003e-\\u003c/code\\u003e.\\nFor example \\u003ccode\\u003e-console\\u003c/code\\u003e removes all \\u003ccode\\u003econsole=\\u0026lt;value\\u0026gt;\\u003c/code\\u003e arguments, whereas \\u003ccode\\u003e-console=tty0\\u003c/code\\u003e removes the \\u003ccode\\u003econsole=tty0\\u003c/code\\u003e default argument.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\nGitHub releases page.\\n\",\n          \"markdownDescription\": \"Allows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n[GitHub releases page](https://github.com/siderolabs/talos/releases).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying the image used to perform the installation.\\nImage reference for each Talos release can be found on\\n\\u003ca href=\\\"https://github.com/siderolabs/talos/releases\\\" target=\\\"_blank\\\"\\u003eGitHub releases page\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extensions\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/InstallExtensionConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extensions\",\n          \"description\": \"Allows for supplying additional system extension images to install on top of base Talos image.\\n\",\n          \"markdownDescription\": \"Allows for supplying additional system extension images to install on top of base Talos image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for supplying additional system extension images to install on top of base Talos image.\\u003c/p\\u003e\\n\"\n        },\n        \"wipe\": {\n          \"type\": \"boolean\",\n          \"title\": \"wipe\",\n          \"description\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to true.\\n\",\n          \"markdownDescription\": \"Indicates if the installation disk should be wiped at installation time.\\nDefaults to `true`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the installation disk should be wiped at installation time.\\nDefaults to \\u003ccode\\u003etrue\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"legacyBIOSSupport\": {\n          \"type\": \"boolean\",\n          \"title\": \"legacyBIOSSupport\",\n          \"description\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn’t support GPT partitioning scheme.\\n\",\n          \"markdownDescription\": \"Indicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn't support GPT partitioning scheme.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if MBR partition should be marked as bootable (active).\\nShould be enabled only for the systems with legacy BIOS that doesn\\u0026rsquo;t support GPT partitioning scheme.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallDiskSelector\": {\n      \"properties\": {\n        \"size\": {\n          \"type\": \"string\",\n          \"title\": \"size\",\n          \"description\": \"Disk size.\\n\",\n          \"markdownDescription\": \"Disk size.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk size.\\u003c/p\\u003e\\n\"\n        },\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Disk name /sys/block/\\u0026lt;dev\\u0026gt;/device/name.\\n\",\n          \"markdownDescription\": \"Disk name `/sys/block/\\u003cdev\\u003e/device/name`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk name \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/name\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"model\": {\n          \"type\": \"string\",\n          \"title\": \"model\",\n          \"description\": \"Disk model /sys/block/\\u0026lt;dev\\u0026gt;/device/model.\\n\",\n          \"markdownDescription\": \"Disk model `/sys/block/\\u003cdev\\u003e/device/model`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk model \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/model\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"serial\": {\n          \"type\": \"string\",\n          \"title\": \"serial\",\n          \"description\": \"Disk serial number /sys/block/\\u0026lt;dev\\u0026gt;/serial.\\n\",\n          \"markdownDescription\": \"Disk serial number `/sys/block/\\u003cdev\\u003e/serial`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk serial number \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/serial\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"modalias\": {\n          \"type\": \"string\",\n          \"title\": \"modalias\",\n          \"description\": \"Disk modalias /sys/block/\\u0026lt;dev\\u0026gt;/device/modalias.\\n\",\n          \"markdownDescription\": \"Disk modalias `/sys/block/\\u003cdev\\u003e/device/modalias`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk modalias \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/device/modalias\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"uuid\": {\n          \"type\": \"string\",\n          \"title\": \"uuid\",\n          \"description\": \"Disk UUID /sys/block/\\u0026lt;dev\\u0026gt;/uuid.\\n\",\n          \"markdownDescription\": \"Disk UUID `/sys/block/\\u003cdev\\u003e/uuid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk UUID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/uuid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"wwid\": {\n          \"type\": \"string\",\n          \"title\": \"wwid\",\n          \"description\": \"Disk WWID /sys/block/\\u0026lt;dev\\u0026gt;/wwid.\\n\",\n          \"markdownDescription\": \"Disk WWID `/sys/block/\\u003cdev\\u003e/wwid`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk WWID \\u003ccode\\u003e/sys/block/\\u0026lt;dev\\u0026gt;/wwid\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"type\": {\n          \"enum\": [\n            \"ssd\",\n            \"hdd\",\n            \"nvme\",\n            \"sd\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Disk Type.\\n\",\n          \"markdownDescription\": \"Disk Type.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk Type.\\u003c/p\\u003e\\n\"\n        },\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"Disk bus path.\\n\",\n          \"markdownDescription\": \"Disk bus path.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisk bus path.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"InstallExtensionConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"System extension image.\\n\",\n          \"markdownDescription\": \"System extension image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSystem extension image.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KernelConfig\": {\n      \"properties\": {\n        \"modules\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/KernelModuleConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"modules\",\n          \"description\": \"Kernel modules to load.\\n\",\n          \"markdownDescription\": \"Kernel modules to load.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel modules to load.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KernelModuleConfig\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"Module name.\\n\",\n          \"markdownDescription\": \"Module name.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule name.\\u003c/p\\u003e\\n\"\n        },\n        \"parameters\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"parameters\",\n          \"description\": \"Module parameters, changes applied after reboot.\\n\",\n          \"markdownDescription\": \"Module parameters, changes applied after reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eModule parameters, changes applied after reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubePrism\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable KubePrism support - will start local load balacing proxy.\\n\",\n          \"markdownDescription\": \"Enable KubePrism support - will start local load balacing proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable KubePrism support - will start local load balacing proxy.\\u003c/p\\u003e\\n\"\n        },\n        \"port\": {\n          \"type\": \"integer\",\n          \"title\": \"port\",\n          \"description\": \"KubePrism port.\\n\",\n          \"markdownDescription\": \"KubePrism port.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubePrism port.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeSpanFilters\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\\n\",\n          \"markdownDescription\": \"Filter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\n\\nBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\n\\nDefault value: no filtering.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFilter node addresses which will be advertised as KubeSpan endpoints for peer-to-peer Wireguard connections.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eBy default, all addresses are advertised, and KubeSpan cycles through all endpoints until it finds one that works.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eDefault value: no filtering.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeletConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The image field is an optional reference to an alternative kubelet image.\\n\",\n          \"markdownDescription\": \"The `image` field is an optional reference to an alternative kubelet image.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eimage\\u003c/code\\u003e field is an optional reference to an alternative kubelet image.\\u003c/p\\u003e\\n\"\n        },\n        \"clusterDNS\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"clusterDNS\",\n          \"description\": \"The ClusterDNS field is an optional reference to an alternative kubelet clusterDNS ip list.\\n\",\n          \"markdownDescription\": \"The `ClusterDNS` field is an optional reference to an alternative kubelet clusterDNS ip list.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eClusterDNS\\u003c/code\\u003e field is an optional reference to an alternative kubelet clusterDNS ip list.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"The extraArgs field is used to provide additional flags to the kubelet.\\n\",\n          \"markdownDescription\": \"The `extraArgs` field is used to provide additional flags to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraArgs\\u003c/code\\u003e field is used to provide additional flags to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"extraMounts\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ExtraMount\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraMounts\",\n          \"description\": \"The extraMounts field is used to add additional mounts to the kubelet container.\\nNote that either bind or rbind are required in the options.\\n\",\n          \"markdownDescription\": \"The `extraMounts` field is used to add additional mounts to the kubelet container.\\nNote that either `bind` or `rbind` are required in the `options`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraMounts\\u003c/code\\u003e field is used to add additional mounts to the kubelet container.\\nNote that either \\u003ccode\\u003ebind\\u003c/code\\u003e or \\u003ccode\\u003erbind\\u003c/code\\u003e are required in the \\u003ccode\\u003eoptions\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"extraConfig\": {\n          \"type\": \"object\",\n          \"title\": \"extraConfig\",\n          \"description\": \"The extraConfig field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\n\",\n          \"markdownDescription\": \"The `extraConfig` field is used to provide kubelet configuration overrides.\\n\\nSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eextraConfig\\u003c/code\\u003e field is used to provide kubelet configuration overrides.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSome fields are not allowed to be overridden: authentication and authorization, cgroups\\nconfiguration, ports, etc.\\u003c/p\\u003e\\n\"\n        },\n        \"credentialProviderConfig\": {\n          \"type\": \"object\",\n          \"title\": \"credentialProviderConfig\",\n          \"description\": \"The KubeletCredentialProviderConfig field is used to provide kubelet credential configuration.\\n\",\n          \"markdownDescription\": \"The `KubeletCredentialProviderConfig` field is used to provide kubelet credential configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eKubeletCredentialProviderConfig\\u003c/code\\u003e field is used to provide kubelet credential configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"defaultRuntimeSeccompProfileEnabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"defaultRuntimeSeccompProfileEnabled\",\n          \"description\": \"Enable container runtime default Seccomp profile.\\n\",\n          \"markdownDescription\": \"Enable container runtime default Seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable container runtime default Seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"registerWithFQDN\": {\n          \"type\": \"boolean\",\n          \"title\": \"registerWithFQDN\",\n          \"description\": \"The registerWithFQDN field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\n\",\n          \"markdownDescription\": \"The `registerWithFQDN` field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eregisterWithFQDN\\u003c/code\\u003e field is used to force kubelet to use the node FQDN for registration.\\nThis is required in clouds like AWS.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeIP\": {\n          \"$ref\": \"#/$defs/KubeletNodeIPConfig\",\n          \"title\": \"nodeIP\",\n          \"description\": \"The nodeIP field is used to configure --node-ip flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\n\",\n          \"markdownDescription\": \"The `nodeIP` field is used to configure `--node-ip` flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003enodeIP\\u003c/code\\u003e field is used to configure \\u003ccode\\u003e--node-ip\\u003c/code\\u003e flag for the kubelet.\\nThis is used when a node has multiple addresses to choose from.\\u003c/p\\u003e\\n\"\n        },\n        \"skipNodeRegistration\": {\n          \"type\": \"boolean\",\n          \"title\": \"skipNodeRegistration\",\n          \"description\": \"The skipNodeRegistration is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\n\",\n          \"markdownDescription\": \"The `skipNodeRegistration` is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eskipNodeRegistration\\u003c/code\\u003e is used to run the kubelet without registering with the apiserver.\\nThis runs kubelet as standalone and only runs static pods.\\u003c/p\\u003e\\n\"\n        },\n        \"disableManifestsDirectory\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableManifestsDirectory\",\n          \"description\": \"The disableManifestsDirectory field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt’s recommended to configure static pods with the “pods” key instead.\\n\",\n          \"markdownDescription\": \"The `disableManifestsDirectory` field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt's recommended to configure static pods with the \\\"pods\\\" key instead.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003edisableManifestsDirectory\\u003c/code\\u003e field configures the kubelet to get static pod manifests from the /etc/kubernetes/manifests directory.\\nIt\\u0026rsquo;s recommended to configure static pods with the \\u0026ldquo;pods\\u0026rdquo; key instead.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubeletNodeIPConfig\": {\n      \"properties\": {\n        \"validSubnets\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"validSubnets\",\n          \"description\": \"The validSubnets field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with !, e.g !10.0.0.0/8.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\n\",\n          \"markdownDescription\": \"The `validSubnets` field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with `!`, e.g `!10.0.0.0/8`.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalidSubnets\\u003c/code\\u003e field configures the networks to pick kubelet node IP from.\\nFor dual stack configuration, there should be two subnets: one for IPv4, another for IPv6.\\nIPs can be excluded from the list by using negative match with \\u003ccode\\u003e!\\u003c/code\\u003e, e.g \\u003ccode\\u003e!10.0.0.0/8\\u003c/code\\u003e.\\nNegative subnet matches should be specified last to filter out IPs picked by positive matches.\\nIf not specified, node IP is picked based on cluster podCIDRs: IPv4/IPv6 address or both.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"KubernetesTalosAPIAccessConfig\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable Talos API access from Kubernetes pods.\\n\",\n          \"markdownDescription\": \"Enable Talos API access from Kubernetes pods.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable Talos API access from Kubernetes pods.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedRoles\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedRoles\",\n          \"description\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\\n\",\n          \"markdownDescription\": \"The list of Talos API roles which can be granted for access from Kubernetes pods.\\n\\nEmpty list means that no roles can be granted, so access is blocked.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Talos API roles which can be granted for access from Kubernetes pods.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eEmpty list means that no roles can be granted, so access is blocked.\\u003c/p\\u003e\\n\"\n        },\n        \"allowedKubernetesNamespaces\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"allowedKubernetesNamespaces\",\n          \"description\": \"The list of Kubernetes namespaces Talos API access is available from.\\n\",\n          \"markdownDescription\": \"The list of Kubernetes namespaces Talos API access is available from.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe list of Kubernetes namespaces Talos API access is available from.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LinuxIDMapping\": {\n      \"properties\": {\n        \"containerID\": {\n          \"type\": \"integer\",\n          \"title\": \"containerID\",\n          \"description\": \"ContainerID is the starting UID/GID in the container.\\n\",\n          \"markdownDescription\": \"ContainerID is the starting UID/GID in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eContainerID is the starting UID/GID in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"hostID\": {\n          \"type\": \"integer\",\n          \"title\": \"hostID\",\n          \"description\": \"HostID is the starting UID/GID on the host to be mapped to ‘ContainerID’.\\n\",\n          \"markdownDescription\": \"HostID is the starting UID/GID on the host to be mapped to 'ContainerID'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eHostID is the starting UID/GID on the host to be mapped to \\u0026lsquo;ContainerID\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"size\": {\n          \"type\": \"integer\",\n          \"title\": \"size\",\n          \"description\": \"Size is the number of IDs to be mapped.\\n\",\n          \"markdownDescription\": \"Size is the number of IDs to be mapped.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSize is the number of IDs to be mapped.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LoggingConfig\": {\n      \"properties\": {\n        \"destinations\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/LoggingDestination\"\n          },\n          \"type\": \"array\",\n          \"title\": \"destinations\",\n          \"description\": \"Logging destination.\\n\",\n          \"markdownDescription\": \"Logging destination.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogging destination.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"LoggingDestination\": {\n      \"properties\": {\n        \"endpoint\": {\n          \"$ref\": \"#/$defs/Endpoint\",\n          \"title\": \"endpoint\",\n          \"description\": \"Where to send logs. Supported protocols are “tcp” and “udp”.\\n\",\n          \"markdownDescription\": \"Where to send logs. Supported protocols are \\\"tcp\\\" and \\\"udp\\\".\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhere to send logs. Supported protocols are \\u0026ldquo;tcp\\u0026rdquo; and \\u0026ldquo;udp\\u0026rdquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"format\": {\n          \"enum\": [\n            \"json_lines\"\n          ],\n          \"title\": \"format\",\n          \"description\": \"Logs format.\\n\",\n          \"markdownDescription\": \"Logs format.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLogs format.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineConfig\": {\n      \"properties\": {\n        \"type\": {\n          \"enum\": [\n            \"controlplane\",\n            \"worker\"\n          ],\n          \"title\": \"type\",\n          \"description\": \"Defines the role of the machine within the cluster.\\n\\nControl Plane\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\nWorker\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as “join”; that value is still supported but deprecated.\\n\",\n          \"markdownDescription\": \"Defines the role of the machine within the cluster.\\n\\n**Control Plane**\\n\\nControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\n\\n**Worker**\\n\\nWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\n\\nThis node type was previously known as \\\"join\\\"; that value is still supported but deprecated.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDefines the role of the machine within the cluster.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eControl Plane\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eControl Plane node type designates the node as a control plane member.\\nThis means it will host etcd along with the Kubernetes controlplane components such as API Server, Controller Manager, Scheduler.\\u003c/p\\u003e\\n\\n\\u003cp\\u003e\\u003cstrong\\u003eWorker\\u003c/strong\\u003e\\u003c/p\\u003e\\n\\n\\u003cp\\u003eWorker node type designates the node as a worker node.\\nThis means it will be an available compute node for scheduling workloads.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThis node type was previously known as \\u0026ldquo;join\\u0026rdquo;; that value is still supported but deprecated.\\u003c/p\\u003e\\n\"\n        },\n        \"token\": {\n          \"type\": \"string\",\n          \"title\": \"token\",\n          \"description\": \"The token is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its’ identity.\\n\",\n          \"markdownDescription\": \"The `token` is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its' identity.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003etoken\\u003c/code\\u003e is used by a machine to join the PKI of the cluster.\\nUsing this token, a machine will create a certificate signing request (CSR), and request a certificate that will be used as its\\u0026rsquo; identity.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"ca\",\n          \"description\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded crt and key.\\n\",\n          \"markdownDescription\": \"The root certificate authority of the PKI.\\nIt is composed of a base64 encoded `crt` and `key`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe root certificate authority of the PKI.\\nIt is composed of a base64 encoded \\u003ccode\\u003ecrt\\u003c/code\\u003e and \\u003ccode\\u003ekey\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"certSANs\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"certSANs\",\n          \"description\": \"Extra certificate subject alternative names for the machine’s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate’s SANs.\\n\",\n          \"markdownDescription\": \"Extra certificate subject alternative names for the machine's certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate's SANs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra certificate subject alternative names for the machine\\u0026rsquo;s certificate.\\nBy default, all non-loopback interface IPs are automatically added to the certificate\\u0026rsquo;s SANs.\\u003c/p\\u003e\\n\"\n        },\n        \"controlPlane\": {\n          \"$ref\": \"#/$defs/MachineControlPlaneConfig\",\n          \"title\": \"controlPlane\",\n          \"description\": \"Provides machine specific control plane configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific control plane configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific control plane configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"kubelet\": {\n          \"$ref\": \"#/$defs/KubeletConfig\",\n          \"title\": \"kubelet\",\n          \"description\": \"Used to provide additional options to the kubelet.\\n\",\n          \"markdownDescription\": \"Used to provide additional options to the kubelet.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide additional options to the kubelet.\\u003c/p\\u003e\\n\"\n        },\n        \"pods\": {\n          \"items\": {\n            \"type\": \"object\"\n          },\n          \"type\": \"array\",\n          \"title\": \"pods\",\n          \"description\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn’t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\\n\",\n          \"markdownDescription\": \"Used to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\n\\nStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn't validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\n\\nSee https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide static pod definitions to be run by the kubelet directly bypassing the kube-apiserver.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eStatic pods can be used to run components which should be started before the Kubernetes control plane is up.\\nTalos doesn\\u0026rsquo;t validate the pod definition.\\nUpdates to this field can be applied without a reboot.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee \\u003ca href=\\\"https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\\" target=\\\"_blank\\\"\\u003ehttps://kubernetes.io/docs/tasks/configure-pod-container/static-pod/\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"network\": {\n          \"$ref\": \"#/$defs/NetworkConfig\",\n          \"title\": \"network\",\n          \"description\": \"Provides machine specific network configuration options.\\n\",\n          \"markdownDescription\": \"Provides machine specific network configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eProvides machine specific network configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"disks\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineDisk\"\n          },\n          \"type\": \"array\",\n          \"title\": \"disks\",\n          \"description\": \"Used to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of /var, mounts are only valid if they are under /var.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf size: is omitted, the partition is sized to occupy the full disk.\\n\",\n          \"markdownDescription\": \"Used to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of `/var`, mounts are only valid if they are under `/var`.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf `size:` is omitted, the partition is sized to occupy the full disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to partition, format and mount additional disks.\\nSince the rootfs is read only with the exception of \\u003ccode\\u003e/var\\u003c/code\\u003e, mounts are only valid if they are under \\u003ccode\\u003e/var\\u003c/code\\u003e.\\nNote that the partitioning and formatting is done only once, if and only if no existing XFS partitions are found.\\nIf \\u003ccode\\u003esize:\\u003c/code\\u003e is omitted, the partition is sized to occupy the full disk.\\u003c/p\\u003e\\n\"\n        },\n        \"install\": {\n          \"$ref\": \"#/$defs/InstallConfig\",\n          \"title\": \"install\",\n          \"description\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\n\",\n          \"markdownDescription\": \"Used to provide instructions for installations.\\n\\nNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to provide instructions for installations.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eNote that this configuration section gets silently ignored by Talos images that are considered pre-installed.\\nTo make sure Talos installs according to the provided configuration, Talos should be booted with ISO or PXE-booted.\\u003c/p\\u003e\\n\"\n        },\n        \"files\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineFile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"files\",\n          \"description\": \"Allows the addition of user specified files.\\nThe value of op can be create, overwrite, or append.\\nIn the case of create, path must not exist.\\nIn the case of overwrite, and append, path must be a valid file.\\nIf an op value of append is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\n\",\n          \"markdownDescription\": \"Allows the addition of user specified files.\\nThe value of `op` can be `create`, `overwrite`, or `append`.\\nIn the case of `create`, `path` must not exist.\\nIn the case of `overwrite`, and `append`, `path` must be a valid file.\\nIf an `op` value of `append` is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows the addition of user specified files.\\nThe value of \\u003ccode\\u003eop\\u003c/code\\u003e can be \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, or \\u003ccode\\u003eappend\\u003c/code\\u003e.\\nIn the case of \\u003ccode\\u003ecreate\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must not exist.\\nIn the case of \\u003ccode\\u003eoverwrite\\u003c/code\\u003e, and \\u003ccode\\u003eappend\\u003c/code\\u003e, \\u003ccode\\u003epath\\u003c/code\\u003e must be a valid file.\\nIf an \\u003ccode\\u003eop\\u003c/code\\u003e value of \\u003ccode\\u003eappend\\u003c/code\\u003e is used, the existing file will be appended.\\nNote that the file contents are not required to be base64 encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables.\\nAll environment variables are set on PID 1 in addition to every service.\\u003c/p\\u003e\\n\"\n        },\n        \"time\": {\n          \"$ref\": \"#/$defs/TimeConfig\",\n          \"title\": \"time\",\n          \"description\": \"Used to configure the machine’s time settings.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's time settings.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s time settings.\\u003c/p\\u003e\\n\"\n        },\n        \"sysctls\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysctls\",\n          \"description\": \"Used to configure the machine’s sysctls.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysctls.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysctls.\\u003c/p\\u003e\\n\"\n        },\n        \"sysfs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"sysfs\",\n          \"description\": \"Used to configure the machine’s sysfs.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's sysfs.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s sysfs.\\u003c/p\\u003e\\n\"\n        },\n        \"registries\": {\n          \"$ref\": \"#/$defs/RegistriesConfig\",\n          \"title\": \"registries\",\n          \"description\": \"Used to configure the machine’s container image registry mirrors.\\n\\nAutomatically generates matching CRI configuration for registry mirrors.\\n\\nThe mirrors section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\n\\nThe config section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in .docker/config.json.\\n\\nSee also matching configuration for CRI containerd plugin.\\n\",\n          \"markdownDescription\": \"Used to configure the machine's container image registry mirrors.\\n\\nAutomatically generates matching CRI configuration for registry mirrors.\\n\\nThe `mirrors` section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\n\\nThe `config` section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\\n\\nSee also matching configuration for [CRI containerd plugin](https://github.com/containerd/cri/blob/master/docs/registry.md).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to configure the machine\\u0026rsquo;s container image registry mirrors.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eAutomatically generates matching CRI configuration for registry mirrors.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe \\u003ccode\\u003emirrors\\u003c/code\\u003e section allows to redirect requests for images to a non-default registry,\\nwhich might be a local registry or a caching mirror.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe \\u003ccode\\u003econfig\\u003c/code\\u003e section provides a way to authenticate to the registry with TLS client\\nidentity, provide registry CA, or authentication information.\\nAuthentication information has same meaning with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSee also matching configuration for \\u003ca href=\\\"https://github.com/containerd/cri/blob/master/docs/registry.md\\\" target=\\\"_blank\\\"\\u003eCRI containerd plugin\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"systemDiskEncryption\": {\n          \"$ref\": \"#/$defs/SystemDiskEncryptionConfig\",\n          \"title\": \"systemDiskEncryption\",\n          \"description\": \"Machine system disk encryption configuration.\\nDefines each system partition encryption parameters.\\n\",\n          \"markdownDescription\": \"Machine system disk encryption configuration.\\nDefines each system partition encryption parameters.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMachine system disk encryption configuration.\\nDefines each system partition encryption parameters.\\u003c/p\\u003e\\n\"\n        },\n        \"features\": {\n          \"$ref\": \"#/$defs/FeaturesConfig\",\n          \"title\": \"features\",\n          \"description\": \"Features describe individual Talos features that can be switched on or off.\\n\",\n          \"markdownDescription\": \"Features describe individual Talos features that can be switched on or off.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eFeatures describe individual Talos features that can be switched on or off.\\u003c/p\\u003e\\n\"\n        },\n        \"udev\": {\n          \"$ref\": \"#/$defs/UdevConfig\",\n          \"title\": \"udev\",\n          \"description\": \"Configures the udev system.\\n\",\n          \"markdownDescription\": \"Configures the udev system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the udev system.\\u003c/p\\u003e\\n\"\n        },\n        \"logging\": {\n          \"$ref\": \"#/$defs/LoggingConfig\",\n          \"title\": \"logging\",\n          \"description\": \"Configures the logging system.\\n\",\n          \"markdownDescription\": \"Configures the logging system.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the logging system.\\u003c/p\\u003e\\n\"\n        },\n        \"kernel\": {\n          \"$ref\": \"#/$defs/KernelConfig\",\n          \"title\": \"kernel\",\n          \"description\": \"Configures the kernel.\\n\",\n          \"markdownDescription\": \"Configures the kernel.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the kernel.\\u003c/p\\u003e\\n\"\n        },\n        \"seccompProfiles\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/MachineSeccompProfile\"\n          },\n          \"type\": \"array\",\n          \"title\": \"seccompProfiles\",\n          \"description\": \"Configures the seccomp profiles for the machine.\\n\",\n          \"markdownDescription\": \"Configures the seccomp profiles for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the seccomp profiles for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeLabels\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeLabels\",\n          \"description\": \"Configures the node labels for the machine.\\n\",\n          \"markdownDescription\": \"Configures the node labels for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node labels for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"nodeTaints\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"nodeTaints\",\n          \"description\": \"Configures the node taints for the machine. Effect is optional.\\n\",\n          \"markdownDescription\": \"Configures the node taints for the machine. Effect is optional.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures the node taints for the machine. Effect is optional.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineControlPlaneConfig\": {\n      \"properties\": {\n        \"controllerManager\": {\n          \"$ref\": \"#/$defs/MachineControllerManagerConfig\",\n          \"title\": \"controllerManager\",\n          \"description\": \"Controller manager machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Controller manager machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eController manager machine specific configuration options.\\u003c/p\\u003e\\n\"\n        },\n        \"scheduler\": {\n          \"$ref\": \"#/$defs/MachineSchedulerConfig\",\n          \"title\": \"scheduler\",\n          \"description\": \"Scheduler machine specific configuration options.\\n\",\n          \"markdownDescription\": \"Scheduler machine specific configuration options.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eScheduler machine specific configuration options.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineControllerManagerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-controller-manager on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-controller-manager on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-controller-manager on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineDisk\": {\n      \"properties\": {\n        \"device\": {\n          \"type\": \"string\",\n          \"title\": \"device\",\n          \"description\": \"The name of the disk to use.\\n\",\n          \"markdownDescription\": \"The name of the disk to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe name of the disk to use.\\u003c/p\\u003e\\n\"\n        },\n        \"partitions\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/DiskPartition\"\n          },\n          \"type\": \"array\",\n          \"title\": \"partitions\",\n          \"description\": \"A list of partitions to create on the disk.\\n\",\n          \"markdownDescription\": \"A list of partitions to create on the disk.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of partitions to create on the disk.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineFile\": {\n      \"properties\": {\n        \"content\": {\n          \"type\": \"string\",\n          \"title\": \"content\",\n          \"description\": \"The contents of the file.\\n\",\n          \"markdownDescription\": \"The contents of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe contents of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"permissions\": {\n          \"type\": \"integer\",\n          \"title\": \"permissions\",\n          \"description\": \"The file’s permissions in octal.\\n\",\n          \"markdownDescription\": \"The file's permissions in octal.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe file\\u0026rsquo;s permissions in octal.\\u003c/p\\u003e\\n\"\n        },\n        \"path\": {\n          \"type\": \"string\",\n          \"title\": \"path\",\n          \"description\": \"The path of the file.\\n\",\n          \"markdownDescription\": \"The path of the file.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe path of the file.\\u003c/p\\u003e\\n\"\n        },\n        \"op\": {\n          \"enum\": [\n            \"create\",\n            \"append\",\n            \"overwrite\"\n          ],\n          \"title\": \"op\",\n          \"description\": \"The operation to use\\n\",\n          \"markdownDescription\": \"The operation to use\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe operation to use\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineSchedulerConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-scheduler on the node.\\n\",\n          \"markdownDescription\": \"Disable kube-scheduler on the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-scheduler on the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"MachineSeccompProfile\": {\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"title\": \"name\",\n          \"description\": \"The name field is used to provide the file name of the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `name` field is used to provide the file name of the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003ename\\u003c/code\\u003e field is used to provide the file name of the seccomp profile.\\u003c/p\\u003e\\n\"\n        },\n        \"value\": {\n          \"type\": \"object\",\n          \"title\": \"value\",\n          \"description\": \"The value field is used to provide the seccomp profile.\\n\",\n          \"markdownDescription\": \"The `value` field is used to provide the seccomp profile.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003evalue\\u003c/code\\u003e field is used to provide the seccomp profile.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkConfig\": {\n      \"properties\": {\n        \"hostname\": {\n          \"type\": \"string\",\n          \"title\": \"hostname\",\n          \"description\": \"Used to statically set the hostname for the machine.\\n\",\n          \"markdownDescription\": \"Used to statically set the hostname for the machine.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to statically set the hostname for the machine.\\u003c/p\\u003e\\n\"\n        },\n        \"interfaces\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Device\"\n          },\n          \"type\": \"array\",\n          \"title\": \"interfaces\",\n          \"description\": \"interfaces is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\\n\",\n          \"markdownDescription\": \"`interfaces` is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003e\\u003ccode\\u003einterfaces\\u003c/code\\u003e is used to define the network interface configuration.\\nBy default all network interfaces will attempt a DHCP discovery.\\nThis can be further tuned through this configuration parameter.\\u003c/p\\u003e\\n\"\n        },\n        \"nameservers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"nameservers\",\n          \"description\": \"Used to statically set the nameservers for the machine.\\nDefaults to 1.1.1.1 and 8.8.8.8\\n\",\n          \"markdownDescription\": \"Used to statically set the nameservers for the machine.\\nDefaults to `1.1.1.1` and `8.8.8.8`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUsed to statically set the nameservers for the machine.\\nDefaults to \\u003ccode\\u003e1.1.1.1\\u003c/code\\u003e and \\u003ccode\\u003e8.8.8.8\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"extraHostEntries\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/ExtraHost\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraHostEntries\",\n          \"description\": \"Allows for extra entries to be added to the /etc/hosts file\\n\",\n          \"markdownDescription\": \"Allows for extra entries to be added to the `/etc/hosts` file\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eAllows for extra entries to be added to the \\u003ccode\\u003e/etc/hosts\\u003c/code\\u003e file\\u003c/p\\u003e\\n\"\n        },\n        \"kubespan\": {\n          \"$ref\": \"#/$defs/NetworkKubeSpan\",\n          \"title\": \"kubespan\",\n          \"description\": \"Configures KubeSpan feature.\\n\",\n          \"markdownDescription\": \"Configures KubeSpan feature.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigures KubeSpan feature.\\u003c/p\\u003e\\n\"\n        },\n        \"disableSearchDomain\": {\n          \"type\": \"boolean\",\n          \"title\": \"disableSearchDomain\",\n          \"description\": \"Disable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to false.\\n\",\n          \"markdownDescription\": \"Disable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to `false`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable generating a default search domain in /etc/resolv.conf\\nbased on the machine hostname.\\nDefaults to \\u003ccode\\u003efalse\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkDeviceSelector\": {\n      \"properties\": {\n        \"busPath\": {\n          \"type\": \"string\",\n          \"title\": \"busPath\",\n          \"description\": \"PCI, USB bus prefix, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"PCI, USB bus prefix, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI, USB bus prefix, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"hardwareAddr\": {\n          \"type\": \"string\",\n          \"title\": \"hardwareAddr\",\n          \"description\": \"Device hardware address, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"Device hardware address, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDevice hardware address, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"pciID\": {\n          \"type\": \"string\",\n          \"title\": \"pciID\",\n          \"description\": \"PCI ID (vendor ID, product ID), supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"PCI ID (vendor ID, product ID), supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePCI ID (vendor ID, product ID), supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        },\n        \"driver\": {\n          \"type\": \"string\",\n          \"title\": \"driver\",\n          \"description\": \"Kernel driver, supports matching by wildcard.\\n\",\n          \"markdownDescription\": \"Kernel driver, supports matching by wildcard.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKernel driver, supports matching by wildcard.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"NetworkKubeSpan\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\\n\",\n          \"markdownDescription\": \"Enable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable the KubeSpan feature.\\nCluster discovery should be enabled with .cluster.discovery.enabled for KubeSpan to be enabled.\\u003c/p\\u003e\\n\"\n        },\n        \"advertiseKubernetesNetworks\": {\n          \"type\": \"boolean\",\n          \"title\": \"advertiseKubernetesNetworks\",\n          \"description\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\\n\",\n          \"markdownDescription\": \"Control whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eControl whether Kubernetes pod CIDRs are announced over KubeSpan from the node.\\nIf disabled, CNI handles encapsulating pod-to-pod traffic into some node-to-node tunnel,\\nand KubeSpan handles the node-to-node traffic.\\nIf enabled, KubeSpan will take over pod-to-pod traffic and send it over KubeSpan directly.\\nWhen enabled, KubeSpan should have a way to detect complete pod CIDRs of the node which\\nis not always the case with CNIs not relying on Kubernetes for IPAM.\\u003c/p\\u003e\\n\"\n        },\n        \"allowDownPeerBypass\": {\n          \"type\": \"boolean\",\n          \"title\": \"allowDownPeerBypass\",\n          \"description\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can’t be established.\\n\",\n          \"markdownDescription\": \"Skip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can't be established.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip sending traffic via KubeSpan if the peer connection state is not up.\\nThis provides configurable choice between connectivity and security: either traffic is always\\nforced to go via KubeSpan (even if Wireguard peer connection is not up), or traffic can go directly\\nto the peer if Wireguard connection can\\u0026rsquo;t be established.\\u003c/p\\u003e\\n\"\n        },\n        \"harvestExtraEndpoints\": {\n          \"type\": \"boolean\",\n          \"title\": \"harvestExtraEndpoints\",\n          \"description\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u0026gt;50) in the KubeSpan network it can cause performance issues.\\n\",\n          \"markdownDescription\": \"KubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u003e50) in the KubeSpan network it can cause performance issues.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan can collect and publish extra endpoints for each member of the cluster\\nbased on Wireguard endpoint information for each peer.\\nThis feature is enabled by default to help discover additional endpoints,\\nbut with high number of peers (\\u0026gt;50) in the KubeSpan network it can cause performance issues.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"KubeSpan link MTU size.\\nDefault value is 1420.\\n\",\n          \"markdownDescription\": \"KubeSpan link MTU size.\\nDefault value is 1420.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan link MTU size.\\nDefault value is 1420.\\u003c/p\\u003e\\n\"\n        },\n        \"filters\": {\n          \"$ref\": \"#/$defs/KubeSpanFilters\",\n          \"title\": \"filters\",\n          \"description\": \"KubeSpan advanced filtering of network addresses .\\n\\nSettings in this section are optional, and settings apply only to the node.\\n\",\n          \"markdownDescription\": \"KubeSpan advanced filtering of network addresses .\\n\\nSettings in this section are optional, and settings apply only to the node.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eKubeSpan advanced filtering of network addresses .\\u003c/p\\u003e\\n\\n\\u003cp\\u003eSettings in this section are optional, and settings apply only to the node.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ProxyConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable kube-proxy deployment on cluster bootstrap.\\n\",\n          \"markdownDescription\": \"Disable kube-proxy deployment on cluster bootstrap.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable kube-proxy deployment on cluster bootstrap.\\u003c/p\\u003e\\n\"\n        },\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the kube-proxy manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the kube-proxy manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the kube-proxy manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"mode\": {\n          \"type\": \"string\",\n          \"title\": \"mode\",\n          \"description\": \"proxy mode of kube-proxy.\\nThe default is ‘iptables’.\\n\",\n          \"markdownDescription\": \"proxy mode of kube-proxy.\\nThe default is 'iptables'.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eproxy mode of kube-proxy.\\nThe default is \\u0026lsquo;iptables\\u0026rsquo;.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to kube-proxy.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to kube-proxy.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to kube-proxy.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistriesConfig\": {\n      \"properties\": {\n        \"mirrors\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"$ref\": \"#/$defs/RegistryMirrorConfig\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"mirrors\",\n          \"description\": \"Specifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\n\\nFor example, when pulling an image with the reference example.com:123/image:v1,\\nthe example.com:123 key will be used to lookup the mirror configuration.\\n\\nOptionally the * key can be used to configure a fallback mirror.\\n\\nRegistry name is the first segment of image identifier, with ‘docker.io’\\nbeing default one.\\n\",\n          \"markdownDescription\": \"Specifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\n\\nFor example, when pulling an image with the reference `example.com:123/image:v1`,\\nthe `example.com:123` key will be used to lookup the mirror configuration.\\n\\nOptionally the `*` key can be used to configure a fallback mirror.\\n\\nRegistry name is the first segment of image identifier, with 'docker.io'\\nbeing default one.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies mirror configuration for each registry host namespace.\\nThis setting allows to configure local pull-through caching registires,\\nair-gapped installations, etc.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eFor example, when pulling an image with the reference \\u003ccode\\u003eexample.com:123/image:v1\\u003c/code\\u003e,\\nthe \\u003ccode\\u003eexample.com:123\\u003c/code\\u003e key will be used to lookup the mirror configuration.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eOptionally the \\u003ccode\\u003e*\\u003c/code\\u003e key can be used to configure a fallback mirror.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eRegistry name is the first segment of image identifier, with \\u0026lsquo;docker.io\\u0026rsquo;\\nbeing default one.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"$ref\": \"#/$defs/RegistryConfig\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specifies TLS \\u0026amp; auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with ‘clientIdentity’ option.\\n\\nThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key * can’t be used for TLS configuration.\\n\\nTLS configuration can be skipped if registry has trusted\\nserver certificate.\\n\",\n          \"markdownDescription\": \"Specifies TLS \\u0026 auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with 'clientIdentity' option.\\n\\nThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key `*` can't be used for TLS configuration.\\n\\nTLS configuration can be skipped if registry has trusted\\nserver certificate.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies TLS \\u0026amp; auth configuration for HTTPS image registries.\\nMutual TLS can be enabled with \\u0026lsquo;clientIdentity\\u0026rsquo; option.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eThe full hostname and port (if not using a default port 443)\\nshould be used as the key.\\nThe fallback key \\u003ccode\\u003e*\\u003c/code\\u003e can\\u0026rsquo;t be used for TLS configuration.\\u003c/p\\u003e\\n\\n\\u003cp\\u003eTLS configuration can be skipped if registry has trusted\\nserver certificate.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryAuthConfig\": {\n      \"properties\": {\n        \"username\": {\n          \"type\": \"string\",\n          \"title\": \"username\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"password\": {\n          \"type\": \"string\",\n          \"title\": \"password\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"type\": \"string\",\n          \"title\": \"auth\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"identityToken\": {\n          \"type\": \"string\",\n          \"title\": \"identityToken\",\n          \"description\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in .docker/config.json.\\n\",\n          \"markdownDescription\": \"Optional registry authentication.\\nThe meaning of each field is the same with the corresponding field in [`.docker/config.json`](https://docs.docker.com/engine/api/v1.41/#section/Authentication).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eOptional registry authentication.\\nThe meaning of each field is the same with the corresponding field in \\u003ca href=\\\"https://docs.docker.com/engine/api/v1.41/#section/Authentication\\\" target=\\\"_blank\\\"\\u003e\\u003ccode\\u003e.docker/config.json\\u003c/code\\u003e\\u003c/a\\u003e.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryConfig\": {\n      \"properties\": {\n        \"tls\": {\n          \"$ref\": \"#/$defs/RegistryTLSConfig\",\n          \"title\": \"tls\",\n          \"description\": \"The TLS configuration for the registry.\\n\",\n          \"markdownDescription\": \"The TLS configuration for the registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe TLS configuration for the registry.\\u003c/p\\u003e\\n\"\n        },\n        \"auth\": {\n          \"$ref\": \"#/$defs/RegistryAuthConfig\",\n          \"title\": \"auth\",\n          \"description\": \"The auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\\n\",\n          \"markdownDescription\": \"The auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe auth configuration for this registry.\\nNote: changes to the registry auth will not be picked up by the CRI containerd plugin without a reboot.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryKubernetesConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable Kubernetes discovery registry.\\n\",\n          \"markdownDescription\": \"Disable Kubernetes discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable Kubernetes discovery registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryMirrorConfig\": {\n      \"properties\": {\n        \"endpoints\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"endpoints\",\n          \"description\": \"List of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to /v2).\\n\",\n          \"markdownDescription\": \"List of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to `/v2`).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of endpoints (URLs) for registry mirrors to use.\\nEndpoint configures HTTP/HTTPS access mode, host name,\\nport and path (if path is not set, it defaults to \\u003ccode\\u003e/v2\\u003c/code\\u003e).\\u003c/p\\u003e\\n\"\n        },\n        \"overridePath\": {\n          \"type\": \"boolean\",\n          \"title\": \"overridePath\",\n          \"description\": \"Use the exact path specified for the endpoint (don’t append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\\n\",\n          \"markdownDescription\": \"Use the exact path specified for the endpoint (don't append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eUse the exact path specified for the endpoint (don\\u0026rsquo;t append /v2/).\\nThis setting is often required for setting up multiple mirrors\\non a single instance of a registry.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryServiceConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Disable external service discovery registry.\\n\",\n          \"markdownDescription\": \"Disable external service discovery registry.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDisable external service discovery registry.\\u003c/p\\u003e\\n\"\n        },\n        \"endpoint\": {\n          \"type\": \"string\",\n          \"title\": \"endpoint\",\n          \"description\": \"External service endpoint.\\n\",\n          \"markdownDescription\": \"External service endpoint.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExternal service endpoint.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"RegistryTLSConfig\": {\n      \"properties\": {\n        \"clientIdentity\": {\n          \"properties\": {\n            \"crt\": {\n              \"type\": \"string\"\n            },\n            \"key\": {\n              \"type\": \"string\"\n            }\n          },\n          \"additionalProperties\": false,\n          \"type\": \"object\",\n          \"title\": \"clientIdentity\",\n          \"description\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\\n\",\n          \"markdownDescription\": \"Enable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEnable mutual TLS authentication with the registry.\\nClient certificate and key should be base64-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"ca\": {\n          \"type\": \"string\",\n          \"title\": \"ca\",\n          \"description\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\\n\",\n          \"markdownDescription\": \"CA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eCA registry certificate to add the list of trusted certificates.\\nCertificate should be base64-encoded.\\u003c/p\\u003e\\n\"\n        },\n        \"insecureSkipVerify\": {\n          \"type\": \"boolean\",\n          \"title\": \"insecureSkipVerify\",\n          \"description\": \"Skip TLS server certificate verification (not recommended).\\n\",\n          \"markdownDescription\": \"Skip TLS server certificate verification (not recommended).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSkip TLS server certificate verification (not recommended).\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"ResourcesConfig\": {\n      \"properties\": {\n        \"requests\": {\n          \"$ref\": \"#/$defs/Unstructured\",\n          \"title\": \"requests\",\n          \"description\": \"Requests configures the reserved cpu/memory resources.\\n\",\n          \"markdownDescription\": \"Requests configures the reserved cpu/memory resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eRequests configures the reserved cpu/memory resources.\\u003c/p\\u003e\\n\"\n        },\n        \"limits\": {\n          \"$ref\": \"#/$defs/Unstructured\",\n          \"title\": \"limits\",\n          \"description\": \"Limits configures the maximum cpu/memory resources a container can use.\\n\",\n          \"markdownDescription\": \"Limits configures the maximum cpu/memory resources a container can use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eLimits configures the maximum cpu/memory resources a container can use.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Route\": {\n      \"properties\": {\n        \"network\": {\n          \"type\": \"string\",\n          \"title\": \"network\",\n          \"description\": \"The route’s network (destination).\\n\",\n          \"markdownDescription\": \"The route's network (destination).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s network (destination).\\u003c/p\\u003e\\n\"\n        },\n        \"gateway\": {\n          \"type\": \"string\",\n          \"title\": \"gateway\",\n          \"description\": \"The route’s gateway (if empty, creates link scope route).\\n\",\n          \"markdownDescription\": \"The route's gateway (if empty, creates link scope route).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s gateway (if empty, creates link scope route).\\u003c/p\\u003e\\n\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"title\": \"source\",\n          \"description\": \"The route’s source address (optional).\\n\",\n          \"markdownDescription\": \"The route's source address (optional).\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe route\\u0026rsquo;s source address (optional).\\u003c/p\\u003e\\n\"\n        },\n        \"metric\": {\n          \"type\": \"integer\",\n          \"title\": \"metric\",\n          \"description\": \"The optional metric for the route.\\n\",\n          \"markdownDescription\": \"The optional metric for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional metric for the route.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The optional MTU for the route.\\n\",\n          \"markdownDescription\": \"The optional MTU for the route.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe optional MTU for the route.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"STP\": {\n      \"properties\": {\n        \"enabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"enabled\",\n          \"description\": \"Whether Spanning Tree Protocol (STP) is enabled.\\n\",\n          \"markdownDescription\": \"Whether Spanning Tree Protocol (STP) is enabled.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eWhether Spanning Tree Protocol (STP) is enabled.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"SchedulerConfig\": {\n      \"properties\": {\n        \"image\": {\n          \"type\": \"string\",\n          \"title\": \"image\",\n          \"description\": \"The container image used in the scheduler manifest.\\n\",\n          \"markdownDescription\": \"The container image used in the scheduler manifest.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe container image used in the scheduler manifest.\\u003c/p\\u003e\\n\"\n        },\n        \"extraArgs\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"extraArgs\",\n          \"description\": \"Extra arguments to supply to the scheduler.\\n\",\n          \"markdownDescription\": \"Extra arguments to supply to the scheduler.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra arguments to supply to the scheduler.\\u003c/p\\u003e\\n\"\n        },\n        \"extraVolumes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/VolumeMountConfig\"\n          },\n          \"type\": \"array\",\n          \"title\": \"extraVolumes\",\n          \"description\": \"Extra volumes to mount to the scheduler static pod.\\n\",\n          \"markdownDescription\": \"Extra volumes to mount to the scheduler static pod.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eExtra volumes to mount to the scheduler static pod.\\u003c/p\\u003e\\n\"\n        },\n        \"env\": {\n          \"patternProperties\": {\n            \".*\": {\n              \"type\": \"string\"\n            }\n          },\n          \"type\": \"object\",\n          \"title\": \"env\",\n          \"description\": \"The env field allows for the addition of environment variables for the control plane component.\\n\",\n          \"markdownDescription\": \"The `env` field allows for the addition of environment variables for the control plane component.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe \\u003ccode\\u003eenv\\u003c/code\\u003e field allows for the addition of environment variables for the control plane component.\\u003c/p\\u003e\\n\"\n        },\n        \"resources\": {\n          \"type\": \"object\",\n          \"title\": \"resources\",\n          \"description\": \"Configure the scheduler resources.\\n\",\n          \"markdownDescription\": \"Configure the scheduler resources.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eConfigure the scheduler resources.\\u003c/p\\u003e\\n\"\n        },\n        \"config\": {\n          \"type\": \"object\",\n          \"title\": \"config\",\n          \"description\": \"Specify custom kube-scheduler configuration.\\n\",\n          \"markdownDescription\": \"Specify custom kube-scheduler configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecify custom kube-scheduler configuration.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"SystemDiskEncryptionConfig\": {\n      \"properties\": {\n        \"state\": {\n          \"$ref\": \"#/$defs/EncryptionConfig\",\n          \"title\": \"state\",\n          \"description\": \"State partition encryption.\\n\",\n          \"markdownDescription\": \"State partition encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eState partition encryption.\\u003c/p\\u003e\\n\"\n        },\n        \"ephemeral\": {\n          \"$ref\": \"#/$defs/EncryptionConfig\",\n          \"title\": \"ephemeral\",\n          \"description\": \"Ephemeral partition encryption.\\n\",\n          \"markdownDescription\": \"Ephemeral partition encryption.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eEphemeral partition encryption.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"TimeConfig\": {\n      \"properties\": {\n        \"disabled\": {\n          \"type\": \"boolean\",\n          \"title\": \"disabled\",\n          \"description\": \"Indicates if the time service is disabled for the machine.\\nDefaults to false.\\n\",\n          \"markdownDescription\": \"Indicates if the time service is disabled for the machine.\\nDefaults to `false`.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if the time service is disabled for the machine.\\nDefaults to \\u003ccode\\u003efalse\\u003c/code\\u003e.\\u003c/p\\u003e\\n\"\n        },\n        \"servers\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"servers\",\n          \"description\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to pool.ntp.org\\n\",\n          \"markdownDescription\": \"Specifies time (NTP) servers to use for setting the system time.\\nDefaults to `pool.ntp.org`\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies time (NTP) servers to use for setting the system time.\\nDefaults to \\u003ccode\\u003epool.ntp.org\\u003c/code\\u003e\\u003c/p\\u003e\\n\"\n        },\n        \"bootTimeout\": {\n          \"type\": \"string\",\n          \"pattern\": \"^[-+]?(((\\\\d+(\\\\.\\\\d*)?|\\\\d*(\\\\.\\\\d+)+)([nuµm]?s|m|h))|0)+$\",\n          \"title\": \"bootTimeout\",\n          \"description\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to “infinity” (waiting forever for time sync)\\n\",\n          \"markdownDescription\": \"Specifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\\"infinity\\\" (waiting forever for time sync)\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the timeout when the node time is considered to be in sync unlocking the boot sequence.\\nNTP sync will be still running in the background.\\nDefaults to \\u0026ldquo;infinity\\u0026rdquo; (waiting forever for time sync)\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"UdevConfig\": {\n      \"properties\": {\n        \"rules\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"rules\",\n          \"description\": \"List of udev rules to apply to the udev system\\n\",\n          \"markdownDescription\": \"List of udev rules to apply to the udev system\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eList of udev rules to apply to the udev system\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VIPEquinixMetalConfig\": {\n      \"properties\": {\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Equinix Metal API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Equinix Metal API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Equinix Metal API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VIPHCloudConfig\": {\n      \"properties\": {\n        \"apiToken\": {\n          \"type\": \"string\",\n          \"title\": \"apiToken\",\n          \"description\": \"Specifies the Hetzner Cloud API Token.\\n\",\n          \"markdownDescription\": \"Specifies the Hetzner Cloud API Token.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eSpecifies the Hetzner Cloud API Token.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"Vlan\": {\n      \"properties\": {\n        \"addresses\": {\n          \"items\": {\n            \"type\": \"string\"\n          },\n          \"type\": \"array\",\n          \"title\": \"addresses\",\n          \"description\": \"The addresses in CIDR notation or as plain IPs to use.\\n\",\n          \"markdownDescription\": \"The addresses in CIDR notation or as plain IPs to use.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe addresses in CIDR notation or as plain IPs to use.\\u003c/p\\u003e\\n\"\n        },\n        \"routes\": {\n          \"items\": {\n            \"$ref\": \"#/$defs/Route\"\n          },\n          \"type\": \"array\",\n          \"title\": \"routes\",\n          \"description\": \"A list of routes associated with the VLAN.\\n\",\n          \"markdownDescription\": \"A list of routes associated with the VLAN.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eA list of routes associated with the VLAN.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcp\": {\n          \"type\": \"boolean\",\n          \"title\": \"dhcp\",\n          \"description\": \"Indicates if DHCP should be used.\\n\",\n          \"markdownDescription\": \"Indicates if DHCP should be used.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eIndicates if DHCP should be used.\\u003c/p\\u003e\\n\"\n        },\n        \"vlanId\": {\n          \"type\": \"integer\",\n          \"title\": \"vlanId\",\n          \"description\": \"The VLAN’s ID.\\n\",\n          \"markdownDescription\": \"The VLAN's ID.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s ID.\\u003c/p\\u003e\\n\"\n        },\n        \"mtu\": {\n          \"type\": \"integer\",\n          \"title\": \"mtu\",\n          \"description\": \"The VLAN’s MTU.\\n\",\n          \"markdownDescription\": \"The VLAN's MTU.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s MTU.\\u003c/p\\u003e\\n\"\n        },\n        \"vip\": {\n          \"$ref\": \"#/$defs/DeviceVIPConfig\",\n          \"title\": \"vip\",\n          \"description\": \"The VLAN’s virtual IP address configuration.\\n\",\n          \"markdownDescription\": \"The VLAN's virtual IP address configuration.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eThe VLAN\\u0026rsquo;s virtual IP address configuration.\\u003c/p\\u003e\\n\"\n        },\n        \"dhcpOptions\": {\n          \"$ref\": \"#/$defs/DHCPOptions\",\n          \"title\": \"dhcpOptions\",\n          \"description\": \"DHCP specific options.\\ndhcp must be set to true for these to take effect.\\n\",\n          \"markdownDescription\": \"DHCP specific options.\\n`dhcp` *must* be set to true for these to take effect.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eDHCP specific options.\\n\\u003ccode\\u003edhcp\\u003c/code\\u003e \\u003cem\\u003emust\\u003c/em\\u003e be set to true for these to take effect.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    },\n    \"VolumeMountConfig\": {\n      \"properties\": {\n        \"hostPath\": {\n          \"type\": \"string\",\n          \"title\": \"hostPath\",\n          \"description\": \"Path on the host.\\n\",\n          \"markdownDescription\": \"Path on the host.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath on the host.\\u003c/p\\u003e\\n\"\n        },\n        \"mountPath\": {\n          \"type\": \"string\",\n          \"title\": \"mountPath\",\n          \"description\": \"Path in the container.\\n\",\n          \"markdownDescription\": \"Path in the container.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003ePath in the container.\\u003c/p\\u003e\\n\"\n        },\n        \"readonly\": {\n          \"type\": \"boolean\",\n          \"title\": \"readonly\",\n          \"description\": \"Mount the volume read only.\\n\",\n          \"markdownDescription\": \"Mount the volume read only.\",\n          \"x-intellij-html-description\": \"\\u003cp\\u003eMount the volume read only.\\u003c/p\\u003e\\n\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"type\": \"object\"\n    }\n  }\n}"
  },
  {
    "path": "website/static/install",
    "content": "#!/usr/bin/env sh\n\nset -eu\n\nINSTALLPATH=${INSTALLPATH:-/usr/local/bin}\n\nhappyexit() {\n  echo \"Installed version:\"\n  echo \"$(talosctl version 2>/dev/null )\"\n  echo \"\"\n  echo \"Now run:\"\n  echo \"\"\n  echo \"  talosctl cluster create                  # install a local test cluster\"\n  echo \"  talosctl dashboard                       # If you have created a cluster, launch the dashboard\"\n  echo \"\"\n  echo \"Looking for more? Visit https://talos.dev/latest\"\n  echo \"\"\n  exit 0\n}\n\nvalidate_checksum() {\n  filename=$1\n  url=\"https://github.com/siderolabs/talos/releases/latest/download/sha256sum.txt\"\n  SHA=$(curl --proto '=https' --tlsv1.2 -sSfL \"${url}\" | grep \"${filename}\" | awk '{print $1 }')\n  echo \"\"\n  echo \"Validating checksum...\"\n\n  case $checksumbin in\n    *openssl)\n      checksum=$($checksumbin dgst -sha256 \"${filename}\" | sed -e 's/^.* //')\n      ;;\n    *shasum)\n      checksum=$($checksumbin -a256 \"${filename}\" | sed -e 's/ .*$//')\n      ;;\n  esac\n\n  if [ \"$checksum\" != \"$SHA\" ]; then\n    echo \"Checksum validation failed.\" >&2\n    return 1\n  fi\n  echo \"Checksum valid.\"\n  return 0\n}\n\nOS=$(uname -s)\narch=$(uname -m)\ncli_arch=\"\"\ncase $OS in\n  CYGWIN* | MINGW64*)\n    OS=windows-amd64.exe\n    ;;\n  Darwin | Linux | FreeBSD)\n    case $arch in\n      x86_64)\n        cli_arch=amd64\n        ;;\n      armv8*)\n        cli_arch=arm64\n        ;;\n      aarch64*)\n        cli_arch=arm64\n        ;;\n      amd64|arm64)\n        cli_arch=$arch\n        ;;\n      *)\n        echo \"There is no talosctl $OS support for $arch. Please open an issue with your platform details.\"\n        exit 1\n        ;;\n    esac\n    ;;\n  *)\n    echo \"There is no talosctl support for $OS/$arch. Please open an issue with your platform details.\"\n    exit 1\n    ;;\nesac\nOS=$(echo $OS | tr '[:upper:]' '[:lower:]')\n\ndstfile=\"${INSTALLPATH}/talosctl\"\n\nchecksumbin=$(command -v openssl) || checksumbin=$(command -v shasum) || {\n  echo \"Failed to find checksum binary. Please install openssl or shasum.\"\n  echo \"\"\n  echo \"You can also elect to just download/install https://github.com/siderolabs/talos/releases/latest/download/${srcfile}\"\n  echo \"into ${dstfile}\"\n  exit 1\n}\n\nif [ -e \"${dstfile}\" ]; then\n    echo \"\"\n    echo \"talosctl was already downloaded;  🎉\"\n    echo \"\"\n    echo \"To force re-downloading, delete '${dstfile}' then run me again.\"\n    happyexit\nfi\n\ntmpdir=$(mktemp -d /tmp/talosctl.XXXXXX)\nsrcfile=\"talosctl-${OS}\"\nif [ -n \"${cli_arch}\" ]; then\n  srcfile=\"${srcfile}-${cli_arch}\"\nfi\n\nurl=\"https://github.com/siderolabs/talos/releases/latest/download/${srcfile}\"\n\n(\n  cd \"$tmpdir\"\n\n  echo \"Downloading ${srcfile}...\"\n  curl --proto '=https' --tlsv1.2 -fLO \"${url}\"\n  echo \"Download complete!\"\n\n  if ! validate_checksum \"${srcfile}\"; then\n    exit 1\n  fi\n  echo \"\"\n  exit\n)\n\n(\n  super=''\n  if [ ! -w \"${INSTALLPATH}\" ]; then\n    if $(command -v sudo > /dev/null 2>&1); then\n      super='sudo -E sh -c'\n    elif $(command -v  su > /dev/null 2>&1); then\n      super='su -c'\n    fi\n  fi\n\n  if [ -z \"${super}\" ]; then\n    mv \"${tmpdir}\"/\"${srcfile}\" \"${dstfile}\"\n    chmod +x \"${dstfile}\"\n  else\n    ${super} 'mv \"'${tmpdir}/${srcfile}'\" \"'${dstfile}'\"'\n    ${super} 'chmod +x \"'${dstfile}'\"'\n  fi\n)\n\nrm -r \"$tmpdir\"\n\necho \"talosctl was successfully installed 🎉\"\necho \"\"\nhappyexit\n"
  }
]